resolve merge conflicts of 4bb8a91 to master

Change-Id: I0611d987875444dd5debfe53a423ef4f069a2241
diff --git a/.gitignore b/.gitignore
index 992ab5c..27eeb9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,58 +1,117 @@
-# git-ls-files --others --exclude-from=.git/info/exclude
-# Lines that start with '#' are comments.
-# For a project mostly in C, the following would be a good set of
-# exclude patterns (uncomment them if you want to use them):
-*.[oa]
-*~
+# autogen.sh-generated files
+Makefile.in
+src/Makefile.in
+config.guess
+config.h.in
+config.sub
+configure
+depcomp
+install-sh
+ltmain.sh
+missing
+
+aclocal.m4
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+autom4te.cache
+
+# downloaded files
+gmock
+
+# in-tree configure-generated files
+Makefile
+src/Makefile
+/config.h
+config.log
+config.status
+
+libtool
+protobuf-lite.pc
+protobuf.pc
+.deps
+stamp-h1
+
+# in-tree build products
+*.o
 *.lo
 *.la
-*.pyc
-*.egg
-.deps
-/stamp-h1
-/Makefile
-/src/Makefile
-/config.log
-/config.status
-/config.h
-gtest/Makefile
-gtest/build-aux/config.h
-gtest/build-aux/stamp-h1
-gtest/config.log
-gtest/config.status
-gtest/libtool
-gtest/scripts/gtest-config
-gtest/lib
-gtest/src/.dirstamp
-protobuf.pc
-protobuf-lite.pc
-libtool
-autom4te.cache/
-core
-python/build/
-python/google/protobuf/descriptor_pb2.py
-python/google/protobuf/internal/more_extensions_pb2.py
-python/google/protobuf/internal/more_messages_pb2.py
-python/google/protobuf/unittest_import_pb2.py
-python/google/protobuf/unittest_mset_pb2.py
-python/google/protobuf/unittest_no_generic_services_pb2.py
-python/google/protobuf/unittest_pb2.py
-python/protobuf.egg-info/
-src/google/protobuf/unittest*pb*
-src/google/protobuf/compiler/cpp/cpp*pb*
-src/unittest_proto_middleman
-src/protobuf-lazy-descriptor-test
-src/protobuf-lite-test
-src/protobuf-test
-src/zcgunzip
-src/zcgzip
 src/.libs
+*.so
+
+.dirstamp
+
+any_test.pb.*
+map*unittest.pb.*
+unittest*.pb.*
+cpp_test*.pb.*
+src/google/protobuf/util/**/*.pb.cc
+src/google/protobuf/util/**/*.pb.h
+
+*.pyc
+*.egg-info
+*_pb2.py
+python/*.egg
+python/.eggs/
+python/.tox
+python/build/
+python/google/protobuf/compiler/
+python/google/protobuf/util/
+
 src/protoc
+src/unittest_proto_middleman
+
+# Generated test scaffolding
+src/protobuf*-test
 src/test_plugin
-src/testzip.jar
-src/testzip.list
-src/testzip.proto
-src/testzip.zip
-vsprojects/config.h
-java/target/
-!prebuilts/**
+src/testzip.*
+src/zcg*zip
+ar-lib
+
+test-driver
+compile
+
+src/**/*.log
+src/**/*.trs
+
+# JavaBuild output.
+java/target
+javanano/target
+
+# Windows native output.
+cmake/build
+build_msvc
+
+# NuGet packages: we want the repository configuration, but not the
+# packages themselves.
+/csharp/src/packages/*/
+
+# Directories created by opening the Objective C Xcode projects.
+objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcuserdata/
+objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/ProtocolBuffers_OSX.xccheckout
+objectivec/ProtocolBuffers_OSX.xcodeproj/xcuserdata/
+objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcuserdata/
+objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/ProtocolBuffers_iOS.xccheckout
+objectivec/ProtocolBuffers_iOS.xcodeproj/xcuserdata/
+# OS X's Finder creates these for state about opened windows/etc.
+**/.DS_Store
+
+# Comformance test output
+conformance/.libs/
+conformance/com/
+conformance/conformance-cpp
+conformance/conformance-csharp
+conformance/conformance-java
+conformance/conformance-objc
+conformance/conformance-test-runner
+conformance/conformance.pb.cc
+conformance/conformance.pb.h
+conformance/Conformance.pbobjc.h
+conformance/Conformance.pbobjc.m
+conformance/conformance.rb
+conformance/google/
+conformance/javac_middleman
+conformance/lite/
+conformance/protoc_middleman
diff --git a/Android.bp b/Android.bp
index 9b747a0..9bffcbc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -26,9 +26,19 @@
     srcs: [
         "src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
         "src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc",
+        "src/google/protobuf/stubs/bytestream.cc",
         "src/google/protobuf/stubs/common.cc",
+        "src/google/protobuf/stubs/int128.cc",
         "src/google/protobuf/stubs/once.cc",
+        "src/google/protobuf/stubs/status.cc",
+        "src/google/protobuf/stubs/statusor.cc",
+        "src/google/protobuf/stubs/stringpiece.cc",
         "src/google/protobuf/stubs/stringprintf.cc",
+        "src/google/protobuf/stubs/structurally_valid.cc",
+        "src/google/protobuf/stubs/strutil.cc",
+        "src/google/protobuf/stubs/time.cc",
+        "src/google/protobuf/arena.cc",
+        "src/google/protobuf/arenastring.cc",
         "src/google/protobuf/extension_set.cc",
         "src/google/protobuf/generated_message_util.cc",
         "src/google/protobuf/message_lite.cc",
@@ -77,6 +87,15 @@
     },
 }
 
+// C++ lite library for the platform and host.
+// =======================================================
+cc_library_static {
+    name: "libprotobuf-cpp-lite_static",
+    host_supported: true,
+    defaults: ["libprotobuf-cpp-lite-defaults"],
+    cflags: ["-DGOOGLE_PROTOBUF_NO_RTTI"],
+}
+
 // C++ lite library + rtti (libc++ flavored for the platform and host)
 // =======================================================
 cc_library_shared {
@@ -90,21 +109,32 @@
 // C++ full library
 // =======================================================
 protobuf_cc_full_src_files = [
-    "src/google/protobuf/stubs/strutil.cc",
-    "src/google/protobuf/stubs/substitute.cc",
-    "src/google/protobuf/stubs/structurally_valid.cc",
+    "src/google/protobuf/any.pb.cc",
+    "src/google/protobuf/api.pb.cc",
+    "src/google/protobuf/stubs/mathlimits.cc",
+    "src/google/protobuf/any.cc",
     "src/google/protobuf/descriptor.cc",
-    "src/google/protobuf/descriptor.pb.cc",
     "src/google/protobuf/descriptor_database.cc",
+    "src/google/protobuf/descriptor.pb.cc",
+    "src/google/protobuf/duration.pb.cc",
     "src/google/protobuf/dynamic_message.cc",
+    "src/google/protobuf/empty.pb.cc",
     "src/google/protobuf/extension_set_heavy.cc",
+    "src/google/protobuf/field_mask.pb.cc",
     "src/google/protobuf/generated_message_reflection.cc",
+    "src/google/protobuf/map_field.cc",
     "src/google/protobuf/message.cc",
     "src/google/protobuf/reflection_ops.cc",
     "src/google/protobuf/service.cc",
+    "src/google/protobuf/source_context.pb.cc",
+    "src/google/protobuf/struct.pb.cc",
+    "src/google/protobuf/stubs/substitute.cc",
     "src/google/protobuf/text_format.cc",
+    "src/google/protobuf/timestamp.pb.cc",
+    "src/google/protobuf/type.pb.cc",
     "src/google/protobuf/unknown_field_set.cc",
     "src/google/protobuf/wire_format.cc",
+    "src/google/protobuf/wrappers.pb.cc",
     "src/google/protobuf/io/gzip_stream.cc",
     "src/google/protobuf/io/printer.cc",
     "src/google/protobuf/io/strtod.cc",
@@ -112,6 +142,26 @@
     "src/google/protobuf/io/zero_copy_stream_impl.cc",
     "src/google/protobuf/compiler/importer.cc",
     "src/google/protobuf/compiler/parser.cc",
+    "src/google/protobuf/util/field_comparator.cc",
+    "src/google/protobuf/util/field_mask_util.cc",
+    "src/google/protobuf/util/internal/datapiece.cc",
+    "src/google/protobuf/util/internal/default_value_objectwriter.cc",
+    "src/google/protobuf/util/internal/error_listener.cc",
+    "src/google/protobuf/util/internal/field_mask_utility.cc",
+    "src/google/protobuf/util/internal/json_escaping.cc",
+    "src/google/protobuf/util/internal/json_objectwriter.cc",
+    "src/google/protobuf/util/internal/json_stream_parser.cc",
+    "src/google/protobuf/util/internal/object_writer.cc",
+    "src/google/protobuf/util/internal/protostream_objectsource.cc",
+    "src/google/protobuf/util/internal/protostream_objectwriter.cc",
+    "src/google/protobuf/util/internal/proto_writer.cc",
+    "src/google/protobuf/util/internal/type_info.cc",
+    "src/google/protobuf/util/internal/type_info_test_helper.cc",
+    "src/google/protobuf/util/internal/utility.cc",
+    "src/google/protobuf/util/json_util.cc",
+    "src/google/protobuf/util/message_differencer.cc",
+    "src/google/protobuf/util/time_util.cc",
+    "src/google/protobuf/util/type_resolver_util.cc",
 ]
 
 // C++ full library for the NDK.
@@ -184,6 +234,26 @@
     },
 }
 
+// Compiler library for the host
+// =======================================================
+cc_library_host_shared {
+    name: "libprotoc",
+    defaults: ["libprotobuf-cpp-lite-defaults"],
+
+    srcs: protobuf_cc_full_src_files + [
+        "src/google/protobuf/compiler/plugin.pb.cc",
+    ],
+
+    local_include_dirs: [
+        "config",
+    ],
+    export_include_dirs: ["src", "config"],
+
+    rtti: true,
+
+    shared_libs: ["libz-host"],
+}
+
 // Android Protocol buffer compiler, aprotoc (host executable)
 // used by the build systems as $(PROTOC) defined in
 // build/core/config.mk
@@ -205,6 +275,9 @@
     stl: "libc++_static",
 
     srcs: [
+        "src/google/protobuf/any.cc",
+        "src/google/protobuf/arena.cc",
+        "src/google/protobuf/arenastring.cc",
         "src/google/protobuf/descriptor.cc",
         "src/google/protobuf/descriptor.pb.cc",
         "src/google/protobuf/descriptor_database.cc",
@@ -213,6 +286,7 @@
         "src/google/protobuf/extension_set_heavy.cc",
         "src/google/protobuf/generated_message_reflection.cc",
         "src/google/protobuf/generated_message_util.cc",
+        "src/google/protobuf/map_field.cc",
         "src/google/protobuf/message.cc",
         "src/google/protobuf/message_lite.cc",
         "src/google/protobuf/reflection_ops.cc",
@@ -224,13 +298,6 @@
         "src/google/protobuf/wire_format_lite.cc",
         "src/google/protobuf/compiler/code_generator.cc",
         "src/google/protobuf/compiler/command_line_interface.cc",
-        "src/google/protobuf/compiler/importer.cc",
-        "src/google/protobuf/compiler/main.cc",
-        "src/google/protobuf/compiler/parser.cc",
-        "src/google/protobuf/compiler/plugin.cc",
-        "src/google/protobuf/compiler/plugin.pb.cc",
-        "src/google/protobuf/compiler/subprocess.cc",
-        "src/google/protobuf/compiler/zip_writer.cc",
         "src/google/protobuf/compiler/cpp/cpp_enum.cc",
         "src/google/protobuf/compiler/cpp/cpp_enum_field.cc",
         "src/google/protobuf/compiler/cpp/cpp_extension.cc",
@@ -238,29 +305,59 @@
         "src/google/protobuf/compiler/cpp/cpp_file.cc",
         "src/google/protobuf/compiler/cpp/cpp_generator.cc",
         "src/google/protobuf/compiler/cpp/cpp_helpers.cc",
+        "src/google/protobuf/compiler/cpp/cpp_map_field.cc",
         "src/google/protobuf/compiler/cpp/cpp_message.cc",
         "src/google/protobuf/compiler/cpp/cpp_message_field.cc",
         "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc",
         "src/google/protobuf/compiler/cpp/cpp_service.cc",
         "src/google/protobuf/compiler/cpp/cpp_string_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_field_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_generator.cc",
+        "src/google/protobuf/compiler/csharp/csharp_helpers.cc",
+        "src/google/protobuf/compiler/csharp/csharp_map_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc",
+        "src/google/protobuf/compiler/importer.cc",
         "src/google/protobuf/compiler/java/java_context.cc",
+        "src/google/protobuf/compiler/java/java_doc_comment.cc",
         "src/google/protobuf/compiler/java/java_enum.cc",
         "src/google/protobuf/compiler/java/java_enum_field.cc",
+        "src/google/protobuf/compiler/java/java_enum_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_enum_lite.cc",
         "src/google/protobuf/compiler/java/java_extension.cc",
+        "src/google/protobuf/compiler/java/java_extension_lite.cc",
         "src/google/protobuf/compiler/java/java_field.cc",
         "src/google/protobuf/compiler/java/java_file.cc",
         "src/google/protobuf/compiler/java/java_generator.cc",
         "src/google/protobuf/compiler/java/java_generator_factory.cc",
         "src/google/protobuf/compiler/java/java_helpers.cc",
         "src/google/protobuf/compiler/java/java_lazy_message_field.cc",
+        "src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_map_field.cc",
+        "src/google/protobuf/compiler/java/java_map_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_builder.cc",
+        "src/google/protobuf/compiler/java/java_message_builder_lite.cc",
         "src/google/protobuf/compiler/java/java_message.cc",
         "src/google/protobuf/compiler/java/java_message_field.cc",
+        "src/google/protobuf/compiler/java/java_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_lite.cc",
         "src/google/protobuf/compiler/java/java_name_resolver.cc",
         "src/google/protobuf/compiler/java/java_primitive_field.cc",
-        "src/google/protobuf/compiler/java/java_shared_code_generator.cc",
+        "src/google/protobuf/compiler/java/java_primitive_field_lite.cc",
         "src/google/protobuf/compiler/java/java_service.cc",
+        "src/google/protobuf/compiler/java/java_shared_code_generator.cc",
         "src/google/protobuf/compiler/java/java_string_field.cc",
-        "src/google/protobuf/compiler/java/java_doc_comment.cc",
+        "src/google/protobuf/compiler/java/java_string_field_lite.cc",
         "src/google/protobuf/compiler/javamicro/javamicro_enum.cc",
         "src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc",
         "src/google/protobuf/compiler/javamicro/javamicro_field.cc",
@@ -277,10 +374,31 @@
         "src/google/protobuf/compiler/javanano/javanano_file.cc",
         "src/google/protobuf/compiler/javanano/javanano_generator.cc",
         "src/google/protobuf/compiler/javanano/javanano_helpers.cc",
+        "src/google/protobuf/compiler/javanano/javanano_map_field.cc",
         "src/google/protobuf/compiler/javanano/javanano_message.cc",
         "src/google/protobuf/compiler/javanano/javanano_message_field.cc",
         "src/google/protobuf/compiler/javanano/javanano_primitive_field.cc",
+        "src/google/protobuf/compiler/js/js_generator.cc",
+        "src/google/protobuf/compiler/main.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_extension.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_file.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_helpers.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_map_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_oneof.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc",
+        "src/google/protobuf/compiler/parser.cc",
+        "src/google/protobuf/compiler/plugin.cc",
+        "src/google/protobuf/compiler/plugin.pb.cc",
         "src/google/protobuf/compiler/python/python_generator.cc",
+        "src/google/protobuf/compiler/ruby/ruby_generator.cc",
+        "src/google/protobuf/compiler/subprocess.cc",
+        "src/google/protobuf/compiler/zip_writer.cc",
         "src/google/protobuf/io/coded_stream.cc",
         "src/google/protobuf/io/gzip_stream.cc",
         "src/google/protobuf/io/printer.cc",
@@ -292,7 +410,10 @@
         "src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
         "src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc",
         "src/google/protobuf/stubs/common.cc",
+        "src/google/protobuf/stubs/int128.cc",
         "src/google/protobuf/stubs/once.cc",
+        "src/google/protobuf/stubs/status.cc",
+        "src/google/protobuf/stubs/stringpiece.cc",
         "src/google/protobuf/stubs/structurally_valid.cc",
         "src/google/protobuf/stubs/strutil.cc",
         "src/google/protobuf/stubs/substitute.cc",
diff --git a/Android.mk b/Android.mk
index c27bcad..272146f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,37 +17,50 @@
 LOCAL_PATH := $(call my-dir)
 
 JAVA_LITE_SRC_FILES := \
-    java/src/main/java/com/google/protobuf/UninitializedMessageException.java \
-    java/src/main/java/com/google/protobuf/MessageLite.java \
-    java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
-    java/src/main/java/com/google/protobuf/CodedOutputStream.java \
-    java/src/main/java/com/google/protobuf/ByteString.java \
-    java/src/main/java/com/google/protobuf/CodedInputStream.java \
-    java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
-    java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
-    java/src/main/java/com/google/protobuf/AbstractParser.java \
-    java/src/main/java/com/google/protobuf/FieldSet.java \
-    java/src/main/java/com/google/protobuf/Internal.java \
-    java/src/main/java/com/google/protobuf/WireFormat.java \
-    java/src/main/java/com/google/protobuf/GeneratedMessageLite.java \
-    java/src/main/java/com/google/protobuf/BoundedByteString.java \
-    java/src/main/java/com/google/protobuf/LazyField.java \
-    java/src/main/java/com/google/protobuf/LazyFieldLite.java \
-    java/src/main/java/com/google/protobuf/LazyStringList.java \
-    java/src/main/java/com/google/protobuf/LazyStringArrayList.java \
-    java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java \
-    java/src/main/java/com/google/protobuf/LiteralByteString.java \
-    java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java \
-    java/src/main/java/com/google/protobuf/Parser.java \
-    java/src/main/java/com/google/protobuf/ProtocolStringList.java \
-    java/src/main/java/com/google/protobuf/RopeByteString.java \
-    java/src/main/java/com/google/protobuf/SmallSortedMap.java \
-    java/src/main/java/com/google/protobuf/Utf8.java
+    java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java \
+    java/core/src/main/java/com/google/protobuf/AbstractParser.java \
+    java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java \
+    java/core/src/main/java/com/google/protobuf/ByteOutput.java \
+    java/core/src/main/java/com/google/protobuf/ByteString.java \
+    java/core/src/main/java/com/google/protobuf/BooleanArrayList.java \
+    java/core/src/main/java/com/google/protobuf/CodedInputStream.java \
+    java/core/src/main/java/com/google/protobuf/CodedOutputStream.java \
+    java/core/src/main/java/com/google/protobuf/DoubleArrayList.java \
+    java/core/src/main/java/com/google/protobuf/ExperimentalApi.java \
+    java/core/src/main/java/com/google/protobuf/ExtensionLite.java \
+    java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
+    java/core/src/main/java/com/google/protobuf/FieldSet.java \
+    java/core/src/main/java/com/google/protobuf/FloatArrayList.java \
+    java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java \
+    java/core/src/main/java/com/google/protobuf/IntArrayList.java \
+    java/core/src/main/java/com/google/protobuf/Internal.java \
+    java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
+    java/core/src/main/java/com/google/protobuf/LazyField.java \
+    java/core/src/main/java/com/google/protobuf/LazyFieldLite.java \
+    java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java \
+    java/core/src/main/java/com/google/protobuf/LazyStringList.java \
+    java/core/src/main/java/com/google/protobuf/LongArrayList.java \
+    java/core/src/main/java/com/google/protobuf/MapFieldLite.java \
+    java/core/src/main/java/com/google/protobuf/MessageLite.java \
+    java/core/src/main/java/com/google/protobuf/MessageLiteToString.java \
+    java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java \
+    java/core/src/main/java/com/google/protobuf/MutabilityOracle.java \
+    java/core/src/main/java/com/google/protobuf/Parser.java \
+    java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java \
+    java/core/src/main/java/com/google/protobuf/ProtocolStringList.java \
+    java/core/src/main/java/com/google/protobuf/RopeByteString.java \
+    java/core/src/main/java/com/google/protobuf/SmallSortedMap.java \
+    java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java \
+    java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java \
+    java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java \
+    java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java \
+    java/core/src/main/java/com/google/protobuf/Utf8.java \
+    java/core/src/main/java/com/google/protobuf/WireFormat.java
 
 # This contains more source files than needed for the full version, but the
 # additional files should not create any conflict.
 JAVA_FULL_SRC_FILES := \
-    $(call all-java-files-under, java/src/main/java) \
+    $(call all-java-files-under, java/core/src/main/java) \
     src/google/protobuf/descriptor.proto
 
 # Java nano library (for device-side users)
@@ -56,10 +69,10 @@
 
 LOCAL_MODULE := libprotobuf-java-nano
 LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := 8
+LOCAL_SDK_VERSION := 9
 
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano)
-LOCAL_SRC_FILES += $(call all-java-files-under, java/src/device/main/java/com/google/protobuf/nano)
+LOCAL_SRC_FILES := $(call all-java-files-under, javanano/src/main/java/com/google/protobuf/nano)
+LOCAL_SRC_FILES += $(call all-java-files-under, javanano/src/device/main/java/com/google/protobuf/nano)
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -71,7 +84,7 @@
 LOCAL_MODULE := host-libprotobuf-java-nano
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano)
+LOCAL_SRC_FILES := $(call all-java-files-under, javanano/src/main/java/com/google/protobuf/nano)
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_HOST_JAVA_LIBRARY)
@@ -84,7 +97,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_SDK_VERSION := 8
 
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+LOCAL_SRC_FILES := $(call all-java-files-under, javamicro/src/main/java/com/google/protobuf/micro)
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -96,7 +109,7 @@
 LOCAL_MODULE := host-libprotobuf-java-micro
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+LOCAL_SRC_FILES := $(call all-java-files-under, javamicro/src/main/java/com/google/protobuf/micro)
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_HOST_JAVA_LIBRARY)
@@ -107,7 +120,6 @@
 
 LOCAL_MODULE := libprotobuf-java-lite
 LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := 9
 
 LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
 
@@ -149,17 +161,17 @@
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 
 LOCAL_SRC_FILES := \
-        src/google/protobuf/unittest_import_nano.proto \
-        src/google/protobuf/unittest_simple_nano.proto \
-        src/google/protobuf/unittest_stringutf8_nano.proto \
-        src/google/protobuf/unittest_recursive_nano.proto
+        javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto \
+        javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto \
+        javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto \
+        javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
 
 
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
 
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
-        java_package = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|com.google.protobuf.nano, \
-        java_outer_classname = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|UnittestImportNano
+        java_package = $(LOCAL_PATH)javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto|com.google.protobuf.nano, \
+        java_outer_classname = $(LOCAL_PATH)/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto|UnittestImportNano
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -177,7 +189,7 @@
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 
-LOCAL_SRC_FILES := src/google/protobuf/unittest_simple_nano.proto
+LOCAL_SRC_FILES := javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
 
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
 
@@ -198,7 +210,7 @@
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 
-LOCAL_SRC_FILES := src/google/protobuf/unittest_extension_nano.proto
+LOCAL_SRC_FILES := javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
 
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
 
@@ -219,9 +231,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src/device/test/java/com/google/protobuf/nano)
+LOCAL_SRC_FILES := $(call all-java-files-under, javanano/src/device/test/java/com/google/protobuf/nano)
 
-LOCAL_MANIFEST_FILE := java/src/device/test/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := javanano/src/device/test/AndroidManifest.xml
 
 LOCAL_STATIC_JAVA_LIBRARIES := libprotobuf-java-nano \
         android-nano-test-parcelable \
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..8b1046b
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,709 @@
+# Bazel (http://bazel.io/) BUILD file for Protobuf.
+
+licenses(["notice"])
+
+################################################################################
+# Protobuf Runtime Library
+################################################################################
+
+COPTS = [
+    "-DHAVE_PTHREAD",
+    "-Wall",
+    "-Wwrite-strings",
+    "-Woverloaded-virtual",
+    "-Wno-sign-compare",
+    "-Wno-error=unused-function",
+]
+
+config_setting(
+    name = "android",
+    values = {
+        "crosstool_top": "//external:android/crosstool",
+    },
+)
+
+# Android builds do not need to link in a separate pthread library.
+LINK_OPTS = select({
+    ":android": [],
+    "//conditions:default": ["-lpthread"],
+})
+
+load(
+    "protobuf",
+    "cc_proto_library",
+    "py_proto_library",
+    "internal_gen_well_known_protos_java",
+    "internal_protobuf_py_tests",
+)
+
+config_setting(
+    name = "ios_armv7",
+    values = {
+        "ios_cpu": "armv7",
+    },
+)
+
+config_setting(
+    name = "ios_armv7s",
+    values = {
+        "ios_cpu": "armv7s",
+    },
+)
+
+config_setting(
+    name = "ios_arm64",
+    values = {
+        "ios_cpu": "arm64",
+    },
+)
+
+IOS_ARM_COPTS = COPTS + [
+    "-DOS_IOS",
+    "-miphoneos-version-min=7.0",
+    "-arch armv7",
+    "-arch armv7s",
+    "-arch arm64",
+    "-D__thread=",
+    "-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.2.sdk/",
+]
+
+cc_library(
+    name = "protobuf_lite",
+    srcs = [
+        # AUTOGEN(protobuf_lite_srcs)
+        "src/google/protobuf/arena.cc",
+        "src/google/protobuf/arenastring.cc",
+        "src/google/protobuf/extension_set.cc",
+        "src/google/protobuf/generated_message_util.cc",
+        "src/google/protobuf/io/coded_stream.cc",
+        "src/google/protobuf/io/zero_copy_stream.cc",
+        "src/google/protobuf/io/zero_copy_stream_impl_lite.cc",
+        "src/google/protobuf/message_lite.cc",
+        "src/google/protobuf/repeated_field.cc",
+        "src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
+        "src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc",
+        "src/google/protobuf/stubs/bytestream.cc",
+        "src/google/protobuf/stubs/common.cc",
+        "src/google/protobuf/stubs/int128.cc",
+        "src/google/protobuf/stubs/once.cc",
+        "src/google/protobuf/stubs/status.cc",
+        "src/google/protobuf/stubs/statusor.cc",
+        "src/google/protobuf/stubs/stringpiece.cc",
+        "src/google/protobuf/stubs/stringprintf.cc",
+        "src/google/protobuf/stubs/structurally_valid.cc",
+        "src/google/protobuf/stubs/strutil.cc",
+        "src/google/protobuf/stubs/time.cc",
+        "src/google/protobuf/wire_format_lite.cc",
+    ],
+    hdrs = glob(["src/google/protobuf/**/*.h"]),
+    copts = select({
+        ":ios_armv7": IOS_ARM_COPTS,
+        ":ios_armv7s": IOS_ARM_COPTS,
+        ":ios_arm64": IOS_ARM_COPTS,
+        "//conditions:default": COPTS,
+    }),
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+)
+
+cc_library(
+    name = "protobuf",
+    srcs = [
+        # AUTOGEN(protobuf_srcs)
+        "src/google/protobuf/any.cc",
+        "src/google/protobuf/any.pb.cc",
+        "src/google/protobuf/api.pb.cc",
+        "src/google/protobuf/compiler/importer.cc",
+        "src/google/protobuf/compiler/parser.cc",
+        "src/google/protobuf/descriptor.cc",
+        "src/google/protobuf/descriptor.pb.cc",
+        "src/google/protobuf/descriptor_database.cc",
+        "src/google/protobuf/duration.pb.cc",
+        "src/google/protobuf/dynamic_message.cc",
+        "src/google/protobuf/empty.pb.cc",
+        "src/google/protobuf/extension_set_heavy.cc",
+        "src/google/protobuf/field_mask.pb.cc",
+        "src/google/protobuf/generated_message_reflection.cc",
+        "src/google/protobuf/io/gzip_stream.cc",
+        "src/google/protobuf/io/printer.cc",
+        "src/google/protobuf/io/strtod.cc",
+        "src/google/protobuf/io/tokenizer.cc",
+        "src/google/protobuf/io/zero_copy_stream_impl.cc",
+        "src/google/protobuf/map_field.cc",
+        "src/google/protobuf/message.cc",
+        "src/google/protobuf/reflection_ops.cc",
+        "src/google/protobuf/service.cc",
+        "src/google/protobuf/source_context.pb.cc",
+        "src/google/protobuf/struct.pb.cc",
+        "src/google/protobuf/stubs/mathlimits.cc",
+        "src/google/protobuf/stubs/substitute.cc",
+        "src/google/protobuf/text_format.cc",
+        "src/google/protobuf/timestamp.pb.cc",
+        "src/google/protobuf/type.pb.cc",
+        "src/google/protobuf/unknown_field_set.cc",
+        "src/google/protobuf/util/field_comparator.cc",
+        "src/google/protobuf/util/field_mask_util.cc",
+        "src/google/protobuf/util/internal/datapiece.cc",
+        "src/google/protobuf/util/internal/default_value_objectwriter.cc",
+        "src/google/protobuf/util/internal/error_listener.cc",
+        "src/google/protobuf/util/internal/field_mask_utility.cc",
+        "src/google/protobuf/util/internal/json_escaping.cc",
+        "src/google/protobuf/util/internal/json_objectwriter.cc",
+        "src/google/protobuf/util/internal/json_stream_parser.cc",
+        "src/google/protobuf/util/internal/object_writer.cc",
+        "src/google/protobuf/util/internal/proto_writer.cc",
+        "src/google/protobuf/util/internal/protostream_objectsource.cc",
+        "src/google/protobuf/util/internal/protostream_objectwriter.cc",
+        "src/google/protobuf/util/internal/type_info.cc",
+        "src/google/protobuf/util/internal/type_info_test_helper.cc",
+        "src/google/protobuf/util/internal/utility.cc",
+        "src/google/protobuf/util/json_util.cc",
+        "src/google/protobuf/util/message_differencer.cc",
+        "src/google/protobuf/util/time_util.cc",
+        "src/google/protobuf/util/type_resolver_util.cc",
+        "src/google/protobuf/wire_format.cc",
+        "src/google/protobuf/wrappers.pb.cc",
+    ],
+    hdrs = glob(["src/**/*.h"]),
+    copts = select({
+        ":ios_armv7": IOS_ARM_COPTS,
+        ":ios_armv7s": IOS_ARM_COPTS,
+        ":ios_arm64": IOS_ARM_COPTS,
+        "//conditions:default": COPTS,
+    }),
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protobuf_lite"],
+)
+
+objc_library(
+    name = "protobuf_objc",
+    hdrs = ["objectivec/GPBProtocolBuffers.h"],
+    includes = ["objectivec"],
+    non_arc_srcs = ["objectivec/GPBProtocolBuffers.m"],
+    visibility = ["//visibility:public"],
+)
+
+RELATIVE_WELL_KNOWN_PROTOS = [
+    # AUTOGEN(well_known_protos)
+    "google/protobuf/any.proto",
+    "google/protobuf/api.proto",
+    "google/protobuf/compiler/plugin.proto",
+    "google/protobuf/descriptor.proto",
+    "google/protobuf/duration.proto",
+    "google/protobuf/empty.proto",
+    "google/protobuf/field_mask.proto",
+    "google/protobuf/source_context.proto",
+    "google/protobuf/struct.proto",
+    "google/protobuf/timestamp.proto",
+    "google/protobuf/type.proto",
+    "google/protobuf/wrappers.proto",
+]
+
+WELL_KNOWN_PROTOS = ["src/" + s for s in RELATIVE_WELL_KNOWN_PROTOS]
+
+filegroup(
+    name = "well_known_protos",
+    srcs = WELL_KNOWN_PROTOS,
+    visibility = ["//visibility:public"],
+)
+
+cc_proto_library(
+    name = "cc_wkt_protos",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    internal_bootstrap_hack = 1,
+    protoc = ":protoc",
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Protocol Buffers Compiler
+################################################################################
+
+cc_library(
+    name = "protoc_lib",
+    srcs = [
+        # AUTOGEN(protoc_lib_srcs)
+        "src/google/protobuf/compiler/code_generator.cc",
+        "src/google/protobuf/compiler/command_line_interface.cc",
+        "src/google/protobuf/compiler/cpp/cpp_enum.cc",
+        "src/google/protobuf/compiler/cpp/cpp_enum_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_extension.cc",
+        "src/google/protobuf/compiler/cpp/cpp_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_file.cc",
+        "src/google/protobuf/compiler/cpp/cpp_generator.cc",
+        "src/google/protobuf/compiler/cpp/cpp_helpers.cc",
+        "src/google/protobuf/compiler/cpp/cpp_map_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_message.cc",
+        "src/google/protobuf/compiler/cpp/cpp_message_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_service.cc",
+        "src/google/protobuf/compiler/cpp/cpp_string_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_field_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_generator.cc",
+        "src/google/protobuf/compiler/csharp/csharp_helpers.cc",
+        "src/google/protobuf/compiler/csharp/csharp_map_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc",
+        "src/google/protobuf/compiler/java/java_context.cc",
+        "src/google/protobuf/compiler/java/java_doc_comment.cc",
+        "src/google/protobuf/compiler/java/java_enum.cc",
+        "src/google/protobuf/compiler/java/java_enum_field.cc",
+        "src/google/protobuf/compiler/java/java_enum_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_enum_lite.cc",
+        "src/google/protobuf/compiler/java/java_extension.cc",
+        "src/google/protobuf/compiler/java/java_extension_lite.cc",
+        "src/google/protobuf/compiler/java/java_field.cc",
+        "src/google/protobuf/compiler/java/java_file.cc",
+        "src/google/protobuf/compiler/java/java_generator.cc",
+        "src/google/protobuf/compiler/java/java_generator_factory.cc",
+        "src/google/protobuf/compiler/java/java_helpers.cc",
+        "src/google/protobuf/compiler/java/java_lazy_message_field.cc",
+        "src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_map_field.cc",
+        "src/google/protobuf/compiler/java/java_map_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message.cc",
+        "src/google/protobuf/compiler/java/java_message_builder.cc",
+        "src/google/protobuf/compiler/java/java_message_builder_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_field.cc",
+        "src/google/protobuf/compiler/java/java_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_lite.cc",
+        "src/google/protobuf/compiler/java/java_name_resolver.cc",
+        "src/google/protobuf/compiler/java/java_primitive_field.cc",
+        "src/google/protobuf/compiler/java/java_primitive_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_service.cc",
+        "src/google/protobuf/compiler/java/java_shared_code_generator.cc",
+        "src/google/protobuf/compiler/java/java_string_field.cc",
+        "src/google/protobuf/compiler/java/java_string_field_lite.cc",
+        "src/google/protobuf/compiler/javanano/javanano_enum.cc",
+        "src/google/protobuf/compiler/javanano/javanano_enum_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_extension.cc",
+        "src/google/protobuf/compiler/javanano/javanano_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_file.cc",
+        "src/google/protobuf/compiler/javanano/javanano_generator.cc",
+        "src/google/protobuf/compiler/javanano/javanano_helpers.cc",
+        "src/google/protobuf/compiler/javanano/javanano_map_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_message.cc",
+        "src/google/protobuf/compiler/javanano/javanano_message_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_primitive_field.cc",
+        "src/google/protobuf/compiler/js/js_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_extension.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_file.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_helpers.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_map_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_oneof.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc",
+        "src/google/protobuf/compiler/plugin.cc",
+        "src/google/protobuf/compiler/plugin.pb.cc",
+        "src/google/protobuf/compiler/python/python_generator.cc",
+        "src/google/protobuf/compiler/ruby/ruby_generator.cc",
+        "src/google/protobuf/compiler/subprocess.cc",
+        "src/google/protobuf/compiler/zip_writer.cc",
+    ],
+    copts = COPTS,
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protobuf"],
+)
+
+cc_binary(
+    name = "protoc",
+    srcs = ["src/google/protobuf/compiler/main.cc"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protoc_lib"],
+)
+
+################################################################################
+# Tests
+################################################################################
+
+RELATIVE_LITE_TEST_PROTOS = [
+    # AUTOGEN(lite_test_protos)
+    "google/protobuf/map_lite_unittest.proto",
+    "google/protobuf/unittest_import_lite.proto",
+    "google/protobuf/unittest_import_public_lite.proto",
+    "google/protobuf/unittest_lite.proto",
+    "google/protobuf/unittest_no_arena_lite.proto",
+]
+
+LITE_TEST_PROTOS = ["src/" + s for s in RELATIVE_LITE_TEST_PROTOS]
+
+RELATIVE_TEST_PROTOS = [
+    # AUTOGEN(test_protos)
+    "google/protobuf/any_test.proto",
+    "google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto",
+    "google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto",
+    "google/protobuf/map_proto2_unittest.proto",
+    "google/protobuf/map_unittest.proto",
+    "google/protobuf/unittest.proto",
+    "google/protobuf/unittest_arena.proto",
+    "google/protobuf/unittest_custom_options.proto",
+    "google/protobuf/unittest_drop_unknown_fields.proto",
+    "google/protobuf/unittest_embed_optimize_for.proto",
+    "google/protobuf/unittest_empty.proto",
+    "google/protobuf/unittest_enormous_descriptor.proto",
+    "google/protobuf/unittest_import.proto",
+    "google/protobuf/unittest_import_public.proto",
+    "google/protobuf/unittest_lite_imports_nonlite.proto",
+    "google/protobuf/unittest_mset.proto",
+    "google/protobuf/unittest_mset_wire_format.proto",
+    "google/protobuf/unittest_no_arena.proto",
+    "google/protobuf/unittest_no_arena_import.proto",
+    "google/protobuf/unittest_no_field_presence.proto",
+    "google/protobuf/unittest_no_generic_services.proto",
+    "google/protobuf/unittest_optimize_for.proto",
+    "google/protobuf/unittest_preserve_unknown_enum.proto",
+    "google/protobuf/unittest_preserve_unknown_enum2.proto",
+    "google/protobuf/unittest_proto3_arena.proto",
+    "google/protobuf/unittest_proto3_arena_lite.proto",
+    "google/protobuf/unittest_proto3_lite.proto",
+    "google/protobuf/unittest_well_known_types.proto",
+    "google/protobuf/util/internal/testdata/anys.proto",
+    "google/protobuf/util/internal/testdata/books.proto",
+    "google/protobuf/util/internal/testdata/default_value.proto",
+    "google/protobuf/util/internal/testdata/default_value_test.proto",
+    "google/protobuf/util/internal/testdata/field_mask.proto",
+    "google/protobuf/util/internal/testdata/maps.proto",
+    "google/protobuf/util/internal/testdata/oneofs.proto",
+    "google/protobuf/util/internal/testdata/struct.proto",
+    "google/protobuf/util/internal/testdata/timestamp_duration.proto",
+    "google/protobuf/util/json_format_proto3.proto",
+    "google/protobuf/util/message_differencer_unittest.proto",
+]
+
+TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
+
+cc_proto_library(
+    name = "cc_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    protoc = ":protoc",
+    deps = [":cc_wkt_protos"],
+)
+
+COMMON_TEST_SRCS = [
+    # AUTOGEN(common_test_srcs)
+    "src/google/protobuf/arena_test_util.cc",
+    "src/google/protobuf/map_test_util.cc",
+    "src/google/protobuf/test_util.cc",
+    "src/google/protobuf/testing/file.cc",
+    "src/google/protobuf/testing/googletest.cc",
+]
+
+cc_binary(
+    name = "test_plugin",
+    srcs = [
+        # AUTOGEN(test_plugin_srcs)
+        "src/google/protobuf/compiler/mock_code_generator.cc",
+        "src/google/protobuf/compiler/test_plugin.cc",
+        "src/google/protobuf/testing/file.cc",
+    ],
+    deps = [
+        ":protobuf",
+        ":protoc_lib",
+        "//external:gtest",
+    ],
+)
+
+cc_test(
+    name = "protobuf_test",
+    srcs = COMMON_TEST_SRCS + [
+        # AUTOGEN(test_srcs)
+        "src/google/protobuf/any_test.cc",
+        "src/google/protobuf/arena_unittest.cc",
+        "src/google/protobuf/arenastring_unittest.cc",
+        "src/google/protobuf/compiler/command_line_interface_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_unittest.cc",
+        "src/google/protobuf/compiler/cpp/metadata_test.cc",
+        "src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc",
+        "src/google/protobuf/compiler/importer_unittest.cc",
+        "src/google/protobuf/compiler/java/java_doc_comment_unittest.cc",
+        "src/google/protobuf/compiler/java/java_plugin_unittest.cc",
+        "src/google/protobuf/compiler/mock_code_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc",
+        "src/google/protobuf/compiler/parser_unittest.cc",
+        "src/google/protobuf/compiler/python/python_plugin_unittest.cc",
+        "src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc",
+        "src/google/protobuf/descriptor_database_unittest.cc",
+        "src/google/protobuf/descriptor_unittest.cc",
+        "src/google/protobuf/drop_unknown_fields_test.cc",
+        "src/google/protobuf/dynamic_message_unittest.cc",
+        "src/google/protobuf/extension_set_unittest.cc",
+        "src/google/protobuf/generated_message_reflection_unittest.cc",
+        "src/google/protobuf/io/coded_stream_unittest.cc",
+        "src/google/protobuf/io/printer_unittest.cc",
+        "src/google/protobuf/io/tokenizer_unittest.cc",
+        "src/google/protobuf/io/zero_copy_stream_unittest.cc",
+        "src/google/protobuf/map_field_test.cc",
+        "src/google/protobuf/map_test.cc",
+        "src/google/protobuf/message_unittest.cc",
+        "src/google/protobuf/no_field_presence_test.cc",
+        "src/google/protobuf/preserve_unknown_enum_test.cc",
+        "src/google/protobuf/proto3_arena_lite_unittest.cc",
+        "src/google/protobuf/proto3_arena_unittest.cc",
+        "src/google/protobuf/proto3_lite_unittest.cc",
+        "src/google/protobuf/reflection_ops_unittest.cc",
+        "src/google/protobuf/repeated_field_reflection_unittest.cc",
+        "src/google/protobuf/repeated_field_unittest.cc",
+        "src/google/protobuf/stubs/bytestream_unittest.cc",
+        "src/google/protobuf/stubs/common_unittest.cc",
+        "src/google/protobuf/stubs/int128_unittest.cc",
+        "src/google/protobuf/stubs/once_unittest.cc",
+        "src/google/protobuf/stubs/status_test.cc",
+        "src/google/protobuf/stubs/statusor_test.cc",
+        "src/google/protobuf/stubs/stringpiece_unittest.cc",
+        "src/google/protobuf/stubs/stringprintf_unittest.cc",
+        "src/google/protobuf/stubs/structurally_valid_unittest.cc",
+        "src/google/protobuf/stubs/strutil_unittest.cc",
+        "src/google/protobuf/stubs/template_util_unittest.cc",
+        "src/google/protobuf/stubs/time_test.cc",
+        "src/google/protobuf/stubs/type_traits_unittest.cc",
+        "src/google/protobuf/text_format_unittest.cc",
+        "src/google/protobuf/unknown_field_set_unittest.cc",
+        "src/google/protobuf/util/field_comparator_test.cc",
+        "src/google/protobuf/util/field_mask_util_test.cc",
+        "src/google/protobuf/util/internal/default_value_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/json_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/json_stream_parser_test.cc",
+        "src/google/protobuf/util/internal/protostream_objectsource_test.cc",
+        "src/google/protobuf/util/internal/protostream_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/type_info_test_helper.cc",
+        "src/google/protobuf/util/json_util_test.cc",
+        "src/google/protobuf/util/message_differencer_unittest.cc",
+        "src/google/protobuf/util/time_util_test.cc",
+        "src/google/protobuf/util/type_resolver_util_test.cc",
+        "src/google/protobuf/well_known_types_unittest.cc",
+        "src/google/protobuf/wire_format_unittest.cc",
+    ],
+    copts = COPTS,
+    data = [
+        ":test_plugin",
+    ] + glob([
+        "src/google/protobuf/**/*",
+    ]),
+    includes = [
+        "src/",
+    ],
+    linkopts = LINK_OPTS,
+    deps = [
+        ":cc_test_protos",
+        ":protobuf",
+        ":protoc_lib",
+        "//external:gtest_main",
+    ],
+)
+
+################################################################################
+# Java support
+################################################################################
+internal_gen_well_known_protos_java(
+    srcs = WELL_KNOWN_PROTOS,
+)
+
+java_library(
+    name = "protobuf_java",
+    srcs = glob([
+        "java/core/src/main/java/com/google/protobuf/*.java",
+    ]) + [
+        ":gen_well_known_protos_java",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "protobuf_java_util",
+    srcs = glob([
+        "java/util/src/main/java/com/google/protobuf/util/*.java",
+    ]),
+    deps = [
+        "protobuf_java",
+        "//external:gson",
+        "//external:guava",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Python support
+################################################################################
+
+py_library(
+    name = "python_srcs",
+    srcs = glob(
+        [
+            "python/google/protobuf/*.py",
+            "python/google/protobuf/**/*.py",
+        ],
+        exclude = [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    srcs_version = "PY2AND3",
+    imports = ["python"],
+)
+
+cc_binary(
+    name = "internal/_api_implementation.so",
+    srcs = ["python/google/protobuf/internal/api_implementation.cc"],
+    copts = COPTS + [
+        "-DPYTHON_PROTO2_CPP_IMPL_V2",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//external:python_headers"],
+    }),
+)
+
+cc_binary(
+    name = "pyext/_message.so",
+    srcs = glob([
+        "python/google/protobuf/pyext/*.cc",
+        "python/google/protobuf/pyext/*.h",
+    ]),
+    copts = COPTS + [
+        "-DGOOGLE_PROTOBUF_HAS_ONEOF=1",
+    ] + select({
+        "//conditions:default": [],
+        ":allow_oversize_protos": ["-DPROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS=1"],
+    }),
+    includes = [
+        "python/",
+        "src/",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = [
+        ":protobuf",
+    ] + select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//external:python_headers"],
+    }),
+)
+
+config_setting(
+    name = "use_fast_cpp_protos",
+    values = {
+        "define": "use_fast_cpp_protos=true",
+    },
+)
+
+config_setting(
+    name = "allow_oversize_protos",
+    values = {
+        "define": "allow_oversize_protos=true",
+    },
+)
+
+py_proto_library(
+    name = "protobuf_python",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    data = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": [
+            ":internal/_api_implementation.so",
+            ":pyext/_message.so",
+        ],
+    }),
+    default_runtime = "",
+    protoc = ":protoc",
+    py_libs = [
+        ":python_srcs",
+        "//external:six"
+    ],
+    srcs_version = "PY2AND3",
+    visibility = ["//visibility:public"],
+)
+
+py_proto_library(
+    name = "python_common_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = "",
+    protoc = ":protoc",
+    srcs_version = "PY2AND3",
+    deps = [":protobuf_python"],
+)
+
+py_proto_library(
+    name = "python_specific_test_protos",
+    srcs = glob([
+        "python/google/protobuf/internal/*.proto",
+        "python/google/protobuf/internal/import_test_package/*.proto",
+    ]),
+    include = "python",
+    default_runtime = ":protobuf_python",
+    protoc = ":protoc",
+    srcs_version = "PY2AND3",
+    deps = [":python_common_test_protos"],
+)
+
+py_library(
+    name = "python_tests",
+    srcs = glob(
+        [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    imports = ["python"],
+    srcs_version = "PY2AND3",
+    deps = [
+        ":protobuf_python",
+        ":python_common_test_protos",
+        ":python_specific_test_protos",
+    ],
+)
+
+internal_protobuf_py_tests(
+    name = "python_tests_batch",
+    data = glob([
+        "src/google/protobuf/**/*",
+    ]),
+    modules = [
+        "descriptor_database_test",
+        "descriptor_pool_test",
+        "descriptor_test",
+        "generator_test",
+        "json_format_test",
+        "message_factory_test",
+        "message_test",
+        "proto_builder_test",
+        "reflection_test",
+        "service_reflection_test",
+        "symbol_database_test",
+        "text_encoding_test",
+        "text_format_test",
+        "unknown_fields_test",
+        "wire_format_test",
+    ],
+    deps = [":python_tests"],
+)
diff --git a/CHANGES.txt b/CHANGES.txt
index 0d0ac81..3459ccc 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,592 @@
+2016-05-16 version 3.0.0-beta-3 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
+  General
+  * Supported Proto3 lite-runtime in C++/Java for mobile platforms.
+  * Any type now supports APIs to specify prefixes other than
+    type.googleapis.com
+  * Removed javanano_use_deprecated_package option; Nano will always has its own
+    ".nano" package.
+
+  C++ (Beta)
+  * Improved hash maps.
+      - Improved hash maps comments. In particular, please note that equal hash
+        maps will not necessarily have the same iteration order and
+        serialization.
+      - Added a new hash maps implementation that will become the default in a
+        later release.
+  * Arenas
+      - Several inlined methods in Arena were moved to out-of-line to improve
+        build performance and code size.
+      - Added SpaceAllocatedAndUsed() to report both space used and allocated
+      - Added convenient class UnsafeArenaAllocatedRepeatedPtrFieldBackInserter
+  * Any
+      - Allow custom type URL prefixes in Any packing.
+      - TextFormat now expand the Any type rather than printing bytes.
+  * Performance optimizations and various bug fixes.
+
+  Java (Beta)
+  * Introduced an ExperimentalApi annotation. Annotated APIs are experimental
+    and are subject to change in a backward incompatible way in future releases.
+  * Introduced zero-copy serialization as an ExperimentalApi
+      - Introduction of the `ByteOutput` interface. This is similar to
+        `OutputStream` but provides semantics for lazy writing (i.e. no
+        immediate copy required) of fields that are considered to be immutable.
+      - `ByteString` now supports writing to a `ByteOutput`, which will directly
+        expose the internals of the `ByteString` (i.e. `byte[]` or `ByteBuffer`)
+        to the `ByteOutput` without copying.
+      - `CodedOutputStream` now supports writing to a `ByteOutput`. `ByteString`
+        instances that are too large to fit in the internal buffer will be
+        (lazily) written to the `ByteOutput` directly.
+      - This allows applications using large `ByteString` fields to avoid
+        duplication of these fields entirely. Such an application can supply a
+        `ByteOutput` that chains together the chunks received from
+        `CodedOutputStream` before forwarding them onto the IO system.
+  * Other related changes to `CodedOutputStream`
+      - Additional use of `sun.misc.Unsafe` where possible to perform fast
+        access to `byte[]` and `ByteBuffer` values and avoiding unnecessary
+        range checking.
+      - `ByteBuffer`-backed `CodedOutputStream` now writes directly to the
+        `ByteBuffer` rather than to an intermediate array.
+  * Improved lite-runtime.
+      - Lite protos now implement deep equals/hashCode/toString
+      - Significantly improved the performance of Builder#mergeFrom() and
+        Builder#mergeDelimitedFrom()
+  * Various bug fixes and small feature enhancement.
+      - Fixed stack overflow when in hashCode() for infinite recursive oneofs.
+      - Fixed the lazy field parsing in lite to merge rather than overwrite.
+      - TextFormat now supports reporting line/column numbers on errors.
+      - Updated to add appropriate @Override for better compiler errors.
+
+  Python (Beta)
+  * Added JSON format for Any, Struct, Value and ListValue
+  * [ ] is now accepted for both repeated scalar fields and repeated message
+    fields in text format parser.
+  * Numerical field name is now supported in text format.
+  * Added DiscardUnknownFields API for python protobuf message.
+
+  Objective-C (Beta)
+  * Proto comments now come over as HeaderDoc comments in the generated sources
+    so Xcode can pick them up and display them.
+  * The library headers have been updated to use HeaderDoc comments so Xcode can
+    pick them up and display them.
+  * The per message and per field overhead in both generated code and runtime
+    object sizes was reduced.
+  * Generated code now include deprecated annotations when the proto file
+    included them.
+
+  C# (Beta)
+  In general: some changes are breaking, which require regenerating messages.
+  Most user-written code will not be impacted *except* for the renaming of enum
+  values.
+
+  * Allow custom type URL prefixes in `Any` packing, and ignore them when
+    unpacking
+  * `protoc` is now in a separate NuGet package (Google.Protobuf.Tools)
+  * New option: `internal_access` to generate internal classes
+  * Enum values are now PascalCased, and if there's a prefix which matches the
+    name of the enum, that is removed (so an enum `COLOR` with a value
+    `COLOR_BLUE` would generate a value of just `Blue`). An option
+    (`legacy_enum_values`) is temporarily available to disable this, but the
+    option will be removed for GA.
+  * `json_name` option is now honored
+  * If group tags are encountered when parsing, they are validated more
+    thoroughly (although we don't support actual groups)
+  * NuGet dependencies are better specified
+  * Breaking: `Preconditions` is renamed to `ProtoPreconditions`
+  * Breaking: `GeneratedCodeInfo` is renamed to `GeneratedClrTypeInfo`
+  * `JsonFormatter` now allows writing to a `TextWriter`
+  * New interface, `ICustomDiagnosticMessage` to allow more compact
+    representations from `ToString`
+  * `CodedInputStream` and `CodedOutputStream` now implement `IDisposable`,
+    which simply disposes of the streams they were constructed with
+  * Map fields no longer support null values (in line with other languages)
+  * Improvements in JSON formatting and parsing
+
+  Javascript (Alpha)
+  * Better support for "bytes" fields: bytes fields can be read as either a
+    base64 string or UInt8Array (in environments where TypedArray is supported).
+  * New support for CommonJS imports.  This should make it easier to use the
+    JavaScript support in Node.js and tools like WebPack.  See js/README.md for
+    more information.
+  * Some significant internal refactoring to simplify and modularize the code.
+
+  Ruby (Alpha)
+  * JSON serialization now properly uses camelCased names, with a runtime option
+    that will preserve original names from .proto files instead.
+  * Well-known types are now included in the distribution.
+  * Release now includes binary gems for Windows, Mac, and Linux instead of just
+    source gems.
+  * Bugfix for serializing oneofs.
+
+  C++/Java Lite (Alpha)
+    A new "lite" generator parameter was introduced in the protoc for C++ and
+    Java for Proto3 syntax messages. Example usage:
+
+     ./protoc --cpp_out=lite:$OUTPUT_PATH foo.proto
+
+    The protoc will treat the current input and all the transitive dependencies
+    as LITE. The same generator parameter must be used to generate the
+    dependencies.
+
+    In Proto3 syntax files, "optimized_for=LITE_RUNTIME" is no longer supported.
+
+
+2015-12-30 version 3.0.0-beta-2 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
+  General
+  * Introduced a new language implementation: JavaScript.
+  * Added a new field option "json_name". By default proto field names are
+    converted to "lowerCamelCase" in proto3 JSON format. This option can be
+    used to override this behavior and specify a different JSON name for the
+    field.
+  * Added conformance tests to ensure implementations are following proto3 JSON
+    specification.
+
+  C++ (Beta)
+  * Various bug fixes and improvements to the JSON support utility:
+      - Duplicate map keys in JSON are now rejected (i.e., translation will
+        fail).
+      - Fixed wire-format for google.protobuf.Value/ListValue.
+      - Fixed precision loss when converting google.protobuf.Timestamp.
+      - Fixed a bug when parsing invalid UTF-8 code points.
+      - Fixed a memory leak.
+      - Reduced call stack usage.
+
+  Java (Beta)
+  * Cleaned up some unused methods on CodedOutputStream.
+  * Presized lists for packed fields during parsing in the lite runtime to
+    reduce allocations and improve performance.
+  * Improved the performance of unknown fields in the lite runtime.
+  * Introduced UnsafeByteStrings to support zero-copy ByteString creation.
+  * Various bug fixes and improvements to the JSON support utility:
+      - Fixed a thread-safety bug.
+      - Added a new option “preservingProtoFieldNames” to JsonFormat.
+      - Added a new option “includingDefaultValueFields” to JsonFormat.
+      - Updated the JSON utility to comply with proto3 JSON specification.
+
+  Python (Beta)
+  * Added proto3 JSON format utility. It includes support for all field types
+    and a few well-known types except for Any and Struct.
+  * Added runtime support for Any, Timestamp, Duration and FieldMask.
+  * [ ] is now accepted for repeated scalar fields in text format parser.
+  * Map fields now have proper O(1) performance for lookup/insert/delete
+    when using the Python/C++ implementation. They were previously using O(n)
+    search-based algorithms because the C++ reflection interface didn't
+    support true map operations.
+
+  Objective-C (Beta)
+  * Various bug-fixes and code tweaks to pass more strict compiler warnings.
+  * Now has conformance test coverage and is passing all tests.
+
+  C# (Beta)
+  * Various bug-fixes.
+  * Code generation: Files generated in directories based on namespace.
+  * Code generation: Include comments from .proto files in XML doc
+    comments (naively)
+  * Code generation: Change organization/naming of "reflection class" (access
+    to file descriptor)
+  * Code generation and library: Add Parser property to MessageDescriptor,
+    and introduce a non-generic parser type.
+  * Library: Added TypeRegistry to support JSON parsing/formatting of Any.
+  * Library: Added Any.Pack/Unpack support.
+  * Library: Implemented JSON parsing.
+
+  Javascript (Alpha)
+  * Added proto3 support for JavaScript. The runtime is written in pure
+    JavaScript and works in browsers and in Node.js. To generate JavaScript
+    code for your proto, invoke protoc with "--js_out". See js/README.md
+    for more build instructions.
+
+2015-08-26 version 3.0.0-beta-1 (C++/Java/Python/Ruby/Nano/Objective-C/C#)
+  About Beta
+  * This is the first beta release of protobuf v3.0.0. Not all languages
+    have reached beta stage. Languages not marked as beta are still in
+    alpha (i.e., be prepared for API breaking changes).
+
+  General
+  * Proto3 JSON is supported in several languages (fully supported in C++
+    and Java, partially supported in Ruby/C#). The JSON spec is defined in
+    the proto3 language guide:
+
+      https://developers.google.com/protocol-buffers/docs/proto3#json
+
+    We will publish a more detailed spec to define the exact behavior of
+    proto3-conformant JSON serializers and parsers. Until then, do not rely
+    on specific behaviors of the implementation if it’s not documented in
+    the above spec. More specifically, the behavior is not yet finalized for
+    the following:
+      - Parsing invalid JSON input (e.g., input with trailing commas).
+      - Non-camelCase names in JSON input.
+      - The same field appears multiple times in JSON input.
+      - JSON arrays contain “null” values.
+      - The message has unknown fields.
+
+  * Proto3 now enforces strict UTF-8 checking. Parsing will fail if a string
+    field contains non UTF-8 data.
+
+  C++ (Beta)
+  * Introduced new utility functions/classes in the google/protobuf/util
+    directory:
+      - MessageDifferencer: compare two proto messages and report their
+                            differences.
+      - JsonUtil: support converting protobuf binary format to/from JSON.
+      - TimeUtil: utility functions to work with well-known types Timestamp
+                  and Duration.
+      - FieldMaskUtil: utility functions to work with FieldMask.
+
+  * Performance optimization of arena construction and destruction.
+  * Bug fixes for arena and maps support.
+  * Changed to use cmake for Windows Visual Studio builds.
+  * Added Bazel support.
+
+  Java (Beta)
+  * Introduced a new util package that will be distributed as a separate
+    artifact in maven. It contains:
+      - JsonFormat: convert proto messages to/from JSON.
+      - TimeUtil: utility functions to work with Timestamp and Duration.
+      - FieldMaskUtil: utility functions to work with FieldMask.
+
+  * The static PARSER in each generated message is deprecated, and it will
+    be removed in a future release. A static parser() getter is generated
+    for each message type instead.
+  * Performance optimizations for String fields serialization.
+  * Performance optimizations for Lite runtime on Android:
+      - Reduced allocations
+      - Reduced method overhead after ProGuarding
+      - Reduced code size after ProGuarding
+
+  Python (Alpha)
+  * Removed legacy Python 2.5 support.
+  * Moved to a single Python 2.x/3.x-compatible codebase, instead of using 2to3.
+  * Fixed build/tests on Python 2.6, 2.7, 3.3, and 3.4.
+      - Pure-Python works on all four.
+      - Python/C++ implementation works on all but 3.4, due to changes in the
+        Python/C++ API in 3.4.
+  * Some preliminary work has been done to allow for multiple DescriptorPools
+    with Python/C++.
+
+  Ruby (Alpha)
+  * Many bugfixes:
+      - fixed parsing/serialization of bytes, sint, sfixed types
+      - other parser bugfixes
+      - fixed memory leak affecting Ruby 2.2
+
+  JavaNano (Alpha)
+  * JavaNano generated code now will be put in a nano package by default to
+    avoid conflicts with Java generated code.
+
+  Objective-C (Alpha)
+  * Added non-null markup to ObjC library. Requires SDK 8.4+ to build.
+  * Many bugfixes:
+      - Removed the class/enum filter.
+      - Renamed some internal types to avoid conflicts with the well-known types
+        protos.
+      - Added missing support for parsing repeated primitive fields in packed or
+        unpacked forms.
+      - Added *Count for repeated and map<> fields to avoid auto-create when
+        checking for them being set.
+
+  C# (Alpha)
+  * Namespace changed to Google.Protobuf (and NuGet package will be named
+    correspondingly).
+  * Target platforms now .NET 4.5 and selected portable subsets only.
+  * Removed lite runtime.
+  * Reimplementation to use mutable message types.
+  * Null references used to represent "no value" for message type fields.
+  * Proto3 semantics supported; proto2 files are prohibited for C# codegen.
+    Most proto3 features supported:
+      - JSON formatting (a.k.a. serialization to JSON), including well-known
+        types (except for Any).
+      - Wrapper types mapped to nullable value types (or string/ByteString
+        allowing nullability). JSON parsing is not supported yet.
+      - maps
+      - oneof
+      - enum unknown value preservation
+
+2015-05-25 version 3.0.0-alpha-3 (Objective-C/C#):
+  General
+  * Introduced two new language implementations (Objective-C, C#) to proto3.
+  * Explicit "optional" keyword are disallowed in proto3 syntax, as fields are
+    optional by default.
+  * Group fields are no longer supported in proto3 syntax.
+  * Changed repeated primitive fields to use packed serialization by default in
+    proto3 (implemented for C++, Java, Python in this release).  The user can
+    still disable packed serialization by setting packed to false for now.
+  * Added well-known type protos (any.proto, empty.proto, timestamp.proto,
+    duration.proto, etc.). Users can import and use these protos just like
+    regular proto files. Additional runtime support will be added for them in
+    future releases (in the form of utility helper functions, or having them
+    replaced by language specific types in generated code).
+  * Added a "reserved" keyword in both proto2 and proto3 syntax. User can use
+    this keyword to declare reserved field numbers and names to prevent them
+    from being reused by other fields in the same message.
+
+    To reserve field numbers, add a reserved declaration in your message:
+
+      message TestMessage {
+        reserved 2, 15, 9 to 11, 3;
+      }
+
+    This reserves field numbers 2, 3, 9, 10, 11 and 15. If a user uses any of
+    these as field numbers, the protocol buffer compiler will report an error.
+
+    Field names can also be reserved:
+
+      message TestMessage {
+        reserved "foo", "bar";
+      }
+
+  * Various bug fixes since 3.0.0-alpha-2
+
+  Objective-C
+    Objective-C includes a code generator and a native objective-c runtime
+    library.  By adding “--objc_out” to protoc, the code generator will generate
+    a header(*.pbobjc.h) and an implementation file(*.pbobjc.m) for each proto
+    file.
+
+    In this first release, the generated interface provides: enums, messages,
+    field support(single, repeated, map, oneof), proto2 and proto3 syntax
+    support, parsing and serialization. It’s  compatible with ARC and non-ARC
+    usage. Besides, user can also access it via the swift bridging header.
+
+    See objectivec/README.md for details.
+
+  C#
+    * C# protobufs are based on project
+      https://github.com/jskeet/protobuf-csharp-port. The original project was
+      frozen and all the new development will happen here.
+    * Codegen plugin for C# was completely rewritten to C++ and is now an
+      integral part of protoc.
+    * Some refactorings and cleanup has been applied to the C# runtime library.
+    * Only proto2 is supported in C# at the moment, proto3 support is in
+      progress and will likely bring significant breaking changes to the API.
+
+    See csharp/README.md for details.
+
+  C++
+    * Added runtime support for Any type. To use Any in your proto file, first
+      import the definition of Any:
+
+        // foo.proto
+        import "google/protobuf/any.proto";
+        message Foo {
+          google.protobuf.Any any_field = 1;
+        }
+        message Bar {
+          int32 value = 1;
+        }
+
+      Then in C++ you can access the Any field using PackFrom()/UnpackTo()
+      methods:
+
+        Foo foo;
+        Bar bar = ...;
+        foo.mutable_any_field()->PackFrom(bar);
+        ...
+        if (foo.any_field().IsType<Bar>()) {
+          foo.any_field().UnpackTo(&bar);
+          ...
+        }
+    * In text format, entries of a map field will be sorted by key.
+
+  Java
+    * Continued optimizations on the lite runtime to improve performance for
+      Android.
+
+  Python
+    * Added map support.
+      - maps now have a dict-like interface (msg.map_field[key] = value)
+      - existing code that modifies maps via the repeated field interface
+        will need to be updated.
+
+  Ruby
+    * Improvements to RepeatedField's emulation of the Ruby Array API.
+    * Various speedups and internal cleanups.
+
+2015-02-26 version 3.0.0-alpha-2 (Python/Ruby/JavaNano):
+  General
+  * Introduced three new language implementations (Ruby, JavaNano, and
+    Python) to proto3.
+  * Various bug fixes since 3.0.0-alpha-1
+
+  Python:
+    Python has received several updates, most notably support for proto3
+    semantics in any .proto file that declares syntax="proto3".
+    Messages declared in proto3 files no longer represent field presence
+    for scalar fields (number, enums, booleans, or strings).  You can
+    no longer call HasField() for such fields, and they are serialized
+    based on whether they have a non-zero/empty/false value.
+
+    One other notable change is in the C++-accelerated implementation.
+    Descriptor objects (which describe the protobuf schema and allow
+    reflection over it) are no longer duplicated between the Python
+    and C++ layers.  The Python descriptors are now simple wrappers
+    around the C++ descriptors.  This change should significantly
+    reduce the memory usage of programs that use a lot of message
+    types.
+
+  Ruby:
+    We have added proto3 support for Ruby via a native C extension.
+
+    The Ruby extension itself is included in the ruby/ directory, and details on
+    building and installing the extension are in ruby/README.md. The extension
+    will also be published as a Ruby gem. Code generator support is included as
+    part of `protoc` with the `--ruby_out` flag.
+
+    The Ruby extension implements a user-friendly DSL to define message types
+    (also generated by the code generator from `.proto` files).  Once a message
+    type is defined, the user may create instances of the message that behave in
+    ways idiomatic to Ruby. For example:
+
+    - Message fields are present as ordinary Ruby properties (getter method
+      `foo` and setter method `foo=`).
+    - Repeated field elements are stored in a container that acts like a native
+      Ruby array, and map elements are stored in a container that acts like a
+      native Ruby hashmap.
+    - The usual well-known methods, such as `#to_s`, `#dup`, and the like, are
+      present.
+
+    Unlike several existing third-party Ruby extensions for protobuf, this
+    extension is built on a "strongly-typed" philosophy: message fields and
+    array/map containers will throw exceptions eagerly when values of the
+    incorrect type are inserted.
+
+    See ruby/README.md for details.
+
+  JavaNano:
+    JavaNano is a special code generator and runtime library designed especially
+    for resource-restricted systems, like Android. It is very resource-friendly
+    in both the amount of code and the runtime overhead. Here is an an overview
+    of JavaNano features compared with the official Java protobuf:
+
+    - No descriptors or message builders.
+    - All messages are mutable; fields are public Java fields.
+    - For optional fields only, encapsulation behind setter/getter/hazzer/
+      clearer functions is opt-in, which provide proper 'has' state support.
+    - For proto2, if not opted in, has state (field presence) is not available.
+      Serialization outputs all fields not equal to their defaults.
+      The behavior is consistent with proto3 semantics.
+    - Required fields (proto2 only) are always serialized.
+    - Enum constants are integers; protection against invalid values only
+      when parsing from the wire.
+    - Enum constants can be generated into container interfaces bearing
+      the enum's name (so the referencing code is in Java style).
+    - CodedInputByteBufferNano can only take byte[] (not InputStream).
+    - Similarly CodedOutputByteBufferNano can only write to byte[].
+    - Repeated fields are in arrays, not ArrayList or Vector. Null array
+      elements are allowed and silently ignored.
+    - Full support for serializing/deserializing repeated packed fields.
+    - Support  extensions (in proto2).
+    - Unset messages/groups are null, not an immutable empty default
+      instance.
+    - toByteArray(...) and mergeFrom(...) are now static functions of
+      MessageNano.
+    - The 'bytes' type translates to the Java type byte[].
+
+    See javanano/README.txt for details.
+
+2014-12-01 version 3.0.0-alpha-1 (C++/Java):
+
+  General
+  * Introduced Protocol Buffers language version 3 (aka proto3).
+
+    When protobuf was initially opensourced it implemented Protocol Buffers
+    language version 2 (aka proto2), which is why the version number
+    started from v2.0.0. From v3.0.0, a new language version (proto3) is
+    introduced while the old version (proto2) will continue to be supported.
+
+    The main intent of introducing proto3 is to clean up protobuf before
+    pushing the language as the foundation of Google's new API platform.
+    In proto3, the language is simplified, both for ease of use and  to
+    make it available in a wider range of programming languages. At the
+    same time a few features are added to better support common idioms
+    found in APIs.
+
+    The following are the main new features in language version 3:
+
+      1. Removal of field presence logic for primitive value fields, removal
+         of required fields, and removal of default values. This makes proto3
+         significantly easier to implement with open struct representations,
+         as in languages like Android Java, Objective C, or Go.
+      2. Removal of unknown fields.
+      3. Removal of extensions, which are instead replaced by a new standard
+         type called Any.
+      4. Fix semantics for unknown enum values.
+      5. Addition of maps.
+      6. Addition of a small set of standard types for representation of time,
+         dynamic data, etc.
+      7. A well-defined encoding in JSON as an alternative to binary proto
+         encoding.
+
+    This release (v3.0.0-alpha-1) includes partial proto3 support for C++ and
+    Java. Items 6 (well-known types) and 7 (JSON format) in the above feature
+    list are not implemented.
+
+    A new notion "syntax" is introduced to specify whether a .proto file
+    uses proto2 or proto3:
+
+      // foo.proto
+      syntax = "proto3";
+      message Bar {...}
+
+    If omitted, the protocol compiler will generate a warning and "proto2" will
+    be used as the default. This warning will be turned into an error in a
+    future release.
+
+    We recommend that new Protocol Buffers users use proto3. However, we do not
+    generally recommend that existing users migrate from proto2 from proto3 due
+    to API incompatibility, and we will continue to support proto2 for a long
+    time.
+
+  * Added support for map fields (implemented in C++/Java for both proto2 and
+    proto3).
+
+    Map fields can be declared using the following syntax:
+
+      message Foo {
+        map<string, string> values = 1;
+      }
+
+    Data of a map field will be stored in memory as an unordered map and it
+    can be accessed through generated accessors.
+
+  C++
+  * Added arena allocation support (for both proto2 and proto3).
+
+    Profiling shows memory allocation and deallocation constitutes a significant
+    fraction of CPU-time spent in protobuf code and arena allocation is a
+    technique introduced to reduce this cost. With arena allocation, new
+    objects will be allocated from a large piece of preallocated memory and
+    deallocation of these objects is almost free. Early adoption shows 20% to
+    50% improvement in some Google binaries.
+
+    To enable arena support, add the following option to your .proto file:
+
+      option cc_enable_arenas = true;
+
+    Protocol compiler will generate additional code to make the generated
+    message classes work with arenas. This does not change the existing API
+    of protobuf messages and does not affect wire format. Your existing code
+    should continue to work after adding this option. In the future we will
+    make this option enabled by default.
+
+    To actually take advantage of arena allocation, you need to use the arena
+    APIs when creating messages. A quick example of using the arena API:
+
+      {
+        google::protobuf::Arena arena;
+        // Allocate a protobuf message in the arena.
+        MyMessage* message = Arena::CreateMessage<MyMessage>(&arena);
+        // All submessages will be allocated in the same arena.
+        if (!message->ParseFromString(data)) {
+          // Deal with malformed input data.
+        }
+        // Must not delete the message here. It will be deleted automatically
+        // when the arena is destroyed.
+      }
+
+    Currently arena does not work with map fields. Enabling arena in a .proto
+    file containing map fields will result in compile errors in the generated
+    code. This will be addressed in a future release.
+
 2014-10-20 version 2.6.1:
 
   C++
@@ -30,7 +619,7 @@
       }
   * Files, services, enums, messages, methods and enum values can be marked
     as deprecated now.
-  * Added Support for list values, including lists of mesaages, when
+  * Added Support for list values, including lists of messages, when
     parsing text-formatted protos in C++ and Java.
       For example:  foo: [1, 2, 3]
 
@@ -110,7 +699,7 @@
 
   Python
   * Added support for dynamic message creation. DescriptorDatabase,
-    DescriptorPool, and MessageFactory work like their C++ couterparts to
+    DescriptorPool, and MessageFactory work like their C++ counterparts to
     simplify Descriptor construction from *DescriptorProtos, and MessageFactory
     provides a message instance from a Descriptor.
   * Added pickle support for protobuf messages.
@@ -124,7 +713,7 @@
 2011-05-01 version 2.4.1:
 
   C++
-  * Fixed the frendship problem for old compilers to make the library now gcc 3
+  * Fixed the friendship problem for old compilers to make the library now gcc 3
     compatible again.
   * Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.
 
@@ -391,7 +980,7 @@
   * Fixed tendency for TextFormat's parsing to overflow the stack when
     parsing large string values.  The underlying problem is with Java's
     regex implementation (which unfortunately uses recursive backtracking
-    rather than building an NFA).  Worked around by making use of possesive
+    rather than building an NFA).  Worked around by making use of possessive
     quantifiers.
   * Generated service classes now also generate pure interfaces.  For a service
     Foo, Foo.Interface is a pure interface containing all of the service's
@@ -405,7 +994,7 @@
     RPC implementations will have to implement the new interfaces in order to
     support blocking mode.
   * New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and
-    writeDelimitedTo() read and write "delemited" messages from/to a stream,
+    writeDelimitedTo() read and write "delimited" messages from/to a stream,
     meaning that the message size precedes the data.  This way, you can write
     multiple messages to a stream without having to worry about delimiting
     them yourself.
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 717ffc1..b8d97fc 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -17,6 +17,12 @@
   Will Robinson <robinson@google.com>
   Petar Petrov <petar@google.com>
 
+Java Nano primary authors:
+  Brian Duff <bduff@google.com>
+  Tom Chao <chaot@google.com>
+  Max Cai <maxtroy@google.com>
+  Ulas Kirazci <ulas@google.com>
+
 Large code contributions:
   Jason Hsueh <jasonh@google.com>
   Joseph Schorr <jschorr@google.com>
@@ -91,3 +97,6 @@
   William Orr <will@worrbase.com>
     * Fixed detection of sched_yield on Solaris.
     * Added atomicops for Solaris
+  Andrew Paprocki <andrew@ishiboo.com>
+    * Fixed minor IBM xlC compiler build issues
+    * Added atomicops for AIX (POWER)
diff --git a/LICENSE b/LICENSE
index 705db57..f028c82 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,14 @@
-Copyright 2008, Google Inc.
-All rights reserved.
+This license applies to all parts of Protocol Buffers except the following:
+
+  - Atomicops support for generic gcc, located in
+    src/google/protobuf/stubs/atomicops_internals_generic_gcc.h.
+    This file is copyrighted by Red Hat Inc.
+
+  - Atomicops support for AIX/POWER, located in
+    src/google/protobuf/stubs/atomicops_internals_power.h.
+    This file is copyrighted by Bloomberg Finance LP.
+
+Copyright 2014, Google Inc.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
diff --git a/Makefile.am b/Makefile.am
index 24e5e55..3e98881 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,192 +8,562 @@
 # the right time.
 SUBDIRS = . src
 
-# Always include gtest in distributions.
-DIST_SUBDIRS = $(subdirs) src
+# Always include gmock in distributions.
+DIST_SUBDIRS = $(subdirs) src conformance benchmarks
 
-# Build gtest before we build protobuf tests.  We don't add gtest to SUBDIRS
-# because then "make check" would also build and run all of gtest's own tests,
+# Build gmock before we build protobuf tests.  We don't add gmock to SUBDIRS
+# because then "make check" would also build and run all of gmock's own tests,
 # which takes a lot of time and is generally not useful to us.  Also, we don't
-# want "make install" to recurse into gtest since we don't want to overwrite
-# the installed version of gtest if there is one.
+# want "make install" to recurse into gmock since we don't want to overwrite
+# the installed version of gmock if there is one.
 check-local:
-	@echo "Making lib/libgtest.a lib/libgtest_main.a in gtest"
-	@cd gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.la lib/libgtest_main.la
+	@echo "Making lib/libgmock.a lib/libgmock_main.a in gmock"
+	@cd gmock && $(MAKE) $(AM_MAKEFLAGS) lib/libgmock.la lib/libgmock_main.la
+	@cd gmock/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.la lib/libgtest_main.la
 
-# We would like to clean gtest when "make clean" is invoked.  But we have to
+# We would like to clean gmock when "make clean" is invoked.  But we have to
 # be careful because clean-local is also invoked during "make distclean", but
-# "make distclean" already recurses into gtest because it's listed among the
-# DIST_SUBDIRS.  distclean will delete gtest/Makefile, so if we then try to
+# "make distclean" already recurses into gmock because it's listed among the
+# DIST_SUBDIRS.  distclean will delete gmock/Makefile, so if we then try to
 # cd to the directory again and "make clean" it will fail.  So, check that the
 # Makefile exists before recursing.
 clean-local:
-	@if test -e gtest/Makefile; then \
-	  echo "Making clean in gtest"; \
-	  cd gtest && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	@if test -e gmock/Makefile; then \
+	  echo "Making clean in gmock"; \
+	  cd gmock && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e conformance/Makefile; then \
+	  echo "Making clean in conformance"; \
+	  cd conformance && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e benchmarks/Makefile; then \
+	  echo "Making clean in benchmarks"; \
+	  cd benchmarks && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e objectivec/DevTools; then \
+	  echo "Cleaning any ObjC pyc files"; \
+	  rm -f objectivec/DevTools/*.pyc; \
 	fi
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = protobuf.pc protobuf-lite.pc
 
-EXTRA_DIST =                                                                 \
-  autogen.sh                                                                 \
-  generate_descriptor_proto.sh                                               \
-  README.md                                                                  \
-  INSTALL.txt                                                                \
-  LICENSE                                                                    \
-  CONTRIBUTORS.txt                                                           \
-  CHANGES.txt                                                                \
-  editors/README.txt                                                         \
-  editors/proto.vim                                                          \
-  editors/protobuf-mode.el                                                   \
-  vsprojects/config.h                                                        \
-  vsprojects/extract_includes.bat                                            \
-  vsprojects/libprotobuf.vcproj                                              \
-  vsprojects/libprotobuf-lite.vcproj                                         \
-  vsprojects/libprotoc.vcproj                                                \
-  vsprojects/protobuf.sln                                                    \
-  vsprojects/protoc.vcproj                                                   \
-  vsprojects/readme.txt                                                      \
-  vsprojects/test_plugin.vcproj                                              \
-  vsprojects/tests.vcproj                                                    \
-  vsprojects/lite-test.vcproj                                                \
-  vsprojects/convert2008to2005.sh                                            \
-  examples/README.txt                                                        \
-  examples/Makefile                                                          \
-  examples/addressbook.proto                                                 \
-  examples/add_person.cc                                                     \
-  examples/list_people.cc                                                    \
-  examples/AddPerson.java                                                    \
-  examples/ListPeople.java                                                   \
-  examples/add_person.py                                                     \
-  examples/list_people.py                                                    \
-  java/src/main/java/com/google/protobuf/AbstractMessage.java                \
-  java/src/main/java/com/google/protobuf/AbstractMessageLite.java            \
-  java/src/main/java/com/google/protobuf/AbstractParser.java                 \
-  java/src/main/java/com/google/protobuf/BlockingRpcChannel.java             \
-  java/src/main/java/com/google/protobuf/BlockingService.java                \
-  java/src/main/java/com/google/protobuf/BoundedByteString.java              \
-  java/src/main/java/com/google/protobuf/ByteString.java                     \
-  java/src/main/java/com/google/protobuf/CodedInputStream.java               \
-  java/src/main/java/com/google/protobuf/CodedOutputStream.java              \
-  java/src/main/java/com/google/protobuf/Descriptors.java                    \
-  java/src/main/java/com/google/protobuf/DynamicMessage.java                 \
-  java/src/main/java/com/google/protobuf/Extension.java                      \
-  java/src/main/java/com/google/protobuf/ExtensionRegistry.java              \
-  java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java          \
-  java/src/main/java/com/google/protobuf/FieldSet.java                       \
-  java/src/main/java/com/google/protobuf/GeneratedMessage.java               \
-  java/src/main/java/com/google/protobuf/GeneratedMessageLite.java           \
-  java/src/main/java/com/google/protobuf/Internal.java                       \
-  java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
-  java/src/main/java/com/google/protobuf/LazyField.java                      \
-  java/src/main/java/com/google/protobuf/LazyFieldLite.java                  \
-  java/src/main/java/com/google/protobuf/LazyStringArrayList.java            \
-  java/src/main/java/com/google/protobuf/LazyStringList.java                 \
-  java/src/main/java/com/google/protobuf/LiteralByteString.java              \
-  java/src/main/java/com/google/protobuf/Message.java                        \
-  java/src/main/java/com/google/protobuf/MessageLite.java                    \
-  java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java           \
-  java/src/main/java/com/google/protobuf/MessageOrBuilder.java               \
-  java/src/main/java/com/google/protobuf/MessageReflection.java              \
-  java/src/main/java/com/google/protobuf/Parser.java                         \
-  java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java            \
-  java/src/main/java/com/google/protobuf/ProtocolStringList.java             \
-  java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java           \
-  java/src/main/java/com/google/protobuf/RopeByteString.java                 \
-  java/src/main/java/com/google/protobuf/RpcCallback.java                    \
-  java/src/main/java/com/google/protobuf/RpcChannel.java                     \
-  java/src/main/java/com/google/protobuf/RpcController.java                  \
-  java/src/main/java/com/google/protobuf/RpcUtil.java                        \
-  java/src/main/java/com/google/protobuf/ServiceException.java               \
-  java/src/main/java/com/google/protobuf/Service.java                        \
-  java/src/main/java/com/google/protobuf/SingleFieldBuilder.java             \
-  java/src/main/java/com/google/protobuf/SmallSortedMap.java                 \
-  java/src/main/java/com/google/protobuf/TextFormat.java                     \
-  java/src/main/java/com/google/protobuf/UninitializedMessageException.java  \
-  java/src/main/java/com/google/protobuf/UnknownFieldSet.java                \
-  java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java     \
-  java/src/main/java/com/google/protobuf/Utf8.java                           \
-  java/src/main/java/com/google/protobuf/WireFormat.java                     \
-  java/src/test/java/com/google/protobuf/AbstractMessageTest.java            \
-  java/src/test/java/com/google/protobuf/BoundedByteStringTest.java          \
-  java/src/test/java/com/google/protobuf/ByteStringTest.java                 \
-  java/src/test/java/com/google/protobuf/CheckUtf8Test.java                  \
-  java/src/test/java/com/google/protobuf/CodedInputStreamTest.java           \
-  java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java          \
-  java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java            \
-  java/src/test/java/com/google/protobuf/DescriptorsTest.java                \
-  java/src/test/java/com/google/protobuf/DynamicMessageTest.java             \
-  java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java       \
-  java/src/test/java/com/google/protobuf/GeneratedMessageTest.java           \
-  java/src/test/java/com/google/protobuf/IsValidUtf8Test.java                \
-  java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java            \
-  java/src/test/java/com/google/protobuf/LazyFieldTest.java                  \
-  java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java              \
-  java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java            \
-  java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java        \
-  java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java         \
-  java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java          \
-  java/src/test/java/com/google/protobuf/LiteralByteStringTest.java          \
-  java/src/test/java/com/google/protobuf/LiteTest.java                       \
-  java/src/test/java/com/google/protobuf/MessageTest.java                    \
-  java/src/test/java/com/google/protobuf/NestedBuildersTest.java             \
-  java/src/test/java/com/google/protobuf/ParserTest.java                     \
-  java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java       \
-  java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java    \
-  java/src/test/java/com/google/protobuf/RopeByteStringTest.java             \
-  java/src/test/java/com/google/protobuf/ServiceTest.java                    \
-  java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java         \
-  java/src/test/java/com/google/protobuf/SmallSortedMapTest.java             \
-  java/src/test/java/com/google/protobuf/TestBadIdentifiers.java             \
-  java/src/test/java/com/google/protobuf/TestUtil.java                       \
-  java/src/test/java/com/google/protobuf/TextFormatTest.java                 \
-  java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java            \
-  java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java \
-  java/src/test/java/com/google/protobuf/WireFormatTest.java                 \
-  java/src/test/java/com/google/protobuf/lazy_fields_lite.proto              \
-  java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto          \
-  java/src/test/java/com/google/protobuf/multiple_files_test.proto           \
-  java/src/test/java/com/google/protobuf/nested_builders_test.proto          \
-  java/src/test/java/com/google/protobuf/nested_extension_lite.proto         \
-  java/src/test/java/com/google/protobuf/nested_extension.proto              \
-  java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto     \
-  java/src/test/java/com/google/protobuf/non_nested_extension.proto          \
-  java/src/test/java/com/google/protobuf/outer_class_name_test.proto         \
-  java/src/test/java/com/google/protobuf/outer_class_name_test2.proto        \
-  java/src/test/java/com/google/protobuf/outer_class_name_test3.proto        \
-  java/src/test/java/com/google/protobuf/test_bad_identifiers.proto          \
-  java/src/test/java/com/google/protobuf/test_check_utf8.proto               \
-  java/src/test/java/com/google/protobuf/test_check_utf8_size.proto          \
-  java/src/test/java/com/google/protobuf/test_custom_options.proto           \
-  java/pom.xml                                                               \
-  java/README.txt                                                            \
+csharp_EXTRA_DIST=                                                           \
+  csharp/.gitignore                                                          \
+  csharp/CHANGES.txt                                                         \
+  csharp/README.md                                                           \
+  csharp/build_packages.bat                                                  \
+  csharp/buildall.sh                                                         \
+  csharp/generate_protos.sh                                                  \
+  csharp/keys/Google.Protobuf.public.snk                                     \
+  csharp/keys/README.md                                                      \
+  csharp/protos/unittest_issues.proto                                        \
+  csharp/src/AddressBook/AddPerson.cs                                        \
+  csharp/src/AddressBook/AddressBook.csproj                                  \
+  csharp/src/AddressBook/Addressbook.cs                                      \
+  csharp/src/AddressBook/ListPeople.cs                                       \
+  csharp/src/AddressBook/Program.cs                                          \
+  csharp/src/AddressBook/Properties/AssemblyInfo.cs                          \
+  csharp/src/AddressBook/SampleUsage.cs                                      \
+  csharp/src/AddressBook/app.config                                          \
+  csharp/src/Google.Protobuf.Conformance/App.config                          \
+  csharp/src/Google.Protobuf.Conformance/Conformance.cs                      \
+  csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj  \
+  csharp/src/Google.Protobuf.Conformance/Program.cs                          \
+  csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs          \
+  csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj        \
+  csharp/src/Google.Protobuf.JsonDump/Program.cs                             \
+  csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs             \
+  csharp/src/Google.Protobuf.JsonDump/app.config                             \
+  csharp/src/Google.Protobuf.Test/ByteStringTest.cs                          \
+  csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs              \
+  csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs                    \
+  csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs                   \
+  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/TypeExtensionsTest.cs        \
+  csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs                    \
+  csharp/src/Google.Protobuf.Test/EqualityTester.cs                          \
+  csharp/src/Google.Protobuf.Test/FieldCodecTest.cs                          \
+  csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs                    \
+  csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj                \
+  csharp/src/Google.Protobuf.Test/IssuesTest.cs                              \
+  csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs                       \
+  csharp/src/Google.Protobuf.Test/JsonParserTest.cs                          \
+  csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs                       \
+  csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml                 \
+  csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs                 \
+  csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs              \
+  csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs              \
+  csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs             \
+  csharp/src/Google.Protobuf.Test/SampleEnum.cs                              \
+  csharp/src/Google.Protobuf.Test/SampleMessages.cs                          \
+  csharp/src/Google.Protobuf.Test/TestCornerCases.cs                         \
+  csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs            \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs         \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs   \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs               \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs               \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs       \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs                  \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs             \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs            \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs             \
+  csharp/src/Google.Protobuf.Test/packages.config                            \
+  csharp/src/Google.Protobuf.sln                                             \
+  csharp/src/Google.Protobuf/ByteArray.cs                                    \
+  csharp/src/Google.Protobuf/ByteString.cs                                   \
+  csharp/src/Google.Protobuf/CodedInputStream.cs                             \
+  csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs                \
+  csharp/src/Google.Protobuf/CodedOutputStream.cs                            \
+  csharp/src/Google.Protobuf/Collections/MapField.cs                         \
+  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/TypeExtensions.cs                 \
+  csharp/src/Google.Protobuf/FieldCodec.cs                                   \
+  csharp/src/Google.Protobuf/FrameworkPortability.cs                         \
+  csharp/src/Google.Protobuf/Google.Protobuf.csproj                          \
+  csharp/src/Google.Protobuf/Google.Protobuf.nuspec                          \
+  csharp/src/Google.Protobuf/IDeepCloneable.cs                               \
+  csharp/src/Google.Protobuf/IMessage.cs                                     \
+  csharp/src/Google.Protobuf/InvalidJsonException.cs                         \
+  csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs               \
+  csharp/src/Google.Protobuf/JsonFormatter.cs                                \
+  csharp/src/Google.Protobuf/JsonParser.cs                                   \
+  csharp/src/Google.Protobuf/JsonToken.cs                                    \
+  csharp/src/Google.Protobuf/JsonTokenizer.cs                                \
+  csharp/src/Google.Protobuf/LimitedInputStream.cs                           \
+  csharp/src/Google.Protobuf/MessageExtensions.cs                            \
+  csharp/src/Google.Protobuf/MessageParser.cs                                \
+  csharp/src/Google.Protobuf/ProtoPreconditions.cs                           \
+  csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs                      \
+  csharp/src/Google.Protobuf/Reflection/Descriptor.cs                        \
+  csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs     \
+  csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs               \
+  csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs                 \
+  csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs                   \
+  csharp/src/Google.Protobuf/Reflection/FieldType.cs                         \
+  csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs              \
+  csharp/src/Google.Protobuf/Reflection/IDescriptor.cs                       \
+  csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs                  \
+  csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs                  \
+  csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs                     \
+  csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs                   \
+  csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs             \
+  csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/PartialClasses.cs                    \
+  csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs                    \
+  csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs             \
+  csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs               \
+  csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/Any.cs                           \
+  csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs                    \
+  csharp/src/Google.Protobuf/WellKnownTypes/Api.cs                           \
+  csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs               \
+  csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs                         \
+  csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs                     \
+  csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs                 \
+  csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs                        \
+  csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs                \
+  csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs                     \
+  csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs              \
+  csharp/src/Google.Protobuf/WellKnownTypes/Type.cs                          \
+  csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs                  \
+  csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs               \
+  csharp/src/Google.Protobuf/WireFormat.cs                                   \
+  csharp/src/Google.Protobuf/packages.config                                 \
+  csharp/src/packages/repositories.config
+
+java_EXTRA_DIST=                                                                   \
+  java/README.md                                                                   \
+  java/core/generate-sources-build.xml                                             \
+  java/core/generate-test-sources-build.xml                                        \
+  java/core/pom.xml                                                                \
+  java/core/src/main/java/com/google/protobuf/AbstractMessage.java                 \
+  java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java             \
+  java/core/src/main/java/com/google/protobuf/AbstractParser.java                  \
+  java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java            \
+  java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java              \
+  java/core/src/main/java/com/google/protobuf/BlockingService.java                 \
+  java/core/src/main/java/com/google/protobuf/BooleanArrayList.java                \
+  java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java                \
+  java/core/src/main/java/com/google/protobuf/ByteOutput.java                      \
+  java/core/src/main/java/com/google/protobuf/ByteString.java                      \
+  java/core/src/main/java/com/google/protobuf/CodedInputStream.java                \
+  java/core/src/main/java/com/google/protobuf/CodedOutputStream.java               \
+  java/core/src/main/java/com/google/protobuf/Descriptors.java                     \
+  java/core/src/main/java/com/google/protobuf/DoubleArrayList.java                 \
+  java/core/src/main/java/com/google/protobuf/DynamicMessage.java                  \
+  java/core/src/main/java/com/google/protobuf/Extension.java                       \
+  java/core/src/main/java/com/google/protobuf/ExtensionLite.java                   \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java               \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java           \
+  java/core/src/main/java/com/google/protobuf/FieldSet.java                        \
+  java/core/src/main/java/com/google/protobuf/FloatArrayList.java                  \
+  java/core/src/main/java/com/google/protobuf/GeneratedMessage.java                \
+  java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java            \
+  java/core/src/main/java/com/google/protobuf/IntArrayList.java                    \
+  java/core/src/main/java/com/google/protobuf/Internal.java                        \
+  java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java  \
+  java/core/src/main/java/com/google/protobuf/LazyField.java                       \
+  java/core/src/main/java/com/google/protobuf/LazyFieldLite.java                   \
+  java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java             \
+  java/core/src/main/java/com/google/protobuf/LazyStringList.java                  \
+  java/core/src/main/java/com/google/protobuf/LongArrayList.java                   \
+  java/core/src/main/java/com/google/protobuf/MapEntry.java                        \
+  java/core/src/main/java/com/google/protobuf/MapEntryLite.java                    \
+  java/core/src/main/java/com/google/protobuf/MapField.java                        \
+  java/core/src/main/java/com/google/protobuf/MapFieldLite.java                    \
+  java/core/src/main/java/com/google/protobuf/Message.java                         \
+  java/core/src/main/java/com/google/protobuf/MessageLite.java                     \
+  java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/MessageLiteToString.java             \
+  java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java                \
+  java/core/src/main/java/com/google/protobuf/MessageReflection.java               \
+  java/core/src/main/java/com/google/protobuf/MutabilityOracle.java                \
+  java/core/src/main/java/com/google/protobuf/NioByteString.java                   \
+  java/core/src/main/java/com/google/protobuf/Parser.java                          \
+  java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java               \
+  java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java             \
+  java/core/src/main/java/com/google/protobuf/ProtocolStringList.java              \
+  java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/RopeByteString.java                  \
+  java/core/src/main/java/com/google/protobuf/RpcCallback.java                     \
+  java/core/src/main/java/com/google/protobuf/RpcChannel.java                      \
+  java/core/src/main/java/com/google/protobuf/RpcController.java                   \
+  java/core/src/main/java/com/google/protobuf/RpcUtil.java                         \
+  java/core/src/main/java/com/google/protobuf/Service.java                         \
+  java/core/src/main/java/com/google/protobuf/ServiceException.java                \
+  java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java              \
+  java/core/src/main/java/com/google/protobuf/SmallSortedMap.java                  \
+  java/core/src/main/java/com/google/protobuf/TextFormat.java                      \
+  java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java               \
+  java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java         \
+  java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java         \
+  java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java   \
+  java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java                 \
+  java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java             \
+  java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java      \
+  java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java            \
+  java/core/src/main/java/com/google/protobuf/Utf8.java                            \
+  java/core/src/main/java/com/google/protobuf/WireFormat.java                      \
+  java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java             \
+  java/core/src/test/java/com/google/protobuf/AnyTest.java                         \
+  java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java            \
+  java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java            \
+  java/core/src/test/java/com/google/protobuf/ByteStringTest.java                  \
+  java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java                   \
+  java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java            \
+  java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java           \
+  java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java             \
+  java/core/src/test/java/com/google/protobuf/DescriptorsTest.java                 \
+  java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java             \
+  java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java              \
+  java/core/src/test/java/com/google/protobuf/EnumTest.java                        \
+  java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java               \
+  java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java              \
+  java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java        \
+  java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java            \
+  java/core/src/test/java/com/google/protobuf/IntArrayListTest.java                \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java                 \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java             \
+  java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java               \
+  java/core/src/test/java/com/google/protobuf/LazyFieldTest.java                   \
+  java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java             \
+  java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java         \
+  java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java          \
+  java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java           \
+  java/core/src/test/java/com/google/protobuf/LiteTest.java                        \
+  java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/LongArrayListTest.java               \
+  java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java            \
+  java/core/src/test/java/com/google/protobuf/MapForProto2Test.java                \
+  java/core/src/test/java/com/google/protobuf/MapTest.java                         \
+  java/core/src/test/java/com/google/protobuf/MessageTest.java                     \
+  java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java              \
+  java/core/src/test/java/com/google/protobuf/NioByteStringTest.java               \
+  java/core/src/test/java/com/google/protobuf/ParserTest.java                      \
+  java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java           \
+  java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java        \
+  java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java     \
+  java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java              \
+  java/core/src/test/java/com/google/protobuf/ServiceTest.java                     \
+  java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java          \
+  java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java              \
+  java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java              \
+  java/core/src/test/java/com/google/protobuf/TestUtil.java                        \
+  java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java     \
+  java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java     \
+  java/core/src/test/java/com/google/protobuf/TextFormatTest.java                  \
+  java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java            \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java         \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java             \
+  java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java  \
+  java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java              \
+  java/core/src/test/java/com/google/protobuf/WireFormatTest.java                  \
+  java/core/src/test/proto/com/google/protobuf/any_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/field_presence_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto              \
+  java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto          \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto      \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto \
+  java/core/src/test/proto/com/google/protobuf/map_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto          \
+  java/core/src/test/proto/com/google/protobuf/nested_extension.proto              \
+  java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto         \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto          \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto     \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto         \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto        \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto        \
+  java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto          \
+  java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto               \
+  java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto          \
+  java/core/src/test/proto/com/google/protobuf/test_custom_options.proto           \
+  java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto         \
+  java/lite/pom.xml                                                                \
+  java/pom.xml                                                                     \
+  java/util/pom.xml                                                                \
+  java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java              \
+  java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java              \
+  java/util/src/main/java/com/google/protobuf/util/JsonFormat.java                 \
+  java/util/src/main/java/com/google/protobuf/util/TimeUtil.java                   \
+  java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java          \
+  java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java          \
+  java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java             \
+  java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java               \
+  java/util/src/test/proto/com/google/protobuf/util/json_test.proto
+
+javanano_EXTRA_DIST=                                                                      \
+  javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java          \
+  javanano/src/main/java/com/google/protobuf/nano/FieldData.java                          \
+  javanano/src/main/java/com/google/protobuf/nano/FieldArray.java                         \
+  javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java                     \
+  javanano/src/main/java/com/google/protobuf/nano/Extension.java                          \
+  javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java           \
+  javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java                   \
+  javanano/src/main/java/com/google/protobuf/nano/MessageNano.java                        \
+  javanano/src/main/java/com/google/protobuf/nano/InternalNano.java                       \
+  javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java \
+  javanano/src/main/java/com/google/protobuf/nano/MapFactories.java                       \
+  javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java              \
+  javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java                 \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto          \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto     \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto                 \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto                     \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/NanoTest.java                           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto      \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto    \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto       \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto          \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto            \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto \
+  javanano/src/test/java/com/google/protobuf/nano/map_test.proto                          \
+  javanano/README.md                                                                      \
+  javanano/pom.xml
+
+objectivec_EXTRA_DIST=                                                       \
+  objectivec/DevTools/check_version_stamps.sh                                \
+  objectivec/DevTools/compile_testing_protos.sh                              \
+  objectivec/DevTools/full_mac_build.sh                                      \
+  objectivec/DevTools/pddm.py                                                \
+  objectivec/DevTools/pddm_tests.py                                          \
+  objectivec/generate_well_known_types.sh                                    \
+  objectivec/google/protobuf/Any.pbobjc.h                                    \
+  objectivec/google/protobuf/Any.pbobjc.m                                    \
+  objectivec/google/protobuf/Api.pbobjc.h                                    \
+  objectivec/google/protobuf/Api.pbobjc.m                                    \
+  objectivec/google/protobuf/Duration.pbobjc.h                               \
+  objectivec/google/protobuf/Duration.pbobjc.m                               \
+  objectivec/google/protobuf/Empty.pbobjc.h                                  \
+  objectivec/google/protobuf/Empty.pbobjc.m                                  \
+  objectivec/google/protobuf/FieldMask.pbobjc.h                              \
+  objectivec/google/protobuf/FieldMask.pbobjc.m                              \
+  objectivec/google/protobuf/SourceContext.pbobjc.h                          \
+  objectivec/google/protobuf/SourceContext.pbobjc.m                          \
+  objectivec/google/protobuf/Struct.pbobjc.h                                 \
+  objectivec/google/protobuf/Struct.pbobjc.m                                 \
+  objectivec/google/protobuf/Timestamp.pbobjc.h                              \
+  objectivec/google/protobuf/Timestamp.pbobjc.m                              \
+  objectivec/google/protobuf/Type.pbobjc.h                                   \
+  objectivec/google/protobuf/Type.pbobjc.m                                   \
+  objectivec/google/protobuf/Wrappers.pbobjc.h                               \
+  objectivec/google/protobuf/Wrappers.pbobjc.m                               \
+  objectivec/GPBArray.h                                                      \
+  objectivec/GPBArray.m                                                      \
+  objectivec/GPBArray_PackagePrivate.h                                       \
+  objectivec/GPBBootstrap.h                                                  \
+  objectivec/GPBCodedInputStream.h                                           \
+  objectivec/GPBCodedInputStream.m                                           \
+  objectivec/GPBCodedInputStream_PackagePrivate.h                            \
+  objectivec/GPBCodedOutputStream.h                                          \
+  objectivec/GPBCodedOutputStream.m                                          \
+  objectivec/GPBCodedOutputStream_PackagePrivate.h                           \
+  objectivec/GPBDescriptor.h                                                 \
+  objectivec/GPBDescriptor.m                                                 \
+  objectivec/GPBDescriptor_PackagePrivate.h                                  \
+  objectivec/GPBDictionary.h                                                 \
+  objectivec/GPBDictionary.m                                                 \
+  objectivec/GPBDictionary_PackagePrivate.h                                  \
+  objectivec/GPBExtensionInternals.h                                         \
+  objectivec/GPBExtensionInternals.m                                         \
+  objectivec/GPBExtensionRegistry.h                                          \
+  objectivec/GPBExtensionRegistry.m                                          \
+  objectivec/GPBMessage.h                                                    \
+  objectivec/GPBMessage.m                                                    \
+  objectivec/GPBMessage_PackagePrivate.h                                     \
+  objectivec/GPBProtocolBuffers.h                                            \
+  objectivec/GPBProtocolBuffers.m                                            \
+  objectivec/GPBProtocolBuffers_RuntimeSupport.h                             \
+  objectivec/GPBRootObject.h                                                 \
+  objectivec/GPBRootObject.m                                                 \
+  objectivec/GPBRootObject_PackagePrivate.h                                  \
+  objectivec/GPBRuntimeTypes.h                                               \
+  objectivec/GPBUnknownField.h                                               \
+  objectivec/GPBUnknownField.m                                               \
+  objectivec/GPBUnknownField_PackagePrivate.h                                \
+  objectivec/GPBUnknownFieldSet.h                                            \
+  objectivec/GPBUnknownFieldSet.m                                            \
+  objectivec/GPBUnknownFieldSet_PackagePrivate.h                             \
+  objectivec/GPBUtilities.h                                                  \
+  objectivec/GPBUtilities.m                                                  \
+  objectivec/GPBUtilities_PackagePrivate.h                                   \
+  objectivec/GPBWellKnownTypes.h                                             \
+  objectivec/GPBWellKnownTypes.m                                             \
+  objectivec/GPBWireFormat.h                                                 \
+  objectivec/GPBWireFormat.m                                                 \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj                   \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj                   \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
+  objectivec/README.md                                                       \
+  objectivec/Tests/golden_message                                            \
+  objectivec/Tests/golden_packed_fields_message                              \
+  objectivec/Tests/GPBARCUnittestProtos.m                                    \
+  objectivec/Tests/GPBArrayTests.m                                           \
+  objectivec/Tests/GPBCodedInputStreamTests.m                                \
+  objectivec/Tests/GPBCodedOuputStreamTests.m                                \
+  objectivec/Tests/GPBConcurrencyTests.m                                     \
+  objectivec/Tests/GPBDescriptorTests.m                                      \
+  objectivec/Tests/GPBDictionaryTests+Bool.m                                 \
+  objectivec/Tests/GPBDictionaryTests+Int32.m                                \
+  objectivec/Tests/GPBDictionaryTests+Int64.m                                \
+  objectivec/Tests/GPBDictionaryTests+String.m                               \
+  objectivec/Tests/GPBDictionaryTests+UInt32.m                               \
+  objectivec/Tests/GPBDictionaryTests+UInt64.m                               \
+  objectivec/Tests/GPBDictionaryTests.pddm                                   \
+  objectivec/Tests/GPBMessageTests+Merge.m                                   \
+  objectivec/Tests/GPBMessageTests+Runtime.m                                 \
+  objectivec/Tests/GPBMessageTests+Serialization.m                           \
+  objectivec/Tests/GPBMessageTests.m                                         \
+  objectivec/Tests/GPBObjectiveCPlusPlusTest.mm                              \
+  objectivec/Tests/GPBPerfTests.m                                            \
+  objectivec/Tests/GPBSwiftTests.swift                                       \
+  objectivec/Tests/GPBTestUtilities.h                                        \
+  objectivec/Tests/GPBTestUtilities.m                                        \
+  objectivec/Tests/GPBUnittestProtos.m                                       \
+  objectivec/Tests/GPBUnknownFieldSetTest.m                                  \
+  objectivec/Tests/GPBUtilitiesTests.m                                       \
+  objectivec/Tests/GPBWellKnownTypesTest.m                                   \
+  objectivec/Tests/GPBWireFormatTests.m                                      \
+  objectivec/Tests/iOSTestHarness/AppDelegate.m                              \
+  objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings                 \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json      \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png          \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6_2x.png       \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png          \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7_2x.png       \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png        \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6_2x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_2x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_3x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json \
+  objectivec/Tests/iOSTestHarness/Info.plist                                  \
+  objectivec/Tests/iOSTestHarness/LaunchScreen.xib                            \
+  objectivec/Tests/text_format_map_unittest_data.txt                          \
+  objectivec/Tests/text_format_unittest_data.txt                              \
+  objectivec/Tests/unittest_cycle.proto                                       \
+  objectivec/Tests/unittest_objc.proto                                        \
+  objectivec/Tests/unittest_objc_startup.proto                                \
+  objectivec/Tests/unittest_runtime_proto2.proto                              \
+  objectivec/Tests/unittest_runtime_proto3.proto                              \
+  objectivec/Tests/UnitTests-Bridging-Header.h                                \
+  objectivec/Tests/UnitTests-Info.plist                                       \
+  Protobuf.podspec
+
+python_EXTRA_DIST=                                                           \
+  python/MANIFEST.in                                                         \
+  python/google/__init__.py                                                  \
+  python/google/protobuf/__init__.py                                         \
+  python/google/protobuf/descriptor.py                                       \
+  python/google/protobuf/descriptor_database.py                              \
+  python/google/protobuf/descriptor_pool.py                                  \
+  python/google/protobuf/internal/__init__.py                                \
+  python/google/protobuf/internal/_parameterized.py                          \
+  python/google/protobuf/internal/any_test.proto                             \
+  python/google/protobuf/internal/any_test.proto                             \
   python/google/protobuf/internal/api_implementation.cc                      \
   python/google/protobuf/internal/api_implementation.py                      \
-  python/google/protobuf/internal/api_implementation_default_test.py         \
   python/google/protobuf/internal/containers.py                              \
-  python/google/protobuf/internal/cpp_message.py                             \
   python/google/protobuf/internal/decoder.py                                 \
   python/google/protobuf/internal/descriptor_database_test.py                \
   python/google/protobuf/internal/descriptor_pool_test.py                    \
   python/google/protobuf/internal/descriptor_pool_test1.proto                \
   python/google/protobuf/internal/descriptor_pool_test2.proto                \
-  python/google/protobuf/internal/descriptor_python_test.py                  \
   python/google/protobuf/internal/descriptor_test.py                         \
   python/google/protobuf/internal/encoder.py                                 \
   python/google/protobuf/internal/enum_type_wrapper.py                       \
   python/google/protobuf/internal/factory_test1.proto                        \
   python/google/protobuf/internal/factory_test2.proto                        \
   python/google/protobuf/internal/generator_test.py                          \
-  python/google/protobuf/internal/message_factory_python_test.py             \
+  python/google/protobuf/internal/import_test_package/__init__.py            \
+  python/google/protobuf/internal/import_test_package/inner.proto            \
+  python/google/protobuf/internal/import_test_package/outer.proto            \
+  python/google/protobuf/internal/json_format_test.py                        \
   python/google/protobuf/internal/message_factory_test.py                    \
   python/google/protobuf/internal/message_listener.py                        \
-  python/google/protobuf/internal/message_python_test.py                     \
+  python/google/protobuf/internal/message_set_extensions.proto               \
   python/google/protobuf/internal/message_test.py                            \
   python/google/protobuf/internal/missing_enum_values.proto                  \
   python/google/protobuf/internal/more_extensions.proto                      \
   python/google/protobuf/internal/more_extensions_dynamic.proto              \
   python/google/protobuf/internal/more_messages.proto                        \
+  python/google/protobuf/internal/packed_field_test.proto                    \
+  python/google/protobuf/internal/proto_builder_test.py                      \
   python/google/protobuf/internal/python_message.py                          \
   python/google/protobuf/internal/reflection_test.py                         \
   python/google/protobuf/internal/service_reflection_test.py                 \
@@ -204,51 +574,183 @@
   python/google/protobuf/internal/text_format_test.py                        \
   python/google/protobuf/internal/type_checkers.py                           \
   python/google/protobuf/internal/unknown_fields_test.py                     \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types_test.py                   \
+  python/google/protobuf/internal/well_known_types_test.py                   \
   python/google/protobuf/internal/wire_format.py                             \
   python/google/protobuf/internal/wire_format_test.py                        \
-  python/google/protobuf/internal/__init__.py                                \
+  python/google/protobuf/json_format.py                                      \
+  python/google/protobuf/message.py                                          \
+  python/google/protobuf/message_factory.py                                  \
+  python/google/protobuf/proto_builder.py                                    \
   python/google/protobuf/pyext/README                                        \
+  python/google/protobuf/pyext/__init__.py                                   \
   python/google/protobuf/pyext/cpp_message.py                                \
-  python/google/protobuf/pyext/descriptor.h                                  \
   python/google/protobuf/pyext/descriptor.cc                                 \
-  python/google/protobuf/pyext/descriptor_cpp2_test.py                       \
-  python/google/protobuf/pyext/extension_dict.h                              \
+  python/google/protobuf/pyext/descriptor.h                                  \
+  python/google/protobuf/pyext/descriptor_containers.cc                      \
+  python/google/protobuf/pyext/descriptor_containers.h                       \
+  python/google/protobuf/pyext/descriptor_database.cc                        \
+  python/google/protobuf/pyext/descriptor_database.h                         \
+  python/google/protobuf/pyext/descriptor_pool.cc                            \
+  python/google/protobuf/pyext/descriptor_pool.h                             \
   python/google/protobuf/pyext/extension_dict.cc                             \
-  python/google/protobuf/pyext/message.h                                     \
+  python/google/protobuf/pyext/extension_dict.h                              \
+  python/google/protobuf/pyext/map_container.cc                              \
+  python/google/protobuf/pyext/map_container.h                               \
   python/google/protobuf/pyext/message.cc                                    \
-  python/google/protobuf/pyext/message_factory_cpp2_test.py                  \
+  python/google/protobuf/pyext/message.h                                     \
   python/google/protobuf/pyext/proto2_api_test.proto                         \
   python/google/protobuf/pyext/python.proto                                  \
   python/google/protobuf/pyext/python_protobuf.h                             \
-  python/google/protobuf/pyext/reflection_cpp2_generated_test.py             \
-  python/google/protobuf/pyext/repeated_composite_container.h                \
   python/google/protobuf/pyext/repeated_composite_container.cc               \
-  python/google/protobuf/pyext/repeated_scalar_container.h                   \
+  python/google/protobuf/pyext/repeated_composite_container.h                \
   python/google/protobuf/pyext/repeated_scalar_container.cc                  \
+  python/google/protobuf/pyext/repeated_scalar_container.h                   \
   python/google/protobuf/pyext/scoped_pyobject_ptr.h                         \
-  python/google/protobuf/pyext/__init__.py                                   \
-  python/google/protobuf/descriptor.py                                       \
-  python/google/protobuf/descriptor_database.py                              \
-  python/google/protobuf/descriptor_pool.py                                  \
-  python/google/protobuf/message.py                                          \
-  python/google/protobuf/message_factory.py                                  \
   python/google/protobuf/reflection.py                                       \
   python/google/protobuf/service.py                                          \
   python/google/protobuf/service_reflection.py                               \
   python/google/protobuf/symbol_database.py                                  \
   python/google/protobuf/text_encoding.py                                    \
   python/google/protobuf/text_format.py                                      \
-  python/google/protobuf/__init__.py                                         \
-  python/google/__init__.py                                                  \
-  python/ez_setup.py                                                         \
-  python/setup.py                                                            \
   python/mox.py                                                              \
+  python/setup.py                                                            \
   python/stubout.py                                                          \
-  python/README.txt
+  python/tox.ini                                                             \
+  python/README.md
+
+ruby_EXTRA_DIST=                                                             \
+  ruby/Gemfile                                                               \
+  ruby/Gemfile.lock                                                          \
+  ruby/.gitignore                                                            \
+  ruby/README.md                                                             \
+  ruby/Rakefile                                                              \
+  ruby/ext/google/protobuf_c/defs.c                                          \
+  ruby/ext/google/protobuf_c/encode_decode.c                                 \
+  ruby/ext/google/protobuf_c/extconf.rb                                      \
+  ruby/ext/google/protobuf_c/map.c                                           \
+  ruby/ext/google/protobuf_c/message.c                                       \
+  ruby/ext/google/protobuf_c/protobuf.c                                      \
+  ruby/ext/google/protobuf_c/protobuf.h                                      \
+  ruby/ext/google/protobuf_c/repeated_field.c                                \
+  ruby/ext/google/protobuf_c/storage.c                                       \
+  ruby/ext/google/protobuf_c/upb.c                                           \
+  ruby/ext/google/protobuf_c/upb.h                                           \
+  ruby/google-protobuf.gemspec                                               \
+  ruby/lib/google/protobuf/message_exts.rb                                   \
+  ruby/lib/google/protobuf/repeated_field.rb                                 \
+  ruby/lib/google/protobuf.rb                                                \
+  ruby/pom.xml                                                               \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java              \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java           \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java   \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java                 \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java      \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java                  \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java              \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java  \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java      \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java             \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java        \
+  ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/Utils.java                    \
+  ruby/src/main/java/google/ProtobufJavaService.java                         \
+  ruby/src/main/sentinel.proto                                               \
+  ruby/tests/basic.rb                                                        \
+  ruby/tests/repeated_field_test.rb                                          \
+  ruby/tests/stress.rb                                                       \
+  ruby/tests/generated_code.proto                                            \
+  ruby/tests/generated_code_test.rb                                          \
+  ruby/travis-test.sh
+
+js_EXTRA_DIST=              \
+  js/README.md              \
+  js/binary/arith.js        \
+  js/binary/arith_test.js   \
+  js/binary/constants.js    \
+  js/binary/decoder.js      \
+  js/binary/decoder_test.js \
+  js/binary/proto_test.js   \
+  js/binary/reader.js       \
+  js/binary/reader_test.js  \
+  js/binary/utils.js        \
+  js/binary/utils_test.js   \
+  js/binary/writer.js       \
+  js/binary/writer_test.js  \
+  js/data.proto             \
+  js/debug.js               \
+  js/debug_test.js          \
+  js/gulpfile.js            \
+  js/jasmine.json           \
+  js/message.js             \
+  js/message_test.js        \
+  js/node_loader.js         \
+  js/package.json           \
+  js/proto3_test.js         \
+  js/proto3_test.proto      \
+  js/test.proto             \
+  js/test2.proto            \
+  js/test3.proto            \
+  js/test4.proto            \
+  js/test5.proto            \
+  js/test_bootstrap.js      \
+  js/testbinary.proto       \
+  js/testempty.proto
+
+all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) $(js_EXTRA_DIST)
+
+EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)   \
+  autogen.sh                             \
+  generate_descriptor_proto.sh           \
+  README.md                              \
+  LICENSE                                \
+  CONTRIBUTORS.txt                       \
+  CHANGES.txt                            \
+  update_file_lists.sh                   \
+  BUILD                                  \
+  gmock.BUILD                            \
+  WORKSPACE                              \
+  cmake/CMakeLists.txt                   \
+  cmake/README.md                        \
+  cmake/extract_includes.bat.in          \
+  cmake/install.cmake                    \
+  cmake/libprotobuf.cmake                \
+  cmake/libprotobuf-lite.cmake           \
+  cmake/libprotoc.cmake                  \
+  cmake/protobuf-config-version.cmake.in \
+  cmake/protobuf-config.cmake.in         \
+  cmake/protobuf-module.cmake.in         \
+  cmake/protoc.cmake                     \
+  cmake/tests.cmake                      \
+  editors/README.txt                     \
+  editors/proto.vim                      \
+  editors/protobuf-mode.el               \
+  examples/README.txt                    \
+  examples/Makefile                      \
+  examples/addressbook.proto             \
+  examples/add_person.cc                 \
+  examples/add_person.go                 \
+  examples/add_person_test.go            \
+  examples/list_people.cc                \
+  examples/list_people.go                \
+  examples/AddPerson.java                \
+  examples/ListPeople.java               \
+  examples/add_person.py                 \
+  examples/list_people.py                \
+  examples/list_people_test.go           \
+  protobuf.bzl                           \
+  six.BUILD                              \
+  util/python/BUILD
 
 # Deletes all the files generated by autogen.sh.
 MAINTAINERCLEANFILES =   \
   aclocal.m4             \
+  ar-lib                 \
   config.guess           \
   config.sub             \
   configure              \
diff --git a/Makefile.in b/Makefile.in
index 93d7a44..bac04e3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -407,7 +407,6 @@
   java/src/main/java/com/google/protobuf/AbstractParser.java                 \
   java/src/main/java/com/google/protobuf/BlockingRpcChannel.java             \
   java/src/main/java/com/google/protobuf/BlockingService.java                \
-  java/src/main/java/com/google/protobuf/BoundedByteString.java              \
   java/src/main/java/com/google/protobuf/ByteString.java                     \
   java/src/main/java/com/google/protobuf/CodedInputStream.java               \
   java/src/main/java/com/google/protobuf/CodedOutputStream.java              \
@@ -425,7 +424,6 @@
   java/src/main/java/com/google/protobuf/LazyFieldLite.java                  \
   java/src/main/java/com/google/protobuf/LazyStringArrayList.java            \
   java/src/main/java/com/google/protobuf/LazyStringList.java                 \
-  java/src/main/java/com/google/protobuf/LiteralByteString.java              \
   java/src/main/java/com/google/protobuf/Message.java                        \
   java/src/main/java/com/google/protobuf/MessageLite.java                    \
   java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java           \
diff --git a/Protobuf.podspec b/Protobuf.podspec
new file mode 100644
index 0000000..0bbd06d
--- /dev/null
+++ b/Protobuf.podspec
@@ -0,0 +1,40 @@
+# This file describes to Cocoapods how to integrate the Objective-C runtime into a dependent
+# project.
+# Despite this file being specific to Objective-C, it needs to be on the root of the repository.
+# Otherwise, Cocoapods gives trouble like not picking up the license file correctly, or not letting
+# dependent projects use the :git notation to refer to the library.
+Pod::Spec.new do |s|
+  s.name     = 'Protobuf'
+  s.version  = '3.0.0-beta-2'
+  s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
+  s.homepage = 'https://github.com/google/protobuf'
+  s.license  = 'New BSD'
+  s.authors  = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
+
+  s.source = { :git => 'https://github.com/google/protobuf.git',
+               :tag => "v#{s.version}" }
+
+  s.source_files = 'objectivec/*.{h,m}',
+                   'objectivec/google/protobuf/Any.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Api.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Duration.pbobjc.h',
+                   'objectivec/google/protobuf/Empty.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/FieldMask.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/SourceContext.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Struct.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Timestamp.pbobjc.h',
+                   'objectivec/google/protobuf/Type.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Wrappers.pbobjc.{h,m}'
+  # Timestamp.pbobjc.m and Duration.pbobjc.m are #imported by GPBWellKnownTypes.m. So we can't
+  # compile them (duplicate symbols), but we need them available for the importing:
+  s.preserve_paths = 'objectivec/google/protobuf/Duration.pbobjc.m',
+                     'objectivec/google/protobuf/Timestamp.pbobjc.m'
+  # The following would cause duplicate symbol definitions. GPBProtocolBuffers is expected to be
+  # left out, as it's an umbrella implementation file.
+  s.exclude_files = 'objectivec/GPBProtocolBuffers.m'
+  s.header_mappings_dir = 'objectivec'
+
+  s.ios.deployment_target = '7.1'
+  s.osx.deployment_target = '10.9'
+  s.requires_arc = false
+end
diff --git a/README.md b/README.md
index 5fbb344..ba9c589 100644
--- a/README.md
+++ b/README.md
@@ -1,162 +1,72 @@
 Protocol Buffers - Google's data interchange format
 ===================================================
 
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
+
 Copyright 2008 Google Inc.
 
 https://developers.google.com/protocol-buffers/
 
-C++ Installation - Unix
------------------------
+Overview
+--------
 
-If you get the source from github, you need to generate the configure script
-first:
+Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
+platform-neutral, extensible mechanism for serializing structured data. You
+can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
 
-    $ ./autogen.sh
+This README file contains protobuf installation instructions. To install
+protobuf, you need to install the protocol compiler (used to compile .proto
+files) and the protobuf runtime for your chosen programming language.
 
-This will download gtest source (which is used for C++ Protocol Buffer
-unit-tests) to the current directory and run automake, autoconf, etc.
-to generate the configure script and various template makefiles.
+Protocol Compiler Installation
+------------------------------
 
-You can skip this step if you are using a release package (which already
-contains gtest and the configure script).
+The protocol compiler is written in C++. If you are using C++, please follow
+the [C++ Installation Instructions](src/README.md) to install protoc along
+with the C++ runtime.
 
-To build and install the C++ Protocol Buffer runtime and the Protocol
-Buffer compiler (protoc) execute the following:
+For non-C++ users, the simplest way to install the protocol compiler is to
+download a pre-built binary from our release page:
 
-    $ ./configure
-    $ make
-    $ make check
-    $ make install
+  [https://github.com/google/protobuf/releases](https://github.com/google/protobuf/releases)
 
-If "make check" fails, you can still install, but it is likely that
-some features of this library will not work correctly on your system.
-Proceed at your own risk.
+In the downloads section of each release, you can find pre-built binaries in
+zip packages: protoc-$VERSION-$PLATFORM.zip. It contains the protoc binary
+as well as a set of standard .proto files distributed along with protobuf.
 
-"make install" may require superuser privileges.
+If you are looking for an old version that is not available in the release
+page, check out the maven repo here:
 
-For advanced usage information on configure and make, see INSTALL.txt.
+  [http://repo1.maven.org/maven2/com/google/protobuf/protoc/](http://repo1.maven.org/maven2/com/google/protobuf/protoc/)
 
-**Hint on install location**
+These pre-built binaries are only provided for released versions. If you want
+to use the github master version at HEAD, or you need to modify protobuf code,
+or you are using C++, it's recommended to build your own protoc binary from
+source.
 
-  By default, the package will be installed to /usr/local.  However,
-  on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
-  You can add it, but it may be easier to just install to /usr
-  instead.  To do this, invoke configure as follows:
+If you would like to build protoc binary from source, see the [C++ Installation
+Instructions](src/README.md).
 
-    ./configure --prefix=/usr
+Protobuf Runtime Installation
+-----------------------------
 
-  If you already built the package with a different prefix, make sure
-  to run "make clean" before building again.
+Protobuf supports several different programming languages. For each programming
+language, you can find instructions in the corresponding source directory about
+how to install protobuf runtime for that specific language:
 
-**Compiling dependent packages**
+| Language                             | Source                                                |
+|--------------------------------------|-------------------------------------------------------|
+| C++ (include C++ runtime and protoc) | [src](src)                                            |
+| Java                                 | [java](java)                                          |
+| Python                               | [python](python)                                      |
+| Objective-C                          | [objectivec](objectivec)                              |
+| C#                                   | [csharp](csharp)                                      |
+| JavaNano                             | [javanano](javanano)                                  |
+| JavaScript                           | [js](js)                                              |
+| Ruby                                 | [ruby](ruby)                                          |
+| Go                                   | [golang/protobuf](https://github.com/golang/protobuf) |
+| PHP                                  | TBD                                                   |
 
-  To compile a package that uses Protocol Buffers, you need to pass
-  various flags to your compiler and linker.  As of version 2.2.0,
-  Protocol Buffers integrates with pkg-config to manage this.  If you
-  have pkg-config installed, then you can invoke it to get a list of
-  flags like so:
-
-    pkg-config --cflags protobuf         # print compiler flags
-    pkg-config --libs protobuf           # print linker flags
-    pkg-config --cflags --libs protobuf  # print both
-
-  For example:
-
-    c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
-
-  Note that packages written prior to the 2.2.0 release of Protocol
-  Buffers may not yet integrate with pkg-config to get flags, and may
-  not pass the correct set of flags to correctly link against
-  libprotobuf.  If the package in question uses autoconf, you can
-  often fix the problem by invoking its configure script like:
-
-    configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
-              LIBS="$(pkg-config --libs protobuf)"
-
-  This will force it to use the correct flags.
-
-  If you are writing an autoconf-based package that uses Protocol
-  Buffers, you should probably use the PKG_CHECK_MODULES macro in your
-  configure script like:
-
-    PKG_CHECK_MODULES([protobuf], [protobuf])
-
-  See the pkg-config man page for more info.
-
-  If you only want protobuf-lite, substitute "protobuf-lite" in place
-  of "protobuf" in these examples.
-
-**Note for cross-compiling**
-
-  The makefiles normally invoke the protoc executable that they just
-  built in order to build tests.  When cross-compiling, the protoc
-  executable may not be executable on the host machine.  In this case,
-  you must build a copy of protoc for the host machine first, then use
-  the --with-protoc option to tell configure to use it instead.  For
-  example:
-
-    ./configure --with-protoc=protoc
-
-  This will use the installed protoc (found in your $PATH) instead of
-  trying to execute the one built during the build process.  You can
-  also use an executable that hasn't been installed.  For example, if
-  you built the protobuf package for your host machine in ../host,
-  you might do:
-
-    ./configure --with-protoc=../host/src/protoc
-
-  Either way, you must make sure that the protoc executable you use
-  has the same version as the protobuf source code you are trying to
-  use it with.
-
-**Note for Solaris users**
-
-  Solaris 10 x86 has a bug that will make linking fail, complaining
-  about libstdc++.la being invalid.  We have included a work-around
-  in this package.  To use the work-around, run configure as follows:
-
-    ./configure LDFLAGS=-L$PWD/src/solaris
-
-  See src/solaris/libstdc++.la for more info on this bug.
-
-**Note for HP C++ Tru64 users**
-
-  To compile invoke configure as follows:
-
-    ./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
-
-  Also, you will need to use gmake instead of make.
-
-C++ Installation - Windows
---------------------------
-
-If you are using Microsoft Visual C++, see vsprojects/readme.txt.
-
-If you are using Cygwin or MinGW, follow the Unix installation
-instructions, above.
-
-Binary Compatibility Warning
-----------------------------
-
-Due to the nature of C++, it is unlikely that any two versions of the
-Protocol Buffers C++ runtime libraries will have compatible ABIs.
-That is, if you linked an executable against an older version of
-libprotobuf, it is unlikely to work with a newer version without
-re-compiling.  This problem, when it occurs, will normally be detected
-immediately on startup of your app.  Still, you may want to consider
-using static linkage.  You can configure this package to install
-static libraries only using:
-
-    ./configure --disable-shared
-
-Java and Python Installation
-----------------------------
-
-The Java and Python runtime libraries for Protocol Buffers are located
-in the java and python directories.  See the README file in each
-directory for more information on how to compile and install them.
-Note that both of them require you to first install the Protocol
-Buffer compiler (protoc), which is part of the C++ package.
 
 Usage
 -----
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..065dc81
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,53 @@
+new_http_archive(
+    name = "gmock_archive",
+    url = "https://googlemock.googlecode.com/files/gmock-1.7.0.zip",
+    sha256 = "26fcbb5925b74ad5fc8c26b0495dfc96353f4d553492eb97e85a8a6d2f43095b",
+    build_file = "gmock.BUILD",
+)
+
+new_http_archive(
+    name = "six_archive",
+    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
+    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
+    build_file = "six.BUILD",
+)
+
+bind(
+    name = "python_headers",
+    actual = "//util/python:python_headers",
+)
+
+bind(
+    name = "gtest",
+    actual = "@gmock_archive//:gtest",
+)
+
+bind(
+    name = "gtest_main",
+    actual = "@gmock_archive//:gtest_main",
+)
+
+bind(
+    name = "six",
+    actual = "@six_archive//:six",
+)
+
+maven_jar(
+  name = "guava_maven",
+  artifact = "com.google.guava:guava:18.0",
+)
+
+bind(
+    name = "guava",
+    actual = "@guava_maven//jar",
+)
+
+maven_jar(
+  name = "gson_maven",
+  artifact = "com.google.code.gson:gson:2.3",
+)
+
+bind(
+    name = "gson",
+    actual = "@gson_maven//jar",
+)
diff --git a/appveyor.bat b/appveyor.bat
new file mode 100644
index 0000000..9a46b92
--- /dev/null
+++ b/appveyor.bat
@@ -0,0 +1,29 @@
+setlocal
+
+IF %language%==cpp GOTO build_cpp
+IF %language%==csharp GOTO build_csharp
+
+echo Unsupported language %language%. Exiting.
+goto :error
+
+:build_cpp
+echo Building C++
+mkdir build_msvc
+cd build_msvc
+cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
+msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
+cd %configuration%
+tests.exe || goto error
+goto :EOF
+
+:build_csharp
+echo Building C#
+cd csharp\src
+nuget restore
+msbuild Google.Protobuf.sln /p:Platform="Any CPU" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
+nunit-console Google.Protobuf.Test\bin\%configuration%\Google.Protobuf.Test.dll || goto error
+goto :EOF
+
+:error
+echo Failed!
+EXIT /b %ERRORLEVEL%
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..c84ecae
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,32 @@
+# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can
+# test more combinations but AppVeyor just takes too long to finish (each
+# combination takes ~15mins).
+platform:
+  - Win64
+
+configuration:
+  - Debug
+
+environment:
+  matrix:
+    - language: cpp
+      BUILD_DLL: ON
+
+    - language: csharp
+
+install:
+  - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+  - 7z x gmock-1.7.0.zip
+  - rename gmock-1.7.0 gmock
+
+before_build:
+  - if %platform%==Win32 set generator=Visual Studio 12
+  - if %platform%==Win64 set generator=Visual Studio 12 Win64
+  - if %platform%==Win32 set vcplatform=Win32
+  - if %platform%==Win64 set vcplatform=x64
+
+build_script:
+  - CALL appveyor.bat
+
+skip_commits:
+  message: /.*\[skip appveyor\].*/
diff --git a/autogen.sh b/autogen.sh
index c3e026d..5b4c29f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -6,6 +6,18 @@
 
 set -e
 
+if [ ! -z "$@" ]; then
+  for argument in "$@"; do
+    case $argument in
+	  # make curl silent
+      "-s")
+        curlopts="-s"
+        ;;
+    esac
+  done
+fi
+
+
 # Check that we're being run from the right directory.
 if test ! -f src/google/protobuf/stubs/common.h; then
   cat >&2 << __EOF__
@@ -15,25 +27,18 @@
   exit 1
 fi
 
-# Check that gtest is present.  Usually it is already there since the
+# Check that gmock is present.  Usually it is already there since the
 # directory is set up as an SVN external.
-if test ! -e gtest; then
-  echo "Google Test not present.  Fetching gtest-1.5.0 from the web..."
-  curl http://googletest.googlecode.com/files/gtest-1.5.0.tar.bz2 | tar jx
-  mv gtest-1.5.0 gtest
+if test ! -e gmock; then
+  echo "Google Mock not present.  Fetching gmock-1.7.0 from the web..."
+  curl $curlopts -O https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+  unzip -q gmock-1.7.0.zip
+  rm gmock-1.7.0.zip
+  mv gmock-1.7.0 gmock
 fi
 
 set -ex
 
-# Temporary hack:  Must change C runtime library to "multi-threaded DLL",
-#   otherwise it will be set to "multi-threaded static" when MSVC upgrades
-#   the project file to MSVC 2005/2008.  vladl of Google Test says gtest will
-#   probably change their default to match, then this will be unnecessary.
-#   One of these mappings converts the debug configuration and the other
-#   converts the release configuration.  I don't know which is which.
-sed -i -e 's/RuntimeLibrary="5"/RuntimeLibrary="3"/g;
-           s/RuntimeLibrary="4"/RuntimeLibrary="2"/g;' gtest/msvc/*.vcproj
-
 # TODO(kenton):  Remove the ",no-obsolete" part and fix the resulting warnings.
 autoreconf -f -i -Wall,no-obsolete
 
diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
new file mode 100644
index 0000000..f730afe
--- /dev/null
+++ b/benchmarks/Makefile.am
@@ -0,0 +1,69 @@
+
+benchmarks_protoc_inputs =                                     \
+  benchmarks.proto                                             \
+  benchmark_messages_proto3.proto
+
+benchmarks_protoc_inputs_proto2 =                              \
+  benchmark_messages_proto2.proto
+
+benchmarks_protoc_outputs =                                    \
+  benchmarks.pb.cc                                             \
+  benchmarks.pb.h                                              \
+  benchmark_messages_proto3.pb.cc                              \
+  benchmark_messages_proto3.pb.h
+
+benchmarks_protoc_outputs_proto2 =                             \
+  benchmark_messages_proto2.pb.cc                              \
+  benchmark_messages_proto2.pb.h
+
+bin_PROGRAMS = generate-datasets
+
+generate_datasets_LDADD = $(top_srcdir)/src/libprotobuf.la
+generate_datasets_SOURCES = generate_datasets.cc
+generate_datasets_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir)
+nodist_generate_datasets_SOURCES =                             \
+  $(benchmarks_protoc_outputs)                                 \
+  $(benchmarks_protoc_outputs_proto2)
+
+# Explicit deps because BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_cpp" could fail if parallel enough.
+# See: https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually
+generate_datasets-generate_datasets.$(OBJEXT): benchmarks.pb.h
+
+$(benchmarks_protoc_outputs): protoc_middleman
+$(benchmarks_protoc_outputs_proto2): protoc_middleman2
+
+CLEANFILES =                                                   \
+  $(benchmarks_protoc_outputs)                                 \
+  $(benchmarks_protoc_outputs_proto2)                          \
+  protoc_middleman                                             \
+  protoc_middleman2                                            \
+  dataset.*
+
+MAINTAINERCLEANFILES =   \
+  Makefile.in
+
+if USE_EXTERNAL_PROTOC
+
+protoc_middleman: $(benchmarks_protoc_inputs)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. $(benchmarks_protoc_inputs)
+	touch protoc_middleman
+
+protoc_middleman2: $(benchmarks_protoc_inputs_proto2)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. $(benchmarks_protoc_inputs_proto2)
+	touch protoc_middleman2
+
+else
+
+# We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
+# relative to srcdir, which may not be the same as the current directory when
+# building out-of-tree.
+protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(benchmarks_protoc_inputs) $(well_known_type_protoc_inputs)
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd $(benchmarks_protoc_inputs) )
+	touch protoc_middleman
+
+protoc_middleman2: $(top_srcdir)/src/protoc$(EXEEXT) $(benchmarks_protoc_inputs_proto2) $(well_known_type_protoc_inputs)
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd $(benchmarks_protoc_inputs_proto2) )
+	touch protoc_middleman
+
+endif
diff --git a/benchmarks/README.md b/benchmarks/README.md
new file mode 100644
index 0000000..c902780
--- /dev/null
+++ b/benchmarks/README.md
@@ -0,0 +1,28 @@
+
+# Protocol Buffers Benchmarks
+
+This directory contains benchmarking schemas and data sets that you
+can use to test a variety of performance scenarios against your
+protobuf language runtime.
+
+The schema for the datasets is described in `benchmarks.proto`.
+
+Generate the data sets like so:
+
+```
+$ make
+$ ./generate-datasets
+Wrote dataset: dataset.google_message1_proto3.pb
+Wrote dataset: dataset.google_message1_proto2.pb
+Wrote dataset: dataset.google_message2.pb
+$
+```
+
+Each data set will be written to its own file.  Benchmarks will
+likely want to run several benchmarks against each data set (parse,
+serialize, possibly JSON, possibly using different APIs, etc).
+
+We would like to add more data sets.  In general we will favor data sets
+that make the overall suite diverse without being too large or having
+too many similar tests.  Ideally everyone can run through the entire
+suite without the test run getting too long.
diff --git a/benchmarks/benchmark_messages_proto2.proto b/benchmarks/benchmark_messages_proto2.proto
new file mode 100644
index 0000000..01f67a1
--- /dev/null
+++ b/benchmarks/benchmark_messages_proto2.proto
@@ -0,0 +1,141 @@
+// Benchmark messages for proto2.
+
+syntax = "proto2";
+
+package benchmarks.proto2;
+option java_package = "com.google.protobuf.benchmarks";
+
+// This is the default, but we specify it here explicitly.
+option optimize_for = SPEED;
+
+message GoogleMessage1 {
+  required string field1 = 1;
+  optional string field9 = 9;
+  optional string field18 = 18;
+  optional bool field80 = 80 [default=false];
+  optional bool field81 = 81 [default=true];
+  required int32 field2 = 2;
+  required int32 field3 = 3;
+  optional int32 field280 = 280;
+  optional int32 field6 = 6 [default=0];
+  optional int64 field22 = 22;
+  optional string field4 = 4;
+  repeated fixed64 field5 = 5;
+  optional bool field59 = 59 [default=false];
+  optional string field7 = 7;
+  optional int32 field16 = 16;
+  optional int32 field130 = 130 [default=0];
+  optional bool field12 = 12 [default=true];
+  optional bool field17 = 17 [default=true];
+  optional bool field13 = 13 [default=true];
+  optional bool field14 = 14 [default=true];
+  optional int32 field104 = 104 [default=0];
+  optional int32 field100 = 100 [default=0];
+  optional int32 field101 = 101 [default=0];
+  optional string field102 = 102;
+  optional string field103 = 103;
+  optional int32 field29 = 29 [default=0];
+  optional bool field30 = 30 [default=false];
+  optional int32 field60 = 60 [default=-1];
+  optional int32 field271 = 271 [default=-1];
+  optional int32 field272 = 272 [default=-1];
+  optional int32 field150 = 150;
+  optional int32 field23 = 23 [default=0];
+  optional bool field24 = 24 [default=false];
+  optional int32 field25 = 25 [default=0];
+  optional GoogleMessage1SubMessage field15 = 15;
+  optional bool field78 = 78;
+  optional int32 field67 = 67 [default=0];
+  optional int32 field68 = 68;
+  optional int32 field128 = 128 [default=0];
+  optional string field129 = 129 [default="xxxxxxxxxxxxxxxxxxxxx"];
+  optional int32 field131 = 131 [default=0];
+}
+
+message GoogleMessage1SubMessage {
+  optional int32 field1 = 1 [default=0];
+  optional int32 field2 = 2 [default=0];
+  optional int32 field3 = 3 [default=0];
+  optional string field15 = 15;
+  optional bool field12 = 12 [default=true];
+  optional int64 field13 = 13;
+  optional int64 field14 = 14;
+  optional int32 field16 = 16;
+  optional int32 field19 = 19 [default=2];
+  optional bool field20  = 20 [default=true];
+  optional bool field28 = 28 [default=true];
+  optional fixed64 field21 = 21;
+  optional int32 field22 = 22;
+  optional bool field23 = 23 [ default=false ];
+  optional bool field206 = 206 [default=false];
+  optional fixed32 field203 = 203;
+  optional int32 field204 = 204;
+  optional string field205 = 205;
+  optional uint64 field207 = 207;
+  optional uint64 field300 = 300;
+}
+
+message GoogleMessage2 {
+  optional string field1 = 1;
+  optional int64 field3 = 3;
+  optional int64 field4 = 4;
+  optional int64 field30 = 30;
+  optional bool field75  = 75 [default=false];
+  optional string field6 = 6;
+  optional bytes field2 = 2;
+  optional int32 field21 = 21 [default=0];
+  optional int32 field71 = 71;
+  optional float field25 = 25;
+  optional int32 field109 = 109 [default=0];
+  optional int32 field210 = 210 [default=0];
+  optional int32 field211 = 211 [default=0];
+  optional int32 field212 = 212 [default=0];
+  optional int32 field213 = 213 [default=0];
+  optional int32 field216 = 216 [default=0];
+  optional int32 field217 = 217 [default=0];
+  optional int32 field218 = 218 [default=0];
+  optional int32 field220 = 220 [default=0];
+  optional int32 field221 = 221 [default=0];
+  optional float field222 = 222 [default=0.0];
+  optional int32 field63 = 63;
+
+  repeated group Group1 = 10 {
+    required float field11 = 11;
+    optional float field26 = 26;
+    optional string field12 = 12;
+    optional string field13 = 13;
+    repeated string field14 = 14;
+    required uint64 field15 = 15;
+    optional int32 field5 = 5;
+    optional string field27 = 27;
+    optional int32 field28 = 28;
+    optional string field29 = 29;
+    optional string field16 = 16;
+    repeated string field22 = 22;
+    repeated int32 field73 = 73;
+    optional int32 field20 = 20 [default=0];
+    optional string field24 = 24;
+    optional GoogleMessage2GroupedMessage field31 = 31;
+  }
+  repeated string field128 = 128;
+  optional int64 field131 = 131;
+  repeated string field127 = 127;
+  optional int32 field129 = 129;
+  repeated int64 field130 = 130;
+  optional bool field205 = 205 [default=false];
+  optional bool field206 = 206 [default=false];
+}
+
+message GoogleMessage2GroupedMessage {
+  optional float field1 = 1;
+  optional float field2 = 2;
+  optional float field3 = 3 [default=0.0];
+  optional bool field4 = 4;
+  optional bool field5 = 5;
+  optional bool field6 = 6 [default=true];
+  optional bool field7 = 7 [default=false];
+  optional float field8 = 8;
+  optional bool field9 = 9;
+  optional float field10 = 10;
+  optional int64 field11 = 11;
+}
diff --git a/benchmarks/benchmark_messages_proto3.proto b/benchmarks/benchmark_messages_proto3.proto
new file mode 100644
index 0000000..32f5869
--- /dev/null
+++ b/benchmarks/benchmark_messages_proto3.proto
@@ -0,0 +1,76 @@
+// Benchmark messages for proto3.
+
+syntax = "proto3";
+
+package benchmarks.proto3;
+option java_package = "com.google.protobuf.benchmarks";
+
+// This is the default, but we specify it here explicitly.
+option optimize_for = SPEED;
+
+message GoogleMessage1 {
+  string field1 = 1;
+  string field9 = 9;
+  string field18 = 18;
+  bool field80 = 80;
+  bool field81 = 81;
+  int32 field2 = 2;
+  int32 field3 = 3;
+  int32 field280 = 280;
+  int32 field6 = 6;
+  int64 field22 = 22;
+  string field4 = 4;
+  repeated fixed64 field5 = 5;
+  bool field59 = 59;
+  string field7 = 7;
+  int32 field16 = 16;
+  int32 field130 = 130;
+  bool field12 = 12;
+  bool field17 = 17;
+  bool field13 = 13;
+  bool field14 = 14;
+  int32 field104 = 104;
+  int32 field100 = 100;
+  int32 field101 = 101;
+  string field102 = 102;
+  string field103 = 103;
+  int32 field29 = 29;
+  bool field30 = 30;
+  int32 field60 = 60;
+  int32 field271 = 271;
+  int32 field272 = 272;
+  int32 field150 = 150;
+  int32 field23 = 23;
+  bool field24 = 24;
+  int32 field25 = 25;
+  GoogleMessage1SubMessage field15 = 15;
+  bool field78 = 78;
+  int32 field67 = 67;
+  int32 field68 = 68;
+  int32 field128 = 128;
+  string field129 = 129;
+  int32 field131 = 131;
+}
+
+message GoogleMessage1SubMessage {
+  int32 field1 = 1;
+  int32 field2 = 2;
+  int32 field3 = 3;
+  string field15 = 15;
+  bool field12 = 12;
+  int64 field13 = 13;
+  int64 field14 = 14;
+  int32 field16 = 16;
+  int32 field19 = 19;
+  bool field20  = 20;
+  bool field28 = 28;
+  fixed64 field21 = 21;
+  int32 field22 = 22;
+  bool field23 = 23;
+  bool field206 = 206;
+  fixed32 field203 = 203;
+  int32 field204 = 204;
+  string field205 = 205;
+  uint64 field207 = 207;
+  uint64 field300 = 300;
+}
diff --git a/benchmarks/benchmarks.proto b/benchmarks/benchmarks.proto
new file mode 100644
index 0000000..51c0b54
--- /dev/null
+++ b/benchmarks/benchmarks.proto
@@ -0,0 +1,63 @@
+// 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.
+
+syntax = "proto3";
+package benchmarks;
+option java_package = "com.google.protobuf.benchmarks";
+
+message BenchmarkDataset {
+  // Name of the benchmark dataset.  This should be unique across all datasets.
+  // Should only contain word characters: [a-zA-Z0-9_]
+  string name = 1;
+
+  // Fully-qualified name of the protobuf message for this dataset.
+  // It will be one of the messages defined benchmark_messages_proto2.proto
+  // or benchmark_messages_proto3.proto.
+  //
+  // Implementations that do not support reflection can implement this with
+  // an explicit "if/else" chain that lists every known message defined
+  // in those files.
+  string message_name = 2;
+
+  // The payload(s) for this dataset.  They should be parsed or serialized
+  // in sequence, in a loop, ie.
+  //
+  //  while (!benchmarkDone) {  // Benchmark runner decides when to exit.
+  //    for (i = 0; i < benchmark.payload.length; i++) {
+  //      parse(benchmark.payload[i])
+  //    }
+  //  }
+  //
+  // This is intended to let datasets include a variety of data to provide
+  // potentially more realistic results than just parsing the same message
+  // over and over.  A single message parsed repeatedly could yield unusually
+  // good branch prediction performance.
+  repeated bytes payload = 3;
+}
diff --git a/benchmarks/generate_datasets.cc b/benchmarks/generate_datasets.cc
new file mode 100644
index 0000000..61e7adf
--- /dev/null
+++ b/benchmarks/generate_datasets.cc
@@ -0,0 +1,117 @@
+// 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.
+
+#include <fstream>
+#include <iostream>
+#include "benchmarks.pb.h"
+
+using benchmarks::BenchmarkDataset;
+using google::protobuf::Descriptor;
+using google::protobuf::DescriptorPool;
+using google::protobuf::Message;
+using google::protobuf::MessageFactory;
+
+std::set<std::string> names;
+
+const char *file_prefix = "dataset.";
+const char *file_suffix = ".pb";
+
+void WriteFileWithPayloads(const std::string& name,
+                           const std::string& message_name,
+                           const std::vector<std::string>& payload) {
+  if (!names.insert(name).second) {
+    std::cerr << "Duplicate test name: " << name << "\n";
+    abort();
+  }
+
+  // First verify that this message name exists in our set of benchmark messages
+  // and that these payloads are valid for the given message.
+  const Descriptor* d =
+      DescriptorPool::generated_pool()->FindMessageTypeByName(message_name);
+
+  if (!d) {
+    std::cerr << "For dataset " << name << ", no such message: "
+              << message_name << "\n";
+    abort();
+  }
+
+  Message* m = MessageFactory::generated_factory()->GetPrototype(d)->New();
+
+  for (size_t i = 0; i < payload.size(); i++) {
+    if (!m->ParseFromString(payload[i])) {
+      std::cerr << "For dataset " << name << ", payload[" << i << "] fails "
+                << "to parse\n";
+      abort();
+    }
+  }
+
+  BenchmarkDataset dataset;
+  dataset.set_name(name);
+  dataset.set_message_name(message_name);
+  for (size_t i = 0; i < payload.size(); i++) {
+    dataset.add_payload()->assign(payload[i]);
+  }
+
+  std::ofstream writer;
+  std::string fname = file_prefix + name + file_suffix;
+  writer.open(fname.c_str());
+  dataset.SerializeToOstream(&writer);
+  writer.close();
+
+  std::cerr << "Wrote dataset: " << fname << "\n";
+}
+
+void WriteFile(const std::string& name, const std::string& message_name,
+               const std::string& payload) {
+  std::vector<std::string> payloads;
+  payloads.push_back(payload);
+  WriteFileWithPayloads(name, message_name, payloads);
+}
+
+std::string ReadFile(const std::string& name) {
+  std::ifstream file(name.c_str());
+  GOOGLE_CHECK(file.is_open()) << "Couldn't find file '" << name <<
+                                  "', please make sure you are running "
+                                  "this command from the benchmarks/ "
+                                  "directory.\n";
+  return std::string((std::istreambuf_iterator<char>(file)),
+                     std::istreambuf_iterator<char>());
+}
+
+int main() {
+  WriteFile("google_message1_proto3", "benchmarks.proto3.GoogleMessage1",
+            ReadFile("google_message1.dat"));
+  WriteFile("google_message1_proto2", "benchmarks.proto2.GoogleMessage1",
+            ReadFile("google_message1.dat"));
+
+  // Not in proto3 because it has a group, which is not supported.
+  WriteFile("google_message2", "benchmarks.proto2.GoogleMessage2",
+            ReadFile("google_message2.dat"));
+}
diff --git a/benchmarks/google_size.proto b/benchmarks/google_size.proto
index 3e6fbdb..d2d319f 100644
--- a/benchmarks/google_size.proto
+++ b/benchmarks/google_size.proto
@@ -1,3 +1,5 @@
+syntax = "proto2";
+
 package benchmarks;
 
 option java_outer_classname = "GoogleSize";
diff --git a/benchmarks/google_speed.proto b/benchmarks/google_speed.proto
deleted file mode 100644
index d6cd032..0000000
--- a/benchmarks/google_speed.proto
+++ /dev/null
@@ -1,136 +0,0 @@
-package benchmarks;
-
-option java_outer_classname = "GoogleSpeed";
-option optimize_for = SPEED;
-
-message SpeedMessage1 {
-  required string field1 = 1;
-  optional string field9 = 9;
-  optional string field18 = 18;
-  optional bool field80 = 80 [default=false];
-  optional bool field81 = 81 [default=true];
-  required int32 field2 = 2;
-  required int32 field3 = 3;
-  optional int32 field280 = 280;
-  optional int32 field6 = 6 [default=0];
-  optional int64 field22 = 22;
-  optional string field4 = 4;
-  repeated fixed64 field5 = 5;
-  optional bool field59 = 59 [default=false];
-  optional string field7 = 7;
-  optional int32 field16 = 16;
-  optional int32 field130 = 130 [default=0];
-  optional bool field12 = 12 [default=true];
-  optional bool field17 = 17 [default=true];
-  optional bool field13 = 13 [default=true];
-  optional bool field14 = 14 [default=true];
-  optional int32 field104 = 104 [default=0];
-  optional int32 field100 = 100 [default=0];
-  optional int32 field101 = 101 [default=0];
-  optional string field102 = 102;
-  optional string field103 = 103;
-  optional int32 field29 = 29 [default=0];
-  optional bool field30 = 30 [default=false];
-  optional int32 field60 = 60 [default=-1];
-  optional int32 field271 = 271 [default=-1];
-  optional int32 field272 = 272 [default=-1];
-  optional int32 field150 = 150;
-  optional int32 field23 = 23 [default=0];
-  optional bool field24 = 24 [default=false];
-  optional int32 field25 = 25 [default=0];
-  optional SpeedMessage1SubMessage field15 = 15;
-  optional bool field78 = 78;
-  optional int32 field67 = 67 [default=0];
-  optional int32 field68 = 68;
-  optional int32 field128 = 128 [default=0];
-  optional string field129 = 129 [default="xxxxxxxxxxxxxxxxxxxxx"];
-  optional int32 field131 = 131 [default=0];
-}
-
-message SpeedMessage1SubMessage {
-  optional int32 field1 = 1 [default=0];
-  optional int32 field2 = 2 [default=0];
-  optional int32 field3 = 3 [default=0];
-  optional string field15 = 15;
-  optional bool field12 = 12 [default=true];
-  optional int64 field13 = 13;
-  optional int64 field14 = 14;
-  optional int32 field16 = 16;
-  optional int32 field19 = 19 [default=2];
-  optional bool field20  = 20 [default=true];
-  optional bool field28 = 28 [default=true];
-  optional fixed64 field21 = 21;
-  optional int32 field22 = 22;
-  optional bool field23 = 23 [ default=false ];
-  optional bool field206 = 206 [default=false];
-  optional fixed32 field203 = 203;
-  optional int32 field204 = 204;
-  optional string field205 = 205;
-  optional uint64 field207 = 207;
-  optional uint64 field300 = 300;
-}
-
-message SpeedMessage2 {
-  optional string field1 = 1;
-  optional int64 field3 = 3;
-  optional int64 field4 = 4;
-  optional int64 field30 = 30;
-  optional bool field75  = 75 [default=false];
-  optional string field6 = 6;
-  optional bytes field2 = 2;
-  optional int32 field21 = 21 [default=0];
-  optional int32 field71 = 71;
-  optional float field25 = 25;
-  optional int32 field109 = 109 [default=0];
-  optional int32 field210 = 210 [default=0];
-  optional int32 field211 = 211 [default=0];
-  optional int32 field212 = 212 [default=0];
-  optional int32 field213 = 213 [default=0];
-  optional int32 field216 = 216 [default=0];
-  optional int32 field217 = 217 [default=0];
-  optional int32 field218 = 218 [default=0];
-  optional int32 field220 = 220 [default=0];
-  optional int32 field221 = 221 [default=0];
-  optional float field222 = 222 [default=0.0];
-  optional int32 field63 = 63;
-
-  repeated group Group1 = 10 {
-    required float field11 = 11;
-    optional float field26 = 26;
-    optional string field12 = 12;
-    optional string field13 = 13;
-    repeated string field14 = 14;
-    required uint64 field15 = 15;
-    optional int32 field5 = 5;
-    optional string field27 = 27;
-    optional int32 field28 = 28;
-    optional string field29 = 29;
-    optional string field16 = 16;
-    repeated string field22 = 22;
-    repeated int32 field73 = 73;
-    optional int32 field20 = 20 [default=0];
-    optional string field24 = 24;
-    optional SpeedMessage2GroupedMessage field31 = 31;
-  }
-  repeated string field128 = 128;
-  optional int64 field131 = 131;
-  repeated string field127 = 127;
-  optional int32 field129 = 129;
-  repeated int64 field130 = 130;
-  optional bool field205 = 205 [default=false];
-  optional bool field206 = 206 [default=false];
-}
-
-message SpeedMessage2GroupedMessage {
-  optional float field1 = 1;
-  optional float field2 = 2;
-  optional float field3 = 3 [default=0.0];
-  optional bool field4 = 4;
-  optional bool field5 = 5;
-  optional bool field6 = 6 [default=true];
-  optional bool field7 = 7 [default=false];
-  optional float field8 = 8;
-  optional bool field9 = 9;
-  optional float field10 = 10;
-  optional int64 field11 = 11;
-}
diff --git a/build.gradle b/build.gradle
index 7aa8ac2..7115f72 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,48 +26,61 @@
 
     micro {
         java {
-            srcDirs = ['java/src/main/java/']
+            srcDirs = ['javamicro/src/main/java/']
             include("com/google/protobuf/micro/*")
         }
     }
 
     lite {
         java {
-            srcDirs = ['java/src/main/java/']
-            include 'com/google/protobuf/UninitializedMessageException.java'
-            include 'com/google/protobuf/MessageLite.java'
-            include 'com/google/protobuf/InvalidProtocolBufferException.java'
-            include 'com/google/protobuf/CodedOutputStream.java'
-            include 'com/google/protobuf/ByteString.java'
-            include 'com/google/protobuf/CodedInputStream.java'
-            include 'com/google/protobuf/ExtensionRegistryLite.java'
+            srcDirs = ['java/core/src/main/java/']
             include 'com/google/protobuf/AbstractMessageLite.java'
             include 'com/google/protobuf/AbstractParser.java'
+            include 'com/google/protobuf/AbstractProtobufList.java'
+            include 'com/google/protobuf/ByteOutput.java'
+            include 'com/google/protobuf/ByteString.java'
+            include 'com/google/protobuf/BooleanArrayList.java'
+            include 'com/google/protobuf/CodedInputStream.java'
+            include 'com/google/protobuf/CodedOutputStream.java'
+            include 'com/google/protobuf/DoubleArrayList.java'
+            include 'com/google/protobuf/ExperimentalApi.java'
+            include 'com/google/protobuf/ExtensionLite.java'
+            include 'com/google/protobuf/ExtensionRegistryLite.java'
             include 'com/google/protobuf/FieldSet.java'
-            include 'com/google/protobuf/Internal.java'
-            include 'com/google/protobuf/WireFormat.java'
+            include 'com/google/protobuf/FloatArrayList.java'
             include 'com/google/protobuf/GeneratedMessageLite.java'
-            include 'com/google/protobuf/BoundedByteString.java'
+            include 'com/google/protobuf/IntArrayList.java'
+            include 'com/google/protobuf/Internal.java'
+            include 'com/google/protobuf/InvalidProtocolBufferException.java'
             include 'com/google/protobuf/LazyField.java'
             include 'com/google/protobuf/LazyFieldLite.java'
-            include 'com/google/protobuf/LazyStringList.java'
             include 'com/google/protobuf/LazyStringArrayList.java'
-            include 'com/google/protobuf/UnmodifiableLazyStringList.java'
-            include 'com/google/protobuf/LiteralByteString.java'
+            include 'com/google/protobuf/LazyStringList.java'
+            include 'com/google/protobuf/LongArrayList.java'
+            include 'com/google/protobuf/MapFieldLite.java'
+            include 'com/google/protobuf/MessageLite.java'
+            include 'com/google/protobuf/MessageLiteToString.java'
             include 'com/google/protobuf/MessageLiteOrBuilder.java'
+            include 'com/google/protobuf/MutabilityOracle.java'
             include 'com/google/protobuf/Parser.java'
+            include 'com/google/protobuf/ProtobufArrayList.java'
             include 'com/google/protobuf/ProtocolStringList.java'
             include 'com/google/protobuf/RopeByteString.java'
             include 'com/google/protobuf/SmallSortedMap.java'
+            include 'com/google/protobuf/TextFormatEscaper.java'
+            include 'com/google/protobuf/UninitializedMessageException.java'
+            include 'com/google/protobuf/UnknownFieldSetLite.java'
+            include 'com/google/protobuf/UnmodifiableLazyStringList.java'
             include 'com/google/protobuf/Utf8.java'
+            include 'com/google/protobuf/WireFormat.java'
         }
     }
 
     nano {
         java {
             srcDirs = [
-                    'java/src/main/java/',
-                    'java/src/device/main/java/'
+                    'javanano/src/main/java/',
+                    'javanano/src/device/main/java/'
             ]
             include("com/google/protobuf/nano/**")
         }
@@ -89,7 +102,7 @@
     from sourceSets.nano.output, sourceSets.micro.output
     baseName "libprotobuf"
     appendix "java"
-    version "2.6"
+    version "3.0"
     classifier "micronano"
 }
 
@@ -98,7 +111,7 @@
     dependsOn nanoClasses
     baseName "libprotobuf"
     appendix "java"
-    version "2.6"
+    version "3.0"
     classifier "nano"
 }
 
@@ -107,7 +120,7 @@
     dependsOn microClasses
     baseName "libprotobuf"
     appendix "java"
-    version "2.6"
+    version "3.0"
     classifier "micro"
 }
 
@@ -116,7 +129,7 @@
     dependsOn liteClasses
     baseName "libprotobuf"
     appendix "java"
-    version "2.3"
+    version "3.0"
     classifier "lite"
 }
 
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
new file mode 100644
index 0000000..f32a0e4
--- /dev/null
+++ b/cmake/CMakeLists.txt
@@ -0,0 +1,153 @@
+# Minimum CMake required
+cmake_minimum_required(VERSION 2.8)
+
+# Project
+project(protobuf C CXX)
+
+# CMake policies
+cmake_policy(SET CMP0022 NEW)
+
+# Options
+option(protobuf_VERBOSE "Enable for verbose output" OFF)
+option(protobuf_BUILD_TESTS "Build tests" ON)
+if (BUILD_SHARED_LIBS)
+  set(protobuf_BUILD_SHARED_LIBS_DEFAULT ON)
+else (BUILD_SHARED_LIBS)
+  set(protobuf_BUILD_SHARED_LIBS_DEFAULT OFF)
+endif (BUILD_SHARED_LIBS)
+option(protobuf_BUILD_SHARED_LIBS "Build Shared Libraries" ${protobuf_BUILD_SHARED_LIBS_DEFAULT})
+option(protobuf_MSVC_STATIC_RUNTIME "Link static runtime libraries" ON)
+if (MSVC)
+  set(protobuf_WITH_ZLIB_DEFAULT OFF)
+else (MSVC)
+  set(protobuf_WITH_ZLIB_DEFAULT ON)
+endif (MSVC)
+option(protobuf_WITH_ZLIB "Build with zlib support" ${protobuf_WITH_ZLIB_DEFAULT})
+set(protobuf_DEBUG_POSTFIX "d"
+  CACHE STRING "Default debug postfix")
+
+# Path to main configure script
+set(protobuf_CONFIGURE_SCRIPT "../configure.ac")
+
+# Parse configure script
+set(protobuf_AC_INIT_REGEX
+  "^AC_INIT\\(\\[([^]]+)\\],\\[([^]]+)\\],\\[([^]]+)\\],\\[([^]]+)\\]\\)$")
+file(STRINGS "${protobuf_CONFIGURE_SCRIPT}" protobuf_AC_INIT_LINE
+  LIMIT_COUNT 1 REGEX "^AC_INIT")
+# Description
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\1"
+    protobuf_DESCRIPTION    "${protobuf_AC_INIT_LINE}")
+# Version
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\2"
+    protobuf_VERSION_STRING "${protobuf_AC_INIT_LINE}")
+# Contact
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\3"
+    protobuf_CONTACT        "${protobuf_AC_INIT_LINE}")
+# Parse version tweaks
+set(protobuf_VERSION_REGEX "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$")
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\1"
+  protobuf_VERSION_MAJOR "${protobuf_VERSION_STRING}")
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\2"
+  protobuf_VERSION_MINOR "${protobuf_VERSION_STRING}")
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\3"
+  protobuf_VERSION_PATCH "${protobuf_VERSION_STRING}")
+# Package version
+set(protobuf_VERSION
+  "${protobuf_VERSION_MAJOR}.${protobuf_VERSION_MINOR}.${protobuf_VERSION_PATCH}")
+
+if(protobuf_VERBOSE)
+  message(STATUS "Configuration script parsing status [")
+  message(STATUS "  Description : ${protobuf_DESCRIPTION}")
+  message(STATUS "  Version     : ${protobuf_VERSION} (${protobuf_VERSION_STRING})")
+  message(STATUS "  Contact     : ${protobuf_CONTACT}")
+  message(STATUS "]")
+endif()
+
+add_definitions(-DGOOGLE_PROTOBUF_CMAKE_BUILD)
+
+find_package(Threads REQUIRED)
+if (CMAKE_USE_PTHREADS_INIT)
+  add_definitions(-DHAVE_PTHREAD)
+endif (CMAKE_USE_PTHREADS_INIT)
+
+if (protobuf_WITH_ZLIB)
+  find_package(ZLIB)
+  if (ZLIB_FOUND)
+    set(HAVE_ZLIB 1)
+    # FindZLIB module define ZLIB_INCLUDE_DIRS variable
+    # Set ZLIB_INCLUDE_DIRECTORIES for compatible
+    set(ZLIB_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIRECTORIES} ${ZLIB_INCLUDE_DIRS})
+    # Using imported target if exists
+    if (TARGET ZLIB::ZLIB)
+      set(ZLIB_LIBRARIES ZLIB::ZLIB)
+    endif (TARGET ZLIB::ZLIB)
+  else (ZLIB_FOUND)
+    set(HAVE_ZLIB 0)
+    # Explicitly set these to empty (override NOT_FOUND) so cmake doesn't
+    # complain when we use them later.
+    set(ZLIB_INCLUDE_DIRECTORIES)
+    set(ZLIB_LIBRARIES)
+  endif (ZLIB_FOUND)
+endif (protobuf_WITH_ZLIB)
+
+if (HAVE_ZLIB)
+  add_definitions(-DHAVE_ZLIB)
+endif (HAVE_ZLIB)
+
+if (protobuf_BUILD_SHARED_LIBS)
+  set(protobuf_SHARED_OR_STATIC "SHARED")
+else (protobuf_BUILD_SHARED_LIBS)
+  set(protobuf_SHARED_OR_STATIC "STATIC")
+  # In case we are building static libraries, link also the runtime library statically
+  # so that MSVCR*.DLL is not required at runtime.
+  # https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
+  # This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
+  # http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
+  if (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+    foreach(flag_var
+        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+      if(${flag_var} MATCHES "/MD")
+        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+      endif(${flag_var} MATCHES "/MD")
+    endforeach(flag_var)
+  endif (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+endif (protobuf_BUILD_SHARED_LIBS)
+
+if (MSVC)
+  # Build with multiple processes
+  add_definitions(/MP)
+  add_definitions(/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305)
+  # Allow big object
+  add_definitions(/bigobj)
+  string(REPLACE "/" "\\" PROTOBUF_SOURCE_WIN32_PATH ${protobuf_SOURCE_DIR})
+  string(REPLACE "/" "\\" PROTOBUF_BINARY_WIN32_PATH ${protobuf_BINARY_DIR})
+  configure_file(extract_includes.bat.in extract_includes.bat)
+endif (MSVC)
+
+get_filename_component(protobuf_source_dir ${protobuf_SOURCE_DIR} PATH)
+
+include_directories(
+  ${ZLIB_INCLUDE_DIRECTORIES}
+  ${protobuf_BINARY_DIR}
+  ${protobuf_source_dir}/src)
+
+if (MSVC)
+  # Add the "lib" prefix for generated .lib outputs.
+  set(LIB_PREFIX lib)
+else (MSVC)
+  # When building with "make", "lib" prefix will be added automatically by
+  # the build tool.
+  set(LIB_PREFIX)
+endif (MSVC)
+
+include(libprotobuf-lite.cmake)
+include(libprotobuf.cmake)
+include(libprotoc.cmake)
+include(protoc.cmake)
+
+if (protobuf_BUILD_TESTS)
+  include(tests.cmake)
+endif (protobuf_BUILD_TESTS)
+
+include(install.cmake)
diff --git a/cmake/README.md b/cmake/README.md
new file mode 100644
index 0000000..1e7410d
--- /dev/null
+++ b/cmake/README.md
@@ -0,0 +1,336 @@
+This directory contains *CMake* files that can be used to build protobuf
+with *MSVC* on *Windows*. You can build the project from *Command Prompt*
+and using an *Visual Studio* IDE.
+
+You need to have [CMake](http://www.cmake.org), [Visual Studio](https://www.visualstudio.com)
+and optionally [Git](http://git-scm.com) installed on your computer before proceeding.
+
+Most of the instructions will be given to the *Сommand Prompt*, but the same
+actions can be performed using appropriate GUI tools.
+
+Environment Setup
+=================
+
+Open the appropriate *Command Prompt* from the *Start* menu.
+
+For example *VS2013 x64 Native Tools Command Prompt*:
+
+    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64>
+
+Change to your working directory:
+
+    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64>cd C:\Path\to
+    C:\Path\to>
+
+Where *C:\Path\to* is path to your real working directory.
+
+Create a folder where protobuf headers/libraries/binaries will be installed after built:
+
+    C:\Path\to>mkdir install
+
+If *cmake* command is not available from *Command Prompt*, add it to system *PATH* variable:
+
+    C:\Path\to>set PATH=%PATH%;C:\Program Files (x86)\CMake\bin
+
+If *git* command is not available from *Command Prompt*, add it to system *PATH* variable:
+
+    C:\Path\to>set PATH=%PATH%;C:\Program Files\Git\cmd
+
+Good. Now you are ready to continue.
+
+Getting Sources
+===============
+
+You can get the latest stable source packages from the
+[releases](https://github.com/google/protobuf/releases) page.
+Or you can type:
+
+     C:\Path\to> git clone -b [release_tag] https://github.com/google/protobuf.git
+
+Where *[release_tag]* is a git tag like *v3.0.0-beta-1* or a branch name like *master*
+if you want to get the latest code.
+
+Go to the project folder:
+
+     C:\Path\to>cd protobuf
+     C:\Path\to\protobuf>
+
+Protobuf unit-tests require gmock to build. If you download protobuf source code
+from the *releases* page, the *gmock* directory should already be there. If you checkout
+the code via `git clone`, this *gmock* directory won't exist and you will have to
+download it manually or skip building protobuf unit-tests.
+
+You can download gmock as follows:
+
+     C:\Path\to\protobuf>git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock
+
+Then go to *gmock* folder and download gtest:
+
+     C:\Path\to\protobuf>cd gmock
+     C:\Path\to\protobuf\gmock>git clone -b release-1.7.0 https://github.com/google/googletest.git gtest
+
+If you absolutely don't want to build and run protobuf unit-tests, skip
+this steps and use protobuf at your own risk.
+
+Now go to *cmake* folder in protobuf sources:
+
+     C:\Path\to\protobuf\gmock>cd ..\cmake
+     C:\Path\to\protobuf\cmake>
+
+Good. Now you are ready to *CMake* configuration.
+
+CMake Configuration
+===================
+
+*CMake* supports a lot of different
+[generators](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html)
+for various native build systems.
+We are only interested in
+[Makefile](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html#makefile-generators)
+and
+[Visual Studio](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators)
+generators.
+
+We will use shadow building to separate the temporary files from the protobuf source code.
+
+Create a temporary *build* folder and change your working directory to it:
+
+     C:\Path\to\protobuf\cmake>mkdir build & cd build
+     C:\Path\to\protobuf\cmake\build>
+
+The *Makefile* generator can build the project in only one configuration, so you need to build
+a separate folder for each configuration.
+
+To start using a *Release* configuration:
+
+     C:\Path\to\protobuf\cmake\build>mkdir release & cd release
+     C:\Path\to\protobuf\cmake\build\release>cmake -G "NMake Makefiles" ^
+     -DCMAKE_BUILD_TYPE=Release ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *nmake* *Makefile* in current directory.
+
+To use *Debug* configuration:
+
+     C:\Path\to\protobuf\cmake\build>mkdir debug & cd debug
+     C:\Path\to\protobuf\cmake\build\debug>cmake -G "NMake Makefiles" ^
+     -DCMAKE_BUILD_TYPE=Debug ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *nmake* *Makefile* in current directory.
+
+To create *Visual Studio* solution file:
+
+     C:\Path\to\protobuf\cmake\build>mkdir solution & cd solution
+     C:\Path\to\protobuf\cmake\build\solution>cmake -G "Visual Studio 12 2013 Win64" ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *Visual Studio* solution file *protobuf.sln* in current directory.
+
+If the *gmock* directory does not exist, and you do not want to build protobuf unit tests,
+you need to add *cmake* command argument `-Dprotobuf_BUILD_TESTS=OFF` to disable testing.
+
+Compiling
+=========
+
+To compile protobuf:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake
+
+And wait for the compilation to finish.
+
+If you prefer to use the IDE:
+
+  * Open the generated protobuf.sln file in Microsoft Visual Studio.
+  * Choose "Debug" or "Release" configuration as desired.
+  * From the Build menu, choose "Build Solution".
+
+And wait for the compilation to finish.
+
+Testing
+=======
+
+To run unit-tests, first you must compile protobuf as described above.
+Then run:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake check
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake check
+
+You can also build project *check* from Visual Studio solution.
+Yes, it may sound strange, but it works.
+
+You should see output similar to:
+
+     Running main() from gmock_main.cc
+     [==========] Running 1546 tests from 165 test cases.
+     
+     ...
+     
+     [==========] 1546 tests from 165 test cases ran. (2529 ms total)
+     [  PASSED  ] 1546 tests.
+
+To run specific tests:
+
+     C:\Path\to\protobuf>cmake\build\release\tests.exe --gtest_filter=AnyTest*
+     Running main() from gmock_main.cc
+     Note: Google Test filter = AnyTest*
+     [==========] Running 3 tests from 1 test case.
+     [----------] Global test environment set-up.
+     [----------] 3 tests from AnyTest
+     [ RUN      ] AnyTest.TestPackAndUnpack
+     [       OK ] AnyTest.TestPackAndUnpack (0 ms)
+     [ RUN      ] AnyTest.TestPackAndUnpackAny
+     [       OK ] AnyTest.TestPackAndUnpackAny (0 ms)
+     [ RUN      ] AnyTest.TestIs
+     [       OK ] AnyTest.TestIs (0 ms)
+     [----------] 3 tests from AnyTest (1 ms total)
+     
+     [----------] Global test environment tear-down
+     [==========] 3 tests from 1 test case ran. (2 ms total)
+     [  PASSED  ] 3 tests.
+
+Note that the tests must be run from the source folder.
+
+If all tests are passed, safely continue.
+
+Installing
+==========
+
+To install protobuf to the specified *install* folder:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake install
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake install
+
+You can also build project *INSTALL* from Visual Studio solution.
+It sounds not so strange and it works.
+
+This will create the following folders under the *install* location:
+  * bin - that contains protobuf *protoc.exe* compiler;
+  * include - that contains C++ headers and protobuf *.proto files;
+  * lib - that contains linking libraries and *CMake* configuration files for *protobuf* package.
+
+Now you can if needed:
+  * Copy the contents of the include directory to wherever you want to put headers.
+  * Copy protoc.exe wherever you put build tools (probably somewhere in your PATH).
+  * Copy linking libraries libprotobuf[d].lib, libprotobuf-lite[d].lib, and libprotoc[d].lib wherever you put libraries.
+
+To avoid conflicts between the MSVC debug and release runtime libraries, when
+compiling a debug build of your application, you may need to link against a
+debug build of libprotobufd.lib with "d" postfix.  Similarly, release builds should link against
+release libprotobuf.lib library.
+
+DLLs vs. static linking
+=======================
+
+Static linking is now the default for the Protocol Buffer libraries.  Due to
+issues with Win32's use of a separate heap for each DLL, as well as binary
+compatibility issues between different versions of MSVC's STL library, it is
+recommended that you use static linkage only.  However, it is possible to
+build libprotobuf and libprotoc as DLLs if you really want.  To do this,
+do the following:
+
+  * Add an additional flag `-Dprotobuf_BUILD_SHARED_LIBS=ON` when invoking cmake
+  * Follow the same steps as described in the above section.
+  * When compiling your project, make sure to `#define PROTOBUF_USE_DLLS`.
+
+When distributing your software to end users, we strongly recommend that you
+do NOT install libprotobuf.dll or libprotoc.dll to any shared location.
+Instead, keep these libraries next to your binaries, in your application's
+own install directory.  C++ makes it very difficult to maintain binary
+compatibility between releases, so it is likely that future versions of these
+libraries will *not* be usable as drop-in replacements.
+
+If your project is itself a DLL intended for use by third-party software, we
+recommend that you do NOT expose protocol buffer objects in your library's
+public interface, and that you statically link protocol buffers into your
+library.
+
+ZLib support
+============
+
+If you want to include GzipInputStream and GzipOutputStream
+(google/protobuf/io/gzip_stream.h) in libprotobuf, you will need to do a few
+additional steps.
+
+Obtain a copy of the zlib library.  The pre-compiled DLL at zlib.net works.
+You need prepare it:
+
+  * Make sure zlib's two headers are in your `C:\Path\to\install\include` path
+  * Make sure zlib's linking libraries (*.lib file) is in your
+    `C:\Path\to\install\lib` library path.
+
+You can also compile it from source by yourself.
+
+Getting sources:
+
+     C:\Path\to>git clone -b v1.2.8 https://github.com/madler/zlib.git
+     C:\Path\to>cd zlib
+
+Compiling and Installing:
+
+     C:\Path\to\zlib>mkdir build & cd build
+     C:\Path\to\zlib\build>mkdir release & cd release
+     C:\Path\to\zlib\build\release>cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ^
+     -DCMAKE_INSTALL_PREFIX=../../../install ../..
+     C:\Path\to\zlib\build\release>nmake & nmake install
+
+You can make *debug* version or use *Visual Studio* generator also as before for the
+protobuf project.
+
+Now add *bin* folder from *install* to system *PATH*:
+
+     C:\Path\to>set PATH=%PATH%;C:\Path\to\install\bin
+
+You need reconfigure protobuf with flag `-Dprotobuf_WITH_ZLIB=ON` when invoking cmake.
+
+Note that if you have compiled ZLIB yourself, as stated above,
+further disable the option `-Dprotobuf_MSVC_STATIC_RUNTIME=OFF`.
+
+If it reports NOTFOUND for zlib_include or zlib_lib, you might haven't put
+the headers or the .lib file in the right directory.
+
+Build and testing protobuf as usual.
+
+Notes on Compiler Warnings
+==========================
+
+The following warnings have been disabled while building the protobuf libraries
+and compiler.  You may have to disable some of them in your own project as
+well, or live with them.
+
+* C4018 - 'expression' : signed/unsigned mismatch
+* C4146 - unary minus operator applied to unsigned type, result still unsigned
+* C4244 - Conversion from 'type1' to 'type2', possible loss of data.
+* C4251 - 'identifier' : class 'type' needs to have dll-interface to be used by
+  clients of class 'type2'
+* C4267 - Conversion from 'size_t' to 'type', possible loss of data.
+* C4305 - 'identifier' : truncation from 'type1' to 'type2'
+* C4355 - 'this' : used in base member initializer list
+* C4800 - 'type' : forcing value to bool 'true' or 'false' (performance warning)
+* C4996 - 'function': was declared deprecated
+
+C4251 is of particular note, if you are compiling the Protocol Buffer library
+as a DLL (see previous section).  The protocol buffer library uses templates in
+its public interfaces.  MSVC does not provide any reasonable way to export
+template classes from a DLL.  However, in practice, it appears that exporting
+templates is not necessary anyway.  Since the complete definition of any
+template is available in the header files, anyone importing the DLL will just
+end up compiling instances of the templates into their own binary.  The
+Protocol Buffer implementation does not rely on static template members being
+unique, so there should be no problem with this, but MSVC prints warning
+nevertheless.  So, we disable it.  Unfortunately, this warning will also be
+produced when compiling code which merely uses protocol buffers, meaning you
+may have to disable it in your code too.
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
new file mode 100644
index 0000000..b593e0c
--- /dev/null
+++ b/cmake/extract_includes.bat.in
@@ -0,0 +1,124 @@
+mkdir include
+mkdir include\google
+mkdir include\google\protobuf
+mkdir include\google\protobuf\compiler
+mkdir include\google\protobuf\compiler\cpp
+mkdir include\google\protobuf\compiler\csharp
+mkdir include\google\protobuf\compiler\java
+mkdir include\google\protobuf\compiler\javanano
+mkdir include\google\protobuf\compiler\js
+mkdir include\google\protobuf\compiler\objectivec
+mkdir include\google\protobuf\compiler\python
+mkdir include\google\protobuf\compiler\ruby
+mkdir include\google\protobuf\io
+mkdir include\google\protobuf\stubs
+mkdir include\google\protobuf\util
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.h include\google\protobuf\any.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.pb.h include\google\protobuf\any.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.pb.h include\google\protobuf\api.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arena.h include\google\protobuf\arena.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arenastring.h include\google\protobuf\arenastring.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\command_line_interface.h include\google\protobuf\compiler\command_line_interface.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_generator.h include\google\protobuf\compiler\csharp\csharp_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h include\google\protobuf\compiler\csharp\csharp_names.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_names.h include\google\protobuf\compiler\java\java_names.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\javanano\javanano_generator.h include\google\protobuf\compiler\javanano\javanano_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\js\js_generator.h include\google\protobuf\compiler\js\js_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_generator.h include\google\protobuf\compiler\objectivec\objectivec_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_helpers.h include\google\protobuf\compiler\objectivec\objectivec_helpers.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h include\google\protobuf\compiler\plugin.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h include\google\protobuf\compiler\ruby\ruby_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.pb.h include\google\protobuf\duration.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\dynamic_message.h include\google\protobuf\dynamic_message.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.pb.h include\google\protobuf\empty.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set.h include\google\protobuf\extension_set.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.pb.h include\google\protobuf\field_mask.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflection.h include\google\protobuf\generated_enum_reflection.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h include\google\protobuf\generated_enum_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h include\google\protobuf\io\gzip_stream.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\strtod.h include\google\protobuf\io\strtod.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\tokenizer.h include\google\protobuf\io\tokenizer.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream.h include\google\protobuf\io\zero_copy_stream.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl.h include\google\protobuf\io\zero_copy_stream_impl.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl_lite.h include\google\protobuf\io\zero_copy_stream_impl_lite.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map.h include\google\protobuf\map.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry.h include\google\protobuf\map_entry.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry_lite.h include\google\protobuf\map_entry_lite.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field.h include\google\protobuf\map_field.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_inl.h include\google\protobuf\map_field_inl.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_lite.h include\google\protobuf\map_field_lite.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_type_handler.h include\google\protobuf\map_type_handler.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message.h include\google\protobuf\message.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message_lite.h include\google\protobuf\message_lite.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata.h include\google\protobuf\metadata.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h include\google\protobuf\reflection.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h include\google\protobuf\reflection_ops.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h include\google\protobuf\repeated_field.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field_reflection.h include\google\protobuf\repeated_field_reflection.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h include\google\protobuf\service.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h include\google\protobuf\source_context.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h include\google\protobuf\struct.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomic_sequence_num.h include\google\protobuf\stubs\atomic_sequence_num.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops.h include\google\protobuf\stubs\atomicops.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm64_gcc.h include\google\protobuf\stubs\atomicops_internals_arm64_gcc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_atomicword_compat.h include\google\protobuf\stubs\atomicops_internals_atomicword_compat.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_generic_gcc.h include\google\protobuf\stubs\atomicops_internals_generic_gcc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_macosx.h include\google\protobuf\stubs\atomicops_internals_macosx.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_pnacl.h include\google\protobuf\stubs\atomicops_internals_pnacl.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_power.h include\google\protobuf\stubs\atomicops_internals_power.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_solaris.h include\google\protobuf\stubs\atomicops_internals_solaris.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_tsan.h include\google\protobuf\stubs\atomicops_internals_tsan.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.h include\google\protobuf\stubs\atomicops_internals_x86_gcc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h include\google\protobuf\stubs\atomicops_internals_x86_msvc.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\bytestream.h include\google\protobuf\stubs\bytestream.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\callback.h include\google\protobuf\stubs\callback.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\casts.h include\google\protobuf\stubs\casts.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\fastmem.h include\google\protobuf\stubs\fastmem.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\hash.h include\google\protobuf\stubs\hash.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\logging.h include\google\protobuf\stubs\logging.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\macros.h include\google\protobuf\stubs\macros.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\mutex.h include\google\protobuf\stubs\mutex.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\once.h include\google\protobuf\stubs\once.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros.h include\google\protobuf\stubs\platform_macros.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\port.h include\google\protobuf\stubs\port.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\scoped_ptr.h include\google\protobuf\stubs\scoped_ptr.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\shared_ptr.h include\google\protobuf\stubs\shared_ptr.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\singleton.h include\google\protobuf\stubs\singleton.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\status.h include\google\protobuf\stubs\status.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stl_util.h include\google\protobuf\stubs\stl_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stringpiece.h include\google\protobuf\stubs\stringpiece.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\template_util.h include\google\protobuf\stubs\template_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\type_traits.h include\google\protobuf\stubs\type_traits.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\text_format.h include\google\protobuf\text_format.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.pb.h include\google\protobuf\timestamp.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.pb.h include\google\protobuf\type.pb.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\unknown_field_set.h include\google\protobuf\unknown_field_set.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_comparator.h include\google\protobuf\util\field_comparator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_mask_util.h include\google\protobuf\util\field_mask_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\json_util.h include\google\protobuf\util\json_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\message_differencer.h include\google\protobuf\util\message_differencer.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\time_util.h include\google\protobuf\util\time_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver.h include\google\protobuf\util\type_resolver.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver_util.h include\google\protobuf\util\type_resolver_util.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format.h include\google\protobuf\wire_format.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite.h include\google\protobuf\wire_format_lite.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite_inl.h include\google\protobuf\wire_format_lite_inl.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.pb.h include\google\protobuf\wrappers.pb.h
diff --git a/cmake/install.cmake b/cmake/install.cmake
new file mode 100644
index 0000000..dbb4265
--- /dev/null
+++ b/cmake/install.cmake
@@ -0,0 +1,103 @@
+include(GNUInstallDirs)
+
+foreach(_library
+  libprotobuf-lite
+  libprotobuf
+  libprotoc)
+  set_property(TARGET ${_library}
+    PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
+  install(TARGETS ${_library} EXPORT protobuf-targets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${_library}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library})
+endforeach()
+
+install(TARGETS protoc EXPORT protobuf-targets
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc)
+
+if(TRUE)
+  file(STRINGS extract_includes.bat.in _extract_strings
+    REGEX "^copy")
+  foreach(_extract_string ${_extract_strings})
+    string(REPLACE "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\" ""
+      _extract_string ${_extract_string})
+    string(REPLACE "\\" "/" _extract_string ${_extract_string})
+    string(REGEX MATCH "^[^ ]+"
+      _extract_from ${_extract_string})
+    string(REGEX REPLACE "^${_extract_from} ([^$]+)" "\\1"
+      _extract_to ${_extract_string})
+    get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/${_extract_from}" ABSOLUTE)
+    get_filename_component(_extract_name ${_extract_to} NAME)
+    get_filename_component(_extract_to ${_extract_to} PATH)
+    string(REPLACE "include/" "${CMAKE_INSTALL_INCLUDEDIR}/"
+      _extract_to "${_extract_to}")
+    if(EXISTS "${_extract_from}")
+      install(FILES "${_extract_from}"
+        DESTINATION "${_extract_to}"
+        COMPONENT protobuf-headers
+        RENAME "${_extract_name}")
+    else()
+      message(AUTHOR_WARNING "The file \"${_extract_from}\" is listed in "
+        "\"${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in\" "
+        "but there not exists. The file will not be installed.")
+    endif()
+  endforeach()
+endif()
+
+# Internal function for parsing auto tools scripts
+function(_protobuf_auto_list FILE_NAME VARIABLE)
+  file(STRINGS ${FILE_NAME} _strings)
+  set(_list)
+  foreach(_string ${_strings})
+    set(_found)
+    string(REGEX MATCH "^[ \t]*${VARIABLE}[ \t]*=[ \t]*" _found "${_string}")
+    if(_found)
+      string(LENGTH "${_found}" _length)
+      string(SUBSTRING "${_string}" ${_length} -1 _draft_list)
+      foreach(_item ${_draft_list})
+        string(STRIP "${_item}" _item)
+        list(APPEND _list "${_item}")
+      endforeach()
+    endif()
+  endforeach()
+  set(${VARIABLE} ${_list} PARENT_SCOPE)
+endfunction()
+
+# Install well-known type proto files
+_protobuf_auto_list("../src/Makefile.am" nobase_dist_proto_DATA)
+foreach(_file ${nobase_dist_proto_DATA})
+  get_filename_component(_file_from "../src/${_file}" ABSOLUTE)
+  get_filename_component(_file_name ${_file} NAME)
+  get_filename_component(_file_path ${_file} PATH)
+  if(EXISTS "${_file_from}")
+    install(FILES "${_file_from}"
+      DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_file_path}"
+      COMPONENT protobuf-protos
+      RENAME "${_file_name}")
+  else()
+    message(AUTHOR_WARNING "The file \"${_file_from}\" is listed in "
+      "\"${protobuf_SOURCE_DIR}/../src/Makefile.am\" as nobase_dist_proto_DATA "
+      "but there not exists. The file will not be installed.")
+  endif()
+endforeach()
+
+# Export configuration
+
+install(EXPORT protobuf-targets
+  DESTINATION "lib/cmake/protobuf"
+  COMPONENT protobuf-export)
+
+configure_file(protobuf-config.cmake.in
+  protobuf-config.cmake @ONLY)
+configure_file(protobuf-config-version.cmake.in
+  protobuf-config-version.cmake @ONLY)
+configure_file(protobuf-module.cmake.in
+  protobuf-module.cmake @ONLY)
+
+install(FILES
+  "${protobuf_BINARY_DIR}/protobuf-config.cmake"
+  "${protobuf_BINARY_DIR}/protobuf-config-version.cmake"
+  "${protobuf_BINARY_DIR}/protobuf-module.cmake"
+  DESTINATION "lib/cmake/protobuf"
+  COMPONENT protobuf-export)
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
new file mode 100644
index 0000000..036b051
--- /dev/null
+++ b/cmake/libprotobuf-lite.cmake
@@ -0,0 +1,38 @@
+set(libprotobuf_lite_files
+  ${protobuf_source_dir}/src/google/protobuf/arena.cc
+  ${protobuf_source_dir}/src/google/protobuf/arenastring.cc
+  ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
+  ${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/message_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/repeated_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/common.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/int128.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/once.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/status.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/statusor.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/stringpiece.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/stringprintf.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/structurally_valid.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/strutil.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/time.cc
+  ${protobuf_source_dir}/src/google/protobuf/wire_format_lite.cc
+)
+
+add_library(libprotobuf-lite ${protobuf_SHARED_OR_STATIC}
+  ${libprotobuf_lite_files})
+target_link_libraries(libprotobuf-lite ${CMAKE_THREAD_LIBS_INIT})
+target_include_directories(libprotobuf-lite PUBLIC ${protobuf_source_dir}/src)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotobuf-lite
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOBUF_EXPORTS)
+endif()
+set_target_properties(libprotobuf-lite PROPERTIES
+    OUTPUT_NAME ${LIB_PREFIX}protobuf-lite
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake
new file mode 100644
index 0000000..8930c1c
--- /dev/null
+++ b/cmake/libprotobuf.cmake
@@ -0,0 +1,68 @@
+set(libprotobuf_files
+  ${protobuf_source_dir}/src/google/protobuf/any.cc
+  ${protobuf_source_dir}/src/google/protobuf/any.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/api.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/importer.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/parser.cc
+  ${protobuf_source_dir}/src/google/protobuf/descriptor.cc
+  ${protobuf_source_dir}/src/google/protobuf/descriptor.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/descriptor_database.cc
+  ${protobuf_source_dir}/src/google/protobuf/duration.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/dynamic_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/empty.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/extension_set_heavy.cc
+  ${protobuf_source_dir}/src/google/protobuf/field_mask.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/generated_message_reflection.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/printer.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/strtod.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/tokenizer.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/message.cc
+  ${protobuf_source_dir}/src/google/protobuf/reflection_ops.cc
+  ${protobuf_source_dir}/src/google/protobuf/service.cc
+  ${protobuf_source_dir}/src/google/protobuf/source_context.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/struct.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/mathlimits.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/substitute.cc
+  ${protobuf_source_dir}/src/google/protobuf/text_format.cc
+  ${protobuf_source_dir}/src/google/protobuf/timestamp.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/type.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/unknown_field_set.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/field_comparator.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/field_mask_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/datapiece.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/default_value_objectwriter.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/error_listener.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/field_mask_utility.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_escaping.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_objectwriter.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_stream_parser.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/object_writer.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/proto_writer.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectsource.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectwriter.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info_test_helper.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/utility.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/json_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/message_differencer.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/time_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/wire_format.cc
+  ${protobuf_source_dir}/src/google/protobuf/wrappers.pb.cc
+)
+
+add_library(libprotobuf ${protobuf_SHARED_OR_STATIC}
+  ${libprotobuf_lite_files} ${libprotobuf_files})
+target_link_libraries(libprotobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES})
+target_include_directories(libprotobuf PUBLIC ${protobuf_source_dir}/src)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotobuf
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOBUF_EXPORTS)
+endif()
+set_target_properties(libprotobuf PROPERTIES
+    OUTPUT_NAME ${LIB_PREFIX}protobuf
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
new file mode 100644
index 0000000..8df8986
--- /dev/null
+++ b/cmake/libprotoc.cmake
@@ -0,0 +1,106 @@
+set(libprotoc_files
+  ${protobuf_source_dir}/src/google/protobuf/compiler/code_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_file.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_service.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_context.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_extension_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_file.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator_factory.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_map_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message_builder.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_message_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_name_resolver.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_service.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_string_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_string_field_lite.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_file.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/js/js_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
+)
+
+add_library(libprotoc ${protobuf_SHARED_OR_STATIC}
+  ${libprotoc_files})
+target_link_libraries(libprotoc libprotobuf)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotoc
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOC_EXPORTS)
+endif()
+set_target_properties(libprotoc PROPERTIES
+    COMPILE_DEFINITIONS LIBPROTOC_EXPORTS
+    OUTPUT_NAME ${LIB_PREFIX}protoc
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/protobuf-config-version.cmake.in b/cmake/protobuf-config-version.cmake.in
new file mode 100644
index 0000000..1f171c6
--- /dev/null
+++ b/cmake/protobuf-config-version.cmake.in
@@ -0,0 +1 @@
+set(PACKAGE_VERSION @protobuf_VERSION@)
diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in
new file mode 100644
index 0000000..bb0997b
--- /dev/null
+++ b/cmake/protobuf-config.cmake.in
@@ -0,0 +1,27 @@
+# Version info variables
+set(PROTOBUF_VERSION        "@protobuf_VERSION@")
+set(PROTOBUF_VERSION_STRING "@protobuf_VERSION_STRING@")
+
+# Current dir
+get_filename_component(_PROTOBUF_PACKAGE_PREFIX
+  "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+# Imported targets
+include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-targets.cmake")
+
+# Compute the installation prefix relative to this file.
+get_filename_component(_PROTOBUF_IMPORT_PREFIX
+  "${_PROTOBUF_PACKAGE_PREFIX}" PATH)
+get_filename_component(_PROTOBUF_IMPORT_PREFIX
+  "${_PROTOBUF_IMPORT_PREFIX}" PATH)
+get_filename_component(_PROTOBUF_IMPORT_PREFIX
+  "${_PROTOBUF_IMPORT_PREFIX}" PATH)
+
+# CMake FindProtobuf module compatible file
+if(NOT DEFINED PROTOBUF_MODULE_COMPATIBLE OR "${PROTOBUF_MODULE_COMPATIBLE}")
+  include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-module.cmake")
+endif()
+
+# Cleanup temporary variables.
+set(_PROTOBUF_PACKAGE_PREFIX)
+set(_PROTOBUF_IMPORT_PREFIX)
diff --git a/cmake/protobuf-module.cmake.in b/cmake/protobuf-module.cmake.in
new file mode 100644
index 0000000..d81dc45
--- /dev/null
+++ b/cmake/protobuf-module.cmake.in
@@ -0,0 +1,139 @@
+if(PROTOBUF_SRC_ROOT_FOLDER)
+  message(AUTHOR_WARNING "Variable PROTOBUF_SRC_ROOT_FOLDER defined, but not"
+    " used in CONFIG mode")
+endif()
+
+function(PROTOBUF_GENERATE_CPP SRCS HDRS)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
+    return()
+  endif()
+
+  if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
+    # Create an include path for each file specified
+    foreach(FIL ${ARGN})
+      get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+      get_filename_component(ABS_PATH ${ABS_FIL} PATH)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  else()
+    set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
+  endif()
+
+  # Add well-known type protos include path
+  list(APPEND _protobuf_include_path
+    -I "${_PROTOBUF_IMPORT_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@")
+
+  if(DEFINED PROTOBUF_IMPORT_DIRS)
+    foreach(DIR ${PROTOBUF_IMPORT_DIRS})
+      get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  endif()
+
+  set(${SRCS})
+  set(${HDRS})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+
+    list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
+    list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
+
+    add_custom_command(
+      OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
+             "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
+      COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
+      ARGS --cpp_out  ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
+      DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE}
+      COMMENT "Running C++ protocol buffer compiler on ${FIL}"
+      VERBATIM)
+  endforeach()
+
+  set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
+  set(${SRCS} ${${SRCS}} PARENT_SCOPE)
+  set(${HDRS} ${${HDRS}} PARENT_SCOPE)
+endfunction()
+
+# Internal function: search for normal library as well as a debug one
+#    if the debug one is specified also include debug/optimized keywords
+#    in *_LIBRARIES variable
+function(_protobuf_find_libraries name filename)
+   get_target_property(${name}_LIBRARY lib${filename}
+     IMPORTED_LOCATION_RELEASE)
+   set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE)
+   get_target_property(${name}_LIBRARY_DEBUG lib${filename}
+     IMPORTED_LOCATION_DEBUG)
+   set(${name}_LIBRARY_DEBUG "${${name}_LIBRARY_DEBUG}" PARENT_SCOPE)
+
+   if(NOT ${name}_LIBRARY_DEBUG)
+      # There is no debug library
+      set(${name}_LIBRARY_DEBUG ${${name}_LIBRARY} PARENT_SCOPE)
+      set(${name}_LIBRARIES     ${${name}_LIBRARY} PARENT_SCOPE)
+   else()
+      # There IS a debug library
+      set(${name}_LIBRARIES
+          optimized ${${name}_LIBRARY}
+          debug     ${${name}_LIBRARY_DEBUG}
+          PARENT_SCOPE
+      )
+   endif()
+endfunction()
+
+# Internal function: find threads library
+function(_protobuf_find_threads)
+    set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+    find_package(Threads)
+    if(Threads_FOUND)
+        list(APPEND PROTOBUF_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+        set(PROTOBUF_LIBRARIES "${PROTOBUF_LIBRARIES}" PARENT_SCOPE)
+    endif()
+endfunction()
+
+#
+# Main.
+#
+
+# By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc
+# for each directory where a proto file is referenced.
+if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
+  set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE)
+endif()
+
+# The Protobuf library
+_protobuf_find_libraries(PROTOBUF protobuf)
+
+# The Protobuf Lite library
+_protobuf_find_libraries(PROTOBUF_LITE protobuf-lite)
+
+# The Protobuf Protoc Library
+_protobuf_find_libraries(PROTOBUF_PROTOC protoc)
+
+if(UNIX)
+  _protobuf_find_threads()
+endif()
+
+# Set the include directory
+set(PROTOBUF_INCLUDE_DIR "${_PROTOBUF_IMPORT_PREFIX}/@CMAKE_INSTALL_INCLUDEDIR@")
+
+# Set the protoc Executable
+get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc
+  IMPORTED_LOCATION_RELEASE)
+if(NOT PROTOBUF_PROTOC_EXECUTABLE)
+  get_target_property(PROTOBUF_PROTOC_EXECUTABLE protoc
+    IMPORTED_LOCATION_DEBUG)
+endif()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROTOBUF DEFAULT_MSG
+    PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR)
+
+if(PROTOBUF_FOUND)
+    set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR})
+endif()
diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake
new file mode 100644
index 0000000..4f07c38
--- /dev/null
+++ b/cmake/protoc.cmake
@@ -0,0 +1,6 @@
+set(protoc_files
+  ${protobuf_source_dir}/src/google/protobuf/compiler/main.cc
+)
+
+add_executable(protoc ${protoc_files})
+target_link_libraries(protoc libprotobuf libprotoc)
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
new file mode 100644
index 0000000..76fdf8e
--- /dev/null
+++ b/cmake/tests.cmake
@@ -0,0 +1,214 @@
+if (NOT EXISTS "${PROJECT_SOURCE_DIR}/../gmock/CMakeLists.txt")
+  message(FATAL_ERROR "Cannot find gmock directory.")
+endif()
+
+option(protobuf_ABSOLUTE_TEST_PLUGIN_PATH
+  "Using absolute test_plugin path in tests" ON)
+
+include_directories(
+  ${protobuf_source_dir}/gmock
+  ${protobuf_source_dir}/gmock/gtest
+  ${protobuf_source_dir}/gmock/gtest/include
+  ${protobuf_source_dir}/gmock/include
+)
+
+add_library(gmock STATIC
+  ${protobuf_source_dir}/gmock/src/gmock-all.cc
+  ${protobuf_source_dir}/gmock/gtest/src/gtest-all.cc
+)
+add_library(gmock_main STATIC ${protobuf_source_dir}/gmock/src/gmock_main.cc)
+target_link_libraries(gmock_main gmock)
+
+set(lite_test_protos
+  google/protobuf/map_lite_unittest.proto
+  google/protobuf/unittest_import_lite.proto
+  google/protobuf/unittest_import_public_lite.proto
+  google/protobuf/unittest_lite.proto
+  google/protobuf/unittest_no_arena_lite.proto
+)
+
+set(tests_protos
+  google/protobuf/any_test.proto
+  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+  google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
+  google/protobuf/map_proto2_unittest.proto
+  google/protobuf/map_unittest.proto
+  google/protobuf/unittest.proto
+  google/protobuf/unittest_arena.proto
+  google/protobuf/unittest_custom_options.proto
+  google/protobuf/unittest_drop_unknown_fields.proto
+  google/protobuf/unittest_embed_optimize_for.proto
+  google/protobuf/unittest_empty.proto
+  google/protobuf/unittest_import.proto
+  google/protobuf/unittest_import_public.proto
+  google/protobuf/unittest_lite_imports_nonlite.proto
+  google/protobuf/unittest_mset.proto
+  google/protobuf/unittest_mset_wire_format.proto
+  google/protobuf/unittest_no_arena.proto
+  google/protobuf/unittest_no_arena_import.proto
+  google/protobuf/unittest_no_field_presence.proto
+  google/protobuf/unittest_no_generic_services.proto
+  google/protobuf/unittest_optimize_for.proto
+  google/protobuf/unittest_preserve_unknown_enum.proto
+  google/protobuf/unittest_preserve_unknown_enum2.proto
+  google/protobuf/unittest_proto3_arena.proto
+  google/protobuf/unittest_proto3_arena_lite.proto
+  google/protobuf/unittest_proto3_lite.proto
+  google/protobuf/unittest_well_known_types.proto
+  google/protobuf/util/internal/testdata/anys.proto
+  google/protobuf/util/internal/testdata/books.proto
+  google/protobuf/util/internal/testdata/default_value.proto
+  google/protobuf/util/internal/testdata/default_value_test.proto
+  google/protobuf/util/internal/testdata/field_mask.proto
+  google/protobuf/util/internal/testdata/maps.proto
+  google/protobuf/util/internal/testdata/oneofs.proto
+  google/protobuf/util/internal/testdata/struct.proto
+  google/protobuf/util/internal/testdata/timestamp_duration.proto
+  google/protobuf/util/json_format_proto3.proto
+  google/protobuf/util/message_differencer_unittest.proto
+)
+
+macro(compile_proto_file filename)
+  get_filename_component(dirname ${filename} PATH)
+  get_filename_component(basename ${filename} NAME_WE)
+  add_custom_command(
+    OUTPUT ${protobuf_source_dir}/src/${dirname}/${basename}.pb.cc
+    DEPENDS protoc ${protobuf_source_dir}/src/${dirname}/${basename}.proto
+    COMMAND protoc ${protobuf_source_dir}/src/${dirname}/${basename}.proto
+        --proto_path=${protobuf_source_dir}/src
+        --cpp_out=${protobuf_source_dir}/src
+  )
+endmacro(compile_proto_file)
+
+set(lite_test_proto_files)
+foreach(proto_file ${lite_test_protos})
+  compile_proto_file(${proto_file})
+  string(REPLACE .proto .pb.cc pb_file ${proto_file})
+  set(lite_test_proto_files ${lite_test_proto_files}
+      ${protobuf_source_dir}/src/${pb_file})
+endforeach(proto_file)
+
+set(tests_proto_files)
+foreach(proto_file ${tests_protos})
+  compile_proto_file(${proto_file})
+  string(REPLACE .proto .pb.cc pb_file ${proto_file})
+  set(tests_proto_files ${tests_proto_files}
+      ${protobuf_source_dir}/src/${pb_file})
+endforeach(proto_file)
+
+set(common_test_files
+  ${protobuf_source_dir}/src/google/protobuf/arena_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/testing/file.cc
+  ${protobuf_source_dir}/src/google/protobuf/testing/googletest.cc
+)
+
+set(common_lite_test_files
+  ${protobuf_source_dir}/src/google/protobuf/arena_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_lite_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/test_util_lite.cc
+)
+
+set(tests_files
+  ${protobuf_source_dir}/src/google/protobuf/any_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/arena_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/arenastring_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/metadata_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/importer_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_plugin_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/mock_code_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/parser_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/descriptor_database_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/descriptor_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/drop_unknown_fields_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/dynamic_message_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/extension_set_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/generated_message_reflection_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/coded_stream_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/printer_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/tokenizer_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_field_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/message_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/no_field_presence_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/preserve_unknown_enum_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/proto3_arena_lite_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/proto3_arena_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/proto3_lite_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/reflection_ops_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/repeated_field_reflection_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/repeated_field_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/bytestream_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/common_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/int128_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/once_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/status_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/statusor_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/stringpiece_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/stringprintf_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/structurally_valid_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/strutil_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/template_util_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/time_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/stubs/type_traits_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/text_format_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/unknown_field_set_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/field_comparator_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/field_mask_util_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_objectwriter_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/json_stream_parser_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info_test_helper.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/json_util_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/message_differencer_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/time_util_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/well_known_types_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.cc
+)
+
+if(protobuf_ABSOLUTE_TEST_PLUGIN_PATH)
+  add_compile_options(-DGOOGLE_PROTOBUF_TEST_PLUGIN_PATH="$<TARGET_FILE:test_plugin>")
+endif()
+
+add_executable(tests ${tests_files} ${common_test_files} ${tests_proto_files} ${lite_test_proto_files})
+target_link_libraries(tests libprotoc libprotobuf gmock_main)
+
+set(test_plugin_files
+  ${protobuf_source_dir}/src/google/protobuf/compiler/mock_code_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/testing/file.cc
+  ${protobuf_source_dir}/src/google/protobuf/testing/file.h
+  ${protobuf_source_dir}/src/google/protobuf/compiler/test_plugin.cc
+)
+
+add_executable(test_plugin ${test_plugin_files})
+target_link_libraries(test_plugin libprotoc libprotobuf gmock)
+
+set(lite_test_files
+  ${protobuf_source_dir}/src/google/protobuf/lite_unittest.cc
+)
+add_executable(lite-test ${lite_test_files} ${common_lite_test_files} ${lite_test_proto_files})
+target_link_libraries(lite-test libprotobuf-lite)
+
+set(lite_arena_test_files
+  ${protobuf_source_dir}/src/google/protobuf/lite_arena_unittest.cc
+)
+add_executable(lite-arena-test ${lite_arena_test_files} ${common_lite_test_files} ${lite_test_proto_files})
+target_link_libraries(lite-arena-test libprotobuf-lite gmock_main)
+
+add_custom_target(check
+  COMMAND tests
+  WORKING_DIRECTORY ${protobuf_source_dir})
diff --git a/config/config.h b/config/config.h
new file mode 100644
index 0000000..366aa84
--- /dev/null
+++ b/config/config.h
@@ -0,0 +1,153 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* the name of <hash_map> */
+#define HASH_MAP_CLASS unordered_map
+
+/* the location of <unordered_map> or <hash_map> */
+#define HASH_MAP_H <tr1/unordered_map>
+
+/* the namespace of hash_map/hash_set */
+#define HASH_NAMESPACE std::tr1
+
+/* the name of <hash_set> */
+#define HASH_SET_CLASS unordered_set
+
+/* the location of <unordered_set> or <hash_set> */
+#define HASH_SET_H <tr1/unordered_set>
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE 1
+
+/* define if the compiler has hash_map */
+#define HAVE_HASH_MAP 1
+
+/* define if the compiler has hash_set */
+#define HAVE_HASH_SET 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mkdir' function. */
+#define HAVE_MKDIR 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Enable classes using zlib compression. */
+#define HAVE_ZLIB 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "protobuf"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "protobuf@googlegroups.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "Protocol Buffers"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "Protocol Buffers 2.6.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "protobuf"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.6.1"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* 64bit enabled */
+/* #undef SOLARIS_64BIT_ENABLED */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Version number of package */
+#define VERSION "2.6.1"
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
diff --git a/configure.ac b/configure.ac
index c07067c..bdc72ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,14 +12,25 @@
 # In the SVN trunk, the version should always be the next anticipated release
 # version with the "-pre" suffix.  (We used to use "-SNAPSHOT" but this pushed
 # the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[2.6.1],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.0.0-beta-3],[protobuf@googlegroups.com],[protobuf])
 
 AM_MAINTAINER_MODE([enable])
 
 AC_CONFIG_SRCDIR(src/google/protobuf/message.cc)
+# The config file is generated but not used by the source code, since we only
+# need very few of them, e.g. HAVE_PTHREAD and HAVE_ZLIB. Those macros are
+# passed down in CXXFLAGS manually in src/Makefile.am
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 
+AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
+case "$DIST_LANG" in
+  "") DIST_LANG=all ;;
+  all | cpp | csharp | java | python | javanano | objectivec | ruby | js) ;;
+  *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
+esac
+AC_SUBST(DIST_LANG)
+
 # autoconf's default CXXFLAGS are usually "-g -O2".  These aren't necessarily
 # the best choice for libprotobuf.
 AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"],
@@ -29,7 +40,7 @@
 
 AC_CANONICAL_TARGET
 
-AM_INIT_AUTOMAKE([subdir-objects])
+AM_INIT_AUTOMAKE([1.9 tar-ustar subdir-objects])
 
 AC_ARG_WITH([zlib],
   [AS_HELP_STRING([--with-zlib],
@@ -46,7 +57,9 @@
 AC_PROG_CXX
 AC_LANG([C++])
 ACX_USE_SYSTEM_EXTENSIONS
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc
+AC_PROG_OBJC
 
 # test_util.cc takes forever to compile with GCC and optimization turned on.
 AC_MSG_CHECKING([C++ compiler flags...])
@@ -137,6 +150,9 @@
 AM_CONDITIONAL([USE_EXTERNAL_PROTOC], [test "$with_protoc" != "no"])
 
 ACX_PTHREAD
+AM_CONDITIONAL([HAVE_PTHREAD], [test "x$acx_pthread_ok" = "xyes"])
+
+# We still keep this for improving pbconfig.h for unsupported platforms.
 AC_CXX_STL_HASH
 
 case "$target_os" in
@@ -148,12 +164,21 @@
     ;;
 esac
 
-# HACK:  Make gtest's configure script pick up our copy of CFLAGS and CXXFLAGS,
-#   since the flags added by ACX_CHECK_SUNCC must be used when compiling gtest
+# Enable ObjC support for conformance directory on OS X.
+OBJC_CONFORMANCE_TEST=0
+case "$target_os" in
+  darwin*)
+    OBJC_CONFORMANCE_TEST=1
+    ;;
+esac
+AM_CONDITIONAL([OBJC_CONFORMANCE_TEST], [test $OBJC_CONFORMANCE_TEST = 1])
+
+# HACK:  Make gmock's configure script pick up our copy of CFLAGS and CXXFLAGS,
+#   since the flags added by ACX_CHECK_SUNCC must be used when compiling gmock
 #   too.
 export CFLAGS
 export CXXFLAGS
-AC_CONFIG_SUBDIRS([gtest])
+AC_CONFIG_SUBDIRS([gmock])
 
-AC_CONFIG_FILES([Makefile src/Makefile protobuf.pc protobuf-lite.pc])
+AC_CONFIG_FILES([Makefile src/Makefile benchmarks/Makefile conformance/Makefile protobuf.pc protobuf-lite.pc])
 AC_OUTPUT
diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java
new file mode 100644
index 0000000..43787ff
--- /dev/null
+++ b/conformance/ConformanceJava.java
@@ -0,0 +1,142 @@
+
+import com.google.protobuf.conformance.Conformance;
+import com.google.protobuf.util.JsonFormat;
+import com.google.protobuf.util.JsonFormat.TypeRegistry;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+class ConformanceJava {
+  private int testCount = 0;
+  private TypeRegistry typeRegistry;
+
+  private boolean readFromStdin(byte[] buf, int len) throws Exception {
+    int ofs = 0;
+    while (len > 0) {
+      int read = System.in.read(buf, ofs, len);
+      if (read == -1) {
+        return false;  // EOF
+      }
+      ofs += read;
+      len -= read;
+    }
+
+    return true;
+  }
+
+  private void writeToStdout(byte[] buf) throws Exception {
+    System.out.write(buf);
+  }
+
+  // Returns -1 on EOF (the actual values will always be positive).
+  private int readLittleEndianIntFromStdin() throws Exception {
+    byte[] buf = new byte[4];
+    if (!readFromStdin(buf, 4)) {
+      return -1;
+    }
+    return (buf[0] & 0xff)
+        | ((buf[1] & 0xff) << 8)
+        | ((buf[2] & 0xff) << 16)
+        | ((buf[3] & 0xff) << 24);
+  }
+
+  private void writeLittleEndianIntToStdout(int val) throws Exception {
+    byte[] buf = new byte[4];
+    buf[0] = (byte)val;
+    buf[1] = (byte)(val >> 8);
+    buf[2] = (byte)(val >> 16);
+    buf[3] = (byte)(val >> 24);
+    writeToStdout(buf);
+  }
+
+  private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
+    Conformance.TestAllTypes testMessage;
+
+    switch (request.getPayloadCase()) {
+      case PROTOBUF_PAYLOAD: {
+        try {
+          testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload());
+        } catch (InvalidProtocolBufferException e) {
+          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        }
+        break;
+      }
+      case JSON_PAYLOAD: {
+        try {
+          Conformance.TestAllTypes.Builder builder = Conformance.TestAllTypes.newBuilder();
+          JsonFormat.parser().usingTypeRegistry(typeRegistry)
+              .merge(request.getJsonPayload(), builder);
+          testMessage = builder.build();
+        } catch (InvalidProtocolBufferException e) {
+          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        }
+        break;
+      }
+      case PAYLOAD_NOT_SET: {
+        throw new RuntimeException("Request didn't have payload.");
+      }
+
+      default: {
+        throw new RuntimeException("Unexpected payload case.");
+      }
+    }
+
+    switch (request.getRequestedOutputFormat()) {
+      case UNSPECIFIED:
+        throw new RuntimeException("Unspecified output format.");
+
+      case PROTOBUF:
+        return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build();
+
+      case JSON:
+        try {
+          return Conformance.ConformanceResponse.newBuilder().setJsonPayload(
+              JsonFormat.printer().usingTypeRegistry(typeRegistry).print(testMessage)).build();
+        } catch (InvalidProtocolBufferException | IllegalArgumentException e) {
+          return Conformance.ConformanceResponse.newBuilder().setSerializeError(
+              e.getMessage()).build();
+        }
+
+      default: {
+        throw new RuntimeException("Unexpected request output.");
+      }
+    }
+  }
+
+  private boolean doTestIo() throws Exception {
+    int bytes = readLittleEndianIntFromStdin();
+
+    if (bytes == -1) {
+      return false;  // EOF
+    }
+
+    byte[] serializedInput = new byte[bytes];
+
+    if (!readFromStdin(serializedInput, bytes)) {
+      throw new RuntimeException("Unexpected EOF from test program.");
+    }
+
+    Conformance.ConformanceRequest request =
+        Conformance.ConformanceRequest.parseFrom(serializedInput);
+    Conformance.ConformanceResponse response = doTest(request);
+    byte[] serializedOutput = response.toByteArray();
+
+    writeLittleEndianIntToStdout(serializedOutput.length);
+    writeToStdout(serializedOutput);
+
+    return true;
+  }
+
+  public void run() throws Exception {
+    typeRegistry = TypeRegistry.newBuilder().add(
+        Conformance.TestAllTypes.getDescriptor()).build();
+    while (doTestIo()) {
+      this.testCount++;
+    }
+
+    System.err.println("ConformanceJava: received EOF from test runner after " +
+        this.testCount + " tests");
+  }
+
+  public static void main(String[] args) throws Exception {
+    new ConformanceJava().run();
+  }
+}
diff --git a/conformance/ConformanceJavaLite.java b/conformance/ConformanceJavaLite.java
new file mode 100644
index 0000000..121dc7d
--- /dev/null
+++ b/conformance/ConformanceJavaLite.java
@@ -0,0 +1,125 @@
+
+import com.google.protobuf.conformance.Conformance;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+class ConformanceJavaLite {
+  private int testCount = 0;
+
+  private boolean readFromStdin(byte[] buf, int len) throws Exception {
+    int ofs = 0;
+    while (len > 0) {
+      int read = System.in.read(buf, ofs, len);
+      if (read == -1) {
+        return false;  // EOF
+      }
+      ofs += read;
+      len -= read;
+    }
+
+    return true;
+  }
+
+  private void writeToStdout(byte[] buf) throws Exception {
+    System.out.write(buf);
+  }
+
+  // Returns -1 on EOF (the actual values will always be positive).
+  private int readLittleEndianIntFromStdin() throws Exception {
+    byte[] buf = new byte[4];
+    if (!readFromStdin(buf, 4)) {
+      return -1;
+    }
+    return (buf[0] & 0xff)
+        | ((buf[1] & 0xff) << 8)
+        | ((buf[2] & 0xff) << 16)
+        | ((buf[3] & 0xff) << 24);
+  }
+
+  private void writeLittleEndianIntToStdout(int val) throws Exception {
+    byte[] buf = new byte[4];
+    buf[0] = (byte)val;
+    buf[1] = (byte)(val >> 8);
+    buf[2] = (byte)(val >> 16);
+    buf[3] = (byte)(val >> 24);
+    writeToStdout(buf);
+  }
+
+  private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
+    Conformance.TestAllTypes testMessage;
+
+    switch (request.getPayloadCase()) {
+      case PROTOBUF_PAYLOAD: {
+        try {
+          testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload());
+        } catch (InvalidProtocolBufferException e) {
+          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        }
+        break;
+      }
+      case JSON_PAYLOAD: {
+        return Conformance.ConformanceResponse.newBuilder().setSkipped(
+            "Lite runtime does not suport Json Formant.").build();
+      }
+      case PAYLOAD_NOT_SET: {
+        throw new RuntimeException("Request didn't have payload.");
+      }
+
+      default: {
+        throw new RuntimeException("Unexpected payload case.");
+      }
+    }
+
+    switch (request.getRequestedOutputFormat()) {
+      case UNSPECIFIED:
+        throw new RuntimeException("Unspecified output format.");
+
+      case PROTOBUF:
+        return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build();
+
+      case JSON:
+        return Conformance.ConformanceResponse.newBuilder().setSkipped(
+            "Lite runtime does not suport Json Formant.").build();
+
+      default: {
+        throw new RuntimeException("Unexpected request output.");
+      }
+    }
+  }
+
+  private boolean doTestIo() throws Exception {
+    int bytes = readLittleEndianIntFromStdin();
+
+    if (bytes == -1) {
+      return false;  // EOF
+    }
+
+    byte[] serializedInput = new byte[bytes];
+
+    if (!readFromStdin(serializedInput, bytes)) {
+      throw new RuntimeException("Unexpected EOF from test program.");
+    }
+
+    Conformance.ConformanceRequest request =
+        Conformance.ConformanceRequest.parseFrom(serializedInput);
+    Conformance.ConformanceResponse response = doTest(request);
+    byte[] serializedOutput = response.toByteArray();
+
+    writeLittleEndianIntToStdout(serializedOutput.length);
+    writeToStdout(serializedOutput);
+
+    return true;
+  }
+
+  public void run() throws Exception {
+    while (doTestIo()) {
+      this.testCount++;
+    }
+
+    System.err.println("ConformanceJavaLite: received EOF from test runner after " +
+        this.testCount + " tests");
+  }
+
+  public static void main(String[] args) throws Exception {
+    new ConformanceJavaLite().run();
+  }
+}
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
new file mode 100644
index 0000000..31a9e40
--- /dev/null
+++ b/conformance/Makefile.am
@@ -0,0 +1,281 @@
+## Process this file with automake to produce Makefile.in
+
+conformance_protoc_inputs =                                    \
+  conformance.proto
+
+well_known_type_protoc_inputs =                                \
+  $(top_srcdir)/src/google/protobuf/any.proto                  \
+  $(top_srcdir)/src/google/protobuf/duration.proto             \
+  $(top_srcdir)/src/google/protobuf/field_mask.proto           \
+  $(top_srcdir)/src/google/protobuf/struct.proto               \
+  $(top_srcdir)/src/google/protobuf/timestamp.proto            \
+  $(top_srcdir)/src/google/protobuf/wrappers.proto
+
+
+protoc_outputs =                                               \
+  conformance.pb.cc                                            \
+  conformance.pb.h
+
+other_language_protoc_outputs =                                \
+  conformance_pb2.py                                           \
+  Conformance.pbobjc.h                                         \
+  Conformance.pbobjc.m                                         \
+  conformance.rb                                               \
+  com/google/protobuf/Any.java                                 \
+  com/google/protobuf/AnyOrBuilder.java                        \
+  com/google/protobuf/AnyProto.java                            \
+  com/google/protobuf/BoolValue.java                           \
+  com/google/protobuf/BoolValueOrBuilder.java                  \
+  com/google/protobuf/BytesValue.java                          \
+  com/google/protobuf/BytesValueOrBuilder.java                 \
+  com/google/protobuf/conformance/Conformance.java             \
+  com/google/protobuf/DoubleValue.java                         \
+  com/google/protobuf/DoubleValueOrBuilder.java                \
+  com/google/protobuf/Duration.java                            \
+  com/google/protobuf/DurationOrBuilder.java                   \
+  com/google/protobuf/DurationProto.java                       \
+  com/google/protobuf/FieldMask.java                           \
+  com/google/protobuf/FieldMaskOrBuilder.java                  \
+  com/google/protobuf/FieldMaskProto.java                      \
+  com/google/protobuf/FloatValue.java                          \
+  com/google/protobuf/FloatValueOrBuilder.java                 \
+  com/google/protobuf/Int32Value.java                          \
+  com/google/protobuf/Int32ValueOrBuilder.java                 \
+  com/google/protobuf/Int64Value.java                          \
+  com/google/protobuf/Int64ValueOrBuilder.java                 \
+  com/google/protobuf/ListValue.java                           \
+  com/google/protobuf/ListValueOrBuilder.java                  \
+  com/google/protobuf/NullValue.java                           \
+  com/google/protobuf/StringValue.java                         \
+  com/google/protobuf/StringValueOrBuilder.java                \
+  com/google/protobuf/Struct.java                              \
+  com/google/protobuf/StructOrBuilder.java                     \
+  com/google/protobuf/StructProto.java                         \
+  com/google/protobuf/Timestamp.java                           \
+  com/google/protobuf/TimestampOrBuilder.java                  \
+  com/google/protobuf/TimestampProto.java                      \
+  com/google/protobuf/UInt32Value.java                         \
+  com/google/protobuf/UInt32ValueOrBuilder.java                \
+  com/google/protobuf/UInt64Value.java                         \
+  com/google/protobuf/UInt64ValueOrBuilder.java                \
+  com/google/protobuf/Value.java                               \
+  com/google/protobuf/ValueOrBuilder.java                      \
+  com/google/protobuf/WrappersProto.java                       \
+  google/protobuf/any.pb.cc                                    \
+  google/protobuf/any.pb.h                                     \
+  google/protobuf/any.rb                                       \
+  google/protobuf/any_pb2.py                                   \
+  google/protobuf/duration.pb.cc                               \
+  google/protobuf/duration.pb.h                                \
+  google/protobuf/duration.rb                                  \
+  google/protobuf/duration_pb2.py                              \
+  google/protobuf/field_mask.pb.cc                             \
+  google/protobuf/field_mask.pb.h                              \
+  google/protobuf/field_mask.rb                                \
+  google/protobuf/field_mask_pb2.py                            \
+  google/protobuf/struct.pb.cc                                 \
+  google/protobuf/struct.pb.h                                  \
+  google/protobuf/struct.rb                                    \
+  google/protobuf/struct_pb2.py                                \
+  google/protobuf/timestamp.pb.cc                              \
+  google/protobuf/timestamp.pb.h                               \
+  google/protobuf/timestamp.rb                                 \
+  google/protobuf/timestamp_pb2.py                             \
+  google/protobuf/wrappers.pb.cc                               \
+  google/protobuf/wrappers.pb.h                                \
+  google/protobuf/wrappers.rb                                  \
+  google/protobuf/wrappers_pb2.py                              \
+  lite/com/google/protobuf/Any.java                            \
+  lite/com/google/protobuf/AnyOrBuilder.java                   \
+  lite/com/google/protobuf/AnyProto.java                       \
+  lite/com/google/protobuf/BoolValue.java                      \
+  lite/com/google/protobuf/BoolValueOrBuilder.java             \
+  lite/com/google/protobuf/BytesValue.java                     \
+  lite/com/google/protobuf/BytesValueOrBuilder.java            \
+  lite/com/google/protobuf/conformance/Conformance.java        \
+  lite/com/google/protobuf/DoubleValue.java                    \
+  lite/com/google/protobuf/DoubleValueOrBuilder.java           \
+  lite/com/google/protobuf/Duration.java                       \
+  lite/com/google/protobuf/DurationOrBuilder.java              \
+  lite/com/google/protobuf/DurationProto.java                  \
+  lite/com/google/protobuf/FieldMask.java                      \
+  lite/com/google/protobuf/FieldMaskOrBuilder.java             \
+  lite/com/google/protobuf/FieldMaskProto.java                 \
+  lite/com/google/protobuf/FloatValue.java                     \
+  lite/com/google/protobuf/FloatValueOrBuilder.java            \
+  lite/com/google/protobuf/Int32Value.java                     \
+  lite/com/google/protobuf/Int32ValueOrBuilder.java            \
+  lite/com/google/protobuf/Int64Value.java                     \
+  lite/com/google/protobuf/Int64ValueOrBuilder.java            \
+  lite/com/google/protobuf/ListValue.java                      \
+  lite/com/google/protobuf/ListValueOrBuilder.java             \
+  lite/com/google/protobuf/NullValue.java                      \
+  lite/com/google/protobuf/StringValue.java                    \
+  lite/com/google/protobuf/StringValueOrBuilder.java           \
+  lite/com/google/protobuf/Struct.java                         \
+  lite/com/google/protobuf/StructOrBuilder.java                \
+  lite/com/google/protobuf/StructProto.java                    \
+  lite/com/google/protobuf/Timestamp.java                      \
+  lite/com/google/protobuf/TimestampOrBuilder.java             \
+  lite/com/google/protobuf/TimestampProto.java                 \
+  lite/com/google/protobuf/UInt32Value.java                    \
+  lite/com/google/protobuf/UInt32ValueOrBuilder.java           \
+  lite/com/google/protobuf/UInt64Value.java                    \
+  lite/com/google/protobuf/UInt64ValueOrBuilder.java           \
+  lite/com/google/protobuf/Value.java                          \
+  lite/com/google/protobuf/ValueOrBuilder.java                 \
+  lite/com/google/protobuf/WrappersProto.java
+
+bin_PROGRAMS = conformance-test-runner conformance-cpp
+
+# All source files excepet C++/Objective-C ones should be explicitly listed
+# here because the autoconf tools don't include files of other languages
+# automatically.
+EXTRA_DIST =                  \
+  ConformanceJava.java        \
+  ConformanceJavaLite.java    \
+  README.md                   \
+  conformance.proto           \
+  conformance_python.py       \
+  conformance_ruby.rb         \
+  failure_list_cpp.txt        \
+  failure_list_csharp.txt     \
+  failure_list_java.txt       \
+  failure_list_objc.txt       \
+  failure_list_python.txt     \
+  failure_list_python_cpp.txt \
+  failure_list_python-post26.txt \
+  failure_list_ruby.txt
+
+conformance_test_runner_LDADD = $(top_srcdir)/src/libprotobuf.la
+conformance_test_runner_SOURCES = conformance_test.h conformance_test.cc \
+                                  conformance_test_runner.cc             \
+                                  third_party/jsoncpp/json.h             \
+                                  third_party/jsoncpp/jsoncpp.cpp
+nodist_conformance_test_runner_SOURCES = conformance.pb.cc
+conformance_test_runner_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir)
+conformance_test_runner_CXXFLAGS = -std=c++11
+# Explicit deps beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_cpp" could fail if parallel enough.
+conformance_test_runner-conformance_test.$(OBJEXT): conformance.pb.h
+conformance_test_runner-conformance_test_runner.$(OBJEXT): conformance.pb.h
+
+conformance_cpp_LDADD = $(top_srcdir)/src/libprotobuf.la
+conformance_cpp_SOURCES = conformance_cpp.cc
+nodist_conformance_cpp_SOURCES = conformance.pb.cc
+conformance_cpp_CPPFLAGS = -I$(top_srcdir)/src
+# Explicit dep beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_cpp" could fail if parallel enough.
+conformance_cpp-conformance_cpp.$(OBJEXT): conformance.pb.h
+
+if OBJC_CONFORMANCE_TEST
+
+bin_PROGRAMS += conformance-objc
+
+conformance_objc_SOURCES = conformance_objc.m ../objectivec/GPBProtocolBuffers.m
+nodist_conformance_objc_SOURCES = Conformance.pbobjc.m
+# On travis, the build fails without the isysroot because whatever system
+# headers are being found don't include generics support for
+# NSArray/NSDictionary, the only guess is their image at one time had an odd
+# setup for Xcode and old frameworks are being found.
+conformance_objc_CPPFLAGS = -I$(top_srcdir)/objectivec -isysroot `xcrun --sdk macosx --show-sdk-path`
+conformance_objc_LDFLAGS = -framework Foundation
+# Explicit dep beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_objc" could fail if parallel enough.
+conformance_objc-conformance_objc.$(OBJEXT): Conformance.pbobjc.h
+
+endif
+
+if USE_EXTERNAL_PROTOC
+
+# Some implementations include pre-generated versions of well-known types.
+protoc_middleman: $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --objc_out=. --python_out=. $(conformance_protoc_inputs)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --python_out=. $(well_known_type_protoc_inputs)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
+	touch protoc_middleman
+
+else
+
+# We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
+# relative to srcdir, which may not be the same as the current directory when
+# building out-of-tree.
+protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --objc_out=$$oldpwd --python_out=$$oldpwd $(conformance_protoc_inputs) )
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --python_out=$$oldpwd $(well_known_type_protoc_inputs) )
+	@mkdir -p lite
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) )
+	touch protoc_middleman
+
+endif
+
+$(protoc_outputs): protoc_middleman
+
+$(other_language_protoc_outputs): protoc_middleman
+
+BUILT_SOURCES = $(protoc_outputs) $(other_language_protoc_outputs)
+
+CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java javac_middleman_lite conformance-java-lite conformance-csharp $(other_language_protoc_outputs)
+
+MAINTAINERCLEANFILES =   \
+  Makefile.in
+
+javac_middleman: ConformanceJava.java protoc_middleman $(other_language_protoc_outputs)
+	jar=`ls ../java/util/target/*jar-with-dependencies.jar` && javac -classpath ../java/target/classes:$$jar ConformanceJava.java com/google/protobuf/conformance/Conformance.java
+	@touch javac_middleman
+
+conformance-java: javac_middleman
+	@echo "Writing shortcut script conformance-java..."
+	@echo '#! /bin/sh' > conformance-java
+	@jar=`ls ../java/util/target/*jar-with-dependencies.jar` && echo java -classpath .:../java/target/classes:$$jar ConformanceJava '$$@' >> conformance-java
+	@chmod +x conformance-java
+
+javac_middleman_lite: ConformanceJavaLite.java protoc_middleman $(other_language_protoc_outputs)
+	javac -classpath ../java/lite/target/classes:lite ConformanceJavaLite.java lite/com/google/protobuf/conformance/Conformance.java
+	@touch javac_middleman_lite
+
+conformance-java-lite: javac_middleman_lite
+	@echo "Writing shortcut script conformance-java-lite..."
+	@echo '#! /bin/sh' > conformance-java-lite
+	@echo java -classpath .:../java/lite/target/classes:lite ConformanceJavaLite '$$@' >> conformance-java-lite
+	@chmod +x conformance-java-lite
+
+# Currently the conformance code is alongside the rest of the C#
+# source, as it's easier to maintain there. We assume we've already
+# built that, so we just need a script to run it.
+conformance-csharp: $(other_language_protoc_outputs)
+	@echo "Writing shortcut script conformance-csharp..."
+	@echo '#! /bin/sh' > conformance-csharp
+	@echo 'mono ../csharp/src/Google.Protobuf.Conformance/bin/Release/Google.Protobuf.Conformance.exe "$$@"' >> conformance-csharp
+	@chmod +x conformance-csharp
+
+# Targets for actually running tests.
+test_cpp: protoc_middleman conformance-test-runner conformance-cpp
+	./conformance-test-runner --failure_list failure_list_cpp.txt ./conformance-cpp
+
+test_java: protoc_middleman conformance-test-runner conformance-java
+	./conformance-test-runner --failure_list failure_list_java.txt ./conformance-java
+
+test_java_lite: protoc_middleman conformance-test-runner conformance-java-lite
+	./conformance-test-runner ./conformance-java-lite
+
+test_csharp: protoc_middleman conformance-test-runner conformance-csharp
+	./conformance-test-runner --failure_list failure_list_csharp.txt ./conformance-csharp
+
+test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
+	RUBYLIB=../ruby/lib:. ./conformance-test-runner --failure_list failure_list_ruby.txt ./conformance_ruby.rb
+
+# These depend on library paths being properly set up.  The easiest way to
+# run them is to just use "tox" from the python dir.
+test_python: protoc_middleman conformance-test-runner
+	./conformance-test-runner --failure_list failure_list_python.txt $(CONFORMANCE_PYTHON_EXTRA_FAILURES) ./conformance_python.py
+
+test_python_cpp: protoc_middleman conformance-test-runner
+	./conformance-test-runner --failure_list failure_list_python_cpp.txt $(CONFORMANCE_PYTHON_EXTRA_FAILURES) ./conformance_python.py
+
+if OBJC_CONFORMANCE_TEST
+
+test_objc: protoc_middleman conformance-test-runner conformance-objc
+	./conformance-test-runner --failure_list failure_list_objc.txt ./conformance-objc
+
+endif
diff --git a/conformance/README.md b/conformance/README.md
new file mode 100644
index 0000000..9388055
--- /dev/null
+++ b/conformance/README.md
@@ -0,0 +1,45 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains conformance tests for testing completeness and
+correctness of Protocol Buffers implementations.  These tests are designed
+to be easy to run against any Protocol Buffers implementation.
+
+This directory contains the tester process `conformance-test`, which
+contains all of the tests themselves.  Then separate programs written
+in whatever language you want to test communicate with the tester
+program over a pipe.
+
+Before running any of these tests, make sure you run `make` in the base
+directory to build `protoc`, since all the tests depend on it.
+
+    $ make
+
+Then to run the tests against the C++ implementation, run:
+
+    $ cd conformance && make test_cpp
+
+More tests and languages will be added soon!
+
+Testing other Protocol Buffer implementations
+---------------------------------------------
+
+To run these tests against a new Protocol Buffers implementation, write a
+program in your language that uses the protobuf implementation you want
+to test.  This program should implement the testing protocol defined in
+[conformance.proto](https://github.com/google/protobuf/blob/master/conformance/conformance.proto).
+This is designed to be as easy as possible: the C++ version is only
+150 lines and is a good example for what this program should look like
+(see [conformance_cpp.cc](https://github.com/google/protobuf/blob/master/conformance/conformance_cpp.cc)).
+The program only needs to be able to read from stdin and write to stdout.
+
+Portability
+-----------
+
+Note that the test runner currently does not work on Windows.  Patches
+to fix this are welcome!  (But please get in touch first to settle on
+a general implementation strategy).
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
new file mode 100644
index 0000000..fc96074
--- /dev/null
+++ b/conformance/conformance.proto
@@ -0,0 +1,273 @@
+// 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.
+
+syntax = "proto3";
+package conformance;
+option java_package = "com.google.protobuf.conformance";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+
+// This defines the conformance testing protocol.  This protocol exists between
+// the conformance test suite itself and the code being tested.  For each test,
+// the suite will send a ConformanceRequest message and expect a
+// ConformanceResponse message.
+//
+// You can either run the tests in two different ways:
+//
+//   1. in-process (using the interface in conformance_test.h).
+//
+//   2. as a sub-process communicating over a pipe.  Information about how to
+//      do this is in conformance_test_runner.cc.
+//
+// Pros/cons of the two approaches:
+//
+//   - running as a sub-process is much simpler for languages other than C/C++.
+//
+//   - running as a sub-process may be more tricky in unusual environments like
+//     iOS apps, where fork/stdin/stdout are not available.
+
+enum WireFormat {
+  UNSPECIFIED = 0;
+  PROTOBUF = 1;
+  JSON = 2;
+}
+
+// Represents a single test case's input.  The testee should:
+//
+//   1. parse this proto (which should always succeed)
+//   2. parse the protobuf or JSON payload in "payload" (which may fail)
+//   3. if the parse succeeded, serialize the message in the requested format.
+message ConformanceRequest {
+  // The payload (whether protobuf of JSON) is always for a TestAllTypes proto
+  // (see below).
+  oneof payload {
+    bytes protobuf_payload = 1;
+    string json_payload = 2;
+  }
+
+  // Which format should the testee serialize its message to?
+  WireFormat requested_output_format = 3;
+}
+
+// Represents a single test case's output.
+message ConformanceResponse {
+  oneof result {
+    // This string should be set to indicate parsing failed.  The string can
+    // provide more information about the parse error if it is available.
+    //
+    // Setting this string does not necessarily mean the testee failed the
+    // test.  Some of the test cases are intentionally invalid input.
+    string parse_error = 1;
+
+    // If the input was successfully parsed but errors occurred when
+    // serializing it to the requested output format, set the error message in
+    // this field.
+    string serialize_error = 6;
+
+    // This should be set if some other error occurred.  This will always
+    // indicate that the test failed.  The string can provide more information
+    // about the failure.
+    string runtime_error = 2;
+
+    // If the input was successfully parsed and the requested output was
+    // protobuf, serialize it to protobuf and set it in this field.
+    bytes protobuf_payload = 3;
+
+    // If the input was successfully parsed and the requested output was JSON,
+    // serialize to JSON and set it in this field.
+    string json_payload = 4;
+
+    // For when the testee skipped the test, likely because a certain feature
+    // wasn't supported, like JSON input/output.
+    string skipped = 5;
+  }
+}
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    int32 a = 1;
+    TestAllTypes corecursive = 2;
+  }
+
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  int32 optional_int32    =  1;
+  int64 optional_int64    =  2;
+  uint32 optional_uint32   =  3;
+  uint64 optional_uint64   =  4;
+  sint32 optional_sint32   =  5;
+  sint64 optional_sint64   =  6;
+  fixed32 optional_fixed32  =  7;
+  fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float    = 11;
+  double optional_double   = 12;
+  bool optional_bool     = 13;
+  string optional_string   = 14;
+  bytes optional_bytes    = 15;
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  TestAllTypes recursive_message = 27;
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  // Map
+  map <   int32, int32>    map_int32_int32 = 56;
+  map <   int64, int64>    map_int64_int64 = 57;
+  map <  uint32, uint32>   map_uint32_uint32 = 58;
+  map <  uint64, uint64>   map_uint64_uint64 = 59;
+  map <  sint32, sint32>   map_sint32_sint32 = 60;
+  map <  sint64, sint64>   map_sint64_sint64 = 61;
+  map < fixed32, fixed32>  map_fixed32_fixed32 = 62;
+  map < fixed64, fixed64>  map_fixed64_fixed64 = 63;
+  map <sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
+  map <sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
+  map <   int32, float>    map_int32_float = 66;
+  map <   int32, double>   map_int32_double = 67;
+  map <    bool, bool>     map_bool_bool = 68;
+  map <  string, string>   map_string_string = 69;
+  map <  string, bytes>    map_string_bytes = 70;
+  map <  string, NestedMessage>  map_string_nested_message = 71;
+  map <  string, ForeignMessage> map_string_foreign_message = 72;
+  map <  string, NestedEnum>     map_string_nested_enum = 73;
+  map <  string, ForeignEnum>    map_string_foreign_enum = 74;
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+
+  // Well-known types
+  google.protobuf.BoolValue optional_bool_wrapper = 201;
+  google.protobuf.Int32Value optional_int32_wrapper = 202;
+  google.protobuf.Int64Value optional_int64_wrapper = 203;
+  google.protobuf.UInt32Value optional_uint32_wrapper = 204;
+  google.protobuf.UInt64Value optional_uint64_wrapper = 205;
+  google.protobuf.FloatValue optional_float_wrapper = 206;
+  google.protobuf.DoubleValue optional_double_wrapper = 207;
+  google.protobuf.StringValue optional_string_wrapper = 208;
+  google.protobuf.BytesValue optional_bytes_wrapper = 209;
+
+  repeated google.protobuf.BoolValue repeated_bool_wrapper = 211;
+  repeated google.protobuf.Int32Value repeated_int32_wrapper = 212;
+  repeated google.protobuf.Int64Value repeated_int64_wrapper = 213;
+  repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214;
+  repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215;
+  repeated google.protobuf.FloatValue repeated_float_wrapper = 216;
+  repeated google.protobuf.DoubleValue repeated_double_wrapper = 217;
+  repeated google.protobuf.StringValue repeated_string_wrapper = 218;
+  repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219;
+
+  google.protobuf.Duration optional_duration = 301;
+  google.protobuf.Timestamp optional_timestamp = 302;
+  google.protobuf.FieldMask optional_field_mask = 303;
+  google.protobuf.Struct optional_struct = 304;
+  google.protobuf.Any optional_any = 305;
+  google.protobuf.Value optional_value = 306;
+
+  repeated google.protobuf.Duration repeated_duration = 311;
+  repeated google.protobuf.Timestamp repeated_timestamp = 312;
+  repeated google.protobuf.FieldMask repeated_fieldmask = 313;
+  repeated google.protobuf.Struct repeated_struct = 324;
+  repeated google.protobuf.Any repeated_any = 315;
+  repeated google.protobuf.Value repeated_value = 316;
+
+  // Test field-name-to-JSON-name convention.
+  int32 fieldname1 = 401;
+  int32 field_name2 = 402;
+  int32 _field_name3 = 403;
+  int32 field__name4_ = 404;
+  int32 field0name5 = 405;
+  int32 field_0_name6 = 406;
+  int32 fieldName7 = 407;
+  int32 FieldName8 = 408;
+  int32 field_Name9 = 409;
+  int32 Field_Name10 = 410;
+  int32 FIELD_NAME11 = 411;
+  int32 FIELD_name12 = 412;
+}
+
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 0;
+  FOREIGN_BAR = 1;
+  FOREIGN_BAZ = 2;
+}
diff --git a/conformance/conformance_cpp.cc b/conformance/conformance_cpp.cc
new file mode 100644
index 0000000..1a26549
--- /dev/null
+++ b/conformance/conformance_cpp.cc
@@ -0,0 +1,207 @@
+// 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.
+
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "conformance.pb.h"
+#include <google/protobuf/util/json_util.h>
+#include <google/protobuf/util/type_resolver_util.h>
+
+using conformance::ConformanceRequest;
+using conformance::ConformanceResponse;
+using conformance::TestAllTypes;
+using google::protobuf::Descriptor;
+using google::protobuf::DescriptorPool;
+using google::protobuf::internal::scoped_ptr;
+using google::protobuf::util::BinaryToJsonString;
+using google::protobuf::util::JsonToBinaryString;
+using google::protobuf::util::NewTypeResolverForDescriptorPool;
+using google::protobuf::util::Status;
+using google::protobuf::util::TypeResolver;
+using std::string;
+
+static const char kTypeUrlPrefix[] = "type.googleapis.com";
+
+static string GetTypeUrl(const Descriptor* message) {
+  return string(kTypeUrlPrefix) + "/" + message->full_name();
+}
+
+int test_count = 0;
+bool verbose = false;
+TypeResolver* type_resolver;
+string* type_url;
+
+
+bool CheckedRead(int fd, void *buf, size_t len) {
+  size_t ofs = 0;
+  while (len > 0) {
+    ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
+
+    if (bytes_read == 0) return false;
+
+    if (bytes_read < 0) {
+      GOOGLE_LOG(FATAL) << "Error reading from test runner: " <<  strerror(errno);
+    }
+
+    len -= bytes_read;
+    ofs += bytes_read;
+  }
+
+  return true;
+}
+
+void CheckedWrite(int fd, const void *buf, size_t len) {
+  if (write(fd, buf, len) != len) {
+    GOOGLE_LOG(FATAL) << "Error writing to test runner: " << strerror(errno);
+  }
+}
+
+void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
+  TestAllTypes test_message;
+
+  switch (request.payload_case()) {
+    case ConformanceRequest::kProtobufPayload:
+      if (!test_message.ParseFromString(request.protobuf_payload())) {
+        // Getting parse details would involve something like:
+        //   http://stackoverflow.com/questions/22121922/how-can-i-get-more-details-about-errors-generated-during-protobuf-parsing-c
+        response->set_parse_error("Parse error (no more details available).");
+        return;
+      }
+      break;
+
+    case ConformanceRequest::kJsonPayload: {
+      string proto_binary;
+      Status status = JsonToBinaryString(type_resolver, *type_url,
+                                         request.json_payload(), &proto_binary);
+      if (!status.ok()) {
+        response->set_parse_error(string("Parse error: ") +
+                                  status.error_message().as_string());
+        return;
+      }
+
+      if (!test_message.ParseFromString(proto_binary)) {
+        response->set_runtime_error(
+            "Parsing JSON generates invalid proto output.");
+        return;
+      }
+      break;
+    }
+
+    case ConformanceRequest::PAYLOAD_NOT_SET:
+      GOOGLE_LOG(FATAL) << "Request didn't have payload.";
+      break;
+  }
+
+  switch (request.requested_output_format()) {
+    case conformance::UNSPECIFIED:
+      GOOGLE_LOG(FATAL) << "Unspecified output format";
+      break;
+
+    case conformance::PROTOBUF:
+      GOOGLE_CHECK(
+          test_message.SerializeToString(response->mutable_protobuf_payload()));
+      break;
+
+    case conformance::JSON: {
+      string proto_binary;
+      GOOGLE_CHECK(test_message.SerializeToString(&proto_binary));
+      Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
+                                         response->mutable_json_payload());
+      if (!status.ok()) {
+        response->set_serialize_error(
+            string("Failed to serialize JSON output: ") +
+            status.error_message().as_string());
+        return;
+      }
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unknown output format: "
+                        << request.requested_output_format();
+  }
+}
+
+bool DoTestIo() {
+  string serialized_input;
+  string serialized_output;
+  ConformanceRequest request;
+  ConformanceResponse response;
+  uint32_t bytes;
+
+  if (!CheckedRead(STDIN_FILENO, &bytes, sizeof(uint32_t))) {
+    // EOF.
+    return false;
+  }
+
+  serialized_input.resize(bytes);
+
+  if (!CheckedRead(STDIN_FILENO, (char*)serialized_input.c_str(), bytes)) {
+    GOOGLE_LOG(ERROR) << "Unexpected EOF on stdin. " << strerror(errno);
+  }
+
+  if (!request.ParseFromString(serialized_input)) {
+    GOOGLE_LOG(FATAL) << "Parse of ConformanceRequest proto failed.";
+    return false;
+  }
+
+  DoTest(request, &response);
+
+  response.SerializeToString(&serialized_output);
+
+  bytes = serialized_output.size();
+  CheckedWrite(STDOUT_FILENO, &bytes, sizeof(uint32_t));
+  CheckedWrite(STDOUT_FILENO, serialized_output.c_str(), bytes);
+
+  if (verbose) {
+    fprintf(stderr, "conformance-cpp: request=%s, response=%s\n",
+            request.ShortDebugString().c_str(),
+            response.ShortDebugString().c_str());
+  }
+
+  test_count++;
+
+  return true;
+}
+
+int main() {
+  type_resolver = NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool());
+  type_url = new string(GetTypeUrl(TestAllTypes::descriptor()));
+  while (1) {
+    if (!DoTestIo()) {
+      fprintf(stderr, "conformance-cpp: received EOF from test runner "
+                      "after %d tests, exiting\n", test_count);
+      return 0;
+    }
+  }
+}
diff --git a/conformance/conformance_objc.m b/conformance/conformance_objc.m
new file mode 100644
index 0000000..1124bfe
--- /dev/null
+++ b/conformance/conformance_objc.m
@@ -0,0 +1,179 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+
+#import "Conformance.pbobjc.h"
+
+static void Die(NSString *format, ...) __dead2;
+
+static BOOL verbose = NO;
+static int32_t testCount = 0;
+
+static void Die(NSString *format, ...) {
+  va_list args;
+  va_start(args, format);
+  NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
+  NSLog(@"%@", msg);
+  va_end(args);
+  [msg release];
+  exit(66);
+}
+
+static NSData *CheckedReadDataOfLength(NSFileHandle *handle, NSUInteger numBytes) {
+  NSData *data = [handle readDataOfLength:numBytes];
+  NSUInteger dataLen = data.length;
+  if (dataLen == 0) {
+    return nil;  // EOF.
+  }
+  if (dataLen != numBytes) {
+    Die(@"Failed to read the request length (%d), only got: %@",
+        numBytes, data);
+  }
+  return data;
+}
+
+static ConformanceResponse *DoTest(ConformanceRequest *request) {
+  ConformanceResponse *response = [ConformanceResponse message];
+  TestAllTypes *testMessage = nil;
+
+  switch (request.payloadOneOfCase) {
+    case ConformanceRequest_Payload_OneOfCase_GPBUnsetOneOfCase:
+      Die(@"Request didn't have a payload: %@", request);
+      break;
+
+    case ConformanceRequest_Payload_OneOfCase_ProtobufPayload: {
+      NSError *error = nil;
+      testMessage = [TestAllTypes parseFromData:request.protobufPayload
+                                          error:&error];
+      if (!testMessage) {
+        response.parseError =
+            [NSString stringWithFormat:@"Parse error: %@", error];
+      }
+      break;
+    }
+
+    case ConformanceRequest_Payload_OneOfCase_JsonPayload:
+      response.skipped = @"ObjC doesn't support parsing JSON";
+      break;
+  }
+
+  if (testMessage) {
+    switch (request.requestedOutputFormat) {
+      case WireFormat_GPBUnrecognizedEnumeratorValue:
+      case WireFormat_Unspecified:
+        Die(@"Unrecognized/unspecified output format: %@", request);
+        break;
+
+      case WireFormat_Protobuf:
+        response.protobufPayload = testMessage.data;
+        if (!response.protobufPayload) {
+          response.serializeError =
+            [NSString stringWithFormat:@"Failed to make data from: %@", testMessage];
+        }
+        break;
+
+      case WireFormat_Json:
+        response.skipped = @"ObjC doesn't support generating JSON";
+        break;
+    }
+  }
+
+  return response;
+}
+
+static uint32_t UInt32FromLittleEndianData(NSData *data) {
+  if (data.length != sizeof(uint32_t)) {
+    Die(@"Data not the right size for uint32_t: %@", data);
+  }
+  uint32_t value;
+  memcpy(&value, data.bytes, sizeof(uint32_t));
+  return CFSwapInt32LittleToHost(value);
+}
+
+static NSData *UInt32ToLittleEndianData(uint32_t num) {
+  uint32_t value = CFSwapInt32HostToLittle(num);
+  return [NSData dataWithBytes:&value length:sizeof(uint32_t)];
+}
+
+static BOOL DoTestIo(NSFileHandle *input, NSFileHandle *output) {
+  // See conformance_test_runner.cc for the wire format.
+  NSData *data = CheckedReadDataOfLength(input, sizeof(uint32_t));
+  if (!data) {
+    // EOF.
+    return NO;
+  }
+  uint32_t numBytes = UInt32FromLittleEndianData(data);
+  data = CheckedReadDataOfLength(input, numBytes);
+  if (!data) {
+    Die(@"Failed to read request");
+  }
+
+  NSError *error = nil;
+  ConformanceRequest *request = [ConformanceRequest parseFromData:data
+                                                            error:&error];
+  if (!request) {
+    Die(@"Failed to parse the message data: %@", error);
+  }
+
+  ConformanceResponse *response = DoTest(request);
+  if (!response) {
+    Die(@"Failed to make a reply from %@", request);
+  }
+
+  data = response.data;
+  [output writeData:UInt32ToLittleEndianData((int32_t)data.length)];
+  [output writeData:data];
+
+  if (verbose) {
+    NSLog(@"Request: %@", request);
+    NSLog(@"Response: %@", response);
+  }
+
+  ++testCount;
+  return YES;
+}
+
+int main(int argc, const char *argv[]) {
+  @autoreleasepool {
+    NSFileHandle *input = [[NSFileHandle fileHandleWithStandardInput] retain];
+    NSFileHandle *output = [[NSFileHandle fileHandleWithStandardOutput] retain];
+
+    BOOL notDone = YES;
+    while (notDone) {
+      @autoreleasepool {
+        notDone = DoTestIo(input, output);
+      }
+    }
+
+    NSLog(@"Received EOF from test runner after %d tests, exiting.", testCount);
+  }
+  return 0;
+}
diff --git a/conformance/conformance_python.py b/conformance/conformance_python.py
new file mode 100755
index 0000000..a490c8e
--- /dev/null
+++ b/conformance/conformance_python.py
@@ -0,0 +1,130 @@
+#!/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.
+
+"""A conformance test implementation for the Python protobuf library.
+
+See conformance.proto for more information.
+"""
+
+import struct
+import sys
+import os
+from google.protobuf import message
+from google.protobuf import json_format
+import conformance_pb2
+
+sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
+sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
+
+test_count = 0
+verbose = False
+
+class ProtocolError(Exception):
+  pass
+
+def do_test(request):
+  test_message = conformance_pb2.TestAllTypes()
+  response = conformance_pb2.ConformanceResponse()
+  test_message = conformance_pb2.TestAllTypes()
+
+  try:
+    if request.WhichOneof('payload') == 'protobuf_payload':
+      try:
+        test_message.ParseFromString(request.protobuf_payload)
+      except message.DecodeError as e:
+        response.parse_error = str(e)
+        return response
+
+    elif request.WhichOneof('payload') == 'json_payload':
+      try:
+        json_format.Parse(request.json_payload, test_message)
+      except json_format.ParseError as e:
+        response.parse_error = str(e)
+        return response
+
+    else:
+      raise ProtocolError("Request didn't have payload.")
+
+    if request.requested_output_format == conformance_pb2.UNSPECIFIED:
+      raise ProtocolError("Unspecified output format")
+
+    elif request.requested_output_format == conformance_pb2.PROTOBUF:
+      response.protobuf_payload = test_message.SerializeToString()
+
+    elif request.requested_output_format == conformance_pb2.JSON:
+      response.json_payload = json_format.MessageToJson(test_message)
+
+  except Exception as e:
+    response.runtime_error = str(e)
+
+  return response
+
+def do_test_io():
+  length_bytes = sys.stdin.read(4)
+  if len(length_bytes) == 0:
+    return False   # EOF
+  elif len(length_bytes) != 4:
+    raise IOError("I/O error")
+
+  # "I" is "unsigned int", so this depends on running on a platform with
+  # 32-bit "unsigned int" type.  The Python struct module unfortunately
+  # has no format specifier for uint32_t.
+  length = struct.unpack("<I", length_bytes)[0]
+  serialized_request = sys.stdin.read(length)
+  if len(serialized_request) != length:
+    raise IOError("I/O error")
+
+  request = conformance_pb2.ConformanceRequest()
+  request.ParseFromString(serialized_request)
+
+  response = do_test(request)
+
+  serialized_response = response.SerializeToString()
+  sys.stdout.write(struct.pack("<I", len(serialized_response)))
+  sys.stdout.write(serialized_response)
+  sys.stdout.flush()
+
+  if verbose:
+    sys.stderr.write("conformance_python: request=%s, response=%s\n" % (
+                       request.ShortDebugString().c_str(),
+                       response.ShortDebugString().c_str()))
+
+  global test_count
+  test_count += 1
+
+  return True
+
+while True:
+  if not do_test_io():
+    sys.stderr.write("conformance_python: received EOF from test runner " +
+                     "after %s tests, exiting\n" % (test_count))
+    sys.exit(0)
diff --git a/conformance/conformance_ruby.rb b/conformance/conformance_ruby.rb
new file mode 100755
index 0000000..c716fac
--- /dev/null
+++ b/conformance/conformance_ruby.rb
@@ -0,0 +1,122 @@
+#!/usr/bin/env ruby
+#
+# 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.
+
+require 'conformance'
+
+$test_count = 0
+$verbose = false
+
+def do_test(request)
+  test_message = Conformance::TestAllTypes.new
+  response = Conformance::ConformanceResponse.new
+
+  begin
+    case request.payload
+    when :protobuf_payload
+      begin
+        test_message =
+          Conformance::TestAllTypes.decode(request.protobuf_payload)
+      rescue Google::Protobuf::ParseError => err
+        response.parse_error = err.message.encode('utf-8')
+        return response
+      end
+
+    when :json_payload
+      begin
+        test_message = Conformance::TestAllTypes.decode_json(request.json_payload)
+      rescue Google::Protobuf::ParseError => err
+        response.parse_error = err.message.encode('utf-8')
+        return response
+      end
+
+    when nil
+      fail "Request didn't have payload"
+    end
+
+    case request.requested_output_format
+    when :UNSPECIFIED
+      fail 'Unspecified output format'
+
+    when :PROTOBUF
+      response.protobuf_payload = test_message.to_proto
+
+    when :JSON
+      response.json_payload = test_message.to_json
+
+    when nil
+      fail "Request didn't have requested output format"
+    end
+  rescue StandardError => err
+    response.runtime_error = err.message.encode('utf-8')
+  end
+
+  response
+end
+
+# Returns true if the test ran successfully, false on legitimate EOF.
+# If EOF is encountered in an unexpected place, raises IOError.
+def do_test_io
+  length_bytes = STDIN.read(4)
+  return false if length_bytes.nil?
+
+  length = length_bytes.unpack('V').first
+  serialized_request = STDIN.read(length)
+  if serialized_request.nil? || serialized_request.length != length
+    fail IOError
+  end
+
+  request = Conformance::ConformanceRequest.decode(serialized_request)
+
+  response = do_test(request)
+
+  serialized_response = Conformance::ConformanceResponse.encode(response)
+  STDOUT.write([serialized_response.length].pack('V'))
+  STDOUT.write(serialized_response)
+  STDOUT.flush
+
+  if $verbose
+    STDERR.puts("conformance_ruby: request=#{request.to_json}, " \
+                                 "response=#{response.to_json}\n")
+  end
+
+  $test_count += 1
+
+  true
+end
+
+loop do
+  unless do_test_io
+    STDERR.puts('conformance_ruby: received EOF from test runner ' \
+                "after #{$test_count} tests, exiting")
+    break
+  end
+end
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
new file mode 100644
index 0000000..fc0605b
--- /dev/null
+++ b/conformance/conformance_test.cc
@@ -0,0 +1,2006 @@
+// 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.
+
+#include <stdarg.h>
+#include <string>
+
+#include "conformance.pb.h"
+#include "conformance_test.h"
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/json_util.h>
+#include <google/protobuf/util/field_comparator.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/util/type_resolver_util.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#include "third_party/jsoncpp/json.h"
+
+using conformance::ConformanceRequest;
+using conformance::ConformanceResponse;
+using conformance::TestAllTypes;
+using conformance::WireFormat;
+using google::protobuf::Descriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::internal::WireFormatLite;
+using google::protobuf::TextFormat;
+using google::protobuf::util::DefaultFieldComparator;
+using google::protobuf::util::JsonToBinaryString;
+using google::protobuf::util::MessageDifferencer;
+using google::protobuf::util::NewTypeResolverForDescriptorPool;
+using google::protobuf::util::Status;
+using std::string;
+
+namespace {
+
+static const char kTypeUrlPrefix[] = "type.googleapis.com";
+
+static string GetTypeUrl(const Descriptor* message) {
+  return string(kTypeUrlPrefix) + "/" + message->full_name();
+}
+
+/* Routines for building arbitrary protos *************************************/
+
+// We would use CodedOutputStream except that we want more freedom to build
+// arbitrary protos (even invalid ones).
+
+const string empty;
+
+string cat(const string& a, const string& b,
+           const string& c = empty,
+           const string& d = empty,
+           const string& e = empty,
+           const string& f = empty,
+           const string& g = empty,
+           const string& h = empty,
+           const string& i = empty,
+           const string& j = empty,
+           const string& k = empty,
+           const string& l = empty) {
+  string ret;
+  ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() +
+              g.size() + h.size() + i.size() + j.size() + k.size() + l.size());
+  ret.append(a);
+  ret.append(b);
+  ret.append(c);
+  ret.append(d);
+  ret.append(e);
+  ret.append(f);
+  ret.append(g);
+  ret.append(h);
+  ret.append(i);
+  ret.append(j);
+  ret.append(k);
+  ret.append(l);
+  return ret;
+}
+
+// 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) {
+  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;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+string varint(uint64_t x) {
+  char buf[VARINT_MAX_LEN];
+  size_t len = vencode64(x, buf);
+  return string(buf, len);
+}
+
+// TODO: proper byte-swapping for big-endian machines.
+string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
+string fixed64(void *data) { return string(static_cast<char*>(data), 8); }
+
+string delim(const string& buf) { return cat(varint(buf.size()), buf); }
+string uint32(uint32_t u32) { return fixed32(&u32); }
+string uint64(uint64_t u64) { return fixed64(&u64); }
+string flt(float f) { return fixed32(&f); }
+string dbl(double d) { return fixed64(&d); }
+string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); }
+string zz64(int64_t x) { return varint(WireFormatLite::ZigZagEncode64(x)); }
+
+string tag(uint32_t fieldnum, char wire_type) {
+  return varint((fieldnum << 3) | wire_type);
+}
+
+string submsg(uint32_t fn, const string& buf) {
+  return cat( tag(fn, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim(buf) );
+}
+
+#define UNKNOWN_FIELD 666
+
+uint32_t GetFieldNumberForType(FieldDescriptor::Type type, bool repeated) {
+  const Descriptor* d = TestAllTypes().GetDescriptor();
+  for (int i = 0; i < d->field_count(); i++) {
+    const FieldDescriptor* f = d->field(i);
+    if (f->type() == type && f->is_repeated() == repeated) {
+      return f->number();
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Couldn't find field with type " << (int)type;
+  return 0;
+}
+
+string UpperCase(string str) {
+  for (int i = 0; i < str.size(); i++) {
+    str[i] = toupper(str[i]);
+  }
+  return str;
+}
+
+}  // anonymous namespace
+
+namespace google {
+namespace protobuf {
+
+void ConformanceTestSuite::ReportSuccess(const string& test_name) {
+  if (expected_to_fail_.erase(test_name) != 0) {
+    StringAppendF(&output_,
+                  "ERROR: test %s is in the failure list, but test succeeded.  "
+                  "Remove it from the failure list.\n",
+                  test_name.c_str());
+    unexpected_succeeding_tests_.insert(test_name);
+  }
+  successes_++;
+}
+
+void ConformanceTestSuite::ReportFailure(const string& test_name,
+                                         const ConformanceRequest& request,
+                                         const ConformanceResponse& response,
+                                         const char* fmt, ...) {
+  if (expected_to_fail_.erase(test_name) == 1) {
+    expected_failures_++;
+    if (!verbose_)
+      return;
+  } else {
+    StringAppendF(&output_, "ERROR, test=%s: ", test_name.c_str());
+    unexpected_failing_tests_.insert(test_name);
+  }
+  va_list args;
+  va_start(args, fmt);
+  StringAppendV(&output_, fmt, args);
+  va_end(args);
+  StringAppendF(&output_, " request=%s, response=%s\n",
+                request.ShortDebugString().c_str(),
+                response.ShortDebugString().c_str());
+}
+
+void ConformanceTestSuite::ReportSkip(const string& test_name,
+                                      const ConformanceRequest& request,
+                                      const ConformanceResponse& response) {
+  if (verbose_) {
+    StringAppendF(&output_, "SKIPPED, test=%s request=%s, response=%s\n",
+                  test_name.c_str(), request.ShortDebugString().c_str(),
+                  response.ShortDebugString().c_str());
+  }
+  skipped_.insert(test_name);
+}
+
+void ConformanceTestSuite::RunTest(const string& test_name,
+                                   const ConformanceRequest& request,
+                                   ConformanceResponse* response) {
+  if (test_names_.insert(test_name).second == false) {
+    GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name;
+  }
+
+  string serialized_request;
+  string serialized_response;
+  request.SerializeToString(&serialized_request);
+
+  runner_->RunTest(test_name, serialized_request, &serialized_response);
+
+  if (!response->ParseFromString(serialized_response)) {
+    response->Clear();
+    response->set_runtime_error("response proto could not be parsed.");
+  }
+
+  if (verbose_) {
+    StringAppendF(&output_, "conformance test: name=%s, request=%s, response=%s\n",
+                  test_name.c_str(),
+                  request.ShortDebugString().c_str(),
+                  response->ShortDebugString().c_str());
+  }
+}
+
+void ConformanceTestSuite::RunValidInputTest(
+    const string& test_name, const string& input, WireFormat input_format,
+    const string& equivalent_text_format, WireFormat requested_output) {
+  TestAllTypes reference_message;
+  GOOGLE_CHECK(
+      TextFormat::ParseFromString(equivalent_text_format, &reference_message))
+          << "Failed to parse data for test case: " << test_name
+          << ", data: " << equivalent_text_format;
+
+  ConformanceRequest request;
+  ConformanceResponse response;
+
+  switch (input_format) {
+    case conformance::PROTOBUF:
+      request.set_protobuf_payload(input);
+      break;
+
+    case conformance::JSON:
+      request.set_json_payload(input);
+      break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unspecified input format";
+  }
+
+  request.set_requested_output_format(requested_output);
+
+  RunTest(test_name, request, &response);
+
+  TestAllTypes test_message;
+
+  switch (response.result_case()) {
+    case ConformanceResponse::kParseError:
+    case ConformanceResponse::kRuntimeError:
+    case ConformanceResponse::kSerializeError:
+      ReportFailure(test_name, request, response,
+                    "Failed to parse JSON input or produce JSON output.");
+      return;
+
+    case ConformanceResponse::kSkipped:
+      ReportSkip(test_name, request, response);
+      return;
+
+    case ConformanceResponse::kJsonPayload: {
+      if (requested_output != conformance::JSON) {
+        ReportFailure(
+            test_name, request, response,
+            "Test was asked for protobuf output but provided JSON instead.");
+        return;
+      }
+      string binary_protobuf;
+      Status status =
+          JsonToBinaryString(type_resolver_.get(), type_url_,
+                             response.json_payload(), &binary_protobuf);
+      if (!status.ok()) {
+        ReportFailure(test_name, request, response,
+                      "JSON output we received from test was unparseable.");
+        return;
+      }
+
+      if (!test_message.ParseFromString(binary_protobuf)) {
+        ReportFailure(test_name, request, response,
+                      "INTERNAL ERROR: internal JSON->protobuf transcode "
+                      "yielded unparseable proto.");
+        return;
+      }
+
+      break;
+    }
+
+    case ConformanceResponse::kProtobufPayload: {
+      if (requested_output != conformance::PROTOBUF) {
+        ReportFailure(
+            test_name, request, response,
+            "Test was asked for JSON output but provided protobuf instead.");
+        return;
+      }
+
+      if (!test_message.ParseFromString(response.protobuf_payload())) {
+        ReportFailure(test_name, request, response,
+                      "Protobuf output we received from test was unparseable.");
+        return;
+      }
+
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << test_name << ": unknown payload type: "
+                        << response.result_case();
+  }
+
+  MessageDifferencer differencer;
+  DefaultFieldComparator field_comparator;
+  field_comparator.set_treat_nan_as_equal(true);
+  differencer.set_field_comparator(&field_comparator);
+  string differences;
+  differencer.ReportDifferencesToString(&differences);
+
+  if (differencer.Compare(reference_message, test_message)) {
+    ReportSuccess(test_name);
+  } else {
+    ReportFailure(test_name, request, response,
+                  "Output was not equivalent to reference message: %s.",
+                  differences.c_str());
+  }
+}
+
+// Expect that this precise protobuf will cause a parse error.
+void ConformanceTestSuite::ExpectParseFailureForProto(
+    const string& proto, const string& test_name) {
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_protobuf_payload(proto);
+  string effective_test_name = "ProtobufInput." + test_name;
+
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  request.set_requested_output_format(conformance::PROTOBUF);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+// Expect that this protobuf will cause a parse error, even if it is followed
+// by valid protobuf data.  We can try running this twice: once with this
+// data verbatim and once with this data followed by some valid data.
+//
+// TODO(haberman): implement the second of these.
+void ConformanceTestSuite::ExpectHardParseFailureForProto(
+    const string& proto, const string& test_name) {
+  return ExpectParseFailureForProto(proto, test_name);
+}
+
+void ConformanceTestSuite::RunValidJsonTest(
+    const string& test_name, const string& input_json,
+    const string& equivalent_text_format) {
+  RunValidInputTest("JsonInput." + test_name + ".ProtobufOutput", input_json,
+                    conformance::JSON, equivalent_text_format,
+                    conformance::PROTOBUF);
+  RunValidInputTest("JsonInput." + test_name + ".JsonOutput", input_json,
+                    conformance::JSON, equivalent_text_format,
+                    conformance::JSON);
+}
+
+void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
+    const string& test_name, const TestAllTypes& input,
+    const string& equivalent_text_format) {
+  RunValidInputTest("ProtobufInput." + test_name + ".JsonOutput",
+                    input.SerializeAsString(), conformance::PROTOBUF,
+                    equivalent_text_format, conformance::JSON);
+}
+
+// According to proto3 JSON specification, JSON serializers follow more strict
+// rules than parsers (e.g., a serializer must serialize int32 values as JSON
+// numbers while the parser is allowed to accept them as JSON strings). This
+// method allows strict checking on a proto3 JSON serializer by inspecting
+// the JSON output directly.
+void ConformanceTestSuite::RunValidJsonTestWithValidator(
+    const string& test_name, const string& input_json,
+    const Validator& validator) {
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_json_payload(input_json);
+  request.set_requested_output_format(conformance::JSON);
+
+  string effective_test_name = "JsonInput." + test_name + ".Validator";
+
+  RunTest(effective_test_name, request, &response);
+
+  if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+    return;
+  }
+
+  if (response.result_case() != ConformanceResponse::kJsonPayload) {
+    ReportFailure(effective_test_name, request, response,
+                  "Expected JSON payload but got type %d.",
+                  response.result_case());
+    return;
+  }
+  Json::Reader reader;
+  Json::Value value;
+  if (!reader.parse(response.json_payload(), value)) {
+    ReportFailure(effective_test_name, request, response,
+                  "JSON payload cannot be parsed as valid JSON: %s",
+                  reader.getFormattedErrorMessages().c_str());
+    return;
+  }
+  if (!validator(value)) {
+    ReportFailure(effective_test_name, request, response,
+                  "JSON payload validation failed.");
+    return;
+  }
+  ReportSuccess(effective_test_name);
+}
+
+void ConformanceTestSuite::ExpectParseFailureForJson(
+    const string& test_name, const string& input_json) {
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_json_payload(input_json);
+  string effective_test_name = "JsonInput." + test_name;
+
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  request.set_requested_output_format(conformance::JSON);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+void ConformanceTestSuite::ExpectSerializeFailureForJson(
+    const string& test_name, const string& text_format) {
+  TestAllTypes payload_message;
+  GOOGLE_CHECK(
+      TextFormat::ParseFromString(text_format, &payload_message))
+          << "Failed to parse: " << text_format;
+
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_protobuf_payload(payload_message.SerializeAsString());
+  string effective_test_name = test_name + ".JsonOutput";
+  request.set_requested_output_format(conformance::JSON);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kSerializeError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, request, response,
+                  "Should have failed to serialize, but didn't.");
+  }
+}
+
+void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
+  // Incomplete values for each wire type.
+  static const string incompletes[6] = {
+    string("\x80"),     // VARINT
+    string("abcdefg"),  // 64BIT
+    string("\x80"),     // DELIMITED (partial length)
+    string(),           // START_GROUP (no value required)
+    string(),           // END_GROUP (no value required)
+    string("abc")       // 32BIT
+  };
+
+  uint32_t fieldnum = GetFieldNumberForType(type, false);
+  uint32_t rep_fieldnum = GetFieldNumberForType(type, true);
+  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(type));
+  const string& incomplete = incompletes[wire_type];
+  const string type_name =
+      UpperCase(string(".") + FieldDescriptor::TypeName(type));
+
+  ExpectParseFailureForProto(
+      tag(fieldnum, wire_type),
+      "PrematureEofBeforeKnownNonRepeatedValue" + type_name);
+
+  ExpectParseFailureForProto(
+      tag(rep_fieldnum, wire_type),
+      "PrematureEofBeforeKnownRepeatedValue" + type_name);
+
+  ExpectParseFailureForProto(
+      tag(UNKNOWN_FIELD, wire_type),
+      "PrematureEofBeforeUnknownValue" + type_name);
+
+  ExpectParseFailureForProto(
+      cat( tag(fieldnum, wire_type), incomplete ),
+      "PrematureEofInsideKnownNonRepeatedValue" + type_name);
+
+  ExpectParseFailureForProto(
+      cat( tag(rep_fieldnum, wire_type), incomplete ),
+      "PrematureEofInsideKnownRepeatedValue" + type_name);
+
+  ExpectParseFailureForProto(
+      cat( tag(UNKNOWN_FIELD, wire_type), incomplete ),
+      "PrematureEofInsideUnknownValue" + type_name);
+
+  if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    ExpectParseFailureForProto(
+        cat( tag(fieldnum, wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name);
+
+    ExpectParseFailureForProto(
+        cat( tag(rep_fieldnum, wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name);
+
+    // EOF in the middle of delimited data for unknown value.
+    ExpectParseFailureForProto(
+        cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForUnknownValue" + type_name);
+
+    if (type == FieldDescriptor::TYPE_MESSAGE) {
+      // Submessage ends in the middle of a value.
+      string incomplete_submsg =
+          cat( tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT),
+                incompletes[WireFormatLite::WIRETYPE_VARINT] );
+      ExpectHardParseFailureForProto(
+          cat( tag(fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+               varint(incomplete_submsg.size()),
+               incomplete_submsg ),
+          "PrematureEofInSubmessageValue" + type_name);
+    }
+  } else if (type != FieldDescriptor::TYPE_GROUP) {
+    // Non-delimited, non-group: eligible for packing.
+
+    // Packed region ends in the middle of a value.
+    ExpectHardParseFailureForProto(
+        cat( tag(rep_fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+             varint(incomplete.size()),
+             incomplete ),
+        "PrematureEofInPackedFieldValue" + type_name);
+
+    // EOF in the middle of packed region.
+    ExpectParseFailureForProto(
+        cat( tag(rep_fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+             varint(1) ),
+        "PrematureEofInPackedField" + type_name);
+  }
+}
+
+void ConformanceTestSuite::SetFailureList(const vector<string>& failure_list) {
+  expected_to_fail_.clear();
+  std::copy(failure_list.begin(), failure_list.end(),
+            std::inserter(expected_to_fail_, expected_to_fail_.end()));
+}
+
+bool ConformanceTestSuite::CheckSetEmpty(const set<string>& set_to_check,
+                                         const char* msg) {
+  if (set_to_check.empty()) {
+    return true;
+  } else {
+    StringAppendF(&output_, "\n");
+    StringAppendF(&output_, "%s:\n", msg);
+    for (set<string>::const_iterator iter = set_to_check.begin();
+         iter != set_to_check.end(); ++iter) {
+      StringAppendF(&output_, "  %s\n", iter->c_str());
+    }
+    StringAppendF(&output_, "\n");
+    return false;
+  }
+}
+
+bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
+                                    std::string* output) {
+  runner_ = runner;
+  successes_ = 0;
+  expected_failures_ = 0;
+  skipped_.clear();
+  test_names_.clear();
+  unexpected_failing_tests_.clear();
+  unexpected_succeeding_tests_.clear();
+  type_resolver_.reset(NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool()));
+  type_url_ = GetTypeUrl(TestAllTypes::descriptor());
+
+  output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
+
+  for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
+    if (i == FieldDescriptor::TYPE_GROUP) continue;
+    TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
+  }
+
+  RunValidJsonTest("HelloWorld", "{\"optionalString\":\"Hello, World!\"}",
+                   "optional_string: 'Hello, World!'");
+
+  // Test field name conventions.
+  RunValidJsonTest(
+      "FieldNameInSnakeCase",
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+      )");
+  RunValidJsonTest(
+      "FieldNameWithNumbers",
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      R"(
+        field0name5: 5
+        field_0_name6: 6
+      )");
+  RunValidJsonTest(
+      "FieldNameWithMixedCases",
+      R"({
+        "fieldName7": 7,
+        "fieldName8": 8,
+        "fieldName9": 9,
+        "fieldName10": 10,
+        "fIELDNAME11": 11,
+        "fIELDName12": 12
+      })",
+      R"(
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+      )");
+  // Using the original proto field name in JSON is also allowed.
+  RunValidJsonTest(
+      "OriginalProtoFieldName",
+      R"({
+        "fieldname1": 1,
+        "field_name2": 2,
+        "_field_name3": 3,
+        "field0name5": 5,
+        "field_0_name6": 6,
+        "fieldName7": 7,
+        "FieldName8": 8,
+        "field_Name9": 9,
+        "Field_Name10": 10,
+        "FIELD_NAME11": 11,
+        "FIELD_name12": 12
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+        field0name5: 5
+        field_0_name6: 6
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+      )");
+  // Field names can be escaped.
+  RunValidJsonTest(
+      "FieldNameEscaped",
+      R"({"fieldn\u0061me1": 1})",
+      "fieldname1: 1");
+  // Field names must be quoted (or it's not valid JSON).
+  ExpectParseFailureForJson(
+      "FieldNameNotQuoted",
+      "{fieldname1: 1}");
+  // Trailing comma is not allowed (not valid JSON).
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObject",
+      R"({"fieldname1":1,})");
+  // JSON doesn't support comments.
+  ExpectParseFailureForJson(
+      "JsonWithComments",
+      R"({
+        // This is a comment.
+        "fieldname1": 1
+      })");
+  // Duplicated field names are not allowed.
+  ExpectParseFailureForJson(
+      "FieldNameDuplicate",
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing1",
+      R"({
+        "optional_nested_message": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing2",
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optional_nested_message": {}
+      })");
+  // Serializers should use lowerCamelCase by default.
+  RunValidJsonTestWithValidator(
+      "FieldNameInLowerCamelCase",
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldname1") &&
+            value.isMember("fieldName2") &&
+            value.isMember("FieldName3");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithNumbers",
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("field0name5") &&
+            value.isMember("field0Name6");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithMixedCases",
+      R"({
+        "fieldName7": 7,
+        "fieldName8": 8,
+        "fieldName9": 9,
+        "fieldName10": 10,
+        "fIELDNAME11": 11,
+        "fIELDName12": 12
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldName7") &&
+            value.isMember("fieldName8") &&
+            value.isMember("fieldName9") &&
+            value.isMember("fieldName10") &&
+            value.isMember("fIELDNAME11") &&
+            value.isMember("fIELDName12");
+      });
+
+  // Integer fields.
+  RunValidJsonTest(
+      "Int32FieldMaxValue",
+      R"({"optionalInt32": 2147483647})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinValue",
+      R"({"optionalInt32": -2147483648})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxValue",
+      R"({"optionalUint32": 4294967295})",
+      "optional_uint32: 4294967295");
+  RunValidJsonTest(
+      "Int64FieldMaxValue",
+      R"({"optionalInt64": "9223372036854775807"})",
+      "optional_int64: 9223372036854775807");
+  RunValidJsonTest(
+      "Int64FieldMinValue",
+      R"({"optionalInt64": "-9223372036854775808"})",
+      "optional_int64: -9223372036854775808");
+  RunValidJsonTest(
+      "Uint64FieldMaxValue",
+      R"({"optionalUint64": "18446744073709551615"})",
+      "optional_uint64: 18446744073709551615");
+  RunValidJsonTest(
+      "Int64FieldMaxValueNotQuoted",
+      R"({"optionalInt64": 9223372036854775807})",
+      "optional_int64: 9223372036854775807");
+  RunValidJsonTest(
+      "Int64FieldMinValueNotQuoted",
+      R"({"optionalInt64": -9223372036854775808})",
+      "optional_int64: -9223372036854775808");
+  RunValidJsonTest(
+      "Uint64FieldMaxValueNotQuoted",
+      R"({"optionalUint64": 18446744073709551615})",
+      "optional_uint64: 18446744073709551615");
+  // Values can be represented as JSON strings.
+  RunValidJsonTest(
+      "Int32FieldStringValue",
+      R"({"optionalInt32": "2147483647"})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldStringValueEscaped",
+      R"({"optionalInt32": "2\u003147483647"})",
+      "optional_int32: 2147483647");
+
+  // Parsers reject out-of-bound integer values.
+  ExpectParseFailureForJson(
+      "Int32FieldTooLarge",
+      R"({"optionalInt32": 2147483648})");
+  ExpectParseFailureForJson(
+      "Int32FieldTooSmall",
+      R"({"optionalInt32": -2147483649})");
+  ExpectParseFailureForJson(
+      "Uint32FieldTooLarge",
+      R"({"optionalUint32": 4294967296})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooLarge",
+      R"({"optionalInt64": "9223372036854775808"})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooSmall",
+      R"({"optionalInt64": "-9223372036854775809"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldTooLarge",
+      R"({"optionalUint64": "18446744073709551616"})");
+  // Parser reject non-integer numeric values as well.
+  ExpectParseFailureForJson(
+      "Int32FieldNotInteger",
+      R"({"optionalInt32": 0.5})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotInteger",
+      R"({"optionalUint32": 0.5})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotInteger",
+      R"({"optionalInt64": "0.5"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotInteger",
+      R"({"optionalUint64": "0.5"})");
+
+  // Integers but represented as float values are accepted.
+  RunValidJsonTest(
+      "Int32FieldFloatTrailingZero",
+      R"({"optionalInt32": 100000.000})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldExponentialFormat",
+      R"({"optionalInt32": 1e5})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldMaxFloatValue",
+      R"({"optionalInt32": 2.147483647e9})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinFloatValue",
+      R"({"optionalInt32": -2.147483648e9})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxFloatValue",
+      R"({"optionalUint32": 4.294967295e9})",
+      "optional_uint32: 4294967295");
+
+  // Parser reject non-numeric values.
+  ExpectParseFailureForJson(
+      "Int32FieldNotNumber",
+      R"({"optionalInt32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotNumber",
+      R"({"optionalUint32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotNumber",
+      R"({"optionalInt64": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotNumber",
+      R"({"optionalUint64": "3x3"})");
+  // JSON does not allow "+" on numric values.
+  ExpectParseFailureForJson(
+      "Int32FieldPlusSign",
+      R"({"optionalInt32": +1})");
+  // JSON doesn't allow leading 0s.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingZero",
+      R"({"optionalInt32": 01})");
+  ExpectParseFailureForJson(
+      "Int32FieldNegativeWithLeadingZero",
+      R"({"optionalInt32": -01})");
+  // String values must follow the same syntax rule. Specifically leading
+  // or traling spaces are not allowed.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingSpace",
+      R"({"optionalInt32": " 1"})");
+  ExpectParseFailureForJson(
+      "Int32FieldTrailingSpace",
+      R"({"optionalInt32": "1 "})");
+
+  // 64-bit values are serialized as strings.
+  RunValidJsonTestWithValidator(
+      "Int64FieldBeString",
+      R"({"optionalInt64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalInt64"].type() == Json::stringValue &&
+            value["optionalInt64"].asString() == "1";
+      });
+  RunValidJsonTestWithValidator(
+      "Uint64FieldBeString",
+      R"({"optionalUint64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalUint64"].type() == Json::stringValue &&
+            value["optionalUint64"].asString() == "1";
+      });
+
+  // Bool fields.
+  RunValidJsonTest(
+      "BoolFieldTrue",
+      R"({"optionalBool":true})",
+      "optional_bool: true");
+  RunValidJsonTest(
+      "BoolFieldFalse",
+      R"({"optionalBool":false})",
+      "optional_bool: false");
+
+  // Other forms are not allowed.
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerZero",
+      R"({"optionalBool":0})");
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerOne",
+      R"({"optionalBool":1})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseTrue",
+      R"({"optionalBool":True})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseFalse",
+      R"({"optionalBool":False})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalTrue",
+      R"({"optionalBool":TRUE})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalFalse",
+      R"({"optionalBool":FALSE})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedTrue",
+      R"({"optionalBool":"true"})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedFalse",
+      R"({"optionalBool":"false"})");
+
+  // Float fields.
+  RunValidJsonTest(
+      "FloatFieldMinPositiveValue",
+      R"({"optionalFloat": 1.175494e-38})",
+      "optional_float: 1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxNegativeValue",
+      R"({"optionalFloat": -1.175494e-38})",
+      "optional_float: -1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxPositiveValue",
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  RunValidJsonTest(
+      "FloatFieldMinNegativeValue",
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "FloatFieldQuotedValue",
+      R"({"optionalFloat": "1"})",
+      "optional_float: 1");
+  // Special values.
+  RunValidJsonTest(
+      "FloatFieldNan",
+      R"({"optionalFloat": "NaN"})",
+      "optional_float: nan");
+  RunValidJsonTest(
+      "FloatFieldInfinity",
+      R"({"optionalFloat": "Infinity"})",
+      "optional_float: inf");
+  RunValidJsonTest(
+      "FloatFieldNegativeInfinity",
+      R"({"optionalFloat": "-Infinity"})",
+      "optional_float: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypes message;
+    // IEEE floating-point standard 32-bit quiet NaN:
+    //   0111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0x7FA12345));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeQuietNan", message,
+        "optional_float: nan");
+    // IEEE floating-point standard 64-bit signaling NaN:
+    //   1111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0xFFB54321));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeSignalingNan", message,
+        "optional_float: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "FloatFieldNanNotQuoted",
+      R"({"optionalFloat": NaN})");
+  ExpectParseFailureForJson(
+      "FloatFieldInfinityNotQuoted",
+      R"({"optionalFloat": Infinity})");
+  ExpectParseFailureForJson(
+      "FloatFieldNegativeInfinityNotQuoted",
+      R"({"optionalFloat": -Infinity})");
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "FloatFieldTooSmall",
+      R"({"optionalFloat": -3.502823e+38})");
+  ExpectParseFailureForJson(
+      "FloatFieldTooLarge",
+      R"({"optionalFloat": 3.502823e+38})");
+
+  // Double fields.
+  RunValidJsonTest(
+      "DoubleFieldMinPositiveValue",
+      R"({"optionalDouble": 2.22507e-308})",
+      "optional_double: 2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxNegativeValue",
+      R"({"optionalDouble": -2.22507e-308})",
+      "optional_double: -2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxPositiveValue",
+      R"({"optionalDouble": 1.79769e+308})",
+      "optional_double: 1.79769e+308");
+  RunValidJsonTest(
+      "DoubleFieldMinNegativeValue",
+      R"({"optionalDouble": -1.79769e+308})",
+      "optional_double: -1.79769e+308");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "DoubleFieldQuotedValue",
+      R"({"optionalDouble": "1"})",
+      "optional_double: 1");
+  // Speical values.
+  RunValidJsonTest(
+      "DoubleFieldNan",
+      R"({"optionalDouble": "NaN"})",
+      "optional_double: nan");
+  RunValidJsonTest(
+      "DoubleFieldInfinity",
+      R"({"optionalDouble": "Infinity"})",
+      "optional_double: inf");
+  RunValidJsonTest(
+      "DoubleFieldNegativeInfinity",
+      R"({"optionalDouble": "-Infinity"})",
+      "optional_double: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypes message;
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0x7FFA123456789ABCLL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeQuietNan", message,
+        "optional_double: nan");
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0xFFFBCBA987654321LL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeSignalingNan", message,
+        "optional_double: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "DoubleFieldNanNotQuoted",
+      R"({"optionalDouble": NaN})");
+  ExpectParseFailureForJson(
+      "DoubleFieldInfinityNotQuoted",
+      R"({"optionalDouble": Infinity})");
+  ExpectParseFailureForJson(
+      "DoubleFieldNegativeInfinityNotQuoted",
+      R"({"optionalDouble": -Infinity})");
+
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "DoubleFieldTooSmall",
+      R"({"optionalDouble": -1.89769e+308})");
+  ExpectParseFailureForJson(
+      "DoubleFieldTooLarge",
+      R"({"optionalDouble": +1.89769e+308})");
+
+  // Enum fields.
+  RunValidJsonTest(
+      "EnumField",
+      R"({"optionalNestedEnum": "FOO"})",
+      "optional_nested_enum: FOO");
+  // Enum values must be represented as strings.
+  ExpectParseFailureForJson(
+      "EnumFieldNotQuoted",
+      R"({"optionalNestedEnum": FOO})");
+  // Numeric values are allowed.
+  RunValidJsonTest(
+      "EnumFieldNumericValueZero",
+      R"({"optionalNestedEnum": 0})",
+      "optional_nested_enum: FOO");
+  RunValidJsonTest(
+      "EnumFieldNumericValueNonZero",
+      R"({"optionalNestedEnum": 1})",
+      "optional_nested_enum: BAR");
+  // Unknown enum values are represented as numeric values.
+  RunValidJsonTestWithValidator(
+      "EnumFieldUnknownValue",
+      R"({"optionalNestedEnum": 123})",
+      [](const Json::Value& value) {
+        return value["optionalNestedEnum"].type() == Json::intValue &&
+            value["optionalNestedEnum"].asInt() == 123;
+      });
+
+  // String fields.
+  RunValidJsonTest(
+      "StringField",
+      R"({"optionalString": "Hello world!"})",
+      "optional_string: \"Hello world!\"");
+  RunValidJsonTest(
+      "StringFieldUnicode",
+      // Google in Chinese.
+      R"({"optionalString": "谷歌"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldEscape",
+      R"({"optionalString": "\"\\\/\b\f\n\r\t"})",
+      R"(optional_string: "\"\\/\b\f\n\r\t")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscape",
+      R"({"optionalString": "\u8C37\u6B4C"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscapeWithLowercaseHexLetters",
+      R"({"optionalString": "\u8c37\u6b4c"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldSurrogatePair",
+      // The character is an emoji: grinning face with smiling eyes. 😁
+      R"({"optionalString": "\uD83D\uDE01"})",
+      R"(optional_string: "\xF0\x9F\x98\x81")");
+
+  // Unicode escapes must start with "\u" (lowercase u).
+  ExpectParseFailureForJson(
+      "StringFieldUppercaseEscapeLetter",
+      R"({"optionalString": "\U8C37\U6b4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldInvalidEscape",
+      R"({"optionalString": "\uXXXX\u6B4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnterminatedEscape",
+      R"({"optionalString": "\u8C3"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedHighSurrogate",
+      R"({"optionalString": "\uD800"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedLowSurrogate",
+      R"({"optionalString": "\uDC00"})");
+  ExpectParseFailureForJson(
+      "StringFieldSurrogateInWrongOrder",
+      R"({"optionalString": "\uDE01\uD83D"})");
+  ExpectParseFailureForJson(
+      "StringFieldNotAString",
+      R"({"optionalString": 12345})");
+
+  // Bytes fields.
+  RunValidJsonTest(
+      "BytesField",
+      R"({"optionalBytes": "AQI="})",
+      R"(optional_bytes: "\x01\x02")");
+  ExpectParseFailureForJson(
+      "BytesFieldNoPadding",
+      R"({"optionalBytes": "AQI"})");
+  ExpectParseFailureForJson(
+      "BytesFieldInvalidBase64Characters",
+      R"({"optionalBytes": "-_=="})");
+
+  // Message fields.
+  RunValidJsonTest(
+      "MessageField",
+      R"({"optionalNestedMessage": {"a": 1234}})",
+      "optional_nested_message: {a: 1234}");
+
+  // Oneof fields.
+  ExpectParseFailureForJson(
+      "OneofFieldDuplicate",
+      R"({"oneofUint32": 1, "oneofString": "test"})");
+
+  // Repeated fields.
+  RunValidJsonTest(
+      "PrimitiveRepeatedField",
+      R"({"repeatedInt32": [1, 2, 3, 4]})",
+      "repeated_int32: [1, 2, 3, 4]");
+  RunValidJsonTest(
+      "EnumRepeatedField",
+      R"({"repeatedNestedEnum": ["FOO", "BAR", "BAZ"]})",
+      "repeated_nested_enum: [FOO, BAR, BAZ]");
+  RunValidJsonTest(
+      "StringRepeatedField",
+      R"({"repeatedString": ["Hello", "world"]})",
+      R"(repeated_string: ["Hello", "world"])");
+  RunValidJsonTest(
+      "BytesRepeatedField",
+      R"({"repeatedBytes": ["AAEC", "AQI="]})",
+      R"(repeated_bytes: ["\x00\x01\x02", "\x01\x02"])");
+  RunValidJsonTest(
+      "MessageRepeatedField",
+      R"({"repeatedNestedMessage": [{"a": 1234}, {"a": 5678}]})",
+      "repeated_nested_message: {a: 1234}"
+      "repeated_nested_message: {a: 5678}");
+
+  // Repeated field elements are of incorrect type.
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotBool",
+      R"({"repeatedInt32": [1, false, 3, 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotString",
+      R"({"repeatedInt32": [1, 2, "name", 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotMessage",
+      R"({"repeatedInt32": [1, 2, 3, {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotInt",
+      R"({"repeatedString": ["1", 2, "3", "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotBool",
+      R"({"repeatedString": ["1", "2", false, "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotMessage",
+      R"({"repeatedString": ["1", 2, "3", {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotInt",
+      R"({"repeatedNestedMessage": [{"a": 1}, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotBool",
+      R"({"repeatedNestedMessage": [{"a": 1}, false]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotString",
+      R"({"repeatedNestedMessage": [{"a": 1}, "2"]})");
+  // Trailing comma in the repeated field is not allowed.
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingComma",
+      R"({"repeatedInt32": [1, 2, 3, 4,]})");
+
+  // Map fields.
+  RunValidJsonTest(
+      "Int32MapField",
+      R"({"mapInt32Int32": {"1": 2, "3": 4}})",
+      "map_int32_int32: {key: 1 value: 2}"
+      "map_int32_int32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int32MapFieldKeyNotQuoted",
+      R"({"mapInt32Int32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint32MapField",
+      R"({"mapUint32Uint32": {"1": 2, "3": 4}})",
+      "map_uint32_uint32: {key: 1 value: 2}"
+      "map_uint32_uint32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint32MapFieldKeyNotQuoted",
+      R"({"mapUint32Uint32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Int64MapField",
+      R"({"mapInt64Int64": {"1": 2, "3": 4}})",
+      "map_int64_int64: {key: 1 value: 2}"
+      "map_int64_int64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int64MapFieldKeyNotQuoted",
+      R"({"mapInt64Int64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint64MapField",
+      R"({"mapUint64Uint64": {"1": 2, "3": 4}})",
+      "map_uint64_uint64: {key: 1 value: 2}"
+      "map_uint64_uint64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint64MapFieldKeyNotQuoted",
+      R"({"mapUint64Uint64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "BoolMapField",
+      R"({"mapBoolBool": {"true": true, "false": false}})",
+      "map_bool_bool: {key: true value: true}"
+      "map_bool_bool: {key: false value: false}");
+  ExpectParseFailureForJson(
+      "BoolMapFieldKeyNotQuoted",
+      R"({"mapBoolBool": {true: true, false: false}})");
+  RunValidJsonTest(
+      "MessageMapField",
+      R"({
+        "mapStringNestedMessage": {
+          "hello": {"a": 1234},
+          "world": {"a": 5678}
+        }
+      })",
+      R"(
+        map_string_nested_message: {
+          key: "hello"
+          value: {a: 1234}
+        }
+        map_string_nested_message: {
+          key: "world"
+          value: {a: 5678}
+        }
+      )");
+  // Since Map keys are represented as JSON strings, escaping should be allowed.
+  RunValidJsonTest(
+      "Int32MapEscapedKey",
+      R"({"mapInt32Int32": {"\u0031": 2}})",
+      "map_int32_int32: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "Int64MapEscapedKey",
+      R"({"mapInt64Int64": {"\u0031": 2}})",
+      "map_int64_int64: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "BoolMapEscapedKey",
+      R"({"mapBoolBool": {"tr\u0075e": true}})",
+      "map_bool_bool: {key: true value: true}");
+
+  // "null" is accepted for all fields types.
+  RunValidJsonTest(
+      "AllFieldAcceptNull",
+      R"({
+        "optionalInt32": null,
+        "optionalInt64": null,
+        "optionalUint32": null,
+        "optionalUint64": null,
+        "optionalBool": null,
+        "optionalString": null,
+        "optionalBytes": null,
+        "optionalNestedEnum": null,
+        "optionalNestedMessage": null,
+        "repeatedInt32": null,
+        "repeatedInt64": null,
+        "repeatedUint32": null,
+        "repeatedUint64": null,
+        "repeatedBool": null,
+        "repeatedString": null,
+        "repeatedBytes": null,
+        "repeatedNestedEnum": null,
+        "repeatedNestedMessage": null,
+        "mapInt32Int32": null,
+        "mapBoolBool": null,
+        "mapStringNestedMessage": null
+      })",
+      "");
+
+  // Repeated field elements cannot be null.
+  ExpectParseFailureForJson(
+      "RepeatedFieldPrimitiveElementIsNull",
+      R"({"repeatedInt32": [1, null, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldMessageElementIsNull",
+      R"({"repeatedNestedMessage": [{"a":1}, null, {"a":2}]})");
+  // Map field keys cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldKeyIsNull",
+      R"({"mapInt32Int32": {null: 1}})");
+  // Map field values cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldValueIsNull",
+      R"({"mapInt32Int32": {"0": null}})");
+
+  // Wrapper types.
+  RunValidJsonTest(
+      "OptionalBoolWrapper",
+      R"({"optionalBoolWrapper": false})",
+      "optional_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "OptionalInt32Wrapper",
+      R"({"optionalInt32Wrapper": 0})",
+      "optional_int32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint32Wrapper",
+      R"({"optionalUint32Wrapper": 0})",
+      "optional_uint32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalInt64Wrapper",
+      R"({"optionalInt64Wrapper": 0})",
+      "optional_int64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint64Wrapper",
+      R"({"optionalUint64Wrapper": 0})",
+      "optional_uint64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalFloatWrapper",
+      R"({"optionalFloatWrapper": 0})",
+      "optional_float_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalDoubleWrapper",
+      R"({"optionalDoubleWrapper": 0})",
+      "optional_double_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalStringWrapper",
+      R"({"optionalStringWrapper": ""})",
+      R"(optional_string_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalBytesWrapper",
+      R"({"optionalBytesWrapper": ""})",
+      R"(optional_bytes_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalWrapperTypesWithNonDefaultValue",
+      R"({
+        "optionalBoolWrapper": true,
+        "optionalInt32Wrapper": 1,
+        "optionalUint32Wrapper": 1,
+        "optionalInt64Wrapper": "1",
+        "optionalUint64Wrapper": "1",
+        "optionalFloatWrapper": 1,
+        "optionalDoubleWrapper": 1,
+        "optionalStringWrapper": "1",
+        "optionalBytesWrapper": "AQI="
+      })",
+      R"(
+        optional_bool_wrapper: {value: true}
+        optional_int32_wrapper: {value: 1}
+        optional_uint32_wrapper: {value: 1}
+        optional_int64_wrapper: {value: 1}
+        optional_uint64_wrapper: {value: 1}
+        optional_float_wrapper: {value: 1}
+        optional_double_wrapper: {value: 1}
+        optional_string_wrapper: {value: "1"}
+        optional_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "RepeatedBoolWrapper",
+      R"({"repeatedBoolWrapper": [true, false]})",
+      "repeated_bool_wrapper: {value: true}"
+      "repeated_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "RepeatedInt32Wrapper",
+      R"({"repeatedInt32Wrapper": [0, 1]})",
+      "repeated_int32_wrapper: {value: 0}"
+      "repeated_int32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint32Wrapper",
+      R"({"repeatedUint32Wrapper": [0, 1]})",
+      "repeated_uint32_wrapper: {value: 0}"
+      "repeated_uint32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedInt64Wrapper",
+      R"({"repeatedInt64Wrapper": [0, 1]})",
+      "repeated_int64_wrapper: {value: 0}"
+      "repeated_int64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint64Wrapper",
+      R"({"repeatedUint64Wrapper": [0, 1]})",
+      "repeated_uint64_wrapper: {value: 0}"
+      "repeated_uint64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedFloatWrapper",
+      R"({"repeatedFloatWrapper": [0, 1]})",
+      "repeated_float_wrapper: {value: 0}"
+      "repeated_float_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedDoubleWrapper",
+      R"({"repeatedDoubleWrapper": [0, 1]})",
+      "repeated_double_wrapper: {value: 0}"
+      "repeated_double_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedStringWrapper",
+      R"({"repeatedStringWrapper": ["", "AQI="]})",
+      R"(
+        repeated_string_wrapper: {value: ""}
+        repeated_string_wrapper: {value: "AQI="}
+      )");
+  RunValidJsonTest(
+      "RepeatedBytesWrapper",
+      R"({"repeatedBytesWrapper": ["", "AQI="]})",
+      R"(
+        repeated_bytes_wrapper: {value: ""}
+        repeated_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "WrapperTypesWithNullValue",
+      R"({
+        "optionalBoolWrapper": null,
+        "optionalInt32Wrapper": null,
+        "optionalUint32Wrapper": null,
+        "optionalInt64Wrapper": null,
+        "optionalUint64Wrapper": null,
+        "optionalFloatWrapper": null,
+        "optionalDoubleWrapper": null,
+        "optionalStringWrapper": null,
+        "optionalBytesWrapper": null,
+        "repeatedBoolWrapper": null,
+        "repeatedInt32Wrapper": null,
+        "repeatedUint32Wrapper": null,
+        "repeatedInt64Wrapper": null,
+        "repeatedUint64Wrapper": null,
+        "repeatedFloatWrapper": null,
+        "repeatedDoubleWrapper": null,
+        "repeatedStringWrapper": null,
+        "repeatedBytesWrapper": null
+      })",
+      "");
+
+  // Duration
+  RunValidJsonTest(
+      "DurationMinValue",
+      R"({"optionalDuration": "-315576000000.999999999s"})",
+      "optional_duration: {seconds: -315576000000 nanos: -999999999}");
+  RunValidJsonTest(
+      "DurationMaxValue",
+      R"({"optionalDuration": "315576000000.999999999s"})",
+      "optional_duration: {seconds: 315576000000 nanos: 999999999}");
+  RunValidJsonTest(
+      "DurationRepeatedValue",
+      R"({"repeatedDuration": ["1.5s", "-1.5s"]})",
+      "repeated_duration: {seconds: 1 nanos: 500000000}"
+      "repeated_duration: {seconds: -1 nanos: -500000000}");
+
+  ExpectParseFailureForJson(
+      "DurationMissingS",
+      R"({"optionalDuration": "1"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooSmall",
+      R"({"optionalDuration": "-315576000001.000000000s"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooLarge",
+      R"({"optionalDuration": "315576000001.000000000s"})");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooSmall",
+      "optional_duration: {seconds: -315576000001 nanos: 0}");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooLarge",
+      "optional_duration: {seconds: 315576000001 nanos: 0}");
+
+  RunValidJsonTestWithValidator(
+      "DurationHasZeroFractionalDigit",
+      R"({"optionalDuration": "1.000000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas3FractionalDigits",
+      R"({"optionalDuration": "1.010000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas6FractionalDigits",
+      R"({"optionalDuration": "1.000010000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas9FractionalDigits",
+      R"({"optionalDuration": "1.000000010s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000000010s";
+      });
+
+  // Timestamp
+  RunValidJsonTest(
+      "TimestampMinValue",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00Z"})",
+      "optional_timestamp: {seconds: -62135596800}");
+  RunValidJsonTest(
+      "TimestampMaxValue",
+      R"({"optionalTimestamp": "9999-12-31T23:59:59.999999999Z"})",
+      "optional_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampRepeatedValue",
+      R"({
+        "repeatedTimestamp": [
+          "0001-01-01T00:00:00Z",
+          "9999-12-31T23:59:59.999999999Z"
+        ]
+      })",
+      "repeated_timestamp: {seconds: -62135596800}"
+      "repeated_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampWithPositiveOffset",
+      R"({"optionalTimestamp": "1970-01-01T08:00:00+08:00"})",
+      "optional_timestamp: {seconds: 0}");
+  RunValidJsonTest(
+      "TimestampWithNegativeOffset",
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      "optional_timestamp: {seconds: 0}");
+
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooSmall",
+      R"({"optionalTimestamp": "0000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooLarge",
+      R"({"optionalTimestamp": "10000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingZ",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingT",
+      R"({"optionalTimestamp": "0001-01-01 00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseZ",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseT",
+      R"({"optionalTimestamp": "0001-01-01t00:00:00Z"})");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooSmall",
+      "optional_timestamp: {seconds: -62135596801}");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooLarge",
+      "optional_timestamp: {seconds: 253402300800}");
+  RunValidJsonTestWithValidator(
+      "TimestampZeroNormalized",
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHasZeroFractionalDigit",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas3FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.010000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas6FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000010000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas9FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000010Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000000010Z";
+      });
+
+  // FieldMask
+  RunValidJsonTest(
+      "FieldMask",
+      R"({"optionalFieldMask": "foo,barBaz"})",
+      R"(optional_field_mask: {paths: "foo" paths: "bar_baz"})");
+  ExpectParseFailureForJson(
+      "FieldMaskInvalidCharacter",
+      R"({"optionalFieldMask": "foo,bar_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskPathsDontRoundTrip",
+      R"(optional_field_mask: {paths: "fooBar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskNumbersDontRoundTrip",
+      R"(optional_field_mask: {paths: "foo_3_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskTooManyUnderscore",
+      R"(optional_field_mask: {paths: "foo__bar"})");
+
+  // Struct
+  RunValidJsonTest(
+      "Struct",
+      R"({
+        "optionalStruct": {
+          "nullValue": null,
+          "intValue": 1234,
+          "boolValue": true,
+          "doubleValue": 1234.5678,
+          "stringValue": "Hello world!",
+          "listValue": [1234, "5678"],
+          "objectValue": {
+            "value": 0
+          }
+        }
+      })",
+      R"(
+        optional_struct: {
+          fields: {
+            key: "nullValue"
+            value: {null_value: NULL_VALUE}
+          }
+          fields: {
+            key: "intValue"
+            value: {number_value: 1234}
+          }
+          fields: {
+            key: "boolValue"
+            value: {bool_value: true}
+          }
+          fields: {
+            key: "doubleValue"
+            value: {number_value: 1234.5678}
+          }
+          fields: {
+            key: "stringValue"
+            value: {string_value: "Hello world!"}
+          }
+          fields: {
+            key: "listValue"
+            value: {
+              list_value: {
+                values: {
+                  number_value: 1234
+                }
+                values: {
+                  string_value: "5678"
+                }
+              }
+            }
+          }
+          fields: {
+            key: "objectValue"
+            value: {
+              struct_value: {
+                fields: {
+                  key: "value"
+                  value: {
+                    number_value: 0
+                  }
+                }
+              }
+            }
+          }
+        }
+      )");
+  // Value
+  RunValidJsonTest(
+      "ValueAcceptInteger",
+      R"({"optionalValue": 1})",
+      "optional_value: { number_value: 1}");
+  RunValidJsonTest(
+      "ValueAcceptFloat",
+      R"({"optionalValue": 1.5})",
+      "optional_value: { number_value: 1.5}");
+  RunValidJsonTest(
+      "ValueAcceptBool",
+      R"({"optionalValue": false})",
+      "optional_value: { bool_value: false}");
+  RunValidJsonTest(
+      "ValueAcceptNull",
+      R"({"optionalValue": null})",
+      "optional_value: { null_value: NULL_VALUE}");
+  RunValidJsonTest(
+      "ValueAcceptString",
+      R"({"optionalValue": "hello"})",
+      R"(optional_value: { string_value: "hello"})");
+  RunValidJsonTest(
+      "ValueAcceptList",
+      R"({"optionalValue": [0, "hello"]})",
+      R"(
+        optional_value: {
+          list_value: {
+            values: {
+              number_value: 0
+            }
+            values: {
+              string_value: "hello"
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "ValueAcceptObject",
+      R"({"optionalValue": {"value": 1}})",
+      R"(
+        optional_value: {
+          struct_value: {
+            fields: {
+              key: "value"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+
+  // Any
+  RunValidJsonTest(
+      "Any",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/conformance.TestAllTypes",
+          "optionalInt32": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/conformance.TestAllTypes] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyNested",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Any",
+          "value": {
+            "@type": "type.googleapis.com/conformance.TestAllTypes",
+            "optionalInt32": 12345
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Any] {
+            [type.googleapis.com/conformance.TestAllTypes] {
+              optional_int32: 12345
+            }
+          }
+        }
+      )");
+  // The special "@type" tag is not required to appear first.
+  RunValidJsonTest(
+      "AnyUnorderedTypeTag",
+      R"({
+        "optionalAny": {
+          "optionalInt32": 12345,
+          "@type": "type.googleapis.com/conformance.TestAllTypes"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/conformance.TestAllTypes] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  // Well-known types in Any.
+  RunValidJsonTest(
+      "AnyWithInt32ValueWrapper",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Int32Value",
+          "value": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Int32Value] {
+            value: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithDuration",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Duration",
+          "value": "1.5s"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Duration] {
+            seconds: 1
+            nanos: 500000000
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithTimestamp",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Timestamp",
+          "value": "1970-01-01T00:00:00Z"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Timestamp] {
+            seconds: 0
+            nanos: 0
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithFieldMask",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.FieldMask",
+          "value": "foo,barBaz"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.FieldMask] {
+            paths: ["foo", "bar_baz"]
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithStruct",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Struct",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Struct] {
+            fields: {
+              key: "foo"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForJsonObject",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            struct_value: {
+              fields: {
+                key: "foo"
+                value: {
+                  number_value: 1
+                }
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForInteger",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": 1
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            number_value: 1
+          }
+        }
+      )");
+
+  bool ok = true;
+  if (!CheckSetEmpty(expected_to_fail_,
+                     "These tests were listed in the failure list, but they "
+                     "don't exist.  Remove them from the failure list")) {
+    ok = false;
+  }
+  if (!CheckSetEmpty(unexpected_failing_tests_,
+                     "These tests failed.  If they can't be fixed right now, "
+                     "you can add them to the failure list so the overall "
+                     "suite can succeed")) {
+    ok = false;
+  }
+
+  // Sometimes the testee may be fixed before we update the failure list (e.g.,
+  // the testee is from a different component). We warn about this case but
+  // don't consider it an overall test failure.
+  CheckSetEmpty(unexpected_succeeding_tests_,
+                "These tests succeeded, even though they were listed in "
+                "the failure list.  Remove them from the failure list");
+
+  if (verbose_) {
+    CheckSetEmpty(skipped_,
+                  "These tests were skipped (probably because support for some "
+                  "features is not implemented)");
+  }
+
+  StringAppendF(&output_,
+                "CONFORMANCE SUITE %s: %d successes, %d skipped, "
+                "%d expected failures, %d unexpected failures.\n",
+                ok ? "PASSED" : "FAILED", successes_, skipped_.size(),
+                expected_failures_, unexpected_failing_tests_.size());
+  StringAppendF(&output_, "\n");
+
+  output->assign(output_);
+
+  return ok;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
new file mode 100644
index 0000000..75fc97b
--- /dev/null
+++ b/conformance/conformance_test.h
@@ -0,0 +1,178 @@
+// 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.
+
+
+// This file defines a protocol for running the conformance test suite
+// in-process.  In other words, the suite itself will run in the same process as
+// the code under test.
+//
+// For pros and cons of this approach, please see conformance.proto.
+
+#ifndef CONFORMANCE_CONFORMANCE_TEST_H
+#define CONFORMANCE_CONFORMANCE_TEST_H
+
+#include <functional>
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#include "third_party/jsoncpp/json.h"
+
+namespace conformance {
+class ConformanceRequest;
+class ConformanceResponse;
+class TestAllTypes;
+}  // namespace conformance
+
+namespace google {
+namespace protobuf {
+
+class ConformanceTestRunner {
+ public:
+  virtual ~ConformanceTestRunner() {}
+
+  // Call to run a single conformance test.
+  //
+  // "input" is a serialized conformance.ConformanceRequest.
+  // "output" should be set to a serialized conformance.ConformanceResponse.
+  //
+  // If there is any error in running the test itself, set "runtime_error" in
+  // the response.
+  virtual void RunTest(const std::string& test_name,
+                       const std::string& input,
+                       std::string* output) = 0;
+};
+
+// Class representing the test suite itself.  To run it, implement your own
+// class derived from ConformanceTestRunner and then write code like:
+//
+//    class MyConformanceTestRunner : public ConformanceTestRunner {
+//     public:
+//      virtual void RunTest(...) {
+//        // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE.
+//      }
+//    };
+//
+//    int main() {
+//      MyConformanceTestRunner runner;
+//      google::protobuf::ConformanceTestSuite suite;
+//
+//      std::string output;
+//      suite.RunSuite(&runner, &output);
+//    }
+//
+class ConformanceTestSuite {
+ public:
+  ConformanceTestSuite() : verbose_(false) {}
+
+  void SetVerbose(bool verbose) { verbose_ = verbose; }
+
+  // Sets the list of tests that are expected to fail when RunSuite() is called.
+  // RunSuite() will fail unless the set of failing tests is exactly the same
+  // as this list.
+  void SetFailureList(const std::vector<std::string>& failure_list);
+
+  // Run all the conformance tests against the given test runner.
+  // Test output will be stored in "output".
+  //
+  // Returns true if the set of failing tests was exactly the same as the
+  // failure list.  If SetFailureList() was not called, returns true if all
+  // tests passed.
+  bool RunSuite(ConformanceTestRunner* runner, std::string* output);
+
+ private:
+  void ReportSuccess(const std::string& test_name);
+  void ReportFailure(const string& test_name,
+                     const conformance::ConformanceRequest& request,
+                     const conformance::ConformanceResponse& response,
+                     const char* fmt, ...);
+  void ReportSkip(const string& test_name,
+                  const conformance::ConformanceRequest& request,
+                  const conformance::ConformanceResponse& response);
+  void RunTest(const std::string& test_name,
+               const conformance::ConformanceRequest& request,
+               conformance::ConformanceResponse* response);
+  void RunValidInputTest(const string& test_name, const string& input,
+                         conformance::WireFormat input_format,
+                         const string& equivalent_text_format,
+                         conformance::WireFormat requested_output);
+  void RunValidJsonTest(const string& test_name, const string& input_json,
+                        const string& equivalent_text_format);
+  void RunValidJsonTestWithProtobufInput(const string& test_name,
+                                         const conformance::TestAllTypes& input,
+                                         const string& equivalent_text_format);
+
+  typedef std::function<bool(const Json::Value&)> Validator;
+  void RunValidJsonTestWithValidator(const string& test_name,
+                                     const string& input_json,
+                                     const Validator& validator);
+  void ExpectParseFailureForJson(const string& test_name,
+                                 const string& input_json);
+  void ExpectSerializeFailureForJson(const string& test_name,
+                                     const string& text_format);
+  void ExpectParseFailureForProto(const std::string& proto,
+                                  const std::string& test_name);
+  void ExpectHardParseFailureForProto(const std::string& proto,
+                                      const std::string& test_name);
+  void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
+  bool CheckSetEmpty(const set<string>& set_to_check, const char* msg);
+  ConformanceTestRunner* runner_;
+  int successes_;
+  int expected_failures_;
+  bool verbose_;
+  std::string output_;
+
+  // The set of test names that are expected to fail in this run, but haven't
+  // failed yet.
+  std::set<std::string> expected_to_fail_;
+
+  // The set of test names that have been run.  Used to ensure that there are no
+  // duplicate names in the suite.
+  std::set<std::string> test_names_;
+
+  // The set of tests that failed, but weren't expected to.
+  std::set<std::string> unexpected_failing_tests_;
+
+  // The set of tests that succeeded, but weren't expected to.
+  std::set<std::string> unexpected_succeeding_tests_;
+
+  // The set of tests that the testee opted out of;
+  std::set<std::string> skipped_;
+
+  google::protobuf::internal::scoped_ptr<google::protobuf::util::TypeResolver>
+      type_resolver_;
+  std::string type_url_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // CONFORMANCE_CONFORMANCE_TEST_H
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
new file mode 100644
index 0000000..376a60b
--- /dev/null
+++ b/conformance/conformance_test_runner.cc
@@ -0,0 +1,312 @@
+// 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.
+
+// This file contains a program for running the test suite in a separate
+// process.  The other alternative is to run the suite in-process.  See
+// conformance.proto for pros/cons of these two options.
+//
+// This program will fork the process under test and communicate with it over
+// its stdin/stdout:
+//
+//     +--------+   pipe   +----------+
+//     | tester | <------> | testee   |
+//     |        |          |          |
+//     |  C++   |          | any lang |
+//     +--------+          +----------+
+//
+// The tester contains all of the test cases and their expected output.
+// The testee is a simple program written in the target language that reads
+// each test case and attempts to produce acceptable output for it.
+//
+// Every test consists of a ConformanceRequest/ConformanceResponse
+// request/reply pair.  The protocol on the pipe is simply:
+//
+//   1. tester sends 4-byte length N (little endian)
+//   2. tester sends N bytes representing a ConformanceRequest proto
+//   3. testee sends 4-byte length M (little endian)
+//   4. testee sends M bytes representing a ConformanceResponse proto
+
+#include <algorithm>
+#include <errno.h>
+#include <fstream>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <vector>
+
+#include <google/protobuf/stubs/stringprintf.h>
+
+#include "conformance.pb.h"
+#include "conformance_test.h"
+
+using conformance::ConformanceRequest;
+using conformance::ConformanceResponse;
+using google::protobuf::internal::scoped_array;
+using google::protobuf::StringAppendF;
+using std::string;
+using std::vector;
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define CHECK_SYSCALL(call) \
+  if (call < 0) { \
+    perror(#call " " __FILE__ ":" TOSTRING(__LINE__)); \
+    exit(1); \
+  }
+
+// Test runner that spawns the process being tested and communicates with it
+// over a pipe.
+class ForkPipeRunner : public google::protobuf::ConformanceTestRunner {
+ public:
+  ForkPipeRunner(const std::string &executable)
+      : child_pid_(-1), executable_(executable) {}
+
+  virtual ~ForkPipeRunner() {}
+
+  void RunTest(const std::string& test_name,
+               const std::string& request,
+               std::string* response) {
+    if (child_pid_ < 0) {
+      SpawnTestProgram();
+    }
+
+    current_test_name_ = test_name;
+
+    uint32_t len = request.size();
+    CheckedWrite(write_fd_, &len, sizeof(uint32_t));
+    CheckedWrite(write_fd_, request.c_str(), request.size());
+
+    if (!TryRead(read_fd_, &len, sizeof(uint32_t))) {
+      // We failed to read from the child, assume a crash and try to reap.
+      GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_;
+
+      int status;
+      waitpid(child_pid_, &status, WEXITED);
+
+      string error_msg;
+      if (WIFEXITED(status)) {
+        StringAppendF(&error_msg,
+                      "child exited, status=%d", WEXITSTATUS(status));
+      } else if (WIFSIGNALED(status)) {
+        StringAppendF(&error_msg,
+                      "child killed by signal %d", WTERMSIG(status));
+      }
+      GOOGLE_LOG(INFO) << error_msg;
+      child_pid_ = -1;
+
+      conformance::ConformanceResponse response_obj;
+      response_obj.set_runtime_error(error_msg);
+      response_obj.SerializeToString(response);
+      return;
+    }
+
+    response->resize(len);
+    CheckedRead(read_fd_, (void*)response->c_str(), len);
+  }
+
+ private:
+  // TODO(haberman): make this work on Windows, instead of using these
+  // UNIX-specific APIs.
+  //
+  // There is a platform-agnostic API in
+  //    src/google/protobuf/compiler/subprocess.h
+  //
+  // However that API only supports sending a single message to the subprocess.
+  // We really want to be able to send messages and receive responses one at a
+  // time:
+  //
+  // 1. Spawning a new process for each test would take way too long for thousands
+  //    of tests and subprocesses like java that can take 100ms or more to start
+  //    up.
+  //
+  // 2. Sending all the tests in one big message and receiving all results in one
+  //    big message would take away our visibility about which test(s) caused a
+  //    crash or other fatal error.  It would also give us only a single failure
+  //    instead of all of them.
+  void SpawnTestProgram() {
+    int toproc_pipe_fd[2];
+    int fromproc_pipe_fd[2];
+    if (pipe(toproc_pipe_fd) < 0 || pipe(fromproc_pipe_fd) < 0) {
+      perror("pipe");
+      exit(1);
+    }
+
+    pid_t pid = fork();
+    if (pid < 0) {
+      perror("fork");
+      exit(1);
+    }
+
+    if (pid) {
+      // Parent.
+      CHECK_SYSCALL(close(toproc_pipe_fd[0]));
+      CHECK_SYSCALL(close(fromproc_pipe_fd[1]));
+      write_fd_ = toproc_pipe_fd[1];
+      read_fd_ = fromproc_pipe_fd[0];
+      child_pid_ = pid;
+    } else {
+      // Child.
+      CHECK_SYSCALL(close(STDIN_FILENO));
+      CHECK_SYSCALL(close(STDOUT_FILENO));
+      CHECK_SYSCALL(dup2(toproc_pipe_fd[0], STDIN_FILENO));
+      CHECK_SYSCALL(dup2(fromproc_pipe_fd[1], STDOUT_FILENO));
+
+      CHECK_SYSCALL(close(toproc_pipe_fd[0]));
+      CHECK_SYSCALL(close(fromproc_pipe_fd[1]));
+      CHECK_SYSCALL(close(toproc_pipe_fd[1]));
+      CHECK_SYSCALL(close(fromproc_pipe_fd[0]));
+
+      scoped_array<char> executable(new char[executable_.size() + 1]);
+      memcpy(executable.get(), executable_.c_str(), executable_.size());
+      executable[executable_.size()] = '\0';
+
+      char *const argv[] = {executable.get(), NULL};
+      CHECK_SYSCALL(execv(executable.get(), argv));  // Never returns.
+    }
+  }
+
+  void CheckedWrite(int fd, const void *buf, size_t len) {
+    if (write(fd, buf, len) != len) {
+      GOOGLE_LOG(FATAL) << current_test_name_
+                        << ": error writing to test program: "
+                        << strerror(errno);
+    }
+  }
+
+  bool TryRead(int fd, void *buf, size_t len) {
+    size_t ofs = 0;
+    while (len > 0) {
+      ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
+
+      if (bytes_read == 0) {
+        GOOGLE_LOG(ERROR) << current_test_name_
+                          << ": unexpected EOF from test program";
+        return false;
+      } else if (bytes_read < 0) {
+        GOOGLE_LOG(ERROR) << current_test_name_
+                          << ": error reading from test program: "
+                          << strerror(errno);
+        return false;
+      }
+
+      len -= bytes_read;
+      ofs += bytes_read;
+    }
+
+    return true;
+  }
+
+  void CheckedRead(int fd, void *buf, size_t len) {
+    if (!TryRead(fd, buf, len)) {
+      GOOGLE_LOG(FATAL) << current_test_name_
+                        << ": error reading from test program: "
+                        << strerror(errno);
+    }
+  }
+
+  int write_fd_;
+  int read_fd_;
+  pid_t child_pid_;
+  std::string executable_;
+  std::string current_test_name_;
+};
+
+void UsageError() {
+  fprintf(stderr,
+          "Usage: conformance-test-runner [options] <test-program>\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "Options:\n");
+  fprintf(stderr,
+          "  --failure_list <filename>   Use to specify list of tests\n");
+  fprintf(stderr,
+          "                              that are expected to fail.  File\n");
+  fprintf(stderr,
+          "                              should contain one test name per\n");
+  fprintf(stderr,
+          "                              line.  Use '#' for comments.\n");
+  exit(1);
+}
+
+void ParseFailureList(const char *filename, vector<string>* failure_list) {
+  std::ifstream infile(filename);
+
+  if (!infile.is_open()) {
+    fprintf(stderr, "Couldn't open failure list file: %s\n", filename);
+    exit(1);
+  }
+
+  for (string line; getline(infile, line);) {
+    // Remove whitespace.
+    line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+               line.end());
+
+    // Remove comments.
+    line = line.substr(0, line.find("#"));
+
+    if (!line.empty()) {
+      failure_list->push_back(line);
+    }
+  }
+}
+
+int main(int argc, char *argv[]) {
+  char *program;
+  google::protobuf::ConformanceTestSuite suite;
+
+  vector<string> failure_list;
+
+  for (int arg = 1; arg < argc; ++arg) {
+    if (strcmp(argv[arg], "--failure_list") == 0) {
+      if (++arg == argc) UsageError();
+      ParseFailureList(argv[arg], &failure_list);
+    } else if (strcmp(argv[arg], "--verbose") == 0) {
+      suite.SetVerbose(true);
+    } else if (argv[arg][0] == '-') {
+      fprintf(stderr, "Unknown option: %s\n", argv[arg]);
+      UsageError();
+    } else {
+      if (arg != argc - 1) {
+        fprintf(stderr, "Too many arguments.\n");
+        UsageError();
+      }
+      program = argv[arg];
+    }
+  }
+
+  suite.SetFailureList(failure_list);
+  ForkPipeRunner runner(program);
+
+  std::string output;
+  bool ok = suite.RunSuite(&runner, &output);
+
+  fwrite(output.c_str(), 1, output.size(), stderr);
+
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/conformance/failure_list_cpp.txt b/conformance/failure_list_cpp.txt
new file mode 100644
index 0000000..2ddf831
--- /dev/null
+++ b/conformance/failure_list_cpp.txt
@@ -0,0 +1,106 @@
+# This is the list of conformance tests that are known to fail for the C++
+# implementation right now.  These should be fixed.
+#
+# By listing them here we can keep tabs on which ones are failing and be sure
+# that we don't introduce regressions in other tests.
+#
+# TODO(haberman): insert links to corresponding bugs tracking the issue.
+# Should we use GitHub issues or the Google-internal bug tracker?
+
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolFieldIntegerOne
+JsonInput.BoolFieldIntegerZero
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.BytesFieldNoPadding
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationHasZeroFractionalDigit.Validator
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameDuplicateDifferentCasing1
+JsonInput.FieldNameDuplicateDifferentCasing2
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldLeadingSpace
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldMinValue.ProtobufOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldNotInteger
+JsonInput.Int32FieldNotNumber
+JsonInput.Int32FieldTooLarge
+JsonInput.Int32FieldTooSmall
+JsonInput.Int32FieldTrailingSpace
+JsonInput.Int64FieldNotInteger
+JsonInput.Int64FieldNotNumber
+JsonInput.Int64FieldTooLarge
+JsonInput.Int64FieldTooSmall
+JsonInput.MapFieldValueIsNull
+JsonInput.OneofFieldDuplicate
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldTrailingComma
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
+JsonInput.StringFieldNotAString
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldSurrogatePair.ProtobufOutput
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.TimestampJsonInputLowercaseZ
+JsonInput.TimestampJsonInputMissingT
+JsonInput.TimestampJsonInputMissingZ
+JsonInput.TimestampJsonInputTooLarge
+JsonInput.TimestampJsonInputTooSmall
+JsonInput.TrailingCommaInAnObject
+JsonInput.Uint32FieldNotInteger
+JsonInput.Uint32FieldNotNumber
+JsonInput.Uint32FieldTooLarge
+JsonInput.Uint64FieldNotInteger
+JsonInput.Uint64FieldNotNumber
+JsonInput.Uint64FieldTooLarge
+JsonInput.WrapperTypesWithNullValue.JsonOutput
+JsonInput.WrapperTypesWithNullValue.ProtobufOutput
+ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInPackedField.BOOL
+ProtobufInput.PrematureEofInPackedField.ENUM
+ProtobufInput.PrematureEofInPackedField.INT32
+ProtobufInput.PrematureEofInPackedField.INT64
+ProtobufInput.PrematureEofInPackedField.SINT32
+ProtobufInput.PrematureEofInPackedField.SINT64
+ProtobufInput.PrematureEofInPackedField.UINT32
+ProtobufInput.PrematureEofInPackedField.UINT64
+ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_csharp.txt b/conformance/failure_list_csharp.txt
new file mode 100644
index 0000000..a46cee4
--- /dev/null
+++ b/conformance/failure_list_csharp.txt
@@ -0,0 +1,16 @@
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.JsonOutput
+JsonInput.FieldNameWithMixedCases.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.Validator
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
diff --git a/conformance/failure_list_java.txt b/conformance/failure_list_java.txt
new file mode 100644
index 0000000..552c0cc
--- /dev/null
+++ b/conformance/failure_list_java.txt
@@ -0,0 +1,49 @@
+# This is the list of conformance tests that are known to fail for the Java
+# implementation right now.  These should be fixed.
+#
+# By listing them here we can keep tabs on which ones are failing and be sure
+# that we don't introduce regressions in other tests.
+
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.BoolFieldAllCapitalFalse
+JsonInput.BoolFieldAllCapitalTrue
+JsonInput.BoolFieldCamelCaseFalse
+JsonInput.BoolFieldCamelCaseTrue
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolMapFieldKeyNotQuoted
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.EnumFieldNotQuoted
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldPlusSign
+JsonInput.Int32MapFieldKeyNotQuoted
+JsonInput.Int64MapFieldKeyNotQuoted
+JsonInput.JsonWithComments
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.StringFieldNotAString
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.Uint32MapFieldKeyNotQuoted
+JsonInput.Uint64MapFieldKeyNotQuoted
diff --git a/conformance/failure_list_objc.txt b/conformance/failure_list_objc.txt
new file mode 100644
index 0000000..5dac350
--- /dev/null
+++ b/conformance/failure_list_objc.txt
@@ -0,0 +1,4 @@
+# No tests currently failing.
+#
+# json input or output tests are skipped (in conformance_objc.m) as mobile
+# platforms don't support json wire format to avoid code bloat.
diff --git a/conformance/failure_list_python-post26.txt b/conformance/failure_list_python-post26.txt
new file mode 100644
index 0000000..19d99b0
--- /dev/null
+++ b/conformance/failure_list_python-post26.txt
@@ -0,0 +1,2 @@
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldUnpairedHighSurrogate
diff --git a/conformance/failure_list_python.txt b/conformance/failure_list_python.txt
new file mode 100644
index 0000000..d2e5263
--- /dev/null
+++ b/conformance/failure_list_python.txt
@@ -0,0 +1,85 @@
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.Any.JsonOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.OriginalProtoFieldName.ProtobufOutput
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_python_cpp.txt b/conformance/failure_list_python_cpp.txt
new file mode 100644
index 0000000..7b5e45f
--- /dev/null
+++ b/conformance/failure_list_python_cpp.txt
@@ -0,0 +1,110 @@
+# This is the list of conformance tests that are known to fail for the
+# Python/C++ implementation right now.  These should be fixed.
+#
+# By listing them here we can keep tabs on which ones are failing and be sure
+# that we don't introduce regressions in other tests.
+#
+# TODO(haberman): insert links to corresponding bugs tracking the issue.
+# Should we use GitHub issues or the Google-internal bug tracker?
+
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.Any.JsonOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.OriginalProtoFieldName.ProtobufOutput
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInPackedField.BOOL
+ProtobufInput.PrematureEofInPackedField.DOUBLE
+ProtobufInput.PrematureEofInPackedField.ENUM
+ProtobufInput.PrematureEofInPackedField.FIXED32
+ProtobufInput.PrematureEofInPackedField.FIXED64
+ProtobufInput.PrematureEofInPackedField.FLOAT
+ProtobufInput.PrematureEofInPackedField.INT32
+ProtobufInput.PrematureEofInPackedField.INT64
+ProtobufInput.PrematureEofInPackedField.SFIXED32
+ProtobufInput.PrematureEofInPackedField.SFIXED64
+ProtobufInput.PrematureEofInPackedField.SINT32
+ProtobufInput.PrematureEofInPackedField.SINT64
+ProtobufInput.PrematureEofInPackedField.UINT32
+ProtobufInput.PrematureEofInPackedField.UINT64
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
new file mode 100644
index 0000000..7c12da0
--- /dev/null
+++ b/conformance/failure_list_ruby.txt
@@ -0,0 +1,199 @@
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.Any.JsonOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BoolFieldIntegerOne
+JsonInput.BoolFieldIntegerZero
+JsonInput.DoubleFieldInfinity.JsonOutput
+JsonInput.DoubleFieldInfinity.ProtobufOutput
+JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
+JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
+JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
+JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
+JsonInput.DoubleFieldMinNegativeValue.JsonOutput
+JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
+JsonInput.DoubleFieldMinPositiveValue.JsonOutput
+JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
+JsonInput.DoubleFieldNan.JsonOutput
+JsonInput.DoubleFieldNan.ProtobufOutput
+JsonInput.DoubleFieldNegativeInfinity.JsonOutput
+JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
+JsonInput.DoubleFieldQuotedValue.JsonOutput
+JsonInput.DoubleFieldQuotedValue.ProtobufOutput
+JsonInput.DurationHas3FractionalDigits.Validator
+JsonInput.DurationHas6FractionalDigits.Validator
+JsonInput.DurationHas9FractionalDigits.Validator
+JsonInput.DurationHasZeroFractionalDigit.Validator
+JsonInput.DurationMaxValue.JsonOutput
+JsonInput.DurationMaxValue.ProtobufOutput
+JsonInput.DurationMinValue.JsonOutput
+JsonInput.DurationMinValue.ProtobufOutput
+JsonInput.DurationRepeatedValue.JsonOutput
+JsonInput.DurationRepeatedValue.ProtobufOutput
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMask.JsonOutput
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameWithMixedCases.JsonOutput
+JsonInput.FieldNameWithMixedCases.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.Validator
+JsonInput.FloatFieldInfinity.JsonOutput
+JsonInput.FloatFieldInfinity.ProtobufOutput
+JsonInput.FloatFieldNan.JsonOutput
+JsonInput.FloatFieldNan.ProtobufOutput
+JsonInput.FloatFieldNegativeInfinity.JsonOutput
+JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
+JsonInput.FloatFieldQuotedValue.JsonOutput
+JsonInput.FloatFieldQuotedValue.ProtobufOutput
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldStringValue.JsonOutput
+JsonInput.Int32FieldStringValue.ProtobufOutput
+JsonInput.Int32FieldStringValueEscaped.JsonOutput
+JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
+JsonInput.Int32MapEscapedKey.JsonOutput
+JsonInput.Int32MapEscapedKey.ProtobufOutput
+JsonInput.Int32MapField.JsonOutput
+JsonInput.Int32MapField.ProtobufOutput
+JsonInput.Int64FieldBeString.Validator
+JsonInput.Int64FieldMaxValue.JsonOutput
+JsonInput.Int64FieldMaxValue.ProtobufOutput
+JsonInput.Int64FieldMinValue.JsonOutput
+JsonInput.Int64FieldMinValue.ProtobufOutput
+JsonInput.Int64MapEscapedKey.JsonOutput
+JsonInput.Int64MapEscapedKey.ProtobufOutput
+JsonInput.Int64MapField.JsonOutput
+JsonInput.Int64MapField.ProtobufOutput
+JsonInput.MessageField.JsonOutput
+JsonInput.MessageField.ProtobufOutput
+JsonInput.MessageMapField.JsonOutput
+JsonInput.MessageMapField.ProtobufOutput
+JsonInput.MessageRepeatedField.JsonOutput
+JsonInput.MessageRepeatedField.ProtobufOutput
+JsonInput.OptionalBoolWrapper.JsonOutput
+JsonInput.OptionalBoolWrapper.ProtobufOutput
+JsonInput.OptionalBytesWrapper.JsonOutput
+JsonInput.OptionalBytesWrapper.ProtobufOutput
+JsonInput.OptionalDoubleWrapper.JsonOutput
+JsonInput.OptionalDoubleWrapper.ProtobufOutput
+JsonInput.OptionalFloatWrapper.JsonOutput
+JsonInput.OptionalFloatWrapper.ProtobufOutput
+JsonInput.OptionalInt32Wrapper.JsonOutput
+JsonInput.OptionalInt32Wrapper.ProtobufOutput
+JsonInput.OptionalInt64Wrapper.JsonOutput
+JsonInput.OptionalInt64Wrapper.ProtobufOutput
+JsonInput.OptionalStringWrapper.JsonOutput
+JsonInput.OptionalStringWrapper.ProtobufOutput
+JsonInput.OptionalUint32Wrapper.JsonOutput
+JsonInput.OptionalUint32Wrapper.ProtobufOutput
+JsonInput.OptionalUint64Wrapper.JsonOutput
+JsonInput.OptionalUint64Wrapper.ProtobufOutput
+JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
+JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.PrimitiveRepeatedField.JsonOutput
+JsonInput.PrimitiveRepeatedField.ProtobufOutput
+JsonInput.RepeatedBoolWrapper.JsonOutput
+JsonInput.RepeatedBoolWrapper.ProtobufOutput
+JsonInput.RepeatedBytesWrapper.JsonOutput
+JsonInput.RepeatedBytesWrapper.ProtobufOutput
+JsonInput.RepeatedDoubleWrapper.JsonOutput
+JsonInput.RepeatedDoubleWrapper.ProtobufOutput
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.RepeatedFloatWrapper.JsonOutput
+JsonInput.RepeatedFloatWrapper.ProtobufOutput
+JsonInput.RepeatedInt32Wrapper.JsonOutput
+JsonInput.RepeatedInt32Wrapper.ProtobufOutput
+JsonInput.RepeatedInt64Wrapper.JsonOutput
+JsonInput.RepeatedInt64Wrapper.ProtobufOutput
+JsonInput.RepeatedStringWrapper.JsonOutput
+JsonInput.RepeatedStringWrapper.ProtobufOutput
+JsonInput.RepeatedUint32Wrapper.JsonOutput
+JsonInput.RepeatedUint32Wrapper.ProtobufOutput
+JsonInput.RepeatedUint64Wrapper.JsonOutput
+JsonInput.RepeatedUint64Wrapper.ProtobufOutput
+JsonInput.StringFieldNotAString
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldSurrogatePair.ProtobufOutput
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampHas3FractionalDigits.Validator
+JsonInput.TimestampHas6FractionalDigits.Validator
+JsonInput.TimestampHas9FractionalDigits.Validator
+JsonInput.TimestampHasZeroFractionalDigit.Validator
+JsonInput.TimestampMaxValue.JsonOutput
+JsonInput.TimestampMaxValue.ProtobufOutput
+JsonInput.TimestampMinValue.JsonOutput
+JsonInput.TimestampMinValue.ProtobufOutput
+JsonInput.TimestampRepeatedValue.JsonOutput
+JsonInput.TimestampRepeatedValue.ProtobufOutput
+JsonInput.TimestampWithNegativeOffset.JsonOutput
+JsonInput.TimestampWithNegativeOffset.ProtobufOutput
+JsonInput.TimestampWithPositiveOffset.JsonOutput
+JsonInput.TimestampWithPositiveOffset.ProtobufOutput
+JsonInput.TimestampZeroNormalized.Validator
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Uint32MapField.JsonOutput
+JsonInput.Uint32MapField.ProtobufOutput
+JsonInput.Uint64FieldBeString.Validator
+JsonInput.Uint64FieldMaxValue.JsonOutput
+JsonInput.Uint64FieldMaxValue.ProtobufOutput
+JsonInput.Uint64MapField.JsonOutput
+JsonInput.Uint64MapField.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
+ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
+ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
+ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/third_party/jsoncpp/json.h b/conformance/third_party/jsoncpp/json.h
new file mode 100644
index 0000000..42e7e7f
--- /dev/null
+++ b/conformance/third_party/jsoncpp/json.h
@@ -0,0 +1,2075 @@
+/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation, 
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all 
+jurisdictions which recognize such a disclaimer. In such jurisdictions, 
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this 
+software may choose to accept it either as 1) Public Domain, 2) under the 
+conditions of the MIT License (see below), or 3) under the terms of dual 
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+   
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_AMALGATED_H_INCLUDED
+# define JSON_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// DO NOT EDIT. This file (and "version") is generated by CMake.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+# define JSON_VERSION_H_INCLUDED
+
+# define JSONCPP_VERSION_STRING "1.6.5"
+# define JSONCPP_VERSION_MAJOR 1
+# define JSONCPP_VERSION_MINOR 6
+# define JSONCPP_VERSION_PATCH 5
+# define JSONCPP_VERSION_QUALIFIER
+# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//#  define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//#  define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+#  if _MSC_VER <= 1200 // MSVC 6
+    // Microsoft Visual Studio 6 only support conversion from __int64 to double
+    // (no conversion from unsigned __int64).
+#    define JSON_USE_INT64_DOUBLE_CONVERSION 1
+    // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+    // characters in the debug information)
+    // All projects I've ever seen with VS6 were using this globally (not bothering
+    // with pragma push/pop).
+#    pragma warning(disable : 4786)
+#  endif // MSVC 6
+
+#  if _MSC_VER >= 1500 // MSVC 2008
+    /// Indicates that the following function is deprecated.
+#    define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#  endif
+
+#endif // defined(_MSC_VER)
+
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif  // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif  // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
+#  elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#    define JSONCPP_DEPRECATED(message)  __attribute__((__deprecated__))
+#  endif  // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else                 // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else                 // if defined(_MSC_VER) // Other platforms, use long long
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+  /** \brief A configuration that allows all features and assumes all strings
+   * are UTF-8.
+   * - C & C++ comments are allowed
+   * - Root object can be any JSON value
+   * - Assumes Value strings are encoded in UTF-8
+   */
+  static Features all();
+
+  /** \brief A configuration that is strictly compatible with the JSON
+   * specification.
+   * - Comments are forbidden.
+   * - Root object must be either an array or an object value.
+   * - Assumes Value strings are encoded in UTF-8
+   */
+  static Features strictMode();
+
+  /** \brief Initialize the configuration like JsonConfig::allFeatures;
+   */
+  Features();
+
+  /// \c true if comments are allowed. Default: \c true.
+  bool allowComments_;
+
+  /// \c true if root must be either an array or an object value. Default: \c
+  /// false.
+  bool strictRoot_;
+
+  /// \c true if dropped null placeholders are allowed. Default: \c false.
+  bool allowDroppedNullPlaceholders_;
+
+  /// \c true if numeric object key are allowed. Default: \c false.
+  bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <string>
+#include <vector>
+#include <exception>
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include <map>
+#else
+#include <cpptl/smallmap.h>
+#endif
+#ifdef JSON_USE_CPPTL
+#include <cpptl/forwards.h>
+#endif
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+/** Base class for all exceptions we throw.
+ *
+ * We use nothing but these internally. Of course, STL can throw others.
+ */
+class JSON_API Exception : public std::exception {
+public:
+  Exception(std::string const& msg);
+  ~Exception() throw() override;
+  char const* what() const throw() override;
+protected:
+  std::string msg_;
+};
+
+/** Exceptions which the user cannot easily avoid.
+ *
+ * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
+ * 
+ * \remark derived from Json::Exception
+ */
+class JSON_API RuntimeError : public Exception {
+public:
+  RuntimeError(std::string const& msg);
+};
+
+/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
+ *
+ * These are precondition-violations (user bugs) and internal errors (our bugs).
+ * 
+ * \remark derived from Json::Exception
+ */
+class JSON_API LogicError : public Exception {
+public:
+  LogicError(std::string const& msg);
+};
+
+/// used internally
+void throwRuntimeError(std::string const& msg);
+/// used internally
+void throwLogicError(std::string const& msg);
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType {
+  nullValue = 0, ///< 'null' value
+  intValue,      ///< signed integer value
+  uintValue,     ///< unsigned integer value
+  realValue,     ///< double value
+  stringValue,   ///< UTF-8 string value
+  booleanValue,  ///< bool value
+  arrayValue,    ///< array value (ordered list)
+  objectValue    ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement {
+  commentBefore = 0,      ///< a comment placed on the line before a value
+  commentAfterOnSameLine, ///< a comment just after a value on the same line
+  commentAfter, ///< a comment on the line after a value (only make sense for
+  /// root value)
+  numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString {
+public:
+  explicit StaticString(const char* czstring) : c_str_(czstring) {}
+
+  operator const char*() const { return c_str_; }
+
+  const char* c_str() const { return c_str_; }
+
+private:
+  const char* c_str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * Values of an #objectValue or #arrayValue can be accessed using operator[]()
+ * methods.
+ * Non-const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resized and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtain default value in the case the
+ * required element does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ *
+ * \note #Value string-length fit in size_t, but keys must be < 2^30.
+ * (The reason is an implementation detail.) A #CharReader will raise an
+ * exception if a bound is exceeded to avoid security holes in your app,
+ * but the Value API does *not* check bounds. That is the responsibility
+ * of the caller.
+ */
+class JSON_API Value {
+  friend class ValueIteratorBase;
+public:
+  typedef std::vector<std::string> Members;
+  typedef ValueIterator iterator;
+  typedef ValueConstIterator const_iterator;
+  typedef Json::UInt UInt;
+  typedef Json::Int Int;
+#if defined(JSON_HAS_INT64)
+  typedef Json::UInt64 UInt64;
+  typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+  typedef Json::LargestInt LargestInt;
+  typedef Json::LargestUInt LargestUInt;
+  typedef Json::ArrayIndex ArrayIndex;
+
+  static const Value& null;  ///< We regret this reference to a global instance; prefer the simpler Value().
+  static const Value& nullRef;  ///< just a kludge for binary-compatibility; same as null
+  /// Minimum signed integer value that can be stored in a Json::Value.
+  static const LargestInt minLargestInt;
+  /// Maximum signed integer value that can be stored in a Json::Value.
+  static const LargestInt maxLargestInt;
+  /// Maximum unsigned integer value that can be stored in a Json::Value.
+  static const LargestUInt maxLargestUInt;
+
+  /// Minimum signed int value that can be stored in a Json::Value.
+  static const Int minInt;
+  /// Maximum signed int value that can be stored in a Json::Value.
+  static const Int maxInt;
+  /// Maximum unsigned int value that can be stored in a Json::Value.
+  static const UInt maxUInt;
+
+#if defined(JSON_HAS_INT64)
+  /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+  static const Int64 minInt64;
+  /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+  static const Int64 maxInt64;
+  /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+  static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+  class CZString {
+  public:
+    enum DuplicationPolicy {
+      noDuplication = 0,
+      duplicate,
+      duplicateOnCopy
+    };
+    CZString(ArrayIndex index);
+    CZString(char const* str, unsigned length, DuplicationPolicy allocate);
+    CZString(CZString const& other);
+#if JSON_HAS_RVALUE_REFERENCES
+    CZString(CZString&& other);
+#endif
+    ~CZString();
+    CZString& operator=(CZString other);
+    bool operator<(CZString const& other) const;
+    bool operator==(CZString const& other) const;
+    ArrayIndex index() const;
+    //const char* c_str() const; ///< \deprecated
+    char const* data() const;
+    unsigned length() const;
+    bool isStaticString() const;
+
+  private:
+    void swap(CZString& other);
+
+    struct StringStorage {
+      unsigned policy_: 2;
+      unsigned length_: 30; // 1GB max
+    };
+
+    char const* cstr_;  // actually, a prefixed string, unless policy is noDup
+    union {
+      ArrayIndex index_;
+      StringStorage storage_;
+    };
+  };
+
+public:
+#ifndef JSON_USE_CPPTL_SMALLMAP
+  typedef std::map<CZString, Value> ObjectValues;
+#else
+  typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#endif // ifndef JSON_USE_CPPTL_SMALLMAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+public:
+  /** \brief Create a default Value of the given type.
+
+    This is a very useful constructor.
+    To create an empty array, pass arrayValue.
+    To create an empty object, pass objectValue.
+    Another Value can then be set to this one by assignment.
+This is useful since clear() and resize() will not alter types.
+
+    Examples:
+\code
+Json::Value null_value; // null
+Json::Value arr_value(Json::arrayValue); // []
+Json::Value obj_value(Json::objectValue); // {}
+\endcode
+  */
+  Value(ValueType type = nullValue);
+  Value(Int value);
+  Value(UInt value);
+#if defined(JSON_HAS_INT64)
+  Value(Int64 value);
+  Value(UInt64 value);
+#endif // if defined(JSON_HAS_INT64)
+  Value(double value);
+  Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
+  Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
+  /** \brief Constructs a value from a static string.
+
+   * Like other value string constructor but do not duplicate the string for
+   * internal storage. The given string must remain alive after the call to this
+   * constructor.
+   * \note This works only for null-terminated strings. (We cannot change the
+   *   size of this class, so we have nowhere to store the length,
+   *   which might be computed later for various operations.)
+   *
+   * Example of usage:
+   * \code
+   * static StaticString foo("some text");
+   * Json::Value aValue(foo);
+   * \endcode
+   */
+  Value(const StaticString& value);
+  Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too.
+#ifdef JSON_USE_CPPTL
+  Value(const CppTL::ConstString& value);
+#endif
+  Value(bool value);
+  /// Deep copy.
+  Value(const Value& other);
+#if JSON_HAS_RVALUE_REFERENCES
+  /// Move constructor
+  Value(Value&& other);
+#endif
+  ~Value();
+
+  /// Deep copy, then swap(other).
+  /// \note Over-write existing comments. To preserve comments, use #swapPayload().
+  Value& operator=(Value other);
+  /// Swap everything.
+  void swap(Value& other);
+  /// Swap values but leave comments and source offsets in place.
+  void swapPayload(Value& other);
+
+  ValueType type() const;
+
+  /// Compare payload only, not comments etc.
+  bool operator<(const Value& other) const;
+  bool operator<=(const Value& other) const;
+  bool operator>=(const Value& other) const;
+  bool operator>(const Value& other) const;
+  bool operator==(const Value& other) const;
+  bool operator!=(const Value& other) const;
+  int compare(const Value& other) const;
+
+  const char* asCString() const; ///< Embedded zeroes could cause you trouble!
+  std::string asString() const; ///< Embedded zeroes are possible.
+  /** Get raw char* of string-value.
+   *  \return false if !string. (Seg-fault if str or end are NULL.)
+   */
+  bool getString(
+      char const** begin, char const** end) const;
+#ifdef JSON_USE_CPPTL
+  CppTL::ConstString asConstString() const;
+#endif
+  Int asInt() const;
+  UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+  Int64 asInt64() const;
+  UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+  LargestInt asLargestInt() const;
+  LargestUInt asLargestUInt() const;
+  float asFloat() const;
+  double asDouble() const;
+  bool asBool() const;
+
+  bool isNull() const;
+  bool isBool() const;
+  bool isInt() const;
+  bool isInt64() const;
+  bool isUInt() const;
+  bool isUInt64() const;
+  bool isIntegral() const;
+  bool isDouble() const;
+  bool isNumeric() const;
+  bool isString() const;
+  bool isArray() const;
+  bool isObject() const;
+
+  bool isConvertibleTo(ValueType other) const;
+
+  /// Number of values in array or object
+  ArrayIndex size() const;
+
+  /// \brief Return true if empty array, empty object, or null;
+  /// otherwise, false.
+  bool empty() const;
+
+  /// Return isNull()
+  bool operator!() const;
+
+  /// Remove all object members and array elements.
+  /// \pre type() is arrayValue, objectValue, or nullValue
+  /// \post type() is unchanged
+  void clear();
+
+  /// Resize the array to size elements.
+  /// New elements are initialized to null.
+  /// May only be called on nullValue or arrayValue.
+  /// \pre type() is arrayValue or nullValue
+  /// \post type() is arrayValue
+  void resize(ArrayIndex size);
+
+  /// Access an array element (zero based index ).
+  /// If the array contains less than index element, then null value are
+  /// inserted
+  /// in the array so that its size is index+1.
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  Value& operator[](ArrayIndex index);
+
+  /// Access an array element (zero based index ).
+  /// If the array contains less than index element, then null value are
+  /// inserted
+  /// in the array so that its size is index+1.
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  Value& operator[](int index);
+
+  /// Access an array element (zero based index )
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  const Value& operator[](ArrayIndex index) const;
+
+  /// Access an array element (zero based index )
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  const Value& operator[](int index) const;
+
+  /// If the array contains at least index+1 elements, returns the element
+  /// value,
+  /// otherwise returns defaultValue.
+  Value get(ArrayIndex index, const Value& defaultValue) const;
+  /// Return true if index < size().
+  bool isValidIndex(ArrayIndex index) const;
+  /// \brief Append value to array at the end.
+  ///
+  /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+  Value& append(const Value& value);
+
+  /// Access an object value by name, create a null member if it does not exist.
+  /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
+  ///  Exceeding that will cause an exception.
+  Value& operator[](const char* key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  const Value& operator[](const char* key) const;
+  /// Access an object value by name, create a null member if it does not exist.
+  /// \param key may contain embedded nulls.
+  Value& operator[](const std::string& key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  /// \param key may contain embedded nulls.
+  const Value& operator[](const std::string& key) const;
+  /** \brief Access an object value by name, create a null member if it does not
+   exist.
+
+   * If the object has no entry for that name, then the member name used to store
+   * the new entry is not duplicated.
+   * Example of use:
+   * \code
+   * Json::Value object;
+   * static const StaticString code("code");
+   * object[code] = 1234;
+   * \endcode
+   */
+  Value& operator[](const StaticString& key);
+#ifdef JSON_USE_CPPTL
+  /// Access an object value by name, create a null member if it does not exist.
+  Value& operator[](const CppTL::ConstString& key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  const Value& operator[](const CppTL::ConstString& key) const;
+#endif
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  Value get(const char* key, const Value& defaultValue) const;
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  /// \note key may contain embedded nulls.
+  Value get(const char* begin, const char* end, const Value& defaultValue) const;
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  /// \param key may contain embedded nulls.
+  Value get(const std::string& key, const Value& defaultValue) const;
+#ifdef JSON_USE_CPPTL
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
+#endif
+  /// Most general and efficient version of isMember()const, get()const,
+  /// and operator[]const
+  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+  Value const* find(char const* begin, char const* end) const;
+  /// Most general and efficient version of object-mutators.
+  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+  /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
+  Value const* demand(char const* begin, char const* end);
+  /// \brief Remove and return the named member.
+  ///
+  /// Do nothing if it did not exist.
+  /// \return the removed Value, or null.
+  /// \pre type() is objectValue or nullValue
+  /// \post type() is unchanged
+  /// \deprecated
+  Value removeMember(const char* key);
+  /// Same as removeMember(const char*)
+  /// \param key may contain embedded nulls.
+  /// \deprecated
+  Value removeMember(const std::string& key);
+  /// Same as removeMember(const char* begin, const char* end, Value* removed),
+  /// but 'key' is null-terminated.
+  bool removeMember(const char* key, Value* removed);
+  /** \brief Remove the named map member.
+
+      Update 'removed' iff removed.
+      \param key may contain embedded nulls.
+      \return true iff removed (no exceptions)
+  */
+  bool removeMember(std::string const& key, Value* removed);
+  /// Same as removeMember(std::string const& key, Value* removed)
+  bool removeMember(const char* begin, const char* end, Value* removed);
+  /** \brief Remove the indexed array element.
+
+      O(n) expensive operations.
+      Update 'removed' iff removed.
+      \return true iff removed (no exceptions)
+  */
+  bool removeIndex(ArrayIndex i, Value* removed);
+
+  /// Return true if the object has a member named key.
+  /// \note 'key' must be null-terminated.
+  bool isMember(const char* key) const;
+  /// Return true if the object has a member named key.
+  /// \param key may contain embedded nulls.
+  bool isMember(const std::string& key) const;
+  /// Same as isMember(std::string const& key)const
+  bool isMember(const char* begin, const char* end) const;
+#ifdef JSON_USE_CPPTL
+  /// Return true if the object has a member named key.
+  bool isMember(const CppTL::ConstString& key) const;
+#endif
+
+  /// \brief Return a list of the member names.
+  ///
+  /// If null, return an empty list.
+  /// \pre type() is objectValue or nullValue
+  /// \post if type() was nullValue, it remains nullValue
+  Members getMemberNames() const;
+
+  //# ifdef JSON_USE_CPPTL
+  //      EnumMemberNames enumMemberNames() const;
+  //      EnumValues enumValues() const;
+  //# endif
+
+  /// \deprecated Always pass len.
+  JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.")
+  void setComment(const char* comment, CommentPlacement placement);
+  /// Comments must be //... or /* ... */
+  void setComment(const char* comment, size_t len, CommentPlacement placement);
+  /// Comments must be //... or /* ... */
+  void setComment(const std::string& comment, CommentPlacement placement);
+  bool hasComment(CommentPlacement placement) const;
+  /// Include delimiters and embedded newlines.
+  std::string getComment(CommentPlacement placement) const;
+
+  std::string toStyledString() const;
+
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  iterator begin();
+  iterator end();
+
+  // Accessors for the [start, limit) range of bytes within the JSON text from
+  // which this value was parsed, if any.
+  void setOffsetStart(size_t start);
+  void setOffsetLimit(size_t limit);
+  size_t getOffsetStart() const;
+  size_t getOffsetLimit() const;
+
+private:
+  void initBasic(ValueType type, bool allocated = false);
+
+  Value& resolveReference(const char* key);
+  Value& resolveReference(const char* key, const char* end);
+
+  struct CommentInfo {
+    CommentInfo();
+    ~CommentInfo();
+
+    void setComment(const char* text, size_t len);
+
+    char* comment_;
+  };
+
+  // struct MemberNamesTransform
+  //{
+  //   typedef const char *result_type;
+  //   const char *operator()( const CZString &name ) const
+  //   {
+  //      return name.c_str();
+  //   }
+  //};
+
+  union ValueHolder {
+    LargestInt int_;
+    LargestUInt uint_;
+    double real_;
+    bool bool_;
+    char* string_;  // actually ptr to unsigned, followed by str, unless !allocated_
+    ObjectValues* map_;
+  } value_;
+  ValueType type_ : 8;
+  unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+                               // If not allocated_, string_ must be null-terminated.
+  CommentInfo* comments_;
+
+  // [start, limit) byte offsets in the source JSON text from which this Value
+  // was extracted.
+  size_t start_;
+  size_t limit_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to
+ * access a node.
+ */
+class JSON_API PathArgument {
+public:
+  friend class Path;
+
+  PathArgument();
+  PathArgument(ArrayIndex index);
+  PathArgument(const char* key);
+  PathArgument(const std::string& key);
+
+private:
+  enum Kind {
+    kindNone = 0,
+    kindIndex,
+    kindKey
+  };
+  std::string key_;
+  ArrayIndex index_;
+  Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class JSON_API Path {
+public:
+  Path(const std::string& path,
+       const PathArgument& a1 = PathArgument(),
+       const PathArgument& a2 = PathArgument(),
+       const PathArgument& a3 = PathArgument(),
+       const PathArgument& a4 = PathArgument(),
+       const PathArgument& a5 = PathArgument());
+
+  const Value& resolve(const Value& root) const;
+  Value resolve(const Value& root, const Value& defaultValue) const;
+  /// Creates the "path" to access the specified node and returns a reference on
+  /// the node.
+  Value& make(Value& root) const;
+
+private:
+  typedef std::vector<const PathArgument*> InArgs;
+  typedef std::vector<PathArgument> Args;
+
+  void makePath(const std::string& path, const InArgs& in);
+  void addPathInArg(const std::string& path,
+                    const InArgs& in,
+                    InArgs::const_iterator& itInArg,
+                    PathArgument::Kind kind);
+  void invalidPath(const std::string& path, int location);
+
+  Args args_;
+};
+
+/** \brief base class for Value iterators.
+ *
+ */
+class JSON_API ValueIteratorBase {
+public:
+  typedef std::bidirectional_iterator_tag iterator_category;
+  typedef unsigned int size_t;
+  typedef int difference_type;
+  typedef ValueIteratorBase SelfType;
+
+  bool operator==(const SelfType& other) const { return isEqual(other); }
+
+  bool operator!=(const SelfType& other) const { return !isEqual(other); }
+
+  difference_type operator-(const SelfType& other) const {
+    return other.computeDistance(*this);
+  }
+
+  /// Return either the index or the member name of the referenced value as a
+  /// Value.
+  Value key() const;
+
+  /// Return the index of the referenced Value, or -1 if it is not an arrayValue.
+  UInt index() const;
+
+  /// Return the member name of the referenced Value, or "" if it is not an
+  /// objectValue.
+  /// \note Avoid `c_str()` on result, as embedded zeroes are possible.
+  std::string name() const;
+
+  /// Return the member name of the referenced Value. "" if it is not an
+  /// objectValue.
+  /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
+  JSONCPP_DEPRECATED("Use `key = name();` instead.")
+  char const* memberName() const;
+  /// Return the member name of the referenced Value, or NULL if it is not an
+  /// objectValue.
+  /// \note Better version than memberName(). Allows embedded nulls.
+  char const* memberName(char const** end) const;
+
+protected:
+  Value& deref() const;
+
+  void increment();
+
+  void decrement();
+
+  difference_type computeDistance(const SelfType& other) const;
+
+  bool isEqual(const SelfType& other) const;
+
+  void copy(const SelfType& other);
+
+private:
+  Value::ObjectValues::iterator current_;
+  // Indicates that iterator is for a null value.
+  bool isNull_;
+
+public:
+  // For some reason, BORLAND needs these at the end, rather
+  // than earlier. No idea why.
+  ValueIteratorBase();
+  explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class JSON_API ValueConstIterator : public ValueIteratorBase {
+  friend class Value;
+
+public:
+  typedef const Value value_type;
+  //typedef unsigned int size_t;
+  //typedef int difference_type;
+  typedef const Value& reference;
+  typedef const Value* pointer;
+  typedef ValueConstIterator SelfType;
+
+  ValueConstIterator();
+  ValueConstIterator(ValueIterator const& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+  explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
+public:
+  SelfType& operator=(const ValueIteratorBase& other);
+
+  SelfType operator++(int) {
+    SelfType temp(*this);
+    ++*this;
+    return temp;
+  }
+
+  SelfType operator--(int) {
+    SelfType temp(*this);
+    --*this;
+    return temp;
+  }
+
+  SelfType& operator--() {
+    decrement();
+    return *this;
+  }
+
+  SelfType& operator++() {
+    increment();
+    return *this;
+  }
+
+  reference operator*() const { return deref(); }
+
+  pointer operator->() const { return &deref(); }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class JSON_API ValueIterator : public ValueIteratorBase {
+  friend class Value;
+
+public:
+  typedef Value value_type;
+  typedef unsigned int size_t;
+  typedef int difference_type;
+  typedef Value& reference;
+  typedef Value* pointer;
+  typedef ValueIterator SelfType;
+
+  ValueIterator();
+  explicit ValueIterator(const ValueConstIterator& other);
+  ValueIterator(const ValueIterator& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+  explicit ValueIterator(const Value::ObjectValues::iterator& current);
+public:
+  SelfType& operator=(const SelfType& other);
+
+  SelfType operator++(int) {
+    SelfType temp(*this);
+    ++*this;
+    return temp;
+  }
+
+  SelfType operator--(int) {
+    SelfType temp(*this);
+    --*this;
+    return temp;
+  }
+
+  SelfType& operator--() {
+    decrement();
+    return *this;
+  }
+
+  SelfType& operator++() {
+    increment();
+    return *this;
+  }
+
+  reference operator*() const { return deref(); }
+
+  pointer operator->() const { return &deref(); }
+};
+
+} // namespace Json
+
+
+namespace std {
+/// Specialize std::swap() for Json::Value.
+template<>
+inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
+}
+
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+#define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "features.h"
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <deque>
+#include <iosfwd>
+#include <stack>
+#include <string>
+#include <istream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
+ *Value.
+ *
+ * \deprecated Use CharReader and CharReaderBuilder.
+ */
+class JSON_API Reader {
+public:
+  typedef char Char;
+  typedef const Char* Location;
+
+  /** \brief An error tagged with where in the JSON text it was encountered.
+   *
+   * The offsets give the [start, limit) range of bytes within the text. Note
+   * that this is bytes, not codepoints.
+   *
+   */
+  struct StructuredError {
+    size_t offset_start;
+    size_t offset_limit;
+    std::string message;
+  };
+
+  /** \brief Constructs a Reader allowing all features
+   * for parsing.
+   */
+  Reader();
+
+  /** \brief Constructs a Reader allowing the specified feature set
+   * for parsing.
+   */
+  Reader(const Features& features);
+
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   * document.
+   * \param document UTF-8 encoded string containing the document to read.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param collectComments \c true to collect comment and allow writing them
+   * back during
+   *                        serialization, \c false to discard comments.
+   *                        This parameter is ignored if
+   * Features::allowComments_
+   *                        is \c false.
+   * \return \c true if the document was successfully parsed, \c false if an
+   * error occurred.
+   */
+  bool
+  parse(const std::string& document, Value& root, bool collectComments = true);
+
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   document.
+   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+   document to read.
+   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+   document to read.
+   *               Must be >= beginDoc.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param collectComments \c true to collect comment and allow writing them
+   back during
+   *                        serialization, \c false to discard comments.
+   *                        This parameter is ignored if
+   Features::allowComments_
+   *                        is \c false.
+   * \return \c true if the document was successfully parsed, \c false if an
+   error occurred.
+   */
+  bool parse(const char* beginDoc,
+             const char* endDoc,
+             Value& root,
+             bool collectComments = true);
+
+  /// \brief Parse from input stream.
+  /// \see Json::operator>>(std::istream&, Json::Value&).
+  bool parse(std::istream& is, Value& root, bool collectComments = true);
+
+  /** \brief Returns a user friendly string that list errors in the parsed
+   * document.
+   * \return Formatted error message with the list of errors with their location
+   * in
+   *         the parsed document. An empty string is returned if no error
+   * occurred
+   *         during parsing.
+   * \deprecated Use getFormattedErrorMessages() instead (typo fix).
+   */
+  JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
+  std::string getFormatedErrorMessages() const;
+
+  /** \brief Returns a user friendly string that list errors in the parsed
+   * document.
+   * \return Formatted error message with the list of errors with their location
+   * in
+   *         the parsed document. An empty string is returned if no error
+   * occurred
+   *         during parsing.
+   */
+  std::string getFormattedErrorMessages() const;
+
+  /** \brief Returns a vector of structured erros encounted while parsing.
+   * \return A (possibly empty) vector of StructuredError objects. Currently
+   *         only one error can be returned, but the caller should tolerate
+   * multiple
+   *         errors.  This can occur if the parser recovers from a non-fatal
+   *         parse error and then encounters additional errors.
+   */
+  std::vector<StructuredError> getStructuredErrors() const;
+
+  /** \brief Add a semantic error message.
+   * \param value JSON Value location associated with the error
+   * \param message The error message.
+   * \return \c true if the error was successfully added, \c false if the
+   * Value offset exceeds the document size.
+   */
+  bool pushError(const Value& value, const std::string& message);
+
+  /** \brief Add a semantic error message with extra context.
+   * \param value JSON Value location associated with the error
+   * \param message The error message.
+   * \param extra Additional JSON Value location to contextualize the error
+   * \return \c true if the error was successfully added, \c false if either
+   * Value offset exceeds the document size.
+   */
+  bool pushError(const Value& value, const std::string& message, const Value& extra);
+
+  /** \brief Return whether there are any errors.
+   * \return \c true if there are no errors to report \c false if
+   * errors have occurred.
+   */
+  bool good() const;
+
+private:
+  enum TokenType {
+    tokenEndOfStream = 0,
+    tokenObjectBegin,
+    tokenObjectEnd,
+    tokenArrayBegin,
+    tokenArrayEnd,
+    tokenString,
+    tokenNumber,
+    tokenTrue,
+    tokenFalse,
+    tokenNull,
+    tokenArraySeparator,
+    tokenMemberSeparator,
+    tokenComment,
+    tokenError
+  };
+
+  class Token {
+  public:
+    TokenType type_;
+    Location start_;
+    Location end_;
+  };
+
+  class ErrorInfo {
+  public:
+    Token token_;
+    std::string message_;
+    Location extra_;
+  };
+
+  typedef std::deque<ErrorInfo> Errors;
+
+  bool readToken(Token& token);
+  void skipSpaces();
+  bool match(Location pattern, int patternLength);
+  bool readComment();
+  bool readCStyleComment();
+  bool readCppStyleComment();
+  bool readString();
+  void readNumber();
+  bool readValue();
+  bool readObject(Token& token);
+  bool readArray(Token& token);
+  bool decodeNumber(Token& token);
+  bool decodeNumber(Token& token, Value& decoded);
+  bool decodeString(Token& token);
+  bool decodeString(Token& token, std::string& decoded);
+  bool decodeDouble(Token& token);
+  bool decodeDouble(Token& token, Value& decoded);
+  bool decodeUnicodeCodePoint(Token& token,
+                              Location& current,
+                              Location end,
+                              unsigned int& unicode);
+  bool decodeUnicodeEscapeSequence(Token& token,
+                                   Location& current,
+                                   Location end,
+                                   unsigned int& unicode);
+  bool addError(const std::string& message, Token& token, Location extra = 0);
+  bool recoverFromError(TokenType skipUntilToken);
+  bool addErrorAndRecover(const std::string& message,
+                          Token& token,
+                          TokenType skipUntilToken);
+  void skipUntilSpace();
+  Value& currentValue();
+  Char getNextChar();
+  void
+  getLocationLineAndColumn(Location location, int& line, int& column) const;
+  std::string getLocationLineAndColumn(Location location) const;
+  void addComment(Location begin, Location end, CommentPlacement placement);
+  void skipCommentTokens(Token& token);
+
+  typedef std::stack<Value*> Nodes;
+  Nodes nodes_;
+  Errors errors_;
+  std::string document_;
+  Location begin_;
+  Location end_;
+  Location current_;
+  Location lastValueEnd_;
+  Value* lastValue_;
+  std::string commentsBefore_;
+  Features features_;
+  bool collectComments_;
+};  // Reader
+
+/** Interface for reading JSON from a char array.
+ */
+class JSON_API CharReader {
+public:
+  virtual ~CharReader() {}
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   document.
+   * The document must be a UTF-8 encoded string containing the document to read.
+   *
+   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+   document to read.
+   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+   document to read.
+   *        Must be >= beginDoc.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param errs [out] Formatted error messages (if not NULL)
+   *        a user friendly string that lists errors in the parsed
+   * document.
+   * \return \c true if the document was successfully parsed, \c false if an
+   error occurred.
+   */
+  virtual bool parse(
+      char const* beginDoc, char const* endDoc,
+      Value* root, std::string* errs) = 0;
+
+  class JSON_API Factory {
+  public:
+    virtual ~Factory() {}
+    /** \brief Allocate a CharReader via operator new().
+     * \throw std::exception if something goes wrong (e.g. invalid settings)
+     */
+    virtual CharReader* newCharReader() const = 0;
+  };  // Factory
+};  // CharReader
+
+/** \brief Build a CharReader implementation.
+
+Usage:
+\code
+  using namespace Json;
+  CharReaderBuilder builder;
+  builder["collectComments"] = false;
+  Value value;
+  std::string errs;
+  bool ok = parseFromStream(builder, std::cin, &value, &errs);
+\endcode
+*/
+class JSON_API CharReaderBuilder : public CharReader::Factory {
+public:
+  // Note: We use a Json::Value so that we can add data-members to this class
+  // without a major version bump.
+  /** Configuration of this builder.
+    These are case-sensitive.
+    Available settings (case-sensitive):
+    - `"collectComments": false or true`
+      - true to collect comment and allow writing them
+        back during serialization, false to discard comments.
+        This parameter is ignored if allowComments is false.
+    - `"allowComments": false or true`
+      - true if comments are allowed.
+    - `"strictRoot": false or true`
+      - true if root must be either an array or an object value
+    - `"allowDroppedNullPlaceholders": false or true`
+      - true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
+    - `"allowNumericKeys": false or true`
+      - true if numeric object keys are allowed.
+    - `"allowSingleQuotes": false or true`
+      - true if '' are allowed for strings (both keys and values)
+    - `"stackLimit": integer`
+      - Exceeding stackLimit (recursive depth of `readValue()`) will
+        cause an exception.
+      - This is a security issue (seg-faults caused by deeply nested JSON),
+        so the default is low.
+    - `"failIfExtra": false or true`
+      - If true, `parse()` returns false when extra non-whitespace trails
+        the JSON value in the input string.
+    - `"rejectDupKeys": false or true`
+      - If true, `parse()` returns false when a key is duplicated within an object.
+    - `"allowSpecialFloats": false or true`
+      - If true, special float values (NaNs and infinities) are allowed 
+        and their values are lossfree restorable.
+
+    You can examine 'settings_` yourself
+    to see the defaults. You can also write and read them just like any
+    JSON Value.
+    \sa setDefaults()
+    */
+  Json::Value settings_;
+
+  CharReaderBuilder();
+  ~CharReaderBuilder() override;
+
+  CharReader* newCharReader() const override;
+
+  /** \return true if 'settings' are legal and consistent;
+   *   otherwise, indicate bad settings via 'invalid'.
+   */
+  bool validate(Json::Value* invalid) const;
+
+  /** A simple way to update a specific setting.
+   */
+  Value& operator[](std::string key);
+
+  /** Called by ctor, but you can use this to reset settings_.
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
+   */
+  static void setDefaults(Json::Value* settings);
+  /** Same as old Features::strictMode().
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
+   */
+  static void strictMode(Json::Value* settings);
+};
+
+/** Consume entire stream and use its begin/end.
+  * Someday we might have a real StreamReader, but for now this
+  * is convenient.
+  */
+bool JSON_API parseFromStream(
+    CharReader::Factory const&,
+    std::istream&,
+    Value* root, std::string* errs);
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+     "file": {
+     // The input stream JSON would be nested here.
+     }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+*/
+JSON_API std::istream& operator>>(std::istream&, Value&);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+#define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <vector>
+#include <string>
+#include <ostream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+class Value;
+
+/**
+
+Usage:
+\code
+  using namespace Json;
+  void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
+    std::unique_ptr<StreamWriter> const writer(
+      factory.newStreamWriter());
+    writer->write(value, &std::cout);
+    std::cout << std::endl;  // add lf and flush
+  }
+\endcode
+*/
+class JSON_API StreamWriter {
+protected:
+  std::ostream* sout_;  // not owned; will not delete
+public:
+  StreamWriter();
+  virtual ~StreamWriter();
+  /** Write Value into document as configured in sub-class.
+      Do not take ownership of sout, but maintain a reference during function.
+      \pre sout != NULL
+      \return zero on success (For now, we always return zero, so check the stream instead.)
+      \throw std::exception possibly, depending on configuration
+   */
+  virtual int write(Value const& root, std::ostream* sout) = 0;
+
+  /** \brief A simple abstract factory.
+   */
+  class JSON_API Factory {
+  public:
+    virtual ~Factory();
+    /** \brief Allocate a CharReader via operator new().
+     * \throw std::exception if something goes wrong (e.g. invalid settings)
+     */
+    virtual StreamWriter* newStreamWriter() const = 0;
+  };  // Factory
+};  // StreamWriter
+
+/** \brief Write into stringstream, then return string, for convenience.
+ * A StreamWriter will be created from the factory, used, and then deleted.
+ */
+std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
+
+
+/** \brief Build a StreamWriter implementation.
+
+Usage:
+\code
+  using namespace Json;
+  Value value = ...;
+  StreamWriterBuilder builder;
+  builder["commentStyle"] = "None";
+  builder["indentation"] = "   ";  // or whatever you like
+  std::unique_ptr<Json::StreamWriter> writer(
+      builder.newStreamWriter());
+  writer->write(value, &std::cout);
+  std::cout << std::endl;  // add lf and flush
+\endcode
+*/
+class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
+public:
+  // Note: We use a Json::Value so that we can add data-members to this class
+  // without a major version bump.
+  /** Configuration of this builder.
+    Available settings (case-sensitive):
+    - "commentStyle": "None" or "All"
+    - "indentation":  "<anything>"
+    - "enableYAMLCompatibility": false or true
+      - slightly change the whitespace around colons
+    - "dropNullPlaceholders": false or true
+      - Drop the "null" string from the writer's output for nullValues.
+        Strictly speaking, this is not valid JSON. But when the output is being
+        fed to a browser's Javascript, it makes for smaller output and the
+        browser can handle the output just fine.
+    - "useSpecialFloats": false or true
+      - If true, outputs non-finite floating point values in the following way:
+        NaN values as "NaN", positive infinity as "Infinity", and negative infinity
+        as "-Infinity".
+
+    You can examine 'settings_` yourself
+    to see the defaults. You can also write and read them just like any
+    JSON Value.
+    \sa setDefaults()
+    */
+  Json::Value settings_;
+
+  StreamWriterBuilder();
+  ~StreamWriterBuilder() override;
+
+  /**
+   * \throw std::exception if something goes wrong (e.g. invalid settings)
+   */
+  StreamWriter* newStreamWriter() const override;
+
+  /** \return true if 'settings' are legal and consistent;
+   *   otherwise, indicate bad settings via 'invalid'.
+   */
+  bool validate(Json::Value* invalid) const;
+  /** A simple way to update a specific setting.
+   */
+  Value& operator[](std::string key);
+
+  /** Called by ctor, but you can use this to reset settings_.
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
+   */
+  static void setDefaults(Json::Value* settings);
+};
+
+/** \brief Abstract class for writers.
+ * \deprecated Use StreamWriter. (And really, this is an implementation detail.)
+ */
+class JSON_API Writer {
+public:
+  virtual ~Writer();
+
+  virtual std::string write(const Value& root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
+ *without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human'
+ *consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API FastWriter : public Writer {
+
+public:
+  FastWriter();
+  ~FastWriter() override {}
+
+  void enableYAMLCompatibility();
+
+  /** \brief Drop the "null" string from the writer's output for nullValues.
+   * Strictly speaking, this is not valid JSON. But when the output is being
+   * fed to a browser's Javascript, it makes for smaller output and the
+   * browser can handle the output just fine.
+   */
+  void dropNullPlaceholders();
+
+  void omitEndingLineFeed();
+
+public: // overridden from Writer
+  std::string write(const Value& root) override;
+
+private:
+  void writeValue(const Value& value);
+
+  std::string document_;
+  bool yamlCompatiblityEnabled_;
+  bool dropNullPlaceholders_;
+  bool omitEndingLineFeed_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ *human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per
+ *line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value
+ *types,
+ *       and all the values fit on one lines, then print the array on a single
+ *line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ *#CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledWriter : public Writer {
+public:
+  StyledWriter();
+  ~StyledWriter() override {}
+
+public: // overridden from Writer
+  /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+   * \param root Value to serialize.
+   * \return String containing the JSON document that represents the root value.
+   */
+  std::string write(const Value& root) override;
+
+private:
+  void writeValue(const Value& value);
+  void writeArrayValue(const Value& value);
+  bool isMultineArray(const Value& value);
+  void pushValue(const std::string& value);
+  void writeIndent();
+  void writeWithIndent(const std::string& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(const Value& root);
+  void writeCommentAfterValueOnSameLine(const Value& root);
+  bool hasCommentForValue(const Value& value);
+  static std::string normalizeEOL(const std::string& text);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::string document_;
+  std::string indentString_;
+  int rightMargin_;
+  int indentSize_;
+  bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ human friendly way,
+     to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per
+ line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value
+ types,
+ *       and all the values fit on one lines, then print the array on a single
+ line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledStreamWriter {
+public:
+  StyledStreamWriter(std::string indentation = "\t");
+  ~StyledStreamWriter() {}
+
+public:
+  /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+   * \param out Stream to write to. (Can be ostringstream, e.g.)
+   * \param root Value to serialize.
+   * \note There is no point in deriving from Writer, since write() should not
+   * return a value.
+   */
+  void write(std::ostream& out, const Value& root);
+
+private:
+  void writeValue(const Value& value);
+  void writeArrayValue(const Value& value);
+  bool isMultineArray(const Value& value);
+  void pushValue(const std::string& value);
+  void writeIndent();
+  void writeWithIndent(const std::string& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(const Value& root);
+  void writeCommentAfterValueOnSameLine(const Value& root);
+  bool hasCommentForValue(const Value& value);
+  static std::string normalizeEOL(const std::string& text);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::ostream* document_;
+  std::string indentString_;
+  int rightMargin_;
+  std::string indentation_;
+  bool addChildValues_ : 1;
+  bool indented_ : 1;
+};
+
+#if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(Int value);
+std::string JSON_API valueToString(UInt value);
+#endif // if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(LargestInt value);
+std::string JSON_API valueToString(LargestUInt value);
+std::string JSON_API valueToString(double value);
+std::string JSON_API valueToString(bool value);
+std::string JSON_API valueToQuotedString(const char* value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // JSON_WRITER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#include <stdlib.h>
+#include <sstream>
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+/** It should not be possible for a maliciously designed file to
+ *  cause an abort() or seg-fault, so these macros are used only
+ *  for pre-condition violations and internal logic errors.
+ */
+#if JSON_USE_EXCEPTION
+
+// @todo <= add detail about condition in exception
+# define JSON_ASSERT(condition)                                                \
+  {if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
+
+# define JSON_FAIL_MESSAGE(message)                                            \
+  {                                                                            \
+    std::ostringstream oss; oss << message;                                    \
+    Json::throwLogicError(oss.str());                                          \
+    abort();                                                                   \
+  }
+
+#else // JSON_USE_EXCEPTION
+
+# define JSON_ASSERT(condition) assert(condition)
+
+// The call to assert() will show the failure message in debug builds. In
+// release builds we abort, for a core-dump or debugger.
+# define JSON_FAIL_MESSAGE(message)                                            \
+  {                                                                            \
+    std::ostringstream oss; oss << message;                                    \
+    assert(false && oss.str().c_str());                                        \
+    abort();                                                                   \
+  }
+
+
+#endif
+
+#define JSON_ASSERT_MESSAGE(condition, message)                                \
+  if (!(condition)) {                                                          \
+    JSON_FAIL_MESSAGE(message);                                                \
+  }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#endif //ifndef JSON_AMALGATED_H_INCLUDED
diff --git a/conformance/third_party/jsoncpp/jsoncpp.cpp b/conformance/third_party/jsoncpp/jsoncpp.cpp
new file mode 100644
index 0000000..f803962
--- /dev/null
+++ b/conformance/third_party/jsoncpp/jsoncpp.cpp
@@ -0,0 +1,5192 @@
+/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation, 
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all 
+jurisdictions which recognize such a disclaimer. In such jurisdictions, 
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this 
+software may choose to accept it either as 1) Public Domain, 2) under the 
+conditions of the MIT License (see below), or 3) under the terms of dual 
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+   
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+#include "third_party/jsoncpp/json.h"
+
+#ifndef JSON_IS_AMALGAMATION
+#error "Compile with -I PATH_TO_JSON_DIRECTORY"
+#endif
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json {
+
+/// Converts a unicode code-point to UTF-8.
+static inline std::string codePointToUTF8(unsigned int cp) {
+  std::string result;
+
+  // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+  if (cp <= 0x7f) {
+    result.resize(1);
+    result[0] = static_cast<char>(cp);
+  } else if (cp <= 0x7FF) {
+    result.resize(2);
+    result[1] = static_cast<char>(0x80 | (0x3f & cp));
+    result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+  } else if (cp <= 0xFFFF) {
+    result.resize(3);
+    result[2] = static_cast<char>(0x80 | (0x3f & cp));
+    result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+    result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
+  } else if (cp <= 0x10FFFF) {
+    result.resize(4);
+    result[3] = static_cast<char>(0x80 | (0x3f & cp));
+    result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+    result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+    result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+  }
+
+  return result;
+}
+
+/// Returns true if ch is a control character (in range [1,31]).
+static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
+
+enum {
+  /// Constant that specify the size of the buffer that must be passed to
+  /// uintToString.
+  uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer.
+ *        Must have at least uintToStringBufferSize chars free.
+ */
+static inline void uintToString(LargestUInt value, char*& current) {
+  *--current = 0;
+  do {
+    *--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
+    value /= 10;
+  } while (value != 0);
+}
+
+/** Change ',' to '.' everywhere in buffer.
+ *
+ * We had a sophisticated way, but it did not work in WinCE.
+ * @see https://github.com/open-source-parsers/jsoncpp/pull/9
+ */
+static inline void fixNumericLocale(char* begin, char* end) {
+  while (begin < end) {
+    if (*begin == ',') {
+      *begin = '.';
+    }
+    ++begin;
+  }
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <istream>
+#include <sstream>
+#include <memory>
+#include <set>
+#include <limits>
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#define snprintf std::snprintf
+#endif
+
+#if defined(__QNXNTO__)
+#define sscanf std::sscanf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+static int const stackLimit_g = 1000;
+static int       stackDepth_g = 0;  // see readValue()
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<CharReader> CharReaderPtr;
+#else
+typedef std::auto_ptr<CharReader>   CharReaderPtr;
+#endif
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+    : allowComments_(true), strictRoot_(false),
+      allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+
+Features Features::all() { return Features(); }
+
+Features Features::strictMode() {
+  Features features;
+  features.allowComments_ = false;
+  features.strictRoot_ = true;
+  features.allowDroppedNullPlaceholders_ = false;
+  features.allowNumericKeys_ = false;
+  return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end) {
+  for (; begin < end; ++begin)
+    if (*begin == '\n' || *begin == '\r')
+      return true;
+  return false;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(), features_(Features::all()),
+      collectComments_() {}
+
+Reader::Reader(const Features& features)
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(), features_(features), collectComments_() {
+}
+
+bool
+Reader::parse(const std::string& document, Value& root, bool collectComments) {
+  document_ = document;
+  const char* begin = document_.c_str();
+  const char* end = begin + document_.length();
+  return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
+  // std::istream_iterator<char> begin(sin);
+  // std::istream_iterator<char> end;
+  // Those would allow streamed input from a file, if parse() were a
+  // template function.
+
+  // Since std::string is reference-counted, this at least does not
+  // create an extra copy.
+  std::string doc;
+  std::getline(sin, doc, (char)EOF);
+  return parse(doc, root, collectComments);
+}
+
+bool Reader::parse(const char* beginDoc,
+                   const char* endDoc,
+                   Value& root,
+                   bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = 0;
+  lastValue_ = 0;
+  commentsBefore_ = "";
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  stackDepth_g = 0;  // Yes, this is bad coding, but options are limited.
+  bool successful = readValue();
+  Token token;
+  skipCommentTokens(token);
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool Reader::readValue() {
+  // This is a non-reentrant way to support a stackLimit. Terrible!
+  // But this deprecated class has a security problem: Bad input can
+  // cause a seg-fault. This seems like a fair, binary-compatible way
+  // to prevent the problem.
+  if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
+  ++stackDepth_g;
+
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_ = "";
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue:
+    {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenFalse:
+    {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNull:
+    {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // Else, fall through...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValue_ = &currentValue();
+  }
+
+  --stackDepth_g;
+  return successful;
+}
+
+void Reader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool Reader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+  case '-':
+    token.type_ = tokenNumber;
+    readNumber();
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return true;
+}
+
+void Reader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+bool Reader::match(Location pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool Reader::readComment() {
+  Location commentBegin = current_ - 1;
+  Char c = getNextChar();
+  bool successful = false;
+  if (c == '*')
+    successful = readCStyleComment();
+  else if (c == '/')
+    successful = readCppStyleComment();
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, current_))
+        placement = commentAfterOnSameLine;
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
+  std::string normalized;
+  normalized.reserve(end - begin);
+  Reader::Location current = begin;
+  while (current != end) {
+    char c = *current++;
+    if (c == '\r') {
+      if (current != end && *current == '\n')
+         // convert dos EOL
+         ++current;
+      // convert Mac EOL
+      normalized += '\n';
+    } else {
+      normalized += c;
+    }
+  }
+  return normalized;
+}
+
+void
+Reader::addComment(Location begin, Location end, CommentPlacement placement) {
+  assert(collectComments_);
+  const std::string& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != 0);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool Reader::readCStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+  }
+  return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+void Reader::readNumber() {
+  const char *p = current_;
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : 0;
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+}
+
+bool Reader::readString() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+bool Reader::readObject(Token& tokenStart) {
+  Token tokenName;
+  std::string name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+      return true;
+    name = "";
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover(
+          "Missing ':' after object member name", colon, tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover(
+          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover(
+      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool Reader::readArray(Token& tokenStart) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  skipSpaces();
+  if (*current_ == ']') // empty array
+  {
+    Token endArray;
+    readToken(endArray);
+    return true;
+  }
+  int index = 0;
+  for (;;) {
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token token;
+    // Accept Comment after last item in the array.
+    ok = readToken(token);
+    while (token.type_ == tokenComment && ok) {
+      ok = readToken(token);
+    }
+    bool badTokenType =
+        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover(
+          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+    }
+    if (token.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  bool isNegative = *current == '-';
+  if (isNegative)
+    ++current;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+  Value::LargestUInt maxIntegerValue =
+      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
+                 : Value::maxLargestUInt;
+  Value::LargestUInt threshold = maxIntegerValue / 10;
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+    Value::UInt digit(c - '0');
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, b) this is the last digit, and
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > maxIntegerValue % 10) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+  if (isNegative && value == maxIntegerValue)
+    decoded = Value::minLargestInt;
+  else if (isNegative)
+    decoded = -Value::LargestInt(value);
+  else if (value <= Value::LargestUInt(Value::maxInt))
+    decoded = Value::LargestInt(value);
+  else
+    decoded = value;
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  std::string buffer(token.start_, token.end_);
+  std::istringstream is(buffer);
+  if (!(is >> value))
+    return addError("'" + std::string(token.start_, token.end_) +
+                        "' is not a number.",
+                    token);
+  decoded = value;
+  return true;
+}
+
+bool Reader::decodeString(Token& token) {
+  std::string decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeString(Token& token, std::string& decoded) {
+  decoded.reserve(token.end_ - token.start_ - 2);
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    else if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token& token,
+                                    Location& current,
+                                    Location end,
+                                    unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token,
+          current);
+    unsigned int surrogatePair;
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token,
+                      current);
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token& token,
+                                         Location& current,
+                                         Location end,
+                                         unsigned int& unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.",
+        token,
+        current);
+  unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token,
+          current);
+  }
+  return true;
+}
+
+bool
+Reader::addError(const std::string& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken) {
+  int errorCount = int(errors_.size());
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool Reader::addErrorAndRecover(const std::string& message,
+                                Token& token,
+                                TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& Reader::currentValue() { return *(nodes_.top()); }
+
+Reader::Char Reader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location,
+                                      int& line,
+                                      int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+std::string Reader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+std::string Reader::getFormatedErrorMessages() const {
+  return getFormattedErrorMessages();
+}
+
+std::string Reader::getFormattedErrorMessages() const {
+  std::string formattedMessage;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+  std::vector<Reader::StructuredError> allErrors;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    Reader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = end_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = 0;
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length
+    || extra.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = begin_ + extra.getOffsetStart();
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::good() const {
+  return !errors_.size();
+}
+
+// exact copy of Features
+class OurFeatures {
+public:
+  static OurFeatures all();
+  bool allowComments_;
+  bool strictRoot_;
+  bool allowDroppedNullPlaceholders_;
+  bool allowNumericKeys_;
+  bool allowSingleQuotes_;
+  bool failIfExtra_;
+  bool rejectDupKeys_;
+  bool allowSpecialFloats_;
+  int stackLimit_;
+};  // OurFeatures
+
+// exact copy of Implementation of class Features
+// ////////////////////////////////
+
+OurFeatures OurFeatures::all() { return OurFeatures(); }
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+// exact copy of Reader, renamed to OurReader
+class OurReader {
+public:
+  typedef char Char;
+  typedef const Char* Location;
+  struct StructuredError {
+    size_t offset_start;
+    size_t offset_limit;
+    std::string message;
+  };
+
+  OurReader(OurFeatures const& features);
+  bool parse(const char* beginDoc,
+             const char* endDoc,
+             Value& root,
+             bool collectComments = true);
+  std::string getFormattedErrorMessages() const;
+  std::vector<StructuredError> getStructuredErrors() const;
+  bool pushError(const Value& value, const std::string& message);
+  bool pushError(const Value& value, const std::string& message, const Value& extra);
+  bool good() const;
+
+private:
+  OurReader(OurReader const&);  // no impl
+  void operator=(OurReader const&);  // no impl
+
+  enum TokenType {
+    tokenEndOfStream = 0,
+    tokenObjectBegin,
+    tokenObjectEnd,
+    tokenArrayBegin,
+    tokenArrayEnd,
+    tokenString,
+    tokenNumber,
+    tokenTrue,
+    tokenFalse,
+    tokenNull,
+    tokenNaN,
+    tokenPosInf,
+    tokenNegInf,
+    tokenArraySeparator,
+    tokenMemberSeparator,
+    tokenComment,
+    tokenError
+  };
+
+  class Token {
+  public:
+    TokenType type_;
+    Location start_;
+    Location end_;
+  };
+
+  class ErrorInfo {
+  public:
+    Token token_;
+    std::string message_;
+    Location extra_;
+  };
+
+  typedef std::deque<ErrorInfo> Errors;
+
+  bool readToken(Token& token);
+  void skipSpaces();
+  bool match(Location pattern, int patternLength);
+  bool readComment();
+  bool readCStyleComment();
+  bool readCppStyleComment();
+  bool readString();
+  bool readStringSingleQuote();
+  bool readNumber(bool checkInf);
+  bool readValue();
+  bool readObject(Token& token);
+  bool readArray(Token& token);
+  bool decodeNumber(Token& token);
+  bool decodeNumber(Token& token, Value& decoded);
+  bool decodeString(Token& token);
+  bool decodeString(Token& token, std::string& decoded);
+  bool decodeDouble(Token& token);
+  bool decodeDouble(Token& token, Value& decoded);
+  bool decodeUnicodeCodePoint(Token& token,
+                              Location& current,
+                              Location end,
+                              unsigned int& unicode);
+  bool decodeUnicodeEscapeSequence(Token& token,
+                                   Location& current,
+                                   Location end,
+                                   unsigned int& unicode);
+  bool addError(const std::string& message, Token& token, Location extra = 0);
+  bool recoverFromError(TokenType skipUntilToken);
+  bool addErrorAndRecover(const std::string& message,
+                          Token& token,
+                          TokenType skipUntilToken);
+  void skipUntilSpace();
+  Value& currentValue();
+  Char getNextChar();
+  void
+  getLocationLineAndColumn(Location location, int& line, int& column) const;
+  std::string getLocationLineAndColumn(Location location) const;
+  void addComment(Location begin, Location end, CommentPlacement placement);
+  void skipCommentTokens(Token& token);
+
+  typedef std::stack<Value*> Nodes;
+  Nodes nodes_;
+  Errors errors_;
+  std::string document_;
+  Location begin_;
+  Location end_;
+  Location current_;
+  Location lastValueEnd_;
+  Value* lastValue_;
+  std::string commentsBefore_;
+  int stackDepth_;
+
+  OurFeatures const features_;
+  bool collectComments_;
+};  // OurReader
+
+// complete copy of Read impl, for OurReader
+
+OurReader::OurReader(OurFeatures const& features)
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(),
+      stackDepth_(0),
+      features_(features), collectComments_() {
+}
+
+bool OurReader::parse(const char* beginDoc,
+                   const char* endDoc,
+                   Value& root,
+                   bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = 0;
+  lastValue_ = 0;
+  commentsBefore_ = "";
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  stackDepth_ = 0;
+  bool successful = readValue();
+  Token token;
+  skipCommentTokens(token);
+  if (features_.failIfExtra_) {
+    if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
+      addError("Extra non-whitespace after JSON value.", token);
+      return false;
+    }
+  }
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool OurReader::readValue() {
+  if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
+  ++stackDepth_;
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_ = "";
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue:
+    {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenFalse:
+    {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNull:
+    {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNaN:
+    {
+    Value v(std::numeric_limits<double>::quiet_NaN());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenPosInf:
+    {
+    Value v(std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNegInf:
+    {
+    Value v(-std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // else, fall through ...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValue_ = &currentValue();
+  }
+
+  --stackDepth_;
+  return successful;
+}
+
+void OurReader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool OurReader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '\'':
+    if (features_.allowSingleQuotes_) {
+    token.type_ = tokenString;
+    ok = readStringSingleQuote();
+    break;
+    } // else continue
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    token.type_ = tokenNumber;
+    readNumber(false);
+    break;
+  case '-':
+    if (readNumber(true)) {
+      token.type_ = tokenNumber;
+    } else {
+      token.type_ = tokenNegInf;
+      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+    }
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case 'N':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenNaN;
+      ok = match("aN", 2);
+    } else {
+      ok = false;
+    }
+    break;
+  case 'I':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenPosInf;
+      ok = match("nfinity", 7);
+    } else {
+      ok = false;
+    }
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return true;
+}
+
+void OurReader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+bool OurReader::match(Location pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool OurReader::readComment() {
+  Location commentBegin = current_ - 1;
+  Char c = getNextChar();
+  bool successful = false;
+  if (c == '*')
+    successful = readCStyleComment();
+  else if (c == '/')
+    successful = readCppStyleComment();
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, current_))
+        placement = commentAfterOnSameLine;
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+void
+OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
+  assert(collectComments_);
+  const std::string& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != 0);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool OurReader::readCStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+  }
+  return getNextChar() == '/';
+}
+
+bool OurReader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+bool OurReader::readNumber(bool checkInf) {
+  const char *p = current_;
+  if (checkInf && p != end_ && *p == 'I') {
+    current_ = ++p;
+    return false;
+  }
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : 0;
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  return true;
+}
+bool OurReader::readString() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+
+bool OurReader::readStringSingleQuote() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '\'')
+      break;
+  }
+  return c == '\'';
+}
+
+bool OurReader::readObject(Token& tokenStart) {
+  Token tokenName;
+  std::string name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+      return true;
+    name = "";
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover(
+          "Missing ':' after object member name", colon, tokenObjectEnd);
+    }
+    if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
+    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
+      std::string msg = "Duplicate key: '" + name + "'";
+      return addErrorAndRecover(
+          msg, tokenName, tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover(
+          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover(
+      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool OurReader::readArray(Token& tokenStart) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  skipSpaces();
+  if (*current_ == ']') // empty array
+  {
+    Token endArray;
+    readToken(endArray);
+    return true;
+  }
+  int index = 0;
+  for (;;) {
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token token;
+    // Accept Comment after last item in the array.
+    ok = readToken(token);
+    while (token.type_ == tokenComment && ok) {
+      ok = readToken(token);
+    }
+    bool badTokenType =
+        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover(
+          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+    }
+    if (token.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  bool isNegative = *current == '-';
+  if (isNegative)
+    ++current;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+  Value::LargestUInt maxIntegerValue =
+      isNegative ? Value::LargestUInt(-Value::minLargestInt)
+                 : Value::maxLargestUInt;
+  Value::LargestUInt threshold = maxIntegerValue / 10;
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+    Value::UInt digit(c - '0');
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, b) this is the last digit, and
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > maxIntegerValue % 10) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+  if (isNegative)
+    decoded = -Value::LargestInt(value);
+  else if (value <= Value::LargestUInt(Value::maxInt))
+    decoded = Value::LargestInt(value);
+  else
+    decoded = value;
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  const int bufferSize = 32;
+  int count;
+  int length = int(token.end_ - token.start_);
+
+  // Sanity check to avoid buffer overflow exploits.
+  if (length < 0) {
+    return addError("Unable to parse token length", token);
+  }
+
+  // Avoid using a string constant for the format control string given to
+  // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+  // info:
+  //
+  //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+  char format[] = "%lf";
+
+  if (length <= bufferSize) {
+    Char buffer[bufferSize + 1];
+    memcpy(buffer, token.start_, length);
+    buffer[length] = 0;
+    count = sscanf(buffer, format, &value);
+  } else {
+    std::string buffer(token.start_, token.end_);
+    count = sscanf(buffer.c_str(), format, &value);
+  }
+
+  if (count != 1)
+    return addError("'" + std::string(token.start_, token.end_) +
+                        "' is not a number.",
+                    token);
+  decoded = value;
+  return true;
+}
+
+bool OurReader::decodeString(Token& token) {
+  std::string decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeString(Token& token, std::string& decoded) {
+  decoded.reserve(token.end_ - token.start_ - 2);
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    else if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeCodePoint(Token& token,
+                                    Location& current,
+                                    Location end,
+                                    unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token,
+          current);
+    unsigned int surrogatePair;
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token,
+                      current);
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeEscapeSequence(Token& token,
+                                         Location& current,
+                                         Location end,
+                                         unsigned int& unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.",
+        token,
+        current);
+  unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token,
+          current);
+  }
+  return true;
+}
+
+bool
+OurReader::addError(const std::string& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool OurReader::recoverFromError(TokenType skipUntilToken) {
+  int errorCount = int(errors_.size());
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool OurReader::addErrorAndRecover(const std::string& message,
+                                Token& token,
+                                TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& OurReader::currentValue() { return *(nodes_.top()); }
+
+OurReader::Char OurReader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void OurReader::getLocationLineAndColumn(Location location,
+                                      int& line,
+                                      int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+std::string OurReader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+std::string OurReader::getFormattedErrorMessages() const {
+  std::string formattedMessage;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
+  std::vector<OurReader::StructuredError> allErrors;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    OurReader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+bool OurReader::pushError(const Value& value, const std::string& message) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = end_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = 0;
+  errors_.push_back(info);
+  return true;
+}
+
+bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length
+    || extra.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = begin_ + extra.getOffsetStart();
+  errors_.push_back(info);
+  return true;
+}
+
+bool OurReader::good() const {
+  return !errors_.size();
+}
+
+
+class OurCharReader : public CharReader {
+  bool const collectComments_;
+  OurReader reader_;
+public:
+  OurCharReader(
+    bool collectComments,
+    OurFeatures const& features)
+  : collectComments_(collectComments)
+  , reader_(features)
+  {}
+  bool parse(
+      char const* beginDoc, char const* endDoc,
+      Value* root, std::string* errs) override {
+    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
+    if (errs) {
+      *errs = reader_.getFormattedErrorMessages();
+    }
+    return ok;
+  }
+};
+
+CharReaderBuilder::CharReaderBuilder()
+{
+  setDefaults(&settings_);
+}
+CharReaderBuilder::~CharReaderBuilder()
+{}
+CharReader* CharReaderBuilder::newCharReader() const
+{
+  bool collectComments = settings_["collectComments"].asBool();
+  OurFeatures features = OurFeatures::all();
+  features.allowComments_ = settings_["allowComments"].asBool();
+  features.strictRoot_ = settings_["strictRoot"].asBool();
+  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
+  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
+  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
+  features.stackLimit_ = settings_["stackLimit"].asInt();
+  features.failIfExtra_ = settings_["failIfExtra"].asBool();
+  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
+  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+  return new OurCharReader(collectComments, features);
+}
+static void getValidReaderKeys(std::set<std::string>* valid_keys)
+{
+  valid_keys->clear();
+  valid_keys->insert("collectComments");
+  valid_keys->insert("allowComments");
+  valid_keys->insert("strictRoot");
+  valid_keys->insert("allowDroppedNullPlaceholders");
+  valid_keys->insert("allowNumericKeys");
+  valid_keys->insert("allowSingleQuotes");
+  valid_keys->insert("stackLimit");
+  valid_keys->insert("failIfExtra");
+  valid_keys->insert("rejectDupKeys");
+  valid_keys->insert("allowSpecialFloats");
+}
+bool CharReaderBuilder::validate(Json::Value* invalid) const
+{
+  Json::Value my_invalid;
+  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  Json::Value& inv = *invalid;
+  std::set<std::string> valid_keys;
+  getValidReaderKeys(&valid_keys);
+  Value::Members keys = settings_.getMemberNames();
+  size_t n = keys.size();
+  for (size_t i = 0; i < n; ++i) {
+    std::string const& key = keys[i];
+    if (valid_keys.find(key) == valid_keys.end()) {
+      inv[key] = settings_[key];
+    }
+  }
+  return 0u == inv.size();
+}
+Value& CharReaderBuilder::operator[](std::string key)
+{
+  return settings_[key];
+}
+// static
+void CharReaderBuilder::strictMode(Json::Value* settings)
+{
+//! [CharReaderBuilderStrictMode]
+  (*settings)["allowComments"] = false;
+  (*settings)["strictRoot"] = true;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = true;
+  (*settings)["rejectDupKeys"] = true;
+  (*settings)["allowSpecialFloats"] = false;
+//! [CharReaderBuilderStrictMode]
+}
+// static
+void CharReaderBuilder::setDefaults(Json::Value* settings)
+{
+//! [CharReaderBuilderDefaults]
+  (*settings)["collectComments"] = true;
+  (*settings)["allowComments"] = true;
+  (*settings)["strictRoot"] = false;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = false;
+  (*settings)["rejectDupKeys"] = false;
+  (*settings)["allowSpecialFloats"] = false;
+//! [CharReaderBuilderDefaults]
+}
+
+//////////////////////////////////
+// global functions
+
+bool parseFromStream(
+    CharReader::Factory const& fact, std::istream& sin,
+    Value* root, std::string* errs)
+{
+  std::ostringstream ssin;
+  ssin << sin.rdbuf();
+  std::string doc = ssin.str();
+  char const* begin = doc.data();
+  char const* end = begin + doc.size();
+  // Note that we do not actually need a null-terminator.
+  CharReaderPtr const reader(fact.newCharReader());
+  return reader->parse(begin, end, root, errs);
+}
+
+std::istream& operator>>(std::istream& sin, Value& root) {
+  CharReaderBuilder b;
+  std::string errs;
+  bool ok = parseFromStream(b, sin, &root, &errs);
+  if (!ok) {
+    fprintf(stderr,
+            "Error from reader: %s",
+            errs.c_str());
+
+    throwRuntimeError(errs);
+  }
+  return sin;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+    : current_(), isNull_(true) {
+}
+
+ValueIteratorBase::ValueIteratorBase(
+    const Value::ObjectValues::iterator& current)
+    : current_(current), isNull_(false) {}
+
+Value& ValueIteratorBase::deref() const {
+  return current_->second;
+}
+
+void ValueIteratorBase::increment() {
+  ++current_;
+}
+
+void ValueIteratorBase::decrement() {
+  --current_;
+}
+
+ValueIteratorBase::difference_type
+ValueIteratorBase::computeDistance(const SelfType& other) const {
+#ifdef JSON_USE_CPPTL_SMALLMAP
+  return other.current_ - current_;
+#else
+  // Iterator for null value are initialized using the default
+  // constructor, which initialize current_ to the default
+  // std::map::iterator. As begin() and end() are two instance
+  // of the default std::map::iterator, they can not be compared.
+  // To allow this, we handle this comparison specifically.
+  if (isNull_ && other.isNull_) {
+    return 0;
+  }
+
+  // Usage of std::distance is not portable (does not compile with Sun Studio 12
+  // RogueWave STL,
+  // which is the one used by default).
+  // Using a portable hand-made version for non random iterator instead:
+  //   return difference_type( std::distance( current_, other.current_ ) );
+  difference_type myDistance = 0;
+  for (Value::ObjectValues::iterator it = current_; it != other.current_;
+       ++it) {
+    ++myDistance;
+  }
+  return myDistance;
+#endif
+}
+
+bool ValueIteratorBase::isEqual(const SelfType& other) const {
+  if (isNull_) {
+    return other.isNull_;
+  }
+  return current_ == other.current_;
+}
+
+void ValueIteratorBase::copy(const SelfType& other) {
+  current_ = other.current_;
+  isNull_ = other.isNull_;
+}
+
+Value ValueIteratorBase::key() const {
+  const Value::CZString czstring = (*current_).first;
+  if (czstring.data()) {
+    if (czstring.isStaticString())
+      return Value(StaticString(czstring.data()));
+    return Value(czstring.data(), czstring.data() + czstring.length());
+  }
+  return Value(czstring.index());
+}
+
+UInt ValueIteratorBase::index() const {
+  const Value::CZString czstring = (*current_).first;
+  if (!czstring.data())
+    return czstring.index();
+  return Value::UInt(-1);
+}
+
+std::string ValueIteratorBase::name() const {
+  char const* keey;
+  char const* end;
+  keey = memberName(&end);
+  if (!keey) return std::string();
+  return std::string(keey, end);
+}
+
+char const* ValueIteratorBase::memberName() const {
+  const char* cname = (*current_).first.data();
+  return cname ? cname : "";
+}
+
+char const* ValueIteratorBase::memberName(char const** end) const {
+  const char* cname = (*current_).first.data();
+  if (!cname) {
+    *end = NULL;
+    return NULL;
+  }
+  *end = cname + (*current_).first.length();
+  return cname;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator() {}
+
+ValueConstIterator::ValueConstIterator(
+    const Value::ObjectValues::iterator& current)
+    : ValueIteratorBase(current) {}
+
+ValueConstIterator::ValueConstIterator(ValueIterator const& other)
+    : ValueIteratorBase(other) {}
+
+ValueConstIterator& ValueConstIterator::
+operator=(const ValueIteratorBase& other) {
+  copy(other);
+  return *this;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator() {}
+
+ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
+    : ValueIteratorBase(current) {}
+
+ValueIterator::ValueIterator(const ValueConstIterator& other)
+    : ValueIteratorBase(other) {
+  throwRuntimeError("ConstIterator to Iterator should never be allowed.");
+}
+
+ValueIterator::ValueIterator(const ValueIterator& other)
+    : ValueIteratorBase(other) {}
+
+ValueIterator& ValueIterator::operator=(const SelfType& other) {
+  copy(other);
+  return *this;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <sstream>
+#include <utility>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+#include <cpptl/conststring.h>
+#endif
+#include <cstddef> // size_t
+#include <algorithm> // min()
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json {
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+const unsigned char& kNullRef = kNull[0];
+const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+const Value& Value::nullRef = null;
+
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+#if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
+const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
+const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  return d >= min && d <= max;
+}
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value) {
+  return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
+}
+
+template <typename T> static inline double integerToDouble(T value) {
+  return static_cast<double>(value);
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ *              length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ *               computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char* duplicateStringValue(const char* value,
+                                         size_t length) {
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  if (length >= (size_t)Value::maxInt)
+    length = Value::maxInt - 1;
+
+  char* newString = static_cast<char*>(malloc(length + 1));
+  if (newString == NULL) {
+    throwRuntimeError(
+        "in Json::Value::duplicateStringValue(): "
+        "Failed to allocate string value buffer");
+  }
+  memcpy(newString, value, length);
+  newString[length] = 0;
+  return newString;
+}
+
+/* Record the length as a prefix.
+ */
+static inline char* duplicateAndPrefixStringValue(
+    const char* value,
+    unsigned int length)
+{
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
+                      "in Json::Value::duplicateAndPrefixStringValue(): "
+                      "length too big for prefixing");
+  unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
+  char* newString = static_cast<char*>(malloc(actualLength));
+  if (newString == 0) {
+    throwRuntimeError(
+        "in Json::Value::duplicateAndPrefixStringValue(): "
+        "Failed to allocate string value buffer");
+  }
+  *reinterpret_cast<unsigned*>(newString) = length;
+  memcpy(newString + sizeof(unsigned), value, length);
+  newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
+  return newString;
+}
+inline static void decodePrefixedString(
+    bool isPrefixed, char const* prefixed,
+    unsigned* length, char const** value)
+{
+  if (!isPrefixed) {
+    *length = static_cast<unsigned>(strlen(prefixed));
+    *value = prefixed;
+  } else {
+    *length = *reinterpret_cast<unsigned const*>(prefixed);
+    *value = prefixed + sizeof(unsigned);
+  }
+}
+/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
+ */
+static inline void releaseStringValue(char* value) { free(value); }
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+Exception::Exception(std::string const& msg)
+  : msg_(msg)
+{}
+Exception::~Exception() throw()
+{}
+char const* Exception::what() const throw()
+{
+  return msg_.c_str();
+}
+RuntimeError::RuntimeError(std::string const& msg)
+  : Exception(msg)
+{}
+LogicError::LogicError(std::string const& msg)
+  : Exception(msg)
+{}
+void throwRuntimeError(std::string const& msg)
+{
+  throw RuntimeError(msg);
+}
+void throwLogicError(std::string const& msg)
+{
+  throw LogicError(msg);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() : comment_(0) {}
+
+Value::CommentInfo::~CommentInfo() {
+  if (comment_)
+    releaseStringValue(comment_);
+}
+
+void Value::CommentInfo::setComment(const char* text, size_t len) {
+  if (comment_) {
+    releaseStringValue(comment_);
+    comment_ = 0;
+  }
+  JSON_ASSERT(text != 0);
+  JSON_ASSERT_MESSAGE(
+      text[0] == '\0' || text[0] == '/',
+      "in Json::Value::setComment(): Comments must start with /");
+  // It seems that /**/ style comments are acceptable as well.
+  comment_ = duplicateStringValue(text, len);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+// Notes: policy_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
+
+Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
+    : cstr_(str) {
+  // allocate != duplicate
+  storage_.policy_ = allocate & 0x3;
+  storage_.length_ = ulength & 0x3FFFFFFF;
+}
+
+Value::CZString::CZString(const CZString& other)
+    : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
+                ? duplicateStringValue(other.cstr_, other.storage_.length_)
+                : other.cstr_) {
+  storage_.policy_ = (other.cstr_
+                 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
+                     ? noDuplication : duplicate)
+                 : static_cast<DuplicationPolicy>(other.storage_.policy_));
+  storage_.length_ = other.storage_.length_;
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+Value::CZString::CZString(CZString&& other)
+  : cstr_(other.cstr_), index_(other.index_) {
+  other.cstr_ = nullptr;
+}
+#endif
+
+Value::CZString::~CZString() {
+  if (cstr_ && storage_.policy_ == duplicate)
+    releaseStringValue(const_cast<char*>(cstr_));
+}
+
+void Value::CZString::swap(CZString& other) {
+  std::swap(cstr_, other.cstr_);
+  std::swap(index_, other.index_);
+}
+
+Value::CZString& Value::CZString::operator=(CZString other) {
+  swap(other);
+  return *this;
+}
+
+bool Value::CZString::operator<(const CZString& other) const {
+  if (!cstr_) return index_ < other.index_;
+  //return strcmp(cstr_, other.cstr_) < 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  unsigned min_len = std::min(this_len, other_len);
+  int comp = memcmp(this->cstr_, other.cstr_, min_len);
+  if (comp < 0) return true;
+  if (comp > 0) return false;
+  return (this_len < other_len);
+}
+
+bool Value::CZString::operator==(const CZString& other) const {
+  if (!cstr_) return index_ == other.index_;
+  //return strcmp(cstr_, other.cstr_) == 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  if (this_len != other_len) return false;
+  int comp = memcmp(this->cstr_, other.cstr_, this_len);
+  return comp == 0;
+}
+
+ArrayIndex Value::CZString::index() const { return index_; }
+
+//const char* Value::CZString::c_str() const { return cstr_; }
+const char* Value::CZString::data() const { return cstr_; }
+unsigned Value::CZString::length() const { return storage_.length_; }
+bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType vtype) {
+  initBasic(vtype);
+  switch (vtype) {
+  case nullValue:
+    break;
+  case intValue:
+  case uintValue:
+    value_.int_ = 0;
+    break;
+  case realValue:
+    value_.real_ = 0.0;
+    break;
+  case stringValue:
+    value_.string_ = 0;
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues();
+    break;
+  case booleanValue:
+    value_.bool_ = false;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+Value::Value(Int value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+
+Value::Value(UInt value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+Value::Value(UInt64 value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value) {
+  initBasic(realValue);
+  value_.real_ = value;
+}
+
+Value::Value(const char* value) {
+  initBasic(stringValue, true);
+  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
+}
+
+Value::Value(const char* beginValue, const char* endValue) {
+  initBasic(stringValue, true);
+  value_.string_ =
+      duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
+}
+
+Value::Value(const std::string& value) {
+  initBasic(stringValue, true);
+  value_.string_ =
+      duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
+}
+
+Value::Value(const StaticString& value) {
+  initBasic(stringValue);
+  value_.string_ = const_cast<char*>(value.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value::Value(const CppTL::ConstString& value) {
+  initBasic(stringValue, true);
+  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
+}
+#endif
+
+Value::Value(bool value) {
+  initBasic(booleanValue);
+  value_.bool_ = value;
+}
+
+Value::Value(Value const& other)
+    : type_(other.type_), allocated_(false)
+      ,
+      comments_(0), start_(other.start_), limit_(other.limit_)
+{
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    value_ = other.value_;
+    break;
+  case stringValue:
+    if (other.value_.string_ && other.allocated_) {
+      unsigned len;
+      char const* str;
+      decodePrefixedString(other.allocated_, other.value_.string_,
+          &len, &str);
+      value_.string_ = duplicateAndPrefixStringValue(str, len);
+      allocated_ = true;
+    } else {
+      value_.string_ = other.value_.string_;
+      allocated_ = false;
+    }
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues(*other.value_.map_);
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  if (other.comments_) {
+    comments_ = new CommentInfo[numberOfCommentPlacement];
+    for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
+      const CommentInfo& otherComment = other.comments_[comment];
+      if (otherComment.comment_)
+        comments_[comment].setComment(
+            otherComment.comment_, strlen(otherComment.comment_));
+    }
+  }
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+// Move constructor
+Value::Value(Value&& other) {
+  initBasic(nullValue);
+  swap(other);
+}
+#endif
+
+Value::~Value() {
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    break;
+  case stringValue:
+    if (allocated_)
+      releaseStringValue(value_.string_);
+    break;
+  case arrayValue:
+  case objectValue:
+    delete value_.map_;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+
+  if (comments_)
+    delete[] comments_;
+}
+
+Value& Value::operator=(Value other) {
+  swap(other);
+  return *this;
+}
+
+void Value::swapPayload(Value& other) {
+  ValueType temp = type_;
+  type_ = other.type_;
+  other.type_ = temp;
+  std::swap(value_, other.value_);
+  int temp2 = allocated_;
+  allocated_ = other.allocated_;
+  other.allocated_ = temp2 & 0x1;
+}
+
+void Value::swap(Value& other) {
+  swapPayload(other);
+  std::swap(comments_, other.comments_);
+  std::swap(start_, other.start_);
+  std::swap(limit_, other.limit_);
+}
+
+ValueType Value::type() const { return type_; }
+
+int Value::compare(const Value& other) const {
+  if (*this < other)
+    return -1;
+  if (*this > other)
+    return 1;
+  return 0;
+}
+
+bool Value::operator<(const Value& other) const {
+  int typeDelta = type_ - other.type_;
+  if (typeDelta)
+    return typeDelta < 0 ? true : false;
+  switch (type_) {
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ < other.value_.int_;
+  case uintValue:
+    return value_.uint_ < other.value_.uint_;
+  case realValue:
+    return value_.real_ < other.value_.real_;
+  case booleanValue:
+    return value_.bool_ < other.value_.bool_;
+  case stringValue:
+  {
+    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
+      if (other.value_.string_) return true;
+      else return false;
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+    unsigned min_len = std::min(this_len, other_len);
+    int comp = memcmp(this_str, other_str, min_len);
+    if (comp < 0) return true;
+    if (comp > 0) return false;
+    return (this_len < other_len);
+  }
+  case arrayValue:
+  case objectValue: {
+    int delta = int(value_.map_->size() - other.value_.map_->size());
+    if (delta)
+      return delta < 0;
+    return (*value_.map_) < (*other.value_.map_);
+  }
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator<=(const Value& other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value& other) const { return !(*this < other); }
+
+bool Value::operator>(const Value& other) const { return other < *this; }
+
+bool Value::operator==(const Value& other) const {
+  // if ( type_ != other.type_ )
+  // GCC 2.95.3 says:
+  // attempt to take address of bit-field structure member `Json::Value::type_'
+  // Beats me, but a temp solves the problem.
+  int temp = other.type_;
+  if (type_ != temp)
+    return false;
+  switch (type_) {
+  case nullValue:
+    return true;
+  case intValue:
+    return value_.int_ == other.value_.int_;
+  case uintValue:
+    return value_.uint_ == other.value_.uint_;
+  case realValue:
+    return value_.real_ == other.value_.real_;
+  case booleanValue:
+    return value_.bool_ == other.value_.bool_;
+  case stringValue:
+  {
+    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
+      return (value_.string_ == other.value_.string_);
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+    if (this_len != other_len) return false;
+    int comp = memcmp(this_str, other_str, this_len);
+    return comp == 0;
+  }
+  case arrayValue:
+  case objectValue:
+    return value_.map_->size() == other.value_.map_->size() &&
+           (*value_.map_) == (*other.value_.map_);
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator!=(const Value& other) const { return !(*this == other); }
+
+const char* Value::asCString() const {
+  JSON_ASSERT_MESSAGE(type_ == stringValue,
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == 0) return 0;
+  unsigned this_len;
+  char const* this_str;
+  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  return this_str;
+}
+
+bool Value::getString(char const** str, char const** cend) const {
+  if (type_ != stringValue) return false;
+  if (value_.string_ == 0) return false;
+  unsigned length;
+  decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
+  *cend = *str + length;
+  return true;
+}
+
+std::string Value::asString() const {
+  switch (type_) {
+  case nullValue:
+    return "";
+  case stringValue:
+  {
+    if (value_.string_ == 0) return "";
+    unsigned this_len;
+    char const* this_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    return std::string(this_str, this_len);
+  }
+  case booleanValue:
+    return value_.bool_ ? "true" : "false";
+  case intValue:
+    return valueToString(value_.int_);
+  case uintValue:
+    return valueToString(value_.uint_);
+  case realValue:
+    return valueToString(value_.real_);
+  default:
+    JSON_FAIL_MESSAGE("Type is not convertible to string");
+  }
+}
+
+#ifdef JSON_USE_CPPTL
+CppTL::ConstString Value::asConstString() const {
+  unsigned len;
+  char const* str;
+  decodePrefixedString(allocated_, value_.string_,
+      &len, &str);
+  return CppTL::ConstString(str, len);
+}
+#endif
+
+Value::Int Value::asInt() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+    return Int(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+    return Int(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+                        "double out of Int range");
+    return Int(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+    return UInt(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+    return UInt(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+                        "double out of UInt range");
+    return UInt(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const {
+  switch (type_) {
+  case intValue:
+    return Int64(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+    return Int64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+                        "double out of Int64 range");
+    return Int64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+    return UInt64(value_.int_);
+  case uintValue:
+    return UInt64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+                        "double out of UInt64 range");
+    return UInt64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const {
+#if defined(JSON_NO_INT64)
+  return asInt();
+#else
+  return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const {
+#if defined(JSON_NO_INT64)
+  return asUInt();
+#else
+  return asUInt64();
+#endif
+}
+
+double Value::asDouble() const {
+  switch (type_) {
+  case intValue:
+    return static_cast<double>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<double>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return value_.real_;
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0 : 0.0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const {
+  switch (type_) {
+  case intValue:
+    return static_cast<float>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<float>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return static_cast<float>(value_.real_);
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0f : 0.0f;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const {
+  switch (type_) {
+  case booleanValue:
+    return value_.bool_;
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ ? true : false;
+  case uintValue:
+    return value_.uint_ ? true : false;
+  case realValue:
+    // This is kind of strange. Not recommended.
+    return (value_.real_ != 0.0) ? true : false;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+  switch (other) {
+  case nullValue:
+    return (isNumeric() && asDouble() == 0.0) ||
+           (type_ == booleanValue && value_.bool_ == false) ||
+           (type_ == stringValue && asString() == "") ||
+           (type_ == arrayValue && value_.map_->size() == 0) ||
+           (type_ == objectValue && value_.map_->size() == 0) ||
+           type_ == nullValue;
+  case intValue:
+    return isInt() ||
+           (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
+           type_ == booleanValue || type_ == nullValue;
+  case uintValue:
+    return isUInt() ||
+           (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
+           type_ == booleanValue || type_ == nullValue;
+  case realValue:
+    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+  case booleanValue:
+    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+  case stringValue:
+    return isNumeric() || type_ == booleanValue || type_ == stringValue ||
+           type_ == nullValue;
+  case arrayValue:
+    return type_ == arrayValue || type_ == nullValue;
+  case objectValue:
+    return type_ == objectValue || type_ == nullValue;
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return false;
+}
+
+/// Number of values in array or object
+ArrayIndex Value::size() const {
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+  case stringValue:
+    return 0;
+  case arrayValue: // size of the array is highest index + 1
+    if (!value_.map_->empty()) {
+      ObjectValues::const_iterator itLast = value_.map_->end();
+      --itLast;
+      return (*itLast).first.index() + 1;
+    }
+    return 0;
+  case objectValue:
+    return ArrayIndex(value_.map_->size());
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return 0; // unreachable;
+}
+
+bool Value::empty() const {
+  if (isNull() || isArray() || isObject())
+    return size() == 0u;
+  else
+    return false;
+}
+
+bool Value::operator!() const { return isNull(); }
+
+void Value::clear() {
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
+                          type_ == objectValue,
+                      "in Json::Value::clear(): requires complex value");
+  start_ = 0;
+  limit_ = 0;
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    value_.map_->clear();
+    break;
+  default:
+    break;
+  }
+}
+
+void Value::resize(ArrayIndex newSize) {
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+                      "in Json::Value::resize(): requires arrayValue");
+  if (type_ == nullValue)
+    *this = Value(arrayValue);
+  ArrayIndex oldSize = size();
+  if (newSize == 0)
+    clear();
+  else if (newSize > oldSize)
+    (*this)[newSize - 1];
+  else {
+    for (ArrayIndex index = newSize; index < oldSize; ++index) {
+      value_.map_->erase(index);
+    }
+    assert(size() == newSize);
+  }
+}
+
+Value& Value::operator[](ArrayIndex index) {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == arrayValue,
+      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+  if (type_ == nullValue)
+    *this = Value(arrayValue);
+  CZString key(index);
+  ObjectValues::iterator it = value_.map_->lower_bound(key);
+  if (it != value_.map_->end() && (*it).first == key)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(key, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  return (*it).second;
+}
+
+Value& Value::operator[](int index) {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index): index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+const Value& Value::operator[](ArrayIndex index) const {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == arrayValue,
+      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+  if (type_ == nullValue)
+    return nullRef;
+  CZString key(index);
+  ObjectValues::const_iterator it = value_.map_->find(key);
+  if (it == value_.map_->end())
+    return nullRef;
+  return (*it).second;
+}
+
+const Value& Value::operator[](int index) const {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index) const: index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+void Value::initBasic(ValueType vtype, bool allocated) {
+  type_ = vtype;
+  allocated_ = allocated;
+  comments_ = 0;
+  start_ = 0;
+  limit_ = 0;
+}
+
+// Access an object value by name, create a null member if it does not exist.
+// @pre Type of '*this' is object or null.
+// @param key is null-terminated.
+Value& Value::resolveReference(const char* key) {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::resolveReference(): requires objectValue");
+  if (type_ == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(
+      key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
+  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+// @param key is not null-terminated.
+Value& Value::resolveReference(char const* key, char const* cend)
+{
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::resolveReference(key, end): requires objectValue");
+  if (type_ == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(
+      key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
+  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+Value Value::get(ArrayIndex index, const Value& defaultValue) const {
+  const Value* value = &((*this)[index]);
+  return value == &nullRef ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+Value const* Value::find(char const* key, char const* cend) const
+{
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::find(key, end, found): requires objectValue or nullValue");
+  if (type_ == nullValue) return NULL;
+  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
+  ObjectValues::const_iterator it = value_.map_->find(actualKey);
+  if (it == value_.map_->end()) return NULL;
+  return &(*it).second;
+}
+const Value& Value::operator[](const char* key) const
+{
+  Value const* found = find(key, key + strlen(key));
+  if (!found) return nullRef;
+  return *found;
+}
+Value const& Value::operator[](std::string const& key) const
+{
+  Value const* found = find(key.data(), key.data() + key.length());
+  if (!found) return nullRef;
+  return *found;
+}
+
+Value& Value::operator[](const char* key) {
+  return resolveReference(key, key + strlen(key));
+}
+
+Value& Value::operator[](const std::string& key) {
+  return resolveReference(key.data(), key.data() + key.length());
+}
+
+Value& Value::operator[](const StaticString& key) {
+  return resolveReference(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value& Value::operator[](const CppTL::ConstString& key) {
+  return resolveReference(key.c_str(), key.end_c_str());
+}
+Value const& Value::operator[](CppTL::ConstString const& key) const
+{
+  Value const* found = find(key.c_str(), key.end_c_str());
+  if (!found) return nullRef;
+  return *found;
+}
+#endif
+
+Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+
+Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
+{
+  Value const* found = find(key, cend);
+  return !found ? defaultValue : *found;
+}
+Value Value::get(char const* key, Value const& defaultValue) const
+{
+  return get(key, key + strlen(key), defaultValue);
+}
+Value Value::get(std::string const& key, Value const& defaultValue) const
+{
+  return get(key.data(), key.data() + key.length(), defaultValue);
+}
+
+
+bool Value::removeMember(const char* key, const char* cend, Value* removed)
+{
+  if (type_ != objectValue) {
+    return false;
+  }
+  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
+  ObjectValues::iterator it = value_.map_->find(actualKey);
+  if (it == value_.map_->end())
+    return false;
+  *removed = it->second;
+  value_.map_->erase(it);
+  return true;
+}
+bool Value::removeMember(const char* key, Value* removed)
+{
+  return removeMember(key, key + strlen(key), removed);
+}
+bool Value::removeMember(std::string const& key, Value* removed)
+{
+  return removeMember(key.data(), key.data() + key.length(), removed);
+}
+Value Value::removeMember(const char* key)
+{
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+                      "in Json::Value::removeMember(): requires objectValue");
+  if (type_ == nullValue)
+    return nullRef;
+
+  Value removed;  // null
+  removeMember(key, key + strlen(key), &removed);
+  return removed; // still null if removeMember() did nothing
+}
+Value Value::removeMember(const std::string& key)
+{
+  return removeMember(key.c_str());
+}
+
+bool Value::removeIndex(ArrayIndex index, Value* removed) {
+  if (type_ != arrayValue) {
+    return false;
+  }
+  CZString key(index);
+  ObjectValues::iterator it = value_.map_->find(key);
+  if (it == value_.map_->end()) {
+    return false;
+  }
+  *removed = it->second;
+  ArrayIndex oldSize = size();
+  // shift left all items left, into the place of the "removed"
+  for (ArrayIndex i = index; i < (oldSize - 1); ++i){
+    CZString keey(i);
+    (*value_.map_)[keey] = (*this)[i + 1];
+  }
+  // erase the last one ("leftover")
+  CZString keyLast(oldSize - 1);
+  ObjectValues::iterator itLast = value_.map_->find(keyLast);
+  value_.map_->erase(itLast);
+  return true;
+}
+
+#ifdef JSON_USE_CPPTL
+Value Value::get(const CppTL::ConstString& key,
+                 const Value& defaultValue) const {
+  return get(key.c_str(), key.end_c_str(), defaultValue);
+}
+#endif
+
+bool Value::isMember(char const* key, char const* cend) const
+{
+  Value const* value = find(key, cend);
+  return NULL != value;
+}
+bool Value::isMember(char const* key) const
+{
+  return isMember(key, key + strlen(key));
+}
+bool Value::isMember(std::string const& key) const
+{
+  return isMember(key.data(), key.data() + key.length());
+}
+
+#ifdef JSON_USE_CPPTL
+bool Value::isMember(const CppTL::ConstString& key) const {
+  return isMember(key.c_str(), key.end_c_str());
+}
+#endif
+
+Value::Members Value::getMemberNames() const {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::getMemberNames(), value must be objectValue");
+  if (type_ == nullValue)
+    return Value::Members();
+  Members members;
+  members.reserve(value_.map_->size());
+  ObjectValues::const_iterator it = value_.map_->begin();
+  ObjectValues::const_iterator itEnd = value_.map_->end();
+  for (; it != itEnd; ++it) {
+    members.push_back(std::string((*it).first.data(),
+                                  (*it).first.length()));
+  }
+  return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames
+// Value::enumMemberNames() const
+//{
+//   if ( type_ == objectValue )
+//   {
+//      return CppTL::Enum::any(  CppTL::Enum::transform(
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+//         MemberNamesTransform() ) );
+//   }
+//   return EnumMemberNames();
+//}
+//
+//
+// EnumValues
+// Value::enumValues() const
+//{
+//   if ( type_ == objectValue  ||  type_ == arrayValue )
+//      return CppTL::Enum::anyValues( *(value_.map_),
+//                                     CppTL::Type<const Value &>() );
+//   return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d) {
+  double integral_part;
+  return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type_ == nullValue; }
+
+bool Value::isBool() const { return type_ == booleanValue; }
+
+bool Value::isInt() const {
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= minInt && value_.int_ <= maxInt;
+  case uintValue:
+    return value_.uint_ <= UInt(maxInt);
+  case realValue:
+    return value_.real_ >= minInt && value_.real_ <= maxInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isUInt() const {
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+  case uintValue:
+    return value_.uint_ <= maxUInt;
+  case realValue:
+    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type_) {
+  case intValue:
+    return true;
+  case uintValue:
+    return value_.uint_ <= UInt64(maxInt64);
+  case realValue:
+    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= double(minInt64) &&
+           value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isUInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= 0;
+  case uintValue:
+    return true;
+  case realValue:
+    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isIntegral() const {
+#if defined(JSON_HAS_INT64)
+  return isInt64() || isUInt64();
+#else
+  return isInt() || isUInt();
+#endif
+}
+
+bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
+
+bool Value::isNumeric() const { return isIntegral() || isDouble(); }
+
+bool Value::isString() const { return type_ == stringValue; }
+
+bool Value::isArray() const { return type_ == arrayValue; }
+
+bool Value::isObject() const { return type_ == objectValue; }
+
+void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
+  if (!comments_)
+    comments_ = new CommentInfo[numberOfCommentPlacement];
+  if ((len > 0) && (comment[len-1] == '\n')) {
+    // Always discard trailing newline, to aid indentation.
+    len -= 1;
+  }
+  comments_[placement].setComment(comment, len);
+}
+
+void Value::setComment(const char* comment, CommentPlacement placement) {
+  setComment(comment, strlen(comment), placement);
+}
+
+void Value::setComment(const std::string& comment, CommentPlacement placement) {
+  setComment(comment.c_str(), comment.length(), placement);
+}
+
+bool Value::hasComment(CommentPlacement placement) const {
+  return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+std::string Value::getComment(CommentPlacement placement) const {
+  if (hasComment(placement))
+    return comments_[placement].comment_;
+  return "";
+}
+
+void Value::setOffsetStart(size_t start) { start_ = start; }
+
+void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
+
+size_t Value::getOffsetStart() const { return start_; }
+
+size_t Value::getOffsetLimit() const { return limit_; }
+
+std::string Value::toStyledString() const {
+  StyledWriter writer;
+  return writer.write(*this);
+}
+
+Value::const_iterator Value::begin() const {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return const_iterator();
+}
+
+Value::const_iterator Value::end() const {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return const_iterator();
+}
+
+Value::iterator Value::begin() {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+Value::iterator Value::end() {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+
+PathArgument::PathArgument(ArrayIndex index)
+    : key_(), index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char* key)
+    : key_(key), index_(), kind_(kindKey) {}
+
+PathArgument::PathArgument(const std::string& key)
+    : key_(key.c_str()), index_(), kind_(kindKey) {}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const std::string& path,
+           const PathArgument& a1,
+           const PathArgument& a2,
+           const PathArgument& a3,
+           const PathArgument& a4,
+           const PathArgument& a5) {
+  InArgs in;
+  in.push_back(&a1);
+  in.push_back(&a2);
+  in.push_back(&a3);
+  in.push_back(&a4);
+  in.push_back(&a5);
+  makePath(path, in);
+}
+
+void Path::makePath(const std::string& path, const InArgs& in) {
+  const char* current = path.c_str();
+  const char* end = current + path.length();
+  InArgs::const_iterator itInArg = in.begin();
+  while (current != end) {
+    if (*current == '[') {
+      ++current;
+      if (*current == '%')
+        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+      else {
+        ArrayIndex index = 0;
+        for (; current != end && *current >= '0' && *current <= '9'; ++current)
+          index = index * 10 + ArrayIndex(*current - '0');
+        args_.push_back(index);
+      }
+      if (current == end || *current++ != ']')
+        invalidPath(path, int(current - path.c_str()));
+    } else if (*current == '%') {
+      addPathInArg(path, in, itInArg, PathArgument::kindKey);
+      ++current;
+    } else if (*current == '.') {
+      ++current;
+    } else {
+      const char* beginName = current;
+      while (current != end && !strchr("[.", *current))
+        ++current;
+      args_.push_back(std::string(beginName, current));
+    }
+  }
+}
+
+void Path::addPathInArg(const std::string& /*path*/,
+                        const InArgs& in,
+                        InArgs::const_iterator& itInArg,
+                        PathArgument::Kind kind) {
+  if (itInArg == in.end()) {
+    // Error: missing argument %d
+  } else if ((*itInArg)->kind_ != kind) {
+    // Error: bad argument type
+  } else {
+    args_.push_back(**itInArg);
+  }
+}
+
+void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
+  // Error: invalid path.
+}
+
+const Value& Path::resolve(const Value& root) const {
+  const Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
+        // Error: unable to resolve path (array value expected at position...
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: unable to resolve path (object value expected at position...)
+      }
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullRef) {
+        // Error: unable to resolve path (object has no member named '' at
+        // position...)
+      }
+    }
+  }
+  return *node;
+}
+
+Value Path::resolve(const Value& root, const Value& defaultValue) const {
+  const Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_))
+        return defaultValue;
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject())
+        return defaultValue;
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullRef)
+        return defaultValue;
+    }
+  }
+  return *node;
+}
+
+Value& Path::make(Value& root) const {
+  Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray()) {
+        // Error: node is not an array at position ...
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: node is not an object at position...
+      }
+      node = &((*node)[arg.key_]);
+    }
+  }
+  return *node;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/writer.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <set>
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
+#include <float.h>
+#define isfinite _finite
+#elif defined(__sun) && defined(__SVR4) //Solaris
+#if !defined(isfinite)
+#include <ieeefp.h>
+#define isfinite finite
+#endif
+#elif defined(_AIX)
+#if !defined(isfinite)
+#include <math.h>
+#define isfinite finite
+#endif
+#elif defined(__hpux)
+#if !defined(isfinite)
+#if defined(__ia64) && !defined(finite)
+#define isfinite(x) ((sizeof(x) == sizeof(float) ? \
+                     _Isfinitef(x) : _IsFinite(x)))
+#else
+#include <math.h>
+#define isfinite finite
+#endif
+#endif
+#else
+#include <cmath>
+#if !(defined(__QNXNTO__)) // QNX already defines isfinite
+#define isfinite std::isfinite
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#define snprintf std::snprintf
+#endif
+
+#if defined(__BORLANDC__)  
+#include <float.h>
+#define isfinite _finite
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
+#else
+typedef std::auto_ptr<StreamWriter>   StreamWriterPtr;
+#endif
+
+static bool containsControlCharacter(const char* str) {
+  while (*str) {
+    if (isControlCharacter(*(str++)))
+      return true;
+  }
+  return false;
+}
+
+static bool containsControlCharacter0(const char* str, unsigned len) {
+  char const* end = str + len;
+  while (end != str) {
+    if (isControlCharacter(*str) || 0==*str)
+      return true;
+    ++str;
+  }
+  return false;
+}
+
+std::string valueToString(LargestInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  if (value == Value::minLargestInt) {
+    uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
+    *--current = '-';
+  } else if (value < 0) {
+    uintToString(LargestUInt(-value), current);
+    *--current = '-';
+  } else {
+    uintToString(LargestUInt(value), current);
+  }
+  assert(current >= buffer);
+  return current;
+}
+
+std::string valueToString(LargestUInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  uintToString(value, current);
+  assert(current >= buffer);
+  return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+std::string valueToString(Int value) {
+  return valueToString(LargestInt(value));
+}
+
+std::string valueToString(UInt value) {
+  return valueToString(LargestUInt(value));
+}
+
+#endif // # if defined(JSON_HAS_INT64)
+
+std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {
+  // Allocate a buffer that is more than large enough to store the 16 digits of
+  // precision requested below.
+  char buffer[32];
+  int len = -1;
+
+  char formatString[6];
+  sprintf(formatString, "%%.%dg", precision);
+
+  // Print into the buffer. We need not request the alternative representation
+  // that always has a decimal point because JSON doesn't distingish the
+  // concepts of reals and integers.
+  if (isfinite(value)) {
+    len = snprintf(buffer, sizeof(buffer), formatString, value);
+  } else {
+    // IEEE standard states that NaN values will not compare to themselves
+    if (value != value) {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
+    } else if (value < 0) {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
+    } else {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
+    }
+    // For those, we do not need to call fixNumLoc, but it is fast.
+  }
+  assert(len >= 0);
+  fixNumericLocale(buffer, buffer + len);
+  return buffer;
+}
+
+std::string valueToString(double value) { return valueToString(value, false, 17); }
+
+std::string valueToString(bool value) { return value ? "true" : "false"; }
+
+std::string valueToQuotedString(const char* value) {
+  if (value == NULL)
+    return "";
+  // Not sure how to handle unicode...
+  if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
+      !containsControlCharacter(value))
+    return std::string("\"") + value + "\"";
+  // We have to walk value and escape any special characters.
+  // Appending to std::string is not efficient, but this should be rare.
+  // (Note: forward slashes are *not* rare, but I am not escaping them.)
+  std::string::size_type maxsize =
+      strlen(value) * 2 + 3; // allescaped+quotes+NULL
+  std::string result;
+  result.reserve(maxsize); // to avoid lots of mallocs
+  result += "\"";
+  for (const char* c = value; *c != 0; ++c) {
+    switch (*c) {
+    case '\"':
+      result += "\\\"";
+      break;
+    case '\\':
+      result += "\\\\";
+      break;
+    case '\b':
+      result += "\\b";
+      break;
+    case '\f':
+      result += "\\f";
+      break;
+    case '\n':
+      result += "\\n";
+      break;
+    case '\r':
+      result += "\\r";
+      break;
+    case '\t':
+      result += "\\t";
+      break;
+    // case '/':
+    // Even though \/ is considered a legal escape in JSON, a bare
+    // slash is also legal, so I see no reason to escape it.
+    // (I hope I am not misunderstanding something.
+    // blep notes: actually escaping \/ may be useful in javascript to avoid </
+    // sequence.
+    // Should add a flag to allow this compatibility mode and prevent this
+    // sequence from occurring.
+    default:
+      if (isControlCharacter(*c)) {
+        std::ostringstream oss;
+        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+            << std::setw(4) << static_cast<int>(*c);
+        result += oss.str();
+      } else {
+        result += *c;
+      }
+      break;
+    }
+  }
+  result += "\"";
+  return result;
+}
+
+// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
+static char const* strnpbrk(char const* s, char const* accept, size_t n) {
+  assert((s || !n) && accept);
+
+  char const* const end = s + n;
+  for (char const* cur = s; cur < end; ++cur) {
+    int const c = *cur;
+    for (char const* a = accept; *a; ++a) {
+      if (*a == c) {
+        return cur;
+      }
+    }
+  }
+  return NULL;
+}
+static std::string valueToQuotedStringN(const char* value, unsigned length) {
+  if (value == NULL)
+    return "";
+  // Not sure how to handle unicode...
+  if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
+      !containsControlCharacter0(value, length))
+    return std::string("\"") + value + "\"";
+  // We have to walk value and escape any special characters.
+  // Appending to std::string is not efficient, but this should be rare.
+  // (Note: forward slashes are *not* rare, but I am not escaping them.)
+  std::string::size_type maxsize =
+      length * 2 + 3; // allescaped+quotes+NULL
+  std::string result;
+  result.reserve(maxsize); // to avoid lots of mallocs
+  result += "\"";
+  char const* end = value + length;
+  for (const char* c = value; c != end; ++c) {
+    switch (*c) {
+    case '\"':
+      result += "\\\"";
+      break;
+    case '\\':
+      result += "\\\\";
+      break;
+    case '\b':
+      result += "\\b";
+      break;
+    case '\f':
+      result += "\\f";
+      break;
+    case '\n':
+      result += "\\n";
+      break;
+    case '\r':
+      result += "\\r";
+      break;
+    case '\t':
+      result += "\\t";
+      break;
+    // case '/':
+    // Even though \/ is considered a legal escape in JSON, a bare
+    // slash is also legal, so I see no reason to escape it.
+    // (I hope I am not misunderstanding something.)
+    // blep notes: actually escaping \/ may be useful in javascript to avoid </
+    // sequence.
+    // Should add a flag to allow this compatibility mode and prevent this
+    // sequence from occurring.
+    default:
+      if ((isControlCharacter(*c)) || (*c == 0)) {
+        std::ostringstream oss;
+        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+            << std::setw(4) << static_cast<int>(*c);
+        result += oss.str();
+      } else {
+        result += *c;
+      }
+      break;
+    }
+  }
+  result += "\"";
+  return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+    : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
+      omitEndingLineFeed_(false) {}
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+std::string FastWriter::write(const Value& root) {
+  document_ = "";
+  writeValue(root);
+  if (!omitEndingLineFeed_)
+    document_ += "\n";
+  return document_;
+}
+
+void FastWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    if (!dropNullPlaceholders_)
+      document_ += "null";
+    break;
+  case intValue:
+    document_ += valueToString(value.asLargestInt());
+    break;
+  case uintValue:
+    document_ += valueToString(value.asLargestUInt());
+    break;
+  case realValue:
+    document_ += valueToString(value.asDouble());
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
+    break;
+  }
+  case booleanValue:
+    document_ += valueToString(value.asBool());
+    break;
+  case arrayValue: {
+    document_ += '[';
+    int size = value.size();
+    for (int index = 0; index < size; ++index) {
+      if (index > 0)
+        document_ += ',';
+      writeValue(value[index]);
+    }
+    document_ += ']';
+  } break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    document_ += '{';
+    for (Value::Members::iterator it = members.begin(); it != members.end();
+         ++it) {
+      const std::string& name = *it;
+      if (it != members.begin())
+        document_ += ',';
+      document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
+      document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+      writeValue(value[name]);
+    }
+    document_ += '}';
+  } break;
+  }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+    : rightMargin_(74), indentSize_(3), addChildValues_() {}
+
+std::string StyledWriter::write(const Value& root) {
+  document_ = "";
+  addChildValues_ = false;
+  indentString_ = "";
+  writeCommentBeforeValue(root);
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  document_ += "\n";
+  return document_;
+}
+
+void StyledWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        const std::string& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        document_ += " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledWriter::writeArrayValue(const Value& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          writeIndent();
+          writeValue(childValue);
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      document_ += "[ ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          document_ += ", ";
+        document_ += childValues_[index];
+      }
+      document_ += " ]";
+    }
+  }
+}
+
+bool StyledWriter::isMultineArray(const Value& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledWriter::pushValue(const std::string& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    document_ += value;
+}
+
+void StyledWriter::writeIndent() {
+  if (!document_.empty()) {
+    char last = document_[document_.length() - 1];
+    if (last == ' ') // already indented
+      return;
+    if (last != '\n') // Comments may add new-line
+      document_ += '\n';
+  }
+  document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const std::string& value) {
+  writeIndent();
+  document_ += value;
+}
+
+void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
+
+void StyledWriter::unindent() {
+  assert(int(indentString_.size()) >= indentSize_);
+  indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  document_ += "\n";
+  writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    document_ += *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      writeIndent();
+    ++iter;
+  }
+
+  // Comments are stripped of trailing newlines, so add one here
+  document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    document_ += " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    document_ += "\n";
+    document_ += root.getComment(commentAfter);
+    document_ += "\n";
+  }
+}
+
+bool StyledWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(std::string indentation)
+    : document_(NULL), rightMargin_(74), indentation_(indentation),
+      addChildValues_() {}
+
+void StyledStreamWriter::write(std::ostream& out, const Value& root) {
+  document_ = &out;
+  addChildValues_ = false;
+  indentString_ = "";
+  indented_ = true;
+  writeCommentBeforeValue(root);
+  if (!indented_) writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *document_ << "\n";
+  document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        const std::string& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        *document_ << " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_) writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *document_ << "[ ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *document_ << ", ";
+        *document_ << childValues_[index];
+      }
+      *document_ << " ]";
+    }
+  }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const std::string& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+  *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const std::string& value) {
+  if (!indented_) writeIndent();
+  *document_ << value;
+  indented_ = false;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_) writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *document_ << *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would include newline
+      *document_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    *document_ << ' ' << root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *document_ << root.getComment(commentAfter);
+  }
+  indented_ = false;
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+//////////////////////////
+// BuiltStyledStreamWriter
+
+/// Scoped enums are not available until C++11.
+struct CommentStyle {
+  /// Decide whether to write comments.
+  enum Enum {
+    None,  ///< Drop all comments.
+    Most,  ///< Recover odd behavior of previous versions (not implemented yet).
+    All  ///< Keep all comments.
+  };
+};
+
+struct BuiltStyledStreamWriter : public StreamWriter
+{
+  BuiltStyledStreamWriter(
+      std::string const& indentation,
+      CommentStyle::Enum cs,
+      std::string const& colonSymbol,
+      std::string const& nullSymbol,
+      std::string const& endingLineFeedSymbol,
+      bool useSpecialFloats,
+      unsigned int precision);
+  int write(Value const& root, std::ostream* sout) override;
+private:
+  void writeValue(Value const& value);
+  void writeArrayValue(Value const& value);
+  bool isMultineArray(Value const& value);
+  void pushValue(std::string const& value);
+  void writeIndent();
+  void writeWithIndent(std::string const& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(Value const& root);
+  void writeCommentAfterValueOnSameLine(Value const& root);
+  static bool hasCommentForValue(const Value& value);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::string indentString_;
+  int rightMargin_;
+  std::string indentation_;
+  CommentStyle::Enum cs_;
+  std::string colonSymbol_;
+  std::string nullSymbol_;
+  std::string endingLineFeedSymbol_;
+  bool addChildValues_ : 1;
+  bool indented_ : 1;
+  bool useSpecialFloats_ : 1;
+  unsigned int precision_;
+};
+BuiltStyledStreamWriter::BuiltStyledStreamWriter(
+      std::string const& indentation,
+      CommentStyle::Enum cs,
+      std::string const& colonSymbol,
+      std::string const& nullSymbol,
+      std::string const& endingLineFeedSymbol,
+      bool useSpecialFloats,
+      unsigned int precision)
+  : rightMargin_(74)
+  , indentation_(indentation)
+  , cs_(cs)
+  , colonSymbol_(colonSymbol)
+  , nullSymbol_(nullSymbol)
+  , endingLineFeedSymbol_(endingLineFeedSymbol)
+  , addChildValues_(false)
+  , indented_(false)
+  , useSpecialFloats_(useSpecialFloats)
+  , precision_(precision)
+{
+}
+int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
+{
+  sout_ = sout;
+  addChildValues_ = false;
+  indented_ = true;
+  indentString_ = "";
+  writeCommentBeforeValue(root);
+  if (!indented_) writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *sout_ << endingLineFeedSymbol_;
+  sout_ = NULL;
+  return 0;
+}
+void BuiltStyledStreamWriter::writeValue(Value const& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue(nullSymbol_);
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
+    break;
+  case stringValue:
+  {
+    // Is NULL is possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        std::string const& name = *it;
+        Value const& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
+        *sout_ << colonSymbol_;
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
+    if (isMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        Value const& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_) writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *sout_ << "[";
+      if (!indentation_.empty()) *sout_ << " ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *sout_ << ", ";
+        *sout_ << childValues_[index];
+      }
+      if (!indentation_.empty()) *sout_ << " ";
+      *sout_ << "]";
+    }
+  }
+}
+
+bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    Value const& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void BuiltStyledStreamWriter::pushValue(std::string const& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *sout_ << value;
+}
+
+void BuiltStyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+
+  if (!indentation_.empty()) {
+    // In this case, drop newlines too.
+    *sout_ << '\n' << indentString_;
+  }
+}
+
+void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
+  if (!indented_) writeIndent();
+  *sout_ << value;
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void BuiltStyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
+  if (cs_ == CommentStyle::None) return;
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_) writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *sout_ << *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would write extra newline
+      *sout_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
+  if (cs_ == CommentStyle::None) return;
+  if (root.hasComment(commentAfterOnSameLine))
+    *sout_ << " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *sout_ << root.getComment(commentAfter);
+  }
+}
+
+// static
+bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+///////////////
+// StreamWriter
+
+StreamWriter::StreamWriter()
+    : sout_(NULL)
+{
+}
+StreamWriter::~StreamWriter()
+{
+}
+StreamWriter::Factory::~Factory()
+{}
+StreamWriterBuilder::StreamWriterBuilder()
+{
+  setDefaults(&settings_);
+}
+StreamWriterBuilder::~StreamWriterBuilder()
+{}
+StreamWriter* StreamWriterBuilder::newStreamWriter() const
+{
+  std::string indentation = settings_["indentation"].asString();
+  std::string cs_str = settings_["commentStyle"].asString();
+  bool eyc = settings_["enableYAMLCompatibility"].asBool();
+  bool dnp = settings_["dropNullPlaceholders"].asBool();
+  bool usf = settings_["useSpecialFloats"].asBool(); 
+  unsigned int pre = settings_["precision"].asUInt();
+  CommentStyle::Enum cs = CommentStyle::All;
+  if (cs_str == "All") {
+    cs = CommentStyle::All;
+  } else if (cs_str == "None") {
+    cs = CommentStyle::None;
+  } else {
+    throwRuntimeError("commentStyle must be 'All' or 'None'");
+  }
+  std::string colonSymbol = " : ";
+  if (eyc) {
+    colonSymbol = ": ";
+  } else if (indentation.empty()) {
+    colonSymbol = ":";
+  }
+  std::string nullSymbol = "null";
+  if (dnp) {
+    nullSymbol = "";
+  }
+  if (pre > 17) pre = 17;
+  std::string endingLineFeedSymbol = "";
+  return new BuiltStyledStreamWriter(
+      indentation, cs,
+      colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
+}
+static void getValidWriterKeys(std::set<std::string>* valid_keys)
+{
+  valid_keys->clear();
+  valid_keys->insert("indentation");
+  valid_keys->insert("commentStyle");
+  valid_keys->insert("enableYAMLCompatibility");
+  valid_keys->insert("dropNullPlaceholders");
+  valid_keys->insert("useSpecialFloats");
+  valid_keys->insert("precision");
+}
+bool StreamWriterBuilder::validate(Json::Value* invalid) const
+{
+  Json::Value my_invalid;
+  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  Json::Value& inv = *invalid;
+  std::set<std::string> valid_keys;
+  getValidWriterKeys(&valid_keys);
+  Value::Members keys = settings_.getMemberNames();
+  size_t n = keys.size();
+  for (size_t i = 0; i < n; ++i) {
+    std::string const& key = keys[i];
+    if (valid_keys.find(key) == valid_keys.end()) {
+      inv[key] = settings_[key];
+    }
+  }
+  return 0u == inv.size();
+}
+Value& StreamWriterBuilder::operator[](std::string key)
+{
+  return settings_[key];
+}
+// static
+void StreamWriterBuilder::setDefaults(Json::Value* settings)
+{
+  //! [StreamWriterBuilderDefaults]
+  (*settings)["commentStyle"] = "All";
+  (*settings)["indentation"] = "\t";
+  (*settings)["enableYAMLCompatibility"] = false;
+  (*settings)["dropNullPlaceholders"] = false;
+  (*settings)["useSpecialFloats"] = false;
+  (*settings)["precision"] = 17;
+  //! [StreamWriterBuilderDefaults]
+}
+
+std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
+  std::ostringstream sout;
+  StreamWriterPtr const writer(builder.newStreamWriter());
+  writer->write(root, &sout);
+  return sout.str();
+}
+
+std::ostream& operator<<(std::ostream& sout, Value const& root) {
+  StreamWriterBuilder builder;
+  StreamWriterPtr const writer(builder.newStreamWriter());
+  writer->write(root, &sout);
+  return sout;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
diff --git a/csharp/.gitignore b/csharp/.gitignore
new file mode 100644
index 0000000..c88f741
--- /dev/null
+++ b/csharp/.gitignore
@@ -0,0 +1,36 @@
+#
+# 	Untracked directories
+#
+src/AddressBook/bin
+src/AddressBook/obj
+src/Google.Protobuf/bin/
+src/Google.Protobuf/obj/
+src/Google.Protobuf.Conformance/bin/
+src/Google.Protobuf.Conformance/obj/
+src/Google.Protobuf.Test/bin/
+src/Google.Protobuf.Test/obj/
+src/Google.Protobuf.JsonDump/bin/
+src/Google.Protobuf.JsonDump/obj/
+mono/bin
+mono/tmp
+mono/protoc
+build_output
+build_temp
+build/msbuild*.log
+lib/Microsoft.Silverlight.Testing
+lib/NUnit
+
+#
+# 	Untracked files
+#
+*.user
+*.suo
+*.nupkg
+_ReSharper.*
+*.sln.cache
+mono/TestResult.xml
+mono/.libs
+mono/*.exe
+mono/*.dll
+lib/protoc.exe
+*.ncrunch*
diff --git a/csharp/CHANGES.txt b/csharp/CHANGES.txt
new file mode 100644
index 0000000..a87cd4d
--- /dev/null
+++ b/csharp/CHANGES.txt
@@ -0,0 +1,148 @@
+===============================================================================
+Welcome to the C# port of Google Protocol Buffers, written by Jon Skeet
+(skeet@pobox.com) based on the work of many talented people.
+
+===============================================================================
+RELEASE NOTES - Code imported into Google's main protobuf repository
+===============================================================================
+
+Everything below note this represents history of protobuf-csharp-port project
+before the code was merged into csharp/ subtree of GitHub google/protobuf
+repository.
+Frozen legacy version of the original project is available in
+https://github.com/jskeet/protobuf-csharp-port.
+
+===============================================================================
+RELEASE NOTES - Version 2.4.1.555
+===============================================================================
+
+Changes:
+- Upgrade solution format to Visual Studio 2012.
+- Add the ability to print a builder (not just a message)
+- TextGenerator introduces a new overload of PrintTo
+- Munge protoc's error format into a VS-C#-compatible output format.
+- Work to make ProtoGen clone that acts as a protoc.exe plugin.
+- Added the AllowPartiallyTrustedCallers attribute
+- Optimized enum parsing.
+
+Fixes:
+- Fix for bug in limited input stream's Position, Introduced Position on 
+  output stream
+- Fix for writing a character to a JSON output overflows allocated buffer
+- Optimize FromBase64String to return Empty when presented with empty string.
+- Use string.Concat instead of operator to avoid potential import problems
+- Issue 81: quoting for NUnit parameters.
+- Issue 56: NuGet package is noisy
+- Issue 70: Portable library project has some invalid Nunit-based code.
+- Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily
+- Issue 84: warning CS0219: The variable `size' is assigned but never used
+
+===============================================================================
+RELEASE NOTES - Version 2.4.1.521
+===============================================================================
+
+Changes:
+- Add generated_code_attributes option, defaulted to false
+- Added support for Portable library
+- Added 'Unsafe' static type in ByteString to allow direct buffer access
+
+Fixes:
+- Issue 50: The XML serializer will fail to deserialize a message with empty 
+  child message
+- Issue 45: Use of 'item' as a field name causes AmbiguousMatchException
+- Issue 49: Generated nested static Types class should be partial
+- Issue 38: Disable CLSCompliant warnings (3021)
+- Issue 40: proto_path does not work for command-line file names
+- Issue 54: should retire all bytes in buffer (bufferSize)
+- Issue 43: Fix to correct identical 'umbrella_classname' options from trying 
+  to write to the same filename.
+
+===============================================================================
+RELEASE NOTES - Version 2.4.1.473
+===============================================================================
+
+Features:
+- Added option service_generator_type to control service generation with
+  NONE, GENERIC, INTERFACE, or IRPCDISPATCH
+- Added interfaces IRpcDispatch and IRpcServerStub to provide for blocking
+  services and implementations.
+- Added ProtoGen.exe command-line argument "--protoc_dir=" to specify the 
+  location of protoc.exe.
+- Extracted interfaces for ICodedInputStream and ICodedOutputStream to allow
+  custom implementation of writers with both speed and size optimizations.
+- Addition of the "Google.ProtoBuffers.Serialization" assembly to support
+  reading and writing messages to/from XML, JSON, IDictionary<,> and others.
+- Several performance related fixes and tweeks
+- Issue 3:	Add option to mark generated code with attribute
+- Issue 20:	Support for decorating classes [Serializable]
+- Issue 21:	Decorate fields with [deprecated=true] as [System.Obsolete]
+- Issue 22:	Reusable Builder classes
+- Issue 24:	Support for using Json/Xml formats with ICodedInputStream
+- Issue 25: Added support for NuGet packages
+- Issue 31: Upgraded protoc.exe and descriptor to 2.4.1
+
+Fixes:
+- Issue 13:	Message with Field same name as message causes uncompilable .cs
+- Issue 16:	Does not integrate well with other tooling
+- Issue 19:	Support for negative enum values
+- Issue 26:	AddRange in GeneratedBuilder iterates twice.
+- Issue 27:	Remove XML documentation output from test projects to clear 
+  warnings/errors.
+- Issue 28: Circular message dependencies result in null default values for 
+  Message fields.
+- Issue 29: Message classes generated have a public default constructor.  You
+  can disable private ctor generation with the option generate_private_ctor.
+- Issue 35: Fixed a bug in ProtoGen handling of arguments with trailing \
+- Big-endian support for float, and double on Silverlight
+- Packed and Unpacked parsing allow for all repeated, as per version 2.3
+- Fix for leaving Builder a public ctor on internal classes for use with
+  generic "where T: new()" constraints.
+
+Other:
+- Changed the code signing key to a privately held key
+- Reformatted all code and line-endings to C# defaults
+- Reworking of performance benchmarks to produce reliable results, option /v2
+- Issue 34: Silverlight assemblies are now unit tested
+
+===============================================================================
+RELEASE NOTES - Version 2.3.0.277
+===============================================================================
+
+Features:
+- Added cls_compliance option to generate attributes indicating 
+  non-CLS-compliance.
+- Added file_extension option to control the generated output file's extension.
+- Added umbrella_namespace option to place the umbrella class into a nested
+  namespace to address issues with proto files having the same name as a 
+  message it contains.
+- Added output_directory option to set the output path for the source file(s).
+- Added ignore_google_protobuf option to avoid generating code for includes 
+  from the google.protobuf package.
+- Added the LITE framework (Google.ProtoBuffersLite.dll) and the ability to
+  generate code with "option optimize_for = LITE_RUNTIME;".
+- Added ability to invoke protoc.exe from within ProtoGen.exe.
+- Upgraded to protoc.exe (2.3) compiler.
+
+Fixes:
+- Issue 9:	Class cannot be static and sealed error
+- Issue 12:	default value for enumerate fields must be filled out
+
+Other:
+- Rewrite of build using MSbuild instead of NAnt
+- Moved to NUnit Version 2.2.8.0
+- Changed to using secure .snk for releases
+
+===============================================================================
+RELEASE NOTES - Version 0.9.1
+===============================================================================
+
+Fixes:
+- issue 10:	Incorrect encoding of packed fields when serialized
+
+===============================================================================
+RELEASE NOTES - Version 0.9.0
+===============================================================================
+
+- Initial release
+
+===============================================================================
\ No newline at end of file
diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec
new file mode 100644
index 0000000..e4240da
--- /dev/null
+++ b/csharp/Google.Protobuf.Tools.nuspec
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Google.Protobuf.Tools</id>
+    <title>Google Protocol Buffers tools</title>
+    <summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
+    <description>See project site for more info.</description>
+    <version>3.0.0-beta3</version>
+    <authors>Google Inc.</authors>
+    <owners>protobuf-packages</owners>
+    <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/google/protobuf</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <releaseNotes>Tools for Protocol Buffers</releaseNotes>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
+  </metadata>
+  <files>
+    <file src="protoc\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe" />
+    <file src="protoc\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe" />
+    <file src="protoc\linux_x86\protoc" target="tools\linux_x86\protoc" />
+    <file src="protoc\linux_x64\protoc" target="tools\linux_x64\protoc" />
+    <file src="protoc\macosx_x86\protoc" target="tools\macosx_x86\protoc" />
+    <file src="protoc\macosx_x64\protoc" target="tools\macosx_x64\protoc" />
+    <file src="..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
+    <file src="..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
+  </files>
+</package>
diff --git a/csharp/README.md b/csharp/README.md
new file mode 100644
index 0000000..8c3993e
--- /dev/null
+++ b/csharp/README.md
@@ -0,0 +1,70 @@
+This directory contains the C# Protocol Buffers runtime library.
+
+Status: Beta - ready for external testing
+=========================================
+
+Usage
+=====
+
+The easiest way how to use C# protobufs is via the `Google.Protobuf`
+NuGet package. Just add the NuGet package to your VS project.
+
+Besides C# runtime library, the NuGet package also contains 
+precompiled version of `protoc.exe` and a copy of well known `.proto`
+files under the package's `tools` directory.
+
+To generate C# files from your `.proto` files, invoke `protoc` with the 
+`--csharp_out` option.
+
+Supported platforms
+===================
+
+The runtime library is built as a portable class library, supporting:
+
+- .NET 4.5
+- Windows 8
+- Windows Phone Silverlight 8
+- Windows Phone 8.1
+- .NET Core
+
+You should be able to use Protocol Buffers in Visual Studio 2012 and
+all later versions. This includes all code generated by `protoc`,
+which only uses features from C# 3 and earlier.
+
+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).
+
+Although *users* of this project are only expected to have Visual
+Studio 2012 or later, *developers* of the library are required to
+have Visual Studio 2015 or later, as the library uses C# 6 features
+in its implementation. These features have no impact when using the
+compiled code - they're only relevant when building the
+`Google.Protobuf` assembly.
+
+History of C# protobufs
+=======================
+
+This subtree was originally imported from https://github.com/jskeet/protobuf-csharp-port
+and represents the latest development version of C# protobufs, that will now be developed
+and maintained by Google. All the development will be done in open, under this repository
+(https://github.com/google/protobuf).
+
+The previous project differs from this project in a number of ways:
+
+- The old code only supported proto2; the new code only supports
+proto3 (so no unknown fields, no required/optional distinction, no
+extensions)
+- The old code was based on immutable message types and builders for
+them
+- The old code did not support maps or `oneof`
+- The old code had its own JSON representation, whereas the new code
+uses the standard protobuf JSON representation
+- The old code had no notion of the "well-known types" which have
+special support in the new code
+- The old project supported some older platforms (such as older
+versions of Silverlight) which are not currently supported in the
+new project
diff --git a/csharp/build_packages.bat b/csharp/build_packages.bat
new file mode 100644
index 0000000..1502f06
--- /dev/null
+++ b/csharp/build_packages.bat
@@ -0,0 +1,13 @@
+@rem Builds Google.Protobuf NuGet packages
+
+@rem Adjust the location of nuget.exe
+set NUGET=C:\nuget\nuget.exe
+
+@rem Build src/Google.Protobuf.sln solution in Release configuration first.
+%NUGET% pack src\Google.Protobuf\Google.Protobuf.nuspec -Symbols || goto :error
+
+goto :EOF
+
+:error
+echo Failed!
+exit /b %errorlevel%
diff --git a/csharp/buildall.sh b/csharp/buildall.sh
new file mode 100755
index 0000000..45af705
--- /dev/null
+++ b/csharp/buildall.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Use mono to build solution and run all tests.
+
+# Adjust these to reflect the location of nunit-console in your system.
+NUNIT_CONSOLE=nunit-console
+
+# The rest you can leave intact
+CONFIG=Release
+SRC=$(dirname $0)/src
+
+set -ex
+
+echo Building the solution.
+xbuild /p:Configuration=$CONFIG $SRC/Google.Protobuf.sln
+
+echo Running tests.
+$NUNIT_CONSOLE $SRC/Google.Protobuf.Test/bin/$CONFIG/Google.Protobuf.Test.dll
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
new file mode 100755
index 0000000..d979aa5
--- /dev/null
+++ b/csharp/generate_protos.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Generates C# source files from .proto files.
+# You first need to make sure protoc has been built (see instructions on
+# building protoc in root of this repository)
+
+set -ex
+
+# cd to repository root
+pushd $(dirname $0)/..
+
+# Protocol buffer compiler to use. If the PROTOC variable is set,
+# use that. Otherwise, probe for expected locations under both
+# Windows and Unix.
+if [ -z "$PROTOC" ]; then
+  # TODO(jonskeet): Use an array and a for loop instead?
+  if [ -x cmake/build/Debug/protoc.exe ]; then
+    PROTOC=cmake/build/Debug/protoc.exe
+  elif [ -x cmake/build/Release/protoc.exe ]; then
+    PROTOC=cmake/build/Release/protoc.exe
+  elif [ -x src/protoc ]; then
+    PROTOC=src/protoc
+  else
+    echo "Unable to find protocol buffer compiler."
+    exit 1
+  fi
+fi
+
+# descriptor.proto and well-known types
+$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf \
+    --csharp_opt=base_namespace=Google.Protobuf \
+    src/google/protobuf/descriptor.proto \
+    src/google/protobuf/any.proto \
+    src/google/protobuf/api.proto \
+    src/google/protobuf/duration.proto \
+    src/google/protobuf/empty.proto \
+    src/google/protobuf/field_mask.proto \
+    src/google/protobuf/source_context.proto \
+    src/google/protobuf/struct.proto \
+    src/google/protobuf/timestamp.proto \
+    src/google/protobuf/type.proto \
+    src/google/protobuf/wrappers.proto
+
+# Test protos where the namespace matches the target location
+$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf.Test \
+    --csharp_opt=base_namespace=Google.Protobuf \
+    src/google/protobuf/map_unittest_proto3.proto \
+    src/google/protobuf/unittest_proto3.proto \
+    src/google/protobuf/unittest_import_proto3.proto \
+    src/google/protobuf/unittest_import_public_proto3.proto \
+    src/google/protobuf/unittest_well_known_types.proto
+
+# Different base namespace to the protos above
+$PROTOC -Icsharp/protos --csharp_out=csharp/src/Google.Protobuf.Test \
+    --csharp_opt=base_namespace=UnitTest.Issues \
+    csharp/protos/unittest_issues.proto
+
+# AddressBook sample protos
+$PROTOC -Iexamples --csharp_out=csharp/src/AddressBook \
+    examples/addressbook.proto
+
+$PROTOC -Iconformance -Isrc --csharp_out=csharp/src/Google.Protobuf.Conformance \
+    conformance/conformance.proto
diff --git a/csharp/keys/Google.Protobuf.public.snk b/csharp/keys/Google.Protobuf.public.snk
new file mode 100644
index 0000000..59cd369
--- /dev/null
+++ b/csharp/keys/Google.Protobuf.public.snk
Binary files differ
diff --git a/csharp/keys/Google.Protobuf.snk b/csharp/keys/Google.Protobuf.snk
new file mode 100644
index 0000000..7515443
--- /dev/null
+++ b/csharp/keys/Google.Protobuf.snk
Binary files differ
diff --git a/csharp/keys/README.md b/csharp/keys/README.md
new file mode 100644
index 0000000..ede6735
--- /dev/null
+++ b/csharp/keys/README.md
@@ -0,0 +1,9 @@
+Contents
+--------
+
+- Google.Protobuf.public.snk:
+  Public key to verify strong name of Google.Protobuf assemblies.
+- Google.Protobuf.snk:
+  Signing key to provide strong name of Google.Protobuf assemblies.
+  As per [Microsoft guidance](https://msdn.microsoft.com/en-us/library/wd40t7ad(v=vs.110).aspx)
+  signing key should be checked into the repository.
diff --git a/csharp/protos/unittest_issues.proto b/csharp/protos/unittest_issues.proto
new file mode 100644
index 0000000..6c9f763
--- /dev/null
+++ b/csharp/protos/unittest_issues.proto
@@ -0,0 +1,126 @@
+syntax = "proto3";
+
+// These proto descriptors have at one time been reported as an issue or defect.
+// They are kept here to replicate the issue, and continue to verify the fix.
+
+// Issue: Non-"Google.Protobuffers" namespace will ensure that protobuffer library types are qualified
+option csharp_namespace = "UnitTest.Issues.TestProtos";
+
+package unittest_issues;
+option optimize_for = SPEED;
+
+// Issue 307: when generating doubly-nested types, any references
+// should be of the form A.Types.B.Types.C.
+message Issue307 {
+  message NestedOnce {
+    message NestedTwice {
+    }
+  }
+}
+
+// Old issue 13: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=13
+// New issue 309: https://github.com/google/protobuf/issues/309
+ 
+// message A {
+//    optional int32 _A = 1;
+// }
+
+// message B {
+//    optional int32 B_ = 1;
+// }
+
+//message AB {
+//    optional int32 a_b = 1;
+//}
+
+// Similar issue with numeric names
+// Java code failed too, so probably best for this to be a restriction.
+// See https://github.com/google/protobuf/issues/308
+// message NumberField {
+//    optional int32 _01 = 1;
+// }
+
+// issue 19 - negative enum values
+
+enum NegativeEnum {
+    NEGATIVE_ENUM_ZERO = 0;
+    FiveBelow = -5;
+    MinusOne = -1;
+}
+
+message NegativeEnumMessage {
+    NegativeEnum value = 1;
+    repeated NegativeEnum values = 2 [packed = false];
+    repeated NegativeEnum packed_values = 3 [packed=true];
+}
+
+// Issue 21: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=21
+// Decorate fields with [deprecated=true] as [System.Obsolete]
+
+message DeprecatedChild {
+}
+
+enum DeprecatedEnum {
+    DEPRECATED_ZERO = 0;
+    one = 1;
+}
+
+message DeprecatedFieldsMessage {
+    int32 PrimitiveValue = 1 [deprecated = true];
+    repeated int32 PrimitiveArray = 2 [deprecated = true];
+
+    DeprecatedChild MessageValue = 3 [deprecated = true];
+    repeated DeprecatedChild MessageArray = 4 [deprecated = true];
+
+    DeprecatedEnum EnumValue = 5 [deprecated = true];
+    repeated DeprecatedEnum EnumArray = 6 [deprecated = true];
+}
+
+// Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45
+message ItemField {
+  int32 item = 1;
+}
+
+message ReservedNames {
+  // Force a nested type called Types
+  message SomeNestedType {
+  }
+
+  int32 types = 1;
+  int32 descriptor = 2;
+}
+
+message TestJsonFieldOrdering {
+  // These fields are deliberately not declared in numeric
+  // order, and the oneof fields aren't contiguous either.
+  // This allows for reasonably robust tests of JSON output
+  // ordering.
+  // TestFieldOrderings in unittest_proto3.proto is similar,
+  // but doesn't include oneofs.
+  // TODO: Consider adding oneofs to TestFieldOrderings, although
+  // that will require fixing other tests in multiple platforms.
+  // Alternatively, consider just adding this to
+  // unittest_proto3.proto if multiple platforms want it.
+  
+  int32 plain_int32 = 4;
+
+  oneof o1 {
+    string o1_string = 2;
+    int32 o1_int32 = 5;
+  }
+  
+  string plain_string = 1;
+  
+  oneof o2 {
+    int32 o2_int32 = 6;
+    string o2_string = 3;
+  }
+  
+}
+
+message TestJsonName {
+  // Message for testing the effects for of the json_name option
+  string name = 1;
+  string description = 2 [json_name = "desc"];
+  string guid = 3 [json_name = "exid"];
+}
diff --git a/csharp/src/AddressBook/AddPerson.cs b/csharp/src/AddressBook/AddPerson.cs
new file mode 100644
index 0000000..62d1788
--- /dev/null
+++ b/csharp/src/AddressBook/AddPerson.cs
@@ -0,0 +1,132 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+

+namespace Google.Protobuf.Examples.AddressBook

+{

+    internal class AddPerson

+    {

+        /// <summary>

+        /// Builds a person based on user input

+        /// </summary>

+        private static Person PromptForAddress(TextReader input, TextWriter output)

+        {

+            Person person = new Person();

+

+            output.Write("Enter person ID: ");

+            person.Id = int.Parse(input.ReadLine());

+

+            output.Write("Enter name: ");

+            person.Name = input.ReadLine();

+

+            output.Write("Enter email address (blank for none): ");

+            string email = input.ReadLine();

+            if (email.Length > 0)

+            {

+                person.Email = email;

+            }

+

+            while (true)

+            {

+                output.Write("Enter a phone number (or leave blank to finish): ");

+                string number = input.ReadLine();

+                if (number.Length == 0)

+                {

+                    break;

+                }

+

+                Person.Types.PhoneNumber phoneNumber = new Person.Types.PhoneNumber { Number = number };

+

+                output.Write("Is this a mobile, home, or work phone? ");

+                String type = input.ReadLine();

+                switch (type)

+                {

+                    case "mobile":

+                        phoneNumber.Type = Person.Types.PhoneType.Mobile;

+                        break;

+                    case "home":

+                        phoneNumber.Type = Person.Types.PhoneType.Home;

+                        break;

+                    case "work":

+                        phoneNumber.Type = Person.Types.PhoneType.Work;

+                        break;

+                    default:

+                        output.Write("Unknown phone type. Using default.");

+                        break;

+                }

+

+                person.Phones.Add(phoneNumber);

+            }

+            return person;

+        }

+

+        /// <summary>

+        /// Entry point - loads an existing addressbook or creates a new one,

+        /// then writes it back to the file.

+        /// </summary>

+        public static int Main(string[] args)

+        {

+            if (args.Length != 1)

+            {

+                Console.Error.WriteLine("Usage:  AddPerson ADDRESS_BOOK_FILE");

+                return -1;

+            }

+

+            AddressBook addressBook;

+

+            if (File.Exists(args[0]))

+            {

+                using (Stream file = File.OpenRead(args[0]))

+                {

+                    addressBook = AddressBook.Parser.ParseFrom(file);

+                }

+            }

+            else

+            {

+                Console.WriteLine("{0}: File not found. Creating a new file.", args[0]);

+                addressBook = new AddressBook();

+            }

+

+            // Add an address.

+            addressBook.People.Add(PromptForAddress(Console.In, Console.Out));

+

+            // Write the new address book back to disk.

+            using (Stream output = File.OpenWrite(args[0]))

+            {

+                addressBook.WriteTo(output);

+            }

+            return 0;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/AddressBook/AddressBook.csproj b/csharp/src/AddressBook/AddressBook.csproj
new file mode 100644
index 0000000..8f8ca7e
--- /dev/null
+++ b/csharp/src/AddressBook/AddressBook.csproj
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>9.0.30729</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{A31F5FB2-4FF3-432A-B35B-5CD203606311}</ProjectGuid>

+    <OutputType>Exe</OutputType>

+    <AppDesignerFolder>Properties</AppDesignerFolder>

+    <RootNamespace>Google.Protobuf.Examples.AddressBook</RootNamespace>

+    <AssemblyName>AddressBook</AssemblyName>

+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

+    <FileAlignment>512</FileAlignment>

+    <StartupObject>Google.Protobuf.Examples.AddressBook.Program</StartupObject>

+    <TargetFrameworkProfile>

+    </TargetFrameworkProfile>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <Optimize>false</Optimize>

+    <OutputPath>bin\Debug</OutputPath>

+    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release</OutputPath>

+    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

+    <DefineConstants>TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="mscorlib" />

+    <Reference Include="System" />

+    <Reference Include="System.Data" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="AddPerson.cs" />

+    <Compile Include="Addressbook.cs" />

+    <Compile Include="SampleUsage.cs" />

+    <Compile Include="ListPeople.cs" />

+    <Compile Include="Program.cs" />

+    <Compile Include="Properties\AssemblyInfo.cs" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

+      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

+      <Name>Google.Protobuf</Name>

+    </ProjectReference>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="app.config" />

+  </ItemGroup>

+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs
new file mode 100644
index 0000000..362e1cb
--- /dev/null
+++ b/csharp/src/AddressBook/Addressbook.cs
@@ -0,0 +1,473 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: addressbook.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.Examples.AddressBook {
+
+  /// <summary>Holder for reflection information generated from addressbook.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class AddressbookReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for addressbook.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static AddressbookReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "ChFhZGRyZXNzYm9vay5wcm90bxIIdHV0b3JpYWwi1QEKBlBlcnNvbhIMCgRu",
+            "YW1lGAEgASgJEgoKAmlkGAIgASgFEg0KBWVtYWlsGAMgASgJEiwKBnBob25l",
+            "cxgEIAMoCzIcLnR1dG9yaWFsLlBlcnNvbi5QaG9uZU51bWJlchpHCgtQaG9u",
+            "ZU51bWJlchIOCgZudW1iZXIYASABKAkSKAoEdHlwZRgCIAEoDjIaLnR1dG9y",
+            "aWFsLlBlcnNvbi5QaG9uZVR5cGUiKwoJUGhvbmVUeXBlEgoKBk1PQklMRRAA",
+            "EggKBEhPTUUQARIICgRXT1JLEAIiLwoLQWRkcmVzc0Jvb2sSIAoGcGVvcGxl",
+            "GAEgAygLMhAudHV0b3JpYWwuUGVyc29uQlAKFGNvbS5leGFtcGxlLnR1dG9y",
+            "aWFsQhFBZGRyZXNzQm9va1Byb3Rvc6oCJEdvb2dsZS5Qcm90b2J1Zi5FeGFt",
+            "cGxlcy5BZGRyZXNzQm9va2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person), global::Google.Protobuf.Examples.AddressBook.Person.Parser, new[]{ "Name", "Id", "Email", "Phones" }, null, new[]{ typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber), global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber.Parser, new[]{ "Number", "Type" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.AddressBook), global::Google.Protobuf.Examples.AddressBook.AddressBook.Parser, new[]{ "People" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  [START messages]
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Person : pb::IMessage<Person> {
+    private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person());
+    public static pb::MessageParser<Person> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Examples.AddressBook.AddressbookReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Person() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Person(Person other) : this() {
+      name_ = other.name_;
+      id_ = other.id_;
+      email_ = other.email_;
+      phones_ = other.phones_.Clone();
+    }
+
+    public Person Clone() {
+      return new Person(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "id" field.</summary>
+    public const int IdFieldNumber = 2;
+    private int id_;
+    /// <summary>
+    ///  Unique ID number for this person.
+    /// </summary>
+    public int Id {
+      get { return id_; }
+      set {
+        id_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "email" field.</summary>
+    public const int EmailFieldNumber = 3;
+    private string email_ = "";
+    public string Email {
+      get { return email_; }
+      set {
+        email_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "phones" field.</summary>
+    public const int PhonesFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber> _repeated_phones_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber> phones_ = new pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber>();
+    public pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber> Phones {
+      get { return phones_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Person);
+    }
+
+    public bool Equals(Person other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Id != other.Id) return false;
+      if (Email != other.Email) return false;
+      if(!phones_.Equals(other.phones_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Id != 0) hash ^= Id.GetHashCode();
+      if (Email.Length != 0) hash ^= Email.GetHashCode();
+      hash ^= phones_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Id != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Id);
+      }
+      if (Email.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Email);
+      }
+      phones_.WriteTo(output, _repeated_phones_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Id != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id);
+      }
+      if (Email.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Email);
+      }
+      size += phones_.CalculateSize(_repeated_phones_codec);
+      return size;
+    }
+
+    public void MergeFrom(Person other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Id != 0) {
+        Id = other.Id;
+      }
+      if (other.Email.Length != 0) {
+        Email = other.Email;
+      }
+      phones_.Add(other.phones_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 16: {
+            Id = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            Email = input.ReadString();
+            break;
+          }
+          case 34: {
+            phones_.AddEntriesFrom(input, _repeated_phones_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the Person message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum PhoneType {
+        [pbr::OriginalName("MOBILE")] Mobile = 0,
+        [pbr::OriginalName("HOME")] Home = 1,
+        [pbr::OriginalName("WORK")] Work = 2,
+      }
+
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class PhoneNumber : pb::IMessage<PhoneNumber> {
+        private static readonly pb::MessageParser<PhoneNumber> _parser = new pb::MessageParser<PhoneNumber>(() => new PhoneNumber());
+        public static pb::MessageParser<PhoneNumber> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Examples.AddressBook.Person.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public PhoneNumber() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public PhoneNumber(PhoneNumber other) : this() {
+          number_ = other.number_;
+          type_ = other.type_;
+        }
+
+        public PhoneNumber Clone() {
+          return new PhoneNumber(this);
+        }
+
+        /// <summary>Field number for the "number" field.</summary>
+        public const int NumberFieldNumber = 1;
+        private string number_ = "";
+        public string Number {
+          get { return number_; }
+          set {
+            number_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "type" field.</summary>
+        public const int TypeFieldNumber = 2;
+        private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = 0;
+        public global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType Type {
+          get { return type_; }
+          set {
+            type_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as PhoneNumber);
+        }
+
+        public bool Equals(PhoneNumber other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Number != other.Number) return false;
+          if (Type != other.Type) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Number.Length != 0) hash ^= Number.GetHashCode();
+          if (Type != 0) hash ^= Type.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Number.Length != 0) {
+            output.WriteRawTag(10);
+            output.WriteString(Number);
+          }
+          if (Type != 0) {
+            output.WriteRawTag(16);
+            output.WriteEnum((int) Type);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Number.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(Number);
+          }
+          if (Type != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
+          }
+          return size;
+        }
+
+        public void MergeFrom(PhoneNumber other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Number.Length != 0) {
+            Number = other.Number;
+          }
+          if (other.Type != 0) {
+            Type = other.Type;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10: {
+                Number = input.ReadString();
+                break;
+              }
+              case 16: {
+                type_ = (global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) input.ReadEnum();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Our address book file is just one of these.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class AddressBook : pb::IMessage<AddressBook> {
+    private static readonly pb::MessageParser<AddressBook> _parser = new pb::MessageParser<AddressBook>(() => new AddressBook());
+    public static pb::MessageParser<AddressBook> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Examples.AddressBook.AddressbookReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public AddressBook() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public AddressBook(AddressBook other) : this() {
+      people_ = other.people_.Clone();
+    }
+
+    public AddressBook Clone() {
+      return new AddressBook(this);
+    }
+
+    /// <summary>Field number for the "people" field.</summary>
+    public const int PeopleFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Examples.AddressBook.Person> _repeated_people_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Examples.AddressBook.Person.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person> people_ = new pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person>();
+    public pbc::RepeatedField<global::Google.Protobuf.Examples.AddressBook.Person> People {
+      get { return people_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as AddressBook);
+    }
+
+    public bool Equals(AddressBook other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!people_.Equals(other.people_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= people_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      people_.WriteTo(output, _repeated_people_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += people_.CalculateSize(_repeated_people_codec);
+      return size;
+    }
+
+    public void MergeFrom(AddressBook other) {
+      if (other == null) {
+        return;
+      }
+      people_.Add(other.people_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            people_.AddEntriesFrom(input, _repeated_people_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/AddressBook/ListPeople.cs b/csharp/src/AddressBook/ListPeople.cs
new file mode 100644
index 0000000..3758c1b
--- /dev/null
+++ b/csharp/src/AddressBook/ListPeople.cs
@@ -0,0 +1,99 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+

+namespace Google.Protobuf.Examples.AddressBook

+{

+    internal class ListPeople

+    {

+        /// <summary>

+        /// Iterates though all people in the AddressBook and prints info about them.

+        /// </summary>

+        private static void Print(AddressBook addressBook)

+        {

+            foreach (Person person in addressBook.People)

+            {

+                Console.WriteLine("Person ID: {0}", person.Id);

+                Console.WriteLine("  Name: {0}", person.Name);

+                if (person.Email != "")

+                {

+                    Console.WriteLine("  E-mail address: {0}", person.Email);

+                }

+

+                foreach (Person.Types.PhoneNumber phoneNumber in person.Phones)

+                {

+                    switch (phoneNumber.Type)

+                    {

+                        case Person.Types.PhoneType.Mobile:

+                            Console.Write("  Mobile phone #: ");

+                            break;

+                        case Person.Types.PhoneType.Home:

+                            Console.Write("  Home phone #: ");

+                            break;

+                        case Person.Types.PhoneType.Work:

+                            Console.Write("  Work phone #: ");

+                            break;

+                    }

+                    Console.WriteLine(phoneNumber.Number);

+                }

+            }

+        }

+

+        /// <summary>

+        /// Entry point - loads the addressbook and then displays it.

+        /// </summary>

+        public static int Main(string[] args)

+        {

+            if (args.Length != 1)

+            {

+                Console.Error.WriteLine("Usage:  ListPeople ADDRESS_BOOK_FILE");

+                return 1;

+            }

+

+            if (!File.Exists(args[0]))

+            {

+                Console.WriteLine("{0} doesn't exist. Add a person to create the file first.", args[0]);

+                return 0;

+            }

+

+            // Read the existing address book.

+            using (Stream stream = File.OpenRead(args[0]))

+            {

+                AddressBook addressBook = AddressBook.Parser.ParseFrom(stream);

+                Print(addressBook);

+            }

+            return 0;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/AddressBook/Program.cs b/csharp/src/AddressBook/Program.cs
new file mode 100644
index 0000000..ff7b9c0
--- /dev/null
+++ b/csharp/src/AddressBook/Program.cs
@@ -0,0 +1,95 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+

+namespace Google.Protobuf.Examples.AddressBook

+{

+    /// <summary>

+    /// Entry point. Repeatedly prompts user for an action to take, delegating actual behaviour

+    /// to individual actions. Each action has its own Main method, so that it can be used as an

+    /// invidual complete program.

+    /// </summary>

+    internal class Program

+    {

+        private static int Main(string[] args)

+        {

+            if (args.Length > 1)

+            {

+                Console.Error.WriteLine("Usage: AddressBook [file]");

+                Console.Error.WriteLine("If the filename isn't specified, \"addressbook.data\" is used instead.");

+                return 1;

+            }

+            string addressBookFile = args.Length > 0 ? args[0] : "addressbook.data";

+

+            bool stopping = false;

+            while (!stopping)

+            {

+                Console.WriteLine("Options:");

+                Console.WriteLine("  L: List contents");

+                Console.WriteLine("  A: Add new person");

+                Console.WriteLine("  Q: Quit");

+                Console.Write("Action? ");

+                Console.Out.Flush();

+                char choice = Console.ReadKey().KeyChar;

+                Console.WriteLine();

+                try

+                {

+                    switch (choice)

+                    {

+                        case 'A':

+                        case 'a':

+                            AddPerson.Main(new string[] {addressBookFile});

+                            break;

+                        case 'L':

+                        case 'l':

+                            ListPeople.Main(new string[] {addressBookFile});

+                            break;

+                        case 'Q':

+                        case 'q':

+                            stopping = true;

+                            break;

+                        default:

+                            Console.WriteLine("Unknown option: {0}", choice);

+                            break;

+                    }

+                }

+                catch (Exception e)

+                {

+                    Console.WriteLine("Exception executing action: {0}", e);

+                }

+                Console.WriteLine();

+            }

+            return 0;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/AddressBook/Properties/AssemblyInfo.cs b/csharp/src/AddressBook/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9cb014c
--- /dev/null
+++ b/csharp/src/AddressBook/Properties/AssemblyInfo.cs
@@ -0,0 +1,18 @@
+using System.Reflection;

+using System.Runtime.InteropServices;

+

+// General Information about an assembly is controlled through the following 

+// set of attributes. Change these attribute values to modify the information

+// associated with an assembly.

+

+[assembly: AssemblyTitle("AddressBook")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("AddressBook")]

+[assembly: AssemblyCopyright("Copyright ©  2015")]

+[assembly: AssemblyTrademark("")]

+[assembly: AssemblyCulture("")]

+

+[assembly: AssemblyVersion("3.0.0.0")]

+[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/AddressBook/SampleUsage.cs b/csharp/src/AddressBook/SampleUsage.cs
new file mode 100644
index 0000000..aaaedda
--- /dev/null
+++ b/csharp/src/AddressBook/SampleUsage.cs
@@ -0,0 +1,73 @@
+#region Copyright notice and license

+// 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.

+#endregion

+    

+using System;

+using System.IO;

+

+namespace Google.Protobuf.Examples.AddressBook

+{

+    internal class SampleUsage

+    {

+        private static void Main()

+        {

+            byte[] bytes;

+            // Create a new person

+            Person person = new Person

+            {

+                Id = 1,

+                Name = "Foo",

+                Email = "foo@bar",

+                Phones = { new Person.Types.PhoneNumber { Number = "555-1212" } }

+            };

+            using (MemoryStream stream = new MemoryStream())

+            {

+                // Save the person to a stream

+                person.WriteTo(stream);

+                bytes = stream.ToArray();

+            }

+            Person copy = Person.Parser.ParseFrom(bytes);

+

+            AddressBook book = new AddressBook

+            {

+                People = { copy }

+            };

+            bytes = book.ToByteArray();

+            // And read the address book back again

+            AddressBook restored = AddressBook.Parser.ParseFrom(bytes);

+            // The message performs a deep-comparison on equality:

+            if (restored.People.Count != 1 || !person.Equals(restored.People[0]))

+            {

+                throw new ApplicationException("There is a bad person in here!");

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/AddressBook/app.config b/csharp/src/AddressBook/app.config
new file mode 100644
index 0000000..a80813a
--- /dev/null
+++ b/csharp/src/AddressBook/app.config
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<configuration>
+	<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
diff --git a/csharp/src/Google.Protobuf.Conformance/App.config b/csharp/src/Google.Protobuf.Conformance/App.config
new file mode 100644
index 0000000..8e15646
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/App.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+    </startup>
+</configuration>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
new file mode 100644
index 0000000..1674a67
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
@@ -0,0 +1,3708 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: conformance.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Conformance {
+
+  /// <summary>Holder for reflection information generated from conformance.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class ConformanceReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for conformance.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static ConformanceReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UaGWdvb2dsZS9wcm90",
+            "b2J1Zi9hbnkucHJvdG8aHmdvb2dsZS9wcm90b2J1Zi9kdXJhdGlvbi5wcm90",
+            "bxogZ29vZ2xlL3Byb3RvYnVmL2ZpZWxkX21hc2sucHJvdG8aHGdvb2dsZS9w",
+            "cm90b2J1Zi9zdHJ1Y3QucHJvdG8aH2dvb2dsZS9wcm90b2J1Zi90aW1lc3Rh",
+            "bXAucHJvdG8aHmdvb2dsZS9wcm90b2J1Zi93cmFwcGVycy5wcm90byKNAQoS",
+            "Q29uZm9ybWFuY2VSZXF1ZXN0EhoKEHByb3RvYnVmX3BheWxvYWQYASABKAxI",
+            "ABIWCgxqc29uX3BheWxvYWQYAiABKAlIABI4ChdyZXF1ZXN0ZWRfb3V0cHV0",
+            "X2Zvcm1hdBgDIAEoDjIXLmNvbmZvcm1hbmNlLldpcmVGb3JtYXRCCQoHcGF5",
+            "bG9hZCKxAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtwYXJzZV9lcnJvchgB",
+            "IAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgAEhcKDXJ1bnRpbWVf",
+            "ZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2FkGAMgASgMSAASFgoM",
+            "anNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgFIAEoCUgAQggKBnJl",
+            "c3VsdCLVMgoMVGVzdEFsbFR5cGVzEhYKDm9wdGlvbmFsX2ludDMyGAEgASgF",
+            "EhYKDm9wdGlvbmFsX2ludDY0GAIgASgDEhcKD29wdGlvbmFsX3VpbnQzMhgD",
+            "IAEoDRIXCg9vcHRpb25hbF91aW50NjQYBCABKAQSFwoPb3B0aW9uYWxfc2lu",
+            "dDMyGAUgASgREhcKD29wdGlvbmFsX3NpbnQ2NBgGIAEoEhIYChBvcHRpb25h",
+            "bF9maXhlZDMyGAcgASgHEhgKEG9wdGlvbmFsX2ZpeGVkNjQYCCABKAYSGQoR",
+            "b3B0aW9uYWxfc2ZpeGVkMzIYCSABKA8SGQoRb3B0aW9uYWxfc2ZpeGVkNjQY",
+            "CiABKBASFgoOb3B0aW9uYWxfZmxvYXQYCyABKAISFwoPb3B0aW9uYWxfZG91",
+            "YmxlGAwgASgBEhUKDW9wdGlvbmFsX2Jvb2wYDSABKAgSFwoPb3B0aW9uYWxf",
+            "c3RyaW5nGA4gASgJEhYKDm9wdGlvbmFsX2J5dGVzGA8gASgMEkgKF29wdGlv",
+            "bmFsX25lc3RlZF9tZXNzYWdlGBIgASgLMicuY29uZm9ybWFuY2UuVGVzdEFs",
+            "bFR5cGVzLk5lc3RlZE1lc3NhZ2USPQoYb3B0aW9uYWxfZm9yZWlnbl9tZXNz",
+            "YWdlGBMgASgLMhsuY29uZm9ybWFuY2UuRm9yZWlnbk1lc3NhZ2USQgoUb3B0",
+            "aW9uYWxfbmVzdGVkX2VudW0YFSABKA4yJC5jb25mb3JtYW5jZS5UZXN0QWxs",
+            "VHlwZXMuTmVzdGVkRW51bRI3ChVvcHRpb25hbF9mb3JlaWduX2VudW0YFiAB",
+            "KA4yGC5jb25mb3JtYW5jZS5Gb3JlaWduRW51bRIhChVvcHRpb25hbF9zdHJp",
+            "bmdfcGllY2UYGCABKAlCAggCEhkKDW9wdGlvbmFsX2NvcmQYGSABKAlCAggB",
+            "EjQKEXJlY3Vyc2l2ZV9tZXNzYWdlGBsgASgLMhkuY29uZm9ybWFuY2UuVGVz",
+            "dEFsbFR5cGVzEhYKDnJlcGVhdGVkX2ludDMyGB8gAygFEhYKDnJlcGVhdGVk",
+            "X2ludDY0GCAgAygDEhcKD3JlcGVhdGVkX3VpbnQzMhghIAMoDRIXCg9yZXBl",
+            "YXRlZF91aW50NjQYIiADKAQSFwoPcmVwZWF0ZWRfc2ludDMyGCMgAygREhcK",
+            "D3JlcGVhdGVkX3NpbnQ2NBgkIAMoEhIYChByZXBlYXRlZF9maXhlZDMyGCUg",
+            "AygHEhgKEHJlcGVhdGVkX2ZpeGVkNjQYJiADKAYSGQoRcmVwZWF0ZWRfc2Zp",
+            "eGVkMzIYJyADKA8SGQoRcmVwZWF0ZWRfc2ZpeGVkNjQYKCADKBASFgoOcmVw",
+            "ZWF0ZWRfZmxvYXQYKSADKAISFwoPcmVwZWF0ZWRfZG91YmxlGCogAygBEhUK",
+            "DXJlcGVhdGVkX2Jvb2wYKyADKAgSFwoPcmVwZWF0ZWRfc3RyaW5nGCwgAygJ",
+            "EhYKDnJlcGVhdGVkX2J5dGVzGC0gAygMEkgKF3JlcGVhdGVkX25lc3RlZF9t",
+            "ZXNzYWdlGDAgAygLMicuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk5lc3Rl",
+            "ZE1lc3NhZ2USPQoYcmVwZWF0ZWRfZm9yZWlnbl9tZXNzYWdlGDEgAygLMhsu",
+            "Y29uZm9ybWFuY2UuRm9yZWlnbk1lc3NhZ2USQgoUcmVwZWF0ZWRfbmVzdGVk",
+            "X2VudW0YMyADKA4yJC5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTmVzdGVk",
+            "RW51bRI3ChVyZXBlYXRlZF9mb3JlaWduX2VudW0YNCADKA4yGC5jb25mb3Jt",
+            "YW5jZS5Gb3JlaWduRW51bRIhChVyZXBlYXRlZF9zdHJpbmdfcGllY2UYNiAD",
+            "KAlCAggCEhkKDXJlcGVhdGVkX2NvcmQYNyADKAlCAggBEkUKD21hcF9pbnQz",
+            "Ml9pbnQzMhg4IAMoCzIsLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBJ",
+            "bnQzMkludDMyRW50cnkSRQoPbWFwX2ludDY0X2ludDY0GDkgAygLMiwuY29u",
+            "Zm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcEludDY0SW50NjRFbnRyeRJJChFt",
+            "YXBfdWludDMyX3VpbnQzMhg6IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBVaW50MzJVaW50MzJFbnRyeRJJChFtYXBfdWludDY0X3VpbnQ2",
+            "NBg7IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBVaW50NjRV",
+            "aW50NjRFbnRyeRJJChFtYXBfc2ludDMyX3NpbnQzMhg8IAMoCzIuLmNvbmZv",
+            "cm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBTaW50MzJTaW50MzJFbnRyeRJJChFt",
+            "YXBfc2ludDY0X3NpbnQ2NBg9IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBTaW50NjRTaW50NjRFbnRyeRJNChNtYXBfZml4ZWQzMl9maXhl",
+            "ZDMyGD4gAygLMjAuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcEZpeGVk",
+            "MzJGaXhlZDMyRW50cnkSTQoTbWFwX2ZpeGVkNjRfZml4ZWQ2NBg/IAMoCzIw",
+            "LmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBGaXhlZDY0Rml4ZWQ2NEVu",
+            "dHJ5ElEKFW1hcF9zZml4ZWQzMl9zZml4ZWQzMhhAIAMoCzIyLmNvbmZvcm1h",
+            "bmNlLlRlc3RBbGxUeXBlcy5NYXBTZml4ZWQzMlNmaXhlZDMyRW50cnkSUQoV",
+            "bWFwX3NmaXhlZDY0X3NmaXhlZDY0GEEgAygLMjIuY29uZm9ybWFuY2UuVGVz",
+            "dEFsbFR5cGVzLk1hcFNmaXhlZDY0U2ZpeGVkNjRFbnRyeRJFCg9tYXBfaW50",
+            "MzJfZmxvYXQYQiADKAsyLC5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFw",
+            "SW50MzJGbG9hdEVudHJ5EkcKEG1hcF9pbnQzMl9kb3VibGUYQyADKAsyLS5j",
+            "b25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwSW50MzJEb3VibGVFbnRyeRJB",
+            "Cg1tYXBfYm9vbF9ib29sGEQgAygLMiouY29uZm9ybWFuY2UuVGVzdEFsbFR5",
+            "cGVzLk1hcEJvb2xCb29sRW50cnkSSQoRbWFwX3N0cmluZ19zdHJpbmcYRSAD",
+            "KAsyLi5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwU3RyaW5nU3RyaW5n",
+            "RW50cnkSRwoQbWFwX3N0cmluZ19ieXRlcxhGIAMoCzItLmNvbmZvcm1hbmNl",
+            "LlRlc3RBbGxUeXBlcy5NYXBTdHJpbmdCeXRlc0VudHJ5ElgKGW1hcF9zdHJp",
+            "bmdfbmVzdGVkX21lc3NhZ2UYRyADKAsyNS5jb25mb3JtYW5jZS5UZXN0QWxs",
+            "VHlwZXMuTWFwU3RyaW5nTmVzdGVkTWVzc2FnZUVudHJ5EloKGm1hcF9zdHJp",
+            "bmdfZm9yZWlnbl9tZXNzYWdlGEggAygLMjYuY29uZm9ybWFuY2UuVGVzdEFs",
+            "bFR5cGVzLk1hcFN0cmluZ0ZvcmVpZ25NZXNzYWdlRW50cnkSUgoWbWFwX3N0",
+            "cmluZ19uZXN0ZWRfZW51bRhJIAMoCzIyLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBTdHJpbmdOZXN0ZWRFbnVtRW50cnkSVAoXbWFwX3N0cmluZ19m",
+            "b3JlaWduX2VudW0YSiADKAsyMy5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMu",
+            "TWFwU3RyaW5nRm9yZWlnbkVudW1FbnRyeRIWCgxvbmVvZl91aW50MzIYbyAB",
+            "KA1IABJHChRvbmVvZl9uZXN0ZWRfbWVzc2FnZRhwIAEoCzInLmNvbmZvcm1h",
+            "bmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlSAASFgoMb25lb2Zfc3Ry",
+            "aW5nGHEgASgJSAASFQoLb25lb2ZfYnl0ZXMYciABKAxIABI6ChVvcHRpb25h",
+            "bF9ib29sX3dyYXBwZXIYyQEgASgLMhouZ29vZ2xlLnByb3RvYnVmLkJvb2xW",
+            "YWx1ZRI8ChZvcHRpb25hbF9pbnQzMl93cmFwcGVyGMoBIAEoCzIbLmdvb2ds",
+            "ZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjwKFm9wdGlvbmFsX2ludDY0X3dyYXBw",
+            "ZXIYywEgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDY0VmFsdWUSPgoXb3B0",
+            "aW9uYWxfdWludDMyX3dyYXBwZXIYzAEgASgLMhwuZ29vZ2xlLnByb3RvYnVm",
+            "LlVJbnQzMlZhbHVlEj4KF29wdGlvbmFsX3VpbnQ2NF93cmFwcGVyGM0BIAEo",
+            "CzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZRI8ChZvcHRpb25hbF9m",
+            "bG9hdF93cmFwcGVyGM4BIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GbG9hdFZh",
+            "bHVlEj4KF29wdGlvbmFsX2RvdWJsZV93cmFwcGVyGM8BIAEoCzIcLmdvb2ds",
+            "ZS5wcm90b2J1Zi5Eb3VibGVWYWx1ZRI+ChdvcHRpb25hbF9zdHJpbmdfd3Jh",
+            "cHBlchjQASABKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSPAoW",
+            "b3B0aW9uYWxfYnl0ZXNfd3JhcHBlchjRASABKAsyGy5nb29nbGUucHJvdG9i",
+            "dWYuQnl0ZXNWYWx1ZRI6ChVyZXBlYXRlZF9ib29sX3dyYXBwZXIY0wEgAygL",
+            "MhouZ29vZ2xlLnByb3RvYnVmLkJvb2xWYWx1ZRI8ChZyZXBlYXRlZF9pbnQz",
+            "Ml93cmFwcGVyGNQBIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVl",
+            "EjwKFnJlcGVhdGVkX2ludDY0X3dyYXBwZXIY1QEgAygLMhsuZ29vZ2xlLnBy",
+            "b3RvYnVmLkludDY0VmFsdWUSPgoXcmVwZWF0ZWRfdWludDMyX3dyYXBwZXIY",
+            "1gEgAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEj4KF3JlcGVh",
+            "dGVkX3VpbnQ2NF93cmFwcGVyGNcBIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5V",
+            "SW50NjRWYWx1ZRI8ChZyZXBlYXRlZF9mbG9hdF93cmFwcGVyGNgBIAMoCzIb",
+            "Lmdvb2dsZS5wcm90b2J1Zi5GbG9hdFZhbHVlEj4KF3JlcGVhdGVkX2RvdWJs",
+            "ZV93cmFwcGVyGNkBIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5Eb3VibGVWYWx1",
+            "ZRI+ChdyZXBlYXRlZF9zdHJpbmdfd3JhcHBlchjaASADKAsyHC5nb29nbGUu",
+            "cHJvdG9idWYuU3RyaW5nVmFsdWUSPAoWcmVwZWF0ZWRfYnl0ZXNfd3JhcHBl",
+            "chjbASADKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZRI1ChFvcHRp",
+            "b25hbF9kdXJhdGlvbhitAiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRp",
+            "b24SNwoSb3B0aW9uYWxfdGltZXN0YW1wGK4CIAEoCzIaLmdvb2dsZS5wcm90",
+            "b2J1Zi5UaW1lc3RhbXASOAoTb3B0aW9uYWxfZmllbGRfbWFzaxivAiABKAsy",
+            "Gi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrEjEKD29wdGlvbmFsX3N0cnVj",
+            "dBiwAiABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EisKDG9wdGlvbmFs",
+            "X2FueRixAiABKAsyFC5nb29nbGUucHJvdG9idWYuQW55Ei8KDm9wdGlvbmFs",
+            "X3ZhbHVlGLICIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZRI1ChFyZXBl",
+            "YXRlZF9kdXJhdGlvbhi3AiADKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRp",
+            "b24SNwoScmVwZWF0ZWRfdGltZXN0YW1wGLgCIAMoCzIaLmdvb2dsZS5wcm90",
+            "b2J1Zi5UaW1lc3RhbXASNwoScmVwZWF0ZWRfZmllbGRtYXNrGLkCIAMoCzIa",
+            "Lmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sSMQoPcmVwZWF0ZWRfc3RydWN0",
+            "GMQCIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSKwoMcmVwZWF0ZWRf",
+            "YW55GLsCIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnkSLwoOcmVwZWF0ZWRf",
+            "dmFsdWUYvAIgAygLMhYuZ29vZ2xlLnByb3RvYnVmLlZhbHVlEhMKCmZpZWxk",
+            "bmFtZTEYkQMgASgFEhQKC2ZpZWxkX25hbWUyGJIDIAEoBRIVCgxfZmllbGRf",
+            "bmFtZTMYkwMgASgFEhYKDWZpZWxkX19uYW1lNF8YlAMgASgFEhQKC2ZpZWxk",
+            "MG5hbWU1GJUDIAEoBRIWCg1maWVsZF8wX25hbWU2GJYDIAEoBRITCgpmaWVs",
+            "ZE5hbWU3GJcDIAEoBRITCgpGaWVsZE5hbWU4GJgDIAEoBRIUCgtmaWVsZF9O",
+            "YW1lORiZAyABKAUSFQoMRmllbGRfTmFtZTEwGJoDIAEoBRIVCgxGSUVMRF9O",
+            "QU1FMTEYmwMgASgFEhUKDEZJRUxEX25hbWUxMhicAyABKAUaSgoNTmVzdGVk",
+            "TWVzc2FnZRIJCgFhGAEgASgFEi4KC2NvcmVjdXJzaXZlGAIgASgLMhkuY29u",
+            "Zm9ybWFuY2UuVGVzdEFsbFR5cGVzGjQKEk1hcEludDMySW50MzJFbnRyeRIL",
+            "CgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcEludDY0SW50",
+            "NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgBGjYKFE1h",
+            "cFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1ZRgCIAEo",
+            "DToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEgASgEEg0K",
+            "BXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRyeRILCgNr",
+            "ZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2NFNpbnQ2",
+            "NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEaOAoWTWFw",
+            "Rml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFsdWUYAiAB",
+            "KAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5GAEgASgG",
+            "Eg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhlZDMyRW50",
+            "cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhNYXBTZml4",
+            "ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVlGAIgASgQ",
+            "OgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgFEg0KBXZh",
+            "bHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsKA2tleRgB",
+            "IAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xFbnRyeRIL",
+            "CgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGjYKFE1hcFN0cmluZ1N0",
+            "cmluZ0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEaNQoT",
+            "TWFwU3RyaW5nQnl0ZXNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB",
+            "KAw6AjgBGmYKG01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRILCgNrZXkY",
+            "ASABKAkSNgoFdmFsdWUYAiABKAsyJy5jb25mb3JtYW5jZS5UZXN0QWxsVHlw",
+            "ZXMuTmVzdGVkTWVzc2FnZToCOAEaWwocTWFwU3RyaW5nRm9yZWlnbk1lc3Nh",
+            "Z2VFbnRyeRILCgNrZXkYASABKAkSKgoFdmFsdWUYAiABKAsyGy5jb25mb3Jt",
+            "YW5jZS5Gb3JlaWduTWVzc2FnZToCOAEaYAoYTWFwU3RyaW5nTmVzdGVkRW51",
+            "bUVudHJ5EgsKA2tleRgBIAEoCRIzCgV2YWx1ZRgCIAEoDjIkLmNvbmZvcm1h",
+            "bmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRFbnVtOgI4ARpVChlNYXBTdHJpbmdG",
+            "b3JlaWduRW51bUVudHJ5EgsKA2tleRgBIAEoCRInCgV2YWx1ZRgCIAEoDjIY",
+            "LmNvbmZvcm1hbmNlLkZvcmVpZ25FbnVtOgI4ASI5CgpOZXN0ZWRFbnVtEgcK",
+            "A0ZPTxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8BQg0K",
+            "C29uZW9mX2ZpZWxkIhsKDkZvcmVpZ25NZXNzYWdlEgkKAWMYASABKAUqNQoK",
+            "V2lyZUZvcm1hdBIPCgtVTlNQRUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoE",
+            "SlNPThACKkAKC0ZvcmVpZ25FbnVtEg8KC0ZPUkVJR05fRk9PEAASDwoLRk9S",
+            "RUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACQiEKH2NvbS5nb29nbGUucHJv",
+            "dG9idWYuY29uZm9ybWFuY2ViBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.ForeignEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat" }, new[]{ "Payload" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes), global::Conformance.TestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OptionalBoolWrapper", "OptionalInt32Wrapper", "OptionalInt64Wrapper", "OptionalUint32Wrapper", "OptionalUint64Wrapper", "OptionalFloatWrapper", "OptionalDoubleWrapper", "OptionalStringWrapper", "OptionalBytesWrapper", "RepeatedBoolWrapper", "RepeatedInt32Wrapper", "RepeatedInt64Wrapper", "RepeatedUint32Wrapper", "RepeatedUint64Wrapper", "RepeatedFloatWrapper", "RepeatedDoubleWrapper", "RepeatedStringWrapper", "RepeatedBytesWrapper", "OptionalDuration", "OptionalTimestamp", "OptionalFieldMask", "OptionalStruct", "OptionalAny", "OptionalValue", "RepeatedDuration", "RepeatedTimestamp", "RepeatedFieldmask", "RepeatedStruct", "RepeatedAny", "RepeatedValue", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12" }, new[]{ "OneofField" }, new[]{ typeof(global::Conformance.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes.Types.NestedMessage), global::Conformance.TestAllTypes.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null),
+            null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ForeignMessage), global::Conformance.ForeignMessage.Parser, new[]{ "C" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum WireFormat {
+    [pbr::OriginalName("UNSPECIFIED")] Unspecified = 0,
+    [pbr::OriginalName("PROTOBUF")] Protobuf = 1,
+    [pbr::OriginalName("JSON")] Json = 2,
+  }
+
+  public enum ForeignEnum {
+    [pbr::OriginalName("FOREIGN_FOO")] ForeignFoo = 0,
+    [pbr::OriginalName("FOREIGN_BAR")] ForeignBar = 1,
+    [pbr::OriginalName("FOREIGN_BAZ")] ForeignBaz = 2,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  Represents a single test case's input.  The testee should:
+  ///
+  ///    1. parse this proto (which should always succeed)
+  ///    2. parse the protobuf or JSON payload in "payload" (which may fail)
+  ///    3. if the parse succeeded, serialize the message in the requested format.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ConformanceRequest : pb::IMessage<ConformanceRequest> {
+    private static readonly pb::MessageParser<ConformanceRequest> _parser = new pb::MessageParser<ConformanceRequest>(() => new ConformanceRequest());
+    public static pb::MessageParser<ConformanceRequest> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ConformanceRequest() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ConformanceRequest(ConformanceRequest other) : this() {
+      requestedOutputFormat_ = other.requestedOutputFormat_;
+      switch (other.PayloadCase) {
+        case PayloadOneofCase.ProtobufPayload:
+          ProtobufPayload = other.ProtobufPayload;
+          break;
+        case PayloadOneofCase.JsonPayload:
+          JsonPayload = other.JsonPayload;
+          break;
+      }
+
+    }
+
+    public ConformanceRequest Clone() {
+      return new ConformanceRequest(this);
+    }
+
+    /// <summary>Field number for the "protobuf_payload" field.</summary>
+    public const int ProtobufPayloadFieldNumber = 1;
+    public pb::ByteString ProtobufPayload {
+      get { return payloadCase_ == PayloadOneofCase.ProtobufPayload ? (pb::ByteString) payload_ : pb::ByteString.Empty; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        payloadCase_ = PayloadOneofCase.ProtobufPayload;
+      }
+    }
+
+    /// <summary>Field number for the "json_payload" field.</summary>
+    public const int JsonPayloadFieldNumber = 2;
+    public string JsonPayload {
+      get { return payloadCase_ == PayloadOneofCase.JsonPayload ? (string) payload_ : ""; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        payloadCase_ = PayloadOneofCase.JsonPayload;
+      }
+    }
+
+    /// <summary>Field number for the "requested_output_format" field.</summary>
+    public const int RequestedOutputFormatFieldNumber = 3;
+    private global::Conformance.WireFormat requestedOutputFormat_ = 0;
+    /// <summary>
+    ///  Which format should the testee serialize its message to?
+    /// </summary>
+    public global::Conformance.WireFormat RequestedOutputFormat {
+      get { return requestedOutputFormat_; }
+      set {
+        requestedOutputFormat_ = value;
+      }
+    }
+
+    private object payload_;
+    /// <summary>Enum of possible cases for the "payload" oneof.</summary>
+    public enum PayloadOneofCase {
+      None = 0,
+      ProtobufPayload = 1,
+      JsonPayload = 2,
+    }
+    private PayloadOneofCase payloadCase_ = PayloadOneofCase.None;
+    public PayloadOneofCase PayloadCase {
+      get { return payloadCase_; }
+    }
+
+    public void ClearPayload() {
+      payloadCase_ = PayloadOneofCase.None;
+      payload_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ConformanceRequest);
+    }
+
+    public bool Equals(ConformanceRequest other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (ProtobufPayload != other.ProtobufPayload) return false;
+      if (JsonPayload != other.JsonPayload) return false;
+      if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
+      if (PayloadCase != other.PayloadCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (payloadCase_ == PayloadOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
+      if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
+      if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
+      hash ^= (int) payloadCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (payloadCase_ == PayloadOneofCase.ProtobufPayload) {
+        output.WriteRawTag(10);
+        output.WriteBytes(ProtobufPayload);
+      }
+      if (payloadCase_ == PayloadOneofCase.JsonPayload) {
+        output.WriteRawTag(18);
+        output.WriteString(JsonPayload);
+      }
+      if (RequestedOutputFormat != 0) {
+        output.WriteRawTag(24);
+        output.WriteEnum((int) RequestedOutputFormat);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (payloadCase_ == PayloadOneofCase.ProtobufPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(ProtobufPayload);
+      }
+      if (payloadCase_ == PayloadOneofCase.JsonPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload);
+      }
+      if (RequestedOutputFormat != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RequestedOutputFormat);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ConformanceRequest other) {
+      if (other == null) {
+        return;
+      }
+      if (other.RequestedOutputFormat != 0) {
+        RequestedOutputFormat = other.RequestedOutputFormat;
+      }
+      switch (other.PayloadCase) {
+        case PayloadOneofCase.ProtobufPayload:
+          ProtobufPayload = other.ProtobufPayload;
+          break;
+        case PayloadOneofCase.JsonPayload:
+          JsonPayload = other.JsonPayload;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            ProtobufPayload = input.ReadBytes();
+            break;
+          }
+          case 18: {
+            JsonPayload = input.ReadString();
+            break;
+          }
+          case 24: {
+            requestedOutputFormat_ = (global::Conformance.WireFormat) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Represents a single test case's output.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ConformanceResponse : pb::IMessage<ConformanceResponse> {
+    private static readonly pb::MessageParser<ConformanceResponse> _parser = new pb::MessageParser<ConformanceResponse>(() => new ConformanceResponse());
+    public static pb::MessageParser<ConformanceResponse> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ConformanceResponse() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ConformanceResponse(ConformanceResponse other) : this() {
+      switch (other.ResultCase) {
+        case ResultOneofCase.ParseError:
+          ParseError = other.ParseError;
+          break;
+        case ResultOneofCase.SerializeError:
+          SerializeError = other.SerializeError;
+          break;
+        case ResultOneofCase.RuntimeError:
+          RuntimeError = other.RuntimeError;
+          break;
+        case ResultOneofCase.ProtobufPayload:
+          ProtobufPayload = other.ProtobufPayload;
+          break;
+        case ResultOneofCase.JsonPayload:
+          JsonPayload = other.JsonPayload;
+          break;
+        case ResultOneofCase.Skipped:
+          Skipped = other.Skipped;
+          break;
+      }
+
+    }
+
+    public ConformanceResponse Clone() {
+      return new ConformanceResponse(this);
+    }
+
+    /// <summary>Field number for the "parse_error" field.</summary>
+    public const int ParseErrorFieldNumber = 1;
+    /// <summary>
+    ///  This string should be set to indicate parsing failed.  The string can
+    ///  provide more information about the parse error if it is available.
+    ///
+    ///  Setting this string does not necessarily mean the testee failed the
+    ///  test.  Some of the test cases are intentionally invalid input.
+    /// </summary>
+    public string ParseError {
+      get { return resultCase_ == ResultOneofCase.ParseError ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.ParseError;
+      }
+    }
+
+    /// <summary>Field number for the "serialize_error" field.</summary>
+    public const int SerializeErrorFieldNumber = 6;
+    /// <summary>
+    ///  If the input was successfully parsed but errors occurred when
+    ///  serializing it to the requested output format, set the error message in
+    ///  this field.
+    /// </summary>
+    public string SerializeError {
+      get { return resultCase_ == ResultOneofCase.SerializeError ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.SerializeError;
+      }
+    }
+
+    /// <summary>Field number for the "runtime_error" field.</summary>
+    public const int RuntimeErrorFieldNumber = 2;
+    /// <summary>
+    ///  This should be set if some other error occurred.  This will always
+    ///  indicate that the test failed.  The string can provide more information
+    ///  about the failure.
+    /// </summary>
+    public string RuntimeError {
+      get { return resultCase_ == ResultOneofCase.RuntimeError ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.RuntimeError;
+      }
+    }
+
+    /// <summary>Field number for the "protobuf_payload" field.</summary>
+    public const int ProtobufPayloadFieldNumber = 3;
+    /// <summary>
+    ///  If the input was successfully parsed and the requested output was
+    ///  protobuf, serialize it to protobuf and set it in this field.
+    /// </summary>
+    public pb::ByteString ProtobufPayload {
+      get { return resultCase_ == ResultOneofCase.ProtobufPayload ? (pb::ByteString) result_ : pb::ByteString.Empty; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.ProtobufPayload;
+      }
+    }
+
+    /// <summary>Field number for the "json_payload" field.</summary>
+    public const int JsonPayloadFieldNumber = 4;
+    /// <summary>
+    ///  If the input was successfully parsed and the requested output was JSON,
+    ///  serialize to JSON and set it in this field.
+    /// </summary>
+    public string JsonPayload {
+      get { return resultCase_ == ResultOneofCase.JsonPayload ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.JsonPayload;
+      }
+    }
+
+    /// <summary>Field number for the "skipped" field.</summary>
+    public const int SkippedFieldNumber = 5;
+    /// <summary>
+    ///  For when the testee skipped the test, likely because a certain feature
+    ///  wasn't supported, like JSON input/output.
+    /// </summary>
+    public string Skipped {
+      get { return resultCase_ == ResultOneofCase.Skipped ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.Skipped;
+      }
+    }
+
+    private object result_;
+    /// <summary>Enum of possible cases for the "result" oneof.</summary>
+    public enum ResultOneofCase {
+      None = 0,
+      ParseError = 1,
+      SerializeError = 6,
+      RuntimeError = 2,
+      ProtobufPayload = 3,
+      JsonPayload = 4,
+      Skipped = 5,
+    }
+    private ResultOneofCase resultCase_ = ResultOneofCase.None;
+    public ResultOneofCase ResultCase {
+      get { return resultCase_; }
+    }
+
+    public void ClearResult() {
+      resultCase_ = ResultOneofCase.None;
+      result_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ConformanceResponse);
+    }
+
+    public bool Equals(ConformanceResponse other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (ParseError != other.ParseError) return false;
+      if (SerializeError != other.SerializeError) return false;
+      if (RuntimeError != other.RuntimeError) return false;
+      if (ProtobufPayload != other.ProtobufPayload) return false;
+      if (JsonPayload != other.JsonPayload) return false;
+      if (Skipped != other.Skipped) return false;
+      if (ResultCase != other.ResultCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (resultCase_ == ResultOneofCase.ParseError) hash ^= ParseError.GetHashCode();
+      if (resultCase_ == ResultOneofCase.SerializeError) hash ^= SerializeError.GetHashCode();
+      if (resultCase_ == ResultOneofCase.RuntimeError) hash ^= RuntimeError.GetHashCode();
+      if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
+      if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
+      if (resultCase_ == ResultOneofCase.Skipped) hash ^= Skipped.GetHashCode();
+      hash ^= (int) resultCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (resultCase_ == ResultOneofCase.ParseError) {
+        output.WriteRawTag(10);
+        output.WriteString(ParseError);
+      }
+      if (resultCase_ == ResultOneofCase.RuntimeError) {
+        output.WriteRawTag(18);
+        output.WriteString(RuntimeError);
+      }
+      if (resultCase_ == ResultOneofCase.ProtobufPayload) {
+        output.WriteRawTag(26);
+        output.WriteBytes(ProtobufPayload);
+      }
+      if (resultCase_ == ResultOneofCase.JsonPayload) {
+        output.WriteRawTag(34);
+        output.WriteString(JsonPayload);
+      }
+      if (resultCase_ == ResultOneofCase.Skipped) {
+        output.WriteRawTag(42);
+        output.WriteString(Skipped);
+      }
+      if (resultCase_ == ResultOneofCase.SerializeError) {
+        output.WriteRawTag(50);
+        output.WriteString(SerializeError);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (resultCase_ == ResultOneofCase.ParseError) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(ParseError);
+      }
+      if (resultCase_ == ResultOneofCase.SerializeError) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(SerializeError);
+      }
+      if (resultCase_ == ResultOneofCase.RuntimeError) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(RuntimeError);
+      }
+      if (resultCase_ == ResultOneofCase.ProtobufPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(ProtobufPayload);
+      }
+      if (resultCase_ == ResultOneofCase.JsonPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload);
+      }
+      if (resultCase_ == ResultOneofCase.Skipped) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Skipped);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ConformanceResponse other) {
+      if (other == null) {
+        return;
+      }
+      switch (other.ResultCase) {
+        case ResultOneofCase.ParseError:
+          ParseError = other.ParseError;
+          break;
+        case ResultOneofCase.SerializeError:
+          SerializeError = other.SerializeError;
+          break;
+        case ResultOneofCase.RuntimeError:
+          RuntimeError = other.RuntimeError;
+          break;
+        case ResultOneofCase.ProtobufPayload:
+          ProtobufPayload = other.ProtobufPayload;
+          break;
+        case ResultOneofCase.JsonPayload:
+          JsonPayload = other.JsonPayload;
+          break;
+        case ResultOneofCase.Skipped:
+          Skipped = other.Skipped;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            ParseError = input.ReadString();
+            break;
+          }
+          case 18: {
+            RuntimeError = input.ReadString();
+            break;
+          }
+          case 26: {
+            ProtobufPayload = input.ReadBytes();
+            break;
+          }
+          case 34: {
+            JsonPayload = input.ReadString();
+            break;
+          }
+          case 42: {
+            Skipped = input.ReadString();
+            break;
+          }
+          case 50: {
+            SerializeError = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  This proto includes every type of field in both singular and repeated
+  ///  forms.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestAllTypes : pb::IMessage<TestAllTypes> {
+    private static readonly pb::MessageParser<TestAllTypes> _parser = new pb::MessageParser<TestAllTypes>(() => new TestAllTypes());
+    public static pb::MessageParser<TestAllTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestAllTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestAllTypes(TestAllTypes other) : this() {
+      optionalInt32_ = other.optionalInt32_;
+      optionalInt64_ = other.optionalInt64_;
+      optionalUint32_ = other.optionalUint32_;
+      optionalUint64_ = other.optionalUint64_;
+      optionalSint32_ = other.optionalSint32_;
+      optionalSint64_ = other.optionalSint64_;
+      optionalFixed32_ = other.optionalFixed32_;
+      optionalFixed64_ = other.optionalFixed64_;
+      optionalSfixed32_ = other.optionalSfixed32_;
+      optionalSfixed64_ = other.optionalSfixed64_;
+      optionalFloat_ = other.optionalFloat_;
+      optionalDouble_ = other.optionalDouble_;
+      optionalBool_ = other.optionalBool_;
+      optionalString_ = other.optionalString_;
+      optionalBytes_ = other.optionalBytes_;
+      OptionalNestedMessage = other.optionalNestedMessage_ != null ? other.OptionalNestedMessage.Clone() : null;
+      OptionalForeignMessage = other.optionalForeignMessage_ != null ? other.OptionalForeignMessage.Clone() : null;
+      optionalNestedEnum_ = other.optionalNestedEnum_;
+      optionalForeignEnum_ = other.optionalForeignEnum_;
+      optionalStringPiece_ = other.optionalStringPiece_;
+      optionalCord_ = other.optionalCord_;
+      RecursiveMessage = other.recursiveMessage_ != null ? other.RecursiveMessage.Clone() : null;
+      repeatedInt32_ = other.repeatedInt32_.Clone();
+      repeatedInt64_ = other.repeatedInt64_.Clone();
+      repeatedUint32_ = other.repeatedUint32_.Clone();
+      repeatedUint64_ = other.repeatedUint64_.Clone();
+      repeatedSint32_ = other.repeatedSint32_.Clone();
+      repeatedSint64_ = other.repeatedSint64_.Clone();
+      repeatedFixed32_ = other.repeatedFixed32_.Clone();
+      repeatedFixed64_ = other.repeatedFixed64_.Clone();
+      repeatedSfixed32_ = other.repeatedSfixed32_.Clone();
+      repeatedSfixed64_ = other.repeatedSfixed64_.Clone();
+      repeatedFloat_ = other.repeatedFloat_.Clone();
+      repeatedDouble_ = other.repeatedDouble_.Clone();
+      repeatedBool_ = other.repeatedBool_.Clone();
+      repeatedString_ = other.repeatedString_.Clone();
+      repeatedBytes_ = other.repeatedBytes_.Clone();
+      repeatedNestedMessage_ = other.repeatedNestedMessage_.Clone();
+      repeatedForeignMessage_ = other.repeatedForeignMessage_.Clone();
+      repeatedNestedEnum_ = other.repeatedNestedEnum_.Clone();
+      repeatedForeignEnum_ = other.repeatedForeignEnum_.Clone();
+      repeatedStringPiece_ = other.repeatedStringPiece_.Clone();
+      repeatedCord_ = other.repeatedCord_.Clone();
+      mapInt32Int32_ = other.mapInt32Int32_.Clone();
+      mapInt64Int64_ = other.mapInt64Int64_.Clone();
+      mapUint32Uint32_ = other.mapUint32Uint32_.Clone();
+      mapUint64Uint64_ = other.mapUint64Uint64_.Clone();
+      mapSint32Sint32_ = other.mapSint32Sint32_.Clone();
+      mapSint64Sint64_ = other.mapSint64Sint64_.Clone();
+      mapFixed32Fixed32_ = other.mapFixed32Fixed32_.Clone();
+      mapFixed64Fixed64_ = other.mapFixed64Fixed64_.Clone();
+      mapSfixed32Sfixed32_ = other.mapSfixed32Sfixed32_.Clone();
+      mapSfixed64Sfixed64_ = other.mapSfixed64Sfixed64_.Clone();
+      mapInt32Float_ = other.mapInt32Float_.Clone();
+      mapInt32Double_ = other.mapInt32Double_.Clone();
+      mapBoolBool_ = other.mapBoolBool_.Clone();
+      mapStringString_ = other.mapStringString_.Clone();
+      mapStringBytes_ = other.mapStringBytes_.Clone();
+      mapStringNestedMessage_ = other.mapStringNestedMessage_.Clone();
+      mapStringForeignMessage_ = other.mapStringForeignMessage_.Clone();
+      mapStringNestedEnum_ = other.mapStringNestedEnum_.Clone();
+      mapStringForeignEnum_ = other.mapStringForeignEnum_.Clone();
+      OptionalBoolWrapper = other.OptionalBoolWrapper;
+      OptionalInt32Wrapper = other.OptionalInt32Wrapper;
+      OptionalInt64Wrapper = other.OptionalInt64Wrapper;
+      OptionalUint32Wrapper = other.OptionalUint32Wrapper;
+      OptionalUint64Wrapper = other.OptionalUint64Wrapper;
+      OptionalFloatWrapper = other.OptionalFloatWrapper;
+      OptionalDoubleWrapper = other.OptionalDoubleWrapper;
+      OptionalStringWrapper = other.OptionalStringWrapper;
+      OptionalBytesWrapper = other.OptionalBytesWrapper;
+      repeatedBoolWrapper_ = other.repeatedBoolWrapper_.Clone();
+      repeatedInt32Wrapper_ = other.repeatedInt32Wrapper_.Clone();
+      repeatedInt64Wrapper_ = other.repeatedInt64Wrapper_.Clone();
+      repeatedUint32Wrapper_ = other.repeatedUint32Wrapper_.Clone();
+      repeatedUint64Wrapper_ = other.repeatedUint64Wrapper_.Clone();
+      repeatedFloatWrapper_ = other.repeatedFloatWrapper_.Clone();
+      repeatedDoubleWrapper_ = other.repeatedDoubleWrapper_.Clone();
+      repeatedStringWrapper_ = other.repeatedStringWrapper_.Clone();
+      repeatedBytesWrapper_ = other.repeatedBytesWrapper_.Clone();
+      OptionalDuration = other.optionalDuration_ != null ? other.OptionalDuration.Clone() : null;
+      OptionalTimestamp = other.optionalTimestamp_ != null ? other.OptionalTimestamp.Clone() : null;
+      OptionalFieldMask = other.optionalFieldMask_ != null ? other.OptionalFieldMask.Clone() : null;
+      OptionalStruct = other.optionalStruct_ != null ? other.OptionalStruct.Clone() : null;
+      OptionalAny = other.optionalAny_ != null ? other.OptionalAny.Clone() : null;
+      OptionalValue = other.optionalValue_ != null ? other.OptionalValue.Clone() : null;
+      repeatedDuration_ = other.repeatedDuration_.Clone();
+      repeatedTimestamp_ = other.repeatedTimestamp_.Clone();
+      repeatedFieldmask_ = other.repeatedFieldmask_.Clone();
+      repeatedStruct_ = other.repeatedStruct_.Clone();
+      repeatedAny_ = other.repeatedAny_.Clone();
+      repeatedValue_ = other.repeatedValue_.Clone();
+      fieldname1_ = other.fieldname1_;
+      fieldName2_ = other.fieldName2_;
+      FieldName3_ = other.FieldName3_;
+      fieldName4_ = other.fieldName4_;
+      field0Name5_ = other.field0Name5_;
+      field0Name6_ = other.field0Name6_;
+      fieldName7_ = other.fieldName7_;
+      fieldName8_ = other.fieldName8_;
+      fieldName9_ = other.fieldName9_;
+      fieldName10_ = other.fieldName10_;
+      fIELDNAME11_ = other.fIELDNAME11_;
+      fIELDName12_ = other.fIELDName12_;
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.OneofUint32:
+          OneofUint32 = other.OneofUint32;
+          break;
+        case OneofFieldOneofCase.OneofNestedMessage:
+          OneofNestedMessage = other.OneofNestedMessage.Clone();
+          break;
+        case OneofFieldOneofCase.OneofString:
+          OneofString = other.OneofString;
+          break;
+        case OneofFieldOneofCase.OneofBytes:
+          OneofBytes = other.OneofBytes;
+          break;
+      }
+
+    }
+
+    public TestAllTypes Clone() {
+      return new TestAllTypes(this);
+    }
+
+    /// <summary>Field number for the "optional_int32" field.</summary>
+    public const int OptionalInt32FieldNumber = 1;
+    private int optionalInt32_;
+    /// <summary>
+    ///  Singular
+    /// </summary>
+    public int OptionalInt32 {
+      get { return optionalInt32_; }
+      set {
+        optionalInt32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int64" field.</summary>
+    public const int OptionalInt64FieldNumber = 2;
+    private long optionalInt64_;
+    public long OptionalInt64 {
+      get { return optionalInt64_; }
+      set {
+        optionalInt64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint32" field.</summary>
+    public const int OptionalUint32FieldNumber = 3;
+    private uint optionalUint32_;
+    public uint OptionalUint32 {
+      get { return optionalUint32_; }
+      set {
+        optionalUint32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint64" field.</summary>
+    public const int OptionalUint64FieldNumber = 4;
+    private ulong optionalUint64_;
+    public ulong OptionalUint64 {
+      get { return optionalUint64_; }
+      set {
+        optionalUint64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_sint32" field.</summary>
+    public const int OptionalSint32FieldNumber = 5;
+    private int optionalSint32_;
+    public int OptionalSint32 {
+      get { return optionalSint32_; }
+      set {
+        optionalSint32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_sint64" field.</summary>
+    public const int OptionalSint64FieldNumber = 6;
+    private long optionalSint64_;
+    public long OptionalSint64 {
+      get { return optionalSint64_; }
+      set {
+        optionalSint64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_fixed32" field.</summary>
+    public const int OptionalFixed32FieldNumber = 7;
+    private uint optionalFixed32_;
+    public uint OptionalFixed32 {
+      get { return optionalFixed32_; }
+      set {
+        optionalFixed32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_fixed64" field.</summary>
+    public const int OptionalFixed64FieldNumber = 8;
+    private ulong optionalFixed64_;
+    public ulong OptionalFixed64 {
+      get { return optionalFixed64_; }
+      set {
+        optionalFixed64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_sfixed32" field.</summary>
+    public const int OptionalSfixed32FieldNumber = 9;
+    private int optionalSfixed32_;
+    public int OptionalSfixed32 {
+      get { return optionalSfixed32_; }
+      set {
+        optionalSfixed32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_sfixed64" field.</summary>
+    public const int OptionalSfixed64FieldNumber = 10;
+    private long optionalSfixed64_;
+    public long OptionalSfixed64 {
+      get { return optionalSfixed64_; }
+      set {
+        optionalSfixed64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_float" field.</summary>
+    public const int OptionalFloatFieldNumber = 11;
+    private float optionalFloat_;
+    public float OptionalFloat {
+      get { return optionalFloat_; }
+      set {
+        optionalFloat_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_double" field.</summary>
+    public const int OptionalDoubleFieldNumber = 12;
+    private double optionalDouble_;
+    public double OptionalDouble {
+      get { return optionalDouble_; }
+      set {
+        optionalDouble_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_bool" field.</summary>
+    public const int OptionalBoolFieldNumber = 13;
+    private bool optionalBool_;
+    public bool OptionalBool {
+      get { return optionalBool_; }
+      set {
+        optionalBool_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_string" field.</summary>
+    public const int OptionalStringFieldNumber = 14;
+    private string optionalString_ = "";
+    public string OptionalString {
+      get { return optionalString_; }
+      set {
+        optionalString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "optional_bytes" field.</summary>
+    public const int OptionalBytesFieldNumber = 15;
+    private pb::ByteString optionalBytes_ = pb::ByteString.Empty;
+    public pb::ByteString OptionalBytes {
+      get { return optionalBytes_; }
+      set {
+        optionalBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "optional_nested_message" field.</summary>
+    public const int OptionalNestedMessageFieldNumber = 18;
+    private global::Conformance.TestAllTypes.Types.NestedMessage optionalNestedMessage_;
+    public global::Conformance.TestAllTypes.Types.NestedMessage OptionalNestedMessage {
+      get { return optionalNestedMessage_; }
+      set {
+        optionalNestedMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_foreign_message" field.</summary>
+    public const int OptionalForeignMessageFieldNumber = 19;
+    private global::Conformance.ForeignMessage optionalForeignMessage_;
+    public global::Conformance.ForeignMessage OptionalForeignMessage {
+      get { return optionalForeignMessage_; }
+      set {
+        optionalForeignMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_nested_enum" field.</summary>
+    public const int OptionalNestedEnumFieldNumber = 21;
+    private global::Conformance.TestAllTypes.Types.NestedEnum optionalNestedEnum_ = 0;
+    public global::Conformance.TestAllTypes.Types.NestedEnum OptionalNestedEnum {
+      get { return optionalNestedEnum_; }
+      set {
+        optionalNestedEnum_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_foreign_enum" field.</summary>
+    public const int OptionalForeignEnumFieldNumber = 22;
+    private global::Conformance.ForeignEnum optionalForeignEnum_ = 0;
+    public global::Conformance.ForeignEnum OptionalForeignEnum {
+      get { return optionalForeignEnum_; }
+      set {
+        optionalForeignEnum_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_string_piece" field.</summary>
+    public const int OptionalStringPieceFieldNumber = 24;
+    private string optionalStringPiece_ = "";
+    public string OptionalStringPiece {
+      get { return optionalStringPiece_; }
+      set {
+        optionalStringPiece_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "optional_cord" field.</summary>
+    public const int OptionalCordFieldNumber = 25;
+    private string optionalCord_ = "";
+    public string OptionalCord {
+      get { return optionalCord_; }
+      set {
+        optionalCord_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "recursive_message" field.</summary>
+    public const int RecursiveMessageFieldNumber = 27;
+    private global::Conformance.TestAllTypes recursiveMessage_;
+    public global::Conformance.TestAllTypes RecursiveMessage {
+      get { return recursiveMessage_; }
+      set {
+        recursiveMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_int32" field.</summary>
+    public const int RepeatedInt32FieldNumber = 31;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
+        = pb::FieldCodec.ForInt32(250);
+    private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Repeated
+    /// </summary>
+    public pbc::RepeatedField<int> RepeatedInt32 {
+      get { return repeatedInt32_; }
+    }
+
+    /// <summary>Field number for the "repeated_int64" field.</summary>
+    public const int RepeatedInt64FieldNumber = 32;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
+        = pb::FieldCodec.ForInt64(258);
+    private readonly pbc::RepeatedField<long> repeatedInt64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedInt64 {
+      get { return repeatedInt64_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint32" field.</summary>
+    public const int RepeatedUint32FieldNumber = 33;
+    private static readonly pb::FieldCodec<uint> _repeated_repeatedUint32_codec
+        = pb::FieldCodec.ForUInt32(266);
+    private readonly pbc::RepeatedField<uint> repeatedUint32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> RepeatedUint32 {
+      get { return repeatedUint32_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
+    public const int RepeatedUint64FieldNumber = 34;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
+        = pb::FieldCodec.ForUInt64(274);
+    private readonly pbc::RepeatedField<ulong> repeatedUint64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> RepeatedUint64 {
+      get { return repeatedUint64_; }
+    }
+
+    /// <summary>Field number for the "repeated_sint32" field.</summary>
+    public const int RepeatedSint32FieldNumber = 35;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedSint32_codec
+        = pb::FieldCodec.ForSInt32(282);
+    private readonly pbc::RepeatedField<int> repeatedSint32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> RepeatedSint32 {
+      get { return repeatedSint32_; }
+    }
+
+    /// <summary>Field number for the "repeated_sint64" field.</summary>
+    public const int RepeatedSint64FieldNumber = 36;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedSint64_codec
+        = pb::FieldCodec.ForSInt64(290);
+    private readonly pbc::RepeatedField<long> repeatedSint64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedSint64 {
+      get { return repeatedSint64_; }
+    }
+
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
+    public const int RepeatedFixed32FieldNumber = 37;
+    private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
+        = pb::FieldCodec.ForFixed32(298);
+    private readonly pbc::RepeatedField<uint> repeatedFixed32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> RepeatedFixed32 {
+      get { return repeatedFixed32_; }
+    }
+
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
+    public const int RepeatedFixed64FieldNumber = 38;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
+        = pb::FieldCodec.ForFixed64(306);
+    private readonly pbc::RepeatedField<ulong> repeatedFixed64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> RepeatedFixed64 {
+      get { return repeatedFixed64_; }
+    }
+
+    /// <summary>Field number for the "repeated_sfixed32" field.</summary>
+    public const int RepeatedSfixed32FieldNumber = 39;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedSfixed32_codec
+        = pb::FieldCodec.ForSFixed32(314);
+    private readonly pbc::RepeatedField<int> repeatedSfixed32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> RepeatedSfixed32 {
+      get { return repeatedSfixed32_; }
+    }
+
+    /// <summary>Field number for the "repeated_sfixed64" field.</summary>
+    public const int RepeatedSfixed64FieldNumber = 40;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedSfixed64_codec
+        = pb::FieldCodec.ForSFixed64(322);
+    private readonly pbc::RepeatedField<long> repeatedSfixed64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedSfixed64 {
+      get { return repeatedSfixed64_; }
+    }
+
+    /// <summary>Field number for the "repeated_float" field.</summary>
+    public const int RepeatedFloatFieldNumber = 41;
+    private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
+        = pb::FieldCodec.ForFloat(330);
+    private readonly pbc::RepeatedField<float> repeatedFloat_ = new pbc::RepeatedField<float>();
+    public pbc::RepeatedField<float> RepeatedFloat {
+      get { return repeatedFloat_; }
+    }
+
+    /// <summary>Field number for the "repeated_double" field.</summary>
+    public const int RepeatedDoubleFieldNumber = 42;
+    private static readonly pb::FieldCodec<double> _repeated_repeatedDouble_codec
+        = pb::FieldCodec.ForDouble(338);
+    private readonly pbc::RepeatedField<double> repeatedDouble_ = new pbc::RepeatedField<double>();
+    public pbc::RepeatedField<double> RepeatedDouble {
+      get { return repeatedDouble_; }
+    }
+
+    /// <summary>Field number for the "repeated_bool" field.</summary>
+    public const int RepeatedBoolFieldNumber = 43;
+    private static readonly pb::FieldCodec<bool> _repeated_repeatedBool_codec
+        = pb::FieldCodec.ForBool(346);
+    private readonly pbc::RepeatedField<bool> repeatedBool_ = new pbc::RepeatedField<bool>();
+    public pbc::RepeatedField<bool> RepeatedBool {
+      get { return repeatedBool_; }
+    }
+
+    /// <summary>Field number for the "repeated_string" field.</summary>
+    public const int RepeatedStringFieldNumber = 44;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedString_codec
+        = pb::FieldCodec.ForString(354);
+    private readonly pbc::RepeatedField<string> repeatedString_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedString {
+      get { return repeatedString_; }
+    }
+
+    /// <summary>Field number for the "repeated_bytes" field.</summary>
+    public const int RepeatedBytesFieldNumber = 45;
+    private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytes_codec
+        = pb::FieldCodec.ForBytes(362);
+    private readonly pbc::RepeatedField<pb::ByteString> repeatedBytes_ = new pbc::RepeatedField<pb::ByteString>();
+    public pbc::RepeatedField<pb::ByteString> RepeatedBytes {
+      get { return repeatedBytes_; }
+    }
+
+    /// <summary>Field number for the "repeated_nested_message" field.</summary>
+    public const int RepeatedNestedMessageFieldNumber = 48;
+    private static readonly pb::FieldCodec<global::Conformance.TestAllTypes.Types.NestedMessage> _repeated_repeatedNestedMessage_codec
+        = pb::FieldCodec.ForMessage(386, global::Conformance.TestAllTypes.Types.NestedMessage.Parser);
+    private readonly pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedMessage> repeatedNestedMessage_ = new pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedMessage>();
+    public pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedMessage> RepeatedNestedMessage {
+      get { return repeatedNestedMessage_; }
+    }
+
+    /// <summary>Field number for the "repeated_foreign_message" field.</summary>
+    public const int RepeatedForeignMessageFieldNumber = 49;
+    private static readonly pb::FieldCodec<global::Conformance.ForeignMessage> _repeated_repeatedForeignMessage_codec
+        = pb::FieldCodec.ForMessage(394, global::Conformance.ForeignMessage.Parser);
+    private readonly pbc::RepeatedField<global::Conformance.ForeignMessage> repeatedForeignMessage_ = new pbc::RepeatedField<global::Conformance.ForeignMessage>();
+    public pbc::RepeatedField<global::Conformance.ForeignMessage> RepeatedForeignMessage {
+      get { return repeatedForeignMessage_; }
+    }
+
+    /// <summary>Field number for the "repeated_nested_enum" field.</summary>
+    public const int RepeatedNestedEnumFieldNumber = 51;
+    private static readonly pb::FieldCodec<global::Conformance.TestAllTypes.Types.NestedEnum> _repeated_repeatedNestedEnum_codec
+        = pb::FieldCodec.ForEnum(410, x => (int) x, x => (global::Conformance.TestAllTypes.Types.NestedEnum) x);
+    private readonly pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedEnum> repeatedNestedEnum_ = new pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedEnum>();
+    public pbc::RepeatedField<global::Conformance.TestAllTypes.Types.NestedEnum> RepeatedNestedEnum {
+      get { return repeatedNestedEnum_; }
+    }
+
+    /// <summary>Field number for the "repeated_foreign_enum" field.</summary>
+    public const int RepeatedForeignEnumFieldNumber = 52;
+    private static readonly pb::FieldCodec<global::Conformance.ForeignEnum> _repeated_repeatedForeignEnum_codec
+        = pb::FieldCodec.ForEnum(418, x => (int) x, x => (global::Conformance.ForeignEnum) x);
+    private readonly pbc::RepeatedField<global::Conformance.ForeignEnum> repeatedForeignEnum_ = new pbc::RepeatedField<global::Conformance.ForeignEnum>();
+    public pbc::RepeatedField<global::Conformance.ForeignEnum> RepeatedForeignEnum {
+      get { return repeatedForeignEnum_; }
+    }
+
+    /// <summary>Field number for the "repeated_string_piece" field.</summary>
+    public const int RepeatedStringPieceFieldNumber = 54;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedStringPiece_codec
+        = pb::FieldCodec.ForString(434);
+    private readonly pbc::RepeatedField<string> repeatedStringPiece_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedStringPiece {
+      get { return repeatedStringPiece_; }
+    }
+
+    /// <summary>Field number for the "repeated_cord" field.</summary>
+    public const int RepeatedCordFieldNumber = 55;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedCord_codec
+        = pb::FieldCodec.ForString(442);
+    private readonly pbc::RepeatedField<string> repeatedCord_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedCord {
+      get { return repeatedCord_; }
+    }
+
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
+    public const int MapInt32Int32FieldNumber = 56;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 450);
+    private readonly pbc::MapField<int, int> mapInt32Int32_ = new pbc::MapField<int, int>();
+    /// <summary>
+    ///  Map
+    /// </summary>
+    public pbc::MapField<int, int> MapInt32Int32 {
+      get { return mapInt32Int32_; }
+    }
+
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
+    public const int MapInt64Int64FieldNumber = 57;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 458);
+    private readonly pbc::MapField<long, long> mapInt64Int64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapInt64Int64 {
+      get { return mapInt64Int64_; }
+    }
+
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
+    public const int MapUint32Uint32FieldNumber = 58;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 466);
+    private readonly pbc::MapField<uint, uint> mapUint32Uint32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapUint32Uint32 {
+      get { return mapUint32Uint32_; }
+    }
+
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
+    public const int MapUint64Uint64FieldNumber = 59;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 474);
+    private readonly pbc::MapField<ulong, ulong> mapUint64Uint64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapUint64Uint64 {
+      get { return mapUint64Uint64_; }
+    }
+
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
+    public const int MapSint32Sint32FieldNumber = 60;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 482);
+    private readonly pbc::MapField<int, int> mapSint32Sint32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSint32Sint32 {
+      get { return mapSint32Sint32_; }
+    }
+
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
+    public const int MapSint64Sint64FieldNumber = 61;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 490);
+    private readonly pbc::MapField<long, long> mapSint64Sint64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSint64Sint64 {
+      get { return mapSint64Sint64_; }
+    }
+
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
+    public const int MapFixed32Fixed32FieldNumber = 62;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 498);
+    private readonly pbc::MapField<uint, uint> mapFixed32Fixed32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapFixed32Fixed32 {
+      get { return mapFixed32Fixed32_; }
+    }
+
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
+    public const int MapFixed64Fixed64FieldNumber = 63;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 506);
+    private readonly pbc::MapField<ulong, ulong> mapFixed64Fixed64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapFixed64Fixed64 {
+      get { return mapFixed64Fixed64_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
+    public const int MapSfixed32Sfixed32FieldNumber = 64;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 514);
+    private readonly pbc::MapField<int, int> mapSfixed32Sfixed32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSfixed32Sfixed32 {
+      get { return mapSfixed32Sfixed32_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
+    public const int MapSfixed64Sfixed64FieldNumber = 65;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 522);
+    private readonly pbc::MapField<long, long> mapSfixed64Sfixed64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSfixed64Sfixed64 {
+      get { return mapSfixed64Sfixed64_; }
+    }
+
+    /// <summary>Field number for the "map_int32_float" field.</summary>
+    public const int MapInt32FloatFieldNumber = 66;
+    private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
+        = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 530);
+    private readonly pbc::MapField<int, float> mapInt32Float_ = new pbc::MapField<int, float>();
+    public pbc::MapField<int, float> MapInt32Float {
+      get { return mapInt32Float_; }
+    }
+
+    /// <summary>Field number for the "map_int32_double" field.</summary>
+    public const int MapInt32DoubleFieldNumber = 67;
+    private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
+        = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 538);
+    private readonly pbc::MapField<int, double> mapInt32Double_ = new pbc::MapField<int, double>();
+    public pbc::MapField<int, double> MapInt32Double {
+      get { return mapInt32Double_; }
+    }
+
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
+    public const int MapBoolBoolFieldNumber = 68;
+    private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
+        = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 546);
+    private readonly pbc::MapField<bool, bool> mapBoolBool_ = new pbc::MapField<bool, bool>();
+    public pbc::MapField<bool, bool> MapBoolBool {
+      get { return mapBoolBool_; }
+    }
+
+    /// <summary>Field number for the "map_string_string" field.</summary>
+    public const int MapStringStringFieldNumber = 69;
+    private static readonly pbc::MapField<string, string>.Codec _map_mapStringString_codec
+        = new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 554);
+    private readonly pbc::MapField<string, string> mapStringString_ = new pbc::MapField<string, string>();
+    public pbc::MapField<string, string> MapStringString {
+      get { return mapStringString_; }
+    }
+
+    /// <summary>Field number for the "map_string_bytes" field.</summary>
+    public const int MapStringBytesFieldNumber = 70;
+    private static readonly pbc::MapField<string, pb::ByteString>.Codec _map_mapStringBytes_codec
+        = new pbc::MapField<string, pb::ByteString>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForBytes(18), 562);
+    private readonly pbc::MapField<string, pb::ByteString> mapStringBytes_ = new pbc::MapField<string, pb::ByteString>();
+    public pbc::MapField<string, pb::ByteString> MapStringBytes {
+      get { return mapStringBytes_; }
+    }
+
+    /// <summary>Field number for the "map_string_nested_message" field.</summary>
+    public const int MapStringNestedMessageFieldNumber = 71;
+    private static readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage>.Codec _map_mapStringNestedMessage_codec
+        = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Conformance.TestAllTypes.Types.NestedMessage.Parser), 570);
+    private readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage> mapStringNestedMessage_ = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage>();
+    public pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage> MapStringNestedMessage {
+      get { return mapStringNestedMessage_; }
+    }
+
+    /// <summary>Field number for the "map_string_foreign_message" field.</summary>
+    public const int MapStringForeignMessageFieldNumber = 72;
+    private static readonly pbc::MapField<string, global::Conformance.ForeignMessage>.Codec _map_mapStringForeignMessage_codec
+        = new pbc::MapField<string, global::Conformance.ForeignMessage>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Conformance.ForeignMessage.Parser), 578);
+    private readonly pbc::MapField<string, global::Conformance.ForeignMessage> mapStringForeignMessage_ = new pbc::MapField<string, global::Conformance.ForeignMessage>();
+    public pbc::MapField<string, global::Conformance.ForeignMessage> MapStringForeignMessage {
+      get { return mapStringForeignMessage_; }
+    }
+
+    /// <summary>Field number for the "map_string_nested_enum" field.</summary>
+    public const int MapStringNestedEnumFieldNumber = 73;
+    private static readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum>.Codec _map_mapStringNestedEnum_codec
+        = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Conformance.TestAllTypes.Types.NestedEnum) x), 586);
+    private readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum> mapStringNestedEnum_ = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum>();
+    public pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum> MapStringNestedEnum {
+      get { return mapStringNestedEnum_; }
+    }
+
+    /// <summary>Field number for the "map_string_foreign_enum" field.</summary>
+    public const int MapStringForeignEnumFieldNumber = 74;
+    private static readonly pbc::MapField<string, global::Conformance.ForeignEnum>.Codec _map_mapStringForeignEnum_codec
+        = new pbc::MapField<string, global::Conformance.ForeignEnum>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Conformance.ForeignEnum) x), 594);
+    private readonly pbc::MapField<string, global::Conformance.ForeignEnum> mapStringForeignEnum_ = new pbc::MapField<string, global::Conformance.ForeignEnum>();
+    public pbc::MapField<string, global::Conformance.ForeignEnum> MapStringForeignEnum {
+      get { return mapStringForeignEnum_; }
+    }
+
+    /// <summary>Field number for the "oneof_uint32" field.</summary>
+    public const int OneofUint32FieldNumber = 111;
+    public uint OneofUint32 {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofUint32;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_nested_message" field.</summary>
+    public const int OneofNestedMessageFieldNumber = 112;
+    public global::Conformance.TestAllTypes.Types.NestedMessage OneofNestedMessage {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage ? (global::Conformance.TestAllTypes.Types.NestedMessage) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.OneofNestedMessage;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_string" field.</summary>
+    public const int OneofStringFieldNumber = 113;
+    public string OneofString {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
+      set {
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        oneofFieldCase_ = OneofFieldOneofCase.OneofString;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_bytes" field.</summary>
+    public const int OneofBytesFieldNumber = 114;
+    public pb::ByteString OneofBytes {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
+      set {
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
+      }
+    }
+
+    /// <summary>Field number for the "optional_bool_wrapper" field.</summary>
+    public const int OptionalBoolWrapperFieldNumber = 201;
+    private static readonly pb::FieldCodec<bool?> _single_optionalBoolWrapper_codec = pb::FieldCodec.ForStructWrapper<bool>(1610);
+    private bool? optionalBoolWrapper_;
+    /// <summary>
+    ///  Well-known types
+    /// </summary>
+    public bool? OptionalBoolWrapper {
+      get { return optionalBoolWrapper_; }
+      set {
+        optionalBoolWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int32_wrapper" field.</summary>
+    public const int OptionalInt32WrapperFieldNumber = 202;
+    private static readonly pb::FieldCodec<int?> _single_optionalInt32Wrapper_codec = pb::FieldCodec.ForStructWrapper<int>(1618);
+    private int? optionalInt32Wrapper_;
+    public int? OptionalInt32Wrapper {
+      get { return optionalInt32Wrapper_; }
+      set {
+        optionalInt32Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int64_wrapper" field.</summary>
+    public const int OptionalInt64WrapperFieldNumber = 203;
+    private static readonly pb::FieldCodec<long?> _single_optionalInt64Wrapper_codec = pb::FieldCodec.ForStructWrapper<long>(1626);
+    private long? optionalInt64Wrapper_;
+    public long? OptionalInt64Wrapper {
+      get { return optionalInt64Wrapper_; }
+      set {
+        optionalInt64Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint32_wrapper" field.</summary>
+    public const int OptionalUint32WrapperFieldNumber = 204;
+    private static readonly pb::FieldCodec<uint?> _single_optionalUint32Wrapper_codec = pb::FieldCodec.ForStructWrapper<uint>(1634);
+    private uint? optionalUint32Wrapper_;
+    public uint? OptionalUint32Wrapper {
+      get { return optionalUint32Wrapper_; }
+      set {
+        optionalUint32Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint64_wrapper" field.</summary>
+    public const int OptionalUint64WrapperFieldNumber = 205;
+    private static readonly pb::FieldCodec<ulong?> _single_optionalUint64Wrapper_codec = pb::FieldCodec.ForStructWrapper<ulong>(1642);
+    private ulong? optionalUint64Wrapper_;
+    public ulong? OptionalUint64Wrapper {
+      get { return optionalUint64Wrapper_; }
+      set {
+        optionalUint64Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_float_wrapper" field.</summary>
+    public const int OptionalFloatWrapperFieldNumber = 206;
+    private static readonly pb::FieldCodec<float?> _single_optionalFloatWrapper_codec = pb::FieldCodec.ForStructWrapper<float>(1650);
+    private float? optionalFloatWrapper_;
+    public float? OptionalFloatWrapper {
+      get { return optionalFloatWrapper_; }
+      set {
+        optionalFloatWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_double_wrapper" field.</summary>
+    public const int OptionalDoubleWrapperFieldNumber = 207;
+    private static readonly pb::FieldCodec<double?> _single_optionalDoubleWrapper_codec = pb::FieldCodec.ForStructWrapper<double>(1658);
+    private double? optionalDoubleWrapper_;
+    public double? OptionalDoubleWrapper {
+      get { return optionalDoubleWrapper_; }
+      set {
+        optionalDoubleWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_string_wrapper" field.</summary>
+    public const int OptionalStringWrapperFieldNumber = 208;
+    private static readonly pb::FieldCodec<string> _single_optionalStringWrapper_codec = pb::FieldCodec.ForClassWrapper<string>(1666);
+    private string optionalStringWrapper_;
+    public string OptionalStringWrapper {
+      get { return optionalStringWrapper_; }
+      set {
+        optionalStringWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_bytes_wrapper" field.</summary>
+    public const int OptionalBytesWrapperFieldNumber = 209;
+    private static readonly pb::FieldCodec<pb::ByteString> _single_optionalBytesWrapper_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(1674);
+    private pb::ByteString optionalBytesWrapper_;
+    public pb::ByteString OptionalBytesWrapper {
+      get { return optionalBytesWrapper_; }
+      set {
+        optionalBytesWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_bool_wrapper" field.</summary>
+    public const int RepeatedBoolWrapperFieldNumber = 211;
+    private static readonly pb::FieldCodec<bool?> _repeated_repeatedBoolWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<bool>(1690);
+    private readonly pbc::RepeatedField<bool?> repeatedBoolWrapper_ = new pbc::RepeatedField<bool?>();
+    public pbc::RepeatedField<bool?> RepeatedBoolWrapper {
+      get { return repeatedBoolWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_int32_wrapper" field.</summary>
+    public const int RepeatedInt32WrapperFieldNumber = 212;
+    private static readonly pb::FieldCodec<int?> _repeated_repeatedInt32Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<int>(1698);
+    private readonly pbc::RepeatedField<int?> repeatedInt32Wrapper_ = new pbc::RepeatedField<int?>();
+    public pbc::RepeatedField<int?> RepeatedInt32Wrapper {
+      get { return repeatedInt32Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_int64_wrapper" field.</summary>
+    public const int RepeatedInt64WrapperFieldNumber = 213;
+    private static readonly pb::FieldCodec<long?> _repeated_repeatedInt64Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<long>(1706);
+    private readonly pbc::RepeatedField<long?> repeatedInt64Wrapper_ = new pbc::RepeatedField<long?>();
+    public pbc::RepeatedField<long?> RepeatedInt64Wrapper {
+      get { return repeatedInt64Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint32_wrapper" field.</summary>
+    public const int RepeatedUint32WrapperFieldNumber = 214;
+    private static readonly pb::FieldCodec<uint?> _repeated_repeatedUint32Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<uint>(1714);
+    private readonly pbc::RepeatedField<uint?> repeatedUint32Wrapper_ = new pbc::RepeatedField<uint?>();
+    public pbc::RepeatedField<uint?> RepeatedUint32Wrapper {
+      get { return repeatedUint32Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint64_wrapper" field.</summary>
+    public const int RepeatedUint64WrapperFieldNumber = 215;
+    private static readonly pb::FieldCodec<ulong?> _repeated_repeatedUint64Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<ulong>(1722);
+    private readonly pbc::RepeatedField<ulong?> repeatedUint64Wrapper_ = new pbc::RepeatedField<ulong?>();
+    public pbc::RepeatedField<ulong?> RepeatedUint64Wrapper {
+      get { return repeatedUint64Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_float_wrapper" field.</summary>
+    public const int RepeatedFloatWrapperFieldNumber = 216;
+    private static readonly pb::FieldCodec<float?> _repeated_repeatedFloatWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<float>(1730);
+    private readonly pbc::RepeatedField<float?> repeatedFloatWrapper_ = new pbc::RepeatedField<float?>();
+    public pbc::RepeatedField<float?> RepeatedFloatWrapper {
+      get { return repeatedFloatWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_double_wrapper" field.</summary>
+    public const int RepeatedDoubleWrapperFieldNumber = 217;
+    private static readonly pb::FieldCodec<double?> _repeated_repeatedDoubleWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<double>(1738);
+    private readonly pbc::RepeatedField<double?> repeatedDoubleWrapper_ = new pbc::RepeatedField<double?>();
+    public pbc::RepeatedField<double?> RepeatedDoubleWrapper {
+      get { return repeatedDoubleWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_string_wrapper" field.</summary>
+    public const int RepeatedStringWrapperFieldNumber = 218;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedStringWrapper_codec
+        = pb::FieldCodec.ForClassWrapper<string>(1746);
+    private readonly pbc::RepeatedField<string> repeatedStringWrapper_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedStringWrapper {
+      get { return repeatedStringWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_bytes_wrapper" field.</summary>
+    public const int RepeatedBytesWrapperFieldNumber = 219;
+    private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytesWrapper_codec
+        = pb::FieldCodec.ForClassWrapper<pb::ByteString>(1754);
+    private readonly pbc::RepeatedField<pb::ByteString> repeatedBytesWrapper_ = new pbc::RepeatedField<pb::ByteString>();
+    public pbc::RepeatedField<pb::ByteString> RepeatedBytesWrapper {
+      get { return repeatedBytesWrapper_; }
+    }
+
+    /// <summary>Field number for the "optional_duration" field.</summary>
+    public const int OptionalDurationFieldNumber = 301;
+    private global::Google.Protobuf.WellKnownTypes.Duration optionalDuration_;
+    public global::Google.Protobuf.WellKnownTypes.Duration OptionalDuration {
+      get { return optionalDuration_; }
+      set {
+        optionalDuration_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_timestamp" field.</summary>
+    public const int OptionalTimestampFieldNumber = 302;
+    private global::Google.Protobuf.WellKnownTypes.Timestamp optionalTimestamp_;
+    public global::Google.Protobuf.WellKnownTypes.Timestamp OptionalTimestamp {
+      get { return optionalTimestamp_; }
+      set {
+        optionalTimestamp_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_field_mask" field.</summary>
+    public const int OptionalFieldMaskFieldNumber = 303;
+    private global::Google.Protobuf.WellKnownTypes.FieldMask optionalFieldMask_;
+    public global::Google.Protobuf.WellKnownTypes.FieldMask OptionalFieldMask {
+      get { return optionalFieldMask_; }
+      set {
+        optionalFieldMask_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_struct" field.</summary>
+    public const int OptionalStructFieldNumber = 304;
+    private global::Google.Protobuf.WellKnownTypes.Struct optionalStruct_;
+    public global::Google.Protobuf.WellKnownTypes.Struct OptionalStruct {
+      get { return optionalStruct_; }
+      set {
+        optionalStruct_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_any" field.</summary>
+    public const int OptionalAnyFieldNumber = 305;
+    private global::Google.Protobuf.WellKnownTypes.Any optionalAny_;
+    public global::Google.Protobuf.WellKnownTypes.Any OptionalAny {
+      get { return optionalAny_; }
+      set {
+        optionalAny_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_value" field.</summary>
+    public const int OptionalValueFieldNumber = 306;
+    private global::Google.Protobuf.WellKnownTypes.Value optionalValue_;
+    public global::Google.Protobuf.WellKnownTypes.Value OptionalValue {
+      get { return optionalValue_; }
+      set {
+        optionalValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_duration" field.</summary>
+    public const int RepeatedDurationFieldNumber = 311;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Duration> _repeated_repeatedDuration_codec
+        = pb::FieldCodec.ForMessage(2490, global::Google.Protobuf.WellKnownTypes.Duration.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> repeatedDuration_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> RepeatedDuration {
+      get { return repeatedDuration_; }
+    }
+
+    /// <summary>Field number for the "repeated_timestamp" field.</summary>
+    public const int RepeatedTimestampFieldNumber = 312;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Timestamp> _repeated_repeatedTimestamp_codec
+        = pb::FieldCodec.ForMessage(2498, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> repeatedTimestamp_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> RepeatedTimestamp {
+      get { return repeatedTimestamp_; }
+    }
+
+    /// <summary>Field number for the "repeated_fieldmask" field.</summary>
+    public const int RepeatedFieldmaskFieldNumber = 313;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.FieldMask> _repeated_repeatedFieldmask_codec
+        = pb::FieldCodec.ForMessage(2506, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> repeatedFieldmask_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> RepeatedFieldmask {
+      get { return repeatedFieldmask_; }
+    }
+
+    /// <summary>Field number for the "repeated_struct" field.</summary>
+    public const int RepeatedStructFieldNumber = 324;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Struct> _repeated_repeatedStruct_codec
+        = pb::FieldCodec.ForMessage(2594, global::Google.Protobuf.WellKnownTypes.Struct.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> repeatedStruct_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> RepeatedStruct {
+      get { return repeatedStruct_; }
+    }
+
+    /// <summary>Field number for the "repeated_any" field.</summary>
+    public const int RepeatedAnyFieldNumber = 315;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Any> _repeated_repeatedAny_codec
+        = pb::FieldCodec.ForMessage(2522, global::Google.Protobuf.WellKnownTypes.Any.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> repeatedAny_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> RepeatedAny {
+      get { return repeatedAny_; }
+    }
+
+    /// <summary>Field number for the "repeated_value" field.</summary>
+    public const int RepeatedValueFieldNumber = 316;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_repeatedValue_codec
+        = pb::FieldCodec.ForMessage(2530, global::Google.Protobuf.WellKnownTypes.Value.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> repeatedValue_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> RepeatedValue {
+      get { return repeatedValue_; }
+    }
+
+    /// <summary>Field number for the "fieldname1" field.</summary>
+    public const int Fieldname1FieldNumber = 401;
+    private int fieldname1_;
+    /// <summary>
+    ///  Test field-name-to-JSON-name convention.
+    /// </summary>
+    public int Fieldname1 {
+      get { return fieldname1_; }
+      set {
+        fieldname1_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_name2" field.</summary>
+    public const int FieldName2FieldNumber = 402;
+    private int fieldName2_;
+    public int FieldName2 {
+      get { return fieldName2_; }
+      set {
+        fieldName2_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "_field_name3" field.</summary>
+    public const int FieldName3FieldNumber = 403;
+    private int FieldName3_;
+    public int FieldName3 {
+      get { return FieldName3_; }
+      set {
+        FieldName3_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field__name4_" field.</summary>
+    public const int FieldName4FieldNumber = 404;
+    private int fieldName4_;
+    public int FieldName4 {
+      get { return fieldName4_; }
+      set {
+        fieldName4_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field0name5" field.</summary>
+    public const int Field0Name5FieldNumber = 405;
+    private int field0Name5_;
+    public int Field0Name5 {
+      get { return field0Name5_; }
+      set {
+        field0Name5_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_0_name6" field.</summary>
+    public const int Field0Name6FieldNumber = 406;
+    private int field0Name6_;
+    public int Field0Name6 {
+      get { return field0Name6_; }
+      set {
+        field0Name6_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "fieldName7" field.</summary>
+    public const int FieldName7FieldNumber = 407;
+    private int fieldName7_;
+    public int FieldName7 {
+      get { return fieldName7_; }
+      set {
+        fieldName7_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FieldName8" field.</summary>
+    public const int FieldName8FieldNumber = 408;
+    private int fieldName8_;
+    public int FieldName8 {
+      get { return fieldName8_; }
+      set {
+        fieldName8_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_Name9" field.</summary>
+    public const int FieldName9FieldNumber = 409;
+    private int fieldName9_;
+    public int FieldName9 {
+      get { return fieldName9_; }
+      set {
+        fieldName9_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "Field_Name10" field.</summary>
+    public const int FieldName10FieldNumber = 410;
+    private int fieldName10_;
+    public int FieldName10 {
+      get { return fieldName10_; }
+      set {
+        fieldName10_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FIELD_NAME11" field.</summary>
+    public const int FIELDNAME11FieldNumber = 411;
+    private int fIELDNAME11_;
+    public int FIELDNAME11 {
+      get { return fIELDNAME11_; }
+      set {
+        fIELDNAME11_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FIELD_name12" field.</summary>
+    public const int FIELDName12FieldNumber = 412;
+    private int fIELDName12_;
+    public int FIELDName12 {
+      get { return fIELDName12_; }
+      set {
+        fIELDName12_ = value;
+      }
+    }
+
+    private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
+    public enum OneofFieldOneofCase {
+      None = 0,
+      OneofUint32 = 111,
+      OneofNestedMessage = 112,
+      OneofString = 113,
+      OneofBytes = 114,
+    }
+    private OneofFieldOneofCase oneofFieldCase_ = OneofFieldOneofCase.None;
+    public OneofFieldOneofCase OneofFieldCase {
+      get { return oneofFieldCase_; }
+    }
+
+    public void ClearOneofField() {
+      oneofFieldCase_ = OneofFieldOneofCase.None;
+      oneofField_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestAllTypes);
+    }
+
+    public bool Equals(TestAllTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (OptionalInt32 != other.OptionalInt32) return false;
+      if (OptionalInt64 != other.OptionalInt64) return false;
+      if (OptionalUint32 != other.OptionalUint32) return false;
+      if (OptionalUint64 != other.OptionalUint64) return false;
+      if (OptionalSint32 != other.OptionalSint32) return false;
+      if (OptionalSint64 != other.OptionalSint64) return false;
+      if (OptionalFixed32 != other.OptionalFixed32) return false;
+      if (OptionalFixed64 != other.OptionalFixed64) return false;
+      if (OptionalSfixed32 != other.OptionalSfixed32) return false;
+      if (OptionalSfixed64 != other.OptionalSfixed64) return false;
+      if (OptionalFloat != other.OptionalFloat) return false;
+      if (OptionalDouble != other.OptionalDouble) return false;
+      if (OptionalBool != other.OptionalBool) return false;
+      if (OptionalString != other.OptionalString) return false;
+      if (OptionalBytes != other.OptionalBytes) return false;
+      if (!object.Equals(OptionalNestedMessage, other.OptionalNestedMessage)) return false;
+      if (!object.Equals(OptionalForeignMessage, other.OptionalForeignMessage)) return false;
+      if (OptionalNestedEnum != other.OptionalNestedEnum) return false;
+      if (OptionalForeignEnum != other.OptionalForeignEnum) return false;
+      if (OptionalStringPiece != other.OptionalStringPiece) return false;
+      if (OptionalCord != other.OptionalCord) return false;
+      if (!object.Equals(RecursiveMessage, other.RecursiveMessage)) return false;
+      if(!repeatedInt32_.Equals(other.repeatedInt32_)) return false;
+      if(!repeatedInt64_.Equals(other.repeatedInt64_)) return false;
+      if(!repeatedUint32_.Equals(other.repeatedUint32_)) return false;
+      if(!repeatedUint64_.Equals(other.repeatedUint64_)) return false;
+      if(!repeatedSint32_.Equals(other.repeatedSint32_)) return false;
+      if(!repeatedSint64_.Equals(other.repeatedSint64_)) return false;
+      if(!repeatedFixed32_.Equals(other.repeatedFixed32_)) return false;
+      if(!repeatedFixed64_.Equals(other.repeatedFixed64_)) return false;
+      if(!repeatedSfixed32_.Equals(other.repeatedSfixed32_)) return false;
+      if(!repeatedSfixed64_.Equals(other.repeatedSfixed64_)) return false;
+      if(!repeatedFloat_.Equals(other.repeatedFloat_)) return false;
+      if(!repeatedDouble_.Equals(other.repeatedDouble_)) return false;
+      if(!repeatedBool_.Equals(other.repeatedBool_)) return false;
+      if(!repeatedString_.Equals(other.repeatedString_)) return false;
+      if(!repeatedBytes_.Equals(other.repeatedBytes_)) return false;
+      if(!repeatedNestedMessage_.Equals(other.repeatedNestedMessage_)) return false;
+      if(!repeatedForeignMessage_.Equals(other.repeatedForeignMessage_)) return false;
+      if(!repeatedNestedEnum_.Equals(other.repeatedNestedEnum_)) return false;
+      if(!repeatedForeignEnum_.Equals(other.repeatedForeignEnum_)) return false;
+      if(!repeatedStringPiece_.Equals(other.repeatedStringPiece_)) return false;
+      if(!repeatedCord_.Equals(other.repeatedCord_)) return false;
+      if (!MapInt32Int32.Equals(other.MapInt32Int32)) return false;
+      if (!MapInt64Int64.Equals(other.MapInt64Int64)) return false;
+      if (!MapUint32Uint32.Equals(other.MapUint32Uint32)) return false;
+      if (!MapUint64Uint64.Equals(other.MapUint64Uint64)) return false;
+      if (!MapSint32Sint32.Equals(other.MapSint32Sint32)) return false;
+      if (!MapSint64Sint64.Equals(other.MapSint64Sint64)) return false;
+      if (!MapFixed32Fixed32.Equals(other.MapFixed32Fixed32)) return false;
+      if (!MapFixed64Fixed64.Equals(other.MapFixed64Fixed64)) return false;
+      if (!MapSfixed32Sfixed32.Equals(other.MapSfixed32Sfixed32)) return false;
+      if (!MapSfixed64Sfixed64.Equals(other.MapSfixed64Sfixed64)) return false;
+      if (!MapInt32Float.Equals(other.MapInt32Float)) return false;
+      if (!MapInt32Double.Equals(other.MapInt32Double)) return false;
+      if (!MapBoolBool.Equals(other.MapBoolBool)) return false;
+      if (!MapStringString.Equals(other.MapStringString)) return false;
+      if (!MapStringBytes.Equals(other.MapStringBytes)) return false;
+      if (!MapStringNestedMessage.Equals(other.MapStringNestedMessage)) return false;
+      if (!MapStringForeignMessage.Equals(other.MapStringForeignMessage)) return false;
+      if (!MapStringNestedEnum.Equals(other.MapStringNestedEnum)) return false;
+      if (!MapStringForeignEnum.Equals(other.MapStringForeignEnum)) return false;
+      if (OneofUint32 != other.OneofUint32) return false;
+      if (!object.Equals(OneofNestedMessage, other.OneofNestedMessage)) return false;
+      if (OneofString != other.OneofString) return false;
+      if (OneofBytes != other.OneofBytes) return false;
+      if (OptionalBoolWrapper != other.OptionalBoolWrapper) return false;
+      if (OptionalInt32Wrapper != other.OptionalInt32Wrapper) return false;
+      if (OptionalInt64Wrapper != other.OptionalInt64Wrapper) return false;
+      if (OptionalUint32Wrapper != other.OptionalUint32Wrapper) return false;
+      if (OptionalUint64Wrapper != other.OptionalUint64Wrapper) return false;
+      if (OptionalFloatWrapper != other.OptionalFloatWrapper) return false;
+      if (OptionalDoubleWrapper != other.OptionalDoubleWrapper) return false;
+      if (OptionalStringWrapper != other.OptionalStringWrapper) return false;
+      if (OptionalBytesWrapper != other.OptionalBytesWrapper) return false;
+      if(!repeatedBoolWrapper_.Equals(other.repeatedBoolWrapper_)) return false;
+      if(!repeatedInt32Wrapper_.Equals(other.repeatedInt32Wrapper_)) return false;
+      if(!repeatedInt64Wrapper_.Equals(other.repeatedInt64Wrapper_)) return false;
+      if(!repeatedUint32Wrapper_.Equals(other.repeatedUint32Wrapper_)) return false;
+      if(!repeatedUint64Wrapper_.Equals(other.repeatedUint64Wrapper_)) return false;
+      if(!repeatedFloatWrapper_.Equals(other.repeatedFloatWrapper_)) return false;
+      if(!repeatedDoubleWrapper_.Equals(other.repeatedDoubleWrapper_)) return false;
+      if(!repeatedStringWrapper_.Equals(other.repeatedStringWrapper_)) return false;
+      if(!repeatedBytesWrapper_.Equals(other.repeatedBytesWrapper_)) return false;
+      if (!object.Equals(OptionalDuration, other.OptionalDuration)) return false;
+      if (!object.Equals(OptionalTimestamp, other.OptionalTimestamp)) return false;
+      if (!object.Equals(OptionalFieldMask, other.OptionalFieldMask)) return false;
+      if (!object.Equals(OptionalStruct, other.OptionalStruct)) return false;
+      if (!object.Equals(OptionalAny, other.OptionalAny)) return false;
+      if (!object.Equals(OptionalValue, other.OptionalValue)) return false;
+      if(!repeatedDuration_.Equals(other.repeatedDuration_)) return false;
+      if(!repeatedTimestamp_.Equals(other.repeatedTimestamp_)) return false;
+      if(!repeatedFieldmask_.Equals(other.repeatedFieldmask_)) return false;
+      if(!repeatedStruct_.Equals(other.repeatedStruct_)) return false;
+      if(!repeatedAny_.Equals(other.repeatedAny_)) return false;
+      if(!repeatedValue_.Equals(other.repeatedValue_)) return false;
+      if (Fieldname1 != other.Fieldname1) return false;
+      if (FieldName2 != other.FieldName2) return false;
+      if (FieldName3 != other.FieldName3) return false;
+      if (FieldName4 != other.FieldName4) return false;
+      if (Field0Name5 != other.Field0Name5) return false;
+      if (Field0Name6 != other.Field0Name6) return false;
+      if (FieldName7 != other.FieldName7) return false;
+      if (FieldName8 != other.FieldName8) return false;
+      if (FieldName9 != other.FieldName9) return false;
+      if (FieldName10 != other.FieldName10) return false;
+      if (FIELDNAME11 != other.FIELDNAME11) return false;
+      if (FIELDName12 != other.FIELDName12) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (OptionalInt32 != 0) hash ^= OptionalInt32.GetHashCode();
+      if (OptionalInt64 != 0L) hash ^= OptionalInt64.GetHashCode();
+      if (OptionalUint32 != 0) hash ^= OptionalUint32.GetHashCode();
+      if (OptionalUint64 != 0UL) hash ^= OptionalUint64.GetHashCode();
+      if (OptionalSint32 != 0) hash ^= OptionalSint32.GetHashCode();
+      if (OptionalSint64 != 0L) hash ^= OptionalSint64.GetHashCode();
+      if (OptionalFixed32 != 0) hash ^= OptionalFixed32.GetHashCode();
+      if (OptionalFixed64 != 0UL) hash ^= OptionalFixed64.GetHashCode();
+      if (OptionalSfixed32 != 0) hash ^= OptionalSfixed32.GetHashCode();
+      if (OptionalSfixed64 != 0L) hash ^= OptionalSfixed64.GetHashCode();
+      if (OptionalFloat != 0F) hash ^= OptionalFloat.GetHashCode();
+      if (OptionalDouble != 0D) hash ^= OptionalDouble.GetHashCode();
+      if (OptionalBool != false) hash ^= OptionalBool.GetHashCode();
+      if (OptionalString.Length != 0) hash ^= OptionalString.GetHashCode();
+      if (OptionalBytes.Length != 0) hash ^= OptionalBytes.GetHashCode();
+      if (optionalNestedMessage_ != null) hash ^= OptionalNestedMessage.GetHashCode();
+      if (optionalForeignMessage_ != null) hash ^= OptionalForeignMessage.GetHashCode();
+      if (OptionalNestedEnum != 0) hash ^= OptionalNestedEnum.GetHashCode();
+      if (OptionalForeignEnum != 0) hash ^= OptionalForeignEnum.GetHashCode();
+      if (OptionalStringPiece.Length != 0) hash ^= OptionalStringPiece.GetHashCode();
+      if (OptionalCord.Length != 0) hash ^= OptionalCord.GetHashCode();
+      if (recursiveMessage_ != null) hash ^= RecursiveMessage.GetHashCode();
+      hash ^= repeatedInt32_.GetHashCode();
+      hash ^= repeatedInt64_.GetHashCode();
+      hash ^= repeatedUint32_.GetHashCode();
+      hash ^= repeatedUint64_.GetHashCode();
+      hash ^= repeatedSint32_.GetHashCode();
+      hash ^= repeatedSint64_.GetHashCode();
+      hash ^= repeatedFixed32_.GetHashCode();
+      hash ^= repeatedFixed64_.GetHashCode();
+      hash ^= repeatedSfixed32_.GetHashCode();
+      hash ^= repeatedSfixed64_.GetHashCode();
+      hash ^= repeatedFloat_.GetHashCode();
+      hash ^= repeatedDouble_.GetHashCode();
+      hash ^= repeatedBool_.GetHashCode();
+      hash ^= repeatedString_.GetHashCode();
+      hash ^= repeatedBytes_.GetHashCode();
+      hash ^= repeatedNestedMessage_.GetHashCode();
+      hash ^= repeatedForeignMessage_.GetHashCode();
+      hash ^= repeatedNestedEnum_.GetHashCode();
+      hash ^= repeatedForeignEnum_.GetHashCode();
+      hash ^= repeatedStringPiece_.GetHashCode();
+      hash ^= repeatedCord_.GetHashCode();
+      hash ^= MapInt32Int32.GetHashCode();
+      hash ^= MapInt64Int64.GetHashCode();
+      hash ^= MapUint32Uint32.GetHashCode();
+      hash ^= MapUint64Uint64.GetHashCode();
+      hash ^= MapSint32Sint32.GetHashCode();
+      hash ^= MapSint64Sint64.GetHashCode();
+      hash ^= MapFixed32Fixed32.GetHashCode();
+      hash ^= MapFixed64Fixed64.GetHashCode();
+      hash ^= MapSfixed32Sfixed32.GetHashCode();
+      hash ^= MapSfixed64Sfixed64.GetHashCode();
+      hash ^= MapInt32Float.GetHashCode();
+      hash ^= MapInt32Double.GetHashCode();
+      hash ^= MapBoolBool.GetHashCode();
+      hash ^= MapStringString.GetHashCode();
+      hash ^= MapStringBytes.GetHashCode();
+      hash ^= MapStringNestedMessage.GetHashCode();
+      hash ^= MapStringForeignMessage.GetHashCode();
+      hash ^= MapStringNestedEnum.GetHashCode();
+      hash ^= MapStringForeignEnum.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) hash ^= OneofUint32.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+      if (optionalBoolWrapper_ != null) hash ^= OptionalBoolWrapper.GetHashCode();
+      if (optionalInt32Wrapper_ != null) hash ^= OptionalInt32Wrapper.GetHashCode();
+      if (optionalInt64Wrapper_ != null) hash ^= OptionalInt64Wrapper.GetHashCode();
+      if (optionalUint32Wrapper_ != null) hash ^= OptionalUint32Wrapper.GetHashCode();
+      if (optionalUint64Wrapper_ != null) hash ^= OptionalUint64Wrapper.GetHashCode();
+      if (optionalFloatWrapper_ != null) hash ^= OptionalFloatWrapper.GetHashCode();
+      if (optionalDoubleWrapper_ != null) hash ^= OptionalDoubleWrapper.GetHashCode();
+      if (optionalStringWrapper_ != null) hash ^= OptionalStringWrapper.GetHashCode();
+      if (optionalBytesWrapper_ != null) hash ^= OptionalBytesWrapper.GetHashCode();
+      hash ^= repeatedBoolWrapper_.GetHashCode();
+      hash ^= repeatedInt32Wrapper_.GetHashCode();
+      hash ^= repeatedInt64Wrapper_.GetHashCode();
+      hash ^= repeatedUint32Wrapper_.GetHashCode();
+      hash ^= repeatedUint64Wrapper_.GetHashCode();
+      hash ^= repeatedFloatWrapper_.GetHashCode();
+      hash ^= repeatedDoubleWrapper_.GetHashCode();
+      hash ^= repeatedStringWrapper_.GetHashCode();
+      hash ^= repeatedBytesWrapper_.GetHashCode();
+      if (optionalDuration_ != null) hash ^= OptionalDuration.GetHashCode();
+      if (optionalTimestamp_ != null) hash ^= OptionalTimestamp.GetHashCode();
+      if (optionalFieldMask_ != null) hash ^= OptionalFieldMask.GetHashCode();
+      if (optionalStruct_ != null) hash ^= OptionalStruct.GetHashCode();
+      if (optionalAny_ != null) hash ^= OptionalAny.GetHashCode();
+      if (optionalValue_ != null) hash ^= OptionalValue.GetHashCode();
+      hash ^= repeatedDuration_.GetHashCode();
+      hash ^= repeatedTimestamp_.GetHashCode();
+      hash ^= repeatedFieldmask_.GetHashCode();
+      hash ^= repeatedStruct_.GetHashCode();
+      hash ^= repeatedAny_.GetHashCode();
+      hash ^= repeatedValue_.GetHashCode();
+      if (Fieldname1 != 0) hash ^= Fieldname1.GetHashCode();
+      if (FieldName2 != 0) hash ^= FieldName2.GetHashCode();
+      if (FieldName3 != 0) hash ^= FieldName3.GetHashCode();
+      if (FieldName4 != 0) hash ^= FieldName4.GetHashCode();
+      if (Field0Name5 != 0) hash ^= Field0Name5.GetHashCode();
+      if (Field0Name6 != 0) hash ^= Field0Name6.GetHashCode();
+      if (FieldName7 != 0) hash ^= FieldName7.GetHashCode();
+      if (FieldName8 != 0) hash ^= FieldName8.GetHashCode();
+      if (FieldName9 != 0) hash ^= FieldName9.GetHashCode();
+      if (FieldName10 != 0) hash ^= FieldName10.GetHashCode();
+      if (FIELDNAME11 != 0) hash ^= FIELDNAME11.GetHashCode();
+      if (FIELDName12 != 0) hash ^= FIELDName12.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (OptionalInt32 != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(OptionalInt32);
+      }
+      if (OptionalInt64 != 0L) {
+        output.WriteRawTag(16);
+        output.WriteInt64(OptionalInt64);
+      }
+      if (OptionalUint32 != 0) {
+        output.WriteRawTag(24);
+        output.WriteUInt32(OptionalUint32);
+      }
+      if (OptionalUint64 != 0UL) {
+        output.WriteRawTag(32);
+        output.WriteUInt64(OptionalUint64);
+      }
+      if (OptionalSint32 != 0) {
+        output.WriteRawTag(40);
+        output.WriteSInt32(OptionalSint32);
+      }
+      if (OptionalSint64 != 0L) {
+        output.WriteRawTag(48);
+        output.WriteSInt64(OptionalSint64);
+      }
+      if (OptionalFixed32 != 0) {
+        output.WriteRawTag(61);
+        output.WriteFixed32(OptionalFixed32);
+      }
+      if (OptionalFixed64 != 0UL) {
+        output.WriteRawTag(65);
+        output.WriteFixed64(OptionalFixed64);
+      }
+      if (OptionalSfixed32 != 0) {
+        output.WriteRawTag(77);
+        output.WriteSFixed32(OptionalSfixed32);
+      }
+      if (OptionalSfixed64 != 0L) {
+        output.WriteRawTag(81);
+        output.WriteSFixed64(OptionalSfixed64);
+      }
+      if (OptionalFloat != 0F) {
+        output.WriteRawTag(93);
+        output.WriteFloat(OptionalFloat);
+      }
+      if (OptionalDouble != 0D) {
+        output.WriteRawTag(97);
+        output.WriteDouble(OptionalDouble);
+      }
+      if (OptionalBool != false) {
+        output.WriteRawTag(104);
+        output.WriteBool(OptionalBool);
+      }
+      if (OptionalString.Length != 0) {
+        output.WriteRawTag(114);
+        output.WriteString(OptionalString);
+      }
+      if (OptionalBytes.Length != 0) {
+        output.WriteRawTag(122);
+        output.WriteBytes(OptionalBytes);
+      }
+      if (optionalNestedMessage_ != null) {
+        output.WriteRawTag(146, 1);
+        output.WriteMessage(OptionalNestedMessage);
+      }
+      if (optionalForeignMessage_ != null) {
+        output.WriteRawTag(154, 1);
+        output.WriteMessage(OptionalForeignMessage);
+      }
+      if (OptionalNestedEnum != 0) {
+        output.WriteRawTag(168, 1);
+        output.WriteEnum((int) OptionalNestedEnum);
+      }
+      if (OptionalForeignEnum != 0) {
+        output.WriteRawTag(176, 1);
+        output.WriteEnum((int) OptionalForeignEnum);
+      }
+      if (OptionalStringPiece.Length != 0) {
+        output.WriteRawTag(194, 1);
+        output.WriteString(OptionalStringPiece);
+      }
+      if (OptionalCord.Length != 0) {
+        output.WriteRawTag(202, 1);
+        output.WriteString(OptionalCord);
+      }
+      if (recursiveMessage_ != null) {
+        output.WriteRawTag(218, 1);
+        output.WriteMessage(RecursiveMessage);
+      }
+      repeatedInt32_.WriteTo(output, _repeated_repeatedInt32_codec);
+      repeatedInt64_.WriteTo(output, _repeated_repeatedInt64_codec);
+      repeatedUint32_.WriteTo(output, _repeated_repeatedUint32_codec);
+      repeatedUint64_.WriteTo(output, _repeated_repeatedUint64_codec);
+      repeatedSint32_.WriteTo(output, _repeated_repeatedSint32_codec);
+      repeatedSint64_.WriteTo(output, _repeated_repeatedSint64_codec);
+      repeatedFixed32_.WriteTo(output, _repeated_repeatedFixed32_codec);
+      repeatedFixed64_.WriteTo(output, _repeated_repeatedFixed64_codec);
+      repeatedSfixed32_.WriteTo(output, _repeated_repeatedSfixed32_codec);
+      repeatedSfixed64_.WriteTo(output, _repeated_repeatedSfixed64_codec);
+      repeatedFloat_.WriteTo(output, _repeated_repeatedFloat_codec);
+      repeatedDouble_.WriteTo(output, _repeated_repeatedDouble_codec);
+      repeatedBool_.WriteTo(output, _repeated_repeatedBool_codec);
+      repeatedString_.WriteTo(output, _repeated_repeatedString_codec);
+      repeatedBytes_.WriteTo(output, _repeated_repeatedBytes_codec);
+      repeatedNestedMessage_.WriteTo(output, _repeated_repeatedNestedMessage_codec);
+      repeatedForeignMessage_.WriteTo(output, _repeated_repeatedForeignMessage_codec);
+      repeatedNestedEnum_.WriteTo(output, _repeated_repeatedNestedEnum_codec);
+      repeatedForeignEnum_.WriteTo(output, _repeated_repeatedForeignEnum_codec);
+      repeatedStringPiece_.WriteTo(output, _repeated_repeatedStringPiece_codec);
+      repeatedCord_.WriteTo(output, _repeated_repeatedCord_codec);
+      mapInt32Int32_.WriteTo(output, _map_mapInt32Int32_codec);
+      mapInt64Int64_.WriteTo(output, _map_mapInt64Int64_codec);
+      mapUint32Uint32_.WriteTo(output, _map_mapUint32Uint32_codec);
+      mapUint64Uint64_.WriteTo(output, _map_mapUint64Uint64_codec);
+      mapSint32Sint32_.WriteTo(output, _map_mapSint32Sint32_codec);
+      mapSint64Sint64_.WriteTo(output, _map_mapSint64Sint64_codec);
+      mapFixed32Fixed32_.WriteTo(output, _map_mapFixed32Fixed32_codec);
+      mapFixed64Fixed64_.WriteTo(output, _map_mapFixed64Fixed64_codec);
+      mapSfixed32Sfixed32_.WriteTo(output, _map_mapSfixed32Sfixed32_codec);
+      mapSfixed64Sfixed64_.WriteTo(output, _map_mapSfixed64Sfixed64_codec);
+      mapInt32Float_.WriteTo(output, _map_mapInt32Float_codec);
+      mapInt32Double_.WriteTo(output, _map_mapInt32Double_codec);
+      mapBoolBool_.WriteTo(output, _map_mapBoolBool_codec);
+      mapStringString_.WriteTo(output, _map_mapStringString_codec);
+      mapStringBytes_.WriteTo(output, _map_mapStringBytes_codec);
+      mapStringNestedMessage_.WriteTo(output, _map_mapStringNestedMessage_codec);
+      mapStringForeignMessage_.WriteTo(output, _map_mapStringForeignMessage_codec);
+      mapStringNestedEnum_.WriteTo(output, _map_mapStringNestedEnum_codec);
+      mapStringForeignEnum_.WriteTo(output, _map_mapStringForeignEnum_codec);
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+        output.WriteRawTag(248, 6);
+        output.WriteUInt32(OneofUint32);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+        output.WriteRawTag(130, 7);
+        output.WriteMessage(OneofNestedMessage);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+        output.WriteRawTag(138, 7);
+        output.WriteString(OneofString);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+        output.WriteRawTag(146, 7);
+        output.WriteBytes(OneofBytes);
+      }
+      if (optionalBoolWrapper_ != null) {
+        _single_optionalBoolWrapper_codec.WriteTagAndValue(output, OptionalBoolWrapper);
+      }
+      if (optionalInt32Wrapper_ != null) {
+        _single_optionalInt32Wrapper_codec.WriteTagAndValue(output, OptionalInt32Wrapper);
+      }
+      if (optionalInt64Wrapper_ != null) {
+        _single_optionalInt64Wrapper_codec.WriteTagAndValue(output, OptionalInt64Wrapper);
+      }
+      if (optionalUint32Wrapper_ != null) {
+        _single_optionalUint32Wrapper_codec.WriteTagAndValue(output, OptionalUint32Wrapper);
+      }
+      if (optionalUint64Wrapper_ != null) {
+        _single_optionalUint64Wrapper_codec.WriteTagAndValue(output, OptionalUint64Wrapper);
+      }
+      if (optionalFloatWrapper_ != null) {
+        _single_optionalFloatWrapper_codec.WriteTagAndValue(output, OptionalFloatWrapper);
+      }
+      if (optionalDoubleWrapper_ != null) {
+        _single_optionalDoubleWrapper_codec.WriteTagAndValue(output, OptionalDoubleWrapper);
+      }
+      if (optionalStringWrapper_ != null) {
+        _single_optionalStringWrapper_codec.WriteTagAndValue(output, OptionalStringWrapper);
+      }
+      if (optionalBytesWrapper_ != null) {
+        _single_optionalBytesWrapper_codec.WriteTagAndValue(output, OptionalBytesWrapper);
+      }
+      repeatedBoolWrapper_.WriteTo(output, _repeated_repeatedBoolWrapper_codec);
+      repeatedInt32Wrapper_.WriteTo(output, _repeated_repeatedInt32Wrapper_codec);
+      repeatedInt64Wrapper_.WriteTo(output, _repeated_repeatedInt64Wrapper_codec);
+      repeatedUint32Wrapper_.WriteTo(output, _repeated_repeatedUint32Wrapper_codec);
+      repeatedUint64Wrapper_.WriteTo(output, _repeated_repeatedUint64Wrapper_codec);
+      repeatedFloatWrapper_.WriteTo(output, _repeated_repeatedFloatWrapper_codec);
+      repeatedDoubleWrapper_.WriteTo(output, _repeated_repeatedDoubleWrapper_codec);
+      repeatedStringWrapper_.WriteTo(output, _repeated_repeatedStringWrapper_codec);
+      repeatedBytesWrapper_.WriteTo(output, _repeated_repeatedBytesWrapper_codec);
+      if (optionalDuration_ != null) {
+        output.WriteRawTag(234, 18);
+        output.WriteMessage(OptionalDuration);
+      }
+      if (optionalTimestamp_ != null) {
+        output.WriteRawTag(242, 18);
+        output.WriteMessage(OptionalTimestamp);
+      }
+      if (optionalFieldMask_ != null) {
+        output.WriteRawTag(250, 18);
+        output.WriteMessage(OptionalFieldMask);
+      }
+      if (optionalStruct_ != null) {
+        output.WriteRawTag(130, 19);
+        output.WriteMessage(OptionalStruct);
+      }
+      if (optionalAny_ != null) {
+        output.WriteRawTag(138, 19);
+        output.WriteMessage(OptionalAny);
+      }
+      if (optionalValue_ != null) {
+        output.WriteRawTag(146, 19);
+        output.WriteMessage(OptionalValue);
+      }
+      repeatedDuration_.WriteTo(output, _repeated_repeatedDuration_codec);
+      repeatedTimestamp_.WriteTo(output, _repeated_repeatedTimestamp_codec);
+      repeatedFieldmask_.WriteTo(output, _repeated_repeatedFieldmask_codec);
+      repeatedAny_.WriteTo(output, _repeated_repeatedAny_codec);
+      repeatedValue_.WriteTo(output, _repeated_repeatedValue_codec);
+      repeatedStruct_.WriteTo(output, _repeated_repeatedStruct_codec);
+      if (Fieldname1 != 0) {
+        output.WriteRawTag(136, 25);
+        output.WriteInt32(Fieldname1);
+      }
+      if (FieldName2 != 0) {
+        output.WriteRawTag(144, 25);
+        output.WriteInt32(FieldName2);
+      }
+      if (FieldName3 != 0) {
+        output.WriteRawTag(152, 25);
+        output.WriteInt32(FieldName3);
+      }
+      if (FieldName4 != 0) {
+        output.WriteRawTag(160, 25);
+        output.WriteInt32(FieldName4);
+      }
+      if (Field0Name5 != 0) {
+        output.WriteRawTag(168, 25);
+        output.WriteInt32(Field0Name5);
+      }
+      if (Field0Name6 != 0) {
+        output.WriteRawTag(176, 25);
+        output.WriteInt32(Field0Name6);
+      }
+      if (FieldName7 != 0) {
+        output.WriteRawTag(184, 25);
+        output.WriteInt32(FieldName7);
+      }
+      if (FieldName8 != 0) {
+        output.WriteRawTag(192, 25);
+        output.WriteInt32(FieldName8);
+      }
+      if (FieldName9 != 0) {
+        output.WriteRawTag(200, 25);
+        output.WriteInt32(FieldName9);
+      }
+      if (FieldName10 != 0) {
+        output.WriteRawTag(208, 25);
+        output.WriteInt32(FieldName10);
+      }
+      if (FIELDNAME11 != 0) {
+        output.WriteRawTag(216, 25);
+        output.WriteInt32(FIELDNAME11);
+      }
+      if (FIELDName12 != 0) {
+        output.WriteRawTag(224, 25);
+        output.WriteInt32(FIELDName12);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (OptionalInt32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OptionalInt32);
+      }
+      if (OptionalInt64 != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(OptionalInt64);
+      }
+      if (OptionalUint32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt32Size(OptionalUint32);
+      }
+      if (OptionalUint64 != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(OptionalUint64);
+      }
+      if (OptionalSint32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeSInt32Size(OptionalSint32);
+      }
+      if (OptionalSint64 != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeSInt64Size(OptionalSint64);
+      }
+      if (OptionalFixed32 != 0) {
+        size += 1 + 4;
+      }
+      if (OptionalFixed64 != 0UL) {
+        size += 1 + 8;
+      }
+      if (OptionalSfixed32 != 0) {
+        size += 1 + 4;
+      }
+      if (OptionalSfixed64 != 0L) {
+        size += 1 + 8;
+      }
+      if (OptionalFloat != 0F) {
+        size += 1 + 4;
+      }
+      if (OptionalDouble != 0D) {
+        size += 1 + 8;
+      }
+      if (OptionalBool != false) {
+        size += 1 + 1;
+      }
+      if (OptionalString.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(OptionalString);
+      }
+      if (OptionalBytes.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(OptionalBytes);
+      }
+      if (optionalNestedMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalNestedMessage);
+      }
+      if (optionalForeignMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalForeignMessage);
+      }
+      if (OptionalNestedEnum != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OptionalNestedEnum);
+      }
+      if (OptionalForeignEnum != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OptionalForeignEnum);
+      }
+      if (OptionalStringPiece.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(OptionalStringPiece);
+      }
+      if (OptionalCord.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(OptionalCord);
+      }
+      if (recursiveMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(RecursiveMessage);
+      }
+      size += repeatedInt32_.CalculateSize(_repeated_repeatedInt32_codec);
+      size += repeatedInt64_.CalculateSize(_repeated_repeatedInt64_codec);
+      size += repeatedUint32_.CalculateSize(_repeated_repeatedUint32_codec);
+      size += repeatedUint64_.CalculateSize(_repeated_repeatedUint64_codec);
+      size += repeatedSint32_.CalculateSize(_repeated_repeatedSint32_codec);
+      size += repeatedSint64_.CalculateSize(_repeated_repeatedSint64_codec);
+      size += repeatedFixed32_.CalculateSize(_repeated_repeatedFixed32_codec);
+      size += repeatedFixed64_.CalculateSize(_repeated_repeatedFixed64_codec);
+      size += repeatedSfixed32_.CalculateSize(_repeated_repeatedSfixed32_codec);
+      size += repeatedSfixed64_.CalculateSize(_repeated_repeatedSfixed64_codec);
+      size += repeatedFloat_.CalculateSize(_repeated_repeatedFloat_codec);
+      size += repeatedDouble_.CalculateSize(_repeated_repeatedDouble_codec);
+      size += repeatedBool_.CalculateSize(_repeated_repeatedBool_codec);
+      size += repeatedString_.CalculateSize(_repeated_repeatedString_codec);
+      size += repeatedBytes_.CalculateSize(_repeated_repeatedBytes_codec);
+      size += repeatedNestedMessage_.CalculateSize(_repeated_repeatedNestedMessage_codec);
+      size += repeatedForeignMessage_.CalculateSize(_repeated_repeatedForeignMessage_codec);
+      size += repeatedNestedEnum_.CalculateSize(_repeated_repeatedNestedEnum_codec);
+      size += repeatedForeignEnum_.CalculateSize(_repeated_repeatedForeignEnum_codec);
+      size += repeatedStringPiece_.CalculateSize(_repeated_repeatedStringPiece_codec);
+      size += repeatedCord_.CalculateSize(_repeated_repeatedCord_codec);
+      size += mapInt32Int32_.CalculateSize(_map_mapInt32Int32_codec);
+      size += mapInt64Int64_.CalculateSize(_map_mapInt64Int64_codec);
+      size += mapUint32Uint32_.CalculateSize(_map_mapUint32Uint32_codec);
+      size += mapUint64Uint64_.CalculateSize(_map_mapUint64Uint64_codec);
+      size += mapSint32Sint32_.CalculateSize(_map_mapSint32Sint32_codec);
+      size += mapSint64Sint64_.CalculateSize(_map_mapSint64Sint64_codec);
+      size += mapFixed32Fixed32_.CalculateSize(_map_mapFixed32Fixed32_codec);
+      size += mapFixed64Fixed64_.CalculateSize(_map_mapFixed64Fixed64_codec);
+      size += mapSfixed32Sfixed32_.CalculateSize(_map_mapSfixed32Sfixed32_codec);
+      size += mapSfixed64Sfixed64_.CalculateSize(_map_mapSfixed64Sfixed64_codec);
+      size += mapInt32Float_.CalculateSize(_map_mapInt32Float_codec);
+      size += mapInt32Double_.CalculateSize(_map_mapInt32Double_codec);
+      size += mapBoolBool_.CalculateSize(_map_mapBoolBool_codec);
+      size += mapStringString_.CalculateSize(_map_mapStringString_codec);
+      size += mapStringBytes_.CalculateSize(_map_mapStringBytes_codec);
+      size += mapStringNestedMessage_.CalculateSize(_map_mapStringNestedMessage_codec);
+      size += mapStringForeignMessage_.CalculateSize(_map_mapStringForeignMessage_codec);
+      size += mapStringNestedEnum_.CalculateSize(_map_mapStringNestedEnum_codec);
+      size += mapStringForeignEnum_.CalculateSize(_map_mapStringForeignEnum_codec);
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+        size += 2 + pb::CodedOutputStream.ComputeUInt32Size(OneofUint32);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OneofNestedMessage);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(OneofString);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+        size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
+      }
+      if (optionalBoolWrapper_ != null) {
+        size += _single_optionalBoolWrapper_codec.CalculateSizeWithTag(OptionalBoolWrapper);
+      }
+      if (optionalInt32Wrapper_ != null) {
+        size += _single_optionalInt32Wrapper_codec.CalculateSizeWithTag(OptionalInt32Wrapper);
+      }
+      if (optionalInt64Wrapper_ != null) {
+        size += _single_optionalInt64Wrapper_codec.CalculateSizeWithTag(OptionalInt64Wrapper);
+      }
+      if (optionalUint32Wrapper_ != null) {
+        size += _single_optionalUint32Wrapper_codec.CalculateSizeWithTag(OptionalUint32Wrapper);
+      }
+      if (optionalUint64Wrapper_ != null) {
+        size += _single_optionalUint64Wrapper_codec.CalculateSizeWithTag(OptionalUint64Wrapper);
+      }
+      if (optionalFloatWrapper_ != null) {
+        size += _single_optionalFloatWrapper_codec.CalculateSizeWithTag(OptionalFloatWrapper);
+      }
+      if (optionalDoubleWrapper_ != null) {
+        size += _single_optionalDoubleWrapper_codec.CalculateSizeWithTag(OptionalDoubleWrapper);
+      }
+      if (optionalStringWrapper_ != null) {
+        size += _single_optionalStringWrapper_codec.CalculateSizeWithTag(OptionalStringWrapper);
+      }
+      if (optionalBytesWrapper_ != null) {
+        size += _single_optionalBytesWrapper_codec.CalculateSizeWithTag(OptionalBytesWrapper);
+      }
+      size += repeatedBoolWrapper_.CalculateSize(_repeated_repeatedBoolWrapper_codec);
+      size += repeatedInt32Wrapper_.CalculateSize(_repeated_repeatedInt32Wrapper_codec);
+      size += repeatedInt64Wrapper_.CalculateSize(_repeated_repeatedInt64Wrapper_codec);
+      size += repeatedUint32Wrapper_.CalculateSize(_repeated_repeatedUint32Wrapper_codec);
+      size += repeatedUint64Wrapper_.CalculateSize(_repeated_repeatedUint64Wrapper_codec);
+      size += repeatedFloatWrapper_.CalculateSize(_repeated_repeatedFloatWrapper_codec);
+      size += repeatedDoubleWrapper_.CalculateSize(_repeated_repeatedDoubleWrapper_codec);
+      size += repeatedStringWrapper_.CalculateSize(_repeated_repeatedStringWrapper_codec);
+      size += repeatedBytesWrapper_.CalculateSize(_repeated_repeatedBytesWrapper_codec);
+      if (optionalDuration_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalDuration);
+      }
+      if (optionalTimestamp_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalTimestamp);
+      }
+      if (optionalFieldMask_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalFieldMask);
+      }
+      if (optionalStruct_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalStruct);
+      }
+      if (optionalAny_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalAny);
+      }
+      if (optionalValue_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalValue);
+      }
+      size += repeatedDuration_.CalculateSize(_repeated_repeatedDuration_codec);
+      size += repeatedTimestamp_.CalculateSize(_repeated_repeatedTimestamp_codec);
+      size += repeatedFieldmask_.CalculateSize(_repeated_repeatedFieldmask_codec);
+      size += repeatedStruct_.CalculateSize(_repeated_repeatedStruct_codec);
+      size += repeatedAny_.CalculateSize(_repeated_repeatedAny_codec);
+      size += repeatedValue_.CalculateSize(_repeated_repeatedValue_codec);
+      if (Fieldname1 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Fieldname1);
+      }
+      if (FieldName2 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName2);
+      }
+      if (FieldName3 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName3);
+      }
+      if (FieldName4 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName4);
+      }
+      if (Field0Name5 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Field0Name5);
+      }
+      if (Field0Name6 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Field0Name6);
+      }
+      if (FieldName7 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName7);
+      }
+      if (FieldName8 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName8);
+      }
+      if (FieldName9 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName9);
+      }
+      if (FieldName10 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName10);
+      }
+      if (FIELDNAME11 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FIELDNAME11);
+      }
+      if (FIELDName12 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FIELDName12);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestAllTypes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.OptionalInt32 != 0) {
+        OptionalInt32 = other.OptionalInt32;
+      }
+      if (other.OptionalInt64 != 0L) {
+        OptionalInt64 = other.OptionalInt64;
+      }
+      if (other.OptionalUint32 != 0) {
+        OptionalUint32 = other.OptionalUint32;
+      }
+      if (other.OptionalUint64 != 0UL) {
+        OptionalUint64 = other.OptionalUint64;
+      }
+      if (other.OptionalSint32 != 0) {
+        OptionalSint32 = other.OptionalSint32;
+      }
+      if (other.OptionalSint64 != 0L) {
+        OptionalSint64 = other.OptionalSint64;
+      }
+      if (other.OptionalFixed32 != 0) {
+        OptionalFixed32 = other.OptionalFixed32;
+      }
+      if (other.OptionalFixed64 != 0UL) {
+        OptionalFixed64 = other.OptionalFixed64;
+      }
+      if (other.OptionalSfixed32 != 0) {
+        OptionalSfixed32 = other.OptionalSfixed32;
+      }
+      if (other.OptionalSfixed64 != 0L) {
+        OptionalSfixed64 = other.OptionalSfixed64;
+      }
+      if (other.OptionalFloat != 0F) {
+        OptionalFloat = other.OptionalFloat;
+      }
+      if (other.OptionalDouble != 0D) {
+        OptionalDouble = other.OptionalDouble;
+      }
+      if (other.OptionalBool != false) {
+        OptionalBool = other.OptionalBool;
+      }
+      if (other.OptionalString.Length != 0) {
+        OptionalString = other.OptionalString;
+      }
+      if (other.OptionalBytes.Length != 0) {
+        OptionalBytes = other.OptionalBytes;
+      }
+      if (other.optionalNestedMessage_ != null) {
+        if (optionalNestedMessage_ == null) {
+          optionalNestedMessage_ = new global::Conformance.TestAllTypes.Types.NestedMessage();
+        }
+        OptionalNestedMessage.MergeFrom(other.OptionalNestedMessage);
+      }
+      if (other.optionalForeignMessage_ != null) {
+        if (optionalForeignMessage_ == null) {
+          optionalForeignMessage_ = new global::Conformance.ForeignMessage();
+        }
+        OptionalForeignMessage.MergeFrom(other.OptionalForeignMessage);
+      }
+      if (other.OptionalNestedEnum != 0) {
+        OptionalNestedEnum = other.OptionalNestedEnum;
+      }
+      if (other.OptionalForeignEnum != 0) {
+        OptionalForeignEnum = other.OptionalForeignEnum;
+      }
+      if (other.OptionalStringPiece.Length != 0) {
+        OptionalStringPiece = other.OptionalStringPiece;
+      }
+      if (other.OptionalCord.Length != 0) {
+        OptionalCord = other.OptionalCord;
+      }
+      if (other.recursiveMessage_ != null) {
+        if (recursiveMessage_ == null) {
+          recursiveMessage_ = new global::Conformance.TestAllTypes();
+        }
+        RecursiveMessage.MergeFrom(other.RecursiveMessage);
+      }
+      repeatedInt32_.Add(other.repeatedInt32_);
+      repeatedInt64_.Add(other.repeatedInt64_);
+      repeatedUint32_.Add(other.repeatedUint32_);
+      repeatedUint64_.Add(other.repeatedUint64_);
+      repeatedSint32_.Add(other.repeatedSint32_);
+      repeatedSint64_.Add(other.repeatedSint64_);
+      repeatedFixed32_.Add(other.repeatedFixed32_);
+      repeatedFixed64_.Add(other.repeatedFixed64_);
+      repeatedSfixed32_.Add(other.repeatedSfixed32_);
+      repeatedSfixed64_.Add(other.repeatedSfixed64_);
+      repeatedFloat_.Add(other.repeatedFloat_);
+      repeatedDouble_.Add(other.repeatedDouble_);
+      repeatedBool_.Add(other.repeatedBool_);
+      repeatedString_.Add(other.repeatedString_);
+      repeatedBytes_.Add(other.repeatedBytes_);
+      repeatedNestedMessage_.Add(other.repeatedNestedMessage_);
+      repeatedForeignMessage_.Add(other.repeatedForeignMessage_);
+      repeatedNestedEnum_.Add(other.repeatedNestedEnum_);
+      repeatedForeignEnum_.Add(other.repeatedForeignEnum_);
+      repeatedStringPiece_.Add(other.repeatedStringPiece_);
+      repeatedCord_.Add(other.repeatedCord_);
+      mapInt32Int32_.Add(other.mapInt32Int32_);
+      mapInt64Int64_.Add(other.mapInt64Int64_);
+      mapUint32Uint32_.Add(other.mapUint32Uint32_);
+      mapUint64Uint64_.Add(other.mapUint64Uint64_);
+      mapSint32Sint32_.Add(other.mapSint32Sint32_);
+      mapSint64Sint64_.Add(other.mapSint64Sint64_);
+      mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
+      mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
+      mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
+      mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
+      mapInt32Float_.Add(other.mapInt32Float_);
+      mapInt32Double_.Add(other.mapInt32Double_);
+      mapBoolBool_.Add(other.mapBoolBool_);
+      mapStringString_.Add(other.mapStringString_);
+      mapStringBytes_.Add(other.mapStringBytes_);
+      mapStringNestedMessage_.Add(other.mapStringNestedMessage_);
+      mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
+      mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
+      mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
+      if (other.optionalBoolWrapper_ != null) {
+        if (optionalBoolWrapper_ == null || other.OptionalBoolWrapper != false) {
+          OptionalBoolWrapper = other.OptionalBoolWrapper;
+        }
+      }
+      if (other.optionalInt32Wrapper_ != null) {
+        if (optionalInt32Wrapper_ == null || other.OptionalInt32Wrapper != 0) {
+          OptionalInt32Wrapper = other.OptionalInt32Wrapper;
+        }
+      }
+      if (other.optionalInt64Wrapper_ != null) {
+        if (optionalInt64Wrapper_ == null || other.OptionalInt64Wrapper != 0L) {
+          OptionalInt64Wrapper = other.OptionalInt64Wrapper;
+        }
+      }
+      if (other.optionalUint32Wrapper_ != null) {
+        if (optionalUint32Wrapper_ == null || other.OptionalUint32Wrapper != 0) {
+          OptionalUint32Wrapper = other.OptionalUint32Wrapper;
+        }
+      }
+      if (other.optionalUint64Wrapper_ != null) {
+        if (optionalUint64Wrapper_ == null || other.OptionalUint64Wrapper != 0UL) {
+          OptionalUint64Wrapper = other.OptionalUint64Wrapper;
+        }
+      }
+      if (other.optionalFloatWrapper_ != null) {
+        if (optionalFloatWrapper_ == null || other.OptionalFloatWrapper != 0F) {
+          OptionalFloatWrapper = other.OptionalFloatWrapper;
+        }
+      }
+      if (other.optionalDoubleWrapper_ != null) {
+        if (optionalDoubleWrapper_ == null || other.OptionalDoubleWrapper != 0D) {
+          OptionalDoubleWrapper = other.OptionalDoubleWrapper;
+        }
+      }
+      if (other.optionalStringWrapper_ != null) {
+        if (optionalStringWrapper_ == null || other.OptionalStringWrapper != "") {
+          OptionalStringWrapper = other.OptionalStringWrapper;
+        }
+      }
+      if (other.optionalBytesWrapper_ != null) {
+        if (optionalBytesWrapper_ == null || other.OptionalBytesWrapper != pb::ByteString.Empty) {
+          OptionalBytesWrapper = other.OptionalBytesWrapper;
+        }
+      }
+      repeatedBoolWrapper_.Add(other.repeatedBoolWrapper_);
+      repeatedInt32Wrapper_.Add(other.repeatedInt32Wrapper_);
+      repeatedInt64Wrapper_.Add(other.repeatedInt64Wrapper_);
+      repeatedUint32Wrapper_.Add(other.repeatedUint32Wrapper_);
+      repeatedUint64Wrapper_.Add(other.repeatedUint64Wrapper_);
+      repeatedFloatWrapper_.Add(other.repeatedFloatWrapper_);
+      repeatedDoubleWrapper_.Add(other.repeatedDoubleWrapper_);
+      repeatedStringWrapper_.Add(other.repeatedStringWrapper_);
+      repeatedBytesWrapper_.Add(other.repeatedBytesWrapper_);
+      if (other.optionalDuration_ != null) {
+        if (optionalDuration_ == null) {
+          optionalDuration_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+        }
+        OptionalDuration.MergeFrom(other.OptionalDuration);
+      }
+      if (other.optionalTimestamp_ != null) {
+        if (optionalTimestamp_ == null) {
+          optionalTimestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+        }
+        OptionalTimestamp.MergeFrom(other.OptionalTimestamp);
+      }
+      if (other.optionalFieldMask_ != null) {
+        if (optionalFieldMask_ == null) {
+          optionalFieldMask_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+        }
+        OptionalFieldMask.MergeFrom(other.OptionalFieldMask);
+      }
+      if (other.optionalStruct_ != null) {
+        if (optionalStruct_ == null) {
+          optionalStruct_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+        }
+        OptionalStruct.MergeFrom(other.OptionalStruct);
+      }
+      if (other.optionalAny_ != null) {
+        if (optionalAny_ == null) {
+          optionalAny_ = new global::Google.Protobuf.WellKnownTypes.Any();
+        }
+        OptionalAny.MergeFrom(other.OptionalAny);
+      }
+      if (other.optionalValue_ != null) {
+        if (optionalValue_ == null) {
+          optionalValue_ = new global::Google.Protobuf.WellKnownTypes.Value();
+        }
+        OptionalValue.MergeFrom(other.OptionalValue);
+      }
+      repeatedDuration_.Add(other.repeatedDuration_);
+      repeatedTimestamp_.Add(other.repeatedTimestamp_);
+      repeatedFieldmask_.Add(other.repeatedFieldmask_);
+      repeatedStruct_.Add(other.repeatedStruct_);
+      repeatedAny_.Add(other.repeatedAny_);
+      repeatedValue_.Add(other.repeatedValue_);
+      if (other.Fieldname1 != 0) {
+        Fieldname1 = other.Fieldname1;
+      }
+      if (other.FieldName2 != 0) {
+        FieldName2 = other.FieldName2;
+      }
+      if (other.FieldName3 != 0) {
+        FieldName3 = other.FieldName3;
+      }
+      if (other.FieldName4 != 0) {
+        FieldName4 = other.FieldName4;
+      }
+      if (other.Field0Name5 != 0) {
+        Field0Name5 = other.Field0Name5;
+      }
+      if (other.Field0Name6 != 0) {
+        Field0Name6 = other.Field0Name6;
+      }
+      if (other.FieldName7 != 0) {
+        FieldName7 = other.FieldName7;
+      }
+      if (other.FieldName8 != 0) {
+        FieldName8 = other.FieldName8;
+      }
+      if (other.FieldName9 != 0) {
+        FieldName9 = other.FieldName9;
+      }
+      if (other.FieldName10 != 0) {
+        FieldName10 = other.FieldName10;
+      }
+      if (other.FIELDNAME11 != 0) {
+        FIELDNAME11 = other.FIELDNAME11;
+      }
+      if (other.FIELDName12 != 0) {
+        FIELDName12 = other.FIELDName12;
+      }
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.OneofUint32:
+          OneofUint32 = other.OneofUint32;
+          break;
+        case OneofFieldOneofCase.OneofNestedMessage:
+          OneofNestedMessage = other.OneofNestedMessage;
+          break;
+        case OneofFieldOneofCase.OneofString:
+          OneofString = other.OneofString;
+          break;
+        case OneofFieldOneofCase.OneofBytes:
+          OneofBytes = other.OneofBytes;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            OptionalInt32 = input.ReadInt32();
+            break;
+          }
+          case 16: {
+            OptionalInt64 = input.ReadInt64();
+            break;
+          }
+          case 24: {
+            OptionalUint32 = input.ReadUInt32();
+            break;
+          }
+          case 32: {
+            OptionalUint64 = input.ReadUInt64();
+            break;
+          }
+          case 40: {
+            OptionalSint32 = input.ReadSInt32();
+            break;
+          }
+          case 48: {
+            OptionalSint64 = input.ReadSInt64();
+            break;
+          }
+          case 61: {
+            OptionalFixed32 = input.ReadFixed32();
+            break;
+          }
+          case 65: {
+            OptionalFixed64 = input.ReadFixed64();
+            break;
+          }
+          case 77: {
+            OptionalSfixed32 = input.ReadSFixed32();
+            break;
+          }
+          case 81: {
+            OptionalSfixed64 = input.ReadSFixed64();
+            break;
+          }
+          case 93: {
+            OptionalFloat = input.ReadFloat();
+            break;
+          }
+          case 97: {
+            OptionalDouble = input.ReadDouble();
+            break;
+          }
+          case 104: {
+            OptionalBool = input.ReadBool();
+            break;
+          }
+          case 114: {
+            OptionalString = input.ReadString();
+            break;
+          }
+          case 122: {
+            OptionalBytes = input.ReadBytes();
+            break;
+          }
+          case 146: {
+            if (optionalNestedMessage_ == null) {
+              optionalNestedMessage_ = new global::Conformance.TestAllTypes.Types.NestedMessage();
+            }
+            input.ReadMessage(optionalNestedMessage_);
+            break;
+          }
+          case 154: {
+            if (optionalForeignMessage_ == null) {
+              optionalForeignMessage_ = new global::Conformance.ForeignMessage();
+            }
+            input.ReadMessage(optionalForeignMessage_);
+            break;
+          }
+          case 168: {
+            optionalNestedEnum_ = (global::Conformance.TestAllTypes.Types.NestedEnum) input.ReadEnum();
+            break;
+          }
+          case 176: {
+            optionalForeignEnum_ = (global::Conformance.ForeignEnum) input.ReadEnum();
+            break;
+          }
+          case 194: {
+            OptionalStringPiece = input.ReadString();
+            break;
+          }
+          case 202: {
+            OptionalCord = input.ReadString();
+            break;
+          }
+          case 218: {
+            if (recursiveMessage_ == null) {
+              recursiveMessage_ = new global::Conformance.TestAllTypes();
+            }
+            input.ReadMessage(recursiveMessage_);
+            break;
+          }
+          case 250:
+          case 248: {
+            repeatedInt32_.AddEntriesFrom(input, _repeated_repeatedInt32_codec);
+            break;
+          }
+          case 258:
+          case 256: {
+            repeatedInt64_.AddEntriesFrom(input, _repeated_repeatedInt64_codec);
+            break;
+          }
+          case 266:
+          case 264: {
+            repeatedUint32_.AddEntriesFrom(input, _repeated_repeatedUint32_codec);
+            break;
+          }
+          case 274:
+          case 272: {
+            repeatedUint64_.AddEntriesFrom(input, _repeated_repeatedUint64_codec);
+            break;
+          }
+          case 282:
+          case 280: {
+            repeatedSint32_.AddEntriesFrom(input, _repeated_repeatedSint32_codec);
+            break;
+          }
+          case 290:
+          case 288: {
+            repeatedSint64_.AddEntriesFrom(input, _repeated_repeatedSint64_codec);
+            break;
+          }
+          case 298:
+          case 301: {
+            repeatedFixed32_.AddEntriesFrom(input, _repeated_repeatedFixed32_codec);
+            break;
+          }
+          case 306:
+          case 305: {
+            repeatedFixed64_.AddEntriesFrom(input, _repeated_repeatedFixed64_codec);
+            break;
+          }
+          case 314:
+          case 317: {
+            repeatedSfixed32_.AddEntriesFrom(input, _repeated_repeatedSfixed32_codec);
+            break;
+          }
+          case 322:
+          case 321: {
+            repeatedSfixed64_.AddEntriesFrom(input, _repeated_repeatedSfixed64_codec);
+            break;
+          }
+          case 330:
+          case 333: {
+            repeatedFloat_.AddEntriesFrom(input, _repeated_repeatedFloat_codec);
+            break;
+          }
+          case 338:
+          case 337: {
+            repeatedDouble_.AddEntriesFrom(input, _repeated_repeatedDouble_codec);
+            break;
+          }
+          case 346:
+          case 344: {
+            repeatedBool_.AddEntriesFrom(input, _repeated_repeatedBool_codec);
+            break;
+          }
+          case 354: {
+            repeatedString_.AddEntriesFrom(input, _repeated_repeatedString_codec);
+            break;
+          }
+          case 362: {
+            repeatedBytes_.AddEntriesFrom(input, _repeated_repeatedBytes_codec);
+            break;
+          }
+          case 386: {
+            repeatedNestedMessage_.AddEntriesFrom(input, _repeated_repeatedNestedMessage_codec);
+            break;
+          }
+          case 394: {
+            repeatedForeignMessage_.AddEntriesFrom(input, _repeated_repeatedForeignMessage_codec);
+            break;
+          }
+          case 410:
+          case 408: {
+            repeatedNestedEnum_.AddEntriesFrom(input, _repeated_repeatedNestedEnum_codec);
+            break;
+          }
+          case 418:
+          case 416: {
+            repeatedForeignEnum_.AddEntriesFrom(input, _repeated_repeatedForeignEnum_codec);
+            break;
+          }
+          case 434: {
+            repeatedStringPiece_.AddEntriesFrom(input, _repeated_repeatedStringPiece_codec);
+            break;
+          }
+          case 442: {
+            repeatedCord_.AddEntriesFrom(input, _repeated_repeatedCord_codec);
+            break;
+          }
+          case 450: {
+            mapInt32Int32_.AddEntriesFrom(input, _map_mapInt32Int32_codec);
+            break;
+          }
+          case 458: {
+            mapInt64Int64_.AddEntriesFrom(input, _map_mapInt64Int64_codec);
+            break;
+          }
+          case 466: {
+            mapUint32Uint32_.AddEntriesFrom(input, _map_mapUint32Uint32_codec);
+            break;
+          }
+          case 474: {
+            mapUint64Uint64_.AddEntriesFrom(input, _map_mapUint64Uint64_codec);
+            break;
+          }
+          case 482: {
+            mapSint32Sint32_.AddEntriesFrom(input, _map_mapSint32Sint32_codec);
+            break;
+          }
+          case 490: {
+            mapSint64Sint64_.AddEntriesFrom(input, _map_mapSint64Sint64_codec);
+            break;
+          }
+          case 498: {
+            mapFixed32Fixed32_.AddEntriesFrom(input, _map_mapFixed32Fixed32_codec);
+            break;
+          }
+          case 506: {
+            mapFixed64Fixed64_.AddEntriesFrom(input, _map_mapFixed64Fixed64_codec);
+            break;
+          }
+          case 514: {
+            mapSfixed32Sfixed32_.AddEntriesFrom(input, _map_mapSfixed32Sfixed32_codec);
+            break;
+          }
+          case 522: {
+            mapSfixed64Sfixed64_.AddEntriesFrom(input, _map_mapSfixed64Sfixed64_codec);
+            break;
+          }
+          case 530: {
+            mapInt32Float_.AddEntriesFrom(input, _map_mapInt32Float_codec);
+            break;
+          }
+          case 538: {
+            mapInt32Double_.AddEntriesFrom(input, _map_mapInt32Double_codec);
+            break;
+          }
+          case 546: {
+            mapBoolBool_.AddEntriesFrom(input, _map_mapBoolBool_codec);
+            break;
+          }
+          case 554: {
+            mapStringString_.AddEntriesFrom(input, _map_mapStringString_codec);
+            break;
+          }
+          case 562: {
+            mapStringBytes_.AddEntriesFrom(input, _map_mapStringBytes_codec);
+            break;
+          }
+          case 570: {
+            mapStringNestedMessage_.AddEntriesFrom(input, _map_mapStringNestedMessage_codec);
+            break;
+          }
+          case 578: {
+            mapStringForeignMessage_.AddEntriesFrom(input, _map_mapStringForeignMessage_codec);
+            break;
+          }
+          case 586: {
+            mapStringNestedEnum_.AddEntriesFrom(input, _map_mapStringNestedEnum_codec);
+            break;
+          }
+          case 594: {
+            mapStringForeignEnum_.AddEntriesFrom(input, _map_mapStringForeignEnum_codec);
+            break;
+          }
+          case 888: {
+            OneofUint32 = input.ReadUInt32();
+            break;
+          }
+          case 898: {
+            global::Conformance.TestAllTypes.Types.NestedMessage subBuilder = new global::Conformance.TestAllTypes.Types.NestedMessage();
+            if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+              subBuilder.MergeFrom(OneofNestedMessage);
+            }
+            input.ReadMessage(subBuilder);
+            OneofNestedMessage = subBuilder;
+            break;
+          }
+          case 906: {
+            OneofString = input.ReadString();
+            break;
+          }
+          case 914: {
+            OneofBytes = input.ReadBytes();
+            break;
+          }
+          case 1610: {
+            bool? value = _single_optionalBoolWrapper_codec.Read(input);
+            if (optionalBoolWrapper_ == null || value != false) {
+              OptionalBoolWrapper = value;
+            }
+            break;
+          }
+          case 1618: {
+            int? value = _single_optionalInt32Wrapper_codec.Read(input);
+            if (optionalInt32Wrapper_ == null || value != 0) {
+              OptionalInt32Wrapper = value;
+            }
+            break;
+          }
+          case 1626: {
+            long? value = _single_optionalInt64Wrapper_codec.Read(input);
+            if (optionalInt64Wrapper_ == null || value != 0L) {
+              OptionalInt64Wrapper = value;
+            }
+            break;
+          }
+          case 1634: {
+            uint? value = _single_optionalUint32Wrapper_codec.Read(input);
+            if (optionalUint32Wrapper_ == null || value != 0) {
+              OptionalUint32Wrapper = value;
+            }
+            break;
+          }
+          case 1642: {
+            ulong? value = _single_optionalUint64Wrapper_codec.Read(input);
+            if (optionalUint64Wrapper_ == null || value != 0UL) {
+              OptionalUint64Wrapper = value;
+            }
+            break;
+          }
+          case 1650: {
+            float? value = _single_optionalFloatWrapper_codec.Read(input);
+            if (optionalFloatWrapper_ == null || value != 0F) {
+              OptionalFloatWrapper = value;
+            }
+            break;
+          }
+          case 1658: {
+            double? value = _single_optionalDoubleWrapper_codec.Read(input);
+            if (optionalDoubleWrapper_ == null || value != 0D) {
+              OptionalDoubleWrapper = value;
+            }
+            break;
+          }
+          case 1666: {
+            string value = _single_optionalStringWrapper_codec.Read(input);
+            if (optionalStringWrapper_ == null || value != "") {
+              OptionalStringWrapper = value;
+            }
+            break;
+          }
+          case 1674: {
+            pb::ByteString value = _single_optionalBytesWrapper_codec.Read(input);
+            if (optionalBytesWrapper_ == null || value != pb::ByteString.Empty) {
+              OptionalBytesWrapper = value;
+            }
+            break;
+          }
+          case 1690: {
+            repeatedBoolWrapper_.AddEntriesFrom(input, _repeated_repeatedBoolWrapper_codec);
+            break;
+          }
+          case 1698: {
+            repeatedInt32Wrapper_.AddEntriesFrom(input, _repeated_repeatedInt32Wrapper_codec);
+            break;
+          }
+          case 1706: {
+            repeatedInt64Wrapper_.AddEntriesFrom(input, _repeated_repeatedInt64Wrapper_codec);
+            break;
+          }
+          case 1714: {
+            repeatedUint32Wrapper_.AddEntriesFrom(input, _repeated_repeatedUint32Wrapper_codec);
+            break;
+          }
+          case 1722: {
+            repeatedUint64Wrapper_.AddEntriesFrom(input, _repeated_repeatedUint64Wrapper_codec);
+            break;
+          }
+          case 1730: {
+            repeatedFloatWrapper_.AddEntriesFrom(input, _repeated_repeatedFloatWrapper_codec);
+            break;
+          }
+          case 1738: {
+            repeatedDoubleWrapper_.AddEntriesFrom(input, _repeated_repeatedDoubleWrapper_codec);
+            break;
+          }
+          case 1746: {
+            repeatedStringWrapper_.AddEntriesFrom(input, _repeated_repeatedStringWrapper_codec);
+            break;
+          }
+          case 1754: {
+            repeatedBytesWrapper_.AddEntriesFrom(input, _repeated_repeatedBytesWrapper_codec);
+            break;
+          }
+          case 2410: {
+            if (optionalDuration_ == null) {
+              optionalDuration_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+            }
+            input.ReadMessage(optionalDuration_);
+            break;
+          }
+          case 2418: {
+            if (optionalTimestamp_ == null) {
+              optionalTimestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+            }
+            input.ReadMessage(optionalTimestamp_);
+            break;
+          }
+          case 2426: {
+            if (optionalFieldMask_ == null) {
+              optionalFieldMask_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+            }
+            input.ReadMessage(optionalFieldMask_);
+            break;
+          }
+          case 2434: {
+            if (optionalStruct_ == null) {
+              optionalStruct_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+            }
+            input.ReadMessage(optionalStruct_);
+            break;
+          }
+          case 2442: {
+            if (optionalAny_ == null) {
+              optionalAny_ = new global::Google.Protobuf.WellKnownTypes.Any();
+            }
+            input.ReadMessage(optionalAny_);
+            break;
+          }
+          case 2450: {
+            if (optionalValue_ == null) {
+              optionalValue_ = new global::Google.Protobuf.WellKnownTypes.Value();
+            }
+            input.ReadMessage(optionalValue_);
+            break;
+          }
+          case 2490: {
+            repeatedDuration_.AddEntriesFrom(input, _repeated_repeatedDuration_codec);
+            break;
+          }
+          case 2498: {
+            repeatedTimestamp_.AddEntriesFrom(input, _repeated_repeatedTimestamp_codec);
+            break;
+          }
+          case 2506: {
+            repeatedFieldmask_.AddEntriesFrom(input, _repeated_repeatedFieldmask_codec);
+            break;
+          }
+          case 2522: {
+            repeatedAny_.AddEntriesFrom(input, _repeated_repeatedAny_codec);
+            break;
+          }
+          case 2530: {
+            repeatedValue_.AddEntriesFrom(input, _repeated_repeatedValue_codec);
+            break;
+          }
+          case 2594: {
+            repeatedStruct_.AddEntriesFrom(input, _repeated_repeatedStruct_codec);
+            break;
+          }
+          case 3208: {
+            Fieldname1 = input.ReadInt32();
+            break;
+          }
+          case 3216: {
+            FieldName2 = input.ReadInt32();
+            break;
+          }
+          case 3224: {
+            FieldName3 = input.ReadInt32();
+            break;
+          }
+          case 3232: {
+            FieldName4 = input.ReadInt32();
+            break;
+          }
+          case 3240: {
+            Field0Name5 = input.ReadInt32();
+            break;
+          }
+          case 3248: {
+            Field0Name6 = input.ReadInt32();
+            break;
+          }
+          case 3256: {
+            FieldName7 = input.ReadInt32();
+            break;
+          }
+          case 3264: {
+            FieldName8 = input.ReadInt32();
+            break;
+          }
+          case 3272: {
+            FieldName9 = input.ReadInt32();
+            break;
+          }
+          case 3280: {
+            FieldName10 = input.ReadInt32();
+            break;
+          }
+          case 3288: {
+            FIELDNAME11 = input.ReadInt32();
+            break;
+          }
+          case 3296: {
+            FIELDName12 = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the TestAllTypes message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum NestedEnum {
+        [pbr::OriginalName("FOO")] Foo = 0,
+        [pbr::OriginalName("BAR")] Bar = 1,
+        [pbr::OriginalName("BAZ")] Baz = 2,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
+        [pbr::OriginalName("NEG")] Neg = -1,
+      }
+
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class NestedMessage : pb::IMessage<NestedMessage> {
+        private static readonly pb::MessageParser<NestedMessage> _parser = new pb::MessageParser<NestedMessage>(() => new NestedMessage());
+        public static pb::MessageParser<NestedMessage> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Conformance.TestAllTypes.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NestedMessage() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NestedMessage(NestedMessage other) : this() {
+          a_ = other.a_;
+          Corecursive = other.corecursive_ != null ? other.Corecursive.Clone() : null;
+        }
+
+        public NestedMessage Clone() {
+          return new NestedMessage(this);
+        }
+
+        /// <summary>Field number for the "a" field.</summary>
+        public const int AFieldNumber = 1;
+        private int a_;
+        public int A {
+          get { return a_; }
+          set {
+            a_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "corecursive" field.</summary>
+        public const int CorecursiveFieldNumber = 2;
+        private global::Conformance.TestAllTypes corecursive_;
+        public global::Conformance.TestAllTypes Corecursive {
+          get { return corecursive_; }
+          set {
+            corecursive_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NestedMessage);
+        }
+
+        public bool Equals(NestedMessage other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (A != other.A) return false;
+          if (!object.Equals(Corecursive, other.Corecursive)) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (A != 0) hash ^= A.GetHashCode();
+          if (corecursive_ != null) hash ^= Corecursive.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (A != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(A);
+          }
+          if (corecursive_ != null) {
+            output.WriteRawTag(18);
+            output.WriteMessage(Corecursive);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (A != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(A);
+          }
+          if (corecursive_ != null) {
+            size += 1 + pb::CodedOutputStream.ComputeMessageSize(Corecursive);
+          }
+          return size;
+        }
+
+        public void MergeFrom(NestedMessage other) {
+          if (other == null) {
+            return;
+          }
+          if (other.A != 0) {
+            A = other.A;
+          }
+          if (other.corecursive_ != null) {
+            if (corecursive_ == null) {
+              corecursive_ = new global::Conformance.TestAllTypes();
+            }
+            Corecursive.MergeFrom(other.Corecursive);
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                A = input.ReadInt32();
+                break;
+              }
+              case 18: {
+                if (corecursive_ == null) {
+                  corecursive_ = new global::Conformance.TestAllTypes();
+                }
+                input.ReadMessage(corecursive_);
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ForeignMessage : pb::IMessage<ForeignMessage> {
+    private static readonly pb::MessageParser<ForeignMessage> _parser = new pb::MessageParser<ForeignMessage>(() => new ForeignMessage());
+    public static pb::MessageParser<ForeignMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ForeignMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ForeignMessage(ForeignMessage other) : this() {
+      c_ = other.c_;
+    }
+
+    public ForeignMessage Clone() {
+      return new ForeignMessage(this);
+    }
+
+    /// <summary>Field number for the "c" field.</summary>
+    public const int CFieldNumber = 1;
+    private int c_;
+    public int C {
+      get { return c_; }
+      set {
+        c_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ForeignMessage);
+    }
+
+    public bool Equals(ForeignMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (C != other.C) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (C != 0) hash ^= C.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (C != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(C);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (C != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(C);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ForeignMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.C != 0) {
+        C = other.C;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            C = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
new file mode 100644
index 0000000..82f728d
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{0607D1B8-80D6-4B35-9857-1263C1B32B94}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Google.Protobuf.Conformance</RootNamespace>
+    <AssemblyName>Google.Protobuf.Conformance</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="Microsoft.CSharp" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Conformance.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">
+      <Project>{6908bdce-d925-43f3-94ac-a531e6df2591}</Project>
+      <Name>Google.Protobuf</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Conformance/Program.cs b/csharp/src/Google.Protobuf.Conformance/Program.cs
new file mode 100644
index 0000000..19827c4
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/Program.cs
@@ -0,0 +1,142 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Conformance;
+using Google.Protobuf.Reflection;
+using System;
+using System.IO;
+
+namespace Google.Protobuf.Conformance
+{
+    /// <summary>
+    /// Conformance tests. The test runner will provide JSON or proto data on stdin,
+    /// and this program will produce its output on stdout.
+    /// </summary>
+    class Program
+    {
+        private static void Main(string[] args)
+        {
+            // This way we get the binary streams instead of readers/writers.
+            var input = new BinaryReader(Console.OpenStandardInput());
+            var output = new BinaryWriter(Console.OpenStandardOutput());
+            var typeRegistry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+
+            int count = 0;
+            while (RunTest(input, output, typeRegistry))
+            {
+                count++;
+            }
+            Console.Error.WriteLine("Received EOF after {0} tests", count);
+        }
+
+        private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry)
+        {
+            int? size = ReadInt32(input);
+            if (size == null)
+            {
+                return false;
+            }
+            byte[] inputData = input.ReadBytes(size.Value);
+            if (inputData.Length != size.Value)
+            {
+                throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size);
+            }
+            ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData);
+            ConformanceResponse response = PerformRequest(request, typeRegistry);
+            byte[] outputData = response.ToByteArray();
+            output.Write(outputData.Length);
+            output.Write(outputData);
+            // Ready for another test...
+            return true;
+        }
+
+        private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry)
+        {
+            TestAllTypes message;
+            try
+            {
+                switch (request.PayloadCase)
+                {
+                    case ConformanceRequest.PayloadOneofCase.JsonPayload:
+                        var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
+                        message = parser.Parse<TestAllTypes>(request.JsonPayload);
+                        break;
+                    case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
+                        message = TestAllTypes.Parser.ParseFrom(request.ProtobufPayload);
+                        break;
+                    default:
+                        throw new Exception("Unsupported request payload: " + request.PayloadCase);
+                }
+            }
+            catch (InvalidProtocolBufferException e)
+            {
+                return new ConformanceResponse { ParseError = e.Message };
+            }
+            catch (InvalidJsonException e)
+            {
+                return new ConformanceResponse { ParseError = e.Message };
+            }
+            try
+            {
+                switch (request.RequestedOutputFormat)
+                {
+                    case global::Conformance.WireFormat.Json:
+                        var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry));
+                        return new ConformanceResponse { JsonPayload = formatter.Format(message) };
+                    case global::Conformance.WireFormat.Protobuf:
+                        return new ConformanceResponse { ProtobufPayload = message.ToByteString() };
+                    default:
+                        throw new Exception("Unsupported request output format: " + request.PayloadCase);
+                }
+            }
+            catch (InvalidOperationException e)
+            {
+                return new ConformanceResponse { SerializeError = e.Message };
+            }
+        }
+
+        private static int? ReadInt32(BinaryReader input)
+        {
+            byte[] bytes = input.ReadBytes(4);
+            if (bytes.Length == 0)
+            {
+                // Cleanly reached the end of the stream
+                return null;
+            }
+            if (bytes.Length != 4)
+            {
+                throw new EndOfStreamException("Read " + bytes.Length + " bytes of size when expecting 4");
+            }
+            return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d22e90f
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
@@ -0,0 +1,48 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Reflection;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: AssemblyVersion("3.0.0.0")]
+[assembly: AssemblyFileVersion("3.0.0.0")]
diff --git a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
new file mode 100644
index 0000000..ede1f77
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>9.0.30729</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{D7282E99-2DC3-405B-946F-177DB2FD2AE2}</ProjectGuid>

+    <OutputType>Exe</OutputType>

+    <AppDesignerFolder>Properties</AppDesignerFolder>

+    <RootNamespace>Google.Protobuf.JsonDump</RootNamespace>

+    <AssemblyName>Google.Protobuf.JsonDump</AssemblyName>

+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

+    <FileAlignment>512</FileAlignment>

+    <TargetFrameworkProfile>

+    </TargetFrameworkProfile>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <Optimize>false</Optimize>

+    <OutputPath>bin\Debug</OutputPath>

+    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release</OutputPath>

+    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

+    <DefineConstants>TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="mscorlib" />

+    <Reference Include="System" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="Program.cs" />

+    <Compile Include="Properties\AssemblyInfo.cs" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

+      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

+      <Name>Google.Protobuf</Name>

+    </ProjectReference>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="app.config" />

+  </ItemGroup>

+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.JsonDump/Program.cs b/csharp/src/Google.Protobuf.JsonDump/Program.cs
new file mode 100644
index 0000000..99e60e9
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/Program.cs
@@ -0,0 +1,72 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+

+namespace Google.Protobuf.ProtoDump

+{

+    /// <summary>

+    /// Small utility to load a binary message and dump it in JSON format.

+    /// </summary>

+    internal class Program

+    {

+        private static int Main(string[] args)

+        {

+            if (args.Length != 2)

+            {

+                Console.Error.WriteLine("Usage: Google.Protobuf.JsonDump <descriptor type name> <input data>");

+                Console.Error.WriteLine("The descriptor type name is the fully-qualified message name,");

+                Console.Error.WriteLine("including assembly e.g. ProjectNamespace.Message,Company.Project");

+                return 1;

+            }

+            Type type = Type.GetType(args[0]);

+            if (type == null)

+            {

+                Console.Error.WriteLine("Unable to load type {0}.", args[0]);

+                return 1;

+            }

+            if (!typeof(IMessage).IsAssignableFrom(type))

+            {

+                Console.Error.WriteLine("Type {0} doesn't implement IMessage.", args[0]);

+                return 1;

+            }

+            IMessage message = (IMessage) Activator.CreateInstance(type);

+            using (var input = File.OpenRead(args[1]))

+            {

+                message.MergeFrom(input);

+            }

+            Console.WriteLine(message);

+            return 0;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d980b01
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;

+using System.Runtime.CompilerServices;

+using System.Runtime.InteropServices;

+

+// General Information about an assembly is controlled through the following 

+// set of attributes. Change these attribute values to modify the information

+// associated with an assembly.

+

+[assembly: AssemblyTitle("ProtoDump")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("ProtoDump")]

+[assembly: AssemblyCopyright("Copyright ©  2015")]

+[assembly: AssemblyTrademark("")]

+[assembly: AssemblyCulture("")]

+

+[assembly: AssemblyVersion("3.0.0.0")]

+[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/Google.Protobuf.JsonDump/app.config b/csharp/src/Google.Protobuf.JsonDump/app.config
new file mode 100644
index 0000000..51278a4
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/app.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
diff --git a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs
new file mode 100644
index 0000000..685e130
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs
@@ -0,0 +1,171 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.Text;

+using NUnit.Framework;

+

+namespace Google.Protobuf

+{

+    public class ByteStringTest

+    {

+        [Test]

+        public void Equality()

+        {

+            ByteString b1 = ByteString.CopyFrom(1, 2, 3);

+            ByteString b2 = ByteString.CopyFrom(1, 2, 3);

+            ByteString b3 = ByteString.CopyFrom(1, 2, 4);

+            ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4);

+            EqualityTester.AssertEquality(b1, b1);

+            EqualityTester.AssertEquality(b1, b2);

+            EqualityTester.AssertInequality(b1, b3);

+            EqualityTester.AssertInequality(b1, b4);

+            EqualityTester.AssertInequality(b1, null);

+#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1)

+            Assert.IsTrue(b1 == b1);

+            Assert.IsTrue(b1 == b2);

+            Assert.IsFalse(b1 == b3);

+            Assert.IsFalse(b1 == b4);

+            Assert.IsFalse(b1 == null);

+            Assert.IsTrue((ByteString) null == null);

+            Assert.IsFalse(b1 != b1);

+            Assert.IsFalse(b1 != b2);

+#pragma warning disable 1718

+            Assert.IsTrue(b1 != b3);

+            Assert.IsTrue(b1 != b4);

+            Assert.IsTrue(b1 != null);

+            Assert.IsFalse((ByteString) null != null);

+        }

+

+        [Test]

+        public void EmptyByteStringHasZeroSize()

+        {

+            Assert.AreEqual(0, ByteString.Empty.Length);

+        }

+

+        [Test]

+        public void CopyFromStringWithExplicitEncoding()

+        {

+            ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode);

+            Assert.AreEqual(4, bs.Length);

+            Assert.AreEqual(65, bs[0]);

+            Assert.AreEqual(0, bs[1]);

+            Assert.AreEqual(66, bs[2]);

+            Assert.AreEqual(0, bs[3]);

+        }

+

+        [Test]

+        public void IsEmptyWhenEmpty()

+        {

+            Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty);

+        }

+

+        [Test]

+        public void IsEmptyWhenNotEmpty()

+        {

+            Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty);

+        }

+

+        [Test]

+        public void CopyFromByteArrayCopiesContents()

+        {

+            byte[] data = new byte[1];

+            data[0] = 10;

+            ByteString bs = ByteString.CopyFrom(data);

+            Assert.AreEqual(10, bs[0]);

+            data[0] = 5;

+            Assert.AreEqual(10, bs[0]);

+        }

+

+        [Test]

+        public void ToByteArrayCopiesContents()

+        {

+            ByteString bs = ByteString.CopyFromUtf8("Hello");

+            byte[] data = bs.ToByteArray();

+            Assert.AreEqual((byte)'H', data[0]);

+            Assert.AreEqual((byte)'H', bs[0]);

+            data[0] = 0;

+            Assert.AreEqual(0, data[0]);

+            Assert.AreEqual((byte)'H', bs[0]);

+        }

+

+        [Test]

+        public void CopyFromUtf8UsesUtf8()

+        {

+            ByteString bs = ByteString.CopyFromUtf8("\u20ac");

+            Assert.AreEqual(3, bs.Length);

+            Assert.AreEqual(0xe2, bs[0]);

+            Assert.AreEqual(0x82, bs[1]);

+            Assert.AreEqual(0xac, bs[2]);

+        }

+

+        [Test]

+        public void CopyFromPortion()

+        {

+            byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6};

+            ByteString bs = ByteString.CopyFrom(data, 2, 3);

+            Assert.AreEqual(3, bs.Length);

+            Assert.AreEqual(2, bs[0]);

+            Assert.AreEqual(3, bs[1]);

+        }

+

+        [Test]

+        public void ToStringUtf8()

+        {

+            ByteString bs = ByteString.CopyFromUtf8("\u20ac");

+            Assert.AreEqual("\u20ac", bs.ToStringUtf8());

+        }

+

+        [Test]

+        public void ToStringWithExplicitEncoding()

+        {

+            ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode);

+            Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode));

+        }

+

+        [Test]

+        public void FromBase64_WithText()

+        {

+            byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6};

+            string base64 = Convert.ToBase64String(data);

+            ByteString bs = ByteString.FromBase64(base64);

+            Assert.AreEqual(data, bs.ToByteArray());

+        }

+

+        [Test]

+        public void FromBase64_Empty()

+        {

+            // Optimization which also fixes issue 61.

+            Assert.AreSame(ByteString.Empty, ByteString.FromBase64(""));

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs
new file mode 100644
index 0000000..23af288
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+
+namespace Google.Protobuf
+{
+    internal static class CodedInputStreamExtensions
+    {
+        public static void AssertNextTag(this CodedInputStream input, uint expectedTag)
+        {
+            uint tag = input.ReadTag();
+            Assert.AreEqual(expectedTag, tag);
+        }
+
+        public static T ReadMessage<T>(this CodedInputStream stream, MessageParser<T> parser)
+            where T : IMessage<T>
+        {
+            var message = parser.CreateTemplate();
+            stream.ReadMessage(message);
+            return message;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
new file mode 100644
index 0000000..c0a9ffd
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
@@ -0,0 +1,598 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+using Google.Protobuf.TestProtos;

+using NUnit.Framework;

+

+namespace Google.Protobuf

+{

+    public class CodedInputStreamTest

+    {

+        /// <summary>

+        /// Helper to construct a byte array from a bunch of bytes.  The inputs are

+        /// actually ints so that I can use hex notation and not get stupid errors

+        /// about precision.

+        /// </summary>

+        private static byte[] Bytes(params int[] bytesAsInts)

+        {

+            byte[] bytes = new byte[bytesAsInts.Length];

+            for (int i = 0; i < bytesAsInts.Length; i++)

+            {

+                bytes[i] = (byte) bytesAsInts[i];

+            }

+            return bytes;

+        }

+

+        /// <summary>

+        /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64()

+        /// </summary>

+        private static void AssertReadVarint(byte[] data, ulong value)

+        {

+            CodedInputStream input = new CodedInputStream(data);

+            Assert.AreEqual((uint) value, input.ReadRawVarint32());

+

+            input = new CodedInputStream(data);

+            Assert.AreEqual(value, input.ReadRawVarint64());

+            Assert.IsTrue(input.IsAtEnd);

+

+            // Try different block sizes.

+            for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)

+            {

+                input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize));

+                Assert.AreEqual((uint) value, input.ReadRawVarint32());

+

+                input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize));

+                Assert.AreEqual(value, input.ReadRawVarint64());

+                Assert.IsTrue(input.IsAtEnd);

+            }

+

+            // Try reading directly from a MemoryStream. We want to verify that it

+            // doesn't read past the end of the input, so write an extra byte - this

+            // lets us test the position at the end.

+            MemoryStream memoryStream = new MemoryStream();

+            memoryStream.Write(data, 0, data.Length);

+            memoryStream.WriteByte(0);

+            memoryStream.Position = 0;

+            Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream));

+            Assert.AreEqual(data.Length, memoryStream.Position);

+        }

+

+        /// <summary>

+        /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and

+        /// expects them to fail with an InvalidProtocolBufferException whose

+        /// description matches the given one.

+        /// </summary>

+        private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)

+        {

+            CodedInputStream input = new CodedInputStream(data);

+            var exception = Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawVarint32());

+            Assert.AreEqual(expected.Message, exception.Message);

+

+            input = new CodedInputStream(data);

+            exception = Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawVarint64());

+            Assert.AreEqual(expected.Message, exception.Message);

+

+            // Make sure we get the same error when reading directly from a Stream.

+            exception = Assert.Throws<InvalidProtocolBufferException>(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data)));

+            Assert.AreEqual(expected.Message, exception.Message);

+        }

+

+        [Test]

+        public void ReadVarint()

+        {

+            AssertReadVarint(Bytes(0x00), 0);

+            AssertReadVarint(Bytes(0x01), 1);

+            AssertReadVarint(Bytes(0x7f), 127);

+            // 14882

+            AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));

+            // 2961488830

+            AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),

+                             (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |

+                             (0x0bL << 28));

+

+            // 64-bit

+            // 7256456126

+            AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),

+                             (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |

+                             (0x1bL << 28));

+            // 41256202580718336

+            AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),

+                             (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |

+                             (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));

+            // 11964378330978735131

+            AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),

+                             (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |

+                             (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) |

+                             (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63));

+

+            // Failures

+            AssertReadVarintFailure(

+                InvalidProtocolBufferException.MalformedVarint(),

+                Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,

+                      0x00));

+            AssertReadVarintFailure(

+                InvalidProtocolBufferException.TruncatedMessage(),

+                Bytes(0x80));

+        }

+

+        /// <summary>

+        /// Parses the given bytes using ReadRawLittleEndian32() and checks

+        /// that the result matches the given value.

+        /// </summary>

+        private static void AssertReadLittleEndian32(byte[] data, uint value)

+        {

+            CodedInputStream input = new CodedInputStream(data);

+            Assert.AreEqual(value, input.ReadRawLittleEndian32());

+            Assert.IsTrue(input.IsAtEnd);

+

+            // Try different block sizes.

+            for (int blockSize = 1; blockSize <= 16; blockSize *= 2)

+            {

+                input = new CodedInputStream(

+                    new SmallBlockInputStream(data, blockSize));

+                Assert.AreEqual(value, input.ReadRawLittleEndian32());

+                Assert.IsTrue(input.IsAtEnd);

+            }

+        }

+

+        /// <summary>

+        /// Parses the given bytes using ReadRawLittleEndian64() and checks

+        /// that the result matches the given value.

+        /// </summary>

+        private static void AssertReadLittleEndian64(byte[] data, ulong value)

+        {

+            CodedInputStream input = new CodedInputStream(data);

+            Assert.AreEqual(value, input.ReadRawLittleEndian64());

+            Assert.IsTrue(input.IsAtEnd);

+

+            // Try different block sizes.

+            for (int blockSize = 1; blockSize <= 16; blockSize *= 2)

+            {

+                input = new CodedInputStream(

+                    new SmallBlockInputStream(data, blockSize));

+                Assert.AreEqual(value, input.ReadRawLittleEndian64());

+                Assert.IsTrue(input.IsAtEnd);

+            }

+        }

+

+        [Test]

+        public void ReadLittleEndian()

+        {

+            AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);

+            AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);

+

+            AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),

+                                     0x123456789abcdef0L);

+            AssertReadLittleEndian64(

+                Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL);

+        }

+

+        [Test]

+        public void DecodeZigZag32()

+        {

+            Assert.AreEqual(0, CodedInputStream.DecodeZigZag32(0));

+            Assert.AreEqual(-1, CodedInputStream.DecodeZigZag32(1));

+            Assert.AreEqual(1, CodedInputStream.DecodeZigZag32(2));

+            Assert.AreEqual(-2, CodedInputStream.DecodeZigZag32(3));

+            Assert.AreEqual(0x3FFFFFFF, CodedInputStream.DecodeZigZag32(0x7FFFFFFE));

+            Assert.AreEqual(unchecked((int) 0xC0000000), CodedInputStream.DecodeZigZag32(0x7FFFFFFF));

+            Assert.AreEqual(0x7FFFFFFF, CodedInputStream.DecodeZigZag32(0xFFFFFFFE));

+            Assert.AreEqual(unchecked((int) 0x80000000), CodedInputStream.DecodeZigZag32(0xFFFFFFFF));

+        }

+

+        [Test]

+        public void DecodeZigZag64()

+        {

+            Assert.AreEqual(0, CodedInputStream.DecodeZigZag64(0));

+            Assert.AreEqual(-1, CodedInputStream.DecodeZigZag64(1));

+            Assert.AreEqual(1, CodedInputStream.DecodeZigZag64(2));

+            Assert.AreEqual(-2, CodedInputStream.DecodeZigZag64(3));

+            Assert.AreEqual(0x000000003FFFFFFFL, CodedInputStream.DecodeZigZag64(0x000000007FFFFFFEL));

+            Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), CodedInputStream.DecodeZigZag64(0x000000007FFFFFFFL));

+            Assert.AreEqual(0x000000007FFFFFFFL, CodedInputStream.DecodeZigZag64(0x00000000FFFFFFFEL));

+            Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), CodedInputStream.DecodeZigZag64(0x00000000FFFFFFFFL));

+            Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, CodedInputStream.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL));

+            Assert.AreEqual(unchecked((long) 0x8000000000000000L), CodedInputStream.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL));

+        }

+        

+        [Test]

+        public void ReadWholeMessage_VaryingBlockSizes()

+        {

+            TestAllTypes message = SampleMessages.CreateFullTestAllTypes();

+

+            byte[] rawBytes = message.ToByteArray();

+            Assert.AreEqual(rawBytes.Length, message.CalculateSize());

+            TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes);

+            Assert.AreEqual(message, message2);

+

+            // Try different block sizes.

+            for (int blockSize = 1; blockSize < 256; blockSize *= 2)

+            {

+                message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize));

+                Assert.AreEqual(message, message2);

+            }

+        }

+                

+        [Test]

+        public void ReadHugeBlob()

+        {

+            // Allocate and initialize a 1MB blob.

+            byte[] blob = new byte[1 << 20];

+            for (int i = 0; i < blob.Length; i++)

+            {

+                blob[i] = (byte) i;

+            }

+

+            // Make a message containing it.

+            var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) };

+

+            // Serialize and parse it.  Make sure to parse from an InputStream, not

+            // directly from a ByteString, so that CodedInputStream uses buffered

+            // reading.

+            TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString());

+

+            Assert.AreEqual(message, message2);

+        }

+

+        [Test]

+        public void ReadMaliciouslyLargeBlob()

+        {

+            MemoryStream ms = new MemoryStream();

+            CodedOutputStream output = new CodedOutputStream(ms);

+

+            uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteRawVarint32(tag);

+            output.WriteRawVarint32(0x7FFFFFFF);

+            output.WriteRawBytes(new byte[32]); // Pad with a few random bytes.

+            output.Flush();

+            ms.Position = 0;

+

+            CodedInputStream input = new CodedInputStream(ms);

+            Assert.AreEqual(tag, input.ReadTag());

+

+            Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());

+        }

+

+        internal static TestRecursiveMessage MakeRecursiveMessage(int depth)

+        {

+            if (depth == 0)

+            {

+                return new TestRecursiveMessage { I = 5 };

+            }

+            else

+            {

+                return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) };

+            }

+        }

+

+        internal static void AssertMessageDepth(TestRecursiveMessage message, int depth)

+        {

+            if (depth == 0)

+            {

+                Assert.IsNull(message.A);

+                Assert.AreEqual(5, message.I);

+            }

+            else

+            {

+                Assert.IsNotNull(message.A);

+                AssertMessageDepth(message.A, depth - 1);

+            }

+        }

+

+        [Test]

+        public void MaliciousRecursion()

+        {

+            ByteString data64 = MakeRecursiveMessage(64).ToByteString();

+            ByteString data65 = MakeRecursiveMessage(65).ToByteString();

+

+            AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(data64), 64);

+

+            Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(data65));

+

+            CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(data64.ToByteArray()), 1000000, 63);

+            Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(input));

+        }

+

+        [Test]

+        public void SizeLimit()

+        {

+            // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't

+            // apply to the latter case.

+            MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray());

+            CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100);

+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(input));

+        }

+

+        /// <summary>

+        /// Tests that if we read an string that contains invalid UTF-8, no exception

+        /// is thrown.  Instead, the invalid bytes are replaced with the Unicode

+        /// "replacement character" U+FFFD.

+        /// </summary>

+        [Test]

+        public void ReadInvalidUtf8()

+        {

+            MemoryStream ms = new MemoryStream();

+            CodedOutputStream output = new CodedOutputStream(ms);

+

+            uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteRawVarint32(tag);

+            output.WriteRawVarint32(1);

+            output.WriteRawBytes(new byte[] {0x80});

+            output.Flush();

+            ms.Position = 0;

+

+            CodedInputStream input = new CodedInputStream(ms);

+

+            Assert.AreEqual(tag, input.ReadTag());

+            string text = input.ReadString();

+            Assert.AreEqual('\ufffd', text[0]);

+        }

+

+        /// <summary>

+        /// A stream which limits the number of bytes it reads at a time.

+        /// We use this to make sure that CodedInputStream doesn't screw up when

+        /// reading in small blocks.

+        /// </summary>

+        private sealed class SmallBlockInputStream : MemoryStream

+        {

+            private readonly int blockSize;

+

+            public SmallBlockInputStream(byte[] data, int blockSize)

+                : base(data)

+            {

+                this.blockSize = blockSize;

+            }

+

+            public override int Read(byte[] buffer, int offset, int count)

+            {

+                return base.Read(buffer, offset, Math.Min(count, blockSize));

+            }

+        }

+

+        [Test]

+        public void TestNegativeEnum()

+        {

+            byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 };

+            CodedInputStream input = new CodedInputStream(bytes);

+            Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum());

+            Assert.IsTrue(input.IsAtEnd);

+        }

+

+        //Issue 71:	CodedInputStream.ReadBytes go to slow path unnecessarily

+        [Test]

+        public void TestSlowPathAvoidance()

+        {

+            using (var ms = new MemoryStream())

+            {

+                CodedOutputStream output = new CodedOutputStream(ms);

+                output.WriteTag(1, WireFormat.WireType.LengthDelimited);

+                output.WriteBytes(ByteString.CopyFrom(new byte[100]));

+                output.WriteTag(2, WireFormat.WireType.LengthDelimited);

+                output.WriteBytes(ByteString.CopyFrom(new byte[100]));

+                output.Flush();

+

+                ms.Position = 0;

+                CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0);

+

+                uint tag = input.ReadTag();

+                Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));

+                Assert.AreEqual(100, input.ReadBytes().Length);

+

+                tag = input.ReadTag();

+                Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag));

+                Assert.AreEqual(100, input.ReadBytes().Length);

+            }

+        }

+

+        [Test]

+        public void Tag0Throws()

+        {

+            var input = new CodedInputStream(new byte[] { 0 });

+            Assert.Throws<InvalidProtocolBufferException>(() => input.ReadTag());

+        }

+

+        [Test]

+        public void SkipGroup()

+        {

+            // Create an output stream with a group in:

+            // Field 1: string "field 1"

+            // Field 2: group containing:

+            //   Field 1: fixed int32 value 100

+            //   Field 2: string "ignore me"

+            //   Field 3: nested group containing

+            //      Field 1: fixed int64 value 1000

+            // Field 3: string "field 3"

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteString("field 1");

+            

+            // The outer group...

+            output.WriteTag(2, WireFormat.WireType.StartGroup);

+            output.WriteTag(1, WireFormat.WireType.Fixed32);

+            output.WriteFixed32(100);

+            output.WriteTag(2, WireFormat.WireType.LengthDelimited);

+            output.WriteString("ignore me");

+            // The nested group...

+            output.WriteTag(3, WireFormat.WireType.StartGroup);

+            output.WriteTag(1, WireFormat.WireType.Fixed64);

+            output.WriteFixed64(1000);

+            // Note: Not sure the field number is relevant for end group...

+            output.WriteTag(3, WireFormat.WireType.EndGroup);

+

+            // End the outer group

+            output.WriteTag(2, WireFormat.WireType.EndGroup);

+

+            output.WriteTag(3, WireFormat.WireType.LengthDelimited);

+            output.WriteString("field 3");

+            output.Flush();

+            stream.Position = 0;

+

+            // Now act like a generated client

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());

+            Assert.AreEqual("field 1", input.ReadString());

+            Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());

+            input.SkipLastField(); // Should consume the whole group, including the nested one.

+            Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag());

+            Assert.AreEqual("field 3", input.ReadString());

+        }

+

+        [Test]

+        public void SkipGroup_WrongEndGroupTag()

+        {

+            // Create an output stream with:

+            // Field 1: string "field 1"

+            // Start group 2

+            //   Field 3: fixed int32

+            // End group 4 (should give an error)

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteString("field 1");

+

+            // The outer group...

+            output.WriteTag(2, WireFormat.WireType.StartGroup);

+            output.WriteTag(3, WireFormat.WireType.Fixed32);

+            output.WriteFixed32(100);

+            output.WriteTag(4, WireFormat.WireType.EndGroup);

+            output.Flush();

+            stream.Position = 0;

+

+            // Now act like a generated client

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());

+            Assert.AreEqual("field 1", input.ReadString());

+            Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

+        public void RogueEndGroupTag()

+        {

+            // If we have an end-group tag without a leading start-group tag, generated

+            // code will just call SkipLastField... so that should fail.

+

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.EndGroup);

+            output.Flush();

+            stream.Position = 0;

+

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

+        public void EndOfStreamReachedWhileSkippingGroup()

+        {

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.StartGroup);

+            output.WriteTag(2, WireFormat.WireType.StartGroup);

+            output.WriteTag(2, WireFormat.WireType.EndGroup);

+

+            output.Flush();

+            stream.Position = 0;

+

+            // Now act like a generated client

+            var input = new CodedInputStream(stream);

+            input.ReadTag();

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

+        public void RecursionLimitAppliedWhileSkippingGroup()

+        {

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)

+            {

+                output.WriteTag(1, WireFormat.WireType.StartGroup);

+            }

+            for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)

+            {

+                output.WriteTag(1, WireFormat.WireType.EndGroup);

+            }

+            output.Flush();

+            stream.Position = 0;

+

+            // Now act like a generated client

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

+        public void Construction_Invalid()

+        {

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream((byte[]) null));

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream(null, 0, 0));

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream((Stream) null));

+            Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 100, 0));

+            Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 5, 10));

+        }

+

+        [Test]

+        public void CreateWithLimits_InvalidLimits()

+        {

+            var stream = new MemoryStream();

+            Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 0, 1));

+            Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 1, 0));

+        }

+

+        [Test]

+        public void Dispose_DisposesUnderlyingStream()

+        {

+            var memoryStream = new MemoryStream();

+            Assert.IsTrue(memoryStream.CanRead);

+            using (var cis = new CodedInputStream(memoryStream))

+            {

+            }

+            Assert.IsFalse(memoryStream.CanRead); // Disposed

+        }

+

+        [Test]

+        public void Dispose_WithLeaveOpen()

+        {

+            var memoryStream = new MemoryStream();

+            Assert.IsTrue(memoryStream.CanRead);

+            using (var cis = new CodedInputStream(memoryStream, true))

+            {

+            }

+            Assert.IsTrue(memoryStream.CanRead); // We left the stream open

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
new file mode 100644
index 0000000..48bf6d6
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
@@ -0,0 +1,419 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+using Google.Protobuf.TestProtos;

+using NUnit.Framework;

+

+namespace Google.Protobuf

+{

+    public class CodedOutputStreamTest

+    {

+        /// <summary>

+        /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and

+        /// checks that the result matches the given bytes

+        /// </summary>

+        private static void AssertWriteVarint(byte[] data, ulong value)

+        {

+            // Only do 32-bit write if the value fits in 32 bits.

+            if ((value >> 32) == 0)

+            {

+                MemoryStream rawOutput = new MemoryStream();

+                CodedOutputStream output = new CodedOutputStream(rawOutput);

+                output.WriteRawVarint32((uint) value);

+                output.Flush();

+                Assert.AreEqual(data, rawOutput.ToArray());

+                // Also try computing size.

+                Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value));

+            }

+

+            {

+                MemoryStream rawOutput = new MemoryStream();

+                CodedOutputStream output = new CodedOutputStream(rawOutput);

+                output.WriteRawVarint64(value);

+                output.Flush();

+                Assert.AreEqual(data, rawOutput.ToArray());

+

+                // Also try computing size.

+                Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value));

+            }

+

+            // Try different buffer sizes.

+            for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)

+            {

+                // Only do 32-bit write if the value fits in 32 bits.

+                if ((value >> 32) == 0)

+                {

+                    MemoryStream rawOutput = new MemoryStream();

+                    CodedOutputStream output =

+                        new CodedOutputStream(rawOutput, bufferSize);

+                    output.WriteRawVarint32((uint) value);

+                    output.Flush();

+                    Assert.AreEqual(data, rawOutput.ToArray());

+                }

+

+                {

+                    MemoryStream rawOutput = new MemoryStream();

+                    CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize);

+                    output.WriteRawVarint64(value);

+                    output.Flush();

+                    Assert.AreEqual(data, rawOutput.ToArray());

+                }

+            }

+        }

+

+        /// <summary>

+        /// Tests WriteRawVarint32() and WriteRawVarint64()

+        /// </summary>

+        [Test]

+        public void WriteVarint()

+        {

+            AssertWriteVarint(new byte[] {0x00}, 0);

+            AssertWriteVarint(new byte[] {0x01}, 1);

+            AssertWriteVarint(new byte[] {0x7f}, 127);

+            // 14882

+            AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7));

+            // 2961488830

+            AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b},

+                              (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |

+                              (0x0bL << 28));

+

+            // 64-bit

+            // 7256456126

+            AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b},

+                              (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |

+                              (0x1bL << 28));

+            // 41256202580718336

+            AssertWriteVarint(

+                new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49},

+                (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |

+                (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49));

+            // 11964378330978735131

+            AssertWriteVarint(

+                new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01},

+                unchecked((ulong)

+                          ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |

+                           (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |

+                           (0x05L << 49) | (0x26L << 56) | (0x01L << 63))));

+        }

+

+        /// <summary>

+        /// Parses the given bytes using WriteRawLittleEndian32() and checks

+        /// that the result matches the given value.

+        /// </summary>

+        private static void AssertWriteLittleEndian32(byte[] data, uint value)

+        {

+            MemoryStream rawOutput = new MemoryStream();

+            CodedOutputStream output = new CodedOutputStream(rawOutput);

+            output.WriteRawLittleEndian32(value);

+            output.Flush();

+            Assert.AreEqual(data, rawOutput.ToArray());

+

+            // Try different buffer sizes.

+            for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)

+            {

+                rawOutput = new MemoryStream();

+                output = new CodedOutputStream(rawOutput, bufferSize);

+                output.WriteRawLittleEndian32(value);

+                output.Flush();

+                Assert.AreEqual(data, rawOutput.ToArray());

+            }

+        }

+

+        /// <summary>

+        /// Parses the given bytes using WriteRawLittleEndian64() and checks

+        /// that the result matches the given value.

+        /// </summary>

+        private static void AssertWriteLittleEndian64(byte[] data, ulong value)

+        {

+            MemoryStream rawOutput = new MemoryStream();

+            CodedOutputStream output = new CodedOutputStream(rawOutput);

+            output.WriteRawLittleEndian64(value);

+            output.Flush();

+            Assert.AreEqual(data, rawOutput.ToArray());

+

+            // Try different block sizes.

+            for (int blockSize = 1; blockSize <= 16; blockSize *= 2)

+            {

+                rawOutput = new MemoryStream();

+                output = new CodedOutputStream(rawOutput, blockSize);

+                output.WriteRawLittleEndian64(value);

+                output.Flush();

+                Assert.AreEqual(data, rawOutput.ToArray());

+            }

+        }

+

+        /// <summary>

+        /// Tests writeRawLittleEndian32() and writeRawLittleEndian64().

+        /// </summary>

+        [Test]

+        public void WriteLittleEndian()

+        {

+            AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678);

+            AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0);

+

+            AssertWriteLittleEndian64(

+                new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12},

+                0x123456789abcdef0L);

+            AssertWriteLittleEndian64(

+                new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a},

+                0x9abcdef012345678UL);

+        }

+

+        [Test]

+        public void WriteWholeMessage_VaryingBlockSizes()

+        {

+            TestAllTypes message = SampleMessages.CreateFullTestAllTypes();

+

+            byte[] rawBytes = message.ToByteArray();

+

+            // Try different block sizes.

+            for (int blockSize = 1; blockSize < 256; blockSize *= 2)

+            {

+                MemoryStream rawOutput = new MemoryStream();

+                CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize);

+                message.WriteTo(output);

+                output.Flush();

+                Assert.AreEqual(rawBytes, rawOutput.ToArray());

+            }

+        }

+        

+        [Test]

+        public void EncodeZigZag32()

+        {

+            Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag32(0));

+            Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag32(-1));

+            Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag32(1));

+            Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag32(-2));

+            Assert.AreEqual(0x7FFFFFFEu, CodedOutputStream.EncodeZigZag32(0x3FFFFFFF));

+            Assert.AreEqual(0x7FFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0xC0000000)));

+            Assert.AreEqual(0xFFFFFFFEu, CodedOutputStream.EncodeZigZag32(0x7FFFFFFF));

+            Assert.AreEqual(0xFFFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0x80000000)));

+        }

+

+        [Test]

+        public void EncodeZigZag64()

+        {

+            Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag64(0));

+            Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag64(-1));

+            Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag64(1));

+            Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag64(-2));

+            Assert.AreEqual(0x000000007FFFFFFEuL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL)));

+            Assert.AreEqual(0x000000007FFFFFFFuL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL)));

+            Assert.AreEqual(0x00000000FFFFFFFEuL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL)));

+            Assert.AreEqual(0x00000000FFFFFFFFuL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL)));

+            Assert.AreEqual(0xFFFFFFFFFFFFFFFEL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL)));

+            Assert.AreEqual(0xFFFFFFFFFFFFFFFFL,

+                            CodedOutputStream.EncodeZigZag64(unchecked((long) 0x8000000000000000UL)));

+        }

+

+        [Test]

+        public void RoundTripZigZag32()

+        {

+            // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)

+            // were chosen semi-randomly via keyboard bashing.

+            Assert.AreEqual(0, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(0)));

+            Assert.AreEqual(1, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(1)));

+            Assert.AreEqual(-1, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-1)));

+            Assert.AreEqual(14927, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(14927)));

+            Assert.AreEqual(-3612, CodedInputStream.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-3612)));

+        }

+

+        [Test]

+        public void RoundTripZigZag64()

+        {

+            Assert.AreEqual(0, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(0)));

+            Assert.AreEqual(1, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(1)));

+            Assert.AreEqual(-1, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-1)));

+            Assert.AreEqual(14927, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(14927)));

+            Assert.AreEqual(-3612, CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-3612)));

+

+            Assert.AreEqual(856912304801416L,

+                            CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(856912304801416L)));

+            Assert.AreEqual(-75123905439571256L,

+                            CodedInputStream.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-75123905439571256L)));

+        }

+

+        [Test]

+        public void TestNegativeEnumNoTag()

+        {

+            Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2));

+            Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue));

+

+            byte[] bytes = new byte[10];

+            CodedOutputStream output = new CodedOutputStream(bytes);

+            output.WriteEnum((int) SampleEnum.NegativeValue);

+

+            Assert.AreEqual(0, output.SpaceLeft);

+            Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes));

+        }

+

+        [Test]

+        public void TestCodedInputOutputPosition()

+        {

+            byte[] content = new byte[110];

+            for (int i = 0; i < content.Length; i++)

+                content[i] = (byte)i;

+

+            byte[] child = new byte[120];

+            {

+                MemoryStream ms = new MemoryStream(child);

+                CodedOutputStream cout = new CodedOutputStream(ms, 20);

+                // Field 11: numeric value: 500

+                cout.WriteTag(11, WireFormat.WireType.Varint);

+                Assert.AreEqual(1, cout.Position);

+                cout.WriteInt32(500);

+                Assert.AreEqual(3, cout.Position);

+                //Field 12: length delimited 120 bytes

+                cout.WriteTag(12, WireFormat.WireType.LengthDelimited);

+                Assert.AreEqual(4, cout.Position);

+                cout.WriteBytes(ByteString.CopyFrom(content));

+                Assert.AreEqual(115, cout.Position);

+                // Field 13: fixed numeric value: 501

+                cout.WriteTag(13, WireFormat.WireType.Fixed32);

+                Assert.AreEqual(116, cout.Position);

+                cout.WriteSFixed32(501);

+                Assert.AreEqual(120, cout.Position);

+                cout.Flush();

+            }

+

+            byte[] bytes = new byte[130];

+            {

+                CodedOutputStream cout = new CodedOutputStream(bytes);

+                // Field 1: numeric value: 500

+                cout.WriteTag(1, WireFormat.WireType.Varint);

+                Assert.AreEqual(1, cout.Position);

+                cout.WriteInt32(500);

+                Assert.AreEqual(3, cout.Position);

+                //Field 2: length delimited 120 bytes

+                cout.WriteTag(2, WireFormat.WireType.LengthDelimited);

+                Assert.AreEqual(4, cout.Position);

+                cout.WriteBytes(ByteString.CopyFrom(child));

+                Assert.AreEqual(125, cout.Position);

+                // Field 3: fixed numeric value: 500

+                cout.WriteTag(3, WireFormat.WireType.Fixed32);

+                Assert.AreEqual(126, cout.Position);

+                cout.WriteSFixed32(501);

+                Assert.AreEqual(130, cout.Position);

+                cout.Flush();

+            }

+            // Now test Input stream:

+            {

+                CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0);

+                Assert.AreEqual(0, cin.Position);

+                // Field 1:

+                uint tag = cin.ReadTag();

+                Assert.AreEqual(1, tag >> 3);

+                Assert.AreEqual(1, cin.Position);

+                Assert.AreEqual(500, cin.ReadInt32());

+                Assert.AreEqual(3, cin.Position);

+                //Field 2:

+                tag = cin.ReadTag();

+                Assert.AreEqual(2, tag >> 3);

+                Assert.AreEqual(4, cin.Position);

+                int childlen = cin.ReadLength();

+                Assert.AreEqual(120, childlen);

+                Assert.AreEqual(5, cin.Position);

+                int oldlimit = cin.PushLimit((int)childlen);

+                Assert.AreEqual(5, cin.Position);

+                // Now we are reading child message

+                {

+                    // Field 11: numeric value: 500

+                    tag = cin.ReadTag();

+                    Assert.AreEqual(11, tag >> 3);

+                    Assert.AreEqual(6, cin.Position);

+                    Assert.AreEqual(500, cin.ReadInt32());

+                    Assert.AreEqual(8, cin.Position);

+                    //Field 12: length delimited 120 bytes

+                    tag = cin.ReadTag();

+                    Assert.AreEqual(12, tag >> 3);

+                    Assert.AreEqual(9, cin.Position);

+                    ByteString bstr = cin.ReadBytes();

+                    Assert.AreEqual(110, bstr.Length);

+                    Assert.AreEqual((byte) 109, bstr[109]);

+                    Assert.AreEqual(120, cin.Position);

+                    // Field 13: fixed numeric value: 501

+                    tag = cin.ReadTag();

+                    Assert.AreEqual(13, tag >> 3);

+                    // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit

+                    Assert.AreEqual(121, cin.Position);

+                    Assert.AreEqual(501, cin.ReadSFixed32());

+                    Assert.AreEqual(125, cin.Position);

+                    Assert.IsTrue(cin.IsAtEnd);

+                }

+                cin.PopLimit(oldlimit);

+                Assert.AreEqual(125, cin.Position);

+                // Field 3: fixed numeric value: 501

+                tag = cin.ReadTag();

+                Assert.AreEqual(3, tag >> 3);

+                Assert.AreEqual(126, cin.Position);

+                Assert.AreEqual(501, cin.ReadSFixed32());

+                Assert.AreEqual(130, cin.Position);

+                Assert.IsTrue(cin.IsAtEnd);

+            }

+        }

+

+        [Test]

+        public void Dispose_DisposesUnderlyingStream()

+        {

+            var memoryStream = new MemoryStream();

+            Assert.IsTrue(memoryStream.CanWrite);

+            using (var cos = new CodedOutputStream(memoryStream))

+            {

+                cos.WriteRawByte(0);

+                Assert.AreEqual(0, memoryStream.Position); // Not flushed yet

+            }

+            Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream

+            Assert.IsFalse(memoryStream.CanWrite); // Disposed

+        }

+

+        [Test]

+        public void Dispose_WithLeaveOpen()

+        {

+            var memoryStream = new MemoryStream();

+            Assert.IsTrue(memoryStream.CanWrite);

+            using (var cos = new CodedOutputStream(memoryStream, true))

+            {

+                cos.WriteRawByte(0);

+                Assert.AreEqual(0, memoryStream.Position); // Not flushed yet

+            }

+            Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream

+            Assert.IsTrue(memoryStream.CanWrite); // We left the stream open

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
new file mode 100644
index 0000000..9c84590
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
@@ -0,0 +1,532 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+using System.Collections;
+using System.Linq;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// Tests for MapField which aren't reliant on the encoded format -
+    /// tests for serialization/deserialization are part of GeneratedMessageTest.
+    /// </summary>
+    public class MapFieldTest
+    {
+        [Test]
+        public void Clone_ClonesMessages()
+        {
+            var message = new ForeignMessage { C = 20 };
+            var map = new MapField<string, ForeignMessage> { { "x", message } };
+            var clone = map.Clone();
+            map["x"].C = 30;
+            Assert.AreEqual(20, clone["x"].C);
+        }
+
+        [Test]
+        public void NullValuesProhibited()
+        {
+            TestNullValues<int?>(0);
+            TestNullValues("");
+            TestNullValues(new TestAllTypes());
+        }
+
+        private void TestNullValues<T>(T nonNullValue)
+        {
+            var map = new MapField<int, T>();
+            var nullValue = (T) (object) null;
+            Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
+            Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
+            map.Add(1, nonNullValue);
+            map[1] = nonNullValue;
+        }
+
+        [Test]
+        public void Add_ForbidsNullKeys()
+        {
+            var map = new MapField<string, ForeignMessage>();
+            Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));
+        }
+
+        [Test]
+        public void Indexer_ForbidsNullKeys()
+        {
+            var map = new MapField<string, ForeignMessage>();
+            Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());
+        }
+        
+        [Test]
+        public void AddPreservesInsertionOrder()
+        {
+            var map = new MapField<string, string>();
+            map.Add("a", "v1");
+            map.Add("b", "v2");
+            map.Add("c", "v3");
+            map.Remove("b");
+            map.Add("d", "v4");
+            CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
+            CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
+        }
+
+        [Test]
+        public void EqualityIsOrderInsensitive()
+        {
+            var map1 = new MapField<string, string>();
+            map1.Add("a", "v1");
+            map1.Add("b", "v2");
+
+            var map2 = new MapField<string, string>();
+            map2.Add("b", "v2");
+            map2.Add("a", "v1");
+
+            EqualityTester.AssertEquality(map1, map2);
+        }
+
+        [Test]
+        public void EqualityIsKeySensitive()
+        {
+            var map1 = new MapField<string, string>();
+            map1.Add("first key", "v1");
+            map1.Add("second key", "v2");
+
+            var map2 = new MapField<string, string>();
+            map2.Add("third key", "v1");
+            map2.Add("fourth key", "v2");
+
+            EqualityTester.AssertInequality(map1, map2);
+        }
+
+        [Test]
+        public void Equality_Simple()
+        {
+            var map = new MapField<string, string>();
+            EqualityTester.AssertEquality(map, map);
+            EqualityTester.AssertInequality(map, null);
+            Assert.IsFalse(map.Equals(new object()));
+        }
+
+        [Test]
+        public void EqualityIsValueSensitive()
+        {
+            // Note: Without some care, it's a little easier than one might
+            // hope to see hash collisions, but only in some environments...
+            var map1 = new MapField<string, string>();
+            map1.Add("a", "first value");
+            map1.Add("b", "second value");
+
+            var map2 = new MapField<string, string>();
+            map2.Add("a", "third value");
+            map2.Add("b", "fourth value");
+
+            EqualityTester.AssertInequality(map1, map2);
+        }
+
+        [Test]
+        public void Add_Dictionary()
+        {
+            var map1 = new MapField<string, string>
+            {
+                { "x", "y" },
+                { "a", "b" }
+            };
+            var map2 = new MapField<string, string>
+            {
+                { "before", "" },
+                map1,
+                { "after", "" }
+            };
+            var expected = new MapField<string, string>
+            {
+                { "before", "" },
+                { "x", "y" },
+                { "a", "b" },
+                { "after", "" }
+            };
+            Assert.AreEqual(expected, map2);
+            CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
+        }
+
+        // General IDictionary<TKey, TValue> behavior tests
+        [Test]
+        public void Add_KeyAlreadyExists()
+        {
+            var map = new MapField<string, string>();
+            map.Add("foo", "bar");
+            Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
+        }
+
+        [Test]
+        public void Add_Pair()
+        {
+            var map = new MapField<string, string>();
+            ICollection<KeyValuePair<string, string>> collection = map;
+            collection.Add(NewKeyValuePair("x", "y"));
+            Assert.AreEqual("y", map["x"]);
+            Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));
+        }
+
+        [Test]
+        public void Contains_Pair()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            ICollection<KeyValuePair<string, string>> collection = map;
+            Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
+            Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
+            Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
+        }
+
+        [Test]
+        public void Remove_Key()
+        {
+            var map = new MapField<string, string>();
+            map.Add("foo", "bar");
+            Assert.AreEqual(1, map.Count);
+            Assert.IsFalse(map.Remove("missing"));
+            Assert.AreEqual(1, map.Count);
+            Assert.IsTrue(map.Remove("foo"));
+            Assert.AreEqual(0, map.Count);
+            Assert.Throws<ArgumentNullException>(() => map.Remove(null));
+        }
+
+        [Test]
+        public void Remove_Pair()
+        {
+            var map = new MapField<string, string>();
+            map.Add("foo", "bar");
+            ICollection<KeyValuePair<string, string>> collection = map;
+            Assert.AreEqual(1, map.Count);
+            Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
+            Assert.AreEqual(1, map.Count);
+            Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
+            Assert.AreEqual(1, map.Count);
+            Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
+            Assert.AreEqual(0, map.Count);
+            Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));
+        }
+
+        [Test]
+        public void CopyTo_Pair()
+        {
+            var map = new MapField<string, string>();
+            map.Add("foo", "bar");
+            ICollection<KeyValuePair<string, string>> collection = map;
+            KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];
+            collection.CopyTo(array, 1);
+            Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
+        }
+
+        [Test]
+        public void Clear()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            Assert.AreEqual(1, map.Count);
+            map.Clear();
+            Assert.AreEqual(0, map.Count);
+            map.Add("x", "y");
+            Assert.AreEqual(1, map.Count);
+        }
+
+        [Test]
+        public void Indexer_Get()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            Assert.AreEqual("y", map["x"]);
+            Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });
+        }
+
+        [Test]
+        public void Indexer_Set()
+        {
+            var map = new MapField<string, string>();
+            map["x"] = "y";
+            Assert.AreEqual("y", map["x"]);
+            map["x"] = "z"; // This won't throw, unlike Add.
+            Assert.AreEqual("z", map["x"]);
+        }
+
+        [Test]
+        public void GetEnumerator_NonGeneric()
+        {
+            IEnumerable map = new MapField<string, string> { { "x", "y" } };
+            CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },
+                map.Cast<object>().ToList());
+        }
+
+        // Test for the explicitly-implemented non-generic IDictionary interface
+        [Test]
+        public void IDictionary_GetEnumerator()
+        {
+            IDictionary map = new MapField<string, string> { { "x", "y" } };
+            var enumerator = map.GetEnumerator();
+
+            // Commented assertions show an ideal situation - it looks like
+            // the LinkedList enumerator doesn't throw when you ask for the current entry
+            // at an inappropriate time; fixing this would be more work than it's worth.
+            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
+            Assert.IsTrue(enumerator.MoveNext());
+            Assert.AreEqual("x", enumerator.Key);
+            Assert.AreEqual("y", enumerator.Value);
+            Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);
+            Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);
+            Assert.IsFalse(enumerator.MoveNext());
+            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
+            enumerator.Reset();
+            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
+            Assert.IsTrue(enumerator.MoveNext());
+            Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay
+        }
+
+        [Test]
+        public void IDictionary_Add()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+            dictionary.Add("a", "b");
+            Assert.AreEqual("b", map["a"]);
+            Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));
+            Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));
+            Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));
+        }
+
+        [Test]
+        public void IDictionary_Contains()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+
+            Assert.IsFalse(dictionary.Contains("a"));
+            Assert.IsFalse(dictionary.Contains(5));
+            // Surprising, but IDictionary.Contains is only about keys.
+            Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));
+            Assert.IsTrue(dictionary.Contains("x"));
+        }
+
+        [Test]
+        public void IDictionary_Remove()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+            dictionary.Remove("a");
+            Assert.AreEqual(1, dictionary.Count);
+            dictionary.Remove(5);
+            Assert.AreEqual(1, dictionary.Count);
+            dictionary.Remove(new DictionaryEntry("x", "y"));
+            Assert.AreEqual(1, dictionary.Count);
+            dictionary.Remove("x");
+            Assert.AreEqual(0, dictionary.Count);
+            Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));
+        }
+
+        [Test]
+        public void IDictionary_CopyTo()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+            var array = new DictionaryEntry[3];
+            dictionary.CopyTo(array, 1);
+            CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
+                array);
+            var objectArray = new object[3];
+            dictionary.CopyTo(objectArray, 1);
+            CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
+                objectArray);
+        }
+
+        [Test]
+        public void IDictionary_IsFixedSize()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+            Assert.IsFalse(dictionary.IsFixedSize);
+        }
+
+        [Test]
+        public void IDictionary_Keys()
+        {
+            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
+            CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);
+        }
+
+        [Test]
+        public void IDictionary_Values()
+        {
+            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
+            CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);
+        }
+
+        [Test]
+        public void IDictionary_IsSynchronized()
+        {
+            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
+            Assert.IsFalse(dictionary.IsSynchronized);
+        }
+
+        [Test]
+        public void IDictionary_SyncRoot()
+        {
+            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
+            Assert.AreSame(dictionary, dictionary.SyncRoot);
+        }
+
+        [Test]
+        public void IDictionary_Indexer_Get()
+        {
+            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
+            Assert.AreEqual("y", dictionary["x"]);
+            Assert.IsNull(dictionary["a"]);
+            Assert.IsNull(dictionary[5]);
+            Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());
+        }
+
+        [Test]
+        public void IDictionary_Indexer_Set()
+        {
+            var map = new MapField<string, string> { { "x", "y" } };
+            IDictionary dictionary = map;
+            map["a"] = "b";
+            Assert.AreEqual("b", map["a"]);
+            map["a"] = "c";
+            Assert.AreEqual("c", map["a"]);
+            Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");
+            Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);
+            Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");
+            Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
+        }
+
+        [Test]
+        public void KeysReturnsLiveView()
+        {
+            var map = new MapField<string, string>();
+            var keys = map.Keys;
+            CollectionAssert.AreEqual(new string[0], keys);
+            map["foo"] = "bar";
+            map["x"] = "y";
+            CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);
+        }
+
+        [Test]
+        public void ValuesReturnsLiveView()
+        {
+            var map = new MapField<string, string>();
+            var values = map.Values;
+            CollectionAssert.AreEqual(new string[0], values);
+            map["foo"] = "bar";
+            map["x"] = "y";
+            CollectionAssert.AreEqual(new[] { "bar", "y" }, values);
+        }
+
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void ViewsAreReadOnly()
+        {
+            var map = new MapField<string, string>();
+            var keys = map.Keys;
+            Assert.IsTrue(keys.IsReadOnly);
+            Assert.Throws<NotSupportedException>(() => keys.Clear());
+            Assert.Throws<NotSupportedException>(() => keys.Remove("a"));
+            Assert.Throws<NotSupportedException>(() => keys.Add("a"));
+        }
+
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void ViewCopyTo()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var keys = map.Keys;
+            var array = new string[4];
+            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
+            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
+            keys.CopyTo(array, 1);
+            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
+        }
+        
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void NonGenericViewCopyTo()
+        {
+            IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            ICollection keys = map.Keys;
+            // Note the use of the Array type here rather than string[]
+            Array array = new string[4];
+            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
+            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
+            keys.CopyTo(array, 1);
+            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
+        }
+
+        [Test]
+        public void KeysContains()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var keys = map.Keys;
+            Assert.IsTrue(keys.Contains("foo"));
+            Assert.IsFalse(keys.Contains("bar")); // It's a value!
+            Assert.IsFalse(keys.Contains("1"));
+            // Keys can't be null, so we should prevent contains check
+            Assert.Throws<ArgumentNullException>(() => keys.Contains(null));
+        }
+
+        [Test]
+        public void ValuesContains()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var values = map.Values;
+            Assert.IsTrue(values.Contains("bar"));
+            Assert.IsFalse(values.Contains("foo")); // It's a key!
+            Assert.IsFalse(values.Contains("1"));
+            // Values can be null, so this makes sense
+            Assert.IsFalse(values.Contains(null));
+        }
+
+        [Test]
+        public void ToString_StringToString()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            Assert.AreEqual("{ \"foo\": \"bar\", \"x\": \"y\" }", map.ToString());
+        }
+
+        [Test]
+        public void ToString_UnsupportedKeyType()
+        {
+            var map = new MapField<byte, string> { { 10, "foo" } };
+            Assert.Throws<ArgumentException>(() => map.ToString());
+        }
+
+        private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
+        {
+            return new KeyValuePair<TKey, TValue>(key, value);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
new file mode 100644
index 0000000..8ed54cf
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
@@ -0,0 +1,660 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework;
+
+namespace Google.Protobuf.Collections
+{
+    public class RepeatedFieldTest
+    {
+        [Test]
+        public void NullValuesRejected()
+        {
+            var list = new RepeatedField<string>();
+            Assert.Throws<ArgumentNullException>(() => list.Add((string)null));
+            Assert.Throws<ArgumentNullException>(() => list.Add((IEnumerable<string>)null));
+            Assert.Throws<ArgumentNullException>(() => list.Add((RepeatedField<string>)null));
+            Assert.Throws<ArgumentNullException>(() => list.Contains(null));
+            Assert.Throws<ArgumentNullException>(() => list.IndexOf(null));
+        }
+
+        [Test]
+        public void Add_SingleItem()
+        {
+            var list = new RepeatedField<string>();
+            list.Add("foo");
+            Assert.AreEqual(1, list.Count);
+            Assert.AreEqual("foo", list[0]);
+        }
+
+        [Test]
+        public void Add_Sequence()
+        {
+            var list = new RepeatedField<string>();
+            list.Add(new[] { "foo", "bar" });
+            Assert.AreEqual(2, list.Count);
+            Assert.AreEqual("foo", list[0]);
+            Assert.AreEqual("bar", list[1]);
+        }
+
+        [Test]
+        public void Add_RepeatedField()
+        {
+            var list = new RepeatedField<string> { "original" };
+            list.Add(new RepeatedField<string> { "foo", "bar" });
+            Assert.AreEqual(3, list.Count);
+            Assert.AreEqual("original", list[0]);
+            Assert.AreEqual("foo", list[1]);
+            Assert.AreEqual("bar", list[2]);
+        }
+
+        [Test]
+        public void RemoveAt_Valid()
+        {
+            var list = new RepeatedField<string> { "first", "second", "third" };
+            list.RemoveAt(1);
+            CollectionAssert.AreEqual(new[] { "first", "third" }, list);
+            // Just check that these don't throw...
+            list.RemoveAt(list.Count - 1); // Now the count will be 1...
+            list.RemoveAt(0);
+            Assert.AreEqual(0, list.Count);
+        }
+
+        [Test]
+        public void RemoveAt_Invalid()
+        {
+            var list = new RepeatedField<string> { "first", "second", "third" };
+            Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(-1));
+            Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(3));
+        }
+
+        [Test]
+        public void Insert_Valid()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            list.Insert(1, "middle");
+            CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
+            list.Insert(3, "end");
+            CollectionAssert.AreEqual(new[] { "first", "middle", "second", "end" }, list);
+            list.Insert(0, "start");
+            CollectionAssert.AreEqual(new[] { "start", "first", "middle", "second", "end" }, list);
+        }
+
+        [Test]
+        public void Insert_Invalid()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(-1, "foo"));
+            Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(3, "foo"));
+            Assert.Throws<ArgumentNullException>(() => list.Insert(0, null));
+        }
+
+        [Test]
+        public void Equals_RepeatedField()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            Assert.IsFalse(list.Equals((RepeatedField<string>) null));
+            Assert.IsTrue(list.Equals(list));
+            Assert.IsFalse(list.Equals(new RepeatedField<string> { "first", "third" }));
+            Assert.IsFalse(list.Equals(new RepeatedField<string> { "first" }));
+            Assert.IsTrue(list.Equals(new RepeatedField<string> { "first", "second" }));
+        }
+
+        [Test]
+        public void Equals_Object()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            Assert.IsFalse(list.Equals((object) null));
+            Assert.IsTrue(list.Equals((object) list));
+            Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first", "third" }));
+            Assert.IsFalse(list.Equals((object) new RepeatedField<string> { "first" }));
+            Assert.IsTrue(list.Equals((object) new RepeatedField<string> { "first", "second" }));
+            Assert.IsFalse(list.Equals(new object()));
+        }
+
+        [Test]
+        public void GetEnumerator_GenericInterface()
+        {
+            IEnumerable<string> list = new RepeatedField<string> { "first", "second" };
+            // Select gets rid of the optimizations in ToList...
+            CollectionAssert.AreEqual(new[] { "first", "second" }, list.Select(x => x).ToList());
+        }
+
+        [Test]
+        public void GetEnumerator_NonGenericInterface()
+        {
+            IEnumerable list = new RepeatedField<string> { "first", "second" };
+            CollectionAssert.AreEqual(new[] { "first", "second" }, list.Cast<object>().ToList());
+        }
+
+        [Test]
+        public void CopyTo()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            string[] stringArray = new string[4];
+            list.CopyTo(stringArray, 1);
+            CollectionAssert.AreEqual(new[] { null, "first", "second", null }, stringArray);
+        }
+
+        [Test]
+        public void Indexer_Get()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            Assert.AreEqual("first", list[0]);
+            Assert.AreEqual("second", list[1]);
+            Assert.Throws<ArgumentOutOfRangeException>(() => list[-1].GetHashCode());
+            Assert.Throws<ArgumentOutOfRangeException>(() => list[2].GetHashCode());
+        }
+
+        [Test]
+        public void Indexer_Set()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            list[0] = "changed";
+            Assert.AreEqual("changed", list[0]);
+            Assert.Throws<ArgumentNullException>(() => list[0] = null);
+            Assert.Throws<ArgumentOutOfRangeException>(() => list[-1] = "bad");
+            Assert.Throws<ArgumentOutOfRangeException>(() => list[2] = "bad");
+        }
+
+        [Test]
+        public void Clone_ReturnsMutable()
+        {
+            var list = new RepeatedField<int> { 0 };
+            var clone = list.Clone();
+            clone[0] = 1;
+        }
+
+        [Test]
+        public void Enumerator()
+        {
+            var list = new RepeatedField<string> { "first", "second" };
+            using (var enumerator = list.GetEnumerator())
+            {
+                Assert.IsTrue(enumerator.MoveNext());
+                Assert.AreEqual("first", enumerator.Current);
+                Assert.IsTrue(enumerator.MoveNext());
+                Assert.AreEqual("second", enumerator.Current);
+                Assert.IsFalse(enumerator.MoveNext());
+                Assert.IsFalse(enumerator.MoveNext());
+            }
+        }
+
+        [Test]
+        public void AddEntriesFrom_PackedInt32()
+        {
+            uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            var length = CodedOutputStream.ComputeInt32Size(10)
+                + CodedOutputStream.ComputeInt32Size(999)
+                + CodedOutputStream.ComputeInt32Size(-1000);
+            output.WriteTag(packedTag);
+            output.WriteRawVarint32((uint) length);
+            output.WriteInt32(10);
+            output.WriteInt32(999);
+            output.WriteInt32(-1000);
+            output.Flush();
+            stream.Position = 0;
+
+            // Deliberately "expecting" a non-packed tag, but we detect that the data is
+            // actually packed.
+            uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var field = new RepeatedField<int>();
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(packedTag);
+            field.AddEntriesFrom(input, FieldCodec.ForInt32(nonPackedTag));
+            CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void AddEntriesFrom_NonPackedInt32()
+        {
+            uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            output.WriteTag(nonPackedTag);
+            output.WriteInt32(10);
+            output.WriteTag(nonPackedTag);
+            output.WriteInt32(999);
+            output.WriteTag(nonPackedTag);
+            output.WriteInt32(-1000); // Just for variety...
+            output.Flush();
+            stream.Position = 0;
+
+            // Deliberately "expecting" a packed tag, but we detect that the data is
+            // actually not packed.
+            uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var field = new RepeatedField<int>();
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(nonPackedTag);
+            field.AddEntriesFrom(input, FieldCodec.ForInt32(packedTag));
+            CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void AddEntriesFrom_String()
+        {
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            output.WriteTag(tag);
+            output.WriteString("Foo");
+            output.WriteTag(tag);
+            output.WriteString("");
+            output.WriteTag(tag);
+            output.WriteString("Bar");
+            output.Flush();
+            stream.Position = 0;
+
+            var field = new RepeatedField<string>();
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            field.AddEntriesFrom(input, FieldCodec.ForString(tag));
+            CollectionAssert.AreEqual(new[] { "Foo", "", "Bar" }, field);
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void AddEntriesFrom_Message()
+        {
+            var message1 = new ForeignMessage { C = 2000 };
+            var message2 = new ForeignMessage { C = -250 };
+
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            output.WriteTag(tag);
+            output.WriteMessage(message1);
+            output.WriteTag(tag);
+            output.WriteMessage(message2);
+            output.Flush();
+            stream.Position = 0;
+
+            var field = new RepeatedField<ForeignMessage>();
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            field.AddEntriesFrom(input, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
+            CollectionAssert.AreEqual(new[] { message1, message2}, field);
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void WriteTo_PackedInt32()
+        {
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var field = new RepeatedField<int> { 10, 1000, 1000000 };
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            field.WriteTo(output, FieldCodec.ForInt32(tag));
+            output.Flush();
+            stream.Position = 0;
+
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            var length = input.ReadLength();
+            Assert.AreEqual(10, input.ReadInt32());
+            Assert.AreEqual(1000, input.ReadInt32());
+            Assert.AreEqual(1000000, input.ReadInt32());
+            Assert.IsTrue(input.IsAtEnd);
+            Assert.AreEqual(1 + CodedOutputStream.ComputeLengthSize(length) + length, stream.Length);
+        }
+
+        [Test]
+        public void WriteTo_NonPackedInt32()
+        {
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
+            var field = new RepeatedField<int> { 10, 1000, 1000000};
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            field.WriteTo(output, FieldCodec.ForInt32(tag));
+            output.Flush();
+            stream.Position = 0;
+
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            Assert.AreEqual(10, input.ReadInt32());
+            input.AssertNextTag(tag);
+            Assert.AreEqual(1000, input.ReadInt32());
+            input.AssertNextTag(tag);
+            Assert.AreEqual(1000000, input.ReadInt32());
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void WriteTo_String()
+        {
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var field = new RepeatedField<string> { "Foo", "", "Bar" };
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            field.WriteTo(output, FieldCodec.ForString(tag));
+            output.Flush();
+            stream.Position = 0;
+
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            Assert.AreEqual("Foo", input.ReadString());
+            input.AssertNextTag(tag);
+            Assert.AreEqual("", input.ReadString());
+            input.AssertNextTag(tag);
+            Assert.AreEqual("Bar", input.ReadString());
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void WriteTo_Message()
+        {
+            var message1 = new ForeignMessage { C = 20 };
+            var message2 = new ForeignMessage { C = 25 };
+            uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
+            var field = new RepeatedField<ForeignMessage> { message1, message2 };
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            field.WriteTo(output, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
+            output.Flush();
+            stream.Position = 0;
+
+            var input = new CodedInputStream(stream);
+            input.AssertNextTag(tag);
+            Assert.AreEqual(message1, input.ReadMessage(ForeignMessage.Parser));
+            input.AssertNextTag(tag);
+            Assert.AreEqual(message2, input.ReadMessage(ForeignMessage.Parser));
+            Assert.IsTrue(input.IsAtEnd);
+        }
+
+        [Test]
+        public void CalculateSize_VariableSizeNonPacked()
+        {
+            var list = new RepeatedField<int> { 1, 500, 1 };
+            var tag = WireFormat.MakeTag(1, WireFormat.WireType.Varint);
+            // 2 bytes for the first entry, 3 bytes for the second, 2 bytes for the third
+            Assert.AreEqual(7, list.CalculateSize(FieldCodec.ForInt32(tag)));
+        }
+
+        [Test]
+        public void CalculateSize_FixedSizeNonPacked()
+        {
+            var list = new RepeatedField<int> { 1, 500, 1 };
+            var tag = WireFormat.MakeTag(1, WireFormat.WireType.Fixed32);
+            // 5 bytes for the each entry
+            Assert.AreEqual(15, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
+        }
+
+        [Test]
+        public void CalculateSize_VariableSizePacked()
+        {
+            var list = new RepeatedField<int> { 1, 500, 1};
+            var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
+            // 1 byte for the tag, 1 byte for the length,
+            // 1 byte for the first entry, 2 bytes for the second, 1 byte for the third
+            Assert.AreEqual(6, list.CalculateSize(FieldCodec.ForInt32(tag)));
+        }
+
+        [Test]
+        public void CalculateSize_FixedSizePacked()
+        {
+            var list = new RepeatedField<int> { 1, 500, 1 };
+            var tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
+            // 1 byte for the tag, 1 byte for the length, 4 bytes per entry
+            Assert.AreEqual(14, list.CalculateSize(FieldCodec.ForSFixed32(tag)));
+        }
+
+        [Test]
+        public void TestNegativeEnumArray()
+        {
+            int arraySize = 1 + 1 + (11 * 5);
+            int msgSize = arraySize;
+            byte[] bytes = new byte[msgSize];
+            CodedOutputStream output = new CodedOutputStream(bytes);
+            uint tag = WireFormat.MakeTag(8, WireFormat.WireType.Varint);
+            for (int i = 0; i >= -5; i--)
+            {
+                output.WriteTag(tag);
+                output.WriteEnum(i);
+            }
+
+            Assert.AreEqual(0, output.SpaceLeft);
+
+            CodedInputStream input = new CodedInputStream(bytes);
+            tag = input.ReadTag();
+
+            RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
+            values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
+
+            Assert.AreEqual(6, values.Count);
+            Assert.AreEqual(SampleEnum.None, values[0]);
+            Assert.AreEqual(((SampleEnum)(-1)), values[1]);
+            Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
+            Assert.AreEqual(((SampleEnum)(-3)), values[3]);
+            Assert.AreEqual(((SampleEnum)(-4)), values[4]);
+            Assert.AreEqual(((SampleEnum)(-5)), values[5]);
+        }
+
+
+        [Test]
+        public void TestNegativeEnumPackedArray()
+        {
+            int arraySize = 1 + (10 * 5);
+            int msgSize = 1 + 1 + arraySize;
+            byte[] bytes = new byte[msgSize];
+            CodedOutputStream output = new CodedOutputStream(bytes);
+            // Length-delimited to show we want the packed representation
+            uint tag = WireFormat.MakeTag(8, WireFormat.WireType.LengthDelimited);
+            output.WriteTag(tag);
+            int size = 0;
+            for (int i = 0; i >= -5; i--)
+            {
+                size += CodedOutputStream.ComputeEnumSize(i);
+            }
+            output.WriteRawVarint32((uint)size);
+            for (int i = 0; i >= -5; i--)
+            {
+                output.WriteEnum(i);
+            }
+            Assert.AreEqual(0, output.SpaceLeft);
+
+            CodedInputStream input = new CodedInputStream(bytes);
+            tag = input.ReadTag();
+
+            RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
+            values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
+
+            Assert.AreEqual(6, values.Count);
+            Assert.AreEqual(SampleEnum.None, values[0]);
+            Assert.AreEqual(((SampleEnum)(-1)), values[1]);
+            Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
+            Assert.AreEqual(((SampleEnum)(-3)), values[3]);
+            Assert.AreEqual(((SampleEnum)(-4)), values[4]);
+            Assert.AreEqual(((SampleEnum)(-5)), values[5]);
+        }
+
+        // Fairly perfunctory tests for the non-generic IList implementation
+        [Test]
+        public void IList_Indexer()
+        {
+            var field = new RepeatedField<string> { "first", "second" };
+            IList list = field;
+            Assert.AreEqual("first", list[0]);
+            list[1] = "changed";
+            Assert.AreEqual("changed", field[1]);
+        }
+
+        [Test]
+        public void IList_Contains()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            Assert.IsTrue(list.Contains("second"));
+            Assert.IsFalse(list.Contains("third"));
+            Assert.IsFalse(list.Contains(new object()));
+        }
+
+        [Test]
+        public void IList_Add()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            list.Add("third");
+            CollectionAssert.AreEqual(new[] { "first", "second", "third" }, list);
+        }
+
+        [Test]
+        public void IList_Remove()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            list.Remove("third"); // No-op, no exception
+            list.Remove(new object()); // No-op, no exception
+            list.Remove("first");
+            CollectionAssert.AreEqual(new[] { "second" }, list);
+        }
+
+        [Test]
+        public void IList_IsFixedSize()
+        {
+            var field = new RepeatedField<string> { "first", "second" };
+            IList list = field;
+            Assert.IsFalse(list.IsFixedSize);
+        }
+
+        [Test]
+        public void IList_IndexOf()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            Assert.AreEqual(1, list.IndexOf("second"));
+            Assert.AreEqual(-1, list.IndexOf("third"));
+            Assert.AreEqual(-1, list.IndexOf(new object()));
+        }
+
+        [Test]
+        public void IList_SyncRoot()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            Assert.AreSame(list, list.SyncRoot);
+        }
+
+        [Test]
+        public void IList_CopyTo()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            string[] stringArray = new string[4];
+            list.CopyTo(stringArray, 1);
+            CollectionAssert.AreEqual(new[] { null, "first",  "second", null }, stringArray);
+
+            object[] objectArray = new object[4];
+            list.CopyTo(objectArray, 1);
+            CollectionAssert.AreEqual(new[] { null, "first", "second", null }, objectArray);
+
+            Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new StringBuilder[4], 1));
+            Assert.Throws<ArrayTypeMismatchException>(() => list.CopyTo(new int[4], 1));
+        }
+
+        [Test]
+        public void IList_IsSynchronized()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            Assert.IsFalse(list.IsSynchronized);
+        }
+
+        [Test]
+        public void IList_Insert()
+        {
+            IList list = new RepeatedField<string> { "first", "second" };
+            list.Insert(1, "middle");
+            CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
+        }
+
+        [Test]
+        public void ToString_Integers()
+        {
+            var list = new RepeatedField<int> { 5, 10, 20 };
+            var text = list.ToString();
+            Assert.AreEqual("[ 5, 10, 20 ]", text);
+        }
+
+        [Test]
+        public void ToString_Strings()
+        {
+            var list = new RepeatedField<string> { "x", "y", "z" };
+            var text = list.ToString();
+            Assert.AreEqual("[ \"x\", \"y\", \"z\" ]", text);
+        }
+
+        [Test]
+        public void ToString_Messages()
+        {
+            var list = new RepeatedField<TestAllTypes> { new TestAllTypes { SingleDouble = 1.5 }, new TestAllTypes { SingleInt32 = 10 } };
+            var text = list.ToString();
+            Assert.AreEqual("[ { \"singleDouble\": 1.5 }, { \"singleInt32\": 10 } ]", text);
+        }
+
+        [Test]
+        public void ToString_Empty()
+        {
+            var list = new RepeatedField<TestAllTypes> { };
+            var text = list.ToString();
+            Assert.AreEqual("[ ]", text);
+        }
+
+        [Test]
+        public void ToString_InvalidElementType()
+        {
+            var list = new RepeatedField<decimal> { 15m };
+            Assert.Throws<ArgumentException>(() => list.ToString());
+        }
+
+        [Test]
+        public void ToString_Timestamp()
+        {
+            var list = new RepeatedField<Timestamp> { Timestamp.FromDateTime(new DateTime(2015, 10, 1, 12, 34, 56, DateTimeKind.Utc)) };
+            var text = list.ToString();
+            Assert.AreEqual("[ \"2015-10-01T12:34:56Z\" ]", text);
+        }
+
+        [Test]
+        public void ToString_Struct()
+        {
+            var message = new Struct { Fields = { { "foo", new Value { NumberValue = 20 } } } };
+            var list = new RepeatedField<Struct> { message };
+            var text = list.ToString();
+            Assert.AreEqual(text, "[ { \"foo\": 20 } ]", message.ToString());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Compatibility/PropertyInfoExtensionsTest.cs b/csharp/src/Google.Protobuf.Test/Compatibility/PropertyInfoExtensionsTest.cs
new file mode 100644
index 0000000..df23a09
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Compatibility/PropertyInfoExtensionsTest.cs
@@ -0,0 +1,98 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    public class PropertyInfoExtensionsTest
+    {
+        public string PublicReadWrite { get; set; }
+        private string PrivateReadWrite { get; set; }
+        public string PublicReadPrivateWrite { get; private set; }
+        public string PrivateReadPublicWrite { private get; set; }
+        public string PublicReadOnly { get { return null; } }
+        private string PrivateReadOnly { get { return null; } }
+        public string PublicWriteOnly { set { } }
+        private string PrivateWriteOnly { set {  } }
+
+        [Test]
+        [TestCase("PublicReadWrite")]
+        [TestCase("PublicReadPrivateWrite")]
+        [TestCase("PublicReadOnly")]
+        public void GetGetMethod_Success(string name)
+        {
+            var propertyInfo = typeof(PropertyInfoExtensionsTest)
+                .GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+            Assert.IsNotNull(PropertyInfoExtensions.GetGetMethod(propertyInfo));
+        }
+
+        [Test]
+        [TestCase("PrivateReadWrite")]
+        [TestCase("PrivateReadPublicWrite")]
+        [TestCase("PrivateReadOnly")]
+        [TestCase("PublicWriteOnly")]
+        [TestCase("PrivateWriteOnly")]
+        public void GetGetMethod_NoAccessibleGetter(string name)
+        {
+            var propertyInfo = typeof(PropertyInfoExtensionsTest)
+                .GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+            Assert.IsNull(PropertyInfoExtensions.GetGetMethod(propertyInfo));
+        }
+
+        [Test]
+        [TestCase("PublicReadWrite")]
+        [TestCase("PrivateReadPublicWrite")]
+        [TestCase("PublicWriteOnly")]
+        public void GetSetMethod_Success(string name)
+        {
+            var propertyInfo = typeof(PropertyInfoExtensionsTest)
+                .GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+            Assert.IsNotNull(PropertyInfoExtensions.GetSetMethod(propertyInfo));
+        }
+
+        [Test]
+        [TestCase("PublicReadPrivateWrite")]
+        [TestCase("PrivateReadWrite")]
+        [TestCase("PrivateReadOnly")]
+        [TestCase("PublicReadOnly")]
+        [TestCase("PrivateWriteOnly")]
+        public void GetSetMethod_NoAccessibleGetter(string name)
+        {
+            var propertyInfo = typeof(PropertyInfoExtensionsTest)
+                .GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+            Assert.IsNull(PropertyInfoExtensions.GetSetMethod(propertyInfo));
+        }
+    }
+
+}
diff --git a/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs
new file mode 100644
index 0000000..f0c8d3b
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs
@@ -0,0 +1,133 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    public class TypeExtensionsTest
+    {
+        public class DerivedList : List<string> { }
+        public string PublicProperty { get; set; }
+        private string PrivateProperty { get; set; }
+
+        public void PublicMethod()
+        {
+        }
+
+        private void PrivateMethod()
+        {
+        }
+
+        [Test]
+        [TestCase(typeof(int), true)]
+        [TestCase(typeof(int?), true)]
+        [TestCase(typeof(Nullable<>), true)]
+        [TestCase(typeof(WireFormat.WireType), true)]
+        [TestCase(typeof(string), false)]
+        [TestCase(typeof(object), false)]
+        [TestCase(typeof(Enum), false)]
+        [TestCase(typeof(ValueType), false)]
+        [TestCase(typeof(TypeExtensionsTest), false)]
+        [TestCase(typeof(Action), false)]
+        [TestCase(typeof(Action<>), false)]
+        [TestCase(typeof(IDisposable), false)]
+        public void IsValueType(Type type, bool expected)
+        {
+            Assert.AreEqual(expected, TypeExtensions.IsValueType(type));
+        }
+
+        [Test]
+        [TestCase(typeof(object), typeof(string), true)]
+        [TestCase(typeof(object), typeof(int), true)]
+        [TestCase(typeof(string), typeof(string), true)]
+        [TestCase(typeof(string), typeof(object), false)]
+        [TestCase(typeof(string), typeof(int), false)]
+        [TestCase(typeof(int), typeof(int), true)]
+        [TestCase(typeof(ValueType), typeof(int), true)]
+        [TestCase(typeof(long), typeof(int), false)] // 
+        public void IsAssignableFrom(Type target, Type argument, bool expected)
+        {
+            Assert.AreEqual(expected, TypeExtensions.IsAssignableFrom(target, argument));
+        }
+
+        [Test]
+        [TestCase(typeof(DerivedList), "Count")] // Go up the type hierarchy
+        [TestCase(typeof(List<string>), "Count")]
+        [TestCase(typeof(List<>), "Count")]
+        [TestCase(typeof(TypeExtensionsTest), "PublicProperty")]
+        public void GetProperty_Success(Type type, string name)
+        {
+            var property = TypeExtensions.GetProperty(type, name);
+            Assert.IsNotNull(property);
+            Assert.AreEqual(name, property.Name);
+        }
+
+        [Test]
+        [TestCase(typeof(TypeExtensionsTest), "PrivateProperty")]
+        [TestCase(typeof(TypeExtensionsTest), "Garbage")]
+        public void GetProperty_NoSuchProperty(Type type, string name)
+        {
+            var property = TypeExtensions.GetProperty(type, name);
+            Assert.IsNull(property);
+        }
+
+        [Test]
+        [TestCase(typeof(DerivedList), "RemoveAt")] // Go up the type hierarchy
+        [TestCase(typeof(List<>), "RemoveAt")]
+        [TestCase(typeof(TypeExtensionsTest), "PublicMethod")]
+        public void GetMethod_Success(Type type, string name)
+        {
+            var method = TypeExtensions.GetMethod(type, name);
+            Assert.IsNotNull(method);
+            Assert.AreEqual(name, method.Name);
+        }
+
+        [Test]
+        [TestCase(typeof(TypeExtensionsTest), "PrivateMethod")]
+        [TestCase(typeof(TypeExtensionsTest), "GarbageMethod")]
+        public void GetMethod_NoSuchMethod(Type type, string name)
+        {
+            var method = TypeExtensions.GetMethod(type, name);
+            Assert.IsNull(method);
+        }
+
+        [Test]
+        [TestCase(typeof(List<string>), "IndexOf")]
+        public void GetMethod_Ambiguous(Type type, string name)
+        {
+            Assert.Throws<AmbiguousMatchException>(() => TypeExtensions.GetMethod(type, name));
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs
new file mode 100644
index 0000000..34d5b9f
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2015 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+    

+using System;

+using System.Reflection;

+using Google.Protobuf.TestProtos;

+using NUnit.Framework;

+

+namespace Google.Protobuf

+{

+    public class DeprecatedMemberTest

+    {

+        private static void AssertIsDeprecated(MemberInfo member)

+        {

+            Assert.NotNull(member);

+            Assert.IsTrue(member.IsDefined(typeof(ObsoleteAttribute), false), "Member not obsolete: " + member);

+        }

+

+        [Test]

+        public void TestDepreatedPrimitiveValue()

+        {

+            AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32"));

+        }

+

+    }

+}

diff --git a/csharp/src/Google.Protobuf.Test/EqualityTester.cs b/csharp/src/Google.Protobuf.Test/EqualityTester.cs
new file mode 100644
index 0000000..a669bab
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/EqualityTester.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using NUnit.Framework;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods when testing equality. NUnit's Assert.AreEqual and
+    /// Assert.AreNotEqual methods try to be clever with collections, which can
+    /// be annoying...
+    /// </summary>
+    internal static class EqualityTester
+    {
+        public static void AssertEquality<T>(T first, T second) where T : IEquatable<T>
+        {
+            Assert.IsTrue(first.Equals(second));
+            Assert.IsTrue(first.Equals((object) second));
+            Assert.AreEqual(first.GetHashCode(), second.GetHashCode());
+        }
+
+        public static void AssertInequality<T>(T first, T second) where T : IEquatable<T>
+        {
+            Assert.IsFalse(first.Equals(second));
+            Assert.IsFalse(first.Equals((object) second));
+            // While this isn't a requirement, the chances of this test failing due to
+            // coincidence rather than a bug are very small.
+            if (first != null && second != null)
+            {
+                Assert.AreNotEqual(first.GetHashCode(), second.GetHashCode());
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
new file mode 100644
index 0000000..c616470
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
@@ -0,0 +1,195 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Collections.Generic;
+using System.IO;
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+
+namespace Google.Protobuf
+{
+    public class FieldCodecTest
+    {
+#pragma warning disable 0414 // Used by tests via reflection - do not remove!
+        private static readonly List<ICodecTestData> Codecs = new List<ICodecTestData>
+        {
+            new FieldCodecTestData<bool>(FieldCodec.ForBool(100), true, "Bool"),
+            new FieldCodecTestData<string>(FieldCodec.ForString(100), "sample", "String"),
+            new FieldCodecTestData<ByteString>(FieldCodec.ForBytes(100), ByteString.CopyFrom(1, 2, 3), "Bytes"),
+            new FieldCodecTestData<int>(FieldCodec.ForInt32(100), -1000, "Int32"),
+            new FieldCodecTestData<int>(FieldCodec.ForSInt32(100), -1000, "SInt32"),
+            new FieldCodecTestData<int>(FieldCodec.ForSFixed32(100), -1000, "SFixed32"),
+            new FieldCodecTestData<uint>(FieldCodec.ForUInt32(100), 1234, "UInt32"),
+            new FieldCodecTestData<uint>(FieldCodec.ForFixed32(100), 1234, "Fixed32"),
+            new FieldCodecTestData<long>(FieldCodec.ForInt64(100), -1000, "Int64"),
+            new FieldCodecTestData<long>(FieldCodec.ForSInt64(100), -1000, "SInt64"),
+            new FieldCodecTestData<long>(FieldCodec.ForSFixed64(100), -1000, "SFixed64"),
+            new FieldCodecTestData<ulong>(FieldCodec.ForUInt64(100), 1234, "UInt64"),
+            new FieldCodecTestData<ulong>(FieldCodec.ForFixed64(100), 1234, "Fixed64"),
+            new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "Float"),
+            new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "Double"),
+            new FieldCodecTestData<ForeignEnum>(
+                FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.ForeignBaz, "Enum"),
+            new FieldCodecTestData<ForeignMessage>(
+                FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
+        };
+#pragma warning restore 0414
+
+        [Test, TestCaseSource("Codecs")]
+        public void RoundTripWithTag(ICodecTestData codec)
+        {
+            codec.TestRoundTripWithTag();
+        }
+
+        [Test, TestCaseSource("Codecs")]
+        public void RoundTripRaw(ICodecTestData codec)
+        {
+            codec.TestRoundTripRaw();
+        }
+
+        [Test, TestCaseSource("Codecs")]
+        public void CalculateSize(ICodecTestData codec)
+        {
+            codec.TestCalculateSizeWithTag();
+        }
+
+        [Test, TestCaseSource("Codecs")]
+        public void DefaultValue(ICodecTestData codec)
+        {
+            codec.TestDefaultValue();
+        }
+
+        [Test, TestCaseSource("Codecs")]
+        public void FixedSize(ICodecTestData codec)
+        {
+            codec.TestFixedSize();
+        }
+
+        // This is ugly, but it means we can have a non-generic interface.
+        // It feels like NUnit should support this better, but I don't know
+        // of any better ways right now.
+        public interface ICodecTestData
+        {
+            void TestRoundTripRaw();
+            void TestRoundTripWithTag();
+            void TestCalculateSizeWithTag();
+            void TestDefaultValue();
+            void TestFixedSize();
+        }
+
+        public class FieldCodecTestData<T> : ICodecTestData
+        {
+            private readonly FieldCodec<T> codec;
+            private readonly T sampleValue;
+            private readonly string name;
+
+            public FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)
+            {
+                this.codec = codec;
+                this.sampleValue = sampleValue;
+                this.name = name;
+            }
+
+            public void TestRoundTripRaw()
+            {
+                var stream = new MemoryStream();
+                var codedOutput = new CodedOutputStream(stream);
+                codec.ValueWriter(codedOutput, sampleValue);
+                codedOutput.Flush();
+                stream.Position = 0;
+                var codedInput = new CodedInputStream(stream);
+                Assert.AreEqual(sampleValue, codec.ValueReader(codedInput));
+                Assert.IsTrue(codedInput.IsAtEnd);
+            }
+
+            public void TestRoundTripWithTag()
+            {
+                var stream = new MemoryStream();
+                var codedOutput = new CodedOutputStream(stream);
+                codec.WriteTagAndValue(codedOutput, sampleValue);
+                codedOutput.Flush();
+                stream.Position = 0;
+                var codedInput = new CodedInputStream(stream);
+                codedInput.AssertNextTag(codec.Tag);
+                Assert.AreEqual(sampleValue, codec.Read(codedInput));
+                Assert.IsTrue(codedInput.IsAtEnd);
+            }
+
+            public void TestCalculateSizeWithTag()
+            {
+                var stream = new MemoryStream();
+                var codedOutput = new CodedOutputStream(stream);
+                codec.WriteTagAndValue(codedOutput, sampleValue);
+                codedOutput.Flush();
+                Assert.AreEqual(stream.Position, codec.CalculateSizeWithTag(sampleValue));
+            }
+
+            public void TestDefaultValue()
+            {
+                // WriteTagAndValue ignores default values
+                var stream = new MemoryStream();
+                var codedOutput = new CodedOutputStream(stream);
+                codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
+                codedOutput.Flush();
+                Assert.AreEqual(0, stream.Position);
+                Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
+                if (typeof(T).IsValueType)
+                {
+                    Assert.AreEqual(default(T), codec.DefaultValue);
+                }
+
+                // The plain ValueWriter/ValueReader delegates don't.
+                if (codec.DefaultValue != null) // This part isn't appropriate for message types.
+                {
+                    codedOutput = new CodedOutputStream(stream);
+                    codec.ValueWriter(codedOutput, codec.DefaultValue);
+                    codedOutput.Flush();
+                    Assert.AreNotEqual(0, stream.Position);
+                    Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
+                    stream.Position = 0;
+                    var codedInput = new CodedInputStream(stream);
+                    Assert.AreEqual(codec.DefaultValue, codec.ValueReader(codedInput));
+                }
+            }
+
+            public void TestFixedSize()
+            {
+                Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
+            }
+
+            public override string ToString()
+            {
+                return name;
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
new file mode 100644
index 0000000..8b153d6
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -0,0 +1,723 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2015 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using System.IO;

+using Google.Protobuf.TestProtos;

+using NUnit.Framework;

+using System.Collections;

+using System.Collections.Generic;

+using System.Linq;

+using Google.Protobuf.WellKnownTypes;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Tests around the generated TestAllTypes message.

+    /// </summary>

+    public class GeneratedMessageTest

+    {

+        [Test]

+        public void EmptyMessageFieldDistinctFromMissingMessageField()

+        {

+            // This demonstrates what we're really interested in...

+            var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() };

+            var message2 = new TestAllTypes(); // SingleForeignMessage is null

+            EqualityTester.AssertInequality(message1, message2);

+        }

+

+        [Test]

+        public void DefaultValues()

+        {

+            // Single fields

+            var message = new TestAllTypes();

+            Assert.AreEqual(false, message.SingleBool);

+            Assert.AreEqual(ByteString.Empty, message.SingleBytes);

+            Assert.AreEqual(0.0, message.SingleDouble);

+            Assert.AreEqual(0, message.SingleFixed32);

+            Assert.AreEqual(0L, message.SingleFixed64);

+            Assert.AreEqual(0.0f, message.SingleFloat);

+            Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum);

+            Assert.IsNull(message.SingleForeignMessage);

+            Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum);

+            Assert.IsNull(message.SingleImportMessage);

+            Assert.AreEqual(0, message.SingleInt32);

+            Assert.AreEqual(0L, message.SingleInt64);

+            Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum);

+            Assert.IsNull(message.SingleNestedMessage);

+            Assert.IsNull(message.SinglePublicImportMessage);

+            Assert.AreEqual(0, message.SingleSfixed32);

+            Assert.AreEqual(0L, message.SingleSfixed64);

+            Assert.AreEqual(0, message.SingleSint32);

+            Assert.AreEqual(0L, message.SingleSint64);

+            Assert.AreEqual("", message.SingleString);

+            Assert.AreEqual(0U, message.SingleUint32);

+            Assert.AreEqual(0UL, message.SingleUint64);

+

+            // Repeated fields

+            Assert.AreEqual(0, message.RepeatedBool.Count);

+            Assert.AreEqual(0, message.RepeatedBytes.Count);

+            Assert.AreEqual(0, message.RepeatedDouble.Count);

+            Assert.AreEqual(0, message.RepeatedFixed32.Count);

+            Assert.AreEqual(0, message.RepeatedFixed64.Count);

+            Assert.AreEqual(0, message.RepeatedFloat.Count);

+            Assert.AreEqual(0, message.RepeatedForeignEnum.Count);

+            Assert.AreEqual(0, message.RepeatedForeignMessage.Count);

+            Assert.AreEqual(0, message.RepeatedImportEnum.Count);

+            Assert.AreEqual(0, message.RepeatedImportMessage.Count);

+            Assert.AreEqual(0, message.RepeatedNestedEnum.Count);

+            Assert.AreEqual(0, message.RepeatedNestedMessage.Count);

+            Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count);

+            Assert.AreEqual(0, message.RepeatedSfixed32.Count);

+            Assert.AreEqual(0, message.RepeatedSfixed64.Count);

+            Assert.AreEqual(0, message.RepeatedSint32.Count);

+            Assert.AreEqual(0, message.RepeatedSint64.Count);

+            Assert.AreEqual(0, message.RepeatedString.Count);

+            Assert.AreEqual(0, message.RepeatedUint32.Count);

+            Assert.AreEqual(0, message.RepeatedUint64.Count);

+

+            // Oneof fields

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+        }

+

+        [Test]

+        public void NullStringAndBytesRejected()

+        {

+            var message = new TestAllTypes();

+            Assert.Throws<ArgumentNullException>(() => message.SingleString = null);

+            Assert.Throws<ArgumentNullException>(() => message.OneofString = null);

+            Assert.Throws<ArgumentNullException>(() => message.SingleBytes = null);

+            Assert.Throws<ArgumentNullException>(() => message.OneofBytes = null);

+        }

+

+        [Test]

+        public void RoundTrip_Empty()

+        {

+            var message = new TestAllTypes();

+            // Without setting any values, there's nothing to write.

+            byte[] bytes = message.ToByteArray();

+            Assert.AreEqual(0, bytes.Length);

+            TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, parsed);

+        }

+

+        [Test]

+        public void RoundTrip_SingleValues()

+        {

+            var message = new TestAllTypes

+            {

+                SingleBool = true,

+                SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),

+                SingleDouble = 23.5,

+                SingleFixed32 = 23,

+                SingleFixed64 = 1234567890123,

+                SingleFloat = 12.25f,

+                SingleForeignEnum = ForeignEnum.ForeignBar,

+                SingleForeignMessage = new ForeignMessage { C = 10 },

+                SingleImportEnum = ImportEnum.ImportBaz,

+                SingleImportMessage = new ImportMessage { D = 20 },

+                SingleInt32 = 100,

+                SingleInt64 = 3210987654321,

+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,

+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },

+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },

+                SingleSfixed32 = -123,

+                SingleSfixed64 = -12345678901234,

+                SingleSint32 = -456,

+                SingleSint64 = -12345678901235,

+                SingleString = "test",

+                SingleUint32 = uint.MaxValue,

+                SingleUint64 = ulong.MaxValue

+            };

+

+            byte[] bytes = message.ToByteArray();

+            TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, parsed);

+        }

+

+        [Test]

+        public void RoundTrip_RepeatedValues()

+        {

+            var message = new TestAllTypes

+            {

+                RepeatedBool = { true, false },

+                RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) },

+                RepeatedDouble = { -12.25, 23.5 },

+                RepeatedFixed32 = { uint.MaxValue, 23 },

+                RepeatedFixed64 = { ulong.MaxValue, 1234567890123 },

+                RepeatedFloat = { 100f, 12.25f },

+                RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar },

+                RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } },

+                RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified },

+                RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } },

+                RepeatedInt32 = { 100, 200 },

+                RepeatedInt64 = { 3210987654321, long.MaxValue },

+                RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg },

+                RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } },

+                RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } },

+                RepeatedSfixed32 = { -123, 123 },

+                RepeatedSfixed64 = { -12345678901234, 12345678901234 },

+                RepeatedSint32 = { -456, 100 },

+                RepeatedSint64 = { -12345678901235, 123 },

+                RepeatedString = { "foo", "bar" },

+                RepeatedUint32 = { uint.MaxValue, uint.MinValue },

+                RepeatedUint64 = { ulong.MaxValue, uint.MinValue }

+            };

+

+            byte[] bytes = message.ToByteArray();

+            TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, parsed);

+        }

+

+        // Note that not every map within map_unittest_proto3 is used. They all go through very

+        // similar code paths. The fact that all maps are present is validation that we have codecs

+        // for every type.

+        [Test]

+        public void RoundTrip_Maps()

+        {

+            var message = new TestMap

+            {

+                MapBoolBool = {

+                    { false, true },

+                    { true, false }

+                },

+                MapInt32Bytes = {

+                    { 5, ByteString.CopyFrom(6, 7, 8) },

+                    { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) },

+                    { 10, ByteString.Empty }

+                },

+                MapInt32ForeignMessage = {

+                    { 0, new ForeignMessage { C = 10 } },

+                    { 5, new ForeignMessage() },

+                },

+                MapInt32Enum = {

+                    { 1, MapEnum.Bar },

+                    { 2000, MapEnum.Foo }

+                }

+            };

+

+            byte[] bytes = message.ToByteArray();

+            TestMap parsed = TestMap.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, parsed);

+        }

+

+        [Test]

+        public void MapWithEmptyEntry()

+        {

+            var message = new TestMap

+            {

+                MapInt32Bytes = { { 0, ByteString.Empty } }

+            };

+

+            byte[] bytes = message.ToByteArray();

+            Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte)

+

+            var parsed = TestMap.Parser.ParseFrom(bytes);

+            Assert.AreEqual(1, parsed.MapInt32Bytes.Count);

+            Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]);

+        }

+

+        [Test]

+        public void MapWithOnlyValue()

+        {

+            // Hand-craft the stream to contain a single entry with just a value.

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+            output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);

+            var nestedMessage = new ForeignMessage { C = 20 };

+            // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage)

+            output.WriteLength(2 + nestedMessage.CalculateSize());

+            output.WriteTag(2, WireFormat.WireType.LengthDelimited);

+            output.WriteMessage(nestedMessage);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]);

+        }

+

+        [Test]

+        public void MapWithOnlyKey_PrimitiveValue()

+        {

+            // Hand-craft the stream to contain a single entry with just a key.

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+            output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited);

+            int key = 10;

+            output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(0.0, parsed.MapInt32Double[key]);

+        }

+

+        [Test]

+        public void MapWithOnlyKey_MessageValue()

+        {

+            // Hand-craft the stream to contain a single entry with just a key.

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+            output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);

+            int key = 10;

+            output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]);

+        }

+

+        [Test]

+        public void MapIgnoresExtraFieldsWithinEntryMessages()

+        {

+            // Hand-craft the stream to contain a single entry with three fields

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+

+            var key = 10; // Field 1 

+            var value = 20; // Field 2

+            var extra = 30; // Field 3

+

+            // Each field can be represented in a single byte, with a single byte tag.

+            // Total message size: 6 bytes.

+            output.WriteLength(6);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value);

+            output.WriteTag(3, WireFormat.WireType.Varint);

+            output.WriteInt32(extra);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(value, parsed.MapInt32Int32[key]);

+        }

+

+        [Test]

+        public void MapFieldOrderIsIrrelevant()

+        {

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+

+            var key = 10;

+            var value = 20;

+

+            // Each field can be represented in a single byte, with a single byte tag.

+            // Total message size: 4 bytes.

+            output.WriteLength(4);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(value, parsed.MapInt32Int32[key]);

+        }

+

+        [Test]

+        public void MapNonContiguousEntries()

+        {

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+

+            // Message structure:

+            // Entry for MapInt32Int32

+            // Entry for MapStringString

+            // Entry for MapInt32Int32

+

+            // First entry

+            var key1 = 10;

+            var value1 = 20;

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteLength(4);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key1);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value1);

+

+            // Second entry

+            var key2 = "a";

+            var value2 = "b";

+            output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteLength(6); // 3 bytes per entry: tag, size, character

+            output.WriteTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteString(key2);

+            output.WriteTag(2, WireFormat.WireType.LengthDelimited);

+            output.WriteString(value2);

+

+            // Third entry

+            var key3 = 15;

+            var value3 = 25;

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteLength(4);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key3);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value3);

+

+            output.Flush();

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            var expected = new TestMap

+            {

+                MapInt32Int32 = { { key1, value1 }, { key3, value3 } },

+                MapStringString = { { key2, value2 } }

+            };

+            Assert.AreEqual(expected, parsed);

+        }

+

+        [Test]

+        public void DuplicateKeys_LastEntryWins()

+        {

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+

+            var key = 10;

+            var value1 = 20;

+            var value2 = 30;

+

+            // First entry

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteLength(4);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value1);

+

+            // Second entry - same key, different value

+            output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteLength(4);

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.WriteTag(2, WireFormat.WireType.Varint);

+            output.WriteInt32(value2);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(value2, parsed.MapInt32Int32[key]);

+        }

+

+        [Test]

+        public void CloneSingleNonMessageValues()

+        {

+            var original = new TestAllTypes

+            {

+                SingleBool = true,

+                SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),

+                SingleDouble = 23.5,

+                SingleFixed32 = 23,

+                SingleFixed64 = 1234567890123,

+                SingleFloat = 12.25f,

+                SingleInt32 = 100,

+                SingleInt64 = 3210987654321,

+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,

+                SingleSfixed32 = -123,

+                SingleSfixed64 = -12345678901234,

+                SingleSint32 = -456,

+                SingleSint64 = -12345678901235,

+                SingleString = "test",

+                SingleUint32 = uint.MaxValue,

+                SingleUint64 = ulong.MaxValue

+            };

+            var clone = original.Clone();

+            Assert.AreNotSame(original, clone);

+            Assert.AreEqual(original, clone);

+            // Just as a single example

+            clone.SingleInt32 = 150;

+            Assert.AreNotEqual(original, clone);

+        }

+

+        [Test]

+        public void CloneRepeatedNonMessageValues()

+        {

+            var original = new TestAllTypes

+            {

+                RepeatedBool = { true, false },

+                RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) },

+                RepeatedDouble = { -12.25, 23.5 },

+                RepeatedFixed32 = { uint.MaxValue, 23 },

+                RepeatedFixed64 = { ulong.MaxValue, 1234567890123 },

+                RepeatedFloat = { 100f, 12.25f },

+                RepeatedInt32 = { 100, 200 },

+                RepeatedInt64 = { 3210987654321, long.MaxValue },

+                RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg },

+                RepeatedSfixed32 = { -123, 123 },

+                RepeatedSfixed64 = { -12345678901234, 12345678901234 },

+                RepeatedSint32 = { -456, 100 },

+                RepeatedSint64 = { -12345678901235, 123 },

+                RepeatedString = { "foo", "bar" },

+                RepeatedUint32 = { uint.MaxValue, uint.MinValue },

+                RepeatedUint64 = { ulong.MaxValue, uint.MinValue }

+            };

+

+            var clone = original.Clone();

+            Assert.AreNotSame(original, clone);

+            Assert.AreEqual(original, clone);

+            // Just as a single example

+            clone.RepeatedDouble.Add(25.5);

+            Assert.AreNotEqual(original, clone);

+        }

+

+        [Test]

+        public void CloneSingleMessageField()

+        {

+            var original = new TestAllTypes

+            {

+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 }

+            };

+

+            var clone = original.Clone();

+            Assert.AreNotSame(original, clone);

+            Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage);

+            Assert.AreEqual(original, clone);

+

+            clone.SingleNestedMessage.Bb = 30;

+            Assert.AreNotEqual(original, clone);

+        }

+

+        [Test]

+        public void CloneRepeatedMessageField()

+        {

+            var original = new TestAllTypes

+            {

+                RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } }

+            };

+

+            var clone = original.Clone();

+            Assert.AreNotSame(original, clone);

+            Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage);

+            Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]);

+            Assert.AreEqual(original, clone);

+

+            clone.RepeatedNestedMessage[0].Bb = 30;

+            Assert.AreNotEqual(original, clone);

+        }

+

+        [Test]

+        public void CloneOneofField()

+        {

+            var original = new TestAllTypes

+            {

+                OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 }

+            };

+

+            var clone = original.Clone();

+            Assert.AreNotSame(original, clone);

+            Assert.AreEqual(original, clone);

+

+            // We should have cloned the message

+            original.OneofNestedMessage.Bb = 30;

+            Assert.AreNotEqual(original, clone);

+        }

+

+        [Test]

+        public void OneofProperties()

+        {

+            // Switch the oneof case between each of the different options, and check everything behaves

+            // as expected in each case.

+            var message = new TestAllTypes();

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);

+

+            message.OneofString = "sample";

+            Assert.AreEqual("sample", message.OneofString);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);

+

+            var bytes = ByteString.CopyFrom(1, 2, 3);

+            message.OneofBytes = bytes;

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual(bytes, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase);

+

+            message.OneofUint32 = 20;

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(20, message.OneofUint32);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase);

+

+            var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 };

+            message.OneofNestedMessage = nestedMessage;

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.AreEqual(nestedMessage, message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase);

+

+            message.ClearOneofField();

+            Assert.AreEqual("", message.OneofString);

+            Assert.AreEqual(0, message.OneofUint32);

+            Assert.AreEqual(ByteString.Empty, message.OneofBytes);

+            Assert.IsNull(message.OneofNestedMessage);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);

+        }

+

+        [Test]

+        public void Oneof_DefaultValuesNotEqual()

+        {

+            var message1 = new TestAllTypes { OneofString = "" };

+            var message2 = new TestAllTypes { OneofUint32 = 0 };

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);

+            Assert.AreNotEqual(message1, message2);

+        }

+

+        [Test]

+        public void OneofSerialization_NonDefaultValue()

+        {

+            var message = new TestAllTypes();

+            message.OneofString = "this would take a bit of space";

+            message.OneofUint32 = 10;

+            var bytes = message.ToByteArray();

+            Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string!

+

+            var message2 = TestAllTypes.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, message2);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);

+        }

+

+        [Test]

+        public void OneofSerialization_DefaultValue()

+        {

+            var message = new TestAllTypes();

+            message.OneofString = "this would take a bit of space";

+            message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized

+            var bytes = message.ToByteArray();

+            Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized

+

+            var message2 = TestAllTypes.Parser.ParseFrom(bytes);

+            Assert.AreEqual(message, message2);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);

+        }

+

+        [Test]

+        public void IgnoreUnknownFields_RealDataStillRead()

+        {

+            var message = SampleMessages.CreateFullTestAllTypes();

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            var unusedFieldNumber = 23456;

+            Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber));

+            output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited);

+            output.WriteString("ignore me");

+            message.WriteTo(output);

+            output.Flush();

+

+            stream.Position = 0;

+            var parsed = TestAllTypes.Parser.ParseFrom(stream);

+            Assert.AreEqual(message, parsed);

+        }

+

+        [Test]

+        public void IgnoreUnknownFields_AllTypes()

+        {

+            // Simple way of ensuring we can skip all kinds of fields.

+            var data = SampleMessages.CreateFullTestAllTypes().ToByteArray();

+            var empty = Empty.Parser.ParseFrom(data);

+            Assert.AreEqual(new Empty(), empty);

+        }

+

+        // This was originally seen as a conformance test failure.

+        [Test]

+        public void TruncatedMessageFieldThrows()

+        {

+            // 130, 3 is the message tag

+            // 1 is the data length - but there's no data.

+            var data = new byte[] { 130, 3, 1 };

+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));

+        }

+

+        /// <summary>

+        /// Demonstrates current behaviour with an extraneous end group tag - see issue 688

+        /// for details; we may want to change this.

+        /// </summary>

+        [Test]

+        public void ExtraEndGroupThrows()

+        {

+            var message = SampleMessages.CreateFullTestAllTypes();

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+

+            output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32);

+            output.WriteFixed32(123);

+            output.WriteTag(100, WireFormat.WireType.EndGroup);

+

+            output.Flush();

+

+            stream.Position = 0;

+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream));

+        }

+

+        [Test]

+        public void CustomDiagnosticMessage_DirectToStringCall()

+        {

+            var message = new ForeignMessage { C = 31 };

+            Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString());

+            Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message));

+        }

+

+        [Test]

+        public void CustomDiagnosticMessage_Nested()

+        {

+            var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } };

+            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString());

+            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message));

+        }

+

+        [Test]

+        public void CustomDiagnosticMessage_DirectToTextWriterCall()

+        {

+            var message = new ForeignMessage { C = 31 };

+            var writer = new StringWriter();

+            JsonFormatter.Default.Format(message, writer);

+            Assert.AreEqual("{ \"c\": 31 }", writer.ToString());

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
new file mode 100644
index 0000000..4f37c5e
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>9.0.30729</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{DD01ED24-3750-4567-9A23-1DB676A15610}</ProjectGuid>

+    <OutputType>Library</OutputType>

+    <AppDesignerFolder>Properties</AppDesignerFolder>

+    <RootNamespace>Google.Protobuf</RootNamespace>

+    <AssemblyName>Google.Protobuf.Test</AssemblyName>

+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

+    <FileAlignment>512</FileAlignment>

+    <OldToolsVersion>3.5</OldToolsVersion>

+    <TargetFrameworkProfile>

+    </TargetFrameworkProfile>

+    <NuGetPackageImportStamp>

+    </NuGetPackageImportStamp>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <Optimize>false</Optimize>

+    <OutputPath>bin\Debug</OutputPath>

+    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

+    <DefineConstants>DEBUG;TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release</OutputPath>

+    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

+    <DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\ReleaseSigned</OutputPath>

+    <IntermediateOutputPath>obj\ReleaseSigned\</IntermediateOutputPath>

+    <DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <Prefer32Bit>false</Prefer32Bit>

+    <SignAssembly>True</SignAssembly>

+    <AssemblyOriginatorKeyFile>..\..\keys\Google.Protobuf.snk</AssemblyOriginatorKeyFile>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="mscorlib" />

+    <Reference Include="nunit.core, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>

+      <Private>True</Private>

+    </Reference>

+    <Reference Include="nunit.core.interfaces, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>

+      <Private>True</Private>

+    </Reference>

+    <Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

+      <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>

+      <Private>True</Private>

+    </Reference>

+    <Reference Include="nunit.util, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>

+      <Private>True</Private>

+    </Reference>

+    <Reference Include="NUnit.VisualStudio.TestAdapter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac, processorArchitecture=MSIL">

+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>

+      <Private>True</Private>

+    </Reference>

+    <Reference Include="System" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="ByteStringTest.cs" />

+    <Compile Include="CodedInputStreamExtensions.cs" />

+    <Compile Include="CodedInputStreamTest.cs" />

+    <Compile Include="CodedOutputStreamTest.cs" />

+    <Compile Include="Compatibility\PropertyInfoExtensionsTest.cs" />

+    <Compile Include="Compatibility\TypeExtensionsTest.cs" />

+    <Compile Include="EqualityTester.cs" />

+    <Compile Include="FieldCodecTest.cs" />

+    <Compile Include="GeneratedMessageTest.cs" />

+    <Compile Include="Collections\MapFieldTest.cs" />

+    <Compile Include="Collections\RepeatedFieldTest.cs" />

+    <Compile Include="JsonFormatterTest.cs" />

+    <Compile Include="JsonParserTest.cs" />

+    <Compile Include="JsonTokenizerTest.cs" />

+    <Compile Include="Reflection\DescriptorsTest.cs" />

+    <Compile Include="Reflection\FieldAccessTest.cs" />

+    <Compile Include="Reflection\TypeRegistryTest.cs" />

+    <Compile Include="SampleEnum.cs" />

+    <Compile Include="SampleMessages.cs" />

+    <Compile Include="TestProtos\ForeignMessagePartial.cs" />

+    <Compile Include="TestProtos\MapUnittestProto3.cs" />

+    <Compile Include="TestProtos\UnittestImportProto3.cs" />

+    <Compile Include="TestProtos\UnittestImportPublicProto3.cs" />

+    <Compile Include="TestProtos\UnittestIssues.cs" />

+    <Compile Include="TestProtos\UnittestProto3.cs" />

+    <Compile Include="DeprecatedMemberTest.cs" />

+    <Compile Include="IssuesTest.cs" />

+    <Compile Include="Properties\AssemblyInfo.cs" />

+    <Compile Include="TestCornerCases.cs" />

+    <Compile Include="TestProtos\UnittestWellKnownTypes.cs" />

+    <Compile Include="WellKnownTypes\AnyTest.cs" />

+    <Compile Include="WellKnownTypes\DurationTest.cs" />

+    <Compile Include="WellKnownTypes\FieldMaskTest.cs" />

+    <Compile Include="WellKnownTypes\TimestampTest.cs" />

+    <Compile Include="WellKnownTypes\WrappersTest.cs" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

+      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

+      <Name>Google.Protobuf</Name>

+    </ProjectReference>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="packages.config" />

+  </ItemGroup>

+  <ItemGroup>

+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

+  </ItemGroup>

+  <ItemGroup />

+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/src/Google.Protobuf.Test/IssuesTest.cs
new file mode 100644
index 0000000..a38d6b0
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs
@@ -0,0 +1,82 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using Google.Protobuf.Reflection;

+using UnitTest.Issues.TestProtos;

+using NUnit.Framework;

+

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Tests for issues which aren't easily compartmentalized into other unit tests.

+    /// </summary>

+    public class IssuesTest

+    {

+        // Issue 45

+        [Test]

+        public void FieldCalledItem()

+        {

+            ItemField message = new ItemField { Item = 3 };

+            FieldDescriptor field = ItemField.Descriptor.FindFieldByName("item");

+            Assert.NotNull(field);

+            Assert.AreEqual(3, (int)field.Accessor.GetValue(message));

+        }

+

+        [Test]

+        public void ReservedNames()

+        {

+            var message = new ReservedNames { Types_ = 10, Descriptor_ = 20 };

+            // Underscores aren't reflected in the JSON.

+            Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString());

+        }

+

+        [Test]

+        public void JsonNameParseTest()

+        {

+            var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor));

+            var parser = new JsonParser(settings);

+

+            // It is safe to use either original field name or explicitly specified json_name

+            Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" },

+                parser.Parse<TestJsonName>("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }"));

+        }

+

+        [Test]

+        public void JsonNameFormatTest()

+        {

+            var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" };

+            Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }",

+                JsonFormatter.Default.Format(message));

+        }

+    }

+}

diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
new file mode 100644
index 0000000..827a759
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
@@ -0,0 +1,526 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+using UnitTest.Issues.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using Google.Protobuf.Reflection;
+
+using static Google.Protobuf.JsonParserTest; // For WrapInQuotes
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Tests for the JSON formatter. Note that in these tests, double quotes are replaced with apostrophes
+    /// for the sake of readability (embedding \" everywhere is painful). See the AssertJson method for details.
+    /// </summary>
+    public class JsonFormatterTest
+    {
+        [Test]
+        public void DefaultValues_WhenOmitted()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(formatDefaultValues: false));
+
+            AssertJson("{ }", formatter.Format(new ForeignMessage()));
+            AssertJson("{ }", formatter.Format(new TestAllTypes()));
+            AssertJson("{ }", formatter.Format(new TestMap()));
+        }
+
+        [Test]
+        public void DefaultValues_WhenIncluded()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(formatDefaultValues: true));
+            AssertJson("{ 'c': 0 }", formatter.Format(new ForeignMessage()));
+        }
+
+        [Test]
+        public void AllSingleFields()
+        {
+            var message = new TestAllTypes
+            {
+                SingleBool = true,
+                SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),
+                SingleDouble = 23.5,
+                SingleFixed32 = 23,
+                SingleFixed64 = 1234567890123,
+                SingleFloat = 12.25f,
+                SingleForeignEnum = ForeignEnum.ForeignBar,
+                SingleForeignMessage = new ForeignMessage { C = 10 },
+                SingleImportEnum = ImportEnum.ImportBaz,
+                SingleImportMessage = new ImportMessage { D = 20 },
+                SingleInt32 = 100,
+                SingleInt64 = 3210987654321,
+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,
+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },
+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },
+                SingleSfixed32 = -123,
+                SingleSfixed64 = -12345678901234,
+                SingleSint32 = -456,
+                SingleSint64 = -12345678901235,
+                SingleString = "test\twith\ttabs",
+                SingleUint32 = uint.MaxValue,
+                SingleUint64 = ulong.MaxValue,
+            };
+            var actualText = JsonFormatter.Default.Format(message);
+
+            // Fields in numeric order
+            var expectedText = "{ " +
+                "'singleInt32': 100, " +
+                "'singleInt64': '3210987654321', " +
+                "'singleUint32': 4294967295, " +
+                "'singleUint64': '18446744073709551615', " +
+                "'singleSint32': -456, " +
+                "'singleSint64': '-12345678901235', " +
+                "'singleFixed32': 23, " +
+                "'singleFixed64': '1234567890123', " +
+                "'singleSfixed32': -123, " +
+                "'singleSfixed64': '-12345678901234', " +
+                "'singleFloat': 12.25, " +
+                "'singleDouble': 23.5, " +
+                "'singleBool': true, " +
+                "'singleString': 'test\\twith\\ttabs', " +
+                "'singleBytes': 'AQIDBA==', " +
+                "'singleNestedMessage': { 'bb': 35 }, " +
+                "'singleForeignMessage': { 'c': 10 }, " +
+                "'singleImportMessage': { 'd': 20 }, " +
+                "'singleNestedEnum': 'FOO', " +
+                "'singleForeignEnum': 'FOREIGN_BAR', " +
+                "'singleImportEnum': 'IMPORT_BAZ', " +
+                "'singlePublicImportMessage': { 'e': 54 }" +
+                " }";
+            AssertJson(expectedText, actualText);
+        }
+
+        [Test]
+        public void RepeatedField()
+        {
+            AssertJson("{ 'repeatedInt32': [ 1, 2, 3, 4, 5 ] }",
+                JsonFormatter.Default.Format(new TestAllTypes { RepeatedInt32 = { 1, 2, 3, 4, 5 } }));
+        }
+
+        [Test]
+        public void MapField_StringString()
+        {
+            AssertJson("{ 'mapStringString': { 'with spaces': 'bar', 'a': 'b' } }",
+                JsonFormatter.Default.Format(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } }));
+        }
+
+        [Test]
+        public void MapField_Int32Int32()
+        {
+            // The keys are quoted, but the values aren't.
+            AssertJson("{ 'mapInt32Int32': { '0': 1, '2': 3 } }",
+                JsonFormatter.Default.Format(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } }));
+        }
+
+        [Test]
+        public void MapField_BoolBool()
+        {
+            // The keys are quoted, but the values aren't.
+            AssertJson("{ 'mapBoolBool': { 'false': true, 'true': false } }",
+                JsonFormatter.Default.Format(new TestMap { MapBoolBool = { { false, true }, { true, false } } }));
+        }
+
+        [TestCase(1.0, "1")]
+        [TestCase(double.NaN, "'NaN'")]
+        [TestCase(double.PositiveInfinity, "'Infinity'")]
+        [TestCase(double.NegativeInfinity, "'-Infinity'")]
+        public void DoubleRepresentations(double value, string expectedValueText)
+        {
+            var message = new TestAllTypes { SingleDouble = value };
+            string actualText = JsonFormatter.Default.Format(message);
+            string expectedText = "{ 'singleDouble': " + expectedValueText + " }";
+            AssertJson(expectedText, actualText);
+        }
+
+        [Test]
+        public void UnknownEnumValueNumeric_SingleField()
+        {
+            var message = new TestAllTypes { SingleForeignEnum = (ForeignEnum) 100 };
+            AssertJson("{ 'singleForeignEnum': 100 }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void UnknownEnumValueNumeric_RepeatedField()
+        {
+            var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } };
+            AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void UnknownEnumValueNumeric_MapField()
+        {
+            var message = new TestMap { MapInt32Enum = { { 1, MapEnum.Foo }, { 2, (MapEnum) 100 }, { 3, MapEnum.Bar } } };
+            AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void UnknownEnumValue_RepeatedField_AllEntriesUnknown()
+        {
+            var message = new TestAllTypes { RepeatedForeignEnum = { (ForeignEnum) 200, (ForeignEnum) 100 } };
+            AssertJson("{ 'repeatedForeignEnum': [ 200, 100 ] }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        [TestCase("a\u17b4b", "a\\u17b4b")] // Explicit
+        [TestCase("a\u0601b", "a\\u0601b")] // Ranged
+        [TestCase("a\u0605b", "a\u0605b")] // Passthrough (note lack of double backslash...)
+        public void SimpleNonAscii(string text, string encoded)
+        {
+            var message = new TestAllTypes { SingleString = text };
+            AssertJson("{ 'singleString': '" + encoded + "' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void SurrogatePairEscaping()
+        {
+            var message = new TestAllTypes { SingleString = "a\uD801\uDC01b" };
+            AssertJson("{ 'singleString': 'a\\ud801\\udc01b' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void InvalidSurrogatePairsFail()
+        {
+            // Note: don't use TestCase for these, as the strings can't be reliably represented 
+            // See http://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/
+
+            // Lone low surrogate
+            var message = new TestAllTypes { SingleString = "a\uDC01b" };
+            Assert.Throws<ArgumentException>(() => JsonFormatter.Default.Format(message));
+
+            // Lone high surrogate
+            message = new TestAllTypes { SingleString = "a\uD801b" };
+            Assert.Throws<ArgumentException>(() => JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        [TestCase("foo_bar", "fooBar")]
+        [TestCase("bananaBanana", "bananaBanana")]
+        [TestCase("BANANABanana", "bananaBanana")]
+        public void ToCamelCase(string original, string expected)
+        {
+            Assert.AreEqual(expected, JsonFormatter.ToCamelCase(original));
+        }
+
+        [Test]
+        [TestCase(null, "{ }")]
+        [TestCase("x", "{ 'fooString': 'x' }")]
+        [TestCase("", "{ 'fooString': '' }")]
+        public void Oneof(string fooStringValue, string expectedJson)
+        {
+            var message = new TestOneof();
+            if (fooStringValue != null)
+            {
+                message.FooString = fooStringValue;
+            }
+
+            // We should get the same result both with and without "format default values".
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false));
+            AssertJson(expectedJson, formatter.Format(message));
+            formatter = new JsonFormatter(new JsonFormatter.Settings(true));
+            AssertJson(expectedJson, formatter.Format(message));
+        }
+
+        [Test]
+        public void WrapperFormatting_Single()
+        {
+            // Just a few examples, handling both classes and value types, and
+            // default vs non-default values
+            var message = new TestWellKnownTypes
+            {
+                Int64Field = 10,
+                Int32Field = 0,
+                BytesField = ByteString.FromBase64("ABCD"),
+                StringField = ""
+            };
+            var expectedJson = "{ 'int64Field': '10', 'int32Field': 0, 'stringField': '', 'bytesField': 'ABCD' }";
+            AssertJson(expectedJson, JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void WrapperFormatting_Message()
+        {
+            Assert.AreEqual("\"\"", JsonFormatter.Default.Format(new StringValue()));
+            Assert.AreEqual("0", JsonFormatter.Default.Format(new Int32Value()));
+        }
+
+        [Test]
+        public void WrapperFormatting_IncludeNull()
+        {
+            // The actual JSON here is very large because there are lots of fields. Just test a couple of them.
+            var message = new TestWellKnownTypes { Int32Field = 10 };
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(true));
+            var actualJson = formatter.Format(message);
+            Assert.IsTrue(actualJson.Contains("\"int64Field\": null"));
+            Assert.IsFalse(actualJson.Contains("\"int32Field\": null"));
+        }
+
+        [Test]
+        public void OutputIsInNumericFieldOrder_NoDefaults()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false));
+            var message = new TestJsonFieldOrdering { PlainString = "p1", PlainInt32 = 2 };
+            AssertJson("{ 'plainString': 'p1', 'plainInt32': 2 }", formatter.Format(message));
+            message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" };
+            AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message));
+            message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" };
+            AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message));
+        }
+
+        [Test]
+        public void OutputIsInNumericFieldOrder_WithDefaults()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(true));
+            var message = new TestJsonFieldOrdering();
+            AssertJson("{ 'plainString': '', 'plainInt32': 0 }", formatter.Format(message));
+            message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" };
+            AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message));
+            message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" };
+            AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message));
+        }
+
+        [Test]
+        [TestCase("1970-01-01T00:00:00Z", 0)]
+        [TestCase("1970-01-01T00:00:00.000000001Z", 1)]
+        [TestCase("1970-01-01T00:00:00.000000010Z", 10)]
+        [TestCase("1970-01-01T00:00:00.000000100Z", 100)]
+        [TestCase("1970-01-01T00:00:00.000001Z", 1000)]
+        [TestCase("1970-01-01T00:00:00.000010Z", 10000)]
+        [TestCase("1970-01-01T00:00:00.000100Z", 100000)]
+        [TestCase("1970-01-01T00:00:00.001Z", 1000000)]
+        [TestCase("1970-01-01T00:00:00.010Z", 10000000)]
+        [TestCase("1970-01-01T00:00:00.100Z", 100000000)]
+        [TestCase("1970-01-01T00:00:00.120Z", 120000000)]
+        [TestCase("1970-01-01T00:00:00.123Z", 123000000)]
+        [TestCase("1970-01-01T00:00:00.123400Z", 123400000)]
+        [TestCase("1970-01-01T00:00:00.123450Z", 123450000)]
+        [TestCase("1970-01-01T00:00:00.123456Z", 123456000)]
+        [TestCase("1970-01-01T00:00:00.123456700Z", 123456700)]
+        [TestCase("1970-01-01T00:00:00.123456780Z", 123456780)]
+        [TestCase("1970-01-01T00:00:00.123456789Z", 123456789)]
+        public void TimestampStandalone(string expected, int nanos)
+        {
+            Assert.AreEqual(WrapInQuotes(expected), new Timestamp { Nanos = nanos }.ToString());
+        }
+
+        [Test]
+        public void TimestampStandalone_FromDateTime()
+        {
+            // One before and one after the Unix epoch, more easily represented via DateTime.
+            Assert.AreEqual("\"1673-06-19T12:34:56Z\"",
+                new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp().ToString());
+            Assert.AreEqual("\"2015-07-31T10:29:34Z\"",
+                new DateTime(2015, 7, 31, 10, 29, 34, DateTimeKind.Utc).ToTimestamp().ToString());
+        }
+
+        [Test]
+        [TestCase(-1, -1)] // Would be valid as duration
+        [TestCase(1, Timestamp.MaxNanos + 1)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, 0)]
+        public void TimestampStandalone_NonNormalized(long seconds, int nanoseconds)
+        {
+            var timestamp = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(timestamp));
+        }
+
+        [Test]
+        public void TimestampField()
+        {
+            var message = new TestWellKnownTypes { TimestampField = new Timestamp() };
+            AssertJson("{ 'timestampField': '1970-01-01T00:00:00Z' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        [TestCase(0, 0, "0s")]
+        [TestCase(1, 0, "1s")]
+        [TestCase(-1, 0, "-1s")]
+        [TestCase(0, 1, "0.000000001s")]
+        [TestCase(0, 10, "0.000000010s")]
+        [TestCase(0, 100, "0.000000100s")]
+        [TestCase(0, 1000, "0.000001s")]
+        [TestCase(0, 10000, "0.000010s")]
+        [TestCase(0, 100000, "0.000100s")]
+        [TestCase(0, 1000000, "0.001s")]
+        [TestCase(0, 10000000, "0.010s")]
+        [TestCase(0, 100000000, "0.100s")]
+        [TestCase(0, 120000000, "0.120s")]
+        [TestCase(0, 123000000, "0.123s")]
+        [TestCase(0, 123400000, "0.123400s")]
+        [TestCase(0, 123450000, "0.123450s")]
+        [TestCase(0, 123456000, "0.123456s")]
+        [TestCase(0, 123456700, "0.123456700s")]
+        [TestCase(0, 123456780, "0.123456780s")]
+        [TestCase(0, 123456789, "0.123456789s")]
+        [TestCase(0, -100000000, "-0.100s")]
+        [TestCase(1, 100000000, "1.100s")]
+        [TestCase(-1, -100000000, "-1.100s")]
+        public void DurationStandalone(long seconds, int nanoseconds, string expected)
+        {
+            var json = JsonFormatter.Default.Format(new Duration { Seconds = seconds, Nanos = nanoseconds });
+            Assert.AreEqual(WrapInQuotes(expected), json);
+        }
+
+        [Test]
+        [TestCase(1, 2123456789)]
+        [TestCase(1, -100000000)]
+        public void DurationStandalone_NonNormalized(long seconds, int nanoseconds)
+        {
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(duration));
+        }
+
+        [Test]
+        public void DurationField()
+        {
+            var message = new TestWellKnownTypes { DurationField = new Duration() };
+            AssertJson("{ 'durationField': '0s' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void StructSample()
+        {
+            var message = new Struct
+            {
+                Fields =
+                {
+                    { "a", Value.ForNull() },
+                    { "b", Value.ForBool(false) },
+                    { "c", Value.ForNumber(10.5) },
+                    { "d", Value.ForString("text") },
+                    { "e", Value.ForList(Value.ForString("t1"), Value.ForNumber(5)) },
+                    { "f", Value.ForStruct(new Struct { Fields = { { "nested", Value.ForString("value") } } }) }
+                }
+            };
+            AssertJson("{ 'a': null, 'b': false, 'c': 10.5, 'd': 'text', 'e': [ 't1', 5 ], 'f': { 'nested': 'value' } }", message.ToString());
+        }
+
+        [Test]
+        [TestCase("foo__bar")]
+        [TestCase("foo_3_ar")]
+        [TestCase("fooBar")]
+        public void FieldMaskInvalid(string input)
+        {
+            var mask = new FieldMask { Paths = { input } };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(mask));
+        }
+
+        [Test]
+        public void FieldMaskStandalone()
+        {
+            var fieldMask = new FieldMask { Paths = { "", "single", "with_underscore", "nested.field.name", "nested..double_dot" } };
+            Assert.AreEqual("\",single,withUnderscore,nested.field.name,nested..doubleDot\"", fieldMask.ToString());
+
+            // Invalid, but we shouldn't create broken JSON...
+            fieldMask = new FieldMask { Paths = { "x\\y" } };
+            Assert.AreEqual(@"""x\\y""", fieldMask.ToString());
+        }
+
+        [Test]
+        public void FieldMaskField()
+        {
+            var message = new TestWellKnownTypes { FieldMaskField = new FieldMask { Paths = { "user.display_name", "photo" } } };
+            AssertJson("{ 'fieldMaskField': 'user.displayName,photo' }", JsonFormatter.Default.Format(message));
+        }
+
+        // SourceContext is an example of a well-known type with no special JSON handling
+        [Test]
+        public void SourceContextStandalone()
+        {
+            var message = new SourceContext { FileName = "foo.proto" };
+            AssertJson("{ 'fileName': 'foo.proto' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void AnyWellKnownType()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(Timestamp.Descriptor)));
+            var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp();
+            var any = Any.Pack(timestamp);
+            AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any));
+        }
+
+        [Test]
+        public void AnyMessageType()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
+            var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } };
+            var any = Any.Pack(message);
+            AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any));
+        }
+
+        [Test]
+        public void AnyMessageType_CustomPrefix()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
+            var message = new TestAllTypes { SingleInt32 = 10 };
+            var any = Any.Pack(message, "foo.bar/baz");
+            AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any));
+        }
+
+        [Test]
+        public void AnyNested()
+        {
+            var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+
+            // Nest an Any as the value of an Any.
+            var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 };
+            var nestedMessage = Any.Pack(doubleNestedMessage);
+            var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
+            AssertJson("{ 'anyField': { '@type': 'type.googleapis.com/google.protobuf.Any', 'value': { '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 20 } } }",
+                formatter.Format(message));
+        }
+
+        [Test]
+        public void AnyUnknownType()
+        {
+            // The default type registry doesn't have any types in it.
+            var message = new TestAllTypes();
+            var any = Any.Pack(message);
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(any));
+        }
+
+        /// <summary>
+        /// Checks that the actual JSON is the same as the expected JSON - but after replacing
+        /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier
+        /// to read.
+        /// </summary>
+        private static void AssertJson(string expectedJsonWithApostrophes, string actualJson)
+        {
+            var expectedJson = expectedJsonWithApostrophes.Replace("'", "\"");
+            Assert.AreEqual(expectedJson, actualJson);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
new file mode 100644
index 0000000..c3ad851
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -0,0 +1,936 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using Google.Protobuf.Reflection;
+using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework;
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Unit tests for JSON parsing.
+    /// </summary>
+    public class JsonParserTest
+    {
+        // Sanity smoke test
+        [Test]
+        public void AllTypesRoundtrip()
+        {
+            AssertRoundtrip(SampleMessages.CreateFullTestAllTypes());
+        }
+
+        [Test]
+        public void Maps()
+        {
+            AssertRoundtrip(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } });
+            AssertRoundtrip(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } });
+            AssertRoundtrip(new TestMap { MapBoolBool = { { false, true }, { true, false } } });
+        }
+
+        [Test]
+        [TestCase(" 1 ")]
+        [TestCase("+1")]
+        [TestCase("1,000")]
+        [TestCase("1.5")]
+        public void IntegerMapKeysAreStrict(string keyText)
+        {
+            // Test that integer parsing is strict. We assume that if this is correct for int32,
+            // it's correct for other numeric key types.
+            var json = "{ \"mapInt32Int32\": { \"" + keyText + "\" : \"1\" } }";
+            Assert.Throws<InvalidProtocolBufferException>(() => JsonParser.Default.Parse<TestMap>(json));
+        }
+
+        [Test]
+        public void OriginalFieldNameAccepted()
+        {
+            var json = "{ \"single_int32\": 10 }";
+            var expected = new TestAllTypes { SingleInt32 = 10 };
+            Assert.AreEqual(expected, TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void SourceContextRoundtrip()
+        {
+            AssertRoundtrip(new SourceContext { FileName = "foo.proto" });
+        }
+
+        [Test]
+        public void SingularWrappers_DefaultNonNullValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "",
+                BytesField = ByteString.Empty,
+                BoolField = false,
+                FloatField = 0f,
+                DoubleField = 0d,
+                Int32Field = 0,
+                Int64Field = 0,
+                Uint32Field = 0,
+                Uint64Field = 0
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void SingularWrappers_NonDefaultValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "x",
+                BytesField = ByteString.CopyFrom(1, 2, 3),
+                BoolField = true,
+                FloatField = 12.5f,
+                DoubleField = 12.25d,
+                Int32Field = 1,
+                Int64Field = 2,
+                Uint32Field = 3,
+                Uint64Field = 4
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void SingularWrappers_ExplicitNulls()
+        {
+            // When we parse the "valueField": null part, we remember it... basically, it's one case
+            // where explicit default values don't fully roundtrip.
+            var message = new TestWellKnownTypes { ValueField = Value.ForNull() };
+            var json = new JsonFormatter(new JsonFormatter.Settings(true)).Format(message);
+            var parsed = JsonParser.Default.Parse<TestWellKnownTypes>(json);
+            Assert.AreEqual(message, parsed);
+        }
+
+        [Test]
+        [TestCase(typeof(Int32Value), "32", 32)]
+        [TestCase(typeof(Int64Value), "32", 32L)]
+        [TestCase(typeof(UInt32Value), "32", 32U)]
+        [TestCase(typeof(UInt64Value), "32", 32UL)]
+        [TestCase(typeof(StringValue), "\"foo\"", "foo")]
+        [TestCase(typeof(FloatValue), "1.5", 1.5f)]
+        [TestCase(typeof(DoubleValue), "1.5", 1.5d)]
+        public void Wrappers_Standalone(System.Type wrapperType, string json, object expectedValue)
+        {
+            IMessage parsed = (IMessage)Activator.CreateInstance(wrapperType);
+            IMessage expected = (IMessage)Activator.CreateInstance(wrapperType);
+            JsonParser.Default.Merge(parsed, "null");
+            Assert.AreEqual(expected, parsed);
+
+            JsonParser.Default.Merge(parsed, json);
+            expected.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(expected, expectedValue);
+            Assert.AreEqual(expected, parsed);
+        }
+
+        [Test]
+        public void ExplicitNullValue()
+        {
+            string json = "{\"valueField\": null}";
+            var message = JsonParser.Default.Parse<TestWellKnownTypes>(json);
+            Assert.AreEqual(new TestWellKnownTypes { ValueField = Value.ForNull() }, message);
+        }
+
+        [Test]
+        public void BytesWrapper_Standalone()
+        {
+            ByteString data = ByteString.CopyFrom(1, 2, 3);
+            // Can't do this with attributes...
+            var parsed = JsonParser.Default.Parse<BytesValue>(WrapInQuotes(data.ToBase64()));
+            var expected = new BytesValue { Value = data };
+            Assert.AreEqual(expected, parsed);
+        }
+
+        [Test]
+        public void RepeatedWrappers()
+        {
+            var message = new RepeatedWellKnownTypes
+            {
+                BoolField = { true, false },
+                BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
+                DoubleField = { 12.5, -1.5, 0d },
+                FloatField = { 123.25f, -20f, 0f },
+                Int32Field = { int.MaxValue, int.MinValue, 0 },
+                Int64Field = { long.MaxValue, long.MinValue, 0L },
+                StringField = { "First", "Second", "" },
+                Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
+                Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void RepeatedField_NullElementProhibited()
+        {
+            string json = "{ \"repeated_foreign_message\": [null] }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void RepeatedField_NullOverallValueAllowed()
+        {
+            string json = "{ \"repeated_foreign_message\": null }";
+            Assert.AreEqual(new TestAllTypes(), TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("{ \"mapInt32Int32\": { \"10\": null }")]
+        [TestCase("{ \"mapStringString\": { \"abc\": null }")]
+        [TestCase("{ \"mapInt32ForeignMessage\": { \"10\": null }")]
+        public void MapField_NullValueProhibited(string json)
+        {
+            Assert.Throws<InvalidProtocolBufferException>(() => TestMap.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void MapField_NullOverallValueAllowed()
+        {
+            string json = "{ \"mapInt32Int32\": null }";
+            Assert.AreEqual(new TestMap(), TestMap.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void IndividualWrapperTypes()
+        {
+            Assert.AreEqual(new StringValue { Value = "foo" }, StringValue.Parser.ParseJson("\"foo\""));
+            Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("1"));
+            // Can parse strings directly too
+            Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("\"1\""));
+        }
+
+        private static void AssertRoundtrip<T>(T message) where T : IMessage<T>, new()
+        {
+            var clone = message.Clone();
+            var json = JsonFormatter.Default.Format(message);
+            var parsed = JsonParser.Default.Parse<T>(json);
+            Assert.AreEqual(clone, parsed);
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        [TestCase("2147483647", 2147483647)]
+        [TestCase("-2147483648", -2147483648)]
+        public void StringToInt32_Valid(string jsonValue, int expectedParsedValue)
+        {
+            string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
+        }
+
+        [Test]
+        [TestCase("+0")]
+        [TestCase(" 1")]
+        [TestCase("1 ")]
+        [TestCase("00")]
+        [TestCase("-00")]
+        [TestCase("--1")]
+        [TestCase("+1")]
+        [TestCase("1.5")]
+        [TestCase("1e10")]
+        [TestCase("2147483648")]
+        [TestCase("-2147483649")]
+        public void StringToInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0U)]
+        [TestCase("1", 1U)]
+        [TestCase("4294967295", 4294967295U)]
+        public void StringToUInt32_Valid(string jsonValue, uint expectedParsedValue)
+        {
+            string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("4294967296")]
+        public void StringToUInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0L)]
+        [TestCase("1", 1L)]
+        [TestCase("-1", -1L)]
+        [TestCase("9223372036854775807", 9223372036854775807)]
+        [TestCase("-9223372036854775808", -9223372036854775808)]
+        public void StringToInt64_Valid(string jsonValue, long expectedParsedValue)
+        {
+            string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-9223372036854775809")]
+        [TestCase("9223372036854775808")]
+        public void StringToInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0UL)]
+        [TestCase("1", 1UL)]
+        [TestCase("18446744073709551615", 18446744073709551615)]
+        public void StringToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
+        {
+            string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("18446744073709551616")]
+        public void StringToUInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0d)]
+        [TestCase("1", 1d)]
+        [TestCase("1.000000", 1d)]
+        [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
+        [TestCase("-1", -1d)]
+        [TestCase("1e1", 10d)]
+        [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
+        [TestCase("1E1", 10d)] // Either case is fine
+        [TestCase("-1e1", -10d)]
+        [TestCase("1.5e1", 15d)]
+        [TestCase("-1.5e1", -15d)]
+        [TestCase("15e-1", 1.5d)]
+        [TestCase("-15e-1", -1.5d)]
+        [TestCase("1.79769e308", 1.79769e308)]
+        [TestCase("-1.79769e308", -1.79769e308)]
+        [TestCase("Infinity", double.PositiveInfinity)]
+        [TestCase("-Infinity", double.NegativeInfinity)]
+        [TestCase("NaN", double.NaN)]
+        public void StringToDouble_Valid(string jsonValue, double expectedParsedValue)
+        {
+            string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
+        }
+
+        [Test]
+        [TestCase("1.7977e308")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1e309")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("01")]
+        [TestCase("-00")]
+        [TestCase("-01")]
+        [TestCase("--1")]
+        [TestCase(" Infinity")]
+        [TestCase(" -Infinity")]
+        [TestCase("NaN ")]
+        [TestCase("Infinity ")]
+        [TestCase("-Infinity ")]
+        [TestCase(" NaN")]
+        [TestCase("INFINITY")]
+        [TestCase("nan")]
+        [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
+        public void StringToDouble_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0f)]
+        [TestCase("1", 1f)]
+        [TestCase("1.000000", 1f)]
+        [TestCase("-1", -1f)]
+        [TestCase("3.402823e38", 3.402823e38f)]
+        [TestCase("-3.402823e38", -3.402823e38f)]
+        [TestCase("1.5e1", 15f)]
+        [TestCase("15e-1", 1.5f)]
+        public void StringToFloat_Valid(string jsonValue, float expectedParsedValue)
+        {
+            string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
+        }
+
+        [Test]
+        [TestCase("3.402824e38")]
+        [TestCase("-3.402824e38")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("--1")]
+        public void StringToFloat_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        [TestCase("2147483647", 2147483647)]
+        [TestCase("-2147483648", -2147483648)]
+        [TestCase("1e1", 10)]
+        [TestCase("-1e1", -10)]
+        [TestCase("10.00", 10)]
+        [TestCase("-10.00", -10)]
+        public void NumberToInt32_Valid(string jsonValue, int expectedParsedValue)
+        {
+            string json = "{ \"singleInt32\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
+        }
+
+        [Test]
+        [TestCase("+0", typeof(InvalidJsonException))]
+        [TestCase("00", typeof(InvalidJsonException))]
+        [TestCase("-00", typeof(InvalidJsonException))]
+        [TestCase("--1", typeof(InvalidJsonException))]
+        [TestCase("+1", typeof(InvalidJsonException))]
+        [TestCase("1.5", typeof(InvalidProtocolBufferException))]
+        // Value is out of range
+        [TestCase("1e10", typeof(InvalidProtocolBufferException))]
+        [TestCase("2147483648", typeof(InvalidProtocolBufferException))]
+        [TestCase("-2147483649", typeof(InvalidProtocolBufferException))]
+        public void NumberToInt32_Invalid(string jsonValue, System.Type expectedExceptionType)
+        {
+            string json = "{ \"singleInt32\": " + jsonValue + "}";
+            Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0U)]
+        [TestCase("1", 1U)]
+        [TestCase("4294967295", 4294967295U)]
+        public void NumberToUInt32_Valid(string jsonValue, uint expectedParsedValue)
+        {
+            string json = "{ \"singleUint32\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("4294967296")]
+        public void NumberToUInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint32\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0L)]
+        [TestCase("1", 1L)]
+        [TestCase("-1", -1L)]
+        // long.MaxValue isn't actually representable as a double. This string value is the highest
+        // representable value which isn't greater than long.MaxValue.
+        [TestCase("9223372036854774784", 9223372036854774784)]
+        [TestCase("-9223372036854775808", -9223372036854775808)]
+        public void NumberToInt64_Valid(string jsonValue, long expectedParsedValue)
+        {
+            string json = "{ \"singleInt64\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("9223372036854775808")]
+        // Theoretical bound would be -9223372036854775809, but when that is parsed to a double
+        // we end up with the exact value of long.MinValue due to lack of precision. The value here
+        // is the "next double down".
+        [TestCase("-9223372036854780000")]
+        public void NumberToInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt64\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0UL)]
+        [TestCase("1", 1UL)]
+        // ulong.MaxValue isn't representable as a double. This value is the largest double within
+        // the range of ulong.
+        [TestCase("18446744073709549568", 18446744073709549568UL)]
+        public void NumberToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
+        {
+            string json = "{ \"singleUint64\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("18446744073709551616")]
+        public void NumberToUInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint64\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0d)]
+        [TestCase("1", 1d)]
+        [TestCase("1.000000", 1d)]
+        [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
+        [TestCase("-1", -1d)]
+        [TestCase("1e1", 10d)]
+        [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
+        [TestCase("1E1", 10d)] // Either case is fine
+        [TestCase("-1e1", -10d)]
+        [TestCase("1.5e1", 15d)]
+        [TestCase("-1.5e1", -15d)]
+        [TestCase("15e-1", 1.5d)]
+        [TestCase("-15e-1", -1.5d)]
+        [TestCase("1.79769e308", 1.79769e308)]
+        [TestCase("-1.79769e308", -1.79769e308)]
+        public void NumberToDouble_Valid(string jsonValue, double expectedParsedValue)
+        {
+            string json = "{ \"singleDouble\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
+        }
+
+        [Test]
+        [TestCase("1.7977e308")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1e309")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("--1")]
+        [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
+        public void NumberToDouble_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleDouble\": " + jsonValue + "}";
+            Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0f)]
+        [TestCase("1", 1f)]
+        [TestCase("1.000000", 1f)]
+        [TestCase("-1", -1f)]
+        [TestCase("3.402823e38", 3.402823e38f)]
+        [TestCase("-3.402823e38", -3.402823e38f)]
+        [TestCase("1.5e1", 15f)]
+        [TestCase("15e-1", 1.5f)]
+        public void NumberToFloat_Valid(string jsonValue, float expectedParsedValue)
+        {
+            string json = "{ \"singleFloat\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
+        }
+
+        [Test]
+        [TestCase("3.402824e38", typeof(InvalidProtocolBufferException))]
+        [TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))]
+        [TestCase("1,0", typeof(InvalidJsonException))]
+        [TestCase("1.0.0", typeof(InvalidJsonException))]
+        [TestCase("+1", typeof(InvalidJsonException))]
+        [TestCase("00", typeof(InvalidJsonException))]
+        [TestCase("--1", typeof(InvalidJsonException))]
+        public void NumberToFloat_Invalid(string jsonValue, System.Type expectedExceptionType)
+        {
+            string json = "{ \"singleFloat\": " + jsonValue + "}";
+            Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        // The simplest way of testing that the value has parsed correctly is to reformat it,
+        // as we trust the formatting. In many cases that will give the same result as the input,
+        // so in those cases we accept an expectedFormatted value of null. Sometimes the results
+        // will be different though, due to a different number of digits being provided.
+        [Test]
+        // Z offset
+        [TestCase("2015-10-09T14:46:23.123456789Z", null)]
+        [TestCase("2015-10-09T14:46:23.123456Z", null)]
+        [TestCase("2015-10-09T14:46:23.123Z", null)]
+        [TestCase("2015-10-09T14:46:23Z", null)]
+        [TestCase("2015-10-09T14:46:23.123456000Z", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.1234560Z", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123000000Z", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.1230Z", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.00Z", "2015-10-09T14:46:23Z")]
+
+        // +00:00 offset
+        [TestCase("2015-10-09T14:46:23.123456789+00:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T14:46:23.123456+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23+00:00", "2015-10-09T14:46:23Z")]
+        [TestCase("2015-10-09T14:46:23.123456000+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.1234560+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123000000+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.1230+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.00+00:00", "2015-10-09T14:46:23Z")]
+
+        // Other offsets (assume by now that the subsecond handling is okay)
+        [TestCase("2015-10-09T15:46:23.123456789+01:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T13:46:23.123456789-01:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T15:16:23.123456789+00:30", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T14:16:23.123456789-00:30", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T16:31:23.123456789+01:45", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T13:01:23.123456789-01:45", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-10T08:46:23.123456789+18:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-08T20:46:23.123456789-18:00", "2015-10-09T14:46:23.123456789Z")]
+
+        // Leap years and min/max
+        [TestCase("2016-02-29T14:46:23.123456789Z", null)]
+        [TestCase("2000-02-29T14:46:23.123456789Z", null)]
+        [TestCase("0001-01-01T00:00:00Z", null)]
+        [TestCase("9999-12-31T23:59:59.999999999Z", null)]
+        public void Timestamp_Valid(string jsonValue, string expectedFormatted)
+        {
+            expectedFormatted = expectedFormatted ?? jsonValue;
+            string json = WrapInQuotes(jsonValue);
+            var parsed = Timestamp.Parser.ParseJson(json);
+            Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
+        }
+
+        [Test]
+        [TestCase("2015-10-09 14:46:23.123456789Z", Description = "No T between date and time")]
+        [TestCase("2015/10/09T14:46:23.123456789Z", Description = "Wrong date separators")]
+        [TestCase("2015-10-09T14.46.23.123456789Z", Description = "Wrong time separators")]
+        [TestCase("2015-10-09T14:46:23,123456789Z", Description = "Wrong fractional second separators (valid ISO-8601 though)")]
+        [TestCase(" 2015-10-09T14:46:23.123456789Z", Description = "Whitespace at start")]
+        [TestCase("2015-10-09T14:46:23.123456789Z ", Description = "Whitespace at end")]
+        [TestCase("2015-10-09T14:46:23.1234567890", Description = "Too many digits")]
+        [TestCase("2015-10-09T14:46:23.123456789", Description = "No offset")]
+        [TestCase("2015-13-09T14:46:23.123456789Z", Description = "Invalid month")]
+        [TestCase("2015-10-32T14:46:23.123456789Z", Description = "Invalid day")]
+        [TestCase("2015-10-09T24:00:00.000000000Z", Description = "Invalid hour (valid ISO-8601 though)")]
+        [TestCase("2015-10-09T14:60:23.123456789Z", Description = "Invalid minutes")]
+        [TestCase("2015-10-09T14:46:60.123456789Z", Description = "Invalid seconds")]
+        [TestCase("2015-10-09T14:46:23.123456789+18:01", Description = "Offset too large (positive)")]
+        [TestCase("2015-10-09T14:46:23.123456789-18:01", Description = "Offset too large (negative)")]
+        [TestCase("2015-10-09T14:46:23.123456789-00:00", Description = "Local offset (-00:00) makes no sense here")]
+        [TestCase("0001-01-01T00:00:00+00:01", Description = "Value before earliest when offset applied")]
+        [TestCase("9999-12-31T23:59:59.999999999-00:01", Description = "Value after latest when offset applied")]
+        [TestCase("2100-02-29T14:46:23.123456789Z", Description = "Feb 29th on a non-leap-year")]
+        public void Timestamp_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => Timestamp.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void StructValue_Null()
+        {
+            Assert.AreEqual(new Value { NullValue = 0 }, Value.Parser.ParseJson("null"));
+        }
+
+        [Test]
+        public void StructValue_String()
+        {
+            Assert.AreEqual(new Value { StringValue = "hi" }, Value.Parser.ParseJson("\"hi\""));
+        }
+
+        [Test]
+        public void StructValue_Bool()
+        {
+            Assert.AreEqual(new Value { BoolValue = true }, Value.Parser.ParseJson("true"));
+            Assert.AreEqual(new Value { BoolValue = false }, Value.Parser.ParseJson("false"));
+        }
+
+        [Test]
+        public void StructValue_List()
+        {
+            Assert.AreEqual(Value.ForList(Value.ForNumber(1), Value.ForString("x")), Value.Parser.ParseJson("[1, \"x\"]"));
+        }
+
+        [Test]
+        public void ParseListValue()
+        {
+            Assert.AreEqual(new ListValue { Values = { Value.ForNumber(1), Value.ForString("x") } }, ListValue.Parser.ParseJson("[1, \"x\"]"));
+        }
+
+        [Test]
+        public void StructValue_Struct()
+        {
+            Assert.AreEqual(
+                Value.ForStruct(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } }),
+                Value.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
+        }
+
+        [Test]
+        public void ParseStruct()
+        {
+            Assert.AreEqual(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } },
+                Struct.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
+        }
+
+        // TODO for duration parsing: upper and lower bounds.
+        // +/- 315576000000 seconds
+
+        [Test]
+        [TestCase("1.123456789s", null)]
+        [TestCase("1.123456s", null)]
+        [TestCase("1.123s", null)]
+        [TestCase("1.12300s", "1.123s")]
+        [TestCase("1.12345s", "1.123450s")]
+        [TestCase("1s", null)]
+        [TestCase("-1.123456789s", null)]
+        [TestCase("-1.123456s", null)]
+        [TestCase("-1.123s", null)]
+        [TestCase("-1s", null)]
+        [TestCase("0.123s", null)]
+        [TestCase("-0.123s", null)]
+        [TestCase("123456.123s", null)]
+        [TestCase("-123456.123s", null)]
+        // Upper and lower bounds
+        [TestCase("315576000000s", null)]
+        [TestCase("-315576000000s", null)]
+        public void Duration_Valid(string jsonValue, string expectedFormatted)
+        {
+            expectedFormatted = expectedFormatted ?? jsonValue;
+            string json = WrapInQuotes(jsonValue);
+            var parsed = Duration.Parser.ParseJson(json);
+            Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
+        }
+
+        // The simplest way of testing that the value has parsed correctly is to reformat it,
+        // as we trust the formatting. In many cases that will give the same result as the input,
+        // so in those cases we accept an expectedFormatted value of null. Sometimes the results
+        // will be different though, due to a different number of digits being provided.
+        [Test]
+        [TestCase("1.1234567890s", Description = "Too many digits")]
+        [TestCase("1.123456789", Description = "No suffix")]
+        [TestCase("1.123456789ss", Description = "Too much suffix")]
+        [TestCase("1.123456789S", Description = "Upper case suffix")]
+        [TestCase("+1.123456789s", Description = "Leading +")]
+        [TestCase(".123456789s", Description = "No integer before the fraction")]
+        [TestCase("1,123456789s", Description = "Comma as decimal separator")]
+        [TestCase("1x1.123456789s", Description = "Non-digit in integer part")]
+        [TestCase("1.1x3456789s", Description = "Non-digit in fractional part")]
+        [TestCase(" 1.123456789s", Description = "Whitespace before fraction")]
+        [TestCase("1.123456789s ", Description = "Whitespace after value")]
+        [TestCase("01.123456789s", Description = "Leading zero (positive)")]
+        [TestCase("-01.123456789s", Description = "Leading zero (negative)")]
+        [TestCase("--0.123456789s", Description = "Double minus sign")]
+        // Violate upper/lower bounds in various ways
+        [TestCase("315576000001s", Description = "Integer part too large")]
+        [TestCase("3155760000000s", Description = "Integer part too long (positive)")]
+        [TestCase("-3155760000000s", Description = "Integer part too long (negative)")]
+        public void Duration_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => Duration.Parser.ParseJson(json));
+        }
+
+        // Not as many tests for field masks as I'd like; more to be added when we have more
+        // detailed specifications.
+
+        [Test]
+        [TestCase("")]
+        [TestCase("foo", "foo")]
+        [TestCase("foo,bar", "foo", "bar")]
+        [TestCase("foo.bar", "foo.bar")]
+        [TestCase("fooBar", "foo_bar")]
+        [TestCase("fooBar.bazQux", "foo_bar.baz_qux")]
+        public void FieldMask_Valid(string jsonValue, params string[] expectedPaths)
+        {
+            string json = WrapInQuotes(jsonValue);
+            var parsed = FieldMask.Parser.ParseJson(json);
+            CollectionAssert.AreEqual(expectedPaths, parsed.Paths);
+        }
+
+        [Test]
+        [TestCase("foo_bar")]
+        public void FieldMask_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => FieldMask.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_RegularMessage()
+        {
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
+            var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } };
+            var original = Any.Pack(message);
+            var json = formatter.Format(original); // This is tested in JsonFormatterTest
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            Assert.AreEqual(original, parser.Parse<Any>(json));
+            string valueFirstJson = "{ \"singleInt32\": 10, \"singleNestedMessage\": { \"bb\": 20 }, \"@type\": \"type.googleapis.com/protobuf_unittest.TestAllTypes\" }";
+            Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
+        }
+
+        [Test]
+        public void Any_CustomPrefix()
+        {
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+            var message = new TestAllTypes { SingleInt32 = 10 };
+            var original = Any.Pack(message, "custom.prefix/middle-part");
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            string json = "{ \"@type\": \"custom.prefix/middle-part/protobuf_unittest.TestAllTypes\", \"singleInt32\": 10 }";
+            Assert.AreEqual(original, parser.Parse<Any>(json));
+        }
+
+        [Test]
+        public void Any_UnknownType()
+        {
+            string json = "{ \"@type\": \"type.googleapis.com/bogus\" }";
+            Assert.Throws<InvalidOperationException>(() => Any.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_NoTypeUrl()
+        {
+            string json = "{ \"foo\": \"bar\" }";
+            Assert.Throws<InvalidProtocolBufferException>(() => Any.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_WellKnownType()
+        {
+            var registry = TypeRegistry.FromMessages(Timestamp.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+            var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp();
+            var original = Any.Pack(timestamp);
+            var json = formatter.Format(original); // This is tested in JsonFormatterTest
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            Assert.AreEqual(original, parser.Parse<Any>(json));
+            string valueFirstJson = "{ \"value\": \"1673-06-19T12:34:56Z\", \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\" }";
+            Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
+        }
+
+        [Test]
+        public void Any_Nested()
+        {
+            var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 };
+            var nestedMessage = Any.Pack(doubleNestedMessage);
+            var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
+            var json = formatter.Format(message);
+            // Use the descriptor-based parser just for a change.
+            Assert.AreEqual(message, parser.Parse(json, TestWellKnownTypes.Descriptor));
+        }
+
+        [Test]
+        public void DataAfterObject()
+        {
+            string json = "{} 10";
+            Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        /// <summary>
+        /// JSON equivalent to <see cref="CodedInputStreamTest.MaliciousRecursion"/>
+        /// </summary>
+        [Test]
+        public void MaliciousRecursion()
+        {
+            string data64 = CodedInputStreamTest.MakeRecursiveMessage(64).ToString();
+            string data65 = CodedInputStreamTest.MakeRecursiveMessage(65).ToString();
+
+            var parser64 = new JsonParser(new JsonParser.Settings(64));
+            CodedInputStreamTest.AssertMessageDepth(parser64.Parse<TestRecursiveMessage>(data64), 64);
+            Assert.Throws<InvalidProtocolBufferException>(() => parser64.Parse<TestRecursiveMessage>(data65));
+
+            var parser63 = new JsonParser(new JsonParser.Settings(63));
+            Assert.Throws<InvalidProtocolBufferException>(() => parser63.Parse<TestRecursiveMessage>(data64));
+        }
+
+        [Test]
+        [TestCase("AQI")]
+        [TestCase("_-==")]
+        public void Bytes_InvalidBase64(string badBase64)
+        {
+            string json = "{ \"singleBytes\": \"" + badBase64 + "\" }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("\"FOREIGN_BAR\"", ForeignEnum.ForeignBar)]
+        [TestCase("5", ForeignEnum.ForeignBar)]
+        [TestCase("100", (ForeignEnum)100)]
+        public void EnumValid(string value, ForeignEnum expectedValue)
+        {
+            string json = "{ \"singleForeignEnum\": " + value + " }";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(new TestAllTypes { SingleForeignEnum = expectedValue }, parsed);
+        }
+
+        [Test]
+        [TestCase("\"NOT_A_VALID_VALUE\"")]
+        [TestCase("5.5")]
+        public void Enum_Invalid(string value)
+        {
+            string json = "{ \"singleForeignEnum\": " + value + " }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void OneofDuplicate_Invalid()
+        {
+            string json = "{ \"oneofString\": \"x\", \"oneofUint32\": 10 }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        /// <summary>
+        /// Various tests use strings which have quotes round them for parsing or as the result
+        /// of formatting, but without those quotes being specified in the tests (for the sake of readability).
+        /// This method simply returns the input, wrapped in double quotes.
+        /// </summary>
+        internal static string WrapInQuotes(string text)
+        {
+            return '"' + text + '"';
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
new file mode 100644
index 0000000..527ab33
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -0,0 +1,408 @@
+#region Copyright notice and license
+// 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.
+#endregion
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    public class JsonTokenizerTest
+    {
+        [Test]
+        public void EmptyObjectValue()
+        {
+            AssertTokens("{}", JsonToken.StartObject, JsonToken.EndObject);
+        }
+
+        [Test]
+        public void EmptyArrayValue()
+        {
+            AssertTokens("[]", JsonToken.StartArray, JsonToken.EndArray);
+        }
+
+        [Test]
+        [TestCase("foo", "foo")]
+        [TestCase("tab\\t", "tab\t")]
+        [TestCase("line\\nfeed", "line\nfeed")]
+        [TestCase("carriage\\rreturn", "carriage\rreturn")]
+        [TestCase("back\\bspace", "back\bspace")]
+        [TestCase("form\\ffeed", "form\ffeed")]
+        [TestCase("escaped\\/slash", "escaped/slash")]
+        [TestCase("escaped\\\\backslash", "escaped\\backslash")]
+        [TestCase("escaped\\\"quote", "escaped\"quote")]
+        [TestCase("foo {}[] bar", "foo {}[] bar")]
+        [TestCase("foo\\u09aFbar", "foo\u09afbar")] // Digits, upper hex, lower hex
+        [TestCase("ab\ud800\udc00cd", "ab\ud800\udc00cd")]
+        [TestCase("ab\\ud800\\udc00cd", "ab\ud800\udc00cd")]
+        public void StringValue(string json, string expectedValue)
+        {
+            AssertTokensNoReplacement("\"" + json + "\"", JsonToken.Value(expectedValue));
+        }
+
+        // Valid surrogate pairs, with mixed escaping. These test cases can't be expressed
+        // using TestCase as they have no valid UTF-8 representation.
+        // It's unclear exactly how we should handle a mixture of escaped or not: that can't
+        // come from UTF-8 text, but could come from a .NET string. For the moment,
+        // treat it as valid in the obvious way.
+        [Test]
+        public void MixedSurrogatePairs()
+        {
+            string expected = "\ud800\udc00";
+            AssertTokens("'\\ud800\udc00'", JsonToken.Value(expected));
+            AssertTokens("'\ud800\\udc00'", JsonToken.Value(expected));
+        }
+
+        [Test]
+        public void ObjectDepth()
+        {
+            string json = "{ \"foo\": { \"x\": 1, \"y\": [ 0 ] } }";
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader(json));
+            // If we had more tests like this, I'd introduce a helper method... but for one test, it's not worth it.
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartObject, tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("foo"), tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartObject, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("x"), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Value(1), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("y"), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartArray, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth); // Depth hasn't changed in array
+            Assert.AreEqual(JsonToken.Value(0), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndArray, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndObject, tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndObject, tokenizer.Next());
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+        }
+
+        [Test]
+        public void ObjectDepth_WithPushBack()
+        {
+            string json = "{}";
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader(json));
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            var token = tokenizer.Next();
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            // When we push back a "start object", we should effectively be back to the previous depth.
+            tokenizer.PushBack(token);
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            // Read the same token again, and get back to depth 1
+            token = tokenizer.Next();
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+
+            // Now the same in reverse, with EndObject
+            token = tokenizer.Next();
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            tokenizer.PushBack(token);
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            tokenizer.Next();
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+        }
+
+        [Test]
+        [TestCase("embedded tab\t")]
+        [TestCase("embedded CR\r")]
+        [TestCase("embedded LF\n")]
+        [TestCase("embedded bell\u0007")]
+        [TestCase("bad escape\\a")]
+        [TestCase("incomplete escape\\")]
+        [TestCase("incomplete Unicode escape\\u000")]
+        [TestCase("invalid Unicode escape\\u000H")]
+        // Surrogate pair handling, both in raw .NET strings and escaped. We only need
+        // to detect this in strings, as non-ASCII characters anywhere other than in strings
+        // will already lead to parsing errors.
+        [TestCase("\\ud800")]
+        [TestCase("\\udc00")]
+        [TestCase("\\ud800x")]
+        [TestCase("\\udc00x")]
+        [TestCase("\\udc00\\ud800y")]
+        public void InvalidStringValue(string json)
+        {
+            AssertThrowsAfter("\"" + json + "\"");
+        }
+
+        // Tests for invalid strings that can't be expressed in attributes,
+        // as the constants can't be expressed as UTF-8 strings.
+        [Test]
+        public void InvalidSurrogatePairs()
+        {
+            AssertThrowsAfter("\"\ud800x\"");
+            AssertThrowsAfter("\"\udc00y\"");
+            AssertThrowsAfter("\"\udc00\ud800y\"");
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // We don't distinguish between positive and negative 0
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        // From here on, assume leading sign is okay...
+        [TestCase("1.125", 1.125)]
+        [TestCase("1.0", 1)]
+        [TestCase("1e5", 100000)]
+        [TestCase("1e000000", 1)] // Weird, but not prohibited by the spec
+        [TestCase("1E5", 100000)]
+        [TestCase("1e+5", 100000)]
+        [TestCase("1E-5", 0.00001)]
+        [TestCase("123E-2", 1.23)]
+        [TestCase("123.45E3", 123450)]
+        [TestCase("   1   ", 1)]
+        public void NumberValue(string json, double expectedValue)
+        {
+            AssertTokens(json, JsonToken.Value(expectedValue));
+        }
+
+        [Test]
+        [TestCase("00")]
+        [TestCase(".5")]
+        [TestCase("1.")]
+        [TestCase("1e")]
+        [TestCase("1e-")]
+        [TestCase("--")]
+        [TestCase("--1")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1.7977e308")]
+        public void InvalidNumberValue(string json)
+        {
+            AssertThrowsAfter(json);
+        }
+
+        [Test]
+        [TestCase("nul")]
+        [TestCase("nothing")]
+        [TestCase("truth")]
+        [TestCase("fALSEhood")]
+        public void InvalidLiterals(string json)
+        {
+            AssertThrowsAfter(json);
+        }
+
+        [Test]
+        public void NullValue()
+        {
+            AssertTokens("null", JsonToken.Null);
+        }
+
+        [Test]
+        public void TrueValue()
+        {
+            AssertTokens("true", JsonToken.True);
+        }
+
+        [Test]
+        public void FalseValue()
+        {
+            AssertTokens("false", JsonToken.False);
+        }
+
+        [Test]
+        public void SimpleObject()
+        {
+            AssertTokens("{'x': 'y'}",
+                JsonToken.StartObject, JsonToken.Name("x"), JsonToken.Value("y"), JsonToken.EndObject);
+        }
+        
+        [Test]
+        [TestCase("[10, 20", 3)]
+        [TestCase("[10,", 2)]
+        [TestCase("[10:20]", 2)]
+        [TestCase("[", 1)]
+        [TestCase("[,", 1)]
+        [TestCase("{", 1)]
+        [TestCase("{,", 1)]
+        [TestCase("{[", 1)]
+        [TestCase("{{", 1)]
+        [TestCase("{0", 1)]
+        [TestCase("{null", 1)]
+        [TestCase("{false", 1)]
+        [TestCase("{true", 1)]
+        [TestCase("}", 0)]
+        [TestCase("]", 0)]
+        [TestCase(",", 0)]
+        [TestCase("'foo' 'bar'", 1)]
+        [TestCase(":", 0)]
+        [TestCase("'foo", 0)] // Incomplete string
+        [TestCase("{ 'foo' }", 2)]
+        [TestCase("{ x:1", 1)] // Property names must be quoted
+        [TestCase("{]", 1)]
+        [TestCase("[}", 1)]
+        [TestCase("[1,", 2)]
+        [TestCase("{'x':0]", 3)]
+        [TestCase("{ 'foo': }", 2)]
+        [TestCase("{ 'foo':'bar', }", 3)]
+        public void InvalidStructure(string json, int expectedValidTokens)
+        {
+            // Note: we don't test that the earlier tokens are exactly as expected,
+            // partly because that's hard to parameterize.
+            var reader = new StringReader(json.Replace('\'', '"'));
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedValidTokens; i++)
+            {
+                Assert.IsNotNull(tokenizer.Next());
+            }
+            Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
+        }
+
+        [Test]
+        public void ArrayMixedType()
+        {
+            AssertTokens("[1, 'foo', null, false, true, [2], {'x':'y' }]",
+                JsonToken.StartArray,
+                JsonToken.Value(1),
+                JsonToken.Value("foo"),
+                JsonToken.Null,
+                JsonToken.False,
+                JsonToken.True,
+                JsonToken.StartArray,
+                JsonToken.Value(2),
+                JsonToken.EndArray,
+                JsonToken.StartObject,
+                JsonToken.Name("x"),
+                JsonToken.Value("y"),
+                JsonToken.EndObject,
+                JsonToken.EndArray);
+        }
+
+        [Test]
+        public void ObjectMixedType()
+        {
+            AssertTokens(@"{'a': 1, 'b': 'bar', 'c': null, 'd': false, 'e': true, 
+                           'f': [2], 'g': {'x':'y' }}",
+                JsonToken.StartObject,
+                JsonToken.Name("a"),
+                JsonToken.Value(1),
+                JsonToken.Name("b"),
+                JsonToken.Value("bar"),
+                JsonToken.Name("c"),
+                JsonToken.Null,
+                JsonToken.Name("d"),
+                JsonToken.False,
+                JsonToken.Name("e"),
+                JsonToken.True,
+                JsonToken.Name("f"),
+                JsonToken.StartArray,
+                JsonToken.Value(2),
+                JsonToken.EndArray,
+                JsonToken.Name("g"),
+                JsonToken.StartObject,
+                JsonToken.Name("x"),
+                JsonToken.Value("y"),
+                JsonToken.EndObject,
+                JsonToken.EndObject);
+        }
+
+        [Test]
+        public void NextAfterEndDocumentThrows()
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader("null"));
+            Assert.AreEqual(JsonToken.Null, tokenizer.Next());
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.Throws<InvalidOperationException>(() => tokenizer.Next());
+        }
+
+        [Test]
+        public void CanPushBackEndDocument()
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader("null"));
+            Assert.AreEqual(JsonToken.Null, tokenizer.Next());
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            tokenizer.PushBack(JsonToken.EndDocument);
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.Throws<InvalidOperationException>(() => tokenizer.Next());
+        }
+       
+        /// <summary>
+        /// Asserts that the specified JSON is tokenized into the given sequence of tokens.
+        /// All apostrophes are first converted to double quotes, allowing any tests
+        /// that don't need to check actual apostrophe handling to use apostrophes in the JSON, avoiding
+        /// messy string literal escaping. The "end document" token is not specified in the list of 
+        /// expected tokens, but is implicit.
+        /// </summary>
+        private static void AssertTokens(string json, params JsonToken[] expectedTokens)
+        {
+            AssertTokensNoReplacement(json.Replace('\'', '"'), expectedTokens);
+        }
+
+        /// <summary>
+        /// Asserts that the specified JSON is tokenized into the given sequence of tokens.
+        /// Unlike <see cref="AssertTokens(string, JsonToken[])"/>, this does not perform any character
+        /// replacement on the specified JSON, and should be used when the text contains apostrophes which
+        /// are expected to be used *as* apostrophes. The "end document" token is not specified in the list of 
+        /// expected tokens, but is implicit.
+        /// </summary>
+        private static void AssertTokensNoReplacement(string json, params JsonToken[] expectedTokens)
+        {
+            var reader = new StringReader(json);
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedTokens.Length; i++)
+            {
+                var actualToken = tokenizer.Next();
+                if (actualToken == JsonToken.EndDocument)
+                {
+                    Assert.Fail("Expected {0} but reached end of token stream", expectedTokens[i]);
+                }
+                Assert.AreEqual(expectedTokens[i], actualToken);
+            }
+            var finalToken = tokenizer.Next();
+            if (finalToken != JsonToken.EndDocument)
+            {
+                Assert.Fail("Expected token stream to be exhausted; received {0}", finalToken);
+            }
+        }
+
+        private static void AssertThrowsAfter(string json, params JsonToken[] expectedTokens)
+        {
+            var reader = new StringReader(json);
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedTokens.Length; i++)
+            {
+                var actualToken = tokenizer.Next();
+                if (actualToken == JsonToken.EndDocument)
+                {
+                    Assert.Fail("Expected {0} but reached end of document", expectedTokens[i]);
+                }
+                Assert.AreEqual(expectedTokens[i], actualToken);
+            }
+            Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml b/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml
new file mode 100644
index 0000000..a955232
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"

+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

+>

+    <Deployment.Parts>

+    </Deployment.Parts>

+</Deployment>

diff --git a/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d00acf8
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System;

+using System.Reflection;

+using System.Runtime.CompilerServices;

+using System.Runtime.InteropServices;

+

+// General Information about an assembly is controlled through the following 

+// set of attributes. Change these attribute values to modify the information

+// associated with an assembly.

+

+[assembly: AssemblyTitle("Google.Protobuf.Test")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("Google.Protobuf.Test")]

+[assembly: AssemblyCopyright("Copyright ©  2015")]

+[assembly: AssemblyTrademark("")]

+[assembly: AssemblyCulture("")]

+

+[assembly: AssemblyVersion("3.0.0.0")]

+[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
new file mode 100644
index 0000000..52d5a67
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
@@ -0,0 +1,259 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System.Linq;
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+using UnitTest.Issues.TestProtos;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Tests for descriptors. (Not in its own namespace or broken up into individual classes as the
+    /// size doesn't warrant it. On the other hand, this makes me feel a bit dirty...)
+    /// </summary>
+    public class DescriptorsTest
+    {
+        [Test]
+        public void FileDescriptor()
+        {
+            FileDescriptor file = UnittestProto3Reflection.Descriptor;
+
+            Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Name);
+            Assert.AreEqual("protobuf_unittest", file.Package);
+
+            Assert.AreEqual("UnittestProto", file.Proto.Options.JavaOuterClassname);
+            Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Proto.Name);
+
+            // unittest.proto doesn't have any public imports, but unittest_import.proto does.
+            Assert.AreEqual(0, file.PublicDependencies.Count);
+            Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.PublicDependencies.Count);
+            Assert.AreEqual(UnittestImportPublicProto3Reflection.Descriptor, UnittestImportProto3Reflection.Descriptor.PublicDependencies[0]);
+
+            Assert.AreEqual(1, file.Dependencies.Count);
+            Assert.AreEqual(UnittestImportProto3Reflection.Descriptor, file.Dependencies[0]);
+
+            MessageDescriptor messageType = TestAllTypes.Descriptor;
+            Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
+            Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
+            Assert.AreEqual(messageType, file.MessageTypes[0]);
+            Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
+            Assert.Null(file.FindTypeByName<MessageDescriptor>("NoSuchType"));
+            Assert.Null(file.FindTypeByName<MessageDescriptor>("protobuf_unittest.TestAllTypes"));
+            for (int i = 0; i < file.MessageTypes.Count; i++)
+            {
+                Assert.AreEqual(i, file.MessageTypes[i].Index);
+            }
+
+            Assert.AreEqual(file.EnumTypes[0], file.FindTypeByName<EnumDescriptor>("ForeignEnum"));
+            Assert.Null(file.FindTypeByName<EnumDescriptor>("NoSuchType"));
+            Assert.Null(file.FindTypeByName<EnumDescriptor>("protobuf_unittest.ForeignEnum"));
+            Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.EnumTypes.Count);
+            Assert.AreEqual("ImportEnum", UnittestImportProto3Reflection.Descriptor.EnumTypes[0].Name);
+            for (int i = 0; i < file.EnumTypes.Count; i++)
+            {
+                Assert.AreEqual(i, file.EnumTypes[i].Index);
+            }
+
+            Assert.AreEqual(10, file.SerializedData[0]);
+        }
+
+        [Test]
+        public void MessageDescriptor()
+        {
+            MessageDescriptor messageType = TestAllTypes.Descriptor;
+            MessageDescriptor nestedType = TestAllTypes.Types.NestedMessage.Descriptor;
+
+            Assert.AreEqual("TestAllTypes", messageType.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes", messageType.FullName);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, messageType.File);
+            Assert.IsNull(messageType.ContainingType);
+            Assert.IsNull(messageType.Proto.Options);
+
+            Assert.AreEqual("TestAllTypes", messageType.Name);
+
+            Assert.AreEqual("NestedMessage", nestedType.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.FullName);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
+            Assert.AreEqual(messageType, nestedType.ContainingType);
+
+            FieldDescriptor field = messageType.Fields.InDeclarationOrder()[0];
+            Assert.AreEqual("single_int32", field.Name);
+            Assert.AreEqual(field, messageType.FindDescriptor<FieldDescriptor>("single_int32"));
+            Assert.Null(messageType.FindDescriptor<FieldDescriptor>("no_such_field"));
+            Assert.AreEqual(field, messageType.FindFieldByNumber(1));
+            Assert.Null(messageType.FindFieldByNumber(571283));
+            var fieldsInDeclarationOrder = messageType.Fields.InDeclarationOrder();
+            for (int i = 0; i < fieldsInDeclarationOrder.Count; i++)
+            {
+                Assert.AreEqual(i, fieldsInDeclarationOrder[i].Index);
+            }
+
+            Assert.AreEqual(nestedType, messageType.NestedTypes[0]);
+            Assert.AreEqual(nestedType, messageType.FindDescriptor<MessageDescriptor>("NestedMessage"));
+            Assert.Null(messageType.FindDescriptor<MessageDescriptor>("NoSuchType"));
+            for (int i = 0; i < messageType.NestedTypes.Count; i++)
+            {
+                Assert.AreEqual(i, messageType.NestedTypes[i].Index);
+            }
+
+            Assert.AreEqual(messageType.EnumTypes[0], messageType.FindDescriptor<EnumDescriptor>("NestedEnum"));
+            Assert.Null(messageType.FindDescriptor<EnumDescriptor>("NoSuchType"));
+            for (int i = 0; i < messageType.EnumTypes.Count; i++)
+            {
+                Assert.AreEqual(i, messageType.EnumTypes[i].Index);
+            }
+        }
+
+        [Test]
+        public void FieldDescriptor()
+        {
+            MessageDescriptor messageType = TestAllTypes.Descriptor;
+            FieldDescriptor primitiveField = messageType.FindDescriptor<FieldDescriptor>("single_int32");
+            FieldDescriptor enumField = messageType.FindDescriptor<FieldDescriptor>("single_nested_enum");
+            FieldDescriptor messageField = messageType.FindDescriptor<FieldDescriptor>("single_foreign_message");
+
+            Assert.AreEqual("single_int32", primitiveField.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes.single_int32",
+                            primitiveField.FullName);
+            Assert.AreEqual(1, primitiveField.FieldNumber);
+            Assert.AreEqual(messageType, primitiveField.ContainingType);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, primitiveField.File);
+            Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
+            Assert.IsNull(primitiveField.Proto.Options);
+            
+            Assert.AreEqual("single_nested_enum", enumField.Name);
+            Assert.AreEqual(FieldType.Enum, enumField.FieldType);
+            // Assert.AreEqual(TestAllTypes.Types.NestedEnum.DescriptorProtoFile, enumField.EnumType);
+
+            Assert.AreEqual("single_foreign_message", messageField.Name);
+            Assert.AreEqual(FieldType.Message, messageField.FieldType);
+            Assert.AreEqual(ForeignMessage.Descriptor, messageField.MessageType);
+        }
+
+        [Test]
+        public void FieldDescriptorLabel()
+        {
+            FieldDescriptor singleField =
+                TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("single_int32");
+            FieldDescriptor repeatedField =
+                TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("repeated_int32");
+
+            Assert.IsFalse(singleField.IsRepeated);
+            Assert.IsTrue(repeatedField.IsRepeated);
+        }
+
+        [Test]
+        public void EnumDescriptor()
+        {
+            // Note: this test is a bit different to the Java version because there's no static way of getting to the descriptor
+            EnumDescriptor enumType = UnittestProto3Reflection.Descriptor.FindTypeByName<EnumDescriptor>("ForeignEnum");
+            EnumDescriptor nestedType = TestAllTypes.Descriptor.FindDescriptor<EnumDescriptor>("NestedEnum");
+
+            Assert.AreEqual("ForeignEnum", enumType.Name);
+            Assert.AreEqual("protobuf_unittest.ForeignEnum", enumType.FullName);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, enumType.File);
+            Assert.Null(enumType.ContainingType);
+            Assert.Null(enumType.Proto.Options);
+
+            Assert.AreEqual("NestedEnum", nestedType.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedEnum",
+                            nestedType.FullName);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
+            Assert.AreEqual(TestAllTypes.Descriptor, nestedType.ContainingType);
+
+            EnumValueDescriptor value = enumType.FindValueByName("FOREIGN_FOO");
+            Assert.AreEqual(value, enumType.Values[1]);
+            Assert.AreEqual("FOREIGN_FOO", value.Name);
+            Assert.AreEqual(4, value.Number);
+            Assert.AreEqual((int) ForeignEnum.ForeignFoo, value.Number);
+            Assert.AreEqual(value, enumType.FindValueByNumber(4));
+            Assert.Null(enumType.FindValueByName("NO_SUCH_VALUE"));
+            for (int i = 0; i < enumType.Values.Count; i++)
+            {
+                Assert.AreEqual(i, enumType.Values[i].Index);
+            }
+        }
+
+        [Test]
+        public void OneofDescriptor()
+        {
+            OneofDescriptor descriptor = TestAllTypes.Descriptor.FindDescriptor<OneofDescriptor>("oneof_field");
+            Assert.AreEqual("oneof_field", descriptor.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes.oneof_field", descriptor.FullName);
+
+            var expectedFields = new[] {
+                TestAllTypes.OneofBytesFieldNumber,
+                TestAllTypes.OneofNestedMessageFieldNumber,
+                TestAllTypes.OneofStringFieldNumber,
+                TestAllTypes.OneofUint32FieldNumber }
+                .Select(fieldNumber => TestAllTypes.Descriptor.FindFieldByNumber(fieldNumber))
+                .ToList();
+            foreach (var field in expectedFields)
+            {
+                Assert.AreSame(descriptor, field.ContainingOneof);
+            }
+
+            CollectionAssert.AreEquivalent(expectedFields, descriptor.Fields);
+        }
+
+        [Test]
+        public void MapEntryMessageDescriptor()
+        {
+            var descriptor = MapWellKnownTypes.Descriptor.NestedTypes[0];
+            Assert.IsNull(descriptor.Parser);
+            Assert.IsNull(descriptor.ClrType);
+            Assert.IsNull(descriptor.Fields[1].Accessor);
+        }
+
+        // From TestFieldOrdering:
+        // string my_string = 11;
+        // int64 my_int = 1;
+        // float my_float = 101;
+        // NestedMessage single_nested_message = 200;
+        [Test]
+        public void FieldListOrderings()
+        { 
+            var fields = TestFieldOrderings.Descriptor.Fields;
+            Assert.AreEqual(new[] { 11, 1, 101, 200 }, fields.InDeclarationOrder().Select(x => x.FieldNumber));
+            Assert.AreEqual(new[] { 1, 11, 101, 200 }, fields.InFieldNumberOrder().Select(x => x.FieldNumber));
+        }
+
+
+        [Test]
+        public void DescriptorProtoFileDescriptor()
+        {
+            var descriptor = Google.Protobuf.Reflection.FileDescriptor.DescriptorProtoFileDescriptor;
+            Assert.AreEqual("google/protobuf/descriptor.proto", descriptor.Name);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
new file mode 100644
index 0000000..a488af3
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
@@ -0,0 +1,218 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Google.Protobuf.Reflection
+{
+    public class FieldAccessTest
+    {
+        [Test]
+        public void GetValue()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var fields = TestAllTypes.Descriptor.Fields;
+            Assert.AreEqual(message.SingleBool, fields[TestAllTypes.SingleBoolFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleBytes, fields[TestAllTypes.SingleBytesFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleDouble, fields[TestAllTypes.SingleDoubleFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleFixed32, fields[TestAllTypes.SingleFixed32FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleFixed64, fields[TestAllTypes.SingleFixed64FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleFloat, fields[TestAllTypes.SingleFloatFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleForeignEnum, fields[TestAllTypes.SingleForeignEnumFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleForeignMessage, fields[TestAllTypes.SingleForeignMessageFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleImportEnum, fields[TestAllTypes.SingleImportEnumFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleImportMessage, fields[TestAllTypes.SingleImportMessageFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleInt32, fields[TestAllTypes.SingleInt32FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleInt64, fields[TestAllTypes.SingleInt64FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleNestedEnum, fields[TestAllTypes.SingleNestedEnumFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleNestedMessage, fields[TestAllTypes.SingleNestedMessageFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SinglePublicImportMessage, fields[TestAllTypes.SinglePublicImportMessageFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleSint32, fields[TestAllTypes.SingleSint32FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleSint64, fields[TestAllTypes.SingleSint64FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleString, fields[TestAllTypes.SingleStringFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleSfixed32, fields[TestAllTypes.SingleSfixed32FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleSfixed64, fields[TestAllTypes.SingleSfixed64FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleUint32, fields[TestAllTypes.SingleUint32FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.SingleUint64, fields[TestAllTypes.SingleUint64FieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.OneofBytes, fields[TestAllTypes.OneofBytesFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.OneofString, fields[TestAllTypes.OneofStringFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.OneofNestedMessage, fields[TestAllTypes.OneofNestedMessageFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(message.OneofUint32, fields[TestAllTypes.OneofUint32FieldNumber].Accessor.GetValue(message));
+
+            // Just one example for repeated fields - they're all just returning the list
+            var list = (IList) fields[TestAllTypes.RepeatedInt32FieldNumber].Accessor.GetValue(message);
+            Assert.AreEqual(message.RepeatedInt32, list);
+            Assert.AreEqual(message.RepeatedInt32[0], list[0]); // Just in case there was any doubt...
+
+            // Just a single map field, for the same reason
+            var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } };
+            fields = TestMap.Descriptor.Fields;
+            var dictionary = (IDictionary) fields[TestMap.MapStringStringFieldNumber].Accessor.GetValue(mapMessage);
+            Assert.AreEqual(mapMessage.MapStringString, dictionary);
+            Assert.AreEqual("value1", dictionary["key1"]);
+        }
+
+        [Test]
+        public void Clear()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var fields = TestAllTypes.Descriptor.Fields;
+            fields[TestAllTypes.SingleBoolFieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.SingleInt32FieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.SingleStringFieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.SingleBytesFieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.SingleForeignEnumFieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.SingleForeignMessageFieldNumber].Accessor.Clear(message);
+            fields[TestAllTypes.RepeatedDoubleFieldNumber].Accessor.Clear(message);
+
+            var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes())
+            {
+                SingleBool = false,
+                SingleInt32 = 0,
+                SingleString = "",
+                SingleBytes = ByteString.Empty,
+                SingleForeignEnum = 0,
+                SingleForeignMessage = null,
+            };
+            expected.RepeatedDouble.Clear();
+
+            Assert.AreEqual(expected, message);
+
+            // Separately, maps.
+            var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } };
+            fields = TestMap.Descriptor.Fields;
+            fields[TestMap.MapStringStringFieldNumber].Accessor.Clear(mapMessage);
+            Assert.AreEqual(0, mapMessage.MapStringString.Count);
+        }
+
+        [Test]
+        public void SetValue_SingleFields()
+        {
+            // Just a sample (primitives, messages, enums, strings, byte strings)
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var fields = TestAllTypes.Descriptor.Fields;
+            fields[TestAllTypes.SingleBoolFieldNumber].Accessor.SetValue(message, false);
+            fields[TestAllTypes.SingleInt32FieldNumber].Accessor.SetValue(message, 500);
+            fields[TestAllTypes.SingleStringFieldNumber].Accessor.SetValue(message, "It's a string");
+            fields[TestAllTypes.SingleBytesFieldNumber].Accessor.SetValue(message, ByteString.CopyFrom(99, 98, 97));
+            fields[TestAllTypes.SingleForeignEnumFieldNumber].Accessor.SetValue(message, ForeignEnum.ForeignFoo);
+            fields[TestAllTypes.SingleForeignMessageFieldNumber].Accessor.SetValue(message, new ForeignMessage { C = 12345 });
+            fields[TestAllTypes.SingleDoubleFieldNumber].Accessor.SetValue(message, 20150701.5);
+
+            var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes())
+            {
+                SingleBool = false,
+                SingleInt32 = 500,
+                SingleString = "It's a string",
+                SingleBytes = ByteString.CopyFrom(99, 98, 97),
+                SingleForeignEnum = ForeignEnum.ForeignFoo,
+                SingleForeignMessage = new ForeignMessage { C = 12345 },
+                SingleDouble = 20150701.5
+            };
+
+            Assert.AreEqual(expected, message);
+        }
+
+        [Test]
+        public void SetValue_SingleFields_WrongType()
+        {
+            IMessage message = SampleMessages.CreateFullTestAllTypes();
+            var fields = message.Descriptor.Fields;
+            Assert.Throws<InvalidCastException>(() => fields[TestAllTypes.SingleBoolFieldNumber].Accessor.SetValue(message, "This isn't a bool"));
+        }
+
+        [Test]
+        public void SetValue_MapFields()
+        {
+            IMessage message = new TestMap();
+            var fields = message.Descriptor.Fields;
+            Assert.Throws<InvalidOperationException>(() => fields[TestMap.MapStringStringFieldNumber].Accessor.SetValue(message, new Dictionary<string, string>()));
+        }
+
+        [Test]
+        public void SetValue_RepeatedFields()
+        {
+            IMessage message = SampleMessages.CreateFullTestAllTypes();
+            var fields = message.Descriptor.Fields;
+            Assert.Throws<InvalidOperationException>(() => fields[TestAllTypes.RepeatedDoubleFieldNumber].Accessor.SetValue(message, new double[10]));
+        }
+
+        [Test]
+        public void GetValue_IncorrectType()
+        {
+            IMessage message = SampleMessages.CreateFullTestAllTypes();
+            var fields = message.Descriptor.Fields;
+            Assert.Throws<InvalidCastException>(() => fields[TestAllTypes.SingleBoolFieldNumber].Accessor.GetValue(new TestMap()));
+        }
+
+        [Test]
+        public void Oneof()
+        {
+            var message = new TestAllTypes();
+            var descriptor = TestAllTypes.Descriptor;
+            Assert.AreEqual(1, descriptor.Oneofs.Count);
+            var oneof = descriptor.Oneofs[0];
+            Assert.AreEqual("oneof_field", oneof.Name);
+            Assert.IsNull(oneof.Accessor.GetCaseFieldDescriptor(message));
+
+            message.OneofString = "foo";
+            Assert.AreSame(descriptor.Fields[TestAllTypes.OneofStringFieldNumber], oneof.Accessor.GetCaseFieldDescriptor(message));
+
+            message.OneofUint32 = 10;
+            Assert.AreSame(descriptor.Fields[TestAllTypes.OneofUint32FieldNumber], oneof.Accessor.GetCaseFieldDescriptor(message));
+
+            oneof.Accessor.Clear(message);
+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
+        }
+
+        [Test]
+        public void FieldDescriptor_ByName()
+        {
+            var descriptor = TestAllTypes.Descriptor;
+            Assert.AreSame(
+                descriptor.Fields[TestAllTypes.SingleBoolFieldNumber],
+                descriptor.Fields["single_bool"]);
+        }
+
+        [Test]
+        public void FieldDescriptor_NotFound()
+        {
+            var descriptor = TestAllTypes.Descriptor;
+            Assert.Throws<KeyNotFoundException>(() => descriptor.Fields[999999].ToString());
+            Assert.Throws<KeyNotFoundException>(() => descriptor.Fields["not found"].ToString());
+        }        
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs
new file mode 100644
index 0000000..5be7ca2
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs
@@ -0,0 +1,94 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework;
+
+namespace Google.Protobuf.Reflection
+{
+    public class TypeRegistryTest
+    {
+        // Most of our tests use messages. Simple test that we really can use files...
+        [Test]
+        public void CreateWithFileDescriptor()
+        {
+            var registry = TypeRegistry.FromFiles(DurationReflection.Descriptor, StructReflection.Descriptor);
+            AssertDescriptorPresent(registry, Duration.Descriptor);
+            AssertDescriptorPresent(registry, ListValue.Descriptor);
+            AssertDescriptorAbsent(registry, Timestamp.Descriptor);
+        }
+
+        [Test]
+        public void TypesFromSameFile()
+        {
+            // Just for kicks, let's start with a nested type
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Types.NestedMessage.Descriptor);
+            // Top-level...
+            AssertDescriptorPresent(registry, TestFieldOrderings.Descriptor);
+            // ... and nested (not the same as the original NestedMessage!)
+            AssertDescriptorPresent(registry, TestFieldOrderings.Types.NestedMessage.Descriptor);
+        }
+
+        [Test]
+        public void DependenciesAreIncluded()
+        {
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+            // Direct dependencies
+            AssertDescriptorPresent(registry, ImportMessage.Descriptor);
+            // Public dependencies
+            AssertDescriptorPresent(registry, PublicImportMessage.Descriptor);
+        }
+
+        [Test]
+        public void DuplicateFiles()
+        {
+            // Duplicates via dependencies and simply via repetition
+            var registry = TypeRegistry.FromFiles(
+                UnittestProto3Reflection.Descriptor, UnittestImportProto3Reflection.Descriptor,
+                TimestampReflection.Descriptor, TimestampReflection.Descriptor);
+            AssertDescriptorPresent(registry, TestAllTypes.Descriptor);
+            AssertDescriptorPresent(registry, ImportMessage.Descriptor);
+            AssertDescriptorPresent(registry, Timestamp.Descriptor);
+        }
+
+        private static void AssertDescriptorPresent(TypeRegistry registry, MessageDescriptor descriptor)
+        {
+            Assert.AreSame(descriptor, registry.Find(descriptor.FullName));
+        }
+
+        private static void AssertDescriptorAbsent(TypeRegistry registry, MessageDescriptor descriptor)
+        {
+            Assert.IsNull(registry.Find(descriptor.FullName));
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/SampleEnum.cs b/csharp/src/Google.Protobuf.Test/SampleEnum.cs
new file mode 100644
index 0000000..77447af
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/SampleEnum.cs
@@ -0,0 +1,42 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+namespace Google.Protobuf
+{
+    // Just a sample enum with positive and negative values to be used in tests.
+    internal enum SampleEnum
+    {
+        NegativeValue = -2,
+        None = 0,
+        PositiveValue = 3
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/SampleMessages.cs b/csharp/src/Google.Protobuf.Test/SampleMessages.cs
new file mode 100644
index 0000000..ffa4e2a
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/SampleMessages.cs
@@ -0,0 +1,99 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using Google.Protobuf.TestProtos;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods to create sample instances of types generated from unit test messages.
+    /// </summary>
+    public class SampleMessages
+    {
+        /// <summary>
+        /// Creates a new sample TestAllTypes message with all fields populated.
+        /// The "oneof" field is populated with the string property (OneofString).
+        /// </summary>
+        public static TestAllTypes CreateFullTestAllTypes()
+        {
+            return new TestAllTypes
+            {
+                SingleBool = true,
+                SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),
+                SingleDouble = 23.5,
+                SingleFixed32 = 23,
+                SingleFixed64 = 1234567890123,
+                SingleFloat = 12.25f,
+                SingleForeignEnum = ForeignEnum.ForeignBar,
+                SingleForeignMessage = new ForeignMessage { C = 10 },
+                SingleImportEnum = ImportEnum.ImportBaz,
+                SingleImportMessage = new ImportMessage { D = 20 },
+                SingleInt32 = 100,
+                SingleInt64 = 3210987654321,
+                SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,
+                SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },
+                SinglePublicImportMessage = new PublicImportMessage { E = 54 },
+                SingleSfixed32 = -123,
+                SingleSfixed64 = -12345678901234,
+                SingleSint32 = -456,
+                SingleSint64 = -12345678901235,
+                SingleString = "test",
+                SingleUint32 = UInt32.MaxValue,
+                SingleUint64 = UInt64.MaxValue,
+                RepeatedBool = { true, false },
+                RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6), ByteString.CopyFrom(new byte[1000]) },
+                RepeatedDouble = { -12.25, 23.5 },
+                RepeatedFixed32 = { UInt32.MaxValue, 23 },
+                RepeatedFixed64 = { UInt64.MaxValue, 1234567890123 },
+                RepeatedFloat = { 100f, 12.25f },
+                RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar },
+                RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } },
+                RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified },
+                RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } },
+                RepeatedInt32 = { 100, 200 },
+                RepeatedInt64 = { 3210987654321, Int64.MaxValue },
+                RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg },
+                RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } },
+                RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } },
+                RepeatedSfixed32 = { -123, 123 },
+                RepeatedSfixed64 = { -12345678901234, 12345678901234 },
+                RepeatedSint32 = { -456, 100 },
+                RepeatedSint64 = { -12345678901235, 123 },
+                RepeatedString = { "foo", "bar" },
+                RepeatedUint32 = { UInt32.MaxValue, UInt32.MinValue },
+                RepeatedUint64 = { UInt64.MaxValue, UInt32.MinValue },
+                OneofString = "Oneof string"
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs
new file mode 100644
index 0000000..248f5fa
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license

+// 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.

+#endregion

+    

+using UnitTest.Issues.TestProtos;

+using NUnit.Framework;

+

+namespace Google.Protobuf

+{

+    public class TestCornerCases

+    {

+        [Test]

+        public void TestRoundTripNegativeEnums()

+        {

+            NegativeEnumMessage msg = new NegativeEnumMessage

+            {

+                Value = NegativeEnum.MinusOne,

+                Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow },

+                PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }

+            };

+

+            Assert.AreEqual(58, msg.CalculateSize());

+

+            byte[] bytes = new byte[58];

+            CodedOutputStream output = new CodedOutputStream(bytes);

+

+            msg.WriteTo(output);

+            Assert.AreEqual(0, output.SpaceLeft);

+

+            NegativeEnumMessage copy = NegativeEnumMessage.Parser.ParseFrom(bytes);

+            Assert.AreEqual(msg, copy);

+        }

+    }

+}

diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs b/csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs
new file mode 100644
index 0000000..5663a69
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs
@@ -0,0 +1,45 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.TestProtos
+{
+    /// <summary>
+    /// A message with custom diagnostics (to test that they work).
+    /// </summary>
+    public partial class ForeignMessage : ICustomDiagnosticMessage
+    {
+        public string ToDiagnosticString()
+        {
+            return $"{{ \"c\": {C}, \"@cInHex\": \"{C:x}\" }}";
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
new file mode 100644
index 0000000..3ba4a2b
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
@@ -0,0 +1,1471 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/map_unittest_proto3.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.TestProtos {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/map_unittest_proto3.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class MapUnittestProto3Reflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/map_unittest_proto3.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static MapUnittestProto3Reflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Cilnb29nbGUvcHJvdG9idWYvbWFwX3VuaXR0ZXN0X3Byb3RvMy5wcm90bxIR",
+            "cHJvdG9idWZfdW5pdHRlc3QaJWdvb2dsZS9wcm90b2J1Zi91bml0dGVzdF9w",
+            "cm90bzMucHJvdG8ilhIKB1Rlc3RNYXASRgoPbWFwX2ludDMyX2ludDMyGAEg",
+            "AygLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkludDMy",
+            "RW50cnkSRgoPbWFwX2ludDY0X2ludDY0GAIgAygLMi0ucHJvdG9idWZfdW5p",
+            "dHRlc3QuVGVzdE1hcC5NYXBJbnQ2NEludDY0RW50cnkSSgoRbWFwX3VpbnQz",
+            "Ml91aW50MzIYAyADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h",
+            "cFVpbnQzMlVpbnQzMkVudHJ5EkoKEW1hcF91aW50NjRfdWludDY0GAQgAygL",
+            "Mi8ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBVaW50NjRVaW50NjRF",
+            "bnRyeRJKChFtYXBfc2ludDMyX3NpbnQzMhgFIAMoCzIvLnByb3RvYnVmX3Vu",
+            "aXR0ZXN0LlRlc3RNYXAuTWFwU2ludDMyU2ludDMyRW50cnkSSgoRbWFwX3Np",
+            "bnQ2NF9zaW50NjQYBiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFw",
+            "Lk1hcFNpbnQ2NFNpbnQ2NEVudHJ5Ek4KE21hcF9maXhlZDMyX2ZpeGVkMzIY",
+            "ByADKAsyMS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcEZpeGVkMzJG",
+            "aXhlZDMyRW50cnkSTgoTbWFwX2ZpeGVkNjRfZml4ZWQ2NBgIIAMoCzIxLnBy",
+            "b3RvYnVmX3VuaXR0ZXN0LlRlc3RNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRy",
+            "eRJSChVtYXBfc2ZpeGVkMzJfc2ZpeGVkMzIYCSADKAsyMy5wcm90b2J1Zl91",
+            "bml0dGVzdC5UZXN0TWFwLk1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRJSChVt",
+            "YXBfc2ZpeGVkNjRfc2ZpeGVkNjQYCiADKAsyMy5wcm90b2J1Zl91bml0dGVz",
+            "dC5UZXN0TWFwLk1hcFNmaXhlZDY0U2ZpeGVkNjRFbnRyeRJGCg9tYXBfaW50",
+            "MzJfZmxvYXQYCyADKAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h",
+            "cEludDMyRmxvYXRFbnRyeRJIChBtYXBfaW50MzJfZG91YmxlGAwgAygLMi4u",
+            "cHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkRvdWJsZUVudHJ5",
+            "EkIKDW1hcF9ib29sX2Jvb2wYDSADKAsyKy5wcm90b2J1Zl91bml0dGVzdC5U",
+            "ZXN0TWFwLk1hcEJvb2xCb29sRW50cnkSSgoRbWFwX3N0cmluZ19zdHJpbmcY",
+            "DiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcFN0cmluZ1N0",
+            "cmluZ0VudHJ5EkYKD21hcF9pbnQzMl9ieXRlcxgPIAMoCzItLnByb3RvYnVm",
+            "X3VuaXR0ZXN0LlRlc3RNYXAuTWFwSW50MzJCeXRlc0VudHJ5EkQKDm1hcF9p",
+            "bnQzMl9lbnVtGBAgAygLMiwucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5N",
+            "YXBJbnQzMkVudW1FbnRyeRJZChltYXBfaW50MzJfZm9yZWlnbl9tZXNzYWdl",
+            "GBEgAygLMjYucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkZv",
+            "cmVpZ25NZXNzYWdlRW50cnkaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tl",
+            "eRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVu",
+            "dHJ5EgsKA2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWlu",
+            "dDMyVWludDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4",
+            "ARo2ChRNYXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFs",
+            "dWUYAiABKAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgB",
+            "IAEoERINCgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50",
+            "cnkSCwoDa2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhl",
+            "ZDMyRml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoC",
+            "OAEaOAoWTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoF",
+            "dmFsdWUYAiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRIL",
+            "CgNrZXkYASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0",
+            "U2ZpeGVkNjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgB",
+            "GjQKEk1hcEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUY",
+            "AiABKAI6AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgF",
+            "Eg0KBXZhbHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tl",
+            "eRgBIAEoCBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5n",
+            "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo0ChJNYXBJ",
+            "bnQzMkJ5dGVzRW50cnkSCwoDa2V5GAEgASgFEg0KBXZhbHVlGAIgASgMOgI4",
+            "ARpPChFNYXBJbnQzMkVudW1FbnRyeRILCgNrZXkYASABKAUSKQoFdmFsdWUY",
+            "AiABKA4yGi5wcm90b2J1Zl91bml0dGVzdC5NYXBFbnVtOgI4ARpgChtNYXBJ",
+            "bnQzMkZvcmVpZ25NZXNzYWdlRW50cnkSCwoDa2V5GAEgASgFEjAKBXZhbHVl",
+            "GAIgASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2U6AjgB",
+            "IkEKEVRlc3RNYXBTdWJtZXNzYWdlEiwKCHRlc3RfbWFwGAEgASgLMhoucHJv",
+            "dG9idWZfdW5pdHRlc3QuVGVzdE1hcCK8AQoOVGVzdE1lc3NhZ2VNYXASUQoR",
+            "bWFwX2ludDMyX21lc3NhZ2UYASADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5U",
+            "ZXN0TWVzc2FnZU1hcC5NYXBJbnQzMk1lc3NhZ2VFbnRyeRpXChRNYXBJbnQz",
+            "Mk1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAUSLgoFdmFsdWUYAiABKAsyHy5w",
+            "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXM6AjgBIuMBCg9UZXN0U2Ft",
+            "ZVR5cGVNYXASOgoEbWFwMRgBIAMoCzIsLnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RTYW1lVHlwZU1hcC5NYXAxRW50cnkSOgoEbWFwMhgCIAMoCzIsLnByb3Rv",
+            "YnVmX3VuaXR0ZXN0LlRlc3RTYW1lVHlwZU1hcC5NYXAyRW50cnkaKwoJTWFw",
+            "MUVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaKwoJTWFw",
+            "MkVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEi5BAKDFRl",
+            "c3RBcmVuYU1hcBJLCg9tYXBfaW50MzJfaW50MzIYASADKAsyMi5wcm90b2J1",
+            "Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50MzJJbnQzMkVudHJ5EksK",
+            "D21hcF9pbnQ2NF9pbnQ2NBgCIAMoCzIyLnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RBcmVuYU1hcC5NYXBJbnQ2NEludDY0RW50cnkSTwoRbWFwX3VpbnQzMl91",
+            "aW50MzIYAyADKAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAu",
+            "TWFwVWludDMyVWludDMyRW50cnkSTwoRbWFwX3VpbnQ2NF91aW50NjQYBCAD",
+            "KAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwVWludDY0",
+            "VWludDY0RW50cnkSTwoRbWFwX3NpbnQzMl9zaW50MzIYBSADKAsyNC5wcm90",
+            "b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDMyU2ludDMyRW50",
+            "cnkSTwoRbWFwX3NpbnQ2NF9zaW50NjQYBiADKAsyNC5wcm90b2J1Zl91bml0",
+            "dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDY0U2ludDY0RW50cnkSUwoTbWFw",
+            "X2ZpeGVkMzJfZml4ZWQzMhgHIAMoCzI2LnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RBcmVuYU1hcC5NYXBGaXhlZDMyRml4ZWQzMkVudHJ5ElMKE21hcF9maXhl",
+            "ZDY0X2ZpeGVkNjQYCCADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJl",
+            "bmFNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRJXChVtYXBfc2ZpeGVkMzJf",
+            "c2ZpeGVkMzIYCSADKAsyOC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFN",
+            "YXAuTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5ElcKFW1hcF9zZml4ZWQ2NF9z",
+            "Zml4ZWQ2NBgKIAMoCzI4LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBcmVuYU1h",
+            "cC5NYXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSSwoPbWFwX2ludDMyX2Zsb2F0",
+            "GAsgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcElu",
+            "dDMyRmxvYXRFbnRyeRJNChBtYXBfaW50MzJfZG91YmxlGAwgAygLMjMucHJv",
+            "dG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcEludDMyRG91YmxlRW50",
+            "cnkSRwoNbWFwX2Jvb2xfYm9vbBgNIAMoCzIwLnByb3RvYnVmX3VuaXR0ZXN0",
+            "LlRlc3RBcmVuYU1hcC5NYXBCb29sQm9vbEVudHJ5EkkKDm1hcF9pbnQzMl9l",
+            "bnVtGA4gAygLMjEucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1h",
+            "cEludDMyRW51bUVudHJ5El4KGW1hcF9pbnQzMl9mb3JlaWduX21lc3NhZ2UY",
+            "DyADKAsyOy5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50",
+            "MzJGb3JlaWduTWVzc2FnZUVudHJ5GjQKEk1hcEludDMySW50MzJFbnRyeRIL",
+            "CgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcEludDY0SW50",
+            "NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgBGjYKFE1h",
+            "cFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1ZRgCIAEo",
+            "DToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEgASgEEg0K",
+            "BXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRyeRILCgNr",
+            "ZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2NFNpbnQ2",
+            "NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEaOAoWTWFw",
+            "Rml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFsdWUYAiAB",
+            "KAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5GAEgASgG",
+            "Eg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhlZDMyRW50",
+            "cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhNYXBTZml4",
+            "ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVlGAIgASgQ",
+            "OgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgFEg0KBXZh",
+            "bHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsKA2tleRgB",
+            "IAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xFbnRyeRIL",
+            "CgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGk8KEU1hcEludDMyRW51",
+            "bUVudHJ5EgsKA2tleRgBIAEoBRIpCgV2YWx1ZRgCIAEoDjIaLnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1hcEVudW06AjgBGmAKG01hcEludDMyRm9yZWlnbk1lc3Nh",
+            "Z2VFbnRyeRILCgNrZXkYASABKAUSMAoFdmFsdWUYAiABKAsyIS5wcm90b2J1",
+            "Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZToCOAEi5AEKH01lc3NhZ2VDb250",
+            "YWluaW5nRW51bUNhbGxlZFR5cGUSSgoEdHlwZRgBIAMoCzI8LnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1lc3NhZ2VDb250YWluaW5nRW51bUNhbGxlZFR5cGUuVHlw",
+            "ZUVudHJ5Gl8KCVR5cGVFbnRyeRILCgNrZXkYASABKAUSQQoFdmFsdWUYAiAB",
+            "KAsyMi5wcm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ0VudW1D",
+            "YWxsZWRUeXBlOgI4ASIUCgRUeXBlEgwKCFRZUEVfRk9PEAAinQEKH01lc3Nh",
+            "Z2VDb250YWluaW5nTWFwQ2FsbGVkRW50cnkSTAoFZW50cnkYASADKAsyPS5w",
+            "cm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ01hcENhbGxlZEVu",
+            "dHJ5LkVudHJ5RW50cnkaLAoKRW50cnlFbnRyeRILCgNrZXkYASABKAUSDQoF",
+            "dmFsdWUYAiABKAU6AjgBKj8KB01hcEVudW0SEAoMTUFQX0VOVU1fRk9PEAAS",
+            "EAoMTUFQX0VOVU1fQkFSEAESEAoMTUFQX0VOVU1fQkFaEAJCIPgBAaoCGkdv",
+            "b2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zYgZwcm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.MapEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMap), global::Google.Protobuf.TestProtos.TestMap.Parser, new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapInt32Bytes", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMapSubmessage), global::Google.Protobuf.TestProtos.TestMapSubmessage.Parser, new[]{ "TestMap" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMessageMap), global::Google.Protobuf.TestProtos.TestMessageMap.Parser, new[]{ "MapInt32Message" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestSameTypeMap), global::Google.Protobuf.TestProtos.TestSameTypeMap.Parser, new[]{ "Map1", "Map2" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestArenaMap), global::Google.Protobuf.TestProtos.TestArenaMap.Parser, new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType), global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Parser, new[]{ "Type" }, null, new[]{ typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Types.Type) }, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingMapCalledEntry), global::Google.Protobuf.TestProtos.MessageContainingMapCalledEntry.Parser, new[]{ "Entry" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, })
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum MapEnum {
+    [pbr::OriginalName("MAP_ENUM_FOO")] Foo = 0,
+    [pbr::OriginalName("MAP_ENUM_BAR")] Bar = 1,
+    [pbr::OriginalName("MAP_ENUM_BAZ")] Baz = 2,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  Tests maps.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestMap : pb::IMessage<TestMap> {
+    private static readonly pb::MessageParser<TestMap> _parser = new pb::MessageParser<TestMap>(() => new TestMap());
+    public static pb::MessageParser<TestMap> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestMap() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestMap(TestMap other) : this() {
+      mapInt32Int32_ = other.mapInt32Int32_.Clone();
+      mapInt64Int64_ = other.mapInt64Int64_.Clone();
+      mapUint32Uint32_ = other.mapUint32Uint32_.Clone();
+      mapUint64Uint64_ = other.mapUint64Uint64_.Clone();
+      mapSint32Sint32_ = other.mapSint32Sint32_.Clone();
+      mapSint64Sint64_ = other.mapSint64Sint64_.Clone();
+      mapFixed32Fixed32_ = other.mapFixed32Fixed32_.Clone();
+      mapFixed64Fixed64_ = other.mapFixed64Fixed64_.Clone();
+      mapSfixed32Sfixed32_ = other.mapSfixed32Sfixed32_.Clone();
+      mapSfixed64Sfixed64_ = other.mapSfixed64Sfixed64_.Clone();
+      mapInt32Float_ = other.mapInt32Float_.Clone();
+      mapInt32Double_ = other.mapInt32Double_.Clone();
+      mapBoolBool_ = other.mapBoolBool_.Clone();
+      mapStringString_ = other.mapStringString_.Clone();
+      mapInt32Bytes_ = other.mapInt32Bytes_.Clone();
+      mapInt32Enum_ = other.mapInt32Enum_.Clone();
+      mapInt32ForeignMessage_ = other.mapInt32ForeignMessage_.Clone();
+    }
+
+    public TestMap Clone() {
+      return new TestMap(this);
+    }
+
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
+    public const int MapInt32Int32FieldNumber = 1;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
+    private readonly pbc::MapField<int, int> mapInt32Int32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapInt32Int32 {
+      get { return mapInt32Int32_; }
+    }
+
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
+    public const int MapInt64Int64FieldNumber = 2;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 18);
+    private readonly pbc::MapField<long, long> mapInt64Int64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapInt64Int64 {
+      get { return mapInt64Int64_; }
+    }
+
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
+    public const int MapUint32Uint32FieldNumber = 3;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 26);
+    private readonly pbc::MapField<uint, uint> mapUint32Uint32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapUint32Uint32 {
+      get { return mapUint32Uint32_; }
+    }
+
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
+    public const int MapUint64Uint64FieldNumber = 4;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 34);
+    private readonly pbc::MapField<ulong, ulong> mapUint64Uint64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapUint64Uint64 {
+      get { return mapUint64Uint64_; }
+    }
+
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
+    public const int MapSint32Sint32FieldNumber = 5;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 42);
+    private readonly pbc::MapField<int, int> mapSint32Sint32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSint32Sint32 {
+      get { return mapSint32Sint32_; }
+    }
+
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
+    public const int MapSint64Sint64FieldNumber = 6;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 50);
+    private readonly pbc::MapField<long, long> mapSint64Sint64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSint64Sint64 {
+      get { return mapSint64Sint64_; }
+    }
+
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
+    public const int MapFixed32Fixed32FieldNumber = 7;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 58);
+    private readonly pbc::MapField<uint, uint> mapFixed32Fixed32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapFixed32Fixed32 {
+      get { return mapFixed32Fixed32_; }
+    }
+
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
+    public const int MapFixed64Fixed64FieldNumber = 8;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 66);
+    private readonly pbc::MapField<ulong, ulong> mapFixed64Fixed64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapFixed64Fixed64 {
+      get { return mapFixed64Fixed64_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
+    public const int MapSfixed32Sfixed32FieldNumber = 9;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 74);
+    private readonly pbc::MapField<int, int> mapSfixed32Sfixed32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSfixed32Sfixed32 {
+      get { return mapSfixed32Sfixed32_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
+    public const int MapSfixed64Sfixed64FieldNumber = 10;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 82);
+    private readonly pbc::MapField<long, long> mapSfixed64Sfixed64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSfixed64Sfixed64 {
+      get { return mapSfixed64Sfixed64_; }
+    }
+
+    /// <summary>Field number for the "map_int32_float" field.</summary>
+    public const int MapInt32FloatFieldNumber = 11;
+    private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
+        = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 90);
+    private readonly pbc::MapField<int, float> mapInt32Float_ = new pbc::MapField<int, float>();
+    public pbc::MapField<int, float> MapInt32Float {
+      get { return mapInt32Float_; }
+    }
+
+    /// <summary>Field number for the "map_int32_double" field.</summary>
+    public const int MapInt32DoubleFieldNumber = 12;
+    private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
+        = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 98);
+    private readonly pbc::MapField<int, double> mapInt32Double_ = new pbc::MapField<int, double>();
+    public pbc::MapField<int, double> MapInt32Double {
+      get { return mapInt32Double_; }
+    }
+
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
+    public const int MapBoolBoolFieldNumber = 13;
+    private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
+        = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 106);
+    private readonly pbc::MapField<bool, bool> mapBoolBool_ = new pbc::MapField<bool, bool>();
+    public pbc::MapField<bool, bool> MapBoolBool {
+      get { return mapBoolBool_; }
+    }
+
+    /// <summary>Field number for the "map_string_string" field.</summary>
+    public const int MapStringStringFieldNumber = 14;
+    private static readonly pbc::MapField<string, string>.Codec _map_mapStringString_codec
+        = new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 114);
+    private readonly pbc::MapField<string, string> mapStringString_ = new pbc::MapField<string, string>();
+    public pbc::MapField<string, string> MapStringString {
+      get { return mapStringString_; }
+    }
+
+    /// <summary>Field number for the "map_int32_bytes" field.</summary>
+    public const int MapInt32BytesFieldNumber = 15;
+    private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_mapInt32Bytes_codec
+        = new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForBytes(18), 122);
+    private readonly pbc::MapField<int, pb::ByteString> mapInt32Bytes_ = new pbc::MapField<int, pb::ByteString>();
+    public pbc::MapField<int, pb::ByteString> MapInt32Bytes {
+      get { return mapInt32Bytes_; }
+    }
+
+    /// <summary>Field number for the "map_int32_enum" field.</summary>
+    public const int MapInt32EnumFieldNumber = 16;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec _map_mapInt32Enum_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Google.Protobuf.TestProtos.MapEnum) x), 130);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum> mapInt32Enum_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum> MapInt32Enum {
+      get { return mapInt32Enum_; }
+    }
+
+    /// <summary>Field number for the "map_int32_foreign_message" field.</summary>
+    public const int MapInt32ForeignMessageFieldNumber = 17;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec _map_mapInt32ForeignMessage_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.ForeignMessage.Parser), 138);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage> mapInt32ForeignMessage_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage> MapInt32ForeignMessage {
+      get { return mapInt32ForeignMessage_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestMap);
+    }
+
+    public bool Equals(TestMap other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!MapInt32Int32.Equals(other.MapInt32Int32)) return false;
+      if (!MapInt64Int64.Equals(other.MapInt64Int64)) return false;
+      if (!MapUint32Uint32.Equals(other.MapUint32Uint32)) return false;
+      if (!MapUint64Uint64.Equals(other.MapUint64Uint64)) return false;
+      if (!MapSint32Sint32.Equals(other.MapSint32Sint32)) return false;
+      if (!MapSint64Sint64.Equals(other.MapSint64Sint64)) return false;
+      if (!MapFixed32Fixed32.Equals(other.MapFixed32Fixed32)) return false;
+      if (!MapFixed64Fixed64.Equals(other.MapFixed64Fixed64)) return false;
+      if (!MapSfixed32Sfixed32.Equals(other.MapSfixed32Sfixed32)) return false;
+      if (!MapSfixed64Sfixed64.Equals(other.MapSfixed64Sfixed64)) return false;
+      if (!MapInt32Float.Equals(other.MapInt32Float)) return false;
+      if (!MapInt32Double.Equals(other.MapInt32Double)) return false;
+      if (!MapBoolBool.Equals(other.MapBoolBool)) return false;
+      if (!MapStringString.Equals(other.MapStringString)) return false;
+      if (!MapInt32Bytes.Equals(other.MapInt32Bytes)) return false;
+      if (!MapInt32Enum.Equals(other.MapInt32Enum)) return false;
+      if (!MapInt32ForeignMessage.Equals(other.MapInt32ForeignMessage)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= MapInt32Int32.GetHashCode();
+      hash ^= MapInt64Int64.GetHashCode();
+      hash ^= MapUint32Uint32.GetHashCode();
+      hash ^= MapUint64Uint64.GetHashCode();
+      hash ^= MapSint32Sint32.GetHashCode();
+      hash ^= MapSint64Sint64.GetHashCode();
+      hash ^= MapFixed32Fixed32.GetHashCode();
+      hash ^= MapFixed64Fixed64.GetHashCode();
+      hash ^= MapSfixed32Sfixed32.GetHashCode();
+      hash ^= MapSfixed64Sfixed64.GetHashCode();
+      hash ^= MapInt32Float.GetHashCode();
+      hash ^= MapInt32Double.GetHashCode();
+      hash ^= MapBoolBool.GetHashCode();
+      hash ^= MapStringString.GetHashCode();
+      hash ^= MapInt32Bytes.GetHashCode();
+      hash ^= MapInt32Enum.GetHashCode();
+      hash ^= MapInt32ForeignMessage.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      mapInt32Int32_.WriteTo(output, _map_mapInt32Int32_codec);
+      mapInt64Int64_.WriteTo(output, _map_mapInt64Int64_codec);
+      mapUint32Uint32_.WriteTo(output, _map_mapUint32Uint32_codec);
+      mapUint64Uint64_.WriteTo(output, _map_mapUint64Uint64_codec);
+      mapSint32Sint32_.WriteTo(output, _map_mapSint32Sint32_codec);
+      mapSint64Sint64_.WriteTo(output, _map_mapSint64Sint64_codec);
+      mapFixed32Fixed32_.WriteTo(output, _map_mapFixed32Fixed32_codec);
+      mapFixed64Fixed64_.WriteTo(output, _map_mapFixed64Fixed64_codec);
+      mapSfixed32Sfixed32_.WriteTo(output, _map_mapSfixed32Sfixed32_codec);
+      mapSfixed64Sfixed64_.WriteTo(output, _map_mapSfixed64Sfixed64_codec);
+      mapInt32Float_.WriteTo(output, _map_mapInt32Float_codec);
+      mapInt32Double_.WriteTo(output, _map_mapInt32Double_codec);
+      mapBoolBool_.WriteTo(output, _map_mapBoolBool_codec);
+      mapStringString_.WriteTo(output, _map_mapStringString_codec);
+      mapInt32Bytes_.WriteTo(output, _map_mapInt32Bytes_codec);
+      mapInt32Enum_.WriteTo(output, _map_mapInt32Enum_codec);
+      mapInt32ForeignMessage_.WriteTo(output, _map_mapInt32ForeignMessage_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += mapInt32Int32_.CalculateSize(_map_mapInt32Int32_codec);
+      size += mapInt64Int64_.CalculateSize(_map_mapInt64Int64_codec);
+      size += mapUint32Uint32_.CalculateSize(_map_mapUint32Uint32_codec);
+      size += mapUint64Uint64_.CalculateSize(_map_mapUint64Uint64_codec);
+      size += mapSint32Sint32_.CalculateSize(_map_mapSint32Sint32_codec);
+      size += mapSint64Sint64_.CalculateSize(_map_mapSint64Sint64_codec);
+      size += mapFixed32Fixed32_.CalculateSize(_map_mapFixed32Fixed32_codec);
+      size += mapFixed64Fixed64_.CalculateSize(_map_mapFixed64Fixed64_codec);
+      size += mapSfixed32Sfixed32_.CalculateSize(_map_mapSfixed32Sfixed32_codec);
+      size += mapSfixed64Sfixed64_.CalculateSize(_map_mapSfixed64Sfixed64_codec);
+      size += mapInt32Float_.CalculateSize(_map_mapInt32Float_codec);
+      size += mapInt32Double_.CalculateSize(_map_mapInt32Double_codec);
+      size += mapBoolBool_.CalculateSize(_map_mapBoolBool_codec);
+      size += mapStringString_.CalculateSize(_map_mapStringString_codec);
+      size += mapInt32Bytes_.CalculateSize(_map_mapInt32Bytes_codec);
+      size += mapInt32Enum_.CalculateSize(_map_mapInt32Enum_codec);
+      size += mapInt32ForeignMessage_.CalculateSize(_map_mapInt32ForeignMessage_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestMap other) {
+      if (other == null) {
+        return;
+      }
+      mapInt32Int32_.Add(other.mapInt32Int32_);
+      mapInt64Int64_.Add(other.mapInt64Int64_);
+      mapUint32Uint32_.Add(other.mapUint32Uint32_);
+      mapUint64Uint64_.Add(other.mapUint64Uint64_);
+      mapSint32Sint32_.Add(other.mapSint32Sint32_);
+      mapSint64Sint64_.Add(other.mapSint64Sint64_);
+      mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
+      mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
+      mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
+      mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
+      mapInt32Float_.Add(other.mapInt32Float_);
+      mapInt32Double_.Add(other.mapInt32Double_);
+      mapBoolBool_.Add(other.mapBoolBool_);
+      mapStringString_.Add(other.mapStringString_);
+      mapInt32Bytes_.Add(other.mapInt32Bytes_);
+      mapInt32Enum_.Add(other.mapInt32Enum_);
+      mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            mapInt32Int32_.AddEntriesFrom(input, _map_mapInt32Int32_codec);
+            break;
+          }
+          case 18: {
+            mapInt64Int64_.AddEntriesFrom(input, _map_mapInt64Int64_codec);
+            break;
+          }
+          case 26: {
+            mapUint32Uint32_.AddEntriesFrom(input, _map_mapUint32Uint32_codec);
+            break;
+          }
+          case 34: {
+            mapUint64Uint64_.AddEntriesFrom(input, _map_mapUint64Uint64_codec);
+            break;
+          }
+          case 42: {
+            mapSint32Sint32_.AddEntriesFrom(input, _map_mapSint32Sint32_codec);
+            break;
+          }
+          case 50: {
+            mapSint64Sint64_.AddEntriesFrom(input, _map_mapSint64Sint64_codec);
+            break;
+          }
+          case 58: {
+            mapFixed32Fixed32_.AddEntriesFrom(input, _map_mapFixed32Fixed32_codec);
+            break;
+          }
+          case 66: {
+            mapFixed64Fixed64_.AddEntriesFrom(input, _map_mapFixed64Fixed64_codec);
+            break;
+          }
+          case 74: {
+            mapSfixed32Sfixed32_.AddEntriesFrom(input, _map_mapSfixed32Sfixed32_codec);
+            break;
+          }
+          case 82: {
+            mapSfixed64Sfixed64_.AddEntriesFrom(input, _map_mapSfixed64Sfixed64_codec);
+            break;
+          }
+          case 90: {
+            mapInt32Float_.AddEntriesFrom(input, _map_mapInt32Float_codec);
+            break;
+          }
+          case 98: {
+            mapInt32Double_.AddEntriesFrom(input, _map_mapInt32Double_codec);
+            break;
+          }
+          case 106: {
+            mapBoolBool_.AddEntriesFrom(input, _map_mapBoolBool_codec);
+            break;
+          }
+          case 114: {
+            mapStringString_.AddEntriesFrom(input, _map_mapStringString_codec);
+            break;
+          }
+          case 122: {
+            mapInt32Bytes_.AddEntriesFrom(input, _map_mapInt32Bytes_codec);
+            break;
+          }
+          case 130: {
+            mapInt32Enum_.AddEntriesFrom(input, _map_mapInt32Enum_codec);
+            break;
+          }
+          case 138: {
+            mapInt32ForeignMessage_.AddEntriesFrom(input, _map_mapInt32ForeignMessage_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestMapSubmessage : pb::IMessage<TestMapSubmessage> {
+    private static readonly pb::MessageParser<TestMapSubmessage> _parser = new pb::MessageParser<TestMapSubmessage>(() => new TestMapSubmessage());
+    public static pb::MessageParser<TestMapSubmessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestMapSubmessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestMapSubmessage(TestMapSubmessage other) : this() {
+      TestMap = other.testMap_ != null ? other.TestMap.Clone() : null;
+    }
+
+    public TestMapSubmessage Clone() {
+      return new TestMapSubmessage(this);
+    }
+
+    /// <summary>Field number for the "test_map" field.</summary>
+    public const int TestMapFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestMap testMap_;
+    public global::Google.Protobuf.TestProtos.TestMap TestMap {
+      get { return testMap_; }
+      set {
+        testMap_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestMapSubmessage);
+    }
+
+    public bool Equals(TestMapSubmessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(TestMap, other.TestMap)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (testMap_ != null) hash ^= TestMap.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (testMap_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(TestMap);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (testMap_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(TestMap);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestMapSubmessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.testMap_ != null) {
+        if (testMap_ == null) {
+          testMap_ = new global::Google.Protobuf.TestProtos.TestMap();
+        }
+        TestMap.MergeFrom(other.TestMap);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (testMap_ == null) {
+              testMap_ = new global::Google.Protobuf.TestProtos.TestMap();
+            }
+            input.ReadMessage(testMap_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestMessageMap : pb::IMessage<TestMessageMap> {
+    private static readonly pb::MessageParser<TestMessageMap> _parser = new pb::MessageParser<TestMessageMap>(() => new TestMessageMap());
+    public static pb::MessageParser<TestMessageMap> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestMessageMap() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestMessageMap(TestMessageMap other) : this() {
+      mapInt32Message_ = other.mapInt32Message_.Clone();
+    }
+
+    public TestMessageMap Clone() {
+      return new TestMessageMap(this);
+    }
+
+    /// <summary>Field number for the "map_int32_message" field.</summary>
+    public const int MapInt32MessageFieldNumber = 1;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes>.Codec _map_mapInt32Message_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.TestAllTypes.Parser), 10);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes> mapInt32Message_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes> MapInt32Message {
+      get { return mapInt32Message_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestMessageMap);
+    }
+
+    public bool Equals(TestMessageMap other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!MapInt32Message.Equals(other.MapInt32Message)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= MapInt32Message.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      mapInt32Message_.WriteTo(output, _map_mapInt32Message_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += mapInt32Message_.CalculateSize(_map_mapInt32Message_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestMessageMap other) {
+      if (other == null) {
+        return;
+      }
+      mapInt32Message_.Add(other.mapInt32Message_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            mapInt32Message_.AddEntriesFrom(input, _map_mapInt32Message_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Two map fields share the same entry default instance.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestSameTypeMap : pb::IMessage<TestSameTypeMap> {
+    private static readonly pb::MessageParser<TestSameTypeMap> _parser = new pb::MessageParser<TestSameTypeMap>(() => new TestSameTypeMap());
+    public static pb::MessageParser<TestSameTypeMap> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestSameTypeMap() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestSameTypeMap(TestSameTypeMap other) : this() {
+      map1_ = other.map1_.Clone();
+      map2_ = other.map2_.Clone();
+    }
+
+    public TestSameTypeMap Clone() {
+      return new TestSameTypeMap(this);
+    }
+
+    /// <summary>Field number for the "map1" field.</summary>
+    public const int Map1FieldNumber = 1;
+    private static readonly pbc::MapField<int, int>.Codec _map_map1_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
+    private readonly pbc::MapField<int, int> map1_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> Map1 {
+      get { return map1_; }
+    }
+
+    /// <summary>Field number for the "map2" field.</summary>
+    public const int Map2FieldNumber = 2;
+    private static readonly pbc::MapField<int, int>.Codec _map_map2_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 18);
+    private readonly pbc::MapField<int, int> map2_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> Map2 {
+      get { return map2_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestSameTypeMap);
+    }
+
+    public bool Equals(TestSameTypeMap other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!Map1.Equals(other.Map1)) return false;
+      if (!Map2.Equals(other.Map2)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= Map1.GetHashCode();
+      hash ^= Map2.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      map1_.WriteTo(output, _map_map1_codec);
+      map2_.WriteTo(output, _map_map2_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += map1_.CalculateSize(_map_map1_codec);
+      size += map2_.CalculateSize(_map_map2_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestSameTypeMap other) {
+      if (other == null) {
+        return;
+      }
+      map1_.Add(other.map1_);
+      map2_.Add(other.map2_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            map1_.AddEntriesFrom(input, _map_map1_codec);
+            break;
+          }
+          case 18: {
+            map2_.AddEntriesFrom(input, _map_map2_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestArenaMap : pb::IMessage<TestArenaMap> {
+    private static readonly pb::MessageParser<TestArenaMap> _parser = new pb::MessageParser<TestArenaMap>(() => new TestArenaMap());
+    public static pb::MessageParser<TestArenaMap> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestArenaMap() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestArenaMap(TestArenaMap other) : this() {
+      mapInt32Int32_ = other.mapInt32Int32_.Clone();
+      mapInt64Int64_ = other.mapInt64Int64_.Clone();
+      mapUint32Uint32_ = other.mapUint32Uint32_.Clone();
+      mapUint64Uint64_ = other.mapUint64Uint64_.Clone();
+      mapSint32Sint32_ = other.mapSint32Sint32_.Clone();
+      mapSint64Sint64_ = other.mapSint64Sint64_.Clone();
+      mapFixed32Fixed32_ = other.mapFixed32Fixed32_.Clone();
+      mapFixed64Fixed64_ = other.mapFixed64Fixed64_.Clone();
+      mapSfixed32Sfixed32_ = other.mapSfixed32Sfixed32_.Clone();
+      mapSfixed64Sfixed64_ = other.mapSfixed64Sfixed64_.Clone();
+      mapInt32Float_ = other.mapInt32Float_.Clone();
+      mapInt32Double_ = other.mapInt32Double_.Clone();
+      mapBoolBool_ = other.mapBoolBool_.Clone();
+      mapInt32Enum_ = other.mapInt32Enum_.Clone();
+      mapInt32ForeignMessage_ = other.mapInt32ForeignMessage_.Clone();
+    }
+
+    public TestArenaMap Clone() {
+      return new TestArenaMap(this);
+    }
+
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
+    public const int MapInt32Int32FieldNumber = 1;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
+    private readonly pbc::MapField<int, int> mapInt32Int32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapInt32Int32 {
+      get { return mapInt32Int32_; }
+    }
+
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
+    public const int MapInt64Int64FieldNumber = 2;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 18);
+    private readonly pbc::MapField<long, long> mapInt64Int64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapInt64Int64 {
+      get { return mapInt64Int64_; }
+    }
+
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
+    public const int MapUint32Uint32FieldNumber = 3;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 26);
+    private readonly pbc::MapField<uint, uint> mapUint32Uint32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapUint32Uint32 {
+      get { return mapUint32Uint32_; }
+    }
+
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
+    public const int MapUint64Uint64FieldNumber = 4;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 34);
+    private readonly pbc::MapField<ulong, ulong> mapUint64Uint64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapUint64Uint64 {
+      get { return mapUint64Uint64_; }
+    }
+
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
+    public const int MapSint32Sint32FieldNumber = 5;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 42);
+    private readonly pbc::MapField<int, int> mapSint32Sint32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSint32Sint32 {
+      get { return mapSint32Sint32_; }
+    }
+
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
+    public const int MapSint64Sint64FieldNumber = 6;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 50);
+    private readonly pbc::MapField<long, long> mapSint64Sint64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSint64Sint64 {
+      get { return mapSint64Sint64_; }
+    }
+
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
+    public const int MapFixed32Fixed32FieldNumber = 7;
+    private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
+        = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 58);
+    private readonly pbc::MapField<uint, uint> mapFixed32Fixed32_ = new pbc::MapField<uint, uint>();
+    public pbc::MapField<uint, uint> MapFixed32Fixed32 {
+      get { return mapFixed32Fixed32_; }
+    }
+
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
+    public const int MapFixed64Fixed64FieldNumber = 8;
+    private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
+        = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 66);
+    private readonly pbc::MapField<ulong, ulong> mapFixed64Fixed64_ = new pbc::MapField<ulong, ulong>();
+    public pbc::MapField<ulong, ulong> MapFixed64Fixed64 {
+      get { return mapFixed64Fixed64_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
+    public const int MapSfixed32Sfixed32FieldNumber = 9;
+    private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 74);
+    private readonly pbc::MapField<int, int> mapSfixed32Sfixed32_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> MapSfixed32Sfixed32 {
+      get { return mapSfixed32Sfixed32_; }
+    }
+
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
+    public const int MapSfixed64Sfixed64FieldNumber = 10;
+    private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
+        = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 82);
+    private readonly pbc::MapField<long, long> mapSfixed64Sfixed64_ = new pbc::MapField<long, long>();
+    public pbc::MapField<long, long> MapSfixed64Sfixed64 {
+      get { return mapSfixed64Sfixed64_; }
+    }
+
+    /// <summary>Field number for the "map_int32_float" field.</summary>
+    public const int MapInt32FloatFieldNumber = 11;
+    private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
+        = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 90);
+    private readonly pbc::MapField<int, float> mapInt32Float_ = new pbc::MapField<int, float>();
+    public pbc::MapField<int, float> MapInt32Float {
+      get { return mapInt32Float_; }
+    }
+
+    /// <summary>Field number for the "map_int32_double" field.</summary>
+    public const int MapInt32DoubleFieldNumber = 12;
+    private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
+        = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 98);
+    private readonly pbc::MapField<int, double> mapInt32Double_ = new pbc::MapField<int, double>();
+    public pbc::MapField<int, double> MapInt32Double {
+      get { return mapInt32Double_; }
+    }
+
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
+    public const int MapBoolBoolFieldNumber = 13;
+    private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
+        = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 106);
+    private readonly pbc::MapField<bool, bool> mapBoolBool_ = new pbc::MapField<bool, bool>();
+    public pbc::MapField<bool, bool> MapBoolBool {
+      get { return mapBoolBool_; }
+    }
+
+    /// <summary>Field number for the "map_int32_enum" field.</summary>
+    public const int MapInt32EnumFieldNumber = 14;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec _map_mapInt32Enum_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Google.Protobuf.TestProtos.MapEnum) x), 114);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum> mapInt32Enum_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum> MapInt32Enum {
+      get { return mapInt32Enum_; }
+    }
+
+    /// <summary>Field number for the "map_int32_foreign_message" field.</summary>
+    public const int MapInt32ForeignMessageFieldNumber = 15;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec _map_mapInt32ForeignMessage_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.ForeignMessage.Parser), 122);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage> mapInt32ForeignMessage_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage> MapInt32ForeignMessage {
+      get { return mapInt32ForeignMessage_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestArenaMap);
+    }
+
+    public bool Equals(TestArenaMap other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!MapInt32Int32.Equals(other.MapInt32Int32)) return false;
+      if (!MapInt64Int64.Equals(other.MapInt64Int64)) return false;
+      if (!MapUint32Uint32.Equals(other.MapUint32Uint32)) return false;
+      if (!MapUint64Uint64.Equals(other.MapUint64Uint64)) return false;
+      if (!MapSint32Sint32.Equals(other.MapSint32Sint32)) return false;
+      if (!MapSint64Sint64.Equals(other.MapSint64Sint64)) return false;
+      if (!MapFixed32Fixed32.Equals(other.MapFixed32Fixed32)) return false;
+      if (!MapFixed64Fixed64.Equals(other.MapFixed64Fixed64)) return false;
+      if (!MapSfixed32Sfixed32.Equals(other.MapSfixed32Sfixed32)) return false;
+      if (!MapSfixed64Sfixed64.Equals(other.MapSfixed64Sfixed64)) return false;
+      if (!MapInt32Float.Equals(other.MapInt32Float)) return false;
+      if (!MapInt32Double.Equals(other.MapInt32Double)) return false;
+      if (!MapBoolBool.Equals(other.MapBoolBool)) return false;
+      if (!MapInt32Enum.Equals(other.MapInt32Enum)) return false;
+      if (!MapInt32ForeignMessage.Equals(other.MapInt32ForeignMessage)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= MapInt32Int32.GetHashCode();
+      hash ^= MapInt64Int64.GetHashCode();
+      hash ^= MapUint32Uint32.GetHashCode();
+      hash ^= MapUint64Uint64.GetHashCode();
+      hash ^= MapSint32Sint32.GetHashCode();
+      hash ^= MapSint64Sint64.GetHashCode();
+      hash ^= MapFixed32Fixed32.GetHashCode();
+      hash ^= MapFixed64Fixed64.GetHashCode();
+      hash ^= MapSfixed32Sfixed32.GetHashCode();
+      hash ^= MapSfixed64Sfixed64.GetHashCode();
+      hash ^= MapInt32Float.GetHashCode();
+      hash ^= MapInt32Double.GetHashCode();
+      hash ^= MapBoolBool.GetHashCode();
+      hash ^= MapInt32Enum.GetHashCode();
+      hash ^= MapInt32ForeignMessage.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      mapInt32Int32_.WriteTo(output, _map_mapInt32Int32_codec);
+      mapInt64Int64_.WriteTo(output, _map_mapInt64Int64_codec);
+      mapUint32Uint32_.WriteTo(output, _map_mapUint32Uint32_codec);
+      mapUint64Uint64_.WriteTo(output, _map_mapUint64Uint64_codec);
+      mapSint32Sint32_.WriteTo(output, _map_mapSint32Sint32_codec);
+      mapSint64Sint64_.WriteTo(output, _map_mapSint64Sint64_codec);
+      mapFixed32Fixed32_.WriteTo(output, _map_mapFixed32Fixed32_codec);
+      mapFixed64Fixed64_.WriteTo(output, _map_mapFixed64Fixed64_codec);
+      mapSfixed32Sfixed32_.WriteTo(output, _map_mapSfixed32Sfixed32_codec);
+      mapSfixed64Sfixed64_.WriteTo(output, _map_mapSfixed64Sfixed64_codec);
+      mapInt32Float_.WriteTo(output, _map_mapInt32Float_codec);
+      mapInt32Double_.WriteTo(output, _map_mapInt32Double_codec);
+      mapBoolBool_.WriteTo(output, _map_mapBoolBool_codec);
+      mapInt32Enum_.WriteTo(output, _map_mapInt32Enum_codec);
+      mapInt32ForeignMessage_.WriteTo(output, _map_mapInt32ForeignMessage_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += mapInt32Int32_.CalculateSize(_map_mapInt32Int32_codec);
+      size += mapInt64Int64_.CalculateSize(_map_mapInt64Int64_codec);
+      size += mapUint32Uint32_.CalculateSize(_map_mapUint32Uint32_codec);
+      size += mapUint64Uint64_.CalculateSize(_map_mapUint64Uint64_codec);
+      size += mapSint32Sint32_.CalculateSize(_map_mapSint32Sint32_codec);
+      size += mapSint64Sint64_.CalculateSize(_map_mapSint64Sint64_codec);
+      size += mapFixed32Fixed32_.CalculateSize(_map_mapFixed32Fixed32_codec);
+      size += mapFixed64Fixed64_.CalculateSize(_map_mapFixed64Fixed64_codec);
+      size += mapSfixed32Sfixed32_.CalculateSize(_map_mapSfixed32Sfixed32_codec);
+      size += mapSfixed64Sfixed64_.CalculateSize(_map_mapSfixed64Sfixed64_codec);
+      size += mapInt32Float_.CalculateSize(_map_mapInt32Float_codec);
+      size += mapInt32Double_.CalculateSize(_map_mapInt32Double_codec);
+      size += mapBoolBool_.CalculateSize(_map_mapBoolBool_codec);
+      size += mapInt32Enum_.CalculateSize(_map_mapInt32Enum_codec);
+      size += mapInt32ForeignMessage_.CalculateSize(_map_mapInt32ForeignMessage_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestArenaMap other) {
+      if (other == null) {
+        return;
+      }
+      mapInt32Int32_.Add(other.mapInt32Int32_);
+      mapInt64Int64_.Add(other.mapInt64Int64_);
+      mapUint32Uint32_.Add(other.mapUint32Uint32_);
+      mapUint64Uint64_.Add(other.mapUint64Uint64_);
+      mapSint32Sint32_.Add(other.mapSint32Sint32_);
+      mapSint64Sint64_.Add(other.mapSint64Sint64_);
+      mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
+      mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
+      mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
+      mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
+      mapInt32Float_.Add(other.mapInt32Float_);
+      mapInt32Double_.Add(other.mapInt32Double_);
+      mapBoolBool_.Add(other.mapBoolBool_);
+      mapInt32Enum_.Add(other.mapInt32Enum_);
+      mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            mapInt32Int32_.AddEntriesFrom(input, _map_mapInt32Int32_codec);
+            break;
+          }
+          case 18: {
+            mapInt64Int64_.AddEntriesFrom(input, _map_mapInt64Int64_codec);
+            break;
+          }
+          case 26: {
+            mapUint32Uint32_.AddEntriesFrom(input, _map_mapUint32Uint32_codec);
+            break;
+          }
+          case 34: {
+            mapUint64Uint64_.AddEntriesFrom(input, _map_mapUint64Uint64_codec);
+            break;
+          }
+          case 42: {
+            mapSint32Sint32_.AddEntriesFrom(input, _map_mapSint32Sint32_codec);
+            break;
+          }
+          case 50: {
+            mapSint64Sint64_.AddEntriesFrom(input, _map_mapSint64Sint64_codec);
+            break;
+          }
+          case 58: {
+            mapFixed32Fixed32_.AddEntriesFrom(input, _map_mapFixed32Fixed32_codec);
+            break;
+          }
+          case 66: {
+            mapFixed64Fixed64_.AddEntriesFrom(input, _map_mapFixed64Fixed64_codec);
+            break;
+          }
+          case 74: {
+            mapSfixed32Sfixed32_.AddEntriesFrom(input, _map_mapSfixed32Sfixed32_codec);
+            break;
+          }
+          case 82: {
+            mapSfixed64Sfixed64_.AddEntriesFrom(input, _map_mapSfixed64Sfixed64_codec);
+            break;
+          }
+          case 90: {
+            mapInt32Float_.AddEntriesFrom(input, _map_mapInt32Float_codec);
+            break;
+          }
+          case 98: {
+            mapInt32Double_.AddEntriesFrom(input, _map_mapInt32Double_codec);
+            break;
+          }
+          case 106: {
+            mapBoolBool_.AddEntriesFrom(input, _map_mapBoolBool_codec);
+            break;
+          }
+          case 114: {
+            mapInt32Enum_.AddEntriesFrom(input, _map_mapInt32Enum_codec);
+            break;
+          }
+          case 122: {
+            mapInt32ForeignMessage_.AddEntriesFrom(input, _map_mapInt32ForeignMessage_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Previously, message containing enum called Type cannot be used as value of
+  ///  map field.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class MessageContainingEnumCalledType : pb::IMessage<MessageContainingEnumCalledType> {
+    private static readonly pb::MessageParser<MessageContainingEnumCalledType> _parser = new pb::MessageParser<MessageContainingEnumCalledType>(() => new MessageContainingEnumCalledType());
+    public static pb::MessageParser<MessageContainingEnumCalledType> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MessageContainingEnumCalledType() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MessageContainingEnumCalledType(MessageContainingEnumCalledType other) : this() {
+      type_ = other.type_.Clone();
+    }
+
+    public MessageContainingEnumCalledType Clone() {
+      return new MessageContainingEnumCalledType(this);
+    }
+
+    /// <summary>Field number for the "type" field.</summary>
+    public const int TypeFieldNumber = 1;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType>.Codec _map_type_codec
+        = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Parser), 10);
+    private readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType> type_ = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType>();
+    public pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType> Type {
+      get { return type_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MessageContainingEnumCalledType);
+    }
+
+    public bool Equals(MessageContainingEnumCalledType other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!Type.Equals(other.Type)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= Type.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      type_.WriteTo(output, _map_type_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += type_.CalculateSize(_map_type_codec);
+      return size;
+    }
+
+    public void MergeFrom(MessageContainingEnumCalledType other) {
+      if (other == null) {
+        return;
+      }
+      type_.Add(other.type_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            type_.AddEntriesFrom(input, _map_type_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the MessageContainingEnumCalledType message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum Type {
+        [pbr::OriginalName("TYPE_FOO")] Foo = 0,
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Previously, message cannot contain map field called "entry".
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class MessageContainingMapCalledEntry : pb::IMessage<MessageContainingMapCalledEntry> {
+    private static readonly pb::MessageParser<MessageContainingMapCalledEntry> _parser = new pb::MessageParser<MessageContainingMapCalledEntry>(() => new MessageContainingMapCalledEntry());
+    public static pb::MessageParser<MessageContainingMapCalledEntry> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MessageContainingMapCalledEntry() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MessageContainingMapCalledEntry(MessageContainingMapCalledEntry other) : this() {
+      entry_ = other.entry_.Clone();
+    }
+
+    public MessageContainingMapCalledEntry Clone() {
+      return new MessageContainingMapCalledEntry(this);
+    }
+
+    /// <summary>Field number for the "entry" field.</summary>
+    public const int EntryFieldNumber = 1;
+    private static readonly pbc::MapField<int, int>.Codec _map_entry_codec
+        = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
+    private readonly pbc::MapField<int, int> entry_ = new pbc::MapField<int, int>();
+    public pbc::MapField<int, int> Entry {
+      get { return entry_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MessageContainingMapCalledEntry);
+    }
+
+    public bool Equals(MessageContainingMapCalledEntry other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!Entry.Equals(other.Entry)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= Entry.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      entry_.WriteTo(output, _map_entry_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += entry_.CalculateSize(_map_entry_codec);
+      return size;
+    }
+
+    public void MergeFrom(MessageContainingMapCalledEntry other) {
+      if (other == null) {
+        return;
+      }
+      entry_.Add(other.entry_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            entry_.AddEntriesFrom(input, _map_entry_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
new file mode 100644
index 0000000..263e17c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
@@ -0,0 +1,161 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/unittest_import_proto3.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.TestProtos {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_import_proto3.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class UnittestImportProto3Reflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_import_proto3.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static UnittestImportProto3Reflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Cixnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3Byb3RvMy5wcm90",
+            "bxIYcHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0GjNnb29nbGUvcHJvdG9idWYv",
+            "dW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90bzMucHJvdG8iGgoNSW1wb3J0",
+            "TWVzc2FnZRIJCgFkGAEgASgFKlkKCkltcG9ydEVudW0SGwoXSU1QT1JUX0VO",
+            "VU1fVU5TUEVDSUZJRUQQABIOCgpJTVBPUlRfRk9PEAcSDgoKSU1QT1JUX0JB",
+            "UhAIEg4KCklNUE9SVF9CQVoQCUI8Chhjb20uZ29vZ2xlLnByb3RvYnVmLnRl",
+            "c3RIAfgBAaoCGkdvb2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zUABiBnByb3Rv",
+            "Mw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportPublicProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ImportEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.ImportMessage), global::Google.Protobuf.TestProtos.ImportMessage.Parser, new[]{ "D" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum ImportEnum {
+    [pbr::OriginalName("IMPORT_ENUM_UNSPECIFIED")] Unspecified = 0,
+    [pbr::OriginalName("IMPORT_FOO")] ImportFoo = 7,
+    [pbr::OriginalName("IMPORT_BAR")] ImportBar = 8,
+    [pbr::OriginalName("IMPORT_BAZ")] ImportBaz = 9,
+  }
+
+  #endregion
+
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ImportMessage : pb::IMessage<ImportMessage> {
+    private static readonly pb::MessageParser<ImportMessage> _parser = new pb::MessageParser<ImportMessage>(() => new ImportMessage());
+    public static pb::MessageParser<ImportMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ImportMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ImportMessage(ImportMessage other) : this() {
+      d_ = other.d_;
+    }
+
+    public ImportMessage Clone() {
+      return new ImportMessage(this);
+    }
+
+    /// <summary>Field number for the "d" field.</summary>
+    public const int DFieldNumber = 1;
+    private int d_;
+    public int D {
+      get { return d_; }
+      set {
+        d_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ImportMessage);
+    }
+
+    public bool Equals(ImportMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (D != other.D) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (D != 0) hash ^= D.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (D != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(D);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (D != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(D);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ImportMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.D != 0) {
+        D = other.D;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            D = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
new file mode 100644
index 0000000..b471a8c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
@@ -0,0 +1,147 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/unittest_import_public_proto3.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.TestProtos {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_import_public_proto3.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class UnittestImportPublicProto3Reflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_import_public_proto3.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static UnittestImportPublicProto3Reflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CjNnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90",
+            "bzMucHJvdG8SGHByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydCIgChNQdWJsaWNJ",
+            "bXBvcnRNZXNzYWdlEgkKAWUYASABKAVCNwoYY29tLmdvb2dsZS5wcm90b2J1",
+            "Zi50ZXN0qgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.PublicImportMessage), global::Google.Protobuf.TestProtos.PublicImportMessage.Parser, new[]{ "E" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class PublicImportMessage : pb::IMessage<PublicImportMessage> {
+    private static readonly pb::MessageParser<PublicImportMessage> _parser = new pb::MessageParser<PublicImportMessage>(() => new PublicImportMessage());
+    public static pb::MessageParser<PublicImportMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3Reflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public PublicImportMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public PublicImportMessage(PublicImportMessage other) : this() {
+      e_ = other.e_;
+    }
+
+    public PublicImportMessage Clone() {
+      return new PublicImportMessage(this);
+    }
+
+    /// <summary>Field number for the "e" field.</summary>
+    public const int EFieldNumber = 1;
+    private int e_;
+    public int E {
+      get { return e_; }
+      set {
+        e_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as PublicImportMessage);
+    }
+
+    public bool Equals(PublicImportMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (E != other.E) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (E != 0) hash ^= E.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (E != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(E);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (E != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(E);
+      }
+      return size;
+    }
+
+    public void MergeFrom(PublicImportMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.E != 0) {
+        E = other.E;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            E = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
new file mode 100644
index 0000000..7d4451b
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
@@ -0,0 +1,1569 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: unittest_issues.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace UnitTest.Issues.TestProtos {
+
+  /// <summary>Holder for reflection information generated from unittest_issues.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class UnittestIssuesReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for unittest_issues.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static UnittestIssuesReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "ChV1bml0dGVzdF9pc3N1ZXMucHJvdG8SD3VuaXR0ZXN0X2lzc3VlcyInCghJ",
+            "c3N1ZTMwNxobCgpOZXN0ZWRPbmNlGg0KC05lc3RlZFR3aWNlIrABChNOZWdh",
+            "dGl2ZUVudW1NZXNzYWdlEiwKBXZhbHVlGAEgASgOMh0udW5pdHRlc3RfaXNz",
+            "dWVzLk5lZ2F0aXZlRW51bRIxCgZ2YWx1ZXMYAiADKA4yHS51bml0dGVzdF9p",
+            "c3N1ZXMuTmVnYXRpdmVFbnVtQgIQABI4Cg1wYWNrZWRfdmFsdWVzGAMgAygO",
+            "Mh0udW5pdHRlc3RfaXNzdWVzLk5lZ2F0aXZlRW51bUICEAEiEQoPRGVwcmVj",
+            "YXRlZENoaWxkIrkCChdEZXByZWNhdGVkRmllbGRzTWVzc2FnZRIaCg5Qcmlt",
+            "aXRpdmVWYWx1ZRgBIAEoBUICGAESGgoOUHJpbWl0aXZlQXJyYXkYAiADKAVC",
+            "AhgBEjoKDE1lc3NhZ2VWYWx1ZRgDIAEoCzIgLnVuaXR0ZXN0X2lzc3Vlcy5E",
+            "ZXByZWNhdGVkQ2hpbGRCAhgBEjoKDE1lc3NhZ2VBcnJheRgEIAMoCzIgLnVu",
+            "aXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkQ2hpbGRCAhgBEjYKCUVudW1WYWx1",
+            "ZRgFIAEoDjIfLnVuaXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkRW51bUICGAES",
+            "NgoJRW51bUFycmF5GAYgAygOMh8udW5pdHRlc3RfaXNzdWVzLkRlcHJlY2F0",
+            "ZWRFbnVtQgIYASIZCglJdGVtRmllbGQSDAoEaXRlbRgBIAEoBSJECg1SZXNl",
+            "cnZlZE5hbWVzEg0KBXR5cGVzGAEgASgFEhIKCmRlc2NyaXB0b3IYAiABKAUa",
+            "EAoOU29tZU5lc3RlZFR5cGUioAEKFVRlc3RKc29uRmllbGRPcmRlcmluZxIT",
+            "CgtwbGFpbl9pbnQzMhgEIAEoBRITCglvMV9zdHJpbmcYAiABKAlIABISCghv",
+            "MV9pbnQzMhgFIAEoBUgAEhQKDHBsYWluX3N0cmluZxgBIAEoCRISCghvMl9p",
+            "bnQzMhgGIAEoBUgBEhMKCW8yX3N0cmluZxgDIAEoCUgBQgQKAm8xQgQKAm8y",
+            "IksKDFRlc3RKc29uTmFtZRIMCgRuYW1lGAEgASgJEhkKC2Rlc2NyaXB0aW9u",
+            "GAIgASgJUgRkZXNjEhIKBGd1aWQYAyABKAlSBGV4aWQqVQoMTmVnYXRpdmVF",
+            "bnVtEhYKEk5FR0FUSVZFX0VOVU1fWkVSTxAAEhYKCUZpdmVCZWxvdxD7////",
+            "//////8BEhUKCE1pbnVzT25lEP///////////wEqLgoORGVwcmVjYXRlZEVu",
+            "dW0SEwoPREVQUkVDQVRFRF9aRVJPEAASBwoDb25lEAFCH0gBqgIaVW5pdFRl",
+            "c3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307), global::UnitTest.Issues.TestProtos.Issue307.Parser, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Parser, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice.Parser, null, null, null, null)})}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NegativeEnumMessage), global::UnitTest.Issues.TestProtos.NegativeEnumMessage.Parser, new[]{ "Value", "Values", "PackedValues" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedChild), global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage), global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage.Parser, new[]{ "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ItemField), global::UnitTest.Issues.TestProtos.ItemField.Parser, new[]{ "Item" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames), global::UnitTest.Issues.TestProtos.ReservedNames.Parser, new[]{ "Types_", "Descriptor_" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType), global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType.Parser, null, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering), global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering.Parser, new[]{ "PlainInt32", "O1String", "O1Int32", "PlainString", "O2Int32", "O2String" }, new[]{ "O1", "O2" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonName), global::UnitTest.Issues.TestProtos.TestJsonName.Parser, new[]{ "Name", "Description", "Guid" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum NegativeEnum {
+    [pbr::OriginalName("NEGATIVE_ENUM_ZERO")] Zero = 0,
+    [pbr::OriginalName("FiveBelow")] FiveBelow = -5,
+    [pbr::OriginalName("MinusOne")] MinusOne = -1,
+  }
+
+  public enum DeprecatedEnum {
+    [pbr::OriginalName("DEPRECATED_ZERO")] DeprecatedZero = 0,
+    [pbr::OriginalName("one")] One = 1,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  Issue 307: when generating doubly-nested types, any references
+  ///  should be of the form A.Types.B.Types.C.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Issue307 : pb::IMessage<Issue307> {
+    private static readonly pb::MessageParser<Issue307> _parser = new pb::MessageParser<Issue307>(() => new Issue307());
+    public static pb::MessageParser<Issue307> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Issue307() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Issue307(Issue307 other) : this() {
+    }
+
+    public Issue307 Clone() {
+      return new Issue307(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Issue307);
+    }
+
+    public bool Equals(Issue307 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(Issue307 other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the Issue307 message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class NestedOnce : pb::IMessage<NestedOnce> {
+        private static readonly pb::MessageParser<NestedOnce> _parser = new pb::MessageParser<NestedOnce>(() => new NestedOnce());
+        public static pb::MessageParser<NestedOnce> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::UnitTest.Issues.TestProtos.Issue307.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NestedOnce() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NestedOnce(NestedOnce other) : this() {
+        }
+
+        public NestedOnce Clone() {
+          return new NestedOnce(this);
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NestedOnce);
+        }
+
+        public bool Equals(NestedOnce other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          return size;
+        }
+
+        public void MergeFrom(NestedOnce other) {
+          if (other == null) {
+            return;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+            }
+          }
+        }
+
+        #region Nested types
+        /// <summary>Container for nested types declared in the NestedOnce message type.</summary>
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        public static partial class Types {
+          [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+          public sealed partial class NestedTwice : pb::IMessage<NestedTwice> {
+            private static readonly pb::MessageParser<NestedTwice> _parser = new pb::MessageParser<NestedTwice>(() => new NestedTwice());
+            public static pb::MessageParser<NestedTwice> Parser { get { return _parser; } }
+
+            public static pbr::MessageDescriptor Descriptor {
+              get { return global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Descriptor.NestedTypes[0]; }
+            }
+
+            pbr::MessageDescriptor pb::IMessage.Descriptor {
+              get { return Descriptor; }
+            }
+
+            public NestedTwice() {
+              OnConstruction();
+            }
+
+            partial void OnConstruction();
+
+            public NestedTwice(NestedTwice other) : this() {
+            }
+
+            public NestedTwice Clone() {
+              return new NestedTwice(this);
+            }
+
+            public override bool Equals(object other) {
+              return Equals(other as NestedTwice);
+            }
+
+            public bool Equals(NestedTwice other) {
+              if (ReferenceEquals(other, null)) {
+                return false;
+              }
+              if (ReferenceEquals(other, this)) {
+                return true;
+              }
+              return true;
+            }
+
+            public override int GetHashCode() {
+              int hash = 1;
+              return hash;
+            }
+
+            public override string ToString() {
+              return pb::JsonFormatter.ToDiagnosticString(this);
+            }
+
+            public void WriteTo(pb::CodedOutputStream output) {
+            }
+
+            public int CalculateSize() {
+              int size = 0;
+              return size;
+            }
+
+            public void MergeFrom(NestedTwice other) {
+              if (other == null) {
+                return;
+              }
+            }
+
+            public void MergeFrom(pb::CodedInputStream input) {
+              uint tag;
+              while ((tag = input.ReadTag()) != 0) {
+                switch(tag) {
+                  default:
+                    input.SkipLastField();
+                    break;
+                }
+              }
+            }
+
+          }
+
+        }
+        #endregion
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class NegativeEnumMessage : pb::IMessage<NegativeEnumMessage> {
+    private static readonly pb::MessageParser<NegativeEnumMessage> _parser = new pb::MessageParser<NegativeEnumMessage>(() => new NegativeEnumMessage());
+    public static pb::MessageParser<NegativeEnumMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public NegativeEnumMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public NegativeEnumMessage(NegativeEnumMessage other) : this() {
+      value_ = other.value_;
+      values_ = other.values_.Clone();
+      packedValues_ = other.packedValues_.Clone();
+    }
+
+    public NegativeEnumMessage Clone() {
+      return new NegativeEnumMessage(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private global::UnitTest.Issues.TestProtos.NegativeEnum value_ = 0;
+    public global::UnitTest.Issues.TestProtos.NegativeEnum Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "values" field.</summary>
+    public const int ValuesFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.NegativeEnum> _repeated_values_codec
+        = pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::UnitTest.Issues.TestProtos.NegativeEnum) x);
+    private readonly pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum> values_ = new pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum>();
+    public pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum> Values {
+      get { return values_; }
+    }
+
+    /// <summary>Field number for the "packed_values" field.</summary>
+    public const int PackedValuesFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.NegativeEnum> _repeated_packedValues_codec
+        = pb::FieldCodec.ForEnum(26, x => (int) x, x => (global::UnitTest.Issues.TestProtos.NegativeEnum) x);
+    private readonly pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum> packedValues_ = new pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum>();
+    public pbc::RepeatedField<global::UnitTest.Issues.TestProtos.NegativeEnum> PackedValues {
+      get { return packedValues_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as NegativeEnumMessage);
+    }
+
+    public bool Equals(NegativeEnumMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      if(!values_.Equals(other.values_)) return false;
+      if(!packedValues_.Equals(other.packedValues_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0) hash ^= Value.GetHashCode();
+      hash ^= values_.GetHashCode();
+      hash ^= packedValues_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Value);
+      }
+      values_.WriteTo(output, _repeated_values_codec);
+      packedValues_.WriteTo(output, _repeated_packedValues_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Value);
+      }
+      size += values_.CalculateSize(_repeated_values_codec);
+      size += packedValues_.CalculateSize(_repeated_packedValues_codec);
+      return size;
+    }
+
+    public void MergeFrom(NegativeEnumMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0) {
+        Value = other.Value;
+      }
+      values_.Add(other.values_);
+      packedValues_.Add(other.packedValues_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            value_ = (global::UnitTest.Issues.TestProtos.NegativeEnum) input.ReadEnum();
+            break;
+          }
+          case 18:
+          case 16: {
+            values_.AddEntriesFrom(input, _repeated_values_codec);
+            break;
+          }
+          case 26:
+          case 24: {
+            packedValues_.AddEntriesFrom(input, _repeated_packedValues_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class DeprecatedChild : pb::IMessage<DeprecatedChild> {
+    private static readonly pb::MessageParser<DeprecatedChild> _parser = new pb::MessageParser<DeprecatedChild>(() => new DeprecatedChild());
+    public static pb::MessageParser<DeprecatedChild> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DeprecatedChild() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DeprecatedChild(DeprecatedChild other) : this() {
+    }
+
+    public DeprecatedChild Clone() {
+      return new DeprecatedChild(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DeprecatedChild);
+    }
+
+    public bool Equals(DeprecatedChild other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(DeprecatedChild other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class DeprecatedFieldsMessage : pb::IMessage<DeprecatedFieldsMessage> {
+    private static readonly pb::MessageParser<DeprecatedFieldsMessage> _parser = new pb::MessageParser<DeprecatedFieldsMessage>(() => new DeprecatedFieldsMessage());
+    public static pb::MessageParser<DeprecatedFieldsMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DeprecatedFieldsMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DeprecatedFieldsMessage(DeprecatedFieldsMessage other) : this() {
+      primitiveValue_ = other.primitiveValue_;
+      primitiveArray_ = other.primitiveArray_.Clone();
+      MessageValue = other.messageValue_ != null ? other.MessageValue.Clone() : null;
+      messageArray_ = other.messageArray_.Clone();
+      enumValue_ = other.enumValue_;
+      enumArray_ = other.enumArray_.Clone();
+    }
+
+    public DeprecatedFieldsMessage Clone() {
+      return new DeprecatedFieldsMessage(this);
+    }
+
+    /// <summary>Field number for the "PrimitiveValue" field.</summary>
+    public const int PrimitiveValueFieldNumber = 1;
+    private int primitiveValue_;
+    [global::System.ObsoleteAttribute()]
+    public int PrimitiveValue {
+      get { return primitiveValue_; }
+      set {
+        primitiveValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "PrimitiveArray" field.</summary>
+    public const int PrimitiveArrayFieldNumber = 2;
+    private static readonly pb::FieldCodec<int> _repeated_primitiveArray_codec
+        = pb::FieldCodec.ForInt32(18);
+    private readonly pbc::RepeatedField<int> primitiveArray_ = new pbc::RepeatedField<int>();
+    [global::System.ObsoleteAttribute()]
+    public pbc::RepeatedField<int> PrimitiveArray {
+      get { return primitiveArray_; }
+    }
+
+    /// <summary>Field number for the "MessageValue" field.</summary>
+    public const int MessageValueFieldNumber = 3;
+    private global::UnitTest.Issues.TestProtos.DeprecatedChild messageValue_;
+    [global::System.ObsoleteAttribute()]
+    public global::UnitTest.Issues.TestProtos.DeprecatedChild MessageValue {
+      get { return messageValue_; }
+      set {
+        messageValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "MessageArray" field.</summary>
+    public const int MessageArrayFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.DeprecatedChild> _repeated_messageArray_codec
+        = pb::FieldCodec.ForMessage(34, global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser);
+    private readonly pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedChild> messageArray_ = new pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedChild>();
+    [global::System.ObsoleteAttribute()]
+    public pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedChild> MessageArray {
+      get { return messageArray_; }
+    }
+
+    /// <summary>Field number for the "EnumValue" field.</summary>
+    public const int EnumValueFieldNumber = 5;
+    private global::UnitTest.Issues.TestProtos.DeprecatedEnum enumValue_ = 0;
+    [global::System.ObsoleteAttribute()]
+    public global::UnitTest.Issues.TestProtos.DeprecatedEnum EnumValue {
+      get { return enumValue_; }
+      set {
+        enumValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "EnumArray" field.</summary>
+    public const int EnumArrayFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.DeprecatedEnum> _repeated_enumArray_codec
+        = pb::FieldCodec.ForEnum(50, x => (int) x, x => (global::UnitTest.Issues.TestProtos.DeprecatedEnum) x);
+    private readonly pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedEnum> enumArray_ = new pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedEnum>();
+    [global::System.ObsoleteAttribute()]
+    public pbc::RepeatedField<global::UnitTest.Issues.TestProtos.DeprecatedEnum> EnumArray {
+      get { return enumArray_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DeprecatedFieldsMessage);
+    }
+
+    public bool Equals(DeprecatedFieldsMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (PrimitiveValue != other.PrimitiveValue) return false;
+      if(!primitiveArray_.Equals(other.primitiveArray_)) return false;
+      if (!object.Equals(MessageValue, other.MessageValue)) return false;
+      if(!messageArray_.Equals(other.messageArray_)) return false;
+      if (EnumValue != other.EnumValue) return false;
+      if(!enumArray_.Equals(other.enumArray_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (PrimitiveValue != 0) hash ^= PrimitiveValue.GetHashCode();
+      hash ^= primitiveArray_.GetHashCode();
+      if (messageValue_ != null) hash ^= MessageValue.GetHashCode();
+      hash ^= messageArray_.GetHashCode();
+      if (EnumValue != 0) hash ^= EnumValue.GetHashCode();
+      hash ^= enumArray_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (PrimitiveValue != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(PrimitiveValue);
+      }
+      primitiveArray_.WriteTo(output, _repeated_primitiveArray_codec);
+      if (messageValue_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(MessageValue);
+      }
+      messageArray_.WriteTo(output, _repeated_messageArray_codec);
+      if (EnumValue != 0) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) EnumValue);
+      }
+      enumArray_.WriteTo(output, _repeated_enumArray_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (PrimitiveValue != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(PrimitiveValue);
+      }
+      size += primitiveArray_.CalculateSize(_repeated_primitiveArray_codec);
+      if (messageValue_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(MessageValue);
+      }
+      size += messageArray_.CalculateSize(_repeated_messageArray_codec);
+      if (EnumValue != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) EnumValue);
+      }
+      size += enumArray_.CalculateSize(_repeated_enumArray_codec);
+      return size;
+    }
+
+    public void MergeFrom(DeprecatedFieldsMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.PrimitiveValue != 0) {
+        PrimitiveValue = other.PrimitiveValue;
+      }
+      primitiveArray_.Add(other.primitiveArray_);
+      if (other.messageValue_ != null) {
+        if (messageValue_ == null) {
+          messageValue_ = new global::UnitTest.Issues.TestProtos.DeprecatedChild();
+        }
+        MessageValue.MergeFrom(other.MessageValue);
+      }
+      messageArray_.Add(other.messageArray_);
+      if (other.EnumValue != 0) {
+        EnumValue = other.EnumValue;
+      }
+      enumArray_.Add(other.enumArray_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            PrimitiveValue = input.ReadInt32();
+            break;
+          }
+          case 18:
+          case 16: {
+            primitiveArray_.AddEntriesFrom(input, _repeated_primitiveArray_codec);
+            break;
+          }
+          case 26: {
+            if (messageValue_ == null) {
+              messageValue_ = new global::UnitTest.Issues.TestProtos.DeprecatedChild();
+            }
+            input.ReadMessage(messageValue_);
+            break;
+          }
+          case 34: {
+            messageArray_.AddEntriesFrom(input, _repeated_messageArray_codec);
+            break;
+          }
+          case 40: {
+            enumValue_ = (global::UnitTest.Issues.TestProtos.DeprecatedEnum) input.ReadEnum();
+            break;
+          }
+          case 50:
+          case 48: {
+            enumArray_.AddEntriesFrom(input, _repeated_enumArray_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ItemField : pb::IMessage<ItemField> {
+    private static readonly pb::MessageParser<ItemField> _parser = new pb::MessageParser<ItemField>(() => new ItemField());
+    public static pb::MessageParser<ItemField> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ItemField() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ItemField(ItemField other) : this() {
+      item_ = other.item_;
+    }
+
+    public ItemField Clone() {
+      return new ItemField(this);
+    }
+
+    /// <summary>Field number for the "item" field.</summary>
+    public const int ItemFieldNumber = 1;
+    private int item_;
+    public int Item {
+      get { return item_; }
+      set {
+        item_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ItemField);
+    }
+
+    public bool Equals(ItemField other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Item != other.Item) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Item != 0) hash ^= Item.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Item != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Item);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Item != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Item);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ItemField other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Item != 0) {
+        Item = other.Item;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Item = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ReservedNames : pb::IMessage<ReservedNames> {
+    private static readonly pb::MessageParser<ReservedNames> _parser = new pb::MessageParser<ReservedNames>(() => new ReservedNames());
+    public static pb::MessageParser<ReservedNames> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ReservedNames() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ReservedNames(ReservedNames other) : this() {
+      types_ = other.types_;
+      descriptor_ = other.descriptor_;
+    }
+
+    public ReservedNames Clone() {
+      return new ReservedNames(this);
+    }
+
+    /// <summary>Field number for the "types" field.</summary>
+    public const int Types_FieldNumber = 1;
+    private int types_;
+    public int Types_ {
+      get { return types_; }
+      set {
+        types_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "descriptor" field.</summary>
+    public const int Descriptor_FieldNumber = 2;
+    private int descriptor_;
+    public int Descriptor_ {
+      get { return descriptor_; }
+      set {
+        descriptor_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ReservedNames);
+    }
+
+    public bool Equals(ReservedNames other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Types_ != other.Types_) return false;
+      if (Descriptor_ != other.Descriptor_) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Types_ != 0) hash ^= Types_.GetHashCode();
+      if (Descriptor_ != 0) hash ^= Descriptor_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Types_ != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Types_);
+      }
+      if (Descriptor_ != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Descriptor_);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Types_ != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Types_);
+      }
+      if (Descriptor_ != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Descriptor_);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ReservedNames other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Types_ != 0) {
+        Types_ = other.Types_;
+      }
+      if (other.Descriptor_ != 0) {
+        Descriptor_ = other.Descriptor_;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Types_ = input.ReadInt32();
+            break;
+          }
+          case 16: {
+            Descriptor_ = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the ReservedNames message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  Force a nested type called Types
+      /// </summary>
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class SomeNestedType : pb::IMessage<SomeNestedType> {
+        private static readonly pb::MessageParser<SomeNestedType> _parser = new pb::MessageParser<SomeNestedType>(() => new SomeNestedType());
+        public static pb::MessageParser<SomeNestedType> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::UnitTest.Issues.TestProtos.ReservedNames.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public SomeNestedType() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public SomeNestedType(SomeNestedType other) : this() {
+        }
+
+        public SomeNestedType Clone() {
+          return new SomeNestedType(this);
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as SomeNestedType);
+        }
+
+        public bool Equals(SomeNestedType other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          return size;
+        }
+
+        public void MergeFrom(SomeNestedType other) {
+          if (other == null) {
+            return;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  These fields are deliberately not declared in numeric
+  ///  order, and the oneof fields aren't contiguous either.
+  ///  This allows for reasonably robust tests of JSON output
+  ///  ordering.
+  ///  TestFieldOrderings in unittest_proto3.proto is similar,
+  ///  but doesn't include oneofs.
+  ///  TODO: Consider adding oneofs to TestFieldOrderings, although
+  ///  that will require fixing other tests in multiple platforms.
+  ///  Alternatively, consider just adding this to
+  ///  unittest_proto3.proto if multiple platforms want it.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestJsonFieldOrdering : pb::IMessage<TestJsonFieldOrdering> {
+    private static readonly pb::MessageParser<TestJsonFieldOrdering> _parser = new pb::MessageParser<TestJsonFieldOrdering>(() => new TestJsonFieldOrdering());
+    public static pb::MessageParser<TestJsonFieldOrdering> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestJsonFieldOrdering() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestJsonFieldOrdering(TestJsonFieldOrdering other) : this() {
+      plainInt32_ = other.plainInt32_;
+      plainString_ = other.plainString_;
+      switch (other.O1Case) {
+        case O1OneofCase.O1String:
+          O1String = other.O1String;
+          break;
+        case O1OneofCase.O1Int32:
+          O1Int32 = other.O1Int32;
+          break;
+      }
+
+      switch (other.O2Case) {
+        case O2OneofCase.O2Int32:
+          O2Int32 = other.O2Int32;
+          break;
+        case O2OneofCase.O2String:
+          O2String = other.O2String;
+          break;
+      }
+
+    }
+
+    public TestJsonFieldOrdering Clone() {
+      return new TestJsonFieldOrdering(this);
+    }
+
+    /// <summary>Field number for the "plain_int32" field.</summary>
+    public const int PlainInt32FieldNumber = 4;
+    private int plainInt32_;
+    public int PlainInt32 {
+      get { return plainInt32_; }
+      set {
+        plainInt32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "o1_string" field.</summary>
+    public const int O1StringFieldNumber = 2;
+    public string O1String {
+      get { return o1Case_ == O1OneofCase.O1String ? (string) o1_ : ""; }
+      set {
+        o1_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        o1Case_ = O1OneofCase.O1String;
+      }
+    }
+
+    /// <summary>Field number for the "o1_int32" field.</summary>
+    public const int O1Int32FieldNumber = 5;
+    public int O1Int32 {
+      get { return o1Case_ == O1OneofCase.O1Int32 ? (int) o1_ : 0; }
+      set {
+        o1_ = value;
+        o1Case_ = O1OneofCase.O1Int32;
+      }
+    }
+
+    /// <summary>Field number for the "plain_string" field.</summary>
+    public const int PlainStringFieldNumber = 1;
+    private string plainString_ = "";
+    public string PlainString {
+      get { return plainString_; }
+      set {
+        plainString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "o2_int32" field.</summary>
+    public const int O2Int32FieldNumber = 6;
+    public int O2Int32 {
+      get { return o2Case_ == O2OneofCase.O2Int32 ? (int) o2_ : 0; }
+      set {
+        o2_ = value;
+        o2Case_ = O2OneofCase.O2Int32;
+      }
+    }
+
+    /// <summary>Field number for the "o2_string" field.</summary>
+    public const int O2StringFieldNumber = 3;
+    public string O2String {
+      get { return o2Case_ == O2OneofCase.O2String ? (string) o2_ : ""; }
+      set {
+        o2_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        o2Case_ = O2OneofCase.O2String;
+      }
+    }
+
+    private object o1_;
+    /// <summary>Enum of possible cases for the "o1" oneof.</summary>
+    public enum O1OneofCase {
+      None = 0,
+      O1String = 2,
+      O1Int32 = 5,
+    }
+    private O1OneofCase o1Case_ = O1OneofCase.None;
+    public O1OneofCase O1Case {
+      get { return o1Case_; }
+    }
+
+    public void ClearO1() {
+      o1Case_ = O1OneofCase.None;
+      o1_ = null;
+    }
+
+    private object o2_;
+    /// <summary>Enum of possible cases for the "o2" oneof.</summary>
+    public enum O2OneofCase {
+      None = 0,
+      O2Int32 = 6,
+      O2String = 3,
+    }
+    private O2OneofCase o2Case_ = O2OneofCase.None;
+    public O2OneofCase O2Case {
+      get { return o2Case_; }
+    }
+
+    public void ClearO2() {
+      o2Case_ = O2OneofCase.None;
+      o2_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestJsonFieldOrdering);
+    }
+
+    public bool Equals(TestJsonFieldOrdering other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (PlainInt32 != other.PlainInt32) return false;
+      if (O1String != other.O1String) return false;
+      if (O1Int32 != other.O1Int32) return false;
+      if (PlainString != other.PlainString) return false;
+      if (O2Int32 != other.O2Int32) return false;
+      if (O2String != other.O2String) return false;
+      if (O1Case != other.O1Case) return false;
+      if (O2Case != other.O2Case) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (PlainInt32 != 0) hash ^= PlainInt32.GetHashCode();
+      if (o1Case_ == O1OneofCase.O1String) hash ^= O1String.GetHashCode();
+      if (o1Case_ == O1OneofCase.O1Int32) hash ^= O1Int32.GetHashCode();
+      if (PlainString.Length != 0) hash ^= PlainString.GetHashCode();
+      if (o2Case_ == O2OneofCase.O2Int32) hash ^= O2Int32.GetHashCode();
+      if (o2Case_ == O2OneofCase.O2String) hash ^= O2String.GetHashCode();
+      hash ^= (int) o1Case_;
+      hash ^= (int) o2Case_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (PlainString.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(PlainString);
+      }
+      if (o1Case_ == O1OneofCase.O1String) {
+        output.WriteRawTag(18);
+        output.WriteString(O1String);
+      }
+      if (o2Case_ == O2OneofCase.O2String) {
+        output.WriteRawTag(26);
+        output.WriteString(O2String);
+      }
+      if (PlainInt32 != 0) {
+        output.WriteRawTag(32);
+        output.WriteInt32(PlainInt32);
+      }
+      if (o1Case_ == O1OneofCase.O1Int32) {
+        output.WriteRawTag(40);
+        output.WriteInt32(O1Int32);
+      }
+      if (o2Case_ == O2OneofCase.O2Int32) {
+        output.WriteRawTag(48);
+        output.WriteInt32(O2Int32);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (PlainInt32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlainInt32);
+      }
+      if (o1Case_ == O1OneofCase.O1String) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(O1String);
+      }
+      if (o1Case_ == O1OneofCase.O1Int32) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(O1Int32);
+      }
+      if (PlainString.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(PlainString);
+      }
+      if (o2Case_ == O2OneofCase.O2Int32) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(O2Int32);
+      }
+      if (o2Case_ == O2OneofCase.O2String) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(O2String);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestJsonFieldOrdering other) {
+      if (other == null) {
+        return;
+      }
+      if (other.PlainInt32 != 0) {
+        PlainInt32 = other.PlainInt32;
+      }
+      if (other.PlainString.Length != 0) {
+        PlainString = other.PlainString;
+      }
+      switch (other.O1Case) {
+        case O1OneofCase.O1String:
+          O1String = other.O1String;
+          break;
+        case O1OneofCase.O1Int32:
+          O1Int32 = other.O1Int32;
+          break;
+      }
+
+      switch (other.O2Case) {
+        case O2OneofCase.O2Int32:
+          O2Int32 = other.O2Int32;
+          break;
+        case O2OneofCase.O2String:
+          O2String = other.O2String;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            PlainString = input.ReadString();
+            break;
+          }
+          case 18: {
+            O1String = input.ReadString();
+            break;
+          }
+          case 26: {
+            O2String = input.ReadString();
+            break;
+          }
+          case 32: {
+            PlainInt32 = input.ReadInt32();
+            break;
+          }
+          case 40: {
+            O1Int32 = input.ReadInt32();
+            break;
+          }
+          case 48: {
+            O2Int32 = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestJsonName : pb::IMessage<TestJsonName> {
+    private static readonly pb::MessageParser<TestJsonName> _parser = new pb::MessageParser<TestJsonName>(() => new TestJsonName());
+    public static pb::MessageParser<TestJsonName> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestJsonName() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestJsonName(TestJsonName other) : this() {
+      name_ = other.name_;
+      description_ = other.description_;
+      guid_ = other.guid_;
+    }
+
+    public TestJsonName Clone() {
+      return new TestJsonName(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  Message for testing the effects for of the json_name option
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "description" field.</summary>
+    public const int DescriptionFieldNumber = 2;
+    private string description_ = "";
+    public string Description {
+      get { return description_; }
+      set {
+        description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "guid" field.</summary>
+    public const int GuidFieldNumber = 3;
+    private string guid_ = "";
+    public string Guid {
+      get { return guid_; }
+      set {
+        guid_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestJsonName);
+    }
+
+    public bool Equals(TestJsonName other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Description != other.Description) return false;
+      if (Guid != other.Guid) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Description.Length != 0) hash ^= Description.GetHashCode();
+      if (Guid.Length != 0) hash ^= Guid.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Description.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Description);
+      }
+      if (Guid.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Guid);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Description.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Description);
+      }
+      if (Guid.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Guid);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestJsonName other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Description.Length != 0) {
+        Description = other.Description;
+      }
+      if (other.Guid.Length != 0) {
+        Guid = other.Guid;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Description = input.ReadString();
+            break;
+          }
+          case 26: {
+            Guid = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
new file mode 100644
index 0000000..b8d159b
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
@@ -0,0 +1,6064 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/unittest_proto3.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.TestProtos {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_proto3.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class UnittestProto3Reflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_proto3.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static UnittestProto3Reflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiVnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfcHJvdG8zLnByb3RvEhFwcm90",
+            "b2J1Zl91bml0dGVzdBosZ29vZ2xlL3Byb3RvYnVmL3VuaXR0ZXN0X2ltcG9y",
+            "dF9wcm90bzMucHJvdG8i8A8KDFRlc3RBbGxUeXBlcxIUCgxzaW5nbGVfaW50",
+            "MzIYASABKAUSFAoMc2luZ2xlX2ludDY0GAIgASgDEhUKDXNpbmdsZV91aW50",
+            "MzIYAyABKA0SFQoNc2luZ2xlX3VpbnQ2NBgEIAEoBBIVCg1zaW5nbGVfc2lu",
+            "dDMyGAUgASgREhUKDXNpbmdsZV9zaW50NjQYBiABKBISFgoOc2luZ2xlX2Zp",
+            "eGVkMzIYByABKAcSFgoOc2luZ2xlX2ZpeGVkNjQYCCABKAYSFwoPc2luZ2xl",
+            "X3NmaXhlZDMyGAkgASgPEhcKD3NpbmdsZV9zZml4ZWQ2NBgKIAEoEBIUCgxz",
+            "aW5nbGVfZmxvYXQYCyABKAISFQoNc2luZ2xlX2RvdWJsZRgMIAEoARITCgtz",
+            "aW5nbGVfYm9vbBgNIAEoCBIVCg1zaW5nbGVfc3RyaW5nGA4gASgJEhQKDHNp",
+            "bmdsZV9ieXRlcxgPIAEoDBJMChVzaW5nbGVfbmVzdGVkX21lc3NhZ2UYEiAB",
+            "KAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVz",
+            "c2FnZRJBChZzaW5nbGVfZm9yZWlnbl9tZXNzYWdlGBMgASgLMiEucHJvdG9i",
+            "dWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USRgoVc2luZ2xlX2ltcG9ydF9t",
+            "ZXNzYWdlGBQgASgLMicucHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9y",
+            "dE1lc3NhZ2USRgoSc2luZ2xlX25lc3RlZF9lbnVtGBUgASgOMioucHJvdG9i",
+            "dWZfdW5pdHRlc3QuVGVzdEFsbFR5cGVzLk5lc3RlZEVudW0SOwoTc2luZ2xl",
+            "X2ZvcmVpZ25fZW51bRgWIAEoDjIeLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVp",
+            "Z25FbnVtEkAKEnNpbmdsZV9pbXBvcnRfZW51bRgXIAEoDjIkLnByb3RvYnVm",
+            "X3VuaXR0ZXN0X2ltcG9ydC5JbXBvcnRFbnVtElMKHHNpbmdsZV9wdWJsaWNf",
+            "aW1wb3J0X21lc3NhZ2UYGiABKAsyLS5wcm90b2J1Zl91bml0dGVzdF9pbXBv",
+            "cnQuUHVibGljSW1wb3J0TWVzc2FnZRIWCg5yZXBlYXRlZF9pbnQzMhgfIAMo",
+            "BRIWCg5yZXBlYXRlZF9pbnQ2NBggIAMoAxIXCg9yZXBlYXRlZF91aW50MzIY",
+            "ISADKA0SFwoPcmVwZWF0ZWRfdWludDY0GCIgAygEEhcKD3JlcGVhdGVkX3Np",
+            "bnQzMhgjIAMoERIXCg9yZXBlYXRlZF9zaW50NjQYJCADKBISGAoQcmVwZWF0",
+            "ZWRfZml4ZWQzMhglIAMoBxIYChByZXBlYXRlZF9maXhlZDY0GCYgAygGEhkK",
+            "EXJlcGVhdGVkX3NmaXhlZDMyGCcgAygPEhkKEXJlcGVhdGVkX3NmaXhlZDY0",
+            "GCggAygQEhYKDnJlcGVhdGVkX2Zsb2F0GCkgAygCEhcKD3JlcGVhdGVkX2Rv",
+            "dWJsZRgqIAMoARIVCg1yZXBlYXRlZF9ib29sGCsgAygIEhcKD3JlcGVhdGVk",
+            "X3N0cmluZxgsIAMoCRIWCg5yZXBlYXRlZF9ieXRlcxgtIAMoDBJOChdyZXBl",
+            "YXRlZF9uZXN0ZWRfbWVzc2FnZRgwIAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0",
+            "LlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlEkMKGHJlcGVhdGVkX2ZvcmVp",
+            "Z25fbWVzc2FnZRgxIAMoCzIhLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVpZ25N",
+            "ZXNzYWdlEkgKF3JlcGVhdGVkX2ltcG9ydF9tZXNzYWdlGDIgAygLMicucHJv",
+            "dG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9ydE1lc3NhZ2USSAoUcmVwZWF0",
+            "ZWRfbmVzdGVkX2VudW0YMyADKA4yKi5wcm90b2J1Zl91bml0dGVzdC5UZXN0",
+            "QWxsVHlwZXMuTmVzdGVkRW51bRI9ChVyZXBlYXRlZF9mb3JlaWduX2VudW0Y",
+            "NCADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bRJCChRyZXBl",
+            "YXRlZF9pbXBvcnRfZW51bRg1IAMoDjIkLnByb3RvYnVmX3VuaXR0ZXN0X2lt",
+            "cG9ydC5JbXBvcnRFbnVtElUKHnJlcGVhdGVkX3B1YmxpY19pbXBvcnRfbWVz",
+            "c2FnZRg2IAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5QdWJsaWNJ",
+            "bXBvcnRNZXNzYWdlEhYKDG9uZW9mX3VpbnQzMhhvIAEoDUgAEk0KFG9uZW9m",
+            "X25lc3RlZF9tZXNzYWdlGHAgASgLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVz",
+            "dEFsbFR5cGVzLk5lc3RlZE1lc3NhZ2VIABIWCgxvbmVvZl9zdHJpbmcYcSAB",
+            "KAlIABIVCgtvbmVvZl9ieXRlcxhyIAEoDEgAGhsKDU5lc3RlZE1lc3NhZ2US",
+            "CgoCYmIYASABKAUiVgoKTmVzdGVkRW51bRIbChdORVNURURfRU5VTV9VTlNQ",
+            "RUNJRklFRBAAEgcKA0ZPTxABEgcKA0JBUhACEgcKA0JBWhADEhAKA05FRxD/",
+            "//////////8BQg0KC29uZW9mX2ZpZWxkIrsBChJOZXN0ZWRUZXN0QWxsVHlw",
+            "ZXMSNAoFY2hpbGQYASABKAsyJS5wcm90b2J1Zl91bml0dGVzdC5OZXN0ZWRU",
+            "ZXN0QWxsVHlwZXMSMAoHcGF5bG9hZBgCIAEoCzIfLnByb3RvYnVmX3VuaXR0",
+            "ZXN0LlRlc3RBbGxUeXBlcxI9Cg5yZXBlYXRlZF9jaGlsZBgDIAMoCzIlLnBy",
+            "b3RvYnVmX3VuaXR0ZXN0Lk5lc3RlZFRlc3RBbGxUeXBlcyI0ChRUZXN0RGVw",
+            "cmVjYXRlZEZpZWxkcxIcChBkZXByZWNhdGVkX2ludDMyGAEgASgFQgIYASIb",
+            "Cg5Gb3JlaWduTWVzc2FnZRIJCgFjGAEgASgFIjAKElRlc3RSZXNlcnZlZEZp",
+            "ZWxkc0oECAIQA0oECA8QEEoECAkQDFIDYmFyUgNiYXoiWgoRVGVzdEZvcmVp",
+            "Z25OZXN0ZWQSRQoOZm9yZWlnbl9uZXN0ZWQYASABKAsyLS5wcm90b2J1Zl91",
+            "bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZSI0ChhUZXN0UmVh",
+            "bGx5TGFyZ2VUYWdOdW1iZXISCQoBYRgBIAEoBRINCgJiYhj///9/IAEoBSJV",
+            "ChRUZXN0UmVjdXJzaXZlTWVzc2FnZRIyCgFhGAEgASgLMicucHJvdG9idWZf",
+            "dW5pdHRlc3QuVGVzdFJlY3Vyc2l2ZU1lc3NhZ2USCQoBaRgCIAEoBSJLChRU",
+            "ZXN0TXV0dWFsUmVjdXJzaW9uQRIzCgJiYhgBIAEoCzInLnByb3RvYnVmX3Vu",
+            "aXR0ZXN0LlRlc3RNdXR1YWxSZWN1cnNpb25CImIKFFRlc3RNdXR1YWxSZWN1",
+            "cnNpb25CEjIKAWEYASABKAsyJy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TXV0",
+            "dWFsUmVjdXJzaW9uQRIWCg5vcHRpb25hbF9pbnQzMhgCIAEoBSLrAgoXVGVz",
+            "dENhbWVsQ2FzZUZpZWxkTmFtZXMSFgoOUHJpbWl0aXZlRmllbGQYASABKAUS",
+            "EwoLU3RyaW5nRmllbGQYAiABKAkSMQoJRW51bUZpZWxkGAMgASgOMh4ucHJv",
+            "dG9idWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SNwoMTWVzc2FnZUZpZWxkGAQg",
+            "ASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USHgoWUmVw",
+            "ZWF0ZWRQcmltaXRpdmVGaWVsZBgHIAMoBRIbChNSZXBlYXRlZFN0cmluZ0Zp",
+            "ZWxkGAggAygJEjkKEVJlcGVhdGVkRW51bUZpZWxkGAkgAygOMh4ucHJvdG9i",
+            "dWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SPwoUUmVwZWF0ZWRNZXNzYWdlRmll",
+            "bGQYCiADKAsyIS5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZSLH",
+            "AQoSVGVzdEZpZWxkT3JkZXJpbmdzEhEKCW15X3N0cmluZxgLIAEoCRIOCgZt",
+            "eV9pbnQYASABKAMSEAoIbXlfZmxvYXQYZSABKAISUwoVc2luZ2xlX25lc3Rl",
+            "ZF9tZXNzYWdlGMgBIAEoCzIzLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RGaWVs",
+            "ZE9yZGVyaW5ncy5OZXN0ZWRNZXNzYWdlGicKDU5lc3RlZE1lc3NhZ2USCgoC",
+            "b28YAiABKAMSCgoCYmIYASABKAUiSwoRU3BhcnNlRW51bU1lc3NhZ2USNgoL",
+            "c3BhcnNlX2VudW0YASABKA4yIS5wcm90b2J1Zl91bml0dGVzdC5UZXN0U3Bh",
+            "cnNlRW51bSIZCglPbmVTdHJpbmcSDAoEZGF0YRgBIAEoCSIaCgpNb3JlU3Ry",
+            "aW5nEgwKBGRhdGEYASADKAkiGAoIT25lQnl0ZXMSDAoEZGF0YRgBIAEoDCIZ",
+            "CglNb3JlQnl0ZXMSDAoEZGF0YRgBIAEoDCIcCgxJbnQzMk1lc3NhZ2USDAoE",
+            "ZGF0YRgBIAEoBSIdCg1VaW50MzJNZXNzYWdlEgwKBGRhdGEYASABKA0iHAoM",
+            "SW50NjRNZXNzYWdlEgwKBGRhdGEYASABKAMiHQoNVWludDY0TWVzc2FnZRIM",
+            "CgRkYXRhGAEgASgEIhsKC0Jvb2xNZXNzYWdlEgwKBGRhdGEYASABKAgicwoJ",
+            "VGVzdE9uZW9mEhEKB2Zvb19pbnQYASABKAVIABIUCgpmb29fc3RyaW5nGAIg",
+            "ASgJSAASNgoLZm9vX21lc3NhZ2UYAyABKAsyHy5wcm90b2J1Zl91bml0dGVz",
+            "dC5UZXN0QWxsVHlwZXNIAEIFCgNmb28iqgMKD1Rlc3RQYWNrZWRUeXBlcxIY",
+            "CgxwYWNrZWRfaW50MzIYWiADKAVCAhABEhgKDHBhY2tlZF9pbnQ2NBhbIAMo",
+            "A0ICEAESGQoNcGFja2VkX3VpbnQzMhhcIAMoDUICEAESGQoNcGFja2VkX3Vp",
+            "bnQ2NBhdIAMoBEICEAESGQoNcGFja2VkX3NpbnQzMhheIAMoEUICEAESGQoN",
+            "cGFja2VkX3NpbnQ2NBhfIAMoEkICEAESGgoOcGFja2VkX2ZpeGVkMzIYYCAD",
+            "KAdCAhABEhoKDnBhY2tlZF9maXhlZDY0GGEgAygGQgIQARIbCg9wYWNrZWRf",
+            "c2ZpeGVkMzIYYiADKA9CAhABEhsKD3BhY2tlZF9zZml4ZWQ2NBhjIAMoEEIC",
+            "EAESGAoMcGFja2VkX2Zsb2F0GGQgAygCQgIQARIZCg1wYWNrZWRfZG91Ymxl",
+            "GGUgAygBQgIQARIXCgtwYWNrZWRfYm9vbBhmIAMoCEICEAESNwoLcGFja2Vk",
+            "X2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bUIC",
+            "EAEiyAMKEVRlc3RVbnBhY2tlZFR5cGVzEhoKDnVucGFja2VkX2ludDMyGFog",
+            "AygFQgIQABIaCg51bnBhY2tlZF9pbnQ2NBhbIAMoA0ICEAASGwoPdW5wYWNr",
+            "ZWRfdWludDMyGFwgAygNQgIQABIbCg91bnBhY2tlZF91aW50NjQYXSADKARC",
+            "AhAAEhsKD3VucGFja2VkX3NpbnQzMhheIAMoEUICEAASGwoPdW5wYWNrZWRf",
+            "c2ludDY0GF8gAygSQgIQABIcChB1bnBhY2tlZF9maXhlZDMyGGAgAygHQgIQ",
+            "ABIcChB1bnBhY2tlZF9maXhlZDY0GGEgAygGQgIQABIdChF1bnBhY2tlZF9z",
+            "Zml4ZWQzMhhiIAMoD0ICEAASHQoRdW5wYWNrZWRfc2ZpeGVkNjQYYyADKBBC",
+            "AhAAEhoKDnVucGFja2VkX2Zsb2F0GGQgAygCQgIQABIbCg91bnBhY2tlZF9k",
+            "b3VibGUYZSADKAFCAhAAEhkKDXVucGFja2VkX2Jvb2wYZiADKAhCAhAAEjkK",
+            "DXVucGFja2VkX2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3Jl",
+            "aWduRW51bUICEAAiwAEKI1Rlc3RSZXBlYXRlZFNjYWxhckRpZmZlcmVudFRh",
+            "Z1NpemVzEhgKEHJlcGVhdGVkX2ZpeGVkMzIYDCADKAcSFgoOcmVwZWF0ZWRf",
+            "aW50MzIYDSADKAUSGQoQcmVwZWF0ZWRfZml4ZWQ2NBj+DyADKAYSFwoOcmVw",
+            "ZWF0ZWRfaW50NjQY/w8gAygDEhgKDnJlcGVhdGVkX2Zsb2F0GP7/DyADKAIS",
+            "GQoPcmVwZWF0ZWRfdWludDY0GP//DyADKAQiKAobVGVzdENvbW1lbnRJbmpl",
+            "Y3Rpb25NZXNzYWdlEgkKAWEYASABKAkiDAoKRm9vUmVxdWVzdCINCgtGb29S",
+            "ZXNwb25zZSISChBGb29DbGllbnRNZXNzYWdlIhIKEEZvb1NlcnZlck1lc3Nh",
+            "Z2UiDAoKQmFyUmVxdWVzdCINCgtCYXJSZXNwb25zZSpZCgtGb3JlaWduRW51",
+            "bRIXChNGT1JFSUdOX1VOU1BFQ0lGSUVEEAASDwoLRk9SRUlHTl9GT08QBBIP",
+            "CgtGT1JFSUdOX0JBUhAFEg8KC0ZPUkVJR05fQkFaEAYqdQoUVGVzdEVudW1X",
+            "aXRoRHVwVmFsdWUSKAokVEVTVF9FTlVNX1dJVEhfRFVQX1ZBTFVFX1VOU1BF",
+            "Q0lGSUVEEAASCAoERk9PMRABEggKBEJBUjEQAhIHCgNCQVoQAxIICgRGT08y",
+            "EAESCAoEQkFSMhACGgIQASqdAQoOVGVzdFNwYXJzZUVudW0SIAocVEVTVF9T",
+            "UEFSU0VfRU5VTV9VTlNQRUNJRklFRBAAEgwKCFNQQVJTRV9BEHsSDgoIU1BB",
+            "UlNFX0IQpucDEg8KCFNQQVJTRV9DELKxgAYSFQoIU1BBUlNFX0QQ8f//////",
+            "////ARIVCghTUEFSU0VfRRC03vz///////8BEgwKCFNQQVJTRV9HEAIymQEK",
+            "C1Rlc3RTZXJ2aWNlEkQKA0ZvbxIdLnByb3RvYnVmX3VuaXR0ZXN0LkZvb1Jl",
+            "cXVlc3QaHi5wcm90b2J1Zl91bml0dGVzdC5Gb29SZXNwb25zZRJECgNCYXIS",
+            "HS5wcm90b2J1Zl91bml0dGVzdC5CYXJSZXF1ZXN0Gh4ucHJvdG9idWZfdW5p",
+            "dHRlc3QuQmFyUmVzcG9uc2VCOkINVW5pdHRlc3RQcm90b0gBgAEBiAEBkAEB",
+            "+AEBqgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes), global::Google.Protobuf.TestProtos.TestAllTypes.Parser, new[]{ "SingleInt32", "SingleInt64", "SingleUint32", "SingleUint64", "SingleSint32", "SingleSint64", "SingleFixed32", "SingleFixed64", "SingleSfixed32", "SingleSfixed64", "SingleFloat", "SingleDouble", "SingleBool", "SingleString", "SingleBytes", "SingleNestedMessage", "SingleForeignMessage", "SingleImportMessage", "SingleNestedEnum", "SingleForeignEnum", "SingleImportEnum", "SinglePublicImportMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedImportMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedImportEnum", "RepeatedPublicImportMessage", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes" }, new[]{ "OneofField" }, new[]{ typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser, new[]{ "Bb" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.NestedTestAllTypes), global::Google.Protobuf.TestProtos.NestedTestAllTypes.Parser, new[]{ "Child", "Payload", "RepeatedChild" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestDeprecatedFields), global::Google.Protobuf.TestProtos.TestDeprecatedFields.Parser, new[]{ "DeprecatedInt32" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.ForeignMessage), global::Google.Protobuf.TestProtos.ForeignMessage.Parser, new[]{ "C" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestReservedFields), global::Google.Protobuf.TestProtos.TestReservedFields.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestForeignNested), global::Google.Protobuf.TestProtos.TestForeignNested.Parser, new[]{ "ForeignNested" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestReallyLargeTagNumber), global::Google.Protobuf.TestProtos.TestReallyLargeTagNumber.Parser, new[]{ "A", "Bb" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestRecursiveMessage), global::Google.Protobuf.TestProtos.TestRecursiveMessage.Parser, new[]{ "A", "I" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionA), global::Google.Protobuf.TestProtos.TestMutualRecursionA.Parser, new[]{ "Bb" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionB), global::Google.Protobuf.TestProtos.TestMutualRecursionB.Parser, new[]{ "A", "OptionalInt32" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestCamelCaseFieldNames), global::Google.Protobuf.TestProtos.TestCamelCaseFieldNames.Parser, new[]{ "PrimitiveField", "StringField", "EnumField", "MessageField", "RepeatedPrimitiveField", "RepeatedStringField", "RepeatedEnumField", "RepeatedMessageField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings), global::Google.Protobuf.TestProtos.TestFieldOrderings.Parser, new[]{ "MyString", "MyInt", "MyFloat", "SingleNestedMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage.Parser, new[]{ "Oo", "Bb" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.SparseEnumMessage), global::Google.Protobuf.TestProtos.SparseEnumMessage.Parser, new[]{ "SparseEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneString), global::Google.Protobuf.TestProtos.OneString.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MoreString), global::Google.Protobuf.TestProtos.MoreString.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneBytes), global::Google.Protobuf.TestProtos.OneBytes.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MoreBytes), global::Google.Protobuf.TestProtos.MoreBytes.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Int32Message), global::Google.Protobuf.TestProtos.Int32Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Uint32Message), global::Google.Protobuf.TestProtos.Uint32Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Int64Message), global::Google.Protobuf.TestProtos.Int64Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Uint64Message), global::Google.Protobuf.TestProtos.Uint64Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BoolMessage), global::Google.Protobuf.TestProtos.BoolMessage.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestOneof), global::Google.Protobuf.TestProtos.TestOneof.Parser, new[]{ "FooInt", "FooString", "FooMessage" }, new[]{ "Foo" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestPackedTypes), global::Google.Protobuf.TestProtos.TestPackedTypes.Parser, new[]{ "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestUnpackedTypes), global::Google.Protobuf.TestProtos.TestUnpackedTypes.Parser, new[]{ "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestRepeatedScalarDifferentTagSizes), global::Google.Protobuf.TestProtos.TestRepeatedScalarDifferentTagSizes.Parser, new[]{ "RepeatedFixed32", "RepeatedInt32", "RepeatedFixed64", "RepeatedInt64", "RepeatedFloat", "RepeatedUint64" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestCommentInjectionMessage), global::Google.Protobuf.TestProtos.TestCommentInjectionMessage.Parser, new[]{ "A" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooRequest), global::Google.Protobuf.TestProtos.FooRequest.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooResponse), global::Google.Protobuf.TestProtos.FooResponse.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooClientMessage), global::Google.Protobuf.TestProtos.FooClientMessage.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooServerMessage), global::Google.Protobuf.TestProtos.FooServerMessage.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarRequest), global::Google.Protobuf.TestProtos.BarRequest.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarResponse), global::Google.Protobuf.TestProtos.BarResponse.Parser, null, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  public enum ForeignEnum {
+    [pbr::OriginalName("FOREIGN_UNSPECIFIED")] ForeignUnspecified = 0,
+    [pbr::OriginalName("FOREIGN_FOO")] ForeignFoo = 4,
+    [pbr::OriginalName("FOREIGN_BAR")] ForeignBar = 5,
+    [pbr::OriginalName("FOREIGN_BAZ")] ForeignBaz = 6,
+  }
+
+  /// <summary>
+  ///  Test an enum that has multiple values with the same number.
+  /// </summary>
+  public enum TestEnumWithDupValue {
+    [pbr::OriginalName("TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED")] Unspecified = 0,
+    [pbr::OriginalName("FOO1")] Foo1 = 1,
+    [pbr::OriginalName("BAR1")] Bar1 = 2,
+    [pbr::OriginalName("BAZ")] Baz = 3,
+    [pbr::OriginalName("FOO2")] Foo2 = 1,
+    [pbr::OriginalName("BAR2")] Bar2 = 2,
+  }
+
+  /// <summary>
+  ///  Test an enum with large, unordered values.
+  /// </summary>
+  public enum TestSparseEnum {
+    [pbr::OriginalName("TEST_SPARSE_ENUM_UNSPECIFIED")] Unspecified = 0,
+    [pbr::OriginalName("SPARSE_A")] SparseA = 123,
+    [pbr::OriginalName("SPARSE_B")] SparseB = 62374,
+    [pbr::OriginalName("SPARSE_C")] SparseC = 12589234,
+    [pbr::OriginalName("SPARSE_D")] SparseD = -15,
+    [pbr::OriginalName("SPARSE_E")] SparseE = -53452,
+    /// <summary>
+    ///  In proto3, value 0 must be the first one specified
+    ///  SPARSE_F = 0;
+    /// </summary>
+    [pbr::OriginalName("SPARSE_G")] SparseG = 2,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  This proto includes every type of field in both singular and repeated
+  ///  forms.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestAllTypes : pb::IMessage<TestAllTypes> {
+    private static readonly pb::MessageParser<TestAllTypes> _parser = new pb::MessageParser<TestAllTypes>(() => new TestAllTypes());
+    public static pb::MessageParser<TestAllTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestAllTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestAllTypes(TestAllTypes other) : this() {
+      singleInt32_ = other.singleInt32_;
+      singleInt64_ = other.singleInt64_;
+      singleUint32_ = other.singleUint32_;
+      singleUint64_ = other.singleUint64_;
+      singleSint32_ = other.singleSint32_;
+      singleSint64_ = other.singleSint64_;
+      singleFixed32_ = other.singleFixed32_;
+      singleFixed64_ = other.singleFixed64_;
+      singleSfixed32_ = other.singleSfixed32_;
+      singleSfixed64_ = other.singleSfixed64_;
+      singleFloat_ = other.singleFloat_;
+      singleDouble_ = other.singleDouble_;
+      singleBool_ = other.singleBool_;
+      singleString_ = other.singleString_;
+      singleBytes_ = other.singleBytes_;
+      SingleNestedMessage = other.singleNestedMessage_ != null ? other.SingleNestedMessage.Clone() : null;
+      SingleForeignMessage = other.singleForeignMessage_ != null ? other.SingleForeignMessage.Clone() : null;
+      SingleImportMessage = other.singleImportMessage_ != null ? other.SingleImportMessage.Clone() : null;
+      singleNestedEnum_ = other.singleNestedEnum_;
+      singleForeignEnum_ = other.singleForeignEnum_;
+      singleImportEnum_ = other.singleImportEnum_;
+      SinglePublicImportMessage = other.singlePublicImportMessage_ != null ? other.SinglePublicImportMessage.Clone() : null;
+      repeatedInt32_ = other.repeatedInt32_.Clone();
+      repeatedInt64_ = other.repeatedInt64_.Clone();
+      repeatedUint32_ = other.repeatedUint32_.Clone();
+      repeatedUint64_ = other.repeatedUint64_.Clone();
+      repeatedSint32_ = other.repeatedSint32_.Clone();
+      repeatedSint64_ = other.repeatedSint64_.Clone();
+      repeatedFixed32_ = other.repeatedFixed32_.Clone();
+      repeatedFixed64_ = other.repeatedFixed64_.Clone();
+      repeatedSfixed32_ = other.repeatedSfixed32_.Clone();
+      repeatedSfixed64_ = other.repeatedSfixed64_.Clone();
+      repeatedFloat_ = other.repeatedFloat_.Clone();
+      repeatedDouble_ = other.repeatedDouble_.Clone();
+      repeatedBool_ = other.repeatedBool_.Clone();
+      repeatedString_ = other.repeatedString_.Clone();
+      repeatedBytes_ = other.repeatedBytes_.Clone();
+      repeatedNestedMessage_ = other.repeatedNestedMessage_.Clone();
+      repeatedForeignMessage_ = other.repeatedForeignMessage_.Clone();
+      repeatedImportMessage_ = other.repeatedImportMessage_.Clone();
+      repeatedNestedEnum_ = other.repeatedNestedEnum_.Clone();
+      repeatedForeignEnum_ = other.repeatedForeignEnum_.Clone();
+      repeatedImportEnum_ = other.repeatedImportEnum_.Clone();
+      repeatedPublicImportMessage_ = other.repeatedPublicImportMessage_.Clone();
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.OneofUint32:
+          OneofUint32 = other.OneofUint32;
+          break;
+        case OneofFieldOneofCase.OneofNestedMessage:
+          OneofNestedMessage = other.OneofNestedMessage.Clone();
+          break;
+        case OneofFieldOneofCase.OneofString:
+          OneofString = other.OneofString;
+          break;
+        case OneofFieldOneofCase.OneofBytes:
+          OneofBytes = other.OneofBytes;
+          break;
+      }
+
+    }
+
+    public TestAllTypes Clone() {
+      return new TestAllTypes(this);
+    }
+
+    /// <summary>Field number for the "single_int32" field.</summary>
+    public const int SingleInt32FieldNumber = 1;
+    private int singleInt32_;
+    /// <summary>
+    ///  Singular
+    /// </summary>
+    public int SingleInt32 {
+      get { return singleInt32_; }
+      set {
+        singleInt32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_int64" field.</summary>
+    public const int SingleInt64FieldNumber = 2;
+    private long singleInt64_;
+    public long SingleInt64 {
+      get { return singleInt64_; }
+      set {
+        singleInt64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_uint32" field.</summary>
+    public const int SingleUint32FieldNumber = 3;
+    private uint singleUint32_;
+    public uint SingleUint32 {
+      get { return singleUint32_; }
+      set {
+        singleUint32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_uint64" field.</summary>
+    public const int SingleUint64FieldNumber = 4;
+    private ulong singleUint64_;
+    public ulong SingleUint64 {
+      get { return singleUint64_; }
+      set {
+        singleUint64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_sint32" field.</summary>
+    public const int SingleSint32FieldNumber = 5;
+    private int singleSint32_;
+    public int SingleSint32 {
+      get { return singleSint32_; }
+      set {
+        singleSint32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_sint64" field.</summary>
+    public const int SingleSint64FieldNumber = 6;
+    private long singleSint64_;
+    public long SingleSint64 {
+      get { return singleSint64_; }
+      set {
+        singleSint64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_fixed32" field.</summary>
+    public const int SingleFixed32FieldNumber = 7;
+    private uint singleFixed32_;
+    public uint SingleFixed32 {
+      get { return singleFixed32_; }
+      set {
+        singleFixed32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_fixed64" field.</summary>
+    public const int SingleFixed64FieldNumber = 8;
+    private ulong singleFixed64_;
+    public ulong SingleFixed64 {
+      get { return singleFixed64_; }
+      set {
+        singleFixed64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_sfixed32" field.</summary>
+    public const int SingleSfixed32FieldNumber = 9;
+    private int singleSfixed32_;
+    public int SingleSfixed32 {
+      get { return singleSfixed32_; }
+      set {
+        singleSfixed32_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_sfixed64" field.</summary>
+    public const int SingleSfixed64FieldNumber = 10;
+    private long singleSfixed64_;
+    public long SingleSfixed64 {
+      get { return singleSfixed64_; }
+      set {
+        singleSfixed64_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_float" field.</summary>
+    public const int SingleFloatFieldNumber = 11;
+    private float singleFloat_;
+    public float SingleFloat {
+      get { return singleFloat_; }
+      set {
+        singleFloat_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_double" field.</summary>
+    public const int SingleDoubleFieldNumber = 12;
+    private double singleDouble_;
+    public double SingleDouble {
+      get { return singleDouble_; }
+      set {
+        singleDouble_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_bool" field.</summary>
+    public const int SingleBoolFieldNumber = 13;
+    private bool singleBool_;
+    public bool SingleBool {
+      get { return singleBool_; }
+      set {
+        singleBool_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_string" field.</summary>
+    public const int SingleStringFieldNumber = 14;
+    private string singleString_ = "";
+    public string SingleString {
+      get { return singleString_; }
+      set {
+        singleString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "single_bytes" field.</summary>
+    public const int SingleBytesFieldNumber = 15;
+    private pb::ByteString singleBytes_ = pb::ByteString.Empty;
+    public pb::ByteString SingleBytes {
+      get { return singleBytes_; }
+      set {
+        singleBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "single_nested_message" field.</summary>
+    public const int SingleNestedMessageFieldNumber = 18;
+    private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage singleNestedMessage_;
+    public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage SingleNestedMessage {
+      get { return singleNestedMessage_; }
+      set {
+        singleNestedMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_foreign_message" field.</summary>
+    public const int SingleForeignMessageFieldNumber = 19;
+    private global::Google.Protobuf.TestProtos.ForeignMessage singleForeignMessage_;
+    public global::Google.Protobuf.TestProtos.ForeignMessage SingleForeignMessage {
+      get { return singleForeignMessage_; }
+      set {
+        singleForeignMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_import_message" field.</summary>
+    public const int SingleImportMessageFieldNumber = 20;
+    private global::Google.Protobuf.TestProtos.ImportMessage singleImportMessage_;
+    public global::Google.Protobuf.TestProtos.ImportMessage SingleImportMessage {
+      get { return singleImportMessage_; }
+      set {
+        singleImportMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_nested_enum" field.</summary>
+    public const int SingleNestedEnumFieldNumber = 21;
+    private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum singleNestedEnum_ = 0;
+    public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum SingleNestedEnum {
+      get { return singleNestedEnum_; }
+      set {
+        singleNestedEnum_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_foreign_enum" field.</summary>
+    public const int SingleForeignEnumFieldNumber = 22;
+    private global::Google.Protobuf.TestProtos.ForeignEnum singleForeignEnum_ = 0;
+    public global::Google.Protobuf.TestProtos.ForeignEnum SingleForeignEnum {
+      get { return singleForeignEnum_; }
+      set {
+        singleForeignEnum_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_import_enum" field.</summary>
+    public const int SingleImportEnumFieldNumber = 23;
+    private global::Google.Protobuf.TestProtos.ImportEnum singleImportEnum_ = 0;
+    public global::Google.Protobuf.TestProtos.ImportEnum SingleImportEnum {
+      get { return singleImportEnum_; }
+      set {
+        singleImportEnum_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_public_import_message" field.</summary>
+    public const int SinglePublicImportMessageFieldNumber = 26;
+    private global::Google.Protobuf.TestProtos.PublicImportMessage singlePublicImportMessage_;
+    /// <summary>
+    ///  Defined in unittest_import_public.proto
+    /// </summary>
+    public global::Google.Protobuf.TestProtos.PublicImportMessage SinglePublicImportMessage {
+      get { return singlePublicImportMessage_; }
+      set {
+        singlePublicImportMessage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_int32" field.</summary>
+    public const int RepeatedInt32FieldNumber = 31;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
+        = pb::FieldCodec.ForInt32(250);
+    private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Repeated
+    /// </summary>
+    public pbc::RepeatedField<int> RepeatedInt32 {
+      get { return repeatedInt32_; }
+    }
+
+    /// <summary>Field number for the "repeated_int64" field.</summary>
+    public const int RepeatedInt64FieldNumber = 32;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
+        = pb::FieldCodec.ForInt64(258);
+    private readonly pbc::RepeatedField<long> repeatedInt64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedInt64 {
+      get { return repeatedInt64_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint32" field.</summary>
+    public const int RepeatedUint32FieldNumber = 33;
+    private static readonly pb::FieldCodec<uint> _repeated_repeatedUint32_codec
+        = pb::FieldCodec.ForUInt32(266);
+    private readonly pbc::RepeatedField<uint> repeatedUint32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> RepeatedUint32 {
+      get { return repeatedUint32_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
+    public const int RepeatedUint64FieldNumber = 34;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
+        = pb::FieldCodec.ForUInt64(274);
+    private readonly pbc::RepeatedField<ulong> repeatedUint64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> RepeatedUint64 {
+      get { return repeatedUint64_; }
+    }
+
+    /// <summary>Field number for the "repeated_sint32" field.</summary>
+    public const int RepeatedSint32FieldNumber = 35;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedSint32_codec
+        = pb::FieldCodec.ForSInt32(282);
+    private readonly pbc::RepeatedField<int> repeatedSint32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> RepeatedSint32 {
+      get { return repeatedSint32_; }
+    }
+
+    /// <summary>Field number for the "repeated_sint64" field.</summary>
+    public const int RepeatedSint64FieldNumber = 36;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedSint64_codec
+        = pb::FieldCodec.ForSInt64(290);
+    private readonly pbc::RepeatedField<long> repeatedSint64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedSint64 {
+      get { return repeatedSint64_; }
+    }
+
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
+    public const int RepeatedFixed32FieldNumber = 37;
+    private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
+        = pb::FieldCodec.ForFixed32(298);
+    private readonly pbc::RepeatedField<uint> repeatedFixed32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> RepeatedFixed32 {
+      get { return repeatedFixed32_; }
+    }
+
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
+    public const int RepeatedFixed64FieldNumber = 38;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
+        = pb::FieldCodec.ForFixed64(306);
+    private readonly pbc::RepeatedField<ulong> repeatedFixed64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> RepeatedFixed64 {
+      get { return repeatedFixed64_; }
+    }
+
+    /// <summary>Field number for the "repeated_sfixed32" field.</summary>
+    public const int RepeatedSfixed32FieldNumber = 39;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedSfixed32_codec
+        = pb::FieldCodec.ForSFixed32(314);
+    private readonly pbc::RepeatedField<int> repeatedSfixed32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> RepeatedSfixed32 {
+      get { return repeatedSfixed32_; }
+    }
+
+    /// <summary>Field number for the "repeated_sfixed64" field.</summary>
+    public const int RepeatedSfixed64FieldNumber = 40;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedSfixed64_codec
+        = pb::FieldCodec.ForSFixed64(322);
+    private readonly pbc::RepeatedField<long> repeatedSfixed64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedSfixed64 {
+      get { return repeatedSfixed64_; }
+    }
+
+    /// <summary>Field number for the "repeated_float" field.</summary>
+    public const int RepeatedFloatFieldNumber = 41;
+    private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
+        = pb::FieldCodec.ForFloat(330);
+    private readonly pbc::RepeatedField<float> repeatedFloat_ = new pbc::RepeatedField<float>();
+    public pbc::RepeatedField<float> RepeatedFloat {
+      get { return repeatedFloat_; }
+    }
+
+    /// <summary>Field number for the "repeated_double" field.</summary>
+    public const int RepeatedDoubleFieldNumber = 42;
+    private static readonly pb::FieldCodec<double> _repeated_repeatedDouble_codec
+        = pb::FieldCodec.ForDouble(338);
+    private readonly pbc::RepeatedField<double> repeatedDouble_ = new pbc::RepeatedField<double>();
+    public pbc::RepeatedField<double> RepeatedDouble {
+      get { return repeatedDouble_; }
+    }
+
+    /// <summary>Field number for the "repeated_bool" field.</summary>
+    public const int RepeatedBoolFieldNumber = 43;
+    private static readonly pb::FieldCodec<bool> _repeated_repeatedBool_codec
+        = pb::FieldCodec.ForBool(346);
+    private readonly pbc::RepeatedField<bool> repeatedBool_ = new pbc::RepeatedField<bool>();
+    public pbc::RepeatedField<bool> RepeatedBool {
+      get { return repeatedBool_; }
+    }
+
+    /// <summary>Field number for the "repeated_string" field.</summary>
+    public const int RepeatedStringFieldNumber = 44;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedString_codec
+        = pb::FieldCodec.ForString(354);
+    private readonly pbc::RepeatedField<string> repeatedString_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedString {
+      get { return repeatedString_; }
+    }
+
+    /// <summary>Field number for the "repeated_bytes" field.</summary>
+    public const int RepeatedBytesFieldNumber = 45;
+    private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytes_codec
+        = pb::FieldCodec.ForBytes(362);
+    private readonly pbc::RepeatedField<pb::ByteString> repeatedBytes_ = new pbc::RepeatedField<pb::ByteString>();
+    public pbc::RepeatedField<pb::ByteString> RepeatedBytes {
+      get { return repeatedBytes_; }
+    }
+
+    /// <summary>Field number for the "repeated_nested_message" field.</summary>
+    public const int RepeatedNestedMessageFieldNumber = 48;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage> _repeated_repeatedNestedMessage_codec
+        = pb::FieldCodec.ForMessage(386, global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage> repeatedNestedMessage_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage> RepeatedNestedMessage {
+      get { return repeatedNestedMessage_; }
+    }
+
+    /// <summary>Field number for the "repeated_foreign_message" field.</summary>
+    public const int RepeatedForeignMessageFieldNumber = 49;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignMessage> _repeated_repeatedForeignMessage_codec
+        = pb::FieldCodec.ForMessage(394, global::Google.Protobuf.TestProtos.ForeignMessage.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage> repeatedForeignMessage_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage> RepeatedForeignMessage {
+      get { return repeatedForeignMessage_; }
+    }
+
+    /// <summary>Field number for the "repeated_import_message" field.</summary>
+    public const int RepeatedImportMessageFieldNumber = 50;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ImportMessage> _repeated_repeatedImportMessage_codec
+        = pb::FieldCodec.ForMessage(402, global::Google.Protobuf.TestProtos.ImportMessage.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportMessage> repeatedImportMessage_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportMessage>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportMessage> RepeatedImportMessage {
+      get { return repeatedImportMessage_; }
+    }
+
+    /// <summary>Field number for the "repeated_nested_enum" field.</summary>
+    public const int RepeatedNestedEnumFieldNumber = 51;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum> _repeated_repeatedNestedEnum_codec
+        = pb::FieldCodec.ForEnum(410, x => (int) x, x => (global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum> repeatedNestedEnum_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum> RepeatedNestedEnum {
+      get { return repeatedNestedEnum_; }
+    }
+
+    /// <summary>Field number for the "repeated_foreign_enum" field.</summary>
+    public const int RepeatedForeignEnumFieldNumber = 52;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_repeatedForeignEnum_codec
+        = pb::FieldCodec.ForEnum(418, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> repeatedForeignEnum_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> RepeatedForeignEnum {
+      get { return repeatedForeignEnum_; }
+    }
+
+    /// <summary>Field number for the "repeated_import_enum" field.</summary>
+    public const int RepeatedImportEnumFieldNumber = 53;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ImportEnum> _repeated_repeatedImportEnum_codec
+        = pb::FieldCodec.ForEnum(426, x => (int) x, x => (global::Google.Protobuf.TestProtos.ImportEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportEnum> repeatedImportEnum_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ImportEnum> RepeatedImportEnum {
+      get { return repeatedImportEnum_; }
+    }
+
+    /// <summary>Field number for the "repeated_public_import_message" field.</summary>
+    public const int RepeatedPublicImportMessageFieldNumber = 54;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.PublicImportMessage> _repeated_repeatedPublicImportMessage_codec
+        = pb::FieldCodec.ForMessage(434, global::Google.Protobuf.TestProtos.PublicImportMessage.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage> repeatedPublicImportMessage_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage>();
+    /// <summary>
+    ///  Defined in unittest_import_public.proto
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage> RepeatedPublicImportMessage {
+      get { return repeatedPublicImportMessage_; }
+    }
+
+    /// <summary>Field number for the "oneof_uint32" field.</summary>
+    public const int OneofUint32FieldNumber = 111;
+    public uint OneofUint32 {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofUint32;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_nested_message" field.</summary>
+    public const int OneofNestedMessageFieldNumber = 112;
+    public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage OneofNestedMessage {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage ? (global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.OneofNestedMessage;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_string" field.</summary>
+    public const int OneofStringFieldNumber = 113;
+    public string OneofString {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
+      set {
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        oneofFieldCase_ = OneofFieldOneofCase.OneofString;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_bytes" field.</summary>
+    public const int OneofBytesFieldNumber = 114;
+    public pb::ByteString OneofBytes {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
+      set {
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
+      }
+    }
+
+    private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
+    public enum OneofFieldOneofCase {
+      None = 0,
+      OneofUint32 = 111,
+      OneofNestedMessage = 112,
+      OneofString = 113,
+      OneofBytes = 114,
+    }
+    private OneofFieldOneofCase oneofFieldCase_ = OneofFieldOneofCase.None;
+    public OneofFieldOneofCase OneofFieldCase {
+      get { return oneofFieldCase_; }
+    }
+
+    public void ClearOneofField() {
+      oneofFieldCase_ = OneofFieldOneofCase.None;
+      oneofField_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestAllTypes);
+    }
+
+    public bool Equals(TestAllTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (SingleInt32 != other.SingleInt32) return false;
+      if (SingleInt64 != other.SingleInt64) return false;
+      if (SingleUint32 != other.SingleUint32) return false;
+      if (SingleUint64 != other.SingleUint64) return false;
+      if (SingleSint32 != other.SingleSint32) return false;
+      if (SingleSint64 != other.SingleSint64) return false;
+      if (SingleFixed32 != other.SingleFixed32) return false;
+      if (SingleFixed64 != other.SingleFixed64) return false;
+      if (SingleSfixed32 != other.SingleSfixed32) return false;
+      if (SingleSfixed64 != other.SingleSfixed64) return false;
+      if (SingleFloat != other.SingleFloat) return false;
+      if (SingleDouble != other.SingleDouble) return false;
+      if (SingleBool != other.SingleBool) return false;
+      if (SingleString != other.SingleString) return false;
+      if (SingleBytes != other.SingleBytes) return false;
+      if (!object.Equals(SingleNestedMessage, other.SingleNestedMessage)) return false;
+      if (!object.Equals(SingleForeignMessage, other.SingleForeignMessage)) return false;
+      if (!object.Equals(SingleImportMessage, other.SingleImportMessage)) return false;
+      if (SingleNestedEnum != other.SingleNestedEnum) return false;
+      if (SingleForeignEnum != other.SingleForeignEnum) return false;
+      if (SingleImportEnum != other.SingleImportEnum) return false;
+      if (!object.Equals(SinglePublicImportMessage, other.SinglePublicImportMessage)) return false;
+      if(!repeatedInt32_.Equals(other.repeatedInt32_)) return false;
+      if(!repeatedInt64_.Equals(other.repeatedInt64_)) return false;
+      if(!repeatedUint32_.Equals(other.repeatedUint32_)) return false;
+      if(!repeatedUint64_.Equals(other.repeatedUint64_)) return false;
+      if(!repeatedSint32_.Equals(other.repeatedSint32_)) return false;
+      if(!repeatedSint64_.Equals(other.repeatedSint64_)) return false;
+      if(!repeatedFixed32_.Equals(other.repeatedFixed32_)) return false;
+      if(!repeatedFixed64_.Equals(other.repeatedFixed64_)) return false;
+      if(!repeatedSfixed32_.Equals(other.repeatedSfixed32_)) return false;
+      if(!repeatedSfixed64_.Equals(other.repeatedSfixed64_)) return false;
+      if(!repeatedFloat_.Equals(other.repeatedFloat_)) return false;
+      if(!repeatedDouble_.Equals(other.repeatedDouble_)) return false;
+      if(!repeatedBool_.Equals(other.repeatedBool_)) return false;
+      if(!repeatedString_.Equals(other.repeatedString_)) return false;
+      if(!repeatedBytes_.Equals(other.repeatedBytes_)) return false;
+      if(!repeatedNestedMessage_.Equals(other.repeatedNestedMessage_)) return false;
+      if(!repeatedForeignMessage_.Equals(other.repeatedForeignMessage_)) return false;
+      if(!repeatedImportMessage_.Equals(other.repeatedImportMessage_)) return false;
+      if(!repeatedNestedEnum_.Equals(other.repeatedNestedEnum_)) return false;
+      if(!repeatedForeignEnum_.Equals(other.repeatedForeignEnum_)) return false;
+      if(!repeatedImportEnum_.Equals(other.repeatedImportEnum_)) return false;
+      if(!repeatedPublicImportMessage_.Equals(other.repeatedPublicImportMessage_)) return false;
+      if (OneofUint32 != other.OneofUint32) return false;
+      if (!object.Equals(OneofNestedMessage, other.OneofNestedMessage)) return false;
+      if (OneofString != other.OneofString) return false;
+      if (OneofBytes != other.OneofBytes) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (SingleInt32 != 0) hash ^= SingleInt32.GetHashCode();
+      if (SingleInt64 != 0L) hash ^= SingleInt64.GetHashCode();
+      if (SingleUint32 != 0) hash ^= SingleUint32.GetHashCode();
+      if (SingleUint64 != 0UL) hash ^= SingleUint64.GetHashCode();
+      if (SingleSint32 != 0) hash ^= SingleSint32.GetHashCode();
+      if (SingleSint64 != 0L) hash ^= SingleSint64.GetHashCode();
+      if (SingleFixed32 != 0) hash ^= SingleFixed32.GetHashCode();
+      if (SingleFixed64 != 0UL) hash ^= SingleFixed64.GetHashCode();
+      if (SingleSfixed32 != 0) hash ^= SingleSfixed32.GetHashCode();
+      if (SingleSfixed64 != 0L) hash ^= SingleSfixed64.GetHashCode();
+      if (SingleFloat != 0F) hash ^= SingleFloat.GetHashCode();
+      if (SingleDouble != 0D) hash ^= SingleDouble.GetHashCode();
+      if (SingleBool != false) hash ^= SingleBool.GetHashCode();
+      if (SingleString.Length != 0) hash ^= SingleString.GetHashCode();
+      if (SingleBytes.Length != 0) hash ^= SingleBytes.GetHashCode();
+      if (singleNestedMessage_ != null) hash ^= SingleNestedMessage.GetHashCode();
+      if (singleForeignMessage_ != null) hash ^= SingleForeignMessage.GetHashCode();
+      if (singleImportMessage_ != null) hash ^= SingleImportMessage.GetHashCode();
+      if (SingleNestedEnum != 0) hash ^= SingleNestedEnum.GetHashCode();
+      if (SingleForeignEnum != 0) hash ^= SingleForeignEnum.GetHashCode();
+      if (SingleImportEnum != 0) hash ^= SingleImportEnum.GetHashCode();
+      if (singlePublicImportMessage_ != null) hash ^= SinglePublicImportMessage.GetHashCode();
+      hash ^= repeatedInt32_.GetHashCode();
+      hash ^= repeatedInt64_.GetHashCode();
+      hash ^= repeatedUint32_.GetHashCode();
+      hash ^= repeatedUint64_.GetHashCode();
+      hash ^= repeatedSint32_.GetHashCode();
+      hash ^= repeatedSint64_.GetHashCode();
+      hash ^= repeatedFixed32_.GetHashCode();
+      hash ^= repeatedFixed64_.GetHashCode();
+      hash ^= repeatedSfixed32_.GetHashCode();
+      hash ^= repeatedSfixed64_.GetHashCode();
+      hash ^= repeatedFloat_.GetHashCode();
+      hash ^= repeatedDouble_.GetHashCode();
+      hash ^= repeatedBool_.GetHashCode();
+      hash ^= repeatedString_.GetHashCode();
+      hash ^= repeatedBytes_.GetHashCode();
+      hash ^= repeatedNestedMessage_.GetHashCode();
+      hash ^= repeatedForeignMessage_.GetHashCode();
+      hash ^= repeatedImportMessage_.GetHashCode();
+      hash ^= repeatedNestedEnum_.GetHashCode();
+      hash ^= repeatedForeignEnum_.GetHashCode();
+      hash ^= repeatedImportEnum_.GetHashCode();
+      hash ^= repeatedPublicImportMessage_.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) hash ^= OneofUint32.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (SingleInt32 != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(SingleInt32);
+      }
+      if (SingleInt64 != 0L) {
+        output.WriteRawTag(16);
+        output.WriteInt64(SingleInt64);
+      }
+      if (SingleUint32 != 0) {
+        output.WriteRawTag(24);
+        output.WriteUInt32(SingleUint32);
+      }
+      if (SingleUint64 != 0UL) {
+        output.WriteRawTag(32);
+        output.WriteUInt64(SingleUint64);
+      }
+      if (SingleSint32 != 0) {
+        output.WriteRawTag(40);
+        output.WriteSInt32(SingleSint32);
+      }
+      if (SingleSint64 != 0L) {
+        output.WriteRawTag(48);
+        output.WriteSInt64(SingleSint64);
+      }
+      if (SingleFixed32 != 0) {
+        output.WriteRawTag(61);
+        output.WriteFixed32(SingleFixed32);
+      }
+      if (SingleFixed64 != 0UL) {
+        output.WriteRawTag(65);
+        output.WriteFixed64(SingleFixed64);
+      }
+      if (SingleSfixed32 != 0) {
+        output.WriteRawTag(77);
+        output.WriteSFixed32(SingleSfixed32);
+      }
+      if (SingleSfixed64 != 0L) {
+        output.WriteRawTag(81);
+        output.WriteSFixed64(SingleSfixed64);
+      }
+      if (SingleFloat != 0F) {
+        output.WriteRawTag(93);
+        output.WriteFloat(SingleFloat);
+      }
+      if (SingleDouble != 0D) {
+        output.WriteRawTag(97);
+        output.WriteDouble(SingleDouble);
+      }
+      if (SingleBool != false) {
+        output.WriteRawTag(104);
+        output.WriteBool(SingleBool);
+      }
+      if (SingleString.Length != 0) {
+        output.WriteRawTag(114);
+        output.WriteString(SingleString);
+      }
+      if (SingleBytes.Length != 0) {
+        output.WriteRawTag(122);
+        output.WriteBytes(SingleBytes);
+      }
+      if (singleNestedMessage_ != null) {
+        output.WriteRawTag(146, 1);
+        output.WriteMessage(SingleNestedMessage);
+      }
+      if (singleForeignMessage_ != null) {
+        output.WriteRawTag(154, 1);
+        output.WriteMessage(SingleForeignMessage);
+      }
+      if (singleImportMessage_ != null) {
+        output.WriteRawTag(162, 1);
+        output.WriteMessage(SingleImportMessage);
+      }
+      if (SingleNestedEnum != 0) {
+        output.WriteRawTag(168, 1);
+        output.WriteEnum((int) SingleNestedEnum);
+      }
+      if (SingleForeignEnum != 0) {
+        output.WriteRawTag(176, 1);
+        output.WriteEnum((int) SingleForeignEnum);
+      }
+      if (SingleImportEnum != 0) {
+        output.WriteRawTag(184, 1);
+        output.WriteEnum((int) SingleImportEnum);
+      }
+      if (singlePublicImportMessage_ != null) {
+        output.WriteRawTag(210, 1);
+        output.WriteMessage(SinglePublicImportMessage);
+      }
+      repeatedInt32_.WriteTo(output, _repeated_repeatedInt32_codec);
+      repeatedInt64_.WriteTo(output, _repeated_repeatedInt64_codec);
+      repeatedUint32_.WriteTo(output, _repeated_repeatedUint32_codec);
+      repeatedUint64_.WriteTo(output, _repeated_repeatedUint64_codec);
+      repeatedSint32_.WriteTo(output, _repeated_repeatedSint32_codec);
+      repeatedSint64_.WriteTo(output, _repeated_repeatedSint64_codec);
+      repeatedFixed32_.WriteTo(output, _repeated_repeatedFixed32_codec);
+      repeatedFixed64_.WriteTo(output, _repeated_repeatedFixed64_codec);
+      repeatedSfixed32_.WriteTo(output, _repeated_repeatedSfixed32_codec);
+      repeatedSfixed64_.WriteTo(output, _repeated_repeatedSfixed64_codec);
+      repeatedFloat_.WriteTo(output, _repeated_repeatedFloat_codec);
+      repeatedDouble_.WriteTo(output, _repeated_repeatedDouble_codec);
+      repeatedBool_.WriteTo(output, _repeated_repeatedBool_codec);
+      repeatedString_.WriteTo(output, _repeated_repeatedString_codec);
+      repeatedBytes_.WriteTo(output, _repeated_repeatedBytes_codec);
+      repeatedNestedMessage_.WriteTo(output, _repeated_repeatedNestedMessage_codec);
+      repeatedForeignMessage_.WriteTo(output, _repeated_repeatedForeignMessage_codec);
+      repeatedImportMessage_.WriteTo(output, _repeated_repeatedImportMessage_codec);
+      repeatedNestedEnum_.WriteTo(output, _repeated_repeatedNestedEnum_codec);
+      repeatedForeignEnum_.WriteTo(output, _repeated_repeatedForeignEnum_codec);
+      repeatedImportEnum_.WriteTo(output, _repeated_repeatedImportEnum_codec);
+      repeatedPublicImportMessage_.WriteTo(output, _repeated_repeatedPublicImportMessage_codec);
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+        output.WriteRawTag(248, 6);
+        output.WriteUInt32(OneofUint32);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+        output.WriteRawTag(130, 7);
+        output.WriteMessage(OneofNestedMessage);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+        output.WriteRawTag(138, 7);
+        output.WriteString(OneofString);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+        output.WriteRawTag(146, 7);
+        output.WriteBytes(OneofBytes);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (SingleInt32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(SingleInt32);
+      }
+      if (SingleInt64 != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(SingleInt64);
+      }
+      if (SingleUint32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt32Size(SingleUint32);
+      }
+      if (SingleUint64 != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(SingleUint64);
+      }
+      if (SingleSint32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeSInt32Size(SingleSint32);
+      }
+      if (SingleSint64 != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeSInt64Size(SingleSint64);
+      }
+      if (SingleFixed32 != 0) {
+        size += 1 + 4;
+      }
+      if (SingleFixed64 != 0UL) {
+        size += 1 + 8;
+      }
+      if (SingleSfixed32 != 0) {
+        size += 1 + 4;
+      }
+      if (SingleSfixed64 != 0L) {
+        size += 1 + 8;
+      }
+      if (SingleFloat != 0F) {
+        size += 1 + 4;
+      }
+      if (SingleDouble != 0D) {
+        size += 1 + 8;
+      }
+      if (SingleBool != false) {
+        size += 1 + 1;
+      }
+      if (SingleString.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(SingleString);
+      }
+      if (SingleBytes.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(SingleBytes);
+      }
+      if (singleNestedMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(SingleNestedMessage);
+      }
+      if (singleForeignMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(SingleForeignMessage);
+      }
+      if (singleImportMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(SingleImportMessage);
+      }
+      if (SingleNestedEnum != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleNestedEnum);
+      }
+      if (SingleForeignEnum != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleForeignEnum);
+      }
+      if (SingleImportEnum != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleImportEnum);
+      }
+      if (singlePublicImportMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(SinglePublicImportMessage);
+      }
+      size += repeatedInt32_.CalculateSize(_repeated_repeatedInt32_codec);
+      size += repeatedInt64_.CalculateSize(_repeated_repeatedInt64_codec);
+      size += repeatedUint32_.CalculateSize(_repeated_repeatedUint32_codec);
+      size += repeatedUint64_.CalculateSize(_repeated_repeatedUint64_codec);
+      size += repeatedSint32_.CalculateSize(_repeated_repeatedSint32_codec);
+      size += repeatedSint64_.CalculateSize(_repeated_repeatedSint64_codec);
+      size += repeatedFixed32_.CalculateSize(_repeated_repeatedFixed32_codec);
+      size += repeatedFixed64_.CalculateSize(_repeated_repeatedFixed64_codec);
+      size += repeatedSfixed32_.CalculateSize(_repeated_repeatedSfixed32_codec);
+      size += repeatedSfixed64_.CalculateSize(_repeated_repeatedSfixed64_codec);
+      size += repeatedFloat_.CalculateSize(_repeated_repeatedFloat_codec);
+      size += repeatedDouble_.CalculateSize(_repeated_repeatedDouble_codec);
+      size += repeatedBool_.CalculateSize(_repeated_repeatedBool_codec);
+      size += repeatedString_.CalculateSize(_repeated_repeatedString_codec);
+      size += repeatedBytes_.CalculateSize(_repeated_repeatedBytes_codec);
+      size += repeatedNestedMessage_.CalculateSize(_repeated_repeatedNestedMessage_codec);
+      size += repeatedForeignMessage_.CalculateSize(_repeated_repeatedForeignMessage_codec);
+      size += repeatedImportMessage_.CalculateSize(_repeated_repeatedImportMessage_codec);
+      size += repeatedNestedEnum_.CalculateSize(_repeated_repeatedNestedEnum_codec);
+      size += repeatedForeignEnum_.CalculateSize(_repeated_repeatedForeignEnum_codec);
+      size += repeatedImportEnum_.CalculateSize(_repeated_repeatedImportEnum_codec);
+      size += repeatedPublicImportMessage_.CalculateSize(_repeated_repeatedPublicImportMessage_codec);
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+        size += 2 + pb::CodedOutputStream.ComputeUInt32Size(OneofUint32);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OneofNestedMessage);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(OneofString);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+        size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestAllTypes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.SingleInt32 != 0) {
+        SingleInt32 = other.SingleInt32;
+      }
+      if (other.SingleInt64 != 0L) {
+        SingleInt64 = other.SingleInt64;
+      }
+      if (other.SingleUint32 != 0) {
+        SingleUint32 = other.SingleUint32;
+      }
+      if (other.SingleUint64 != 0UL) {
+        SingleUint64 = other.SingleUint64;
+      }
+      if (other.SingleSint32 != 0) {
+        SingleSint32 = other.SingleSint32;
+      }
+      if (other.SingleSint64 != 0L) {
+        SingleSint64 = other.SingleSint64;
+      }
+      if (other.SingleFixed32 != 0) {
+        SingleFixed32 = other.SingleFixed32;
+      }
+      if (other.SingleFixed64 != 0UL) {
+        SingleFixed64 = other.SingleFixed64;
+      }
+      if (other.SingleSfixed32 != 0) {
+        SingleSfixed32 = other.SingleSfixed32;
+      }
+      if (other.SingleSfixed64 != 0L) {
+        SingleSfixed64 = other.SingleSfixed64;
+      }
+      if (other.SingleFloat != 0F) {
+        SingleFloat = other.SingleFloat;
+      }
+      if (other.SingleDouble != 0D) {
+        SingleDouble = other.SingleDouble;
+      }
+      if (other.SingleBool != false) {
+        SingleBool = other.SingleBool;
+      }
+      if (other.SingleString.Length != 0) {
+        SingleString = other.SingleString;
+      }
+      if (other.SingleBytes.Length != 0) {
+        SingleBytes = other.SingleBytes;
+      }
+      if (other.singleNestedMessage_ != null) {
+        if (singleNestedMessage_ == null) {
+          singleNestedMessage_ = new global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage();
+        }
+        SingleNestedMessage.MergeFrom(other.SingleNestedMessage);
+      }
+      if (other.singleForeignMessage_ != null) {
+        if (singleForeignMessage_ == null) {
+          singleForeignMessage_ = new global::Google.Protobuf.TestProtos.ForeignMessage();
+        }
+        SingleForeignMessage.MergeFrom(other.SingleForeignMessage);
+      }
+      if (other.singleImportMessage_ != null) {
+        if (singleImportMessage_ == null) {
+          singleImportMessage_ = new global::Google.Protobuf.TestProtos.ImportMessage();
+        }
+        SingleImportMessage.MergeFrom(other.SingleImportMessage);
+      }
+      if (other.SingleNestedEnum != 0) {
+        SingleNestedEnum = other.SingleNestedEnum;
+      }
+      if (other.SingleForeignEnum != 0) {
+        SingleForeignEnum = other.SingleForeignEnum;
+      }
+      if (other.SingleImportEnum != 0) {
+        SingleImportEnum = other.SingleImportEnum;
+      }
+      if (other.singlePublicImportMessage_ != null) {
+        if (singlePublicImportMessage_ == null) {
+          singlePublicImportMessage_ = new global::Google.Protobuf.TestProtos.PublicImportMessage();
+        }
+        SinglePublicImportMessage.MergeFrom(other.SinglePublicImportMessage);
+      }
+      repeatedInt32_.Add(other.repeatedInt32_);
+      repeatedInt64_.Add(other.repeatedInt64_);
+      repeatedUint32_.Add(other.repeatedUint32_);
+      repeatedUint64_.Add(other.repeatedUint64_);
+      repeatedSint32_.Add(other.repeatedSint32_);
+      repeatedSint64_.Add(other.repeatedSint64_);
+      repeatedFixed32_.Add(other.repeatedFixed32_);
+      repeatedFixed64_.Add(other.repeatedFixed64_);
+      repeatedSfixed32_.Add(other.repeatedSfixed32_);
+      repeatedSfixed64_.Add(other.repeatedSfixed64_);
+      repeatedFloat_.Add(other.repeatedFloat_);
+      repeatedDouble_.Add(other.repeatedDouble_);
+      repeatedBool_.Add(other.repeatedBool_);
+      repeatedString_.Add(other.repeatedString_);
+      repeatedBytes_.Add(other.repeatedBytes_);
+      repeatedNestedMessage_.Add(other.repeatedNestedMessage_);
+      repeatedForeignMessage_.Add(other.repeatedForeignMessage_);
+      repeatedImportMessage_.Add(other.repeatedImportMessage_);
+      repeatedNestedEnum_.Add(other.repeatedNestedEnum_);
+      repeatedForeignEnum_.Add(other.repeatedForeignEnum_);
+      repeatedImportEnum_.Add(other.repeatedImportEnum_);
+      repeatedPublicImportMessage_.Add(other.repeatedPublicImportMessage_);
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.OneofUint32:
+          OneofUint32 = other.OneofUint32;
+          break;
+        case OneofFieldOneofCase.OneofNestedMessage:
+          OneofNestedMessage = other.OneofNestedMessage;
+          break;
+        case OneofFieldOneofCase.OneofString:
+          OneofString = other.OneofString;
+          break;
+        case OneofFieldOneofCase.OneofBytes:
+          OneofBytes = other.OneofBytes;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            SingleInt32 = input.ReadInt32();
+            break;
+          }
+          case 16: {
+            SingleInt64 = input.ReadInt64();
+            break;
+          }
+          case 24: {
+            SingleUint32 = input.ReadUInt32();
+            break;
+          }
+          case 32: {
+            SingleUint64 = input.ReadUInt64();
+            break;
+          }
+          case 40: {
+            SingleSint32 = input.ReadSInt32();
+            break;
+          }
+          case 48: {
+            SingleSint64 = input.ReadSInt64();
+            break;
+          }
+          case 61: {
+            SingleFixed32 = input.ReadFixed32();
+            break;
+          }
+          case 65: {
+            SingleFixed64 = input.ReadFixed64();
+            break;
+          }
+          case 77: {
+            SingleSfixed32 = input.ReadSFixed32();
+            break;
+          }
+          case 81: {
+            SingleSfixed64 = input.ReadSFixed64();
+            break;
+          }
+          case 93: {
+            SingleFloat = input.ReadFloat();
+            break;
+          }
+          case 97: {
+            SingleDouble = input.ReadDouble();
+            break;
+          }
+          case 104: {
+            SingleBool = input.ReadBool();
+            break;
+          }
+          case 114: {
+            SingleString = input.ReadString();
+            break;
+          }
+          case 122: {
+            SingleBytes = input.ReadBytes();
+            break;
+          }
+          case 146: {
+            if (singleNestedMessage_ == null) {
+              singleNestedMessage_ = new global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage();
+            }
+            input.ReadMessage(singleNestedMessage_);
+            break;
+          }
+          case 154: {
+            if (singleForeignMessage_ == null) {
+              singleForeignMessage_ = new global::Google.Protobuf.TestProtos.ForeignMessage();
+            }
+            input.ReadMessage(singleForeignMessage_);
+            break;
+          }
+          case 162: {
+            if (singleImportMessage_ == null) {
+              singleImportMessage_ = new global::Google.Protobuf.TestProtos.ImportMessage();
+            }
+            input.ReadMessage(singleImportMessage_);
+            break;
+          }
+          case 168: {
+            singleNestedEnum_ = (global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) input.ReadEnum();
+            break;
+          }
+          case 176: {
+            singleForeignEnum_ = (global::Google.Protobuf.TestProtos.ForeignEnum) input.ReadEnum();
+            break;
+          }
+          case 184: {
+            singleImportEnum_ = (global::Google.Protobuf.TestProtos.ImportEnum) input.ReadEnum();
+            break;
+          }
+          case 210: {
+            if (singlePublicImportMessage_ == null) {
+              singlePublicImportMessage_ = new global::Google.Protobuf.TestProtos.PublicImportMessage();
+            }
+            input.ReadMessage(singlePublicImportMessage_);
+            break;
+          }
+          case 250:
+          case 248: {
+            repeatedInt32_.AddEntriesFrom(input, _repeated_repeatedInt32_codec);
+            break;
+          }
+          case 258:
+          case 256: {
+            repeatedInt64_.AddEntriesFrom(input, _repeated_repeatedInt64_codec);
+            break;
+          }
+          case 266:
+          case 264: {
+            repeatedUint32_.AddEntriesFrom(input, _repeated_repeatedUint32_codec);
+            break;
+          }
+          case 274:
+          case 272: {
+            repeatedUint64_.AddEntriesFrom(input, _repeated_repeatedUint64_codec);
+            break;
+          }
+          case 282:
+          case 280: {
+            repeatedSint32_.AddEntriesFrom(input, _repeated_repeatedSint32_codec);
+            break;
+          }
+          case 290:
+          case 288: {
+            repeatedSint64_.AddEntriesFrom(input, _repeated_repeatedSint64_codec);
+            break;
+          }
+          case 298:
+          case 301: {
+            repeatedFixed32_.AddEntriesFrom(input, _repeated_repeatedFixed32_codec);
+            break;
+          }
+          case 306:
+          case 305: {
+            repeatedFixed64_.AddEntriesFrom(input, _repeated_repeatedFixed64_codec);
+            break;
+          }
+          case 314:
+          case 317: {
+            repeatedSfixed32_.AddEntriesFrom(input, _repeated_repeatedSfixed32_codec);
+            break;
+          }
+          case 322:
+          case 321: {
+            repeatedSfixed64_.AddEntriesFrom(input, _repeated_repeatedSfixed64_codec);
+            break;
+          }
+          case 330:
+          case 333: {
+            repeatedFloat_.AddEntriesFrom(input, _repeated_repeatedFloat_codec);
+            break;
+          }
+          case 338:
+          case 337: {
+            repeatedDouble_.AddEntriesFrom(input, _repeated_repeatedDouble_codec);
+            break;
+          }
+          case 346:
+          case 344: {
+            repeatedBool_.AddEntriesFrom(input, _repeated_repeatedBool_codec);
+            break;
+          }
+          case 354: {
+            repeatedString_.AddEntriesFrom(input, _repeated_repeatedString_codec);
+            break;
+          }
+          case 362: {
+            repeatedBytes_.AddEntriesFrom(input, _repeated_repeatedBytes_codec);
+            break;
+          }
+          case 386: {
+            repeatedNestedMessage_.AddEntriesFrom(input, _repeated_repeatedNestedMessage_codec);
+            break;
+          }
+          case 394: {
+            repeatedForeignMessage_.AddEntriesFrom(input, _repeated_repeatedForeignMessage_codec);
+            break;
+          }
+          case 402: {
+            repeatedImportMessage_.AddEntriesFrom(input, _repeated_repeatedImportMessage_codec);
+            break;
+          }
+          case 410:
+          case 408: {
+            repeatedNestedEnum_.AddEntriesFrom(input, _repeated_repeatedNestedEnum_codec);
+            break;
+          }
+          case 418:
+          case 416: {
+            repeatedForeignEnum_.AddEntriesFrom(input, _repeated_repeatedForeignEnum_codec);
+            break;
+          }
+          case 426:
+          case 424: {
+            repeatedImportEnum_.AddEntriesFrom(input, _repeated_repeatedImportEnum_codec);
+            break;
+          }
+          case 434: {
+            repeatedPublicImportMessage_.AddEntriesFrom(input, _repeated_repeatedPublicImportMessage_codec);
+            break;
+          }
+          case 888: {
+            OneofUint32 = input.ReadUInt32();
+            break;
+          }
+          case 898: {
+            global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage subBuilder = new global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage();
+            if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
+              subBuilder.MergeFrom(OneofNestedMessage);
+            }
+            input.ReadMessage(subBuilder);
+            OneofNestedMessage = subBuilder;
+            break;
+          }
+          case 906: {
+            OneofString = input.ReadString();
+            break;
+          }
+          case 914: {
+            OneofBytes = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the TestAllTypes message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum NestedEnum {
+        [pbr::OriginalName("NESTED_ENUM_UNSPECIFIED")] Unspecified = 0,
+        [pbr::OriginalName("FOO")] Foo = 1,
+        [pbr::OriginalName("BAR")] Bar = 2,
+        [pbr::OriginalName("BAZ")] Baz = 3,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
+        [pbr::OriginalName("NEG")] Neg = -1,
+      }
+
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class NestedMessage : pb::IMessage<NestedMessage> {
+        private static readonly pb::MessageParser<NestedMessage> _parser = new pb::MessageParser<NestedMessage>(() => new NestedMessage());
+        public static pb::MessageParser<NestedMessage> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.TestProtos.TestAllTypes.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NestedMessage() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NestedMessage(NestedMessage other) : this() {
+          bb_ = other.bb_;
+        }
+
+        public NestedMessage Clone() {
+          return new NestedMessage(this);
+        }
+
+        /// <summary>Field number for the "bb" field.</summary>
+        public const int BbFieldNumber = 1;
+        private int bb_;
+        /// <summary>
+        ///  The field name "b" fails to compile in proto1 because it conflicts with
+        ///  a local variable named "b" in one of the generated methods.  Doh.
+        ///  This file needs to compile in proto1 to test backwards-compatibility.
+        /// </summary>
+        public int Bb {
+          get { return bb_; }
+          set {
+            bb_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NestedMessage);
+        }
+
+        public bool Equals(NestedMessage other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Bb != other.Bb) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Bb != 0) hash ^= Bb.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Bb != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Bb);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Bb != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Bb);
+          }
+          return size;
+        }
+
+        public void MergeFrom(NestedMessage other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Bb != 0) {
+            Bb = other.Bb;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Bb = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  This proto includes a recusively nested message.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class NestedTestAllTypes : pb::IMessage<NestedTestAllTypes> {
+    private static readonly pb::MessageParser<NestedTestAllTypes> _parser = new pb::MessageParser<NestedTestAllTypes>(() => new NestedTestAllTypes());
+    public static pb::MessageParser<NestedTestAllTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public NestedTestAllTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public NestedTestAllTypes(NestedTestAllTypes other) : this() {
+      Child = other.child_ != null ? other.Child.Clone() : null;
+      Payload = other.payload_ != null ? other.Payload.Clone() : null;
+      repeatedChild_ = other.repeatedChild_.Clone();
+    }
+
+    public NestedTestAllTypes Clone() {
+      return new NestedTestAllTypes(this);
+    }
+
+    /// <summary>Field number for the "child" field.</summary>
+    public const int ChildFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.NestedTestAllTypes child_;
+    public global::Google.Protobuf.TestProtos.NestedTestAllTypes Child {
+      get { return child_; }
+      set {
+        child_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "payload" field.</summary>
+    public const int PayloadFieldNumber = 2;
+    private global::Google.Protobuf.TestProtos.TestAllTypes payload_;
+    public global::Google.Protobuf.TestProtos.TestAllTypes Payload {
+      get { return payload_; }
+      set {
+        payload_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_child" field.</summary>
+    public const int RepeatedChildFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.NestedTestAllTypes> _repeated_repeatedChild_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.TestProtos.NestedTestAllTypes.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.NestedTestAllTypes> repeatedChild_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.NestedTestAllTypes>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.NestedTestAllTypes> RepeatedChild {
+      get { return repeatedChild_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as NestedTestAllTypes);
+    }
+
+    public bool Equals(NestedTestAllTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(Child, other.Child)) return false;
+      if (!object.Equals(Payload, other.Payload)) return false;
+      if(!repeatedChild_.Equals(other.repeatedChild_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (child_ != null) hash ^= Child.GetHashCode();
+      if (payload_ != null) hash ^= Payload.GetHashCode();
+      hash ^= repeatedChild_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (child_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(Child);
+      }
+      if (payload_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(Payload);
+      }
+      repeatedChild_.WriteTo(output, _repeated_repeatedChild_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (child_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Child);
+      }
+      if (payload_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
+      }
+      size += repeatedChild_.CalculateSize(_repeated_repeatedChild_codec);
+      return size;
+    }
+
+    public void MergeFrom(NestedTestAllTypes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.child_ != null) {
+        if (child_ == null) {
+          child_ = new global::Google.Protobuf.TestProtos.NestedTestAllTypes();
+        }
+        Child.MergeFrom(other.Child);
+      }
+      if (other.payload_ != null) {
+        if (payload_ == null) {
+          payload_ = new global::Google.Protobuf.TestProtos.TestAllTypes();
+        }
+        Payload.MergeFrom(other.Payload);
+      }
+      repeatedChild_.Add(other.repeatedChild_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (child_ == null) {
+              child_ = new global::Google.Protobuf.TestProtos.NestedTestAllTypes();
+            }
+            input.ReadMessage(child_);
+            break;
+          }
+          case 18: {
+            if (payload_ == null) {
+              payload_ = new global::Google.Protobuf.TestProtos.TestAllTypes();
+            }
+            input.ReadMessage(payload_);
+            break;
+          }
+          case 26: {
+            repeatedChild_.AddEntriesFrom(input, _repeated_repeatedChild_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestDeprecatedFields : pb::IMessage<TestDeprecatedFields> {
+    private static readonly pb::MessageParser<TestDeprecatedFields> _parser = new pb::MessageParser<TestDeprecatedFields>(() => new TestDeprecatedFields());
+    public static pb::MessageParser<TestDeprecatedFields> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestDeprecatedFields() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestDeprecatedFields(TestDeprecatedFields other) : this() {
+      deprecatedInt32_ = other.deprecatedInt32_;
+    }
+
+    public TestDeprecatedFields Clone() {
+      return new TestDeprecatedFields(this);
+    }
+
+    /// <summary>Field number for the "deprecated_int32" field.</summary>
+    public const int DeprecatedInt32FieldNumber = 1;
+    private int deprecatedInt32_;
+    [global::System.ObsoleteAttribute()]
+    public int DeprecatedInt32 {
+      get { return deprecatedInt32_; }
+      set {
+        deprecatedInt32_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestDeprecatedFields);
+    }
+
+    public bool Equals(TestDeprecatedFields other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (DeprecatedInt32 != other.DeprecatedInt32) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (DeprecatedInt32 != 0) hash ^= DeprecatedInt32.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (DeprecatedInt32 != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(DeprecatedInt32);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (DeprecatedInt32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(DeprecatedInt32);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestDeprecatedFields other) {
+      if (other == null) {
+        return;
+      }
+      if (other.DeprecatedInt32 != 0) {
+        DeprecatedInt32 = other.DeprecatedInt32;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            DeprecatedInt32 = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Define these after TestAllTypes to make sure the compiler can handle
+  ///  that.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ForeignMessage : pb::IMessage<ForeignMessage> {
+    private static readonly pb::MessageParser<ForeignMessage> _parser = new pb::MessageParser<ForeignMessage>(() => new ForeignMessage());
+    public static pb::MessageParser<ForeignMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ForeignMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ForeignMessage(ForeignMessage other) : this() {
+      c_ = other.c_;
+    }
+
+    public ForeignMessage Clone() {
+      return new ForeignMessage(this);
+    }
+
+    /// <summary>Field number for the "c" field.</summary>
+    public const int CFieldNumber = 1;
+    private int c_;
+    public int C {
+      get { return c_; }
+      set {
+        c_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ForeignMessage);
+    }
+
+    public bool Equals(ForeignMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (C != other.C) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (C != 0) hash ^= C.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (C != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(C);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (C != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(C);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ForeignMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.C != 0) {
+        C = other.C;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            C = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestReservedFields : pb::IMessage<TestReservedFields> {
+    private static readonly pb::MessageParser<TestReservedFields> _parser = new pb::MessageParser<TestReservedFields>(() => new TestReservedFields());
+    public static pb::MessageParser<TestReservedFields> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestReservedFields() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestReservedFields(TestReservedFields other) : this() {
+    }
+
+    public TestReservedFields Clone() {
+      return new TestReservedFields(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestReservedFields);
+    }
+
+    public bool Equals(TestReservedFields other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(TestReservedFields other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test that we can use NestedMessage from outside TestAllTypes.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestForeignNested : pb::IMessage<TestForeignNested> {
+    private static readonly pb::MessageParser<TestForeignNested> _parser = new pb::MessageParser<TestForeignNested>(() => new TestForeignNested());
+    public static pb::MessageParser<TestForeignNested> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestForeignNested() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestForeignNested(TestForeignNested other) : this() {
+      ForeignNested = other.foreignNested_ != null ? other.ForeignNested.Clone() : null;
+    }
+
+    public TestForeignNested Clone() {
+      return new TestForeignNested(this);
+    }
+
+    /// <summary>Field number for the "foreign_nested" field.</summary>
+    public const int ForeignNestedFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage foreignNested_;
+    public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage ForeignNested {
+      get { return foreignNested_; }
+      set {
+        foreignNested_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestForeignNested);
+    }
+
+    public bool Equals(TestForeignNested other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(ForeignNested, other.ForeignNested)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (foreignNested_ != null) hash ^= ForeignNested.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (foreignNested_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(ForeignNested);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (foreignNested_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ForeignNested);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestForeignNested other) {
+      if (other == null) {
+        return;
+      }
+      if (other.foreignNested_ != null) {
+        if (foreignNested_ == null) {
+          foreignNested_ = new global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage();
+        }
+        ForeignNested.MergeFrom(other.ForeignNested);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (foreignNested_ == null) {
+              foreignNested_ = new global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage();
+            }
+            input.ReadMessage(foreignNested_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test that really large tag numbers don't break anything.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestReallyLargeTagNumber : pb::IMessage<TestReallyLargeTagNumber> {
+    private static readonly pb::MessageParser<TestReallyLargeTagNumber> _parser = new pb::MessageParser<TestReallyLargeTagNumber>(() => new TestReallyLargeTagNumber());
+    public static pb::MessageParser<TestReallyLargeTagNumber> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestReallyLargeTagNumber() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestReallyLargeTagNumber(TestReallyLargeTagNumber other) : this() {
+      a_ = other.a_;
+      bb_ = other.bb_;
+    }
+
+    public TestReallyLargeTagNumber Clone() {
+      return new TestReallyLargeTagNumber(this);
+    }
+
+    /// <summary>Field number for the "a" field.</summary>
+    public const int AFieldNumber = 1;
+    private int a_;
+    /// <summary>
+    ///  The largest possible tag number is 2^28 - 1, since the wire format uses
+    ///  three bits to communicate wire type.
+    /// </summary>
+    public int A {
+      get { return a_; }
+      set {
+        a_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "bb" field.</summary>
+    public const int BbFieldNumber = 268435455;
+    private int bb_;
+    public int Bb {
+      get { return bb_; }
+      set {
+        bb_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestReallyLargeTagNumber);
+    }
+
+    public bool Equals(TestReallyLargeTagNumber other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (A != other.A) return false;
+      if (Bb != other.Bb) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (A != 0) hash ^= A.GetHashCode();
+      if (Bb != 0) hash ^= Bb.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (A != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(A);
+      }
+      if (Bb != 0) {
+        output.WriteRawTag(248, 255, 255, 255, 7);
+        output.WriteInt32(Bb);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (A != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(A);
+      }
+      if (Bb != 0) {
+        size += 5 + pb::CodedOutputStream.ComputeInt32Size(Bb);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestReallyLargeTagNumber other) {
+      if (other == null) {
+        return;
+      }
+      if (other.A != 0) {
+        A = other.A;
+      }
+      if (other.Bb != 0) {
+        Bb = other.Bb;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            A = input.ReadInt32();
+            break;
+          }
+          case 2147483640: {
+            Bb = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestRecursiveMessage : pb::IMessage<TestRecursiveMessage> {
+    private static readonly pb::MessageParser<TestRecursiveMessage> _parser = new pb::MessageParser<TestRecursiveMessage>(() => new TestRecursiveMessage());
+    public static pb::MessageParser<TestRecursiveMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestRecursiveMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestRecursiveMessage(TestRecursiveMessage other) : this() {
+      A = other.a_ != null ? other.A.Clone() : null;
+      i_ = other.i_;
+    }
+
+    public TestRecursiveMessage Clone() {
+      return new TestRecursiveMessage(this);
+    }
+
+    /// <summary>Field number for the "a" field.</summary>
+    public const int AFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestRecursiveMessage a_;
+    public global::Google.Protobuf.TestProtos.TestRecursiveMessage A {
+      get { return a_; }
+      set {
+        a_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "i" field.</summary>
+    public const int IFieldNumber = 2;
+    private int i_;
+    public int I {
+      get { return i_; }
+      set {
+        i_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestRecursiveMessage);
+    }
+
+    public bool Equals(TestRecursiveMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(A, other.A)) return false;
+      if (I != other.I) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (a_ != null) hash ^= A.GetHashCode();
+      if (I != 0) hash ^= I.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (a_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(A);
+      }
+      if (I != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(I);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (a_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(A);
+      }
+      if (I != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(I);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestRecursiveMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.a_ != null) {
+        if (a_ == null) {
+          a_ = new global::Google.Protobuf.TestProtos.TestRecursiveMessage();
+        }
+        A.MergeFrom(other.A);
+      }
+      if (other.I != 0) {
+        I = other.I;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (a_ == null) {
+              a_ = new global::Google.Protobuf.TestProtos.TestRecursiveMessage();
+            }
+            input.ReadMessage(a_);
+            break;
+          }
+          case 16: {
+            I = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test that mutual recursion works.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestMutualRecursionA : pb::IMessage<TestMutualRecursionA> {
+    private static readonly pb::MessageParser<TestMutualRecursionA> _parser = new pb::MessageParser<TestMutualRecursionA>(() => new TestMutualRecursionA());
+    public static pb::MessageParser<TestMutualRecursionA> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[8]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestMutualRecursionA() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestMutualRecursionA(TestMutualRecursionA other) : this() {
+      Bb = other.bb_ != null ? other.Bb.Clone() : null;
+    }
+
+    public TestMutualRecursionA Clone() {
+      return new TestMutualRecursionA(this);
+    }
+
+    /// <summary>Field number for the "bb" field.</summary>
+    public const int BbFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestMutualRecursionB bb_;
+    public global::Google.Protobuf.TestProtos.TestMutualRecursionB Bb {
+      get { return bb_; }
+      set {
+        bb_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestMutualRecursionA);
+    }
+
+    public bool Equals(TestMutualRecursionA other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(Bb, other.Bb)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (bb_ != null) hash ^= Bb.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (bb_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(Bb);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (bb_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Bb);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestMutualRecursionA other) {
+      if (other == null) {
+        return;
+      }
+      if (other.bb_ != null) {
+        if (bb_ == null) {
+          bb_ = new global::Google.Protobuf.TestProtos.TestMutualRecursionB();
+        }
+        Bb.MergeFrom(other.Bb);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (bb_ == null) {
+              bb_ = new global::Google.Protobuf.TestProtos.TestMutualRecursionB();
+            }
+            input.ReadMessage(bb_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestMutualRecursionB : pb::IMessage<TestMutualRecursionB> {
+    private static readonly pb::MessageParser<TestMutualRecursionB> _parser = new pb::MessageParser<TestMutualRecursionB>(() => new TestMutualRecursionB());
+    public static pb::MessageParser<TestMutualRecursionB> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[9]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestMutualRecursionB() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestMutualRecursionB(TestMutualRecursionB other) : this() {
+      A = other.a_ != null ? other.A.Clone() : null;
+      optionalInt32_ = other.optionalInt32_;
+    }
+
+    public TestMutualRecursionB Clone() {
+      return new TestMutualRecursionB(this);
+    }
+
+    /// <summary>Field number for the "a" field.</summary>
+    public const int AFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestMutualRecursionA a_;
+    public global::Google.Protobuf.TestProtos.TestMutualRecursionA A {
+      get { return a_; }
+      set {
+        a_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int32" field.</summary>
+    public const int OptionalInt32FieldNumber = 2;
+    private int optionalInt32_;
+    public int OptionalInt32 {
+      get { return optionalInt32_; }
+      set {
+        optionalInt32_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestMutualRecursionB);
+    }
+
+    public bool Equals(TestMutualRecursionB other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(A, other.A)) return false;
+      if (OptionalInt32 != other.OptionalInt32) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (a_ != null) hash ^= A.GetHashCode();
+      if (OptionalInt32 != 0) hash ^= OptionalInt32.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (a_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(A);
+      }
+      if (OptionalInt32 != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(OptionalInt32);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (a_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(A);
+      }
+      if (OptionalInt32 != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OptionalInt32);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestMutualRecursionB other) {
+      if (other == null) {
+        return;
+      }
+      if (other.a_ != null) {
+        if (a_ == null) {
+          a_ = new global::Google.Protobuf.TestProtos.TestMutualRecursionA();
+        }
+        A.MergeFrom(other.A);
+      }
+      if (other.OptionalInt32 != 0) {
+        OptionalInt32 = other.OptionalInt32;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (a_ == null) {
+              a_ = new global::Google.Protobuf.TestProtos.TestMutualRecursionA();
+            }
+            input.ReadMessage(a_);
+            break;
+          }
+          case 16: {
+            OptionalInt32 = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test message with CamelCase field names.  This violates Protocol Buffer
+  ///  standard style.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestCamelCaseFieldNames : pb::IMessage<TestCamelCaseFieldNames> {
+    private static readonly pb::MessageParser<TestCamelCaseFieldNames> _parser = new pb::MessageParser<TestCamelCaseFieldNames>(() => new TestCamelCaseFieldNames());
+    public static pb::MessageParser<TestCamelCaseFieldNames> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[10]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestCamelCaseFieldNames() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestCamelCaseFieldNames(TestCamelCaseFieldNames other) : this() {
+      primitiveField_ = other.primitiveField_;
+      stringField_ = other.stringField_;
+      enumField_ = other.enumField_;
+      MessageField = other.messageField_ != null ? other.MessageField.Clone() : null;
+      repeatedPrimitiveField_ = other.repeatedPrimitiveField_.Clone();
+      repeatedStringField_ = other.repeatedStringField_.Clone();
+      repeatedEnumField_ = other.repeatedEnumField_.Clone();
+      repeatedMessageField_ = other.repeatedMessageField_.Clone();
+    }
+
+    public TestCamelCaseFieldNames Clone() {
+      return new TestCamelCaseFieldNames(this);
+    }
+
+    /// <summary>Field number for the "PrimitiveField" field.</summary>
+    public const int PrimitiveFieldFieldNumber = 1;
+    private int primitiveField_;
+    public int PrimitiveField {
+      get { return primitiveField_; }
+      set {
+        primitiveField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "StringField" field.</summary>
+    public const int StringFieldFieldNumber = 2;
+    private string stringField_ = "";
+    public string StringField {
+      get { return stringField_; }
+      set {
+        stringField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "EnumField" field.</summary>
+    public const int EnumFieldFieldNumber = 3;
+    private global::Google.Protobuf.TestProtos.ForeignEnum enumField_ = 0;
+    public global::Google.Protobuf.TestProtos.ForeignEnum EnumField {
+      get { return enumField_; }
+      set {
+        enumField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "MessageField" field.</summary>
+    public const int MessageFieldFieldNumber = 4;
+    private global::Google.Protobuf.TestProtos.ForeignMessage messageField_;
+    public global::Google.Protobuf.TestProtos.ForeignMessage MessageField {
+      get { return messageField_; }
+      set {
+        messageField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "RepeatedPrimitiveField" field.</summary>
+    public const int RepeatedPrimitiveFieldFieldNumber = 7;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedPrimitiveField_codec
+        = pb::FieldCodec.ForInt32(58);
+    private readonly pbc::RepeatedField<int> repeatedPrimitiveField_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> RepeatedPrimitiveField {
+      get { return repeatedPrimitiveField_; }
+    }
+
+    /// <summary>Field number for the "RepeatedStringField" field.</summary>
+    public const int RepeatedStringFieldFieldNumber = 8;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedStringField_codec
+        = pb::FieldCodec.ForString(66);
+    private readonly pbc::RepeatedField<string> repeatedStringField_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedStringField {
+      get { return repeatedStringField_; }
+    }
+
+    /// <summary>Field number for the "RepeatedEnumField" field.</summary>
+    public const int RepeatedEnumFieldFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_repeatedEnumField_codec
+        = pb::FieldCodec.ForEnum(74, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> repeatedEnumField_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> RepeatedEnumField {
+      get { return repeatedEnumField_; }
+    }
+
+    /// <summary>Field number for the "RepeatedMessageField" field.</summary>
+    public const int RepeatedMessageFieldFieldNumber = 10;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignMessage> _repeated_repeatedMessageField_codec
+        = pb::FieldCodec.ForMessage(82, global::Google.Protobuf.TestProtos.ForeignMessage.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage> repeatedMessageField_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignMessage> RepeatedMessageField {
+      get { return repeatedMessageField_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestCamelCaseFieldNames);
+    }
+
+    public bool Equals(TestCamelCaseFieldNames other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (PrimitiveField != other.PrimitiveField) return false;
+      if (StringField != other.StringField) return false;
+      if (EnumField != other.EnumField) return false;
+      if (!object.Equals(MessageField, other.MessageField)) return false;
+      if(!repeatedPrimitiveField_.Equals(other.repeatedPrimitiveField_)) return false;
+      if(!repeatedStringField_.Equals(other.repeatedStringField_)) return false;
+      if(!repeatedEnumField_.Equals(other.repeatedEnumField_)) return false;
+      if(!repeatedMessageField_.Equals(other.repeatedMessageField_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (PrimitiveField != 0) hash ^= PrimitiveField.GetHashCode();
+      if (StringField.Length != 0) hash ^= StringField.GetHashCode();
+      if (EnumField != 0) hash ^= EnumField.GetHashCode();
+      if (messageField_ != null) hash ^= MessageField.GetHashCode();
+      hash ^= repeatedPrimitiveField_.GetHashCode();
+      hash ^= repeatedStringField_.GetHashCode();
+      hash ^= repeatedEnumField_.GetHashCode();
+      hash ^= repeatedMessageField_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (PrimitiveField != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(PrimitiveField);
+      }
+      if (StringField.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(StringField);
+      }
+      if (EnumField != 0) {
+        output.WriteRawTag(24);
+        output.WriteEnum((int) EnumField);
+      }
+      if (messageField_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(MessageField);
+      }
+      repeatedPrimitiveField_.WriteTo(output, _repeated_repeatedPrimitiveField_codec);
+      repeatedStringField_.WriteTo(output, _repeated_repeatedStringField_codec);
+      repeatedEnumField_.WriteTo(output, _repeated_repeatedEnumField_codec);
+      repeatedMessageField_.WriteTo(output, _repeated_repeatedMessageField_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (PrimitiveField != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(PrimitiveField);
+      }
+      if (StringField.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(StringField);
+      }
+      if (EnumField != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) EnumField);
+      }
+      if (messageField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(MessageField);
+      }
+      size += repeatedPrimitiveField_.CalculateSize(_repeated_repeatedPrimitiveField_codec);
+      size += repeatedStringField_.CalculateSize(_repeated_repeatedStringField_codec);
+      size += repeatedEnumField_.CalculateSize(_repeated_repeatedEnumField_codec);
+      size += repeatedMessageField_.CalculateSize(_repeated_repeatedMessageField_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestCamelCaseFieldNames other) {
+      if (other == null) {
+        return;
+      }
+      if (other.PrimitiveField != 0) {
+        PrimitiveField = other.PrimitiveField;
+      }
+      if (other.StringField.Length != 0) {
+        StringField = other.StringField;
+      }
+      if (other.EnumField != 0) {
+        EnumField = other.EnumField;
+      }
+      if (other.messageField_ != null) {
+        if (messageField_ == null) {
+          messageField_ = new global::Google.Protobuf.TestProtos.ForeignMessage();
+        }
+        MessageField.MergeFrom(other.MessageField);
+      }
+      repeatedPrimitiveField_.Add(other.repeatedPrimitiveField_);
+      repeatedStringField_.Add(other.repeatedStringField_);
+      repeatedEnumField_.Add(other.repeatedEnumField_);
+      repeatedMessageField_.Add(other.repeatedMessageField_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            PrimitiveField = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            StringField = input.ReadString();
+            break;
+          }
+          case 24: {
+            enumField_ = (global::Google.Protobuf.TestProtos.ForeignEnum) input.ReadEnum();
+            break;
+          }
+          case 34: {
+            if (messageField_ == null) {
+              messageField_ = new global::Google.Protobuf.TestProtos.ForeignMessage();
+            }
+            input.ReadMessage(messageField_);
+            break;
+          }
+          case 58:
+          case 56: {
+            repeatedPrimitiveField_.AddEntriesFrom(input, _repeated_repeatedPrimitiveField_codec);
+            break;
+          }
+          case 66: {
+            repeatedStringField_.AddEntriesFrom(input, _repeated_repeatedStringField_codec);
+            break;
+          }
+          case 74:
+          case 72: {
+            repeatedEnumField_.AddEntriesFrom(input, _repeated_repeatedEnumField_codec);
+            break;
+          }
+          case 82: {
+            repeatedMessageField_.AddEntriesFrom(input, _repeated_repeatedMessageField_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  We list fields out of order, to ensure that we're using field number and not
+  ///  field index to determine serialization order.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestFieldOrderings : pb::IMessage<TestFieldOrderings> {
+    private static readonly pb::MessageParser<TestFieldOrderings> _parser = new pb::MessageParser<TestFieldOrderings>(() => new TestFieldOrderings());
+    public static pb::MessageParser<TestFieldOrderings> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[11]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestFieldOrderings() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestFieldOrderings(TestFieldOrderings other) : this() {
+      myString_ = other.myString_;
+      myInt_ = other.myInt_;
+      myFloat_ = other.myFloat_;
+      SingleNestedMessage = other.singleNestedMessage_ != null ? other.SingleNestedMessage.Clone() : null;
+    }
+
+    public TestFieldOrderings Clone() {
+      return new TestFieldOrderings(this);
+    }
+
+    /// <summary>Field number for the "my_string" field.</summary>
+    public const int MyStringFieldNumber = 11;
+    private string myString_ = "";
+    public string MyString {
+      get { return myString_; }
+      set {
+        myString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "my_int" field.</summary>
+    public const int MyIntFieldNumber = 1;
+    private long myInt_;
+    public long MyInt {
+      get { return myInt_; }
+      set {
+        myInt_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "my_float" field.</summary>
+    public const int MyFloatFieldNumber = 101;
+    private float myFloat_;
+    public float MyFloat {
+      get { return myFloat_; }
+      set {
+        myFloat_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "single_nested_message" field.</summary>
+    public const int SingleNestedMessageFieldNumber = 200;
+    private global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage singleNestedMessage_;
+    public global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage SingleNestedMessage {
+      get { return singleNestedMessage_; }
+      set {
+        singleNestedMessage_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestFieldOrderings);
+    }
+
+    public bool Equals(TestFieldOrderings other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (MyString != other.MyString) return false;
+      if (MyInt != other.MyInt) return false;
+      if (MyFloat != other.MyFloat) return false;
+      if (!object.Equals(SingleNestedMessage, other.SingleNestedMessage)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (MyString.Length != 0) hash ^= MyString.GetHashCode();
+      if (MyInt != 0L) hash ^= MyInt.GetHashCode();
+      if (MyFloat != 0F) hash ^= MyFloat.GetHashCode();
+      if (singleNestedMessage_ != null) hash ^= SingleNestedMessage.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (MyInt != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(MyInt);
+      }
+      if (MyString.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(MyString);
+      }
+      if (MyFloat != 0F) {
+        output.WriteRawTag(173, 6);
+        output.WriteFloat(MyFloat);
+      }
+      if (singleNestedMessage_ != null) {
+        output.WriteRawTag(194, 12);
+        output.WriteMessage(SingleNestedMessage);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (MyString.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(MyString);
+      }
+      if (MyInt != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(MyInt);
+      }
+      if (MyFloat != 0F) {
+        size += 2 + 4;
+      }
+      if (singleNestedMessage_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(SingleNestedMessage);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestFieldOrderings other) {
+      if (other == null) {
+        return;
+      }
+      if (other.MyString.Length != 0) {
+        MyString = other.MyString;
+      }
+      if (other.MyInt != 0L) {
+        MyInt = other.MyInt;
+      }
+      if (other.MyFloat != 0F) {
+        MyFloat = other.MyFloat;
+      }
+      if (other.singleNestedMessage_ != null) {
+        if (singleNestedMessage_ == null) {
+          singleNestedMessage_ = new global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage();
+        }
+        SingleNestedMessage.MergeFrom(other.SingleNestedMessage);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            MyInt = input.ReadInt64();
+            break;
+          }
+          case 90: {
+            MyString = input.ReadString();
+            break;
+          }
+          case 813: {
+            MyFloat = input.ReadFloat();
+            break;
+          }
+          case 1602: {
+            if (singleNestedMessage_ == null) {
+              singleNestedMessage_ = new global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage();
+            }
+            input.ReadMessage(singleNestedMessage_);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the TestFieldOrderings message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class NestedMessage : pb::IMessage<NestedMessage> {
+        private static readonly pb::MessageParser<NestedMessage> _parser = new pb::MessageParser<NestedMessage>(() => new NestedMessage());
+        public static pb::MessageParser<NestedMessage> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.TestProtos.TestFieldOrderings.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NestedMessage() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NestedMessage(NestedMessage other) : this() {
+          oo_ = other.oo_;
+          bb_ = other.bb_;
+        }
+
+        public NestedMessage Clone() {
+          return new NestedMessage(this);
+        }
+
+        /// <summary>Field number for the "oo" field.</summary>
+        public const int OoFieldNumber = 2;
+        private long oo_;
+        public long Oo {
+          get { return oo_; }
+          set {
+            oo_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "bb" field.</summary>
+        public const int BbFieldNumber = 1;
+        private int bb_;
+        /// <summary>
+        ///  The field name "b" fails to compile in proto1 because it conflicts with
+        ///  a local variable named "b" in one of the generated methods.  Doh.
+        ///  This file needs to compile in proto1 to test backwards-compatibility.
+        /// </summary>
+        public int Bb {
+          get { return bb_; }
+          set {
+            bb_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NestedMessage);
+        }
+
+        public bool Equals(NestedMessage other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Oo != other.Oo) return false;
+          if (Bb != other.Bb) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Oo != 0L) hash ^= Oo.GetHashCode();
+          if (Bb != 0) hash ^= Bb.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Bb != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Bb);
+          }
+          if (Oo != 0L) {
+            output.WriteRawTag(16);
+            output.WriteInt64(Oo);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Oo != 0L) {
+            size += 1 + pb::CodedOutputStream.ComputeInt64Size(Oo);
+          }
+          if (Bb != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Bb);
+          }
+          return size;
+        }
+
+        public void MergeFrom(NestedMessage other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Oo != 0L) {
+            Oo = other.Oo;
+          }
+          if (other.Bb != 0) {
+            Bb = other.Bb;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Bb = input.ReadInt32();
+                break;
+              }
+              case 16: {
+                Oo = input.ReadInt64();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class SparseEnumMessage : pb::IMessage<SparseEnumMessage> {
+    private static readonly pb::MessageParser<SparseEnumMessage> _parser = new pb::MessageParser<SparseEnumMessage>(() => new SparseEnumMessage());
+    public static pb::MessageParser<SparseEnumMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[12]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public SparseEnumMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public SparseEnumMessage(SparseEnumMessage other) : this() {
+      sparseEnum_ = other.sparseEnum_;
+    }
+
+    public SparseEnumMessage Clone() {
+      return new SparseEnumMessage(this);
+    }
+
+    /// <summary>Field number for the "sparse_enum" field.</summary>
+    public const int SparseEnumFieldNumber = 1;
+    private global::Google.Protobuf.TestProtos.TestSparseEnum sparseEnum_ = 0;
+    public global::Google.Protobuf.TestProtos.TestSparseEnum SparseEnum {
+      get { return sparseEnum_; }
+      set {
+        sparseEnum_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as SparseEnumMessage);
+    }
+
+    public bool Equals(SparseEnumMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (SparseEnum != other.SparseEnum) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (SparseEnum != 0) hash ^= SparseEnum.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (SparseEnum != 0) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) SparseEnum);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (SparseEnum != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SparseEnum);
+      }
+      return size;
+    }
+
+    public void MergeFrom(SparseEnumMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.SparseEnum != 0) {
+        SparseEnum = other.SparseEnum;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            sparseEnum_ = (global::Google.Protobuf.TestProtos.TestSparseEnum) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test String and Bytes: string is for valid UTF-8 strings
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class OneString : pb::IMessage<OneString> {
+    private static readonly pb::MessageParser<OneString> _parser = new pb::MessageParser<OneString>(() => new OneString());
+    public static pb::MessageParser<OneString> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[13]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public OneString() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public OneString(OneString other) : this() {
+      data_ = other.data_;
+    }
+
+    public OneString Clone() {
+      return new OneString(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private string data_ = "";
+    public string Data {
+      get { return data_; }
+      set {
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as OneString);
+    }
+
+    public bool Equals(OneString other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data.Length != 0) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(OneString other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data.Length != 0) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Data = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class MoreString : pb::IMessage<MoreString> {
+    private static readonly pb::MessageParser<MoreString> _parser = new pb::MessageParser<MoreString>(() => new MoreString());
+    public static pb::MessageParser<MoreString> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[14]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MoreString() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MoreString(MoreString other) : this() {
+      data_ = other.data_.Clone();
+    }
+
+    public MoreString Clone() {
+      return new MoreString(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private static readonly pb::FieldCodec<string> _repeated_data_codec
+        = pb::FieldCodec.ForString(10);
+    private readonly pbc::RepeatedField<string> data_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> Data {
+      get { return data_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MoreString);
+    }
+
+    public bool Equals(MoreString other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!data_.Equals(other.data_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= data_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      data_.WriteTo(output, _repeated_data_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += data_.CalculateSize(_repeated_data_codec);
+      return size;
+    }
+
+    public void MergeFrom(MoreString other) {
+      if (other == null) {
+        return;
+      }
+      data_.Add(other.data_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            data_.AddEntriesFrom(input, _repeated_data_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class OneBytes : pb::IMessage<OneBytes> {
+    private static readonly pb::MessageParser<OneBytes> _parser = new pb::MessageParser<OneBytes>(() => new OneBytes());
+    public static pb::MessageParser<OneBytes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[15]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public OneBytes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public OneBytes(OneBytes other) : this() {
+      data_ = other.data_;
+    }
+
+    public OneBytes Clone() {
+      return new OneBytes(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private pb::ByteString data_ = pb::ByteString.Empty;
+    public pb::ByteString Data {
+      get { return data_; }
+      set {
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as OneBytes);
+    }
+
+    public bool Equals(OneBytes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data.Length != 0) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteBytes(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(OneBytes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data.Length != 0) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Data = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class MoreBytes : pb::IMessage<MoreBytes> {
+    private static readonly pb::MessageParser<MoreBytes> _parser = new pb::MessageParser<MoreBytes>(() => new MoreBytes());
+    public static pb::MessageParser<MoreBytes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[16]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MoreBytes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MoreBytes(MoreBytes other) : this() {
+      data_ = other.data_;
+    }
+
+    public MoreBytes Clone() {
+      return new MoreBytes(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private pb::ByteString data_ = pb::ByteString.Empty;
+    public pb::ByteString Data {
+      get { return data_; }
+      set {
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MoreBytes);
+    }
+
+    public bool Equals(MoreBytes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data.Length != 0) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteBytes(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(MoreBytes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data.Length != 0) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Data = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test int32, uint32, int64, uint64, and bool are all compatible
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int32Message : pb::IMessage<Int32Message> {
+    private static readonly pb::MessageParser<Int32Message> _parser = new pb::MessageParser<Int32Message>(() => new Int32Message());
+    public static pb::MessageParser<Int32Message> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[17]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int32Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int32Message(Int32Message other) : this() {
+      data_ = other.data_;
+    }
+
+    public Int32Message Clone() {
+      return new Int32Message(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private int data_;
+    public int Data {
+      get { return data_; }
+      set {
+        data_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int32Message);
+    }
+
+    public bool Equals(Int32Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data != 0) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int32Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data != 0) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Data = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Uint32Message : pb::IMessage<Uint32Message> {
+    private static readonly pb::MessageParser<Uint32Message> _parser = new pb::MessageParser<Uint32Message>(() => new Uint32Message());
+    public static pb::MessageParser<Uint32Message> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[18]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Uint32Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Uint32Message(Uint32Message other) : this() {
+      data_ = other.data_;
+    }
+
+    public Uint32Message Clone() {
+      return new Uint32Message(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private uint data_;
+    public uint Data {
+      get { return data_; }
+      set {
+        data_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Uint32Message);
+    }
+
+    public bool Equals(Uint32Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data != 0) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data != 0) {
+        output.WriteRawTag(8);
+        output.WriteUInt32(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Uint32Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data != 0) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Data = input.ReadUInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int64Message : pb::IMessage<Int64Message> {
+    private static readonly pb::MessageParser<Int64Message> _parser = new pb::MessageParser<Int64Message>(() => new Int64Message());
+    public static pb::MessageParser<Int64Message> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[19]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int64Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int64Message(Int64Message other) : this() {
+      data_ = other.data_;
+    }
+
+    public Int64Message Clone() {
+      return new Int64Message(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private long data_;
+    public long Data {
+      get { return data_; }
+      set {
+        data_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int64Message);
+    }
+
+    public bool Equals(Int64Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data != 0L) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int64Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data != 0L) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Data = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Uint64Message : pb::IMessage<Uint64Message> {
+    private static readonly pb::MessageParser<Uint64Message> _parser = new pb::MessageParser<Uint64Message>(() => new Uint64Message());
+    public static pb::MessageParser<Uint64Message> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[20]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Uint64Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Uint64Message(Uint64Message other) : this() {
+      data_ = other.data_;
+    }
+
+    public Uint64Message Clone() {
+      return new Uint64Message(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private ulong data_;
+    public ulong Data {
+      get { return data_; }
+      set {
+        data_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Uint64Message);
+    }
+
+    public bool Equals(Uint64Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data != 0UL) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data != 0UL) {
+        output.WriteRawTag(8);
+        output.WriteUInt64(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Data);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Uint64Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data != 0UL) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Data = input.ReadUInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BoolMessage : pb::IMessage<BoolMessage> {
+    private static readonly pb::MessageParser<BoolMessage> _parser = new pb::MessageParser<BoolMessage>(() => new BoolMessage());
+    public static pb::MessageParser<BoolMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[21]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BoolMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BoolMessage(BoolMessage other) : this() {
+      data_ = other.data_;
+    }
+
+    public BoolMessage Clone() {
+      return new BoolMessage(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private bool data_;
+    public bool Data {
+      get { return data_; }
+      set {
+        data_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BoolMessage);
+    }
+
+    public bool Equals(BoolMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Data != false) hash ^= Data.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Data != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Data);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Data != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(BoolMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Data != false) {
+        Data = other.Data;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Data = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test oneofs.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestOneof : pb::IMessage<TestOneof> {
+    private static readonly pb::MessageParser<TestOneof> _parser = new pb::MessageParser<TestOneof>(() => new TestOneof());
+    public static pb::MessageParser<TestOneof> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[22]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestOneof() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestOneof(TestOneof other) : this() {
+      switch (other.FooCase) {
+        case FooOneofCase.FooInt:
+          FooInt = other.FooInt;
+          break;
+        case FooOneofCase.FooString:
+          FooString = other.FooString;
+          break;
+        case FooOneofCase.FooMessage:
+          FooMessage = other.FooMessage.Clone();
+          break;
+      }
+
+    }
+
+    public TestOneof Clone() {
+      return new TestOneof(this);
+    }
+
+    /// <summary>Field number for the "foo_int" field.</summary>
+    public const int FooIntFieldNumber = 1;
+    public int FooInt {
+      get { return fooCase_ == FooOneofCase.FooInt ? (int) foo_ : 0; }
+      set {
+        foo_ = value;
+        fooCase_ = FooOneofCase.FooInt;
+      }
+    }
+
+    /// <summary>Field number for the "foo_string" field.</summary>
+    public const int FooStringFieldNumber = 2;
+    public string FooString {
+      get { return fooCase_ == FooOneofCase.FooString ? (string) foo_ : ""; }
+      set {
+        foo_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        fooCase_ = FooOneofCase.FooString;
+      }
+    }
+
+    /// <summary>Field number for the "foo_message" field.</summary>
+    public const int FooMessageFieldNumber = 3;
+    public global::Google.Protobuf.TestProtos.TestAllTypes FooMessage {
+      get { return fooCase_ == FooOneofCase.FooMessage ? (global::Google.Protobuf.TestProtos.TestAllTypes) foo_ : null; }
+      set {
+        foo_ = value;
+        fooCase_ = value == null ? FooOneofCase.None : FooOneofCase.FooMessage;
+      }
+    }
+
+    private object foo_;
+    /// <summary>Enum of possible cases for the "foo" oneof.</summary>
+    public enum FooOneofCase {
+      None = 0,
+      FooInt = 1,
+      FooString = 2,
+      FooMessage = 3,
+    }
+    private FooOneofCase fooCase_ = FooOneofCase.None;
+    public FooOneofCase FooCase {
+      get { return fooCase_; }
+    }
+
+    public void ClearFoo() {
+      fooCase_ = FooOneofCase.None;
+      foo_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestOneof);
+    }
+
+    public bool Equals(TestOneof other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (FooInt != other.FooInt) return false;
+      if (FooString != other.FooString) return false;
+      if (!object.Equals(FooMessage, other.FooMessage)) return false;
+      if (FooCase != other.FooCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (fooCase_ == FooOneofCase.FooInt) hash ^= FooInt.GetHashCode();
+      if (fooCase_ == FooOneofCase.FooString) hash ^= FooString.GetHashCode();
+      if (fooCase_ == FooOneofCase.FooMessage) hash ^= FooMessage.GetHashCode();
+      hash ^= (int) fooCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (fooCase_ == FooOneofCase.FooInt) {
+        output.WriteRawTag(8);
+        output.WriteInt32(FooInt);
+      }
+      if (fooCase_ == FooOneofCase.FooString) {
+        output.WriteRawTag(18);
+        output.WriteString(FooString);
+      }
+      if (fooCase_ == FooOneofCase.FooMessage) {
+        output.WriteRawTag(26);
+        output.WriteMessage(FooMessage);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (fooCase_ == FooOneofCase.FooInt) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(FooInt);
+      }
+      if (fooCase_ == FooOneofCase.FooString) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(FooString);
+      }
+      if (fooCase_ == FooOneofCase.FooMessage) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(FooMessage);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestOneof other) {
+      if (other == null) {
+        return;
+      }
+      switch (other.FooCase) {
+        case FooOneofCase.FooInt:
+          FooInt = other.FooInt;
+          break;
+        case FooOneofCase.FooString:
+          FooString = other.FooString;
+          break;
+        case FooOneofCase.FooMessage:
+          FooMessage = other.FooMessage;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            FooInt = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            FooString = input.ReadString();
+            break;
+          }
+          case 26: {
+            global::Google.Protobuf.TestProtos.TestAllTypes subBuilder = new global::Google.Protobuf.TestProtos.TestAllTypes();
+            if (fooCase_ == FooOneofCase.FooMessage) {
+              subBuilder.MergeFrom(FooMessage);
+            }
+            input.ReadMessage(subBuilder);
+            FooMessage = subBuilder;
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestPackedTypes : pb::IMessage<TestPackedTypes> {
+    private static readonly pb::MessageParser<TestPackedTypes> _parser = new pb::MessageParser<TestPackedTypes>(() => new TestPackedTypes());
+    public static pb::MessageParser<TestPackedTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[23]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestPackedTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestPackedTypes(TestPackedTypes other) : this() {
+      packedInt32_ = other.packedInt32_.Clone();
+      packedInt64_ = other.packedInt64_.Clone();
+      packedUint32_ = other.packedUint32_.Clone();
+      packedUint64_ = other.packedUint64_.Clone();
+      packedSint32_ = other.packedSint32_.Clone();
+      packedSint64_ = other.packedSint64_.Clone();
+      packedFixed32_ = other.packedFixed32_.Clone();
+      packedFixed64_ = other.packedFixed64_.Clone();
+      packedSfixed32_ = other.packedSfixed32_.Clone();
+      packedSfixed64_ = other.packedSfixed64_.Clone();
+      packedFloat_ = other.packedFloat_.Clone();
+      packedDouble_ = other.packedDouble_.Clone();
+      packedBool_ = other.packedBool_.Clone();
+      packedEnum_ = other.packedEnum_.Clone();
+    }
+
+    public TestPackedTypes Clone() {
+      return new TestPackedTypes(this);
+    }
+
+    /// <summary>Field number for the "packed_int32" field.</summary>
+    public const int PackedInt32FieldNumber = 90;
+    private static readonly pb::FieldCodec<int> _repeated_packedInt32_codec
+        = pb::FieldCodec.ForInt32(722);
+    private readonly pbc::RepeatedField<int> packedInt32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> PackedInt32 {
+      get { return packedInt32_; }
+    }
+
+    /// <summary>Field number for the "packed_int64" field.</summary>
+    public const int PackedInt64FieldNumber = 91;
+    private static readonly pb::FieldCodec<long> _repeated_packedInt64_codec
+        = pb::FieldCodec.ForInt64(730);
+    private readonly pbc::RepeatedField<long> packedInt64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> PackedInt64 {
+      get { return packedInt64_; }
+    }
+
+    /// <summary>Field number for the "packed_uint32" field.</summary>
+    public const int PackedUint32FieldNumber = 92;
+    private static readonly pb::FieldCodec<uint> _repeated_packedUint32_codec
+        = pb::FieldCodec.ForUInt32(738);
+    private readonly pbc::RepeatedField<uint> packedUint32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> PackedUint32 {
+      get { return packedUint32_; }
+    }
+
+    /// <summary>Field number for the "packed_uint64" field.</summary>
+    public const int PackedUint64FieldNumber = 93;
+    private static readonly pb::FieldCodec<ulong> _repeated_packedUint64_codec
+        = pb::FieldCodec.ForUInt64(746);
+    private readonly pbc::RepeatedField<ulong> packedUint64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> PackedUint64 {
+      get { return packedUint64_; }
+    }
+
+    /// <summary>Field number for the "packed_sint32" field.</summary>
+    public const int PackedSint32FieldNumber = 94;
+    private static readonly pb::FieldCodec<int> _repeated_packedSint32_codec
+        = pb::FieldCodec.ForSInt32(754);
+    private readonly pbc::RepeatedField<int> packedSint32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> PackedSint32 {
+      get { return packedSint32_; }
+    }
+
+    /// <summary>Field number for the "packed_sint64" field.</summary>
+    public const int PackedSint64FieldNumber = 95;
+    private static readonly pb::FieldCodec<long> _repeated_packedSint64_codec
+        = pb::FieldCodec.ForSInt64(762);
+    private readonly pbc::RepeatedField<long> packedSint64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> PackedSint64 {
+      get { return packedSint64_; }
+    }
+
+    /// <summary>Field number for the "packed_fixed32" field.</summary>
+    public const int PackedFixed32FieldNumber = 96;
+    private static readonly pb::FieldCodec<uint> _repeated_packedFixed32_codec
+        = pb::FieldCodec.ForFixed32(770);
+    private readonly pbc::RepeatedField<uint> packedFixed32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> PackedFixed32 {
+      get { return packedFixed32_; }
+    }
+
+    /// <summary>Field number for the "packed_fixed64" field.</summary>
+    public const int PackedFixed64FieldNumber = 97;
+    private static readonly pb::FieldCodec<ulong> _repeated_packedFixed64_codec
+        = pb::FieldCodec.ForFixed64(778);
+    private readonly pbc::RepeatedField<ulong> packedFixed64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> PackedFixed64 {
+      get { return packedFixed64_; }
+    }
+
+    /// <summary>Field number for the "packed_sfixed32" field.</summary>
+    public const int PackedSfixed32FieldNumber = 98;
+    private static readonly pb::FieldCodec<int> _repeated_packedSfixed32_codec
+        = pb::FieldCodec.ForSFixed32(786);
+    private readonly pbc::RepeatedField<int> packedSfixed32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> PackedSfixed32 {
+      get { return packedSfixed32_; }
+    }
+
+    /// <summary>Field number for the "packed_sfixed64" field.</summary>
+    public const int PackedSfixed64FieldNumber = 99;
+    private static readonly pb::FieldCodec<long> _repeated_packedSfixed64_codec
+        = pb::FieldCodec.ForSFixed64(794);
+    private readonly pbc::RepeatedField<long> packedSfixed64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> PackedSfixed64 {
+      get { return packedSfixed64_; }
+    }
+
+    /// <summary>Field number for the "packed_float" field.</summary>
+    public const int PackedFloatFieldNumber = 100;
+    private static readonly pb::FieldCodec<float> _repeated_packedFloat_codec
+        = pb::FieldCodec.ForFloat(802);
+    private readonly pbc::RepeatedField<float> packedFloat_ = new pbc::RepeatedField<float>();
+    public pbc::RepeatedField<float> PackedFloat {
+      get { return packedFloat_; }
+    }
+
+    /// <summary>Field number for the "packed_double" field.</summary>
+    public const int PackedDoubleFieldNumber = 101;
+    private static readonly pb::FieldCodec<double> _repeated_packedDouble_codec
+        = pb::FieldCodec.ForDouble(810);
+    private readonly pbc::RepeatedField<double> packedDouble_ = new pbc::RepeatedField<double>();
+    public pbc::RepeatedField<double> PackedDouble {
+      get { return packedDouble_; }
+    }
+
+    /// <summary>Field number for the "packed_bool" field.</summary>
+    public const int PackedBoolFieldNumber = 102;
+    private static readonly pb::FieldCodec<bool> _repeated_packedBool_codec
+        = pb::FieldCodec.ForBool(818);
+    private readonly pbc::RepeatedField<bool> packedBool_ = new pbc::RepeatedField<bool>();
+    public pbc::RepeatedField<bool> PackedBool {
+      get { return packedBool_; }
+    }
+
+    /// <summary>Field number for the "packed_enum" field.</summary>
+    public const int PackedEnumFieldNumber = 103;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_packedEnum_codec
+        = pb::FieldCodec.ForEnum(826, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> packedEnum_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> PackedEnum {
+      get { return packedEnum_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestPackedTypes);
+    }
+
+    public bool Equals(TestPackedTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!packedInt32_.Equals(other.packedInt32_)) return false;
+      if(!packedInt64_.Equals(other.packedInt64_)) return false;
+      if(!packedUint32_.Equals(other.packedUint32_)) return false;
+      if(!packedUint64_.Equals(other.packedUint64_)) return false;
+      if(!packedSint32_.Equals(other.packedSint32_)) return false;
+      if(!packedSint64_.Equals(other.packedSint64_)) return false;
+      if(!packedFixed32_.Equals(other.packedFixed32_)) return false;
+      if(!packedFixed64_.Equals(other.packedFixed64_)) return false;
+      if(!packedSfixed32_.Equals(other.packedSfixed32_)) return false;
+      if(!packedSfixed64_.Equals(other.packedSfixed64_)) return false;
+      if(!packedFloat_.Equals(other.packedFloat_)) return false;
+      if(!packedDouble_.Equals(other.packedDouble_)) return false;
+      if(!packedBool_.Equals(other.packedBool_)) return false;
+      if(!packedEnum_.Equals(other.packedEnum_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= packedInt32_.GetHashCode();
+      hash ^= packedInt64_.GetHashCode();
+      hash ^= packedUint32_.GetHashCode();
+      hash ^= packedUint64_.GetHashCode();
+      hash ^= packedSint32_.GetHashCode();
+      hash ^= packedSint64_.GetHashCode();
+      hash ^= packedFixed32_.GetHashCode();
+      hash ^= packedFixed64_.GetHashCode();
+      hash ^= packedSfixed32_.GetHashCode();
+      hash ^= packedSfixed64_.GetHashCode();
+      hash ^= packedFloat_.GetHashCode();
+      hash ^= packedDouble_.GetHashCode();
+      hash ^= packedBool_.GetHashCode();
+      hash ^= packedEnum_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      packedInt32_.WriteTo(output, _repeated_packedInt32_codec);
+      packedInt64_.WriteTo(output, _repeated_packedInt64_codec);
+      packedUint32_.WriteTo(output, _repeated_packedUint32_codec);
+      packedUint64_.WriteTo(output, _repeated_packedUint64_codec);
+      packedSint32_.WriteTo(output, _repeated_packedSint32_codec);
+      packedSint64_.WriteTo(output, _repeated_packedSint64_codec);
+      packedFixed32_.WriteTo(output, _repeated_packedFixed32_codec);
+      packedFixed64_.WriteTo(output, _repeated_packedFixed64_codec);
+      packedSfixed32_.WriteTo(output, _repeated_packedSfixed32_codec);
+      packedSfixed64_.WriteTo(output, _repeated_packedSfixed64_codec);
+      packedFloat_.WriteTo(output, _repeated_packedFloat_codec);
+      packedDouble_.WriteTo(output, _repeated_packedDouble_codec);
+      packedBool_.WriteTo(output, _repeated_packedBool_codec);
+      packedEnum_.WriteTo(output, _repeated_packedEnum_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += packedInt32_.CalculateSize(_repeated_packedInt32_codec);
+      size += packedInt64_.CalculateSize(_repeated_packedInt64_codec);
+      size += packedUint32_.CalculateSize(_repeated_packedUint32_codec);
+      size += packedUint64_.CalculateSize(_repeated_packedUint64_codec);
+      size += packedSint32_.CalculateSize(_repeated_packedSint32_codec);
+      size += packedSint64_.CalculateSize(_repeated_packedSint64_codec);
+      size += packedFixed32_.CalculateSize(_repeated_packedFixed32_codec);
+      size += packedFixed64_.CalculateSize(_repeated_packedFixed64_codec);
+      size += packedSfixed32_.CalculateSize(_repeated_packedSfixed32_codec);
+      size += packedSfixed64_.CalculateSize(_repeated_packedSfixed64_codec);
+      size += packedFloat_.CalculateSize(_repeated_packedFloat_codec);
+      size += packedDouble_.CalculateSize(_repeated_packedDouble_codec);
+      size += packedBool_.CalculateSize(_repeated_packedBool_codec);
+      size += packedEnum_.CalculateSize(_repeated_packedEnum_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestPackedTypes other) {
+      if (other == null) {
+        return;
+      }
+      packedInt32_.Add(other.packedInt32_);
+      packedInt64_.Add(other.packedInt64_);
+      packedUint32_.Add(other.packedUint32_);
+      packedUint64_.Add(other.packedUint64_);
+      packedSint32_.Add(other.packedSint32_);
+      packedSint64_.Add(other.packedSint64_);
+      packedFixed32_.Add(other.packedFixed32_);
+      packedFixed64_.Add(other.packedFixed64_);
+      packedSfixed32_.Add(other.packedSfixed32_);
+      packedSfixed64_.Add(other.packedSfixed64_);
+      packedFloat_.Add(other.packedFloat_);
+      packedDouble_.Add(other.packedDouble_);
+      packedBool_.Add(other.packedBool_);
+      packedEnum_.Add(other.packedEnum_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 722:
+          case 720: {
+            packedInt32_.AddEntriesFrom(input, _repeated_packedInt32_codec);
+            break;
+          }
+          case 730:
+          case 728: {
+            packedInt64_.AddEntriesFrom(input, _repeated_packedInt64_codec);
+            break;
+          }
+          case 738:
+          case 736: {
+            packedUint32_.AddEntriesFrom(input, _repeated_packedUint32_codec);
+            break;
+          }
+          case 746:
+          case 744: {
+            packedUint64_.AddEntriesFrom(input, _repeated_packedUint64_codec);
+            break;
+          }
+          case 754:
+          case 752: {
+            packedSint32_.AddEntriesFrom(input, _repeated_packedSint32_codec);
+            break;
+          }
+          case 762:
+          case 760: {
+            packedSint64_.AddEntriesFrom(input, _repeated_packedSint64_codec);
+            break;
+          }
+          case 770:
+          case 773: {
+            packedFixed32_.AddEntriesFrom(input, _repeated_packedFixed32_codec);
+            break;
+          }
+          case 778:
+          case 777: {
+            packedFixed64_.AddEntriesFrom(input, _repeated_packedFixed64_codec);
+            break;
+          }
+          case 786:
+          case 789: {
+            packedSfixed32_.AddEntriesFrom(input, _repeated_packedSfixed32_codec);
+            break;
+          }
+          case 794:
+          case 793: {
+            packedSfixed64_.AddEntriesFrom(input, _repeated_packedSfixed64_codec);
+            break;
+          }
+          case 802:
+          case 805: {
+            packedFloat_.AddEntriesFrom(input, _repeated_packedFloat_codec);
+            break;
+          }
+          case 810:
+          case 809: {
+            packedDouble_.AddEntriesFrom(input, _repeated_packedDouble_codec);
+            break;
+          }
+          case 818:
+          case 816: {
+            packedBool_.AddEntriesFrom(input, _repeated_packedBool_codec);
+            break;
+          }
+          case 826:
+          case 824: {
+            packedEnum_.AddEntriesFrom(input, _repeated_packedEnum_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A message with the same fields as TestPackedTypes, but without packing. Used
+  ///  to test packed &lt;-> unpacked wire compatibility.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestUnpackedTypes : pb::IMessage<TestUnpackedTypes> {
+    private static readonly pb::MessageParser<TestUnpackedTypes> _parser = new pb::MessageParser<TestUnpackedTypes>(() => new TestUnpackedTypes());
+    public static pb::MessageParser<TestUnpackedTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[24]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestUnpackedTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestUnpackedTypes(TestUnpackedTypes other) : this() {
+      unpackedInt32_ = other.unpackedInt32_.Clone();
+      unpackedInt64_ = other.unpackedInt64_.Clone();
+      unpackedUint32_ = other.unpackedUint32_.Clone();
+      unpackedUint64_ = other.unpackedUint64_.Clone();
+      unpackedSint32_ = other.unpackedSint32_.Clone();
+      unpackedSint64_ = other.unpackedSint64_.Clone();
+      unpackedFixed32_ = other.unpackedFixed32_.Clone();
+      unpackedFixed64_ = other.unpackedFixed64_.Clone();
+      unpackedSfixed32_ = other.unpackedSfixed32_.Clone();
+      unpackedSfixed64_ = other.unpackedSfixed64_.Clone();
+      unpackedFloat_ = other.unpackedFloat_.Clone();
+      unpackedDouble_ = other.unpackedDouble_.Clone();
+      unpackedBool_ = other.unpackedBool_.Clone();
+      unpackedEnum_ = other.unpackedEnum_.Clone();
+    }
+
+    public TestUnpackedTypes Clone() {
+      return new TestUnpackedTypes(this);
+    }
+
+    /// <summary>Field number for the "unpacked_int32" field.</summary>
+    public const int UnpackedInt32FieldNumber = 90;
+    private static readonly pb::FieldCodec<int> _repeated_unpackedInt32_codec
+        = pb::FieldCodec.ForInt32(720);
+    private readonly pbc::RepeatedField<int> unpackedInt32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> UnpackedInt32 {
+      get { return unpackedInt32_; }
+    }
+
+    /// <summary>Field number for the "unpacked_int64" field.</summary>
+    public const int UnpackedInt64FieldNumber = 91;
+    private static readonly pb::FieldCodec<long> _repeated_unpackedInt64_codec
+        = pb::FieldCodec.ForInt64(728);
+    private readonly pbc::RepeatedField<long> unpackedInt64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> UnpackedInt64 {
+      get { return unpackedInt64_; }
+    }
+
+    /// <summary>Field number for the "unpacked_uint32" field.</summary>
+    public const int UnpackedUint32FieldNumber = 92;
+    private static readonly pb::FieldCodec<uint> _repeated_unpackedUint32_codec
+        = pb::FieldCodec.ForUInt32(736);
+    private readonly pbc::RepeatedField<uint> unpackedUint32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> UnpackedUint32 {
+      get { return unpackedUint32_; }
+    }
+
+    /// <summary>Field number for the "unpacked_uint64" field.</summary>
+    public const int UnpackedUint64FieldNumber = 93;
+    private static readonly pb::FieldCodec<ulong> _repeated_unpackedUint64_codec
+        = pb::FieldCodec.ForUInt64(744);
+    private readonly pbc::RepeatedField<ulong> unpackedUint64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> UnpackedUint64 {
+      get { return unpackedUint64_; }
+    }
+
+    /// <summary>Field number for the "unpacked_sint32" field.</summary>
+    public const int UnpackedSint32FieldNumber = 94;
+    private static readonly pb::FieldCodec<int> _repeated_unpackedSint32_codec
+        = pb::FieldCodec.ForSInt32(752);
+    private readonly pbc::RepeatedField<int> unpackedSint32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> UnpackedSint32 {
+      get { return unpackedSint32_; }
+    }
+
+    /// <summary>Field number for the "unpacked_sint64" field.</summary>
+    public const int UnpackedSint64FieldNumber = 95;
+    private static readonly pb::FieldCodec<long> _repeated_unpackedSint64_codec
+        = pb::FieldCodec.ForSInt64(760);
+    private readonly pbc::RepeatedField<long> unpackedSint64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> UnpackedSint64 {
+      get { return unpackedSint64_; }
+    }
+
+    /// <summary>Field number for the "unpacked_fixed32" field.</summary>
+    public const int UnpackedFixed32FieldNumber = 96;
+    private static readonly pb::FieldCodec<uint> _repeated_unpackedFixed32_codec
+        = pb::FieldCodec.ForFixed32(773);
+    private readonly pbc::RepeatedField<uint> unpackedFixed32_ = new pbc::RepeatedField<uint>();
+    public pbc::RepeatedField<uint> UnpackedFixed32 {
+      get { return unpackedFixed32_; }
+    }
+
+    /// <summary>Field number for the "unpacked_fixed64" field.</summary>
+    public const int UnpackedFixed64FieldNumber = 97;
+    private static readonly pb::FieldCodec<ulong> _repeated_unpackedFixed64_codec
+        = pb::FieldCodec.ForFixed64(777);
+    private readonly pbc::RepeatedField<ulong> unpackedFixed64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> UnpackedFixed64 {
+      get { return unpackedFixed64_; }
+    }
+
+    /// <summary>Field number for the "unpacked_sfixed32" field.</summary>
+    public const int UnpackedSfixed32FieldNumber = 98;
+    private static readonly pb::FieldCodec<int> _repeated_unpackedSfixed32_codec
+        = pb::FieldCodec.ForSFixed32(789);
+    private readonly pbc::RepeatedField<int> unpackedSfixed32_ = new pbc::RepeatedField<int>();
+    public pbc::RepeatedField<int> UnpackedSfixed32 {
+      get { return unpackedSfixed32_; }
+    }
+
+    /// <summary>Field number for the "unpacked_sfixed64" field.</summary>
+    public const int UnpackedSfixed64FieldNumber = 99;
+    private static readonly pb::FieldCodec<long> _repeated_unpackedSfixed64_codec
+        = pb::FieldCodec.ForSFixed64(793);
+    private readonly pbc::RepeatedField<long> unpackedSfixed64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> UnpackedSfixed64 {
+      get { return unpackedSfixed64_; }
+    }
+
+    /// <summary>Field number for the "unpacked_float" field.</summary>
+    public const int UnpackedFloatFieldNumber = 100;
+    private static readonly pb::FieldCodec<float> _repeated_unpackedFloat_codec
+        = pb::FieldCodec.ForFloat(805);
+    private readonly pbc::RepeatedField<float> unpackedFloat_ = new pbc::RepeatedField<float>();
+    public pbc::RepeatedField<float> UnpackedFloat {
+      get { return unpackedFloat_; }
+    }
+
+    /// <summary>Field number for the "unpacked_double" field.</summary>
+    public const int UnpackedDoubleFieldNumber = 101;
+    private static readonly pb::FieldCodec<double> _repeated_unpackedDouble_codec
+        = pb::FieldCodec.ForDouble(809);
+    private readonly pbc::RepeatedField<double> unpackedDouble_ = new pbc::RepeatedField<double>();
+    public pbc::RepeatedField<double> UnpackedDouble {
+      get { return unpackedDouble_; }
+    }
+
+    /// <summary>Field number for the "unpacked_bool" field.</summary>
+    public const int UnpackedBoolFieldNumber = 102;
+    private static readonly pb::FieldCodec<bool> _repeated_unpackedBool_codec
+        = pb::FieldCodec.ForBool(816);
+    private readonly pbc::RepeatedField<bool> unpackedBool_ = new pbc::RepeatedField<bool>();
+    public pbc::RepeatedField<bool> UnpackedBool {
+      get { return unpackedBool_; }
+    }
+
+    /// <summary>Field number for the "unpacked_enum" field.</summary>
+    public const int UnpackedEnumFieldNumber = 103;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_unpackedEnum_codec
+        = pb::FieldCodec.ForEnum(824, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> unpackedEnum_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum>();
+    public pbc::RepeatedField<global::Google.Protobuf.TestProtos.ForeignEnum> UnpackedEnum {
+      get { return unpackedEnum_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestUnpackedTypes);
+    }
+
+    public bool Equals(TestUnpackedTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!unpackedInt32_.Equals(other.unpackedInt32_)) return false;
+      if(!unpackedInt64_.Equals(other.unpackedInt64_)) return false;
+      if(!unpackedUint32_.Equals(other.unpackedUint32_)) return false;
+      if(!unpackedUint64_.Equals(other.unpackedUint64_)) return false;
+      if(!unpackedSint32_.Equals(other.unpackedSint32_)) return false;
+      if(!unpackedSint64_.Equals(other.unpackedSint64_)) return false;
+      if(!unpackedFixed32_.Equals(other.unpackedFixed32_)) return false;
+      if(!unpackedFixed64_.Equals(other.unpackedFixed64_)) return false;
+      if(!unpackedSfixed32_.Equals(other.unpackedSfixed32_)) return false;
+      if(!unpackedSfixed64_.Equals(other.unpackedSfixed64_)) return false;
+      if(!unpackedFloat_.Equals(other.unpackedFloat_)) return false;
+      if(!unpackedDouble_.Equals(other.unpackedDouble_)) return false;
+      if(!unpackedBool_.Equals(other.unpackedBool_)) return false;
+      if(!unpackedEnum_.Equals(other.unpackedEnum_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= unpackedInt32_.GetHashCode();
+      hash ^= unpackedInt64_.GetHashCode();
+      hash ^= unpackedUint32_.GetHashCode();
+      hash ^= unpackedUint64_.GetHashCode();
+      hash ^= unpackedSint32_.GetHashCode();
+      hash ^= unpackedSint64_.GetHashCode();
+      hash ^= unpackedFixed32_.GetHashCode();
+      hash ^= unpackedFixed64_.GetHashCode();
+      hash ^= unpackedSfixed32_.GetHashCode();
+      hash ^= unpackedSfixed64_.GetHashCode();
+      hash ^= unpackedFloat_.GetHashCode();
+      hash ^= unpackedDouble_.GetHashCode();
+      hash ^= unpackedBool_.GetHashCode();
+      hash ^= unpackedEnum_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      unpackedInt32_.WriteTo(output, _repeated_unpackedInt32_codec);
+      unpackedInt64_.WriteTo(output, _repeated_unpackedInt64_codec);
+      unpackedUint32_.WriteTo(output, _repeated_unpackedUint32_codec);
+      unpackedUint64_.WriteTo(output, _repeated_unpackedUint64_codec);
+      unpackedSint32_.WriteTo(output, _repeated_unpackedSint32_codec);
+      unpackedSint64_.WriteTo(output, _repeated_unpackedSint64_codec);
+      unpackedFixed32_.WriteTo(output, _repeated_unpackedFixed32_codec);
+      unpackedFixed64_.WriteTo(output, _repeated_unpackedFixed64_codec);
+      unpackedSfixed32_.WriteTo(output, _repeated_unpackedSfixed32_codec);
+      unpackedSfixed64_.WriteTo(output, _repeated_unpackedSfixed64_codec);
+      unpackedFloat_.WriteTo(output, _repeated_unpackedFloat_codec);
+      unpackedDouble_.WriteTo(output, _repeated_unpackedDouble_codec);
+      unpackedBool_.WriteTo(output, _repeated_unpackedBool_codec);
+      unpackedEnum_.WriteTo(output, _repeated_unpackedEnum_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += unpackedInt32_.CalculateSize(_repeated_unpackedInt32_codec);
+      size += unpackedInt64_.CalculateSize(_repeated_unpackedInt64_codec);
+      size += unpackedUint32_.CalculateSize(_repeated_unpackedUint32_codec);
+      size += unpackedUint64_.CalculateSize(_repeated_unpackedUint64_codec);
+      size += unpackedSint32_.CalculateSize(_repeated_unpackedSint32_codec);
+      size += unpackedSint64_.CalculateSize(_repeated_unpackedSint64_codec);
+      size += unpackedFixed32_.CalculateSize(_repeated_unpackedFixed32_codec);
+      size += unpackedFixed64_.CalculateSize(_repeated_unpackedFixed64_codec);
+      size += unpackedSfixed32_.CalculateSize(_repeated_unpackedSfixed32_codec);
+      size += unpackedSfixed64_.CalculateSize(_repeated_unpackedSfixed64_codec);
+      size += unpackedFloat_.CalculateSize(_repeated_unpackedFloat_codec);
+      size += unpackedDouble_.CalculateSize(_repeated_unpackedDouble_codec);
+      size += unpackedBool_.CalculateSize(_repeated_unpackedBool_codec);
+      size += unpackedEnum_.CalculateSize(_repeated_unpackedEnum_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestUnpackedTypes other) {
+      if (other == null) {
+        return;
+      }
+      unpackedInt32_.Add(other.unpackedInt32_);
+      unpackedInt64_.Add(other.unpackedInt64_);
+      unpackedUint32_.Add(other.unpackedUint32_);
+      unpackedUint64_.Add(other.unpackedUint64_);
+      unpackedSint32_.Add(other.unpackedSint32_);
+      unpackedSint64_.Add(other.unpackedSint64_);
+      unpackedFixed32_.Add(other.unpackedFixed32_);
+      unpackedFixed64_.Add(other.unpackedFixed64_);
+      unpackedSfixed32_.Add(other.unpackedSfixed32_);
+      unpackedSfixed64_.Add(other.unpackedSfixed64_);
+      unpackedFloat_.Add(other.unpackedFloat_);
+      unpackedDouble_.Add(other.unpackedDouble_);
+      unpackedBool_.Add(other.unpackedBool_);
+      unpackedEnum_.Add(other.unpackedEnum_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 722:
+          case 720: {
+            unpackedInt32_.AddEntriesFrom(input, _repeated_unpackedInt32_codec);
+            break;
+          }
+          case 730:
+          case 728: {
+            unpackedInt64_.AddEntriesFrom(input, _repeated_unpackedInt64_codec);
+            break;
+          }
+          case 738:
+          case 736: {
+            unpackedUint32_.AddEntriesFrom(input, _repeated_unpackedUint32_codec);
+            break;
+          }
+          case 746:
+          case 744: {
+            unpackedUint64_.AddEntriesFrom(input, _repeated_unpackedUint64_codec);
+            break;
+          }
+          case 754:
+          case 752: {
+            unpackedSint32_.AddEntriesFrom(input, _repeated_unpackedSint32_codec);
+            break;
+          }
+          case 762:
+          case 760: {
+            unpackedSint64_.AddEntriesFrom(input, _repeated_unpackedSint64_codec);
+            break;
+          }
+          case 770:
+          case 773: {
+            unpackedFixed32_.AddEntriesFrom(input, _repeated_unpackedFixed32_codec);
+            break;
+          }
+          case 778:
+          case 777: {
+            unpackedFixed64_.AddEntriesFrom(input, _repeated_unpackedFixed64_codec);
+            break;
+          }
+          case 786:
+          case 789: {
+            unpackedSfixed32_.AddEntriesFrom(input, _repeated_unpackedSfixed32_codec);
+            break;
+          }
+          case 794:
+          case 793: {
+            unpackedSfixed64_.AddEntriesFrom(input, _repeated_unpackedSfixed64_codec);
+            break;
+          }
+          case 802:
+          case 805: {
+            unpackedFloat_.AddEntriesFrom(input, _repeated_unpackedFloat_codec);
+            break;
+          }
+          case 810:
+          case 809: {
+            unpackedDouble_.AddEntriesFrom(input, _repeated_unpackedDouble_codec);
+            break;
+          }
+          case 818:
+          case 816: {
+            unpackedBool_.AddEntriesFrom(input, _repeated_unpackedBool_codec);
+            break;
+          }
+          case 826:
+          case 824: {
+            unpackedEnum_.AddEntriesFrom(input, _repeated_unpackedEnum_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestRepeatedScalarDifferentTagSizes : pb::IMessage<TestRepeatedScalarDifferentTagSizes> {
+    private static readonly pb::MessageParser<TestRepeatedScalarDifferentTagSizes> _parser = new pb::MessageParser<TestRepeatedScalarDifferentTagSizes>(() => new TestRepeatedScalarDifferentTagSizes());
+    public static pb::MessageParser<TestRepeatedScalarDifferentTagSizes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[25]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestRepeatedScalarDifferentTagSizes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestRepeatedScalarDifferentTagSizes(TestRepeatedScalarDifferentTagSizes other) : this() {
+      repeatedFixed32_ = other.repeatedFixed32_.Clone();
+      repeatedInt32_ = other.repeatedInt32_.Clone();
+      repeatedFixed64_ = other.repeatedFixed64_.Clone();
+      repeatedInt64_ = other.repeatedInt64_.Clone();
+      repeatedFloat_ = other.repeatedFloat_.Clone();
+      repeatedUint64_ = other.repeatedUint64_.Clone();
+    }
+
+    public TestRepeatedScalarDifferentTagSizes Clone() {
+      return new TestRepeatedScalarDifferentTagSizes(this);
+    }
+
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
+    public const int RepeatedFixed32FieldNumber = 12;
+    private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
+        = pb::FieldCodec.ForFixed32(98);
+    private readonly pbc::RepeatedField<uint> repeatedFixed32_ = new pbc::RepeatedField<uint>();
+    /// <summary>
+    ///  Parsing repeated fixed size values used to fail. This message needs to be
+    ///  used in order to get a tag of the right size; all of the repeated fields
+    ///  in TestAllTypes didn't trigger the check.
+    /// </summary>
+    public pbc::RepeatedField<uint> RepeatedFixed32 {
+      get { return repeatedFixed32_; }
+    }
+
+    /// <summary>Field number for the "repeated_int32" field.</summary>
+    public const int RepeatedInt32FieldNumber = 13;
+    private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
+        = pb::FieldCodec.ForInt32(106);
+    private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Check for a varint type, just for good measure.
+    /// </summary>
+    public pbc::RepeatedField<int> RepeatedInt32 {
+      get { return repeatedInt32_; }
+    }
+
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
+    public const int RepeatedFixed64FieldNumber = 2046;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
+        = pb::FieldCodec.ForFixed64(16370);
+    private readonly pbc::RepeatedField<ulong> repeatedFixed64_ = new pbc::RepeatedField<ulong>();
+    /// <summary>
+    ///  These have two-byte tags.
+    /// </summary>
+    public pbc::RepeatedField<ulong> RepeatedFixed64 {
+      get { return repeatedFixed64_; }
+    }
+
+    /// <summary>Field number for the "repeated_int64" field.</summary>
+    public const int RepeatedInt64FieldNumber = 2047;
+    private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
+        = pb::FieldCodec.ForInt64(16378);
+    private readonly pbc::RepeatedField<long> repeatedInt64_ = new pbc::RepeatedField<long>();
+    public pbc::RepeatedField<long> RepeatedInt64 {
+      get { return repeatedInt64_; }
+    }
+
+    /// <summary>Field number for the "repeated_float" field.</summary>
+    public const int RepeatedFloatFieldNumber = 262142;
+    private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
+        = pb::FieldCodec.ForFloat(2097138);
+    private readonly pbc::RepeatedField<float> repeatedFloat_ = new pbc::RepeatedField<float>();
+    /// <summary>
+    ///  Three byte tags.
+    /// </summary>
+    public pbc::RepeatedField<float> RepeatedFloat {
+      get { return repeatedFloat_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
+    public const int RepeatedUint64FieldNumber = 262143;
+    private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
+        = pb::FieldCodec.ForUInt64(2097146);
+    private readonly pbc::RepeatedField<ulong> repeatedUint64_ = new pbc::RepeatedField<ulong>();
+    public pbc::RepeatedField<ulong> RepeatedUint64 {
+      get { return repeatedUint64_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestRepeatedScalarDifferentTagSizes);
+    }
+
+    public bool Equals(TestRepeatedScalarDifferentTagSizes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!repeatedFixed32_.Equals(other.repeatedFixed32_)) return false;
+      if(!repeatedInt32_.Equals(other.repeatedInt32_)) return false;
+      if(!repeatedFixed64_.Equals(other.repeatedFixed64_)) return false;
+      if(!repeatedInt64_.Equals(other.repeatedInt64_)) return false;
+      if(!repeatedFloat_.Equals(other.repeatedFloat_)) return false;
+      if(!repeatedUint64_.Equals(other.repeatedUint64_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= repeatedFixed32_.GetHashCode();
+      hash ^= repeatedInt32_.GetHashCode();
+      hash ^= repeatedFixed64_.GetHashCode();
+      hash ^= repeatedInt64_.GetHashCode();
+      hash ^= repeatedFloat_.GetHashCode();
+      hash ^= repeatedUint64_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      repeatedFixed32_.WriteTo(output, _repeated_repeatedFixed32_codec);
+      repeatedInt32_.WriteTo(output, _repeated_repeatedInt32_codec);
+      repeatedFixed64_.WriteTo(output, _repeated_repeatedFixed64_codec);
+      repeatedInt64_.WriteTo(output, _repeated_repeatedInt64_codec);
+      repeatedFloat_.WriteTo(output, _repeated_repeatedFloat_codec);
+      repeatedUint64_.WriteTo(output, _repeated_repeatedUint64_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += repeatedFixed32_.CalculateSize(_repeated_repeatedFixed32_codec);
+      size += repeatedInt32_.CalculateSize(_repeated_repeatedInt32_codec);
+      size += repeatedFixed64_.CalculateSize(_repeated_repeatedFixed64_codec);
+      size += repeatedInt64_.CalculateSize(_repeated_repeatedInt64_codec);
+      size += repeatedFloat_.CalculateSize(_repeated_repeatedFloat_codec);
+      size += repeatedUint64_.CalculateSize(_repeated_repeatedUint64_codec);
+      return size;
+    }
+
+    public void MergeFrom(TestRepeatedScalarDifferentTagSizes other) {
+      if (other == null) {
+        return;
+      }
+      repeatedFixed32_.Add(other.repeatedFixed32_);
+      repeatedInt32_.Add(other.repeatedInt32_);
+      repeatedFixed64_.Add(other.repeatedFixed64_);
+      repeatedInt64_.Add(other.repeatedInt64_);
+      repeatedFloat_.Add(other.repeatedFloat_);
+      repeatedUint64_.Add(other.repeatedUint64_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 98:
+          case 101: {
+            repeatedFixed32_.AddEntriesFrom(input, _repeated_repeatedFixed32_codec);
+            break;
+          }
+          case 106:
+          case 104: {
+            repeatedInt32_.AddEntriesFrom(input, _repeated_repeatedInt32_codec);
+            break;
+          }
+          case 16370:
+          case 16369: {
+            repeatedFixed64_.AddEntriesFrom(input, _repeated_repeatedFixed64_codec);
+            break;
+          }
+          case 16378:
+          case 16376: {
+            repeatedInt64_.AddEntriesFrom(input, _repeated_repeatedInt64_codec);
+            break;
+          }
+          case 2097138:
+          case 2097141: {
+            repeatedFloat_.AddEntriesFrom(input, _repeated_repeatedFloat_codec);
+            break;
+          }
+          case 2097146:
+          case 2097144: {
+            repeatedUint64_.AddEntriesFrom(input, _repeated_repeatedUint64_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestCommentInjectionMessage : pb::IMessage<TestCommentInjectionMessage> {
+    private static readonly pb::MessageParser<TestCommentInjectionMessage> _parser = new pb::MessageParser<TestCommentInjectionMessage>(() => new TestCommentInjectionMessage());
+    public static pb::MessageParser<TestCommentInjectionMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[26]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestCommentInjectionMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestCommentInjectionMessage(TestCommentInjectionMessage other) : this() {
+      a_ = other.a_;
+    }
+
+    public TestCommentInjectionMessage Clone() {
+      return new TestCommentInjectionMessage(this);
+    }
+
+    /// <summary>Field number for the "a" field.</summary>
+    public const int AFieldNumber = 1;
+    private string a_ = "";
+    /// <summary>
+    ///  */ &lt;- This should not close the generated doc comment
+    /// </summary>
+    public string A {
+      get { return a_; }
+      set {
+        a_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestCommentInjectionMessage);
+    }
+
+    public bool Equals(TestCommentInjectionMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (A != other.A) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (A.Length != 0) hash ^= A.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (A.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(A);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (A.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(A);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestCommentInjectionMessage other) {
+      if (other == null) {
+        return;
+      }
+      if (other.A.Length != 0) {
+        A = other.A;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            A = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Test that RPC services work.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FooRequest : pb::IMessage<FooRequest> {
+    private static readonly pb::MessageParser<FooRequest> _parser = new pb::MessageParser<FooRequest>(() => new FooRequest());
+    public static pb::MessageParser<FooRequest> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[27]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FooRequest() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FooRequest(FooRequest other) : this() {
+    }
+
+    public FooRequest Clone() {
+      return new FooRequest(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FooRequest);
+    }
+
+    public bool Equals(FooRequest other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(FooRequest other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FooResponse : pb::IMessage<FooResponse> {
+    private static readonly pb::MessageParser<FooResponse> _parser = new pb::MessageParser<FooResponse>(() => new FooResponse());
+    public static pb::MessageParser<FooResponse> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[28]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FooResponse() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FooResponse(FooResponse other) : this() {
+    }
+
+    public FooResponse Clone() {
+      return new FooResponse(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FooResponse);
+    }
+
+    public bool Equals(FooResponse other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(FooResponse other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FooClientMessage : pb::IMessage<FooClientMessage> {
+    private static readonly pb::MessageParser<FooClientMessage> _parser = new pb::MessageParser<FooClientMessage>(() => new FooClientMessage());
+    public static pb::MessageParser<FooClientMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[29]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FooClientMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FooClientMessage(FooClientMessage other) : this() {
+    }
+
+    public FooClientMessage Clone() {
+      return new FooClientMessage(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FooClientMessage);
+    }
+
+    public bool Equals(FooClientMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(FooClientMessage other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FooServerMessage : pb::IMessage<FooServerMessage> {
+    private static readonly pb::MessageParser<FooServerMessage> _parser = new pb::MessageParser<FooServerMessage>(() => new FooServerMessage());
+    public static pb::MessageParser<FooServerMessage> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[30]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FooServerMessage() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FooServerMessage(FooServerMessage other) : this() {
+    }
+
+    public FooServerMessage Clone() {
+      return new FooServerMessage(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FooServerMessage);
+    }
+
+    public bool Equals(FooServerMessage other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(FooServerMessage other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BarRequest : pb::IMessage<BarRequest> {
+    private static readonly pb::MessageParser<BarRequest> _parser = new pb::MessageParser<BarRequest>(() => new BarRequest());
+    public static pb::MessageParser<BarRequest> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[31]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BarRequest() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BarRequest(BarRequest other) : this() {
+    }
+
+    public BarRequest Clone() {
+      return new BarRequest(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BarRequest);
+    }
+
+    public bool Equals(BarRequest other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(BarRequest other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BarResponse : pb::IMessage<BarResponse> {
+    private static readonly pb::MessageParser<BarResponse> _parser = new pb::MessageParser<BarResponse>(() => new BarResponse());
+    public static pb::MessageParser<BarResponse> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[32]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BarResponse() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BarResponse(BarResponse other) : this() {
+    }
+
+    public BarResponse Clone() {
+      return new BarResponse(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BarResponse);
+    }
+
+    public bool Equals(BarResponse other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(BarResponse other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
new file mode 100644
index 0000000..ae12f4a
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
@@ -0,0 +1,2413 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/unittest_well_known_types.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.TestProtos {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_well_known_types.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class UnittestWellKnownTypesReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_well_known_types.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static UnittestWellKnownTypesReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ci9nb29nbGUvcHJvdG9idWYvdW5pdHRlc3Rfd2VsbF9rbm93bl90eXBlcy5w",
+            "cm90bxIRcHJvdG9idWZfdW5pdHRlc3QaGWdvb2dsZS9wcm90b2J1Zi9hbnku",
+            "cHJvdG8aGWdvb2dsZS9wcm90b2J1Zi9hcGkucHJvdG8aHmdvb2dsZS9wcm90",
+            "b2J1Zi9kdXJhdGlvbi5wcm90bxobZ29vZ2xlL3Byb3RvYnVmL2VtcHR5LnBy",
+            "b3RvGiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxokZ29vZ2xl",
+            "L3Byb3RvYnVmL3NvdXJjZV9jb250ZXh0LnByb3RvGhxnb29nbGUvcHJvdG9i",
+            "dWYvc3RydWN0LnByb3RvGh9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnBy",
+            "b3RvGhpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxoeZ29vZ2xlL3Byb3Rv",
+            "YnVmL3dyYXBwZXJzLnByb3RvIr4HChJUZXN0V2VsbEtub3duVHlwZXMSJwoJ",
+            "YW55X2ZpZWxkGAEgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueRInCglhcGlf",
+            "ZmllbGQYAiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpEjEKDmR1cmF0aW9u",
+            "X2ZpZWxkGAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uEisKC2Vt",
+            "cHR5X2ZpZWxkGAQgASgLMhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5EjQKEGZp",
+            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN",
+            "YXNrEjwKFHNvdXJjZV9jb250ZXh0X2ZpZWxkGAYgASgLMh4uZ29vZ2xlLnBy",
+            "b3RvYnVmLlNvdXJjZUNvbnRleHQSLQoMc3RydWN0X2ZpZWxkGAcgASgLMhcu",
+            "Z29vZ2xlLnByb3RvYnVmLlN0cnVjdBIzCg90aW1lc3RhbXBfZmllbGQYCCAB",
+            "KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEikKCnR5cGVfZmllbGQY",
+            "CSABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZRIyCgxkb3VibGVfZmllbGQY",
+            "CiABKAsyHC5nb29nbGUucHJvdG9idWYuRG91YmxlVmFsdWUSMAoLZmxvYXRf",
+            "ZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxvYXRWYWx1ZRIwCgtp",
+            "bnQ2NF9maWVsZBgMIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl",
+            "EjIKDHVpbnQ2NF9maWVsZBgNIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50",
+            "NjRWYWx1ZRIwCgtpbnQzMl9maWVsZBgOIAEoCzIbLmdvb2dsZS5wcm90b2J1",
+            "Zi5JbnQzMlZhbHVlEjIKDHVpbnQzMl9maWVsZBgPIAEoCzIcLmdvb2dsZS5w",
+            "cm90b2J1Zi5VSW50MzJWYWx1ZRIuCgpib29sX2ZpZWxkGBAgASgLMhouZ29v",
+            "Z2xlLnByb3RvYnVmLkJvb2xWYWx1ZRIyCgxzdHJpbmdfZmllbGQYESABKAsy",
+            "HC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSMAoLYnl0ZXNfZmllbGQY",
+            "EiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZRIrCgt2YWx1ZV9m",
+            "aWVsZBgTIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSKVBwoWUmVwZWF0",
+            "ZWRXZWxsS25vd25UeXBlcxInCglhbnlfZmllbGQYASADKAsyFC5nb29nbGUu",
+            "cHJvdG9idWYuQW55EicKCWFwaV9maWVsZBgCIAMoCzIULmdvb2dsZS5wcm90",
+            "b2J1Zi5BcGkSMQoOZHVyYXRpb25fZmllbGQYAyADKAsyGS5nb29nbGUucHJv",
+            "dG9idWYuRHVyYXRpb24SKwoLZW1wdHlfZmllbGQYBCADKAsyFi5nb29nbGUu",
+            "cHJvdG9idWYuRW1wdHkSNAoQZmllbGRfbWFza19maWVsZBgFIAMoCzIaLmdv",
+            "b2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sSPAoUc291cmNlX2NvbnRleHRfZmll",
+            "bGQYBiADKAsyHi5nb29nbGUucHJvdG9idWYuU291cmNlQ29udGV4dBItCgxz",
+            "dHJ1Y3RfZmllbGQYByADKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EjMK",
+            "D3RpbWVzdGFtcF9maWVsZBgIIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1l",
+            "c3RhbXASKQoKdHlwZV9maWVsZBgJIAMoCzIVLmdvb2dsZS5wcm90b2J1Zi5U",
+            "eXBlEjIKDGRvdWJsZV9maWVsZBgKIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5E",
+            "b3VibGVWYWx1ZRIwCgtmbG9hdF9maWVsZBgLIAMoCzIbLmdvb2dsZS5wcm90",
+            "b2J1Zi5GbG9hdFZhbHVlEjAKC2ludDY0X2ZpZWxkGAwgAygLMhsuZ29vZ2xl",
+            "LnByb3RvYnVmLkludDY0VmFsdWUSMgoMdWludDY0X2ZpZWxkGA0gAygLMhwu",
+            "Z29vZ2xlLnByb3RvYnVmLlVJbnQ2NFZhbHVlEjAKC2ludDMyX2ZpZWxkGA4g",
+            "AygLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSMgoMdWludDMyX2Zp",
+            "ZWxkGA8gAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEi4KCmJv",
+            "b2xfZmllbGQYECADKAsyGi5nb29nbGUucHJvdG9idWYuQm9vbFZhbHVlEjIK",
+            "DHN0cmluZ19maWVsZBgRIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5TdHJpbmdW",
+            "YWx1ZRIwCgtieXRlc19maWVsZBgSIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5C",
+            "eXRlc1ZhbHVlIsUHChNPbmVvZldlbGxLbm93blR5cGVzEikKCWFueV9maWVs",
+            "ZBgBIAEoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlIABIpCglhcGlfZmllbGQY",
+            "AiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpSAASMwoOZHVyYXRpb25fZmll",
+            "bGQYAyABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25IABItCgtlbXB0",
+            "eV9maWVsZBgEIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eUgAEjYKEGZp",
+            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN",
+            "YXNrSAASPgoUc291cmNlX2NvbnRleHRfZmllbGQYBiABKAsyHi5nb29nbGUu",
+            "cHJvdG9idWYuU291cmNlQ29udGV4dEgAEi8KDHN0cnVjdF9maWVsZBgHIAEo",
+            "CzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIABI1Cg90aW1lc3RhbXBfZmll",
+            "bGQYCCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAASKwoKdHlw",
+            "ZV9maWVsZBgJIAEoCzIVLmdvb2dsZS5wcm90b2J1Zi5UeXBlSAASNAoMZG91",
+            "YmxlX2ZpZWxkGAogASgLMhwuZ29vZ2xlLnByb3RvYnVmLkRvdWJsZVZhbHVl",
+            "SAASMgoLZmxvYXRfZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxv",
+            "YXRWYWx1ZUgAEjIKC2ludDY0X2ZpZWxkGAwgASgLMhsuZ29vZ2xlLnByb3Rv",
+            "YnVmLkludDY0VmFsdWVIABI0Cgx1aW50NjRfZmllbGQYDSABKAsyHC5nb29n",
+            "bGUucHJvdG9idWYuVUludDY0VmFsdWVIABIyCgtpbnQzMl9maWVsZBgOIAEo",
+            "CzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlSAASNAoMdWludDMyX2Zp",
+            "ZWxkGA8gASgLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlSAASMAoK",
+            "Ym9vbF9maWVsZBgQIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5Cb29sVmFsdWVI",
+            "ABI0CgxzdHJpbmdfZmllbGQYESABKAsyHC5nb29nbGUucHJvdG9idWYuU3Ry",
+            "aW5nVmFsdWVIABIyCgtieXRlc19maWVsZBgSIAEoCzIbLmdvb2dsZS5wcm90",
+            "b2J1Zi5CeXRlc1ZhbHVlSABCDQoLb25lb2ZfZmllbGQilhYKEU1hcFdlbGxL",
+            "bm93blR5cGVzEkUKCWFueV9maWVsZBgBIAMoCzIyLnByb3RvYnVmX3VuaXR0",
+            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkFueUZpZWxkRW50cnkSRQoJYXBpX2Zp",
+            "ZWxkGAIgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlw",
+            "ZXMuQXBpRmllbGRFbnRyeRJPCg5kdXJhdGlvbl9maWVsZBgDIAMoCzI3LnBy",
+            "b3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkR1cmF0aW9uRmll",
+            "bGRFbnRyeRJJCgtlbXB0eV9maWVsZBgEIAMoCzI0LnByb3RvYnVmX3VuaXR0",
+            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkVtcHR5RmllbGRFbnRyeRJSChBmaWVs",
+            "ZF9tYXNrX2ZpZWxkGAUgAygLMjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs",
+            "bEtub3duVHlwZXMuRmllbGRNYXNrRmllbGRFbnRyeRJaChRzb3VyY2VfY29u",
+            "dGV4dF9maWVsZBgGIAMoCzI8LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxL",
+            "bm93blR5cGVzLlNvdXJjZUNvbnRleHRGaWVsZEVudHJ5EksKDHN0cnVjdF9m",
+            "aWVsZBgHIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5",
+            "cGVzLlN0cnVjdEZpZWxkRW50cnkSUQoPdGltZXN0YW1wX2ZpZWxkGAggAygL",
+            "MjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVGltZXN0",
+            "YW1wRmllbGRFbnRyeRJHCgp0eXBlX2ZpZWxkGAkgAygLMjMucHJvdG9idWZf",
+            "dW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVHlwZUZpZWxkRW50cnkSSwoM",
+            "ZG91YmxlX2ZpZWxkGAogAygLMjUucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs",
+            "bEtub3duVHlwZXMuRG91YmxlRmllbGRFbnRyeRJJCgtmbG9hdF9maWVsZBgL",
+            "IAMoCzI0LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkZs",
+            "b2F0RmllbGRFbnRyeRJJCgtpbnQ2NF9maWVsZBgMIAMoCzI0LnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkludDY0RmllbGRFbnRyeRJL",
+            "Cgx1aW50NjRfZmllbGQYDSADKAsyNS5wcm90b2J1Zl91bml0dGVzdC5NYXBX",
+            "ZWxsS25vd25UeXBlcy5VaW50NjRGaWVsZEVudHJ5EkkKC2ludDMyX2ZpZWxk",
+            "GA4gAygLMjQucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMu",
+            "SW50MzJGaWVsZEVudHJ5EksKDHVpbnQzMl9maWVsZBgPIAMoCzI1LnByb3Rv",
+            "YnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLlVpbnQzMkZpZWxkRW50",
+            "cnkSRwoKYm9vbF9maWVsZBgQIAMoCzIzLnByb3RvYnVmX3VuaXR0ZXN0Lk1h",
+            "cFdlbGxLbm93blR5cGVzLkJvb2xGaWVsZEVudHJ5EksKDHN0cmluZ19maWVs",
+            "ZBgRIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVz",
+            "LlN0cmluZ0ZpZWxkRW50cnkSSQoLYnl0ZXNfZmllbGQYEiADKAsyNC5wcm90",
+            "b2J1Zl91bml0dGVzdC5NYXBXZWxsS25vd25UeXBlcy5CeXRlc0ZpZWxkRW50",
+            "cnkaRQoNQW55RmllbGRFbnRyeRILCgNrZXkYASABKAUSIwoFdmFsdWUYAiAB",
+            "KAsyFC5nb29nbGUucHJvdG9idWYuQW55OgI4ARpFCg1BcGlGaWVsZEVudHJ5",
+            "EgsKA2tleRgBIAEoBRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5wcm90b2J1",
+            "Zi5BcGk6AjgBGk8KEkR1cmF0aW9uRmllbGRFbnRyeRILCgNrZXkYASABKAUS",
+            "KAoFdmFsdWUYAiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb246AjgB",
+            "GkkKD0VtcHR5RmllbGRFbnRyeRILCgNrZXkYASABKAUSJQoFdmFsdWUYAiAB",
+            "KAsyFi5nb29nbGUucHJvdG9idWYuRW1wdHk6AjgBGlEKE0ZpZWxkTWFza0Zp",
+            "ZWxkRW50cnkSCwoDa2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xl",
+            "LnByb3RvYnVmLkZpZWxkTWFzazoCOAEaWQoXU291cmNlQ29udGV4dEZpZWxk",
+            "RW50cnkSCwoDa2V5GAEgASgFEi0KBXZhbHVlGAIgASgLMh4uZ29vZ2xlLnBy",
+            "b3RvYnVmLlNvdXJjZUNvbnRleHQ6AjgBGksKEFN0cnVjdEZpZWxkRW50cnkS",
+            "CwoDa2V5GAEgASgFEiYKBXZhbHVlGAIgASgLMhcuZ29vZ2xlLnByb3RvYnVm",
+            "LlN0cnVjdDoCOAEaUQoTVGltZXN0YW1wRmllbGRFbnRyeRILCgNrZXkYASAB",
+            "KAUSKQoFdmFsdWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w",
+            "OgI4ARpHCg5UeXBlRmllbGRFbnRyeRILCgNrZXkYASABKAUSJAoFdmFsdWUY",
+            "AiABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZToCOAEaUAoQRG91YmxlRmll",
+            "bGRFbnRyeRILCgNrZXkYASABKAUSKwoFdmFsdWUYAiABKAsyHC5nb29nbGUu",
+            "cHJvdG9idWYuRG91YmxlVmFsdWU6AjgBGk4KD0Zsb2F0RmllbGRFbnRyeRIL",
+            "CgNrZXkYASABKAUSKgoFdmFsdWUYAiABKAsyGy5nb29nbGUucHJvdG9idWYu",
+            "RmxvYXRWYWx1ZToCOAEaTgoPSW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEo",
+            "BRIqCgV2YWx1ZRgCIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl",
+            "OgI4ARpQChBVaW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1",
+            "ZRgCIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZToCOAEaTgoP",
+            "SW50MzJGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIqCgV2YWx1ZRgCIAEoCzIb",
+            "Lmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlOgI4ARpQChBVaW50MzJGaWVs",
+            "ZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1ZRgCIAEoCzIcLmdvb2dsZS5w",
+            "cm90b2J1Zi5VSW50MzJWYWx1ZToCOAEaTAoOQm9vbEZpZWxkRW50cnkSCwoD",
+            "a2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkJv",
+            "b2xWYWx1ZToCOAEaUAoQU3RyaW5nRmllbGRFbnRyeRILCgNrZXkYASABKAUS",
+            "KwoFdmFsdWUYAiABKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWU6",
+            "AjgBGk4KD0J5dGVzRmllbGRFbnRyeRILCgNrZXkYASABKAUSKgoFdmFsdWUY",
+            "AiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZToCOAFCOQoYY29t",
+            "Lmdvb2dsZS5wcm90b2J1Zi50ZXN0UAGqAhpHb29nbGUuUHJvdG9idWYuVGVz",
+            "dFByb3Rvc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestWellKnownTypes), global::Google.Protobuf.TestProtos.TestWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField", "ValueField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.RepeatedWellKnownTypes), global::Google.Protobuf.TestProtos.RepeatedWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneofWellKnownTypes), global::Google.Protobuf.TestProtos.OneofWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, new[]{ "OneofField" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MapWellKnownTypes), global::Google.Protobuf.TestProtos.MapWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, })
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  Test that we can include all well-known types.
+  ///  Each wrapper type is included separately, as languages
+  ///  map handle different wrappers in different ways.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestWellKnownTypes : pb::IMessage<TestWellKnownTypes> {
+    private static readonly pb::MessageParser<TestWellKnownTypes> _parser = new pb::MessageParser<TestWellKnownTypes>(() => new TestWellKnownTypes());
+    public static pb::MessageParser<TestWellKnownTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public TestWellKnownTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public TestWellKnownTypes(TestWellKnownTypes other) : this() {
+      AnyField = other.anyField_ != null ? other.AnyField.Clone() : null;
+      ApiField = other.apiField_ != null ? other.ApiField.Clone() : null;
+      DurationField = other.durationField_ != null ? other.DurationField.Clone() : null;
+      EmptyField = other.emptyField_ != null ? other.EmptyField.Clone() : null;
+      FieldMaskField = other.fieldMaskField_ != null ? other.FieldMaskField.Clone() : null;
+      SourceContextField = other.sourceContextField_ != null ? other.SourceContextField.Clone() : null;
+      StructField = other.structField_ != null ? other.StructField.Clone() : null;
+      TimestampField = other.timestampField_ != null ? other.TimestampField.Clone() : null;
+      TypeField = other.typeField_ != null ? other.TypeField.Clone() : null;
+      DoubleField = other.DoubleField;
+      FloatField = other.FloatField;
+      Int64Field = other.Int64Field;
+      Uint64Field = other.Uint64Field;
+      Int32Field = other.Int32Field;
+      Uint32Field = other.Uint32Field;
+      BoolField = other.BoolField;
+      StringField = other.StringField;
+      BytesField = other.BytesField;
+      ValueField = other.valueField_ != null ? other.ValueField.Clone() : null;
+    }
+
+    public TestWellKnownTypes Clone() {
+      return new TestWellKnownTypes(this);
+    }
+
+    /// <summary>Field number for the "any_field" field.</summary>
+    public const int AnyFieldFieldNumber = 1;
+    private global::Google.Protobuf.WellKnownTypes.Any anyField_;
+    public global::Google.Protobuf.WellKnownTypes.Any AnyField {
+      get { return anyField_; }
+      set {
+        anyField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "api_field" field.</summary>
+    public const int ApiFieldFieldNumber = 2;
+    private global::Google.Protobuf.WellKnownTypes.Api apiField_;
+    public global::Google.Protobuf.WellKnownTypes.Api ApiField {
+      get { return apiField_; }
+      set {
+        apiField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "duration_field" field.</summary>
+    public const int DurationFieldFieldNumber = 3;
+    private global::Google.Protobuf.WellKnownTypes.Duration durationField_;
+    public global::Google.Protobuf.WellKnownTypes.Duration DurationField {
+      get { return durationField_; }
+      set {
+        durationField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "empty_field" field.</summary>
+    public const int EmptyFieldFieldNumber = 4;
+    private global::Google.Protobuf.WellKnownTypes.Empty emptyField_;
+    public global::Google.Protobuf.WellKnownTypes.Empty EmptyField {
+      get { return emptyField_; }
+      set {
+        emptyField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_mask_field" field.</summary>
+    public const int FieldMaskFieldFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.FieldMask fieldMaskField_;
+    public global::Google.Protobuf.WellKnownTypes.FieldMask FieldMaskField {
+      get { return fieldMaskField_; }
+      set {
+        fieldMaskField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "source_context_field" field.</summary>
+    public const int SourceContextFieldFieldNumber = 6;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContextField_;
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContextField {
+      get { return sourceContextField_; }
+      set {
+        sourceContextField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "struct_field" field.</summary>
+    public const int StructFieldFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Struct structField_;
+    public global::Google.Protobuf.WellKnownTypes.Struct StructField {
+      get { return structField_; }
+      set {
+        structField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "timestamp_field" field.</summary>
+    public const int TimestampFieldFieldNumber = 8;
+    private global::Google.Protobuf.WellKnownTypes.Timestamp timestampField_;
+    public global::Google.Protobuf.WellKnownTypes.Timestamp TimestampField {
+      get { return timestampField_; }
+      set {
+        timestampField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "type_field" field.</summary>
+    public const int TypeFieldFieldNumber = 9;
+    private global::Google.Protobuf.WellKnownTypes.Type typeField_;
+    public global::Google.Protobuf.WellKnownTypes.Type TypeField {
+      get { return typeField_; }
+      set {
+        typeField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "double_field" field.</summary>
+    public const int DoubleFieldFieldNumber = 10;
+    private static readonly pb::FieldCodec<double?> _single_doubleField_codec = pb::FieldCodec.ForStructWrapper<double>(82);
+    private double? doubleField_;
+    public double? DoubleField {
+      get { return doubleField_; }
+      set {
+        doubleField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "float_field" field.</summary>
+    public const int FloatFieldFieldNumber = 11;
+    private static readonly pb::FieldCodec<float?> _single_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90);
+    private float? floatField_;
+    public float? FloatField {
+      get { return floatField_; }
+      set {
+        floatField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "int64_field" field.</summary>
+    public const int Int64FieldFieldNumber = 12;
+    private static readonly pb::FieldCodec<long?> _single_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98);
+    private long? int64Field_;
+    public long? Int64Field {
+      get { return int64Field_; }
+      set {
+        int64Field_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uint64_field" field.</summary>
+    public const int Uint64FieldFieldNumber = 13;
+    private static readonly pb::FieldCodec<ulong?> _single_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106);
+    private ulong? uint64Field_;
+    public ulong? Uint64Field {
+      get { return uint64Field_; }
+      set {
+        uint64Field_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "int32_field" field.</summary>
+    public const int Int32FieldFieldNumber = 14;
+    private static readonly pb::FieldCodec<int?> _single_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114);
+    private int? int32Field_;
+    public int? Int32Field {
+      get { return int32Field_; }
+      set {
+        int32Field_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uint32_field" field.</summary>
+    public const int Uint32FieldFieldNumber = 15;
+    private static readonly pb::FieldCodec<uint?> _single_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122);
+    private uint? uint32Field_;
+    public uint? Uint32Field {
+      get { return uint32Field_; }
+      set {
+        uint32Field_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "bool_field" field.</summary>
+    public const int BoolFieldFieldNumber = 16;
+    private static readonly pb::FieldCodec<bool?> _single_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130);
+    private bool? boolField_;
+    public bool? BoolField {
+      get { return boolField_; }
+      set {
+        boolField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "string_field" field.</summary>
+    public const int StringFieldFieldNumber = 17;
+    private static readonly pb::FieldCodec<string> _single_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138);
+    private string stringField_;
+    public string StringField {
+      get { return stringField_; }
+      set {
+        stringField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "bytes_field" field.</summary>
+    public const int BytesFieldFieldNumber = 18;
+    private static readonly pb::FieldCodec<pb::ByteString> _single_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
+    private pb::ByteString bytesField_;
+    public pb::ByteString BytesField {
+      get { return bytesField_; }
+      set {
+        bytesField_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "value_field" field.</summary>
+    public const int ValueFieldFieldNumber = 19;
+    private global::Google.Protobuf.WellKnownTypes.Value valueField_;
+    /// <summary>
+    ///  Part of struct, but useful to be able to test separately
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Value ValueField {
+      get { return valueField_; }
+      set {
+        valueField_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as TestWellKnownTypes);
+    }
+
+    public bool Equals(TestWellKnownTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(AnyField, other.AnyField)) return false;
+      if (!object.Equals(ApiField, other.ApiField)) return false;
+      if (!object.Equals(DurationField, other.DurationField)) return false;
+      if (!object.Equals(EmptyField, other.EmptyField)) return false;
+      if (!object.Equals(FieldMaskField, other.FieldMaskField)) return false;
+      if (!object.Equals(SourceContextField, other.SourceContextField)) return false;
+      if (!object.Equals(StructField, other.StructField)) return false;
+      if (!object.Equals(TimestampField, other.TimestampField)) return false;
+      if (!object.Equals(TypeField, other.TypeField)) return false;
+      if (DoubleField != other.DoubleField) return false;
+      if (FloatField != other.FloatField) return false;
+      if (Int64Field != other.Int64Field) return false;
+      if (Uint64Field != other.Uint64Field) return false;
+      if (Int32Field != other.Int32Field) return false;
+      if (Uint32Field != other.Uint32Field) return false;
+      if (BoolField != other.BoolField) return false;
+      if (StringField != other.StringField) return false;
+      if (BytesField != other.BytesField) return false;
+      if (!object.Equals(ValueField, other.ValueField)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (anyField_ != null) hash ^= AnyField.GetHashCode();
+      if (apiField_ != null) hash ^= ApiField.GetHashCode();
+      if (durationField_ != null) hash ^= DurationField.GetHashCode();
+      if (emptyField_ != null) hash ^= EmptyField.GetHashCode();
+      if (fieldMaskField_ != null) hash ^= FieldMaskField.GetHashCode();
+      if (sourceContextField_ != null) hash ^= SourceContextField.GetHashCode();
+      if (structField_ != null) hash ^= StructField.GetHashCode();
+      if (timestampField_ != null) hash ^= TimestampField.GetHashCode();
+      if (typeField_ != null) hash ^= TypeField.GetHashCode();
+      if (doubleField_ != null) hash ^= DoubleField.GetHashCode();
+      if (floatField_ != null) hash ^= FloatField.GetHashCode();
+      if (int64Field_ != null) hash ^= Int64Field.GetHashCode();
+      if (uint64Field_ != null) hash ^= Uint64Field.GetHashCode();
+      if (int32Field_ != null) hash ^= Int32Field.GetHashCode();
+      if (uint32Field_ != null) hash ^= Uint32Field.GetHashCode();
+      if (boolField_ != null) hash ^= BoolField.GetHashCode();
+      if (stringField_ != null) hash ^= StringField.GetHashCode();
+      if (bytesField_ != null) hash ^= BytesField.GetHashCode();
+      if (valueField_ != null) hash ^= ValueField.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (anyField_ != null) {
+        output.WriteRawTag(10);
+        output.WriteMessage(AnyField);
+      }
+      if (apiField_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(ApiField);
+      }
+      if (durationField_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(DurationField);
+      }
+      if (emptyField_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(EmptyField);
+      }
+      if (fieldMaskField_ != null) {
+        output.WriteRawTag(42);
+        output.WriteMessage(FieldMaskField);
+      }
+      if (sourceContextField_ != null) {
+        output.WriteRawTag(50);
+        output.WriteMessage(SourceContextField);
+      }
+      if (structField_ != null) {
+        output.WriteRawTag(58);
+        output.WriteMessage(StructField);
+      }
+      if (timestampField_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(TimestampField);
+      }
+      if (typeField_ != null) {
+        output.WriteRawTag(74);
+        output.WriteMessage(TypeField);
+      }
+      if (doubleField_ != null) {
+        _single_doubleField_codec.WriteTagAndValue(output, DoubleField);
+      }
+      if (floatField_ != null) {
+        _single_floatField_codec.WriteTagAndValue(output, FloatField);
+      }
+      if (int64Field_ != null) {
+        _single_int64Field_codec.WriteTagAndValue(output, Int64Field);
+      }
+      if (uint64Field_ != null) {
+        _single_uint64Field_codec.WriteTagAndValue(output, Uint64Field);
+      }
+      if (int32Field_ != null) {
+        _single_int32Field_codec.WriteTagAndValue(output, Int32Field);
+      }
+      if (uint32Field_ != null) {
+        _single_uint32Field_codec.WriteTagAndValue(output, Uint32Field);
+      }
+      if (boolField_ != null) {
+        _single_boolField_codec.WriteTagAndValue(output, BoolField);
+      }
+      if (stringField_ != null) {
+        _single_stringField_codec.WriteTagAndValue(output, StringField);
+      }
+      if (bytesField_ != null) {
+        _single_bytesField_codec.WriteTagAndValue(output, BytesField);
+      }
+      if (valueField_ != null) {
+        output.WriteRawTag(154, 1);
+        output.WriteMessage(ValueField);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (anyField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(AnyField);
+      }
+      if (apiField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ApiField);
+      }
+      if (durationField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(DurationField);
+      }
+      if (emptyField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(EmptyField);
+      }
+      if (fieldMaskField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(FieldMaskField);
+      }
+      if (sourceContextField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContextField);
+      }
+      if (structField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(StructField);
+      }
+      if (timestampField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(TimestampField);
+      }
+      if (typeField_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(TypeField);
+      }
+      if (doubleField_ != null) {
+        size += _single_doubleField_codec.CalculateSizeWithTag(DoubleField);
+      }
+      if (floatField_ != null) {
+        size += _single_floatField_codec.CalculateSizeWithTag(FloatField);
+      }
+      if (int64Field_ != null) {
+        size += _single_int64Field_codec.CalculateSizeWithTag(Int64Field);
+      }
+      if (uint64Field_ != null) {
+        size += _single_uint64Field_codec.CalculateSizeWithTag(Uint64Field);
+      }
+      if (int32Field_ != null) {
+        size += _single_int32Field_codec.CalculateSizeWithTag(Int32Field);
+      }
+      if (uint32Field_ != null) {
+        size += _single_uint32Field_codec.CalculateSizeWithTag(Uint32Field);
+      }
+      if (boolField_ != null) {
+        size += _single_boolField_codec.CalculateSizeWithTag(BoolField);
+      }
+      if (stringField_ != null) {
+        size += _single_stringField_codec.CalculateSizeWithTag(StringField);
+      }
+      if (bytesField_ != null) {
+        size += _single_bytesField_codec.CalculateSizeWithTag(BytesField);
+      }
+      if (valueField_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(ValueField);
+      }
+      return size;
+    }
+
+    public void MergeFrom(TestWellKnownTypes other) {
+      if (other == null) {
+        return;
+      }
+      if (other.anyField_ != null) {
+        if (anyField_ == null) {
+          anyField_ = new global::Google.Protobuf.WellKnownTypes.Any();
+        }
+        AnyField.MergeFrom(other.AnyField);
+      }
+      if (other.apiField_ != null) {
+        if (apiField_ == null) {
+          apiField_ = new global::Google.Protobuf.WellKnownTypes.Api();
+        }
+        ApiField.MergeFrom(other.ApiField);
+      }
+      if (other.durationField_ != null) {
+        if (durationField_ == null) {
+          durationField_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+        }
+        DurationField.MergeFrom(other.DurationField);
+      }
+      if (other.emptyField_ != null) {
+        if (emptyField_ == null) {
+          emptyField_ = new global::Google.Protobuf.WellKnownTypes.Empty();
+        }
+        EmptyField.MergeFrom(other.EmptyField);
+      }
+      if (other.fieldMaskField_ != null) {
+        if (fieldMaskField_ == null) {
+          fieldMaskField_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+        }
+        FieldMaskField.MergeFrom(other.FieldMaskField);
+      }
+      if (other.sourceContextField_ != null) {
+        if (sourceContextField_ == null) {
+          sourceContextField_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContextField.MergeFrom(other.SourceContextField);
+      }
+      if (other.structField_ != null) {
+        if (structField_ == null) {
+          structField_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+        }
+        StructField.MergeFrom(other.StructField);
+      }
+      if (other.timestampField_ != null) {
+        if (timestampField_ == null) {
+          timestampField_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+        }
+        TimestampField.MergeFrom(other.TimestampField);
+      }
+      if (other.typeField_ != null) {
+        if (typeField_ == null) {
+          typeField_ = new global::Google.Protobuf.WellKnownTypes.Type();
+        }
+        TypeField.MergeFrom(other.TypeField);
+      }
+      if (other.doubleField_ != null) {
+        if (doubleField_ == null || other.DoubleField != 0D) {
+          DoubleField = other.DoubleField;
+        }
+      }
+      if (other.floatField_ != null) {
+        if (floatField_ == null || other.FloatField != 0F) {
+          FloatField = other.FloatField;
+        }
+      }
+      if (other.int64Field_ != null) {
+        if (int64Field_ == null || other.Int64Field != 0L) {
+          Int64Field = other.Int64Field;
+        }
+      }
+      if (other.uint64Field_ != null) {
+        if (uint64Field_ == null || other.Uint64Field != 0UL) {
+          Uint64Field = other.Uint64Field;
+        }
+      }
+      if (other.int32Field_ != null) {
+        if (int32Field_ == null || other.Int32Field != 0) {
+          Int32Field = other.Int32Field;
+        }
+      }
+      if (other.uint32Field_ != null) {
+        if (uint32Field_ == null || other.Uint32Field != 0) {
+          Uint32Field = other.Uint32Field;
+        }
+      }
+      if (other.boolField_ != null) {
+        if (boolField_ == null || other.BoolField != false) {
+          BoolField = other.BoolField;
+        }
+      }
+      if (other.stringField_ != null) {
+        if (stringField_ == null || other.StringField != "") {
+          StringField = other.StringField;
+        }
+      }
+      if (other.bytesField_ != null) {
+        if (bytesField_ == null || other.BytesField != pb::ByteString.Empty) {
+          BytesField = other.BytesField;
+        }
+      }
+      if (other.valueField_ != null) {
+        if (valueField_ == null) {
+          valueField_ = new global::Google.Protobuf.WellKnownTypes.Value();
+        }
+        ValueField.MergeFrom(other.ValueField);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            if (anyField_ == null) {
+              anyField_ = new global::Google.Protobuf.WellKnownTypes.Any();
+            }
+            input.ReadMessage(anyField_);
+            break;
+          }
+          case 18: {
+            if (apiField_ == null) {
+              apiField_ = new global::Google.Protobuf.WellKnownTypes.Api();
+            }
+            input.ReadMessage(apiField_);
+            break;
+          }
+          case 26: {
+            if (durationField_ == null) {
+              durationField_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+            }
+            input.ReadMessage(durationField_);
+            break;
+          }
+          case 34: {
+            if (emptyField_ == null) {
+              emptyField_ = new global::Google.Protobuf.WellKnownTypes.Empty();
+            }
+            input.ReadMessage(emptyField_);
+            break;
+          }
+          case 42: {
+            if (fieldMaskField_ == null) {
+              fieldMaskField_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+            }
+            input.ReadMessage(fieldMaskField_);
+            break;
+          }
+          case 50: {
+            if (sourceContextField_ == null) {
+              sourceContextField_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContextField_);
+            break;
+          }
+          case 58: {
+            if (structField_ == null) {
+              structField_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+            }
+            input.ReadMessage(structField_);
+            break;
+          }
+          case 66: {
+            if (timestampField_ == null) {
+              timestampField_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+            }
+            input.ReadMessage(timestampField_);
+            break;
+          }
+          case 74: {
+            if (typeField_ == null) {
+              typeField_ = new global::Google.Protobuf.WellKnownTypes.Type();
+            }
+            input.ReadMessage(typeField_);
+            break;
+          }
+          case 82: {
+            double? value = _single_doubleField_codec.Read(input);
+            if (doubleField_ == null || value != 0D) {
+              DoubleField = value;
+            }
+            break;
+          }
+          case 90: {
+            float? value = _single_floatField_codec.Read(input);
+            if (floatField_ == null || value != 0F) {
+              FloatField = value;
+            }
+            break;
+          }
+          case 98: {
+            long? value = _single_int64Field_codec.Read(input);
+            if (int64Field_ == null || value != 0L) {
+              Int64Field = value;
+            }
+            break;
+          }
+          case 106: {
+            ulong? value = _single_uint64Field_codec.Read(input);
+            if (uint64Field_ == null || value != 0UL) {
+              Uint64Field = value;
+            }
+            break;
+          }
+          case 114: {
+            int? value = _single_int32Field_codec.Read(input);
+            if (int32Field_ == null || value != 0) {
+              Int32Field = value;
+            }
+            break;
+          }
+          case 122: {
+            uint? value = _single_uint32Field_codec.Read(input);
+            if (uint32Field_ == null || value != 0) {
+              Uint32Field = value;
+            }
+            break;
+          }
+          case 130: {
+            bool? value = _single_boolField_codec.Read(input);
+            if (boolField_ == null || value != false) {
+              BoolField = value;
+            }
+            break;
+          }
+          case 138: {
+            string value = _single_stringField_codec.Read(input);
+            if (stringField_ == null || value != "") {
+              StringField = value;
+            }
+            break;
+          }
+          case 146: {
+            pb::ByteString value = _single_bytesField_codec.Read(input);
+            if (bytesField_ == null || value != pb::ByteString.Empty) {
+              BytesField = value;
+            }
+            break;
+          }
+          case 154: {
+            if (valueField_ == null) {
+              valueField_ = new global::Google.Protobuf.WellKnownTypes.Value();
+            }
+            input.ReadMessage(valueField_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A repeated field for each well-known type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class RepeatedWellKnownTypes : pb::IMessage<RepeatedWellKnownTypes> {
+    private static readonly pb::MessageParser<RepeatedWellKnownTypes> _parser = new pb::MessageParser<RepeatedWellKnownTypes>(() => new RepeatedWellKnownTypes());
+    public static pb::MessageParser<RepeatedWellKnownTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public RepeatedWellKnownTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public RepeatedWellKnownTypes(RepeatedWellKnownTypes other) : this() {
+      anyField_ = other.anyField_.Clone();
+      apiField_ = other.apiField_.Clone();
+      durationField_ = other.durationField_.Clone();
+      emptyField_ = other.emptyField_.Clone();
+      fieldMaskField_ = other.fieldMaskField_.Clone();
+      sourceContextField_ = other.sourceContextField_.Clone();
+      structField_ = other.structField_.Clone();
+      timestampField_ = other.timestampField_.Clone();
+      typeField_ = other.typeField_.Clone();
+      doubleField_ = other.doubleField_.Clone();
+      floatField_ = other.floatField_.Clone();
+      int64Field_ = other.int64Field_.Clone();
+      uint64Field_ = other.uint64Field_.Clone();
+      int32Field_ = other.int32Field_.Clone();
+      uint32Field_ = other.uint32Field_.Clone();
+      boolField_ = other.boolField_.Clone();
+      stringField_ = other.stringField_.Clone();
+      bytesField_ = other.bytesField_.Clone();
+    }
+
+    public RepeatedWellKnownTypes Clone() {
+      return new RepeatedWellKnownTypes(this);
+    }
+
+    /// <summary>Field number for the "any_field" field.</summary>
+    public const int AnyFieldFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Any> _repeated_anyField_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> anyField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> AnyField {
+      get { return anyField_; }
+    }
+
+    /// <summary>Field number for the "api_field" field.</summary>
+    public const int ApiFieldFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Api> _repeated_apiField_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Api.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Api> apiField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Api>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Api> ApiField {
+      get { return apiField_; }
+    }
+
+    /// <summary>Field number for the "duration_field" field.</summary>
+    public const int DurationFieldFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Duration> _repeated_durationField_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Duration.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> durationField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> DurationField {
+      get { return durationField_; }
+    }
+
+    /// <summary>Field number for the "empty_field" field.</summary>
+    public const int EmptyFieldFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Empty> _repeated_emptyField_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Empty.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Empty> emptyField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Empty>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Empty> EmptyField {
+      get { return emptyField_; }
+    }
+
+    /// <summary>Field number for the "field_mask_field" field.</summary>
+    public const int FieldMaskFieldFieldNumber = 5;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.FieldMask> _repeated_fieldMaskField_codec
+        = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> fieldMaskField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> FieldMaskField {
+      get { return fieldMaskField_; }
+    }
+
+    /// <summary>Field number for the "source_context_field" field.</summary>
+    public const int SourceContextFieldFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.SourceContext> _repeated_sourceContextField_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.SourceContext.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.SourceContext> sourceContextField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.SourceContext>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.SourceContext> SourceContextField {
+      get { return sourceContextField_; }
+    }
+
+    /// <summary>Field number for the "struct_field" field.</summary>
+    public const int StructFieldFieldNumber = 7;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Struct> _repeated_structField_codec
+        = pb::FieldCodec.ForMessage(58, global::Google.Protobuf.WellKnownTypes.Struct.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> structField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> StructField {
+      get { return structField_; }
+    }
+
+    /// <summary>Field number for the "timestamp_field" field.</summary>
+    public const int TimestampFieldFieldNumber = 8;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Timestamp> _repeated_timestampField_codec
+        = pb::FieldCodec.ForMessage(66, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> timestampField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> TimestampField {
+      get { return timestampField_; }
+    }
+
+    /// <summary>Field number for the "type_field" field.</summary>
+    public const int TypeFieldFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Type> _repeated_typeField_codec
+        = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Type.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Type> typeField_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Type>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Type> TypeField {
+      get { return typeField_; }
+    }
+
+    /// <summary>Field number for the "double_field" field.</summary>
+    public const int DoubleFieldFieldNumber = 10;
+    private static readonly pb::FieldCodec<double?> _repeated_doubleField_codec
+        = pb::FieldCodec.ForStructWrapper<double>(82);
+    private readonly pbc::RepeatedField<double?> doubleField_ = new pbc::RepeatedField<double?>();
+    /// <summary>
+    ///  These don't actually make a lot of sense, but they're not prohibited...
+    /// </summary>
+    public pbc::RepeatedField<double?> DoubleField {
+      get { return doubleField_; }
+    }
+
+    /// <summary>Field number for the "float_field" field.</summary>
+    public const int FloatFieldFieldNumber = 11;
+    private static readonly pb::FieldCodec<float?> _repeated_floatField_codec
+        = pb::FieldCodec.ForStructWrapper<float>(90);
+    private readonly pbc::RepeatedField<float?> floatField_ = new pbc::RepeatedField<float?>();
+    public pbc::RepeatedField<float?> FloatField {
+      get { return floatField_; }
+    }
+
+    /// <summary>Field number for the "int64_field" field.</summary>
+    public const int Int64FieldFieldNumber = 12;
+    private static readonly pb::FieldCodec<long?> _repeated_int64Field_codec
+        = pb::FieldCodec.ForStructWrapper<long>(98);
+    private readonly pbc::RepeatedField<long?> int64Field_ = new pbc::RepeatedField<long?>();
+    public pbc::RepeatedField<long?> Int64Field {
+      get { return int64Field_; }
+    }
+
+    /// <summary>Field number for the "uint64_field" field.</summary>
+    public const int Uint64FieldFieldNumber = 13;
+    private static readonly pb::FieldCodec<ulong?> _repeated_uint64Field_codec
+        = pb::FieldCodec.ForStructWrapper<ulong>(106);
+    private readonly pbc::RepeatedField<ulong?> uint64Field_ = new pbc::RepeatedField<ulong?>();
+    public pbc::RepeatedField<ulong?> Uint64Field {
+      get { return uint64Field_; }
+    }
+
+    /// <summary>Field number for the "int32_field" field.</summary>
+    public const int Int32FieldFieldNumber = 14;
+    private static readonly pb::FieldCodec<int?> _repeated_int32Field_codec
+        = pb::FieldCodec.ForStructWrapper<int>(114);
+    private readonly pbc::RepeatedField<int?> int32Field_ = new pbc::RepeatedField<int?>();
+    public pbc::RepeatedField<int?> Int32Field {
+      get { return int32Field_; }
+    }
+
+    /// <summary>Field number for the "uint32_field" field.</summary>
+    public const int Uint32FieldFieldNumber = 15;
+    private static readonly pb::FieldCodec<uint?> _repeated_uint32Field_codec
+        = pb::FieldCodec.ForStructWrapper<uint>(122);
+    private readonly pbc::RepeatedField<uint?> uint32Field_ = new pbc::RepeatedField<uint?>();
+    public pbc::RepeatedField<uint?> Uint32Field {
+      get { return uint32Field_; }
+    }
+
+    /// <summary>Field number for the "bool_field" field.</summary>
+    public const int BoolFieldFieldNumber = 16;
+    private static readonly pb::FieldCodec<bool?> _repeated_boolField_codec
+        = pb::FieldCodec.ForStructWrapper<bool>(130);
+    private readonly pbc::RepeatedField<bool?> boolField_ = new pbc::RepeatedField<bool?>();
+    public pbc::RepeatedField<bool?> BoolField {
+      get { return boolField_; }
+    }
+
+    /// <summary>Field number for the "string_field" field.</summary>
+    public const int StringFieldFieldNumber = 17;
+    private static readonly pb::FieldCodec<string> _repeated_stringField_codec
+        = pb::FieldCodec.ForClassWrapper<string>(138);
+    private readonly pbc::RepeatedField<string> stringField_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> StringField {
+      get { return stringField_; }
+    }
+
+    /// <summary>Field number for the "bytes_field" field.</summary>
+    public const int BytesFieldFieldNumber = 18;
+    private static readonly pb::FieldCodec<pb::ByteString> _repeated_bytesField_codec
+        = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
+    private readonly pbc::RepeatedField<pb::ByteString> bytesField_ = new pbc::RepeatedField<pb::ByteString>();
+    public pbc::RepeatedField<pb::ByteString> BytesField {
+      get { return bytesField_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as RepeatedWellKnownTypes);
+    }
+
+    public bool Equals(RepeatedWellKnownTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!anyField_.Equals(other.anyField_)) return false;
+      if(!apiField_.Equals(other.apiField_)) return false;
+      if(!durationField_.Equals(other.durationField_)) return false;
+      if(!emptyField_.Equals(other.emptyField_)) return false;
+      if(!fieldMaskField_.Equals(other.fieldMaskField_)) return false;
+      if(!sourceContextField_.Equals(other.sourceContextField_)) return false;
+      if(!structField_.Equals(other.structField_)) return false;
+      if(!timestampField_.Equals(other.timestampField_)) return false;
+      if(!typeField_.Equals(other.typeField_)) return false;
+      if(!doubleField_.Equals(other.doubleField_)) return false;
+      if(!floatField_.Equals(other.floatField_)) return false;
+      if(!int64Field_.Equals(other.int64Field_)) return false;
+      if(!uint64Field_.Equals(other.uint64Field_)) return false;
+      if(!int32Field_.Equals(other.int32Field_)) return false;
+      if(!uint32Field_.Equals(other.uint32Field_)) return false;
+      if(!boolField_.Equals(other.boolField_)) return false;
+      if(!stringField_.Equals(other.stringField_)) return false;
+      if(!bytesField_.Equals(other.bytesField_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= anyField_.GetHashCode();
+      hash ^= apiField_.GetHashCode();
+      hash ^= durationField_.GetHashCode();
+      hash ^= emptyField_.GetHashCode();
+      hash ^= fieldMaskField_.GetHashCode();
+      hash ^= sourceContextField_.GetHashCode();
+      hash ^= structField_.GetHashCode();
+      hash ^= timestampField_.GetHashCode();
+      hash ^= typeField_.GetHashCode();
+      hash ^= doubleField_.GetHashCode();
+      hash ^= floatField_.GetHashCode();
+      hash ^= int64Field_.GetHashCode();
+      hash ^= uint64Field_.GetHashCode();
+      hash ^= int32Field_.GetHashCode();
+      hash ^= uint32Field_.GetHashCode();
+      hash ^= boolField_.GetHashCode();
+      hash ^= stringField_.GetHashCode();
+      hash ^= bytesField_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      anyField_.WriteTo(output, _repeated_anyField_codec);
+      apiField_.WriteTo(output, _repeated_apiField_codec);
+      durationField_.WriteTo(output, _repeated_durationField_codec);
+      emptyField_.WriteTo(output, _repeated_emptyField_codec);
+      fieldMaskField_.WriteTo(output, _repeated_fieldMaskField_codec);
+      sourceContextField_.WriteTo(output, _repeated_sourceContextField_codec);
+      structField_.WriteTo(output, _repeated_structField_codec);
+      timestampField_.WriteTo(output, _repeated_timestampField_codec);
+      typeField_.WriteTo(output, _repeated_typeField_codec);
+      doubleField_.WriteTo(output, _repeated_doubleField_codec);
+      floatField_.WriteTo(output, _repeated_floatField_codec);
+      int64Field_.WriteTo(output, _repeated_int64Field_codec);
+      uint64Field_.WriteTo(output, _repeated_uint64Field_codec);
+      int32Field_.WriteTo(output, _repeated_int32Field_codec);
+      uint32Field_.WriteTo(output, _repeated_uint32Field_codec);
+      boolField_.WriteTo(output, _repeated_boolField_codec);
+      stringField_.WriteTo(output, _repeated_stringField_codec);
+      bytesField_.WriteTo(output, _repeated_bytesField_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += anyField_.CalculateSize(_repeated_anyField_codec);
+      size += apiField_.CalculateSize(_repeated_apiField_codec);
+      size += durationField_.CalculateSize(_repeated_durationField_codec);
+      size += emptyField_.CalculateSize(_repeated_emptyField_codec);
+      size += fieldMaskField_.CalculateSize(_repeated_fieldMaskField_codec);
+      size += sourceContextField_.CalculateSize(_repeated_sourceContextField_codec);
+      size += structField_.CalculateSize(_repeated_structField_codec);
+      size += timestampField_.CalculateSize(_repeated_timestampField_codec);
+      size += typeField_.CalculateSize(_repeated_typeField_codec);
+      size += doubleField_.CalculateSize(_repeated_doubleField_codec);
+      size += floatField_.CalculateSize(_repeated_floatField_codec);
+      size += int64Field_.CalculateSize(_repeated_int64Field_codec);
+      size += uint64Field_.CalculateSize(_repeated_uint64Field_codec);
+      size += int32Field_.CalculateSize(_repeated_int32Field_codec);
+      size += uint32Field_.CalculateSize(_repeated_uint32Field_codec);
+      size += boolField_.CalculateSize(_repeated_boolField_codec);
+      size += stringField_.CalculateSize(_repeated_stringField_codec);
+      size += bytesField_.CalculateSize(_repeated_bytesField_codec);
+      return size;
+    }
+
+    public void MergeFrom(RepeatedWellKnownTypes other) {
+      if (other == null) {
+        return;
+      }
+      anyField_.Add(other.anyField_);
+      apiField_.Add(other.apiField_);
+      durationField_.Add(other.durationField_);
+      emptyField_.Add(other.emptyField_);
+      fieldMaskField_.Add(other.fieldMaskField_);
+      sourceContextField_.Add(other.sourceContextField_);
+      structField_.Add(other.structField_);
+      timestampField_.Add(other.timestampField_);
+      typeField_.Add(other.typeField_);
+      doubleField_.Add(other.doubleField_);
+      floatField_.Add(other.floatField_);
+      int64Field_.Add(other.int64Field_);
+      uint64Field_.Add(other.uint64Field_);
+      int32Field_.Add(other.int32Field_);
+      uint32Field_.Add(other.uint32Field_);
+      boolField_.Add(other.boolField_);
+      stringField_.Add(other.stringField_);
+      bytesField_.Add(other.bytesField_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            anyField_.AddEntriesFrom(input, _repeated_anyField_codec);
+            break;
+          }
+          case 18: {
+            apiField_.AddEntriesFrom(input, _repeated_apiField_codec);
+            break;
+          }
+          case 26: {
+            durationField_.AddEntriesFrom(input, _repeated_durationField_codec);
+            break;
+          }
+          case 34: {
+            emptyField_.AddEntriesFrom(input, _repeated_emptyField_codec);
+            break;
+          }
+          case 42: {
+            fieldMaskField_.AddEntriesFrom(input, _repeated_fieldMaskField_codec);
+            break;
+          }
+          case 50: {
+            sourceContextField_.AddEntriesFrom(input, _repeated_sourceContextField_codec);
+            break;
+          }
+          case 58: {
+            structField_.AddEntriesFrom(input, _repeated_structField_codec);
+            break;
+          }
+          case 66: {
+            timestampField_.AddEntriesFrom(input, _repeated_timestampField_codec);
+            break;
+          }
+          case 74: {
+            typeField_.AddEntriesFrom(input, _repeated_typeField_codec);
+            break;
+          }
+          case 82: {
+            doubleField_.AddEntriesFrom(input, _repeated_doubleField_codec);
+            break;
+          }
+          case 90: {
+            floatField_.AddEntriesFrom(input, _repeated_floatField_codec);
+            break;
+          }
+          case 98: {
+            int64Field_.AddEntriesFrom(input, _repeated_int64Field_codec);
+            break;
+          }
+          case 106: {
+            uint64Field_.AddEntriesFrom(input, _repeated_uint64Field_codec);
+            break;
+          }
+          case 114: {
+            int32Field_.AddEntriesFrom(input, _repeated_int32Field_codec);
+            break;
+          }
+          case 122: {
+            uint32Field_.AddEntriesFrom(input, _repeated_uint32Field_codec);
+            break;
+          }
+          case 130: {
+            boolField_.AddEntriesFrom(input, _repeated_boolField_codec);
+            break;
+          }
+          case 138: {
+            stringField_.AddEntriesFrom(input, _repeated_stringField_codec);
+            break;
+          }
+          case 146: {
+            bytesField_.AddEntriesFrom(input, _repeated_bytesField_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class OneofWellKnownTypes : pb::IMessage<OneofWellKnownTypes> {
+    private static readonly pb::MessageParser<OneofWellKnownTypes> _parser = new pb::MessageParser<OneofWellKnownTypes>(() => new OneofWellKnownTypes());
+    public static pb::MessageParser<OneofWellKnownTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public OneofWellKnownTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public OneofWellKnownTypes(OneofWellKnownTypes other) : this() {
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.AnyField:
+          AnyField = other.AnyField.Clone();
+          break;
+        case OneofFieldOneofCase.ApiField:
+          ApiField = other.ApiField.Clone();
+          break;
+        case OneofFieldOneofCase.DurationField:
+          DurationField = other.DurationField.Clone();
+          break;
+        case OneofFieldOneofCase.EmptyField:
+          EmptyField = other.EmptyField.Clone();
+          break;
+        case OneofFieldOneofCase.FieldMaskField:
+          FieldMaskField = other.FieldMaskField.Clone();
+          break;
+        case OneofFieldOneofCase.SourceContextField:
+          SourceContextField = other.SourceContextField.Clone();
+          break;
+        case OneofFieldOneofCase.StructField:
+          StructField = other.StructField.Clone();
+          break;
+        case OneofFieldOneofCase.TimestampField:
+          TimestampField = other.TimestampField.Clone();
+          break;
+        case OneofFieldOneofCase.TypeField:
+          TypeField = other.TypeField.Clone();
+          break;
+        case OneofFieldOneofCase.DoubleField:
+          DoubleField = other.DoubleField;
+          break;
+        case OneofFieldOneofCase.FloatField:
+          FloatField = other.FloatField;
+          break;
+        case OneofFieldOneofCase.Int64Field:
+          Int64Field = other.Int64Field;
+          break;
+        case OneofFieldOneofCase.Uint64Field:
+          Uint64Field = other.Uint64Field;
+          break;
+        case OneofFieldOneofCase.Int32Field:
+          Int32Field = other.Int32Field;
+          break;
+        case OneofFieldOneofCase.Uint32Field:
+          Uint32Field = other.Uint32Field;
+          break;
+        case OneofFieldOneofCase.BoolField:
+          BoolField = other.BoolField;
+          break;
+        case OneofFieldOneofCase.StringField:
+          StringField = other.StringField;
+          break;
+        case OneofFieldOneofCase.BytesField:
+          BytesField = other.BytesField;
+          break;
+      }
+
+    }
+
+    public OneofWellKnownTypes Clone() {
+      return new OneofWellKnownTypes(this);
+    }
+
+    /// <summary>Field number for the "any_field" field.</summary>
+    public const int AnyFieldFieldNumber = 1;
+    public global::Google.Protobuf.WellKnownTypes.Any AnyField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.AnyField ? (global::Google.Protobuf.WellKnownTypes.Any) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.AnyField;
+      }
+    }
+
+    /// <summary>Field number for the "api_field" field.</summary>
+    public const int ApiFieldFieldNumber = 2;
+    public global::Google.Protobuf.WellKnownTypes.Api ApiField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.ApiField ? (global::Google.Protobuf.WellKnownTypes.Api) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.ApiField;
+      }
+    }
+
+    /// <summary>Field number for the "duration_field" field.</summary>
+    public const int DurationFieldFieldNumber = 3;
+    public global::Google.Protobuf.WellKnownTypes.Duration DurationField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.DurationField ? (global::Google.Protobuf.WellKnownTypes.Duration) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.DurationField;
+      }
+    }
+
+    /// <summary>Field number for the "empty_field" field.</summary>
+    public const int EmptyFieldFieldNumber = 4;
+    public global::Google.Protobuf.WellKnownTypes.Empty EmptyField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.EmptyField ? (global::Google.Protobuf.WellKnownTypes.Empty) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.EmptyField;
+      }
+    }
+
+    /// <summary>Field number for the "field_mask_field" field.</summary>
+    public const int FieldMaskFieldFieldNumber = 5;
+    public global::Google.Protobuf.WellKnownTypes.FieldMask FieldMaskField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField ? (global::Google.Protobuf.WellKnownTypes.FieldMask) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.FieldMaskField;
+      }
+    }
+
+    /// <summary>Field number for the "source_context_field" field.</summary>
+    public const int SourceContextFieldFieldNumber = 6;
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContextField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.SourceContextField ? (global::Google.Protobuf.WellKnownTypes.SourceContext) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.SourceContextField;
+      }
+    }
+
+    /// <summary>Field number for the "struct_field" field.</summary>
+    public const int StructFieldFieldNumber = 7;
+    public global::Google.Protobuf.WellKnownTypes.Struct StructField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.StructField ? (global::Google.Protobuf.WellKnownTypes.Struct) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.StructField;
+      }
+    }
+
+    /// <summary>Field number for the "timestamp_field" field.</summary>
+    public const int TimestampFieldFieldNumber = 8;
+    public global::Google.Protobuf.WellKnownTypes.Timestamp TimestampField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.TimestampField ? (global::Google.Protobuf.WellKnownTypes.Timestamp) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.TimestampField;
+      }
+    }
+
+    /// <summary>Field number for the "type_field" field.</summary>
+    public const int TypeFieldFieldNumber = 9;
+    public global::Google.Protobuf.WellKnownTypes.Type TypeField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.TypeField ? (global::Google.Protobuf.WellKnownTypes.Type) oneofField_ : null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.TypeField;
+      }
+    }
+
+    /// <summary>Field number for the "double_field" field.</summary>
+    public const int DoubleFieldFieldNumber = 10;
+    private static readonly pb::FieldCodec<double?> _oneof_doubleField_codec = pb::FieldCodec.ForStructWrapper<double>(82);
+    public double? DoubleField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.DoubleField ? (double?) oneofField_ : (double?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.DoubleField;
+      }
+    }
+
+    /// <summary>Field number for the "float_field" field.</summary>
+    public const int FloatFieldFieldNumber = 11;
+    private static readonly pb::FieldCodec<float?> _oneof_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90);
+    public float? FloatField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.FloatField ? (float?) oneofField_ : (float?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.FloatField;
+      }
+    }
+
+    /// <summary>Field number for the "int64_field" field.</summary>
+    public const int Int64FieldFieldNumber = 12;
+    private static readonly pb::FieldCodec<long?> _oneof_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98);
+    public long? Int64Field {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.Int64Field ? (long?) oneofField_ : (long?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.Int64Field;
+      }
+    }
+
+    /// <summary>Field number for the "uint64_field" field.</summary>
+    public const int Uint64FieldFieldNumber = 13;
+    private static readonly pb::FieldCodec<ulong?> _oneof_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106);
+    public ulong? Uint64Field {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.Uint64Field ? (ulong?) oneofField_ : (ulong?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.Uint64Field;
+      }
+    }
+
+    /// <summary>Field number for the "int32_field" field.</summary>
+    public const int Int32FieldFieldNumber = 14;
+    private static readonly pb::FieldCodec<int?> _oneof_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114);
+    public int? Int32Field {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.Int32Field ? (int?) oneofField_ : (int?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.Int32Field;
+      }
+    }
+
+    /// <summary>Field number for the "uint32_field" field.</summary>
+    public const int Uint32FieldFieldNumber = 15;
+    private static readonly pb::FieldCodec<uint?> _oneof_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122);
+    public uint? Uint32Field {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.Uint32Field ? (uint?) oneofField_ : (uint?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.Uint32Field;
+      }
+    }
+
+    /// <summary>Field number for the "bool_field" field.</summary>
+    public const int BoolFieldFieldNumber = 16;
+    private static readonly pb::FieldCodec<bool?> _oneof_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130);
+    public bool? BoolField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.BoolField ? (bool?) oneofField_ : (bool?) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.BoolField;
+      }
+    }
+
+    /// <summary>Field number for the "string_field" field.</summary>
+    public const int StringFieldFieldNumber = 17;
+    private static readonly pb::FieldCodec<string> _oneof_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138);
+    public string StringField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.StringField ? (string) oneofField_ : (string) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.StringField;
+      }
+    }
+
+    /// <summary>Field number for the "bytes_field" field.</summary>
+    public const int BytesFieldFieldNumber = 18;
+    private static readonly pb::FieldCodec<pb::ByteString> _oneof_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
+    public pb::ByteString BytesField {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.BytesField ? (pb::ByteString) oneofField_ : (pb::ByteString) null; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = value == null ? OneofFieldOneofCase.None : OneofFieldOneofCase.BytesField;
+      }
+    }
+
+    private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
+    public enum OneofFieldOneofCase {
+      None = 0,
+      AnyField = 1,
+      ApiField = 2,
+      DurationField = 3,
+      EmptyField = 4,
+      FieldMaskField = 5,
+      SourceContextField = 6,
+      StructField = 7,
+      TimestampField = 8,
+      TypeField = 9,
+      DoubleField = 10,
+      FloatField = 11,
+      Int64Field = 12,
+      Uint64Field = 13,
+      Int32Field = 14,
+      Uint32Field = 15,
+      BoolField = 16,
+      StringField = 17,
+      BytesField = 18,
+    }
+    private OneofFieldOneofCase oneofFieldCase_ = OneofFieldOneofCase.None;
+    public OneofFieldOneofCase OneofFieldCase {
+      get { return oneofFieldCase_; }
+    }
+
+    public void ClearOneofField() {
+      oneofFieldCase_ = OneofFieldOneofCase.None;
+      oneofField_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as OneofWellKnownTypes);
+    }
+
+    public bool Equals(OneofWellKnownTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!object.Equals(AnyField, other.AnyField)) return false;
+      if (!object.Equals(ApiField, other.ApiField)) return false;
+      if (!object.Equals(DurationField, other.DurationField)) return false;
+      if (!object.Equals(EmptyField, other.EmptyField)) return false;
+      if (!object.Equals(FieldMaskField, other.FieldMaskField)) return false;
+      if (!object.Equals(SourceContextField, other.SourceContextField)) return false;
+      if (!object.Equals(StructField, other.StructField)) return false;
+      if (!object.Equals(TimestampField, other.TimestampField)) return false;
+      if (!object.Equals(TypeField, other.TypeField)) return false;
+      if (DoubleField != other.DoubleField) return false;
+      if (FloatField != other.FloatField) return false;
+      if (Int64Field != other.Int64Field) return false;
+      if (Uint64Field != other.Uint64Field) return false;
+      if (Int32Field != other.Int32Field) return false;
+      if (Uint32Field != other.Uint32Field) return false;
+      if (BoolField != other.BoolField) return false;
+      if (StringField != other.StringField) return false;
+      if (BytesField != other.BytesField) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (oneofFieldCase_ == OneofFieldOneofCase.AnyField) hash ^= AnyField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.ApiField) hash ^= ApiField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.DurationField) hash ^= DurationField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.EmptyField) hash ^= EmptyField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField) hash ^= FieldMaskField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.SourceContextField) hash ^= SourceContextField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.StructField) hash ^= StructField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.TimestampField) hash ^= TimestampField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.TypeField) hash ^= TypeField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.DoubleField) hash ^= DoubleField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.FloatField) hash ^= FloatField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int64Field) hash ^= Int64Field.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint64Field) hash ^= Uint64Field.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int32Field) hash ^= Int32Field.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint32Field) hash ^= Uint32Field.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.BoolField) hash ^= BoolField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.StringField) hash ^= StringField.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.BytesField) hash ^= BytesField.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (oneofFieldCase_ == OneofFieldOneofCase.AnyField) {
+        output.WriteRawTag(10);
+        output.WriteMessage(AnyField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.ApiField) {
+        output.WriteRawTag(18);
+        output.WriteMessage(ApiField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.DurationField) {
+        output.WriteRawTag(26);
+        output.WriteMessage(DurationField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.EmptyField) {
+        output.WriteRawTag(34);
+        output.WriteMessage(EmptyField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField) {
+        output.WriteRawTag(42);
+        output.WriteMessage(FieldMaskField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.SourceContextField) {
+        output.WriteRawTag(50);
+        output.WriteMessage(SourceContextField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.StructField) {
+        output.WriteRawTag(58);
+        output.WriteMessage(StructField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.TimestampField) {
+        output.WriteRawTag(66);
+        output.WriteMessage(TimestampField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.TypeField) {
+        output.WriteRawTag(74);
+        output.WriteMessage(TypeField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.DoubleField) {
+        _oneof_doubleField_codec.WriteTagAndValue(output, (double?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.FloatField) {
+        _oneof_floatField_codec.WriteTagAndValue(output, (float?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int64Field) {
+        _oneof_int64Field_codec.WriteTagAndValue(output, (long?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint64Field) {
+        _oneof_uint64Field_codec.WriteTagAndValue(output, (ulong?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int32Field) {
+        _oneof_int32Field_codec.WriteTagAndValue(output, (int?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint32Field) {
+        _oneof_uint32Field_codec.WriteTagAndValue(output, (uint?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.BoolField) {
+        _oneof_boolField_codec.WriteTagAndValue(output, (bool?) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.StringField) {
+        _oneof_stringField_codec.WriteTagAndValue(output, (string) oneofField_);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.BytesField) {
+        _oneof_bytesField_codec.WriteTagAndValue(output, (pb::ByteString) oneofField_);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (oneofFieldCase_ == OneofFieldOneofCase.AnyField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(AnyField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.ApiField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ApiField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.DurationField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(DurationField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.EmptyField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(EmptyField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(FieldMaskField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.SourceContextField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContextField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.StructField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(StructField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.TimestampField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(TimestampField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.TypeField) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(TypeField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.DoubleField) {
+        size += _oneof_doubleField_codec.CalculateSizeWithTag(DoubleField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.FloatField) {
+        size += _oneof_floatField_codec.CalculateSizeWithTag(FloatField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int64Field) {
+        size += _oneof_int64Field_codec.CalculateSizeWithTag(Int64Field);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint64Field) {
+        size += _oneof_uint64Field_codec.CalculateSizeWithTag(Uint64Field);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Int32Field) {
+        size += _oneof_int32Field_codec.CalculateSizeWithTag(Int32Field);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.Uint32Field) {
+        size += _oneof_uint32Field_codec.CalculateSizeWithTag(Uint32Field);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.BoolField) {
+        size += _oneof_boolField_codec.CalculateSizeWithTag(BoolField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.StringField) {
+        size += _oneof_stringField_codec.CalculateSizeWithTag(StringField);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.BytesField) {
+        size += _oneof_bytesField_codec.CalculateSizeWithTag(BytesField);
+      }
+      return size;
+    }
+
+    public void MergeFrom(OneofWellKnownTypes other) {
+      if (other == null) {
+        return;
+      }
+      switch (other.OneofFieldCase) {
+        case OneofFieldOneofCase.AnyField:
+          AnyField = other.AnyField;
+          break;
+        case OneofFieldOneofCase.ApiField:
+          ApiField = other.ApiField;
+          break;
+        case OneofFieldOneofCase.DurationField:
+          DurationField = other.DurationField;
+          break;
+        case OneofFieldOneofCase.EmptyField:
+          EmptyField = other.EmptyField;
+          break;
+        case OneofFieldOneofCase.FieldMaskField:
+          FieldMaskField = other.FieldMaskField;
+          break;
+        case OneofFieldOneofCase.SourceContextField:
+          SourceContextField = other.SourceContextField;
+          break;
+        case OneofFieldOneofCase.StructField:
+          StructField = other.StructField;
+          break;
+        case OneofFieldOneofCase.TimestampField:
+          TimestampField = other.TimestampField;
+          break;
+        case OneofFieldOneofCase.TypeField:
+          TypeField = other.TypeField;
+          break;
+        case OneofFieldOneofCase.DoubleField:
+          DoubleField = other.DoubleField;
+          break;
+        case OneofFieldOneofCase.FloatField:
+          FloatField = other.FloatField;
+          break;
+        case OneofFieldOneofCase.Int64Field:
+          Int64Field = other.Int64Field;
+          break;
+        case OneofFieldOneofCase.Uint64Field:
+          Uint64Field = other.Uint64Field;
+          break;
+        case OneofFieldOneofCase.Int32Field:
+          Int32Field = other.Int32Field;
+          break;
+        case OneofFieldOneofCase.Uint32Field:
+          Uint32Field = other.Uint32Field;
+          break;
+        case OneofFieldOneofCase.BoolField:
+          BoolField = other.BoolField;
+          break;
+        case OneofFieldOneofCase.StringField:
+          StringField = other.StringField;
+          break;
+        case OneofFieldOneofCase.BytesField:
+          BytesField = other.BytesField;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            global::Google.Protobuf.WellKnownTypes.Any subBuilder = new global::Google.Protobuf.WellKnownTypes.Any();
+            if (oneofFieldCase_ == OneofFieldOneofCase.AnyField) {
+              subBuilder.MergeFrom(AnyField);
+            }
+            input.ReadMessage(subBuilder);
+            AnyField = subBuilder;
+            break;
+          }
+          case 18: {
+            global::Google.Protobuf.WellKnownTypes.Api subBuilder = new global::Google.Protobuf.WellKnownTypes.Api();
+            if (oneofFieldCase_ == OneofFieldOneofCase.ApiField) {
+              subBuilder.MergeFrom(ApiField);
+            }
+            input.ReadMessage(subBuilder);
+            ApiField = subBuilder;
+            break;
+          }
+          case 26: {
+            global::Google.Protobuf.WellKnownTypes.Duration subBuilder = new global::Google.Protobuf.WellKnownTypes.Duration();
+            if (oneofFieldCase_ == OneofFieldOneofCase.DurationField) {
+              subBuilder.MergeFrom(DurationField);
+            }
+            input.ReadMessage(subBuilder);
+            DurationField = subBuilder;
+            break;
+          }
+          case 34: {
+            global::Google.Protobuf.WellKnownTypes.Empty subBuilder = new global::Google.Protobuf.WellKnownTypes.Empty();
+            if (oneofFieldCase_ == OneofFieldOneofCase.EmptyField) {
+              subBuilder.MergeFrom(EmptyField);
+            }
+            input.ReadMessage(subBuilder);
+            EmptyField = subBuilder;
+            break;
+          }
+          case 42: {
+            global::Google.Protobuf.WellKnownTypes.FieldMask subBuilder = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+            if (oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField) {
+              subBuilder.MergeFrom(FieldMaskField);
+            }
+            input.ReadMessage(subBuilder);
+            FieldMaskField = subBuilder;
+            break;
+          }
+          case 50: {
+            global::Google.Protobuf.WellKnownTypes.SourceContext subBuilder = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            if (oneofFieldCase_ == OneofFieldOneofCase.SourceContextField) {
+              subBuilder.MergeFrom(SourceContextField);
+            }
+            input.ReadMessage(subBuilder);
+            SourceContextField = subBuilder;
+            break;
+          }
+          case 58: {
+            global::Google.Protobuf.WellKnownTypes.Struct subBuilder = new global::Google.Protobuf.WellKnownTypes.Struct();
+            if (oneofFieldCase_ == OneofFieldOneofCase.StructField) {
+              subBuilder.MergeFrom(StructField);
+            }
+            input.ReadMessage(subBuilder);
+            StructField = subBuilder;
+            break;
+          }
+          case 66: {
+            global::Google.Protobuf.WellKnownTypes.Timestamp subBuilder = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+            if (oneofFieldCase_ == OneofFieldOneofCase.TimestampField) {
+              subBuilder.MergeFrom(TimestampField);
+            }
+            input.ReadMessage(subBuilder);
+            TimestampField = subBuilder;
+            break;
+          }
+          case 74: {
+            global::Google.Protobuf.WellKnownTypes.Type subBuilder = new global::Google.Protobuf.WellKnownTypes.Type();
+            if (oneofFieldCase_ == OneofFieldOneofCase.TypeField) {
+              subBuilder.MergeFrom(TypeField);
+            }
+            input.ReadMessage(subBuilder);
+            TypeField = subBuilder;
+            break;
+          }
+          case 82: {
+            DoubleField = _oneof_doubleField_codec.Read(input);
+            break;
+          }
+          case 90: {
+            FloatField = _oneof_floatField_codec.Read(input);
+            break;
+          }
+          case 98: {
+            Int64Field = _oneof_int64Field_codec.Read(input);
+            break;
+          }
+          case 106: {
+            Uint64Field = _oneof_uint64Field_codec.Read(input);
+            break;
+          }
+          case 114: {
+            Int32Field = _oneof_int32Field_codec.Read(input);
+            break;
+          }
+          case 122: {
+            Uint32Field = _oneof_uint32Field_codec.Read(input);
+            break;
+          }
+          case 130: {
+            BoolField = _oneof_boolField_codec.Read(input);
+            break;
+          }
+          case 138: {
+            StringField = _oneof_stringField_codec.Read(input);
+            break;
+          }
+          case 146: {
+            BytesField = _oneof_bytesField_codec.Read(input);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A map field for each well-known type. We only
+  ///  need to worry about the value part of the map being the
+  ///  well-known types, as messages can't be map keys.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class MapWellKnownTypes : pb::IMessage<MapWellKnownTypes> {
+    private static readonly pb::MessageParser<MapWellKnownTypes> _parser = new pb::MessageParser<MapWellKnownTypes>(() => new MapWellKnownTypes());
+    public static pb::MessageParser<MapWellKnownTypes> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MapWellKnownTypes() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MapWellKnownTypes(MapWellKnownTypes other) : this() {
+      anyField_ = other.anyField_.Clone();
+      apiField_ = other.apiField_.Clone();
+      durationField_ = other.durationField_.Clone();
+      emptyField_ = other.emptyField_.Clone();
+      fieldMaskField_ = other.fieldMaskField_.Clone();
+      sourceContextField_ = other.sourceContextField_.Clone();
+      structField_ = other.structField_.Clone();
+      timestampField_ = other.timestampField_.Clone();
+      typeField_ = other.typeField_.Clone();
+      doubleField_ = other.doubleField_.Clone();
+      floatField_ = other.floatField_.Clone();
+      int64Field_ = other.int64Field_.Clone();
+      uint64Field_ = other.uint64Field_.Clone();
+      int32Field_ = other.int32Field_.Clone();
+      uint32Field_ = other.uint32Field_.Clone();
+      boolField_ = other.boolField_.Clone();
+      stringField_ = other.stringField_.Clone();
+      bytesField_ = other.bytesField_.Clone();
+    }
+
+    public MapWellKnownTypes Clone() {
+      return new MapWellKnownTypes(this);
+    }
+
+    /// <summary>Field number for the "any_field" field.</summary>
+    public const int AnyFieldFieldNumber = 1;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any>.Codec _map_anyField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Any.Parser), 10);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any> anyField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any> AnyField {
+      get { return anyField_; }
+    }
+
+    /// <summary>Field number for the "api_field" field.</summary>
+    public const int ApiFieldFieldNumber = 2;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api>.Codec _map_apiField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Api.Parser), 18);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api> apiField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api> ApiField {
+      get { return apiField_; }
+    }
+
+    /// <summary>Field number for the "duration_field" field.</summary>
+    public const int DurationFieldFieldNumber = 3;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration>.Codec _map_durationField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Duration.Parser), 26);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration> durationField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration> DurationField {
+      get { return durationField_; }
+    }
+
+    /// <summary>Field number for the "empty_field" field.</summary>
+    public const int EmptyFieldFieldNumber = 4;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty>.Codec _map_emptyField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Empty.Parser), 34);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty> emptyField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty> EmptyField {
+      get { return emptyField_; }
+    }
+
+    /// <summary>Field number for the "field_mask_field" field.</summary>
+    public const int FieldMaskFieldFieldNumber = 5;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask>.Codec _map_fieldMaskField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser), 42);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask> fieldMaskField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask> FieldMaskField {
+      get { return fieldMaskField_; }
+    }
+
+    /// <summary>Field number for the "source_context_field" field.</summary>
+    public const int SourceContextFieldFieldNumber = 6;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext>.Codec _map_sourceContextField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.SourceContext.Parser), 50);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext> sourceContextField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext> SourceContextField {
+      get { return sourceContextField_; }
+    }
+
+    /// <summary>Field number for the "struct_field" field.</summary>
+    public const int StructFieldFieldNumber = 7;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct>.Codec _map_structField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Struct.Parser), 58);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct> structField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct> StructField {
+      get { return structField_; }
+    }
+
+    /// <summary>Field number for the "timestamp_field" field.</summary>
+    public const int TimestampFieldFieldNumber = 8;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp>.Codec _map_timestampField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser), 66);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp> timestampField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp> TimestampField {
+      get { return timestampField_; }
+    }
+
+    /// <summary>Field number for the "type_field" field.</summary>
+    public const int TypeFieldFieldNumber = 9;
+    private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type>.Codec _map_typeField_codec
+        = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Type.Parser), 74);
+    private readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type> typeField_ = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type>();
+    public pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type> TypeField {
+      get { return typeField_; }
+    }
+
+    /// <summary>Field number for the "double_field" field.</summary>
+    public const int DoubleFieldFieldNumber = 10;
+    private static readonly pbc::MapField<int, double?>.Codec _map_doubleField_codec
+        = new pbc::MapField<int, double?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<double>(18), 82);
+    private readonly pbc::MapField<int, double?> doubleField_ = new pbc::MapField<int, double?>();
+    public pbc::MapField<int, double?> DoubleField {
+      get { return doubleField_; }
+    }
+
+    /// <summary>Field number for the "float_field" field.</summary>
+    public const int FloatFieldFieldNumber = 11;
+    private static readonly pbc::MapField<int, float?>.Codec _map_floatField_codec
+        = new pbc::MapField<int, float?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<float>(18), 90);
+    private readonly pbc::MapField<int, float?> floatField_ = new pbc::MapField<int, float?>();
+    public pbc::MapField<int, float?> FloatField {
+      get { return floatField_; }
+    }
+
+    /// <summary>Field number for the "int64_field" field.</summary>
+    public const int Int64FieldFieldNumber = 12;
+    private static readonly pbc::MapField<int, long?>.Codec _map_int64Field_codec
+        = new pbc::MapField<int, long?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<long>(18), 98);
+    private readonly pbc::MapField<int, long?> int64Field_ = new pbc::MapField<int, long?>();
+    public pbc::MapField<int, long?> Int64Field {
+      get { return int64Field_; }
+    }
+
+    /// <summary>Field number for the "uint64_field" field.</summary>
+    public const int Uint64FieldFieldNumber = 13;
+    private static readonly pbc::MapField<int, ulong?>.Codec _map_uint64Field_codec
+        = new pbc::MapField<int, ulong?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<ulong>(18), 106);
+    private readonly pbc::MapField<int, ulong?> uint64Field_ = new pbc::MapField<int, ulong?>();
+    public pbc::MapField<int, ulong?> Uint64Field {
+      get { return uint64Field_; }
+    }
+
+    /// <summary>Field number for the "int32_field" field.</summary>
+    public const int Int32FieldFieldNumber = 14;
+    private static readonly pbc::MapField<int, int?>.Codec _map_int32Field_codec
+        = new pbc::MapField<int, int?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<int>(18), 114);
+    private readonly pbc::MapField<int, int?> int32Field_ = new pbc::MapField<int, int?>();
+    public pbc::MapField<int, int?> Int32Field {
+      get { return int32Field_; }
+    }
+
+    /// <summary>Field number for the "uint32_field" field.</summary>
+    public const int Uint32FieldFieldNumber = 15;
+    private static readonly pbc::MapField<int, uint?>.Codec _map_uint32Field_codec
+        = new pbc::MapField<int, uint?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<uint>(18), 122);
+    private readonly pbc::MapField<int, uint?> uint32Field_ = new pbc::MapField<int, uint?>();
+    public pbc::MapField<int, uint?> Uint32Field {
+      get { return uint32Field_; }
+    }
+
+    /// <summary>Field number for the "bool_field" field.</summary>
+    public const int BoolFieldFieldNumber = 16;
+    private static readonly pbc::MapField<int, bool?>.Codec _map_boolField_codec
+        = new pbc::MapField<int, bool?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<bool>(18), 130);
+    private readonly pbc::MapField<int, bool?> boolField_ = new pbc::MapField<int, bool?>();
+    public pbc::MapField<int, bool?> BoolField {
+      get { return boolField_; }
+    }
+
+    /// <summary>Field number for the "string_field" field.</summary>
+    public const int StringFieldFieldNumber = 17;
+    private static readonly pbc::MapField<int, string>.Codec _map_stringField_codec
+        = new pbc::MapField<int, string>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<string>(18), 138);
+    private readonly pbc::MapField<int, string> stringField_ = new pbc::MapField<int, string>();
+    public pbc::MapField<int, string> StringField {
+      get { return stringField_; }
+    }
+
+    /// <summary>Field number for the "bytes_field" field.</summary>
+    public const int BytesFieldFieldNumber = 18;
+    private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_bytesField_codec
+        = new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<pb::ByteString>(18), 146);
+    private readonly pbc::MapField<int, pb::ByteString> bytesField_ = new pbc::MapField<int, pb::ByteString>();
+    public pbc::MapField<int, pb::ByteString> BytesField {
+      get { return bytesField_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MapWellKnownTypes);
+    }
+
+    public bool Equals(MapWellKnownTypes other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!AnyField.Equals(other.AnyField)) return false;
+      if (!ApiField.Equals(other.ApiField)) return false;
+      if (!DurationField.Equals(other.DurationField)) return false;
+      if (!EmptyField.Equals(other.EmptyField)) return false;
+      if (!FieldMaskField.Equals(other.FieldMaskField)) return false;
+      if (!SourceContextField.Equals(other.SourceContextField)) return false;
+      if (!StructField.Equals(other.StructField)) return false;
+      if (!TimestampField.Equals(other.TimestampField)) return false;
+      if (!TypeField.Equals(other.TypeField)) return false;
+      if (!DoubleField.Equals(other.DoubleField)) return false;
+      if (!FloatField.Equals(other.FloatField)) return false;
+      if (!Int64Field.Equals(other.Int64Field)) return false;
+      if (!Uint64Field.Equals(other.Uint64Field)) return false;
+      if (!Int32Field.Equals(other.Int32Field)) return false;
+      if (!Uint32Field.Equals(other.Uint32Field)) return false;
+      if (!BoolField.Equals(other.BoolField)) return false;
+      if (!StringField.Equals(other.StringField)) return false;
+      if (!BytesField.Equals(other.BytesField)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= AnyField.GetHashCode();
+      hash ^= ApiField.GetHashCode();
+      hash ^= DurationField.GetHashCode();
+      hash ^= EmptyField.GetHashCode();
+      hash ^= FieldMaskField.GetHashCode();
+      hash ^= SourceContextField.GetHashCode();
+      hash ^= StructField.GetHashCode();
+      hash ^= TimestampField.GetHashCode();
+      hash ^= TypeField.GetHashCode();
+      hash ^= DoubleField.GetHashCode();
+      hash ^= FloatField.GetHashCode();
+      hash ^= Int64Field.GetHashCode();
+      hash ^= Uint64Field.GetHashCode();
+      hash ^= Int32Field.GetHashCode();
+      hash ^= Uint32Field.GetHashCode();
+      hash ^= BoolField.GetHashCode();
+      hash ^= StringField.GetHashCode();
+      hash ^= BytesField.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      anyField_.WriteTo(output, _map_anyField_codec);
+      apiField_.WriteTo(output, _map_apiField_codec);
+      durationField_.WriteTo(output, _map_durationField_codec);
+      emptyField_.WriteTo(output, _map_emptyField_codec);
+      fieldMaskField_.WriteTo(output, _map_fieldMaskField_codec);
+      sourceContextField_.WriteTo(output, _map_sourceContextField_codec);
+      structField_.WriteTo(output, _map_structField_codec);
+      timestampField_.WriteTo(output, _map_timestampField_codec);
+      typeField_.WriteTo(output, _map_typeField_codec);
+      doubleField_.WriteTo(output, _map_doubleField_codec);
+      floatField_.WriteTo(output, _map_floatField_codec);
+      int64Field_.WriteTo(output, _map_int64Field_codec);
+      uint64Field_.WriteTo(output, _map_uint64Field_codec);
+      int32Field_.WriteTo(output, _map_int32Field_codec);
+      uint32Field_.WriteTo(output, _map_uint32Field_codec);
+      boolField_.WriteTo(output, _map_boolField_codec);
+      stringField_.WriteTo(output, _map_stringField_codec);
+      bytesField_.WriteTo(output, _map_bytesField_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += anyField_.CalculateSize(_map_anyField_codec);
+      size += apiField_.CalculateSize(_map_apiField_codec);
+      size += durationField_.CalculateSize(_map_durationField_codec);
+      size += emptyField_.CalculateSize(_map_emptyField_codec);
+      size += fieldMaskField_.CalculateSize(_map_fieldMaskField_codec);
+      size += sourceContextField_.CalculateSize(_map_sourceContextField_codec);
+      size += structField_.CalculateSize(_map_structField_codec);
+      size += timestampField_.CalculateSize(_map_timestampField_codec);
+      size += typeField_.CalculateSize(_map_typeField_codec);
+      size += doubleField_.CalculateSize(_map_doubleField_codec);
+      size += floatField_.CalculateSize(_map_floatField_codec);
+      size += int64Field_.CalculateSize(_map_int64Field_codec);
+      size += uint64Field_.CalculateSize(_map_uint64Field_codec);
+      size += int32Field_.CalculateSize(_map_int32Field_codec);
+      size += uint32Field_.CalculateSize(_map_uint32Field_codec);
+      size += boolField_.CalculateSize(_map_boolField_codec);
+      size += stringField_.CalculateSize(_map_stringField_codec);
+      size += bytesField_.CalculateSize(_map_bytesField_codec);
+      return size;
+    }
+
+    public void MergeFrom(MapWellKnownTypes other) {
+      if (other == null) {
+        return;
+      }
+      anyField_.Add(other.anyField_);
+      apiField_.Add(other.apiField_);
+      durationField_.Add(other.durationField_);
+      emptyField_.Add(other.emptyField_);
+      fieldMaskField_.Add(other.fieldMaskField_);
+      sourceContextField_.Add(other.sourceContextField_);
+      structField_.Add(other.structField_);
+      timestampField_.Add(other.timestampField_);
+      typeField_.Add(other.typeField_);
+      doubleField_.Add(other.doubleField_);
+      floatField_.Add(other.floatField_);
+      int64Field_.Add(other.int64Field_);
+      uint64Field_.Add(other.uint64Field_);
+      int32Field_.Add(other.int32Field_);
+      uint32Field_.Add(other.uint32Field_);
+      boolField_.Add(other.boolField_);
+      stringField_.Add(other.stringField_);
+      bytesField_.Add(other.bytesField_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            anyField_.AddEntriesFrom(input, _map_anyField_codec);
+            break;
+          }
+          case 18: {
+            apiField_.AddEntriesFrom(input, _map_apiField_codec);
+            break;
+          }
+          case 26: {
+            durationField_.AddEntriesFrom(input, _map_durationField_codec);
+            break;
+          }
+          case 34: {
+            emptyField_.AddEntriesFrom(input, _map_emptyField_codec);
+            break;
+          }
+          case 42: {
+            fieldMaskField_.AddEntriesFrom(input, _map_fieldMaskField_codec);
+            break;
+          }
+          case 50: {
+            sourceContextField_.AddEntriesFrom(input, _map_sourceContextField_codec);
+            break;
+          }
+          case 58: {
+            structField_.AddEntriesFrom(input, _map_structField_codec);
+            break;
+          }
+          case 66: {
+            timestampField_.AddEntriesFrom(input, _map_timestampField_codec);
+            break;
+          }
+          case 74: {
+            typeField_.AddEntriesFrom(input, _map_typeField_codec);
+            break;
+          }
+          case 82: {
+            doubleField_.AddEntriesFrom(input, _map_doubleField_codec);
+            break;
+          }
+          case 90: {
+            floatField_.AddEntriesFrom(input, _map_floatField_codec);
+            break;
+          }
+          case 98: {
+            int64Field_.AddEntriesFrom(input, _map_int64Field_codec);
+            break;
+          }
+          case 106: {
+            uint64Field_.AddEntriesFrom(input, _map_uint64Field_codec);
+            break;
+          }
+          case 114: {
+            int32Field_.AddEntriesFrom(input, _map_int32Field_codec);
+            break;
+          }
+          case 122: {
+            uint32Field_.AddEntriesFrom(input, _map_uint32Field_codec);
+            break;
+          }
+          case 130: {
+            boolField_.AddEntriesFrom(input, _map_boolField_codec);
+            break;
+          }
+          case 138: {
+            stringField_.AddEntriesFrom(input, _map_stringField_codec);
+            break;
+          }
+          case 146: {
+            bytesField_.AddEntriesFrom(input, _map_bytesField_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
new file mode 100644
index 0000000..f21be7d
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
@@ -0,0 +1,116 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class AnyTest
+    {
+        [Test]
+        public void Pack()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            Assert.AreEqual("type.googleapis.com/protobuf_unittest.TestAllTypes", any.TypeUrl);
+            Assert.AreEqual(message.CalculateSize(), any.Value.Length);
+        }
+
+        [Test]
+        public void Pack_WithCustomPrefix()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message, "foo.bar/baz");
+            Assert.AreEqual("foo.bar/baz/protobuf_unittest.TestAllTypes", any.TypeUrl);
+            Assert.AreEqual(message.CalculateSize(), any.Value.Length);
+        }
+
+        [Test]
+        public void Pack_WithCustomPrefixTrailingSlash()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message, "foo.bar/baz/");
+            Assert.AreEqual("foo.bar/baz/protobuf_unittest.TestAllTypes", any.TypeUrl);
+            Assert.AreEqual(message.CalculateSize(), any.Value.Length);
+        }
+
+        [Test]
+        public void Unpack_WrongType()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            Assert.Throws<InvalidProtocolBufferException>(() => any.Unpack<TestOneof>());
+        }
+
+        [Test]
+        public void Unpack_Success()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            var unpacked = any.Unpack<TestAllTypes>();
+            Assert.AreEqual(message, unpacked);
+        }
+
+        [Test]
+        public void Unpack_CustomPrefix_Success()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message, "foo.bar/baz");
+            var unpacked = any.Unpack<TestAllTypes>();
+            Assert.AreEqual(message, unpacked);
+        }
+
+        [Test]
+        public void ToString_WithValues()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            var text = any.ToString();
+            Assert.That(text, Is.StringContaining("\"@value\": \"" + message.ToByteString().ToBase64() + "\""));
+        }
+
+        [Test]
+        public void ToString_Empty()
+        {
+            var any = new Any();
+            Assert.AreEqual("{ \"@type\": \"\", \"@value\": \"\" }", any.ToString());
+        }
+
+        [Test]
+        public void ToString_MessageContainingAny()
+        {
+            var message = new TestWellKnownTypes { AnyField = new Any() };
+            Assert.AreEqual("{ \"anyField\": { \"@type\": \"\", \"@value\": \"\" } }", message.ToString());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
new file mode 100644
index 0000000..141faf8
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
@@ -0,0 +1,132 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class DurationTest
+    {
+        [Test]
+        public void ToTimeSpan()
+        {
+            Assert.AreEqual(TimeSpan.FromSeconds(1), new Duration { Seconds = 1 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromSeconds(-1), new Duration { Seconds = -1 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromMilliseconds(1), new Duration { Nanos = 1000000 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromMilliseconds(-1), new Duration { Nanos = -1000000 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromTicks(1), new Duration { Nanos = 100 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromTicks(-1), new Duration { Nanos = -100 }.ToTimeSpan());
+
+            // Rounding is towards 0
+            Assert.AreEqual(TimeSpan.FromTicks(2), new Duration { Nanos = 250 }.ToTimeSpan());
+            Assert.AreEqual(TimeSpan.FromTicks(-2), new Duration { Nanos = -250 }.ToTimeSpan());
+        }
+
+        [Test]
+        public void Addition()
+        {
+            Assert.AreEqual(new Duration { Seconds = 2, Nanos = 100000000 },
+                new Duration { Seconds = 1, Nanos = 600000000 } + new Duration { Nanos = 500000000 });
+            Assert.AreEqual(new Duration { Seconds = -2, Nanos = -100000000 },
+                new Duration { Seconds = -1, Nanos = -600000000 } + new Duration { Nanos = -500000000 });
+            Assert.AreEqual(new Duration { Seconds = 1, Nanos = 100000000 },
+                new Duration { Seconds = 1, Nanos = 600000000 } + new Duration { Nanos = -500000000 });
+
+            // Non-normalized durations, or non-normalized intermediate results
+            Assert.AreEqual(new Duration { Seconds = 1 },
+                new Duration { Seconds = 1, Nanos = -500000000 } + new Duration { Nanos = 500000000 });
+
+            Assert.AreEqual(new Duration { Nanos = -900000000 },
+                new Duration { Seconds = -1, Nanos = -100000000 } + new Duration { Nanos = 200000000 });
+            Assert.AreEqual(new Duration { Nanos = 900000000 },
+                new Duration { Seconds = 1, Nanos = 100000000 } + new Duration { Nanos = -200000000 });
+        }
+
+        [Test]
+        public void Subtraction()
+        {
+            Assert.AreEqual(new Duration { Seconds = 1, Nanos = 100000000 },
+                new Duration { Seconds = 1, Nanos = 600000000 } - new Duration { Nanos = 500000000 });
+            Assert.AreEqual(new Duration { Seconds = -1, Nanos = -100000000 },
+                new Duration { Seconds = -1, Nanos = -600000000 } - new Duration { Nanos = -500000000 });
+            Assert.AreEqual(new Duration { Seconds = 2, Nanos = 100000000 },
+                new Duration { Seconds = 1, Nanos = 600000000 } - new Duration { Nanos = -500000000 });
+
+            // Non-normalized durations
+            Assert.AreEqual(new Duration(),
+                new Duration { Seconds = 1, Nanos = -500000000 } - new Duration { Nanos = 500000000 });
+            Assert.AreEqual(new Duration { Seconds = 1 },
+                new Duration { Nanos = 2000000000 } - new Duration { Nanos = 1000000000 });
+        }
+
+        [Test]
+        public void FromTimeSpan()
+        {
+            Assert.AreEqual(new Duration { Seconds = 1 }, Duration.FromTimeSpan(TimeSpan.FromSeconds(1)));
+            Assert.AreEqual(new Duration { Nanos = Duration.NanosecondsPerTick }, Duration.FromTimeSpan(TimeSpan.FromTicks(1)));
+        }
+
+        [Test]
+        [TestCase(0, Duration.MaxNanoseconds + 1)]
+        [TestCase(0, Duration.MinNanoseconds - 1)]
+        [TestCase(Duration.MinSeconds - 1, 0)]
+        [TestCase(Duration.MaxSeconds + 1, 0)]
+        [TestCase(1, -1)]
+        [TestCase(-1, 1)]
+        public void ToTimeSpan_Invalid(long seconds, int nanoseconds)
+        {
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => duration.ToTimeSpan());
+        }
+
+        [Test]
+        [TestCase(0, Duration.MaxNanoseconds)]
+        [TestCase(0, Duration.MinNanoseconds)]
+        [TestCase(Duration.MinSeconds, Duration.MinNanoseconds)]
+        [TestCase(Duration.MaxSeconds, Duration.MaxNanoseconds)]
+        public void ToTimeSpan_Valid(long seconds, int nanoseconds)
+        {
+            // Only testing that these values don't throw, unlike their similar tests in ToTimeSpan_Invalid
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            duration.ToTimeSpan();
+        }
+
+        [Test]
+        public void ToString_NonNormalized()
+        {
+            // Just a single example should be sufficient...
+            var duration = new Duration { Seconds = 1, Nanos = -1 };
+            Assert.AreEqual("{ \"@warning\": \"Invalid Duration\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
new file mode 100644
index 0000000..89bc827
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+
+using NUnit.Framework;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class FieldMaskTest
+    {
+        [Test]
+        [TestCase("foo__bar")]
+        [TestCase("foo_3_ar")]
+        [TestCase("fooBar")]
+        public void ToString_Invalid(string input)
+        {
+            var mask = new FieldMask { Paths = { input } };
+            var text = mask.ToString();
+            // More specific test below
+            Assert.That(text, Is.StringContaining("@warning"));
+            Assert.That(text, Is.StringContaining(input));
+        }
+
+        [Test]
+        public void ToString_Invalid_Precise()
+        {
+            var mask = new FieldMask { Paths = { "x", "foo__bar", @"x\y" } };
+            Assert.AreEqual(
+                "{ \"@warning\": \"Invalid FieldMask\", \"paths\": [ \"x\", \"foo__bar\", \"x\\\\y\" ] }",
+                mask.ToString());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs
new file mode 100644
index 0000000..9ecd24c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs
@@ -0,0 +1,115 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using NUnit.Framework;
+using System;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class TimestampTest
+    {
+        [Test]
+        public void FromAndToDateTime()
+        {
+            DateTime utcMin = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
+            DateTime utcMax = DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc);
+            AssertRoundtrip(new Timestamp { Seconds = -62135596800 }, utcMin);
+            AssertRoundtrip(new Timestamp { Seconds = 253402300799, Nanos = 999999900 }, utcMax);
+            AssertRoundtrip(new Timestamp(), new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
+            AssertRoundtrip(new Timestamp { Nanos = 1000000}, new DateTime(1970, 1, 1, 0, 0, 0, 1, DateTimeKind.Utc));
+            AssertRoundtrip(new Timestamp { Seconds = -1, Nanos = 999000000 }, new DateTime(1969, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc));
+            AssertRoundtrip(new Timestamp { Seconds = 3600 }, new DateTime(1970, 1, 1, 1, 0, 0, DateTimeKind.Utc));
+            AssertRoundtrip(new Timestamp { Seconds = -3600 }, new DateTime(1969, 12, 31, 23, 0, 0, DateTimeKind.Utc));
+        }
+
+        [Test]
+        public void ToDateTimeTruncation()
+        {
+            var t1 = new Timestamp { Seconds = 1, Nanos = 1000000 + Duration.NanosecondsPerTick - 1 };
+            Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 1, DateTimeKind.Utc).AddMilliseconds(1), t1.ToDateTime());
+
+            var t2 = new Timestamp { Seconds = -1, Nanos = 1000000 + Duration.NanosecondsPerTick - 1 };
+            Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 59).AddMilliseconds(1), t2.ToDateTime());
+        }
+
+        [Test]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, Timestamp.MaxNanos)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)]
+        [TestCase(0, -1)]
+        [TestCase(0, Timestamp.MaxNanos + 1)]
+        public void ToDateTime_OutOfRange(long seconds, int nanoseconds)
+        {
+            var value = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => value.ToDateTime());
+        }
+
+        // 1ns larger or smaller than the above values
+        [Test]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue, 0)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue, Timestamp.MaxNanos)]
+        [TestCase(0, 0)]
+        [TestCase(0, Timestamp.MaxNanos)]
+        public void ToDateTime_ValidBoundaries(long seconds, int nanoseconds)
+        {
+            var value = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            value.ToDateTime();
+        }
+
+        private static void AssertRoundtrip(Timestamp timestamp, DateTime dateTime)
+        {
+            Assert.AreEqual(timestamp, Timestamp.FromDateTime(dateTime));
+            Assert.AreEqual(dateTime, timestamp.ToDateTime());
+            Assert.AreEqual(DateTimeKind.Utc, timestamp.ToDateTime().Kind);
+        }
+
+        [Test]
+        public void Arithmetic()
+        {
+            Timestamp t1 = new Timestamp { Seconds = 10000, Nanos = 5000 };
+            Timestamp t2 = new Timestamp { Seconds = 8000, Nanos = 10000 };
+            Duration difference = new Duration { Seconds = 1999, Nanos = Duration.NanosecondsPerSecond - 5000 };
+            Assert.AreEqual(difference, t1 - t2);
+            Assert.AreEqual(-difference, t2 - t1);
+            
+            Assert.AreEqual(t1, t2 + difference);
+            Assert.AreEqual(t2, t1 - difference);
+        }
+
+        [Test]
+        public void ToString_NonNormalized()
+        {
+            // Just a single example should be sufficient...
+            var duration = new Timestamp { Seconds = 1, Nanos = -1 };
+            Assert.AreEqual("{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
new file mode 100644
index 0000000..5b7185d
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
@@ -0,0 +1,421 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using Google.Protobuf.TestProtos;
+using NUnit.Framework;
+using System.Collections;
+using System.IO;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class WrappersTest
+    {
+        [Test]
+        public void NullIsDefault()
+        {
+            var message = new TestWellKnownTypes();
+            Assert.IsNull(message.StringField);
+            Assert.IsNull(message.BytesField);
+            Assert.IsNull(message.BoolField);
+            Assert.IsNull(message.FloatField);
+            Assert.IsNull(message.DoubleField);
+            Assert.IsNull(message.Int32Field);
+            Assert.IsNull(message.Int64Field);
+            Assert.IsNull(message.Uint32Field);
+            Assert.IsNull(message.Uint64Field);
+        }
+
+        [Test]
+        public void NonDefaultSingleValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "x",
+                BytesField = ByteString.CopyFrom(1, 2, 3),
+                BoolField = true,
+                FloatField = 12.5f,
+                DoubleField = 12.25d,
+                Int32Field = 1,
+                Int64Field = 2,
+                Uint32Field = 3,
+                Uint64Field = 4
+            };
+
+            var bytes = message.ToByteArray();
+            var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
+
+            Assert.AreEqual("x", parsed.StringField);
+            Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), parsed.BytesField);
+            Assert.AreEqual(true, parsed.BoolField);
+            Assert.AreEqual(12.5f, parsed.FloatField);
+            Assert.AreEqual(12.25d, parsed.DoubleField);
+            Assert.AreEqual(1, parsed.Int32Field);
+            Assert.AreEqual(2L, parsed.Int64Field);
+            Assert.AreEqual(3U, parsed.Uint32Field);
+            Assert.AreEqual(4UL, parsed.Uint64Field);
+        }
+
+        [Test]
+        public void NonNullDefaultIsPreservedThroughSerialization()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "",
+                BytesField = ByteString.Empty,
+                BoolField = false,
+                FloatField = 0f,
+                DoubleField = 0d,
+                Int32Field = 0,
+                Int64Field = 0,
+                Uint32Field = 0,
+                Uint64Field = 0
+            };
+
+            var bytes = message.ToByteArray();
+            var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
+
+            Assert.AreEqual("", parsed.StringField);
+            Assert.AreEqual(ByteString.Empty, parsed.BytesField);
+            Assert.AreEqual(false, parsed.BoolField);
+            Assert.AreEqual(0f, parsed.FloatField);
+            Assert.AreEqual(0d, parsed.DoubleField);
+            Assert.AreEqual(0, parsed.Int32Field);
+            Assert.AreEqual(0L, parsed.Int64Field);
+            Assert.AreEqual(0U, parsed.Uint32Field);
+            Assert.AreEqual(0UL, parsed.Uint64Field);
+        }
+
+        [Test]
+        public void RepeatedWrappersProhibitNullItems()
+        {
+            var message = new RepeatedWellKnownTypes();
+            Assert.Throws<ArgumentNullException>(() => message.BoolField.Add((bool?) null));
+            Assert.Throws<ArgumentNullException>(() => message.Int32Field.Add((int?) null));
+            Assert.Throws<ArgumentNullException>(() => message.StringField.Add((string) null));
+            Assert.Throws<ArgumentNullException>(() => message.BytesField.Add((ByteString) null));
+        }
+
+        [Test]
+        public void RepeatedWrappersSerializeDeserialize()
+        {
+            var message = new RepeatedWellKnownTypes
+            {
+                BoolField = { true, false },
+                BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
+                DoubleField = { 12.5, -1.5, 0d },
+                FloatField = { 123.25f, -20f, 0f },
+                Int32Field = { int.MaxValue, int.MinValue, 0 },
+                Int64Field = { long.MaxValue, long.MinValue, 0L },                
+                StringField = { "First", "Second", "" },
+                Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
+                Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
+            };
+            var bytes = message.ToByteArray();
+            var parsed = RepeatedWellKnownTypes.Parser.ParseFrom(bytes);
+
+            Assert.AreEqual(message, parsed);
+            // Just to test a single value for sanity...
+            Assert.AreEqual("Second", message.StringField[1]);
+        }
+
+        [Test]
+        public void RepeatedWrappersBinaryFormat()
+        {
+            // At one point we accidentally used a packed format for repeated wrappers, which is wrong (and weird).
+            // This test is just to prove that we use the right format.
+
+            var rawOutput = new MemoryStream();
+            var output = new CodedOutputStream(rawOutput);
+            // Write a value of 5
+            output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            output.WriteLength(2);
+            output.WriteTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint);
+            output.WriteInt32(5);
+            // Write a value of 0 (empty message)
+            output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            output.WriteLength(0);
+            output.Flush();
+            var expectedBytes = rawOutput.ToArray();
+
+            var message = new RepeatedWellKnownTypes { Int32Field = { 5, 0 } };
+            var actualBytes = message.ToByteArray();
+            Assert.AreEqual(expectedBytes, actualBytes);
+        }
+
+        [Test]
+        public void MapWrappersSerializeDeserialize()
+        {
+            // Note: no null values here, as they are prohibited in map fields
+            // (despite being representable).
+            var message = new MapWellKnownTypes
+            {
+                BoolField = { { 10, false }, { 20, true } },
+                BytesField = {
+                    { -1, ByteString.CopyFrom(1, 2, 3) },
+                    { 10, ByteString.CopyFrom(4, 5, 6) },
+                    { 1000, ByteString.Empty },
+                },
+                DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } },
+                FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } },
+                Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } },
+                Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } },
+                StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" } },
+                Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } },
+                Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } },
+            };
+
+            var bytes = message.ToByteArray();
+            var parsed = MapWellKnownTypes.Parser.ParseFrom(bytes);
+
+            Assert.AreEqual(message, parsed);
+            // Just to test a single value for sanity...
+            Assert.AreEqual("Second", message.StringField[12]);
+        }
+
+        [Test]
+        public void Reflection_SingleValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "x",
+                BytesField = ByteString.CopyFrom(1, 2, 3),
+                BoolField = true,
+                FloatField = 12.5f,
+                DoubleField = 12.25d,
+                Int32Field = 1,
+                Int64Field = 2,
+                Uint32Field = 3,
+                Uint64Field = 4
+            };
+            var fields = TestWellKnownTypes.Descriptor.Fields;
+
+            Assert.AreEqual("x", fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), fields[TestWellKnownTypes.BytesFieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(true, fields[TestWellKnownTypes.BoolFieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(12.5f, fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(12.25d, fields[TestWellKnownTypes.DoubleFieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(1, fields[TestWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(2L, fields[TestWellKnownTypes.Int64FieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(3U, fields[TestWellKnownTypes.Uint32FieldFieldNumber].Accessor.GetValue(message));
+            Assert.AreEqual(4UL, fields[TestWellKnownTypes.Uint64FieldFieldNumber].Accessor.GetValue(message));
+
+            // And a couple of null fields...
+            message.StringField = null;
+            message.FloatField = null;
+            Assert.IsNull(fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message));
+            Assert.IsNull(fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message));
+        }
+
+        [Test]
+        public void Reflection_RepeatedFields()
+        {
+            // Just a single example... note that we can't have a null value here
+            var message = new RepeatedWellKnownTypes { Int32Field = { 1, 2 } };
+            var fields = RepeatedWellKnownTypes.Descriptor.Fields;
+            var list = (IList) fields[RepeatedWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
+            CollectionAssert.AreEqual(new[] { 1, 2 }, list);
+        }
+
+        [Test]
+        public void Reflection_MapFields()
+        {
+            // Just a single example... note that we can't have a null value here despite the value type being int?
+            var message = new MapWellKnownTypes { Int32Field = { { 1, 2 } } };
+            var fields = MapWellKnownTypes.Descriptor.Fields;
+            var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
+            Assert.AreEqual(2, dictionary[1]);
+        }
+
+        [Test]
+        public void Oneof()
+        {
+            var message = new OneofWellKnownTypes { EmptyField = new Empty() };
+            // Start off with a non-wrapper
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.EmptyField, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+
+            message.StringField = "foo";
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+
+            message.StringField = "foo";
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+
+            message.DoubleField = 0.0f;
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+
+            message.DoubleField = 1.0f;
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+
+            message.ClearOneofField();
+            Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
+            AssertOneofRoundTrip(message);
+        }
+
+        private void AssertOneofRoundTrip(OneofWellKnownTypes message)
+        {
+            // Normal roundtrip, but explicitly checking the case...
+            var bytes = message.ToByteArray();
+            var parsed = OneofWellKnownTypes.Parser.ParseFrom(bytes);
+            Assert.AreEqual(message, parsed);
+            Assert.AreEqual(message.OneofFieldCase, parsed.OneofFieldCase);
+        }
+
+        [Test]
+        [TestCase("x", "y", "y")]
+        [TestCase("x", "", "x")]
+        [TestCase("x", null, "x")]
+        [TestCase("", "y", "y")]
+        [TestCase("", "", "")]
+        [TestCase("", null, "")]
+        [TestCase(null, "y", "y")]
+        [TestCase(null, "", "")]
+        [TestCase(null, null, null)]
+        public void Merging(string original, string merged, string expected)
+        {
+            var originalMessage = new TestWellKnownTypes { StringField = original };
+            var mergingMessage = new TestWellKnownTypes { StringField = merged };
+            originalMessage.MergeFrom(mergingMessage);
+            Assert.AreEqual(expected, originalMessage.StringField);
+
+            // Try it using MergeFrom(CodedInputStream) too...
+            originalMessage = new TestWellKnownTypes { StringField = original };
+            originalMessage.MergeFrom(mergingMessage.ToByteArray());
+            Assert.AreEqual(expected, originalMessage.StringField);
+        }
+
+        // Merging is odd with wrapper types, due to the way that default values aren't emitted in
+        // the binary stream. In fact we cheat a little bit - a message with an explicitly present default
+        // value will have that default value ignored. See issue 615. Fixing this would require significant upheaval to
+        // the FieldCodec side of things.
+        [Test]
+        public void MergingStreamExplicitValue()
+        {
+            var message = new TestWellKnownTypes { Int32Field = 5 };
+
+            // Create a byte array which has the data of an Int32Value explicitly containing a value of 0.
+            // This wouldn't normally happen.
+            byte[] bytes;
+            var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
+            using (var stream = new MemoryStream())
+            {
+                var coded = new CodedOutputStream(stream);
+                coded.WriteTag(wrapperTag);
+                coded.WriteLength(2); // valueTag + a value 0, each one byte
+                coded.WriteTag(valueTag);
+                coded.WriteInt32(0);
+                coded.Flush();
+                bytes = stream.ToArray();
+            }
+
+            message.MergeFrom(bytes);
+            // A normal implementation would have 0 now, as the explicit default would have been overwritten the 5.
+            // With the FieldCodec for Nullable<int>, we can't tell the difference between an implicit 0 and an explicit 0.
+            Assert.AreEqual(5, message.Int32Field);
+        }
+
+        [Test]
+        public void MergingStreamNoValue()
+        {
+            var message = new TestWellKnownTypes { Int32Field = 5 };
+
+            // Create a byte array which an Int32 field, but with no value.
+            var bytes = new TestWellKnownTypes { Int32Field = 0 }.ToByteArray();
+            Assert.AreEqual(2, bytes.Length); // The tag for Int32Field is a single byte, then a byte indicating a 0-length message.
+            message.MergeFrom(bytes);
+
+            // The "implicit" 0 did *not* overwrite the value.
+            // (This is the correct behaviour.)
+            Assert.AreEqual(5, message.Int32Field);
+        }
+
+        // All permutations of origin/merging value being null, zero (default) or non-default.
+        // As this is the in-memory version, we don't need to worry about the difference between implicit and explicit 0.
+        [Test]
+        [TestCase(null, null, null)]
+        [TestCase(null, 0, 0)]
+        [TestCase(null, 5, 5)]
+        [TestCase(0, null, 0)]
+        [TestCase(0, 0, 0)]
+        [TestCase(0, 5, 5)]
+        [TestCase(5, null, 5)]
+        [TestCase(5, 0, 5)]
+        [TestCase(5, 10, 10)]
+        public void MergingMessageWithZero(int? originValue, int? mergingValue, int? expectedResult)
+        {
+            // This differs from the MergingStreamCornerCase because when we merge message *objects*,
+            // we ignore default values from the "source".
+            var message1 = new TestWellKnownTypes { Int32Field = originValue };
+            var message2 = new TestWellKnownTypes { Int32Field = mergingValue };
+            message1.MergeFrom(message2);
+            Assert.AreEqual(expectedResult, message1.Int32Field);
+        }
+
+        [Test]
+        public void UnknownFieldInWrapper()
+        {
+            var stream = new MemoryStream();
+            var output = new CodedOutputStream(stream);
+            var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint);
+            var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
+
+            output.WriteTag(wrapperTag);
+            output.WriteLength(4); // unknownTag + value 5 + valueType + value 6, each 1 byte
+            output.WriteTag(unknownTag);
+            output.WriteInt32((int) valueTag); // Sneakily "pretend" it's a tag when it's really a value
+            output.WriteTag(valueTag);
+            output.WriteInt32(6);
+
+            output.Flush();
+            stream.Position = 0;
+            
+            var message = TestWellKnownTypes.Parser.ParseFrom(stream);
+            Assert.AreEqual(6, message.Int32Field);
+        }
+
+        [Test]
+        public void ClearWithReflection()
+        {
+            // String and Bytes are the tricky ones here, as the CLR type of the property
+            // is the same between the wrapper and non-wrapper types.
+            var message = new TestWellKnownTypes { StringField = "foo" };
+            TestWellKnownTypes.Descriptor.Fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.Clear(message);
+            Assert.IsNull(message.StringField);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/packages.config b/csharp/src/Google.Protobuf.Test/packages.config
new file mode 100644
index 0000000..c765399
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="NUnit" version="2.6.4" targetFramework="net45" userInstalled="true" />
+  <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" userInstalled="true" />
+</packages>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.sln b/csharp/src/Google.Protobuf.sln
new file mode 100644
index 0000000..72d87f7
--- /dev/null
+++ b/csharp/src/Google.Protobuf.sln
@@ -0,0 +1,56 @@
+Microsoft Visual Studio Solution File, Format Version 12.00

+# Visual Studio 2015

+VisualStudioVersion = 14.0.24720.0

+MinimumVisualStudioVersion = 14.0.24720.0

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf", "Google.Protobuf\Google.Protobuf.csproj", "{6908BDCE-D925-43F3-94AC-A531E6DF2591}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Test", "Google.Protobuf.Test\Google.Protobuf.Test.csproj", "{DD01ED24-3750-4567-9A23-1DB676A15610}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddressBook", "AddressBook\AddressBook.csproj", "{A31F5FB2-4FF3-432A-B35B-5CD203606311}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.JsonDump", "Google.Protobuf.JsonDump\Google.Protobuf.JsonDump.csproj", "{D7282E99-2DC3-405B-946F-177DB2FD2AE2}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Conformance", "Google.Protobuf.Conformance\Google.Protobuf.Conformance.csproj", "{0607D1B8-80D6-4B35-9857-1263C1B32B94}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Any CPU = Debug|Any CPU

+		Release|Any CPU = Release|Any CPU

+		ReleaseSigned|Any CPU = ReleaseSigned|Any CPU

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Release|Any CPU.Build.0 = Release|Any CPU

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU

+		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.Release|Any CPU.Build.0 = Release|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU

+		{DD01ED24-3750-4567-9A23-1DB676A15610}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Release|Any CPU.Build.0 = Release|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

+		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Release|Any CPU.Build.0 = Release|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

+		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Release|Any CPU.Build.0 = Release|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

+		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/csharp/src/Google.Protobuf/ByteArray.cs b/csharp/src/Google.Protobuf/ByteArray.cs
new file mode 100644
index 0000000..69b6ef8
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ByteArray.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy

+    /// </summary>

+    internal static class ByteArray

+    {

+        /// <summary>

+        /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy

+        /// </summary>

+        private const int CopyThreshold = 12;

+

+        /// <summary>

+        /// Determines which copy routine to use based on the number of bytes to be copied.

+        /// </summary>

+        internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)

+        {

+            if (count > CopyThreshold)

+            {

+                Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);

+            }

+            else

+            {

+                int stop = srcOffset + count;

+                for (int i = srcOffset; i < stop; i++)

+                {

+                    dst[dstOffset++] = src[i];

+                }

+            }

+        }

+

+        /// <summary>

+        /// Reverses the order of bytes in the array

+        /// </summary>

+        internal static void Reverse(byte[] bytes)

+        {

+            for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)

+            {

+                byte temp = bytes[first];

+                bytes[first] = bytes[last];

+                bytes[last] = temp;

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs
new file mode 100644
index 0000000..dd7f22d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ByteString.cs
@@ -0,0 +1,345 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.Collections;

+using System.Collections.Generic;

+using System.IO;

+using System.Text;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Immutable array of bytes.

+    /// </summary>

+    public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>

+    {

+        private static readonly ByteString empty = new ByteString(new byte[0]);

+

+        private readonly byte[] bytes;

+

+        /// <summary>

+        /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.

+        /// </summary>

+        internal static class Unsafe

+        {

+            /// <summary>

+            /// Constructs a new ByteString from the given byte array. The array is

+            /// *not* copied, and must not be modified after this constructor is called.

+            /// </summary>

+            internal static ByteString FromBytes(byte[] bytes)

+            {

+                return new ByteString(bytes);

+            }

+

+            /// <summary>

+            /// Provides direct, unrestricted access to the bytes contained in this instance.

+            /// You must not modify or resize the byte array returned by this method.

+            /// </summary>

+            internal static byte[] GetBuffer(ByteString bytes)

+            {

+                return bytes.bytes;

+            }

+        }

+

+        /// <summary>

+        /// Internal use only.  Ensure that the provided array is not mutated and belongs to this instance.

+        /// </summary>

+        internal static ByteString AttachBytes(byte[] bytes)

+        {

+            return new ByteString(bytes);

+        }

+

+        /// <summary>

+        /// Constructs a new ByteString from the given byte array. The array is

+        /// *not* copied, and must not be modified after this constructor is called.

+        /// </summary>

+        private ByteString(byte[] bytes)

+        {

+            this.bytes = bytes;

+        }

+

+        /// <summary>

+        /// Returns an empty ByteString.

+        /// </summary>

+        public static ByteString Empty

+        {

+            get { return empty; }

+        }

+

+        /// <summary>

+        /// Returns the length of this ByteString in bytes.

+        /// </summary>

+        public int Length

+        {

+            get { return bytes.Length; }

+        }

+

+        /// <summary>

+        /// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.

+        /// </summary>

+        public bool IsEmpty

+        {

+            get { return Length == 0; }

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a byte array.

+        /// </summary>

+        /// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>

+        /// <returns>A byte array with the same data as this <c>ByteString</c>.</returns>

+        public byte[] ToByteArray()

+        {

+            return (byte[]) bytes.Clone();

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a standard base64 representation.

+        /// </summary>

+        /// <returns>A base64 representation of this <c>ByteString</c>.</returns>

+        public string ToBase64()

+        {

+            return Convert.ToBase64String(bytes);

+        }

+

+        /// <summary>

+        /// Constructs a <see cref="ByteString" /> from the Base64 Encoded String.

+        /// </summary>

+        public static ByteString FromBase64(string bytes)

+        {

+            // By handling the empty string explicitly, we not only optimize but we fix a

+            // problem on CF 2.0. See issue 61 for details.

+            return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));

+        }

+

+        /// <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.

+        /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form

+        /// which is primarily useful for testing.

+        /// </summary>

+        public static ByteString CopyFrom(params byte[] bytes)

+        {

+            return new ByteString((byte[]) bytes.Clone());

+        }

+

+        /// <summary>

+        /// Constructs a <see cref="ByteString" /> from a portion of a byte array.

+        /// </summary>

+        public static ByteString CopyFrom(byte[] bytes, int offset, int count)

+        {

+            byte[] portion = new byte[count];

+            ByteArray.Copy(bytes, offset, portion, 0, count);

+            return new ByteString(portion);

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="ByteString" /> by encoding the specified text with

+        /// the given encoding.

+        /// </summary>

+        public static ByteString CopyFrom(string text, Encoding encoding)

+        {

+            return new ByteString(encoding.GetBytes(text));

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8.

+        /// </summary>

+        public static ByteString CopyFromUtf8(string text)

+        {

+            return CopyFrom(text, Encoding.UTF8);

+        }

+

+        /// <summary>

+        /// Retuns the byte at the given index.

+        /// </summary>

+        public byte this[int index]

+        {

+            get { return bytes[index]; }

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a string by applying the given encoding.

+        /// </summary>

+        /// <remarks>

+        /// This method should only be used to convert binary data which was the result of encoding

+        /// text with the given encoding.

+        /// </remarks>

+        /// <param name="encoding">The encoding to use to decode the binary data into text.</param>

+        /// <returns>The result of decoding the binary data with the given decoding.</returns>

+        public string ToString(Encoding encoding)

+        {

+            return encoding.GetString(bytes, 0, bytes.Length);

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.

+        /// </summary>

+        /// <remarks>

+        /// This method should only be used to convert binary data which was the result of encoding

+        /// text with UTF-8.

+        /// </remarks>

+        /// <returns>The result of decoding the binary data with the given decoding.</returns>

+        public string ToStringUtf8()

+        {

+            return ToString(Encoding.UTF8);

+        }

+

+        /// <summary>

+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.

+        /// </summary>

+        /// <returns>An iterator over the bytes in this object.</returns>

+        public IEnumerator<byte> GetEnumerator()

+        {

+            return ((IEnumerable<byte>) bytes).GetEnumerator();

+        }

+

+        /// <summary>

+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.

+        /// </summary>

+        /// <returns>An iterator over the bytes in this object.</returns>

+        IEnumerator IEnumerable.GetEnumerator()

+        {

+            return GetEnumerator();

+        }

+

+        /// <summary>

+        /// Creates a CodedInputStream from this ByteString's data.

+        /// </summary>

+        public CodedInputStream CreateCodedInput()

+        {

+            // We trust CodedInputStream not to reveal the provided byte array or modify it

+            return new CodedInputStream(bytes);

+        }

+

+        /// <summary>

+        /// Compares two byte strings for equality.

+        /// </summary>

+        /// <param name="lhs">The first byte string to compare.</param>

+        /// <param name="rhs">The second byte string to compare.</param>

+        /// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>

+        public static bool operator ==(ByteString lhs, ByteString rhs)

+        {

+            if (ReferenceEquals(lhs, rhs))

+            {

+                return true;

+            }

+            if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))

+            {

+                return false;

+            }

+            if (lhs.bytes.Length != rhs.bytes.Length)

+            {

+                return false;

+            }

+            for (int i = 0; i < lhs.Length; i++)

+            {

+                if (rhs.bytes[i] != lhs.bytes[i])

+                {

+                    return false;

+                }

+            }

+            return true;

+        }

+

+        /// <summary>

+        /// Compares two byte strings for inequality.

+        /// </summary>

+        /// <param name="lhs">The first byte string to compare.</param>

+        /// <param name="rhs">The second byte string to compare.</param>

+        /// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>

+        public static bool operator !=(ByteString lhs, ByteString rhs)

+        {

+            return !(lhs == rhs);

+        }

+

+        /// <summary>

+        /// Compares this byte string with another object.

+        /// </summary>

+        /// <param name="obj">The object to compare this with.</param>

+        /// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>

+        public override bool Equals(object obj)

+        {

+            return this == (obj as ByteString);

+        }

+

+        /// <summary>

+        /// Returns a hash code for this object. Two equal byte strings

+        /// will return the same hash code.

+        /// </summary>

+        /// <returns>A hash code for this object.</returns>

+        public override int GetHashCode()

+        {

+            int ret = 23;

+            foreach (byte b in bytes)

+            {

+                ret = (ret << 8) | b;

+            }

+            return ret;

+        }

+

+        /// <summary>

+        /// Compares this byte string with another.

+        /// </summary>

+        /// <param name="other">The <see cref="ByteString"/> to compare this with.</param>

+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>

+        public bool Equals(ByteString other)

+        {

+            return this == other;

+        }

+

+        /// <summary>

+        /// Used internally by CodedOutputStream to avoid creating a copy for the write

+        /// </summary>

+        internal void WriteRawBytesTo(CodedOutputStream outputStream)

+        {

+            outputStream.WriteRawBytes(bytes, 0, bytes.Length);

+        }

+

+        /// <summary>

+        /// Copies the entire byte array to the destination array provided at the offset specified.

+        /// </summary>

+        public void CopyTo(byte[] array, int position)

+        {

+            ByteArray.Copy(bytes, 0, array, position, bytes.Length);

+        }

+

+        /// <summary>

+        /// Writes the entire byte array to the provided stream

+        /// </summary>

+        public void WriteTo(Stream outputStream)

+        {

+            outputStream.Write(bytes, 0, bytes.Length);

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
new file mode 100644
index 0000000..ce6856d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -0,0 +1,1277 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using Google.Protobuf.Collections;

+using System;

+using System.Collections.Generic;

+using System.IO;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Reads and decodes protocol message fields.

+    /// </summary>

+    /// <remarks>

+    /// <para>

+    /// This class is generally used by generated code to read appropriate

+    /// primitives from the stream. It effectively encapsulates the lowest

+    /// levels of protocol buffer format.

+    /// </para>

+    /// <para>

+    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>

+    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.

+    /// </para>

+    /// </remarks>

+    public sealed class CodedInputStream : IDisposable

+    {

+        /// <summary>

+        /// Whether to leave the underlying stream open when disposing of this stream.

+        /// This is always true when there's no stream.

+        /// </summary>

+        private readonly bool leaveOpen;

+

+        /// <summary>

+        /// Buffer of data read from the stream or provided at construction time.

+        /// </summary>

+        private readonly byte[] buffer;

+

+        /// <summary>

+        /// The index of the buffer at which we need to refill from the stream (if there is one).

+        /// </summary>

+        private int bufferSize;

+

+        private int bufferSizeAfterLimit = 0;

+        /// <summary>

+        /// The position within the current buffer (i.e. the next byte to read)

+        /// </summary>

+        private int bufferPos = 0;

+

+        /// <summary>

+        /// The stream to read further input from, or null if the byte array buffer was provided

+        /// directly on construction, with no further data available.

+        /// </summary>

+        private readonly Stream input;

+

+        /// <summary>

+        /// The last tag we read. 0 indicates we've read to the end of the stream

+        /// (or haven't read anything yet).

+        /// </summary>

+        private uint lastTag = 0;

+

+        /// <summary>

+        /// The next tag, used to store the value read by PeekTag.

+        /// </summary>

+        private uint nextTag = 0;

+        private bool hasNextTag = false;

+

+        internal const int DefaultRecursionLimit = 64;

+        internal const int DefaultSizeLimit = 64 << 20; // 64MB

+        internal const int BufferSize = 4096;

+

+        /// <summary>

+        /// The total number of bytes read before the current buffer. The

+        /// total bytes read up to the current position can be computed as

+        /// totalBytesRetired + bufferPos.

+        /// </summary>

+        private int totalBytesRetired = 0;

+

+        /// <summary>

+        /// The absolute position of the end of the current message.

+        /// </summary> 

+        private int currentLimit = int.MaxValue;

+

+        private int recursionDepth = 0;

+

+        private readonly int recursionLimit;

+        private readonly int sizeLimit;

+

+        #region Construction

+        // Note that the checks are performed such that we don't end up checking obviously-valid things

+        // like non-null references for arrays we've just created.

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given byte array.

+        /// </summary>

+        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)

+        {            

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.

+        /// </summary>

+        public CodedInputStream(byte[] buffer, int offset, int length)

+            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)

+        {            

+            if (offset < 0 || offset > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");

+            }

+            if (length < 0 || offset + length > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");

+            }

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed

+        /// when the returned object is disposed.

+        /// </summary>

+        /// <param name="input">The stream to read from.</param>

+        public CodedInputStream(Stream input) : this(input, false)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.

+        /// </summary>

+        /// <param name="input">The stream to read from.</param>

+        /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned

+        /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the

+        /// returned object is disposed.</param>

+        public CodedInputStream(Stream input, bool leaveOpen)

+            : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0)

+        {

+            this.leaveOpen = leaveOpen;

+        }

+        

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given

+        /// stream and buffer, using the default limits.

+        /// </summary>

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize)

+        {

+            this.input = input;

+            this.buffer = buffer;

+            this.bufferPos = bufferPos;

+            this.bufferSize = bufferSize;

+            this.sizeLimit = DefaultSizeLimit;

+            this.recursionLimit = DefaultRecursionLimit;

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given

+        /// stream and buffer, using the specified limits.

+        /// </summary>

+        /// <remarks>

+        /// This chains to the version with the default limits instead of vice versa to avoid

+        /// having to check that the default values are valid every time.

+        /// </remarks>

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit)

+            : this(input, buffer, bufferPos, bufferSize)

+        {

+            if (sizeLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");

+            }

+            if (recursionLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");

+            }

+            this.sizeLimit = sizeLimit;

+            this.recursionLimit = recursionLimit;

+        }

+        #endregion

+

+        /// <summary>

+        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading

+        /// from an input stream.

+        /// </summary>

+        /// <remarks>

+        /// This method exists separately from the constructor to reduce the number of constructor overloads.

+        /// It is likely to be used considerably less frequently than the constructors, as the default limits

+        /// are suitable for most use cases.

+        /// </remarks>

+        /// <param name="input">The input stream to read from</param>

+        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>

+        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>

+        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size

+        /// and recursion limits.</returns>

+        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)

+        {

+            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit);

+        }

+

+        /// <summary>

+        /// Returns the current position in the input stream, or the position in the input buffer

+        /// </summary>

+        public long Position 

+        {

+            get

+            {

+                if (input != null)

+                {

+                    return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);

+                }

+                return bufferPos;

+            }

+        }

+

+        /// <summary>

+        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond

+        /// the end of the stream.

+        /// </summary>

+        internal uint LastTag { get { return lastTag; } }

+

+        /// <summary>

+        /// Returns the size limit for this stream.

+        /// </summary>

+        /// <remarks>

+        /// This limit is applied when reading from the underlying stream, as a sanity check. It is

+        /// not applied when reading from a byte array data source without an underlying stream.

+        /// The default value is 64MB.

+        /// </remarks>

+        /// <value>

+        /// The size limit.

+        /// </value>

+        public int SizeLimit { get { return sizeLimit; } }

+

+        /// <summary>

+        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,

+        /// to avoid maliciously-recursive data.

+        /// </summary>

+        /// <remarks>

+        /// The default limit is 64.

+        /// </remarks>

+        /// <value>

+        /// The recursion limit for this stream.

+        /// </value>

+        public int RecursionLimit { get { return recursionLimit; } }

+

+        /// <summary>

+        /// Disposes of this instance, potentially closing any underlying stream.

+        /// </summary>

+        /// <remarks>

+        /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which

+        /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which

+        /// was constructed to read from a byte array) has no effect.

+        /// </remarks>

+        public void Dispose()

+        {

+            if (!leaveOpen)

+            {

+                input.Dispose();

+            }

+        }

+

+        #region Validation

+        /// <summary>

+        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,

+        /// we've reached the end of the stream when we expected to.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">The 

+        /// tag read was not the one specified</exception>

+        internal void CheckReadEndOfStreamTag()

+        {

+            if (lastTag != 0)

+            {

+                throw InvalidProtocolBufferException.MoreDataAvailable();

+            }

+        }

+        #endregion

+

+        #region Reading of tags etc

+

+        /// <summary>

+        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the

+        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the

+        /// same value.)

+        /// </summary>

+        public uint PeekTag()

+        {

+            if (hasNextTag)

+            {

+                return nextTag;

+            }

+

+            uint savedLast = lastTag;

+            nextTag = ReadTag();

+            hasNextTag = true;

+            lastTag = savedLast; // Undo the side effect of ReadTag

+            return nextTag;

+        }

+

+        /// <summary>

+        /// Reads a field tag, returning the tag of 0 for "end of stream".

+        /// </summary>

+        /// <remarks>

+        /// If this method returns 0, it doesn't necessarily mean the end of all

+        /// the data in this CodedInputStream; it may be the end of the logical stream

+        /// for an embedded message, for example.

+        /// </remarks>

+        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>

+        public uint ReadTag()

+        {

+            if (hasNextTag)

+            {

+                lastTag = nextTag;

+                hasNextTag = false;

+                return lastTag;

+            }

+

+            // Optimize for the incredibly common case of having at least two bytes left in the buffer,

+            // and those two bytes being enough to get the tag. This will be true for fields up to 4095.

+            if (bufferPos + 2 <= bufferSize)

+            {

+                int tmp = buffer[bufferPos++];

+                if (tmp < 128)

+                {

+                    lastTag = (uint)tmp;

+                }

+                else

+                {

+                    int result = tmp & 0x7f;

+                    if ((tmp = buffer[bufferPos++]) < 128)

+                    {

+                        result |= tmp << 7;

+                        lastTag = (uint) result;

+                    }

+                    else

+                    {

+                        // Nope, rewind and go the potentially slow route.

+                        bufferPos -= 2;

+                        lastTag = ReadRawVarint32();

+                    }

+                }

+            }

+            else

+            {

+                if (IsAtEnd)

+                {

+                    lastTag = 0;

+                    return 0; // This is the only case in which we return 0.

+                }

+

+                lastTag = ReadRawVarint32();

+            }

+            if (lastTag == 0)

+            {

+                // If we actually read zero, that's not a valid tag.

+                throw InvalidProtocolBufferException.InvalidTag();

+            }

+            return lastTag;

+        }

+

+        /// <summary>

+        /// Skips the data for the field with the tag we've just read.

+        /// This should be called directly after <see cref="ReadTag"/>, when

+        /// the caller wishes to skip an unknown field.

+        /// </summary>

+        /// <remarks>

+        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.

+        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the

+        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly

+        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.

+        /// </remarks>

+        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>

+        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>

+        public void SkipLastField()

+        {

+            if (lastTag == 0)

+            {

+                throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");

+            }

+            switch (WireFormat.GetTagWireType(lastTag))

+            {

+                case WireFormat.WireType.StartGroup:

+                    SkipGroup(lastTag);

+                    break;

+                case WireFormat.WireType.EndGroup:

+                    throw new InvalidProtocolBufferException(

+                        "SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");

+                case WireFormat.WireType.Fixed32:

+                    ReadFixed32();

+                    break;

+                case WireFormat.WireType.Fixed64:

+                    ReadFixed64();

+                    break;

+                case WireFormat.WireType.LengthDelimited:

+                    var length = ReadLength();

+                    SkipRawBytes(length);

+                    break;

+                case WireFormat.WireType.Varint:

+                    ReadRawVarint32();

+                    break;

+            }

+        }

+

+        private void SkipGroup(uint startGroupTag)

+        {

+            // Note: Currently we expect this to be the way that groups are read. We could put the recursion

+            // depth changes into the ReadTag method instead, potentially...

+            recursionDepth++;

+            if (recursionDepth >= recursionLimit)

+            {

+                throw InvalidProtocolBufferException.RecursionLimitExceeded();

+            }

+            uint tag;

+            while (true)

+            {

+                tag = ReadTag();

+                if (tag == 0)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                // Can't call SkipLastField for this case- that would throw.

+                if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)

+                {

+                    break;

+                }

+                // This recursion will allow us to handle nested groups.

+                SkipLastField();

+            }

+            int startField = WireFormat.GetTagFieldNumber(startGroupTag);

+            int endField = WireFormat.GetTagFieldNumber(tag);

+            if (startField != endField)

+            {

+                throw new InvalidProtocolBufferException(

+                    $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}");

+            }

+            recursionDepth--;

+        }

+

+        /// <summary>

+        /// Reads a double field from the stream.

+        /// </summary>

+        public double ReadDouble()

+        {

+            return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());

+        }

+

+        /// <summary>

+        /// Reads a float field from the stream.

+        /// </summary>

+        public float ReadFloat()

+        {

+            if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)

+            {

+                float ret = BitConverter.ToSingle(buffer, bufferPos);

+                bufferPos += 4;

+                return ret;

+            }

+            else

+            {

+                byte[] rawBytes = ReadRawBytes(4);

+                if (!BitConverter.IsLittleEndian)

+                {

+                    ByteArray.Reverse(rawBytes);

+                }

+                return BitConverter.ToSingle(rawBytes, 0);

+            }

+        }

+

+        /// <summary>

+        /// Reads a uint64 field from the stream.

+        /// </summary>

+        public ulong ReadUInt64()

+        {

+            return ReadRawVarint64();

+        }

+

+        /// <summary>

+        /// Reads an int64 field from the stream.

+        /// </summary>

+        public long ReadInt64()

+        {

+            return (long) ReadRawVarint64();

+        }

+

+        /// <summary>

+        /// Reads an int32 field from the stream.

+        /// </summary>

+        public int ReadInt32()

+        {

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads a fixed64 field from the stream.

+        /// </summary>

+        public ulong ReadFixed64()

+        {

+            return ReadRawLittleEndian64();

+        }

+

+        /// <summary>

+        /// Reads a fixed32 field from the stream.

+        /// </summary>

+        public uint ReadFixed32()

+        {

+            return ReadRawLittleEndian32();

+        }

+

+        /// <summary>

+        /// Reads a bool field from the stream.

+        /// </summary>

+        public bool ReadBool()

+        {

+            return ReadRawVarint32() != 0;

+        }

+

+        /// <summary>

+        /// Reads a string field from the stream.

+        /// </summary>

+        public string ReadString()

+        {

+            int length = ReadLength();

+            // No need to read any data for an empty string.

+            if (length == 0)

+            {

+                return "";

+            }

+            if (length <= bufferSize - bufferPos)

+            {

+                // Fast path:  We already have the bytes in a contiguous buffer, so

+                //   just copy directly from it.

+                String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);

+                bufferPos += length;

+                return result;

+            }

+            // Slow path: Build a byte array first then copy it.

+            return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);

+        }

+

+        /// <summary>

+        /// Reads an embedded message field value from the stream.

+        /// </summary>   

+        public void ReadMessage(IMessage builder)

+        {

+            int length = ReadLength();

+            if (recursionDepth >= recursionLimit)

+            {

+                throw InvalidProtocolBufferException.RecursionLimitExceeded();

+            }

+            int oldLimit = PushLimit(length);

+            ++recursionDepth;

+            builder.MergeFrom(this);

+            CheckReadEndOfStreamTag();

+            // Check that we've read exactly as much data as expected.

+            if (!ReachedLimit)

+            {

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+            --recursionDepth;

+            PopLimit(oldLimit);

+        }

+

+        /// <summary>

+        /// Reads a bytes field value from the stream.

+        /// </summary>   

+        public ByteString ReadBytes()

+        {

+            int length = ReadLength();

+            if (length <= bufferSize - bufferPos && length > 0)

+            {

+                // Fast path:  We already have the bytes in a contiguous buffer, so

+                //   just copy directly from it.

+                ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);

+                bufferPos += length;

+                return result;

+            }

+            else

+            {

+                // Slow path:  Build a byte array and attach it to a new ByteString.

+                return ByteString.AttachBytes(ReadRawBytes(length));

+            }

+        }

+

+        /// <summary>

+        /// Reads a uint32 field value from the stream.

+        /// </summary>   

+        public uint ReadUInt32()

+        {

+            return ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads an enum field value from the stream. If the enum is valid for type T,

+        /// then the ref value is set and it returns true.  Otherwise the unknown output

+        /// value is set and this method returns false.

+        /// </summary>   

+        public int ReadEnum()

+        {

+            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads an sfixed32 field value from the stream.

+        /// </summary>   

+        public int ReadSFixed32()

+        {

+            return (int) ReadRawLittleEndian32();

+        }

+

+        /// <summary>

+        /// Reads an sfixed64 field value from the stream.

+        /// </summary>   

+        public long ReadSFixed64()

+        {

+            return (long) ReadRawLittleEndian64();

+        }

+

+        /// <summary>

+        /// Reads an sint32 field value from the stream.

+        /// </summary>   

+        public int ReadSInt32()

+        {

+            return DecodeZigZag32(ReadRawVarint32());

+        }

+

+        /// <summary>

+        /// Reads an sint64 field value from the stream.

+        /// </summary>   

+        public long ReadSInt64()

+        {

+            return DecodeZigZag64(ReadRawVarint64());

+        }

+

+        /// <summary>

+        /// Reads a length for length-delimited data.

+        /// </summary>

+        /// <remarks>

+        /// This is internally just reading a varint, but this method exists

+        /// to make the calling code clearer.

+        /// </remarks>

+        public int ReadLength()

+        {

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,

+        /// the tag is consumed and the method returns <c>true</c>; otherwise, the

+        /// stream is left in the original position and the method returns <c>false</c>.

+        /// </summary>

+        public bool MaybeConsumeTag(uint tag)

+        {

+            if (PeekTag() == tag)

+            {

+                hasNextTag = false;

+                return true;

+            }

+            return false;

+        }

+

+        #endregion

+

+        #region Underlying reading primitives

+

+        /// <summary>

+        /// Same code as ReadRawVarint32, but read each byte individually, checking for

+        /// buffer overflow.

+        /// </summary>

+        private uint SlowReadRawVarint32()

+        {

+            int tmp = ReadRawByte();

+            if (tmp < 128)

+            {

+                return (uint) tmp;

+            }

+            int result = tmp & 0x7f;

+            if ((tmp = ReadRawByte()) < 128)

+            {

+                result |= tmp << 7;

+            }

+            else

+            {

+                result |= (tmp & 0x7f) << 7;

+                if ((tmp = ReadRawByte()) < 128)

+                {

+                    result |= tmp << 14;

+                }

+                else

+                {

+                    result |= (tmp & 0x7f) << 14;

+                    if ((tmp = ReadRawByte()) < 128)

+                    {

+                        result |= tmp << 21;

+                    }

+                    else

+                    {

+                        result |= (tmp & 0x7f) << 21;

+                        result |= (tmp = ReadRawByte()) << 28;

+                        if (tmp >= 128)

+                        {

+                            // Discard upper 32 bits.

+                            for (int i = 0; i < 5; i++)

+                            {

+                                if (ReadRawByte() < 128)

+                                {

+                                    return (uint) result;

+                                }

+                            }

+                            throw InvalidProtocolBufferException.MalformedVarint();

+                        }

+                    }

+                }

+            }

+            return (uint) result;

+        }

+

+        /// <summary>

+        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.

+        /// This method is optimised for the case where we've got lots of data in the buffer.

+        /// That means we can check the size just once, then just read directly from the buffer

+        /// without constant rechecking of the buffer length.

+        /// </summary>

+        internal uint ReadRawVarint32()

+        {

+            if (bufferPos + 5 > bufferSize)

+            {

+                return SlowReadRawVarint32();

+            }

+

+            int tmp = buffer[bufferPos++];

+            if (tmp < 128)

+            {

+                return (uint) tmp;

+            }

+            int result = tmp & 0x7f;

+            if ((tmp = buffer[bufferPos++]) < 128)

+            {

+                result |= tmp << 7;

+            }

+            else

+            {

+                result |= (tmp & 0x7f) << 7;

+                if ((tmp = buffer[bufferPos++]) < 128)

+                {

+                    result |= tmp << 14;

+                }

+                else

+                {

+                    result |= (tmp & 0x7f) << 14;

+                    if ((tmp = buffer[bufferPos++]) < 128)

+                    {

+                        result |= tmp << 21;

+                    }

+                    else

+                    {

+                        result |= (tmp & 0x7f) << 21;

+                        result |= (tmp = buffer[bufferPos++]) << 28;

+                        if (tmp >= 128)

+                        {

+                            // Discard upper 32 bits.

+                            // Note that this has to use ReadRawByte() as we only ensure we've

+                            // got at least 5 bytes at the start of the method. This lets us

+                            // use the fast path in more cases, and we rarely hit this section of code.

+                            for (int i = 0; i < 5; i++)

+                            {

+                                if (ReadRawByte() < 128)

+                                {

+                                    return (uint) result;

+                                }

+                            }

+                            throw InvalidProtocolBufferException.MalformedVarint();

+                        }

+                    }

+                }

+            }

+            return (uint) result;

+        }

+

+        /// <summary>

+        /// Reads a varint from the input one byte at a time, so that it does not

+        /// read any bytes after the end of the varint. If you simply wrapped the

+        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)

+        /// then you would probably end up reading past the end of the varint since

+        /// CodedInputStream buffers its input.

+        /// </summary>

+        /// <param name="input"></param>

+        /// <returns></returns>

+        internal static uint ReadRawVarint32(Stream input)

+        {

+            int result = 0;

+            int offset = 0;

+            for (; offset < 32; offset += 7)

+            {

+                int b = input.ReadByte();

+                if (b == -1)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                result |= (b & 0x7f) << offset;

+                if ((b & 0x80) == 0)

+                {

+                    return (uint) result;

+                }

+            }

+            // Keep reading up to 64 bits.

+            for (; offset < 64; offset += 7)

+            {

+                int b = input.ReadByte();

+                if (b == -1)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                if ((b & 0x80) == 0)

+                {

+                    return (uint) result;

+                }

+            }

+            throw InvalidProtocolBufferException.MalformedVarint();

+        }

+

+        /// <summary>

+        /// Reads a raw varint from the stream.

+        /// </summary>

+        internal ulong ReadRawVarint64()

+        {

+            int shift = 0;

+            ulong result = 0;

+            while (shift < 64)

+            {

+                byte b = ReadRawByte();

+                result |= (ulong) (b & 0x7F) << shift;

+                if ((b & 0x80) == 0)

+                {

+                    return result;

+                }

+                shift += 7;

+            }

+            throw InvalidProtocolBufferException.MalformedVarint();

+        }

+

+        /// <summary>

+        /// Reads a 32-bit little-endian integer from the stream.

+        /// </summary>

+        internal uint ReadRawLittleEndian32()

+        {

+            uint b1 = ReadRawByte();

+            uint b2 = ReadRawByte();

+            uint b3 = ReadRawByte();

+            uint b4 = ReadRawByte();

+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);

+        }

+

+        /// <summary>

+        /// Reads a 64-bit little-endian integer from the stream.

+        /// </summary>

+        internal ulong ReadRawLittleEndian64()

+        {

+            ulong b1 = ReadRawByte();

+            ulong b2 = ReadRawByte();

+            ulong b3 = ReadRawByte();

+            ulong b4 = ReadRawByte();

+            ulong b5 = ReadRawByte();

+            ulong b6 = ReadRawByte();

+            ulong b7 = ReadRawByte();

+            ulong b8 = ReadRawByte();

+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)

+                   | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);

+        }

+

+        /// <summary>

+        /// Decode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static int DecodeZigZag32(uint n)

+        {

+            return (int)(n >> 1) ^ -(int)(n & 1);

+        }

+

+        /// <summary>

+        /// Decode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static long DecodeZigZag64(ulong n)

+        {

+            return (long)(n >> 1) ^ -(long)(n & 1);

+        }

+        #endregion

+

+        #region Internal reading and buffer management

+

+        /// <summary>

+        /// Sets currentLimit to (current position) + byteLimit. This is called

+        /// when descending into a length-delimited embedded message. The previous

+        /// limit is returned.

+        /// </summary>

+        /// <returns>The old limit.</returns>

+        internal int PushLimit(int byteLimit)

+        {

+            if (byteLimit < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+            byteLimit += totalBytesRetired + bufferPos;

+            int oldLimit = currentLimit;

+            if (byteLimit > oldLimit)

+            {

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+            currentLimit = byteLimit;

+

+            RecomputeBufferSizeAfterLimit();

+

+            return oldLimit;

+        }

+

+        private void RecomputeBufferSizeAfterLimit()

+        {

+            bufferSize += bufferSizeAfterLimit;

+            int bufferEnd = totalBytesRetired + bufferSize;

+            if (bufferEnd > currentLimit)

+            {

+                // Limit is in current buffer.

+                bufferSizeAfterLimit = bufferEnd - currentLimit;

+                bufferSize -= bufferSizeAfterLimit;

+            }

+            else

+            {

+                bufferSizeAfterLimit = 0;

+            }

+        }

+

+        /// <summary>

+        /// Discards the current limit, returning the previous limit.

+        /// </summary>

+        internal void PopLimit(int oldLimit)

+        {

+            currentLimit = oldLimit;

+            RecomputeBufferSizeAfterLimit();

+        }

+

+        /// <summary>

+        /// Returns whether or not all the data before the limit has been read.

+        /// </summary>

+        /// <returns></returns>

+        internal bool ReachedLimit

+        {

+            get

+            {

+                if (currentLimit == int.MaxValue)

+                {

+                    return false;

+                }

+                int currentAbsolutePosition = totalBytesRetired + bufferPos;

+                return currentAbsolutePosition >= currentLimit;

+            }

+        }

+

+        /// <summary>

+        /// Returns true if the stream has reached the end of the input. This is the

+        /// case if either the end of the underlying input source has been reached or

+        /// the stream has reached a limit created using PushLimit.

+        /// </summary>

+        public bool IsAtEnd

+        {

+            get { return bufferPos == bufferSize && !RefillBuffer(false); }

+        }

+

+        /// <summary>

+        /// Called when buffer is empty to read more bytes from the

+        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that

+        /// either there will be at least one byte in the buffer when it returns

+        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,

+        /// RefillBuffer() returns false if no more bytes were available.

+        /// </summary>

+        /// <param name="mustSucceed"></param>

+        /// <returns></returns>

+        private bool RefillBuffer(bool mustSucceed)

+        {

+            if (bufferPos < bufferSize)

+            {

+                throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");

+            }

+

+            if (totalBytesRetired + bufferSize == currentLimit)

+            {

+                // Oops, we hit a limit.

+                if (mustSucceed)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                else

+                {

+                    return false;

+                }

+            }

+

+            totalBytesRetired += bufferSize;

+

+            bufferPos = 0;

+            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);

+            if (bufferSize < 0)

+            {

+                throw new InvalidOperationException("Stream.Read returned a negative count");

+            }

+            if (bufferSize == 0)

+            {

+                if (mustSucceed)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                else

+                {

+                    return false;

+                }

+            }

+            else

+            {

+                RecomputeBufferSizeAfterLimit();

+                int totalBytesRead =

+                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;

+                if (totalBytesRead > sizeLimit || totalBytesRead < 0)

+                {

+                    throw InvalidProtocolBufferException.SizeLimitExceeded();

+                }

+                return true;

+            }

+        }

+

+        /// <summary>

+        /// Read one byte from the input.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">

+        /// the end of the stream or the current limit was reached

+        /// </exception>

+        internal byte ReadRawByte()

+        {

+            if (bufferPos == bufferSize)

+            {

+                RefillBuffer(true);

+            }

+            return buffer[bufferPos++];

+        }

+

+        /// <summary>

+        /// Reads a fixed size of bytes from the input.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">

+        /// the end of the stream or the current limit was reached

+        /// </exception>

+        internal byte[] ReadRawBytes(int size)

+        {

+            if (size < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+

+            if (totalBytesRetired + bufferPos + size > currentLimit)

+            {

+                // Read to the end of the stream (up to the current limit) anyway.

+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);

+                // Then fail.

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+

+            if (size <= bufferSize - bufferPos)

+            {

+                // We have all the bytes we need already.

+                byte[] bytes = new byte[size];

+                ByteArray.Copy(buffer, bufferPos, bytes, 0, size);

+                bufferPos += size;

+                return bytes;

+            }

+            else if (size < buffer.Length)

+            {

+                // Reading more bytes than are in the buffer, but not an excessive number

+                // of bytes.  We can safely allocate the resulting array ahead of time.

+

+                // First copy what we have.

+                byte[] bytes = new byte[size];

+                int pos = bufferSize - bufferPos;

+                ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);

+                bufferPos = bufferSize;

+

+                // We want to use RefillBuffer() and then copy from the buffer into our

+                // byte array rather than reading directly into our byte array because

+                // the input may be unbuffered.

+                RefillBuffer(true);

+

+                while (size - pos > bufferSize)

+                {

+                    Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);

+                    pos += bufferSize;

+                    bufferPos = bufferSize;

+                    RefillBuffer(true);

+                }

+

+                ByteArray.Copy(buffer, 0, bytes, pos, size - pos);

+                bufferPos = size - pos;

+

+                return bytes;

+            }

+            else

+            {

+                // The size is very large.  For security reasons, we can't allocate the

+                // entire byte array yet.  The size comes directly from the input, so a

+                // maliciously-crafted message could provide a bogus very large size in

+                // order to trick the app into allocating a lot of memory.  We avoid this

+                // by allocating and reading only a small chunk at a time, so that the

+                // malicious message must actually *be* extremely large to cause

+                // problems.  Meanwhile, we limit the allowed size of a message elsewhere.

+

+                // Remember the buffer markers since we'll have to copy the bytes out of

+                // it later.

+                int originalBufferPos = bufferPos;

+                int originalBufferSize = bufferSize;

+

+                // Mark the current buffer consumed.

+                totalBytesRetired += bufferSize;

+                bufferPos = 0;

+                bufferSize = 0;

+

+                // Read all the rest of the bytes we need.

+                int sizeLeft = size - (originalBufferSize - originalBufferPos);

+                List<byte[]> chunks = new List<byte[]>();

+

+                while (sizeLeft > 0)

+                {

+                    byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];

+                    int pos = 0;

+                    while (pos < chunk.Length)

+                    {

+                        int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);

+                        if (n <= 0)

+                        {

+                            throw InvalidProtocolBufferException.TruncatedMessage();

+                        }

+                        totalBytesRetired += n;

+                        pos += n;

+                    }

+                    sizeLeft -= chunk.Length;

+                    chunks.Add(chunk);

+                }

+

+                // OK, got everything.  Now concatenate it all into one buffer.

+                byte[] bytes = new byte[size];

+

+                // Start by copying the leftover bytes from this.buffer.

+                int newPos = originalBufferSize - originalBufferPos;

+                ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);

+

+                // And now all the chunks.

+                foreach (byte[] chunk in chunks)

+                {

+                    Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);

+                    newPos += chunk.Length;

+                }

+

+                // Done.

+                return bytes;

+            }

+        }

+

+        /// <summary>

+        /// Reads and discards <paramref name="size"/> bytes.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">the end of the stream

+        /// or the current limit was reached</exception>

+        private void SkipRawBytes(int size)

+        {

+            if (size < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+

+            if (totalBytesRetired + bufferPos + size > currentLimit)

+            {

+                // Read to the end of the stream anyway.

+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);

+                // Then fail.

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+

+            if (size <= bufferSize - bufferPos)

+            {

+                // We have all the bytes we need already.

+                bufferPos += size;

+            }

+            else

+            {

+                // Skipping more bytes than are in the buffer.  First skip what we have.

+                int pos = bufferSize - bufferPos;

+

+                // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)

+                // totalBytesRetired += pos;

+                totalBytesRetired += bufferSize;

+                

+                bufferPos = 0;

+                bufferSize = 0;

+

+                // Then skip directly from the InputStream for the rest.

+                if (pos < size)

+                {

+                    if (input == null)

+                    {

+                        throw InvalidProtocolBufferException.TruncatedMessage();

+                    }

+                    SkipImpl(size - pos);

+                    totalBytesRetired += size - pos;

+                }

+            }

+        }

+

+        /// <summary>

+        /// Abstraction of skipping to cope with streams which can't really skip.

+        /// </summary>

+        private void SkipImpl(int amountToSkip)

+        {

+            if (input.CanSeek)

+            {

+                long previousPosition = input.Position;

+                input.Position += amountToSkip;

+                if (input.Position != previousPosition + amountToSkip)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+            }

+            else

+            {

+                byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];

+                while (amountToSkip > 0)

+                {

+                    int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));

+                    if (bytesRead <= 0)

+                    {

+                        throw InvalidProtocolBufferException.TruncatedMessage();

+                    }

+                    amountToSkip -= bytesRead;

+                }

+            }

+        }

+

+        #endregion

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
new file mode 100644
index 0000000..bf221c9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
@@ -0,0 +1,304 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+

+namespace Google.Protobuf

+{

+    // This part of CodedOutputStream provides all the static entry points that are used

+    // by generated code and internally to compute the size of messages prior to being

+    // written to an instance of CodedOutputStream.

+    public sealed partial class CodedOutputStream

+    {

+        private const int LittleEndian64Size = 8;

+        private const int LittleEndian32Size = 4;        

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// double field, including the tag.

+        /// </summary>

+        public static int ComputeDoubleSize(double value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// float field, including the tag.

+        /// </summary>

+        public static int ComputeFloatSize(float value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// uint64 field, including the tag.

+        /// </summary>

+        public static int ComputeUInt64Size(ulong value)

+        {

+            return ComputeRawVarint64Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// int64 field, including the tag.

+        /// </summary>

+        public static int ComputeInt64Size(long value)

+        {

+            return ComputeRawVarint64Size((ulong) value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// int32 field, including the tag.

+        /// </summary>

+        public static int ComputeInt32Size(int value)

+        {

+            if (value >= 0)

+            {

+                return ComputeRawVarint32Size((uint) value);

+            }

+            else

+            {

+                // Must sign-extend.

+                return 10;

+            }

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// fixed64 field, including the tag.

+        /// </summary>

+        public static int ComputeFixed64Size(ulong value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// fixed32 field, including the tag.

+        /// </summary>

+        public static int ComputeFixed32Size(uint value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// bool field, including the tag.

+        /// </summary>

+        public static int ComputeBoolSize(bool value)

+        {

+            return 1;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// string field, including the tag.

+        /// </summary>

+        public static int ComputeStringSize(String value)

+        {

+            int byteArraySize = Utf8Encoding.GetByteCount(value);

+            return ComputeLengthSize(byteArraySize) + byteArraySize;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// group field, including the tag.

+        /// </summary>

+        public static int ComputeGroupSize(IMessage value)

+        {

+            return value.CalculateSize();

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// embedded message field, including the tag.

+        /// </summary>

+        public static int ComputeMessageSize(IMessage value)

+        {

+            int size = value.CalculateSize();

+            return ComputeLengthSize(size) + size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// bytes field, including the tag.

+        /// </summary>

+        public static int ComputeBytesSize(ByteString value)

+        {

+            return ComputeLengthSize(value.Length) + value.Length;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// uint32 field, including the tag.

+        /// </summary>

+        public static int ComputeUInt32Size(uint value)

+        {

+            return ComputeRawVarint32Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// enum field, including the tag. The caller is responsible for

+        /// converting the enum value to its numeric value.

+        /// </summary>

+        public static int ComputeEnumSize(int value)

+        {

+            // Currently just a pass-through, but it's nice to separate it logically.

+            return ComputeInt32Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sfixed32 field, including the tag.

+        /// </summary>

+        public static int ComputeSFixed32Size(int value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sfixed64 field, including the tag.

+        /// </summary>

+        public static int ComputeSFixed64Size(long value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sint32 field, including the tag.

+        /// </summary>

+        public static int ComputeSInt32Size(int value)

+        {

+            return ComputeRawVarint32Size(EncodeZigZag32(value));

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sint64 field, including the tag.

+        /// </summary>

+        public static int ComputeSInt64Size(long value)

+        {

+            return ComputeRawVarint64Size(EncodeZigZag64(value));

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a length,

+        /// as written by <see cref="WriteLength"/>.

+        /// </summary>

+        public static int ComputeLengthSize(int length)

+        {

+            return ComputeRawVarint32Size((uint) length);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a varint.

+        /// </summary>

+        public static int ComputeRawVarint32Size(uint value)

+        {

+            if ((value & (0xffffffff << 7)) == 0)

+            {

+                return 1;

+            }

+            if ((value & (0xffffffff << 14)) == 0)

+            {

+                return 2;

+            }

+            if ((value & (0xffffffff << 21)) == 0)

+            {

+                return 3;

+            }

+            if ((value & (0xffffffff << 28)) == 0)

+            {

+                return 4;

+            }

+            return 5;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a varint.

+        /// </summary>

+        public static int ComputeRawVarint64Size(ulong value)

+        {

+            if ((value & (0xffffffffffffffffL << 7)) == 0)

+            {

+                return 1;

+            }

+            if ((value & (0xffffffffffffffffL << 14)) == 0)

+            {

+                return 2;

+            }

+            if ((value & (0xffffffffffffffffL << 21)) == 0)

+            {

+                return 3;

+            }

+            if ((value & (0xffffffffffffffffL << 28)) == 0)

+            {

+                return 4;

+            }

+            if ((value & (0xffffffffffffffffL << 35)) == 0)

+            {

+                return 5;

+            }

+            if ((value & (0xffffffffffffffffL << 42)) == 0)

+            {

+                return 6;

+            }

+            if ((value & (0xffffffffffffffffL << 49)) == 0)

+            {

+                return 7;

+            }

+            if ((value & (0xffffffffffffffffL << 56)) == 0)

+            {

+                return 8;

+            }

+            if ((value & (0xffffffffffffffffL << 63)) == 0)

+            {

+                return 9;

+            }

+            return 10;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a tag.

+        /// </summary>

+        public static int ComputeTagSize(int fieldNumber)

+        {

+            return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs
new file mode 100644
index 0000000..6211aac
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs
@@ -0,0 +1,761 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using Google.Protobuf.Collections;

+using System;

+using System.IO;

+using System.Text;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Encodes and writes protocol message fields.

+    /// </summary>

+    /// <remarks>

+    /// <para>

+    /// This class is generally used by generated code to write appropriate

+    /// primitives to the stream. It effectively encapsulates the lowest

+    /// levels of protocol buffer format. Unlike some other implementations,

+    /// this does not include combined "write tag and value" methods. Generated

+    /// code knows the exact byte representations of the tags they're going to write,

+    /// so there's no need to re-encode them each time. Manually-written code calling

+    /// this class should just call one of the <c>WriteTag</c> overloads before each value.

+    /// </para>

+    /// <para>

+    /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>

+    /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.

+    /// </para>

+    /// </remarks>

+    public sealed partial class CodedOutputStream : IDisposable

+    {

+        // "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)

+        internal static readonly Encoding Utf8Encoding = Encoding.UTF8;

+

+        /// <summary>

+        /// The buffer size used by CreateInstance(Stream).

+        /// </summary>

+        public static readonly int DefaultBufferSize = 4096;

+

+        private readonly bool leaveOpen;

+        private readonly byte[] buffer;

+        private readonly int limit;

+        private int position;

+        private readonly Stream output;

+

+        #region Construction

+        /// <summary>

+        /// Creates a new CodedOutputStream that writes directly to the given

+        /// byte array. If more bytes are written than fit in the array,

+        /// OutOfSpaceException will be thrown.

+        /// </summary>

+        public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream that writes directly to the given

+        /// byte array slice. If more bytes are written than fit in the array,

+        /// OutOfSpaceException will be thrown.

+        /// </summary>

+        private CodedOutputStream(byte[] buffer, int offset, int length)

+        {

+            this.output = null;

+            this.buffer = buffer;

+            this.position = offset;

+            this.limit = offset + length;

+            leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference

+        }

+

+        private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)

+        {

+            this.output = ProtoPreconditions.CheckNotNull(output, nameof(output));

+            this.buffer = buffer;

+            this.position = 0;

+            this.limit = buffer.Length;

+            this.leaveOpen = leaveOpen;

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="CodedOutputStream" /> which write to the given stream, and disposes of that

+        /// stream when the returned <c>CodedOutputStream</c> is disposed.

+        /// </summary>

+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>

+        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream and uses

+        /// the specified buffer size.

+        /// </summary>

+        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>

+        /// <param name="bufferSize">The size of buffer to use internally.</param>

+        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream.

+        /// </summary>

+        /// <param name="output">The stream to write to.</param>

+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;

+        /// if <c>false</c>, the provided stream is disposed as well.</param>

+        public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream and uses

+        /// the specified buffer size.

+        /// </summary>

+        /// <param name="output">The stream to write to.</param>

+        /// <param name="bufferSize">The size of buffer to use internally.</param>

+        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;

+        /// if <c>false</c>, the provided stream is disposed as well.</param>

+        public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen)

+        {

+        }

+        #endregion

+

+        /// <summary>

+        /// Returns the current position in the stream, or the position in the output buffer

+        /// </summary>

+        public long Position

+        {

+            get

+            {

+                if (output != null)

+                {

+                    return output.Position + position;

+                }

+                return position;

+            }

+        }

+

+        #region Writing of values (not including tags)

+

+        /// <summary>

+        /// Writes a double field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteDouble(double value)

+        {

+            WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));

+        }

+

+        /// <summary>

+        /// Writes a float field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFloat(float value)

+        {

+            byte[] rawBytes = BitConverter.GetBytes(value);

+            if (!BitConverter.IsLittleEndian)

+            {

+                ByteArray.Reverse(rawBytes);

+            }

+

+            if (limit - position >= 4)

+            {

+                buffer[position++] = rawBytes[0];

+                buffer[position++] = rawBytes[1];

+                buffer[position++] = rawBytes[2];

+                buffer[position++] = rawBytes[3];

+            }

+            else

+            {

+                WriteRawBytes(rawBytes, 0, 4);

+            }

+        }

+

+        /// <summary>

+        /// Writes a uint64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteUInt64(ulong value)

+        {

+            WriteRawVarint64(value);

+        }

+

+        /// <summary>

+        /// Writes an int64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteInt64(long value)

+        {

+            WriteRawVarint64((ulong) value);

+        }

+

+        /// <summary>

+        /// Writes an int32 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteInt32(int value)

+        {

+            if (value >= 0)

+            {

+                WriteRawVarint32((uint) value);

+            }

+            else

+            {

+                // Must sign-extend.

+                WriteRawVarint64((ulong) value);

+            }

+        }

+

+        /// <summary>

+        /// Writes a fixed64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFixed64(ulong value)

+        {

+            WriteRawLittleEndian64(value);

+        }

+

+        /// <summary>

+        /// Writes a fixed32 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFixed32(uint value)

+        {

+            WriteRawLittleEndian32(value);

+        }

+

+        /// <summary>

+        /// Writes a bool field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteBool(bool value)

+        {

+            WriteRawByte(value ? (byte) 1 : (byte) 0);

+        }

+

+        /// <summary>

+        /// Writes a string field value, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteString(string value)

+        {

+            // Optimise the case where we have enough space to write

+            // the string directly to the buffer, which should be common.

+            int length = Utf8Encoding.GetByteCount(value);

+            WriteLength(length);

+            if (limit - position >= length)

+            {

+                if (length == value.Length) // Must be all ASCII...

+                {

+                    for (int i = 0; i < length; i++)

+                    {

+                        buffer[position + i] = (byte)value[i];

+                    }

+                }

+                else

+                {

+                    Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);

+                }

+                position += length;

+            }

+            else

+            {

+                byte[] bytes = Utf8Encoding.GetBytes(value);

+                WriteRawBytes(bytes);

+            }

+        }

+

+        /// <summary>

+        /// Writes a message, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteMessage(IMessage value)

+        {

+            WriteLength(value.CalculateSize());

+            value.WriteTo(this);

+        }

+

+        /// <summary>

+        /// Write a byte string, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteBytes(ByteString value)

+        {

+            WriteLength(value.Length);

+            value.WriteRawBytesTo(this);

+        }

+

+        /// <summary>

+        /// Writes a uint32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteUInt32(uint value)

+        {

+            WriteRawVarint32(value);

+        }

+

+        /// <summary>

+        /// Writes an enum value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteEnum(int value)

+        {

+            WriteInt32(value);

+        }

+

+        /// <summary>

+        /// Writes an sfixed32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write.</param>

+        public void WriteSFixed32(int value)

+        {

+            WriteRawLittleEndian32((uint) value);

+        }

+

+        /// <summary>

+        /// Writes an sfixed64 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSFixed64(long value)

+        {

+            WriteRawLittleEndian64((ulong) value);

+        }

+

+        /// <summary>

+        /// Writes an sint32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSInt32(int value)

+        {

+            WriteRawVarint32(EncodeZigZag32(value));

+        }

+

+        /// <summary>

+        /// Writes an sint64 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSInt64(long value)

+        {

+            WriteRawVarint64(EncodeZigZag64(value));

+        }

+

+        /// <summary>

+        /// Writes a length (in bytes) for length-delimited data.

+        /// </summary>

+        /// <remarks>

+        /// This method simply writes a rawint, but exists for clarity in calling code.

+        /// </remarks>

+        /// <param name="length">Length value, in bytes.</param>

+        public void WriteLength(int length)

+        {

+            WriteRawVarint32((uint) length);

+        }

+

+        #endregion

+

+        #region Raw tag writing

+        /// <summary>

+        /// Encodes and writes a tag.

+        /// </summary>

+        /// <param name="fieldNumber">The number of the field to write the tag for</param>

+        /// <param name="type">The wire format type of the tag to write</param>

+        public void WriteTag(int fieldNumber, WireFormat.WireType type)

+        {

+            WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));

+        }

+

+        /// <summary>

+        /// Writes an already-encoded tag.

+        /// </summary>

+        /// <param name="tag">The encoded tag</param>

+        public void WriteTag(uint tag)

+        {

+            WriteRawVarint32(tag);

+        }

+

+        /// <summary>

+        /// Writes the given single-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The encoded tag</param>

+        public void WriteRawTag(byte b1)

+        {

+            WriteRawByte(b1);

+        }

+

+        /// <summary>

+        /// Writes the given two-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+        }

+

+        /// <summary>

+        /// Writes the given three-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+        }

+

+        /// <summary>

+        /// Writes the given four-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        /// <param name="b4">The fourth byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+            WriteRawByte(b4);

+        }

+

+        /// <summary>

+        /// Writes the given five-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        /// <param name="b4">The fourth byte of the encoded tag</param>

+        /// <param name="b5">The fifth byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+            WriteRawByte(b4);

+            WriteRawByte(b5);

+        }

+        #endregion

+

+        #region Underlying writing primitives

+        /// <summary>

+        /// Writes a 32 bit value as a varint. The fast route is taken when

+        /// there's enough buffer space left to whizz through without checking

+        /// for each byte; otherwise, we resort to calling WriteRawByte each time.

+        /// </summary>

+        internal void WriteRawVarint32(uint value)

+        {

+            // Optimize for the common case of a single byte value

+            if (value < 128 && position < limit)

+            {

+                buffer[position++] = (byte)value;

+                return;

+            }

+

+            while (value > 127 && position < limit)

+            {

+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);

+                value >>= 7;

+            }

+            while (value > 127)

+            {

+                WriteRawByte((byte) ((value & 0x7F) | 0x80));

+                value >>= 7;

+            }

+            if (position < limit)

+            {

+                buffer[position++] = (byte) value;

+            }

+            else

+            {

+                WriteRawByte((byte) value);

+            }

+        }

+

+        internal void WriteRawVarint64(ulong value)

+        {

+            while (value > 127 && position < limit)

+            {

+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);

+                value >>= 7;

+            }

+            while (value > 127)

+            {

+                WriteRawByte((byte) ((value & 0x7F) | 0x80));

+                value >>= 7;

+            }

+            if (position < limit)

+            {

+                buffer[position++] = (byte) value;

+            }

+            else

+            {

+                WriteRawByte((byte) value);

+            }

+        }

+

+        internal void WriteRawLittleEndian32(uint value)

+        {

+            if (position + 4 > limit)

+            {

+                WriteRawByte((byte) value);

+                WriteRawByte((byte) (value >> 8));

+                WriteRawByte((byte) (value >> 16));

+                WriteRawByte((byte) (value >> 24));

+            }

+            else

+            {

+                buffer[position++] = ((byte) value);

+                buffer[position++] = ((byte) (value >> 8));

+                buffer[position++] = ((byte) (value >> 16));

+                buffer[position++] = ((byte) (value >> 24));

+            }

+        }

+

+        internal void WriteRawLittleEndian64(ulong value)

+        {

+            if (position + 8 > limit)

+            {

+                WriteRawByte((byte) value);

+                WriteRawByte((byte) (value >> 8));

+                WriteRawByte((byte) (value >> 16));

+                WriteRawByte((byte) (value >> 24));

+                WriteRawByte((byte) (value >> 32));

+                WriteRawByte((byte) (value >> 40));

+                WriteRawByte((byte) (value >> 48));

+                WriteRawByte((byte) (value >> 56));

+            }

+            else

+            {

+                buffer[position++] = ((byte) value);

+                buffer[position++] = ((byte) (value >> 8));

+                buffer[position++] = ((byte) (value >> 16));

+                buffer[position++] = ((byte) (value >> 24));

+                buffer[position++] = ((byte) (value >> 32));

+                buffer[position++] = ((byte) (value >> 40));

+                buffer[position++] = ((byte) (value >> 48));

+                buffer[position++] = ((byte) (value >> 56));

+            }

+        }

+

+        internal void WriteRawByte(byte value)

+        {

+            if (position == limit)

+            {

+                RefreshBuffer();

+            }

+

+            buffer[position++] = value;

+        }

+

+        internal void WriteRawByte(uint value)

+        {

+            WriteRawByte((byte) value);

+        }

+

+        /// <summary>

+        /// Writes out an array of bytes.

+        /// </summary>

+        internal void WriteRawBytes(byte[] value)

+        {

+            WriteRawBytes(value, 0, value.Length);

+        }

+

+        /// <summary>

+        /// Writes out part of an array of bytes.

+        /// </summary>

+        internal void WriteRawBytes(byte[] value, int offset, int length)

+        {

+            if (limit - position >= length)

+            {

+                ByteArray.Copy(value, offset, buffer, position, length);

+                // We have room in the current buffer.

+                position += length;

+            }

+            else

+            {

+                // Write extends past current buffer.  Fill the rest of this buffer and

+                // flush.

+                int bytesWritten = limit - position;

+                ByteArray.Copy(value, offset, buffer, position, bytesWritten);

+                offset += bytesWritten;

+                length -= bytesWritten;

+                position = limit;

+                RefreshBuffer();

+

+                // Now deal with the rest.

+                // Since we have an output stream, this is our buffer

+                // and buffer offset == 0

+                if (length <= limit)

+                {

+                    // Fits in new buffer.

+                    ByteArray.Copy(value, offset, buffer, 0, length);

+                    position = length;

+                }

+                else

+                {

+                    // Write is very big.  Let's do it all at once.

+                    output.Write(value, offset, length);

+                }

+            }

+        }

+

+        #endregion

+

+        /// <summary>

+        /// Encode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static uint EncodeZigZag32(int n)

+        {

+            // Note:  the right-shift must be arithmetic

+            return (uint) ((n << 1) ^ (n >> 31));

+        }

+

+        /// <summary>

+        /// Encode a 64-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static ulong EncodeZigZag64(long n)

+        {

+            return (ulong) ((n << 1) ^ (n >> 63));

+        }

+

+        private void RefreshBuffer()

+        {

+            if (output == null)

+            {

+                // We're writing to a single buffer.

+                throw new OutOfSpaceException();

+            }

+

+            // Since we have an output stream, this is our buffer

+            // and buffer offset == 0

+            output.Write(buffer, 0, position);

+            position = 0;

+        }

+

+        /// <summary>

+        /// Indicates that a CodedOutputStream wrapping a flat byte array

+        /// ran out of space.

+        /// </summary>

+        public sealed class OutOfSpaceException : IOException

+        {

+            internal OutOfSpaceException()

+                : base("CodedOutputStream was writing to a flat byte array and ran out of space.")

+            {

+            }

+        }

+

+        /// <summary>

+        /// Flushes any buffered data and optionally closes the underlying stream, if any.

+        /// </summary>

+        /// <remarks>

+        /// <para>

+        /// By default, any underlying stream is closed by this method. To configure this behaviour,

+        /// use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not

+        /// have an underlying stream, this method does nothing.

+        /// </para>

+        /// <para>

+        /// For the sake of efficiency, calling this method does not prevent future write calls - but

+        /// if a later write ends up writing to a stream which has been disposed, that is likely to

+        /// fail. It is recommend that you not call any other methods after this.

+        /// </para>

+        /// </remarks>

+        public void Dispose()

+        {

+            Flush();

+            if (!leaveOpen)

+            {

+                output.Dispose();

+            }

+        }

+

+        /// <summary>

+        /// Flushes any buffered data to the underlying stream (if there is one).

+        /// </summary>

+        public void Flush()

+        {

+            if (output != null)

+            {

+                RefreshBuffer();

+            }

+        }

+

+        /// <summary>

+        /// Verifies that SpaceLeft returns zero. It's common to create a byte array

+        /// that is exactly big enough to hold a message, then write to it with

+        /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that

+        /// the message was actually as big as expected, which can help bugs.

+        /// </summary>

+        public void CheckNoSpaceLeft()

+        {

+            if (SpaceLeft != 0)

+            {

+                throw new InvalidOperationException("Did not write as much data as expected.");

+            }

+        }

+

+        /// <summary>

+        /// If writing to a flat array, returns the space left in the array. Otherwise,

+        /// throws an InvalidOperationException.

+        /// </summary>

+        public int SpaceLeft

+        {

+            get

+            {

+                if (output == null)

+                {

+                    return limit - position;

+                }

+                else

+                {

+                    throw new InvalidOperationException(

+                        "SpaceLeft can only be called on CodedOutputStreams that are " +

+                        "writing to a flat array.");

+                }

+            }

+        }

+    }

+}

diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
new file mode 100644
index 0000000..993a89d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -0,0 +1,760 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// Representation of a map field in a Protocol Buffer message.
+    /// </summary>
+    /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
+    /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
+    /// <remarks>
+    /// <para>
+    /// This implementation preserves insertion order for simplicity of testing
+    /// code using maps fields. Overwriting an existing entry does not change the
+    /// position of that entry within the map. Equality is not order-sensitive.
+    /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
+    /// </para>
+    /// <para>
+    /// Null values are not permitted in the map, either for wrapper types or regular messages.
+    /// If a map is deserialized from a data stream and the value is missing from an entry, a default value
+    /// is created instead. For primitive types, that is the regular default value (0, the empty string and so
+    /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
+    /// encoded value for the field.
+    /// </para>
+    /// <para>
+    /// This implementation does not generally prohibit the use of key/value types which are not
+    /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
+    /// that all operations will work in such cases.
+    /// </para>
+    /// </remarks>
+    public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
+    {
+        // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
+        private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
+            new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
+        private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
+
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>
+        /// A deep clone of this object.
+        /// </returns>
+        public MapField<TKey, TValue> Clone()
+        {
+            var clone = new MapField<TKey, TValue>();
+            // Keys are never cloneable. Values might be.
+            if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
+            {
+                foreach (var pair in list)
+                {
+                    clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
+                }
+            }
+            else
+            {
+                // Nothing is cloneable, so we don't need to worry.
+                clone.Add(this);
+            }
+            return clone;
+        }
+
+        /// <summary>
+        /// Adds the specified key/value pair to the map.
+        /// </summary>
+        /// <remarks>
+        /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
+        /// </remarks>
+        /// <param name="key">The key to add</param>
+        /// <param name="value">The value to add.</param>
+        /// <exception cref="System.ArgumentException">The given key already exists in map.</exception>
+        public void Add(TKey key, TValue value)
+        {
+            // Validation of arguments happens in ContainsKey and the indexer
+            if (ContainsKey(key))
+            {
+                throw new ArgumentException("Key already exists in map", "key");
+            }
+            this[key] = value;
+        }
+
+        /// <summary>
+        /// Determines whether the specified key is present in the map.
+        /// </summary>
+        /// <param name="key">The key to check.</param>
+        /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
+        public bool ContainsKey(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            return map.ContainsKey(key);
+        }
+
+        private bool ContainsValue(TValue value)
+        {
+            var comparer = EqualityComparer<TValue>.Default;
+            return list.Any(pair => comparer.Equals(pair.Value, value));
+        }
+
+        /// <summary>
+        /// Removes the entry identified by the given key from the map.
+        /// </summary>
+        /// <param name="key">The key indicating the entry to remove from the map.</param>
+        /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
+        public bool Remove(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                map.Remove(key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key whose value to get.</param>
+        /// <param name="value">When this method returns, the value associated with the specified key, if the key is found;
+        /// otherwise, the default value for the type of the <paramref name="value"/> parameter.
+        /// This parameter is passed uninitialized.</param>
+        /// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
+        public bool TryGetValue(TKey key, out TValue value)
+        {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                value = node.Value.Value;
+                return true;
+            }
+            else
+            {
+                value = default(TValue);
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key of the value to get or set.</param>
+        /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
+        /// <returns>The value associated with the specified key. If the specified key is not found,
+        /// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
+        public TValue this[TKey key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                TValue value;
+                if (TryGetValue(key, out value))
+                {
+                    return value;
+                }
+                throw new KeyNotFoundException();
+            }
+            set
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                // value == null check here is redundant, but avoids boxing.
+                if (value == null)
+                {
+                    ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
+                }
+                LinkedListNode<KeyValuePair<TKey, TValue>> node;
+                var pair = new KeyValuePair<TKey, TValue>(key, value);
+                if (map.TryGetValue(key, out node))
+                {
+                    node.Value = pair;
+                }
+                else
+                {
+                    node = list.AddLast(pair);
+                    map[key] = node;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a collection containing the keys in the map.
+        /// </summary>
+        public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
+
+        /// <summary>
+        /// Gets a collection containing the values in the map.
+        /// </summary>
+        public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
+
+        /// <summary>
+        /// Adds the specified entries to the map. The keys and values are not automatically cloned.
+        /// </summary>
+        /// <param name="entries">The entries to add to the map.</param>
+        public void Add(IDictionary<TKey, TValue> entries)
+        {
+            ProtoPreconditions.CheckNotNull(entries, "entries");
+            foreach (var pair in entries)
+            {
+                Add(pair.Key, pair.Value);
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            return list.GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Adds the specified item to the map.
+        /// </summary>
+        /// <param name="item">The item to add to the map.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+        {
+            Add(item.Key, item.Value);
+        }
+
+        /// <summary>
+        /// Removes all items from the map.
+        /// </summary>
+        public void Clear()
+        {
+            list.Clear();
+            map.Clear();
+        }
+
+        /// <summary>
+        /// Determines whether map contains an entry equivalent to the given key/value pair.
+        /// </summary>
+        /// <param name="item">The key/value pair to find.</param>
+        /// <returns></returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+        {
+            TValue value;
+            return TryGetValue(item.Key, out value)
+                && EqualityComparer<TValue>.Default.Equals(item.Value, value);
+        }
+
+        /// <summary>
+        /// Copies the key/value pairs in this map to an array.
+        /// </summary>
+        /// <param name="array">The array to copy the entries into.</param>
+        /// <param name="arrayIndex">The index of the array at which to start copying values.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+        {
+            list.CopyTo(array, arrayIndex);
+        }
+
+        /// <summary>
+        /// Removes the specified key/value pair from the map.
+        /// </summary>
+        /// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
+        /// <param name="item">The key/value pair to remove.</param>
+        /// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+        {
+            if (item.Key == null)
+            {
+                throw new ArgumentException("Key is null", "item");
+            }
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(item.Key, out node) &&
+                EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
+            {
+                map.Remove(item.Key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the map.
+        /// </summary>
+        public int Count { get { return list.Count; } }
+
+        /// <summary>
+        /// Gets a value indicating whether the map is read-only.
+        /// </summary>
+        public bool IsReadOnly { get { return false; } }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object other)
+        {
+            return Equals(other as MapField<TKey, TValue>);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            var valueComparer = EqualityComparer<TValue>.Default;
+            int hash = 0;
+            foreach (var pair in list)
+            {
+                hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value);
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this map with another for equality.
+        /// </summary>
+        /// <remarks>
+        /// The order of the key/value pairs in the maps is not deemed significant in this comparison.
+        /// </remarks>
+        /// <param name="other">The map to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
+        public bool Equals(MapField<TKey, TValue> other)
+        {
+            if (other == null)
+            {
+                return false;
+            }
+            if (other == this)
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            var valueComparer = EqualityComparer<TValue>.Default;
+            foreach (var pair in this)
+            {
+                TValue value;
+                if (!other.TryGetValue(pair.Key, out value))
+                {
+                    return false;
+                }
+                if (!valueComparer.Equals(value, pair.Value))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Adds entries to the map from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// It is assumed that the stream is initially positioned after the tag specified by the codec.
+        /// This method will continue reading entries from the stream until the end is reached, or
+        /// a different tag is encountered.
+        /// </remarks>
+        /// <param name="input">Stream to read from</param>
+        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>
+        public void AddEntriesFrom(CodedInputStream input, Codec codec)
+        {
+            var adapter = new Codec.MessageAdapter(codec);
+            do
+            {
+                adapter.Reset();
+                input.ReadMessage(adapter);
+                this[adapter.Key] = adapter.Value;
+            } while (input.MaybeConsumeTag(codec.MapTag));
+        }
+
+        /// <summary>
+        /// Writes the contents of this map to the given coded output stream, using the specified codec
+        /// to encode each entry.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use for each entry.</param>
+        public void WriteTo(CodedOutputStream output, Codec codec)
+        {
+            var message = new Codec.MessageAdapter(codec);
+            foreach (var entry in list)
+            {
+                message.Key = entry.Key;
+                message.Value = entry.Value;
+                output.WriteTag(codec.MapTag);
+                output.WriteMessage(message);
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this map based on the given entry codec.
+        /// </summary>
+        /// <param name="codec">The codec to use to encode each entry.</param>
+        /// <returns></returns>
+        public int CalculateSize(Codec codec)
+        {
+            if (Count == 0)
+            {
+                return 0;
+            }
+            var message = new Codec.MessageAdapter(codec);
+            int size = 0;
+            foreach (var entry in list)
+            {
+                message.Key = entry.Key;
+                message.Value = entry.Value;
+                size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
+                size += CodedOutputStream.ComputeMessageSize(message);
+            }
+            return size;
+        }
+
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var writer = new StringWriter();
+            JsonFormatter.Default.WriteDictionary(writer, this);
+            return writer.ToString();
+        }
+
+        #region IDictionary explicit interface implementation
+        void IDictionary.Add(object key, object value)
+        {
+            Add((TKey)key, (TValue)value);
+        }
+
+        bool IDictionary.Contains(object key)
+        {
+            if (!(key is TKey))
+            {
+                return false;
+            }
+            return ContainsKey((TKey)key);
+        }
+
+        IDictionaryEnumerator IDictionary.GetEnumerator()
+        {
+            return new DictionaryEnumerator(GetEnumerator());
+        }
+
+        void IDictionary.Remove(object key)
+        {
+            ProtoPreconditions.CheckNotNull(key, "key");
+            if (!(key is TKey))
+            {
+                return;
+            }
+            Remove((TKey)key);
+        }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            // This is ugly and slow as heck, but with any luck it will never be used anyway.
+            ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
+            temp.CopyTo(array, index);
+        }
+
+        bool IDictionary.IsFixedSize { get { return false; } }
+
+        ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
+
+        ICollection IDictionary.Values { get { return (ICollection)Values; } }
+
+        bool ICollection.IsSynchronized { get { return false; } }
+
+        object ICollection.SyncRoot { get { return this; } }
+
+        object IDictionary.this[object key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNull(key, "key");
+                if (!(key is TKey))
+                {
+                    return null;
+                }
+                TValue value;
+                TryGetValue((TKey)key, out value);
+                return value;
+            }
+
+            set
+            {
+                this[(TKey)key] = (TValue)value;
+            }
+        }
+        #endregion
+
+        private class DictionaryEnumerator : IDictionaryEnumerator
+        {
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
+
+            internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
+            {
+                this.enumerator = enumerator;
+            }
+
+            public bool MoveNext()
+            {
+                return enumerator.MoveNext();
+            }
+
+            public void Reset()
+            {
+                enumerator.Reset();
+            }
+
+            public object Current { get { return Entry; } }
+            public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
+            public object Key { get { return enumerator.Current.Key; } }
+            public object Value { get { return enumerator.Current.Value; } }
+        }
+
+        /// <summary>
+        /// A codec for a specific map field. This contains all the information required to encode and
+        /// decode the nested messages.
+        /// </summary>
+        public sealed class Codec
+        {
+            private readonly FieldCodec<TKey> keyCodec;
+            private readonly FieldCodec<TValue> valueCodec;
+            private readonly uint mapTag;
+
+            /// <summary>
+            /// Creates a new entry codec based on a separate key codec and value codec,
+            /// and the tag to use for each map entry.
+            /// </summary>
+            /// <param name="keyCodec">The key codec.</param>
+            /// <param name="valueCodec">The value codec.</param>
+            /// <param name="mapTag">The map tag to use to introduce each map entry.</param>
+            public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
+            {
+                this.keyCodec = keyCodec;
+                this.valueCodec = valueCodec;
+                this.mapTag = mapTag;
+            }
+
+            /// <summary>
+            /// The tag used in the enclosing message to indicate map entries.
+            /// </summary>
+            internal uint MapTag { get { return mapTag; } }
+
+            /// <summary>
+            /// A mutable message class, used for parsing and serializing. This
+            /// delegates the work to a codec, but implements the <see cref="IMessage"/> interface
+            /// for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
+            /// This is nested inside Codec as it's tightly coupled to the associated codec,
+            /// and it's simpler if it has direct access to all its fields.
+            /// </summary>
+            internal class MessageAdapter : IMessage
+            {
+                private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
+
+                private readonly Codec codec;
+                internal TKey Key { get; set; }
+                internal TValue Value { get; set; }
+
+                internal MessageAdapter(Codec codec)
+                {
+                    this.codec = codec;
+                }
+
+                internal void Reset()
+                {
+                    Key = codec.keyCodec.DefaultValue;
+                    Value = codec.valueCodec.DefaultValue;
+                }
+
+                public void MergeFrom(CodedInputStream input)
+                {
+                    uint tag;
+                    while ((tag = input.ReadTag()) != 0)
+                    {
+                        if (tag == codec.keyCodec.Tag)
+                        {
+                            Key = codec.keyCodec.Read(input);
+                        }
+                        else if (tag == codec.valueCodec.Tag)
+                        {
+                            Value = codec.valueCodec.Read(input);
+                        }
+                        else 
+                        {
+                            input.SkipLastField();
+                        }
+                    }
+
+                    // Corner case: a map entry with a key but no value, where the value type is a message.
+                    // Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
+                    if (Value == null)
+                    {
+                        Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
+                    }
+                }
+
+                public void WriteTo(CodedOutputStream output)
+                {
+                    codec.keyCodec.WriteTagAndValue(output, Key);
+                    codec.valueCodec.WriteTagAndValue(output, Value);
+                }
+
+                public int CalculateSize()
+                {
+                    return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value);
+                }
+
+                MessageDescriptor IMessage.Descriptor { get { return null; } }
+            }
+        }
+
+        private class MapView<T> : ICollection<T>, ICollection
+        {
+            private readonly MapField<TKey, TValue> parent;
+            private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
+            private readonly Func<T, bool> containsCheck;
+
+            internal MapView(
+                MapField<TKey, TValue> parent,
+                Func<KeyValuePair<TKey, TValue>, T> projection,
+                Func<T, bool> containsCheck)
+            {
+                this.parent = parent;
+                this.projection = projection;
+                this.containsCheck = containsCheck;
+            }
+
+            public int Count { get { return parent.Count; } }
+
+            public bool IsReadOnly { get { return true; } }
+
+            public bool IsSynchronized { get { return false; } }
+
+            public object SyncRoot { get { return parent; } }
+
+            public void Add(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            public void Clear()
+            {
+                throw new NotSupportedException();
+            }
+
+            public bool Contains(T item)
+            {
+                return containsCheck(item);
+            }
+
+            public void CopyTo(T[] array, int arrayIndex)
+            {
+                if (arrayIndex < 0)
+                {
+                    throw new ArgumentOutOfRangeException("arrayIndex");
+                }
+                if (arrayIndex + Count  >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array[arrayIndex++] = item;
+                }
+            }
+
+            public IEnumerator<T> GetEnumerator()
+            {
+                return parent.list.Select(projection).GetEnumerator();
+            }
+
+            public bool Remove(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
+            }
+
+            public void CopyTo(Array array, int index)
+            {
+                if (index < 0)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                if (index + Count >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array.SetValue(item, index++);
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
new file mode 100644
index 0000000..8436066
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
@@ -0,0 +1,147 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.Collections;

+using System.Collections.Generic;

+

+namespace Google.Protobuf.Collections

+{

+    /// <summary>

+    /// Read-only wrapper around another dictionary.

+    /// </summary>

+    internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>

+    {

+        private readonly IDictionary<TKey, TValue> wrapped;

+

+        public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped)

+        {

+            this.wrapped = wrapped;

+        }

+

+        public void Add(TKey key, TValue value)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool ContainsKey(TKey key)

+        {

+            return wrapped.ContainsKey(key);

+        }

+

+        public ICollection<TKey> Keys

+        {

+            get { return wrapped.Keys; }

+        }

+

+        public bool Remove(TKey key)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool TryGetValue(TKey key, out TValue value)

+        {

+            return wrapped.TryGetValue(key, out value);

+        }

+

+        public ICollection<TValue> Values

+        {

+            get { return wrapped.Values; }

+        }

+

+        public TValue this[TKey key]

+        {

+            get { return wrapped[key]; }

+            set { throw new InvalidOperationException(); }

+        }

+

+        public void Add(KeyValuePair<TKey, TValue> item)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public void Clear()

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool Contains(KeyValuePair<TKey, TValue> item)

+        {

+            return wrapped.Contains(item);

+        }

+

+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)

+        {

+            wrapped.CopyTo(array, arrayIndex);

+        }

+

+        public int Count

+        {

+            get { return wrapped.Count; }

+        }

+

+        public bool IsReadOnly

+        {

+            get { return true; }

+        }

+

+        public bool Remove(KeyValuePair<TKey, TValue> item)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()

+        {

+            return wrapped.GetEnumerator();

+        }

+

+        IEnumerator IEnumerable.GetEnumerator()

+        {

+            return ((IEnumerable) wrapped).GetEnumerator();

+        }

+

+        public override bool Equals(object obj)

+        {

+            return wrapped.Equals(obj);

+        }

+

+        public override int GetHashCode()

+        {

+            return wrapped.GetHashCode();

+        }

+

+        public override string ToString()

+        {

+            return wrapped.ToString();

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
new file mode 100644
index 0000000..d1db856
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -0,0 +1,568 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// The contents of a repeated field: essentially, a collection with some extra
+    /// restrictions (no null values) and capabilities (deep cloning).
+    /// </summary>
+    /// <remarks>
+    /// This implementation does not generally prohibit the use of types which are not
+    /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
+    /// </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>>
+    {
+        private static readonly T[] EmptyArray = new T[0];
+        private const int MinArraySize = 8;
+
+        private T[] array = EmptyArray;
+        private int count = 0;
+
+        /// <summary>
+        /// Creates a deep clone of this repeated field.
+        /// </summary>
+        /// <remarks>
+        /// If the field type is
+        /// a message type, each element is also cloned; otherwise, it is
+        /// assumed that the field type is primitive (including string and
+        /// bytes, both of which are immutable) and so a simple copy is
+        /// equivalent to a deep clone.
+        /// </remarks>
+        /// <returns>A deep clone of this repeated field.</returns>
+        public RepeatedField<T> Clone()
+        {
+            RepeatedField<T> clone = new RepeatedField<T>();
+            if (array != EmptyArray)
+            {
+                clone.array = (T[])array.Clone();
+                IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
+                if (cloneableArray != null)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        clone.array[i] = cloneableArray[i].Clone();
+                    }
+                }
+            }
+            clone.count = count;
+            return clone;
+        }
+
+        /// <summary>
+        /// Adds the entries from the given input stream, decoding them with the specified codec.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <param name="codec">The codec to use in order to read each entry.</param>
+        public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
+        {
+            // TODO: Inline some of the Add code, so we can avoid checking the size on every
+            // iteration.
+            uint tag = input.LastTag;
+            var reader = codec.ValueReader;
+            // Non-nullable value types can be packed or not.
+            if (FieldCodec<T>.IsPackedRepeatedField(tag))
+            {
+                int length = input.ReadLength();
+                if (length > 0)
+                {
+                    int oldLimit = input.PushLimit(length);
+                    while (!input.ReachedLimit)
+                    {
+                        Add(reader(input));
+                    }
+                    input.PopLimit(oldLimit);
+                }
+                // Empty packed field. Odd, but valid - just ignore.
+            }
+            else
+            {
+                // Not packed... (possibly not packable)
+                do
+                {
+                    Add(reader(input));
+                } while (input.MaybeConsumeTag(tag));
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this collection based on the given codec.
+        /// </summary>
+        /// <param name="codec">The codec to use when encoding each field.</param>
+        /// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
+        /// using the same codec.</returns>
+        public int CalculateSize(FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return 0;
+            }
+            uint tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                int dataSize = CalculatePackedDataSize(codec);
+                return CodedOutputStream.ComputeRawVarint32Size(tag) +
+                    CodedOutputStream.ComputeLengthSize(dataSize) +
+                    dataSize;
+            }
+            else
+            {
+                var sizeCalculator = codec.ValueSizeCalculator;
+                int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
+                for (int i = 0; i < count; i++)
+                {
+                    size += sizeCalculator(array[i]);
+                }
+                return size;
+            }
+        }
+
+        private int CalculatePackedDataSize(FieldCodec<T> codec)
+        {
+            int fixedSize = codec.FixedSize;
+            if (fixedSize == 0)
+            {
+                var calculator = codec.ValueSizeCalculator;
+                int tmp = 0;
+                for (int i = 0; i < count; i++)
+                {
+                    tmp += calculator(array[i]);
+                }
+                return tmp;
+            }
+            else
+            {
+                return fixedSize * Count;
+            }
+        }
+
+        /// <summary>
+        /// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
+        /// encoding each value using the specified codec.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use when encoding each value.</param>
+        public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return;
+            }
+            var writer = codec.ValueWriter;
+            var tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                // Packed primitive type
+                uint size = (uint)CalculatePackedDataSize(codec);
+                output.WriteTag(tag);
+                output.WriteRawVarint32(size);
+                for (int i = 0; i < count; i++)
+                {
+                    writer(output, array[i]);
+                }
+            }
+            else
+            {
+                // Not packed: a simple tag/value pair for each value.
+                // Can't use codec.WriteTagAndValue, as that omits default values.
+                for (int i = 0; i < count; i++)
+                {
+                    output.WriteTag(tag);
+                    writer(output, array[i]);
+                }
+            }
+        }
+
+        private void EnsureSize(int size)
+        {
+            if (array.Length < size)
+            {
+                size = Math.Max(size, MinArraySize);
+                int newSize = Math.Max(array.Length * 2, size);
+                var tmp = new T[newSize];
+                Array.Copy(array, 0, tmp, 0, array.Length);
+                array = tmp;
+            }
+        }
+
+        /// <summary>
+        /// Adds the specified item to the collection.
+        /// </summary>
+        /// <param name="item">The item to add.</param>
+        public void Add(T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            EnsureSize(count + 1);
+            array[count++] = item;
+        }
+
+        /// <summary>
+        /// Removes all items from the collection.
+        /// </summary>
+        public void Clear()
+        {
+            array = EmptyArray;
+            count = 0;
+        }
+
+        /// <summary>
+        /// Determines whether this collection contains the given item.
+        /// </summary>
+        /// <param name="item">The item to find.</param>
+        /// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
+        public bool Contains(T item)
+        {
+            return IndexOf(item) != -1;
+        }
+
+        /// <summary>
+        /// Copies this collection to the given array.
+        /// </summary>
+        /// <param name="array">The array to copy to.</param>
+        /// <param name="arrayIndex">The first index of the array to copy to.</param>
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            Array.Copy(this.array, 0, array, arrayIndex, count);
+        }
+
+        /// <summary>
+        /// Removes the specified item from the collection
+        /// </summary>
+        /// <param name="item">The item to remove.</param>
+        /// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
+        public bool Remove(T item)
+        {
+            int index = IndexOf(item);
+            if (index == -1)
+            {
+                return false;
+            }            
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the collection.
+        /// </summary>
+        public int Count { get { return count; } }
+
+        /// <summary>
+        /// Gets a value indicating whether the collection is read-only.
+        /// </summary>
+        public bool IsReadOnly { get { return false; } }
+
+        // TODO: Remove this overload and just handle it in the one below, at execution time?
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(RepeatedField<T> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException("values");
+            }
+            EnsureSize(count + values.count);
+            // We know that all the values will be valid, because it's a RepeatedField.
+            Array.Copy(values.array, 0, array, count, values.count);
+            count += values.count;
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(IEnumerable<T> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException("values");
+            }
+            // TODO: Check for ICollection and get the Count, to optimize?
+            foreach (T item in values)
+            {
+                Add(item);
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<T> GetEnumerator()
+        {
+            for (int i = 0; i < count; i++)
+            {
+                yield return array[i];
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as RepeatedField<T>);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            int hash = 0;
+            for (int i = 0; i < count; i++)
+            {
+                hash = hash * 31 + array[i].GetHashCode();
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this repeated field with another for equality.
+        /// </summary>
+        /// <param name="other">The repeated field to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
+        public bool Equals(RepeatedField<T> other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            if (ReferenceEquals(other, this))
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (!comparer.Equals(array[i], other.array[i]))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns the index of the given item within the collection, or -1 if the item is not
+        /// present.
+        /// </summary>
+        /// <param name="item">The item to find in the collection.</param>
+        /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
+        public int IndexOf(T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (comparer.Equals(array[i], item))
+                {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Inserts the given item at the specified index.
+        /// </summary>
+        /// <param name="index">The index at which to insert the item.</param>
+        /// <param name="item">The item to insert.</param>
+        public void Insert(int index, T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            if (index < 0 || index > count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            EnsureSize(count + 1);
+            Array.Copy(array, index, array, index + 1, count - index);
+            array[index] = item;
+            count++;
+        }
+
+        /// <summary>
+        /// Removes the item at the given index.
+        /// </summary>
+        /// <param name="index">The zero-based index of the item to remove.</param>
+        public void RemoveAt(int index)
+        {
+            if (index < 0 || index >= count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+        }
+
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var writer = new StringWriter();
+            JsonFormatter.Default.WriteList(writer, this);
+            return writer.ToString();
+        }
+
+        /// <summary>
+        /// Gets or sets the item at the specified index.
+        /// </summary>
+        /// <value>
+        /// The element at the specified index.
+        /// </value>
+        /// <param name="index">The zero-based index of the element to get or set.</param>
+        /// <returns>The item at the specified index.</returns>
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                return array[index];
+            }
+            set
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                if (value == null)
+                {
+                    throw new ArgumentNullException("value");
+                }
+                array[index] = value;
+            }
+        }
+
+        #region Explicit interface implementation for IList and ICollection.
+        bool IList.IsFixedSize { get { return false; } }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            Array.Copy(this.array, 0, array, index, count);
+        }
+
+        bool ICollection.IsSynchronized { get { return false; } }
+
+        object ICollection.SyncRoot { get { return this; } }
+
+        object IList.this[int index]
+        {
+            get { return this[index]; }
+            set { this[index] = (T)value; }
+        }
+
+        int IList.Add(object value)
+        {
+            Add((T) value);
+            return count - 1;
+        }
+
+        bool IList.Contains(object value)
+        {
+            return (value is T && Contains((T)value));
+        }
+
+        int IList.IndexOf(object value)
+        {
+            if (!(value is T))
+            {
+                return -1;
+            }
+            return IndexOf((T)value);
+        }
+
+        void IList.Insert(int index, object value)
+        {
+            Insert(index, (T) value);
+        }
+
+        void IList.Remove(object value)
+        {
+            if (!(value is T))
+            {
+                return;
+            }
+            Remove((T)value);
+        }
+        #endregion        
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
new file mode 100644
index 0000000..8a6fefa
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="PropertyInfo"/>, effectively providing
+    /// the familiar members from previous desktop framework versions while
+    /// targeting the newer releases, .NET Core etc.
+    /// </summary>
+    internal static class PropertyInfoExtensions
+    {
+        /// <summary>
+        /// Returns the public getter of a property, or null if there is no such getter
+        /// (either because it's read-only, or the getter isn't public).
+        /// </summary>
+        internal static MethodInfo GetGetMethod(this PropertyInfo target)
+        {
+            var method = target.GetMethod;
+            return method != null && method.IsPublic ? method : null;
+        }
+
+        /// <summary>
+        /// Returns the public setter of a property, or null if there is no such setter
+        /// (either because it's write-only, or the setter isn't public).
+        /// </summary>
+        internal static MethodInfo GetSetMethod(this PropertyInfo target)
+        {
+            var method = target.SetMethod;
+            return method != null && method.IsPublic ? method : null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
new file mode 100644
index 0000000..762a29e
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Provides extension methods on Type that just proxy to TypeInfo.
+    /// These are used to support the new type system from .NET 4.5, without
+    /// having calls to GetTypeInfo all over the place. While the methods here are meant to be
+    /// broadly compatible with the desktop framework, there are some subtle differences in behaviour - but
+    /// they're not expected to affect our use cases. While the class is internal, that should be fine: we can
+    /// evaluate each new use appropriately.
+    /// </summary>
+    internal static class TypeExtensions
+    {
+        /// <summary>
+        /// Returns true if the target type is a value type, including a nullable value type or an enum, or false
+        /// if it's a reference type (class, delegate, interface - including System.ValueType and System.Enum).
+        /// </summary>
+        internal static bool IsValueType(this Type target)
+        {
+            return target.GetTypeInfo().IsValueType;
+        }
+
+        /// <summary>
+        /// See https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom
+        /// </summary>
+        internal static bool IsAssignableFrom(this Type target, Type c)
+        {
+            return target.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
+        }
+
+        /// <summary>
+        /// Returns a representation of the public property associated with the given name in the given type,
+        /// including inherited properties or null if there is no such public property.
+        /// Here, "public property" means a property where either the getter, or the setter, or both, is public.
+        /// </summary>
+        internal static PropertyInfo GetProperty(this Type target, string name)
+        {
+            // GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
+            while (target != null)
+            {
+                var typeInfo = target.GetTypeInfo();
+                var ret = typeInfo.GetDeclaredProperty(name);
+                if (ret != null && ((ret.CanRead && ret.GetMethod.IsPublic) || (ret.CanWrite && ret.SetMethod.IsPublic)))
+                {
+                    return ret;
+                }
+                target = typeInfo.BaseType;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Returns a representation of the public method associated with the given name in the given type,
+        /// including inherited methods.
+        /// </summary>
+        /// <remarks>
+        /// This has a few differences compared with Type.GetMethod in the desktop framework. It will throw
+        /// if there is an ambiguous match even between a private method and a public one, but it *won't* throw
+        /// if there are two overloads at different levels in the type hierarchy (e.g. class Base declares public void Foo(int) and
+        /// class Child : Base declares public void Foo(long)).
+        /// </remarks>
+        /// <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
+        internal static MethodInfo GetMethod(this Type target, string name)
+        {
+            // GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
+            while (target != null)
+            {
+                var typeInfo = target.GetTypeInfo();
+                var ret = typeInfo.GetDeclaredMethod(name);
+                if (ret != null && ret.IsPublic)
+                {
+                    return ret;
+                }
+                target = typeInfo.BaseType;
+            }
+            return null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
new file mode 100644
index 0000000..9831308
--- /dev/null
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -0,0 +1,473 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Compatibility;
+using Google.Protobuf.WellKnownTypes;
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Factory methods for <see cref="FieldCodec{T}"/>.
+    /// </summary>
+    public static class FieldCodec
+    {
+        // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
+
+        /// <summary>
+        /// Retrieves a codec suitable for a string field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<string> ForString(uint tag)
+        {
+            return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bytes field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ByteString> ForBytes(uint tag)
+        {
+            return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bool field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<bool> ForBool(uint tag)
+        {
+            return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForFixed32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSFixed32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForUInt32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForFixed64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSFixed64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForUInt64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a float field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<float> ForFloat(uint tag)
+        {
+            return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a double field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<double> ForDouble(uint tag)
+        {
+            return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
+        }
+
+        // Enums are tricky. We can probably use expression trees to build these delegates automatically,
+        // but it's easy to generate the code for it.
+
+        /// <summary>
+        /// Retrieves a codec suitable for an enum field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
+        /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
+        {
+            return new FieldCodec<T>(input => fromInt32(
+                input.ReadEnum()),
+                (output, value) => output.WriteEnum(toInt32(value)),
+                value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a message field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="parser">A parser to use for the message type.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage<T>
+        {
+            return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
+                (output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
+        }
+
+        /// <summary>
+        /// Creates a codec for a wrapper type of a class - which must be string or ByteString.
+        /// </summary>
+        public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
+        {
+            var nestedCodec = WrapperCodecs.GetCodec<T>();
+            return new FieldCodec<T>(
+                input => WrapperCodecs.Read<T>(input, nestedCodec),
+                (output, value) => WrapperCodecs.Write<T>(output, value, nestedCodec),
+                value => WrapperCodecs.CalculateSize<T>(value, nestedCodec),
+                tag,
+                null); // Default value for the wrapper
+        }
+
+        /// <summary>
+        /// Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
+        /// Bool, Single or Double.
+        /// </summary>
+        public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct
+        {
+            var nestedCodec = WrapperCodecs.GetCodec<T>();
+            return new FieldCodec<T?>(
+                input => WrapperCodecs.Read<T>(input, nestedCodec),
+                (output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
+                value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(value.Value, nestedCodec),
+                tag,
+                null); // Default value for the wrapper
+        }
+
+        /// <summary>
+        /// Helper code to create codecs for wrapper types.
+        /// </summary>
+        /// <remarks>
+        /// Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
+        /// slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
+        /// we can refactor later if we come up with something cleaner.
+        /// </remarks>
+        private static class WrapperCodecs
+        {
+            private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
+            {
+                { typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
+                { typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
+                { typeof(string), ForString(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
+                { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
+            };
+
+            /// <summary>
+            /// Returns a field codec which effectively wraps a value of type T in a message.
+            /// 
+            /// </summary>
+            internal static FieldCodec<T> GetCodec<T>()
+            {
+                object value;
+                if (!Codecs.TryGetValue(typeof(T), out value))
+                {
+                    throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
+                }
+                return (FieldCodec<T>) value;
+            }
+
+            internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
+            {
+                int length = input.ReadLength();
+                int oldLimit = input.PushLimit(length);
+
+                uint tag;
+                T value = codec.DefaultValue;
+                while ((tag = input.ReadTag()) != 0)
+                {
+                    if (tag == codec.Tag)
+                    {
+                        value = codec.Read(input);
+                    }
+                    else
+                    {
+                        input.SkipLastField();
+                    }
+
+                }
+                input.CheckReadEndOfStreamTag();
+                input.PopLimit(oldLimit);
+
+                return value;
+            }
+
+            internal static void Write<T>(CodedOutputStream output, T value, FieldCodec<T> codec)
+            {
+                output.WriteLength(codec.CalculateSizeWithTag(value));
+                codec.WriteTagAndValue(output, value);
+            }
+
+            internal  static int CalculateSize<T>(T value, FieldCodec<T> codec)
+            {
+                int fieldLength = codec.CalculateSizeWithTag(value);
+                return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength;
+            }
+        }
+    }
+
+    /// <summary>
+    /// <para>
+    /// An encode/decode pair for a single field. This effectively encapsulates
+    /// all the information needed to read or write the field value from/to a coded
+    /// stream.
+    /// </para>
+    /// <para>
+    /// This class is public and has to be as it is used by generated code, but its public
+    /// API is very limited - just what the generated code needs to call directly.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// This never writes default values to the stream, and does not address "packedness"
+    /// in repeated fields itself, other than to know whether or not the field *should* be packed.
+    /// </remarks>
+    public sealed class FieldCodec<T>
+    {
+        private static readonly T DefaultDefault;
+        private static readonly bool TypeSupportsPacking = typeof(T).IsValueType() && Nullable.GetUnderlyingType(typeof(T)) == null;
+
+        static FieldCodec()
+        {
+            if (typeof(T) == typeof(string))
+            {
+                DefaultDefault = (T)(object)"";
+            }
+            else if (typeof(T) == typeof(ByteString))
+            {
+                DefaultDefault = (T)(object)ByteString.Empty;
+            }
+            // Otherwise it's the default value of the CLR type
+        }
+
+        internal static bool IsPackedRepeatedField(uint tag) =>
+            TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
+
+        internal bool PackedRepeatedField { get; }
+
+        /// <summary>
+        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
+        /// </summary>
+        internal Action<CodedOutputStream, T> ValueWriter { get; }
+
+        /// <summary>
+        /// Returns the size calculator for just a value.
+        /// </summary>
+        internal Func<T, int> ValueSizeCalculator { get; }
+
+        /// <summary>
+        /// Returns a delegate to read a value from a coded input stream. It is assumed that
+        /// the stream is already positioned on the appropriate tag.
+        /// </summary>
+        internal Func<CodedInputStream, T> ValueReader { get; }
+
+        /// <summary>
+        /// Returns the fixed size for an entry, or 0 if sizes vary.
+        /// </summary>
+        internal int FixedSize { get; }
+
+        /// <summary>
+        /// Gets the tag of the codec.
+        /// </summary>
+        /// <value>
+        /// The tag of the codec.
+        /// </value>
+        internal uint Tag { get; }
+
+        /// <summary>
+        /// Default value for this codec. Usually the same for every instance of the same type, but
+        /// for string/ByteString wrapper fields the codec's default value is null, whereas for
+        /// other string/ByteString fields it's "" or ByteString.Empty.
+        /// </summary>
+        /// <value>
+        /// The default value of the codec's type.
+        /// </value>
+        internal T DefaultValue { get; }
+
+        private readonly int tagSize;
+        
+        internal FieldCodec(
+                Func<CodedInputStream, T> reader,
+                Action<CodedOutputStream, T> writer,
+                int fixedSize,
+                uint tag) : this(reader, writer, _ => fixedSize, tag)
+        {
+            FixedSize = fixedSize;
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
+        {
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag,
+            T defaultValue)
+        {
+            ValueReader = reader;
+            ValueWriter = writer;
+            ValueSizeCalculator = sizeCalculator;
+            FixedSize = 0;
+            Tag = tag;
+            DefaultValue = defaultValue;
+            tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
+            // Detect packed-ness once, so we can check for it within RepeatedField<T>.
+            PackedRepeatedField = IsPackedRepeatedField(tag);
+        }
+
+        /// <summary>
+        /// Write a tag and the given value, *if* the value is not the default.
+        /// </summary>
+        public void WriteTagAndValue(CodedOutputStream output, T value)
+        {
+            if (!IsDefault(value))
+            {
+                output.WriteTag(Tag);
+                ValueWriter(output, value);
+            }
+        }
+
+        /// <summary>
+        /// Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <returns>The value read from the stream.</returns>
+        public T Read(CodedInputStream input) => ValueReader(input);
+
+        /// <summary>
+        /// Calculates the size required to write the given value, with a tag,
+        /// if the value is not the default.
+        /// </summary>
+        public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
+
+        private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(value, DefaultValue);
+    }
+}
diff --git a/csharp/src/Google.Protobuf/FrameworkPortability.cs b/csharp/src/Google.Protobuf/FrameworkPortability.cs
new file mode 100644
index 0000000..9498dbe
--- /dev/null
+++ b/csharp/src/Google.Protobuf/FrameworkPortability.cs
@@ -0,0 +1,49 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.Text.RegularExpressions;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Class containing helpful workarounds for various platform compatibility

+    /// </summary>

+    internal static class FrameworkPortability

+    {

+        // The value of RegexOptions.Compiled is 8. We can test for the presence at

+        // execution time using Enum.IsDefined, so a single build will do the right thing

+        // on each platform. (RegexOptions.Compiled isn't supported by PCLs.)

+        internal static readonly RegexOptions CompiledRegexWhereAvailable =

+            Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None;

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
new file mode 100644
index 0000000..5557612
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>9.0.30729</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</ProjectGuid>

+    <OutputType>Library</OutputType>

+    <AppDesignerFolder>Properties</AppDesignerFolder>

+    <RootNamespace>Google.Protobuf</RootNamespace>

+    <AssemblyName>Google.Protobuf</AssemblyName>

+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

+    <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>

+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

+    <FileAlignment>512</FileAlignment>

+    <OldToolsVersion>3.5</OldToolsVersion>

+    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>

+    <NuGetPackageImportStamp>

+    </NuGetPackageImportStamp>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <Optimize>false</Optimize>

+    <OutputPath>bin\Debug</OutputPath>

+    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

+    <DocumentationFile>bin\Debug\Google.Protobuf.xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release</OutputPath>

+    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

+    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\ReleaseSigned</OutputPath>

+    <IntermediateOutputPath>obj\ReleaseSigned\</IntermediateOutputPath>

+    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>TRACE;SIGNED</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <SignAssembly>True</SignAssembly>

+    <AssemblyOriginatorKeyFile>..\..\keys\Google.Protobuf.snk</AssemblyOriginatorKeyFile>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="mscorlib" />

+    <Reference Include="System" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="ByteArray.cs" />

+    <Compile Include="ByteString.cs" />

+    <Compile Include="CodedOutputStream.ComputeSize.cs" />

+    <Compile Include="CodedInputStream.cs" />

+    <Compile Include="CodedOutputStream.cs" />

+    <Compile Include="Collections\MapField.cs" />

+    <Compile Include="Collections\ReadOnlyDictionary.cs" />

+    <Compile Include="Collections\RepeatedField.cs" />

+    <Compile Include="Compatibility\PropertyInfoExtensions.cs" />

+    <Compile Include="Compatibility\TypeExtensions.cs" />

+    <Compile Include="FieldCodec.cs" />

+    <Compile Include="FrameworkPortability.cs" />

+    <Compile Include="ICustomDiagnosticMessage.cs" />

+    <Compile Include="IDeepCloneable.cs" />

+    <Compile Include="InvalidJsonException.cs" />

+    <Compile Include="JsonFormatter.cs" />

+    <Compile Include="JsonParser.cs" />

+    <Compile Include="JsonToken.cs" />

+    <Compile Include="JsonTokenizer.cs" />

+    <Compile Include="MessageExtensions.cs" />

+    <Compile Include="IMessage.cs" />

+    <Compile Include="InvalidProtocolBufferException.cs" />

+    <Compile Include="LimitedInputStream.cs" />

+    <Compile Include="MessageParser.cs" />

+    <Compile Include="Properties\AssemblyInfo.cs" />

+    <Compile Include="Reflection\Descriptor.cs" />

+    <Compile Include="Reflection\DescriptorBase.cs" />

+    <Compile Include="Reflection\DescriptorPool.cs" />

+    <Compile Include="Reflection\DescriptorUtil.cs" />

+    <Compile Include="Reflection\DescriptorValidationException.cs" />

+    <Compile Include="Reflection\EnumDescriptor.cs" />

+    <Compile Include="Reflection\EnumValueDescriptor.cs" />

+    <Compile Include="Reflection\FieldAccessorBase.cs" />

+    <Compile Include="Reflection\FieldDescriptor.cs" />

+    <Compile Include="Reflection\FieldType.cs" />

+    <Compile Include="Reflection\FileDescriptor.cs" />

+    <Compile Include="Reflection\GeneratedClrTypeInfo.cs" />

+    <Compile Include="Reflection\IDescriptor.cs" />

+    <Compile Include="Reflection\IFieldAccessor.cs" />

+    <Compile Include="Reflection\MapFieldAccessor.cs" />

+    <Compile Include="Reflection\MessageDescriptor.cs" />

+    <Compile Include="Reflection\MethodDescriptor.cs" />

+    <Compile Include="Reflection\OneofAccessor.cs" />

+    <Compile Include="Reflection\OneofDescriptor.cs" />

+    <Compile Include="Reflection\OriginalNameAttribute.cs" />

+    <Compile Include="Reflection\PackageDescriptor.cs" />

+    <Compile Include="Reflection\PartialClasses.cs" />

+    <Compile Include="Reflection\ReflectionUtil.cs" />

+    <Compile Include="Reflection\RepeatedFieldAccessor.cs" />

+    <Compile Include="Reflection\ServiceDescriptor.cs" />

+    <Compile Include="Reflection\SingleFieldAccessor.cs" />

+    <Compile Include="ProtoPreconditions.cs" />

+    <Compile Include="Reflection\TypeRegistry.cs" />

+    <Compile Include="WellKnownTypes\Any.cs" />

+    <Compile Include="WellKnownTypes\AnyPartial.cs" />

+    <Compile Include="WellKnownTypes\Api.cs" />

+    <Compile Include="WellKnownTypes\Duration.cs" />

+    <Compile Include="WellKnownTypes\DurationPartial.cs" />

+    <Compile Include="WellKnownTypes\Empty.cs" />

+    <Compile Include="WellKnownTypes\FieldMask.cs" />

+    <Compile Include="WellKnownTypes\FieldMaskPartial.cs" />

+    <Compile Include="WellKnownTypes\SourceContext.cs" />

+    <Compile Include="WellKnownTypes\Struct.cs" />

+    <Compile Include="WellKnownTypes\TimeExtensions.cs" />

+    <Compile Include="WellKnownTypes\Timestamp.cs" />

+    <Compile Include="WellKnownTypes\TimestampPartial.cs" />

+    <Compile Include="WellKnownTypes\Type.cs" />

+    <Compile Include="WellKnownTypes\ValuePartial.cs" />

+    <Compile Include="WellKnownTypes\Wrappers.cs" />

+    <Compile Include="WellKnownTypes\WrappersPartial.cs" />

+    <Compile Include="WireFormat.cs" />

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="Google.Protobuf.nuspec" />

+    <None Include="packages.config" />

+  </ItemGroup>

+  <ItemGroup />

+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />

+  <Import Project="..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets" Condition="Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" />

+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

+    <PropertyGroup>

+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>

+    </PropertyGroup>

+    <Error Condition="!Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets'))" />

+  </Target>

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
new file mode 100644
index 0000000..90e3da3
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Google.Protobuf</id>
+    <title>Google Protocol Buffers C#</title>
+    <summary>C# runtime library for Protocol Buffers - Google's data interchange format.</summary>
+    <description>See project site for more info.</description>
+    <version>3.0.0-beta3</version>
+    <authors>Google Inc.</authors>
+    <owners>protobuf-packages</owners>
+    <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/google/protobuf</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <releaseNotes>C# proto3 support</releaseNotes>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
+    <dependencies>
+      <!-- Dependencies for older, monolithic-assembly platforms -->
+      <group targetFramework="net45" />
+      <group targetFramework="wp8" />
+      <group targetFramework="win8" />
+      <group targetFramework="wpa81" />
+      <group targetFramework="xamarin.ios" />
+      <group targetFramework="monotouch" />
+      <group targetFramework="monoandroid" />
+      <!-- Dependencies for newer, more granular platforms (.NET Core etc) -->
+      <group targetFramework="dotnet">
+        <dependency id="System.Collections" version="4.0.0" />
+        <dependency id="System.Diagnostics.Debug" version="4.0.0" />
+        <dependency id="System.Globalization" version="4.0.0" />
+        <dependency id="System.IO" version="4.0.0" />
+        <dependency id="System.Linq" version="4.0.0" />
+        <dependency id="System.Linq.Expressions" version="4.0.0" />
+        <dependency id="System.ObjectModel" version="4.0.0" />
+        <dependency id="System.Reflection" version="4.0.0" />
+        <dependency id="System.Reflection.Extensions" version="4.0.0" />
+        <dependency id="System.Runtime" version="4.0.0" />
+        <dependency id="System.Runtime.Extensions" version="4.0.0" />
+        <dependency id="System.Text.Encoding" version="4.0.0" />
+        <dependency id="System.Text.RegularExpressions" version="4.0.0" />
+        <dependency id="System.Threading" version="4.0.0" />
+      </group>
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
+    <file src="**\*.cs" target="src" />
+  </files>
+</package>
diff --git a/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
new file mode 100644
index 0000000..a009056
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
@@ -0,0 +1,69 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A message type that has a custom string format for diagnostic purposes.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Calling <see cref="object.ToString"/> on a generated message type normally
+    /// returns the JSON representation. If a message type implements this interface,
+    /// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
+    /// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
+    /// or on another message which contains it. This does not affect the normal JSON formatting of
+    /// the message.
+    /// </para>
+    /// <para>
+    /// For example, if you create a proto message representing a GUID, the internal
+    /// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
+    /// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
+    /// </para>
+    /// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
+    /// on types other than messages, where it would not be used by anything in the framework.</para>
+    /// </remarks>
+    public interface ICustomDiagnosticMessage : IMessage
+    {
+        /// <summary>
+        /// Returns a string representation of this object, for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
+        /// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
+        /// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
+        /// that the result is valid JSON, this is never assumed by the Protobuf library.
+        /// </remarks>
+        /// <returns>A string representation of this object, for diagnostic purposes.</returns>
+        string ToDiagnosticString();
+    }
+}
diff --git a/csharp/src/Google.Protobuf/IDeepCloneable.cs b/csharp/src/Google.Protobuf/IDeepCloneable.cs
new file mode 100644
index 0000000..c9c71bb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/IDeepCloneable.cs
@@ -0,0 +1,54 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Generic interface for a deeply cloneable type.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// All generated messages implement this interface, but so do some non-message types.
+    /// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,
+    /// it is simpler to keep this as a separate interface.
+    /// </para>
+    /// </remarks>
+    /// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
+    public interface IDeepCloneable<T>
+    {
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>A deep clone of this object.</returns>
+        T Clone();
+    }
+}
diff --git a/csharp/src/Google.Protobuf/IMessage.cs b/csharp/src/Google.Protobuf/IMessage.cs
new file mode 100644
index 0000000..d089f94
--- /dev/null
+++ b/csharp/src/Google.Protobuf/IMessage.cs
@@ -0,0 +1,87 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using Google.Protobuf.Reflection;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Interface for a Protocol Buffers message, supporting

+    /// basic operations required for serialization.

+    /// </summary>

+    public interface IMessage

+    {

+        /// <summary>

+        /// Merges the data from the specified coded input stream with the current message.

+        /// </summary>

+        /// <remarks>See the user guide for precise merge semantics.</remarks>

+        /// <param name="input"></param>

+        void MergeFrom(CodedInputStream input);

+

+        /// <summary>

+        /// Writes the data to the given coded output stream.

+        /// </summary>

+        /// <param name="output">Coded output stream to write the data to. Must not be null.</param>

+        void WriteTo(CodedOutputStream output);

+

+        /// <summary>

+        /// Calculates the size of this message in Protocol Buffer wire format, in bytes.

+        /// </summary>

+        /// <returns>The number of bytes required to write this message

+        /// to a coded output stream.</returns>

+        int CalculateSize();

+

+        /// <summary>

+        /// Descriptor for this message. All instances are expected to return the same descriptor,

+        /// and for generated types this will be an explicitly-implemented member, returning the

+        /// same value as the static property declared on the type.

+        /// </summary>

+        MessageDescriptor Descriptor { get; }

+    }

+

+    /// <summary>

+    /// Generic interface for a Protocol Buffers message,

+    /// where the type parameter is expected to be the same type as

+    /// the implementation class.

+    /// </summary>

+    /// <typeparam name="T">The message type.</typeparam>

+    public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>

+    {

+        /// <summary>

+        /// Merges the given message into this one.

+        /// </summary>

+        /// <remarks>See the user guide for precise merge semantics.</remarks>

+        /// <param name="message">The message to merge with this one. Must not be null.</param>

+        void MergeFrom(T message);

+    }

+}

diff --git a/csharp/src/Google.Protobuf/InvalidJsonException.cs b/csharp/src/Google.Protobuf/InvalidJsonException.cs
new file mode 100644
index 0000000..b543420
--- /dev/null
+++ b/csharp/src/Google.Protobuf/InvalidJsonException.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Thrown when an attempt is made to parse invalid JSON, e.g. using
+    /// a non-string property key, or including a redundant comma. Parsing a protocol buffer
+    /// message represented in JSON using <see cref="JsonParser"/> can throw both this
+    /// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
+    /// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
+    /// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
+    /// message.
+    /// </summary>
+    public sealed class InvalidJsonException : IOException
+    {
+        internal InvalidJsonException(string message)
+            : base(message)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
new file mode 100644
index 0000000..eeb0f13
--- /dev/null
+++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
@@ -0,0 +1,129 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System;

+using System.IO;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Thrown when a protocol message being parsed is invalid in some way,

+    /// e.g. it contains a malformed varint or a negative byte length.

+    /// </summary>

+    public sealed class InvalidProtocolBufferException : IOException

+    {

+        internal InvalidProtocolBufferException(string message)

+            : base(message)

+        {

+        }

+

+        internal InvalidProtocolBufferException(string message, Exception innerException)

+            : base(message, innerException)

+        {

+        }

+

+        internal static InvalidProtocolBufferException MoreDataAvailable()

+        {

+            return new InvalidProtocolBufferException(

+                "Completed reading a message while more data was available in the stream.");

+        }

+

+        internal static InvalidProtocolBufferException TruncatedMessage()

+        {

+            return new InvalidProtocolBufferException(

+                "While parsing a protocol message, the input ended unexpectedly " +

+                "in the middle of a field.  This could mean either than the " +

+                "input has been truncated or that an embedded message " +

+                "misreported its own length.");

+        }

+

+        internal static InvalidProtocolBufferException NegativeSize()

+        {

+            return new InvalidProtocolBufferException(

+                "CodedInputStream encountered an embedded string or message " +

+                "which claimed to have negative size.");

+        }

+

+        internal static InvalidProtocolBufferException MalformedVarint()

+        {

+            return new InvalidProtocolBufferException(

+                "CodedInputStream encountered a malformed varint.");

+        }

+

+        /// <summary>

+        /// Creates an exception for an error condition of an invalid tag being encountered.

+        /// </summary>

+        internal static InvalidProtocolBufferException InvalidTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message contained an invalid tag (zero).");

+        }

+

+        internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)

+        {

+            return new InvalidProtocolBufferException("Invalid base64 data", innerException);

+        }

+

+        internal static InvalidProtocolBufferException InvalidEndTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message end-group tag did not match expected tag.");

+        }

+

+        internal static InvalidProtocolBufferException RecursionLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message had too many levels of nesting.  May be malicious.  " +

+                "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");

+        }

+

+        internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message had too many levels of nesting.  May be malicious.  " +

+                "Use JsonParser.Settings to increase the depth limit.");

+        }

+

+        internal static InvalidProtocolBufferException SizeLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message was too large.  May be malicious.  " +

+                "Use CodedInputStream.SetSizeLimit() to increase the size limit.");

+        }

+

+        internal static InvalidProtocolBufferException InvalidMessageStreamTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
new file mode 100644
index 0000000..8377247
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -0,0 +1,912 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Text;
+using Google.Protobuf.Reflection;
+using Google.Protobuf.WellKnownTypes;
+using System.IO;
+using System.Linq;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reflection-based converter from messages to JSON.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Instances of this class are thread-safe, with no mutable state.
+    /// </para>
+    /// <para>
+    /// This is a simple start to get JSON formatting working. As it's reflection-based,
+    /// it's not as quick as baking calls into generated messages - but is a simpler implementation.
+    /// (This code is generally not heavily optimized.)
+    /// </para>
+    /// </remarks>
+    public sealed class JsonFormatter
+    {
+        internal const string AnyTypeUrlField = "@type";
+        internal const string AnyDiagnosticValueField = "@value";
+        internal const string AnyWellKnownTypeValueField = "value";
+        private const string TypeUrlPrefix = "type.googleapis.com";
+        private const string NameValueSeparator = ": ";
+        private const string PropertySeparator = ", ";
+
+        /// <summary>
+        /// Returns a formatter using the default settings.
+        /// </summary>
+        public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
+
+        // A JSON formatter which *only* exists 
+        private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
+
+        /// <summary>
+        /// The JSON representation of the first 160 characters of Unicode.
+        /// Empty strings are replaced by the static constructor.
+        /// </summary>
+        private static readonly string[] CommonRepresentations = {
+            // C0 (ASCII and derivatives) control characters
+            "\\u0000", "\\u0001", "\\u0002", "\\u0003",  // 0x00
+          "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+          "\\b",     "\\t",     "\\n",     "\\u000b",
+          "\\f",     "\\r",     "\\u000e", "\\u000f",
+          "\\u0010", "\\u0011", "\\u0012", "\\u0013",  // 0x10
+          "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+          "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+          "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+            // Escaping of " and \ are required by www.json.org string definition.
+            // Escaping of < and > are required for HTML security.
+            "", "", "\\\"", "", "",        "", "",        "",  // 0x20
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x30
+          "", "", "",     "", "\\u003c", "", "\\u003e", "",
+          "", "", "",     "", "",        "", "",        "",  // 0x40
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x50
+          "", "", "",     "", "\\\\",    "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x60
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x70
+          "", "", "",     "", "",        "", "",        "\\u007f",
+            // C1 (ISO 8859 and Unicode) extended control characters
+            "\\u0080", "\\u0081", "\\u0082", "\\u0083",  // 0x80
+          "\\u0084", "\\u0085", "\\u0086", "\\u0087",
+          "\\u0088", "\\u0089", "\\u008a", "\\u008b",
+          "\\u008c", "\\u008d", "\\u008e", "\\u008f",
+          "\\u0090", "\\u0091", "\\u0092", "\\u0093",  // 0x90
+          "\\u0094", "\\u0095", "\\u0096", "\\u0097",
+          "\\u0098", "\\u0099", "\\u009a", "\\u009b",
+          "\\u009c", "\\u009d", "\\u009e", "\\u009f"
+        };
+
+        static JsonFormatter()
+        {
+            for (int i = 0; i < CommonRepresentations.Length; i++)
+            {
+                if (CommonRepresentations[i] == "")
+                {
+                    CommonRepresentations[i] = ((char) i).ToString();
+                }
+            }
+        }
+
+        private readonly Settings settings;
+
+        private bool DiagnosticOnly => ReferenceEquals(this, diagnosticFormatter);
+
+        /// <summary>
+        /// Creates a new formatted with the given settings.
+        /// </summary>
+        /// <param name="settings">The settings.</param>
+        public JsonFormatter(Settings settings)
+        {
+            this.settings = settings;
+        }
+
+        /// <summary>
+        /// Formats the specified message as JSON.
+        /// </summary>
+        /// <param name="message">The message to format.</param>
+        /// <returns>The formatted message.</returns>
+        public string Format(IMessage message)
+        {
+            var writer = new StringWriter();
+            Format(message, writer);
+            return writer.ToString();
+        }
+
+        /// <summary>
+        /// Formats the specified message as JSON.
+        /// </summary>
+        /// <param name="message">The message to format.</param>
+        /// <param name="writer">The TextWriter to write the formatted message to.</param>
+        /// <returns>The formatted message.</returns>
+        public void Format(IMessage message, TextWriter writer)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            ProtoPreconditions.CheckNotNull(writer, nameof(writer));
+
+            if (message.Descriptor.IsWellKnownType)
+            {
+                WriteWellKnownTypeValue(writer, message.Descriptor, message);
+            }
+            else
+            {
+                WriteMessage(writer, message);
+            }
+        }
+
+        /// <summary>
+        /// Converts a message to JSON for diagnostic purposes with no extra context.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
+        /// formatter in its handling of <see cref="Any"/>. As no type registry is available
+        /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
+        /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
+        /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
+        /// </para>
+        /// <para>The value returned by this method is only designed to be used for diagnostic
+        /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
+        /// by other Protocol Buffer implementations.</para>
+        /// </remarks>
+        /// <param name="message">The message to format for diagnostic purposes.</param>
+        /// <returns>The diagnostic-only JSON representation of the message</returns>
+        public static string ToDiagnosticString(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            return diagnosticFormatter.Format(message);
+        }
+
+        private void WriteMessage(TextWriter writer, IMessage message)
+        {
+            if (message == null)
+            {
+                WriteNull(writer);
+                return;
+            }
+            if (DiagnosticOnly)
+            {
+                ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
+                if (customDiagnosticMessage != null)
+                {
+                    writer.Write(customDiagnosticMessage.ToDiagnosticString());
+                    return;
+                }
+            }
+            writer.Write("{ ");
+            bool writtenFields = WriteMessageFields(writer, message, false);
+            writer.Write(writtenFields ? " }" : "}");
+        }
+
+        private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten)
+        {
+            var fields = message.Descriptor.Fields;
+            bool first = !assumeFirstFieldWritten;
+            // First non-oneof fields
+            foreach (var field in fields.InFieldNumberOrder())
+            {
+                var accessor = field.Accessor;
+                if (field.ContainingOneof != null && field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) != field)
+                {
+                    continue;
+                }
+                // Omit default values unless we're asked to format them, or they're oneofs (where the default
+                // value is still formatted regardless, because that's how we preserve the oneof case).
+                object value = accessor.GetValue(message);
+                if (field.ContainingOneof == null && !settings.FormatDefaultValues && IsDefaultValue(accessor, value))
+                {
+                    continue;
+                }
+
+                // Okay, all tests complete: let's write the field value...
+                if (!first)
+                {
+                    writer.Write(PropertySeparator);
+                }
+
+                WriteString(writer, accessor.Descriptor.JsonName);
+                writer.Write(NameValueSeparator);
+                WriteValue(writer, value);
+
+                first = false;
+            }
+            return !first;
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static string ToCamelCaseForFieldMask(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                    }
+                }
+            }
+            return ToCamelCase(input);
+        }
+
+        // Converted from src/google/protobuf/util/internal/utility.cc ToCamelCase
+        // TODO: Use the new field in FieldDescriptor.
+        internal static string ToCamelCase(string input)
+        {
+            bool capitalizeNext = false;
+            bool wasCap = true;
+            bool isCap = false;
+            bool firstWord = true;
+            StringBuilder result = new StringBuilder(input.Length);
+
+            for (int i = 0; i < input.Length; i++, wasCap = isCap)
+            {
+                isCap = char.IsUpper(input[i]);
+                if (input[i] == '_')
+                {
+                    capitalizeNext = true;
+                    if (result.Length != 0)
+                    {
+                        firstWord = false;
+                    }
+                    continue;
+                }
+                else if (firstWord)
+                {
+                    // Consider when the current character B is capitalized,
+                    // first word ends when:
+                    // 1) following a lowercase:   "...aB..."
+                    // 2) followed by a lowercase: "...ABc..."
+                    if (result.Length != 0 && isCap &&
+                        (!wasCap || (i + 1 < input.Length && char.IsLower(input[i + 1]))))
+                    {
+                        firstWord = false;
+                    }
+                    else
+                    {
+                        result.Append(char.ToLowerInvariant(input[i]));
+                        continue;
+                    }
+                }
+                else if (capitalizeNext)
+                {
+                    capitalizeNext = false;
+                    if (char.IsLower(input[i]))
+                    {
+                        result.Append(char.ToUpperInvariant(input[i]));
+                        continue;
+                    }
+                }
+                result.Append(input[i]);
+            }
+            return result.ToString();
+        }
+        
+        private static void WriteNull(TextWriter writer)
+        {
+            writer.Write("null");
+        }
+
+        private static bool IsDefaultValue(IFieldAccessor accessor, object value)
+        {
+            if (accessor.Descriptor.IsMap)
+            {
+                IDictionary dictionary = (IDictionary) value;
+                return dictionary.Count == 0;
+            }
+            if (accessor.Descriptor.IsRepeated)
+            {
+                IList list = (IList) value;
+                return list.Count == 0;
+            }
+            switch (accessor.Descriptor.FieldType)
+            {
+                case FieldType.Bool:
+                    return (bool) value == false;
+                case FieldType.Bytes:
+                    return (ByteString) value == ByteString.Empty;
+                case FieldType.String:
+                    return (string) value == "";
+                case FieldType.Double:
+                    return (double) value == 0.0;
+                case FieldType.SInt32:
+                case FieldType.Int32:
+                case FieldType.SFixed32:
+                case FieldType.Enum:
+                    return (int) value == 0;
+                case FieldType.Fixed32:
+                case FieldType.UInt32:
+                    return (uint) value == 0;
+                case FieldType.Fixed64:
+                case FieldType.UInt64:
+                    return (ulong) value == 0;
+                case FieldType.SFixed64:
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                    return (long) value == 0;
+                case FieldType.Float:
+                    return (float) value == 0f;
+                case FieldType.Message:
+                case FieldType.Group: // Never expect to get this, but...
+                    return value == null;
+                default:
+                    throw new ArgumentException("Invalid field type");
+            }
+        }
+        
+        private void WriteValue(TextWriter writer, object value)
+        {
+            if (value == null)
+            {
+                WriteNull(writer);
+            }
+            else if (value is bool)
+            {
+                writer.Write((bool)value ? "true" : "false");
+            }
+            else if (value is ByteString)
+            {
+                // Nothing in Base64 needs escaping
+                writer.Write('"');
+                writer.Write(((ByteString)value).ToBase64());
+                writer.Write('"');
+            }
+            else if (value is string)
+            {
+                WriteString(writer, (string)value);
+            }
+            else if (value is IDictionary)
+            {
+                WriteDictionary(writer, (IDictionary)value);
+            }
+            else if (value is IList)
+            {
+                WriteList(writer, (IList)value);
+            }
+            else if (value is int || value is uint)
+            {
+                IFormattable formattable = (IFormattable) value;
+                writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture));
+            }
+            else if (value is long || value is ulong)
+            {
+                writer.Write('"');
+                IFormattable formattable = (IFormattable) value;
+                writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture));
+                writer.Write('"');
+            }
+            else if (value is System.Enum)
+            {
+                string name = OriginalEnumValueHelper.GetOriginalName(value);
+                if (name != null)
+                {
+                    WriteString(writer, name);
+                }
+                else
+                {
+                    WriteValue(writer, (int)value);
+                }
+            }
+            else if (value is float || value is double)
+            {
+                string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
+                if (text == "NaN" || text == "Infinity" || text == "-Infinity")
+                {
+                    writer.Write('"');
+                    writer.Write(text);
+                    writer.Write('"');
+                }
+                else
+                {
+                    writer.Write(text);
+                }
+            }
+            else if (value is IMessage)
+            {
+                IMessage message = (IMessage) value;
+                if (message.Descriptor.IsWellKnownType)
+                {
+                    WriteWellKnownTypeValue(writer, message.Descriptor, value);
+                }
+                else
+                {
+                    WriteMessage(writer, (IMessage)value);
+                }
+            }
+            else
+            {
+                throw new ArgumentException("Unable to format value of type " + value.GetType());
+            }
+        }
+
+        /// <summary>
+        /// Central interception point for well-known type formatting. Any well-known types which
+        /// don't need special handling can fall back to WriteMessage. We avoid assuming that the
+        /// values are using the embedded well-known types, in order to allow for dynamic messages
+        /// in the future.
+        /// </summary>
+        private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value)
+        {
+            // Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
+            // this would do the right thing.
+            if (value == null)
+            {
+                WriteNull(writer);
+                return;
+            }
+            // For wrapper types, the value will either be the (possibly boxed) "native" value,
+            // or the message itself if we're formatting it at the top level (e.g. just calling ToString on the object itself).
+            // If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
+            // and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
+            // WriteValue will do the right thing.)
+            if (descriptor.IsWrapperType)
+            {
+                if (value is IMessage)
+                {
+                    var message = (IMessage) value;
+                    value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message);
+                }
+                WriteValue(writer, value);
+                return;
+            }
+            if (descriptor.FullName == Timestamp.Descriptor.FullName)
+            {
+                WriteTimestamp(writer, (IMessage)value);
+                return;
+            }
+            if (descriptor.FullName == Duration.Descriptor.FullName)
+            {
+                WriteDuration(writer, (IMessage)value);
+                return;
+            }
+            if (descriptor.FullName == FieldMask.Descriptor.FullName)
+            {
+                WriteFieldMask(writer, (IMessage)value);
+                return;
+            }
+            if (descriptor.FullName == Struct.Descriptor.FullName)
+            {
+                WriteStruct(writer, (IMessage)value);
+                return;
+            }
+            if (descriptor.FullName == ListValue.Descriptor.FullName)
+            {
+                var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
+                WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value));
+                return;
+            }
+            if (descriptor.FullName == Value.Descriptor.FullName)
+            {
+                WriteStructFieldValue(writer, (IMessage)value);
+                return;
+            }
+            if (descriptor.FullName == Any.Descriptor.FullName)
+            {
+                WriteAny(writer, (IMessage)value);
+                return;
+            }
+            WriteMessage(writer, (IMessage)value);
+        }
+
+        private void WriteTimestamp(TextWriter writer, IMessage value)
+        {
+            // TODO: In the common case where this *is* using the built-in Timestamp type, we could
+            // avoid all the reflection at this point, by casting to Timestamp. In the interests of
+            // avoiding subtle bugs, don't do that until we've implemented DynamicMessage so that we can prove
+            // it still works in that case.
+            int nanos = (int) value.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.GetValue(value);
+            long seconds = (long) value.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.GetValue(value);
+            writer.Write(Timestamp.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteDuration(TextWriter writer, IMessage value)
+        {
+            // TODO: Same as for WriteTimestamp
+            int nanos = (int) value.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.GetValue(value);
+            long seconds = (long) value.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.GetValue(value);
+            writer.Write(Duration.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteFieldMask(TextWriter writer, IMessage value)
+        {
+            var paths = (IList<string>) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
+            writer.Write(FieldMask.ToJson(paths, DiagnosticOnly));
+        }
+
+        private void WriteAny(TextWriter writer, IMessage value)
+        {
+            if (DiagnosticOnly)
+            {
+                WriteDiagnosticOnlyAny(writer, value);
+                return;
+            }
+
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            string typeName = Any.GetTypeName(typeUrl);
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+            IMessage message = descriptor.Parser.ParseFrom(data);
+            writer.Write("{ ");
+            WriteString(writer, AnyTypeUrlField);
+            writer.Write(NameValueSeparator);
+            WriteString(writer, typeUrl);
+
+            if (descriptor.IsWellKnownType)
+            {
+                writer.Write(PropertySeparator);
+                WriteString(writer, AnyWellKnownTypeValueField);
+                writer.Write(NameValueSeparator);
+                WriteWellKnownTypeValue(writer, descriptor, message);
+            }
+            else
+            {
+                WriteMessageFields(writer, message, true);
+            }
+            writer.Write(" }");
+        }
+
+        private void WriteDiagnosticOnlyAny(TextWriter writer, IMessage value)
+        {
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            writer.Write("{ ");
+            WriteString(writer, AnyTypeUrlField);
+            writer.Write(NameValueSeparator);
+            WriteString(writer, typeUrl);
+            writer.Write(PropertySeparator);
+            WriteString(writer, AnyDiagnosticValueField);
+            writer.Write(NameValueSeparator);
+            writer.Write('"');
+            writer.Write(data.ToBase64());
+            writer.Write('"');
+            writer.Write(" }");
+        }        
+
+        private void WriteStruct(TextWriter writer, IMessage message)
+        {
+            writer.Write("{ ");
+            IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
+            bool first = true;
+            foreach (DictionaryEntry entry in fields)
+            {
+                string key = (string) entry.Key;
+                IMessage value = (IMessage) entry.Value;
+                if (string.IsNullOrEmpty(key) || value == null)
+                {
+                    throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
+                }
+
+                if (!first)
+                {
+                    writer.Write(PropertySeparator);
+                }
+                WriteString(writer, key);
+                writer.Write(NameValueSeparator);
+                WriteStructFieldValue(writer, value);
+                first = false;
+            }
+            writer.Write(first ? "}" : " }");
+        }
+
+        private void WriteStructFieldValue(TextWriter writer, IMessage message)
+        {
+            var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
+            if (specifiedField == null)
+            {
+                throw new InvalidOperationException("Value message must contain a value for the oneof.");
+            }
+
+            object value = specifiedField.Accessor.GetValue(message);
+            
+            switch (specifiedField.FieldNumber)
+            {
+                case Value.BoolValueFieldNumber:
+                case Value.StringValueFieldNumber:
+                case Value.NumberValueFieldNumber:
+                    WriteValue(writer, value);
+                    return;
+                case Value.StructValueFieldNumber:
+                case Value.ListValueFieldNumber:
+                    // Structs and ListValues are nested messages, and already well-known types.
+                    var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
+                    WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage);
+                    return;
+                case Value.NullValueFieldNumber:
+                    WriteNull(writer);
+                    return;
+                default:
+                    throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber);
+            }
+        }
+
+        internal void WriteList(TextWriter writer, IList list)
+        {
+            writer.Write("[ ");
+            bool first = true;
+            foreach (var value in list)
+            {
+                if (!first)
+                {
+                    writer.Write(PropertySeparator);
+                }
+                WriteValue(writer, value);
+                first = false;
+            }
+            writer.Write(first ? "]" : " ]");
+        }
+
+        internal void WriteDictionary(TextWriter writer, IDictionary dictionary)
+        {
+            writer.Write("{ ");
+            bool first = true;
+            // This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
+            foreach (DictionaryEntry pair in dictionary)
+            {
+                if (!first)
+                {
+                    writer.Write(PropertySeparator);
+                }
+                string keyText;
+                if (pair.Key is string)
+                {
+                    keyText = (string) pair.Key;
+                }
+                else if (pair.Key is bool)
+                {
+                    keyText = (bool) pair.Key ? "true" : "false";
+                }
+                else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
+                {
+                    keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
+                }
+                else
+                {
+                    if (pair.Key == null)
+                    {
+                        throw new ArgumentException("Dictionary has entry with null key");
+                    }
+                    throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
+                }
+                WriteString(writer, keyText);
+                writer.Write(NameValueSeparator);
+                WriteValue(writer, pair.Value);
+                first = false;
+            }
+            writer.Write(first ? "}" : " }");
+        }
+
+        /// <summary>
+        /// Returns whether or not a singular value can be represented in JSON.
+        /// Currently only relevant for enums, where unknown values can't be represented.
+        /// For repeated/map fields, this always returns true.
+        /// </summary>
+        private bool CanWriteSingleValue(object value)
+        {
+            if (value is System.Enum)
+            {
+                return System.Enum.IsDefined(value.GetType(), value);
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Writes a string (including leading and trailing double quotes) to a builder, escaping as required.
+        /// </summary>
+        /// <remarks>
+        /// Other than surrogate pair handling, this code is mostly taken from src/google/protobuf/util/internal/json_escaping.cc.
+        /// </remarks>
+        internal static void WriteString(TextWriter writer, string text)
+        {
+            writer.Write('"');
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c < 0xa0)
+                {
+                    writer.Write(CommonRepresentations[c]);
+                    continue;
+                }
+                if (char.IsHighSurrogate(c))
+                {
+                    // Encountered first part of a surrogate pair.
+                    // Check that we have the whole pair, and encode both parts as hex.
+                    i++;
+                    if (i == text.Length || !char.IsLowSurrogate(text[i]))
+                    {
+                        throw new ArgumentException("String contains low surrogate not followed by high surrogate");
+                    }
+                    HexEncodeUtf16CodeUnit(writer, c);
+                    HexEncodeUtf16CodeUnit(writer, text[i]);
+                    continue;
+                }
+                else if (char.IsLowSurrogate(c))
+                {
+                    throw new ArgumentException("String contains high surrogate not preceded by low surrogate");
+                }
+                switch ((uint) c)
+                {
+                    // These are not required by json spec
+                    // but used to prevent security bugs in javascript.
+                    case 0xfeff:  // Zero width no-break space
+                    case 0xfff9:  // Interlinear annotation anchor
+                    case 0xfffa:  // Interlinear annotation separator
+                    case 0xfffb:  // Interlinear annotation terminator
+
+                    case 0x00ad:  // Soft-hyphen
+                    case 0x06dd:  // Arabic end of ayah
+                    case 0x070f:  // Syriac abbreviation mark
+                    case 0x17b4:  // Khmer vowel inherent Aq
+                    case 0x17b5:  // Khmer vowel inherent Aa
+                        HexEncodeUtf16CodeUnit(writer, c);
+                        break;
+
+                    default:
+                        if ((c >= 0x0600 && c <= 0x0603) ||  // Arabic signs
+                            (c >= 0x200b && c <= 0x200f) ||  // Zero width etc.
+                            (c >= 0x2028 && c <= 0x202e) ||  // Separators etc.
+                            (c >= 0x2060 && c <= 0x2064) ||  // Invisible etc.
+                            (c >= 0x206a && c <= 0x206f))
+                        {
+                            HexEncodeUtf16CodeUnit(writer, c);
+                        }
+                        else
+                        {
+                            // No handling of surrogates here - that's done earlier
+                            writer.Write(c);
+                        }
+                        break;
+                }
+            }
+            writer.Write('"');
+        }
+
+        private const string Hex = "0123456789abcdef";
+        private static void HexEncodeUtf16CodeUnit(TextWriter writer, char c)
+        {
+            writer.Write("\\u");
+            writer.Write(Hex[(c >> 12) & 0xf]);
+            writer.Write(Hex[(c >> 8) & 0xf]);
+            writer.Write(Hex[(c >> 4) & 0xf]);
+            writer.Write(Hex[(c >> 0) & 0xf]);
+        }
+
+        /// <summary>
+        /// Settings controlling JSON formatting.
+        /// </summary>
+        public sealed class Settings
+        {
+            /// <summary>
+            /// Default settings, as used by <see cref="JsonFormatter.Default"/>
+            /// </summary>
+            public static Settings Default { get; }
+
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(false);
+            }
+
+            /// <summary>
+            /// Whether fields whose values are the default for the field type (e.g. 0 for integers)
+            /// should be formatted (true) or omitted (false).
+            /// </summary>
+            public bool FormatDefaultValues { get; }
+
+            /// <summary>
+            /// The type registry used to format <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            // TODO: Work out how we're going to scale this to multiple settings. "WithXyz" methods?
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and an empty type registry.
+            /// </summary>
+            /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
+            public Settings(bool formatDefaultValues) : this(formatDefaultValues, TypeRegistry.Empty)
+            {
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and type registry.
+            /// </summary>
+            /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
+            /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
+            public Settings(bool formatDefaultValues, TypeRegistry typeRegistry)
+            {
+                FormatDefaultValues = formatDefaultValues;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
+            }
+        }
+
+        // Effectively a cache of mapping from enum values to the original name as specified in the proto file,
+        // fetched by reflection.
+        // The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues.
+        private static class OriginalEnumValueHelper
+        {
+            // TODO: In the future we might want to use ConcurrentDictionary, at the point where all
+            // the platforms we target have it.
+            private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
+                = new Dictionary<System.Type, Dictionary<object, string>>();
+            
+            internal static string GetOriginalName(object value)
+            {
+                var enumType = value.GetType();
+                Dictionary<object, string> nameMapping;
+                lock (dictionaries)
+                {
+                    if (!dictionaries.TryGetValue(enumType, out nameMapping))
+                    {
+                        nameMapping = GetNameMapping(enumType);
+                        dictionaries[enumType] = nameMapping;
+                    }
+                }
+
+                string originalName;
+                // If this returns false, originalName will be null, which is what we want.
+                nameMapping.TryGetValue(value, out originalName);
+                return originalName;
+            }
+
+            private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
+                enumType.GetTypeInfo().DeclaredFields
+                    .Where(f => f.IsStatic)
+                    .ToDictionary(f => f.GetValue(null),
+                                  f => f.GetCustomAttributes<OriginalNameAttribute>()
+                                        .FirstOrDefault()
+                                        // If the attribute hasn't been applied, fall back to the name of the field.
+                                        ?.Name ?? f.Name);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs
new file mode 100644
index 0000000..d738ebb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonParser.cs
@@ -0,0 +1,1018 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+using Google.Protobuf.WellKnownTypes;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reflection-based converter from JSON to messages.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Instances of this class are thread-safe, with no mutable state.
+    /// </para>
+    /// <para>
+    /// This is a simple start to get JSON parsing working. As it's reflection-based,
+    /// it's not as quick as baking calls into generated messages - but is a simpler implementation.
+    /// (This code is generally not heavily optimized.)
+    /// </para>
+    /// </remarks>
+    public sealed class JsonParser
+    {
+        // Note: using 0-9 instead of \d to ensure no non-ASCII digits.
+        // This regex isn't a complete validator, but will remove *most* invalid input. We rely on parsing to do the rest.
+        private static readonly Regex TimestampRegex = new Regex(@"^(?<datetime>[0-9]{4}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9])(?<subseconds>\.[0-9]{1,9})?(?<offset>(Z|[+-][0-1][0-9]:[0-5][0-9]))$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly Regex DurationRegex = new Regex(@"^(?<sign>-)?(?<int>[0-9]{1,12})(?<subseconds>\.[0-9]{1,9})?s$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly int[] SubsecondScalingFactors = { 0, 100000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
+        private static readonly char[] FieldMaskPathSeparators = new[] { ',' };
+
+        private static readonly JsonParser defaultInstance = new JsonParser(Settings.Default);
+
+        // TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers
+        // and the signatures of various methods.
+        private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+            WellKnownTypeHandlers = new Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+        {
+            { Timestamp.Descriptor.FullName, (parser, message, tokenizer) => MergeTimestamp(message, tokenizer.Next()) },
+            { Duration.Descriptor.FullName, (parser, message, tokenizer) => MergeDuration(message, tokenizer.Next()) },
+            { Value.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStructValue(message, tokenizer) },
+            { ListValue.Descriptor.FullName, (parser, message, tokenizer) =>
+                parser.MergeRepeatedField(message, message.Descriptor.Fields[ListValue.ValuesFieldNumber], tokenizer) },
+            { Struct.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStruct(message, tokenizer) },
+            { Any.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeAny(message, tokenizer) },
+            { FieldMask.Descriptor.FullName, (parser, message, tokenizer) => MergeFieldMask(message, tokenizer.Next()) },
+            { Int32Value.Descriptor.FullName, MergeWrapperField },
+            { Int64Value.Descriptor.FullName, MergeWrapperField },
+            { UInt32Value.Descriptor.FullName, MergeWrapperField },
+            { UInt64Value.Descriptor.FullName, MergeWrapperField },
+            { FloatValue.Descriptor.FullName, MergeWrapperField },
+            { DoubleValue.Descriptor.FullName, MergeWrapperField },
+            { BytesValue.Descriptor.FullName, MergeWrapperField },
+            { StringValue.Descriptor.FullName, MergeWrapperField }
+        };
+
+        // Convenience method to avoid having to repeat the same code multiple times in the above
+        // dictionary initialization.
+        private static void MergeWrapperField(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
+        {
+            parser.MergeField(message, message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber], tokenizer);
+        }
+
+        /// <summary>
+        /// Returns a formatter using the default settings.
+        /// </summary>
+        public static JsonParser Default { get { return defaultInstance; } }
+
+        private readonly Settings settings;
+
+        /// <summary>
+        /// Creates a new formatted with the given settings.
+        /// </summary>
+        /// <param name="settings">The settings.</param>
+        public JsonParser(Settings settings)
+        {
+            this.settings = settings;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="json">The JSON to parse.</param>
+        internal void Merge(IMessage message, string json)
+        {
+            Merge(message, new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        internal void Merge(IMessage message, TextReader jsonReader)
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(jsonReader);
+            Merge(message, tokenizer);
+            var lastToken = tokenizer.Next();
+            if (lastToken != JsonToken.EndDocument)
+            {
+                throw new InvalidProtocolBufferException("Expected end of JSON after object");
+            }
+        }
+
+        /// <summary>
+        /// Merges the given message using data from the given tokenizer. In most cases, the next
+        /// token should be a "start object" token, but wrapper types and nullity can invalidate
+        /// that assumption. This is implemented as an LL(1) recursive descent parser over the stream
+        /// of tokens provided by the tokenizer. This token stream is assumed to be valid JSON, with the
+        /// tokenizer performing that validation - but not every token stream is valid "protobuf JSON".
+        /// </summary>
+        private void Merge(IMessage message, JsonTokenizer tokenizer)
+        {
+            if (tokenizer.ObjectDepth > settings.RecursionLimit)
+            {
+                throw InvalidProtocolBufferException.JsonRecursionLimitExceeded();
+            }
+            if (message.Descriptor.IsWellKnownType)
+            {
+                Action<JsonParser, IMessage, JsonTokenizer> handler;
+                if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out handler))
+                {
+                    handler(this, message, tokenizer);
+                    return;
+                }
+                // Well-known types with no special handling continue in the normal way.
+            }
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object");
+            }
+            var descriptor = message.Descriptor;
+            var jsonFieldMap = descriptor.Fields.ByJsonName();
+            // All the oneof fields we've already accounted for - we can only see each of them once.
+            // The set is created lazily to avoid the overhead of creating a set for every message
+            // we parsed, when oneofs are relatively rare.
+            HashSet<OneofDescriptor> seenOneofs = null;
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                if (token.Type != JsonToken.TokenType.Name)
+                {
+                    throw new InvalidOperationException("Unexpected token type " + token.Type);
+                }
+                string name = token.StringValue;
+                FieldDescriptor field;
+                if (jsonFieldMap.TryGetValue(name, out field))
+                {
+                    if (field.ContainingOneof != null)
+                    {
+                        if (seenOneofs == null)
+                        {
+                            seenOneofs = new HashSet<OneofDescriptor>();
+                        }
+                        if (!seenOneofs.Add(field.ContainingOneof))
+                        {
+                            throw new InvalidProtocolBufferException($"Multiple values specified for oneof {field.ContainingOneof.Name}");
+                        }
+                    }
+                    MergeField(message, field, tokenizer);
+                }
+                else
+                {
+                    // TODO: Is this what we want to do? If not, we'll need to skip the value,
+                    // which may be an object or array. (We might want to put code in the tokenizer
+                    // to do that.)
+                    throw new InvalidProtocolBufferException("Unknown field: " + name);
+                }
+            }
+        }
+
+        private void MergeField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // Clear the field if we see a null token, unless it's for a singular field of type
+                // google.protobuf.Value.
+                // Note: different from Java API, which just ignores it.
+                // TODO: Bring it more in line? Discuss...
+                if (field.IsMap || field.IsRepeated || !IsGoogleProtobufValueField(field))
+                {
+                    field.Accessor.Clear(message);
+                    return;
+                }
+            }
+            tokenizer.PushBack(token);
+
+            if (field.IsMap)
+            {
+                MergeMapField(message, field, tokenizer);
+            }
+            else if (field.IsRepeated)
+            {
+                MergeRepeatedField(message, field, tokenizer);
+            }
+            else
+            {
+                var value = ParseSingleValue(field, tokenizer);
+                field.Accessor.SetValue(message, value);
+            }
+        }
+
+        private void MergeRepeatedField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartArray)
+            {
+                throw new InvalidProtocolBufferException("Repeated field value was not an array. Token type: " + token.Type);
+            }
+
+            IList list = (IList) field.Accessor.GetValue(message);
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndArray)
+                {
+                    return;
+                }
+                tokenizer.PushBack(token);
+                if (token.Type == JsonToken.TokenType.Null)
+                {
+                    throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
+                }
+                list.Add(ParseSingleValue(field, tokenizer));
+            }
+        }
+
+        private void MergeMapField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object to populate a map");
+            }
+
+            var type = field.MessageType;
+            var keyField = type.FindFieldByNumber(1);
+            var valueField = type.FindFieldByNumber(2);
+            if (keyField == null || valueField == null)
+            {
+                throw new InvalidProtocolBufferException("Invalid map field: " + field.FullName);
+            }
+            IDictionary dictionary = (IDictionary) field.Accessor.GetValue(message);
+
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                object key = ParseMapKey(keyField, token.StringValue);
+                object value = ParseSingleValue(valueField, tokenizer);
+                if (value == null)
+                {
+                    throw new InvalidProtocolBufferException("Map values must not be null");
+                }
+                dictionary[key] = value;
+            }
+        }
+
+        private static bool IsGoogleProtobufValueField(FieldDescriptor field)
+        {
+            return field.FieldType == FieldType.Message &&
+                field.MessageType.FullName == Value.Descriptor.FullName;
+        }
+
+        private object ParseSingleValue(FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // TODO: In order to support dynamic messages, we should really build this up
+                // dynamically.
+                if (IsGoogleProtobufValueField(field))
+                {
+                    return Value.ForNull();
+                }
+                return null;
+            }
+
+            var fieldType = field.FieldType;
+            if (fieldType == FieldType.Message)
+            {
+                // Parse wrapper types as their constituent types.
+                // TODO: What does this mean for null?
+                if (field.MessageType.IsWrapperType)
+                {
+                    field = field.MessageType.Fields[WrappersReflection.WrapperValueFieldNumber];
+                    fieldType = field.FieldType;
+                }
+                else
+                {
+                    // TODO: Merge the current value in message? (Public API currently doesn't make this relevant as we don't expose merging.)
+                    tokenizer.PushBack(token);
+                    IMessage subMessage = NewMessageForField(field);
+                    Merge(subMessage, tokenizer);
+                    return subMessage;
+                }
+            }
+
+            switch (token.Type)
+            {
+                case JsonToken.TokenType.True:
+                case JsonToken.TokenType.False:
+                    if (fieldType == FieldType.Bool)
+                    {
+                        return token.Type == JsonToken.TokenType.True;
+                    }
+                    // Fall through to "we don't support this type for this case"; could duplicate the behaviour of the default
+                    // case instead, but this way we'd only need to change one place.
+                    goto default;
+                case JsonToken.TokenType.StringValue:
+                    return ParseSingleStringValue(field, token.StringValue);
+                // Note: not passing the number value itself here, as we may end up storing the string value in the token too.
+                case JsonToken.TokenType.Number:
+                    return ParseSingleNumberValue(field, token);
+                case JsonToken.TokenType.Null:
+                    throw new NotImplementedException("Haven't worked out what to do for null yet");
+                default:
+                    throw new InvalidProtocolBufferException("Unsupported JSON token type " + token.Type + " for field type " + fieldType);
+            }
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="json">The JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(string json) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            return Parse<T>(new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(TextReader jsonReader) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            T message = new T();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(string json, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            return Parse(new StringReader(json), descriptor);
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(TextReader jsonReader, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            IMessage message = descriptor.Parser.CreateTemplate();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        private void MergeStructValue(IMessage message, JsonTokenizer tokenizer)
+        {
+            var firstToken = tokenizer.Next();
+            var fields = message.Descriptor.Fields;
+            switch (firstToken.Type)
+            {
+                case JsonToken.TokenType.Null:
+                    fields[Value.NullValueFieldNumber].Accessor.SetValue(message, 0);
+                    return;
+                case JsonToken.TokenType.StringValue:
+                    fields[Value.StringValueFieldNumber].Accessor.SetValue(message, firstToken.StringValue);
+                    return;
+                case JsonToken.TokenType.Number:
+                    fields[Value.NumberValueFieldNumber].Accessor.SetValue(message, firstToken.NumberValue);
+                    return;
+                case JsonToken.TokenType.False:
+                case JsonToken.TokenType.True:
+                    fields[Value.BoolValueFieldNumber].Accessor.SetValue(message, firstToken.Type == JsonToken.TokenType.True);
+                    return;
+                case JsonToken.TokenType.StartObject:
+                    {
+                        var field = fields[Value.StructValueFieldNumber];
+                        var structMessage = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(structMessage, tokenizer);
+                        field.Accessor.SetValue(message, structMessage);
+                        return;
+                    }
+                case JsonToken.TokenType.StartArray:
+                    {
+                        var field = fields[Value.ListValueFieldNumber];
+                        var list = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(list, tokenizer);
+                        field.Accessor.SetValue(message, list);
+                        return;
+                    }
+                default:
+                    throw new InvalidOperationException("Unexpected token type: " + firstToken.Type);
+            }
+        }
+
+        private void MergeStruct(IMessage message, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Struct");
+            }
+            tokenizer.PushBack(token);
+
+            var field = message.Descriptor.Fields[Struct.FieldsFieldNumber];
+            MergeMapField(message, field, tokenizer);
+        }
+
+        private void MergeAny(IMessage message, JsonTokenizer tokenizer)
+        {
+            // Record the token stream until we see the @type property. At that point, we can take the value, consult
+            // the type registry for the relevant message, and replay the stream, omitting the @type property.
+            var tokens = new List<JsonToken>();
+
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Any");
+            }
+            int typeUrlObjectDepth = tokenizer.ObjectDepth;
+
+            // The check for the property depth protects us from nested Any values which occur before the type URL
+            // for *this* Any.
+            while (token.Type != JsonToken.TokenType.Name ||
+                token.StringValue != JsonFormatter.AnyTypeUrlField ||
+                tokenizer.ObjectDepth != typeUrlObjectDepth)
+            {
+                tokens.Add(token);
+                token = tokenizer.Next();
+
+                if (tokenizer.ObjectDepth < typeUrlObjectDepth)
+                {
+                    throw new InvalidProtocolBufferException("Any message with no @type");
+                }
+            }
+
+            // Don't add the @type property or its value to the recorded token list
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Any.@type");
+            }
+            string typeUrl = token.StringValue;
+            string typeName = Any.GetTypeName(typeUrl);
+
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+
+            // Now replay the token stream we've already read and anything that remains of the object, just parsing it
+            // as normal. Our original tokenizer should end up at the end of the object.
+            var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer);
+            var body = descriptor.Parser.CreateTemplate();
+            if (descriptor.IsWellKnownType)
+            {
+                MergeWellKnownTypeAnyBody(body, replay);
+            }
+            else
+            {
+                Merge(body, replay);
+            }
+            var data = body.ToByteString();
+
+            // Now that we have the message data, we can pack it into an Any (the message received as a parameter).
+            message.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.SetValue(message, typeUrl);
+            message.Descriptor.Fields[Any.ValueFieldNumber].Accessor.SetValue(message, data);
+        }
+
+        // Well-known types end up in a property called "value" in the JSON. As there's no longer a @type property
+        // in the given JSON token stream, we should *only* have tokens of start-object, name("value"), the value
+        // itself, and then end-object.
+        private void MergeWellKnownTypeAnyBody(IMessage body, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next(); // Definitely start-object; checked in previous method
+            token = tokenizer.Next();
+            // TODO: What about an absent Int32Value, for example?
+            if (token.Type != JsonToken.TokenType.Name || token.StringValue != JsonFormatter.AnyWellKnownTypeValueField)
+            {
+                throw new InvalidProtocolBufferException($"Expected '{JsonFormatter.AnyWellKnownTypeValueField}' property for well-known type Any body");
+            }
+            Merge(body, tokenizer);
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.EndObject)
+            {
+                throw new InvalidProtocolBufferException($"Expected end-object token after @type/value for well-known type");
+            }
+        }
+
+        #region Utility methods which don't depend on the state (or settings) of the parser.
+        private static object ParseMapKey(FieldDescriptor field, string keyText)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.Bool:
+                    if (keyText == "true")
+                    {
+                        return true;
+                    }
+                    if (keyText == "false")
+                    {
+                        return false;
+                    }
+                    throw new InvalidProtocolBufferException("Invalid string for bool map key: " + keyText);
+                case FieldType.String:
+                    return keyText;
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(keyText, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(keyText, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(keyText, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(keyText, ulong.Parse);
+                default:
+                    throw new InvalidProtocolBufferException("Invalid field type for map: " + field.FieldType);
+            }
+        }
+
+        private static object ParseSingleNumberValue(FieldDescriptor field, JsonToken token)
+        {
+            double value = token.NumberValue;
+            checked
+            {
+                try
+                {
+                    switch (field.FieldType)
+                    {
+                        case FieldType.Int32:
+                        case FieldType.SInt32:
+                        case FieldType.SFixed32:
+                            CheckInteger(value);
+                            return (int) value;
+                        case FieldType.UInt32:
+                        case FieldType.Fixed32:
+                            CheckInteger(value);
+                            return (uint) value;
+                        case FieldType.Int64:
+                        case FieldType.SInt64:
+                        case FieldType.SFixed64:
+                            CheckInteger(value);
+                            return (long) value;
+                        case FieldType.UInt64:
+                        case FieldType.Fixed64:
+                            CheckInteger(value);
+                            return (ulong) value;
+                        case FieldType.Double:
+                            return value;
+                        case FieldType.Float:
+                            if (double.IsNaN(value))
+                            {
+                                return float.NaN;
+                            }
+                            if (value > float.MaxValue || value < float.MinValue)
+                            {
+                                if (double.IsPositiveInfinity(value))
+                                {
+                                    return float.PositiveInfinity;
+                                }
+                                if (double.IsNegativeInfinity(value))
+                                {
+                                    return float.NegativeInfinity;
+                                }
+                                throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                            }
+                            return (float) value;
+                        case FieldType.Enum:
+                            CheckInteger(value);
+                            // Just return it as an int, and let the CLR convert it.
+                            // Note that we deliberately don't check that it's a known value.
+                            return (int) value;
+                        default:
+                            throw new InvalidProtocolBufferException($"Unsupported conversion from JSON number for field type {field.FieldType}");
+                    }
+                }
+                catch (OverflowException)
+                {
+                    throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                }
+            }
+        }
+
+        private static void CheckInteger(double value)
+        {
+            if (double.IsInfinity(value) || double.IsNaN(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }
+            if (value != Math.Floor(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }            
+        }
+
+        private static object ParseSingleStringValue(FieldDescriptor field, string text)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.String:
+                    return text;
+                case FieldType.Bytes:
+                    try
+                    {
+                        return ByteString.FromBase64(text);
+                    }
+                    catch (FormatException e)
+                    {
+                        throw InvalidProtocolBufferException.InvalidBase64(e);
+                    }
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(text, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(text, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(text, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(text, ulong.Parse);
+                case FieldType.Double:
+                    double d = ParseNumericString(text, double.Parse);
+                    ValidateInfinityAndNan(text, double.IsPositiveInfinity(d), double.IsNegativeInfinity(d), double.IsNaN(d));
+                    return d;
+                case FieldType.Float:
+                    float f = ParseNumericString(text, float.Parse);
+                    ValidateInfinityAndNan(text, float.IsPositiveInfinity(f), float.IsNegativeInfinity(f), float.IsNaN(f));
+                    return f;
+                case FieldType.Enum:
+                    var enumValue = field.EnumType.FindValueByName(text);
+                    if (enumValue == null)
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid enum value: {text} for enum type: {field.EnumType.FullName}");
+                    }
+                    // Just return it as an int, and let the CLR convert it.
+                    return enumValue.Number;
+                default:
+                    throw new InvalidProtocolBufferException($"Unsupported conversion from JSON string for field type {field.FieldType}");
+            }
+        }
+
+        /// <summary>
+        /// Creates a new instance of the message type for the given field.
+        /// </summary>
+        private static IMessage NewMessageForField(FieldDescriptor field)
+        {
+            return field.MessageType.Parser.CreateTemplate();
+        }
+
+        private static T ParseNumericString<T>(string text, Func<string, NumberStyles, IFormatProvider, T> parser)
+        {
+            // Can't prohibit this with NumberStyles.
+            if (text.StartsWith("+"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+            if (text.StartsWith("0") && text.Length > 1)
+            {
+                if (text[1] >= '0' && text[1] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            else if (text.StartsWith("-0") && text.Length > 2)
+            {
+                if (text[2] >= '0' && text[2] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            try
+            {
+                return parser(text, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value for type: {text}");
+            }
+            catch (OverflowException)
+            {
+                throw new InvalidProtocolBufferException($"Value out of range: {text}");
+            }
+        }
+
+        /// <summary>
+        /// Checks that any infinite/NaN values originated from the correct text.
+        /// This corrects the lenient whitespace handling of double.Parse/float.Parse, as well as the
+        /// way that Mono parses out-of-range values as infinity.
+        /// </summary>
+        private static void ValidateInfinityAndNan(string text, bool isPositiveInfinity, bool isNegativeInfinity, bool isNaN)
+        {
+            if ((isPositiveInfinity && text != "Infinity") ||
+                (isNegativeInfinity && text != "-Infinity") ||
+                (isNaN && text != "NaN"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+        }
+
+        private static void MergeTimestamp(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Timestamp");
+            }
+            var match = TimestampRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Timestamp value: {token.StringValue}");
+            }
+            var dateTime = match.Groups["datetime"].Value;
+            var subseconds = match.Groups["subseconds"].Value;
+            var offset = match.Groups["offset"].Value;
+
+            try
+            {
+                DateTime parsed = DateTime.ParseExact(
+                    dateTime,
+                    "yyyy-MM-dd'T'HH:mm:ss",
+                    CultureInfo.InvariantCulture,
+                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
+                // TODO: It would be nice not to have to create all these objects... easy to optimize later though.
+                Timestamp timestamp = Timestamp.FromDateTime(parsed);
+                int nanosToAdd = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1), CultureInfo.InvariantCulture);
+                    nanosToAdd = parsedFraction * SubsecondScalingFactors[subseconds.Length];
+                }
+                int secondsToAdd = 0;
+                if (offset != "Z")
+                {
+                    // This is the amount we need to *subtract* from the local time to get to UTC - hence - => +1 and vice versa.
+                    int sign = offset[0] == '-' ? 1 : -1;
+                    int hours = int.Parse(offset.Substring(1, 2), CultureInfo.InvariantCulture);
+                    int minutes = int.Parse(offset.Substring(4, 2));
+                    int totalMinutes = hours * 60 + minutes;
+                    if (totalMinutes > 18 * 60)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    if (totalMinutes == 0 && sign == 1)
+                    {
+                        // This is an offset of -00:00, which means "unknown local offset". It makes no sense for a timestamp.
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    // We need to *subtract* the offset from local time to get UTC.
+                    secondsToAdd = sign * totalMinutes * 60;
+                }
+                // Ensure we've got the right signs. Currently unnecessary, but easy to do.
+                if (secondsToAdd < 0 && nanosToAdd > 0)
+                {
+                    secondsToAdd++;
+                    nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond;
+                }
+                if (secondsToAdd != 0 || nanosToAdd != 0)
+                {
+                    timestamp += new Duration { Nanos = nanosToAdd, Seconds = secondsToAdd };
+                    // The resulting timestamp after offset change would be out of our expected range. Currently the Timestamp message doesn't validate this
+                    // anywhere, but we shouldn't parse it.
+                    if (timestamp.Seconds < Timestamp.UnixSecondsAtBclMinValue || timestamp.Seconds > Timestamp.UnixSecondsAtBclMaxValue)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                }
+                message.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.SetValue(message, timestamp.Seconds);
+                message.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.SetValue(message, timestamp.Nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+            }
+        }
+
+        private static void MergeDuration(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Duration");
+            }
+            var match = DurationRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var sign = match.Groups["sign"].Value;
+            var secondsText = match.Groups["int"].Value;
+            // Prohibit leading insignficant zeroes
+            if (secondsText[0] == '0' && secondsText.Length > 1)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var subseconds = match.Groups["subseconds"].Value;
+            var multiplier = sign == "-" ? -1 : 1;
+
+            try
+            {
+                long seconds = long.Parse(secondsText, CultureInfo.InvariantCulture) * multiplier;
+                int nanos = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1));
+                    nanos = parsedFraction * SubsecondScalingFactors[subseconds.Length] * multiplier;
+                }
+                if (!Duration.IsNormalized(seconds, nanos))
+                {
+                    throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+                }
+                message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.SetValue(message, seconds);
+                message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.SetValue(message, nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+            }
+        }
+
+        private static void MergeFieldMask(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for FieldMask");
+            }
+            // TODO: Do we *want* to remove empty entries? Probably okay to treat "" as "no paths", but "foo,,bar"?
+            string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators, StringSplitOptions.RemoveEmptyEntries);
+            IList messagePaths = (IList) message.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(message);
+            foreach (var path in jsonPaths)
+            {
+                messagePaths.Add(ToSnakeCase(path));
+            }
+        }
+        
+        // Ported from src/google/protobuf/util/internal/utility.cc
+        private static string ToSnakeCase(string text)
+        {
+            var builder = new StringBuilder(text.Length * 2);
+            // Note: this is probably unnecessary now, but currently retained to be as close as possible to the
+            // C++, whilst still throwing an exception on underscores.
+            bool wasNotUnderscore = false;  // Initialize to false for case 1 (below)
+            bool wasNotCap = false;
+
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c >= 'A' && c <= 'Z') // ascii_isupper
+                {
+                    // Consider when the current character B is capitalized:
+                    // 1) At beginning of input:   "B..." => "b..."
+                    //    (e.g. "Biscuit" => "biscuit")
+                    // 2) Following a lowercase:   "...aB..." => "...a_b..."
+                    //    (e.g. "gBike" => "g_bike")
+                    // 3) At the end of input:     "...AB" => "...ab"
+                    //    (e.g. "GoogleLAB" => "google_lab")
+                    // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
+                    //    (e.g. "GBike" => "g_bike")
+                    if (wasNotUnderscore &&               //            case 1 out
+                        (wasNotCap ||                     // case 2 in, case 3 out
+                         (i + 1 < text.Length &&         //            case 3 out
+                          (text[i + 1] >= 'a' && text[i + 1] <= 'z')))) // ascii_islower(text[i + 1])
+                    {  // case 4 in
+                       // We add an underscore for case 2 and case 4.
+                        builder.Append('_');
+                    }
+                    // ascii_tolower, but we already know that c *is* an upper case ASCII character...
+                    builder.Append((char) (c + 'a' - 'A'));
+                    wasNotUnderscore = true;
+                    wasNotCap = false;
+                }
+                else
+                {
+                    builder.Append(c);
+                    if (c == '_')
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid field mask: {text}");
+                    }
+                    wasNotUnderscore = true;
+                    wasNotCap = true;
+                }
+            }
+            return builder.ToString();
+        }
+        #endregion
+
+        /// <summary>
+        /// Settings controlling JSON parsing.
+        /// </summary>
+        public sealed class Settings
+        {
+            /// <summary>
+            /// Default settings, as used by <see cref="JsonParser.Default"/>. This has the same default
+            /// recursion limit as <see cref="CodedInputStream"/>, and an empty type registry.
+            /// </summary>
+            public static Settings Default { get; }
+
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(CodedInputStream.DefaultRecursionLimit);
+            }
+
+            /// <summary>
+            /// The maximum depth of messages to parse. Note that this limit only applies to parsing
+            /// messages, not collections - so a message within a collection within a message only counts as
+            /// depth 2, not 3.
+            /// </summary>
+            public int RecursionLimit { get; }
+
+            /// <summary>
+            /// The type registry used to parse <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            public Settings(int recursionLimit) : this(recursionLimit, TypeRegistry.Empty)
+            {
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit and type registry.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            /// <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param>
+            public Settings(int recursionLimit, TypeRegistry typeRegistry)
+            {
+                RecursionLimit = recursionLimit;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonToken.cs b/csharp/src/Google.Protobuf/JsonToken.cs
new file mode 100644
index 0000000..6c0138c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonToken.cs
@@ -0,0 +1,166 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    internal sealed class JsonToken : IEquatable<JsonToken>
+    {
+        // Tokens with no value can be reused.
+        private static readonly JsonToken _true = new JsonToken(TokenType.True);
+        private static readonly JsonToken _false = new JsonToken(TokenType.False);
+        private static readonly JsonToken _null = new JsonToken(TokenType.Null);
+        private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject);
+        private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject);
+        private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray);
+        private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray);
+        private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument);
+
+        internal static JsonToken Null { get { return _null; } }
+        internal static JsonToken False { get { return _false; } }
+        internal static JsonToken True { get { return _true; } }
+        internal static JsonToken StartObject{ get { return startObject; } }
+        internal static JsonToken EndObject { get { return endObject; } }
+        internal static JsonToken StartArray { get { return startArray; } }
+        internal static JsonToken EndArray { get { return endArray; } }
+        internal static JsonToken EndDocument { get { return endDocument; } }
+
+        internal static JsonToken Name(string name)
+        {
+            return new JsonToken(TokenType.Name, stringValue: name);
+        }
+
+        internal static JsonToken Value(string value)
+        {
+            return new JsonToken(TokenType.StringValue, stringValue: value);
+        }
+
+        internal static JsonToken Value(double value)
+        {
+            return new JsonToken(TokenType.Number, numberValue: value);
+        }
+
+        internal enum TokenType
+        {
+            Null,
+            False,
+            True,
+            StringValue,
+            Number,
+            Name,
+            StartObject,
+            EndObject,
+            StartArray,
+            EndArray,
+            EndDocument
+        }
+
+        // A value is a string, number, array, object, null, true or false
+        // Arrays and objects have start/end
+        // A document consists of a value
+        // Objects are name/value sequences.
+
+        private readonly TokenType type;
+        private readonly string stringValue;
+        private readonly double numberValue;
+
+        internal TokenType Type { get { return type; } }
+        internal string StringValue { get { return stringValue; } }
+        internal double NumberValue { get { return numberValue; } }
+
+        private JsonToken(TokenType type, string stringValue = null, double numberValue = 0)
+        {
+            this.type = type;
+            this.stringValue = stringValue;
+            this.numberValue = numberValue;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as JsonToken);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+                hash = hash * 31 + (int) type;
+                hash = hash * 31 + stringValue == null ? 0 : stringValue.GetHashCode();
+                hash = hash * 31 + numberValue.GetHashCode();
+                return hash;
+            }
+        }
+
+        public override string ToString()
+        {
+            switch (type)
+            {
+                case TokenType.Null:
+                    return "null";
+                case TokenType.True:
+                    return "true";
+                case TokenType.False:
+                    return "false";
+                case TokenType.Name:
+                    return "name (" + stringValue + ")";
+                case TokenType.StringValue:
+                    return "value (" + stringValue + ")";
+                case TokenType.Number:
+                    return "number (" + numberValue + ")";
+                case TokenType.StartObject:
+                    return "start-object";
+                case TokenType.EndObject:
+                    return "end-object";
+                case TokenType.StartArray:
+                    return "start-array";
+                case TokenType.EndArray:
+                    return "end-array";
+                case TokenType.EndDocument:
+                    return "end-document";
+                default:
+                    throw new InvalidOperationException("Token is of unknown type " + type);
+            }
+        }
+
+        public bool Equals(JsonToken other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            // Note use of other.numberValue.Equals rather than ==, so that NaN compares appropriately.
+            return other.type == type && other.stringValue == stringValue && other.numberValue.Equals(numberValue);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
new file mode 100644
index 0000000..09a6d43
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -0,0 +1,738 @@
+#region Copyright notice and license
+// 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.
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Simple but strict JSON tokenizer, rigidly following RFC 7159.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This tokenizer is stateful, and only returns "useful" tokens - names, values etc.
+    /// It does not create tokens for the separator between names and values, or for the comma
+    /// between values. It validates the token stream as it goes - so callers can assume that the
+    /// tokens it produces are appropriate. For example, it would never produce "start object, end array."
+    /// </para>
+    /// <para>Implementation details: the base class handles single token push-back and </para>
+    /// <para>Not thread-safe.</para>
+    /// </remarks>
+    internal abstract class JsonTokenizer
+    {
+        private JsonToken bufferedToken;
+
+        /// <summary>
+        ///  Creates a tokenizer that reads from the given text reader.
+        /// </summary>
+        internal static JsonTokenizer FromTextReader(TextReader reader)
+        {
+            return new JsonTextTokenizer(reader);
+        }
+
+        /// <summary>
+        /// Creates a tokenizer that first replays the given list of tokens, then continues reading
+        /// from another tokenizer. Note that if the returned tokenizer is "pushed back", that does not push back
+        /// on the continuation tokenizer, or vice versa. Care should be taken when using this method - it was
+        /// created for the sake of Any parsing.
+        /// </summary>
+        internal static JsonTokenizer FromReplayedTokens(IList<JsonToken> tokens, JsonTokenizer continuation)
+        {
+            return new JsonReplayTokenizer(tokens, continuation);
+        }
+
+        /// <summary>
+        /// Returns the depth of the stack, purely in objects (not collections).
+        /// Informally, this is the number of remaining unclosed '{' characters we have.
+        /// </summary>
+        internal int ObjectDepth { get; private set; }
+
+        // TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
+        // token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
+        internal void PushBack(JsonToken token)
+        {
+            if (bufferedToken != null)
+            {
+                throw new InvalidOperationException("Can't push back twice");
+            }
+            bufferedToken = token;
+            if (token.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth--;
+            }
+            else if (token.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth++;
+            }
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream. An EndDocument token is returned to indicate the end of the stream,
+        /// after which point <c>Next()</c> should not be called again.
+        /// </summary>
+        /// <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
+        /// <returns>The next token in the stream. This is never null.</returns>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        internal JsonToken Next()
+        {
+            JsonToken tokenToReturn;
+            if (bufferedToken != null)
+            {
+                tokenToReturn = bufferedToken;
+                bufferedToken = null;
+            }
+            else
+            {
+                tokenToReturn = NextImpl();
+            }
+            if (tokenToReturn.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth++;
+            }
+            else if (tokenToReturn.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth--;
+            }
+            return tokenToReturn;
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream, when requested by the base class. (The <see cref="Next"/> method delegates
+        /// to this if it doesn't have a buffered token.)
+        /// </summary>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        protected abstract JsonToken NextImpl();
+
+        /// <summary>
+        /// Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
+        /// </summary>
+        private class JsonReplayTokenizer : JsonTokenizer
+        {
+            private readonly IList<JsonToken> tokens;
+            private readonly JsonTokenizer nextTokenizer;
+            private int nextTokenIndex;
+
+            internal JsonReplayTokenizer(IList<JsonToken> tokens, JsonTokenizer nextTokenizer)
+            {
+                this.tokens = tokens;
+                this.nextTokenizer = nextTokenizer;
+            }
+
+            // FIXME: Object depth not maintained...
+            protected override JsonToken NextImpl()
+            {
+                if (nextTokenIndex >= tokens.Count)
+                {
+                    return nextTokenizer.Next();
+                }
+                return tokens[nextTokenIndex++];
+            }
+        }
+
+        /// <summary>
+        /// Tokenizer which does all the *real* work of parsing JSON.
+        /// </summary>
+        private sealed class JsonTextTokenizer : JsonTokenizer
+        {
+            // The set of states in which a value is valid next token.
+            private static readonly State ValueStates = State.ArrayStart | State.ArrayAfterComma | State.ObjectAfterColon | State.StartOfDocument;
+
+            private readonly Stack<ContainerType> containerStack = new Stack<ContainerType>();
+            private readonly PushBackReader reader;
+            private State state;
+
+            internal JsonTextTokenizer(TextReader reader)
+            {
+                this.reader = new PushBackReader(reader);
+                state = State.StartOfDocument;
+                containerStack.Push(ContainerType.Document);
+            }
+
+            /// <remarks>
+            /// This method essentially just loops through characters skipping whitespace, validating and
+            /// changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
+            /// until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
+            /// it returns the token. Although the method is large, it would be relatively hard to break down further... most
+            /// of it is the large switch statement, which sometimes returns and sometimes doesn't.
+            /// </remarks>
+            protected override JsonToken NextImpl()
+            {
+                if (state == State.ReaderExhausted)
+                {
+                    throw new InvalidOperationException("Next() called after end of document");
+                }
+                while (true)
+                {
+                    var next = reader.Read();
+                    if (next == null)
+                    {
+                        ValidateState(State.ExpectedEndOfDocument, "Unexpected end of document in state: ");
+                        state = State.ReaderExhausted;
+                        return JsonToken.EndDocument;
+                    }
+                    switch (next.Value)
+                    {
+                        // Skip whitespace between tokens
+                        case ' ':
+                        case '\t':
+                        case '\r':
+                        case '\n':
+                            break;
+                        case ':':
+                            ValidateState(State.ObjectBeforeColon, "Invalid state to read a colon: ");
+                            state = State.ObjectAfterColon;
+                            break;
+                        case ',':
+                            ValidateState(State.ObjectAfterProperty | State.ArrayAfterValue, "Invalid state to read a colon: ");
+                            state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
+                            break;
+                        case '"':
+                            string stringValue = ReadString();
+                            if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
+                            {
+                                state = State.ObjectBeforeColon;
+                                return JsonToken.Name(stringValue);
+                            }
+                            else
+                            {
+                                ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
+                                return JsonToken.Value(stringValue);
+                            }
+                        case '{':
+                            ValidateState(ValueStates, "Invalid state to read an open brace: ");
+                            state = State.ObjectStart;
+                            containerStack.Push(ContainerType.Object);
+                            return JsonToken.StartObject;
+                        case '}':
+                            ValidateState(State.ObjectAfterProperty | State.ObjectStart, "Invalid state to read a close brace: ");
+                            PopContainer();
+                            return JsonToken.EndObject;
+                        case '[':
+                            ValidateState(ValueStates, "Invalid state to read an open square bracket: ");
+                            state = State.ArrayStart;
+                            containerStack.Push(ContainerType.Array);
+                            return JsonToken.StartArray;
+                        case ']':
+                            ValidateState(State.ArrayAfterValue | State.ArrayStart, "Invalid state to read a close square bracket: ");
+                            PopContainer();
+                            return JsonToken.EndArray;
+                        case 'n': // Start of null
+                            ConsumeLiteral("null");
+                            ValidateAndModifyStateForValue("Invalid state to read a null literal: ");
+                            return JsonToken.Null;
+                        case 't': // Start of true
+                            ConsumeLiteral("true");
+                            ValidateAndModifyStateForValue("Invalid state to read a true literal: ");
+                            return JsonToken.True;
+                        case 'f': // Start of false
+                            ConsumeLiteral("false");
+                            ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
+                            return JsonToken.False;
+                        case '-': // Start of a number
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
+                            double number = ReadNumber(next.Value);
+                            ValidateAndModifyStateForValue("Invalid state to read a number token: ");
+                            return JsonToken.Value(number);
+                        default:
+                            throw new InvalidJsonException("Invalid first character of token: " + next.Value);
+                    }
+                }
+            }
+
+            private void ValidateState(State validStates, string errorPrefix)
+            {
+                if ((validStates & state) == 0)
+                {
+                    throw reader.CreateException(errorPrefix + state);
+                }
+            }
+
+            /// <summary>
+            /// Reads a string token. It is assumed that the opening " has already been read.
+            /// </summary>
+            private string ReadString()
+            {
+                var value = new StringBuilder();
+                bool haveHighSurrogate = false;
+                while (true)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading string");
+                    if (c < ' ')
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
+                    }
+                    if (c == '"')
+                    {
+                        if (haveHighSurrogate)
+                        {
+                            throw reader.CreateException("Invalid use of surrogate pair code units");
+                        }
+                        return value.ToString();
+                    }
+                    if (c == '\\')
+                    {
+                        c = ReadEscapedCharacter();
+                    }
+                    // TODO: Consider only allowing surrogate pairs that are either both escaped,
+                    // or both not escaped. It would be a very odd text stream that contained a "lone" high surrogate
+                    // followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
+                    if (haveHighSurrogate != char.IsLowSurrogate(c))
+                    {
+                        throw reader.CreateException("Invalid use of surrogate pair code units");
+                    }
+                    haveHighSurrogate = char.IsHighSurrogate(c);
+                    value.Append(c);
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped character. It is assumed that the leading backslash has already been read.
+            /// </summary>
+            private char ReadEscapedCharacter()
+            {
+                char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence");
+                switch (c)
+                {
+                    case 'n':
+                        return '\n';
+                    case '\\':
+                        return '\\';
+                    case 'b':
+                        return '\b';
+                    case 'f':
+                        return '\f';
+                    case 'r':
+                        return '\r';
+                    case 't':
+                        return '\t';
+                    case '"':
+                        return '"';
+                    case '/':
+                        return '/';
+                    case 'u':
+                        return ReadUnicodeEscape();
+                    default:
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped Unicode 4-nybble hex sequence. It is assumed that the leading \u has already been read.
+            /// </summary>
+            private char ReadUnicodeEscape()
+            {
+                int result = 0;
+                for (int i = 0; i < 4; i++)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading Unicode escape sequence");
+                    int nybble;
+                    if (c >= '0' && c <= '9')
+                    {
+                        nybble = c - '0';
+                    }
+                    else if (c >= 'a' && c <= 'f')
+                    {
+                        nybble = c - 'a' + 10;
+                    }
+                    else if (c >= 'A' && c <= 'F')
+                    {
+                        nybble = c - 'A' + 10;
+                    }
+                    else
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                    }
+                    result = (result << 4) + nybble;
+                }
+                return (char) result;
+            }
+
+            /// <summary>
+            /// Consumes a text-only literal, throwing an exception if the read text doesn't match it.
+            /// It is assumed that the first letter of the literal has already been read.
+            /// </summary>
+            private void ConsumeLiteral(string text)
+            {
+                for (int i = 1; i < text.Length; i++)
+                {
+                    char? next = reader.Read();
+                    if (next == null)
+                    {
+                        throw reader.CreateException("Unexpected end of text while reading literal token " + text);
+                    }
+                    if (next.Value != text[i])
+                    {
+                        throw reader.CreateException("Unexpected character while reading literal token " + text);
+                    }
+                }
+            }
+
+            private double ReadNumber(char initialCharacter)
+            {
+                StringBuilder builder = new StringBuilder();
+                if (initialCharacter == '-')
+                {
+                    builder.Append("-");
+                }
+                else
+                {
+                    reader.PushBack(initialCharacter);
+                }
+                // Each method returns the character it read that doesn't belong in that part,
+                // so we know what to do next, including pushing the character back at the end.
+                // null is returned for "end of text".
+                char? next = ReadInt(builder);
+                if (next == '.')
+                {
+                    next = ReadFrac(builder);
+                }
+                if (next == 'e' || next == 'E')
+                {
+                    next = ReadExp(builder);
+                }
+                // If we read a character which wasn't part of the number, push it back so we can read it again
+                // to parse the next token.
+                if (next != null)
+                {
+                    reader.PushBack(next.Value);
+                }
+
+                // TODO: What exception should we throw if the value can't be represented as a double?
+                try
+                {
+                    return double.Parse(builder.ToString(),
+                        NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
+                        CultureInfo.InvariantCulture);
+                }
+                catch (OverflowException)
+                {
+                    throw reader.CreateException("Numeric value out of range: " + builder);
+                }
+            }
+
+            private char? ReadInt(StringBuilder builder)
+            {
+                char first = reader.ReadOrFail("Invalid numeric literal");
+                if (first < '0' || first > '9')
+                {
+                    throw reader.CreateException("Invalid numeric literal");
+                }
+                builder.Append(first);
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (first == '0' && digitCount != 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
+                }
+                return next;
+            }
+
+            private char? ReadFrac(StringBuilder builder)
+            {
+                builder.Append('.'); // Already consumed this
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
+                }
+                return next;
+            }
+
+            private char? ReadExp(StringBuilder builder)
+            {
+                builder.Append('E'); // Already consumed this (or 'e')
+                char? next = reader.Read();
+                if (next == null)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits");
+                }
+                if (next == '-' || next == '+')
+                {
+                    builder.Append(next.Value);
+                }
+                else
+                {
+                    reader.PushBack(next.Value);
+                }
+                int digitCount;
+                next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent without value");
+                }
+                return next;
+            }
+
+            private char? ConsumeDigits(StringBuilder builder, out int count)
+            {
+                count = 0;
+                while (true)
+                {
+                    char? next = reader.Read();
+                    if (next == null || next.Value < '0' || next.Value > '9')
+                    {
+                        return next;
+                    }
+                    count++;
+                    builder.Append(next.Value);
+                }
+            }
+
+            /// <summary>
+            /// Validates that we're in a valid state to read a value (using the given error prefix if necessary)
+            /// and changes the state to the appropriate one, e.g. ObjectAfterColon to ObjectAfterProperty.
+            /// </summary>
+            private void ValidateAndModifyStateForValue(string errorPrefix)
+            {
+                ValidateState(ValueStates, errorPrefix);
+                switch (state)
+                {
+                    case State.StartOfDocument:
+                        state = State.ExpectedEndOfDocument;
+                        return;
+                    case State.ObjectAfterColon:
+                        state = State.ObjectAfterProperty;
+                        return;
+                    case State.ArrayStart:
+                    case State.ArrayAfterComma:
+                        state = State.ArrayAfterValue;
+                        return;
+                    default:
+                        throw new InvalidOperationException("ValidateAndModifyStateForValue does not handle all value states (and should)");
+                }
+            }
+
+            /// <summary>
+            /// Pops the top-most container, and sets the state to the appropriate one for the end of a value
+            /// in the parent container.
+            /// </summary>
+            private void PopContainer()
+            {
+                containerStack.Pop();
+                var parent = containerStack.Peek();
+                switch (parent)
+                {
+                    case ContainerType.Object:
+                        state = State.ObjectAfterProperty;
+                        break;
+                    case ContainerType.Array:
+                        state = State.ArrayAfterValue;
+                        break;
+                    case ContainerType.Document:
+                        state = State.ExpectedEndOfDocument;
+                        break;
+                    default:
+                        throw new InvalidOperationException("Unexpected container type: " + parent);
+                }
+            }
+
+            private enum ContainerType
+            {
+                Document, Object, Array
+            }
+
+            /// <summary>
+            /// Possible states of the tokenizer.
+            /// </summary>
+            /// <remarks>
+            /// <para>This is a flags enum purely so we can simply and efficiently represent a set of valid states
+            /// for checking.</para>
+            /// <para>
+            /// Each is documented with an example,
+            /// where ^ represents the current position within the text stream. The examples all use string values,
+            /// but could be any value, including nested objects/arrays.
+            /// The complete state of the tokenizer also includes a stack to indicate the contexts (arrays/objects).
+            /// Any additional notional state of "AfterValue" indicates that a value has been completed, at which 
+            /// point there's an immediate transition to ExpectedEndOfDocument,  ObjectAfterProperty or ArrayAfterValue.
+            /// </para>
+            /// <para>
+            /// These states were derived manually by reading RFC 7159 carefully.
+            /// </para>
+            /// </remarks>
+            [Flags]
+            private enum State
+            {
+                /// <summary>
+                /// ^ { "foo": "bar" }
+                /// Before the value in a document. Next states: ObjectStart, ArrayStart, "AfterValue"
+                /// </summary>
+                StartOfDocument = 1 << 0,
+                /// <summary>
+                /// { "foo": "bar" } ^
+                /// After the value in a document. Next states: ReaderExhausted
+                /// </summary>
+                ExpectedEndOfDocument = 1 << 1,
+                /// <summary>
+                /// { "foo": "bar" } ^ (and already read to the end of the reader)
+                /// Terminal state.
+                /// </summary>
+                ReaderExhausted = 1 << 2,
+                /// <summary>
+                /// { ^ "foo": "bar" }
+                /// Before the *first* property in an object.
+                /// Next states:
+                /// "AfterValue" (empty object)
+                /// ObjectBeforeColon (read a name)
+                /// </summary>
+                ObjectStart = 1 << 3,
+                /// <summary>
+                /// { "foo" ^ : "bar", "x": "y" }
+                /// Next state: ObjectAfterColon
+                /// </summary>
+                ObjectBeforeColon = 1 << 4,
+                /// <summary>
+                /// { "foo" : ^ "bar", "x": "y" }
+                /// Before any property other than the first in an object.
+                /// (Equivalently: after any property in an object) 
+                /// Next states:
+                /// "AfterValue" (value is simple)
+                /// ObjectStart (value is object)
+                /// ArrayStart (value is array)
+                /// </summary>
+                ObjectAfterColon = 1 << 5,
+                /// <summary>
+                /// { "foo" : "bar" ^ , "x" : "y" }
+                /// At the end of a property, so expecting either a comma or end-of-object
+                /// Next states: ObjectAfterComma or "AfterValue"
+                /// </summary>
+                ObjectAfterProperty = 1 << 6,
+                /// <summary>
+                /// { "foo":"bar", ^ "x":"y" }
+                /// Read the comma after the previous property, so expecting another property.
+                /// This is like ObjectStart, but closing brace isn't valid here
+                /// Next state: ObjectBeforeColon.
+                /// </summary>
+                ObjectAfterComma = 1 << 7,
+                /// <summary>
+                /// [ ^ "foo", "bar" ]
+                /// Before the *first* value in an array.
+                /// Next states:
+                /// "AfterValue" (read a value)
+                /// "AfterValue" (end of array; will pop stack)
+                /// </summary>
+                ArrayStart = 1 << 8,
+                /// <summary>
+                /// [ "foo" ^ , "bar" ]
+                /// After any value in an array, so expecting either a comma or end-of-array
+                /// Next states: ArrayAfterComma or "AfterValue"
+                /// </summary>
+                ArrayAfterValue = 1 << 9,
+                /// <summary>
+                /// [ "foo", ^ "bar" ]
+                /// After a comma in an array, so there *must* be another value (simple or complex).
+                /// Next states: "AfterValue" (simple value), StartObject, StartArray
+                /// </summary>
+                ArrayAfterComma = 1 << 10
+            }
+
+            /// <summary>
+            /// Wrapper around a text reader allowing small amounts of buffering and location handling.
+            /// </summary>
+            private class PushBackReader
+            {
+                // TODO: Add locations for errors etc.
+
+                private readonly TextReader reader;
+
+                internal PushBackReader(TextReader reader)
+                {
+                    // TODO: Wrap the reader in a BufferedReader?
+                    this.reader = reader;
+                }
+
+                /// <summary>
+                /// The buffered next character, if we have one.
+                /// </summary>
+                private char? nextChar;
+
+                /// <summary>
+                /// Returns the next character in the stream, or null if we have reached the end.
+                /// </summary>
+                /// <returns></returns>
+                internal char? Read()
+                {
+                    if (nextChar != null)
+                    {
+                        char? tmp = nextChar;
+                        nextChar = null;
+                        return tmp;
+                    }
+                    int next = reader.Read();
+                    return next == -1 ? null : (char?) next;
+                }
+
+                internal char ReadOrFail(string messageOnFailure)
+                {
+                    char? next = Read();
+                    if (next == null)
+                    {
+                        throw CreateException(messageOnFailure);
+                    }
+                    return next.Value;
+                }
+
+                internal void PushBack(char c)
+                {
+                    if (nextChar != null)
+                    {
+                        throw new InvalidOperationException("Cannot push back when already buffering a character");
+                    }
+                    nextChar = c;
+                }
+
+                /// <summary>
+                /// Creates a new exception appropriate for the current state of the reader.
+                /// </summary>
+                internal InvalidJsonException CreateException(string message)
+                {
+                    // TODO: Keep track of and use the location.
+                    return new InvalidJsonException(message);
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/LimitedInputStream.cs b/csharp/src/Google.Protobuf/LimitedInputStream.cs
new file mode 100644
index 0000000..f11d19d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/LimitedInputStream.cs
@@ -0,0 +1,110 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Stream implementation which proxies another stream, only allowing a certain amount
+    /// of data to be read. Note that this is only used to read delimited streams, so it
+    /// doesn't attempt to implement everything.
+    /// </summary>
+    internal sealed class LimitedInputStream : Stream
+    {
+        private readonly Stream proxied;
+        private int bytesLeft;
+
+        internal LimitedInputStream(Stream proxied, int size)
+        {
+            this.proxied = proxied;
+            bytesLeft = size;
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return false; }
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Length
+        {
+            get { throw new NotSupportedException(); }
+        }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (bytesLeft > 0)
+            {
+                int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
+                bytesLeft -= bytesRead;
+                return bytesRead;
+            }
+            return 0;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
new file mode 100644
index 0000000..047156c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -0,0 +1,157 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
+    /// </summary>
+    public static class MessageExtensions
+    {
+        /// <summary>
+        /// Merges data from the given byte array into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = new CodedInputStream(data);
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given byte string into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = data.CreateCodedInput();
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given stream into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            CodedInputStream codedInput = new CodedInputStream(input);
+            message.MergeFrom(codedInput);
+            codedInput.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges length-delimited data from the given stream into an existing message.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeDelimitedFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            int size = (int) CodedInputStream.ReadRawVarint32(input);
+            Stream limitedStream = new LimitedInputStream(input, size);
+            message.MergeFrom(limitedStream);
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte array in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte array.</returns>
+        public static byte[] ToByteArray(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            byte[] result = new byte[message.CalculateSize()];
+            CodedOutputStream output = new CodedOutputStream(result);
+            message.WriteTo(output);
+            output.CheckNoSpaceLeft();
+            return result;
+        }
+
+        /// <summary>
+        /// Writes the given message data to the given stream in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to write to the stream.</param>
+        /// <param name="output">The stream to write to.</param>
+        public static void WriteTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Writes the length and then data of the given message to a stream.
+        /// </summary>
+        /// <param name="message">The message to write.</param>
+        /// <param name="output">The output stream to write to.</param>
+        public static void WriteDelimitedTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            codedOutput.WriteRawVarint32((uint)message.CalculateSize());
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte string in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte string.</returns>
+        public static ByteString ToByteString(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return ByteString.AttachBytes(message.ToByteArray());
+        }        
+    }
+}
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
new file mode 100644
index 0000000..8889638
--- /dev/null
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -0,0 +1,267 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A general message parser, typically used by reflection-based code as all the methods
+    /// return simple <see cref="IMessage"/>.
+    /// </summary>
+    public class MessageParser
+    {
+        private Func<IMessage> factory;
+
+        internal MessageParser(Func<IMessage> factory)
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal IMessage CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public IMessage ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseDelimitedFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(CodedInputStream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage ParseJson(string json)
+        {
+            IMessage message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
+    }
+
+    /// <summary>
+    /// A parser for a specific message type.
+    /// </summary>
+    /// <remarks>
+    /// <p>
+    /// This delegates most behavior to the
+    /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
+    /// provides convenient overloads to parse from a variety of sources.
+    /// </p>
+    /// <p>
+    /// Most applications will never need to create their own instances of this type;
+    /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
+    /// parser for that type.
+    /// </p>
+    /// </remarks>
+    /// <typeparam name="T">The type of message to be parsed.</typeparam>
+    public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
+    {
+        // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
+        // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
+        // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
+        // The API wouldn't change anyway - just the implementation - so this work can be deferred.
+        private readonly Func<T> factory; 
+
+        /// <summary>
+        /// Creates a new parser.
+        /// </summary>
+        /// <remarks>
+        /// The factory method is effectively an optimization over using a generic constraint
+        /// to require a parameterless constructor: delegates are significantly faster to execute.
+        /// </remarks>
+        /// <param name="factory">Function to invoke when a new, empty message is required.</param>
+        public MessageParser(Func<T> factory) : base(() => factory())
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal new T CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public new T ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseDelimitedFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(CodedInputStream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public new T ParseJson(string json)
+        {
+            T message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0516f18
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+using System.Reflection;

+using System.Runtime.CompilerServices;

+using System.Security;

+

+// General Information about an assembly is controlled through the following 

+// set of attributes. Change these attribute values to modify the information

+// associated with an assembly.

+

+[assembly: AssemblyTitle("Google.Protobuf")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("Google.Protobuf")]

+[assembly: AssemblyCopyright("Copyright ©  2015")]

+[assembly: AssemblyTrademark("")]

+[assembly: AssemblyCulture("")]

+

+#if !NCRUNCH

+[assembly: AllowPartiallyTrustedCallers]

+#endif

+

+#if SIGNED

+[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" +

+    "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" +

+    "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" +

+    "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +

+    "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +

+    "c5ae9cb6")]

+#else

+[assembly: InternalsVisibleTo("Google.Protobuf.Test")]

+#endif

+

+[assembly: AssemblyVersion("3.0.0.0")]

+[assembly: AssemblyFileVersion("3.0.0.0")]

+[assembly: AssemblyInformationalVersion("3.0.0-beta3")]

diff --git a/csharp/src/Google.Protobuf/ProtoPreconditions.cs b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
new file mode 100644
index 0000000..abaeb9b
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods for throwing exceptions when preconditions are not met.
+    /// </summary>
+    /// <remarks>
+    /// This class is used internally and by generated code; it is not particularly
+    /// expected to be used from application code, although nothing prevents it
+    /// from being used that way.
+    /// </remarks>
+    public static class ProtoPreconditions
+    {
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        public static T CheckNotNull<T>(T value, string name) where T : class
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        /// <remarks>
+        /// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
+        /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
+        /// with a value type - but it gets in the way if either you want to use it with a nullable
+        /// value type, or you want to use it with an unconstrained type parameter.
+        /// </remarks>
+        internal static T CheckNotNullUnconstrained<T>(T value, string name)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
new file mode 100644
index 0000000..fa138df
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -0,0 +1,5421 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.Reflection {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/descriptor.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal static partial class DescriptorReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/descriptor.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static DescriptorReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiBnb29nbGUvcHJvdG9idWYvZGVzY3JpcHRvci5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIkcKEUZpbGVEZXNjcmlwdG9yU2V0EjIKBGZpbGUYASADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuRmlsZURlc2NyaXB0b3JQcm90byLbAwoTRmlsZURl",
+            "c2NyaXB0b3JQcm90bxIMCgRuYW1lGAEgASgJEg8KB3BhY2thZ2UYAiABKAkS",
+            "EgoKZGVwZW5kZW5jeRgDIAMoCRIZChFwdWJsaWNfZGVwZW5kZW5jeRgKIAMo",
+            "BRIXCg93ZWFrX2RlcGVuZGVuY3kYCyADKAUSNgoMbWVzc2FnZV90eXBlGAQg",
+            "AygLMiAuZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90bxI3CgllbnVt",
+            "X3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQ",
+            "cm90bxI4CgdzZXJ2aWNlGAYgAygLMicuZ29vZ2xlLnByb3RvYnVmLlNlcnZp",
+            "Y2VEZXNjcmlwdG9yUHJvdG8SOAoJZXh0ZW5zaW9uGAcgAygLMiUuZ29vZ2xl",
+            "LnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvEi0KB29wdGlvbnMYCCAB",
+            "KAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMSOQoQc291cmNlX2Nv",
+            "ZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5m",
+            "bxIOCgZzeW50YXgYDCABKAki8AQKD0Rlc2NyaXB0b3JQcm90bxIMCgRuYW1l",
+            "GAEgASgJEjQKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxk",
+            "RGVzY3JpcHRvclByb3RvEjgKCWV4dGVuc2lvbhgGIAMoCzIlLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90bxI1CgtuZXN0ZWRfdHlwZRgD",
+            "IAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8SNwoJZW51",
+            "bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9y",
+            "UHJvdG8SSAoPZXh0ZW5zaW9uX3JhbmdlGAUgAygLMi8uZ29vZ2xlLnByb3Rv",
+            "YnVmLkRlc2NyaXB0b3JQcm90by5FeHRlbnNpb25SYW5nZRI5CgpvbmVvZl9k",
+            "ZWNsGAggAygLMiUuZ29vZ2xlLnByb3RvYnVmLk9uZW9mRGVzY3JpcHRvclBy",
+            "b3RvEjAKB29wdGlvbnMYByABKAsyHy5nb29nbGUucHJvdG9idWYuTWVzc2Fn",
+            "ZU9wdGlvbnMSRgoOcmVzZXJ2ZWRfcmFuZ2UYCSADKAsyLi5nb29nbGUucHJv",
+            "dG9idWYuRGVzY3JpcHRvclByb3RvLlJlc2VydmVkUmFuZ2USFQoNcmVzZXJ2",
+            "ZWRfbmFtZRgKIAMoCRosCg5FeHRlbnNpb25SYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUaKwoNUmVzZXJ2ZWRSYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUivAUKFEZpZWxkRGVzY3JpcHRvclByb3RvEgwKBG5h",
+            "bWUYASABKAkSDgoGbnVtYmVyGAMgASgFEjoKBWxhYmVsGAQgASgOMisuZ29v",
+            "Z2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsEjgKBHR5",
+            "cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJv",
+            "dG8uVHlwZRIRCgl0eXBlX25hbWUYBiABKAkSEAoIZXh0ZW5kZWUYAiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgHIAEoCRITCgtvbmVvZl9pbmRleBgJIAEoBRIR",
+            "Cglqc29uX25hbWUYCiABKAkSLgoHb3B0aW9ucxgIIAEoCzIdLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZE9wdGlvbnMitgIKBFR5cGUSDwoLVFlQRV9ET1VCTEUQ",
+            "ARIOCgpUWVBFX0ZMT0FUEAISDgoKVFlQRV9JTlQ2NBADEg8KC1RZUEVfVUlO",
+            "VDY0EAQSDgoKVFlQRV9JTlQzMhAFEhAKDFRZUEVfRklYRUQ2NBAGEhAKDFRZ",
+            "UEVfRklYRUQzMhAHEg0KCVRZUEVfQk9PTBAIEg8KC1RZUEVfU1RSSU5HEAkS",
+            "DgoKVFlQRV9HUk9VUBAKEhAKDFRZUEVfTUVTU0FHRRALEg4KClRZUEVfQllU",
+            "RVMQDBIPCgtUWVBFX1VJTlQzMhANEg0KCVRZUEVfRU5VTRAOEhEKDVRZUEVf",
+            "U0ZJWEVEMzIQDxIRCg1UWVBFX1NGSVhFRDY0EBASDwoLVFlQRV9TSU5UMzIQ",
+            "ERIPCgtUWVBFX1NJTlQ2NBASIkMKBUxhYmVsEhIKDkxBQkVMX09QVElPTkFM",
+            "EAESEgoOTEFCRUxfUkVRVUlSRUQQAhISCg5MQUJFTF9SRVBFQVRFRBADIiQK",
+            "FE9uZW9mRGVzY3JpcHRvclByb3RvEgwKBG5hbWUYASABKAkijAEKE0VudW1E",
+            "ZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRI4CgV2YWx1ZRgCIAMoCzIp",
+            "Lmdvb2dsZS5wcm90b2J1Zi5FbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SLQoH",
+            "b3B0aW9ucxgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9ucyJs",
+            "ChhFbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRIOCgZu",
+            "dW1iZXIYAiABKAUSMgoHb3B0aW9ucxgDIAEoCzIhLmdvb2dsZS5wcm90b2J1",
+            "Zi5FbnVtVmFsdWVPcHRpb25zIpABChZTZXJ2aWNlRGVzY3JpcHRvclByb3Rv",
+            "EgwKBG5hbWUYASABKAkSNgoGbWV0aG9kGAIgAygLMiYuZ29vZ2xlLnByb3Rv",
+            "YnVmLk1ldGhvZERlc2NyaXB0b3JQcm90bxIwCgdvcHRpb25zGAMgASgLMh8u",
+            "Z29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zIsEBChVNZXRob2REZXNj",
+            "cmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRISCgppbnB1dF90eXBlGAIgASgJ",
+            "EhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5nb29n",
+            "bGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFtaW5n",
+            "GAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVmYWxz",
+            "ZSKHBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph",
+            "dmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVfZmls",
+            "ZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2FuZF9o",
+            "YXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
+            "ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
+            "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
+            "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
+            "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
+            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
+            "cGFjZRglIAEoCRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6",
+            "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ",
+            "TUUQAyoJCOgHEICAgIACSgQIJhAnIuYBCg5NZXNzYWdlT3B0aW9ucxImChdt",
+            "ZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3Rh",
+            "bmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVw",
+            "cmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVu",
+            "aW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5V",
+            "bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9u",
+            "cxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlv",
+            "bnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYg",
+            "ASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpT",
+            "X05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMg",
+            "ASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJl",
+            "dGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnBy",
+            "ZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoM",
+            "U1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpT",
+            "X1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1P",
+            "cHRpb25zEhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyAB",
+            "KAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
+            "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi",
+            "fQoQRW51bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxz",
+            "ZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJv",
+            "dG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZp",
+            "Y2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50",
+            "ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu",
+            "dGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZ",
+            "CgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w",
+            "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w",
+            "dGlvbioJCOgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5h",
+            "bWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlv",
+            "bi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0",
+            "aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSAB",
+            "KAMSFAoMZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEo",
+            "DBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFt",
+            "ZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNl",
+            "Q29kZUluZm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYu",
+            "U291cmNlQ29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgY",
+            "ASADKAVCAhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVu",
+            "dHMYAyABKAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGlu",
+            "Z19kZXRhY2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUlu",
+            "Zm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5l",
+            "cmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0",
+            "aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyAB",
+            "KAUSCwoDZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2Ny",
+            "aXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90",
+            "b2J1Zi5SZWZsZWN0aW9u"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorSet), global::Google.Protobuf.Reflection.FileDescriptorSet.Parser, new[]{ "File" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorProto), global::Google.Protobuf.Reflection.FileDescriptorProto.Parser, new[]{ "Name", "Package", "Dependency", "PublicDependency", "WeakDependency", "MessageType", "EnumType", "Service", "Extension", "Options", "SourceCodeInfo", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto), global::Google.Protobuf.Reflection.DescriptorProto.Parser, new[]{ "Name", "Field", "Extension", "NestedType", "EnumType", "ExtensionRange", "OneofDecl", "Options", "ReservedRange", "ReservedName" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser, new[]{ "Start", "End" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser, new[]{ "Start", "End" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto), global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser, new[]{ "Name", "Number", "Label", "Type", "TypeName", "Extendee", "DefaultValue", "OneofIndex", "JsonName", "Options" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type), typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.OneofDescriptorProto), global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser, new[]{ "Name" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumDescriptorProto), global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser, new[]{ "Name", "Value", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser, new[]{ "Name", "Method", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser, new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), global::Google.Protobuf.Reflection.MessageOptions.Parser, new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), global::Google.Protobuf.Reflection.EnumValueOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceOptions), global::Google.Protobuf.Reflection.ServiceOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), global::Google.Protobuf.Reflection.MethodOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption), global::Google.Protobuf.Reflection.UninterpretedOption.Parser, new[]{ "Name", "IdentifierValue", "PositiveIntValue", "NegativeIntValue", "DoubleValue", "StringValue", "AggregateValue" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart), global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser, new[]{ "NamePart_", "IsExtension" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo), global::Google.Protobuf.Reflection.SourceCodeInfo.Parser, new[]{ "Location" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location), global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser, new[]{ "Path", "Span", "LeadingComments", "TrailingComments", "LeadingDetachedComments" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Parser, new[]{ "Annotation" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser, new[]{ "Path", "SourceFile", "Begin", "End" }, null, null, null)})
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  The protocol compiler can output a FileDescriptorSet containing the .proto
+  ///  files it parses.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileDescriptorSet : pb::IMessage<FileDescriptorSet> {
+    private static readonly pb::MessageParser<FileDescriptorSet> _parser = new pb::MessageParser<FileDescriptorSet>(() => new FileDescriptorSet());
+    public static pb::MessageParser<FileDescriptorSet> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileDescriptorSet() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileDescriptorSet(FileDescriptorSet other) : this() {
+      file_ = other.file_.Clone();
+    }
+
+    public FileDescriptorSet Clone() {
+      return new FileDescriptorSet(this);
+    }
+
+    /// <summary>Field number for the "file" field.</summary>
+    public const int FileFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FileDescriptorProto> _repeated_file_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.FileDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto> file_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto> File {
+      get { return file_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileDescriptorSet);
+    }
+
+    public bool Equals(FileDescriptorSet other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!file_.Equals(other.file_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= file_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      file_.WriteTo(output, _repeated_file_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += file_.CalculateSize(_repeated_file_codec);
+      return size;
+    }
+
+    public void MergeFrom(FileDescriptorSet other) {
+      if (other == null) {
+        return;
+      }
+      file_.Add(other.file_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            file_.AddEntriesFrom(input, _repeated_file_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a complete .proto file.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileDescriptorProto : pb::IMessage<FileDescriptorProto> {
+    private static readonly pb::MessageParser<FileDescriptorProto> _parser = new pb::MessageParser<FileDescriptorProto>(() => new FileDescriptorProto());
+    public static pb::MessageParser<FileDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileDescriptorProto(FileDescriptorProto other) : this() {
+      name_ = other.name_;
+      package_ = other.package_;
+      dependency_ = other.dependency_.Clone();
+      publicDependency_ = other.publicDependency_.Clone();
+      weakDependency_ = other.weakDependency_.Clone();
+      messageType_ = other.messageType_.Clone();
+      enumType_ = other.enumType_.Clone();
+      service_ = other.service_.Clone();
+      extension_ = other.extension_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      SourceCodeInfo = other.sourceCodeInfo_ != null ? other.SourceCodeInfo.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public FileDescriptorProto Clone() {
+      return new FileDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  file name, relative to root of source tree
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "package" field.</summary>
+    public const int PackageFieldNumber = 2;
+    private string package_ = "";
+    /// <summary>
+    ///  e.g. "foo", "foo.bar", etc.
+    /// </summary>
+    public string Package {
+      get { return package_; }
+      set {
+        package_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "dependency" field.</summary>
+    public const int DependencyFieldNumber = 3;
+    private static readonly pb::FieldCodec<string> _repeated_dependency_codec
+        = pb::FieldCodec.ForString(26);
+    private readonly pbc::RepeatedField<string> dependency_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Names of files imported by this file.
+    /// </summary>
+    public pbc::RepeatedField<string> Dependency {
+      get { return dependency_; }
+    }
+
+    /// <summary>Field number for the "public_dependency" field.</summary>
+    public const int PublicDependencyFieldNumber = 10;
+    private static readonly pb::FieldCodec<int> _repeated_publicDependency_codec
+        = pb::FieldCodec.ForInt32(80);
+    private readonly pbc::RepeatedField<int> publicDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the public imported files in the dependency list above.
+    /// </summary>
+    public pbc::RepeatedField<int> PublicDependency {
+      get { return publicDependency_; }
+    }
+
+    /// <summary>Field number for the "weak_dependency" field.</summary>
+    public const int WeakDependencyFieldNumber = 11;
+    private static readonly pb::FieldCodec<int> _repeated_weakDependency_codec
+        = pb::FieldCodec.ForInt32(88);
+    private readonly pbc::RepeatedField<int> weakDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the weak imported files in the dependency list.
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
+    public pbc::RepeatedField<int> WeakDependency {
+      get { return weakDependency_; }
+    }
+
+    /// <summary>Field number for the "message_type" field.</summary>
+    public const int MessageTypeFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_messageType_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> messageType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto>();
+    /// <summary>
+    ///  All top-level definitions in this file.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> MessageType {
+      get { return messageType_; }
+    }
+
+    /// <summary>Field number for the "enum_type" field.</summary>
+    public const int EnumTypeFieldNumber = 5;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
+        = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> enumType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> EnumType {
+      get { return enumType_; }
+    }
+
+    /// <summary>Field number for the "service" field.</summary>
+    public const int ServiceFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.ServiceDescriptorProto> _repeated_service_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto> service_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto> Service {
+      get { return service_; }
+    }
+
+    /// <summary>Field number for the "extension" field.</summary>
+    public const int ExtensionFieldNumber = 7;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
+        = pb::FieldCodec.ForMessage(58, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> extension_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Extension {
+      get { return extension_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 8;
+    private global::Google.Protobuf.Reflection.FileOptions options_;
+    public global::Google.Protobuf.Reflection.FileOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "source_code_info" field.</summary>
+    public const int SourceCodeInfoFieldNumber = 9;
+    private global::Google.Protobuf.Reflection.SourceCodeInfo sourceCodeInfo_;
+    /// <summary>
+    ///  This field contains optional information about the original source code.
+    ///  You may safely remove this entire field without harming runtime
+    ///  functionality of the descriptors -- the information is needed only by
+    ///  development tools.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.SourceCodeInfo SourceCodeInfo {
+      get { return sourceCodeInfo_; }
+      set {
+        sourceCodeInfo_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 12;
+    private string syntax_ = "";
+    /// <summary>
+    ///  The syntax of the proto file.
+    ///  The supported values are "proto2" and "proto3".
+    /// </summary>
+    public string Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileDescriptorProto);
+    }
+
+    public bool Equals(FileDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Package != other.Package) return false;
+      if(!dependency_.Equals(other.dependency_)) return false;
+      if(!publicDependency_.Equals(other.publicDependency_)) return false;
+      if(!weakDependency_.Equals(other.weakDependency_)) return false;
+      if(!messageType_.Equals(other.messageType_)) return false;
+      if(!enumType_.Equals(other.enumType_)) return false;
+      if(!service_.Equals(other.service_)) return false;
+      if(!extension_.Equals(other.extension_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if (!object.Equals(SourceCodeInfo, other.SourceCodeInfo)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Package.Length != 0) hash ^= Package.GetHashCode();
+      hash ^= dependency_.GetHashCode();
+      hash ^= publicDependency_.GetHashCode();
+      hash ^= weakDependency_.GetHashCode();
+      hash ^= messageType_.GetHashCode();
+      hash ^= enumType_.GetHashCode();
+      hash ^= service_.GetHashCode();
+      hash ^= extension_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      if (sourceCodeInfo_ != null) hash ^= SourceCodeInfo.GetHashCode();
+      if (Syntax.Length != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Package.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Package);
+      }
+      dependency_.WriteTo(output, _repeated_dependency_codec);
+      messageType_.WriteTo(output, _repeated_messageType_codec);
+      enumType_.WriteTo(output, _repeated_enumType_codec);
+      service_.WriteTo(output, _repeated_service_codec);
+      extension_.WriteTo(output, _repeated_extension_codec);
+      if (options_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(Options);
+      }
+      if (sourceCodeInfo_ != null) {
+        output.WriteRawTag(74);
+        output.WriteMessage(SourceCodeInfo);
+      }
+      publicDependency_.WriteTo(output, _repeated_publicDependency_codec);
+      weakDependency_.WriteTo(output, _repeated_weakDependency_codec);
+      if (Syntax.Length != 0) {
+        output.WriteRawTag(98);
+        output.WriteString(Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Package.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Package);
+      }
+      size += dependency_.CalculateSize(_repeated_dependency_codec);
+      size += publicDependency_.CalculateSize(_repeated_publicDependency_codec);
+      size += weakDependency_.CalculateSize(_repeated_weakDependency_codec);
+      size += messageType_.CalculateSize(_repeated_messageType_codec);
+      size += enumType_.CalculateSize(_repeated_enumType_codec);
+      size += service_.CalculateSize(_repeated_service_codec);
+      size += extension_.CalculateSize(_repeated_extension_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      if (sourceCodeInfo_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceCodeInfo);
+      }
+      if (Syntax.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(FileDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Package.Length != 0) {
+        Package = other.Package;
+      }
+      dependency_.Add(other.dependency_);
+      publicDependency_.Add(other.publicDependency_);
+      weakDependency_.Add(other.weakDependency_);
+      messageType_.Add(other.messageType_);
+      enumType_.Add(other.enumType_);
+      service_.Add(other.service_);
+      extension_.Add(other.extension_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.FileOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      if (other.sourceCodeInfo_ != null) {
+        if (sourceCodeInfo_ == null) {
+          sourceCodeInfo_ = new global::Google.Protobuf.Reflection.SourceCodeInfo();
+        }
+        SourceCodeInfo.MergeFrom(other.SourceCodeInfo);
+      }
+      if (other.Syntax.Length != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Package = input.ReadString();
+            break;
+          }
+          case 26: {
+            dependency_.AddEntriesFrom(input, _repeated_dependency_codec);
+            break;
+          }
+          case 34: {
+            messageType_.AddEntriesFrom(input, _repeated_messageType_codec);
+            break;
+          }
+          case 42: {
+            enumType_.AddEntriesFrom(input, _repeated_enumType_codec);
+            break;
+          }
+          case 50: {
+            service_.AddEntriesFrom(input, _repeated_service_codec);
+            break;
+          }
+          case 58: {
+            extension_.AddEntriesFrom(input, _repeated_extension_codec);
+            break;
+          }
+          case 66: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.FileOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 74: {
+            if (sourceCodeInfo_ == null) {
+              sourceCodeInfo_ = new global::Google.Protobuf.Reflection.SourceCodeInfo();
+            }
+            input.ReadMessage(sourceCodeInfo_);
+            break;
+          }
+          case 82:
+          case 80: {
+            publicDependency_.AddEntriesFrom(input, _repeated_publicDependency_codec);
+            break;
+          }
+          case 90:
+          case 88: {
+            weakDependency_.AddEntriesFrom(input, _repeated_weakDependency_codec);
+            break;
+          }
+          case 98: {
+            Syntax = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class DescriptorProto : pb::IMessage<DescriptorProto> {
+    private static readonly pb::MessageParser<DescriptorProto> _parser = new pb::MessageParser<DescriptorProto>(() => new DescriptorProto());
+    public static pb::MessageParser<DescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DescriptorProto(DescriptorProto other) : this() {
+      name_ = other.name_;
+      field_ = other.field_.Clone();
+      extension_ = other.extension_.Clone();
+      nestedType_ = other.nestedType_.Clone();
+      enumType_ = other.enumType_.Clone();
+      extensionRange_ = other.extensionRange_.Clone();
+      oneofDecl_ = other.oneofDecl_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      reservedRange_ = other.reservedRange_.Clone();
+      reservedName_ = other.reservedName_.Clone();
+    }
+
+    public DescriptorProto Clone() {
+      return new DescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "field" field.</summary>
+    public const int FieldFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_field_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> field_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Field {
+      get { return field_; }
+    }
+
+    /// <summary>Field number for the "extension" field.</summary>
+    public const int ExtensionFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> extension_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Extension {
+      get { return extension_; }
+    }
+
+    /// <summary>Field number for the "nested_type" field.</summary>
+    public const int NestedTypeFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_nestedType_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> nestedType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> NestedType {
+      get { return nestedType_; }
+    }
+
+    /// <summary>Field number for the "enum_type" field.</summary>
+    public const int EnumTypeFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> enumType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> EnumType {
+      get { return enumType_; }
+    }
+
+    /// <summary>Field number for the "extension_range" field.</summary>
+    public const int ExtensionRangeFieldNumber = 5;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> _repeated_extensionRange_codec
+        = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> extensionRange_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> ExtensionRange {
+      get { return extensionRange_; }
+    }
+
+    /// <summary>Field number for the "oneof_decl" field.</summary>
+    public const int OneofDeclFieldNumber = 8;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.OneofDescriptorProto> _repeated_oneofDecl_codec
+        = pb::FieldCodec.ForMessage(66, global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto> oneofDecl_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto> OneofDecl {
+      get { return oneofDecl_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 7;
+    private global::Google.Protobuf.Reflection.MessageOptions options_;
+    public global::Google.Protobuf.Reflection.MessageOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "reserved_range" field.</summary>
+    public const int ReservedRangeFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> _repeated_reservedRange_codec
+        = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> reservedRange_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> ReservedRange {
+      get { return reservedRange_; }
+    }
+
+    /// <summary>Field number for the "reserved_name" field.</summary>
+    public const int ReservedNameFieldNumber = 10;
+    private static readonly pb::FieldCodec<string> _repeated_reservedName_codec
+        = pb::FieldCodec.ForString(82);
+    private readonly pbc::RepeatedField<string> reservedName_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Reserved field names, which may not be used by fields in the same message.
+    ///  A given name may only be reserved once.
+    /// </summary>
+    public pbc::RepeatedField<string> ReservedName {
+      get { return reservedName_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DescriptorProto);
+    }
+
+    public bool Equals(DescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!field_.Equals(other.field_)) return false;
+      if(!extension_.Equals(other.extension_)) return false;
+      if(!nestedType_.Equals(other.nestedType_)) return false;
+      if(!enumType_.Equals(other.enumType_)) return false;
+      if(!extensionRange_.Equals(other.extensionRange_)) return false;
+      if(!oneofDecl_.Equals(other.oneofDecl_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if(!reservedRange_.Equals(other.reservedRange_)) return false;
+      if(!reservedName_.Equals(other.reservedName_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= field_.GetHashCode();
+      hash ^= extension_.GetHashCode();
+      hash ^= nestedType_.GetHashCode();
+      hash ^= enumType_.GetHashCode();
+      hash ^= extensionRange_.GetHashCode();
+      hash ^= oneofDecl_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      hash ^= reservedRange_.GetHashCode();
+      hash ^= reservedName_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      field_.WriteTo(output, _repeated_field_codec);
+      nestedType_.WriteTo(output, _repeated_nestedType_codec);
+      enumType_.WriteTo(output, _repeated_enumType_codec);
+      extensionRange_.WriteTo(output, _repeated_extensionRange_codec);
+      extension_.WriteTo(output, _repeated_extension_codec);
+      if (options_ != null) {
+        output.WriteRawTag(58);
+        output.WriteMessage(Options);
+      }
+      oneofDecl_.WriteTo(output, _repeated_oneofDecl_codec);
+      reservedRange_.WriteTo(output, _repeated_reservedRange_codec);
+      reservedName_.WriteTo(output, _repeated_reservedName_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += field_.CalculateSize(_repeated_field_codec);
+      size += extension_.CalculateSize(_repeated_extension_codec);
+      size += nestedType_.CalculateSize(_repeated_nestedType_codec);
+      size += enumType_.CalculateSize(_repeated_enumType_codec);
+      size += extensionRange_.CalculateSize(_repeated_extensionRange_codec);
+      size += oneofDecl_.CalculateSize(_repeated_oneofDecl_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      size += reservedRange_.CalculateSize(_repeated_reservedRange_codec);
+      size += reservedName_.CalculateSize(_repeated_reservedName_codec);
+      return size;
+    }
+
+    public void MergeFrom(DescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      field_.Add(other.field_);
+      extension_.Add(other.extension_);
+      nestedType_.Add(other.nestedType_);
+      enumType_.Add(other.enumType_);
+      extensionRange_.Add(other.extensionRange_);
+      oneofDecl_.Add(other.oneofDecl_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.MessageOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      reservedRange_.Add(other.reservedRange_);
+      reservedName_.Add(other.reservedName_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            field_.AddEntriesFrom(input, _repeated_field_codec);
+            break;
+          }
+          case 26: {
+            nestedType_.AddEntriesFrom(input, _repeated_nestedType_codec);
+            break;
+          }
+          case 34: {
+            enumType_.AddEntriesFrom(input, _repeated_enumType_codec);
+            break;
+          }
+          case 42: {
+            extensionRange_.AddEntriesFrom(input, _repeated_extensionRange_codec);
+            break;
+          }
+          case 50: {
+            extension_.AddEntriesFrom(input, _repeated_extension_codec);
+            break;
+          }
+          case 58: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.MessageOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 66: {
+            oneofDecl_.AddEntriesFrom(input, _repeated_oneofDecl_codec);
+            break;
+          }
+          case 74: {
+            reservedRange_.AddEntriesFrom(input, _repeated_reservedRange_codec);
+            break;
+          }
+          case 82: {
+            reservedName_.AddEntriesFrom(input, _repeated_reservedName_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the DescriptorProto message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class ExtensionRange : pb::IMessage<ExtensionRange> {
+        private static readonly pb::MessageParser<ExtensionRange> _parser = new pb::MessageParser<ExtensionRange>(() => new ExtensionRange());
+        public static pb::MessageParser<ExtensionRange> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.DescriptorProto.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public ExtensionRange() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public ExtensionRange(ExtensionRange other) : this() {
+          start_ = other.start_;
+          end_ = other.end_;
+        }
+
+        public ExtensionRange Clone() {
+          return new ExtensionRange(this);
+        }
+
+        /// <summary>Field number for the "start" field.</summary>
+        public const int StartFieldNumber = 1;
+        private int start_;
+        public int Start {
+          get { return start_; }
+          set {
+            start_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 2;
+        private int end_;
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as ExtensionRange);
+        }
+
+        public bool Equals(ExtensionRange other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Start != other.Start) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Start != 0) hash ^= Start.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Start != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Start);
+          }
+          if (End != 0) {
+            output.WriteRawTag(16);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Start != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Start);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(ExtensionRange other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Start != 0) {
+            Start = other.Start;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Start = input.ReadInt32();
+                break;
+              }
+              case 16: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+      /// <summary>
+      ///  Range of reserved tag numbers. Reserved tag numbers may not be used by
+      ///  fields or extension ranges in the same message. Reserved ranges may
+      ///  not overlap.
+      /// </summary>
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class ReservedRange : pb::IMessage<ReservedRange> {
+        private static readonly pb::MessageParser<ReservedRange> _parser = new pb::MessageParser<ReservedRange>(() => new ReservedRange());
+        public static pb::MessageParser<ReservedRange> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.DescriptorProto.Descriptor.NestedTypes[1]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public ReservedRange() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public ReservedRange(ReservedRange other) : this() {
+          start_ = other.start_;
+          end_ = other.end_;
+        }
+
+        public ReservedRange Clone() {
+          return new ReservedRange(this);
+        }
+
+        /// <summary>Field number for the "start" field.</summary>
+        public const int StartFieldNumber = 1;
+        private int start_;
+        /// <summary>
+        ///  Inclusive.
+        /// </summary>
+        public int Start {
+          get { return start_; }
+          set {
+            start_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 2;
+        private int end_;
+        /// <summary>
+        ///  Exclusive.
+        /// </summary>
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as ReservedRange);
+        }
+
+        public bool Equals(ReservedRange other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Start != other.Start) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Start != 0) hash ^= Start.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Start != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Start);
+          }
+          if (End != 0) {
+            output.WriteRawTag(16);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Start != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Start);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(ReservedRange other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Start != 0) {
+            Start = other.Start;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Start = input.ReadInt32();
+                break;
+              }
+              case 16: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes a field within a message.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FieldDescriptorProto : pb::IMessage<FieldDescriptorProto> {
+    private static readonly pb::MessageParser<FieldDescriptorProto> _parser = new pb::MessageParser<FieldDescriptorProto>(() => new FieldDescriptorProto());
+    public static pb::MessageParser<FieldDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldDescriptorProto(FieldDescriptorProto other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      label_ = other.label_;
+      type_ = other.type_;
+      typeName_ = other.typeName_;
+      extendee_ = other.extendee_;
+      defaultValue_ = other.defaultValue_;
+      oneofIndex_ = other.oneofIndex_;
+      jsonName_ = other.jsonName_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public FieldDescriptorProto Clone() {
+      return new FieldDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 3;
+    private int number_;
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "label" field.</summary>
+    public const int LabelFieldNumber = 4;
+    private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label label_ = 0;
+    public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label Label {
+      get { return label_; }
+      set {
+        label_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "type" field.</summary>
+    public const int TypeFieldNumber = 5;
+    private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type type_ = 0;
+    /// <summary>
+    ///  If type_name is set, this need not be set.  If both this and type_name
+    ///  are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type Type {
+      get { return type_; }
+      set {
+        type_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "type_name" field.</summary>
+    public const int TypeNameFieldNumber = 6;
+    private string typeName_ = "";
+    /// <summary>
+    ///  For message and enum types, this is the name of the type.  If the name
+    ///  starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+    ///  rules are used to find the type (i.e. first the nested types within this
+    ///  message are searched, then within the parent, on up to the root
+    ///  namespace).
+    /// </summary>
+    public string TypeName {
+      get { return typeName_; }
+      set {
+        typeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "extendee" field.</summary>
+    public const int ExtendeeFieldNumber = 2;
+    private string extendee_ = "";
+    /// <summary>
+    ///  For extensions, this is the name of the type being extended.  It is
+    ///  resolved in the same manner as type_name.
+    /// </summary>
+    public string Extendee {
+      get { return extendee_; }
+      set {
+        extendee_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "default_value" field.</summary>
+    public const int DefaultValueFieldNumber = 7;
+    private string defaultValue_ = "";
+    /// <summary>
+    ///  For numeric types, contains the original text representation of the value.
+    ///  For booleans, "true" or "false".
+    ///  For strings, contains the default text contents (not escaped in any way).
+    ///  For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+    ///  TODO(kenton):  Base-64 encode?
+    /// </summary>
+    public string DefaultValue {
+      get { return defaultValue_; }
+      set {
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "oneof_index" field.</summary>
+    public const int OneofIndexFieldNumber = 9;
+    private int oneofIndex_;
+    /// <summary>
+    ///  If set, gives the index of a oneof in the containing type's oneof_decl
+    ///  list.  This field is a member of that oneof.
+    /// </summary>
+    public int OneofIndex {
+      get { return oneofIndex_; }
+      set {
+        oneofIndex_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  JSON name of this field. The value is set by protocol compiler. If the
+    ///  user has set a "json_name" option on this field, that option's value
+    ///  will be used. Otherwise, it's deduced from the field's name by converting
+    ///  it to camelCase.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 8;
+    private global::Google.Protobuf.Reflection.FieldOptions options_;
+    public global::Google.Protobuf.Reflection.FieldOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldDescriptorProto);
+    }
+
+    public bool Equals(FieldDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if (Label != other.Label) return false;
+      if (Type != other.Type) return false;
+      if (TypeName != other.TypeName) return false;
+      if (Extendee != other.Extendee) return false;
+      if (DefaultValue != other.DefaultValue) return false;
+      if (OneofIndex != other.OneofIndex) return false;
+      if (JsonName != other.JsonName) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (Label != 0) hash ^= Label.GetHashCode();
+      if (Type != 0) hash ^= Type.GetHashCode();
+      if (TypeName.Length != 0) hash ^= TypeName.GetHashCode();
+      if (Extendee.Length != 0) hash ^= Extendee.GetHashCode();
+      if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
+      if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Extendee.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Extendee);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(24);
+        output.WriteInt32(Number);
+      }
+      if (Label != 0) {
+        output.WriteRawTag(32);
+        output.WriteEnum((int) Label);
+      }
+      if (Type != 0) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) Type);
+      }
+      if (TypeName.Length != 0) {
+        output.WriteRawTag(50);
+        output.WriteString(TypeName);
+      }
+      if (DefaultValue.Length != 0) {
+        output.WriteRawTag(58);
+        output.WriteString(DefaultValue);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(Options);
+      }
+      if (OneofIndex != 0) {
+        output.WriteRawTag(72);
+        output.WriteInt32(OneofIndex);
+      }
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (Label != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Label);
+      }
+      if (Type != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
+      }
+      if (TypeName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeName);
+      }
+      if (Extendee.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Extendee);
+      }
+      if (DefaultValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
+      }
+      if (OneofIndex != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofIndex);
+      }
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(FieldDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.Label != 0) {
+        Label = other.Label;
+      }
+      if (other.Type != 0) {
+        Type = other.Type;
+      }
+      if (other.TypeName.Length != 0) {
+        TypeName = other.TypeName;
+      }
+      if (other.Extendee.Length != 0) {
+        Extendee = other.Extendee;
+      }
+      if (other.DefaultValue.Length != 0) {
+        DefaultValue = other.DefaultValue;
+      }
+      if (other.OneofIndex != 0) {
+        OneofIndex = other.OneofIndex;
+      }
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.FieldOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Extendee = input.ReadString();
+            break;
+          }
+          case 24: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 32: {
+            label_ = (global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) input.ReadEnum();
+            break;
+          }
+          case 40: {
+            type_ = (global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type) input.ReadEnum();
+            break;
+          }
+          case 50: {
+            TypeName = input.ReadString();
+            break;
+          }
+          case 58: {
+            DefaultValue = input.ReadString();
+            break;
+          }
+          case 66: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.FieldOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 72: {
+            OneofIndex = input.ReadInt32();
+            break;
+          }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FieldDescriptorProto message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      internal enum Type {
+        /// <summary>
+        ///  0 is reserved for errors.
+        ///  Order is weird for historical reasons.
+        /// </summary>
+        [pbr::OriginalName("TYPE_DOUBLE")] Double = 1,
+        [pbr::OriginalName("TYPE_FLOAT")] Float = 2,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+        ///  negative values are likely.
+        /// </summary>
+        [pbr::OriginalName("TYPE_INT64")] Int64 = 3,
+        [pbr::OriginalName("TYPE_UINT64")] Uint64 = 4,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+        ///  negative values are likely.
+        /// </summary>
+        [pbr::OriginalName("TYPE_INT32")] Int32 = 5,
+        [pbr::OriginalName("TYPE_FIXED64")] Fixed64 = 6,
+        [pbr::OriginalName("TYPE_FIXED32")] Fixed32 = 7,
+        [pbr::OriginalName("TYPE_BOOL")] Bool = 8,
+        [pbr::OriginalName("TYPE_STRING")] String = 9,
+        /// <summary>
+        ///  Tag-delimited aggregate.
+        /// </summary>
+        [pbr::OriginalName("TYPE_GROUP")] Group = 10,
+        /// <summary>
+        ///  Length-delimited aggregate.
+        /// </summary>
+        [pbr::OriginalName("TYPE_MESSAGE")] Message = 11,
+        /// <summary>
+        ///  New in version 2.
+        /// </summary>
+        [pbr::OriginalName("TYPE_BYTES")] Bytes = 12,
+        [pbr::OriginalName("TYPE_UINT32")] Uint32 = 13,
+        [pbr::OriginalName("TYPE_ENUM")] Enum = 14,
+        [pbr::OriginalName("TYPE_SFIXED32")] Sfixed32 = 15,
+        [pbr::OriginalName("TYPE_SFIXED64")] Sfixed64 = 16,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SINT32")] Sint32 = 17,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SINT64")] Sint64 = 18,
+      }
+
+      internal enum Label {
+        /// <summary>
+        ///  0 is reserved for errors
+        /// </summary>
+        [pbr::OriginalName("LABEL_OPTIONAL")] Optional = 1,
+        [pbr::OriginalName("LABEL_REQUIRED")] Required = 2,
+        /// <summary>
+        ///  TODO(sanjay): Should we add LABEL_MAP?
+        /// </summary>
+        [pbr::OriginalName("LABEL_REPEATED")] Repeated = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes a oneof.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class OneofDescriptorProto : pb::IMessage<OneofDescriptorProto> {
+    private static readonly pb::MessageParser<OneofDescriptorProto> _parser = new pb::MessageParser<OneofDescriptorProto>(() => new OneofDescriptorProto());
+    public static pb::MessageParser<OneofDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public OneofDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public OneofDescriptorProto(OneofDescriptorProto other) : this() {
+      name_ = other.name_;
+    }
+
+    public OneofDescriptorProto Clone() {
+      return new OneofDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as OneofDescriptorProto);
+    }
+
+    public bool Equals(OneofDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      return size;
+    }
+
+    public void MergeFrom(OneofDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes an enum type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumDescriptorProto : pb::IMessage<EnumDescriptorProto> {
+    private static readonly pb::MessageParser<EnumDescriptorProto> _parser = new pb::MessageParser<EnumDescriptorProto>(() => new EnumDescriptorProto());
+    public static pb::MessageParser<EnumDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumDescriptorProto(EnumDescriptorProto other) : this() {
+      name_ = other.name_;
+      value_ = other.value_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public EnumDescriptorProto Clone() {
+      return new EnumDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> _repeated_value_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> value_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> Value {
+      get { return value_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.EnumOptions options_;
+    public global::Google.Protobuf.Reflection.EnumOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumDescriptorProto);
+    }
+
+    public bool Equals(EnumDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!value_.Equals(other.value_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= value_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      value_.WriteTo(output, _repeated_value_codec);
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += value_.CalculateSize(_repeated_value_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(EnumDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      value_.Add(other.value_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.EnumOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            value_.AddEntriesFrom(input, _repeated_value_codec);
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.EnumOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a value within an enum.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumValueDescriptorProto : pb::IMessage<EnumValueDescriptorProto> {
+    private static readonly pb::MessageParser<EnumValueDescriptorProto> _parser = new pb::MessageParser<EnumValueDescriptorProto>(() => new EnumValueDescriptorProto());
+    public static pb::MessageParser<EnumValueDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValueDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValueDescriptorProto(EnumValueDescriptorProto other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public EnumValueDescriptorProto Clone() {
+      return new EnumValueDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 2;
+    private int number_;
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.EnumValueOptions options_;
+    public global::Google.Protobuf.Reflection.EnumValueOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValueDescriptorProto);
+    }
+
+    public bool Equals(EnumValueDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Number);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(EnumValueDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.EnumValueOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 16: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.EnumValueOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class ServiceDescriptorProto : pb::IMessage<ServiceDescriptorProto> {
+    private static readonly pb::MessageParser<ServiceDescriptorProto> _parser = new pb::MessageParser<ServiceDescriptorProto>(() => new ServiceDescriptorProto());
+    public static pb::MessageParser<ServiceDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ServiceDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ServiceDescriptorProto(ServiceDescriptorProto other) : this() {
+      name_ = other.name_;
+      method_ = other.method_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public ServiceDescriptorProto Clone() {
+      return new ServiceDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "method" field.</summary>
+    public const int MethodFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.MethodDescriptorProto> _repeated_method_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto> method_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto> Method {
+      get { return method_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.ServiceOptions options_;
+    public global::Google.Protobuf.Reflection.ServiceOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ServiceDescriptorProto);
+    }
+
+    public bool Equals(ServiceDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!method_.Equals(other.method_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= method_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      method_.WriteTo(output, _repeated_method_codec);
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += method_.CalculateSize(_repeated_method_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ServiceDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      method_.Add(other.method_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.ServiceOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            method_.AddEntriesFrom(input, _repeated_method_codec);
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.ServiceOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a method of a service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MethodDescriptorProto : pb::IMessage<MethodDescriptorProto> {
+    private static readonly pb::MessageParser<MethodDescriptorProto> _parser = new pb::MessageParser<MethodDescriptorProto>(() => new MethodDescriptorProto());
+    public static pb::MessageParser<MethodDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[8]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MethodDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MethodDescriptorProto(MethodDescriptorProto other) : this() {
+      name_ = other.name_;
+      inputType_ = other.inputType_;
+      outputType_ = other.outputType_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      clientStreaming_ = other.clientStreaming_;
+      serverStreaming_ = other.serverStreaming_;
+    }
+
+    public MethodDescriptorProto Clone() {
+      return new MethodDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "input_type" field.</summary>
+    public const int InputTypeFieldNumber = 2;
+    private string inputType_ = "";
+    /// <summary>
+    ///  Input and output type names.  These are resolved in the same way as
+    ///  FieldDescriptorProto.type_name, but must refer to a message type.
+    /// </summary>
+    public string InputType {
+      get { return inputType_; }
+      set {
+        inputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "output_type" field.</summary>
+    public const int OutputTypeFieldNumber = 3;
+    private string outputType_ = "";
+    public string OutputType {
+      get { return outputType_; }
+      set {
+        outputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 4;
+    private global::Google.Protobuf.Reflection.MethodOptions options_;
+    public global::Google.Protobuf.Reflection.MethodOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "client_streaming" field.</summary>
+    public const int ClientStreamingFieldNumber = 5;
+    private bool clientStreaming_;
+    /// <summary>
+    ///  Identifies if client streams multiple client messages
+    /// </summary>
+    public bool ClientStreaming {
+      get { return clientStreaming_; }
+      set {
+        clientStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "server_streaming" field.</summary>
+    public const int ServerStreamingFieldNumber = 6;
+    private bool serverStreaming_;
+    /// <summary>
+    ///  Identifies if server streams multiple server messages
+    /// </summary>
+    public bool ServerStreaming {
+      get { return serverStreaming_; }
+      set {
+        serverStreaming_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MethodDescriptorProto);
+    }
+
+    public bool Equals(MethodDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (InputType != other.InputType) return false;
+      if (OutputType != other.OutputType) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if (ClientStreaming != other.ClientStreaming) return false;
+      if (ServerStreaming != other.ServerStreaming) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (InputType.Length != 0) hash ^= InputType.GetHashCode();
+      if (OutputType.Length != 0) hash ^= OutputType.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      if (ClientStreaming != false) hash ^= ClientStreaming.GetHashCode();
+      if (ServerStreaming != false) hash ^= ServerStreaming.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (InputType.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(InputType);
+      }
+      if (OutputType.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(OutputType);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(Options);
+      }
+      if (ClientStreaming != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(ClientStreaming);
+      }
+      if (ServerStreaming != false) {
+        output.WriteRawTag(48);
+        output.WriteBool(ServerStreaming);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (InputType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(InputType);
+      }
+      if (OutputType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(OutputType);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      if (ClientStreaming != false) {
+        size += 1 + 1;
+      }
+      if (ServerStreaming != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(MethodDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.InputType.Length != 0) {
+        InputType = other.InputType;
+      }
+      if (other.OutputType.Length != 0) {
+        OutputType = other.OutputType;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.MethodOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      if (other.ClientStreaming != false) {
+        ClientStreaming = other.ClientStreaming;
+      }
+      if (other.ServerStreaming != false) {
+        ServerStreaming = other.ServerStreaming;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            InputType = input.ReadString();
+            break;
+          }
+          case 26: {
+            OutputType = input.ReadString();
+            break;
+          }
+          case 34: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.MethodOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 40: {
+            ClientStreaming = input.ReadBool();
+            break;
+          }
+          case 48: {
+            ServerStreaming = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileOptions : pb::IMessage<FileOptions> {
+    private static readonly pb::MessageParser<FileOptions> _parser = new pb::MessageParser<FileOptions>(() => new FileOptions());
+    public static pb::MessageParser<FileOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[9]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileOptions(FileOptions other) : this() {
+      javaPackage_ = other.javaPackage_;
+      javaOuterClassname_ = other.javaOuterClassname_;
+      javaMultipleFiles_ = other.javaMultipleFiles_;
+      javaGenerateEqualsAndHash_ = other.javaGenerateEqualsAndHash_;
+      javaStringCheckUtf8_ = other.javaStringCheckUtf8_;
+      optimizeFor_ = other.optimizeFor_;
+      goPackage_ = other.goPackage_;
+      ccGenericServices_ = other.ccGenericServices_;
+      javaGenericServices_ = other.javaGenericServices_;
+      pyGenericServices_ = other.pyGenericServices_;
+      deprecated_ = other.deprecated_;
+      ccEnableArenas_ = other.ccEnableArenas_;
+      objcClassPrefix_ = other.objcClassPrefix_;
+      csharpNamespace_ = other.csharpNamespace_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public FileOptions Clone() {
+      return new FileOptions(this);
+    }
+
+    /// <summary>Field number for the "java_package" field.</summary>
+    public const int JavaPackageFieldNumber = 1;
+    private string javaPackage_ = "";
+    /// <summary>
+    ///  Sets the Java package where classes generated from this .proto will be
+    ///  placed.  By default, the proto package is used, but this is often
+    ///  inappropriate because proto packages do not normally start with backwards
+    ///  domain names.
+    /// </summary>
+    public string JavaPackage {
+      get { return javaPackage_; }
+      set {
+        javaPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "java_outer_classname" field.</summary>
+    public const int JavaOuterClassnameFieldNumber = 8;
+    private string javaOuterClassname_ = "";
+    /// <summary>
+    ///  If set, all the classes from the .proto file are wrapped in a single
+    ///  outer class with the given name.  This applies to both Proto1
+    ///  (equivalent to the old "--one_java_file" option) and Proto2 (where
+    ///  a .proto always translates to a single class, but you may want to
+    ///  explicitly choose the class name).
+    /// </summary>
+    public string JavaOuterClassname {
+      get { return javaOuterClassname_; }
+      set {
+        javaOuterClassname_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "java_multiple_files" field.</summary>
+    public const int JavaMultipleFilesFieldNumber = 10;
+    private bool javaMultipleFiles_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate a separate .java
+    ///  file for each top-level message, enum, and service defined in the .proto
+    ///  file.  Thus, these types will *not* be nested inside the outer class
+    ///  named by java_outer_classname.  However, the outer class will still be
+    ///  generated to contain the file's getDescriptor() method as well as any
+    ///  top-level extensions defined in the file.
+    /// </summary>
+    public bool JavaMultipleFiles {
+      get { return javaMultipleFiles_; }
+      set {
+        javaMultipleFiles_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_generate_equals_and_hash" field.</summary>
+    public const int JavaGenerateEqualsAndHashFieldNumber = 20;
+    private bool javaGenerateEqualsAndHash_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate equals() and
+    ///  hashCode() methods for all messages defined in the .proto file.
+    ///  This increases generated code size, potentially substantially for large
+    ///  protos, which may harm a memory-constrained application.
+    ///  - In the full runtime this is a speed optimization, as the
+    ///  AbstractMessage base class includes reflection-based implementations of
+    ///  these methods.
+    ///  - In the lite runtime, setting this option changes the semantics of
+    ///  equals() and hashCode() to more closely match those of the full runtime;
+    ///  the generated methods compute their results based on field values rather
+    ///  than object identity. (Implementations should not assume that hashcodes
+    ///  will be consistent across runtimes or versions of the protocol compiler.)
+    /// </summary>
+    public bool JavaGenerateEqualsAndHash {
+      get { return javaGenerateEqualsAndHash_; }
+      set {
+        javaGenerateEqualsAndHash_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_string_check_utf8" field.</summary>
+    public const int JavaStringCheckUtf8FieldNumber = 27;
+    private bool javaStringCheckUtf8_;
+    /// <summary>
+    ///  If set true, then the Java2 code generator will generate code that
+    ///  throws an exception whenever an attempt is made to assign a non-UTF-8
+    ///  byte sequence to a string field.
+    ///  Message reflection will do the same.
+    ///  However, an extension field still accepts non-UTF-8 byte sequences.
+    ///  This option has no effect on when used with the lite runtime.
+    /// </summary>
+    public bool JavaStringCheckUtf8 {
+      get { return javaStringCheckUtf8_; }
+      set {
+        javaStringCheckUtf8_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optimize_for" field.</summary>
+    public const int OptimizeForFieldNumber = 9;
+    private global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode optimizeFor_ = 0;
+    public global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode OptimizeFor {
+      get { return optimizeFor_; }
+      set {
+        optimizeFor_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "go_package" field.</summary>
+    public const int GoPackageFieldNumber = 11;
+    private string goPackage_ = "";
+    /// <summary>
+    ///  Sets the Go package where structs generated from this .proto will be
+    ///  placed. If omitted, the Go package will be derived from the following:
+    ///    - The basename of the package import path, if provided.
+    ///    - Otherwise, the package statement in the .proto file, if present.
+    ///    - Otherwise, the basename of the .proto file, without extension.
+    /// </summary>
+    public string GoPackage {
+      get { return goPackage_; }
+      set {
+        goPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "cc_generic_services" field.</summary>
+    public const int CcGenericServicesFieldNumber = 16;
+    private bool ccGenericServices_;
+    /// <summary>
+    ///  Should generic services be generated in each language?  "Generic" services
+    ///  are not specific to any particular RPC system.  They are generated by the
+    ///  main code generators in each language (without additional plugins).
+    ///  Generic services were the only kind of service generation supported by
+    ///  early versions of google.protobuf.
+    ///
+    ///  Generic services are now considered deprecated in favor of using plugins
+    ///  that generate code specific to your particular RPC system.  Therefore,
+    ///  these default to false.  Old code which depends on generic services should
+    ///  explicitly set them to true.
+    /// </summary>
+    public bool CcGenericServices {
+      get { return ccGenericServices_; }
+      set {
+        ccGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_generic_services" field.</summary>
+    public const int JavaGenericServicesFieldNumber = 17;
+    private bool javaGenericServices_;
+    public bool JavaGenericServices {
+      get { return javaGenericServices_; }
+      set {
+        javaGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "py_generic_services" field.</summary>
+    public const int PyGenericServicesFieldNumber = 18;
+    private bool pyGenericServices_;
+    public bool PyGenericServices {
+      get { return pyGenericServices_; }
+      set {
+        pyGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 23;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this file deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for everything in the file, or it will be completely ignored; in the very
+    ///  least, this is a formalization for deprecating files.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "cc_enable_arenas" field.</summary>
+    public const int CcEnableArenasFieldNumber = 31;
+    private bool ccEnableArenas_;
+    /// <summary>
+    ///  Enables the use of arenas for the proto messages in this file. This applies
+    ///  only to generated classes for C++.
+    /// </summary>
+    public bool CcEnableArenas {
+      get { return ccEnableArenas_; }
+      set {
+        ccEnableArenas_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "objc_class_prefix" field.</summary>
+    public const int ObjcClassPrefixFieldNumber = 36;
+    private string objcClassPrefix_ = "";
+    /// <summary>
+    ///  Sets the objective c class prefix which is prepended to all objective c
+    ///  generated classes from this .proto. There is no default.
+    /// </summary>
+    public string ObjcClassPrefix {
+      get { return objcClassPrefix_; }
+      set {
+        objcClassPrefix_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "csharp_namespace" field.</summary>
+    public const int CsharpNamespaceFieldNumber = 37;
+    private string csharpNamespace_ = "";
+    /// <summary>
+    ///  Namespace for generated classes; defaults to the package.
+    /// </summary>
+    public string CsharpNamespace {
+      get { return csharpNamespace_; }
+      set {
+        csharpNamespace_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileOptions);
+    }
+
+    public bool Equals(FileOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (JavaPackage != other.JavaPackage) return false;
+      if (JavaOuterClassname != other.JavaOuterClassname) return false;
+      if (JavaMultipleFiles != other.JavaMultipleFiles) return false;
+      if (JavaGenerateEqualsAndHash != other.JavaGenerateEqualsAndHash) return false;
+      if (JavaStringCheckUtf8 != other.JavaStringCheckUtf8) return false;
+      if (OptimizeFor != other.OptimizeFor) return false;
+      if (GoPackage != other.GoPackage) return false;
+      if (CcGenericServices != other.CcGenericServices) return false;
+      if (JavaGenericServices != other.JavaGenericServices) return false;
+      if (PyGenericServices != other.PyGenericServices) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (CcEnableArenas != other.CcEnableArenas) return false;
+      if (ObjcClassPrefix != other.ObjcClassPrefix) return false;
+      if (CsharpNamespace != other.CsharpNamespace) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (JavaPackage.Length != 0) hash ^= JavaPackage.GetHashCode();
+      if (JavaOuterClassname.Length != 0) hash ^= JavaOuterClassname.GetHashCode();
+      if (JavaMultipleFiles != false) hash ^= JavaMultipleFiles.GetHashCode();
+      if (JavaGenerateEqualsAndHash != false) hash ^= JavaGenerateEqualsAndHash.GetHashCode();
+      if (JavaStringCheckUtf8 != false) hash ^= JavaStringCheckUtf8.GetHashCode();
+      if (OptimizeFor != 0) hash ^= OptimizeFor.GetHashCode();
+      if (GoPackage.Length != 0) hash ^= GoPackage.GetHashCode();
+      if (CcGenericServices != false) hash ^= CcGenericServices.GetHashCode();
+      if (JavaGenericServices != false) hash ^= JavaGenericServices.GetHashCode();
+      if (PyGenericServices != false) hash ^= PyGenericServices.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (CcEnableArenas != false) hash ^= CcEnableArenas.GetHashCode();
+      if (ObjcClassPrefix.Length != 0) hash ^= ObjcClassPrefix.GetHashCode();
+      if (CsharpNamespace.Length != 0) hash ^= CsharpNamespace.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (JavaPackage.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(JavaPackage);
+      }
+      if (JavaOuterClassname.Length != 0) {
+        output.WriteRawTag(66);
+        output.WriteString(JavaOuterClassname);
+      }
+      if (OptimizeFor != 0) {
+        output.WriteRawTag(72);
+        output.WriteEnum((int) OptimizeFor);
+      }
+      if (JavaMultipleFiles != false) {
+        output.WriteRawTag(80);
+        output.WriteBool(JavaMultipleFiles);
+      }
+      if (GoPackage.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(GoPackage);
+      }
+      if (CcGenericServices != false) {
+        output.WriteRawTag(128, 1);
+        output.WriteBool(CcGenericServices);
+      }
+      if (JavaGenericServices != false) {
+        output.WriteRawTag(136, 1);
+        output.WriteBool(JavaGenericServices);
+      }
+      if (PyGenericServices != false) {
+        output.WriteRawTag(144, 1);
+        output.WriteBool(PyGenericServices);
+      }
+      if (JavaGenerateEqualsAndHash != false) {
+        output.WriteRawTag(160, 1);
+        output.WriteBool(JavaGenerateEqualsAndHash);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(184, 1);
+        output.WriteBool(Deprecated);
+      }
+      if (JavaStringCheckUtf8 != false) {
+        output.WriteRawTag(216, 1);
+        output.WriteBool(JavaStringCheckUtf8);
+      }
+      if (CcEnableArenas != false) {
+        output.WriteRawTag(248, 1);
+        output.WriteBool(CcEnableArenas);
+      }
+      if (ObjcClassPrefix.Length != 0) {
+        output.WriteRawTag(162, 2);
+        output.WriteString(ObjcClassPrefix);
+      }
+      if (CsharpNamespace.Length != 0) {
+        output.WriteRawTag(170, 2);
+        output.WriteString(CsharpNamespace);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (JavaPackage.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JavaPackage);
+      }
+      if (JavaOuterClassname.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JavaOuterClassname);
+      }
+      if (JavaMultipleFiles != false) {
+        size += 1 + 1;
+      }
+      if (JavaGenerateEqualsAndHash != false) {
+        size += 2 + 1;
+      }
+      if (JavaStringCheckUtf8 != false) {
+        size += 2 + 1;
+      }
+      if (OptimizeFor != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) OptimizeFor);
+      }
+      if (GoPackage.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(GoPackage);
+      }
+      if (CcGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (JavaGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (PyGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      if (CcEnableArenas != false) {
+        size += 2 + 1;
+      }
+      if (ObjcClassPrefix.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(ObjcClassPrefix);
+      }
+      if (CsharpNamespace.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(CsharpNamespace);
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(FileOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.JavaPackage.Length != 0) {
+        JavaPackage = other.JavaPackage;
+      }
+      if (other.JavaOuterClassname.Length != 0) {
+        JavaOuterClassname = other.JavaOuterClassname;
+      }
+      if (other.JavaMultipleFiles != false) {
+        JavaMultipleFiles = other.JavaMultipleFiles;
+      }
+      if (other.JavaGenerateEqualsAndHash != false) {
+        JavaGenerateEqualsAndHash = other.JavaGenerateEqualsAndHash;
+      }
+      if (other.JavaStringCheckUtf8 != false) {
+        JavaStringCheckUtf8 = other.JavaStringCheckUtf8;
+      }
+      if (other.OptimizeFor != 0) {
+        OptimizeFor = other.OptimizeFor;
+      }
+      if (other.GoPackage.Length != 0) {
+        GoPackage = other.GoPackage;
+      }
+      if (other.CcGenericServices != false) {
+        CcGenericServices = other.CcGenericServices;
+      }
+      if (other.JavaGenericServices != false) {
+        JavaGenericServices = other.JavaGenericServices;
+      }
+      if (other.PyGenericServices != false) {
+        PyGenericServices = other.PyGenericServices;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.CcEnableArenas != false) {
+        CcEnableArenas = other.CcEnableArenas;
+      }
+      if (other.ObjcClassPrefix.Length != 0) {
+        ObjcClassPrefix = other.ObjcClassPrefix;
+      }
+      if (other.CsharpNamespace.Length != 0) {
+        CsharpNamespace = other.CsharpNamespace;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            JavaPackage = input.ReadString();
+            break;
+          }
+          case 66: {
+            JavaOuterClassname = input.ReadString();
+            break;
+          }
+          case 72: {
+            optimizeFor_ = (global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) input.ReadEnum();
+            break;
+          }
+          case 80: {
+            JavaMultipleFiles = input.ReadBool();
+            break;
+          }
+          case 90: {
+            GoPackage = input.ReadString();
+            break;
+          }
+          case 128: {
+            CcGenericServices = input.ReadBool();
+            break;
+          }
+          case 136: {
+            JavaGenericServices = input.ReadBool();
+            break;
+          }
+          case 144: {
+            PyGenericServices = input.ReadBool();
+            break;
+          }
+          case 160: {
+            JavaGenerateEqualsAndHash = input.ReadBool();
+            break;
+          }
+          case 184: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 216: {
+            JavaStringCheckUtf8 = input.ReadBool();
+            break;
+          }
+          case 248: {
+            CcEnableArenas = input.ReadBool();
+            break;
+          }
+          case 290: {
+            ObjcClassPrefix = input.ReadString();
+            break;
+          }
+          case 298: {
+            CsharpNamespace = input.ReadString();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FileOptions message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  Generated classes can be optimized for speed or code size.
+      /// </summary>
+      internal enum OptimizeMode {
+        /// <summary>
+        ///  Generate complete code for parsing, serialization,
+        /// </summary>
+        [pbr::OriginalName("SPEED")] Speed = 1,
+        /// <summary>
+        ///  etc.
+        /// </summary>
+        [pbr::OriginalName("CODE_SIZE")] CodeSize = 2,
+        /// <summary>
+        ///  Generate code using MessageLite and the lite runtime.
+        /// </summary>
+        [pbr::OriginalName("LITE_RUNTIME")] LiteRuntime = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MessageOptions : pb::IMessage<MessageOptions> {
+    private static readonly pb::MessageParser<MessageOptions> _parser = new pb::MessageParser<MessageOptions>(() => new MessageOptions());
+    public static pb::MessageParser<MessageOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[10]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MessageOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MessageOptions(MessageOptions other) : this() {
+      messageSetWireFormat_ = other.messageSetWireFormat_;
+      noStandardDescriptorAccessor_ = other.noStandardDescriptorAccessor_;
+      deprecated_ = other.deprecated_;
+      mapEntry_ = other.mapEntry_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public MessageOptions Clone() {
+      return new MessageOptions(this);
+    }
+
+    /// <summary>Field number for the "message_set_wire_format" field.</summary>
+    public const int MessageSetWireFormatFieldNumber = 1;
+    private bool messageSetWireFormat_;
+    /// <summary>
+    ///  Set true to use the old proto1 MessageSet wire format for extensions.
+    ///  This is provided for backwards-compatibility with the MessageSet wire
+    ///  format.  You should not use this for any other reason:  It's less
+    ///  efficient, has fewer features, and is more complicated.
+    ///
+    ///  The message must be defined exactly as follows:
+    ///    message Foo {
+    ///      option message_set_wire_format = true;
+    ///      extensions 4 to max;
+    ///    }
+    ///  Note that the message cannot have any defined fields; MessageSets only
+    ///  have extensions.
+    ///
+    ///  All extensions of your type must be singular messages; e.g. they cannot
+    ///  be int32s, enums, or repeated messages.
+    ///
+    ///  Because this is an option, the above two restrictions are not enforced by
+    ///  the protocol compiler.
+    /// </summary>
+    public bool MessageSetWireFormat {
+      get { return messageSetWireFormat_; }
+      set {
+        messageSetWireFormat_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "no_standard_descriptor_accessor" field.</summary>
+    public const int NoStandardDescriptorAccessorFieldNumber = 2;
+    private bool noStandardDescriptorAccessor_;
+    /// <summary>
+    ///  Disables the generation of the standard "descriptor()" accessor, which can
+    ///  conflict with a field of the same name.  This is meant to make migration
+    ///  from proto1 easier; new code should avoid fields named "descriptor".
+    /// </summary>
+    public bool NoStandardDescriptorAccessor {
+      get { return noStandardDescriptorAccessor_; }
+      set {
+        noStandardDescriptorAccessor_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this message deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the message, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating messages.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "map_entry" field.</summary>
+    public const int MapEntryFieldNumber = 7;
+    private bool mapEntry_;
+    /// <summary>
+    ///  Whether the message is an automatically generated map entry type for the
+    ///  maps field.
+    ///
+    ///  For maps fields:
+    ///      map&lt;KeyType, ValueType> map_field = 1;
+    ///  The parsed descriptor looks like:
+    ///      message MapFieldEntry {
+    ///          option map_entry = true;
+    ///          optional KeyType key = 1;
+    ///          optional ValueType value = 2;
+    ///      }
+    ///      repeated MapFieldEntry map_field = 1;
+    ///
+    ///  Implementations may choose not to generate the map_entry=true message, but
+    ///  use a native map in the target language to hold the keys and values.
+    ///  The reflection APIs in such implementions still need to work as
+    ///  if the field is a repeated message field.
+    ///
+    ///  NOTE: Do not set the option in .proto files. Always use the maps syntax
+    ///  instead. The option should only be implicitly set by the proto compiler
+    ///  parser.
+    /// </summary>
+    public bool MapEntry {
+      get { return mapEntry_; }
+      set {
+        mapEntry_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MessageOptions);
+    }
+
+    public bool Equals(MessageOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (MessageSetWireFormat != other.MessageSetWireFormat) return false;
+      if (NoStandardDescriptorAccessor != other.NoStandardDescriptorAccessor) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (MapEntry != other.MapEntry) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (MessageSetWireFormat != false) hash ^= MessageSetWireFormat.GetHashCode();
+      if (NoStandardDescriptorAccessor != false) hash ^= NoStandardDescriptorAccessor.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (MapEntry != false) hash ^= MapEntry.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (MessageSetWireFormat != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(MessageSetWireFormat);
+      }
+      if (NoStandardDescriptorAccessor != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(NoStandardDescriptorAccessor);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      if (MapEntry != false) {
+        output.WriteRawTag(56);
+        output.WriteBool(MapEntry);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (MessageSetWireFormat != false) {
+        size += 1 + 1;
+      }
+      if (NoStandardDescriptorAccessor != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      if (MapEntry != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(MessageOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.MessageSetWireFormat != false) {
+        MessageSetWireFormat = other.MessageSetWireFormat;
+      }
+      if (other.NoStandardDescriptorAccessor != false) {
+        NoStandardDescriptorAccessor = other.NoStandardDescriptorAccessor;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.MapEntry != false) {
+        MapEntry = other.MapEntry;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            MessageSetWireFormat = input.ReadBool();
+            break;
+          }
+          case 16: {
+            NoStandardDescriptorAccessor = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 56: {
+            MapEntry = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FieldOptions : pb::IMessage<FieldOptions> {
+    private static readonly pb::MessageParser<FieldOptions> _parser = new pb::MessageParser<FieldOptions>(() => new FieldOptions());
+    public static pb::MessageParser<FieldOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[11]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldOptions(FieldOptions other) : this() {
+      ctype_ = other.ctype_;
+      packed_ = other.packed_;
+      jstype_ = other.jstype_;
+      lazy_ = other.lazy_;
+      deprecated_ = other.deprecated_;
+      weak_ = other.weak_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public FieldOptions Clone() {
+      return new FieldOptions(this);
+    }
+
+    /// <summary>Field number for the "ctype" field.</summary>
+    public const int CtypeFieldNumber = 1;
+    private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_ = 0;
+    /// <summary>
+    ///  The ctype option instructs the C++ code generator to use a different
+    ///  representation of the field than it normally would.  See the specific
+    ///  options below.  This option is not yet implemented in the open source
+    ///  release -- sorry, we'll try to include it in a future version!
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldOptions.Types.CType Ctype {
+      get { return ctype_; }
+      set {
+        ctype_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "packed" field.</summary>
+    public const int PackedFieldNumber = 2;
+    private bool packed_;
+    /// <summary>
+    ///  The packed option can be enabled for repeated primitive fields to enable
+    ///  a more efficient representation on the wire. Rather than repeatedly
+    ///  writing the tag and type for each element, the entire array is encoded as
+    ///  a single length-delimited blob. In proto3, only explicit setting it to
+    ///  false will avoid using packed encoding.
+    /// </summary>
+    public bool Packed {
+      get { return packed_; }
+      set {
+        packed_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "jstype" field.</summary>
+    public const int JstypeFieldNumber = 6;
+    private global::Google.Protobuf.Reflection.FieldOptions.Types.JSType jstype_ = 0;
+    /// <summary>
+    ///  The jstype option determines the JavaScript type used for values of the
+    ///  field.  The option is permitted only for 64 bit integral and fixed types
+    ///  (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+    ///  represented as JavaScript strings.  This avoids loss of precision that can
+    ///  happen when a large value is converted to a floating point JavaScript
+    ///  numbers.  Specifying JS_NUMBER for the jstype causes the generated
+    ///  JavaScript code to use the JavaScript "number" type instead of strings.
+    ///  This option is an enum to permit additional types to be added,
+    ///  e.g. goog.math.Integer.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldOptions.Types.JSType Jstype {
+      get { return jstype_; }
+      set {
+        jstype_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "lazy" field.</summary>
+    public const int LazyFieldNumber = 5;
+    private bool lazy_;
+    /// <summary>
+    ///  Should this field be parsed lazily?  Lazy applies only to message-type
+    ///  fields.  It means that when the outer message is initially parsed, the
+    ///  inner message's contents will not be parsed but instead stored in encoded
+    ///  form.  The inner message will actually be parsed when it is first accessed.
+    ///
+    ///  This is only a hint.  Implementations are free to choose whether to use
+    ///  eager or lazy parsing regardless of the value of this option.  However,
+    ///  setting this option true suggests that the protocol author believes that
+    ///  using lazy parsing on this field is worth the additional bookkeeping
+    ///  overhead typically needed to implement it.
+    ///
+    ///  This option does not affect the public interface of any generated code;
+    ///  all method signatures remain the same.  Furthermore, thread-safety of the
+    ///  interface is not affected by this option; const methods remain safe to
+    ///  call from multiple threads concurrently, while non-const methods continue
+    ///  to require exclusive access.
+    ///
+    ///  Note that implementations may choose not to check required fields within
+    ///  a lazy sub-message.  That is, calling IsInitialized() on the outher message
+    ///  may return true even if the inner message has missing required fields.
+    ///  This is necessary because otherwise the inner message would have to be
+    ///  parsed in order to perform the check, defeating the purpose of lazy
+    ///  parsing.  An implementation which chooses not to check required fields
+    ///  must be consistent about it.  That is, for any particular sub-message, the
+    ///  implementation must either *always* check its required fields, or *never*
+    ///  check its required fields, regardless of whether or not the message has
+    ///  been parsed.
+    /// </summary>
+    public bool Lazy {
+      get { return lazy_; }
+      set {
+        lazy_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this field deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for accessors, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating fields.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "weak" field.</summary>
+    public const int WeakFieldNumber = 10;
+    private bool weak_;
+    /// <summary>
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
+    public bool Weak {
+      get { return weak_; }
+      set {
+        weak_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldOptions);
+    }
+
+    public bool Equals(FieldOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Ctype != other.Ctype) return false;
+      if (Packed != other.Packed) return false;
+      if (Jstype != other.Jstype) return false;
+      if (Lazy != other.Lazy) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (Weak != other.Weak) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Ctype != 0) hash ^= Ctype.GetHashCode();
+      if (Packed != false) hash ^= Packed.GetHashCode();
+      if (Jstype != 0) hash ^= Jstype.GetHashCode();
+      if (Lazy != false) hash ^= Lazy.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (Weak != false) hash ^= Weak.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Ctype != 0) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Ctype);
+      }
+      if (Packed != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(Packed);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      if (Lazy != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(Lazy);
+      }
+      if (Jstype != 0) {
+        output.WriteRawTag(48);
+        output.WriteEnum((int) Jstype);
+      }
+      if (Weak != false) {
+        output.WriteRawTag(80);
+        output.WriteBool(Weak);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Ctype != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Ctype);
+      }
+      if (Packed != false) {
+        size += 1 + 1;
+      }
+      if (Jstype != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Jstype);
+      }
+      if (Lazy != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      if (Weak != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(FieldOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Ctype != 0) {
+        Ctype = other.Ctype;
+      }
+      if (other.Packed != false) {
+        Packed = other.Packed;
+      }
+      if (other.Jstype != 0) {
+        Jstype = other.Jstype;
+      }
+      if (other.Lazy != false) {
+        Lazy = other.Lazy;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.Weak != false) {
+        Weak = other.Weak;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            ctype_ = (global::Google.Protobuf.Reflection.FieldOptions.Types.CType) input.ReadEnum();
+            break;
+          }
+          case 16: {
+            Packed = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 40: {
+            Lazy = input.ReadBool();
+            break;
+          }
+          case 48: {
+            jstype_ = (global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) input.ReadEnum();
+            break;
+          }
+          case 80: {
+            Weak = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FieldOptions message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      internal enum CType {
+        /// <summary>
+        ///  Default mode.
+        /// </summary>
+        [pbr::OriginalName("STRING")] String = 0,
+        [pbr::OriginalName("CORD")] Cord = 1,
+        [pbr::OriginalName("STRING_PIECE")] StringPiece = 2,
+      }
+
+      internal enum JSType {
+        /// <summary>
+        ///  Use the default type.
+        /// </summary>
+        [pbr::OriginalName("JS_NORMAL")] JsNormal = 0,
+        /// <summary>
+        ///  Use JavaScript strings.
+        /// </summary>
+        [pbr::OriginalName("JS_STRING")] JsString = 1,
+        /// <summary>
+        ///  Use JavaScript numbers.
+        /// </summary>
+        [pbr::OriginalName("JS_NUMBER")] JsNumber = 2,
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumOptions : pb::IMessage<EnumOptions> {
+    private static readonly pb::MessageParser<EnumOptions> _parser = new pb::MessageParser<EnumOptions>(() => new EnumOptions());
+    public static pb::MessageParser<EnumOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[12]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumOptions(EnumOptions other) : this() {
+      allowAlias_ = other.allowAlias_;
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public EnumOptions Clone() {
+      return new EnumOptions(this);
+    }
+
+    /// <summary>Field number for the "allow_alias" field.</summary>
+    public const int AllowAliasFieldNumber = 2;
+    private bool allowAlias_;
+    /// <summary>
+    ///  Set this option to true to allow mapping different tag names to the same
+    ///  value.
+    /// </summary>
+    public bool AllowAlias {
+      get { return allowAlias_; }
+      set {
+        allowAlias_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this enum deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating enums.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumOptions);
+    }
+
+    public bool Equals(EnumOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (AllowAlias != other.AllowAlias) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (AllowAlias != false) hash ^= AllowAlias.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (AllowAlias != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(AllowAlias);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (AllowAlias != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.AllowAlias != false) {
+        AllowAlias = other.AllowAlias;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 16: {
+            AllowAlias = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumValueOptions : pb::IMessage<EnumValueOptions> {
+    private static readonly pb::MessageParser<EnumValueOptions> _parser = new pb::MessageParser<EnumValueOptions>(() => new EnumValueOptions());
+    public static pb::MessageParser<EnumValueOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[13]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValueOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValueOptions(EnumValueOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public EnumValueOptions Clone() {
+      return new EnumValueOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 1;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this enum value deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum value, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating enum values.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValueOptions);
+    }
+
+    public bool Equals(EnumValueOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumValueOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class ServiceOptions : pb::IMessage<ServiceOptions> {
+    private static readonly pb::MessageParser<ServiceOptions> _parser = new pb::MessageParser<ServiceOptions>(() => new ServiceOptions());
+    public static pb::MessageParser<ServiceOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[14]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ServiceOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ServiceOptions(ServiceOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public ServiceOptions Clone() {
+      return new ServiceOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 33;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this service deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the service, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating services.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ServiceOptions);
+    }
+
+    public bool Equals(ServiceOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(136, 2);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(ServiceOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 264: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MethodOptions : pb::IMessage<MethodOptions> {
+    private static readonly pb::MessageParser<MethodOptions> _parser = new pb::MessageParser<MethodOptions>(() => new MethodOptions());
+    public static pb::MessageParser<MethodOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[15]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MethodOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MethodOptions(MethodOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public MethodOptions Clone() {
+      return new MethodOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 33;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this method deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the method, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating methods.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MethodOptions);
+    }
+
+    public bool Equals(MethodOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(136, 2);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(MethodOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 264: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A message representing a option the parser does not recognize. This only
+  ///  appears in options protos created by the compiler::Parser class.
+  ///  DescriptorPool resolves these when building Descriptor objects. Therefore,
+  ///  options protos in descriptor objects (e.g. returned by Descriptor::options(),
+  ///  or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+  ///  in them.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class UninterpretedOption : pb::IMessage<UninterpretedOption> {
+    private static readonly pb::MessageParser<UninterpretedOption> _parser = new pb::MessageParser<UninterpretedOption>(() => new UninterpretedOption());
+    public static pb::MessageParser<UninterpretedOption> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[16]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UninterpretedOption() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UninterpretedOption(UninterpretedOption other) : this() {
+      name_ = other.name_.Clone();
+      identifierValue_ = other.identifierValue_;
+      positiveIntValue_ = other.positiveIntValue_;
+      negativeIntValue_ = other.negativeIntValue_;
+      doubleValue_ = other.doubleValue_;
+      stringValue_ = other.stringValue_;
+      aggregateValue_ = other.aggregateValue_;
+    }
+
+    public UninterpretedOption Clone() {
+      return new UninterpretedOption(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> _repeated_name_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> name_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> Name {
+      get { return name_; }
+    }
+
+    /// <summary>Field number for the "identifier_value" field.</summary>
+    public const int IdentifierValueFieldNumber = 3;
+    private string identifierValue_ = "";
+    /// <summary>
+    ///  The value of the uninterpreted option, in whatever type the tokenizer
+    ///  identified it as during parsing. Exactly one of these should be set.
+    /// </summary>
+    public string IdentifierValue {
+      get { return identifierValue_; }
+      set {
+        identifierValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "positive_int_value" field.</summary>
+    public const int PositiveIntValueFieldNumber = 4;
+    private ulong positiveIntValue_;
+    public ulong PositiveIntValue {
+      get { return positiveIntValue_; }
+      set {
+        positiveIntValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "negative_int_value" field.</summary>
+    public const int NegativeIntValueFieldNumber = 5;
+    private long negativeIntValue_;
+    public long NegativeIntValue {
+      get { return negativeIntValue_; }
+      set {
+        negativeIntValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "double_value" field.</summary>
+    public const int DoubleValueFieldNumber = 6;
+    private double doubleValue_;
+    public double DoubleValue {
+      get { return doubleValue_; }
+      set {
+        doubleValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "string_value" field.</summary>
+    public const int StringValueFieldNumber = 7;
+    private pb::ByteString stringValue_ = pb::ByteString.Empty;
+    public pb::ByteString StringValue {
+      get { return stringValue_; }
+      set {
+        stringValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "aggregate_value" field.</summary>
+    public const int AggregateValueFieldNumber = 8;
+    private string aggregateValue_ = "";
+    public string AggregateValue {
+      get { return aggregateValue_; }
+      set {
+        aggregateValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UninterpretedOption);
+    }
+
+    public bool Equals(UninterpretedOption other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!name_.Equals(other.name_)) return false;
+      if (IdentifierValue != other.IdentifierValue) return false;
+      if (PositiveIntValue != other.PositiveIntValue) return false;
+      if (NegativeIntValue != other.NegativeIntValue) return false;
+      if (DoubleValue != other.DoubleValue) return false;
+      if (StringValue != other.StringValue) return false;
+      if (AggregateValue != other.AggregateValue) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= name_.GetHashCode();
+      if (IdentifierValue.Length != 0) hash ^= IdentifierValue.GetHashCode();
+      if (PositiveIntValue != 0UL) hash ^= PositiveIntValue.GetHashCode();
+      if (NegativeIntValue != 0L) hash ^= NegativeIntValue.GetHashCode();
+      if (DoubleValue != 0D) hash ^= DoubleValue.GetHashCode();
+      if (StringValue.Length != 0) hash ^= StringValue.GetHashCode();
+      if (AggregateValue.Length != 0) hash ^= AggregateValue.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      name_.WriteTo(output, _repeated_name_codec);
+      if (IdentifierValue.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(IdentifierValue);
+      }
+      if (PositiveIntValue != 0UL) {
+        output.WriteRawTag(32);
+        output.WriteUInt64(PositiveIntValue);
+      }
+      if (NegativeIntValue != 0L) {
+        output.WriteRawTag(40);
+        output.WriteInt64(NegativeIntValue);
+      }
+      if (DoubleValue != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(DoubleValue);
+      }
+      if (StringValue.Length != 0) {
+        output.WriteRawTag(58);
+        output.WriteBytes(StringValue);
+      }
+      if (AggregateValue.Length != 0) {
+        output.WriteRawTag(66);
+        output.WriteString(AggregateValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += name_.CalculateSize(_repeated_name_codec);
+      if (IdentifierValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(IdentifierValue);
+      }
+      if (PositiveIntValue != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(PositiveIntValue);
+      }
+      if (NegativeIntValue != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(NegativeIntValue);
+      }
+      if (DoubleValue != 0D) {
+        size += 1 + 8;
+      }
+      if (StringValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(StringValue);
+      }
+      if (AggregateValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AggregateValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UninterpretedOption other) {
+      if (other == null) {
+        return;
+      }
+      name_.Add(other.name_);
+      if (other.IdentifierValue.Length != 0) {
+        IdentifierValue = other.IdentifierValue;
+      }
+      if (other.PositiveIntValue != 0UL) {
+        PositiveIntValue = other.PositiveIntValue;
+      }
+      if (other.NegativeIntValue != 0L) {
+        NegativeIntValue = other.NegativeIntValue;
+      }
+      if (other.DoubleValue != 0D) {
+        DoubleValue = other.DoubleValue;
+      }
+      if (other.StringValue.Length != 0) {
+        StringValue = other.StringValue;
+      }
+      if (other.AggregateValue.Length != 0) {
+        AggregateValue = other.AggregateValue;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 18: {
+            name_.AddEntriesFrom(input, _repeated_name_codec);
+            break;
+          }
+          case 26: {
+            IdentifierValue = input.ReadString();
+            break;
+          }
+          case 32: {
+            PositiveIntValue = input.ReadUInt64();
+            break;
+          }
+          case 40: {
+            NegativeIntValue = input.ReadInt64();
+            break;
+          }
+          case 49: {
+            DoubleValue = input.ReadDouble();
+            break;
+          }
+          case 58: {
+            StringValue = input.ReadBytes();
+            break;
+          }
+          case 66: {
+            AggregateValue = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the UninterpretedOption message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  The name of the uninterpreted option.  Each string represents a segment in
+      ///  a dot-separated name.  is_extension is true iff a segment represents an
+      ///  extension (denoted with parentheses in options specs in .proto files).
+      ///  E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+      ///  "foo.(bar.baz).qux".
+      /// </summary>
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class NamePart : pb::IMessage<NamePart> {
+        private static readonly pb::MessageParser<NamePart> _parser = new pb::MessageParser<NamePart>(() => new NamePart());
+        public static pb::MessageParser<NamePart> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.UninterpretedOption.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NamePart() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NamePart(NamePart other) : this() {
+          namePart_ = other.namePart_;
+          isExtension_ = other.isExtension_;
+        }
+
+        public NamePart Clone() {
+          return new NamePart(this);
+        }
+
+        /// <summary>Field number for the "name_part" field.</summary>
+        public const int NamePart_FieldNumber = 1;
+        private string namePart_ = "";
+        public string NamePart_ {
+          get { return namePart_; }
+          set {
+            namePart_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "is_extension" field.</summary>
+        public const int IsExtensionFieldNumber = 2;
+        private bool isExtension_;
+        public bool IsExtension {
+          get { return isExtension_; }
+          set {
+            isExtension_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NamePart);
+        }
+
+        public bool Equals(NamePart other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (NamePart_ != other.NamePart_) return false;
+          if (IsExtension != other.IsExtension) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (NamePart_.Length != 0) hash ^= NamePart_.GetHashCode();
+          if (IsExtension != false) hash ^= IsExtension.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (NamePart_.Length != 0) {
+            output.WriteRawTag(10);
+            output.WriteString(NamePart_);
+          }
+          if (IsExtension != false) {
+            output.WriteRawTag(16);
+            output.WriteBool(IsExtension);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (NamePart_.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(NamePart_);
+          }
+          if (IsExtension != false) {
+            size += 1 + 1;
+          }
+          return size;
+        }
+
+        public void MergeFrom(NamePart other) {
+          if (other == null) {
+            return;
+          }
+          if (other.NamePart_.Length != 0) {
+            NamePart_ = other.NamePart_;
+          }
+          if (other.IsExtension != false) {
+            IsExtension = other.IsExtension;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10: {
+                NamePart_ = input.ReadString();
+                break;
+              }
+              case 16: {
+                IsExtension = input.ReadBool();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Encapsulates information about the original source file from which a
+  ///  FileDescriptorProto was generated.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class SourceCodeInfo : pb::IMessage<SourceCodeInfo> {
+    private static readonly pb::MessageParser<SourceCodeInfo> _parser = new pb::MessageParser<SourceCodeInfo>(() => new SourceCodeInfo());
+    public static pb::MessageParser<SourceCodeInfo> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[17]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public SourceCodeInfo() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public SourceCodeInfo(SourceCodeInfo other) : this() {
+      location_ = other.location_.Clone();
+    }
+
+    public SourceCodeInfo Clone() {
+      return new SourceCodeInfo(this);
+    }
+
+    /// <summary>Field number for the "location" field.</summary>
+    public const int LocationFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> _repeated_location_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> location_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location>();
+    /// <summary>
+    ///  A Location identifies a piece of source code in a .proto file which
+    ///  corresponds to a particular definition.  This information is intended
+    ///  to be useful to IDEs, code indexers, documentation generators, and similar
+    ///  tools.
+    ///
+    ///  For example, say we have a file like:
+    ///    message Foo {
+    ///      optional string foo = 1;
+    ///    }
+    ///  Let's look at just the field definition:
+    ///    optional string foo = 1;
+    ///    ^       ^^     ^^  ^  ^^^
+    ///    a       bc     de  f  ghi
+    ///  We have the following locations:
+    ///    span   path               represents
+    ///    [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+    ///    [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+    ///    [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+    ///    [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+    ///    [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+    ///
+    ///  Notes:
+    ///  - A location may refer to a repeated field itself (i.e. not to any
+    ///    particular index within it).  This is used whenever a set of elements are
+    ///    logically enclosed in a single code segment.  For example, an entire
+    ///    extend block (possibly containing multiple extension definitions) will
+    ///    have an outer location whose path refers to the "extensions" repeated
+    ///    field without an index.
+    ///  - Multiple locations may have the same path.  This happens when a single
+    ///    logical declaration is spread out across multiple places.  The most
+    ///    obvious example is the "extend" block again -- there may be multiple
+    ///    extend blocks in the same scope, each of which will have the same path.
+    ///  - A location's span is not always a subset of its parent's span.  For
+    ///    example, the "extendee" of an extension declaration appears at the
+    ///    beginning of the "extend" block and is shared by all extensions within
+    ///    the block.
+    ///  - Just because a location's span is a subset of some other location's span
+    ///    does not mean that it is a descendent.  For example, a "group" defines
+    ///    both a type and a field in a single declaration.  Thus, the locations
+    ///    corresponding to the type and field and their components will overlap.
+    ///  - Code which tries to interpret locations should probably be designed to
+    ///    ignore those that it doesn't understand, as more types of locations could
+    ///    be recorded in the future.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> Location {
+      get { return location_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as SourceCodeInfo);
+    }
+
+    public bool Equals(SourceCodeInfo other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!location_.Equals(other.location_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= location_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      location_.WriteTo(output, _repeated_location_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += location_.CalculateSize(_repeated_location_codec);
+      return size;
+    }
+
+    public void MergeFrom(SourceCodeInfo other) {
+      if (other == null) {
+        return;
+      }
+      location_.Add(other.location_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            location_.AddEntriesFrom(input, _repeated_location_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the SourceCodeInfo message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class Location : pb::IMessage<Location> {
+        private static readonly pb::MessageParser<Location> _parser = new pb::MessageParser<Location>(() => new Location());
+        public static pb::MessageParser<Location> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.SourceCodeInfo.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public Location() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public Location(Location other) : this() {
+          path_ = other.path_.Clone();
+          span_ = other.span_.Clone();
+          leadingComments_ = other.leadingComments_;
+          trailingComments_ = other.trailingComments_;
+          leadingDetachedComments_ = other.leadingDetachedComments_.Clone();
+        }
+
+        public Location Clone() {
+          return new Location(this);
+        }
+
+        /// <summary>Field number for the "path" field.</summary>
+        public const int PathFieldNumber = 1;
+        private static readonly pb::FieldCodec<int> _repeated_path_codec
+            = pb::FieldCodec.ForInt32(10);
+        private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies which part of the FileDescriptorProto was defined at this
+        ///  location.
+        ///
+        ///  Each element is a field number or an index.  They form a path from
+        ///  the root FileDescriptorProto to the place where the definition.  For
+        ///  example, this path:
+        ///    [ 4, 3, 2, 7, 1 ]
+        ///  refers to:
+        ///    file.message_type(3)  // 4, 3
+        ///        .field(7)         // 2, 7
+        ///        .name()           // 1
+        ///  This is because FileDescriptorProto.message_type has field number 4:
+        ///    repeated DescriptorProto message_type = 4;
+        ///  and DescriptorProto.field has field number 2:
+        ///    repeated FieldDescriptorProto field = 2;
+        ///  and FieldDescriptorProto.name has field number 1:
+        ///    optional string name = 1;
+        ///
+        ///  Thus, the above path gives the location of a field name.  If we removed
+        ///  the last element:
+        ///    [ 4, 3, 2, 7 ]
+        ///  this path refers to the whole field declaration (from the beginning
+        ///  of the label to the terminating semicolon).
+        /// </summary>
+        public pbc::RepeatedField<int> Path {
+          get { return path_; }
+        }
+
+        /// <summary>Field number for the "span" field.</summary>
+        public const int SpanFieldNumber = 2;
+        private static readonly pb::FieldCodec<int> _repeated_span_codec
+            = pb::FieldCodec.ForInt32(18);
+        private readonly pbc::RepeatedField<int> span_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Always has exactly three or four elements: start line, start column,
+        ///  end line (optional, otherwise assumed same as start line), end column.
+        ///  These are packed into a single field for efficiency.  Note that line
+        ///  and column numbers are zero-based -- typically you will want to add
+        ///  1 to each before displaying to a user.
+        /// </summary>
+        public pbc::RepeatedField<int> Span {
+          get { return span_; }
+        }
+
+        /// <summary>Field number for the "leading_comments" field.</summary>
+        public const int LeadingCommentsFieldNumber = 3;
+        private string leadingComments_ = "";
+        /// <summary>
+        ///  If this SourceCodeInfo represents a complete declaration, these are any
+        ///  comments appearing before and after the declaration which appear to be
+        ///  attached to the declaration.
+        ///
+        ///  A series of line comments appearing on consecutive lines, with no other
+        ///  tokens appearing on those lines, will be treated as a single comment.
+        ///
+        ///  leading_detached_comments will keep paragraphs of comments that appear
+        ///  before (but not connected to) the current element. Each paragraph,
+        ///  separated by empty lines, will be one comment element in the repeated
+        ///  field.
+        ///
+        ///  Only the comment content is provided; comment markers (e.g. //) are
+        ///  stripped out.  For block comments, leading whitespace and an asterisk
+        ///  will be stripped from the beginning of each line other than the first.
+        ///  Newlines are included in the output.
+        ///
+        ///  Examples:
+        ///
+        ///    optional int32 foo = 1;  // Comment attached to foo.
+        ///    // Comment attached to bar.
+        ///    optional int32 bar = 2;
+        ///
+        ///    optional string baz = 3;
+        ///    // Comment attached to baz.
+        ///    // Another line attached to baz.
+        ///
+        ///    // Comment attached to qux.
+        ///    //
+        ///    // Another line attached to qux.
+        ///    optional double qux = 4;
+        ///
+        ///    // Detached comment for corge. This is not leading or trailing comments
+        ///    // to qux or corge because there are blank lines separating it from
+        ///    // both.
+        ///
+        ///    // Detached comment for corge paragraph 2.
+        ///
+        ///    optional string corge = 5;
+        ///    /* Block comment attached
+        ///     * to corge.  Leading asterisks
+        ///     * will be removed. */
+        ///    /* Block comment attached to
+        ///     * grault. */
+        ///    optional int32 grault = 6;
+        ///
+        ///    // ignored detached comments.
+        /// </summary>
+        public string LeadingComments {
+          get { return leadingComments_; }
+          set {
+            leadingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "trailing_comments" field.</summary>
+        public const int TrailingCommentsFieldNumber = 4;
+        private string trailingComments_ = "";
+        public string TrailingComments {
+          get { return trailingComments_; }
+          set {
+            trailingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "leading_detached_comments" field.</summary>
+        public const int LeadingDetachedCommentsFieldNumber = 6;
+        private static readonly pb::FieldCodec<string> _repeated_leadingDetachedComments_codec
+            = pb::FieldCodec.ForString(50);
+        private readonly pbc::RepeatedField<string> leadingDetachedComments_ = new pbc::RepeatedField<string>();
+        public pbc::RepeatedField<string> LeadingDetachedComments {
+          get { return leadingDetachedComments_; }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as Location);
+        }
+
+        public bool Equals(Location other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if(!path_.Equals(other.path_)) return false;
+          if(!span_.Equals(other.span_)) return false;
+          if (LeadingComments != other.LeadingComments) return false;
+          if (TrailingComments != other.TrailingComments) return false;
+          if(!leadingDetachedComments_.Equals(other.leadingDetachedComments_)) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= path_.GetHashCode();
+          hash ^= span_.GetHashCode();
+          if (LeadingComments.Length != 0) hash ^= LeadingComments.GetHashCode();
+          if (TrailingComments.Length != 0) hash ^= TrailingComments.GetHashCode();
+          hash ^= leadingDetachedComments_.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          path_.WriteTo(output, _repeated_path_codec);
+          span_.WriteTo(output, _repeated_span_codec);
+          if (LeadingComments.Length != 0) {
+            output.WriteRawTag(26);
+            output.WriteString(LeadingComments);
+          }
+          if (TrailingComments.Length != 0) {
+            output.WriteRawTag(34);
+            output.WriteString(TrailingComments);
+          }
+          leadingDetachedComments_.WriteTo(output, _repeated_leadingDetachedComments_codec);
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          size += path_.CalculateSize(_repeated_path_codec);
+          size += span_.CalculateSize(_repeated_span_codec);
+          if (LeadingComments.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(LeadingComments);
+          }
+          if (TrailingComments.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(TrailingComments);
+          }
+          size += leadingDetachedComments_.CalculateSize(_repeated_leadingDetachedComments_codec);
+          return size;
+        }
+
+        public void MergeFrom(Location other) {
+          if (other == null) {
+            return;
+          }
+          path_.Add(other.path_);
+          span_.Add(other.span_);
+          if (other.LeadingComments.Length != 0) {
+            LeadingComments = other.LeadingComments;
+          }
+          if (other.TrailingComments.Length != 0) {
+            TrailingComments = other.TrailingComments;
+          }
+          leadingDetachedComments_.Add(other.leadingDetachedComments_);
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10:
+              case 8: {
+                path_.AddEntriesFrom(input, _repeated_path_codec);
+                break;
+              }
+              case 18:
+              case 16: {
+                span_.AddEntriesFrom(input, _repeated_span_codec);
+                break;
+              }
+              case 26: {
+                LeadingComments = input.ReadString();
+                break;
+              }
+              case 34: {
+                TrailingComments = input.ReadString();
+                break;
+              }
+              case 50: {
+                leadingDetachedComments_.AddEntriesFrom(input, _repeated_leadingDetachedComments_codec);
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes the relationship between generated code and its original source
+  ///  file. A GeneratedCodeInfo message is associated with only one generated
+  ///  source file, but may contain references to different source .proto files.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class GeneratedCodeInfo : pb::IMessage<GeneratedCodeInfo> {
+    private static readonly pb::MessageParser<GeneratedCodeInfo> _parser = new pb::MessageParser<GeneratedCodeInfo>(() => new GeneratedCodeInfo());
+    public static pb::MessageParser<GeneratedCodeInfo> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[18]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public GeneratedCodeInfo() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public GeneratedCodeInfo(GeneratedCodeInfo other) : this() {
+      annotation_ = other.annotation_.Clone();
+    }
+
+    public GeneratedCodeInfo Clone() {
+      return new GeneratedCodeInfo(this);
+    }
+
+    /// <summary>Field number for the "annotation" field.</summary>
+    public const int AnnotationFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> _repeated_annotation_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> annotation_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation>();
+    /// <summary>
+    ///  An Annotation connects some span of text in generated code to an element
+    ///  of its generating .proto file.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> Annotation {
+      get { return annotation_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as GeneratedCodeInfo);
+    }
+
+    public bool Equals(GeneratedCodeInfo other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!annotation_.Equals(other.annotation_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= annotation_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      annotation_.WriteTo(output, _repeated_annotation_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += annotation_.CalculateSize(_repeated_annotation_codec);
+      return size;
+    }
+
+    public void MergeFrom(GeneratedCodeInfo other) {
+      if (other == null) {
+        return;
+      }
+      annotation_.Add(other.annotation_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            annotation_.AddEntriesFrom(input, _repeated_annotation_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the GeneratedCodeInfo message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class Annotation : pb::IMessage<Annotation> {
+        private static readonly pb::MessageParser<Annotation> _parser = new pb::MessageParser<Annotation>(() => new Annotation());
+        public static pb::MessageParser<Annotation> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.GeneratedCodeInfo.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public Annotation() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public Annotation(Annotation other) : this() {
+          path_ = other.path_.Clone();
+          sourceFile_ = other.sourceFile_;
+          begin_ = other.begin_;
+          end_ = other.end_;
+        }
+
+        public Annotation Clone() {
+          return new Annotation(this);
+        }
+
+        /// <summary>Field number for the "path" field.</summary>
+        public const int PathFieldNumber = 1;
+        private static readonly pb::FieldCodec<int> _repeated_path_codec
+            = pb::FieldCodec.ForInt32(10);
+        private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies the element in the original source .proto file. This field
+        ///  is formatted the same as SourceCodeInfo.Location.path.
+        /// </summary>
+        public pbc::RepeatedField<int> Path {
+          get { return path_; }
+        }
+
+        /// <summary>Field number for the "source_file" field.</summary>
+        public const int SourceFileFieldNumber = 2;
+        private string sourceFile_ = "";
+        /// <summary>
+        ///  Identifies the filesystem path to the original source .proto.
+        /// </summary>
+        public string SourceFile {
+          get { return sourceFile_; }
+          set {
+            sourceFile_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "begin" field.</summary>
+        public const int BeginFieldNumber = 3;
+        private int begin_;
+        /// <summary>
+        ///  Identifies the starting offset in bytes in the generated code
+        ///  that relates to the identified object.
+        /// </summary>
+        public int Begin {
+          get { return begin_; }
+          set {
+            begin_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 4;
+        private int end_;
+        /// <summary>
+        ///  Identifies the ending offset in bytes in the generated code that
+        ///  relates to the identified offset. The end offset should be one past
+        ///  the last relevant byte (so the length of the text = end - begin).
+        /// </summary>
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as Annotation);
+        }
+
+        public bool Equals(Annotation other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if(!path_.Equals(other.path_)) return false;
+          if (SourceFile != other.SourceFile) return false;
+          if (Begin != other.Begin) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= path_.GetHashCode();
+          if (SourceFile.Length != 0) hash ^= SourceFile.GetHashCode();
+          if (Begin != 0) hash ^= Begin.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          path_.WriteTo(output, _repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            output.WriteRawTag(18);
+            output.WriteString(SourceFile);
+          }
+          if (Begin != 0) {
+            output.WriteRawTag(24);
+            output.WriteInt32(Begin);
+          }
+          if (End != 0) {
+            output.WriteRawTag(32);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          size += path_.CalculateSize(_repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceFile);
+          }
+          if (Begin != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Begin);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(Annotation other) {
+          if (other == null) {
+            return;
+          }
+          path_.Add(other.path_);
+          if (other.SourceFile.Length != 0) {
+            SourceFile = other.SourceFile;
+          }
+          if (other.Begin != 0) {
+            Begin = other.Begin;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10:
+              case 8: {
+                path_.AddEntriesFrom(input, _repeated_path_codec);
+                break;
+              }
+              case 18: {
+                SourceFile = input.ReadString();
+                break;
+              }
+              case 24: {
+                Begin = input.ReadInt32();
+                break;
+              }
+              case 32: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs
new file mode 100644
index 0000000..194041a
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs
@@ -0,0 +1,85 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Base class for nearly all descriptors, providing common functionality.
+    /// </summary>
+    public abstract class DescriptorBase : IDescriptor
+    {
+        private readonly FileDescriptor file;
+        private readonly string fullName;
+        private readonly int index;
+
+        internal DescriptorBase(FileDescriptor file, string fullName, int index)
+        {
+            this.file = file;
+            this.fullName = fullName;
+            this.index = index;
+        }
+
+        /// <value>
+        /// The index of this descriptor within its parent descriptor. 
+        /// </value>
+        /// <remarks>
+        /// This returns the index of this descriptor within its parent, for
+        /// this descriptor's type. (There can be duplicate values for different
+        /// types, e.g. one enum type with index 0 and one message type with index 0.)
+        /// </remarks>
+        public int Index
+        {
+            get { return index; }
+        }
+
+        /// <summary>
+        /// Returns the name of the entity (field, message etc) being described.
+        /// </summary>
+        public abstract string Name { get; }
+
+        /// <summary>
+        /// The fully qualified name of the descriptor's target.
+        /// </summary>
+        public string FullName
+        {
+            get { return fullName; }
+        }
+
+        /// <value>
+        /// The file this descriptor was declared in.
+        /// </value>
+        public FileDescriptor File
+        {
+            get { return file; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
new file mode 100644
index 0000000..99ca4bf
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
@@ -0,0 +1,368 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Contains lookup tables containing all the descriptors defined in a particular file.
+    /// </summary>
+    internal sealed class DescriptorPool
+    {
+        private readonly IDictionary<string, IDescriptor> descriptorsByName =
+            new Dictionary<string, IDescriptor>();
+
+        private readonly IDictionary<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
+            new Dictionary<DescriptorIntPair, FieldDescriptor>();
+
+        private readonly IDictionary<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
+            new Dictionary<DescriptorIntPair, EnumValueDescriptor>();
+
+        private readonly HashSet<FileDescriptor> dependencies;
+
+        internal DescriptorPool(FileDescriptor[] dependencyFiles)
+        {
+            dependencies = new HashSet<FileDescriptor>();
+            for (int i = 0; i < dependencyFiles.Length; i++)
+            {
+                dependencies.Add(dependencyFiles[i]);
+                ImportPublicDependencies(dependencyFiles[i]);
+            }
+
+            foreach (FileDescriptor dependency in dependencyFiles)
+            {
+                AddPackage(dependency.Package, dependency);
+            }
+        }
+
+        private void ImportPublicDependencies(FileDescriptor file)
+        {
+            foreach (FileDescriptor dependency in file.PublicDependencies)
+            {
+                if (dependencies.Add(dependency))
+                {
+                    ImportPublicDependencies(dependency);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Finds a symbol of the given name within the pool.
+        /// </summary>
+        /// <typeparam name="T">The type of symbol to look for</typeparam>
+        /// <param name="fullName">Fully-qualified name to look up</param>
+        /// <returns>The symbol with the given name and type,
+        /// or null if the symbol doesn't exist or has the wrong type</returns>
+        internal T FindSymbol<T>(string fullName) where T : class
+        {
+            IDescriptor result;
+            descriptorsByName.TryGetValue(fullName, out result);
+            T descriptor = result as T;
+            if (descriptor != null)
+            {
+                return descriptor;
+            }
+
+            // dependencies contains direct dependencies and any *public* dependencies
+            // of those dependencies (transitively)... so we don't need to recurse here.
+            foreach (FileDescriptor dependency in dependencies)
+            {
+                dependency.DescriptorPool.descriptorsByName.TryGetValue(fullName, out result);
+                descriptor = result as T;
+                if (descriptor != null)
+                {
+                    return descriptor;
+                }
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Adds a package to the symbol tables. If a package by the same name
+        /// already exists, that is fine, but if some other kind of symbol
+        /// exists under the same name, an exception is thrown. If the package
+        /// has multiple components, this also adds the parent package(s).
+        /// </summary>
+        internal void AddPackage(string fullName, FileDescriptor file)
+        {
+            int dotpos = fullName.LastIndexOf('.');
+            String name;
+            if (dotpos != -1)
+            {
+                AddPackage(fullName.Substring(0, dotpos), file);
+                name = fullName.Substring(dotpos + 1);
+            }
+            else
+            {
+                name = fullName;
+            }
+
+            IDescriptor old;
+            if (descriptorsByName.TryGetValue(fullName, out old))
+            {
+                if (!(old is PackageDescriptor))
+                {
+                    throw new DescriptorValidationException(file,
+                                                            "\"" + name +
+                                                            "\" is already defined (as something other than a " +
+                                                            "package) in file \"" + old.File.Name + "\".");
+                }
+            }
+            descriptorsByName[fullName] = new PackageDescriptor(name, fullName, file);
+        }
+
+        /// <summary>
+        /// Adds a symbol to the symbol table.
+        /// </summary>
+        /// <exception cref="DescriptorValidationException">The symbol already existed
+        /// in the symbol table.</exception>
+        internal void AddSymbol(IDescriptor descriptor)
+        {
+            ValidateSymbolName(descriptor);
+            String fullName = descriptor.FullName;
+
+            IDescriptor old;
+            if (descriptorsByName.TryGetValue(fullName, out old))
+            {
+                int dotPos = fullName.LastIndexOf('.');
+                string message;
+                if (descriptor.File == old.File)
+                {
+                    if (dotPos == -1)
+                    {
+                        message = "\"" + fullName + "\" is already defined.";
+                    }
+                    else
+                    {
+                        message = "\"" + fullName.Substring(dotPos + 1) + "\" is already defined in \"" +
+                                  fullName.Substring(0, dotPos) + "\".";
+                    }
+                }
+                else
+                {
+                    message = "\"" + fullName + "\" is already defined in file \"" + old.File.Name + "\".";
+                }
+                throw new DescriptorValidationException(descriptor, message);
+            }
+            descriptorsByName[fullName] = descriptor;
+        }
+
+        private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$",
+                                                                  FrameworkPortability.CompiledRegexWhereAvailable);
+
+        /// <summary>
+        /// Verifies that the descriptor's name is valid (i.e. it contains
+        /// only letters, digits and underscores, and does not start with a digit).
+        /// </summary>
+        /// <param name="descriptor"></param>
+        private static void ValidateSymbolName(IDescriptor descriptor)
+        {
+            if (descriptor.Name == "")
+            {
+                throw new DescriptorValidationException(descriptor, "Missing name.");
+            }
+            if (!ValidationRegex.IsMatch(descriptor.Name))
+            {
+                throw new DescriptorValidationException(descriptor,
+                                                        "\"" + descriptor.Name + "\" is not a valid identifier.");
+            }
+        }
+
+        /// <summary>
+        /// Returns the field with the given number in the given descriptor,
+        /// or null if it can't be found.
+        /// </summary>
+        internal FieldDescriptor FindFieldByNumber(MessageDescriptor messageDescriptor, int number)
+        {
+            FieldDescriptor ret;
+            fieldsByNumber.TryGetValue(new DescriptorIntPair(messageDescriptor, number), out ret);
+            return ret;
+        }
+
+        internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number)
+        {
+            EnumValueDescriptor ret;
+            enumValuesByNumber.TryGetValue(new DescriptorIntPair(enumDescriptor, number), out ret);
+            return ret;
+        }
+
+        /// <summary>
+        /// Adds a field to the fieldsByNumber table.
+        /// </summary>
+        /// <exception cref="DescriptorValidationException">A field with the same
+        /// containing type and number already exists.</exception>
+        internal void AddFieldByNumber(FieldDescriptor field)
+        {
+            DescriptorIntPair key = new DescriptorIntPair(field.ContainingType, field.FieldNumber);
+            FieldDescriptor old;
+            if (fieldsByNumber.TryGetValue(key, out old))
+            {
+                throw new DescriptorValidationException(field, "Field number " + field.FieldNumber +
+                                                               "has already been used in \"" +
+                                                               field.ContainingType.FullName +
+                                                               "\" by field \"" + old.Name + "\".");
+            }
+            fieldsByNumber[key] = field;
+        }
+
+        /// <summary>
+        /// Adds an enum value to the enumValuesByNumber table. If an enum value
+        /// with the same type and number already exists, this method does nothing.
+        /// (This is allowed; the first value defined with the number takes precedence.)
+        /// </summary>
+        internal void AddEnumValueByNumber(EnumValueDescriptor enumValue)
+        {
+            DescriptorIntPair key = new DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number);
+            if (!enumValuesByNumber.ContainsKey(key))
+            {
+                enumValuesByNumber[key] = enumValue;
+            }
+        }
+
+        /// <summary>
+        /// Looks up a descriptor by name, relative to some other descriptor.
+        /// The name may be fully-qualified (with a leading '.'), partially-qualified,
+        /// or unqualified. C++-like name lookup semantics are used to search for the
+        /// matching descriptor.
+        /// </summary>
+        /// <remarks>
+        /// This isn't heavily optimized, but it's only used during cross linking anyway.
+        /// If it starts being used more widely, we should look at performance more carefully.
+        /// </remarks>
+        internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
+        {
+            IDescriptor result;
+            if (name.StartsWith("."))
+            {
+                // Fully-qualified name.
+                result = FindSymbol<IDescriptor>(name.Substring(1));
+            }
+            else
+            {
+                // If "name" is a compound identifier, we want to search for the
+                // first component of it, then search within it for the rest.
+                int firstPartLength = name.IndexOf('.');
+                string firstPart = firstPartLength == -1 ? name : name.Substring(0, firstPartLength);
+
+                // We will search each parent scope of "relativeTo" looking for the
+                // symbol.
+                StringBuilder scopeToTry = new StringBuilder(relativeTo.FullName);
+
+                while (true)
+                {
+                    // Chop off the last component of the scope.
+
+                    int dotpos = scopeToTry.ToString().LastIndexOf(".");
+                    if (dotpos == -1)
+                    {
+                        result = FindSymbol<IDescriptor>(name);
+                        break;
+                    }
+                    else
+                    {
+                        scopeToTry.Length = dotpos + 1;
+
+                        // Append firstPart and try to find.
+                        scopeToTry.Append(firstPart);
+                        result = FindSymbol<IDescriptor>(scopeToTry.ToString());
+
+                        if (result != null)
+                        {
+                            if (firstPartLength != -1)
+                            {
+                                // We only found the first part of the symbol.  Now look for
+                                // the whole thing.  If this fails, we *don't* want to keep
+                                // searching parent scopes.
+                                scopeToTry.Length = dotpos + 1;
+                                scopeToTry.Append(name);
+                                result = FindSymbol<IDescriptor>(scopeToTry.ToString());
+                            }
+                            break;
+                        }
+
+                        // Not found.  Remove the name so we can try again.
+                        scopeToTry.Length = dotpos;
+                    }
+                }
+            }
+
+            if (result == null)
+            {
+                throw new DescriptorValidationException(relativeTo, "\"" + name + "\" is not defined.");
+            }
+            else
+            {
+                return result;
+            }
+        }
+
+        /// <summary>
+        /// Struct used to hold the keys for the fieldByNumber table.
+        /// </summary>
+        private struct DescriptorIntPair : IEquatable<DescriptorIntPair>
+        {
+            private readonly int number;
+            private readonly IDescriptor descriptor;
+
+            internal DescriptorIntPair(IDescriptor descriptor, int number)
+            {
+                this.number = number;
+                this.descriptor = descriptor;
+            }
+
+            public bool Equals(DescriptorIntPair other)
+            {
+                return descriptor == other.descriptor
+                       && number == other.number;
+            }
+
+            public override bool Equals(object obj)
+            {
+                if (obj is DescriptorIntPair)
+                {
+                    return Equals((DescriptorIntPair) obj);
+                }
+                return false;
+            }
+
+            public override int GetHashCode()
+            {
+                return descriptor.GetHashCode()*((1 << 16) - 1) + number;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs
new file mode 100644
index 0000000..f5570fc
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Internal class containing utility methods when working with descriptors.
+    /// </summary>
+    internal static class DescriptorUtil
+    {
+        /// <summary>
+        /// Equivalent to Func[TInput, int, TOutput] but usable in .NET 2.0. Only used to convert
+        /// arrays.
+        /// </summary>
+        internal delegate TOutput IndexedConverter<TInput, TOutput>(TInput element, int index);
+
+        /// <summary>
+        /// Converts the given array into a read-only list, applying the specified conversion to
+        /// each input element.
+        /// </summary>
+        internal static IList<TOutput> ConvertAndMakeReadOnly<TInput, TOutput>
+            (IList<TInput> input, IndexedConverter<TInput, TOutput> converter)
+        {
+            TOutput[] array = new TOutput[input.Count];
+            for (int i = 0; i < array.Length; i++)
+            {
+                array[i] = converter(input[i], i);
+            }
+            return new ReadOnlyCollection<TOutput>(array);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs
new file mode 100644
index 0000000..143671d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs
@@ -0,0 +1,80 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Thrown when building descriptors fails because the source DescriptorProtos
+    /// are not valid.
+    /// </summary>
+    public sealed class DescriptorValidationException : Exception
+    {
+        private readonly String name;
+        private readonly string description;
+
+        /// <value>
+        /// The full name of the descriptor where the error occurred.
+        /// </value>
+        public String ProblemSymbolName
+        {
+            get { return name; }
+        }
+
+        /// <value>
+        /// A human-readable description of the error. (The Message property
+        /// is made up of the descriptor's name and this description.)
+        /// </value>
+        public string Description
+        {
+            get { return description; }
+        }
+
+        internal DescriptorValidationException(IDescriptor problemDescriptor, string description) :
+            base(problemDescriptor.FullName + ": " + description)
+        {
+            // Note that problemDescriptor may be partially uninitialized, so we
+            // don't want to expose it directly to the user.  So, we only provide
+            // the name and the original proto.
+            name = problemDescriptor.FullName;
+            this.description = description;
+        }
+
+        internal DescriptorValidationException(IDescriptor problemDescriptor, string description, Exception cause) :
+            base(problemDescriptor.FullName + ": " + description, cause)
+        {
+            name = problemDescriptor.FullName;
+            this.description = description;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
new file mode 100644
index 0000000..c732c93
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
@@ -0,0 +1,116 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for an enum type in a .proto file.
+    /// </summary>
+    public sealed class EnumDescriptor : DescriptorBase
+    {
+        private readonly EnumDescriptorProto proto;
+        private readonly MessageDescriptor containingType;
+        private readonly IList<EnumValueDescriptor> values;
+        private readonly Type clrType;
+
+        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.proto = proto;
+            this.clrType = clrType;
+            containingType = parent;
+
+            if (proto.Value.Count == 0)
+            {
+                // We cannot allow enums with no values because this would mean there
+                // would be no valid default value for fields of this type.
+                throw new DescriptorValidationException(this, "Enums must contain at least one value.");
+            }
+
+            values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value,
+                                                           (value, i) => new EnumValueDescriptor(value, file, this, i));
+
+            File.DescriptorPool.AddSymbol(this);
+        }
+
+        internal EnumDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// The CLR type for this enum. For generated code, this will be a CLR enum type.
+        /// </summary>
+        public Type ClrType { get { return clrType; } }
+
+        /// <value>
+        /// If this is a nested type, get the outer descriptor, otherwise null.
+        /// </value>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <value>
+        /// An unmodifiable list of defined value descriptors for this enum.
+        /// </value>
+        public IList<EnumValueDescriptor> Values
+        {
+            get { return values; }
+        }
+
+        /// <summary>
+        /// Finds an enum value by number. If multiple enum values have the
+        /// same number, this returns the first defined value with that number.
+        /// If there is no value for the given number, this returns <c>null</c>.
+        /// </summary>
+        public EnumValueDescriptor FindValueByNumber(int number)
+        {
+            return File.DescriptorPool.FindEnumValueByNumber(this, number);
+        }
+
+        /// <summary>
+        /// Finds an enum value by name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the value (e.g. "FOO").</param>
+        /// <returns>The value's descriptor, or null if not found.</returns>
+        public EnumValueDescriptor FindValueByName(string name)
+        {
+            return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
new file mode 100644
index 0000000..b212ce9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
@@ -0,0 +1,70 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for a single enum value within an enum in a .proto file.
+    /// </summary>
+    public sealed class EnumValueDescriptor : DescriptorBase                                            
+    {
+        private readonly EnumDescriptor enumDescriptor;
+        private readonly EnumValueDescriptorProto proto;
+
+        internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
+                                     EnumDescriptor parent, int index)
+            : base(file, parent.FullName + "." + proto.Name, index)
+        {
+            this.proto = proto;
+            enumDescriptor = parent;
+            file.DescriptorPool.AddSymbol(this);
+            file.DescriptorPool.AddEnumValueByNumber(this);
+        }
+
+        internal EnumValueDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// Returns the name of the enum value described by this object.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// Returns the number associated with this enum value.
+        /// </summary>
+        public int Number { get { return Proto.Number; } }
+
+        /// <summary>
+        /// Returns the enum descriptor that this value is part of.
+        /// </summary>
+        public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
new file mode 100644
index 0000000..82ce505
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Base class for field accessors.
+    /// </summary>
+    internal abstract class FieldAccessorBase : IFieldAccessor
+    {
+        private readonly Func<IMessage, object> getValueDelegate;
+        private readonly FieldDescriptor descriptor;
+
+        internal FieldAccessorBase(PropertyInfo property, FieldDescriptor descriptor)
+        {
+            this.descriptor = descriptor;
+            getValueDelegate = ReflectionUtil.CreateFuncIMessageObject(property.GetGetMethod());
+        }
+
+        public FieldDescriptor Descriptor { get { return descriptor; } }
+
+        public object GetValue(IMessage message)
+        {
+            return getValueDelegate(message);
+        }
+
+        public abstract void Clear(IMessage message);
+        public abstract void SetValue(IMessage message, object value);
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
new file mode 100644
index 0000000..6c6f6ee
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -0,0 +1,343 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using Google.Protobuf.Compatibility;
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for a field or extension within a message in a .proto file.
+    /// </summary>
+    public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
+    {
+        private EnumDescriptor enumType;
+        private MessageDescriptor messageType;
+        private FieldType fieldType;
+        private readonly string propertyName; // Annoyingly, needed in Crosslink.
+        private IFieldAccessor accessor;
+
+        /// <summary>
+        /// Get the field's containing message type.
+        /// </summary>
+        public MessageDescriptor ContainingType { get; }
+
+        /// <summary>
+        /// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
+        /// </summary>
+        public OneofDescriptor ContainingOneof { get; }
+
+        /// <summary>
+        /// The effective JSON name for this field. This is usually the lower-camel-cased form of the field name,
+        /// but can be overridden using the <c>json_name</c> option in the .proto file.
+        /// </summary>
+        public string JsonName { get; }
+
+        internal FieldDescriptorProto Proto { get; }
+
+        internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
+                                 MessageDescriptor parent, int index, string propertyName)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            Proto = proto;
+            if (proto.Type != 0)
+            {
+                fieldType = GetFieldTypeFromProtoType(proto.Type);
+            }
+
+            if (FieldNumber <= 0)
+            {
+                throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
+            }
+            ContainingType = parent;
+            // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
+            if (proto.OneofIndex != -1)
+            {
+                if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
+                {
+                    throw new DescriptorValidationException(this,
+                        $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
+                }
+                ContainingOneof = parent.Oneofs[proto.OneofIndex];
+            }
+
+            file.DescriptorPool.AddSymbol(this);
+            // We can't create the accessor until we've cross-linked, unfortunately, as we
+            // may not know whether the type of the field is a map or not. Remember the property name
+            // for later.
+            // We could trust the generated code and check whether the type of the property is
+            // a MapField, but that feels a tad nasty.
+            this.propertyName = propertyName;
+            JsonName =  Proto.JsonName == "" ? JsonFormatter.ToCamelCase(Proto.Name) : Proto.JsonName;
+        }
+    
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name => Proto.Name;
+
+        /// <summary>
+        /// Returns the accessor for this field.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// While a <see cref="FieldDescriptor"/> describes the field, it does not provide
+        /// any way of obtaining or changing the value of the field within a specific message;
+        /// that is the responsibility of the accessor.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, and the value of the map field itself is represented by a dictionary in the
+        /// reflection API. There are never instances of those "hidden" messages, so no accessor is provided
+        /// and this property will return null.
+        /// </para>
+        /// </remarks>
+        public IFieldAccessor Accessor => accessor;
+        
+        /// <summary>
+        /// Maps a field type as included in the .proto file to a FieldType.
+        /// </summary>
+        private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Type type)
+        {
+            switch (type)
+            {
+                case FieldDescriptorProto.Types.Type.Double:
+                    return FieldType.Double;
+                case FieldDescriptorProto.Types.Type.Float:
+                    return FieldType.Float;
+                case FieldDescriptorProto.Types.Type.Int64:
+                    return FieldType.Int64;
+                case FieldDescriptorProto.Types.Type.Uint64:
+                    return FieldType.UInt64;
+                case FieldDescriptorProto.Types.Type.Int32:
+                    return FieldType.Int32;
+                case FieldDescriptorProto.Types.Type.Fixed64:
+                    return FieldType.Fixed64;
+                case FieldDescriptorProto.Types.Type.Fixed32:
+                    return FieldType.Fixed32;
+                case FieldDescriptorProto.Types.Type.Bool:
+                    return FieldType.Bool;
+                case FieldDescriptorProto.Types.Type.String:
+                    return FieldType.String;
+                case FieldDescriptorProto.Types.Type.Group:
+                    return FieldType.Group;
+                case FieldDescriptorProto.Types.Type.Message:
+                    return FieldType.Message;
+                case FieldDescriptorProto.Types.Type.Bytes:
+                    return FieldType.Bytes;
+                case FieldDescriptorProto.Types.Type.Uint32:
+                    return FieldType.UInt32;
+                case FieldDescriptorProto.Types.Type.Enum:
+                    return FieldType.Enum;
+                case FieldDescriptorProto.Types.Type.Sfixed32:
+                    return FieldType.SFixed32;
+                case FieldDescriptorProto.Types.Type.Sfixed64:
+                    return FieldType.SFixed64;
+                case FieldDescriptorProto.Types.Type.Sint32:
+                    return FieldType.SInt32;
+                case FieldDescriptorProto.Types.Type.Sint64:
+                    return FieldType.SInt64;
+                default:
+                    throw new ArgumentException("Invalid type specified");
+            }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated;
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsMap => fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry;
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsPacked => 
+            // Note the || rather than && here - we're effectively defaulting to packed, because that *is*
+            // the default in proto3, which is all we support. We may give the wrong result for the protos
+            // within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
+            // within the runtime.
+            Proto.Options == null || Proto.Options.Packed;
+        
+        /// <summary>
+        /// Returns the type of the field.
+        /// </summary>
+        public FieldType FieldType => fieldType;
+
+        /// <summary>
+        /// Returns the field number declared in the proto file.
+        /// </summary>
+        public int FieldNumber => Proto.Number;
+
+        /// <summary>
+        /// Compares this descriptor with another one, ordering in "canonical" order
+        /// which simply means ascending order by field number. <paramref name="other"/>
+        /// must be a field of the same type, i.e. the <see cref="ContainingType"/> of
+        /// both fields must be the same.
+        /// </summary>
+        public int CompareTo(FieldDescriptor other)
+        {
+            if (other.ContainingType != ContainingType)
+            {
+                throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
+                                            "for fields of the same message type.");
+            }
+            return FieldNumber - other.FieldNumber;
+        }
+
+        /// <summary>
+        /// For enum fields, returns the field's type.
+        /// </summary>
+        public EnumDescriptor EnumType
+        {
+            get
+            {
+                if (fieldType != FieldType.Enum)
+                {
+                    throw new InvalidOperationException("EnumType is only valid for enum fields.");
+                }
+                return enumType;
+            }
+        }
+
+        /// <summary>
+        /// For embedded message and group fields, returns the field's type.
+        /// </summary>
+        public MessageDescriptor MessageType
+        {
+            get
+            {
+                if (fieldType != FieldType.Message)
+                {
+                    throw new InvalidOperationException("MessageType is only valid for message fields.");
+                }
+                return messageType;
+            }
+        }
+
+        /// <summary>
+        /// Look up and cross-link all field types etc.
+        /// </summary>
+        internal void CrossLink()
+        {
+            if (Proto.TypeName != "")
+            {
+                IDescriptor typeDescriptor =
+                    File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
+
+                if (Proto.Type != 0)
+                {
+                    // Choose field type based on symbol.
+                    if (typeDescriptor is MessageDescriptor)
+                    {
+                        fieldType = FieldType.Message;
+                    }
+                    else if (typeDescriptor is EnumDescriptor)
+                    {
+                        fieldType = FieldType.Enum;
+                    }
+                    else
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a type.");
+                    }
+                }
+
+                if (fieldType == FieldType.Message)
+                {
+                    if (!(typeDescriptor is MessageDescriptor))
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
+                    }
+                    messageType = (MessageDescriptor) typeDescriptor;
+
+                    if (Proto.DefaultValue != "")
+                    {
+                        throw new DescriptorValidationException(this, "Messages can't have default values.");
+                    }
+                }
+                else if (fieldType == FieldType.Enum)
+                {
+                    if (!(typeDescriptor is EnumDescriptor))
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type.");
+                    }
+                    enumType = (EnumDescriptor) typeDescriptor;
+                }
+                else
+                {
+                    throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
+                }
+            }
+            else
+            {
+                if (fieldType == FieldType.Message || fieldType == FieldType.Enum)
+                {
+                    throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
+                }
+            }
+
+            // Note: no attempt to perform any default value parsing
+
+            File.DescriptorPool.AddFieldByNumber(this);
+
+            if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat)
+            {
+                throw new DescriptorValidationException(this, "MessageSet format is not supported.");
+            }
+            accessor = CreateAccessor();
+        }
+
+        private IFieldAccessor CreateAccessor()
+        {
+            // If we're given no property name, that's because we really don't want an accessor.
+            // (At the moment, that means it's a map entry message...)
+            if (propertyName == null)
+            {
+                return null;
+            }
+            var property = ContainingType.ClrType.GetProperty(propertyName);
+            if (property == null)
+            {
+                throw new DescriptorValidationException(this, $"Property {propertyName} not found in {ContainingType.ClrType}");
+            }
+            return IsMap ? new MapFieldAccessor(property, this)
+                : IsRepeated ? new RepeatedFieldAccessor(property, this)
+                : (IFieldAccessor) new SingleFieldAccessor(property, this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldType.cs b/csharp/src/Google.Protobuf/Reflection/FieldType.cs
new file mode 100644
index 0000000..1658e34
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldType.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Enumeration of all the possible field types.
+    /// </summary>
+    public enum FieldType
+    {
+        /// <summary>
+        /// The <c>double</c> field type.
+        /// </summary>
+        Double,
+        /// <summary>
+        /// The <c>float</c> field type.
+        /// </summary>
+        Float,
+        /// <summary>
+        /// The <c>int64</c> field type.
+        /// </summary>
+        Int64,
+        /// <summary>
+        /// The <c>uint64</c> field type.
+        /// </summary>
+        UInt64,
+        /// <summary>
+        /// The <c>int32</c> field type.
+        /// </summary>
+        Int32,
+        /// <summary>
+        /// The <c>fixed64</c> field type.
+        /// </summary>
+        Fixed64,
+        /// <summary>
+        /// The <c>fixed32</c> field type.
+        /// </summary>
+        Fixed32,
+        /// <summary>
+        /// The <c>bool</c> field type.
+        /// </summary>
+        Bool,
+        /// <summary>
+        /// The <c>string</c> field type.
+        /// </summary>
+        String,
+        /// <summary>
+        /// The field type used for groups (not supported in this implementation).
+        /// </summary>
+        Group,
+        /// <summary>
+        /// The field type used for message fields.
+        /// </summary>
+        Message,
+        /// <summary>
+        /// The <c>bytes</c> field type.
+        /// </summary>
+        Bytes,
+        /// <summary>
+        /// The <c>uint32</c> field type.
+        /// </summary>
+        UInt32,
+        /// <summary>
+        /// The <c>sfixed32</c> field type.
+        /// </summary>
+        SFixed32,
+        /// <summary>
+        /// The <c>sfixed64</c> field type.
+        /// </summary>
+        SFixed64,
+        /// <summary>
+        /// The <c>sint32</c> field type.
+        /// </summary>
+        SInt32,
+        /// <summary>
+        /// The <c>sint64</c> field type.
+        /// </summary>
+        SInt64,
+        /// <summary>
+        /// The field type used for enum fields.
+        /// </summary>
+        Enum
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
new file mode 100644
index 0000000..ab7cd92
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -0,0 +1,344 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a .proto file, including everything defined within.
+    /// IDescriptor is implemented such that the File property returns this descriptor,
+    /// and the FullName is the same as the Name.
+    /// </summary>
+    public sealed class FileDescriptor : IDescriptor
+    {
+        private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            SerializedData = descriptorData;
+            DescriptorPool = pool;
+            Proto = proto;
+            Dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
+
+            PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
+
+            pool.AddPackage(Package, this);
+
+            MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
+                                                                 (message, index) =>
+                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo.NestedTypes[index]));
+
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
+                                                              (enumType, index) =>
+                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo.NestedEnums[index]));
+
+            Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
+                                                             (service, index) =>
+                                                             new ServiceDescriptor(service, this, index));
+        }
+
+        /// <summary>
+        /// Computes the full name of a descriptor within this file, with an optional parent message.
+        /// </summary>
+        internal string ComputeFullName(MessageDescriptor parent, string name)
+        {
+            if (parent != null)
+            {
+                return parent.FullName + "." + name;
+            }
+            if (Package.Length > 0)
+            {
+                return Package + "." + name;
+            }
+            return name;
+        }
+
+        /// <summary>
+        /// Extracts public dependencies from direct dependencies. This is a static method despite its
+        /// first parameter, as the value we're in the middle of constructing is only used for exceptions.
+        /// </summary>
+        private static IList<FileDescriptor> DeterminePublicDependencies(FileDescriptor @this, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies)
+        {
+            var nameToFileMap = new Dictionary<string, FileDescriptor>();
+            foreach (var file in dependencies)
+            {
+                nameToFileMap[file.Name] = file;
+            }
+            var publicDependencies = new List<FileDescriptor>();
+            for (int i = 0; i < proto.PublicDependency.Count; i++)
+            {
+                int index = proto.PublicDependency[i];
+                if (index < 0 || index >= proto.Dependency.Count)
+                {
+                    throw new DescriptorValidationException(@this, "Invalid public dependency index.");
+                }
+                string name = proto.Dependency[index];
+                FileDescriptor file = nameToFileMap[name];
+                if (file == null)
+                {
+                    if (!allowUnknownDependencies)
+                    {
+                        throw new DescriptorValidationException(@this, "Invalid public dependency: " + name);
+                    }
+                    // Ignore unknown dependencies.
+                }
+                else
+                {
+                    publicDependencies.Add(file);
+                }
+            }
+            return new ReadOnlyCollection<FileDescriptor>(publicDependencies);
+        }
+
+        /// <value>
+        /// The descriptor in its protocol message representation.
+        /// </value>
+        internal FileDescriptorProto Proto { get; }
+
+        /// <value>
+        /// The file name.
+        /// </value>
+        public string Name => Proto.Name;
+
+        /// <summary>
+        /// The package as declared in the .proto file. This may or may not
+        /// be equivalent to the .NET namespace of the generated classes.
+        /// </summary>
+        public string Package => Proto.Package;
+
+        /// <value>
+        /// Unmodifiable list of top-level message types declared in this file.
+        /// </value>
+        public IList<MessageDescriptor> MessageTypes { get; }
+
+        /// <value>
+        /// Unmodifiable list of top-level enum types declared in this file.
+        /// </value>
+        public IList<EnumDescriptor> EnumTypes { get; }
+
+        /// <value>
+        /// Unmodifiable list of top-level services declared in this file.
+        /// </value>
+        public IList<ServiceDescriptor> Services { get; }
+
+        /// <value>
+        /// Unmodifiable list of this file's dependencies (imports).
+        /// </value>
+        public IList<FileDescriptor> Dependencies { get; }
+
+        /// <value>
+        /// Unmodifiable list of this file's public dependencies (public imports).
+        /// </value>
+        public IList<FileDescriptor> PublicDependencies { get; }
+
+        /// <value>
+        /// The original serialized binary form of this descriptor.
+        /// </value>
+        public ByteString SerializedData { get; }
+
+        /// <value>
+        /// Implementation of IDescriptor.FullName - just returns the same as Name.
+        /// </value>
+        string IDescriptor.FullName => Name;
+
+        /// <value>
+        /// Implementation of IDescriptor.File - just returns this descriptor.
+        /// </value>
+        FileDescriptor IDescriptor.File => this;
+
+        /// <value>
+        /// Pool containing symbol descriptors.
+        /// </value>
+        internal DescriptorPool DescriptorPool { get; }
+
+        /// <summary>
+        /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
+        /// </summary>
+        /// <param name="name">The unqualified type name to look for.</param>
+        /// <typeparam name="T">The type of descriptor to look for</typeparam>
+        /// <returns>The type's descriptor, or null if not found.</returns>
+        public T FindTypeByName<T>(String name)
+            where T : class, IDescriptor
+        {
+            // Don't allow looking up nested types.  This will make optimization
+            // easier later.
+            if (name.IndexOf('.') != -1)
+            {
+                return null;
+            }
+            if (Package.Length > 0)
+            {
+                name = Package + "." + name;
+            }
+            T result = DescriptorPool.FindSymbol<T>(name);
+            if (result != null && result.File == this)
+            {
+                return result;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Builds a FileDescriptor from its protocol buffer representation.
+        /// </summary>
+        /// <param name="descriptorData">The original serialized descriptor data.
+        /// We have only limited proto2 support, so serializing FileDescriptorProto
+        /// would not necessarily give us this.</param>
+        /// <param name="proto">The protocol message form of the FileDescriptor.</param>
+        /// <param name="dependencies">FileDescriptors corresponding to all of the
+        /// file's dependencies, in the exact order listed in the .proto file. May be null,
+        /// in which case it is treated as an empty array.</param>
+        /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
+        /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
+        /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
+        /// a valid descriptor. This can occur for a number of reasons, such as a field
+        /// having an undefined type or because two messages were defined with the same name.</exception>
+        private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            // Building descriptors involves two steps: translating and linking.
+            // In the translation step (implemented by FileDescriptor's
+            // constructor), we build an object tree mirroring the
+            // FileDescriptorProto's tree and put all of the descriptors into the
+            // DescriptorPool's lookup tables.  In the linking step, we look up all
+            // type references in the DescriptorPool, so that, for example, a
+            // FieldDescriptor for an embedded message contains a pointer directly
+            // to the Descriptor for that message's type.  We also detect undefined
+            // types in the linking step.
+            if (dependencies == null)
+            {
+                dependencies = new FileDescriptor[0];
+            }
+
+            DescriptorPool pool = new DescriptorPool(dependencies);
+            FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo);
+
+            // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we
+            // need.
+            if (dependencies.Length != proto.Dependency.Count)
+            {
+                throw new DescriptorValidationException(
+                    result,
+                    "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+                    "those listed in the FileDescriptorProto.");
+            }
+            for (int i = 0; i < proto.Dependency.Count; i++)
+            {
+                if (dependencies[i].Name != proto.Dependency[i])
+                {
+                    throw new DescriptorValidationException(
+                        result,
+                        "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+                        "those listed in the FileDescriptorProto. Expected: " +
+                        proto.Dependency[i] + " but was: " + dependencies[i].Name);
+                }
+            }
+
+            result.CrossLink();
+            return result;
+        }
+
+        private void CrossLink()
+        {
+            foreach (MessageDescriptor message in MessageTypes)
+            {
+                message.CrossLink();
+            }
+
+            foreach (ServiceDescriptor service in Services)
+            {
+                service.CrossLink();
+            }
+        }
+
+        /// <summary>
+        /// Creates a descriptor for generated code.
+        /// </summary>
+        /// <remarks>
+        /// This method is only designed to be used by the results of generating code with protoc,
+        /// which creates the appropriate dependencies etc. It has to be public because the generated
+        /// code is "external", but should not be called directly by end users.
+        /// </remarks>
+        public static FileDescriptor FromGeneratedCode(
+            byte[] descriptorData,
+            FileDescriptor[] dependencies,
+            GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            FileDescriptorProto proto;
+            try
+            {
+                proto = FileDescriptorProto.Parser.ParseFrom(descriptorData);
+            }
+            catch (InvalidProtocolBufferException e)
+            {
+                throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
+            }
+
+            try
+            {
+                // When building descriptors for generated code, we allow unknown
+                // dependencies by default.
+                return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, true, generatedCodeInfo);
+            }
+            catch (DescriptorValidationException e)
+            {
+                throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e);
+            }
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String" /> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String" /> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return $"FileDescriptor for {Name}";
+        }
+
+        /// <summary>
+        /// Returns the file descriptor for descriptor.proto.
+        /// </summary>
+        /// <remarks>
+        /// This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for
+        /// annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf
+        /// runtime for reflection purposes. The messages are internal to the runtime as they would require
+        /// proto2 semantics for full support, but the file descriptor is available via this property. The
+        /// C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>.
+        /// </remarks>
+        /// <value>
+        /// The file descriptor for <c>descriptor.proto</c>.
+        /// </value>
+        public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
new file mode 100644
index 0000000..fe5db65
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Extra information provided by generated code when initializing a message or file descriptor.
+    /// These are constructed as required, and are not long-lived. Hand-written code should
+    /// never need to use this type.
+    /// </summary>
+    public sealed class GeneratedClrTypeInfo
+    {
+        private static readonly string[] EmptyNames = new string[0];
+        private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
+        /// </summary>
+        public Type ClrType { get; private set; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the parser for message descriptors.
+        /// </summary>
+        public MessageParser Parser { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
+        /// for fields in the message for message descriptors.
+        /// </summary>
+        public string[] PropertyNames { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
+        /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
+        /// there will be a "FooCase" property and a "ClearFoo" method.
+        /// </summary>
+        public string[] OneofNames { get; }
+
+        /// <summary>
+        /// The reflection information for types within this file/message descriptor. Elements may be null
+        /// if there is no corresponding generated type, e.g. for map entry types.
+        /// </summary>
+        public GeneratedClrTypeInfo[] NestedTypes { get; }
+
+        /// <summary>
+        /// The CLR types for enums within this file/message descriptor.
+        /// </summary>
+        public Type[] NestedEnums { get; }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
+        /// Each array parameter may be null, to indicate a lack of values.
+        /// The parameter order is designed to make it feasible to format the generated code readably.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+        {
+            NestedTypes = nestedTypes ?? EmptyCodeInfo;
+            NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
+            ClrType = clrType;
+            Parser = parser;
+            PropertyNames = propertyNames ?? EmptyNames;
+            OneofNames = oneofNames ?? EmptyNames;
+        }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a file descriptor, with only types and enums.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+            : this(null, null, null, null, nestedEnums, nestedTypes)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs
new file mode 100644
index 0000000..318d58c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Interface implemented by all descriptor types.
+    /// </summary>
+    public interface IDescriptor
+    {
+        /// <summary>
+        /// Returns the name of the entity (message, field etc) being described.
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Returns the fully-qualified name of the entity being described.
+        /// </summary>
+        string FullName { get; }
+
+        /// <summary>
+        /// Returns the descriptor for the .proto file that this entity is part of.
+        /// </summary>
+        FileDescriptor File { get; }
+    }    
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
new file mode 100644
index 0000000..cfe56fd
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
@@ -0,0 +1,71 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Allows fields to be reflectively accessed.
+    /// </summary>
+    public interface IFieldAccessor
+    {
+        /// <summary>
+        /// Returns the descriptor associated with this field.
+        /// </summary>
+        FieldDescriptor Descriptor { get; }
+
+        /// <summary>
+        /// Clears the field in the specified message. (For repeated fields,
+        /// this clears the list.)
+        /// </summary>
+        void Clear(IMessage message);
+
+        /// <summary>
+        /// Fetches the field value. For repeated values, this will be an
+        /// <see cref="IList"/> implementation. For map values, this will be an
+        /// <see cref="IDictionary"/> implementation.
+        /// </summary>
+        object GetValue(IMessage message);
+
+        /// <summary>
+        /// Mutator for single "simple" fields only.
+        /// </summary>
+        /// <remarks>
+        /// Repeated fields are mutated by fetching the value and manipulating it as a list.
+        /// Map fields are mutated by fetching the value and manipulating it as a dictionary.
+        /// </remarks>
+        /// <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
+        void SetValue(IMessage message, object value);
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
new file mode 100644
index 0000000..9ed7f8c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for map fields.
+    /// </summary>
+    internal sealed class MapFieldAccessor : FieldAccessorBase
+    {
+        internal MapFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+        }
+
+        public override void Clear(IMessage message)
+        {
+            IDictionary list = (IDictionary) GetValue(message);
+            list.Clear();
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            throw new InvalidOperationException("SetValue is not implemented for map fields");
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
new file mode 100644
index 0000000..f5a835e
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -0,0 +1,317 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a message type.
+    /// </summary>
+    public sealed class MessageDescriptor : DescriptorBase
+    {
+        private static readonly HashSet<string> WellKnownTypeNames = new HashSet<string>
+        {
+            "google/protobuf/any.proto",
+            "google/protobuf/api.proto",
+            "google/protobuf/duration.proto",
+            "google/protobuf/empty.proto",
+            "google/protobuf/wrappers.proto",
+            "google/protobuf/timestamp.proto",
+            "google/protobuf/field_mask.proto",
+            "google/protobuf/source_context.proto",
+            "google/protobuf/struct.proto",
+            "google/protobuf/type.proto",
+        };
+
+        private readonly IList<FieldDescriptor> fieldsInDeclarationOrder;
+        private readonly IList<FieldDescriptor> fieldsInNumberOrder;
+        private readonly IDictionary<string, FieldDescriptor> jsonFieldMap;
+        
+        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedClrTypeInfo generatedCodeInfo)
+            : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
+        {
+            Proto = proto;
+            Parser = generatedCodeInfo?.Parser;
+            ClrType = generatedCodeInfo?.ClrType;
+            ContainingType = parent;
+
+            // Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
+            // to see any nested oneofs, types or enums in "not actually generated" code... we do
+            // expect fields though (for map entry messages).
+            Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.OneofDecl,
+                (oneof, index) =>
+                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo.OneofNames[index]));
+
+            NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.NestedType,
+                (type, index) =>
+                new MessageDescriptor(type, file, this, index, generatedCodeInfo.NestedTypes[index]));
+
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.EnumType,
+                (type, index) =>
+                new EnumDescriptor(type, file, this, index, generatedCodeInfo.NestedEnums[index]));
+
+            fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.Field,
+                (field, index) =>
+                new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index]));
+            fieldsInNumberOrder = new ReadOnlyCollection<FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray());
+            // TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
+            jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder);
+            file.DescriptorPool.AddSymbol(this);
+            Fields = new FieldCollection(this);
+        }
+
+        private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields)
+        {
+            var map = new Dictionary<string, FieldDescriptor>();
+            foreach (var field in fields)
+            {
+                map[field.Name] = field;
+                map[field.JsonName] = field;
+            }
+            return new ReadOnlyDictionary<string, FieldDescriptor>(map);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name => Proto.Name;
+
+        internal DescriptorProto Proto { get; }
+
+        /// <summary>
+        /// The CLR type used to represent message instances from this descriptor.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public Type ClrType { get; }
+
+        /// <summary>
+        /// A parser for this message type.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
+        /// typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. No message parser object is created for
+        /// such messages, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public MessageParser Parser { get; }
+
+        /// <summary>
+        /// Returns whether this message is one of the "well known types" which may have runtime/protoc support.
+        /// </summary>
+        internal bool IsWellKnownType => File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
+
+        /// <summary>
+        /// Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
+        /// with the addition of presence.
+        /// </summary>
+        internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
+
+        /// <value>
+        /// If this is a nested type, get the outer descriptor, otherwise null.
+        /// </value>
+        public MessageDescriptor ContainingType { get; }
+
+        /// <value>
+        /// A collection of fields, which can be retrieved by name or field number.
+        /// </value>
+        public FieldCollection Fields { get; }
+
+        /// <value>
+        /// An unmodifiable list of this message type's nested types.
+        /// </value>
+        public IList<MessageDescriptor> NestedTypes { get; }
+
+        /// <value>
+        /// An unmodifiable list of this message type's enum types.
+        /// </value>
+        public IList<EnumDescriptor> EnumTypes { get; }
+
+        /// <value>
+        /// An unmodifiable list of the "oneof" field collections in this message type.
+        /// </value>
+        public IList<OneofDescriptor> Oneofs { get; }
+
+        /// <summary>
+        /// Finds a field by field name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the field (e.g. "foo").</param>
+        /// <returns>The field's descriptor, or null if not found.</returns>
+        public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
+
+        /// <summary>
+        /// Finds a field by field number.
+        /// </summary>
+        /// <param name="number">The field number within this message type.</param>
+        /// <returns>The field's descriptor, or null if not found.</returns>
+        public FieldDescriptor FindFieldByNumber(int number) => File.DescriptorPool.FindFieldByNumber(this, number);
+
+        /// <summary>
+        /// Finds a nested descriptor by name. The is valid for fields, nested
+        /// message types, oneofs and enums.
+        /// </summary>
+        /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
+        /// <returns>The descriptor, or null if not found.</returns>
+        public T FindDescriptor<T>(string name)  where T : class, IDescriptor =>
+            File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
+
+        /// <summary>
+        /// Looks up and cross-links all fields and nested types.
+        /// </summary>
+        internal void CrossLink()
+        {
+            foreach (MessageDescriptor message in NestedTypes)
+            {
+                message.CrossLink();
+            }
+
+            foreach (FieldDescriptor field in fieldsInDeclarationOrder)
+            {
+                field.CrossLink();
+            }
+
+            foreach (OneofDescriptor oneof in Oneofs)
+            {
+                oneof.CrossLink();
+            }
+        }
+
+        /// <summary>
+        /// A collection to simplify retrieving the field accessor for a particular field.
+        /// </summary>
+        public sealed class FieldCollection
+        {
+            private readonly MessageDescriptor messageDescriptor;
+
+            internal FieldCollection(MessageDescriptor messageDescriptor)
+            {
+                this.messageDescriptor = messageDescriptor;
+            }
+
+            /// <value>
+            /// Returns the fields in the message as an immutable list, in the order in which they
+            /// are declared in the source .proto file.
+            /// </value>
+            public IList<FieldDescriptor> InDeclarationOrder() => messageDescriptor.fieldsInDeclarationOrder;
+
+            /// <value>
+            /// Returns the fields in the message as an immutable list, in ascending field number
+            /// order. Field numbers need not be contiguous, so there is no direct mapping from the
+            /// index in the list to the field number; to retrieve a field by field number, it is better
+            /// to use the <see cref="FieldCollection"/> indexer.
+            /// </value>
+            public IList<FieldDescriptor> InFieldNumberOrder() => messageDescriptor.fieldsInNumberOrder;
+
+            // TODO: consider making this public in the future. (Being conservative for now...)
+
+            /// <value>
+            /// Returns a read-only dictionary mapping the field names in this message as they're available
+            /// in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
+            /// in the message would result two entries, one with a key <c>fooBar</c> and one with a key
+            /// <c>foo_bar</c>, both referring to the same field.
+            /// </value>
+            internal IDictionary<string, FieldDescriptor> ByJsonName() => messageDescriptor.jsonFieldMap;
+
+            /// <summary>
+            /// Retrieves the descriptor for the field with the given number.
+            /// </summary>
+            /// <param name="number">Number of the field to retrieve the descriptor for</param>
+            /// <returns>The accessor for the given field</returns>
+            /// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
+            /// with the given number</exception>
+            public FieldDescriptor this[int number]
+            {
+                get
+                {
+                    var fieldDescriptor = messageDescriptor.FindFieldByNumber(number);
+                    if (fieldDescriptor == null)
+                    {
+                        throw new KeyNotFoundException("No such field number");
+                    }
+                    return fieldDescriptor;
+                }
+            }
+
+            /// <summary>
+            /// Retrieves the descriptor for the field with the given name.
+            /// </summary>
+            /// <param name="name">Name of the field to retrieve the descriptor for</param>
+            /// <returns>The descriptor for the given field</returns>
+            /// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
+            /// with the given name</exception>
+            public FieldDescriptor this[string name]
+            {
+                get
+                {
+                    var fieldDescriptor = messageDescriptor.FindFieldByName(name);
+                    if (fieldDescriptor == null)
+                    {
+                        throw new KeyNotFoundException("No such field name");
+                    }
+                    return fieldDescriptor;
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
new file mode 100644
index 0000000..f9539f6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a single method in a service.
+    /// </summary>
+    public sealed class MethodDescriptor : DescriptorBase
+    {
+        private readonly MethodDescriptorProto proto;
+        private readonly ServiceDescriptor service;
+        private MessageDescriptor inputType;
+        private MessageDescriptor outputType;
+
+        /// <value>
+        /// The service this method belongs to.
+        /// </value>
+        public ServiceDescriptor Service { get { return service; } }
+
+        /// <value>
+        /// The method's input type.
+        /// </value>
+        public MessageDescriptor InputType { get { return inputType; } }
+
+        /// <value>
+        /// The method's input type.
+        /// </value>
+        public MessageDescriptor OutputType { get { return outputType; } }
+
+        /// <value>
+        /// Indicates if client streams multiple requests.
+        /// </value>
+        public bool IsClientStreaming { get { return proto.ClientStreaming; } }
+
+        /// <value>
+        /// Indicates if server streams multiple responses.
+        /// </value>
+        public bool IsServerStreaming { get { return proto.ServerStreaming; } }
+
+        internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
+                                  ServiceDescriptor parent, int index)
+            : base(file, parent.FullName + "." + proto.Name, index)
+        {
+            this.proto = proto;
+            service = parent;
+            file.DescriptorPool.AddSymbol(this);
+        }
+
+        internal MethodDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal void CrossLink()
+        {
+            IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);
+            if (!(lookup is MessageDescriptor))
+            {
+                throw new DescriptorValidationException(this, "\"" + Proto.InputType + "\" is not a message type.");
+            }
+            inputType = (MessageDescriptor) lookup;
+
+            lookup = File.DescriptorPool.LookupSymbol(Proto.OutputType, this);
+            if (!(lookup is MessageDescriptor))
+            {
+                throw new DescriptorValidationException(this, "\"" + Proto.OutputType + "\" is not a message type.");
+            }
+            outputType = (MessageDescriptor) lookup;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
new file mode 100644
index 0000000..8714ab1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
@@ -0,0 +1,90 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Reflection access for a oneof, allowing clear and "get case" actions.
+    /// </summary>
+    public sealed class OneofAccessor
+    {
+        private readonly Func<IMessage, int> caseDelegate;
+        private readonly Action<IMessage> clearDelegate;
+        private OneofDescriptor descriptor;
+
+        internal OneofAccessor(PropertyInfo caseProperty, MethodInfo clearMethod, OneofDescriptor descriptor) 
+        {
+            if (!caseProperty.CanRead)
+            {
+                throw new ArgumentException("Cannot read from property");
+            }
+            this.descriptor = descriptor;
+            caseDelegate = ReflectionUtil.CreateFuncIMessageT<int>(caseProperty.GetGetMethod());
+
+            this.descriptor = descriptor;
+            clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
+        }
+
+        /// <summary>
+        /// Gets the descriptor for this oneof.
+        /// </summary>
+        /// <value>
+        /// The descriptor of the oneof.
+        /// </value>
+        public OneofDescriptor Descriptor { get { return descriptor; } }
+
+        /// <summary>
+        /// Clears the oneof in the specified message.
+        /// </summary>
+        public void Clear(IMessage message)
+        {
+            clearDelegate(message);
+        }
+
+        /// <summary>
+        /// Indicates which field in the oneof is set for specified message
+        /// </summary>
+        public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
+        {
+            int fieldNumber = caseDelegate(message);
+            if (fieldNumber > 0)
+            {
+                return descriptor.ContainingType.FindFieldByNumber(fieldNumber);
+            }
+            return null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
new file mode 100644
index 0000000..22020ac
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
@@ -0,0 +1,122 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a "oneof" field collection in a message type: a set of
+    /// fields of which at most one can be set in any particular message.
+    /// </summary>
+    public sealed class OneofDescriptor : DescriptorBase
+    {
+        private readonly OneofDescriptorProto proto;
+        private MessageDescriptor containingType;
+        private IList<FieldDescriptor> fields;
+        private readonly OneofAccessor accessor;
+
+        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string clrName)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.proto = proto;
+            containingType = parent;
+
+            file.DescriptorPool.AddSymbol(this);
+            accessor = CreateAccessor(clrName);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// Gets the message type containing this oneof.
+        /// </summary>
+        /// <value>
+        /// The message type containing this oneof.
+        /// </value>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <summary>
+        /// Gets the fields within this oneof, in declaration order.
+        /// </summary>
+        /// <value>
+        /// The fields within this oneof, in declaration order.
+        /// </value>
+        public IList<FieldDescriptor> Fields { get { return fields; } }
+
+        /// <summary>
+        /// Gets an accessor for reflective access to the values associated with the oneof
+        /// in a particular message.
+        /// </summary>
+        /// <value>
+        /// The accessor used for reflective access.
+        /// </value>
+        public OneofAccessor Accessor { get { return accessor; } }
+
+        internal void CrossLink()
+        {
+            List<FieldDescriptor> fieldCollection = new List<FieldDescriptor>();
+            foreach (var field in ContainingType.Fields.InDeclarationOrder())
+            {
+                if (field.ContainingOneof == this)
+                {
+                    fieldCollection.Add(field);
+                }
+            }
+            fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
+        }
+
+        private OneofAccessor CreateAccessor(string clrName)
+        {
+            var caseProperty = containingType.ClrType.GetProperty(clrName + "Case");
+            if (caseProperty == null)
+            {
+                throw new DescriptorValidationException(this, $"Property {clrName}Case not found in {containingType.ClrType}");
+            }
+            var clearMethod = containingType.ClrType.GetMethod("Clear" + clrName);
+            if (clearMethod == null)
+            {
+                throw new DescriptorValidationException(this, $"Method Clear{clrName} not found in {containingType.ClrType}");
+            }
+
+            return new OneofAccessor(caseProperty, clearMethod, this);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs
new file mode 100644
index 0000000..27f9ab9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs
@@ -0,0 +1,58 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Specifies the original name (in the .proto file) of a named element,
+    /// such as an enum value.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field)]
+    public class OriginalNameAttribute : Attribute
+    {
+        /// <summary>
+        /// The name of the element in the .proto file.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Constructs a new attribute instance for the given name.
+        /// </summary>
+        /// <param name="name">The name of the element in the .proto file.</param>
+        public OriginalNameAttribute(string name)
+        {
+            Name = ProtoPreconditions.CheckNotNull(name, nameof(name));
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs
new file mode 100644
index 0000000..e547d83
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs
@@ -0,0 +1,68 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Represents a package in the symbol table.  We use PackageDescriptors
+    /// just as placeholders so that someone cannot define, say, a message type
+    /// that has the same name as an existing package.
+    /// </summary>
+    internal sealed class PackageDescriptor : IDescriptor
+    {
+        private readonly string name;
+        private readonly string fullName;
+        private readonly FileDescriptor file;
+
+        internal PackageDescriptor(string name, string fullName, FileDescriptor file)
+        {
+            this.file = file;
+            this.fullName = fullName;
+            this.name = name;
+        }
+
+        public string Name
+        {
+            get { return name; }
+        }
+
+        public string FullName
+        {
+            get { return fullName; }
+        }
+
+        public FileDescriptor File
+        {
+            get { return file; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
new file mode 100644
index 0000000..8c055d6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+// This file just contains partial classes for any autogenerated classes that need additional support.

+namespace Google.Protobuf.Reflection

+{

+    internal partial class FieldDescriptorProto

+    {

+        // We can't tell the difference between "explicitly set to 0" and "not set"

+        // in proto3, but we need to tell the difference for OneofIndex. descriptor.proto

+        // is really a proto2 file, but the runtime doesn't know about proto2 semantics...

+        // We fake it by defaulting to -1.

+        partial void OnConstruction()

+        {

+            OneofIndex = -1;

+        }

+    }

+

+    internal partial class FieldOptions

+    {

+        // We can't tell the difference between "explicitly set to false" and "not set"

+        // in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.

+        // This won't work if we ever need to support proto2, but at that point we'll be

+        // able to remove this hack and use field presence instead. 

+        partial void OnConstruction()

+        {

+            Packed = true;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
new file mode 100644
index 0000000..df820ca
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// The methods in this class are somewhat evil, and should not be tampered with lightly.
+    /// Basically they allow the creation of relatively weakly typed delegates from MethodInfos
+    /// which are more strongly typed. They do this by creating an appropriate strongly typed
+    /// delegate from the MethodInfo, and then calling that within an anonymous method.
+    /// Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
+    /// very fast compared with calling Invoke later on.
+    /// </summary>
+    internal static class ReflectionUtil
+    {
+        /// <summary>
+        /// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
+        /// </summary>
+        internal static readonly Type[] EmptyTypes = new Type[0];
+
+        /// <summary>
+        /// Creates a delegate which will cast the argument to the appropriate method target type,
+        /// call the method on it, then convert the result to object.
+        /// </summary>
+        internal static Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method)
+        {
+            ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
+            Expression downcast = Expression.Convert(parameter, method.DeclaringType);
+            Expression call = Expression.Call(downcast, method);
+            Expression upcast = Expression.Convert(call, typeof(object));
+            return Expression.Lambda<Func<IMessage, object>>(upcast, parameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will cast the argument to the appropriate method target type,
+        /// call the method on it, then convert the result to the specified type.
+        /// </summary>
+        internal static Func<IMessage, T> CreateFuncIMessageT<T>(MethodInfo method)
+        {
+            ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
+            Expression downcast = Expression.Convert(parameter, method.DeclaringType);
+            Expression call = Expression.Call(downcast, method);
+            Expression upcast = Expression.Convert(call, typeof(T));
+            return Expression.Lambda<Func<IMessage, T>>(upcast, parameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will execute the given method after casting the first argument to
+        /// the target type of the method, and the second argument to the first parameter type of the method.
+        /// </summary>
+        internal static Action<IMessage, object> CreateActionIMessageObject(MethodInfo method)
+        {
+            ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
+            ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
+            Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
+            Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
+            Expression call = Expression.Call(castTarget, method, castArgument);
+            return Expression.Lambda<Action<IMessage, object>>(call, targetParameter, argParameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will execute the given method after casting the first argument to
+        /// the target type of the method.
+        /// </summary>
+        internal static Action<IMessage> CreateActionIMessage(MethodInfo method)
+        {
+            ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
+            Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
+            Expression call = Expression.Call(castTarget, method);
+            return Expression.Lambda<Action<IMessage>>(call, targetParameter).Compile();
+        }        
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
new file mode 100644
index 0000000..bd40847
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
@@ -0,0 +1,60 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for repeated fields.
+    /// </summary>
+    internal sealed class RepeatedFieldAccessor : FieldAccessorBase
+    {
+        internal RepeatedFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+        }
+
+        public override void Clear(IMessage message)
+        {
+            IList list = (IList) GetValue(message);
+            list.Clear();
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            throw new InvalidOperationException("SetValue is not implemented for repeated fields");
+        }
+
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
new file mode 100644
index 0000000..cc0a501
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
@@ -0,0 +1,89 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a service type.
+    /// </summary>
+    public sealed class ServiceDescriptor : DescriptorBase
+    {
+        private readonly ServiceDescriptorProto proto;
+        private readonly IList<MethodDescriptor> methods;
+
+        internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
+            : base(file, file.ComputeFullName(null, proto.Name), index)
+        {
+            this.proto = proto;
+            methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
+                                                            (method, i) => new MethodDescriptor(method, file, this, i));
+
+            file.DescriptorPool.AddSymbol(this);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal ServiceDescriptorProto Proto { get { return proto; } }
+
+        /// <value>
+        /// An unmodifiable list of methods in this service.
+        /// </value>
+        public IList<MethodDescriptor> Methods
+        {
+            get { return methods; }
+        }
+
+        /// <summary>
+        /// Finds a method by name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the method (e.g. "Foo").</param>
+        /// <returns>The method's decsriptor, or null if not found.</returns>
+        public MethodDescriptor FindMethodByName(String name)
+        {
+            return File.DescriptorPool.FindSymbol<MethodDescriptor>(FullName + "." + name);
+        }
+
+        internal void CrossLink()
+        {
+            foreach (MethodDescriptor method in methods)
+            {
+                method.CrossLink();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
new file mode 100644
index 0000000..bbac217
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
@@ -0,0 +1,81 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for single fields.
+    /// </summary>
+    internal sealed class SingleFieldAccessor : FieldAccessorBase
+    {
+        // All the work here is actually done in the constructor - it creates the appropriate delegates.
+        // There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
+        // and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
+        // values.
+
+        private readonly Action<IMessage, object> setValueDelegate;
+        private readonly Action<IMessage> clearDelegate;
+
+        internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+            if (!property.CanWrite)
+            {
+                throw new ArgumentException("Not all required properties/methods available");
+            }
+            setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
+
+            var clrType = property.PropertyType;
+            
+            // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
+            object defaultValue =
+                descriptor.FieldType == FieldType.Message ? null
+                : clrType == typeof(string) ? ""
+                : clrType == typeof(ByteString) ? ByteString.Empty
+                : Activator.CreateInstance(clrType);
+            clearDelegate = message => SetValue(message, defaultValue);
+        }
+
+        public override void Clear(IMessage message)
+        {
+            clearDelegate(message);
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            setValueDelegate(message, value);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
new file mode 100644
index 0000000..e94e3e6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
@@ -0,0 +1,183 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// An immutable registry of types which can be looked up by their full name.
+    /// </summary>
+    public sealed class TypeRegistry
+    {
+        /// <summary>
+        /// An empty type registry, containing no types.
+        /// </summary>
+        public static TypeRegistry Empty { get; } = new TypeRegistry(new Dictionary<string, MessageDescriptor>());
+
+        private readonly Dictionary<string, MessageDescriptor> fullNameToMessageMap;
+
+        private TypeRegistry(Dictionary<string, MessageDescriptor> fullNameToMessageMap)
+        {
+            this.fullNameToMessageMap = fullNameToMessageMap;
+        }
+
+        /// <summary>
+        /// Attempts to find a message descriptor by its full name.
+        /// </summary>
+        /// <param name="fullName">The full name of the message, which is the dot-separated
+        /// combination of package, containing messages and message name</param>
+        /// <returns>The message descriptor corresponding to <paramref name="fullName"/> or null
+        /// if there is no such message descriptor.</returns>
+        public MessageDescriptor Find(string fullName)
+        {
+            MessageDescriptor ret;
+            // Ignore the return value as ret will end up with the right value either way.
+            fullNameToMessageMap.TryGetValue(fullName, out ret);
+            return ret;
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromFiles(IEnumerable{FileDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(params FileDescriptor[] fileDescriptors)
+        {
+            return FromFiles((IEnumerable<FileDescriptor>) fileDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// All message types within all the specified files are added to the registry, and
+        /// the dependencies of the specified files are also added, recursively.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(fileDescriptors, nameof(fileDescriptors));
+            var builder = new Builder();
+            foreach (var file in fileDescriptors)
+            {
+                builder.AddFile(file);
+            }
+            return builder.Build();
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromMessages(IEnumerable{MessageDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(params MessageDescriptor[] messageDescriptors)
+        {
+            return FromMessages((IEnumerable<MessageDescriptor>) messageDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// The specified message descriptors are only used to identify their file descriptors; the returned registry
+        /// contains all the types within the file descriptors which contain the specified message descriptors (and
+        /// the dependencies of those files), not just the specified messages.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(IEnumerable<MessageDescriptor> messageDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(messageDescriptors, nameof(messageDescriptors));
+            return FromFiles(messageDescriptors.Select(md => md.File));
+        }
+
+        /// <summary>
+        /// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
+        /// </summary>
+        private class Builder
+        {
+            private readonly Dictionary<string, MessageDescriptor> types;
+            private readonly HashSet<string> fileDescriptorNames;
+
+            internal Builder()
+            {
+                types = new Dictionary<string, MessageDescriptor>();
+                fileDescriptorNames = new HashSet<string>();
+            }
+
+            internal void AddFile(FileDescriptor fileDescriptor)
+            {
+                if (!fileDescriptorNames.Add(fileDescriptor.Name))
+                {
+                    return;
+                }
+                foreach (var dependency in fileDescriptor.Dependencies)
+                {
+                    AddFile(dependency);
+                }
+                foreach (var message in fileDescriptor.MessageTypes)
+                {
+                    AddMessage(message);
+                }
+            }
+
+            private void AddMessage(MessageDescriptor messageDescriptor)
+            {
+                foreach (var nestedType in messageDescriptor.NestedTypes)
+                {
+                    AddMessage(nestedType);
+                }
+                // This will overwrite any previous entry. Given that each file should
+                // only be added once, this could be a problem such as package A.B with type C,
+                // and package A with type B.C... it's unclear what we should do in that case.
+                types[messageDescriptor.FullName] = messageDescriptor;
+            }
+
+            internal TypeRegistry Build()
+            {
+                return new TypeRegistry(types);
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
new file mode 100644
index 0000000..871a383
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
@@ -0,0 +1,261 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/any.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class AnyReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/any.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static AnyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi",
+            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQnIKE2Nv",
+            "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29s",
+            "YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmgAQGiAgNHUEKqAh5Hb29nbGUuUHJv",
+            "dG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), global::Google.Protobuf.WellKnownTypes.Any.Parser, new[]{ "TypeUrl", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `Any` contains an arbitrary serialized protocol buffer message along with a
+  ///  URL that describes the type of the serialized message.
+  ///
+  ///  Protobuf library provides support to pack/unpack Any values in the form
+  ///  of utility functions or additional generated methods of the Any type.
+  ///
+  ///  Example 1: Pack and unpack a message in C++.
+  ///
+  ///      Foo foo = ...;
+  ///      Any any;
+  ///      any.PackFrom(foo);
+  ///      ...
+  ///      if (any.UnpackTo(&amp;foo)) {
+  ///        ...
+  ///      }
+  ///
+  ///  Example 2: Pack and unpack a message in Java.
+  ///
+  ///      Foo foo = ...;
+  ///      Any any = Any.pack(foo);
+  ///      ...
+  ///      if (any.is(Foo.class)) {
+  ///        foo = any.unpack(Foo.class);
+  ///      }
+  ///
+  ///  The pack methods provided by protobuf library will by default use
+  ///  'type.googleapis.com/full.type.name' as the type URL and the unpack
+  ///  methods only use the fully qualified type name after the last '/'
+  ///  in the type URL, for example "foo.bar.com/x/y.z" will yield type
+  ///  name "y.z".
+  ///
+  ///  JSON
+  ///  ====
+  ///  The JSON representation of an `Any` value uses the regular
+  ///  representation of the deserialized, embedded message, with an
+  ///  additional field `@type` which contains the type URL. Example:
+  ///
+  ///      package google.profile;
+  ///      message Person {
+  ///        string first_name = 1;
+  ///        string last_name = 2;
+  ///      }
+  ///
+  ///      {
+  ///        "@type": "type.googleapis.com/google.profile.Person",
+  ///        "firstName": &lt;string>,
+  ///        "lastName": &lt;string>
+  ///      }
+  ///
+  ///  If the embedded message type is well-known and has a custom JSON
+  ///  representation, that representation will be embedded adding a field
+  ///  `value` which holds the custom JSON in addition to the `@type`
+  ///  field. Example (for message [google.protobuf.Duration][]):
+  ///
+  ///      {
+  ///        "@type": "type.googleapis.com/google.protobuf.Duration",
+  ///        "value": "1.212s"
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Any : pb::IMessage<Any> {
+    private static readonly pb::MessageParser<Any> _parser = new pb::MessageParser<Any>(() => new Any());
+    public static pb::MessageParser<Any> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Any() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Any(Any other) : this() {
+      typeUrl_ = other.typeUrl_;
+      value_ = other.value_;
+    }
+
+    public Any Clone() {
+      return new Any(this);
+    }
+
+    /// <summary>Field number for the "type_url" field.</summary>
+    public const int TypeUrlFieldNumber = 1;
+    private string typeUrl_ = "";
+    /// <summary>
+    ///  A URL/resource name whose content describes the type of the
+    ///  serialized protocol buffer message.
+    ///
+    ///  For URLs which use the schema `http`, `https`, or no schema, the
+    ///  following restrictions and interpretations apply:
+    ///
+    ///  * If no schema is provided, `https` is assumed.
+    ///  * The last segment of the URL's path must represent the fully
+    ///    qualified name of the type (as in `path/google.protobuf.Duration`).
+    ///    The name should be in a canonical form (e.g., leading "." is
+    ///    not accepted).
+    ///  * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+    ///    value in binary format, or produce an error.
+    ///  * Applications are allowed to cache lookup results based on the
+    ///    URL, or have them precompiled into a binary to avoid any
+    ///    lookup. Therefore, binary compatibility needs to be preserved
+    ///    on changes to types. (Use versioned type names to manage
+    ///    breaking changes.)
+    ///
+    ///  Schemas other than `http`, `https` (or the empty schema) might be
+    ///  used with implementation specific semantics.
+    /// </summary>
+    public string TypeUrl {
+      get { return typeUrl_; }
+      set {
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  Must be a valid serialized protocol buffer of the above specified type.
+    /// </summary>
+    public pb::ByteString Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Any);
+    }
+
+    public bool Equals(Any other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (TypeUrl != other.TypeUrl) return false;
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (TypeUrl.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(TypeUrl);
+      }
+      if (Value.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteBytes(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (TypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeUrl);
+      }
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Any other) {
+      if (other == null) {
+        return;
+      }
+      if (other.TypeUrl.Length != 0) {
+        TypeUrl = other.TypeUrl;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            TypeUrl = input.ReadString();
+            break;
+          }
+          case 18: {
+            Value = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
new file mode 100644
index 0000000..f4fac73
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Any
+    {
+        private const string DefaultPrefix = "type.googleapis.com";
+
+        // This could be moved to MessageDescriptor if we wanted to, but keeping it here means
+        // all the Any-specific code is in the same place.
+        private static string GetTypeUrl(MessageDescriptor descriptor, string prefix) =>
+            prefix.EndsWith("/") ? prefix + descriptor.FullName : prefix + "/" + descriptor.FullName;
+
+        /// <summary>
+        /// Retrieves the type name for a type URL. This is always just the last part of the URL,
+        /// after the trailing slash. No validation of anything before the trailing slash is performed.
+        /// If the type URL does not include a slash, an empty string is returned rather than an exception
+        /// being thrown; this won't match any types, and the calling code is probably in a better position
+        /// to give a meaningful error.
+        /// There is no handling of fragments or queries  at the moment.
+        /// </summary>
+        /// <param name="typeUrl">The URL to extract the type name from</param>
+        /// <returns>The type name</returns>
+        internal static string GetTypeName(string typeUrl)
+        {
+            int lastSlash = typeUrl.LastIndexOf('/');
+            return lastSlash == -1 ? "" : typeUrl.Substring(lastSlash + 1);
+        }
+
+        /// <summary>
+        /// Unpacks the content of this Any message into the target message type,
+        /// which must match the type URL within this Any message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to unpack the content into.</typeparam>
+        /// <returns>The unpacked message.</returns>
+        /// <exception cref="InvalidProtocolBufferException">The target message type doesn't match the type URL in this message</exception>
+        public T Unpack<T>() where T : IMessage, new()
+        {
+            // Note: this doesn't perform as well is it might. We could take a MessageParser<T> in an alternative overload,
+            // which would be expected to perform slightly better... although the difference is likely to be negligible.
+            T target = new T();
+            if (GetTypeName(TypeUrl) != target.Descriptor.FullName)
+            {
+                throw new InvalidProtocolBufferException(
+                    $"Full type name for {target.Descriptor.Name} is {target.Descriptor.FullName}; Any message's type url is {TypeUrl}");
+            }
+            target.MergeFrom(Value);
+            return target;
+        }
+
+        /// <summary>
+        /// Packs the specified message into an Any message using a type URL prefix of "type.googleapis.com".
+        /// </summary>
+        /// <param name="message">The message to pack.</param>
+        /// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
+        public static Any Pack(IMessage message) => Pack(message, DefaultPrefix);
+
+        /// <summary>
+        /// Packs the specified message into an Any message using the specified type URL prefix.
+        /// </summary>
+        /// <param name="message">The message to pack.</param>
+        /// <param name="typeUrlPrefix">The prefix for the type URL.</param>
+        /// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
+        public static Any Pack(IMessage message, string typeUrlPrefix)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            ProtoPreconditions.CheckNotNull(typeUrlPrefix, nameof(typeUrlPrefix));
+            return new Any
+            {
+                TypeUrl = GetTypeUrl(message.Descriptor, typeUrlPrefix),
+                Value = message.ToByteString()
+            };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
new file mode 100644
index 0000000..e568a2c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
@@ -0,0 +1,847 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/api.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class ApiReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/api.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static ApiReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYXBpLnByb3RvEg9nb29nbGUucHJvdG9idWYa",
+            "JGdvb2dsZS9wcm90b2J1Zi9zb3VyY2VfY29udGV4dC5wcm90bxoaZ29vZ2xl",
+            "L3Byb3RvYnVmL3R5cGUucHJvdG8igQIKA0FwaRIMCgRuYW1lGAEgASgJEigK",
+            "B21ldGhvZHMYAiADKAsyFy5nb29nbGUucHJvdG9idWYuTWV0aG9kEigKB29w",
+            "dGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEg8KB3ZlcnNp",
+            "b24YBCABKAkSNgoOc291cmNlX2NvbnRleHQYBSABKAsyHi5nb29nbGUucHJv",
+            "dG9idWYuU291cmNlQ29udGV4dBImCgZtaXhpbnMYBiADKAsyFi5nb29nbGUu",
+            "cHJvdG9idWYuTWl4aW4SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3Rv",
+            "YnVmLlN5bnRheCLVAQoGTWV0aG9kEgwKBG5hbWUYASABKAkSGAoQcmVxdWVz",
+            "dF90eXBlX3VybBgCIAEoCRIZChFyZXF1ZXN0X3N0cmVhbWluZxgDIAEoCBIZ",
+            "ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
+            "bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
+            "cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
+            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSwoTY29t",
+            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaABAaICA0dQQqoCHkdvb2ds",
+            "ZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), global::Google.Protobuf.WellKnownTypes.Api.Parser, new[]{ "Name", "Methods", "Options", "Version", "SourceContext", "Mixins", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Method), global::Google.Protobuf.WellKnownTypes.Method.Parser, new[]{ "Name", "RequestTypeUrl", "RequestStreaming", "ResponseTypeUrl", "ResponseStreaming", "Options", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Mixin), global::Google.Protobuf.WellKnownTypes.Mixin.Parser, new[]{ "Name", "Root" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  Api is a light-weight descriptor for a protocol buffer service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Api : pb::IMessage<Api> {
+    private static readonly pb::MessageParser<Api> _parser = new pb::MessageParser<Api>(() => new Api());
+    public static pb::MessageParser<Api> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Api() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Api(Api other) : this() {
+      name_ = other.name_;
+      methods_ = other.methods_.Clone();
+      options_ = other.options_.Clone();
+      version_ = other.version_;
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      mixins_ = other.mixins_.Clone();
+      syntax_ = other.syntax_;
+    }
+
+    public Api Clone() {
+      return new Api(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of this api, including package name
+    ///  followed by the api's simple name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "methods" field.</summary>
+    public const int MethodsFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Method> _repeated_methods_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Method.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> methods_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method>();
+    /// <summary>
+    ///  The methods of this api, in unspecified order.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> Methods {
+      get { return methods_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the API.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "version" field.</summary>
+    public const int VersionFieldNumber = 4;
+    private string version_ = "";
+    /// <summary>
+    ///  A version string for this api. If specified, must have the form
+    ///  `major-version.minor-version`, as in `1.10`. If the minor version
+    ///  is omitted, it defaults to zero. If the entire version field is
+    ///  empty, the major version is derived from the package name, as
+    ///  outlined below. If the field is not empty, the version in the
+    ///  package name will be verified to be consistent with what is
+    ///  provided here.
+    ///
+    ///  The versioning schema uses [semantic
+    ///  versioning](http://semver.org) where the major version number
+    ///  indicates a breaking change and the minor version an additive,
+    ///  non-breaking change. Both version numbers are signals to users
+    ///  what to expect from different versions, and should be carefully
+    ///  chosen based on the product plan.
+    ///
+    ///  The major version is also reflected in the package name of the
+    ///  API, which must end in `v&lt;major-version>`, as in
+    ///  `google.feature.v1`. For major versions 0 and 1, the suffix can
+    ///  be omitted. Zero major versions must only be used for
+    ///  experimental, none-GA apis.
+    /// </summary>
+    public string Version {
+      get { return version_; }
+      set {
+        version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  Source context for the protocol buffer service represented by this
+    ///  message.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "mixins" field.</summary>
+    public const int MixinsFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Mixin> _repeated_mixins_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Mixin.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> mixins_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin>();
+    /// <summary>
+    ///  Included APIs. See [Mixin][].
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> Mixins {
+      get { return mixins_; }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
+    /// <summary>
+    ///  The source syntax of the service.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Api);
+    }
+
+    public bool Equals(Api other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!methods_.Equals(other.methods_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (Version != other.Version) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if(!mixins_.Equals(other.mixins_)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= methods_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (Version.Length != 0) hash ^= Version.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      hash ^= mixins_.GetHashCode();
+      if (Syntax != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      methods_.WriteTo(output, _repeated_methods_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (Version.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(Version);
+      }
+      if (sourceContext_ != null) {
+        output.WriteRawTag(42);
+        output.WriteMessage(SourceContext);
+      }
+      mixins_.WriteTo(output, _repeated_mixins_codec);
+      if (Syntax != 0) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += methods_.CalculateSize(_repeated_methods_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (Version.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Version);
+      }
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      size += mixins_.CalculateSize(_repeated_mixins_codec);
+      if (Syntax != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Api other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      methods_.Add(other.methods_);
+      options_.Add(other.options_);
+      if (other.Version.Length != 0) {
+        Version = other.Version;
+      }
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      mixins_.Add(other.mixins_);
+      if (other.Syntax != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            methods_.AddEntriesFrom(input, _repeated_methods_codec);
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 34: {
+            Version = input.ReadString();
+            break;
+          }
+          case 42: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 50: {
+            mixins_.AddEntriesFrom(input, _repeated_mixins_codec);
+            break;
+          }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Method represents a method of an api.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Method : pb::IMessage<Method> {
+    private static readonly pb::MessageParser<Method> _parser = new pb::MessageParser<Method>(() => new Method());
+    public static pb::MessageParser<Method> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Method() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Method(Method other) : this() {
+      name_ = other.name_;
+      requestTypeUrl_ = other.requestTypeUrl_;
+      requestStreaming_ = other.requestStreaming_;
+      responseTypeUrl_ = other.responseTypeUrl_;
+      responseStreaming_ = other.responseStreaming_;
+      options_ = other.options_.Clone();
+      syntax_ = other.syntax_;
+    }
+
+    public Method Clone() {
+      return new Method(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The simple name of this method.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "request_type_url" field.</summary>
+    public const int RequestTypeUrlFieldNumber = 2;
+    private string requestTypeUrl_ = "";
+    /// <summary>
+    ///  A URL of the input message type.
+    /// </summary>
+    public string RequestTypeUrl {
+      get { return requestTypeUrl_; }
+      set {
+        requestTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "request_streaming" field.</summary>
+    public const int RequestStreamingFieldNumber = 3;
+    private bool requestStreaming_;
+    /// <summary>
+    ///  If true, the request is streamed.
+    /// </summary>
+    public bool RequestStreaming {
+      get { return requestStreaming_; }
+      set {
+        requestStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "response_type_url" field.</summary>
+    public const int ResponseTypeUrlFieldNumber = 4;
+    private string responseTypeUrl_ = "";
+    /// <summary>
+    ///  The URL of the output message type.
+    /// </summary>
+    public string ResponseTypeUrl {
+      get { return responseTypeUrl_; }
+      set {
+        responseTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "response_streaming" field.</summary>
+    public const int ResponseStreamingFieldNumber = 5;
+    private bool responseStreaming_;
+    /// <summary>
+    ///  If true, the response is streamed.
+    /// </summary>
+    public bool ResponseStreaming {
+      get { return responseStreaming_; }
+      set {
+        responseStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the method.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
+    /// <summary>
+    ///  The source syntax of this method.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Method);
+    }
+
+    public bool Equals(Method other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (RequestTypeUrl != other.RequestTypeUrl) return false;
+      if (RequestStreaming != other.RequestStreaming) return false;
+      if (ResponseTypeUrl != other.ResponseTypeUrl) return false;
+      if (ResponseStreaming != other.ResponseStreaming) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (RequestTypeUrl.Length != 0) hash ^= RequestTypeUrl.GetHashCode();
+      if (RequestStreaming != false) hash ^= RequestStreaming.GetHashCode();
+      if (ResponseTypeUrl.Length != 0) hash ^= ResponseTypeUrl.GetHashCode();
+      if (ResponseStreaming != false) hash ^= ResponseStreaming.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (Syntax != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (RequestTypeUrl.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(RequestTypeUrl);
+      }
+      if (RequestStreaming != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(RequestStreaming);
+      }
+      if (ResponseTypeUrl.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(ResponseTypeUrl);
+      }
+      if (ResponseStreaming != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(ResponseStreaming);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+      if (Syntax != 0) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (RequestTypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(RequestTypeUrl);
+      }
+      if (RequestStreaming != false) {
+        size += 1 + 1;
+      }
+      if (ResponseTypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(ResponseTypeUrl);
+      }
+      if (ResponseStreaming != false) {
+        size += 1 + 1;
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (Syntax != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Method other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.RequestTypeUrl.Length != 0) {
+        RequestTypeUrl = other.RequestTypeUrl;
+      }
+      if (other.RequestStreaming != false) {
+        RequestStreaming = other.RequestStreaming;
+      }
+      if (other.ResponseTypeUrl.Length != 0) {
+        ResponseTypeUrl = other.ResponseTypeUrl;
+      }
+      if (other.ResponseStreaming != false) {
+        ResponseStreaming = other.ResponseStreaming;
+      }
+      options_.Add(other.options_);
+      if (other.Syntax != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            RequestTypeUrl = input.ReadString();
+            break;
+          }
+          case 24: {
+            RequestStreaming = input.ReadBool();
+            break;
+          }
+          case 34: {
+            ResponseTypeUrl = input.ReadString();
+            break;
+          }
+          case 40: {
+            ResponseStreaming = input.ReadBool();
+            break;
+          }
+          case 50: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Declares an API to be included in this API. The including API must
+  ///  redeclare all the methods from the included API, but documentation
+  ///  and options are inherited as follows:
+  ///
+  ///  - If after comment and whitespace stripping, the documentation
+  ///    string of the redeclared method is empty, it will be inherited
+  ///    from the original method.
+  ///
+  ///  - Each annotation belonging to the service config (http,
+  ///    visibility) which is not set in the redeclared method will be
+  ///    inherited.
+  ///
+  ///  - If an http annotation is inherited, the path pattern will be
+  ///    modified as follows. Any version prefix will be replaced by the
+  ///    version of the including API plus the [root][] path if specified.
+  ///
+  ///  Example of a simple mixin:
+  ///
+  ///      package google.acl.v1;
+  ///      service AccessControl {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v1/{resource=**}:getAcl";
+  ///        }
+  ///      }
+  ///
+  ///      package google.storage.v2;
+  ///      service Storage {
+  ///        rpc GetAcl(GetAclRequest) returns (Acl);
+  ///
+  ///        // Get a data record.
+  ///        rpc GetData(GetDataRequest) returns (Data) {
+  ///          option (google.api.http).get = "/v2/{resource=**}";
+  ///        }
+  ///      }
+  ///
+  ///  Example of a mixin configuration:
+  ///
+  ///      apis:
+  ///      - name: google.storage.v2.Storage
+  ///        mixins:
+  ///        - name: google.acl.v1.AccessControl
+  ///
+  ///  The mixin construct implies that all methods in `AccessControl` are
+  ///  also declared with same name and request/response types in
+  ///  `Storage`. A documentation generator or annotation processor will
+  ///  see the effective `Storage.GetAcl` method after inherting
+  ///  documentation and annotations as follows:
+  ///
+  ///      service Storage {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v2/{resource=**}:getAcl";
+  ///        }
+  ///        ...
+  ///      }
+  ///
+  ///  Note how the version in the path pattern changed from `v1` to `v2`.
+  ///
+  ///  If the `root` field in the mixin is specified, it should be a
+  ///  relative path under which inherited HTTP paths are placed. Example:
+  ///
+  ///      apis:
+  ///      - name: google.storage.v2.Storage
+  ///        mixins:
+  ///        - name: google.acl.v1.AccessControl
+  ///          root: acls
+  ///
+  ///  This implies the following inherited HTTP annotation:
+  ///
+  ///      service Storage {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
+  ///        }
+  ///        ...
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Mixin : pb::IMessage<Mixin> {
+    private static readonly pb::MessageParser<Mixin> _parser = new pb::MessageParser<Mixin>(() => new Mixin());
+    public static pb::MessageParser<Mixin> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Mixin() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Mixin(Mixin other) : this() {
+      name_ = other.name_;
+      root_ = other.root_;
+    }
+
+    public Mixin Clone() {
+      return new Mixin(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of the API which is included.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "root" field.</summary>
+    public const int RootFieldNumber = 2;
+    private string root_ = "";
+    /// <summary>
+    ///  If non-empty specifies a path under which inherited HTTP paths
+    ///  are rooted.
+    /// </summary>
+    public string Root {
+      get { return root_; }
+      set {
+        root_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Mixin);
+    }
+
+    public bool Equals(Mixin other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Root != other.Root) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Root.Length != 0) hash ^= Root.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Root.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Root);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Root.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Root);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Mixin other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Root.Length != 0) {
+        Root = other.Root;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Root = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
new file mode 100644
index 0000000..f17358f
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
@@ -0,0 +1,230 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/duration.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class DurationReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/duration.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static DurationReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg",
+            "ASgFQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoq",
+            "Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9uoAEB",
+            "ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90",
+            "bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), global::Google.Protobuf.WellKnownTypes.Duration.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A Duration represents a signed, fixed-length span of time represented
+  ///  as a count of seconds and fractions of seconds at nanosecond
+  ///  resolution. It is independent of any calendar and concepts like "day"
+  ///  or "month". It is related to Timestamp in that the difference between
+  ///  two Timestamp values is a Duration and it can be added or subtracted
+  ///  from a Timestamp. Range is approximately +-10,000 years.
+  ///
+  ///  Example 1: Compute Duration from two Timestamps in pseudo code.
+  ///
+  ///      Timestamp start = ...;
+  ///      Timestamp end = ...;
+  ///      Duration duration = ...;
+  ///
+  ///      duration.seconds = end.seconds - start.seconds;
+  ///      duration.nanos = end.nanos - start.nanos;
+  ///
+  ///      if (duration.seconds &lt; 0 &amp;&amp; duration.nanos > 0) {
+  ///        duration.seconds += 1;
+  ///        duration.nanos -= 1000000000;
+  ///      } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 0) {
+  ///        duration.seconds -= 1;
+  ///        duration.nanos += 1000000000;
+  ///      }
+  ///
+  ///  Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
+  ///
+  ///      Timestamp start = ...;
+  ///      Duration duration = ...;
+  ///      Timestamp end = ...;
+  ///
+  ///      end.seconds = start.seconds + duration.seconds;
+  ///      end.nanos = start.nanos + duration.nanos;
+  ///
+  ///      if (end.nanos &lt; 0) {
+  ///        end.seconds -= 1;
+  ///        end.nanos += 1000000000;
+  ///      } else if (end.nanos >= 1000000000) {
+  ///        end.seconds += 1;
+  ///        end.nanos -= 1000000000;
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Duration : pb::IMessage<Duration> {
+    private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
+    public static pb::MessageParser<Duration> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Duration() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Duration(Duration other) : this() {
+      seconds_ = other.seconds_;
+      nanos_ = other.nanos_;
+    }
+
+    public Duration Clone() {
+      return new Duration(this);
+    }
+
+    /// <summary>Field number for the "seconds" field.</summary>
+    public const int SecondsFieldNumber = 1;
+    private long seconds_;
+    /// <summary>
+    ///  Signed seconds of the span of time. Must be from -315,576,000,000
+    ///  to +315,576,000,000 inclusive.
+    /// </summary>
+    public long Seconds {
+      get { return seconds_; }
+      set {
+        seconds_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "nanos" field.</summary>
+    public const int NanosFieldNumber = 2;
+    private int nanos_;
+    /// <summary>
+    ///  Signed fractions of a second at nanosecond resolution of the span
+    ///  of time. Durations less than one second are represented with a 0
+    ///  `seconds` field and a positive or negative `nanos` field. For durations
+    ///  of one second or more, a non-zero value for the `nanos` field must be
+    ///  of the same sign as the `seconds` field. Must be from -999,999,999
+    ///  to +999,999,999 inclusive.
+    /// </summary>
+    public int Nanos {
+      get { return nanos_; }
+      set {
+        nanos_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Duration);
+    }
+
+    public bool Equals(Duration other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Seconds != other.Seconds) return false;
+      if (Nanos != other.Nanos) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Seconds != 0L) hash ^= Seconds.GetHashCode();
+      if (Nanos != 0) hash ^= Nanos.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Seconds != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Seconds);
+      }
+      if (Nanos != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Nanos);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Seconds != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
+      }
+      if (Nanos != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Duration other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Seconds != 0L) {
+        Seconds = other.Seconds;
+      }
+      if (other.Nanos != 0) {
+        Nanos = other.Nanos;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Seconds = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Nanos = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
new file mode 100644
index 0000000..f164bfd
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
@@ -0,0 +1,270 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    // Manually-written partial class for the Duration well-known type,
+    // providing a conversion to TimeSpan and convenience operators.
+    public partial class Duration : ICustomDiagnosticMessage
+    {
+        /// <summary>
+        /// The number of nanoseconds in a second.
+        /// </summary>
+        public const int NanosecondsPerSecond = 1000000000;
+        /// <summary>
+        /// The number of nanoseconds in a BCL tick (as used by <see cref="TimeSpan"/> and <see cref="DateTime"/>).
+        /// </summary>
+        public const int NanosecondsPerTick = 100;
+
+        /// <summary>
+        /// The maximum permitted number of seconds.
+        /// </summary>
+        public const long MaxSeconds = 315576000000L;
+
+        /// <summary>
+        /// The minimum permitted number of seconds.
+        /// </summary>
+        public const long MinSeconds = -315576000000L;
+
+        internal const int MaxNanoseconds = NanosecondsPerSecond - 1;
+        internal const int MinNanoseconds = -NanosecondsPerSecond + 1;
+
+        internal static bool IsNormalized(long seconds, int nanoseconds)
+        {
+            // Simple boundaries
+            if (seconds < MinSeconds || seconds > MaxSeconds ||
+                nanoseconds < MinNanoseconds || nanoseconds > MaxNanoseconds)
+            {
+                return false;
+            }
+            // We only have a problem is one is strictly negative and the other is
+            // strictly positive.
+            return Math.Sign(seconds) * Math.Sign(nanoseconds) != -1;
+        }
+
+        /// <summary>
+        /// Converts this <see cref="Duration"/> to a <see cref="TimeSpan"/>.
+        /// </summary>
+        /// <remarks>If the duration is not a precise number of ticks, it is truncated towards 0.</remarks>
+        /// <returns>The value of this duration, as a <c>TimeSpan</c>.</returns>
+        /// <exception cref="InvalidOperationException">This value isn't a valid normalized duration, as
+        /// described in the documentation.</exception>
+        public TimeSpan ToTimeSpan()
+        {
+            checked
+            {
+                if (!IsNormalized(Seconds, Nanos))
+                {
+                    throw new InvalidOperationException("Duration was not a valid normalized duration");
+                }
+                long ticks = Seconds * TimeSpan.TicksPerSecond + Nanos / NanosecondsPerTick;
+                return TimeSpan.FromTicks(ticks);
+            }
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="timeSpan">The <c>TimeSpan</c> to convert.</param>
+        /// <returns>The value of the given <c>TimeSpan</c>, as a <c>Duration</c>.</returns>
+        public static Duration FromTimeSpan(TimeSpan timeSpan)
+        {
+            checked
+            {
+                long ticks = timeSpan.Ticks;
+                long seconds = ticks / TimeSpan.TicksPerSecond;
+                int nanos = (int) (ticks % TimeSpan.TicksPerSecond) * NanosecondsPerTick;
+                return new Duration { Seconds = seconds, Nanos = nanos };
+            }
+        }
+
+        /// <summary>
+        /// Returns the result of negating the duration. For example, the negation of 5 minutes is -5 minutes.
+        /// </summary>
+        /// <param name="value">The duration to negate. Must not be null.</param>
+        /// <returns>The negated value of this duration.</returns>
+        public static Duration operator -(Duration value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            checked
+            {
+                return Normalize(-value.Seconds, -value.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Adds the two specified <see cref="Duration"/> values together.
+        /// </summary>
+        /// <param name="lhs">The first value to add. Must not be null.</param>
+        /// <param name="rhs">The second value to add. Must not be null.</param>
+        /// <returns></returns>
+        public static Duration operator +(Duration lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Subtracts one <see cref="Duration"/> from another.
+        /// </summary>
+        /// <param name="lhs">The duration to subtract from. Must not be null.</param>
+        /// <param name="rhs">The duration to subtract. Must not be null.</param>
+        /// <returns>The difference between the two specified durations.</returns>
+        public static Duration operator -(Duration lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+        
+        /// <summary>
+        /// Creates a duration with the normalized values from the given number of seconds and
+        /// nanoseconds, conforming with the description in the proto file.
+        /// </summary>
+        internal static Duration Normalize(long seconds, int nanoseconds)
+        {
+            // Ensure that nanoseconds is in the range (-1,000,000,000, +1,000,000,000)
+            int extraSeconds = nanoseconds / NanosecondsPerSecond;
+            seconds += extraSeconds;
+            nanoseconds -= extraSeconds * NanosecondsPerSecond;
+
+            // Now make sure that Sign(seconds) == Sign(nanoseconds) if Sign(seconds) != 0.
+            if (seconds < 0 && nanoseconds > 0)
+            {
+                seconds += 1;
+                nanoseconds -= NanosecondsPerSecond;
+            }
+            else if (seconds > 0 && nanoseconds < 0)
+            {
+                seconds -= 1;
+                nanoseconds += NanosecondsPerSecond;
+            }
+            return new Duration { Seconds = seconds, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts a duration specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>duration.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                var builder = new StringBuilder();
+                builder.Append('"');
+                // The seconds part will normally provide the minus sign if we need it, but not if it's 0...
+                if (seconds == 0 && nanoseconds < 0)
+                {
+                    builder.Append('-');
+                }
+
+                builder.Append(seconds.ToString("d", CultureInfo.InvariantCulture));
+                AppendNanoseconds(builder, Math.Abs(nanoseconds));
+                builder.Append("s\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                // Note: the double braces here are escaping for braces in format strings.
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Duration\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized duration value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Duration"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
+
+        /// <summary>
+        /// Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
+        /// case no "." is appended), or 3 6 or 9 digits. This is internal for use in Timestamp as well
+        /// as Duration.
+        /// </summary>
+        internal static void AppendNanoseconds(StringBuilder builder, int nanos)
+        {
+            if (nanos != 0)
+            {
+                builder.Append('.');
+                // Output to 3, 6 or 9 digits.
+                if (nanos % 1000000 == 0)
+                {
+                    builder.Append((nanos / 1000000).ToString("d3", CultureInfo.InvariantCulture));
+                }
+                else if (nanos % 1000 == 0)
+                {
+                    builder.Append((nanos / 1000).ToString("d6", CultureInfo.InvariantCulture));
+                }
+                else
+                {
+                    builder.Append(nanos.ToString("d9", CultureInfo.InvariantCulture));
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
new file mode 100644
index 0000000..e08ea24
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
@@ -0,0 +1,132 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/empty.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class EmptyReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/empty.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static EmptyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
+            "ZiIHCgVFbXB0eUJ5ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
+            "UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0eaAB",
+            "AfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
+            "cHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), global::Google.Protobuf.WellKnownTypes.Empty.Parser, null, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A generic empty message that you can re-use to avoid defining duplicated
+  ///  empty messages in your APIs. A typical example is to use it as the request
+  ///  or the response type of an API method. For instance:
+  ///
+  ///      service Foo {
+  ///        rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+  ///      }
+  ///
+  ///  The JSON representation for `Empty` is empty JSON object `{}`.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Empty : pb::IMessage<Empty> {
+    private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty());
+    public static pb::MessageParser<Empty> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Empty() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Empty(Empty other) : this() {
+    }
+
+    public Empty Clone() {
+      return new Empty(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Empty);
+    }
+
+    public bool Equals(Empty other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(Empty other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
new file mode 100644
index 0000000..6f0a64d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
@@ -0,0 +1,292 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/field_mask.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class FieldMaskReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/field_mask.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static FieldMaskReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v",
+            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v",
+            "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), global::Google.Protobuf.WellKnownTypes.FieldMask.Parser, new[]{ "Paths" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `FieldMask` represents a set of symbolic field paths, for example:
+  ///
+  ///      paths: "f.a"
+  ///      paths: "f.b.d"
+  ///
+  ///  Here `f` represents a field in some root message, `a` and `b`
+  ///  fields in the message found in `f`, and `d` a field found in the
+  ///  message in `f.b`.
+  ///
+  ///  Field masks are used to specify a subset of fields that should be
+  ///  returned by a get operation or modified by an update operation.
+  ///  Field masks also have a custom JSON encoding (see below).
+  ///
+  ///  # Field Masks in Projections
+  ///
+  ///  When used in the context of a projection, a response message or
+  ///  sub-message is filtered by the API to only contain those fields as
+  ///  specified in the mask. For example, if the mask in the previous
+  ///  example is applied to a response message as follows:
+  ///
+  ///      f {
+  ///        a : 22
+  ///        b {
+  ///          d : 1
+  ///          x : 2
+  ///        }
+  ///        y : 13
+  ///      }
+  ///      z: 8
+  ///
+  ///  The result will not contain specific values for fields x,y and z
+  ///  (their value will be set to the default, and omitted in proto text
+  ///  output):
+  ///
+  ///      f {
+  ///        a : 22
+  ///        b {
+  ///          d : 1
+  ///        }
+  ///      }
+  ///
+  ///  A repeated field is not allowed except at the last position of a
+  ///  field mask.
+  ///
+  ///  If a FieldMask object is not present in a get operation, the
+  ///  operation applies to all fields (as if a FieldMask of all fields
+  ///  had been specified).
+  ///
+  ///  Note that a field mask does not necessarily apply to the
+  ///  top-level response message. In case of a REST get operation, the
+  ///  field mask applies directly to the response, but in case of a REST
+  ///  list operation, the mask instead applies to each individual message
+  ///  in the returned resource list. In case of a REST custom method,
+  ///  other definitions may be used. Where the mask applies will be
+  ///  clearly documented together with its declaration in the API.  In
+  ///  any case, the effect on the returned resource/resources is required
+  ///  behavior for APIs.
+  ///
+  ///  # Field Masks in Update Operations
+  ///
+  ///  A field mask in update operations specifies which fields of the
+  ///  targeted resource are going to be updated. The API is required
+  ///  to only change the values of the fields as specified in the mask
+  ///  and leave the others untouched. If a resource is passed in to
+  ///  describe the updated values, the API ignores the values of all
+  ///  fields not covered by the mask.
+  ///
+  ///  In order to reset a field's value to the default, the field must
+  ///  be in the mask and set to the default value in the provided resource.
+  ///  Hence, in order to reset all fields of a resource, provide a default
+  ///  instance of the resource and set all fields in the mask, or do
+  ///  not provide a mask as described below.
+  ///
+  ///  If a field mask is not present on update, the operation applies to
+  ///  all fields (as if a field mask of all fields has been specified).
+  ///  Note that in the presence of schema evolution, this may mean that
+  ///  fields the client does not know and has therefore not filled into
+  ///  the request will be reset to their default. If this is unwanted
+  ///  behavior, a specific service may require a client to always specify
+  ///  a field mask, producing an error if not.
+  ///
+  ///  As with get operations, the location of the resource which
+  ///  describes the updated values in the request message depends on the
+  ///  operation kind. In any case, the effect of the field mask is
+  ///  required to be honored by the API.
+  ///
+  ///  ## Considerations for HTTP REST
+  ///
+  ///  The HTTP kind of an update operation which uses a field mask must
+  ///  be set to PATCH instead of PUT in order to satisfy HTTP semantics
+  ///  (PUT must only be used for full updates).
+  ///
+  ///  # JSON Encoding of Field Masks
+  ///
+  ///  In JSON, a field mask is encoded as a single string where paths are
+  ///  separated by a comma. Fields name in each path are converted
+  ///  to/from lower-camel naming conventions.
+  ///
+  ///  As an example, consider the following message declarations:
+  ///
+  ///      message Profile {
+  ///        User user = 1;
+  ///        Photo photo = 2;
+  ///      }
+  ///      message User {
+  ///        string display_name = 1;
+  ///        string address = 2;
+  ///      }
+  ///
+  ///  In proto a field mask for `Profile` may look as such:
+  ///
+  ///      mask {
+  ///        paths: "user.display_name"
+  ///        paths: "photo"
+  ///      }
+  ///
+  ///  In JSON, the same mask is represented as below:
+  ///
+  ///      {
+  ///        mask: "user.displayName,photo"
+  ///      }
+  ///
+  ///  # Field Masks and Oneof Fields
+  ///
+  ///  Field masks treat fields in oneofs just as regular fields. Consider the
+  ///  following message:
+  ///
+  ///      message SampleMessage {
+  ///        oneof test_oneof {
+  ///          string name = 4;
+  ///          SubMessage sub_message = 9;
+  ///        }
+  ///      }
+  ///
+  ///  The field mask can be:
+  ///
+  ///      mask {
+  ///        paths: "name"
+  ///      }
+  ///
+  ///  Or:
+  ///
+  ///      mask {
+  ///        paths: "sub_message"
+  ///      }
+  ///
+  ///  Note that oneof type names ("test_oneof" in this case) cannot be used in
+  ///  paths.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FieldMask : pb::IMessage<FieldMask> {
+    private static readonly pb::MessageParser<FieldMask> _parser = new pb::MessageParser<FieldMask>(() => new FieldMask());
+    public static pb::MessageParser<FieldMask> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldMask() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldMask(FieldMask other) : this() {
+      paths_ = other.paths_.Clone();
+    }
+
+    public FieldMask Clone() {
+      return new FieldMask(this);
+    }
+
+    /// <summary>Field number for the "paths" field.</summary>
+    public const int PathsFieldNumber = 1;
+    private static readonly pb::FieldCodec<string> _repeated_paths_codec
+        = pb::FieldCodec.ForString(10);
+    private readonly pbc::RepeatedField<string> paths_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The set of field mask paths.
+    /// </summary>
+    public pbc::RepeatedField<string> Paths {
+      get { return paths_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldMask);
+    }
+
+    public bool Equals(FieldMask other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!paths_.Equals(other.paths_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= paths_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      paths_.WriteTo(output, _repeated_paths_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += paths_.CalculateSize(_repeated_paths_codec);
+      return size;
+    }
+
+    public void MergeFrom(FieldMask other) {
+      if (other == null) {
+        return;
+      }
+      paths_.Add(other.paths_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            paths_.AddEntriesFrom(input, _repeated_paths_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
new file mode 100644
index 0000000..4bd62cf
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -0,0 +1,123 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    // Manually-written partial class for the FieldMask well-known type.
+    public partial class FieldMask : ICustomDiagnosticMessage
+    {
+        /// <summary>
+        /// Converts a timestamp  specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="paths">Paths in the field mask</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(IList<string> paths, bool diagnosticOnly)
+        {
+            var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
+            if (firstInvalid == null)
+            {
+                var writer = new StringWriter();
+                JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToCamelCase)));
+                return writer.ToString();
+            }
+            else
+            {
+                if (diagnosticOnly)
+                {
+                    var writer = new StringWriter();
+                    writer.Write("{ \"@warning\": \"Invalid FieldMask\", \"paths\": ");
+                    JsonFormatter.Default.WriteList(writer, (IList)paths);
+                    writer.Write(" }");
+                    return writer.ToString();
+                }
+                else
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {firstInvalid}");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static bool ValidatePath(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    return false;
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="FieldMask"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Paths, true);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
new file mode 100644
index 0000000..a235ece
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
@@ -0,0 +1,156 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/source_context.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class SourceContextReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/source_context.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static SourceContextReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
+            "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
+            "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
+            "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
+            "cHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), global::Google.Protobuf.WellKnownTypes.SourceContext.Parser, new[]{ "FileName" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `SourceContext` represents information about the source of a
+  ///  protobuf element, like the file in which it is defined.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class SourceContext : pb::IMessage<SourceContext> {
+    private static readonly pb::MessageParser<SourceContext> _parser = new pb::MessageParser<SourceContext>(() => new SourceContext());
+    public static pb::MessageParser<SourceContext> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public SourceContext() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public SourceContext(SourceContext other) : this() {
+      fileName_ = other.fileName_;
+    }
+
+    public SourceContext Clone() {
+      return new SourceContext(this);
+    }
+
+    /// <summary>Field number for the "file_name" field.</summary>
+    public const int FileNameFieldNumber = 1;
+    private string fileName_ = "";
+    /// <summary>
+    ///  The path-qualified name of the .proto file that contained the associated
+    ///  protobuf element.  For example: `"google/protobuf/source.proto"`.
+    /// </summary>
+    public string FileName {
+      get { return fileName_; }
+      set {
+        fileName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as SourceContext);
+    }
+
+    public bool Equals(SourceContext other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (FileName != other.FileName) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (FileName.Length != 0) hash ^= FileName.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (FileName.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(FileName);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (FileName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(FileName);
+      }
+      return size;
+    }
+
+    public void MergeFrom(SourceContext other) {
+      if (other == null) {
+        return;
+      }
+      if (other.FileName.Length != 0) {
+        FileName = other.FileName;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            FileName = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
new file mode 100644
index 0000000..edc8940
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -0,0 +1,600 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/struct.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class StructReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/struct.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static StructReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i",
+            "dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i",
+            "dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB",
+            "IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC",
+            "OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv",
+            "dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM",
+            "c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K",
+            "DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI",
+            "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW",
+            "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW",
+            "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W",
+            "QUxVRRAAQoEBChNjb20uZ29vZ2xlLnByb3RvYnVmQgtTdHJ1Y3RQcm90b1AB",
+            "WjFnaXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wdHlwZXMvc3RydWN0O3N0",
+            "cnVjdHBioAEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5",
+            "cGVzYgZwcm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), global::Google.Protobuf.WellKnownTypes.Struct.Parser, new[]{ "Fields" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Value), global::Google.Protobuf.WellKnownTypes.Value.Parser, new[]{ "NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue" }, new[]{ "Kind" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.ListValue), global::Google.Protobuf.WellKnownTypes.ListValue.Parser, new[]{ "Values" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  /// <summary>
+  ///  `NullValue` is a singleton enumeration to represent the null value for the
+  ///  `Value` type union.
+  ///
+  ///   The JSON representation for `NullValue` is JSON `null`.
+  /// </summary>
+  public enum NullValue {
+    /// <summary>
+    ///  Null value.
+    /// </summary>
+    [pbr::OriginalName("NULL_VALUE")] NullValue = 0,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  `Struct` represents a structured data value, consisting of fields
+  ///  which map to dynamically typed values. In some languages, `Struct`
+  ///  might be supported by a native representation. For example, in
+  ///  scripting languages like JS a struct is represented as an
+  ///  object. The details of that representation are described together
+  ///  with the proto support for the language.
+  ///
+  ///  The JSON representation for `Struct` is JSON object.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Struct : pb::IMessage<Struct> {
+    private static readonly pb::MessageParser<Struct> _parser = new pb::MessageParser<Struct>(() => new Struct());
+    public static pb::MessageParser<Struct> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Struct() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Struct(Struct other) : this() {
+      fields_ = other.fields_.Clone();
+    }
+
+    public Struct Clone() {
+      return new Struct(this);
+    }
+
+    /// <summary>Field number for the "fields" field.</summary>
+    public const int FieldsFieldNumber = 1;
+    private static readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec _map_fields_codec
+        = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10);
+    private readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> fields_ = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Unordered map of dynamically typed values.
+    /// </summary>
+    public pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> Fields {
+      get { return fields_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Struct);
+    }
+
+    public bool Equals(Struct other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!Fields.Equals(other.Fields)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= Fields.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      fields_.WriteTo(output, _map_fields_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += fields_.CalculateSize(_map_fields_codec);
+      return size;
+    }
+
+    public void MergeFrom(Struct other) {
+      if (other == null) {
+        return;
+      }
+      fields_.Add(other.fields_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            fields_.AddEntriesFrom(input, _map_fields_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  `Value` represents a dynamically typed value which can be either
+  ///  null, a number, a string, a boolean, a recursive struct value, or a
+  ///  list of values. A producer of value is expected to set one of that
+  ///  variants, absence of any variant indicates an error.
+  ///
+  ///  The JSON representation for `Value` is JSON value.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Value : pb::IMessage<Value> {
+    private static readonly pb::MessageParser<Value> _parser = new pb::MessageParser<Value>(() => new Value());
+    public static pb::MessageParser<Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Value(Value other) : this() {
+      switch (other.KindCase) {
+        case KindOneofCase.NullValue:
+          NullValue = other.NullValue;
+          break;
+        case KindOneofCase.NumberValue:
+          NumberValue = other.NumberValue;
+          break;
+        case KindOneofCase.StringValue:
+          StringValue = other.StringValue;
+          break;
+        case KindOneofCase.BoolValue:
+          BoolValue = other.BoolValue;
+          break;
+        case KindOneofCase.StructValue:
+          StructValue = other.StructValue.Clone();
+          break;
+        case KindOneofCase.ListValue:
+          ListValue = other.ListValue.Clone();
+          break;
+      }
+
+    }
+
+    public Value Clone() {
+      return new Value(this);
+    }
+
+    /// <summary>Field number for the "null_value" field.</summary>
+    public const int NullValueFieldNumber = 1;
+    /// <summary>
+    ///  Represents a null value.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
+      get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : 0; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.NullValue;
+      }
+    }
+
+    /// <summary>Field number for the "number_value" field.</summary>
+    public const int NumberValueFieldNumber = 2;
+    /// <summary>
+    ///  Represents a double value.
+    /// </summary>
+    public double NumberValue {
+      get { return kindCase_ == KindOneofCase.NumberValue ? (double) kind_ : 0D; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.NumberValue;
+      }
+    }
+
+    /// <summary>Field number for the "string_value" field.</summary>
+    public const int StringValueFieldNumber = 3;
+    /// <summary>
+    ///  Represents a string value.
+    /// </summary>
+    public string StringValue {
+      get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
+      set {
+        kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        kindCase_ = KindOneofCase.StringValue;
+      }
+    }
+
+    /// <summary>Field number for the "bool_value" field.</summary>
+    public const int BoolValueFieldNumber = 4;
+    /// <summary>
+    ///  Represents a boolean value.
+    /// </summary>
+    public bool BoolValue {
+      get { return kindCase_ == KindOneofCase.BoolValue ? (bool) kind_ : false; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.BoolValue;
+      }
+    }
+
+    /// <summary>Field number for the "struct_value" field.</summary>
+    public const int StructValueFieldNumber = 5;
+    /// <summary>
+    ///  Represents a structured value.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Struct StructValue {
+      get { return kindCase_ == KindOneofCase.StructValue ? (global::Google.Protobuf.WellKnownTypes.Struct) kind_ : null; }
+      set {
+        kind_ = value;
+        kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.StructValue;
+      }
+    }
+
+    /// <summary>Field number for the "list_value" field.</summary>
+    public const int ListValueFieldNumber = 6;
+    /// <summary>
+    ///  Represents a repeated `Value`.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.ListValue ListValue {
+      get { return kindCase_ == KindOneofCase.ListValue ? (global::Google.Protobuf.WellKnownTypes.ListValue) kind_ : null; }
+      set {
+        kind_ = value;
+        kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.ListValue;
+      }
+    }
+
+    private object kind_;
+    /// <summary>Enum of possible cases for the "kind" oneof.</summary>
+    public enum KindOneofCase {
+      None = 0,
+      NullValue = 1,
+      NumberValue = 2,
+      StringValue = 3,
+      BoolValue = 4,
+      StructValue = 5,
+      ListValue = 6,
+    }
+    private KindOneofCase kindCase_ = KindOneofCase.None;
+    public KindOneofCase KindCase {
+      get { return kindCase_; }
+    }
+
+    public void ClearKind() {
+      kindCase_ = KindOneofCase.None;
+      kind_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Value);
+    }
+
+    public bool Equals(Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (NullValue != other.NullValue) return false;
+      if (NumberValue != other.NumberValue) return false;
+      if (StringValue != other.StringValue) return false;
+      if (BoolValue != other.BoolValue) return false;
+      if (!object.Equals(StructValue, other.StructValue)) return false;
+      if (!object.Equals(ListValue, other.ListValue)) return false;
+      if (KindCase != other.KindCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (kindCase_ == KindOneofCase.NullValue) hash ^= NullValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.NumberValue) hash ^= NumberValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.StringValue) hash ^= StringValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.StructValue) hash ^= StructValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.ListValue) hash ^= ListValue.GetHashCode();
+      hash ^= (int) kindCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (kindCase_ == KindOneofCase.NullValue) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) NullValue);
+      }
+      if (kindCase_ == KindOneofCase.NumberValue) {
+        output.WriteRawTag(17);
+        output.WriteDouble(NumberValue);
+      }
+      if (kindCase_ == KindOneofCase.StringValue) {
+        output.WriteRawTag(26);
+        output.WriteString(StringValue);
+      }
+      if (kindCase_ == KindOneofCase.BoolValue) {
+        output.WriteRawTag(32);
+        output.WriteBool(BoolValue);
+      }
+      if (kindCase_ == KindOneofCase.StructValue) {
+        output.WriteRawTag(42);
+        output.WriteMessage(StructValue);
+      }
+      if (kindCase_ == KindOneofCase.ListValue) {
+        output.WriteRawTag(50);
+        output.WriteMessage(ListValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (kindCase_ == KindOneofCase.NullValue) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NullValue);
+      }
+      if (kindCase_ == KindOneofCase.NumberValue) {
+        size += 1 + 8;
+      }
+      if (kindCase_ == KindOneofCase.StringValue) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
+      }
+      if (kindCase_ == KindOneofCase.BoolValue) {
+        size += 1 + 1;
+      }
+      if (kindCase_ == KindOneofCase.StructValue) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(StructValue);
+      }
+      if (kindCase_ == KindOneofCase.ListValue) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ListValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Value other) {
+      if (other == null) {
+        return;
+      }
+      switch (other.KindCase) {
+        case KindOneofCase.NullValue:
+          NullValue = other.NullValue;
+          break;
+        case KindOneofCase.NumberValue:
+          NumberValue = other.NumberValue;
+          break;
+        case KindOneofCase.StringValue:
+          StringValue = other.StringValue;
+          break;
+        case KindOneofCase.BoolValue:
+          BoolValue = other.BoolValue;
+          break;
+        case KindOneofCase.StructValue:
+          StructValue = other.StructValue;
+          break;
+        case KindOneofCase.ListValue:
+          ListValue = other.ListValue;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            kind_ = input.ReadEnum();
+            kindCase_ = KindOneofCase.NullValue;
+            break;
+          }
+          case 17: {
+            NumberValue = input.ReadDouble();
+            break;
+          }
+          case 26: {
+            StringValue = input.ReadString();
+            break;
+          }
+          case 32: {
+            BoolValue = input.ReadBool();
+            break;
+          }
+          case 42: {
+            global::Google.Protobuf.WellKnownTypes.Struct subBuilder = new global::Google.Protobuf.WellKnownTypes.Struct();
+            if (kindCase_ == KindOneofCase.StructValue) {
+              subBuilder.MergeFrom(StructValue);
+            }
+            input.ReadMessage(subBuilder);
+            StructValue = subBuilder;
+            break;
+          }
+          case 50: {
+            global::Google.Protobuf.WellKnownTypes.ListValue subBuilder = new global::Google.Protobuf.WellKnownTypes.ListValue();
+            if (kindCase_ == KindOneofCase.ListValue) {
+              subBuilder.MergeFrom(ListValue);
+            }
+            input.ReadMessage(subBuilder);
+            ListValue = subBuilder;
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  `ListValue` is a wrapper around a repeated field of values.
+  ///
+  ///  The JSON representation for `ListValue` is JSON array.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ListValue : pb::IMessage<ListValue> {
+    private static readonly pb::MessageParser<ListValue> _parser = new pb::MessageParser<ListValue>(() => new ListValue());
+    public static pb::MessageParser<ListValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ListValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ListValue(ListValue other) : this() {
+      values_ = other.values_.Clone();
+    }
+
+    public ListValue Clone() {
+      return new ListValue(this);
+    }
+
+    /// <summary>Field number for the "values" field.</summary>
+    public const int ValuesFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_values_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Value.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> values_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Repeated field of dynamically typed values.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> Values {
+      get { return values_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ListValue);
+    }
+
+    public bool Equals(ListValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!values_.Equals(other.values_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= values_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      values_.WriteTo(output, _repeated_values_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += values_.CalculateSize(_repeated_values_codec);
+      return size;
+    }
+
+    public void MergeFrom(ListValue other) {
+      if (other == null) {
+        return;
+      }
+      values_.Add(other.values_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            values_.AddEntriesFrom(input, _repeated_values_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs
new file mode 100644
index 0000000..dd485d3
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs
@@ -0,0 +1,80 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    /// <summary>
+    /// Extension methods on BCL time-related types, converting to protobuf types.
+    /// </summary>
+    public static class TimeExtensions
+    {
+        /// <summary>
+        /// Converts the given <see cref="DateTime"/> to a <see cref="Timestamp"/>.
+        /// </summary>
+        /// <param name="dateTime">The date and time to convert to a timestamp.</param>
+        /// <exception cref="ArgumentException">The <paramref name="dateTime"/> value has a <see cref="DateTime.Kind"/>other than <c>Utc</c>.</exception>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp ToTimestamp(this DateTime dateTime)
+        {
+            return Timestamp.FromDateTime(dateTime);
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
+        /// </summary>
+        /// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
+        /// is represented) but is not a separate part of the resulting value. In other words, there is no
+        /// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
+        /// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp ToTimestamp(this DateTimeOffset dateTimeOffset)
+        {
+            return Timestamp.FromDateTimeOffset(dateTimeOffset);
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="timeSpan">The time span to convert.</param>
+        /// <returns>The converted duration.</returns>
+        public static Duration ToDuration(this TimeSpan timeSpan)
+        {
+            return Duration.FromTimeSpan(timeSpan);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
new file mode 100644
index 0000000..053b88b
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -0,0 +1,241 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/timestamp.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TimestampReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/timestamp.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static TimestampReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
+            "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
+            "AiABKAVCgQEKE2NvbS5nb29nbGUucHJvdG9idWZCDlRpbWVzdGFtcFByb3Rv",
+            "UAFaK2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy90aW1lc3Rh",
+            "bXCgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
+            "ZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), global::Google.Protobuf.WellKnownTypes.Timestamp.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A Timestamp represents a point in time independent of any time zone
+  ///  or calendar, represented as seconds and fractions of seconds at
+  ///  nanosecond resolution in UTC Epoch time. It is encoded using the
+  ///  Proleptic Gregorian Calendar which extends the Gregorian calendar
+  ///  backwards to year one. It is encoded assuming all minutes are 60
+  ///  seconds long, i.e. leap seconds are "smeared" so that no leap second
+  ///  table is needed for interpretation. Range is from
+  ///  0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+  ///  By restricting to that range, we ensure that we can convert to
+  ///  and from  RFC 3339 date strings.
+  ///  See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+  ///
+  ///  Example 1: Compute Timestamp from POSIX `time()`.
+  ///
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds(time(NULL));
+  ///      timestamp.set_nanos(0);
+  ///
+  ///  Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+  ///
+  ///      struct timeval tv;
+  ///      gettimeofday(&amp;tv, NULL);
+  ///
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds(tv.tv_sec);
+  ///      timestamp.set_nanos(tv.tv_usec * 1000);
+  ///
+  ///  Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+  ///
+  ///      FILETIME ft;
+  ///      GetSystemTimeAsFileTime(&amp;ft);
+  ///      UINT64 ticks = (((UINT64)ft.dwHighDateTime) &lt;&lt; 32) | ft.dwLowDateTime;
+  ///
+  ///      // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+  ///      // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+  ///      timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+  ///
+  ///  Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+  ///
+  ///      long millis = System.currentTimeMillis();
+  ///
+  ///      Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+  ///          .setNanos((int) ((millis % 1000) * 1000000)).build();
+  ///
+  ///  Example 5: Compute Timestamp from current time in Python.
+  ///
+  ///      now = time.time()
+  ///      seconds = int(now)
+  ///      nanos = int((now - seconds) * 10**9)
+  ///      timestamp = Timestamp(seconds=seconds, nanos=nanos)
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Timestamp : pb::IMessage<Timestamp> {
+    private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
+    public static pb::MessageParser<Timestamp> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Timestamp() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Timestamp(Timestamp other) : this() {
+      seconds_ = other.seconds_;
+      nanos_ = other.nanos_;
+    }
+
+    public Timestamp Clone() {
+      return new Timestamp(this);
+    }
+
+    /// <summary>Field number for the "seconds" field.</summary>
+    public const int SecondsFieldNumber = 1;
+    private long seconds_;
+    /// <summary>
+    ///  Represents seconds of UTC time since Unix epoch
+    ///  1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+    ///  9999-12-31T23:59:59Z inclusive.
+    /// </summary>
+    public long Seconds {
+      get { return seconds_; }
+      set {
+        seconds_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "nanos" field.</summary>
+    public const int NanosFieldNumber = 2;
+    private int nanos_;
+    /// <summary>
+    ///  Non-negative fractions of a second at nanosecond resolution. Negative
+    ///  second values with fractions must still have non-negative nanos values
+    ///  that count forward in time. Must be from 0 to 999,999,999
+    ///  inclusive.
+    /// </summary>
+    public int Nanos {
+      get { return nanos_; }
+      set {
+        nanos_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Timestamp);
+    }
+
+    public bool Equals(Timestamp other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Seconds != other.Seconds) return false;
+      if (Nanos != other.Nanos) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Seconds != 0L) hash ^= Seconds.GetHashCode();
+      if (Nanos != 0) hash ^= Nanos.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Seconds != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Seconds);
+      }
+      if (Nanos != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Nanos);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Seconds != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
+      }
+      if (Nanos != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Timestamp other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Seconds != 0L) {
+        Seconds = other.Seconds;
+      }
+      if (other.Nanos != 0) {
+        Nanos = other.Nanos;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Seconds = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Nanos = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
new file mode 100644
index 0000000..aa40347
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
@@ -0,0 +1,241 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Timestamp : ICustomDiagnosticMessage
+    {
+        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+        // Constants determined programmatically, but then hard-coded so they can be constant expressions.
+        private const long BclSecondsAtUnixEpoch = 62135596800;
+        internal const long UnixSecondsAtBclMaxValue = 253402300799;
+        internal const long UnixSecondsAtBclMinValue = -BclSecondsAtUnixEpoch;
+        internal const int MaxNanos = Duration.NanosecondsPerSecond - 1;
+
+        private static bool IsNormalized(long seconds, int nanoseconds) =>
+            nanoseconds >= 0 &&
+            nanoseconds <= MaxNanos &&
+            seconds >= UnixSecondsAtBclMinValue &&
+            seconds <= UnixSecondsAtBclMaxValue;
+
+        /// <summary>
+        /// Returns the difference between one <see cref="Timestamp"/> and another, as a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to subtract from. Must not be null.</param>
+        /// <param name="rhs">The timestamp to subtract. Must not be null.</param>
+        /// <returns>The difference between the two specified timestamps.</returns>
+        public static Duration operator -(Timestamp lhs, Timestamp rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Adds a <see cref="Duration"/> to a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to add the duration to. Must not be null.</param>
+        /// <param name="rhs">The duration to add. Must not be null.</param>
+        /// <returns>The result of adding the duration to the timestamp.</returns>
+        public static Timestamp operator +(Timestamp lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Subtracts a <see cref="Duration"/> from a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to subtract the duration from. Must not be null.</param>
+        /// <param name="rhs">The duration to subtract.</param>
+        /// <returns>The result of subtracting the duration from the timestamp.</returns>
+        public static Timestamp operator -(Timestamp lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Converts this timestamp into a <see cref="DateTime"/>.
+        /// </summary>
+        /// <remarks>
+        /// The resulting <c>DateTime</c> will always have a <c>Kind</c> of <c>Utc</c>.
+        /// If the timestamp is not a precise number of ticks, it will be truncated towards the start
+        /// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
+        /// <see cref="DateTime"/> value precisely on a second.
+        /// </remarks>
+        /// <returns>This timestamp as a <c>DateTime</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
+        public DateTime ToDateTime()
+        {
+            if (!IsNormalized(Seconds, Nanos))
+            {
+                throw new InvalidOperationException(@"Timestamp contains invalid values: Seconds={Seconds}; Nanos={Nanos}");
+            }
+            return UnixEpoch.AddSeconds(Seconds).AddTicks(Nanos / Duration.NanosecondsPerTick);
+        }
+
+        /// <summary>
+        /// Converts this timestamp into a <see cref="DateTimeOffset"/>.
+        /// </summary>
+        /// <remarks>
+        /// The resulting <c>DateTimeOffset</c> will always have an <c>Offset</c> of zero.
+        /// If the timestamp is not a precise number of ticks, it will be truncated towards the start
+        /// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
+        /// <see cref="DateTimeOffset"/> value precisely on a second.
+        /// </remarks>
+        /// <returns>This timestamp as a <c>DateTimeOffset</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
+        public DateTimeOffset ToDateTimeOffset()
+        {
+            return new DateTimeOffset(ToDateTime(), TimeSpan.Zero);
+        }
+
+        /// <summary>
+        /// Converts the specified <see cref="DateTime"/> to a <see cref="Timestamp"/>.
+        /// </summary>
+        /// <param name="dateTime"></param>
+        /// <exception cref="ArgumentException">The <c>Kind</c> of <paramref name="dateTime"/> is not <c>DateTimeKind.Utc</c>.</exception>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp FromDateTime(DateTime dateTime)
+        {
+            if (dateTime.Kind != DateTimeKind.Utc)
+            {
+                throw new ArgumentException("Conversion from DateTime to Timestamp requires the DateTime kind to be Utc", "dateTime");
+            }
+            // Do the arithmetic using DateTime.Ticks, which is always non-negative, making things simpler.
+            long secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond;
+            int nanoseconds = (int)  (dateTime.Ticks % TimeSpan.TicksPerSecond) * Duration.NanosecondsPerTick;
+            return new Timestamp { Seconds = secondsSinceBclEpoch - BclSecondsAtUnixEpoch, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
+        /// </summary>
+        /// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
+        /// is represented) but is not a separate part of the resulting value. In other words, there is no
+        /// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
+        /// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp FromDateTimeOffset(DateTimeOffset dateTimeOffset)
+        {
+            // We don't need to worry about this having negative ticks: DateTimeOffset is constrained to handle
+            // values whose *UTC* value is in the range of DateTime.
+            return FromDateTime(dateTimeOffset.UtcDateTime);
+        }
+
+        internal static Timestamp Normalize(long seconds, int nanoseconds)
+        {
+            int extraSeconds = nanoseconds / Duration.NanosecondsPerSecond;
+            seconds += extraSeconds;
+            nanoseconds -= extraSeconds * Duration.NanosecondsPerSecond;
+
+            if (nanoseconds < 0)
+            {
+                nanoseconds += Duration.NanosecondsPerSecond;
+                seconds--;
+            }
+            return new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts a timestamp specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                // Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
+                DateTime dateTime = UnixEpoch.AddSeconds(seconds);
+                var builder = new StringBuilder();
+                builder.Append('"');
+                builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture));
+                Duration.AppendNanoseconds(builder, nanoseconds);
+                builder.Append("Z\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized timestamp value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Timestamp"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
new file mode 100644
index 0000000..657c246
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
@@ -0,0 +1,1347 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/type.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TypeReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/type.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static TypeReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxIPZ29vZ2xlLnByb3RvYnVm",
+            "Ghlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGiRnb29nbGUvcHJvdG9idWYv",
+            "c291cmNlX2NvbnRleHQucHJvdG8i1wEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm",
+            "CgZmaWVsZHMYAiADKAsyFi5nb29nbGUucHJvdG9idWYuRmllbGQSDgoGb25l",
+            "b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu",
+            "T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv",
+            "YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy",
+            "b3RvYnVmLlN5bnRheCLVBQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds",
+            "ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD",
+            "IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m",
+            "X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL",
+            "MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgLIAEoCSLIAgoES2luZBIQCgxUWVBFX1VOS05P",
+            "V04QABIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBF",
+            "X0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoM",
+            "VFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09M",
+            "EAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9N",
+            "RVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJ",
+            "VFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVE",
+            "NjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2Fy",
+            "ZGluYWxpdHkSFwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFM",
+            "SVRZX09QVElPTkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRD",
+            "QVJESU5BTElUWV9SRVBFQVRFRBADIs4BCgRFbnVtEgwKBG5hbWUYASABKAkS",
+            "LQoJZW51bXZhbHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1",
+            "ZRIoCgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2",
+            "Cg5zb3VyY2VfY29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3Vy",
+            "Y2VDb250ZXh0EicKBnN5bnRheBgFIAEoDjIXLmdvb2dsZS5wcm90b2J1Zi5T",
+            "eW50YXgiUwoJRW51bVZhbHVlEgwKBG5hbWUYASABKAkSDgoGbnVtYmVyGAIg",
+            "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
+            "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
+            "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
+            "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
+            "eXBlUHJvdG9QAaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
+            "d25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName", "DefaultValue" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  /// <summary>
+  ///  The syntax in which a protocol buffer element is defined.
+  /// </summary>
+  public enum Syntax {
+    /// <summary>
+    ///  Syntax `proto2`.
+    /// </summary>
+    [pbr::OriginalName("SYNTAX_PROTO2")] Proto2 = 0,
+    /// <summary>
+    ///  Syntax `proto3`.
+    /// </summary>
+    [pbr::OriginalName("SYNTAX_PROTO3")] Proto3 = 1,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  A protocol buffer message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Type : pb::IMessage<Type> {
+    private static readonly pb::MessageParser<Type> _parser = new pb::MessageParser<Type>(() => new Type());
+    public static pb::MessageParser<Type> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Type() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Type(Type other) : this() {
+      name_ = other.name_;
+      fields_ = other.fields_.Clone();
+      oneofs_ = other.oneofs_.Clone();
+      options_ = other.options_.Clone();
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public Type Clone() {
+      return new Type(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified message name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "fields" field.</summary>
+    public const int FieldsFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Field> _repeated_fields_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Field.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> fields_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field>();
+    /// <summary>
+    ///  The list of fields.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> Fields {
+      get { return fields_; }
+    }
+
+    /// <summary>Field number for the "oneofs" field.</summary>
+    public const int OneofsFieldNumber = 3;
+    private static readonly pb::FieldCodec<string> _repeated_oneofs_codec
+        = pb::FieldCodec.ForString(26);
+    private readonly pbc::RepeatedField<string> oneofs_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The list of types appearing in `oneof` definitions in this type.
+    /// </summary>
+    public pbc::RepeatedField<string> Oneofs {
+      get { return oneofs_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 6;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Type);
+    }
+
+    public bool Equals(Type other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!fields_.Equals(other.fields_)) return false;
+      if(!oneofs_.Equals(other.oneofs_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= fields_.GetHashCode();
+      hash ^= oneofs_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      fields_.WriteTo(output, _repeated_fields_codec);
+      oneofs_.WriteTo(output, _repeated_oneofs_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (sourceContext_ != null) {
+        output.WriteRawTag(42);
+        output.WriteMessage(SourceContext);
+      }
+      if (Syntax != 0) {
+        output.WriteRawTag(48);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += fields_.CalculateSize(_repeated_fields_codec);
+      size += oneofs_.CalculateSize(_repeated_oneofs_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      if (Syntax != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Type other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      fields_.Add(other.fields_);
+      oneofs_.Add(other.oneofs_);
+      options_.Add(other.options_);
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      if (other.Syntax != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            fields_.AddEntriesFrom(input, _repeated_fields_codec);
+            break;
+          }
+          case 26: {
+            oneofs_.AddEntriesFrom(input, _repeated_oneofs_codec);
+            break;
+          }
+          case 34: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 42: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 48: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A single field of a message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Field : pb::IMessage<Field> {
+    private static readonly pb::MessageParser<Field> _parser = new pb::MessageParser<Field>(() => new Field());
+    public static pb::MessageParser<Field> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Field() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Field(Field other) : this() {
+      kind_ = other.kind_;
+      cardinality_ = other.cardinality_;
+      number_ = other.number_;
+      name_ = other.name_;
+      typeUrl_ = other.typeUrl_;
+      oneofIndex_ = other.oneofIndex_;
+      packed_ = other.packed_;
+      options_ = other.options_.Clone();
+      jsonName_ = other.jsonName_;
+      defaultValue_ = other.defaultValue_;
+    }
+
+    public Field Clone() {
+      return new Field(this);
+    }
+
+    /// <summary>Field number for the "kind" field.</summary>
+    public const int KindFieldNumber = 1;
+    private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = 0;
+    /// <summary>
+    ///  The field type.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Field.Types.Kind Kind {
+      get { return kind_; }
+      set {
+        kind_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "cardinality" field.</summary>
+    public const int CardinalityFieldNumber = 2;
+    private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = 0;
+    /// <summary>
+    ///  The field cardinality.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality Cardinality {
+      get { return cardinality_; }
+      set {
+        cardinality_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 3;
+    private int number_;
+    /// <summary>
+    ///  The field number.
+    /// </summary>
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 4;
+    private string name_ = "";
+    /// <summary>
+    ///  The field name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "type_url" field.</summary>
+    public const int TypeUrlFieldNumber = 6;
+    private string typeUrl_ = "";
+    /// <summary>
+    ///  The field type URL, without the scheme, for message or enumeration
+    ///  types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+    /// </summary>
+    public string TypeUrl {
+      get { return typeUrl_; }
+      set {
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "oneof_index" field.</summary>
+    public const int OneofIndexFieldNumber = 7;
+    private int oneofIndex_;
+    /// <summary>
+    ///  The index of the field type in `Type.oneofs`, for message or enumeration
+    ///  types. The first type has index 1; zero means the type is not in the list.
+    /// </summary>
+    public int OneofIndex {
+      get { return oneofIndex_; }
+      set {
+        oneofIndex_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "packed" field.</summary>
+    public const int PackedFieldNumber = 8;
+    private bool packed_;
+    /// <summary>
+    ///  Whether to use alternative packed wire representation.
+    /// </summary>
+    public bool Packed {
+      get { return packed_; }
+      set {
+        packed_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  The field JSON name.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "default_value" field.</summary>
+    public const int DefaultValueFieldNumber = 11;
+    private string defaultValue_ = "";
+    /// <summary>
+    ///  The string value of the default value of this field. Proto2 syntax only.
+    /// </summary>
+    public string DefaultValue {
+      get { return defaultValue_; }
+      set {
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Field);
+    }
+
+    public bool Equals(Field other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Kind != other.Kind) return false;
+      if (Cardinality != other.Cardinality) return false;
+      if (Number != other.Number) return false;
+      if (Name != other.Name) return false;
+      if (TypeUrl != other.TypeUrl) return false;
+      if (OneofIndex != other.OneofIndex) return false;
+      if (Packed != other.Packed) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (JsonName != other.JsonName) return false;
+      if (DefaultValue != other.DefaultValue) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Kind != 0) hash ^= Kind.GetHashCode();
+      if (Cardinality != 0) hash ^= Cardinality.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
+      if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
+      if (Packed != false) hash ^= Packed.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
+      if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Kind != 0) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Kind);
+      }
+      if (Cardinality != 0) {
+        output.WriteRawTag(16);
+        output.WriteEnum((int) Cardinality);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(24);
+        output.WriteInt32(Number);
+      }
+      if (Name.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(Name);
+      }
+      if (TypeUrl.Length != 0) {
+        output.WriteRawTag(50);
+        output.WriteString(TypeUrl);
+      }
+      if (OneofIndex != 0) {
+        output.WriteRawTag(56);
+        output.WriteInt32(OneofIndex);
+      }
+      if (Packed != false) {
+        output.WriteRawTag(64);
+        output.WriteBool(Packed);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(DefaultValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Kind != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Kind);
+      }
+      if (Cardinality != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Cardinality);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (TypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeUrl);
+      }
+      if (OneofIndex != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofIndex);
+      }
+      if (Packed != false) {
+        size += 1 + 1;
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Field other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Kind != 0) {
+        Kind = other.Kind;
+      }
+      if (other.Cardinality != 0) {
+        Cardinality = other.Cardinality;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.TypeUrl.Length != 0) {
+        TypeUrl = other.TypeUrl;
+      }
+      if (other.OneofIndex != 0) {
+        OneofIndex = other.OneofIndex;
+      }
+      if (other.Packed != false) {
+        Packed = other.Packed;
+      }
+      options_.Add(other.options_);
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
+      if (other.DefaultValue.Length != 0) {
+        DefaultValue = other.DefaultValue;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            kind_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Kind) input.ReadEnum();
+            break;
+          }
+          case 16: {
+            cardinality_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) input.ReadEnum();
+            break;
+          }
+          case 24: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 34: {
+            Name = input.ReadString();
+            break;
+          }
+          case 50: {
+            TypeUrl = input.ReadString();
+            break;
+          }
+          case 56: {
+            OneofIndex = input.ReadInt32();
+            break;
+          }
+          case 64: {
+            Packed = input.ReadBool();
+            break;
+          }
+          case 74: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
+          case 90: {
+            DefaultValue = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the Field message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  Basic field types.
+      /// </summary>
+      public enum Kind {
+        /// <summary>
+        ///  Field type unknown.
+        /// </summary>
+        [pbr::OriginalName("TYPE_UNKNOWN")] TypeUnknown = 0,
+        /// <summary>
+        ///  Field type double.
+        /// </summary>
+        [pbr::OriginalName("TYPE_DOUBLE")] TypeDouble = 1,
+        /// <summary>
+        ///  Field type float.
+        /// </summary>
+        [pbr::OriginalName("TYPE_FLOAT")] TypeFloat = 2,
+        /// <summary>
+        ///  Field type int64.
+        /// </summary>
+        [pbr::OriginalName("TYPE_INT64")] TypeInt64 = 3,
+        /// <summary>
+        ///  Field type uint64.
+        /// </summary>
+        [pbr::OriginalName("TYPE_UINT64")] TypeUint64 = 4,
+        /// <summary>
+        ///  Field type int32.
+        /// </summary>
+        [pbr::OriginalName("TYPE_INT32")] TypeInt32 = 5,
+        /// <summary>
+        ///  Field type fixed64.
+        /// </summary>
+        [pbr::OriginalName("TYPE_FIXED64")] TypeFixed64 = 6,
+        /// <summary>
+        ///  Field type fixed32.
+        /// </summary>
+        [pbr::OriginalName("TYPE_FIXED32")] TypeFixed32 = 7,
+        /// <summary>
+        ///  Field type bool.
+        /// </summary>
+        [pbr::OriginalName("TYPE_BOOL")] TypeBool = 8,
+        /// <summary>
+        ///  Field type string.
+        /// </summary>
+        [pbr::OriginalName("TYPE_STRING")] TypeString = 9,
+        /// <summary>
+        ///  Field type group. Proto2 syntax only, and deprecated.
+        /// </summary>
+        [pbr::OriginalName("TYPE_GROUP")] TypeGroup = 10,
+        /// <summary>
+        ///  Field type message.
+        /// </summary>
+        [pbr::OriginalName("TYPE_MESSAGE")] TypeMessage = 11,
+        /// <summary>
+        ///  Field type bytes.
+        /// </summary>
+        [pbr::OriginalName("TYPE_BYTES")] TypeBytes = 12,
+        /// <summary>
+        ///  Field type uint32.
+        /// </summary>
+        [pbr::OriginalName("TYPE_UINT32")] TypeUint32 = 13,
+        /// <summary>
+        ///  Field type enum.
+        /// </summary>
+        [pbr::OriginalName("TYPE_ENUM")] TypeEnum = 14,
+        /// <summary>
+        ///  Field type sfixed32.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SFIXED32")] TypeSfixed32 = 15,
+        /// <summary>
+        ///  Field type sfixed64.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SFIXED64")] TypeSfixed64 = 16,
+        /// <summary>
+        ///  Field type sint32.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SINT32")] TypeSint32 = 17,
+        /// <summary>
+        ///  Field type sint64.
+        /// </summary>
+        [pbr::OriginalName("TYPE_SINT64")] TypeSint64 = 18,
+      }
+
+      /// <summary>
+      ///  Whether a field is optional, required, or repeated.
+      /// </summary>
+      public enum Cardinality {
+        /// <summary>
+        ///  For fields with unknown cardinality.
+        /// </summary>
+        [pbr::OriginalName("CARDINALITY_UNKNOWN")] Unknown = 0,
+        /// <summary>
+        ///  For optional fields.
+        /// </summary>
+        [pbr::OriginalName("CARDINALITY_OPTIONAL")] Optional = 1,
+        /// <summary>
+        ///  For required fields. Proto2 syntax only.
+        /// </summary>
+        [pbr::OriginalName("CARDINALITY_REQUIRED")] Required = 2,
+        /// <summary>
+        ///  For repeated fields.
+        /// </summary>
+        [pbr::OriginalName("CARDINALITY_REPEATED")] Repeated = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Enum type definition.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Enum : pb::IMessage<Enum> {
+    private static readonly pb::MessageParser<Enum> _parser = new pb::MessageParser<Enum>(() => new Enum());
+    public static pb::MessageParser<Enum> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Enum() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Enum(Enum other) : this() {
+      name_ = other.name_;
+      enumvalue_ = other.enumvalue_.Clone();
+      options_ = other.options_.Clone();
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public Enum Clone() {
+      return new Enum(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  Enum type name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "enumvalue" field.</summary>
+    public const int EnumvalueFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.EnumValue> _repeated_enumvalue_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.EnumValue.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> enumvalue_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue>();
+    /// <summary>
+    ///  Enum value definitions.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> Enumvalue {
+      get { return enumvalue_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 4;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Enum);
+    }
+
+    public bool Equals(Enum other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!enumvalue_.Equals(other.enumvalue_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= enumvalue_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      enumvalue_.WriteTo(output, _repeated_enumvalue_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (sourceContext_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(SourceContext);
+      }
+      if (Syntax != 0) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += enumvalue_.CalculateSize(_repeated_enumvalue_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      if (Syntax != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Enum other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      enumvalue_.Add(other.enumvalue_);
+      options_.Add(other.options_);
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      if (other.Syntax != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            enumvalue_.AddEntriesFrom(input, _repeated_enumvalue_codec);
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 34: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 40: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Enum value definition.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class EnumValue : pb::IMessage<EnumValue> {
+    private static readonly pb::MessageParser<EnumValue> _parser = new pb::MessageParser<EnumValue>(() => new EnumValue());
+    public static pb::MessageParser<EnumValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValue(EnumValue other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      options_ = other.options_.Clone();
+    }
+
+    public EnumValue Clone() {
+      return new EnumValue(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  Enum value name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 2;
+    private int number_;
+    /// <summary>
+    ///  Enum value number.
+    /// </summary>
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValue);
+    }
+
+    public bool Equals(EnumValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if(!options_.Equals(other.options_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      hash ^= options_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Number);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      options_.Add(other.options_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 16: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A protocol buffer option, which can be attached to a message, field,
+  ///  enumeration, etc.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Option : pb::IMessage<Option> {
+    private static readonly pb::MessageParser<Option> _parser = new pb::MessageParser<Option>(() => new Option());
+    public static pb::MessageParser<Option> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Option() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Option(Option other) : this() {
+      name_ = other.name_;
+      Value = other.value_ != null ? other.Value.Clone() : null;
+    }
+
+    public Option Clone() {
+      return new Option(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The option's name. For example, `"java_package"`.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private global::Google.Protobuf.WellKnownTypes.Any value_;
+    /// <summary>
+    ///  The option's value. For example, `"com.google.protobuf"`.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Any Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Option);
+    }
+
+    public bool Equals(Option other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (!object.Equals(Value, other.Value)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (value_ != null) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (value_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (value_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Option other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.value_ != null) {
+        if (value_ == null) {
+          value_ = new global::Google.Protobuf.WellKnownTypes.Any();
+        }
+        Value.MergeFrom(other.Value);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            if (value_ == null) {
+              value_ = new global::Google.Protobuf.WellKnownTypes.Any();
+            }
+            input.ReadMessage(value_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
new file mode 100644
index 0000000..d34b560
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
@@ -0,0 +1,99 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Value
+    {
+        /// <summary>
+        /// Convenience method to create a Value message with a string value.
+        /// </summary>
+        /// <param name="value">Value to set for the StringValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForString(string value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StringValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a number value.
+        /// </summary>
+        /// <param name="value">Value to set for the NumberValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForNumber(double value)
+        {
+            return new Value { NumberValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a Boolean value.
+        /// </summary>
+        /// <param name="value">Value to set for the BoolValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForBool(bool value)
+        {
+            return new Value { BoolValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a null initial value.
+        /// </summary>
+        /// <returns>A newly-created Value message a null initial value.</returns>
+        public static Value ForNull()
+        {
+            return new Value { NullValue = 0 };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial list of values.
+        /// </summary>
+        /// <remarks>The values provided are not cloned; the references are copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial list value.</returns>
+        public static Value ForList(params Value[] values)
+        {
+            ProtoPreconditions.CheckNotNull(values, "values");
+            return new Value { ListValue = new ListValue { Values = { values } } };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial struct value
+        /// </summary>
+        /// <remarks>The value provided is not cloned; the reference is copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial struct value.</returns>
+        public static Value ForStruct(Struct value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StructValue = value };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
new file mode 100644
index 0000000..c8867d0
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
@@ -0,0 +1,1057 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/wrappers.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class WrappersReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/wrappers.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static WrappersReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5nb29nbGUvcHJvdG9idWYvd3JhcHBlcnMucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIcCgtEb3VibGVWYWx1ZRINCgV2YWx1ZRgBIAEoASIbCgpGbG9hdFZh",
+            "bHVlEg0KBXZhbHVlGAEgASgCIhsKCkludDY0VmFsdWUSDQoFdmFsdWUYASAB",
+            "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1",
+            "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo",
+            "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS",
+            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJ/",
+            "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAFaKmdpdGh1",
+            "Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy93cmFwcGVyc6ABAfgBAaIC",
+            "A0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.DoubleValue), global::Google.Protobuf.WellKnownTypes.DoubleValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FloatValue), global::Google.Protobuf.WellKnownTypes.FloatValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int64Value), global::Google.Protobuf.WellKnownTypes.Int64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt64Value), global::Google.Protobuf.WellKnownTypes.UInt64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int32Value), global::Google.Protobuf.WellKnownTypes.Int32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt32Value), global::Google.Protobuf.WellKnownTypes.UInt32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BoolValue), global::Google.Protobuf.WellKnownTypes.BoolValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.StringValue), global::Google.Protobuf.WellKnownTypes.StringValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BytesValue), global::Google.Protobuf.WellKnownTypes.BytesValue.Parser, new[]{ "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  Wrapper message for `double`.
+  ///
+  ///  The JSON representation for `DoubleValue` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class DoubleValue : pb::IMessage<DoubleValue> {
+    private static readonly pb::MessageParser<DoubleValue> _parser = new pb::MessageParser<DoubleValue>(() => new DoubleValue());
+    public static pb::MessageParser<DoubleValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DoubleValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DoubleValue(DoubleValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public DoubleValue Clone() {
+      return new DoubleValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private double value_;
+    /// <summary>
+    ///  The double value.
+    /// </summary>
+    public double Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DoubleValue);
+    }
+
+    public bool Equals(DoubleValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0D) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(DoubleValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0D) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            Value = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `float`.
+  ///
+  ///  The JSON representation for `FloatValue` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FloatValue : pb::IMessage<FloatValue> {
+    private static readonly pb::MessageParser<FloatValue> _parser = new pb::MessageParser<FloatValue>(() => new FloatValue());
+    public static pb::MessageParser<FloatValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FloatValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FloatValue(FloatValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public FloatValue Clone() {
+      return new FloatValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private float value_;
+    /// <summary>
+    ///  The float value.
+    /// </summary>
+    public float Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FloatValue);
+    }
+
+    public bool Equals(FloatValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0F) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0F) {
+        output.WriteRawTag(13);
+        output.WriteFloat(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0F) {
+        size += 1 + 4;
+      }
+      return size;
+    }
+
+    public void MergeFrom(FloatValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0F) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 13: {
+            Value = input.ReadFloat();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `int64`.
+  ///
+  ///  The JSON representation for `Int64Value` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int64Value : pb::IMessage<Int64Value> {
+    private static readonly pb::MessageParser<Int64Value> _parser = new pb::MessageParser<Int64Value>(() => new Int64Value());
+    public static pb::MessageParser<Int64Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int64Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int64Value(Int64Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public Int64Value Clone() {
+      return new Int64Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private long value_;
+    /// <summary>
+    ///  The int64 value.
+    /// </summary>
+    public long Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int64Value);
+    }
+
+    public bool Equals(Int64Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0L) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int64Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0L) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `uint64`.
+  ///
+  ///  The JSON representation for `UInt64Value` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class UInt64Value : pb::IMessage<UInt64Value> {
+    private static readonly pb::MessageParser<UInt64Value> _parser = new pb::MessageParser<UInt64Value>(() => new UInt64Value());
+    public static pb::MessageParser<UInt64Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UInt64Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UInt64Value(UInt64Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public UInt64Value Clone() {
+      return new UInt64Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private ulong value_;
+    /// <summary>
+    ///  The uint64 value.
+    /// </summary>
+    public ulong Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UInt64Value);
+    }
+
+    public bool Equals(UInt64Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0UL) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0UL) {
+        output.WriteRawTag(8);
+        output.WriteUInt64(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UInt64Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0UL) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadUInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `int32`.
+  ///
+  ///  The JSON representation for `Int32Value` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int32Value : pb::IMessage<Int32Value> {
+    private static readonly pb::MessageParser<Int32Value> _parser = new pb::MessageParser<Int32Value>(() => new Int32Value());
+    public static pb::MessageParser<Int32Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int32Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int32Value(Int32Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public Int32Value Clone() {
+      return new Int32Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private int value_;
+    /// <summary>
+    ///  The int32 value.
+    /// </summary>
+    public int Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int32Value);
+    }
+
+    public bool Equals(Int32Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int32Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `uint32`.
+  ///
+  ///  The JSON representation for `UInt32Value` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class UInt32Value : pb::IMessage<UInt32Value> {
+    private static readonly pb::MessageParser<UInt32Value> _parser = new pb::MessageParser<UInt32Value>(() => new UInt32Value());
+    public static pb::MessageParser<UInt32Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UInt32Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UInt32Value(UInt32Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public UInt32Value Clone() {
+      return new UInt32Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private uint value_;
+    /// <summary>
+    ///  The uint32 value.
+    /// </summary>
+    public uint Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UInt32Value);
+    }
+
+    public bool Equals(UInt32Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0) {
+        output.WriteRawTag(8);
+        output.WriteUInt32(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UInt32Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadUInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `bool`.
+  ///
+  ///  The JSON representation for `BoolValue` is JSON `true` and `false`.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BoolValue : pb::IMessage<BoolValue> {
+    private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue());
+    public static pb::MessageParser<BoolValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BoolValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BoolValue(BoolValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public BoolValue Clone() {
+      return new BoolValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private bool value_;
+    /// <summary>
+    ///  The bool value.
+    /// </summary>
+    public bool Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BoolValue);
+    }
+
+    public bool Equals(BoolValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != false) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(BoolValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != false) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `string`.
+  ///
+  ///  The JSON representation for `StringValue` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class StringValue : pb::IMessage<StringValue> {
+    private static readonly pb::MessageParser<StringValue> _parser = new pb::MessageParser<StringValue>(() => new StringValue());
+    public static pb::MessageParser<StringValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public StringValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public StringValue(StringValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public StringValue Clone() {
+      return new StringValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private string value_ = "";
+    /// <summary>
+    ///  The string value.
+    /// </summary>
+    public string Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as StringValue);
+    }
+
+    public bool Equals(StringValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(StringValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Value = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `bytes`.
+  ///
+  ///  The JSON representation for `BytesValue` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BytesValue : pb::IMessage<BytesValue> {
+    private static readonly pb::MessageParser<BytesValue> _parser = new pb::MessageParser<BytesValue>(() => new BytesValue());
+    public static pb::MessageParser<BytesValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[8]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BytesValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BytesValue(BytesValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public BytesValue Clone() {
+      return new BytesValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  The bytes value.
+    /// </summary>
+    public pb::ByteString Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BytesValue);
+    }
+
+    public bool Equals(BytesValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteBytes(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(BytesValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Value = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
new file mode 100644
index 0000000..9f620eb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
@@ -0,0 +1,42 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public static partial class WrappersReflection
+    {
+        /// <summary>
+        /// Field number for the single "value" field in all wrapper types.
+        /// </summary>
+        internal const int WrapperValueFieldNumber = Int32Value.ValueFieldNumber;
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WireFormat.cs b/csharp/src/Google.Protobuf/WireFormat.cs
new file mode 100644
index 0000000..faf1e71
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WireFormat.cs
@@ -0,0 +1,104 @@
+#region Copyright notice and license

+// 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.

+#endregion

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// This class is used internally by the Protocol Buffer Library and generated

+    /// message implementations. It is public only for the sake of those generated

+    /// messages. Others should not use this class directly.

+    /// <para>

+    /// This class contains constants and helper functions useful for dealing with

+    /// the Protocol Buffer wire format.

+    /// </para>

+    /// </summary>

+    public static class WireFormat

+    {

+        /// <summary>

+        /// Wire types within protobuf encoding.

+        /// </summary>

+        public enum WireType : uint

+        {

+            /// <summary>

+            /// Variable-length integer.

+            /// </summary>

+            Varint = 0,

+            /// <summary>

+            /// A fixed-length 64-bit value.

+            /// </summary>

+            Fixed64 = 1,

+            /// <summary>

+            /// A length-delimited value, i.e. a length followed by that many bytes of data.

+            /// </summary>

+            LengthDelimited = 2,

+            /// <summary>

+            /// A "start group" value - not supported by this implementation.

+            /// </summary>

+            StartGroup = 3,

+            /// <summary>

+            /// An "end group" value - not supported by this implementation.

+            /// </summary>

+            EndGroup = 4,

+            /// <summary>

+            /// A fixed-length 32-bit value.

+            /// </summary>

+            Fixed32 = 5

+        }

+        

+        private const int TagTypeBits = 3;

+        private const uint TagTypeMask = (1 << TagTypeBits) - 1;

+

+        /// <summary>

+        /// Given a tag value, determines the wire type (lower 3 bits).

+        /// </summary>

+        public static WireType GetTagWireType(uint tag)

+        {

+            return (WireType) (tag & TagTypeMask);

+        }

+

+        /// <summary>

+        /// Given a tag value, determines the field number (the upper 29 bits).

+        /// </summary>

+        public static int GetTagFieldNumber(uint tag)

+        {

+            return (int) tag >> TagTypeBits;

+        }

+

+        /// <summary>

+        /// Makes a tag value given a field number and wire type.

+        /// </summary>

+        public static uint MakeTag(int fieldNumber, WireType wireType)

+        {

+            return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;

+        }        

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/packages.config b/csharp/src/Google.Protobuf/packages.config
new file mode 100644
index 0000000..40b8fd9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="NuSpec.ReferenceGenerator" version="1.4.1" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
+</packages>
\ No newline at end of file
diff --git a/csharp/src/packages/repositories.config b/csharp/src/packages/repositories.config
new file mode 100644
index 0000000..7037941
--- /dev/null
+++ b/csharp/src/packages/repositories.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<repositories>
+  <repository path="..\Google.Protobuf.Test\packages.config" />
+</repositories>
\ No newline at end of file
diff --git a/docs/swift/DesignDoc.md b/docs/swift/DesignDoc.md
new file mode 100644
index 0000000..364a4d3
--- /dev/null
+++ b/docs/swift/DesignDoc.md
@@ -0,0 +1,674 @@
+# Protocol Buffers in Swift
+
+## Objective
+
+This document describes the user-facing API and internal implementation of
+proto2 and proto3 messages in Apple’s Swift programming language.
+
+One of the key goals of protobufs is to provide idiomatic APIs for each
+language. In that vein, **interoperability with Objective-C is a non-goal of
+this proposal.** Protobuf users who need to pass messages between Objective-C
+and Swift code in the same application should use the existing Objective-C proto
+library. The goal of the effort described here is to provide an API for protobuf
+messages that uses features specific to Swift—optional types, algebraic
+enumerated types, value types, and so forth—in a natural way that will delight,
+rather than surprise, users of the language.
+
+## Naming
+
+*   By convention, both typical protobuf message names and Swift structs/classes
+    are `UpperCamelCase`, so for most messages, the name of a message can be the
+    same as the name of its generated type. (However, see the discussion below
+    about prefixes under [Packages](#packages).)
+
+*   Enum cases in protobufs typically are `UPPERCASE_WITH_UNDERSCORES`, whereas
+    in Swift they are `lowerCamelCase` (as of the Swift 3 API design
+    guidelines). We will transform the names to match Swift convention, using
+    a whitelist similar to the Objective-C compiler plugin to handle commonly
+    used acronyms.
+
+*   Typical fields in proto messages are `lowercase_with_underscores`, while in
+    Swift they are `lowerCamelCase`. We will transform the names to match
+    Swift convention by removing the underscores and uppercasing the subsequent
+    letter.
+
+## Swift reserved words
+
+Swift has a large set of reserved words—some always reserved and some
+contextually reserved (that is, they can be used as identifiers in contexts
+where they would not be confused). As of Swift 2.2, the set of always-reserved
+words is:
+
+```
+_, #available, #column, #else, #elseif, #endif, #file, #function, #if, #line,
+#selector, as, associatedtype, break, case, catch, class, continue, default,
+defer, deinit, do, dynamicType, else, enum, extension, fallthrough, false, for,
+func, guard, if, import, in, init, inout, internal, is, let, nil, operator,
+private, protocol, public, repeat, rethrows, return, self, Self, static,
+struct, subscript, super, switch, throw, throws, true, try, typealias, var,
+where, while
+```
+
+The set of contextually reserved words is:
+
+```
+associativity, convenience, dynamic, didSet, final, get, infix, indirect,
+lazy, left, mutating, none, nonmutating, optional, override, postfix,
+precedence, prefix, Protocol, required, right, set, Type, unowned, weak,
+willSet
+```
+
+It is possible to use any reserved word as an identifier by escaping it with
+backticks (for example, ``let `class` = 5``). Other name-mangling schemes would
+require us to transform the names themselves (for example, by appending an
+underscore), which requires us to then ensure that the new name does not collide
+with something else in the same namespace.
+
+While the backtick feature may not be widely known by all Swift developers, a
+small amount of user education can address this and it seems like the best
+approach. We can unconditionally surround all property names with backticks to
+simplify generation.
+
+Some remapping will still be required, though, to avoid collisions between
+generated properties and the names of methods and properties defined in the base
+protocol/implementation of messages.
+
+# Features of Protocol Buffers
+
+This section describes how the features of the protocol buffer syntaxes (proto2
+and proto3) map to features in Swift—what the code generated from a proto will
+look like, and how it will be implemented in the underlying library.
+
+## Packages
+
+Modules are the main form of namespacing in Swift, but they are not declared
+using syntactic constructs like namespaces in C++ or packages in Java. Instead,
+they are tied to build targets in Xcode (or, in the future with open-source
+Swift, declarations in a Swift Package Manager manifest). They also do not
+easily support nesting submodules (Clang module maps support this, but pure
+Swift does not yet provide a way to define submodules).
+
+We will generate types with fully-qualified underscore-delimited names. For
+example, a message `Baz` in package `foo.bar` would generate a struct named
+`Foo_Bar_Baz`. For each fully-qualified proto message, there will be exactly one
+unique type symbol emitted in the generated binary.
+
+Users are likely to balk at the ugliness of underscore-delimited names for every
+generated type. To improve upon this situation, we will add a new string file
+level option, `swift_package_typealias`, that can be added to `.proto` files.
+When present, this will cause `typealias`es to be added to the generated Swift
+messages that replace the package name prefix with the provided string. For
+example, the following `.proto` file:
+
+```protobuf
+option swift_package_typealias = "FBP";
+package foo.bar;
+
+message Baz {
+  // Message fields
+}
+```
+
+would generate the following Swift source:
+
+```swift
+public struct Foo_Bar_Baz {
+  // Message fields and other methods
+}
+
+typealias FBPBaz = Foo_Bar_Baz
+```
+
+It should be noted that this type alias is recorded in the generated
+`.swiftmodule` so that code importing the module can refer to it, but it does
+not cause a new symbol to be generated in the compiled binary (i.e., we do not
+risk compiled size bloat by adding `typealias`es for every type).
+
+Other strategies to handle packages that were considered and rejected can be
+found in [Appendix A](#appendix-a-rejected-strategies-to-handle-packages).
+
+## Messages
+
+Proto messages are natural value types and we will generate messages as structs
+instead of classes. Users will benefit from Swift’s built-in behavior with
+regard to mutability. We will define a `ProtoMessage` protocol that defines the
+common methods and properties for all messages (such as serialization) and also
+lets users treat messages polymorphically. Any shared method implementations
+that do not differ between individual messages can be implemented in a protocol
+extension.
+
+The backing storage itself for fields of a message will be managed by a
+`ProtoFieldStorage` type that uses an internal dictionary keyed by field number,
+and whose values are the value of the field with that number (up-cast to Swift’s
+`Any` type). This class will provide type-safe getters and setters so that
+generated messages can manipulate this storage, and core serialization logic
+will live here as well. Furthermore, factoring the storage out into a separate
+type, rather than inlining the fields as stored properties in the message
+itself, lets us implement copy-on-write efficiently to support passing around
+large messages. (Furthermore, because the messages themselves are value types,
+inlining fields is not possible if the fields are submessages of the same type,
+or a type that eventually includes a submessage of the same type.)
+
+### Required fields (proto2 only)
+
+Required fields in proto2 messages seem like they could be naturally represented
+by non-optional properties in Swift, but this presents some problems/concerns.
+
+Serialization APIs permit partial serialization, which allows required fields to
+remain unset. Furthermore, other language APIs still provide `has*` and `clear*`
+methods for required fields, and knowing whether a property has a value when the
+message is in memory is still useful.
+
+For example, an e-mail draft message may have the “to” address required on the
+wire, but when the user constructs it in memory, it doesn’t make sense to force
+a value until they provide one. We only want to force a value to be present when
+the message is serialized to the wire. Using non-optional properties prevents
+this use case, and makes client usage awkward because the user would be forced
+to select a sentinel or placeholder value for any required fields at the time
+the message was created.
+
+### Default values
+
+In proto2, fields can have a default value specified that may be a value other
+than the default value for its corresponding language type (for example, a
+default value of 5 instead of 0 for an integer). When reading a field that is
+not explicitly set, the user expects to get that value. This makes Swift
+optionals (i.e., `Foo?`) unsuitable for fields in general. Unfortunately, we
+cannot implement our own “enhanced optional” type without severely complicating
+usage (Swift’s use of type inference and its lack of implicit conversions would
+require manual unwrapping of every property value).
+
+Instead, we can use **implicitly unwrapped optionals.** For example, a property
+generated for a field of type `int32` would have Swift type `Int32!`. These
+properties would behave with the following characteristics, which mirror the
+nil-resettable properties used elsewhere in Apple’s SDKs (for example,
+`UIView.tintColor`):
+
+*   Assigning a non-nil value to a property sets the field to that value.
+*   Assigning nil to a property clears the field (its internal representation is
+    nilled out).
+*   Reading the value of a property returns its value if it is set, or returns
+    its default value if it is not set. Reading a property never returns nil.
+
+The final point in the list above implies that the optional cannot be checked to
+determine if the field is set to a value other than its default: it will never
+be nil. Instead, we must provide `has*` methods for each field to allow the user
+to check this. These methods will be public in proto2. In proto3, these methods
+will be private (if generated at all), since the user can test the returned
+value against the zero value for that type.
+
+### Autocreation of nested messages
+
+For convenience, dotting into an unset field representing a nested message will
+return an instance of that message with default values. As in the Objective-C
+implementation, this does not actually cause the field to be set until the
+returned message is mutated. Fortunately, thanks to the way mutability of value
+types is implemented in Swift, the language automatically handles the
+reassignment-on-mutation for us. A static singleton instance containing default
+values can be associated with each message that can be returned when reading, so
+copies are only made by the Swift runtime when mutation occurs. For example,
+given the following proto:
+
+```protobuf
+message Node {
+  Node child = 1;
+  string value = 2 [default = "foo"];
+}
+```
+
+The following Swift code would act as commented, where setting deeply nested
+properties causes the copies and mutations to occur as the assignment statement
+is unwound:
+
+```swift
+var node = Node()
+
+let s = node.child.child.value
+// 1. node.child returns the "default Node".
+// 2. Reading .child on the result of (1) returns the same default Node.
+// 3. Reading .value on the result of (2) returns the default value "foo".
+
+node.child.child.value = "bar"
+// 4. Setting .value on the default Node causes a copy to be made and sets
+//    the property on that copy. Subsequently, the language updates the
+//    value of "node.child.child" to point to that copy.
+// 5. Updating "node.child.child" in (4) requires another copy, because
+//    "node.child" was also the instance of the default node. The copy is
+//    assigned back to "node.child".
+// 6. Setting "node.child" in (5) is a simple value reassignment, since
+//    "node" is a mutable var.
+```
+
+In other words, the generated messages do not internally have to manage parental
+relationships to backfill the appropriate properties on mutation. Swift provides
+this for free.
+
+## Scalar value fields
+
+Proto scalar value fields will map to Swift types in the following way:
+
+.proto Type | Swift Type
+----------- | -------------------
+`double`    | `Double`
+`float`     | `Float`
+`int32`     | `Int32`
+`int64`     | `Int64`
+`uint32`    | `UInt32`
+`uint64`    | `UInt64`
+`sint32`    | `Int32`
+`sint64`    | `Int64`
+`fixed32`   | `UInt32`
+`fixed64`   | `UInt64`
+`sfixed32`  | `Int32`
+`sfixed64`  | `Int64`
+`bool`      | `Bool`
+`string`    | `String`
+`bytes`     | `Foundation.NSData`
+
+The proto spec defines a number of integral types that map to the same Swift
+type; for example, `intXX`, `sintXX`, and `sfixedXX` are all signed integers,
+and `uintXX` and `fixedXX` are both unsigned integers. No other language
+implementation distinguishes these further, so we do not do so either. The
+rationale is that the various types only serve to distinguish how the value is
+**encoded on the wire**; once loaded in memory, the user is not concerned about
+these variations.
+
+Swift’s lack of implicit conversions among types will make it slightly annoying
+to use these types in a context expecting an `Int`, or vice-versa, but since
+this is a data-interchange format with explicitly-sized fields, we should not
+hide that information from the user. Users will have to explicitly write
+`Int(message.myField)`, for example.
+
+## Embedded message fields
+
+Embedded message fields can be represented using an optional variable of the
+generated message type. Thus, the message
+
+```protobuf
+message Foo {
+  Bar bar = 1;
+}
+```
+
+would be represented in Swift as
+
+```swift
+public struct Foo: ProtoMessage {
+  public var bar: Bar! {
+    get { ... }
+    set { ... }
+  }
+}
+```
+
+If the user explicitly sets `bar` to nil, or if it was never set when read from
+the wire, retrieving the value of `bar` would return a default, statically
+allocated instance of `Bar` containing default values for its fields. This
+achieves the desired behavior for default values in the same way that scalar
+fields are designed, and also allows users to deep-drill into complex object
+graphs to get or set fields without checking for nil at each step.
+
+## Enum fields
+
+The design and implementation of enum fields will differ somewhat drastically
+depending on whether the message being generated is a proto2 or proto3 message.
+
+### proto2 enums
+
+For proto2, we do not need to be concerned about unknown enum values, so we can
+use the simple raw-value enum syntax provided by Swift. So the following enum in
+proto2:
+
+```protobuf
+enum ContentType {
+  TEXT = 0;
+  IMAGE = 1;
+}
+```
+
+would become this Swift enum:
+
+```swift
+public enum ContentType: Int32, NilLiteralConvertible {
+  case text = 0
+  case image = 1
+
+  public init(nilLiteral: ()) {
+    self = .text
+  }
+}
+```
+
+See below for the discussion about `NilLiteralConvertible`.
+
+### proto3 enums
+
+For proto3, we need to be able to preserve unknown enum values that may come
+across the wire so that they can be written back if unmodified. We can
+accomplish this in Swift by using a case with an associated value for unknowns.
+So the following enum in proto3:
+
+```protobuf
+enum ContentType {
+  TEXT = 0;
+  IMAGE = 1;
+}
+```
+
+would become this Swift enum:
+
+```swift
+public enum ContentType: RawRepresentable, NilLiteralConvertible {
+  case text
+  case image
+  case UNKNOWN_VALUE(Int32)
+
+  public typealias RawValue = Int32
+
+  public init(nilLiteral: ()) {
+    self = .text
+  }
+
+  public init(rawValue: RawValue) {
+    switch rawValue {
+      case 0: self = .text
+      case 1: self = .image
+      default: self = .UNKNOWN_VALUE(rawValue)
+  }
+
+  public var rawValue: RawValue {
+    switch self {
+      case .text: return 0
+      case .image: return 1
+      case .UNKNOWN_VALUE(let value): return value
+    }
+  }
+}
+```
+
+Note that the use of a parameterized case prevents us from inheriting from the
+raw `Int32` type; Swift does not allow an enum with a raw type to have cases
+with arguments. Instead, we must implement the raw value initializer and
+computed property manually. The `UNKNOWN_VALUE` case is explicitly chosen to be
+"ugly" so that it stands out and does not conflict with other possible case
+names.
+
+Using this approach, proto3 consumers must always have a default case or handle
+the `.UNKNOWN_VALUE` case to satisfy case exhaustion in a switch statement; the
+Swift compiler considers it an error if switch statements are not exhaustive.
+
+### NilLiteralConvertible conformance
+
+This is required to clean up the usage of enum-typed properties in switch
+statements. Unlike other field types, enum properties cannot be
+implicitly-unwrapped optionals without requiring that uses in switch statements
+be explicitly unwrapped. For example, if we consider a message with the enum
+above, this usage will fail to compile:
+
+```swift
+// Without NilLiteralConvertible conformance on ContentType
+public struct SomeMessage: ProtoMessage {
+  public var contentType: ContentType! { ... }
+}
+
+// ERROR: no case named text or image
+switch someMessage.contentType {
+  case .text: { ... }
+  case .image: { ... }
+}
+```
+
+Even though our implementation guarantees that `contentType` will never be nil,
+if it is an optional type, its cases would be `some` and `none`, not the cases
+of the underlying enum type. In order to use it in this context, the user must
+write `someMessage.contentType!` in their switch statement.
+
+Making the enum itself `NilLiteralConvertible` permits us to make the property
+non-optional, so the user can still set it to nil to clear it (i.e., reset it to
+its default value), while eliminating the need to explicitly unwrap it in a
+switch statement.
+
+```swift
+// With NilLiteralConvertible conformance on ContentType
+public struct SomeMessage: ProtoMessage {
+  // Note that the property type is no longer optional
+  public var contentType: ContentType { ... }
+}
+
+// OK: Compiles and runs as expected
+switch someMessage.contentType {
+  case .text: { ... }
+  case .image: { ... }
+}
+
+// The enum can be reset to its default value this way
+someMessage.contentType = nil
+```
+
+One minor oddity with this approach is that nil will be auto-converted to the
+default value of the enum in any context, not just field assignment. In other
+words, this is valid:
+
+```swift
+func foo(contentType: ContentType) { ... }
+foo(nil) // Inside foo, contentType == .text
+```
+
+That being said, the advantage of being able to simultaneously support
+nil-resettability and switch-without-unwrapping outweighs this side effect,
+especially if appropriately documented. It is our hope that a new form of
+resettable properties will be added to Swift that eliminates this inconsistency.
+Some community members have already drafted or sent proposals for review that
+would benefit our designs:
+
+*   [SE-0030: Property Behaviors]
+    (https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md)
+*   [Drafted: Resettable Properties]
+    (https://github.com/patters/swift-evolution/blob/master/proposals/0000-resettable-properties.md)
+
+### Enum aliases
+
+The `allow_alias` option in protobuf slightly complicates the use of Swift enums
+to represent that type, because raw values of cases in an enum must be unique.
+Swift lets us define static variables in an enum that alias actual cases. For
+example, the following protobuf enum:
+
+```protobuf
+enum Foo {
+  option allow_alias = true;
+  BAR = 0;
+  BAZ = 0;
+}
+```
+
+will be represented in Swift as:
+
+```swift
+public enum Foo: Int32, NilLiteralConvertible {
+  case bar = 0
+  static public let baz = bar
+
+  // ... etc.
+}
+
+// Can still use .baz shorthand to reference the alias in contexts
+// where the type is inferred
+```
+
+That is, we use the first name as the actual case and use static variables for
+the other aliases. One drawback to this approach is that the static aliases
+cannot be used as cases in a switch statement (the compiler emits the error
+*“Enum case ‘baz’ not found in type ‘Foo’”*). However, in our own code bases,
+there are only a few places where enum aliases are not mere renamings of an
+older value, but they also don’t appear to be the type of value that one would
+expect to switch on (for example, a group of named constants representing
+metrics rather than a set of options), so this restriction is not significant.
+
+This strategy also implies that changing the name of an enum and adding the old
+name as an alias below the new name will be a breaking change in the generated
+Swift code.
+
+## Oneof types
+
+The `oneof` feature represents a “variant/union” data type that maps nicely to
+Swift enums with associated values (algebraic types). These fields can also be
+accessed independently though, and, specifically in the case of proto2, it’s
+reasonable to expect access to default values when accessing a field that is not
+explicitly set.
+
+Taking all this into account, we can represent a `oneof` in Swift with two sets
+of constructs:
+
+*   Properties in the message that correspond to the `oneof` fields.
+*   A nested enum named after the `oneof` and which provides the corresponding
+    field values as case arguments.
+
+This approach fulfills the needs of proto consumers by providing a
+Swift-idiomatic way of simultaneously checking which field is set and accessing
+its value, providing individual properties to access the default values
+(important for proto2), and safely allows a field to be moved into a `oneof`
+without breaking clients.
+
+Consider the following proto:
+
+```protobuf
+message MyMessage {
+  oneof record {
+    string name = 1 [default = "unnamed"];
+    int32 id_number = 2 [default = 0];
+  }
+}
+```
+
+In Swift, we would generate an enum, a property for that enum, and properties
+for the fields themselves:
+
+```swift
+public struct MyMessage: ProtoMessage {
+  public enum Record: NilLiteralConvertible {
+    case name(String)
+    case idNumber(Int32)
+    case NOT_SET
+
+    public init(nilLiteral: ()) { self = .NOT_SET }
+  }
+
+  // This is the "Swifty" way of accessing the value
+  public var record: Record { ... }
+
+  // Direct access to the underlying fields
+  public var name: String! { ... }
+  public var idNumber: Int32! { ... }
+}
+```
+
+This makes both usage patterns possible:
+
+```swift
+// Usage 1: Case-based dispatch
+switch message.record {
+  case .name(let name):
+    // Do something with name if it was explicitly set
+  case .idNumber(let id):
+    // Do something with id_number if it was explicitly set
+  case .NOT_SET:
+    // Do something if it’s not set
+}
+
+// Usage 2: Direct access for default value fallback
+// Sets the label text to the name if it was explicitly set, or to
+// "unnamed" (the default value for the field) if id_number was set
+// instead
+let myLabel = UILabel()
+myLabel.text = message.name
+```
+
+As with proto enums, the generated `oneof` enum conforms to
+`NilLiteralConvertible` to avoid switch statement issues. Setting the property
+to nil will clear it (i.e., reset it to `NOT_SET`).
+
+## Unknown Fields (proto2 only)
+
+To be written.
+
+## Extensions (proto2 only)
+
+To be written.
+
+## Reflection and Descriptors
+
+We will not include reflection or descriptors in the first version of the Swift
+library. The use cases for reflection on mobile are not as strong and the static
+data to represent the descriptors would add bloat when we wish to keep the code
+size small.
+
+In the future, we will investigate whether they can be included as extensions
+which might be able to be excluded from a build and/or automatically dead
+stripped by the compiler if they are not used.
+
+## Appendix A: Rejected strategies to handle packages
+
+### Each package is its own Swift module
+
+Each proto package could be declared as its own Swift module, replacing dots
+with underscores (e.g., package `foo.bar` becomes module `Foo_Bar`). Then, users
+would simply import modules containing whatever proto modules they want to use
+and refer to the generated types by their short names.
+
+**This solution is simply not possible, however.** Swift modules cannot
+circularly reference each other, but there is no restriction against proto
+packages doing so. Circular imports are forbidden (e.g., `foo.proto` importing
+`bar.proto` importing `foo.proto`), but nothing prevents package `foo` from
+using a type in package `bar` which uses a different type in package `foo`, as
+long as there is no import cycle. If these packages were generated as Swift
+modules, then `Foo` would contain an `import Bar` statement and `Bar` would
+contain an `import Foo` statement, and there is no way to compile this.
+
+### Ad hoc namespacing with structs
+
+We can “fake” namespaces in Swift by declaring empty structs with private
+initializers. Since modules are constructed based on compiler arguments, not by
+syntactic constructs, and because there is no pure Swift way to define
+submodules (even though Clang module maps support this), there is no
+source-drive way to group generated code into namespaces aside from this
+approach.
+
+Types can be added to those intermediate package structs using Swift extensions.
+For example, a message `Baz` in package `foo.bar` could be represented in Swift
+as follows:
+
+```swift
+public struct Foo {
+  private init() {}
+}
+
+public extension Foo {
+  public struct Bar {
+    private init() {}
+  }
+}
+
+public extension Foo.Bar {
+  public struct Baz {
+    // Message fields and other methods
+  }
+}
+
+let baz = Foo.Bar.Baz()
+```
+
+Each of these constructs would actually be defined in a separate file; Swift
+lets us keep them separate and add multiple structs to a single “namespace”
+through extensions.
+
+Unfortunately, these intermediate structs generate symbols of their own
+(metatype information in the data segment). This becomes problematic if multiple
+build targets contain Swift sources generated from different messages in the
+same package. At link time, these symbols would collide, resulting in multiple
+definition errors.
+
+This approach also has the disadvantage that there is no automatic “short” way
+to refer to the generated messages at the deepest nesting levels; since this use
+of structs is a hack around the lack of namespaces, there is no equivalent to
+import (Java) or using (C++) to simplify this. Users would have to declare type
+aliases to make this cleaner, or we would have to generate them for users.
diff --git a/docs/third_party.md b/docs/third_party.md
new file mode 100644
index 0000000..69ed6a3
--- /dev/null
+++ b/docs/third_party.md
@@ -0,0 +1,147 @@
+# Third-Party Add-ons for Protocol Buffers
+
+This page lists code related to Protocol Buffers which is developed and maintained by third parties.  You may find this code useful, but note that **these projects are not affiliated with or endorsed by Google (unless explicitly marked)**; try them at your own risk.  Also note that many projects here are in the early stages of development and not production-ready.
+
+If you have a project that should be listed here, please [send us a pull request](https://github.com/google/protobuf/pulls) to update this page.
+
+## Programming Languages
+
+These are projects we know about implementing Protocol Buffers for other programming languages:
+* Action Script: http://code.google.com/p/protobuf-actionscript3/
+* Action Script: https://code.google.com/p/protoc-gen-as3/
+* Action Script: https://github.com/matrix3d/JProtoc
+* C: https://github.com/protobuf-c/protobuf-c
+* C: http://koti.kapsi.fi/jpa/nanopb/
+* C: https://github.com/cloudwu/pbc/
+* C: https://github.com/haberman/upb/wiki
+* C: https://github.com/squidfunk/protobluff
+* C++: https://github.com/google/protobuf (Google-official implementation)
+* C/C++: http://spbc.sf.net/
+* C#: http://code.google.com/p/protobuf-csharp-port
+* C#: http://code.google.com/p/protosharp/
+* C#: https://silentorbit.com/protobuf/
+* C#/.NET/WCF/VB: http://code.google.com/p/protobuf-net/
+* Clojure: http://github.com/ninjudd/clojure-protobuf
+* Common Lisp: http://www.prism.gatech.edu/~ndantam3/docs/s-protobuf/
+* Common Lisp: http://github.com/brown/protobuf
+* D: https://github.com/msoucy/dproto
+* D: http://256.makerslocal.org/wiki/index.php/ProtocolBuffer
+* D: https://github.com/opticron/ProtocolBuffer
+* Dart: https://github.com/dart-lang/dart-protobuf (runtime) https://github.com/dart-lang/dart-protoc-plugin (code generator)
+* Delphi: http://sourceforge.net/projects/protobuf-delphi/
+* Delphi: http://fundementals.sourceforge.net/dl.html
+* Elixir: https://github.com/jeremyong/exprotoc
+* Erlang: http://github.com/ngerakines/erlang_protobuffs/tree/master
+* Erlang: http://piqi.org/
+* Erlang: https://code.google.com/p/protoc-gen-erl/
+* Erlang: https://github.com/basho/erlang_protobuffs
+* Go: https://github.com/golang/protobuf (Google-official implementation)
+* Go: http://code.google.com/p/goprotobuf/
+* Go: https://github.com/akunspy/gopbuf
+* Haskell: http://hackage.haskell.org/package/hprotoc
+* Haxe: https://github.com/Atry/protoc-gen-haxe
+* Java: https://github.com/google/protobuf (Google-official implementation)
+* Java/Android: https://github.com/square/wire
+* Java ME: http://code.google.com/p/protobuf-javame/
+* Java ME: http://swingme.sourceforge.net/encode.shtml
+* Java ME: http://github.com/ponderingpanda/protobuf-j2me
+* Java ME: http://code.google.com/p/protobuf-j2me/
+* Javascript: http://code.google.com/p/protobuf-js/
+* Javascript: http://github.com/sirikata/protojs
+* Javascript: https://github.com/dcodeIO/ProtoBuf.js
+* Javascript: http://code.google.com/p/protobuf-for-node/
+* Javascript: http://code.google.com/p/protostuff/
+* Julia: https://github.com/tanmaykm/ProtoBuf.jl
+* Lua: http://code.google.com/p/protoc-gen-lua/
+* Lua: http://github.com/indygreg/lua-protobuf
+* Lua: https://github.com/Neopallium/lua-pb
+* Matlab: http://code.google.com/p/protobuf-matlab/
+* Mercury: http://code.google.com/p/protobuf-mercury/
+* Objective C: http://code.google.com/p/protobuf-objc/
+* Objective C: https://github.com/alexeyxo/protobuf-objc
+* OCaml: http://piqi.org/
+* Perl: http://groups.google.com/group/protobuf-perl
+* Perl: http://search.cpan.org/perldoc?Google::ProtocolBuffers
+* Perl/XS: http://code.google.com/p/protobuf-perlxs/
+* PHP: http://code.google.com/p/pb4php/
+* PHP: https://github.com/allegro/php-protobuf/
+* PHP: https://github.com/chobie/php-protocolbuffers
+* PHP: http://drslump.github.com/Protobuf-PHP
+* Prolog: http://www.swi-prolog.org/pldoc/package/protobufs.html
+* Python: https://github.com/google/protobuf (Google-official implementation)
+* Python: http://eigenein.github.com/protobuf/
+* R: http://cran.r-project.org/package=RProtoBuf
+* Ruby: http://code.google.com/p/ruby-protobuf/
+* Ruby: http://github.com/mozy/ruby-protocol-buffers
+* Ruby: https://github.com/bmizerany/beefcake/tree/master/lib/beefcake
+* Ruby: https://github.com/localshred/protobuf
+* Rust: https://github.com/stepancheg/rust-protobuf/
+* Scala: http://github.com/jeffplaisance/scala-protobuf
+* Scala: http://code.google.com/p/protobuf-scala
+* Scala: https://github.com/SandroGrzicic/ScalaBuff
+* Scala: http://trueaccord.github.io/ScalaPB/
+* Swift: https://github.com/alexeyxo/protobuf-swift
+* Vala: https://launchpad.net/protobuf-vala
+* Visual Basic: http://code.google.com/p/protobuf-net/
+
+## RPC Implementations
+
+GRPC (http://www.grpc.io/) is Google's RPC implementation for Protocol Buffers. There are other third-party RPC implementations as well.  Some of these actually work with Protocol Buffers service definitions (defined using the `service` keyword in `.proto` files) while others just use Protocol Buffers message objects.
+
+* https://github.com/grpc/grpc (C++, Node.js, Python, Ruby, Objective-C, PHP, C#, Google-official implementation)
+* http://zeroc.com/ice.html (Multiple languages)
+* http://code.google.com/p/protobuf-net/ (C#/.NET/WCF/VB)
+* https://launchpad.net/txprotobuf/ (Python)
+* https://github.com/modeswitch/protobuf-rpc (Python)
+* http://code.google.com/p/protobuf-socket-rpc/ (Java, Python)
+* http://code.google.com/p/proto-streamer/ (Java)
+* http://code.google.com/p/server1/ (C++)
+* http://deltavsoft.com/RcfUserGuide/Protobufs (C++)
+* http://code.google.com/p/protobuf-mina-rpc/ (Python client, Java server)
+* http://code.google.com/p/casocklib/ (C++)
+* http://code.google.com/p/cxf-protobuf/ (Java)
+* http://code.google.com/p/protobuf-remote/ (C++/C#)
+* http://code.google.com/p/protobuf-rpc-pro/ (Java)
+* https://code.google.com/p/protorpc/ (Go/C++)
+* https://code.google.com/p/eneter-protobuf-serializer/ (Java/.NET)
+* http://www.deltavsoft.com/RCFProto.html (C++/Java/Python/C#)
+* https://github.com/robbinfan/claire-protorpc (C++)
+* https://github.com/BaiduPS/sofa-pbrpc (C++)
+* https://github.com/ebencheung/arab (C++)
+* http://code.google.com/p/protobuf-csharp-rpc/ (C#)
+* https://github.com/thesamet/rpcz (C++/Python, based on ZeroMQ)
+* https://github.com/w359405949/libmaid (C++, Python)
+* https://github.com/madwyn/libpbrpc (C++)
+
+## Other Utilities
+
+There are miscellaneous other things you may find useful as a Protocol Buffers developer.
+
+* [NetBeans IDE plugin](http://code.google.com/p/protobuf-netbeans-plugin/)
+* [Wireshark/Ethereal packet sniffer plugin](http://code.google.com/p/protobuf-wireshark/)
+* [Alternate encodings (JSON, XML, HTML) for Java protobufs](http://code.google.com/p/protobuf-java-format/)
+* [Another JSON encoder/decoder for Java](https://github.com/sijuv/protobuf-codec)
+* [Editor for serialized protobufs](http://code.google.com/p/protobufeditor/)
+* [Intellij IDEA plugin](http://github.com/nnmatveev/idea-plugin-protobuf)
+* [TextMate syntax highlighting](http://github.com/michaeledgar/protobuf-tmbundle)
+* [Oracle PL SQL plugin](http://code.google.com/p/protocol-buffer-plsql/)
+* [Eclipse editor for protobuf (from Google)](http://code.google.com/p/protobuf-dt/)
+* [C++ Builder compatible protobuf](https://github.com/saadware/protobuf-cppbuilder)
+* Maven Protocol Compiler Plugin
+    * https://github.com/sergei-ivanov/maven-protoc-plugin/
+    * http://igor-petruk.github.com/protobuf-maven-plugin/
+    * http://code.google.com/p/maven-protoc-plugin/
+    * https://github.com/os72/protoc-jar-maven-plugin
+* [Documentation generator plugin (Markdown/HTML/DocBook/...)](https://github.com/estan/protoc-gen-doc)
+* [DocBook generator for .proto files](http://code.google.com/p/protoc-gen-docbook/)
+* [Protobuf for nginx module](https://github.com/dbcode/protobuf-nginx/)
+* [RSpec matchers and Cucumber step defs for testing Protocol Buffers](https://github.com/connamara/protobuf_spec)
+* [Sbt plugin for Protocol Buffers](https://github.com/Atry/sbt-cppp)
+* [Gradle Protobuf Plugin](https://github.com/aantono/gradle-plugin-protobuf)
+* [Multi-platform executable JAR and Java API for protoc](https://github.com/os72/protoc-jar)
+* [Python scripts to convert between Protocol Buffers and JSON](https://github.com/NextTuesday/py-pb-converters)
+* [Visual Studio Language Service support for Protocol Buffers](http://visualstudiogallery.msdn.microsoft.com/4bc0f38c-b058-4e05-ae38-155e053c19c5)
+* [C++ library for serialization/de-serialization between Protocol Buffers and JSON.](https://github.com/yinqiwen/pbjson)
+* [ProtoBuf with Java EE7 Expression Language 3.0; pure Java ProtoBuf Parser and Builder.](https://github.com/protobufel/protobuf-el)
+* [Notepad++ Syntax Highlighting for .proto files](https://github.com/chai2010/notepadplus-protobuf)
+* [Linter for .proto files](https://github.com/ckaznocha/protoc-gen-lint)
diff --git a/editors/proto.vim b/editors/proto.vim
index 7cd1dbf..7f1aeb7 100644
--- a/editors/proto.vim
+++ b/editors/proto.vim
@@ -54,10 +54,10 @@
 syn cluster pbCommentGrp contains=pbTodo
 
 syn keyword pbSyntax     syntax import option
-syn keyword pbStructure  package message group
+syn keyword pbStructure  package message group oneof
 syn keyword pbRepeat     optional required repeated
 syn keyword pbDefault    default
-syn keyword pbExtend     extend extensions to max
+syn keyword pbExtend     extend extensions to max reserved
 syn keyword pbRPC        service rpc returns
 
 syn keyword pbType      int32 int64 uint32 uint64 sint32 sint64
diff --git a/editors/protobuf-mode.el b/editors/protobuf-mode.el
index 09aecc9..f615a0a 100644
--- a/editors/protobuf-mode.el
+++ b/editors/protobuf-mode.el
@@ -106,7 +106,7 @@
 ;; cc-mode.  So, we approximate as best we can.
 
 (c-lang-defconst c-type-list-kwds
-  protobuf '("extensions" "to"))
+  protobuf '("extensions" "to" "reserved"))
 
 (c-lang-defconst c-typeless-decl-kwds
   protobuf '("extend" "rpc" "option" "returns"))
diff --git a/examples/AddPerson.java b/examples/AddPerson.java
index ca5ac27..c262ab7 100644
--- a/examples/AddPerson.java
+++ b/examples/AddPerson.java
@@ -50,7 +50,7 @@
         stdout.println("Unknown phone type.  Using default.");
       }
 
-      person.addPhone(phoneNumber);
+      person.addPhones(phoneNumber);
     }
 
     return person.build();
@@ -80,7 +80,7 @@
     }
 
     // Add an address.
-    addressBook.addPerson(
+    addressBook.addPeople(
       PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
                        System.out));
 
diff --git a/examples/ListPeople.java b/examples/ListPeople.java
index b2f153a..7892430 100644
--- a/examples/ListPeople.java
+++ b/examples/ListPeople.java
@@ -9,14 +9,14 @@
 class ListPeople {
   // Iterates though all people in the AddressBook and prints info about them.
   static void Print(AddressBook addressBook) {
-    for (Person person: addressBook.getPersonList()) {
+    for (Person person: addressBook.getPeopleList()) {
       System.out.println("Person ID: " + person.getId());
       System.out.println("  Name: " + person.getName());
-      if (person.hasEmail()) {
+      if (!person.getEmail().isEmpty()) {
         System.out.println("  E-mail address: " + person.getEmail());
       }
 
-      for (Person.PhoneNumber phoneNumber : person.getPhoneList()) {
+      for (Person.PhoneNumber phoneNumber : person.getPhonesList()) {
         switch (phoneNumber.getType()) {
           case MOBILE:
             System.out.print("  Mobile phone #: ");
diff --git a/examples/Makefile b/examples/Makefile
index 8dc9083..51f1342 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -5,6 +5,8 @@
 all: cpp java python
 
 cpp:    add_person_cpp    list_people_cpp
+go:     add_person_go     list_people_go
+gotest: add_person_gotest list_people_gotest
 java:   add_person_java   list_people_java
 python: add_person_python list_people_python
 
@@ -13,6 +15,8 @@
 	rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
 	rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
 	rm -f *.pyc
+	rm -f protoc_middleman_go tutorial/*.pb.go add_person_go list_people_go
+	rmdir tutorial 2>/dev/null || true
 	rmdir com/example/tutorial 2>/dev/null || true
 	rmdir com/example 2>/dev/null || true
 	rmdir com 2>/dev/null || true
@@ -21,6 +25,11 @@
 	protoc --cpp_out=. --java_out=. --python_out=. addressbook.proto
 	@touch protoc_middleman
 
+protoc_middleman_go: addressbook.proto
+	mkdir tutorial # make directory for go package
+	protoc --go_out=tutorial addressbook.proto
+	@touch protoc_middleman_go
+
 add_person_cpp: add_person.cc protoc_middleman
 	pkg-config --cflags protobuf  # fails if protobuf is not installed
 	c++ add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
@@ -29,6 +38,18 @@
 	pkg-config --cflags protobuf  # fails if protobuf is not installed
 	c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`
 
+add_person_go: add_person.go protoc_middleman_go
+	go build -o add_person_go add_person.go
+
+add_person_gotest: add_person_test.go add_person_go
+	go test add_person.go add_person_test.go
+
+list_people_go: list_people.go protoc_middleman_go
+	go build -o list_people_go list_people.go
+
+list_people_gotest: list_people.go list_people_go
+	go test list_people.go list_people_test.go
+
 javac_middleman: AddPerson.java ListPeople.java protoc_middleman
 	javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
 	@touch javac_middleman
diff --git a/examples/README.txt b/examples/README.txt
index f5530a5..b33f841 100644
--- a/examples/README.txt
+++ b/examples/README.txt
@@ -27,3 +27,28 @@
 * Note that on some platforms you may have to edit the Makefile and remove
 "-lpthread" from the linker commands (perhaps replacing it with something else).
 We didn't do this automatically because we wanted to keep the example simple.
+
+## Go ##
+
+The Go example requires a plugin to the protocol buffer compiler, so it is not
+build with all the other examples.  See:
+  https://github.com/golang/protobuf
+for more information about Go protocol buffer support.
+
+First, install the Protocol Buffers compiler (protoc).
+Then, install the Go Protocol Buffers plugin
+($GOPATH/bin must be in your $PATH for protoc to find it):
+  go get github.com/golang/protobuf/protoc-gen-go
+
+Build the Go samples in this directory with "make go".  This creates the
+following executable files in the current directory:
+  add_person_go      list_people_go
+To run the example:
+  ./add_person_go addressbook.data
+to add a person to the protocol buffer encoded file addressbook.data.  The file
+is created if it does not exist.  To view the data, run:
+  ./list_people_go addressbook.data
+
+Observe that the C++, Python, and Java examples in this directory run in a
+similar way and can view/modify files created by the Go example and vice
+versa.
diff --git a/examples/add_person.cc b/examples/add_person.cc
index b9ca44f..9bec4b3 100644
--- a/examples/add_person.cc
+++ b/examples/add_person.cc
@@ -32,7 +32,7 @@
       break;
     }
 
-    tutorial::Person::PhoneNumber* phone_number = person->add_phone();
+    tutorial::Person::PhoneNumber* phone_number = person->add_phones();
     phone_number->set_number(number);
 
     cout << "Is this a mobile, home, or work phone? ";
@@ -77,7 +77,7 @@
   }
 
   // Add an address.
-  PromptForAddress(address_book.add_person());
+  PromptForAddress(address_book.add_people());
 
   {
     // Write the new address book back to disk.
diff --git a/examples/add_person.go b/examples/add_person.go
new file mode 100644
index 0000000..4f2e7f7
--- /dev/null
+++ b/examples/add_person.go
@@ -0,0 +1,133 @@
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func promptForAddress(r io.Reader) (*pb.Person, error) {
+	// A protocol buffer can be created like any struct.
+	p := &pb.Person{}
+
+	rd := bufio.NewReader(r)
+	fmt.Print("Enter person ID number: ")
+	// An int32 field in the .proto file is represented as an int32 field
+	// in the generated Go struct.
+	if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil {
+		return p, err
+	}
+
+	fmt.Print("Enter name: ")
+	name, err := rd.ReadString('\n')
+	if err != nil {
+		return p, err
+	}
+	// A string field in the .proto file results in a string field in Go.
+	// We trim the whitespace because rd.ReadString includes the trailing
+	// newline character in its output.
+	p.Name = strings.TrimSpace(name)
+
+	fmt.Print("Enter email address (blank for none): ")
+	email, err := rd.ReadString('\n')
+	if err != nil {
+		return p, err
+	}
+	p.Email = strings.TrimSpace(email)
+
+	for {
+		fmt.Print("Enter a phone number (or leave blank to finish): ")
+		phone, err := rd.ReadString('\n')
+		if err != nil {
+			return p, err
+		}
+		phone = strings.TrimSpace(phone)
+		if phone == "" {
+			break
+		}
+		// The PhoneNumber message type is nested within the Person
+		// message in the .proto file.  This results in a Go struct
+		// named using the name of the parent prefixed to the name of
+		// the nested message.  Just as with pb.Person, it can be
+		// created like any other struct.
+		pn := &pb.Person_PhoneNumber{
+			Number: phone,
+		}
+
+		fmt.Print("Is this a mobile, home, or work phone? ")
+		ptype, err := rd.ReadString('\n')
+		if err != nil {
+			return p, err
+		}
+		ptype = strings.TrimSpace(ptype)
+
+		// A proto enum results in a Go constant for each enum value.
+		switch ptype {
+		case "mobile":
+			pn.Type = pb.Person_MOBILE
+		case "home":
+			pn.Type = pb.Person_HOME
+		case "work":
+			pn.Type = pb.Person_WORK
+		default:
+			fmt.Printf("Unknown phone type %q.  Using default.\n", ptype)
+		}
+
+		// A repeated proto field maps to a slice field in Go.  We can
+		// append to it like any other slice.
+		p.Phones = append(p.Phones, pn)
+	}
+
+	return p, nil
+}
+
+// Main reads the entire address book from a file, adds one person based on
+// user input, then writes it back out to the same file.
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatalf("Usage:  %s ADDRESS_BOOK_FILE\n", os.Args[0])
+	}
+	fname := os.Args[1]
+
+	// Read the existing address book.
+	in, err := ioutil.ReadFile(fname)
+	if err != nil {
+		if os.IsNotExist(err) {
+			fmt.Printf("%s: File not found.  Creating new file.\n", fname)
+		} else {
+			log.Fatalln("Error reading file:", err)
+		}
+	}
+
+	// [START marshal_proto]
+	book := &pb.AddressBook{}
+	// [START_EXCLUDE]
+	if err := proto.Unmarshal(in, book); err != nil {
+		log.Fatalln("Failed to parse address book:", err)
+	}
+
+	// Add an address.
+	addr, err := promptForAddress(os.Stdin)
+	if err != nil {
+		log.Fatalln("Error with address:", err)
+	}
+	book.People = append(book.People, addr)
+	// [END_EXCLUDE]
+
+	// Write the new address book back to disk.
+	out, err := proto.Marshal(book)
+	if err != nil {
+		log.Fatalln("Failed to encode address book:", err)
+	}
+	if err := ioutil.WriteFile(fname, out, 0644); err != nil {
+		log.Fatalln("Failed to write address book:", err)
+	}
+	// [END marshal_proto]
+}
diff --git a/examples/add_person.py b/examples/add_person.py
index 78e5696..0b69857 100755
--- a/examples/add_person.py
+++ b/examples/add_person.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 
 # See README.txt for information and build instructions.
 
@@ -19,7 +19,7 @@
     if number == "":
       break
 
-    phone_number = person.phone.add()
+    phone_number = person.phones.add()
     phone_number.number = number
 
     type = raw_input("Is this a mobile, home, or work phone? ")
@@ -43,16 +43,14 @@
 
 # Read the existing address book.
 try:
-  f = open(sys.argv[1], "rb")
-  address_book.ParseFromString(f.read())
-  f.close()
+  with open(sys.argv[1], "rb") as f:
+    address_book.ParseFromString(f.read())
 except IOError:
   print sys.argv[1] + ": File not found.  Creating a new file."
 
 # Add an address.
-PromptForAddress(address_book.person.add())
+PromptForAddress(address_book.people.add())
 
 # Write the new address book back to disk.
-f = open(sys.argv[1], "wb")
-f.write(address_book.SerializeToString())
-f.close()
+with open(sys.argv[1], "wb") as f:
+  f.write(address_book.SerializeToString())
diff --git a/examples/add_person_test.go b/examples/add_person_test.go
new file mode 100644
index 0000000..0507db6
--- /dev/null
+++ b/examples/add_person_test.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func TestPromptForAddressReturnsAddress(t *testing.T) {
+	in := `12345
+Example Name
+name@example.com
+123-456-7890
+home
+222-222-2222
+mobile
+111-111-1111
+work
+777-777-7777
+unknown
+
+`
+	got, err := promptForAddress(strings.NewReader(in))
+	if err != nil {
+		t.Fatalf("promptForAddress(%q) had unexpected error: %s", in, err.Error())
+	}
+	if got.Id != 12345 {
+		t.Errorf("promptForAddress(%q) got %d, want ID %d", in, got.Id, 12345)
+	}
+	if got.Name != "Example Name" {
+		t.Errorf("promptForAddress(%q) => want name %q, got %q", "Example Name", got.Name)
+	}
+	if got.Email != "name@example.com" {
+		t.Errorf("promptForAddress(%q) => want email %q, got %q", "name@example.com", got.Email)
+	}
+
+	want := []*pb.Person_PhoneNumber{
+		{Number: "123-456-7890", Type: pb.Person_HOME},
+		{Number: "222-222-2222", Type: pb.Person_MOBILE},
+		{Number: "111-111-1111", Type: pb.Person_WORK},
+		{Number: "777-777-7777", Type: pb.Person_MOBILE},
+	}
+	if len(got.Phones) != len(want) {
+		t.Errorf("want %d phone numbers, got %d", len(want), len(got.Phones))
+	}
+	phones := len(got.Phones)
+	if phones > len(want) {
+		phones = len(want)
+	}
+	for i := 0; i < phones; i++ {
+		if !proto.Equal(got.Phones[i], want[i]) {
+			t.Errorf("want phone %q, got %q", *want[i], *got.Phones[i])
+		}
+
+	}
+}
diff --git a/examples/addressbook.proto b/examples/addressbook.proto
index b14829e..23cc2f9 100644
--- a/examples/addressbook.proto
+++ b/examples/addressbook.proto
@@ -1,14 +1,30 @@
 // See README.txt for information and build instructions.
+//
+// Note: START and END tags are used in comments to define sections used in
+// tutorials.  They are not part of the syntax for Protocol Buffers.
+//
+// To get an in-depth walkthrough of this file and the related examples, see:
+// https://developers.google.com/protocol-buffers/docs/tutorials
 
+// [START declaration]
+syntax = "proto3";
 package tutorial;
+// [END declaration]
 
+// [START java_declaration]
 option java_package = "com.example.tutorial";
 option java_outer_classname = "AddressBookProtos";
+// [END java_declaration]
 
+// [START csharp_declaration]
+option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
+// [END csharp_declaration]
+
+// [START messages]
 message Person {
-  required string name = 1;
-  required int32 id = 2;        // Unique ID number for this person.
-  optional string email = 3;
+  string name = 1;
+  int32 id = 2;  // Unique ID number for this person.
+  string email = 3;
 
   enum PhoneType {
     MOBILE = 0;
@@ -17,14 +33,15 @@
   }
 
   message PhoneNumber {
-    required string number = 1;
-    optional PhoneType type = 2 [default = HOME];
+    string number = 1;
+    PhoneType type = 2;
   }
 
-  repeated PhoneNumber phone = 4;
+  repeated PhoneNumber phones = 4;
 }
 
 // Our address book file is just one of these.
 message AddressBook {
-  repeated Person person = 1;
+  repeated Person people = 1;
 }
+// [END messages]
diff --git a/examples/list_people.cc b/examples/list_people.cc
index 5363152..68e5666 100644
--- a/examples/list_people.cc
+++ b/examples/list_people.cc
@@ -8,17 +8,17 @@
 
 // Iterates though all people in the AddressBook and prints info about them.
 void ListPeople(const tutorial::AddressBook& address_book) {
-  for (int i = 0; i < address_book.person_size(); i++) {
-    const tutorial::Person& person = address_book.person(i);
+  for (int i = 0; i < address_book.people_size(); i++) {
+    const tutorial::Person& person = address_book.people(i);
 
     cout << "Person ID: " << person.id() << endl;
     cout << "  Name: " << person.name() << endl;
-    if (person.has_email()) {
+    if (person.email() != "") {
       cout << "  E-mail address: " << person.email() << endl;
     }
 
-    for (int j = 0; j < person.phone_size(); j++) {
-      const tutorial::Person::PhoneNumber& phone_number = person.phone(j);
+    for (int j = 0; j < person.phones_size(); j++) {
+      const tutorial::Person::PhoneNumber& phone_number = person.phones(j);
 
       switch (phone_number.type()) {
         case tutorial::Person::MOBILE:
diff --git a/examples/list_people.go b/examples/list_people.go
new file mode 100644
index 0000000..70bc589
--- /dev/null
+++ b/examples/list_people.go
@@ -0,0 +1,61 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func writePerson(w io.Writer, p *pb.Person) {
+	fmt.Fprintln(w, "Person ID:", p.Id)
+	fmt.Fprintln(w, "  Name:", p.Name)
+	if p.Email != "" {
+		fmt.Fprintln(w, "  E-mail address:", p.Email)
+	}
+
+	for _, pn := range p.Phones {
+		switch pn.Type {
+		case pb.Person_MOBILE:
+			fmt.Fprint(w, "  Mobile phone #: ")
+		case pb.Person_HOME:
+			fmt.Fprint(w, "  Home phone #: ")
+		case pb.Person_WORK:
+			fmt.Fprint(w, "  Work phone #: ")
+		}
+		fmt.Fprintln(w, pn.Number)
+	}
+}
+
+func listPeople(w io.Writer, book *pb.AddressBook) {
+	for _, p := range book.People {
+		writePerson(w, p)
+	}
+}
+
+// Main reads the entire address book from a file and prints all the
+// information inside.
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatalf("Usage:  %s ADDRESS_BOOK_FILE\n", os.Args[0])
+	}
+	fname := os.Args[1]
+
+	// [START unmarshal_proto]
+	// Read the existing address book.
+	in, err := ioutil.ReadFile(fname)
+	if err != nil {
+		log.Fatalln("Error reading file:", err)
+	}
+	book := &pb.AddressBook{}
+	if err := proto.Unmarshal(in, book); err != nil {
+		log.Fatalln("Failed to parse address book:", err)
+	}
+	// [END unmarshal_proto]
+
+	listPeople(os.Stdout, book)
+}
diff --git a/examples/list_people.py b/examples/list_people.py
index f9f36b9..f131872 100755
--- a/examples/list_people.py
+++ b/examples/list_people.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 
 # See README.txt for information and build instructions.
 
@@ -7,13 +7,13 @@
 
 # Iterates though all people in the AddressBook and prints info about them.
 def ListPeople(address_book):
-  for person in address_book.person:
+  for person in address_book.people:
     print "Person ID:", person.id
     print "  Name:", person.name
-    if person.HasField('email'):
+    if person.email != "":
       print "  E-mail address:", person.email
 
-    for phone_number in person.phone:
+    for phone_number in person.phones:
       if phone_number.type == addressbook_pb2.Person.MOBILE:
         print "  Mobile phone #:",
       elif phone_number.type == addressbook_pb2.Person.HOME:
@@ -31,8 +31,7 @@
 address_book = addressbook_pb2.AddressBook()
 
 # Read the existing address book.
-f = open(sys.argv[1], "rb")
-address_book.ParseFromString(f.read())
-f.close()
+with open(sys.argv[1], "rb") as f:
+  address_book.ParseFromString(f.read())
 
 ListPeople(address_book)
diff --git a/examples/list_people_test.go b/examples/list_people_test.go
new file mode 100644
index 0000000..87d6ad6
--- /dev/null
+++ b/examples/list_people_test.go
@@ -0,0 +1,120 @@
+package main
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func TestWritePersonWritesPerson(t *testing.T) {
+	buf := new(bytes.Buffer)
+	// [START populate_proto]
+	p := pb.Person{
+		Id:    1234,
+		Name:  "John Doe",
+		Email: "jdoe@example.com",
+		Phones: []*pb.Person_PhoneNumber{
+			{Number: "555-4321", Type: pb.Person_HOME},
+		},
+	}
+	// [END populate_proto]
+	writePerson(buf, &p)
+	got := buf.String()
+	want := `Person ID: 1234
+  Name: John Doe
+  E-mail address: jdoe@example.com
+  Home phone #: 555-4321
+`
+	if got != want {
+		t.Errorf("writePerson(%s) =>\n\t%q, want %q", p.String(), got, want)
+	}
+}
+
+func TestListPeopleWritesList(t *testing.T) {
+	buf := new(bytes.Buffer)
+	in := pb.AddressBook{[]*pb.Person{
+		{
+			Name:  "John Doe",
+			Id:    101,
+			Email: "john@example.com",
+		},
+		{
+			Name: "Jane Doe",
+			Id:   102,
+		},
+		{
+			Name:  "Jack Doe",
+			Id:    201,
+			Email: "jack@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-555-5555", Type: pb.Person_WORK},
+			},
+		},
+		{
+			Name:  "Jack Buck",
+			Id:    301,
+			Email: "buck@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-555-0000", Type: pb.Person_HOME},
+				{Number: "555-555-0001", Type: pb.Person_MOBILE},
+				{Number: "555-555-0002", Type: pb.Person_WORK},
+			},
+		},
+		{
+			Name:  "Janet Doe",
+			Id:    1001,
+			Email: "janet@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-777-0000"},
+				{Number: "555-777-0001", Type: pb.Person_HOME},
+			},
+		},
+	}}
+	listPeople(buf, &in)
+	want := strings.Split(`Person ID: 101
+  Name: John Doe
+  E-mail address: john@example.com
+Person ID: 102
+  Name: Jane Doe
+Person ID: 201
+  Name: Jack Doe
+  E-mail address: jack@example.com
+  Work phone #: 555-555-5555
+Person ID: 301
+  Name: Jack Buck
+  E-mail address: buck@example.com
+  Home phone #: 555-555-0000
+  Mobile phone #: 555-555-0001
+  Work phone #: 555-555-0002
+Person ID: 1001
+  Name: Janet Doe
+  E-mail address: janet@example.com
+  Mobile phone #: 555-777-0000
+  Home phone #: 555-777-0001
+`, "\n")
+	got := strings.Split(buf.String(), "\n")
+	if len(got) != len(want) {
+		t.Errorf(
+			"listPeople(%s) =>\n\t%q has %d lines, want %d",
+			in.String(),
+			buf.String(),
+			len(got),
+			len(want))
+	}
+	lines := len(got)
+	if lines > len(want) {
+		lines = len(want)
+	}
+	for i := 0; i < lines; i++ {
+		if got[i] != want[i] {
+			t.Errorf(
+				"listPeople(%s) =>\n\tline %d %q, want %q",
+				in.String(),
+				i,
+				got[i],
+				want[i])
+		}
+	}
+}
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index 07219dc..c170c83 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -27,7 +27,80 @@
 fi
 
 cd src
-make $@ protoc &&
-  ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto && \
-  ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+
+declare -a RUNTIME_PROTO_FILES=(\
+  google/protobuf/any.proto \
+  google/protobuf/api.proto \
+  google/protobuf/descriptor.proto \
+  google/protobuf/duration.proto \
+  google/protobuf/empty.proto \
+  google/protobuf/field_mask.proto \
+  google/protobuf/source_context.proto \
+  google/protobuf/struct.proto \
+  google/protobuf/timestamp.proto \
+  google/protobuf/type.proto \
+  google/protobuf/wrappers.proto)
+
+CORE_PROTO_IS_CORRECT=0
+PROCESS_ROUND=1
+TMP=$(mktemp -d)
+echo "Updating descriptor protos..."
+while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
+do
+  echo "Round $PROCESS_ROUND"
+  CORE_PROTO_IS_CORRECT=1
+
+  make $@ protoc
+  if test $? -ne 0; then
+    echo "Failed to build protoc."
+    exit 1
+  fi
+
+  ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
+  ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto
+
+  for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
+    BASE_NAME=${PROTO_FILE%.*}
+    diff ${BASE_NAME}.pb.h $TMP/${BASE_NAME}.pb.h > /dev/null
+    if test $? -ne 0; then
+      CORE_PROTO_IS_CORRECT=0
+    fi
+    diff ${BASE_NAME}.pb.cc $TMP/${BASE_NAME}.pb.cc > /dev/null
+    if test $? -ne 0; then
+      CORE_PROTO_IS_CORRECT=0
+    fi
+  done
+
+  diff google/protobuf/compiler/plugin.pb.h $TMP/google/protobuf/compiler/plugin.pb.h > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+  diff google/protobuf/compiler/plugin.pb.cc $TMP/google/protobuf/compiler/plugin.pb.cc > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+
+  # Only override the output if the files are different to avoid re-compilation
+  # of the protoc.
+  if [ $CORE_PROTO_IS_CORRECT -ne 1 ]; then
+    for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
+      BASE_NAME=${PROTO_FILE%.*}
+      mv $TMP/${BASE_NAME}.pb.h ${BASE_NAME}.pb.h
+      mv $TMP/${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc
+    done
+    mv $TMP/google/protobuf/compiler/plugin.pb.* google/protobuf/compiler/
+  fi
+
+  PROCESS_ROUND=$((PROCESS_ROUND + 1))
+done
 cd ..
+
+if test -x objectivec/generate_well_known_types.sh; then
+  echo "Generating messages for objc."
+  objectivec/generate_well_known_types.sh $@
+fi
+
+if test -x csharp/generate_protos.sh; then
+  echo "Generating messages for C#."
+  csharp/generate_protos.sh $@
+fi
diff --git a/gmock.BUILD b/gmock.BUILD
new file mode 100644
index 0000000..82abf27
--- /dev/null
+++ b/gmock.BUILD
@@ -0,0 +1,28 @@
+cc_library(
+    name = "gtest",
+    srcs = [
+        "gmock-1.7.0/gtest/src/gtest-all.cc",
+        "gmock-1.7.0/src/gmock-all.cc",
+    ],
+    hdrs = glob([
+        "gmock-1.7.0/**/*.h",
+        "gmock-1.7.0/gtest/src/*.cc",
+        "gmock-1.7.0/src/*.cc",
+    ]),
+    includes = [
+        "gmock-1.7.0",
+        "gmock-1.7.0/gtest",
+        "gmock-1.7.0/gtest/include",
+        "gmock-1.7.0/include",
+    ],
+    linkopts = ["-pthread"],
+    visibility = ["//visibility:public"],
+)
+
+cc_library(
+    name = "gtest_main",
+    srcs = ["gmock-1.7.0/src/gmock_main.cc"],
+    linkopts = ["-pthread"],
+    visibility = ["//visibility:public"],
+    deps = [":gtest"],
+)
diff --git a/java/README.md b/java/README.md
new file mode 100644
index 0000000..060d9ac
--- /dev/null
+++ b/java/README.md
@@ -0,0 +1,102 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers runtime library.
+
+Installation - With Maven
+=========================
+
+The Protocol Buffers build is managed using Maven.  If you would
+rather build without Maven, see below.
+
+1) Install Apache Maven if you don't have it:
+
+     http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc.  If
+   you install a binary distribution, make sure that it is the same
+   version as this package.  If in doubt, run:
+
+     $ protoc --version
+
+   You will need to place the protoc executable in ../src.  (If you
+   built it yourself, it should already be there.)
+
+3) Run the tests:
+
+     $ mvn test
+
+   If some tests fail, this library may not work correctly on your
+   system.  Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+     $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+   .jar file to use:
+
+     $ mvn package
+
+   The .jar will be placed in the "target" directory.
+
+Installation - 'Lite' Version - With Maven
+==========================================
+
+Building the 'lite' version of the Java Protocol Buffers library is
+the same as building the full version, except that all commands are
+run using the 'lite' profile.  (see
+http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
+
+E.g. to install the lite version of the jar, you would run:
+
+    $ mvn install -P lite
+
+The resulting artifact has the 'lite' classifier.  To reference it
+for dependency resolution, you would specify it as:
+
+```
+  <dependency>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-java</artifactId>
+    <version>${version}</version>
+    <classifier>lite</classifier>
+  </dependency>
+```
+
+Installation - Without Maven
+============================
+
+If you would rather not install Maven to build the library, you may
+follow these instructions instead.  Note that these instructions skip
+running unit tests.
+
+1) Build the C++ code, or obtain a binary distribution of protoc.  If
+   you install a binary distribution, make sure that it is the same
+   version as this package.  If in doubt, run:
+
+     $ protoc --version
+
+   If you built the C++ code without installing, the compiler binary
+   should be located in ../src.
+
+2) Invoke protoc to build DescriptorProtos.java:
+
+     $ protoc --java_out=src/main/java -I../src \
+         ../src/google/protobuf/descriptor.proto
+
+3) Compile the code in src/main/java using whatever means you prefer.
+
+4) Install the classes wherever you prefer.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+  https://developers.google.com/protocol-buffers/
diff --git a/java/README.txt b/java/README.txt
deleted file mode 100644
index b02e88b..0000000
--- a/java/README.txt
+++ /dev/null
@@ -1,685 +0,0 @@
-Protocol Buffers - Google's data interchange format
-Copyright 2008 Google Inc.
-
-This directory contains the Java Protocol Buffers runtime library.
-
-Installation - With Maven
-=========================
-
-The Protocol Buffers build is managed using Maven.  If you would
-rather build without Maven, see below.
-
-1) Install Apache Maven if you don't have it:
-
-     http://maven.apache.org/
-
-2) Build the C++ code, or obtain a binary distribution of protoc.  If
-   you install a binary distribution, make sure that it is the same
-   version as this package.  If in doubt, run:
-
-     $ protoc --version
-
-   You will need to place the protoc executable in ../src.  (If you
-   built it yourself, it should already be there.)
-
-3) Run the tests:
-
-     $ mvn test
-
-   If some tests fail, this library may not work correctly on your
-   system.  Continue at your own risk.
-
-4) Install the library into your Maven repository:
-
-     $ mvn install
-
-5) If you do not use Maven to manage your own build, you can build a
-   .jar file to use:
-
-     $ mvn package
-
-   The .jar will be placed in the "target" directory.
-
-Installation - 'Lite' Version - With Maven
-==========================================
-
-Building the 'lite' version of the Java Protocol Buffers library is
-the same as building the full version, except that all commands are
-run using the 'lite' profile.  (see
-http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
-
-E.g. to install the lite version of the jar, you would run:
-
-  $ mvn install -P lite
-
-The resulting artifact has the 'lite' classifier.  To reference it
-for dependency resolution, you would specify it as:
-
-  <dependency>
-    <groupId>com.google.protobuf</groupId>
-    <artifactId>protobuf-java</artifactId>
-    <version>${version}</version>
-    <classifier>lite</classifier>
-  </dependency>
-
-Installation - Without Maven
-============================
-
-If you would rather not install Maven to build the library, you may
-follow these instructions instead.  Note that these instructions skip
-running unit tests.
-
-1) Build the C++ code, or obtain a binary distribution of protoc.  If
-   you install a binary distribution, make sure that it is the same
-   version as this package.  If in doubt, run:
-
-     $ protoc --version
-
-   If you built the C++ code without installing, the compiler binary
-   should be located in ../src.
-
-2) Invoke protoc to build DescriptorProtos.java:
-
-     $ protoc --java_out=src/main/java -I../src \
-         ../src/google/protobuf/descriptor.proto
-
-3) Compile the code in src/main/java using whatever means you prefer.
-
-4) Install the classes wherever you prefer.
-
-Micro version
-============================
-
-The runtime and generated code for MICRO_RUNTIME is smaller
-because it does not include support for the descriptor and
-reflection, and enums are generated as integer constants in
-the parent message or the file's outer class, with no
-protection against invalid values set to enum fields. Also,
-not currently supported are packed repeated elements or
-extensions.
-
-To create a jar file for the runtime and run tests invoke
-"mvn package -P micro" from the <protobuf-root>/java
-directory. The generated jar file is
-<protobuf-root>java/target/protobuf-java-2.6.0-micro.jar.
-
-If you wish to compile the MICRO_RUNTIME your self, place
-the 7 files below, in <root>/com/google/protobuf and
-create a jar file for use with your code and the generated
-code:
-
-ByteStringMicro.java
-CodedInputStreamMicro.java
-CodedOutputStreamMicro.java
-InvalidProtocolBufferException.java
-MessageMicro.java
-WireFormatMicro.java
-
-If you wish to change on the code generator it is located
-in /src/google/protobuf/compiler/javamicro.
-
-To generate code for the MICRO_RUNTIME invoke protoc with
---javamicro_out command line parameter. javamicro_out takes
-a series of optional sub-parameters separated by commas
-and a final parameter, with a colon separator, which defines
-the source directory. Sub-parameters begin with a name
-followed by an equal and if that sub-parameter has multiple
-parameters they are seperated by "|". The command line options
-are:
-
-opt                  -> speed or space
-java_use_vector      -> true or false
-java_package         -> <file-name>|<package-name>
-java_outer_classname -> <file-name>|<package-name>
-java_multiple_files  -> true or false
-
-opt={speed,space} (default: space)
-  This changes the code generation to optimize for speed or
-  space. When opt=speed this changes the code generation
-  for strings so that multiple conversions to Utf8 are
-  eliminated.
-
-java_use_vector={true,false} (default: false)
-  This specifies the collection class for repeated elements.
-  If false, repeated elements use java.util.ArrayList<> and
-  the code must be compiled with Java 1.5 or above. If true,
-  repeated elements use java.util.Vector and the code can
-  be compiled with Java 1.3 or above. The 'source'
-  parameter of 'javac' may be used to control the version
-  of the source: "javac -source 1.3". You can also change
-  the <source> xml element for the maven-compiler-plugin.
-  Below is for 1.5 sources:
-
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-
-  And below would be for 1.3 sources (note when changing
-  to 1.3 you must also set java_use_vector=true):
-
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.3</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-
-java_package=<file-name>|<package-name> (no default)
-  This allows overriding the 'java_package' option value
-  for the given file from the command line. Use multiple
-  java_package options to override the option for multiple
-  files. The final Java package for each file is the value
-  of this command line option if present, or the value of
-  the same option defined in the file if present, or the
-  proto package if present, or the default Java package.
-
-java_outer_classname=<file-name>|<outer-classname> (no default)
-  This allows overriding the 'java_outer_classname' option
-  for the given file from the command line. Use multiple
-  java_outer_classname options to override the option for
-  multiple files. The final Java outer class name for each
-  file is the value of this command line option if present,
-  or the value of the same option defined in the file if
-  present, or the file name converted to CamelCase. This
-  outer class will nest all classes and integer constants
-  generated from file-scope messages and enums.
-
-java_multiple_files={true,false} (no default)
-  This allows overriding the 'java_multiple_files' option
-  in all source files and their imported files from the
-  command line. The final value of this option for each
-  file is the value defined in this command line option, or
-  the value of the same option defined in the file if
-  present, or false. This specifies whether to generate
-  package-level classes for the file-scope messages in the
-  same Java package as the outer class (instead of nested
-  classes in the outer class). File-scope enum constants
-  are still generated as integer constants in the outer
-  class. This affects the fully qualified references in the
-  Java code. NOTE: because the command line option
-  overrides the value for all files and their imported
-  files, using this option inconsistently may result in
-  incorrect references to the imported messages and enum
-  constants.
-
-
-IMPORTANT: change of javamicro_out behavior:
-
-In previous versions, if the outer class name has not been
-given explicitly, javamicro_out would not infer the outer
-class name from the file name, and would skip the outer
-class generation. This makes the compilation succeed only
-if the source file contains a single message and no enums,
-and the generated class for that message is placed at the
-package level. To re-align with java_out, javamicro_out
-will now always generate the outer class, inferring its
-name from the file name if not given, as a container of the
-message classes and enum constants. To keep any existing
-single-message source file from causing the generation of
-an unwanted outer class, you can set the option
-java_multiple_files to true, either in the file or as a
-command line option.
-
-
-Below are a series of examples for clarification of the
-various parameters and options. Assuming this file:
-
-src/proto/simple-data-protos.proto:
-
-    package testprotobuf;
-
-    message SimpleData {
-      optional fixed64 id = 1;
-      optional string description = 2;
-      optional bool ok = 3 [default = false];
-    };
-
-and the compiled protoc in the current working directory,
-then a simple command line to compile this file would be:
-
-./protoc --javamicro_out=. src/proto/simple-data-protos.proto
-
-This will create testprotobuf/SimpleDataProtos.java, which
-has the following content (extremely simplified):
-
-    package testprotobuf;
-
-    public final class SimpleDataProtos {
-      public static final class SimpleData
-          extends MessageMicro {
-        ...
-      }
-    }
-
-The message SimpleData is compiled into the SimpleData
-class, nested in the file's outer class SimpleDataProtos,
-whose name is implicitly defined by the proto file name
-"simple-data-protos".
-
-The directory, aka Java package, testprotobuf is created
-because on line 1 of simple-data-protos.proto is
-"package testprotobuf;". If you wanted a different
-package name you could use the java_package option in the
-file:
-
-    option java_package = "my_package";
-
-or in command line sub-parameter:
-
-./protoc '--javamicro_out=\
-java_package=src/proto/simple-data-protos.proto|my_package:\
-.' src/proto/simple-data-protos.proto
-
-Here you see the new java_package sub-parameter which
-itself needs two parameters the file name and the
-package name, these are separated by "|". The value set
-in the command line overrides the value set in the file.
-Now you'll find SimpleDataProtos.java in the my_package/
-directory.
-
-If you wanted to also change the optimization for
-speed you'd add opt=speed with the comma seperator
-as follows:
-
-./protoc '--javamicro_out=\
-opt=speed,\
-java_package=src/proto/simple-data-protos.proto|my_package:
-.' src/proto/simple-data-protos.proto
-
-If you also wanted a different outer class name you'd
-do the following:
-
-./protoc '--javamicro_out=\
-opt=speed,\
-java_package=src/proto/simple-data-protos.proto|my_package,\
-java_outer_classname=src/proto/simple-data-protos.proto|OuterName:\
-.' src/proto/simple-data-protos.proto
-
-Now you'll find my_package/OuterName.java and the
-message class SimpleData nested in it.
-
-As mentioned java_package, java_outer_classname and
-java_multiple_files may also be specified in the file.
-In the example below we must define
-java_outer_classname because otherwise the outer class
-and one of the message classes will have the same name,
-which is forbidden to prevent name ambiguity:
-
-src/proto/sample-message.proto:
-
-    package testmicroruntime;
-
-    option java_package = "com.example";
-    option java_outer_classname = "SampleMessageProtos";
-
-    enum MessageType {
-      SAMPLE = 1;
-      EXAMPLE = 2;
-    }
-
-    message SampleMessage {
-      required int32 id = 1;
-      required MessageType type = 2;
-    }
-
-    message SampleMessageContainer {
-      required SampleMessage message = 1;
-    }
-
-This could be compiled using:
-
-./protoc --javamicro_out=. src/proto/sample-message.proto
-
-and the output will be:
-
-com/example/SampleMessageProtos.java:
-
-    package com.example;
-
-    public final class SampleMessageProtos {
-      public static final int SAMPLE = 1;
-      public static final int EXAMPLE = 2;
-      public static final class SampleMessage
-          extends MessageMicro {
-        ...
-      }
-      public static final class SampleMessageContainer
-          extends MessageMicro {
-        ...
-      }
-    }
-
-As you can see the file-scope enum MessageType is
-disassembled into two integer constants in the outer class.
-In javamicro_out, all enums are disassembled and compiled
-into integer constants in the parent scope (the containing
-message's class or the file's (i.e. outer) class).
-
-You may prefer the file-scope messages to be saved in
-separate files. You can do this by setting the option
-java_multiple_files to true, in either the file like this:
-
-    option java_multiple_files = true;
-
-or the command line like this:
-
-./protoc --javamicro_out=\
-java_multiple_files=true:\
-. src/proto/sample-message.proto
-
-The java_multiple_files option causes javamicro to use a
-separate file for each file-scope message, which resides
-directly in the Java package alongside the outer class:
-
-com/example/SampleMessageProtos.java:
-
-    package com.example;
-    public final class SampleMessageProtos {
-      public static final int SAMPLE = 1;
-      public static final int EXAMPLE = 2;
-    }
-
-com/example/SampleMessage.java:
-
-    package com.example;
-    public final class SampleMessage
-        extends MessageMicro {
-      ...
-    }
-
-com/example/SampleMessageContainer.java:
-
-    package com.example;
-    public final class SampleMessageContainer
-        extends MessageMicro {
-      ...
-    }
-
-As you can see, the outer class now contains only the
-integer constants, generated from the file-scope enum
-"MessageType". Please note that message-scope enums are
-still generated as integer constants in the message class.
-
-
-Nano version
-============================
-
-Nano is a special code generator and runtime library designed specially
-for Android, and is very resource-friendly in both the amount of code
-and the runtime overhead. An overview of Nano features:
-
-- No descriptors or message builders.
-- All messages are mutable; fields are public Java fields.
-- For optional fields only, encapsulation behind setter/getter/hazzer/
-  clearer functions is opt-in, which provide proper 'has' state support.
-- If not opted in, has state is not available. Serialization outputs
-  all fields not equal to their defaults (see important implications
-  below).
-- Required fields are always serialized.
-- Enum constants are integers; protection against invalid values only
-  when parsing from the wire.
-- Enum constants can be generated into container interfaces bearing
-  the enum's name (so the referencing code is in Java style).
-- CodedInputByteBufferNano can only take byte[] (not InputStream).
-- Similarly CodedOutputByteBufferNano can only write to byte[].
-- Repeated fields are in arrays, not ArrayList or Vector. Null array
-  elements are allowed and silently ignored.
-- Full support of serializing/deserializing repeated packed fields.
-- Support of extensions.
-- Unset messages/groups are null, not an immutable empty default
-  instance.
-- toByteArray(...) and mergeFrom(...) are now static functions of
-  MessageNano.
-- The 'bytes' type translates to the Java type byte[].
-
-The generated messages are not thread-safe for writes, but may be
-used simultaneously from multiple threads in a read-only manner.
-In other words, an appropriate synchronization mechanism (such as
-a ReadWriteLock) must be used to ensure that a message, its
-ancestors, and descendants are not accessed by any other threads
-while the message is being modified. Field reads, getter methods
-(but not getExtension(...)), toByteArray(...), writeTo(...),
-getCachedSize(), and getSerializedSize() are all considered read-only
-operations.
-
-IMPORTANT: If you have fields with defaults and opt out of accessors
-
-How fields with defaults are serialized has changed. Because we don't
-keep "has" state, any field equal to its default is assumed to be not
-set and therefore is not serialized. Consider the situation where we
-change the default value of a field. Senders compiled against an older
-version of the proto continue to match against the old default, and
-don't send values to the receiver even though the receiver assumes the
-new default value. Therefore, think carefully about the implications
-of changing the default value. Alternatively, turn on accessors and
-enjoy the benefit of the explicit has() checks.
-
-IMPORTANT: If you have "bytes" fields with non-empty defaults
-
-Because the byte buffer is now of mutable type byte[], the default
-static final cannot be exposed through a public field. Each time a
-message's constructor or clear() function is called, the default value
-(kept in a private byte[]) is cloned. This causes a small memory
-penalty. This is not a problem if the field has no default or is an
-empty default.
-
-Nano Generator options
-
-java_package           -> <file-name>|<package-name>
-java_outer_classname   -> <file-name>|<package-name>
-java_multiple_files    -> true or false
-java_nano_generate_has -> true or false [DEPRECATED]
-optional_field_style   -> default or accessors
-enum_style             -> c or java
-ignore_services        -> true or false
-parcelable_messages    -> true or false
-
-java_package:
-java_outer_classname:
-java_multiple_files:
-  Same as Micro version.
-
-java_nano_generate_has={true,false} (default: false)
-  DEPRECATED. Use optional_field_style=accessors.
-
-  If true, generates a public boolean variable has<fieldname>
-  accompanying each optional or required field (not present for
-  repeated fields, groups or messages). It is set to false initially
-  and upon clear(). If parseFrom(...) reads the field from the wire,
-  it is set to true. This is a way for clients to inspect the "has"
-  value upon parse. If it is set to true, writeTo(...) will ALWAYS
-  output that field (even if field value is equal to its
-  default).
-
-  IMPORTANT: This option costs an extra 4 bytes per primitive field in
-  the message. Think carefully about whether you really need this. In
-  many cases reading the default works and determining whether the
-  field was received over the wire is irrelevant.
-
-optional_field_style={default,accessors,reftypes} (default: default)
-  Defines the style of the generated code for fields.
-
-  * default *
-
-  In the default style, optional fields translate into public mutable
-  Java fields, and the serialization process is as discussed in the
-  "IMPORTANT" section above. 
-
-  * accessors *
-
-  When set to 'accessors', each optional field is encapsulated behind
-  4 accessors, namely get<fieldname>(), set<fieldname>(), has<fieldname>()
-  and clear<fieldname>() methods, with the standard semantics. The hazzer's
-  return value determines whether a field is serialized, so this style is
-  useful when you need to serialize a field with the default value, or check
-  if a field has been explicitly set to its default value from the wire.
-
-  In the 'accessors' style, required and nested message fields are still
-  translated to one public mutable Java field each, repeated fields are still
-  translated to arrays. No accessors are generated for them.
-
-  IMPORTANT: When using the 'accessors' style, ProGuard should always
-  be enabled with optimization (don't use -dontoptimize) and allowing
-  access modification (use -allowaccessmodification). This removes the
-  unused accessors and maybe inline the rest at the call sites,
-  reducing the final code size.
-  TODO(maxtroy): find ProGuard config that would work the best.
-
-  * reftypes *
-
-  When set to 'reftypes', each proto field is generated as a public Java
-  field. For primitive types, these fields use the Java reference types
-  such as java.lang.Integer instead of primitive types such as int.
-
-  In the 'reftypes' style, fields are initialized to null (or empty
-  arrays for repeated fields), and their default values are not available.
-  They are serialized over the wire based on equality to null.
-
-  The 'reftypes' mode has some additional cost due to autoboxing and usage
-  of reference types. In practice, many boxed types are cached, and so don't
-  result in object creation. However, references do take slightly more memory
-  than primitives.
-
-  The 'reftypes' mode is useful when you want to be able to serialize fields
-  with default values, or check if a field has been explicitly set to the
-  default over the wire without paying the extra method cost of the
-  'accessors' mode.
-
-  Note that if you attempt to write null to a required field in the reftypes
-  mode, serialization of the proto will cause a NullPointerException. This is
-  an intentional indicator that you must set required fields.
-
-  NOTE
-  optional_field_style=accessors or reftypes cannot be used together with
-  java_nano_generate_has=true. If you need the 'has' flag for any
-  required field (you have no reason to), you can only use
-  java_nano_generate_has=true.
-
-enum_style={c,java} (default: c)
-  Defines where to put the int constants generated from enum members.
-
-  * c *
-
-  Use C-style, so the enum constants are available at the scope where
-  the enum is defined. A file-scope enum's members are referenced like
-  'FileOuterClass.ENUM_VALUE'; a message-scope enum's members are
-  referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
-  This complies with the Micro code generator's behavior.
-
-  * java *
-
-  Use Java-style, so the enum constants are available under the enum
-  name and referenced like 'EnumName.ENUM_VALUE' (they are still int
-  constants). The enum name becomes the name of a public interface, at
-  the scope where the enum is defined. If the enum is file-scope and
-  the java_multiple_files option is on, the interface will be defined
-  in its own file. To reduce code size, this interface should not be
-  implemented and ProGuard shrinking should be used, so after the Java
-  compiler inlines all referenced enum constants into the call sites,
-  the interface remains unused and can be removed by ProGuard.
-
-ignore_services={true,false} (default: false)
-  Skips services definitions.
-
-  Nano doesn't support services. By default, if a service is defined
-  it will generate a compilation error. If this flag is set to true,
-  services will be silently ignored, instead.
-
-parcelable_messages={true,false} (default: false)
-  Android-specific option to generate Parcelable messages.
-
-generate_intdefs={true,false} (default: false)
-  Android-specific option to generate @IntDef annotations for enums.
-
-  If turned on, an @IntDef annotation (a public @interface) will be
-  generated for each enum, and every integer parameter and return
-  value in the generated code meant for this enum will be annotated
-  with it. This interface is generated with the same name and at the
-  same place as the enum members' container interfaces described
-  above under enum_style=java, regardless of the enum_style option
-  used. When this is combined with enum_style=java, the interface
-  will be both the @IntDef annotation and the container of the enum
-  members; otherwise the interface has an empty body.
-
-  Your app must declare a compile-time dependency on the
-  android-support-annotations library.
-
-  For more information on how these @IntDef annotations help with
-  compile-time type safety, see:
-  https://sites.google.com/a/android.com/tools/tech-docs/support-annotations
-  and
-  https://developer.android.com/reference/android/support/annotation/IntDef.html
-
-
-To use nano protobufs within the Android repo:
-
-- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
-  When building a Java library or an app (package) target, the build
-  system will add the Java nano runtime library to the
-  LOCAL_STATIC_JAVA_LIBRARIES variable, so you don't need to.
-- Set 'LOCAL_PROTO_JAVA_OUTPUT_PARAMS := ...' in your local .mk file
-  for any command-line options you need. Use commas to join multiple
-  options. In the nano flavor only, whitespace surrounding the option
-  names and values are ignored, so you can use backslash-newline or
-  '+=' to structure your make files nicely.
-- The options will be applied to *all* proto files in LOCAL_SRC_FILES
-  when you build a Java library or package. In case different options
-  are needed for different proto files, build separate Java libraries
-  and reference them in your main target. Note: you should make sure
-  that, for each separate target, all proto files imported from any
-  proto file in LOCAL_SRC_FILES are included in LOCAL_SRC_FILES. This
-  is because the generator has to assume that the imported files are
-  built using the same options, and will generate code that reference
-  the fields and enums from the imported files using the same code
-  style.
-- Hint: 'include $(CLEAR_VARS)' resets all LOCAL_ variables, including
-  the two above.
-
-To use nano protobufs outside of Android repo:
-
-- Link with the generated jar file
-  <protobuf-root>java/target/protobuf-java-2.6.0-nano.jar.
-- Invoke with --javanano_out, e.g.:
-
-./protoc '--javanano_out=\
-    java_package=src/proto/simple-data.proto|my_package,\
-    java_outer_classname=src/proto/simple-data.proto|OuterName\
-  :.' src/proto/simple-data.proto
-
-Contributing to nano:
-
-Please add/edit tests in NanoTest.java.
-
-Please run the following steps to test:
-
-- cd external/protobuf
-- ./configure
-- Run "make -j12 check" and verify all tests pass.
-- cd java
-- Run "mvn test" and verify all tests pass.
-- cd ../../..
-- . build/envsetup.sh
-- lunch 1
-- "make -j12 aprotoc libprotobuf-java-nano aprotoc-test-nano-params NanoAndroidTest" and
-  check for build errors.
-- Plug in an Android device or start an emulator.
-- adb install -r out/target/product/generic/data/app/NanoAndroidTest/NanoAndroidTest.apk
-- Run:
-  "adb shell am instrument -w com.google.protobuf.nano.test/android.test.InstrumentationTestRunner"
-  and verify all tests pass.
-- repo sync -c -j256
-- "make -j12" and check for build errors
-
-
-Usage
-=====
-
-The complete documentation for Protocol Buffers is available via the
-web at:
-
-  https://developers.google.com/protocol-buffers/
diff --git a/java/core/generate-sources-build.xml b/java/core/generate-sources-build.xml
new file mode 100644
index 0000000..0996e5f
--- /dev/null
+++ b/java/core/generate-sources-build.xml
@@ -0,0 +1,20 @@
+<project name="generate-sources">
+    <echo message="Running protoc ..."/>
+    <mkdir dir="${generated.sources.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=${generated.sources.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/duration.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/empty.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/field_mask.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/source_context.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/struct.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/timestamp.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/type.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/wrappers.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/compiler/plugin.proto"/>
+    </exec>
+</project>
\ No newline at end of file
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
new file mode 100644
index 0000000..ab415db
--- /dev/null
+++ b/java/core/generate-test-sources-build.xml
@@ -0,0 +1,43 @@
+<project name="generate-test-sources">
+    <mkdir dir="${generated.testsources.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=${generated.testsources.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="--proto_path=${test.proto.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset_wire_format.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_optimize_for.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite_imports_nonlite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test2.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test3.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_bad_identifiers.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8_size.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_custom_options.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
+    </exec>
+</project>
\ No newline at end of file
diff --git a/java/core/pom.xml b/java/core/pom.xml
new file mode 100644
index 0000000..0d4c5c7
--- /dev/null
+++ b/java/core/pom.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-3</version>
+  </parent>
+
+  <artifactId>protobuf-java</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Protocol Buffers [Core]</name>
+  <description>
+    Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <!-- Include core protos in the bundle as resources -->
+    <resources>
+      <resource>
+        <directory>${protobuf.source.dir}</directory>
+        <includes>
+          <include>google/protobuf/any.proto</include>
+          <include>google/protobuf/api.proto</include>
+          <include>google/protobuf/descriptor.proto</include>
+          <include>google/protobuf/duration.proto</include>
+          <include>google/protobuf/empty.proto</include>
+          <include>google/protobuf/field_mask.proto</include>
+          <include>google/protobuf/source_context.proto</include>
+          <include>google/protobuf/struct.proto</include>
+          <include>google/protobuf/timestamp.proto</include>
+          <include>google/protobuf/type.proto</include>
+          <include>google/protobuf/wrappers.proto</include>
+          <include>google/protobuf/compiler/plugin.proto</include>
+        </includes>
+      </resource>
+    </resources>
+
+    <plugins>
+      <!-- Use Antrun plugin to generate sources with protoc -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate core protos -->
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+
+          <!-- Generate the test protos -->
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-test-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Add the generated sources to the build -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
+          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+        </configuration>
+      </plugin>
+
+      <!-- OSGI bundle configuration -->
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+            <Export-Package>com.google.protobuf;version=${project.version}</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
new file mode 100644
index 0000000..03c0d57
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -0,0 +1,553 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+import com.google.protobuf.Internal.EnumLite;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A partial implementation of the {@link Message} interface which implements
+ * as many methods of that interface as possible in terms of other methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessage
+    // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
+    extends AbstractMessageLite
+    implements Message {
+  
+  @Override
+  public boolean isInitialized() {
+    return MessageReflection.isInitialized(this);
+  }
+
+
+  @Override
+  public List<String> findInitializationErrors() {
+    return MessageReflection.findMissingFields(this);
+  }
+
+  @Override
+  public String getInitializationErrorString() {
+    return MessageReflection.delimitWithCommas(findInitializationErrors());
+  }
+
+  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+  @Override
+  public boolean hasOneof(OneofDescriptor oneof) {
+    throw new UnsupportedOperationException("hasOneof() is not implemented.");
+  }
+
+  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+    throw new UnsupportedOperationException(
+        "getOneofFieldDescriptor() is not implemented.");
+  }
+
+  @Override
+  public final String toString() {
+    return TextFormat.printToString(this);
+  }
+
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    MessageReflection.writeMessageTo(this, getAllFields(), output, false);
+  }
+
+  protected int memoizedSize = -1;
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) {
+      return size;
+    }
+
+    memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
+    return memoizedSize;
+  }
+
+  @Override
+  public boolean equals(final Object other) {
+    if (other == this) {
+      return true;
+    }
+    if (!(other instanceof Message)) {
+      return false;
+    }
+    final Message otherMessage = (Message) other;
+    if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
+      return false;
+    }
+    return compareFields(getAllFields(), otherMessage.getAllFields()) &&
+        getUnknownFields().equals(otherMessage.getUnknownFields());
+  }
+
+  @Override
+  public int hashCode() {
+    int hash = memoizedHashCode;
+    if (hash == 0) {
+      hash = 41;
+      hash = (19 * hash) + getDescriptorForType().hashCode();
+      hash = hashFields(hash, getAllFields());
+      hash = (29 * hash) + getUnknownFields().hashCode();
+      memoizedHashCode = hash;
+    }
+    return hash;
+  }
+  
+  private static ByteString toByteString(Object value) {
+    if (value instanceof byte[]) {
+      return ByteString.copyFrom((byte[]) value);
+    } else {
+      return (ByteString) value;
+    }
+  }
+ 
+  /**
+   * Compares two bytes fields. The parameters must be either a byte array or a
+   * ByteString object. They can be of different type though.
+   */
+  private static boolean compareBytes(Object a, Object b) {
+    if (a instanceof byte[] && b instanceof byte[]) {
+      return Arrays.equals((byte[])a, (byte[])b);
+    }
+    return toByteString(a).equals(toByteString(b));
+  }
+  
+  /**
+   * Converts a list of MapEntry messages into a Map used for equals() and
+   * hashCode().
+   */
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  private static Map convertMapEntryListToMap(List list) {
+    if (list.isEmpty()) {
+      return Collections.emptyMap();
+    }
+    Map result = new HashMap();
+    Iterator iterator = list.iterator();
+    Message entry = (Message) iterator.next();
+    Descriptors.Descriptor descriptor = entry.getDescriptorForType();
+    Descriptors.FieldDescriptor key = descriptor.findFieldByName("key");
+    Descriptors.FieldDescriptor value = descriptor.findFieldByName("value");
+    Object fieldValue = entry.getField(value);
+    if (fieldValue instanceof EnumValueDescriptor) {
+      fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
+    }
+    result.put(entry.getField(key), fieldValue);
+    while (iterator.hasNext()) {
+      entry = (Message) iterator.next();
+      fieldValue = entry.getField(value);
+      if (fieldValue instanceof EnumValueDescriptor) {
+        fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
+      }
+      result.put(entry.getField(key), fieldValue);
+    }
+    return result;
+  }
+  
+  /**
+   * Compares two map fields. The parameters must be a list of MapEntry
+   * messages.
+   */
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  private static boolean compareMapField(Object a, Object b) {
+    Map ma = convertMapEntryListToMap((List) a);
+    Map mb = convertMapEntryListToMap((List) b);
+    return MapFieldLite.equals(ma, mb);
+  }
+  
+  /**
+   * Compares two set of fields.
+   * This method is used to implement {@link AbstractMessage#equals(Object)}
+   * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
+   * of bytes fields because immutable messages and mutable messages use
+   * different Java type to reprensent a bytes field and this method should be
+   * able to compare immutable messages, mutable messages and also an immutable
+   * message to a mutable message.
+   */
+  static boolean compareFields(Map<FieldDescriptor, Object> a,
+      Map<FieldDescriptor, Object> b) {
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (FieldDescriptor descriptor : a.keySet()) {
+      if (!b.containsKey(descriptor)) {
+        return false;
+      }
+      Object value1 = a.get(descriptor);
+      Object value2 = b.get(descriptor);
+      if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
+        if (descriptor.isRepeated()) {
+          List list1 = (List) value1;
+          List list2 = (List) value2;
+          if (list1.size() != list2.size()) {
+            return false;
+          }
+          for (int i = 0; i < list1.size(); i++) {
+            if (!compareBytes(list1.get(i), list2.get(i))) {
+              return false;
+            }
+          }
+        } else {
+          // Compares a singular bytes field.
+          if (!compareBytes(value1, value2)) {
+            return false;
+          }
+        }
+      } else if (descriptor.isMapField()) {
+        if (!compareMapField(value1, value2)) {
+          return false;
+        }
+      } else {
+        // Compare non-bytes fields.
+        if (!value1.equals(value2)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Calculates the hash code of a map field. {@code value} must be a list of
+   * MapEntry messages.
+   */
+  @SuppressWarnings("unchecked")
+  private static int hashMapField(Object value) {
+    return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value));
+  }
+
+  /** Get a hash code for given fields and values, using the given seed. */
+  @SuppressWarnings("unchecked")
+  protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
+    for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
+      FieldDescriptor field = entry.getKey();
+      Object value = entry.getValue();
+      hash = (37 * hash) + field.getNumber();
+      if (field.isMapField()) {
+        hash = (53 * hash) + hashMapField(value);
+      } else if (field.getType() != FieldDescriptor.Type.ENUM){
+        hash = (53 * hash) + value.hashCode();
+      } else if (field.isRepeated()) {
+        List<? extends EnumLite> list = (List<? extends EnumLite>) value;
+        hash = (53 * hash) + Internal.hashEnumList(list);
+      } else {
+        hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
+      }
+    }
+    return hash;
+  }
+
+  /**
+   * Package private helper method for AbstractParser to create
+   * UninitializedMessageException with missing field information.
+   */
+  @Override
+  UninitializedMessageException newUninitializedMessageException() {
+    return Builder.newUninitializedMessageException(this);
+  }
+
+  // =================================================================
+
+  /**
+   * A partial implementation of the {@link Message.Builder} interface which
+   * implements as many methods of that interface as possible in terms of
+   * other methods.
+   */
+  @SuppressWarnings("unchecked")
+  public static abstract class Builder<BuilderType extends Builder<BuilderType>>
+      extends AbstractMessageLite.Builder
+      implements Message.Builder {
+    // The compiler produces an error if this is not declared explicitly.
+    @Override
+    public abstract BuilderType clone();
+
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public boolean hasOneof(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException("hasOneof() is not implemented.");
+    }
+
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException(
+          "getOneofFieldDescriptor() is not implemented.");
+    }
+
+    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
+    @Override
+    public BuilderType clearOneof(OneofDescriptor oneof) {
+      throw new UnsupportedOperationException("clearOneof() is not implemented.");
+    }
+
+    @Override
+    public BuilderType clear() {
+      for (final Map.Entry<FieldDescriptor, Object> entry :
+           getAllFields().entrySet()) {
+        clearField(entry.getKey());
+      }
+      return (BuilderType) this;
+    }
+
+    @Override
+    public List<String> findInitializationErrors() {
+      return MessageReflection.findMissingFields(this);
+    }
+
+    @Override
+    public String getInitializationErrorString() {
+      return MessageReflection.delimitWithCommas(findInitializationErrors());
+    }
+    
+    @Override
+    protected BuilderType internalMergeFrom(AbstractMessageLite other) {
+      return mergeFrom((Message) other);
+    }
+
+    @Override
+    public BuilderType mergeFrom(final Message other) {
+      if (other.getDescriptorForType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "mergeFrom(Message) can only merge messages of the same type.");
+      }
+
+      // Note:  We don't attempt to verify that other's fields have valid
+      //   types.  Doing so would be a losing battle.  We'd have to verify
+      //   all sub-messages as well, and we'd have to make copies of all of
+      //   them to insure that they don't change after verification (since
+      //   the Message interface itself cannot enforce immutability of
+      //   implementations).
+      // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
+      //   which allows people to make secure deep copies of messages.
+
+      for (final Map.Entry<FieldDescriptor, Object> entry :
+           other.getAllFields().entrySet()) {
+        final FieldDescriptor field = entry.getKey();
+        if (field.isRepeated()) {
+          for (final Object element : (List)entry.getValue()) {
+            addRepeatedField(field, element);
+          }
+        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          final Message existingValue = (Message)getField(field);
+          if (existingValue == existingValue.getDefaultInstanceForType()) {
+            setField(field, entry.getValue());
+          } else {
+            setField(field,
+              existingValue.newBuilderForType()
+                .mergeFrom(existingValue)
+                .mergeFrom((Message)entry.getValue())
+                .build());
+          }
+        } else {
+          setField(field, entry.getValue());
+        }
+      }
+
+      mergeUnknownFields(other.getUnknownFields());
+
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeFrom(final CodedInputStream input)
+                                 throws IOException {
+      return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final CodedInputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      final UnknownFieldSet.Builder unknownFields =
+        UnknownFieldSet.newBuilder(getUnknownFields());
+      while (true) {
+        final int tag = input.readTag();
+        if (tag == 0) {
+          break;
+        }
+
+        MessageReflection.BuilderAdapter builderAdapter =
+            new MessageReflection.BuilderAdapter(this);
+        if (!MessageReflection.mergeFieldFrom(input, unknownFields,
+                                              extensionRegistry,
+                                              getDescriptorForType(),
+                                              builderAdapter,
+                                              tag)) {
+          // end group tag
+          break;
+        }
+      }
+      setUnknownFields(unknownFields.build());
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
+      setUnknownFields(
+        UnknownFieldSet.newBuilder(getUnknownFields())
+                       .mergeFrom(unknownFields)
+                       .build());
+      return (BuilderType) this;
+    }
+
+    @Override
+    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+      throw new UnsupportedOperationException(
+          "getFieldBuilder() called on an unsupported message type.");
+    }
+
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
+      throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on an unsupported message type.");
+    }
+
+    @Override
+    public String toString() {
+      return TextFormat.printToString(this);
+    }
+
+    /**
+     * Construct an UninitializedMessageException reporting missing fields in
+     * the given message.
+     */
+    protected static UninitializedMessageException
+        newUninitializedMessageException(Message message) {
+      return new UninitializedMessageException(
+          MessageReflection.findMissingFields(message));
+    }
+
+    // ===============================================================
+    // The following definitions seem to be required in order to make javac
+    // not produce weird errors like:
+    //
+    // java/com/google/protobuf/DynamicMessage.java:203: types
+    //   com.google.protobuf.AbstractMessage.Builder<
+    //     com.google.protobuf.DynamicMessage.Builder> and
+    //   com.google.protobuf.AbstractMessage.Builder<
+    //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
+    //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
+    //   return types.
+    //
+    // Strangely, these lines are only needed if javac is invoked separately
+    // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
+    // invoked on both simultaneously, it works.  (Or maybe the important
+    // point is whether or not DynamicMessage.java is compiled together with
+    // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
+    // bug.
+
+    @Override
+    public BuilderType mergeFrom(final ByteString data)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final ByteString data,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data, extensionRegistry);
+    }
+
+    @Override
+    public BuilderType mergeFrom(final byte[] data)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data, final int off, final int len)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data, off, len);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data, extensionRegistry);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data, final int off, final int len,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry);
+    }
+
+    @Override
+    public BuilderType mergeFrom(final InputStream input)
+        throws IOException {
+      return (BuilderType) super.mergeFrom(input);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      return (BuilderType) super.mergeFrom(input, extensionRegistry);
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(final InputStream input)
+        throws IOException {
+      return super.mergeDelimitedFrom(input);
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(
+        final InputStream input,
+        final ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      return super.mergeDelimitedFrom(input, extensionRegistry);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
new file mode 100644
index 0000000..43736dd
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -0,0 +1,386 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+
+/**
+ * A partial implementation of the {@link MessageLite} interface which
+ * implements as many methods of that interface as possible in terms of other
+ * methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessageLite<
+    MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+    BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>> 
+        implements MessageLite {
+  protected int memoizedHashCode = 0;
+  
+  @Override
+  public ByteString toByteString() {
+    try {
+      final ByteString.CodedBuilder out =
+        ByteString.newCodedBuilder(getSerializedSize());
+      writeTo(out.getCodedOutput());
+      return out.build();
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Serializing to a ByteString threw an IOException (should " +
+        "never happen).", e);
+    }
+  }
+
+  @Override
+  public byte[] toByteArray() {
+    try {
+      final byte[] result = new byte[getSerializedSize()];
+      final CodedOutputStream output = CodedOutputStream.newInstance(result);
+      writeTo(output);
+      output.checkNoSpaceLeft();
+      return result;
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Serializing to a byte array threw an IOException " +
+        "(should never happen).", e);
+    }
+  }
+
+  @Override
+  public void writeTo(final OutputStream output) throws IOException {
+    final int bufferSize =
+        CodedOutputStream.computePreferredBufferSize(getSerializedSize());
+    final CodedOutputStream codedOutput =
+        CodedOutputStream.newInstance(output, bufferSize);
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  @Override
+  public void writeDelimitedTo(final OutputStream output) throws IOException {
+    final int serialized = getSerializedSize();
+    final int bufferSize = CodedOutputStream.computePreferredBufferSize(
+        CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
+    final CodedOutputStream codedOutput =
+        CodedOutputStream.newInstance(output, bufferSize);
+    codedOutput.writeRawVarint32(serialized);
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+
+  /**
+   * Package private helper method for AbstractParser to create
+   * UninitializedMessageException.
+   */
+  UninitializedMessageException newUninitializedMessageException() {
+    return new UninitializedMessageException(this);
+  }
+
+  protected static void checkByteStringIsUtf8(ByteString byteString)
+      throws IllegalArgumentException {
+    if (!byteString.isValidUtf8()) {
+      throw new IllegalArgumentException("Byte string is not UTF-8.");
+    }
+  }
+
+  protected static <T> void addAll(final Iterable<T> values,
+      final Collection<? super T> list) {
+    Builder.addAll(values, list);
+  }
+  
+  /**
+   * A partial implementation of the {@link Message.Builder} interface which
+   * implements as many methods of that interface as possible in terms of
+   * other methods.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder<
+      MessageType extends AbstractMessageLite<MessageType, BuilderType>,
+      BuilderType extends Builder<MessageType, BuilderType>>
+      implements MessageLite.Builder {
+    // The compiler produces an error if this is not declared explicitly.
+    @Override
+    public abstract BuilderType clone();
+
+    @Override
+    public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
+      return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
+    }
+
+    // Re-defined here for return type covariance.
+    @Override
+    public abstract BuilderType mergeFrom(
+        final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+
+    @Override
+    public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = data.newCodedInput();
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a ByteString threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final ByteString data, final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = data.newCodedInput();
+        mergeFrom(input, extensionRegistry);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a ByteString threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    @Override
+    public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
+      return mergeFrom(data, 0, data.length);
+    }
+
+    @Override
+    public BuilderType mergeFrom(final byte[] data, final int off, final int len)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    @Override
+    public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return mergeFrom(data, 0, data.length, extensionRegistry);
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final byte[] data,
+        final int off,
+        final int len,
+        final ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input, extensionRegistry);
+        input.checkLastTagWas(0);
+        return (BuilderType) this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    @Override
+    public BuilderType mergeFrom(final InputStream input) throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+      mergeFrom(codedInput);
+      codedInput.checkLastTagWas(0);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeFrom(
+        final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+      mergeFrom(codedInput, extensionRegistry);
+      codedInput.checkLastTagWas(0);
+      return (BuilderType) this;
+    }
+
+    /**
+     * An InputStream implementations which reads from some other InputStream
+     * but is limited to a particular number of bytes.  Used by
+     * mergeDelimitedFrom().  This is intentionally package-private so that
+     * UnknownFieldSet can share it.
+     */
+    static final class LimitedInputStream extends FilterInputStream {
+      private int limit;
+
+      LimitedInputStream(InputStream in, int limit) {
+        super(in);
+        this.limit = limit;
+      }
+
+      @Override
+      public int available() throws IOException {
+        return Math.min(super.available(), limit);
+      }
+
+      @Override
+      public int read() throws IOException {
+        if (limit <= 0) {
+          return -1;
+        }
+        final int result = super.read();
+        if (result >= 0) {
+          --limit;
+        }
+        return result;
+      }
+
+      @Override
+      public int read(final byte[] b, final int off, int len)
+                      throws IOException {
+        if (limit <= 0) {
+          return -1;
+        }
+        len = Math.min(len, limit);
+        final int result = super.read(b, off, len);
+        if (result >= 0) {
+          limit -= result;
+        }
+        return result;
+      }
+
+      @Override
+      public long skip(final long n) throws IOException {
+        final long result = super.skip(Math.min(n, limit));
+        if (result >= 0) {
+          limit -= result;
+        }
+        return result;
+      }
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(
+        final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
+      final int firstByte = input.read();
+      if (firstByte == -1) {
+        return false;
+      }
+      final int size = CodedInputStream.readRawVarint32(firstByte, input);
+      final InputStream limitedInput = new LimitedInputStream(input, size);
+      mergeFrom(limitedInput, extensionRegistry);
+      return true;
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
+      return mergeDelimitedFrom(input,
+          ExtensionRegistryLite.getEmptyRegistry());
+    }
+    
+    @Override
+    @SuppressWarnings("unchecked") // isInstance takes care of this
+    public BuilderType mergeFrom(final MessageLite other) {
+      if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+        throw new IllegalArgumentException(
+            "mergeFrom(MessageLite) can only merge messages of the same type.");
+      }
+        
+      return internalMergeFrom((MessageType) other);
+    }
+    
+    protected abstract BuilderType internalMergeFrom(MessageType message);
+
+    /**
+     * Construct an UninitializedMessageException reporting missing fields in
+     * the given message.
+     */
+    protected static UninitializedMessageException
+        newUninitializedMessageException(MessageLite message) {
+      return new UninitializedMessageException(message);
+    }
+
+    /**
+     * Adds the {@code values} to the {@code list}.  This is a helper method
+     * used by generated code.  Users should ignore it.
+     *
+     * @throws NullPointerException if {@code values} or any of the elements of
+     * {@code values} is null. When that happens, some elements of
+     * {@code values} may have already been added to the result {@code list}.
+     */
+    protected static <T> void addAll(final Iterable<T> values,
+                                     final Collection<? super T> list) {
+      if (values == null) {
+        throw new NullPointerException();
+      }
+      if (values instanceof LazyStringList) {
+        // For StringOrByteStringLists, check the underlying elements to avoid
+        // forcing conversions of ByteStrings to Strings.
+        checkForNullValues(((LazyStringList) values).getUnderlyingElements());
+        list.addAll((Collection<T>) values);
+      } else if (values instanceof Collection) {
+        checkForNullValues(values);
+        list.addAll((Collection<T>) values);
+      } else {
+        for (final T value : values) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          list.add(value);
+        }
+      }
+    }
+
+    private static void checkForNullValues(final Iterable<?> values) {
+      for (final Object value : values) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+      }
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
new file mode 100644
index 0000000..66b0ee3
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
@@ -0,0 +1,258 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A partial implementation of the {@link Parser} interface which implements
+ * as many methods of that interface as possible in terms of other methods.
+ *
+ * Note: This class implements all the convenience methods in the
+ * {@link Parser} interface. See {@link Parser} for related javadocs.
+ * Subclasses need to implement
+ * {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public abstract class AbstractParser<MessageType extends MessageLite>
+    implements Parser<MessageType> {
+  /**
+   * Creates an UninitializedMessageException for MessageType.
+   */
+  private UninitializedMessageException
+      newUninitializedMessageException(MessageType message) {
+    if (message instanceof AbstractMessageLite) {
+      return ((AbstractMessageLite) message).newUninitializedMessageException();
+    }
+    return new UninitializedMessageException(message);
+  }
+
+  /**
+   * Helper method to check if message is initialized.
+   *
+   * @throws InvalidProtocolBufferException if it is not initialized.
+   * @return The message to check.
+   */
+  private MessageType checkMessageInitialized(MessageType message)
+      throws InvalidProtocolBufferException {
+    if (message != null && !message.isInitialized()) {
+      throw newUninitializedMessageException(message)
+          .asInvalidProtocolBufferException()
+          .setUnfinishedMessage(message);
+    }
+    return message;
+  }
+
+  private static final ExtensionRegistryLite EMPTY_REGISTRY
+      = ExtensionRegistryLite.getEmptyRegistry();
+
+  @Override
+  public MessageType parsePartialFrom(CodedInputStream input)
+      throws InvalidProtocolBufferException {
+    return parsePartialFrom(input, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(input, extensionRegistry));
+  }
+
+  @Override
+  public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException {
+    return parseFrom(input, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    MessageType message;
+    try {
+      CodedInputStream input = data.newCodedInput();
+      message = parsePartialFrom(input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
+  }
+
+  @Override
+  public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException {
+    return parsePartialFrom(data, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
+  }
+
+  @Override
+  public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException {
+    return parseFrom(data, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(
+      byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    try {
+      CodedInputStream input = CodedInputStream.newInstance(data, off, len);
+      MessageType message = parsePartialFrom(input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
+  }
+
+  @Override
+  public MessageType parsePartialFrom(byte[] data, int off, int len)
+      throws InvalidProtocolBufferException {
+    return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return parsePartialFrom(data, 0, data.length, extensionRegistry);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException {
+    return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseFrom(
+      byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(data, off, len, extensionRegistry));
+  }
+
+  @Override
+  public MessageType parseFrom(byte[] data, int off, int len)
+      throws InvalidProtocolBufferException {
+    return parseFrom(data, off, len, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return parseFrom(data, 0, data.length, extensionRegistry);
+  }
+
+  @Override
+  public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException {
+    return parseFrom(data, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    CodedInputStream codedInput = CodedInputStream.newInstance(input);
+    MessageType message = parsePartialFrom(codedInput, extensionRegistry);
+    try {
+      codedInput.checkLastTagWas(0);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(message);
+    }
+    return message;
+  }
+
+  @Override
+  public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException {
+    return parsePartialFrom(input, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(input, extensionRegistry));
+  }
+
+  @Override
+  public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException {
+    return parseFrom(input, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parsePartialDelimitedFrom(
+      InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    int size;
+    try {
+      int firstByte = input.read();
+      if (firstByte == -1) {
+        return null;
+      }
+      size = CodedInputStream.readRawVarint32(firstByte, input);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e.getMessage());
+    }
+    InputStream limitedInput = new LimitedInputStream(input, size);
+    return parsePartialFrom(limitedInput, extensionRegistry);
+  }
+
+  @Override
+  public MessageType parsePartialDelimitedFrom(InputStream input)
+      throws InvalidProtocolBufferException {
+    return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
+  }
+
+  @Override
+  public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialDelimitedFrom(input, extensionRegistry));
+  }
+
+  @Override
+  public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException {
+    return parseDelimitedFrom(input, EMPTY_REGISTRY);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
new file mode 100644
index 0000000..b17db6e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
@@ -0,0 +1,180 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.ProtobufList;
+
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
+ * methods must check if the list is mutable before proceeding. Subclasses must invoke
+ * {@link #ensureIsMutable()} manually when overriding those methods.
+ * <p>
+ * This implementation assumes all subclasses are array based, supporting random access.
+ */
+abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
+
+  protected static final int DEFAULT_CAPACITY = 10;
+
+  /**
+   * Whether or not this list is modifiable.
+   */
+  private boolean isMutable;
+
+  /**
+   * Constructs a mutable list by default.
+   */
+  AbstractProtobufList() {
+    isMutable = true;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof List)) {
+      return false;
+    }
+    // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator
+    // based approach in our super class. Otherwise our index based approach will avoid those
+    // allocations.
+    if (!(o instanceof RandomAccess)) {
+      return super.equals(o);
+    }
+
+    List<?> other = (List<?>) o;
+    final int size = size();
+    if (size != other.size()) {
+      return false;
+    }
+    for (int i = 0; i < size; i++) {
+      if (!get(i).equals(other.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    final int size = size();
+    int hashCode = 1;
+    for (int i = 0; i < size; i++) {
+      hashCode = (31 * hashCode) + get(i).hashCode();
+    }
+    return hashCode;
+  }
+
+  @Override
+  public boolean add(E e) {
+    ensureIsMutable();
+    return super.add(e);
+  }
+
+  @Override
+  public void add(int index, E element) {
+    ensureIsMutable();
+    super.add(index, element);
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends E> c) {
+    ensureIsMutable();
+    return super.addAll(c);
+  }
+  
+  @Override
+  public boolean addAll(int index, Collection<? extends E> c) {
+    ensureIsMutable();
+    return super.addAll(index, c);
+  }
+
+  @Override
+  public void clear() {
+    ensureIsMutable();
+    super.clear();
+  }
+  
+  @Override
+  public boolean isModifiable() {
+    return isMutable;
+  }
+  
+  @Override
+  public final void makeImmutable() {
+    isMutable = false;
+  }
+  
+  @Override
+  public E remove(int index) {
+    ensureIsMutable();
+    return super.remove(index);
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    return super.remove(o);
+  }
+  
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    ensureIsMutable();
+    return super.removeAll(c);
+  }
+  
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    ensureIsMutable();
+    return super.retainAll(c);
+  }
+  
+  @Override
+  public E set(int index, E element) {
+    ensureIsMutable();
+    return super.set(index, element);
+  }
+  
+  /**
+   * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are
+   * responsible for invoking this method on mutate operations.
+   */
+  protected void ensureIsMutable() {
+    if (!isMutable) {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
rename to java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java
diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/core/src/main/java/com/google/protobuf/BlockingService.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/BlockingService.java
rename to java/core/src/main/java/com/google/protobuf/BlockingService.java
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
new file mode 100644
index 0000000..8b2820b
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -0,0 +1,270 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.BooleanList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link BooleanList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class BooleanArrayList
+    extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess {
+  
+  private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static BooleanArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private boolean[] array;
+
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList} with default capacity.
+   */
+  BooleanArrayList() {
+    this(new boolean[DEFAULT_CAPACITY], 0);
+  }
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList}.
+   */
+  private BooleanArrayList(boolean[] array, int size) {
+    this.array = array;
+    this.size = size;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof BooleanArrayList)) {
+      return super.equals(o);
+    }
+    BooleanArrayList other = (BooleanArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+    
+    final boolean[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
+      }
+    }
+    
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Internal.hashBoolean(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public BooleanList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new BooleanArrayList(Arrays.copyOf(array, capacity), size);
+  }
+
+  @Override
+  public Boolean get(int index) {
+    return getBoolean(index);
+  }
+
+  @Override
+  public boolean getBoolean(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Boolean set(int index, Boolean element) {
+    return setBoolean(index, element);
+  }
+
+  @Override
+  public boolean setBoolean(int index, boolean element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    boolean previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Boolean element) {
+    addBoolean(index, element);
+  }
+
+  /**
+   * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addBoolean(boolean element) {
+    addBoolean(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element.
+   */
+  private void addBoolean(int index, boolean element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      boolean[] newArray = new boolean[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Boolean> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another BooleanArrayList to avoid boxing elements.
+    if (!(collection instanceof BooleanArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    BooleanArrayList list = (BooleanArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Boolean remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    boolean value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
new file mode 100644
index 0000000..0cc3817
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
@@ -0,0 +1,145 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+
+/**
+ * Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s.
+ */
+final class ByteBufferWriter {
+  private ByteBufferWriter() {}
+
+  /**
+   * Minimum size for a cached buffer. This prevents us from allocating buffers that are too
+   * small to be easily reused.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final int MIN_CACHED_BUFFER_SIZE = 1024;
+
+  /**
+   * Maximum size for a cached buffer. If a larger buffer is required, it will be allocated
+   * but not cached.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
+
+  /**
+   * The fraction of the requested buffer size under which the buffer will be reallocated.
+   */
+  // TODO(nathanmittler): tune this property or allow configuration?
+  private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
+
+  /**
+   * Keeping a soft reference to a thread-local buffer. This buffer is used for writing a
+   * {@link ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available.
+   * Using a "soft" reference since VMs may keep this reference around longer than "weak"
+   * (e.g. HotSpot will maintain soft references until memory pressure warrants collection).
+   */
+  private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
+      new ThreadLocal<SoftReference<byte[]>>();
+
+  /**
+   * For testing purposes only. Clears the cached buffer to force a new allocation on the next
+   * invocation.
+   */
+  static void clearCachedBuffer() {
+    BUFFER.set(null);
+  }
+
+  /**
+   * Writes the remaining content of the buffer to the given stream. The buffer {@code position}
+   * will remain unchanged by this method.
+   */
+  static void write(ByteBuffer buffer, OutputStream output) throws IOException {
+    final int initialPos = buffer.position();
+    try {
+      if (buffer.hasArray()) {
+        // Optimized write for array-backed buffers.
+        // Note that we're taking the risk that a malicious OutputStream could modify the array.
+        output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
+      } else if (output instanceof FileOutputStream) {
+        // Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
+        ((FileOutputStream) output).getChannel().write(buffer);
+      } else {
+        // Read all of the data from the buffer to an array.
+        // TODO(nathanmittler): Consider performance improvements for other "known" stream types.
+        final byte[] array = getOrCreateBuffer(buffer.remaining());
+        while (buffer.hasRemaining()) {
+          int length = min(buffer.remaining(), array.length);
+          buffer.get(array, 0, length);
+          output.write(array, 0, length);
+        }
+      }
+    } finally {
+      // Restore the initial position.
+      buffer.position(initialPos);
+    }
+  }
+
+  private static byte[] getOrCreateBuffer(int requestedSize) {
+    requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
+
+    byte[] buffer = getBuffer();
+    // Only allocate if we need to.
+    if (buffer == null || needToReallocate(requestedSize, buffer.length)) {
+      buffer = new byte[requestedSize];
+
+      // Only cache the buffer if it's not too big.
+      if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
+        setBuffer(buffer);
+      }
+    }
+    return buffer;
+  }
+
+  private static boolean needToReallocate(int requestedSize, int bufferLength) {
+    // First check against just the requested length to avoid the multiply.
+    return bufferLength < requestedSize
+        && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
+  }
+
+  private static byte[] getBuffer() {
+    SoftReference<byte[]> sr = BUFFER.get();
+    return sr == null ? null : sr.get();
+  }
+
+  private static void setBuffer(byte[] value) {
+    BUFFER.set(new SoftReference<byte[]>(value));
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteOutput.java b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
new file mode 100644
index 0000000..8b7b04c
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
@@ -0,0 +1,116 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * An output target for raw bytes. This interface provides semantics that support two types of
+ * writing:
+ *
+ * <p/><b>Traditional write operations:</b>
+ * (as defined by {@link java.io.OutputStream}) where the target method is responsible for either
+ * copying the data or completing the write before returning from the method call.
+ *
+ * <p/><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
+ * provided buffer and it can therefore be considered immutable. The target method is free to
+ * maintain a reference to the buffer beyond the scope of the method call (e.g. until the write
+ * operation completes).
+ */
+@ExperimentalApi
+public abstract class ByteOutput {
+  /**
+   * Writes a single byte.
+   *
+   * @param value the byte to be written
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(byte value) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+   * not be processed prior to the return of this method call, since {@code value} may be
+   * reused/altered by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written
+   * @param offset the offset of the start of the writable range
+   * @param length the number of bytes to write starting from {@code offset}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(byte[] value, int offset, int length) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+   * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+   * guaranteed not to change by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written
+   * @param offset the offset of the start of the writable range
+   * @param length the number of bytes to write starting from {@code offset}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will
+   * not be processed prior to the return of this method call, since {@code value} may be
+   * reused/altered by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+   * this buffer will be set to the {@code limit}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void write(ByteBuffer value) throws IOException;
+
+  /**
+   * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value
+   * beyond the scope of this method call (e.g. write later) since it is considered immutable and is
+   * guaranteed not to change by the caller.
+   *
+   * <p>NOTE: This method <strong>MUST NOT</strong> modify the {@code value}. Doing so is a
+   * programming error and will lead to data corruption which will be difficult to debug.
+   *
+   * @param value the bytes to be written. Upon returning from this call, the {@code position} of
+   * this buffer will be set to the {@code limit}
+   * @throws IOException thrown if an error occurred while writing
+   */
+  public abstract void writeLazy(ByteBuffer value) throws IOException;
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
new file mode 100644
index 0000000..62c9450
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -0,0 +1,1544 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Immutable sequence of bytes.  Substring is supported by sharing the reference
+ * to the immutable underlying bytes, as with {@link String}.  Concatenation is
+ * likewise supported without copying (long strings) by building a tree of
+ * pieces in {@link RopeByteString}.
+ * <p>
+ * Like {@link String}, the contents of a {@link ByteString} can never be
+ * observed to change, not even in the presence of a data race or incorrect
+ * API usage in the client code.
+ *
+ * @author crazybob@google.com Bob Lee
+ * @author kenton@google.com Kenton Varda
+ * @author carlanton@google.com Carl Haverl
+ * @author martinrb@google.com Martin Buchholz
+ */
+public abstract class ByteString implements Iterable<Byte>, Serializable {
+
+  /**
+   * When two strings to be concatenated have a combined length shorter than
+   * this, we just copy their bytes on {@link #concat(ByteString)}.
+   * The trade-off is copy size versus the overhead of creating tree nodes
+   * in {@link RopeByteString}.
+   */
+  static final int CONCATENATE_BY_COPY_SIZE = 128;
+
+  /**
+   * When copying an InputStream into a ByteString with .readFrom(),
+   * the chunks in the underlying rope start at 256 bytes, but double
+   * each iteration up to 8192 bytes.
+   */
+  static final int MIN_READ_FROM_CHUNK_SIZE = 0x100;  // 256b
+  static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000;  // 8k
+
+  /**
+   * Empty {@code ByteString}.
+   */
+  public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
+  
+  /** 
+   * An interface to efficiently copy {@code byte[]}.
+   * 
+   * <p>One of the noticable costs of copying a byte[] into a new array using 
+   * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown 
+   * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this
+   * expensive nullification and provide substantial performance gain. Unfortunately this does not
+   * hold on Android runtimes and could make the copy slightly slower due to additional code in
+   * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier
+   * for Hotspot and Android runtimes. 
+   */
+  private interface ByteArrayCopier {
+    /**
+     * Copies the specified range of the specified array into a new array
+     */
+    byte[] copyFrom(byte[] bytes, int offset, int size);
+  }
+  
+  /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */
+  private static final class SystemByteArrayCopier implements ByteArrayCopier {
+    @Override
+    public byte[] copyFrom(byte[] bytes, int offset, int size) {
+      byte[] copy = new byte[size];
+      System.arraycopy(bytes, offset, copy, 0, size);
+      return copy;
+    }
+  }
+  
+  /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */
+  private static final class ArraysByteArrayCopier implements ByteArrayCopier {
+    @Override
+    public byte[] copyFrom(byte[] bytes, int offset, int size) {
+      return Arrays.copyOfRange(bytes, offset, offset + size);
+    }
+  }
+  
+  private static final ByteArrayCopier byteArrayCopier;
+  static {
+    boolean isAndroid = true;
+    try {
+      Class.forName("android.content.Context");
+    } catch (ClassNotFoundException e) {
+      isAndroid = false;
+    }
+    
+    byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
+  }
+
+  /**
+   * Cached hash value. Intentionally accessed via a data race, which
+   * is safe because of the Java Memory Model's "no out-of-thin-air values"
+   * guarantees for ints. A value of 0 implies that the hash has not been set.
+   */
+  private int hash = 0;
+
+  // This constructor is here to prevent subclassing outside of this package,
+  ByteString() {}
+
+  /**
+   * Gets the byte at the given index. This method should be used only for
+   * random access to individual bytes. To access bytes sequentially, use the
+   * {@link ByteIterator} returned by {@link #iterator()}, and call {@link
+   * #substring(int, int)} first if necessary.
+   *
+   * @param index index of byte
+   * @return the value
+   * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
+   */
+  public abstract byte byteAt(int index);
+
+  /**
+   * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString.
+   * To avoid auto-boxing, you may get the iterator manually and call
+   * {@link ByteIterator#nextByte()}.
+   *
+   * @return the iterator
+   */
+  @Override
+  public final ByteIterator iterator() {
+    return new ByteIterator() {
+      private int position = 0;
+      private final int limit = size();
+
+      @Override
+      public boolean hasNext() {
+        return position < limit;
+      }
+
+      @Override
+      public Byte next() {
+        // Boxing calls Byte.valueOf(byte), which does not instantiate.
+        return nextByte();
+      }
+
+      @Override
+      public byte nextByte() {
+        try {
+          return byteAt(position++);
+        } catch (IndexOutOfBoundsException e) {
+          throw new NoSuchElementException(e.getMessage());
+        }
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  /**
+   * This interface extends {@code Iterator<Byte>}, so that we can return an
+   * unboxed {@code byte}.
+   */
+  public interface ByteIterator extends Iterator<Byte> {
+    /**
+     * An alternative to {@link Iterator#next()} that returns an
+     * unboxed primitive {@code byte}.
+     *
+     * @return the next {@code byte} in the iteration
+     * @throws NoSuchElementException if the iteration has no more elements
+     */
+    byte nextByte();
+  }
+
+  /**
+   * Gets the number of bytes.
+   *
+   * @return size in bytes
+   */
+  public abstract int size();
+
+  /**
+   * Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
+   *
+   * @return true if this is zero bytes long
+   */
+  public final boolean isEmpty() {
+    return size() == 0;
+  }
+
+  // =================================================================
+  // ByteString -> substring
+
+  /**
+   * Return the substring from {@code beginIndex}, inclusive, to the end of the
+   * string.
+   *
+   * @param beginIndex start at this index
+   * @return substring sharing underlying data
+   * @throws IndexOutOfBoundsException if {@code beginIndex < 0} or
+   *     {@code beginIndex > size()}.
+   */
+  public final ByteString substring(int beginIndex) {
+    return substring(beginIndex, size());
+  }
+
+  /**
+   * Return the substring from {@code beginIndex}, inclusive, to {@code
+   * endIndex}, exclusive.
+   *
+   * @param beginIndex start at this index
+   * @param endIndex   the last character is the one before this index
+   * @return substring sharing underlying data
+   * @throws IndexOutOfBoundsException if {@code beginIndex < 0},
+   *     {@code endIndex > size()}, or {@code beginIndex > endIndex}.
+   */
+  public abstract ByteString substring(int beginIndex, int endIndex);
+
+  /**
+   * Tests if this bytestring starts with the specified prefix.
+   * Similar to {@link String#startsWith(String)}
+   *
+   * @param prefix the prefix.
+   * @return <code>true</code> if the byte sequence represented by the
+   *         argument is a prefix of the byte sequence represented by
+   *         this string; <code>false</code> otherwise.
+   */
+  public final boolean startsWith(ByteString prefix) {
+    return size() >= prefix.size() &&
+           substring(0, prefix.size()).equals(prefix);
+  }
+
+  /**
+   * Tests if this bytestring ends with the specified suffix.
+   * Similar to {@link String#endsWith(String)}
+   *
+   * @param suffix the suffix.
+   * @return <code>true</code> if the byte sequence represented by the
+   *         argument is a suffix of the byte sequence represented by
+   *         this string; <code>false</code> otherwise.
+   */
+  public final boolean endsWith(ByteString suffix) {
+    return size() >= suffix.size() &&
+        substring(size() - suffix.size()).equals(suffix);
+  }
+
+  // =================================================================
+  // byte[] -> ByteString
+
+  /**
+   * Copies the given bytes into a {@code ByteString}.
+   *
+   * @param bytes source array
+   * @param offset offset in source array
+   * @param size number of bytes to copy
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(byte[] bytes, int offset, int size) {
+    return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
+  }
+
+  /**
+   * Copies the given bytes into a {@code ByteString}.
+   *
+   * @param bytes to copy
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(byte[] bytes) {
+    return copyFrom(bytes, 0, bytes.length);
+  }
+  
+  /**
+   * Wraps the given bytes into a {@code ByteString}. Intended for internal only
+   * usage to force a classload of ByteString before LiteralByteString.
+   */
+  static ByteString wrap(byte[] bytes) {
+    // TODO(dweis): Return EMPTY when bytes are empty to reduce allocations?
+    return new LiteralByteString(bytes);
+  }
+
+  /**
+   * Wraps the given bytes into a {@code ByteString}. Intended for internal only
+   * usage to force a classload of ByteString before BoundedByteString and
+   * LiteralByteString.
+   */
+  static ByteString wrap(byte[] bytes, int offset, int length) {
+    return new BoundedByteString(bytes, offset, length);
+  }
+
+  /**
+   * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
+   * a {@code ByteString}.
+   *
+   * @param bytes source buffer
+   * @param size number of bytes to copy
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(ByteBuffer bytes, int size) {
+    byte[] copy = new byte[size];
+    bytes.get(copy);
+    return new LiteralByteString(copy);
+  }
+
+  /**
+   * Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
+   * a {@code ByteString}.
+   *
+   * @param bytes sourceBuffer
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(ByteBuffer bytes) {
+    return copyFrom(bytes, bytes.remaining());
+  }
+
+  /**
+   * Encodes {@code text} into a sequence of bytes using the named charset
+   * and returns the result as a {@code ByteString}.
+   *
+   * @param text source string
+   * @param charsetName encoding to use
+   * @return new {@code ByteString}
+   * @throws UnsupportedEncodingException if the encoding isn't found
+   */
+  public static ByteString copyFrom(String text, String charsetName)
+      throws UnsupportedEncodingException {
+    return new LiteralByteString(text.getBytes(charsetName));
+  }
+
+  /**
+   * Encodes {@code text} into a sequence of bytes using the named charset
+   * and returns the result as a {@code ByteString}.
+   *
+   * @param text source string
+   * @param charset encode using this charset
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(String text, Charset charset) {
+    return new LiteralByteString(text.getBytes(charset));
+  }
+
+  /**
+   * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
+   * result as a {@code ByteString}.
+   *
+   * @param text source string
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFromUtf8(String text) {
+    return new LiteralByteString(text.getBytes(Internal.UTF_8));
+  }
+
+  // =================================================================
+  // InputStream -> ByteString
+
+  /**
+   * Completely reads the given stream's bytes into a
+   * {@code ByteString}, blocking if necessary until all bytes are
+   * read through to the end of the stream.
+   *
+   * <b>Performance notes:</b> The returned {@code ByteString} is an
+   * immutable tree of byte arrays ("chunks") of the stream data.  The
+   * first chunk is small, with subsequent chunks each being double
+   * the size, up to 8K.
+   * 
+   * <p>Each byte read from the input stream will be copied twice to ensure
+   * that the resulting ByteString is truly immutable.
+   *
+   * @param streamToDrain The source stream, which is read completely
+   *     but not closed.
+   * @return A new {@code ByteString} which is made up of chunks of
+   *     various sizes, depending on the behavior of the underlying
+   *     stream.
+   * @throws IOException IOException is thrown if there is a problem
+   *     reading the underlying stream.
+   */
+  public static ByteString readFrom(InputStream streamToDrain)
+      throws IOException {
+    return readFrom(streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
+  }
+
+  /**
+   * Completely reads the given stream's bytes into a
+   * {@code ByteString}, blocking if necessary until all bytes are
+   * read through to the end of the stream.
+   *
+   * <b>Performance notes:</b> The returned {@code ByteString} is an
+   * immutable tree of byte arrays ("chunks") of the stream data.  The
+   * chunkSize parameter sets the size of these byte arrays.
+   *
+   * <p>Each byte read from the input stream will be copied twice to ensure
+   * that the resulting ByteString is truly immutable.
+   *
+   * @param streamToDrain The source stream, which is read completely
+   *     but not closed.
+   * @param chunkSize The size of the chunks in which to read the
+   *     stream.
+   * @return A new {@code ByteString} which is made up of chunks of
+   *     the given size.
+   * @throws IOException IOException is thrown if there is a problem
+   *     reading the underlying stream.
+   */
+  public static ByteString readFrom(InputStream streamToDrain, int chunkSize)
+      throws IOException {
+    return readFrom(streamToDrain, chunkSize, chunkSize);
+  }
+
+  // Helper method that takes the chunk size range as a parameter.
+  public static ByteString readFrom(InputStream streamToDrain, int minChunkSize,
+      int maxChunkSize) throws IOException {
+    Collection<ByteString> results = new ArrayList<ByteString>();
+
+    // copy the inbound bytes into a list of chunks; the chunk size
+    // grows exponentially to support both short and long streams.
+    int chunkSize = minChunkSize;
+    while (true) {
+      ByteString chunk = readChunk(streamToDrain, chunkSize);
+      if (chunk == null) {
+        break;
+      }
+      results.add(chunk);
+      chunkSize = Math.min(chunkSize * 2, maxChunkSize);
+    }
+
+    return ByteString.copyFrom(results);
+  }
+
+  /**
+   * Blocks until a chunk of the given size can be made from the
+   * stream, or EOF is reached.  Calls read() repeatedly in case the
+   * given stream implementation doesn't completely fill the given
+   * buffer in one read() call.
+   *
+   * @return A chunk of the desired size, or else a chunk as large as
+   * was available when end of stream was reached. Returns null if the
+   * given stream had no more data in it.
+   */
+  private static ByteString readChunk(InputStream in, final int chunkSize)
+      throws IOException {
+      final byte[] buf = new byte[chunkSize];
+      int bytesRead = 0;
+      while (bytesRead < chunkSize) {
+        final int count = in.read(buf, bytesRead, chunkSize - bytesRead);
+        if (count == -1) {
+          break;
+        }
+        bytesRead += count;
+      }
+
+      if (bytesRead == 0) {
+        return null;
+      }
+
+      // Always make a copy since InputStream could steal a reference to buf.
+      return ByteString.copyFrom(buf, 0, bytesRead);
+  }
+
+  // =================================================================
+  // Multiple ByteStrings -> One ByteString
+
+  /**
+   * Concatenate the given {@code ByteString} to this one. Short concatenations,
+   * of total size smaller than {@link ByteString#CONCATENATE_BY_COPY_SIZE}, are
+   * produced by copying the underlying bytes (as per Rope.java, <a
+   * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+   * BAP95 </a>. In general, the concatenate involves no copying.
+   *
+   * @param other string to concatenate
+   * @return a new {@code ByteString} instance
+   */
+  public final ByteString concat(ByteString other) {
+    if (Integer.MAX_VALUE - size() < other.size()) {
+      throw new IllegalArgumentException("ByteString would be too long: " +
+          size() + "+" + other.size());
+    }
+
+    return RopeByteString.concatenate(this, other);
+  }
+
+  /**
+   * Concatenates all byte strings in the iterable and returns the result.
+   * This is designed to run in O(list size), not O(total bytes).
+   *
+   * <p>The returned {@code ByteString} is not necessarily a unique object.
+   * If the list is empty, the returned object is the singleton empty
+   * {@code ByteString}.  If the list has only one element, that
+   * {@code ByteString} will be returned without copying.
+   *
+   * @param byteStrings strings to be concatenated
+   * @return new {@code ByteString}
+   */
+  public static ByteString copyFrom(Iterable<ByteString> byteStrings) {
+    // Determine the size;
+    final int size;
+    if (!(byteStrings instanceof Collection)) {
+      int tempSize = 0;
+      for (Iterator<ByteString> iter = byteStrings.iterator(); iter.hasNext();
+          iter.next(), ++tempSize) {
+      }
+      size = tempSize;
+    } else {
+      size = ((Collection<ByteString>) byteStrings).size();
+    }
+
+    if (size == 0) {
+      return EMPTY;
+    }
+
+    return balancedConcat(byteStrings.iterator(), size);
+  }
+
+  // Internal function used by copyFrom(Iterable<ByteString>).
+  // Create a balanced concatenation of the next "length" elements from the
+  // iterable.
+  private static ByteString balancedConcat(Iterator<ByteString> iterator, int length) {
+    assert length >= 1;
+    ByteString result;
+    if (length == 1) {
+      result = iterator.next();
+    } else {
+      int halfLength = length >>> 1;
+      ByteString left = balancedConcat(iterator, halfLength);
+      ByteString right = balancedConcat(iterator, length - halfLength);
+      result = left.concat(right);
+    }
+    return result;
+  }
+
+  // =================================================================
+  // ByteString -> byte[]
+
+  /**
+   * Copies bytes into a buffer at the given offset.
+   *
+   * @param target buffer to copy into
+   * @param offset in the target buffer
+   * @throws IndexOutOfBoundsException if the offset is negative or too large
+   */
+  public void copyTo(byte[] target, int offset) {
+    copyTo(target, 0, offset, size());
+  }
+
+  /**
+   * Copies bytes into a buffer.
+   *
+   * @param target       buffer to copy into
+   * @param sourceOffset offset within these bytes
+   * @param targetOffset offset within the target buffer
+   * @param numberToCopy number of bytes to copy
+   * @throws IndexOutOfBoundsException if an offset or size is negative or too
+   *     large
+   */
+  public final void copyTo(byte[] target, int sourceOffset, int targetOffset,
+      int numberToCopy) {
+    checkRange(sourceOffset, sourceOffset + numberToCopy, size());
+    checkRange(targetOffset, targetOffset + numberToCopy, target.length);
+    if (numberToCopy > 0) {
+      copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
+    }
+  }
+
+  /**
+   * Internal (package private) implementation of
+   * {@link #copyTo(byte[],int,int,int)}.
+   * It assumes that all error checking has already been performed and that
+   * {@code numberToCopy > 0}.
+   */
+  protected abstract void copyToInternal(byte[] target, int sourceOffset,
+      int targetOffset, int numberToCopy);
+
+  /**
+   * Copies bytes into a ByteBuffer.
+   *
+   * @param target ByteBuffer to copy into.
+   * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
+   * @throws java.nio.BufferOverflowException if the {@code target}'s
+   *     remaining() space is not large enough to hold the data.
+   */
+  public abstract void copyTo(ByteBuffer target);
+
+  /**
+   * Copies bytes to a {@code byte[]}.
+   *
+   * @return copied bytes
+   */
+  public final byte[] toByteArray() {
+    final int size = size();
+    if (size == 0) {
+      return Internal.EMPTY_BYTE_ARRAY;
+    }
+    byte[] result = new byte[size];
+    copyToInternal(result, 0, 0, size);
+    return result;
+  }
+
+  /**
+   * Writes a copy of the contents of this byte string to the specified output stream argument.
+   *
+   * @param  out  the output stream to which to write the data.
+   * @throws IOException  if an I/O error occurs.
+   */
+  public abstract void writeTo(OutputStream out) throws IOException;
+
+  /**
+   * Writes a specified part of this byte string to an output stream.
+   *
+   * @param  out  the output stream to which to write the data.
+   * @param  sourceOffset offset within these bytes
+   * @param  numberToWrite number of bytes to write
+   * @throws IOException  if an I/O error occurs.
+   * @throws IndexOutOfBoundsException if an offset or size is negative or too large
+   */
+  final void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
+      throws IOException {
+    checkRange(sourceOffset, sourceOffset + numberToWrite, size());
+    if (numberToWrite > 0) {
+      writeToInternal(out, sourceOffset, numberToWrite);
+    }
+  }
+
+  /**
+   * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes
+   * all error checking has already been done.
+   */
+  abstract void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite)
+      throws IOException;
+
+  /**
+   * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling
+   * this method may result in multiple operations on the target {@link ByteOutput}.
+   *
+   * <p>This method may expose internal backing buffers of the {@link ByteString} to the {@link
+   * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+   * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+   *
+   * @param  byteOutput  the output target to receive the bytes
+   * @throws IOException  if an I/O error occurs
+   * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput)
+   */
+  abstract void writeTo(ByteOutput byteOutput) throws IOException;
+
+  /**
+   * Constructs a read-only {@code java.nio.ByteBuffer} whose content
+   * is equal to the contents of this byte string.
+   * The result uses the same backing array as the byte string, if possible.
+   *
+   * @return wrapped bytes
+   */
+  public abstract ByteBuffer asReadOnlyByteBuffer();
+
+  /**
+   * Constructs a list of read-only {@code java.nio.ByteBuffer} objects
+   * such that the concatenation of their contents is equal to the contents
+   * of this byte string.  The result uses the same backing arrays as the
+   * byte string.
+   * <p>
+   * By returning a list, implementations of this method may be able to avoid
+   * copying even when there are multiple backing arrays.
+   *
+   * @return a list of wrapped bytes
+   */
+  public abstract List<ByteBuffer> asReadOnlyByteBufferList();
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes using the
+   * specified charset.
+   *
+   * @param charsetName encode using this charset
+   * @return new string
+   * @throws UnsupportedEncodingException if charset isn't recognized
+   */
+  public final String toString(String charsetName)
+      throws UnsupportedEncodingException {
+    try {
+      return toString(Charset.forName(charsetName));
+    } catch (UnsupportedCharsetException e) {
+      UnsupportedEncodingException exception = new UnsupportedEncodingException(charsetName);
+      exception.initCause(e);
+      throw exception;
+    }
+  }
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes using the
+   * specified charset. Returns the same empty String if empty.
+   *
+   * @param charset encode using this charset
+   * @return new string
+   */
+  public final String toString(Charset charset) {
+    return size() == 0 ? "" : toStringInternal(charset);
+  }
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes using the
+   * specified charset.
+   *
+   * @param charset encode using this charset
+   * @return new string
+   */
+  protected abstract String toStringInternal(Charset charset);
+
+  // =================================================================
+  // UTF-8 decoding
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes as UTF-8.
+   *
+   * @return new string using UTF-8 encoding
+   */
+  public final String toStringUtf8() {
+    return toString(Internal.UTF_8);
+  }
+
+  /**
+   * Tells whether this {@code ByteString} represents a well-formed UTF-8
+   * byte sequence, such that the original bytes can be converted to a
+   * String object and then round tripped back to bytes without loss.
+   *
+   * <p>More precisely, returns {@code true} whenever: <pre> {@code
+   * Arrays.equals(byteString.toByteArray(),
+   *     new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
+   * }</pre>
+   *
+   * <p>This method returns {@code false} for "overlong" byte sequences,
+   * as well as for 3-byte sequences that would map to a surrogate
+   * character, in accordance with the restricted definition of UTF-8
+   * introduced in Unicode 3.1.  Note that the UTF-8 decoder included in
+   * Oracle's JDK has been modified to also reject "overlong" byte
+   * sequences, but (as of 2011) still accepts 3-byte surrogate
+   * character byte sequences.
+   *
+   * <p>See the Unicode Standard,<br>
+   * Table 3-6. <em>UTF-8 Bit Distribution</em>,<br>
+   * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+   *
+   * @return whether the bytes in this {@code ByteString} are a
+   * well-formed UTF-8 byte sequence
+   */
+  public abstract boolean isValidUtf8();
+
+  /**
+   * Tells whether the given byte sequence is a well-formed, malformed, or
+   * incomplete UTF-8 byte sequence.  This method accepts and returns a partial
+   * state result, allowing the bytes for a complete UTF-8 byte sequence to be
+   * composed from multiple {@code ByteString} segments.
+   *
+   * @param state either {@code 0} (if this is the initial decoding operation)
+   *     or the value returned from a call to a partial decoding method for the
+   *     previous bytes
+   * @param offset offset of the first byte to check
+   * @param length number of bytes to check
+   *
+   * @return {@code -1} if the partial byte sequence is definitely malformed,
+   * {@code 0} if it is well-formed (no additional input needed), or, if the
+   * byte sequence is "incomplete", i.e. apparently terminated in the middle of
+   * a character, an opaque integer "state" value containing enough information
+   * to decode the character when passed to a subsequent invocation of a
+   * partial decoding method.
+   */
+  protected abstract int partialIsValidUtf8(int state, int offset, int length);
+
+  // =================================================================
+  // equals() and hashCode()
+
+  @Override
+  public abstract boolean equals(Object o);
+
+  /**
+   * Base class for leaf {@link ByteString}s (i.e. non-ropes).
+   */
+  abstract static class LeafByteString extends ByteString {
+    @Override
+    protected final int getTreeDepth() {
+      return 0;
+    }
+
+    @Override
+    protected final boolean isBalanced() {
+      return true;
+    }
+
+    /**
+     * Check equality of the substring of given length of this object starting at
+     * zero with another {@code ByteString} substring starting at offset.
+     *
+     * @param other  what to compare a substring in
+     * @param offset offset into other
+     * @param length number of bytes to compare
+     * @return true for equality of substrings, else false.
+     */
+    abstract boolean equalsRange(ByteString other, int offset, int length);
+  }
+
+  /**
+   * Compute the hashCode using the traditional algorithm from {@link
+   * ByteString}.
+   *
+   * @return hashCode value
+   */
+  @Override
+  public final int hashCode() {
+    int h = hash;
+
+    if (h == 0) {
+      int size = size();
+      h = partialHash(size, 0, size);
+      if (h == 0) {
+        h = 1;
+      }
+      hash = h;
+    }
+    return h;
+  }
+
+  // =================================================================
+  // Input stream
+
+  /**
+   * Creates an {@code InputStream} which can be used to read the bytes.
+   * <p>
+   * The {@link InputStream} returned by this method is guaranteed to be
+   * completely non-blocking.  The method {@link InputStream#available()}
+   * returns the number of bytes remaining in the stream. The methods
+   * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)}
+   * and {@link InputStream#skip(long)} will read/skip as many bytes as are
+   * available.  The method {@link InputStream#markSupported()} returns
+   * {@code true}.
+   * <p>
+   * The methods in the returned {@link InputStream} might <b>not</b> be
+   * thread safe.
+   *
+   * @return an input stream that returns the bytes of this byte string.
+   */
+  public abstract InputStream newInput();
+
+  /**
+   * Creates a {@link CodedInputStream} which can be used to read the bytes.
+   * Using this is often more efficient than creating a {@link CodedInputStream}
+   * that wraps the result of {@link #newInput()}.
+   *
+   * @return stream based on wrapped data
+   */
+  public abstract CodedInputStream newCodedInput();
+
+  // =================================================================
+  // Output stream
+
+  /**
+   * Creates a new {@link Output} with the given initial capacity. Call {@link
+   * Output#toByteString()} to create the {@code ByteString} instance.
+   * <p>
+   * A {@link ByteString.Output} offers the same functionality as a
+   * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
+   * rather than a {@code byte} array.
+   *
+   * @param initialCapacity estimate of number of bytes to be written
+   * @return {@code OutputStream} for building a {@code ByteString}
+   */
+  public static Output newOutput(int initialCapacity) {
+    return new Output(initialCapacity);
+  }
+
+  /**
+   * Creates a new {@link Output}. Call {@link Output#toByteString()} to create
+   * the {@code ByteString} instance.
+   * <p>
+   * A {@link ByteString.Output} offers the same functionality as a
+   * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
+   * rather than a {@code byte array}.
+   *
+   * @return {@code OutputStream} for building a {@code ByteString}
+   */
+  public static Output newOutput() {
+    return new Output(CONCATENATE_BY_COPY_SIZE);
+  }
+
+  /**
+   * Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
+   * create the {@code ByteString} instance.
+   */
+  public static final class Output extends OutputStream {
+    // Implementation note.
+    // The public methods of this class must be synchronized.  ByteStrings
+    // are guaranteed to be immutable.  Without some sort of locking, it could
+    // be possible for one thread to call toByteSring(), while another thread
+    // is still modifying the underlying byte array.
+
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    // argument passed by user, indicating initial capacity.
+    private final int initialCapacity;
+    // ByteStrings to be concatenated to create the result
+    private final ArrayList<ByteString> flushedBuffers;
+    // Total number of bytes in the ByteStrings of flushedBuffers
+    private int flushedBuffersTotalBytes;
+    // Current buffer to which we are writing
+    private byte[] buffer;
+    // Location in buffer[] to which we write the next byte.
+    private int bufferPos;
+
+    /**
+     * Creates a new ByteString output stream with the specified
+     * initial capacity.
+     *
+     * @param initialCapacity  the initial capacity of the output stream.
+     */
+    Output(int initialCapacity) {
+      if (initialCapacity < 0) {
+        throw new IllegalArgumentException("Buffer size < 0");
+      }
+      this.initialCapacity = initialCapacity;
+      this.flushedBuffers = new ArrayList<ByteString>();
+      this.buffer = new byte[initialCapacity];
+    }
+
+    @Override
+    public synchronized void write(int b) {
+      if (bufferPos == buffer.length) {
+        flushFullBuffer(1);
+      }
+      buffer[bufferPos++] = (byte)b;
+    }
+
+    @Override
+    public synchronized void write(byte[] b, int offset, int length)  {
+      if (length <= buffer.length - bufferPos) {
+        // The bytes can fit into the current buffer.
+        System.arraycopy(b, offset, buffer, bufferPos, length);
+        bufferPos += length;
+      } else {
+        // Use up the current buffer
+        int copySize  = buffer.length - bufferPos;
+        System.arraycopy(b, offset, buffer, bufferPos, copySize);
+        offset += copySize;
+        length -= copySize;
+        // Flush the buffer, and get a new buffer at least big enough to cover
+        // what we still need to output
+        flushFullBuffer(length);
+        System.arraycopy(b, offset, buffer, 0 /* count */, length);
+        bufferPos = length;
+      }
+    }
+
+    /**
+     * Creates a byte string. Its size is the current size of this output
+     * stream and its output has been copied to it.
+     *
+     * @return  the current contents of this output stream, as a byte string.
+     */
+    public synchronized ByteString toByteString() {
+      flushLastBuffer();
+      return ByteString.copyFrom(flushedBuffers);
+    }
+
+    /**
+     * Implement java.util.Arrays.copyOf() for jdk 1.5.
+     */
+    private byte[] copyArray(byte[] buffer, int length) {
+      byte[] result = new byte[length];
+      System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length));
+      return result;
+    }
+
+    /**
+     * Writes the complete contents of this byte array output stream to
+     * the specified output stream argument.
+     *
+     * @param out the output stream to which to write the data.
+     * @throws IOException  if an I/O error occurs.
+     */
+    public void writeTo(OutputStream out) throws IOException {
+      ByteString[] cachedFlushBuffers;
+      byte[] cachedBuffer;
+      int cachedBufferPos;
+      synchronized (this) {
+        // Copy the information we need into local variables so as to hold
+        // the lock for as short a time as possible.
+        cachedFlushBuffers =
+            flushedBuffers.toArray(new ByteString[flushedBuffers.size()]);
+        cachedBuffer = buffer;
+        cachedBufferPos = bufferPos;
+      }
+      for (ByteString byteString : cachedFlushBuffers) {
+        byteString.writeTo(out);
+      }
+
+      out.write(copyArray(cachedBuffer, cachedBufferPos));
+    }
+
+    /**
+     * Returns the current size of the output stream.
+     *
+     * @return  the current size of the output stream
+     */
+    public synchronized int size() {
+      return flushedBuffersTotalBytes + bufferPos;
+    }
+
+    /**
+     * Resets this stream, so that all currently accumulated output in the
+     * output stream is discarded. The output stream can be used again,
+     * reusing the already allocated buffer space.
+     */
+    public synchronized void reset() {
+      flushedBuffers.clear();
+      flushedBuffersTotalBytes = 0;
+      bufferPos = 0;
+    }
+
+    @Override
+    public String toString() {
+      return String.format("<ByteString.Output@%s size=%d>",
+          Integer.toHexString(System.identityHashCode(this)), size());
+    }
+
+    /**
+     * Internal function used by writers.  The current buffer is full, and the
+     * writer needs a new buffer whose size is at least the specified minimum
+     * size.
+     */
+    private void flushFullBuffer(int minSize)  {
+      flushedBuffers.add(new LiteralByteString(buffer));
+      flushedBuffersTotalBytes += buffer.length;
+      // We want to increase our total capacity by 50%, but as a minimum,
+      // the new buffer should also at least be >= minSize and
+      // >= initial Capacity.
+      int newSize = Math.max(initialCapacity,
+          Math.max(minSize, flushedBuffersTotalBytes >>> 1));
+      buffer = new byte[newSize];
+      bufferPos = 0;
+    }
+
+    /**
+     * Internal function used by {@link #toByteString()}. The current buffer may
+     * or may not be full, but it needs to be flushed.
+     */
+    private void flushLastBuffer()  {
+      if (bufferPos < buffer.length) {
+        if (bufferPos > 0) {
+          byte[] bufferCopy = copyArray(buffer, bufferPos);
+          flushedBuffers.add(new LiteralByteString(bufferCopy));
+        }
+        // We reuse this buffer for further writes.
+      } else {
+        // Buffer is completely full.  Huzzah.
+        flushedBuffers.add(new LiteralByteString(buffer));
+        // 99% of the time, we're not going to use this OutputStream again.
+        // We set buffer to an empty byte stream so that we're handling this
+        // case without wasting space.  In the rare case that more writes
+        // *do* occur, this empty buffer will be flushed and an appropriately
+        // sized new buffer will be created.
+        buffer = EMPTY_BYTE_ARRAY;
+      }
+      flushedBuffersTotalBytes += bufferPos;
+      bufferPos = 0;
+    }
+  }
+
+  /**
+   * Constructs a new {@code ByteString} builder, which allows you to
+   * efficiently construct a {@code ByteString} by writing to a {@link
+   * CodedOutputStream}. Using this is much more efficient than calling {@code
+   * newOutput()} and wrapping that in a {@code CodedOutputStream}.
+   *
+   * <p>This is package-private because it's a somewhat confusing interface.
+   * Users can call {@link Message#toByteString()} instead of calling this
+   * directly.
+   *
+   * @param size The target byte size of the {@code ByteString}.  You must write
+   *     exactly this many bytes before building the result.
+   * @return the builder
+   */
+  static CodedBuilder newCodedBuilder(int size) {
+    return new CodedBuilder(size);
+  }
+
+  /** See {@link ByteString#newCodedBuilder(int)}. */
+  static final class CodedBuilder {
+    private final CodedOutputStream output;
+    private final byte[] buffer;
+
+    private CodedBuilder(int size) {
+      buffer = new byte[size];
+      output = CodedOutputStream.newInstance(buffer);
+    }
+
+    public ByteString build() {
+      output.checkNoSpaceLeft();
+
+      // We can be confident that the CodedOutputStream will not modify the
+      // underlying bytes anymore because it already wrote all of them.  So,
+      // no need to make a copy.
+      return new LiteralByteString(buffer);
+    }
+
+    public CodedOutputStream getCodedOutput() {
+      return output;
+    }
+  }
+
+  // =================================================================
+  // Methods {@link RopeByteString} needs on instances, which aren't part of the
+  // public API.
+
+  /**
+   * Return the depth of the tree representing this {@code ByteString}, if any,
+   * whose root is this node. If this is a leaf node, return 0.
+   *
+   * @return tree depth or zero
+   */
+  protected abstract int getTreeDepth();
+
+  /**
+   * Return {@code true} if this ByteString is literal (a leaf node) or a
+   * flat-enough tree in the sense of {@link RopeByteString}.
+   *
+   * @return true if the tree is flat enough
+   */
+  protected abstract boolean isBalanced();
+
+  /**
+   * Return the cached hash code if available.
+   *
+   * @return value of cached hash code or 0 if not computed yet
+   */
+  protected final int peekCachedHashCode() {
+    return hash;
+  }
+
+  /**
+   * Compute the hash across the value bytes starting with the given hash, and
+   * return the result.  This is used to compute the hash across strings
+   * represented as a set of pieces by allowing the hash computation to be
+   * continued from piece to piece.
+   *
+   * @param h starting hash value
+   * @param offset offset into this value to start looking at data values
+   * @param length number of data values to include in the hash computation
+   * @return ending hash value
+   */
+  protected abstract int partialHash(int h, int offset, int length);
+
+  /**
+   * Checks that the given index falls within the specified array size.
+   *
+   * @param index the index position to be tested
+   * @param size the length of the array
+   * @throws IndexOutOfBoundsException if the index does not fall within the array.
+   */
+  static void checkIndex(int index, int size) {
+    if ((index | (size - (index + 1))) < 0) {
+      if (index < 0) {
+        throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
+      }
+      throw new ArrayIndexOutOfBoundsException("Index > length: " + index + ", " + size);
+    }
+  }
+
+  /**
+   * Checks that the given range falls within the bounds of an array
+   *
+   * @param startIndex the start index of the range (inclusive)
+   * @param endIndex the end index of the range (exclusive)
+   * @param size the size of the array.
+   * @return the length of the range.
+   * @throws IndexOutOfBoundsException some or all of the range falls outside of the array.
+   */
+  static int checkRange(int startIndex, int endIndex, int size) {
+    final int length = endIndex - startIndex;
+    if ((startIndex | endIndex | length | (size - endIndex)) < 0) {
+      if (startIndex < 0) {
+        throw new IndexOutOfBoundsException("Beginning index: " + startIndex + " < 0");
+      }
+      if (endIndex < startIndex) {
+        throw new IndexOutOfBoundsException(
+            "Beginning index larger than ending index: " + startIndex + ", " + endIndex);
+      }
+      // endIndex >= size
+      throw new IndexOutOfBoundsException("End index: " + endIndex + " >= " + size);
+    }
+    return length;
+  }
+
+  @Override
+  public final String toString() {
+    return String.format("<ByteString@%s size=%d>",
+        Integer.toHexString(System.identityHashCode(this)), size());
+  }
+  
+  /**
+   * This class implements a {@link com.google.protobuf.ByteString} backed by a
+   * single array of bytes, contiguous in memory. It supports substring by
+   * pointing to only a sub-range of the underlying byte array, meaning that a
+   * substring will reference the full byte-array of the string it's made from,
+   * exactly as with {@link String}.
+   *
+   * @author carlanton@google.com (Carl Haverl)
+   */
+  // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
+  // static initializer loads LiteralByteString and another thread loads LiteralByteString.
+  private static class LiteralByteString extends ByteString.LeafByteString {
+    private static final long serialVersionUID = 1L;
+
+    protected final byte[] bytes;
+
+    /**
+     * Creates a {@code LiteralByteString} backed by the given array, without
+     * copying.
+     *
+     * @param bytes array to wrap
+     */
+    LiteralByteString(byte[] bytes) {
+      this.bytes = bytes;
+    }
+
+    @Override
+    public byte byteAt(int index) {
+      // Unlike most methods in this class, this one is a direct implementation
+      // ignoring the potential offset because we need to do range-checking in the
+      // substring case anyway.
+      return bytes[index];
+    }
+
+    @Override
+    public int size() {
+      return bytes.length;
+    }
+
+    // =================================================================
+    // ByteString -> substring
+
+    @Override
+    public final ByteString substring(int beginIndex, int endIndex) {
+      final int length = checkRange(beginIndex, endIndex, size());
+
+      if (length == 0) {
+        return ByteString.EMPTY;
+      }
+
+      return new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex, length);
+    }
+
+    // =================================================================
+    // ByteString -> byte[]
+
+    @Override
+    protected void copyToInternal(
+        byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
+      // Optimized form, not for subclasses, since we don't call
+      // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
+      // TODO(nathanmittler): Is not calling getOffsetIntoBytes really saving that much?
+      System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
+    }
+
+    @Override
+    public final void copyTo(ByteBuffer target) {
+      target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes
+    }
+
+    @Override
+    public final ByteBuffer asReadOnlyByteBuffer() {
+      return ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size()).asReadOnlyBuffer();
+    }
+
+    @Override
+    public final List<ByteBuffer> asReadOnlyByteBufferList() {
+      return Collections.singletonList(asReadOnlyByteBuffer());
+    }
+
+    @Override
+    public final void writeTo(OutputStream outputStream) throws IOException {
+      outputStream.write(toByteArray());
+    }
+
+    @Override
+    final void writeToInternal(OutputStream outputStream, int sourceOffset, int numberToWrite)
+        throws IOException {
+      outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset, numberToWrite);
+    }
+
+    @Override
+    final void writeTo(ByteOutput output) throws IOException {
+      output.writeLazy(bytes, getOffsetIntoBytes(), size());
+    }
+
+    @Override
+    protected final String toStringInternal(Charset charset) {
+      return new String(bytes, getOffsetIntoBytes(), size(), charset);
+    }
+
+    // =================================================================
+    // UTF-8 decoding
+
+    @Override
+    public final boolean isValidUtf8() {
+      int offset = getOffsetIntoBytes();
+      return Utf8.isValidUtf8(bytes, offset, offset + size());
+    }
+
+    @Override
+    protected final int partialIsValidUtf8(int state, int offset, int length) {
+      int index = getOffsetIntoBytes() + offset;
+      return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
+    }
+
+    // =================================================================
+    // equals() and hashCode()
+
+    @Override
+    public final boolean equals(Object other) {
+      if (other == this) {
+        return true;
+      }
+      if (!(other instanceof ByteString)) {
+        return false;
+      }
+
+      if (size() != ((ByteString) other).size()) {
+        return false;
+      }
+      if (size() == 0) {
+        return true;
+      }
+
+      if (other instanceof LiteralByteString) {
+        LiteralByteString otherAsLiteral = (LiteralByteString) other;
+        // If we know the hash codes and they are not equal, we know the byte
+        // strings are not equal.
+        int thisHash = peekCachedHashCode();
+        int thatHash = otherAsLiteral.peekCachedHashCode();
+        if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) {
+          return false;
+        }
+
+        return equalsRange((LiteralByteString) other, 0, size());
+      } else {
+        // RopeByteString and NioByteString.
+        return other.equals(this);
+      }
+    }
+
+    /**
+     * Check equality of the substring of given length of this object starting at
+     * zero with another {@code LiteralByteString} substring starting at offset.
+     *
+     * @param other  what to compare a substring in
+     * @param offset offset into other
+     * @param length number of bytes to compare
+     * @return true for equality of substrings, else false.
+     */
+    @Override
+    final boolean equalsRange(ByteString other, int offset, int length) {
+      if (length > other.size()) {
+        throw new IllegalArgumentException("Length too large: " + length + size());
+      }
+      if (offset + length > other.size()) {
+        throw new IllegalArgumentException(
+            "Ran off end of other: " + offset + ", " + length + ", " + other.size());
+      }
+
+      if (other instanceof LiteralByteString) {
+        LiteralByteString lbsOther = (LiteralByteString) other;
+        byte[] thisBytes = bytes;
+        byte[] otherBytes = lbsOther.bytes;
+        int thisLimit = getOffsetIntoBytes() + length;
+        for (
+            int thisIndex = getOffsetIntoBytes(),
+                otherIndex = lbsOther.getOffsetIntoBytes() + offset;
+            (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
+          if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      return other.substring(offset, offset + length).equals(substring(0, length));
+    }
+
+    @Override
+    protected final int partialHash(int h, int offset, int length) {
+      return Internal.partialHash(h, bytes, getOffsetIntoBytes() + offset, length);
+    }
+
+    // =================================================================
+    // Input stream
+
+    @Override
+    public final InputStream newInput() {
+      return new ByteArrayInputStream(bytes, getOffsetIntoBytes(), size()); // No copy
+    }
+
+    @Override
+    public final CodedInputStream newCodedInput() {
+      // We trust CodedInputStream not to modify the bytes, or to give anyone
+      // else access to them.
+      return CodedInputStream.newInstance(
+          bytes, getOffsetIntoBytes(), size(), true /* bufferIsImmutable */);
+    }
+
+    // =================================================================
+    // Internal methods
+
+    /**
+     * Offset into {@code bytes[]} to use, non-zero for substrings.
+     *
+     * @return always 0 for this class
+     */
+    protected int getOffsetIntoBytes() {
+      return 0;
+    }
+  }
+  
+  /**
+   * This class is used to represent the substring of a {@link ByteString} over a
+   * single byte array. In terms of the public API of {@link ByteString}, you end
+   * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
+   * ByteString#substring(int, int)}.
+   *
+   * <p>This class contains most of the overhead involved in creating a substring
+   * from a {@link LiteralByteString}.  The overhead involves some range-checking
+   * and two extra fields.
+   *
+   * @author carlanton@google.com (Carl Haverl)
+   */
+  // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
+  // static initializer loads LiteralByteString and another thread loads BoundedByteString.
+  private static final class BoundedByteString extends LiteralByteString {
+
+    private final int bytesOffset;
+    private final int bytesLength;
+
+    /**
+     * Creates a {@code BoundedByteString} backed by the sub-range of given array,
+     * without copying.
+     *
+     * @param bytes  array to wrap
+     * @param offset index to first byte to use in bytes
+     * @param length number of bytes to use from bytes
+     * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
+     *                                  or if {@code offset + length >
+     *                                  bytes.length}.
+     */
+    BoundedByteString(byte[] bytes, int offset, int length) {
+      super(bytes);
+      checkRange(offset, offset + length, bytes.length);
+
+      this.bytesOffset = offset;
+      this.bytesLength = length;
+    }
+
+    /**
+     * Gets the byte at the given index.
+     * Throws {@link ArrayIndexOutOfBoundsException}
+     * for backwards-compatibility reasons although it would more properly be
+     * {@link IndexOutOfBoundsException}.
+     *
+     * @param index index of byte
+     * @return the value
+     * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+     */
+    @Override
+    public byte byteAt(int index) {
+      // We must check the index ourselves as we cannot rely on Java array index
+      // checking for substrings.
+      checkIndex(index, size());
+      return bytes[bytesOffset + index];
+    }
+
+    @Override
+    public int size() {
+      return bytesLength;
+    }
+
+    @Override
+    protected int getOffsetIntoBytes() {
+      return bytesOffset;
+    }
+
+    // =================================================================
+    // ByteString -> byte[]
+
+    @Override
+    protected void copyToInternal(byte[] target, int sourceOffset, int targetOffset,
+        int numberToCopy) {
+      System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
+          targetOffset, numberToCopy);
+    }
+
+    // =================================================================
+    // Serializable
+
+    private static final long serialVersionUID = 1L;
+
+    Object writeReplace() {
+      return ByteString.wrap(toByteArray());
+    }
+
+    private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
+      throw new InvalidObjectException(
+          "BoundedByteStream instances are not to be serialized directly");
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
new file mode 100644
index 0000000..e886065
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -0,0 +1,1302 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods:  methods that read specific
+ * protocol message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputStream {
+  /**
+   * Create a new CodedInputStream wrapping the given InputStream.
+   */
+  public static CodedInputStream newInstance(final InputStream input) {
+    return new CodedInputStream(input, BUFFER_SIZE);
+  }
+  
+  /**
+   * Create a new CodedInputStream wrapping the given InputStream.
+   */
+  static CodedInputStream newInstance(final InputStream input, int bufferSize) {
+    return new CodedInputStream(input, bufferSize);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array.
+   */
+  public static CodedInputStream newInstance(final byte[] buf) {
+    return newInstance(buf, 0, buf.length);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  public static CodedInputStream newInstance(final byte[] buf, final int off,
+                                             final int len) {
+    return newInstance(buf, off, len, false /* bufferIsImmutable */);
+  }
+  
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  static CodedInputStream newInstance(
+      final byte[] buf, final int off, final int len, final boolean bufferIsImmutable) {
+    CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable);
+    try {
+      // Some uses of CodedInputStream can be more efficient if they know
+      // exactly how many bytes are available.  By pushing the end point of the
+      // buffer as a limit, we allow them to get this information via
+      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
+      // the stream can never hurt, since we can never past that point anyway.
+      result.pushLimit(len);
+    } catch (InvalidProtocolBufferException ex) {
+      // The only reason pushLimit() might throw an exception here is if len
+      // is negative. Normally pushLimit()'s parameter comes directly off the
+      // wire, so it's important to catch exceptions in case of corrupt or
+      // malicious data. However, in this case, we expect that len is not a
+      // user-supplied value, so we can assume that it being negative indicates
+      // a programming error. Therefore, throwing an unchecked exception is
+      // appropriate.
+      throw new IllegalArgumentException(ex);
+    }
+    return result;
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given ByteBuffer. The data
+   * starting from the ByteBuffer's current position to its limit will be read.
+   * The returned CodedInputStream may or may not share the underlying data
+   * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the
+   * CodedInputStream is in use.
+   * Note that the ByteBuffer's position won't be changed by this function.
+   * Concurrent calls with the same ByteBuffer object are safe if no other
+   * thread is trying to alter the ByteBuffer's status.
+   */
+  public static CodedInputStream newInstance(ByteBuffer buf) {
+    if (buf.hasArray()) {
+      return newInstance(buf.array(), buf.arrayOffset() + buf.position(),
+          buf.remaining());
+    } else {
+      ByteBuffer temp = buf.duplicate();
+      byte[] buffer = new byte[temp.remaining()];
+      temp.get(buffer);
+      return newInstance(buffer);
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Attempt to read a field tag, returning zero if we have reached EOF.
+   * Protocol message parsers use this to read tags, since a protocol message
+   * may legally end wherever a tag occurs, and zero is not a valid tag number.
+   */
+  public int readTag() throws IOException {
+    if (isAtEnd()) {
+      lastTag = 0;
+      return 0;
+    }
+
+    lastTag = readRawVarint32();
+    if (WireFormat.getTagFieldNumber(lastTag) == 0) {
+      // If we actually read zero (or any tag number corresponding to field
+      // number zero), that's not a valid tag.
+      throw InvalidProtocolBufferException.invalidTag();
+    }
+    return lastTag;
+  }
+
+  /**
+   * Verifies that the last call to readTag() returned the given tag value.
+   * This is used to verify that a nested group ended with the correct
+   * end tag.
+   *
+   * @throws InvalidProtocolBufferException {@code value} does not match the
+   *                                        last tag.
+   */
+  public void checkLastTagWas(final int value)
+                              throws InvalidProtocolBufferException {
+    if (lastTag != value) {
+      throw InvalidProtocolBufferException.invalidEndTag();
+    }
+  }
+
+  public int getLastTag() {
+    return lastTag;
+  }
+
+  /**
+   * Reads and discards a single field, given its tag value.
+   *
+   * @return {@code false} if the tag is an endgroup tag, in which case
+   *         nothing is skipped.  Otherwise, returns {@code true}.
+   */
+  public boolean skipField(final int tag) throws IOException {
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT:
+        skipRawVarint();
+        return true;
+      case WireFormat.WIRETYPE_FIXED64:
+        skipRawBytes(8);
+        return true;
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+        skipRawBytes(readRawVarint32());
+        return true;
+      case WireFormat.WIRETYPE_START_GROUP:
+        skipMessage();
+        checkLastTagWas(
+          WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+                             WireFormat.WIRETYPE_END_GROUP));
+        return true;
+      case WireFormat.WIRETYPE_END_GROUP:
+        return false;
+      case WireFormat.WIRETYPE_FIXED32:
+        skipRawBytes(4);
+        return true;
+      default:
+        throw InvalidProtocolBufferException.invalidWireType();
+    }
+  }
+
+  /**
+   * Reads a single field and writes it to output in wire format,
+   * given its tag value.
+   *
+   * @return {@code false} if the tag is an endgroup tag, in which case
+   *         nothing is skipped.  Otherwise, returns {@code true}.
+   */
+  public boolean skipField(final int tag, final CodedOutputStream output)
+      throws IOException {
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT: {
+        long value = readInt64();
+        output.writeRawVarint32(tag);
+        output.writeUInt64NoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_FIXED64: {
+        long value = readRawLittleEndian64();
+        output.writeRawVarint32(tag);
+        output.writeFixed64NoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED: {
+        ByteString value = readBytes();
+        output.writeRawVarint32(tag);
+        output.writeBytesNoTag(value);
+        return true;
+      }
+      case WireFormat.WIRETYPE_START_GROUP: {
+        output.writeRawVarint32(tag);
+        skipMessage(output);
+        int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+                                        WireFormat.WIRETYPE_END_GROUP);
+        checkLastTagWas(endtag);
+        output.writeRawVarint32(endtag);
+        return true;
+      }
+      case WireFormat.WIRETYPE_END_GROUP: {
+        return false;
+      }
+      case WireFormat.WIRETYPE_FIXED32: {
+        int value = readRawLittleEndian32();
+        output.writeRawVarint32(tag);
+        output.writeFixed32NoTag(value);
+        return true;
+      }
+      default:
+        throw InvalidProtocolBufferException.invalidWireType();
+    }
+  }
+
+  /**
+   * Reads and discards an entire message.  This will read either until EOF
+   * or until an endgroup tag, whichever comes first.
+   */
+  public void skipMessage() throws IOException {
+    while (true) {
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag)) {
+        return;
+      }
+    }
+  }
+
+  /**
+   * Reads an entire message and writes it to output in wire format.
+   * This will read either until EOF or until an endgroup tag,
+   * whichever comes first.
+   */
+  public void skipMessage(CodedOutputStream output) throws IOException {
+    while (true) {
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag, output)) {
+        return;
+      }
+    }
+  }
+
+  /**
+   * Collects the bytes skipped and returns the data in a ByteBuffer.
+   */
+  private class SkippedDataSink implements RefillCallback {
+    private int lastPos = bufferPos;
+    private ByteArrayOutputStream byteArrayStream;
+
+    @Override
+    public void onRefill() {
+      if (byteArrayStream == null) {
+        byteArrayStream = new ByteArrayOutputStream();
+      }
+      byteArrayStream.write(buffer, lastPos, bufferPos - lastPos);
+      lastPos = 0;
+    }
+
+    /**
+     * Gets skipped data in a ByteBuffer. This method should only be
+     * called once.
+     */
+    ByteBuffer getSkippedData() {
+      if (byteArrayStream == null) {
+        return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos);
+      } else {
+        byteArrayStream.write(buffer, lastPos, bufferPos);
+        return ByteBuffer.wrap(byteArrayStream.toByteArray());
+      }
+    }
+  }
+
+
+  // -----------------------------------------------------------------
+
+  /** Read a {@code double} field value from the stream. */
+  public double readDouble() throws IOException {
+    return Double.longBitsToDouble(readRawLittleEndian64());
+  }
+
+  /** Read a {@code float} field value from the stream. */
+  public float readFloat() throws IOException {
+    return Float.intBitsToFloat(readRawLittleEndian32());
+  }
+
+  /** Read a {@code uint64} field value from the stream. */
+  public long readUInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int64} field value from the stream. */
+  public long readInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int32} field value from the stream. */
+  public int readInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read a {@code fixed64} field value from the stream. */
+  public long readFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read a {@code fixed32} field value from the stream. */
+  public int readFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read a {@code bool} field value from the stream. */
+  public boolean readBool() throws IOException {
+    return readRawVarint64() != 0;
+  }
+
+  /**
+   * Read a {@code string} field value from the stream.
+   * If the stream contains malformed UTF-8,
+   * replace the offending bytes with the standard UTF-8 replacement character.
+   */
+  public String readString() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final String result = new String(buffer, bufferPos, size, Internal.UTF_8);
+      bufferPos += size;
+      return result;
+    } else if (size == 0) {
+      return "";
+    } else if (size <= bufferSize) {
+      refillBuffer(size);
+      String result = new String(buffer, bufferPos, size, Internal.UTF_8);
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return new String(readRawBytesSlowPath(size), Internal.UTF_8);
+    }
+  }
+
+  /**
+   * Read a {@code string} field value from the stream.
+   * If the stream contains malformed UTF-8,
+   * throw exception {@link InvalidProtocolBufferException}.
+   */
+  public String readStringRequireUtf8() throws IOException {
+    final int size = readRawVarint32();
+    final byte[] bytes;
+    final int oldPos = bufferPos;
+    final int pos;
+    if (size <= (bufferSize - oldPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      bytes = buffer;
+      bufferPos = oldPos + size;
+      pos = oldPos;
+    } else if (size == 0) {
+      return "";
+    } else if (size <= bufferSize) {
+      refillBuffer(size);
+      bytes = buffer;
+      pos = 0;
+      bufferPos = pos + size;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      bytes = readRawBytesSlowPath(size);
+      pos = 0;
+    }
+    // TODO(martinrb): We could save a pass by validating while decoding.
+    if (!Utf8.isValidUtf8(bytes, pos, pos + size)) {
+      throw InvalidProtocolBufferException.invalidUtf8();
+    }
+    return new String(bytes, pos, size, Internal.UTF_8);
+  }
+
+  /** Read a {@code group} field value from the stream. */
+  public void readGroup(final int fieldNumber,
+                        final MessageLite.Builder builder,
+                        final ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferException.recursionLimitExceeded();
+    }
+    ++recursionDepth;
+    builder.mergeFrom(this, extensionRegistry);
+    checkLastTagWas(
+      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+    --recursionDepth;
+  }
+
+
+  /** Read a {@code group} field value from the stream. */
+  public <T extends MessageLite> T readGroup(
+      final int fieldNumber,
+      final Parser<T> parser,
+      final ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferException.recursionLimitExceeded();
+    }
+    ++recursionDepth;
+    T result = parser.parsePartialFrom(this, extensionRegistry);
+    checkLastTagWas(
+      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+    --recursionDepth;
+    return result;
+  }
+
+  /**
+   * Reads a {@code group} field value from the stream and merges it into the
+   * given {@link UnknownFieldSet}.
+   *
+   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
+   *             you can just call {@link #readGroup}.
+   */
+  @Deprecated
+  public void readUnknownGroup(final int fieldNumber,
+                               final MessageLite.Builder builder)
+      throws IOException {
+    // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
+    // is safe to pass null here.  (We can't call
+    // ExtensionRegistry.getEmptyRegistry() because that would make this
+    // class depend on ExtensionRegistry, which is not part of the lite
+    // library.)
+    readGroup(fieldNumber, builder, null);
+  }
+
+  /** Read an embedded message field value from the stream. */
+  public void readMessage(final MessageLite.Builder builder,
+                          final ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    final int length = readRawVarint32();
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferException.recursionLimitExceeded();
+    }
+    final int oldLimit = pushLimit(length);
+    ++recursionDepth;
+    builder.mergeFrom(this, extensionRegistry);
+    checkLastTagWas(0);
+    --recursionDepth;
+    popLimit(oldLimit);
+  }
+
+
+  /** Read an embedded message field value from the stream. */
+  public <T extends MessageLite> T readMessage(
+      final Parser<T> parser,
+      final ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    int length = readRawVarint32();
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferException.recursionLimitExceeded();
+    }
+    final int oldLimit = pushLimit(length);
+    ++recursionDepth;
+    T result = parser.parsePartialFrom(this, extensionRegistry);
+    checkLastTagWas(0);
+    --recursionDepth;
+    popLimit(oldLimit);
+    return result;
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public ByteString readBytes() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final ByteString result = bufferIsImmutable && enableAliasing
+          ? ByteString.wrap(buffer, bufferPos, size)
+          : ByteString.copyFrom(buffer, bufferPos, size);
+      bufferPos += size;
+      return result;
+    } else if (size == 0) {
+      return ByteString.EMPTY;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return ByteString.wrap(readRawBytesSlowPath(size));
+    }
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public byte[] readByteArray() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path: We already have the bytes in a contiguous buffer, so
+      // just copy directly from it.
+      final byte[] result =
+          Arrays.copyOfRange(buffer, bufferPos, bufferPos + size);
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path: Build a byte array first then copy it.
+      return readRawBytesSlowPath(size);
+    }
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public ByteBuffer readByteBuffer() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path: We already have the bytes in a contiguous buffer.
+      // When aliasing is enabled, we can return a ByteBuffer pointing directly
+      // into the underlying byte array without copy if the CodedInputStream is
+      // constructed from a byte array. If aliasing is disabled or the input is
+      // from an InputStream or ByteString, we have to make a copy of the bytes.
+      ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing
+          ? ByteBuffer.wrap(buffer, bufferPos, size).slice()
+          : ByteBuffer.wrap(Arrays.copyOfRange(
+              buffer, bufferPos, bufferPos + size));
+      bufferPos += size;
+      return result;
+    } else if (size == 0) {
+      return Internal.EMPTY_BYTE_BUFFER;
+    } else {
+      // Slow path: Build a byte array first then copy it.
+      return ByteBuffer.wrap(readRawBytesSlowPath(size));
+    }
+  }
+
+  /** Read a {@code uint32} field value from the stream. */
+  public int readUInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /**
+   * Read an enum field value from the stream.  Caller is responsible
+   * for converting the numeric value to an actual enum.
+   */
+  public int readEnum() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read an {@code sfixed32} field value from the stream. */
+  public int readSFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read an {@code sfixed64} field value from the stream. */
+  public long readSFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read an {@code sint32} field value from the stream. */
+  public int readSInt32() throws IOException {
+    return decodeZigZag32(readRawVarint32());
+  }
+
+  /** Read an {@code sint64} field value from the stream. */
+  public long readSInt64() throws IOException {
+    return decodeZigZag64(readRawVarint64());
+  }
+
+  // =================================================================
+
+  /**
+   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
+   * upper bits.
+   */
+  public int readRawVarint32() throws IOException {
+    // See implementation notes for readRawVarint64
+ fastpath: {
+      int pos = bufferPos;
+
+      if (bufferSize == pos) {
+        break fastpath;
+      }
+
+      final byte[] buffer = this.buffer;
+      int x;
+      if ((x = buffer[pos++]) >= 0) {
+        bufferPos = pos;
+        return x;
+      } else if (bufferSize - pos < 9) {
+        break fastpath;
+      } else if ((x ^= (buffer[pos++] << 7)) < 0) {
+        x ^= (~0 << 7);
+      } else if ((x ^= (buffer[pos++] << 14)) >= 0) {
+        x ^= (~0 << 7) ^ (~0 << 14);
+      } else if ((x ^= (buffer[pos++] << 21)) < 0) {
+        x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21);
+      } else {
+        int y = buffer[pos++];
+        x ^= y << 28;
+        x ^= (~0 << 7) ^ (~0 << 14) ^ (~0 << 21) ^ (~0 << 28);
+        if (y < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0 &&
+            buffer[pos++] < 0) {
+          break fastpath;  // Will throw malformedVarint()
+        }
+      }
+      bufferPos = pos;
+      return x;
+    }
+    return (int) readRawVarint64SlowPath();
+  }
+
+  private void skipRawVarint() throws IOException {
+    if (bufferSize - bufferPos >= 10) {
+      final byte[] buffer = this.buffer;
+      int pos = bufferPos;
+      for (int i = 0; i < 10; i++) {
+        if (buffer[pos++] >= 0) {
+          bufferPos = pos;
+          return;
+        }
+      }
+    }
+    skipRawVarintSlowPath();
+  }
+
+  private void skipRawVarintSlowPath() throws IOException {
+    for (int i = 0; i < 10; i++) {
+      if (readRawByte() >= 0) {
+        return;
+      }
+    }
+    throw InvalidProtocolBufferException.malformedVarint();
+  }
+
+  /**
+   * Reads a varint from the input one byte at a time, so that it does not
+   * read any bytes after the end of the varint.  If you simply wrapped the
+   * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
+   * then you would probably end up reading past the end of the varint since
+   * CodedInputStream buffers its input.
+   */
+  static int readRawVarint32(final InputStream input) throws IOException {
+    final int firstByte = input.read();
+    if (firstByte == -1) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+    return readRawVarint32(firstByte, input);
+  }
+
+  /**
+   * Like {@link #readRawVarint32(InputStream)}, but expects that the caller
+   * has already read one byte.  This allows the caller to determine if EOF
+   * has been reached before attempting to read.
+   */
+  public static int readRawVarint32(
+      final int firstByte, final InputStream input) throws IOException {
+    if ((firstByte & 0x80) == 0) {
+      return firstByte;
+    }
+
+    int result = firstByte & 0x7f;
+    int offset = 7;
+    for (; offset < 32; offset += 7) {
+      final int b = input.read();
+      if (b == -1) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      result |= (b & 0x7f) << offset;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+    }
+    // Keep reading up to 64 bits.
+    for (; offset < 64; offset += 7) {
+      final int b = input.read();
+      if (b == -1) {
+        throw InvalidProtocolBufferException.truncatedMessage();
+      }
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+    }
+    throw InvalidProtocolBufferException.malformedVarint();
+  }
+
+  /** Read a raw Varint from the stream. */
+  public long readRawVarint64() throws IOException {
+    // Implementation notes:
+    //
+    // Optimized for one-byte values, expected to be common.
+    // The particular code below was selected from various candidates
+    // empirically, by winning VarintBenchmark.
+    //
+    // Sign extension of (signed) Java bytes is usually a nuisance, but
+    // we exploit it here to more easily obtain the sign of bytes read.
+    // Instead of cleaning up the sign extension bits by masking eagerly,
+    // we delay until we find the final (positive) byte, when we clear all
+    // accumulated bits with one xor.  We depend on javac to constant fold.
+ fastpath: {
+      int pos = bufferPos;
+
+      if (bufferSize == pos) {
+        break fastpath;
+      }
+
+      final byte[] buffer = this.buffer;
+      long x;
+      int y;
+      if ((y = buffer[pos++]) >= 0) {
+        bufferPos = pos;
+        return y;
+      } else if (bufferSize - pos < 9) {
+        break fastpath;
+      } else if ((y ^= (buffer[pos++] << 7)) < 0) {
+        x = y ^ (~0 << 7);
+      } else if ((y ^= (buffer[pos++] << 14)) >= 0) {
+        x = y ^ ((~0 << 7) ^ (~0 << 14));
+      } else if ((y ^= (buffer[pos++] << 21)) < 0) {
+        x = y ^ ((~0 << 7) ^ (~0 << 14) ^ (~0 << 21));
+      } else if ((x = ((long) y) ^ ((long) buffer[pos++] << 28)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
+      } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
+      } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
+      } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) {
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+            ^ (~0L << 49);
+      } else {
+        x ^= ((long) buffer[pos++] << 56);
+        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
+            ^ (~0L << 49) ^ (~0L << 56);
+        if (x < 0L) {
+          if (buffer[pos++] < 0L) {
+            break fastpath;  // Will throw malformedVarint()
+          }
+        }
+      }
+      bufferPos = pos;
+      return x;
+    }
+    return readRawVarint64SlowPath();
+  }
+
+  /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
+  /* Visible for testing */
+  long readRawVarint64SlowPath() throws IOException {
+    long result = 0;
+    for (int shift = 0; shift < 64; shift += 7) {
+      final byte b = readRawByte();
+      result |= (long) (b & 0x7F) << shift;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+    }
+    throw InvalidProtocolBufferException.malformedVarint();
+  }
+
+  /** Read a 32-bit little-endian integer from the stream. */
+  public int readRawLittleEndian32() throws IOException {
+    int pos = bufferPos;
+
+    // hand-inlined ensureAvailable(4);
+    if (bufferSize - pos < 4) {
+      refillBuffer(4);
+      pos = bufferPos;
+    }
+
+    final byte[] buffer = this.buffer;
+    bufferPos = pos + 4;
+    return (((buffer[pos]     & 0xff))       |
+            ((buffer[pos + 1] & 0xff) <<  8) |
+            ((buffer[pos + 2] & 0xff) << 16) |
+            ((buffer[pos + 3] & 0xff) << 24));
+  }
+
+  /** Read a 64-bit little-endian integer from the stream. */
+  public long readRawLittleEndian64() throws IOException {
+    int pos = bufferPos;
+
+    // hand-inlined ensureAvailable(8);
+    if (bufferSize - pos < 8) {
+      refillBuffer(8);
+      pos = bufferPos;
+    }
+
+    final byte[] buffer = this.buffer;
+    bufferPos = pos + 8;
+    return ((((long) buffer[pos]     & 0xffL))       |
+            (((long) buffer[pos + 1] & 0xffL) <<  8) |
+            (((long) buffer[pos + 2] & 0xffL) << 16) |
+            (((long) buffer[pos + 3] & 0xffL) << 24) |
+            (((long) buffer[pos + 4] & 0xffL) << 32) |
+            (((long) buffer[pos + 5] & 0xffL) << 40) |
+            (((long) buffer[pos + 6] & 0xffL) << 48) |
+            (((long) buffer[pos + 7] & 0xffL) << 56));
+  }
+
+  /**
+   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 32-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 32-bit integer.
+   */
+  public static int decodeZigZag32(final int n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 64-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 64-bit integer.
+   */
+  public static long decodeZigZag64(final long n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  // -----------------------------------------------------------------
+
+  private final byte[] buffer;
+  private final boolean bufferIsImmutable;
+  private int bufferSize;
+  private int bufferSizeAfterLimit;
+  private int bufferPos;
+  private final InputStream input;
+  private int lastTag;
+  private boolean enableAliasing = false;
+
+  /**
+   * The total number of bytes read before the current buffer.  The total
+   * bytes read up to the current position can be computed as
+   * {@code totalBytesRetired + bufferPos}.  This value may be negative if
+   * reading started in the middle of the current buffer (e.g. if the
+   * constructor that takes a byte array and an offset was used).
+   */
+  private int totalBytesRetired;
+
+  /** The absolute position of the end of the current message. */
+  private int currentLimit = Integer.MAX_VALUE;
+
+  /** See setRecursionLimit() */
+  private int recursionDepth;
+  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+  /** See setSizeLimit() */
+  private int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+  private static final int DEFAULT_RECURSION_LIMIT = 100;
+  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
+  private static final int BUFFER_SIZE = 4096;
+
+  private CodedInputStream(
+      final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) {
+    this.buffer = buffer;
+    bufferSize = off + len;
+    bufferPos = off;
+    totalBytesRetired = -off;
+    input = null;
+    this.bufferIsImmutable = bufferIsImmutable;
+  }
+
+  private CodedInputStream(final InputStream input, int bufferSize) {
+    buffer = new byte[bufferSize];
+    bufferSize = 0;
+    bufferPos = 0;
+    totalBytesRetired = 0;
+    this.input = input;
+    bufferIsImmutable = false;
+  }
+
+  public void enableAliasing(boolean enabled) {
+    this.enableAliasing = enabled;
+  }
+
+  /**
+   * Set the maximum message recursion depth.  In order to prevent malicious
+   * messages from causing stack overflows, {@code CodedInputStream} limits
+   * how deeply messages may be nested.  The default limit is 64.
+   *
+   * @return the old limit.
+   */
+  public int setRecursionLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Recursion limit cannot be negative: " + limit);
+    }
+    final int oldLimit = recursionLimit;
+    recursionLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Set the maximum message size.  In order to prevent malicious
+   * messages from exhausting memory or causing integer overflows,
+   * {@code CodedInputStream} limits how large a message may be.
+   * The default limit is 64MB.  You should set this limit as small
+   * as you can without harming your app's functionality.  Note that
+   * size limits only apply when reading from an {@code InputStream}, not
+   * when constructed around a raw byte array (nor with
+   * {@link ByteString#newCodedInput}).
+   * <p>
+   * If you want to read several messages from a single CodedInputStream, you
+   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
+   * size limit.
+   *
+   * @return the old limit.
+   */
+  public int setSizeLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Size limit cannot be negative: " + limit);
+    }
+    final int oldLimit = sizeLimit;
+    sizeLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
+   */
+  public void resetSizeCounter() {
+    totalBytesRetired = -bufferPos;
+  }
+
+  /**
+   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
+   * is called when descending into a length-delimited embedded message.
+   *
+   * <p>Note that {@code pushLimit()} does NOT affect how many bytes the
+   * {@code CodedInputStream} reads from an underlying {@code InputStream} when
+   * refreshing its buffer.  If you need to prevent reading past a certain
+   * point in the underlying {@code InputStream} (e.g. because you expect it to
+   * contain more data after the end of the message which you need to handle
+   * differently) then you must place a wrapper around your {@code InputStream}
+   * which limits the amount of data that can be read from it.
+   *
+   * @return the old limit.
+   */
+  public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
+    if (byteLimit < 0) {
+      throw InvalidProtocolBufferException.negativeSize();
+    }
+    byteLimit += totalBytesRetired + bufferPos;
+    final int oldLimit = currentLimit;
+    if (byteLimit > oldLimit) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+    currentLimit = byteLimit;
+
+    recomputeBufferSizeAfterLimit();
+
+    return oldLimit;
+  }
+
+  private void recomputeBufferSizeAfterLimit() {
+    bufferSize += bufferSizeAfterLimit;
+    final int bufferEnd = totalBytesRetired + bufferSize;
+    if (bufferEnd > currentLimit) {
+      // Limit is in current buffer.
+      bufferSizeAfterLimit = bufferEnd - currentLimit;
+      bufferSize -= bufferSizeAfterLimit;
+    } else {
+      bufferSizeAfterLimit = 0;
+    }
+  }
+
+  /**
+   * Discards the current limit, returning to the previous limit.
+   *
+   * @param oldLimit The old limit, as returned by {@code pushLimit}.
+   */
+  public void popLimit(final int oldLimit) {
+    currentLimit = oldLimit;
+    recomputeBufferSizeAfterLimit();
+  }
+
+  /**
+   * Returns the number of bytes to be read before the current limit.
+   * If no limit is set, returns -1.
+   */
+  public int getBytesUntilLimit() {
+    if (currentLimit == Integer.MAX_VALUE) {
+      return -1;
+    }
+
+    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
+    return currentLimit - currentAbsolutePosition;
+  }
+
+  /**
+   * Returns true if the stream has reached the end of the input.  This is the
+   * case if either the end of the underlying input source has been reached or
+   * if the stream has reached a limit created using {@link #pushLimit(int)}.
+   */
+  public boolean isAtEnd() throws IOException {
+    return bufferPos == bufferSize && !tryRefillBuffer(1);
+  }
+
+  /**
+   * The total bytes read up to the current position. Calling
+   * {@link #resetSizeCounter()} resets this value to zero.
+   */
+  public int getTotalBytesRead() {
+      return totalBytesRetired + bufferPos;
+  }
+
+  private interface RefillCallback {
+    void onRefill();
+  }
+
+  private RefillCallback refillCallback = null;
+
+  /**
+   * Reads more bytes from the input, making at least {@code n} bytes available
+   * in the buffer.  Caller must ensure that the requested space is not yet
+   * available, and that the requested space is less than BUFFER_SIZE.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  private void refillBuffer(int n) throws IOException {
+    if (!tryRefillBuffer(n)) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+  }
+
+  /**
+   * Tries to read more bytes from the input, making at least {@code n} bytes
+   * available in the buffer.  Caller must ensure that the requested space is
+   * not yet available, and that the requested space is less than BUFFER_SIZE.
+   *
+   * @return {@code true} if the bytes could be made available; {@code false}
+   *         if the end of the stream or the current limit was reached.
+   */
+  private boolean tryRefillBuffer(int n) throws IOException {
+    if (bufferPos + n <= bufferSize) {
+      throw new IllegalStateException(
+          "refillBuffer() called when " + n +
+          " bytes were already available in buffer");
+    }
+
+    if (totalBytesRetired + bufferPos + n > currentLimit) {
+      // Oops, we hit a limit.
+      return false;
+    }
+
+    if (refillCallback != null) {
+      refillCallback.onRefill();
+    }
+
+    if (input != null) {
+      int pos = bufferPos;
+      if (pos > 0) {
+        if (bufferSize > pos) {
+          System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
+        }
+        totalBytesRetired += pos;
+        bufferSize -= pos;
+        bufferPos = 0;
+      }
+
+      int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
+      if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
+        throw new IllegalStateException(
+            "InputStream#read(byte[]) returned invalid result: " + bytesRead +
+            "\nThe InputStream implementation is buggy.");
+      }
+      if (bytesRead > 0) {
+        bufferSize += bytesRead;
+        // Integer-overflow-conscious check against sizeLimit
+        if (totalBytesRetired + n - sizeLimit > 0) {
+          throw InvalidProtocolBufferException.sizeLimitExceeded();
+        }
+        recomputeBufferSizeAfterLimit();
+        return (bufferSize >= n) ? true : tryRefillBuffer(n);
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Read one byte from the input.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte readRawByte() throws IOException {
+    if (bufferPos == bufferSize) {
+      refillBuffer(1);
+    }
+    return buffer[bufferPos++];
+  }
+
+  /**
+   * Read a fixed size of bytes from the input.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte[] readRawBytes(final int size) throws IOException {
+    final int pos = bufferPos;
+    if (size <= (bufferSize - pos) && size > 0) {
+      bufferPos = pos + size;
+      return Arrays.copyOfRange(buffer, pos, pos + size);
+    } else {
+      return readRawBytesSlowPath(size);
+    }
+  }
+
+  /**
+   * Exactly like readRawBytes, but caller must have already checked the fast
+   * path: (size <= (bufferSize - pos) && size > 0)
+   */
+  private byte[] readRawBytesSlowPath(final int size) throws IOException {
+    if (size <= 0) {
+      if (size == 0) {
+        return Internal.EMPTY_BYTE_ARRAY;
+      } else {
+        throw InvalidProtocolBufferException.negativeSize();
+      }
+    }
+
+    // Verify that the message size so far has not exceeded sizeLimit.
+    int currentMessageSize = totalBytesRetired + bufferPos + size;
+    if (currentMessageSize > sizeLimit) {
+      throw InvalidProtocolBufferException.sizeLimitExceeded();
+    }
+
+    // Verify that the message size so far has not exceeded currentLimit.
+    if (currentMessageSize > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    // We need the input stream to proceed.
+    if (input == null) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    final int originalBufferPos = bufferPos;
+    final int bufferedBytes = bufferSize - bufferPos;
+
+    // Mark the current buffer consumed.
+    totalBytesRetired += bufferSize;
+    bufferPos = 0;
+    bufferSize = 0;
+
+    // Determine the number of bytes we need to read from the input stream.
+    int sizeLeft = size - bufferedBytes;
+    // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
+    if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) {
+      // Either the bytes we need are known to be available, or the required buffer is
+      // within an allowed threshold - go ahead and allocate the buffer now.
+      final byte[] bytes = new byte[size];
+
+      // Copy all of the buffered bytes to the result buffer.
+      System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+
+      // Fill the remaining bytes from the input stream.
+      int pos = bufferedBytes;
+      while (pos < bytes.length) {
+        int n = input.read(bytes, pos, size - pos);
+        if (n == -1) {
+          throw InvalidProtocolBufferException.truncatedMessage();
+        }
+        totalBytesRetired += n;
+        pos += n;
+      }
+
+      return bytes;
+    }
+
+    // The size is very large.  For security reasons, we can't allocate the
+    // entire byte array yet.  The size comes directly from the input, so a
+    // maliciously-crafted message could provide a bogus very large size in
+    // order to trick the app into allocating a lot of memory.  We avoid this
+    // by allocating and reading only a small chunk at a time, so that the
+    // malicious message must actually *be* extremely large to cause
+    // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+    final List<byte[]> chunks = new ArrayList<byte[]>();
+
+    while (sizeLeft > 0) {
+      // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
+      final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
+      int pos = 0;
+      while (pos < chunk.length) {
+        final int n = input.read(chunk, pos, chunk.length - pos);
+        if (n == -1) {
+          throw InvalidProtocolBufferException.truncatedMessage();
+        }
+        totalBytesRetired += n;
+        pos += n;
+      }
+      sizeLeft -= chunk.length;
+      chunks.add(chunk);
+    }
+
+    // OK, got everything.  Now concatenate it all into one buffer.
+    final byte[] bytes = new byte[size];
+
+    // Start by copying the leftover bytes from this.buffer.
+    System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+
+    // And now all the chunks.
+    int pos = bufferedBytes;
+    for (final byte[] chunk : chunks) {
+      System.arraycopy(chunk, 0, bytes, pos, chunk.length);
+      pos += chunk.length;
+    }
+
+    // Done.
+    return bytes;
+  }
+
+  /**
+   * Reads and discards {@code size} bytes.
+   *
+   * @throws InvalidProtocolBufferException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public void skipRawBytes(final int size) throws IOException {
+    if (size <= (bufferSize - bufferPos) && size >= 0) {
+      // We have all the bytes we need already.
+      bufferPos += size;
+    } else {
+      skipRawBytesSlowPath(size);
+    }
+  }
+
+  /**
+   * Exactly like skipRawBytes, but caller must have already checked the fast
+   * path: (size <= (bufferSize - pos) && size >= 0)
+   */
+  private void skipRawBytesSlowPath(final int size) throws IOException {
+    if (size < 0) {
+      throw InvalidProtocolBufferException.negativeSize();
+    }
+
+    if (totalBytesRetired + bufferPos + size > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+      // Then fail.
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
+
+    // Skipping more bytes than are in the buffer.  First skip what we have.
+    int pos = bufferSize - bufferPos;
+    bufferPos = bufferSize;
+
+    // Keep refilling the buffer until we get to the point we wanted to skip to.
+    // This has the side effect of ensuring the limits are updated correctly.
+    refillBuffer(1);
+    while (size - pos > bufferSize) {
+      pos += bufferSize;
+      bufferPos = bufferSize;
+      refillBuffer(1);
+    }
+
+    bufferPos = size - pos;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
new file mode 100644
index 0000000..ad174d0
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -0,0 +1,2664 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.lang.Math.max;
+
+import com.google.protobuf.Utf8.UnpairedSurrogateException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ * <p>This class contains two kinds of methods:  methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ */
+public abstract class CodedOutputStream extends ByteOutput {
+  private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
+  private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+  private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+
+  private static final int FIXED_32_SIZE = 4;
+  private static final int FIXED_64_SIZE = 8;
+  private static final int MAX_VARINT_SIZE = 10;
+
+  /**
+   * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
+   */
+  @Deprecated
+  public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE;
+
+  /**
+   * The buffer size used in {@link #newInstance(OutputStream)}.
+   */
+  public static final int DEFAULT_BUFFER_SIZE = 4096;
+
+  /**
+   * Returns the buffer size to efficiently write dataLength bytes to this
+   * CodedOutputStream. Used by AbstractMessageLite.
+   *
+   * @return the buffer size to efficiently write dataLength bytes to this
+   *         CodedOutputStream.
+   */
+  static int computePreferredBufferSize(int dataLength) {
+    if (dataLength > DEFAULT_BUFFER_SIZE) {
+      return DEFAULT_BUFFER_SIZE;
+    }
+    return dataLength;
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}.
+   *
+   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+   * difficult to debug.
+   */
+  public static CodedOutputStream newInstance(final OutputStream output) {
+    return newInstance(output, DEFAULT_BUFFER_SIZE);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given
+   * buffer size.
+   *
+   * <p> NOTE: The provided {@link OutputStream} <strong>MUST NOT</strong> retain access or
+   * modify the provided byte arrays. Doing so may result in corrupted data, which would be
+   * difficult to debug.
+   */
+  public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) {
+    return new OutputStreamEncoder(output, bufferSize);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array.  If more bytes are written than fit in the array,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.  See also
+   * {@link ByteString#newCodedBuilder}.
+   */
+  public static CodedOutputStream newInstance(final byte[] flatArray) {
+    return newInstance(flatArray, 0, flatArray.length);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array slice.  If more bytes are written than fit in the slice,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.  See also
+   * {@link ByteString#newCodedBuilder}.
+   */
+  public static CodedOutputStream newInstance(
+      final byte[] flatArray, final int offset, final int length) {
+    return new ArrayEncoder(flatArray, offset, length);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
+   */
+  public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
+    if (byteBuffer.hasArray()) {
+      return new NioHeapEncoder(byteBuffer);
+    }
+    return new NioEncoder(byteBuffer);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
+   *
+   * @deprecated the size parameter is no longer used since use of an internal buffer is useless
+   * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)}
+   * instead.
+   */
+  @Deprecated
+  public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
+      @SuppressWarnings("unused") int unused) {
+    return newInstance(byteBuffer);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}.
+   *
+   * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+   * so may result in corrupted data, which would be difficult to debug.
+   *
+   * @param byteOutput the output target for encoded bytes.
+   * @param bufferSize the size of the internal scratch buffer to be used for string encoding.
+   * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded
+   * string.
+   */
+  static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) {
+    if (bufferSize < 0) {
+      throw new IllegalArgumentException("bufferSize must be positive");
+    }
+
+    return new ByteOutputEncoder(byteOutput, bufferSize);
+  }
+
+  // Disallow construction outside of this class.
+  private CodedOutputStream() {
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Encode and write a tag. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeTag(int fieldNumber, int wireType) throws IOException;
+
+  /** Write an {@code int32} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeInt32(int fieldNumber, int value) throws IOException;
+
+  /** Write a {@code uint32} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt32(int fieldNumber, int value) throws IOException;
+
+  /** Write a {@code sint32} field, including tag, to the stream. */
+  public final void writeSInt32(final int fieldNumber, final int value) throws IOException {
+    writeUInt32(fieldNumber, encodeZigZag32(value));
+  }
+
+  /** Write a {@code fixed32} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed32(int fieldNumber, int value) throws IOException;
+
+  /** Write an {@code sfixed32} field, including tag, to the stream. */
+  public final void writeSFixed32(final int fieldNumber, final int value) throws IOException {
+    writeFixed32(fieldNumber, value);
+  }
+
+  /** Write an {@code int64} field, including tag, to the stream. */
+  public final void writeInt64(final int fieldNumber, final long value) throws IOException {
+    writeUInt64(fieldNumber, value);
+  }
+
+  /** Write a {@code uint64} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt64(int fieldNumber, long value) throws IOException;
+
+  /** Write an {@code sint64} field, including tag, to the stream. */
+  public final void writeSInt64(final int fieldNumber, final long value) throws IOException {
+    writeUInt64(fieldNumber, encodeZigZag64(value));
+  }
+
+  /** Write a {@code fixed64} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed64(int fieldNumber, long value) throws IOException;
+
+  /** Write an {@code sfixed64} field, including tag, to the stream. */
+  public final void writeSFixed64(final int fieldNumber, final long value) throws IOException {
+    writeFixed64(fieldNumber, value);
+  }
+
+  /** Write a {@code float} field, including tag, to the stream. */
+  public final void writeFloat(final int fieldNumber, final float value) throws IOException {
+    writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
+  }
+
+  /** Write a {@code double} field, including tag, to the stream. */
+  public final void writeDouble(final int fieldNumber, final double value) throws IOException {
+    writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
+  }
+
+  /** Write a {@code bool} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBool(int fieldNumber, boolean value) throws IOException;
+
+  /**
+   * Write an enum field, including tag, to the stream. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public final void writeEnum(final int fieldNumber, final int value) throws IOException {
+    writeInt32(fieldNumber, value);
+  }
+
+  /** Write a {@code string} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeString(int fieldNumber, String value) throws IOException;
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException;
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException;
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
+      throws IOException;
+
+  /**
+   * Write a {@code bytes} field, including tag, to the stream.
+   * This method will write all content of the ByteBuffer regardless of the
+   * current position and limit (i.e., the number of bytes to be written is
+   * value.capacity(), not value.remaining()). Furthermore, this method doesn't
+   * alter the state of the passed-in ByteBuffer. Its position, limit, mark,
+   * etc. will remain unchanged. If you only want to write the remaining bytes
+   * of a ByteBuffer, you can call
+   * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
+   */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException;
+
+  /**
+   * Write a single byte.
+   */
+  public final void writeRawByte(final byte value) throws IOException {
+    write(value);
+  }
+
+  /** Write a single byte, represented by an integer value. */
+  public final void writeRawByte(final int value) throws IOException {
+    write((byte) value);
+  }
+
+  /** Write an array of bytes. */
+  public final void writeRawBytes(final byte[] value) throws IOException {
+    write(value, 0, value.length);
+  }
+
+  /**
+   * Write part of an array of bytes.
+   */
+  public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException {
+    write(value, offset, length);
+  }
+
+  /** Write a byte string. */
+  public final void writeRawBytes(final ByteString value) throws IOException {
+    value.writeTo(this);
+  }
+
+  /**
+   * Write a ByteBuffer. This method will write all content of the ByteBuffer
+   * regardless of the current position and limit (i.e., the number of bytes
+   * to be written is value.capacity(), not value.remaining()). Furthermore,
+   * this method doesn't alter the state of the passed-in ByteBuffer. Its
+   * position, limit, mark, etc. will remain unchanged. If you only want to
+   * write the remaining bytes of a ByteBuffer, you can call
+   * {@code writeRawBytes(byteBuffer.slice())}.
+   */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeRawBytes(final ByteBuffer value) throws IOException;
+
+  /** Write an embedded message field, including tag, to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessage(final int fieldNumber, final MessageLite value)
+      throws IOException;
+
+  /**
+   * Write a MessageSet extension field to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+      throws IOException;
+
+  /**
+   * Write an unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+      throws IOException;
+
+  // -----------------------------------------------------------------
+
+  /** Write an {@code int32} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeInt32NoTag(final int value) throws IOException;
+
+  /** Write a {@code uint32} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt32NoTag(int value) throws IOException;
+
+  /** Write a {@code sint32} field to the stream. */
+  public final void writeSInt32NoTag(final int value) throws IOException {
+    writeUInt32NoTag(encodeZigZag32(value));
+  }
+
+  /** Write a {@code fixed32} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed32NoTag(int value) throws IOException;
+
+  /** Write a {@code sfixed32} field to the stream. */
+  public final void writeSFixed32NoTag(final int value) throws IOException {
+    writeFixed32NoTag(value);
+  }
+
+  /** Write an {@code int64} field to the stream. */
+  public final void writeInt64NoTag(final long value) throws IOException {
+    writeUInt64NoTag(value);
+  }
+
+  /** Write a {@code uint64} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeUInt64NoTag(long value) throws IOException;
+
+  /** Write a {@code sint64} field to the stream. */
+  public final void writeSInt64NoTag(final long value) throws IOException {
+    writeUInt64NoTag(encodeZigZag64(value));
+  }
+
+  /** Write a {@code fixed64} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeFixed64NoTag(long value) throws IOException;
+
+  /** Write a {@code sfixed64} field to the stream. */
+  public final void writeSFixed64NoTag(final long value) throws IOException {
+    writeFixed64NoTag(value);
+  }
+
+  /** Write a {@code float} field to the stream. */
+  public final void writeFloatNoTag(final float value) throws IOException {
+    writeFixed32NoTag(Float.floatToRawIntBits(value));
+  }
+
+  /** Write a {@code double} field to the stream. */
+  public final void writeDoubleNoTag(final double value) throws IOException {
+    writeFixed64NoTag(Double.doubleToRawLongBits(value));
+  }
+
+  /** Write a {@code bool} field to the stream. */
+  public final void writeBoolNoTag(final boolean value) throws IOException {
+    write((byte) (value ? 1 : 0));
+  }
+
+  /**
+   * Write an enum field to the stream. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public final void writeEnumNoTag(final int value) throws IOException {
+    writeInt32NoTag(value);
+  }
+
+  /** Write a {@code string} field to the stream. */
+  // TODO(dweis): Document behavior on ill-formed UTF-16 input.
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeStringNoTag(String value) throws IOException;
+
+  /** Write a {@code bytes} field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeBytesNoTag(final ByteString value) throws IOException;
+
+  /** Write a {@code bytes} field to the stream. */
+  public final void writeByteArrayNoTag(final byte[] value) throws IOException {
+    writeByteArrayNoTag(value, 0, value.length);
+  }
+
+  /** Write an embedded message field to the stream. */
+  // Abstract to avoid overhead of additional virtual method calls.
+  public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
+
+  //=================================================================
+
+  @ExperimentalApi
+  @Override
+  public abstract void write(byte value) throws IOException;
+
+  @ExperimentalApi
+  @Override
+  public abstract void write(byte[] value, int offset, int length) throws IOException;
+
+  @ExperimentalApi
+  @Override
+  public abstract void writeLazy(byte[] value, int offset, int length) throws IOException;
+
+  @Override
+  public abstract void write(ByteBuffer value) throws IOException;
+
+  @ExperimentalApi
+  @Override
+  public abstract void writeLazy(ByteBuffer value) throws IOException;
+
+  // =================================================================
+  // =================================================================
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field, including tag.
+   */
+  public static int computeUInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field, including tag.
+   */
+  public static int computeSInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field, including tag.
+   */
+  public static int computeFixed32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field, including tag.
+   */
+  public static int computeSFixed32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field, including tag.
+   */
+  public static int computeSInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field, including tag.
+   */
+  public static int computeFixed64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field, including tag.
+   */
+  public static int computeSFixed64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSize(final int fieldNumber, final float value) {
+    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSize(final int fieldNumber, final double value) {
+    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field, including tag.
+   */
+  public static int computeBoolSize(final int fieldNumber, final boolean value) {
+    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * enum field, including tag. The provided value is the numeric
+   * value used to represent the enum value on the wire (not the enum ordinal value).
+   */
+  public static int computeEnumSize(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field, including tag.
+   */
+  public static int computeStringSize(final int fieldNumber, final String value) {
+    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeBytesSize(final int fieldNumber, final ByteString value) {
+    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteArraySize(final int fieldNumber, final byte[] value) {
+    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) {
+    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message in lazy field, including tag.
+   */
+  public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) {
+    return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message field, including tag.
+   */
+  public static int computeMessageSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * MessageSet extension to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+  public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+  public static int computeRawMessageSetExtensionSize(
+      final int fieldNumber, final ByteString value) {
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * lazily parsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+  public static int computeLazyFieldMessageSetExtensionSize(
+      final int fieldNumber, final LazyFieldLite value) {
+    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2
+        + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber)
+        + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Compute the number of bytes that would be needed to encode a tag. */
+  public static int computeTagSize(final int fieldNumber) {
+    return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32SizeNoTag(final int value) {
+    if (value >= 0) {
+      return computeUInt32SizeNoTag(value);
+    } else {
+      // Must sign-extend.
+      return MAX_VARINT_SIZE;
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field.
+   */
+  public static int computeUInt32SizeNoTag(final int value) {
+    if ((value & (~0 <<  7)) == 0) {
+      return 1;
+    }
+    if ((value & (~0 << 14)) == 0) {
+      return 2;
+    }
+    if ((value & (~0 << 21)) == 0) {
+      return 3;
+    }
+    if ((value & (~0 << 28)) == 0) {
+      return 4;
+    }
+    return 5;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field.
+   */
+  public static int computeSInt32SizeNoTag(final int value) {
+    return computeUInt32SizeNoTag(encodeZigZag32(value));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field.
+   */
+  public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+    return FIXED_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field.
+   */
+  public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
+    return FIXED_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64SizeNoTag(final long value) {
+    return computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64SizeNoTag(long value) {
+    // handle two popular special cases up front ...
+    if ((value & (~0L << 7)) == 0L) {
+      return 1;
+    }
+    if (value < 0L) {
+      return 10;
+    }
+    // ... leaving us with 8 remaining, which we can divide and conquer
+    int n = 2;
+    if ((value & (~0L << 35)) != 0L) {
+      n += 4; value >>>= 28;
+    }
+    if ((value & (~0L << 21)) != 0L) {
+      n += 2; value >>>= 14;
+    }
+    if ((value & (~0L << 14)) != 0L) {
+      n += 1;
+    }
+    return n;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field.
+   */
+  public static int computeSInt64SizeNoTag(final long value) {
+    return computeUInt64SizeNoTag(encodeZigZag64(value));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field.
+   */
+  public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+    return FIXED_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field.
+   */
+  public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
+    return FIXED_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
+    return FIXED_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
+    return FIXED_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field.
+   */
+  public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) {
+    return 1;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an enum field.
+   * The provided value is the numeric value used to represent the enum value on the wire
+   * (not the enum ordinal value).
+   */
+  public static int computeEnumSizeNoTag(final int value) {
+    return computeInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field.
+   */
+  public static int computeStringSizeNoTag(final String value) {
+    int length;
+    try {
+      length = Utf8.encodedLength(value);
+    } catch (UnpairedSurrogateException e) {
+      // TODO(dweis): Consider using nio Charset methods instead.
+      final byte[] bytes = value.getBytes(Internal.UTF_8);
+      length = bytes.length;
+    }
+
+    return computeLengthDelimitedFieldSize(length);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an embedded
+   * message stored in lazy field.
+   */
+  public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
+    return computeLengthDelimitedFieldSize(value.getSerializedSize());
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeBytesSizeNoTag(final ByteString value) {
+    return computeLengthDelimitedFieldSize(value.size());
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeByteArraySizeNoTag(final byte[] value) {
+    return computeLengthDelimitedFieldSize(value.length);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
+    return computeLengthDelimitedFieldSize(value.capacity());
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an embedded
+   * message field.
+   */
+  public static int computeMessageSizeNoTag(final MessageLite value) {
+    return computeLengthDelimitedFieldSize(value.getSerializedSize());
+  }
+
+  private static int computeLengthDelimitedFieldSize(int fieldLength) {
+    return computeUInt32SizeNoTag(fieldLength) + fieldLength;
+  }
+
+  /**
+   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 32-bit integer.
+   * @return An unsigned 32-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static int encodeZigZag32(final int n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 31);
+  }
+
+  /**
+   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 64-bit integer.
+   * @return An unsigned 64-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static long encodeZigZag64(final long n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 63);
+  }
+
+  // =================================================================
+
+  /**
+   * Flushes the stream and forces any buffered bytes to be written.  This
+   * does not flush the underlying OutputStream.
+   */
+  public abstract void flush() throws IOException;
+
+  /**
+   * If writing to a flat array, return the space left in the array.
+   * Otherwise, throws {@code UnsupportedOperationException}.
+   */
+  public abstract int spaceLeft();
+
+  /**
+   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
+   * a byte array that is exactly big enough to hold a message, then write to
+   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
+   * after writing verifies that the message was actually as big as expected,
+   * which can help catch bugs.
+   */
+  public final void checkNoSpaceLeft() {
+    if (spaceLeft() != 0) {
+      throw new IllegalStateException("Did not write as much data as expected.");
+    }
+  }
+
+  /**
+   * If you create a CodedOutputStream around a simple flat array, you must
+   * not attempt to write more bytes than the array has space.  Otherwise,
+   * this exception will be thrown.
+   */
+  public static class OutOfSpaceException extends IOException {
+    private static final long serialVersionUID = -6947486886997889499L;
+
+    private static final String MESSAGE =
+        "CodedOutputStream was writing to a flat byte array and ran out of space.";
+
+    OutOfSpaceException() {
+      super(MESSAGE);
+    }
+
+    OutOfSpaceException(Throwable cause) {
+      super(MESSAGE, cause);
+    }
+  }
+
+  /**
+   * Get the total number of bytes successfully written to this stream.  The
+   * returned value is not guaranteed to be accurate if exceptions have been
+   * found in the middle of writing.
+   */
+  public abstract int getTotalBytesWritten();
+
+  // =================================================================
+
+  /** Write a {@code bytes} field to the stream. Visible for testing. */
+  abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length)
+      throws IOException;
+
+  final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause)
+      throws IOException {
+    logger.log(Level.WARNING,
+        "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause);
+
+    // Unfortunately there does not appear to be any way to tell Java to encode
+    // UTF-8 directly into our buffer, so we have to let it create its own byte
+    // array and then copy.
+    // TODO(dweis): Consider using nio Charset methods instead.
+    final byte[] bytes = value.getBytes(Internal.UTF_8);
+    try {
+      writeUInt32NoTag(bytes.length);
+      writeLazy(bytes, 0, bytes.length);
+    } catch (IndexOutOfBoundsException e) {
+      throw new OutOfSpaceException(e);
+    } catch (OutOfSpaceException e) {
+      throw e;
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Write a {@code group} field, including tag, to the stream.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException {
+    writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+    writeGroupNoTag(value);
+    writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+  }
+
+  /**
+   * Write a {@code group} field to the stream.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public final void writeGroupNoTag(final MessageLite value) throws IOException {
+    value.writeTo(this);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field, including tag.
+   *
+   * @deprecated groups are deprecated.
+   */
+  @Deprecated
+  public static int computeGroupSize(final int fieldNumber, final MessageLite value) {
+    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field.
+   */
+  @Deprecated
+  public static int computeGroupSizeNoTag(final MessageLite value) {
+    return value.getSerializedSize();
+  }
+
+  /**
+   * Encode and write a varint.  {@code value} is treated as
+   * unsigned, so it won't be sign-extended if negative.
+   *
+   * @deprecated use {@link #writeUInt32NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawVarint32(int value) throws IOException {
+    writeUInt32NoTag(value);
+  }
+
+  /**
+   * Encode and write a varint.
+   *
+   * @deprecated use {@link #writeUInt64NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawVarint64(long value) throws IOException {
+    writeUInt64NoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   * {@code value} is treated as unsigned, so it won't be sign-extended if
+   * negative.
+   *
+   * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
+   */
+  @Deprecated
+  public static int computeRawVarint32Size(final int value) {
+    return computeUInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   *
+   * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead.
+   */
+  @Deprecated
+  public static int computeRawVarint64Size(long value) {
+    return computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Write a little-endian 32-bit integer.
+   *
+   * @deprecated Use {@link #writeFixed32NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawLittleEndian32(final int value) throws IOException {
+    writeFixed32NoTag(value);
+  }
+
+  /**
+   * Write a little-endian 64-bit integer.
+   *
+   * @deprecated Use {@link #writeFixed64NoTag} instead.
+   */
+  @Deprecated
+  public final void writeRawLittleEndian64(final long value) throws IOException {
+    writeFixed64NoTag(value);
+  }
+
+  // =================================================================
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a byte array.
+   */
+  private static class ArrayEncoder extends CodedOutputStream {
+    private final byte[] buffer;
+    private final int offset;
+    private final int limit;
+    private int position;
+
+    ArrayEncoder(byte[] buffer, int offset, int length) {
+      if (buffer == null) {
+        throw new NullPointerException("buffer");
+      }
+      if ((offset | length | (buffer.length - (offset + length))) < 0) {
+        throw new IllegalArgumentException(String.format(
+            "Array range is invalid. Buffer.length=%d, offset=%d, length=%d",
+            buffer.length, offset, length));
+      }
+      this.buffer = buffer;
+      this.offset = offset;
+      position = offset;
+      limit = offset + length;
+    }
+
+    @Override
+    public final void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public final void writeInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeInt32NoTag(value);
+    }
+
+    @Override
+    public final void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt32NoTag(value);
+    }
+
+    @Override
+    public final void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      writeFixed32NoTag(value);
+    }
+
+    @Override
+    public final void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt64NoTag(value);
+    }
+
+    @Override
+    public final void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      writeFixed64NoTag(value);
+    }
+
+    @Override
+    public final void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      write((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public final void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public final void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public final void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public final void writeByteArrayNoTag(final byte[] value, int offset, int length)
+        throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public final void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public final void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+    @Override
+    public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public final void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+    @Override
+    public final void write(byte value) throws IOException {
+      try {
+        buffer[position++] = value;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(new IndexOutOfBoundsException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+      }
+    }
+
+    @Override
+    public final void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public final void writeUInt32NoTag(int value) throws IOException {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+        long pos = ARRAY_BASE_OFFSET + position;
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            UNSAFE.putByte(buffer, pos++, (byte) value);
+            position++;
+            return;
+          } else {
+            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+            position++;
+            value >>>= 7;
+          }
+        }
+      } else {
+        try {
+          while (true) {
+            if ((value & ~0x7F) == 0) {
+              buffer[position++] = (byte) value;
+              return;
+            } else {
+              buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+              value >>>= 7;
+            }
+          }
+        } catch (IndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(
+              new IndexOutOfBoundsException(
+                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+        }
+      }
+    }
+
+    @Override
+    public final void writeFixed32NoTag(int value) throws IOException {
+      try {
+        buffer[position++] = (byte) (value & 0xFF);
+        buffer[position++] = (byte) ((value >> 8) & 0xFF);
+        buffer[position++] = (byte) ((value >> 16) & 0xFF);
+        buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            new IndexOutOfBoundsException(
+                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+      }
+    }
+
+    @Override
+    public final void writeUInt64NoTag(long value) throws IOException {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
+        long pos = ARRAY_BASE_OFFSET + position;
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            UNSAFE.putByte(buffer, pos++, (byte) value);
+            position++;
+            return;
+          } else {
+            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+            position++;
+            value >>>= 7;
+          }
+        }
+      } else {
+        try {
+          while (true) {
+            if ((value & ~0x7FL) == 0) {
+              buffer[position++] = (byte) value;
+              return;
+            } else {
+              buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+              value >>>= 7;
+            }
+          }
+        } catch (IndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(
+              new IndexOutOfBoundsException(
+                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+        }
+      }
+    }
+
+    @Override
+    public final void writeFixed64NoTag(long value) throws IOException {
+      try {
+        buffer[position++] = (byte) ((int) (value) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 8) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 16) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 24) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+        buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            new IndexOutOfBoundsException(
+                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+      }
+    }
+
+    @Override
+    public final void write(byte[] value, int offset, int length) throws IOException {
+      try {
+        System.arraycopy(value, offset, buffer, position, length);
+        position += length;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            new IndexOutOfBoundsException(
+                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+      }
+    }
+
+    @Override
+    public final void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public final void write(ByteBuffer value) throws IOException {
+      final int length = value.remaining();
+      try {
+        value.get(buffer, position, length);
+        position += length;
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(
+            new IndexOutOfBoundsException(
+                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+      }
+    }
+
+    @Override
+    public final void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    @Override
+    public final void writeStringNoTag(String value) throws IOException {
+      final int oldPosition = position;
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          position = oldPosition + minLengthVarIntSize;
+          int newPosition = Utf8.encode(value, buffer, position, spaceLeft());
+          // Since this class is stateful and tracks the position, we rewind and store the state,
+          // prepend the length, then reset it back to the end of the string.
+          position = oldPosition;
+          int length = newPosition - oldPosition - minLengthVarIntSize;
+          writeUInt32NoTag(length);
+          position = newPosition;
+        } else {
+          int length = Utf8.encodedLength(value);
+          writeUInt32NoTag(length);
+          position = Utf8.encode(value, buffer, position, spaceLeft());
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change - we fall back to inefficient path.
+        position = oldPosition;
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() {
+      // Do nothing.
+    }
+
+    @Override
+    public final int spaceLeft() {
+      return limit - position;
+    }
+
+    @Override
+    public final int getTotalBytesWritten() {
+      return position - offset;
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
+   * done directly to the underlying array. The buffer position is only updated after a flush.
+   */
+  private static final class NioHeapEncoder extends ArrayEncoder {
+    private final ByteBuffer byteBuffer;
+    private int initialPosition;
+
+    NioHeapEncoder(ByteBuffer byteBuffer) {
+      super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
+          byteBuffer.remaining());
+      this.byteBuffer = byteBuffer;
+      this.initialPosition = byteBuffer.position();
+    }
+
+    @Override
+    public void flush() {
+      // Update the position on the buffer.
+      byteBuffer.position(initialPosition + getTotalBytesWritten());
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}.
+   */
+  private static final class NioEncoder extends CodedOutputStream {
+    private final ByteBuffer originalBuffer;
+    private final ByteBuffer buffer;
+    private final int initialPosition;
+
+    NioEncoder(ByteBuffer buffer) {
+      this.originalBuffer = buffer;
+      this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+      initialPosition = buffer.position();
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      writeFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      writeUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      writeFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      write((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void write(byte value) throws IOException {
+      try {
+        buffer.put(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      try {
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            buffer.put((byte) value);
+            return;
+          } else {
+            buffer.put((byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeFixed32NoTag(int value) throws IOException {
+      try {
+        buffer.putInt(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      try {
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            buffer.put((byte) value);
+            return;
+          } else {
+            buffer.put((byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeFixed64NoTag(long value) throws IOException {
+      try {
+        buffer.putLong(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length) throws IOException {
+      try {
+        buffer.put(value, offset, length);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      try {
+        buffer.put(value);
+      } catch (BufferOverflowException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      final int startPos = buffer.position();
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          // Save the current position and increment past the length field. We'll come back
+          // and write the length field after the encoding is complete.
+          final int startOfBytes = buffer.position() + minLengthVarIntSize;
+          buffer.position(startOfBytes);
+
+          // Encode the string.
+          encode(value);
+
+          // Now go back to the beginning and write the length.
+          int endOfBytes = buffer.position();
+          buffer.position(startPos);
+          writeUInt32NoTag(endOfBytes - startOfBytes);
+
+          // Reposition the buffer past the written data.
+          buffer.position(endOfBytes);
+        } else {
+          final int length = Utf8.encodedLength(value);
+          writeUInt32NoTag(length);
+          encode(value);
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change and convert to an IOException.
+        buffer.position(startPos);
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IllegalArgumentException e) {
+        // Thrown by buffer.position() if out of range.
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() {
+      // Update the position of the original buffer.
+      originalBuffer.position(buffer.position());
+    }
+
+    @Override
+    public int spaceLeft() {
+      return buffer.remaining();
+    }
+
+    @Override
+    public int getTotalBytesWritten() {
+      return buffer.position() - initialPosition;
+    }
+
+    private void encode(String value) throws IOException {
+      try {
+        Utf8.encodeUtf8(value, buffer);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+  }
+
+  /**
+   * Abstract base class for buffered encoders.
+   */
+  private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
+    final byte[] buffer;
+    final int limit;
+    int position;
+    int totalBytesWritten;
+
+    AbstractBufferedEncoder(int bufferSize) {
+      if (bufferSize < 0) {
+        throw new IllegalArgumentException("bufferSize must be >= 0");
+      }
+      // As an optimization, we require that the buffer be able to store at least 2
+      // varints so that we can buffer any integer write (tag + value). This reduces the
+      // number of range checks for a single write to 1 (i.e. if there is not enough space
+      // to buffer the tag+value, flush and then buffer it).
+      this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)];
+      this.limit = buffer.length;
+    }
+
+    @Override
+    public final int spaceLeft() {
+      throw new UnsupportedOperationException(
+          "spaceLeft() can only be called on CodedOutputStreams that are "
+              + "writing to a flat array or ByteBuffer.");
+    }
+
+    @Override
+    public final int getTotalBytesWritten() {
+      return totalBytesWritten;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void buffer(byte value) {
+      buffer[position++] = value;
+      totalBytesWritten++;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferTag(final int fieldNumber, final int wireType) {
+      bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferInt32NoTag(final int value) {
+      if (value >= 0) {
+        bufferUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        bufferUInt64NoTag(value);
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferUInt32NoTag(int value) {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+        final long originalPos = ARRAY_BASE_OFFSET + position;
+        long pos = originalPos;
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            UNSAFE.putByte(buffer, pos++, (byte) value);
+            break;
+          } else {
+            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        int delta = (int) (pos - originalPos);
+        position += delta;
+        totalBytesWritten += delta;
+      } else {
+        while (true) {
+          if ((value & ~0x7F) == 0) {
+            buffer[position++] = (byte) value;
+            totalBytesWritten++;
+            return;
+          } else {
+            buffer[position++] = (byte) ((value & 0x7F) | 0x80);
+            totalBytesWritten++;
+            value >>>= 7;
+          }
+        }
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferUInt64NoTag(long value) {
+      if (HAS_UNSAFE_ARRAY_OPERATIONS) {
+        final long originalPos = ARRAY_BASE_OFFSET + position;
+        long pos = originalPos;
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            UNSAFE.putByte(buffer, pos++, (byte) value);
+            break;
+          } else {
+            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+            value >>>= 7;
+          }
+        }
+        int delta = (int) (pos - originalPos);
+        position += delta;
+        totalBytesWritten += delta;
+      } else {
+        while (true) {
+          if ((value & ~0x7FL) == 0) {
+            buffer[position++] = (byte) value;
+            totalBytesWritten++;
+            return;
+          } else {
+            buffer[position++] = (byte) (((int) value & 0x7F) | 0x80);
+            totalBytesWritten++;
+            value >>>= 7;
+          }
+        }
+      }
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferFixed32NoTag(int value) {
+      buffer[position++] = (byte) (value & 0xFF);
+      buffer[position++] = (byte) ((value >> 8) & 0xFF);
+      buffer[position++] = (byte) ((value >> 16) & 0xFF);
+      buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      totalBytesWritten += FIXED_32_SIZE;
+    }
+
+    /**
+     * This method does not perform bounds checking on the array. Checking array bounds is the
+     * responsibility of the caller.
+     */
+    final void bufferFixed64NoTag(long value) {
+      buffer[position++] = (byte) (value & 0xFF);
+      buffer[position++] = (byte) ((value >> 8) & 0xFF);
+      buffer[position++] = (byte) ((value >> 16) & 0xFF);
+      buffer[position++] = (byte) ((value >> 24) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 32) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
+      buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
+      totalBytesWritten += FIXED_64_SIZE;
+    }
+  }
+
+  /**
+   * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to
+   * support string encoding operations. All other writes are just passed through to the
+   * {@link ByteOutput}.
+   */
+  private static final class ByteOutputEncoder extends AbstractBufferedEncoder {
+    private final ByteOutput out;
+
+    ByteOutputEncoder(ByteOutput out, int bufferSize) {
+      super(bufferSize);
+      if (out == null) {
+        throw new NullPointerException("out");
+      }
+      this.out = out;
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      buffer((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void write(byte value) throws IOException {
+      if (position == limit) {
+        doFlush();
+      }
+
+      buffer(value);
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32NoTag(final int value) throws IOException {
+      flushIfNotAvailable(FIXED_32_SIZE);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64NoTag(final long value) throws IOException {
+      flushIfNotAvailable(FIXED_64_SIZE);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+      // and at most 3 times of it. We take advantage of this in both branches below.
+      final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+      final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+      // If we are streaming and the potential length is too big to fit in our buffer, we take the
+      // slower path.
+      if (maxLengthVarIntSize + maxLength > limit) {
+        // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+        // does the same internally and then does *another copy* to return a byte[] of exactly the
+        // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+        // UTF-8 encoded bytes.
+        final byte[] encodedBytes = new byte[maxLength];
+        int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+        writeUInt32NoTag(actualLength);
+        writeLazy(encodedBytes, 0, actualLength);
+        return;
+      }
+
+      // Fast path: we have enough space available in our buffer for the string...
+      if (maxLengthVarIntSize + maxLength > limit - position) {
+        // Flush to free up space.
+        doFlush();
+      }
+
+      final int oldPosition = position;
+      try {
+        // Optimize for the case where we know this length results in a constant varint length as
+        // this saves a pass for measuring the length of the string.
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+
+        if (minLengthVarIntSize == maxLengthVarIntSize) {
+          position = oldPosition + minLengthVarIntSize;
+          int newPosition = Utf8.encode(value, buffer, position, limit - position);
+          // Since this class is stateful and tracks the position, we rewind and store the state,
+          // prepend the length, then reset it back to the end of the string.
+          position = oldPosition;
+          int length = newPosition - oldPosition - minLengthVarIntSize;
+          bufferUInt32NoTag(length);
+          position = newPosition;
+          totalBytesWritten += length;
+        } else {
+          int length = Utf8.encodedLength(value);
+          bufferUInt32NoTag(length);
+          position = Utf8.encode(value, buffer, position, length);
+          totalBytesWritten += length;
+        }
+      } catch (UnpairedSurrogateException e) {
+        // Roll back the change and convert to an IOException.
+        totalBytesWritten -= position - oldPosition;
+        position = oldPosition;
+
+        // TODO(nathanmittler): We should throw an IOException here instead.
+        inefficientWriteStringNoTag(value, e);
+      } catch (IndexOutOfBoundsException e) {
+        throw new OutOfSpaceException(e);
+      }
+    }
+
+    @Override
+    public void flush() throws IOException {
+      if (position > 0) {
+        // Flush the buffer.
+        doFlush();
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length) throws IOException {
+      flush();
+      out.write(value, offset, length);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      flush();
+      out.writeLazy(value, offset, length);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      flush();
+      int length = value.remaining();
+      out.write(value);
+      totalBytesWritten += length;
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      flush();
+      int length = value.remaining();
+      out.writeLazy(value);
+      totalBytesWritten += length;
+    }
+
+    private void flushIfNotAvailable(int requiredSize) throws IOException {
+      if (limit - position < requiredSize) {
+        doFlush();
+      }
+    }
+
+    private void doFlush() throws IOException {
+      out.write(buffer, 0, position);
+      position = 0;
+    }
+  }
+
+  /**
+   * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal
+   * buffering to optimize writes to the {@link OutputStream}.
+   */
+  private static final class OutputStreamEncoder extends AbstractBufferedEncoder {
+    private final OutputStream out;
+
+    OutputStreamEncoder(OutputStream out, int bufferSize) {
+      super(bufferSize);
+      if (out == null) {
+        throw new NullPointerException("out");
+      }
+      this.out = out;
+    }
+
+    @Override
+    public void writeTag(final int fieldNumber, final int wireType) throws IOException {
+      writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
+    }
+
+    @Override
+    public void writeInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferInt32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32(final int fieldNumber, final int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE * 2);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64(final int fieldNumber, final long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeBool(final int fieldNumber, final boolean value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE + 1);
+      bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
+      buffer((byte) (value ? 1 : 0));
+    }
+
+    @Override
+    public void writeString(final int fieldNumber, final String value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeStringNoTag(value);
+    }
+
+    @Override
+    public void writeBytes(final int fieldNumber, final ByteString value) throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeBytesNoTag(value);
+    }
+
+    @Override
+    public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException {
+      writeByteArray(fieldNumber, value, 0, value.length);
+    }
+
+    @Override
+    public void writeByteArray(
+        final int fieldNumber, final byte[] value, final int offset, final int length)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeByteArrayNoTag(value, offset, length);
+    }
+
+    @Override
+    public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeUInt32NoTag(value.capacity());
+      writeRawBytes(value);
+    }
+
+    @Override
+    public void writeBytesNoTag(final ByteString value) throws IOException {
+      writeUInt32NoTag(value.size());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException {
+      writeUInt32NoTag(length);
+      write(value, offset, length);
+    }
+
+    @Override
+    public void writeRawBytes(final ByteBuffer value) throws IOException {
+      if (value.hasArray()) {
+        write(value.array(), value.arrayOffset(), value.capacity());
+      } else {
+        ByteBuffer duplicated = value.duplicate();
+        duplicated.clear();
+        write(duplicated);
+      }
+    }
+
+    @Override
+    public void writeMessage(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      writeMessageNoTag(value);
+    }
+
+    @Override
+    public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value)
+        throws IOException {
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+      writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+      writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+      writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+    }
+
+    @Override
+    public void writeMessageNoTag(final MessageLite value) throws IOException {
+      writeUInt32NoTag(value.getSerializedSize());
+      value.writeTo(this);
+    }
+
+    @Override
+    public void write(byte value) throws IOException {
+      if (position == limit) {
+        doFlush();
+      }
+
+      buffer(value);
+    }
+
+    @Override
+    public void writeInt32NoTag(int value) throws IOException {
+      if (value >= 0) {
+        writeUInt32NoTag(value);
+      } else {
+        // Must sign-extend.
+        writeUInt64NoTag(value);
+      }
+    }
+
+    @Override
+    public void writeUInt32NoTag(int value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt32NoTag(value);
+    }
+
+    @Override
+    public void writeFixed32NoTag(final int value) throws IOException {
+      flushIfNotAvailable(FIXED_32_SIZE);
+      bufferFixed32NoTag(value);
+    }
+
+    @Override
+    public void writeUInt64NoTag(long value) throws IOException {
+      flushIfNotAvailable(MAX_VARINT_SIZE);
+      bufferUInt64NoTag(value);
+    }
+
+    @Override
+    public void writeFixed64NoTag(final long value) throws IOException {
+      flushIfNotAvailable(FIXED_64_SIZE);
+      bufferFixed64NoTag(value);
+    }
+
+    @Override
+    public void writeStringNoTag(String value) throws IOException {
+      try {
+        // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+        // and at most 3 times of it. We take advantage of this in both branches below.
+        final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR;
+        final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength);
+
+        // If we are streaming and the potential length is too big to fit in our buffer, we take the
+        // slower path.
+        if (maxLengthVarIntSize + maxLength > limit) {
+          // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes()
+          // does the same internally and then does *another copy* to return a byte[] of exactly the
+          // right size. We can skip that copy and just writeRawBytes up to the actualLength of the
+          // UTF-8 encoded bytes.
+          final byte[] encodedBytes = new byte[maxLength];
+          int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength);
+          writeUInt32NoTag(actualLength);
+          writeLazy(encodedBytes, 0, actualLength);
+          return;
+        }
+
+        // Fast path: we have enough space available in our buffer for the string...
+        if (maxLengthVarIntSize + maxLength > limit - position) {
+          // Flush to free up space.
+          doFlush();
+        }
+
+        // Optimize for the case where we know this length results in a constant varint length as
+        // this saves a pass for measuring the length of the string.
+        final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
+        int oldPosition = position;
+        final int length;
+        try {
+          if (minLengthVarIntSize == maxLengthVarIntSize) {
+            position = oldPosition + minLengthVarIntSize;
+            int newPosition = Utf8.encode(value, buffer, position, limit - position);
+            // Since this class is stateful and tracks the position, we rewind and store the
+            // state, prepend the length, then reset it back to the end of the string.
+            position = oldPosition;
+            length = newPosition - oldPosition - minLengthVarIntSize;
+            bufferUInt32NoTag(length);
+            position = newPosition;
+          } else {
+            length = Utf8.encodedLength(value);
+            bufferUInt32NoTag(length);
+            position = Utf8.encode(value, buffer, position, length);
+          }
+          totalBytesWritten += length;
+        } catch (UnpairedSurrogateException e) {
+          // Be extra careful and restore the original position for retrying the write with the
+          // less efficient path.
+          totalBytesWritten -= position - oldPosition;
+          position = oldPosition;
+          throw e;
+        } catch (ArrayIndexOutOfBoundsException e) {
+          throw new OutOfSpaceException(e);
+        }
+      } catch (UnpairedSurrogateException e) {
+        inefficientWriteStringNoTag(value, e);
+      }
+    }
+
+    @Override
+    public void flush() throws IOException {
+      if (position > 0) {
+        // Flush the buffer.
+        doFlush();
+      }
+    }
+
+    @Override
+    public void write(byte[] value, int offset, int length)
+        throws IOException {
+      if (limit - position >= length) {
+        // We have room in the current buffer.
+        System.arraycopy(value, offset, buffer, position, length);
+        position += length;
+        totalBytesWritten += length;
+      } else {
+        // Write extends past current buffer.  Fill the rest of this buffer and
+        // flush.
+        final int bytesWritten = limit - position;
+        System.arraycopy(value, offset, buffer, position, bytesWritten);
+        offset += bytesWritten;
+        length -= bytesWritten;
+        position = limit;
+        totalBytesWritten += bytesWritten;
+        doFlush();
+
+        // Now deal with the rest.
+        // Since we have an output stream, this is our buffer
+        // and buffer offset == 0
+        if (length <= limit) {
+          // Fits in new buffer.
+          System.arraycopy(value, offset, buffer, 0, length);
+          position = length;
+        } else {
+          // Write is very big.  Let's do it all at once.
+          out.write(value, offset, length);
+        }
+        totalBytesWritten += length;
+      }
+    }
+
+    @Override
+    public void writeLazy(byte[] value, int offset, int length) throws IOException {
+      write(value, offset, length);
+    }
+
+    @Override
+    public void write(ByteBuffer value) throws IOException {
+      int length = value.remaining();
+      if (limit - position >= length) {
+        // We have room in the current buffer.
+        value.get(buffer, position, length);
+        position += length;
+        totalBytesWritten += length;
+      } else {
+        // Write extends past current buffer.  Fill the rest of this buffer and
+        // flush.
+        final int bytesWritten = limit - position;
+        value.get(buffer, position, bytesWritten);
+        length -= bytesWritten;
+        position = limit;
+        totalBytesWritten += bytesWritten;
+        doFlush();
+
+        // Now deal with the rest.
+        // Since we have an output stream, this is our buffer
+        // and buffer offset == 0
+        while (length > limit) {
+          // Copy data into the buffer before writing it to OutputStream.
+          value.get(buffer, 0, limit);
+          out.write(buffer, 0, limit);
+          length -= limit;
+          totalBytesWritten += limit;
+        }
+        value.get(buffer, 0, length);
+        position = length;
+        totalBytesWritten += length;
+      }
+    }
+
+    @Override
+    public void writeLazy(ByteBuffer value) throws IOException {
+      write(value);
+    }
+
+    private void flushIfNotAvailable(int requiredSize) throws IOException {
+      if (limit - position < requiredSize) {
+        doFlush();
+      }
+    }
+
+    private void doFlush() throws IOException {
+      out.write(buffer, 0, position);
+      position = 0;
+    }
+  }
+
+  /**
+   * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
+   * platform.
+   */
+  private static sun.misc.Unsafe getUnsafe() {
+    sun.misc.Unsafe unsafe = null;
+    try {
+      unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
+        @Override
+        public sun.misc.Unsafe run() throws Exception {
+          Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+          for (Field f : k.getDeclaredFields()) {
+            f.setAccessible(true);
+            Object x = f.get(null);
+            if (k.isInstance(x)) {
+              return k.cast(x);
+            }
+          }
+          // The sun.misc.Unsafe field does not exist.
+          return null;
+        }
+      });
+    } catch (Throwable e) {
+      // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+      // for Unsafe.
+    }
+
+    logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
+        unsafe != null ? "available" : "unavailable");
+    return unsafe;
+  }
+
+  /**
+   * Indicates whether or not unsafe array operations are supported on this platform.
+   */
+  // TODO(nathanmittler): Add support for Android's MemoryBlock.
+  private static boolean supportsUnsafeArrayOperations() {
+    boolean supported = false;
+    if (UNSAFE != null) {
+      try {
+        UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
+        UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
+        supported = true;
+      } catch (Throwable e) {
+        // Do nothing.
+      }
+    }
+    logger.log(Level.FINEST, "Unsafe array operations: {}",
+        supported ? "available" : "unavailable");
+    return supported;
+  }
+
+  /**
+   * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
+   * available.
+   */
+  private static <T> int byteArrayBaseOffset() {
+    return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
new file mode 100644
index 0000000..e00ea34
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -0,0 +1,2548 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.DescriptorProtos.*;
+import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Logger;
+
+/**
+ * Contains a collection of classes which describe protocol message types.
+ *
+ * Every message type has a {@link Descriptor}, which lists all
+ * its fields and other information about a type.  You can get a message
+ * type's descriptor by calling {@code MessageType.getDescriptor()}, or
+ * (given a message object of the type) {@code message.getDescriptorForType()}.
+ * Furthermore, each message is associated with a {@link FileDescriptor} for
+ * a relevant {@code .proto} file. You can obtain it by calling
+ * {@code Descriptor.getFile()}. A {@link FileDescriptor} contains descriptors
+ * for all the messages defined in that file, and file descriptors for all the
+ * imported {@code .proto} files.
+ *
+ * Descriptors are built from DescriptorProtos, as defined in
+ * {@code google/protobuf/descriptor.proto}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class Descriptors {
+  private static final Logger logger =
+      Logger.getLogger(Descriptors.class.getName());
+  /**
+   * Describes a {@code .proto} file, including everything defined within.
+   * That includes, in particular, descriptors for all the messages and
+   * file descriptors for all other imported {@code .proto} files
+   * (dependencies).
+   */
+  public static final class FileDescriptor extends GenericDescriptor {
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public FileDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the file name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /** Returns this object. */
+    @Override
+    public FileDescriptor getFile() {
+      return this;
+    }
+
+    /** Returns the same as getName(). */
+    @Override
+    public String getFullName() {
+      return proto.getName();
+    }
+
+    /**
+     * Get the proto package name.  This is the package name given by the
+     * {@code package} statement in the {@code .proto} file, which differs
+     * from the Java package.
+     */
+    public String getPackage() { return proto.getPackage(); }
+
+    /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
+    public FileOptions getOptions() { return proto.getOptions(); }
+
+    /** Get a list of top-level message types declared in this file. */
+    public List<Descriptor> getMessageTypes() {
+      return Collections.unmodifiableList(Arrays.asList(messageTypes));
+    }
+
+    /** Get a list of top-level enum types declared in this file. */
+    public List<EnumDescriptor> getEnumTypes() {
+      return Collections.unmodifiableList(Arrays.asList(enumTypes));
+    }
+
+    /** Get a list of top-level services declared in this file. */
+    public List<ServiceDescriptor> getServices() {
+      return Collections.unmodifiableList(Arrays.asList(services));
+    }
+
+    /** Get a list of top-level extensions declared in this file. */
+    public List<FieldDescriptor> getExtensions() {
+      return Collections.unmodifiableList(Arrays.asList(extensions));
+    }
+
+    /** Get a list of this file's dependencies (imports). */
+    public List<FileDescriptor> getDependencies() {
+      return Collections.unmodifiableList(Arrays.asList(dependencies));
+    }
+
+    /** Get a list of this file's public dependencies (public imports). */
+    public List<FileDescriptor> getPublicDependencies() {
+      return Collections.unmodifiableList(Arrays.asList(publicDependencies));
+    }
+
+    /** The syntax of the .proto file. */
+    public enum Syntax {
+      UNKNOWN("unknown"),
+      PROTO2("proto2"),
+      PROTO3("proto3");
+
+      Syntax(String name) {
+        this.name = name;
+      }
+      private final String name;
+    }
+
+    /** Get the syntax of the .proto file. */
+    public Syntax getSyntax() {
+      if (Syntax.PROTO3.name.equals(proto.getSyntax())) {
+        return Syntax.PROTO3;
+      }
+      return Syntax.PROTO2;
+    }
+
+    /**
+     * Find a message type in the file by name.  Does not find nested types.
+     *
+     * @param name The unqualified type name to look for.
+     * @return The message type's descriptor, or {@code null} if not found.
+     */
+    public Descriptor findMessageTypeByName(String name) {
+      // Don't allow looking up nested types.  This will make optimization
+      // easier later.
+      if (name.indexOf('.') != -1) {
+        return null;
+      }
+      if (getPackage().length() > 0) {
+        name = getPackage() + '.' + name;
+      }
+      final GenericDescriptor result = pool.findSymbol(name);
+      if (result != null && result instanceof Descriptor &&
+          result.getFile() == this) {
+        return (Descriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Find an enum type in the file by name.  Does not find nested types.
+     *
+     * @param name The unqualified type name to look for.
+     * @return The enum type's descriptor, or {@code null} if not found.
+     */
+    public EnumDescriptor findEnumTypeByName(String name) {
+      // Don't allow looking up nested types.  This will make optimization
+      // easier later.
+      if (name.indexOf('.') != -1) {
+        return null;
+      }
+      if (getPackage().length() > 0) {
+        name = getPackage() + '.' + name;
+      }
+      final GenericDescriptor result = pool.findSymbol(name);
+      if (result != null && result instanceof EnumDescriptor &&
+          result.getFile() == this) {
+        return (EnumDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Find a service type in the file by name.
+     *
+     * @param name The unqualified type name to look for.
+     * @return The service type's descriptor, or {@code null} if not found.
+     */
+    public ServiceDescriptor findServiceByName(String name) {
+      // Don't allow looking up nested types.  This will make optimization
+      // easier later.
+      if (name.indexOf('.') != -1) {
+        return null;
+      }
+      if (getPackage().length() > 0) {
+        name = getPackage() + '.' + name;
+      }
+      final GenericDescriptor result = pool.findSymbol(name);
+      if (result != null && result instanceof ServiceDescriptor &&
+          result.getFile() == this) {
+        return (ServiceDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Find an extension in the file by name.  Does not find extensions nested
+     * inside message types.
+     *
+     * @param name The unqualified extension name to look for.
+     * @return The extension's descriptor, or {@code null} if not found.
+     */
+    public FieldDescriptor findExtensionByName(String name) {
+      if (name.indexOf('.') != -1) {
+        return null;
+      }
+      if (getPackage().length() > 0) {
+        name = getPackage() + '.' + name;
+      }
+      final GenericDescriptor result = pool.findSymbol(name);
+      if (result != null && result instanceof FieldDescriptor &&
+          result.getFile() == this) {
+        return (FieldDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Construct a {@code FileDescriptor}.
+     *
+     * @param proto The protocol message form of the FileDescriptor.
+     * @param dependencies {@code FileDescriptor}s corresponding to all of
+     *                     the file's dependencies.
+     * @throws DescriptorValidationException {@code proto} is not a valid
+     *           descriptor.  This can occur for a number of reasons, e.g.
+     *           because a field has an undefined type or because two messages
+     *           were defined with the same name.
+     */
+    public static FileDescriptor buildFrom(final FileDescriptorProto proto,
+                                           final FileDescriptor[] dependencies)
+                                    throws DescriptorValidationException {
+      return buildFrom(proto, dependencies, false);
+    }
+
+
+    /**
+     * Construct a {@code FileDescriptor}.
+     *
+     * @param proto The protocol message form of the FileDescriptor.
+     * @param dependencies {@code FileDescriptor}s corresponding to all of
+     *                     the file's dependencies.
+     * @param allowUnknownDependencies If true, non-exist dependenncies will be
+     *           ignored and undefined message types will be replaced with a
+     *           placeholder type.
+     * @throws DescriptorValidationException {@code proto} is not a valid
+     *           descriptor.  This can occur for a number of reasons, e.g.
+     *           because a field has an undefined type or because two messages
+     *           were defined with the same name.
+     */
+    public static FileDescriptor buildFrom(
+        final FileDescriptorProto proto, final FileDescriptor[] dependencies,
+        final boolean allowUnknownDependencies)
+        throws DescriptorValidationException {
+      // Building descriptors involves two steps:  translating and linking.
+      // In the translation step (implemented by FileDescriptor's
+      // constructor), we build an object tree mirroring the
+      // FileDescriptorProto's tree and put all of the descriptors into the
+      // DescriptorPool's lookup tables.  In the linking step, we look up all
+      // type references in the DescriptorPool, so that, for example, a
+      // FieldDescriptor for an embedded message contains a pointer directly
+      // to the Descriptor for that message's type.  We also detect undefined
+      // types in the linking step.
+      final DescriptorPool pool = new DescriptorPool(
+          dependencies, allowUnknownDependencies);
+      final FileDescriptor result = new FileDescriptor(
+          proto, dependencies, pool, allowUnknownDependencies);
+      result.crossLink();
+      return result;
+    }
+
+    /**
+     * This method is to be called by generated code only.  It is equivalent
+     * to {@code buildFrom} except that the {@code FileDescriptorProto} is
+     * encoded in protocol buffer wire format.
+     */
+    public static void internalBuildGeneratedFileFrom(
+        final String[] descriptorDataParts,
+        final FileDescriptor[] dependencies,
+        final InternalDescriptorAssigner descriptorAssigner) {
+      // Hack:  We can't embed a raw byte array inside generated Java code
+      //   (at least, not efficiently), but we can embed Strings.  So, the
+      //   protocol compiler embeds the FileDescriptorProto as a giant
+      //   string literal which is passed to this function to construct the
+      //   file's FileDescriptor.  The string literal contains only 8-bit
+      //   characters, each one representing a byte of the FileDescriptorProto's
+      //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
+      //   should get the original bytes that we want.
+
+      // descriptorData may contain multiple strings in order to get around the
+      // Java 64k string literal limit.
+      StringBuilder descriptorData = new StringBuilder();
+      for (String part : descriptorDataParts) {
+        descriptorData.append(part);
+      }
+
+      final byte[] descriptorBytes;
+      descriptorBytes = descriptorData.toString().getBytes(Internal.ISO_8859_1);
+
+      FileDescriptorProto proto;
+      try {
+        proto = FileDescriptorProto.parseFrom(descriptorBytes);
+      } catch (InvalidProtocolBufferException e) {
+        throw new IllegalArgumentException(
+          "Failed to parse protocol buffer descriptor for generated code.", e);
+      }
+
+      final FileDescriptor result;
+      try {
+        // When building descriptors for generated code, we allow unknown
+        // dependencies by default.
+        result = buildFrom(proto, dependencies, true);
+      } catch (DescriptorValidationException e) {
+        throw new IllegalArgumentException(
+          "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
+      }
+
+      final ExtensionRegistry registry =
+          descriptorAssigner.assignDescriptors(result);
+
+      if (registry != null) {
+        // We must re-parse the proto using the registry.
+        try {
+          proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
+        } catch (InvalidProtocolBufferException e) {
+          throw new IllegalArgumentException(
+            "Failed to parse protocol buffer descriptor for generated code.",
+            e);
+        }
+
+        result.setProto(proto);
+      }
+    }
+
+    /**
+     * This method is to be called by generated code only.  It uses Java
+     * reflection to load the dependencies' descriptors.
+     */
+    public static void internalBuildGeneratedFileFrom(
+        final String[] descriptorDataParts,
+        final Class<?> descriptorOuterClass,
+        final String[] dependencies,
+        final String[] dependencyFileNames,
+        final InternalDescriptorAssigner descriptorAssigner) {
+      List<FileDescriptor> descriptors = new ArrayList<FileDescriptor>();
+      for (int i = 0; i < dependencies.length; i++) {
+        try {
+          Class<?> clazz =
+              descriptorOuterClass.getClassLoader().loadClass(dependencies[i]);
+          descriptors.add(
+              (FileDescriptor) clazz.getField("descriptor").get(null));
+        } catch (Exception e) {
+          // We allow unknown dependencies by default. If a dependency cannot
+          // be found we only generate a warning.
+          logger.warning("Descriptors for \"" + dependencyFileNames[i] +
+              "\" can not be found.");
+        }
+      }
+      FileDescriptor[] descriptorArray = new FileDescriptor[descriptors.size()];
+      descriptors.toArray(descriptorArray);
+      internalBuildGeneratedFileFrom(
+          descriptorDataParts, descriptorArray, descriptorAssigner);
+    }
+
+    /**
+     * This method is to be called by generated code only.  It is used to
+     * update the FileDescriptorProto associated with the descriptor by
+     * parsing it again with the given ExtensionRegistry. This is needed to
+     * recognize custom options.
+     */
+    public static void internalUpdateFileDescriptor(
+        final FileDescriptor descriptor,
+        final ExtensionRegistry registry) {
+      ByteString bytes = descriptor.proto.toByteString();
+      FileDescriptorProto proto;
+      try {
+        proto = FileDescriptorProto.parseFrom(bytes, registry);
+      } catch (InvalidProtocolBufferException e) {
+        throw new IllegalArgumentException(
+          "Failed to parse protocol buffer descriptor for generated code.", e);
+      }
+      descriptor.setProto(proto);
+    }
+
+    /**
+     * This class should be used by generated code only.  When calling
+     * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
+     * provides a callback implementing this interface.  The callback is called
+     * after the FileDescriptor has been constructed, in order to assign all
+     * the global variables defined in the generated code which point at parts
+     * of the FileDescriptor.  The callback returns an ExtensionRegistry which
+     * contains any extensions which might be used in the descriptor -- that
+     * is, extensions of the various "Options" messages defined in
+     * descriptor.proto.  The callback may also return null to indicate that
+     * no extensions are used in the descriptor.
+     */
+    public interface InternalDescriptorAssigner {
+      ExtensionRegistry assignDescriptors(FileDescriptor root);
+    }
+
+    private FileDescriptorProto proto;
+    private final Descriptor[] messageTypes;
+    private final EnumDescriptor[] enumTypes;
+    private final ServiceDescriptor[] services;
+    private final FieldDescriptor[] extensions;
+    private final FileDescriptor[] dependencies;
+    private final FileDescriptor[] publicDependencies;
+    private final DescriptorPool pool;
+
+    private FileDescriptor(final FileDescriptorProto proto,
+                           final FileDescriptor[] dependencies,
+                           final DescriptorPool pool,
+                           boolean allowUnknownDependencies)
+                    throws DescriptorValidationException {
+      this.pool = pool;
+      this.proto = proto;
+      this.dependencies = dependencies.clone();
+      HashMap<String, FileDescriptor> nameToFileMap =
+          new HashMap<String, FileDescriptor>();
+      for (FileDescriptor file : dependencies) {
+        nameToFileMap.put(file.getName(), file);
+      }
+      List<FileDescriptor> publicDependencies = new ArrayList<FileDescriptor>();
+      for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
+        int index = proto.getPublicDependency(i);
+        if (index < 0 || index >= proto.getDependencyCount()) {
+          throw new DescriptorValidationException(this,
+              "Invalid public dependency index.");
+        }
+        String name = proto.getDependency(index);
+        FileDescriptor file = nameToFileMap.get(name);
+        if (file == null) {
+          if (!allowUnknownDependencies) {
+            throw new DescriptorValidationException(this,
+                "Invalid public dependency: " + name);
+          }
+          // Ignore unknown dependencies.
+        } else {
+          publicDependencies.add(file);
+        }
+      }
+      this.publicDependencies = new FileDescriptor[publicDependencies.size()];
+      publicDependencies.toArray(this.publicDependencies);
+
+      pool.addPackage(getPackage(), this);
+
+      messageTypes = new Descriptor[proto.getMessageTypeCount()];
+      for (int i = 0; i < proto.getMessageTypeCount(); i++) {
+        messageTypes[i] =
+          new Descriptor(proto.getMessageType(i), this, null, i);
+      }
+
+      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+        enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
+      }
+
+      services = new ServiceDescriptor[proto.getServiceCount()];
+      for (int i = 0; i < proto.getServiceCount(); i++) {
+        services[i] = new ServiceDescriptor(proto.getService(i), this, i);
+      }
+
+      extensions = new FieldDescriptor[proto.getExtensionCount()];
+      for (int i = 0; i < proto.getExtensionCount(); i++) {
+        extensions[i] = new FieldDescriptor(
+          proto.getExtension(i), this, null, i, true);
+      }
+    }
+
+    /**
+     * Create a placeholder FileDescriptor for a message Descriptor.
+     */
+    FileDescriptor(String packageName, Descriptor message)
+        throws DescriptorValidationException {
+      this.pool = new DescriptorPool(new FileDescriptor[0], true);
+      this.proto = FileDescriptorProto.newBuilder()
+          .setName(message.getFullName() + ".placeholder.proto")
+          .setPackage(packageName).addMessageType(message.toProto()).build();
+      this.dependencies = new FileDescriptor[0];
+      this.publicDependencies = new FileDescriptor[0];
+
+      messageTypes = new Descriptor[] {message};
+      enumTypes = new EnumDescriptor[0];
+      services = new ServiceDescriptor[0];
+      extensions = new FieldDescriptor[0];
+
+      pool.addPackage(packageName, this);
+      pool.addSymbol(message);
+    }
+
+    /** Look up and cross-link all field types, etc. */
+    private void crossLink() throws DescriptorValidationException {
+      for (final Descriptor messageType : messageTypes) {
+        messageType.crossLink();
+      }
+
+      for (final ServiceDescriptor service : services) {
+        service.crossLink();
+      }
+
+      for (final FieldDescriptor extension : extensions) {
+        extension.crossLink();
+      }
+    }
+
+    /**
+     * Replace our {@link FileDescriptorProto} with the given one, which is
+     * identical except that it might contain extensions that weren't present
+     * in the original.  This method is needed for bootstrapping when a file
+     * defines custom options.  The options may be defined in the file itself,
+     * so we can't actually parse them until we've constructed the descriptors,
+     * but to construct the descriptors we have to have parsed the descriptor
+     * protos.  So, we have to parse the descriptor protos a second time after
+     * constructing the descriptors.
+     */
+    private void setProto(final FileDescriptorProto proto) {
+      this.proto = proto;
+
+      for (int i = 0; i < messageTypes.length; i++) {
+        messageTypes[i].setProto(proto.getMessageType(i));
+      }
+
+      for (int i = 0; i < enumTypes.length; i++) {
+        enumTypes[i].setProto(proto.getEnumType(i));
+      }
+
+      for (int i = 0; i < services.length; i++) {
+        services[i].setProto(proto.getService(i));
+      }
+
+      for (int i = 0; i < extensions.length; i++) {
+        extensions[i].setProto(proto.getExtension(i));
+      }
+    }
+
+    boolean supportsUnknownEnumValue() {
+      return getSyntax() == Syntax.PROTO3;
+    }
+  }
+
+  // =================================================================
+
+  /** Describes a message type. */
+  public static final class Descriptor extends GenericDescriptor {
+    /**
+     * Get the index of this descriptor within its parent.  In other words,
+     * given a {@link FileDescriptor} {@code file}, the following is true:
+     * <pre>
+     *   for all i in [0, file.getMessageTypeCount()):
+     *     file.getMessageType(i).getIndex() == i
+     * </pre>
+     * Similarly, for a {@link Descriptor} {@code messageType}:
+     * <pre>
+     *   for all i in [0, messageType.getNestedTypeCount()):
+     *     messageType.getNestedType(i).getIndex() == i
+     * </pre>
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public DescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the type's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /**
+     * Get the type's fully-qualified name, within the proto language's
+     * namespace.  This differs from the Java name.  For example, given this
+     * {@code .proto}:
+     * <pre>
+     *   package foo.bar;
+     *   option java_package = "com.example.protos"
+     *   message Baz {}
+     * </pre>
+     * {@code Baz}'s full name is "foo.bar.Baz".
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the {@link FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** If this is a nested type, get the outer descriptor, otherwise null. */
+    public Descriptor getContainingType() { return containingType; }
+
+    /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
+    public MessageOptions getOptions() { return proto.getOptions(); }
+
+    /** Get a list of this message type's fields. */
+    public List<FieldDescriptor> getFields() {
+      return Collections.unmodifiableList(Arrays.asList(fields));
+    }
+
+    /** Get a list of this message type's oneofs. */
+    public List<OneofDescriptor> getOneofs() {
+      return Collections.unmodifiableList(Arrays.asList(oneofs));
+    }
+
+    /** Get a list of this message type's extensions. */
+    public List<FieldDescriptor> getExtensions() {
+      return Collections.unmodifiableList(Arrays.asList(extensions));
+    }
+
+    /** Get a list of message types nested within this one. */
+    public List<Descriptor> getNestedTypes() {
+      return Collections.unmodifiableList(Arrays.asList(nestedTypes));
+    }
+
+    /** Get a list of enum types nested within this one. */
+    public List<EnumDescriptor> getEnumTypes() {
+      return Collections.unmodifiableList(Arrays.asList(enumTypes));
+    }
+
+    /** Determines if the given field number is an extension. */
+    public boolean isExtensionNumber(final int number) {
+      for (final DescriptorProto.ExtensionRange range :
+          proto.getExtensionRangeList()) {
+        if (range.getStart() <= number && number < range.getEnd()) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    /** Determines if the given field number is reserved. */
+    public boolean isReservedNumber(final int number) {
+      for (final DescriptorProto.ReservedRange range :
+          proto.getReservedRangeList()) {
+        if (range.getStart() <= number && number < range.getEnd()) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    /** Determines if the given field name is reserved. */
+    public boolean isReservedName(final String name) {
+      if (name == null) {
+        throw new NullPointerException();
+      }
+      for (final String reservedName : proto.getReservedNameList()) {
+        if (reservedName.equals(name)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    /**
+     * Indicates whether the message can be extended.  That is, whether it has
+     * any "extensions x to y" ranges declared on it.
+     */
+    public boolean isExtendable() {
+      return proto.getExtensionRangeList().size() != 0;
+    }
+
+    /**
+     * Finds a field by name.
+     * @param name The unqualified name of the field (e.g. "foo").
+     * @return The field's descriptor, or {@code null} if not found.
+     */
+    public FieldDescriptor findFieldByName(final String name) {
+      final GenericDescriptor result =
+          file.pool.findSymbol(fullName + '.' + name);
+      if (result != null && result instanceof FieldDescriptor) {
+        return (FieldDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Finds a field by field number.
+     * @param number The field number within this message type.
+     * @return The field's descriptor, or {@code null} if not found.
+     */
+    public FieldDescriptor findFieldByNumber(final int number) {
+      return file.pool.fieldsByNumber.get(
+        new DescriptorPool.DescriptorIntPair(this, number));
+    }
+
+    /**
+     * Finds a nested message type by name.
+     * @param name The unqualified name of the nested type (e.g. "Foo").
+     * @return The types's descriptor, or {@code null} if not found.
+     */
+    public Descriptor findNestedTypeByName(final String name) {
+      final GenericDescriptor result =
+          file.pool.findSymbol(fullName + '.' + name);
+      if (result != null && result instanceof Descriptor) {
+        return (Descriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Finds a nested enum type by name.
+     * @param name The unqualified name of the nested type (e.g. "Foo").
+     * @return The types's descriptor, or {@code null} if not found.
+     */
+    public EnumDescriptor findEnumTypeByName(final String name) {
+      final GenericDescriptor result =
+          file.pool.findSymbol(fullName + '.' + name);
+      if (result != null && result instanceof EnumDescriptor) {
+        return (EnumDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    private final int index;
+    private DescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+    private final Descriptor containingType;
+    private final Descriptor[] nestedTypes;
+    private final EnumDescriptor[] enumTypes;
+    private final FieldDescriptor[] fields;
+    private final FieldDescriptor[] extensions;
+    private final OneofDescriptor[] oneofs;
+
+    // Used to create a placeholder when the type cannot be found.
+    Descriptor(final String fullname) throws DescriptorValidationException {
+      String name = fullname;
+      String packageName = "";
+      int pos = fullname.lastIndexOf('.');
+      if (pos != -1) {
+        name = fullname.substring(pos + 1);
+        packageName = fullname.substring(0, pos);
+      }
+      this.index = 0;
+      this.proto = DescriptorProto.newBuilder().setName(name).addExtensionRange(
+          DescriptorProto.ExtensionRange.newBuilder().setStart(1)
+          .setEnd(536870912).build()).build();
+      this.fullName = fullname;
+      this.containingType = null;
+
+      this.nestedTypes = new Descriptor[0];
+      this.enumTypes = new EnumDescriptor[0];
+      this.fields = new FieldDescriptor[0];
+      this.extensions = new FieldDescriptor[0];
+      this.oneofs = new OneofDescriptor[0];
+
+      // Create a placeholder FileDescriptor to hold this message.
+      this.file = new FileDescriptor(packageName, this);
+    }
+
+    private Descriptor(final DescriptorProto proto,
+                       final FileDescriptor file,
+                       final Descriptor parent,
+                       final int index)
+                throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      fullName = computeFullName(file, parent, proto.getName());
+      this.file = file;
+      containingType = parent;
+
+      oneofs = new OneofDescriptor[proto.getOneofDeclCount()];
+      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+        oneofs[i] = new OneofDescriptor(
+          proto.getOneofDecl(i), file, this, i);
+      }
+
+      nestedTypes = new Descriptor[proto.getNestedTypeCount()];
+      for (int i = 0; i < proto.getNestedTypeCount(); i++) {
+        nestedTypes[i] = new Descriptor(
+          proto.getNestedType(i), file, this, i);
+      }
+
+      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+        enumTypes[i] = new EnumDescriptor(
+          proto.getEnumType(i), file, this, i);
+      }
+
+      fields = new FieldDescriptor[proto.getFieldCount()];
+      for (int i = 0; i < proto.getFieldCount(); i++) {
+        fields[i] = new FieldDescriptor(
+          proto.getField(i), file, this, i, false);
+      }
+
+      extensions = new FieldDescriptor[proto.getExtensionCount()];
+      for (int i = 0; i < proto.getExtensionCount(); i++) {
+        extensions[i] = new FieldDescriptor(
+          proto.getExtension(i), file, this, i, true);
+      }
+
+      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
+        oneofs[i].fields = new FieldDescriptor[oneofs[i].getFieldCount()];
+        oneofs[i].fieldCount = 0;
+      }
+      for (int i = 0; i < proto.getFieldCount(); i++) {
+        OneofDescriptor oneofDescriptor = fields[i].getContainingOneof();
+        if (oneofDescriptor != null) {
+          oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
+        }
+      }
+
+      file.pool.addSymbol(this);
+    }
+
+    /** Look up and cross-link all field types, etc. */
+    private void crossLink() throws DescriptorValidationException {
+      for (final Descriptor nestedType : nestedTypes) {
+        nestedType.crossLink();
+      }
+
+      for (final FieldDescriptor field : fields) {
+        field.crossLink();
+      }
+
+      for (final FieldDescriptor extension : extensions) {
+        extension.crossLink();
+      }
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final DescriptorProto proto) {
+      this.proto = proto;
+
+      for (int i = 0; i < nestedTypes.length; i++) {
+        nestedTypes[i].setProto(proto.getNestedType(i));
+      }
+
+      for (int i = 0; i < enumTypes.length; i++) {
+        enumTypes[i].setProto(proto.getEnumType(i));
+      }
+
+      for (int i = 0; i < fields.length; i++) {
+        fields[i].setProto(proto.getField(i));
+      }
+
+      for (int i = 0; i < extensions.length; i++) {
+        extensions[i].setProto(proto.getExtension(i));
+      }
+    }
+  }
+
+  // =================================================================
+
+  /** Describes a field of a message type. */
+  public static final class FieldDescriptor
+        extends GenericDescriptor
+        implements Comparable<FieldDescriptor>,
+                 FieldSet.FieldDescriptorLite<FieldDescriptor> {
+    /**
+     * Get the index of this descriptor within its parent.
+     * @see Descriptors.Descriptor#getIndex()
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public FieldDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the field's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /** Get the field's number. */
+    @Override
+    public int getNumber() {
+      return proto.getNumber();
+    }
+
+    /**
+     * Get the field's fully-qualified name.
+     * @see Descriptors.Descriptor#getFullName()
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the JSON name of this field. */
+    public String getJsonName() {
+      return jsonName;
+    }
+
+    /**
+     * Get the field's java type.  This is just for convenience.  Every
+     * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
+     */
+    public JavaType getJavaType() { return type.getJavaType(); }
+
+    /** For internal use only. */
+    @Override
+    public WireFormat.JavaType getLiteJavaType() {
+      return getLiteType().getJavaType();
+    }
+
+    /** Get the {@code FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** Get the field's declared type. */
+    public Type getType() { return type; }
+
+    /** For internal use only. */
+    @Override
+    public WireFormat.FieldType getLiteType() {
+      return table[type.ordinal()];
+    }
+
+    /** For internal use only. */
+    public boolean needsUtf8Check() {
+      if (type != Type.STRING) {
+        return false;
+      }
+      if (getContainingType().getOptions().getMapEntry()) {
+        // Always enforce strict UTF-8 checking for map fields.
+        return true;
+      }
+      if (getFile().getSyntax() == Syntax.PROTO3) {
+        return true;
+      }
+      return getFile().getOptions().getJavaStringCheckUtf8();
+    }
+
+    public boolean isMapField() {
+      return getType() == Type.MESSAGE && isRepeated()
+          && getMessageType().getOptions().getMapEntry();
+    }
+
+    // I'm pretty sure values() constructs a new array every time, since there
+    // is nothing stopping the caller from mutating the array.  Therefore we
+    // make a static copy here.
+    private static final WireFormat.FieldType[] table =
+        WireFormat.FieldType.values();
+
+    /** Is this field declared required? */
+    public boolean isRequired() {
+      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
+    }
+
+    /** Is this field declared optional? */
+    public boolean isOptional() {
+      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
+    }
+
+    /** Is this field declared repeated? */
+    @Override
+    public boolean isRepeated() {
+      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
+    }
+
+    /** Does this field have the {@code [packed = true]} option or is this field
+     *  packable in proto3 and not explicitly setted to unpacked?
+     */
+    @Override
+    public boolean isPacked() {
+      if (!isPackable()) {
+        return false;
+      }
+      if (getFile().getSyntax() == FileDescriptor.Syntax.PROTO2) {
+        return getOptions().getPacked();
+      } else {
+        return !getOptions().hasPacked() || getOptions().getPacked();
+      }
+    }
+
+    /** Can this field be packed? i.e. is it a repeated primitive field? */
+    public boolean isPackable() {
+      return isRepeated() && getLiteType().isPackable();
+    }
+
+    /** Returns true if the field had an explicitly-defined default value. */
+    public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
+
+    /**
+     * Returns the field's default value.  Valid for all types except for
+     * messages and groups.  For all other types, the object returned is of
+     * the same class that would returned by Message.getField(this).
+     */
+    public Object getDefaultValue() {
+      if (getJavaType() == JavaType.MESSAGE) {
+        throw new UnsupportedOperationException(
+          "FieldDescriptor.getDefaultValue() called on an embedded message " +
+          "field.");
+      }
+      return defaultValue;
+    }
+
+    /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
+    public FieldOptions getOptions() { return proto.getOptions(); }
+
+    /** Is this field an extension? */
+    public boolean isExtension() { return proto.hasExtendee(); }
+
+    /**
+     * Get the field's containing type. For extensions, this is the type being
+     * extended, not the location where the extension was defined.  See
+     * {@link #getExtensionScope()}.
+     */
+    public Descriptor getContainingType() { return containingType; }
+
+    /** Get the field's containing oneof. */
+    public OneofDescriptor getContainingOneof() { return containingOneof; }
+
+    /**
+     * For extensions defined nested within message types, gets the outer
+     * type.  Not valid for non-extension fields.  For example, consider
+     * this {@code .proto} file:
+     * <pre>
+     *   message Foo {
+     *     extensions 1000 to max;
+     *   }
+     *   extend Foo {
+     *     optional int32 baz = 1234;
+     *   }
+     *   message Bar {
+     *     extend Foo {
+     *       optional int32 qux = 4321;
+     *     }
+     *   }
+     * </pre>
+     * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
+     * However, {@code baz}'s extension scope is {@code null} while
+     * {@code qux}'s extension scope is {@code Bar}.
+     */
+    public Descriptor getExtensionScope() {
+      if (!isExtension()) {
+        throw new UnsupportedOperationException(
+          "This field is not an extension.");
+      }
+      return extensionScope;
+    }
+
+    /** For embedded message and group fields, gets the field's type. */
+    public Descriptor getMessageType() {
+      if (getJavaType() != JavaType.MESSAGE) {
+        throw new UnsupportedOperationException(
+          "This field is not of message type.");
+      }
+      return messageType;
+    }
+
+    /** For enum fields, gets the field's type. */
+    @Override
+    public EnumDescriptor getEnumType() {
+      if (getJavaType() != JavaType.ENUM) {
+        throw new UnsupportedOperationException(
+          "This field is not of enum type.");
+      }
+      return enumType;
+    }
+
+    /**
+     * Compare with another {@code FieldDescriptor}.  This orders fields in
+     * "canonical" order, which simply means ascending order by field number.
+     * {@code other} must be a field of the same type -- i.e.
+     * {@code getContainingType()} must return the same {@code Descriptor} for
+     * both fields.
+     *
+     * @return negative, zero, or positive if {@code this} is less than,
+     *         equal to, or greater than {@code other}, respectively.
+     */
+    @Override
+    public int compareTo(final FieldDescriptor other) {
+      if (other.containingType != containingType) {
+        throw new IllegalArgumentException(
+          "FieldDescriptors can only be compared to other FieldDescriptors " +
+          "for fields of the same message type.");
+      }
+      return getNumber() - other.getNumber();
+    }
+
+    @Override
+    public String toString() {
+      return getFullName();
+    }
+
+    private final int index;
+
+    private FieldDescriptorProto proto;
+    private final String fullName;
+    private final String jsonName;
+    private final FileDescriptor file;
+    private final Descriptor extensionScope;
+
+    // Possibly initialized during cross-linking.
+    private Type type;
+    private Descriptor containingType;
+    private Descriptor messageType;
+    private OneofDescriptor containingOneof;
+    private EnumDescriptor enumType;
+    private Object defaultValue;
+
+    public enum Type {
+      DOUBLE  (JavaType.DOUBLE     ),
+      FLOAT   (JavaType.FLOAT      ),
+      INT64   (JavaType.LONG       ),
+      UINT64  (JavaType.LONG       ),
+      INT32   (JavaType.INT        ),
+      FIXED64 (JavaType.LONG       ),
+      FIXED32 (JavaType.INT        ),
+      BOOL    (JavaType.BOOLEAN    ),
+      STRING  (JavaType.STRING     ),
+      GROUP   (JavaType.MESSAGE    ),
+      MESSAGE (JavaType.MESSAGE    ),
+      BYTES   (JavaType.BYTE_STRING),
+      UINT32  (JavaType.INT        ),
+      ENUM    (JavaType.ENUM       ),
+      SFIXED32(JavaType.INT        ),
+      SFIXED64(JavaType.LONG       ),
+      SINT32  (JavaType.INT        ),
+      SINT64  (JavaType.LONG       );
+
+      Type(final JavaType javaType) {
+        this.javaType = javaType;
+      }
+
+      private JavaType javaType;
+
+      public FieldDescriptorProto.Type toProto() {
+        return FieldDescriptorProto.Type.forNumber(ordinal() + 1);
+      }
+      public JavaType getJavaType() { return javaType; }
+
+      public static Type valueOf(final FieldDescriptorProto.Type type) {
+        return values()[type.getNumber() - 1];
+      }
+    }
+
+    static {
+      // Refuse to init if someone added a new declared type.
+      if (Type.values().length != FieldDescriptorProto.Type.values().length) {
+        throw new RuntimeException(""
+            + "descriptor.proto has a new declared type but Descriptors.java "
+            + "wasn't updated.");
+      }
+    }
+
+    public enum JavaType {
+      INT(0),
+      LONG(0L),
+      FLOAT(0F),
+      DOUBLE(0D),
+      BOOLEAN(false),
+      STRING(""),
+      BYTE_STRING(ByteString.EMPTY),
+      ENUM(null),
+      MESSAGE(null);
+
+      JavaType(final Object defaultDefault) {
+        this.defaultDefault = defaultDefault;
+      }
+
+      /**
+       * The default default value for fields of this type, if it's a primitive
+       * type.  This is meant for use inside this file only, hence is private.
+       */
+      private final Object defaultDefault;
+    }
+
+    // TODO(xiaofeng): Implement it consistently across different languages. See b/24751348.
+    private static String fieldNameToLowerCamelCase(String name) {
+      StringBuilder result = new StringBuilder(name.length());
+      boolean isNextUpperCase = false;
+      for (int i = 0; i < name.length(); i++) {
+        Character ch = name.charAt(i);
+        if (Character.isLowerCase(ch)) {
+          if (isNextUpperCase) {
+            result.append(Character.toUpperCase(ch));
+          } else {
+            result.append(ch);
+          }
+          isNextUpperCase = false;
+        } else if (Character.isUpperCase(ch)) {
+          if (i == 0) {
+            // Force first letter to lower-case.
+            result.append(Character.toLowerCase(ch));
+          } else {
+            // Capital letters after the first are left as-is.
+            result.append(ch);
+          }
+          isNextUpperCase = false;
+        } else if (Character.isDigit(ch)) {
+          result.append(ch);
+          isNextUpperCase = false;
+        } else {
+          isNextUpperCase = true;
+        }
+      }
+      return result.toString();
+    }
+
+    private FieldDescriptor(final FieldDescriptorProto proto,
+                            final FileDescriptor file,
+                            final Descriptor parent,
+                            final int index,
+                            final boolean isExtension)
+                     throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      fullName = computeFullName(file, parent, proto.getName());
+      this.file = file;
+      if (proto.hasJsonName()) {
+        jsonName = proto.getJsonName();
+      } else {
+        jsonName = fieldNameToLowerCamelCase(proto.getName());
+      }
+
+      if (proto.hasType()) {
+        type = Type.valueOf(proto.getType());
+      }
+
+      if (getNumber() <= 0) {
+        throw new DescriptorValidationException(this,
+          "Field numbers must be positive integers.");
+      }
+
+      if (isExtension) {
+        if (!proto.hasExtendee()) {
+          throw new DescriptorValidationException(this,
+            "FieldDescriptorProto.extendee not set for extension field.");
+        }
+        containingType = null;  // Will be filled in when cross-linking
+        if (parent != null) {
+          extensionScope = parent;
+        } else {
+          extensionScope = null;
+        }
+
+        if (proto.hasOneofIndex()) {
+          throw new DescriptorValidationException(this,
+            "FieldDescriptorProto.oneof_index set for extension field.");
+        }
+        containingOneof = null;
+      } else {
+        if (proto.hasExtendee()) {
+          throw new DescriptorValidationException(this,
+            "FieldDescriptorProto.extendee set for non-extension field.");
+        }
+        containingType = parent;
+
+        if (proto.hasOneofIndex()) {
+          if (proto.getOneofIndex() < 0 ||
+              proto.getOneofIndex() >= parent.toProto().getOneofDeclCount()) {
+            throw new DescriptorValidationException(this,
+              "FieldDescriptorProto.oneof_index is out of range for type "
+              + parent.getName());
+          }
+          containingOneof = parent.getOneofs().get(proto.getOneofIndex());
+          containingOneof.fieldCount++;
+        } else {
+          containingOneof = null;
+        }
+        extensionScope = null;
+      }
+
+      file.pool.addSymbol(this);
+    }
+
+    /** Look up and cross-link all field types, etc. */
+    private void crossLink() throws DescriptorValidationException {
+      if (proto.hasExtendee()) {
+        final GenericDescriptor extendee =
+          file.pool.lookupSymbol(proto.getExtendee(), this,
+              DescriptorPool.SearchFilter.TYPES_ONLY);
+        if (!(extendee instanceof Descriptor)) {
+          throw new DescriptorValidationException(this,
+              '\"' + proto.getExtendee() + "\" is not a message type.");
+        }
+        containingType = (Descriptor)extendee;
+
+        if (!getContainingType().isExtensionNumber(getNumber())) {
+          throw new DescriptorValidationException(this,
+              '\"' + getContainingType().getFullName() +
+              "\" does not declare " + getNumber() +
+              " as an extension number.");
+        }
+      }
+
+      if (proto.hasTypeName()) {
+        final GenericDescriptor typeDescriptor =
+          file.pool.lookupSymbol(proto.getTypeName(), this,
+              DescriptorPool.SearchFilter.TYPES_ONLY);
+
+        if (!proto.hasType()) {
+          // Choose field type based on symbol.
+          if (typeDescriptor instanceof Descriptor) {
+            type = Type.MESSAGE;
+          } else if (typeDescriptor instanceof EnumDescriptor) {
+            type = Type.ENUM;
+          } else {
+            throw new DescriptorValidationException(this,
+                '\"' + proto.getTypeName() + "\" is not a type.");
+          }
+        }
+
+        if (getJavaType() == JavaType.MESSAGE) {
+          if (!(typeDescriptor instanceof Descriptor)) {
+            throw new DescriptorValidationException(this,
+                '\"' + proto.getTypeName() + "\" is not a message type.");
+          }
+          messageType = (Descriptor)typeDescriptor;
+
+          if (proto.hasDefaultValue()) {
+            throw new DescriptorValidationException(this,
+              "Messages can't have default values.");
+          }
+        } else if (getJavaType() == JavaType.ENUM) {
+          if (!(typeDescriptor instanceof EnumDescriptor)) {
+            throw new DescriptorValidationException(this,
+                '\"' + proto.getTypeName() + "\" is not an enum type.");
+          }
+          enumType = (EnumDescriptor)typeDescriptor;
+        } else {
+          throw new DescriptorValidationException(this,
+            "Field with primitive type has type_name.");
+        }
+      } else {
+        if (getJavaType() == JavaType.MESSAGE ||
+            getJavaType() == JavaType.ENUM) {
+          throw new DescriptorValidationException(this,
+            "Field with message or enum type missing type_name.");
+        }
+      }
+
+      // Only repeated primitive fields may be packed.
+      if (proto.getOptions().getPacked() && !isPackable()) {
+        throw new DescriptorValidationException(this,
+          "[packed = true] can only be specified for repeated primitive " +
+          "fields.");
+      }
+
+      // We don't attempt to parse the default value until here because for
+      // enums we need the enum type's descriptor.
+      if (proto.hasDefaultValue()) {
+        if (isRepeated()) {
+          throw new DescriptorValidationException(this,
+            "Repeated fields cannot have default values.");
+        }
+
+        try {
+          switch (getType()) {
+            case INT32:
+            case SINT32:
+            case SFIXED32:
+              defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
+              break;
+            case UINT32:
+            case FIXED32:
+              defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
+              break;
+            case INT64:
+            case SINT64:
+            case SFIXED64:
+              defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
+              break;
+            case UINT64:
+            case FIXED64:
+              defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
+              break;
+            case FLOAT:
+              if (proto.getDefaultValue().equals("inf")) {
+                defaultValue = Float.POSITIVE_INFINITY;
+              } else if (proto.getDefaultValue().equals("-inf")) {
+                defaultValue = Float.NEGATIVE_INFINITY;
+              } else if (proto.getDefaultValue().equals("nan")) {
+                defaultValue = Float.NaN;
+              } else {
+                defaultValue = Float.valueOf(proto.getDefaultValue());
+              }
+              break;
+            case DOUBLE:
+              if (proto.getDefaultValue().equals("inf")) {
+                defaultValue = Double.POSITIVE_INFINITY;
+              } else if (proto.getDefaultValue().equals("-inf")) {
+                defaultValue = Double.NEGATIVE_INFINITY;
+              } else if (proto.getDefaultValue().equals("nan")) {
+                defaultValue = Double.NaN;
+              } else {
+                defaultValue = Double.valueOf(proto.getDefaultValue());
+              }
+              break;
+            case BOOL:
+              defaultValue = Boolean.valueOf(proto.getDefaultValue());
+              break;
+            case STRING:
+              defaultValue = proto.getDefaultValue();
+              break;
+            case BYTES:
+              try {
+                defaultValue =
+                  TextFormat.unescapeBytes(proto.getDefaultValue());
+              } catch (TextFormat.InvalidEscapeSequenceException e) {
+                throw new DescriptorValidationException(this,
+                  "Couldn't parse default value: " + e.getMessage(), e);
+              }
+              break;
+            case ENUM:
+              defaultValue = enumType.findValueByName(proto.getDefaultValue());
+              if (defaultValue == null) {
+                throw new DescriptorValidationException(this,
+                  "Unknown enum default value: \"" +
+                  proto.getDefaultValue() + '\"');
+              }
+              break;
+            case MESSAGE:
+            case GROUP:
+              throw new DescriptorValidationException(this,
+                "Message type had default value.");
+          }
+        } catch (NumberFormatException e) {
+          throw new DescriptorValidationException(this,
+              "Could not parse default value: \"" +
+              proto.getDefaultValue() + '\"', e);
+        }
+      } else {
+        // Determine the default default for this field.
+        if (isRepeated()) {
+          defaultValue = Collections.emptyList();
+        } else {
+          switch (getJavaType()) {
+            case ENUM:
+              // We guarantee elsewhere that an enum type always has at least
+              // one possible value.
+              defaultValue = enumType.getValues().get(0);
+              break;
+            case MESSAGE:
+              defaultValue = null;
+              break;
+            default:
+              defaultValue = getJavaType().defaultDefault;
+              break;
+          }
+        }
+      }
+
+      if (!isExtension()) {
+        file.pool.addFieldByNumber(this);
+      }
+
+      if (containingType != null &&
+          containingType.getOptions().getMessageSetWireFormat()) {
+        if (isExtension()) {
+          if (!isOptional() || getType() != Type.MESSAGE) {
+            throw new DescriptorValidationException(this,
+              "Extensions of MessageSets must be optional messages.");
+          }
+        } else {
+          throw new DescriptorValidationException(this,
+            "MessageSets cannot have fields, only extensions.");
+        }
+      }
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final FieldDescriptorProto proto) {
+      this.proto = proto;
+    }
+
+    /**
+     * For internal use only.  This is to satisfy the FieldDescriptorLite
+     * interface.
+     */
+    @Override
+    public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
+      // FieldDescriptors are only used with non-lite messages so we can just
+      // down-cast and call mergeFrom directly.
+      return ((Message.Builder) to).mergeFrom((Message) from);
+    }
+
+  }
+
+  // =================================================================
+
+  /** Describes an enum type. */
+  public static final class EnumDescriptor extends GenericDescriptor
+      implements Internal.EnumLiteMap<EnumValueDescriptor> {
+    /**
+     * Get the index of this descriptor within its parent.
+     * @see Descriptors.Descriptor#getIndex()
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public EnumDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the type's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /**
+     * Get the type's fully-qualified name.
+     * @see Descriptors.Descriptor#getFullName()
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the {@link FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** If this is a nested type, get the outer descriptor, otherwise null. */
+    public Descriptor getContainingType() { return containingType; }
+
+    /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
+    public EnumOptions getOptions() { return proto.getOptions(); }
+
+    /** Get a list of defined values for this enum. */
+    public List<EnumValueDescriptor> getValues() {
+      return Collections.unmodifiableList(Arrays.asList(values));
+    }
+
+    /**
+     * Find an enum value by name.
+     * @param name The unqualified name of the value (e.g. "FOO").
+     * @return the value's descriptor, or {@code null} if not found.
+     */
+    public EnumValueDescriptor findValueByName(final String name) {
+      final GenericDescriptor result =
+          file.pool.findSymbol(fullName + '.' + name);
+      if (result != null && result instanceof EnumValueDescriptor) {
+        return (EnumValueDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Find an enum value by number.  If multiple enum values have the same
+     * number, this returns the first defined value with that number.
+     * @param number The value's number.
+     * @return the value's descriptor, or {@code null} if not found.
+     */
+    @Override
+    public EnumValueDescriptor findValueByNumber(final int number) {
+      return file.pool.enumValuesByNumber.get(
+        new DescriptorPool.DescriptorIntPair(this, number));
+    }
+
+    /**
+     * Get the enum value for a number. If no enum value has this number,
+     * construct an EnumValueDescriptor for it.
+     */
+    public EnumValueDescriptor findValueByNumberCreatingIfUnknown(final int number) {
+      EnumValueDescriptor result = findValueByNumber(number);
+      if (result != null) {
+        return result;
+      }
+      // The number represents an unknown enum value.
+      synchronized (this) {
+        // Descriptors are compared by object identity so for the same number
+        // we need to return the same EnumValueDescriptor object. This means
+        // we have to store created EnumValueDescriptors. However, as there
+        // are potentially 2G unknown enum values, storing all of these
+        // objects persistently will consume lots of memory for long-running
+        // services and it's also unnecessary as not many EnumValueDescriptors
+        // will be used at the same time.
+        //
+        // To solve the problem we take advantage of Java's weak references and
+        // rely on gc to release unused descriptors.
+        //
+        // Here is how it works:
+        //   * We store unknown EnumValueDescriptors in a WeakHashMap with the
+        //     value being a weak reference to the descriptor.
+        //   * The descriptor holds a strong reference to the key so as long
+        //     as the EnumValueDescriptor is in use, the key will be there
+        //     and the corresponding map entry will be there. Following-up
+        //     queries with the same number will return the same descriptor.
+        //   * If the user no longer uses an unknown EnumValueDescriptor,
+        //     it will be gc-ed since we only hold a weak reference to it in
+        //     the map. The key in the corresponding map entry will also be
+        //     gc-ed as the only strong reference to it is in the descriptor
+        //     which is just gc-ed. With the key being gone WeakHashMap will
+        //     then remove the whole entry. This way unknown descriptors will
+        //     be freed automatically and we don't need to do anything to
+        //     clean-up unused map entries.
+
+        // Note: We must use "new Integer(number)" here because we don't want
+        // these Integer objects to be cached.
+        Integer key = new Integer(number);
+        WeakReference<EnumValueDescriptor> reference = unknownValues.get(key);
+        if (reference != null) {
+          result = reference.get();
+        }
+        if (result == null) {
+          result = new EnumValueDescriptor(file, this, key);
+          unknownValues.put(key, new WeakReference<EnumValueDescriptor>(result));
+        }
+      }
+      return result;
+    }
+
+    // Used in tests only.
+    int getUnknownEnumValueDescriptorCount() {
+      return unknownValues.size();
+    }
+
+    private final int index;
+    private EnumDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+    private final Descriptor containingType;
+    private EnumValueDescriptor[] values;
+    private final WeakHashMap<Integer, WeakReference<EnumValueDescriptor>> unknownValues =
+        new WeakHashMap<Integer, WeakReference<EnumValueDescriptor>>();
+
+    private EnumDescriptor(final EnumDescriptorProto proto,
+                           final FileDescriptor file,
+                           final Descriptor parent,
+                           final int index)
+                    throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      fullName = computeFullName(file, parent, proto.getName());
+      this.file = file;
+      containingType = parent;
+
+      if (proto.getValueCount() == 0) {
+        // We cannot allow enums with no values because this would mean there
+        // would be no valid default value for fields of this type.
+        throw new DescriptorValidationException(this,
+          "Enums must contain at least one value.");
+      }
+
+      values = new EnumValueDescriptor[proto.getValueCount()];
+      for (int i = 0; i < proto.getValueCount(); i++) {
+        values[i] = new EnumValueDescriptor(
+          proto.getValue(i), file, this, i);
+      }
+
+      file.pool.addSymbol(this);
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final EnumDescriptorProto proto) {
+      this.proto = proto;
+
+      for (int i = 0; i < values.length; i++) {
+        values[i].setProto(proto.getValue(i));
+      }
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Describes one value within an enum type.  Note that multiple defined
+   * values may have the same number.  In generated Java code, all values
+   * with the same number after the first become aliases of the first.
+   * However, they still have independent EnumValueDescriptors.
+   */
+  public static final class EnumValueDescriptor extends GenericDescriptor
+      implements Internal.EnumLite {
+    /**
+     * Get the index of this descriptor within its parent.
+     * @see Descriptors.Descriptor#getIndex()
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public EnumValueDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the value's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /** Get the value's number. */
+    @Override
+    public int getNumber() {
+      return proto.getNumber();
+    }
+
+    @Override
+    public String toString() { return proto.getName(); }
+
+    /**
+     * Get the value's fully-qualified name.
+     * @see Descriptors.Descriptor#getFullName()
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the {@link FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** Get the value's enum type. */
+    public EnumDescriptor getType() { return type; }
+
+    /**
+     * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
+     */
+    public EnumValueOptions getOptions() { return proto.getOptions(); }
+
+    private final int index;
+    private EnumValueDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+    private final EnumDescriptor type;
+
+    private EnumValueDescriptor(final EnumValueDescriptorProto proto,
+                                final FileDescriptor file,
+                                final EnumDescriptor parent,
+                                final int index)
+                         throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      this.file = file;
+      type = parent;
+
+      fullName = parent.getFullName() + '.' + proto.getName();
+
+      file.pool.addSymbol(this);
+      file.pool.addEnumValueByNumber(this);
+    }
+
+    private Integer number;
+    // Create an unknown enum value.
+    private EnumValueDescriptor(
+        final FileDescriptor file,
+        final EnumDescriptor parent,
+        final Integer number) {
+      String name = "UNKNOWN_ENUM_VALUE_" + parent.getName() + "_" + number;
+      EnumValueDescriptorProto proto = EnumValueDescriptorProto
+          .newBuilder().setName(name).setNumber(number).build();
+      this.index = -1;
+      this.proto = proto;
+      this.file = file;
+      this.type = parent;
+      this.fullName = parent.getFullName() + '.' + proto.getName();
+      this.number = number;
+
+      // Don't add this descriptor into pool.
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final EnumValueDescriptorProto proto) {
+      this.proto = proto;
+    }
+  }
+
+  // =================================================================
+
+  /** Describes a service type. */
+  public static final class ServiceDescriptor extends GenericDescriptor {
+    /**
+     * Get the index of this descriptor within its parent.
+     * * @see Descriptors.Descriptor#getIndex()
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public ServiceDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the type's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /**
+     * Get the type's fully-qualified name.
+     * @see Descriptors.Descriptor#getFullName()
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the {@link FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
+    public ServiceOptions getOptions() { return proto.getOptions(); }
+
+    /** Get a list of methods for this service. */
+    public List<MethodDescriptor> getMethods() {
+      return Collections.unmodifiableList(Arrays.asList(methods));
+    }
+
+    /**
+     * Find a method by name.
+     * @param name The unqualified name of the method (e.g. "Foo").
+     * @return the method's descriptor, or {@code null} if not found.
+     */
+    public MethodDescriptor findMethodByName(final String name) {
+      final GenericDescriptor result =
+          file.pool.findSymbol(fullName + '.' + name);
+      if (result != null && result instanceof MethodDescriptor) {
+        return (MethodDescriptor)result;
+      } else {
+        return null;
+      }
+    }
+
+    private final int index;
+    private ServiceDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+    private MethodDescriptor[] methods;
+
+    private ServiceDescriptor(final ServiceDescriptorProto proto,
+                              final FileDescriptor file,
+                              final int index)
+                       throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      fullName = computeFullName(file, null, proto.getName());
+      this.file = file;
+
+      methods = new MethodDescriptor[proto.getMethodCount()];
+      for (int i = 0; i < proto.getMethodCount(); i++) {
+        methods[i] = new MethodDescriptor(
+          proto.getMethod(i), file, this, i);
+      }
+
+      file.pool.addSymbol(this);
+    }
+
+    private void crossLink() throws DescriptorValidationException {
+      for (final MethodDescriptor method : methods) {
+        method.crossLink();
+      }
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final ServiceDescriptorProto proto) {
+      this.proto = proto;
+
+      for (int i = 0; i < methods.length; i++) {
+        methods[i].setProto(proto.getMethod(i));
+      }
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Describes one method within a service type.
+   */
+  public static final class MethodDescriptor extends GenericDescriptor {
+    /**
+     * Get the index of this descriptor within its parent.
+     * * @see Descriptors.Descriptor#getIndex()
+     */
+    public int getIndex() { return index; }
+
+    /** Convert the descriptor to its protocol message representation. */
+    @Override
+    public MethodDescriptorProto toProto() {
+      return proto;
+    }
+
+    /** Get the method's unqualified name. */
+    @Override
+    public String getName() {
+      return proto.getName();
+    }
+
+    /**
+     * Get the method's fully-qualified name.
+     * @see Descriptors.Descriptor#getFullName()
+     */
+    @Override
+    public String getFullName() {
+      return fullName;
+    }
+
+    /** Get the {@link FileDescriptor} containing this descriptor. */
+    @Override
+    public FileDescriptor getFile() {
+      return file;
+    }
+
+    /** Get the method's service type. */
+    public ServiceDescriptor getService() { return service; }
+
+    /** Get the method's input type. */
+    public Descriptor getInputType() { return inputType; }
+
+    /** Get the method's output type. */
+    public Descriptor getOutputType() { return outputType; }
+
+    /**
+     * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
+     */
+    public MethodOptions getOptions() { return proto.getOptions(); }
+
+    private final int index;
+    private MethodDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+    private final ServiceDescriptor service;
+
+    // Initialized during cross-linking.
+    private Descriptor inputType;
+    private Descriptor outputType;
+
+    private MethodDescriptor(final MethodDescriptorProto proto,
+                             final FileDescriptor file,
+                             final ServiceDescriptor parent,
+                             final int index)
+                      throws DescriptorValidationException {
+      this.index = index;
+      this.proto = proto;
+      this.file = file;
+      service = parent;
+
+      fullName = parent.getFullName() + '.' + proto.getName();
+
+      file.pool.addSymbol(this);
+    }
+
+    private void crossLink() throws DescriptorValidationException {
+      final GenericDescriptor input =
+        file.pool.lookupSymbol(proto.getInputType(), this,
+            DescriptorPool.SearchFilter.TYPES_ONLY);
+      if (!(input instanceof Descriptor)) {
+        throw new DescriptorValidationException(this,
+            '\"' + proto.getInputType() + "\" is not a message type.");
+      }
+      inputType = (Descriptor)input;
+
+      final GenericDescriptor output =
+        file.pool.lookupSymbol(proto.getOutputType(), this,
+            DescriptorPool.SearchFilter.TYPES_ONLY);
+      if (!(output instanceof Descriptor)) {
+        throw new DescriptorValidationException(this,
+            '\"' + proto.getOutputType() + "\" is not a message type.");
+      }
+      outputType = (Descriptor)output;
+    }
+
+    /** See {@link FileDescriptor#setProto}. */
+    private void setProto(final MethodDescriptorProto proto) {
+      this.proto = proto;
+    }
+  }
+
+  // =================================================================
+
+  private static String computeFullName(final FileDescriptor file,
+                                        final Descriptor parent,
+                                        final String name) {
+    if (parent != null) {
+      return parent.getFullName() + '.' + name;
+    } else if (file.getPackage().length() > 0) {
+      return file.getPackage() + '.' + name;
+    } else {
+      return name;
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * All descriptors implement this to make it easier to implement tools like
+   * {@code DescriptorPool}.<p>
+   *
+   * This class is public so that the methods it exposes can be called from
+   * outside of this package. However, it should only be subclassed from
+   * nested classes of Descriptors.
+   */
+  public abstract static class GenericDescriptor {
+    public abstract Message toProto();
+    public abstract String getName();
+    public abstract String getFullName();
+    public abstract FileDescriptor getFile();
+  }
+
+  /**
+   * Thrown when building descriptors fails because the source DescriptorProtos
+   * are not valid.
+   */
+  public static class DescriptorValidationException extends Exception {
+    private static final long serialVersionUID = 5750205775490483148L;
+
+    /** Gets the full name of the descriptor where the error occurred. */
+    public String getProblemSymbolName() { return name; }
+
+    /**
+     * Gets the protocol message representation of the invalid descriptor.
+     */
+    public Message getProblemProto() { return proto; }
+
+    /**
+     * Gets a human-readable description of the error.
+     */
+    public String getDescription() { return description; }
+
+    private final String name;
+    private final Message proto;
+    private final String description;
+
+    private DescriptorValidationException(
+        final GenericDescriptor problemDescriptor,
+        final String description) {
+      super(problemDescriptor.getFullName() + ": " + description);
+
+      // Note that problemDescriptor may be partially uninitialized, so we
+      // don't want to expose it directly to the user.  So, we only provide
+      // the name and the original proto.
+      name = problemDescriptor.getFullName();
+      proto = problemDescriptor.toProto();
+      this.description = description;
+    }
+
+    private DescriptorValidationException(
+        final GenericDescriptor problemDescriptor,
+        final String description,
+        final Throwable cause) {
+      this(problemDescriptor, description);
+      initCause(cause);
+    }
+
+    private DescriptorValidationException(
+        final FileDescriptor problemDescriptor,
+        final String description) {
+      super(problemDescriptor.getName() + ": " + description);
+
+      // Note that problemDescriptor may be partially uninitialized, so we
+      // don't want to expose it directly to the user.  So, we only provide
+      // the name and the original proto.
+      name = problemDescriptor.getName();
+      proto = problemDescriptor.toProto();
+      this.description = description;
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * A private helper class which contains lookup tables containing all the
+   * descriptors defined in a particular file.
+   */
+  private static final class DescriptorPool {
+
+    /** Defines what subclass of descriptors to search in the descriptor pool.
+     */
+    enum SearchFilter {
+      TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
+    }
+
+    DescriptorPool(final FileDescriptor[] dependencies,
+        boolean allowUnknownDependencies) {
+      this.dependencies = new HashSet<FileDescriptor>();
+      this.allowUnknownDependencies = allowUnknownDependencies;
+
+      for (int i = 0; i < dependencies.length; i++) {
+        this.dependencies.add(dependencies[i]);
+        importPublicDependencies(dependencies[i]);
+      }
+
+      for (final FileDescriptor dependency : this.dependencies) {
+        try {
+          addPackage(dependency.getPackage(), dependency);
+        } catch (DescriptorValidationException e) {
+          // Can't happen, because addPackage() only fails when the name
+          // conflicts with a non-package, but we have not yet added any
+          // non-packages at this point.
+          assert false;
+        }
+      }
+    }
+
+    /** Find and put public dependencies of the file into dependencies set.*/
+    private void importPublicDependencies(final FileDescriptor file) {
+      for (FileDescriptor dependency : file.getPublicDependencies()) {
+        if (dependencies.add(dependency)) {
+          importPublicDependencies(dependency);
+        }
+      }
+    }
+
+    private final Set<FileDescriptor> dependencies;
+    private boolean allowUnknownDependencies;
+
+    private final Map<String, GenericDescriptor> descriptorsByName =
+      new HashMap<String, GenericDescriptor>();
+    private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
+      new HashMap<DescriptorIntPair, FieldDescriptor>();
+    private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
+        = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
+
+    /** Find a generic descriptor by fully-qualified name. */
+    GenericDescriptor findSymbol(final String fullName) {
+      return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
+    }
+
+    /** Find a descriptor by fully-qualified name and given option to only
+     * search valid field type descriptors.
+     */
+    GenericDescriptor findSymbol(final String fullName,
+                                 final SearchFilter filter) {
+      GenericDescriptor result = descriptorsByName.get(fullName);
+      if (result != null) {
+        if ((filter==SearchFilter.ALL_SYMBOLS) ||
+            ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
+            ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
+          return result;
+        }
+      }
+
+      for (final FileDescriptor dependency : dependencies) {
+        result = dependency.pool.descriptorsByName.get(fullName);
+        if (result != null) {
+          if ((filter==SearchFilter.ALL_SYMBOLS) ||
+              ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
+              ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
+            return result;
+          }
+        }
+      }
+
+      return null;
+    }
+
+    /** Checks if the descriptor is a valid type for a message field. */
+    boolean isType(GenericDescriptor descriptor) {
+      return (descriptor instanceof Descriptor) ||
+        (descriptor instanceof EnumDescriptor);
+    }
+
+    /** Checks if the descriptor is a valid namespace type. */
+    boolean isAggregate(GenericDescriptor descriptor) {
+      return (descriptor instanceof Descriptor) ||
+        (descriptor instanceof EnumDescriptor) ||
+        (descriptor instanceof PackageDescriptor) ||
+        (descriptor instanceof ServiceDescriptor);
+    }
+
+    /**
+     * Look up a type descriptor by name, relative to some other descriptor.
+     * The name may be fully-qualified (with a leading '.'),
+     * partially-qualified, or unqualified.  C++-like name lookup semantics
+     * are used to search for the matching descriptor.
+     */
+    GenericDescriptor lookupSymbol(final String name,
+                                   final GenericDescriptor relativeTo,
+                                   final DescriptorPool.SearchFilter filter)
+                            throws DescriptorValidationException {
+      // TODO(kenton):  This could be optimized in a number of ways.
+
+      GenericDescriptor result;
+      String fullname;
+      if (name.startsWith(".")) {
+        // Fully-qualified name.
+        fullname = name.substring(1);
+        result = findSymbol(fullname, filter);
+      } else {
+        // If "name" is a compound identifier, we want to search for the
+        // first component of it, then search within it for the rest.
+        // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
+        // defined in multiple parent scopes, we only want to find "Bar.baz" in
+        // the innermost one.  E.g., the following should produce an error:
+        //   message Bar { message Baz {} }
+        //   message Foo {
+        //     message Bar {
+        //     }
+        //     optional Bar.Baz baz = 1;
+        //   }
+        // So, we look for just "Foo" first, then look for "Bar.baz" within it
+        // if found.
+        final int firstPartLength = name.indexOf('.');
+        final String firstPart;
+        if (firstPartLength == -1) {
+          firstPart = name;
+        } else {
+          firstPart = name.substring(0, firstPartLength);
+        }
+
+        // We will search each parent scope of "relativeTo" looking for the
+        // symbol.
+        final StringBuilder scopeToTry =
+            new StringBuilder(relativeTo.getFullName());
+
+        while (true) {
+          // Chop off the last component of the scope.
+          final int dotpos = scopeToTry.lastIndexOf(".");
+          if (dotpos == -1) {
+            fullname = name;
+            result = findSymbol(name, filter);
+            break;
+          } else {
+            scopeToTry.setLength(dotpos + 1);
+
+            // Append firstPart and try to find
+            scopeToTry.append(firstPart);
+            result = findSymbol(scopeToTry.toString(),
+                DescriptorPool.SearchFilter.AGGREGATES_ONLY);
+
+            if (result != null) {
+              if (firstPartLength != -1) {
+                // We only found the first part of the symbol.  Now look for
+                // the whole thing.  If this fails, we *don't* want to keep
+                // searching parent scopes.
+                scopeToTry.setLength(dotpos + 1);
+                scopeToTry.append(name);
+                result = findSymbol(scopeToTry.toString(), filter);
+              }
+              fullname = scopeToTry.toString();
+              break;
+            }
+
+            // Not found.  Remove the name so we can try again.
+            scopeToTry.setLength(dotpos);
+          }
+        }
+      }
+
+      if (result == null) {
+        if (allowUnknownDependencies && filter == SearchFilter.TYPES_ONLY) {
+          logger.warning("The descriptor for message type \"" + name +
+              "\" can not be found and a placeholder is created for it");
+          // We create a dummy message descriptor here regardless of the
+          // expected type. If the type should be message, this dummy
+          // descriptor will work well and if the type should be enum, a
+          // DescriptorValidationException will be thrown latter. In either
+          // case, the code works as expected: we allow unknown message types
+          // but not unknwon enum types.
+          result = new Descriptor(fullname);
+          // Add the placeholder file as a dependency so we can find the
+          // placeholder symbol when resolving other references.
+          this.dependencies.add(result.getFile());
+          return result;
+        } else {
+          throw new DescriptorValidationException(relativeTo,
+              '\"' + name + "\" is not defined.");
+        }
+      } else {
+        return result;
+      }
+    }
+
+    /**
+     * Adds a symbol to the symbol table.  If a symbol with the same name
+     * already exists, throws an error.
+     */
+    void addSymbol(final GenericDescriptor descriptor)
+            throws DescriptorValidationException {
+      validateSymbolName(descriptor);
+
+      final String fullName = descriptor.getFullName();
+      final int dotpos = fullName.lastIndexOf('.');
+
+      final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
+      if (old != null) {
+        descriptorsByName.put(fullName, old);
+
+        if (descriptor.getFile() == old.getFile()) {
+          if (dotpos == -1) {
+            throw new DescriptorValidationException(descriptor,
+                '\"' + fullName + "\" is already defined.");
+          } else {
+            throw new DescriptorValidationException(descriptor,
+                '\"' + fullName.substring(dotpos + 1) +
+              "\" is already defined in \"" +
+              fullName.substring(0, dotpos) + "\".");
+          }
+        } else {
+          throw new DescriptorValidationException(descriptor,
+              '\"' + fullName + "\" is already defined in file \"" +
+            old.getFile().getName() + "\".");
+        }
+      }
+    }
+
+    /**
+     * Represents a package in the symbol table.  We use PackageDescriptors
+     * just as placeholders so that someone cannot define, say, a message type
+     * that has the same name as an existing package.
+     */
+    private static final class PackageDescriptor extends GenericDescriptor {
+      @Override
+      public Message toProto() {
+        return file.toProto();
+      }
+      @Override
+      public String getName() {
+        return name;
+      }
+      @Override
+      public String getFullName() {
+        return fullName;
+      }
+      @Override
+      public FileDescriptor getFile() {
+        return file;
+      }
+
+      PackageDescriptor(final String name, final String fullName,
+                        final FileDescriptor file) {
+        this.file = file;
+        this.fullName = fullName;
+        this.name = name;
+      }
+
+      private final String name;
+      private final String fullName;
+      private final FileDescriptor file;
+    }
+
+    /**
+     * Adds a package to the symbol tables.  If a package by the same name
+     * already exists, that is fine, but if some other kind of symbol exists
+     * under the same name, an exception is thrown.  If the package has
+     * multiple components, this also adds the parent package(s).
+     */
+    void addPackage(final String fullName, final FileDescriptor file)
+             throws DescriptorValidationException {
+      final int dotpos = fullName.lastIndexOf('.');
+      final String name;
+      if (dotpos == -1) {
+        name = fullName;
+      } else {
+        addPackage(fullName.substring(0, dotpos), file);
+        name = fullName.substring(dotpos + 1);
+      }
+
+      final GenericDescriptor old =
+        descriptorsByName.put(fullName,
+          new PackageDescriptor(name, fullName, file));
+      if (old != null) {
+        descriptorsByName.put(fullName, old);
+        if (!(old instanceof PackageDescriptor)) {
+          throw new DescriptorValidationException(file,
+              '\"' + name + "\" is already defined (as something other than a "
+              + "package) in file \"" + old.getFile().getName() + "\".");
+        }
+      }
+    }
+
+    /** A (GenericDescriptor, int) pair, used as a map key. */
+    private static final class DescriptorIntPair {
+      private final GenericDescriptor descriptor;
+      private final int number;
+
+      DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
+        this.descriptor = descriptor;
+        this.number = number;
+      }
+
+      @Override
+      public int hashCode() {
+        return descriptor.hashCode() * ((1 << 16) - 1) + number;
+      }
+      @Override
+      public boolean equals(final Object obj) {
+        if (!(obj instanceof DescriptorIntPair)) {
+          return false;
+        }
+        final DescriptorIntPair other = (DescriptorIntPair)obj;
+        return descriptor == other.descriptor && number == other.number;
+      }
+    }
+
+    /**
+     * Adds a field to the fieldsByNumber table.  Throws an exception if a
+     * field with the same containing type and number already exists.
+     */
+    void addFieldByNumber(final FieldDescriptor field)
+                   throws DescriptorValidationException {
+      final DescriptorIntPair key =
+        new DescriptorIntPair(field.getContainingType(), field.getNumber());
+      final FieldDescriptor old = fieldsByNumber.put(key, field);
+      if (old != null) {
+        fieldsByNumber.put(key, old);
+        throw new DescriptorValidationException(field,
+          "Field number " + field.getNumber() +
+          " has already been used in \"" +
+          field.getContainingType().getFullName() +
+          "\" by field \"" + old.getName() + "\".");
+      }
+    }
+
+    /**
+     * Adds an enum value to the enumValuesByNumber table.  If an enum value
+     * with the same type and number already exists, does nothing.  (This is
+     * allowed; the first value define with the number takes precedence.)
+     */
+    void addEnumValueByNumber(final EnumValueDescriptor value) {
+      final DescriptorIntPair key =
+        new DescriptorIntPair(value.getType(), value.getNumber());
+      final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
+      if (old != null) {
+        enumValuesByNumber.put(key, old);
+        // Not an error:  Multiple enum values may have the same number, but
+        // we only want the first one in the map.
+      }
+    }
+
+    /**
+     * Verifies that the descriptor's name is valid (i.e. it contains only
+     * letters, digits, and underscores, and does not start with a digit).
+     */
+    static void validateSymbolName(final GenericDescriptor descriptor)
+                                   throws DescriptorValidationException {
+      final String name = descriptor.getName();
+      if (name.length() == 0) {
+        throw new DescriptorValidationException(descriptor, "Missing name.");
+      } else {
+        boolean valid = true;
+        for (int i = 0; i < name.length(); i++) {
+          final char c = name.charAt(i);
+          // Non-ASCII characters are not valid in protobuf identifiers, even
+          // if they are letters or digits.
+          if (c >= 128) {
+            valid = false;
+          }
+          // First character must be letter or _.  Subsequent characters may
+          // be letters, numbers, or digits.
+          if (Character.isLetter(c) || c == '_' ||
+              (Character.isDigit(c) && i > 0)) {
+            // Valid
+          } else {
+            valid = false;
+          }
+        }
+        if (!valid) {
+          throw new DescriptorValidationException(descriptor,
+              '\"' + name + "\" is not a valid identifier.");
+        }
+      }
+    }
+  }
+
+  /** Describes an oneof of a message type. */
+  public static final class OneofDescriptor {
+    /** Get the index of this descriptor within its parent. */
+    public int getIndex() { return index; }
+
+    public String getName() { return proto.getName(); }
+
+    public FileDescriptor getFile() { return file; }
+
+    public String getFullName() { return fullName; }
+
+    public Descriptor getContainingType() { return containingType; }
+
+    public int getFieldCount() { return fieldCount; }
+
+    /** Get a list of this message type's fields. */
+    public List<FieldDescriptor> getFields() {
+      return Collections.unmodifiableList(Arrays.asList(fields));
+    }
+
+    public FieldDescriptor getField(int index) {
+      return fields[index];
+    }
+
+    private OneofDescriptor(final OneofDescriptorProto proto,
+                            final FileDescriptor file,
+                            final Descriptor parent,
+                            final int index)
+                     throws DescriptorValidationException {
+      this.proto = proto;
+      fullName = computeFullName(file, parent, proto.getName());
+      this.file = file;
+      this.index = index;
+
+      containingType = parent;
+      fieldCount = 0;
+    }
+
+    private final int index;
+    private OneofDescriptorProto proto;
+    private final String fullName;
+    private final FileDescriptor file;
+
+    private Descriptor containingType;
+    private int fieldCount;
+    private FieldDescriptor[] fields;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
new file mode 100644
index 0000000..a9543b8
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -0,0 +1,271 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.DoubleList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link DoubleList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class DoubleArrayList
+    extends AbstractProtobufList<Double> implements DoubleList, RandomAccess {
+  
+  private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static DoubleArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private double[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} with default capacity.
+   */
+  DoubleArrayList() {
+    this(new double[DEFAULT_CAPACITY], 0);
+  }
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
+   */
+  private DoubleArrayList(double[] array, int size) {
+    this.array = array;
+    this.size = size;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof DoubleArrayList)) {
+      return super.equals(o);
+    }
+    DoubleArrayList other = (DoubleArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+    
+    final double[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
+      }
+    }
+    
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      long bits = Double.doubleToLongBits(array[i]);
+      result = (31 * result) + Internal.hashLong(bits);
+    }
+    return result;
+  }
+
+  @Override
+  public DoubleList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
+  }
+  
+  @Override
+  public Double get(int index) {
+    return getDouble(index);
+  }
+
+  @Override
+  public double getDouble(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Double set(int index, Double element) {
+    return setDouble(index, element);
+  }
+
+  @Override
+  public double setDouble(int index, double element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    double previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Double element) {
+    addDouble(index, element);
+  }
+
+  /**
+   * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addDouble(double element) {
+    addDouble(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Double)} but more efficient in that it doesn't box the element.
+   */
+  private void addDouble(int index, double element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      double[] newArray = new double[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Double> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another DoubleArrayList to avoid boxing elements.
+    if (!(collection instanceof DoubleArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    DoubleArrayList list = (DoubleArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Double remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    double value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
new file mode 100644
index 0000000..859a9e8
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -0,0 +1,676 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of {@link Message} that can represent arbitrary types,
+ * given a {@link Descriptors.Descriptor}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class DynamicMessage extends AbstractMessage {
+  private final Descriptor type;
+  private final FieldSet<FieldDescriptor> fields;
+  private final FieldDescriptor[] oneofCases;
+  private final UnknownFieldSet unknownFields;
+  private int memoizedSize = -1;
+
+  /**
+   * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
+   * oneofCases stores the FieldDescriptor for each oneof to indicate
+   * which field is set. Caller should make sure the array is immutable.
+   *
+   * This constructor is package private and will be used in
+   * {@code DynamicMutableMessage} to convert a mutable message to an immutable
+   * message.
+   */
+  DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
+                 FieldDescriptor[] oneofCases,
+                 UnknownFieldSet unknownFields) {
+    this.type = type;
+    this.fields = fields;
+    this.oneofCases = oneofCases;
+    this.unknownFields = unknownFields;
+  }
+
+  /**
+   * Get a {@code DynamicMessage} representing the default instance of the
+   * given type.
+   */
+  public static DynamicMessage getDefaultInstance(Descriptor type) {
+    int oneofDeclCount = type.toProto().getOneofDeclCount();
+    FieldDescriptor[] oneofCases = new FieldDescriptor[oneofDeclCount];
+    return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
+                              oneofCases,
+                              UnknownFieldSet.getDefaultInstance());
+  }
+
+
+  /** Parse a message of the given type from the given input stream. */
+  public static DynamicMessage parseFrom(Descriptor type,
+                                         CodedInputStream input)
+                                         throws IOException {
+    return newBuilder(type).mergeFrom(input).buildParsed();
+  }
+
+  /** Parse a message of the given type from the given input stream. */
+  public static DynamicMessage parseFrom(
+      Descriptor type,
+      CodedInputStream input,
+      ExtensionRegistry extensionRegistry)
+      throws IOException {
+    return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+  }
+
+  /** Parse {@code data} as a message of the given type and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, ByteString data)
+                                         throws InvalidProtocolBufferException {
+    return newBuilder(type).mergeFrom(data).buildParsed();
+  }
+
+  /** Parse {@code data} as a message of the given type and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, ByteString data,
+                                         ExtensionRegistry extensionRegistry)
+                                         throws InvalidProtocolBufferException {
+    return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+  }
+
+  /** Parse {@code data} as a message of the given type and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, byte[] data)
+                                         throws InvalidProtocolBufferException {
+    return newBuilder(type).mergeFrom(data).buildParsed();
+  }
+
+  /** Parse {@code data} as a message of the given type and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, byte[] data,
+                                         ExtensionRegistry extensionRegistry)
+                                         throws InvalidProtocolBufferException {
+    return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+  }
+
+  /** Parse a message of the given type from {@code input} and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, InputStream input)
+                                         throws IOException {
+    return newBuilder(type).mergeFrom(input).buildParsed();
+  }
+
+  /** Parse a message of the given type from {@code input} and return it. */
+  public static DynamicMessage parseFrom(Descriptor type, InputStream input,
+                                         ExtensionRegistry extensionRegistry)
+                                         throws IOException {
+    return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+  }
+
+  /** Construct a {@link Message.Builder} for the given type. */
+  public static Builder newBuilder(Descriptor type) {
+    return new Builder(type);
+  }
+
+  /**
+   * Construct a {@link Message.Builder} for a message of the same type as
+   * {@code prototype}, and initialize it with {@code prototype}'s contents.
+   */
+  public static Builder newBuilder(Message prototype) {
+    return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
+  }
+
+  // -----------------------------------------------------------------
+  // Implementation of Message interface.
+
+  @Override
+  public Descriptor getDescriptorForType() {
+    return type;
+  }
+
+  @Override
+  public DynamicMessage getDefaultInstanceForType() {
+    return getDefaultInstance(type);
+  }
+
+  @Override
+  public Map<FieldDescriptor, Object> getAllFields() {
+    return fields.getAllFields();
+  }
+
+  @Override
+  public boolean hasOneof(OneofDescriptor oneof) {
+    verifyOneofContainingType(oneof);
+    FieldDescriptor field = oneofCases[oneof.getIndex()];
+    if (field == null) {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+    verifyOneofContainingType(oneof);
+    return oneofCases[oneof.getIndex()];
+  }
+
+  @Override
+  public boolean hasField(FieldDescriptor field) {
+    verifyContainingType(field);
+    return fields.hasField(field);
+  }
+
+  @Override
+  public Object getField(FieldDescriptor field) {
+    verifyContainingType(field);
+    Object result = fields.getField(field);
+    if (result == null) {
+      if (field.isRepeated()) {
+        result = Collections.emptyList();
+      } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        result = getDefaultInstance(field.getMessageType());
+      } else {
+        result = field.getDefaultValue();
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public int getRepeatedFieldCount(FieldDescriptor field) {
+    verifyContainingType(field);
+    return fields.getRepeatedFieldCount(field);
+  }
+
+  @Override
+  public Object getRepeatedField(FieldDescriptor field, int index) {
+    verifyContainingType(field);
+    return fields.getRepeatedField(field, index);
+  }
+
+  @Override
+  public UnknownFieldSet getUnknownFields() {
+    return unknownFields;
+  }
+
+  static boolean isInitialized(Descriptor type,
+                               FieldSet<FieldDescriptor> fields) {
+    // Check that all required fields are present.
+    for (final FieldDescriptor field : type.getFields()) {
+      if (field.isRequired()) {
+        if (!fields.hasField(field)) {
+          return false;
+        }
+      }
+    }
+
+    // Check that embedded messages are initialized.
+    return fields.isInitialized();
+  }
+
+  @Override
+  public boolean isInitialized() {
+    return isInitialized(type, fields);
+  }
+
+  @Override
+  public void writeTo(CodedOutputStream output) throws IOException {
+    if (type.getOptions().getMessageSetWireFormat()) {
+      fields.writeMessageSetTo(output);
+      unknownFields.writeAsMessageSetTo(output);
+    } else {
+      fields.writeTo(output);
+      unknownFields.writeTo(output);
+    }
+  }
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    if (type.getOptions().getMessageSetWireFormat()) {
+      size = fields.getMessageSetSerializedSize();
+      size += unknownFields.getSerializedSizeAsMessageSet();
+    } else {
+      size = fields.getSerializedSize();
+      size += unknownFields.getSerializedSize();
+    }
+
+    memoizedSize = size;
+    return size;
+  }
+
+  @Override
+  public Builder newBuilderForType() {
+    return new Builder(type);
+  }
+
+  @Override
+  public Builder toBuilder() {
+    return newBuilderForType().mergeFrom(this);
+  }
+
+  @Override
+  public Parser<DynamicMessage> getParserForType() {
+    return new AbstractParser<DynamicMessage>() {
+      @Override
+      public DynamicMessage parsePartialFrom(
+          CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+        Builder builder = newBuilder(type);
+        try {
+          builder.mergeFrom(input, extensionRegistry);
+        } catch (InvalidProtocolBufferException e) {
+          throw e.setUnfinishedMessage(builder.buildPartial());
+        } catch (IOException e) {
+          throw new InvalidProtocolBufferException(e.getMessage())
+              .setUnfinishedMessage(builder.buildPartial());
+        }
+        return builder.buildPartial();
+      }
+    };
+  }
+
+  /** Verifies that the field is a field of this message. */
+  private void verifyContainingType(FieldDescriptor field) {
+    if (field.getContainingType() != type) {
+      throw new IllegalArgumentException(
+        "FieldDescriptor does not match message type.");
+    }
+  }
+
+  /** Verifies that the oneof is an oneof of this message. */
+  private void verifyOneofContainingType(OneofDescriptor oneof) {
+    if (oneof.getContainingType() != type) {
+      throw new IllegalArgumentException(
+        "OneofDescriptor does not match message type.");
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Builder for {@link DynamicMessage}s.
+   */
+  public static final class Builder extends AbstractMessage.Builder<Builder> {
+    private final Descriptor type;
+    private FieldSet<FieldDescriptor> fields;
+    private final FieldDescriptor[] oneofCases;
+    private UnknownFieldSet unknownFields;
+
+    /** Construct a {@code Builder} for the given type. */
+    private Builder(Descriptor type) {
+      this.type = type;
+      this.fields = FieldSet.newFieldSet();
+      this.unknownFields = UnknownFieldSet.getDefaultInstance();
+      this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
+    }
+
+    // ---------------------------------------------------------------
+    // Implementation of Message.Builder interface.
+
+    @Override
+    public Builder clear() {
+      if (fields.isImmutable()) {
+        fields = FieldSet.newFieldSet();
+      } else {
+        fields.clear();
+      }
+      unknownFields = UnknownFieldSet.getDefaultInstance();
+      return this;
+    }
+
+    @Override
+    public Builder mergeFrom(Message other) {
+      if (other instanceof DynamicMessage) {
+        // This should be somewhat faster than calling super.mergeFrom().
+        DynamicMessage otherDynamicMessage = (DynamicMessage) other;
+        if (otherDynamicMessage.type != type) {
+          throw new IllegalArgumentException(
+            "mergeFrom(Message) can only merge messages of the same type.");
+        }
+        ensureIsMutable();
+        fields.mergeFrom(otherDynamicMessage.fields);
+        mergeUnknownFields(otherDynamicMessage.unknownFields);
+        for (int i = 0; i < oneofCases.length; i++) {
+          if (oneofCases[i] == null) {
+            oneofCases[i] = otherDynamicMessage.oneofCases[i];
+          } else {
+            if ((otherDynamicMessage.oneofCases[i] != null)
+                && (oneofCases[i] != otherDynamicMessage.oneofCases[i])) {
+              fields.clearField(oneofCases[i]);
+              oneofCases[i] = otherDynamicMessage.oneofCases[i];
+            }
+          }
+        }
+        return this;
+      } else {
+        return super.mergeFrom(other);
+      }
+    }
+
+    @Override
+    public DynamicMessage build() {
+      if (!isInitialized()) {
+        throw newUninitializedMessageException(
+          new DynamicMessage(type, fields,
+              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
+      }
+      return buildPartial();
+    }
+
+    /**
+     * Helper for DynamicMessage.parseFrom() methods to call.  Throws
+     * {@link InvalidProtocolBufferException} instead of
+     * {@link UninitializedMessageException}.
+     */
+    private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
+      if (!isInitialized()) {
+        throw newUninitializedMessageException(
+          new DynamicMessage(type, fields,
+              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields))
+          .asInvalidProtocolBufferException();
+      }
+      return buildPartial();
+    }
+
+    @Override
+    public DynamicMessage buildPartial() {
+      fields.makeImmutable();
+      DynamicMessage result =
+        new DynamicMessage(type, fields,
+            java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
+      return result;
+    }
+
+    @Override
+    public Builder clone() {
+      Builder result = new Builder(type);
+      result.fields.mergeFrom(fields);
+      result.mergeUnknownFields(unknownFields);
+      System.arraycopy(oneofCases, 0, result.oneofCases, 0 , oneofCases.length);
+      return result;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return DynamicMessage.isInitialized(type, fields);
+    }
+
+    @Override
+    public Descriptor getDescriptorForType() {
+      return type;
+    }
+
+    @Override
+    public DynamicMessage getDefaultInstanceForType() {
+      return getDefaultInstance(type);
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      return fields.getAllFields();
+    }
+
+    @Override
+    public Builder newBuilderForField(FieldDescriptor field) {
+      verifyContainingType(field);
+
+      if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+        throw new IllegalArgumentException(
+          "newBuilderForField is only valid for fields with message type.");
+      }
+
+      return new Builder(field.getMessageType());
+    }
+
+    @Override
+    public boolean hasOneof(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      FieldDescriptor field = oneofCases[oneof.getIndex()];
+      if (field == null) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      return oneofCases[oneof.getIndex()];
+    }
+
+    @Override
+    public Builder clearOneof(OneofDescriptor oneof) {
+      verifyOneofContainingType(oneof);
+      FieldDescriptor field = oneofCases[oneof.getIndex()];
+      if (field != null) {
+        clearField(field);
+      }
+      return this;
+    }
+
+    @Override
+    public boolean hasField(FieldDescriptor field) {
+      verifyContainingType(field);
+      return fields.hasField(field);
+    }
+
+    @Override
+    public Object getField(FieldDescriptor field) {
+      verifyContainingType(field);
+      Object result = fields.getField(field);
+      if (result == null) {
+        if (field.isRepeated()) {
+          result = Collections.emptyList();
+        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          result = getDefaultInstance(field.getMessageType());
+        } else {
+          result = field.getDefaultValue();
+        }
+      }
+      return result;
+    }
+
+    @Override
+    public Builder setField(FieldDescriptor field, Object value) {
+      verifyContainingType(field);
+      ensureIsMutable();
+      // TODO(xiaofeng): This check should really be put in FieldSet.setField()
+      // where all other such checks are done. However, currently
+      // FieldSet.setField() permits Integer value for enum fields probably
+      // because of some internal features we support. Should figure it out
+      // and move this check to a more appropriate place.
+      if (field.getType() == FieldDescriptor.Type.ENUM) {
+        ensureEnumValueDescriptor(field, value);
+      }
+      OneofDescriptor oneofDescriptor = field.getContainingOneof();
+      if (oneofDescriptor != null) {
+        int index = oneofDescriptor.getIndex();
+        FieldDescriptor oldField = oneofCases[index];
+        if ((oldField != null) && (oldField != field)) {
+          fields.clearField(oldField);
+        }
+        oneofCases[index] = field;
+      }
+      fields.setField(field, value);
+      return this;
+    }
+
+    @Override
+    public Builder clearField(FieldDescriptor field) {
+      verifyContainingType(field);
+      ensureIsMutable();
+      OneofDescriptor oneofDescriptor = field.getContainingOneof();
+      if (oneofDescriptor != null) {
+        int index = oneofDescriptor.getIndex();
+        if (oneofCases[index] == field) {
+          oneofCases[index] = null;
+        }
+      }
+      fields.clearField(field);
+      return this;
+    }
+
+    @Override
+    public int getRepeatedFieldCount(FieldDescriptor field) {
+      verifyContainingType(field);
+      return fields.getRepeatedFieldCount(field);
+    }
+
+    @Override
+    public Object getRepeatedField(FieldDescriptor field, int index) {
+      verifyContainingType(field);
+      return fields.getRepeatedField(field, index);
+    }
+
+    @Override
+    public Builder setRepeatedField(FieldDescriptor field, int index, Object value) {
+      verifyContainingType(field);
+      ensureIsMutable();
+      fields.setRepeatedField(field, index, value);
+      return this;
+    }
+
+    @Override
+    public Builder addRepeatedField(FieldDescriptor field, Object value) {
+      verifyContainingType(field);
+      ensureIsMutable();
+      fields.addRepeatedField(field, value);
+      return this;
+    }
+
+    @Override
+    public UnknownFieldSet getUnknownFields() {
+      return unknownFields;
+    }
+
+    @Override
+    public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+      if (getDescriptorForType().getFile().getSyntax()
+          == Descriptors.FileDescriptor.Syntax.PROTO3) {
+        // Proto3 discards unknown fields.
+        return this;
+      }
+      this.unknownFields = unknownFields;
+      return this;
+    }
+
+    @Override
+    public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
+      if (getDescriptorForType().getFile().getSyntax()
+          == Descriptors.FileDescriptor.Syntax.PROTO3) {
+        // Proto3 discards unknown fields.
+        return this;
+      }
+      this.unknownFields =
+        UnknownFieldSet.newBuilder(this.unknownFields)
+                       .mergeFrom(unknownFields)
+                       .build();
+      return this;
+    }
+
+    /** Verifies that the field is a field of this message. */
+    private void verifyContainingType(FieldDescriptor field) {
+      if (field.getContainingType() != type) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+
+    /** Verifies that the oneof is an oneof of this message. */
+    private void verifyOneofContainingType(OneofDescriptor oneof) {
+      if (oneof.getContainingType() != type) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+    }
+
+    /** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
+    private void ensureSingularEnumValueDescriptor(
+        FieldDescriptor field, Object value) {
+      if (value == null) {
+        throw new NullPointerException();
+      }
+      if (!(value instanceof EnumValueDescriptor)) {
+        throw new IllegalArgumentException(
+          "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
+      }
+      // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
+      // set incorrect EnumValueDescriptors.
+      // EnumDescriptor fieldType = field.getEnumType();
+      // EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
+      // if (fieldType != fieldValueType) {
+      //  throw new IllegalArgumentException(String.format(
+      //      "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
+      //      fieldType.getFullName(), fieldValueType.getFullName()));
+      // }
+    }
+
+    /** Verifies the value for an enum field. */
+    private void ensureEnumValueDescriptor(
+        FieldDescriptor field, Object value) {
+      if (field.isRepeated()) {
+        for (Object item : (List) value) {
+          ensureSingularEnumValueDescriptor(field, item);
+        }
+      } else {
+         ensureSingularEnumValueDescriptor(field, value);
+      }
+    }
+
+    private void ensureIsMutable() {
+      if (fields.isImmutable()) {
+        fields = fields.clone();
+      }
+    }
+
+    @Override
+    public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
+      // TODO(xiangl): need implementation for dynamic message
+      throw new UnsupportedOperationException(
+        "getFieldBuilder() called on a dynamic message type.");
+    }
+
+    @Override
+    public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(FieldDescriptor field,
+        int index) {
+      throw new UnsupportedOperationException(
+        "getRepeatedFieldBuilder() called on a dynamic message type.");
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
new file mode 100644
index 0000000..3cd4c88
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
@@ -0,0 +1,66 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates a public API that can change at any time, and has no guarantee of API stability and
+ * backward-compatibility.
+ *
+ * <p>Usage guidelines:
+ * <ol>
+ * <li>This annotation is used only on public API. Internal interfaces should not use it.</li>
+ * <li>This annotation should only be added to new APIs. Adding it to an existing API is
+ * considered API-breaking.</li>
+ * <li>Removing this annotation from an API gives it stable status.</li>
+ * </ol>
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+    ElementType.ANNOTATION_TYPE,
+    ElementType.CONSTRUCTOR,
+    ElementType.FIELD,
+    ElementType.METHOD,
+    ElementType.PACKAGE,
+    ElementType.TYPE})
+@Documented
+public @interface ExperimentalApi {
+  /**
+   * Context information such as links to discussion thread, tracking issue etc.
+   */
+  String value() default "";
+}
+
diff --git a/java/core/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
new file mode 100644
index 0000000..08ec5b4
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Extension.java
@@ -0,0 +1,86 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Interface that generated extensions implement.
+ *
+ * @author liujisi@google.com (Jisi Liu)
+ */
+public abstract class Extension<ContainingType extends MessageLite, Type>
+    extends ExtensionLite<ContainingType, Type> {
+
+  /** Returns the descriptor of the extension. */
+  public abstract Descriptors.FieldDescriptor getDescriptor();
+
+  /** Returns whether or not this extension is a Lite Extension. */
+  @Override
+  final boolean isLite() {
+    return false;
+  }
+
+  // All the methods below are extension implementation details.
+
+  /**
+   * The API type that the extension is used for.
+   */
+  protected enum ExtensionType {
+    IMMUTABLE,
+    MUTABLE,
+    PROTO1,
+  }
+
+  protected ExtensionType getExtensionType() {
+    // TODO(liujisi): make this abstract after we fix proto1.
+    return ExtensionType.IMMUTABLE;
+  }
+
+  /**
+   * Type of a message extension.
+   */
+  public enum MessageType {
+    PROTO1,
+    PROTO2,
+  }
+  
+  /**
+   * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
+   * returns the type of the message, otherwise undefined.
+   */
+  public MessageType getMessageType() {
+    return MessageType.PROTO2;
+  }
+
+  protected abstract Object fromReflectionType(Object value);
+  protected abstract Object singularFromReflectionType(Object value);
+  protected abstract Object toReflectionType(Object value);
+  protected abstract Object singularToReflectionType(Object value);
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionLite.java
new file mode 100644
index 0000000..f8f5bd2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionLite.java
@@ -0,0 +1,63 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Lite interface that generated extensions implement.
+ * <p>
+ * Methods are for use by generated code only. You can hold a reference to
+ * extensions using this type name.
+ */
+public abstract class ExtensionLite<ContainingType extends MessageLite, Type> {
+
+  /** Returns the field number of the extension. */
+  public abstract int getNumber();
+
+  /** Returns the type of the field. */
+  public abstract WireFormat.FieldType getLiteType();
+
+  /** Returns whether it is a repeated field. */
+  public abstract boolean isRepeated();
+
+  /** Returns the default value of the extension field. */
+  public abstract Type getDefaultValue();
+
+  /**
+   * Returns the default instance of the extension field, if it's a message
+   * extension.
+   */
+  public abstract MessageLite getMessageDefaultInstance();
+  
+  /** Returns whether or not this extension is a Lite Extension. */
+  boolean isLite() {
+    return true;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionRegistry.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
new file mode 100644
index 0000000..4e89709
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -0,0 +1,908 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.LazyField.LazyIterator;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A class which represents an arbitrary set of fields of some message type.
+ * This is used to implement {@link DynamicMessage}, and also to represent
+ * extensions in {@link GeneratedMessage}.  This class is package-private,
+ * since outside users should probably be using {@link DynamicMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+final class FieldSet<FieldDescriptorType extends
+      FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
+  /**
+   * Interface for a FieldDescriptor or lite extension descriptor.  This
+   * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
+   */
+  public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
+      extends Comparable<T> {
+    int getNumber();
+    WireFormat.FieldType getLiteType();
+    WireFormat.JavaType getLiteJavaType();
+    boolean isRepeated();
+    boolean isPacked();
+    Internal.EnumLiteMap<?> getEnumType();
+
+    // If getLiteJavaType() == MESSAGE, this merges a message object of the
+    // type into a builder of the type.  Returns {@code to}.
+    MessageLite.Builder internalMergeFrom(
+        MessageLite.Builder to, MessageLite from);
+  }
+
+  private final SmallSortedMap<FieldDescriptorType, Object> fields;
+  private boolean isImmutable;
+  private boolean hasLazyField = false;
+
+  /** Construct a new FieldSet. */
+  private FieldSet() {
+    this.fields = SmallSortedMap.newFieldMap(16);
+  }
+
+  /**
+   * Construct an empty FieldSet.  This is only used to initialize
+   * DEFAULT_INSTANCE.
+   */
+  private FieldSet(final boolean dummy) {
+    this.fields = SmallSortedMap.newFieldMap(0);
+    makeImmutable();
+  }
+
+  /** Construct a new FieldSet. */
+  public static <T extends FieldSet.FieldDescriptorLite<T>>
+      FieldSet<T> newFieldSet() {
+    return new FieldSet<T>();
+  }
+
+  /** Get an immutable empty FieldSet. */
+  @SuppressWarnings("unchecked")
+  public static <T extends FieldSet.FieldDescriptorLite<T>>
+      FieldSet<T> emptySet() {
+    return DEFAULT_INSTANCE;
+  }
+  @SuppressWarnings("rawtypes")
+  private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
+
+  /** Make this FieldSet immutable from this point forward. */
+  @SuppressWarnings("unchecked")
+  public void makeImmutable() {
+    if (isImmutable) {
+      return;
+    }
+    fields.makeImmutable();
+    isImmutable = true;
+  }
+
+  /**
+   * Returns whether the FieldSet is immutable. This is true if it is the
+   * {@link #emptySet} or if {@link #makeImmutable} were called.
+   *
+   * @return whether the FieldSet is immutable.
+   */
+  public boolean isImmutable() {
+    return isImmutable;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    
+    if (!(o instanceof FieldSet)) {
+      return false;
+    }
+    
+    FieldSet<?> other = (FieldSet<?>) o;
+    return other.fields.equals(other.fields);
+  }
+  
+  @Override
+  public int hashCode() {
+    return fields.hashCode();
+  }
+
+  /**
+   * Clones the FieldSet. The returned FieldSet will be mutable even if the
+   * original FieldSet was immutable.
+   *
+   * @return the newly cloned FieldSet
+   */
+  @Override
+  public FieldSet<FieldDescriptorType> clone() {
+    // We can't just call fields.clone because List objects in the map
+    // should not be shared.
+    FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
+      FieldDescriptorType descriptor = entry.getKey();
+      clone.setField(descriptor, entry.getValue());
+    }
+    for (Map.Entry<FieldDescriptorType, Object> entry :
+             fields.getOverflowEntries()) {
+      FieldDescriptorType descriptor = entry.getKey();
+      clone.setField(descriptor, entry.getValue());
+    }
+    clone.hasLazyField = hasLazyField;
+    return clone;
+  }
+
+
+  // =================================================================
+
+  /** See {@link Message.Builder#clear()}. */
+  public void clear() {
+    fields.clear();
+    hasLazyField = false;
+  }
+
+  /**
+   * Get a simple map containing all the fields.
+   */
+  public Map<FieldDescriptorType, Object> getAllFields() {
+    if (hasLazyField) {
+      SmallSortedMap<FieldDescriptorType, Object> result =
+          SmallSortedMap.newFieldMap(16);
+      for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+        cloneFieldEntry(result, fields.getArrayEntryAt(i));
+      }
+      for (Map.Entry<FieldDescriptorType, Object> entry :
+          fields.getOverflowEntries()) {
+        cloneFieldEntry(result, entry);
+      }
+      if (fields.isImmutable()) {
+        result.makeImmutable();
+      }
+      return result;
+    }
+    return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
+  }
+
+  private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
+      Map.Entry<FieldDescriptorType, Object> entry) {
+    FieldDescriptorType key = entry.getKey();
+    Object value = entry.getValue();
+    if (value instanceof LazyField) {
+      map.put(key, ((LazyField) value).getValue());
+    } else {
+      map.put(key, value);
+    }
+  }
+
+  /**
+   * Get an iterator to the field map. This iterator should not be leaked out
+   * of the protobuf library as it is not protected from mutation when fields
+   * is not immutable.
+   */
+  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
+    if (hasLazyField) {
+      return new LazyIterator<FieldDescriptorType>(
+          fields.entrySet().iterator());
+    }
+    return fields.entrySet().iterator();
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message#hasField(Descriptors.FieldDescriptor)}.
+   */
+  public boolean hasField(final FieldDescriptorType descriptor) {
+    if (descriptor.isRepeated()) {
+      throw new IllegalArgumentException(
+        "hasField() can only be called on non-repeated fields.");
+    }
+
+    return fields.get(descriptor) != null;
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
+   * returns {@code null} if the field is not set; in this case it is up
+   * to the caller to fetch the field's default value.
+   */
+  public Object getField(final FieldDescriptorType descriptor) {
+    Object o = fields.get(descriptor);
+    if (o instanceof LazyField) {
+      return ((LazyField) o).getValue();
+    }
+    return o;
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
+   */
+  @SuppressWarnings({"unchecked", "rawtypes"})
+  public void setField(final FieldDescriptorType descriptor,
+                       Object value) {
+    if (descriptor.isRepeated()) {
+      if (!(value instanceof List)) {
+        throw new IllegalArgumentException(
+          "Wrong object type used with protocol message reflection.");
+      }
+
+      // Wrap the contents in a new list so that the caller cannot change
+      // the list's contents after setting it.
+      final List newList = new ArrayList();
+      newList.addAll((List) value);
+      for (final Object element : newList) {
+        verifyType(descriptor.getLiteType(), element);
+      }
+      value = newList;
+    } else {
+      verifyType(descriptor.getLiteType(), value);
+    }
+
+    if (value instanceof LazyField) {
+      hasLazyField = true;
+    }
+    fields.put(descriptor, value);
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
+   */
+  public void clearField(final FieldDescriptorType descriptor) {
+    fields.remove(descriptor);
+    if (fields.isEmpty()) {
+      hasLazyField = false;
+    }
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
+   */
+  public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
+    if (!descriptor.isRepeated()) {
+      throw new IllegalArgumentException(
+        "getRepeatedField() can only be called on repeated fields.");
+    }
+
+    final Object value = getField(descriptor);
+    if (value == null) {
+      return 0;
+    } else {
+      return ((List<?>) value).size();
+    }
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
+   */
+  public Object getRepeatedField(final FieldDescriptorType descriptor,
+                                 final int index) {
+    if (!descriptor.isRepeated()) {
+      throw new IllegalArgumentException(
+        "getRepeatedField() can only be called on repeated fields.");
+    }
+
+    final Object value = getField(descriptor);
+
+    if (value == null) {
+      throw new IndexOutOfBoundsException();
+    } else {
+      return ((List<?>) value).get(index);
+    }
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
+   */
+  @SuppressWarnings("unchecked")
+  public void setRepeatedField(final FieldDescriptorType descriptor,
+                               final int index,
+                               final Object value) {
+    if (!descriptor.isRepeated()) {
+      throw new IllegalArgumentException(
+        "getRepeatedField() can only be called on repeated fields.");
+    }
+
+    final Object list = getField(descriptor);
+    if (list == null) {
+      throw new IndexOutOfBoundsException();
+    }
+
+    verifyType(descriptor.getLiteType(), value);
+    ((List<Object>) list).set(index, value);
+  }
+
+  /**
+   * Useful for implementing
+   * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
+   */
+  @SuppressWarnings("unchecked")
+  public void addRepeatedField(final FieldDescriptorType descriptor,
+                               final Object value) {
+    if (!descriptor.isRepeated()) {
+      throw new IllegalArgumentException(
+        "addRepeatedField() can only be called on repeated fields.");
+    }
+
+    verifyType(descriptor.getLiteType(), value);
+
+    final Object existingValue = getField(descriptor);
+    List<Object> list;
+    if (existingValue == null) {
+      list = new ArrayList<Object>();
+      fields.put(descriptor, list);
+    } else {
+      list = (List<Object>) existingValue;
+    }
+
+    list.add(value);
+  }
+
+  /**
+   * Verifies that the given object is of the correct type to be a valid
+   * value for the given field.  (For repeated fields, this checks if the
+   * object is the right type to be one element of the field.)
+   *
+   * @throws IllegalArgumentException The value is not of the right type.
+   */
+  private static void verifyType(final WireFormat.FieldType type,
+                                 final Object value) {
+    if (value == null) {
+      throw new NullPointerException();
+    }
+
+    boolean isValid = false;
+    switch (type.getJavaType()) {
+      case INT:          isValid = value instanceof Integer   ; break;
+      case LONG:         isValid = value instanceof Long      ; break;
+      case FLOAT:        isValid = value instanceof Float     ; break;
+      case DOUBLE:       isValid = value instanceof Double    ; break;
+      case BOOLEAN:      isValid = value instanceof Boolean   ; break;
+      case STRING:       isValid = value instanceof String    ; break;
+      case BYTE_STRING:
+        isValid = value instanceof ByteString || value instanceof byte[];
+        break;
+      case ENUM:
+        // TODO(kenton):  Caller must do type checking here, I guess.
+        isValid =
+            (value instanceof Integer || value instanceof Internal.EnumLite);
+        break;
+      case MESSAGE:
+        // TODO(kenton):  Caller must do type checking here, I guess.
+        isValid =
+            (value instanceof MessageLite) || (value instanceof LazyField);
+        break;
+    }
+
+    if (!isValid) {
+      // TODO(kenton):  When chaining calls to setField(), it can be hard to
+      //   tell from the stack trace which exact call failed, since the whole
+      //   chain is considered one line of code.  It would be nice to print
+      //   more information here, e.g. naming the field.  We used to do that.
+      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
+      //   isn't a big deal, though, since it would only really apply when using
+      //   reflection and generally people don't chain reflection setters.
+      throw new IllegalArgumentException(
+        "Wrong object type used with protocol message reflection.");
+    }
+  }
+
+  // =================================================================
+  // Parsing and serialization
+
+  /**
+   * See {@link Message#isInitialized()}.  Note:  Since {@code FieldSet}
+   * itself does not have any way of knowing about required fields that
+   * aren't actually present in the set, it is up to the caller to check
+   * that all required fields are present.
+   */
+  public boolean isInitialized() {
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      if (!isInitialized(fields.getArrayEntryAt(i))) {
+        return false;
+      }
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+             fields.getOverflowEntries()) {
+      if (!isInitialized(entry)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @SuppressWarnings("unchecked")
+  private boolean isInitialized(
+      final Map.Entry<FieldDescriptorType, Object> entry) {
+    final FieldDescriptorType descriptor = entry.getKey();
+    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+      if (descriptor.isRepeated()) {
+        for (final MessageLite element:
+                 (List<MessageLite>) entry.getValue()) {
+          if (!element.isInitialized()) {
+            return false;
+          }
+        }
+      } else {
+        Object value = entry.getValue();
+        if (value instanceof MessageLite) {
+          if (!((MessageLite) value).isInitialized()) {
+            return false;
+          }
+        } else if (value instanceof LazyField) {
+          return true;
+        } else {
+          throw new IllegalArgumentException(
+              "Wrong object type used with protocol message reflection.");
+        }
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Given a field type, return the wire type.
+   *
+   * @returns One of the {@code WIRETYPE_} constants defined in
+   *          {@link WireFormat}.
+   */
+  static int getWireFormatForFieldType(final WireFormat.FieldType type,
+                                       boolean isPacked) {
+    if (isPacked) {
+      return WireFormat.WIRETYPE_LENGTH_DELIMITED;
+    } else {
+      return type.getWireType();
+    }
+  }
+
+  /**
+   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 
+   * {@link FieldSet}.
+   */
+  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
+    for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
+      mergeFromField(other.fields.getArrayEntryAt(i));
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+             other.fields.getOverflowEntries()) {
+      mergeFromField(entry);
+    }
+  }
+
+  private Object cloneIfMutable(Object value) {
+    if (value instanceof byte[]) {
+      byte[] bytes = (byte[]) value;
+      byte[] copy = new byte[bytes.length];
+      System.arraycopy(bytes, 0, copy, 0, bytes.length);
+      return copy;
+    } else {
+      return value;
+    }
+  }
+
+  @SuppressWarnings({"unchecked", "rawtypes"})
+  private void mergeFromField(
+      final Map.Entry<FieldDescriptorType, Object> entry) {
+    final FieldDescriptorType descriptor = entry.getKey();
+    Object otherValue = entry.getValue();
+    if (otherValue instanceof LazyField) {
+      otherValue = ((LazyField) otherValue).getValue();
+    }
+
+    if (descriptor.isRepeated()) {
+      Object value = getField(descriptor);
+      if (value == null) {
+        value = new ArrayList();
+      }
+      for (Object element : (List) otherValue) {
+        ((List) value).add(cloneIfMutable(element));
+      }
+      fields.put(descriptor, value);
+    } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+      Object value = getField(descriptor);
+      if (value == null) {
+        fields.put(descriptor, cloneIfMutable(otherValue));
+      } else {
+        // Merge the messages.
+          value = descriptor.internalMergeFrom(
+                ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
+                .build();
+
+        fields.put(descriptor, value);
+      }
+    } else {
+      fields.put(descriptor, cloneIfMutable(otherValue));
+    }
+  }
+
+  // TODO(kenton):  Move static parsing and serialization methods into some
+  //   other class.  Probably WireFormat.
+
+  /**
+   * Read a field of any primitive type for immutable messages from a
+   * CodedInputStream. Enums, groups, and embedded messages are not handled by
+   * this method.
+   *
+   * @param input The stream from which to read.
+   * @param type Declared type of the field.
+   * @param checkUtf8 When true, check that the input is valid utf8.
+   * @return An object representing the field's value, of the exact
+   *         type which would be returned by
+   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *         this field.
+   */
+  public static Object readPrimitiveField(
+      CodedInputStream input,
+      final WireFormat.FieldType type,
+      boolean checkUtf8) throws IOException {
+    if (checkUtf8) {
+      return WireFormat.readPrimitiveField(input, type,
+          WireFormat.Utf8Validation.STRICT);
+    } else {
+      return WireFormat.readPrimitiveField(input, type,
+          WireFormat.Utf8Validation.LOOSE);
+    }
+  }
+
+
+  /** See {@link Message#writeTo(CodedOutputStream)}. */
+  public void writeTo(final CodedOutputStream output)
+                      throws IOException {
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      final Map.Entry<FieldDescriptorType, Object> entry =
+          fields.getArrayEntryAt(i);
+      writeField(entry.getKey(), entry.getValue(), output);
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+         fields.getOverflowEntries()) {
+      writeField(entry.getKey(), entry.getValue(), output);
+    }
+  }
+
+  /**
+   * Like {@link #writeTo} but uses MessageSet wire format.
+   */
+  public void writeMessageSetTo(final CodedOutputStream output)
+                                throws IOException {
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      writeMessageSetTo(fields.getArrayEntryAt(i), output);
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+             fields.getOverflowEntries()) {
+      writeMessageSetTo(entry, output);
+    }
+  }
+
+  private void writeMessageSetTo(
+      final Map.Entry<FieldDescriptorType, Object> entry,
+      final CodedOutputStream output) throws IOException {
+    final FieldDescriptorType descriptor = entry.getKey();
+    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
+        !descriptor.isRepeated() && !descriptor.isPacked()) {
+      Object value = entry.getValue();
+      if (value instanceof LazyField) {
+        value = ((LazyField) value).getValue();
+      }
+      output.writeMessageSetExtension(entry.getKey().getNumber(),
+                                      (MessageLite) value);
+    } else {
+      writeField(descriptor, entry.getValue(), output);
+    }
+  }
+
+  /**
+   * Write a single tag-value pair to the stream.
+   *
+   * @param output The output stream.
+   * @param type   The field's type.
+   * @param number The field's number.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  private static void writeElement(final CodedOutputStream output,
+                                   final WireFormat.FieldType type,
+                                   final int number,
+                                   final Object value) throws IOException {
+    // Special case for groups, which need a start and end tag; other fields
+    // can just use writeTag() and writeFieldNoTag().
+    if (type == WireFormat.FieldType.GROUP) {
+        output.writeGroup(number, (MessageLite) value);
+    } else {
+      output.writeTag(number, getWireFormatForFieldType(type, false));
+      writeElementNoTag(output, type, value);
+    }
+  }
+
+  /**
+   * Write a field of arbitrary type, without its tag, to the stream.
+   *
+   * @param output The output stream.
+   * @param type The field's type.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  static void writeElementNoTag(
+      final CodedOutputStream output,
+      final WireFormat.FieldType type,
+      final Object value) throws IOException {
+    switch (type) {
+      case DOUBLE  : output.writeDoubleNoTag  ((Double     ) value); break;
+      case FLOAT   : output.writeFloatNoTag   ((Float      ) value); break;
+      case INT64   : output.writeInt64NoTag   ((Long       ) value); break;
+      case UINT64  : output.writeUInt64NoTag  ((Long       ) value); break;
+      case INT32   : output.writeInt32NoTag   ((Integer    ) value); break;
+      case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
+      case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
+      case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
+      case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
+      case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
+      case STRING:
+        if (value instanceof ByteString) {
+          output.writeBytesNoTag((ByteString) value);
+        } else {
+          output.writeStringNoTag((String) value);
+        }
+        break;
+      case BYTES:
+        if (value instanceof ByteString) {
+          output.writeBytesNoTag((ByteString) value);
+        } else {
+          output.writeByteArrayNoTag((byte[]) value);
+        }
+        break;
+      case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
+      case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
+      case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
+      case SINT32  : output.writeSInt32NoTag  ((Integer    ) value); break;
+      case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
+
+      case ENUM:
+        if (value instanceof Internal.EnumLite) {
+          output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+        } else {
+          output.writeEnumNoTag(((Integer) value).intValue());
+        }
+        break;
+    }
+  }
+
+  /** Write a single field. */
+  public static void writeField(final FieldDescriptorLite<?> descriptor,
+                                final Object value,
+                                final CodedOutputStream output)
+                                throws IOException {
+    WireFormat.FieldType type = descriptor.getLiteType();
+    int number = descriptor.getNumber();
+    if (descriptor.isRepeated()) {
+      final List<?> valueList = (List<?>)value;
+      if (descriptor.isPacked()) {
+        output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+        // Compute the total data size so the length can be written.
+        int dataSize = 0;
+        for (final Object element : valueList) {
+          dataSize += computeElementSizeNoTag(type, element);
+        }
+        output.writeRawVarint32(dataSize);
+        // Write the data itself, without any tags.
+        for (final Object element : valueList) {
+          writeElementNoTag(output, type, element);
+        }
+      } else {
+        for (final Object element : valueList) {
+          writeElement(output, type, number, element);
+        }
+      }
+    } else {
+      if (value instanceof LazyField) {
+        writeElement(output, type, number, ((LazyField) value).getValue());
+      } else {
+        writeElement(output, type, number, value);
+      }
+    }
+  }
+
+  /**
+   * See {@link Message#getSerializedSize()}.  It's up to the caller to cache
+   * the resulting size if desired.
+   */
+  public int getSerializedSize() {
+    int size = 0;
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      final Map.Entry<FieldDescriptorType, Object> entry =
+          fields.getArrayEntryAt(i);
+      size += computeFieldSize(entry.getKey(), entry.getValue());
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+         fields.getOverflowEntries()) {
+      size += computeFieldSize(entry.getKey(), entry.getValue());
+    }
+    return size;
+  }
+
+  /**
+   * Like {@link #getSerializedSize} but uses MessageSet wire format.
+   */
+  public int getMessageSetSerializedSize() {
+    int size = 0;
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
+    }
+    for (final Map.Entry<FieldDescriptorType, Object> entry :
+             fields.getOverflowEntries()) {
+      size += getMessageSetSerializedSize(entry);
+    }
+    return size;
+  }
+
+  private int getMessageSetSerializedSize(
+      final Map.Entry<FieldDescriptorType, Object> entry) {
+    final FieldDescriptorType descriptor = entry.getKey();
+    Object value = entry.getValue();
+    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
+        && !descriptor.isRepeated() && !descriptor.isPacked()) {
+      if (value instanceof LazyField) {
+        return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
+            entry.getKey().getNumber(), (LazyField) value);
+      } else {
+        return CodedOutputStream.computeMessageSetExtensionSize(
+            entry.getKey().getNumber(), (MessageLite) value);
+      }
+    } else {
+      return computeFieldSize(descriptor, value);
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * single tag/value pair of arbitrary type.
+   *
+   * @param type   The field's type.
+   * @param number The field's number.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  private static int computeElementSize(
+      final WireFormat.FieldType type,
+      final int number, final Object value) {
+    int tagSize = CodedOutputStream.computeTagSize(number);
+    if (type == WireFormat.FieldType.GROUP) {
+      // Only count the end group tag for proto2 messages as for proto1 the end
+      // group tag will be counted as a part of getSerializedSize().
+        tagSize *= 2;
+    }
+    return tagSize + computeElementSizeNoTag(type, value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * particular value of arbitrary type, excluding tag.
+   *
+   * @param type   The field's type.
+   * @param value  Object representing the field's value.  Must be of the exact
+   *               type which would be returned by
+   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *               this field.
+   */
+  static int computeElementSizeNoTag(
+      final WireFormat.FieldType type, final Object value) {
+    switch (type) {
+      // Note:  Minor violation of 80-char limit rule here because this would
+      //   actually be harder to read if we wrapped the lines.
+      case DOUBLE  : return CodedOutputStream.computeDoubleSizeNoTag  ((Double     )value);
+      case FLOAT   : return CodedOutputStream.computeFloatSizeNoTag   ((Float      )value);
+      case INT64   : return CodedOutputStream.computeInt64SizeNoTag   ((Long       )value);
+      case UINT64  : return CodedOutputStream.computeUInt64SizeNoTag  ((Long       )value);
+      case INT32   : return CodedOutputStream.computeInt32SizeNoTag   ((Integer    )value);
+      case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
+      case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
+      case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
+      case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
+      case BYTES   :
+        if (value instanceof ByteString) {
+          return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+        } else {
+          return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
+        }
+      case STRING  :
+        if (value instanceof ByteString) {
+          return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+        } else {
+          return CodedOutputStream.computeStringSizeNoTag((String) value);
+        }
+      case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
+      case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
+      case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
+      case SINT32  : return CodedOutputStream.computeSInt32SizeNoTag  ((Integer    )value);
+      case SINT64  : return CodedOutputStream.computeSInt64SizeNoTag  ((Long       )value);
+
+      case MESSAGE:
+        if (value instanceof LazyField) {
+          return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
+        } else {
+          return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
+        }
+
+      case ENUM:
+        if (value instanceof Internal.EnumLite) {
+          return CodedOutputStream.computeEnumSizeNoTag(
+              ((Internal.EnumLite) value).getNumber());
+        } else {
+          return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
+        }
+    }
+
+    throw new RuntimeException(
+      "There is no way to get here, but the compiler thinks otherwise.");
+  }
+
+  /**
+   * Compute the number of bytes needed to encode a particular field.
+   */
+  public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
+                                     final Object value) {
+    WireFormat.FieldType type = descriptor.getLiteType();
+    int number = descriptor.getNumber();
+    if (descriptor.isRepeated()) {
+      if (descriptor.isPacked()) {
+        int dataSize = 0;
+        for (final Object element : (List<?>)value) {
+          dataSize += computeElementSizeNoTag(type, element);
+        }
+        return dataSize +
+            CodedOutputStream.computeTagSize(number) +
+            CodedOutputStream.computeRawVarint32Size(dataSize);
+      } else {
+        int size = 0;
+        for (final Object element : (List<?>)value) {
+          size += computeElementSize(type, number, element);
+        }
+        return size;
+      }
+    } else {
+      return computeElementSize(type, number, value);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
new file mode 100644
index 0000000..63cb6d7
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -0,0 +1,269 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.FloatList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link FloatList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class FloatArrayList extends AbstractProtobufList<Float> implements FloatList, RandomAccess {
+  
+  private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static FloatArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private float[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} with default capacity.
+   */
+  FloatArrayList() {
+    this(new float[DEFAULT_CAPACITY], 0);
+  }
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
+   */
+  private FloatArrayList(float[] array, int size) {
+    this.array = array;
+    this.size = size;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof FloatArrayList)) {
+      return super.equals(o);
+    }
+    FloatArrayList other = (FloatArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+    
+    final float[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
+      }
+    }
+    
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Float.floatToIntBits(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public FloatList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new FloatArrayList(Arrays.copyOf(array, capacity), size);
+  }
+  
+  @Override
+  public Float get(int index) {
+    return getFloat(index);
+  }
+
+  @Override
+  public float getFloat(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Float set(int index, Float element) {
+    return setFloat(index, element);
+  }
+
+  @Override
+  public float setFloat(int index, float element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    float previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Float element) {
+    addFloat(index, element);
+  }
+
+  /**
+   * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addFloat(float element) {
+    addFloat(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Float)} but more efficient in that it doesn't box the element.
+   */
+  private void addFloat(int index, float element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      float[] newArray = new float[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Float> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another FloatArrayList to avoid boxing elements.
+    if (!(collection instanceof FloatArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    FloatArrayList list = (FloatArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Float remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    float value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
new file mode 100644
index 0000000..790cb62
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -0,0 +1,2883 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * All generated protocol message classes extend this class.  This class
+ * implements most of the Message and Builder interfaces using Java reflection.
+ * Users can ignore this class and pretend that generated messages implement
+ * the Message interface directly.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessage extends AbstractMessage
+    implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * For testing. Allows a test to disable the optimization that avoids using
+   * field builders for nested messages until they are requested. By disabling
+   * this optimization, existing tests can be reused to test the field builders.
+   */
+  protected static boolean alwaysUseFieldBuilders = false;
+
+  /** For use by generated code only.  */
+  protected UnknownFieldSet unknownFields;
+
+  protected GeneratedMessage() {
+    unknownFields = UnknownFieldSet.getDefaultInstance();
+  }
+
+  protected GeneratedMessage(Builder<?> builder) {
+    unknownFields = builder.getUnknownFields();
+  }
+
+  @Override
+  public Parser<? extends GeneratedMessage> getParserForType() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+ /**
+  * For testing. Allows a test to disable the optimization that avoids using
+  * field builders for nested messages until they are requested. By disabling
+  * this optimization, existing tests can be reused to test the field builders.
+  * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
+  */
+  static void enableAlwaysUseFieldBuildersForTesting() {
+    alwaysUseFieldBuilders = true;
+  }
+
+  /**
+   * Get the FieldAccessorTable for this type.  We can't have the message
+   * class pass this in to the constructor because of bootstrapping trouble
+   * with DescriptorProtos.
+   */
+  protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+  @Override
+  public Descriptor getDescriptorForType() {
+    return internalGetFieldAccessorTable().descriptor;
+  }
+
+  /**
+   * Internal helper to return a modifiable map containing all the fields.
+   * The returned Map is modifialbe so that the caller can add additional
+   * extension fields to implement {@link #getAllFields()}.
+   *
+   * @param getBytesForString whether to generate ByteString for string fields
+   */
+  private Map<FieldDescriptor, Object> getAllFieldsMutable(
+      boolean getBytesForString) {
+    final TreeMap<FieldDescriptor, Object> result =
+      new TreeMap<FieldDescriptor, Object>();
+    final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+    final List<FieldDescriptor> fields = descriptor.getFields();
+
+    for (int i = 0; i < fields.size(); i++) {
+      FieldDescriptor field = fields.get(i);
+      final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+      /*
+       * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+       * and it is not repeated. There is no need to iterate through the others.
+       */
+      if (oneofDescriptor != null) {
+        // Skip other fields in the Oneof we know are not set
+        i += oneofDescriptor.getFieldCount() - 1;
+        if (!hasOneof(oneofDescriptor)) {
+          // If no field is set in the Oneof, skip all the fields in the Oneof
+          continue;
+        }
+        // Get the pointer to the only field which is set in the Oneof
+        field = getOneofFieldDescriptor(oneofDescriptor);
+      } else {
+        // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+        if (field.isRepeated()) {
+          final List<?> value = (List<?>) getField(field);
+          if (!value.isEmpty()) {
+            result.put(field, value);
+          }
+          continue;
+        }
+        if (!hasField(field)) {
+          continue;
+        }
+      }
+      // Add the field to the map
+      if (getBytesForString && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+        result.put(field, getFieldRaw(field));
+      } else {
+        result.put(field, getField(field));
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+      // Check that all required fields are present.
+      if (field.isRequired()) {
+        if (!hasField(field)) {
+          return false;
+        }
+      }
+      // Check that embedded messages are initialized.
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          @SuppressWarnings("unchecked") final
+          List<Message> messageList = (List<Message>) getField(field);
+          for (final Message element : messageList) {
+            if (!element.isInitialized()) {
+              return false;
+            }
+          }
+        } else {
+          if (hasField(field) && !((Message) getField(field)).isInitialized()) {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  @Override
+  public Map<FieldDescriptor, Object> getAllFields() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ false));
+  }
+
+  /**
+   * Returns a collection of all the fields in this message which are set
+   * and their corresponding values.  A singular ("required" or "optional")
+   * field is set iff hasField() returns true for that field.  A "repeated"
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
+   * values are exactly what would be returned by calling
+   * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field.  The map
+   * is guaranteed to be a sorted map, so iterating over it will return fields
+   * in order by field number.
+   */
+  Map<FieldDescriptor, Object> getAllFieldsRaw() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ true));
+  }
+
+  @Override
+  public boolean hasOneof(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+  }
+
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+  }
+
+  @Override
+  public boolean hasField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).has(this);
+  }
+
+  @Override
+  public Object getField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).get(this);
+  }
+
+  /**
+   * Obtains the value of the given field, or the default value if it is
+   * not set.  For primitive fields, the boxed primitive value is returned.
+   * For enum fields, the EnumValueDescriptor for the value is returned. For
+   * embedded message fields, the sub-message is returned.  For repeated
+   * fields, a java.util.List is returned. For present string fields, a
+   * ByteString is returned representing the bytes that the field contains.
+   */
+  Object getFieldRaw(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).getRaw(this);
+  }
+
+  @Override
+  public int getRepeatedFieldCount(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeatedCount(this);
+  }
+
+  @Override
+  public Object getRepeatedField(final FieldDescriptor field, final int index) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeated(this, index);
+  }
+
+  @Override
+  public UnknownFieldSet getUnknownFields() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+  /**
+   * Called by subclasses to parse an unknown field.
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  protected boolean parseUnknownField(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      int tag) throws IOException {
+    return unknownFields.mergeFieldFrom(tag, input);
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
+      throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input,
+      ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input) throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
+  }
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) {
+      return size;
+    }
+
+    memoizedSize = MessageReflection.getSerializedSize(
+        this, getAllFieldsRaw());
+    return memoizedSize;
+  }
+
+
+
+  /**
+   * Used by parsing constructors in generated classes.
+   */
+  protected void makeExtensionsImmutable() {
+    // Noop for messages without extensions.
+  }
+
+  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
+
+  /**
+   * Interface for the parent of a Builder that allows the builder to
+   * communicate invalidations back to the parent for use when using nested
+   * builders.
+   */
+  protected interface BuilderParent {
+
+    /**
+     * A builder becomes dirty whenever a field is modified -- including fields
+     * in nested builders -- and becomes clean when build() is called.  Thus,
+     * when a builder becomes dirty, all its parents become dirty as well, and
+     * when it becomes clean, all its children become clean.  The dirtiness
+     * state is used to invalidate certain cached values.
+     * <br>
+     * To this end, a builder calls markAsDirty() on its parent whenever it
+     * transitions from clean to dirty.  The parent must propagate this call to
+     * its own parent, unless it was already dirty, in which case the
+     * grandparent must necessarily already be dirty as well.  The parent can
+     * only transition back to "clean" after calling build() on all children.
+     */
+    void markDirty();
+  }
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder <BuilderType extends Builder<BuilderType>>
+      extends AbstractMessage.Builder<BuilderType> {
+
+    private BuilderParent builderParent;
+
+    private BuilderParentImpl meAsParent;
+
+    // Indicates that we've built a message and so we are now obligated
+    // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
+    private boolean isClean;
+
+    private UnknownFieldSet unknownFields =
+        UnknownFieldSet.getDefaultInstance();
+
+    protected Builder() {
+      this(null);
+    }
+
+    protected Builder(BuilderParent builderParent) {
+      this.builderParent = builderParent;
+    }
+
+    void dispose() {
+      builderParent = null;
+    }
+
+    /**
+     * Called by the subclass when a message is built.
+     */
+    protected void onBuilt() {
+      if (builderParent != null) {
+        markClean();
+      }
+    }
+
+    /**
+     * Called by the subclass or a builder to notify us that a message was
+     * built and may be cached and therefore invalidations are needed.
+     */
+    protected void markClean() {
+      this.isClean = true;
+    }
+
+    /**
+     * Gets whether invalidations are needed
+     *
+     * @return whether invalidations are needed
+     */
+    protected boolean isClean() {
+      return isClean;
+    }
+
+    @Override
+    public BuilderType clone() {
+      BuilderType builder =
+          (BuilderType) getDefaultInstanceForType().newBuilderForType();
+      builder.mergeFrom(buildPartial());
+      return builder;
+    }
+
+    /**
+     * Called by the initialization and clear code paths to allow subclasses to
+     * reset any of their builtin fields back to the initial values.
+     */
+    @Override
+    public BuilderType clear() {
+      unknownFields = UnknownFieldSet.getDefaultInstance();
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /**
+     * Get the FieldAccessorTable for this type.  We can't have the message
+     * class pass this in to the constructor because of bootstrapping trouble
+     * with DescriptorProtos.
+     */
+    protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+    @Override
+    public Descriptor getDescriptorForType() {
+      return internalGetFieldAccessorTable().descriptor;
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      return Collections.unmodifiableMap(getAllFieldsMutable());
+    }
+
+    /** Internal helper which returns a mutable map. */
+    private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+      final TreeMap<FieldDescriptor, Object> result =
+        new TreeMap<FieldDescriptor, Object>();
+      final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+      final List<FieldDescriptor> fields = descriptor.getFields();
+
+      for (int i = 0; i < fields.size(); i++) {
+        FieldDescriptor field = fields.get(i);
+        final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+        /*
+         * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+         * and it is not repeated. There is no need to iterate through the others.
+         */
+        if (oneofDescriptor != null) {
+          // Skip other fields in the Oneof we know are not set
+          i += oneofDescriptor.getFieldCount() - 1;
+          if (!hasOneof(oneofDescriptor)) {
+            // If no field is set in the Oneof, skip all the fields in the Oneof
+            continue;
+          }
+          // Get the pointer to the only field which is set in the Oneof
+          field = getOneofFieldDescriptor(oneofDescriptor);
+        } else {
+          // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+          if (field.isRepeated()) {
+            final List<?> value = (List<?>) getField(field);
+            if (!value.isEmpty()) {
+              result.put(field, value);
+            }
+            continue;
+          }
+          if (!hasField(field)) {
+            continue;
+          }
+        }
+        // Add the field to the map
+        result.put(field, getField(field));
+      }
+      return result;
+    }
+
+    @Override
+    public Message.Builder newBuilderForField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).newBuilder();
+    }
+
+    @Override
+    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).getBuilder(this);
+    }
+
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
+      return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
+          this, index);
+    }
+
+    @Override
+    public boolean hasOneof(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+    }
+
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).has(this);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      Object object = internalGetFieldAccessorTable().getField(field).get(this);
+      if (field.isRepeated()) {
+        // The underlying list object is still modifiable at this point.
+        // Make sure not to expose the modifiable list to the caller.
+        return Collections.unmodifiableList((List) object);
+      } else {
+        return object;
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).set(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      internalGetFieldAccessorTable().getField(field).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearOneof(final OneofDescriptor oneof) {
+      internalGetFieldAccessorTable().getOneof(oneof).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeatedCount(this);
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field, final int index) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeated(this, index);
+    }
+
+    @Override
+    public BuilderType setRepeatedField(
+        final FieldDescriptor field, final int index, final Object value) {
+      internalGetFieldAccessorTable().getField(field)
+        .setRepeated(this, index, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
+      this.unknownFields = unknownFields;
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeUnknownFields(
+        final UnknownFieldSet unknownFields) {
+      this.unknownFields =
+        UnknownFieldSet.newBuilder(this.unknownFields)
+                       .mergeFrom(unknownFields)
+                       .build();
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+        // Check that all required fields are present.
+        if (field.isRequired()) {
+          if (!hasField(field)) {
+            return false;
+          }
+        }
+        // Check that embedded messages are initialized.
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (field.isRepeated()) {
+            @SuppressWarnings("unchecked") final
+            List<Message> messageList = (List<Message>) getField(field);
+            for (final Message element : messageList) {
+              if (!element.isInitialized()) {
+                return false;
+              }
+            }
+          } else {
+            if (hasField(field) &&
+                !((Message) getField(field)).isInitialized()) {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    }
+
+    @Override
+    public final UnknownFieldSet getUnknownFields() {
+      return unknownFields;
+    }
+
+    /**
+     * Called by subclasses to parse an unknown field.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      return unknownFields.mergeFieldFrom(tag, input);
+    }
+
+    /**
+     * Implementation of {@link BuilderParent} for giving to our children. This
+     * small inner class makes it so we don't publicly expose the BuilderParent
+     * methods.
+     */
+    private class BuilderParentImpl implements BuilderParent {
+
+      @Override
+      public void markDirty() {
+        onChanged();
+      }
+    }
+
+    /**
+     * Gets the {@link BuilderParent} for giving to our children.
+     * @return The builder parent for our children.
+     */
+    protected BuilderParent getParentForChildren() {
+      if (meAsParent == null) {
+        meAsParent = new BuilderParentImpl();
+      }
+      return meAsParent;
+    }
+
+    /**
+     * Called when a the builder or one of its nested children has changed
+     * and any parent should be notified of its invalidation.
+     */
+    protected final void onChanged() {
+      if (isClean && builderParent != null) {
+        builderParent.markDirty();
+
+        // Don't keep dispatching invalidations until build is called again.
+        isClean = false;
+      }
+    }
+
+    /**
+     * Gets the map field with the given field number. This method should be
+     * overridden in the generated message class if the message contains map
+     * fields.
+     *
+     * Unlike other field types, reflection support for map fields can't be
+     * implemented based on generated public API because we need to access a
+     * map field as a list in reflection API but the generated API only allows
+     * us to access it as a map. This method returns the underlying map field
+     * directly and thus enables us to access the map field as a list.
+     */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+
+    /** Like {@link #internalGetMapField} but return a mutable version. */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMutableMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+  }
+
+  // =================================================================
+  // Extensions-related stuff
+
+  public interface ExtendableMessageOrBuilder<
+      MessageType extends ExtendableMessage> extends MessageOrBuilder {
+    // Re-define for return type covariance.
+    @Override
+    Message getDefaultInstanceForType();
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        ExtensionLite<MessageType, List<Type>> extension);
+
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, List<Type>> extension,
+        int index);
+  }
+
+  /**
+   * Generated message classes for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "has", "get", and "getCount" -- but for extensions.  The extensions
+   * are identified using instances of the class {@link GeneratedExtension};
+   * the protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo = getFoo();
+   * int i = foo.getExtension(MyProto.bar);
+   * </pre>
+   *
+   * <p>See also {@link ExtendableBuilder}.
+   */
+  public abstract static class ExtendableMessage<
+        MessageType extends ExtendableMessage>
+      extends GeneratedMessage
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final FieldSet<FieldDescriptor> extensions;
+
+    protected ExtendableMessage() {
+      this.extensions = FieldSet.newFieldSet();
+    }
+
+    protected ExtendableMessage(
+        ExtendableBuilder<MessageType, ?> builder) {
+      super(builder);
+      this.extensions = builder.buildExtensions();
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    @Override
+    protected boolean parseUnknownField(
+        CodedInputStream input,
+        UnknownFieldSet.Builder unknownFields,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.ExtensionAdapter(extensions), tag);
+    }
+
+
+    /**
+     * Used by parsing constructors in generated classes.
+     */
+    @Override
+    protected void makeExtensionsImmutable() {
+      extensions.makeImmutable();
+    }
+
+    /**
+     * Used by subclasses to serialize extensions.  Extension ranges may be
+     * interleaved with field numbers, but we must write them in canonical
+     * (sorted by field number) order.  ExtensionWriter helps us write
+     * individual ranges of extensions at once.
+     */
+    protected class ExtensionWriter {
+      // Imagine how much simpler this code would be if Java iterators had
+      // a way to get the next element without advancing the iterator.
+
+      private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
+        extensions.iterator();
+      private Map.Entry<FieldDescriptor, Object> next;
+      private final boolean messageSetWireFormat;
+
+      private ExtensionWriter(final boolean messageSetWireFormat) {
+        if (iter.hasNext()) {
+          next = iter.next();
+        }
+        this.messageSetWireFormat = messageSetWireFormat;
+      }
+
+      public void writeUntil(final int end, final CodedOutputStream output)
+                             throws IOException {
+        while (next != null && next.getKey().getNumber() < end) {
+          FieldDescriptor descriptor = next.getKey();
+          if (messageSetWireFormat && descriptor.getLiteJavaType() ==
+                  WireFormat.JavaType.MESSAGE &&
+              !descriptor.isRepeated()) {
+            if (next instanceof LazyField.LazyEntry<?>) {
+              output.writeRawMessageSetExtension(descriptor.getNumber(),
+                  ((LazyField.LazyEntry<?>) next).getField().toByteString());
+            } else {
+              output.writeMessageSetExtension(descriptor.getNumber(),
+                                              (Message) next.getValue());
+            }
+          } else {
+            // TODO(xiangl): Taken care of following code, it may cause
+            // problem when we use LazyField for normal fields/extensions.
+            // Due to the optional field can be duplicated at the end of
+            // serialized bytes, which will make the serialized size change
+            // after lazy field parsed. So when we use LazyField globally,
+            // we need to change the following write method to write cached
+            // bytes directly rather than write the parsed message.
+            FieldSet.writeField(descriptor, next.getValue(), output);
+          }
+          if (iter.hasNext()) {
+            next = iter.next();
+          } else {
+            next = null;
+          }
+        }
+      }
+    }
+
+    protected ExtensionWriter newExtensionWriter() {
+      return new ExtensionWriter(false);
+    }
+    protected ExtensionWriter newMessageSetExtensionWriter() {
+      return new ExtensionWriter(true);
+    }
+
+    /** Called by subclasses to compute the size of extensions. */
+    protected int extensionsSerializedSize() {
+      return extensions.getSerializedSize();
+    }
+    protected int extensionsSerializedSizeAsMessageSet() {
+      return extensions.getMessageSetSerializedSize();
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    protected Map<FieldDescriptor, Object> getExtensionFields() {
+      return extensions.getAllFields();
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFieldsRaw() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.isRepeated()) {
+            return Collections.emptyList();
+          } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  /**
+   * Generated message builders for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "get", "set", and "add" -- but for extensions.  The extensions are
+   * identified using instances of the class {@link GeneratedExtension}; the
+   * protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo =
+   *   MyProto.Foo.newBuilder()
+   *     .setExtension(MyProto.bar, 123)
+   *     .build();
+   * </pre>
+   *
+   * <p>See also {@link ExtendableMessage}.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class ExtendableBuilder<
+        MessageType extends ExtendableMessage,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+      extends Builder<BuilderType>
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
+
+    protected ExtendableBuilder() {}
+
+    protected ExtendableBuilder(
+        BuilderParent parent) {
+      super(parent);
+    }
+
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
+    @Override
+    public BuilderType clear() {
+      extensions = FieldSet.emptySet();
+      return super.clear();
+    }
+
+    // This is implemented here only to work around an apparent bug in the
+    // Java compiler and/or build system.  See bug #1898463.  The mere presence
+    // of this clone() implementation makes it go away.
+    @Override
+    public BuilderType clone() {
+      return super.clone();
+    }
+
+    private void ensureExtensionsIsMutable() {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, Type> extensionLite,
+        final Type value) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setField(descriptor, extension.toReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final int index, final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setRepeatedField(
+        descriptor, index,
+        extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.addRepeatedField(
+          descriptor, extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final ExtensionLite<MessageType, ?> extensionLite) {
+      Extension<MessageType, ?> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      extensions.clearField(extension.getDescriptor());
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    /**
+     * Called by the build code path to create a copy of the extensions for
+     * building the message.
+     */
+    private FieldSet<FieldDescriptor> buildExtensions() {
+      extensions.makeImmutable();
+      return extensions;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    /**
+     * Called by subclasses to parse an unknown field or an extension.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    @Override
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.BuilderAdapter(this), tag);
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+      result.putAll(extensions.getAllFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field,
+                                final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setField(field, value);
+      }
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.clearField(field);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.clearField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setRepeatedField(final FieldDescriptor field,
+                                        final int index, final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setRepeatedField(field, index, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setRepeatedField(field, index, value);
+      }
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field,
+                                        final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.addRepeatedField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.addRepeatedField(field, value);
+      }
+    }
+
+    protected final void mergeExtensionFields(final ExtendableMessage other) {
+      ensureExtensionsIsMutable();
+      extensions.mergeFrom(other.extensions);
+      onChanged();
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Gets the descriptor for an extension. The implementation depends on whether
+   * the extension is scoped in the top level of a file or scoped in a Message.
+   */
+  static interface ExtensionDescriptorRetriever {
+    FieldDescriptor getDescriptor();
+  }
+
+  /** For use by generated code only. */
+  public static <ContainingType extends Message, Type>
+      GeneratedExtension<ContainingType, Type>
+      newMessageScopedGeneratedExtension(final Message scope,
+                                         final int descriptorIndex,
+                                         final Class singularType,
+                                         final Message defaultInstance) {
+    // For extensions scoped within a Message, we use the Message to resolve
+    // the outer class's descriptor, from which the extension descriptor is
+    // obtained.
+    return new GeneratedExtension<ContainingType, Type>(
+        new CachedDescriptorRetriever() {
+          @Override
+          public FieldDescriptor loadDescriptor() {
+            return scope.getDescriptorForType().getExtensions().get(descriptorIndex);
+          }
+        },
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.IMMUTABLE);
+  }
+
+  /** For use by generated code only. */
+  public static <ContainingType extends Message, Type>
+     GeneratedExtension<ContainingType, Type>
+     newFileScopedGeneratedExtension(final Class singularType,
+                                     final Message defaultInstance) {
+    // For extensions scoped within a file, we rely on the outer class's
+    // static initializer to call internalInit() on the extension when the
+    // descriptor is available.
+    return new GeneratedExtension<ContainingType, Type>(
+        null,  // ExtensionDescriptorRetriever is initialized in internalInit();
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.IMMUTABLE);
+  }
+
+  private abstract static class CachedDescriptorRetriever
+      implements ExtensionDescriptorRetriever {
+    private volatile FieldDescriptor descriptor;
+    protected abstract FieldDescriptor loadDescriptor();
+
+    @Override
+    public FieldDescriptor getDescriptor() {
+      if (descriptor == null) {
+        synchronized (this) {
+          if (descriptor == null) {
+            descriptor = loadDescriptor();
+          }
+        }
+      }
+      return descriptor;
+    }
+  }
+
+  /**
+   * Used in proto1 generated code only.
+   *
+   * After enabling bridge, we can define proto2 extensions (the extended type
+   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+   * we should generate proto2 GeneratedExtensions.
+   */
+  public static <ContainingType extends Message, Type>
+      GeneratedExtension<ContainingType, Type>
+      newMessageScopedGeneratedExtension(
+          final Message scope, final String name,
+          final Class singularType, final Message defaultInstance) {
+    // For extensions scoped within a Message, we use the Message to resolve
+    // the outer class's descriptor, from which the extension descriptor is
+    // obtained.
+    return new GeneratedExtension<ContainingType, Type>(
+        new CachedDescriptorRetriever() {
+          @Override
+          protected FieldDescriptor loadDescriptor() {
+            return scope.getDescriptorForType().findFieldByName(name);
+          }
+        },
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.MUTABLE);
+  }
+
+  /**
+   * Used in proto1 generated code only.
+   *
+   * After enabling bridge, we can define proto2 extensions (the extended type
+   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
+   * we should generate proto2 GeneratedExtensions.
+   */
+  public static <ContainingType extends Message, Type>
+     GeneratedExtension<ContainingType, Type>
+     newFileScopedGeneratedExtension(
+         final Class singularType, final Message defaultInstance,
+         final String descriptorOuterClass, final String extensionName) {
+    // For extensions scoped within a file, we load the descriptor outer
+    // class and rely on it to get the FileDescriptor which then can be
+    // used to obtain the extension's FieldDescriptor.
+    return new GeneratedExtension<ContainingType, Type>(
+        new CachedDescriptorRetriever() {
+          @Override
+          protected FieldDescriptor loadDescriptor() {
+            try {
+              Class clazz = singularType.getClassLoader().loadClass(descriptorOuterClass);
+              FileDescriptor file = (FileDescriptor) clazz.getField("descriptor").get(null);
+              return file.findExtensionByName(extensionName);
+            } catch (Exception e) {
+              throw new RuntimeException(
+                  "Cannot load descriptors: "
+                      + descriptorOuterClass
+                      + " is not a valid descriptor class name",
+                  e);
+            }
+          }
+        },
+        singularType,
+        defaultInstance,
+        Extension.ExtensionType.MUTABLE);
+  }
+
+  /**
+   * Type used to represent generated extensions.  The protocol compiler
+   * generates a static singleton instance of this class for each extension.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then, {@code MyProto.Foo.bar} has type
+   * {@code GeneratedExtension<MyProto.Foo, Integer>}.
+   *
+   * <p>In general, users should ignore the details of this type, and simply use
+   * these static singletons as parameters to the extension accessors defined
+   * in {@link ExtendableMessage} and {@link ExtendableBuilder}.
+   */
+  public static class GeneratedExtension<
+      ContainingType extends Message, Type> extends
+      Extension<ContainingType, Type> {
+    // TODO(kenton):  Find ways to avoid using Java reflection within this
+    //   class.  Also try to avoid suppressing unchecked warnings.
+
+    // We can't always initialize the descriptor of a GeneratedExtension when
+    // we first construct it due to initialization order difficulties (namely,
+    // the descriptor may not have been constructed yet, since it is often
+    // constructed by the initializer of a separate module).
+    //
+    // In the case of nested extensions, we initialize the
+    // ExtensionDescriptorRetriever with an instance that uses the scoping
+    // Message's default instance to retrieve the extension's descriptor.
+    //
+    // In the case of non-nested extensions, we initialize the
+    // ExtensionDescriptorRetriever to null and rely on the outer class's static
+    // initializer to call internalInit() after the descriptor has been parsed.
+    GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
+        Class singularType,
+        Message messageDefaultInstance,
+        ExtensionType extensionType) {
+      if (Message.class.isAssignableFrom(singularType) &&
+          !singularType.isInstance(messageDefaultInstance)) {
+        throw new IllegalArgumentException(
+            "Bad messageDefaultInstance for " + singularType.getName());
+      }
+      this.descriptorRetriever = descriptorRetriever;
+      this.singularType = singularType;
+      this.messageDefaultInstance = messageDefaultInstance;
+
+      if (ProtocolMessageEnum.class.isAssignableFrom(singularType)) {
+        this.enumValueOf = getMethodOrDie(singularType, "valueOf",
+                                          EnumValueDescriptor.class);
+        this.enumGetValueDescriptor =
+            getMethodOrDie(singularType, "getValueDescriptor");
+      } else {
+        this.enumValueOf = null;
+        this.enumGetValueDescriptor = null;
+      }
+      this.extensionType = extensionType;
+    }
+
+    /** For use by generated code only. */
+    public void internalInit(final FieldDescriptor descriptor) {
+      if (descriptorRetriever != null) {
+        throw new IllegalStateException("Already initialized.");
+      }
+      descriptorRetriever =
+          new ExtensionDescriptorRetriever() {
+            @Override
+            public FieldDescriptor getDescriptor() {
+              return descriptor;
+            }
+          };
+    }
+
+    private ExtensionDescriptorRetriever descriptorRetriever;
+    private final Class singularType;
+    private final Message messageDefaultInstance;
+    private final Method enumValueOf;
+    private final Method enumGetValueDescriptor;
+    private final ExtensionType extensionType;
+
+    @Override
+    public FieldDescriptor getDescriptor() {
+      if (descriptorRetriever == null) {
+        throw new IllegalStateException(
+            "getDescriptor() called before internalInit()");
+      }
+      return descriptorRetriever.getDescriptor();
+    }
+
+    /**
+     * If the extension is an embedded message or group, returns the default
+     * instance of the message.
+     */
+    @Override
+    public Message getMessageDefaultInstance() {
+      return messageDefaultInstance;
+    }
+
+    @Override
+    protected ExtensionType getExtensionType() {
+      return extensionType;
+    }
+
+    /**
+     * Convert from the type used by the reflection accessors to the type used
+     * by native accessors.  E.g., for enums, the reflection accessors use
+     * EnumValueDescriptors but the native accessors use the generated enum
+     * type.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Object fromReflectionType(final Object value) {
+      FieldDescriptor descriptor = getDescriptor();
+      if (descriptor.isRepeated()) {
+        if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
+            descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+          // Must convert the whole list.
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularFromReflectionType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularFromReflectionType(value);
+      }
+    }
+
+    /**
+     * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
+     * type, this converts a single element.
+     */
+    @Override
+    protected Object singularFromReflectionType(final Object value) {
+      FieldDescriptor descriptor = getDescriptor();
+      switch (descriptor.getJavaType()) {
+        case MESSAGE:
+          if (singularType.isInstance(value)) {
+            return value;
+          } else {
+            return messageDefaultInstance.newBuilderForType()
+                .mergeFrom((Message) value).build();
+          }
+        case ENUM:
+          return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
+        default:
+          return value;
+      }
+    }
+
+    /**
+     * Convert from the type used by the native accessors to the type used
+     * by reflection accessors.  E.g., for enums, the reflection accessors use
+     * EnumValueDescriptors but the native accessors use the generated enum
+     * type.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Object toReflectionType(final Object value) {
+      FieldDescriptor descriptor = getDescriptor();
+      if (descriptor.isRepeated()) {
+        if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+          // Must convert the whole list.
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularToReflectionType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularToReflectionType(value);
+      }
+    }
+
+    /**
+     * Like {@link #toReflectionType(Object)}, but if the type is a repeated
+     * type, this converts a single element.
+     */
+    @Override
+    protected Object singularToReflectionType(final Object value) {
+      FieldDescriptor descriptor = getDescriptor();
+      switch (descriptor.getJavaType()) {
+        case ENUM:
+          return invokeOrDie(enumGetValueDescriptor, value);
+        default:
+          return value;
+      }
+    }
+
+    @Override
+    public int getNumber() {
+      return getDescriptor().getNumber();
+    }
+
+    @Override
+    public WireFormat.FieldType getLiteType() {
+      return getDescriptor().getLiteType();
+    }
+
+    @Override
+    public boolean isRepeated() {
+      return getDescriptor().isRepeated();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Type getDefaultValue() {
+      if (isRepeated()) {
+        return (Type) Collections.emptyList();
+      }
+      if (getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        return (Type) messageDefaultInstance;
+      }
+      return (Type) singularFromReflectionType(
+          getDescriptor().getDefaultValue());
+    }
+  }
+
+  // =================================================================
+
+  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+  @SuppressWarnings("unchecked")
+  private static Method getMethodOrDie(
+      final Class clazz, final String name, final Class... params) {
+    try {
+      return clazz.getMethod(name, params);
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(
+        "Generated message class \"" + clazz.getName() +
+        "\" missing method \"" + name + "\".", e);
+    }
+  }
+
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  private static Object invokeOrDie(
+      final Method method, final Object object, final Object... params) {
+    try {
+      return method.invoke(object, params);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(
+        "Couldn't use Java reflection to implement protocol message " +
+        "reflection.", e);
+    } catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof RuntimeException) {
+        throw (RuntimeException) cause;
+      } else if (cause instanceof Error) {
+        throw (Error) cause;
+      } else {
+        throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", cause);
+      }
+    }
+  }
+
+  /**
+   * Gets the map field with the given field number. This method should be
+   * overridden in the generated message class if the message contains map
+   * fields.
+   *
+   * Unlike other field types, reflection support for map fields can't be
+   * implemented based on generated public API because we need to access a
+   * map field as a list in reflection API but the generated API only allows
+   * us to access it as a map. This method returns the underlying map field
+   * directly and thus enables us to access the map field as a list.
+   */
+  @SuppressWarnings({"rawtypes", "unused"})
+  protected MapField internalGetMapField(int fieldNumber) {
+    // Note that we can't use descriptor names here because this method will
+    // be called when descriptor is being initialized.
+    throw new RuntimeException(
+        "No map fields found in " + getClass().getName());
+  }
+
+  /**
+   * Users should ignore this class.  This class provides the implementation
+   * with access to the fields of a message object using Java reflection.
+   */
+  public static final class FieldAccessorTable {
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class.  Only
+     * one FieldAccessorTable should ever be constructed per class.
+     *
+     * @param descriptor     The type's descriptor.
+     * @param camelCaseNames The camelcase names of all fields in the message.
+     *                       These are used to derive the accessor method names.
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames,
+        final Class<? extends GeneratedMessage> messageClass,
+        final Class<? extends Builder> builderClass) {
+      this(descriptor, camelCaseNames);
+      ensureFieldAccessorsInitialized(messageClass, builderClass);
+    }
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class without
+     * initializing FieldAccessors.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames) {
+      this.descriptor = descriptor;
+      this.camelCaseNames = camelCaseNames;
+      fields = new FieldAccessor[descriptor.getFields().size()];
+      oneofs = new OneofAccessor[descriptor.getOneofs().size()];
+      initialized = false;
+    }
+
+    private boolean isMapFieldEnabled(FieldDescriptor field) {
+      boolean result = true;
+      return result;
+    }
+
+    /**
+     * Ensures the field accessors are initialized. This method is thread-safe.
+     *
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     * @return this
+     */
+    public FieldAccessorTable ensureFieldAccessorsInitialized(
+        Class<? extends GeneratedMessage> messageClass,
+        Class<? extends Builder> builderClass) {
+      if (initialized) { return this; }
+      synchronized (this) {
+        if (initialized) { return this; }
+        int fieldsSize = fields.length;
+        for (int i = 0; i < fieldsSize; i++) {
+          FieldDescriptor field = descriptor.getFields().get(i);
+          String containingOneofCamelCaseName = null;
+          if (field.getContainingOneof() != null) {
+            containingOneofCamelCaseName =
+                camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
+          }
+          if (field.isRepeated()) {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              if (field.isMapField() && isMapFieldEnabled(field)) {
+                fields[i] = new MapFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              } else {
+                fields[i] = new RepeatedMessageFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              }
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new RepeatedEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            } else {
+              fields[i] = new RepeatedFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            }
+          } else {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              fields[i] = new SingularMessageFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new SingularEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+              fields[i] = new SingularStringFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else {
+              fields[i] = new SingularFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            }
+          }
+        }
+
+        int oneofsSize = oneofs.length;
+        for (int i = 0; i < oneofsSize; i++) {
+          oneofs[i] = new OneofAccessor(
+              descriptor, camelCaseNames[i + fieldsSize],
+              messageClass, builderClass);
+        }
+        initialized = true;
+        camelCaseNames = null;
+        return this;
+      }
+    }
+
+    private final Descriptor descriptor;
+    private final FieldAccessor[] fields;
+    private String[] camelCaseNames;
+    private final OneofAccessor[] oneofs;
+    private volatile boolean initialized;
+
+    /** Get the FieldAccessor for a particular field. */
+    private FieldAccessor getField(final FieldDescriptor field) {
+      if (field.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      } else if (field.isExtension()) {
+        // If this type had extensions, it would subclass ExtendableMessage,
+        // which overrides the reflection interface to handle extensions.
+        throw new IllegalArgumentException(
+          "This type does not have extensions.");
+      }
+      return fields[field.getIndex()];
+    }
+
+    /** Get the OneofAccessor for a particular oneof. */
+    private OneofAccessor getOneof(final OneofDescriptor oneof) {
+      if (oneof.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+      return oneofs[oneof.getIndex()];
+    }
+
+    /**
+     * Abstract interface that provides access to a single field.  This is
+     * implemented differently depending on the field type and cardinality.
+     */
+    private interface FieldAccessor {
+      Object get(GeneratedMessage message);
+      Object get(GeneratedMessage.Builder builder);
+      Object getRaw(GeneratedMessage message);
+      Object getRaw(GeneratedMessage.Builder builder);
+      void set(Builder builder, Object value);
+      Object getRepeated(GeneratedMessage message, int index);
+      Object getRepeated(GeneratedMessage.Builder builder, int index);
+      Object getRepeatedRaw(GeneratedMessage message, int index);
+      Object getRepeatedRaw(GeneratedMessage.Builder builder, int index);
+      void setRepeated(Builder builder,
+                       int index, Object value);
+      void addRepeated(Builder builder, Object value);
+      boolean has(GeneratedMessage message);
+      boolean has(GeneratedMessage.Builder builder);
+      int getRepeatedCount(GeneratedMessage message);
+      int getRepeatedCount(GeneratedMessage.Builder builder);
+      void clear(Builder builder);
+      Message.Builder newBuilder();
+      Message.Builder getBuilder(GeneratedMessage.Builder builder);
+      Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder,
+                                         int index);
+    }
+
+    /** OneofAccessor provides access to a single oneof. */
+    private static class OneofAccessor {
+      OneofAccessor(
+          final Descriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        this.descriptor = descriptor;
+        caseMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
+        caseMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      private final Descriptor descriptor;
+      private final Method caseMethod;
+      private final Method caseMethodBuilder;
+      private final Method clearMethod;
+
+      public boolean has(final GeneratedMessage message) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public boolean has(GeneratedMessage.Builder builder) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public FieldDescriptor get(final GeneratedMessage message) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public FieldDescriptor get(GeneratedMessage.Builder builder) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+    }
+
+    private static boolean supportFieldPresence(FileDescriptor file) {
+      return file.getSyntax() == FileDescriptor.Syntax.PROTO2;
+    }
+
+    // ---------------------------------------------------------------
+
+    private static class SingularFieldAccessor implements FieldAccessor {
+      SingularFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        field = descriptor;
+        isOneofField = descriptor.getContainingOneof() != null;
+        hasHasMethod = supportFieldPresence(descriptor.getFile())
+            || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
+        getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+        getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
+        type = getMethod.getReturnType();
+        setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+        hasMethod =
+            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
+        hasMethodBuilder =
+            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+        caseMethod = isOneofField ? getMethodOrDie(
+            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
+        caseMethodBuilder = isOneofField ? getMethodOrDie(
+            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
+      }
+
+      // Note:  We use Java reflection to call public methods rather than
+      //   access private fields directly as this avoids runtime security
+      //   checks.
+      protected final Class<?> type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method setMethod;
+      protected final Method hasMethod;
+      protected final Method hasMethodBuilder;
+      protected final Method clearMethod;
+      protected final Method caseMethod;
+      protected final Method caseMethodBuilder;
+      protected final FieldDescriptor field;
+      protected final boolean isOneofField;
+      protected final boolean hasHasMethod;
+
+      private int getOneofFieldNumber(final GeneratedMessage message) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+      }
+
+      private int getOneofFieldNumber(final GeneratedMessage.Builder builder) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+      }
+
+      @Override
+      public Object get(final GeneratedMessage message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        invokeOrDie(setMethod, builder, value);
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessage message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(final GeneratedMessage message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        throw new UnsupportedOperationException(
+          "setRepeatedField() called on a singular field.");
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        throw new UnsupportedOperationException(
+          "addRepeatedField() called on a singular field.");
+      }
+      @Override
+      public boolean has(final GeneratedMessage message) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(message) == field.getNumber();
+          }
+          return !get(message).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethod, message);
+      }
+      @Override
+      public boolean has(GeneratedMessage.Builder builder) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(builder) == field.getNumber();
+          }
+          return !get(builder).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethodBuilder, builder);
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessage message) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessage.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class RepeatedFieldAccessor implements FieldAccessor {
+      protected final Class type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method getRepeatedMethod;
+      protected final Method getRepeatedMethodBuilder;
+      protected final Method setRepeatedMethod;
+      protected final Method addRepeatedMethod;
+      protected final Method getCountMethod;
+      protected final Method getCountMethodBuilder;
+      protected final Method clearMethod;
+
+      RepeatedFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        getMethod = getMethodOrDie(messageClass,
+                                   "get" + camelCaseName + "List");
+        getMethodBuilder = getMethodOrDie(builderClass,
+                                   "get" + camelCaseName + "List");
+        getRepeatedMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+        getRepeatedMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
+        type = getRepeatedMethod.getReturnType();
+        setRepeatedMethod =
+            getMethodOrDie(builderClass, "set" + camelCaseName,
+                           Integer.TYPE, type);
+        addRepeatedMethod =
+            getMethodOrDie(builderClass, "add" + camelCaseName, type);
+        getCountMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+        getCountMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
+
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      @Override
+      public Object get(final GeneratedMessage message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        // Add all the elements individually.  This serves two purposes:
+        // 1) Verifies that each element has the correct type.
+        // 2) Insures that the caller cannot modify the list later on and
+        //    have the modifications be reflected in the message.
+        clear(builder);
+        for (final Object element : (List<?>) value) {
+          addRepeated(builder, element);
+        }
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessage message, final int index) {
+        return invokeOrDie(getRepeatedMethod, message, index);
+      }
+      @Override
+      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
+        return invokeOrDie(getRepeatedMethodBuilder, builder, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        invokeOrDie(setRepeatedMethod, builder, index, value);
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        invokeOrDie(addRepeatedMethod, builder, value);
+      }
+      @Override
+      public boolean has(final GeneratedMessage message) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public boolean has(GeneratedMessage.Builder builder) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessage message) {
+        return (Integer) invokeOrDie(getCountMethod, message);
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessage.Builder builder) {
+        return (Integer) invokeOrDie(getCountMethodBuilder, builder);
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class MapFieldAccessor implements FieldAccessor {
+      MapFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        field = descriptor;
+        Method getDefaultInstanceMethod =
+            getMethodOrDie(messageClass, "getDefaultInstance");
+        MapField defaultMapField = getMapField(
+            (GeneratedMessage) invokeOrDie(getDefaultInstanceMethod, null));
+        mapEntryMessageDefaultInstance =
+            defaultMapField.getMapEntryMessageDefaultInstance();
+      }
+
+      private final FieldDescriptor field;
+      private final Message mapEntryMessageDefaultInstance;
+
+      private MapField<?, ?> getMapField(GeneratedMessage message) {
+        return (MapField<?, ?>) message.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMapField(GeneratedMessage.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMutableMapField(
+          GeneratedMessage.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMutableMapField(
+            field.getNumber());
+      }
+
+      @Override
+      public Object get(GeneratedMessage message) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(message); i++) {
+          result.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      public Object get(Builder builder) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(builder); i++) {
+          result.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessage message) {
+        return get(message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
+
+      @Override
+      public void set(Builder builder, Object value) {
+        clear(builder);
+        for (Object entry : (List) value) {
+          addRepeated(builder, entry);
+        }
+      }
+
+      @Override
+      public Object getRepeated(GeneratedMessage message, int index) {
+        return getMapField(message).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeated(Builder builder, int index) {
+        return getMapField(builder).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+
+      @Override
+      public void setRepeated(Builder builder, int index, Object value) {
+        getMutableMapField(builder).getMutableList().set(index, (Message) value);
+      }
+
+      @Override
+      public void addRepeated(Builder builder, Object value) {
+        getMutableMapField(builder).getMutableList().add((Message) value);
+      }
+
+      @Override
+      public boolean has(GeneratedMessage message) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public boolean has(Builder builder) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public int getRepeatedCount(GeneratedMessage message) {
+        return getMapField(message).getList().size();
+      }
+
+      @Override
+      public int getRepeatedCount(Builder builder) {
+        return getMapField(builder).getList().size();
+      }
+
+      @Override
+      public void clear(Builder builder) {
+        getMutableMapField(builder).getMutableList().clear();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder newBuilder() {
+        return mapEntryMessageDefaultInstance.newBuilderForType();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularEnumFieldAccessor
+        extends SingularFieldAccessor {
+      SingularEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
+          getValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
+          setValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class);
+        }
+      }
+
+      private EnumDescriptor enumDescriptor;
+
+      private Method valueOfMethod;
+      private Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getValueMethod;
+      private Method getValueMethodBuilder;
+      private Method setValueMethod;
+
+      @Override
+      public Object get(final GeneratedMessage message) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethod, message);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(message));
+      }
+
+      @Override
+      public Object get(final GeneratedMessage.Builder builder) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethodBuilder, builder);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(builder));
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.set(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    private static final class RepeatedEnumFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getRepeatedValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
+          getRepeatedValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value", int.class);
+          setRepeatedValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class, int.class);
+          addRepeatedValueMethod =
+              getMethodOrDie(builderClass, "add" + camelCaseName + "Value", int.class);
+        }
+      }
+      private EnumDescriptor enumDescriptor;
+
+      private final Method valueOfMethod;
+      private final Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getRepeatedValueMethod;
+      private Method getRepeatedValueMethodBuilder;
+      private Method setRepeatedValueMethod;
+      private Method addRepeatedValueMethod;
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessage message) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(message);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessage.Builder builder) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(builder);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      public Object getRepeated(final GeneratedMessage message,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(message, index));
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessage.Builder builder,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(builder, index));
+      }
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setRepeatedValueMethod, builder, index,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
+                          value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(addRepeatedValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    /**
+     * Field accessor for string fields.
+     *
+     * <p>This class makes getFooBytes() and setFooBytes() available for
+     * reflection API so that reflection based serialize/parse functions can
+     * access the raw bytes of the field to preserve non-UTF8 bytes in the
+     * string.
+     *
+     * <p>This ensures the serialize/parse round-trip safety, which is important
+     * for servers which forward messages.
+     */
+    private static final class SingularStringFieldAccessor
+        extends SingularFieldAccessor {
+      SingularStringFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+        getBytesMethod = getMethodOrDie(messageClass,
+            "get" + camelCaseName + "Bytes");
+        getBytesMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Bytes");
+        setBytesMethodBuilder = getMethodOrDie(builderClass,
+            "set" + camelCaseName + "Bytes", ByteString.class);
+      }
+
+      private final Method getBytesMethod;
+      private final Method getBytesMethodBuilder;
+      private final Method setBytesMethodBuilder;
+
+      @Override
+      public Object getRaw(final GeneratedMessage message) {
+        return invokeOrDie(getBytesMethod, message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getBytesMethodBuilder, builder);
+      }
+
+      @Override
+      public void set(GeneratedMessage.Builder builder, Object value) {
+        if (value instanceof ByteString) {
+          invokeOrDie(setBytesMethodBuilder, builder, value);
+        } else {
+          super.set(builder, value);
+        }
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularMessageFieldAccessor
+        extends SingularFieldAccessor {
+      SingularMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).buildPartial();
+        }
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        super.set(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
+        return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
+      }
+    }
+
+    private static final class RepeatedMessageFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Builder", Integer.TYPE);
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).build();
+        }
+      }
+
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        super.setRepeated(builder, index, coerceType(value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        super.addRepeated(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(
+          final GeneratedMessage.Builder builder, final int index) {
+        return (Message.Builder) invokeOrDie(
+            getBuilderMethodBuilder, builder, index);
+      }
+    }
+  }
+
+  /**
+   * Replaces this object in the output stream with a serialized form.
+   * Part of Java's serialization magic.  Generated sub-classes must override
+   * this method by calling {@code return super.writeReplace();}
+   * @return a SerializedForm of this message
+   */
+  protected Object writeReplace() throws ObjectStreamException {
+    return new GeneratedMessageLite.SerializedForm(this);
+  }
+
+  /**
+   * Checks that the {@link Extension} is non-Lite and returns it as a
+   * {@link GeneratedExtension}.
+   */
+  private static <MessageType extends ExtendableMessage<MessageType>, T>
+    Extension<MessageType, T> checkNotLite(
+        ExtensionLite<MessageType, T> extension) {
+    if (extension.isLite()) {
+      throw new IllegalArgumentException("Expected non-lite extension.");
+    }
+
+    return (Extension<MessageType, T>) extension;
+  }
+  
+  protected static int computeStringSize(final int fieldNumber, final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
+    } else {
+      return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
+    }
+  }
+  
+  protected static int computeStringSizeNoTag(final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSizeNoTag((String) value);
+    } else {
+      return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+    }
+  }
+  
+  protected static void writeString(
+      CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeString(fieldNumber, (String) value);
+    } else {
+      output.writeBytes(fieldNumber, (ByteString) value);
+    }
+  }
+  
+  protected static void writeStringNoTag(
+      CodedOutputStream output, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeStringNoTag((String) value);
+    } else {
+      output.writeBytesNoTag((ByteString) value);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
new file mode 100644
index 0000000..c5adc5a
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -0,0 +1,2242 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
+import com.google.protobuf.GeneratedMessageLite.EqualsVisitor.NotEqualsException;
+import com.google.protobuf.Internal.BooleanList;
+import com.google.protobuf.Internal.DoubleList;
+import com.google.protobuf.Internal.FloatList;
+import com.google.protobuf.Internal.IntList;
+import com.google.protobuf.Internal.LongList;
+import com.google.protobuf.Internal.ProtobufList;
+import com.google.protobuf.WireFormat.FieldType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Lite version of {@link GeneratedMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessageLite<
+    MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
+        extends AbstractMessageLite<MessageType, BuilderType> {
+
+  /** For use by generated code only. Lazily initialized to reduce allocations. */
+  protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
+  
+  /** For use by generated code only.  */
+  protected int memoizedSerializedSize = -1;
+  
+  @Override
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final Parser<MessageType> getParserForType() {
+    return (Parser<MessageType>) dynamicMethod(MethodToInvoke.GET_PARSER);
+  }
+
+  @Override
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final MessageType getDefaultInstanceForType() {
+    return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE);
+  }
+
+  @Override
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final BuilderType newBuilderForType() {
+    return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+  }
+
+  /**
+   * A reflective toString function. This is primarily intended as a developer aid, while keeping
+   * binary size down. The first line of the {@code toString()} representation includes a commented
+   * version of {@code super.toString()} to act as an indicator that this should not be relied on
+   * for comparisons.
+   * <p>
+   * NOTE: This method relies on the field getter methods not being stripped or renamed by proguard.
+   * If they are, the fields will not be included in the returned string representation.
+   * <p>
+   * NOTE: This implementation is liable to change in the future, and should not be relied on in
+   * code.
+   */
+  @Override
+  public String toString() {
+    return MessageLiteToString.toString(this, super.toString());
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime
+  @Override
+  public int hashCode() {
+    if (memoizedHashCode == 0) {
+      HashCodeVisitor visitor = new HashCodeVisitor();
+      visit(visitor, (MessageType) this);
+      memoizedHashCode = visitor.hashCode;
+    }
+    return memoizedHashCode;
+  }
+  
+  @SuppressWarnings("unchecked") // Guaranteed by runtime
+  int hashCode(HashCodeVisitor visitor) {
+    if (memoizedHashCode == 0) {
+      int inProgressHashCode = visitor.hashCode;
+      visitor.hashCode = 0;
+      visit(visitor, (MessageType) this);
+      memoizedHashCode = visitor.hashCode;
+      visitor.hashCode = inProgressHashCode;
+    }
+    return memoizedHashCode;
+  }
+  
+  @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+  @Override
+  public boolean equals(Object other) {
+    if (this == other) {
+      return true;
+    }
+    
+    if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+      return false;
+    }
+    
+    try {
+      visit(EqualsVisitor.INSTANCE, (MessageType) other);
+    } catch (NotEqualsException e) {
+      return false;
+    }
+    return true;
+  }
+  
+  /**
+   * Same as {@link #equals(Object)} but throws {@code NotEqualsException}.
+   */
+  @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
+  boolean equals(EqualsVisitor visitor, MessageLite other) {
+    if (this == other) {
+      return true;
+    }
+    
+    if (!getDefaultInstanceForType().getClass().isInstance(other)) {
+      return false;
+    }
+
+    visit(visitor, (MessageType) other);
+    return true;
+  }
+  
+  // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
+  // mutable during the parsing constructor and immutable after. This allows us to avoid
+  // any unnecessary intermediary allocations while reducing the generated code size.
+
+  /**
+   * Lazily initializes unknown fields.
+   */
+  private final void ensureUnknownFieldsInitialized() {
+    if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
+      unknownFields = UnknownFieldSetLite.newInstance();
+    }
+  }
+  
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   * 
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
+    // This will avoid the allocation of unknown fields when a group tag is encountered.
+    if (WireFormat.getTagWireType(tag) == WireFormat.WIRETYPE_END_GROUP) {
+      return false;
+    }
+    
+    ensureUnknownFieldsInitialized();
+    return unknownFields.mergeFieldFrom(tag, input);
+  }
+
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   */
+  protected void mergeVarintField(int tag, int value) {
+    ensureUnknownFieldsInitialized();
+    unknownFields.mergeVarintField(tag, value);
+  }
+  
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   */
+  protected void mergeLengthDelimitedField(int fieldNumber, ByteString value) {
+    ensureUnknownFieldsInitialized();
+    unknownFields.mergeLengthDelimitedField(fieldNumber, value);
+  }
+  
+  /**
+   * Called by subclasses to complete parsing. For use by generated code only.
+   */
+  protected void makeImmutable() {
+    dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+
+    unknownFields.makeImmutable();
+  }
+
+  @Override
+  public final boolean isInitialized() {
+    return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
+  }
+
+  @Override
+  public final BuilderType toBuilder() {
+    BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+    builder.mergeFrom((MessageType) this);
+    return builder;
+  }
+
+  /**
+   * Defines which method path to invoke in {@link GeneratedMessageLite
+   * #dynamicMethod(MethodToInvoke, Object...)}.
+   * <p>
+   * For use by generated code only.
+   */
+  public static enum MethodToInvoke {
+    // Rely on/modify instance state
+    IS_INITIALIZED,
+    VISIT,
+    MERGE_FROM_STREAM,
+    MAKE_IMMUTABLE,
+
+    // Rely on static state
+    NEW_MUTABLE_INSTANCE,
+    NEW_BUILDER,
+    GET_DEFAULT_INSTANCE,
+    GET_PARSER;
+  }
+
+  /**
+   * A method that implements different types of operations described in {@link MethodToInvoke}.
+   * Theses different kinds of operations are required to implement message-level operations for
+   * builders in the runtime. This method bundles those operations to reduce the generated methods
+   * count.
+   * <ul>
+   * <li>{@code MERGE_FROM_STREAM} is parameterized with an {@link CodedInputStream} and
+   * {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the
+   * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the
+   * implementation wraps it in a RuntimeException.
+   * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer that has not yet been
+   * made immutable. See {@code MAKE_IMMUTABLE}.
+   * <li>{@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to
+   * memoize. It returns {@code null} for false and the default instance for true. We optionally
+   * memoize to support the Builder case, where memoization is not desired.
+   * <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance.
+   * <li>{@code VISIT} is parameterized with a {@code Visitor} and a {@code MessageType} and
+   * recursively iterates through the fields side by side between this and the instance.
+   * <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state.
+   * </ul>
+   * This method, plus the implementation of the Builder, enables the Builder class to be proguarded
+   * away entirely on Android.
+   * <p>
+   * For use by generated code only.
+   */
+  protected abstract Object dynamicMethod(MethodToInvoke method, Object arg0, Object arg1);
+
+  /**
+   * Same as {@link #dynamicMethod(MethodToInvoke, Object, Object)} with {@code null} padding.
+   */
+  protected Object dynamicMethod(MethodToInvoke method, Object arg0) {
+    return dynamicMethod(method, arg0, null);
+  }
+
+  /**
+   * Same as {@link #dynamicMethod(MethodToInvoke, Object, Object)} with {@code null} padding.
+   */
+  protected Object dynamicMethod(MethodToInvoke method) {
+    return dynamicMethod(method, null, null);
+  }
+
+  void visit(Visitor visitor, MessageType other) {
+    dynamicMethod(MethodToInvoke.VISIT, visitor, other);
+    unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
+  }
+  
+  /**
+   * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
+   * message.
+   *
+   * <p>For use by generated code only.
+   */
+  protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) {
+    this.unknownFields = UnknownFieldSetLite.mutableCopyOf(this.unknownFields, unknownFields);
+  }
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder<
+      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+      BuilderType extends Builder<MessageType, BuilderType>>
+          extends AbstractMessageLite.Builder<MessageType, BuilderType> {
+
+    private final MessageType defaultInstance;
+    protected MessageType instance;
+    protected boolean isBuilt;
+
+    protected Builder(MessageType defaultInstance) {
+      this.defaultInstance = defaultInstance;
+      this.instance =
+          (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+      isBuilt = false;
+    }
+
+    /**
+     * Called before any method that would mutate the builder to ensure that it correctly copies
+     * any state before the write happens to preserve immutability guarantees.
+     */
+    protected void copyOnWrite() {
+      if (isBuilt) {
+        MessageType newInstance =
+            (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+        newInstance.visit(MergeFromVisitor.INSTANCE, instance);
+        instance = newInstance;
+        isBuilt = false;
+      }
+    }
+
+    @Override
+    public final boolean isInitialized() {
+      return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */);
+    }
+
+    @Override
+    public final BuilderType clear() {
+      // No need to copy on write since we're dropping the instance anyways.
+      instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clone() {
+      BuilderType builder =
+          (BuilderType) getDefaultInstanceForType().newBuilderForType();
+      builder.mergeFrom(buildPartial());
+      return builder;
+    }
+
+    @Override
+    public MessageType buildPartial() {
+      if (isBuilt) {
+        return instance;
+      }
+      
+      instance.makeImmutable();
+      
+      isBuilt = true;
+      return instance;
+    }
+
+    @Override
+    public final MessageType build() {
+      MessageType result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+    
+    @Override
+    protected BuilderType internalMergeFrom(MessageType message) {
+      return mergeFrom(message);
+    }
+    
+    /** All subclasses implement this. */
+    public BuilderType mergeFrom(MessageType message) {
+      copyOnWrite();
+      instance.visit(MergeFromVisitor.INSTANCE, message);
+      return (BuilderType) this;
+    }
+    
+    @Override
+    public MessageType getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+    
+    @Override
+    public BuilderType mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      copyOnWrite();
+      try {
+        instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+      } catch (RuntimeException e) {
+        if (e.getCause() instanceof IOException) {
+          throw (IOException) e.getCause();
+        }
+        throw e;
+      }
+      return (BuilderType) this;
+    }
+  }
+
+
+  // =================================================================
+  // Extensions-related stuff
+
+  /**
+   * Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
+   */
+  public interface ExtendableMessageOrBuilder<
+      MessageType extends ExtendableMessage<MessageType, BuilderType>,
+      BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+          extends MessageLiteOrBuilder {
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        ExtensionLite<MessageType, List<Type>> extension);
+
+    /** Get the value of an extension. */
+    <Type> Type getExtension(ExtensionLite<MessageType, Type> extension);
+
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, List<Type>> extension,
+        int index);
+  }
+
+  /**
+   * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
+   */
+  public abstract static class ExtendableMessage<
+        MessageType extends ExtendableMessage<MessageType, BuilderType>,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+            extends GeneratedMessageLite<MessageType, BuilderType>
+            implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
+
+    /**
+     * Represents the set of extensions on this message. For use by generated
+     * code only.
+     */
+    protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
+
+    protected final void mergeExtensionFields(final MessageType other) {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+      extensions.mergeFrom(((ExtendableMessage) other).extensions);
+    }
+
+    @Override
+    final void visit(Visitor visitor, MessageType other) {
+      super.visit(visitor, other);
+      extensions = visitor.visitExtensions(extensions, other.extensions);
+    }
+    
+    /**
+     * Parse an unknown field or an extension. For use by generated code only.
+     * 
+     * <p>For use by generated code only.
+     * 
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected <MessageType extends MessageLite> boolean parseUnknownField(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      int wireType = WireFormat.getTagWireType(tag);
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+      // TODO(dweis): How much bytecode would be saved by not requiring the generated code to
+      //     provide the default instance?
+      GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(
+          defaultInstance, fieldNumber);
+
+      boolean unknown = false;
+      boolean packed = false;
+      if (extension == null) {
+        unknown = true;  // Unknown field.
+      } else if (wireType == FieldSet.getWireFormatForFieldType(
+                   extension.descriptor.getLiteType(),
+                   false  /* isPacked */)) {
+        packed = false;  // Normal, unpacked value.
+      } else if (extension.descriptor.isRepeated &&
+                 extension.descriptor.type.isPackable() &&
+                 wireType == FieldSet.getWireFormatForFieldType(
+                   extension.descriptor.getLiteType(),
+                   true  /* isPacked */)) {
+        packed = true;  // Packed value.
+      } else {
+        unknown = true;  // Wrong wire type.
+      }
+
+      if (unknown) {  // Unknown field or wrong wire type.  Skip.
+        return parseUnknownField(tag, input);
+      }
+
+      if (packed) {
+        int length = input.readRawVarint32();
+        int limit = input.pushLimit(length);
+        if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+          while (input.getBytesUntilLimit() > 0) {
+            int rawValue = input.readEnum();
+            Object value =
+                extension.descriptor.getEnumType().findValueByNumber(rawValue);
+            if (value == null) {
+              // If the number isn't recognized as a valid value for this
+              // enum, drop it (don't even add it to unknownFields).
+              return true;
+            }
+            extensions.addRepeatedField(extension.descriptor,
+                                        extension.singularToFieldSetType(value));
+          }
+        } else {
+          while (input.getBytesUntilLimit() > 0) {
+            Object value =
+                FieldSet.readPrimitiveField(input,
+                                            extension.descriptor.getLiteType(),
+                                            /*checkUtf8=*/ false);
+            extensions.addRepeatedField(extension.descriptor, value);
+          }
+        }
+        input.popLimit(limit);
+      } else {
+        Object value;
+        switch (extension.descriptor.getLiteJavaType()) {
+          case MESSAGE: {
+            MessageLite.Builder subBuilder = null;
+            if (!extension.descriptor.isRepeated()) {
+              MessageLite existingValue =
+                  (MessageLite) extensions.getField(extension.descriptor);
+              if (existingValue != null) {
+                subBuilder = existingValue.toBuilder();
+              }
+            }
+            if (subBuilder == null) {
+              subBuilder = extension.getMessageDefaultInstance()
+                  .newBuilderForType();
+            }
+            if (extension.descriptor.getLiteType() ==
+                WireFormat.FieldType.GROUP) {
+              input.readGroup(extension.getNumber(),
+                              subBuilder, extensionRegistry);
+            } else {
+              input.readMessage(subBuilder, extensionRegistry);
+            }
+            value = subBuilder.build();
+            break;
+          }
+          case ENUM:
+            int rawValue = input.readEnum();
+            value = extension.descriptor.getEnumType()
+                             .findValueByNumber(rawValue);
+            // If the number isn't recognized as a valid value for this enum,
+            // write it to unknown fields object.
+            if (value == null) {
+              mergeVarintField(fieldNumber, rawValue);
+              return true;
+            }
+            break;
+          default:
+            value = FieldSet.readPrimitiveField(input,
+                extension.descriptor.getLiteType(),
+                /*checkUtf8=*/ false);
+            break;
+        }
+
+        if (extension.descriptor.isRepeated()) {
+          extensions.addRepeatedField(extension.descriptor,
+                                      extension.singularToFieldSetType(value));
+        } else {
+          extensions.setField(extension.descriptor,
+                              extension.singularToFieldSetType(value));
+        }
+      }
+
+      return true;
+    }
+    
+    private void verifyExtensionContainingType(
+        final GeneratedExtension<MessageType, ?> extension) {
+      if (extension.getContainingTypeDefaultInstance() !=
+          getDefaultInstanceForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "This extension is for a different message type.  Please make " +
+          "sure that you are not suppressing any generics type warnings.");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
+      GeneratedExtension<MessageType, Type> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      return extensions.hasField(extensionLite.descriptor);
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extension) {
+      GeneratedExtension<MessageType, List<Type>> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      return extensions.getRepeatedFieldCount(extensionLite.descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
+      GeneratedExtension<MessageType, Type> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      final Object value = extensions.getField(extensionLite.descriptor);
+      if (value == null) {
+        return extensionLite.defaultValue;
+      } else {
+        return (Type) extensionLite.fromFieldSetType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extension, final int index) {
+      GeneratedExtension<MessageType, List<Type>> extensionLite =
+          checkIsLite(extension);
+
+      verifyExtensionContainingType(extensionLite);
+      return (Type) extensionLite.singularFromFieldSetType(
+          extensions.getRepeatedField(extensionLite.descriptor, index));
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    @Override
+    protected final void makeImmutable() {
+      super.makeImmutable();
+      
+      extensions.makeImmutable();
+    }
+
+    /**
+     * Used by subclasses to serialize extensions.  Extension ranges may be
+     * interleaved with field numbers, but we must write them in canonical
+     * (sorted by field number) order.  ExtensionWriter helps us write
+     * individual ranges of extensions at once.
+     */
+    protected class ExtensionWriter {
+      // Imagine how much simpler this code would be if Java iterators had
+      // a way to get the next element without advancing the iterator.
+
+      private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
+            extensions.iterator();
+      private Map.Entry<ExtensionDescriptor, Object> next;
+      private final boolean messageSetWireFormat;
+
+      private ExtensionWriter(boolean messageSetWireFormat) {
+        if (iter.hasNext()) {
+          next = iter.next();
+        }
+        this.messageSetWireFormat = messageSetWireFormat;
+      }
+
+      public void writeUntil(final int end, final CodedOutputStream output)
+                             throws IOException {
+        while (next != null && next.getKey().getNumber() < end) {
+          ExtensionDescriptor extension = next.getKey();
+          if (messageSetWireFormat && extension.getLiteJavaType() ==
+                  WireFormat.JavaType.MESSAGE &&
+              !extension.isRepeated()) {
+            output.writeMessageSetExtension(extension.getNumber(),
+                                            (MessageLite) next.getValue());
+          } else {
+            FieldSet.writeField(extension, next.getValue(), output);
+          }
+          if (iter.hasNext()) {
+            next = iter.next();
+          } else {
+            next = null;
+          }
+        }
+      }
+    }
+
+    protected ExtensionWriter newExtensionWriter() {
+      return new ExtensionWriter(false);
+    }
+    protected ExtensionWriter newMessageSetExtensionWriter() {
+      return new ExtensionWriter(true);
+    }
+
+    /** Called by subclasses to compute the size of extensions. */
+    protected int extensionsSerializedSize() {
+      return extensions.getSerializedSize();
+    }
+    protected int extensionsSerializedSizeAsMessageSet() {
+      return extensions.getMessageSetSerializedSize();
+    }
+  }
+
+  /**
+   * Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class ExtendableBuilder<
+        MessageType extends ExtendableMessage<MessageType, BuilderType>,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+      extends Builder<MessageType, BuilderType>
+      implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
+    protected ExtendableBuilder(MessageType defaultInstance) {
+      super(defaultInstance);
+      
+      // TODO(dweis): This is kind of an unnecessary clone since we construct a
+      //     new instance in the parent constructor which makes the extensions
+      //     immutable. This extra allocation shouldn't matter in practice
+      //     though.
+      instance.extensions = instance.extensions.clone();
+    }
+
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
+      copyOnWrite();
+      instance.extensions = extensions;
+    }
+
+    @Override
+    protected void copyOnWrite() {
+      if (!isBuilt) {
+        return;
+      }
+      
+      super.copyOnWrite();
+      instance.extensions = instance.extensions.clone();
+    }
+
+    @Override
+    public final MessageType buildPartial() {
+      if (isBuilt) {
+        return instance;
+      }
+
+      instance.extensions.makeImmutable();
+      return super.buildPartial();
+    }
+
+    private void verifyExtensionContainingType(
+        final GeneratedExtension<MessageType, ?> extension) {
+      if (extension.getContainingTypeDefaultInstance() !=
+          getDefaultInstanceForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "This extension is for a different message type.  Please make " +
+          "sure that you are not suppressing any generics type warnings.");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
+      return instance.hasExtension(extension);
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extension) {
+      return instance.getExtensionCount(extension);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
+      return instance.getExtension(extension);
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extension, final int index) {
+      return instance.getExtension(extension, index);
+    }
+
+    // This is implemented here only to work around an apparent bug in the
+    // Java compiler and/or build system.  See bug #1898463.  The mere presence
+    // of this dummy clone() implementation makes it go away.
+    @Override
+    public BuilderType clone() {
+      return super.clone();
+    }
+    
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, Type> extension,
+        final Type value) {
+      GeneratedExtension<MessageType, Type> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      copyOnWrite();
+      instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
+      return (BuilderType) this;
+    }
+
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      GeneratedExtension<MessageType, List<Type>> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      copyOnWrite();
+      instance.extensions.setRepeatedField(
+          extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
+      return (BuilderType) this;
+    }
+
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final ExtensionLite<MessageType, List<Type>> extension,
+        final Type value) {
+      GeneratedExtension<MessageType, List<Type>> extensionLite =
+          checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      copyOnWrite();
+      instance.extensions.addRepeatedField(
+          extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
+      return (BuilderType) this;
+    }
+
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final ExtensionLite<MessageType, ?> extension) {
+      GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
+      
+      verifyExtensionContainingType(extensionLite);
+      copyOnWrite();
+      instance.extensions.clearField(extensionLite.descriptor);
+      return (BuilderType) this;
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /** For use by generated code only. */
+  public static <ContainingType extends MessageLite, Type>
+      GeneratedExtension<ContainingType, Type>
+          newSingularGeneratedExtension(
+              final ContainingType containingTypeDefaultInstance,
+              final Type defaultValue,
+              final MessageLite messageDefaultInstance,
+              final Internal.EnumLiteMap<?> enumTypeMap,
+              final int number,
+              final WireFormat.FieldType type,
+              final Class singularType) {
+    return new GeneratedExtension<ContainingType, Type>(
+        containingTypeDefaultInstance,
+        defaultValue,
+        messageDefaultInstance,
+        new ExtensionDescriptor(enumTypeMap, number, type,
+                                false /* isRepeated */,
+                                false /* isPacked */),
+        singularType);
+  }
+
+  /** For use by generated code only. */
+  public static <ContainingType extends MessageLite, Type>
+      GeneratedExtension<ContainingType, Type>
+          newRepeatedGeneratedExtension(
+              final ContainingType containingTypeDefaultInstance,
+              final MessageLite messageDefaultInstance,
+              final Internal.EnumLiteMap<?> enumTypeMap,
+              final int number,
+              final WireFormat.FieldType type,
+              final boolean isPacked,
+              final Class singularType) {
+    @SuppressWarnings("unchecked")  // Subclasses ensure Type is a List
+    Type emptyList = (Type) Collections.emptyList();
+    return new GeneratedExtension<ContainingType, Type>(
+        containingTypeDefaultInstance,
+        emptyList,
+        messageDefaultInstance,
+        new ExtensionDescriptor(
+            enumTypeMap, number, type, true /* isRepeated */, isPacked),
+        singularType);
+  }
+
+  static final class ExtensionDescriptor
+      implements FieldSet.FieldDescriptorLite<
+        ExtensionDescriptor> {
+    ExtensionDescriptor(
+        final Internal.EnumLiteMap<?> enumTypeMap,
+        final int number,
+        final WireFormat.FieldType type,
+        final boolean isRepeated,
+        final boolean isPacked) {
+      this.enumTypeMap = enumTypeMap;
+      this.number = number;
+      this.type = type;
+      this.isRepeated = isRepeated;
+      this.isPacked = isPacked;
+    }
+
+    final Internal.EnumLiteMap<?> enumTypeMap;
+    final int number;
+    final WireFormat.FieldType type;
+    final boolean isRepeated;
+    final boolean isPacked;
+
+    @Override
+    public int getNumber() {
+      return number;
+    }
+
+    @Override
+    public WireFormat.FieldType getLiteType() {
+      return type;
+    }
+
+    @Override
+    public WireFormat.JavaType getLiteJavaType() {
+      return type.getJavaType();
+    }
+
+    @Override
+    public boolean isRepeated() {
+      return isRepeated;
+    }
+
+    @Override
+    public boolean isPacked() {
+      return isPacked;
+    }
+
+    @Override
+    public Internal.EnumLiteMap<?> getEnumType() {
+      return enumTypeMap;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
+      return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
+    }
+
+
+    @Override
+    public int compareTo(ExtensionDescriptor other) {
+      return number - other.number;
+    }
+  }
+
+  // =================================================================
+
+  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+  @SuppressWarnings("unchecked")
+  static Method getMethodOrDie(Class clazz, String name, Class... params) {
+    try {
+      return clazz.getMethod(name, params);
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(
+        "Generated message class \"" + clazz.getName() +
+        "\" missing method \"" + name + "\".", e);
+    }
+  }
+
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  static Object invokeOrDie(Method method, Object object, Object... params) {
+    try {
+      return method.invoke(object, params);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(
+        "Couldn't use Java reflection to implement protocol message " +
+        "reflection.", e);
+    } catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof RuntimeException) {
+        throw (RuntimeException) cause;
+      } else if (cause instanceof Error) {
+        throw (Error) cause;
+      } else {
+        throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", cause);
+      }
+    }
+  }
+
+  /**
+   * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
+   *
+   * Users should ignore the contents of this class and only use objects of
+   * this type as parameters to extension accessors and ExtensionRegistry.add().
+   */
+  public static class GeneratedExtension<
+      ContainingType extends MessageLite, Type>
+          extends ExtensionLite<ContainingType, Type> {
+
+    /**
+     * Create a new instance with the given parameters.
+     *
+     * The last parameter {@code singularType} is only needed for enum types.
+     * We store integer values for enum types in a {@link ExtendableMessage}
+     * and use Java reflection to convert an integer value back into a concrete
+     * enum object.
+     */
+    GeneratedExtension(
+        final ContainingType containingTypeDefaultInstance,
+        final Type defaultValue,
+        final MessageLite messageDefaultInstance,
+        final ExtensionDescriptor descriptor,
+        final Class singularType) {
+      // Defensive checks to verify the correct initialization order of
+      // GeneratedExtensions and their related GeneratedMessages.
+      if (containingTypeDefaultInstance == null) {
+        throw new IllegalArgumentException(
+            "Null containingTypeDefaultInstance");
+      }
+      if (descriptor.getLiteType() == WireFormat.FieldType.MESSAGE &&
+          messageDefaultInstance == null) {
+        throw new IllegalArgumentException(
+            "Null messageDefaultInstance");
+      }
+      this.containingTypeDefaultInstance = containingTypeDefaultInstance;
+      this.defaultValue = defaultValue;
+      this.messageDefaultInstance = messageDefaultInstance;
+      this.descriptor = descriptor;
+    }
+
+    final ContainingType containingTypeDefaultInstance;
+    final Type defaultValue;
+    final MessageLite messageDefaultInstance;
+    final ExtensionDescriptor descriptor;
+
+    /**
+     * Default instance of the type being extended, used to identify that type.
+     */
+    public ContainingType getContainingTypeDefaultInstance() {
+      return containingTypeDefaultInstance;
+    }
+
+    /** Get the field number. */
+    @Override
+    public int getNumber() {
+      return descriptor.getNumber();
+    }
+
+
+    /**
+     * If the extension is an embedded message or group, returns the default
+     * instance of the message.
+     */
+    @Override
+    public MessageLite getMessageDefaultInstance() {
+      return messageDefaultInstance;
+    }
+
+    @SuppressWarnings("unchecked")
+    Object fromFieldSetType(final Object value) {
+      if (descriptor.isRepeated()) {
+        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularFromFieldSetType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularFromFieldSetType(value);
+      }
+    }
+
+    Object singularFromFieldSetType(final Object value) {
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+        return descriptor.enumTypeMap.findValueByNumber((Integer) value);
+      } else {
+        return value;
+      }
+    }
+
+    @SuppressWarnings("unchecked")
+    Object toFieldSetType(final Object value) {
+      if (descriptor.isRepeated()) {
+        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+          final List result = new ArrayList();
+          for (final Object element : (List) value) {
+            result.add(singularToFieldSetType(element));
+          }
+          return result;
+        } else {
+          return value;
+        }
+      } else {
+        return singularToFieldSetType(value);
+      }
+    }
+
+    Object singularToFieldSetType(final Object value) {
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
+        return ((Internal.EnumLite) value).getNumber();
+      } else {
+        return value;
+      }
+    }
+
+    @Override
+    public FieldType getLiteType() {
+      return descriptor.getLiteType();
+    }
+
+    @Override
+    public boolean isRepeated() {
+      return descriptor.isRepeated;
+    }
+
+    @Override
+    public Type getDefaultValue() {
+      return defaultValue;
+    }
+  }
+
+  /**
+   * A serialized (serializable) form of the generated message.  Stores the
+   * message as a class name and a byte array.
+   */
+  protected static final class SerializedForm implements Serializable {
+
+    public static SerializedForm of(MessageLite message) {
+      return new SerializedForm(message);
+    }
+    
+    private static final long serialVersionUID = 0L;
+
+    private final String messageClassName;
+    private final byte[] asBytes;
+
+    /**
+     * Creates the serialized form by calling {@link com.google.protobuf.MessageLite#toByteArray}.
+     * @param regularForm the message to serialize
+     */
+    SerializedForm(MessageLite regularForm) {
+      messageClassName = regularForm.getClass().getName();
+      asBytes = regularForm.toByteArray();
+    }
+
+    /**
+     * When read from an ObjectInputStream, this method converts this object
+     * back to the regular form.  Part of Java's serialization magic.
+     * @return a GeneratedMessage of the type that was serialized
+     */
+    @SuppressWarnings("unchecked")
+    protected Object readResolve() throws ObjectStreamException {
+      try {
+        Class<?> messageClass = Class.forName(messageClassName);
+        java.lang.reflect.Field defaultInstanceField =
+            messageClass.getDeclaredField("DEFAULT_INSTANCE");
+        defaultInstanceField.setAccessible(true);
+        MessageLite defaultInstance = (MessageLite) defaultInstanceField.get(null);
+        return defaultInstance.newBuilderForType()
+            .mergeFrom(asBytes)
+            .buildPartial();
+      } catch (ClassNotFoundException e) {
+        throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
+      } catch (NoSuchFieldException e) {
+        throw new RuntimeException("Unable to find DEFAULT_INSTANCE in " + messageClassName, e);
+      } catch (SecurityException e) {
+        throw new RuntimeException("Unable to call DEFAULT_INSTANCE in " + messageClassName, e);
+      } catch (IllegalAccessException e) {
+        throw new RuntimeException("Unable to call parsePartialFrom", e);
+      } catch (InvalidProtocolBufferException e) {
+        throw new RuntimeException("Unable to understand proto buffer", e);
+      }
+    }
+  }
+  
+  /**
+   * Checks that the {@link Extension} is Lite and returns it as a
+   * {@link GeneratedExtension}.
+   */
+  private static <
+      MessageType extends ExtendableMessage<MessageType, BuilderType>,
+      BuilderType extends ExtendableBuilder<MessageType, BuilderType>,
+      T>
+    GeneratedExtension<MessageType, T> checkIsLite(
+        ExtensionLite<MessageType, T> extension) {
+    if (!extension.isLite()) {
+      throw new IllegalArgumentException("Expected a lite extension.");
+    }
+    
+    return (GeneratedExtension<MessageType, T>) extension;
+  }
+
+  /**
+   * A static helper method for checking if a message is initialized, optionally memoizing.
+   * <p>
+   * For use by generated code only.
+   */
+  protected static final <T extends GeneratedMessageLite<T, ?>> boolean isInitialized(
+      T message, boolean shouldMemoize) {
+    return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null;
+  } 
+  
+  protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
+    message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+  }
+
+  protected static IntList emptyIntList() {
+    return IntArrayList.emptyList();
+  }
+
+  protected static IntList mutableCopy(IntList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static LongList emptyLongList() {
+    return LongArrayList.emptyList();
+  }
+  
+  protected static LongList mutableCopy(LongList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static FloatList emptyFloatList() {
+    return FloatArrayList.emptyList();
+  }
+  
+  protected static FloatList mutableCopy(FloatList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static DoubleList emptyDoubleList() {
+    return DoubleArrayList.emptyList();
+  }
+  
+  protected static DoubleList mutableCopy(DoubleList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static BooleanList emptyBooleanList() {
+    return BooleanArrayList.emptyList();
+  }
+  
+  protected static BooleanList mutableCopy(BooleanList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static <E> ProtobufList<E> emptyProtobufList() {
+    return ProtobufArrayList.emptyList();
+  }
+  
+  protected static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  /**
+   * A {@link Parser} implementation that delegates to the default instance.
+   * <p>
+   * For use by generated code only.
+   */
+  protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
+      extends AbstractParser<T> {
+    
+    private T defaultInstance;
+    
+    public DefaultInstanceBasedParser(T defaultInstance) {
+      this.defaultInstance = defaultInstance;
+    }
+    
+    @Override
+    public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
+    }
+  }
+  
+  /**
+   * A static helper method for parsing a partial from input using the extension registry and the
+   * instance.
+   */
+  // TODO(dweis): Should this verify that the last tag was 0?
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+    @SuppressWarnings("unchecked") // Guaranteed by protoc
+    T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
+    try {
+      result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
+      result.makeImmutable();
+    } catch (RuntimeException e) {
+      if (e.getCause() instanceof InvalidProtocolBufferException) {
+        throw (InvalidProtocolBufferException) e.getCause();
+      }
+      throw e;
+    }
+    return result;
+  }
+  
+  protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance,
+      CodedInputStream input)
+      throws InvalidProtocolBufferException {
+    return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
+  }
+  
+  /**
+   * Helper method to check if message is initialized.
+   *
+   * @throws InvalidProtocolBufferException if it is not initialized.
+   * @return The message to check.
+   */
+  private static <T extends GeneratedMessageLite<T, ?>> T checkMessageInitialized(T message)
+      throws InvalidProtocolBufferException {
+    if (message != null && !message.isInitialized()) {
+      throw message.newUninitializedMessageException()
+          .asInvalidProtocolBufferException()
+          .setUnfinishedMessage(message);
+    }
+    return message;
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteString data)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
+  }
+  
+  // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+  // ByteString.
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    T message;
+    try {
+      CodedInputStream input = data.newCodedInput();
+      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
+  }
+  
+  // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
+  // ByteString.
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    T message;
+    try {
+      CodedInputStream input = CodedInputStream.newInstance(data);
+      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
+      try {
+        input.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, byte[] data)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
+  }
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, InputStream input)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input),
+            ExtensionRegistryLite.getEmptyRegistry()));
+  }
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input), extensionRegistry));
+  }
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, CodedInputStream input)
+      throws InvalidProtocolBufferException {
+    return parseFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
+  }
+
+  // Does not validate last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+      T defaultInstance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, input, extensionRegistry));
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+      T defaultInstance, InputStream input)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialDelimitedFrom(defaultInstance, input,
+            ExtensionRegistryLite.getEmptyRegistry()));
+  }
+
+  // Validates last tag.
+  protected static <T extends GeneratedMessageLite<T, ?>> T parseDelimitedFrom(
+      T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    return checkMessageInitialized(
+        parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry));
+  }
+  
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialDelimitedFrom(
+      T defaultInstance,
+      InputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    int size;
+    try {
+      int firstByte = input.read();
+      if (firstByte == -1) {
+        return null;
+      }
+      size = CodedInputStream.readRawVarint32(firstByte, input);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e.getMessage());
+    }
+    InputStream limitedInput = new LimitedInputStream(input, size);
+    CodedInputStream codedInput = CodedInputStream.newInstance(limitedInput);
+    T message = parsePartialFrom(defaultInstance, codedInput, extensionRegistry);
+    try {
+      codedInput.checkLastTagWas(0);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(message);
+    }
+    return message;
+  }
+
+  /**
+   * An abstract visitor that the generated code calls into that we use to implement various
+   * features. Fields that are not members of oneofs are always visited. Members of a oneof are only
+   * visited when they are the set oneof case value on the "other" proto. The visitOneofNotSet
+   * method is invoked if other's oneof case is not set.
+   */
+  protected interface Visitor {
+    boolean visitBoolean(boolean minePresent, boolean mine, boolean otherPresent, boolean other);
+    int visitInt(boolean minePresent, int mine, boolean otherPresent, int other);
+    double visitDouble(boolean minePresent, double mine, boolean otherPresent, double other);
+    float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other);
+    long visitLong(boolean minePresent, long mine, boolean otherPresent, long other);
+    String visitString(boolean minePresent, String mine, boolean otherPresent, String other);
+    ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other);
+
+    Object visitOneofBoolean(boolean minePresent, Object mine, Object other);
+    Object visitOneofInt(boolean minePresent, Object mine, Object other);
+    Object visitOneofDouble(boolean minePresent, Object mine, Object other);
+    Object visitOneofFloat(boolean minePresent, Object mine, Object other);
+    Object visitOneofLong(boolean minePresent, Object mine, Object other);
+    Object visitOneofString(boolean minePresent, Object mine, Object other);
+    Object visitOneofByteString(boolean minePresent, Object mine, Object other);
+    Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other);
+    Object visitOneofMessage(boolean minePresent, Object mine, Object other);
+    void visitOneofNotSet(boolean minePresent);
+    
+    /**
+     * Message fields use null sentinals.
+     */
+    <T extends MessageLite> T visitMessage(T mine, T other);
+    LazyFieldLite visitLazyMessage(
+        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other);
+
+    <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
+    BooleanList visitBooleanList(BooleanList mine, BooleanList other);
+    IntList visitIntList(IntList mine, IntList other);
+    DoubleList visitDoubleList(DoubleList mine, DoubleList other);
+    FloatList visitFloatList(FloatList mine, FloatList other);
+    LongList visitLongList(LongList mine, LongList other);
+    FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine, FieldSet<ExtensionDescriptor> other);
+    UnknownFieldSetLite visitUnknownFields(UnknownFieldSetLite mine, UnknownFieldSetLite other);
+    <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other);
+  }
+
+  /**
+   * Implements equals. Throws a {@link NotEqualsException} when not equal.
+   */
+  static class EqualsVisitor implements Visitor {
+
+    static final class NotEqualsException extends RuntimeException {}
+
+    static final EqualsVisitor INSTANCE = new EqualsVisitor();
+
+    static final NotEqualsException NOT_EQUALS = new NotEqualsException();
+
+    private EqualsVisitor() {}
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      if (minePresent != otherPresent || mine != other) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      if (minePresent != otherPresent || !mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      if (minePresent != otherPresent || !mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+    
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+    
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      if (minePresent) {
+        throw NOT_EQUALS;
+      }
+    }
+
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      if (mine == null && other == null) {
+        return null;
+      }
+
+      if (mine == null || other == null) {
+        throw NOT_EQUALS;
+      }
+
+      ((GeneratedMessageLite<?, ?>) mine).equals(this, other);
+
+      return mine;
+    }
+    
+    @Override
+    public LazyFieldLite visitLazyMessage(
+        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+      if (!minePresent && !otherPresent) {
+        return mine;
+      } else if (minePresent && otherPresent && mine.equals(other)) {
+        return mine;
+      }
+      throw NOT_EQUALS;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      if (!mine.equals(other)) {
+        throw NOT_EQUALS;
+      }
+      return mine;
+    }
+  }
+
+  /**
+   * Implements hashCode by accumulating state.
+   */
+  private static class HashCodeVisitor implements Visitor {
+
+    // The caller must ensure that the visitor is invoked parameterized with this and this such that
+    // other is this. This is required due to how oneof cases are handled. See the class comment
+    // on Visitor for more information.
+    
+    private int hashCode = 0;
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      hashCode = (53 * hashCode) + Internal.hashBoolean(mine);
+      return mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      hashCode = (53 * hashCode) + mine;
+      return mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits(mine));
+      return mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      hashCode = (53 * hashCode) + Float.floatToIntBits(mine);
+      return mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(mine);
+      return mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashBoolean(((Boolean) mine));
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + (Integer) mine;
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits((Double) mine));
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Float.floatToIntBits((Float) mine);
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + Internal.hashLong((Long) mine);
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+    
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      return visitMessage((MessageLite) mine, (MessageLite) other);
+    }
+
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      if (minePresent) {
+        throw new IllegalStateException(); // Can't happen if other == this. 
+      }
+    }
+
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      final int protoHash;
+      if (mine != null) {
+        if (mine instanceof GeneratedMessageLite) {
+          protoHash = ((GeneratedMessageLite) mine).hashCode(this);
+        } else {
+          protoHash = mine.hashCode();
+        }
+      } else {
+        protoHash = 37;
+      }
+      hashCode = (53 * hashCode) + protoHash;
+      return mine;
+    }
+
+    @Override
+    public LazyFieldLite visitLazyMessage(
+        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+    
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      hashCode = (53 * hashCode) + mine.hashCode();
+      return mine;
+    }
+  }
+
+  /**
+   * Implements field merging semantics over the visitor interface.
+   */
+  protected static class MergeFromVisitor implements Visitor {
+
+    public static final MergeFromVisitor INSTANCE = new MergeFromVisitor();
+
+    private MergeFromVisitor() {}
+
+    @Override
+    public boolean visitBoolean(
+        boolean minePresent, boolean mine, boolean otherPresent, boolean other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public double visitDouble(
+        boolean minePresent, double mine, boolean otherPresent, double other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public String visitString(
+        boolean minePresent, String mine, boolean otherPresent, String other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public ByteString visitByteString(
+        boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) {
+      return otherPresent ? other : mine;
+    }
+
+    @Override
+    public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofInt(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
+      return other;      
+    }
+
+    @Override
+    public Object visitOneofFloat(boolean minePresent, Object mine, Object other) {
+      return other;
+    }
+
+    @Override
+    public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
+      return other;      
+    }
+
+    @Override
+    public Object visitOneofString(boolean minePresent, Object mine, Object other) {
+      return other;      
+    }
+
+    @Override
+    public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
+      return other;      
+    }
+
+    @Override
+    public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent) {
+        LazyFieldLite lazy = (LazyFieldLite) mine;
+        lazy.merge((LazyFieldLite) other);
+        return lazy;
+      }
+      return other;
+    }
+    
+    @Override
+    public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
+      if (minePresent) {
+        return visitMessage((MessageLite) mine, (MessageLite) other);
+      }
+      return other;
+    }
+    
+    @Override
+    public void visitOneofNotSet(boolean minePresent) {
+      return;
+    }
+
+    @SuppressWarnings("unchecked") // Guaranteed by runtime.
+    @Override
+    public <T extends MessageLite> T visitMessage(T mine, T other) {
+      if (mine != null && other != null) {
+        return (T) mine.toBuilder().mergeFrom(other).build();
+      }
+
+      return mine != null ? mine : other;
+    }
+
+    @Override
+    public LazyFieldLite visitLazyMessage(
+        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
+      // LazyFieldLite's are never null so we can just copy across. Necessary to avoid leakage
+      // from builder into immutable message.
+      // TODO(dweis): Change to null sentinels?
+      mine.merge(other);
+      return mine;
+    }
+
+    @Override
+    public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public BooleanList visitBooleanList(BooleanList mine, BooleanList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public IntList visitIntList(IntList mine, IntList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public DoubleList visitDoubleList(DoubleList mine, DoubleList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public FloatList visitFloatList(FloatList mine, FloatList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public LongList visitLongList(LongList mine, LongList other) {
+      int size = mine.size();
+      int otherSize = other.size();
+      if (size > 0 && otherSize > 0) {
+        if (!mine.isModifiable()) {
+          mine = mine.mutableCopyWithCapacity(size + otherSize);
+        }
+        mine.addAll(other);
+      }
+      
+      return size > 0 ? mine : other;
+    }
+
+    @Override
+    public FieldSet<ExtensionDescriptor> visitExtensions(
+        FieldSet<ExtensionDescriptor> mine,
+        FieldSet<ExtensionDescriptor> other) {
+      if (mine.isImmutable()) {
+        mine = mine.clone();
+      }
+      mine.mergeFrom(other);
+      return mine;
+    }
+
+    @Override
+    public UnknownFieldSetLite visitUnknownFields(
+        UnknownFieldSetLite mine,
+        UnknownFieldSetLite other) {
+      return other == UnknownFieldSetLite.getDefaultInstance()
+          ? mine : UnknownFieldSetLite.mutableCopyOf(mine, other);
+    }
+    
+    @Override
+    public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
+      mine.mergeFrom(other);
+      return mine;
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
new file mode 100644
index 0000000..6d6ece5
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -0,0 +1,269 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.IntList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link IntList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
+  
+  private static final IntArrayList EMPTY_LIST = new IntArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static IntArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private int[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} with default capacity.
+   */
+  IntArrayList() {
+    this(new int[DEFAULT_CAPACITY], 0);
+  }
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
+   */
+  private IntArrayList(int[] array, int size) {
+    this.array = array;
+    this.size = size;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof IntArrayList)) {
+      return super.equals(o);
+    }
+    IntArrayList other = (IntArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+    
+    final int[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
+      }
+    }
+    
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + array[i];
+    }
+    return result;
+  }
+
+  @Override
+  public IntList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new IntArrayList(Arrays.copyOf(array, capacity), size);
+  }
+  
+  @Override
+  public Integer get(int index) {
+    return getInt(index);
+  }
+
+  @Override
+  public int getInt(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Integer set(int index, Integer element) {
+    return setInt(index, element);
+  }
+
+  @Override
+  public int setInt(int index, int element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    int previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Integer element) {
+    addInt(index, element);
+  }
+
+  /**
+   * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addInt(int element) {
+    addInt(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element.
+   */
+  private void addInt(int index, int element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      int[] newArray = new int[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Integer> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another IntArrayList to avoid boxing elements.
+    if (!(collection instanceof IntArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    IntArrayList list = (IntArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Integer remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    int value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
new file mode 100644
index 0000000..d1de375
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -0,0 +1,741 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.AbstractList;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.RandomAccess;
+import java.util.Set;
+
+/**
+ * The classes contained within are used internally by the Protocol Buffer
+ * library and generated message implementations. They are public only because
+ * those generated messages do not reside in the {@code protobuf} package.
+ * Others should not use this class directly.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public final class Internal {
+
+  private Internal() {}
+
+  static final Charset UTF_8 = Charset.forName("UTF-8");
+  static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+  /**
+   * Helper called by generated code to construct default values for string
+   * fields.
+   * <p>
+   * The protocol compiler does not actually contain a UTF-8 decoder -- it
+   * just pushes UTF-8-encoded text around without touching it.  The one place
+   * where this presents a problem is when generating Java string literals.
+   * Unicode characters in the string literal would normally need to be encoded
+   * using a Unicode escape sequence, which would require decoding them.
+   * To get around this, protoc instead embeds the UTF-8 bytes into the
+   * generated code and leaves it to the runtime library to decode them.
+   * <p>
+   * It gets worse, though.  If protoc just generated a byte array, like:
+   *   new byte[] {0x12, 0x34, 0x56, 0x78}
+   * Java actually generates *code* which allocates an array and then fills
+   * in each value.  This is much less efficient than just embedding the bytes
+   * directly into the bytecode.  To get around this, we need another
+   * work-around.  String literals are embedded directly, so protoc actually
+   * generates a string literal corresponding to the bytes.  The easiest way
+   * to do this is to use the ISO-8859-1 character set, which corresponds to
+   * the first 256 characters of the Unicode range.  Protoc can then use
+   * good old CEscape to generate the string.
+   * <p>
+   * So we have a string literal which represents a set of bytes which
+   * represents another string.  This function -- stringDefaultValue --
+   * converts from the generated string to the string we actually want.  The
+   * generated code calls this automatically.
+   */
+  public static String stringDefaultValue(String bytes) {
+    return new String(bytes.getBytes(ISO_8859_1), UTF_8);
+  }
+
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+   * In this case we only need the second of the two hacks -- allowing us to
+   * embed raw bytes as a string literal with ISO-8859-1 encoding.
+   */
+  public static ByteString bytesDefaultValue(String bytes) {
+    return ByteString.copyFrom(bytes.getBytes(ISO_8859_1));
+  }
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is like {@link #bytesDefaultValue}, but returns a byte array.
+   */
+  public static byte[] byteArrayDefaultValue(String bytes) {
+    return bytes.getBytes(ISO_8859_1);
+  }
+
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer.
+   */
+  public static ByteBuffer byteBufferDefaultValue(String bytes) {
+    return ByteBuffer.wrap(byteArrayDefaultValue(bytes));
+  }
+
+  /**
+   * Create a new ByteBuffer and copy all the content of {@code source}
+   * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and
+   * capacity will be source.capacity(), and its position will be 0.
+   * Note that the state of {@code source} ByteBuffer won't be changed.
+   */
+  public static ByteBuffer copyByteBuffer(ByteBuffer source) {
+    // Make a duplicate of the source ByteBuffer and read data from the
+    // duplicate. This is to avoid affecting the source ByteBuffer's state.
+    ByteBuffer temp = source.duplicate();
+    // We want to copy all the data in the source ByteBuffer, not just the
+    // remaining bytes.
+    temp.clear();
+    ByteBuffer result = ByteBuffer.allocate(temp.capacity());
+    result.put(temp);
+    result.clear();
+    return result;
+  }
+
+  /**
+   * Helper called by generated code to determine if a byte array is a valid
+   * UTF-8 encoded string such that the original bytes can be converted to
+   * a String object and then back to a byte array round tripping the bytes
+   * without loss.  More precisely, returns {@code true} whenever:
+   * <pre>   {@code
+   * Arrays.equals(byteString.toByteArray(),
+   *     new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
+   * }</pre>
+   *
+   * <p>This method rejects "overlong" byte sequences, as well as
+   * 3-byte sequences that would map to a surrogate character, in
+   * accordance with the restricted definition of UTF-8 introduced in
+   * Unicode 3.1.  Note that the UTF-8 decoder included in Oracle's
+   * JDK has been modified to also reject "overlong" byte sequences,
+   * but currently (2011) still accepts 3-byte surrogate character
+   * byte sequences.
+   *
+   * <p>See the Unicode Standard,<br>
+   * Table 3-6. <em>UTF-8 Bit Distribution</em>,<br>
+   * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+   *
+   * <p>As of 2011-02, this method simply returns the result of {@link
+   * ByteString#isValidUtf8()}.  Calling that method directly is preferred.
+   *
+   * @param byteString the string to check
+   * @return whether the byte array is round trippable
+   */
+  public static boolean isValidUtf8(ByteString byteString) {
+    return byteString.isValidUtf8();
+  }
+
+  /**
+   * Like {@link #isValidUtf8(ByteString)} but for byte arrays.
+   */
+  public static boolean isValidUtf8(byte[] byteArray) {
+    return Utf8.isValidUtf8(byteArray);
+  }
+
+  /**
+   * Helper method to get the UTF-8 bytes of a string.
+   */
+  public static byte[] toByteArray(String value) {
+    return value.getBytes(UTF_8);
+  }
+
+  /**
+   * Helper method to convert a byte array to a string using UTF-8 encoding.
+   */
+  public static String toStringUtf8(byte[] bytes) {
+    return new String(bytes, UTF_8);
+  }
+
+  /**
+   * Interface for an enum value or value descriptor, to be used in FieldSet.
+   * The lite library stores enum values directly in FieldSets but the full
+   * library stores EnumValueDescriptors in order to better support reflection.
+   */
+  public interface EnumLite {
+    int getNumber();
+  }
+
+  /**
+   * Interface for an object which maps integers to {@link EnumLite}s.
+   * {@link Descriptors.EnumDescriptor} implements this interface by mapping
+   * numbers to {@link Descriptors.EnumValueDescriptor}s.  Additionally,
+   * every generated enum type has a static method internalGetValueMap() which
+   * returns an implementation of this type that maps numbers to enum values.
+   */
+  public interface EnumLiteMap<T extends EnumLite> {
+    T findValueByNumber(int number);
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for longs.
+   * @see Long#hashCode()
+   */
+  public static int hashLong(long n) {
+    return (int) (n ^ (n >>> 32));
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for
+   * booleans.
+   * @see Boolean#hashCode()
+   */
+  public static int hashBoolean(boolean b) {
+    return b ? 1231 : 1237;
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for enums.
+   * <p>
+   * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
+   * need to use the field number as the hash code to ensure compatibility
+   * between statically and dynamically generated enum objects.
+   */
+  public static int hashEnum(EnumLite e) {
+    return e.getNumber();
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for
+   * enum lists.
+   */
+  public static int hashEnumList(List<? extends EnumLite> list) {
+    int hash = 1;
+    for (EnumLite e : list) {
+      hash = 31 * hash + hashEnum(e);
+    }
+    return hash;
+  }
+
+  /**
+   * Helper method for implementing {@link Message#equals(Object)} for bytes field.
+   */
+  public static boolean equals(List<byte[]> a, List<byte[]> b) {
+    if (a.size() != b.size()) return false;
+    for (int i = 0; i < a.size(); ++i) {
+      if (!Arrays.equals(a.get(i), b.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for bytes field.
+   */
+  public static int hashCode(List<byte[]> list) {
+    int hash = 1;
+    for (byte[] bytes : list) {
+      hash = 31 * hash + hashCode(bytes);
+    }
+    return hash;
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for bytes field.
+   */
+  public static int hashCode(byte[] bytes) {
+    // The hash code for a byte array should be the same as the hash code for a
+    // ByteString with the same content. This is to ensure that the generated
+    // hashCode() method will return the same value as the pure reflection
+    // based hashCode() method.
+    return Internal.hashCode(bytes, 0, bytes.length);
+  }
+  
+  /**
+   * Helper method for implementing {@link LiteralByteString#hashCode()}.
+   */
+  static int hashCode(byte[] bytes, int offset, int length) {
+    // The hash code for a byte array should be the same as the hash code for a
+    // ByteString with the same content. This is to ensure that the generated
+    // hashCode() method will return the same value as the pure reflection
+    // based hashCode() method.
+    int h = Internal.partialHash(length, bytes, offset, length);
+    return h == 0 ? 1 : h;
+  }
+
+  /**
+   * Helper method for continuously hashing bytes.
+   */
+  static int partialHash(int h, byte[] bytes, int offset, int length) {
+    for (int i = offset; i < offset + length; i++) {
+      h = h * 31 + bytes[i];
+    }
+    return h;
+  }
+  
+  /**
+   * Helper method for implementing {@link Message#equals(Object)} for bytes
+   * field.
+   */
+  public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
+    if (a.capacity() != b.capacity()) {
+      return false;
+    }
+    // ByteBuffer.equals() will only compare the remaining bytes, but we want to
+    // compare all the content.
+    return a.duplicate().clear().equals(b.duplicate().clear());
+  }
+
+  /**
+   * Helper method for implementing {@link Message#equals(Object)} for bytes
+   * field.
+   */
+  public static boolean equalsByteBuffer(
+      List<ByteBuffer> a, List<ByteBuffer> b) {
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (int i = 0; i < a.size(); ++i) {
+      if (!equalsByteBuffer(a.get(i), b.get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for bytes
+   * field.
+   */
+  public static int hashCodeByteBuffer(List<ByteBuffer> list) {
+    int hash = 1;
+    for (ByteBuffer bytes : list) {
+      hash = 31 * hash + hashCodeByteBuffer(bytes);
+    }
+    return hash;
+  }
+
+  private static final int DEFAULT_BUFFER_SIZE = 4096;
+
+  /**
+   * Helper method for implementing {@link Message#hashCode()} for bytes
+   * field.
+   */
+  public static int hashCodeByteBuffer(ByteBuffer bytes) {
+    if (bytes.hasArray()) {
+      // Fast path.
+      int h = partialHash(bytes.capacity(), bytes.array(), bytes.arrayOffset(), bytes.capacity());
+      return h == 0 ? 1 : h;
+    } else {
+      // Read the data into a temporary byte array before calculating the
+      // hash value.
+      final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE
+          ? DEFAULT_BUFFER_SIZE : bytes.capacity();
+      final byte[] buffer = new byte[bufferSize];
+      final ByteBuffer duplicated = bytes.duplicate();
+      duplicated.clear();
+      int h = bytes.capacity();
+      while (duplicated.remaining() > 0) {
+        final int length = duplicated.remaining() <= bufferSize ?
+            duplicated.remaining() : bufferSize;
+        duplicated.get(buffer, 0, length);
+        h = partialHash(h, buffer, 0, length);
+      }
+      return h == 0 ? 1 : h;
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T extends MessageLite> T getDefaultInstance(Class<T> clazz) {
+    try {
+      Method method = clazz.getMethod("getDefaultInstance");
+      return (T) method.invoke(method);
+    } catch (Exception e) {
+      throw new RuntimeException(
+          "Failed to get default instance for " + clazz, e);
+    }
+  }
+
+  /**
+   * An empty byte array constant used in generated code.
+   */
+  public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+  /**
+   * An empty byte array constant used in generated code.
+   */
+  public static final ByteBuffer EMPTY_BYTE_BUFFER =
+      ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
+
+  /** An empty coded input stream constant used in generated code. */
+  public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
+      CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
+
+
+  /**
+   * Provides an immutable view of {@code List<T>} around a {@code List<F>}.
+   *
+   * Protobuf internal. Used in protobuf generated code only.
+   */
+  public static class ListAdapter<F, T> extends AbstractList<T> {
+    /**
+     * Convert individual elements of the List from F to T.
+     */
+    public interface Converter<F, T> {
+      T convert(F from);
+    }
+
+    private final List<F> fromList;
+    private final Converter<F, T> converter;
+
+    public ListAdapter(List<F> fromList, Converter<F, T> converter) {
+      this.fromList = fromList;
+      this.converter = converter;
+    }
+
+    @Override
+    public T get(int index) {
+      return converter.convert(fromList.get(index));
+    }
+
+    @Override
+    public int size() {
+      return fromList.size();
+    }
+  }
+
+  /**
+   * Wrap around a {@code Map<K, RealValue>} and provide a {@code Map<K, V>}
+   * interface.
+   */
+  public static class MapAdapter<K, V, RealValue> extends AbstractMap<K, V> {
+    /**
+     * An interface used to convert between two types.
+     */
+    public interface Converter<A, B> {
+      B doForward(A object);
+      A doBackward(B object);
+    }
+
+    public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
+        final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
+      return new Converter<Integer, T>() {
+        @Override
+        public T doForward(Integer value) {
+          T result = enumMap.findValueByNumber(value);
+          return result == null ? unrecognizedValue : result;
+        }
+
+        @Override
+        public Integer doBackward(T value) {
+          return value.getNumber();
+        }
+      };
+    }
+
+    private final Map<K, RealValue> realMap;
+    private final Converter<RealValue, V> valueConverter;
+
+    public MapAdapter(Map<K, RealValue> realMap,
+        Converter<RealValue, V> valueConverter) {
+      this.realMap = realMap;
+      this.valueConverter = valueConverter;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V get(Object key) {
+      RealValue result = realMap.get(key);
+      if (result == null) {
+        return null;
+      }
+      return valueConverter.doForward(result);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      RealValue oldValue = realMap.put(key, valueConverter.doBackward(value));
+      if (oldValue == null) {
+        return null;
+      }
+      return valueConverter.doForward(oldValue);
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+      return new SetAdapter(realMap.entrySet());
+    }
+
+    private class SetAdapter extends AbstractSet<Map.Entry<K, V>> {
+      private final Set<Map.Entry<K, RealValue>> realSet;
+      public SetAdapter(Set<Map.Entry<K, RealValue>> realSet) {
+        this.realSet = realSet;
+      }
+
+      @Override
+      public Iterator<java.util.Map.Entry<K, V>> iterator() {
+        return new IteratorAdapter(realSet.iterator());
+      }
+
+      @Override
+      public int size() {
+        return realSet.size();
+      }
+    }
+
+    private class IteratorAdapter implements Iterator<Map.Entry<K, V>> {
+      private final Iterator<Map.Entry<K, RealValue>> realIterator;
+
+      public IteratorAdapter(
+          Iterator<Map.Entry<K, RealValue>> realIterator) {
+        this.realIterator = realIterator;
+      }
+
+      @Override
+      public boolean hasNext() {
+        return realIterator.hasNext();
+      }
+
+      @Override
+      public java.util.Map.Entry<K, V> next() {
+        return new EntryAdapter(realIterator.next());
+      }
+
+      @Override
+      public void remove() {
+        realIterator.remove();
+      }
+    }
+
+    private class EntryAdapter implements Map.Entry<K, V> {
+      private final Map.Entry<K, RealValue> realEntry;
+
+      public EntryAdapter(Map.Entry<K, RealValue> realEntry) {
+        this.realEntry = realEntry;
+      }
+
+      @Override
+      public K getKey() {
+        return realEntry.getKey();
+      }
+
+      @Override
+      public V getValue() {
+        return valueConverter.doForward(realEntry.getValue());
+      }
+
+      @Override
+      public V setValue(V value) {
+        RealValue oldValue = realEntry.setValue(
+            valueConverter.doBackward(value));
+        if (oldValue == null) {
+          return null;
+        }
+        return valueConverter.doForward(oldValue);
+      }
+    }
+  }
+
+  /**
+   * Extends {@link List} to add the capability to make the list immutable and inspect if it is
+   * modifiable.
+   * <p>
+   * All implementations must support efficient random access.
+   */
+  public static interface ProtobufList<E> extends List<E>, RandomAccess {
+
+    /**
+     * Makes this list immutable. All subsequent modifications will throw an
+     * {@link UnsupportedOperationException}.
+     */
+    void makeImmutable();
+
+    /**
+     * Returns whether this list can be modified via the publicly accessible {@link List} methods.
+     */
+    boolean isModifiable();
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    ProtobufList<E> mutableCopyWithCapacity(int capacity);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Integers if
+   * possible. Does not support null elements.
+   */
+  public static interface IntList extends ProtobufList<Integer> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    int getInt(int index);
+
+    /**
+     * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
+     */
+    void addInt(int element);
+
+    /**
+     * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element.
+     */
+    int setInt(int index, int element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    IntList mutableCopyWithCapacity(int capacity);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Booleans if
+   * possible. Does not support null elements.
+   */
+  public static interface BooleanList extends ProtobufList<Boolean> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    boolean getBoolean(int index);
+
+    /**
+     * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
+     */
+    void addBoolean(boolean element);
+
+    /**
+     * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element.
+     */
+    boolean setBoolean(int index, boolean element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    BooleanList mutableCopyWithCapacity(int capacity);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Longs if
+   * possible. Does not support null elements.
+   */
+  public static interface LongList extends ProtobufList<Long> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    long getLong(int index);
+
+    /**
+     * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
+     */
+    void addLong(long element);
+
+    /**
+     * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element.
+     */
+    long setLong(int index, long element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    LongList mutableCopyWithCapacity(int capacity);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Doubles if
+   * possible. Does not support null elements.
+   */
+  public static interface DoubleList extends ProtobufList<Double> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    double getDouble(int index);
+
+    /**
+     * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
+     */
+    void addDouble(double element);
+
+    /**
+     * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element.
+     */
+    double setDouble(int index, double element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    DoubleList mutableCopyWithCapacity(int capacity);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Floats if
+   * possible. Does not support null elements.
+   */
+  public static interface FloatList extends ProtobufList<Float> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    float getFloat(int index);
+
+    /**
+     * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
+     */
+    void addFloat(float element);
+
+    /**
+     * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element.
+     */
+    float setFloat(int index, float element);
+
+    /**
+     * Returns a mutable clone of this list with the specified capacity.
+     */
+    @Override
+    FloatList mutableCopyWithCapacity(int capacity);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
new file mode 100644
index 0000000..85ce7b2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -0,0 +1,134 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way,
+ * e.g. it contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferException extends IOException {
+  private static final long serialVersionUID = -1616151763072450476L;
+  private MessageLite unfinishedMessage = null;
+
+  public InvalidProtocolBufferException(final String description) {
+    super(description);
+  }
+
+  public InvalidProtocolBufferException(IOException e) {
+    super(e.getMessage(), e);
+  }
+
+  /**
+   * Attaches an unfinished message to the exception to support best-effort
+   * parsing in {@code Parser} interface.
+   *
+   * @return this
+   */
+  public InvalidProtocolBufferException setUnfinishedMessage(
+      MessageLite unfinishedMessage) {
+    this.unfinishedMessage = unfinishedMessage;
+    return this;
+  }
+
+  /**
+   * Returns the unfinished message attached to the exception, or null if
+   * no message is attached.
+   */
+  public MessageLite getUnfinishedMessage() {
+    return unfinishedMessage;
+  }
+
+  /**
+   * Unwraps the underlying {@link IOException} if this exception was caused by an I/O
+   * problem. Otherwise, returns {@code this}.
+   */
+  public IOException unwrapIOException() {
+    return getCause() instanceof IOException ? (IOException) getCause() : this;
+  }
+
+  static InvalidProtocolBufferException truncatedMessage() {
+    return new InvalidProtocolBufferException(
+      "While parsing a protocol message, the input ended unexpectedly " +
+      "in the middle of a field.  This could mean either that the " +
+      "input has been truncated or that an embedded message " +
+      "misreported its own length.");
+  }
+
+  static InvalidProtocolBufferException negativeSize() {
+    return new InvalidProtocolBufferException(
+      "CodedInputStream encountered an embedded string or message " +
+      "which claimed to have negative size.");
+  }
+
+  static InvalidProtocolBufferException malformedVarint() {
+    return new InvalidProtocolBufferException(
+      "CodedInputStream encountered a malformed varint.");
+  }
+
+  static InvalidProtocolBufferException invalidTag() {
+    return new InvalidProtocolBufferException(
+      "Protocol message contained an invalid tag (zero).");
+  }
+
+  static InvalidProtocolBufferException invalidEndTag() {
+    return new InvalidProtocolBufferException(
+      "Protocol message end-group tag did not match expected tag.");
+  }
+
+  static InvalidProtocolBufferException invalidWireType() {
+    return new InvalidProtocolBufferException(
+      "Protocol message tag had invalid wire type.");
+  }
+
+  static InvalidProtocolBufferException recursionLimitExceeded() {
+    return new InvalidProtocolBufferException(
+      "Protocol message had too many levels of nesting.  May be malicious.  " +
+      "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+  }
+
+  static InvalidProtocolBufferException sizeLimitExceeded() {
+    return new InvalidProtocolBufferException(
+      "Protocol message was too large.  May be malicious.  " +
+      "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+  }
+
+  static InvalidProtocolBufferException parseFailure() {
+    return new InvalidProtocolBufferException("Failed to parse the message.");
+  }
+
+  static InvalidProtocolBufferException invalidUtf8() {
+    return new InvalidProtocolBufferException("Protocol message had invalid UTF-8.");
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java
new file mode 100644
index 0000000..98e13ca
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LazyField.java
@@ -0,0 +1,154 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+/**
+ * LazyField encapsulates the logic of lazily parsing message fields. It stores
+ * the message in a ByteString initially and then parse it on-demand.
+ *
+ * Most of key methods are implemented in {@link LazyFieldLite} but this class
+ * can contain default instance of the message to provide {@code hashCode()},
+ * {@code euqals()} and {@code toString()}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyField extends LazyFieldLite {
+
+  /**
+   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
+   * {@code toString()}.
+   */
+  private final MessageLite defaultInstance;
+
+  public LazyField(MessageLite defaultInstance,
+      ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+    super(extensionRegistry, bytes);
+
+    this.defaultInstance = defaultInstance;
+  }
+
+  @Override
+  public boolean containsDefaultInstance() {
+    return super.containsDefaultInstance() || value == defaultInstance;
+  }
+
+  public MessageLite getValue() {
+    return getValue(defaultInstance);
+  }
+
+  @Override
+  public int hashCode() {
+    return getValue().hashCode();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return getValue().equals(obj);
+  }
+
+  @Override
+  public String toString() {
+    return getValue().toString();
+  }
+
+  // ====================================================
+
+  /**
+   * LazyEntry and LazyIterator are used to encapsulate the LazyField, when
+   * users iterate all fields from FieldSet.
+   */
+  static class LazyEntry<K> implements Entry<K, Object> {
+    private Entry<K, LazyField> entry;
+
+    private LazyEntry(Entry<K, LazyField> entry) {
+      this.entry = entry;
+    }
+
+    @Override
+    public K getKey() {
+      return entry.getKey();
+    }
+
+    @Override
+    public Object getValue() {
+      LazyField field = entry.getValue();
+      if (field == null) {
+        return null;
+      }
+      return field.getValue();
+    }
+
+    public LazyField getField() {
+      return entry.getValue();
+    }
+
+    @Override
+    public Object setValue(Object value) {
+      if (!(value instanceof MessageLite)) {
+        throw new IllegalArgumentException(
+            "LazyField now only used for MessageSet, "
+            + "and the value of MessageSet must be an instance of MessageLite");
+      }
+      return entry.getValue().setValue((MessageLite) value);
+    }
+  }
+
+  static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
+    private Iterator<Entry<K, Object>> iterator;
+
+    public LazyIterator(Iterator<Entry<K, Object>> iterator) {
+      this.iterator = iterator;
+    }
+
+    @Override
+    public boolean hasNext() {
+      return iterator.hasNext();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Entry<K, Object> next() {
+      Entry<K, ?> entry = iterator.next();
+      if (entry.getValue() instanceof LazyField) {
+        return new LazyEntry<K>((Entry<K, LazyField>) entry);
+      }
+      return (Entry<K, Object>) entry;
+    }
+
+    @Override
+    public void remove() {
+      iterator.remove();
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
new file mode 100644
index 0000000..2febaac
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -0,0 +1,458 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+
+/**
+ * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
+ * the message in a ByteString initially and then parses it on-demand.
+ *
+ * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
+ * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit
+ * synchronization is needed under read/write situations.
+ *
+ * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered
+ * to be immutable and none of the setter methods in its API are expected to be invoked. All of the
+ * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder,
+ * setters can be invoked, but there is no guarantee of thread safety.
+ * 
+ * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
+ * into a separate builder class to allow us to give stronger compile-time guarantees.
+ *
+ * This class is internal implementation detail of the protobuf library, so you don't need to use it
+ * directly.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldLite {
+  private static final ExtensionRegistryLite EMPTY_REGISTRY =
+      ExtensionRegistryLite.getEmptyRegistry();
+
+  /**
+   * The value associated with the LazyFieldLite object is stored in one or more of the following
+   * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as
+   * follows.
+   * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
+   *    this state while the value for the object has not yet been parsed.
+   * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
+   *    some caller needs to access the value (by invoking getValue()).
+   * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
+   *    recomputing the ByteString representation on each call. Instead, when the value is parsed
+   *    from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since
+   *    that is the ByteString representation of value).
+   * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
+   *    delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
+   *    LazyFieldLite.toByteString().
+   *
+   * Given the above conditions, any caller that needs a serialized representation of this object
+   * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it
+   * directly; if both of those are null, it can look at the parsed value field. Similarly, any
+   * caller that needs a parsed value must first check if the value field is already non-null, if
+   * not it must parse the value from delayedBytes.
+   */
+
+  /**
+   * A delayed-parsed version of the contents of this field. When this field is non-null, then the
+   * "value" field is allowed to be null until the time that the value needs to be read.
+   *
+   * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null.
+   * {@code value} and {@code memoizedBytes} will be initialized lazily.
+   */
+  private ByteString delayedBytes;
+
+  /**
+   * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It
+   * is only guaranteed to be non-null if this message was initialized using bytes and an
+   * {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has
+   * been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
+   */
+  private ExtensionRegistryLite extensionRegistry;
+
+  /**
+   * The parsed value. When this is null and a caller needs access to the MessageLite value, then
+   * {@code delayedBytes} will be parsed lazily at that time.
+   */
+  protected volatile MessageLite value;
+
+  /**
+   * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to
+   * not have to recompute its return-value on each invocation.
+   * TODO(yatin): Figure out whether this optimization is actually necessary.
+   */
+  private volatile ByteString memoizedBytes;
+
+  /**
+   * Constructs a LazyFieldLite with bytes that will be parsed lazily.
+   */
+  public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+    checkArguments(extensionRegistry, bytes);
+    this.extensionRegistry = extensionRegistry;
+    this.delayedBytes = bytes;
+  }
+
+  /**
+   * Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
+   */
+  public LazyFieldLite() {
+  }
+
+  /**
+   * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse
+   * the extensions in the value as it has no ExtensionRegistry.
+   */
+  public static LazyFieldLite fromValue(MessageLite value) {
+    LazyFieldLite lf = new LazyFieldLite();
+    lf.setValue(value);
+    return lf;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    
+    if (!(o instanceof LazyFieldLite)) {
+      return false;
+    }
+
+    LazyFieldLite other = (LazyFieldLite) o;
+    
+    // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a
+    // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an
+    // actual message (if necessary) and call equals on the message itself. This implies that two
+    // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field.
+    MessageLite value1 = value;
+    MessageLite value2 = other.value;
+    if (value1 == null && value2 == null) {
+      return toByteString().equals(other.toByteString());
+    } else if (value1 != null && value2 != null) {
+      return value1.equals(value2);
+    } else if (value1 != null) {
+      return value1.equals(other.getValue(value1.getDefaultInstanceForType()));
+    } else {
+      return getValue(value2.getDefaultInstanceForType()).equals(value2);
+    }
+  }
+  
+  @Override
+  public int hashCode() {
+    // We can't provide a memoizable hash code for lazy fields. The byte strings may have different
+    // hash codes but evaluate to equivalent messages. And we have no facility for constructing
+    // a message here if we were not already holding a value.
+    return 1;
+  }
+  
+  /**
+   * Determines whether this LazyFieldLite instance represents the default instance of this type.
+   */
+  public boolean containsDefaultInstance() {
+    return memoizedBytes == ByteString.EMPTY
+        || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY);
+  }
+
+  /**
+   * Clears the value state of this instance.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void clear() {
+    // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another
+    // value, but there is no guarantee that it will contain all extensions that were directly set
+    // on the values that need to be merged.
+    delayedBytes = null;
+    value = null;
+    memoizedBytes = null;
+  }
+
+  /**
+   * Overrides the contents of this LazyField.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void set(LazyFieldLite other) {
+    this.delayedBytes = other.delayedBytes;
+    this.value = other.value;
+    this.memoizedBytes = other.memoizedBytes;
+    // If the other LazyFieldLite was created by directly setting the value rather than first by
+    // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing
+    // extensionRegistry, which has no guarantees that it has all the extensions that will be
+    // directly set on the value.
+    if (other.extensionRegistry != null) {
+      this.extensionRegistry = other.extensionRegistry;
+    }
+  }
+
+  /**
+   * Returns message instance. It may do some thread-safe delayed parsing of bytes.
+   *
+   * @param defaultInstance its message's default instance. It's also used to get parser for the
+   * message type.
+   */
+  public MessageLite getValue(MessageLite defaultInstance) {
+    ensureInitialized(defaultInstance);
+    return value;
+  }
+
+  /**
+   * Sets the value of the instance and returns the old value without delay parsing anything.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public MessageLite setValue(MessageLite value) {
+    MessageLite originalValue = this.value;
+    this.delayedBytes = null;
+    this.memoizedBytes = null;
+    this.value = value;
+    return originalValue;
+  }
+
+  /**
+   * Merges another instance's contents. In some cases may drop some extensions if both fields
+   * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this
+   * field will copy over that {@code ExtensionRegistry}.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void merge(LazyFieldLite other) {
+    if (other.containsDefaultInstance()) {
+      return;
+    }
+
+    if (this.containsDefaultInstance()) {
+      set(other);
+      return;
+    }
+
+    // If the other field has an extension registry but this does not, copy over the other extension
+    // registry.
+    if (this.extensionRegistry == null) {
+      this.extensionRegistry = other.extensionRegistry;
+    }
+
+    // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+    // the (probably rare) case that they have different extension registries there is a chance that
+    // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+    // to outway the benefits of combining the extension registries, which is not normally done for
+    // lite protos anyways.
+    if (this.delayedBytes != null && other.delayedBytes != null) {
+      this.delayedBytes = this.delayedBytes.concat(other.delayedBytes);
+      return;
+    }
+
+    // At least one is parsed and both contain data. We won't drop any extensions here directly, but
+    // in the case that the extension registries are not the same then we might in the future if we
+    // need to serialze and parse a message again.
+    if (this.value == null && other.value != null) {
+      setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry));
+      return;
+    } else if (this.value != null && other.value == null) {
+      setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry));
+      return;
+    }
+
+    // At this point we have two fully parsed messages. We can't merge directly from one to the
+    // other because only generated builder code contains methods to mergeFrom another parsed
+    // message. We have to serialize one instance and then merge the bytes into the other. This may
+    // drop extensions from one of the messages if one of the values had an extension set on it
+    // directly.
+    //
+    // To mitigate this we prefer serializing a message that has an extension registry, and
+    // therefore a chance that all extensions set on it are in that registry.
+    //
+    // NOTE: The check for other.extensionRegistry not being null must come first because at this
+    // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be
+    // null either.
+    if (other.extensionRegistry != null) {
+      setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry));
+      return;
+    } else if (this.extensionRegistry != null) {
+      setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry));
+      return;
+    } else {
+      // All extensions from the other message will be dropped because we have no registry.
+      setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
+      return;
+    }
+  }
+  
+  /**
+   * Merges another instance's contents from a stream.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    if (this.containsDefaultInstance()) {
+      setByteString(input.readBytes(), extensionRegistry);
+      return;
+    }
+
+    // If the other field has an extension registry but this does not, copy over the other extension
+    // registry.
+    if (this.extensionRegistry == null) {
+      this.extensionRegistry = extensionRegistry;
+    }
+
+    // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+    // the (probably rare) case that they have different extension registries there is a chance that
+    // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+    // to outway the benefits of combining the extension registries, which is not normally done for
+    // lite protos anyways.
+    if (this.delayedBytes != null) {
+      setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry);
+      return;
+    }
+
+    // We are parsed and both contain data. We won't drop any extensions here directly, but in the
+    // case that the extension registries are not the same then we might in the future if we
+    // need to serialize and parse a message again.
+    try {
+      setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build());
+    } catch (InvalidProtocolBufferException e) {
+      // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+      // was invalid.
+    }
+  }
+
+  private static MessageLite mergeValueAndBytes(
+      MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
+    try {
+      return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build();
+    } catch (InvalidProtocolBufferException e) {
+      // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+      // was invalid.
+      return value;
+    }
+  }
+
+  /**
+   * Sets this field with bytes to delay-parse.
+   */
+  public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
+    checkArguments(extensionRegistry, bytes);
+    this.delayedBytes = bytes;
+    this.extensionRegistry = extensionRegistry;
+    this.value = null;
+    this.memoizedBytes = null;
+  }
+
+  /**
+   * Due to the optional field can be duplicated at the end of serialized
+   * bytes, which will make the serialized size changed after LazyField
+   * parsed. Be careful when using this method.
+   */
+  public int getSerializedSize() {
+    // We *must* return delayed bytes size if it was ever set because the dependent messages may
+    // have memoized serialized size based off of it.
+    if (memoizedBytes != null) {
+      return memoizedBytes.size();
+    } else if (delayedBytes != null) {
+      return delayedBytes.size();
+    } else if (value != null) {
+      return value.getSerializedSize();
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Returns a BytesString for this field in a thread-safe way.
+   */
+  public ByteString toByteString() {
+    if (memoizedBytes != null) {
+      return memoizedBytes;
+    }
+    // We *must* return delayed bytes if it was set because the dependent messages may have
+    // memoized serialized size based off of it.
+    if (delayedBytes != null) {
+      return delayedBytes;
+    }
+    synchronized (this) {
+      if (memoizedBytes != null) {
+        return memoizedBytes;
+      }
+      if (value == null) {
+        memoizedBytes = ByteString.EMPTY;
+      } else {
+        memoizedBytes = value.toByteString();
+      }
+      return memoizedBytes;
+    }
+  }
+
+  /**
+   * Might lazily parse the bytes that were previously passed in. Is thread-safe.
+   */
+  protected void ensureInitialized(MessageLite defaultInstance) {
+    if (value != null) {
+      return;
+    }
+    synchronized (this) {
+      if (value != null) {
+        return;
+      }
+      try {
+        if (delayedBytes != null) {
+          // The extensionRegistry shouldn't be null here since we have delayedBytes.
+          MessageLite parsedValue = defaultInstance.getParserForType()
+              .parseFrom(delayedBytes, extensionRegistry);
+          this.value = parsedValue;
+          this.memoizedBytes = delayedBytes;
+        } else {
+          this.value = defaultInstance;
+          this.memoizedBytes = ByteString.EMPTY;
+        }
+      } catch (InvalidProtocolBufferException e) {
+        // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
+        // was invalid.
+        this.value = defaultInstance;
+        this.memoizedBytes = ByteString.EMPTY;
+      }
+    }
+  }
+
+
+  private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+    if (extensionRegistry == null) {
+      throw new NullPointerException("found null ExtensionRegistry");
+    }
+    if (bytes == null) {
+      throw new NullPointerException("found null ByteString");
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
new file mode 100644
index 0000000..d474c51
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -0,0 +1,423 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link LazyStringList} that wraps an ArrayList. Each
+ * element is one of String, ByteString, or byte[]. It caches the last one
+ * requested which is most likely the one needed next. This minimizes memory
+ * usage while satisfying the most common use cases.
+ * <p>
+ * <strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
+ * and at least one of the threads modifies the list structurally, it
+ * <i>must</i> be synchronized externally.  (A structural modification is
+ * any operation that adds or deletes one or more elements, or explicitly
+ * resizes the backing array; merely setting the value of an element is not
+ * a structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the list.
+ * <p>
+ * If the implementation is accessed via concurrent reads, this is thread safe.
+ * Conversions are done in a thread safe manner. It's possible that the
+ * conversion may happen more than once if two threads attempt to access the
+ * same element and the modifications were not visible to each other, but this
+ * will not result in any corruption of the list or change in behavior other
+ * than performance.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class LazyStringArrayList extends AbstractProtobufList<String>
+    implements LazyStringList, RandomAccess {
+
+  private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  static LazyStringArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+
+  // For compatibility with older runtimes.
+  public static final LazyStringList EMPTY = EMPTY_LIST;
+
+  private final List<Object> list;
+
+  public LazyStringArrayList() {
+    this(DEFAULT_CAPACITY);
+  }
+
+  public LazyStringArrayList(int intialCapacity) {
+    this(new ArrayList<Object>(intialCapacity));
+  }
+
+  public LazyStringArrayList(LazyStringList from) {
+    list = new ArrayList<Object>(from.size());
+    addAll(from);
+  }
+
+  public LazyStringArrayList(List<String> from) {
+    this(new ArrayList<Object>(from));
+  }
+  
+  private LazyStringArrayList(ArrayList<Object> list) {
+    this.list = list;
+  }
+
+  @Override
+  public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size()) {
+      throw new IllegalArgumentException();
+    }
+    ArrayList<Object> newList = new ArrayList<Object>(capacity);
+    newList.addAll(list);
+    return new LazyStringArrayList(newList);
+  }
+
+  @Override
+  public String get(int index) {
+    Object o = list.get(index);
+    if (o instanceof String) {
+      return (String) o;
+    } else if (o instanceof ByteString) {
+      ByteString bs = (ByteString) o;
+      String s = bs.toStringUtf8();
+      if (bs.isValidUtf8()) {
+        list.set(index, s);
+      }
+      return s;
+    } else {
+      byte[] ba = (byte[]) o;
+      String s = Internal.toStringUtf8(ba);
+      if (Internal.isValidUtf8(ba)) {
+        list.set(index, s);
+      }
+      return s;
+    }
+  }
+
+  @Override
+  public int size() {
+    return list.size();
+  }
+
+  @Override
+  public String set(int index, String s) {
+    ensureIsMutable();
+    Object o = list.set(index, s);
+    return asString(o);
+  }
+
+  @Override
+  public void add(int index, String element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+  
+  private void add(int index, ByteString element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+  
+  private void add(int index, byte[] element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends String> c) {
+    // The default implementation of AbstractCollection.addAll(Collection)
+    // delegates to add(Object). This implementation instead delegates to
+    // addAll(int, Collection), which makes a special case for Collections
+    // which are instances of LazyStringList.
+    return addAll(size(), c);
+  }
+
+  @Override
+  public boolean addAll(int index, Collection<? extends String> c) {
+    ensureIsMutable();
+    // When copying from another LazyStringList, directly copy the underlying
+    // elements rather than forcing each element to be decoded to a String.
+    Collection<?> collection = c instanceof LazyStringList
+        ? ((LazyStringList) c).getUnderlyingElements() : c;
+    boolean ret = list.addAll(index, collection);
+    modCount++;
+    return ret;
+  }
+
+  @Override
+  public boolean addAllByteString(Collection<? extends ByteString> values) {
+    ensureIsMutable();
+    boolean ret = list.addAll(values);
+    modCount++;
+    return ret;
+  }
+
+  @Override
+  public boolean addAllByteArray(Collection<byte[]> c) {
+    ensureIsMutable();
+    boolean ret = list.addAll(c);
+    modCount++;
+    return ret;
+  }
+
+  @Override
+  public String remove(int index) {
+    ensureIsMutable();
+    Object o = list.remove(index);
+    modCount++;
+    return asString(o);
+  }
+
+  @Override
+  public void clear() {
+    ensureIsMutable();
+    list.clear();
+    modCount++;
+  }
+
+  @Override
+  public void add(ByteString element) {
+    ensureIsMutable();
+    list.add(element);
+    modCount++;
+  }
+  
+  @Override
+  public void add(byte[] element) {
+    ensureIsMutable();
+    list.add(element);
+    modCount++;
+  }
+
+  @Override
+  public Object getRaw(int index) {
+    return list.get(index);
+  }
+  
+  @Override
+  public ByteString getByteString(int index) {
+    Object o = list.get(index);
+    ByteString b = asByteString(o);
+    if (b != o) {
+      list.set(index, b);
+    }
+    return b;
+  }
+  
+  @Override
+  public byte[] getByteArray(int index) {
+    Object o = list.get(index);
+    byte[] b = asByteArray(o);
+    if (b != o) {
+      list.set(index, b);
+    }
+    return b;
+  }
+
+  @Override
+  public void set(int index, ByteString s) {
+    setAndReturn(index, s);
+  }
+  
+  private Object setAndReturn(int index, ByteString s) {
+    ensureIsMutable();
+    return list.set(index, s);
+  }
+
+  @Override
+  public void set(int index, byte[] s) {
+    setAndReturn(index, s);
+  }
+  
+  private Object setAndReturn(int index, byte[] s) {
+    ensureIsMutable();
+    return list.set(index, s);
+  }
+
+  private static String asString(Object o) {
+    if (o instanceof String) {
+      return (String) o;
+    } else if (o instanceof ByteString) {
+      return ((ByteString) o).toStringUtf8();
+    } else {
+      return Internal.toStringUtf8((byte[]) o);
+    }
+  }
+  
+  private static ByteString asByteString(Object o) {
+    if (o instanceof ByteString) {
+      return (ByteString) o;
+    } else if (o instanceof String) {
+      return ByteString.copyFromUtf8((String) o);
+    } else {
+      return ByteString.copyFrom((byte[]) o);
+    }
+  }
+  
+  private static byte[] asByteArray(Object o) {
+    if (o instanceof byte[]) {
+      return (byte[]) o;
+    } else if (o instanceof String) {
+      return Internal.toByteArray((String) o);
+    } else {
+      return ((ByteString) o).toByteArray();
+    }
+  }
+
+  @Override
+  public List<?> getUnderlyingElements() {
+    return Collections.unmodifiableList(list);
+  }
+
+  @Override
+  public void mergeFrom(LazyStringList other) {
+    ensureIsMutable();
+    for (Object o : other.getUnderlyingElements()) {
+      if (o instanceof byte[]) {
+        byte[] b = (byte[]) o;
+        // Byte array's content is mutable so they should be copied rather than
+        // shared when merging from one message to another.
+        list.add(Arrays.copyOf(b, b.length));
+      } else {
+        list.add(o);
+      }
+    }
+  }
+
+  private static class ByteArrayListView extends AbstractList<byte[]>
+      implements RandomAccess {
+    private final LazyStringArrayList list;
+    
+    ByteArrayListView(LazyStringArrayList list) {
+      this.list = list;
+    }
+    
+    @Override
+    public byte[] get(int index) {
+      return list.getByteArray(index);
+    }
+
+    @Override
+    public int size() {
+      return list.size();
+    }
+
+    @Override
+    public byte[] set(int index, byte[] s) {
+      Object o = list.setAndReturn(index, s);
+      modCount++;
+      return asByteArray(o);
+    }
+
+    @Override
+    public void add(int index, byte[] s) {
+      list.add(index, s);
+      modCount++;
+    }
+
+    @Override
+    public byte[] remove(int index) {
+      Object o = list.remove(index);
+      modCount++;
+      return asByteArray(o);
+    }
+  }
+  
+  @Override
+  public List<byte[]> asByteArrayList() {
+    return new ByteArrayListView(this);
+  }
+
+  private static class ByteStringListView extends AbstractList<ByteString>
+      implements RandomAccess {
+    private final LazyStringArrayList list;
+
+    ByteStringListView(LazyStringArrayList list) {
+      this.list = list;
+    }
+
+    @Override
+    public ByteString get(int index) {
+      return list.getByteString(index);
+    }
+
+    @Override
+    public int size() {
+      return list.size();
+    }
+
+    @Override
+    public ByteString set(int index, ByteString s) {
+      Object o = list.setAndReturn(index, s);
+      modCount++;
+      return asByteString(o);
+    }
+
+    @Override
+    public void add(int index, ByteString s) {
+      list.add(index, s);
+      modCount++;
+    }
+
+    @Override
+    public ByteString remove(int index) {
+      Object o = list.remove(index);
+      modCount++;
+      return asByteString(o);
+    }
+  }
+
+  @Override
+  public List<ByteString> asByteStringList() {
+    return new ByteStringListView(this);
+  }
+
+  @Override
+  public LazyStringList getUnmodifiableView() {
+    if (isModifiable()) {
+      return new UnmodifiableLazyStringList(this);
+    }
+    return this;
+  }
+
+}
diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringList.java b/java/core/src/main/java/com/google/protobuf/LazyStringList.java
new file mode 100644
index 0000000..3eeedca
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringList.java
@@ -0,0 +1,174 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * An interface extending {@code List<String>} that also provides access to the
+ * items of the list as UTF8-encoded ByteString or byte[] objects. This is
+ * used by the protocol buffer implementation to support lazily converting bytes
+ * parsed over the wire to String objects until needed and also increases the
+ * efficiency of serialization if the String was never requested as the
+ * ByteString or byte[] is already cached. The ByteString methods are used in
+ * immutable API only and byte[] methods used in mutable API only for they use
+ * different representations for string/bytes fields.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public interface LazyStringList extends ProtocolStringList {
+
+  /**
+   * Returns the element at the specified position in this list as a ByteString.
+   *
+   * @param index index of the element to return
+   * @return the element at the specified position in this list
+   * @throws IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  ByteString getByteString(int index);
+
+  /**
+   * Returns the element at the specified position in this list as an Object
+   * that will either be a String or a ByteString.
+   *
+   * @param index index of the element to return
+   * @return the element at the specified position in this list
+   * @throws IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  Object getRaw(int index);
+
+  /**
+   * Returns the element at the specified position in this list as byte[].
+   *
+   * @param index index of the element to return
+   * @return the element at the specified position in this list
+   * @throws IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  byte[] getByteArray(int index);
+
+  /**
+   * Appends the specified element to the end of this list (optional
+   * operation).
+   *
+   * @param element element to be appended to this list
+   * @throws UnsupportedOperationException if the <tt>add</tt> operation
+   *         is not supported by this list
+   */
+  void add(ByteString element);
+
+  /**
+   * Appends the specified element to the end of this list (optional
+   * operation).
+   *
+   * @param element element to be appended to this list
+   * @throws UnsupportedOperationException if the <tt>add</tt> operation
+   *         is not supported by this list
+   */
+  void add(byte[] element);
+
+  /**
+   * Replaces the element at the specified position in this list with the
+   * specified element (optional operation).
+   *
+   * @param index index of the element to replace
+   * @param element the element to be stored at the specified position
+   * @throws UnsupportedOperationException if the <tt>set</tt> operation
+   *         is not supported by this list
+   *         IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  void set(int index, ByteString element);
+  
+  /**
+   * Replaces the element at the specified position in this list with the
+   * specified element (optional operation).
+   *
+   * @param index index of the element to replace
+   * @param element the element to be stored at the specified position
+   * @throws UnsupportedOperationException if the <tt>set</tt> operation
+   *         is not supported by this list
+   *         IndexOutOfBoundsException if the index is out of range
+   *         ({@code index < 0 || index >= size()})
+   */
+  void set(int index, byte[] element);
+
+  /**
+   * Appends all elements in the specified ByteString collection to the end of
+   * this list.
+   *
+   * @param c collection whose elements are to be added to this list
+   * @return true if this list changed as a result of the call
+   * @throws UnsupportedOperationException if the <tt>addAllByteString</tt>
+   *         operation is not supported by this list
+   */
+  boolean addAllByteString(Collection<? extends ByteString> c);
+
+  /**
+   * Appends all elements in the specified byte[] collection to the end of
+   * this list.
+   *
+   * @param c collection whose elements are to be added to this list
+   * @return true if this list changed as a result of the call
+   * @throws UnsupportedOperationException if the <tt>addAllByteArray</tt>
+   *         operation is not supported by this list
+   */
+  boolean addAllByteArray(Collection<byte[]> c);
+
+  /**
+   * Returns an unmodifiable List of the underlying elements, each of which is
+   * either a {@code String} or its equivalent UTF-8 encoded {@code ByteString}
+   * or byte[]. It is an error for the caller to modify the returned
+   * List, and attempting to do so will result in an
+   * {@link UnsupportedOperationException}.
+   */
+  List<?> getUnderlyingElements();
+
+  /**
+   * Merges all elements from another LazyStringList into this one. This method
+   * differs from {@link #addAll(Collection)} on that underlying byte arrays are
+   * copied instead of reference shared. Immutable API doesn't need to use this
+   * method as byte[] is not used there at all.
+   */
+  void mergeFrom(LazyStringList other);
+
+  /**
+   * Returns a mutable view of this list. Changes to the view will be made into
+   * the original list. This method is used in mutable API only.
+   */
+  List<byte[]> asByteArrayList();
+
+  /** Returns an unmodifiable view of the list. */
+  LazyStringList getUnmodifiableView();
+}
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
new file mode 100644
index 0000000..bc4475d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -0,0 +1,269 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.LongList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link LongList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class LongArrayList extends AbstractProtobufList<Long> implements LongList, RandomAccess {
+  
+  private static final LongArrayList EMPTY_LIST = new LongArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static LongArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private long[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} with default capacity.
+   */
+  LongArrayList() {
+    this(new long[DEFAULT_CAPACITY], 0);
+  }
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
+   */
+  private LongArrayList(long[] array, int size) {
+    this.array = array;
+    this.size = size;
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof IntArrayList)) {
+      return super.equals(o);
+    }
+    LongArrayList other = (LongArrayList) o;
+    if (size != other.size) {
+      return false;
+    }
+    
+    final long[] arr = other.array;
+    for (int i = 0; i < size; i++) {
+      if (array[i] != arr[i]) {
+        return false;
+      }
+    }
+    
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = 1;
+    for (int i = 0; i < size; i++) {
+      result = (31 * result) + Internal.hashLong(array[i]);
+    }
+    return result;
+  }
+
+  @Override
+  public LongList mutableCopyWithCapacity(int capacity) {
+    if (capacity < size) {
+      throw new IllegalArgumentException();
+    }
+    return new LongArrayList(Arrays.copyOf(array, capacity), size);
+  }
+  
+  @Override
+  public Long get(int index) {
+    return getLong(index);
+  }
+
+  @Override
+  public long getLong(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Long set(int index, Long element) {
+    return setLong(index, element);
+  }
+
+  @Override
+  public long setLong(int index, long element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    long previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Long element) {
+    addLong(index, element);
+  }
+
+  /**
+   * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addLong(long element) {
+    addLong(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Long)} but more efficient in that it doesn't box the element.
+   */
+  private void addLong(int index, long element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      long[] newArray = new long[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Long> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another LongArrayList to avoid boxing elements.
+    if (!(collection instanceof LongArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    LongArrayList list = (LongArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Long remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    long value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
new file mode 100644
index 0000000..31414bb
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -0,0 +1,433 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Implements MapEntry messages.
+ * 
+ * In reflection API, map fields will be treated as repeated message fields and
+ * each map entry is accessed as a message. This MapEntry class is used to
+ * represent these map entry messages in reflection API.
+ * 
+ * Protobuf internal. Users shouldn't use this class.
+ */
+public final class MapEntry<K, V> extends AbstractMessage {
+  private static class Metadata<K, V> {
+    public final Descriptor descriptor;  
+    public final MapEntry<K, V> defaultInstance;
+    public final AbstractParser<MapEntry<K, V>> parser;
+    
+    public Metadata(
+        final Descriptor descriptor, final MapEntry<K, V> defaultInstance) {
+      this.descriptor = descriptor;
+      this.defaultInstance = defaultInstance;
+      final Metadata<K, V> thisMetadata = this;
+      this.parser = new AbstractParser<MapEntry<K, V>>() {
+        private final Parser<MapEntryLite<K, V>> dataParser =
+            defaultInstance.data.getParserForType();
+        @Override
+        public MapEntry<K, V> parsePartialFrom(
+            CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+            throws InvalidProtocolBufferException {
+          MapEntryLite<K, V> data =
+              dataParser.parsePartialFrom(input, extensionRegistry);
+          return new MapEntry<K, V>(thisMetadata, data);
+        }
+        
+      };
+    }
+  }
+  
+  private final Metadata<K, V> metadata;
+  private final MapEntryLite<K, V> data;
+  
+  /** Create a default MapEntry instance. */
+  private MapEntry(Descriptor descriptor,
+      WireFormat.FieldType keyType, K defaultKey,
+      WireFormat.FieldType valueType, V defaultValue) {
+    this.data = MapEntryLite.newDefaultInstance(
+        keyType, defaultKey, valueType, defaultValue);
+    this.metadata = new Metadata<K, V>(descriptor, this); 
+  }
+  
+  /** Create a new MapEntry message. */
+  private MapEntry(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+    this.metadata = metadata;
+    this.data = data;
+  }
+  
+  /**
+   * Create a default MapEntry instance. A default MapEntry instance should be
+   * created only once for each map entry message type. Generated code should
+   * store the created default instance and use it later to create new MapEntry
+   * messages of the same type. 
+   */
+  public static <K, V> MapEntry<K, V> newDefaultInstance(
+      Descriptor descriptor,
+      WireFormat.FieldType keyType, K defaultKey,
+      WireFormat.FieldType valueType, V defaultValue) {
+    return new MapEntry<K, V>(
+        descriptor, keyType, defaultKey, valueType, defaultValue);
+  }
+  
+  public K getKey() {
+    return data.getKey();
+  }
+  
+  public V getValue() {
+    return data.getValue();
+  }
+  
+  @Override
+  public int getSerializedSize() {
+    return data.getSerializedSize();
+  }
+  
+  @Override
+  public void writeTo(CodedOutputStream output) throws IOException {
+    data.writeTo(output);
+  }
+  
+  @Override
+  public boolean isInitialized() {
+    return data.isInitialized();
+  }
+  
+  @Override
+  public Parser<MapEntry<K, V>> getParserForType() {
+    return metadata.parser;
+  }
+
+  @Override
+  public Builder<K, V> newBuilderForType() {
+    return new Builder<K, V>(metadata);
+  }
+  
+  @Override
+  public Builder<K, V> toBuilder() {
+    return new Builder<K, V>(metadata, data);
+  }
+
+  @Override
+  public MapEntry<K, V> getDefaultInstanceForType() {
+    return metadata.defaultInstance;
+  }
+
+  @Override
+  public Descriptor getDescriptorForType() {
+    return metadata.descriptor;
+  }
+
+  @Override
+  public Map<FieldDescriptor, Object> getAllFields() {
+    final TreeMap<FieldDescriptor, Object> result =
+        new TreeMap<FieldDescriptor, Object>();
+    for (final FieldDescriptor field : metadata.descriptor.getFields()) {
+      if (hasField(field)) {
+        result.put(field, getField(field));
+      }
+    }
+    return Collections.unmodifiableMap(result);
+  }
+  
+  private void checkFieldDescriptor(FieldDescriptor field) {
+    if (field.getContainingType() != metadata.descriptor) {
+      throw new RuntimeException(
+          "Wrong FieldDescriptor \"" + field.getFullName()
+          + "\" used in message \"" + metadata.descriptor.getFullName()); 
+    }
+  }
+
+  @Override
+  public boolean hasField(FieldDescriptor field) {
+    checkFieldDescriptor(field);;
+    // A MapEntry always contains two fields.
+    return true;
+  }
+
+  @Override
+  public Object getField(FieldDescriptor field) {
+    checkFieldDescriptor(field);
+    Object result = field.getNumber() == 1 ? getKey() : getValue();
+    // Convert enums to EnumValueDescriptor.
+    if (field.getType() == FieldDescriptor.Type.ENUM) {
+      result = field.getEnumType().findValueByNumberCreatingIfUnknown(
+          (java.lang.Integer) result);
+    }
+    return result;
+  }
+
+  @Override
+  public int getRepeatedFieldCount(FieldDescriptor field) {
+    throw new RuntimeException(
+        "There is no repeated field in a map entry message.");
+  }
+
+  @Override
+  public Object getRepeatedField(FieldDescriptor field, int index) {
+    throw new RuntimeException(
+        "There is no repeated field in a map entry message.");
+  }
+
+  @Override
+  public UnknownFieldSet getUnknownFields() {
+    return UnknownFieldSet.getDefaultInstance();
+  }
+
+  /**
+   * Builder to create {@link MapEntry} messages.
+   */
+  public static class Builder<K, V>
+      extends AbstractMessage.Builder<Builder<K, V>> {
+    private final Metadata<K, V> metadata;
+    private MapEntryLite<K, V> data;
+    private MapEntryLite.Builder<K, V> dataBuilder;
+    
+    private Builder(Metadata<K, V> metadata) {
+      this.metadata = metadata;
+      this.data = metadata.defaultInstance.data;
+      this.dataBuilder = null;
+    }
+    
+    private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+      this.metadata = metadata;
+      this.data = data;
+      this.dataBuilder = null;
+    }
+    
+    public K getKey() {
+      return dataBuilder == null ? data.getKey() : dataBuilder.getKey();
+    }
+    
+    public V getValue() {
+      return dataBuilder == null ? data.getValue() : dataBuilder.getValue();
+    }
+    
+    private void ensureMutable() {
+      if (dataBuilder == null) {
+        dataBuilder = data.toBuilder();
+      }
+    }
+    
+    public Builder<K, V> setKey(K key) {
+      ensureMutable();
+      dataBuilder.setKey(key);
+      return this;
+    }
+    
+    public Builder<K, V> clearKey() {
+      ensureMutable();
+      dataBuilder.clearKey();
+      return this;
+    }
+    
+    public Builder<K, V> setValue(V value) {
+      ensureMutable();
+      dataBuilder.setValue(value);
+      return this;
+    }
+    
+    public Builder<K, V> clearValue() {
+      ensureMutable();
+      dataBuilder.clearValue();
+      return this;
+    }
+
+    @Override
+    public MapEntry<K, V> build() {
+      MapEntry<K, V> result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @Override
+    public MapEntry<K, V> buildPartial() {
+      if (dataBuilder != null) {
+        data = dataBuilder.buildPartial();
+        dataBuilder = null;
+      }
+      return new MapEntry<K, V>(metadata, data);
+    }
+
+    @Override
+    public Descriptor getDescriptorForType() {
+      return metadata.descriptor;
+    }
+    
+    private void checkFieldDescriptor(FieldDescriptor field) {
+      if (field.getContainingType() != metadata.descriptor) {
+        throw new RuntimeException(
+            "Wrong FieldDescriptor \"" + field.getFullName()
+            + "\" used in message \"" + metadata.descriptor.getFullName()); 
+      }
+    }
+
+    @Override
+    public com.google.protobuf.Message.Builder newBuilderForField(
+        FieldDescriptor field) {
+      checkFieldDescriptor(field);;
+      // This method should be called for message fields and in a MapEntry
+      // message only the value field can possibly be a message field.
+      if (field.getNumber() != 2
+          || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+        throw new RuntimeException(
+            "\"" + field.getFullName() + "\" is not a message value field.");
+      }
+      return ((Message) data.getValue()).newBuilderForType();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Builder<K, V> setField(FieldDescriptor field, Object value) {
+      checkFieldDescriptor(field);
+      if (field.getNumber() == 1) {
+        setKey((K) value);
+      } else {
+        if (field.getType() == FieldDescriptor.Type.ENUM) {
+          value = ((EnumValueDescriptor) value).getNumber();
+        }
+        setValue((V) value);
+      }
+      return this;
+    }
+
+    @Override
+    public Builder<K, V> clearField(FieldDescriptor field) {
+      checkFieldDescriptor(field);
+      if (field.getNumber() == 1) {
+        clearKey();
+      } else {
+        clearValue();
+      }
+      return this;
+    }
+
+    @Override
+    public Builder<K, V> setRepeatedField(FieldDescriptor field, int index,
+        Object value) {
+      throw new RuntimeException(
+          "There is no repeated field in a map entry message.");
+    }
+
+    @Override
+    public Builder<K, V> addRepeatedField(FieldDescriptor field, Object value) {
+      throw new RuntimeException(
+          "There is no repeated field in a map entry message.");
+    }
+
+    @Override
+    public Builder<K, V> setUnknownFields(UnknownFieldSet unknownFields) {
+      // Unknown fields are discarded for MapEntry message.
+      return this;
+    }
+
+    @Override
+    public MapEntry<K, V> getDefaultInstanceForType() {
+      return metadata.defaultInstance;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      if (dataBuilder != null) {
+        return dataBuilder.isInitialized();
+      } else {
+        return data.isInitialized();
+      }
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final TreeMap<FieldDescriptor, Object> result =
+          new TreeMap<FieldDescriptor, Object>();
+      for (final FieldDescriptor field : metadata.descriptor.getFields()) {
+        if (hasField(field)) {
+          result.put(field, getField(field));
+        }
+      }
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public boolean hasField(FieldDescriptor field) {
+      checkFieldDescriptor(field);
+      return true;
+    }
+
+    @Override
+    public Object getField(FieldDescriptor field) {
+      checkFieldDescriptor(field);
+      Object result = field.getNumber() == 1 ? getKey() : getValue();
+      // Convert enums to EnumValueDescriptor.
+      if (field.getType() == FieldDescriptor.Type.ENUM) {
+        result = field.getEnumType().findValueByNumberCreatingIfUnknown(
+            (java.lang.Integer) result);
+      }
+      return result;
+    }
+
+    @Override
+    public int getRepeatedFieldCount(FieldDescriptor field) {
+      throw new RuntimeException(
+          "There is no repeated field in a map entry message.");
+    }
+    
+    @Override
+    public Object getRepeatedField(FieldDescriptor field, int index) {
+      throw new RuntimeException(
+          "There is no repeated field in a map entry message.");
+    }
+    
+    @Override
+    public UnknownFieldSet getUnknownFields() {
+      return UnknownFieldSet.getDefaultInstance();
+    }
+
+    @Override
+    public Builder<K, V> clone() {
+      if (dataBuilder == null) {
+        return new Builder<K, V>(metadata, data);
+      } else {
+        return new Builder<K, V>(metadata, dataBuilder.build());
+      }
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
new file mode 100644
index 0000000..12c64ab
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -0,0 +1,337 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+
+/**
+ * Implements the lite version of map entry messages.
+ * 
+ * This class serves as an utility class to help do serialization/parsing of
+ * map entries. It's used in generated code and also in the full version
+ * MapEntry message.
+ * 
+ * Protobuf internal. Users shouldn't use.
+ */
+public class MapEntryLite<K, V>
+    extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
+  private static class Metadata<K, V> {
+    public final MapEntryLite<K, V> defaultInstance;
+    public final WireFormat.FieldType keyType;
+    public final WireFormat.FieldType valueType;
+    public final Parser<MapEntryLite<K, V>> parser;
+    public Metadata(
+        MapEntryLite<K, V> defaultInstance,
+        WireFormat.FieldType keyType,
+        WireFormat.FieldType valueType) {
+      this.defaultInstance = defaultInstance; 
+      this.keyType = keyType;
+      this.valueType = valueType;
+      final Metadata<K, V> finalThis = this;
+      this.parser = new AbstractParser<MapEntryLite<K, V>>() {
+        @Override
+        public MapEntryLite<K, V> parsePartialFrom(
+            CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+            throws InvalidProtocolBufferException {
+          return new MapEntryLite<K, V>(finalThis, input, extensionRegistry);
+        }
+      };
+    }
+  }
+  
+  private static final int KEY_FIELD_NUMBER = 1;
+  private static final int VALUE_FIELD_NUMBER = 2;
+  
+  private final Metadata<K, V> metadata;
+  private final K key;
+  private final V value;
+  
+  /** Creates a default MapEntryLite message instance. */
+  private MapEntryLite(
+      WireFormat.FieldType keyType, K defaultKey,
+      WireFormat.FieldType valueType, V defaultValue) {
+    this.metadata = new Metadata<K, V>(this, keyType, valueType);
+    this.key = defaultKey;
+    this.value = defaultValue;
+  }
+  
+  /** Creates a new MapEntryLite message. */
+  private MapEntryLite(Metadata<K, V> metadata, K key, V value) {
+    this.metadata = metadata;
+    this.key = key;
+    this.value = value;
+  }
+  
+  public K getKey() {
+    return key;
+  }
+  
+  public V getValue() {
+    return value;
+  }
+
+  /**
+   * Creates a default MapEntryLite message instance.
+   * 
+   * This method is used by generated code to create the default instance for
+   * a map entry message. The created default instance should be used to create
+   * new map entry messages of the same type. For each map entry message, only
+   * one default instance should be created. 
+   */
+  public static <K, V> MapEntryLite<K, V> newDefaultInstance(
+      WireFormat.FieldType keyType, K defaultKey,
+      WireFormat.FieldType valueType, V defaultValue) {
+    return new MapEntryLite<K, V>(
+        keyType, defaultKey, valueType, defaultValue);
+  }
+  
+  @Override
+  public void writeTo(CodedOutputStream output) throws IOException {
+    writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output);
+    writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output);
+  }
+
+  private void writeField(
+      int number, WireFormat.FieldType type, Object value,
+      CodedOutputStream output) throws IOException {
+    output.writeTag(number, type.getWireType());
+    FieldSet.writeElementNoTag(output, type, value);
+  }
+
+  private volatile int cachedSerializedSize = -1;
+  @Override
+  public int getSerializedSize() {
+    if (cachedSerializedSize != -1) {
+      return cachedSerializedSize;
+    }
+    int size = 0;
+    size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key);
+    size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value);
+    cachedSerializedSize = size;
+    return size;
+  }
+
+  private int getFieldSize(
+      int number, WireFormat.FieldType type, Object value) {
+    return CodedOutputStream.computeTagSize(number)
+        + FieldSet.computeElementSizeNoTag(type, value);
+  }
+  
+  /** Parsing constructor. */
+  private MapEntryLite(
+      Metadata<K, V> metadata,
+      CodedInputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    try {
+      K key = metadata.defaultInstance.key;
+      V value = metadata.defaultInstance.value;
+      while (true) {
+        int tag = input.readTag();
+        if (tag == 0) {
+          break;
+        }
+        if (tag == WireFormat.makeTag(
+                KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
+          key = mergeField(
+              input, extensionRegistry, metadata.keyType, key);
+        } else if (tag == WireFormat.makeTag(
+                       VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
+          value = mergeField(
+              input, extensionRegistry, metadata.valueType, value);
+        } else {
+          if (!input.skipField(tag)) {
+            break;
+          }
+        }
+      }
+      this.metadata = metadata;
+      this.key = key;
+      this.value = value;
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e.getMessage())
+          .setUnfinishedMessage(this);
+    }
+  }
+  
+  @SuppressWarnings("unchecked")
+  private <T> T mergeField(
+      CodedInputStream input, ExtensionRegistryLite extensionRegistry,
+      WireFormat.FieldType type, T value) throws IOException {
+    switch (type) {
+      case MESSAGE:
+        MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder();
+        input.readMessage(subBuilder, extensionRegistry);
+        return (T) subBuilder.buildPartial();
+      case ENUM:
+        return (T) (java.lang.Integer) input.readEnum();
+      case GROUP:
+        throw new RuntimeException("Groups are not allowed in maps.");
+      default:
+        return (T) FieldSet.readPrimitiveField(input, type, true);
+    }
+  }
+
+  @Override
+  public Parser<MapEntryLite<K, V>> getParserForType() {
+    return metadata.parser;
+  }
+
+  @Override
+  public Builder<K, V> newBuilderForType() {
+    return new Builder<K, V>(metadata);
+  }
+
+  @Override
+  public Builder<K, V> toBuilder() {
+    return new Builder<K, V>(metadata, key, value);
+  }
+
+  @Override
+  public MapEntryLite<K, V> getDefaultInstanceForType() {
+    return metadata.defaultInstance;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
+      return ((MessageLite) value).isInitialized();
+    }
+    return true;
+  }
+
+  /**
+   * Builder used to create {@link MapEntryLite} messages.
+   */
+  public static class Builder<K, V>
+      extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> {
+    private final Metadata<K, V> metadata;
+    private K key;
+    private V value;
+    
+    private Builder(Metadata<K, V> metadata) {
+      this.metadata = metadata;
+      this.key = metadata.defaultInstance.key;
+      this.value = metadata.defaultInstance.value;
+    }
+    
+    public K getKey() {
+      return key;
+    }
+    
+    public V getValue() {
+      return value;
+    }
+    
+    public Builder<K, V> setKey(K key) {
+      this.key = key;
+      return this;
+    }
+    
+    public Builder<K, V> setValue(V value) {
+      this.value = value;
+      return this;
+    }
+    
+    public Builder<K, V> clearKey() {
+      this.key = metadata.defaultInstance.key;
+      return this;
+    }
+    
+    public Builder<K, V> clearValue() {
+      this.value = metadata.defaultInstance.value;
+      return this;
+    }
+
+    @Override
+    public Builder<K, V> clear() {
+      this.key = metadata.defaultInstance.key;
+      this.value = metadata.defaultInstance.value;
+      return this;
+    }
+
+    @Override
+    public MapEntryLite<K, V> build() {
+      MapEntryLite<K, V> result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @Override
+    public MapEntryLite<K, V> buildPartial() {
+      return new MapEntryLite<K, V>(metadata, key, value);
+    }
+
+    @Override
+    public MessageLite getDefaultInstanceForType() {
+      return metadata.defaultInstance;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
+        return ((MessageLite) value).isInitialized();
+      }
+      return true;
+    }
+
+    private Builder(Metadata<K, V> metadata, K key, V value) {
+      this.metadata = metadata;
+      this.key = key;
+      this.value = value;
+    }
+    
+    @Override
+    public Builder<K, V> clone() {
+      return new Builder<K, V>(metadata, key, value);
+    }
+
+    @Override
+    public Builder<K, V> mergeFrom(
+        CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      MapEntryLite<K, V> entry =
+          new MapEntryLite<K, V>(metadata, input, extensionRegistry);
+      this.key = entry.key;
+      this.value = entry.value;
+      return this;
+    }
+
+    @Override
+    protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
new file mode 100644
index 0000000..907f0f7
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -0,0 +1,289 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.MapFieldLite.MutatabilityAwareMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Internal representation of map fields in generated messages.
+ * 
+ * This class supports accessing the map field as a {@link Map} to be used in
+ * generated API and also supports accessing the field as a {@link List} to be
+ * used in reflection API. It keeps track of where the data is currently stored
+ * and do necessary conversions between map and list.  
+ * 
+ * This class is a protobuf implementation detail. Users shouldn't use this
+ * class directly.
+ * 
+ * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap()
+ * and getList() concurrently in multiple threads. If write-access is needed,
+ * all access must be synchronized.
+ */
+public class MapField<K, V> implements MutabilityOracle {
+  /**
+   * Indicates where the data of this map field is currently stored.
+   * 
+   * MAP: Data is stored in mapData.
+   * LIST: Data is stored in listData.
+   * BOTH: mapData and listData have the same data.
+   *
+   * When the map field is accessed (through generated API or reflection API),
+   * it will shift between these 3 modes:
+   * 
+   *          getMap()   getList()   getMutableMap()   getMutableList()
+   *   MAP      MAP        BOTH          MAP               LIST
+   *   LIST     BOTH       LIST          MAP               LIST
+   *   BOTH     BOTH       BOTH          MAP               LIST
+   *   
+   * As the map field changes its mode, the list/map reference returned in a
+   * previous method call may be invalidated. 
+   */
+  private enum StorageMode {MAP, LIST, BOTH}
+
+  private volatile boolean isMutable;
+  private volatile StorageMode mode;
+  private MutatabilityAwareMap<K, V> mapData;
+  private List<Message> listData;
+  
+  // Convert between a map entry Message and a key-value pair.
+  private static interface Converter<K, V> {
+    Message convertKeyAndValueToMessage(K key, V value);
+    void convertMessageToKeyAndValue(Message message, Map<K, V> map);
+    
+    Message getMessageDefaultInstance();
+  }
+  
+  private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
+    private final MapEntry<K, V> defaultEntry;
+    public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
+      this.defaultEntry = defaultEntry;
+    }
+    
+    @Override
+    public Message convertKeyAndValueToMessage(K key, V value) {
+      return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
+    }
+    
+    @Override
+    public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
+      MapEntry<K, V> entry = (MapEntry<K, V>) message;
+      map.put(entry.getKey(), entry.getValue());
+    }
+
+    @Override
+    public Message getMessageDefaultInstance() {
+      return defaultEntry;
+    }
+  }
+  
+
+  private final Converter<K, V> converter;
+  
+  private MapField(
+      Converter<K, V> converter,
+      StorageMode mode,
+      Map<K, V> mapData) {
+    this.converter = converter;
+    this.isMutable = true;
+    this.mode = mode;
+    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+    this.listData = null;
+  }
+    
+  private MapField(
+      MapEntry<K, V> defaultEntry,
+      StorageMode mode,
+      Map<K, V> mapData) {
+    this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
+  }
+  
+  
+  /** Returns an immutable empty MapField. */
+  public static <K, V> MapField<K, V> emptyMapField(
+      MapEntry<K, V> defaultEntry) {
+    return new MapField<K, V>(
+        defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
+  }
+  
+  
+  /** Creates a new mutable empty MapField. */
+  public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
+    return new MapField<K, V>(
+        defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
+  }
+  
+  
+  private Message convertKeyAndValueToMessage(K key, V value) {
+    return converter.convertKeyAndValueToMessage(key, value);
+  }
+  
+  @SuppressWarnings("unchecked")
+  private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
+    converter.convertMessageToKeyAndValue(message, map);
+  }
+
+  private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) {
+    List<Message> listData = new ArrayList<Message>();
+    for (Map.Entry<K, V> entry : mapData.entrySet()) {
+      listData.add(
+          convertKeyAndValueToMessage(
+              entry.getKey(), entry.getValue()));
+    }
+    return listData;
+  }
+
+  private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) {
+    Map<K, V> mapData = new LinkedHashMap<K, V>();
+    for (Message item : listData) {
+      convertMessageToKeyAndValue(item, mapData);
+    }
+    return new MutatabilityAwareMap<K, V>(this, mapData);
+  }
+  
+  /** Returns the content of this MapField as a read-only Map. */
+  public Map<K, V> getMap() {
+    if (mode == StorageMode.LIST) {
+      synchronized (this) {
+        if (mode == StorageMode.LIST) {
+          mapData = convertListToMap(listData);
+          mode = StorageMode.BOTH;
+        }
+      }
+    }
+    return Collections.unmodifiableMap(mapData);
+  }
+  
+  /** Gets a mutable Map view of this MapField. */
+  public Map<K, V> getMutableMap() {
+    if (mode != StorageMode.MAP) {
+      if (mode == StorageMode.LIST) {
+        mapData = convertListToMap(listData);
+      }
+      listData = null;
+      mode = StorageMode.MAP; 
+    }
+    return mapData;
+  }
+  
+  public void mergeFrom(MapField<K, V> other) {
+    getMutableMap().putAll(MapFieldLite.copy(other.getMap()));
+  }
+  
+  public void clear() {
+    mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
+    mode = StorageMode.MAP;
+  }
+  
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean equals(Object object) {
+    if (!(object instanceof MapField)) {
+      return false;
+    }
+    MapField<K, V> other = (MapField<K, V>) object;
+    return MapFieldLite.<K, V>equals(getMap(), other.getMap());
+  }
+  
+  @Override
+  public int hashCode() {
+    return MapFieldLite.<K, V>calculateHashCodeForMap(getMap());
+  }
+  
+  /** Returns a deep copy of this MapField. */
+  public MapField<K, V> copy() {
+    return new MapField<K, V>(
+        converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
+  }
+  
+  /** Gets the content of this MapField as a read-only List. */
+  List<Message> getList() {
+    if (mode == StorageMode.MAP) {
+      synchronized (this) {
+        if (mode == StorageMode.MAP) {
+          listData = convertMapToList(mapData);
+          mode = StorageMode.BOTH;
+        }
+      }
+    }
+    return Collections.unmodifiableList(listData);
+  }
+  
+  /** Gets a mutable List view of this MapField. */
+  List<Message> getMutableList() {
+    if (mode != StorageMode.LIST) {
+      if (mode == StorageMode.MAP) {
+        listData = convertMapToList(mapData);
+      }
+      mapData = null;
+      mode = StorageMode.LIST;
+    }
+    return listData;
+  }
+  
+  /**
+   * Gets the default instance of the message stored in the list view of this
+   * map field.
+   */
+  Message getMapEntryMessageDefaultInstance() {
+    return converter.getMessageDefaultInstance();
+  }
+  
+  /**
+   * Makes this list immutable. All subsequent modifications will throw an
+   * {@link UnsupportedOperationException}.
+   */
+  public void makeImmutable() {
+    isMutable = false;
+  }
+  
+  /**
+   * Returns whether this field can be modified.
+   */
+  public boolean isMutable() {
+    return isMutable;
+  }
+  
+  /* (non-Javadoc)
+   * @see com.google.protobuf.MutabilityOracle#ensureMutable()
+   */
+  @Override
+  public void ensureMutable() {
+    if (!isMutable()) {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
new file mode 100644
index 0000000..960b633
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -0,0 +1,549 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.EnumLite;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Internal representation of map fields in generated lite-runtime messages.
+ * 
+ * This class is a protobuf implementation detail. Users shouldn't use this
+ * class directly.
+ */
+public final class MapFieldLite<K, V> implements MutabilityOracle {
+  private MutatabilityAwareMap<K, V> mapData;
+  private boolean isMutable;
+  
+  private MapFieldLite(Map<K, V> mapData) {
+    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+    this.isMutable = true;
+  }
+  
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  private static final MapFieldLite EMPTY_MAP_FIELD =
+      new MapFieldLite(Collections.emptyMap());
+  static {
+    EMPTY_MAP_FIELD.makeImmutable();
+  }
+  
+  /** Returns an singleton immutable empty MapFieldLite instance. */
+  @SuppressWarnings({"unchecked", "cast"})
+  public static <K, V> MapFieldLite<K, V> emptyMapField() {
+    return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
+  }
+  
+  /** Creates a new MapFieldLite instance. */
+  public static <K, V> MapFieldLite<K, V> newMapField() {
+    return new MapFieldLite<K, V>(new LinkedHashMap<K, V>());
+  }
+  
+  /** Gets the content of this MapField as a read-only Map. */
+  public Map<K, V> getMap() {
+    return Collections.unmodifiableMap(mapData);
+  }
+  
+  /** Gets a mutable Map view of this MapField. */
+  public Map<K, V> getMutableMap() {
+    return mapData;
+  }
+  
+  public void mergeFrom(MapFieldLite<K, V> other) {
+    mapData.putAll(copy(other.mapData));
+  }
+  
+  public void clear() {
+    mapData.clear();
+  }
+  
+  private static boolean equals(Object a, Object b) {
+    if (a instanceof byte[] && b instanceof byte[]) {
+      return Arrays.equals((byte[]) a, (byte[]) b);
+    }
+    return a.equals(b);
+  }
+  
+  /**
+   * Checks whether two {@link Map}s are equal. We don't use the default equals
+   * method of {@link Map} because it compares by identity not by content for
+   * byte arrays.
+   */
+  static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
+    if (a == b) {
+      return true;
+    }
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (Map.Entry<K, V> entry : a.entrySet()) {
+      if (!b.containsKey(entry.getKey())) {
+        return false;
+      }
+      if (!equals(entry.getValue(), b.get(entry.getKey()))) {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Checks whether two map fields are equal.
+   */
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean equals(Object object) {
+    if (!(object instanceof MapFieldLite)) {
+      return false;
+    }
+    MapFieldLite<K, V> other = (MapFieldLite<K, V>) object;
+    return equals(mapData, other.mapData);
+  }
+  
+  private static int calculateHashCodeForObject(Object a) {
+    if (a instanceof byte[]) {
+      return Internal.hashCode((byte[]) a);
+    }
+    // Enums should be stored as integers internally.
+    if (a instanceof EnumLite) {
+      throw new UnsupportedOperationException();
+    }
+    return a.hashCode();
+  }
+
+  /**
+   * Calculates the hash code for a {@link Map}. We don't use the default hash
+   * code method of {@link Map} because for byte arrays and protobuf enums it
+   * use {@link Object#hashCode()}.
+   */
+  static <K, V> int calculateHashCodeForMap(Map<K, V> a) {
+    int result = 0;
+    for (Map.Entry<K, V> entry : a.entrySet()) {
+      result += calculateHashCodeForObject(entry.getKey())
+          ^ calculateHashCodeForObject(entry.getValue());
+    }
+    return result;    
+  }
+  
+  @Override
+  public int hashCode() {
+    return calculateHashCodeForMap(mapData);
+  }
+  
+  private static Object copy(Object object) {
+    if (object instanceof byte[]) {
+      byte[] data = (byte[]) object;
+      return Arrays.copyOf(data, data.length);
+    }
+    return object;
+  }
+  
+  /**
+   * Makes a deep copy of a {@link Map}. Immutable objects in the map will be
+   * shared (e.g., integers, strings, immutable messages) and mutable ones will
+   * have a copy (e.g., byte arrays, mutable messages).
+   */
+  @SuppressWarnings("unchecked")
+  static <K, V> Map<K, V> copy(Map<K, V> map) {
+    Map<K, V> result = new LinkedHashMap<K, V>();
+    for (Map.Entry<K, V> entry : map.entrySet()) {
+      result.put(entry.getKey(), (V) copy(entry.getValue()));
+    }
+    return result;
+  }
+  
+  /** Returns a deep copy of this map field. */
+  public MapFieldLite<K, V> copy() {
+    return new MapFieldLite<K, V>(copy(mapData));
+  }
+  
+  /**
+   * Makes this field immutable. All subsequent modifications will throw an
+   * {@link UnsupportedOperationException}.
+   */
+  public void makeImmutable() {
+    isMutable = false;
+  }
+  
+  /**
+   * Returns whether this field can be modified.
+   */
+  public boolean isMutable() {
+    return isMutable;
+  }
+  
+  @Override
+  public void ensureMutable() {
+    if (!isMutable()) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  /**
+   * An internal map that checks for mutability before delegating.
+   */
+  static class MutatabilityAwareMap<K, V> implements Map<K, V> {    
+    private final MutabilityOracle mutabilityOracle;
+    private final Map<K, V> delegate;
+    
+    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+      return delegate.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+      return delegate.containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+      return delegate.get(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      mutabilityOracle.ensureMutable();
+      return delegate.put(key, value);
+    }
+
+    @Override
+    public V remove(Object key) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+      mutabilityOracle.ensureMutable();
+      delegate.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+
+  /**
+   * An internal collection that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareCollection<E> implements Collection<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Collection<E> delegate;
+    
+    MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      return delegate.contains(o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+    }
+
+    @Override
+    public Object[] toArray() {
+      return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+      return delegate.toArray(a);
+    }
+
+    @Override
+    public boolean add(E e) {
+      // Unsupported operation in the delegate.
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean remove(Object o) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(o);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+      return delegate.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+      // Unsupported operation in the delegate.
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.removeAll(c);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.retainAll(c);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+    
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+
+  /**
+   * An internal set that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareSet<E> implements Set<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Set<E> delegate;
+    
+    MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      return delegate.contains(o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+    }
+
+    @Override
+    public Object[] toArray() {
+      return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+      return delegate.toArray(a);
+    }
+
+    @Override
+    public boolean add(E e) {
+      mutabilityOracle.ensureMutable();
+      return delegate.add(e);
+    }
+
+    @Override
+    public boolean remove(Object o) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(o);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+      return delegate.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.addAll(c);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.retainAll(c);
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.removeAll(c);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+  
+  /**
+   * An internal iterator that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareIterator<E> implements Iterator<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Iterator<E> delegate;
+    
+    MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public boolean hasNext() {
+      return delegate.hasNext();
+    }
+
+    @Override
+    public E next() {
+      return delegate.next();
+    }
+
+    @Override
+    public void remove() {
+      mutabilityOracle.ensureMutable();
+      delegate.remove();
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+      return delegate.equals(obj);
+    }
+    
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
new file mode 100644
index 0000000..94590fb
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -0,0 +1,292 @@
+// 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.
+
+// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
+//   mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ * <p>
+ * See also {@link MessageLite}, which defines most of the methods that typical
+ * users care about.  {@link Message} adds to it methods that are not available
+ * in the "lite" runtime.  The biggest added features are introspection and
+ * reflection -- i.e., getting descriptors for the message type and accessing
+ * the field values dynamically.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface Message extends MessageLite, MessageOrBuilder {
+
+  // (From MessageLite, re-declared here only for return type covariance.)
+  @Override
+  Parser<? extends Message> getParserForType();
+
+
+  // -----------------------------------------------------------------
+  // Comparison and hashing
+
+  /**
+   * Compares the specified object with this message for equality.  Returns
+   * {@code true} if the given object is a message of the same type (as
+   * defined by {@code getDescriptorForType()}) and has identical values for
+   * all of its fields.  Subclasses must implement this; inheriting
+   * {@code Object.equals()} is incorrect.
+   *
+   * @param other object to be compared for equality with this message
+   * @return {@code true} if the specified object is equal to this message
+   */
+  @Override
+  boolean equals(Object other);
+
+  /**
+   * Returns the hash code value for this message.  The hash code of a message
+   * should mix the message's type (object identity of the descriptor) with its
+   * contents (known and unknown field values).  Subclasses must implement this;
+   * inheriting {@code Object.hashCode()} is incorrect.
+   *
+   * @return the hash code value for this message
+   * @see Map#hashCode()
+   */
+  @Override
+  int hashCode();
+
+  // -----------------------------------------------------------------
+  // Convenience methods.
+
+  /**
+   * Converts the message to a string in protocol buffer text format. This is
+   * just a trivial wrapper around {@link
+   * TextFormat#printToString(MessageOrBuilder)}.
+   */
+  @Override
+  String toString();
+
+  // =================================================================
+  // Builders
+
+  // (From MessageLite, re-declared here only for return type covariance.)
+  @Override
+  Builder newBuilderForType();
+
+  @Override
+  Builder toBuilder();
+
+  /**
+   * Abstract interface implemented by Protocol Message builders.
+   */
+  interface Builder extends MessageLite.Builder, MessageOrBuilder {
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
+    @Override
+    Builder clear();
+
+    /**
+     * Merge {@code other} into the message being built.  {@code other} must
+     * have the exact same type as {@code this} (i.e.
+     * {@code getDescriptorForType() == other.getDescriptorForType()}).
+     *
+     * Merging occurs as follows.  For each field:<br>
+     * * For singular primitive fields, if the field is set in {@code other},
+     *   then {@code other}'s value overwrites the value in this message.<br>
+     * * For singular message fields, if the field is set in {@code other},
+     *   it is merged into the corresponding sub-message of this message
+     *   using the same merging rules.<br>
+     * * For repeated fields, the elements in {@code other} are concatenated
+     *   with the elements in this message.
+     * * For oneof groups, if the other message has one of the fields set,
+     *   the group of this message is cleared and replaced by the field
+     *   of the other message, so that the oneof constraint is preserved.
+     *
+     * This is equivalent to the {@code Message::MergeFrom} method in C++.
+     */
+    Builder mergeFrom(Message other);
+
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
+    @Override
+    Message build();
+
+    @Override
+    Message buildPartial();
+
+    @Override
+    Builder clone();
+
+    @Override
+    Builder mergeFrom(CodedInputStream input) throws IOException;
+
+    @Override
+    Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+
+    /**
+     * Get the message's type's descriptor.
+     * See {@link Message#getDescriptorForType()}.
+     */
+    @Override
+    Descriptors.Descriptor getDescriptorForType();
+
+    /**
+     * Create a Builder for messages of the appropriate type for the given
+     * field.  Messages built with this can then be passed to setField(),
+     * setRepeatedField(), or addRepeatedField().
+     */
+    Builder newBuilderForField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Get a nested builder instance for the given field.
+     * <p>
+     * Normally, we hold a reference to the immutable message object for the
+     * message type field. Some implementations(the generated message builders),
+     * however, can also hold a reference to the builder object (a nested
+     * builder) for the field.
+     * <p>
+     * If the field is already backed up by a nested builder, the nested builder
+     * will be returned. Otherwise, a new field builder will be created and
+     * returned. The original message field (if exist) will be merged into the
+     * field builder, which will then be nested into its parent builder.
+     * <p>
+     * NOTE: implementations that do not support nested builders will throw
+     * <code>UnsupportedOperationException</code>.
+     */
+    Builder getFieldBuilder(Descriptors.FieldDescriptor field);
+
+    /**
+     * Get a nested builder instance for the given repeated field instance.
+     * <p>
+     * Normally, we hold a reference to the immutable message object for the
+     * message type field. Some implementations(the generated message builders),
+     * however, can also hold a reference to the builder object (a nested
+     * builder) for the field.
+     * <p>
+     * If the field is already backed up by a nested builder, the nested builder
+     * will be returned. Otherwise, a new field builder will be created and
+     * returned. The original message field (if exist) will be merged into the
+     * field builder, which will then be nested into its parent builder.
+     * <p>
+     * NOTE: implementations that do not support nested builders will throw
+     * <code>UnsupportedOperationException</code>.
+     */
+    Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field,
+                                    int index);
+
+    /**
+     * Sets a field to the given value.  The value must be of the correct type
+     * for this field, i.e. the same type that
+     * {@link Message#getField(Descriptors.FieldDescriptor)} would return.
+     */
+    Builder setField(Descriptors.FieldDescriptor field, Object value);
+
+    /**
+     * Clears the field.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the field.
+     */
+    Builder clearField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Clears the oneof.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the oneof.
+     */
+    Builder clearOneof(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Sets an element of a repeated field to the given value.  The value must
+     * be of the correct type for this field, i.e. the same type that
+     * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
+     * return.
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *           {@code field.getContainingType() != getDescriptorForType()}.
+     */
+    Builder setRepeatedField(Descriptors.FieldDescriptor field,
+                             int index, Object value);
+
+    /**
+     * Like {@code setRepeatedField}, but appends the value as a new element.
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *           {@code field.getContainingType() != getDescriptorForType()}.
+     */
+    Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
+
+    /** Set the {@link UnknownFieldSet} for this message. */
+    Builder setUnknownFields(UnknownFieldSet unknownFields);
+
+    /**
+     * Merge some unknown fields into the {@link UnknownFieldSet} for this
+     * message.
+     */
+    Builder mergeUnknownFields(UnknownFieldSet unknownFields);
+
+    // ---------------------------------------------------------------
+    // Convenience methods.
+
+    // (From MessageLite.Builder, re-declared here only for return type
+    // covariance.)
+    @Override
+    Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException;
+
+    @Override
+    Builder mergeFrom(InputStream input) throws IOException;
+
+    @Override
+    Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+
+    @Override
+    boolean mergeDelimitedFrom(InputStream input) throws IOException;
+
+    @Override
+    boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java
new file mode 100644
index 0000000..88f531d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageLite.java
@@ -0,0 +1,341 @@
+// 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.
+
+// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
+//   mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * <p>This interface is implemented by all protocol message objects.  Non-lite
+ * messages additionally implement the Message interface, which is a subclass
+ * of MessageLite.  Use MessageLite instead when you only need the subset of
+ * features which it supports -- namely, nothing that uses descriptors or
+ * reflection.  You can instruct the protocol compiler to generate classes
+ * which implement only MessageLite, not the full Message interface, by adding
+ * the follow line to the .proto file:
+ * <pre>
+ *   option optimize_for = LITE_RUNTIME;
+ * </pre>
+ *
+ * <p>This is particularly useful on resource-constrained systems where the
+ * full protocol buffers runtime library is too big.
+ *
+ * <p>Note that on non-constrained systems (e.g. servers) when you need to link
+ * in lots of protocol definitions, a better way to reduce total code footprint
+ * is to use {@code optimize_for = CODE_SIZE}.  This will make the generated
+ * code smaller while still supporting all the same features (at the expense of
+ * speed).  {@code optimize_for = LITE_RUNTIME} is best when you only have a
+ * small number of message types linked into your binary, in which case the
+ * size of the protocol buffers runtime itself is the biggest problem.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface MessageLite extends MessageLiteOrBuilder {
+
+
+  /**
+   * Serializes the message and writes it to {@code output}.  This does not
+   * flush or close the stream.
+   */
+  void writeTo(CodedOutputStream output) throws IOException;
+
+  /**
+   * Get the number of bytes required to encode this message.  The result
+   * is only computed on the first call and memoized after that.
+   */
+  int getSerializedSize();
+
+
+  /**
+   * Gets the parser for a message of the same type as this message.
+   */
+  Parser<? extends MessageLite> getParserForType();
+
+  // -----------------------------------------------------------------
+  // Convenience methods.
+
+  /**
+   * Serializes the message to a {@code ByteString} and returns it. This is
+   * just a trivial wrapper around
+   * {@link #writeTo(CodedOutputStream)}.
+   */
+  ByteString toByteString();
+
+  /**
+   * Serializes the message to a {@code byte} array and returns it.  This is
+   * just a trivial wrapper around
+   * {@link #writeTo(CodedOutputStream)}.
+   */
+  byte[] toByteArray();
+
+  /**
+   * Serializes the message and writes it to {@code output}.  This is just a
+   * trivial wrapper around {@link #writeTo(CodedOutputStream)}.  This does
+   * not flush or close the stream.
+   * <p>
+   * NOTE:  Protocol Buffers are not self-delimiting.  Therefore, if you write
+   * any more data to the stream after the message, you must somehow ensure
+   * that the parser on the receiving end does not interpret this as being
+   * part of the protocol message.  This can be done e.g. by writing the size
+   * of the message before the data, then making sure to limit the input to
+   * that size on the receiving end (e.g. by wrapping the InputStream in one
+   * which limits the input).  Alternatively, just use
+   * {@link #writeDelimitedTo(OutputStream)}.
+   */
+  void writeTo(OutputStream output) throws IOException;
+
+  /**
+   * Like {@link #writeTo(OutputStream)}, but writes the size of the message
+   * as a varint before writing the data.  This allows more data to be written
+   * to the stream after the message without the need to delimit the message
+   * data yourself.  Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
+   * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
+   * to parse messages written by this method.
+   */
+  void writeDelimitedTo(OutputStream output) throws IOException;
+
+
+  // =================================================================
+  // Builders
+
+  /**
+   * Constructs a new builder for a message of the same type as this message.
+   */
+  Builder newBuilderForType();
+
+  /**
+   * Constructs a builder initialized with the current message.  Use this to
+   * derive a new message from the current one.
+   */
+  Builder toBuilder();
+
+  /**
+   * Abstract interface implemented by Protocol Message builders.
+   */
+  interface Builder extends MessageLiteOrBuilder, Cloneable {
+    /** Resets all fields to their default values. */
+    Builder clear();
+
+    /**
+     * Constructs the message based on the state of the Builder. Subsequent
+     * changes to the Builder will not affect the returned message.
+     * @throws UninitializedMessageException The message is missing one or more
+     *         required fields (i.e. {@link #isInitialized()} returns false).
+     *         Use {@link #buildPartial()} to bypass this check.
+     */
+    MessageLite build();
+
+    /**
+     * Like {@link #build()}, but does not throw an exception if the message
+     * is missing required fields.  Instead, a partial message is returned.
+     * Subsequent changes to the Builder will not affect the returned message.
+     */
+    MessageLite buildPartial();
+
+    /**
+     * Clones the Builder.
+     * @see Object#clone()
+     */
+    Builder clone();
+
+    /**
+     * Parses a message of this type from the input and merges it with this
+     * message.
+     *
+     * <p>Warning:  This does not verify that all required fields are present in
+     * the input message.  If you call {@link #build()} without setting all
+     * required fields, it will throw an {@link UninitializedMessageException},
+     * which is a {@code RuntimeException} and thus might not be caught.  There
+     * are a few good ways to deal with this:
+     * <ul>
+     *   <li>Call {@link #isInitialized()} to verify that all required fields
+     *       are set before building.
+     *   <li>Use {@code buildPartial()} to build, which ignores missing
+     *       required fields.
+     * </ul>
+     *
+     * <p>Note:  The caller should call
+     * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
+     * verify that the last tag seen was the appropriate end-group tag,
+     * or zero for EOF.
+     */
+    Builder mergeFrom(CodedInputStream input) throws IOException;
+
+    /**
+     * Like {@link Builder#mergeFrom(CodedInputStream)}, but also
+     * parses extensions.  The extensions that you want to be able to parse
+     * must be registered in {@code extensionRegistry}.  Extensions not in
+     * the registry will be treated as unknown fields.
+     */
+    Builder mergeFrom(CodedInputStream input,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws IOException;
+
+    // ---------------------------------------------------------------
+    // Convenience methods.
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(ByteString data,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(byte[] data, int off, int len)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(byte[] data,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(byte[] data, int off, int len,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws InvalidProtocolBufferException;
+
+    /**
+     * Parse a message of this type from {@code input} and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.  Note that this method always
+     * reads the <i>entire</i> input (unless it throws an exception).  If you
+     * want it to stop earlier, you will need to wrap your input in some
+     * wrapper stream that limits reading.  Or, use
+     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
+     * and {@link #mergeDelimitedFrom(InputStream)} to read it.
+     * <p>
+     * Despite usually reading the entire input, this does not close the stream.
+     *
+     * @return this
+     */
+    Builder mergeFrom(InputStream input) throws IOException;
+
+    /**
+     * Parse a message of this type from {@code input} and merge it with the
+     * message being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
+     *
+     * @return this
+     */
+    Builder mergeFrom(InputStream input,
+                      ExtensionRegistryLite extensionRegistry)
+                      throws IOException;
+    
+    /**
+     * Merge {@code other} into the message being built.  {@code other} must
+     * have the exact same type as {@code this} (i.e.
+     * {@code getClass().equals(getDefaultInstanceForType().getClass())}).
+     *
+     * Merging occurs as follows.  For each field:<br>
+     * * For singular primitive fields, if the field is set in {@code other},
+     *   then {@code other}'s value overwrites the value in this message.<br>
+     * * For singular message fields, if the field is set in {@code other},
+     *   it is merged into the corresponding sub-message of this message
+     *   using the same merging rules.<br>
+     * * For repeated fields, the elements in {@code other} are concatenated
+     *   with the elements in this message.
+     * * For oneof groups, if the other message has one of the fields set,
+     *   the group of this message is cleared and replaced by the field
+     *   of the other message, so that the oneof constraint is preserved.
+     *
+     * This is equivalent to the {@code Message::MergeFrom} method in C++.
+     */
+    Builder mergeFrom(MessageLite other);
+
+    /**
+     * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
+     * Instead, the size of the message (encoded as a varint) is read first,
+     * then the message data.  Use
+     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
+     * this format.
+     *
+     * @return True if successful, or false if the stream is at EOF when the
+     *         method starts.  Any other error (including reaching EOF during
+     *         parsing) will cause an exception to be thrown.
+     */
+    boolean mergeDelimitedFrom(InputStream input)
+                               throws IOException;
+
+    /**
+     * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
+     */
+    boolean mergeDelimitedFrom(InputStream input,
+                               ExtensionRegistryLite extensionRegistry)
+                               throws IOException;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
rename to java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
new file mode 100644
index 0000000..4384765
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
@@ -0,0 +1,239 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Helps generate {@link String} representations of {@link MessageLite} protos.
+ */
+// TODO(dweis): Fix map fields.
+final class MessageLiteToString {
+
+  private static final String LIST_SUFFIX = "List";
+  private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
+  private static final String BYTES_SUFFIX = "Bytes";
+  
+  /**
+   * Returns a {@link String} representation of the {@link MessageLite} object.  The first line of
+   * the {@code String} representation representation includes a comment string to uniquely identify
+   * the objcet instance. This acts as an indicator that this should not be relied on for
+   * comparisons.
+   *
+   * <p>For use by generated code only.
+   */
+  static String toString(MessageLite messageLite, String commentString) {
+    StringBuilder buffer = new StringBuilder();
+    buffer.append("# ").append(commentString);
+    reflectivePrintWithIndent(messageLite, buffer, 0);
+    return buffer.toString();
+  }
+
+  /**
+   * Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces to indent the proto by
+   */
+  private static void reflectivePrintWithIndent(
+      MessageLite messageLite, StringBuilder buffer, int indent) {
+    // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and
+    // getFooList() which might be useful for building an object's string representation.
+    Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
+    Map<String, Method> nameToMethod = new HashMap<String, Method>();
+    Set<String> getters = new TreeSet<String>();
+    for (Method method : messageLite.getClass().getDeclaredMethods()) {
+      nameToMethod.put(method.getName(), method);
+      if (method.getParameterTypes().length == 0) {
+        nameToNoArgMethod.put(method.getName(), method);
+
+        if (method.getName().startsWith("get")) {
+          getters.add(method.getName());
+        }
+      }
+    }
+
+    for (String getter : getters) {
+      String suffix = getter.replaceFirst("get", "");
+      if (suffix.endsWith(LIST_SUFFIX) && !suffix.endsWith(BUILDER_LIST_SUFFIX)) {
+        String camelCase = suffix.substring(0, 1).toLowerCase()
+            + suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
+        // Try to reflectively get the value and toString() the field as if it were repeated. This
+        // only works if the method names have not be proguarded out or renamed.
+        Method listMethod = nameToNoArgMethod.get("get" + suffix);
+        if (listMethod != null) {
+          printField(
+              buffer,
+              indent,
+              camelCaseToSnakeCase(camelCase),
+              GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
+          continue;
+        }
+      }
+
+      Method setter = nameToMethod.get("set" + suffix);
+      if (setter == null) {
+        continue;
+      }
+      if (suffix.endsWith(BYTES_SUFFIX)
+          && nameToNoArgMethod.containsKey(
+              "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) {
+        // Heuristic to skip bytes based accessors for string fields.
+        continue;
+      }
+      
+      String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
+
+      // Try to reflectively get the value and toString() the field as if it were optional. This
+      // only works if the method names have not be proguarded out or renamed.
+      Method getMethod = nameToNoArgMethod.get("get" + suffix);
+      Method hasMethod = nameToNoArgMethod.get("has" + suffix);
+      // TODO(dweis): Fix proto3 semantics.
+      if (getMethod != null) {
+        Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
+        final boolean hasValue = hasMethod == null
+            ? !isDefaultValue(value)
+            : (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
+         // TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
+        if (hasValue) {
+          printField(
+              buffer,
+              indent,
+              camelCaseToSnakeCase(camelCase),
+              value);
+        }
+        continue;
+      }
+    }
+
+    if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
+      Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
+          ((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
+      while (iter.hasNext()) {
+        Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
+        printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
+      }
+    }
+
+    if (((GeneratedMessageLite<?, ?>) messageLite).unknownFields != null) {
+      ((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
+    }
+  }
+  
+  private static boolean isDefaultValue(Object o) {
+    if (o instanceof Boolean) {
+      return !((Boolean) o);
+    }
+    if (o instanceof Integer) {
+      return ((Integer) o) == 0;
+    }
+    if (o instanceof Float) {
+      return ((Float) o) == 0f;
+    }
+    if (o instanceof Double) {
+      return ((Double) o) == 0d;
+    }
+    if (o instanceof String) {
+      return o.equals("");
+    }
+    if (o instanceof ByteString) {
+      return o.equals(ByteString.EMPTY);
+    }
+    if (o instanceof MessageLite) { // Can happen in oneofs.
+      return o == ((MessageLite) o).getDefaultInstanceForType();
+    }
+    if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
+      return ((java.lang.Enum<?>) o).ordinal() == 0;
+    }
+    
+    return false;
+  }
+
+  /**
+   * Formats a text proto field.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces the proto should be indented by
+   * @param name the field name (in lower underscore case)
+   * @param object the object value of the field
+   */
+  static final void printField(StringBuilder buffer, int indent, String name, Object object) {
+    if (object instanceof List<?>) {
+      List<?> list = (List<?>) object;
+      for (Object entry : list) {
+        printField(buffer, indent, name, entry);
+      }
+      return;
+    }
+
+    buffer.append('\n');
+    for (int i = 0; i < indent; i++) {
+      buffer.append(' ');
+    }
+    buffer.append(name);
+
+    if (object instanceof String) {
+      buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"');
+    } else if (object instanceof ByteString) {
+      buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"');
+    } else if (object instanceof GeneratedMessageLite) {
+      buffer.append(" {");
+      reflectivePrintWithIndent((GeneratedMessageLite<?, ?>) object, buffer, indent + 2);
+      buffer.append("\n");
+      for (int i = 0; i < indent; i++) {
+        buffer.append(' ');
+      }
+      buffer.append("}");
+    } else {
+      buffer.append(": ").append(object.toString());
+    }
+  }
+  
+  private static final String camelCaseToSnakeCase(String camelCase) {
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < camelCase.length(); i++) {
+      char ch = camelCase.charAt(i);
+      if (Character.isUpperCase(ch)) {
+        builder.append("_");
+      }
+      builder.append(Character.toLowerCase(ch));
+    }
+    return builder.toString();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
new file mode 100644
index 0000000..5e7d782
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
@@ -0,0 +1,143 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base interface for methods common to {@link Message} and
+ * {@link Message.Builder} to provide type equivalency.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public interface MessageOrBuilder extends MessageLiteOrBuilder {
+
+  // (From MessageLite, re-declared here only for return type covariance.)
+  @Override
+  Message getDefaultInstanceForType();
+
+  /**
+   * Returns a list of field paths (e.g. "foo.bar.baz") of required fields
+   * which are not set in this message.  You should call
+   * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+   * are any missing fields, as that method is likely to be much faster
+   * than this one even when the message is fully-initialized.
+   */
+  List<String> findInitializationErrors();
+
+  /**
+   * Returns a comma-delimited list of required fields which are not set
+   * in this message object.  You should call
+   * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
+   * are any missing fields, as that method is likely to be much faster
+   * than this one even when the message is fully-initialized.
+   */
+  String getInitializationErrorString();
+
+  /**
+   * Get the message's type's descriptor.  This differs from the
+   * {@code getDescriptor()} method of generated message classes in that
+   * this method is an abstract method of the {@code Message} interface
+   * whereas {@code getDescriptor()} is a static method of a specific class.
+   * They return the same thing.
+   */
+  Descriptors.Descriptor getDescriptorForType();
+
+  /**
+   * Returns a collection of all the fields in this message which are set
+   * and their corresponding values.  A singular ("required" or "optional")
+   * field is set iff hasField() returns true for that field.  A "repeated"
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
+   * values are exactly what would be returned by calling
+   * {@link #getField(Descriptors.FieldDescriptor)} for each field.  The map
+   * is guaranteed to be a sorted map, so iterating over it will return fields
+   * in order by field number.
+   * <br>
+   * If this is for a builder, the returned map may or may not reflect future
+   * changes to the builder.  Either way, the returned map is itself
+   * unmodifiable.
+   */
+  Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+  /**
+   * Returns true if the given oneof is set.
+   * @throws IllegalArgumentException if
+   *           {@code oneof.getContainingType() != getDescriptorForType()}.
+   */
+  boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+  /**
+   * Obtains the FieldDescriptor if the given oneof is set. Returns null
+   * if no field is set.
+   */
+  Descriptors.FieldDescriptor getOneofFieldDescriptor(
+      Descriptors.OneofDescriptor oneof);
+
+  /**
+   * Returns true if the given field is set.  This is exactly equivalent to
+   * calling the generated "has" accessor method corresponding to the field.
+   * @throws IllegalArgumentException The field is a repeated field, or
+   *           {@code field.getContainingType() != getDescriptorForType()}.
+   */
+  boolean hasField(Descriptors.FieldDescriptor field);
+
+  /**
+   * Obtains the value of the given field, or the default value if it is
+   * not set.  For primitive fields, the boxed primitive value is returned.
+   * For enum fields, the EnumValueDescriptor for the value is returned. For
+   * embedded message fields, the sub-message is returned.  For repeated
+   * fields, a java.util.List is returned.
+   */
+  Object getField(Descriptors.FieldDescriptor field);
+
+  /**
+   * Gets the number of elements of a repeated field.  This is exactly
+   * equivalent to calling the generated "Count" accessor method corresponding
+   * to the field.
+   * @throws IllegalArgumentException The field is not a repeated field, or
+   *           {@code field.getContainingType() != getDescriptorForType()}.
+   */
+  int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+  /**
+   * Gets an element of a repeated field.  For primitive fields, the boxed
+   * primitive value is returned.  For enum fields, the EnumValueDescriptor
+   * for the value is returned. For embedded message fields, the sub-message
+   * is returned.
+   * @throws IllegalArgumentException The field is not a repeated field, or
+   *           {@code field.getContainingType() != getDescriptorForType()}.
+   */
+  Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+  /** Get the {@link UnknownFieldSet} for this message. */
+  UnknownFieldSet getUnknownFields();
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
new file mode 100644
index 0000000..7b791d9
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -0,0 +1,993 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Reflection utility methods shared by both mutable and immutable messages.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+class MessageReflection {
+
+  static void writeMessageTo(
+      Message message,
+      Map<FieldDescriptor, Object> fields,
+      CodedOutputStream output,
+      boolean alwaysWriteRequiredFields)
+      throws IOException {
+    final boolean isMessageSet =
+        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+    if (alwaysWriteRequiredFields) {
+      fields = new TreeMap<FieldDescriptor, Object>(fields);
+      for (final FieldDescriptor field :
+          message.getDescriptorForType().getFields()) {
+        if (field.isRequired() && !fields.containsKey(field)) {
+          fields.put(field, message.getField(field));
+        }
+      }
+    }
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        fields.entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        output.writeMessageSetExtension(field.getNumber(), (Message) value);
+      } else {
+        FieldSet.writeField(field, value, output);
+      }
+    }
+
+    final UnknownFieldSet unknownFields = message.getUnknownFields();
+    if (isMessageSet) {
+      unknownFields.writeAsMessageSetTo(output);
+    } else {
+      unknownFields.writeTo(output);
+    }
+  }
+
+  static int getSerializedSize(
+      Message message,
+      Map<FieldDescriptor, Object> fields) {
+    int size = 0;
+    final boolean isMessageSet =
+        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        fields.entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+      if (isMessageSet && field.isExtension() &&
+          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+          !field.isRepeated()) {
+        size += CodedOutputStream.computeMessageSetExtensionSize(
+            field.getNumber(), (Message) value);
+      } else {
+        size += FieldSet.computeFieldSize(field, value);
+      }
+    }
+
+    final UnknownFieldSet unknownFields = message.getUnknownFields();
+    if (isMessageSet) {
+      size += unknownFields.getSerializedSizeAsMessageSet();
+    } else {
+      size += unknownFields.getSerializedSize();
+    }
+    return size;
+  }
+
+  static String delimitWithCommas(List<String> parts) {
+    StringBuilder result = new StringBuilder();
+    for (String part : parts) {
+      if (result.length() > 0) {
+        result.append(", ");
+      }
+      result.append(part);
+    }
+    return result.toString();
+  }
+
+  @SuppressWarnings("unchecked")
+  static boolean isInitialized(MessageOrBuilder message) {
+    // Check that all required fields are present.
+    for (final Descriptors.FieldDescriptor field : message
+        .getDescriptorForType()
+        .getFields()) {
+      if (field.isRequired()) {
+        if (!message.hasField(field)) {
+          return false;
+        }
+      }
+    }
+
+    // Check that embedded messages are initialized.
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        message.getAllFields().entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          for (final Message element
+              : (List<Message>) entry.getValue()) {
+            if (!element.isInitialized()) {
+              return false;
+            }
+          }
+        } else {
+          if (!((Message) entry.getValue()).isInitialized()) {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  private static String subMessagePrefix(final String prefix,
+      final Descriptors.FieldDescriptor field,
+      final int index) {
+    final StringBuilder result = new StringBuilder(prefix);
+    if (field.isExtension()) {
+      result.append('(')
+          .append(field.getFullName())
+          .append(')');
+    } else {
+      result.append(field.getName());
+    }
+    if (index != -1) {
+      result.append('[')
+          .append(index)
+          .append(']');
+    }
+    result.append('.');
+    return result.toString();
+  }
+
+  private static void findMissingFields(final MessageOrBuilder message,
+      final String prefix,
+      final List<String> results) {
+    for (final Descriptors.FieldDescriptor field :
+        message.getDescriptorForType().getFields()) {
+      if (field.isRequired() && !message.hasField(field)) {
+        results.add(prefix + field.getName());
+      }
+    }
+
+    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
+        message.getAllFields().entrySet()) {
+      final Descriptors.FieldDescriptor field = entry.getKey();
+      final Object value = entry.getValue();
+
+      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          int i = 0;
+          for (final Object element : (List) value) {
+            findMissingFields((MessageOrBuilder) element,
+                subMessagePrefix(prefix, field, i++),
+                results);
+          }
+        } else {
+          if (message.hasField(field)) {
+            findMissingFields((MessageOrBuilder) value,
+                subMessagePrefix(prefix, field, -1),
+                results);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Populates {@code this.missingFields} with the full "path" of each missing
+   * required field in the given message.
+   */
+  static List<String> findMissingFields(
+      final MessageOrBuilder message) {
+    final List<String> results = new ArrayList<String>();
+    findMissingFields(message, "", results);
+    return results;
+  }
+
+  static interface MergeTarget {
+    enum ContainerType {
+      MESSAGE, EXTENSION_SET
+    }
+
+    /**
+     * Returns the descriptor for the target.
+     */
+    public Descriptors.Descriptor getDescriptorForType();
+
+    public ContainerType getContainerType();
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name);
+
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType,
+        int fieldNumber);
+
+    /**
+     * Obtains the value of the given field, or the default value if it is not
+     * set.  For primitive fields, the boxed primitive value is returned. For
+     * enum fields, the EnumValueDescriptor for the value is returned. For
+     * embedded message fields, the sub-message is returned.  For repeated
+     * fields, a java.util.List is returned.
+     */
+    public Object getField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Returns true if the given field is set.  This is exactly equivalent to
+     * calling the generated "has" accessor method corresponding to the field.
+     *
+     * @throws IllegalArgumentException The field is a repeated field, or {@code
+     *     field.getContainingType() != getDescriptorForType()}.
+     */
+    boolean hasField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Sets a field to the given value.  The value must be of the correct type
+     * for this field, i.e. the same type that
+     * {@link Message#getField(Descriptors.FieldDescriptor)}
+     * would return.
+     */
+    MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
+
+    /**
+     * Clears the field.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the field.
+     */
+    MergeTarget clearField(Descriptors.FieldDescriptor field);
+
+    /**
+     * Sets an element of a repeated field to the given value.  The value must
+     * be of the correct type for this field, i.e. the same type that {@link
+     * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
+     *
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *                                  {@code field.getContainingType() !=
+     *                                  getDescriptorForType()}.
+     */
+    MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
+        int index, Object value);
+
+    /**
+     * Like {@code setRepeatedField}, but appends the value as a new element.
+     *
+     * @throws IllegalArgumentException The field is not a repeated field, or
+     *                                  {@code field.getContainingType() !=
+     *                                  getDescriptorForType()}.
+     */
+    MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
+        Object value);
+
+    /**
+     * Returns true if the given oneof is set.
+     *
+     * @throws IllegalArgumentException if
+     *           {@code oneof.getContainingType() != getDescriptorForType()}.
+     */
+    boolean hasOneof(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Clears the oneof.  This is exactly equivalent to calling the generated
+     * "clear" accessor method corresponding to the oneof.
+     */
+    MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Obtains the FieldDescriptor if the given oneof is set. Returns null
+     * if no field is set.
+     */
+    Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
+
+    /**
+     * Parse the input stream into a sub field group defined based on either
+     * FieldDescriptor or the default instance.
+     */
+    Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+
+    /**
+     * Parse the input stream into a sub field message defined based on either
+     * FieldDescriptor or the default instance.
+     */
+    Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+
+    /**
+     * Parse from a ByteString into a sub field message defined based on either
+     * FieldDescriptor or the default instance.  There isn't a varint indicating
+     * the length of the message at the beginning of the input ByteString.
+     */
+    Object parseMessageFromBytes(
+        ByteString bytes, ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
+        throws IOException;
+
+    /**
+     * Returns the UTF8 validation level for the field.
+     */
+    WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor
+        descriptor);
+
+    /**
+     * Returns a new merge target for a sub-field. When defaultInstance is
+     * provided, it indicates the descriptor is for an extension type, and
+     * implementations should create a new instance from the defaultInstance
+     * prototype directly.
+     */
+    MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor descriptor,
+        Message defaultInstance);
+
+    /**
+     * Finishes the merge and returns the underlying object.
+     */
+    Object finish();
+    
+  }
+
+  static class BuilderAdapter implements MergeTarget {
+
+    private final Message.Builder builder;
+
+    @Override
+    public Descriptors.Descriptor getDescriptorForType() {
+      return builder.getDescriptorForType();
+    }
+
+    public BuilderAdapter(Message.Builder builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return builder.getField(field);
+    }
+
+    @Override
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return builder.hasField(field);
+    }
+
+    @Override
+    public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
+      builder.setField(field, value);
+      return this;
+    }
+
+    @Override
+    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+      builder.clearField(field);
+      return this;
+    }
+
+    @Override
+    public MergeTarget setRepeatedField(
+        Descriptors.FieldDescriptor field, int index, Object value) {
+      builder.setRepeatedField(field, index, value);
+      return this;
+    }
+
+    @Override
+    public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
+      builder.addRepeatedField(field, value);
+      return this;
+    }
+
+    @Override
+    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+      return builder.hasOneof(oneof);
+    }
+
+    @Override
+    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+      builder.clearOneof(oneof);
+      return this;
+    }
+
+    @Override
+    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+      return builder.getOneofFieldDescriptor(oneof);
+    }
+
+    @Override
+    public ContainerType getContainerType() {
+      return ContainerType.MESSAGE;
+    }
+
+    @Override
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name) {
+      return registry.findImmutableExtensionByName(name);
+    }
+
+    @Override
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
+      return registry.findImmutableExtensionByNumber(containingType,
+          fieldNumber);
+    }
+
+    @Override
+    public Object parseGroup(
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public Object parseMessage(
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readMessage(subBuilder, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public Object parseMessageFromBytes(
+        ByteString bytes,
+        ExtensionRegistryLite extensionRegistry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder;
+      // When default instance is not null. The field is an extension field.
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      subBuilder.mergeFrom(bytes, extensionRegistry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor field, Message defaultInstance) {
+      if (defaultInstance != null) {
+        return new BuilderAdapter(
+            defaultInstance.newBuilderForType());
+      } else {
+        return new BuilderAdapter(builder.newBuilderForField(field));
+      }
+    }
+
+    @Override
+    public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+      if (descriptor.needsUtf8Check()) {
+        return WireFormat.Utf8Validation.STRICT;
+      }
+      // TODO(liujisi): support lazy strings for repeated fields.
+      if (!descriptor.isRepeated()
+          && builder instanceof GeneratedMessage.Builder) {
+        return WireFormat.Utf8Validation.LAZY;
+      }
+      return WireFormat.Utf8Validation.LOOSE;
+    }
+
+    @Override
+    public Object finish() {
+      return builder.buildPartial();
+    }
+    
+  }
+
+
+  static class ExtensionAdapter implements MergeTarget {
+
+    private final FieldSet<Descriptors.FieldDescriptor> extensions;
+
+    ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
+    @Override
+    public Descriptors.Descriptor getDescriptorForType() {
+      throw new UnsupportedOperationException(
+          "getDescriptorForType() called on FieldSet object");
+    }
+
+    @Override
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return extensions.getField(field);
+    }
+
+    @Override
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return extensions.hasField(field);
+    }
+
+    @Override
+    public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) {
+      extensions.setField(field, value);
+      return this;
+    }
+
+    @Override
+    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
+      extensions.clearField(field);
+      return this;
+    }
+
+    @Override
+    public MergeTarget setRepeatedField(
+        Descriptors.FieldDescriptor field, int index, Object value) {
+      extensions.setRepeatedField(field, index, value);
+      return this;
+    }
+
+    @Override
+    public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
+      extensions.addRepeatedField(field, value);
+      return this;
+    }
+
+    @Override
+    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
+      return false;
+    }
+
+    @Override
+    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
+      // Nothing to clear.
+      return this;
+    }
+
+    @Override
+    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
+      return null;
+    }
+
+    @Override
+    public ContainerType getContainerType() {
+      return ContainerType.EXTENSION_SET;
+    }
+
+    @Override
+    public ExtensionRegistry.ExtensionInfo findExtensionByName(
+        ExtensionRegistry registry, String name) {
+      return registry.findImmutableExtensionByName(name);
+    }
+
+    @Override
+    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
+        ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) {
+      return registry.findImmutableExtensionByNumber(containingType,
+          fieldNumber);
+    }
+
+    @Override
+    public Object parseGroup(
+        CodedInputStream input,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder =
+          defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readGroup(field.getNumber(), subBuilder, registry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public Object parseMessage(
+        CodedInputStream input,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder =
+          defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      input.readMessage(subBuilder, registry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public Object parseMessageFromBytes(
+        ByteString bytes,
+        ExtensionRegistryLite registry,
+        Descriptors.FieldDescriptor field,
+        Message defaultInstance)
+        throws IOException {
+      Message.Builder subBuilder =  defaultInstance.newBuilderForType();
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      subBuilder.mergeFrom(bytes, registry);
+      return subBuilder.buildPartial();
+    }
+
+    @Override
+    public MergeTarget newMergeTargetForField(
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
+      throw new UnsupportedOperationException(
+          "newMergeTargetForField() called on FieldSet object");
+    }
+
+    @Override
+    public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+      if (descriptor.needsUtf8Check()) {
+        return WireFormat.Utf8Validation.STRICT;
+      }
+      // TODO(liujisi): support lazy strings for ExtesnsionSet.
+      return WireFormat.Utf8Validation.LOOSE;
+    }
+
+    @Override
+    public Object finish() {
+      throw new UnsupportedOperationException(
+          "finish() called on FieldSet object");
+    }
+    
+  }
+
+  /**
+   * Parses a single field into MergeTarget. The target can be Message.Builder,
+   * FieldSet or MutableMessage.
+   *
+   * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+   *
+   * @param tag The tag, which should have already been read.
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  static boolean mergeFieldFrom(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      Descriptors.Descriptor type,
+      MergeTarget target,
+      int tag) throws IOException {
+    if (type.getOptions().getMessageSetWireFormat() &&
+        tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+      mergeMessageSetExtensionFromCodedStream(
+          input, unknownFields, extensionRegistry, type, target);
+      return true;
+    }
+
+    final int wireType = WireFormat.getTagWireType(tag);
+    final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+    final Descriptors.FieldDescriptor field;
+    Message defaultInstance = null;
+
+    if (type.isExtensionNumber(fieldNumber)) {
+      // extensionRegistry may be either ExtensionRegistry or
+      // ExtensionRegistryLite.  Since the type we are parsing is a full
+      // message, only a full ExtensionRegistry could possibly contain
+      // extensions of it.  Otherwise we will treat the registry as if it
+      // were empty.
+      if (extensionRegistry instanceof ExtensionRegistry) {
+        final ExtensionRegistry.ExtensionInfo extension =
+            target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
+                type, fieldNumber);
+        if (extension == null) {
+          field = null;
+        } else {
+          field = extension.descriptor;
+          defaultInstance = extension.defaultInstance;
+          if (defaultInstance == null &&
+              field.getJavaType()
+                  == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+            throw new IllegalStateException(
+                "Message-typed extension lacked default instance: " +
+                    field.getFullName());
+          }
+        }
+      } else {
+        field = null;
+      }
+    } else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) {
+      field = type.findFieldByNumber(fieldNumber);
+    } else {
+      field = null;
+    }
+
+    boolean unknown = false;
+    boolean packed = false;
+    if (field == null) {
+      unknown = true;  // Unknown field.
+    } else if (wireType == FieldSet.getWireFormatForFieldType(
+        field.getLiteType(),
+        false  /* isPacked */)) {
+      packed = false;
+    } else if (field.isPackable() &&
+        wireType == FieldSet.getWireFormatForFieldType(
+            field.getLiteType(),
+            true  /* isPacked */)) {
+      packed = true;
+    } else {
+      unknown = true;  // Unknown wire type.
+    }
+
+    if (unknown) {  // Unknown field or wrong wire type.  Skip.
+      return unknownFields.mergeFieldFrom(tag, input);
+    }
+
+    if (packed) {
+      final int length = input.readRawVarint32();
+      final int limit = input.pushLimit(length);
+      if (field.getLiteType() == WireFormat.FieldType.ENUM) {
+        while (input.getBytesUntilLimit() > 0) {
+          final int rawValue = input.readEnum();
+          if (field.getFile().supportsUnknownEnumValue()) {
+            target.addRepeatedField(field,
+                field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue));
+          } else {
+            final Object value = field.getEnumType().findValueByNumber(rawValue);
+            if (value == null) {
+              // If the number isn't recognized as a valid value for this
+              // enum, drop it (don't even add it to unknownFields).
+              return true;
+            }
+            target.addRepeatedField(field, value);
+          }
+        }
+      } else {
+        while (input.getBytesUntilLimit() > 0) {
+          final Object value = WireFormat.readPrimitiveField(
+              input, field.getLiteType(), target.getUtf8Validation(field));
+          target.addRepeatedField(field, value);
+        }
+      }
+      input.popLimit(limit);
+    } else {
+      final Object value;
+      switch (field.getType()) {
+        case GROUP: {
+          value = target
+              .parseGroup(input, extensionRegistry, field, defaultInstance);
+          break;
+        }
+        case MESSAGE: {
+          value = target
+              .parseMessage(input, extensionRegistry, field, defaultInstance);
+          break;
+        }
+        case ENUM:
+          final int rawValue = input.readEnum();
+          if (field.getFile().supportsUnknownEnumValue()) {
+            value = field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue);
+          } else {
+            value = field.getEnumType().findValueByNumber(rawValue);
+            // If the number isn't recognized as a valid value for this enum,
+            // drop it.
+            if (value == null) {
+              unknownFields.mergeVarintField(fieldNumber, rawValue);
+              return true;
+            }
+          }
+          break;
+        default:
+          value = WireFormat.readPrimitiveField(
+              input, field.getLiteType(), target.getUtf8Validation(field));
+          break;
+      }
+
+      if (field.isRepeated()) {
+        target.addRepeatedField(field, value);
+      } else {
+        target.setField(field, value);
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
+   * MergeTarget.
+   */
+  private static void mergeMessageSetExtensionFromCodedStream(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      Descriptors.Descriptor type,
+      MergeTarget target) throws IOException {
+
+    // The wire format for MessageSet is:
+    //   message MessageSet {
+    //     repeated group Item = 1 {
+    //       required int32 typeId = 2;
+    //       required bytes message = 3;
+    //     }
+    //   }
+    // "typeId" is the extension's field number.  The extension can only be
+    // a message type, where "message" contains the encoded bytes of that
+    // message.
+    //
+    // In practice, we will probably never see a MessageSet item in which
+    // the message appears before the type ID, or where either field does not
+    // appear exactly once.  However, in theory such cases are valid, so we
+    // should be prepared to accept them.
+
+    int typeId = 0;
+    ByteString rawBytes = null; // If we encounter "message" before "typeId"
+    ExtensionRegistry.ExtensionInfo extension = null;
+
+    // Read bytes from input, if we get it's type first then parse it eagerly,
+    // otherwise we store the raw bytes in a local variable.
+    while (true) {
+      final int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+
+      if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+        typeId = input.readUInt32();
+        if (typeId != 0) {
+          // extensionRegistry may be either ExtensionRegistry or
+          // ExtensionRegistryLite. Since the type we are parsing is a full
+          // message, only a full ExtensionRegistry could possibly contain
+          // extensions of it. Otherwise we will treat the registry as if it
+          // were empty.
+          if (extensionRegistry instanceof ExtensionRegistry) {
+            extension = target.findExtensionByNumber(
+                (ExtensionRegistry) extensionRegistry, type, typeId);
+          }
+        }
+
+      } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+        if (typeId != 0) {
+          if (extension != null &&
+              ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+            // We already know the type, so we can parse directly from the
+            // input with no copying.  Hooray!
+            eagerlyMergeMessageSetExtension(
+                input, extension, extensionRegistry, target);
+            rawBytes = null;
+            continue;
+          }
+        }
+        // We haven't seen a type ID yet or we want parse message lazily.
+        rawBytes = input.readBytes();
+
+      } else { // Unknown tag. Skip it.
+        if (!input.skipField(tag)) {
+          break; // End of group
+        }
+      }
+    }
+    input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+    // Process the raw bytes.
+    if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
+      if (extension != null) { // We known the type
+        mergeMessageSetExtensionFromBytes(
+            rawBytes, extension, extensionRegistry, target);
+      } else { // We don't know how to parse this. Ignore it.
+        if (rawBytes != null) {
+          unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
+              .addLengthDelimited(rawBytes).build());
+        }
+      }
+    }
+  }
+
+  private static void mergeMessageSetExtensionFromBytes(
+      ByteString rawBytes,
+      ExtensionRegistry.ExtensionInfo extension,
+      ExtensionRegistryLite extensionRegistry,
+      MergeTarget target) throws IOException {
+
+    Descriptors.FieldDescriptor field = extension.descriptor;
+    boolean hasOriginalValue = target.hasField(field);
+
+    if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
+      // If the field already exists, we just parse the field.
+      Object value = target.parseMessageFromBytes(
+          rawBytes, extensionRegistry,field, extension.defaultInstance);
+      target.setField(field, value);
+    } else {
+      // Use LazyField to load MessageSet lazily.
+      LazyField lazyField = new LazyField(
+          extension.defaultInstance, extensionRegistry, rawBytes);
+      target.setField(field, lazyField);
+    }
+  }
+
+  private static void eagerlyMergeMessageSetExtension(
+      CodedInputStream input,
+      ExtensionRegistry.ExtensionInfo extension,
+      ExtensionRegistryLite extensionRegistry,
+      MergeTarget target) throws IOException {
+    Descriptors.FieldDescriptor field = extension.descriptor;
+    Object value = target.parseMessage(input, extensionRegistry, field,
+                                       extension.defaultInstance);
+    target.setField(field, value);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MutabilityOracle.java b/java/core/src/main/java/com/google/protobuf/MutabilityOracle.java
new file mode 100644
index 0000000..82b723c
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MutabilityOracle.java
@@ -0,0 +1,48 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Verifies that an object is mutable, throwing if not.
+ */
+interface MutabilityOracle {
+  static final MutabilityOracle IMMUTABLE = new MutabilityOracle() {
+    @Override
+    public void ensureMutable() {
+      throw new UnsupportedOperationException();
+    }
+  };
+
+  /**
+   * Throws an {@link UnsupportedOperationException} if not mutable.
+   */
+  void ensureMutable();
+}
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
new file mode 100644
index 0000000..6163c7b
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -0,0 +1,290 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.InvalidMarkException;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A {@link ByteString} that wraps around a {@link ByteBuffer}.
+ */
+final class NioByteString extends ByteString.LeafByteString {
+  private final ByteBuffer buffer;
+
+  NioByteString(ByteBuffer buffer) {
+    if (buffer == null) {
+      throw new NullPointerException("buffer");
+    }
+
+    this.buffer = buffer.slice().order(ByteOrder.nativeOrder());
+  }
+
+  // =================================================================
+  // Serializable
+
+  /**
+   * Magic method that lets us override serialization behavior.
+   */
+  private Object writeReplace() {
+    return ByteString.copyFrom(buffer.slice());
+  }
+
+  /**
+   * Magic method that lets us override deserialization behavior.
+   */
+  private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
+    throw new InvalidObjectException("NioByteString instances are not to be serialized directly");
+  }
+
+  // =================================================================
+
+  @Override
+  public byte byteAt(int index) {
+    try {
+      return buffer.get(index);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw e;
+    } catch (IndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException(e.getMessage());
+    }
+  }
+
+  @Override
+  public int size() {
+    return buffer.remaining();
+  }
+
+  @Override
+  public ByteString substring(int beginIndex, int endIndex) {
+    try {
+      ByteBuffer slice = slice(beginIndex, endIndex);
+      return new NioByteString(slice);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw e;
+    } catch (IndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException(e.getMessage());
+    }
+  }
+
+  @Override
+  protected void copyToInternal(
+      byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
+    ByteBuffer slice = buffer.slice();
+    slice.position(sourceOffset);
+    slice.get(target, targetOffset, numberToCopy);
+  }
+
+  @Override
+  public void copyTo(ByteBuffer target) {
+    target.put(buffer.slice());
+  }
+
+  @Override
+  public void writeTo(OutputStream out) throws IOException {
+    out.write(toByteArray());
+  }
+
+  @Override
+  boolean equalsRange(ByteString other, int offset, int length) {
+    return substring(0, length).equals(other.substring(offset, offset + length));
+  }
+
+  @Override
+  void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) throws IOException {
+    if (buffer.hasArray()) {
+      // Optimized write for array-backed buffers.
+      // Note that we're taking the risk that a malicious OutputStream could modify the array.
+      int bufferOffset = buffer.arrayOffset() + buffer.position() + sourceOffset;
+      out.write(buffer.array(), bufferOffset, numberToWrite);
+      return;
+    }
+
+    ByteBufferWriter.write(slice(sourceOffset, sourceOffset + numberToWrite), out);
+  }
+
+  @Override
+  void writeTo(ByteOutput output) throws IOException {
+    output.writeLazy(buffer.slice());
+  }
+
+  @Override
+  public ByteBuffer asReadOnlyByteBuffer() {
+    return buffer.asReadOnlyBuffer();
+  }
+
+  @Override
+  public List<ByteBuffer> asReadOnlyByteBufferList() {
+    return Collections.singletonList(asReadOnlyByteBuffer());
+  }
+
+  @Override
+  protected String toStringInternal(Charset charset) {
+    final byte[] bytes;
+    final int offset;
+    final int length;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      offset = buffer.arrayOffset() + buffer.position();
+      length = buffer.remaining();
+    } else {
+      // TODO(nathanmittler): Can we optimize this?
+      bytes = toByteArray();
+      offset = 0;
+      length = bytes.length;
+    }
+    return new String(bytes, offset, length, charset);
+  }
+
+  @Override
+  public boolean isValidUtf8() {
+    return Utf8.isValidUtf8(buffer);
+  }
+
+  @Override
+  protected int partialIsValidUtf8(int state, int offset, int length) {
+    return Utf8.partialIsValidUtf8(state, buffer, offset, offset + length);
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == this) {
+      return true;
+    }
+    if (!(other instanceof ByteString)) {
+      return false;
+    }
+    ByteString otherString = ((ByteString) other);
+    if (size() != otherString.size()) {
+      return false;
+    }
+    if (size() == 0) {
+      return true;
+    }
+    if (other instanceof NioByteString) {
+      return buffer.equals(((NioByteString) other).buffer);
+    }
+    if (other instanceof RopeByteString) {
+      return other.equals(this);
+    }
+    return buffer.equals(otherString.asReadOnlyByteBuffer());
+  }
+
+  @Override
+  protected int partialHash(int h, int offset, int length) {
+    for (int i = offset; i < offset + length; i++) {
+      h = h * 31 + buffer.get(i);
+    }
+    return h;
+  }
+
+  @Override
+  public InputStream newInput() {
+    return new InputStream() {
+      private final ByteBuffer buf = buffer.slice();
+
+      @Override
+      public void mark(int readlimit) {
+        buf.mark();
+      }
+
+      @Override
+      public boolean markSupported() {
+        return true;
+      }
+
+      @Override
+      public void reset() throws IOException {
+        try {
+          buf.reset();
+        } catch (InvalidMarkException e) {
+          throw new IOException(e);
+        }
+      }
+
+      @Override
+      public int available() throws IOException {
+        return buf.remaining();
+      }
+
+      @Override
+      public int read() throws IOException {
+        if (!buf.hasRemaining()) {
+          return -1;
+        }
+        return buf.get() & 0xFF;
+      }
+
+      @Override
+      public int read(byte[] bytes, int off, int len) throws IOException {
+        if (!buf.hasRemaining()) {
+          return -1;
+        }
+
+        len = Math.min(len, buf.remaining());
+        buf.get(bytes, off, len);
+        return len;
+      }
+    };
+  }
+
+  @Override
+  public CodedInputStream newCodedInput() {
+    return CodedInputStream.newInstance(buffer);
+  }
+
+  /**
+   * Creates a slice of a range of this buffer.
+   *
+   * @param beginIndex the beginning index of the slice (inclusive).
+   * @param endIndex the end index of the slice (exclusive).
+   * @return the requested slice.
+   */
+  private ByteBuffer slice(int beginIndex, int endIndex) {
+    if (beginIndex < buffer.position() || endIndex > buffer.limit() || beginIndex > endIndex) {
+      throw new IllegalArgumentException(
+          String.format("Invalid indices [%d, %d]", beginIndex, endIndex));
+    }
+
+    ByteBuffer slice = buffer.slice();
+    slice.position(beginIndex - buffer.position());
+    slice.limit(endIndex - buffer.position());
+    return slice;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
new file mode 100644
index 0000000..6db6924
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -0,0 +1,272 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.InputStream;
+
+/**
+ * Abstract interface for parsing Protocol Messages.
+ *
+ * The implementation should be stateless and thread-safe.
+ *
+ * <p>All methods may throw {@link InvalidProtocolBufferException}. In the event of invalid data,
+ * like an encoding error, the cause of the thrown exception will be {@code null}. However, if an
+ * I/O problem occurs, an exception is thrown with an {@link IOException} cause.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public interface Parser<MessageType> {
+
+  // NB(jh): Other parts of the protobuf API that parse messages distinguish between an I/O problem
+  // (like failure reading bytes from a socket) and invalid data (encoding error) via the type of
+  // thrown exception. But it would be source-incompatible to make the methods in this interface do
+  // so since they were originally spec'ed to only throw InvalidProtocolBufferException. So callers
+  // must inspect the cause of the exception to distinguish these two cases.
+
+  /**
+   * Parses a message of {@code MessageType} from the input.
+   *
+   * <p>Note:  The caller should call
+   * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
+   * verify that the last tag seen was the appropriate end-group tag,
+   * or zero for EOF.
+   */
+  public MessageType parseFrom(CodedInputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(CodedInputStream)}, but also parses extensions.
+   * The extensions that you want to be able to parse must be registered in
+   * {@code extensionRegistry}. Extensions not in the registry will be treated
+   * as unknown fields.
+   */
+  public MessageType parseFrom(CodedInputStream input,
+                               ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(CodedInputStream)}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialFrom(CodedInputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialFrom(CodedInputStream input,
+                                      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  // ---------------------------------------------------------------
+  // Convenience methods.
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+   */
+  public MessageType parseFrom(ByteString data)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+   */
+  public MessageType parseFrom(ByteString data,
+                               ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(ByteString)}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialFrom(ByteString data)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialFrom(ByteString data,
+                                      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+   */
+  public MessageType parseFrom(byte[] data, int off, int len)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+   */
+  public MessageType parseFrom(byte[] data, int off, int len,
+                               ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+   */
+  public MessageType parseFrom(byte[] data)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses {@code data} as a message of {@code MessageType}.
+   * This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+   */
+  public MessageType parseFrom(byte[] data,
+                               ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(byte[], int, int)}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialFrom(byte[] data, int off, int len)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialFrom(byte[] data, int off, int len,
+                                      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(byte[])}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialFrom(byte[] data)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(byte[], ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialFrom(byte[] data,
+                                      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parse a message of {@code MessageType} from {@code input}.
+   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
+   * Note that this method always reads the <i>entire</i> input (unless it
+   * throws an exception).  If you want it to stop earlier, you will need to
+   * wrap your input in some wrapper stream that limits reading.  Or, use
+   * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your
+   * message and {@link #parseDelimitedFrom(InputStream)} to read it.
+   * <p>
+   * Despite usually reading the entire input, this does not close the stream.
+   */
+  public MessageType parseFrom(InputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Parses a message of {@code MessageType} from {@code input}.
+   * This is just a small wrapper around
+   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+   */
+  public MessageType parseFrom(InputStream input,
+                               ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(InputStream)}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialFrom(InputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(InputStream, ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialFrom(InputStream input,
+                                      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseFrom(InputStream)}, but does not read util EOF.
+   * Instead, the size of message (encoded as a varint) is read first,
+   * then the message data. Use
+   * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write
+   * messages in this format.
+   *
+   * @return Parsed message if successful, or null if the stream is at EOF when
+   *         the method starts. Any other error (including reaching EOF during
+   *         parsing) will cause an exception to be thrown.
+   */
+  public MessageType parseDelimitedFrom(InputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions.
+   */
+  public MessageType parseDelimitedFrom(InputStream input,
+                                        ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an
+   * exception if the message is missing required fields. Instead, a partial
+   * message is returned.
+   */
+  public MessageType parsePartialDelimitedFrom(InputStream input)
+      throws InvalidProtocolBufferException;
+
+  /**
+   * Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)},
+   * but does not throw an exception if the message is missing required fields.
+   * Instead, a partial message is returned.
+   */
+  public MessageType parsePartialDelimitedFrom(
+      InputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException;
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
new file mode 100644
index 0000000..81255ec
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -0,0 +1,105 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.ProtobufList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements {@link ProtobufList} for non-primitive and {@link String} types.
+ */
+final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
+
+  private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  @SuppressWarnings("unchecked") // Guaranteed safe by runtime.
+  public static <E> ProtobufArrayList<E> emptyList() {
+    return (ProtobufArrayList<E>) EMPTY_LIST;
+  }
+  
+  private final List<E> list;
+
+  ProtobufArrayList() {
+    this(new ArrayList<E>(DEFAULT_CAPACITY));
+  }
+  
+  private ProtobufArrayList(List<E> list) {
+    this.list = list;
+  }
+
+  @Override
+  public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
+    if (capacity < size()) {
+      throw new IllegalArgumentException();
+    }
+    List<E> newList = new ArrayList<E>(capacity);
+    newList.addAll(list);
+    return new ProtobufArrayList<E>(newList);
+  }
+  
+  @Override
+  public void add(int index, E element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+
+  @Override
+  public E get(int index) {
+    return list.get(index);
+  }
+  
+  @Override
+  public E remove(int index) {
+    ensureIsMutable();
+    E toReturn = list.remove(index);
+    modCount++;
+    return toReturn;
+  }
+  
+  @Override
+  public E set(int index, E element) {
+    ensureIsMutable();
+    E toReturn = list.set(index, element);
+    modCount++;
+    return toReturn;
+  }
+
+  @Override
+  public int size() {
+    return list.size();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
new file mode 100644
index 0000000..a596d30
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
@@ -0,0 +1,59 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+/**
+ * Interface of useful methods added to all enums generated by the protocol
+ * compiler.
+ */
+public interface ProtocolMessageEnum extends Internal.EnumLite {
+
+  /**
+   * Return the value's numeric value as defined in the .proto file.
+   */
+  @Override
+  int getNumber();
+
+  /**
+   * Return the value's descriptor, which contains information such as
+   * value name, number, and type.
+   */
+  EnumValueDescriptor getValueDescriptor();
+
+  /**
+   * Return the enum type's descriptor, which contains information
+   * about each defined value, etc.
+   */
+  EnumDescriptor getDescriptorForType();
+}
diff --git a/java/src/main/java/com/google/protobuf/ProtocolStringList.java b/java/core/src/main/java/com/google/protobuf/ProtocolStringList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ProtocolStringList.java
rename to java/core/src/main/java/com/google/protobuf/ProtocolStringList.java
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
new file mode 100644
index 0000000..29f567d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
@@ -0,0 +1,708 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * {@code RepeatedFieldBuilder} implements a structure that a protocol
+ * message uses to hold a repeated field of other protocol messages. It supports
+ * the classical use case of adding immutable {@link Message}'s to the
+ * repeated field and is highly optimized around this (no extra memory
+ * allocations and sharing of immutable arrays).
+ * <br>
+ * It also supports the additional use case of adding a {@link Message.Builder}
+ * to the repeated field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class RepeatedFieldBuilder
+    <MType extends GeneratedMessage,
+     BType extends GeneratedMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements GeneratedMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private GeneratedMessage.BuilderParent parent;
+
+  // List of messages. Never null. It may be immutable, in which case
+  // isMessagesListMutable will be false. See note below.
+  private List<MType> messages;
+
+  // Whether messages is an mutable array that can be modified.
+  private boolean isMessagesListMutable;
+
+  // List of builders. May be null, in which case, no nested builders were
+  // created. If not null, entries represent the builder for that index.
+  private List<SingleFieldBuilder<MType, BType, IType>> builders;
+
+  // Here are the invariants for messages and builders:
+  // 1. messages is never null and its count corresponds to the number of items
+  //    in the repeated field.
+  // 2. If builders is non-null, messages and builders MUST always
+  //    contain the same number of items.
+  // 3. Entries in either array can be null, but for any index, there MUST be
+  //    either a Message in messages or a builder in builders.
+  // 4. If the builder at an index is non-null, the builder is
+  //    authoritative. This is the case where a Builder was set on the index.
+  //    Any message in the messages array MUST be ignored.
+  // t. If the builder at an index is null, the message in the messages
+  //    list is authoritative. This is the case where a Message (not a Builder)
+  //    was set directly for an index.
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
+  private boolean isClean;
+
+  // A view of this builder that exposes a List interface of messages. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a message if it
+  // was a builder.
+  private MessageExternalList<MType, BType, IType> externalMessageList;
+
+  // A view of this builder that exposes a List interface of builders. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a builder if it
+  // was a message.
+  private BuilderExternalList<MType, BType, IType> externalBuilderList;
+
+  // A view of this builder that exposes a List interface of the interface
+  // implemented by messages and builders. This is initialized on demand. This
+  // is fully backed by this object and all changes are reflected in it.
+  // Access to any item returns either a builder or message depending on
+  // what is most efficient.
+  private MessageOrBuilderExternalList<MType, BType, IType>
+      externalMessageOrBuilderList;
+
+  /**
+   * Constructs a new builder with an empty list of messages.
+   *
+   * @param messages the current list of messages
+   * @param isMessagesListMutable Whether the messages list is mutable
+   * @param parent a listener to notify of changes
+   * @param isClean whether the builder is initially marked clean
+   */
+  public RepeatedFieldBuilder(
+      List<MType> messages,
+      boolean isMessagesListMutable,
+      GeneratedMessage.BuilderParent parent,
+      boolean isClean) {
+    this.messages = messages;
+    this.isMessagesListMutable = isMessagesListMutable;
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Ensures that the list of messages is mutable so it can be updated. If it's
+   * immutable, a copy is made.
+   */
+  private void ensureMutableMessageList() {
+    if (!isMessagesListMutable) {
+      messages = new ArrayList<MType>(messages);
+      isMessagesListMutable = true;
+    }
+  }
+
+  /**
+   * Ensures that the list of builders is not null. If it's null, the list is
+   * created and initialized to be the same size as the messages list with
+   * null entries.
+   */
+  private void ensureBuilders() {
+    if (this.builders == null) {
+      this.builders =
+          new ArrayList<SingleFieldBuilder<MType, BType, IType>>(
+              messages.size());
+      for (int i = 0; i < messages.size(); i++) {
+        builders.add(null);
+      }
+    }
+  }
+
+  /**
+   * Gets the count of items in the list.
+   *
+   * @return the count of items in the list.
+   */
+  public int getCount() {
+    return messages.size();
+  }
+
+  /**
+   * Gets whether the list is empty.
+   *
+   * @return whether the list is empty
+   */
+  public boolean isEmpty() {
+    return messages.isEmpty();
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @return the message for the specified index
+   */
+  public MType getMessage(int index) {
+    return getMessage(index, false);
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @param forBuild this is being called for build so we want to make sure
+   *     we SingleFieldBuilder.build to send dirty invalidations
+   * @return the message for the specified index
+   */
+  private MType getMessage(int index, boolean forBuild) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return messages.get(index);
+    }
+
+    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return messages.get(index);
+
+    } else {
+      return forBuild ? builder.build() : builder.getMessage();
+    }
+  }
+
+  /**
+   * Gets a builder for the specified index. If no builder has been created for
+   * that index, a builder is created on demand by calling
+   * {@link Message#toBuilder}.
+   *
+   * @param index the index of the message to get
+   * @return The builder for that index
+   */
+  public BType getBuilder(int index) {
+    ensureBuilders();
+    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      MType message = messages.get(index);
+      builder = new SingleFieldBuilder<MType, BType, IType>(
+          message, this, isClean);
+      builders.set(index, builder);
+    }
+    return builder.getBuilder();
+  }
+
+  /**
+   * Gets the base class interface for the specified index. This may either be
+   * a builder or a message. It will return whatever is more efficient.
+   *
+   * @param index the index of the message to get
+   * @return the message or builder for the index as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder(int index) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return (IType) messages.get(index);
+    }
+
+    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return (IType) messages.get(index);
+
+    } else {
+      return builder.getMessageOrBuilder();
+    }
+  }
+
+  /**
+   * Sets a  message at the specified index replacing the existing item at
+   * that index.
+   *
+   * @param index the index to set.
+   * @param message the message to set
+   * @return the builder
+   */
+  public RepeatedFieldBuilder<MType, BType, IType> setMessage(
+      int index, MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.set(index, message);
+    if (builders != null) {
+      SingleFieldBuilder<MType, BType, IType> entry =
+          builders.set(index, null);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends the specified element to the end of this list.
+   *
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilder<MType, BType, IType> addMessage(
+      MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.add(message);
+    if (builders != null) {
+      builders.add(null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Inserts the specified message at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the message
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilder<MType, BType, IType> addMessage(
+      int index, MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.add(index, message);
+    if (builders != null) {
+      builders.add(index, null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends all of the messages in the specified collection to the end of
+   * this list, in the order that they are returned by the specified
+   * collection's iterator.
+   *
+   * @param values the messages to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
+      Iterable<? extends MType> values) {
+    for (final MType value : values) {
+      if (value == null) {
+        throw new NullPointerException();
+      }
+    }
+
+    // If we can inspect the size, we can more efficiently add messages.
+    int size = -1;
+    if (values instanceof Collection) {
+      @SuppressWarnings("unchecked") final
+      Collection<MType> collection = (Collection<MType>) values;
+      if (collection.size() == 0) {
+        return this;
+      }
+      size = collection.size();
+    }
+    ensureMutableMessageList();
+
+    if (size >= 0 && messages instanceof ArrayList) {
+      ((ArrayList<MType>) messages)
+          .ensureCapacity(messages.size() + size);
+    }
+
+    for (MType value : values) {
+      addMessage(value);
+    }
+
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends a new builder to the end of this list and returns the builder.
+   *
+   * @param message the message to add which is the basis of the builder
+   * @return the new builder
+   */
+  public BType addBuilder(MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilder<MType, BType, IType> builder =
+        new SingleFieldBuilder<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(null);
+    builders.add(builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Inserts a new builder at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the builder
+   * @param message the message to add which is the basis of the builder
+   * @return the builder
+   */
+  public BType addBuilder(int index, MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilder<MType, BType, IType> builder =
+        new SingleFieldBuilder<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(index, null);
+    builders.add(index, builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Removes the element at the specified position in this list. Shifts any
+   * subsequent elements to the left (subtracts one from their indices).
+   * Returns the element that was removed from the list.
+   *
+   * @param index the index at which to remove the message
+   */
+  public void remove(int index) {
+    ensureMutableMessageList();
+    messages.remove(index);
+    if (builders != null) {
+      SingleFieldBuilder<MType, BType, IType> entry =
+          builders.remove(index);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Removes all of the elements from this list.
+   * The list will be empty after this call returns.
+   */
+  public void clear() {
+    messages = Collections.emptyList();
+    isMessagesListMutable = false;
+    if (builders != null) {
+      for (SingleFieldBuilder<MType, BType, IType> entry :
+          builders) {
+        if (entry != null) {
+          entry.dispose();
+        }
+      }
+      builders = null;
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Builds the list of messages from the builder and returns them.
+   *
+   * @return an immutable list of messages
+   */
+  public List<MType> build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+
+    if (!isMessagesListMutable && builders == null) {
+      // We still have an immutable list and we never created a builder.
+      return messages;
+    }
+
+    boolean allMessagesInSync = true;
+    if (!isMessagesListMutable) {
+      // We still have an immutable list. Let's see if any of them are out
+      // of sync with their builders.
+      for (int i = 0; i < messages.size(); i++) {
+        Message message = messages.get(i);
+        SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
+        if (builder != null) {
+          if (builder.build() != message) {
+            allMessagesInSync = false;
+            break;
+          }
+        }
+      }
+      if (allMessagesInSync) {
+        // Immutable list is still in sync.
+        return messages;
+      }
+    }
+
+    // Need to make sure messages is up to date
+    ensureMutableMessageList();
+    for (int i = 0; i < messages.size(); i++) {
+      messages.set(i, getMessage(i, true));
+    }
+
+    // We're going to return our list as immutable so we mark that we can
+    // no longer update it.
+    messages = Collections.unmodifiableList(messages);
+    isMessagesListMutable = false;
+    return messages;
+  }
+
+  /**
+   * Gets a view of the builder as a list of messages. The returned list is live
+   * and will reflect any changes to the underlying builder.
+   *
+   * @return the messages in the list
+   */
+  public List<MType> getMessageList() {
+    if (externalMessageList == null) {
+      externalMessageList =
+          new MessageExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of builders. This returned list is
+   * live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<BType> getBuilderList() {
+    if (externalBuilderList == null) {
+      externalBuilderList =
+          new BuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalBuilderList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of MessageOrBuilders. This returned
+   * list is live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<IType> getMessageOrBuilderList() {
+    if (externalMessageOrBuilderList == null) {
+      externalMessageOrBuilderList =
+          new MessageOrBuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageOrBuilderList;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+
+  /**
+   * Increments the mod counts so that an ConcurrentModificationException can
+   * be thrown if calling code tries to modify the builder while its iterating
+   * the list.
+   */
+  private void incrementModCounts() {
+    if (externalMessageList != null) {
+      externalMessageList.incrementModCount();
+    }
+    if (externalBuilderList != null) {
+      externalBuilderList.incrementModCount();
+    }
+    if (externalMessageOrBuilderList != null) {
+      externalMessageOrBuilderList.incrementModCount();
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of messages.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageExternalList<
+      MType extends GeneratedMessage,
+      BType extends GeneratedMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<MType> implements List<MType> {
+
+    RepeatedFieldBuilder<MType, BType, IType> builder;
+
+    MessageExternalList(
+        RepeatedFieldBuilder<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public MType get(int index) {
+      return builder.getMessage(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class BuilderExternalList<
+      MType extends GeneratedMessage,
+      BType extends GeneratedMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<BType> implements List<BType> {
+
+    RepeatedFieldBuilder<MType, BType, IType> builder;
+
+    BuilderExternalList(
+        RepeatedFieldBuilder<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public BType get(int index) {
+      return builder.getBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageOrBuilderExternalList<
+      MType extends GeneratedMessage,
+      BType extends GeneratedMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<IType> implements List<IType> {
+
+    RepeatedFieldBuilder<MType, BType, IType> builder;
+
+    MessageOrBuilderExternalList(
+        RepeatedFieldBuilder<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public IType get(int index) {
+      return builder.getMessageOrBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
new file mode 100644
index 0000000..3f3e9bd
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -0,0 +1,896 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+/**
+ * Class to represent {@code ByteStrings} formed by concatenation of other
+ * ByteStrings, without copying the data in the pieces. The concatenation is
+ * represented as a tree whose leaf nodes are each a
+ * {@link com.google.protobuf.ByteString.LeafByteString}.
+ *
+ * <p>Most of the operation here is inspired by the now-famous paper <a
+ * href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
+ * BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
+ * michael plass
+ *
+ * <p>The algorithms described in the paper have been implemented for character
+ * strings in {@code com.google.common.string.Rope} and in the c++ class {@code
+ * cord.cc}.
+ *
+ * <p>Fundamentally the Rope algorithm represents the collection of pieces as a
+ * binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
+ * sequence length, sequences that are too short relative to their depth cause a
+ * tree rebalance.  More precisely, a tree of depth d is "balanced" in the
+ * terminology of BAP95 if its length is at least F(d+2), where F(n) is the
+ * n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum
+ * lengths 1, 2, 3, 5, 8, 13,...
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+final class RopeByteString extends ByteString {
+
+  /**
+   * BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
+   * depth n is "balanced", i.e flat enough, if its length is at least Fn+2,
+   * e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at
+   * least 2, of depth 4 must have length >= 8, etc.
+   *
+   * <p>There's nothing special about using the Fibonacci numbers for this, but
+   * they are a reasonable sequence for encapsulating the idea that we are OK
+   * with longer strings being encoded in deeper binary trees.
+   *
+   * <p>For 32-bit integers, this array has length 46.
+   */
+  private static final int[] minLengthByDepth;
+
+  static {
+    // Dynamically generate the list of Fibonacci numbers the first time this
+    // class is accessed.
+    List<Integer> numbers = new ArrayList<Integer>();
+
+    // we skip the first Fibonacci number (1).  So instead of: 1 1 2 3 5 8 ...
+    // we have: 1 2 3 5 8 ...
+    int f1 = 1;
+    int f2 = 1;
+
+    // get all the values until we roll over.
+    while (f2 > 0) {
+      numbers.add(f2);
+      int temp = f1 + f2;
+      f1 = f2;
+      f2 = temp;
+    }
+
+    // we include this here so that we can index this array to [x + 1] in the
+    // loops below.
+    numbers.add(Integer.MAX_VALUE);
+    minLengthByDepth = new int[numbers.size()];
+    for (int i = 0; i < minLengthByDepth.length; i++) {
+      // unbox all the values
+      minLengthByDepth[i] = numbers.get(i);
+    }
+  }
+
+  private final int totalLength;
+  private final ByteString left;
+  private final ByteString right;
+  private final int leftLength;
+  private final int treeDepth;
+
+  /**
+   * Create a new RopeByteString, which can be thought of as a new tree node, by
+   * recording references to the two given strings.
+   *
+   * @param left  string on the left of this node, should have {@code size() >
+   *              0}
+   * @param right string on the right of this node, should have {@code size() >
+   *              0}
+   */
+  private RopeByteString(ByteString left, ByteString right) {
+    this.left = left;
+    this.right = right;
+    leftLength = left.size();
+    totalLength = leftLength + right.size();
+    treeDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
+  }
+
+  /**
+   * Concatenate the given strings while performing various optimizations to
+   * slow the growth rate of tree depth and tree node count. The result is
+   * either a {@link com.google.protobuf.ByteString.LeafByteString} or a
+   * {@link RopeByteString} depending on which optimizations, if any, were
+   * applied.
+   *
+   * <p>Small pieces of length less than {@link
+   * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
+   * BAP95.  Large pieces are referenced without copy.
+   *
+   * @param left  string on the left
+   * @param right string on the right
+   * @return concatenation representing the same sequence as the given strings
+   */
+  static ByteString concatenate(ByteString left, ByteString right) {
+    if (right.size() == 0) {
+      return left;
+    }
+
+    if (left.size() == 0) {
+      return right;
+    }
+
+    final int newLength = left.size() + right.size();
+    if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
+      // Optimization from BAP95: For short (leaves in paper, but just short
+      // here) total length, do a copy of data to a new leaf.
+      return concatenateBytes(left, right);
+    }
+
+    if (left instanceof RopeByteString) {
+      final RopeByteString leftRope = (RopeByteString) left;
+      if (leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
+        // Optimization from BAP95: As an optimization of the case where the
+        // ByteString is constructed by repeated concatenate, recognize the case
+        // where a short string is concatenated to a left-hand node whose
+        // right-hand branch is short.  In the paper this applies to leaves, but
+        // we just look at the length here. This has the advantage of shedding
+        // references to unneeded data when substrings have been taken.
+        //
+        // When we recognize this case, we do a copy of the data and create a
+        // new parent node so that the depth of the result is the same as the
+        // given left tree.
+        ByteString newRight = concatenateBytes(leftRope.right, right);
+        return new RopeByteString(leftRope.left, newRight);
+      }
+
+      if (leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
+          && leftRope.getTreeDepth() > right.getTreeDepth()) {
+        // Typically for concatenate-built strings the left-side is deeper than
+        // the right.  This is our final attempt to concatenate without
+        // increasing the tree depth.  We'll redo the node on the RHS.  This
+        // is yet another optimization for building the string by repeatedly
+        // concatenating on the right.
+        ByteString newRight = new RopeByteString(leftRope.right, right);
+        return new RopeByteString(leftRope.left, newRight);
+      }
+    }
+
+    // Fine, we'll add a node and increase the tree depth--unless we rebalance ;^)
+    int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
+    if (newLength >= minLengthByDepth[newDepth]) {
+      // The tree is shallow enough, so don't rebalance
+      return new RopeByteString(left, right);
+    }
+
+    return new Balancer().balance(left, right);
+  }
+
+  /**
+   * Concatenates two strings by copying data values. This is called in a few
+   * cases in order to reduce the growth of the number of tree nodes.
+   *
+   * @param left  string on the left
+   * @param right string on the right
+   * @return string formed by copying data bytes
+   */
+  private static ByteString concatenateBytes(ByteString left,
+      ByteString right) {
+    int leftSize = left.size();
+    int rightSize = right.size();
+    byte[] bytes = new byte[leftSize + rightSize];
+    left.copyTo(bytes, 0, 0, leftSize);
+    right.copyTo(bytes, 0, leftSize, rightSize);
+    return ByteString.wrap(bytes);  // Constructor wraps bytes
+  }
+
+  /**
+   * Create a new RopeByteString for testing only while bypassing all the
+   * defenses of {@link #concatenate(ByteString, ByteString)}. This allows
+   * testing trees of specific structure. We are also able to insert empty
+   * leaves, though these are dis-allowed, so that we can make sure the
+   * implementation can withstand their presence.
+   *
+   * @param left  string on the left of this node
+   * @param right string on the right of this node
+   * @return an unsafe instance for testing only
+   */
+  static RopeByteString newInstanceForTest(ByteString left, ByteString right) {
+    return new RopeByteString(left, right);
+  }
+
+  /**
+   * Gets the byte at the given index.
+   * Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility
+   * reasons although it would more properly be {@link
+   * IndexOutOfBoundsException}.
+   *
+   * @param index index of byte
+   * @return the value
+   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+   */
+  @Override
+  public byte byteAt(int index) {
+    checkIndex(index, totalLength);
+
+    // Find the relevant piece by recursive descent
+    if (index < leftLength) {
+      return left.byteAt(index);
+    }
+
+    return right.byteAt(index - leftLength);
+  }
+
+  @Override
+  public int size() {
+    return totalLength;
+  }
+
+  // =================================================================
+  // Pieces
+
+  @Override
+  protected int getTreeDepth() {
+    return treeDepth;
+  }
+
+  /**
+   * Determines if the tree is balanced according to BAP95, which means the tree
+   * is flat-enough with respect to the bounds. Note that this definition of
+   * balanced is one where sub-trees of balanced trees are not necessarily
+   * balanced.
+   *
+   * @return true if the tree is balanced
+   */
+  @Override
+  protected boolean isBalanced() {
+    return totalLength >= minLengthByDepth[treeDepth];
+  }
+
+  /**
+   * Takes a substring of this one. This involves recursive descent along the
+   * left and right edges of the substring, and referencing any wholly contained
+   * segments in between. Any leaf nodes entirely uninvolved in the substring
+   * will not be referenced by the substring.
+   *
+   * <p>Substrings of {@code length < 2} should result in at most a single
+   * recursive call chain, terminating at a leaf node. Thus the result will be a
+   * {@link com.google.protobuf.ByteString.LeafByteString}.
+   *
+   * @param beginIndex start at this index
+   * @param endIndex   the last character is the one before this index
+   * @return substring leaf node or tree
+   */
+  @Override
+  public ByteString substring(int beginIndex, int endIndex) {
+    final int length = checkRange(beginIndex, endIndex, totalLength);
+
+    if (length == 0) {
+      // Empty substring
+      return ByteString.EMPTY;
+    }
+
+    if (length == totalLength) {
+      // The whole string
+      return this;
+    }
+
+    // Proper substring
+    if (endIndex <= leftLength) {
+      // Substring on the left
+      return left.substring(beginIndex, endIndex);
+    }
+
+    if (beginIndex >= leftLength) {
+      // Substring on the right
+      return right.substring(beginIndex - leftLength, endIndex - leftLength);
+    }
+
+    // Split substring
+    ByteString leftSub = left.substring(beginIndex);
+    ByteString rightSub = right.substring(0, endIndex - leftLength);
+    // Intentionally not rebalancing, since in many cases these two
+    // substrings will already be less deep than the top-level
+    // RopeByteString we're taking a substring of.
+    return new RopeByteString(leftSub, rightSub);
+  }
+
+  // =================================================================
+  // ByteString -> byte[]
+
+  @Override
+  protected void copyToInternal(byte[] target, int sourceOffset,
+      int targetOffset, int numberToCopy) {
+   if (sourceOffset + numberToCopy <= leftLength) {
+      left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
+    } else if (sourceOffset >= leftLength) {
+      right.copyToInternal(target, sourceOffset - leftLength, targetOffset,
+          numberToCopy);
+    } else {
+      int leftLength = this.leftLength - sourceOffset;
+      left.copyToInternal(target, sourceOffset, targetOffset, leftLength);
+      right.copyToInternal(target, 0, targetOffset + leftLength,
+          numberToCopy - leftLength);
+    }
+  }
+
+  @Override
+  public void copyTo(ByteBuffer target) {
+    left.copyTo(target);
+    right.copyTo(target);
+  }
+
+  @Override
+  public ByteBuffer asReadOnlyByteBuffer() {
+    ByteBuffer byteBuffer = ByteBuffer.wrap(toByteArray());
+    return byteBuffer.asReadOnlyBuffer();
+  }
+
+  @Override
+  public List<ByteBuffer> asReadOnlyByteBufferList() {
+    // Walk through the list of LeafByteString's that make up this
+    // rope, and add each one as a read-only ByteBuffer.
+    List<ByteBuffer> result = new ArrayList<ByteBuffer>();
+    PieceIterator pieces = new PieceIterator(this);
+    while (pieces.hasNext()) {
+      LeafByteString byteString = pieces.next();
+      result.add(byteString.asReadOnlyByteBuffer());
+    }
+    return result;
+  }
+
+  @Override
+  public void writeTo(OutputStream outputStream) throws IOException {
+    left.writeTo(outputStream);
+    right.writeTo(outputStream);
+  }
+
+  @Override
+  void writeToInternal(OutputStream out, int sourceOffset,
+      int numberToWrite) throws IOException {
+    if (sourceOffset + numberToWrite <= leftLength) {
+      left.writeToInternal(out, sourceOffset, numberToWrite);
+    } else if (sourceOffset >= leftLength) {
+      right.writeToInternal(out, sourceOffset - leftLength, numberToWrite);
+    } else {
+      int numberToWriteInLeft = leftLength - sourceOffset;
+      left.writeToInternal(out, sourceOffset, numberToWriteInLeft);
+      right.writeToInternal(out, 0, numberToWrite - numberToWriteInLeft);
+    }
+  }
+
+  @Override
+  void writeTo(ByteOutput output) throws IOException {
+    left.writeTo(output);
+    right.writeTo(output);
+  }
+
+  @Override
+  protected String toStringInternal(Charset charset) {
+    return new String(toByteArray(), charset);
+  }
+
+  // =================================================================
+  // UTF-8 decoding
+
+  @Override
+  public boolean isValidUtf8() {
+    int leftPartial = left.partialIsValidUtf8(Utf8.COMPLETE, 0, leftLength);
+    int state = right.partialIsValidUtf8(leftPartial, 0, right.size());
+    return state == Utf8.COMPLETE;
+  }
+
+  @Override
+  protected int partialIsValidUtf8(int state, int offset, int length) {
+    int toIndex = offset + length;
+    if (toIndex <= leftLength) {
+      return left.partialIsValidUtf8(state, offset, length);
+    } else if (offset >= leftLength) {
+      return right.partialIsValidUtf8(state, offset - leftLength, length);
+    } else {
+      int leftLength = this.leftLength - offset;
+      int leftPartial = left.partialIsValidUtf8(state, offset, leftLength);
+      return right.partialIsValidUtf8(leftPartial, 0, length - leftLength);
+    }
+  }
+
+  // =================================================================
+  // equals() and hashCode()
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == this) {
+      return true;
+    }
+    if (!(other instanceof ByteString)) {
+      return false;
+    }
+
+    ByteString otherByteString = (ByteString) other;
+    if (totalLength != otherByteString.size()) {
+      return false;
+    }
+    if (totalLength == 0) {
+      return true;
+    }
+
+    // You don't really want to be calling equals on long strings, but since
+    // we cache the hashCode, we effectively cache inequality. We use the cached
+    // hashCode if it's already computed.  It's arguable we should compute the
+    // hashCode here, and if we're going to be testing a bunch of byteStrings,
+    // it might even make sense.
+    int thisHash = peekCachedHashCode();
+    int thatHash = otherByteString.peekCachedHashCode();
+    if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) {
+      return false;
+    }
+
+    return equalsFragments(otherByteString);
+  }
+
+  /**
+   * Determines if this string is equal to another of the same length by
+   * iterating over the leaf nodes. On each step of the iteration, the
+   * overlapping segments of the leaves are compared.
+   *
+   * @param other string of the same length as this one
+   * @return true if the values of this string equals the value of the given
+   *         one
+   */
+  private boolean equalsFragments(ByteString other) {
+    int thisOffset = 0;
+    Iterator<LeafByteString> thisIter = new PieceIterator(this);
+    LeafByteString thisString = thisIter.next();
+
+    int thatOffset = 0;
+    Iterator<LeafByteString> thatIter = new PieceIterator(other);
+    LeafByteString thatString = thatIter.next();
+
+    int pos = 0;
+    while (true) {
+      int thisRemaining = thisString.size() - thisOffset;
+      int thatRemaining = thatString.size() - thatOffset;
+      int bytesToCompare = Math.min(thisRemaining, thatRemaining);
+
+      // At least one of the offsets will be zero
+      boolean stillEqual = (thisOffset == 0)
+          ? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
+          : thatString.equalsRange(thisString, thisOffset, bytesToCompare);
+      if (!stillEqual) {
+        return false;
+      }
+
+      pos += bytesToCompare;
+      if (pos >= totalLength) {
+        if (pos == totalLength) {
+          return true;
+        }
+        throw new IllegalStateException();
+      }
+      // We always get to the end of at least one of the pieces
+      if (bytesToCompare == thisRemaining) { // If reached end of this
+        thisOffset = 0;
+        thisString = thisIter.next();
+      } else {
+        thisOffset += bytesToCompare;
+      }
+      if (bytesToCompare == thatRemaining) { // If reached end of that
+        thatOffset = 0;
+        thatString = thatIter.next();
+      } else {
+        thatOffset += bytesToCompare;
+      }
+    }
+  }
+
+  @Override
+  protected int partialHash(int h, int offset, int length) {
+    int toIndex = offset + length;
+    if (toIndex <= leftLength) {
+      return left.partialHash(h, offset, length);
+    } else if (offset >= leftLength) {
+      return right.partialHash(h, offset - leftLength, length);
+    } else {
+      int leftLength = this.leftLength - offset;
+      int leftPartial = left.partialHash(h, offset, leftLength);
+      return right.partialHash(leftPartial, 0, length - leftLength);
+    }
+  }
+
+  // =================================================================
+  // Input stream
+
+  @Override
+  public CodedInputStream newCodedInput() {
+    return CodedInputStream.newInstance(new RopeInputStream());
+  }
+
+  @Override
+  public InputStream newInput() {
+    return new RopeInputStream();
+  }
+
+  /**
+   * This class implements the balancing algorithm of BAP95. In the paper the
+   * authors use an array to keep track of pieces, while here we use a stack.
+   * The tree is balanced by traversing subtrees in left to right order, and the
+   * stack always contains the part of the string we've traversed so far.
+   *
+   * <p>One surprising aspect of the algorithm is the result of balancing is not
+   * necessarily balanced, though it is nearly balanced.  For details, see
+   * BAP95.
+   */
+  private static class Balancer {
+    // Stack containing the part of the string, starting from the left, that
+    // we've already traversed.  The final string should be the equivalent of
+    // concatenating the strings on the stack from bottom to top.
+    private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
+
+    private ByteString balance(ByteString left, ByteString right) {
+      doBalance(left);
+      doBalance(right);
+
+      // Sweep stack to gather the result
+      ByteString partialString = prefixesStack.pop();
+      while (!prefixesStack.isEmpty()) {
+        ByteString newLeft = prefixesStack.pop();
+        partialString = new RopeByteString(newLeft, partialString);
+      }
+      // We should end up with a RopeByteString since at a minimum we will
+      // create one from concatenating left and right
+      return partialString;
+    }
+
+    private void doBalance(ByteString root) {
+      // BAP95: Insert balanced subtrees whole. This means the result might not
+      // be balanced, leading to repeated rebalancings on concatenate. However,
+      // these rebalancings are shallow due to ignoring balanced subtrees, and
+      // relatively few calls to insert() result.
+      if (root.isBalanced()) {
+        insert(root);
+      } else if (root instanceof RopeByteString) {
+        RopeByteString rbs = (RopeByteString) root;
+        doBalance(rbs.left);
+        doBalance(rbs.right);
+      } else {
+        throw new IllegalArgumentException(
+            "Has a new type of ByteString been created? Found " +
+                root.getClass());
+      }
+    }
+
+    /**
+     * Push a string on the balance stack (BAP95).  BAP95 uses an array and
+     * calls the elements in the array 'bins'.  We instead use a stack, so the
+     * 'bins' of lengths are represented by differences between the elements of
+     * minLengthByDepth.
+     *
+     * <p>If the length bin for our string, and all shorter length bins, are
+     * empty, we just push it on the stack.  Otherwise, we need to start
+     * concatenating, putting the given string in the "middle" and continuing
+     * until we land in an empty length bin that matches the length of our
+     * concatenation.
+     *
+     * @param byteString string to place on the balance stack
+     */
+    private void insert(ByteString byteString) {
+      int depthBin = getDepthBinForLength(byteString.size());
+      int binEnd = minLengthByDepth[depthBin + 1];
+
+      // BAP95: Concatenate all trees occupying bins representing the length of
+      // our new piece or of shorter pieces, to the extent that is possible.
+      // The goal is to clear the bin which our piece belongs in, but that may
+      // not be entirely possible if there aren't enough longer bins occupied.
+      if (prefixesStack.isEmpty() || prefixesStack.peek().size() >= binEnd) {
+        prefixesStack.push(byteString);
+      } else {
+        int binStart = minLengthByDepth[depthBin];
+
+        // Concatenate the subtrees of shorter length
+        ByteString newTree = prefixesStack.pop();
+        while (!prefixesStack.isEmpty()
+            && prefixesStack.peek().size() < binStart) {
+          ByteString left = prefixesStack.pop();
+          newTree = new RopeByteString(left, newTree);
+        }
+
+        // Concatenate the given string
+        newTree = new RopeByteString(newTree, byteString);
+
+        // Continue concatenating until we land in an empty bin
+        while (!prefixesStack.isEmpty()) {
+          depthBin = getDepthBinForLength(newTree.size());
+          binEnd = minLengthByDepth[depthBin + 1];
+          if (prefixesStack.peek().size() < binEnd) {
+            ByteString left = prefixesStack.pop();
+            newTree = new RopeByteString(left, newTree);
+          } else {
+            break;
+          }
+        }
+        prefixesStack.push(newTree);
+      }
+    }
+
+    private int getDepthBinForLength(int length) {
+      int depth = Arrays.binarySearch(minLengthByDepth, length);
+      if (depth < 0) {
+        // It wasn't an exact match, so convert to the index of the containing
+        // fragment, which is one less even than the insertion point.
+        int insertionPoint = -(depth + 1);
+        depth = insertionPoint - 1;
+      }
+
+      return depth;
+    }
+  }
+
+  /**
+   * This class is a continuable tree traversal, which keeps the state
+   * information which would exist on the stack in a recursive traversal instead
+   * on a stack of "Bread Crumbs". The maximum depth of the stack in this
+   * iterator is the same as the depth of the tree being traversed.
+   *
+   * <p>This iterator is used to implement
+   * {@link RopeByteString#equalsFragments(ByteString)}.
+   */
+  private static class PieceIterator implements Iterator<LeafByteString> {
+
+    private final Stack<RopeByteString> breadCrumbs =
+        new Stack<RopeByteString>();
+    private LeafByteString next;
+
+    private PieceIterator(ByteString root) {
+      next = getLeafByLeft(root);
+    }
+
+    private LeafByteString getLeafByLeft(ByteString root) {
+      ByteString pos = root;
+      while (pos instanceof RopeByteString) {
+        RopeByteString rbs = (RopeByteString) pos;
+        breadCrumbs.push(rbs);
+        pos = rbs.left;
+      }
+      return (LeafByteString) pos;
+    }
+
+    private LeafByteString getNextNonEmptyLeaf() {
+      while (true) {
+        // Almost always, we go through this loop exactly once.  However, if
+        // we discover an empty string in the rope, we toss it and try again.
+        if (breadCrumbs.isEmpty()) {
+          return null;
+        } else {
+          LeafByteString result = getLeafByLeft(breadCrumbs.pop().right);
+          if (!result.isEmpty()) {
+            return result;
+          }
+        }
+      }
+    }
+
+    @Override
+    public boolean hasNext() {
+      return next != null;
+    }
+
+    /**
+     * Returns the next item and advances one
+     * {@link com.google.protobuf.ByteString.LeafByteString}.
+     *
+     * @return next non-empty LeafByteString or {@code null}
+     */
+    @Override
+    public LeafByteString next() {
+      if (next == null) {
+        throw new NoSuchElementException();
+      }
+      LeafByteString result = next;
+      next = getNextNonEmptyLeaf();
+      return result;
+    }
+
+    @Override
+    public void remove() {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  // =================================================================
+  // Serializable
+
+  private static final long serialVersionUID = 1L;
+
+  Object writeReplace() {
+    return ByteString.wrap(toByteArray());
+  }
+
+  private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
+    throw new InvalidObjectException(
+        "RopeByteStream instances are not to be serialized directly");
+  }
+
+  /**
+   * This class is the {@link RopeByteString} equivalent for
+   * {@link ByteArrayInputStream}.
+   */
+  private class RopeInputStream extends InputStream {
+    // Iterates through the pieces of the rope
+    private PieceIterator pieceIterator;
+    // The current piece
+    private LeafByteString currentPiece;
+    // The size of the current piece
+    private int currentPieceSize;
+    // The index of the next byte to read in the current piece
+    private int currentPieceIndex;
+    // The offset of the start of the current piece in the rope byte string
+    private int currentPieceOffsetInRope;
+    // Offset in the buffer at which user called mark();
+    private int mark;
+
+    public RopeInputStream() {
+      initialize();
+    }
+
+    @Override
+    public int read(byte b[], int offset, int length)  {
+      if (b == null) {
+        throw new NullPointerException();
+      } else if (offset < 0 || length < 0 || length > b.length - offset) {
+        throw new IndexOutOfBoundsException();
+      }
+      return readSkipInternal(b, offset, length);
+    }
+
+    @Override
+    public long skip(long length) {
+      if (length < 0) {
+        throw new IndexOutOfBoundsException();
+      } else if (length > Integer.MAX_VALUE) {
+        length = Integer.MAX_VALUE;
+      }
+      return readSkipInternal(null, 0, (int) length);
+    }
+
+    /**
+     * Internal implementation of read and skip.  If b != null, then read the
+     * next {@code length} bytes into the buffer {@code b} at
+     * offset {@code offset}.  If b == null, then skip the next {@code length}
+     * bytes.
+     * <p>
+     * This method assumes that all error checking has already happened.
+     * <p>
+     * Returns the actual number of bytes read or skipped.
+     */
+    private int readSkipInternal(byte b[], int offset, int length)  {
+      int bytesRemaining = length;
+      while (bytesRemaining > 0) {
+        advanceIfCurrentPieceFullyRead();
+        if (currentPiece == null) {
+          if (bytesRemaining == length) {
+             // We didn't manage to read anything
+             return -1;
+           }
+          break;
+        } else {
+          // Copy the bytes from this piece.
+          int currentPieceRemaining = currentPieceSize - currentPieceIndex;
+          int count = Math.min(currentPieceRemaining, bytesRemaining);
+          if (b != null) {
+            currentPiece.copyTo(b, currentPieceIndex, offset, count);
+            offset += count;
+          }
+          currentPieceIndex += count;
+          bytesRemaining -= count;
+        }
+      }
+       // Return the number of bytes read.
+      return length - bytesRemaining;
+    }
+
+    @Override
+    public int read() throws IOException {
+      advanceIfCurrentPieceFullyRead();
+      if (currentPiece == null) {
+        return -1;
+      } else {
+        return currentPiece.byteAt(currentPieceIndex++) & 0xFF;
+      }
+    }
+
+    @Override
+    public int available() throws IOException {
+      int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
+      return RopeByteString.this.size() - bytesRead;
+    }
+
+    @Override
+    public boolean markSupported() {
+      return true;
+    }
+
+    @Override
+    public void mark(int readAheadLimit) {
+      // Set the mark to our position in the byte string
+      mark = currentPieceOffsetInRope + currentPieceIndex;
+    }
+
+    @Override
+    public synchronized void reset() {
+      // Just reinitialize and skip the specified number of bytes.
+      initialize();
+      readSkipInternal(null, 0, mark);
+    }
+
+    /** Common initialization code used by both the constructor and reset() */
+    private void initialize() {
+      pieceIterator = new PieceIterator(RopeByteString.this);
+      currentPiece = pieceIterator.next();
+      currentPieceSize = currentPiece.size();
+      currentPieceIndex = 0;
+      currentPieceOffsetInRope = 0;
+    }
+
+    /**
+     * Skips to the next piece if we have read all the data in the current
+     * piece.  Sets currentPiece to null if we have reached the end of the
+     * input.
+     */
+    private void advanceIfCurrentPieceFullyRead() {
+      if (currentPiece != null && currentPieceIndex == currentPieceSize) {
+        // Generally, we can only go through this loop at most once, since
+        // empty strings can't end up in a rope.  But better to test.
+        currentPieceOffsetInRope += currentPieceSize;
+        currentPieceIndex = 0;
+        if (pieceIterator.hasNext()) {
+          currentPiece = pieceIterator.next();
+          currentPieceSize = currentPiece.size();
+        } else {
+          currentPiece = null;
+          currentPieceSize = 0;
+        }
+      }
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcCallback.java b/java/core/src/main/java/com/google/protobuf/RpcCallback.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcCallback.java
rename to java/core/src/main/java/com/google/protobuf/RpcCallback.java
diff --git a/java/src/main/java/com/google/protobuf/RpcChannel.java b/java/core/src/main/java/com/google/protobuf/RpcChannel.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcChannel.java
rename to java/core/src/main/java/com/google/protobuf/RpcChannel.java
diff --git a/java/src/main/java/com/google/protobuf/RpcController.java b/java/core/src/main/java/com/google/protobuf/RpcController.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcController.java
rename to java/core/src/main/java/com/google/protobuf/RpcController.java
diff --git a/java/core/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
new file mode 100644
index 0000000..f7d555a
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
@@ -0,0 +1,136 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Grab-bag of utility functions useful when dealing with RPCs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class RpcUtil {
+  private RpcUtil() {}
+
+  /**
+   * Take an {@code RpcCallback<Message>} and convert it to an
+   * {@code RpcCallback} accepting a specific message type.  This is always
+   * type-safe (parameter type contravariance).
+   */
+  @SuppressWarnings("unchecked")
+  public static <Type extends Message> RpcCallback<Type>
+  specializeCallback(final RpcCallback<Message> originalCallback) {
+    return (RpcCallback<Type>)originalCallback;
+    // The above cast works, but only due to technical details of the Java
+    // implementation.  A more theoretically correct -- but less efficient --
+    // implementation would be as follows:
+    //   return new RpcCallback<Type>() {
+    //     public void run(Type parameter) {
+    //       originalCallback.run(parameter);
+    //     }
+    //   };
+  }
+
+  /**
+   * Take an {@code RpcCallback} accepting a specific message type and convert
+   * it to an {@code RpcCallback<Message>}.  The generalized callback will
+   * accept any message object which has the same descriptor, and will convert
+   * it to the correct class before calling the original callback.  However,
+   * if the generalized callback is given a message with a different descriptor,
+   * an exception will be thrown.
+   */
+  public static <Type extends Message>
+  RpcCallback<Message> generalizeCallback(
+      final RpcCallback<Type> originalCallback,
+      final Class<Type> originalClass,
+      final Type defaultInstance) {
+    return new RpcCallback<Message>() {
+      @Override
+      public void run(final Message parameter) {
+        Type typedParameter;
+        try {
+          typedParameter = originalClass.cast(parameter);
+        } catch (ClassCastException ignored) {
+          typedParameter = copyAsType(defaultInstance, parameter);
+        }
+        originalCallback.run(typedParameter);
+      }
+    };
+  }
+
+  /**
+   * Creates a new message of type "Type" which is a copy of "source".  "source"
+   * must have the same descriptor but may be a different class (e.g.
+   * DynamicMessage).
+   */
+  @SuppressWarnings("unchecked")
+  private static <Type extends Message> Type copyAsType(
+      final Type typeDefaultInstance, final Message source) {
+    return (Type) typeDefaultInstance
+        .newBuilderForType().mergeFrom(source).build();
+  }
+
+  /**
+   * Creates a callback which can only be called once.  This may be useful for
+   * security, when passing a callback to untrusted code:  most callbacks do
+   * not expect to be called more than once, so doing so may expose bugs if it
+   * is not prevented.
+   */
+  public static <ParameterType>
+    RpcCallback<ParameterType> newOneTimeCallback(
+      final RpcCallback<ParameterType> originalCallback) {
+    return new RpcCallback<ParameterType>() {
+      private boolean alreadyCalled = false;
+
+      @Override
+      public void run(final ParameterType parameter) {
+        synchronized (this) {
+          if (alreadyCalled) {
+            throw new AlreadyCalledException();
+          }
+          alreadyCalled = true;
+        }
+
+        originalCallback.run(parameter);
+      }
+    };
+  }
+
+  /**
+   * Exception thrown when a one-time callback is called more than once.
+   */
+  public static final class AlreadyCalledException extends RuntimeException {
+    private static final long serialVersionUID = 5469741279507848266L;
+
+    public AlreadyCalledException() {
+      super("This RpcCallback was already called and cannot be called " +
+            "multiple times.");
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/Service.java b/java/core/src/main/java/com/google/protobuf/Service.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/Service.java
rename to java/core/src/main/java/com/google/protobuf/Service.java
diff --git a/java/src/main/java/com/google/protobuf/ServiceException.java b/java/core/src/main/java/com/google/protobuf/ServiceException.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ServiceException.java
rename to java/core/src/main/java/com/google/protobuf/ServiceException.java
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
new file mode 100644
index 0000000..941b5de
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
@@ -0,0 +1,241 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * {@code SingleFieldBuilder} implements a structure that a protocol
+ * message uses to hold a single field of another protocol message. It supports
+ * the classical use case of setting an immutable {@link Message} as the value
+ * of the field and is highly optimized around this.
+ * <br>
+ * It also supports the additional use case of setting a {@link Message.Builder}
+ * as the field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class SingleFieldBuilder
+    <MType extends GeneratedMessage,
+     BType extends GeneratedMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements GeneratedMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private GeneratedMessage.BuilderParent parent;
+
+  // Invariant: one of builder or message fields must be non-null.
+
+  // If set, this is the case where we are backed by a builder. In this case,
+  // message field represents a cached message for the builder (or null if
+  // there is no cached message).
+  private BType builder;
+
+  // If builder is non-null, this represents a cached message from the builder.
+  // If builder is null, this is the authoritative message for the field.
+  private MType message;
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
+  private boolean isClean;
+
+  public SingleFieldBuilder(
+      MType message,
+      GeneratedMessage.BuilderParent parent,
+      boolean isClean) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    this.message = message;
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Get the message for the field. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it. If no message has
+   * been set, returns the default instance of the message.
+   *
+   * @return the message for the field
+   */
+  @SuppressWarnings("unchecked")
+  public MType getMessage() {
+    if (message == null) {
+      // If message is null, the invariant is that we must be have a builder.
+      message = (MType) builder.buildPartial();
+    }
+    return message;
+  }
+
+  /**
+   * Builds the message and returns it.
+   *
+   * @return the message
+   */
+  public MType build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+    return getMessage();
+  }
+
+  /**
+   * Gets a builder for the field. If no builder has been created yet, a
+   * builder is created on demand by calling {@link Message#toBuilder}.
+   *
+   * @return The builder for the field
+   */
+  @SuppressWarnings("unchecked")
+  public BType getBuilder() {
+    if (builder == null) {
+      // builder.mergeFrom() on a fresh builder
+      // does not create any sub-objects with independent clean/dirty states,
+      // therefore setting the builder itself to clean without actually calling
+      // build() cannot break any invariants.
+      builder = (BType) message.newBuilderForType(this);
+      builder.mergeFrom(message); // no-op if message is the default message
+      builder.markClean();
+    }
+    return builder;
+  }
+
+  /**
+   * Gets the base class interface for the field. This may either be a builder
+   * or a message. It will return whatever is more efficient.
+   *
+   * @return the message or builder for the field as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder() {
+    if (builder != null) {
+      return  (IType) builder;
+    } else {
+      return (IType) message;
+    }
+  }
+
+  /**
+   * Sets a  message for the field replacing any existing value.
+   *
+   * @param message the message to set
+   * @return the builder
+   */
+  public SingleFieldBuilder<MType, BType, IType> setMessage(
+      MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    this.message = message;
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Merges the field from another field.
+   *
+   * @param value the value to merge from
+   * @return the builder
+   */
+  public SingleFieldBuilder<MType, BType, IType> mergeFrom(
+      MType value) {
+    if (builder == null && message == message.getDefaultInstanceForType()) {
+      message = value;
+    } else {
+      getBuilder().mergeFrom(value);
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Clears the value of the field.
+   *
+   * @return the builder
+   */
+  @SuppressWarnings("unchecked")
+  public SingleFieldBuilder<MType, BType, IType> clear() {
+    message = (MType) (message != null ?
+        message.getDefaultInstanceForType() :
+        builder.getDefaultInstanceForType());
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    // If builder is null, this is the case where onChanged is being called
+    // from setMessage or clear.
+    if (builder != null) {
+      message = null;
+    }
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
new file mode 100644
index 0000000..409fec1
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -0,0 +1,670 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A custom map implementation from FieldDescriptor to Object optimized to
+ * minimize the number of memory allocations for instances with a small number
+ * of mappings. The implementation stores the first {@code k} mappings in an
+ * array for a configurable value of {@code k}, allowing direct access to the
+ * corresponding {@code Entry}s without the need to create an Iterator. The
+ * remaining entries are stored in an overflow map. Iteration over the entries
+ * in the map should be done as follows:
+ *
+ * <pre>   {@code
+ * for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
+ *   process(fieldMap.getArrayEntryAt(i));
+ * }
+ * for (Map.Entry<K, V> entry : fieldMap.getOverflowEntries()) {
+ *   process(entry);
+ * }
+ * }</pre>
+ *
+ * The resulting iteration is in order of ascending field tag number. The
+ * object returned by {@link #entrySet()} adheres to the same contract but is
+ * less efficient as it necessarily involves creating an object for iteration.
+ * <p>
+ * The tradeoff for this memory efficiency is that the worst case running time
+ * of the {@code put()} operation is {@code O(k + lg n)}, which happens when
+ * entries are added in descending order. {@code k} should be chosen such that
+ * it covers enough common cases without adversely affecting larger maps. In
+ * practice, the worst case scenario does not happen for extensions because
+ * extension fields are serialized and deserialized in order of ascending tag
+ * number, but the worst case scenario can happen for DynamicMessages.
+ * <p>
+ * The running time for all other operations is similar to that of
+ * {@code TreeMap}.
+ * <p>
+ * Instances are not thread-safe until {@link #makeImmutable()} is called,
+ * after which any modifying operation will result in an
+ * {@link UnsupportedOperationException}.
+ *
+ * @author darick@google.com Darick Tong
+ */
+// This class is final for all intents and purposes because the constructor is
+// private. However, the FieldDescriptor-specific logic is encapsulated in
+// a subclass to aid testability of the core logic.
+class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
+
+  /**
+   * Creates a new instance for mapping FieldDescriptors to their values.
+   * The {@link #makeImmutable()} implementation will convert the List values
+   * of any repeated fields to unmodifiable lists.
+   *
+   * @param arraySize The size of the entry array containing the
+   *        lexicographically smallest mappings.
+   */
+  static <FieldDescriptorType extends
+      FieldSet.FieldDescriptorLite<FieldDescriptorType>>
+      SmallSortedMap<FieldDescriptorType, Object> newFieldMap(int arraySize) {
+    return new SmallSortedMap<FieldDescriptorType, Object>(arraySize) {
+      @Override
+      @SuppressWarnings("unchecked")
+      public void makeImmutable() {
+        if (!isImmutable()) {
+          for (int i = 0; i < getNumArrayEntries(); i++) {
+            final Map.Entry<FieldDescriptorType, Object> entry =
+                getArrayEntryAt(i);
+            if (entry.getKey().isRepeated()) {
+              final List value = (List) entry.getValue();
+              entry.setValue(Collections.unmodifiableList(value));
+            }
+          }
+          for (Map.Entry<FieldDescriptorType, Object> entry :
+                   getOverflowEntries()) {
+            if (entry.getKey().isRepeated()) {
+              final List value = (List) entry.getValue();
+              entry.setValue(Collections.unmodifiableList(value));
+            }
+          }
+        }
+        super.makeImmutable();
+      }
+    };
+  }
+
+  /**
+   * Creates a new instance for testing.
+   *
+   * @param arraySize The size of the entry array containing the
+   *        lexicographically smallest mappings.
+   */
+  static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest(
+      int arraySize) {
+    return new SmallSortedMap<K, V>(arraySize);
+  }
+
+  private final int maxArraySize;
+  // The "entry array" is actually a List because generic arrays are not
+  // allowed. ArrayList also nicely handles the entry shifting on inserts and
+  // removes.
+  private List<Entry> entryList;
+  private Map<K, V> overflowEntries;
+  private boolean isImmutable;
+  // The EntrySet is a stateless view of the Map. It's initialized the first
+  // time it is requested and reused henceforth.
+  private volatile EntrySet lazyEntrySet;
+
+  /**
+   * @code arraySize Size of the array in which the lexicographically smallest
+   *       mappings are stored. (i.e. the {@code k} referred to in the class
+   *       documentation).
+   */
+  private SmallSortedMap(int arraySize) {
+    this.maxArraySize = arraySize;
+    this.entryList = Collections.emptyList();
+    this.overflowEntries = Collections.emptyMap();
+  }
+
+  /** Make this map immutable from this point forward. */
+  public void makeImmutable() {
+    if (!isImmutable) {
+      // Note: There's no need to wrap the entryList in an unmodifiableList
+      // because none of the list's accessors are exposed. The iterator() of
+      // overflowEntries, on the other hand, is exposed so it must be made
+      // unmodifiable.
+      overflowEntries = overflowEntries.isEmpty() ?
+          Collections.<K, V>emptyMap() :
+          Collections.unmodifiableMap(overflowEntries);
+      isImmutable = true;
+    }
+  }
+
+  /** @return Whether {@link #makeImmutable()} has been called. */
+  public boolean isImmutable() {
+    return isImmutable;
+  }
+
+  /** @return The number of entries in the entry array. */
+  public int getNumArrayEntries() {
+    return entryList.size();
+  }
+
+  /** @return The array entry at the given {@code index}. */
+  public Map.Entry<K, V> getArrayEntryAt(int index) {
+    return entryList.get(index);
+  }
+
+  /** @return There number of overflow entries. */
+  public int getNumOverflowEntries() {
+    return overflowEntries.size();
+  }
+
+  /** @return An iterable over the overflow entries. */
+  public Iterable<Map.Entry<K, V>> getOverflowEntries() {
+    return overflowEntries.isEmpty() ?
+        EmptySet.<Map.Entry<K, V>>iterable() :
+        overflowEntries.entrySet();
+  }
+
+  @Override
+  public int size() {
+    return entryList.size() + overflowEntries.size();
+  }
+
+  /**
+   * The implementation throws a {@code ClassCastException} if o is not an
+   * object of type {@code K}.
+   *
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean containsKey(Object o) {
+    @SuppressWarnings("unchecked")
+    final K key = (K) o;
+    return binarySearchInArray(key) >= 0 || overflowEntries.containsKey(key);
+  }
+
+  /**
+   * The implementation throws a {@code ClassCastException} if o is not an
+   * object of type {@code K}.
+   *
+   * {@inheritDoc}
+   */
+  @Override
+  public V get(Object o) {
+    @SuppressWarnings("unchecked")
+    final K key = (K) o;
+    final int index = binarySearchInArray(key);
+    if (index >= 0) {
+      return entryList.get(index).getValue();
+    }
+    return overflowEntries.get(key);
+  }
+
+  @Override
+  public V put(K key, V value) {
+    checkMutable();
+    final int index = binarySearchInArray(key);
+    if (index >= 0) {
+      // Replace existing array entry.
+      return entryList.get(index).setValue(value);
+    }
+    ensureEntryArrayMutable();
+    final int insertionPoint = -(index + 1);
+    if (insertionPoint >= maxArraySize) {
+      // Put directly in overflow.
+      return getOverflowEntriesMutable().put(key, value);
+    }
+    // Insert new Entry in array.
+    if (entryList.size() == maxArraySize) {
+      // Shift the last array entry into overflow.
+      final Entry lastEntryInArray = entryList.remove(maxArraySize - 1);
+      getOverflowEntriesMutable().put(lastEntryInArray.getKey(),
+                                      lastEntryInArray.getValue());
+    }
+    entryList.add(insertionPoint, new Entry(key, value));
+    return null;
+  }
+
+  @Override
+  public void clear() {
+    checkMutable();
+    if (!entryList.isEmpty()) {
+      entryList.clear();
+    }
+    if (!overflowEntries.isEmpty()) {
+      overflowEntries.clear();
+    }
+  }
+
+  /**
+   * The implementation throws a {@code ClassCastException} if o is not an
+   * object of type {@code K}.
+   *
+   * {@inheritDoc}
+   */
+  @Override
+  public V remove(Object o) {
+    checkMutable();
+    @SuppressWarnings("unchecked")
+    final K key = (K) o;
+    final int index = binarySearchInArray(key);
+    if (index >= 0) {
+      return removeArrayEntryAt(index);
+    }
+    // overflowEntries might be Collections.unmodifiableMap(), so only
+    // call remove() if it is non-empty.
+    if (overflowEntries.isEmpty()) {
+      return null;
+    } else {
+      return overflowEntries.remove(key);
+    }
+  }
+
+  private V removeArrayEntryAt(int index) {
+    checkMutable();
+    final V removed = entryList.remove(index).getValue();
+    if (!overflowEntries.isEmpty()) {
+      // Shift the first entry in the overflow to be the last entry in the
+      // array.
+      final Iterator<Map.Entry<K, V>> iterator =
+          getOverflowEntriesMutable().entrySet().iterator();
+      entryList.add(new Entry(iterator.next()));
+      iterator.remove();
+    }
+    return removed;
+  }
+
+  /**
+   * @param key The key to find in the entry array.
+   * @return The returned integer position follows the same semantics as the
+   *     value returned by {@link java.util.Arrays#binarySearch()}.
+   */
+  private int binarySearchInArray(K key) {
+    int left = 0;
+    int right = entryList.size() - 1;
+
+    // Optimization: For the common case in which entries are added in
+    // ascending tag order, check the largest element in the array before
+    // doing a full binary search.
+    if (right >= 0) {
+      int cmp = key.compareTo(entryList.get(right).getKey());
+      if (cmp > 0) {
+        return -(right + 2);  // Insert point is after "right".
+      } else if (cmp == 0) {
+        return right;
+      }
+    }
+
+    while (left <= right) {
+      int mid = (left + right) / 2;
+      int cmp = key.compareTo(entryList.get(mid).getKey());
+      if (cmp < 0) {
+        right = mid - 1;
+      } else if (cmp > 0) {
+        left = mid + 1;
+      } else {
+        return mid;
+      }
+    }
+    return -(left + 1);
+  }
+
+  /**
+   * Similar to the AbstractMap implementation of {@code keySet()} and
+   * {@code values()}, the entry set is created the first time this method is
+   * called, and returned in response to all subsequent calls.
+   *
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Map.Entry<K, V>> entrySet() {
+    if (lazyEntrySet == null) {
+      lazyEntrySet = new EntrySet();
+    }
+    return lazyEntrySet;
+  }
+
+  /**
+   * @throws UnsupportedOperationException if {@link #makeImmutable()} has
+   *         has been called.
+   */
+  private void checkMutable() {
+    if (isImmutable) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  /**
+   * @return a {@link SortedMap} to which overflow entries mappings can be
+   *         added or removed.
+   * @throws UnsupportedOperationException if {@link #makeImmutable()} has been
+   *         called.
+   */
+  @SuppressWarnings("unchecked")
+  private SortedMap<K, V> getOverflowEntriesMutable() {
+    checkMutable();
+    if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) {
+      overflowEntries = new TreeMap<K, V>();
+    }
+    return (SortedMap<K, V>) overflowEntries;
+  }
+
+  /**
+   * Lazily creates the entry list. Any code that adds to the list must first
+   * call this method.
+   */
+  private void ensureEntryArrayMutable() {
+    checkMutable();
+    if (entryList.isEmpty() && !(entryList instanceof ArrayList)) {
+      entryList = new ArrayList<Entry>(maxArraySize);
+    }
+  }
+
+  /**
+   * Entry implementation that implements Comparable in order to support
+   * binary search within the entry array. Also checks mutability in
+   * {@link #setValue()}.
+   */
+  private class Entry implements Map.Entry<K, V>, Comparable<Entry> {
+
+    private final K key;
+    private V value;
+
+    Entry(Map.Entry<K, V> copy) {
+      this(copy.getKey(), copy.getValue());
+    }
+
+    Entry(K key, V value) {
+      this.key = key;
+      this.value = value;
+    }
+
+    @Override
+    public K getKey() {
+      return key;
+    }
+
+    @Override
+    public V getValue() {
+      return value;
+    }
+
+    @Override
+    public int compareTo(Entry other) {
+      return getKey().compareTo(other.getKey());
+    }
+
+    @Override
+    public V setValue(V newValue) {
+      checkMutable();
+      final V oldValue = this.value;
+      this.value = newValue;
+      return oldValue;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o == this) {
+        return true;
+      }
+      if (!(o instanceof Map.Entry)) {
+        return false;
+      }
+      @SuppressWarnings("unchecked")
+      Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
+      return equals(key, other.getKey()) && equals(value, other.getValue());
+    }
+
+    @Override
+    public int hashCode() {
+      return (key == null ? 0 : key.hashCode()) ^
+          (value == null ? 0 : value.hashCode());
+    }
+
+    @Override
+    public String toString() {
+      return key + "=" + value;
+    }
+
+    /** equals() that handles null values. */
+    private boolean equals(Object o1, Object o2) {
+      return o1 == null ? o2 == null : o1.equals(o2);
+    }
+  }
+
+  /**
+   * Stateless view of the entries in the field map.
+   */
+  private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
+
+    @Override
+    public Iterator<Map.Entry<K, V>> iterator() {
+      return new EntryIterator();
+    }
+
+    @Override
+    public int size() {
+      return SmallSortedMap.this.size();
+    }
+
+    /**
+     * Throws a {@link ClassCastException} if o is not of the expected type.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean contains(Object o) {
+      @SuppressWarnings("unchecked")
+      final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
+      final V existing = get(entry.getKey());
+      final V value = entry.getValue();
+      return existing == value ||
+          (existing != null && existing.equals(value));
+    }
+
+    @Override
+    public boolean add(Map.Entry<K, V> entry) {
+      if (!contains(entry)) {
+        put(entry.getKey(), entry.getValue());
+        return true;
+      }
+      return false;
+    }
+
+    /**
+     * Throws a {@link ClassCastException} if o is not of the expected type.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean remove(Object o) {
+      @SuppressWarnings("unchecked")
+      final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
+      if (contains(entry)) {
+        SmallSortedMap.this.remove(entry.getKey());
+        return true;
+      }
+      return false;
+    }
+
+    @Override
+    public void clear() {
+      SmallSortedMap.this.clear();
+    }
+  }
+
+  /**
+   * Iterator implementation that switches from the entry array to the overflow
+   * entries appropriately.
+   */
+  private class EntryIterator implements Iterator<Map.Entry<K, V>> {
+
+    private int pos = -1;
+    private boolean nextCalledBeforeRemove;
+    private Iterator<Map.Entry<K, V>> lazyOverflowIterator;
+
+    @Override
+    public boolean hasNext() {
+      return (pos + 1) < entryList.size() ||
+          getOverflowIterator().hasNext();
+    }
+
+    @Override
+    public Map.Entry<K, V> next() {
+      nextCalledBeforeRemove = true;
+      // Always increment pos so that we know whether the last returned value
+      // was from the array or from overflow.
+      if (++pos < entryList.size()) {
+        return entryList.get(pos);
+      }
+      return getOverflowIterator().next();
+    }
+
+    @Override
+    public void remove() {
+      if (!nextCalledBeforeRemove) {
+        throw new IllegalStateException("remove() was called before next()");
+      }
+      nextCalledBeforeRemove = false;
+      checkMutable();
+
+      if (pos < entryList.size()) {
+        removeArrayEntryAt(pos--);
+      } else {
+        getOverflowIterator().remove();
+      }
+    }
+
+    /**
+     * It is important to create the overflow iterator only after the array
+     * entries have been iterated over because the overflow entry set changes
+     * when the client calls remove() on the array entries, which invalidates
+     * any existing iterators.
+     */
+    private Iterator<Map.Entry<K, V>> getOverflowIterator() {
+      if (lazyOverflowIterator == null) {
+        lazyOverflowIterator = overflowEntries.entrySet().iterator();
+      }
+      return lazyOverflowIterator;
+    }
+  }
+
+  /**
+   * Helper class that holds immutable instances of an Iterable/Iterator that
+   * we return when the overflow entries is empty. This eliminates the creation
+   * of an Iterator object when there is nothing to iterate over.
+   */
+  private static class EmptySet {
+
+    private static final Iterator<Object> ITERATOR =
+        new Iterator<Object>() {
+          @Override
+          public boolean hasNext() {
+            return false;
+          }
+          @Override
+          public Object next() {
+            throw new NoSuchElementException();
+          }
+          @Override
+          public void remove() {
+            throw new UnsupportedOperationException();
+          }
+        };
+
+    private static final Iterable<Object> ITERABLE =
+        new Iterable<Object>() {
+          @Override
+          public Iterator<Object> iterator() {
+            return ITERATOR;
+          }
+        };
+
+    @SuppressWarnings("unchecked")
+    static <T> Iterable<T> iterable() {
+      return (Iterable<T>) ITERABLE;
+    }
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    
+    if (!(o instanceof SmallSortedMap)) {
+      return super.equals(o);
+    }
+    
+    SmallSortedMap<?, ?> other = (SmallSortedMap<?, ?>) o;
+    final int size = size();
+    if (size != other.size()) {
+      return false;
+    }
+    
+    // Best effort try to avoid allocating an entry set.
+    final int numArrayEntries = getNumArrayEntries();
+    if (numArrayEntries != other.getNumArrayEntries()) {
+      return entrySet().equals(other.entrySet());
+    }
+    
+    for (int i = 0; i < numArrayEntries; i++) {
+      if (!getArrayEntryAt(i).equals(other.getArrayEntryAt(i))) {
+        return false;
+      }
+    }
+    
+    if (numArrayEntries != size) {
+      return overflowEntries.equals(other.overflowEntries);
+    }
+    
+    
+    return true;
+  }
+  
+  @Override
+  public int hashCode() {
+    int h = 0;
+    final int listSize = getNumArrayEntries();
+    for (int i = 0; i < listSize; i++) {
+      h += entryList.get(i).hashCode();
+    }
+    // Avoid the iterator allocation if possible.
+    if (getNumOverflowEntries() > 0) {
+      h += overflowEntries.hashCode();
+    }
+    return h;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
new file mode 100644
index 0000000..c1c328f
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -0,0 +1,2071 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provide text parsing and formatting support for proto2 instances.
+ * The implementation largely follows google/protobuf/text_format.cc.
+ *
+ * @author wenboz@google.com Wenbo Zhu
+ * @author kenton@google.com Kenton Varda
+ */
+public final class TextFormat {
+  private TextFormat() {}
+
+  private static final Logger logger =
+      Logger.getLogger(TextFormat.class.getName());
+
+  private static final Printer DEFAULT_PRINTER = new Printer();
+  private static final Printer SINGLE_LINE_PRINTER =
+      (new Printer()).setSingleLineMode(true);
+  private static final Printer UNICODE_PRINTER =
+      (new Printer()).setEscapeNonAscii(false);
+
+  /**
+   * Outputs a textual representation of the Protocol Message supplied into
+   * the parameter output. (This representation is the new version of the
+   * classic "ProtocolPrinter" output from the original Protocol Buffer system)
+   */
+  public static void print(
+      final MessageOrBuilder message, final Appendable output)
+      throws IOException {
+    DEFAULT_PRINTER.print(message, new TextGenerator(output));
+  }
+
+  /** Outputs a textual representation of {@code fields} to {@code output}. */
+  public static void print(final UnknownFieldSet fields,
+                           final Appendable output)
+                           throws IOException {
+    DEFAULT_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+  }
+
+  /**
+   * Same as {@code print()}, except that non-ASCII characters are not
+   * escaped.
+   */
+  public static void printUnicode(
+      final MessageOrBuilder message, final Appendable output)
+      throws IOException {
+    UNICODE_PRINTER.print(message, new TextGenerator(output));
+  }
+
+  /**
+   * Same as {@code print()}, except that non-ASCII characters are not
+   * escaped.
+   */
+  public static void printUnicode(final UnknownFieldSet fields,
+                                  final Appendable output)
+                                  throws IOException {
+    UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
+  }
+
+  /**
+   * Generates a human readable form of this message, useful for debugging and
+   * other purposes, with no newline characters.
+   */
+  public static String shortDebugString(final MessageOrBuilder message) {
+    try {
+      final StringBuilder sb = new StringBuilder();
+      SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb));
+      // Single line mode currently might have an extra space at the end.
+      return sb.toString().trim();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Generates a human readable form of the field, useful for debugging
+   * and other purposes, with no newline characters.
+   */
+  public static String shortDebugString(final FieldDescriptor field,
+                                        final Object value) {
+    try {
+      final StringBuilder sb = new StringBuilder();
+      SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
+      return sb.toString().trim();
+    } catch (IOException e) {
+        throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Generates a human readable form of the unknown fields, useful for debugging
+   * and other purposes, with no newline characters.
+   */
+  public static String shortDebugString(final UnknownFieldSet fields) {
+    try {
+      final StringBuilder sb = new StringBuilder();
+      SINGLE_LINE_PRINTER.printUnknownFields(fields, new TextGenerator(sb));
+      // Single line mode currently might have an extra space at the end.
+      return sb.toString().trim();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Like {@code print()}, but writes directly to a {@code String} and
+   * returns it.
+   */
+  public static String printToString(final MessageOrBuilder message) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      print(message, text);
+      return text.toString();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Like {@code print()}, but writes directly to a {@code String} and
+   * returns it.
+   */
+  public static String printToString(final UnknownFieldSet fields) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      print(fields, text);
+      return text.toString();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Same as {@code printToString()}, except that non-ASCII characters
+   * in string type fields are not escaped in backslash+octals.
+   */
+  public static String printToUnicodeString(final MessageOrBuilder message) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      UNICODE_PRINTER.print(message, new TextGenerator(text));
+      return text.toString();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Same as {@code printToString()}, except that non-ASCII characters
+   * in string type fields are not escaped in backslash+octals.
+   */
+  public static String printToUnicodeString(final UnknownFieldSet fields) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text));
+      return text.toString();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  public static void printField(final FieldDescriptor field,
+                                final Object value,
+                                final Appendable output)
+                                throws IOException {
+    DEFAULT_PRINTER.printField(field, value, new TextGenerator(output));
+  }
+
+  public static String printFieldToString(final FieldDescriptor field,
+                                          final Object value) {
+    try {
+      final StringBuilder text = new StringBuilder();
+      printField(field, value, text);
+      return text.toString();
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  /**
+   * Outputs a textual representation of the value of given field value.
+   *
+   * @param field the descriptor of the field
+   * @param value the value of the field
+   * @param output the output to which to append the formatted value
+   * @throws ClassCastException if the value is not appropriate for the
+   *     given field descriptor
+   * @throws IOException if there is an exception writing to the output
+   */
+  public static void printFieldValue(final FieldDescriptor field,
+                                     final Object value,
+                                     final Appendable output)
+                                     throws IOException {
+    DEFAULT_PRINTER.printFieldValue(field, value, new TextGenerator(output));
+  }
+
+  /**
+   * Outputs a textual representation of the value of an unknown field.
+   *
+   * @param tag the field's tag number
+   * @param value the value of the field
+   * @param output the output to which to append the formatted value
+   * @throws ClassCastException if the value is not appropriate for the
+   *     given field descriptor
+   * @throws IOException if there is an exception writing to the output
+   */
+  public static void printUnknownFieldValue(final int tag,
+                                            final Object value,
+                                            final Appendable output)
+                                            throws IOException {
+    printUnknownFieldValue(tag, value, new TextGenerator(output));
+  }
+
+  private static void printUnknownFieldValue(final int tag,
+                                             final Object value,
+                                             final TextGenerator generator)
+                                             throws IOException {
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT:
+        generator.print(unsignedToString((Long) value));
+        break;
+      case WireFormat.WIRETYPE_FIXED32:
+        generator.print(
+            String.format((Locale) null, "0x%08x", (Integer) value));
+        break;
+      case WireFormat.WIRETYPE_FIXED64:
+        generator.print(String.format((Locale) null, "0x%016x", (Long) value));
+        break;
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+        generator.print("\"");
+        generator.print(escapeBytes((ByteString) value));
+        generator.print("\"");
+        break;
+      case WireFormat.WIRETYPE_START_GROUP:
+        DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator);
+        break;
+      default:
+        throw new IllegalArgumentException("Bad tag: " + tag);
+    }
+  }
+
+  /** Helper class for converting protobufs to text. */
+  private static final class Printer {
+    /** Whether to omit newlines from the output. */
+    boolean singleLineMode = false;
+
+    /** Whether to escape non ASCII characters with backslash and octal. */
+    boolean escapeNonAscii = true;
+
+    private Printer() {}
+
+    /** Setter of singleLineMode */
+    private Printer setSingleLineMode(boolean singleLineMode) {
+      this.singleLineMode = singleLineMode;
+      return this;
+    }
+
+    /** Setter of escapeNonAscii */
+    private Printer setEscapeNonAscii(boolean escapeNonAscii) {
+      this.escapeNonAscii = escapeNonAscii;
+      return this;
+    }
+
+    private void print(
+        final MessageOrBuilder message, final TextGenerator generator)
+        throws IOException {
+      for (Map.Entry<FieldDescriptor, Object> field
+          : message.getAllFields().entrySet()) {
+        printField(field.getKey(), field.getValue(), generator);
+      }
+      printUnknownFields(message.getUnknownFields(), generator);
+    }
+
+    private void printField(final FieldDescriptor field, final Object value,
+        final TextGenerator generator) throws IOException {
+      if (field.isRepeated()) {
+        // Repeated field.  Print each element.
+        for (Object element : (List<?>) value) {
+          printSingleField(field, element, generator);
+        }
+      } else {
+        printSingleField(field, value, generator);
+      }
+    }
+
+    private void printSingleField(final FieldDescriptor field,
+                                  final Object value,
+                                  final TextGenerator generator)
+                                  throws IOException {
+      if (field.isExtension()) {
+        generator.print("[");
+        // We special-case MessageSet elements for compatibility with proto1.
+        if (field.getContainingType().getOptions().getMessageSetWireFormat()
+            && (field.getType() == FieldDescriptor.Type.MESSAGE)
+            && (field.isOptional())
+            // object equality
+            && (field.getExtensionScope() == field.getMessageType())) {
+          generator.print(field.getMessageType().getFullName());
+        } else {
+          generator.print(field.getFullName());
+        }
+        generator.print("]");
+      } else {
+        if (field.getType() == FieldDescriptor.Type.GROUP) {
+          // Groups must be serialized with their original capitalization.
+          generator.print(field.getMessageType().getName());
+        } else {
+          generator.print(field.getName());
+        }
+      }
+
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (singleLineMode) {
+          generator.print(" { ");
+        } else {
+          generator.print(" {\n");
+          generator.indent();
+        }
+      } else {
+        generator.print(": ");
+      }
+
+      printFieldValue(field, value, generator);
+
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (singleLineMode) {
+          generator.print("} ");
+        } else {
+          generator.outdent();
+          generator.print("}\n");
+        }
+      } else {
+        if (singleLineMode) {
+          generator.print(" ");
+        } else {
+          generator.print("\n");
+        }
+      }
+    }
+
+    private void printFieldValue(final FieldDescriptor field,
+                                 final Object value,
+                                 final TextGenerator generator)
+                                 throws IOException {
+      switch (field.getType()) {
+        case INT32:
+        case SINT32:
+        case SFIXED32:
+          generator.print(((Integer) value).toString());
+          break;
+
+        case INT64:
+        case SINT64:
+        case SFIXED64:
+          generator.print(((Long) value).toString());
+          break;
+
+        case BOOL:
+          generator.print(((Boolean) value).toString());
+          break;
+
+        case FLOAT:
+          generator.print(((Float) value).toString());
+          break;
+
+        case DOUBLE:
+          generator.print(((Double) value).toString());
+          break;
+
+        case UINT32:
+        case FIXED32:
+          generator.print(unsignedToString((Integer) value));
+          break;
+
+        case UINT64:
+        case FIXED64:
+          generator.print(unsignedToString((Long) value));
+          break;
+
+        case STRING:
+          generator.print("\"");
+          generator.print(escapeNonAscii
+              ? TextFormatEscaper.escapeText((String) value)
+              : escapeDoubleQuotesAndBackslashes((String) value)
+                  .replace("\n", "\\n"));
+          generator.print("\"");
+          break;
+
+        case BYTES:
+          generator.print("\"");
+          if (value instanceof ByteString) {
+            generator.print(escapeBytes((ByteString) value));
+          } else {
+            generator.print(escapeBytes((byte[]) value));
+          }
+          generator.print("\"");
+          break;
+
+        case ENUM:
+          generator.print(((EnumValueDescriptor) value).getName());
+          break;
+
+        case MESSAGE:
+        case GROUP:
+          print((Message) value, generator);
+          break;
+      }
+    }
+
+    private void printUnknownFields(final UnknownFieldSet unknownFields,
+                                    final TextGenerator generator)
+                                    throws IOException {
+      for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+               unknownFields.asMap().entrySet()) {
+        final int number = entry.getKey();
+        final UnknownFieldSet.Field field = entry.getValue();
+        printUnknownField(number, WireFormat.WIRETYPE_VARINT,
+            field.getVarintList(), generator);
+        printUnknownField(number, WireFormat.WIRETYPE_FIXED32,
+            field.getFixed32List(), generator);
+        printUnknownField(number, WireFormat.WIRETYPE_FIXED64,
+            field.getFixed64List(), generator);
+        printUnknownField(number, WireFormat.WIRETYPE_LENGTH_DELIMITED,
+            field.getLengthDelimitedList(), generator);
+        for (final UnknownFieldSet value : field.getGroupList()) {
+          generator.print(entry.getKey().toString());
+          if (singleLineMode) {
+            generator.print(" { ");
+          } else {
+            generator.print(" {\n");
+            generator.indent();
+          }
+          printUnknownFields(value, generator);
+          if (singleLineMode) {
+            generator.print("} ");
+          } else {
+            generator.outdent();
+            generator.print("}\n");
+          }
+        }
+      }
+    }
+
+    private void printUnknownField(final int number,
+                                   final int wireType,
+                                   final List<?> values,
+                                   final TextGenerator generator)
+                                   throws IOException {
+      for (final Object value : values) {
+        generator.print(String.valueOf(number));
+        generator.print(": ");
+        printUnknownFieldValue(wireType, value, generator);
+        generator.print(singleLineMode ? " " : "\n");
+      }
+    }
+  }
+
+  /** Convert an unsigned 32-bit integer to a string. */
+  public static String unsignedToString(final int value) {
+    if (value >= 0) {
+      return Integer.toString(value);
+    } else {
+      return Long.toString(value & 0x00000000FFFFFFFFL);
+    }
+  }
+
+  /** Convert an unsigned 64-bit integer to a string. */
+  public static String unsignedToString(final long value) {
+    if (value >= 0) {
+      return Long.toString(value);
+    } else {
+      // Pull off the most-significant bit so that BigInteger doesn't think
+      // the number is negative, then set it again using setBit().
+      return BigInteger.valueOf(value & 0x7FFFFFFFFFFFFFFFL)
+                       .setBit(63).toString();
+    }
+  }
+
+  /**
+   * An inner class for writing text to the output stream.
+   */
+  private static final class TextGenerator {
+    private final Appendable output;
+    private final StringBuilder indent = new StringBuilder();
+    private boolean atStartOfLine = true;
+
+    private TextGenerator(final Appendable output) {
+      this.output = output;
+    }
+
+    /**
+     * Indent text by two spaces.  After calling Indent(), two spaces will be
+     * inserted at the beginning of each line of text.  Indent() may be called
+     * multiple times to produce deeper indents.
+     */
+    public void indent() {
+      indent.append("  ");
+    }
+
+    /**
+     * Reduces the current indent level by two spaces, or crashes if the indent
+     * level is zero.
+     */
+    public void outdent() {
+      final int length = indent.length();
+      if (length == 0) {
+        throw new IllegalArgumentException(
+            " Outdent() without matching Indent().");
+      }
+      indent.delete(length - 2, length);
+    }
+
+    /**
+     * Print text to the output stream.
+     */
+    public void print(final CharSequence text) throws IOException {
+      final int size = text.length();
+      int pos = 0;
+
+      for (int i = 0; i < size; i++) {
+        if (text.charAt(i) == '\n') {
+          write(text.subSequence(pos, i + 1));
+          pos = i + 1;
+          atStartOfLine = true;
+        }
+      }
+      write(text.subSequence(pos, size));
+    }
+
+    private void write(final CharSequence data) throws IOException {
+      if (data.length() == 0) {
+        return;
+      }
+      if (atStartOfLine) {
+        atStartOfLine = false;
+        output.append(indent);
+      }
+      output.append(data);
+    }
+  }
+
+  // =================================================================
+  // Parsing
+
+  /**
+   * Represents a stream of tokens parsed from a {@code String}.
+   *
+   * <p>The Java standard library provides many classes that you might think
+   * would be useful for implementing this, but aren't.  For example:
+   *
+   * <ul>
+   * <li>{@code java.io.StreamTokenizer}:  This almost does what we want -- or,
+   *   at least, something that would get us close to what we want -- except
+   *   for one fatal flaw:  It automatically un-escapes strings using Java
+   *   escape sequences, which do not include all the escape sequences we
+   *   need to support (e.g. '\x').
+   * <li>{@code java.util.Scanner}:  This seems like a great way at least to
+   *   parse regular expressions out of a stream (so we wouldn't have to load
+   *   the entire input into a single string before parsing).  Sadly,
+   *   {@code Scanner} requires that tokens be delimited with some delimiter.
+   *   Thus, although the text "foo:" should parse to two tokens ("foo" and
+   *   ":"), {@code Scanner} would recognize it only as a single token.
+   *   Furthermore, {@code Scanner} provides no way to inspect the contents
+   *   of delimiters, making it impossible to keep track of line and column
+   *   numbers.
+   * </ul>
+   *
+   * <p>Luckily, Java's regular expression support does manage to be useful to
+   * us.  (Barely:  We need {@code Matcher.usePattern()}, which is new in
+   * Java 1.5.)  So, we can use that, at least.  Unfortunately, this implies
+   * that we need to have the entire input in one contiguous string.
+   */
+  private static final class Tokenizer {
+    private final CharSequence text;
+    private final Matcher matcher;
+    private String currentToken;
+
+    // The character index within this.text at which the current token begins.
+    private int pos = 0;
+
+    // The line and column numbers of the current token.
+    private int line = 0;
+    private int column = 0;
+
+    // The line and column numbers of the previous token (allows throwing
+    // errors *after* consuming).
+    private int previousLine = 0;
+    private int previousColumn = 0;
+
+    // We use possessive quantifiers (*+ and ++) because otherwise the Java
+    // regex matcher has stack overflows on large inputs.
+    private static final Pattern WHITESPACE =
+      Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
+    private static final Pattern TOKEN = Pattern.compile(
+      "[a-zA-Z_][0-9a-zA-Z_+-]*+|" +                // an identifier
+      "[.]?[0-9+-][0-9a-zA-Z_.+-]*+|" +             // a number
+      "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" +       // a double-quoted string
+      "\'([^\'\n\\\\]|\\\\.)*+(\'|\\\\?$)",         // a single-quoted string
+      Pattern.MULTILINE);
+
+    private static final Pattern DOUBLE_INFINITY = Pattern.compile(
+      "-?inf(inity)?",
+      Pattern.CASE_INSENSITIVE);
+    private static final Pattern FLOAT_INFINITY = Pattern.compile(
+      "-?inf(inity)?f?",
+      Pattern.CASE_INSENSITIVE);
+    private static final Pattern FLOAT_NAN = Pattern.compile(
+      "nanf?",
+      Pattern.CASE_INSENSITIVE);
+
+    /** Construct a tokenizer that parses tokens from the given text. */
+    private Tokenizer(final CharSequence text) {
+      this.text = text;
+      this.matcher = WHITESPACE.matcher(text);
+      skipWhitespace();
+      nextToken();
+    }
+
+    int getLine() {
+      return line;
+    }
+
+    int getColumn() {
+      return column;
+    }
+
+    /** Are we at the end of the input? */
+    public boolean atEnd() {
+      return currentToken.length() == 0;
+    }
+
+    /** Advance to the next token. */
+    public void nextToken() {
+      previousLine = line;
+      previousColumn = column;
+
+      // Advance the line counter to the current position.
+      while (pos < matcher.regionStart()) {
+        if (text.charAt(pos) == '\n') {
+          ++line;
+          column = 0;
+        } else {
+          ++column;
+        }
+        ++pos;
+      }
+
+      // Match the next token.
+      if (matcher.regionStart() == matcher.regionEnd()) {
+        // EOF
+        currentToken = "";
+      } else {
+        matcher.usePattern(TOKEN);
+        if (matcher.lookingAt()) {
+          currentToken = matcher.group();
+          matcher.region(matcher.end(), matcher.regionEnd());
+        } else {
+          // Take one character.
+          currentToken = String.valueOf(text.charAt(pos));
+          matcher.region(pos + 1, matcher.regionEnd());
+        }
+
+        skipWhitespace();
+      }
+    }
+
+    /**
+     * Skip over any whitespace so that the matcher region starts at the next
+     * token.
+     */
+    private void skipWhitespace() {
+      matcher.usePattern(WHITESPACE);
+      if (matcher.lookingAt()) {
+        matcher.region(matcher.end(), matcher.regionEnd());
+      }
+    }
+
+    /**
+     * If the next token exactly matches {@code token}, consume it and return
+     * {@code true}.  Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsume(final String token) {
+      if (currentToken.equals(token)) {
+        nextToken();
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token exactly matches {@code token}, consume it.  Otherwise,
+     * throw a {@link ParseException}.
+     */
+    public void consume(final String token) throws ParseException {
+      if (!tryConsume(token)) {
+        throw parseException("Expected \"" + token + "\".");
+      }
+    }
+
+    /**
+     * Returns {@code true} if the next token is an integer, but does
+     * not consume it.
+     */
+    public boolean lookingAtInteger() {
+      if (currentToken.length() == 0) {
+        return false;
+      }
+
+      final char c = currentToken.charAt(0);
+      return ('0' <= c && c <= '9')
+          || c == '-' || c == '+';
+    }
+
+    /**
+     * Returns {@code true} if the current token's text is equal to that
+     * specified.
+     */
+    public boolean lookingAt(String text) {
+      return currentToken.equals(text);
+    }
+
+    /**
+     * If the next token is an identifier, consume it and return its value.
+     * Otherwise, throw a {@link ParseException}.
+     */
+    public String consumeIdentifier() throws ParseException {
+      for (int i = 0; i < currentToken.length(); i++) {
+        final char c = currentToken.charAt(i);
+        if (('a' <= c && c <= 'z')
+            || ('A' <= c && c <= 'Z')
+            || ('0' <= c && c <= '9')
+            || (c == '_') || (c == '.')) {
+          // OK
+        } else {
+          throw parseException(
+              "Expected identifier. Found '" + currentToken + "'");
+        }
+      }
+
+      final String result = currentToken;
+      nextToken();
+      return result;
+    }
+
+    /**
+     * If the next token is an identifier, consume it and return {@code true}.
+     * Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsumeIdentifier() {
+      try {
+        consumeIdentifier();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a 32-bit signed integer, consume it and return its
+     * value.  Otherwise, throw a {@link ParseException}.
+     */
+    public int consumeInt32() throws ParseException {
+      try {
+        final int result = parseInt32(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw integerParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a 32-bit unsigned integer, consume it and return its
+     * value.  Otherwise, throw a {@link ParseException}.
+     */
+    public int consumeUInt32() throws ParseException {
+      try {
+        final int result = parseUInt32(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw integerParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a 64-bit signed integer, consume it and return its
+     * value.  Otherwise, throw a {@link ParseException}.
+     */
+    public long consumeInt64() throws ParseException {
+      try {
+        final long result = parseInt64(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw integerParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a 64-bit signed integer, consume it and return
+     * {@code true}.  Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsumeInt64() {
+      try {
+        consumeInt64();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a 64-bit unsigned integer, consume it and return its
+     * value.  Otherwise, throw a {@link ParseException}.
+     */
+    public long consumeUInt64() throws ParseException {
+      try {
+        final long result = parseUInt64(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw integerParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a 64-bit unsigned integer, consume it and return
+     * {@code true}.  Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsumeUInt64() {
+      try {
+        consumeUInt64();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a double, consume it and return its value.
+     * Otherwise, throw a {@link ParseException}.
+     */
+    public double consumeDouble() throws ParseException {
+      // We need to parse infinity and nan separately because
+      // Double.parseDouble() does not accept "inf", "infinity", or "nan".
+      if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
+        final boolean negative = currentToken.startsWith("-");
+        nextToken();
+        return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+      }
+      if (currentToken.equalsIgnoreCase("nan")) {
+        nextToken();
+        return Double.NaN;
+      }
+      try {
+        final double result = Double.parseDouble(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw floatParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a double, consume it and return {@code true}.
+     * Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsumeDouble() {
+      try {
+        consumeDouble();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a float, consume it and return its value.
+     * Otherwise, throw a {@link ParseException}.
+     */
+    public float consumeFloat() throws ParseException {
+      // We need to parse infinity and nan separately because
+      // Float.parseFloat() does not accept "inf", "infinity", or "nan".
+      if (FLOAT_INFINITY.matcher(currentToken).matches()) {
+        final boolean negative = currentToken.startsWith("-");
+        nextToken();
+        return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+      }
+      if (FLOAT_NAN.matcher(currentToken).matches()) {
+        nextToken();
+        return Float.NaN;
+      }
+      try {
+        final float result = Float.parseFloat(currentToken);
+        nextToken();
+        return result;
+      } catch (NumberFormatException e) {
+        throw floatParseException(e);
+      }
+    }
+
+    /**
+     * If the next token is a float, consume it and return {@code true}.
+     * Otherwise, return {@code false} without doing anything.
+     */
+    public boolean tryConsumeFloat() {
+      try {
+        consumeFloat();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a boolean, consume it and return its value.
+     * Otherwise, throw a {@link ParseException}.
+     */
+    public boolean consumeBoolean() throws ParseException {
+      if (currentToken.equals("true")
+          || currentToken.equals("True")
+          || currentToken.equals("t")
+          || currentToken.equals("1")) {
+        nextToken();
+        return true;
+      } else if (currentToken.equals("false")
+          || currentToken.equals("False")
+          || currentToken.equals("f")
+          || currentToken.equals("0")) {
+        nextToken();
+        return false;
+      } else {
+        throw parseException("Expected \"true\" or \"false\".");
+      }
+    }
+
+    /**
+     * If the next token is a string, consume it and return its (unescaped)
+     * value.  Otherwise, throw a {@link ParseException}.
+     */
+    public String consumeString() throws ParseException {
+      return consumeByteString().toStringUtf8();
+    }
+
+    /**
+     * If the next token is a string, consume it and return true.  Otherwise,
+     * return false.
+     */
+    public boolean tryConsumeString() {
+      try {
+        consumeString();
+        return true;
+      } catch (ParseException e) {
+        return false;
+      }
+    }
+
+    /**
+     * If the next token is a string, consume it, unescape it as a
+     * {@link ByteString}, and return it.  Otherwise, throw a
+     * {@link ParseException}.
+     */
+    public ByteString consumeByteString() throws ParseException {
+      List<ByteString> list = new ArrayList<ByteString>();
+      consumeByteString(list);
+      while (currentToken.startsWith("'") || currentToken.startsWith("\"")) {
+        consumeByteString(list);
+      }
+      return ByteString.copyFrom(list);
+    }
+
+    /**
+     * Like {@link #consumeByteString()} but adds each token of the string to
+     * the given list.  String literals (whether bytes or text) may come in
+     * multiple adjacent tokens which are automatically concatenated, like in
+     * C or Python.
+     */
+    private void consumeByteString(List<ByteString> list)
+        throws ParseException {
+      final char quote = currentToken.length() > 0
+          ? currentToken.charAt(0)
+          : '\0';
+      if (quote != '\"' && quote != '\'') {
+        throw parseException("Expected string.");
+      }
+
+      if (currentToken.length() < 2
+          || currentToken.charAt(currentToken.length() - 1) != quote) {
+        throw parseException("String missing ending quote.");
+      }
+
+      try {
+        final String escaped =
+            currentToken.substring(1, currentToken.length() - 1);
+        final ByteString result = unescapeBytes(escaped);
+        nextToken();
+        list.add(result);
+      } catch (InvalidEscapeSequenceException e) {
+        throw parseException(e.getMessage());
+      }
+    }
+
+    /**
+     * Returns a {@link ParseException} with the current line and column
+     * numbers in the description, suitable for throwing.
+     */
+    public ParseException parseException(final String description) {
+      // Note:  People generally prefer one-based line and column numbers.
+      return new ParseException(
+        line + 1, column + 1, description);
+    }
+
+    /**
+     * Returns a {@link ParseException} with the line and column numbers of
+     * the previous token in the description, suitable for throwing.
+     */
+    public ParseException parseExceptionPreviousToken(
+        final String description) {
+      // Note:  People generally prefer one-based line and column numbers.
+      return new ParseException(
+        previousLine + 1, previousColumn + 1, description);
+    }
+
+    /**
+     * Constructs an appropriate {@link ParseException} for the given
+     * {@code NumberFormatException} when trying to parse an integer.
+     */
+    private ParseException integerParseException(
+        final NumberFormatException e) {
+      return parseException("Couldn't parse integer: " + e.getMessage());
+    }
+
+    /**
+     * Constructs an appropriate {@link ParseException} for the given
+     * {@code NumberFormatException} when trying to parse a float or double.
+     */
+    private ParseException floatParseException(final NumberFormatException e) {
+      return parseException("Couldn't parse number: " + e.getMessage());
+    }
+
+    /**
+     * Returns a {@link UnknownFieldParseException} with the line and column
+     * numbers of the previous token in the description, and the unknown field
+     * name, suitable for throwing.
+     */
+    public UnknownFieldParseException unknownFieldParseExceptionPreviousToken(
+        final String unknownField, final String description) {
+      // Note:  People generally prefer one-based line and column numbers.
+      return new UnknownFieldParseException(
+        previousLine + 1, previousColumn + 1, unknownField, description);
+    }
+  }
+
+  /** Thrown when parsing an invalid text format message. */
+  public static class ParseException extends IOException {
+    private static final long serialVersionUID = 3196188060225107702L;
+
+    private final int line;
+    private final int column;
+
+    /** Create a new instance, with -1 as the line and column numbers. */
+    public ParseException(final String message) {
+      this(-1, -1, message);
+    }
+
+    /**
+     * Create a new instance
+     *
+     * @param line the line number where the parse error occurred,
+     * using 1-offset.
+     * @param column the column number where the parser error occurred,
+     * using 1-offset.
+     */
+    public ParseException(final int line, final int column,
+        final String message) {
+      super(Integer.toString(line) + ":" + column + ": " + message);
+      this.line = line;
+      this.column = column;
+    }
+
+    /**
+     * Return the line where the parse exception occurred, or -1 when
+     * none is provided. The value is specified as 1-offset, so the first
+     * line is line 1.
+     */
+    public int getLine() {
+      return line;
+    }
+
+    /**
+     * Return the column where the parse exception occurred, or -1 when
+     * none is provided. The value is specified as 1-offset, so the first
+     * line is line 1.
+     */
+    public int getColumn() {
+      return column;
+    }
+  }
+
+  /**
+   * Thrown when encountering an unknown field while parsing
+   * a text format message.
+   */
+  public static class UnknownFieldParseException extends ParseException {
+    private final String unknownField;
+
+    /**
+     * Create a new instance, with -1 as the line and column numbers, and an
+     * empty unknown field name.
+     */
+    public UnknownFieldParseException(final String message) {
+      this(-1, -1, "", message);
+    }
+
+    /**
+     * Create a new instance
+     *
+     * @param line the line number where the parse error occurred,
+     * using 1-offset.
+     * @param column the column number where the parser error occurred,
+     * using 1-offset.
+     * @param unknownField the name of the unknown field found while parsing.
+     */
+    public UnknownFieldParseException(final int line, final int column,
+        final String unknownField, final String message) {
+      super(line, column, message);
+      this.unknownField = unknownField;
+    }
+
+    /**
+     * Return the name of the unknown field encountered while parsing the
+     * protocol buffer string.
+     */
+    public String getUnknownField() {
+      return unknownField;
+    }
+  }
+
+  private static final Parser PARSER = Parser.newBuilder().build();
+
+  /**
+   * Return a {@link Parser} instance which can parse text-format
+   * messages. The returned instance is thread-safe.
+   */
+  public static Parser getParser() {
+    return PARSER;
+  }
+
+  /**
+   * Parse a text-format message from {@code input} and merge the contents
+   * into {@code builder}.
+   */
+  public static void merge(final Readable input,
+                           final Message.Builder builder)
+                           throws IOException {
+    PARSER.merge(input, builder);
+  }
+
+  /**
+   * Parse a text-format message from {@code input} and merge the contents
+   * into {@code builder}.
+   */
+  public static void merge(final CharSequence input,
+                           final Message.Builder builder)
+                           throws ParseException {
+    PARSER.merge(input, builder);
+  }
+
+  /**
+   * Parse a text-format message from {@code input} and merge the contents
+   * into {@code builder}.  Extensions will be recognized if they are
+   * registered in {@code extensionRegistry}.
+   */
+  public static void merge(final Readable input,
+                           final ExtensionRegistry extensionRegistry,
+                           final Message.Builder builder)
+                           throws IOException {
+    PARSER.merge(input, extensionRegistry, builder);
+  }
+
+
+  /**
+   * Parse a text-format message from {@code input} and merge the contents
+   * into {@code builder}.  Extensions will be recognized if they are
+   * registered in {@code extensionRegistry}.
+   */
+  public static void merge(final CharSequence input,
+                           final ExtensionRegistry extensionRegistry,
+                           final Message.Builder builder)
+                           throws ParseException {
+    PARSER.merge(input, extensionRegistry, builder);
+  }
+
+
+  /**
+   * Parser for text-format proto2 instances. This class is thread-safe.
+   * The implementation largely follows google/protobuf/text_format.cc.
+   *
+   * <p>Use {@link TextFormat#getParser()} to obtain the default parser, or
+   * {@link Builder} to control the parser behavior.
+   */
+  public static class Parser {
+    /**
+     * Determines if repeated values for non-repeated fields and
+     * oneofs are permitted. For example, given required/optional field "foo"
+     * and a oneof containing "baz" and "qux":
+     * <ul>
+     * <li>"foo: 1 foo: 2"
+     * <li>"baz: 1 qux: 2"
+     * <li>merging "foo: 2" into a proto in which foo is already set, or
+     * <li>merging "qux: 2" into a proto in which baz is already set.
+     * </ul>
+     */
+    public enum SingularOverwritePolicy {
+      /** The last value is retained. */
+      ALLOW_SINGULAR_OVERWRITES,
+      /** An error is issued. */
+      FORBID_SINGULAR_OVERWRITES
+    }
+
+    private final boolean allowUnknownFields;
+    private final SingularOverwritePolicy singularOverwritePolicy;
+    private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
+
+    private Parser(
+        boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy,
+        TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
+      this.allowUnknownFields = allowUnknownFields;
+      this.singularOverwritePolicy = singularOverwritePolicy;
+      this.parseInfoTreeBuilder = parseInfoTreeBuilder;
+    }
+
+    /**
+     * Returns a new instance of {@link Builder}.
+     */
+    public static Builder newBuilder() {
+      return new Builder();
+    }
+
+    /**
+     * Builder that can be used to obtain new instances of {@link Parser}.
+     */
+    public static class Builder {
+      private boolean allowUnknownFields = false;
+      private SingularOverwritePolicy singularOverwritePolicy =
+          SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
+      private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
+
+
+      /**
+       * Sets parser behavior when a non-repeated field appears more than once.
+       */
+      public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
+        this.singularOverwritePolicy = p;
+        return this;
+      }
+
+      public Builder setParseInfoTreeBuilder(
+          TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
+        this.parseInfoTreeBuilder = parseInfoTreeBuilder;
+        return this;
+      }
+
+      public Parser build() {
+        return new Parser(
+            allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder);
+      }
+    }
+
+    /**
+     * Parse a text-format message from {@code input} and merge the contents
+     * into {@code builder}.
+     */
+    public void merge(final Readable input,
+                      final Message.Builder builder)
+                      throws IOException {
+      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+    }
+
+    /**
+     * Parse a text-format message from {@code input} and merge the contents
+     * into {@code builder}.
+     */
+    public void merge(final CharSequence input,
+                      final Message.Builder builder)
+                      throws ParseException {
+      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+    }
+
+    /**
+     * Parse a text-format message from {@code input} and merge the contents
+     * into {@code builder}.  Extensions will be recognized if they are
+     * registered in {@code extensionRegistry}.
+     */
+    public void merge(final Readable input,
+                      final ExtensionRegistry extensionRegistry,
+                      final Message.Builder builder)
+                      throws IOException {
+      // Read the entire input to a String then parse that.
+
+      // If StreamTokenizer were not quite so crippled, or if there were a kind
+      // of Reader that could read in chunks that match some particular regex,
+      // or if we wanted to write a custom Reader to tokenize our stream, then
+      // we would not have to read to one big String.  Alas, none of these is
+      // the case.  Oh well.
+
+      merge(toStringBuilder(input), extensionRegistry, builder);
+    }
+
+
+    private static final int BUFFER_SIZE = 4096;
+
+    // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
+    // overhead is worthwhile
+    private static StringBuilder toStringBuilder(final Readable input)
+        throws IOException {
+      final StringBuilder text = new StringBuilder();
+      final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
+      while (true) {
+        final int n = input.read(buffer);
+        if (n == -1) {
+          break;
+        }
+        buffer.flip();
+        text.append(buffer, 0, n);
+      }
+      return text;
+    }
+
+    /**
+     * Parse a text-format message from {@code input} and merge the contents
+     * into {@code builder}.  Extensions will be recognized if they are
+     * registered in {@code extensionRegistry}.
+     */
+    public void merge(final CharSequence input,
+                      final ExtensionRegistry extensionRegistry,
+                      final Message.Builder builder)
+                      throws ParseException {
+      final Tokenizer tokenizer = new Tokenizer(input);
+      MessageReflection.BuilderAdapter target =
+          new MessageReflection.BuilderAdapter(builder);
+
+      while (!tokenizer.atEnd()) {
+        mergeField(tokenizer, extensionRegistry, target);
+      }
+    }
+
+
+    /**
+     * Parse a single field from {@code tokenizer} and merge it into
+     * {@code builder}.
+     */
+    private void mergeField(final Tokenizer tokenizer,
+                            final ExtensionRegistry extensionRegistry,
+                            final MessageReflection.MergeTarget target)
+                            throws ParseException {
+      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder);
+    }
+
+    /**
+     * Parse a single field from {@code tokenizer} and merge it into
+     * {@code builder}.
+     */
+    private void mergeField(final Tokenizer tokenizer,
+                            final ExtensionRegistry extensionRegistry,
+                            final MessageReflection.MergeTarget target,
+                            TextFormatParseInfoTree.Builder parseTreeBuilder)
+                            throws ParseException {
+      FieldDescriptor field = null;
+      int startLine = tokenizer.getLine();
+      int startColumn = tokenizer.getColumn();
+      final Descriptor type = target.getDescriptorForType();
+      ExtensionRegistry.ExtensionInfo extension = null;
+
+      if (tokenizer.tryConsume("[")) {
+        // An extension.
+        final StringBuilder name =
+            new StringBuilder(tokenizer.consumeIdentifier());
+        while (tokenizer.tryConsume(".")) {
+          name.append('.');
+          name.append(tokenizer.consumeIdentifier());
+        }
+
+        extension = target.findExtensionByName(
+            extensionRegistry, name.toString());
+
+        if (extension == null) {
+          if (!allowUnknownFields) {
+            throw tokenizer.parseExceptionPreviousToken(
+              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+          } else {
+            logger.warning(
+              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+          }
+        } else {
+          if (extension.descriptor.getContainingType() != type) {
+            throw tokenizer.parseExceptionPreviousToken(
+              "Extension \"" + name + "\" does not extend message type \""
+              + type.getFullName() + "\".");
+          }
+          field = extension.descriptor;
+        }
+
+        tokenizer.consume("]");
+      } else {
+        final String name = tokenizer.consumeIdentifier();
+        field = type.findFieldByName(name);
+
+        // Group names are expected to be capitalized as they appear in the
+        // .proto file, which actually matches their type names, not their field
+        // names.
+        if (field == null) {
+          // Explicitly specify US locale so that this code does not break when
+          // executing in Turkey.
+          final String lowerName = name.toLowerCase(Locale.US);
+          field = type.findFieldByName(lowerName);
+          // If the case-insensitive match worked but the field is NOT a group,
+          if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
+            field = null;
+          }
+        }
+        // Again, special-case group names as described above.
+        if (field != null && field.getType() == FieldDescriptor.Type.GROUP
+            && !field.getMessageType().getName().equals(name)) {
+          field = null;
+        }
+
+        if (field == null) {
+          if (!allowUnknownFields) {
+            throw tokenizer.unknownFieldParseExceptionPreviousToken(
+              name,
+              "Message type \"" + type.getFullName()
+              + "\" has no field named \"" + name + "\".");
+          } else {
+            logger.warning(
+              "Message type \"" + type.getFullName()
+              + "\" has no field named \"" + name + "\".");
+          }
+        }
+      }
+
+      // Skips unknown fields.
+      if (field == null) {
+        // Try to guess the type of this field.
+        // If this field is not a message, there should be a ":" between the
+        // field name and the field value and also the field value should not
+        // start with "{" or "<" which indicates the beginning of a message body.
+        // If there is no ":" or there is a "{" or "<" after ":", this field has
+        // to be a message or the input is ill-formed.
+        if (tokenizer.tryConsume(":")
+            && !tokenizer.lookingAt("{")
+            && !tokenizer.lookingAt("<")) {
+          skipFieldValue(tokenizer);
+        } else {
+          skipFieldMessage(tokenizer);
+        }
+        return;
+      }
+
+      // Handle potential ':'.
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        tokenizer.tryConsume(":");  // optional
+        if (parseTreeBuilder != null) {
+          TextFormatParseInfoTree.Builder childParseTreeBuilder =
+              parseTreeBuilder.getBuilderForSubMessageField(field);
+          consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+              childParseTreeBuilder);
+        } else {
+          consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
+              parseTreeBuilder);
+        }
+      } else {
+        tokenizer.consume(":");  // required
+        consumeFieldValues(
+            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+      }
+
+      if (parseTreeBuilder != null) {
+        parseTreeBuilder.setLocation(
+            field, TextFormatParseLocation.create(startLine, startColumn));
+      }
+
+      // For historical reasons, fields may optionally be separated by commas or
+      // semicolons.
+      if (!tokenizer.tryConsume(";")) {
+        tokenizer.tryConsume(",");
+      }
+    }
+
+    /**
+     * Parse a one or more field values from {@code tokenizer} and merge it into
+     * {@code builder}.
+     */
+    private void consumeFieldValues(
+        final Tokenizer tokenizer,
+        final ExtensionRegistry extensionRegistry,
+        final MessageReflection.MergeTarget target,
+        final FieldDescriptor field,
+        final ExtensionRegistry.ExtensionInfo extension,
+        final TextFormatParseInfoTree.Builder parseTreeBuilder)
+        throws ParseException {
+      // Support specifying repeated field values as a comma-separated list.
+      // Ex."foo: [1, 2, 3]"
+      if (field.isRepeated() && tokenizer.tryConsume("[")) {
+        while (true) {
+          consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
+              parseTreeBuilder);
+          if (tokenizer.tryConsume("]")) {
+            // End of list.
+            break;
+          }
+          tokenizer.consume(",");
+        }
+      } else {
+        consumeFieldValue(
+            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+      }
+    }
+
+    /**
+     * Parse a single field value from {@code tokenizer} and merge it into
+     * {@code builder}.
+     */
+    private void consumeFieldValue(
+        final Tokenizer tokenizer,
+        final ExtensionRegistry extensionRegistry,
+        final MessageReflection.MergeTarget target,
+        final FieldDescriptor field,
+        final ExtensionRegistry.ExtensionInfo extension,
+        final TextFormatParseInfoTree.Builder parseTreeBuilder)
+        throws ParseException {
+      Object value = null;
+
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        final String endToken;
+        if (tokenizer.tryConsume("<")) {
+          endToken = ">";
+        } else {
+          tokenizer.consume("{");
+          endToken = "}";
+        }
+
+        final MessageReflection.MergeTarget subField;
+        subField = target.newMergeTargetForField(field,
+            (extension == null) ? null : extension.defaultInstance);
+
+        while (!tokenizer.tryConsume(endToken)) {
+          if (tokenizer.atEnd()) {
+            throw tokenizer.parseException(
+              "Expected \"" + endToken + "\".");
+          }
+          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder);
+        }
+
+        value = subField.finish();
+
+      } else {
+        switch (field.getType()) {
+          case INT32:
+          case SINT32:
+          case SFIXED32:
+            value = tokenizer.consumeInt32();
+            break;
+
+          case INT64:
+          case SINT64:
+          case SFIXED64:
+            value = tokenizer.consumeInt64();
+            break;
+
+          case UINT32:
+          case FIXED32:
+            value = tokenizer.consumeUInt32();
+            break;
+
+          case UINT64:
+          case FIXED64:
+            value = tokenizer.consumeUInt64();
+            break;
+
+          case FLOAT:
+            value = tokenizer.consumeFloat();
+            break;
+
+          case DOUBLE:
+            value = tokenizer.consumeDouble();
+            break;
+
+          case BOOL:
+            value = tokenizer.consumeBoolean();
+            break;
+
+          case STRING:
+            value = tokenizer.consumeString();
+            break;
+
+          case BYTES:
+            value = tokenizer.consumeByteString();
+            break;
+
+          case ENUM:
+            final EnumDescriptor enumType = field.getEnumType();
+
+            if (tokenizer.lookingAtInteger()) {
+              final int number = tokenizer.consumeInt32();
+              value = enumType.findValueByNumber(number);
+              if (value == null) {
+                throw tokenizer.parseExceptionPreviousToken(
+                  "Enum type \"" + enumType.getFullName()
+                  + "\" has no value with number " + number + '.');
+              }
+            } else {
+              final String id = tokenizer.consumeIdentifier();
+              value = enumType.findValueByName(id);
+              if (value == null) {
+                throw tokenizer.parseExceptionPreviousToken(
+                  "Enum type \"" + enumType.getFullName()
+                  + "\" has no value named \"" + id + "\".");
+              }
+            }
+
+            break;
+
+          case MESSAGE:
+          case GROUP:
+            throw new RuntimeException("Can't get here.");
+        }
+      }
+
+      if (field.isRepeated()) {
+        target.addRepeatedField(field, value);
+      } else if ((singularOverwritePolicy
+              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+          && target.hasField(field)) {
+        throw tokenizer.parseExceptionPreviousToken("Non-repeated field \""
+            + field.getFullName() + "\" cannot be overwritten.");
+      } else if ((singularOverwritePolicy
+              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+          && field.getContainingOneof() != null
+          && target.hasOneof(field.getContainingOneof())) {
+        Descriptors.OneofDescriptor oneof = field.getContainingOneof();
+        throw tokenizer.parseExceptionPreviousToken("Field \""
+            + field.getFullName() + "\" is specified along with field \""
+            + target.getOneofFieldDescriptor(oneof).getFullName()
+            + "\", another member of oneof \"" + oneof.getName() + "\".");
+      } else {
+        target.setField(field, value);
+      }
+    }
+
+    /**
+     * Skips the next field including the field's name and value.
+     */
+    private void skipField(Tokenizer tokenizer) throws ParseException {
+      if (tokenizer.tryConsume("[")) {
+        // Extension name.
+        do {
+          tokenizer.consumeIdentifier();
+        } while (tokenizer.tryConsume("."));
+        tokenizer.consume("]");
+      } else {
+        tokenizer.consumeIdentifier();
+      }
+
+      // Try to guess the type of this field.
+      // If this field is not a message, there should be a ":" between the
+      // field name and the field value and also the field value should not
+      // start with "{" or "<" which indicates the beginning of a message body.
+      // If there is no ":" or there is a "{" or "<" after ":", this field has
+      // to be a message or the input is ill-formed.
+      if (tokenizer.tryConsume(":")
+          && !tokenizer.lookingAt("<")
+          && !tokenizer.lookingAt("{")) {
+        skipFieldValue(tokenizer);
+      } else {
+        skipFieldMessage(tokenizer);
+      }
+      // For historical reasons, fields may optionally be separated by commas or
+      // semicolons.
+      if (!tokenizer.tryConsume(";")) {
+        tokenizer.tryConsume(",");
+      }
+    }
+
+    /**
+     * Skips the whole body of a message including the beginning delimiter and
+     * the ending delimiter.
+     */
+    private void skipFieldMessage(Tokenizer tokenizer) throws ParseException {
+      final String delimiter;
+      if (tokenizer.tryConsume("<")) {
+        delimiter = ">";
+      } else {
+        tokenizer.consume("{");
+        delimiter = "}";
+      }
+      while (!tokenizer.lookingAt(">") && !tokenizer.lookingAt("}")) {
+        skipField(tokenizer);
+      }
+      tokenizer.consume(delimiter);
+    }
+
+    /**
+     * Skips a field value.
+     */
+    private void skipFieldValue(Tokenizer tokenizer) throws ParseException {
+      if (tokenizer.tryConsumeString()) {
+        while (tokenizer.tryConsumeString()) {}
+        return;
+      }
+      if (!tokenizer.tryConsumeIdentifier()   // includes enum & boolean
+          && !tokenizer.tryConsumeInt64()     // includes int32
+          && !tokenizer.tryConsumeUInt64()    // includes uint32
+          && !tokenizer.tryConsumeDouble()
+          && !tokenizer.tryConsumeFloat()) {
+        throw tokenizer.parseException(
+            "Invalid field value: " + tokenizer.currentToken);
+      }
+    }
+  }
+
+  // =================================================================
+  // Utility functions
+  //
+  // Some of these methods are package-private because Descriptors.java uses
+  // them.
+
+  /**
+   * Escapes bytes in the format used in protocol buffer text format, which
+   * is the same as the format used for C string literals.  All bytes
+   * that are not printable 7-bit ASCII characters are escaped, as well as
+   * backslash, single-quote, and double-quote characters.  Characters for
+   * which no defined short-hand escape sequence is defined will be escaped
+   * using 3-digit octal sequences.
+   */
+  public static String escapeBytes(ByteString input) {
+    return TextFormatEscaper.escapeBytes(input);
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but used for byte array.
+   */
+  public static String escapeBytes(byte[] input) {
+    return TextFormatEscaper.escapeBytes(input);
+  }
+
+  /**
+   * Un-escape a byte sequence as escaped using
+   * {@link #escapeBytes(ByteString)}.  Two-digit hex escapes (starting with
+   * "\x") are also recognized.
+   */
+  public static ByteString unescapeBytes(final CharSequence charString)
+      throws InvalidEscapeSequenceException {
+    // First convert the Java character sequence to UTF-8 bytes.
+    ByteString input = ByteString.copyFromUtf8(charString.toString());
+    // Then unescape certain byte sequences introduced by ASCII '\\'.  The valid
+    // escapes can all be expressed with ASCII characters, so it is safe to
+    // operate on bytes here.
+    //
+    // Unescaping the input byte array will result in a byte sequence that's no
+    // longer than the input.  That's because each escape sequence is between
+    // two and four bytes long and stands for a single byte.
+    final byte[] result = new byte[input.size()];
+    int pos = 0;
+    for (int i = 0; i < input.size(); i++) {
+      byte c = input.byteAt(i);
+      if (c == '\\') {
+        if (i + 1 < input.size()) {
+          ++i;
+          c = input.byteAt(i);
+          if (isOctal(c)) {
+            // Octal escape.
+            int code = digitValue(c);
+            if (i + 1 < input.size() && isOctal(input.byteAt(i + 1))) {
+              ++i;
+              code = code * 8 + digitValue(input.byteAt(i));
+            }
+            if (i + 1 < input.size() && isOctal(input.byteAt(i + 1))) {
+              ++i;
+              code = code * 8 + digitValue(input.byteAt(i));
+            }
+            // TODO: Check that 0 <= code && code <= 0xFF.
+            result[pos++] = (byte) code;
+          } else {
+            switch (c) {
+              case 'a' : result[pos++] = 0x07; break;
+              case 'b' : result[pos++] = '\b'; break;
+              case 'f' : result[pos++] = '\f'; break;
+              case 'n' : result[pos++] = '\n'; break;
+              case 'r' : result[pos++] = '\r'; break;
+              case 't' : result[pos++] = '\t'; break;
+              case 'v' : result[pos++] = 0x0b; break;
+              case '\\': result[pos++] = '\\'; break;
+              case '\'': result[pos++] = '\''; break;
+              case '"' : result[pos++] = '\"'; break;
+
+              case 'x':
+                // hex escape
+                int code = 0;
+                if (i + 1 < input.size() && isHex(input.byteAt(i + 1))) {
+                  ++i;
+                  code = digitValue(input.byteAt(i));
+                } else {
+                  throw new InvalidEscapeSequenceException(
+                      "Invalid escape sequence: '\\x' with no digits");
+                }
+                if (i + 1 < input.size() && isHex(input.byteAt(i + 1))) {
+                  ++i;
+                  code = code * 16 + digitValue(input.byteAt(i));
+                }
+                result[pos++] = (byte) code;
+                break;
+
+              default:
+                throw new InvalidEscapeSequenceException(
+                    "Invalid escape sequence: '\\" + (char) c + '\'');
+            }
+          }
+        } else {
+          throw new InvalidEscapeSequenceException(
+              "Invalid escape sequence: '\\' at end of string.");
+        }
+      } else {
+        result[pos++] = c;
+      }
+    }
+
+    return result.length == pos
+        ? ByteString.wrap(result)  // This reference has not been out of our control.
+        : ByteString.copyFrom(result, 0, pos);
+  }
+
+  /**
+   * Thrown by {@link TextFormat#unescapeBytes} and
+   * {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
+   */
+  public static class InvalidEscapeSequenceException extends IOException {
+    private static final long serialVersionUID = -8164033650142593304L;
+
+    InvalidEscapeSequenceException(final String description) {
+      super(description);
+    }
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+   * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+   * individually as a 3-digit octal escape.  Yes, it's weird.
+   */
+  static String escapeText(final String input) {
+    return escapeBytes(ByteString.copyFromUtf8(input));
+  }
+
+  /**
+   * Escape double quotes and backslashes in a String for unicode output of a message.
+   */
+  public static String escapeDoubleQuotesAndBackslashes(final String input) {
+    return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input);
+  }
+
+  /**
+   * Un-escape a text string as escaped using {@link #escapeText(String)}.
+   * Two-digit hex escapes (starting with "\x") are also recognized.
+   */
+  static String unescapeText(final String input)
+                             throws InvalidEscapeSequenceException {
+    return unescapeBytes(input).toStringUtf8();
+  }
+
+  /** Is this an octal digit? */
+  private static boolean isOctal(final byte c) {
+    return '0' <= c && c <= '7';
+  }
+
+  /** Is this a hex digit? */
+  private static boolean isHex(final byte c) {
+    return ('0' <= c && c <= '9')
+        || ('a' <= c && c <= 'f')
+        || ('A' <= c && c <= 'F');
+  }
+
+  /**
+   * Interpret a character as a digit (in any base up to 36) and return the
+   * numeric value.  This is like {@code Character.digit()} but we don't accept
+   * non-ASCII digits.
+   */
+  private static int digitValue(final byte c) {
+    if ('0' <= c && c <= '9') {
+      return c - '0';
+    } else if ('a' <= c && c <= 'z') {
+      return c - 'a' + 10;
+    } else {
+      return c - 'A' + 10;
+    }
+  }
+
+  /**
+   * Parse a 32-bit signed integer from the text.  Unlike the Java standard
+   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+   * and "0" to signify hexadecimal and octal numbers, respectively.
+   */
+  static int parseInt32(final String text) throws NumberFormatException {
+    return (int) parseInteger(text, true, false);
+  }
+
+  /**
+   * Parse a 32-bit unsigned integer from the text.  Unlike the Java standard
+   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+   * and "0" to signify hexadecimal and octal numbers, respectively.  The
+   * result is coerced to a (signed) {@code int} when returned since Java has
+   * no unsigned integer type.
+   */
+  static int parseUInt32(final String text) throws NumberFormatException {
+    return (int) parseInteger(text, false, false);
+  }
+
+  /**
+   * Parse a 64-bit signed integer from the text.  Unlike the Java standard
+   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+   * and "0" to signify hexadecimal and octal numbers, respectively.
+   */
+  static long parseInt64(final String text) throws NumberFormatException {
+    return parseInteger(text, true, true);
+  }
+
+  /**
+   * Parse a 64-bit unsigned integer from the text.  Unlike the Java standard
+   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+   * and "0" to signify hexadecimal and octal numbers, respectively.  The
+   * result is coerced to a (signed) {@code long} when returned since Java has
+   * no unsigned long type.
+   */
+  static long parseUInt64(final String text) throws NumberFormatException {
+    return parseInteger(text, false, true);
+  }
+
+  private static long parseInteger(final String text,
+                                   final boolean isSigned,
+                                   final boolean isLong)
+                                   throws NumberFormatException {
+    int pos = 0;
+
+    boolean negative = false;
+    if (text.startsWith("-", pos)) {
+      if (!isSigned) {
+        throw new NumberFormatException("Number must be positive: " + text);
+      }
+      ++pos;
+      negative = true;
+    }
+
+    int radix = 10;
+    if (text.startsWith("0x", pos)) {
+      pos += 2;
+      radix = 16;
+    } else if (text.startsWith("0", pos)) {
+      radix = 8;
+    }
+
+    final String numberText = text.substring(pos);
+
+    long result = 0;
+    if (numberText.length() < 16) {
+      // Can safely assume no overflow.
+      result = Long.parseLong(numberText, radix);
+      if (negative) {
+        result = -result;
+      }
+
+      // Check bounds.
+      // No need to check for 64-bit numbers since they'd have to be 16 chars
+      // or longer to overflow.
+      if (!isLong) {
+        if (isSigned) {
+          if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
+            throw new NumberFormatException(
+              "Number out of range for 32-bit signed integer: " + text);
+          }
+        } else {
+          if (result >= (1L << 32) || result < 0) {
+            throw new NumberFormatException(
+              "Number out of range for 32-bit unsigned integer: " + text);
+          }
+        }
+      }
+    } else {
+      BigInteger bigValue = new BigInteger(numberText, radix);
+      if (negative) {
+        bigValue = bigValue.negate();
+      }
+
+      // Check bounds.
+      if (!isLong) {
+        if (isSigned) {
+          if (bigValue.bitLength() > 31) {
+            throw new NumberFormatException(
+              "Number out of range for 32-bit signed integer: " + text);
+          }
+        } else {
+          if (bigValue.bitLength() > 32) {
+            throw new NumberFormatException(
+              "Number out of range for 32-bit unsigned integer: " + text);
+          }
+        }
+      } else {
+        if (isSigned) {
+          if (bigValue.bitLength() > 63) {
+            throw new NumberFormatException(
+              "Number out of range for 64-bit signed integer: " + text);
+          }
+        } else {
+          if (bigValue.bitLength() > 64) {
+            throw new NumberFormatException(
+              "Number out of range for 64-bit unsigned integer: " + text);
+          }
+        }
+      }
+
+      result = bigValue.longValue();
+    }
+
+    return result;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
new file mode 100644
index 0000000..da9cead
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
@@ -0,0 +1,137 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * Provide text format escaping support for proto2 instances.
+ */
+final class TextFormatEscaper {
+  private TextFormatEscaper() {}
+
+  private interface ByteSequence {
+    int size();
+    byte byteAt(int offset);
+  }
+
+  /**
+   * Escapes bytes in the format used in protocol buffer text format, which
+   * is the same as the format used for C string literals.  All bytes
+   * that are not printable 7-bit ASCII characters are escaped, as well as
+   * backslash, single-quote, and double-quote characters.  Characters for
+   * which no defined short-hand escape sequence is defined will be escaped
+   * using 3-digit octal sequences.
+   */
+  static String escapeBytes(final ByteSequence input) {
+    final StringBuilder builder = new StringBuilder(input.size());
+    for (int i = 0; i < input.size(); i++) {
+      final byte b = input.byteAt(i);
+      switch (b) {
+        // Java does not recognize \a or \v, apparently.
+        case 0x07: builder.append("\\a"); break;
+        case '\b': builder.append("\\b"); break;
+        case '\f': builder.append("\\f"); break;
+        case '\n': builder.append("\\n"); break;
+        case '\r': builder.append("\\r"); break;
+        case '\t': builder.append("\\t"); break;
+        case 0x0b: builder.append("\\v"); break;
+        case '\\': builder.append("\\\\"); break;
+        case '\'': builder.append("\\\'"); break;
+        case '"' : builder.append("\\\""); break;
+        default:
+          // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
+          // printable.  Other byte values must be escaped.
+          if (b >= 0x20 && b <= 0x7e) {
+            builder.append((char) b);
+          } else {
+            builder.append('\\');
+            builder.append((char) ('0' + ((b >>> 6) & 3)));
+            builder.append((char) ('0' + ((b >>> 3) & 7)));
+            builder.append((char) ('0' + (b & 7)));
+          }
+          break;
+      }
+    }
+    return builder.toString();
+  }
+
+  /**
+   * Escapes bytes in the format used in protocol buffer text format, which
+   * is the same as the format used for C string literals.  All bytes
+   * that are not printable 7-bit ASCII characters are escaped, as well as
+   * backslash, single-quote, and double-quote characters.  Characters for
+   * which no defined short-hand escape sequence is defined will be escaped
+   * using 3-digit octal sequences.
+   */
+  static String escapeBytes(final ByteString input) {
+    return escapeBytes(new ByteSequence() {
+      @Override
+      public int size() {
+        return input.size();
+      }
+      @Override
+      public byte byteAt(int offset) {
+        return input.byteAt(offset);
+      }
+    });
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but used for byte array.
+   */
+  static String escapeBytes(final byte[] input) {
+    return escapeBytes(new ByteSequence() {
+      @Override
+      public int size() {
+        return input.length;
+      }
+      @Override
+      public byte byteAt(int offset) {
+        return input[offset];
+      }
+    });
+  }
+
+  /**
+   * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+   * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+   * individually as a 3-digit octal escape.  Yes, it's weird.
+   */
+  static String escapeText(final String input) {
+    return escapeBytes(ByteString.copyFromUtf8(input));
+  }
+
+  /**
+   * Escape double quotes and backslashes in a String for unicode output of a message.
+   */
+  static String escapeDoubleQuotesAndBackslashes(final String input) {
+    return input.replace("\\", "\\\\").replace("\"", "\\\"");
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
new file mode 100644
index 0000000..2ecf912
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
@@ -0,0 +1,225 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * Data structure which is populated with the locations of each field value parsed from the text.
+ *
+ * <p>The locations of primary fields values are retrieved by {@code getLocation} or
+ * {@code getLocations}.  The locations of sub message values are within nested
+ * {@code TextFormatParseInfoTree}s and are retrieve by {@getNestedTree} or {code @getNestedTrees}.
+ *
+ * <p>The {@code TextFormatParseInfoTree} is created by a Builder.
+ */
+public class TextFormatParseInfoTree {
+
+  // Defines a mapping between each field's descriptor to the list of locations where
+  // its value(s) were was encountered.
+  private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+  // Defines a mapping between a field's descriptor to a list of TextFormatParseInfoTrees for
+  // sub message location information.
+  Map<FieldDescriptor, List<TextFormatParseInfoTree>> subtreesFromField;
+
+  /**
+   * Construct a {@code TextFormatParseInfoTree}.
+   *
+   * @param locationsFromField a map of fields to location in the source code
+   * @param subtreeBuildersFromField a map of fields to parse tree location information builders
+   */
+  private TextFormatParseInfoTree(
+      Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField,
+      Map<FieldDescriptor, List<TextFormatParseInfoTree.Builder>> subtreeBuildersFromField) {
+
+    // The maps are unmodifiable.  The values in the maps are unmodifiable.
+    Map<FieldDescriptor, List<TextFormatParseLocation>> locs =
+        new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+    for (Entry<FieldDescriptor, List<TextFormatParseLocation>> kv : locationsFromField.entrySet()) {
+      locs.put(kv.getKey(), Collections.unmodifiableList(kv.getValue()));
+    }
+    this.locationsFromField = Collections.unmodifiableMap(locs);
+
+    Map<FieldDescriptor, List<TextFormatParseInfoTree>> subs =
+        new HashMap<FieldDescriptor, List<TextFormatParseInfoTree>>();
+    for (Entry<FieldDescriptor, List<Builder>> kv : subtreeBuildersFromField.entrySet()) {
+      List<TextFormatParseInfoTree> submessagesOfField = new ArrayList<TextFormatParseInfoTree>();
+      for (Builder subBuilder : kv.getValue()) {
+        submessagesOfField.add(subBuilder.build());
+      }
+      subs.put(kv.getKey(), Collections.unmodifiableList(submessagesOfField));
+    }
+    this.subtreesFromField = Collections.unmodifiableMap(subs);
+  }
+
+ /**
+  * Retrieve all the locations of a field.
+  *
+  * @param fieldDescriptor the the @{link FieldDescriptor} of the desired field
+  * @return a list of the locations of values of the field.  If there are not values
+  *         or the field doesn't exist, an empty list is returned.
+  */
+  public List<TextFormatParseLocation> getLocations(final FieldDescriptor fieldDescriptor) {
+    List<TextFormatParseLocation> result = locationsFromField.get(fieldDescriptor);
+    return (result == null) ? Collections.<TextFormatParseLocation>emptyList() : result;
+  }
+
+  /**
+   * Get the location in the source of a field's value.
+   *
+   * <p>Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed
+   * text.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+   * @param index the index of the value.
+   * @return the {@link TextFormatParseLocation} of the value
+   * @throws IllegalArgumentException index is out of range
+   */
+  public TextFormatParseLocation getLocation(final FieldDescriptor fieldDescriptor, int index) {
+    return getFromList(getLocations(fieldDescriptor), index, fieldDescriptor);
+  }
+
+  /**
+   * Retrieve a list of all the location information trees for a sub message field.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired field
+   * @return A list of {@link TextFormatParseInfoTree}
+   */
+  public List<TextFormatParseInfoTree> getNestedTrees(final FieldDescriptor fieldDescriptor) {
+    List<TextFormatParseInfoTree> result = subtreesFromField.get(fieldDescriptor);
+    return result == null ? Collections.<TextFormatParseInfoTree>emptyList() : result;
+  }
+
+  /**
+   * Returns the parse info tree for the given field, which must be a message type.
+   *
+   * @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message
+   * @param index the index of message value.
+   * @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field
+   *         doesn't exist or the index is out of range.
+   * @throws IllegalArgumentException if index is out of range
+   */
+  public TextFormatParseInfoTree getNestedTree(final FieldDescriptor fieldDescriptor, int index) {
+    return getFromList(getNestedTrees(fieldDescriptor), index, fieldDescriptor);
+  }
+
+  /**
+   * Create a builder for a {@code ParseInfoTree}.
+   *
+   * @return the builder
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private static <T> T getFromList(List<T> list, int index, FieldDescriptor fieldDescriptor) {
+    if (index >= list.size() || index < 0)  {
+      throw new IllegalArgumentException(String.format("Illegal index field: %s, index %d",
+          fieldDescriptor == null ? "<null>" : fieldDescriptor.getName(), index));
+    }
+    return list.get(index);
+  }
+
+  /**
+   * Builder for a {@link TextFormatParseInfoTree}.
+   */
+  public static class Builder {
+
+    private Map<FieldDescriptor, List<TextFormatParseLocation>> locationsFromField;
+
+    // Defines a mapping between a field's descriptor to a list of ParseInfoTrees builders for
+    // sub message location information.
+    private Map<FieldDescriptor, List<Builder>> subtreeBuildersFromField;
+
+     /**
+     * Create a root level {@ParseInfoTree} builder.
+     */
+    private Builder() {
+      locationsFromField = new HashMap<FieldDescriptor, List<TextFormatParseLocation>>();
+      subtreeBuildersFromField = new HashMap<FieldDescriptor, List<Builder>>();
+    }
+
+    /**
+     * Record the starting location of a single value for a field.
+     *
+     * @param fieldDescriptor the field
+     * @param location source code location information
+     */
+    public Builder setLocation(
+        final FieldDescriptor fieldDescriptor, TextFormatParseLocation location) {
+      List<TextFormatParseLocation> fieldLocations = locationsFromField.get(fieldDescriptor);
+      if (fieldLocations == null) {
+        fieldLocations = new ArrayList<TextFormatParseLocation>();
+        locationsFromField.put(fieldDescriptor, fieldLocations);
+      }
+      fieldLocations.add(location);
+      return this;
+    }
+
+    /**
+     * Set for a sub message.
+     *
+     * <p>A new builder is created for a sub message. The builder that is returned is a new builder.
+     * The return is <emph>not</emph> the invoked {@code builder.getBuilderForSubMessageField}.
+     *
+     * @param fieldDescriptor the field whose value is the submessage
+     * @return a new Builder for the sub message
+     */
+    public Builder getBuilderForSubMessageField(final FieldDescriptor fieldDescriptor) {
+      List<Builder> submessageBuilders = subtreeBuildersFromField.get(fieldDescriptor);
+      if (submessageBuilders == null) {
+        submessageBuilders = new ArrayList<Builder>();
+        subtreeBuildersFromField.put(fieldDescriptor, submessageBuilders);
+      }
+      Builder subtreeBuilder = new Builder();
+      submessageBuilders.add(subtreeBuilder);
+      return subtreeBuilder;
+    }
+
+    /**
+     * Build the {@code TextFormatParseInfoTree}.
+     *
+     * @return the {@code TextFormatParseInfoTree}
+     */
+    public TextFormatParseInfoTree build() {
+      return new TextFormatParseInfoTree(locationsFromField, subtreeBuildersFromField);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
new file mode 100644
index 0000000..cce286e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java
@@ -0,0 +1,104 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.Arrays;
+
+/**
+ * A location in the source code.
+ *
+ * <p>A location is the starting line number and starting column number.
+ */
+public final class TextFormatParseLocation {
+
+  /**
+   * The empty location.
+   */
+  public static final TextFormatParseLocation EMPTY = new TextFormatParseLocation(-1, -1);
+
+  /**
+   * Create a location.
+   *
+   * @param line the starting line number
+   * @param column the starting column number
+   * @return a {@code ParseLocation}
+   */
+  static TextFormatParseLocation create(int line, int column) {
+    if (line == -1 && column == -1) {
+      return EMPTY;
+    }
+    if (line < 0 || column < 0) {
+      throw new IllegalArgumentException(
+          String.format("line and column values must be >= 0: line %d, column: %d", line, column));
+    }
+    return new TextFormatParseLocation(line, column);
+  }
+
+  private final int line;
+  private final int column;
+
+  private TextFormatParseLocation(int line, int column) {
+    this.line = line;
+    this.column = column;
+  }
+
+  public int getLine() {
+    return line;
+  }
+
+  public int getColumn() {
+    return column;
+  }
+
+  @Override
+  public String toString() {
+    return String.format("ParseLocation{line=%d, column=%d}", line, column);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof TextFormatParseLocation)) {
+      return false;
+    }
+    TextFormatParseLocation that = (TextFormatParseLocation) o;
+    return (this.line == that.getLine())
+         && (this.column == that.getColumn());
+  }
+
+  @Override
+  public int hashCode() {
+    int[] values = {line, column};
+    return Arrays.hashCode(values);
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java b/java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/UninitializedMessageException.java
rename to java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
new file mode 100644
index 0000000..c906420
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -0,0 +1,1035 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * {@code UnknownFieldSet} is used to keep track of fields which were seen when
+ * parsing a protocol message but whose field numbers or types are unrecognized.
+ * This most frequently occurs when new fields are added to a message type
+ * and then messages containing those fields are read by old software that was
+ * compiled before the new types were added.
+ *
+ * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
+ * {@link Message.Builder} contains an {@link Builder}).
+ *
+ * <p>Most users will never need to use this class.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class UnknownFieldSet implements MessageLite {
+  private UnknownFieldSet() {}
+
+  /** Create a new {@link Builder}. */
+  public static Builder newBuilder() {
+    return Builder.create();
+  }
+
+  /**
+   * Create a new {@link Builder} and initialize it to be a copy
+   * of {@code copyFrom}.
+   */
+  public static Builder newBuilder(final UnknownFieldSet copyFrom) {
+    return newBuilder().mergeFrom(copyFrom);
+  }
+
+  /** Get an empty {@code UnknownFieldSet}. */
+  public static UnknownFieldSet getDefaultInstance() {
+    return defaultInstance;
+  }
+  @Override
+  public UnknownFieldSet getDefaultInstanceForType() {
+    return defaultInstance;
+  }
+  private static final UnknownFieldSet defaultInstance =
+    new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
+
+  /**
+   * Construct an {@code UnknownFieldSet} around the given map.  The map is
+   * expected to be immutable.
+   */
+  private UnknownFieldSet(final Map<Integer, Field> fields) {
+    this.fields = fields;
+  }
+  private Map<Integer, Field> fields;
+
+
+  @Override
+  public boolean equals(final Object other) {
+    if (this == other) {
+      return true;
+    }
+    return (other instanceof UnknownFieldSet) &&
+           fields.equals(((UnknownFieldSet) other).fields);
+  }
+
+  @Override
+  public int hashCode() {
+    return fields.hashCode();
+  }
+
+  /** Get a map of fields in the set by number. */
+  public Map<Integer, Field> asMap() {
+    return fields;
+  }
+
+  /** Check if the given field number is present in the set. */
+  public boolean hasField(final int number) {
+    return fields.containsKey(number);
+  }
+
+  /**
+   * Get a field by number.  Returns an empty field if not present.  Never
+   * returns {@code null}.
+   */
+  public Field getField(final int number) {
+    final Field result = fields.get(number);
+    return (result == null) ? Field.getDefaultInstance() : result;
+  }
+
+  /** Serializes the set and writes it to {@code output}. */
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+      entry.getValue().writeTo(entry.getKey(), output);
+    }
+  }
+
+  /**
+   * Converts the set to a string in protocol buffer text format. This is
+   * just a trivial wrapper around
+   * {@link TextFormat#printToString(UnknownFieldSet)}.
+   */
+  @Override
+  public String toString() {
+    return TextFormat.printToString(this);
+  }
+
+  /**
+   * Serializes the message to a {@code ByteString} and returns it. This is
+   * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+   */
+  @Override
+  public ByteString toByteString() {
+    try {
+      final ByteString.CodedBuilder out =
+        ByteString.newCodedBuilder(getSerializedSize());
+      writeTo(out.getCodedOutput());
+      return out.build();
+    } catch (final IOException e) {
+      throw new RuntimeException(
+        "Serializing to a ByteString threw an IOException (should " +
+        "never happen).", e);
+    }
+  }
+
+  /**
+   * Serializes the message to a {@code byte} array and returns it.  This is
+   * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+   */
+  @Override
+  public byte[] toByteArray() {
+    try {
+      final byte[] result = new byte[getSerializedSize()];
+      final CodedOutputStream output = CodedOutputStream.newInstance(result);
+      writeTo(output);
+      output.checkNoSpaceLeft();
+      return result;
+    } catch (final IOException e) {
+      throw new RuntimeException(
+        "Serializing to a byte array threw an IOException " +
+        "(should never happen).", e);
+    }
+  }
+
+  /**
+   * Serializes the message and writes it to {@code output}.  This is just a
+   * trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+   */
+  @Override
+  public void writeTo(final OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  @Override
+  public void writeDelimitedTo(OutputStream output) throws IOException {
+    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    codedOutput.writeRawVarint32(getSerializedSize());
+    writeTo(codedOutput);
+    codedOutput.flush();
+  }
+
+  /** Get the number of bytes required to encode this set. */
+  @Override
+  public int getSerializedSize() {
+    int result = 0;
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+      result += entry.getValue().getSerializedSize(entry.getKey());
+    }
+    return result;
+  }
+
+  /**
+   * Serializes the set and writes it to {@code output} using
+   * {@code MessageSet} wire format.
+   */
+  public void writeAsMessageSetTo(final CodedOutputStream output)
+      throws IOException {
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+      entry.getValue().writeAsMessageSetExtensionTo(
+        entry.getKey(), output);
+    }
+  }
+
+  /**
+   * Get the number of bytes required to encode this set using
+   * {@code MessageSet} wire format.
+   */
+  public int getSerializedSizeAsMessageSet() {
+    int result = 0;
+    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+      result += entry.getValue().getSerializedSizeAsMessageSetExtension(
+        entry.getKey());
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    // UnknownFieldSets do not have required fields, so they are always
+    // initialized.
+    return true;
+  }
+
+  /** Parse an {@code UnknownFieldSet} from the given input stream. */
+  public static UnknownFieldSet parseFrom(final CodedInputStream input)
+                                          throws IOException {
+    return newBuilder().mergeFrom(input).build();
+  }
+
+  /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+  public static UnknownFieldSet parseFrom(final ByteString data)
+      throws InvalidProtocolBufferException {
+    return newBuilder().mergeFrom(data).build();
+  }
+
+  /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+  public static UnknownFieldSet parseFrom(final byte[] data)
+      throws InvalidProtocolBufferException {
+    return newBuilder().mergeFrom(data).build();
+  }
+
+  /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
+  public static UnknownFieldSet parseFrom(final InputStream input)
+                                          throws IOException {
+    return newBuilder().mergeFrom(input).build();
+  }
+
+  @Override
+  public Builder newBuilderForType() {
+    return newBuilder();
+  }
+
+  @Override
+  public Builder toBuilder() {
+    return newBuilder().mergeFrom(this);
+  }
+
+  /**
+   * Builder for {@link UnknownFieldSet}s.
+   *
+   * <p>Note that this class maintains {@link Field.Builder}s for all fields
+   * in the set.  Thus, adding one element to an existing {@link Field} does not
+   * require making a copy.  This is important for efficient parsing of
+   * unknown repeated fields.  However, it implies that {@link Field}s cannot
+   * be constructed independently, nor can two {@link UnknownFieldSet}s share
+   * the same {@code Field} object.
+   *
+   * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
+   */
+  public static final class Builder implements MessageLite.Builder {
+    // This constructor should never be called directly (except from 'create').
+    private Builder() {}
+
+    private Map<Integer, Field> fields;
+
+    // Optimization:  We keep around a builder for the last field that was
+    //   modified so that we can efficiently add to it multiple times in a
+    //   row (important when parsing an unknown repeated field).
+    private int lastFieldNumber;
+    private Field.Builder lastField;
+
+    private static Builder create() {
+      Builder builder = new Builder();
+      builder.reinitialize();
+      return builder;
+    }
+
+    /**
+     * Get a field builder for the given field number which includes any
+     * values that already exist.
+     */
+    private Field.Builder getFieldBuilder(final int number) {
+      if (lastField != null) {
+        if (number == lastFieldNumber) {
+          return lastField;
+        }
+        // Note:  addField() will reset lastField and lastFieldNumber.
+        addField(lastFieldNumber, lastField.build());
+      }
+      if (number == 0) {
+        return null;
+      } else {
+        final Field existing = fields.get(number);
+        lastFieldNumber = number;
+        lastField = Field.newBuilder();
+        if (existing != null) {
+          lastField.mergeFrom(existing);
+        }
+        return lastField;
+      }
+    }
+
+    /**
+     * Build the {@link UnknownFieldSet} and return it.
+     *
+     * <p>Once {@code build()} has been called, the {@code Builder} will no
+     * longer be usable.  Calling any method after {@code build()} will result
+     * in undefined behavior and can cause a {@code NullPointerException} to be
+     * thrown.
+     */
+    @Override
+    public UnknownFieldSet build() {
+      getFieldBuilder(0);  // Force lastField to be built.
+      final UnknownFieldSet result;
+      if (fields.isEmpty()) {
+        result = getDefaultInstance();
+      } else {
+        result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
+      }
+      fields = null;
+      return result;
+    }
+
+    @Override
+    public UnknownFieldSet buildPartial() {
+      // No required fields, so this is the same as build().
+      return build();
+    }
+
+    @Override
+    public Builder clone() {
+      getFieldBuilder(0);  // Force lastField to be built.
+      return UnknownFieldSet.newBuilder().mergeFrom(
+          new UnknownFieldSet(fields));
+    }
+
+    @Override
+    public UnknownFieldSet getDefaultInstanceForType() {
+      return UnknownFieldSet.getDefaultInstance();
+    }
+
+    private void reinitialize() {
+      fields = Collections.emptyMap();
+      lastFieldNumber = 0;
+      lastField = null;
+    }
+
+    /** Reset the builder to an empty set. */
+    @Override
+    public Builder clear() {
+      reinitialize();
+      return this;
+    }
+    
+    /** Clear fields from the set with a given field number. */
+    public Builder clearField(final int number) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      if (lastField != null && lastFieldNumber == number) {
+        // Discard this.
+        lastField = null;
+        lastFieldNumber = 0;
+      }
+      if (fields.containsKey(number)) {
+        fields.remove(number);
+      }
+      return this;
+    }
+
+    /**
+     * Merge the fields from {@code other} into this set.  If a field number
+     * exists in both sets, {@code other}'s values for that field will be
+     * appended to the values in this set.
+     */
+    public Builder mergeFrom(final UnknownFieldSet other) {
+      if (other != getDefaultInstance()) {
+        for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
+          mergeField(entry.getKey(), entry.getValue());
+        }
+      }
+      return this;
+    }
+
+    /**
+     * Add a field to the {@code UnknownFieldSet}.  If a field with the same
+     * number already exists, the two are merged.
+     */
+    public Builder mergeField(final int number, final Field field) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      if (hasField(number)) {
+        getFieldBuilder(number).mergeFrom(field);
+      } else {
+        // Optimization:  We could call getFieldBuilder(number).mergeFrom(field)
+        // in this case, but that would create a copy of the Field object.
+        // We'd rather reuse the one passed to us, so call addField() instead.
+        addField(number, field);
+      }
+      return this;
+    }
+
+    /**
+     * Convenience method for merging a new field containing a single varint
+     * value.  This is used in particular when an unknown enum value is
+     * encountered.
+     */
+    public Builder mergeVarintField(final int number, final int value) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      getFieldBuilder(number).addVarint(value);
+      return this;
+    }
+
+
+    /**
+     * Convenience method for merging a length-delimited field.
+     *
+     * <p>For use by generated code only.
+     */
+    public Builder mergeLengthDelimitedField(
+        final int number, final ByteString value) {  
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      getFieldBuilder(number).addLengthDelimited(value);
+      return this;
+    }
+
+    /** Check if the given field number is present in the set. */
+    public boolean hasField(final int number) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      return number == lastFieldNumber || fields.containsKey(number);
+    }
+
+    /**
+     * Add a field to the {@code UnknownFieldSet}.  If a field with the same
+     * number already exists, it is removed.
+     */
+    public Builder addField(final int number, final Field field) {
+      if (number == 0) {
+        throw new IllegalArgumentException("Zero is not a valid field number.");
+      }
+      if (lastField != null && lastFieldNumber == number) {
+        // Discard this.
+        lastField = null;
+        lastFieldNumber = 0;
+      }
+      if (fields.isEmpty()) {
+        fields = new TreeMap<Integer,Field>();
+      }
+      fields.put(number, field);
+      return this;
+    }
+
+    /**
+     * Get all present {@code Field}s as an immutable {@code Map}.  If more
+     * fields are added, the changes may or may not be reflected in this map.
+     */
+    public Map<Integer, Field> asMap() {
+      getFieldBuilder(0);  // Force lastField to be built.
+      return Collections.unmodifiableMap(fields);
+    }
+
+    /**
+     * Parse an entire message from {@code input} and merge its fields into
+     * this set.
+     */
+    @Override
+    public Builder mergeFrom(final CodedInputStream input) throws IOException {
+      while (true) {
+        final int tag = input.readTag();
+        if (tag == 0 || !mergeFieldFrom(tag, input)) {
+          break;
+        }
+      }
+      return this;
+    }
+
+    /**
+     * Parse a single field from {@code input} and merge it into this set.
+     * @param tag The field's tag number, which was already parsed.
+     * @return {@code false} if the tag is an end group tag.
+     */
+    public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
+                                  throws IOException {
+      final int number = WireFormat.getTagFieldNumber(tag);
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          getFieldBuilder(number).addVarint(input.readInt64());
+          return true;
+        case WireFormat.WIRETYPE_FIXED64:
+          getFieldBuilder(number).addFixed64(input.readFixed64());
+          return true;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          getFieldBuilder(number).addLengthDelimited(input.readBytes());
+          return true;
+        case WireFormat.WIRETYPE_START_GROUP:
+          final Builder subBuilder = newBuilder();
+          input.readGroup(number, subBuilder,
+                          ExtensionRegistry.getEmptyRegistry());
+          getFieldBuilder(number).addGroup(subBuilder.build());
+          return true;
+        case WireFormat.WIRETYPE_END_GROUP:
+          return false;
+        case WireFormat.WIRETYPE_FIXED32:
+          getFieldBuilder(number).addFixed32(input.readFixed32());
+          return true;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+
+    /**
+     * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+     * set being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     */
+    @Override
+    public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = data.newCodedInput();
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return this;
+      } catch (final InvalidProtocolBufferException e) {
+        throw e;
+      } catch (final IOException e) {
+        throw new RuntimeException(
+          "Reading from a ByteString threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    /**
+     * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+     * set being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     */
+    @Override
+    public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input = CodedInputStream.newInstance(data);
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return this;
+      } catch (final InvalidProtocolBufferException e) {
+        throw e;
+      } catch (final IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    /**
+     * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
+     * set being built.  This is just a small wrapper around
+     * {@link #mergeFrom(CodedInputStream)}.
+     */
+    @Override
+    public Builder mergeFrom(final InputStream input) throws IOException {
+      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+      mergeFrom(codedInput);
+      codedInput.checkLastTagWas(0);
+      return this;
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(InputStream input) throws IOException {
+      final int firstByte = input.read();
+      if (firstByte == -1) {
+        return false;
+      }
+      final int size = CodedInputStream.readRawVarint32(firstByte, input);
+      final InputStream limitedInput = new LimitedInputStream(input, size);
+      mergeFrom(limitedInput);
+      return true;
+    }
+
+    @Override
+    public boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeDelimitedFrom(input);
+    }
+
+    @Override
+    public Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(input);
+    }
+
+    @Override
+    public Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data);
+    }
+
+    @Override
+    public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException {
+      try {
+        final CodedInputStream input =
+            CodedInputStream.newInstance(data, off, len);
+        mergeFrom(input);
+        input.checkLastTagWas(0);
+        return this;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        throw new RuntimeException(
+          "Reading from a byte array threw an IOException (should " +
+          "never happen).", e);
+      }
+    }
+
+    @Override
+    public Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data);
+    }
+
+    @Override
+    public Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(data, off, len);
+    }
+
+    @Override
+    public Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      // UnknownFieldSet has no extensions.
+      return mergeFrom(input);
+    }
+
+    @Override
+    public Builder mergeFrom(MessageLite m) {
+      if (m instanceof UnknownFieldSet) {
+        return mergeFrom((UnknownFieldSet) m);
+      }
+      throw new IllegalArgumentException(
+          "mergeFrom(MessageLite) can only merge messages of the same type.");
+    }
+
+    @Override
+    public boolean isInitialized() {
+      // UnknownFieldSets do not have required fields, so they are always
+      // initialized.
+      return true;
+    }
+  }
+
+  /**
+   * Represents a single field in an {@code UnknownFieldSet}.
+   *
+   * <p>A {@code Field} consists of five lists of values.  The lists correspond
+   * to the five "wire types" used in the protocol buffer binary format.
+   * The wire type of each field can be determined from the encoded form alone,
+   * without knowing the field's declared type.  So, we are able to parse
+   * unknown values at least this far and separate them.  Normally, only one
+   * of the five lists will contain any values, since it is impossible to
+   * define a valid message type that declares two different types for the
+   * same field number.  However, the code is designed to allow for the case
+   * where the same unknown field number is encountered using multiple different
+   * wire types.
+   *
+   * <p>{@code Field} is an immutable class.  To construct one, you must use a
+   * {@link Builder}.
+   *
+   * @see UnknownFieldSet
+   */
+  public static final class Field {
+    private Field() {}
+
+    /** Construct a new {@link Builder}. */
+    public static Builder newBuilder() {
+      return Builder.create();
+    }
+
+    /**
+     * Construct a new {@link Builder} and initialize it to a copy of
+     * {@code copyFrom}.
+     */
+    public static Builder newBuilder(final Field copyFrom) {
+      return newBuilder().mergeFrom(copyFrom);
+    }
+
+    /** Get an empty {@code Field}. */
+    public static Field getDefaultInstance() {
+      return fieldDefaultInstance;
+    }
+    private static final Field fieldDefaultInstance = newBuilder().build();
+
+    /** Get the list of varint values for this field. */
+    public List<Long> getVarintList()               { return varint;          }
+
+    /** Get the list of fixed32 values for this field. */
+    public List<Integer> getFixed32List()           { return fixed32;         }
+
+    /** Get the list of fixed64 values for this field. */
+    public List<Long> getFixed64List()              { return fixed64;         }
+
+    /** Get the list of length-delimited values for this field. */
+    public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
+
+    /**
+     * Get the list of embedded group values for this field.  These are
+     * represented using {@link UnknownFieldSet}s rather than {@link Message}s
+     * since the group's type is presumably unknown.
+     */
+    public List<UnknownFieldSet> getGroupList()      { return group;           }
+
+    @Override
+    public boolean equals(final Object other) {
+      if (this == other) {
+        return true;
+      }
+      if (!(other instanceof Field)) {
+        return false;
+      }
+      return Arrays.equals(getIdentityArray(),
+          ((Field) other).getIdentityArray());
+    }
+
+    @Override
+    public int hashCode() {
+      return Arrays.hashCode(getIdentityArray());
+    }
+
+    /**
+     * Returns the array of objects to be used to uniquely identify this
+     * {@link Field} instance.
+     */
+    private Object[] getIdentityArray() {
+      return new Object[] {
+          varint,
+          fixed32,
+          fixed64,
+          lengthDelimited,
+          group};
+    }
+
+    /**
+     * Serializes the field, including field number, and writes it to
+     * {@code output}.
+     */
+    public void writeTo(final int fieldNumber, final CodedOutputStream output)
+                        throws IOException {
+      for (final long value : varint) {
+        output.writeUInt64(fieldNumber, value);
+      }
+      for (final int value : fixed32) {
+        output.writeFixed32(fieldNumber, value);
+      }
+      for (final long value : fixed64) {
+        output.writeFixed64(fieldNumber, value);
+      }
+      for (final ByteString value : lengthDelimited) {
+        output.writeBytes(fieldNumber, value);
+      }
+      for (final UnknownFieldSet value : group) {
+        output.writeGroup(fieldNumber, value);
+      }
+    }
+
+    /**
+     * Get the number of bytes required to encode this field, including field
+     * number.
+     */
+    public int getSerializedSize(final int fieldNumber) {
+      int result = 0;
+      for (final long value : varint) {
+        result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
+      }
+      for (final int value : fixed32) {
+        result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
+      }
+      for (final long value : fixed64) {
+        result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
+      }
+      for (final ByteString value : lengthDelimited) {
+        result += CodedOutputStream.computeBytesSize(fieldNumber, value);
+      }
+      for (final UnknownFieldSet value : group) {
+        result += CodedOutputStream.computeGroupSize(fieldNumber, value);
+      }
+      return result;
+    }
+
+    /**
+     * Serializes the field, including field number, and writes it to
+     * {@code output}, using {@code MessageSet} wire format.
+     */
+    public void writeAsMessageSetExtensionTo(
+        final int fieldNumber,
+        final CodedOutputStream output)
+        throws IOException {
+      for (final ByteString value : lengthDelimited) {
+        output.writeRawMessageSetExtension(fieldNumber, value);
+      }
+    }
+
+    /**
+     * Get the number of bytes required to encode this field, including field
+     * number, using {@code MessageSet} wire format.
+     */
+    public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
+      int result = 0;
+      for (final ByteString value : lengthDelimited) {
+        result += CodedOutputStream.computeRawMessageSetExtensionSize(
+          fieldNumber, value);
+      }
+      return result;
+    }
+
+    private List<Long> varint;
+    private List<Integer> fixed32;
+    private List<Long> fixed64;
+    private List<ByteString> lengthDelimited;
+    private List<UnknownFieldSet> group;
+
+    /**
+     * Used to build a {@link Field} within an {@link UnknownFieldSet}.
+     *
+     * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
+     */
+    public static final class Builder {
+      // This constructor should never be called directly (except from 'create').
+      private Builder() {}
+
+      private static Builder create() {
+        Builder builder = new Builder();
+        builder.result = new Field();
+        return builder;
+      }
+
+      private Field result;
+
+      /**
+       * Build the field.  After {@code build()} has been called, the
+       * {@code Builder} is no longer usable.  Calling any other method will
+       * result in undefined behavior and can cause a
+       * {@code NullPointerException} to be thrown.
+       */
+      public Field build() {
+        if (result.varint == null) {
+          result.varint = Collections.emptyList();
+        } else {
+          result.varint = Collections.unmodifiableList(result.varint);
+        }
+        if (result.fixed32 == null) {
+          result.fixed32 = Collections.emptyList();
+        } else {
+          result.fixed32 = Collections.unmodifiableList(result.fixed32);
+        }
+        if (result.fixed64 == null) {
+          result.fixed64 = Collections.emptyList();
+        } else {
+          result.fixed64 = Collections.unmodifiableList(result.fixed64);
+        }
+        if (result.lengthDelimited == null) {
+          result.lengthDelimited = Collections.emptyList();
+        } else {
+          result.lengthDelimited =
+            Collections.unmodifiableList(result.lengthDelimited);
+        }
+        if (result.group == null) {
+          result.group = Collections.emptyList();
+        } else {
+          result.group = Collections.unmodifiableList(result.group);
+        }
+
+        final Field returnMe = result;
+        result = null;
+        return returnMe;
+      }
+
+      /** Discard the field's contents. */
+      public Builder clear() {
+        result = new Field();
+        return this;
+      }
+
+      /**
+       * Merge the values in {@code other} into this field.  For each list
+       * of values, {@code other}'s values are append to the ones in this
+       * field.
+       */
+      public Builder mergeFrom(final Field other) {
+        if (!other.varint.isEmpty()) {
+          if (result.varint == null) {
+            result.varint = new ArrayList<Long>();
+          }
+          result.varint.addAll(other.varint);
+        }
+        if (!other.fixed32.isEmpty()) {
+          if (result.fixed32 == null) {
+            result.fixed32 = new ArrayList<Integer>();
+          }
+          result.fixed32.addAll(other.fixed32);
+        }
+        if (!other.fixed64.isEmpty()) {
+          if (result.fixed64 == null) {
+            result.fixed64 = new ArrayList<Long>();
+          }
+          result.fixed64.addAll(other.fixed64);
+        }
+        if (!other.lengthDelimited.isEmpty()) {
+          if (result.lengthDelimited == null) {
+            result.lengthDelimited = new ArrayList<ByteString>();
+          }
+          result.lengthDelimited.addAll(other.lengthDelimited);
+        }
+        if (!other.group.isEmpty()) {
+          if (result.group == null) {
+            result.group = new ArrayList<UnknownFieldSet>();
+          }
+          result.group.addAll(other.group);
+        }
+        return this;
+      }
+
+      /** Add a varint value. */
+      public Builder addVarint(final long value) {
+        if (result.varint == null) {
+          result.varint = new ArrayList<Long>();
+        }
+        result.varint.add(value);
+        return this;
+      }
+
+      /** Add a fixed32 value. */
+      public Builder addFixed32(final int value) {
+        if (result.fixed32 == null) {
+          result.fixed32 = new ArrayList<Integer>();
+        }
+        result.fixed32.add(value);
+        return this;
+      }
+
+      /** Add a fixed64 value. */
+      public Builder addFixed64(final long value) {
+        if (result.fixed64 == null) {
+          result.fixed64 = new ArrayList<Long>();
+        }
+        result.fixed64.add(value);
+        return this;
+      }
+
+      /** Add a length-delimited value. */
+      public Builder addLengthDelimited(final ByteString value) {
+        if (result.lengthDelimited == null) {
+          result.lengthDelimited = new ArrayList<ByteString>();
+        }
+        result.lengthDelimited.add(value);
+        return this;
+      }
+
+      /** Add an embedded group. */
+      public Builder addGroup(final UnknownFieldSet value) {
+        if (result.group == null) {
+          result.group = new ArrayList<UnknownFieldSet>();
+        }
+        result.group.add(value);
+        return this;
+      }
+    }
+  }
+
+  /**
+   * Parser to implement MessageLite interface.
+   */
+  public static final class Parser extends AbstractParser<UnknownFieldSet> {
+    @Override
+    public UnknownFieldSet parsePartialFrom(
+        CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      Builder builder = newBuilder();
+      try {
+        builder.mergeFrom(input);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(builder.buildPartial());
+      } catch (IOException e) {
+        throw new InvalidProtocolBufferException(e.getMessage())
+            .setUnfinishedMessage(builder.buildPartial());
+      }
+      return builder.buildPartial();
+    }
+  }
+
+  private static final Parser PARSER = new Parser();
+  @Override
+  public final Parser getParserForType() {
+    return PARSER;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
new file mode 100644
index 0000000..9500f905
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -0,0 +1,378 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * {@code UnknownFieldSetLite} is used to keep track of fields which were seen
+ * when parsing a protocol message but whose field numbers or types are
+ * unrecognized. This most frequently occurs when new fields are added to a
+ * message type and then messages containing those fields are read by old
+ * software that was compiled before the new types were added.
+ *
+ * <p>For use by generated code only.
+ *
+ * @author dweis@google.com (Daniel Weis)
+ */
+public final class UnknownFieldSetLite {
+  
+  // Arbitrarily chosen.
+  // TODO(dweis): Tune this number?
+  private static final int MIN_CAPACITY = 8;
+
+  private static final UnknownFieldSetLite DEFAULT_INSTANCE =
+      new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */);
+
+  /**
+   * Get an empty {@code UnknownFieldSetLite}.
+   *
+   * <p>For use by generated code only.
+   */
+  public static UnknownFieldSetLite getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+  
+  /**
+   * Returns a new mutable instance.
+   */
+  static UnknownFieldSetLite newInstance() {
+    return new UnknownFieldSetLite();
+  }
+
+  /**
+   * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and
+   * {@code second}.
+   */
+  static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) {
+    int count = first.count + second.count;
+    int[] tags = Arrays.copyOf(first.tags, count);
+    System.arraycopy(second.tags, 0, tags, first.count, second.count);
+    Object[] objects = Arrays.copyOf(first.objects, count);
+    System.arraycopy(second.objects, 0, objects, first.count, second.count);
+    return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
+  }
+  
+  /**
+   * The number of elements in the set.
+   */
+  private int count;
+  
+  /**
+   * The tag numbers for the elements in the set.
+   */
+  private int[] tags;
+  
+  /**
+   * The boxed values of the elements in the set.
+   */
+  private Object[] objects;
+  
+  /**
+   * The lazily computed serialized size of the set.
+   */
+  private int memoizedSerializedSize = -1;
+  
+  /**
+   * Indicates that this object is mutable. 
+   */
+  private boolean isMutable;
+
+  /**
+   * Constructs a mutable {@code UnknownFieldSetLite}.
+   */
+  private UnknownFieldSetLite() {
+    this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */);
+  }
+  
+  /**
+   * Constructs the {@code UnknownFieldSetLite}.
+   */
+  private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) {
+    this.count = count;
+    this.tags = tags;
+    this.objects = objects;
+    this.isMutable = isMutable;
+  }
+  
+  /**
+   * Marks this object as immutable.
+   * 
+   * <p>Future calls to methods that attempt to modify this object will throw.
+   */
+  public void makeImmutable() {
+    this.isMutable = false;
+  }
+  
+  /**
+   * Throws an {@link UnsupportedOperationException} if immutable.
+   */
+  void checkMutable() {
+    if (!isMutable) {
+      throw new UnsupportedOperationException(); 
+    }
+  }
+
+  /**
+   * Serializes the set and writes it to {@code output}.
+   *
+   * <p>For use by generated code only.
+   */
+  public void writeTo(CodedOutputStream output) throws IOException {
+    for (int i = 0; i < count; i++) {
+      int tag = tags[i];
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          output.writeUInt64(fieldNumber, (Long) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_FIXED32:
+          output.writeFixed32(fieldNumber, (Integer) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_FIXED64:
+          output.writeFixed64(fieldNumber, (Long) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          output.writeBytes(fieldNumber, (ByteString) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_START_GROUP:
+          output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+          ((UnknownFieldSetLite) objects[i]).writeTo(output);
+          output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+          break;
+        default:
+          throw InvalidProtocolBufferException.invalidWireType();
+      }
+    }
+  }
+
+  /**
+   * Get the number of bytes required to encode this set.
+   *
+   * <p>For use by generated code only.
+   */
+  public int getSerializedSize() {
+    int size = memoizedSerializedSize;
+    if (size != -1) {
+      return size;
+    }
+    
+    size = 0;
+    for (int i = 0; i < count; i++) {
+      int tag = tags[i];
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          size += CodedOutputStream.computeUInt64Size(fieldNumber, (Long) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_FIXED32:
+          size += CodedOutputStream.computeFixed32Size(fieldNumber, (Integer) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_FIXED64:
+          size += CodedOutputStream.computeFixed64Size(fieldNumber, (Long) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          size += CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) objects[i]);
+          break;
+        case WireFormat.WIRETYPE_START_GROUP:
+          size +=  CodedOutputStream.computeTagSize(fieldNumber) * 2
+              + ((UnknownFieldSetLite) objects[i]).getSerializedSize();
+          break;
+        default:
+          throw new IllegalStateException(InvalidProtocolBufferException.invalidWireType());
+      }
+    }
+    
+    memoizedSerializedSize = size;
+    
+    return size;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+
+    if (obj == null) {
+      return false;
+    }
+
+    if (!(obj instanceof UnknownFieldSetLite)) {
+      return false;
+    }
+    
+    UnknownFieldSetLite other = (UnknownFieldSetLite) obj;    
+    if (count != other.count
+        // TODO(dweis): Only have to compare up to count but at worst 2x worse than we need to do.
+        || !Arrays.equals(tags, other.tags)
+        || !Arrays.deepEquals(objects, other.objects)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 17;
+    
+    hashCode = 31 * hashCode + count;
+    hashCode = 31 * hashCode + Arrays.hashCode(tags);
+    hashCode = 31 * hashCode + Arrays.deepHashCode(objects);
+    
+    return hashCode;
+  }
+
+  /**
+   * Prints a String representation of the unknown field set.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param buffer the buffer to write to
+   * @param indent the number of spaces the fields should be indented by
+   */
+  final void printWithIndent(StringBuilder buffer, int indent) {
+    for (int i = 0; i < count; i++) {
+      int fieldNumber = WireFormat.getTagFieldNumber(tags[i]);
+      MessageLiteToString.printField(buffer, indent, String.valueOf(fieldNumber), objects[i]);
+    }
+  }
+
+  private void storeField(int tag, Object value) {
+    ensureCapacity();
+    
+    tags[count] = tag;
+    objects[count] = value;
+    count++;
+  }
+  
+  /**
+   * Ensures that our arrays are long enough to store more metadata.
+   */
+  private void ensureCapacity() {
+    if (count == tags.length) {        
+      int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
+      int newLength = count + increment;
+        
+      tags = Arrays.copyOf(tags, newLength);
+      objects = Arrays.copyOf(objects, newLength);
+    }
+  }
+  
+  /**
+   * Parse a single field from {@code input} and merge it into this set.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param tag The field's tag number, which was already parsed.
+   * @return {@code false} if the tag is an end group tag.
+   */
+  boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
+    checkMutable();
+    final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT:
+        storeField(tag, input.readInt64());
+        return true;
+      case WireFormat.WIRETYPE_FIXED32:
+        storeField(tag, input.readFixed32());
+        return true;
+      case WireFormat.WIRETYPE_FIXED64:
+        storeField(tag, input.readFixed64());
+        return true;
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+        storeField(tag, input.readBytes());
+        return true;
+      case WireFormat.WIRETYPE_START_GROUP:
+        final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite();
+        subFieldSet.mergeFrom(input);
+        input.checkLastTagWas(
+            WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+        storeField(tag, subFieldSet);
+        return true;
+      case WireFormat.WIRETYPE_END_GROUP:
+        return false;
+      default:
+        throw InvalidProtocolBufferException.invalidWireType();
+    }
+  }
+
+  /**
+   * Convenience method for merging a new field containing a single varint
+   * value. This is used in particular when an unknown enum value is
+   * encountered.
+   *
+   * <p>For use by generated code only.
+   */
+  UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) {
+    checkMutable();
+    if (fieldNumber == 0) {
+      throw new IllegalArgumentException("Zero is not a valid field number.");
+    }
+
+    storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
+    
+    return this;
+  }
+
+  /**
+   * Convenience method for merging a length-delimited field.
+   *
+   * <p>For use by generated code only.
+   */
+  UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {  
+    checkMutable();
+    if (fieldNumber == 0) {
+      throw new IllegalArgumentException("Zero is not a valid field number.");
+    }
+
+    storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
+    
+    return this;
+  }
+  
+  /**
+   * Parse an entire message from {@code input} and merge its fields into
+   * this set.
+   */
+  private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException {
+    // Ensures initialization in mergeFieldFrom.
+    while (true) {
+      final int tag = input.readTag();
+      if (tag == 0 || !mergeFieldFrom(tag, input)) {
+        break;
+      }
+    }
+    return this;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
new file mode 100644
index 0000000..30e8791
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
@@ -0,0 +1,210 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link LazyStringList} that wraps another
+ * {@link LazyStringList} such that it cannot be modified via the wrapper.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class UnmodifiableLazyStringList extends AbstractList<String>
+    implements LazyStringList, RandomAccess {
+
+  private final LazyStringList list;
+
+  public UnmodifiableLazyStringList(LazyStringList list) {
+    this.list = list;
+  }
+
+  @Override
+  public String get(int index) {
+    return list.get(index);
+  }
+  
+  @Override
+  public Object getRaw(int index) {
+    return list.getRaw(index);
+  }
+
+  @Override
+  public int size() {
+    return list.size();
+  }
+
+  @Override
+  public ByteString getByteString(int index) {
+    return list.getByteString(index);
+  }
+
+  @Override
+  public void add(ByteString element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void set(int index, ByteString element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean addAllByteString(Collection<? extends ByteString> element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public byte[] getByteArray(int index) {
+    return list.getByteArray(index);
+  }
+
+  @Override
+  public void add(byte[] element) {
+    throw new UnsupportedOperationException();
+  }
+  
+  @Override
+  public void set(int index, byte[] element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean addAllByteArray(Collection<byte[]> element) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public ListIterator<String> listIterator(final int index) {
+    return new ListIterator<String>() {
+      ListIterator<String> iter = list.listIterator(index);
+
+      @Override
+      public boolean hasNext() {
+        return iter.hasNext();
+      }
+
+      @Override
+      public String next() {
+        return iter.next();
+      }
+
+      @Override
+      public boolean hasPrevious() {
+        return iter.hasPrevious();
+      }
+
+      @Override
+      public String previous() {
+        return iter.previous();
+      }
+
+      @Override
+      public int nextIndex() {
+        return iter.nextIndex();
+      }
+
+      @Override
+      public int previousIndex() {
+        return iter.previousIndex();
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void set(String o) {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void add(String o) {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  @Override
+  public Iterator<String> iterator() {
+    return new Iterator<String>() {
+      Iterator<String> iter = list.iterator();
+
+      @Override
+      public boolean hasNext() {
+        return iter.hasNext();
+      }
+
+      @Override
+      public String next() {
+        return iter.next();
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  @Override
+  public List<?> getUnderlyingElements() {
+    // The returned value is already unmodifiable.
+    return list.getUnderlyingElements();
+  }
+
+  @Override
+  public void mergeFrom(LazyStringList other) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<byte[]> asByteArrayList() {
+    return Collections.unmodifiableList(list.asByteArrayList());
+  }
+
+  @Override
+  public List<ByteString> asByteStringList() {
+    return Collections.unmodifiableList(list.asByteStringList());
+  }
+
+  @Override
+  public LazyStringList getUnmodifiableView() {
+    return this;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
new file mode 100644
index 0000000..0fbf4d4
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -0,0 +1,84 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Provides a number of unsafe byte operations to be used by advanced applications with high
+ * performance requirements. These methods are referred to as "unsafe" due to the fact that they
+ * potentially expose the backing buffer of a {@link ByteString} to the application.
+ *
+ * <p><strong>DISCLAIMER:</strong> The methods in this class should only be called if it is
+ * guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a
+ * {@link ByteString} can lead to unexpected and undesirable consequences in your application,
+ * and will likely be difficult to debug. Proceed with caution!
+ */
+@ExperimentalApi
+public final class UnsafeByteOperations {
+  private UnsafeByteOperations() {}
+
+  /**
+   * An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
+   *
+   * @param buffer the Java NIO buffer to be wrapped
+   * @return a {@link ByteString} backed by the provided buffer
+   */
+  public static ByteString unsafeWrap(ByteBuffer buffer) {
+    if (buffer.hasArray()) {
+      final int offset = buffer.arrayOffset();
+      return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
+    } else {
+      return new NioByteString(buffer);
+    }
+  }
+
+  /**
+   * Writes the given {@link ByteString} to the provided {@link ByteOutput}. Calling this method may
+   * result in multiple operations on the target {@link ByteOutput}
+   * (i.e. for roped {@link ByteString}s).
+   *
+   * <p>This method exposes the internal backing buffer(s) of the {@link ByteString} to the {@link
+   * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
+   * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
+   *
+   * <p> NOTE: The {@link ByteOutput} <strong>MUST NOT</strong> modify the provided buffers. Doing
+   * so may result in corrupted data, which would be difficult to debug.
+   *
+   * @param bytes the {@link ByteString} to be written
+   * @param  output  the output to receive the bytes
+   * @throws IOException  if an I/O error occurs
+   */
+  public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException {
+    bytes.writeTo(output);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
new file mode 100644
index 0000000..308c69e
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -0,0 +1,1683 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.lang.Character.MAX_SURROGATE;
+import static java.lang.Character.MIN_SURROGATE;
+import static java.lang.Character.isSurrogatePair;
+import static java.lang.Character.toCodePoint;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A set of low-level, high-performance static utility methods related
+ * to the UTF-8 character encoding.  This class has no dependencies
+ * outside of the core JDK libraries.
+ *
+ * <p>There are several variants of UTF-8.  The one implemented by
+ * this class is the restricted definition of UTF-8 introduced in
+ * Unicode 3.1, which mandates the rejection of "overlong" byte
+ * sequences as well as rejection of 3-byte surrogate codepoint byte
+ * sequences.  Note that the UTF-8 decoder included in Oracle's JDK
+ * has been modified to also reject "overlong" byte sequences, but (as
+ * of 2011) still accepts 3-byte surrogate codepoint byte sequences.
+ *
+ * <p>The byte sequences considered valid by this class are exactly
+ * those that can be roundtrip converted to Strings and back to bytes
+ * using the UTF-8 charset, without loss: <pre> {@code
+ * Arrays.equals(bytes, new String(bytes, Internal.UTF_8).getBytes(Internal.UTF_8))
+ * }</pre>
+ *
+ * <p>See the Unicode Standard,</br>
+ * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
+ * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+ *
+ * <p>This class supports decoding of partial byte sequences, so that the
+ * bytes in a complete UTF-8 byte sequences can be stored in multiple
+ * segments.  Methods typically return {@link #MALFORMED} if the partial
+ * byte sequence is definitely not well-formed, {@link #COMPLETE} if it is
+ * well-formed in the absence of additional input, or if the byte sequence
+ * apparently terminated in the middle of a character, an opaque integer
+ * "state" value containing enough information to decode the character when
+ * passed to a subsequent invocation of a partial decoding method.
+ *
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+// TODO(nathanmittler): Copy changes in this class back to Guava
+final class Utf8 {
+  private static final Logger logger = Logger.getLogger(Utf8.class.getName());
+
+  /**
+   * UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations
+   * depending on what is available on the platform. The processor is the platform-optimized
+   * delegate for which all methods are delegated directly to.
+   */
+  private static final Processor processor =
+      UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor();
+
+  /**
+   * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII
+   * characters (i.e. any byte >= 0x80).
+   */
+  private static final long ASCII_MASK_LONG = 0x8080808080808080L;
+
+  /**
+   * Maximum number of bytes per Java UTF-16 char in UTF-8.
+   * @see java.nio.charset.CharsetEncoder#maxBytesPerChar()
+   */
+  static final int MAX_BYTES_PER_CHAR = 3;
+
+  /**
+   * State value indicating that the byte sequence is well-formed and
+   * complete (no further bytes are needed to complete a character).
+   */
+  public static final int COMPLETE = 0;
+
+  /**
+   * State value indicating that the byte sequence is definitely not
+   * well-formed.
+   */
+  public static final int MALFORMED = -1;
+
+  /**
+   * Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length
+   * above which to employ an optimized algorithm for counting ASCII characters. The reason for this
+   * threshold is that for small strings, the optimization may not be beneficial or may even
+   * negatively impact performance since it requires additional logic to avoid unaligned reads
+   * (when calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial
+   * offset is unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()}
+   * which provides a performance improvement that entirely subsumes the cost of the additional
+   * logic.
+   */
+  private static final int UNSAFE_COUNT_ASCII_THRESHOLD = 16;
+
+  // Other state values include the partial bytes of the incomplete
+  // character to be decoded in the simplest way: we pack the bytes
+  // into the state int in little-endian order.  For example:
+  //
+  // int state = byte1 ^ (byte2 << 8) ^ (byte3 << 16);
+  //
+  // Such a state is unpacked thus (note the ~ operation for byte2 to
+  // undo byte1's sign-extension bits):
+  //
+  // int byte1 = (byte) state;
+  // int byte2 = (byte) ~(state >> 8);
+  // int byte3 = (byte) (state >> 16);
+  //
+  // We cannot store a zero byte in the state because it would be
+  // indistinguishable from the absence of a byte.  But we don't need
+  // to, because partial bytes must always be negative.  When building
+  // a state, we ensure that byte1 is negative and subsequent bytes
+  // are valid trailing bytes.
+
+  /**
+   * Returns {@code true} if the given byte array is a well-formed
+   * UTF-8 byte sequence.
+   *
+   * <p>This is a convenience method, equivalent to a call to {@code
+   * isValidUtf8(bytes, 0, bytes.length)}.
+   */
+  public static boolean isValidUtf8(byte[] bytes) {
+    return processor.isValidUtf8(bytes, 0, bytes.length);
+  }
+
+  /**
+   * Returns {@code true} if the given byte array slice is a
+   * well-formed UTF-8 byte sequence.  The range of bytes to be
+   * checked extends from index {@code index}, inclusive, to {@code
+   * limit}, exclusive.
+   *
+   * <p>This is a convenience method, equivalent to {@code
+   * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+   */
+  public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
+    return processor.isValidUtf8(bytes, index, limit);
+  }
+
+  /**
+   * Tells whether the given byte array slice is a well-formed,
+   * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
+   * to be checked extends from index {@code index}, inclusive, to
+   * {@code limit}, exclusive.
+   *
+   * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
+   * operation) or the value returned from a call to a partial decoding method
+   * for the previous bytes
+   *
+   * @return {@link #MALFORMED} if the partial byte sequence is
+   * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+   * (no additional input needed), or if the byte sequence is
+   * "incomplete", i.e. apparently terminated in the middle of a character,
+   * an opaque integer "state" value containing enough information to
+   * decode the character when passed to a subsequent invocation of a
+   * partial decoding method.
+   */
+  public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+    return processor.partialIsValidUtf8(state, bytes, index, limit);
+  }
+
+  private static int incompleteStateFor(int byte1) {
+    return (byte1 > (byte) 0xF4) ?
+        MALFORMED : byte1;
+  }
+
+  private static int incompleteStateFor(int byte1, int byte2) {
+    return (byte1 > (byte) 0xF4 ||
+            byte2 > (byte) 0xBF) ?
+        MALFORMED : byte1 ^ (byte2 << 8);
+  }
+
+  private static int incompleteStateFor(int byte1, int byte2, int byte3) {
+    return (byte1 > (byte) 0xF4 ||
+            byte2 > (byte) 0xBF ||
+            byte3 > (byte) 0xBF) ?
+        MALFORMED : byte1 ^ (byte2 << 8) ^ (byte3 << 16);
+  }
+
+  private static int incompleteStateFor(byte[] bytes, int index, int limit) {
+    int byte1 = bytes[index - 1];
+    switch (limit - index) {
+      case 0: return incompleteStateFor(byte1);
+      case 1: return incompleteStateFor(byte1, bytes[index]);
+      case 2: return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
+      default: throw new AssertionError();
+    }
+  }
+
+  private static int incompleteStateFor(
+      final ByteBuffer buffer, final int byte1, final int index, final int remaining) {
+    switch (remaining) {
+      case 0:
+        return incompleteStateFor(byte1);
+      case 1:
+        return incompleteStateFor(byte1, buffer.get(index));
+      case 2:
+        return incompleteStateFor(byte1, buffer.get(index), buffer.get(index + 1));
+      default:
+        throw new AssertionError();
+    }
+  }
+
+  // These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw
+  // a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
+  // fallback to more lenient behavior.
+  
+  static class UnpairedSurrogateException extends IllegalArgumentException {
+    private UnpairedSurrogateException(int index, int length) {
+      super("Unpaired surrogate at index " + index + " of " + length);
+    }
+  }
+
+  /**
+   * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
+   * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
+   * both time and space.
+   *
+   * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+   *     surrogates)
+   */
+  static int encodedLength(CharSequence sequence) {
+    // Warning to maintainers: this implementation is highly optimized.
+    int utf16Length = sequence.length();
+    int utf8Length = utf16Length;
+    int i = 0;
+
+    // This loop optimizes for pure ASCII.
+    while (i < utf16Length && sequence.charAt(i) < 0x80) {
+      i++;
+    }
+
+    // This loop optimizes for chars less than 0x800.
+    for (; i < utf16Length; i++) {
+      char c = sequence.charAt(i);
+      if (c < 0x800) {
+        utf8Length += ((0x7f - c) >>> 31);  // branch free!
+      } else {
+        utf8Length += encodedLengthGeneral(sequence, i);
+        break;
+      }
+    }
+
+    if (utf8Length < utf16Length) {
+      // Necessary and sufficient condition for overflow because of maximum 3x expansion
+      throw new IllegalArgumentException("UTF-8 length does not fit in int: "
+              + (utf8Length + (1L << 32)));
+    }
+    return utf8Length;
+  }
+
+  private static int encodedLengthGeneral(CharSequence sequence, int start) {
+    int utf16Length = sequence.length();
+    int utf8Length = 0;
+    for (int i = start; i < utf16Length; i++) {
+      char c = sequence.charAt(i);
+      if (c < 0x800) {
+        utf8Length += (0x7f - c) >>> 31; // branch free!
+      } else {
+        utf8Length += 2;
+        // jdk7+: if (Character.isSurrogate(c)) {
+        if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
+          // Check that we have a well-formed surrogate pair.
+          int cp = Character.codePointAt(sequence, i);
+          if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            throw new UnpairedSurrogateException(i, utf16Length);
+          }
+          i++;
+        }
+      }
+    }
+    return utf8Length;
+  }
+
+  static int encode(CharSequence in, byte[] out, int offset, int length) {
+    return processor.encodeUtf8(in, out, offset, length);
+  }
+  // End Guava UTF-8 methods.
+
+  /**
+   * Determines if the given {@link ByteBuffer} is a valid UTF-8 string.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param buffer the buffer to check.
+   * @see Utf8#isValidUtf8(byte[], int, int)
+   */
+  static boolean isValidUtf8(ByteBuffer buffer) {
+    return processor.isValidUtf8(buffer, buffer.position(), buffer.remaining());
+  }
+
+  /**
+   * Determines if the given {@link ByteBuffer} is a partially valid UTF-8 string.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param buffer the buffer to check.
+   * @see Utf8#partialIsValidUtf8(int, byte[], int, int)
+   */
+  static int partialIsValidUtf8(int state, ByteBuffer buffer, int index, int limit) {
+    return processor.partialIsValidUtf8(state, buffer, index, limit);
+  }
+
+  /**
+   * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
+   *
+   * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+   * and the capabilities of the platform.
+   *
+   * @param in the source string to be encoded
+   * @param out the target buffer to receive the encoded string.
+   * @see Utf8#encode(CharSequence, byte[], int, int)
+   */
+  static void encodeUtf8(CharSequence in, ByteBuffer out) {
+    processor.encodeUtf8(in, out);
+  }
+
+  /**
+   * Counts (approximately) the number of consecutive ASCII characters in the given buffer.
+   * The byte order of the {@link ByteBuffer} does not matter, so performance can be improved if
+   * native byte order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}).
+   *
+   * @param buffer the buffer to be scanned for ASCII chars
+   * @param index the starting index of the scan
+   * @param limit the limit within buffer for the scan
+   * @return the number of ASCII characters found. The stopping position will be at or
+   * before the first non-ASCII byte.
+   */
+  private static int estimateConsecutiveAscii(ByteBuffer buffer, int index, int limit) {
+    int i = index;
+    final int lim = limit - 7;
+    // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+    // To speed things up further, we're reading longs instead of bytes so we use a mask to
+    // determine if any byte in the current long is non-ASCII.
+    for (; i < lim && (buffer.getLong(i) & ASCII_MASK_LONG) == 0; i += 8) {}
+    return i - index;
+  }
+
+  /**
+   * A processor of UTF-8 strings, providing methods for checking validity and encoding.
+   */
+  // TODO(nathanmittler): Add support for Memory/MemoryBlock on Android.
+  abstract static class Processor {
+    /**
+     * Returns {@code true} if the given byte array slice is a
+     * well-formed UTF-8 byte sequence.  The range of bytes to be
+     * checked extends from index {@code index}, inclusive, to {@code
+     * limit}, exclusive.
+     *
+     * <p>This is a convenience method, equivalent to {@code
+     * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+     */
+    final boolean isValidUtf8(byte[] bytes, int index, int limit) {
+      return partialIsValidUtf8(COMPLETE, bytes, index, limit) == COMPLETE;
+    }
+
+    /**
+     * Tells whether the given byte array slice is a well-formed,
+     * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
+     * to be checked extends from index {@code index}, inclusive, to
+     * {@code limit}, exclusive.
+     *
+     * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
+     * operation) or the value returned from a call to a partial decoding method
+     * for the previous bytes
+     *
+     * @return {@link #MALFORMED} if the partial byte sequence is
+     * definitely not well-formed, {@link #COMPLETE} if it is well-formed
+     * (no additional input needed), or if the byte sequence is
+     * "incomplete", i.e. apparently terminated in the middle of a character,
+     * an opaque integer "state" value containing enough information to
+     * decode the character when passed to a subsequent invocation of a
+     * partial decoding method.
+     */
+    abstract int partialIsValidUtf8(int state, byte[] bytes, int index, int limit);
+
+    /**
+     * Returns {@code true} if the given portion of the {@link ByteBuffer} is a
+     * well-formed UTF-8 byte sequence.  The range of bytes to be
+     * checked extends from index {@code index}, inclusive, to {@code
+     * limit}, exclusive.
+     *
+     * <p>This is a convenience method, equivalent to {@code
+     * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
+     */
+    final boolean isValidUtf8(ByteBuffer buffer, int index, int limit) {
+      return partialIsValidUtf8(COMPLETE, buffer, index, limit) == COMPLETE;
+    }
+
+    /**
+     * Indicates whether or not the given buffer contains a valid UTF-8 string.
+     *
+     * @param buffer the buffer to check.
+     * @return {@code true} if the given buffer contains a valid UTF-8 string.
+     */
+    final int partialIsValidUtf8(
+        final int state, final ByteBuffer buffer, int index, final int limit) {
+      if (buffer.hasArray()) {
+        final int offset = buffer.arrayOffset();
+        return partialIsValidUtf8(state, buffer.array(), offset + index, offset + limit);
+      } else if (buffer.isDirect()){
+        return partialIsValidUtf8Direct(state, buffer, index, limit);
+      }
+      return partialIsValidUtf8Default(state, buffer, index, limit);
+    }
+
+    /**
+     * Performs validation for direct {@link ByteBuffer} instances.
+     */
+    abstract int partialIsValidUtf8Direct(
+        final int state, final ByteBuffer buffer, int index, final int limit);
+
+    /**
+     * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+     * than potentially faster approaches. This first completes validation for the current
+     * character (provided by {@code state}) and then finishes validation for the sequence.
+     */
+    final int partialIsValidUtf8Default(
+        final int state, final ByteBuffer buffer, int index, final int limit) {
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (index >= limit) { // No bytes? No progress.
+          return state;
+        }
+
+        byte byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          byte byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          byte byte2 = (byte) ~(state >> 8);
+          byte byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = buffer.get(index++);
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      // Finish validation for the sequence.
+      return partialIsValidUtf8(buffer, index, limit);
+    }
+
+    /**
+     * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather
+     * than potentially faster approaches.
+     */
+    private static int partialIsValidUtf8(final ByteBuffer buffer, int index, final int limit) {
+      index += estimateConsecutiveAscii(buffer, index, limit);
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1;
+        do {
+          if (index >= limit) {
+            return COMPLETE;
+          }
+        } while ((byte1 = buffer.get(index++)) >= 0);
+
+        // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form (110xxxxx 10xxxxxx)
+          if (index >= limit) {
+            // Incomplete sequence
+            return byte1;
+          }
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2 || buffer.get(index) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+          index++;
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+          if (index >= limit - 1) {
+            // Incomplete sequence
+            return incompleteStateFor(buffer, byte1, index, limit - index);
+          }
+
+          final byte byte2 = buffer.get(index++);
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || buffer.get(index) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+          index++;
+        } else {
+          // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+          if (index >= limit - 2) {
+            // Incomplete sequence
+            return incompleteStateFor(buffer, byte1, index, limit - index);
+          }
+
+          // TODO(nathanmittler): Consider using getInt() to improve performance.
+          final int byte2 = buffer.get(index++);
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || buffer.get(index++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    /**
+     * Encodes an input character sequence ({@code in}) to UTF-8 in the target array ({@code out}).
+     * For a string, this method is similar to
+     * <pre>{@code
+     * byte[] a = string.getBytes(UTF_8);
+     * System.arraycopy(a, 0, bytes, offset, a.length);
+     * return offset + a.length;
+     * }</pre>
+     *
+     * but is more efficient in both time and space. One key difference is that this method
+     * requires paired surrogates, and therefore does not support chunking.
+     * While {@code String.getBytes(UTF_8)} replaces unpaired surrogates with the default
+     * replacement character, this method throws {@link UnpairedSurrogateException}.
+     *
+     * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+     * compute the exact amount needed, or leave room for 
+     * {@code Utf8.MAX_BYTES_PER_CHAR * sequence.length()}, which is the largest possible number
+     * of bytes that any input can be encoded to.
+     *
+     * @param in the input character sequence to be encoded
+     * @param out the target array
+     * @param offset the starting offset in {@code bytes} to start writing at
+     * @param length the length of the {@code bytes}, starting from {@code offset}
+     * @throws UnpairedSurrogateException if {@code sequence} contains ill-formed UTF-16 (unpaired
+     *     surrogates)
+     * @throws ArrayIndexOutOfBoundsException if {@code sequence} encoded in UTF-8 is longer than
+     *     {@code bytes.length - offset}
+     * @return the new offset, equivalent to {@code offset + Utf8.encodedLength(sequence)}
+     */
+    abstract int encodeUtf8(CharSequence in, byte[] out, int offset, int length);
+
+    /**
+     * Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}).
+     * Upon returning from this method, the {@code out} position will point to the position after
+     * the last encoded byte. This method requires paired surrogates, and therefore does not
+     * support chunking.
+     *
+     * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+     * compute the exact amount needed, or leave room for
+     * {@code Utf8.MAX_BYTES_PER_CHAR * in.length()}, which is the largest possible number
+     * of bytes that any input can be encoded to.
+     *
+     * @param in the source character sequence to be encoded
+     * @param out the target buffer
+     * @throws UnpairedSurrogateException if {@code in} contains ill-formed UTF-16 (unpaired
+     *     surrogates)
+     * @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than
+     *     {@code out.remaining()}
+     */
+    final void encodeUtf8(CharSequence in, ByteBuffer out) {
+      if (out.hasArray()) {
+        final int offset = out.arrayOffset();
+        int endIndex =
+            Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
+        out.position(endIndex - offset);
+      } else if (out.isDirect()) {
+        encodeUtf8Direct(in, out);
+      } else {
+        encodeUtf8Default(in, out);
+      }
+    }
+
+    /**
+     * Encodes the input character sequence to a direct {@link ByteBuffer} instance.
+     */
+    abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out);
+
+    /**
+     * Encodes the input character sequence to a {@link ByteBuffer} instance using the {@link
+     * ByteBuffer} API, rather than potentially faster approaches.
+     */
+    final void encodeUtf8Default(CharSequence in, ByteBuffer out) {
+      final int inLength = in.length();
+      int outIx = out.position();
+      int inIx = 0;
+
+      // Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check
+      // access. Assume the buffer is big enough and let it handle the out of bounds exception
+      // if it occurs.
+      try {
+        // Designed to take advantage of
+        // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+        for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+          out.put(outIx + inIx, (byte) c);
+        }
+        if (inIx == inLength) {
+          // Successfully encoded the entire string.
+          out.position(outIx + inIx);
+          return;
+        }
+
+        outIx += inIx;
+        for (char c; inIx < inLength; ++inIx, ++outIx) {
+          c = in.charAt(inIx);
+          if (c < 0x80) {
+            // One byte (0xxx xxxx)
+            out.put(outIx, (byte) c);
+          } else if (c < 0x800) {
+            // Two bytes (110x xxxx 10xx xxxx)
+
+            // Benchmarks show put performs better than putShort here (for HotSpot).
+            out.put(outIx++, (byte) (0xC0 | (c >>> 6)));
+            out.put(outIx, (byte) (0x80 | (0x3F & c)));
+          } else if (c < MIN_SURROGATE || MAX_SURROGATE < c) {
+            // Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
+            // Maximum single-char code point is 0xFFFF, 16 bits.
+
+            // Benchmarks show put performs better than putShort here (for HotSpot).
+            out.put(outIx++, (byte) (0xE0 | (c >>> 12)));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+            out.put(outIx, (byte) (0x80 | (0x3F & c)));
+          } else {
+            // Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx)
+
+            // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+            // bytes
+            final char low;
+            if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+              throw new UnpairedSurrogateException(inIx, inLength);
+            }
+            // TODO(nathanmittler): Consider using putInt() to improve performance.
+            int codePoint = toCodePoint(c, low);
+            out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+            out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+            out.put(outIx, (byte) (0x80 | (0x3F & codePoint)));
+          }
+        }
+
+        // Successfully encoded the entire string.
+        out.position(outIx);
+      } catch (IndexOutOfBoundsException e) {
+        // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
+
+        // If we failed in the outer ASCII loop, outIx will not have been updated. In this case,
+        // use inIx to determine the bad write index.
+        int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1);
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex);
+      }
+    }
+  }
+
+  /**
+   * {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods.
+   */
+  static final class SafeProcessor extends Processor {
+    @Override
+    int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (index >= limit) {  // No bytes? No progress.
+          return state;
+        }
+        int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = bytes[index++];
+            if (index >= limit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(bytes, index, limit);
+    }
+
+    @Override
+    int partialIsValidUtf8Direct(int state, ByteBuffer buffer, int index, int limit) {
+      // For safe processing, we have to use the ByteBuffer API.
+      return partialIsValidUtf8Default(state, buffer, index, limit);
+    }
+
+    @Override
+    int encodeUtf8(CharSequence in, byte[] out, int offset, int length) {
+      int utf16Length = in.length();
+      int j = offset;
+      int i = 0;
+      int limit = offset + length;
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) {
+        out[j + i] = (byte) c;
+      }
+      if (i == utf16Length) {
+        return j + utf16Length;
+      }
+      j += i;
+      for (char c; i < utf16Length; i++) {
+        c = in.charAt(i);
+        if (c < 0x80 && j < limit) {
+          out[j++] = (byte) c;
+        } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+          out[j++] = (byte) ((0xF << 6) | (c >>> 6));
+          out[j++] = (byte) (0x80 | (0x3F & c));
+        } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          out[j++] = (byte) ((0xF << 5) | (c >>> 12));
+          out[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+          out[j++] = (byte) (0x80 | (0x3F & c));
+        } else if (j <= limit - 4) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
+          // four UTF-8 bytes
+          final char low;
+          if (i + 1 == in.length()
+                  || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
+            throw new UnpairedSurrogateException((i - 1), utf16Length);
+          }
+          int codePoint = Character.toCodePoint(c, low);
+          out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+          out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+          out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+          out[j++] = (byte) (0x80 | (0x3F & codePoint));
+        } else {
+          // If we are surrogates and we're not a surrogate pair, always throw an
+          // UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
+          if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
+              && (i + 1 == in.length()
+                  || !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
+            throw new UnpairedSurrogateException(i, utf16Length);
+          }
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+        }
+      }
+      return j;
+    }
+
+    @Override
+    void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+      // For safe processing, we have to use the ByteBuffer API.
+      encodeUtf8Default(in, out);
+    }
+
+    private static int partialIsValidUtf8(byte[] bytes, int index, int limit) {
+      // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      while (index < limit && bytes[index] >= 0) {
+        index++;
+      }
+
+      return (index >= limit) ? COMPLETE : partialIsValidUtf8NonAscii(bytes, index, limit);
+    }
+
+    private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) {
+      for (;;) {
+        int byte1, byte2;
+
+        // Optimize for interior runs of ASCII bytes.
+        do {
+          if (index >= limit) {
+            return COMPLETE;
+          }
+        } while ((byte1 = bytes[index++]) >= 0);
+
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          if (index >= limit) {
+            // Incomplete sequence
+            return byte1;
+          }
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          if (index >= limit - 1) { // incomplete sequence
+            return incompleteStateFor(bytes, index, limit);
+          }
+          if ((byte2 = bytes[index++]) > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          if (index >= limit - 2) {  // incomplete sequence
+            return incompleteStateFor(bytes, index, limit);
+          }
+          if ((byte2 = bytes[index++]) > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || bytes[index++] > (byte) 0xBF
+              // byte4 trailing-byte test
+              || bytes[index++] > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
+   */
+  static final class UnsafeProcessor extends Processor {
+    private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+    private static final long BUFFER_ADDRESS_OFFSET =
+        fieldOffset(field(Buffer.class, "address"));
+    private static final int ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+
+    /**
+     * We only use Unsafe operations if we have access to direct {@link ByteBuffer}'s address
+     * and the array base offset is a multiple of 8 (needed by Unsafe.getLong()).
+     */
+    private static final boolean AVAILABLE =
+        BUFFER_ADDRESS_OFFSET != -1 && ARRAY_BASE_OFFSET % 8 == 0;
+
+    /**
+     * Indicates whether or not all required unsafe operations are supported on this platform.
+     */
+    static boolean isAvailable() {
+      return AVAILABLE;
+    }
+
+    @Override
+    int partialIsValidUtf8(int state, byte[] bytes, final int index, final int limit) {
+      if ((index | limit | bytes.length - limit) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
+      }
+      long offset = ARRAY_BASE_OFFSET + index;
+      final long offsetLimit = ARRAY_BASE_OFFSET + limit;
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (offset >= offsetLimit) {  // No bytes? No progress.
+          return state;
+        }
+        int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = UNSAFE.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = UNSAFE.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = UNSAFE.getByte(bytes, offset++);
+            if (offset >= offsetLimit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(bytes, offset, (int) (offsetLimit - offset));
+    }
+
+    @Override
+    int partialIsValidUtf8Direct(
+        final int state, ByteBuffer buffer, final int index, final int limit) {
+      if ((index | limit | buffer.limit() - limit) < 0) {
+        throw new ArrayIndexOutOfBoundsException(
+            String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, limit));
+      }
+      long address = addressOffset(buffer) + index;
+      final long addressLimit = address + (limit - index);
+      if (state != COMPLETE) {
+        // The previous decoding operation was incomplete (or malformed).
+        // We look for a well-formed sequence consisting of bytes from
+        // the previous decoding operation (stored in state) together
+        // with bytes from the array slice.
+        //
+        // We expect such "straddler characters" to be rare.
+
+        if (address >= addressLimit) { // No bytes? No progress.
+          return state;
+        }
+
+        final int byte1 = (byte) state;
+        // byte1 is never ASCII.
+        if (byte1 < (byte) 0xE0) {
+          // two-byte form
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              // byte2 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // three-byte form
+
+          // Get byte2 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          if (byte2 == 0) {
+            byte2 = UNSAFE.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          }
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // illegal surrogate codepoint?
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // four-byte form
+
+          // Get byte2 and byte3 from saved state or array
+          int byte2 = (byte) ~(state >> 8);
+          int byte3 = 0;
+          if (byte2 == 0) {
+            byte2 = UNSAFE.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2);
+            }
+          } else {
+            byte3 = (byte) (state >> 16);
+          }
+          if (byte3 == 0) {
+            byte3 = UNSAFE.getByte(address++);
+            if (address >= addressLimit) {
+              return incompleteStateFor(byte1, byte2, byte3);
+            }
+          }
+
+          // If we were called with state == MALFORMED, then byte1 is 0xFF,
+          // which never occurs in well-formed UTF-8, and so we will return
+          // MALFORMED again below.
+
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || byte3 > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+
+      return partialIsValidUtf8(address, (int) (addressLimit - address));
+    }
+
+    @Override
+    int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
+      long outIx = ARRAY_BASE_OFFSET + offset;
+      final long outLimit = outIx + length;
+      final int inLimit = in.length();
+      if (inLimit > length || out.length - length < offset) {
+        // Not even enough room for an ASCII-encoded string.
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inLimit - 1) + " at index " + (offset + length));
+      }
+
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      int inIx = 0;
+      for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+        UNSAFE.putByte(out, outIx++, (byte) c);
+      }
+      if (inIx == inLimit) {
+        // We're done, it was ASCII encoded.
+        return (int) (outIx - ARRAY_BASE_OFFSET);
+      }
+
+      for (char c; inIx < inLimit; ++inIx) {
+        c = in.charAt(inIx);
+        if (c < 0x80 && outIx < outLimit) {
+          UNSAFE.putByte(out, outIx++, (byte) c);
+        } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if (outIx <= outLimit - 4L) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+          // bytes
+          final char low;
+          if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+            throw new UnpairedSurrogateException((inIx - 1), inLimit);
+          }
+          int codePoint = toCodePoint(c, low);
+          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
+        } else {
+          if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+              && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+            // We are surrogates and we're not a surrogate pair.
+            throw new UnpairedSurrogateException(inIx, inLimit);
+          }
+          // Not enough space in the output buffer.
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+        }
+      }
+
+      // All bytes have been encoded.
+      return (int) (outIx - ARRAY_BASE_OFFSET);
+    }
+
+    @Override
+    void encodeUtf8Direct(CharSequence in, ByteBuffer out) {
+      final long address = addressOffset(out);
+      long outIx = address + out.position();
+      final long outLimit = address + out.limit();
+      final int inLimit = in.length();
+      if (inLimit > outLimit - outIx) {
+        // Not even enough room for an ASCII-encoded string.
+        throw new ArrayIndexOutOfBoundsException(
+            "Failed writing " + in.charAt(inLimit - 1) + " at index " + out.limit());
+      }
+
+      // Designed to take advantage of
+      // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+      int inIx = 0;
+      for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+        UNSAFE.putByte(outIx++, (byte) c);
+      }
+      if (inIx == inLimit) {
+        // We're done, it was ASCII encoded.
+        out.position((int) (outIx - address));
+        return;
+      }
+
+      for (char c; inIx < inLimit; ++inIx) {
+        c = in.charAt(inIx);
+        if (c < 0x80 && outIx < outLimit) {
+          UNSAFE.putByte(outIx++, (byte) c);
+        } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
+          UNSAFE.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
+          // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+          UNSAFE.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+        } else if (outIx <= outLimit - 4L) {
+          // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+          // bytes
+          final char low;
+          if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+            throw new UnpairedSurrogateException((inIx - 1), inLimit);
+          }
+          int codePoint = toCodePoint(c, low);
+          UNSAFE.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
+        } else {
+          if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
+              && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
+            // We are surrogates and we're not a surrogate pair.
+            throw new UnpairedSurrogateException(inIx, inLimit);
+          }
+          // Not enough space in the output buffer.
+          throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx);
+        }
+      }
+
+      // All bytes have been encoded.
+      out.position((int) (outIx - address));
+    }
+
+    /**
+     * Counts (approximately) the number of consecutive ASCII characters starting from the given
+     * position, using the most efficient method available to the platform.
+     *
+     * @param bytes the array containing the character sequence
+     * @param offset the offset position of the index (same as index + arrayBaseOffset)
+     * @param maxChars the maximum number of characters to count
+     * @return the number of ASCII characters found. The stopping position will be at or
+     * before the first non-ASCII byte.
+     */
+    private static int unsafeEstimateConsecutiveAscii(
+        byte[] bytes, long offset, final int maxChars) {
+      int remaining = maxChars;
+      if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+        // Don't bother with small strings.
+        return 0;
+      }
+
+      // Read bytes until 8-byte aligned so that we can read longs in the loop below.
+      // Byte arrays are already either 8 or 16-byte aligned, so we just need to make sure that
+      // the index (relative to the start of the array) is also 8-byte aligned. We do this by
+      // ANDing the index with 7 to determine the number of bytes that need to be read before
+      // we're 8-byte aligned.
+      final int unaligned = (int) offset & 7;
+      for (int j = unaligned; j > 0; j--) {
+        if (UNSAFE.getByte(bytes, offset++) < 0) {
+          return unaligned - j;
+        }
+      }
+
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      // To speed things up further, we're reading longs instead of bytes so we use a mask to
+      // determine if any byte in the current long is non-ASCII.
+      remaining -= unaligned;
+      for (; remaining >= 8 && (UNSAFE.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
+          offset += 8, remaining -= 8) {}
+      return maxChars - remaining;
+    }
+
+    /**
+     * Same as {@link Utf8#estimateConsecutiveAscii(ByteBuffer, int, int)} except that it uses the
+     * most efficient method available to the platform.
+     */
+    private static int unsafeEstimateConsecutiveAscii(long address, final int maxChars) {
+      int remaining = maxChars;
+      if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
+        // Don't bother with small strings.
+        return 0;
+      }
+
+      // Read bytes until 8-byte aligned so that we can read longs in the loop below.
+      // We do this by ANDing the address with 7 to determine the number of bytes that need to
+      // be read before we're 8-byte aligned.
+      final int unaligned = (int) address & 7;
+      for (int j = unaligned; j > 0; j--) {
+        if (UNSAFE.getByte(address++) < 0) {
+          return unaligned - j;
+        }
+      }
+
+      // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+      // To speed things up further, we're reading longs instead of bytes so we use a mask to
+      // determine if any byte in the current long is non-ASCII.
+      remaining -= unaligned;
+      for (; remaining >= 8 && (UNSAFE.getLong(address) & ASCII_MASK_LONG) == 0;
+          address += 8, remaining -= 8) {}
+      return maxChars - remaining;
+    }
+
+    private static int partialIsValidUtf8(final byte[] bytes, long offset, int remaining) {
+      // Skip past ASCII characters as quickly as possible. 
+      final int skipped = unsafeEstimateConsecutiveAscii(bytes, offset, remaining);
+      remaining -= skipped;
+      offset += skipped;
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1 = 0;
+        for (; remaining > 0 && (byte1 = UNSAFE.getByte(bytes, offset++)) >= 0; --remaining) {
+        }
+        if (remaining == 0) {
+          return COMPLETE;
+        }
+        remaining--;
+
+        // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms.
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form (110xxxxx 10xxxxxx)
+          if (remaining == 0) {
+            // Incomplete sequence
+            return byte1;
+          }
+          remaining--;
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx)
+          if (remaining < 2) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+          }
+          remaining -= 2;
+
+          final int byte2;
+          if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+          if (remaining < 3) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(bytes, byte1, offset, remaining);
+          }
+          remaining -= 3;
+
+          final int byte2;
+          if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    private static int partialIsValidUtf8(long address, int remaining) {
+      // Skip past ASCII characters as quickly as possible.
+      final int skipped = unsafeEstimateConsecutiveAscii(address, remaining);
+      address += skipped;
+      remaining -= skipped;
+
+      for (;;) {
+        // Optimize for interior runs of ASCII bytes.
+        // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
+        // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
+        int byte1 = 0;
+        for (; remaining > 0 && (byte1 = UNSAFE.getByte(address++)) >= 0; --remaining) {
+        }
+        if (remaining == 0) {
+          return COMPLETE;
+        }
+        remaining--;
+
+        if (byte1 < (byte) 0xE0) {
+          // Two-byte form
+
+          if (remaining == 0) {
+            // Incomplete sequence
+            return byte1;
+          }
+          remaining--;
+
+          // Simultaneously checks for illegal trailing-byte in
+          // leading position and overlong 2-byte form.
+          if (byte1 < (byte) 0xC2 || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else if (byte1 < (byte) 0xF0) {
+          // Three-byte form
+
+          if (remaining < 2) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(address, byte1, remaining);
+          }
+          remaining -= 2;
+
+          final byte byte2 = UNSAFE.getByte(address++);
+          if (byte2 > (byte) 0xBF
+              // overlong? 5 most significant bits must not all be zero
+              || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+              // check for illegal surrogate codepoints
+              || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        } else {
+          // Four-byte form
+
+          if (remaining < 3) {
+            // Incomplete sequence
+            return unsafeIncompleteStateFor(address, byte1, remaining);
+          }
+          remaining -= 3;
+
+          final byte byte2 = UNSAFE.getByte(address++);
+          if (byte2 > (byte) 0xBF
+              // Check that 1 <= plane <= 16.  Tricky optimized form of:
+              // if (byte1 > (byte) 0xF4 ||
+              //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+              //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+              || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+              // byte3 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF
+              // byte4 trailing-byte test
+              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+            return MALFORMED;
+          }
+        }
+      }
+    }
+
+    private static int unsafeIncompleteStateFor(byte[] bytes, int byte1, long offset,
+        int remaining) {
+      switch (remaining) {
+        case 0: {
+          return incompleteStateFor(byte1);
+        }
+        case 1: {
+          return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset));
+        }
+        case 2: {
+          return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset),
+              UNSAFE.getByte(bytes, offset + 1));
+        }
+        default: {
+          throw new AssertionError();
+        }
+      }
+    }
+
+    private static int unsafeIncompleteStateFor(long address, final int byte1, int remaining) {
+      switch (remaining) {
+        case 0: {
+          return incompleteStateFor(byte1);
+        }
+        case 1: {
+          return incompleteStateFor(byte1, UNSAFE.getByte(address));
+        }
+        case 2: {
+          return incompleteStateFor(byte1, UNSAFE.getByte(address), UNSAFE.getByte(address + 1));
+        }
+        default: {
+          throw new AssertionError();
+        }
+      }
+    }
+
+    /**
+     * Gets the field with the given name within the class, or {@code null} if not found. If
+     * found, the field is made accessible.
+     */
+    private static Field field(Class<?> clazz, String fieldName) {
+      Field field;
+      try {
+        field = clazz.getDeclaredField(fieldName);
+        field.setAccessible(true);
+      } catch (Throwable t) {
+        // Failed to access the fields.
+        field = null;
+      }
+      logger.log(Level.FINEST, "{0}.{1}: {2}",
+          new Object[] {clazz.getName(), fieldName, (field != null ? "available" : "unavailable")});
+      return field;
+    }
+
+    /**
+     * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
+     * available.
+     */
+    private static long fieldOffset(Field field) {
+      return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
+    }
+
+    /**
+     * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
+     * available.
+     */
+    private static <T> int byteArrayBaseOffset() {
+      return UNSAFE == null ? -1 : UNSAFE.arrayBaseOffset(byte[].class);
+    }
+
+    /**
+     * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
+     */
+    private static long addressOffset(ByteBuffer buffer) {
+      return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+    }
+
+    /**
+     * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
+     * platform.
+     */
+    private static sun.misc.Unsafe getUnsafe() {
+      sun.misc.Unsafe unsafe = null;
+      try {
+        unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
+          @Override
+          public sun.misc.Unsafe run() throws Exception {
+            Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+            // Check that this platform supports all of the required unsafe methods.
+            checkRequiredMethods(k);
+
+            for (Field f : k.getDeclaredFields()) {
+              f.setAccessible(true);
+              Object x = f.get(null);
+              if (k.isInstance(x)) {
+                return k.cast(x);
+              }
+            }
+            // The sun.misc.Unsafe field does not exist.
+            return null;
+          }
+        });
+      } catch (Throwable e) {
+        // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+        // for Unsafe.
+      }
+
+      logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
+          unsafe != null ? "available" : "unavailable");
+      return unsafe;
+    }
+
+    /**
+     * Verifies that all required methods of {@code sun.misc.Unsafe} are available on this platform.
+     */
+    private static void checkRequiredMethods(Class<sun.misc.Unsafe> clazz)
+        throws NoSuchMethodException, SecurityException {
+      // Needed for Unsafe byte[] access
+      clazz.getMethod("arrayBaseOffset", Class.class);
+      clazz.getMethod("getByte", Object.class, long.class);
+      clazz.getMethod("putByte", Object.class, long.class, byte.class);
+      clazz.getMethod("getLong", Object.class, long.class);
+
+      // Needed for Unsafe Direct ByteBuffer access
+      clazz.getMethod("objectFieldOffset", Field.class);
+      clazz.getMethod("getByte", long.class);
+      clazz.getMethod("getLong", Object.class, long.class);
+      clazz.getMethod("putByte", long.class, byte.class);
+      clazz.getMethod("getLong", long.class);
+    }
+  }
+
+  private Utf8() {}
+}
diff --git a/java/core/src/main/java/com/google/protobuf/WireFormat.java b/java/core/src/main/java/com/google/protobuf/WireFormat.java
new file mode 100644
index 0000000..6a58b08
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java
@@ -0,0 +1,256 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations.  It is public only because those generated messages
+ * do not reside in the {@code protobuf} package.  Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormat {
+  // Do not allow instantiation.
+  private WireFormat() {}
+
+  public static final int WIRETYPE_VARINT           = 0;
+  public static final int WIRETYPE_FIXED64          = 1;
+  public static final int WIRETYPE_LENGTH_DELIMITED = 2;
+  public static final int WIRETYPE_START_GROUP      = 3;
+  public static final int WIRETYPE_END_GROUP        = 4;
+  public static final int WIRETYPE_FIXED32          = 5;
+
+  static final int TAG_TYPE_BITS = 3;
+  static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+  /** Given a tag value, determines the wire type (the lower 3 bits). */
+  public static int getTagWireType(final int tag) {
+    return tag & TAG_TYPE_MASK;
+  }
+
+  /** Given a tag value, determines the field number (the upper 29 bits). */
+  public static int getTagFieldNumber(final int tag) {
+    return tag >>> TAG_TYPE_BITS;
+  }
+
+  /** Makes a tag value given a field number and wire type. */
+  static int makeTag(final int fieldNumber, final int wireType) {
+    return (fieldNumber << TAG_TYPE_BITS) | wireType;
+  }
+
+  /**
+   * Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}.  This is
+   * only here to support the lite runtime and should not be used by users.
+   */
+  public enum JavaType {
+    INT(0),
+    LONG(0L),
+    FLOAT(0F),
+    DOUBLE(0D),
+    BOOLEAN(false),
+    STRING(""),
+    BYTE_STRING(ByteString.EMPTY),
+    ENUM(null),
+    MESSAGE(null);
+
+    JavaType(final Object defaultDefault) {
+      this.defaultDefault = defaultDefault;
+    }
+
+    /**
+     * The default default value for fields of this type, if it's a primitive
+     * type.
+     */
+    Object getDefaultDefault() {
+      return defaultDefault;
+    }
+
+    private final Object defaultDefault;
+  }
+
+  /**
+   * Lite equivalent to {@link Descriptors.FieldDescriptor.Type}.  This is
+   * only here to support the lite runtime and should not be used by users.
+   */
+  public enum FieldType {
+    DOUBLE  (JavaType.DOUBLE     , WIRETYPE_FIXED64         ),
+    FLOAT   (JavaType.FLOAT      , WIRETYPE_FIXED32         ),
+    INT64   (JavaType.LONG       , WIRETYPE_VARINT          ),
+    UINT64  (JavaType.LONG       , WIRETYPE_VARINT          ),
+    INT32   (JavaType.INT        , WIRETYPE_VARINT          ),
+    FIXED64 (JavaType.LONG       , WIRETYPE_FIXED64         ),
+    FIXED32 (JavaType.INT        , WIRETYPE_FIXED32         ),
+    BOOL    (JavaType.BOOLEAN    , WIRETYPE_VARINT          ),
+    STRING  (JavaType.STRING     , WIRETYPE_LENGTH_DELIMITED) {
+      @Override
+      public boolean isPackable() {
+        return false; }
+    },
+    GROUP   (JavaType.MESSAGE    , WIRETYPE_START_GROUP     ) {
+      @Override
+      public boolean isPackable() {
+        return false; }
+    },
+    MESSAGE (JavaType.MESSAGE    , WIRETYPE_LENGTH_DELIMITED) {
+      @Override
+      public boolean isPackable() {
+        return false; }
+    },
+    BYTES   (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
+      @Override
+      public boolean isPackable() {
+        return false; }
+    },
+    UINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
+    ENUM    (JavaType.ENUM       , WIRETYPE_VARINT          ),
+    SFIXED32(JavaType.INT        , WIRETYPE_FIXED32         ),
+    SFIXED64(JavaType.LONG       , WIRETYPE_FIXED64         ),
+    SINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
+    SINT64  (JavaType.LONG       , WIRETYPE_VARINT          );
+
+    FieldType(final JavaType javaType, final int wireType) {
+      this.javaType = javaType;
+      this.wireType = wireType;
+    }
+
+    private final JavaType javaType;
+    private final int wireType;
+
+    public JavaType getJavaType() { return javaType; }
+    public int getWireType() { return wireType; }
+
+    public boolean isPackable() { return true; }
+  }
+
+  // Field numbers for fields in MessageSet wire format.
+  static final int MESSAGE_SET_ITEM    = 1;
+  static final int MESSAGE_SET_TYPE_ID = 2;
+  static final int MESSAGE_SET_MESSAGE = 3;
+
+  // Tag numbers.
+  static final int MESSAGE_SET_ITEM_TAG =
+    makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
+  static final int MESSAGE_SET_ITEM_END_TAG =
+    makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
+  static final int MESSAGE_SET_TYPE_ID_TAG =
+    makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
+  static final int MESSAGE_SET_MESSAGE_TAG =
+    makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+
+  /**
+   * Validation level for handling incoming string field data which potentially
+   * contain non-UTF8 bytes.
+   */
+  enum Utf8Validation {
+    /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
+    LOOSE {
+      @Override
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readString();
+      }
+    },
+    /** Eagerly parses to String; throws an IOException on invalid bytes. */
+    STRICT {
+      @Override
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readStringRequireUtf8();
+      }
+    },
+    /** Keep data as ByteString; validation/conversion to String is lazy. */
+    LAZY {
+      @Override
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readBytes();
+      }
+    };
+
+    /** Read a string field from the input with the proper UTF8 validation. */
+    abstract Object readString(CodedInputStream input) throws IOException;
+  }
+
+  /**
+   * Read a field of any primitive type for immutable messages from a
+   * CodedInputStream. Enums, groups, and embedded messages are not handled by
+   * this method.
+   *
+   * @param input The stream from which to read.
+   * @param type Declared type of the field.
+   * @param utf8Validation Different string UTF8 validation level for handling
+   *                       string fields.
+   * @return An object representing the field's value, of the exact
+   *         type which would be returned by
+   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *         this field.
+   */
+  static Object readPrimitiveField(
+      CodedInputStream input,
+      FieldType type,
+      Utf8Validation utf8Validation) throws IOException {
+    switch (type) {
+      case DOUBLE  : return input.readDouble  ();
+      case FLOAT   : return input.readFloat   ();
+      case INT64   : return input.readInt64   ();
+      case UINT64  : return input.readUInt64  ();
+      case INT32   : return input.readInt32   ();
+      case FIXED64 : return input.readFixed64 ();
+      case FIXED32 : return input.readFixed32 ();
+      case BOOL    : return input.readBool    ();
+      case BYTES   : return input.readBytes   ();
+      case UINT32  : return input.readUInt32  ();
+      case SFIXED32: return input.readSFixed32();
+      case SFIXED64: return input.readSFixed64();
+      case SINT32  : return input.readSInt32  ();
+      case SINT64  : return input.readSInt64  ();
+
+      case STRING  : return utf8Validation.readString(input);
+      case GROUP:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle nested groups.");
+      case MESSAGE:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle embedded messages.");
+      case ENUM:
+        // We don't handle enums because we don't know what to do if the
+        // value is not recognized.
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle enums.");
+    }
+
+    throw new RuntimeException(
+      "There is no way to get here, but the compiler thinks otherwise.");
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
new file mode 100644
index 0000000..7dc9fc1
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -0,0 +1,551 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+/**
+ * Unit test for {@link AbstractMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class AbstractMessageTest extends TestCase {
+  /**
+   * Extends AbstractMessage and wraps some other message object.  The methods
+   * of the Message interface which aren't explicitly implemented by
+   * AbstractMessage are forwarded to the wrapped object.  This allows us to
+   * test that AbstractMessage's implementations work even if the wrapped
+   * object does not use them.
+   */
+  private static class AbstractMessageWrapper extends AbstractMessage {
+    private final Message wrappedMessage;
+
+    public AbstractMessageWrapper(Message wrappedMessage) {
+      this.wrappedMessage = wrappedMessage;
+    }
+
+    @Override
+    public Descriptors.Descriptor getDescriptorForType() {
+      return wrappedMessage.getDescriptorForType();
+    }
+    @Override
+    public AbstractMessageWrapper getDefaultInstanceForType() {
+      return new AbstractMessageWrapper(
+        wrappedMessage.getDefaultInstanceForType());
+    }
+    @Override
+    public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+      return wrappedMessage.getAllFields();
+    }
+    @Override
+    public boolean hasField(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.hasField(field);
+    }
+    @Override
+    public Object getField(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.getField(field);
+    }
+    @Override
+    public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+      return wrappedMessage.getRepeatedFieldCount(field);
+    }
+    @Override
+    public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
+      return wrappedMessage.getRepeatedField(field, index);
+    }
+    @Override
+    public UnknownFieldSet getUnknownFields() {
+      return wrappedMessage.getUnknownFields();
+    }
+    @Override
+    public Builder newBuilderForType() {
+      return new Builder(wrappedMessage.newBuilderForType());
+    }
+    @Override
+    public Builder toBuilder() {
+      return new Builder(wrappedMessage.toBuilder());
+    }
+
+    static class Builder extends AbstractMessage.Builder<Builder> {
+      private final Message.Builder wrappedBuilder;
+
+      public Builder(Message.Builder wrappedBuilder) {
+        this.wrappedBuilder = wrappedBuilder;
+      }
+
+      @Override
+      public AbstractMessageWrapper build() {
+        return new AbstractMessageWrapper(wrappedBuilder.build());
+      }
+      @Override
+      public AbstractMessageWrapper buildPartial() {
+        return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
+      }
+      @Override
+      public Builder clone() {
+        return new Builder(wrappedBuilder.clone());
+      }
+      @Override
+      public boolean isInitialized() {
+        return clone().buildPartial().isInitialized();
+      }
+      @Override
+      public Descriptors.Descriptor getDescriptorForType() {
+        return wrappedBuilder.getDescriptorForType();
+      }
+      @Override
+      public AbstractMessageWrapper getDefaultInstanceForType() {
+        return new AbstractMessageWrapper(
+          wrappedBuilder.getDefaultInstanceForType());
+      }
+      @Override
+      public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+        return wrappedBuilder.getAllFields();
+      }
+      @Override
+      public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
+        return new Builder(wrappedBuilder.newBuilderForField(field));
+      }
+      @Override
+      public boolean hasField(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.hasField(field);
+      }
+      @Override
+      public Object getField(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.getField(field);
+      }
+      @Override
+      public Builder setField(Descriptors.FieldDescriptor field, Object value) {
+        wrappedBuilder.setField(field, value);
+        return this;
+      }
+      @Override
+      public Builder clearField(Descriptors.FieldDescriptor field) {
+        wrappedBuilder.clearField(field);
+        return this;
+      }
+      @Override
+      public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+        return wrappedBuilder.getRepeatedFieldCount(field);
+      }
+      @Override
+      public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
+        return wrappedBuilder.getRepeatedField(field, index);
+      }
+      @Override
+      public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) {
+        wrappedBuilder.setRepeatedField(field, index, value);
+        return this;
+      }
+      @Override
+      public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) {
+        wrappedBuilder.addRepeatedField(field, value);
+        return this;
+      }
+      @Override
+      public UnknownFieldSet getUnknownFields() {
+        return wrappedBuilder.getUnknownFields();
+      }
+      @Override
+      public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+        wrappedBuilder.setUnknownFields(unknownFields);
+        return this;
+      }
+      @Override
+      public Message.Builder getFieldBuilder(FieldDescriptor field) {
+        return wrappedBuilder.getFieldBuilder(field);
+      }
+    }
+    @Override
+    public Parser<? extends Message> getParserForType() {
+      return wrappedMessage.getParserForType();
+    }
+  }
+
+  // =================================================================
+
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+
+  public void testClear() throws Exception {
+    AbstractMessageWrapper message =
+      new AbstractMessageWrapper.Builder(
+          TestAllTypes.newBuilder(TestUtil.getAllSet()))
+        .clear().build();
+    TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testCopy() throws Exception {
+    AbstractMessageWrapper message =
+      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
+        .mergeFrom(TestUtil.getAllSet()).build();
+    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testSerializedSize() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+    assertEquals(message.getSerializedSize(),
+                 abstractMessage.getSerializedSize());
+  }
+
+  public void testSerialization() throws Exception {
+    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+    TestUtil.assertAllFieldsSet(
+      TestAllTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getAllSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
+    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+  }
+
+  public void testParsingUninitialized() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+    builder.getOptionalMessageBuilder().setDummy2(10);
+    ByteString bytes = builder.buildPartial().toByteString();
+    Message.Builder abstractMessageBuilder =
+        new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
+    // mergeFrom() should not throw initialization error.
+    abstractMessageBuilder.mergeFrom(bytes).buildPartial();
+    try {
+      abstractMessageBuilder.mergeFrom(bytes).build();
+      fail();
+    } catch (UninitializedMessageException ex) {
+      // pass
+    }
+
+    // test DynamicMessage directly.
+    Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
+        TestRequiredForeign.getDescriptor());
+    // mergeFrom() should not throw initialization error.
+    dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
+    try {
+      dynamicMessageBuilder.mergeFrom(bytes).build();
+      fail();
+    } catch (UninitializedMessageException ex) {
+      // pass
+    }
+  }
+
+  public void testPackedSerialization() throws Exception {
+    Message abstractMessage =
+        new AbstractMessageWrapper(TestUtil.getPackedSet());
+
+    TestUtil.assertPackedFieldsSet(
+      TestPackedTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getPackedSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testPackedParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
+  }
+
+  public void testUnpackedSerialization() throws Exception {
+    Message abstractMessage =
+      new AbstractMessageWrapper(TestUtil.getUnpackedSet());
+
+    TestUtil.assertUnpackedFieldsSet(
+      TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
+
+    assertEquals(TestUtil.getUnpackedSet().toByteString(),
+                 abstractMessage.toByteString());
+  }
+
+  public void testParsePackedToUnpacked() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(
+      (TestUnpackedTypes) message.wrappedMessage);
+  }
+
+  public void testParseUnpackedToPacked() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
+  }
+
+  public void testUnpackedParsing() throws Exception {
+    AbstractMessageWrapper.Builder builder =
+      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
+    AbstractMessageWrapper message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(
+      (TestUnpackedTypes) message.wrappedMessage);
+  }
+
+  public void testOptimizedForSize() throws Exception {
+    // We're mostly only checking that this class was compiled successfully.
+    TestOptimizedForSize message =
+      TestOptimizedForSize.newBuilder().setI(1).build();
+    message = TestOptimizedForSize.parseFrom(message.toByteString());
+    assertEquals(2, message.getSerializedSize());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for isInitialized().
+
+  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+    TestRequired.getDefaultInstance();
+  private static final TestRequired TEST_REQUIRED_INITIALIZED =
+    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+  public void testIsInitialized() throws Exception {
+    TestRequired.Builder builder = TestRequired.newBuilder();
+    AbstractMessageWrapper.Builder abstractBuilder =
+      new AbstractMessageWrapper.Builder(builder);
+
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
+    builder.setA(1);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals("b, c", abstractBuilder.getInitializationErrorString());
+    builder.setB(1);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals("c", abstractBuilder.getInitializationErrorString());
+    builder.setC(1);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+  }
+
+  public void testForeignIsInitialized() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+    AbstractMessageWrapper.Builder abstractBuilder =
+      new AbstractMessageWrapper.Builder(builder);
+
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+
+    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals(
+        "optional_message.a, optional_message.b, optional_message.c",
+        abstractBuilder.getInitializationErrorString());
+
+    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+
+    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(abstractBuilder.isInitialized());
+    assertEquals(
+        "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+        abstractBuilder.getInitializationErrorString());
+
+    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(abstractBuilder.isInitialized());
+    assertEquals("", abstractBuilder.getInitializationErrorString());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for mergeFrom
+
+  static final TestAllTypes MERGE_SOURCE =
+    TestAllTypes.newBuilder()
+      .setOptionalInt32(1)
+      .setOptionalString("foo")
+      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+      .addRepeatedString("bar")
+      .build();
+
+  static final TestAllTypes MERGE_DEST =
+    TestAllTypes.newBuilder()
+      .setOptionalInt64(2)
+      .setOptionalString("baz")
+      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+      .addRepeatedString("qux")
+      .build();
+
+  static final String MERGE_RESULT_TEXT =
+      "optional_int32: 1\n" +
+      "optional_int64: 2\n" +
+      "optional_string: \"foo\"\n" +
+      "optional_foreign_message {\n" +
+      "  c: 3\n" +
+      "}\n" +
+      "repeated_string: \"qux\"\n" +
+      "repeated_string: \"bar\"\n";
+
+  public void testMergeFrom() throws Exception {
+    AbstractMessageWrapper result =
+      new AbstractMessageWrapper.Builder(
+        TestAllTypes.newBuilder(MERGE_DEST))
+      .mergeFrom(MERGE_SOURCE).build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  // -----------------------------------------------------------------
+  // Tests for equals and hashCode
+
+  public void testEqualsAndHashCode() throws Exception {
+    TestAllTypes a = TestUtil.getAllSet();
+    TestAllTypes b = TestAllTypes.newBuilder().build();
+    TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
+    TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
+    TestAllExtensions e = TestUtil.getAllExtensionsSet();
+    TestAllExtensions f = TestAllExtensions.newBuilder(e)
+        .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
+
+    checkEqualsIsConsistent(a);
+    checkEqualsIsConsistent(b);
+    checkEqualsIsConsistent(c);
+    checkEqualsIsConsistent(d);
+    checkEqualsIsConsistent(e);
+    checkEqualsIsConsistent(f);
+
+    checkNotEqual(a, b);
+    checkNotEqual(a, c);
+    checkNotEqual(a, d);
+    checkNotEqual(a, e);
+    checkNotEqual(a, f);
+
+    checkNotEqual(b, c);
+    checkNotEqual(b, d);
+    checkNotEqual(b, e);
+    checkNotEqual(b, f);
+
+    checkNotEqual(c, d);
+    checkNotEqual(c, e);
+    checkNotEqual(c, f);
+
+    checkNotEqual(d, e);
+    checkNotEqual(d, f);
+
+    checkNotEqual(e, f);
+
+    // Deserializing into the TestEmptyMessage such that every field
+    // is an {@link UnknownFieldSet.Field}.
+    UnittestProto.TestEmptyMessage eUnknownFields =
+        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+    UnittestProto.TestEmptyMessage fUnknownFields =
+        UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
+    checkNotEqual(eUnknownFields, fUnknownFields);
+    checkEqualsIsConsistent(eUnknownFields);
+    checkEqualsIsConsistent(fUnknownFields);
+
+    // Subsequent reconstitutions should be identical
+    UnittestProto.TestEmptyMessage eUnknownFields2 =
+        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+    checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
+  }
+
+
+  /**
+   * Asserts that the given proto has symmetric equals and hashCode methods.
+   */
+  private void checkEqualsIsConsistent(Message message) {
+    // Object should be equal to itself.
+    assertEquals(message, message);
+
+    // Object should be equal to a dynamic copy of itself.
+    DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
+    checkEqualsIsConsistent(message, dynamic);
+  }
+
+  /**
+   * Asserts that the given protos are equal and have the same hash code.
+   */
+  private void checkEqualsIsConsistent(Message message1, Message message2) {
+    assertEquals(message1, message2);
+    assertEquals(message2, message1);
+    assertEquals(message2.hashCode(), message1.hashCode());
+  }
+
+  /**
+   * Asserts that the given protos are not equal and have different hash codes.
+   *
+   * @warning It's valid for non-equal objects to have the same hash code, so
+   *   this test is stricter than it needs to be. However, this should happen
+   *   relatively rarely.
+   */
+  private void checkNotEqual(Message m1, Message m2) {
+    String equalsError = String.format("%s should not be equal to %s", m1, m2);
+    assertFalse(equalsError, m1.equals(m2));
+    assertFalse(equalsError, m2.equals(m1));
+
+    assertFalse(
+        String.format("%s should have a different hash code from %s", m1, m2),
+        m1.hashCode() == m2.hashCode());
+  }
+
+  public void testCheckByteStringIsUtf8OnUtf8() {
+    ByteString byteString = ByteString.copyFromUtf8("some text");
+    AbstractMessageLite.checkByteStringIsUtf8(byteString);
+    // No exception thrown.
+  }
+
+  public void testCheckByteStringIsUtf8OnNonUtf8() {
+    ByteString byteString =
+        ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+    try {
+      AbstractMessageLite.checkByteStringIsUtf8(byteString);
+      fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+}
diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
new file mode 100644
index 0000000..cf91ed9
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -0,0 +1,137 @@
+// 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.
+
+package com.google.protobuf;
+
+import any_test.AnyTestProto.TestAny;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for Any message.
+ */
+public class AnyTest extends TestCase {
+  public void testAnyGeneratedApi() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    TestAny container = TestAny.newBuilder()
+        .setValue(Any.pack(message)).build();
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+
+
+    // Unpacking to a wrong type will throw an exception.
+    try {
+      TestAny wrongMessage = container.getValue().unpack(TestAny.class);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // expected.
+    }
+
+    // Test that unpacking throws an exception if parsing fails.
+    TestAny.Builder containerBuilder = container.toBuilder();
+    containerBuilder.getValueBuilder().setValue(
+        ByteString.copyFrom(new byte[]{0x11}));
+    container = containerBuilder.build();
+    try {
+      TestAllTypes parsingFailed = container.getValue().unpack(TestAllTypes.class);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // expected.
+    }
+  }
+
+  public void testCustomTypeUrls() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    TestAny container = TestAny.newBuilder()
+        .setValue(Any.pack(message, "xxx.com")).build();
+
+    assertEquals(
+        "xxx.com/" + TestAllTypes.getDescriptor().getFullName(),
+        container.getValue().getTypeUrl());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+
+    container = TestAny.newBuilder()
+        .setValue(Any.pack(message, "yyy.com/")).build();
+
+    assertEquals(
+        "yyy.com/" + TestAllTypes.getDescriptor().getFullName(),
+        container.getValue().getTypeUrl());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+
+    container = TestAny.newBuilder()
+        .setValue(Any.pack(message, "")).build();
+
+    assertEquals(
+        "/" + TestAllTypes.getDescriptor().getFullName(),
+        container.getValue().getTypeUrl());
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+    assertFalse(container.getValue().is(TestAny.class));
+
+    result = container.getValue().unpack(TestAllTypes.class);
+    TestUtil.assertAllFieldsSet(result);
+  }
+
+  public void testCachedUnpackResult() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    TestAny container = TestAny.newBuilder()
+        .setValue(Any.pack(message)).build();
+
+    assertTrue(container.getValue().is(TestAllTypes.class));
+
+    TestAllTypes result1 = container.getValue().unpack(TestAllTypes.class);
+    TestAllTypes result2 = container.getValue().unpack(TestAllTypes.class);
+    assertTrue(result1 == result2);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
new file mode 100644
index 0000000..24b96c6
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -0,0 +1,455 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link BooleanArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class BooleanArrayListTest extends TestCase {
+  
+  private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
+  private static final BooleanArrayList TERTIARY_LIST =
+      newImmutableBooleanArrayList(true, true, false);
+  
+  private BooleanArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new BooleanArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(BooleanArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addBoolean(true);
+    list.addBoolean(false);
+    list.addBoolean(true);
+    list.addBoolean(true);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(true, false, false, true));
+    Iterator<Boolean> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, (boolean) iterator.next());
+    list.set(0, true);
+    assertEquals(false, (boolean) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, false);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(true, (boolean) TERTIARY_LIST.get(0));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(1));
+    assertEquals(false, (boolean) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(true, TERTIARY_LIST.getBoolean(0));
+    assertEquals(true, TERTIARY_LIST.getBoolean(1));
+    assertEquals(false, TERTIARY_LIST.getBoolean(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, BooleanArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addBoolean(true);
+    list.addBoolean(false);
+    list.addBoolean(false);
+    list.addBoolean(false);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(true);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addBoolean(false);
+    list.addBoolean(false);
+    
+    assertEquals(false, (boolean) list.set(0, true));
+    assertEquals(true, list.getBoolean(0));
+
+    assertEquals(false, (boolean) list.set(1, false));
+    assertEquals(false, list.getBoolean(1));
+    
+    try {
+      list.set(-1, true);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, false);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addBoolean(true);
+    list.addBoolean(true);
+    
+    assertEquals(true, list.setBoolean(0, false));
+    assertEquals(false, list.getBoolean(0));
+
+    assertEquals(true, list.setBoolean(1, false));
+    assertEquals(false, list.getBoolean(1));
+    
+    try {
+      list.setBoolean(-1, false);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setBoolean(2, true);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(true));
+    assertEquals(asList(true), list);
+
+    assertTrue(list.add(false));
+    list.add(0, false);
+    assertEquals(asList(false, true, false), list);
+    
+    list.add(0, false);
+    list.add(0, true);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(true);
+    }
+    assertEquals(asList(true, false, false, true, false, true, true, true, true, true, true), list);
+    
+    try {
+      list.add(-1, false);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, true);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addBoolean(true);
+    assertEquals(asList(true), list);
+
+    list.addBoolean(false);
+    assertEquals(asList(true, false), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(false)));
+    assertEquals(1, list.size());
+    assertEquals(false, (boolean) list.get(0));
+    assertEquals(false, list.getBoolean(0));
+    
+    assertTrue(list.addAll(asList(true, false, false, false, true)));
+    assertEquals(asList(false, true, false, false, false, true), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(false, true, false, false, false, true, true, true, false), list);
+
+    assertFalse(list.addAll(Collections.<Boolean>emptyList()));
+    assertFalse(list.addAll(BooleanArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(true, (boolean) list.remove(0));
+    assertEquals(asList(true, false), list);
+
+    assertTrue(list.remove(Boolean.TRUE));
+    assertEquals(asList(false), list);
+
+    assertFalse(list.remove(Boolean.TRUE));
+    assertEquals(asList(false), list);
+
+    assertEquals(false, (boolean) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(BooleanArrayList list) {
+    try {
+      list.add(false);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(false));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new BooleanArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(true));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addBoolean(true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(Boolean.TRUE));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(Boolean.TRUE));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setBoolean(0, false);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static BooleanArrayList newImmutableBooleanArrayList(boolean... elements) {
+    BooleanArrayList list = new BooleanArrayList();
+    for (boolean element : elements) {
+      list.addBoolean(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
new file mode 100644
index 0000000..db10ee7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -0,0 +1,100 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
+ * by inheriting the tests from {@link LiteralByteStringTest}.  The only method which
+ * is strange enough that it needs to be overridden here is {@link #testToString()}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class BoundedByteStringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "BoundedByteString";
+    byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
+    int from = 100;
+    int to = sourceBytes.length - 100;
+    stringUnderTest = ByteString.copyFrom(sourceBytes).substring(from, to);
+    referenceBytes = new byte[to - from];
+    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+    expectedHashCode = 727575887;
+  }
+
+  @Override
+  public void testToString() throws UnsupportedEncodingException {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
+    ByteString chopped = unicode.substring(2, unicode.size() - 6);
+    assertEquals(classUnderTest + ".substring() must have the expected type",
+        classUnderTest, getActualClassName(chopped));
+
+    String roundTripString = chopped.toString(UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString.substring(2, testString.length() - 6), roundTripString);
+  }
+
+  @Override
+  public void testCharsetToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
+    ByteString chopped = unicode.substring(2, unicode.size() - 6);
+    assertEquals(classUnderTest + ".substring() must have the expected type",
+        classUnderTest, getActualClassName(chopped));
+
+    String roundTripString = chopped.toString(Internal.UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString.substring(2, testString.length() - 6), roundTripString);
+  }
+
+  @Override
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(stringUnderTest);
+    oos.close();
+    byte[] pickled = out.toByteArray();
+    InputStream in = new ByteArrayInputStream(pickled);
+    ObjectInputStream ois = new ObjectInputStream(in);
+    Object o = ois.readObject();
+    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
new file mode 100644
index 0000000..cbe742e
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java
@@ -0,0 +1,81 @@
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Tests for {@link ByteBufferWriter}.
+ */
+public class ByteBufferWriterTest extends TestCase {
+
+  public void testHeapBuffer() throws IOException {
+    // Test a small and large buffer.
+    testWrite(ByteBuffer.allocate(100));
+    testWrite(ByteBuffer.allocate(1024 * 100));
+  }
+
+  public void testDirectBuffer() throws IOException {
+    // Test a small and large buffer.
+    testWrite(ByteBuffer.allocateDirect(100));
+    testWrite(ByteBuffer.allocateDirect(1024 * 100));
+  }
+
+  private void testWrite(ByteBuffer buffer) throws IOException {
+    fillRandom(buffer);
+    ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.remaining());
+    ByteBufferWriter.write(buffer, os);
+    assertEquals(0, buffer.position());
+    assertTrue(Arrays.equals(toArray(buffer), os.toByteArray()));
+  }
+
+  private void fillRandom(ByteBuffer buf) {
+    byte[] bytes = new byte[buf.remaining()];
+    new Random().nextBytes(bytes);
+    buf.put(bytes);
+    buf.flip();
+    return;
+  }
+
+  private byte[] toArray(ByteBuffer buf) {
+    int originalPosition = buf.position();
+    byte[] bytes = new byte[buf.remaining()];
+    buf.get(bytes);
+    buf.position(originalPosition);
+    return bytes;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
new file mode 100644
index 0000000..ad9f266
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -0,0 +1,774 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.ByteString.Output;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+ * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
+ * tests.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class ByteStringTest extends TestCase {
+
+  private static final Charset UTF_16 = Charset.forName("UTF-16");
+
+  static byte[] getTestBytes(int size, long seed) {
+    Random random = new Random(seed);
+    byte[] result = new byte[size];
+    random.nextBytes(result);
+    return result;
+  }
+
+  private byte[] getTestBytes(int size) {
+    return getTestBytes(size, 445566L);
+  }
+
+  private byte[] getTestBytes() {
+    return getTestBytes(1000);
+  }
+
+  // Compare the entire left array with a subset of the right array.
+  private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
+    boolean stillEqual = (left.length == length);
+    for (int i = 0; (stillEqual && i < length); ++i) {
+      stillEqual = (left[i] == right[rightOffset + i]);
+    }
+    return stillEqual;
+  }
+
+  // Returns true only if the given two arrays have identical contents.
+  private boolean isArray(byte[] left, byte[] right) {
+    return left.length == right.length && isArrayRange(left, right, 0, left.length);
+  }
+
+  public void testSubstring_BeginIndex() {
+    byte[] bytes = getTestBytes();
+    ByteString substring = ByteString.copyFrom(bytes).substring(500);
+    assertTrue("substring must contain the tail of the string",
+        isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
+  }
+
+  public void testCopyFrom_BytesOffsetSize() {
+    byte[] bytes = getTestBytes();
+    ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
+    assertTrue("copyFrom sub-range must contain the expected bytes",
+        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+  }
+
+  public void testCopyFrom_Bytes() {
+    byte[] bytes = getTestBytes();
+    ByteString byteString = ByteString.copyFrom(bytes);
+    assertTrue("copyFrom must contain the expected bytes",
+        isArray(byteString.toByteArray(), bytes));
+  }
+
+  public void testCopyFrom_ByteBufferSize() {
+    byte[] bytes = getTestBytes();
+    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
+    byteBuffer.put(bytes);
+    byteBuffer.position(500);
+    ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
+    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
+  }
+
+  public void testCopyFrom_ByteBuffer() {
+    byte[] bytes = getTestBytes();
+    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
+    byteBuffer.put(bytes);
+    byteBuffer.position(500);
+    ByteString byteString = ByteString.copyFrom(byteBuffer);
+    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+        isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
+  }
+
+  public void testCopyFrom_StringEncoding() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString byteString = ByteString.copyFrom(testString, UTF_16);
+    byte[] testBytes = testString.getBytes(UTF_16);
+    assertTrue("copyFrom string must respect the charset",
+        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+  }
+
+  public void testCopyFrom_Utf8() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString byteString = ByteString.copyFromUtf8(testString);
+    byte[] testBytes = testString.getBytes(Internal.UTF_8);
+    assertTrue("copyFromUtf8 string must respect the charset",
+        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+  }
+
+  public void testCopyFrom_Iterable() {
+    byte[] testBytes = getTestBytes(77777, 113344L);
+    final List<ByteString> pieces = makeConcretePieces(testBytes);
+    // Call copyFrom() on a Collection
+    ByteString byteString = ByteString.copyFrom(pieces);
+    assertTrue("copyFrom a List must contain the expected bytes",
+        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
+    // Call copyFrom on an iteration that's not a collection
+    ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
+      @Override
+      public Iterator<ByteString> iterator() {
+        return pieces.iterator();
+      }
+    });
+    assertEquals("copyFrom from an Iteration must contain the expected bytes",
+        byteString, byteStringAlt);
+  }
+
+  public void testCopyTo_TargetOffset() {
+    byte[] bytes = getTestBytes();
+    ByteString byteString = ByteString.copyFrom(bytes);
+    byte[] target = new byte[bytes.length + 1000];
+    byteString.copyTo(target, 400);
+    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
+        isArrayRange(bytes, target, 400, bytes.length));
+  }
+
+  public void testReadFrom_emptyStream() throws IOException {
+    ByteString byteString =
+        ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
+    assertSame("reading an empty stream must result in the EMPTY constant "
+        + "byte string", ByteString.EMPTY, byteString);
+  }
+
+  public void testReadFrom_smallStream() throws IOException {
+    assertReadFrom(getTestBytes(10));
+  }
+
+  public void testReadFrom_mutating() throws IOException {
+    byte[] capturedArray = null;
+    EvilInputStream eis = new EvilInputStream();
+    ByteString byteString = ByteString.readFrom(eis);
+
+    capturedArray = eis.capturedArray;
+    byte[] originalValue = byteString.toByteArray();
+    for (int x = 0; x < capturedArray.length; ++x) {
+      capturedArray[x] = (byte) 0;
+    }
+
+    byte[] newValue = byteString.toByteArray();
+    assertTrue("copyFrom byteBuffer must not grant access to underlying array",
+        Arrays.equals(originalValue, newValue));
+  }
+
+  // Tests sizes that are near the rope copy-out threshold.
+  public void testReadFrom_mediumStream() throws IOException {
+    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
+    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
+    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1));
+    assertReadFrom(getTestBytes(200));
+  }
+
+  // Tests sizes that are over multi-segment rope threshold.
+  public void testReadFrom_largeStream() throws IOException {
+    assertReadFrom(getTestBytes(0x100));
+    assertReadFrom(getTestBytes(0x101));
+    assertReadFrom(getTestBytes(0x110));
+    assertReadFrom(getTestBytes(0x1000));
+    assertReadFrom(getTestBytes(0x1001));
+    assertReadFrom(getTestBytes(0x1010));
+    assertReadFrom(getTestBytes(0x10000));
+    assertReadFrom(getTestBytes(0x10001));
+    assertReadFrom(getTestBytes(0x10010));
+  }
+
+  // Tests sizes that are near the read buffer size.
+  public void testReadFrom_byteBoundaries() throws IOException {
+    final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
+    final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
+
+    assertReadFrom(getTestBytes(min - 1));
+    assertReadFrom(getTestBytes(min));
+    assertReadFrom(getTestBytes(min + 1));
+
+    assertReadFrom(getTestBytes(min * 2 - 1));
+    assertReadFrom(getTestBytes(min * 2));
+    assertReadFrom(getTestBytes(min * 2 + 1));
+
+    assertReadFrom(getTestBytes(min * 4 - 1));
+    assertReadFrom(getTestBytes(min * 4));
+    assertReadFrom(getTestBytes(min * 4 + 1));
+
+    assertReadFrom(getTestBytes(min * 8 - 1));
+    assertReadFrom(getTestBytes(min * 8));
+    assertReadFrom(getTestBytes(min * 8 + 1));
+
+    assertReadFrom(getTestBytes(max - 1));
+    assertReadFrom(getTestBytes(max));
+    assertReadFrom(getTestBytes(max + 1));
+
+    assertReadFrom(getTestBytes(max * 2 - 1));
+    assertReadFrom(getTestBytes(max * 2));
+    assertReadFrom(getTestBytes(max * 2 + 1));
+  }
+
+  // Tests that IOExceptions propagate through ByteString.readFrom().
+  public void testReadFrom_IOExceptions() {
+    try {
+      ByteString.readFrom(new FailStream());
+      fail("readFrom must throw the underlying IOException");
+
+    } catch (IOException e) {
+      assertEquals("readFrom must throw the expected exception",
+                   "synthetic failure", e.getMessage());
+    }
+  }
+
+  // Tests that ByteString.readFrom works with streams that don't
+  // always fill their buffers.
+  public void testReadFrom_reluctantStream() throws IOException {
+    final byte[] data = getTestBytes(0x1000);
+
+    ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
+    assertTrue("readFrom byte stream must contain the expected bytes",
+        isArray(byteString.toByteArray(), data));
+
+    // Same test as above, but with some specific chunk sizes.
+    assertReadFromReluctantStream(data, 100);
+    assertReadFromReluctantStream(data, 248);
+    assertReadFromReluctantStream(data, 249);
+    assertReadFromReluctantStream(data, 250);
+    assertReadFromReluctantStream(data, 251);
+    assertReadFromReluctantStream(data, 0x1000);
+    assertReadFromReluctantStream(data, 0x1001);
+  }
+
+  // Fails unless ByteString.readFrom reads the bytes correctly from a
+  // reluctant stream with the given chunkSize parameter.
+  private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
+      throws IOException {
+    ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
+    assertTrue("readFrom byte stream must contain the expected bytes",
+        isArray(b.toByteArray(), bytes));
+  }
+
+  // Tests that ByteString.readFrom works with streams that implement
+  // available().
+  public void testReadFrom_available() throws IOException {
+    final byte[] data = getTestBytes(0x1001);
+
+    ByteString byteString = ByteString.readFrom(new AvailableStream(data));
+    assertTrue("readFrom byte stream must contain the expected bytes",
+        isArray(byteString.toByteArray(), data));
+  }
+
+  // Fails unless ByteString.readFrom reads the bytes correctly.
+  private void assertReadFrom(byte[] bytes) throws IOException {
+    ByteString byteString =
+        ByteString.readFrom(new ByteArrayInputStream(bytes));
+    assertTrue("readFrom byte stream must contain the expected bytes",
+        isArray(byteString.toByteArray(), bytes));
+  }
+
+  // A stream that fails when read.
+  private static final class FailStream extends InputStream {
+    @Override public int read() throws IOException {
+      throw new IOException("synthetic failure");
+    }
+  }
+
+  // A stream that simulates blocking by only producing 250 characters
+  // per call to read(byte[]).
+  private static class ReluctantStream extends InputStream {
+    protected final byte[] data;
+    protected int pos = 0;
+
+    public ReluctantStream(byte[] data) {
+      this.data = data;
+    }
+
+    @Override public int read() {
+      if (pos == data.length) {
+        return -1;
+      } else {
+        return data[pos++];
+      }
+    }
+
+    @Override public int read(byte[] buf) {
+      return read(buf, 0, buf.length);
+    }
+
+    @Override public int read(byte[] buf, int offset, int size) {
+      if (pos == data.length) {
+        return -1;
+      }
+      int count = Math.min(Math.min(size, data.length - pos), 250);
+      System.arraycopy(data, pos, buf, offset, count);
+      pos += count;
+      return count;
+    }
+  }
+
+  // Same as above, but also implements available().
+  private static final class AvailableStream extends ReluctantStream {
+    public AvailableStream(byte[] data) {
+      super(data);
+    }
+
+    @Override public int available() {
+      return Math.min(250, data.length - pos);
+    }
+  }
+
+  // A stream which exposes the byte array passed into read(byte[], int, int).
+  private static class EvilInputStream extends InputStream {
+    public byte[] capturedArray = null;
+
+    @Override
+    public int read(byte[] buf, int off, int len) {
+      if (capturedArray != null) {
+        return -1;
+      } else {
+        capturedArray = buf;
+        for (int x = 0; x < len; ++x) {
+          buf[x] = (byte) x;
+        }
+        return len;
+      }
+    }
+
+    @Override
+    public int read() {
+      // Purposefully do nothing.
+      return -1;
+    }
+  }
+
+  // A stream which exposes the byte array passed into write(byte[], int, int).
+  private static class EvilOutputStream extends OutputStream {
+    public byte[] capturedArray = null;
+
+    @Override
+    public void write(byte[] buf, int off, int len) {
+      if (capturedArray == null) {
+        capturedArray = buf;
+      }
+    }
+
+    @Override
+    public void write(int ignored) {
+      // Purposefully do nothing.
+    }
+  }
+
+  public void testToStringUtf8() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    byte[] testBytes = testString.getBytes(Internal.UTF_8);
+    ByteString byteString = ByteString.copyFrom(testBytes);
+    assertEquals("copyToStringUtf8 must respect the charset",
+        testString, byteString.toStringUtf8());
+  }
+
+  public void testNewOutput_InitialCapacity() throws IOException {
+    byte[] bytes = getTestBytes();
+    ByteString.Output output = ByteString.newOutput(bytes.length + 100);
+    output.write(bytes);
+    ByteString byteString = output.toByteString();
+    assertTrue(
+        "String built from newOutput(int) must contain the expected bytes",
+        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+  }
+
+  // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
+  // write sizes
+  public void testNewOutput_ArrayWrite() {
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
+                         2 * length, 3 * length};
+    int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
+
+    for (int bufferSize : bufferSizes) {
+      for (int writeSize : writeSizes) {
+        // Test writing the entire output writeSize bytes at a time.
+        ByteString.Output output = ByteString.newOutput(bufferSize);
+        for (int i = 0; i < length; i += writeSize) {
+          output.write(bytes, i, Math.min(writeSize, length - i));
+        }
+        ByteString byteString = output.toByteString();
+        assertTrue("String built from newOutput() must contain the expected bytes",
+            isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+      }
+    }
+  }
+
+  // Test newOutput() using a variety of buffer sizes, but writing all the
+  // characters using write(byte);
+  public void testNewOutput_WriteChar() {
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {0, 1, 128, 256, length / 2,
+                         length - 1, length, length + 1,
+                         2 * length, 3 * length};
+    for (int bufferSize : bufferSizes) {
+      ByteString.Output output = ByteString.newOutput(bufferSize);
+      for (byte byteValue : bytes) {
+        output.write(byteValue);
+      }
+      ByteString byteString = output.toByteString();
+      assertTrue("String built from newOutput() must contain the expected bytes",
+          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    }
+  }
+
+  // Test newOutput() in which we write the bytes using a variety of methods
+  // and sizes, and in which we repeatedly call toByteString() in the middle.
+  public void testNewOutput_Mixed() {
+    Random rng = new Random(1);
+    byte[] bytes = getTestBytes();
+    int length = bytes.length;
+    int[] bufferSizes = {0, 1, 128, 256, length / 2,
+                         length - 1, length, length + 1,
+                         2 * length, 3 * length};
+
+    for (int bufferSize : bufferSizes) {
+      // Test writing the entire output using a mixture of write sizes and
+      // methods;
+      ByteString.Output output = ByteString.newOutput(bufferSize);
+      int position = 0;
+      while (position < bytes.length) {
+        if (rng.nextBoolean()) {
+          int count = 1 + rng.nextInt(bytes.length - position);
+          output.write(bytes, position, count);
+          position += count;
+        } else {
+          output.write(bytes[position]);
+          position++;
+        }
+        assertEquals("size() returns the right value", position, output.size());
+        assertTrue("newOutput() substring must have correct bytes",
+            isArrayRange(output.toByteString().toByteArray(),
+                bytes, 0, position));
+      }
+      ByteString byteString = output.toByteString();
+      assertTrue("String built from newOutput() must contain the expected bytes",
+          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+    }
+  }
+
+  public void testNewOutputEmpty() {
+    // Make sure newOutput() correctly builds empty byte strings
+    ByteString byteString = ByteString.newOutput().toByteString();
+    assertEquals(ByteString.EMPTY, byteString);
+  }
+
+  public void testNewOutput_Mutating() throws IOException {
+    Output os = ByteString.newOutput(5);
+    os.write(new byte[] {1, 2, 3, 4, 5});
+    EvilOutputStream eos = new EvilOutputStream();
+    os.writeTo(eos);
+    byte[] capturedArray = eos.capturedArray;
+    ByteString byteString = os.toByteString();
+    byte[] oldValue = byteString.toByteArray();
+    Arrays.fill(capturedArray, (byte) 0);
+    byte[] newValue = byteString.toByteArray();
+    assertTrue("Output must not provide access to the underlying byte array",
+        Arrays.equals(oldValue, newValue));
+  }
+
+  public void testNewCodedBuilder() throws IOException {
+    byte[] bytes = getTestBytes();
+    ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
+    builder.getCodedOutput().writeRawBytes(bytes);
+    ByteString byteString = builder.build();
+    assertTrue("String built from newCodedBuilder() must contain the expected bytes",
+        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
+  }
+
+  public void testSubstringParity() {
+    byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
+    int start = 512 * 1024 - 3333;
+    int end   = 512 * 1024 + 7777;
+    ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
+    boolean ok = true;
+    for (int i = start; ok && i < end; ++i) {
+      ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
+    }
+    assertTrue("Concrete substring didn't capture the right bytes", ok);
+
+    ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
+    assertTrue("Substring must be equal to literal string",
+        concreteSubstring.equals(literalString));
+    assertEquals("Substring must have same hashcode as literal string",
+        literalString.hashCode(), concreteSubstring.hashCode());
+  }
+
+  public void testCompositeSubstring() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+    ByteString listString = ByteString.copyFrom(pieces);
+
+    int from = 1000;
+    int to = 40000;
+    ByteString compositeSubstring = listString.substring(from, to);
+    byte[] substringBytes = compositeSubstring.toByteArray();
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < to - from; ++i) {
+      stillEqual = referenceBytes[from + i] == substringBytes[i];
+    }
+    assertTrue("Substring must return correct bytes", stillEqual);
+
+    stillEqual = true;
+    for (int i = 0; stillEqual && i < to - from; ++i) {
+      stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
+    }
+    assertTrue("Substring must support byteAt() correctly", stillEqual);
+
+    ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
+    assertTrue("Composite substring must equal a literal substring over the same bytes",
+        compositeSubstring.equals(literalSubstring));
+    assertTrue("Literal substring must equal a composite substring over the same bytes",
+        literalSubstring.equals(compositeSubstring));
+
+    assertEquals("We must get the same hashcodes for composite and literal substrings",
+        literalSubstring.hashCode(), compositeSubstring.hashCode());
+
+    assertFalse("We can't be equal to a proper substring",
+        compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
+  }
+
+  public void testCopyFromList() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+    ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+    ByteString listString = ByteString.copyFrom(pieces);
+
+    assertTrue("Composite string must be equal to literal string",
+        listString.equals(literalString));
+    assertEquals("Composite string must have same hashcode as literal string",
+        literalString.hashCode(), listString.hashCode());
+  }
+
+  public void testConcat() {
+    byte[] referenceBytes = getTestBytes(77748, 113344L);
+    ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+    List<ByteString> pieces = makeConcretePieces(referenceBytes);
+
+    Iterator<ByteString> iter = pieces.iterator();
+    ByteString concatenatedString = iter.next();
+    while (iter.hasNext()) {
+      concatenatedString = concatenatedString.concat(iter.next());
+    }
+
+    assertTrue("Concatenated string must be equal to literal string",
+        concatenatedString.equals(literalString));
+    assertEquals("Concatenated string must have same hashcode as literal string",
+        literalString.hashCode(), concatenatedString.hashCode());
+  }
+
+  /**
+   * Test the Rope implementation can deal with Empty nodes, even though we
+   * guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
+   */
+  public void testConcat_empty() {
+    byte[] referenceBytes = getTestBytes(7748, 113344L);
+    ByteString literalString = ByteString.copyFrom(referenceBytes);
+
+    ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
+    ByteString temp = RopeByteString.newInstanceForTest(
+        RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
+    ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
+
+    assertTrue("String with concatenated nulls must equal simple concatenate",
+        duo.equals(quintet));
+    assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
+        duo.hashCode(), quintet.hashCode());
+
+    ByteString.ByteIterator duoIter = duo.iterator();
+    ByteString.ByteIterator quintetIter = quintet.iterator();
+    boolean stillEqual = true;
+    while (stillEqual && quintetIter.hasNext()) {
+      stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
+    }
+    assertTrue("We must get the same characters by iterating", stillEqual);
+    assertFalse("Iterator must be exhausted", duoIter.hasNext());
+    try {
+      duoIter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+    try {
+      quintetIter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+
+    // Test that even if we force empty strings in as rope leaves in this
+    // configuration, we always get a (possibly Bounded) LiteralByteString
+    // for a length 1 substring.
+    //
+    // It is possible, using the testing factory method to create deeply nested
+    // trees of empty leaves, to make a string that will fail this test.
+    for (int i = 1; i < duo.size(); ++i) {
+      assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
+          duo.substring(i - 1, i) instanceof ByteString.LeafByteString);
+    }
+    for (int i = 1; i < quintet.size(); ++i) {
+      assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
+          quintet.substring(i - 1, i) instanceof ByteString.LeafByteString);
+    }
+  }
+
+  public void testStartsWith() {
+    byte[] bytes = getTestBytes(1000, 1234L);
+    ByteString string = ByteString.copyFrom(bytes);
+    ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
+    ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
+    assertTrue(string.startsWith(ByteString.EMPTY));
+    assertTrue(string.startsWith(string));
+    assertTrue(string.startsWith(prefix));
+    assertFalse(string.startsWith(suffix));
+    assertFalse(prefix.startsWith(suffix));
+    assertFalse(suffix.startsWith(prefix));
+    assertFalse(ByteString.EMPTY.startsWith(prefix));
+    assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
+  }
+
+  public void testEndsWith() {
+    byte[] bytes = getTestBytes(1000, 1234L);
+    ByteString string = ByteString.copyFrom(bytes);
+    ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
+    ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
+    assertTrue(string.endsWith(ByteString.EMPTY));
+    assertTrue(string.endsWith(string));
+    assertTrue(string.endsWith(suffix));
+    assertFalse(string.endsWith(prefix));
+    assertFalse(suffix.endsWith(prefix));
+    assertFalse(prefix.endsWith(suffix));
+    assertFalse(ByteString.EMPTY.endsWith(suffix));
+    assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY));
+  }
+
+  static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
+    List<ByteString> pieces = new ArrayList<ByteString>();
+    // Starting length should be small enough that we'll do some concatenating by
+    // copying if we just concatenate all these pieces together.
+    for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
+      length = (length << 1) - 1;
+      if (start + length > referenceBytes.length) {
+        length = referenceBytes.length - start;
+      }
+      pieces.add(ByteString.copyFrom(referenceBytes, start, length));
+    }
+    return pieces;
+  }
+
+  private byte[] substringUsingWriteTo(
+      ByteString data, int offset, int length) throws IOException {
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    data.writeTo(output, offset, length);
+    return output.toByteArray();
+  }
+
+  public void testWriteToOutputStream() throws Exception {
+    // Choose a size large enough so when two ByteStrings are concatenated they
+    // won't be merged into one byte array due to some optimizations.
+    final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1;
+    byte[] data1 = new byte[dataSize];
+    for (int i = 0; i < data1.length; i++) {
+      data1[i] = (byte) 1;
+    }
+    data1[1] = (byte) 11;
+    // Test LiteralByteString.writeTo(OutputStream,int,int)
+    ByteString left = ByteString.wrap(data1);
+    byte[] result = substringUsingWriteTo(left, 1, 1);
+    assertEquals(1, result.length);
+    assertEquals((byte) 11, result[0]);
+
+    byte[] data2 = new byte[dataSize];
+    for (int i = 0; i < data1.length; i++) {
+      data2[i] = (byte) 2;
+    }
+    ByteString right = ByteString.wrap(data2);
+    // Concatenate two ByteStrings to create a RopeByteString.
+    ByteString root = left.concat(right);
+    // Make sure we are actually testing a RopeByteString with a simple tree
+    // structure.
+    assertEquals(1, root.getTreeDepth());
+    // Write parts of the left node.
+    result = substringUsingWriteTo(root, 0, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 1, result[0]);
+    assertEquals((byte) 1, result[dataSize - 1]);
+    // Write parts of the right node.
+    result = substringUsingWriteTo(root, dataSize, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 2, result[0]);
+    assertEquals((byte) 2, result[dataSize - 1]);
+    // Write a segment of bytes that runs across both nodes.
+    result = substringUsingWriteTo(root, dataSize / 2, dataSize);
+    assertEquals(dataSize, result.length);
+    assertEquals((byte) 1, result[0]);
+    assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]);
+    assertEquals((byte) 2, result[dataSize - dataSize / 2]);
+    assertEquals((byte) 2, result[dataSize - 1]);
+  }
+  
+  /**
+   * Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
+   */
+  public void testByteArrayCopier() throws Exception {
+    Field field = ByteString.class.getDeclaredField("byteArrayCopier");
+    field.setAccessible(true);
+    Object byteArrayCopier = field.get(null);
+    assertNotNull(byteArrayCopier);
+    assertTrue(
+        byteArrayCopier.toString(),
+        byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier"));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
new file mode 100644
index 0000000..cc65d19
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
@@ -0,0 +1,141 @@
+// 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.
+
+package com.google.protobuf;
+
+import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
+import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
+import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
+
+import junit.framework.TestCase;
+
+/**
+ * Test that protos generated with file option java_string_check_utf8 do in
+ * fact perform appropriate UTF-8 checks.
+ *
+ * @author jbaum@google.com (Jacob Butcher)
+ */
+public class CheckUtf8Test extends TestCase {
+
+  private static final String UTF8_BYTE_STRING_TEXT = "some text";
+  private static final ByteString UTF8_BYTE_STRING =
+      ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
+  private static final ByteString NON_UTF8_BYTE_STRING =
+      ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
+
+  public void testBuildRequiredStringWithGoodUtf8() throws Exception {
+    assertEquals(UTF8_BYTE_STRING_TEXT,
+                 StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
+  }
+
+  public void testParseRequiredStringWithGoodUtf8() throws Exception {
+    ByteString serialized =
+        BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
+    assertEquals(UTF8_BYTE_STRING_TEXT, StringWrapper.parser().parseFrom(serialized).getReq());
+  }
+
+  public void testBuildRequiredStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildOptionalStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRepeatedStringWithBadUtf8() throws Exception {
+    try {
+      StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testParseRequiredStringWithBadUtf8() throws Exception {
+    ByteString serialized =
+        BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+    try {
+      StringWrapper.parser().parseFrom(serialized);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildOptionalStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testBuildRepeatedStringWithBadUtf8Size() throws Exception {
+    try {
+      StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
+      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
+    } catch (IllegalArgumentException exception) {
+      assertEquals("Byte string is not UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testParseRequiredStringWithBadUtf8Size() throws Exception {
+    ByteString serialized =
+        BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
+    try {
+      StringWrapperSize.parser().parseFrom(serialized);
+      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
+}
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
new file mode 100644
index 0000000..ca940ce
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -0,0 +1,821 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.BoolMessage;
+import protobuf_unittest.UnittestProto.Int32Message;
+import protobuf_unittest.UnittestProto.Int64Message;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRecursiveMessage;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Unit test for {@link CodedInputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedInputStreamTest extends TestCase {
+  /**
+   * Helper to construct a byte array from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private byte[] bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return bytes;
+  }
+
+  /**
+   * An InputStream which limits the number of bytes it reads at a time.
+   * We use this to make sure that CodedInputStream doesn't screw up when
+   * reading in small blocks.
+   */
+  private static final class SmallBlockInputStream extends FilterInputStream {
+    private final int blockSize;
+
+    public SmallBlockInputStream(byte[] data, int blockSize) {
+      this(new ByteArrayInputStream(data), blockSize);
+    }
+
+    public SmallBlockInputStream(InputStream in, int blockSize) {
+      super(in);
+      this.blockSize = blockSize;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+      return super.read(b, 0, Math.min(b.length, blockSize));
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+      return super.read(b, off, Math.min(len, blockSize));
+    }
+  }
+
+  private void assertDataConsumed(byte[] data, CodedInputStream input)
+      throws IOException {
+    assertEquals(data.length, input.getTotalBytesRead());
+    assertTrue(input.isAtEnd());
+  }
+
+  /**
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+   * checks that the result matches the given value.
+   */
+  private void assertReadVarint(byte[] data, long value) throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals((int) value, input.readRawVarint32());
+    assertDataConsumed(data, input);
+
+    input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawVarint64());
+    assertDataConsumed(data, input);
+
+    input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawVarint64SlowPath());
+    assertDataConsumed(data, input);
+
+    input = CodedInputStream.newInstance(data);
+    assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+    assertDataConsumed(data, input);
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals((int) value, input.readRawVarint32());
+      assertDataConsumed(data, input);
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawVarint64());
+      assertDataConsumed(data, input);
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawVarint64SlowPath());
+      assertDataConsumed(data, input);
+
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
+      assertDataConsumed(data, input);
+    }
+
+    // Try reading direct from an InputStream.  We want to verify that it
+    // doesn't read past the end of the input, so we copy to a new, bigger
+    // array first.
+    byte[] longerData = new byte[data.length + 1];
+    System.arraycopy(data, 0, longerData, 0, data.length);
+    InputStream rawInput = new ByteArrayInputStream(longerData);
+    assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
+    assertEquals(1, rawInput.available());
+  }
+
+  /**
+   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+   * expects them to fail with an InvalidProtocolBufferException whose
+   * description matches the given one.
+   */
+  private void assertReadVarintFailure(
+      InvalidProtocolBufferException expected, byte[] data)
+      throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint32();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+
+    input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint64();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+
+    input = CodedInputStream.newInstance(data);
+    try {
+      input.readRawVarint64SlowPath();
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+
+    // Make sure we get the same error when reading direct from an InputStream.
+    try {
+      CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(expected.getMessage(), e.getMessage());
+    }
+  }
+
+  /** Tests readRawVarint32() and readRawVarint64(). */
+  public void testReadVarint() throws Exception {
+    assertReadVarint(bytes(0x00), 0);
+    assertReadVarint(bytes(0x01), 1);
+    assertReadVarint(bytes(0x7f), 127);
+    // 14882
+    assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+    // 2961488830
+    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x0bL << 28));
+
+    // 64-bit
+    // 7256456126
+    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+      (0x1bL << 28));
+    // 41256202580718336
+    assertReadVarint(
+      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+    // 11964378330978735131
+    assertReadVarint(
+      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+
+    // Failures
+    assertReadVarintFailure(
+      InvalidProtocolBufferException.malformedVarint(),
+      bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+            0x00));
+    assertReadVarintFailure(
+      InvalidProtocolBufferException.truncatedMessage(),
+      bytes(0x80));
+  }
+
+  /**
+   * Parses the given bytes using readRawLittleEndian32() and checks
+   * that the result matches the given value.
+   */
+  private void assertReadLittleEndian32(byte[] data, int value)
+                                        throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawLittleEndian32());
+    assertTrue(input.isAtEnd());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawLittleEndian32());
+      assertTrue(input.isAtEnd());
+    }
+  }
+
+  /**
+   * Parses the given bytes using readRawLittleEndian64() and checks
+   * that the result matches the given value.
+   */
+  private void assertReadLittleEndian64(byte[] data, long value)
+                                        throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(data);
+    assertEquals(value, input.readRawLittleEndian64());
+    assertTrue(input.isAtEnd());
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(data, blockSize));
+      assertEquals(value, input.readRawLittleEndian64());
+      assertTrue(input.isAtEnd());
+    }
+  }
+
+  /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
+  public void testReadLittleEndian() throws Exception {
+    assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+    assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+    assertReadLittleEndian64(
+      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+      0x123456789abcdef0L);
+    assertReadLittleEndian64(
+      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+      0x9abcdef012345678L);
+  }
+
+  /** Test decodeZigZag32() and decodeZigZag64(). */
+  public void testDecodeZigZag() throws Exception {
+    assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+    assertEquals(-1, CodedInputStream.decodeZigZag32(1));
+    assertEquals( 1, CodedInputStream.decodeZigZag32(2));
+    assertEquals(-2, CodedInputStream.decodeZigZag32(3));
+    assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
+    assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
+    assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
+    assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
+
+    assertEquals( 0, CodedInputStream.decodeZigZag64(0));
+    assertEquals(-1, CodedInputStream.decodeZigZag64(1));
+    assertEquals( 1, CodedInputStream.decodeZigZag64(2));
+    assertEquals(-2, CodedInputStream.decodeZigZag64(3));
+    assertEquals(0x000000003FFFFFFFL,
+                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
+    assertEquals(0xFFFFFFFFC0000000L,
+                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
+    assertEquals(0x000000007FFFFFFFL,
+                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
+    assertEquals(0xFFFFFFFF80000000L,
+                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
+    assertEquals(0x7FFFFFFFFFFFFFFFL,
+                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+    assertEquals(0x8000000000000000L,
+                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+  }
+
+  /** Tests reading and parsing a whole message with every field type. */
+  public void testReadWholeMessage() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    byte[] rawBytes = message.toByteArray();
+    assertEquals(rawBytes.length, message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+    TestUtil.assertAllFieldsSet(message2);
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+      message2 = TestAllTypes.parseFrom(
+        new SmallBlockInputStream(rawBytes, blockSize));
+      TestUtil.assertAllFieldsSet(message2);
+    }
+  }
+
+  /** Tests skipField(). */
+  public void testSkipWholeMessage() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+    byte[] rawBytes = message.toByteArray();
+
+    // Create two parallel inputs.  Parse one as unknown fields while using
+    // skipField() to skip each field on the other.  Expect the same tags.
+    CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
+    CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+    UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
+
+    while (true) {
+      int tag = input1.readTag();
+      assertEquals(tag, input2.readTag());
+      if (tag == 0) {
+        break;
+      }
+      unknownFields.mergeFieldFrom(tag, input1);
+      input2.skipField(tag);
+    }
+  }
+
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * exactly up to a limit, this should not break things.
+   */
+  public void testSkipRawBytesBug() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2 };
+    CodedInputStream input = CodedInputStream.newInstance(rawBytes);
+
+    int limit = input.pushLimit(1);
+    input.skipRawBytes(1);
+    input.popLimit(limit);
+    assertEquals(2, input.readRawByte());
+  }
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * past the end of a buffer with a limit that has been set past the end of
+   * that buffer, this should not break things.
+   */
+  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(rawBytes, 3));
+
+    int limit = input.pushLimit(4);
+    // In order to expose the bug we need to read at least one byte to prime the
+    // buffer inside the CodedInputStream.
+    assertEquals(1, input.readRawByte());
+    // Skip to the end of the limit.
+    input.skipRawBytes(3);
+    assertTrue(input.isAtEnd());
+    input.popLimit(limit);
+    assertEquals(5, input.readRawByte());
+  }
+
+  public void testReadHugeBlob() throws Exception {
+    // Allocate and initialize a 1MB blob.
+    byte[] blob = new byte[1 << 20];
+    for (int i = 0; i < blob.length; i++) {
+      blob[i] = (byte) i;
+    }
+
+    // Make a message containing it.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    builder.setOptionalBytes(ByteString.copyFrom(blob));
+    TestAllTypes message = builder.build();
+
+    // Serialize and parse it.  Make sure to parse from an InputStream, not
+    // directly from a ByteString, so that CodedInputStream uses buffered
+    // reading.
+    TestAllTypes message2 =
+      TestAllTypes.parseFrom(message.toByteString().newInput());
+
+    assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
+
+    // Make sure all the other fields were parsed correctly.
+    TestAllTypes message3 = TestAllTypes.newBuilder(message2)
+      .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+      .build();
+    TestUtil.assertAllFieldsSet(message3);
+  }
+
+  public void testReadMaliciouslyLargeBlob() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(0x7FFFFFFF);
+    output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+
+    try {
+      input.readBytes();
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException e) {
+      // success.
+    }
+  }
+
+  private TestRecursiveMessage makeRecursiveMessage(int depth) {
+    if (depth == 0) {
+      return TestRecursiveMessage.newBuilder().setI(5).build();
+    } else {
+      return TestRecursiveMessage.newBuilder()
+        .setA(makeRecursiveMessage(depth - 1)).build();
+    }
+  }
+
+  private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+    if (depth == 0) {
+      assertFalse(message.hasA());
+      assertEquals(5, message.getI());
+    } else {
+      assertTrue(message.hasA());
+      assertMessageDepth(message.getA(), depth - 1);
+    }
+  }
+
+  public void testMaliciousRecursion() throws Exception {
+    ByteString data100 = makeRecursiveMessage(100).toByteString();
+    ByteString data101 = makeRecursiveMessage(101).toByteString();
+
+    assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100);
+
+    try {
+      TestRecursiveMessage.parseFrom(data101);
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException e) {
+      // success.
+    }
+
+    CodedInputStream input = data100.newCodedInput();
+    input.setRecursionLimit(8);
+    try {
+      TestRecursiveMessage.parseFrom(input);
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException e) {
+      // success.
+    }
+  }
+
+  private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
+      assertEquals(
+          InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
+          e.getMessage());
+  }
+
+  public void testSizeLimit() throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(
+            TestUtil.getAllSet().toByteString().newInput(), 16));
+    input.setSizeLimit(16);
+
+    try {
+      TestAllTypes.parseFrom(input);
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
+    }
+  }
+
+  public void testResetSizeCounter() throws Exception {
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(new byte[256], 8));
+    input.setSizeLimit(16);
+    input.readRawBytes(16);
+    assertEquals(16, input.getTotalBytesRead());
+
+    try {
+      input.readRawByte();
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
+    }
+
+    input.resetSizeCounter();
+    assertEquals(0, input.getTotalBytesRead());
+    input.readRawByte();  // No exception thrown.
+    input.resetSizeCounter();
+    assertEquals(0, input.getTotalBytesRead());
+    input.readRawBytes(16);
+    assertEquals(16, input.getTotalBytesRead());
+    input.resetSizeCounter();
+
+    try {
+      input.readRawBytes(17);  // Hits limit again.
+      fail("Should have thrown an exception!");
+    } catch (InvalidProtocolBufferException expected) {
+      checkSizeLimitExceeded(expected);
+    }
+  }
+
+  public void testSizeLimitMultipleMessages() throws Exception {
+    byte[] bytes = new byte[256];
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] = (byte) i;
+    }
+    CodedInputStream input = CodedInputStream.newInstance(
+        new SmallBlockInputStream(bytes, 7));
+    input.setSizeLimit(16);
+    for (int i = 0; i < 256 / 16; i++) {
+      byte[] message = input.readRawBytes(16);
+      for (int j = 0; j < message.length; j++) {
+        assertEquals(i * 16 + j, message[j] & 0xff);
+      }
+      assertEquals(16, input.getTotalBytesRead());
+      input.resetSizeCounter();
+      assertEquals(0, input.getTotalBytesRead());
+    }
+  }
+
+  public void testReadString() throws Exception {
+    String lorem = "Lorem ipsum dolor sit amet ";
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < 4096; i += lorem.length()) {
+      builder.append(lorem);
+    }
+    lorem = builder.toString().substring(0, 4096);
+    byte[] bytes = lorem.getBytes("UTF-8");
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
+    assertEquals(tag, input.readTag());
+    String text = input.readString();
+    assertEquals(lorem, text);
+  }
+
+  public void testReadStringRequireUtf8() throws Exception {
+    String lorem = "Lorem ipsum dolor sit amet ";
+    StringBuilder builder = new StringBuilder();
+    for (int i = 0; i < 4096; i += lorem.length()) {
+      builder.append(lorem);
+    }
+    lorem = builder.toString().substring(0, 4096);
+    byte[] bytes = lorem.getBytes("UTF-8");
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(bytes.length);
+    output.writeRawBytes(bytes);
+    output.flush();
+
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
+    assertEquals(tag, input.readTag());
+    String text = input.readStringRequireUtf8();
+    assertEquals(lorem, text);
+  }
+
+  /**
+   * Tests that if we readString invalid UTF-8 bytes, no exception
+   * is thrown.  Instead, the invalid bytes are replaced with the Unicode
+   * "replacement character" U+FFFD.
+   */
+  public void testReadStringInvalidUtf8() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+    String text = input.readString();
+    assertEquals(0xfffd, text.charAt(0));
+  }
+
+  /**
+   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
+   * InvalidProtocolBufferException is thrown.
+   */
+  public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(tag);
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 0x80 });
+    output.flush();
+
+    CodedInputStream input = rawOutput.toByteString().newCodedInput();
+    assertEquals(tag, input.readTag());
+    try {
+      input.readStringRequireUtf8();
+      fail("Expected invalid UTF-8 exception.");
+    } catch (InvalidProtocolBufferException exception) {
+      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
+    }
+  }
+
+  public void testReadFromSlice() throws Exception {
+    byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
+    assertEquals(0, in.getTotalBytesRead());
+    for (int i = 3; i < 8; i++) {
+      assertEquals(i, in.readRawByte());
+      assertEquals(i - 2, in.getTotalBytesRead());
+    }
+    // eof
+    assertEquals(0, in.readTag());
+    assertEquals(5, in.getTotalBytesRead());
+  }
+
+  public void testInvalidTag() throws Exception {
+    // Any tag number which corresponds to field number zero is invalid and
+    // should throw InvalidProtocolBufferException.
+    for (int i = 0; i < 8; i++) {
+      try {
+        CodedInputStream.newInstance(bytes(i)).readTag();
+        fail("Should have thrown an exception.");
+      } catch (InvalidProtocolBufferException e) {
+        assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
+                     e.getMessage());
+      }
+    }
+  }
+
+  public void testReadByteArray() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 23 });
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[] { (byte) 45 });
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+
+    output.flush();
+    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+    byte[] result = inputStream.readByteArray();
+    assertEquals(0, result.length);
+    result = inputStream.readByteArray();
+    assertEquals(1, result.length);
+    assertEquals((byte) 23, result[0]);
+    result = inputStream.readByteArray();
+    assertEquals(1, result.length);
+    assertEquals((byte) 45, result[0]);
+    result = inputStream.readByteArray();
+    assertEquals(bytesLength, result.length);
+    assertEquals((byte) 67, result[0]);
+    assertEquals((byte) 89, result[bytesLength - 1]);
+  }
+
+  public void testReadByteBuffer() throws Exception {
+    ByteString.Output rawOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 23});
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 45});
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+
+    output.flush();
+    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
+
+    ByteBuffer result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+  }
+
+  public void testReadByteBufferAliasing() throws Exception {
+    ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
+    // Zero-sized bytes field.
+    output.writeRawVarint32(0);
+    // One one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 23});
+    // Another one-byte bytes field
+    output.writeRawVarint32(1);
+    output.writeRawBytes(new byte[]{(byte) 45});
+    // A bytes field large enough that won't fit into the 4K buffer.
+    final int bytesLength = 16 * 1024;
+    byte[] bytes = new byte[bytesLength];
+    bytes[0] = (byte) 67;
+    bytes[bytesLength - 1] = (byte) 89;
+    output.writeRawVarint32(bytesLength);
+    output.writeRawBytes(bytes);
+    output.flush();
+    byte[] data = byteArrayStream.toByteArray();
+
+    // Without aliasing
+    CodedInputStream inputStream = CodedInputStream.newInstance(data);
+    ByteBuffer result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() != data);
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+
+    // Enable aliasing
+    inputStream = CodedInputStream.newInstance(data);
+    inputStream.enableAliasing(true);
+    result = inputStream.readByteBuffer();
+    assertEquals(0, result.capacity());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 23, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(1, result.capacity());
+    assertEquals((byte) 45, result.get());
+    result = inputStream.readByteBuffer();
+    assertTrue(result.array() == data);
+    assertEquals(bytesLength, result.capacity());
+    assertEquals((byte) 67, result.get());
+    result.position(bytesLength - 1);
+    assertEquals((byte) 89, result.get());
+  }
+
+  public void testCompatibleTypes() throws Exception {
+    long data = 0x100000000L;
+    Int64Message message = Int64Message.newBuilder().setData(data).build();
+    ByteString serialized = message.toByteString();
+
+    // Test int64(long) is compatible with bool(boolean)
+    BoolMessage msg2 = BoolMessage.parseFrom(serialized);
+    assertTrue(msg2.getData());
+
+    // Test int64(long) is compatible with int32(int)
+    Int32Message msg3 = Int32Message.parseFrom(serialized);
+    assertEquals((int) data, msg3.getData());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
new file mode 100644
index 0000000..33aa435
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -0,0 +1,776 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
+import protobuf_unittest.UnittestProto.SparseEnumMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestSparseEnum;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for {@link CodedOutputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedOutputStreamTest extends TestCase {
+  private interface Coder {
+    CodedOutputStream stream();
+
+    byte[] toByteArray();
+
+    OutputType getOutputType();
+  }
+
+  private static final class OutputStreamCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final ByteArrayOutputStream output;
+
+    OutputStreamCoder(int size) {
+      output = new ByteArrayOutputStream();
+      stream = CodedOutputStream.newInstance(output, size);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      return output.toByteArray();
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.STREAM;
+    }
+  }
+
+  private static final class ArrayCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final byte[] bytes;
+
+    ArrayCoder(int size) {
+      bytes = new byte[size];
+      stream = CodedOutputStream.newInstance(bytes);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      return Arrays.copyOf(bytes, stream.getTotalBytesWritten());
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.ARRAY;
+    }
+  }
+
+  private static final class NioHeapCoder implements Coder {
+    private final CodedOutputStream stream;
+    private final ByteBuffer buffer;
+    private final int initialPosition;
+
+    NioHeapCoder(int size) {
+      this(size, 0);
+    }
+
+    NioHeapCoder(int size, int initialPosition) {
+      this.initialPosition = initialPosition;
+      buffer = ByteBuffer.allocate(size);
+      buffer.position(initialPosition);
+      stream = CodedOutputStream.newInstance(buffer);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      ByteBuffer dup = buffer.duplicate();
+      dup.position(initialPosition);
+      dup.limit(buffer.position());
+
+      byte[] bytes = new byte[dup.remaining()];
+      dup.get(bytes);
+      return bytes;
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.NIO_HEAP;
+    }
+  }
+
+  private static final class NioDirectCoder implements Coder {
+    private final int initialPosition;
+    private final CodedOutputStream stream;
+    private final ByteBuffer buffer;
+
+    NioDirectCoder(int size) {
+      this(size, 0);
+    }
+
+    NioDirectCoder(int size, int initialPosition) {
+      this.initialPosition = initialPosition;
+      buffer = ByteBuffer.allocateDirect(size);
+      buffer.position(initialPosition);
+      stream = CodedOutputStream.newInstance(buffer);
+    }
+
+    @Override
+    public CodedOutputStream stream() {
+      return stream;
+    }
+
+    @Override
+    public byte[] toByteArray() {
+      ByteBuffer dup = buffer.duplicate();
+      dup.position(initialPosition);
+      dup.limit(buffer.position());
+
+      byte[] bytes = new byte[dup.remaining()];
+      dup.get(bytes);
+      return bytes;
+    }
+
+    @Override
+    public OutputType getOutputType() {
+      return OutputType.NIO_DIRECT;
+    }
+  }
+
+  private enum OutputType {
+    ARRAY() {
+      @Override
+      Coder newCoder(int size) {
+        return new ArrayCoder(size);
+      }
+    },
+    NIO_HEAP() {
+      @Override
+      Coder newCoder(int size) {
+        return new NioHeapCoder(size);
+      }
+    },
+    NIO_DIRECT() {
+      @Override
+      Coder newCoder(int size) {
+        return new NioDirectCoder(size);
+      }
+    },
+    STREAM() {
+      @Override
+      Coder newCoder(int size) {
+        return new OutputStreamCoder(size);
+      }
+    };
+
+    abstract Coder newCoder(int size);
+  }
+
+  /** Checks that invariants are maintained for varint round trip input and output. */
+  public void testVarintRoundTrips() throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      assertVarintRoundTrip(outputType, 0L);
+      for (int bits = 0; bits < 64; bits++) {
+        long value = 1L << bits;
+        assertVarintRoundTrip(outputType, value);
+        assertVarintRoundTrip(outputType, value + 1);
+        assertVarintRoundTrip(outputType, value - 1);
+        assertVarintRoundTrip(outputType, -value);
+      }
+    }
+  }
+
+  /** Tests writeRawVarint32() and writeRawVarint64(). */
+  public void testWriteVarint() throws Exception {
+    assertWriteVarint(bytes(0x00), 0);
+    assertWriteVarint(bytes(0x01), 1);
+    assertWriteVarint(bytes(0x7f), 127);
+    // 14882
+    assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+    // 2961488830
+    assertWriteVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
+
+    // 64-bit
+    // 7256456126
+    assertWriteVarint(
+        bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+        (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
+    // 41256202580718336
+    assertWriteVarint(
+        bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+        (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35)
+        | (0x24L << 42) | (0x49L << 49));
+    // 11964378330978735131
+    assertWriteVarint(
+        bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+        (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35)
+        | (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+  }
+
+  /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
+  public void testWriteLittleEndian() throws Exception {
+    assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+    assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+    assertWriteLittleEndian64(
+        bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
+    assertWriteLittleEndian64(
+        bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
+  }
+
+  /** Test encodeZigZag32() and encodeZigZag64(). */
+  public void testEncodeZigZag() throws Exception {
+    assertEquals(0, CodedOutputStream.encodeZigZag32(0));
+    assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
+    assertEquals(2, CodedOutputStream.encodeZigZag32(1));
+    assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
+    assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
+    assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
+    assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
+    assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
+
+    assertEquals(0, CodedOutputStream.encodeZigZag64(0));
+    assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
+    assertEquals(2, CodedOutputStream.encodeZigZag64(1));
+    assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
+    assertEquals(0x000000007FFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
+    assertEquals(0x000000007FFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
+    assertEquals(0x00000000FFFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
+    assertEquals(0x00000000FFFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
+    assertEquals(0xFFFFFFFFFFFFFFFEL, CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
+    assertEquals(0xFFFFFFFFFFFFFFFFL, CodedOutputStream.encodeZigZag64(0x8000000000000000L));
+
+    // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
+    // were chosen semi-randomly via keyboard bashing.
+    assertEquals(0, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
+    assertEquals(1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
+    assertEquals(-1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
+    assertEquals(14927, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
+    assertEquals(-3612, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
+
+    assertEquals(0, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
+    assertEquals(1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
+    assertEquals(-1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
+    assertEquals(14927, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
+    assertEquals(-3612, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
+
+    assertEquals(
+        856912304801416L,
+        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L)));
+    assertEquals(
+        -75123905439571256L,
+        CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L)));
+  }
+
+  /** Tests writing a whole message with every field type. */
+  public void testWriteWholeMessage() throws Exception {
+    final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray();
+    TestAllTypes message = TestUtil.getAllSet();
+
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(message.getSerializedSize());
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      byte[] rawBytes = coder.toByteArray();
+      assertEqualBytes(outputType, expectedBytes, rawBytes);
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, expectedBytes, coder.toByteArray());
+    }
+  }
+
+  /**
+   * Tests writing a whole message with every packed field type. Ensures the
+   * wire format of packed fields is compatible with C++.
+   */
+  public void testWriteWholePackedFieldsMessage() throws Exception {
+    byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(message.getSerializedSize());
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      byte[] rawBytes = coder.toByteArray();
+      assertEqualBytes(outputType, expectedBytes, rawBytes);
+    }
+  }
+
+  /**
+   * Test writing a message containing a negative enum value. This used to
+   * fail because the size was not properly computed as a sign-extended varint.
+   */
+  public void testWriteMessageWithNegativeEnumValue() throws Exception {
+    SparseEnumMessage message =
+        SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build();
+    assertTrue(message.getSparseEnum().getNumber() < 0);
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(message.getSerializedSize());
+      message.writeTo(coder.stream());
+      coder.stream().flush();
+      byte[] rawBytes = coder.toByteArray();
+      SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
+      assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
+    }
+  }
+
+  /** Test getTotalBytesWritten() */
+  public void testGetTotalBytesWritten() throws Exception {
+    Coder coder = OutputType.STREAM.newCoder(4 * 1024);
+
+    // Write some some bytes (more than the buffer can hold) and verify that totalWritten
+    // is correct.
+    byte[] value = "abcde".getBytes(Internal.UTF_8);
+    for (int i = 0; i < 1024; ++i) {
+      coder.stream().writeRawBytes(value, 0, value.length);
+    }
+    assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten());
+
+    // Now write an encoded string.
+    String string =
+        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+    // Ensure we take the slower fast path.
+    assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length())
+        != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+
+    coder.stream().writeStringNoTag(string);
+    int stringSize = CodedOutputStream.computeStringSizeNoTag(string);
+
+    // Verify that the total bytes written is correct
+    assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalBytesWritten());
+  }
+
+  // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just
+  //    this case.
+  public void testWriteStringNoTag_fastpath() throws Exception {
+    int bufferSize = 153;
+    String threeBytesPer = "\u0981";
+    String string = threeBytesPer;
+    for (int i = 0; i < 50; i++) {
+      string += threeBytesPer;
+    }
+    // These checks ensure we will tickle the slower fast path.
+    assertEquals(1, CodedOutputStream.computeUInt32SizeNoTag(string.length()));
+    assertEquals(
+        2, CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
+    assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR);
+
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(bufferSize + 2);
+      coder.stream().writeStringNoTag(string);
+      coder.stream().flush();
+    }
+  }
+
+  public void testWriteToByteBuffer() throws Exception {
+    final int bufferSize = 16 * 1024;
+    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(buffer);
+    // Write raw bytes into the ByteBuffer.
+    final int length1 = 5000;
+    for (int i = 0; i < length1; i++) {
+      codedStream.writeRawByte((byte) 1);
+    }
+    final int length2 = 8 * 1024;
+    byte[] data = new byte[length2];
+    for (int i = 0; i < length2; i++) {
+      data[i] = (byte) 2;
+    }
+    codedStream.writeRawBytes(data);
+    final int length3 = bufferSize - length1 - length2;
+    for (int i = 0; i < length3; i++) {
+      codedStream.writeRawByte((byte) 3);
+    }
+    codedStream.flush();
+
+    // Check that data is correctly written to the ByteBuffer.
+    assertEquals(0, buffer.remaining());
+    buffer.flip();
+    for (int i = 0; i < length1; i++) {
+      assertEquals((byte) 1, buffer.get());
+    }
+    for (int i = 0; i < length2; i++) {
+      assertEquals((byte) 2, buffer.get());
+    }
+    for (int i = 0; i < length3; i++) {
+      assertEquals((byte) 3, buffer.get());
+    }
+  }
+
+  public void testWriteByteBuffer() throws Exception {
+    byte[] value = "abcde".getBytes(Internal.UTF_8);
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
+    ByteBuffer byteBuffer = ByteBuffer.wrap(value, 0, 1);
+    // This will actually write 5 bytes into the CodedOutputStream as the
+    // ByteBuffer's capacity() is 5.
+    codedStream.writeRawBytes(byteBuffer);
+    // The above call shouldn't affect the ByteBuffer's state.
+    assertEquals(0, byteBuffer.position());
+    assertEquals(1, byteBuffer.limit());
+
+    // The correct way to write part of an array using ByteBuffer.
+    codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice());
+
+    codedStream.flush();
+    byte[] result = outputStream.toByteArray();
+    assertEquals(6, result.length);
+    for (int i = 0; i < 5; i++) {
+      assertEquals(value[i], result[i]);
+    }
+    assertEquals(value[2], result[5]);
+  }
+
+  public void testWriteByteArrayWithOffsets() throws Exception {
+    byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
+    byte[] destination = new byte[4];
+    CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
+    codedStream.writeByteArrayNoTag(fullArray, 2, 2);
+    assertEqualBytes(OutputType.ARRAY, bytes(0x02, 0x33, 0x44, 0x00), destination);
+    assertEquals(3, codedStream.getTotalBytesWritten());
+  }
+
+  public void testSerializeUtf8_MultipleSmallWrites() throws Exception {
+    final String source = "abcdefghijklmnopqrstuvwxyz";
+
+    // Generate the expected output if the source string is written 2 bytes at a time.
+    ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream();
+    for (int pos = 0; pos < source.length(); pos += 2) {
+      String substr = source.substring(pos, pos + 2);
+      expectedBytesStream.write(2);
+      expectedBytesStream.write(substr.getBytes(Internal.UTF_8));
+    }
+    final byte[] expectedBytes = expectedBytesStream.toByteArray();
+
+    // For each output type, write the source string 2 bytes at a time and verify the output.
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(expectedBytes.length);
+      for (int pos = 0; pos < source.length(); pos += 2) {
+        String substr = source.substring(pos, pos + 2);
+        coder.stream().writeStringNoTag(substr);
+      }
+      coder.stream().flush();
+      assertEqualBytes(outputType, expectedBytes, coder.toByteArray());
+    }
+  }
+
+  public void testSerializeInvalidUtf8() throws Exception {
+    String[] invalidStrings = new String[] {newString(Character.MIN_HIGH_SURROGATE),
+        "foobar" + newString(Character.MIN_HIGH_SURROGATE), newString(Character.MIN_LOW_SURROGATE),
+        "foobar" + newString(Character.MIN_LOW_SURROGATE),
+        newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)};
+
+    CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream());
+    CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]);
+    CodedOutputStream outputWithByteBuffer =
+        CodedOutputStream.newInstance(ByteBuffer.allocate(10000));
+    for (String s : invalidStrings) {
+      // TODO(dweis): These should all fail; instead they are corrupting data.
+      CodedOutputStream.computeStringSizeNoTag(s);
+      outputWithStream.writeStringNoTag(s);
+      outputWithArray.writeStringNoTag(s);
+      outputWithByteBuffer.writeStringNoTag(s);
+    }
+  }
+
+  // TODO(nathanmittler): This test can be deleted once we properly throw IOException while
+  // encoding invalid UTF-8 strings.
+  public void testSerializeInvalidUtf8FollowedByOutOfSpace() throws Exception {
+    final int notEnoughBytes = 4;
+    CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[notEnoughBytes]);
+    CodedOutputStream outputWithByteBuffer =
+        CodedOutputStream.newInstance(ByteBuffer.allocate(notEnoughBytes));
+
+    String invalidString = newString(Character.MIN_HIGH_SURROGATE, 'f', 'o', 'o', 'b', 'a', 'r');
+    try {
+      outputWithArray.writeStringNoTag(invalidString);
+      fail("Expected OutOfSpaceException");
+    } catch (OutOfSpaceException e) {
+      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+    }
+    try {
+      outputWithByteBuffer.writeStringNoTag(invalidString);
+      fail("Expected OutOfSpaceException");
+    } catch (OutOfSpaceException e) {
+      assertTrue(e.getCause() instanceof IndexOutOfBoundsException);
+    }
+  }
+
+  /** Regression test for https://github.com/google/protobuf/issues/292 */
+  public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
+    String testCase = "Foooooooo";
+    assertEquals(
+        CodedOutputStream.computeUInt32SizeNoTag(testCase.length()),
+        CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3));
+    assertEquals(11, CodedOutputStream.computeStringSize(1, testCase));
+    // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
+    // An array of size 1 will cause a failure when trying to write the varint.
+    for (OutputType outputType :
+        new OutputType[] {OutputType.ARRAY, OutputType.NIO_HEAP, OutputType.NIO_DIRECT}) {
+      for (int i = 0; i < 11; i++) {
+        Coder coder = outputType.newCoder(i);
+        try {
+          coder.stream().writeString(1, testCase);
+          fail("Should have thrown an out of space exception");
+        } catch (CodedOutputStream.OutOfSpaceException expected) {
+        }
+      }
+    }
+  }
+
+  public void testDifferentStringLengths() throws Exception {
+    // Test string serialization roundtrip using strings of the following lengths,
+    // with ASCII and Unicode characters requiring different UTF-8 byte counts per
+    // char, hence causing the length delimiter varint to sometimes require more
+    // bytes for the Unicode strings than the ASCII string of the same length.
+    int[] lengths = new int[] {
+        0,
+        1,
+        (1 << 4) - 1, // 1 byte for ASCII and Unicode
+        (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode
+        (1 << 11) - 1, // 2 bytes for ASCII and Unicode
+        (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
+        (1 << 17) - 1,
+        // 3 bytes for ASCII and Unicode
+    };
+    for (OutputType outputType : OutputType.values()) {
+      for (int i : lengths) {
+        testEncodingOfString(outputType, 'q', i); // 1 byte per char
+        testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char
+        testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char
+      }
+    }
+  }
+
+  public void testNioEncodersWithInitialOffsets() throws Exception {
+    String value = "abc";
+    for (Coder coder : new Coder[] {new NioHeapCoder(10, 2), new NioDirectCoder(10, 2)}) {
+      coder.stream().writeStringNoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(coder.getOutputType(), new byte[]{3, 'a', 'b', 'c'}, coder.toByteArray());
+    }
+  }
+
+  /**
+   * Parses the given bytes using writeRawLittleEndian32() and checks
+   * that the result matches the given value.
+   */
+  private static void assertWriteLittleEndian32(byte[] data, int value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(data.length);
+      coder.stream().writeFixed32NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(outputType, data, coder.toByteArray());
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      coder.stream().writeFixed32NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+    }
+  }
+
+  /**
+   * Parses the given bytes using writeRawLittleEndian64() and checks
+   * that the result matches the given value.
+   */
+  private static void assertWriteLittleEndian64(byte[] data, long value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      Coder coder = outputType.newCoder(data.length);
+      coder.stream().writeFixed64NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(outputType, data, coder.toByteArray());
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      Coder coder = OutputType.STREAM.newCoder(blockSize);
+      coder.stream().writeFixed64NoTag(value);
+      coder.stream().flush();
+      assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+    }
+  }
+
+  private static String newString(char... chars) {
+    return new String(chars);
+  }
+
+  private static void testEncodingOfString(OutputType outputType, char c, int length)
+      throws Exception {
+    String fullString = fullString(c, length);
+    TestAllTypes testAllTypes = TestAllTypes.newBuilder().setOptionalString(fullString).build();
+    Coder coder = outputType.newCoder(testAllTypes.getSerializedSize());
+    testAllTypes.writeTo(coder.stream());
+    coder.stream().flush();
+    assertEquals(
+        "OuputType: " + outputType,
+        fullString,
+        TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString());
+  }
+
+  private static String fullString(char c, int length) {
+    char[] result = new char[length];
+    Arrays.fill(result, c);
+    return new String(result);
+  }
+
+  /**
+   * Helper to construct a byte array from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private static byte[] bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return bytes;
+  }
+
+  /** Arrays.asList() does not work with arrays of primitives.  :( */
+  private static List<Byte> toList(byte[] bytes) {
+    List<Byte> result = new ArrayList<Byte>();
+    for (byte b : bytes) {
+      result.add(b);
+    }
+    return result;
+  }
+
+  private static void assertEqualBytes(OutputType outputType, byte[] a, byte[] b) {
+    assertEquals(outputType.name(), toList(a), toList(b));
+  }
+
+  /**
+   * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+   * checks that the result matches the given bytes.
+   */
+  private static void assertWriteVarint(byte[] data, long value) throws Exception {
+    for (OutputType outputType : OutputType.values()) {
+      // Only test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
+        Coder coder = outputType.newCoder(10);
+        coder.stream().writeUInt32NoTag((int) value);
+        coder.stream().flush();
+        assertEqualBytes(outputType, data, coder.toByteArray());
+
+        // Also try computing size.
+        assertEquals(data.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+      }
+
+      {
+        Coder coder = outputType.newCoder(10);
+        coder.stream().writeUInt64NoTag(value);
+        coder.stream().flush();
+        assertEqualBytes(outputType, data, coder.toByteArray());
+
+        // Also try computing size.
+        assertEquals(data.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+      }
+    }
+
+    // Try different block sizes.
+    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+      // Only test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
+        Coder coder = OutputType.STREAM.newCoder(blockSize);
+        coder.stream().writeUInt64NoTag((int) value);
+        coder.stream().flush();
+        assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+
+        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+        CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, blockSize);
+        output.writeUInt32NoTag((int) value);
+        output.flush();
+        assertEqualBytes(OutputType.STREAM, data, rawOutput.toByteArray());
+      }
+
+      {
+        Coder coder = OutputType.STREAM.newCoder(blockSize);
+        coder.stream().writeUInt64NoTag(value);
+        coder.stream().flush();
+        assertEqualBytes(OutputType.STREAM, data, coder.toByteArray());
+      }
+    }
+  }
+
+  private static void assertVarintRoundTrip(OutputType outputType, long value) throws Exception {
+    {
+      Coder coder = outputType.newCoder(10);
+      coder.stream().writeUInt64NoTag(value);
+      coder.stream().flush();
+      byte[] bytes = coder.toByteArray();
+      assertEquals(
+          outputType.name(), bytes.length, CodedOutputStream.computeUInt64SizeNoTag(value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(outputType.name(), value, input.readRawVarint64());
+    }
+
+    if (value == (int) value) {
+      Coder coder = outputType.newCoder(10);
+      coder.stream().writeUInt32NoTag((int) value);
+      coder.stream().flush();
+      byte[] bytes = coder.toByteArray();
+      assertEquals(
+          outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNoTag((int) value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(outputType.name(), value, input.readRawVarint32());
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
new file mode 100644
index 0000000..ce85ae2
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
@@ -0,0 +1,81 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestDeprecatedFields;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+
+/**
+ * Test field deprecation
+ * 
+ * @author birdo@google.com (Roberto Scaramuzzi)
+ */
+public class DeprecatedFieldTest extends TestCase {
+  private String[] deprecatedGetterNames = {
+      "hasDeprecatedInt32",
+      "getDeprecatedInt32"};
+  
+  private String[] deprecatedBuilderGetterNames = {
+      "hasDeprecatedInt32",
+      "getDeprecatedInt32",
+      "clearDeprecatedInt32"};
+  
+  private String[] deprecatedBuilderSetterNames = {
+      "setDeprecatedInt32"}; 
+  
+  public void testDeprecatedField() throws Exception {
+    Class<?> deprecatedFields = TestDeprecatedFields.class;
+    Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
+    for (String name : deprecatedGetterNames) {
+      Method method = deprecatedFields.getMethod(name);
+      assertTrue("Method " + name + " should be deprecated",
+          isDeprecated(method));
+    }
+    for (String name : deprecatedBuilderGetterNames) {
+      Method method = deprecatedFieldsBuilder.getMethod(name);
+      assertTrue("Method " + name + " should be deprecated",
+          isDeprecated(method));
+    }
+    for (String name : deprecatedBuilderSetterNames) {
+      Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
+      assertTrue("Method " + name + " should be deprecated",
+          isDeprecated(method));
+    }
+  }
+  
+  private boolean isDeprecated(AnnotatedElement annotated) {
+    return annotated.isAnnotationPresent(Deprecated.class);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
new file mode 100644
index 0000000..ef89b38
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -0,0 +1,800 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.DescriptorValidationException;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+import com.google.protobuf.Descriptors.ServiceDescriptor;
+import com.google.protobuf.test.UnittestImport;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
+import protobuf_unittest.TestCustomOptions;
+import protobuf_unittest.UnittestCustomOptions;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestReservedFields;
+import protobuf_unittest.UnittestProto.TestService;
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unit test for {@link Descriptors}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DescriptorsTest extends TestCase {
+
+  // Regression test for bug where referencing a FieldDescriptor.Type value
+  // before a FieldDescriptorProto.Type value would yield a
+  // ExceptionInInitializerError.
+  @SuppressWarnings("unused")
+  private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
+
+  public void testFieldTypeEnumMapping() throws Exception {
+    assertEquals(FieldDescriptor.Type.values().length,
+        FieldDescriptorProto.Type.values().length);
+    for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
+      FieldDescriptorProto.Type protoType = type.toProto();
+      assertEquals("TYPE_" + type.name(), protoType.name());
+      assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
+    }
+  }
+
+  public void testFileDescriptor() throws Exception {
+    FileDescriptor file = UnittestProto.getDescriptor();
+
+    assertEquals("google/protobuf/unittest.proto", file.getName());
+    assertEquals("protobuf_unittest", file.getPackage());
+
+    assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
+    assertEquals("google/protobuf/unittest.proto",
+                 file.toProto().getName());
+
+    assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
+                 file.getDependencies());
+
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    assertEquals(messageType, file.getMessageTypes().get(0));
+    assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
+    assertNull(file.findMessageTypeByName("NoSuchType"));
+    assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
+    for (int i = 0; i < file.getMessageTypes().size(); i++) {
+      assertEquals(i, file.getMessageTypes().get(i).getIndex());
+    }
+
+    EnumDescriptor enumType = ForeignEnum.getDescriptor();
+    assertEquals(enumType, file.getEnumTypes().get(0));
+    assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
+    assertNull(file.findEnumTypeByName("NoSuchType"));
+    assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
+    assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
+                               ImportEnumForMap.getDescriptor()),
+                 UnittestImport.getDescriptor().getEnumTypes());
+    for (int i = 0; i < file.getEnumTypes().size(); i++) {
+      assertEquals(i, file.getEnumTypes().get(i).getIndex());
+    }
+
+    ServiceDescriptor service = TestService.getDescriptor();
+    assertEquals(service, file.getServices().get(0));
+    assertEquals(service, file.findServiceByName("TestService"));
+    assertNull(file.findServiceByName("NoSuchType"));
+    assertNull(file.findServiceByName("protobuf_unittest.TestService"));
+    assertEquals(Collections.emptyList(),
+                 UnittestImport.getDescriptor().getServices());
+    for (int i = 0; i < file.getServices().size(); i++) {
+      assertEquals(i, file.getServices().get(i).getIndex());
+    }
+
+    FieldDescriptor extension =
+      UnittestProto.optionalInt32Extension.getDescriptor();
+    assertEquals(extension, file.getExtensions().get(0));
+    assertEquals(extension,
+                 file.findExtensionByName("optional_int32_extension"));
+    assertNull(file.findExtensionByName("no_such_ext"));
+    assertNull(file.findExtensionByName(
+      "protobuf_unittest.optional_int32_extension"));
+    assertEquals(Collections.emptyList(),
+                 UnittestImport.getDescriptor().getExtensions());
+    for (int i = 0; i < file.getExtensions().size(); i++) {
+      assertEquals(i, file.getExtensions().get(i).getIndex());
+    }
+  }
+
+  public void testDescriptor() throws Exception {
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
+
+    assertEquals("TestAllTypes", messageType.getName());
+    assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
+    assertNull(messageType.getContainingType());
+    assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
+                 messageType.getOptions());
+    assertEquals("TestAllTypes", messageType.toProto().getName());
+
+    assertEquals("NestedMessage", nestedType.getName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
+                 nestedType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+    assertEquals(messageType, nestedType.getContainingType());
+
+    FieldDescriptor field = messageType.getFields().get(0);
+    assertEquals("optional_int32", field.getName());
+    assertEquals(field, messageType.findFieldByName("optional_int32"));
+    assertNull(messageType.findFieldByName("no_such_field"));
+    assertEquals(field, messageType.findFieldByNumber(1));
+    assertNull(messageType.findFieldByNumber(571283));
+    for (int i = 0; i < messageType.getFields().size(); i++) {
+      assertEquals(i, messageType.getFields().get(i).getIndex());
+    }
+
+    assertEquals(nestedType, messageType.getNestedTypes().get(0));
+    assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
+    assertNull(messageType.findNestedTypeByName("NoSuchType"));
+    for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
+      assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
+    }
+
+    EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+    assertEquals(enumType, messageType.getEnumTypes().get(0));
+    assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
+    assertNull(messageType.findEnumTypeByName("NoSuchType"));
+    for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
+      assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
+    }
+  }
+
+  public void testFieldDescriptor() throws Exception {
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    FieldDescriptor primitiveField =
+      messageType.findFieldByName("optional_int32");
+    FieldDescriptor enumField =
+      messageType.findFieldByName("optional_nested_enum");
+    FieldDescriptor messageField =
+      messageType.findFieldByName("optional_foreign_message");
+    FieldDescriptor cordField =
+      messageType.findFieldByName("optional_cord");
+    FieldDescriptor extension =
+      UnittestProto.optionalInt32Extension.getDescriptor();
+    FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
+
+    assertEquals("optional_int32", primitiveField.getName());
+    assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
+                 primitiveField.getFullName());
+    assertEquals(1, primitiveField.getNumber());
+    assertEquals(messageType, primitiveField.getContainingType());
+    assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
+    assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
+    assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
+    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+                 primitiveField.getOptions());
+    assertFalse(primitiveField.isExtension());
+    assertEquals("optional_int32", primitiveField.toProto().getName());
+
+    assertEquals("optional_nested_enum", enumField.getName());
+    assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
+    assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
+    assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
+                 enumField.getEnumType());
+
+    assertEquals("optional_foreign_message", messageField.getName());
+    assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
+    assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
+    assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
+
+    assertEquals("optional_cord", cordField.getName());
+    assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
+    assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
+    assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
+                 cordField.getOptions().getCtype());
+
+    assertEquals("optional_int32_extension", extension.getName());
+    assertEquals("protobuf_unittest.optional_int32_extension",
+                 extension.getFullName());
+    assertEquals(1, extension.getNumber());
+    assertEquals(TestAllExtensions.getDescriptor(),
+                 extension.getContainingType());
+    assertEquals(UnittestProto.getDescriptor(), extension.getFile());
+    assertEquals(FieldDescriptor.Type.INT32, extension.getType());
+    assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
+    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+                 extension.getOptions());
+    assertTrue(extension.isExtension());
+    assertEquals(null, extension.getExtensionScope());
+    assertEquals("optional_int32_extension", extension.toProto().getName());
+
+    assertEquals("single", nestedExtension.getName());
+    assertEquals("protobuf_unittest.TestRequired.single",
+                 nestedExtension.getFullName());
+    assertEquals(TestRequired.getDescriptor(),
+                 nestedExtension.getExtensionScope());
+  }
+
+  public void testFieldDescriptorLabel() throws Exception {
+    FieldDescriptor requiredField =
+      TestRequired.getDescriptor().findFieldByName("a");
+    FieldDescriptor optionalField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+    FieldDescriptor repeatedField =
+      TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+
+    assertTrue(requiredField.isRequired());
+    assertFalse(requiredField.isRepeated());
+    assertFalse(optionalField.isRequired());
+    assertFalse(optionalField.isRepeated());
+    assertFalse(repeatedField.isRequired());
+    assertTrue(repeatedField.isRepeated());
+  }
+  
+  public void testFieldDescriptorJsonName() throws Exception {
+    FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
+    FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+    FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+    assertEquals("a", requiredField.getJsonName());
+    assertEquals("optionalInt32", optionalField.getJsonName());
+    assertEquals("repeatedInt32", repeatedField.getJsonName());
+  }
+
+  public void testFieldDescriptorDefault() throws Exception {
+    Descriptor d = TestAllTypes.getDescriptor();
+    assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
+    assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
+    assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
+    assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
+
+    d = TestExtremeDefaultValues.getDescriptor();
+    assertEquals(
+      ByteString.copyFrom(
+        "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
+      d.findFieldByName("escaped_bytes").getDefaultValue());
+    assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
+    assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
+  }
+
+  public void testEnumDescriptor() throws Exception {
+    EnumDescriptor enumType = ForeignEnum.getDescriptor();
+    EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
+
+    assertEquals("ForeignEnum", enumType.getName());
+    assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
+    assertNull(enumType.getContainingType());
+    assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
+                 enumType.getOptions());
+
+    assertEquals("NestedEnum", nestedType.getName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
+                 nestedType.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+    assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
+
+    EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
+    assertEquals(value, enumType.getValues().get(0));
+    assertEquals("FOREIGN_FOO", value.getName());
+    assertEquals("FOREIGN_FOO", value.toString());
+    assertEquals(4, value.getNumber());
+    assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
+    assertEquals(value, enumType.findValueByNumber(4));
+    assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
+    for (int i = 0; i < enumType.getValues().size(); i++) {
+      assertEquals(i, enumType.getValues().get(i).getIndex());
+    }
+  }
+
+  public void testServiceDescriptor() throws Exception {
+    ServiceDescriptor service = TestService.getDescriptor();
+
+    assertEquals("TestService", service.getName());
+    assertEquals("protobuf_unittest.TestService", service.getFullName());
+    assertEquals(UnittestProto.getDescriptor(), service.getFile());
+
+
+    MethodDescriptor fooMethod = service.getMethods().get(0);
+    assertEquals("Foo", fooMethod.getName());
+    assertEquals(UnittestProto.FooRequest.getDescriptor(),
+                 fooMethod.getInputType());
+    assertEquals(UnittestProto.FooResponse.getDescriptor(),
+                 fooMethod.getOutputType());
+    assertEquals(fooMethod, service.findMethodByName("Foo"));
+
+    MethodDescriptor barMethod = service.getMethods().get(1);
+    assertEquals("Bar", barMethod.getName());
+    assertEquals(UnittestProto.BarRequest.getDescriptor(),
+                 barMethod.getInputType());
+    assertEquals(UnittestProto.BarResponse.getDescriptor(),
+                 barMethod.getOutputType());
+    assertEquals(barMethod, service.findMethodByName("Bar"));
+
+    assertNull(service.findMethodByName("NoSuchMethod"));
+
+    for (int i = 0; i < service.getMethods().size(); i++) {
+      assertEquals(i, service.getMethods().get(i).getIndex());
+    }
+  }
+
+
+  public void testCustomOptions() throws Exception {
+    // Get the descriptor indirectly from a dependent proto class. This is to
+    // ensure that when a proto class is loaded, custom options defined in its
+    // dependencies are also properly initialized.
+    Descriptor descriptor =
+        TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
+        .findFieldByName("field").getMessageType();
+
+    assertTrue(
+      descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
+    assertEquals(Integer.valueOf(-56),
+      descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+
+    FieldDescriptor field = descriptor.findFieldByName("field1");
+    assertNotNull(field);
+
+    assertTrue(
+      field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
+    assertEquals(Long.valueOf(8765432109L),
+      field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+
+    EnumDescriptor enumType =
+      UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
+
+    assertTrue(
+      enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
+    assertEquals(Integer.valueOf(-789),
+      enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+
+    ServiceDescriptor service =
+      UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
+
+    assertTrue(
+      service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
+    assertEquals(Long.valueOf(-9876543210L),
+      service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+
+    MethodDescriptor method = service.findMethodByName("Foo");
+    assertNotNull(method);
+
+    assertTrue(
+      method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
+    assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
+      method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+  }
+
+  /**
+   * Test that the FieldDescriptor.Type enum is the same as the
+   * WireFormat.FieldType enum.
+   */
+  public void testFieldTypeTablesMatch() throws Exception {
+    FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
+    WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
+
+  /**
+   * Test that the FieldDescriptor.JavaType enum is the same as the
+   * WireFormat.JavaType enum.
+   */
+  public void testJavaTypeTablesMatch() throws Exception {
+    FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
+    WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
+
+    assertEquals(values1.length, values2.length);
+
+    for (int i = 0; i < values1.length; i++) {
+      assertEquals(values1[i].toString(), values2[i].toString());
+    }
+  }
+
+  public void testEnormousDescriptor() throws Exception {
+    // The descriptor for this file is larger than 64k, yet it did not cause
+    // a compiler error due to an over-long string literal.
+    assertTrue(
+        UnittestEnormousDescriptor.getDescriptor()
+          .toProto().getSerializedSize() > 65536);
+  }
+
+  /**
+   * Tests that the DescriptorValidationException works as intended.
+   */
+  public void testDescriptorValidatorException() throws Exception {
+    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+      .setName("foo.proto")
+      .addMessageType(DescriptorProto.newBuilder()
+      .setName("Foo")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setType(FieldDescriptorProto.Type.TYPE_INT32)
+          .setName("foo")
+          .setNumber(1)
+          .setDefaultValue("invalid")
+          .build())
+        .build())
+      .build();
+    try {
+      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
+          new FileDescriptor[0]);
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      // Expected; check that the error message contains some useful hints
+      assertTrue(e.getMessage().indexOf("foo") != -1);
+      assertTrue(e.getMessage().indexOf("Foo") != -1);
+      assertTrue(e.getMessage().indexOf("invalid") != -1);
+      assertTrue(e.getCause() instanceof NumberFormatException);
+      assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
+    }
+  }
+
+  /**
+   * Tests the translate/crosslink for an example where a message field's name
+   * and type name are the same.
+   */
+  public void testDescriptorComplexCrosslink() throws Exception {
+    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+      .setName("foo.proto")
+      .addMessageType(DescriptorProto.newBuilder()
+        .setName("Foo")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setType(FieldDescriptorProto.Type.TYPE_INT32)
+          .setName("foo")
+          .setNumber(1)
+          .build())
+        .build())
+      .addMessageType(DescriptorProto.newBuilder()
+        .setName("Bar")
+        .addField(FieldDescriptorProto.newBuilder()
+          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+          .setTypeName("Foo")
+          .setName("Foo")
+          .setNumber(1)
+          .build())
+        .build())
+      .build();
+    // translate and crosslink
+    FileDescriptor file =
+      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
+          new FileDescriptor[0]);
+    // verify resulting descriptors
+    assertNotNull(file);
+    List<Descriptor> msglist = file.getMessageTypes();
+    assertNotNull(msglist);
+    assertTrue(msglist.size() == 2);
+    boolean barFound = false;
+    for (Descriptor desc : msglist) {
+      if (desc.getName().equals("Bar")) {
+        barFound = true;
+        assertNotNull(desc.getFields());
+        List<FieldDescriptor> fieldlist = desc.getFields();
+        assertNotNull(fieldlist);
+        assertTrue(fieldlist.size() == 1);
+        assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
+        assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
+      }
+    }
+    assertTrue(barFound);
+  }
+
+  public void testDependencyOrder() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto").build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addDependency("foo.proto")
+        .build();
+    FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
+        .setName("baz.proto")
+        .addDependency("foo.proto")
+        .addDependency("bar.proto")
+        .addPublicDependency(0)
+        .addPublicDependency(1)
+        .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+        new FileDescriptor[0]);
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
+        new FileDescriptor[] {fooFile});
+
+    // Items in the FileDescriptor array can be in any order.
+    Descriptors.FileDescriptor.buildFrom(bazProto,
+        new FileDescriptor[] {fooFile, barFile});
+    Descriptors.FileDescriptor.buildFrom(bazProto,
+        new FileDescriptor[] {barFile, fooFile});
+  }
+
+  public void testInvalidPublicDependency() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto").build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("boo.proto")
+        .addDependency("foo.proto")
+        .addPublicDependency(1)  // Error, should be 0.
+        .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
+        new FileDescriptor[0]);
+    try {
+      Descriptors.FileDescriptor.buildFrom(barProto,
+          new FileDescriptor[] {fooFile});
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(
+          e.getMessage().indexOf("Invalid public dependency index.") != -1);
+    }
+  }
+
+  public void testUnknownFieldsDenied() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+
+    try {
+      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(e.getMessage().indexOf("Bar") != -1);
+      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+    }
+  }
+
+  public void testUnknownFieldsAllowed() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
+  }
+
+  public void testHiddenDependency() throws Exception {
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+        .build();
+    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+        .setName("forward.proto")
+        .addDependency("bar.proto")
+        .build();
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("forward.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+        forwardProto, new FileDescriptor[] {barFile});
+
+    try {
+      Descriptors.FileDescriptor.buildFrom(
+          fooProto, new FileDescriptor[] {forwardFile});
+      fail("DescriptorValidationException expected");
+    } catch (DescriptorValidationException e) {
+      assertTrue(e.getMessage().indexOf("Bar") != -1);
+      assertTrue(e.getMessage().indexOf("is not defined") != -1);
+    }
+  }
+
+  public void testPublicDependency() throws Exception {
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+        .build();
+    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
+        .setName("forward.proto")
+        .addDependency("bar.proto")
+        .addPublicDependency(0)
+        .build();
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("forward.proto")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("Foo")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setTypeName("Bar")
+                .setName("bar")
+                .setNumber(1)))
+        .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
+        forwardProto, new FileDescriptor[]{barFile});
+    Descriptors.FileDescriptor.buildFrom(
+        fooProto, new FileDescriptor[] {forwardFile});
+  }
+
+  /**
+   * Tests the translate/crosslink for an example with a more complex namespace
+   * referencing.
+   */
+  public void testComplexNamespacePublicDependency() throws Exception {
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
+        .setName("bar.proto")
+        .setPackage("a.b.c.d.bar.shared")
+        .addEnumType(EnumDescriptorProto.newBuilder()
+            .setName("MyEnum")
+            .addValue(EnumValueDescriptorProto.newBuilder()
+                .setName("BLAH")
+                .setNumber(1)))
+        .build();
+    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addDependency("bar.proto")
+        .setPackage("a.b.c.d.foo.shared")
+        .addMessageType(DescriptorProto.newBuilder()
+            .setName("MyMessage")
+            .addField(FieldDescriptorProto.newBuilder()
+                .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+                .setTypeName("bar.shared.MyEnum")
+                .setName("MyField")
+                .setNumber(1)))
+        .build();
+    // translate and crosslink
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
+        fooProto, new FileDescriptor[0]);
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
+        barProto, new FileDescriptor[]{fooFile});
+    // verify resulting descriptors
+    assertNotNull(barFile);
+    List<Descriptor> msglist = barFile.getMessageTypes();
+    assertNotNull(msglist);
+    assertTrue(msglist.size() == 1);
+    Descriptor desc = msglist.get(0);
+    if (desc.getName().equals("MyMessage")) {
+      assertNotNull(desc.getFields());
+      List<FieldDescriptor> fieldlist = desc.getFields();
+      assertNotNull(fieldlist);
+      assertTrue(fieldlist.size() == 1);
+      FieldDescriptor field = fieldlist.get(0);
+      assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
+      assertTrue(field.getEnumType().getName().equals("MyEnum"));
+      assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
+      assertTrue(field.getEnumType().getFile().getPackage().equals(
+          "a.b.c.d.bar.shared"));
+    }
+  }
+
+  public void testOneofDescriptor() throws Exception {
+    Descriptor messageType = TestAllTypes.getDescriptor();
+    FieldDescriptor field =
+        messageType.findFieldByName("oneof_nested_message");
+    OneofDescriptor oneofDescriptor = field.getContainingOneof();
+    assertNotNull(oneofDescriptor);
+    assertSame(oneofDescriptor, messageType.getOneofs().get(0));
+    assertEquals("oneof_field", oneofDescriptor.getName());
+
+    assertEquals(4, oneofDescriptor.getFieldCount());
+    assertSame(oneofDescriptor.getField(1), field);
+
+    assertEquals(4, oneofDescriptor.getFields().size());
+    assertEquals(oneofDescriptor.getFields().get(1), field);
+  }
+
+  public void testMessageDescriptorExtensions() throws Exception {
+    assertFalse(TestAllTypes.getDescriptor().isExtendable());
+    assertTrue(TestAllExtensions.getDescriptor().isExtendable());
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
+
+    assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
+    assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
+    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
+    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
+    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
+  }
+
+  public void testReservedFields() {
+    Descriptor d = TestReservedFields.getDescriptor();
+    assertTrue(d.isReservedNumber(2));
+    assertFalse(d.isReservedNumber(8));
+    assertTrue(d.isReservedNumber(9));
+    assertTrue(d.isReservedNumber(10));
+    assertTrue(d.isReservedNumber(11));
+    assertFalse(d.isReservedNumber(12));
+    assertFalse(d.isReservedName("foo"));
+    assertTrue(d.isReservedName("bar"));
+    assertTrue(d.isReservedName("baz"));
+  }
+
+  public void testToString() {
+    assertEquals("protobuf_unittest.TestAllTypes.optional_uint64",
+        UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber(
+            UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString());
+  }
+
+  public void testPackedEnumField() throws Exception {
+    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
+        .setName("foo.proto")
+        .addEnumType(EnumDescriptorProto.newBuilder()
+          .setName("Enum")
+          .addValue(EnumValueDescriptorProto.newBuilder()
+            .setName("FOO")
+            .setNumber(1)
+            .build())
+          .build())
+        .addMessageType(DescriptorProto.newBuilder()
+          .setName("Message")
+          .addField(FieldDescriptorProto.newBuilder()
+            .setName("foo")
+            .setTypeName("Enum")
+            .setNumber(1)
+            .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+            .setOptions(DescriptorProtos.FieldOptions.newBuilder()
+              .setPacked(true)
+              .build())
+            .build())
+          .build())
+        .build();
+    Descriptors.FileDescriptor.buildFrom(
+        fileDescriptorProto, new FileDescriptor[0]);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
new file mode 100644
index 0000000..85b418c
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -0,0 +1,459 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link DoubleArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class DoubleArrayListTest extends TestCase {
+  
+  private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
+  private static final DoubleArrayList TERTIARY_LIST =
+      newImmutableDoubleArrayList(1, 2, 3);
+  
+  private DoubleArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new DoubleArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(DoubleArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addDouble(2);
+    list.addDouble(4);
+    list.addDouble(6);
+    list.addDouble(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1D, 2D, 3D, 4D));
+    Iterator<Double> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1D, (double) list.get(0));
+    assertEquals(1D, (double) iterator.next());
+    list.set(0, 1D);
+    assertEquals(2D, (double) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0D);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1D, (double) TERTIARY_LIST.get(0));
+    assertEquals(2D, (double) TERTIARY_LIST.get(1));
+    assertEquals(3D, (double) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(1D, TERTIARY_LIST.getDouble(0));
+    assertEquals(2D, TERTIARY_LIST.getDouble(1));
+    assertEquals(3D, TERTIARY_LIST.getDouble(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, DoubleArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addDouble(2);
+    list.addDouble(4);
+    list.addDouble(6);
+    list.addDouble(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16D);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addDouble(2);
+    list.addDouble(4);
+    
+    assertEquals(2D, (double) list.set(0, 0D));
+    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(4D, (double) list.set(1, 0D));
+    assertEquals(0D, list.getDouble(1));
+    
+    try {
+      list.set(-1, 0D);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0D);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addDouble(2);
+    list.addDouble(4);
+    
+    assertEquals(2D, list.setDouble(0, 0));
+    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(4D, list.setDouble(1, 0));
+    assertEquals(0D, list.getDouble(1));
+    
+    try {
+      list.setDouble(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setDouble(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2D));
+    assertEquals(asList(2D), list);
+
+    assertTrue(list.add(3D));
+    list.add(0, 4D);
+    assertEquals(asList(4D, 2D, 3D), list);
+    
+    list.add(0, 1D);
+    list.add(0, 0D);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Double.valueOf(5 + i));
+    }
+    assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list);
+    
+    try {
+      list.add(-1, 5D);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5D);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addDouble(2);
+    assertEquals(asList(2D), list);
+
+    list.addDouble(3);
+    assertEquals(asList(2D, 3D), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1D)));
+    assertEquals(1, list.size());
+    assertEquals(1D, (double) list.get(0));
+    assertEquals(1D, list.getDouble(0));
+    
+    assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
+    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list);
+
+    assertFalse(list.addAll(Collections.<Double>emptyList()));
+    assertFalse(list.addAll(DoubleArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1D, (double) list.remove(0));
+    assertEquals(asList(2D, 3D), list);
+
+    assertTrue(list.remove(Double.valueOf(3)));
+    assertEquals(asList(2D), list);
+
+    assertFalse(list.remove(Double.valueOf(3)));
+    assertEquals(asList(2D), list);
+
+    assertEquals(2D, (double) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(DoubleArrayList list) {
+    if (list.contains(1D)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new DoubleArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addDouble(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.retainAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setDouble(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static DoubleArrayList newImmutableDoubleArrayList(double... elements) {
+    DoubleArrayList list = new DoubleArrayList();
+    for (double element : elements) {
+      list.addDouble(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
new file mode 100644
index 0000000..8f3a74c
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -0,0 +1,326 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Unit test for {@link DynamicMessage}.  See also {@link MessageTest}, which
+ * tests some {@link DynamicMessage} functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DynamicMessageTest extends TestCase {
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+  TestUtil.ReflectionTester packedReflectionTester =
+    new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
+
+  public void testDynamicMessageAccessors() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testSettersAfterBuild() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    Message firstMessage = builder.build();
+    // double build()
+    builder.build();
+    // clear() after build()
+    builder.clear();
+    // setters after build()
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+    // repeated setters after build()
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    message = builder.build();
+    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+    // firstMessage shouldn't have been modified.
+    reflectionTester.assertClearViaReflection(firstMessage);
+  }
+
+  public void testUnknownFields() throws Exception {
+    Message.Builder builder =
+        DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
+    builder.setUnknownFields(UnknownFieldSet.newBuilder()
+        .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
+        .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
+        .build());
+    Message message = builder.build();
+    assertEquals(2, message.getUnknownFields().asMap().size());
+    // clone() with unknown fields
+    Message.Builder newBuilder = builder.clone();
+    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+    // clear() with unknown fields
+    newBuilder.clear();
+    assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
+    // serialize/parse with unknown fields
+    newBuilder.mergeFrom(message.toByteString());
+    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
+  }
+
+  public void testDynamicMessageSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testDynamicMessageExtensionAccessors() throws Exception {
+    // We don't need to extensively test DynamicMessage's handling of
+    // extensions because, frankly, it doesn't do anything special with them.
+    // It treats them just like any other fields.
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testDynamicMessageRepeatedSetters() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    Message message = builder.build();
+    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+  }
+
+  public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+  }
+
+  public void testDynamicMessageDefaults() throws Exception {
+    reflectionTester.assertClearViaReflection(
+      DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
+    reflectionTester.assertClearViaReflection(
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
+  }
+
+  public void testDynamicMessageSerializedSize() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    Message.Builder dynamicBuilder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
+    Message dynamicMessage = dynamicBuilder.build();
+
+    assertEquals(message.getSerializedSize(),
+                 dynamicMessage.getSerializedSize());
+  }
+
+  public void testDynamicMessageSerialization() throws Exception {
+    Message.Builder builder =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Message message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+
+    // In fact, the serialized forms should be exactly the same, byte-for-byte.
+    assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
+  }
+
+  public void testDynamicMessageParsing() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+
+    Message message2 =
+      DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
+    reflectionTester.assertAllFieldsSetViaReflection(message2);
+
+    // Test Parser interface.
+    Message message3 = message2.getParserForType().parseFrom(rawBytes);
+    reflectionTester.assertAllFieldsSetViaReflection(message3);
+  }
+
+  public void testDynamicMessageExtensionParsing() throws Exception {
+    ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
+    Message message = DynamicMessage.parseFrom(
+        TestAllExtensions.getDescriptor(), rawBytes,
+        TestUtil.getExtensionRegistry());
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+
+    // Test Parser interface.
+    Message message2 = message.getParserForType().parseFrom(
+        rawBytes, TestUtil.getExtensionRegistry());
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
+  }
+
+  public void testDynamicMessagePackedSerialization() throws Exception {
+    Message.Builder builder =
+        DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
+    packedReflectionTester.setPackedFieldsViaReflection(builder);
+    Message message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+    TestUtil.assertPackedFieldsSet(message2);
+
+    // In fact, the serialized forms should be exactly the same, byte-for-byte.
+    assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
+  }
+
+  public void testDynamicMessagePackedParsing() throws Exception {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    TestUtil.setPackedFields(builder);
+    TestPackedTypes message = builder.build();
+
+    ByteString rawBytes = message.toByteString();
+
+    Message message2 =
+      DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
+    packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
+
+    // Test Parser interface.
+    Message message3 = message2.getParserForType().parseFrom(rawBytes);
+    packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
+  }
+
+  public void testDynamicMessageCopy() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    DynamicMessage copy = DynamicMessage.newBuilder(message).build();
+    reflectionTester.assertAllFieldsSetViaReflection(copy);
+
+    // Test oneof behavior
+    FieldDescriptor bytesField =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+    FieldDescriptor uint32Field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
+    assertTrue(copy.hasField(bytesField));
+    assertFalse(copy.hasField(uint32Field));
+    DynamicMessage copy2 =
+        DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
+    assertFalse(copy2.hasField(bytesField));
+    assertTrue(copy2.hasField(uint32Field));
+    assertEquals(123, copy2.getField(uint32Field));
+  }
+
+  public void testToBuilder() throws Exception {
+    DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    reflectionTester.setAllFieldsViaReflection(builder);
+    int unknownFieldNum = 9;
+    long unknownFieldVal = 90;
+    builder.setUnknownFields(UnknownFieldSet.newBuilder()
+        .addField(unknownFieldNum,
+            UnknownFieldSet.Field.newBuilder()
+                .addVarint(unknownFieldVal).build())
+        .build());
+    DynamicMessage message = builder.build();
+
+    DynamicMessage derived = message.toBuilder().build();
+    reflectionTester.assertAllFieldsSetViaReflection(derived);
+    assertEquals(Arrays.asList(unknownFieldVal),
+        derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
+  }
+
+  public void testDynamicOneofMessage() throws Exception {
+    DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
+    assertFalse(builder.hasOneof(oneof));
+    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+
+    reflectionTester.setAllFieldsViaReflection(builder);
+    assertTrue(builder.hasOneof(oneof));
+    FieldDescriptor field = oneof.getField(3);
+    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+    DynamicMessage message = builder.buildPartial();
+    assertTrue(message.hasOneof(oneof));
+
+    DynamicMessage.Builder mergedBuilder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    FieldDescriptor mergedField = oneof.getField(0);
+    mergedBuilder.setField(mergedField, 123);
+    assertTrue(mergedBuilder.hasField(mergedField));
+    mergedBuilder.mergeFrom(message);
+    assertTrue(mergedBuilder.hasField(field));
+    assertFalse(mergedBuilder.hasField(mergedField));
+
+    builder.clearOneof(oneof);
+    assertSame(null, builder.getOneofFieldDescriptor(oneof));
+    message = builder.build();
+    assertSame(null, message.getOneofFieldDescriptor(oneof));
+  }
+
+  // Regression test for a bug that makes setField() not work for repeated
+  // enum fields.
+  public void testSettersForRepeatedEnumField() throws Exception {
+    DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+    FieldDescriptor repeatedEnumField =
+        TestAllTypes.getDescriptor().findFieldByName(
+            "repeated_nested_enum");
+    EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor();
+    builder.setField(repeatedEnumField, enumDescriptor.getValues());
+    DynamicMessage message = builder.build();
+    assertEquals(
+        enumDescriptor.getValues(), message.getField(repeatedEnumField));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/EnumTest.java b/java/core/src/test/java/com/google/protobuf/EnumTest.java
new file mode 100644
index 0000000..14c7406
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/EnumTest.java
@@ -0,0 +1,76 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+public class EnumTest extends TestCase {
+  
+  public void testForNumber() {
+    ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber());
+    assertEquals(ForeignEnum.FOREIGN_BAR, e);
+
+    e = ForeignEnum.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumber_oneof() {
+    TestAllTypes.OneofFieldCase e = TestAllTypes.OneofFieldCase.forNumber(
+        TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+    assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+    e = TestAllTypes.OneofFieldCase.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumberLite() {
+    ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber());
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e);
+
+    e = ForeignEnumLite.forNumber(1000);
+    assertEquals(null, e);
+  }
+  
+  public void testForNumberLite_oneof() {
+    TestAllTypesLite.OneofFieldCase e = TestAllTypesLite.OneofFieldCase.forNumber(
+        TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber());
+    assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e);
+
+    e = TestAllTypesLite.OneofFieldCase.forNumber(1000);
+    assertEquals(null, e);
+  }
+}
+
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
new file mode 100644
index 0000000..304cec4
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -0,0 +1,373 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
+import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
+import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly;
+import protobuf_unittest.UnittestProto;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for protos that doesn't support field presence test for optional
+ * non-message fields.
+ */
+public class FieldPresenceTest extends TestCase {
+  private static boolean hasMethod(Class<?> clazz, String name) {
+    try {
+      if (clazz.getMethod(name) != null) {
+        return true;
+      } else {
+        return false;
+      }
+    } catch (NoSuchMethodException e) {
+      return false;
+    }
+  }
+
+  private static void assertHasMethodRemoved(
+      Class<?> classWithFieldPresence,
+      Class<?> classWithoutFieldPresence,
+      String camelName) {
+    assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
+    assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
+    assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
+    assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
+  }
+
+  public void testHasMethod() {
+    // Optional non-message fields don't have a hasFoo() method generated.
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalInt32");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalString");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalBytes");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OptionalNestedEnum");
+
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalInt32");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalString");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalBytes");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OptionalNestedEnum");
+
+    // message fields still have the hasFoo() method generated.
+    assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
+    assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
+
+    // oneof fields don't have hasFoo() methods (even for message types).
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofUint32");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofString");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofBytes");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.class,
+        TestAllTypes.class,
+        "OneofNestedMessage");
+
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofUint32");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofString");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofBytes");
+    assertHasMethodRemoved(
+        UnittestProto.TestAllTypes.Builder.class,
+        TestAllTypes.Builder.class,
+        "OneofNestedMessage");
+  }
+
+  public void testOneofEquals() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes message1 = builder.build();
+    // Set message2's oneof_uint32 field to defalut value. The two
+    // messages should be different when check with oneof case.
+    builder.setOneofUint32(0);
+    TestAllTypes message2 = builder.build();
+    assertFalse(message1.equals(message2));
+  }
+
+  public void testFieldPresence() {
+    // Optional non-message fields set to their default value are treated the
+    // same way as not set.
+
+    // Serialization will ignore such fields.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalInt32(0);
+    builder.setOptionalString("");
+    builder.setOptionalBytes(ByteString.EMPTY);
+    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
+    TestAllTypes message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+
+    // mergeFrom() will ignore such fields.
+    TestAllTypes.Builder a = TestAllTypes.newBuilder();
+    a.setOptionalInt32(1);
+    a.setOptionalString("x");
+    a.setOptionalBytes(ByteString.copyFromUtf8("y"));
+    a.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
+    TestAllTypes.Builder b = TestAllTypes.newBuilder();
+    b.setOptionalInt32(0);
+    b.setOptionalString("");
+    b.setOptionalBytes(ByteString.EMPTY);
+    b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
+    a.mergeFrom(b.build());
+    message = a.build();
+    assertEquals(1, message.getOptionalInt32());
+    assertEquals("x", message.getOptionalString());
+    assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes());
+    assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
+
+    // equals()/hashCode() should produce the same results.
+    TestAllTypes empty = TestAllTypes.newBuilder().build();
+    message = builder.build();
+    assertTrue(empty.equals(message));
+    assertTrue(message.equals(empty));
+    assertEquals(empty.hashCode(), message.hashCode());
+  }
+
+  public void testFieldPresenceByReflection() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
+    FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
+    FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
+    FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+
+    // Field not present.
+    TestAllTypes message = TestAllTypes.newBuilder().build();
+    assertFalse(message.hasField(optionalInt32Field));
+    assertFalse(message.hasField(optionalStringField));
+    assertFalse(message.hasField(optionalBytesField));
+    assertFalse(message.hasField(optionalNestedEnumField));
+    assertEquals(0, message.getAllFields().size());
+
+    // Field set to default value is seen as not present.
+    message = TestAllTypes.newBuilder()
+        .setOptionalInt32(0)
+        .setOptionalString("")
+        .setOptionalBytes(ByteString.EMPTY)
+        .setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO)
+        .build();
+    assertFalse(message.hasField(optionalInt32Field));
+    assertFalse(message.hasField(optionalStringField));
+    assertFalse(message.hasField(optionalBytesField));
+    assertFalse(message.hasField(optionalNestedEnumField));
+    assertEquals(0, message.getAllFields().size());
+
+    // Field set to non-default value is seen as present.
+    message = TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("x")
+        .setOptionalBytes(ByteString.copyFromUtf8("y"))
+        .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR)
+        .build();
+    assertTrue(message.hasField(optionalInt32Field));
+    assertTrue(message.hasField(optionalStringField));
+    assertTrue(message.hasField(optionalBytesField));
+    assertTrue(message.hasField(optionalNestedEnumField));
+    assertEquals(4, message.getAllFields().size());
+  }
+
+  public void testMessageField() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    assertFalse(builder.hasOptionalNestedMessage());
+    assertFalse(builder.build().hasOptionalNestedMessage());
+
+    TestAllTypes.NestedMessage.Builder nestedBuilder =
+        builder.getOptionalNestedMessageBuilder();
+    assertTrue(builder.hasOptionalNestedMessage());
+    assertTrue(builder.build().hasOptionalNestedMessage());
+
+    nestedBuilder.setValue(1);
+    assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
+
+    builder.clearOptionalNestedMessage();
+    assertFalse(builder.hasOptionalNestedMessage());
+    assertFalse(builder.build().hasOptionalNestedMessage());
+
+    // Unlike non-message fields, if we set a message field to its default value (i.e.,
+    // default instance), the field should be seen as present.
+    builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    assertTrue(builder.hasOptionalNestedMessage());
+    assertTrue(builder.build().hasOptionalNestedMessage());
+  }
+
+  public void testSerializeAndParse() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalInt32(1234);
+    builder.setOptionalString("hello");
+    builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    // Set an oneof field to its default value and expect it to be serialized (i.e.,
+    // an oneof field set to the default value should be treated as present).
+    builder.setOneofInt32(0);
+    ByteString data = builder.build().toByteString();
+
+    TestAllTypes message = TestAllTypes.parseFrom(data);
+    assertEquals(1234, message.getOptionalInt32());
+    assertEquals("hello", message.getOptionalString());
+    // Fields not set will have the default value.
+    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum());
+    // The message field is set despite that it's set with a default instance.
+    assertTrue(message.hasOptionalNestedMessage());
+    assertEquals(0, message.getOptionalNestedMessage().getValue());
+    // The oneof field set to its default value is also present.
+    assertEquals(
+        TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase());
+  }
+
+  // Regression test for b/16173397
+  // Make sure we haven't screwed up the code generation for repeated fields.
+  public void testRepeatedFields() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalInt32(1234);
+    builder.setOptionalString("hello");
+    builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    builder.addRepeatedInt32(4321);
+    builder.addRepeatedString("world");
+    builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    ByteString data = builder.build().toByteString();
+
+    TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data);
+    assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
+    assertEquals("hello", optionalOnlyMessage.getOptionalString());
+    assertTrue(optionalOnlyMessage.hasOptionalNestedMessage());
+    assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue());
+
+    TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data);
+    assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count());
+    assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0));
+    assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount());
+    assertEquals("world", repeatedOnlyMessage.getRepeatedString(0));
+    assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount());
+    assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue());
+  }
+
+  public void testIsInitialized() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    // Test optional proto2 message fields.
+    UnittestProto.TestRequired.Builder proto2Builder =
+        builder.getOptionalProto2MessageBuilder();
+    assertFalse(builder.isInitialized());
+    assertFalse(builder.buildPartial().isInitialized());
+
+    proto2Builder.setA(1).setB(2).setC(3);
+    assertTrue(builder.isInitialized());
+    assertTrue(builder.buildPartial().isInitialized());
+
+    // Test oneof proto2 message fields.
+    proto2Builder = builder.getOneofProto2MessageBuilder();
+    assertFalse(builder.isInitialized());
+    assertFalse(builder.buildPartial().isInitialized());
+
+    proto2Builder.setA(1).setB(2).setC(3);
+    assertTrue(builder.isInitialized());
+    assertTrue(builder.buildPartial().isInitialized());
+
+    // Test repeated proto2 message fields.
+    proto2Builder = builder.addRepeatedProto2MessageBuilder();
+    assertFalse(builder.isInitialized());
+    assertFalse(builder.buildPartial().isInitialized());
+
+    proto2Builder.setA(1).setB(2).setC(3);
+    assertTrue(builder.isInitialized());
+    assertTrue(builder.buildPartial().isInitialized());
+  }
+
+
+  // Test that unknown fields are dropped.
+  public void testUnknownFields() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalInt32(1234);
+    builder.addRepeatedInt32(5678);
+    TestAllTypes message = builder.build();
+    ByteString data = message.toByteString();
+
+    TestOptionalFieldsOnly optionalOnlyMessage =
+        TestOptionalFieldsOnly.parseFrom(data);
+    // UnknownFieldSet should be empty.
+    assertEquals(
+        0, optionalOnlyMessage.getUnknownFields().toByteString().size());
+    assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
+    message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString());
+    assertEquals(1234, message.getOptionalInt32());
+    // The repeated field is discarded because it's unknown to the optional-only
+    // message.
+    assertEquals(0, message.getRepeatedInt32Count());
+
+    DynamicMessage dynamicOptionalOnlyMessage =
+        DynamicMessage.getDefaultInstance(
+            TestOptionalFieldsOnly.getDescriptor())
+        .getParserForType().parseFrom(data);
+    assertEquals(
+        0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size());
+    assertEquals(optionalOnlyMessage.toByteString(),
+        dynamicOptionalOnlyMessage.toByteString());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
new file mode 100644
index 0000000..88a7574
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -0,0 +1,459 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link FloatArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class FloatArrayListTest extends TestCase {
+  
+  private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
+  private static final FloatArrayList TERTIARY_LIST =
+      newImmutableFloatArrayList(1, 2, 3);
+  
+  private FloatArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new FloatArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(FloatArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addFloat(2);
+    list.addFloat(4);
+    list.addFloat(6);
+    list.addFloat(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1F, 2F, 3F, 4F));
+    Iterator<Float> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1F, (float) list.get(0));
+    assertEquals(1F, (float) iterator.next());
+    list.set(0, 1F);
+    assertEquals(2F, (float) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0F);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1F, (float) TERTIARY_LIST.get(0));
+    assertEquals(2F, (float) TERTIARY_LIST.get(1));
+    assertEquals(3F, (float) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetFloat() {
+    assertEquals(1F, TERTIARY_LIST.getFloat(0));
+    assertEquals(2F, TERTIARY_LIST.getFloat(1));
+    assertEquals(3F, TERTIARY_LIST.getFloat(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, FloatArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addFloat(2);
+    list.addFloat(4);
+    list.addFloat(6);
+    list.addFloat(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16F);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addFloat(2);
+    list.addFloat(4);
+    
+    assertEquals(2F, (float) list.set(0, 0F));
+    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(4F, (float) list.set(1, 0F));
+    assertEquals(0F, list.getFloat(1));
+    
+    try {
+      list.set(-1, 0F);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0F);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetFloat() {
+    list.addFloat(2);
+    list.addFloat(4);
+    
+    assertEquals(2F, list.setFloat(0, 0));
+    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(4F, list.setFloat(1, 0));
+    assertEquals(0F, list.getFloat(1));
+    
+    try {
+      list.setFloat(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setFloat(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2F));
+    assertEquals(asList(2F), list);
+
+    assertTrue(list.add(3F));
+    list.add(0, 4F);
+    assertEquals(asList(4F, 2F, 3F), list);
+    
+    list.add(0, 1F);
+    list.add(0, 0F);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Float.valueOf(5 + i));
+    }
+    assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list);
+    
+    try {
+      list.add(-1, 5F);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5F);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddFloat() {
+    assertEquals(0, list.size());
+
+    list.addFloat(2);
+    assertEquals(asList(2F), list);
+
+    list.addFloat(3);
+    assertEquals(asList(2F, 3F), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1F)));
+    assertEquals(1, list.size());
+    assertEquals(1F, (float) list.get(0));
+    assertEquals(1F, list.getFloat(0));
+    
+    assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
+    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list);
+
+    assertFalse(list.addAll(Collections.<Float>emptyList()));
+    assertFalse(list.addAll(FloatArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1F, (float) list.remove(0));
+    assertEquals(asList(2F, 3F), list);
+
+    assertTrue(list.remove(Float.valueOf(3)));
+    assertEquals(asList(2F), list);
+
+    assertFalse(list.remove(Float.valueOf(3)));
+    assertEquals(asList(2F), list);
+
+    assertEquals(2F, (float) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(FloatArrayList list) {
+    if (list.contains(1F)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new FloatArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addFloat(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setFloat(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static FloatArrayList newImmutableFloatArrayList(int... elements) {
+    FloatArrayList list = new FloatArrayList();
+    for (int element : elements) {
+      list.addFloat(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
new file mode 100644
index 0000000..b7eaebf
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
@@ -0,0 +1,48 @@
+// 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.
+
+package com.google.protobuf;
+
+/**
+ * A prerun for a test suite that allows running the full protocol buffer
+ * tests in a mode that disables the optimization for not using
+ * {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are
+ * requested. This allows us to run all the tests through both code paths
+ * and ensures that both code paths produce identical results.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class ForceFieldBuildersPreRun implements Runnable {
+
+  @Override
+  public void run() {
+    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
new file mode 100644
index 0000000..a9b8b63
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -0,0 +1,1676 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.test.UnittestImport;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.MultipleFilesTestProto;
+import protobuf_unittest.NestedExtension.MyNestedExtension;
+import protobuf_unittest.NestedExtensionLite.MyNestedExtensionLite;
+import protobuf_unittest.NonNestedExtension;
+import protobuf_unittest.NonNestedExtension.MessageToBeExtended;
+import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
+import protobuf_unittest.NonNestedExtensionLite;
+import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
+import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
+import protobuf_unittest.OuterClassNameTest2OuterClass;
+import protobuf_unittest.OuterClassNameTest3OuterClass;
+import protobuf_unittest.OuterClassNameTestOuterClass;
+import protobuf_unittest.ServiceWithNoOuter;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
+import protobuf_unittest.UnittestProto.NestedTestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Unit test for generated messages and generated code.  See also
+ * {@link MessageTest}, which tests some generated message functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class GeneratedMessageTest extends TestCase {
+  TestUtil.ReflectionTester reflectionTester =
+    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+  public void testDefaultInstance() throws Exception {
+    assertSame(TestAllTypes.getDefaultInstance(),
+               TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
+    assertSame(TestAllTypes.getDefaultInstance(),
+               TestAllTypes.newBuilder().getDefaultInstanceForType());
+  }
+
+  public void testMessageOrBuilder() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+  }
+
+  public void testUsingBuilderMultipleTimes() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    // primitive field scalar and repeated
+    builder.setOptionalSfixed64(100);
+    builder.addRepeatedInt32(100);
+    // enum field scalar and repeated
+    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    // proto field scalar and repeated
+    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(1));
+    builder.addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(1));
+
+    TestAllTypes value1 = builder.build();
+
+    assertEquals(100, value1.getOptionalSfixed64());
+    assertEquals(100, value1.getRepeatedInt32(0));
+    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
+        value1.getOptionalImportEnum());
+    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
+        value1.getRepeatedImportEnum(0));
+    assertEquals(1, value1.getOptionalForeignMessage().getC());
+    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
+
+    // Make sure that builder didn't update previously created values
+    builder.setOptionalSfixed64(200);
+    builder.setRepeatedInt32(0, 200);
+    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_FOO);
+    builder.setRepeatedImportEnum(0, UnittestImport.ImportEnum.IMPORT_FOO);
+    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(2));
+    builder.setRepeatedForeignMessage(0, ForeignMessage.newBuilder().setC(2));
+
+    TestAllTypes value2 = builder.build();
+
+    // Make sure value1 didn't change.
+    assertEquals(100, value1.getOptionalSfixed64());
+    assertEquals(100, value1.getRepeatedInt32(0));
+    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
+        value1.getOptionalImportEnum());
+    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
+        value1.getRepeatedImportEnum(0));
+    assertEquals(1, value1.getOptionalForeignMessage().getC());
+    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
+
+    // Make sure value2 is correct
+    assertEquals(200, value2.getOptionalSfixed64());
+    assertEquals(200, value2.getRepeatedInt32(0));
+    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO,
+        value2.getOptionalImportEnum());
+    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO,
+        value2.getRepeatedImportEnum(0));
+    assertEquals(2, value2.getOptionalForeignMessage().getC());
+    assertEquals(2, value2.getRepeatedForeignMessage(0).getC());
+  }
+
+  public void testProtosShareRepeatedArraysIfDidntChange() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addRepeatedInt32(100);
+    builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance());
+
+    TestAllTypes value1 = builder.build();
+    TestAllTypes value2 = value1.toBuilder().build();
+
+    assertSame(value1.getRepeatedInt32List(), value2.getRepeatedInt32List());
+    assertSame(value1.getRepeatedForeignMessageList(),
+        value2.getRepeatedForeignMessageList());
+  }
+
+  public void testRepeatedArraysAreImmutable() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addRepeatedInt32(100);
+    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
+    builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance());
+    assertIsUnmodifiable(builder.getRepeatedInt32List());
+    assertIsUnmodifiable(builder.getRepeatedImportEnumList());
+    assertIsUnmodifiable(builder.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(builder.getRepeatedFloatList());
+
+
+    TestAllTypes value = builder.build();
+    assertIsUnmodifiable(value.getRepeatedInt32List());
+    assertIsUnmodifiable(value.getRepeatedImportEnumList());
+    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(value.getRepeatedFloatList());
+  }
+
+  public void testParsedMessagesAreImmutable() throws Exception {
+    TestAllTypes value = TestAllTypes.parser().parseFrom(TestUtil.getAllSet().toByteString());
+    assertIsUnmodifiable(value.getRepeatedInt32List());
+    assertIsUnmodifiable(value.getRepeatedInt64List());
+    assertIsUnmodifiable(value.getRepeatedUint32List());
+    assertIsUnmodifiable(value.getRepeatedUint64List());
+    assertIsUnmodifiable(value.getRepeatedSint32List());
+    assertIsUnmodifiable(value.getRepeatedSint64List());
+    assertIsUnmodifiable(value.getRepeatedFixed32List());
+    assertIsUnmodifiable(value.getRepeatedFixed64List());
+    assertIsUnmodifiable(value.getRepeatedSfixed32List());
+    assertIsUnmodifiable(value.getRepeatedSfixed64List());
+    assertIsUnmodifiable(value.getRepeatedFloatList());
+    assertIsUnmodifiable(value.getRepeatedDoubleList());
+    assertIsUnmodifiable(value.getRepeatedBoolList());
+    assertIsUnmodifiable(value.getRepeatedStringList());
+    assertIsUnmodifiable(value.getRepeatedBytesList());
+    assertIsUnmodifiable(value.getRepeatedGroupList());
+    assertIsUnmodifiable(value.getRepeatedNestedMessageList());
+    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
+    assertIsUnmodifiable(value.getRepeatedImportMessageList());
+    assertIsUnmodifiable(value.getRepeatedNestedEnumList());
+    assertIsUnmodifiable(value.getRepeatedForeignEnumList());
+    assertIsUnmodifiable(value.getRepeatedImportEnumList());
+  }
+
+  private void assertIsUnmodifiable(List<?> list) {
+    if (list == Collections.emptyList()) {
+      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
+    } else {
+      try {
+        list.clear();
+        fail("List wasn't immutable");
+      } catch (UnsupportedOperationException e) {
+        // good
+      }
+    }
+  }
+
+  public void testSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      builder.setOptionalString(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalBytes(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedMessage(
+          (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setOptionalNestedEnum(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedString(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedBytes(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedMessage(
+          (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.addRepeatedNestedEnum(null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testRepeatedSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestUtil.modifyRepeatedFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertRepeatedFieldsModified(message);
+  }
+
+  public void testRepeatedSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    builder.addRepeatedString("one");
+    builder.addRepeatedString("two");
+    try {
+      builder.setRepeatedString(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedBytes(TestUtil.toBytes("one"));
+    builder.addRepeatedBytes(TestUtil.toBytes("two"));
+    try {
+      builder.setRepeatedBytes(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    builder.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(456).build());
+    try {
+      builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.setRepeatedNestedMessage(
+          1, (TestAllTypes.NestedMessage.Builder) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.FOO);
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
+    try {
+      builder.setRepeatedNestedEnum(1, null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testRepeatedAppend() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
+    builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+
+    ForeignMessage foreignMessage =
+        ForeignMessage.newBuilder().setC(12).build();
+    builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
+
+    TestAllTypes message = builder.build();
+    assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
+    assertEquals(message.getRepeatedForeignEnumList(),
+        Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+    assertEquals(1, message.getRepeatedForeignMessageCount());
+    assertEquals(12, message.getRepeatedForeignMessage(0).getC());
+  }
+
+  public void testRepeatedAppendRejectsNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    ForeignMessage foreignMessage =
+        ForeignMessage.newBuilder().setC(12).build();
+    try {
+      builder.addAllRepeatedForeignMessage(
+          Arrays.asList(foreignMessage, (ForeignMessage) null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedForeignEnum(
+          Arrays.asList(ForeignEnum.FOREIGN_BAZ, null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedString(Arrays.asList("one", null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+
+    try {
+      builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null));
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+  
+  public void testRepeatedAppendIterateOnlyOnce() throws Exception {
+    // Create a Iterable that can only be iterated once.
+    Iterable<String> stringIterable = new Iterable<String>() {
+      private boolean called = false;
+      @Override
+      public Iterator<String> iterator() {
+        if (called) {
+          throw new IllegalStateException();
+        }
+        called = true;
+        return Arrays.asList("one", "two", "three").iterator();
+      }
+    };
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addAllRepeatedString(stringIterable);
+    assertEquals(3, builder.getRepeatedStringCount());
+    assertEquals("one", builder.getRepeatedString(0));
+    assertEquals("two", builder.getRepeatedString(1));
+    assertEquals("three", builder.getRepeatedString(2));
+
+    try {
+      builder.addAllRepeatedString(stringIterable);
+      fail("Exception was not thrown");
+    } catch (IllegalStateException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testMergeFromOtherRejectsNull() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      builder.mergeFrom((TestAllTypes) null);
+      fail("Exception was not thrown");
+    } catch (NullPointerException e) {
+      // We expect this exception.
+    }
+  }
+
+  public void testSettingForeignMessageUsingBuilder() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        // Pass builder for foreign message instance.
+        .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123))
+        .build();
+    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+        // Create expected version passing foreign message instance explicitly.
+        .setOptionalForeignMessage(
+            ForeignMessage.newBuilder().setC(123).build())
+        .build();
+    // TODO(ngd): Upgrade to using real #equals method once implemented
+    assertEquals(expectedMessage.toString(), message.toString());
+  }
+
+  public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        // Pass builder for foreign message instance.
+        .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456))
+        .build();
+    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+        // Create expected version passing foreign message instance explicitly.
+        .addRepeatedForeignMessage(
+            ForeignMessage.newBuilder().setC(456).build())
+        .build();
+    assertEquals(expectedMessage.toString(), message.toString());
+  }
+
+  public void testDefaults() throws Exception {
+    TestUtil.assertClear(TestAllTypes.getDefaultInstance());
+    TestUtil.assertClear(TestAllTypes.newBuilder().build());
+
+    TestExtremeDefaultValues message =
+        TestExtremeDefaultValues.getDefaultInstance();
+    assertEquals("\u1234", message.getUtf8String());
+    assertEquals(Double.POSITIVE_INFINITY, message.getInfDouble());
+    assertEquals(Double.NEGATIVE_INFINITY, message.getNegInfDouble());
+    assertTrue(Double.isNaN(message.getNanDouble()));
+    assertEquals(Float.POSITIVE_INFINITY, message.getInfFloat());
+    assertEquals(Float.NEGATIVE_INFINITY, message.getNegInfFloat());
+    assertTrue(Float.isNaN(message.getNanFloat()));
+    assertEquals("? ? ?? ?? ??? ??/ ??-", message.getCppTrigraph());
+  }
+
+  public void testClear() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.assertClear(builder);
+    TestUtil.setAllFields(builder);
+    builder.clear();
+    TestUtil.assertClear(builder);
+  }
+
+  public void testReflectionGetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    reflectionTester.assertAllFieldsSetViaReflection(builder);
+
+    TestAllTypes message = builder.build();
+    reflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testReflectionSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    TestUtil.assertAllFieldsSet(builder);
+
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+  }
+
+  public void testReflectionSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testReflectionRepeatedSetters() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    TestUtil.assertRepeatedFieldsModified(builder);
+
+    TestAllTypes message = builder.build();
+    TestUtil.assertRepeatedFieldsModified(message);
+  }
+
+  public void testReflectionRepeatedSettersRejectNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+  }
+
+  public void testReflectionDefaults() throws Exception {
+    reflectionTester.assertClearViaReflection(
+      TestAllTypes.getDefaultInstance());
+    reflectionTester.assertClearViaReflection(
+      TestAllTypes.newBuilder().build());
+  }
+
+  public void testReflectionGetOneof() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Descriptors.OneofDescriptor oneof =
+        TestAllTypes.getDescriptor().getOneofs().get(0);
+    Descriptors.FieldDescriptor field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+    assertSame(field, builder.getOneofFieldDescriptor(oneof));
+
+    TestAllTypes message = builder.build();
+    assertSame(field, message.getOneofFieldDescriptor(oneof));
+  }
+
+  public void testReflectionClearOneof() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    reflectionTester.setAllFieldsViaReflection(builder);
+    Descriptors.OneofDescriptor oneof =
+        TestAllTypes.getDescriptor().getOneofs().get(0);
+    Descriptors.FieldDescriptor field =
+        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
+
+    assertTrue(builder.hasOneof(oneof));
+    assertTrue(builder.hasField(field));
+    builder.clearOneof(oneof);
+    assertFalse(builder.hasOneof(oneof));
+    assertFalse(builder.hasField(field));
+  }
+
+  public void testEnumInterface() throws Exception {
+    assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
+        instanceof ProtocolMessageEnum);
+  }
+
+  public void testEnumMap() throws Exception {
+    Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
+
+    for (ForeignEnum value : ForeignEnum.values()) {
+      assertEquals(value, map.findValueByNumber(value.getNumber()));
+    }
+
+    assertTrue(map.findValueByNumber(12345) == null);
+  }
+
+  public void testParsePackedToUnpacked() throws Exception {
+    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
+    TestUnpackedTypes message =
+      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+    TestUtil.assertUnpackedFieldsSet(message);
+  }
+
+  public void testParseUnpackedToPacked() throws Exception {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    TestPackedTypes message =
+      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
+    TestUtil.assertPackedFieldsSet(message);
+  }
+
+  // =================================================================
+  // Extensions.
+
+  TestUtil.ReflectionTester extensionsReflectionTester =
+    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+                                  TestUtil.getExtensionRegistry());
+
+  public void testExtensionMessageOrBuilder() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestAllExtensions message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testExtensionRepeatedSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    TestUtil.modifyRepeatedExtensions(builder);
+    TestAllExtensions message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testExtensionDefaults() throws Exception {
+    TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
+    TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
+  }
+
+  public void testUnsetRepeatedExtensionGetField() {
+    TestAllExtensions message = TestAllExtensions.getDefaultInstance();
+    Object value;
+
+    value = message.getField(UnittestProto.repeatedStringExtension.getDescriptor());
+    assertTrue(value instanceof List);
+    assertTrue(((List<?>) value).isEmpty());
+    assertIsUnmodifiable((List<?>) value);
+
+    value = message.getField(UnittestProto.repeatedNestedMessageExtension.getDescriptor());
+    assertTrue(value instanceof List);
+    assertTrue(((List<?>) value).isEmpty());
+    assertIsUnmodifiable((List<?>) value);
+  }
+
+  public void testExtensionReflectionGetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TestUtil.setAllExtensions(builder);
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(builder);
+
+    TestAllExtensions message = builder.build();
+    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+  }
+
+  public void testExtensionReflectionSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    TestUtil.assertAllExtensionsSet(builder);
+
+    TestAllExtensions message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testExtensionReflectionSettersRejectNull() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+  }
+
+  public void testExtensionReflectionRepeatedSetters() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.setAllFieldsViaReflection(builder);
+    extensionsReflectionTester.modifyRepeatedFieldsViaReflection(builder);
+    TestUtil.assertRepeatedExtensionsModified(builder);
+
+    TestAllExtensions message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testExtensionReflectionRepeatedSettersRejectNull()
+      throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull(
+        builder);
+  }
+
+  public void testExtensionReflectionDefaults() throws Exception {
+    extensionsReflectionTester.assertClearViaReflection(
+      TestAllExtensions.getDefaultInstance());
+    extensionsReflectionTester.assertClearViaReflection(
+      TestAllExtensions.newBuilder().build());
+  }
+
+  public void testClearExtension() throws Exception {
+    // clearExtension() is not actually used in TestUtil, so try it manually.
+    assertFalse(
+      TestAllExtensions.newBuilder()
+        .setExtension(UnittestProto.optionalInt32Extension, 1)
+        .clearExtension(UnittestProto.optionalInt32Extension)
+        .hasExtension(UnittestProto.optionalInt32Extension));
+    assertEquals(0,
+      TestAllExtensions.newBuilder()
+        .addExtension(UnittestProto.repeatedInt32Extension, 1)
+        .clearExtension(UnittestProto.repeatedInt32Extension)
+        .getExtensionCount(UnittestProto.repeatedInt32Extension));
+  }
+
+  public void testExtensionCopy() throws Exception {
+    TestAllExtensions original = TestUtil.getAllExtensionsSet();
+    TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
+    TestUtil.assertAllExtensionsSet(copy);
+  }
+
+  public void testExtensionMergeFrom() throws Exception {
+    TestAllExtensions original =
+      TestAllExtensions.newBuilder()
+        .setExtension(UnittestProto.optionalInt32Extension, 1).build();
+    TestAllExtensions merged =
+        TestAllExtensions.newBuilder().mergeFrom(original).build();
+    assertTrue(merged.hasExtension(UnittestProto.optionalInt32Extension));
+    assertEquals(
+        1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
+  }
+
+  // =================================================================
+  // Lite Extensions.
+
+  // We test lite extensions directly because they have a separate
+  // implementation from full extensions.  In contrast, we do not test
+  // lite fields directly since they are implemented exactly the same as
+  // regular fields.
+
+  public void testLiteExtensionMessageOrBuilder() throws Exception {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    TestUtilLite.setAllExtensions(builder);
+    TestUtil.assertAllExtensionsSet(builder);
+
+    TestAllExtensionsLite message = builder.build();
+    TestUtil.assertAllExtensionsSet(message);
+  }
+
+  public void testLiteExtensionRepeatedSetters() throws Exception {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    TestUtilLite.setAllExtensions(builder);
+    TestUtilLite.modifyRepeatedExtensions(builder);
+    TestUtil.assertRepeatedExtensionsModified(builder);
+
+    TestAllExtensionsLite message = builder.build();
+    TestUtil.assertRepeatedExtensionsModified(message);
+  }
+
+  public void testLiteExtensionDefaults() throws Exception {
+    TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
+    TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
+  }
+
+  public void testClearLiteExtension() throws Exception {
+    // clearExtension() is not actually used in TestUtil, so try it manually.
+    assertFalse(
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
+        .clearExtension(UnittestLite.optionalInt32ExtensionLite)
+        .hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(0,
+      TestAllExtensionsLite.newBuilder()
+        .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
+        .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
+        .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
+  }
+
+  public void testLiteExtensionCopy() throws Exception {
+    TestAllExtensionsLite original = TestUtilLite.getAllLiteExtensionsSet();
+    TestAllExtensionsLite copy =
+        TestAllExtensionsLite.newBuilder(original).build();
+    TestUtil.assertAllExtensionsSet(copy);
+  }
+
+  public void testLiteExtensionMergeFrom() throws Exception {
+    TestAllExtensionsLite original =
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
+    TestAllExtensionsLite merged =
+        TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
+    assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
+  }
+
+  // =================================================================
+  // multiple_files_test
+
+  // Test that custom options of an file level enum are properly initialized.
+  // This test needs to be put before any other access to MultipleFilesTestProto
+  // or messages defined in multiple_files_test.proto because the class loading
+  // order affects initialization process of custom options.
+  public void testEnumValueOptionsInMultipleFilesMode() throws Exception {
+    assertEquals(12345, EnumWithNoOuter.FOO.getValueDescriptor().getOptions()
+        .getExtension(MultipleFilesTestProto.enumValueOption).intValue());
+  }
+
+  public void testMultipleFilesOption() throws Exception {
+    // We mostly just want to check that things compile.
+    MessageWithNoOuter message =
+      MessageWithNoOuter.newBuilder()
+        .setNested(MessageWithNoOuter.NestedMessage.newBuilder().setI(1))
+        .addForeign(TestAllTypes.newBuilder().setOptionalInt32(1))
+        .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
+        .setForeignEnum(EnumWithNoOuter.BAR)
+        .build();
+    assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
+
+    assertEquals(MultipleFilesTestProto.getDescriptor(),
+                 MessageWithNoOuter.getDescriptor().getFile());
+
+    Descriptors.FieldDescriptor field =
+      MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
+    assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(),
+                 message.getField(field));
+
+    assertEquals(MultipleFilesTestProto.getDescriptor(),
+                 ServiceWithNoOuter.getDescriptor().getFile());
+
+    assertFalse(
+      TestAllExtensions.getDefaultInstance().hasExtension(
+        MultipleFilesTestProto.extensionWithOuter));
+  }
+
+  public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize()
+    throws Exception {
+    TestOptionalOptimizedForSize message =
+        TestOptionalOptimizedForSize.getDefaultInstance();
+    assertTrue(message.isInitialized());
+
+    message = TestOptionalOptimizedForSize.newBuilder().setO(
+        TestRequiredOptimizedForSize.newBuilder().buildPartial()
+        ).buildPartial();
+    assertFalse(message.isInitialized());
+
+    message = TestOptionalOptimizedForSize.newBuilder().setO(
+        TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial()
+        ).buildPartial();
+    assertTrue(message.isInitialized());
+  }
+
+  public void testUninitializedExtensionInOptimizedForSize()
+      throws Exception {
+    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().buildPartial());
+    assertFalse(builder.isInitialized());
+    assertFalse(builder.buildPartial().isInitialized());
+
+    builder = TestOptimizedForSize.newBuilder();
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().setX(10).buildPartial());
+    assertTrue(builder.isInitialized());
+    assertTrue(builder.buildPartial().isInitialized());
+  }
+
+  public void testToBuilder() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes message = builder.build();
+    TestUtil.assertAllFieldsSet(message);
+    TestUtil.assertAllFieldsSet(message.toBuilder().build());
+  }
+
+  public void testFieldConstantValues() throws Exception {
+    assertEquals(TestAllTypes.NestedMessage.BB_FIELD_NUMBER, 1);
+    assertEquals(TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 1);
+    assertEquals(TestAllTypes.OPTIONALGROUP_FIELD_NUMBER, 16);
+    assertEquals(TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER, 18);
+    assertEquals(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 21);
+    assertEquals(TestAllTypes.REPEATED_INT32_FIELD_NUMBER, 31);
+    assertEquals(TestAllTypes.REPEATEDGROUP_FIELD_NUMBER, 46);
+    assertEquals(TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER, 48);
+    assertEquals(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 51);
+  }
+
+  public void testExtensionConstantValues() throws Exception {
+    assertEquals(UnittestProto.TestRequired.SINGLE_FIELD_NUMBER, 1000);
+    assertEquals(UnittestProto.TestRequired.MULTI_FIELD_NUMBER, 1001);
+    assertEquals(UnittestProto.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER, 1);
+    assertEquals(UnittestProto.OPTIONALGROUP_EXTENSION_FIELD_NUMBER, 16);
+    assertEquals(
+      UnittestProto.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 18);
+    assertEquals(UnittestProto.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 21);
+    assertEquals(UnittestProto.REPEATED_INT32_EXTENSION_FIELD_NUMBER, 31);
+    assertEquals(UnittestProto.REPEATEDGROUP_EXTENSION_FIELD_NUMBER, 46);
+    assertEquals(
+      UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48);
+    assertEquals(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 51);
+  }
+
+  public void testRecursiveMessageDefaultInstance() throws Exception {
+    UnittestProto.TestRecursiveMessage message =
+        UnittestProto.TestRecursiveMessage.getDefaultInstance();
+    assertTrue(message != null);
+    assertNotNull(message.getA());
+    assertTrue(message.getA() == message);
+  }
+
+  public void testSerialize() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestUtil.setAllFields(builder);
+    TestAllTypes expected = builder.build();
+    ObjectOutputStream out = new ObjectOutputStream(baos);
+    try {
+      out.writeObject(expected);
+    } finally {
+      out.close();
+    }
+    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+    ObjectInputStream in = new ObjectInputStream(bais);
+    TestAllTypes actual = (TestAllTypes) in.readObject();
+    assertEquals(expected, actual);
+  }
+
+  public void testSerializePartial() throws Exception {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes expected = builder.buildPartial();
+    ObjectOutputStream out = new ObjectOutputStream(baos);
+    try {
+      out.writeObject(expected);
+    } finally {
+      out.close();
+    }
+    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+    ObjectInputStream in = new ObjectInputStream(bais);
+    TestAllTypes actual = (TestAllTypes) in.readObject();
+    assertEquals(expected, actual);
+  }
+
+  public void testEnumValues() {
+     assertEquals(
+         TestAllTypes.NestedEnum.BAR.getNumber(),
+         TestAllTypes.NestedEnum.BAR_VALUE);
+    assertEquals(
+        TestAllTypes.NestedEnum.BAZ.getNumber(),
+        TestAllTypes.NestedEnum.BAZ_VALUE);
+    assertEquals(
+        TestAllTypes.NestedEnum.FOO.getNumber(),
+        TestAllTypes.NestedEnum.FOO_VALUE);
+  }
+
+  public void testNonNestedExtensionInitialization() {
+    assertTrue(NonNestedExtension.nonNestedExtension
+               .getMessageDefaultInstance() instanceof MyNonNestedExtension);
+    assertEquals("nonNestedExtension",
+                 NonNestedExtension.nonNestedExtension.getDescriptor().getName());
+  }
+
+  public void testNestedExtensionInitialization() {
+    assertTrue(MyNestedExtension.recursiveExtension.getMessageDefaultInstance()
+               instanceof MessageToBeExtended);
+    assertEquals("recursiveExtension",
+                 MyNestedExtension.recursiveExtension.getDescriptor().getName());
+  }
+
+  public void testNonNestedExtensionLiteInitialization() {
+    assertTrue(NonNestedExtensionLite.nonNestedExtensionLite
+               .getMessageDefaultInstance() instanceof MyNonNestedExtensionLite);
+  }
+
+  public void testNestedExtensionLiteInitialization() {
+    assertTrue(MyNestedExtensionLite.recursiveExtensionLite
+               .getMessageDefaultInstance() instanceof MessageLiteToBeExtended);
+  }
+
+  public void testInvalidations() throws Exception {
+    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+    TestAllTypes.NestedMessage nestedMessage1 =
+        TestAllTypes.NestedMessage.newBuilder().build();
+    TestAllTypes.NestedMessage nestedMessage2 =
+        TestAllTypes.NestedMessage.newBuilder().build();
+
+    // Set all three flavors (enum, primitive, message and singular/repeated)
+    // and verify no invalidations fired
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+
+    TestAllTypes.Builder builder = (TestAllTypes.Builder)
+        ((GeneratedMessage) TestAllTypes.getDefaultInstance()).
+            newBuilderForType(mockParent);
+    builder.setOptionalInt32(1);
+    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
+    builder.setOptionalNestedMessage(nestedMessage1);
+    builder.addRepeatedInt32(1);
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
+    builder.addRepeatedNestedMessage(nestedMessage1);
+    assertEquals(0, mockParent.getInvalidationCount());
+
+    // Now tell it we want changes and make sure it's only fired once
+    // And do this for each flavor
+
+    // primitive single
+    builder.buildPartial();
+    builder.setOptionalInt32(2);
+    builder.setOptionalInt32(3);
+    assertEquals(1, mockParent.getInvalidationCount());
+
+    // enum single
+    builder.buildPartial();
+    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ);
+    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
+    assertEquals(2, mockParent.getInvalidationCount());
+
+    // message single
+    builder.buildPartial();
+    builder.setOptionalNestedMessage(nestedMessage2);
+    builder.setOptionalNestedMessage(nestedMessage1);
+    assertEquals(3, mockParent.getInvalidationCount());
+
+    // primitive repeated
+    builder.buildPartial();
+    builder.addRepeatedInt32(2);
+    builder.addRepeatedInt32(3);
+    assertEquals(4, mockParent.getInvalidationCount());
+
+    // enum repeated
+    builder.buildPartial();
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
+    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
+    assertEquals(5, mockParent.getInvalidationCount());
+
+    // message repeated
+    builder.buildPartial();
+    builder.addRepeatedNestedMessage(nestedMessage2);
+    builder.addRepeatedNestedMessage(nestedMessage1);
+    assertEquals(6, mockParent.getInvalidationCount());
+
+  }
+
+  public void testInvalidations_Extensions() throws Exception {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+
+    TestAllExtensions.Builder builder = (TestAllExtensions.Builder)
+        ((GeneratedMessage) TestAllExtensions.getDefaultInstance()).
+            newBuilderForType(mockParent);
+
+    builder.addExtension(UnittestProto.repeatedInt32Extension, 1);
+    builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 2);
+    builder.clearExtension(UnittestProto.repeatedInt32Extension);
+    assertEquals(0, mockParent.getInvalidationCount());
+
+    // Now tell it we want changes and make sure it's only fired once
+    builder.buildPartial();
+    builder.addExtension(UnittestProto.repeatedInt32Extension, 2);
+    builder.addExtension(UnittestProto.repeatedInt32Extension, 3);
+    assertEquals(1, mockParent.getInvalidationCount());
+
+    builder.buildPartial();
+    builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 4);
+    builder.setExtension(UnittestProto.repeatedInt32Extension, 1, 5);
+    assertEquals(2, mockParent.getInvalidationCount());
+
+    builder.buildPartial();
+    builder.clearExtension(UnittestProto.repeatedInt32Extension);
+    builder.clearExtension(UnittestProto.repeatedInt32Extension);
+    assertEquals(3, mockParent.getInvalidationCount());
+  }
+
+  public void testBaseMessageOrBuilder() {
+    // Mostly just makes sure the base interface exists and has some methods.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes message = builder.buildPartial();
+    TestAllTypesOrBuilder builderAsInterface = (TestAllTypesOrBuilder) builder;
+    TestAllTypesOrBuilder messageAsInterface = (TestAllTypesOrBuilder) message;
+
+    assertEquals(
+        messageAsInterface.getDefaultBool(),
+        messageAsInterface.getDefaultBool());
+    assertEquals(
+        messageAsInterface.getOptionalDouble(),
+        messageAsInterface.getOptionalDouble());
+  }
+
+  public void testMessageOrBuilderGetters() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    // single fields
+    assertSame(ForeignMessage.getDefaultInstance(),
+        builder.getOptionalForeignMessageOrBuilder());
+    ForeignMessage.Builder subBuilder =
+        builder.getOptionalForeignMessageBuilder();
+    assertSame(subBuilder, builder.getOptionalForeignMessageOrBuilder());
+
+    // repeated fields
+    ForeignMessage m0 = ForeignMessage.newBuilder().buildPartial();
+    ForeignMessage m1 = ForeignMessage.newBuilder().buildPartial();
+    ForeignMessage m2 = ForeignMessage.newBuilder().buildPartial();
+    builder.addRepeatedForeignMessage(m0);
+    builder.addRepeatedForeignMessage(m1);
+    builder.addRepeatedForeignMessage(m2);
+    assertSame(m0, builder.getRepeatedForeignMessageOrBuilder(0));
+    assertSame(m1, builder.getRepeatedForeignMessageOrBuilder(1));
+    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
+    ForeignMessage.Builder b0 = builder.getRepeatedForeignMessageBuilder(0);
+    ForeignMessage.Builder b1 = builder.getRepeatedForeignMessageBuilder(1);
+    assertSame(b0, builder.getRepeatedForeignMessageOrBuilder(0));
+    assertSame(b1, builder.getRepeatedForeignMessageOrBuilder(1));
+    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
+
+    List<? extends ForeignMessageOrBuilder> messageOrBuilderList =
+        builder.getRepeatedForeignMessageOrBuilderList();
+    assertSame(b0, messageOrBuilderList.get(0));
+    assertSame(b1, messageOrBuilderList.get(1));
+    assertSame(m2, messageOrBuilderList.get(2));
+  }
+
+  public void testGetFieldBuilder() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("optional_nested_message");
+    FieldDescriptor foreignFieldDescriptor =
+        descriptor.findFieldByName("optional_foreign_message");
+    FieldDescriptor importFieldDescriptor =
+        descriptor.findFieldByName("optional_import_message");
+
+    // Mutate the message with new field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
+    Message.Builder fieldBuilder1 = builder1.newBuilderForField(fieldDescriptor)
+        .mergeFrom((Message) builder1.getField(fieldDescriptor));
+    FieldDescriptor subFieldDescriptor1 =
+        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder1.setField(subFieldDescriptor1, 1);
+    builder1.setField(fieldDescriptor, fieldBuilder1.build());
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField(
+        foreignFieldDescriptor)
+        .mergeFrom((Message) builder1.getField(foreignFieldDescriptor));
+    FieldDescriptor subForeignFieldDescriptor1 =
+        foreignFieldBuilder1.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2);
+    builder1.setField(foreignFieldDescriptor, foreignFieldBuilder1.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder1 = builder1.newBuilderForField(
+        importFieldDescriptor)
+        .mergeFrom((Message) builder1.getField(importFieldDescriptor));
+    FieldDescriptor subImportFieldDescriptor1 =
+        importFieldBuilder1.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder1.setField(subImportFieldDescriptor1, 3);
+    builder1.setField(importFieldDescriptor, importFieldBuilder1.build());
+
+    Message newMessage1 = builder1.build();
+
+    // Mutate the message with existing field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
+    Message.Builder fieldBuilder2 = builder2.getFieldBuilder(fieldDescriptor);
+    FieldDescriptor subFieldDescriptor2 =
+        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder2.setField(subFieldDescriptor2, 1);
+    builder2.setField(fieldDescriptor, fieldBuilder2.build());
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(
+        foreignFieldDescriptor)
+        .mergeFrom((Message) builder2.getField(foreignFieldDescriptor));
+    FieldDescriptor subForeignFieldDescriptor2 =
+        foreignFieldBuilder2.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2);
+    builder2.setField(foreignFieldDescriptor, foreignFieldBuilder2.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder2 = builder2.newBuilderForField(
+        importFieldDescriptor)
+        .mergeFrom((Message) builder2.getField(importFieldDescriptor));
+    FieldDescriptor subImportFieldDescriptor2 =
+        importFieldBuilder2.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder2.setField(subImportFieldDescriptor2, 3);
+    builder2.setField(importFieldDescriptor, importFieldBuilder2.build());
+
+    Message newMessage2 = builder2.build();
+
+    // These two messages should be equal.
+    assertEquals(newMessage1, newMessage2);
+  }
+
+  public void testGetFieldBuilderWithInitializedValue() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("optional_nested_message");
+
+    // Before setting field, builder is initialized by default value. 
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    NestedMessage.Builder fieldBuilder =
+        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+    assertEquals(0, fieldBuilder.getBb());
+
+    // Setting field value with new field builder instance.
+    builder = TestAllTypes.newBuilder();
+    NestedMessage.Builder newFieldBuilder =
+        builder.getOptionalNestedMessageBuilder();
+    newFieldBuilder.setBb(2);
+    // Then get the field builder instance by getFieldBuilder().
+    fieldBuilder =
+        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
+    // It should contain new value.
+    assertEquals(2, fieldBuilder.getBb());
+    // These two builder should be equal.
+    assertSame(fieldBuilder, newFieldBuilder);
+  }
+
+  public void testGetFieldBuilderNotSupportedException() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      builder.getFieldBuilder(descriptor.findFieldByName("optional_int32"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("optional_nested_enum"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(descriptor.findFieldByName("repeated_int32"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("repeated_nested_enum"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getFieldBuilder(
+          descriptor.findFieldByName("repeated_nested_message"));
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+  }
+
+  // Test that when the default outer class name conflicts with another type
+  // defined in the proto the compiler will append a suffix to avoid the
+  // conflict.
+  public void testConflictingOuterClassName() {
+    // We just need to make sure we can refer to the outer class with the
+    // expected name. There is nothing else to test.
+    OuterClassNameTestOuterClass.OuterClassNameTest message =
+        OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build();
+    assertTrue(message.getDescriptorForType() ==
+        OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
+
+    OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2
+        message2 = OuterClassNameTest2OuterClass.TestMessage2.NestedMessage
+            .OuterClassNameTest2.newBuilder().build();
+    assertEquals(0, message2.getSerializedSize());
+
+    OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3
+        enumValue = OuterClassNameTest3OuterClass.TestMessage3.NestedMessage
+            .OuterClassNameTest3.DUMMY_VALUE;
+    assertEquals(1, enumValue.getNumber());
+  }
+
+  // =================================================================
+  // oneof generated code test
+  public void testOneofEnumCase() throws Exception {
+    TestOneof2 message = TestOneof2.newBuilder()
+        .setFooInt(123).setFooString("foo").setFooCord("bar").build();
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+  }
+
+  public void testClearOneof() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123);
+    assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase());
+    builder.clearFoo();
+    assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase());
+  }
+
+  public void testSetOneofClearsOthers() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestOneof2 message =
+        builder.setFooInt(123).setFooString("foo").buildPartial();
+    assertTrue(message.hasFooString());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooCord("bar").buildPartial();
+    assertTrue(message.hasFooCord());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooStringPiece("baz").buildPartial();
+    assertTrue(message.hasFooStringPiece());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial();
+    assertTrue(message.hasFooBytes());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial();
+    assertTrue(message.hasFooEnum());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooMessage(
+        TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).buildPartial();
+    assertTrue(message.hasFooMessage());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+
+    message = builder.setFooInt(123).buildPartial();
+    assertTrue(message.hasFooInt());
+    TestUtil.assertAtMostOneFieldSetOneof(message);
+  }
+
+  public void testOneofTypes() throws Exception {
+    // Primitive
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooInt(), 0);
+      assertFalse(builder.hasFooInt());
+      assertTrue(builder.setFooInt(123).hasFooInt());
+      assertEquals(builder.getFooInt(), 123);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooInt());
+      assertEquals(message.getFooInt(), 123);
+
+      assertFalse(builder.clearFooInt().hasFooInt());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 0);
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
+      assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
+      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooEnum());
+      assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
+
+      assertFalse(builder.clearFooEnum().hasFooEnum());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooString(), "");
+      builder.setFooString("foo");
+      assertTrue(builder.hasFooString());
+      assertEquals(builder.getFooString(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooString());
+      assertEquals(message.getFooString(), "foo");
+      assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooString().hasFooString());
+      TestOneof2 message2 = builder.buildPartial();
+      assertFalse(message2.hasFooString());
+      assertEquals(message2.getFooString(), "");
+      assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
+
+      // Get method should not change the oneof value.
+      builder.setFooInt(123);
+      assertEquals(builder.getFooString(), "");
+      assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
+      assertEquals(123, builder.getFooInt());
+
+      message = builder.build();
+      assertEquals(message.getFooString(), "");
+      assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
+      assertEquals(123, message.getFooInt());
+    }
+
+    // Cord
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooCord(), "");
+      builder.setFooCord("foo");
+      assertTrue(builder.hasFooCord());
+      assertEquals(builder.getFooCord(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooCord());
+      assertEquals(message.getFooCord(), "foo");
+      assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooCord().hasFooCord());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooCord());
+      assertEquals(message2.getFooCord(), "");
+      assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
+    }
+
+    // StringPiece
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooStringPiece(), "");
+      builder.setFooStringPiece("foo");
+      assertTrue(builder.hasFooStringPiece());
+      assertEquals(builder.getFooStringPiece(), "foo");
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooStringPiece());
+      assertEquals(message.getFooStringPiece(), "foo");
+      assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
+
+      assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
+      TestOneof2 message2 = builder.build();
+      assertFalse(message2.hasFooStringPiece());
+      assertEquals(message2.getFooStringPiece(), "");
+      assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
+    }
+
+    // Message
+    {
+      // set
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      assertEquals(builder.getFooMessage().getQuxInt(), 0);
+      builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
+      assertTrue(builder.hasFooMessage());
+      assertEquals(builder.getFooMessage().getQuxInt(), 234);
+      TestOneof2 message = builder.buildPartial();
+      assertTrue(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 234);
+
+      // clear
+      assertFalse(builder.clearFooMessage().hasFooString());
+      message = builder.build();
+      assertFalse(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 0);
+
+      // nested builder
+      builder = TestOneof2.newBuilder();
+      assertSame(builder.getFooMessageOrBuilder(),
+          TestOneof2.NestedMessage.getDefaultInstance());
+      assertFalse(builder.hasFooMessage());
+      builder.getFooMessageBuilder().setQuxInt(123);
+      assertTrue(builder.hasFooMessage());
+      assertEquals(builder.getFooMessage().getQuxInt(), 123);
+      message = builder.build();
+      assertTrue(message.hasFooMessage());
+      assertEquals(message.getFooMessage().getQuxInt(), 123);
+    }
+
+    // LazyMessage is tested in LazyMessageLiteTest.java
+  }
+
+  public void testOneofMerge() throws Exception {
+    // Primitive Type
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooInt(123).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 123);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooString("foo").build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooString());
+      assertEquals(message2.getFooString(), "foo");
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+    }
+
+    // Message
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+      assertTrue(message2.hasFooMessage());
+      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+    }
+  }
+
+  public void testOneofSerialization() throws Exception {
+    // Primitive Type
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooInt(123).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooInt());
+      assertEquals(message2.getFooInt(), 123);
+    }
+
+    // String
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooString("foo").build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooString());
+      assertEquals(message2.getFooString(), "foo");
+    }
+
+    // Enum
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooEnum());
+      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
+    }
+
+    // Message
+    {
+      TestOneof2.Builder builder = TestOneof2.newBuilder();
+      TestOneof2 message = builder.setFooMessage(
+          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+      ByteString serialized = message.toByteString();
+      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
+      assertTrue(message2.hasFooMessage());
+      assertEquals(message2.getFooMessage().getQuxInt(), 234);
+    }
+  }
+
+  public void testOneofNestedBuilderOnChangePropagation() {
+    NestedTestAllTypes.Builder parentBuilder = NestedTestAllTypes.newBuilder();
+    TestAllTypes.Builder builder = parentBuilder.getPayloadBuilder();
+    builder.getOneofNestedMessageBuilder();
+    assertTrue(builder.hasOneofNestedMessage());
+    assertTrue(parentBuilder.hasPayload());
+    NestedTestAllTypes message = parentBuilder.build();
+    assertTrue(message.hasPayload());
+    assertTrue(message.getPayload().hasOneofNestedMessage());
+  }
+
+  public void testGetRepeatedFieldBuilder() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("repeated_nested_message");
+    FieldDescriptor foreignFieldDescriptor =
+        descriptor.findFieldByName("repeated_foreign_message");
+    FieldDescriptor importFieldDescriptor =
+        descriptor.findFieldByName("repeated_import_message");
+
+    // Mutate the message with new field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
+    Message.Builder fieldBuilder1 = builder1.newBuilderForField(
+        fieldDescriptor);
+    FieldDescriptor subFieldDescriptor1 =
+        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder1.setField(subFieldDescriptor1, 1);
+    builder1.addRepeatedField(fieldDescriptor, fieldBuilder1.build());
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField(
+        foreignFieldDescriptor);
+    FieldDescriptor subForeignFieldDescriptor1 =
+        foreignFieldBuilder1.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2);
+    builder1.addRepeatedField(foreignFieldDescriptor,
+        foreignFieldBuilder1.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder1 = builder1.newBuilderForField(
+        importFieldDescriptor);
+    FieldDescriptor subImportFieldDescriptor1 =
+        importFieldBuilder1.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder1.setField(subImportFieldDescriptor1, 3);
+    builder1.addRepeatedField(importFieldDescriptor,
+        importFieldBuilder1.build());
+
+    Message newMessage1 = builder1.build();
+
+    // Mutate the message with existing field builder
+    // Mutate nested message
+    TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
+    builder2.addRepeatedNestedMessageBuilder();
+    Message.Builder fieldBuilder2 = builder2.getRepeatedFieldBuilder(
+        fieldDescriptor, 0);
+    FieldDescriptor subFieldDescriptor2 =
+        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
+    fieldBuilder2.setField(subFieldDescriptor2, 1);
+
+    // Mutate foreign message
+    Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(
+        foreignFieldDescriptor);
+    FieldDescriptor subForeignFieldDescriptor2 =
+        foreignFieldBuilder2.getDescriptorForType().findFieldByName("c");
+    foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2);
+    builder2.addRepeatedField(foreignFieldDescriptor,
+        foreignFieldBuilder2.build());
+
+    // Mutate import message
+    Message.Builder importFieldBuilder2 = builder2.newBuilderForField(
+        importFieldDescriptor);
+    FieldDescriptor subImportFieldDescriptor2 =
+        importFieldBuilder2.getDescriptorForType().findFieldByName("d");
+    importFieldBuilder2.setField(subImportFieldDescriptor2, 3);
+    builder2.addRepeatedField(importFieldDescriptor,
+        importFieldBuilder2.build());
+
+    Message newMessage2 = builder2.build();
+
+    // These two messages should be equal.
+    assertEquals(newMessage1, newMessage2);
+  }
+
+  public void testGetRepeatedFieldBuilderWithInitializedValue() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor fieldDescriptor =
+        descriptor.findFieldByName("repeated_nested_message");
+
+    // Before setting field, builder is initialized by default value. 
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.addRepeatedNestedMessageBuilder();
+    NestedMessage.Builder fieldBuilder =
+        (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0);
+    assertEquals(0, fieldBuilder.getBb());
+
+    // Setting field value with new field builder instance.
+    builder = TestAllTypes.newBuilder();
+    NestedMessage.Builder newFieldBuilder =
+        builder.addRepeatedNestedMessageBuilder();
+    newFieldBuilder.setBb(2);
+    // Then get the field builder instance by getRepeatedFieldBuilder().
+    fieldBuilder =
+        (NestedMessage.Builder) builder.getRepeatedFieldBuilder(fieldDescriptor, 0);
+    // It should contain new value.
+    assertEquals(2, fieldBuilder.getBb());
+    // These two builder should be equal.
+    assertSame(fieldBuilder, newFieldBuilder);
+  }
+
+  public void testGetRepeatedFieldBuilderNotSupportedException() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      builder.getRepeatedFieldBuilder(descriptor.findFieldByName("repeated_int32"), 0);
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getRepeatedFieldBuilder(
+          descriptor.findFieldByName("repeated_nested_enum"), 0);
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getRepeatedFieldBuilder(descriptor.findFieldByName("optional_int32"), 0);
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getRepeatedFieldBuilder(
+          descriptor.findFieldByName("optional_nested_enum"), 0);
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+    try {
+      builder.getRepeatedFieldBuilder(
+          descriptor.findFieldByName("optional_nested_message"), 0);
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // We expect this exception.
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
new file mode 100644
index 0000000..efb8f3e
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -0,0 +1,459 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link IntArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class IntArrayListTest extends TestCase {
+  
+  private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
+  private static final IntArrayList TERTIARY_LIST =
+      newImmutableIntArrayList(1, 2, 3);
+  
+  private IntArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new IntArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(IntArrayList.emptyList(), IntArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(IntArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addInt(2);
+    list.addInt(4);
+    list.addInt(6);
+    list.addInt(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+
+  public void testModificationWithIteration() {
+    list.addAll(asList(1, 2, 3, 4));
+    Iterator<Integer> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, (int) iterator.next());
+    list.set(0, 1);
+    assertEquals(2, (int) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+
+    iterator = list.iterator();
+    list.add(0, 0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1, (int) TERTIARY_LIST.get(0));
+    assertEquals(2, (int) TERTIARY_LIST.get(1));
+    assertEquals(3, (int) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(1, TERTIARY_LIST.getInt(0));
+    assertEquals(2, TERTIARY_LIST.getInt(1));
+    assertEquals(3, TERTIARY_LIST.getInt(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, IntArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addInt(2);
+    list.addInt(4);
+    list.addInt(6);
+    list.addInt(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addInt(2);
+    list.addInt(4);
+    
+    assertEquals(2, (int) list.set(0, 0));
+    assertEquals(0, list.getInt(0));
+
+    assertEquals(4, (int) list.set(1, 0));
+    assertEquals(0, list.getInt(1));
+    
+    try {
+      list.set(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addInt(2);
+    list.addInt(4);
+    
+    assertEquals(2, list.setInt(0, 0));
+    assertEquals(0, list.getInt(0));
+
+    assertEquals(4, list.setInt(1, 0));
+    assertEquals(0, list.getInt(1));
+    
+    try {
+      list.setInt(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setInt(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2));
+    assertEquals(asList(2), list);
+
+    assertTrue(list.add(3));
+    list.add(0, 4);
+    assertEquals(asList(4, 2, 3), list);
+    
+    list.add(0, 1);
+    list.add(0, 0);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(5 + i);
+    }
+    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
+    
+    try {
+      list.add(-1, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addInt(2);
+    assertEquals(asList(2), list);
+
+    list.addInt(3);
+    assertEquals(asList(2, 3), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1)));
+    assertEquals(1, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, list.getInt(0));
+    
+    assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
+    assertEquals(asList(1, 2, 3, 4, 5, 6), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
+
+    assertFalse(list.addAll(Collections.<Integer>emptyList()));
+    assertFalse(list.addAll(IntArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1, (int) list.remove(0));
+    assertEquals(asList(2, 3), list);
+
+    assertTrue(list.remove(Integer.valueOf(3)));
+    assertEquals(asList(2), list);
+
+    assertFalse(list.remove(Integer.valueOf(3)));
+    assertEquals(asList(2), list);
+
+    assertEquals(2, (int) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(IntArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new IntArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addInt(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setInt(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static IntArrayList newImmutableIntArrayList(int... elements) {
+    IntArrayList list = new IntArrayList();
+    for (int element : elements) {
+      list.addInt(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
new file mode 100644
index 0000000..756049b
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -0,0 +1,186 @@
+// 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.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.IsValidUtf8TestUtil.DIRECT_NIO_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT;
+import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT;
+import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY;
+import static com.google.protobuf.IsValidUtf8TestUtil.testBytes;
+
+import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
+import com.google.protobuf.IsValidUtf8TestUtil.Shard;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests cases for {@link ByteString#isValidUtf8()}. This includes three
+ * brute force tests that actually test every permutation of one byte, two byte,
+ * and three byte sequences to ensure that the method produces the right result
+ * for every possible byte encoding where "right" means it's consistent with
+ * java's UTF-8 string encoding/decoding such that the method returns true for
+ * any sequence that will round trip when converted to a String and then back to
+ * bytes and will return false for any sequence that will not round trip.
+ * See also {@link IsValidUtf8FourByteTest}. It also includes some
+ * other more targeted tests.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+public class IsValidUtf8Test extends TestCase {
+  /**
+   * Tests that round tripping of all two byte permutations work.
+   */
+  public void testIsValidUtf8_1Byte() {
+    testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
+  }
+
+  /**
+   * Tests that round tripping of all two byte permutations work.
+   */
+  public void testIsValidUtf8_2Bytes() {
+    testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+    testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
+  }
+
+  /**
+   * Tests that round tripping of all three byte permutations work.
+   */
+  public void testIsValidUtf8_3Bytes() {
+    // Travis' OOM killer doesn't like this test
+    if (System.getenv("TRAVIS") == null) {
+      testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+      testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+      testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
+    }
+  }
+
+  /**
+   * Tests that round tripping of a sample of four byte permutations work.
+   * All permutations are prohibitively expensive to test for automated runs;
+   * {@link IsValidUtf8FourByteTest} is used for full coverage. This method
+   * tests specific four-byte cases.
+   */
+  public void testIsValidUtf8_4BytesSamples() {
+    // Valid 4 byte.
+    assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
+
+    // Bad trailing bytes
+    assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0x7F);
+    assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0xC0);
+
+    // Special cases for byte2
+    assertInvalidUtf8(0xF0, 0x8F, 0xAD, 0xA2);
+    assertInvalidUtf8(0xF4, 0x90, 0xAD, 0xA2);
+  }
+
+  /**
+   * Tests some hard-coded test cases.
+   */
+  public void testSomeSequences() {
+    // Empty
+    assertTrue(asBytes("").isValidUtf8());
+
+    // One-byte characters, including control characters
+    assertTrue(asBytes("\u0000abc\u007f").isValidUtf8());
+
+    // Two-byte characters
+    assertTrue(asBytes("\u00a2\u00a2").isValidUtf8());
+
+    // Three-byte characters
+    assertTrue(asBytes("\u020ac\u020ac").isValidUtf8());
+
+    // Four-byte characters
+    assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
+
+    // Mixed string
+    assertTrue(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8());
+
+    // Not a valid string
+    assertInvalidUtf8(-1, 0, -1, 0);
+  }
+
+  private byte[] toByteArray(int... bytes) {
+    byte[] realBytes = new byte[bytes.length];
+    for (int i = 0; i < bytes.length; i++) {
+      realBytes[i] = (byte) bytes[i];
+    }
+    return realBytes;
+  }
+
+  private void assertValidUtf8(ByteStringFactory factory, int[] bytes, boolean not) {
+    byte[] realBytes = toByteArray(bytes);
+    assertTrue(not ^ Utf8.isValidUtf8(realBytes));
+    assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
+    ByteString leaf = factory.newByteString(realBytes);
+    ByteString sub = leaf.substring(0, bytes.length);
+    assertTrue(not ^ leaf.isValidUtf8());
+    assertTrue(not ^ sub.isValidUtf8());
+    ByteString[] ropes = {
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf),
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
+        RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY),
+        RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
+        RopeByteString.newInstanceForTest(sub, leaf)};
+    for (ByteString rope : ropes) {
+      assertTrue(not ^ rope.isValidUtf8());
+    }
+  }
+
+  private void assertValidUtf8(int... bytes) {
+    assertValidUtf8(LITERAL_FACTORY, bytes, false);
+    assertValidUtf8(HEAP_NIO_FACTORY, bytes, false);
+    assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false);
+  }
+
+  private void assertInvalidUtf8(int... bytes) {
+    assertValidUtf8(LITERAL_FACTORY, bytes, true);
+    assertValidUtf8(HEAP_NIO_FACTORY, bytes, true);
+    assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true);
+  }
+
+  private static ByteString asBytes(String s) {
+    return ByteString.copyFromUtf8(s);
+  }
+
+  public void testShardsHaveExpectedRoundTrippables() {
+    // A sanity check.
+    int actual = 0;
+    for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
+      actual += shard.expected;
+    }
+    assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
new file mode 100644
index 0000000..16a808b
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -0,0 +1,448 @@
+// 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.
+
+package com.google.protobuf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Logger;
+
+/**
+ * Shared testing code for {@link IsValidUtf8Test} and
+ * {@link IsValidUtf8FourByteTest}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ * @author martinrb@google.com (Martin Buchholz)
+ */
+final class IsValidUtf8TestUtil {
+  private static Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
+
+  private IsValidUtf8TestUtil() {}
+
+  static interface ByteStringFactory {
+    ByteString newByteString(byte[] bytes);
+  }
+
+  static final ByteStringFactory LITERAL_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      return ByteString.wrap(bytes);
+    }
+  };
+
+  static final ByteStringFactory HEAP_NIO_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      return new NioByteString(ByteBuffer.wrap(bytes));
+    }
+  };
+
+  private static ThreadLocal<SoftReference<ByteBuffer>> directBuffer =
+      new ThreadLocal<SoftReference<ByteBuffer>>();
+
+  /**
+   * Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this
+   * uses a thread local direct buffer. This means that each call will overwrite the buffer's
+   * contents from the previous call, so the calling code must be careful not to continue using
+   * a buffer returned from a previous invocation.
+   */
+  static final ByteStringFactory DIRECT_NIO_FACTORY = new ByteStringFactory() {
+    @Override
+    public ByteString newByteString(byte[] bytes) {
+      SoftReference<ByteBuffer> ref = directBuffer.get();
+      ByteBuffer buffer = ref == null ? null : ref.get();
+      if (buffer == null || buffer.capacity() < bytes.length) {
+        buffer = ByteBuffer.allocateDirect(bytes.length);
+        directBuffer.set(new SoftReference<ByteBuffer>(buffer));
+      }
+      buffer.clear();
+      buffer.put(bytes);
+      buffer.flip();
+      return new NioByteString(buffer);
+    }
+  };
+
+  // 128 - [chars 0x0000 to 0x007f]
+  static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
+
+  // 128
+  static final long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  // 1920 [chars 0x0080 to 0x07FF]
+  static final long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
+
+  // 18,304
+  static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
+      // Both bytes are one byte characters
+      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
+      // The possible number of two byte characters
+      TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  // 2048
+  static final long THREE_BYTE_SURROGATES = 2 * 1024;
+
+  // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
+  static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
+      0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
+
+  // 2,650,112
+  static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
+      // All one byte characters
+      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
+      // One two byte character and a one byte character
+      2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      // Three byte characters
+      THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  // 1,048,576 [chars 0x10000L to 0x10FFFF]
+  static final long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
+
+  // 289,571,839
+  static final long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
+      // All one byte characters
+      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
+      // One and three byte characters
+      2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      // Two two byte characters
+      TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
+      // Permutations of one and two byte characters
+      3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+      * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS
+      +
+      // Four byte characters
+      FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  static final class Shard {
+    final long index;
+    final long start;
+    final long lim;
+    final long expected;
+
+
+    public Shard(long index, long start, long lim, long expected) {
+      assertTrue(start < lim);
+      this.index = index;
+      this.start = start;
+      this.lim = lim;
+      this.expected = expected;
+    }
+  }
+
+  static final long[] FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES =
+      generateFourByteShardsExpectedRunnables();
+
+  private static long[] generateFourByteShardsExpectedRunnables() {
+    long[] expected = new long[128];
+
+    // 0-63 are all 5300224
+    for (int i = 0; i <= 63; i++) {
+      expected[i] = 5300224;
+    }
+
+    // 97-111 are all 2342912
+    for (int i = 97; i <= 111; i++) {
+      expected[i] = 2342912;
+    }
+
+    // 113-117 are all 1048576
+    for (int i = 113; i <= 117; i++) {
+      expected[i] = 1048576;
+    }
+
+    // One offs
+    expected[112] = 786432;
+    expected[118] = 786432;
+    expected[119] = 1048576;
+    expected[120] = 458752;
+    expected[121] = 524288;
+    expected[122] = 65536;
+
+    // Anything not assigned was the default 0.
+    return expected;
+  }
+
+  static final List<Shard> FOUR_BYTE_SHARDS =
+      generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
+
+
+  private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
+    assertEquals(numShards, expected.length);
+    List<Shard> shards = new ArrayList<Shard>(numShards);
+    long LIM = 1L << 32;
+    long increment = LIM / numShards;
+    assertTrue(LIM % numShards == 0);
+    for (int i = 0; i < numShards; i++) {
+      shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
+    }
+    return shards;
+  }
+
+  /**
+   * Helper to run the loop to test all the permutations for the number of bytes
+   * specified.
+   *
+   * @param factory the factory for {@link ByteString} instances.
+   * @param numBytes the number of bytes in the byte array
+   * @param expectedCount the expected number of roundtrippable permutations
+   */
+  static void testBytes(ByteStringFactory factory, int numBytes, long expectedCount) {
+    testBytes(factory, numBytes, expectedCount, 0, -1);
+  }
+
+  /**
+   * Helper to run the loop to test all the permutations for the number of bytes
+   * specified. This overload is useful for debugging to get the loop to start
+   * at a certain character.
+   *
+   * @param factory the factory for {@link ByteString} instances.
+   * @param numBytes the number of bytes in the byte array
+   * @param expectedCount the expected number of roundtrippable permutations
+   * @param start the starting bytes encoded as a long as big-endian
+   * @param lim the limit of bytes to process encoded as a long as big-endian,
+   *     or -1 to mean the max limit for numBytes
+   */
+  static void testBytes(
+      ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
+    Random rnd = new Random();
+    byte[] bytes = new byte[numBytes];
+
+    if (lim == -1) {
+      lim = 1L << (numBytes * 8);
+    }
+    long count = 0;
+    long countRoundTripped = 0;
+    for (long byteChar = start; byteChar < lim; byteChar++) {
+      long tmpByteChar = byteChar;
+      for (int i = 0; i < numBytes; i++) {
+        bytes[bytes.length - i - 1] = (byte) tmpByteChar;
+        tmpByteChar = tmpByteChar >> 8;
+      }
+      ByteString bs = factory.newByteString(bytes);
+      boolean isRoundTrippable = bs.isValidUtf8();
+      String s = new String(bytes, Internal.UTF_8);
+      byte[] bytesReencoded = s.getBytes(Internal.UTF_8);
+      boolean bytesEqual = Arrays.equals(bytes, bytesReencoded);
+
+      if (bytesEqual != isRoundTrippable) {
+        outputFailure(byteChar, bytes, bytesReencoded);
+      }
+
+      // Check agreement with static Utf8 methods.
+      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
+      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
+
+      // Test partial sequences.
+      // Partition numBytes into three segments (not necessarily non-empty).
+      int i = rnd.nextInt(numBytes);
+      int j = rnd.nextInt(numBytes);
+      if (j < i) {
+        int tmp = i;
+        i = j;
+        j = tmp;
+      }
+      int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
+      int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
+      int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
+      if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
+        System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j);
+        outputFailure(byteChar, bytes, bytesReencoded);
+      }
+      assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
+
+      // Test ropes built out of small partial sequences
+      ByteString rope = RopeByteString.newInstanceForTest(
+          bs.substring(0, i),
+          RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
+      assertSame(RopeByteString.class, rope.getClass());
+
+      ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
+      for (ByteString x : byteStrings) {
+        assertEquals(isRoundTrippable, x.isValidUtf8());
+        assertEquals(state3, x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
+
+        assertEquals(state1, x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+        assertEquals(state1, x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
+        assertEquals(state2, x.partialIsValidUtf8(state1, i, j - i));
+        assertEquals(state2, x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
+        assertEquals(state3, x.partialIsValidUtf8(state2, j, numBytes - j));
+        assertEquals(state3, x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j));
+      }
+
+      // ByteString reduplication should not affect its UTF-8 validity.
+      ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
+      assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
+
+      if (isRoundTrippable) {
+        countRoundTripped++;
+      }
+      count++;
+      if (byteChar != 0 && byteChar % 1000000L == 0) {
+        logger.info("Processed " + (byteChar / 1000000L) + " million characters");
+      }
+    }
+    logger.info("Round tripped " + countRoundTripped + " of " + count);
+    assertEquals(expectedCount, countRoundTripped);
+  }
+
+  /**
+   * Variation of {@link #testBytes} that does less allocation using the
+   * low-level encoders/decoders directly. Checked in because it's useful for
+   * debugging when trying to process bytes faster, but since it doesn't use the
+   * actual String class, it's possible for incompatibilities to develop
+   * (although unlikely).
+   *
+   * @param factory the factory for {@link ByteString} instances.
+   * @param numBytes the number of bytes in the byte array
+   * @param expectedCount the expected number of roundtrippable permutations
+   * @param start the starting bytes encoded as a long as big-endian
+   * @param lim the limit of bytes to process encoded as a long as big-endian,
+   *     or -1 to mean the max limit for numBytes
+   */
+  static void testBytesUsingByteBuffers(
+      ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
+    CharsetDecoder decoder =
+        Internal.UTF_8.newDecoder()
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+    CharsetEncoder encoder =
+        Internal.UTF_8.newEncoder()
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+    byte[] bytes = new byte[numBytes];
+    int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
+    char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
+    int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
+    byte[] bytesReencoded = new byte[maxBytes];
+
+    ByteBuffer bb = ByteBuffer.wrap(bytes);
+    CharBuffer cb = CharBuffer.wrap(charsDecoded);
+    ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded);
+    if (lim == -1) {
+      lim = 1L << (numBytes * 8);
+    }
+    long count = 0;
+    long countRoundTripped = 0;
+    for (long byteChar = start; byteChar < lim; byteChar++) {
+      bb.rewind();
+      bb.limit(bytes.length);
+      cb.rewind();
+      cb.limit(charsDecoded.length);
+      bbReencoded.rewind();
+      bbReencoded.limit(bytesReencoded.length);
+      encoder.reset();
+      decoder.reset();
+      long tmpByteChar = byteChar;
+      for (int i = 0; i < bytes.length; i++) {
+        bytes[bytes.length - i - 1] = (byte) tmpByteChar;
+        tmpByteChar = tmpByteChar >> 8;
+      }
+      boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8();
+      CoderResult result = decoder.decode(bb, cb, true);
+      assertFalse(result.isError());
+      result = decoder.flush(cb);
+      assertFalse(result.isError());
+
+      int charLen = cb.position();
+      cb.rewind();
+      cb.limit(charLen);
+      result = encoder.encode(cb, bbReencoded, true);
+      assertFalse(result.isError());
+      result = encoder.flush(bbReencoded);
+      assertFalse(result.isError());
+
+      boolean bytesEqual = true;
+      int bytesLen = bbReencoded.position();
+      if (bytesLen != numBytes) {
+        bytesEqual = false;
+      } else {
+        for (int i = 0; i < numBytes; i++) {
+          if (bytes[i] != bytesReencoded[i]) {
+            bytesEqual = false;
+            break;
+          }
+        }
+      }
+      if (bytesEqual != isRoundTrippable) {
+        outputFailure(byteChar, bytes, bytesReencoded, bytesLen);
+      }
+
+      count++;
+      if (isRoundTrippable) {
+        countRoundTripped++;
+      }
+      if (byteChar != 0 && byteChar % 1000000 == 0) {
+        logger.info("Processed " + (byteChar / 1000000) + " million characters");
+      }
+    }
+    logger.info("Round tripped " + countRoundTripped + " of " + count);
+    assertEquals(expectedCount, countRoundTripped);
+  }
+
+  private static void outputFailure(long byteChar, byte[] bytes, byte[] after) {
+    outputFailure(byteChar, bytes, after, after.length);
+  }
+
+  private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) {
+    fail("Failure: (" + Long.toHexString(byteChar) + ") " + toHexString(bytes) + " => "
+        + toHexString(after, len));
+  }
+
+  private static String toHexString(byte[] b) {
+    return toHexString(b, b.length);
+  }
+
+  private static String toHexString(byte[] b, int len) {
+    StringBuilder s = new StringBuilder();
+    s.append("\"");
+    for (int i = 0; i < len; i++) {
+      if (i > 0) {
+        s.append(" ");
+      }
+      s.append(String.format("%02x", b[i] & 0xFF));
+    }
+    s.append("\"");
+    return s.toString();
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
new file mode 100644
index 0000000..8d1de6d
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -0,0 +1,272 @@
+// 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.
+
+package com.google.protobuf;
+
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Unit test for {@link LazyFieldLite}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldLiteTest extends TestCase {
+
+  public void testGetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testGetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+  }
+
+  public void testSetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+    message = lazyField.getValue(TestAllTypes.getDefaultInstance());
+    changeValue(lazyField);
+    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testSetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+    MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance());
+    changeValue(lazyField);
+    assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
+  }
+
+  public void testGetSerializedSize() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    changeValue(lazyField);
+    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+  }
+
+  public void testGetSerializedSizeEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
+    changeValue(lazyField);
+    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
+  }
+
+  public void testGetByteString() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.toByteString(), lazyField.toByteString());
+    changeValue(lazyField);
+    assertNotEqual(message.toByteString(), lazyField.toByteString());
+  }
+
+  public void testGetByteStringEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
+    assertEquals(message.toByteString(), lazyField.toByteString());
+    changeValue(lazyField);
+    assertNotEqual(message.toByteString(), lazyField.toByteString());
+  }
+
+  public void testMergeExtensions() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite original = createLazyFieldLiteFromMessage(message);
+    LazyFieldLite merged = new LazyFieldLite();
+    merged.merge(original);
+    TestAllExtensions value = (TestAllExtensions) merged.getValue(
+        TestAllExtensions.getDefaultInstance());
+    assertEquals(message, value);
+  }
+
+  public void testEmptyLazyField() throws Exception {
+    LazyFieldLite field = new LazyFieldLite();
+    assertEquals(0, field.getSerializedSize());
+    assertEquals(ByteString.EMPTY, field.toByteString());
+  }
+
+  public void testInvalidProto() throws Exception {
+    // Silently fails and uses the default instance.
+    LazyFieldLite field = new LazyFieldLite(
+        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    assertEquals(
+        TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
+    assertEquals(0, field.getSerializedSize());
+    assertEquals(ByteString.EMPTY, field.toByteString());
+  }
+
+  public void testMergeBeforeParsing() throws Exception {
+    TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    LazyFieldLite field1 = createLazyFieldLiteFromMessage(message1);
+    TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+    LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+
+    field1.merge(field2);
+    TestAllTypes expected =
+        TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeOneNotParsed() throws Exception {
+    // Test a few different paths that involve one message that was not parsed.
+    TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+    TestAllTypes expected =
+        TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+
+    LazyFieldLite field1 = LazyFieldLite.fromValue(message1);
+    field1.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+    field1.merge(field2);
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+
+    // Now reverse which one is parsed first.
+    field1 = LazyFieldLite.fromValue(message1);
+    field2 = createLazyFieldLiteFromMessage(message2);
+    field2.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    field1.merge(field2);
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeInvalid() throws Exception {
+    // Test a few different paths that involve one message that was not parsed.
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    LazyFieldLite valid = LazyFieldLite.fromValue(message);
+    LazyFieldLite invalid = new LazyFieldLite(
+        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    invalid.merge(valid);
+
+    // We swallow the exception and just use the set field.
+    assertEquals(message, invalid.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeKeepsExtensionsWhenPossible() throws Exception {
+    // In this test we attempt to only use the empty registry, which will strip out all extensions
+    // when serializing and then parsing. We verify that each code path will attempt to not
+    // serialize and parse a message that was set directly without going through the
+    // extensionRegistry.
+    TestAllExtensions messageWithExtensions =
+        TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 42).build();
+    TestAllExtensions emptyMessage = TestAllExtensions.newBuilder().build();
+
+    ExtensionRegistryLite emptyRegistry = ExtensionRegistryLite.getEmptyRegistry();
+
+    LazyFieldLite field = LazyFieldLite.fromValue(messageWithExtensions);
+    field.merge(createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage));
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // Now reverse the order of the merging.
+    field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    field.merge(LazyFieldLite.fromValue(messageWithExtensions));
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // Now try parsing the empty field first.
+    field = LazyFieldLite.fromValue(messageWithExtensions);
+    LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    other.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    field.merge(other);
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // And again reverse.
+    field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    field.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    other = LazyFieldLite.fromValue(messageWithExtensions);
+    field.merge(other);
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+  }
+
+  public void testMergeMightLoseExtensions() throws Exception {
+    // Test that we don't know about the extensions when parsing.
+    TestAllExtensions message1 =
+        TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 1).build();
+    TestAllExtensions message2 =
+        TestAllExtensions.newBuilder().setExtension(optionalInt64Extension, 2L).build();
+
+    LazyFieldLite field = LazyFieldLite.fromValue(message1);
+    field.merge(LazyFieldLite.fromValue(message2));
+
+    // We lose the extensions from message 2 because we have to serialize it and then parse it
+    // again, using the empty registry this time.
+    TestAllExtensions value =
+        (TestAllExtensions) field.getValue(TestAllExtensions.getDefaultInstance());
+    assertTrue(value.hasExtension(optionalInt32Extension));
+    assertEquals(Integer.valueOf(1), value.getExtension(optionalInt32Extension));
+    assertFalse(value.hasExtension(optionalInt64Extension));
+
+    // The field is still there, it is just unknown.
+    assertTrue(value.getUnknownFields()
+        .hasField(optionalInt64Extension.getDescriptor().getNumber()));
+  }
+
+
+  // Help methods.
+
+  private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
+    return createLazyFieldLiteFromMessage(TestUtil.getExtensionRegistry(), message);
+  }
+
+  private LazyFieldLite createLazyFieldLiteFromMessage(
+      ExtensionRegistryLite extensionRegistry, MessageLite message) {
+    ByteString bytes = message.toByteString();
+    return new LazyFieldLite(extensionRegistry, bytes);
+  }
+
+  private void changeValue(LazyFieldLite lazyField) {
+    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+    builder.addRepeatedBool(true);
+    MessageLite newMessage = builder.build();
+    lazyField.setValue(newMessage);
+  }
+
+  private void assertNotEqual(Object unexpected, Object actual) {
+    assertFalse(unexpected == actual
+        || (unexpected != null && unexpected.equals(actual)));
+  }
+
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
new file mode 100644
index 0000000..ce473ae
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
@@ -0,0 +1,122 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Unit test for {@link LazyField}.
+ *
+ * @author xiangl@google.com (Xiang Li)
+ */
+public class LazyFieldTest extends TestCase {
+  public void testHashCode() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField =
+        createLazyFieldFromMessage(message);
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    lazyField.getValue();
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    changeValue(lazyField);
+    // make sure two messages have different hash code
+    assertNotEqual(message.hashCode(), lazyField.hashCode());
+  }
+
+  public void testHashCodeEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    lazyField.getValue();
+    assertEquals(message.hashCode(), lazyField.hashCode());
+    changeValue(lazyField);
+    // make sure two messages have different hash code
+    assertNotEqual(message.hashCode(), lazyField.hashCode());
+  }
+
+  public void testGetValue() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message, lazyField.getValue());
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue());
+  }
+
+  public void testGetValueEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertEquals(message, lazyField.getValue());
+    changeValue(lazyField);
+    assertNotEqual(message, lazyField.getValue());
+  }
+
+  public void testEqualsObject() {
+    MessageLite message = TestUtil.getAllSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertTrue(lazyField.equals(message));
+    changeValue(lazyField);
+    assertFalse(lazyField.equals(message));
+    assertFalse(message.equals(lazyField.getValue()));
+  }
+
+  public void testEqualsObjectEx() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyField lazyField = createLazyFieldFromMessage(message);
+    assertTrue(lazyField.equals(message));
+    changeValue(lazyField);
+    assertFalse(lazyField.equals(message));
+    assertFalse(message.equals(lazyField.getValue()));
+  }
+
+  // Help methods.
+
+  private LazyField createLazyFieldFromMessage(MessageLite message) {
+    ByteString bytes = message.toByteString();
+    return new LazyField(message.getDefaultInstanceForType(),
+        TestUtil.getExtensionRegistry(), bytes);
+  }
+
+  private void changeValue(LazyField lazyField) {
+    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
+    builder.addRepeatedBool(true);
+    MessageLite newMessage = builder.build();
+    lazyField.setValue(newMessage);
+  }
+
+  private void assertNotEqual(Object unexpected, Object actual) {
+    assertFalse(unexpected == actual
+        || (unexpected != null && unexpected.equals(actual)));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
new file mode 100644
index 0000000..afe0fff
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -0,0 +1,307 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.LazyFieldsLite.LazyExtension;
+import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
+import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+
+/**
+ * Unit test for messages with lazy fields.
+ *
+ * @author niwasaki@google.com (Naoki Iwasaki)
+ */
+public class LazyMessageLiteTest extends TestCase {
+
+  private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    super.tearDown();
+  }
+
+  public void testSetValues() {
+    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+        .setNum(3)
+        .build();
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(2)
+        .setNested(nested)
+        .build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .setInner(inner)
+        .setOneofNum(123)
+        .setOneofInner(inner)
+        .build();
+
+    assertEquals(1, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+
+    assertEquals(2, outer.getInner().getNum());
+    assertEquals(42, outer.getInner().getNumWithDefault());
+
+    assertEquals(3, outer.getInner().getNested().getNum());
+    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+    assertFalse(outer.hasOneofNum());
+    assertTrue(outer.hasOneofInner());
+
+    assertEquals(2, outer.getOneofInner().getNum());
+    assertEquals(42, outer.getOneofInner().getNumWithDefault());
+    assertEquals(3, outer.getOneofInner().getNested().getNum());
+    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+  }
+
+  public void testSetRepeatedValues() {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .build();
+
+    assertEquals(1, outer.getNum());
+    assertEquals(2, outer.getRepeatedInnerCount());
+    assertEquals(119, outer.getRepeatedInner(0).getNum());
+    assertEquals(122, outer.getRepeatedInner(1).getNum());
+  }
+
+  public void testAddAll() {
+    ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
+    int count = 4;
+    for (int i = 0; i < count; i++) {
+      LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+          .setNum(i)
+          .build();
+      inners.add(inner);
+    }
+
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .addAllRepeatedInner(inners)
+        .build();
+    assertEquals(count, outer.getRepeatedInnerCount());
+    for (int i = 0; i < count; i++) {
+      assertEquals(i, outer.getRepeatedInner(i).getNum());
+    }
+  }
+
+  public void testGetDefaultValues() {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .build();
+
+    assertEquals(0, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+
+    assertEquals(0, outer.getInner().getNum());
+    assertEquals(42, outer.getInner().getNumWithDefault());
+
+    assertEquals(0, outer.getInner().getNested().getNum());
+    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
+
+    assertEquals(0, outer.getOneofNum());
+
+    assertEquals(0, outer.getOneofInner().getNum());
+    assertEquals(42, outer.getOneofInner().getNumWithDefault());
+    assertEquals(0, outer.getOneofInner().getNested().getNum());
+    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
+  }
+
+  public void testClearValues() {
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+
+    LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
+
+    assertEquals(0, outerBuilder.build().getNum());
+
+
+    // Set/Clear num
+    outerBuilder.setNum(100);
+
+    assertEquals(100, outerBuilder.build().getNum());
+    assertEquals(421, outerBuilder.build().getNumWithDefault());
+    assertFalse(outerBuilder.build().hasInner());
+
+    outerBuilder.clearNum();
+
+    assertEquals(0, outerBuilder.build().getNum());
+    assertEquals(421, outerBuilder.build().getNumWithDefault());
+    assertFalse(outerBuilder.build().hasInner());
+
+
+    // Set/Clear all
+    outerBuilder.setNum(100)
+        .setInner(inner)
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123));
+
+    LazyMessageLite outer = outerBuilder.build();
+    assertEquals(100, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+    assertTrue(outer.hasInner());
+    assertEquals(115, outer.getInner().getNum());
+    assertEquals(2, outer.getRepeatedInnerCount());
+    assertEquals(119, outer.getRepeatedInner(0).getNum());
+    assertEquals(122, outer.getRepeatedInner(1).getNum());
+    assertTrue(outer.hasOneofInner());
+    assertEquals(123, outer.getOneofInner().getNum());
+
+    outerBuilder.clear();
+
+    outer = outerBuilder.build();
+
+    assertEquals(0, outer.getNum());
+    assertEquals(421, outer.getNumWithDefault());
+    assertFalse(outer.hasInner());
+    assertEquals(0, outer.getRepeatedInnerCount());
+    assertFalse(outer.hasOneofInner());
+    assertEquals(0, outer.getOneofInner().getNum());
+  }
+
+  public void testMergeValues() {
+    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+        .setNumWithDefault(122)
+        .build();
+
+    LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+        .setNum(119)
+        .setInner(innerMerging)
+        .setOneofInner(innerMerging)
+        .build();
+
+    LazyMessageLite merged = LazyMessageLite
+        .newBuilder(outerBase)
+        .mergeFrom(outerMerging)
+        .build();
+    assertEquals(119, merged.getNum());
+    assertEquals(122, merged.getNumWithDefault());
+    assertEquals(115, merged.getInner().getNum());
+    assertEquals(42, merged.getInner().getNumWithDefault());
+    assertEquals(115, merged.getOneofInner().getNum());
+    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+  }
+
+  public void testMergeDefaultValues() {
+    LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder()
+        .setNum(115)
+        .build();
+    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
+        .setNum(119)
+        .setNumWithDefault(122)
+        .setInner(innerBase)
+        .setOneofInner(innerBase)
+        .build();
+
+    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
+        .build();
+
+    LazyMessageLite merged = LazyMessageLite
+        .newBuilder(outerBase)
+        .mergeFrom(outerMerging)
+        .build();
+    // Merging default-instance shouldn't overwrite values in the base message.
+    assertEquals(119, merged.getNum());
+    assertEquals(122, merged.getNumWithDefault());
+    assertEquals(115, merged.getInner().getNum());
+    assertEquals(42, merged.getInner().getNumWithDefault());
+    assertEquals(115, merged.getOneofInner().getNum());
+    assertEquals(42, merged.getOneofInner().getNumWithDefault());
+  }
+
+  public void testSerialize() throws InvalidProtocolBufferException {
+    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
+        .setNum(3)
+        .build();
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
+        .setNum(2)
+        .setNested(nested)
+        .build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .setNum(1)
+        .setInner(inner)
+        .setOneofInner(inner)
+        .build();
+
+    ByteString bytes = outer.toByteString();
+    assertEquals(bytes.size(), outer.getSerializedSize());
+
+    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
+
+    assertEquals(1, deserialized.getNum());
+    assertEquals(421,  deserialized.getNumWithDefault());
+
+    assertEquals(2,  deserialized.getInner().getNum());
+    assertEquals(42,  deserialized.getInner().getNumWithDefault());
+
+    assertEquals(3,  deserialized.getInner().getNested().getNum());
+    assertEquals(4,  deserialized.getInner().getNested().getNumWithDefault());
+
+    assertEquals(2,  deserialized.getOneofInner().getNum());
+    assertEquals(42,  deserialized.getOneofInner().getNumWithDefault());
+    assertEquals(3,  deserialized.getOneofInner().getNested().getNum());
+    assertEquals(4,  deserialized.getOneofInner().getNested().getNumWithDefault());
+
+    assertEquals(bytes, deserialized.toByteString());
+  }
+
+  public void testExtensions() throws Exception {
+    LazyInnerMessageLite.Builder innerBuilder = LazyInnerMessageLite.newBuilder();
+    innerBuilder.setExtension(
+        LazyExtension.extension, LazyExtension.newBuilder()
+        .setName("name").build());
+    assertTrue(innerBuilder.hasExtension(LazyExtension.extension));
+    assertEquals("name", innerBuilder.getExtension(LazyExtension.extension).getName());
+
+    LazyInnerMessageLite innerMessage = innerBuilder.build();
+    assertTrue(innerMessage.hasExtension(LazyExtension.extension));
+    assertEquals("name", innerMessage.getExtension(LazyExtension.extension).getName());
+
+    LazyMessageLite lite = LazyMessageLite.newBuilder()
+        .setInner(innerMessage).build();
+    assertTrue(lite.getInner().hasExtension(LazyExtension.extension));
+    assertEquals("name", lite.getInner().getExtension(LazyExtension.extension).getName());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
new file mode 100644
index 0000000..0f42ac5
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -0,0 +1,362 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests for {@link LazyStringArrayList}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class LazyStringArrayListTest extends TestCase {
+
+  private static String STRING_A = "A";
+  private static String STRING_B = "B";
+  private static String STRING_C = "C";
+
+  private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
+  private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
+  private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
+
+  public void testJustStrings() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.add(STRING_B);
+    list.add(STRING_C);
+
+    assertEquals(3, list.size());
+    assertSame(STRING_A, list.get(0));
+    assertSame(STRING_B, list.get(1));
+    assertSame(STRING_C, list.get(2));
+
+    list.set(1, STRING_C);
+    assertSame(STRING_C, list.get(1));
+
+    list.remove(1);
+    assertSame(STRING_A, list.get(0));
+    assertSame(STRING_C, list.get(1));
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    assertEquals(BYTE_STRING_A, byteStringList.get(0));
+    assertEquals(BYTE_STRING_C, byteStringList.get(1));
+
+    // Underlying list should be transformed.
+    assertSame(byteStringList.get(0), list.getByteString(0));
+    assertSame(byteStringList.get(1), list.getByteString(1));
+  }
+
+  public void testJustByteString() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(BYTE_STRING_A);
+    list.add(BYTE_STRING_B);
+    list.add(BYTE_STRING_C);
+
+    assertEquals(3, list.size());
+    assertSame(BYTE_STRING_A, list.getByteString(0));
+    assertSame(BYTE_STRING_B, list.getByteString(1));
+    assertSame(BYTE_STRING_C, list.getByteString(2));
+
+    list.remove(1);
+    assertSame(BYTE_STRING_A, list.getByteString(0));
+    assertSame(BYTE_STRING_C, list.getByteString(1));
+
+    List<ByteString> byteStringList = list.asByteStringList();
+    assertSame(BYTE_STRING_A, byteStringList.get(0));
+    assertSame(BYTE_STRING_C, byteStringList.get(1));
+  }
+
+  public void testConversionBackAndForth() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.add(BYTE_STRING_B);
+    list.add(BYTE_STRING_C);
+
+    // String a should be the same because it was originally a string
+    assertSame(STRING_A, list.get(0));
+
+    // String b and c should be different because the string has to be computed
+    // from the ByteString
+    String bPrime = list.get(1);
+    assertNotSame(STRING_B, bPrime);
+    assertEquals(STRING_B, bPrime);
+    String cPrime = list.get(2);
+    assertNotSame(STRING_C, cPrime);
+    assertEquals(STRING_C, cPrime);
+
+    // String c and c should stay the same once cached.
+    assertSame(bPrime, list.get(1));
+    assertSame(cPrime, list.get(2));
+
+    // ByteString needs to be computed from string for both a and b
+    ByteString aPrimeByteString = list.getByteString(0);
+    assertEquals(BYTE_STRING_A, aPrimeByteString);
+    ByteString bPrimeByteString = list.getByteString(1);
+    assertNotSame(BYTE_STRING_B, bPrimeByteString);
+    assertEquals(BYTE_STRING_B, list.getByteString(1));
+
+    // Once cached, ByteString should stay cached.
+    assertSame(aPrimeByteString, list.getByteString(0));
+    assertSame(bPrimeByteString, list.getByteString(1));
+  }
+
+  public void testCopyConstructorCopiesByReference() {
+    LazyStringArrayList list1 = new LazyStringArrayList();
+    list1.add(STRING_A);
+    list1.add(BYTE_STRING_B);
+    list1.add(BYTE_STRING_C);
+
+    LazyStringArrayList list2 = new LazyStringArrayList(list1);
+    assertEquals(3, list2.size());
+    assertSame(STRING_A, list2.get(0));
+    assertSame(BYTE_STRING_B, list2.getByteString(1));
+    assertSame(BYTE_STRING_C, list2.getByteString(2));
+  }
+
+  public void testListCopyConstructor() {
+    List<String> list1 = new ArrayList<String>();
+    list1.add(STRING_A);
+    list1.add(STRING_B);
+    list1.add(STRING_C);
+
+    LazyStringArrayList list2 = new LazyStringArrayList(list1);
+    assertEquals(3, list2.size());
+    assertSame(STRING_A, list2.get(0));
+    assertSame(STRING_B, list2.get(1));
+    assertSame(STRING_C, list2.get(2));
+  }
+
+  public void testAddAllCopiesByReferenceIfPossible() {
+    LazyStringArrayList list1 = new LazyStringArrayList();
+    list1.add(STRING_A);
+    list1.add(BYTE_STRING_B);
+    list1.add(BYTE_STRING_C);
+
+    LazyStringArrayList list2 = new LazyStringArrayList();
+    list2.addAll(list1);
+
+    assertEquals(3, list2.size());
+    assertSame(STRING_A, list2.get(0));
+    assertSame(BYTE_STRING_B, list2.getByteString(1));
+    assertSame(BYTE_STRING_C, list2.getByteString(2));
+  }
+  
+  public void testModificationWithIteration() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.addAll(asList(STRING_A, STRING_B, STRING_C));
+    Iterator<String> iterator = list.iterator();
+    assertEquals(3, list.size());
+    assertEquals(STRING_A, list.get(0));
+    assertEquals(STRING_A, iterator.next());
+    
+    // Does not structurally modify.
+    iterator = list.iterator();
+    list.set(0, STRING_B);
+    iterator.next();
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, STRING_C);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testMakeImmutable() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.add(STRING_B);
+    list.add(STRING_C);
+    list.makeImmutable();
+    assertGenericListImmutable(list, STRING_A);
+    
+    // LazyStringArrayList has extra methods not covered in the generic
+    // assertion.
+    
+    try {
+      list.add(BYTE_STRING_A.toByteArray());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(BYTE_STRING_A);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAllByteArray(asList(BYTE_STRING_A.toByteArray()));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAllByteString(asList(BYTE_STRING_A));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.mergeFrom(new LazyStringArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, BYTE_STRING_A.toByteArray());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, BYTE_STRING_A);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  public void testImmutabilityPropagation() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.makeImmutable();
+
+    assertGenericListImmutable(list.asByteStringList(), BYTE_STRING_A);
+    
+    // Arrays use reference equality so need to retrieve the underlying value
+    // to properly test deep immutability.
+    List<byte[]> byteArrayList = list.asByteArrayList();
+    assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
+  }
+  
+  private static <T> void assertGenericListImmutable(List<T> list, T value) {
+    try {
+      list.add(value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(asList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(asList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
new file mode 100644
index 0000000..0ef414a
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
@@ -0,0 +1,132 @@
+// 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.
+
+package com.google.protobuf;
+
+
+import protobuf_unittest.UnittestProto;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
+ * strings works correctly.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class LazyStringEndToEndTest extends TestCase {
+
+  private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
+      ByteString.copyFrom(new byte[] {
+          114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
+          0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
+
+  private ByteString encodedTestAllTypes;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
+        .setOptionalString("foo")
+        .addRepeatedString("bar")
+        .addRepeatedString("baz")
+        .build()
+        .toByteString();
+  }
+
+  /**
+   * Tests that an invalid UTF8 string will roundtrip through a parse
+   * and serialization.
+   */
+  public void testParseAndSerialize() throws InvalidProtocolBufferException {
+    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
+        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+    ByteString bytes = tV2.toByteString();
+    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+
+    tV2.getOptionalString();
+    bytes = tV2.toByteString();
+    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
+  }
+
+  public void testParseAndWrite() throws IOException {
+    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
+        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
+    byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()];
+    CodedOutputStream outputStream = CodedOutputStream.newInstance(sink);
+    tV2.writeTo(outputStream);
+    outputStream.flush();
+    assertEquals(
+        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
+        ByteString.copyFrom(sink));
+  }
+  
+  public void testCaching() {
+    String a = "a";
+    String b = "b";
+    String c = "c";
+    UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.newBuilder()
+        .setOptionalString(a)
+        .addRepeatedString(b)
+        .addRepeatedString(c)
+        .build();
+
+    // String should be the one we passed it.
+    assertSame(a, proto.getOptionalString());
+    assertSame(b, proto.getRepeatedString(0));
+    assertSame(c, proto.getRepeatedString(1));
+
+
+    // Ensure serialization keeps strings cached.
+    proto.toByteString();
+
+    // And now the string should stay cached.
+    assertSame(a, proto.getOptionalString());
+    assertSame(b, proto.getRepeatedString(0));
+    assertSame(c, proto.getRepeatedString(1));
+  }
+
+  public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
+    UnittestProto.TestAllTypes proto =
+        UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
+    ByteString optional = proto.getOptionalStringBytes();
+    assertSame(optional, proto.getOptionalStringBytes());
+    assertSame(optional, proto.toBuilder().getOptionalStringBytes());
+
+    ByteString repeated0 = proto.getRepeatedStringBytes(0);
+    ByteString repeated1 = proto.getRepeatedStringBytes(1);
+    assertSame(repeated0, proto.getRepeatedStringBytes(0));
+    assertSame(repeated1, proto.getRepeatedStringBytes(1));
+    assertSame(repeated0, proto.toBuilder().getRepeatedStringBytes(0));
+    assertSame(repeated1, proto.toBuilder().getRepeatedStringBytes(1));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
new file mode 100644
index 0000000..29e8d87
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
@@ -0,0 +1,125 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
+
+import junit.framework.TestCase;
+
+/**
+ * Test generate equal and hash methods for the lite runtime.
+ *
+ * @author pbogle@google.com Phil Bogle
+ */
+public class LiteEqualsAndHashTest extends TestCase {
+
+  public void testEquals() throws Exception {
+    // Since the generated equals and hashCode methods for lite messages are a
+    // mostly complete subset of those for regular messages, we can mostly assume
+    // that the generated methods are already thoroughly tested by the regular tests.
+
+    // This test mostly just verifies is that a proto with
+    // optimize_for = LITE_RUNTIME and java_generates_equals_and_hash_compiles
+    // correctly when linked only against the lite library.
+
+    // We do however do some basic testing to make sure that equals is actually
+    // overriden to test for value equality rather than simple object equality.
+
+    // Check that two identical objs are equal.
+    Foo foo1a = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo1b = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo2 = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo2"))
+        .build();
+
+    // Check that equals is doing value rather than object equality.
+    assertEquals(foo1a, foo1b);
+    assertEquals(foo1a.hashCode(), foo1b.hashCode());
+
+    // Check that a diffeent object is not equal.
+    assertFalse(foo1a.equals(foo2));
+
+    // Check that two objects which have different types but the same field values are not
+    // considered to be equal.
+    Bar bar = Bar.newBuilder().setName("bar").build();
+    BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
+    assertFalse(bar.equals(barPrime));
+  }
+
+  public void testOneofEquals() throws Exception {
+    TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+    TestOneofEquals message1 = builder.build();
+    // Set message2's name field to default value. The two messages should be different when we
+    // check with the oneof case.
+    builder.setName("");
+    TestOneofEquals message2 = builder.build();
+    assertFalse(message1.equals(message2));
+  }
+
+  public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
+    Foo fooWithOnlyValue = Foo.newBuilder()
+        .setValue(1)
+        .build();
+
+    Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
+        .setValue(1)
+        .setExtension(Bar.fooExt, Bar.newBuilder()
+            .setName("name")
+            .build())
+        .build();
+
+    Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray());
+
+    assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields);
+    assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
+  }
+
+  private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
+    assertFalse(o1.equals(o2));
+    assertFalse(o1.hashCode() == o2.hashCode());
+  }
+
+  public void testRecursiveHashcode() {
+    // This tests that we don't infinite loop.
+    TestRecursiveOneof.getDefaultInstance().hashCode();
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
new file mode 100644
index 0000000..88c3e0b
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -0,0 +1,2229 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+import com.google.protobuf.UnittestLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
+import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Test lite runtime.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class LiteTest extends TestCase {
+  @Override
+  public void setUp() throws Exception {
+    // Test that nested extensions are initialized correctly even if the outer
+    // class has not been accessed directly.  This was once a bug with lite
+    // messages.
+    //
+    // We put this in setUp() rather than in its own test method because we
+    // need to make sure it runs before any actual tests.
+    assertTrue(TestNestedExtensionLite.nestedExtension != null);
+  }
+
+  public void testLite() throws Exception {
+    // Since lite messages are a subset of regular messages, we can mostly
+    // assume that the functionality of lite messages is already thoroughly
+    // tested by the regular tests.  All this test really verifies is that
+    // a proto with optimize_for = LITE_RUNTIME compiles correctly when
+    // linked only against the lite library.  That is all tested at compile
+    // time, leaving not much to do in this method.  Let's just do some random
+    // stuff to make sure the lite message is actually here and usable.
+
+    TestAllTypesLite message =
+      TestAllTypesLite.newBuilder()
+                      .setOptionalInt32(123)
+                      .addRepeatedString("hello")
+                      .setOptionalNestedMessage(
+                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+                      .build();
+
+    ByteString data = message.toByteString();
+
+    TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
+
+    assertEquals(123, message2.getOptionalInt32());
+    assertEquals(1, message2.getRepeatedStringCount());
+    assertEquals("hello", message2.getRepeatedString(0));
+    assertEquals(7, message2.getOptionalNestedMessage().getBb());
+  }
+
+  public void testLiteExtensions() throws Exception {
+    // TODO(kenton):  Unlike other features of the lite library, extensions are
+    //   implemented completely differently from the regular library.  We
+    //   should probably test them more thoroughly.
+
+    TestAllExtensionsLite message =
+      TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+            TestAllTypesLite.NestedEnum.BAZ)
+        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+        .build();
+
+    // Test copying a message, since coping extensions actually does use a
+    // different code path between lite and regular libraries, and as of this
+    // writing, parsing hasn't been implemented yet.
+    TestAllExtensionsLite message2 = message.toBuilder().build();
+
+    assertEquals(123, (int) message2.getExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(1, message2.getExtensionCount(
+        UnittestLite.repeatedStringExtensionLite));
+    assertEquals(1, message2.getExtension(
+        UnittestLite.repeatedStringExtensionLite).size());
+    assertEquals("hello", message2.getExtension(
+        UnittestLite.repeatedStringExtensionLite, 0));
+    assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
+        UnittestLite.optionalNestedEnumExtensionLite));
+    assertEquals(7, message2.getExtension(
+        UnittestLite.optionalNestedMessageExtensionLite).getBb());
+  }
+  
+  
+  public void testClone() {
+    TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
+        .setOptionalInt32(123);
+    assertEquals(
+        expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+   
+    TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
+    assertEquals(
+        expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
+        expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
+  }
+  
+  public void testAddAll() {
+    try {
+      TestAllTypesLite.newBuilder()
+          .addAllRepeatedBytes(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+  }
+  
+  public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
+    // Since builders are implemented as a thin wrapper around a message
+    // instance, we attempt to verify that we can't cause the builder to modify
+    // a produced message.
+
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    TestAllTypesLite message = builder.build();
+    TestAllTypesLite messageAfterBuild;
+    builder.setOptionalBool(true);
+    assertEquals(false, message.getOptionalBool());
+    assertEquals(true, builder.getOptionalBool());
+    messageAfterBuild = builder.build();
+    assertEquals(true, messageAfterBuild.getOptionalBool());
+    assertEquals(false, message.getOptionalBool());
+    builder.clearOptionalBool();
+    assertEquals(false, builder.getOptionalBool());
+    assertEquals(true, messageAfterBuild.getOptionalBool());
+
+    message = builder.build();
+    builder.setOptionalBytes(ByteString.copyFromUtf8("hi"));
+    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    builder.clearOptionalBytes();
+    assertEquals(ByteString.EMPTY, builder.getOptionalBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+
+    message = builder.build();
+    builder.setOptionalCord("hi");
+    assertEquals("", message.getOptionalCord());
+    assertEquals("hi", builder.getOptionalCord());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalCord());
+    assertEquals("", message.getOptionalCord());
+    builder.clearOptionalCord();
+    assertEquals("", builder.getOptionalCord());
+    assertEquals("hi", messageAfterBuild.getOptionalCord());
+
+    message = builder.build();
+    builder.setOptionalCordBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalCordBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
+    builder.clearOptionalCord();
+    assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalCordBytes());
+    
+    message = builder.build();
+    builder.setOptionalDouble(1);
+    assertEquals(0D, message.getOptionalDouble());
+    assertEquals(1D, builder.getOptionalDouble());
+    messageAfterBuild = builder.build();
+    assertEquals(1D, messageAfterBuild.getOptionalDouble());
+    assertEquals(0D, message.getOptionalDouble());
+    builder.clearOptionalDouble();
+    assertEquals(0D, builder.getOptionalDouble());
+    assertEquals(1D, messageAfterBuild.getOptionalDouble());
+    
+    message = builder.build();
+    builder.setOptionalFixed32(1);
+    assertEquals(0, message.getOptionalFixed32());
+    assertEquals(1, builder.getOptionalFixed32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalFixed32());
+    assertEquals(0, message.getOptionalFixed32());
+    builder.clearOptionalFixed32();
+    assertEquals(0, builder.getOptionalFixed32());
+    assertEquals(1, messageAfterBuild.getOptionalFixed32());
+    
+    message = builder.build();
+    builder.setOptionalFixed64(1);
+    assertEquals(0L, message.getOptionalFixed64());
+    assertEquals(1L, builder.getOptionalFixed64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
+    assertEquals(0L, message.getOptionalFixed64());
+    builder.clearOptionalFixed64();
+    assertEquals(0L, builder.getOptionalFixed64());
+    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
+
+    message = builder.build();
+    builder.setOptionalFloat(1);
+    assertEquals(0F, message.getOptionalFloat());
+    assertEquals(1F, builder.getOptionalFloat());
+    messageAfterBuild = builder.build();
+    assertEquals(1F, messageAfterBuild.getOptionalFloat());
+    assertEquals(0F, message.getOptionalFloat());
+    builder.clearOptionalFloat();
+    assertEquals(0F, builder.getOptionalFloat());
+    assertEquals(1F, messageAfterBuild.getOptionalFloat());
+
+    message = builder.build();
+    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    builder.clearOptionalForeignEnum();
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getOptionalForeignEnum());
+
+    message = builder.build();
+    ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder()
+        .setC(1)
+        .build();
+    builder.setOptionalForeignMessage(foreignMessage);
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    assertEquals(foreignMessage, builder.getOptionalForeignMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    builder.clearOptionalForeignMessage();
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getOptionalForeignMessage());
+    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
+
+    message = builder.build();
+    ForeignMessageLite.Builder foreignMessageBuilder =
+        ForeignMessageLite.newBuilder()
+            .setC(3);
+    builder.setOptionalForeignMessage(foreignMessageBuilder);
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    builder.clearOptionalForeignMessage();
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getOptionalForeignMessage());
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+
+    message = builder.build();
+    OptionalGroup optionalGroup = OptionalGroup.newBuilder()
+        .setA(1)
+        .build();
+    builder.setOptionalGroup(optionalGroup);
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(optionalGroup, builder.getOptionalGroup());
+    messageAfterBuild = builder.build();
+    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    builder.clearOptionalGroup();
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
+
+    message = builder.build();
+    OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder()
+        .setA(3);
+    builder.setOptionalGroup(optionalGroupBuilder);
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup());
+    messageAfterBuild = builder.build();
+    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    builder.clearOptionalGroup();
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup());
+
+    message = builder.build();
+    builder.setOptionalInt32(1);
+    assertEquals(0, message.getOptionalInt32());
+    assertEquals(1, builder.getOptionalInt32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalInt32());
+    assertEquals(0, message.getOptionalInt32());
+    builder.clearOptionalInt32();
+    assertEquals(0, builder.getOptionalInt32());
+    assertEquals(1, messageAfterBuild.getOptionalInt32());
+
+    message = builder.build();
+    builder.setOptionalInt64(1);
+    assertEquals(0L, message.getOptionalInt64());
+    assertEquals(1L, builder.getOptionalInt64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalInt64());
+    assertEquals(0L, message.getOptionalInt64());
+    builder.clearOptionalInt64();
+    assertEquals(0L, builder.getOptionalInt64());
+    assertEquals(1L, messageAfterBuild.getOptionalInt64());
+    
+    message = builder.build();
+    NestedMessage nestedMessage = NestedMessage.newBuilder()
+        .setBb(1)
+        .build();
+    builder.setOptionalLazyMessage(nestedMessage);
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    assertEquals(nestedMessage, builder.getOptionalLazyMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    builder.clearOptionalLazyMessage();
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
+
+    message = builder.build();
+    NestedMessage.Builder nestedMessageBuilder =
+        NestedMessage.newBuilder()
+            .setBb(3);
+    builder.setOptionalLazyMessage(nestedMessageBuilder);
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    builder.clearOptionalLazyMessage();
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage());
+
+    message = builder.build();
+    builder.setOptionalSfixed32(1);
+    assertEquals(0, message.getOptionalSfixed32());
+    assertEquals(1, builder.getOptionalSfixed32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
+    assertEquals(0, message.getOptionalSfixed32());
+    builder.clearOptionalSfixed32();
+    assertEquals(0, builder.getOptionalSfixed32());
+    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
+
+    message = builder.build();
+    builder.setOptionalSfixed64(1);
+    assertEquals(0L, message.getOptionalSfixed64());
+    assertEquals(1L, builder.getOptionalSfixed64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
+    assertEquals(0L, message.getOptionalSfixed64());
+    builder.clearOptionalSfixed64();
+    assertEquals(0L, builder.getOptionalSfixed64());
+    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
+
+    message = builder.build();
+    builder.setOptionalSint32(1);
+    assertEquals(0, message.getOptionalSint32());
+    assertEquals(1, builder.getOptionalSint32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalSint32());
+    builder.clearOptionalSint32();
+    assertEquals(0, builder.getOptionalSint32());
+    assertEquals(1, messageAfterBuild.getOptionalSint32());
+
+    message = builder.build();
+    builder.setOptionalSint64(1);
+    assertEquals(0L, message.getOptionalSint64());
+    assertEquals(1L, builder.getOptionalSint64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalSint64());
+    assertEquals(0L, message.getOptionalSint64());
+    builder.clearOptionalSint64();
+    assertEquals(0L, builder.getOptionalSint64());
+    assertEquals(1L, messageAfterBuild.getOptionalSint64());
+
+    message = builder.build();
+    builder.setOptionalString("hi");
+    assertEquals("", message.getOptionalString());
+    assertEquals("hi", builder.getOptionalString());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalString());
+    assertEquals("", message.getOptionalString());
+    builder.clearOptionalString();
+    assertEquals("", builder.getOptionalString());
+    assertEquals("hi", messageAfterBuild.getOptionalString());
+
+    message = builder.build();
+    builder.setOptionalStringBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
+    builder.clearOptionalString();
+    assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringBytes());
+    
+    message = builder.build();
+    builder.setOptionalStringPiece("hi");
+    assertEquals("", message.getOptionalStringPiece());
+    assertEquals("hi", builder.getOptionalStringPiece());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
+    assertEquals("", message.getOptionalStringPiece());
+    builder.clearOptionalStringPiece();
+    assertEquals("", builder.getOptionalStringPiece());
+    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
+
+    message = builder.build();
+    builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringPieceBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
+    builder.clearOptionalStringPiece();
+    assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringPieceBytes());
+
+    message = builder.build();
+    builder.setOptionalUint32(1);
+    assertEquals(0, message.getOptionalUint32());
+    assertEquals(1, builder.getOptionalUint32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalUint32());
+    assertEquals(0, message.getOptionalUint32());
+    builder.clearOptionalUint32();
+    assertEquals(0, builder.getOptionalUint32());
+    assertEquals(1, messageAfterBuild.getOptionalUint32());
+
+    message = builder.build();
+    builder.setOptionalUint64(1);
+    assertEquals(0L, message.getOptionalUint64());
+    assertEquals(1L, builder.getOptionalUint64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalUint64());
+    assertEquals(0L, message.getOptionalUint64());
+    builder.clearOptionalUint64();
+    assertEquals(0L, builder.getOptionalUint64());
+    assertEquals(1L, messageAfterBuild.getOptionalUint64());
+
+    message = builder.build();
+    builder.addAllRepeatedBool(singletonList(true));
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertEquals(singletonList(true), builder.getRepeatedBoolList());
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBool();
+    assertEquals(emptyList(), builder.getRepeatedBoolList());
+    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+
+    message = builder.build();
+    builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi")));
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        builder.getRepeatedBytesList());
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBytes();
+    assertEquals(emptyList(), builder.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        messageAfterBuild.getRepeatedBytesList());
+
+    message = builder.build();
+    builder.addAllRepeatedCord(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedCord();
+    assertEquals(emptyList(), builder.getRepeatedCordList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+
+    message = builder.build();
+    builder.addAllRepeatedDouble(singletonList(1D));
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedDouble();
+    assertEquals(emptyList(), builder.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+
+    message = builder.build();
+    builder.addAllRepeatedFixed32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed32();
+    assertEquals(emptyList(), builder.getRepeatedFixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+
+    message = builder.build();
+    builder.addAllRepeatedFixed64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed64();
+    assertEquals(emptyList(), builder.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+
+    message = builder.build();
+    builder.addAllRepeatedFloat(singletonList(1F));
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFloat();
+    assertEquals(emptyList(), builder.getRepeatedFloatList());
+    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+
+    message = builder.build();
+    builder.addAllRepeatedForeignEnum(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        builder.getRepeatedForeignEnumList());
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignEnum();
+    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        messageAfterBuild.getRepeatedForeignEnumList());
+
+    message = builder.build();
+    builder.addAllRepeatedForeignMessage(singletonList(foreignMessage));
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignMessage();
+    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage),
+        messageAfterBuild.getRepeatedForeignMessageList());
+
+    message = builder.build();
+    builder.addAllRepeatedGroup(
+        singletonList(RepeatedGroup.getDefaultInstance()));
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        builder.getRepeatedGroupList());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedGroup();
+    assertEquals(emptyList(), builder.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        messageAfterBuild.getRepeatedGroupList());
+
+    message = builder.build();
+    builder.addAllRepeatedInt32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertEquals(singletonList(1), builder.getRepeatedInt32List());
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt32();
+    assertEquals(emptyList(), builder.getRepeatedInt32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+
+    message = builder.build();
+    builder.addAllRepeatedInt64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt64();
+    assertEquals(emptyList(), builder.getRepeatedInt64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+
+    message = builder.build();
+    builder.addAllRepeatedLazyMessage(singletonList(nestedMessage));
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedLazyMessage();
+    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage),
+        messageAfterBuild.getRepeatedLazyMessageList());
+
+    message = builder.build();
+    builder.addAllRepeatedSfixed32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed32();
+    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+
+    message = builder.build();
+    builder.addAllRepeatedSfixed64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed64();
+    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
+    assertEquals(
+        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+
+    message = builder.build();
+    builder.addAllRepeatedSint32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertEquals(singletonList(1), builder.getRepeatedSint32List());
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint32();
+    assertEquals(emptyList(), builder.getRepeatedSint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+
+    message = builder.build();
+    builder.addAllRepeatedSint64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint64();
+    assertEquals(emptyList(), builder.getRepeatedSint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+
+    message = builder.build();
+    builder.addAllRepeatedString(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedString();
+    assertEquals(emptyList(), builder.getRepeatedStringList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+
+    message = builder.build();
+    builder.addAllRepeatedStringPiece(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedStringPiece();
+    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+
+    message = builder.build();
+    builder.addAllRepeatedUint32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertEquals(singletonList(1), builder.getRepeatedUint32List());
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint32();
+    assertEquals(emptyList(), builder.getRepeatedUint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+
+    message = builder.build();
+    builder.addAllRepeatedUint64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint64();
+    assertEquals(emptyList(), builder.getRepeatedUint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+
+    message = builder.build();
+    builder.addRepeatedBool(true);
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertEquals(singletonList(true), builder.getRepeatedBoolList());
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBool();
+    assertEquals(emptyList(), builder.getRepeatedBoolList());
+    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+
+    message = builder.build();
+    builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        builder.getRepeatedBytesList());
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBytes();
+    assertEquals(emptyList(), builder.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        messageAfterBuild.getRepeatedBytesList());
+
+    message = builder.build();
+    builder.addRepeatedCord("hi");
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedCord();
+    assertEquals(emptyList(), builder.getRepeatedCordList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+
+    message = builder.build();
+    builder.addRepeatedDouble(1D);
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedDouble();
+    assertEquals(emptyList(), builder.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+
+    message = builder.build();
+    builder.addRepeatedFixed32(1);
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed32();
+    assertEquals(emptyList(), builder.getRepeatedFixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+
+    message = builder.build();
+    builder.addRepeatedFixed64(1L);
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed64();
+    assertEquals(emptyList(), builder.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+
+    message = builder.build();
+    builder.addRepeatedFloat(1F);
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFloat();
+    assertEquals(emptyList(), builder.getRepeatedFloatList());
+    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+
+    message = builder.build();
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        builder.getRepeatedForeignEnumList());
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignEnum();
+    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        messageAfterBuild.getRepeatedForeignEnumList());
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessage);
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedForeignMessage(0);
+    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage),
+        messageAfterBuild.getRepeatedForeignMessageList());
+
+    message = builder.build();
+    builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        builder.getRepeatedGroupList());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedGroup(0);
+    assertEquals(emptyList(), builder.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        messageAfterBuild.getRepeatedGroupList());
+
+    message = builder.build();
+    builder.addRepeatedInt32(1);
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertEquals(singletonList(1), builder.getRepeatedInt32List());
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt32();
+    assertEquals(emptyList(), builder.getRepeatedInt32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+
+    message = builder.build();
+    builder.addRepeatedInt64(1L);
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt64();
+    assertEquals(emptyList(), builder.getRepeatedInt64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessage);
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedLazyMessage(0);
+    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage),
+        messageAfterBuild.getRepeatedLazyMessageList());
+
+    message = builder.build();
+    builder.addRepeatedSfixed32(1);
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed32();
+    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+
+    message = builder.build();
+    builder.addRepeatedSfixed64(1L);
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed64();
+    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
+    assertEquals(
+        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+
+    message = builder.build();
+    builder.addRepeatedSint32(1);
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertEquals(singletonList(1), builder.getRepeatedSint32List());
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint32();
+    assertEquals(emptyList(), builder.getRepeatedSint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+
+    message = builder.build();
+    builder.addRepeatedSint64(1L);
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint64();
+    assertEquals(emptyList(), builder.getRepeatedSint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+
+    message = builder.build();
+    builder.addRepeatedString("hi");
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedString();
+    assertEquals(emptyList(), builder.getRepeatedStringList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+
+    message = builder.build();
+    builder.addRepeatedStringPiece("hi");
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedStringPiece();
+    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+
+    message = builder.build();
+    builder.addRepeatedUint32(1);
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertEquals(singletonList(1), builder.getRepeatedUint32List());
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint32();
+    assertEquals(emptyList(), builder.getRepeatedUint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+
+    message = builder.build();
+    builder.addRepeatedUint64(1L);
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint64();
+    assertEquals(emptyList(), builder.getRepeatedUint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+    
+    message = builder.build();
+    builder.addRepeatedBool(true);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedBoolCount());
+    builder.setRepeatedBool(0, false);
+    assertEquals(true, messageAfterBuild.getRepeatedBool(0));
+    assertEquals(false, builder.getRepeatedBool(0));
+    builder.clearRepeatedBool();
+    
+    message = builder.build();
+    builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedBytesCount());
+    builder.setRepeatedBytes(0, ByteString.EMPTY);
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0));
+    builder.clearRepeatedBytes();
+
+    message = builder.build();
+    builder.addRepeatedCord("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedCordCount());
+    builder.setRepeatedCord(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedCord(0));
+    assertEquals("", builder.getRepeatedCord(0));
+    builder.clearRepeatedCord();
+    message = builder.build();
+
+    builder.addRepeatedCordBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedCordCount());
+    builder.setRepeatedCord(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0));
+    builder.clearRepeatedCord();
+
+    message = builder.build();
+    builder.addRepeatedDouble(1D);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedDoubleCount());
+    builder.setRepeatedDouble(0, 0D);
+    assertEquals(1D, messageAfterBuild.getRepeatedDouble(0));
+    assertEquals(0D, builder.getRepeatedDouble(0));
+    builder.clearRepeatedDouble();
+
+    message = builder.build();
+    builder.addRepeatedFixed32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFixed32Count());
+    builder.setRepeatedFixed32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedFixed32(0));
+    assertEquals(0, builder.getRepeatedFixed32(0));
+    builder.clearRepeatedFixed32();
+
+    message = builder.build();
+    builder.addRepeatedFixed64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFixed64Count());
+    builder.setRepeatedFixed64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedFixed64(0));
+    assertEquals(0L, builder.getRepeatedFixed64(0));
+    builder.clearRepeatedFixed64();
+
+    message = builder.build();
+    builder.addRepeatedFloat(1F);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFloatCount());
+    builder.setRepeatedFloat(0, 0F);
+    assertEquals(1F, messageAfterBuild.getRepeatedFloat(0));
+    assertEquals(0F, builder.getRepeatedFloat(0));
+    builder.clearRepeatedFloat();
+
+    message = builder.build();
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignEnumCount());
+    builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO);
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getRepeatedForeignEnum(0));
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
+    builder.clearRepeatedForeignEnum();
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(
+        0, ForeignMessageLite.getDefaultInstance());
+    assertEquals(
+        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getRepeatedForeignMessage(0));
+    builder.clearRepeatedForeignMessage();
+    
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(
+        0, ForeignMessageLite.getDefaultInstance());
+    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getRepeatedForeignMessage(0));
+    builder.clearRepeatedForeignMessage();
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(0, foreignMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
+    assertEquals(
+        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
+    builder.clearRepeatedForeignMessage();
+
+    message = builder.build();
+    RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder()
+        .setA(1)
+        .build();
+    builder.addRepeatedGroup(repeatedGroup);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    builder.addRepeatedGroup(0, repeatedGroup);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder()
+        .setA(3);
+    builder.addRepeatedGroup(repeatedGroupBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    builder.addRepeatedGroup(0, repeatedGroupBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+
+    message = builder.build();
+    builder.addRepeatedInt32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedInt32Count());
+    builder.setRepeatedInt32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedInt32(0));
+    assertEquals(0, builder.getRepeatedInt32(0));
+    builder.clearRepeatedInt32();
+
+    message = builder.build();
+    builder.addRepeatedInt64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedInt64Count());
+    builder.setRepeatedInt64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedInt64(0));
+    assertEquals(0L, builder.getRepeatedInt64(0));
+    builder.clearRepeatedInt64();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(0, nestedMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(0, nestedMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+
+    message = builder.build();
+    builder.addRepeatedSfixed32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedSfixed32Count());
+    builder.setRepeatedSfixed32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedSfixed32(0));
+    assertEquals(0, builder.getRepeatedSfixed32(0));
+    builder.clearRepeatedSfixed32();
+
+    message = builder.build();
+    builder.addRepeatedSfixed64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedSfixed64Count());
+    builder.setRepeatedSfixed64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedSfixed64(0));
+    assertEquals(0L, builder.getRepeatedSfixed64(0));
+    builder.clearRepeatedSfixed64();
+
+    message = builder.build();
+    builder.addRepeatedSint32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedSint32Count());
+    builder.setRepeatedSint32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedSint32(0));
+    assertEquals(0, builder.getRepeatedSint32(0));
+    builder.clearRepeatedSint32();
+
+    message = builder.build();
+    builder.addRepeatedSint64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedSint64Count());
+    builder.setRepeatedSint64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedSint64(0));
+    assertEquals(0L, builder.getRepeatedSint64(0));
+    builder.clearRepeatedSint64();
+
+    message = builder.build();
+    builder.addRepeatedString("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringCount());
+    builder.setRepeatedString(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedString(0));
+    assertEquals("", builder.getRepeatedString(0));
+    builder.clearRepeatedString();
+
+    message = builder.build();
+    builder.addRepeatedStringBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringCount());
+    builder.setRepeatedString(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"),
+        messageAfterBuild.getRepeatedStringBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0));
+    builder.clearRepeatedString();
+
+    message = builder.build();
+    builder.addRepeatedStringPiece("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringPieceCount());
+    builder.setRepeatedStringPiece(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedStringPiece(0));
+    assertEquals("", builder.getRepeatedStringPiece(0));
+    builder.clearRepeatedStringPiece();
+
+    message = builder.build();
+    builder.addRepeatedStringPieceBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringPieceCount());
+    builder.setRepeatedStringPiece(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"),
+        messageAfterBuild.getRepeatedStringPieceBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0));
+    builder.clearRepeatedStringPiece();
+
+    message = builder.build();
+    builder.addRepeatedUint32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedUint32Count());
+    builder.setRepeatedUint32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedUint32(0));
+    assertEquals(0, builder.getRepeatedUint32(0));
+    builder.clearRepeatedUint32();
+
+    message = builder.build();
+    builder.addRepeatedUint64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedUint64Count());
+    builder.setRepeatedUint64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedUint64(0));
+    assertEquals(0L, builder.getRepeatedUint64(0));
+    builder.clearRepeatedUint64();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeFrom(TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .build());
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(true, builder.build().getOptionalBool());
+    builder.clearOptionalBool();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeFrom(TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .build());
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(true, builder.build().getOptionalBool());
+    builder.clear();
+    assertEquals(0, builder.build().getSerializedSize());
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeOptionalForeignMessage(foreignMessage);
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(
+        foreignMessage.getC(),
+        builder.build().getOptionalForeignMessage().getC());
+    builder.clearOptionalForeignMessage();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeOptionalLazyMessage(nestedMessage);
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(
+        nestedMessage.getBb(),
+        builder.build().getOptionalLazyMessage().getBb());
+    builder.clearOptionalLazyMessage();
+    
+    message = builder.build();
+    builder.setOneofString("hi");
+    assertEquals(
+        OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
+    assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase());
+    assertEquals("hi", builder.getOneofString());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals("hi", messageAfterBuild.getOneofString());
+    builder.setOneofUint32(1);
+    assertEquals(
+        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals("hi", messageAfterBuild.getOneofString());
+    assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
+    assertEquals(1, builder.getOneofUint32());
+    TestAllTypesLiteOrBuilder messageOrBuilder = builder;
+    assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase());
+    
+    TestAllExtensionsLite.Builder extendableMessageBuilder =
+        TestAllExtensionsLite.newBuilder();
+    TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build();
+    extendableMessageBuilder.setExtension(
+        UnittestLite.optionalInt32ExtensionLite, 1);
+    assertFalse(extendableMessage.hasExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    extendableMessage = extendableMessageBuilder.build();
+    assertEquals(
+        1, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    extendableMessageBuilder.setExtension(
+        UnittestLite.optionalInt32ExtensionLite, 3);
+    assertEquals(
+        3, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    extendableMessage = extendableMessageBuilder.build();
+    assertEquals(
+        3, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        3, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    
+    // No extension registry, so it should be in unknown fields.
+    extendableMessage =
+        TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
+    assertFalse(extendableMessage.hasExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    
+    extendableMessageBuilder = extendableMessage.toBuilder();
+    extendableMessageBuilder.mergeFrom(TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
+        .build());
+    
+    extendableMessage = extendableMessageBuilder.build();
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+    extendableMessage = TestAllExtensionsLite.parseFrom(
+        extendableMessage.toByteArray(), registry);
+    
+    // The unknown field was preserved.
+    assertEquals(
+        3, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        11, (int) extendableMessage.getExtension(
+            UnittestLite.optionalFixed32ExtensionLite));
+  }
+
+  public void testToStringDefaultInstance() throws Exception {
+    assertToStringEquals("", TestAllTypesLite.getDefaultInstance());
+  }
+
+  public void testToStringPrimitives() throws Exception {
+    TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalInt64(9223372036854775807L)
+        .build();
+    assertToStringEquals("optional_int32: 1\noptional_int64: 9223372036854775807", proto);
+
+    proto = TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .setOptionalNestedEnum(TestAllTypesLite.NestedEnum.BAZ)
+        .build();
+    assertToStringEquals("optional_bool: true\noptional_nested_enum: BAZ", proto);
+
+    proto = TestAllTypesLite.newBuilder()
+        .setOptionalFloat(2.72f)
+        .setOptionalDouble(3.14)
+        .build();
+    assertToStringEquals("optional_double: 3.14\noptional_float: 2.72", proto);
+  }
+
+  public void testToStringStringFields() throws Exception {
+    TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+        .setOptionalString("foo\"bar\nbaz\\")
+        .build();
+    assertToStringEquals("optional_string: \"foo\\\"bar\\nbaz\\\\\"", proto);
+
+    proto = TestAllTypesLite.newBuilder()
+        .setOptionalString("\u6587")
+        .build();
+    assertToStringEquals("optional_string: \"\\346\\226\\207\"", proto);
+  }
+
+  public void testToStringNestedMessage() throws Exception {
+    TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+        .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.getDefaultInstance())
+        .build();
+    assertToStringEquals("optional_nested_message {\n}", proto);
+
+    proto = TestAllTypesLite.newBuilder()
+        .setOptionalNestedMessage(
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+        .build();
+    assertToStringEquals("optional_nested_message {\n  bb: 7\n}", proto);
+  }
+
+  public void testToStringRepeatedFields() throws Exception {
+    TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+        .addRepeatedInt32(32)
+        .addRepeatedInt32(32)
+        .addRepeatedInt64(64)
+        .build();
+    assertToStringEquals("repeated_int32: 32\nrepeated_int32: 32\nrepeated_int64: 64", proto);
+
+    proto = TestAllTypesLite.newBuilder()
+        .addRepeatedLazyMessage(
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+        .addRepeatedLazyMessage(
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(8))
+        .build();
+    assertToStringEquals(
+        "repeated_lazy_message {\n  bb: 7\n}\nrepeated_lazy_message {\n  bb: 8\n}",
+        proto);
+  }
+
+  public void testToStringForeignFields() throws Exception {
+    TestAllTypesLite proto = TestAllTypesLite.newBuilder()
+        .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+        .setOptionalForeignMessage(
+            ForeignMessageLite.newBuilder()
+            .setC(3))
+        .build();
+    assertToStringEquals(
+        "optional_foreign_enum: FOREIGN_LITE_BAR\noptional_foreign_message {\n  c: 3\n}",
+        proto);
+  }
+
+  public void testToStringExtensions() throws Exception {
+    TestAllExtensionsLite message = TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+            TestAllTypesLite.NestedEnum.BAZ)
+        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+        .build();
+    assertToStringEquals(
+        "[1]: 123\n[18] {\n  bb: 7\n}\n[21]: 3\n[44]: \"spam\"\n[44]: \"eggs\"",
+        message);
+  }
+
+  public void testToStringUnknownFields() throws Exception {
+    TestAllExtensionsLite messageWithExtensions = TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "spam")
+        .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs")
+        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+            TestAllTypesLite.NestedEnum.BAZ)
+        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+        .build();
+    TestAllExtensionsLite messageWithUnknownFields = TestAllExtensionsLite.parseFrom(
+        messageWithExtensions.toByteArray());
+    assertToStringEquals(
+        "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"",
+        messageWithUnknownFields);
+  }
+  
+  public void testToStringLazyMessage() throws Exception {
+    TestAllTypesLite message = TestAllTypesLite.newBuilder()
+        .setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1).build())
+        .build();
+    assertToStringEquals("optional_lazy_message {\n  bb: 1\n}", message);
+  }
+  
+  public void testToStringGroup() throws Exception {
+    TestAllTypesLite message = TestAllTypesLite.newBuilder()
+        .setOptionalGroup(OptionalGroup.newBuilder().setA(1).build())
+        .build();
+    assertToStringEquals("optional_group {\n  a: 1\n}", message);
+  }
+  
+  public void testToStringOneof() throws Exception {
+    TestAllTypesLite message = TestAllTypesLite.newBuilder()
+        .setOneofString("hello")
+        .build();
+    assertToStringEquals("oneof_string: \"hello\"", message);
+  }
+
+  // Asserts that the toString() representation of the message matches the expected. This verifies
+  // the first line starts with a comment; but, does not factor in said comment as part of the
+  // comparison as it contains unstable addresses.
+  private static void assertToStringEquals(String expected, MessageLite message) {
+    String toString = message.toString();
+    assertEquals('#', toString.charAt(0));
+    if (toString.indexOf("\n") >= 0) {
+      toString = toString.substring(toString.indexOf("\n") + 1);
+    } else {
+      toString = "";
+    }
+    assertEquals(expected, toString);
+  }
+  
+  public void testParseLazy() throws Exception {
+    ByteString bb = TestAllTypesLite.newBuilder()
+        .setOptionalLazyMessage(NestedMessage.newBuilder()
+            .setBb(11)
+            .build())
+        .build().toByteString();
+    ByteString cc = TestAllTypesLite.newBuilder()
+        .setOptionalLazyMessage(NestedMessage.newBuilder()
+            .setCc(22)
+            .build())
+        .build().toByteString();
+    
+    ByteString concat = bb.concat(cc);
+    TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+    assertEquals(11, message.getOptionalLazyMessage().getBb());
+    assertEquals(22L, message.getOptionalLazyMessage().getCc());
+  }
+  
+  public void testParseLazy_oneOf() throws Exception {
+    ByteString bb = TestAllTypesLite.newBuilder()
+        .setOneofLazyNestedMessage(NestedMessage.newBuilder()
+            .setBb(11)
+            .build())
+        .build().toByteString();
+    ByteString cc = TestAllTypesLite.newBuilder()
+        .setOneofLazyNestedMessage(NestedMessage.newBuilder()
+            .setCc(22)
+            .build())
+        .build().toByteString();
+    
+    ByteString concat = bb.concat(cc);
+    TestAllTypesLite message = TestAllTypesLite.parseFrom(concat);
+
+    assertEquals(11, message.getOneofLazyNestedMessage().getBb());
+    assertEquals(22L, message.getOneofLazyNestedMessage().getCc());
+  }
+
+  public void testMergeFromStream_repeatedField() throws Exception {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder()
+        .addRepeatedString("hello");
+    builder.mergeFrom(CodedInputStream.newInstance(builder.build().toByteArray()));
+
+    assertEquals(2, builder.getRepeatedStringCount());
+  }
+
+  public void testMergeFromStream_invalidBytes() throws Exception {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder()
+        .setDefaultBool(true);
+    try {
+      builder.mergeFrom(CodedInputStream.newInstance("Invalid bytes".getBytes(Internal.UTF_8)));
+      fail();
+    } catch (InvalidProtocolBufferException expected) {}
+  }
+  
+  public void testMergeFrom_sanity() throws Exception {
+    TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+    byte[] bytes = one.toByteArray();
+    TestAllTypesLite two = TestAllTypesLite.parseFrom(bytes);
+    
+    one = one.toBuilder().mergeFrom(one).build();
+    two = two.toBuilder().mergeFrom(bytes).build();
+    assertEquals(one, two);
+    assertEquals(two, one);
+    assertEquals(one.hashCode(), two.hashCode());
+  }
+  
+  public void testEquals_notEqual() throws Exception {
+    TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+    byte[] bytes = one.toByteArray();
+    TestAllTypesLite two = one.toBuilder().mergeFrom(one).mergeFrom(bytes).build();
+    
+    assertFalse(one.equals(two));
+    assertFalse(two.equals(one));
+    
+    assertFalse(one.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(one));
+    
+    TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultBool(true)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultCord("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultCordBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultDouble(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultFixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultFixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultFloat(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultInt32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultInt64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultNestedEnum(NestedEnum.BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultSfixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultSfixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultSint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultSint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultString("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultStringBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultStringPiece("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultStringPieceBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultUint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setDefaultUint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedBool(true)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedCord("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedCordBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedDouble(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedFixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedFixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedFloat(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedInt32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedInt64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedNestedEnum(NestedEnum.BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedSfixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedSfixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedSint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedSint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedString("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedStringBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedStringPiece("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedStringPieceBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedUint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedUint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalCord("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalCordBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalDouble(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalFixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalFixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalFloat(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalImportEnum(ImportEnumLite.IMPORT_LITE_BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalInt32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalInt64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalNestedEnum(NestedEnum.BAR)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalSfixed32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalSfixed64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalSint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalSint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalString("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalStringBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalStringPiece("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalStringPieceBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalUint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalUint64(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofString("")
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofStringBytes(ByteString.EMPTY)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOneofUint32(0)
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalGroup(OptionalGroup.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .setOptionalLazyMessage(NestedMessage.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+    oneFieldSet = TestAllTypesLite.newBuilder()
+        .addRepeatedLazyMessage(NestedMessage.getDefaultInstance())
+        .build();
+    assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance()));
+    assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet));
+  }
+
+  public void testEquals() throws Exception {
+    // Check that two identical objs are equal.
+    Foo foo1a = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo1b = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo1"))
+        .build();
+    Foo foo2 = Foo.newBuilder()
+        .setValue(1)
+        .addBar(Bar.newBuilder().setName("foo2"))
+        .build();
+
+    // Check that equals is doing value rather than object equality.
+    assertEquals(foo1a, foo1b);
+    assertEquals(foo1a.hashCode(), foo1b.hashCode());
+
+    // Check that a diffeent object is not equal.
+    assertFalse(foo1a.equals(foo2));
+
+    // Check that two objects which have different types but the same field values are not
+    // considered to be equal.
+    Bar bar = Bar.newBuilder().setName("bar").build();
+    BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
+    assertFalse(bar.equals(barPrime));
+  }
+
+  public void testOneofEquals() throws Exception {
+    TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
+    TestOneofEquals message1 = builder.build();
+    // Set message2's name field to default value. The two messages should be different when we
+    // check with the oneof case.
+    builder.setName("");
+    TestOneofEquals message2 = builder.build();
+    assertFalse(message1.equals(message2));
+  }
+  
+  public void testEquals_sanity() throws Exception {
+    TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
+    TestAllTypesLite two = TestAllTypesLite.parseFrom(one.toByteArray());
+    assertEquals(one, two);
+    assertEquals(one.hashCode(), two.hashCode());
+    
+    assertEquals(
+        one.toBuilder().mergeFrom(two).build(),
+        two.toBuilder().mergeFrom(two.toByteArray()).build());
+  }
+
+  public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException {
+    Foo fooWithOnlyValue = Foo.newBuilder()
+        .setValue(1)
+        .build();
+
+    Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
+        .setValue(1)
+        .setExtension(Bar.fooExt, Bar.newBuilder()
+            .setName("name")
+            .build())
+        .build();
+
+    Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray());
+
+    assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields);
+    assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
+  }
+  
+  // Test to ensure we avoid a class cast exception with oneofs.
+  public void testEquals_oneOfMessages() {
+    TestAllTypesLite mine = TestAllTypesLite.newBuilder()
+        .setOneofString("Hello")
+        .build();
+    
+    TestAllTypesLite other = TestAllTypesLite.newBuilder()
+        .setOneofNestedMessage(NestedMessage.getDefaultInstance())
+        .build();
+    
+    assertFalse(mine.equals(other));
+    assertFalse(other.equals(mine));
+  }
+
+  private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
+    assertFalse(o1.equals(o2));
+    assertFalse(o1.hashCode() == o2.hashCode());
+  }
+
+  public void testRecursiveHashcode() {
+    // This tests that we don't infinite loop.
+    TestRecursiveOneof.getDefaultInstance().hashCode();
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
new file mode 100644
index 0000000..2e7792a
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -0,0 +1,545 @@
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}.
+ * This class is designed to be extended for testing extensions of {@code LiteralByteString}
+ * such as {@code BoundedByteString}, see {@link BoundedByteStringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class LiteralByteStringTest extends TestCase {
+  protected static final String UTF_8 = "UTF-8";
+
+  protected String classUnderTest;
+  protected byte[] referenceBytes;
+  protected ByteString stringUnderTest;
+  protected int expectedHashCode;
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "LiteralByteString";
+    referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
+    stringUnderTest = ByteString.copyFrom(referenceBytes);
+    expectedHashCode = 331161852;
+  }
+
+  public void testExpectedType() {
+    String actualClassName = getActualClassName(stringUnderTest);
+    assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName);
+  }
+
+  protected String getActualClassName(Object object) {
+    return object.getClass().getSimpleName();
+  }
+
+  public void testByteAt() {
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
+      stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i));
+    }
+    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
+  }
+
+  public void testByteIterator() {
+    boolean stillEqual = true;
+    ByteString.ByteIterator iter = stringUnderTest.iterator();
+    for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
+      stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte());
+    }
+    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
+    assertFalse(classUnderTest + " must have exhausted the itertor", iter.hasNext());
+
+    try {
+      iter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+  }
+
+  public void testByteIterable() {
+    boolean stillEqual = true;
+    int j = 0;
+    for (byte quantum : stringUnderTest) {
+      stillEqual = (referenceBytes[j] == quantum);
+      ++j;
+    }
+    assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
+    assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
+  }
+
+  public void testSize() {
+    assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
+        stringUnderTest.size());
+  }
+
+  public void testGetTreeDepth() {
+    assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth());
+  }
+
+  public void testIsBalanced() {
+    assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced());
+  }
+
+  public void testCopyTo_ByteArrayOffsetLength() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+    int sourceOffset = 213;
+    stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length);
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < length; ++i) {
+      stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset];
+    }
+    assertTrue(classUnderTest + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+  }
+
+  public void testCopyTo_ByteArrayOffsetLengthErrors() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+
+    try {
+      // Copy one too many bytes
+      stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length,
+          destinationOffset, length);
+      fail("Should have thrown an exception when copying too many bytes of a "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative sourceOffset
+      stringUnderTest.copyTo(destination, -1, destinationOffset, length);
+      fail("Should have thrown an exception when given a negative sourceOffset in "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative destinationOffset
+      stringUnderTest.copyTo(destination, 0, -1, length);
+      fail("Should have thrown an exception when given a negative destinationOffset in "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative size
+      stringUnderTest.copyTo(destination, 0, 0, -1);
+      fail("Should have thrown an exception when given a negative size in "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large sourceOffset
+      stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large destinationOffset
+      stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + classUnderTest);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+  }
+
+  public void testCopyTo_ByteBuffer() {
+    ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
+    stringUnderTest.copyTo(myBuffer);
+    assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
+        Arrays.equals(referenceBytes, myBuffer.array()));
+  }
+
+  public void testMarkSupported() {
+    InputStream stream = stringUnderTest.newInput();
+    assertTrue(classUnderTest + ".newInput() must support marking", stream.markSupported());
+  }
+
+  public void testMarkAndReset() throws IOException {
+    int fraction = stringUnderTest.size() / 3;
+
+    InputStream stream = stringUnderTest.newInput();
+    stream.mark(stringUnderTest.size()); // First, mark() the end.
+
+    skipFully(stream, fraction); // Skip a large fraction, but not all.
+    int available = stream.available();
+    assertTrue(
+        classUnderTest + ": after skipping to the 'middle', half the bytes are available",
+        (stringUnderTest.size() - fraction) == available);
+    stream.reset();
+
+    skipFully(stream, stringUnderTest.size()); // Skip to the end.
+    available = stream.available();
+    assertTrue(
+        classUnderTest + ": after skipping to the end, no more bytes are available",
+        0 == available);
+  }
+
+  /**
+   * Discards {@code n} bytes of data from the input stream. This method
+   * will block until the full amount has been skipped. Does not close the
+   * stream.
+   * <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency.
+   *
+   * @param in the input stream to read from
+   * @param n the number of bytes to skip
+   * @throws EOFException if this stream reaches the end before skipping all
+   *     the bytes
+   * @throws IOException if an I/O error occurs, or the stream does not
+   *     support skipping
+   */
+  static void skipFully(InputStream in, long n) throws IOException {
+    long toSkip = n;
+    while (n > 0) {
+      long amt = in.skip(n);
+      if (amt == 0) {
+        // Force a blocking read to avoid infinite loop
+        if (in.read() == -1) {
+          long skipped = toSkip - n;
+          throw new EOFException("reached end of stream after skipping "
+              + skipped + " bytes; " + toSkip + " bytes expected");
+        }
+        n--;
+      } else {
+        n -= amt;
+      }
+    }
+  }
+
+  public void testAsReadOnlyByteBuffer() {
+    ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
+    byte[] roundTripBytes = new byte[referenceBytes.length];
+    assertTrue(byteBuffer.remaining() == referenceBytes.length);
+    assertTrue(byteBuffer.isReadOnly());
+    byteBuffer.get(roundTripBytes);
+    assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  public void testAsReadOnlyByteBufferList() {
+    List<ByteBuffer> byteBuffers = stringUnderTest.asReadOnlyByteBufferList();
+    int bytesSeen = 0;
+    byte[] roundTripBytes = new byte[referenceBytes.length];
+    for (ByteBuffer byteBuffer : byteBuffers) {
+      int thisLength = byteBuffer.remaining();
+      assertTrue(byteBuffer.isReadOnly());
+      assertTrue(bytesSeen + thisLength <= referenceBytes.length);
+      byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
+      bytesSeen += thisLength;
+    }
+    assertTrue(bytesSeen == referenceBytes.length);
+    assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  public void testToByteArray() {
+    byte[] roundTripBytes = stringUnderTest.toByteArray();
+    assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  public void testWriteTo() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    stringUnderTest.writeTo(bos);
+    byte[] roundTripBytes = bos.toByteArray();
+    assertTrue(classUnderTest + ".writeTo() must give back the same bytes",
+        Arrays.equals(referenceBytes, roundTripBytes));
+  }
+
+  public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    stringUnderTest.writeTo(os);
+    assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
+        Arrays.equals(referenceBytes, stringUnderTest.toByteArray()));
+  }
+
+  public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    stringUnderTest.writeToInternal(os, 0, stringUnderTest.size());
+    byte[] allZeros = new byte[stringUnderTest.size()];
+    assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
+        Arrays.equals(allZeros, stringUnderTest.toByteArray()));
+  }
+
+  public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+    ByteOutput out = new ByteOutput() {
+      @Override
+      public void write(byte value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(byte[] value, int offset, int length) throws IOException {
+        Arrays.fill(value, offset, offset + length, (byte) 0);
+      }
+
+      @Override
+      public void write(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    stringUnderTest.writeTo(out);
+    byte[] allZeros = new byte[stringUnderTest.size()];
+    assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array",
+        Arrays.equals(allZeros, stringUnderTest.toByteArray()));
+  }
+
+  public void testNewOutput() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    ByteString.Output output = ByteString.newOutput();
+    stringUnderTest.writeTo(output);
+    assertEquals("Output Size returns correct result",
+        output.size(), stringUnderTest.size());
+    output.writeTo(bos);
+    assertTrue("Output.writeTo() must give back the same bytes",
+        Arrays.equals(referenceBytes, bos.toByteArray()));
+
+    // write the output stream to itself! This should cause it to double
+    output.writeTo(output);
+    assertEquals("Writing an output stream to itself is successful",
+        stringUnderTest.concat(stringUnderTest), output.toByteString());
+
+    output.reset();
+    assertEquals("Output.reset() resets the output", 0, output.size());
+    assertEquals("Output.reset() resets the output",
+        ByteString.EMPTY, output.toByteString());
+  }
+
+  public void testToString() throws UnsupportedEncodingException {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
+  }
+
+  public void testCharsetToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
+    String roundTripString = unicode.toString(Internal.UTF_8);
+    assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
+  }
+
+  public void testToString_returnsCanonicalEmptyString() {
+    assertSame(classUnderTest + " must be the same string references",
+        ByteString.EMPTY.toString(Internal.UTF_8),
+        ByteString.wrap(new byte[]{}).toString(Internal.UTF_8));
+  }
+
+  public void testToString_raisesException() {
+    try {
+      ByteString.EMPTY.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      ByteString.wrap(referenceBytes).toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
+  public void testEquals() {
+    assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
+    assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
+    assertFalse(classUnderTest + " must not equal the empty string",
+        stringUnderTest.equals(ByteString.EMPTY));
+    assertEquals(classUnderTest + " empty strings must be equal",
+        ByteString.wrap(new byte[]{}), stringUnderTest.substring(55, 55));
+    assertEquals(classUnderTest + " must equal another string with the same value",
+        stringUnderTest, ByteString.wrap(referenceBytes));
+
+    byte[] mungedBytes = new byte[referenceBytes.length];
+    System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
+    mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
+    assertFalse(classUnderTest + " must not equal every string with the same length",
+        stringUnderTest.equals(ByteString.wrap(mungedBytes)));
+  }
+
+  public void testHashCode() {
+    int hash = stringUnderTest.hashCode();
+    assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
+  }
+
+  public void testPeekCachedHashCode() {
+    assertEquals(classUnderTest + ".peekCachedHashCode() should return zero at first", 0,
+        stringUnderTest.peekCachedHashCode());
+    stringUnderTest.hashCode();
+    assertEquals(classUnderTest + ".peekCachedHashCode should return zero at first",
+        expectedHashCode, stringUnderTest.peekCachedHashCode());
+  }
+
+  public void testPartialHash() {
+    // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
+    // This test would fail if the expected hash were 1.  It's not.
+    int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
+    assertEquals(classUnderTest + ".partialHash() must yield expected hashCode",
+        expectedHashCode, hash);
+  }
+
+  public void testNewInput() throws IOException {
+    InputStream input = stringUnderTest.newInput();
+    assertEquals("InputStream.available() returns correct value",
+        stringUnderTest.size(), input.available());
+    boolean stillEqual = true;
+    for (byte referenceByte : referenceBytes) {
+      int expectedInt = (referenceByte & 0xFF);
+      stillEqual = (expectedInt == input.read());
+    }
+    assertEquals("InputStream.available() returns correct value",
+        0, input.available());
+    assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
+    assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
+  }
+
+  public void testNewInput_skip() throws IOException {
+    InputStream input = stringUnderTest.newInput();
+    int stringSize = stringUnderTest.size();
+    int nearEndIndex = stringSize * 2 / 3;
+    long skipped1 = input.skip(nearEndIndex);
+    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
+    assertEquals("InputStream.available()",
+        stringSize - skipped1, input.available());
+    assertTrue("InputStream.mark() is available", input.markSupported());
+    input.mark(0);
+    assertEquals("InputStream.skip(), read()",
+        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertEquals("InputStream.available()",
+                 stringSize - skipped1 - 1, input.available());
+    long skipped2 = input.skip(stringSize);
+    assertEquals("InputStream.skip() incomplete",
+        skipped2, stringSize - skipped1 - 1);
+    assertEquals("InputStream.skip(), no more input", 0, input.available());
+    assertEquals("InputStream.skip(), no more input", -1, input.read());
+    input.reset();
+    assertEquals("InputStream.reset() succeded",
+                 stringSize - skipped1, input.available());
+    assertEquals("InputStream.reset(), read()",
+        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
+  }
+
+  public void testNewCodedInput() throws IOException {
+    CodedInputStream cis = stringUnderTest.newCodedInput();
+    byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
+    assertTrue(classUnderTest + " must give the same bytes back from the CodedInputStream",
+        Arrays.equals(referenceBytes, roundTripBytes));
+    assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
+  }
+
+  /**
+   * Make sure we keep things simple when concatenating with empty. See also
+   * {@link ByteStringTest#testConcat_empty()}.
+   */
+  public void testConcat_empty() {
+    assertSame(classUnderTest + " concatenated with empty must give " + classUnderTest,
+        stringUnderTest.concat(ByteString.EMPTY), stringUnderTest);
+    assertSame("empty concatenated with " + classUnderTest + " must give " + classUnderTest,
+        ByteString.EMPTY.concat(stringUnderTest), stringUnderTest);
+  }
+
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(stringUnderTest);
+    oos.close();
+    byte[] pickled = out.toByteArray();
+    InputStream in = new ByteArrayInputStream(pickled);
+    ObjectInputStream ois = new ObjectInputStream(in);
+    Object o = ois.readObject();
+    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
new file mode 100644
index 0000000..0a8f9ed
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -0,0 +1,459 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link LongArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class LongArrayListTest extends TestCase {
+  
+  private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1);
+  private static final LongArrayList TERTIARY_LIST =
+      newImmutableLongArrayList(1, 2, 3);
+  
+  private LongArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new LongArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(LongArrayList.emptyList(), LongArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(LongArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addLong(2);
+    list.addLong(4);
+    list.addLong(6);
+    list.addLong(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1L, 2L, 3L, 4L));
+    Iterator<Long> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (long) list.get(0));
+    assertEquals(1, (long) iterator.next());
+    list.set(0, 1L);
+    assertEquals(2, (long) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0L);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1, (long) TERTIARY_LIST.get(0));
+    assertEquals(2, (long) TERTIARY_LIST.get(1));
+    assertEquals(3, (long) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetLong() {
+    assertEquals(1, TERTIARY_LIST.getLong(0));
+    assertEquals(2, TERTIARY_LIST.getLong(1));
+    assertEquals(3, TERTIARY_LIST.getLong(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, LongArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addLong(2);
+    list.addLong(4);
+    list.addLong(6);
+    list.addLong(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16L);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addLong(2);
+    list.addLong(4);
+    
+    assertEquals(2, (long) list.set(0, 0L));
+    assertEquals(0, list.getLong(0));
+
+    assertEquals(4, (long) list.set(1, 0L));
+    assertEquals(0, list.getLong(1));
+    
+    try {
+      list.set(-1, 0L);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0L);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetLong() {
+    list.addLong(2);
+    list.addLong(4);
+    
+    assertEquals(2, list.setLong(0, 0));
+    assertEquals(0, list.getLong(0));
+
+    assertEquals(4, list.setLong(1, 0));
+    assertEquals(0, list.getLong(1));
+    
+    try {
+      list.setLong(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setLong(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2L));
+    assertEquals(asList(2L), list);
+
+    assertTrue(list.add(3L));
+    list.add(0, 4L);
+    assertEquals(asList(4L, 2L, 3L), list);
+    
+    list.add(0, 1L);
+    list.add(0, 0L);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Long.valueOf(5 + i));
+    }
+    assertEquals(asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L), list);
+    
+    try {
+      list.add(-1, 5L);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5L);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddLong() {
+    assertEquals(0, list.size());
+
+    list.addLong(2);
+    assertEquals(asList(2L), list);
+
+    list.addLong(3);
+    assertEquals(asList(2L, 3L), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1L)));
+    assertEquals(1, list.size());
+    assertEquals(1, (long) list.get(0));
+    assertEquals(1, list.getLong(0));
+    
+    assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L)));
+    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list);
+
+    assertFalse(list.addAll(Collections.<Long>emptyList()));
+    assertFalse(list.addAll(LongArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1, (long) list.remove(0));
+    assertEquals(asList(2L, 3L), list);
+
+    assertTrue(list.remove(3L));
+    assertEquals(asList(2L), list);
+
+    assertFalse(list.remove(3L));
+    assertEquals(asList(2L), list);
+
+    assertEquals(2, (long) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(LongArrayList list) {
+    if (list.contains(1L)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new LongArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addLong(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setLong(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static LongArrayList newImmutableLongArrayList(long... elements) {
+    LongArrayList list = new LongArrayList();
+    for (long element : elements) {
+      list.addLong(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
new file mode 100644
index 0000000..d79d002
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -0,0 +1,458 @@
+// 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.
+
+package com.google.protobuf;
+
+import map_lite_test.MapForProto2TestProto.TestMap;
+import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
+import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for map fields.
+ */
+public class MapForProto2LiteTest extends TestCase {
+  private void setMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 11);
+    builder.getMutableInt32ToInt32Field().put(2, 22);
+    builder.getMutableInt32ToInt32Field().put(3, 33);
+
+    builder.getMutableInt32ToStringField().put(1, "11");
+    builder.getMutableInt32ToStringField().put(2, "22");
+    builder.getMutableInt32ToStringField().put(3, "33");
+    
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
+    builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
+    builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
+    
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
+    
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(11).build());
+    builder.getMutableInt32ToMessageField().put(
+        2, MessageValue.newBuilder().setValue(22).build());
+    builder.getMutableInt32ToMessageField().put(
+        3, MessageValue.newBuilder().setValue(33).build());
+    
+    builder.getMutableStringToInt32Field().put("1", 11);
+    builder.getMutableStringToInt32Field().put("2", 22);
+    builder.getMutableStringToInt32Field().put("3", 33);
+  }
+
+  private void copyMapValues(TestMap source, TestMap.Builder destination) {
+    destination
+        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
+        .putAllInt32ToStringField(source.getInt32ToStringField())
+        .putAllInt32ToBytesField(source.getInt32ToBytesField())
+        .putAllInt32ToEnumField(source.getInt32ToEnumField())
+        .putAllInt32ToMessageField(source.getInt32ToMessageField())
+        .putAllStringToInt32Field(source.getStringToInt32Field());
+  }
+
+  private void assertMapValuesSet(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("11", message.getInt32ToStringField().get(1));
+    assertEquals("22", message.getInt32ToStringField().get(2));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+    
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+  }
+
+  private void updateMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 111);
+    builder.getMutableInt32ToInt32Field().remove(2);
+    builder.getMutableInt32ToInt32Field().put(4, 44);
+
+    builder.getMutableInt32ToStringField().put(1, "111");
+    builder.getMutableInt32ToStringField().remove(2);
+    builder.getMutableInt32ToStringField().put(4, "44");
+    
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
+    builder.getMutableInt32ToBytesField().remove(2);
+    builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
+    
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().remove(2);
+    builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
+    
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(111).build());
+    builder.getMutableInt32ToMessageField().remove(2);
+    builder.getMutableInt32ToMessageField().put(
+        4, MessageValue.newBuilder().setValue(44).build());
+    
+    builder.getMutableStringToInt32Field().put("1", 111);
+    builder.getMutableStringToInt32Field().remove("2");
+    builder.getMutableStringToInt32Field().put("4", 44);
+  }
+
+  private void assertMapValuesUpdated(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("111", message.getInt32ToStringField().get(1));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals("44", message.getInt32ToStringField().get(4));
+    
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+    
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+    
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+    
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+  }
+
+  private void assertMapValuesCleared(TestMap message) {
+    assertEquals(0, message.getInt32ToInt32Field().size());
+    assertEquals(0, message.getInt32ToStringField().size());
+    assertEquals(0, message.getInt32ToBytesField().size());
+    assertEquals(0, message.getInt32ToEnumField().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+    assertEquals(0, message.getStringToInt32Field().size());
+  }
+
+  public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
+    // Since builders are implemented as a thin wrapper around a message
+    // instance, we attempt to verify that we can't cause the builder to modify
+    // a produced message.
+    
+    TestMap.Builder builder = TestMap.newBuilder();
+    TestMap message = builder.build();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertTrue(message.getInt32ToInt32Field().isEmpty());
+    message = builder.build();
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+  }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
+
+  public void testGettersAndSetters() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    TestMap message = builder.build();
+    assertMapValuesCleared(message);
+    
+    builder = message.toBuilder();
+    setMapValues(builder);
+    message = builder.build();
+    assertMapValuesSet(message);
+    
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertMapValuesUpdated(message);
+    
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertMapValuesCleared(message);
+  }
+
+  public void testPutAll() throws Exception {
+    TestMap.Builder sourceBuilder = TestMap.newBuilder();
+    setMapValues(sourceBuilder);
+    TestMap source = sourceBuilder.build();
+
+    TestMap.Builder destination = TestMap.newBuilder();
+    copyMapValues(source, destination);
+    assertMapValuesSet(destination.build());
+  }
+
+  public void testSerializeAndParse() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesSet(message);
+    
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesUpdated(message);
+    
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesCleared(message);
+  }
+  
+  public void testMergeFrom() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    
+    TestMap.Builder other = TestMap.newBuilder();
+    other.mergeFrom(message);
+    assertMapValuesSet(other.build());
+  }
+
+  public void testEqualsAndHashCode() throws Exception {
+    // Test that generated equals() and hashCode() will disregard the order
+    // of map entries when comparing/hashing map fields.
+    
+    // We can't control the order of elements in a HashMap. The best we can do
+    // here is to add elements in different order.
+    TestMap.Builder b1 = TestMap.newBuilder();
+    b1.getMutableInt32ToInt32Field().put(1, 2);
+    b1.getMutableInt32ToInt32Field().put(3, 4);
+    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap m1 = b1.build();
+    
+    TestMap.Builder b2 = TestMap.newBuilder();
+    b2.getMutableInt32ToInt32Field().put(5, 6);
+    b2.getMutableInt32ToInt32Field().put(1, 2);
+    b2.getMutableInt32ToInt32Field().put(3, 4);
+    TestMap m2 = b2.build();
+    
+    assertEquals(m1, m2);
+    assertEquals(m1.hashCode(), m2.hashCode());
+    
+    // Make sure we did compare map fields.
+    b2.getMutableInt32ToInt32Field().put(1, 0);
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
+    // to be different.
+  }
+
+  public void testUnknownEnumValues() throws Exception {
+    TestUnknownEnumValue.Builder builder =
+        TestUnknownEnumValue.newBuilder();
+    builder.getMutableInt32ToInt32Field().put(1, 1);
+    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    ByteString data = builder.build().toByteString();
+
+    TestMap message = TestMap.parseFrom(data);
+    // Entries with unknown enum values will be stored into UnknownFieldSet so
+    // there is only one entry in the map.
+    assertEquals(1, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    // Serializing and parsing should preserve the unknown entry.
+    data = message.toByteString();
+    TestUnknownEnumValue messageWithUnknownEnums =
+        TestUnknownEnumValue.parseFrom(data);
+    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
+    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
+  }
+
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
new file mode 100644
index 0000000..73154c0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -0,0 +1,683 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapForProto2TestProto.TestMap;
+import map_test.MapForProto2TestProto.TestMap.MessageValue;
+import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
+import map_test.MapForProto2TestProto.TestRecursiveMap;
+import map_test.MapForProto2TestProto.TestUnknownEnumValue;
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for map fields in proto2 protos.
+ */
+public class MapForProto2Test extends TestCase {
+  private void setMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 11);
+    builder.getMutableInt32ToInt32Field().put(2, 22);
+    builder.getMutableInt32ToInt32Field().put(3, 33);
+
+    builder.getMutableInt32ToStringField().put(1, "11");
+    builder.getMutableInt32ToStringField().put(2, "22");
+    builder.getMutableInt32ToStringField().put(3, "33");
+    
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
+    builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
+    builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
+    
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
+    
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(11).build());
+    builder.getMutableInt32ToMessageField().put(
+        2, MessageValue.newBuilder().setValue(22).build());
+    builder.getMutableInt32ToMessageField().put(
+        3, MessageValue.newBuilder().setValue(33).build());
+    
+    builder.getMutableStringToInt32Field().put("1", 11);
+    builder.getMutableStringToInt32Field().put("2", 22);
+    builder.getMutableStringToInt32Field().put("3", 33);
+  }
+
+  private void copyMapValues(TestMap source, TestMap.Builder destination) {
+    destination
+        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
+        .putAllInt32ToStringField(source.getInt32ToStringField())
+        .putAllInt32ToBytesField(source.getInt32ToBytesField())
+        .putAllInt32ToEnumField(source.getInt32ToEnumField())
+        .putAllInt32ToMessageField(source.getInt32ToMessageField())
+        .putAllStringToInt32Field(source.getStringToInt32Field());
+  }
+
+  private void assertMapValuesSet(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("11", message.getInt32ToStringField().get(1));
+    assertEquals("22", message.getInt32ToStringField().get(2));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+    
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+  }
+
+  private void updateMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 111);
+    builder.getMutableInt32ToInt32Field().remove(2);
+    builder.getMutableInt32ToInt32Field().put(4, 44);
+
+    builder.getMutableInt32ToStringField().put(1, "111");
+    builder.getMutableInt32ToStringField().remove(2);
+    builder.getMutableInt32ToStringField().put(4, "44");
+    
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
+    builder.getMutableInt32ToBytesField().remove(2);
+    builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
+    
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().remove(2);
+    builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
+    
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(111).build());
+    builder.getMutableInt32ToMessageField().remove(2);
+    builder.getMutableInt32ToMessageField().put(
+        4, MessageValue.newBuilder().setValue(44).build());
+    
+    builder.getMutableStringToInt32Field().put("1", 111);
+    builder.getMutableStringToInt32Field().remove("2");
+    builder.getMutableStringToInt32Field().put("4", 44);
+  }
+
+  private void assertMapValuesUpdated(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("111", message.getInt32ToStringField().get(1));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals("44", message.getInt32ToStringField().get(4));
+    
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+    
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+    
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+    
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+  }
+
+  private void assertMapValuesCleared(TestMap message) {
+    assertEquals(0, message.getInt32ToInt32Field().size());
+    assertEquals(0, message.getInt32ToStringField().size());
+    assertEquals(0, message.getInt32ToBytesField().size());
+    assertEquals(0, message.getInt32ToEnumField().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+    assertEquals(0, message.getStringToInt32Field().size());
+  }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
+
+  public void testGettersAndSetters() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    TestMap message = builder.build();
+    assertMapValuesCleared(message);
+    
+    builder = message.toBuilder();
+    setMapValues(builder);
+    message = builder.build();
+    assertMapValuesSet(message);
+    
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertMapValuesUpdated(message);
+    
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertMapValuesCleared(message);
+  }
+
+  public void testPutAll() throws Exception {
+    TestMap.Builder sourceBuilder = TestMap.newBuilder();
+    setMapValues(sourceBuilder);
+    TestMap source = sourceBuilder.build();
+
+    TestMap.Builder destination = TestMap.newBuilder();
+    copyMapValues(source, destination);
+    assertMapValuesSet(destination.build());
+  }
+
+  public void testSerializeAndParse() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesSet(message);
+    
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesUpdated(message);
+    
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesCleared(message);
+  }
+  
+  public void testMergeFrom() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    
+    TestMap.Builder other = TestMap.newBuilder();
+    other.mergeFrom(message);
+    assertMapValuesSet(other.build());
+  }
+
+  public void testEqualsAndHashCode() throws Exception {
+    // Test that generated equals() and hashCode() will disregard the order
+    // of map entries when comparing/hashing map fields.
+    
+    // We can't control the order of elements in a HashMap. The best we can do
+    // here is to add elements in different order.
+    TestMap.Builder b1 = TestMap.newBuilder();
+    b1.getMutableInt32ToInt32Field().put(1, 2);
+    b1.getMutableInt32ToInt32Field().put(3, 4);
+    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap m1 = b1.build();
+    
+    TestMap.Builder b2 = TestMap.newBuilder();
+    b2.getMutableInt32ToInt32Field().put(5, 6);
+    b2.getMutableInt32ToInt32Field().put(1, 2);
+    b2.getMutableInt32ToInt32Field().put(3, 4);
+    TestMap m2 = b2.build();
+    
+    assertEquals(m1, m2);
+    assertEquals(m1.hashCode(), m2.hashCode());
+    
+    // Make sure we did compare map fields.
+    b2.getMutableInt32ToInt32Field().put(1, 0);
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
+    // to be different.
+  }
+  
+  
+  // The following methods are used to test reflection API.
+  
+  private static FieldDescriptor f(String name) {
+    return TestMap.getDescriptor().findFieldByName(name);
+  }
+  
+  private static Object getFieldValue(Message mapEntry, String name) {
+    FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
+    return mapEntry.getField(field);
+  }
+  
+  private static Message.Builder setFieldValue(
+      Message.Builder mapEntry, String name, Object value) {
+    FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
+    mapEntry.setField(field, value);
+    return mapEntry;
+  }
+  
+  private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
+    FieldDescriptor field = f(name);
+    for (Object entry : (List<?>) message.getField(field)) {
+      Message mapEntry = (Message) entry;
+      Object key = getFieldValue(mapEntry, "key");
+      Object value = getFieldValue(mapEntry, "value");
+      assertTrue(values.containsKey(key));
+      assertEquals(value, values.get(key));
+    }
+    assertEquals(values.size(), message.getRepeatedFieldCount(field));
+    for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
+      Message mapEntry = (Message) message.getRepeatedField(field, i);
+      Object key = getFieldValue(mapEntry, "key");
+      Object value = getFieldValue(mapEntry, "value");
+      assertTrue(values.containsKey(key));
+      assertEquals(value, values.get(key));
+    }
+  }
+  
+  private static <KeyType, ValueType>
+  Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
+    FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
+    Message.Builder entryBuilder = builder.newBuilderForField(field);
+    FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
+    FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value");
+    entryBuilder.setField(keyField, key);
+    entryBuilder.setField(valueField, value);
+    return entryBuilder.build();
+  }
+  
+  private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
+    List<Message> entryList = new ArrayList<Message>();
+    for (Map.Entry<?, ?> entry : values.entrySet()) {
+      entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
+    }
+    FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
+    builder.setField(field, entryList);
+  }
+  
+  private static <KeyType, ValueType>
+  Map<KeyType, ValueType> mapForValues(
+      KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
+    Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
+
+  public void testReflectionApi() throws Exception {
+    // In reflection API, map fields are just repeated message fields.
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.getMutableInt32ToInt32Field().put(1, 2);
+    builder.getMutableInt32ToInt32Field().put(3, 4);
+    builder.getMutableInt32ToMessageField().put(
+        11, MessageValue.newBuilder().setValue(22).build());
+    builder.getMutableInt32ToMessageField().put(
+        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap message = builder.build();
+
+    // Test getField(), getRepeatedFieldCount(), getRepeatedField().
+    assertHasMapValues(message, "int32_to_int32_field",
+        mapForValues(1, 2, 3, 4));
+    assertHasMapValues(message, "int32_to_message_field",
+        mapForValues(
+            11, MessageValue.newBuilder().setValue(22).build(),
+            33, MessageValue.newBuilder().setValue(44).build()));
+    
+    // Test clearField()
+    builder.clearField(f("int32_to_int32_field"));
+    builder.clearField(f("int32_to_message_field"));
+    message = builder.build();
+    assertEquals(0, message.getInt32ToInt32Field().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+    
+    // Test setField()
+    setMapValues(builder, "int32_to_int32_field",
+        mapForValues(11, 22, 33, 44));
+    setMapValues(builder, "int32_to_message_field",
+        mapForValues(
+            111, MessageValue.newBuilder().setValue(222).build(),
+            333, MessageValue.newBuilder().setValue(444).build()));
+    message = builder.build();
+    assertEquals(22, message.getInt32ToInt32Field().get(11).intValue());
+    assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
+    assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
+    assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
+    
+    // Test addRepeatedField
+    builder.addRepeatedField(f("int32_to_int32_field"),
+        newMapEntry(builder, "int32_to_int32_field", 55, 66));
+    builder.addRepeatedField(f("int32_to_message_field"),
+        newMapEntry(builder, "int32_to_message_field", 555,
+            MessageValue.newBuilder().setValue(666).build()));
+    message = builder.build();
+    assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
+
+    // Test addRepeatedField (overriding existing values)
+    builder.addRepeatedField(f("int32_to_int32_field"),
+        newMapEntry(builder, "int32_to_int32_field", 55, 55));
+    builder.addRepeatedField(f("int32_to_message_field"),
+        newMapEntry(builder, "int32_to_message_field", 555,
+            MessageValue.newBuilder().setValue(555).build()));
+    message = builder.build();
+    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
+    
+    // Test setRepeatedField
+    for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
+      Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
+      int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue();
+      int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue();
+      // Swap key with value for each entry.
+      Message.Builder mapEntryBuilder = mapEntry.toBuilder();
+      setFieldValue(mapEntryBuilder, "key", oldValue);
+      setFieldValue(mapEntryBuilder, "value", oldKey);
+      builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
+    }
+    message = builder.build();
+    assertEquals(11, message.getInt32ToInt32Field().get(22).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
+    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+  }
+  
+  public void testTextFormat() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    
+    String textData = TextFormat.printToString(message);
+    
+    builder = TestMap.newBuilder();
+    TextFormat.merge(textData, builder);
+    message = builder.build();
+    
+    assertMapValuesSet(message);
+  }
+  
+  public void testDynamicMessage() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message dynamicMessage = dynamicDefaultInstance
+        .newBuilderForType().mergeFrom(message.toByteString()).build();
+    
+    assertEquals(message, dynamicMessage);
+    assertEquals(message.hashCode(), dynamicMessage.hashCode());
+  }
+  
+  public void testReflectionEqualsAndHashCode() throws Exception {
+    // Test that generated equals() and hashCode() will disregard the order
+    // of map entries when comparing/hashing map fields.
+
+    // We use DynamicMessage to test reflection based equals()/hashCode().
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    FieldDescriptor field = f("int32_to_int32_field");
+    
+    Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
+    Message m1 = b1.build();
+    
+    Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
+    Message m2 = b2.build();
+    
+    assertEquals(m1, m2);
+    assertEquals(m1.hashCode(), m2.hashCode());
+    
+    // Make sure we did compare map fields.
+    b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
+    // to be different.
+  }
+  
+  public void testUnknownEnumValues() throws Exception {
+    TestUnknownEnumValue.Builder builder =
+        TestUnknownEnumValue.newBuilder();
+    builder.getMutableInt32ToInt32Field().put(1, 1);
+    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    ByteString data = builder.build().toByteString();
+
+    TestMap message = TestMap.parseFrom(data);
+    // Entries with unknown enum values will be stored into UnknownFieldSet so
+    // there is only one entry in the map.
+    assertEquals(1, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    // UnknownFieldSet should not be empty.
+    assertFalse(message.getUnknownFields().asMap().isEmpty());
+    // Serializing and parsing should preserve the unknown entry.
+    data = message.toByteString();
+    TestUnknownEnumValue messageWithUnknownEnums =
+        TestUnknownEnumValue.parseFrom(data);
+    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
+    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
+  }
+
+
+  public void testRequiredMessage() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.getMutableRequiredMessageMap().put(0,
+        MessageWithRequiredFields.newBuilder().buildPartial());
+    TestMap message = builder.buildPartial();
+    assertFalse(message.isInitialized());
+
+    builder.getMutableRequiredMessageMap().put(0,
+        MessageWithRequiredFields.newBuilder().setValue(1).build());
+    message = builder.build();
+    assertTrue(message.isInitialized());
+  }
+
+  public void testRecursiveMap() throws Exception {
+    TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
+    builder.getMutableRecursiveMapField().put(
+        1, TestRecursiveMap.newBuilder().setValue(2).build());
+    builder.getMutableRecursiveMapField().put(
+        3, TestRecursiveMap.newBuilder().setValue(4).build());
+    ByteString data = builder.build().toByteString();
+
+    TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
+    assertEquals(2, message.getRecursiveMapField().get(1).getValue());
+    assertEquals(4, message.getRecursiveMapField().get(3).getValue());
+  }
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+
+  // Regression test for b/20494788
+  public void testMapInitializationOrder() throws Exception {
+    assertEquals("RedactAllTypes", map_test.RedactAllTypes
+        .getDefaultInstance().getDescriptorForType().getName());
+
+    map_test.Message1.Builder builder =
+        map_test.Message1.newBuilder();
+    builder.getMutableMapField().put("key", true);
+    map_test.Message1 message = builder.build();
+    Message mapEntry = (Message) message.getRepeatedField(
+        message.getDescriptorForType().findFieldByName("map_field"), 0);
+    assertEquals(2, mapEntry.getAllFields().size());
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
+}
+
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
new file mode 100644
index 0000000..1dc5787
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -0,0 +1,782 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapTestProto.TestMap;
+import map_test.MapTestProto.TestMap.MessageValue;
+import map_test.MapTestProto.TestOnChangeEventPropagation;
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for map fields.
+ */
+public class MapTest extends TestCase {
+  private void setMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 11);
+    builder.getMutableInt32ToInt32Field().put(2, 22);
+    builder.getMutableInt32ToInt32Field().put(3, 33);
+
+    builder.getMutableInt32ToStringField().put(1, "11");
+    builder.getMutableInt32ToStringField().put(2, "22");
+    builder.getMutableInt32ToStringField().put(3, "33");
+
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
+    builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
+    builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
+
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
+
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(11).build());
+    builder.getMutableInt32ToMessageField().put(
+        2, MessageValue.newBuilder().setValue(22).build());
+    builder.getMutableInt32ToMessageField().put(
+        3, MessageValue.newBuilder().setValue(33).build());
+
+    builder.getMutableStringToInt32Field().put("1", 11);
+    builder.getMutableStringToInt32Field().put("2", 22);
+    builder.getMutableStringToInt32Field().put("3", 33);
+  }
+
+  private void copyMapValues(TestMap source, TestMap.Builder destination) {
+    destination
+        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
+        .putAllInt32ToStringField(source.getInt32ToStringField())
+        .putAllInt32ToBytesField(source.getInt32ToBytesField())
+        .putAllInt32ToEnumField(source.getInt32ToEnumField())
+        .putAllInt32ToMessageField(source.getInt32ToMessageField())
+        .putAllStringToInt32Field(source.getStringToInt32Field());
+  }
+
+  private void assertMapValuesSet(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("11", message.getInt32ToStringField().get(1));
+    assertEquals("22", message.getInt32ToStringField().get(2));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+  }
+
+  private void updateMapValues(TestMap.Builder builder) {
+    builder.getMutableInt32ToInt32Field().put(1, 111);
+    builder.getMutableInt32ToInt32Field().remove(2);
+    builder.getMutableInt32ToInt32Field().put(4, 44);
+
+    builder.getMutableInt32ToStringField().put(1, "111");
+    builder.getMutableInt32ToStringField().remove(2);
+    builder.getMutableInt32ToStringField().put(4, "44");
+
+    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
+    builder.getMutableInt32ToBytesField().remove(2);
+    builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
+
+    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
+    builder.getMutableInt32ToEnumField().remove(2);
+    builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
+
+    builder.getMutableInt32ToMessageField().put(
+        1, MessageValue.newBuilder().setValue(111).build());
+    builder.getMutableInt32ToMessageField().remove(2);
+    builder.getMutableInt32ToMessageField().put(
+        4, MessageValue.newBuilder().setValue(44).build());
+
+    builder.getMutableStringToInt32Field().put("1", 111);
+    builder.getMutableStringToInt32Field().remove("2");
+    builder.getMutableStringToInt32Field().put("4", 44);
+  }
+
+  private void assertMapValuesUpdated(TestMap message) {
+    assertEquals(3, message.getInt32ToInt32Field().size());
+    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+
+    assertEquals(3, message.getInt32ToStringField().size());
+    assertEquals("111", message.getInt32ToStringField().get(1));
+    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals("44", message.getInt32ToStringField().get(4));
+
+    assertEquals(3, message.getInt32ToBytesField().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+
+    assertEquals(3, message.getInt32ToEnumField().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+
+    assertEquals(3, message.getInt32ToMessageField().size());
+    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+
+    assertEquals(3, message.getStringToInt32Field().size());
+    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
+    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+  }
+
+  private void assertMapValuesCleared(TestMap message) {
+    assertEquals(0, message.getInt32ToInt32Field().size());
+    assertEquals(0, message.getInt32ToStringField().size());
+    assertEquals(0, message.getInt32ToBytesField().size());
+    assertEquals(0, message.getInt32ToEnumField().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+    assertEquals(0, message.getStringToInt32Field().size());
+  }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
+  
+  public void testGettersAndSetters() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    TestMap message = builder.build();
+    assertMapValuesCleared(message);
+
+    builder = message.toBuilder();
+    setMapValues(builder);
+    message = builder.build();
+    assertMapValuesSet(message);
+
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertMapValuesUpdated(message);
+
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertMapValuesCleared(message);
+  }
+
+  public void testPutAll() throws Exception {
+    TestMap.Builder sourceBuilder = TestMap.newBuilder();
+    setMapValues(sourceBuilder);
+    TestMap source = sourceBuilder.build();
+
+    TestMap.Builder destination = TestMap.newBuilder();
+    copyMapValues(source, destination);
+    assertMapValuesSet(destination.build());
+  }
+
+  public void testPutAllForUnknownEnumValues() throws Exception {
+    TestMap.Builder sourceBuilder = TestMap.newBuilder();
+    sourceBuilder.getMutableInt32ToEnumFieldValue().put(0, 0);
+    sourceBuilder.getMutableInt32ToEnumFieldValue().put(1, 1);
+    sourceBuilder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
+    TestMap source = sourceBuilder.build();
+
+    TestMap.Builder destinationBuilder = TestMap.newBuilder();
+    destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue());
+    TestMap destination = destinationBuilder.build();
+
+    assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
+    assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
+    assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue());
+  }
+
+  public void testSerializeAndParse() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesSet(message);
+
+    builder = message.toBuilder();
+    updateMapValues(builder);
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesUpdated(message);
+
+    builder = message.toBuilder();
+    builder.clear();
+    message = builder.build();
+    assertEquals(message.getSerializedSize(), message.toByteString().size());
+    message = TestMap.parser().parseFrom(message.toByteString());
+    assertMapValuesCleared(message);
+  }
+
+  public void testMergeFrom() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    TestMap.Builder other = TestMap.newBuilder();
+    other.mergeFrom(message);
+    assertMapValuesSet(other.build());
+  }
+
+  public void testEqualsAndHashCode() throws Exception {
+    // Test that generated equals() and hashCode() will disregard the order
+    // of map entries when comparing/hashing map fields.
+
+    // We can't control the order of elements in a HashMap. The best we can do
+    // here is to add elements in different order.
+    TestMap.Builder b1 = TestMap.newBuilder();
+    b1.getMutableInt32ToInt32Field().put(1, 2);
+    b1.getMutableInt32ToInt32Field().put(3, 4);
+    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap m1 = b1.build();
+
+    TestMap.Builder b2 = TestMap.newBuilder();
+    b2.getMutableInt32ToInt32Field().put(5, 6);
+    b2.getMutableInt32ToInt32Field().put(1, 2);
+    b2.getMutableInt32ToInt32Field().put(3, 4);
+    TestMap m2 = b2.build();
+
+    assertEquals(m1, m2);
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    // Make sure we did compare map fields.
+    b2.getMutableInt32ToInt32Field().put(1, 0);
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
+    // to be different.
+
+    // Regression test for b/18549190: if a map is a subset of the other map,
+    // equals() should return false.
+    b2.getMutableInt32ToInt32Field().remove(1);
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    assertFalse(m2.equals(m1));
+  }
+
+  public void testNestedBuilderOnChangeEventPropagation() {
+    TestOnChangeEventPropagation.Builder parent =
+        TestOnChangeEventPropagation.newBuilder();
+    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 2);
+    TestOnChangeEventPropagation message = parent.build();
+    assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+
+    // Make a change using nested builder.
+    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 3);
+
+    // Should be able to observe the change.
+    message = parent.build();
+    assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+
+    // Make another change using mergeFrom()
+    TestMap.Builder other = TestMap.newBuilder();
+    other.getMutableInt32ToInt32Field().put(1, 4);
+    parent.getOptionalMessageBuilder().mergeFrom(other.build());
+
+    // Should be able to observe the change.
+    message = parent.build();
+    assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+
+    // Make yet another change by clearing the nested builder.
+    parent.getOptionalMessageBuilder().clear();
+
+    // Should be able to observe the change.
+    message = parent.build();
+    assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size());
+  }
+
+  public void testNestedBuilderOnChangeEventPropagationReflection() {
+    FieldDescriptor intMapField = f("int32_to_int32_field");
+    // Create an outer message builder with nested builder.
+    TestOnChangeEventPropagation.Builder parentBuilder =
+        TestOnChangeEventPropagation.newBuilder();
+    TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+
+    // Create a map entry message.
+    TestMap.Builder entryBuilder = TestMap.newBuilder();
+    entryBuilder.getMutableInt32ToInt32Field().put(1, 1);
+
+    // Put the entry into the nested builder.
+    testMapBuilder.addRepeatedField(
+        intMapField, entryBuilder.getRepeatedField(intMapField, 0));
+
+    // Should be able to observe the change.
+    TestOnChangeEventPropagation message = parentBuilder.build();
+    assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size());
+
+    // Change the entry value.
+    entryBuilder.getMutableInt32ToInt32Field().put(1, 4);
+    testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+    testMapBuilder.setRepeatedField(
+        intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0));
+
+    // Should be able to observe the change.
+    message = parentBuilder.build();
+    assertEquals(4,
+        message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+
+    // Clear the nested builder.
+    testMapBuilder = parentBuilder.getOptionalMessageBuilder();
+    testMapBuilder.clearField(intMapField);
+
+    // Should be able to observe the change.
+    message = parentBuilder.build();
+    assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size());
+  }
+
+  // The following methods are used to test reflection API.
+
+  private static FieldDescriptor f(String name) {
+    return TestMap.getDescriptor().findFieldByName(name);
+  }
+
+  private static Object getFieldValue(Message mapEntry, String name) {
+    FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
+    return mapEntry.getField(field);
+  }
+
+  private static Message.Builder setFieldValue(
+      Message.Builder mapEntry, String name, Object value) {
+    FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
+    mapEntry.setField(field, value);
+    return mapEntry;
+  }
+
+  private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
+    FieldDescriptor field = f(name);
+    for (Object entry : (List<?>) message.getField(field)) {
+      Message mapEntry = (Message) entry;
+      Object key = getFieldValue(mapEntry, "key");
+      Object value = getFieldValue(mapEntry, "value");
+      assertTrue(values.containsKey(key));
+      assertEquals(value, values.get(key));
+    }
+    assertEquals(values.size(), message.getRepeatedFieldCount(field));
+    for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
+      Message mapEntry = (Message) message.getRepeatedField(field, i);
+      Object key = getFieldValue(mapEntry, "key");
+      Object value = getFieldValue(mapEntry, "value");
+      assertTrue(values.containsKey(key));
+      assertEquals(value, values.get(key));
+    }
+  }
+
+  private static <KeyType, ValueType>
+  Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
+    FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
+    Message.Builder entryBuilder = builder.newBuilderForField(field);
+    FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
+    FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value");
+    entryBuilder.setField(keyField, key);
+    entryBuilder.setField(valueField, value);
+    return entryBuilder.build();
+  }
+
+  private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
+    List<Message> entryList = new ArrayList<Message>();
+    for (Map.Entry<?, ?> entry : values.entrySet()) {
+      entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
+    }
+    FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
+    builder.setField(field, entryList);
+  }
+
+  private static <KeyType, ValueType>
+  Map<KeyType, ValueType> mapForValues(
+      KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
+    Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
+
+  public void testReflectionApi() throws Exception {
+    // In reflection API, map fields are just repeated message fields.
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.getMutableInt32ToInt32Field().put(1, 2);
+    builder.getMutableInt32ToInt32Field().put(3, 4);
+    builder.getMutableInt32ToMessageField().put(
+        11, MessageValue.newBuilder().setValue(22).build());
+    builder.getMutableInt32ToMessageField().put(
+        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap message = builder.build();
+
+    // Test getField(), getRepeatedFieldCount(), getRepeatedField().
+    assertHasMapValues(message, "int32_to_int32_field",
+        mapForValues(1, 2, 3, 4));
+    assertHasMapValues(message, "int32_to_message_field",
+        mapForValues(
+            11, MessageValue.newBuilder().setValue(22).build(),
+            33, MessageValue.newBuilder().setValue(44).build()));
+
+    // Test clearField()
+    builder.clearField(f("int32_to_int32_field"));
+    builder.clearField(f("int32_to_message_field"));
+    message = builder.build();
+    assertEquals(0, message.getInt32ToInt32Field().size());
+    assertEquals(0, message.getInt32ToMessageField().size());
+
+    // Test setField()
+    setMapValues(builder, "int32_to_int32_field",
+        mapForValues(11, 22, 33, 44));
+    setMapValues(builder, "int32_to_message_field",
+        mapForValues(
+            111, MessageValue.newBuilder().setValue(222).build(),
+            333, MessageValue.newBuilder().setValue(444).build()));
+    message = builder.build();
+    assertEquals(22, message.getInt32ToInt32Field().get(11).intValue());
+    assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
+    assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
+    assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
+
+    // Test addRepeatedField
+    builder.addRepeatedField(f("int32_to_int32_field"),
+        newMapEntry(builder, "int32_to_int32_field", 55, 66));
+    builder.addRepeatedField(f("int32_to_message_field"),
+        newMapEntry(builder, "int32_to_message_field", 555,
+            MessageValue.newBuilder().setValue(666).build()));
+    message = builder.build();
+    assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
+
+    // Test addRepeatedField (overriding existing values)
+    builder.addRepeatedField(f("int32_to_int32_field"),
+        newMapEntry(builder, "int32_to_int32_field", 55, 55));
+    builder.addRepeatedField(f("int32_to_message_field"),
+        newMapEntry(builder, "int32_to_message_field", 555,
+            MessageValue.newBuilder().setValue(555).build()));
+    message = builder.build();
+    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
+
+    // Test setRepeatedField
+    for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
+      Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
+      int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue();
+      int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue();
+      // Swap key with value for each entry.
+      Message.Builder mapEntryBuilder = mapEntry.toBuilder();
+      setFieldValue(mapEntryBuilder, "key", oldValue);
+      setFieldValue(mapEntryBuilder, "value", oldKey);
+      builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
+    }
+    message = builder.build();
+    assertEquals(11, message.getInt32ToInt32Field().get(22).intValue());
+    assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
+    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+  }
+
+  public void testTextFormat() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    String textData = TextFormat.printToString(message);
+
+    builder = TestMap.newBuilder();
+    TextFormat.merge(textData, builder);
+    message = builder.build();
+
+    assertMapValuesSet(message);
+  }
+
+  public void testDynamicMessage() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message dynamicMessage = dynamicDefaultInstance
+        .newBuilderForType().mergeFrom(message.toByteString()).build();
+
+    assertEquals(message, dynamicMessage);
+    assertEquals(message.hashCode(), dynamicMessage.hashCode());
+  }
+
+  public void testReflectionEqualsAndHashCode() throws Exception {
+    // Test that generated equals() and hashCode() will disregard the order
+    // of map entries when comparing/hashing map fields.
+
+    // We use DynamicMessage to test reflection based equals()/hashCode().
+    Message dynamicDefaultInstance =
+        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    FieldDescriptor field = f("int32_to_int32_field");
+
+    Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
+    b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
+    Message m1 = b1.build();
+
+    Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
+    b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
+    Message m2 = b2.build();
+
+    assertEquals(m1, m2);
+    assertEquals(m1.hashCode(), m2.hashCode());
+
+    // Make sure we did compare map fields.
+    b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
+    m2 = b2.build();
+    assertFalse(m1.equals(m2));
+    // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
+    // to be different.
+  }
+
+  public void testUnknownEnumValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.getMutableInt32ToEnumFieldValue().put(0, 0);
+    builder.getMutableInt32ToEnumFieldValue().put(1, 1);
+    builder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
+    TestMap message = builder.build();
+
+    assertEquals(TestMap.EnumValue.FOO,
+        message.getInt32ToEnumField().get(0));
+    assertEquals(TestMap.EnumValue.BAR,
+        message.getInt32ToEnumField().get(1));
+    assertEquals(TestMap.EnumValue.UNRECOGNIZED,
+        message.getInt32ToEnumField().get(2));
+    assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue());
+
+    // Unknown enum values should be preserved after:
+    //   1. Serialization and parsing.
+    //   2. toBuild().
+    //   3. mergeFrom().
+    message = TestMap.parseFrom(message.toByteString());
+    assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue());
+    builder = message.toBuilder();
+    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+    builder = TestMap.newBuilder().mergeFrom(message);
+    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+
+    // hashCode()/equals() should take unknown enum values into account.
+    builder.getMutableInt32ToEnumFieldValue().put(2, 1001);
+    TestMap message2 = builder.build();
+    assertFalse(message.hashCode() == message2.hashCode());
+    assertFalse(message.equals(message2));
+    // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
+    // should be the same.
+    assertTrue(message.getInt32ToEnumField().equals(message2.getInt32ToEnumField()));
+  }
+
+  public void testUnknownEnumValuesInReflectionApi() throws Exception {
+    Descriptor descriptor = TestMap.getDescriptor();
+    EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor();
+    FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field");
+
+    Map<Integer, Integer> data = new HashMap<Integer, Integer>();
+    data.put(0, 0);
+    data.put(1, 1);
+    data.put(2, 1000);  // unknown value.
+
+    TestMap.Builder builder = TestMap.newBuilder();
+    for (Map.Entry<Integer, Integer> entry : data.entrySet()) {
+      builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue());
+    }
+
+    // Try to read unknown enum values using reflection API.
+    for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) {
+      Message mapEntry = (Message) builder.getRepeatedField(field, i);
+      int key = ((Integer) getFieldValue(mapEntry, "key")).intValue();
+      int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber();
+      assertEquals(data.get(key).intValue(), value);
+      Message.Builder mapEntryBuilder = mapEntry.toBuilder();
+      // Increase the value by 1.
+      setFieldValue(mapEntryBuilder, "value",
+          enumDescriptor.findValueByNumberCreatingIfUnknown(value + 1));
+      builder.setRepeatedField(field, i, mapEntryBuilder.build());
+    }
+
+    // Verify that enum values have been successfully updated.
+    TestMap message = builder.build();
+    for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValue().entrySet()) {
+      assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue());
+    }
+  }
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java
new file mode 100644
index 0000000..dcd1aba
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java
@@ -0,0 +1,353 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Misc. unit tests for message operations that apply to both generated
+ * and dynamic messages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class MessageTest extends TestCase {
+  // =================================================================
+  // Message-merging tests.
+
+  static final TestAllTypes MERGE_SOURCE =
+    TestAllTypes.newBuilder()
+      .setOptionalInt32(1)
+      .setOptionalString("foo")
+      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+      .addRepeatedString("bar")
+      .build();
+
+  static final TestAllTypes MERGE_DEST =
+    TestAllTypes.newBuilder()
+      .setOptionalInt64(2)
+      .setOptionalString("baz")
+      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+      .addRepeatedString("qux")
+      .build();
+
+  static final String MERGE_RESULT_TEXT =
+      "optional_int32: 1\n" +
+      "optional_int64: 2\n" +
+      "optional_string: \"foo\"\n" +
+      "optional_foreign_message {\n" +
+      "  c: 3\n" +
+      "}\n" +
+      "repeated_string: \"qux\"\n" +
+      "repeated_string: \"bar\"\n";
+
+  public void testMergeFrom() throws Exception {
+    TestAllTypes result =
+      TestAllTypes.newBuilder(MERGE_DEST)
+        .mergeFrom(MERGE_SOURCE).build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  /**
+   * Test merging a DynamicMessage into a GeneratedMessage.  As long as they
+   * have the same descriptor, this should work, but it is an entirely different
+   * code path.
+   */
+  public void testMergeFromDynamic() throws Exception {
+    TestAllTypes result =
+      TestAllTypes.newBuilder(MERGE_DEST)
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  /** Test merging two DynamicMessages. */
+  public void testDynamicMergeFrom() throws Exception {
+    DynamicMessage result =
+      DynamicMessage.newBuilder(MERGE_DEST)
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertEquals(MERGE_RESULT_TEXT, result.toString());
+  }
+
+  // =================================================================
+  // Required-field-related tests.
+
+  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+    TestRequired.getDefaultInstance();
+  private static final TestRequired TEST_REQUIRED_INITIALIZED =
+    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+  public void testRequired() throws Exception {
+    TestRequired.Builder builder = TestRequired.newBuilder();
+
+    assertFalse(builder.isInitialized());
+    builder.setA(1);
+    assertFalse(builder.isInitialized());
+    builder.setB(1);
+    assertFalse(builder.isInitialized());
+    builder.setC(1);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredForeign() throws Exception {
+    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+
+    assertTrue(builder.isInitialized());
+
+    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredExtension() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+
+    assertTrue(builder.isInitialized());
+
+    builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredDynamic() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("a"), 1);
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("b"), 1);
+    assertFalse(builder.isInitialized());
+    builder.setField(descriptor.findFieldByName("c"), 1);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testRequiredDynamicForeign() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
+    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+    assertTrue(builder.isInitialized());
+
+    builder.setField(descriptor.findFieldByName("optional_message"),
+                     TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setField(descriptor.findFieldByName("optional_message"),
+                     TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+
+    builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
+                             TEST_REQUIRED_UNINITIALIZED);
+    assertFalse(builder.isInitialized());
+
+    builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
+                             TEST_REQUIRED_INITIALIZED);
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testUninitializedException() throws Exception {
+    try {
+      TestRequired.newBuilder().build();
+      fail("Should have thrown an exception.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testBuildPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    TestRequired message = TestRequired.newBuilder().buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testNestedUninitializedException() throws Exception {
+    try {
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .build();
+      fail("Should have thrown an exception.");
+    } catch (UninitializedMessageException e) {
+      assertEquals(
+        "Message missing required fields: " +
+        "optional_message.a, " +
+        "optional_message.b, " +
+        "optional_message.c, " +
+        "repeated_message[0].a, " +
+        "repeated_message[0].b, " +
+        "repeated_message[0].c, " +
+        "repeated_message[1].a, " +
+        "repeated_message[1].b, " +
+        "repeated_message[1].c",
+        e.getMessage());
+    }
+  }
+
+  public void testBuildNestedPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    TestRequiredForeign message =
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testParseUnititialized() throws Exception {
+    try {
+      TestRequired.parseFrom(ByteString.EMPTY);
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testParseNestedUnititialized() throws Exception {
+    ByteString data =
+      TestRequiredForeign.newBuilder()
+        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+        .buildPartial().toByteString();
+
+    try {
+      TestRequiredForeign.parseFrom(data);
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals(
+        "Message missing required fields: " +
+        "optional_message.a, " +
+        "optional_message.b, " +
+        "optional_message.c, " +
+        "repeated_message[0].a, " +
+        "repeated_message[0].b, " +
+        "repeated_message[0].c, " +
+        "repeated_message[1].a, " +
+        "repeated_message[1].b, " +
+        "repeated_message[1].c",
+        e.getMessage());
+    }
+  }
+
+  public void testDynamicUninitializedException() throws Exception {
+    try {
+      DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
+      fail("Should have thrown an exception.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+
+  public void testDynamicBuildPartial() throws Exception {
+    // We're mostly testing that no exception is thrown.
+    DynamicMessage message =
+      DynamicMessage.newBuilder(TestRequired.getDescriptor())
+        .buildPartial();
+    assertFalse(message.isInitialized());
+  }
+
+  public void testDynamicParseUnititialized() throws Exception {
+    try {
+      Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+      DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
+      fail("Should have thrown an exception.");
+    } catch (InvalidProtocolBufferException e) {
+      assertEquals("Message missing required fields: a, b, c", e.getMessage());
+    }
+  }
+  
+  /** Test reading unset repeated message from DynamicMessage. */
+  public void testDynamicRepeatedMessageNull() throws Exception {
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage result =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+        .build();
+
+    assertTrue(result.getField(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")), 0);
+  }
+  
+  /** Test reading repeated message from DynamicMessage. */
+  public void testDynamicRepeatedMessageNotNull() throws Exception {
+
+    TestAllTypes REPEATED_NESTED =
+      TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("foo")
+        .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+        .addRepeatedString("bar")
+        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
+        .build();
+    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+    DynamicMessage result =
+      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
+        .mergeFrom(DynamicMessage.newBuilder(REPEATED_NESTED).build())
+        .build();
+
+    assertTrue(result.getField(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
+    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
+        .findFieldByName("repeated_foreign_message")), 2);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
new file mode 100644
index 0000000..542e28c
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
@@ -0,0 +1,185 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.Vehicle;
+import protobuf_unittest.Wheel;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test cases that exercise end-to-end use cases involving
+ * {@link SingleFieldBuilder} and {@link RepeatedFieldBuilder}.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class NestedBuildersTest extends TestCase {
+
+  public void testMessagesAndBuilders() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(1);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(2);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(3);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(4)
+        .setWidth(4);
+    vehicleBuilder.getEngineBuilder()
+        .setLiters(10);
+
+    Vehicle vehicle = vehicleBuilder.build();
+    assertEquals(4, vehicle.getWheelCount());
+    for (int i = 0; i < 4; i++) {
+      Wheel wheel = vehicle.getWheel(i);
+      assertEquals(4, wheel.getRadius());
+      assertEquals(i + 1, wheel.getWidth());
+    }
+    assertEquals(10, vehicle.getEngine().getLiters());
+
+    for (int i = 0; i < 4; i++) {
+      vehicleBuilder.getWheelBuilder(i)
+          .setRadius(5)
+          .setWidth(i + 10);
+    }
+    vehicleBuilder.getEngineBuilder().setLiters(20);
+
+    vehicle = vehicleBuilder.build();
+    for (int i = 0; i < 4; i++) {
+      Wheel wheel = vehicle.getWheel(i);
+      assertEquals(5, wheel.getRadius());
+      assertEquals(i + 10, wheel.getWidth());
+    }
+    assertEquals(20, vehicle.getEngine().getLiters());
+    assertTrue(vehicle.hasEngine());
+  }
+
+  public void testMessagesAreCached() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(1)
+        .setWidth(2);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(3)
+        .setWidth(4);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(5)
+        .setWidth(6);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(7)
+        .setWidth(8);
+
+    // Make sure messages are cached.
+    List<Wheel> wheels = new ArrayList<Wheel>(vehicleBuilder.getWheelList());
+    for (int i = 0; i < wheels.size(); i++) {
+      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+    }
+
+    // Now get builders and check they didn't change.
+    for (int i = 0; i < wheels.size(); i++) {
+      vehicleBuilder.getWheel(i);
+    }
+    for (int i = 0; i < wheels.size(); i++) {
+      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+    }
+
+    // Change just one
+    vehicleBuilder.getWheelBuilder(3)
+        .setRadius(20).setWidth(20);
+
+    // Now get wheels and check that only that one changed
+    for (int i = 0; i < wheels.size(); i++) {
+      if (i < 3) {
+        assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
+      } else {
+        assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i));
+      }
+    }
+  }
+
+  public void testRemove_WithNestedBuilders() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(1)
+        .setWidth(1);
+    vehicleBuilder.addWheelBuilder()
+        .setRadius(2)
+        .setWidth(2);
+    vehicleBuilder.removeWheel(0);
+
+    assertEquals(1, vehicleBuilder.getWheelCount());
+    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
+  }
+
+  public void testRemove_WithNestedMessages() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.addWheel(Wheel.newBuilder()
+        .setRadius(1)
+        .setWidth(1));
+    vehicleBuilder.addWheel(Wheel.newBuilder()
+        .setRadius(2)
+        .setWidth(2));
+    vehicleBuilder.removeWheel(0);
+
+    assertEquals(1, vehicleBuilder.getWheelCount());
+    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
+  }
+
+  public void testMerge() {
+    Vehicle vehicle1 = Vehicle.newBuilder()
+        .addWheel(Wheel.newBuilder().setRadius(1).build())
+        .addWheel(Wheel.newBuilder().setRadius(2).build())
+        .build();
+
+    Vehicle vehicle2 = Vehicle.newBuilder()
+        .mergeFrom(vehicle1)
+        .build();
+    // List should be the same -- no allocation
+    assertSame(vehicle1.getWheelList(), vehicle2.getWheelList());
+
+    Vehicle vehicle3 = vehicle1.toBuilder().build();
+    assertSame(vehicle1.getWheelList(), vehicle3.getWheelList());
+  }
+
+  public void testGettingBuilderMarksFieldAsHaving() {
+    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
+    vehicleBuilder.getEngineBuilder();
+    Vehicle vehicle = vehicleBuilder.buildPartial();
+    assertTrue(vehicle.hasEngine());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
new file mode 100644
index 0000000..6be5b93
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -0,0 +1,620 @@
+// 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.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.Internal.UTF_8;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for {@link NioByteString}.
+ */
+public class NioByteStringTest extends TestCase {
+  private static final ByteString EMPTY = new NioByteString(ByteBuffer.wrap(new byte[0]));
+  private static final String CLASSNAME = NioByteString.class.getSimpleName();
+  private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L);
+  private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode();
+
+  private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone());
+  private final ByteString testString = new NioByteString(backingBuffer);
+
+  public void testExpectedType() {
+    String actualClassName = getActualClassName(testString);
+    assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName);
+  }
+
+  protected String getActualClassName(Object object) {
+    String actualClassName = object.getClass().getName();
+    actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
+    return actualClassName;
+  }
+
+  public void testByteAt() {
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < BYTES.length; ++i) {
+      stillEqual = (BYTES[i] == testString.byteAt(i));
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+  }
+
+  public void testByteIterator() {
+    boolean stillEqual = true;
+    ByteString.ByteIterator iter = testString.iterator();
+    for (int i = 0; stillEqual && i < BYTES.length; ++i) {
+      stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte());
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+    assertFalse(CLASSNAME + " must have exhausted the itertor", iter.hasNext());
+
+    try {
+      iter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+  }
+
+  public void testByteIterable() {
+    boolean stillEqual = true;
+    int j = 0;
+    for (byte quantum : testString) {
+      stillEqual = (BYTES[j] == quantum);
+      ++j;
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes as Bytes", stillEqual);
+    assertEquals(CLASSNAME + " iterable character count", BYTES.length, j);
+  }
+
+  public void testSize() {
+    assertEquals(CLASSNAME + " must have the expected size", BYTES.length,
+        testString.size());
+  }
+
+  public void testGetTreeDepth() {
+    assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth());
+  }
+
+  public void testIsBalanced() {
+    assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced());
+  }
+
+  public void testCopyTo_ByteArrayOffsetLength() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+    int sourceOffset = 213;
+    testString.copyTo(destination, sourceOffset, destinationOffset, length);
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < length; ++i) {
+      stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset];
+    }
+    assertTrue(CLASSNAME + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+  }
+
+  public void testCopyTo_ByteArrayOffsetLengthErrors() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+
+    try {
+      // Copy one too many bytes
+      testString.copyTo(destination, testString.size() + 1 - length,
+          destinationOffset, length);
+      fail("Should have thrown an exception when copying too many bytes of a "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative sourceOffset
+      testString.copyTo(destination, -1, destinationOffset, length);
+      fail("Should have thrown an exception when given a negative sourceOffset in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative destinationOffset
+      testString.copyTo(destination, 0, -1, length);
+      fail("Should have thrown an exception when given a negative destinationOffset in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative size
+      testString.copyTo(destination, 0, 0, -1);
+      fail("Should have thrown an exception when given a negative size in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large sourceOffset
+      testString.copyTo(destination, 2 * testString.size(), 0, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large destinationOffset
+      testString.copyTo(destination, 0, 2 * destination.length, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+  }
+
+  public void testCopyTo_ByteBuffer() {
+    // Same length.
+    ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length);
+    testString.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes",
+        backingBuffer, myBuffer);
+
+    // Target buffer bigger than required.
+    myBuffer = ByteBuffer.allocate(testString.size() + 1);
+    testString.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(backingBuffer, myBuffer);
+
+    // Target buffer has no space.
+    myBuffer = ByteBuffer.allocate(0);
+    try {
+      testString.copyTo(myBuffer);
+      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+    } catch (BufferOverflowException e) {
+      // Expected.
+    }
+
+    // Target buffer too small.
+    myBuffer = ByteBuffer.allocate(1);
+    try {
+      testString.copyTo(myBuffer);
+      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+    } catch (BufferOverflowException e) {
+      // Expected.
+    }
+  }
+
+  public void testMarkSupported() {
+    InputStream stream = testString.newInput();
+    assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
+  }
+
+  public void testMarkAndReset() throws IOException {
+    int fraction = testString.size() / 3;
+
+    InputStream stream = testString.newInput();
+    stream.mark(testString.size()); // First, mark() the end.
+
+    skipFully(stream, fraction); // Skip a large fraction, but not all.
+    assertEquals(
+        CLASSNAME + ": after skipping to the 'middle', half the bytes are available",
+        (testString.size() - fraction), stream.available());
+    stream.reset();
+    assertEquals(
+        CLASSNAME + ": after resetting, all bytes are available",
+        testString.size(), stream.available());
+
+    skipFully(stream, testString.size()); // Skip to the end.
+    assertEquals(
+        CLASSNAME + ": after skipping to the end, no more bytes are available",
+        0, stream.available());
+  }
+
+  /**
+   * Discards {@code n} bytes of data from the input stream. This method
+   * will block until the full amount has been skipped. Does not close the
+   * stream.
+   * <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency.
+   *
+   * @param in the input stream to read from
+   * @param n the number of bytes to skip
+   * @throws EOFException if this stream reaches the end before skipping all
+   *     the bytes
+   * @throws IOException if an I/O error occurs, or the stream does not
+   *     support skipping
+   */
+  static void skipFully(InputStream in, long n) throws IOException {
+    long toSkip = n;
+    while (n > 0) {
+      long amt = in.skip(n);
+      if (amt == 0) {
+        // Force a blocking read to avoid infinite loop
+        if (in.read() == -1) {
+          long skipped = toSkip - n;
+          throw new EOFException("reached end of stream after skipping "
+              + skipped + " bytes; " + toSkip + " bytes expected");
+        }
+        n--;
+      } else {
+        n -= amt;
+      }
+    }
+  }
+
+  public void testAsReadOnlyByteBuffer() {
+    ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer();
+    byte[] roundTripBytes = new byte[BYTES.length];
+    assertTrue(byteBuffer.remaining() == BYTES.length);
+    assertTrue(byteBuffer.isReadOnly());
+    byteBuffer.get(roundTripBytes);
+    assertTrue(CLASSNAME + ".asReadOnlyByteBuffer() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testAsReadOnlyByteBufferList() {
+    List<ByteBuffer> byteBuffers = testString.asReadOnlyByteBufferList();
+    int bytesSeen = 0;
+    byte[] roundTripBytes = new byte[BYTES.length];
+    for (ByteBuffer byteBuffer : byteBuffers) {
+      int thisLength = byteBuffer.remaining();
+      assertTrue(byteBuffer.isReadOnly());
+      assertTrue(bytesSeen + thisLength <= BYTES.length);
+      byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
+      bytesSeen += thisLength;
+    }
+    assertTrue(bytesSeen == BYTES.length);
+    assertTrue(CLASSNAME + ".asReadOnlyByteBufferTest() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testToByteArray() {
+    byte[] roundTripBytes = testString.toByteArray();
+    assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testWriteTo() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    testString.writeTo(bos);
+    byte[] roundTripBytes = bos.toByteArray();
+    assertTrue(CLASSNAME + ".writeTo() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    byte[] original = Arrays.copyOf(BYTES, BYTES.length);
+    testString.writeTo(os);
+    assertTrue(CLASSNAME + ".writeTo() must NOT grant access to underlying buffer",
+        Arrays.equals(original, BYTES));
+  }
+
+  public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException {
+    OutputStream os = new OutputStream() {
+      @Override
+      public void write(byte[] b, int off, int len) {
+        Arrays.fill(b, off, off + len, (byte) 0);
+      }
+
+      @Override
+      public void write(int b) {
+        throw new UnsupportedOperationException();
+      }
+    };
+
+    testString.writeToInternal(os, 0, testString.size());
+    byte[] allZeros = new byte[testString.size()];
+    assertTrue(CLASSNAME + ".writeToInternal() must grant access to underlying buffer",
+        Arrays.equals(allZeros, backingBuffer.array()));
+  }
+
+  public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException {
+    ByteOutput out = new ByteOutput() {
+      @Override
+      public void write(byte value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(byte[] value, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void write(ByteBuffer value) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public void writeLazy(ByteBuffer value) throws IOException {
+        Arrays.fill(value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(),
+            (byte) 0);
+      }
+    };
+
+    testString.writeTo(out);
+    byte[] allZeros = new byte[testString.size()];
+    assertTrue(CLASSNAME + ".writeTo() must grant access to underlying buffer",
+        Arrays.equals(allZeros, backingBuffer.array()));
+  }
+
+  public void testNewOutput() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    ByteString.Output output = ByteString.newOutput();
+    testString.writeTo(output);
+    assertEquals("Output Size returns correct result",
+        output.size(), testString.size());
+    output.writeTo(bos);
+    assertTrue("Output.writeTo() must give back the same bytes",
+        Arrays.equals(BYTES, bos.toByteArray()));
+
+    // write the output stream to itself! This should cause it to double
+    output.writeTo(output);
+    assertEquals("Writing an output stream to itself is successful",
+        testString.concat(testString), output.toByteString());
+
+    output.reset();
+    assertEquals("Output.reset() resets the output", 0, output.size());
+    assertEquals("Output.reset() resets the output",
+        EMPTY, output.toByteString());
+  }
+
+  public void testToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = forString(testString);
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+  }
+
+  public void testCharsetToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = forString(testString);
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+  }
+
+  public void testToString_returnsCanonicalEmptyString() {
+    assertSame(CLASSNAME + " must be the same string references",
+        EMPTY.toString(UTF_8),
+        new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8));
+  }
+
+  public void testToString_raisesException() {
+    try {
+      EMPTY.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      testString.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
+  public void testEquals() {
+    assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null));
+    assertEquals(CLASSNAME + " must equal self", testString, testString);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        testString.equals(EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        EMPTY, testString.substring(55, 55));
+    assertEquals(CLASSNAME + " must equal another string with the same value",
+        testString, new NioByteString(backingBuffer));
+
+    byte[] mungedBytes = mungedBytes();
+    assertFalse(CLASSNAME + " must not equal every string with the same length",
+        testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+  }
+
+  public void testEqualsLiteralByteString() {
+    ByteString literal = ByteString.copyFrom(BYTES);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal,
+        testString);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString,
+        literal);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        testString.equals(ByteString.EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY, testString.substring(55, 55));
+
+    literal = ByteString.copyFrom(mungedBytes());
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        testString.equals(literal));
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        literal.equals(testString));
+  }
+
+  public void testEqualsRopeByteString() {
+    ByteString p1 = ByteString.copyFrom(BYTES, 0, 5);
+    ByteString p2 = ByteString.copyFrom(BYTES, 5, BYTES.length - 5);
+    ByteString rope = p1.concat(p2);
+
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope,
+        testString);
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString,
+        rope);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY.concat(ByteString.EMPTY), testString.substring(55, 55));
+
+    byte[] mungedBytes = mungedBytes();
+    p1 = ByteString.copyFrom(mungedBytes, 0, 5);
+    p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5);
+    rope = p1.concat(p2);
+    assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
+        testString.equals(rope));
+    assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
+        rope.equals(testString));
+  }
+
+  private byte[] mungedBytes() {
+    byte[] mungedBytes = new byte[BYTES.length];
+    System.arraycopy(BYTES, 0, mungedBytes, 0, BYTES.length);
+    mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
+    return mungedBytes;
+  }
+
+  public void testHashCode() {
+    int hash = testString.hashCode();
+    assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
+  }
+
+  public void testPeekCachedHashCode() {
+    ByteString newString = new NioByteString(backingBuffer);
+    assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0,
+        newString.peekCachedHashCode());
+    newString.hashCode();
+    assertEquals(CLASSNAME + ".peekCachedHashCode should return zero at first",
+        EXPECTED_HASH, newString.peekCachedHashCode());
+  }
+
+  public void testPartialHash() {
+    // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
+    // This test would fail if the expected hash were 1.  It's not.
+    int hash = testString.partialHash(testString.size(), 0, testString.size());
+    assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode",
+        EXPECTED_HASH, hash);
+  }
+
+  public void testNewInput() throws IOException {
+    InputStream input = testString.newInput();
+    assertEquals("InputStream.available() returns correct value",
+        testString.size(), input.available());
+    boolean stillEqual = true;
+    for (byte referenceByte : BYTES) {
+      int expectedInt = (referenceByte & 0xFF);
+      stillEqual = (expectedInt == input.read());
+    }
+    assertEquals("InputStream.available() returns correct value",
+        0, input.available());
+    assertTrue(CLASSNAME + " must give the same bytes from the InputStream", stillEqual);
+    assertEquals(CLASSNAME + " InputStream must now be exhausted", -1, input.read());
+  }
+
+  public void testNewInput_skip() throws IOException {
+    InputStream input = testString.newInput();
+    int stringSize = testString.size();
+    int nearEndIndex = stringSize * 2 / 3;
+    long skipped1 = input.skip(nearEndIndex);
+    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
+    assertEquals("InputStream.available()",
+        stringSize - skipped1, input.available());
+    assertTrue("InputStream.mark() is available", input.markSupported());
+    input.mark(0);
+    assertEquals("InputStream.skip(), read()",
+        testString.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertEquals("InputStream.available()",
+        stringSize - skipped1 - 1, input.available());
+    long skipped2 = input.skip(stringSize);
+    assertEquals("InputStream.skip() incomplete",
+        skipped2, stringSize - skipped1 - 1);
+    assertEquals("InputStream.skip(), no more input", 0, input.available());
+    assertEquals("InputStream.skip(), no more input", -1, input.read());
+    input.reset();
+    assertEquals("InputStream.reset() succeded",
+        stringSize - skipped1, input.available());
+    assertEquals("InputStream.reset(), read()",
+        testString.byteAt(nearEndIndex) & 0xFF, input.read());
+  }
+
+  public void testNewCodedInput() throws IOException {
+    CodedInputStream cis = testString.newCodedInput();
+    byte[] roundTripBytes = cis.readRawBytes(BYTES.length);
+    assertTrue(CLASSNAME + " must give the same bytes back from the CodedInputStream",
+        Arrays.equals(BYTES, roundTripBytes));
+    assertTrue(CLASSNAME + " CodedInputStream must now be exhausted", cis.isAtEnd());
+  }
+
+  /**
+   * Make sure we keep things simple when concatenating with empty. See also
+   * {@link ByteStringTest#testConcat_empty()}.
+   */
+  public void testConcat_empty() {
+    assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME,
+        testString.concat(EMPTY), testString);
+    assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
+        EMPTY.concat(testString), testString);
+  }
+
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(testString);
+    oos.close();
+    byte[] pickled = out.toByteArray();
+    InputStream in = new ByteArrayInputStream(pickled);
+    ObjectInputStream ois = new ObjectInputStream(in);
+    Object o = ois.readObject();
+    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+    assertEquals("Should get an equal ByteString back", testString, o);
+  }
+
+  private static ByteString forString(String str) {
+    return new NioByteString(ByteBuffer.wrap(str.getBytes(UTF_8)));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
new file mode 100644
index 0000000..bf1f1d7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -0,0 +1,273 @@
+// 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.
+
+package com.google.protobuf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser}
+ * interface are specified to only throw {@link InvalidProtocolBufferException}. But we really want
+ * to distinguish between invalid protos vs. actual I/O errors (like failures reading from a
+ * socket, etc.). So, when we're not using the parser directly, an {@link IOException} should be
+ * thrown where appropriate, instead of always an {@link InvalidProtocolBufferException}.
+ *
+ * @author jh@squareup.com (Joshua Humphries)
+ */
+@RunWith(JUnit4.class)
+public class ParseExceptionsTest {
+
+  private interface ParseTester {
+    DescriptorProto parse(InputStream in) throws IOException;
+  }
+
+  private byte serializedProto[];
+
+  private void setup() {
+    serializedProto = DescriptorProto.getDescriptor().toProto().toByteArray();
+  }
+
+  private void setupDelimited() {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    try {
+      DescriptorProto.getDescriptor().toProto().writeDelimitedTo(bos);
+    } catch (IOException e) {
+      fail("Exception not expected: " + e);
+    }
+    serializedProto = bos.toByteArray();
+  }
+
+  @Test public void message_parseFrom_InputStream() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(in);
+          }
+        });
+  }
+
+  @Test public void message_parseFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
+          }
+        });
+  }
+
+  @Test public void message_parseFrom_CodedInputStream() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
+          }
+        });
+  }
+
+  @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseFrom(
+                CodedInputStream.newInstance(in), ExtensionRegistry.newInstance());
+          }
+        });
+  }
+
+  @Test public void message_parseDelimitedFrom_InputStream() {
+    setupDelimited();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseDelimitedFrom(in);
+          }
+        });
+  }
+
+  @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() {
+    setupDelimited();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStream() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder().mergeFrom(in).build();
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder()
+                .mergeFrom(in, ExtensionRegistry.newInstance())
+                .build();
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeFrom_CodedInputStream() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            return DescriptorProto.newBuilder()
+                .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance())
+                .build();
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeDelimitedFrom_InputStream() {
+    setupDelimited();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+            builder.mergeDelimitedFrom(in);
+            return builder.build();
+          }
+        });
+  }
+
+  @Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() {
+    setupDelimited();
+    verifyExceptions(
+        new ParseTester() {
+          @Override
+          public DescriptorProto parse(InputStream in) throws IOException {
+            DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+            builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
+            return builder.build();
+          }
+        });
+  }
+
+  private void verifyExceptions(ParseTester parseTester) {
+    // No exception
+    try {
+      assertEquals(DescriptorProto.getDescriptor().toProto(),
+          parseTester.parse(new ByteArrayInputStream(serializedProto)));
+    } catch (IOException e) {
+      fail("No exception expected: " + e);
+    }
+
+    // IOException
+    try {
+      // using a "broken" stream that will throw part-way through reading the message
+      parseTester.parse(broken(new ByteArrayInputStream(serializedProto)));
+      fail("IOException expected but not thrown");
+    } catch (IOException e) {
+      assertFalse(e instanceof InvalidProtocolBufferException);
+    }
+
+    // InvalidProtocolBufferException
+    try {
+      // make the serialized proto invalid
+      for (int i = 0; i < 50; i++) {
+        serializedProto[i] = -1;
+      }
+      parseTester.parse(new ByteArrayInputStream(serializedProto));
+      fail("InvalidProtocolBufferException expected but not thrown");
+    } catch (IOException e) {
+      assertTrue(e instanceof InvalidProtocolBufferException);
+    }
+  }
+
+  private InputStream broken(InputStream i) {
+    return new FilterInputStream(i) {
+      int count = 0;
+
+      @Override public int read() throws IOException {
+        if (count++ >= 50) {
+          throw new IOException("I'm broken!");
+        }
+        return super.read();
+      }
+
+      @Override public int read(byte b[], int off, int len) throws IOException {
+        if ((count += len) >= 50) {
+          throw new IOException("I'm broken!");
+        }
+        return super.read(b, off, len);
+      }
+    };
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
new file mode 100644
index 0000000..30842d2
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -0,0 +1,377 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.UnittestLite.TestParsingMergeLite;
+import protobuf_unittest.UnittestOptimizeFor;
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestParsingMerge;
+import protobuf_unittest.UnittestProto.TestRequired;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit test for {@link Parser}.
+ *
+ * @author liujisi@google.com (Pherl Liu)
+ */
+public class ParserTest extends TestCase {
+  public void testGeneratedMessageParserSingleton() throws Exception {
+    for (int i = 0; i < 10; i++) {
+      assertEquals(TestAllTypes.parser(), TestUtil.getAllSet().getParserForType());
+    }
+  }
+
+  private void assertRoundTripEquals(MessageLite message,
+                                     ExtensionRegistryLite registry)
+      throws Exception {
+    final byte[] data = message.toByteArray();
+    final int offset = 20;
+    final int length = data.length;
+    final int padding = 30;
+    Parser<? extends MessageLite> parser = message.getParserForType();
+    assertMessageEquals(message, parser.parseFrom(data, registry));
+    assertMessageEquals(message, parser.parseFrom(
+        generatePaddingArray(data, offset, padding),
+        offset, length, registry));
+    assertMessageEquals(message, parser.parseFrom(
+        message.toByteString(), registry));
+    assertMessageEquals(message, parser.parseFrom(
+        new ByteArrayInputStream(data), registry));
+    assertMessageEquals(message, parser.parseFrom(
+        CodedInputStream.newInstance(data), registry));
+  }
+
+  @SuppressWarnings("unchecked")
+  private void assertRoundTripEquals(MessageLite message) throws Exception {
+    final byte[] data = message.toByteArray();
+    final int offset = 20;
+    final int length = data.length;
+    final int padding = 30;
+
+    Parser<MessageLite> parser =
+        (Parser<MessageLite>) message.getParserForType();
+    assertMessageEquals(message, parser.parseFrom(data));
+    assertMessageEquals(message, parser.parseFrom(
+        generatePaddingArray(data, offset, padding),
+        offset, length));
+    assertMessageEquals(message, parser.parseFrom(message.toByteString()));
+    assertMessageEquals(message, parser.parseFrom(
+        new ByteArrayInputStream(data)));
+    assertMessageEquals(message, parser.parseFrom(
+        CodedInputStream.newInstance(data)));
+  }
+
+  private void assertMessageEquals(
+      MessageLite expected, MessageLite actual)
+      throws Exception {
+    if (expected instanceof Message) {
+      assertEquals(expected, actual);
+    } else {
+      assertEquals(expected.toByteString(), actual.toByteString());
+    }
+  }
+
+  private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
+    byte[] result = new byte[offset + data.length + padding];
+    System.arraycopy(data, 0, result, offset, data.length);
+    return result;
+  }
+
+  public void testNormalMessage() throws Exception {
+    assertRoundTripEquals(TestUtil.getAllSet());
+  }
+
+
+  public void testParsePartial() throws Exception {
+    assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
+  }
+
+  private <T extends MessageLite> void assertParsePartial(
+      Parser<T> parser, T partialMessage) throws Exception {
+    final String errorString =
+        "Should throw exceptions when the parsed message isn't initialized.";
+
+    // parsePartialFrom should pass.
+    byte[] data = partialMessage.toByteArray();
+    assertEquals(partialMessage, parser.parsePartialFrom(data));
+    assertEquals(partialMessage, parser.parsePartialFrom(
+        partialMessage.toByteString()));
+    assertEquals(partialMessage, parser.parsePartialFrom(
+        new ByteArrayInputStream(data)));
+    assertEquals(partialMessage, parser.parsePartialFrom(
+        CodedInputStream.newInstance(data)));
+
+    // parseFrom(ByteArray)
+    try {
+      parser.parseFrom(partialMessage.toByteArray());
+      fail(errorString);
+    } catch (InvalidProtocolBufferException e) {
+      // pass.
+    }
+
+    // parseFrom(ByteString)
+    try {
+      parser.parseFrom(partialMessage.toByteString());
+      fail(errorString);
+    } catch (InvalidProtocolBufferException e) {
+      // pass.
+    }
+
+    // parseFrom(InputStream)
+    try {
+      parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
+      fail(errorString);
+    } catch (IOException e) {
+      // pass.
+    }
+
+    // parseFrom(CodedInputStream)
+    try {
+      parser.parseFrom(CodedInputStream.newInstance(
+          partialMessage.toByteArray()));
+      fail(errorString);
+    } catch (IOException e) {
+      // pass.
+    }
+  }
+
+  public void testParseExtensions() throws Exception {
+    assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
+                          TestUtil.getExtensionRegistry());
+    assertRoundTripEquals(
+        TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
+  }
+
+  public void testParsePacked() throws Exception {
+    assertRoundTripEquals(TestUtil.getPackedSet());
+    assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
+                          TestUtil.getExtensionRegistry());
+    assertRoundTripEquals(
+        TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
+  }
+
+  public void testParseDelimitedTo() throws Exception {
+    // Write normal Message.
+    TestAllTypes normalMessage = TestUtil.getAllSet();
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    normalMessage.writeDelimitedTo(output);
+
+    // Write MessageLite with packed extension fields.
+    TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet();
+    packedMessage.writeDelimitedTo(output);
+
+    InputStream input = new ByteArrayInputStream(output.toByteArray());
+    assertMessageEquals(
+        normalMessage,
+        normalMessage.getParserForType().parseDelimitedFrom(input));
+    assertMessageEquals(
+        packedMessage,
+        packedMessage
+            .getParserForType()
+            .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
+  }
+
+  public void testParseUnknownFields() throws Exception {
+    // All fields will be treated as unknown fields in emptyMessage.
+    TestEmptyMessage emptyMessage =
+        TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString());
+    assertEquals(
+        TestUtil.getAllSet().toByteString(),
+        emptyMessage.toByteString());
+  }
+
+
+  public void testOptimizeForSize() throws Exception {
+    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+    builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
+    builder.setExtension(TestOptimizedForSize.testExtension, 56);
+    builder.setExtension(TestOptimizedForSize.testExtension2,
+        TestRequiredOptimizedForSize.newBuilder().setX(78).build());
+
+    TestOptimizedForSize message = builder.build();
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestOptimizeFor.registerAllExtensions(registry);
+
+    assertRoundTripEquals(message, registry);
+  }
+
+  /** Helper method for {@link #testParsingMerge()}.*/
+  private void assertMessageMerged(TestAllTypes allTypes)
+      throws Exception {
+    assertEquals(3, allTypes.getOptionalInt32());
+    assertEquals(2, allTypes.getOptionalInt64());
+    assertEquals("hello", allTypes.getOptionalString());
+  }
+
+  /** Helper method for {@link #testParsingMergeLite()}.*/
+  private void assertMessageMerged(TestAllTypesLite allTypes)
+      throws Exception {
+    assertEquals(3, allTypes.getOptionalInt32());
+    assertEquals(2, allTypes.getOptionalInt64());
+    assertEquals("hello", allTypes.getOptionalString());
+  }
+
+  public void testParsingMerge() throws Exception {
+    // Build messages.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes msg1 = builder.setOptionalInt32(1).build();
+    builder.clear();
+    TestAllTypes msg2 = builder.setOptionalInt64(2).build();
+    builder.clear();
+    TestAllTypes msg3 = builder.setOptionalInt32(3)
+        .setOptionalString("hello").build();
+
+    // Build groups.
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg3).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg3).build();
+
+    // Assign and serialize RepeatedFieldsGenerator.
+    ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
+        .addField1(msg1).addField1(msg2).addField1(msg3)
+        .addField2(msg1).addField2(msg2).addField2(msg3)
+        .addField3(msg1).addField3(msg2).addField3(msg3)
+        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
+        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
+        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
+        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
+        .build().toByteString();
+
+    // Parse TestParsingMerge.
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestProto.registerAllExtensions(registry);
+    TestParsingMerge parsingMerge = TestParsingMerge.parser().parseFrom(data, registry);
+
+    // Required and optional fields should be merged.
+    assertMessageMerged(parsingMerge.getRequiredAllTypes());
+    assertMessageMerged(parsingMerge.getOptionalAllTypes());
+    assertMessageMerged(
+        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+    assertMessageMerged(parsingMerge.getExtension(
+        TestParsingMerge.optionalExt));
+
+    // Repeated fields should not be merged.
+    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
+    assertEquals(3, parsingMerge.getRepeatedGroupCount());
+    assertEquals(3, parsingMerge.getExtensionCount(
+        TestParsingMerge.repeatedExt));
+  }
+
+  public void testParsingMergeLite() throws Exception {
+    // Build messages.
+    TestAllTypesLite.Builder builder =
+        TestAllTypesLite.newBuilder();
+    TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
+    builder.clear();
+    TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
+    builder.clear();
+    TestAllTypesLite msg3 = builder.setOptionalInt32(3)
+        .setOptionalString("hello").build();
+
+    // Build groups.
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
+        .setField1(msg3).build();
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg1).build();
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg2).build();
+    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
+        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
+        .setField1(msg3).build();
+
+    // Assign and serialize RepeatedFieldsGenerator.
+    ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
+        .addField1(msg1).addField1(msg2).addField1(msg3)
+        .addField2(msg1).addField2(msg2).addField2(msg3)
+        .addField3(msg1).addField3(msg2).addField3(msg3)
+        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
+        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
+        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
+        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
+        .build().toByteString();
+
+    // Parse TestParsingMergeLite.
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+    TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry);
+
+    // Required and optional fields should be merged.
+    assertMessageMerged(parsingMerge.getRequiredAllTypes());
+    assertMessageMerged(parsingMerge.getOptionalAllTypes());
+    assertMessageMerged(
+        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+    assertMessageMerged(parsingMerge.getExtension(
+        TestParsingMergeLite.optionalExt));
+
+    // Repeated fields should not be merged.
+    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
+    assertEquals(3, parsingMerge.getRepeatedGroupCount());
+    assertEquals(3, parsingMerge.getExtensionCount(
+        TestParsingMergeLite.repeatedExt));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
new file mode 100644
index 0000000..3f45e22
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -0,0 +1,289 @@
+// 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.
+
+package com.google.protobuf;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests for {@link ProtobufArrayList}.
+ */
+public class ProtobufArrayListTest extends TestCase {
+  
+  private static final ProtobufArrayList<Integer> UNARY_LIST = newImmutableProtoArrayList(1);
+  private static final ProtobufArrayList<Integer> TERTIARY_LIST =
+      newImmutableProtoArrayList(1, 2, 3);
+  
+  private ProtobufArrayList<Integer> list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new ProtobufArrayList<Integer>();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(ProtobufArrayList.<Integer>emptyList());
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1, 2, 3, 4));
+    Iterator<Integer> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, (int) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.set(0, 1);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testMakeImmutable() {
+    list.add(2);
+    list.add(4);
+    list.add(6);
+    list.add(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testRemove() {
+    list.add(2);
+    list.add(4);
+    list.add(6);
+
+    list.remove(1);
+    assertEquals(asList(2, 6), list);
+
+    list.remove(1);
+    assertEquals(asList(2), list);
+
+    list.remove(0);
+    assertEquals(asList(), list);
+  }
+  
+  public void testGet() {
+    list.add(2);
+    list.add(6);
+    
+    assertEquals(2, (int) list.get(0));
+    assertEquals(6, (int) list.get(1));
+  }
+  
+  public void testSet() {
+    list.add(2);
+    list.add(6);
+    
+    list.set(0, 1);
+    assertEquals(1, (int) list.get(0));
+    list.set(1, 2);
+    assertEquals(2, (int) list.get(1));
+  }
+
+  private void assertImmutable(List<Integer> list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new ProtobufArrayList<Integer>());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    } 
+
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static ProtobufArrayList<Integer> newImmutableProtoArrayList(int... elements) {
+    ProtobufArrayList<Integer> list = new ProtobufArrayList<Integer>();
+    for (int element : elements) {
+      list.add(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
diff --git a/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
new file mode 100644
index 0000000..dc56f2e
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
@@ -0,0 +1,127 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from
+ * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringSubstringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "RopeByteString";
+    byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
+    ByteString sourceString = iter.next();
+    while (iter.hasNext()) {
+      sourceString = sourceString.concat(iter.next());
+    }
+
+    int from = 1130;
+    int to = sourceBytes.length - 5555;
+    stringUnderTest = sourceString.substring(from, to);
+    referenceBytes = new byte[to - from];
+    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
+    expectedHashCode = -1259260680;
+  }
+
+  @Override
+  public void testGetTreeDepth() {
+    assertEquals(classUnderTest + " must have the expected tree depth",
+        3, stringUnderTest.getTreeDepth());
+  }
+
+  @Override
+  public void testToString() throws UnsupportedEncodingException {
+    String sourceString = "I love unicode \u1234\u5678 characters";
+    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+    int copies = 250;
+
+    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+    StringBuilder builder = new StringBuilder(copies * sourceString.length());
+    ByteString unicode = ByteString.EMPTY;
+    for (int i = 0; i < copies; ++i) {
+      builder.append(sourceString);
+      unicode = RopeByteString.concatenate(unicode, sourceByteString);
+    }
+    String testString = builder.toString();
+
+    // Do the substring part
+    testString = testString.substring(2, testString.length() - 6);
+    unicode = unicode.substring(2, unicode.size() - 6);
+
+    assertEquals(classUnderTest + " from string must have the expected type",
+        classUnderTest, getActualClassName(unicode));
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString, roundTripString);
+    ByteString flatString = ByteString.copyFromUtf8(testString);
+    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+        flatString.hashCode(), unicode.hashCode());
+  }
+
+  @Override
+  public void testCharsetToString() {
+    String sourceString = "I love unicode \u1234\u5678 characters";
+    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+    int copies = 250;
+
+    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+    StringBuilder builder = new StringBuilder(copies * sourceString.length());
+    ByteString unicode = ByteString.EMPTY;
+    for (int i = 0; i < copies; ++i) {
+      builder.append(sourceString);
+      unicode = RopeByteString.concatenate(unicode, sourceByteString);
+    }
+    String testString = builder.toString();
+
+    // Do the substring part
+    testString = testString.substring(2, testString.length() - 6);
+    unicode = unicode.substring(2, unicode.size() - 6);
+
+    assertEquals(classUnderTest + " from string must have the expected type",
+        classUnderTest, getActualClassName(unicode));
+    String roundTripString = unicode.toString(Internal.UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString, roundTripString);
+    ByteString flatString = ByteString.copyFromUtf8(testString);
+    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+        flatString.hashCode(), unicode.hashCode());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
new file mode 100644
index 0000000..4ec3a40
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
@@ -0,0 +1,189 @@
+// 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.
+
+package com.google.protobuf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * This class tests {@link RopeByteString} by inheriting the tests from
+ * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.
+ *
+ * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
+ * separate class {@link RopeByteStringSubstringTest}.
+ *
+ * @author carlanton@google.com (Carl Haverl)
+ */
+public class RopeByteStringTest extends LiteralByteStringTest {
+
+  @Override
+  protected void setUp() throws Exception {
+    classUnderTest = "RopeByteString";
+    referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
+    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
+    stringUnderTest = iter.next();
+    while (iter.hasNext()) {
+      stringUnderTest = stringUnderTest.concat(iter.next());
+    }
+    expectedHashCode = -1214197238;
+  }
+
+  @Override
+  public void testGetTreeDepth() {
+    assertEquals(classUnderTest + " must have the expected tree depth",
+        4, stringUnderTest.getTreeDepth());
+  }
+
+  public void testBalance() {
+    int numberOfPieces = 10000;
+    int pieceSize = 64;
+    byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L);
+
+    // Build up a big ByteString from smaller pieces to force a rebalance
+    ByteString concatenated = ByteString.EMPTY;
+    for (int i = 0; i < numberOfPieces; ++i) {
+      concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize));
+    }
+
+    assertEquals(classUnderTest + " from string must have the expected type",
+        classUnderTest, getActualClassName(concatenated));
+    assertTrue(classUnderTest + " underlying bytes must match after balancing",
+        Arrays.equals(testBytes, concatenated.toByteArray()));
+    ByteString testString = ByteString.copyFrom(testBytes);
+    assertTrue(classUnderTest + " balanced string must equal flat string",
+        concatenated.equals(testString));
+    assertTrue(classUnderTest + " flat string must equal balanced string",
+        testString.equals(concatenated));
+    assertEquals(classUnderTest + " balanced string must have same hash code as flat string",
+        testString.hashCode(), concatenated.hashCode());
+  }
+
+  @Override
+  public void testToString() throws UnsupportedEncodingException {
+    String sourceString = "I love unicode \u1234\u5678 characters";
+    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+    int copies = 250;
+
+    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+    StringBuilder builder = new StringBuilder(copies * sourceString.length());
+    ByteString unicode = ByteString.EMPTY;
+    for (int i = 0; i < copies; ++i) {
+      builder.append(sourceString);
+      unicode = RopeByteString.concatenate(unicode, sourceByteString);
+    }
+    String testString = builder.toString();
+
+    assertEquals(classUnderTest + " from string must have the expected type",
+        classUnderTest, getActualClassName(unicode));
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString, roundTripString);
+    ByteString flatString = ByteString.copyFromUtf8(testString);
+    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+        flatString.hashCode(), unicode.hashCode());
+  }
+
+  @Override
+  public void testCharsetToString() {
+    String sourceString = "I love unicode \u1234\u5678 characters";
+    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
+    int copies = 250;
+
+    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
+    StringBuilder builder = new StringBuilder(copies * sourceString.length());
+    ByteString unicode = ByteString.EMPTY;
+    for (int i = 0; i < copies; ++i) {
+      builder.append(sourceString);
+      unicode = RopeByteString.concatenate(unicode, sourceByteString);
+    }
+    String testString = builder.toString();
+
+    assertEquals(classUnderTest + " from string must have the expected type",
+        classUnderTest, getActualClassName(unicode));
+    String roundTripString = unicode.toString(Internal.UTF_8);
+    assertEquals(classUnderTest + " unicode bytes must match",
+        testString, roundTripString);
+    ByteString flatString = ByteString.copyFromUtf8(testString);
+    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
+    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
+        flatString.hashCode(), unicode.hashCode());
+  }
+
+  @Override
+  public void testToString_returnsCanonicalEmptyString() {
+    RopeByteString ropeByteString =
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+    assertSame(classUnderTest + " must be the same string references",
+        ByteString.EMPTY.toString(Internal.UTF_8), ropeByteString.toString(Internal.UTF_8));
+  }
+
+  @Override
+  public void testToString_raisesException() {
+    try {
+      ByteString byteString =
+          RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+      byteString.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      ByteString byteString = RopeByteString.concatenate(ByteString.copyFromUtf8("foo"),
+          ByteString.copyFromUtf8("bar"));
+      byteString.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
+  @Override
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(stringUnderTest);
+    oos.close();
+    byte[] pickled = out.toByteArray();
+    InputStream in = new ByteArrayInputStream(pickled);
+    ObjectInputStream ois = new ObjectInputStream(in);
+    Object o = ois.readObject();
+    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+    assertEquals("Should get an equal ByteString back", stringUnderTest, o);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
new file mode 100644
index 0000000..b902737
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -0,0 +1,326 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.ServiceWithNoOuter;
+import protobuf_unittest.UnittestProto.BarRequest;
+import protobuf_unittest.UnittestProto.BarResponse;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestService;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.IMocksControl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests services and stubs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ServiceTest extends TestCase {
+  private IMocksControl control;
+  private RpcController mockController;
+
+  private final Descriptors.MethodDescriptor fooDescriptor =
+    TestService.getDescriptor().getMethods().get(0);
+  private final Descriptors.MethodDescriptor barDescriptor =
+    TestService.getDescriptor().getMethods().get(1);
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    control = EasyMock.createStrictControl();
+    mockController = control.createMock(RpcController.class);
+  }
+
+  // =================================================================
+
+  /** Tests Service.callMethod(). */
+  public void testCallMethod() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    MockCallback<Message> fooCallback = new MockCallback<Message>();
+    MockCallback<Message> barCallback = new MockCallback<Message>();
+    TestService mockService = control.createMock(TestService.class);
+
+    mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
+                    this.<FooResponse>wrapsCallback(fooCallback));
+    mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
+                    this.<BarResponse>wrapsCallback(barCallback));
+    control.replay();
+
+    mockService.callMethod(fooDescriptor, mockController,
+                           fooRequest, fooCallback);
+    mockService.callMethod(barDescriptor, mockController,
+                           barRequest, barCallback);
+    control.verify();
+  }
+
+  /** Tests Service.get{Request,Response}Prototype(). */
+  public void testGetPrototype() throws Exception {
+    TestService mockService = control.createMock(TestService.class);
+
+    assertSame(mockService.getRequestPrototype(fooDescriptor),
+               FooRequest.getDefaultInstance());
+    assertSame(mockService.getResponsePrototype(fooDescriptor),
+               FooResponse.getDefaultInstance());
+    assertSame(mockService.getRequestPrototype(barDescriptor),
+               BarRequest.getDefaultInstance());
+    assertSame(mockService.getResponsePrototype(barDescriptor),
+               BarResponse.getDefaultInstance());
+  }
+
+  /** Tests generated stubs. */
+  public void testStub() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
+    MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
+    RpcChannel mockChannel = control.createMock(RpcChannel.class);
+    TestService stub = TestService.newStub(mockChannel);
+
+    mockChannel.callMethod(
+      EasyMock.same(fooDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(fooRequest),
+      EasyMock.same(FooResponse.getDefaultInstance()),
+      this.<Message>wrapsCallback(fooCallback));
+    mockChannel.callMethod(
+      EasyMock.same(barDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(barRequest),
+      EasyMock.same(BarResponse.getDefaultInstance()),
+      this.<Message>wrapsCallback(barCallback));
+    control.replay();
+
+    stub.foo(mockController, fooRequest, fooCallback);
+    stub.bar(mockController, barRequest, barCallback);
+    control.verify();
+  }
+
+  /** Tests generated blocking stubs. */
+  public void testBlockingStub() throws Exception {
+    FooRequest fooRequest = FooRequest.newBuilder().build();
+    BarRequest barRequest = BarRequest.newBuilder().build();
+    BlockingRpcChannel mockChannel =
+        control.createMock(BlockingRpcChannel.class);
+    TestService.BlockingInterface stub =
+        TestService.newBlockingStub(mockChannel);
+
+    FooResponse fooResponse = FooResponse.newBuilder().build();
+    BarResponse barResponse = BarResponse.newBuilder().build();
+
+    EasyMock.expect(mockChannel.callBlockingMethod(
+      EasyMock.same(fooDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(fooRequest),
+      EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
+    EasyMock.expect(mockChannel.callBlockingMethod(
+      EasyMock.same(barDescriptor),
+      EasyMock.same(mockController),
+      EasyMock.same(barRequest),
+      EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
+    control.replay();
+
+    assertSame(fooResponse, stub.foo(mockController, fooRequest));
+    assertSame(barResponse, stub.bar(mockController, barRequest));
+    control.verify();
+  }
+
+  public void testNewReflectiveService() {
+    ServiceWithNoOuter.Interface impl =
+        control.createMock(ServiceWithNoOuter.Interface.class);
+    RpcController controller = control.createMock(RpcController.class);
+    Service service = ServiceWithNoOuter.newReflectiveService(impl);
+
+    MethodDescriptor fooMethod =
+        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+    RpcCallback<Message> callback =
+        new RpcCallback<Message>() {
+          @Override
+          public void run(Message parameter) {
+            // No reason this should be run.
+            fail();
+          }
+        };
+    RpcCallback<TestAllTypes> specializedCallback =
+        RpcUtil.specializeCallback(callback);
+
+    impl.foo(EasyMock.same(controller), EasyMock.same(request),
+        EasyMock.same(specializedCallback));
+    EasyMock.expectLastCall();
+
+    control.replay();
+
+    service.callMethod(fooMethod, controller, request, callback);
+
+    control.verify();
+  }
+
+  public void testNewReflectiveBlockingService() throws ServiceException {
+    ServiceWithNoOuter.BlockingInterface impl =
+        control.createMock(ServiceWithNoOuter.BlockingInterface.class);
+    RpcController controller = control.createMock(RpcController.class);
+    BlockingService service =
+        ServiceWithNoOuter.newReflectiveBlockingService(impl);
+
+    MethodDescriptor fooMethod =
+        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+
+    TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
+    EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
+        .andReturn(expectedResponse);
+
+    control.replay();
+
+    Message response =
+        service.callBlockingMethod(fooMethod, controller, request);
+    assertEquals(expectedResponse, response);
+
+    control.verify();
+  }
+
+  public void testNoGenericServices() throws Exception {
+    // Non-services should be usable.
+    UnittestNoGenericServices.TestMessage message =
+      UnittestNoGenericServices.TestMessage.newBuilder()
+        .setA(123)
+        .setExtension(UnittestNoGenericServices.testExtension, 456)
+        .build();
+    assertEquals(123, message.getA());
+    assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
+
+    // Build a list of the class names nested in UnittestNoGenericServices.
+    String outerName = "google.protobuf.no_generic_services_test." +
+                       "UnittestNoGenericServices";
+    Class<?> outerClass = Class.forName(outerName);
+
+    Set<String> innerClassNames = new HashSet<String>();
+    for (Class<?> innerClass : outerClass.getClasses()) {
+      String fullName = innerClass.getName();
+      // Figure out the unqualified name of the inner class.
+      // Note:  Surprisingly, the full name of an inner class will be separated
+      //   from the outer class name by a '$' rather than a '.'.  This is not
+      //   mentioned in the documentation for java.lang.Class.  I don't want to
+      //   make assumptions, so I'm just going to accept any character as the
+      //   separator.
+      assertTrue(fullName.startsWith(outerName));
+
+      if (!Service.class.isAssignableFrom(innerClass) &&
+          !Message.class.isAssignableFrom(innerClass) &&
+          !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
+        // Ignore any classes not generated by the base code generator.
+        continue;
+      }
+
+      innerClassNames.add(fullName.substring(outerName.length() + 1));
+    }
+
+    // No service class should have been generated.
+    assertTrue(innerClassNames.contains("TestMessage"));
+    assertTrue(innerClassNames.contains("TestEnum"));
+    assertFalse(innerClassNames.contains("TestService"));
+
+    // But descriptors are there.
+    FileDescriptor file = UnittestNoGenericServices.getDescriptor();
+    assertEquals(1, file.getServices().size());
+    assertEquals("TestService", file.getServices().get(0).getName());
+    assertEquals(1, file.getServices().get(0).getMethods().size());
+    assertEquals("Foo",
+        file.getServices().get(0).getMethods().get(0).getName());
+  }
+
+  // =================================================================
+
+  /**
+   * wrapsCallback() is an EasyMock argument predicate.  wrapsCallback(c)
+   * matches a callback if calling that callback causes c to be called.
+   * In other words, c wraps the given callback.
+   */
+  private <Type extends Message> RpcCallback<Type> wrapsCallback(
+      MockCallback<?> callback) {
+    EasyMock.reportMatcher(new WrapsCallback(callback));
+    return null;
+  }
+
+  /** The parameter to wrapsCallback() must be a MockCallback. */
+  private static class MockCallback<Type extends Message>
+      implements RpcCallback<Type> {
+    private boolean called = false;
+
+    public boolean isCalled() { return called; }
+
+    public void reset() { called = false; }
+    @Override
+    public void run(Type message) {
+      called = true; }
+  }
+
+  /** Implementation of the wrapsCallback() argument matcher. */
+  private static class WrapsCallback implements IArgumentMatcher {
+    private MockCallback<?> callback;
+
+    public WrapsCallback(MockCallback<?> callback) {
+      this.callback = callback;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean matches(Object actual) {
+      if (!(actual instanceof RpcCallback)) {
+        return false;
+      }
+      RpcCallback actualCallback = (RpcCallback)actual;
+
+      callback.reset();
+      actualCallback.run(null);
+      return callback.isCalled();
+    }
+
+    @Override
+    public void appendTo(StringBuffer buffer) {
+      buffer.append("wrapsCallback(mockCallback)");
+    }
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
diff --git a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
new file mode 100644
index 0000000..e96ecd6
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
@@ -0,0 +1,423 @@
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author darick@google.com Darick Tong
+ */
+public class SmallSortedMapTest extends TestCase {
+  // java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it
+  // here for JDK 1.5 users.
+  private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
+    private final K key;
+    private V value;
+
+    SimpleEntry(K key, V value) {
+      this.key = key;
+      this.value = value;
+    }
+
+    @Override
+    public K getKey() {
+      return key;
+    }
+
+    @Override
+    public V getValue() {
+      return value;
+    }
+
+    @Override
+    public V setValue(V value) {
+      V oldValue = this.value;
+      this.value = value;
+      return oldValue;
+    }
+
+    private static boolean eq(Object o1, Object o2) {
+      return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof Map.Entry))
+        return false;
+      Map.Entry e = (Map.Entry) o;
+      return eq(key, e.getKey()) && eq(value, e.getValue());
+    }
+
+    @Override
+    public int hashCode() {
+      return ((key == null) ? 0 : key.hashCode()) ^
+          ((value == null) ? 0 : value.hashCode());
+    }
+  }
+
+  public void testPutAndGetArrayEntriesOnly() {
+    runPutAndGetTest(3);
+  }
+
+  public void testPutAndGetOverflowEntries() {
+    runPutAndGetTest(6);
+  }
+
+  private void runPutAndGetTest(int numElements) {
+    // Test with even and odd arraySize
+    SmallSortedMap<Integer, Integer> map1 =
+        SmallSortedMap.newInstanceForTest(3);
+    SmallSortedMap<Integer, Integer> map2 =
+        SmallSortedMap.newInstanceForTest(4);
+    SmallSortedMap<Integer, Integer> map3 =
+        SmallSortedMap.newInstanceForTest(3);
+    SmallSortedMap<Integer, Integer> map4 =
+        SmallSortedMap.newInstanceForTest(4);
+
+    // Test with puts in ascending order.
+    for (int i = 0; i < numElements; i++) {
+      assertNull(map1.put(i, i + 1));
+      assertNull(map2.put(i, i + 1));
+    }
+    // Test with puts in descending order.
+    for (int i = numElements - 1; i >= 0; i--) {
+      assertNull(map3.put(i, i + 1));
+      assertNull(map4.put(i, i + 1));
+    }
+
+    assertEquals(Math.min(3, numElements), map1.getNumArrayEntries());
+    assertEquals(Math.min(4, numElements), map2.getNumArrayEntries());
+    assertEquals(Math.min(3, numElements), map3.getNumArrayEntries());
+    assertEquals(Math.min(4, numElements), map4.getNumArrayEntries());
+
+    List<SmallSortedMap<Integer, Integer>> allMaps =
+        new ArrayList<SmallSortedMap<Integer, Integer>>();
+    allMaps.add(map1);
+    allMaps.add(map2);
+    allMaps.add(map3);
+    allMaps.add(map4);
+
+    for (SmallSortedMap<Integer, Integer> map : allMaps) {
+      assertEquals(numElements, map.size());
+      for (int i = 0; i < numElements; i++) {
+        assertEquals(new Integer(i + 1), map.get(i));
+      }
+    }
+
+    assertEquals(map1, map2);
+    assertEquals(map2, map3);
+    assertEquals(map3, map4);
+  }
+
+  public void testReplacingPut() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+      assertNull(map.remove(i + 1));
+    }
+    for (int i = 0; i < 6; i++) {
+      assertEquals(new Integer(i + 1), map.put(i, i + 2));
+    }
+  }
+
+  public void testRemove() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+      assertNull(map.remove(i + 1));
+    }
+
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(3, map.getNumOverflowEntries());
+    assertEquals(6,  map.size());
+    assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet());
+
+    assertEquals(new Integer(2), map.remove(1));
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(2, map.getNumOverflowEntries());
+    assertEquals(5,  map.size());
+    assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet());
+
+    assertEquals(new Integer(5), map.remove(4));
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(1, map.getNumOverflowEntries());
+    assertEquals(4,  map.size());
+    assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet());
+
+    assertEquals(new Integer(4), map.remove(3));
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(3, map.size());
+    assertEquals(makeSortedKeySet(0, 2, 5), map.keySet());
+
+    assertNull(map.remove(3));
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(3, map.size());
+
+    assertEquals(new Integer(1), map.remove(0));
+    assertEquals(2, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(2, map.size());
+  }
+
+  public void testClear() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    map.clear();
+    assertEquals(0, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(0, map.size());
+  }
+
+  public void testGetArrayEntryAndOverflowEntries() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    assertEquals(3, map.getNumArrayEntries());
+    for (int i = 0; i < 3; i++) {
+      Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i);
+      assertEquals(new Integer(i), entry.getKey());
+      assertEquals(new Integer(i + 1), entry.getValue());
+    }
+    Iterator<Map.Entry<Integer, Integer>> it =
+        map.getOverflowEntries().iterator();
+    for (int i = 3; i < 6; i++) {
+      assertTrue(it.hasNext());
+      Map.Entry<Integer, Integer> entry = it.next();
+      assertEquals(new Integer(i), entry.getKey());
+      assertEquals(new Integer(i + 1), entry.getValue());
+    }
+    assertFalse(it.hasNext());
+  }
+
+  public void testEntrySetContains() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
+    for (int i = 0; i < 6; i++) {
+      assertTrue(
+          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1)));
+      assertFalse(
+          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i)));
+    }
+  }
+
+  public void testEntrySetAdd() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
+    for (int i = 0; i < 6; i++) {
+      Map.Entry<Integer, Integer> entry =
+          new SimpleEntry<Integer, Integer>(i, i + 1);
+      assertTrue(entrySet.add(entry));
+      assertFalse(entrySet.add(entry));
+    }
+    for (int i = 0; i < 6; i++) {
+      assertEquals(new Integer(i + 1), map.get(i));
+    }
+    assertEquals(3, map.getNumArrayEntries());
+    assertEquals(3, map.getNumOverflowEntries());
+    assertEquals(6, map.size());
+  }
+
+  public void testEntrySetRemove() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    for (int i = 0; i < 6; i++) {
+      Map.Entry<Integer, Integer> entry =
+          new SimpleEntry<Integer, Integer>(i, i + 1);
+      assertTrue(entrySet.remove(entry));
+      assertFalse(entrySet.remove(entry));
+    }
+    assertTrue(map.isEmpty());
+    assertEquals(0, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(0, map.size());
+  }
+
+  public void testEntrySetClear() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    map.entrySet().clear();
+    assertTrue(map.isEmpty());
+    assertEquals(0, map.getNumArrayEntries());
+    assertEquals(0, map.getNumOverflowEntries());
+    assertEquals(0, map.size());
+  }
+
+  public void testEntrySetIteratorNext() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
+    for (int i = 0; i < 6; i++) {
+      assertTrue(it.hasNext());
+      Map.Entry<Integer, Integer> entry = it.next();
+      assertEquals(new Integer(i), entry.getKey());
+      assertEquals(new Integer(i + 1), entry.getValue());
+    }
+    assertFalse(it.hasNext());
+  }
+
+  public void testEntrySetIteratorRemove() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
+    for (int i = 0; i < 6; i++) {
+      assertTrue(map.containsKey(i));
+      it.next();
+      it.remove();
+      assertFalse(map.containsKey(i));
+      assertEquals(6 - i - 1, map.size());
+    }
+  }
+
+  public void testMapEntryModification() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
+    for (int i = 0; i < 6; i++) {
+      Map.Entry<Integer, Integer> entry = it.next();
+      entry.setValue(i + 23);
+    }
+    for (int i = 0; i < 6; i++) {
+      assertEquals(new Integer(i + 23), map.get(i));
+    }
+  }
+
+  public void testMakeImmutable() {
+    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
+    for (int i = 0; i < 6; i++) {
+      assertNull(map.put(i, i + 1));
+    }
+    map.makeImmutable();
+    assertEquals(new Integer(1), map.get(0));
+    assertEquals(6, map.size());
+
+    try {
+      map.put(23, 23);
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Map<Integer, Integer> other = new HashMap<Integer, Integer>();
+    other.put(23, 23);
+    try {
+      map.putAll(other);
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    try {
+      map.remove(0);
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    try {
+      map.clear();
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
+    try {
+      entrySet.clear();
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator();
+    while (it.hasNext()) {
+      Map.Entry<Integer, Integer> entry = it.next();
+      try {
+        entry.setValue(0);
+        fail("Expected UnsupportedOperationException");
+      } catch (UnsupportedOperationException expected) {
+      }
+      try {
+        it.remove();
+        fail("Expected UnsupportedOperationException");
+      } catch (UnsupportedOperationException expected) {
+      }
+    }
+
+    Set<Integer> keySet = map.keySet();
+    try {
+      keySet.clear();
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    Iterator<Integer> keys = keySet.iterator();
+    while (keys.hasNext()) {
+      Integer key = keys.next();
+      try {
+        keySet.remove(key);
+        fail("Expected UnsupportedOperationException");
+      } catch (UnsupportedOperationException expected) {
+      }
+      try {
+        keys.remove();
+        fail("Expected UnsupportedOperationException");
+      } catch (UnsupportedOperationException expected) {
+      }
+    }
+  }
+
+  private Set<Integer> makeSortedKeySet(Integer... keys) {
+    return new TreeSet<Integer>(Arrays.<Integer>asList(keys));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
new file mode 100644
index 0000000..2c60fe0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
@@ -0,0 +1,96 @@
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that proto2 api generation doesn't cause compile errors when
+ * compiling protocol buffers that have names that would otherwise conflict
+ * if not fully qualified (like @Deprecated and @Override).
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class TestBadIdentifiers extends TestCase {
+
+  public void testCompilation() {
+    // If this compiles, it means the generation was correct.
+    TestBadIdentifiersProto.Deprecated.newBuilder();
+    TestBadIdentifiersProto.Override.newBuilder();
+  }
+
+  public void testGetDescriptor() {
+    Descriptors.FileDescriptor fileDescriptor =
+        TestBadIdentifiersProto.getDescriptor();
+    String descriptorField = TestBadIdentifiersProto.Descriptor
+        .getDefaultInstance().getDescriptor();
+    Descriptors.Descriptor protoDescriptor = TestBadIdentifiersProto.Descriptor
+        .getDefaultInstance().getDescriptorForType();
+    String nestedDescriptorField = TestBadIdentifiersProto.Descriptor
+        .NestedDescriptor.getDefaultInstance().getDescriptor();
+    Descriptors.Descriptor nestedProtoDescriptor = TestBadIdentifiersProto
+        .Descriptor.NestedDescriptor.getDefaultInstance()
+        .getDescriptorForType();
+  }
+
+  public void testConflictingFieldNames() throws Exception {
+    TestBadIdentifiersProto.TestConflictingFieldNames message =
+        TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
+    // Make sure generated accessors are properly named.
+    assertEquals(0, message.getInt32Field1Count());
+    assertEquals(0, message.getEnumField2Count());
+    assertEquals(0, message.getStringField3Count());
+    assertEquals(0, message.getBytesField4Count());
+    assertEquals(0, message.getMessageField5Count());
+
+    assertEquals(0, message.getInt32FieldCount11());
+    assertEquals(0, message.getEnumFieldCount12().getNumber());
+    assertEquals("", message.getStringFieldCount13());
+    assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
+    assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
+
+    assertEquals(0, message.getInt32Field21Count());
+    assertEquals(0, message.getEnumField22Count());
+    assertEquals(0, message.getStringField23Count());
+    assertEquals(0, message.getBytesField24Count());
+    assertEquals(0, message.getMessageField25Count());
+
+    assertEquals(0, message.getInt32Field1List().size());
+    assertEquals(0, message.getInt32FieldList31());
+
+    assertEquals(0, message.getInt64FieldCount());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
+    assertEquals(0L, message.getExtension(
+        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
+
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
new file mode 100644
index 0000000..08b2a76
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -0,0 +1,3857 @@
+// 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.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
+import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultBytesExtension;
+import static protobuf_unittest.UnittestProto.defaultCordExtension;
+import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
+import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultFloatExtension;
+import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
+// The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
+// import static protobuf_unittest.UnittestProto.*;
+import static protobuf_unittest.UnittestProto.defaultInt32Extension;
+import static protobuf_unittest.UnittestProto.defaultInt64Extension;
+import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultSint32Extension;
+import static protobuf_unittest.UnittestProto.defaultSint64Extension;
+import static protobuf_unittest.UnittestProto.defaultStringExtension;
+import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
+import static protobuf_unittest.UnittestProto.defaultUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint64Extension;
+import static protobuf_unittest.UnittestProto.oneofBytesExtension;
+import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.oneofStringExtension;
+import static protobuf_unittest.UnittestProto.oneofUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalBoolExtension;
+import static protobuf_unittest.UnittestProto.optionalBytesExtension;
+import static protobuf_unittest.UnittestProto.optionalCordExtension;
+import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
+import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalFloatExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalGroupExtension;
+import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalSint32Extension;
+import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalStringExtension;
+import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
+import static protobuf_unittest.UnittestProto.optionalUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalUint64Extension;
+import static protobuf_unittest.UnittestProto.packedBoolExtension;
+import static protobuf_unittest.UnittestProto.packedDoubleExtension;
+import static protobuf_unittest.UnittestProto.packedEnumExtension;
+import static protobuf_unittest.UnittestProto.packedFixed32Extension;
+import static protobuf_unittest.UnittestProto.packedFixed64Extension;
+import static protobuf_unittest.UnittestProto.packedFloatExtension;
+import static protobuf_unittest.UnittestProto.packedInt32Extension;
+import static protobuf_unittest.UnittestProto.packedInt64Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.packedSint32Extension;
+import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.packedUint32Extension;
+import static protobuf_unittest.UnittestProto.packedUint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
+import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
+import static protobuf_unittest.UnittestProto.repeatedCordExtension;
+import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
+import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
+import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
+import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedStringExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
+import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
+
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestUnpackedTypes;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Contains methods for setting all fields of {@code TestAllTypes} to
+ * some values as well as checking that all the fields are set to those values.
+ * These are useful for testing various protocol message features, e.g.
+ * set all fields of a message, serialize it, parse it, and check that all
+ * fields are set.
+ *
+ * <p>This code is not to be used outside of {@code com.google.protobuf} and
+ * subpackages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class TestUtil {
+  private TestUtil() {}
+
+  /** Helper to convert a String to ByteString. */
+  static ByteString toBytes(String str) {
+    return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
+  }
+
+  /**
+   * Get a {@code TestAllTypes} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}.
+   */
+  public static TestAllTypes getAllSet() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    setAllFields(builder);
+    return builder.build();
+  }
+
+  /**
+   * Get a {@code TestAllTypes.Builder} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}.
+   */
+  public static TestAllTypes.Builder getAllSetBuilder() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    setAllFields(builder);
+    return builder;
+  }
+
+  /**
+   * Get a {@code TestAllExtensions} with all fields set as they would be by
+   * {@link #setAllExtensions(TestAllExtensions.Builder)}.
+   */
+  public static TestAllExtensions getAllExtensionsSet() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    setAllExtensions(builder);
+    return builder.build();
+  }
+
+  public static TestPackedTypes getPackedSet() {
+    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+    setPackedFields(builder);
+    return builder.build();
+  }
+
+  public static TestUnpackedTypes getUnpackedSet() {
+    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
+    setUnpackedFields(builder);
+    return builder.build();
+  }
+
+  public static TestPackedExtensions getPackedExtensionsSet() {
+    TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder();
+    setPackedExtensions(builder);
+    return builder.build();
+  }
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllFieldsSet()}.
+   */
+  public static void setAllFields(TestAllTypes.Builder message) {
+    message.setOptionalInt32   (101);
+    message.setOptionalInt64   (102);
+    message.setOptionalUint32  (103);
+    message.setOptionalUint64  (104);
+    message.setOptionalSint32  (105);
+    message.setOptionalSint64  (106);
+    message.setOptionalFixed32 (107);
+    message.setOptionalFixed64 (108);
+    message.setOptionalSfixed32(109);
+    message.setOptionalSfixed64(110);
+    message.setOptionalFloat   (111);
+    message.setOptionalDouble  (112);
+    message.setOptionalBool    (true);
+    message.setOptionalString  ("115");
+    message.setOptionalBytes   (toBytes("116"));
+
+    message.setOptionalGroup(
+      TestAllTypes.OptionalGroup.newBuilder().setA(117).build());
+    message.setOptionalNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+    message.setOptionalForeignMessage(
+      ForeignMessage.newBuilder().setC(119).build());
+    message.setOptionalImportMessage(
+      ImportMessage.newBuilder().setD(120).build());
+    message.setOptionalPublicImportMessage(
+      PublicImportMessage.newBuilder().setE(126).build());
+    message.setOptionalLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
+    message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
+    message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
+
+    message.setOptionalStringPiece("124");
+    message.setOptionalCord("125");
+
+    // -----------------------------------------------------------------
+
+    message.addRepeatedInt32   (201);
+    message.addRepeatedInt64   (202);
+    message.addRepeatedUint32  (203);
+    message.addRepeatedUint64  (204);
+    message.addRepeatedSint32  (205);
+    message.addRepeatedSint64  (206);
+    message.addRepeatedFixed32 (207);
+    message.addRepeatedFixed64 (208);
+    message.addRepeatedSfixed32(209);
+    message.addRepeatedSfixed64(210);
+    message.addRepeatedFloat   (211);
+    message.addRepeatedDouble  (212);
+    message.addRepeatedBool    (true);
+    message.addRepeatedString  ("215");
+    message.addRepeatedBytes   (toBytes("216"));
+
+    message.addRepeatedGroup(
+      TestAllTypes.RepeatedGroup.newBuilder().setA(217).build());
+    message.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    message.addRepeatedForeignMessage(
+      ForeignMessage.newBuilder().setC(219).build());
+    message.addRepeatedImportMessage(
+      ImportMessage.newBuilder().setD(220).build());
+    message.addRepeatedLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
+    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
+    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAR);
+
+    message.addRepeatedStringPiece("224");
+    message.addRepeatedCord("225");
+
+    // Add a second one of each field.
+    message.addRepeatedInt32   (301);
+    message.addRepeatedInt64   (302);
+    message.addRepeatedUint32  (303);
+    message.addRepeatedUint64  (304);
+    message.addRepeatedSint32  (305);
+    message.addRepeatedSint64  (306);
+    message.addRepeatedFixed32 (307);
+    message.addRepeatedFixed64 (308);
+    message.addRepeatedSfixed32(309);
+    message.addRepeatedSfixed64(310);
+    message.addRepeatedFloat   (311);
+    message.addRepeatedDouble  (312);
+    message.addRepeatedBool    (false);
+    message.addRepeatedString  ("315");
+    message.addRepeatedBytes   (toBytes("316"));
+
+    message.addRepeatedGroup(
+      TestAllTypes.RepeatedGroup.newBuilder().setA(317).build());
+    message.addRepeatedNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+    message.addRepeatedForeignMessage(
+      ForeignMessage.newBuilder().setC(319).build());
+    message.addRepeatedImportMessage(
+      ImportMessage.newBuilder().setD(320).build());
+    message.addRepeatedLazyMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
+    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
+    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAZ);
+
+    message.addRepeatedStringPiece("324");
+    message.addRepeatedCord("325");
+
+    // -----------------------------------------------------------------
+
+    message.setDefaultInt32   (401);
+    message.setDefaultInt64   (402);
+    message.setDefaultUint32  (403);
+    message.setDefaultUint64  (404);
+    message.setDefaultSint32  (405);
+    message.setDefaultSint64  (406);
+    message.setDefaultFixed32 (407);
+    message.setDefaultFixed64 (408);
+    message.setDefaultSfixed32(409);
+    message.setDefaultSfixed64(410);
+    message.setDefaultFloat   (411);
+    message.setDefaultDouble  (412);
+    message.setDefaultBool    (false);
+    message.setDefaultString  ("415");
+    message.setDefaultBytes   (toBytes("416"));
+
+    message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
+    message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
+    message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
+
+    message.setDefaultStringPiece("424");
+    message.setDefaultCord("425");
+
+    message.setOneofUint32(601);
+    message.setOneofNestedMessage(
+      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+    message.setOneofString("603");
+    message.setOneofBytes(toBytes("604"));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated fields of {@code message} to contain the values
+   * expected by {@code assertRepeatedFieldsModified()}.
+   */
+  public static void modifyRepeatedFields(TestAllTypes.Builder message) {
+    message.setRepeatedInt32   (1, 501);
+    message.setRepeatedInt64   (1, 502);
+    message.setRepeatedUint32  (1, 503);
+    message.setRepeatedUint64  (1, 504);
+    message.setRepeatedSint32  (1, 505);
+    message.setRepeatedSint64  (1, 506);
+    message.setRepeatedFixed32 (1, 507);
+    message.setRepeatedFixed64 (1, 508);
+    message.setRepeatedSfixed32(1, 509);
+    message.setRepeatedSfixed64(1, 510);
+    message.setRepeatedFloat   (1, 511);
+    message.setRepeatedDouble  (1, 512);
+    message.setRepeatedBool    (1, true);
+    message.setRepeatedString  (1, "515");
+    message.setRepeatedBytes   (1, toBytes("516"));
+
+    message.setRepeatedGroup(1,
+      TestAllTypes.RepeatedGroup.newBuilder().setA(517).build());
+    message.setRepeatedNestedMessage(1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+    message.setRepeatedForeignMessage(1,
+      ForeignMessage.newBuilder().setC(519).build());
+    message.setRepeatedImportMessage(1,
+      ImportMessage.newBuilder().setD(520).build());
+    message.setRepeatedLazyMessage(1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
+    message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
+    message.setRepeatedImportEnum (1, ImportEnum.IMPORT_FOO);
+
+    message.setRepeatedStringPiece(1, "524");
+    message.setRepeatedCord(1, "525");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setAllFields}.
+   */
+  public static void assertAllFieldsSet(TestAllTypesOrBuilder message) {
+    Assert.assertTrue(message.hasOptionalInt32   ());
+    Assert.assertTrue(message.hasOptionalInt64   ());
+    Assert.assertTrue(message.hasOptionalUint32  ());
+    Assert.assertTrue(message.hasOptionalUint64  ());
+    Assert.assertTrue(message.hasOptionalSint32  ());
+    Assert.assertTrue(message.hasOptionalSint64  ());
+    Assert.assertTrue(message.hasOptionalFixed32 ());
+    Assert.assertTrue(message.hasOptionalFixed64 ());
+    Assert.assertTrue(message.hasOptionalSfixed32());
+    Assert.assertTrue(message.hasOptionalSfixed64());
+    Assert.assertTrue(message.hasOptionalFloat   ());
+    Assert.assertTrue(message.hasOptionalDouble  ());
+    Assert.assertTrue(message.hasOptionalBool    ());
+    Assert.assertTrue(message.hasOptionalString  ());
+    Assert.assertTrue(message.hasOptionalBytes   ());
+
+    Assert.assertTrue(message.hasOptionalGroup         ());
+    Assert.assertTrue(message.hasOptionalNestedMessage ());
+    Assert.assertTrue(message.hasOptionalForeignMessage());
+    Assert.assertTrue(message.hasOptionalImportMessage ());
+
+    Assert.assertTrue(message.getOptionalGroup         ().hasA());
+    Assert.assertTrue(message.getOptionalNestedMessage ().hasBb());
+    Assert.assertTrue(message.getOptionalForeignMessage().hasC());
+    Assert.assertTrue(message.getOptionalImportMessage ().hasD());
+
+    Assert.assertTrue(message.hasOptionalNestedEnum ());
+    Assert.assertTrue(message.hasOptionalForeignEnum());
+    Assert.assertTrue(message.hasOptionalImportEnum ());
+
+    Assert.assertTrue(message.hasOptionalStringPiece());
+    Assert.assertTrue(message.hasOptionalCord());
+
+    Assert.assertEquals(101  , message.getOptionalInt32   ());
+    Assert.assertEquals(102  , message.getOptionalInt64   ());
+    Assert.assertEquals(103  , message.getOptionalUint32  ());
+    Assert.assertEquals(104  , message.getOptionalUint64  ());
+    Assert.assertEquals(105  , message.getOptionalSint32  ());
+    Assert.assertEquals(106  , message.getOptionalSint64  ());
+    Assert.assertEquals(107  , message.getOptionalFixed32 ());
+    Assert.assertEquals(108  , message.getOptionalFixed64 ());
+    Assert.assertEquals(109  , message.getOptionalSfixed32());
+    Assert.assertEquals(110  , message.getOptionalSfixed64());
+    Assert.assertEquals(111  , message.getOptionalFloat   (), 0.0);
+    Assert.assertEquals(112  , message.getOptionalDouble  (), 0.0);
+    Assert.assertEquals(true , message.getOptionalBool    ());
+    Assert.assertEquals("115", message.getOptionalString  ());
+    Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
+
+    Assert.assertEquals(117, message.getOptionalGroup              ().getA());
+    Assert.assertEquals(118, message.getOptionalNestedMessage      ().getBb());
+    Assert.assertEquals(119, message.getOptionalForeignMessage     ().getC());
+    Assert.assertEquals(120, message.getOptionalImportMessage      ().getD());
+    Assert.assertEquals(126, message.getOptionalPublicImportMessage().getE());
+    Assert.assertEquals(127, message.getOptionalLazyMessage        ().getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
+
+    Assert.assertEquals("124", message.getOptionalStringPiece());
+    Assert.assertEquals("125", message.getOptionalCord());
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(2, message.getRepeatedStringCount  ());
+    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(2, message.getRepeatedCordCount());
+
+    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
+    Assert.assertEquals(202  , message.getRepeatedInt64   (0));
+    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
+    Assert.assertEquals(204  , message.getRepeatedUint64  (0));
+    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
+    Assert.assertEquals(206  , message.getRepeatedSint64  (0));
+    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
+    Assert.assertEquals(208  , message.getRepeatedFixed64 (0));
+    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
+    Assert.assertEquals(210  , message.getRepeatedSfixed64(0));
+    Assert.assertEquals(211  , message.getRepeatedFloat   (0), 0.0);
+    Assert.assertEquals(212  , message.getRepeatedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getRepeatedBool    (0));
+    Assert.assertEquals("215", message.getRepeatedString  (0));
+    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
+    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+    Assert.assertEquals("225", message.getRepeatedCord(0));
+
+    Assert.assertEquals(301  , message.getRepeatedInt32   (1));
+    Assert.assertEquals(302  , message.getRepeatedInt64   (1));
+    Assert.assertEquals(303  , message.getRepeatedUint32  (1));
+    Assert.assertEquals(304  , message.getRepeatedUint64  (1));
+    Assert.assertEquals(305  , message.getRepeatedSint32  (1));
+    Assert.assertEquals(306  , message.getRepeatedSint64  (1));
+    Assert.assertEquals(307  , message.getRepeatedFixed32 (1));
+    Assert.assertEquals(308  , message.getRepeatedFixed64 (1));
+    Assert.assertEquals(309  , message.getRepeatedSfixed32(1));
+    Assert.assertEquals(310  , message.getRepeatedSfixed64(1));
+    Assert.assertEquals(311  , message.getRepeatedFloat   (1), 0.0);
+    Assert.assertEquals(312  , message.getRepeatedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getRepeatedBool    (1));
+    Assert.assertEquals("315", message.getRepeatedString  (1));
+    Assert.assertEquals(toBytes("316"), message.getRepeatedBytes(1));
+
+    Assert.assertEquals(317, message.getRepeatedGroup         (1).getA());
+    Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
+    Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
+    Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
+    Assert.assertEquals(327, message.getRepeatedLazyMessage   (1).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
+    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnum(1));
+
+    Assert.assertEquals("324", message.getRepeatedStringPiece(1));
+    Assert.assertEquals("325", message.getRepeatedCord(1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasDefaultInt32   ());
+    Assert.assertTrue(message.hasDefaultInt64   ());
+    Assert.assertTrue(message.hasDefaultUint32  ());
+    Assert.assertTrue(message.hasDefaultUint64  ());
+    Assert.assertTrue(message.hasDefaultSint32  ());
+    Assert.assertTrue(message.hasDefaultSint64  ());
+    Assert.assertTrue(message.hasDefaultFixed32 ());
+    Assert.assertTrue(message.hasDefaultFixed64 ());
+    Assert.assertTrue(message.hasDefaultSfixed32());
+    Assert.assertTrue(message.hasDefaultSfixed64());
+    Assert.assertTrue(message.hasDefaultFloat   ());
+    Assert.assertTrue(message.hasDefaultDouble  ());
+    Assert.assertTrue(message.hasDefaultBool    ());
+    Assert.assertTrue(message.hasDefaultString  ());
+    Assert.assertTrue(message.hasDefaultBytes   ());
+
+    Assert.assertTrue(message.hasDefaultNestedEnum ());
+    Assert.assertTrue(message.hasDefaultForeignEnum());
+    Assert.assertTrue(message.hasDefaultImportEnum ());
+
+    Assert.assertTrue(message.hasDefaultStringPiece());
+    Assert.assertTrue(message.hasDefaultCord());
+
+    Assert.assertEquals(401  , message.getDefaultInt32   ());
+    Assert.assertEquals(402  , message.getDefaultInt64   ());
+    Assert.assertEquals(403  , message.getDefaultUint32  ());
+    Assert.assertEquals(404  , message.getDefaultUint64  ());
+    Assert.assertEquals(405  , message.getDefaultSint32  ());
+    Assert.assertEquals(406  , message.getDefaultSint64  ());
+    Assert.assertEquals(407  , message.getDefaultFixed32 ());
+    Assert.assertEquals(408  , message.getDefaultFixed64 ());
+    Assert.assertEquals(409  , message.getDefaultSfixed32());
+    Assert.assertEquals(410  , message.getDefaultSfixed64());
+    Assert.assertEquals(411  , message.getDefaultFloat   (), 0.0);
+    Assert.assertEquals(412  , message.getDefaultDouble  (), 0.0);
+    Assert.assertEquals(false, message.getDefaultBool    ());
+    Assert.assertEquals("415", message.getDefaultString  ());
+    Assert.assertEquals(toBytes("416"), message.getDefaultBytes());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
+
+    Assert.assertEquals("424", message.getDefaultStringPiece());
+    Assert.assertEquals("425", message.getDefaultCord());
+
+    Assert.assertEquals(TestAllTypes.OneofFieldCase.ONEOF_BYTES, message.getOneofFieldCase());
+    Assert.assertFalse(message.hasOneofUint32());
+    Assert.assertFalse(message.hasOneofNestedMessage());
+    Assert.assertFalse(message.hasOneofString());
+    Assert.assertTrue(message.hasOneofBytes());
+
+    Assert.assertEquals(toBytes("604"), message.getOneofBytes());
+  }
+
+  // -------------------------------------------------------------------
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are cleared, and that getting the fields returns their
+   * default values.
+   */
+  public static void assertClear(TestAllTypesOrBuilder message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasOptionalInt32   ());
+    Assert.assertFalse(message.hasOptionalInt64   ());
+    Assert.assertFalse(message.hasOptionalUint32  ());
+    Assert.assertFalse(message.hasOptionalUint64  ());
+    Assert.assertFalse(message.hasOptionalSint32  ());
+    Assert.assertFalse(message.hasOptionalSint64  ());
+    Assert.assertFalse(message.hasOptionalFixed32 ());
+    Assert.assertFalse(message.hasOptionalFixed64 ());
+    Assert.assertFalse(message.hasOptionalSfixed32());
+    Assert.assertFalse(message.hasOptionalSfixed64());
+    Assert.assertFalse(message.hasOptionalFloat   ());
+    Assert.assertFalse(message.hasOptionalDouble  ());
+    Assert.assertFalse(message.hasOptionalBool    ());
+    Assert.assertFalse(message.hasOptionalString  ());
+    Assert.assertFalse(message.hasOptionalBytes   ());
+
+    Assert.assertFalse(message.hasOptionalGroup         ());
+    Assert.assertFalse(message.hasOptionalNestedMessage ());
+    Assert.assertFalse(message.hasOptionalForeignMessage());
+    Assert.assertFalse(message.hasOptionalImportMessage ());
+
+    Assert.assertFalse(message.hasOptionalNestedEnum ());
+    Assert.assertFalse(message.hasOptionalForeignEnum());
+    Assert.assertFalse(message.hasOptionalImportEnum ());
+
+    Assert.assertFalse(message.hasOptionalStringPiece());
+    Assert.assertFalse(message.hasOptionalCord());
+
+    // Optional fields without defaults are set to zero or something like it.
+    Assert.assertEquals(0    , message.getOptionalInt32   ());
+    Assert.assertEquals(0    , message.getOptionalInt64   ());
+    Assert.assertEquals(0    , message.getOptionalUint32  ());
+    Assert.assertEquals(0    , message.getOptionalUint64  ());
+    Assert.assertEquals(0    , message.getOptionalSint32  ());
+    Assert.assertEquals(0    , message.getOptionalSint64  ());
+    Assert.assertEquals(0    , message.getOptionalFixed32 ());
+    Assert.assertEquals(0    , message.getOptionalFixed64 ());
+    Assert.assertEquals(0    , message.getOptionalSfixed32());
+    Assert.assertEquals(0    , message.getOptionalSfixed64());
+    Assert.assertEquals(0    , message.getOptionalFloat   (), 0.0);
+    Assert.assertEquals(0    , message.getOptionalDouble  (), 0.0);
+    Assert.assertEquals(false, message.getOptionalBool    ());
+    Assert.assertEquals(""   , message.getOptionalString  ());
+    Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getOptionalGroup              ().hasA());
+    Assert.assertFalse(message.getOptionalNestedMessage      ().hasBb());
+    Assert.assertFalse(message.getOptionalForeignMessage     ().hasC());
+    Assert.assertFalse(message.getOptionalImportMessage      ().hasD());
+    Assert.assertFalse(message.getOptionalPublicImportMessage().hasE());
+    Assert.assertFalse(message.getOptionalLazyMessage        ().hasBb());
+
+    Assert.assertEquals(0, message.getOptionalGroup              ().getA());
+    Assert.assertEquals(0, message.getOptionalNestedMessage      ().getBb());
+    Assert.assertEquals(0, message.getOptionalForeignMessage     ().getC());
+    Assert.assertEquals(0, message.getOptionalImportMessage      ().getD());
+    Assert.assertEquals(0, message.getOptionalPublicImportMessage().getE());
+    Assert.assertEquals(0, message.getOptionalLazyMessage        ().getBb());
+
+    // Enums without defaults are set to the first value in the enum.
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getOptionalForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getOptionalImportEnum());
+
+    Assert.assertEquals("", message.getOptionalStringPiece());
+    Assert.assertEquals("", message.getOptionalCord());
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(0, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(0, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(0, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(0, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(0, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(0, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(0, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(0, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(0, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(0, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(0, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(0, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(0, message.getRepeatedStringCount  ());
+    Assert.assertEquals(0, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(0, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(0, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(0, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(0, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(0, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(0, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(0, message.getRepeatedCordCount());
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasDefaultInt32   ());
+    Assert.assertFalse(message.hasDefaultInt64   ());
+    Assert.assertFalse(message.hasDefaultUint32  ());
+    Assert.assertFalse(message.hasDefaultUint64  ());
+    Assert.assertFalse(message.hasDefaultSint32  ());
+    Assert.assertFalse(message.hasDefaultSint64  ());
+    Assert.assertFalse(message.hasDefaultFixed32 ());
+    Assert.assertFalse(message.hasDefaultFixed64 ());
+    Assert.assertFalse(message.hasDefaultSfixed32());
+    Assert.assertFalse(message.hasDefaultSfixed64());
+    Assert.assertFalse(message.hasDefaultFloat   ());
+    Assert.assertFalse(message.hasDefaultDouble  ());
+    Assert.assertFalse(message.hasDefaultBool    ());
+    Assert.assertFalse(message.hasDefaultString  ());
+    Assert.assertFalse(message.hasDefaultBytes   ());
+
+    Assert.assertFalse(message.hasDefaultNestedEnum ());
+    Assert.assertFalse(message.hasDefaultForeignEnum());
+    Assert.assertFalse(message.hasDefaultImportEnum ());
+
+    Assert.assertFalse(message.hasDefaultStringPiece());
+    Assert.assertFalse(message.hasDefaultCord());
+
+    // Fields with defaults have their default values (duh).
+    Assert.assertEquals( 41    , message.getDefaultInt32   ());
+    Assert.assertEquals( 42    , message.getDefaultInt64   ());
+    Assert.assertEquals( 43    , message.getDefaultUint32  ());
+    Assert.assertEquals( 44    , message.getDefaultUint64  ());
+    Assert.assertEquals(-45    , message.getDefaultSint32  ());
+    Assert.assertEquals( 46    , message.getDefaultSint64  ());
+    Assert.assertEquals( 47    , message.getDefaultFixed32 ());
+    Assert.assertEquals( 48    , message.getDefaultFixed64 ());
+    Assert.assertEquals( 49    , message.getDefaultSfixed32());
+    Assert.assertEquals(-50    , message.getDefaultSfixed64());
+    Assert.assertEquals( 51.5  , message.getDefaultFloat   (), 0.0);
+    Assert.assertEquals( 52e3  , message.getDefaultDouble  (), 0.0);
+    Assert.assertEquals(true   , message.getDefaultBool    ());
+    Assert.assertEquals("hello", message.getDefaultString  ());
+    Assert.assertEquals(toBytes("world"), message.getDefaultBytes());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
+
+    Assert.assertEquals("abc", message.getDefaultStringPiece());
+    Assert.assertEquals("123", message.getDefaultCord());
+
+    Assert.assertFalse(message.hasOneofUint32());
+    Assert.assertFalse(message.hasOneofNestedMessage());
+    Assert.assertFalse(message.hasOneofString());
+    Assert.assertFalse(message.hasOneofBytes());
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setAllFields}
+   * followed by {@code modifyRepeatedFields}.
+   */
+  public static void assertRepeatedFieldsModified(
+      TestAllTypesOrBuilder message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
+    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
+    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
+    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
+    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
+    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
+    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
+    Assert.assertEquals(2, message.getRepeatedStringCount  ());
+    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
+
+    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
+    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
+    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
+    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
+    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
+
+    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+    Assert.assertEquals(2, message.getRepeatedCordCount());
+
+    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
+    Assert.assertEquals(202L , message.getRepeatedInt64   (0));
+    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
+    Assert.assertEquals(204L , message.getRepeatedUint64  (0));
+    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
+    Assert.assertEquals(206L , message.getRepeatedSint64  (0));
+    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
+    Assert.assertEquals(208L , message.getRepeatedFixed64 (0));
+    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
+    Assert.assertEquals(210L , message.getRepeatedSfixed64(0));
+    Assert.assertEquals(211F , message.getRepeatedFloat   (0));
+    Assert.assertEquals(212D , message.getRepeatedDouble  (0));
+    Assert.assertEquals(true , message.getRepeatedBool    (0));
+    Assert.assertEquals("215", message.getRepeatedString  (0));
+    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
+    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+    Assert.assertEquals("225", message.getRepeatedCord(0));
+
+    // Actually verify the second (modified) elements now.
+    Assert.assertEquals(501  , message.getRepeatedInt32   (1));
+    Assert.assertEquals(502L , message.getRepeatedInt64   (1));
+    Assert.assertEquals(503  , message.getRepeatedUint32  (1));
+    Assert.assertEquals(504L , message.getRepeatedUint64  (1));
+    Assert.assertEquals(505  , message.getRepeatedSint32  (1));
+    Assert.assertEquals(506L , message.getRepeatedSint64  (1));
+    Assert.assertEquals(507  , message.getRepeatedFixed32 (1));
+    Assert.assertEquals(508L , message.getRepeatedFixed64 (1));
+    Assert.assertEquals(509  , message.getRepeatedSfixed32(1));
+    Assert.assertEquals(510L , message.getRepeatedSfixed64(1));
+    Assert.assertEquals(511F , message.getRepeatedFloat   (1));
+    Assert.assertEquals(512D , message.getRepeatedDouble  (1));
+    Assert.assertEquals(true , message.getRepeatedBool    (1));
+    Assert.assertEquals("515", message.getRepeatedString  (1));
+    Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
+
+    Assert.assertEquals(517, message.getRepeatedGroup         (1).getA());
+    Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
+    Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
+    Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
+    Assert.assertEquals(527, message.getRepeatedLazyMessage   (1).getBb());
+
+    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
+    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnum(1));
+
+    Assert.assertEquals("524", message.getRepeatedStringPiece(1));
+    Assert.assertEquals("525", message.getRepeatedCord(1));
+  }
+
+  /**
+   * Set every field of {@code message} to a unique value.
+   */
+  public static void setPackedFields(TestPackedTypes.Builder message) {
+    message.addPackedInt32   (601);
+    message.addPackedInt64   (602);
+    message.addPackedUint32  (603);
+    message.addPackedUint64  (604);
+    message.addPackedSint32  (605);
+    message.addPackedSint64  (606);
+    message.addPackedFixed32 (607);
+    message.addPackedFixed64 (608);
+    message.addPackedSfixed32(609);
+    message.addPackedSfixed64(610);
+    message.addPackedFloat   (611);
+    message.addPackedDouble  (612);
+    message.addPackedBool    (true);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addPackedInt32   (701);
+    message.addPackedInt64   (702);
+    message.addPackedUint32  (703);
+    message.addPackedUint64  (704);
+    message.addPackedSint32  (705);
+    message.addPackedSint64  (706);
+    message.addPackedFixed32 (707);
+    message.addPackedFixed64 (708);
+    message.addPackedSfixed32(709);
+    message.addPackedSfixed64(710);
+    message.addPackedFloat   (711);
+    message.addPackedDouble  (712);
+    message.addPackedBool    (false);
+    message.addPackedEnum    (ForeignEnum.FOREIGN_BAZ);
+  }
+
+  /**
+   * Set every field of {@code message} to a unique value. Must correspond with
+   * the values applied by {@code setPackedFields}.
+   */
+  public static void setUnpackedFields(TestUnpackedTypes.Builder message) {
+    message.addUnpackedInt32   (601);
+    message.addUnpackedInt64   (602);
+    message.addUnpackedUint32  (603);
+    message.addUnpackedUint64  (604);
+    message.addUnpackedSint32  (605);
+    message.addUnpackedSint64  (606);
+    message.addUnpackedFixed32 (607);
+    message.addUnpackedFixed64 (608);
+    message.addUnpackedSfixed32(609);
+    message.addUnpackedSfixed64(610);
+    message.addUnpackedFloat   (611);
+    message.addUnpackedDouble  (612);
+    message.addUnpackedBool    (true);
+    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addUnpackedInt32   (701);
+    message.addUnpackedInt64   (702);
+    message.addUnpackedUint32  (703);
+    message.addUnpackedUint64  (704);
+    message.addUnpackedSint32  (705);
+    message.addUnpackedSint64  (706);
+    message.addUnpackedFixed32 (707);
+    message.addUnpackedFixed64 (708);
+    message.addUnpackedSfixed32(709);
+    message.addUnpackedSfixed64(710);
+    message.addUnpackedFloat   (711);
+    message.addUnpackedDouble  (712);
+    message.addUnpackedBool    (false);
+    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAZ);
+  }
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setPackedFields}.
+   */
+  public static void assertPackedFieldsSet(TestPackedTypes message) {
+    Assert.assertEquals(2, message.getPackedInt32Count   ());
+    Assert.assertEquals(2, message.getPackedInt64Count   ());
+    Assert.assertEquals(2, message.getPackedUint32Count  ());
+    Assert.assertEquals(2, message.getPackedUint64Count  ());
+    Assert.assertEquals(2, message.getPackedSint32Count  ());
+    Assert.assertEquals(2, message.getPackedSint64Count  ());
+    Assert.assertEquals(2, message.getPackedFixed32Count ());
+    Assert.assertEquals(2, message.getPackedFixed64Count ());
+    Assert.assertEquals(2, message.getPackedSfixed32Count());
+    Assert.assertEquals(2, message.getPackedSfixed64Count());
+    Assert.assertEquals(2, message.getPackedFloatCount   ());
+    Assert.assertEquals(2, message.getPackedDoubleCount  ());
+    Assert.assertEquals(2, message.getPackedBoolCount    ());
+    Assert.assertEquals(2, message.getPackedEnumCount   ());
+    Assert.assertEquals(601  , message.getPackedInt32   (0));
+    Assert.assertEquals(602  , message.getPackedInt64   (0));
+    Assert.assertEquals(603  , message.getPackedUint32  (0));
+    Assert.assertEquals(604  , message.getPackedUint64  (0));
+    Assert.assertEquals(605  , message.getPackedSint32  (0));
+    Assert.assertEquals(606  , message.getPackedSint64  (0));
+    Assert.assertEquals(607  , message.getPackedFixed32 (0));
+    Assert.assertEquals(608  , message.getPackedFixed64 (0));
+    Assert.assertEquals(609  , message.getPackedSfixed32(0));
+    Assert.assertEquals(610  , message.getPackedSfixed64(0));
+    Assert.assertEquals(611  , message.getPackedFloat   (0), 0.0);
+    Assert.assertEquals(612  , message.getPackedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getPackedBool    (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
+    Assert.assertEquals(701  , message.getPackedInt32   (1));
+    Assert.assertEquals(702  , message.getPackedInt64   (1));
+    Assert.assertEquals(703  , message.getPackedUint32  (1));
+    Assert.assertEquals(704  , message.getPackedUint64  (1));
+    Assert.assertEquals(705  , message.getPackedSint32  (1));
+    Assert.assertEquals(706  , message.getPackedSint64  (1));
+    Assert.assertEquals(707  , message.getPackedFixed32 (1));
+    Assert.assertEquals(708  , message.getPackedFixed64 (1));
+    Assert.assertEquals(709  , message.getPackedSfixed32(1));
+    Assert.assertEquals(710  , message.getPackedSfixed64(1));
+    Assert.assertEquals(711  , message.getPackedFloat   (1), 0.0);
+    Assert.assertEquals(712  , message.getPackedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getPackedBool    (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
+  }
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all fields of
+   * {@code message} are set to the values assigned by {@code setUnpackedFields}.
+   */
+  public static void assertUnpackedFieldsSet(TestUnpackedTypes message) {
+    Assert.assertEquals(2, message.getUnpackedInt32Count   ());
+    Assert.assertEquals(2, message.getUnpackedInt64Count   ());
+    Assert.assertEquals(2, message.getUnpackedUint32Count  ());
+    Assert.assertEquals(2, message.getUnpackedUint64Count  ());
+    Assert.assertEquals(2, message.getUnpackedSint32Count  ());
+    Assert.assertEquals(2, message.getUnpackedSint64Count  ());
+    Assert.assertEquals(2, message.getUnpackedFixed32Count ());
+    Assert.assertEquals(2, message.getUnpackedFixed64Count ());
+    Assert.assertEquals(2, message.getUnpackedSfixed32Count());
+    Assert.assertEquals(2, message.getUnpackedSfixed64Count());
+    Assert.assertEquals(2, message.getUnpackedFloatCount   ());
+    Assert.assertEquals(2, message.getUnpackedDoubleCount  ());
+    Assert.assertEquals(2, message.getUnpackedBoolCount    ());
+    Assert.assertEquals(2, message.getUnpackedEnumCount   ());
+    Assert.assertEquals(601  , message.getUnpackedInt32   (0));
+    Assert.assertEquals(602  , message.getUnpackedInt64   (0));
+    Assert.assertEquals(603  , message.getUnpackedUint32  (0));
+    Assert.assertEquals(604  , message.getUnpackedUint64  (0));
+    Assert.assertEquals(605  , message.getUnpackedSint32  (0));
+    Assert.assertEquals(606  , message.getUnpackedSint64  (0));
+    Assert.assertEquals(607  , message.getUnpackedFixed32 (0));
+    Assert.assertEquals(608  , message.getUnpackedFixed64 (0));
+    Assert.assertEquals(609  , message.getUnpackedSfixed32(0));
+    Assert.assertEquals(610  , message.getUnpackedSfixed64(0));
+    Assert.assertEquals(611  , message.getUnpackedFloat   (0), 0.0);
+    Assert.assertEquals(612  , message.getUnpackedDouble  (0), 0.0);
+    Assert.assertEquals(true , message.getUnpackedBool    (0));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getUnpackedEnum(0));
+    Assert.assertEquals(701  , message.getUnpackedInt32   (1));
+    Assert.assertEquals(702  , message.getUnpackedInt64   (1));
+    Assert.assertEquals(703  , message.getUnpackedUint32  (1));
+    Assert.assertEquals(704  , message.getUnpackedUint64  (1));
+    Assert.assertEquals(705  , message.getUnpackedSint32  (1));
+    Assert.assertEquals(706  , message.getUnpackedSint64  (1));
+    Assert.assertEquals(707  , message.getUnpackedFixed32 (1));
+    Assert.assertEquals(708  , message.getUnpackedFixed64 (1));
+    Assert.assertEquals(709  , message.getUnpackedSfixed32(1));
+    Assert.assertEquals(710  , message.getUnpackedSfixed64(1));
+    Assert.assertEquals(711  , message.getUnpackedFloat   (1), 0.0);
+    Assert.assertEquals(712  , message.getUnpackedDouble  (1), 0.0);
+    Assert.assertEquals(false, message.getUnpackedBool    (1));
+    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getUnpackedEnum(1));
+  }
+
+  // ===================================================================
+  // Like above, but for extensions
+
+  // Java gets confused with things like assertEquals(int, Integer):  it can't
+  // decide whether to call assertEquals(int, int) or assertEquals(Object,
+  // Object).  So we define these methods to help it.
+  private static void assertEqualsExactType(int a, int b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(long a, long b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(float a, float b) {
+    Assert.assertEquals(a, b, 0.0);
+  }
+  private static void assertEqualsExactType(double a, double b) {
+    Assert.assertEquals(a, b, 0.0);
+  }
+  private static void assertEqualsExactType(boolean a, boolean b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(String a, String b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ByteString a, ByteString b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
+                                            TestAllTypes.NestedEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(TestAllTypesLite.NestedEnum a,
+                                            TestAllTypesLite.NestedEnum b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ForeignEnumLite a,
+                                            ForeignEnumLite b) {
+    Assert.assertEquals(a, b);
+  }
+  private static void assertEqualsExactType(ImportEnumLite a,
+                                            ImportEnumLite b) {
+    Assert.assertEquals(a, b);
+  }
+
+  /**
+   * Get an unmodifiable {@link ExtensionRegistry} containing all the
+   * extensions of {@code TestAllExtensions}.
+   */
+  public static ExtensionRegistry getExtensionRegistry() {
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    registerAllExtensions(registry);
+    return registry.getUnmodifiable();
+  }
+
+  /**
+   * Register all of {@code TestAllExtensions}'s extensions with the
+   * given {@link ExtensionRegistry}.
+   */
+  public static void registerAllExtensions(ExtensionRegistry registry) {
+    UnittestProto.registerAllExtensions(registry);
+    TestUtilLite.registerAllExtensionsLite(registry);
+  }
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllExtensionsSet()}.
+   */
+  public static void setAllExtensions(TestAllExtensions.Builder message) {
+    message.setExtension(optionalInt32Extension   , 101);
+    message.setExtension(optionalInt64Extension   , 102L);
+    message.setExtension(optionalUint32Extension  , 103);
+    message.setExtension(optionalUint64Extension  , 104L);
+    message.setExtension(optionalSint32Extension  , 105);
+    message.setExtension(optionalSint64Extension  , 106L);
+    message.setExtension(optionalFixed32Extension , 107);
+    message.setExtension(optionalFixed64Extension , 108L);
+    message.setExtension(optionalSfixed32Extension, 109);
+    message.setExtension(optionalSfixed64Extension, 110L);
+    message.setExtension(optionalFloatExtension   , 111F);
+    message.setExtension(optionalDoubleExtension  , 112D);
+    message.setExtension(optionalBoolExtension    , true);
+    message.setExtension(optionalStringExtension  , "115");
+    message.setExtension(optionalBytesExtension   , toBytes("116"));
+
+    message.setExtension(optionalGroupExtension,
+      OptionalGroup_extension.newBuilder().setA(117).build());
+    message.setExtension(optionalNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+    message.setExtension(optionalForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(119).build());
+    message.setExtension(optionalImportMessageExtension,
+      ImportMessage.newBuilder().setD(120).build());
+    message.setExtension(optionalPublicImportMessageExtension,
+      PublicImportMessage.newBuilder().setE(126).build());
+    message.setExtension(optionalLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+    message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+    message.setExtension(optionalImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+    message.setExtension(optionalStringPieceExtension, "124");
+    message.setExtension(optionalCordExtension, "125");
+
+    // -----------------------------------------------------------------
+
+    message.addExtension(repeatedInt32Extension   , 201);
+    message.addExtension(repeatedInt64Extension   , 202L);
+    message.addExtension(repeatedUint32Extension  , 203);
+    message.addExtension(repeatedUint64Extension  , 204L);
+    message.addExtension(repeatedSint32Extension  , 205);
+    message.addExtension(repeatedSint64Extension  , 206L);
+    message.addExtension(repeatedFixed32Extension , 207);
+    message.addExtension(repeatedFixed64Extension , 208L);
+    message.addExtension(repeatedSfixed32Extension, 209);
+    message.addExtension(repeatedSfixed64Extension, 210L);
+    message.addExtension(repeatedFloatExtension   , 211F);
+    message.addExtension(repeatedDoubleExtension  , 212D);
+    message.addExtension(repeatedBoolExtension    , true);
+    message.addExtension(repeatedStringExtension  , "215");
+    message.addExtension(repeatedBytesExtension   , toBytes("216"));
+
+    message.addExtension(repeatedGroupExtension,
+      RepeatedGroup_extension.newBuilder().setA(217).build());
+    message.addExtension(repeatedNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+    message.addExtension(repeatedForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(219).build());
+    message.addExtension(repeatedImportMessageExtension,
+      ImportMessage.newBuilder().setD(220).build());
+    message.addExtension(repeatedLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR);
+    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR);
+    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAR);
+
+    message.addExtension(repeatedStringPieceExtension, "224");
+    message.addExtension(repeatedCordExtension, "225");
+
+    // Add a second one of each field.
+    message.addExtension(repeatedInt32Extension   , 301);
+    message.addExtension(repeatedInt64Extension   , 302L);
+    message.addExtension(repeatedUint32Extension  , 303);
+    message.addExtension(repeatedUint64Extension  , 304L);
+    message.addExtension(repeatedSint32Extension  , 305);
+    message.addExtension(repeatedSint64Extension  , 306L);
+    message.addExtension(repeatedFixed32Extension , 307);
+    message.addExtension(repeatedFixed64Extension , 308L);
+    message.addExtension(repeatedSfixed32Extension, 309);
+    message.addExtension(repeatedSfixed64Extension, 310L);
+    message.addExtension(repeatedFloatExtension   , 311F);
+    message.addExtension(repeatedDoubleExtension  , 312D);
+    message.addExtension(repeatedBoolExtension    , false);
+    message.addExtension(repeatedStringExtension  , "315");
+    message.addExtension(repeatedBytesExtension   , toBytes("316"));
+
+    message.addExtension(repeatedGroupExtension,
+      RepeatedGroup_extension.newBuilder().setA(317).build());
+    message.addExtension(repeatedNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+    message.addExtension(repeatedForeignMessageExtension,
+      ForeignMessage.newBuilder().setC(319).build());
+    message.addExtension(repeatedImportMessageExtension,
+      ImportMessage.newBuilder().setD(320).build());
+    message.addExtension(repeatedLazyMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+    message.addExtension(repeatedStringPieceExtension, "324");
+    message.addExtension(repeatedCordExtension, "325");
+
+    // -----------------------------------------------------------------
+
+    message.setExtension(defaultInt32Extension   , 401);
+    message.setExtension(defaultInt64Extension   , 402L);
+    message.setExtension(defaultUint32Extension  , 403);
+    message.setExtension(defaultUint64Extension  , 404L);
+    message.setExtension(defaultSint32Extension  , 405);
+    message.setExtension(defaultSint64Extension  , 406L);
+    message.setExtension(defaultFixed32Extension , 407);
+    message.setExtension(defaultFixed64Extension , 408L);
+    message.setExtension(defaultSfixed32Extension, 409);
+    message.setExtension(defaultSfixed64Extension, 410L);
+    message.setExtension(defaultFloatExtension   , 411F);
+    message.setExtension(defaultDoubleExtension  , 412D);
+    message.setExtension(defaultBoolExtension    , false);
+    message.setExtension(defaultStringExtension  , "415");
+    message.setExtension(defaultBytesExtension   , toBytes("416"));
+
+    message.setExtension(defaultNestedEnumExtension, TestAllTypes.NestedEnum.FOO);
+    message.setExtension(defaultForeignEnumExtension, ForeignEnum.FOREIGN_FOO);
+    message.setExtension(defaultImportEnumExtension, ImportEnum.IMPORT_FOO);
+
+    message.setExtension(defaultStringPieceExtension, "424");
+    message.setExtension(defaultCordExtension, "425");
+
+    message.setExtension(oneofUint32Extension, 601);
+    message.setExtension(oneofNestedMessageExtension,
+      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
+    message.setExtension(oneofStringExtension, "603");
+    message.setExtension(oneofBytesExtension, toBytes("604"));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated extensions of {@code message} to contain the values
+   * expected by {@code assertRepeatedExtensionsModified()}.
+   */
+  public static void modifyRepeatedExtensions(
+      TestAllExtensions.Builder message) {
+    message.setExtension(repeatedInt32Extension   , 1, 501);
+    message.setExtension(repeatedInt64Extension   , 1, 502L);
+    message.setExtension(repeatedUint32Extension  , 1, 503);
+    message.setExtension(repeatedUint64Extension  , 1, 504L);
+    message.setExtension(repeatedSint32Extension  , 1, 505);
+    message.setExtension(repeatedSint64Extension  , 1, 506L);
+    message.setExtension(repeatedFixed32Extension , 1, 507);
+    message.setExtension(repeatedFixed64Extension , 1, 508L);
+    message.setExtension(repeatedSfixed32Extension, 1, 509);
+    message.setExtension(repeatedSfixed64Extension, 1, 510L);
+    message.setExtension(repeatedFloatExtension   , 1, 511F);
+    message.setExtension(repeatedDoubleExtension  , 1, 512D);
+    message.setExtension(repeatedBoolExtension    , 1, true);
+    message.setExtension(repeatedStringExtension  , 1, "515");
+    message.setExtension(repeatedBytesExtension   , 1, toBytes("516"));
+
+    message.setExtension(repeatedGroupExtension, 1,
+      RepeatedGroup_extension.newBuilder().setA(517).build());
+    message.setExtension(repeatedNestedMessageExtension, 1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+    message.setExtension(repeatedForeignMessageExtension, 1,
+      ForeignMessage.newBuilder().setC(519).build());
+    message.setExtension(repeatedImportMessageExtension, 1,
+      ImportMessage.newBuilder().setD(520).build());
+    message.setExtension(repeatedLazyMessageExtension, 1,
+      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO);
+    message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO);
+    message.setExtension(repeatedImportEnumExtension , 1, ImportEnum.IMPORT_FOO);
+
+    message.setExtension(repeatedStringPieceExtension, 1, "524");
+    message.setExtension(repeatedCordExtension, 1, "525");
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}.
+   */
+  public static void assertAllExtensionsSet(
+      TestAllExtensionsOrBuilder message) {
+    Assert.assertTrue(message.hasExtension(optionalInt32Extension   ));
+    Assert.assertTrue(message.hasExtension(optionalInt64Extension   ));
+    Assert.assertTrue(message.hasExtension(optionalUint32Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalUint64Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalSint32Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalSint64Extension  ));
+    Assert.assertTrue(message.hasExtension(optionalFixed32Extension ));
+    Assert.assertTrue(message.hasExtension(optionalFixed64Extension ));
+    Assert.assertTrue(message.hasExtension(optionalSfixed32Extension));
+    Assert.assertTrue(message.hasExtension(optionalSfixed64Extension));
+    Assert.assertTrue(message.hasExtension(optionalFloatExtension   ));
+    Assert.assertTrue(message.hasExtension(optionalDoubleExtension  ));
+    Assert.assertTrue(message.hasExtension(optionalBoolExtension    ));
+    Assert.assertTrue(message.hasExtension(optionalStringExtension  ));
+    Assert.assertTrue(message.hasExtension(optionalBytesExtension   ));
+
+    Assert.assertTrue(message.hasExtension(optionalGroupExtension         ));
+    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtension ));
+    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtension));
+    Assert.assertTrue(message.hasExtension(optionalImportMessageExtension ));
+
+    Assert.assertTrue(message.getExtension(optionalGroupExtension         ).hasA());
+    Assert.assertTrue(message.getExtension(optionalNestedMessageExtension ).hasBb());
+    Assert.assertTrue(message.getExtension(optionalForeignMessageExtension).hasC());
+    Assert.assertTrue(message.getExtension(optionalImportMessageExtension ).hasD());
+
+    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtension ));
+    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtension));
+    Assert.assertTrue(message.hasExtension(optionalImportEnumExtension ));
+
+    Assert.assertTrue(message.hasExtension(optionalStringPieceExtension));
+    Assert.assertTrue(message.hasExtension(optionalCordExtension));
+
+    assertEqualsExactType(101  , message.getExtension(optionalInt32Extension   ));
+    assertEqualsExactType(102L , message.getExtension(optionalInt64Extension   ));
+    assertEqualsExactType(103  , message.getExtension(optionalUint32Extension  ));
+    assertEqualsExactType(104L , message.getExtension(optionalUint64Extension  ));
+    assertEqualsExactType(105  , message.getExtension(optionalSint32Extension  ));
+    assertEqualsExactType(106L , message.getExtension(optionalSint64Extension  ));
+    assertEqualsExactType(107  , message.getExtension(optionalFixed32Extension ));
+    assertEqualsExactType(108L , message.getExtension(optionalFixed64Extension ));
+    assertEqualsExactType(109  , message.getExtension(optionalSfixed32Extension));
+    assertEqualsExactType(110L , message.getExtension(optionalSfixed64Extension));
+    assertEqualsExactType(111F , message.getExtension(optionalFloatExtension   ));
+    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtension  ));
+    assertEqualsExactType(true , message.getExtension(optionalBoolExtension    ));
+    assertEqualsExactType("115", message.getExtension(optionalStringExtension  ));
+    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension));
+
+    assertEqualsExactType(117, message.getExtension(optionalGroupExtension              ).getA());
+    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension      ).getBb());
+    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension     ).getC());
+    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension      ).getD());
+    assertEqualsExactType(126, message.getExtension(optionalPublicImportMessageExtension).getE());
+    assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtension        ).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+      message.getExtension(optionalNestedEnumExtension));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+      message.getExtension(optionalForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+      message.getExtension(optionalImportEnumExtension));
+
+    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtension));
+    assertEqualsExactType("125", message.getExtension(optionalCordExtension));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtension, 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(repeatedForeignEnumExtension, 0));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(repeatedImportEnumExtension, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+    assertEqualsExactType(301  , message.getExtension(repeatedInt32Extension   , 1));
+    assertEqualsExactType(302L , message.getExtension(repeatedInt64Extension   , 1));
+    assertEqualsExactType(303  , message.getExtension(repeatedUint32Extension  , 1));
+    assertEqualsExactType(304L , message.getExtension(repeatedUint64Extension  , 1));
+    assertEqualsExactType(305  , message.getExtension(repeatedSint32Extension  , 1));
+    assertEqualsExactType(306L , message.getExtension(repeatedSint64Extension  , 1));
+    assertEqualsExactType(307  , message.getExtension(repeatedFixed32Extension , 1));
+    assertEqualsExactType(308L , message.getExtension(repeatedFixed64Extension , 1));
+    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32Extension, 1));
+    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64Extension, 1));
+    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtension   , 1));
+    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtension  , 1));
+    assertEqualsExactType(false, message.getExtension(repeatedBoolExtension    , 1));
+    assertEqualsExactType("315", message.getExtension(repeatedStringExtension  , 1));
+    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtension, 1));
+
+    assertEqualsExactType(317, message.getExtension(repeatedGroupExtension         , 1).getA());
+    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD());
+    assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+      message.getExtension(repeatedNestedEnumExtension, 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+      message.getExtension(repeatedForeignEnumExtension, 1));
+    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+      message.getExtension(repeatedImportEnumExtension, 1));
+
+    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtension, 1));
+    assertEqualsExactType("325", message.getExtension(repeatedCordExtension, 1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasExtension(defaultInt32Extension   ));
+    Assert.assertTrue(message.hasExtension(defaultInt64Extension   ));
+    Assert.assertTrue(message.hasExtension(defaultUint32Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultUint64Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultSint32Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultSint64Extension  ));
+    Assert.assertTrue(message.hasExtension(defaultFixed32Extension ));
+    Assert.assertTrue(message.hasExtension(defaultFixed64Extension ));
+    Assert.assertTrue(message.hasExtension(defaultSfixed32Extension));
+    Assert.assertTrue(message.hasExtension(defaultSfixed64Extension));
+    Assert.assertTrue(message.hasExtension(defaultFloatExtension   ));
+    Assert.assertTrue(message.hasExtension(defaultDoubleExtension  ));
+    Assert.assertTrue(message.hasExtension(defaultBoolExtension    ));
+    Assert.assertTrue(message.hasExtension(defaultStringExtension  ));
+    Assert.assertTrue(message.hasExtension(defaultBytesExtension   ));
+
+    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtension ));
+    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtension));
+    Assert.assertTrue(message.hasExtension(defaultImportEnumExtension ));
+
+    Assert.assertTrue(message.hasExtension(defaultStringPieceExtension));
+    Assert.assertTrue(message.hasExtension(defaultCordExtension));
+
+    assertEqualsExactType(401  , message.getExtension(defaultInt32Extension   ));
+    assertEqualsExactType(402L , message.getExtension(defaultInt64Extension   ));
+    assertEqualsExactType(403  , message.getExtension(defaultUint32Extension  ));
+    assertEqualsExactType(404L , message.getExtension(defaultUint64Extension  ));
+    assertEqualsExactType(405  , message.getExtension(defaultSint32Extension  ));
+    assertEqualsExactType(406L , message.getExtension(defaultSint64Extension  ));
+    assertEqualsExactType(407  , message.getExtension(defaultFixed32Extension ));
+    assertEqualsExactType(408L , message.getExtension(defaultFixed64Extension ));
+    assertEqualsExactType(409  , message.getExtension(defaultSfixed32Extension));
+    assertEqualsExactType(410L , message.getExtension(defaultSfixed64Extension));
+    assertEqualsExactType(411F , message.getExtension(defaultFloatExtension   ));
+    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtension  ));
+    assertEqualsExactType(false, message.getExtension(defaultBoolExtension    ));
+    assertEqualsExactType("415", message.getExtension(defaultStringExtension  ));
+    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtension));
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(defaultNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(defaultForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(defaultImportEnumExtension));
+
+    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
+    assertEqualsExactType("425", message.getExtension(defaultCordExtension));
+
+    Assert.assertTrue(message.hasExtension(oneofBytesExtension));
+
+    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtension));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are cleared, and that getting the extensions returns their
+   * default values.
+   */
+  public static void assertExtensionsClear(TestAllExtensionsOrBuilder message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasExtension(optionalInt32Extension   ));
+    Assert.assertFalse(message.hasExtension(optionalInt64Extension   ));
+    Assert.assertFalse(message.hasExtension(optionalUint32Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalUint64Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalSint32Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalSint64Extension  ));
+    Assert.assertFalse(message.hasExtension(optionalFixed32Extension ));
+    Assert.assertFalse(message.hasExtension(optionalFixed64Extension ));
+    Assert.assertFalse(message.hasExtension(optionalSfixed32Extension));
+    Assert.assertFalse(message.hasExtension(optionalSfixed64Extension));
+    Assert.assertFalse(message.hasExtension(optionalFloatExtension   ));
+    Assert.assertFalse(message.hasExtension(optionalDoubleExtension  ));
+    Assert.assertFalse(message.hasExtension(optionalBoolExtension    ));
+    Assert.assertFalse(message.hasExtension(optionalStringExtension  ));
+    Assert.assertFalse(message.hasExtension(optionalBytesExtension   ));
+
+    Assert.assertFalse(message.hasExtension(optionalGroupExtension         ));
+    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtension ));
+    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtension));
+    Assert.assertFalse(message.hasExtension(optionalImportMessageExtension ));
+
+    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtension ));
+    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtension));
+    Assert.assertFalse(message.hasExtension(optionalImportEnumExtension ));
+
+    Assert.assertFalse(message.hasExtension(optionalStringPieceExtension));
+    Assert.assertFalse(message.hasExtension(optionalCordExtension));
+
+    // Optional fields without defaults are set to zero or something like it.
+    assertEqualsExactType(0    , message.getExtension(optionalInt32Extension   ));
+    assertEqualsExactType(0L   , message.getExtension(optionalInt64Extension   ));
+    assertEqualsExactType(0    , message.getExtension(optionalUint32Extension  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalUint64Extension  ));
+    assertEqualsExactType(0    , message.getExtension(optionalSint32Extension  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalSint64Extension  ));
+    assertEqualsExactType(0    , message.getExtension(optionalFixed32Extension ));
+    assertEqualsExactType(0L   , message.getExtension(optionalFixed64Extension ));
+    assertEqualsExactType(0    , message.getExtension(optionalSfixed32Extension));
+    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64Extension));
+    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtension   ));
+    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtension  ));
+    assertEqualsExactType(false, message.getExtension(optionalBoolExtension    ));
+    assertEqualsExactType(""   , message.getExtension(optionalStringExtension  ));
+    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtension));
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getExtension(optionalGroupExtension         ).hasA());
+    Assert.assertFalse(message.getExtension(optionalNestedMessageExtension ).hasBb());
+    Assert.assertFalse(message.getExtension(optionalForeignMessageExtension).hasC());
+    Assert.assertFalse(message.getExtension(optionalImportMessageExtension ).hasD());
+
+    assertEqualsExactType(0, message.getExtension(optionalGroupExtension         ).getA());
+    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtension ).getBb());
+    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtension).getC());
+    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtension ).getD());
+
+    // Enums without defaults are set to the first value in the enum.
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(optionalNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(optionalForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(optionalImportEnumExtension));
+
+    assertEqualsExactType("", message.getExtension(optionalStringPieceExtension));
+    assertEqualsExactType("", message.getExtension(optionalCordExtension));
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtension));
+
+    // Repeated fields are empty via getExtension().size().
+    Assert.assertEquals(0, message.getExtension(repeatedInt32Extension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedInt64Extension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedUint32Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedUint64Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSint32Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSint64Extension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFixed32Extension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFixed64Extension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSfixed32Extension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedSfixed64Extension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedFloatExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedDoubleExtension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedBoolExtension    ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedStringExtension  ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedBytesExtension   ).size());
+
+    Assert.assertEquals(0, message.getExtension(repeatedGroupExtension         ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedNestedMessageExtension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedForeignMessageExtension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedImportMessageExtension ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedLazyMessageExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedNestedEnumExtension    ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedForeignEnumExtension   ).size());
+    Assert.assertEquals(0, message.getExtension(repeatedImportEnumExtension    ).size());
+
+    Assert.assertEquals(0, message.getExtension(repeatedStringPieceExtension).size());
+    Assert.assertEquals(0, message.getExtension(repeatedCordExtension).size());
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasExtension(defaultInt32Extension   ));
+    Assert.assertFalse(message.hasExtension(defaultInt64Extension   ));
+    Assert.assertFalse(message.hasExtension(defaultUint32Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultUint64Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultSint32Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultSint64Extension  ));
+    Assert.assertFalse(message.hasExtension(defaultFixed32Extension ));
+    Assert.assertFalse(message.hasExtension(defaultFixed64Extension ));
+    Assert.assertFalse(message.hasExtension(defaultSfixed32Extension));
+    Assert.assertFalse(message.hasExtension(defaultSfixed64Extension));
+    Assert.assertFalse(message.hasExtension(defaultFloatExtension   ));
+    Assert.assertFalse(message.hasExtension(defaultDoubleExtension  ));
+    Assert.assertFalse(message.hasExtension(defaultBoolExtension    ));
+    Assert.assertFalse(message.hasExtension(defaultStringExtension  ));
+    Assert.assertFalse(message.hasExtension(defaultBytesExtension   ));
+
+    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtension ));
+    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtension));
+    Assert.assertFalse(message.hasExtension(defaultImportEnumExtension ));
+
+    Assert.assertFalse(message.hasExtension(defaultStringPieceExtension));
+    Assert.assertFalse(message.hasExtension(defaultCordExtension));
+
+    // Fields with defaults have their default values (duh).
+    assertEqualsExactType( 41    , message.getExtension(defaultInt32Extension   ));
+    assertEqualsExactType( 42L   , message.getExtension(defaultInt64Extension   ));
+    assertEqualsExactType( 43    , message.getExtension(defaultUint32Extension  ));
+    assertEqualsExactType( 44L   , message.getExtension(defaultUint64Extension  ));
+    assertEqualsExactType(-45    , message.getExtension(defaultSint32Extension  ));
+    assertEqualsExactType( 46L   , message.getExtension(defaultSint64Extension  ));
+    assertEqualsExactType( 47    , message.getExtension(defaultFixed32Extension ));
+    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64Extension ));
+    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32Extension));
+    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64Extension));
+    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtension   ));
+    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtension  ));
+    assertEqualsExactType(true   , message.getExtension(defaultBoolExtension    ));
+    assertEqualsExactType("hello", message.getExtension(defaultStringExtension  ));
+    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtension));
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(defaultNestedEnumExtension ));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(defaultForeignEnumExtension));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(defaultImportEnumExtension));
+
+    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
+    assertEqualsExactType("123", message.getExtension(defaultCordExtension));
+
+    Assert.assertFalse(message.hasExtension(oneofUint32Extension));
+    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtension));
+    Assert.assertFalse(message.hasExtension(oneofStringExtension));
+    Assert.assertFalse(message.hasExtension(oneofBytesExtension));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}
+   * followed by {@code modifyRepeatedExtensions}.
+   */
+  public static void assertRepeatedExtensionsModified(
+      TestAllExtensionsOrBuilder message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtension, 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+      message.getExtension(repeatedForeignEnumExtension, 0));
+    assertEqualsExactType(ImportEnum.IMPORT_BAR,
+      message.getExtension(repeatedImportEnumExtension, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+    // Actually verify the second (modified) elements now.
+    assertEqualsExactType(501  , message.getExtension(repeatedInt32Extension   , 1));
+    assertEqualsExactType(502L , message.getExtension(repeatedInt64Extension   , 1));
+    assertEqualsExactType(503  , message.getExtension(repeatedUint32Extension  , 1));
+    assertEqualsExactType(504L , message.getExtension(repeatedUint64Extension  , 1));
+    assertEqualsExactType(505  , message.getExtension(repeatedSint32Extension  , 1));
+    assertEqualsExactType(506L , message.getExtension(repeatedSint64Extension  , 1));
+    assertEqualsExactType(507  , message.getExtension(repeatedFixed32Extension , 1));
+    assertEqualsExactType(508L , message.getExtension(repeatedFixed64Extension , 1));
+    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32Extension, 1));
+    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64Extension, 1));
+    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtension   , 1));
+    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtension  , 1));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 1));
+    assertEqualsExactType("515", message.getExtension(repeatedStringExtension  , 1));
+    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtension, 1));
+
+    assertEqualsExactType(517, message.getExtension(repeatedGroupExtension         , 1).getA());
+    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD());
+    assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
+
+    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+      message.getExtension(repeatedNestedEnumExtension, 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+      message.getExtension(repeatedForeignEnumExtension, 1));
+    assertEqualsExactType(ImportEnum.IMPORT_FOO,
+      message.getExtension(repeatedImportEnumExtension, 1));
+
+    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtension, 1));
+    assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1));
+  }
+
+  public static void setPackedExtensions(TestPackedExtensions.Builder message) {
+    message.addExtension(packedInt32Extension   , 601);
+    message.addExtension(packedInt64Extension   , 602L);
+    message.addExtension(packedUint32Extension  , 603);
+    message.addExtension(packedUint64Extension  , 604L);
+    message.addExtension(packedSint32Extension  , 605);
+    message.addExtension(packedSint64Extension  , 606L);
+    message.addExtension(packedFixed32Extension , 607);
+    message.addExtension(packedFixed64Extension , 608L);
+    message.addExtension(packedSfixed32Extension, 609);
+    message.addExtension(packedSfixed64Extension, 610L);
+    message.addExtension(packedFloatExtension   , 611F);
+    message.addExtension(packedDoubleExtension  , 612D);
+    message.addExtension(packedBoolExtension    , true);
+    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAR);
+    // Add a second one of each field.
+    message.addExtension(packedInt32Extension   , 701);
+    message.addExtension(packedInt64Extension   , 702L);
+    message.addExtension(packedUint32Extension  , 703);
+    message.addExtension(packedUint64Extension  , 704L);
+    message.addExtension(packedSint32Extension  , 705);
+    message.addExtension(packedSint64Extension  , 706L);
+    message.addExtension(packedFixed32Extension , 707);
+    message.addExtension(packedFixed64Extension , 708L);
+    message.addExtension(packedSfixed32Extension, 709);
+    message.addExtension(packedSfixed64Extension, 710L);
+    message.addExtension(packedFloatExtension   , 711F);
+    message.addExtension(packedDoubleExtension  , 712D);
+    message.addExtension(packedBoolExtension    , false);
+    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAZ);
+  }
+
+  public static void assertPackedExtensionsSet(TestPackedExtensions message) {
+    Assert.assertEquals(2, message.getExtensionCount(packedInt32Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedInt64Extension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint32Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint64Extension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed32Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed64Extension ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32Extension));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64Extension));
+    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtension   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtension  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtension    ));
+    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtension));
+    assertEqualsExactType(601  , message.getExtension(packedInt32Extension   , 0));
+    assertEqualsExactType(602L , message.getExtension(packedInt64Extension   , 0));
+    assertEqualsExactType(603  , message.getExtension(packedUint32Extension  , 0));
+    assertEqualsExactType(604L , message.getExtension(packedUint64Extension  , 0));
+    assertEqualsExactType(605  , message.getExtension(packedSint32Extension  , 0));
+    assertEqualsExactType(606L , message.getExtension(packedSint64Extension  , 0));
+    assertEqualsExactType(607  , message.getExtension(packedFixed32Extension , 0));
+    assertEqualsExactType(608L , message.getExtension(packedFixed64Extension , 0));
+    assertEqualsExactType(609  , message.getExtension(packedSfixed32Extension, 0));
+    assertEqualsExactType(610L , message.getExtension(packedSfixed64Extension, 0));
+    assertEqualsExactType(611F , message.getExtension(packedFloatExtension   , 0));
+    assertEqualsExactType(612D , message.getExtension(packedDoubleExtension  , 0));
+    assertEqualsExactType(true , message.getExtension(packedBoolExtension    , 0));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+                          message.getExtension(packedEnumExtension, 0));
+    assertEqualsExactType(701  , message.getExtension(packedInt32Extension   , 1));
+    assertEqualsExactType(702L , message.getExtension(packedInt64Extension   , 1));
+    assertEqualsExactType(703  , message.getExtension(packedUint32Extension  , 1));
+    assertEqualsExactType(704L , message.getExtension(packedUint64Extension  , 1));
+    assertEqualsExactType(705  , message.getExtension(packedSint32Extension  , 1));
+    assertEqualsExactType(706L , message.getExtension(packedSint64Extension  , 1));
+    assertEqualsExactType(707  , message.getExtension(packedFixed32Extension , 1));
+    assertEqualsExactType(708L , message.getExtension(packedFixed64Extension , 1));
+    assertEqualsExactType(709  , message.getExtension(packedSfixed32Extension, 1));
+    assertEqualsExactType(710L , message.getExtension(packedSfixed64Extension, 1));
+    assertEqualsExactType(711F , message.getExtension(packedFloatExtension   , 1));
+    assertEqualsExactType(712D , message.getExtension(packedDoubleExtension  , 1));
+    assertEqualsExactType(false, message.getExtension(packedBoolExtension    , 1));
+    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+                          message.getExtension(packedEnumExtension, 1));
+  }
+
+  // ===================================================================
+  // Lite extensions
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}.
+   */
+  public static void assertAllExtensionsSet(
+      TestAllExtensionsLiteOrBuilder message) {
+    Assert.assertTrue(message.hasExtension(optionalInt32ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalInt64ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalUint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalUint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalSint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalSint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalFixed32ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalFixed64ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalSfixed32ExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalSfixed64ExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalFloatExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(optionalDoubleExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalBoolExtensionLite    ));
+    Assert.assertTrue(message.hasExtension(optionalStringExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(optionalBytesExtensionLite   ));
+
+    Assert.assertTrue(message.hasExtension(optionalGroupExtensionLite         ));
+    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalImportMessageExtensionLite ));
+
+    Assert.assertTrue(message.getExtension(optionalGroupExtensionLite         ).hasA());
+    Assert.assertTrue(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+    Assert.assertTrue(message.getExtension(optionalForeignMessageExtensionLite).hasC());
+    Assert.assertTrue(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+
+    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtensionLite ));
+    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalImportEnumExtensionLite ));
+
+    Assert.assertTrue(message.hasExtension(optionalStringPieceExtensionLite));
+    Assert.assertTrue(message.hasExtension(optionalCordExtensionLite));
+
+    assertEqualsExactType(101  , message.getExtension(optionalInt32ExtensionLite   ));
+    assertEqualsExactType(102L , message.getExtension(optionalInt64ExtensionLite   ));
+    assertEqualsExactType(103  , message.getExtension(optionalUint32ExtensionLite  ));
+    assertEqualsExactType(104L , message.getExtension(optionalUint64ExtensionLite  ));
+    assertEqualsExactType(105  , message.getExtension(optionalSint32ExtensionLite  ));
+    assertEqualsExactType(106L , message.getExtension(optionalSint64ExtensionLite  ));
+    assertEqualsExactType(107  , message.getExtension(optionalFixed32ExtensionLite ));
+    assertEqualsExactType(108L , message.getExtension(optionalFixed64ExtensionLite ));
+    assertEqualsExactType(109  , message.getExtension(optionalSfixed32ExtensionLite));
+    assertEqualsExactType(110L , message.getExtension(optionalSfixed64ExtensionLite));
+    assertEqualsExactType(111F , message.getExtension(optionalFloatExtensionLite   ));
+    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtensionLite  ));
+    assertEqualsExactType(true , message.getExtension(optionalBoolExtensionLite    ));
+    assertEqualsExactType("115", message.getExtension(optionalStringExtensionLite  ));
+    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtensionLite));
+
+    assertEqualsExactType(117, message.getExtension(optionalGroupExtensionLite         ).getA());
+    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtensionLite).getC());
+    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtensionLite ).getD());
+    assertEqualsExactType(126, message.getExtension(
+        optionalPublicImportMessageExtensionLite).getE());
+    assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtensionLite).getBb());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+      message.getExtension(optionalNestedEnumExtensionLite));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+      message.getExtension(optionalForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+      message.getExtension(optionalImportEnumExtensionLite));
+
+    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtensionLite));
+    assertEqualsExactType("125", message.getExtension(optionalCordExtensionLite));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite   ,0).getBb());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtensionLite, 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(repeatedForeignEnumExtensionLite, 0));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+    assertEqualsExactType(301  , message.getExtension(repeatedInt32ExtensionLite   , 1));
+    assertEqualsExactType(302L , message.getExtension(repeatedInt64ExtensionLite   , 1));
+    assertEqualsExactType(303  , message.getExtension(repeatedUint32ExtensionLite  , 1));
+    assertEqualsExactType(304L , message.getExtension(repeatedUint64ExtensionLite  , 1));
+    assertEqualsExactType(305  , message.getExtension(repeatedSint32ExtensionLite  , 1));
+    assertEqualsExactType(306L , message.getExtension(repeatedSint64ExtensionLite  , 1));
+    assertEqualsExactType(307  , message.getExtension(repeatedFixed32ExtensionLite , 1));
+    assertEqualsExactType(308L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtensionLite   , 1));
+    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtensionLite  , 1));
+    assertEqualsExactType(false, message.getExtension(repeatedBoolExtensionLite    , 1));
+    assertEqualsExactType("315", message.getExtension(repeatedStringExtensionLite  , 1));
+    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+    assertEqualsExactType(317, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
+    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+    assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtensionLite   ,1).getBb());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+      message.getExtension(repeatedNestedEnumExtensionLite, 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+      message.getExtension(repeatedForeignEnumExtensionLite, 1));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+      message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtensionLite, 1));
+    assertEqualsExactType("325", message.getExtension(repeatedCordExtensionLite, 1));
+
+    // -----------------------------------------------------------------
+
+    Assert.assertTrue(message.hasExtension(defaultInt32ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultInt64ExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultUint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultUint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultSint32ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultSint64ExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultFixed32ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultFixed64ExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultSfixed32ExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultSfixed64ExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultFloatExtensionLite   ));
+    Assert.assertTrue(message.hasExtension(defaultDoubleExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultBoolExtensionLite    ));
+    Assert.assertTrue(message.hasExtension(defaultStringExtensionLite  ));
+    Assert.assertTrue(message.hasExtension(defaultBytesExtensionLite   ));
+
+    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtensionLite ));
+    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultImportEnumExtensionLite ));
+
+    Assert.assertTrue(message.hasExtension(defaultStringPieceExtensionLite));
+    Assert.assertTrue(message.hasExtension(defaultCordExtensionLite));
+
+    assertEqualsExactType(401  , message.getExtension(defaultInt32ExtensionLite   ));
+    assertEqualsExactType(402L , message.getExtension(defaultInt64ExtensionLite   ));
+    assertEqualsExactType(403  , message.getExtension(defaultUint32ExtensionLite  ));
+    assertEqualsExactType(404L , message.getExtension(defaultUint64ExtensionLite  ));
+    assertEqualsExactType(405  , message.getExtension(defaultSint32ExtensionLite  ));
+    assertEqualsExactType(406L , message.getExtension(defaultSint64ExtensionLite  ));
+    assertEqualsExactType(407  , message.getExtension(defaultFixed32ExtensionLite ));
+    assertEqualsExactType(408L , message.getExtension(defaultFixed64ExtensionLite ));
+    assertEqualsExactType(409  , message.getExtension(defaultSfixed32ExtensionLite));
+    assertEqualsExactType(410L , message.getExtension(defaultSfixed64ExtensionLite));
+    assertEqualsExactType(411F , message.getExtension(defaultFloatExtensionLite   ));
+    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtensionLite  ));
+    assertEqualsExactType(false, message.getExtension(defaultBoolExtensionLite    ));
+    assertEqualsExactType("415", message.getExtension(defaultStringExtensionLite  ));
+    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtensionLite));
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(defaultNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(defaultForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(defaultImportEnumExtensionLite));
+
+    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
+    assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
+
+    Assert.assertTrue(message.hasExtension(oneofBytesExtensionLite));
+
+    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtensionLite));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are cleared, and that getting the extensions returns their
+   * default values.
+   */
+  public static void assertExtensionsClear(
+      TestAllExtensionsLiteOrBuilder message) {
+    // hasBlah() should initially be false for all optional fields.
+    Assert.assertFalse(message.hasExtension(optionalInt32ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalInt64ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalUint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalUint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalSint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalSint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalFixed32ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalFixed64ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalSfixed32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalSfixed64ExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalFloatExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(optionalDoubleExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalBoolExtensionLite    ));
+    Assert.assertFalse(message.hasExtension(optionalStringExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(optionalBytesExtensionLite   ));
+
+    Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite              ));
+    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite      ));
+    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite     ));
+    Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite      ));
+    Assert.assertFalse(message.hasExtension(optionalPublicImportMessageExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalLazyMessageExtensionLite        ));
+
+    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtensionLite ));
+    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalImportEnumExtensionLite ));
+
+    Assert.assertFalse(message.hasExtension(optionalStringPieceExtensionLite));
+    Assert.assertFalse(message.hasExtension(optionalCordExtensionLite));
+
+    // Optional fields without defaults are set to zero or something like it.
+    assertEqualsExactType(0    , message.getExtension(optionalInt32ExtensionLite   ));
+    assertEqualsExactType(0L   , message.getExtension(optionalInt64ExtensionLite   ));
+    assertEqualsExactType(0    , message.getExtension(optionalUint32ExtensionLite  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalUint64ExtensionLite  ));
+    assertEqualsExactType(0    , message.getExtension(optionalSint32ExtensionLite  ));
+    assertEqualsExactType(0L   , message.getExtension(optionalSint64ExtensionLite  ));
+    assertEqualsExactType(0    , message.getExtension(optionalFixed32ExtensionLite ));
+    assertEqualsExactType(0L   , message.getExtension(optionalFixed64ExtensionLite ));
+    assertEqualsExactType(0    , message.getExtension(optionalSfixed32ExtensionLite));
+    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64ExtensionLite));
+    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtensionLite   ));
+    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtensionLite  ));
+    assertEqualsExactType(false, message.getExtension(optionalBoolExtensionLite    ));
+    assertEqualsExactType(""   , message.getExtension(optionalStringExtensionLite  ));
+    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtensionLite));
+
+    // Embedded messages should also be clear.
+    Assert.assertFalse(message.getExtension(optionalGroupExtensionLite              ).hasA());
+    Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite      ).hasBb());
+    Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite     ).hasC());
+    Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite      ).hasD());
+    Assert.assertFalse(message.getExtension(optionalPublicImportMessageExtensionLite).hasE());
+    Assert.assertFalse(message.getExtension(optionalLazyMessageExtensionLite        ).hasBb());
+
+    assertEqualsExactType(0, message.getExtension(optionalGroupExtensionLite         ).getA());
+    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtensionLite).getC());
+    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtensionLite ).getD());
+    assertEqualsExactType(0, message.getExtension(
+        optionalPublicImportMessageExtensionLite).getE());
+    assertEqualsExactType(0, message.getExtension(optionalLazyMessageExtensionLite   ).getBb());
+
+    // Enums without defaults are set to the first value in the enum.
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(optionalNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(optionalForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(optionalImportEnumExtensionLite));
+
+    assertEqualsExactType("", message.getExtension(optionalStringPieceExtensionLite));
+    assertEqualsExactType("", message.getExtension(optionalCordExtensionLite));
+
+    // Repeated fields are empty.
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtensionLite));
+
+    // hasBlah() should also be false for all default fields.
+    Assert.assertFalse(message.hasExtension(defaultInt32ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultInt64ExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultUint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultUint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultSint32ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultSint64ExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultFixed32ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultFixed64ExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultSfixed32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultSfixed64ExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultFloatExtensionLite   ));
+    Assert.assertFalse(message.hasExtension(defaultDoubleExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultBoolExtensionLite    ));
+    Assert.assertFalse(message.hasExtension(defaultStringExtensionLite  ));
+    Assert.assertFalse(message.hasExtension(defaultBytesExtensionLite   ));
+
+    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtensionLite ));
+    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultImportEnumExtensionLite ));
+
+    Assert.assertFalse(message.hasExtension(defaultStringPieceExtensionLite));
+    Assert.assertFalse(message.hasExtension(defaultCordExtensionLite));
+
+    // Fields with defaults have their default values (duh).
+    assertEqualsExactType( 41    , message.getExtension(defaultInt32ExtensionLite   ));
+    assertEqualsExactType( 42L   , message.getExtension(defaultInt64ExtensionLite   ));
+    assertEqualsExactType( 43    , message.getExtension(defaultUint32ExtensionLite  ));
+    assertEqualsExactType( 44L   , message.getExtension(defaultUint64ExtensionLite  ));
+    assertEqualsExactType(-45    , message.getExtension(defaultSint32ExtensionLite  ));
+    assertEqualsExactType( 46L   , message.getExtension(defaultSint64ExtensionLite  ));
+    assertEqualsExactType( 47    , message.getExtension(defaultFixed32ExtensionLite ));
+    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64ExtensionLite ));
+    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32ExtensionLite));
+    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64ExtensionLite));
+    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtensionLite   ));
+    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtensionLite  ));
+    assertEqualsExactType(true   , message.getExtension(defaultBoolExtensionLite    ));
+    assertEqualsExactType("hello", message.getExtension(defaultStringExtensionLite  ));
+    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtensionLite));
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(defaultNestedEnumExtensionLite ));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(defaultForeignEnumExtensionLite));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(defaultImportEnumExtensionLite));
+
+    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
+    assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
+
+    Assert.assertFalse(message.hasExtension(oneofUint32ExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofStringExtensionLite));
+    Assert.assertFalse(message.hasExtension(oneofBytesExtensionLite));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Assert (using {@code junit.framework.Assert}} that all extensions of
+   * {@code message} are set to the values assigned by {@code setAllExtensions}
+   * followed by {@code modifyRepeatedExtensions}.
+   */
+  public static void assertRepeatedExtensionsModified(
+      TestAllExtensionsLiteOrBuilder message) {
+    // ModifyRepeatedFields only sets the second repeated element of each
+    // field.  In addition to verifying this, we also verify that the first
+    // element and size were *not* modified.
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
+
+    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
+    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
+    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
+    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
+    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
+    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
+    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
+    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
+    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
+    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
+    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
+    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite   ,0).getBb());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+      message.getExtension(repeatedNestedEnumExtensionLite, 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+      message.getExtension(repeatedForeignEnumExtensionLite, 0));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+      message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+    // Actually verify the second (modified) elements now.
+    assertEqualsExactType(501  , message.getExtension(repeatedInt32ExtensionLite   , 1));
+    assertEqualsExactType(502L , message.getExtension(repeatedInt64ExtensionLite   , 1));
+    assertEqualsExactType(503  , message.getExtension(repeatedUint32ExtensionLite  , 1));
+    assertEqualsExactType(504L , message.getExtension(repeatedUint64ExtensionLite  , 1));
+    assertEqualsExactType(505  , message.getExtension(repeatedSint32ExtensionLite  , 1));
+    assertEqualsExactType(506L , message.getExtension(repeatedSint64ExtensionLite  , 1));
+    assertEqualsExactType(507  , message.getExtension(repeatedFixed32ExtensionLite , 1));
+    assertEqualsExactType(508L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtensionLite   , 1));
+    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtensionLite  , 1));
+    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 1));
+    assertEqualsExactType("515", message.getExtension(repeatedStringExtensionLite  , 1));
+    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+    assertEqualsExactType(517, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
+    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+    assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtensionLite   ,1).getBb());
+
+    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+      message.getExtension(repeatedNestedEnumExtensionLite, 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+      message.getExtension(repeatedForeignEnumExtensionLite, 1));
+    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+      message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtensionLite, 1));
+    assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
+  }
+
+  public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
+    Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedUint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint32ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSint64ExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed32ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(packedFixed64ExtensionLite ));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64ExtensionLite));
+    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtensionLite   ));
+    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtensionLite  ));
+    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtensionLite    ));
+    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtensionLite));
+    assertEqualsExactType(601  , message.getExtension(packedInt32ExtensionLite   , 0));
+    assertEqualsExactType(602L , message.getExtension(packedInt64ExtensionLite   , 0));
+    assertEqualsExactType(603  , message.getExtension(packedUint32ExtensionLite  , 0));
+    assertEqualsExactType(604L , message.getExtension(packedUint64ExtensionLite  , 0));
+    assertEqualsExactType(605  , message.getExtension(packedSint32ExtensionLite  , 0));
+    assertEqualsExactType(606L , message.getExtension(packedSint64ExtensionLite  , 0));
+    assertEqualsExactType(607  , message.getExtension(packedFixed32ExtensionLite , 0));
+    assertEqualsExactType(608L , message.getExtension(packedFixed64ExtensionLite , 0));
+    assertEqualsExactType(609  , message.getExtension(packedSfixed32ExtensionLite, 0));
+    assertEqualsExactType(610L , message.getExtension(packedSfixed64ExtensionLite, 0));
+    assertEqualsExactType(611F , message.getExtension(packedFloatExtensionLite   , 0));
+    assertEqualsExactType(612D , message.getExtension(packedDoubleExtensionLite  , 0));
+    assertEqualsExactType(true , message.getExtension(packedBoolExtensionLite    , 0));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+                          message.getExtension(packedEnumExtensionLite, 0));
+    assertEqualsExactType(701  , message.getExtension(packedInt32ExtensionLite   , 1));
+    assertEqualsExactType(702L , message.getExtension(packedInt64ExtensionLite   , 1));
+    assertEqualsExactType(703  , message.getExtension(packedUint32ExtensionLite  , 1));
+    assertEqualsExactType(704L , message.getExtension(packedUint64ExtensionLite  , 1));
+    assertEqualsExactType(705  , message.getExtension(packedSint32ExtensionLite  , 1));
+    assertEqualsExactType(706L , message.getExtension(packedSint64ExtensionLite  , 1));
+    assertEqualsExactType(707  , message.getExtension(packedFixed32ExtensionLite , 1));
+    assertEqualsExactType(708L , message.getExtension(packedFixed64ExtensionLite , 1));
+    assertEqualsExactType(709  , message.getExtension(packedSfixed32ExtensionLite, 1));
+    assertEqualsExactType(710L , message.getExtension(packedSfixed64ExtensionLite, 1));
+    assertEqualsExactType(711F , message.getExtension(packedFloatExtensionLite   , 1));
+    assertEqualsExactType(712D , message.getExtension(packedDoubleExtensionLite  , 1));
+    assertEqualsExactType(false, message.getExtension(packedBoolExtensionLite    , 1));
+    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+                          message.getExtension(packedEnumExtensionLite, 1));
+  }
+
+  // ===================================================================
+  // oneof
+  public static void setOneof(TestOneof2.Builder message) {
+    message.setFooLazyMessage(
+        TestOneof2.NestedMessage.newBuilder().setQuxInt(100).build());
+    message.setBarString("101");
+    message.setBazInt(102);
+    message.setBazString("103");
+  }
+
+  public static void assertOneofSet(TestOneof2 message) {
+    Assert.assertTrue(message.hasFooLazyMessage            ());
+    Assert.assertTrue(message.getFooLazyMessage().hasQuxInt());
+
+    Assert.assertTrue(message.hasBarString());
+    Assert.assertTrue(message.hasBazInt   ());
+    Assert.assertTrue(message.hasBazString());
+
+    Assert.assertEquals(100  , message.getFooLazyMessage().getQuxInt());
+    Assert.assertEquals("101", message.getBarString                 ());
+    Assert.assertEquals(102  , message.getBazInt                    ());
+    Assert.assertEquals("103", message.getBazString                 ());
+  }
+
+  public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
+    int count = 0;
+    if (message.hasFooInt()) { ++count; }
+    if (message.hasFooString()) { ++count; }
+    if (message.hasFooCord()) { ++count; }
+    if (message.hasFooStringPiece()) { ++count; }
+    if (message.hasFooBytes()) { ++count; }
+    if (message.hasFooEnum()) { ++count; }
+    if (message.hasFooMessage()) { ++count; }
+    if (message.hasFooGroup()) { ++count; }
+    if (message.hasFooLazyMessage()) { ++count; }
+    Assert.assertTrue(count <= 1);
+
+    count = 0;
+    if (message.hasBarInt()) { ++count; }
+    if (message.hasBarString()) { ++count; }
+    if (message.hasBarCord()) { ++count; }
+    if (message.hasBarStringPiece()) { ++count; }
+    if (message.hasBarBytes()) { ++count; }
+    if (message.hasBarEnum()) { ++count; }
+    Assert.assertTrue(count <= 1);
+
+    switch (message.getFooCase()) {
+      case FOO_INT:
+        Assert.assertTrue(message.hasFooInt());
+        break;
+      case FOO_STRING:
+        Assert.assertTrue(message.hasFooString());
+        break;
+      case FOO_CORD:
+        Assert.assertTrue(message.hasFooCord());
+        break;
+      case FOO_BYTES:
+        Assert.assertTrue(message.hasFooBytes());
+        break;
+      case FOO_ENUM:
+        Assert.assertTrue(message.hasFooEnum());
+        break;
+      case FOO_MESSAGE:
+        Assert.assertTrue(message.hasFooMessage());
+        break;
+      case FOOGROUP:
+        Assert.assertTrue(message.hasFooGroup());
+        break;
+      case FOO_LAZY_MESSAGE:
+        Assert.assertTrue(message.hasFooLazyMessage());
+        break;
+      case FOO_NOT_SET:
+        break;
+    }
+  }
+
+  // =================================================================
+
+  /**
+   * Performs the same things that the methods of {@code TestUtil} do, but
+   * via the reflection interface.  This is its own class because it needs
+   * to know what descriptor to use.
+   */
+  public static class ReflectionTester {
+    private final Descriptors.Descriptor baseDescriptor;
+    private final ExtensionRegistry extensionRegistry;
+
+    private final Descriptors.FileDescriptor file;
+    private final Descriptors.FileDescriptor importFile;
+    private final Descriptors.FileDescriptor publicImportFile;
+
+    private final Descriptors.Descriptor optionalGroup;
+    private final Descriptors.Descriptor repeatedGroup;
+    private final Descriptors.Descriptor nestedMessage;
+    private final Descriptors.Descriptor foreignMessage;
+    private final Descriptors.Descriptor importMessage;
+    private final Descriptors.Descriptor publicImportMessage;
+
+    private final Descriptors.FieldDescriptor groupA;
+    private final Descriptors.FieldDescriptor repeatedGroupA;
+    private final Descriptors.FieldDescriptor nestedB;
+    private final Descriptors.FieldDescriptor foreignC;
+    private final Descriptors.FieldDescriptor importD;
+    private final Descriptors.FieldDescriptor importE;
+
+    private final Descriptors.EnumDescriptor nestedEnum;
+    private final Descriptors.EnumDescriptor foreignEnum;
+    private final Descriptors.EnumDescriptor importEnum;
+
+    private final Descriptors.EnumValueDescriptor nestedFoo;
+    private final Descriptors.EnumValueDescriptor nestedBar;
+    private final Descriptors.EnumValueDescriptor nestedBaz;
+    private final Descriptors.EnumValueDescriptor foreignFoo;
+    private final Descriptors.EnumValueDescriptor foreignBar;
+    private final Descriptors.EnumValueDescriptor foreignBaz;
+    private final Descriptors.EnumValueDescriptor importFoo;
+    private final Descriptors.EnumValueDescriptor importBar;
+    private final Descriptors.EnumValueDescriptor importBaz;
+
+    /**
+     * Construct a {@code ReflectionTester} that will expect messages using
+     * the given descriptor.
+     *
+     * Normally {@code baseDescriptor} should be a descriptor for the type
+     * {@code TestAllTypes}, defined in
+     * {@code google/protobuf/unittest.proto}.  However, if
+     * {@code extensionRegistry} is non-null, then {@code baseDescriptor} should
+     * be for {@code TestAllExtensions} instead, and instead of reading and
+     * writing normal fields, the tester will read and write extensions.
+     * All of {@code TestAllExtensions}' extensions must be registered in the
+     * registry.
+     */
+    public ReflectionTester(Descriptors.Descriptor baseDescriptor,
+                            ExtensionRegistry extensionRegistry) {
+      this.baseDescriptor = baseDescriptor;
+      this.extensionRegistry = extensionRegistry;
+
+      this.file = baseDescriptor.getFile();
+      Assert.assertEquals(1, file.getDependencies().size());
+      this.importFile = file.getDependencies().get(0);
+      this.publicImportFile = importFile.getDependencies().get(0);
+
+      Descriptors.Descriptor testAllTypes;
+      if (baseDescriptor.getName() == "TestAllTypes") {
+        testAllTypes = baseDescriptor;
+      } else {
+        testAllTypes = file.findMessageTypeByName("TestAllTypes");
+        Assert.assertNotNull(testAllTypes);
+      }
+
+      if (extensionRegistry == null) {
+        // Use testAllTypes, rather than baseDescriptor, to allow
+        // initialization using TestPackedTypes descriptors. These objects
+        // won't be used by the methods for packed fields.
+        this.optionalGroup =
+          testAllTypes.findNestedTypeByName("OptionalGroup");
+        this.repeatedGroup =
+          testAllTypes.findNestedTypeByName("RepeatedGroup");
+      } else {
+        this.optionalGroup =
+          file.findMessageTypeByName("OptionalGroup_extension");
+        this.repeatedGroup =
+          file.findMessageTypeByName("RepeatedGroup_extension");
+      }
+      this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
+      this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
+      this.importMessage = importFile.findMessageTypeByName("ImportMessage");
+      this.publicImportMessage = publicImportFile.findMessageTypeByName(
+          "PublicImportMessage");
+
+      this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
+      this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
+      this.importEnum = importFile.findEnumTypeByName("ImportEnum");
+
+      Assert.assertNotNull(optionalGroup );
+      Assert.assertNotNull(repeatedGroup );
+      Assert.assertNotNull(nestedMessage );
+      Assert.assertNotNull(foreignMessage);
+      Assert.assertNotNull(importMessage );
+      Assert.assertNotNull(nestedEnum    );
+      Assert.assertNotNull(foreignEnum   );
+      Assert.assertNotNull(importEnum    );
+
+      this.nestedB  = nestedMessage .findFieldByName("bb");
+      this.foreignC = foreignMessage.findFieldByName("c");
+      this.importD  = importMessage .findFieldByName("d");
+      this.importE  = publicImportMessage.findFieldByName("e");
+      this.nestedFoo = nestedEnum.findValueByName("FOO");
+      this.nestedBar = nestedEnum.findValueByName("BAR");
+      this.nestedBaz = nestedEnum.findValueByName("BAZ");
+      this.foreignFoo = foreignEnum.findValueByName("FOREIGN_FOO");
+      this.foreignBar = foreignEnum.findValueByName("FOREIGN_BAR");
+      this.foreignBaz = foreignEnum.findValueByName("FOREIGN_BAZ");
+      this.importFoo = importEnum.findValueByName("IMPORT_FOO");
+      this.importBar = importEnum.findValueByName("IMPORT_BAR");
+      this.importBaz = importEnum.findValueByName("IMPORT_BAZ");
+
+      this.groupA = optionalGroup.findFieldByName("a");
+      this.repeatedGroupA = repeatedGroup.findFieldByName("a");
+
+      Assert.assertNotNull(groupA        );
+      Assert.assertNotNull(repeatedGroupA);
+      Assert.assertNotNull(nestedB       );
+      Assert.assertNotNull(foreignC      );
+      Assert.assertNotNull(importD       );
+      Assert.assertNotNull(importE       );
+      Assert.assertNotNull(nestedFoo     );
+      Assert.assertNotNull(nestedBar     );
+      Assert.assertNotNull(nestedBaz     );
+      Assert.assertNotNull(foreignFoo    );
+      Assert.assertNotNull(foreignBar    );
+      Assert.assertNotNull(foreignBaz    );
+      Assert.assertNotNull(importFoo     );
+      Assert.assertNotNull(importBar     );
+      Assert.assertNotNull(importBaz     );
+    }
+
+    /**
+     * Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+     */
+    private Descriptors.FieldDescriptor f(String name) {
+      Descriptors.FieldDescriptor result;
+      if (extensionRegistry == null) {
+        result = baseDescriptor.findFieldByName(name);
+      } else {
+        result = file.findExtensionByName(name + "_extension");
+      }
+      Assert.assertNotNull(result);
+      return result;
+    }
+
+    /**
+     * Calls {@code parent.newBuilderForField()} or uses the
+     * {@code ExtensionRegistry} to find an appropriate builder, depending
+     * on what type is being tested.
+     */
+    private Message.Builder newBuilderForField(
+        Message.Builder parent, Descriptors.FieldDescriptor field) {
+      if (extensionRegistry == null) {
+        return parent.newBuilderForField(field);
+      } else {
+        ExtensionRegistry.ExtensionInfo extension =
+          extensionRegistry.findImmutableExtensionByNumber(
+              field.getContainingType(), field.getNumber());
+        Assert.assertNotNull(extension);
+        Assert.assertNotNull(extension.defaultInstance);
+        return extension.defaultInstance.newBuilderForType();
+      }
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Set every field of {@code message} to the values expected by
+     * {@code assertAllFieldsSet()}, using the {@link Message.Builder}
+     * reflection interface.
+     */
+    void setAllFieldsViaReflection(Message.Builder message) {
+      message.setField(f("optional_int32"   ), 101 );
+      message.setField(f("optional_int64"   ), 102L);
+      message.setField(f("optional_uint32"  ), 103 );
+      message.setField(f("optional_uint64"  ), 104L);
+      message.setField(f("optional_sint32"  ), 105 );
+      message.setField(f("optional_sint64"  ), 106L);
+      message.setField(f("optional_fixed32" ), 107 );
+      message.setField(f("optional_fixed64" ), 108L);
+      message.setField(f("optional_sfixed32"), 109 );
+      message.setField(f("optional_sfixed64"), 110L);
+      message.setField(f("optional_float"   ), 111F);
+      message.setField(f("optional_double"  ), 112D);
+      message.setField(f("optional_bool"    ), true);
+      message.setField(f("optional_string"  ), "115");
+      message.setField(f("optional_bytes"   ), toBytes("116"));
+
+      message.setField(f("optionalgroup"),
+        newBuilderForField(message, f("optionalgroup"))
+               .setField(groupA, 117).build());
+      message.setField(f("optional_nested_message"),
+        newBuilderForField(message, f("optional_nested_message"))
+               .setField(nestedB, 118).build());
+      message.setField(f("optional_foreign_message"),
+        newBuilderForField(message, f("optional_foreign_message"))
+               .setField(foreignC, 119).build());
+      message.setField(f("optional_import_message"),
+        newBuilderForField(message, f("optional_import_message"))
+               .setField(importD, 120).build());
+      message.setField(f("optional_public_import_message"),
+        newBuilderForField(message, f("optional_public_import_message"))
+               .setField(importE, 126).build());
+      message.setField(f("optional_lazy_message"),
+        newBuilderForField(message, f("optional_lazy_message"))
+               .setField(nestedB, 127).build());
+
+      message.setField(f("optional_nested_enum" ),  nestedBaz);
+      message.setField(f("optional_foreign_enum"), foreignBaz);
+      message.setField(f("optional_import_enum" ),  importBaz);
+
+      message.setField(f("optional_string_piece" ), "124");
+      message.setField(f("optional_cord" ), "125");
+
+      // -----------------------------------------------------------------
+
+      message.addRepeatedField(f("repeated_int32"   ), 201 );
+      message.addRepeatedField(f("repeated_int64"   ), 202L);
+      message.addRepeatedField(f("repeated_uint32"  ), 203 );
+      message.addRepeatedField(f("repeated_uint64"  ), 204L);
+      message.addRepeatedField(f("repeated_sint32"  ), 205 );
+      message.addRepeatedField(f("repeated_sint64"  ), 206L);
+      message.addRepeatedField(f("repeated_fixed32" ), 207 );
+      message.addRepeatedField(f("repeated_fixed64" ), 208L);
+      message.addRepeatedField(f("repeated_sfixed32"), 209 );
+      message.addRepeatedField(f("repeated_sfixed64"), 210L);
+      message.addRepeatedField(f("repeated_float"   ), 211F);
+      message.addRepeatedField(f("repeated_double"  ), 212D);
+      message.addRepeatedField(f("repeated_bool"    ), true);
+      message.addRepeatedField(f("repeated_string"  ), "215");
+      message.addRepeatedField(f("repeated_bytes"   ), toBytes("216"));
+
+      message.addRepeatedField(f("repeatedgroup"),
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 217).build());
+      message.addRepeatedField(f("repeated_nested_message"),
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 218).build());
+      message.addRepeatedField(f("repeated_foreign_message"),
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 219).build());
+      message.addRepeatedField(f("repeated_import_message"),
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 220).build());
+      message.addRepeatedField(f("repeated_lazy_message"),
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 227).build());
+
+      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBar);
+      message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
+      message.addRepeatedField(f("repeated_import_enum" ),  importBar);
+
+      message.addRepeatedField(f("repeated_string_piece" ), "224");
+      message.addRepeatedField(f("repeated_cord" ), "225");
+
+      // Add a second one of each field.
+      message.addRepeatedField(f("repeated_int32"   ), 301 );
+      message.addRepeatedField(f("repeated_int64"   ), 302L);
+      message.addRepeatedField(f("repeated_uint32"  ), 303 );
+      message.addRepeatedField(f("repeated_uint64"  ), 304L);
+      message.addRepeatedField(f("repeated_sint32"  ), 305 );
+      message.addRepeatedField(f("repeated_sint64"  ), 306L);
+      message.addRepeatedField(f("repeated_fixed32" ), 307 );
+      message.addRepeatedField(f("repeated_fixed64" ), 308L);
+      message.addRepeatedField(f("repeated_sfixed32"), 309 );
+      message.addRepeatedField(f("repeated_sfixed64"), 310L);
+      message.addRepeatedField(f("repeated_float"   ), 311F);
+      message.addRepeatedField(f("repeated_double"  ), 312D);
+      message.addRepeatedField(f("repeated_bool"    ), false);
+      message.addRepeatedField(f("repeated_string"  ), "315");
+      message.addRepeatedField(f("repeated_bytes"   ), toBytes("316"));
+
+      message.addRepeatedField(f("repeatedgroup"),
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 317).build());
+      message.addRepeatedField(f("repeated_nested_message"),
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 318).build());
+      message.addRepeatedField(f("repeated_foreign_message"),
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 319).build());
+      message.addRepeatedField(f("repeated_import_message"),
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 320).build());
+      message.addRepeatedField(f("repeated_lazy_message"),
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 327).build());
+
+      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBaz);
+      message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
+      message.addRepeatedField(f("repeated_import_enum" ),  importBaz);
+
+      message.addRepeatedField(f("repeated_string_piece" ), "324");
+      message.addRepeatedField(f("repeated_cord" ), "325");
+
+      // -----------------------------------------------------------------
+
+      message.setField(f("default_int32"   ), 401 );
+      message.setField(f("default_int64"   ), 402L);
+      message.setField(f("default_uint32"  ), 403 );
+      message.setField(f("default_uint64"  ), 404L);
+      message.setField(f("default_sint32"  ), 405 );
+      message.setField(f("default_sint64"  ), 406L);
+      message.setField(f("default_fixed32" ), 407 );
+      message.setField(f("default_fixed64" ), 408L);
+      message.setField(f("default_sfixed32"), 409 );
+      message.setField(f("default_sfixed64"), 410L);
+      message.setField(f("default_float"   ), 411F);
+      message.setField(f("default_double"  ), 412D);
+      message.setField(f("default_bool"    ), false);
+      message.setField(f("default_string"  ), "415");
+      message.setField(f("default_bytes"   ), toBytes("416"));
+
+      message.setField(f("default_nested_enum" ),  nestedFoo);
+      message.setField(f("default_foreign_enum"), foreignFoo);
+      message.setField(f("default_import_enum" ),  importFoo);
+
+      message.setField(f("default_string_piece" ), "424");
+      message.setField(f("default_cord" ), "425");
+
+      message.setField(f("oneof_uint32" ), 601);
+      message.setField(f("oneof_nested_message"),
+        newBuilderForField(message, f("oneof_nested_message"))
+          .setField(nestedB, 602).build());
+      message.setField(f("oneof_string" ), "603");
+      message.setField(f("oneof_bytes" ), toBytes("604"));
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Modify the repeated fields of {@code message} to contain the values
+     * expected by {@code assertRepeatedFieldsModified()}, using the
+     * {@link Message.Builder} reflection interface.
+     */
+    void modifyRepeatedFieldsViaReflection(Message.Builder message) {
+      message.setRepeatedField(f("repeated_int32"   ), 1, 501 );
+      message.setRepeatedField(f("repeated_int64"   ), 1, 502L);
+      message.setRepeatedField(f("repeated_uint32"  ), 1, 503 );
+      message.setRepeatedField(f("repeated_uint64"  ), 1, 504L);
+      message.setRepeatedField(f("repeated_sint32"  ), 1, 505 );
+      message.setRepeatedField(f("repeated_sint64"  ), 1, 506L);
+      message.setRepeatedField(f("repeated_fixed32" ), 1, 507 );
+      message.setRepeatedField(f("repeated_fixed64" ), 1, 508L);
+      message.setRepeatedField(f("repeated_sfixed32"), 1, 509 );
+      message.setRepeatedField(f("repeated_sfixed64"), 1, 510L);
+      message.setRepeatedField(f("repeated_float"   ), 1, 511F);
+      message.setRepeatedField(f("repeated_double"  ), 1, 512D);
+      message.setRepeatedField(f("repeated_bool"    ), 1, true);
+      message.setRepeatedField(f("repeated_string"  ), 1, "515");
+      message.setRepeatedField(f("repeated_bytes"   ), 1, toBytes("516"));
+
+      message.setRepeatedField(f("repeatedgroup"), 1,
+        newBuilderForField(message, f("repeatedgroup"))
+               .setField(repeatedGroupA, 517).build());
+      message.setRepeatedField(f("repeated_nested_message"), 1,
+        newBuilderForField(message, f("repeated_nested_message"))
+               .setField(nestedB, 518).build());
+      message.setRepeatedField(f("repeated_foreign_message"), 1,
+        newBuilderForField(message, f("repeated_foreign_message"))
+               .setField(foreignC, 519).build());
+      message.setRepeatedField(f("repeated_import_message"), 1,
+        newBuilderForField(message, f("repeated_import_message"))
+               .setField(importD, 520).build());
+      message.setRepeatedField(f("repeated_lazy_message"), 1,
+        newBuilderForField(message, f("repeated_lazy_message"))
+               .setField(nestedB, 527).build());
+
+      message.setRepeatedField(f("repeated_nested_enum" ), 1,  nestedFoo);
+      message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
+      message.setRepeatedField(f("repeated_import_enum" ), 1,  importFoo);
+
+      message.setRepeatedField(f("repeated_string_piece"), 1, "524");
+      message.setRepeatedField(f("repeated_cord"), 1, "525");
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Assert (using {@code junit.framework.Assert}} that all fields of
+     * {@code message} are set to the values assigned by {@code setAllFields},
+     * using the {@link Message} reflection interface.
+     */
+    public void assertAllFieldsSetViaReflection(MessageOrBuilder message) {
+      Assert.assertTrue(message.hasField(f("optional_int32"   )));
+      Assert.assertTrue(message.hasField(f("optional_int64"   )));
+      Assert.assertTrue(message.hasField(f("optional_uint32"  )));
+      Assert.assertTrue(message.hasField(f("optional_uint64"  )));
+      Assert.assertTrue(message.hasField(f("optional_sint32"  )));
+      Assert.assertTrue(message.hasField(f("optional_sint64"  )));
+      Assert.assertTrue(message.hasField(f("optional_fixed32" )));
+      Assert.assertTrue(message.hasField(f("optional_fixed64" )));
+      Assert.assertTrue(message.hasField(f("optional_sfixed32")));
+      Assert.assertTrue(message.hasField(f("optional_sfixed64")));
+      Assert.assertTrue(message.hasField(f("optional_float"   )));
+      Assert.assertTrue(message.hasField(f("optional_double"  )));
+      Assert.assertTrue(message.hasField(f("optional_bool"    )));
+      Assert.assertTrue(message.hasField(f("optional_string"  )));
+      Assert.assertTrue(message.hasField(f("optional_bytes"   )));
+
+      Assert.assertTrue(message.hasField(f("optionalgroup"           )));
+      Assert.assertTrue(message.hasField(f("optional_nested_message" )));
+      Assert.assertTrue(message.hasField(f("optional_foreign_message")));
+      Assert.assertTrue(message.hasField(f("optional_import_message" )));
+
+      Assert.assertTrue(
+        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_nested_message")))
+                         .hasField(nestedB));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .hasField(foreignC));
+      Assert.assertTrue(
+        ((Message)message.getField(f("optional_import_message")))
+                         .hasField(importD));
+
+      Assert.assertTrue(message.hasField(f("optional_nested_enum" )));
+      Assert.assertTrue(message.hasField(f("optional_foreign_enum")));
+      Assert.assertTrue(message.hasField(f("optional_import_enum" )));
+
+      Assert.assertTrue(message.hasField(f("optional_string_piece")));
+      Assert.assertTrue(message.hasField(f("optional_cord")));
+
+      Assert.assertEquals(101  , message.getField(f("optional_int32"   )));
+      Assert.assertEquals(102L , message.getField(f("optional_int64"   )));
+      Assert.assertEquals(103  , message.getField(f("optional_uint32"  )));
+      Assert.assertEquals(104L , message.getField(f("optional_uint64"  )));
+      Assert.assertEquals(105  , message.getField(f("optional_sint32"  )));
+      Assert.assertEquals(106L , message.getField(f("optional_sint64"  )));
+      Assert.assertEquals(107  , message.getField(f("optional_fixed32" )));
+      Assert.assertEquals(108L , message.getField(f("optional_fixed64" )));
+      Assert.assertEquals(109  , message.getField(f("optional_sfixed32")));
+      Assert.assertEquals(110L , message.getField(f("optional_sfixed64")));
+      Assert.assertEquals(111F , message.getField(f("optional_float"   )));
+      Assert.assertEquals(112D , message.getField(f("optional_double"  )));
+      Assert.assertEquals(true , message.getField(f("optional_bool"    )));
+      Assert.assertEquals("115", message.getField(f("optional_string"  )));
+      Assert.assertEquals(toBytes("116"), message.getField(f("optional_bytes")));
+
+      Assert.assertEquals(117,
+        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+      Assert.assertEquals(118,
+        ((Message)message.getField(f("optional_nested_message")))
+                         .getField(nestedB));
+      Assert.assertEquals(119,
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .getField(foreignC));
+      Assert.assertEquals(120,
+        ((Message)message.getField(f("optional_import_message")))
+                         .getField(importD));
+      Assert.assertEquals(126,
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .getField(importE));
+      Assert.assertEquals(127,
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
+      Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
+      Assert.assertEquals( importBaz, message.getField(f("optional_import_enum" )));
+
+      Assert.assertEquals("124", message.getField(f("optional_string_piece")));
+      Assert.assertEquals("125", message.getField(f("optional_cord")));
+
+      // -----------------------------------------------------------------
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
+      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
+      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
+      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
+      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
+      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
+      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
+      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
+      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
+      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
+      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
+      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+      Assert.assertEquals(217,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(218,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+                         .getField(nestedB));
+      Assert.assertEquals(219,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+                         .getField(foreignC));
+      Assert.assertEquals(220,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+                         .getField(importD));
+      Assert.assertEquals(227,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+      Assert.assertEquals(301  , message.getRepeatedField(f("repeated_int32"   ), 1));
+      Assert.assertEquals(302L , message.getRepeatedField(f("repeated_int64"   ), 1));
+      Assert.assertEquals(303  , message.getRepeatedField(f("repeated_uint32"  ), 1));
+      Assert.assertEquals(304L , message.getRepeatedField(f("repeated_uint64"  ), 1));
+      Assert.assertEquals(305  , message.getRepeatedField(f("repeated_sint32"  ), 1));
+      Assert.assertEquals(306L , message.getRepeatedField(f("repeated_sint64"  ), 1));
+      Assert.assertEquals(307  , message.getRepeatedField(f("repeated_fixed32" ), 1));
+      Assert.assertEquals(308L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+      Assert.assertEquals(309  , message.getRepeatedField(f("repeated_sfixed32"), 1));
+      Assert.assertEquals(310L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+      Assert.assertEquals(311F , message.getRepeatedField(f("repeated_float"   ), 1));
+      Assert.assertEquals(312D , message.getRepeatedField(f("repeated_double"  ), 1));
+      Assert.assertEquals(false, message.getRepeatedField(f("repeated_bool"    ), 1));
+      Assert.assertEquals("315", message.getRepeatedField(f("repeated_string"  ), 1));
+      Assert.assertEquals(toBytes("316"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+      Assert.assertEquals(317,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(318,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+                         .getField(nestedB));
+      Assert.assertEquals(319,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+                         .getField(foreignC));
+      Assert.assertEquals(320,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+                         .getField(importD));
+      Assert.assertEquals(327,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
+      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
+      Assert.assertEquals( importBaz, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+      Assert.assertEquals("324", message.getRepeatedField(f("repeated_string_piece"), 1));
+      Assert.assertEquals("325", message.getRepeatedField(f("repeated_cord"), 1));
+
+      // -----------------------------------------------------------------
+
+      Assert.assertTrue(message.hasField(f("default_int32"   )));
+      Assert.assertTrue(message.hasField(f("default_int64"   )));
+      Assert.assertTrue(message.hasField(f("default_uint32"  )));
+      Assert.assertTrue(message.hasField(f("default_uint64"  )));
+      Assert.assertTrue(message.hasField(f("default_sint32"  )));
+      Assert.assertTrue(message.hasField(f("default_sint64"  )));
+      Assert.assertTrue(message.hasField(f("default_fixed32" )));
+      Assert.assertTrue(message.hasField(f("default_fixed64" )));
+      Assert.assertTrue(message.hasField(f("default_sfixed32")));
+      Assert.assertTrue(message.hasField(f("default_sfixed64")));
+      Assert.assertTrue(message.hasField(f("default_float"   )));
+      Assert.assertTrue(message.hasField(f("default_double"  )));
+      Assert.assertTrue(message.hasField(f("default_bool"    )));
+      Assert.assertTrue(message.hasField(f("default_string"  )));
+      Assert.assertTrue(message.hasField(f("default_bytes"   )));
+
+      Assert.assertTrue(message.hasField(f("default_nested_enum" )));
+      Assert.assertTrue(message.hasField(f("default_foreign_enum")));
+      Assert.assertTrue(message.hasField(f("default_import_enum" )));
+
+      Assert.assertTrue(message.hasField(f("default_string_piece")));
+      Assert.assertTrue(message.hasField(f("default_cord")));
+
+      Assert.assertEquals(401  , message.getField(f("default_int32"   )));
+      Assert.assertEquals(402L , message.getField(f("default_int64"   )));
+      Assert.assertEquals(403  , message.getField(f("default_uint32"  )));
+      Assert.assertEquals(404L , message.getField(f("default_uint64"  )));
+      Assert.assertEquals(405  , message.getField(f("default_sint32"  )));
+      Assert.assertEquals(406L , message.getField(f("default_sint64"  )));
+      Assert.assertEquals(407  , message.getField(f("default_fixed32" )));
+      Assert.assertEquals(408L , message.getField(f("default_fixed64" )));
+      Assert.assertEquals(409  , message.getField(f("default_sfixed32")));
+      Assert.assertEquals(410L , message.getField(f("default_sfixed64")));
+      Assert.assertEquals(411F , message.getField(f("default_float"   )));
+      Assert.assertEquals(412D , message.getField(f("default_double"  )));
+      Assert.assertEquals(false, message.getField(f("default_bool"    )));
+      Assert.assertEquals("415", message.getField(f("default_string"  )));
+      Assert.assertEquals(toBytes("416"), message.getField(f("default_bytes")));
+
+      Assert.assertEquals( nestedFoo, message.getField(f("default_nested_enum" )));
+      Assert.assertEquals(foreignFoo, message.getField(f("default_foreign_enum")));
+      Assert.assertEquals( importFoo, message.getField(f("default_import_enum" )));
+
+      Assert.assertEquals("424", message.getField(f("default_string_piece")));
+      Assert.assertEquals("425", message.getField(f("default_cord")));
+
+      Assert.assertTrue(message.hasField(f("oneof_bytes")));
+      Assert.assertEquals(toBytes("604"), message.getField(f("oneof_bytes")));
+
+      if (extensionRegistry == null) {
+        Assert.assertFalse(message.hasField(f("oneof_uint32")));
+        Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+        Assert.assertFalse(message.hasField(f("oneof_string")));
+      } else {
+        Assert.assertTrue(message.hasField(f("oneof_uint32")));
+        Assert.assertTrue(message.hasField(f("oneof_nested_message")));
+        Assert.assertTrue(message.hasField(f("oneof_string")));
+        Assert.assertEquals(601, message.getField(f("oneof_uint32")));
+        Assert.assertEquals(602,
+            ((MessageOrBuilder) message.getField(f("oneof_nested_message")))
+            .getField(nestedB));
+        Assert.assertEquals("603", message.getField(f("oneof_string")));
+      }
+    }
+
+    // -------------------------------------------------------------------
+
+    /**
+     * Assert (using {@code junit.framework.Assert}} that all fields of
+     * {@code message} are cleared, and that getting the fields returns their
+     * default values, using the {@link Message} reflection interface.
+     */
+    public void assertClearViaReflection(MessageOrBuilder message) {
+      // has_blah() should initially be false for all optional fields.
+      Assert.assertFalse(message.hasField(f("optional_int32"   )));
+      Assert.assertFalse(message.hasField(f("optional_int64"   )));
+      Assert.assertFalse(message.hasField(f("optional_uint32"  )));
+      Assert.assertFalse(message.hasField(f("optional_uint64"  )));
+      Assert.assertFalse(message.hasField(f("optional_sint32"  )));
+      Assert.assertFalse(message.hasField(f("optional_sint64"  )));
+      Assert.assertFalse(message.hasField(f("optional_fixed32" )));
+      Assert.assertFalse(message.hasField(f("optional_fixed64" )));
+      Assert.assertFalse(message.hasField(f("optional_sfixed32")));
+      Assert.assertFalse(message.hasField(f("optional_sfixed64")));
+      Assert.assertFalse(message.hasField(f("optional_float"   )));
+      Assert.assertFalse(message.hasField(f("optional_double"  )));
+      Assert.assertFalse(message.hasField(f("optional_bool"    )));
+      Assert.assertFalse(message.hasField(f("optional_string"  )));
+      Assert.assertFalse(message.hasField(f("optional_bytes"   )));
+
+      Assert.assertFalse(message.hasField(f("optionalgroup"           )));
+      Assert.assertFalse(message.hasField(f("optional_nested_message" )));
+      Assert.assertFalse(message.hasField(f("optional_foreign_message")));
+      Assert.assertFalse(message.hasField(f("optional_import_message" )));
+
+      Assert.assertFalse(message.hasField(f("optional_nested_enum" )));
+      Assert.assertFalse(message.hasField(f("optional_foreign_enum")));
+      Assert.assertFalse(message.hasField(f("optional_import_enum" )));
+
+      Assert.assertFalse(message.hasField(f("optional_string_piece")));
+      Assert.assertFalse(message.hasField(f("optional_cord")));
+
+      // Optional fields without defaults are set to zero or something like it.
+      Assert.assertEquals(0    , message.getField(f("optional_int32"   )));
+      Assert.assertEquals(0L   , message.getField(f("optional_int64"   )));
+      Assert.assertEquals(0    , message.getField(f("optional_uint32"  )));
+      Assert.assertEquals(0L   , message.getField(f("optional_uint64"  )));
+      Assert.assertEquals(0    , message.getField(f("optional_sint32"  )));
+      Assert.assertEquals(0L   , message.getField(f("optional_sint64"  )));
+      Assert.assertEquals(0    , message.getField(f("optional_fixed32" )));
+      Assert.assertEquals(0L   , message.getField(f("optional_fixed64" )));
+      Assert.assertEquals(0    , message.getField(f("optional_sfixed32")));
+      Assert.assertEquals(0L   , message.getField(f("optional_sfixed64")));
+      Assert.assertEquals(0F   , message.getField(f("optional_float"   )));
+      Assert.assertEquals(0D   , message.getField(f("optional_double"  )));
+      Assert.assertEquals(false, message.getField(f("optional_bool"    )));
+      Assert.assertEquals(""   , message.getField(f("optional_string"  )));
+      Assert.assertEquals(ByteString.EMPTY, message.getField(f("optional_bytes")));
+
+      // Embedded messages should also be clear.
+      Assert.assertFalse(
+        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_nested_message")))
+                         .hasField(nestedB));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .hasField(foreignC));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_import_message")))
+                         .hasField(importD));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .hasField(importE));
+      Assert.assertFalse(
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .hasField(nestedB));
+
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_nested_message")))
+                         .getField(nestedB));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_foreign_message")))
+                         .getField(foreignC));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_import_message")))
+                         .getField(importD));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_public_import_message")))
+                         .getField(importE));
+      Assert.assertEquals(0,
+        ((Message)message.getField(f("optional_lazy_message")))
+                         .getField(nestedB));
+
+      // Enums without defaults are set to the first value in the enum.
+      Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
+      Assert.assertEquals(foreignFoo, message.getField(f("optional_foreign_enum")));
+      Assert.assertEquals( importFoo, message.getField(f("optional_import_enum" )));
+
+      Assert.assertEquals("", message.getField(f("optional_string_piece")));
+      Assert.assertEquals("", message.getField(f("optional_cord")));
+
+      // Repeated fields are empty.
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      // has_blah() should also be false for all default fields.
+      Assert.assertFalse(message.hasField(f("default_int32"   )));
+      Assert.assertFalse(message.hasField(f("default_int64"   )));
+      Assert.assertFalse(message.hasField(f("default_uint32"  )));
+      Assert.assertFalse(message.hasField(f("default_uint64"  )));
+      Assert.assertFalse(message.hasField(f("default_sint32"  )));
+      Assert.assertFalse(message.hasField(f("default_sint64"  )));
+      Assert.assertFalse(message.hasField(f("default_fixed32" )));
+      Assert.assertFalse(message.hasField(f("default_fixed64" )));
+      Assert.assertFalse(message.hasField(f("default_sfixed32")));
+      Assert.assertFalse(message.hasField(f("default_sfixed64")));
+      Assert.assertFalse(message.hasField(f("default_float"   )));
+      Assert.assertFalse(message.hasField(f("default_double"  )));
+      Assert.assertFalse(message.hasField(f("default_bool"    )));
+      Assert.assertFalse(message.hasField(f("default_string"  )));
+      Assert.assertFalse(message.hasField(f("default_bytes"   )));
+
+      Assert.assertFalse(message.hasField(f("default_nested_enum" )));
+      Assert.assertFalse(message.hasField(f("default_foreign_enum")));
+      Assert.assertFalse(message.hasField(f("default_import_enum" )));
+
+      Assert.assertFalse(message.hasField(f("default_string_piece" )));
+      Assert.assertFalse(message.hasField(f("default_cord" )));
+
+      // Fields with defaults have their default values (duh).
+      Assert.assertEquals( 41    , message.getField(f("default_int32"   )));
+      Assert.assertEquals( 42L   , message.getField(f("default_int64"   )));
+      Assert.assertEquals( 43    , message.getField(f("default_uint32"  )));
+      Assert.assertEquals( 44L   , message.getField(f("default_uint64"  )));
+      Assert.assertEquals(-45    , message.getField(f("default_sint32"  )));
+      Assert.assertEquals( 46L   , message.getField(f("default_sint64"  )));
+      Assert.assertEquals( 47    , message.getField(f("default_fixed32" )));
+      Assert.assertEquals( 48L   , message.getField(f("default_fixed64" )));
+      Assert.assertEquals( 49    , message.getField(f("default_sfixed32")));
+      Assert.assertEquals(-50L   , message.getField(f("default_sfixed64")));
+      Assert.assertEquals( 51.5F , message.getField(f("default_float"   )));
+      Assert.assertEquals( 52e3D , message.getField(f("default_double"  )));
+      Assert.assertEquals(true   , message.getField(f("default_bool"    )));
+      Assert.assertEquals("hello", message.getField(f("default_string"  )));
+      Assert.assertEquals(toBytes("world"), message.getField(f("default_bytes")));
+
+      Assert.assertEquals( nestedBar, message.getField(f("default_nested_enum" )));
+      Assert.assertEquals(foreignBar, message.getField(f("default_foreign_enum")));
+      Assert.assertEquals( importBar, message.getField(f("default_import_enum" )));
+
+      Assert.assertEquals("abc", message.getField(f("default_string_piece")));
+      Assert.assertEquals("123", message.getField(f("default_cord")));
+
+      Assert.assertFalse(message.hasField(f("oneof_uint32")));
+      Assert.assertFalse(message.hasField(f("oneof_nested_message")));
+      Assert.assertFalse(message.hasField(f("oneof_string")));
+      Assert.assertFalse(message.hasField(f("oneof_bytes")));
+
+      Assert.assertEquals(0, message.getField(f("oneof_uint32")));
+      Assert.assertEquals("", message.getField(f("oneof_string")));
+      Assert.assertEquals(toBytes(""), message.getField(f("oneof_bytes")));
+    }
+
+
+    // ---------------------------------------------------------------
+
+    public void assertRepeatedFieldsModifiedViaReflection(
+        MessageOrBuilder message) {
+      // ModifyRepeatedFields only sets the second repeated element of each
+      // field.  In addition to verifying this, we also verify that the first
+      // element and size were *not* modified.
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
+
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
+      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
+      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
+      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
+      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
+      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
+      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
+      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
+      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
+      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
+      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
+      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+      Assert.assertEquals(217,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(218,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+                         .getField(nestedB));
+      Assert.assertEquals(219,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+                         .getField(foreignC));
+      Assert.assertEquals(220,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+                         .getField(importD));
+      Assert.assertEquals(227,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+      Assert.assertEquals(501  , message.getRepeatedField(f("repeated_int32"   ), 1));
+      Assert.assertEquals(502L , message.getRepeatedField(f("repeated_int64"   ), 1));
+      Assert.assertEquals(503  , message.getRepeatedField(f("repeated_uint32"  ), 1));
+      Assert.assertEquals(504L , message.getRepeatedField(f("repeated_uint64"  ), 1));
+      Assert.assertEquals(505  , message.getRepeatedField(f("repeated_sint32"  ), 1));
+      Assert.assertEquals(506L , message.getRepeatedField(f("repeated_sint64"  ), 1));
+      Assert.assertEquals(507  , message.getRepeatedField(f("repeated_fixed32" ), 1));
+      Assert.assertEquals(508L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+      Assert.assertEquals(509  , message.getRepeatedField(f("repeated_sfixed32"), 1));
+      Assert.assertEquals(510L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+      Assert.assertEquals(511F , message.getRepeatedField(f("repeated_float"   ), 1));
+      Assert.assertEquals(512D , message.getRepeatedField(f("repeated_double"  ), 1));
+      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 1));
+      Assert.assertEquals("515", message.getRepeatedField(f("repeated_string"  ), 1));
+      Assert.assertEquals(toBytes("516"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+      Assert.assertEquals(517,
+        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+                         .getField(repeatedGroupA));
+      Assert.assertEquals(518,
+        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+                         .getField(nestedB));
+      Assert.assertEquals(519,
+        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+                         .getField(foreignC));
+      Assert.assertEquals(520,
+        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+                         .getField(importD));
+      Assert.assertEquals(527,
+        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
+                         .getField(nestedB));
+
+      Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
+      Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
+      Assert.assertEquals( importFoo, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+      Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1));
+      Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1));
+    }
+
+    public void setPackedFieldsViaReflection(Message.Builder message) {
+      message.addRepeatedField(f("packed_int32"   ), 601 );
+      message.addRepeatedField(f("packed_int64"   ), 602L);
+      message.addRepeatedField(f("packed_uint32"  ), 603 );
+      message.addRepeatedField(f("packed_uint64"  ), 604L);
+      message.addRepeatedField(f("packed_sint32"  ), 605 );
+      message.addRepeatedField(f("packed_sint64"  ), 606L);
+      message.addRepeatedField(f("packed_fixed32" ), 607 );
+      message.addRepeatedField(f("packed_fixed64" ), 608L);
+      message.addRepeatedField(f("packed_sfixed32"), 609 );
+      message.addRepeatedField(f("packed_sfixed64"), 610L);
+      message.addRepeatedField(f("packed_float"   ), 611F);
+      message.addRepeatedField(f("packed_double"  ), 612D);
+      message.addRepeatedField(f("packed_bool"    ), true);
+      message.addRepeatedField(f("packed_enum" ),  foreignBar);
+      // Add a second one of each field.
+      message.addRepeatedField(f("packed_int32"   ), 701 );
+      message.addRepeatedField(f("packed_int64"   ), 702L);
+      message.addRepeatedField(f("packed_uint32"  ), 703 );
+      message.addRepeatedField(f("packed_uint64"  ), 704L);
+      message.addRepeatedField(f("packed_sint32"  ), 705 );
+      message.addRepeatedField(f("packed_sint64"  ), 706L);
+      message.addRepeatedField(f("packed_fixed32" ), 707 );
+      message.addRepeatedField(f("packed_fixed64" ), 708L);
+      message.addRepeatedField(f("packed_sfixed32"), 709 );
+      message.addRepeatedField(f("packed_sfixed64"), 710L);
+      message.addRepeatedField(f("packed_float"   ), 711F);
+      message.addRepeatedField(f("packed_double"  ), 712D);
+      message.addRepeatedField(f("packed_bool"    ), false);
+      message.addRepeatedField(f("packed_enum" ),  foreignBaz);
+    }
+
+    public void assertPackedFieldsSetViaReflection(MessageOrBuilder message) {
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int32"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int64"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint32"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint64"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed32" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed64" )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed32")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed64")));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_float"   )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_double"  )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_bool"    )));
+      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_enum"   )));
+      Assert.assertEquals(601  , message.getRepeatedField(f("packed_int32"   ), 0));
+      Assert.assertEquals(602L , message.getRepeatedField(f("packed_int64"   ), 0));
+      Assert.assertEquals(603  , message.getRepeatedField(f("packed_uint32"  ), 0));
+      Assert.assertEquals(604L , message.getRepeatedField(f("packed_uint64"  ), 0));
+      Assert.assertEquals(605  , message.getRepeatedField(f("packed_sint32"  ), 0));
+      Assert.assertEquals(606L , message.getRepeatedField(f("packed_sint64"  ), 0));
+      Assert.assertEquals(607  , message.getRepeatedField(f("packed_fixed32" ), 0));
+      Assert.assertEquals(608L , message.getRepeatedField(f("packed_fixed64" ), 0));
+      Assert.assertEquals(609  , message.getRepeatedField(f("packed_sfixed32"), 0));
+      Assert.assertEquals(610L , message.getRepeatedField(f("packed_sfixed64"), 0));
+      Assert.assertEquals(611F , message.getRepeatedField(f("packed_float"   ), 0));
+      Assert.assertEquals(612D , message.getRepeatedField(f("packed_double"  ), 0));
+      Assert.assertEquals(true , message.getRepeatedField(f("packed_bool"    ), 0));
+      Assert.assertEquals(foreignBar, message.getRepeatedField(f("packed_enum" ),0));
+      Assert.assertEquals(701  , message.getRepeatedField(f("packed_int32"   ), 1));
+      Assert.assertEquals(702L , message.getRepeatedField(f("packed_int64"   ), 1));
+      Assert.assertEquals(703  , message.getRepeatedField(f("packed_uint32"  ), 1));
+      Assert.assertEquals(704L , message.getRepeatedField(f("packed_uint64"  ), 1));
+      Assert.assertEquals(705  , message.getRepeatedField(f("packed_sint32"  ), 1));
+      Assert.assertEquals(706L , message.getRepeatedField(f("packed_sint64"  ), 1));
+      Assert.assertEquals(707  , message.getRepeatedField(f("packed_fixed32" ), 1));
+      Assert.assertEquals(708L , message.getRepeatedField(f("packed_fixed64" ), 1));
+      Assert.assertEquals(709  , message.getRepeatedField(f("packed_sfixed32"), 1));
+      Assert.assertEquals(710L , message.getRepeatedField(f("packed_sfixed64"), 1));
+      Assert.assertEquals(711F , message.getRepeatedField(f("packed_float"   ), 1));
+      Assert.assertEquals(712D , message.getRepeatedField(f("packed_double"  ), 1));
+      Assert.assertEquals(false, message.getRepeatedField(f("packed_bool"    ), 1));
+      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("packed_enum" ),1));
+    }
+
+    /**
+     * Verifies that the reflection setters for the given.Builder object throw a
+     * NullPointerException if they are passed a null value.  Uses Assert to throw an
+     * appropriate assertion failure, if the condition is not verified.
+     */
+    public void assertReflectionSettersRejectNull(Message.Builder builder)
+        throws Exception {
+      try {
+        builder.setField(f("optional_string"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_bytes"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_enum"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_message"),
+                         (TestAllTypes.NestedMessage) null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.setField(f("optional_nested_message"),
+                         (TestAllTypes.NestedMessage.Builder) null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      try {
+        builder.addRepeatedField(f("repeated_string"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_bytes"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_nested_enum"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+      try {
+        builder.addRepeatedField(f("repeated_nested_message"), null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+    }
+
+    /**
+     * Verifies that the reflection repeated setters for the given Builder object throw a
+     * NullPointerException if they are passed a null value.  Uses Assert to throw an appropriate
+     * assertion failure, if the condition is not verified.
+     */
+    public void assertReflectionRepeatedSettersRejectNull(Message.Builder builder)
+        throws Exception {
+      builder.addRepeatedField(f("repeated_string"), "one");
+      try {
+        builder.setRepeatedField(f("repeated_string"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(f("repeated_bytes"), toBytes("one"));
+      try {
+        builder.setRepeatedField(f("repeated_bytes"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(f("repeated_nested_enum"), nestedBaz);
+      try {
+        builder.setRepeatedField(f("repeated_nested_enum"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+
+      builder.addRepeatedField(
+          f("repeated_nested_message"),
+          TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+      try {
+        builder.setRepeatedField(f("repeated_nested_message"), 0, null);
+        Assert.fail("Exception was not thrown");
+      } catch (NullPointerException e) {
+        // We expect this exception.
+      }
+    }
+  }
+
+  /**
+   * @param filePath The path relative to
+   * {@link #getTestDataDir}.
+   */
+  public static String readTextFromFile(String filePath) {
+    return readBytesFromFile(filePath).toStringUtf8();
+  }
+
+  private static File getTestDataDir() {
+    // Search each parent directory looking for "src/google/protobuf".
+    File ancestor = new File(".");
+    try {
+      ancestor = ancestor.getCanonicalFile();
+    } catch (IOException e) {
+      throw new RuntimeException(
+        "Couldn't get canonical name of working directory.", e);
+    }
+    while (ancestor != null && ancestor.exists()) {
+      if (new File(ancestor, "src/google/protobuf").exists()) {
+        return new File(ancestor, "src/google/protobuf/testdata");
+      }
+      ancestor = ancestor.getParentFile();
+    }
+
+    throw new RuntimeException(
+      "Could not find golden files.  This test must be run from within the " +
+      "protobuf source package so that it can read test data files from the " +
+      "C++ source tree.");
+  }
+
+  /**
+   * @param filename The path relative to
+   * {@link #getTestDataDir}.
+   */
+  public static ByteString readBytesFromFile(String filename) {
+    File fullPath = new File(getTestDataDir(), filename);
+    try {
+      RandomAccessFile file = new RandomAccessFile(fullPath, "r");
+      byte[] content = new byte[(int) file.length()];
+      file.readFully(content);
+      return ByteString.copyFrom(content);
+    } catch (IOException e) {
+      // Throw a RuntimeException here so that we can call this function from
+      // static initializers.
+      throw new IllegalArgumentException(
+        "Couldn't read file: " + fullPath.getPath(), e);
+    }
+  }
+
+  /**
+   * Get the bytes of the "golden message".  This is a serialized TestAllTypes
+   * with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
+   * on disk rather than generated dynamically.  The file is actually generated
+   * by C++ code, so testing against it verifies compatibility with C++.
+   */
+  public static ByteString getGoldenMessage() {
+    if (goldenMessage == null) {
+      goldenMessage = readBytesFromFile("golden_message_oneof_implemented");
+    }
+    return goldenMessage;
+  }
+  private static ByteString goldenMessage = null;
+
+  /**
+   * Get the bytes of the "golden packed fields message".  This is a serialized
+   * TestPackedTypes with all fields set as they would be by
+   * {@link #setPackedFields(TestPackedTypes.Builder)}, but it is loaded from a
+   * file on disk rather than generated dynamically.  The file is actually
+   * generated by C++ code, so testing against it verifies compatibility with
+   * C++.
+   */
+  public static ByteString getGoldenPackedFieldsMessage() {
+    if (goldenPackedFieldsMessage == null) {
+      goldenPackedFieldsMessage =
+          readBytesFromFile("golden_packed_fields_message");
+    }
+    return goldenPackedFieldsMessage;
+  }
+  private static ByteString goldenPackedFieldsMessage = null;
+
+  /**
+   * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
+   *
+   * @author jonp@google.com (Jon Perlow)
+   */
+  public static class MockBuilderParent
+      implements GeneratedMessage.BuilderParent {
+
+    private int invalidations;
+
+    @Override
+    public void markDirty() {
+      invalidations++;
+    }
+
+    public int getInvalidationCount() {
+      return invalidations;
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtilLite.java b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
new file mode 100644
index 0000000..8f33fa1
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java
@@ -0,0 +1,559 @@
+// 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.
+
+package com.google.protobuf;
+
+import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
+import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+
+/**
+ * Contains methods for setting fields of {@code TestAllTypesLite}, {@code TestAllExtensionsLite},
+ * and {@code TestPackedExtensionsLite}. This is analogous to the functionality in TestUtil.java but
+ * does not depend on the presence of any non-lite protos.
+ *
+ * <p>This code is not to be used outside of {@code com.google.protobuf} and
+ * subpackages.
+ */
+public final class TestUtilLite {
+  private TestUtilLite() {}
+
+  /** Helper to convert a String to ByteString. */
+  static ByteString toBytes(String str) {
+    return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
+  }
+
+  /**
+   * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypesLite.Builder)}.
+   */
+  public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    setAllFields(builder);
+    return builder;
+  }
+
+  /**
+   * Get a {@code TestAllExtensionsLite} with all fields set as they would be by
+   * {@link #setAllExtensions(TestAllExtensionsLite.Builder)}.
+   */
+  public static TestAllExtensionsLite getAllLiteExtensionsSet() {
+    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+    setAllExtensions(builder);
+    return builder.build();
+  }
+
+  public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
+    TestPackedExtensionsLite.Builder builder = TestPackedExtensionsLite.newBuilder();
+    setPackedExtensions(builder);
+    return builder.build();
+  }
+  
+  /**
+   * Set every field of {@code builder} to the values expected by
+   * {@code assertAllFieldsSet()}.
+   */
+  public static void setAllFields(TestAllTypesLite.Builder builder) {
+    builder.setOptionalInt32   (101);
+    builder.setOptionalInt64   (102);
+    builder.setOptionalUint32  (103);
+    builder.setOptionalUint64  (104);
+    builder.setOptionalSint32  (105);
+    builder.setOptionalSint64  (106);
+    builder.setOptionalFixed32 (107);
+    builder.setOptionalFixed64 (108);
+    builder.setOptionalSfixed32(109);
+    builder.setOptionalSfixed64(110);
+    builder.setOptionalFloat   (111);
+    builder.setOptionalDouble  (112);
+    builder.setOptionalBool    (true);
+    builder.setOptionalString  ("115");
+    builder.setOptionalBytes   (toBytes("116"));
+
+    builder.setOptionalGroup(
+        TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
+    builder.setOptionalNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    builder.setOptionalForeignMessage(
+        ForeignMessageLite.newBuilder().setC(119).build());
+    builder.setOptionalImportMessage(
+        ImportMessageLite.newBuilder().setD(120).build());
+    builder.setOptionalPublicImportMessage(
+        PublicImportMessageLite.newBuilder().setE(126).build());
+    builder.setOptionalLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+    builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.setOptionalStringPiece("124");
+    builder.setOptionalCord("125");
+
+    // -----------------------------------------------------------------
+
+    builder.addRepeatedInt32   (201);
+    builder.addRepeatedInt64   (202);
+    builder.addRepeatedUint32  (203);
+    builder.addRepeatedUint64  (204);
+    builder.addRepeatedSint32  (205);
+    builder.addRepeatedSint64  (206);
+    builder.addRepeatedFixed32 (207);
+    builder.addRepeatedFixed64 (208);
+    builder.addRepeatedSfixed32(209);
+    builder.addRepeatedSfixed64(210);
+    builder.addRepeatedFloat   (211);
+    builder.addRepeatedDouble  (212);
+    builder.addRepeatedBool    (true);
+    builder.addRepeatedString  ("215");
+    builder.addRepeatedBytes   (toBytes("216"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(219).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(220).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
+
+    builder.addRepeatedStringPiece("224");
+    builder.addRepeatedCord("225");
+
+    // Add a second one of each field.
+    builder.addRepeatedInt32   (301);
+    builder.addRepeatedInt64   (302);
+    builder.addRepeatedUint32  (303);
+    builder.addRepeatedUint64  (304);
+    builder.addRepeatedSint32  (305);
+    builder.addRepeatedSint64  (306);
+    builder.addRepeatedFixed32 (307);
+    builder.addRepeatedFixed64 (308);
+    builder.addRepeatedSfixed32(309);
+    builder.addRepeatedSfixed64(310);
+    builder.addRepeatedFloat   (311);
+    builder.addRepeatedDouble  (312);
+    builder.addRepeatedBool    (false);
+    builder.addRepeatedString  ("315");
+    builder.addRepeatedBytes   (toBytes("316"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(319).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(320).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.addRepeatedStringPiece("324");
+    builder.addRepeatedCord("325");
+
+    // -----------------------------------------------------------------
+
+    builder.setDefaultInt32   (401);
+    builder.setDefaultInt64   (402);
+    builder.setDefaultUint32  (403);
+    builder.setDefaultUint64  (404);
+    builder.setDefaultSint32  (405);
+    builder.setDefaultSint64  (406);
+    builder.setDefaultFixed32 (407);
+    builder.setDefaultFixed64 (408);
+    builder.setDefaultSfixed32(409);
+    builder.setDefaultSfixed64(410);
+    builder.setDefaultFloat   (411);
+    builder.setDefaultDouble  (412);
+    builder.setDefaultBool    (false);
+    builder.setDefaultString  ("415");
+    builder.setDefaultBytes   (toBytes("416"));
+
+    builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
+    builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
+    builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
+
+    builder.setDefaultStringPiece("424");
+    builder.setDefaultCord("425");
+
+    builder.setOneofUint32(601);
+    builder.setOneofNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    builder.setOneofString("603");
+    builder.setOneofBytes(toBytes("604"));
+  }
+
+  /**
+   * Get an unmodifiable {@link ExtensionRegistryLite} containing all the
+   * extensions of {@code TestAllExtensionsLite}.
+   */
+  public static ExtensionRegistryLite getExtensionRegistryLite() {
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    registerAllExtensionsLite(registry);
+    return registry.getUnmodifiable();
+  }
+
+  /**
+   * Register all of {@code TestAllExtensionsLite}'s extensions with the
+   * given {@link ExtensionRegistryLite}.
+   */
+  public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
+    UnittestLite.registerAllExtensions(registry);
+  }
+
+  // ===================================================================
+  // Lite extensions
+
+  /**
+   * Set every field of {@code message} to the values expected by
+   * {@code assertAllExtensionsSet()}.
+   */
+  public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
+    message.setExtension(optionalInt32ExtensionLite   , 101);
+    message.setExtension(optionalInt64ExtensionLite   , 102L);
+    message.setExtension(optionalUint32ExtensionLite  , 103);
+    message.setExtension(optionalUint64ExtensionLite  , 104L);
+    message.setExtension(optionalSint32ExtensionLite  , 105);
+    message.setExtension(optionalSint64ExtensionLite  , 106L);
+    message.setExtension(optionalFixed32ExtensionLite , 107);
+    message.setExtension(optionalFixed64ExtensionLite , 108L);
+    message.setExtension(optionalSfixed32ExtensionLite, 109);
+    message.setExtension(optionalSfixed64ExtensionLite, 110L);
+    message.setExtension(optionalFloatExtensionLite   , 111F);
+    message.setExtension(optionalDoubleExtensionLite  , 112D);
+    message.setExtension(optionalBoolExtensionLite    , true);
+    message.setExtension(optionalStringExtensionLite  , "115");
+    message.setExtension(optionalBytesExtensionLite   , toBytes("116"));
+
+    message.setExtension(optionalGroupExtensionLite,
+      OptionalGroup_extension_lite.newBuilder().setA(117).build());
+    message.setExtension(optionalNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    message.setExtension(optionalForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(119).build());
+    message.setExtension(optionalImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(120).build());
+    message.setExtension(optionalPublicImportMessageExtensionLite,
+      PublicImportMessageLite.newBuilder().setE(126).build());
+    message.setExtension(optionalLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+    message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.setExtension(optionalStringPieceExtensionLite, "124");
+    message.setExtension(optionalCordExtensionLite, "125");
+
+    // -----------------------------------------------------------------
+
+    message.addExtension(repeatedInt32ExtensionLite   , 201);
+    message.addExtension(repeatedInt64ExtensionLite   , 202L);
+    message.addExtension(repeatedUint32ExtensionLite  , 203);
+    message.addExtension(repeatedUint64ExtensionLite  , 204L);
+    message.addExtension(repeatedSint32ExtensionLite  , 205);
+    message.addExtension(repeatedSint64ExtensionLite  , 206L);
+    message.addExtension(repeatedFixed32ExtensionLite , 207);
+    message.addExtension(repeatedFixed64ExtensionLite , 208L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 209);
+    message.addExtension(repeatedSfixed64ExtensionLite, 210L);
+    message.addExtension(repeatedFloatExtensionLite   , 211F);
+    message.addExtension(repeatedDoubleExtensionLite  , 212D);
+    message.addExtension(repeatedBoolExtensionLite    , true);
+    message.addExtension(repeatedStringExtensionLite  , "215");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("216"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(217).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(219).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(220).build());
+    message.addExtension(repeatedLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "224");
+    message.addExtension(repeatedCordExtensionLite, "225");
+
+    // Add a second one of each field.
+    message.addExtension(repeatedInt32ExtensionLite   , 301);
+    message.addExtension(repeatedInt64ExtensionLite   , 302L);
+    message.addExtension(repeatedUint32ExtensionLite  , 303);
+    message.addExtension(repeatedUint64ExtensionLite  , 304L);
+    message.addExtension(repeatedSint32ExtensionLite  , 305);
+    message.addExtension(repeatedSint64ExtensionLite  , 306L);
+    message.addExtension(repeatedFixed32ExtensionLite , 307);
+    message.addExtension(repeatedFixed64ExtensionLite , 308L);
+    message.addExtension(repeatedSfixed32ExtensionLite, 309);
+    message.addExtension(repeatedSfixed64ExtensionLite, 310L);
+    message.addExtension(repeatedFloatExtensionLite   , 311F);
+    message.addExtension(repeatedDoubleExtensionLite  , 312D);
+    message.addExtension(repeatedBoolExtensionLite    , false);
+    message.addExtension(repeatedStringExtensionLite  , "315");
+    message.addExtension(repeatedBytesExtensionLite   , toBytes("316"));
+
+    message.addExtension(repeatedGroupExtensionLite,
+      RepeatedGroup_extension_lite.newBuilder().setA(317).build());
+    message.addExtension(repeatedNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    message.addExtension(repeatedForeignMessageExtensionLite,
+      ForeignMessageLite.newBuilder().setC(319).build());
+    message.addExtension(repeatedImportMessageExtensionLite,
+      ImportMessageLite.newBuilder().setD(320).build());
+    message.addExtension(repeatedLazyMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+    message.addExtension(repeatedStringPieceExtensionLite, "324");
+    message.addExtension(repeatedCordExtensionLite, "325");
+
+    // -----------------------------------------------------------------
+
+    message.setExtension(defaultInt32ExtensionLite   , 401);
+    message.setExtension(defaultInt64ExtensionLite   , 402L);
+    message.setExtension(defaultUint32ExtensionLite  , 403);
+    message.setExtension(defaultUint64ExtensionLite  , 404L);
+    message.setExtension(defaultSint32ExtensionLite  , 405);
+    message.setExtension(defaultSint64ExtensionLite  , 406L);
+    message.setExtension(defaultFixed32ExtensionLite , 407);
+    message.setExtension(defaultFixed64ExtensionLite , 408L);
+    message.setExtension(defaultSfixed32ExtensionLite, 409);
+    message.setExtension(defaultSfixed64ExtensionLite, 410L);
+    message.setExtension(defaultFloatExtensionLite   , 411F);
+    message.setExtension(defaultDoubleExtensionLite  , 412D);
+    message.setExtension(defaultBoolExtensionLite    , false);
+    message.setExtension(defaultStringExtensionLite  , "415");
+    message.setExtension(defaultBytesExtensionLite   , toBytes("416"));
+
+    message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(defaultStringPieceExtensionLite, "424");
+    message.setExtension(defaultCordExtensionLite, "425");
+
+    message.setExtension(oneofUint32ExtensionLite, 601);
+    message.setExtension(oneofNestedMessageExtensionLite,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    message.setExtension(oneofStringExtensionLite, "603");
+    message.setExtension(oneofBytesExtensionLite, toBytes("604"));
+  }
+
+  // -------------------------------------------------------------------
+
+  /**
+   * Modify the repeated extensions of {@code message} to contain the values
+   * expected by {@code assertRepeatedExtensionsModified()}.
+   */
+  public static void modifyRepeatedExtensions(
+      TestAllExtensionsLite.Builder message) {
+    message.setExtension(repeatedInt32ExtensionLite   , 1, 501);
+    message.setExtension(repeatedInt64ExtensionLite   , 1, 502L);
+    message.setExtension(repeatedUint32ExtensionLite  , 1, 503);
+    message.setExtension(repeatedUint64ExtensionLite  , 1, 504L);
+    message.setExtension(repeatedSint32ExtensionLite  , 1, 505);
+    message.setExtension(repeatedSint64ExtensionLite  , 1, 506L);
+    message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
+    message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
+    message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
+    message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
+    message.setExtension(repeatedFloatExtensionLite   , 1, 511F);
+    message.setExtension(repeatedDoubleExtensionLite  , 1, 512D);
+    message.setExtension(repeatedBoolExtensionLite    , 1, true);
+    message.setExtension(repeatedStringExtensionLite  , 1, "515");
+    message.setExtension(repeatedBytesExtensionLite   , 1, toBytes("516"));
+
+    message.setExtension(repeatedGroupExtensionLite, 1,
+      RepeatedGroup_extension_lite.newBuilder().setA(517).build());
+    message.setExtension(repeatedNestedMessageExtensionLite, 1,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
+    message.setExtension(repeatedForeignMessageExtensionLite, 1,
+      ForeignMessageLite.newBuilder().setC(519).build());
+    message.setExtension(repeatedImportMessageExtensionLite, 1,
+      ImportMessageLite.newBuilder().setD(520).build());
+    message.setExtension(repeatedLazyMessageExtensionLite, 1,
+      TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
+
+    message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
+    message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
+    message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
+
+    message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
+    message.setExtension(repeatedCordExtensionLite, 1, "525");
+  }
+
+  public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
+    message.addExtension(packedInt32ExtensionLite   , 601);
+    message.addExtension(packedInt64ExtensionLite   , 602L);
+    message.addExtension(packedUint32ExtensionLite  , 603);
+    message.addExtension(packedUint64ExtensionLite  , 604L);
+    message.addExtension(packedSint32ExtensionLite  , 605);
+    message.addExtension(packedSint64ExtensionLite  , 606L);
+    message.addExtension(packedFixed32ExtensionLite , 607);
+    message.addExtension(packedFixed64ExtensionLite , 608L);
+    message.addExtension(packedSfixed32ExtensionLite, 609);
+    message.addExtension(packedSfixed64ExtensionLite, 610L);
+    message.addExtension(packedFloatExtensionLite   , 611F);
+    message.addExtension(packedDoubleExtensionLite  , 612D);
+    message.addExtension(packedBoolExtensionLite    , true);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+    // Add a second one of each field.
+    message.addExtension(packedInt32ExtensionLite   , 701);
+    message.addExtension(packedInt64ExtensionLite   , 702L);
+    message.addExtension(packedUint32ExtensionLite  , 703);
+    message.addExtension(packedUint64ExtensionLite  , 704L);
+    message.addExtension(packedSint32ExtensionLite  , 705);
+    message.addExtension(packedSint64ExtensionLite  , 706L);
+    message.addExtension(packedFixed32ExtensionLite , 707);
+    message.addExtension(packedFixed64ExtensionLite , 708L);
+    message.addExtension(packedSfixed32ExtensionLite, 709);
+    message.addExtension(packedSfixed64ExtensionLite, 710L);
+    message.addExtension(packedFloatExtensionLite   , 711F);
+    message.addExtension(packedDoubleExtensionLite  , 712D);
+    message.addExtension(packedBoolExtensionLite    , false);
+    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
new file mode 100644
index 0000000..e338af2
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java
@@ -0,0 +1,182 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseInfoTree}.
+ */
+public class TextFormatParseInfoTreeTest extends TestCase {
+
+  private static final Descriptor DESCRIPTOR = TestAllTypes.getDescriptor();
+  private static final FieldDescriptor OPTIONAL_INT32 =
+      DESCRIPTOR.findFieldByName("optional_int32");
+  private static final FieldDescriptor OPTIONAL_BOOLEAN =
+      DESCRIPTOR.findFieldByName("optional_boolean");
+  private static final FieldDescriptor REPEATED_INT32 =
+      DESCRIPTOR.findFieldByName("repeated_int32");
+  private static final FieldDescriptor OPTIONAL_NESTED_MESSAGE =
+      DESCRIPTOR.findFieldByName("optional_nested_message");
+  private static final FieldDescriptor REPEATED_NESTED_MESSAGE =
+      DESCRIPTOR.findFieldByName("repeated_nested_message");
+  private static final FieldDescriptor FIELD_BB =
+      TestAllTypes.NestedMessage.getDescriptor().findFieldByName("bb");
+
+  private static final TextFormatParseLocation LOC0 = TextFormatParseLocation.create(1, 2);
+  private static final TextFormatParseLocation LOC1 = TextFormatParseLocation.create(2, 3);
+
+  private TextFormatParseInfoTree.Builder rootBuilder;
+
+  @Override
+  public void setUp() {
+    rootBuilder = TextFormatParseInfoTree.builder();
+  }
+
+  public void testBuildEmptyParseTree() {
+    TextFormatParseInfoTree tree = rootBuilder.build();
+    assertTrue(tree.getLocations(null).isEmpty());
+  }
+
+  public void testGetLocationReturnsSingleLocation() {
+    rootBuilder.setLocation(OPTIONAL_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertEquals(LOC0, root.getLocation(OPTIONAL_INT32, 0));
+    assertEquals(1, root.getLocations(OPTIONAL_INT32).size());
+    }
+
+  public void testGetLocationsReturnsNoParseLocationsForUnknownField() {
+    assertTrue(rootBuilder.build().getLocations(OPTIONAL_INT32).isEmpty());
+    rootBuilder.setLocation(OPTIONAL_BOOLEAN, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertTrue(root.getLocations(OPTIONAL_INT32).isEmpty());
+    assertEquals(LOC0, root.getLocations(OPTIONAL_BOOLEAN).get(0));
+  }
+
+  public void testGetLocationThrowsIllegalArgumentExceptionForUnknownField() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    try {
+      root.getNestedTree(OPTIONAL_INT32, 0);
+      fail("Did not detect unknown field");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetLocationThrowsIllegalArgumentExceptionForInvalidIndex() {
+    TextFormatParseInfoTree root = rootBuilder.setLocation(OPTIONAL_INT32, LOC0).build();
+    try {
+      root.getLocation(OPTIONAL_INT32, 1);
+      fail("Invalid index not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+    try {
+      root.getLocation(OPTIONAL_INT32, -1);
+      fail("Negative index not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetLocationsReturnsMultipleLocations() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    rootBuilder.setLocation(REPEATED_INT32, LOC1);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertEquals(LOC0, root.getLocation(REPEATED_INT32, 0));
+    assertEquals(LOC1, root.getLocation(REPEATED_INT32, 1));
+    assertEquals(2, root.getLocations(REPEATED_INT32).size());
+  }
+
+  public void testGetNestedTreeThrowsIllegalArgumentExceptionForUnknownField() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    try {
+      root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 0);
+      fail("Did not detect unknown field");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetNestedTreesReturnsNoParseInfoTreesForUnknownField() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertTrue(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).isEmpty());
+  }
+
+  public void testGetNestedTreeThrowsIllegalArgumentExceptionForInvalidIndex() {
+    rootBuilder.setLocation(REPEATED_INT32, LOC0);
+    rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    try {
+      root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 1);
+      fail("Submessage index that is too large not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+    try {
+      rootBuilder.build().getNestedTree(OPTIONAL_NESTED_MESSAGE, -1);
+      fail("Invalid submessage index (-1) not detected");
+    } catch (IllegalArgumentException expected) {
+      // pass
+    }
+  }
+
+  public void testGetNestedTreesReturnsSingleTree() {
+    rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertEquals(1, root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).size());
+    TextFormatParseInfoTree subtree = root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).get(0);
+    assertNotNull(subtree);
+  }
+
+  public void testGetNestedTreesReturnsMultipleTrees() {
+    TextFormatParseInfoTree.Builder subtree1Builder =
+        rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
+    subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+    subtree1Builder.getBuilderForSubMessageField(FIELD_BB);
+    TextFormatParseInfoTree.Builder subtree2Builder =
+        rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE);
+    subtree2Builder.getBuilderForSubMessageField(FIELD_BB);
+    TextFormatParseInfoTree root = rootBuilder.build();
+    assertEquals(2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).size());
+    assertEquals(
+        2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(0).getNestedTrees(FIELD_BB).size());
+    assertEquals(
+        1, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(1).getNestedTrees(FIELD_BB).size());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
new file mode 100644
index 0000000..c42bfa6
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java
@@ -0,0 +1,86 @@
+// 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.
+
+package com.google.protobuf;
+
+import junit.framework.TestCase;
+
+/**
+ * Test @{link TextFormatParseLocation}.
+ */
+public class TextFormatParseLocationTest extends TestCase {
+
+  public void testCreateEmpty() {
+    TextFormatParseLocation location = TextFormatParseLocation.create(-1, -1);
+    assertEquals(TextFormatParseLocation.EMPTY, location);
+  }
+
+  public void testCreate() {
+    TextFormatParseLocation location = TextFormatParseLocation.create(2, 1);
+    assertEquals(2, location.getLine());
+    assertEquals(1, location.getColumn());
+  }
+
+  public void testCreateThrowsIllegalArgumentExceptionForInvalidIndex() {
+    try {
+      TextFormatParseLocation.create(-1, 0);
+      fail("Should throw IllegalArgumentException if line is less than 0");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+    try {
+      TextFormatParseLocation.create(0, -1);
+      fail("Should throw, column < 0");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+  }
+
+  public void testHashCode() {
+    TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
+    TextFormatParseLocation loc1 = TextFormatParseLocation.create(2, 1);
+
+    assertEquals(loc0.hashCode(), loc1.hashCode());
+    assertEquals(
+        TextFormatParseLocation.EMPTY.hashCode(), TextFormatParseLocation.EMPTY.hashCode());
+  }
+
+  public void testEquals() {
+    TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1);
+    TextFormatParseLocation loc1 = TextFormatParseLocation.create(1, 2);
+    TextFormatParseLocation loc2 = TextFormatParseLocation.create(2, 2);
+    TextFormatParseLocation loc3 = TextFormatParseLocation.create(2, 1);
+
+    assertEquals(loc0, loc3);
+    assertNotSame(loc0, loc1);
+    assertNotSame(loc0, loc2);
+    assertNotSame(loc1, loc2);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
new file mode 100644
index 0000000..63c17cd
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -0,0 +1,1129 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import protobuf_unittest.UnittestProto.OneString;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+import java.util.List;
+
+/**
+ * Test case for {@link TextFormat}.
+ *
+ * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
+ *
+ * @author wenboz@google.com (Wenbo Zhu)
+ */
+public class TextFormatTest extends TestCase {
+
+  // A basic string with different escapable characters for testing.
+  private final static String kEscapeTestString =
+      "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+          + "slashes \\";
+
+  // A representation of the above string with all the characters escaped.
+  private final static String kEscapeTestStringEscaped =
+      "\\\"A string with \\' characters \\n and \\r newlines "
+          + "and \\t tabs and \\001 slashes \\\\";
+
+  private static String allFieldsSetText = TestUtil.readTextFromFile(
+    "text_format_unittest_data_oneof_implemented.txt");
+  private static String allExtensionsSetText = TestUtil.readTextFromFile(
+    "text_format_unittest_extensions_data.txt");
+
+  private static String exoticText =
+    "repeated_int32: -1\n" +
+    "repeated_int32: -2147483648\n" +
+    "repeated_int64: -1,\n" +
+    "repeated_int64: -9223372036854775808\n" +
+    "repeated_uint32: 4294967295\n" +
+    "repeated_uint32: 2147483648\n" +
+    "repeated_uint64: 18446744073709551615\n" +
+    "repeated_uint64: 9223372036854775808\n" +
+    "repeated_double: 123.0\n" +
+    "repeated_double: 123.5\n" +
+    "repeated_double: 0.125\n" +
+    "repeated_double: .125\n" +
+    "repeated_double: -.125\n" +
+    "repeated_double: 1.23E17\n" +
+    "repeated_double: 1.23E+17\n" +
+    "repeated_double: -1.23e-17\n" +
+    "repeated_double: .23e+17\n" +
+    "repeated_double: -.23E17\n" +
+    "repeated_double: 1.235E22\n" +
+    "repeated_double: 1.235E-18\n" +
+    "repeated_double: 123.456789\n" +
+    "repeated_double: Infinity\n" +
+    "repeated_double: -Infinity\n" +
+    "repeated_double: NaN\n" +
+    "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
+      "\\341\\210\\264\"\n" +
+    "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
+
+  private static String canonicalExoticText =
+      exoticText.replace(": .", ": 0.").replace(": -.", ": -0.")   // short-form double
+      .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16").replace(",", "");
+
+  private String messageSetText =
+    "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+    "  i: 123\n" +
+    "}\n" +
+    "[protobuf_unittest.TestMessageSetExtension2] {\n" +
+    "  str: \"foo\"\n" +
+    "}\n";
+
+  private String messageSetTextWithRepeatedExtension =
+      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+      "  i: 123\n" +
+      "}\n" +
+      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+      "  i: 456\n" +
+      "}\n";
+
+
+  private final TextFormat.Parser parserWithOverwriteForbidden =
+      TextFormat.Parser.newBuilder()
+          .setSingularOverwritePolicy(
+              SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
+          .build();
+
+  private final TextFormat.Parser defaultParser =
+      TextFormat.Parser.newBuilder().build();
+
+  /** Print TestAllTypes and compare with golden file. */
+  public void testPrintMessage() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllSet());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allFieldsSetText, javaText);
+  }
+
+  /** Print TestAllTypes as Builder and compare with golden file. */
+  public void testPrintMessageBuilder() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allFieldsSetText, javaText);
+  }
+
+  /** Print TestAllExtensions and compare with golden file. */
+  public void testPrintExtensions() throws Exception {
+    String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
+
+    // Java likes to add a trailing ".0" to floats and doubles.  C printf
+    // (with %g format) does not.  Our golden files are used for both
+    // C++ and Java TextFormat classes, so we need to conform.
+    javaText = javaText.replace(".0\n", "\n");
+
+    assertEquals(allExtensionsSetText, javaText);
+  }
+
+  // Creates an example unknown field set.
+  private UnknownFieldSet makeUnknownFieldSet() {
+    return UnknownFieldSet.newBuilder()
+        .addField(5,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .addFixed32(2)
+            .addFixed64(3)
+            .addLengthDelimited(ByteString.copyFromUtf8("4"))
+            .addGroup(
+                UnknownFieldSet.newBuilder()
+                .addField(10,
+                    UnknownFieldSet.Field.newBuilder()
+                    .addVarint(5)
+                    .build())
+                .build())
+            .build())
+        .addField(8,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .addVarint(2)
+            .addVarint(3)
+            .build())
+        .addField(15,
+            UnknownFieldSet.Field.newBuilder()
+            .addVarint(0xABCDEF1234567890L)
+            .addFixed32(0xABCD1234)
+            .addFixed64(0xABCDEF1234567890L)
+            .build())
+        .build();
+  }
+
+  public void testPrintUnknownFields() throws Exception {
+    // Test printing of unknown fields in a message.
+
+    TestEmptyMessage message =
+      TestEmptyMessage.newBuilder()
+        .setUnknownFields(makeUnknownFieldSet())
+        .build();
+
+    assertEquals(
+      "5: 1\n" +
+      "5: 0x00000002\n" +
+      "5: 0x0000000000000003\n" +
+      "5: \"4\"\n" +
+      "5 {\n" +
+      "  10: 5\n" +
+      "}\n" +
+      "8: 1\n" +
+      "8: 2\n" +
+      "8: 3\n" +
+      "15: 12379813812177893520\n" +
+      "15: 0xabcd1234\n" +
+      "15: 0xabcdef1234567890\n",
+      TextFormat.printToString(message));
+  }
+
+  public void testPrintField() throws Exception {
+    final FieldDescriptor dataField =
+      OneString.getDescriptor().findFieldByName("data");
+    assertEquals(
+      "data: \"test data\"\n",
+      TextFormat.printFieldToString(dataField, "test data"));
+
+    final FieldDescriptor optionalField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+    final Object value = NestedMessage.newBuilder().setBb(42).build();
+
+    assertEquals(
+      "optional_nested_message {\n  bb: 42\n}\n",
+      TextFormat.printFieldToString(optionalField, value));
+  }
+
+  /**
+   * Helper to construct a ByteString from a String containing only 8-bit
+   * characters.  The characters are converted directly to bytes, *not*
+   * encoded using UTF-8.
+   */
+  private ByteString bytes(String str) {
+    return ByteString.copyFrom(str.getBytes(Internal.ISO_8859_1));
+  }
+
+  /**
+   * Helper to construct a ByteString from a bunch of bytes.  The inputs are
+   * actually ints so that I can use hex notation and not get stupid errors
+   * about precision.
+   */
+  private ByteString bytes(int... bytesAsInts) {
+    byte[] bytes = new byte[bytesAsInts.length];
+    for (int i = 0; i < bytesAsInts.length; i++) {
+      bytes[i] = (byte) bytesAsInts[i];
+    }
+    return ByteString.copyFrom(bytes);
+  }
+
+  public void testPrintExotic() throws Exception {
+    Message message = TestAllTypes.newBuilder()
+      // Signed vs. unsigned numbers.
+      .addRepeatedInt32 (-1)
+      .addRepeatedUint32(-1)
+      .addRepeatedInt64 (-1)
+      .addRepeatedUint64(-1)
+
+      .addRepeatedInt32 (1  << 31)
+      .addRepeatedUint32(1  << 31)
+      .addRepeatedInt64 (1L << 63)
+      .addRepeatedUint64(1L << 63)
+
+      // Floats of various precisions and exponents.
+      .addRepeatedDouble(123)
+      .addRepeatedDouble(123.5)
+      .addRepeatedDouble(0.125)
+      .addRepeatedDouble(.125)
+      .addRepeatedDouble(-.125)
+      .addRepeatedDouble(123e15)
+      .addRepeatedDouble(123e15)
+      .addRepeatedDouble(-1.23e-17)
+      .addRepeatedDouble(.23e17)
+      .addRepeatedDouble(-23e15)
+      .addRepeatedDouble(123.5e20)
+      .addRepeatedDouble(123.5e-20)
+      .addRepeatedDouble(123.456789)
+      .addRepeatedDouble(Double.POSITIVE_INFINITY)
+      .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+      .addRepeatedDouble(Double.NaN)
+
+      // Strings and bytes that needing escaping.
+      .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
+      .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
+      .build();
+
+    assertEquals(canonicalExoticText, message.toString());
+  }
+
+  public void testPrintMessageSet() throws Exception {
+    TestMessageSet messageSet =
+      TestMessageSet.newBuilder()
+        .setExtension(
+          TestMessageSetExtension1.messageSetExtension,
+          TestMessageSetExtension1.newBuilder().setI(123).build())
+        .setExtension(
+          TestMessageSetExtension2.messageSetExtension,
+          TestMessageSetExtension2.newBuilder().setStr("foo").build())
+        .build();
+
+    assertEquals(messageSetText, messageSet.toString());
+  }
+
+  // =================================================================
+
+  public void testParse() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(allFieldsSetText, builder);
+    TestUtil.assertAllFieldsSet(builder.build());
+  }
+
+  public void testParseReader() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(new StringReader(allFieldsSetText), builder);
+    TestUtil.assertAllFieldsSet(builder.build());
+  }
+
+  public void testParseExtensions() throws Exception {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    TextFormat.merge(allExtensionsSetText,
+                     TestUtil.getExtensionRegistry(),
+                     builder);
+    TestUtil.assertAllExtensionsSet(builder.build());
+  }
+
+  public void testParseCompatibility() throws Exception {
+    String original = "repeated_float: inf\n" +
+                      "repeated_float: -inf\n" +
+                      "repeated_float: nan\n" +
+                      "repeated_float: inff\n" +
+                      "repeated_float: -inff\n" +
+                      "repeated_float: nanf\n" +
+                      "repeated_float: 1.0f\n" +
+                      "repeated_float: infinityf\n" +
+                      "repeated_float: -Infinityf\n" +
+                      "repeated_double: infinity\n" +
+                      "repeated_double: -infinity\n" +
+                      "repeated_double: nan\n";
+    String canonical =  "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_float: NaN\n" +
+                        "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_float: NaN\n" +
+                        "repeated_float: 1.0\n" +
+                        "repeated_float: Infinity\n" +
+                        "repeated_float: -Infinity\n" +
+                        "repeated_double: Infinity\n" +
+                        "repeated_double: -Infinity\n" +
+                        "repeated_double: NaN\n";
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(original, builder);
+    assertEquals(canonical, builder.build().toString());
+  }
+
+  public void testParseExotic() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(exoticText, builder);
+
+    // Too lazy to check things individually.  Don't try to debug this
+    // if testPrintExotic() is failing.
+    assertEquals(canonicalExoticText, builder.build().toString());
+  }
+
+  public void testParseMessageSet() throws Exception {
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+    TextFormat.merge(messageSetText, extensionRegistry, builder);
+    TestMessageSet messageSet = builder.build();
+
+    assertTrue(messageSet.hasExtension(
+      TestMessageSetExtension1.messageSetExtension));
+    assertEquals(123, messageSet.getExtension(
+      TestMessageSetExtension1.messageSetExtension).getI());
+    assertTrue(messageSet.hasExtension(
+      TestMessageSetExtension2.messageSetExtension));
+    assertEquals("foo", messageSet.getExtension(
+      TestMessageSetExtension2.messageSetExtension).getStr());
+
+    builder = TestMessageSet.newBuilder();
+    TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry,
+        builder);
+    messageSet = builder.build();
+    assertEquals(456, messageSet.getExtension(
+      TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+    parserWithOverwriteForbidden.merge(
+        messageSetText, extensionRegistry, builder);
+    TestMessageSet messageSet = builder.build();
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+    assertEquals("foo", messageSet.getExtension(
+      TestMessageSetExtension2.messageSetExtension).getStr());
+
+    builder = TestMessageSet.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          messageSetTextWithRepeatedExtension, extensionRegistry, builder);
+      fail("expected parse exception");
+    } catch (TextFormat.ParseException e) {
+      assertEquals("6:1: Non-repeated field "
+          + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+          + " cannot be overwritten.",
+          e.getMessage());
+    }
+  }
+
+  public void testParseNumericEnum() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_nested_enum: 2", builder);
+    assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
+  }
+
+  public void testParseAngleBrackets() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("OptionalGroup: < a: 1 >", builder);
+    assertTrue(builder.hasOptionalGroup());
+    assertEquals(1, builder.getOptionalGroup().getA());
+  }
+
+  public void testParseComment() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(
+      "# this is a comment\n" +
+      "optional_int32: 1  # another comment\n" +
+      "optional_int64: 2\n" +
+      "# EOF comment", builder);
+    assertEquals(1, builder.getOptionalInt32());
+    assertEquals(2, builder.getOptionalInt64());
+  }
+
+  private void assertParseError(String error, String text) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
+  }
+
+
+  private void assertParseErrorWithOverwriteForbidden(String error,
+      String text) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          text, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
+  }
+
+  private TestAllTypes assertParseSuccessWithOverwriteForbidden(
+      String text) throws TextFormat.ParseException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    parserWithOverwriteForbidden.merge(
+        text, TestUtil.getExtensionRegistry(), builder);
+    return builder.build();
+  }
+
+  public void testParseErrors() throws Exception {
+    assertParseError(
+      "1:16: Expected \":\".",
+      "optional_int32 123");
+    assertParseError(
+      "1:23: Expected identifier. Found '?'",
+      "optional_nested_enum: ?");
+    assertParseError(
+      "1:18: Couldn't parse integer: Number must be positive: -1",
+      "optional_uint32: -1");
+    assertParseError(
+      "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
+        "integer: 82301481290849012385230157",
+      "optional_int32: 82301481290849012385230157");
+    assertParseError(
+      "1:16: Expected \"true\" or \"false\".",
+      "optional_bool: maybe");
+    assertParseError(
+      "1:16: Expected \"true\" or \"false\".",
+      "optional_bool: 2");
+    assertParseError(
+      "1:18: Expected string.",
+      "optional_string: 123");
+    assertParseError(
+      "1:18: String missing ending quote.",
+      "optional_string: \"ueoauaoe");
+    assertParseError(
+      "1:18: String missing ending quote.",
+      "optional_string: \"ueoauaoe\n" +
+      "optional_int32: 123");
+    assertParseError(
+      "1:18: Invalid escape sequence: '\\z'",
+      "optional_string: \"\\z\"");
+    assertParseError(
+      "1:18: String missing ending quote.",
+      "optional_string: \"ueoauaoe\n" +
+      "optional_int32: 123");
+    assertParseError(
+      "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
+      "[nosuchext]: 123");
+    assertParseError(
+      "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
+        "not extend message type \"protobuf_unittest.TestAllTypes\".",
+      "[protobuf_unittest.optional_int32_extension]: 123");
+    assertParseError(
+      "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
+        "named \"nosuchfield\".",
+      "nosuchfield: 123");
+    assertParseError(
+      "1:21: Expected \">\".",
+      "OptionalGroup < a: 1");
+    assertParseError(
+      "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+        "value named \"NO_SUCH_VALUE\".",
+      "optional_nested_enum: NO_SUCH_VALUE");
+    assertParseError(
+      "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+        "value with number 123.",
+      "optional_nested_enum: 123");
+
+    // Delimiters must match.
+    assertParseError(
+      "1:22: Expected identifier. Found '}'",
+      "OptionalGroup < a: 1 }");
+    assertParseError(
+      "1:22: Expected identifier. Found '>'",
+      "OptionalGroup { a: 1 >");
+  }
+
+  // =================================================================
+
+  public void testEscape() throws Exception {
+    // Escape sequences.
+    assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177",
+      TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\177")));
+    assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\177",
+      TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\"\177"));
+    assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
+      TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+    assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
+      TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+    assertEquals(kEscapeTestStringEscaped,
+      TextFormat.escapeText(kEscapeTestString));
+    assertEquals(kEscapeTestString,
+      TextFormat.unescapeText(kEscapeTestStringEscaped));
+
+    // Invariant
+    assertEquals("hello",
+        TextFormat.escapeBytes(bytes("hello")));
+    assertEquals("hello",
+        TextFormat.escapeText("hello"));
+    assertEquals(bytes("hello"),
+        TextFormat.unescapeBytes("hello"));
+    assertEquals("hello",
+        TextFormat.unescapeText("hello"));
+
+    // Unicode handling.
+    assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
+    assertEquals("\\341\\210\\264",
+                 TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
+    assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
+    assertEquals(bytes(0xe1, 0x88, 0xb4),
+                 TextFormat.unescapeBytes("\\341\\210\\264"));
+    assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
+    assertEquals(bytes(0xe1, 0x88, 0xb4),
+                 TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
+
+    // Handling of strings with unescaped Unicode characters > 255.
+    final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
+    ByteString zhByteString = ByteString.copyFromUtf8(zh);
+    assertEquals(zhByteString, TextFormat.unescapeBytes(zh));
+
+    // Errors.
+    try {
+      TextFormat.unescapeText("\\x");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      // success
+    }
+
+    try {
+      TextFormat.unescapeText("\\z");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      // success
+    }
+
+    try {
+      TextFormat.unescapeText("\\");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      // success
+    }
+  }
+
+  public void testParseInteger() throws Exception {
+    assertEquals(          0, TextFormat.parseInt32(          "0"));
+    assertEquals(          1, TextFormat.parseInt32(          "1"));
+    assertEquals(         -1, TextFormat.parseInt32(         "-1"));
+    assertEquals(      12345, TextFormat.parseInt32(      "12345"));
+    assertEquals(     -12345, TextFormat.parseInt32(     "-12345"));
+    assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
+    assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
+
+    assertEquals(                0, TextFormat.parseUInt32(         "0"));
+    assertEquals(                1, TextFormat.parseUInt32(         "1"));
+    assertEquals(            12345, TextFormat.parseUInt32(     "12345"));
+    assertEquals(       2147483647, TextFormat.parseUInt32("2147483647"));
+    assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
+    assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
+
+    assertEquals(          0L, TextFormat.parseInt64(          "0"));
+    assertEquals(          1L, TextFormat.parseInt64(          "1"));
+    assertEquals(         -1L, TextFormat.parseInt64(         "-1"));
+    assertEquals(      12345L, TextFormat.parseInt64(      "12345"));
+    assertEquals(     -12345L, TextFormat.parseInt64(     "-12345"));
+    assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
+    assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
+    assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
+    assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
+    assertEquals(9223372036854775807L,
+                 TextFormat.parseInt64("9223372036854775807"));
+    assertEquals(-9223372036854775808L,
+                 TextFormat.parseInt64("-9223372036854775808"));
+
+    assertEquals(          0L, TextFormat.parseUInt64(          "0"));
+    assertEquals(          1L, TextFormat.parseUInt64(          "1"));
+    assertEquals(      12345L, TextFormat.parseUInt64(      "12345"));
+    assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
+    assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
+    assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
+    assertEquals(9223372036854775807L,
+                 TextFormat.parseUInt64("9223372036854775807"));
+    assertEquals(-9223372036854775808L,
+                 TextFormat.parseUInt64("9223372036854775808"));
+    assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
+
+    // Hex
+    assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
+    assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
+    assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
+    assertEquals(0x7fffffffffffffffL,
+                 TextFormat.parseInt64("0x7fffffffffffffff"));
+
+    // Octal
+    assertEquals(01234567, TextFormat.parseInt32("01234567"));
+
+    // Out-of-range
+    try {
+      TextFormat.parseInt32("2147483648");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseInt32("-2147483649");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseUInt32("4294967296");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseUInt32("-1");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseInt64("9223372036854775808");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseInt64("-9223372036854775809");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseUInt64("18446744073709551616");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    try {
+      TextFormat.parseUInt64("-1");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+
+    // Not a number.
+    try {
+      TextFormat.parseInt32("abcd");
+      fail("Should have thrown an exception.");
+    } catch (NumberFormatException e) {
+      // success
+    }
+  }
+
+  public void testParseString() throws Exception {
+    final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_string: \"" + zh + "\"", builder);
+    assertEquals(zh, builder.getOptionalString());
+  }
+
+  public void testParseLongString() throws Exception {
+    String longText =
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890" +
+      "123456789012345678901234567890123456789012345678901234567890";
+
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_string: \"" + longText + "\"", builder);
+    assertEquals(longText, builder.getOptionalString());
+  }
+
+  public void testParseBoolean() throws Exception {
+    String goodText =
+        "repeated_bool: t  repeated_bool : 0\n" +
+        "repeated_bool :f repeated_bool:1\n" +
+        "repeated_bool: False repeated_bool: True";
+    String goodTextCanonical =
+        "repeated_bool: true\n" +
+        "repeated_bool: false\n" +
+        "repeated_bool: false\n" +
+        "repeated_bool: true\n" +
+        "repeated_bool: false\n" +
+        "repeated_bool: true\n";
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(goodText, builder);
+    assertEquals(goodTextCanonical, builder.build().toString());
+
+    try {
+      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
+      TextFormat.merge("optional_bool:2", badBuilder);
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.ParseException e) {
+      // success
+    }
+    try {
+      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
+      TextFormat.merge("optional_bool: foo", badBuilder);
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.ParseException e) {
+      // success
+    }
+  }
+
+  public void testParseAdjacentStringLiterals() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
+    assertEquals("foocorgegrault", builder.getOptionalString());
+  }
+
+  public void testPrintFieldValue() throws Exception {
+    assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
+    assertPrintFieldValue("123.0",  123f, "repeated_float");
+    assertPrintFieldValue("123.0",  123d, "repeated_double");
+    assertPrintFieldValue("123",  123, "repeated_int32");
+    assertPrintFieldValue("123",  123L, "repeated_int64");
+    assertPrintFieldValue("true",  true, "repeated_bool");
+    assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32");
+    assertPrintFieldValue("18446744073709551615",  0xFFFFFFFFFFFFFFFFL,
+        "repeated_uint64");
+    assertPrintFieldValue("\"\\001\\002\\003\"",
+        ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes");
+  }
+
+  private void assertPrintFieldValue(String expect, Object value,
+      String fieldName) throws Exception {
+    StringBuilder sb = new StringBuilder();
+    TextFormat.printFieldValue(
+        TestAllTypes.getDescriptor().findFieldByName(fieldName),
+        value, sb);
+    assertEquals(expect, sb.toString());
+  }
+
+  public void testShortDebugString() {
+    assertEquals("optional_nested_message { bb: 42 } repeated_int32: 1"
+        + " repeated_uint32: 2",
+        TextFormat.shortDebugString(TestAllTypes.newBuilder()
+            .addRepeatedInt32(1)
+            .addRepeatedUint32(2)
+            .setOptionalNestedMessage(
+                NestedMessage.newBuilder().setBb(42).build())
+            .build()));
+  }
+
+  public void testShortDebugString_field() {
+    final FieldDescriptor dataField =
+      OneString.getDescriptor().findFieldByName("data");
+    assertEquals(
+      "data: \"test data\"",
+      TextFormat.shortDebugString(dataField, "test data"));
+
+    final FieldDescriptor optionalField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+    final Object value = NestedMessage.newBuilder().setBb(42).build();
+
+    assertEquals(
+      "optional_nested_message { bb: 42 }",
+      TextFormat.shortDebugString(optionalField, value));
+  }
+
+  public void testShortDebugString_unknown() {
+    assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+        + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
+        + " 0xabcdef1234567890",
+        TextFormat.shortDebugString(makeUnknownFieldSet()));
+  }
+
+  public void testPrintToUnicodeString() throws Exception {
+    assertEquals(
+        "optional_string: \"abc\u3042efg\"\n" +
+        "optional_bytes: \"\\343\\201\\202\"\n" +
+        "repeated_string: \"\u3093XYZ\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("abc\u3042efg")
+            .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
+            .addRepeatedString("\u3093XYZ")
+            .build()));
+
+    // Double quotes and backslashes should be escaped
+    assertEquals(
+        "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("a\\bc\"ef\"g")
+            .build()));
+
+    // Test escaping roundtrip
+    TestAllTypes message = TestAllTypes.newBuilder()
+        .setOptionalString("a\\bc\\\"ef\"g")
+        .build();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+    assertEquals(message.getOptionalString(), builder.getOptionalString());
+  }
+
+  public void testPrintToUnicodeStringWithNewlines() throws Exception {
+    // No newlines at start and end
+    assertEquals("optional_string: \"test newlines\\n\\nin\\nstring\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("test newlines\n\nin\nstring")
+            .build()));
+
+    // Newlines at start and end
+    assertEquals("optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+            .build()));
+
+    // Strings with 0, 1 and 2 newlines.
+    assertEquals("optional_string: \"\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("")
+            .build()));
+    assertEquals("optional_string: \"\\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\n")
+            .build()));
+    assertEquals("optional_string: \"\\n\\n\"\n",
+        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
+            .setOptionalString("\n\n")
+            .build()));
+
+    // Test escaping roundtrip
+    TestAllTypes message = TestAllTypes.newBuilder()
+        .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+        .build();
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+    assertEquals(message.getOptionalString(), builder.getOptionalString());
+  }
+
+  public void testPrintToUnicodeString_unknown() {
+    assertEquals(
+        "1: \"\\343\\201\\202\"\n",
+        TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder()
+            .addField(1,
+                UnknownFieldSet.Field.newBuilder()
+                .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
+            .build()));
+  }
+
+
+  public void testParseNonRepeatedFields() throws Exception {
+    assertParseSuccessWithOverwriteForbidden(
+        "repeated_int32: 1\n" +
+        "repeated_int32: 2\n");
+    assertParseSuccessWithOverwriteForbidden(
+        "RepeatedGroup { a: 1 }\n" +
+        "RepeatedGroup { a: 2 }\n");
+    assertParseSuccessWithOverwriteForbidden(
+        "repeated_nested_message { bb: 1 }\n" +
+        "repeated_nested_message { bb: 2 }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "3:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optional_int32\" " +
+        "cannot be overwritten.",
+        "optional_int32: 1\n" +
+        "optional_bool: true\n" +
+        "optional_int32: 1\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optionalgroup\" " +
+        "cannot be overwritten.",
+        "OptionalGroup { a: 1 }\n" +
+        "OptionalGroup { }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:33: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " +
+        "cannot be overwritten.",
+        "optional_nested_message { }\n" +
+        "optional_nested_message { bb: 3 }\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:16: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.default_int32\" " +
+        "cannot be overwritten.",
+        "default_int32: 41\n" +  // the default value
+        "default_int32: 41\n");
+    assertParseErrorWithOverwriteForbidden(
+        "2:17: Non-repeated field " +
+        "\"protobuf_unittest.TestAllTypes.default_string\" " +
+        "cannot be overwritten.",
+        "default_string: \"zxcv\"\n" +
+        "default_string: \"asdf\"\n");
+  }
+
+  public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
+    assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
+    assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
+    assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
+    assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
+  }
+
+  public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
+    assertParseErrorWithOverwriteForbidden(
+        "1:17: Couldn't parse integer: For input string: \"[\"",
+        "optional_int32: [1]\n");
+  }
+
+  // =======================================================================
+  // test oneof
+
+  public void testOneofTextFormat() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestUtil.setOneof(builder);
+    TestOneof2 message = builder.build();
+    TestOneof2.Builder dest = TestOneof2.newBuilder();
+    TextFormat.merge(TextFormat.printToUnicodeString(message), dest);
+    TestUtil.assertOneofSet(dest.build());
+  }
+
+  public void testOneofOverwriteForbidden() throws Exception {
+    String input = "foo_string: \"stringvalue\" foo_int: 123";
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    try {
+      parserWithOverwriteForbidden.merge(
+          input, TestUtil.getExtensionRegistry(), builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
+                   + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+                   + " another member of oneof \"foo\".", e.getMessage());
+    }
+  }
+
+  public void testOneofOverwriteAllowed() throws Exception {
+    String input = "foo_string: \"stringvalue\" foo_int: 123";
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder);
+    // Only the last value sticks.
+    TestOneof2 oneof = builder.build();
+    assertFalse(oneof.hasFooString());
+    assertTrue(oneof.hasFooInt());
+  }
+
+  // =======================================================================
+  // test location information
+
+  public void testParseInfoTreeBuilding() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder();
+    // Set to allow unknown fields
+    TextFormat.Parser parser =
+        TextFormat.Parser.newBuilder()
+            .setParseInfoTreeBuilder(treeBuilder)
+            .build();
+
+    final String stringData =
+        "optional_int32: 1\n"
+        + "optional_int64: 2\n"
+        + "  optional_double: 2.4\n"
+        + "repeated_int32: 5\n"
+        + "repeated_int32: 10\n"
+        + "optional_nested_message <\n"
+        + "  bb: 78\n"
+        + ">\n"
+        + "repeated_nested_message <\n"
+        + "  bb: 79\n"
+        + ">\n"
+        + "repeated_nested_message <\n"
+        + "  bb: 80\n"
+        + ">";
+
+    parser.merge(stringData, builder);
+    TextFormatParseInfoTree tree = treeBuilder.build();
+
+    // Verify that the tree has the correct positions.
+    assertLocation(tree, descriptor, "optional_int32", 0, 0, 0);
+    assertLocation(tree, descriptor, "optional_int64", 0, 1, 0);
+    assertLocation(tree, descriptor, "optional_double", 0, 2, 2);
+
+    assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0);
+    assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0);
+
+    assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0);
+    assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0);
+    assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0);
+
+    // Check for fields not set. For an invalid field, the location returned should be -1, -1.
+    assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1);
+    assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1);
+
+    // Verify inside the nested message.
+    FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message");
+
+    TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2);
+
+    // Verify inside another nested message.
+    nestedField = descriptor.findFieldByName("repeated_nested_message");
+    nestedTree = tree.getNestedTrees(nestedField).get(0);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2);
+
+    nestedTree = tree.getNestedTrees(nestedField).get(1);
+    assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2);
+
+    // Verify a NULL tree for an unknown nested field.
+    try {
+      tree.getNestedTree(nestedField, 2);
+      fail("unknown nested field should throw");
+    } catch (IllegalArgumentException unused) {
+      // pass
+    }
+  }
+
+  private void assertLocation(
+      TextFormatParseInfoTree tree,
+      final Descriptor descriptor,
+      final String fieldName,
+      int index,
+      int line,
+      int column) {
+    List<TextFormatParseLocation> locs = tree.getLocations(descriptor.findFieldByName(fieldName));
+    if (index < locs.size()) {
+      TextFormatParseLocation location = locs.get(index);
+      TextFormatParseLocation expected = TextFormatParseLocation.create(line, column);
+      assertEquals(expected, location);
+    } else if (line != -1 && column != -1) {
+      fail(
+          String.format(
+              "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected",
+              index,
+              line,
+              column));
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
new file mode 100644
index 0000000..8f45976
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
@@ -0,0 +1,255 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
+import com.google.protobuf.TextFormat.ParseException;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for protos that keep unknown enum values rather than discard
+ * them as unknown fields.
+ */
+public class UnknownEnumValueTest extends TestCase {
+  public void testUnknownEnumValues() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalNestedEnumValue(4321);
+    builder.addRepeatedNestedEnumValue(5432);
+    builder.addPackedNestedEnumValue(6543);
+    TestAllTypes message = builder.build();
+    assertEquals(4321, message.getOptionalNestedEnumValue());
+    assertEquals(5432, message.getRepeatedNestedEnumValue(0));
+    assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue());
+    assertEquals(6543, message.getPackedNestedEnumValue(0));
+    // Returns UNRECOGNIZED if an enum type is requested.
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum());
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0));
+    
+    // Test serialization and parsing.
+    ByteString data = message.toByteString();
+    message = TestAllTypes.parseFrom(data);
+    assertEquals(4321, message.getOptionalNestedEnumValue());
+    assertEquals(5432, message.getRepeatedNestedEnumValue(0));
+    assertEquals(5432, message.getRepeatedNestedEnumValueList().get(0).intValue());
+    assertEquals(6543, message.getPackedNestedEnumValue(0));
+    // Returns UNRECOGNIZED if an enum type is requested.
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getOptionalNestedEnum());
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getRepeatedNestedEnumList().get(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, message.getPackedNestedEnum(0));
+    
+    // Test toBuilder().
+    builder = message.toBuilder();
+    assertEquals(4321, builder.getOptionalNestedEnumValue());
+    assertEquals(5432, builder.getRepeatedNestedEnumValue(0));
+    assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue());
+    assertEquals(6543, builder.getPackedNestedEnumValue(0));    
+    // Returns UNRECOGNIZED if an enum type is requested.
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum());
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0));
+    
+    // Test mergeFrom().
+    builder = TestAllTypes.newBuilder().mergeFrom(message);
+    assertEquals(4321, builder.getOptionalNestedEnumValue());
+    assertEquals(5432, builder.getRepeatedNestedEnumValue(0));
+    assertEquals(5432, builder.getRepeatedNestedEnumValueList().get(0).intValue());
+    assertEquals(6543, builder.getPackedNestedEnumValue(0));
+    // Returns UNRECOGNIZED if an enum type is requested.
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getOptionalNestedEnum());
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getRepeatedNestedEnumList().get(0));
+    assertEquals(TestAllTypes.NestedEnum.UNRECOGNIZED, builder.getPackedNestedEnum(0));
+    
+    // Test equals() and hashCode()
+    TestAllTypes sameMessage = builder.build();
+    assertEquals(message, sameMessage);
+    assertEquals(message.hashCode(), sameMessage.hashCode());
+
+    // Getting the numeric value of UNRECOGNIZED will throw an exception.
+    try {
+      TestAllTypes.NestedEnum.UNRECOGNIZED.getNumber();
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    // Setting an enum field to an UNRECOGNIZED value will throw an exception.
+    try {
+      builder.setOptionalNestedEnum(builder.getOptionalNestedEnum());
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+    try {
+      builder.addRepeatedNestedEnum(builder.getOptionalNestedEnum());
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+  }
+  
+  public void testUnknownEnumValueInReflectionApi() throws Exception {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+    FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum");
+    FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum");
+    EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setField(optionalNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(4321));
+    builder.addRepeatedField(repeatedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(5432));
+    builder.addRepeatedField(packedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(6543));
+    TestAllTypes message = builder.build();
+    
+    // Getters will return unknown enum values as EnumValueDescriptor.
+    EnumValueDescriptor unknown4321 =
+        (EnumValueDescriptor) message.getField(optionalNestedEnumField);
+    EnumValueDescriptor unknown5432 =
+        (EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0);
+    EnumValueDescriptor unknown6543 =
+        (EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0);
+    assertEquals(4321, unknown4321.getNumber());
+    assertEquals(5432, unknown5432.getNumber());
+    assertEquals(6543, unknown6543.getNumber());
+    
+    // Unknown EnumValueDescriptor will map to UNRECOGNIZED.
+    assertEquals(
+        TestAllTypes.NestedEnum.valueOf(unknown4321),
+        TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertEquals(
+        TestAllTypes.NestedEnum.valueOf(unknown5432),
+        TestAllTypes.NestedEnum.UNRECOGNIZED);
+    assertEquals(
+        TestAllTypes.NestedEnum.valueOf(unknown6543),
+        TestAllTypes.NestedEnum.UNRECOGNIZED);
+    
+    // Setters also accept unknown EnumValueDescriptor.
+    builder.setField(optionalNestedEnumField, unknown6543);
+    builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321);
+    builder.setRepeatedField(packedNestedEnumField, 0, unknown5432);
+    message = builder.build();
+    // Like other descriptors, unknown EnumValueDescriptor can be compared by
+    // object identity.
+    assertTrue(unknown6543 == message.getField(optionalNestedEnumField));
+    assertTrue(unknown4321 == message.getRepeatedField(repeatedNestedEnumField, 0));
+    assertTrue(unknown5432 == message.getRepeatedField(packedNestedEnumField, 0));
+  }
+  
+  public void testUnknownEnumValueWithDynamicMessage() throws Exception {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+    FieldDescriptor repeatedNestedEnumField = descriptor.findFieldByName("repeated_nested_enum");
+    FieldDescriptor packedNestedEnumField = descriptor.findFieldByName("packed_nested_enum");
+    EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+    
+    Message dynamicMessageDefaultInstance = DynamicMessage.getDefaultInstance(descriptor);
+
+    Message.Builder builder = dynamicMessageDefaultInstance.newBuilderForType();
+    builder.setField(optionalNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(4321));
+    builder.addRepeatedField(repeatedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(5432));
+    builder.addRepeatedField(packedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(6543));
+    Message message = builder.build();
+    assertEquals(4321,
+        ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber());
+    assertEquals(5432,
+        ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber());
+    assertEquals(6543,
+        ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber());
+    
+    // Test reflection based serialization/parsing implementation.
+    ByteString data = message.toByteString();
+    message = dynamicMessageDefaultInstance
+        .newBuilderForType()
+        .mergeFrom(data)
+        .build();
+    assertEquals(4321,
+        ((EnumValueDescriptor) message.getField(optionalNestedEnumField)).getNumber());
+    assertEquals(5432,
+        ((EnumValueDescriptor) message.getRepeatedField(repeatedNestedEnumField, 0)).getNumber());
+    assertEquals(6543,
+        ((EnumValueDescriptor) message.getRepeatedField(packedNestedEnumField, 0)).getNumber());
+    
+    // Test reflection based equals()/hashCode().
+    builder = dynamicMessageDefaultInstance.newBuilderForType();
+    builder.setField(optionalNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(4321));
+    builder.addRepeatedField(repeatedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(5432));
+    builder.addRepeatedField(packedNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(6543));
+    Message sameMessage = builder.build();
+    assertEquals(message, sameMessage);
+    assertEquals(message.hashCode(), sameMessage.hashCode());
+    builder.setField(optionalNestedEnumField,
+        enumType.findValueByNumberCreatingIfUnknown(0));
+    Message differentMessage = builder.build();
+    assertFalse(message.equals(differentMessage));
+  }
+  
+  public void testUnknownEnumValuesInTextFormat() {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    builder.setOptionalNestedEnumValue(4321);
+    builder.addRepeatedNestedEnumValue(5432);
+    builder.addPackedNestedEnumValue(6543);
+    TestAllTypes message = builder.build();
+    
+    // We can print a message with unknown enum values.
+    String textData = TextFormat.printToString(message);
+    assertEquals(
+        "optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n"
+        + "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n"
+        + "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n", textData);
+    
+    // Parsing unknown enum values will fail just like parsing other kinds of
+    // unknown fields.
+    try {
+      TextFormat.merge(textData, builder);
+      fail();
+    } catch (ParseException e) {
+      // expected.
+    }
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
new file mode 100644
index 0000000..573cd66
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -0,0 +1,328 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
+import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Tests for {@link UnknownFieldSetLite}.
+ *
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class UnknownFieldSetLiteTest extends TestCase {
+  
+  public void testDefaultInstance() {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
+
+    assertEquals(0, unknownFields.getSerializedSize());
+    assertEquals(ByteString.EMPTY, toByteString(unknownFields));
+  }
+
+  public void testMergeFieldFrom() throws IOException {
+    Foo foo = Foo.newBuilder()
+      .setValue(2)
+      .build();
+
+    CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
+
+    UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+    instance.mergeFieldFrom(input.readTag(), input);
+
+    assertEquals(foo.toByteString(), toByteString(instance));
+  }
+
+  public void testSerializedSize() throws IOException {
+    Foo foo = Foo.newBuilder()
+      .setValue(2)
+      .build();
+
+    CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
+
+    UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+    instance.mergeFieldFrom(input.readTag(), input);
+
+    assertEquals(foo.toByteString().size(), instance.getSerializedSize());
+  }
+
+  public void testMergeVarintField() throws IOException {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.mergeVarintField(10, 2);
+
+    CodedInputStream input =
+        CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
+
+    int tag = input.readTag();
+    assertEquals(10, WireFormat.getTagFieldNumber(tag));
+    assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag));
+    assertEquals(2, input.readUInt64());
+    assertTrue(input.isAtEnd());
+  }
+
+  public void testMergeVarintField_negative() throws IOException {
+    UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance();
+    builder.mergeVarintField(10, -6);
+
+    CodedInputStream input =
+        CodedInputStream.newInstance(toByteString(builder).toByteArray());
+
+    int tag = input.readTag();
+    assertEquals(10, WireFormat.getTagFieldNumber(tag));
+    assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag));
+    assertEquals(-6, input.readUInt64());
+    assertTrue(input.isAtEnd());
+  }
+
+  public void testEqualsAndHashCode() {
+    UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance();
+    unknownFields1.mergeVarintField(10, 2);
+
+    UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance();
+    unknownFields2.mergeVarintField(10, 2);
+
+    assertEquals(unknownFields1, unknownFields2);
+    assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode());
+    assertFalse(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance()));
+    assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode());
+  }
+
+  public void testMutableCopyOf() throws IOException {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.mergeVarintField(10, 2);
+    unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields);
+    unknownFields.checkMutable();
+
+    CodedInputStream input =
+        CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
+
+    int tag = input.readTag();
+    assertEquals(10, WireFormat.getTagFieldNumber(tag));
+    assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag));
+    assertEquals(2, input.readUInt64());
+    assertFalse(input.isAtEnd());
+    input.readTag();
+    assertEquals(10, WireFormat.getTagFieldNumber(tag));
+    assertEquals(WireFormat.WIRETYPE_VARINT, WireFormat.getTagWireType(tag));
+    assertEquals(2, input.readUInt64());
+    assertTrue(input.isAtEnd());
+  }
+
+  public void testMutableCopyOf_empty() {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.mutableCopyOf(
+        UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance());
+    unknownFields.checkMutable();
+
+    assertEquals(0, unknownFields.getSerializedSize());
+    assertEquals(ByteString.EMPTY, toByteString(unknownFields));
+  }
+
+  public void testRoundTrips() throws InvalidProtocolBufferException {
+    Foo foo = Foo.newBuilder()
+        .setValue(1)
+        .setExtension(Bar.fooExt, Bar.newBuilder()
+            .setName("name")
+            .build())
+        .setExtension(LiteEqualsAndHash.varint, 22)
+        .setExtension(LiteEqualsAndHash.fixed32, 44)
+        .setExtension(LiteEqualsAndHash.fixed64, 66L)
+        .setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder()
+            .setGroupValue("value")
+            .build())
+        .build();
+
+    Foo copy = Foo.parseFrom(foo.toByteArray());
+
+    assertEquals(foo.getSerializedSize(), copy.getSerializedSize());
+    assertFalse(foo.equals(copy));
+
+    Foo secondCopy = Foo.parseFrom(foo.toByteArray());
+    assertEquals(copy, secondCopy);
+
+    ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance();
+    LiteEqualsAndHash.registerAllExtensions(extensionRegistry);
+    Foo copyOfCopy = Foo.parseFrom(copy.toByteArray(), extensionRegistry);
+
+    assertEquals(foo, copyOfCopy);
+  }
+
+  public void testMalformedBytes() throws Exception {
+    try {
+      Foo.parseFrom("this is a malformed protocol buffer".getBytes(Internal.UTF_8));
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testMissingStartGroupTag() throws IOException {
+    ByteString.Output byteStringOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput);
+    output.writeGroupNoTag(Foo.newBuilder().setValue(11).build());
+    output.writeTag(100, WireFormat.WIRETYPE_END_GROUP);
+    output.flush();
+
+    try {
+      Foo.parseFrom(byteStringOutput.toByteString());
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testMissingEndGroupTag() throws IOException {
+    ByteString.Output byteStringOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput);
+    output.writeTag(100, WireFormat.WIRETYPE_START_GROUP);
+    output.writeGroupNoTag(Foo.newBuilder().setValue(11).build());
+    output.flush();
+
+    try {
+      Foo.parseFrom(byteStringOutput.toByteString());
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testMismatchingGroupTags() throws IOException {
+    ByteString.Output byteStringOutput = ByteString.newOutput();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput);
+    output.writeTag(100, WireFormat.WIRETYPE_START_GROUP);
+    output.writeGroupNoTag(Foo.newBuilder().setValue(11).build());
+    output.writeTag(101, WireFormat.WIRETYPE_END_GROUP);
+    output.flush();
+
+    try {
+      Foo.parseFrom(byteStringOutput.toByteString());
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testTruncatedInput() {
+    Foo foo = Foo.newBuilder()
+        .setValue(1)
+        .setExtension(Bar.fooExt, Bar.newBuilder()
+            .setName("name")
+            .build())
+        .setExtension(LiteEqualsAndHash.varint, 22)
+        .setExtension(LiteEqualsAndHash.myGroup, LiteEqualsAndHash.MyGroup.newBuilder()
+            .setGroupValue("value")
+            .build())
+        .build();
+
+    try {
+      Foo.parseFrom(foo.toByteString().substring(0, foo.toByteString().size() - 10));
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+  
+  public void testMakeImmutable() throws Exception {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.makeImmutable();
+    
+    try {
+      unknownFields.mergeVarintField(1, 1);
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    try {
+      unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello"));
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    try {
+      unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0]));
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
+  
+  public void testEndToEnd() throws Exception {
+    TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.parseFrom(new byte[0]);
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.newBuilder().build();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.newBuilder()
+        .setDefaultBool(true)
+        .build();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    TestAllExtensionsLite testAllExtensions = TestAllExtensionsLite.newBuilder()
+        .mergeFrom(TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 2)
+            .build().toByteArray())
+        .build();
+    try {
+      testAllExtensions.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
+
+  private ByteString toByteString(UnknownFieldSetLite unknownFields) {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    try {
+      unknownFields.writeTo(output);
+      output.flush();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    return ByteString.copyFrom(byteArrayOutputStream.toByteArray());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
new file mode 100644
index 0000000..32380f7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -0,0 +1,654 @@
+// 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.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests related to unknown field handling.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class UnknownFieldSetTest extends TestCase {
+  @Override
+  public void setUp() throws Exception {
+    descriptor = TestAllTypes.getDescriptor();
+    allFields = TestUtil.getAllSet();
+    allFieldsData = allFields.toByteString();
+    emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+    unknownFields = emptyMessage.getUnknownFields();
+  }
+
+  UnknownFieldSet.Field getField(String name) {
+    Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
+    assertNotNull(field);
+    return unknownFields.getField(field.getNumber());
+  }
+
+  // Constructs a protocol buffer which contains fields with all the same
+  // numbers as allFieldsData except that each field is some other wire
+  // type.
+  ByteString getBizarroData() throws Exception {
+    UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+    UnknownFieldSet.Field varintField =
+      UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+    UnknownFieldSet.Field fixed32Field =
+      UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+    for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+         unknownFields.asMap().entrySet()) {
+      if (entry.getValue().getVarintList().isEmpty()) {
+        // Original field is not a varint, so use a varint.
+        bizarroFields.addField(entry.getKey(), varintField);
+      } else {
+        // Original field *is* a varint, so use something else.
+        bizarroFields.addField(entry.getKey(), fixed32Field);
+      }
+    }
+
+    return bizarroFields.build().toByteString();
+  }
+
+  Descriptors.Descriptor descriptor;
+  TestAllTypes allFields;
+  ByteString allFieldsData;
+
+  // An empty message that has been parsed from allFieldsData.  So, it has
+  // unknown fields of every type.
+  TestEmptyMessage emptyMessage;
+  UnknownFieldSet unknownFields;
+
+  // =================================================================
+
+  public void testVarint() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(allFields.getOptionalInt32(),
+                 (long) field.getVarintList().get(0));
+  }
+
+  public void testFixed32() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_fixed32");
+    assertEquals(1, field.getFixed32List().size());
+    assertEquals(allFields.getOptionalFixed32(),
+                 (int) field.getFixed32List().get(0));
+  }
+
+  public void testFixed64() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_fixed64");
+    assertEquals(1, field.getFixed64List().size());
+    assertEquals(allFields.getOptionalFixed64(),
+                 (long) field.getFixed64List().get(0));
+  }
+
+  public void testLengthDelimited() throws Exception {
+    UnknownFieldSet.Field field = getField("optional_bytes");
+    assertEquals(1, field.getLengthDelimitedList().size());
+    assertEquals(allFields.getOptionalBytes(),
+                 field.getLengthDelimitedList().get(0));
+  }
+
+  public void testGroup() throws Exception {
+    Descriptors.FieldDescriptor nestedFieldDescriptor =
+      TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
+    assertNotNull(nestedFieldDescriptor);
+
+    UnknownFieldSet.Field field = getField("optionalgroup");
+    assertEquals(1, field.getGroupList().size());
+
+    UnknownFieldSet group = field.getGroupList().get(0);
+    assertEquals(1, group.asMap().size());
+    assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
+
+    UnknownFieldSet.Field nestedField =
+      group.getField(nestedFieldDescriptor.getNumber());
+    assertEquals(1, nestedField.getVarintList().size());
+    assertEquals(allFields.getOptionalGroup().getA(),
+                 (long) nestedField.getVarintList().get(0));
+  }
+
+  public void testSerialize() throws Exception {
+    // Check that serializing the UnknownFieldSet produces the original data
+    // again.
+    ByteString data = emptyMessage.toByteString();
+    assertEquals(allFieldsData, data);
+  }
+
+  public void testCopyFrom() throws Exception {
+    TestEmptyMessage message =
+      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
+
+    assertEquals(emptyMessage.toString(), message.toString());
+  }
+
+  public void testMergeFrom() throws Exception {
+    TestEmptyMessage source =
+      TestEmptyMessage.newBuilder()
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(2,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(2).build())
+            .addField(3,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(4).build())
+            .build())
+        .build();
+    TestEmptyMessage destination =
+      TestEmptyMessage.newBuilder()
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(1,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(1).build())
+            .addField(3,
+              UnknownFieldSet.Field.newBuilder()
+                .addVarint(3).build())
+            .build())
+        .mergeFrom(source)
+        .build();
+
+    assertEquals(
+      "1: 1\n" +
+      "2: 2\n" +
+      "3: 3\n" +
+      "3: 4\n",
+      destination.toString());
+  }
+
+  public void testClear() throws Exception {
+    UnknownFieldSet fields =
+      UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
+    assertTrue(fields.asMap().isEmpty());
+  }
+
+  public void testClearMessage() throws Exception {
+    TestEmptyMessage message =
+      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
+    assertEquals(0, message.getSerializedSize());
+  }
+  
+  public void testClearField() throws Exception {
+    int fieldNumber = unknownFields.asMap().keySet().iterator().next();
+    UnknownFieldSet fields =
+        UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
+    assertFalse(fields.hasField(fieldNumber));
+  }
+
+  public void testParseKnownAndUnknown() throws Exception {
+    // Test mixing known and unknown fields when parsing.
+
+    UnknownFieldSet fields =
+      UnknownFieldSet.newBuilder(unknownFields)
+        .addField(123456,
+          UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
+        .build();
+
+    ByteString data = fields.toByteString();
+    TestAllTypes destination = TestAllTypes.parseFrom(data);
+
+    TestUtil.assertAllFieldsSet(destination);
+    assertEquals(1, destination.getUnknownFields().asMap().size());
+
+    UnknownFieldSet.Field field =
+      destination.getUnknownFields().getField(123456);
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(654321, (long) field.getVarintList().get(0));
+  }
+
+  public void testWrongTypeTreatedAsUnknown() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the debug strings
+    // should be the same.
+    assertEquals(emptyMessage.toString(), allTypesMessage.toString());
+  }
+
+  public void testUnknownExtensions() throws Exception {
+    // Make sure fields are properly parsed to the UnknownFieldSet even when
+    // they are declared as extension numbers.
+
+    TestEmptyMessageWithExtensions message =
+      TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
+
+    assertEquals(unknownFields.asMap().size(),
+                 message.getUnknownFields().asMap().size());
+    assertEquals(allFieldsData, message.toByteString());
+  }
+
+  public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing extensions.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllExtensions allExtensionsMessage =
+      TestAllExtensions.parseFrom(bizarroData);
+    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the debug strings
+    // should be the same.
+    assertEquals(emptyMessage.toString(),
+                 allExtensionsMessage.toString());
+  }
+
+  public void testParseUnknownEnumValue() throws Exception {
+    Descriptors.FieldDescriptor singularField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+    Descriptors.FieldDescriptor repeatedField =
+      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+    assertNotNull(singularField);
+    assertNotNull(repeatedField);
+
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(singularField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+            .addVarint(5)   // not valid
+            .build())
+        .addField(repeatedField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+            .addVarint(4)   // not valid
+            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+            .addVarint(6)   // not valid
+            .build())
+        .build()
+        .toByteString();
+
+    {
+      TestAllTypes message = TestAllTypes.parseFrom(data);
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+                   message.getOptionalNestedEnum());
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getRepeatedNestedEnumList());
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+
+    {
+      TestAllExtensions message =
+        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+        message.getExtension(UnittestProto.optionalNestedEnumExtension));
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+  }
+
+  public void testLargeVarint() throws Exception {
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(1,
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(0x7FFFFFFFFFFFFFFFL)
+            .build())
+        .build()
+        .toByteString();
+    UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
+    UnknownFieldSet.Field field = parsed.getField(1);
+    assertEquals(1, field.getVarintList().size());
+    assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
+  }
+
+  public void testEqualsAndHashCode() {
+    UnknownFieldSet.Field fixed32Field =
+        UnknownFieldSet.Field.newBuilder()
+            .addFixed32(1)
+            .build();
+    UnknownFieldSet.Field fixed64Field =
+        UnknownFieldSet.Field.newBuilder()
+            .addFixed64(1)
+            .build();
+    UnknownFieldSet.Field varIntField =
+        UnknownFieldSet.Field.newBuilder()
+            .addVarint(1)
+            .build();
+    UnknownFieldSet.Field lengthDelimitedField =
+        UnknownFieldSet.Field.newBuilder()
+            .addLengthDelimited(ByteString.EMPTY)
+            .build();
+    UnknownFieldSet.Field groupField =
+        UnknownFieldSet.Field.newBuilder()
+            .addGroup(unknownFields)
+            .build();
+
+    UnknownFieldSet a =
+        UnknownFieldSet.newBuilder()
+            .addField(1, fixed32Field)
+            .build();
+    UnknownFieldSet b =
+        UnknownFieldSet.newBuilder()
+            .addField(1, fixed64Field)
+            .build();
+    UnknownFieldSet c =
+        UnknownFieldSet.newBuilder()
+            .addField(1, varIntField)
+            .build();
+    UnknownFieldSet d =
+        UnknownFieldSet.newBuilder()
+            .addField(1, lengthDelimitedField)
+            .build();
+    UnknownFieldSet e =
+        UnknownFieldSet.newBuilder()
+            .addField(1, groupField)
+            .build();
+
+    checkEqualsIsConsistent(a);
+    checkEqualsIsConsistent(b);
+    checkEqualsIsConsistent(c);
+    checkEqualsIsConsistent(d);
+    checkEqualsIsConsistent(e);
+
+    checkNotEqual(a, b);
+    checkNotEqual(a, c);
+    checkNotEqual(a, d);
+    checkNotEqual(a, e);
+    checkNotEqual(b, c);
+    checkNotEqual(b, d);
+    checkNotEqual(b, e);
+    checkNotEqual(c, d);
+    checkNotEqual(c, e);
+    checkNotEqual(d, e);
+  }
+
+  /**
+   * Asserts that the given field sets are not equal and have different
+   * hash codes.
+   *
+   * @warning It's valid for non-equal objects to have the same hash code, so
+   *   this test is stricter than it needs to be. However, this should happen
+   *   relatively rarely.
+   */
+  private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
+    String equalsError = String.format("%s should not be equal to %s", s1, s2);
+    assertFalse(equalsError, s1.equals(s2));
+    assertFalse(equalsError, s2.equals(s1));
+
+    assertFalse(
+        String.format("%s should have a different hash code from %s", s1, s2),
+        s1.hashCode() == s2.hashCode());
+  }
+
+  /**
+   * Asserts that the given field sets are equal and have identical hash codes.
+   */
+  private void checkEqualsIsConsistent(UnknownFieldSet set) {
+    // Object should be equal to itself.
+    assertEquals(set, set);
+
+    // Object should be equal to a copy of itself.
+    UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
+    assertEquals(set, copy);
+    assertEquals(copy, set);
+    assertEquals(set.hashCode(), copy.hashCode());
+  }
+
+  // =================================================================
+
+  public void testSerializeLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes message = TestAllTypes.parseFrom(data);
+    TestUtil.assertAllFieldsSet(message);
+    assertEquals(allFieldsData, data);
+  }
+
+  public void testAllExtensionsLite() throws Exception {
+    TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
+    ByteString allExtensionsData = allExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllExtensions message =
+        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertAllExtensionsSet(message);
+    assertEquals(allExtensionsData, data);
+  }
+
+  public void testAllPackedFieldsLite() throws Exception {
+    TestPackedTypes allPackedFields = TestUtil.getPackedSet();
+    ByteString allPackedData = allPackedFields.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedTypes message =
+        TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedFieldsSet(message);
+    assertEquals(allPackedData, data);
+  }
+
+  public void testAllPackedExtensionsLite() throws Exception {
+    TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
+    ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestPackedExtensions message =
+        TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+    TestUtil.assertPackedExtensionsSet(message);
+    assertEquals(allPackedExtensionsData, data);
+  }
+
+  public void testCopyFromLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder()
+        .mergeFrom(emptyMessageLite).build();
+    assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
+  }
+
+  public void testMergeFromLite() throws Exception {
+    TestAllTypes message1 = TestAllTypes.newBuilder()
+        .setOptionalInt32(1)
+        .setOptionalString("foo")
+        .addRepeatedString("bar")
+        .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
+        .build();
+
+    TestAllTypes message2 = TestAllTypes.newBuilder()
+        .setOptionalInt64(2)
+        .setOptionalString("baz")
+        .addRepeatedString("qux")
+        .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
+        .build();
+
+    ByteString data1 = message1.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data1);
+    ByteString data2 = message2.toByteString();
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data2);
+
+    message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
+    emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
+                        .mergeFrom(emptyMessageLite2).build();
+
+    data1 = emptyMessageLite1.toByteString();
+    message2 = TestAllTypes.parseFrom(data1);
+
+    assertEquals(message1, message2);
+  }
+
+  public void testWrongTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+    ByteString data = emptyMessageLite.toByteString();
+    TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
+
+    assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
+  }
+
+  public void testUnknownExtensionsLite() throws Exception {
+    // Make sure fields are properly parsed to the UnknownFieldSet even when
+    // they are declared as extension numbers.
+
+    UnittestLite.TestEmptyMessageWithExtensionsLite message =
+      UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
+
+    assertEquals(allFieldsData, message.toByteString());
+  }
+
+  public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
+    // Test that fields of the wrong wire type are treated like unknown fields
+    // when parsing extensions.
+
+    ByteString bizarroData = getBizarroData();
+    TestAllExtensions allExtensionsMessage =
+      TestAllExtensions.parseFrom(bizarroData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
+
+    // All fields should have been interpreted as unknown, so the byte strings
+    // should be the same.
+    assertEquals(emptyMessageLite.toByteString(),
+                 allExtensionsMessage.toByteString());
+  }
+
+  public void testParseUnknownEnumValueLite() throws Exception {
+    Descriptors.FieldDescriptor singularField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+    Descriptors.FieldDescriptor repeatedField =
+      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+    assertNotNull(singularField);
+    assertNotNull(repeatedField);
+
+    ByteString data =
+      UnknownFieldSet.newBuilder()
+        .addField(singularField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+            .addVarint(5)   // not valid
+            .build())
+        .addField(repeatedField.getNumber(),
+          UnknownFieldSet.Field.newBuilder()
+            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+            .addVarint(4)   // not valid
+            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+            .addVarint(6)   // not valid
+            .build())
+        .build()
+        .toByteString();
+
+    UnittestLite.TestEmptyMessageLite emptyMessageLite =
+        UnittestLite.TestEmptyMessageLite.parseFrom(data);
+    data = emptyMessageLite.toByteString();
+
+    {
+      TestAllTypes message = TestAllTypes.parseFrom(data);
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+                   message.getOptionalNestedEnum());
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getRepeatedNestedEnumList());
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+
+    {
+      TestAllExtensions message =
+        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+      assertEquals(TestAllTypes.NestedEnum.BAR,
+        message.getExtension(UnittestProto.optionalNestedEnumExtension));
+      assertEquals(
+        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+        message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+      assertEquals(Arrays.asList(5L),
+                   message.getUnknownFields()
+                          .getField(singularField.getNumber())
+                          .getVarintList());
+      assertEquals(Arrays.asList(4L, 6L),
+                   message.getUnknownFields()
+                          .getField(repeatedField.getNumber())
+                          .getVarintList());
+    }
+  }
+
+  public void testClearLite() throws Exception {
+    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
+        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
+    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
+        UnittestLite.TestEmptyMessageLite.newBuilder()
+        .mergeFrom(emptyMessageLite1).clear().build();
+    assertEquals(0, emptyMessageLite2.getSerializedSize());
+    ByteString data = emptyMessageLite2.toByteString();
+    assertEquals(0, data.size());
+  }
+
+}
diff --git a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
rename to java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
diff --git a/java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java b/java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java
new file mode 100644
index 0000000..982e200
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java
@@ -0,0 +1,65 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.test.TestWellKnownTypes;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This test ensures that well-known types are included in protobuf Java
+ * runtime library.
+ */
+public class WellKnownTypesTest extends TestCase {
+  public void testWellKnownTypes() {
+    // The test passes if it compiles.
+    TestWellKnownTypes message = TestWellKnownTypes.newBuilder().build();
+    assertEquals(0, message.getAnyField().getSerializedSize());
+    assertEquals(0, message.getApiField().getSerializedSize());
+    assertEquals(0, message.getDurationField().getSerializedSize());
+    assertEquals(0, message.getEmptyField().getSerializedSize());
+    assertEquals(0, message.getFieldMaskField().getSerializedSize());
+    assertEquals(0, message.getSourceContextField().getSerializedSize());
+    assertEquals(0, message.getStructField().getSerializedSize());
+    assertEquals(0, message.getTimestampField().getSerializedSize());
+    assertEquals(0, message.getTypeField().getSerializedSize());
+    assertEquals(0, message.getInt32Field().getSerializedSize());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
new file mode 100644
index 0000000..e66b371
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -0,0 +1,606 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+/**
+ * Tests related to parsing and serialization.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class WireFormatTest extends TestCase {
+  public void testSerialization() throws Exception {
+    TestAllTypes message = TestUtil.getAllSet();
+
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializationPacked() throws Exception {
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+    TestUtil.assertPackedFieldsSet(message2);
+  }
+
+  public void testSerializeExtensions() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+    // it should work.
+
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializePackedExtensions() throws Exception {
+    // TestPackedTypes and TestPackedExtensions should have compatible wire
+    // formats; check that they serialize to the same string.
+    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    TestPackedTypes message2 = TestUtil.getPackedSet();
+    ByteString rawBytes2 = message2.toByteString();
+
+    assertEquals(rawBytes, rawBytes2);
+  }
+
+  public void testSerializationPackedWithoutGetSerializedSize()
+      throws Exception {
+    // Write directly to an OutputStream, without invoking getSerializedSize()
+    // This used to be a bug where the size of a packed field was incorrect,
+    // since getSerializedSize() was never invoked.
+    TestPackedTypes message = TestUtil.getPackedSet();
+
+    // Directly construct a CodedOutputStream around the actual OutputStream,
+    // in case writeTo(OutputStream output) invokes getSerializedSize();
+    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
+
+    message.writeTo(codedOutput);
+
+    codedOutput.flush();
+
+    TestPackedTypes message2 = TestPackedTypes.parseFrom(
+        outputStream.toByteArray());
+
+    TestUtil.assertPackedFieldsSet(message2);
+  }
+
+  public void testSerializeExtensionsLite() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+    // it should work.
+
+    TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+    TestUtil.assertAllFieldsSet(message2);
+  }
+
+  public void testSerializePackedExtensionsLite() throws Exception {
+    // TestPackedTypes and TestPackedExtensions should have compatible wire
+    // formats; check that they serialize to the same string.
+    TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    TestPackedTypes message2 = TestUtil.getPackedSet();
+    ByteString rawBytes2 = message2.toByteString();
+
+    assertEquals(rawBytes, rawBytes2);
+  }
+
+  public void testParseExtensions() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+    // it should work.
+
+    TestAllTypes message = TestUtil.getAllSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestAllExtensions message2 =
+      TestAllExtensions.parseFrom(rawBytes, registry);
+
+    TestUtil.assertAllExtensionsSet(message2);
+  }
+
+  public void testParsePackedExtensions() throws Exception {
+    // Ensure that packed extensions can be properly parsed.
+    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestPackedExtensions message2 =
+        TestPackedExtensions.parseFrom(rawBytes, registry);
+
+    TestUtil.assertPackedExtensionsSet(message2);
+  }
+
+  public void testParseExtensionsLite() throws Exception {
+    // TestAllTypes and TestAllExtensions should have compatible wire formats,
+    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+    // it should work.
+
+    TestAllTypes message = TestUtil.getAllSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistryLite registry_lite = TestUtilLite.getExtensionRegistryLite();
+
+    TestAllExtensionsLite message2 =
+      TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
+
+    TestUtil.assertAllExtensionsSet(message2);
+
+    // Try again using a full extension registry.
+    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+    TestAllExtensionsLite message3 =
+      TestAllExtensionsLite.parseFrom(rawBytes, registry);
+
+    TestUtil.assertAllExtensionsSet(message3);
+  }
+
+  public void testParsePackedExtensionsLite() throws Exception {
+    // Ensure that packed extensions can be properly parsed.
+    TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet();
+    ByteString rawBytes = message.toByteString();
+
+    ExtensionRegistryLite registry = TestUtilLite.getExtensionRegistryLite();
+
+    TestPackedExtensionsLite message2 =
+        TestPackedExtensionsLite.parseFrom(rawBytes, registry);
+
+    TestUtil.assertPackedExtensionsSet(message2);
+  }
+
+  public void testExtensionsSerializedSize() throws Exception {
+    assertNotSame(TestUtil.getAllSet().getSerializedSize(),
+                  TestUtil.getAllExtensionsSet().getSerializedSize());
+  }
+
+  public void testSerializeDelimited() throws Exception {
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    TestUtil.getAllSet().writeDelimitedTo(output);
+    output.write(12);
+    TestUtil.getPackedSet().writeDelimitedTo(output);
+    output.write(34);
+
+    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
+
+    TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
+    assertEquals(12, input.read());
+    TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
+    assertEquals(34, input.read());
+    assertEquals(-1, input.read());
+
+    // We're at EOF, so parsing again should return null.
+    assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
+  }
+
+  private void assertFieldsInOrder(ByteString data) throws Exception {
+    CodedInputStream input = data.newCodedInput();
+    int previousTag = 0;
+
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+
+      assertTrue(tag > previousTag);
+      previousTag = tag;
+      input.skipField(tag);
+    }
+  }
+
+  public void testInterleavedFieldsAndExtensions() throws Exception {
+    // Tests that fields are written in order even when extension ranges
+    // are interleaved with field numbers.
+    ByteString data =
+      TestFieldOrderings.newBuilder()
+        .setMyInt(1)
+        .setMyString("foo")
+        .setMyFloat(1.0F)
+        .setExtension(UnittestProto.myExtensionInt, 23)
+        .setExtension(UnittestProto.myExtensionString, "bar")
+        .build().toByteString();
+    assertFieldsInOrder(data);
+
+    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+    ByteString dynamic_data =
+      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+        .setField(descriptor.findFieldByName("my_int"), 1L)
+        .setField(descriptor.findFieldByName("my_string"), "foo")
+        .setField(descriptor.findFieldByName("my_float"), 1.0F)
+        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+        .build().toByteString();
+    assertFieldsInOrder(dynamic_data);
+  }
+
+  private ExtensionRegistry getTestFieldOrderingsRegistry() {
+    ExtensionRegistry result = ExtensionRegistry.newInstance();
+    result.add(UnittestProto.myExtensionInt);
+    result.add(UnittestProto.myExtensionString);
+    return result;
+  }
+
+  public void testParseMultipleExtensionRanges() throws Exception {
+    // Make sure we can parse a message that contains multiple extensions
+    // ranges.
+    TestFieldOrderings source =
+      TestFieldOrderings.newBuilder()
+        .setMyInt(1)
+        .setMyString("foo")
+        .setMyFloat(1.0F)
+        .setExtension(UnittestProto.myExtensionInt, 23)
+        .setExtension(UnittestProto.myExtensionString, "bar")
+        .build();
+    TestFieldOrderings dest =
+      TestFieldOrderings.parseFrom(source.toByteString(),
+                                   getTestFieldOrderingsRegistry());
+    assertEquals(source, dest);
+  }
+
+  public void testParseMultipleExtensionRangesDynamic() throws Exception {
+    // Same as above except with DynamicMessage.
+    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+    DynamicMessage source =
+      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+        .setField(descriptor.findFieldByName("my_int"), 1L)
+        .setField(descriptor.findFieldByName("my_string"), "foo")
+        .setField(descriptor.findFieldByName("my_float"), 1.0F)
+        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+        .build();
+    DynamicMessage dest =
+      DynamicMessage.parseFrom(descriptor, source.toByteString(),
+                               getTestFieldOrderingsRegistry());
+    assertEquals(source, dest);
+  }
+
+  private static final int UNKNOWN_TYPE_ID = 1550055;
+  private static final int TYPE_ID_1 =
+    TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
+  private static final int TYPE_ID_2 =
+    TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
+
+  public void testSerializeMessageSetEagerly() throws Exception {
+    testSerializeMessageSetWithFlag(true);
+  }
+
+  public void testSerializeMessageSetNotEagerly() throws Exception {
+    testSerializeMessageSetWithFlag(false);
+  }
+
+  private void testSerializeMessageSetWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    // Set up a TestMessageSet with two known messages and an unknown one.
+    TestMessageSet messageSet =
+      TestMessageSet.newBuilder()
+        .setExtension(
+          TestMessageSetExtension1.messageSetExtension,
+          TestMessageSetExtension1.newBuilder().setI(123).build())
+        .setExtension(
+          TestMessageSetExtension2.messageSetExtension,
+          TestMessageSetExtension2.newBuilder().setStr("foo").build())
+        .setUnknownFields(
+          UnknownFieldSet.newBuilder()
+            .addField(UNKNOWN_TYPE_ID,
+              UnknownFieldSet.Field.newBuilder()
+                .addLengthDelimited(ByteString.copyFromUtf8("bar"))
+                .build())
+            .build())
+        .build();
+
+    ByteString data = messageSet.toByteString();
+
+    // Parse back using RawMessageSet and check the contents.
+    RawMessageSet raw = RawMessageSet.parseFrom(data);
+
+    assertTrue(raw.getUnknownFields().asMap().isEmpty());
+
+    assertEquals(3, raw.getItemCount());
+    assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
+    assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
+    assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
+
+    TestMessageSetExtension1 message1 =
+      TestMessageSetExtension1.parseFrom(
+        raw.getItem(0).getMessage().toByteArray());
+    assertEquals(123, message1.getI());
+
+    TestMessageSetExtension2 message2 =
+      TestMessageSetExtension2.parseFrom(
+        raw.getItem(1).getMessage().toByteArray());
+    assertEquals("foo", message2.getStr());
+
+    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+  }
+
+  public void testParseMessageSetEagerly() throws Exception {
+    testParseMessageSetWithFlag(true);
+  }
+
+  public void testParseMessageSetNotEagerly()throws Exception {
+    testParseMessageSetWithFlag(false);
+  }
+
+  private void testParseMessageSetWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+    // Set up a RawMessageSet with two known messages and an unknown one.
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_2)
+            .setMessage(
+              TestMessageSetExtension2.newBuilder()
+                .setStr("foo")
+                .build().toByteString())
+            .build())
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(UNKNOWN_TYPE_ID)
+            .setMessage(ByteString.copyFromUtf8("bar"))
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // Parse as a TestMessageSet and check the contents.
+    TestMessageSet messageSet =
+      TestMessageSet.parseFrom(data, extensionRegistry);
+
+    assertEquals(123, messageSet.getExtension(
+      TestMessageSetExtension1.messageSetExtension).getI());
+    assertEquals("foo", messageSet.getExtension(
+      TestMessageSetExtension2.messageSetExtension).getStr());
+
+    // Check for unknown field with type LENGTH_DELIMITED,
+    //   number UNKNOWN_TYPE_ID, and contents "bar".
+    UnknownFieldSet unknownFields = messageSet.getUnknownFields();
+    assertEquals(1, unknownFields.asMap().size());
+    assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
+
+    UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
+    assertEquals(1, field.getLengthDelimitedList().size());
+    assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
+  }
+
+  public void testParseMessageSetExtensionEagerly() throws Exception {
+    testParseMessageSetExtensionWithFlag(true);
+  }
+
+  public void testParseMessageSetExtensionNotEagerly() throws Exception {
+    testParseMessageSetExtensionWithFlag(false);
+  }
+
+  private void testParseMessageSetExtensionWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+    // Set up a RawMessageSet with a known messages.
+    int TYPE_ID_1 =
+        TestMessageSetExtension1
+            .getDescriptor().getExtensions().get(0).getNumber();
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // Parse as a TestMessageSet and check the contents.
+    TestMessageSet messageSet =
+        TestMessageSet.parseFrom(data, extensionRegistry);
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
+    testMergeLazyMessageSetExtensionWithFlag(true);
+  }
+
+  public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
+    testMergeLazyMessageSetExtensionWithFlag(false);
+  }
+
+  private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+    // Set up a RawMessageSet with a known messages.
+    int TYPE_ID_1 =
+        TestMessageSetExtension1
+            .getDescriptor().getExtensions().get(0).getNumber();
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .build();
+
+    ByteString data = raw.toByteString();
+
+    // Parse as a TestMessageSet and store value into lazy field
+    TestMessageSet messageSet =
+        TestMessageSet.parseFrom(data, extensionRegistry);
+    // Merge lazy field check the contents.
+    messageSet =
+        messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  public void testMergeMessageSetExtensionEagerly() throws Exception {
+    testMergeMessageSetExtensionWithFlag(true);
+  }
+
+  public void testMergeMessageSetExtensionNotEagerly() throws Exception {
+    testMergeMessageSetExtensionWithFlag(false);
+  }
+
+  private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing)
+      throws Exception {
+    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
+    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+
+    // Set up a RawMessageSet with a known messages.
+    int TYPE_ID_1 =
+        TestMessageSetExtension1
+            .getDescriptor().getExtensions().get(0).getNumber();
+    RawMessageSet raw =
+      RawMessageSet.newBuilder()
+        .addItem(
+          RawMessageSet.Item.newBuilder()
+            .setTypeId(TYPE_ID_1)
+            .setMessage(
+              TestMessageSetExtension1.newBuilder()
+                .setI(123)
+                .build().toByteString())
+            .build())
+        .build();
+
+    // Serialize RawMessageSet unnormally (message value before type id)
+    ByteString.CodedBuilder out = ByteString.newCodedBuilder(
+        raw.getSerializedSize());
+    CodedOutputStream output = out.getCodedOutput();
+    List<RawMessageSet.Item> items = raw.getItemList();
+    for (int i = 0; i < items.size(); i++) {
+      RawMessageSet.Item item = items.get(i);
+      output.writeTag(1, WireFormat.WIRETYPE_START_GROUP);
+      output.writeBytes(3, item.getMessage());
+      output.writeInt32(2, item.getTypeId());
+      output.writeTag(1, WireFormat.WIRETYPE_END_GROUP);
+    }
+    ByteString data = out.build();
+
+    // Merge bytes into TestMessageSet and check the contents.
+    TestMessageSet messageSet =
+        TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
+    assertEquals(123, messageSet.getExtension(
+        TestMessageSetExtension1.messageSetExtension).getI());
+  }
+
+  // ================================================================
+  // oneof
+  public void testOneofWireFormat() throws Exception {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestUtil.setOneof(builder);
+    TestOneof2 message = builder.build();
+    ByteString rawBytes = message.toByteString();
+
+    assertEquals(rawBytes.size(), message.getSerializedSize());
+
+    TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
+    TestUtil.assertOneofSet(message2);
+  }
+
+  public void testOneofOnlyLastSet() throws Exception {
+    TestOneofBackwardsCompatible source = TestOneofBackwardsCompatible
+        .newBuilder().setFooInt(100).setFooString("101").build();
+
+    ByteString rawBytes = source.toByteString();
+    TestOneof2 message = TestOneof2.parseFrom(rawBytes);
+    assertFalse(message.hasFooInt());
+    assertTrue(message.hasFooString());
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/any_test.proto b/java/core/src/test/proto/com/google/protobuf/any_test.proto
new file mode 100644
index 0000000..80173d8
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/any_test.proto
@@ -0,0 +1,42 @@
+// 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.
+
+syntax = "proto3";
+
+package any_test;
+
+option java_package = "any_test";
+option java_outer_classname = "AnyTestProto";
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  google.protobuf.Any value = 1;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
new file mode 100644
index 0000000..8f3ca8c
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
@@ -0,0 +1,93 @@
+// 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.
+
+syntax = "proto3";
+
+package field_presence_test;
+
+import "google/protobuf/unittest.proto";
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldPresenceTestProto";
+option java_generate_equals_and_hash = true;
+
+message TestAllTypes {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  message NestedMessage {
+    int32 value = 1;
+  }
+
+  int32 optional_int32 = 1;
+  string optional_string = 2;
+  bytes optional_bytes = 3;
+  NestedEnum optional_nested_enum = 4;
+  NestedMessage optional_nested_message = 5;
+  protobuf_unittest.TestRequired optional_proto2_message = 6;
+
+  oneof oneof_field {
+    int32 oneof_int32 = 11;
+    uint32 oneof_uint32 = 12;
+    string oneof_string = 13;
+    bytes oneof_bytes = 14;
+    NestedEnum oneof_nested_enum = 15;
+    NestedMessage oneof_nested_message = 16;
+    protobuf_unittest.TestRequired oneof_proto2_message = 17;
+  }
+
+  repeated int32 repeated_int32 = 21;
+  repeated string repeated_string = 22;
+  repeated bytes repeated_bytes = 23;
+  repeated NestedEnum repeated_nested_enum = 24;
+  repeated NestedMessage repeated_nested_message = 25;
+  repeated protobuf_unittest.TestRequired repeated_proto2_message = 26;
+  repeated NestedEnum packed_nested_enum = 27 [packed = true];
+}
+
+message TestOptionalFieldsOnly {
+  int32 optional_int32 = 1;
+  string optional_string = 2;
+  bytes optional_bytes = 3;
+  TestAllTypes.NestedEnum optional_nested_enum = 4;
+  TestAllTypes.NestedMessage optional_nested_message = 5;
+  protobuf_unittest.TestRequired optional_proto2_message = 6;
+}
+
+message TestRepeatedFieldsOnly {
+  repeated int32 repeated_int32 = 21;
+  repeated string repeated_string = 22;
+  repeated bytes repeated_bytes = 23;
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 24;
+  repeated TestAllTypes.NestedMessage repeated_nested_message = 25;
+  repeated protobuf_unittest.TestRequired repeated_proto2_message = 26;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
new file mode 100644
index 0000000..5580f72
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
@@ -0,0 +1,71 @@
+// 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.
+
+// Author: Naoki Iwasaki (niwasaki@google.com)
+//
+// A proto file with lazy fields
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message LazyMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 421];
+  optional LazyInnerMessageLite inner = 3 [lazy = true];
+  repeated LazyInnerMessageLite repeated_inner = 4 [lazy = true];
+
+  oneof oneof_field {
+    int32 oneof_num = 5;
+    LazyInnerMessageLite oneof_inner = 6 [lazy = true];
+  }
+}
+
+message LazyInnerMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 42];
+  optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
+
+  extensions 1000 to max;
+}
+
+message LazyExtension {
+  extend LazyInnerMessageLite {
+    optional LazyExtension extension = 1000;
+  }
+  optional string name = 1;
+}
+
+message LazyNestedInnerMessageLite {
+  optional int32 num = 1;
+  optional int32 num_with_default = 2 [default = 4];
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
new file mode 100644
index 0000000..6eef42c
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
@@ -0,0 +1,81 @@
+// 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.
+
+// Author: pbogle@google.com (Phil Bogle)
+
+syntax = "proto2";
+
+package protobuf_unittest.lite_equals_and_hash;
+
+option optimize_for = LITE_RUNTIME;
+
+message TestOneofEquals {
+  oneof oneof_field {
+    string name = 1;
+    int32 value = 2;
+  }
+}
+
+message Foo {
+  optional int32 value = 1;
+  repeated Bar bar = 2;
+
+  extensions 100 to max;
+}
+
+message Bar {
+  extend Foo {
+    optional Bar foo_ext = 100;
+  }
+
+  optional string name = 1;
+}
+
+message BarPrime {
+  optional string name = 1;
+}
+
+message Empty {
+}
+
+extend Foo {
+  optional int32 varint = 101;
+  optional fixed32 fixed32 = 102;
+  optional fixed64 fixed64 = 103;
+  optional group MyGroup = 104 {
+    optional string group_value = 1;
+  }
+}
+
+message TestRecursiveOneof {
+  oneof Foo {
+    TestRecursiveOneof r = 1;
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
new file mode 100644
index 0000000..d5418f2
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -0,0 +1,75 @@
+// 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.
+
+syntax = "proto2";
+
+
+option java_outer_classname = "MapForProto2TestProto";
+option java_generate_equals_and_hash = true;
+
+message TestMap {
+  message MessageValue {
+    optional int32 value = 1;
+  }
+  enum EnumValue {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+
+  map<int32, int32>         int32_to_int32_field = 1;
+  map<int32, string>        int32_to_string_field = 2;
+  map<int32, bytes>         int32_to_bytes_field = 3;
+  map<int32, EnumValue>     int32_to_enum_field = 4;
+  map<int32, MessageValue>  int32_to_message_field = 5;
+  map<string, int32>        string_to_int32_field = 6;
+
+  message MessageWithRequiredFields {
+    required int32 value = 1;
+  }
+  map<int32, MessageWithRequiredFields> required_message_map = 11;
+}
+
+message TestUnknownEnumValue {
+  // Wire-compatible with TestMap.int32_to_enum_field so we can test the
+  // parsing behavior of TestMap regarding unknown enum values.
+  map<int32, int32> int32_to_int32_field = 4;
+}
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+  optional int32 value = 1;
+  map<int32, TestRecursiveMap> recursive_map_field = 2;
+}
+package map_for_proto2_lite_test;
+option java_package = "map_lite_test";
+option optimize_for = LITE_RUNTIME;
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
new file mode 100644
index 0000000..a9be516
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
@@ -0,0 +1,74 @@
+// 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.
+
+syntax = "proto2";
+
+package map_for_proto2_test;
+
+option java_package = "map_test";
+option java_outer_classname = "MapForProto2TestProto";
+option java_generate_equals_and_hash = true;
+
+message TestMap {
+  message MessageValue {
+    optional int32 value = 1;
+  }
+  enum EnumValue {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+
+  map<int32, int32>         int32_to_int32_field = 1;
+  map<int32, string>        int32_to_string_field = 2;
+  map<int32, bytes>         int32_to_bytes_field = 3;
+  map<int32, EnumValue>     int32_to_enum_field = 4;
+  map<int32, MessageValue>  int32_to_message_field = 5;
+  map<string, int32>        string_to_int32_field = 6;
+
+  message MessageWithRequiredFields {
+    required int32 value = 1;
+  }
+  map<int32, MessageWithRequiredFields> required_message_map = 11;
+}
+
+message TestUnknownEnumValue {
+  // Wire-compatible with TestMap.int32_to_enum_field so we can test the
+  // parsing behavior of TestMap regarding unknown enum values.
+  map<int32, int32> int32_to_int32_field = 4;
+}
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+  optional int32 value = 1;
+  map<int32, TestRecursiveMap> recursive_map_field = 2;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
new file mode 100644
index 0000000..b02ac59
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
@@ -0,0 +1,61 @@
+// 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.
+
+// Regression test for a map initilaization order bug. The bug only manifests
+// when:
+//   1. A message contains map fields and is also extendable.
+//   2. There is a file-level extension defined in the same file referencing
+//      the above message as the extension type.
+//   3. The program executes in the following order:
+//        a. getDescriptor() is called on another message in the same file.
+//        b. use protobuf reflection to access the map field.
+// The symptom is a NullPointerException being thrown.
+syntax = "proto2";
+
+package map_test;
+
+option java_package = "map_test";
+option java_outer_classname = "MapInitializationOrderTest";
+option java_multiple_files = true;
+
+// Mirrors the structure of
+// javatests/com/google/cloud/common/logging/logging_test.proto.
+
+message Message1 {
+  map<string, bool> map_field = 1;
+  extensions 1000 to max;
+}
+
+extend Message1 {
+  optional Message1 recursive_extension = 1001;
+}
+
+message RedactAllTypes {
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
new file mode 100644
index 0000000..2280ac0
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -0,0 +1,63 @@
+// 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.
+
+syntax = "proto3";
+
+package map_test;
+
+option java_package = "map_test";
+option java_outer_classname = "MapTestProto";
+option java_generate_equals_and_hash = true;
+
+message TestMap {
+  message MessageValue {
+    int32 value = 1;
+  }
+  enum EnumValue {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+
+  map<int32, int32>        int32_to_int32_field = 1;
+  map<int32, string>       int32_to_string_field = 2;
+  map<int32, bytes>        int32_to_bytes_field = 3;
+  map<int32, EnumValue>    int32_to_enum_field = 4;
+  map<int32, MessageValue> int32_to_message_field = 5;
+  map<string, int32>       string_to_int32_field = 6;
+}
+
+// Used to test that a nested bulider containing map fields will properly
+// propagate the onChange event and mark its parent dirty when a change
+// is made to a map field.
+message TestOnChangeEventPropagation {
+  TestMap optional_message = 1;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto b/java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 0000000..9279050
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
@@ -0,0 +1,78 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+import "google/protobuf/unittest.proto";
+import "google/protobuf/descriptor.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+
+message MessageWithNoOuter {
+  message NestedMessage {
+    optional int32 i = 1;
+  }
+  enum NestedEnum {
+    BAZ = 3;
+  }
+  optional NestedMessage nested = 1;
+  repeated TestAllTypes foreign = 2;
+  optional NestedEnum nested_enum = 3;
+  optional EnumWithNoOuter foreign_enum = 4;
+}
+
+extend google.protobuf.EnumValueOptions {
+  optional int32 enum_value_option = 7654321;
+}
+
+enum EnumWithNoOuter {
+  FOO = 1 [(enum_value_option) = 12345];
+  BAR = 2;
+}
+
+service ServiceWithNoOuter {
+  rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+  optional int32 extension_with_outer = 1234567;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
new file mode 100644
index 0000000..a5dd66d
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
@@ -0,0 +1,54 @@
+// 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.
+
+// Author: jonp@google.com (Jon Perlow)
+//
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "NestedBuilders";
+
+
+message Vehicle {
+  optional Engine engine = 1;
+  repeated Wheel wheel = 2;
+}
+
+message Engine {
+  optional int32 cylinder = 1;
+  optional int32 liters = 2;
+}
+
+message Wheel {
+  optional int32 radius = 1;
+  optional int32 width = 2;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto
new file mode 100644
index 0000000..704e649
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto
@@ -0,0 +1,47 @@
+// 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.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions. Note that this must be defined in
+// a separate file to properly test the initialization of the outer class.
+
+syntax = "proto2";
+
+import "com/google/protobuf/non_nested_extension.proto";
+
+package protobuf_unittest;
+
+
+message MyNestedExtension {
+  extend MessageToBeExtended {
+    optional MessageToBeExtended recursiveExtension = 2;
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
new file mode 100644
index 0000000..a95c38b
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
@@ -0,0 +1,49 @@
+// 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.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with nested extensions for a MessageLite messages. Note that
+// this must be defined in a separate file to properly test the initialization
+// of the outer class.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+import "com/google/protobuf/non_nested_extension_lite.proto";
+
+message MyNestedExtensionLite {
+  extend MessageLiteToBeExtended {
+    optional MessageLiteToBeExtended recursiveExtensionLite = 3;
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
new file mode 100644
index 0000000..31fac55
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
@@ -0,0 +1,50 @@
+// 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.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+message MessageToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtension {
+}
+
+extend MessageToBeExtended {
+  optional MyNonNestedExtension nonNestedExtension = 1;
+}
+
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
new file mode 100644
index 0000000..37c369e
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
@@ -0,0 +1,51 @@
+// 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.
+
+// Author: Darick Tong (darick@google.com)
+//
+// A proto file with extensions for a MessageLite messages.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+option optimize_for = LITE_RUNTIME;
+
+message MessageLiteToBeExtended {
+  extensions 1 to max;
+}
+
+message MyNonNestedExtensionLite {
+}
+
+extend MessageLiteToBeExtended {
+  optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
+}
+
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
new file mode 100644
index 0000000..4208368
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
@@ -0,0 +1,40 @@
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+// This message's name is the same with the default outer class name of this
+// proto file. It's used to test if the compiler can avoid this conflict
+// correctly.
+message OuterClassNameTest {
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
new file mode 100644
index 0000000..3e5956b
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
@@ -0,0 +1,44 @@
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+message TestMessage2 {
+  message NestedMessage {
+    // This message's name is the same with the default outer class name of this
+    // proto file. It's used to test if the compiler can avoid this conflict
+    // correctly.
+    message OuterClassNameTest2 {
+    }
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
new file mode 100644
index 0000000..74a8ba3
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
@@ -0,0 +1,45 @@
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+message TestMessage3 {
+  message NestedMessage {
+    // This enum's name is the same with the default outer class name of this
+    // proto file. It's used to test if the compiler can avoid this conflict
+    // correctly.
+    enum OuterClassNameTest3 {
+      DUMMY_VALUE = 1;
+    }
+  }
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
new file mode 100644
index 0000000..2b1f65e
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -0,0 +1,169 @@
+// 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.
+
+// Author: jonp@google.com (Jon Perlow)
+
+// This file tests that various identifiers work as field and type names even
+// though the same identifiers are used internally by the java code generator.
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option java_generic_services = true;   // auto-added
+
+package io_protocol_tests;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TestBadIdentifiersProto";
+option java_generate_equals_and_hash = true;
+
+message TestMessage {
+  optional string cached_size = 1;
+  optional string serialized_size = 2;
+  optional string class = 3;
+}
+
+message Descriptor {
+  option no_standard_descriptor_accessor = true;
+  optional string descriptor = 1;
+  message NestedDescriptor {
+    option no_standard_descriptor_accessor = true;
+    optional string descriptor = 1;
+  }
+  optional NestedDescriptor nested_descriptor = 2;
+  enum NestedEnum {
+    UNKNOWN = 0;
+    FOO = 1;
+  }
+}
+
+message Parser {
+  enum ParserEnum {
+    UNKNOWN = 0;
+    PARSER = 1;
+  }
+  optional ParserEnum parser = 1;
+}
+
+message Deprecated {
+  enum TestEnum {
+    UNKNOWN = 0;
+    FOO = 1;
+
+    // Test if @Deprecated annotation conflicts with Deprecated message name.
+    BAR = 2 [ deprecated = true ];
+  }
+
+  optional int32 field1 = 1 [deprecated=true];
+  optional TestEnum field2 = 2 [deprecated=true];
+  optional TestMessage field3 = 3 [deprecated=true];
+}
+
+message Override {
+  optional int32 override = 1;
+}
+
+message Object {
+  optional int32 object = 1;
+  optional string string_object = 2;
+}
+
+message String {
+  optional string string = 1;
+}
+
+message Integer {
+  optional int32 integer = 1;
+}
+
+message Long {
+  optional int32 long = 1;
+}
+
+message Float {
+  optional float float = 1;
+}
+
+message Double {
+  optional double double = 1;
+}
+
+service TestConflictingMethodNames {
+  rpc Override(TestMessage) returns (TestMessage);
+}
+
+message TestConflictingFieldNames {
+  enum TestEnum {
+    UNKNOWN = 0;
+    FOO = 1;
+  }
+  message TestMessage {
+  }
+  repeated int32 int32_field = 1;
+  repeated TestEnum enum_field = 2;
+  repeated string string_field = 3;
+  repeated bytes bytes_field = 4;
+  repeated TestMessage message_field = 5;
+
+  optional int32 int32_field_count = 11;
+  optional TestEnum enum_field_count = 12;
+  optional string string_field_count = 13;
+  optional bytes bytes_field_count = 14;
+  optional TestMessage message_field_count = 15;
+
+  repeated int32 Int32Field = 21;  // NO_PROTO3
+  repeated TestEnum EnumField = 22;  // NO_PROTO3
+  repeated string StringField = 23;  // NO_PROTO3
+  repeated bytes BytesField = 24;  // NO_PROTO3
+  repeated TestMessage MessageField = 25;  // NO_PROTO3
+
+  // This field conflicts with "int32_field" as they both generate
+  // the method getInt32FieldList().
+  required int32 int32_field_list = 31;  // NO_PROTO3
+
+  extensions 1000 to max;  // NO_PROTO3
+
+  repeated int64 int64_field = 41;
+  extend TestConflictingFieldNames {  // NO_PROTO3
+    // We don't generate accessors for extensions so the following extension
+    // fields don't conflict with the repeated field "int64_field".
+    optional int64 int64_field_count = 1001;  // NO_PROTO3
+    optional int64 int64_field_list = 1002;  // NO_PROTO3
+  }  // NO_PROTO3
+}
+
+message TestMapField {
+  message MapField {}
+  message Pair {}
+  message Message {}
+
+  map<int32, int32> map_field = 1;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
new file mode 100644
index 0000000..119c1dc
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
@@ -0,0 +1,51 @@
+// 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.
+
+// Author: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+syntax = "proto2";
+
+package proto2_test_check_utf8;
+
+option java_outer_classname = "TestCheckUtf8";
+option java_string_check_utf8 = true;
+
+message StringWrapper {
+  required string req = 1;
+  optional string opt = 2;
+  repeated string rep = 3;
+}
+
+message BytesWrapper {
+  required bytes req = 1;
+  optional bytes opt = 2;
+  repeated bytes rep = 3;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
new file mode 100644
index 0000000..f06d76d
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
@@ -0,0 +1,52 @@
+// 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.
+
+// Author: Jacob Butcher (jbaum@google.com)
+//
+// Test file option java_string_check_utf8.
+syntax = "proto2";
+
+package proto2_test_check_utf8_size;
+
+option java_outer_classname = "TestCheckUtf8Size";
+option java_string_check_utf8 = true;
+option optimize_for = CODE_SIZE;
+
+message StringWrapperSize {
+  required string req = 1;
+  optional string opt = 2;
+  repeated string rep = 3;
+}
+
+message BytesWrapperSize {
+  required bytes req = 1;
+  optional bytes opt = 2;
+  repeated bytes rep = 3;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_custom_options.proto b/java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
new file mode 100644
index 0000000..f8efd45
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
@@ -0,0 +1,44 @@
+// 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.
+
+// Author: Feng Xiao (xiaofeng@google.com)
+//
+// Test that custom options defined in a proto file's dependencies are properly
+// initialized.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+
+import "google/protobuf/unittest_custom_options.proto";
+
+message TestMessageWithCustomOptionsContainer {
+  optional TestMessageWithCustomOptions field = 1;
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto b/java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
new file mode 100644
index 0000000..645f57b
--- /dev/null
+++ b/java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
@@ -0,0 +1,61 @@
+// 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.
+
+// Author: Darick Tong (darick@google.com)
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message Proto1 {
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
+
+  option experimental_java_interface_extends =
+      "com.google.protobuf.ExtraInterfaces.HasByteValue";
+
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>";
+
+  option experimental_java_builder_interface =
+      "com.google.protobuf.ExtraInterfaces.HasStringValueBuilder"
+      "<Proto1, Builder>";
+
+  optional string string_value = 1;
+  optional bool bool_value = 2;
+  optional bytes byte_value = 3;
+  optional int32 int_value = 4;
+}
+
+message Proto2 {
+  option experimental_java_message_interface =
+      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
+
+  optional bool bool_value = 1;
+}
diff --git a/java/lite/generate-sources-build.xml b/java/lite/generate-sources-build.xml
new file mode 100644
index 0000000..89c21c1
--- /dev/null
+++ b/java/lite/generate-sources-build.xml
@@ -0,0 +1,20 @@
+<project name="generate-sources">
+    <echo message="Running protoc ..."/>
+    <mkdir dir="${generated.sources.lite.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=lite:${generated.sources.lite.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/duration.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/empty.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/field_mask.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/source_context.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/struct.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/timestamp.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/type.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/wrappers.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/compiler/plugin.proto"/>
+    </exec>
+</project>
diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml
new file mode 100644
index 0000000..cdd1ee8
--- /dev/null
+++ b/java/lite/generate-test-sources-build.xml
@@ -0,0 +1,43 @@
+<project name="generate-test-sources">
+    <mkdir dir="${generated.testsources.lite.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=lite:${generated.testsources.lite.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="--proto_path=${test.proto.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset_wire_format.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_optimize_for.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite_imports_nonlite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test2.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test3.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_bad_identifiers.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8_size.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_custom_options.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
+    </exec>
+</project>
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
new file mode 100644
index 0000000..c403dc0
--- /dev/null
+++ b/java/lite/pom.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-3</version>
+  </parent>
+
+  <artifactId>protobuf-lite</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Protocol Buffers [Lite]</name>
+  <description>A trimmed-down version of the Protocol Buffers library.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <core.root>../core</core.root>
+    <test.proto.dir>${core.root}/src/test/proto</test.proto.dir>
+  </properties>
+
+  <build>
+    <sourceDirectory>${core.root}/src/main/java</sourceDirectory>
+    <testSourceDirectory>${core.root}/src/test/java</testSourceDirectory>
+
+    <plugins>
+      <!-- Use Antrun plugin to generate sources with protoc -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate core protos -->
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+
+          <!-- Generate the test protos -->
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-test-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Only compile a subset of the files -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <generatedSourcesDirectory>${generated.sources.lite.dir}</generatedSourcesDirectory>
+          <generatedTestSourcesDirectory>${generated.testsources.lite.dir}</generatedTestSourcesDirectory>
+          <includes>
+            <include>**/AbstractMessageLite.java</include>
+            <include>**/AbstractParser.java</include>
+            <include>**/AbstractProtobufList.java</include>
+            <include>**/BooleanArrayList.java</include>
+            <include>**/ByteString.java</include>
+            <include>**/CodedInputStream.java</include>
+            <include>**/CodedOutputStream.java</include>
+            <include>**/DoubleArrayList.java</include>
+            <include>**/ExtensionLite.java</include>
+            <include>**/ExtensionRegistryLite.java</include>
+            <include>**/FieldSet.java</include>
+            <include>**/FloatArrayList.java</include>
+            <include>**/GeneratedMessageLite.java</include>
+            <include>**/IntArrayList.java</include>
+            <include>**/Internal.java</include>
+            <include>**/InvalidProtocolBufferException.java</include>
+            <include>**/LazyFieldLite.java</include>
+            <include>**/LazyStringArrayList.java</include>
+            <include>**/LazyStringList.java</include>
+            <include>**/LongArrayList.java</include>
+            <include>**/MapEntryLite.java</include>
+            <include>**/MapFieldLite.java</include>
+            <include>**/MessageLite.java</include>
+            <include>**/MessageLiteOrBuilder.java</include>
+            <include>**/MessageLiteToString.java</include>
+            <include>**/MutabilityOracle.java</include>
+            <include>**/NioByteString.java</include>
+            <include>**/Parser.java</include>
+            <include>**/ProtobufArrayList.java</include>
+            <include>**/ProtocolStringList.java</include>
+            <include>**/RopeByteString.java</include>
+            <include>**/SmallSortedMap.java</include>
+            <include>**/TextFormatEscaper.java</include>
+            <include>**/UninitializedMessageException.java</include>
+            <include>**/UnknownFieldSetLite.java</include>
+            <include>**/UnmodifiableLazyStringList.java</include>
+            <include>**/UnsafeByteOperations.java</include>
+            <include>**/Utf8.java</include>
+            <include>**/WireFormat.java</include>
+          </includes>
+          <testIncludes>
+            <testInclude>**/*Lite.java</testInclude>
+            <testInclude>**/BooleanArrayListTest.java</testInclude>
+            <testInclude>**/DoubleArrayListTest.java</testInclude>
+            <testInclude>**/FloatArrayListTest.java</testInclude>
+            <testInclude>**/IntArrayListTest.java</testInclude>
+            <testInclude>**/LazyMessageLiteTest.java</testInclude>
+            <testInclude>**/LiteTest.java</testInclude>
+            <testInclude>**/LongArrayListTest.java</testInclude>
+            <testInclude>**/NioByteStringTest.java</testInclude>
+            <testInclude>**/ProtobufArrayListTest.java</testInclude>
+            <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
+          </testIncludes>
+        </configuration>
+      </plugin>
+
+      <!-- OSGI bundle configuration -->
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+            <Export-Package>com.google.${project.artifactId};version=${project.version}</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/java/pom.xml b/java/pom.xml
index 59083c2..7a1a91f 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -8,17 +8,35 @@
     <artifactId>google</artifactId>
     <version>1</version>
   </parent>
+
   <groupId>com.google.protobuf</groupId>
-  <artifactId>protobuf-java</artifactId>
-  <version>2.6.1</version>
-  <packaging>bundle</packaging>
-  <name>Protocol Buffer Java API</name>
+  <artifactId>protobuf-parent</artifactId>
+  <version>3.0.0-beta-3</version>
+  <packaging>pom</packaging>
+
+  <name>Protocol Buffers [Parent]</name>
+  <inceptionYear>2008</inceptionYear>
+  <url>https://developers.google.com/protocol-buffers/</url>
   <description>
     Protocol Buffers are a way of encoding structured data in an efficient yet
     extensible format.
   </description>
-  <inceptionYear>2008</inceptionYear>
-  <url>https://developers.google.com/protocol-buffers/</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+    <!-- These are relative to the submodules -->
+    <protobuf.basedir>${project.basedir}/../..</protobuf.basedir>
+    <protobuf.source.dir>${protobuf.basedir}/src</protobuf.source.dir>
+    <protoc>${protobuf.source.dir}/protoc</protoc>
+    <test.proto.dir>src/test/proto</test.proto.dir>
+    <generated.sources.dir>${project.build.directory}/generated-sources</generated.sources.dir>
+    <generated.testsources.dir>${project.build.directory}/generated-test-sources</generated.testsources.dir>
+    <generated.sources.lite.dir>${project.build.directory}/generated-sources-lite</generated.sources.lite.dir>
+    <generated.testsources.lite.dir>${project.build.directory}/generated-test-sources-lite</generated.testsources.lite.dir>
+  </properties>
+
   <licenses>
     <license>
       <name>New BSD license</name>
@@ -26,388 +44,146 @@
       <distribution>repo</distribution>
     </license>
   </licenses>
+
   <scm>
     <url>https://github.com/google/protobuf</url>
-    <connection>
-      scm:git:https://github.com/google/protobuf.git
-    </connection>
+    <connection>scm:git:https://github.com/google/protobuf.git</connection>
   </scm>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.4</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
-      <version>2.2</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymockclassextension</artifactId>
-      <version>2.2.1</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
+
+  <distributionManagement>
+    <snapshotRepository>
+      <id>sonatype-nexus-staging</id>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+    </snapshotRepository>
+    <repository>
+      <id>sonatype-nexus-staging</id>
+      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+    </repository>
+  </distributionManagement>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.12</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymock</artifactId>
+        <version>2.2</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymockclassextension</artifactId>
+        <version>2.2.1</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>com.google.guava</groupId>
+        <artifactId>guava</artifactId>
+        <version>18.0</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <includes>
-            <include>**/*Test.java</include>
-          </includes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>generate-sources</id>
-            <phase>generate-sources</phase>
-            <configuration>
-              <tasks>
-                <mkdir dir="target/generated-sources" />
-                <exec executable="../src/protoc">
-                  <arg value="--java_out=target/generated-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="../src/google/protobuf/descriptor.proto" />
-                </exec>
-              </tasks>
-              <sourceRoot>target/generated-sources</sourceRoot>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-          <execution>
-            <id>generate-test-sources</id>
-            <phase>generate-test-sources</phase>
-            <configuration>
-              <tasks>
-                <mkdir dir="target/generated-test-sources" />
-                <exec executable="../src/protoc">
-                  <arg value="--java_out=target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest.proto" />
-                  <arg value="../src/google/protobuf/unittest_import.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_public.proto" />
-                  <arg value="../src/google/protobuf/unittest_mset.proto" />
-                  <arg value="src/test/java/com/google/protobuf/lazy_fields_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/lite_equals_and_hash.proto" />
-                  <arg
-                    value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_builders_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_extension.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_extension_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/non_nested_extension.proto" />
-                  <arg value="src/test/java/com/google/protobuf/non_nested_extension_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test2.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test3.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_bad_identifiers.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_check_utf8.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_check_utf8_size.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_custom_options.proto" />
-                  <arg
-                    value="../src/google/protobuf/unittest_optimize_for.proto" />
-                  <arg
-                    value="../src/google/protobuf/unittest_custom_options.proto" />
-                  <arg value="../src/google/protobuf/unittest_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_public_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
-                  <arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
-                  <arg value="../src/google/protobuf/unittest_no_generic_services.proto" />
-                </exec>
-		<!-- java micro -->
-                <exec executable="../src/protoc">
-                  <arg value="--javamicro_out=opt=speed,java_use_vector=false,java_package=google/protobuf/unittest_import_micro.proto|com.google.protobuf.micro,java_outer_classname=google/protobuf/unittest_import_micro.proto|UnittestImportMicro:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_simple_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_stringutf8_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_recursive_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_single_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_multiple_micro.proto" />
-                  <arg value="../src/google/protobuf/unittest_multiple_nameclash_micro.proto" />
-                </exec>
-		<!-- java nano -->
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=
-                                  java_package = google/protobuf/unittest_import_nano.proto|com.google.protobuf.nano.testimport,
-                                  java_outer_classname = google/protobuf/unittest_import_nano.proto|UnittestImportNano,
-                                  generate_equals = true
-                                :target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_simple_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_stringutf8_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_recursive_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_single_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_multiple_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_multiple_nameclash_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_enum_class_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_repeated_merge_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_extension_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_extension_singular_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_extension_repeated_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_extension_packed_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_unknown_enum_values_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_has_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=optional_field_style=accessors,generate_equals=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_accessors_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=enum_style=java:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_enum_class_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_enum_class_multiple_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_repeated_packables_nano.proto" />
-                  <arg value="../src/google/protobuf/unittest_enum_validity_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=
-                                  optional_field_style=accessors,
-                                  java_outer_classname=google/protobuf/unittest_enum_validity_nano.proto|EnumValidityAccessors
-                                :target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_enum_validity_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=optional_field_style=reftypes,generate_equals=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_reference_types_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=optional_field_style=reftypes_compat_mode,generate_equals=true,java_outer_classname=google/protobuf/unittest_reference_types_nano.proto|NanoReferenceTypesCompat:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_reference_types_nano.proto" />
-                </exec>
-                <exec executable="../src/protoc">
-                  <arg value="--javanano_out=bytes_offset_length=true:target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest_bytes_offset_length_nano.proto" />
-                </exec>
-              </tasks>
-              <testSourceRoot>target/generated-test-sources</testSourceRoot>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
-            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
-            <Export-Package>com.google.protobuf;version=2.6.1</Export-Package>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.3</version>
+          <configuration>
+            <source>1.6</source>
+            <target>1.6</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-source-plugin</artifactId>
+          <version>2.4</version>
+          <executions>
+            <execution>
+              <id>attach-sources</id>
+              <goals>
+                <goal>jar-no-fork</goal>
+              </goals>
+            </execution>
+          </executions>
+        </plugin>
+        <plugin>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <version>2.10.3</version>
+          <executions>
+            <execution>
+              <id>attach-javadocs</id>
+              <goals>
+                <goal>jar</goal>
+              </goals>
+            </execution>
+          </executions>
+        </plugin>
+        <plugin>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>2.6</version>
+        </plugin>
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>build-helper-maven-plugin</artifactId>
+          <version>1.10</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>3.0.1</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-antrun-plugin</artifactId>
+          <version>1.8</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
   </build>
+
   <profiles>
     <profile>
-      <id>lite</id>
+      <id>release</id>
       <build>
         <plugins>
           <plugin>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/AbstractMessageLite.java</include>
-                <include>**/ByteString.java</include>
-                <include>**/CodedInputStream.java</include>
-                <include>**/CodedOutputStream.java</include>
-                <include>**/ExtensionRegistryLite.java</include>
-                <include>**/FieldSet.java</include>
-                <include>**/GeneratedMessageLite.java</include>
-                <include>**/Internal.java</include>
-                <include>**/InvalidProtocolBufferException.java</include>
-                <include>**/LazyStringArrayList.java</include>
-                <include>**/LazyStringList.java</include>
-                <include>**/MessageLite.java</include>
-                <include>**/MessageLiteOrBuilder.java</include>
-                <include>**/SmallSortedMap.java</include>
-                <include>**/UninitializedMessageException.java</include>
-                <include>**/UnmodifiableLazyStringList.java</include>
-                <include>**/WireFormat.java</include>
-                <include>**/Parser.java</include>
-                <include>**/AbstractParser.java</include>
-                <include>**/BoundedByteString.java</include>
-                <include>**/LiteralByteString.java</include>
-                <include>**/RopeByteString.java</include>
-                <include>**/Utf8.java</include>
-                <include>**/LazyField.java</include>
-                <include>**/LazyFieldLite.java</include>
-                <include>**/ProtocolStringList.java</include>
-              </includes>
-              <testIncludes>
-                <testInclude>**/LiteTest.java</testInclude>
-                <testInclude>**/*Lite.java</testInclude>
-              </testIncludes>
-            </configuration>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.6</version>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
           </plugin>
           <plugin>
-            <artifactId>maven-surefire-plugin</artifactId>
+            <groupId>org.sonatype.plugins</groupId>
+            <artifactId>nexus-staging-maven-plugin</artifactId>
+            <version>1.6.6</version>
+            <extensions>true</extensions>
             <configuration>
-              <includes>
-                <include>**/LiteTest.java</include>
-              </includes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-jar-plugin</artifactId>
-            <configuration>
-              <classifier>lite</classifier>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-    <profile>
-      <id>micro</id>
-      <build>
-        <plugins>
-          <plugin>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/MessageMicro.java</include>
-                <include>**/ByteStringMicro.java</include>
-                <include>**/CodedInputStreamMicro.java</include>
-                <include>**/CodedOutputStreamMicro.java</include>
-                <include>**/InvalidProtocolBufferMicroException.java</include>
-                <include>**/WireFormatMicro.java</include>
-              </includes>
-              <testIncludes>
-                <testInclude>**/MicroTest.java</testInclude>
-                <testInclude>**/MicroOuterClass.java</testInclude>
-                <testInclude>**/SimpleMessageMicro.java</testInclude>
-                <testInclude>**/StringUtf8.java</testInclude>
-                <testInclude>**/RecursiveMessageMicro.java</testInclude>
-                <testInclude>**/UnittestImportMicro.java</testInclude>
-              </testIncludes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/MicroTest.java</include>
-              </includes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-jar-plugin</artifactId>
-            <configuration>
-              <classifier>micro</classifier>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-    <profile>
-      <id>nano</id>
-      <build>
-        <plugins>
-          <plugin>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/MessageNano.java</include>
-                <include>**/CodedInputByteBufferNano.java</include>
-                <include>**/CodedOutputByteBufferNano.java</include>
-                <include>**/InternalNano.java</include>
-                <include>**/InvalidProtocolBufferNanoException.java</include>
-                <include>**/WireFormatNano.java</include>
-              </includes>
-              <testIncludes>
-                <testInclude>**/NanoTest.java</testInclude>
-                <testInclude>**/NanoOuterClass.java</testInclude>
-                <testInclude>**/SimpleMessageNano.java</testInclude>
-                <testInclude>**/StringUtf8.java</testInclude>
-                <testInclude>**/RecursiveMessageNano.java</testInclude>
-                <testInclude>**/UnittestImportNano.java</testInclude>
-              </testIncludes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/NanoTest.java</include>
-              </includes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-jar-plugin</artifactId>
-            <configuration>
-              <classifier>nano</classifier>
+              <serverId>sonatype-nexus-staging</serverId>
+              <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+              <autoReleaseAfterClose>false</autoReleaseAfterClose>
             </configuration>
           </plugin>
         </plugins>
       </build>
     </profile>
   </profiles>
+
+  <modules>
+    <module>core</module>
+    <module>lite</module>
+    <module>util</module>
+  </modules>
+
 </project>
diff --git a/java/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java b/java/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java
deleted file mode 100644
index 4b53607..0000000
--- a/java/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2014 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import android.os.Parcel;
-
-import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
-import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano.NestedMessage;
-import com.google.protobuf.nano.testext.Extensions.ContainerMessage;
-import com.google.protobuf.nano.testext.Extensions.ExtendableMessage;
-
-import junit.framework.TestCase;
-
-public class NanoAndroidTest extends TestCase {
-    public void testParceling() {
-        SimpleMessageNano message = new SimpleMessageNano();
-        message.d = 54321;
-        message.nestedMsg = new NestedMessage();
-        message.nestedMsg.bb = 12345;
-        message.defaultNestedEnum = SimpleMessageNano.FOO;
-
-        Parcel parcel = null;
-        try {
-            parcel = Parcel.obtain();
-            parcel.writeParcelable(message, 0);
-            parcel.setDataPosition(0);
-            message = parcel.readParcelable(getClass().getClassLoader());
-        } finally {
-            if (parcel != null) {
-                parcel.recycle();
-            }
-        }
-
-        assertEquals(54321, message.d);
-        assertEquals(12345, message.nestedMsg.bb);
-        assertEquals(SimpleMessageNano.FOO, message.defaultNestedEnum);
-    }
-
-    public void testExtendableParceling() {
-        ExtendableMessage message = new ExtendableMessage();
-        message.field = 12345;
-        message.setExtension(ContainerMessage.anotherThing, true);
-
-        Parcel parcel = null;
-        try {
-            parcel = Parcel.obtain();
-            parcel.writeParcelable(message, 0);
-            parcel.setDataPosition(0);
-            message = parcel.readParcelable(getClass().getClassLoader());
-        } finally {
-            if (parcel != null) {
-                parcel.recycle();
-            }
-        }
-
-        assertEquals(12345, message.field);
-        assertTrue((boolean) message.getExtension(ContainerMessage.anotherThing));
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
deleted file mode 100644
index ae9d5e3..0000000
--- a/java/src/main/java/com/google/protobuf/AbstractMessage.java
+++ /dev/null
@@ -1,466 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-import com.google.protobuf.Internal.EnumLite;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A partial implementation of the {@link Message} interface which implements
- * as many methods of that interface as possible in terms of other methods.
- *
- * @author kenton@google.com Kenton Varda
- */
-public abstract class AbstractMessage extends AbstractMessageLite
-                                      implements Message {
-  public boolean isInitialized() {
-    return MessageReflection.isInitialized(this);
-  }
-
-
-  public List<String> findInitializationErrors() {
-    return MessageReflection.findMissingFields(this);
-  }
-
-  public String getInitializationErrorString() {
-    return MessageReflection.delimitWithCommas(findInitializationErrors());
-  }
-
-  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
-  @Override
-  public boolean hasOneof(OneofDescriptor oneof) {
-    throw new UnsupportedOperationException("hasOneof() is not implemented.");
-  }
-
-  /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
-  @Override
-  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
-    throw new UnsupportedOperationException(
-        "getOneofFieldDescriptor() is not implemented.");
-  }
-
-  @Override
-  public final String toString() {
-    return TextFormat.printToString(this);
-  }
-
-  public void writeTo(final CodedOutputStream output) throws IOException {
-    MessageReflection.writeMessageTo(this, output, false);
-  }
-
-  private int memoizedSize = -1;
-
-  public int getSerializedSize() {
-    int size = memoizedSize;
-    if (size != -1) {
-      return size;
-    }
-
-    memoizedSize = MessageReflection.getSerializedSize(this);
-    return memoizedSize;
-  }
-
-  @Override
-  public boolean equals(final Object other) {
-    if (other == this) {
-      return true;
-    }
-    if (!(other instanceof Message)) {
-      return false;
-    }
-    final Message otherMessage = (Message) other;
-    if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
-      return false;
-    }
-    return compareFields(getAllFields(), otherMessage.getAllFields()) &&
-        getUnknownFields().equals(otherMessage.getUnknownFields());
-  }
-
-  @Override
-  public int hashCode() {
-    int hash = memoizedHashCode;
-    if (hash == 0) {
-      hash = 41;
-      hash = (19 * hash) + getDescriptorForType().hashCode();
-      hash = hashFields(hash, getAllFields());
-      hash = (29 * hash) + getUnknownFields().hashCode();
-      memoizedHashCode = hash;
-    }
-    return hash;
-  }
-  
-  private static ByteString toByteString(Object value) {
-    if (value instanceof byte[]) {
-      return ByteString.copyFrom((byte[]) value);
-    } else {
-      return (ByteString) value;
-    }
-  }
- 
-  /**
-   * Compares two bytes fields. The parameters must be either a byte array or a
-   * ByteString object. They can be of different type though.
-   */
-  private static boolean compareBytes(Object a, Object b) {
-    if (a instanceof byte[] && b instanceof byte[]) {
-      return Arrays.equals((byte[])a, (byte[])b);
-    }
-    return toByteString(a).equals(toByteString(b));
-  }
-  
-  /**
-   * Compares two set of fields.
-   * This method is used to implement {@link AbstractMessage#equals(Object)}
-   * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
-   * of bytes fields because immutable messages and mutable messages use
-   * different Java type to reprensent a bytes field and this method should be
-   * able to compare immutable messages, mutable messages and also an immutable
-   * message to a mutable message.
-   */
-  static boolean compareFields(Map<FieldDescriptor, Object> a,
-      Map<FieldDescriptor, Object> b) {
-    if (a.size() != b.size()) {
-      return false;
-    }
-    for (FieldDescriptor descriptor : a.keySet()) {
-      if (!b.containsKey(descriptor)) {
-        return false;
-      }
-      Object value1 = a.get(descriptor);
-      Object value2 = b.get(descriptor);
-      if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
-        if (descriptor.isRepeated()) {
-          List list1 = (List) value1;
-          List list2 = (List) value2;
-          if (list1.size() != list2.size()) {
-            return false;
-          }
-          for (int i = 0; i < list1.size(); i++) {
-            if (!compareBytes(list1.get(i), list2.get(i))) {
-              return false;
-            }
-          }
-        } else {
-          // Compares a singular bytes field.
-          if (!compareBytes(value1, value2)) {
-            return false;
-          }
-        }
-      } else {
-        // Compare non-bytes fields.
-        if (!value1.equals(value2)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  /** Get a hash code for given fields and values, using the given seed. */
-  @SuppressWarnings("unchecked")
-  protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) {
-    for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
-      FieldDescriptor field = entry.getKey();
-      Object value = entry.getValue();
-      hash = (37 * hash) + field.getNumber();
-      if (field.getType() != FieldDescriptor.Type.ENUM){
-        hash = (53 * hash) + value.hashCode();
-      } else if (field.isRepeated()) {
-        List<? extends EnumLite> list = (List<? extends EnumLite>) value;
-        hash = (53 * hash) + Internal.hashEnumList(list);
-      } else {
-        hash = (53 * hash) + Internal.hashEnum((EnumLite) value);
-      }
-    }
-    return hash;
-  }
-
-  /**
-   * Package private helper method for AbstractParser to create
-   * UninitializedMessageException with missing field information.
-   */
-  @Override
-  UninitializedMessageException newUninitializedMessageException() {
-    return Builder.newUninitializedMessageException(this);
-  }
-
-  // =================================================================
-
-  /**
-   * A partial implementation of the {@link Message.Builder} interface which
-   * implements as many methods of that interface as possible in terms of
-   * other methods.
-   */
-  @SuppressWarnings("unchecked")
-  public static abstract class Builder<BuilderType extends Builder>
-      extends AbstractMessageLite.Builder<BuilderType>
-      implements Message.Builder {
-    // The compiler produces an error if this is not declared explicitly.
-    @Override
-    public abstract BuilderType clone();
-
-    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
-    @Override
-    public boolean hasOneof(OneofDescriptor oneof) {
-      throw new UnsupportedOperationException("hasOneof() is not implemented.");
-    }
-
-    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
-    @Override
-    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
-      throw new UnsupportedOperationException(
-          "getOneofFieldDescriptor() is not implemented.");
-    }
-
-    /** TODO(jieluo): Clear it when all subclasses have implemented this method. */
-    @Override
-    public BuilderType clearOneof(OneofDescriptor oneof) {
-      throw new UnsupportedOperationException("clearOneof() is not implemented.");
-    }
-
-    public BuilderType clear() {
-      for (final Map.Entry<FieldDescriptor, Object> entry :
-           getAllFields().entrySet()) {
-        clearField(entry.getKey());
-      }
-      return (BuilderType) this;
-    }
-
-    public List<String> findInitializationErrors() {
-      return MessageReflection.findMissingFields(this);
-    }
-
-    public String getInitializationErrorString() {
-      return MessageReflection.delimitWithCommas(findInitializationErrors());
-    }
-
-    public BuilderType mergeFrom(final Message other) {
-      if (other.getDescriptorForType() != getDescriptorForType()) {
-        throw new IllegalArgumentException(
-          "mergeFrom(Message) can only merge messages of the same type.");
-      }
-
-      // Note:  We don't attempt to verify that other's fields have valid
-      //   types.  Doing so would be a losing battle.  We'd have to verify
-      //   all sub-messages as well, and we'd have to make copies of all of
-      //   them to insure that they don't change after verification (since
-      //   the Message interface itself cannot enforce immutability of
-      //   implementations).
-      // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
-      //   which allows people to make secure deep copies of messages.
-
-      for (final Map.Entry<FieldDescriptor, Object> entry :
-           other.getAllFields().entrySet()) {
-        final FieldDescriptor field = entry.getKey();
-        if (field.isRepeated()) {
-          for (final Object element : (List)entry.getValue()) {
-            addRepeatedField(field, element);
-          }
-        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-          final Message existingValue = (Message)getField(field);
-          if (existingValue == existingValue.getDefaultInstanceForType()) {
-            setField(field, entry.getValue());
-          } else {
-            setField(field,
-              existingValue.newBuilderForType()
-                .mergeFrom(existingValue)
-                .mergeFrom((Message)entry.getValue())
-                .build());
-          }
-        } else {
-          setField(field, entry.getValue());
-        }
-      }
-
-      mergeUnknownFields(other.getUnknownFields());
-
-      return (BuilderType) this;
-    }
-
-    @Override
-    public BuilderType mergeFrom(final CodedInputStream input)
-                                 throws IOException {
-      return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final CodedInputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      final UnknownFieldSet.Builder unknownFields =
-        UnknownFieldSet.newBuilder(getUnknownFields());
-      while (true) {
-        final int tag = input.readTag();
-        if (tag == 0) {
-          break;
-        }
-
-        MessageReflection.BuilderAdapter builderAdapter =
-            new MessageReflection.BuilderAdapter(this);
-        if (!MessageReflection.mergeFieldFrom(input, unknownFields,
-                                              extensionRegistry,
-                                              getDescriptorForType(),
-                                              builderAdapter,
-                                              tag)) {
-          // end group tag
-          break;
-        }
-      }
-      setUnknownFields(unknownFields.build());
-      return (BuilderType) this;
-    }
-
-    public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
-      setUnknownFields(
-        UnknownFieldSet.newBuilder(getUnknownFields())
-                       .mergeFrom(unknownFields)
-                       .build());
-      return (BuilderType) this;
-    }
-
-    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
-      throw new UnsupportedOperationException(
-          "getFieldBuilder() called on an unsupported message type.");
-    }
-
-    public String toString() {
-      return TextFormat.printToString(this);
-    }
-
-    /**
-     * Construct an UninitializedMessageException reporting missing fields in
-     * the given message.
-     */
-    protected static UninitializedMessageException
-        newUninitializedMessageException(Message message) {
-      return new UninitializedMessageException(
-          MessageReflection.findMissingFields(message));
-    }
-
-    // ===============================================================
-    // The following definitions seem to be required in order to make javac
-    // not produce weird errors like:
-    //
-    // java/com/google/protobuf/DynamicMessage.java:203: types
-    //   com.google.protobuf.AbstractMessage.Builder<
-    //     com.google.protobuf.DynamicMessage.Builder> and
-    //   com.google.protobuf.AbstractMessage.Builder<
-    //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
-    //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
-    //   return types.
-    //
-    // Strangely, these lines are only needed if javac is invoked separately
-    // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
-    // invoked on both simultaneously, it works.  (Or maybe the important
-    // point is whether or not DynamicMessage.java is compiled together with
-    // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
-    // bug.
-
-    @Override
-    public BuilderType mergeFrom(final ByteString data)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data);
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final ByteString data,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, extensionRegistry);
-    }
-
-    @Override
-    public BuilderType mergeFrom(final byte[] data)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data);
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final byte[] data, final int off, final int len)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, off, len);
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final byte[] data,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, extensionRegistry);
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final byte[] data, final int off, final int len,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      return super.mergeFrom(data, off, len, extensionRegistry);
-    }
-
-    @Override
-    public BuilderType mergeFrom(final InputStream input)
-        throws IOException {
-      return super.mergeFrom(input);
-    }
-
-    @Override
-    public BuilderType mergeFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      return super.mergeFrom(input, extensionRegistry);
-    }
-
-    @Override
-    public boolean mergeDelimitedFrom(final InputStream input)
-        throws IOException {
-      return super.mergeDelimitedFrom(input);
-    }
-
-    @Override
-    public boolean mergeDelimitedFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      return super.mergeDelimitedFrom(input, extensionRegistry);
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
deleted file mode 100644
index aac4fa7..0000000
--- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ /dev/null
@@ -1,355 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collection;
-
-/**
- * A partial implementation of the {@link MessageLite} interface which
- * implements as many methods of that interface as possible in terms of other
- * methods.
- *
- * @author kenton@google.com Kenton Varda
- */
-public abstract class AbstractMessageLite implements MessageLite {
-  protected int memoizedHashCode = 0;
-
-  public ByteString toByteString() {
-    try {
-      final ByteString.CodedBuilder out =
-        ByteString.newCodedBuilder(getSerializedSize());
-      writeTo(out.getCodedOutput());
-      return out.build();
-    } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a ByteString threw an IOException (should " +
-        "never happen).", e);
-    }
-  }
-
-  public byte[] toByteArray() {
-    try {
-      final byte[] result = new byte[getSerializedSize()];
-      final CodedOutputStream output = CodedOutputStream.newInstance(result);
-      writeTo(output);
-      output.checkNoSpaceLeft();
-      return result;
-    } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a byte array threw an IOException " +
-        "(should never happen).", e);
-    }
-  }
-
-  public void writeTo(final OutputStream output) throws IOException {
-    final int bufferSize =
-        CodedOutputStream.computePreferredBufferSize(getSerializedSize());
-    final CodedOutputStream codedOutput =
-        CodedOutputStream.newInstance(output, bufferSize);
-    writeTo(codedOutput);
-    codedOutput.flush();
-  }
-
-  public void writeDelimitedTo(final OutputStream output) throws IOException {
-    final int serialized = getSerializedSize();
-    final int bufferSize = CodedOutputStream.computePreferredBufferSize(
-        CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
-    final CodedOutputStream codedOutput =
-        CodedOutputStream.newInstance(output, bufferSize);
-    codedOutput.writeRawVarint32(serialized);
-    writeTo(codedOutput);
-    codedOutput.flush();
-  }
-
-
-  /**
-   * Package private helper method for AbstractParser to create
-   * UninitializedMessageException.
-   */
-  UninitializedMessageException newUninitializedMessageException() {
-    return new UninitializedMessageException(this);
-  }
-
-  protected static void checkByteStringIsUtf8(ByteString byteString)
-      throws IllegalArgumentException {
-    if (!byteString.isValidUtf8()) {
-      throw new IllegalArgumentException("Byte string is not UTF-8.");
-    }
-  }
-
-  /**
-   * A partial implementation of the {@link Message.Builder} interface which
-   * implements as many methods of that interface as possible in terms of
-   * other methods.
-   */
-  @SuppressWarnings("unchecked")
-  public static abstract class Builder<BuilderType extends Builder>
-      implements MessageLite.Builder {
-    // The compiler produces an error if this is not declared explicitly.
-    @Override
-    public abstract BuilderType clone();
-
-    public BuilderType mergeFrom(final CodedInputStream input)
-                                 throws IOException {
-      return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
-    }
-
-    // Re-defined here for return type covariance.
-    public abstract BuilderType mergeFrom(
-        final CodedInputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException;
-
-    public BuilderType mergeFrom(final ByteString data)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input = data.newCodedInput();
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    public BuilderType mergeFrom(
-        final ByteString data,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input = data.newCodedInput();
-        mergeFrom(input, extensionRegistry);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    public BuilderType mergeFrom(final byte[] data)
-        throws InvalidProtocolBufferException {
-      return mergeFrom(data, 0, data.length);
-    }
-
-    public BuilderType mergeFrom(final byte[] data, final int off,
-                                 final int len)
-                                 throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input =
-            CodedInputStream.newInstance(data, off, len);
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    public BuilderType mergeFrom(
-        final byte[] data,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      return mergeFrom(data, 0, data.length, extensionRegistry);
-    }
-
-    public BuilderType mergeFrom(
-        final byte[] data, final int off, final int len,
-        final ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input =
-            CodedInputStream.newInstance(data, off, len);
-        mergeFrom(input, extensionRegistry);
-        input.checkLastTagWas(0);
-        return (BuilderType) this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    public BuilderType mergeFrom(final InputStream input) throws IOException {
-      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
-      mergeFrom(codedInput);
-      codedInput.checkLastTagWas(0);
-      return (BuilderType) this;
-    }
-
-    public BuilderType mergeFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
-      mergeFrom(codedInput, extensionRegistry);
-      codedInput.checkLastTagWas(0);
-      return (BuilderType) this;
-    }
-
-    /**
-     * An InputStream implementations which reads from some other InputStream
-     * but is limited to a particular number of bytes.  Used by
-     * mergeDelimitedFrom().  This is intentionally package-private so that
-     * UnknownFieldSet can share it.
-     */
-    static final class LimitedInputStream extends FilterInputStream {
-      private int limit;
-
-      LimitedInputStream(InputStream in, int limit) {
-        super(in);
-        this.limit = limit;
-      }
-
-      @Override
-      public int available() throws IOException {
-        return Math.min(super.available(), limit);
-      }
-
-      @Override
-      public int read() throws IOException {
-        if (limit <= 0) {
-          return -1;
-        }
-        final int result = super.read();
-        if (result >= 0) {
-          --limit;
-        }
-        return result;
-      }
-
-      @Override
-      public int read(final byte[] b, final int off, int len)
-                      throws IOException {
-        if (limit <= 0) {
-          return -1;
-        }
-        len = Math.min(len, limit);
-        final int result = super.read(b, off, len);
-        if (result >= 0) {
-          limit -= result;
-        }
-        return result;
-      }
-
-      @Override
-      public long skip(final long n) throws IOException {
-        final long result = super.skip(Math.min(n, limit));
-        if (result >= 0) {
-          limit -= result;
-        }
-        return result;
-      }
-    }
-
-    public boolean mergeDelimitedFrom(
-        final InputStream input,
-        final ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      final int firstByte = input.read();
-      if (firstByte == -1) {
-        return false;
-      }
-      final int size = CodedInputStream.readRawVarint32(firstByte, input);
-      final InputStream limitedInput = new LimitedInputStream(input, size);
-      mergeFrom(limitedInput, extensionRegistry);
-      return true;
-    }
-
-    public boolean mergeDelimitedFrom(final InputStream input)
-        throws IOException {
-      return mergeDelimitedFrom(input,
-          ExtensionRegistryLite.getEmptyRegistry());
-    }
-
-    /**
-     * Construct an UninitializedMessageException reporting missing fields in
-     * the given message.
-     */
-    protected static UninitializedMessageException
-        newUninitializedMessageException(MessageLite message) {
-      return new UninitializedMessageException(message);
-    }
-
-    /**
-     * Adds the {@code values} to the {@code list}.  This is a helper method
-     * used by generated code.  Users should ignore it.
-     *
-     * @throws NullPointerException if any of the elements of {@code values} is
-     * null. When that happens, some elements of {@code values} may have already
-     * been added to the result {@code list}.
-     */
-    protected static <T> void addAll(final Iterable<T> values,
-                                     final Collection<? super T> list) {
-      if (values instanceof LazyStringList) {
-        // For StringOrByteStringLists, check the underlying elements to avoid
-        // forcing conversions of ByteStrings to Strings.
-        checkForNullValues(((LazyStringList) values).getUnderlyingElements());
-        list.addAll((Collection<T>) values);
-      } else if (values instanceof Collection) {
-        checkForNullValues(values);
-        list.addAll((Collection<T>) values);
-      } else {
-        for (final T value : values) {
-          if (value == null) {
-            throw new NullPointerException();
-          }
-          list.add(value);
-        }
-      }
-    }
-
-    private static void checkForNullValues(final Iterable<?> values) {
-      for (final Object value : values) {
-        if (value == null) {
-          throw new NullPointerException();
-        }
-      }
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/AbstractParser.java b/java/src/main/java/com/google/protobuf/AbstractParser.java
deleted file mode 100644
index 1a4c631..0000000
--- a/java/src/main/java/com/google/protobuf/AbstractParser.java
+++ /dev/null
@@ -1,253 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A partial implementation of the {@link Parser} interface which implements
- * as many methods of that interface as possible in terms of other methods.
- *
- * Note: This class implements all the convenience methods in the
- * {@link Parser} interface. See {@link Parser} for related javadocs.
- * Subclasses need to implement
- * {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
- *
- * @author liujisi@google.com (Pherl Liu)
- */
-public abstract class AbstractParser<MessageType extends MessageLite>
-    implements Parser<MessageType> {
-  /**
-   * Creates an UninitializedMessageException for MessageType.
-   */
-  private UninitializedMessageException
-      newUninitializedMessageException(MessageType message) {
-    if (message instanceof AbstractMessageLite) {
-      return ((AbstractMessageLite) message).newUninitializedMessageException();
-    }
-    return new UninitializedMessageException(message);
-  }
-
-  /**
-   * Helper method to check if message is initialized.
-   *
-   * @throws InvalidProtocolBufferException if it is not initialized.
-   * @return The message to check.
-   */
-  private MessageType checkMessageInitialized(MessageType message)
-      throws InvalidProtocolBufferException {
-    if (message != null && !message.isInitialized()) {
-      throw newUninitializedMessageException(message)
-          .asInvalidProtocolBufferException()
-          .setUnfinishedMessage(message);
-    }
-    return message;
-  }
-
-  private static final ExtensionRegistryLite EMPTY_REGISTRY
-      = ExtensionRegistryLite.getEmptyRegistry();
-
-  public MessageType parsePartialFrom(CodedInputStream input)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(input, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseFrom(CodedInputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(
-        parsePartialFrom(input, extensionRegistry));
-  }
-
-  public MessageType parseFrom(CodedInputStream input)
-      throws InvalidProtocolBufferException {
-    return parseFrom(input, EMPTY_REGISTRY);
-  }
-
-  public MessageType parsePartialFrom(ByteString data,
-                                      ExtensionRegistryLite extensionRegistry)
-    throws InvalidProtocolBufferException {
-    MessageType message;
-    try {
-      CodedInputStream input = data.newCodedInput();
-      message = parsePartialFrom(input, extensionRegistry);
-      try {
-        input.checkLastTagWas(0);
-      } catch (InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(message);
-      }
-      return message;
-    } catch (InvalidProtocolBufferException e) {
-      throw e;
-    }
-  }
-
-  public MessageType parsePartialFrom(ByteString data)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(data, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseFrom(ByteString data,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
-  }
-
-  public MessageType parseFrom(ByteString data)
-      throws InvalidProtocolBufferException {
-    return parseFrom(data, EMPTY_REGISTRY);
-  }
-
-  public MessageType parsePartialFrom(byte[] data, int off, int len,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    try {
-      CodedInputStream input = CodedInputStream.newInstance(data, off, len);
-      MessageType message = parsePartialFrom(input, extensionRegistry);
-      try {
-        input.checkLastTagWas(0);
-      } catch (InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(message);
-      }
-      return message;
-    } catch (InvalidProtocolBufferException e) {
-      throw e;
-    }
-  }
-
-  public MessageType parsePartialFrom(byte[] data, int off, int len)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
-  }
-
-  public MessageType parsePartialFrom(byte[] data,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(data, 0, data.length, extensionRegistry);
-  }
-
-  public MessageType parsePartialFrom(byte[] data)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseFrom(byte[] data, int off, int len,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(
-        parsePartialFrom(data, off, len, extensionRegistry));
-  }
-
-  public MessageType parseFrom(byte[] data, int off, int len)
-      throws InvalidProtocolBufferException {
-    return parseFrom(data, off, len, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseFrom(byte[] data,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return parseFrom(data, 0, data.length, extensionRegistry);
-  }
-
-  public MessageType parseFrom(byte[] data)
-      throws InvalidProtocolBufferException {
-    return parseFrom(data, EMPTY_REGISTRY);
-  }
-
-  public MessageType parsePartialFrom(InputStream input,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    CodedInputStream codedInput = CodedInputStream.newInstance(input);
-    MessageType message = parsePartialFrom(codedInput, extensionRegistry);
-    try {
-      codedInput.checkLastTagWas(0);
-    } catch (InvalidProtocolBufferException e) {
-      throw e.setUnfinishedMessage(message);
-    }
-    return message;
-  }
-
-  public MessageType parsePartialFrom(InputStream input)
-      throws InvalidProtocolBufferException {
-    return parsePartialFrom(input, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(
-        parsePartialFrom(input, extensionRegistry));
-  }
-
-  public MessageType parseFrom(InputStream input)
-      throws InvalidProtocolBufferException {
-    return parseFrom(input, EMPTY_REGISTRY);
-  }
-
-  public MessageType parsePartialDelimitedFrom(
-      InputStream input,
-      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    int size;
-    try {
-      int firstByte = input.read();
-      if (firstByte == -1) {
-        return null;
-      }
-      size = CodedInputStream.readRawVarint32(firstByte, input);
-    } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage());
-    }
-    InputStream limitedInput = new LimitedInputStream(input, size);
-    return parsePartialFrom(limitedInput, extensionRegistry);
-  }
-
-  public MessageType parsePartialDelimitedFrom(InputStream input)
-      throws InvalidProtocolBufferException {
-    return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
-  }
-
-  public MessageType parseDelimitedFrom(
-      InputStream input,
-      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(
-        parsePartialDelimitedFrom(input, extensionRegistry));
-  }
-
-  public MessageType parseDelimitedFrom(InputStream input)
-      throws InvalidProtocolBufferException {
-    return parseDelimitedFrom(input, EMPTY_REGISTRY);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/BoundedByteString.java b/java/src/main/java/com/google/protobuf/BoundedByteString.java
deleted file mode 100644
index 2828e9c..0000000
--- a/java/src/main/java/com/google/protobuf/BoundedByteString.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.NoSuchElementException;
-
-/**
- * This class is used to represent the substring of a {@link ByteString} over a
- * single byte array. In terms of the public API of {@link ByteString}, you end
- * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
- * ByteString#substring(int, int)}.
- *
- * <p>This class contains most of the overhead involved in creating a substring
- * from a {@link LiteralByteString}.  The overhead involves some range-checking
- * and two extra fields.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-class BoundedByteString extends LiteralByteString {
-
-  private final int bytesOffset;
-  private final int bytesLength;
-
-  /**
-   * Creates a {@code BoundedByteString} backed by the sub-range of given array,
-   * without copying.
-   *
-   * @param bytes  array to wrap
-   * @param offset index to first byte to use in bytes
-   * @param length number of bytes to use from bytes
-   * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
-   *                                  or if {@code offset + length >
-   *                                  bytes.length}.
-   */
-  BoundedByteString(byte[] bytes, int offset, int length) {
-    super(bytes);
-    if (offset < 0) {
-      throw new IllegalArgumentException("Offset too small: " + offset);
-    }
-    if (length < 0) {
-      throw new IllegalArgumentException("Length too small: " + offset);
-    }
-    if ((long) offset + length > bytes.length) {
-      throw new IllegalArgumentException(
-          "Offset+Length too large: " + offset + "+" + length);
-    }
-
-    this.bytesOffset = offset;
-    this.bytesLength = length;
-  }
-
-  /**
-   * Gets the byte at the given index.
-   * Throws {@link ArrayIndexOutOfBoundsException}
-   * for backwards-compatibility reasons although it would more properly be
-   * {@link IndexOutOfBoundsException}.
-   *
-   * @param index index of byte
-   * @return the value
-   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
-   */
-  @Override
-  public byte byteAt(int index) {
-    // We must check the index ourselves as we cannot rely on Java array index
-    // checking for substrings.
-    if (index < 0) {
-      throw new ArrayIndexOutOfBoundsException("Index too small: " + index);
-    }
-    if (index >= size()) {
-      throw new ArrayIndexOutOfBoundsException(
-          "Index too large: " + index + ", " + size());
-    }
-
-    return bytes[bytesOffset + index];
-  }
-
-  @Override
-  public int size() {
-    return bytesLength;
-  }
-
-  @Override
-  protected int getOffsetIntoBytes() {
-    return bytesOffset;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  @Override
-  protected void copyToInternal(byte[] target, int sourceOffset, 
-      int targetOffset, int numberToCopy) {
-    System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
-        targetOffset, numberToCopy);
-  }
-
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new BoundedByteIterator();
-  }
-
-  private class BoundedByteIterator implements ByteIterator {
-
-    private int position;
-    private final int limit;
-
-    private BoundedByteIterator() {
-      position = getOffsetIntoBytes();
-      limit = position + size();
-    }
-
-    public boolean hasNext() {
-      return (position < limit);
-    }
-
-    public Byte next() {
-      // Boxing calls Byte.valueOf(byte), which does not instantiate.
-      return nextByte();
-    }
-
-    public byte nextByte() {
-      if (position >= limit) {
-        throw new NoSuchElementException();
-      }
-      return bytes[position++];
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java
deleted file mode 100644
index 7da5612..0000000
--- a/java/src/main/java/com/google/protobuf/ByteString.java
+++ /dev/null
@@ -1,1022 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * Immutable sequence of bytes.  Substring is supported by sharing the reference
- * to the immutable underlying bytes, as with {@link String}.  Concatenation is
- * likewise supported without copying (long strings) by building a tree of
- * pieces in {@link RopeByteString}.
- * <p>
- * Like {@link String}, the contents of a {@link ByteString} can never be
- * observed to change, not even in the presence of a data race or incorrect
- * API usage in the client code.
- *
- * @author crazybob@google.com Bob Lee
- * @author kenton@google.com Kenton Varda
- * @author carlanton@google.com Carl Haverl
- * @author martinrb@google.com Martin Buchholz
- */
-public abstract class ByteString implements Iterable<Byte> {
-
-  /**
-   * When two strings to be concatenated have a combined length shorter than
-   * this, we just copy their bytes on {@link #concat(ByteString)}.
-   * The trade-off is copy size versus the overhead of creating tree nodes
-   * in {@link RopeByteString}.
-   */
-  static final int CONCATENATE_BY_COPY_SIZE = 128;
-
-  /**
-   * When copying an InputStream into a ByteString with .readFrom(),
-   * the chunks in the underlying rope start at 256 bytes, but double
-   * each iteration up to 8192 bytes.
-   */
-  static final int MIN_READ_FROM_CHUNK_SIZE = 0x100;  // 256b
-  static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000;  // 8k
-
-  /**
-   * Empty {@code ByteString}.
-   */
-  public static final ByteString EMPTY = new LiteralByteString(new byte[0]);
-
-  // This constructor is here to prevent subclassing outside of this package,
-  ByteString() {}
-
-  /**
-   * Gets the byte at the given index. This method should be used only for
-   * random access to individual bytes. To access bytes sequentially, use the
-   * {@link ByteIterator} returned by {@link #iterator()}, and call {@link
-   * #substring(int, int)} first if necessary.
-   *
-   * @param index index of byte
-   * @return the value
-   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
-   */
-  public abstract byte byteAt(int index);
-
-  /**
-   * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString.
-   * To avoid auto-boxing, you may get the iterator manually and call
-   * {@link ByteIterator#nextByte()}.
-   *
-   * @return the iterator
-   */
-  public abstract ByteIterator iterator();
-
-  /**
-   * This interface extends {@code Iterator<Byte>}, so that we can return an
-   * unboxed {@code byte}.
-   */
-  public interface ByteIterator extends Iterator<Byte> {
-    /**
-     * An alternative to {@link Iterator#next()} that returns an
-     * unboxed primitive {@code byte}.
-     *
-     * @return the next {@code byte} in the iteration
-     * @throws NoSuchElementException if the iteration has no more elements
-     */
-    byte nextByte();
-  }
-
-  /**
-   * Gets the number of bytes.
-   *
-   * @return size in bytes
-   */
-  public abstract int size();
-
-  /**
-   * Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
-   *
-   * @return true if this is zero bytes long
-   */
-  public boolean isEmpty() {
-    return size() == 0;
-  }
-
-  // =================================================================
-  // ByteString -> substring
-
-  /**
-   * Return the substring from {@code beginIndex}, inclusive, to the end of the
-   * string.
-   *
-   * @param beginIndex start at this index
-   * @return substring sharing underlying data
-   * @throws IndexOutOfBoundsException if {@code beginIndex < 0} or
-   *     {@code beginIndex > size()}.
-   */
-  public ByteString substring(int beginIndex) {
-    return substring(beginIndex, size());
-  }
-
-  /**
-   * Return the substring from {@code beginIndex}, inclusive, to {@code
-   * endIndex}, exclusive.
-   *
-   * @param beginIndex start at this index
-   * @param endIndex   the last character is the one before this index
-   * @return substring sharing underlying data
-   * @throws IndexOutOfBoundsException if {@code beginIndex < 0},
-   *     {@code endIndex > size()}, or {@code beginIndex > endIndex}.
-   */
-  public abstract ByteString substring(int beginIndex, int endIndex);
-
-  /**
-   * Tests if this bytestring starts with the specified prefix.
-   * Similar to {@link String#startsWith(String)}
-   *
-   * @param prefix the prefix.
-   * @return <code>true</code> if the byte sequence represented by the
-   *         argument is a prefix of the byte sequence represented by
-   *         this string; <code>false</code> otherwise.
-   */
-  public boolean startsWith(ByteString prefix) {
-    return size() >= prefix.size() &&
-           substring(0, prefix.size()).equals(prefix);
-  }
-
-  /**
-   * Tests if this bytestring ends with the specified suffix.
-   * Similar to {@link String#endsWith(String)}
-   *
-   * @param suffix the suffix.
-   * @return <code>true</code> if the byte sequence represented by the
-   *         argument is a suffix of the byte sequence represented by
-   *         this string; <code>false</code> otherwise.
-   */
-  public boolean endsWith(ByteString suffix) {
-    return size() >= suffix.size() &&
-        substring(size() - suffix.size()).equals(suffix);
-  }
-
-  // =================================================================
-  // byte[] -> ByteString
-
-  /**
-   * Copies the given bytes into a {@code ByteString}.
-   *
-   * @param bytes source array
-   * @param offset offset in source array
-   * @param size number of bytes to copy
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFrom(byte[] bytes, int offset, int size) {
-    byte[] copy = new byte[size];
-    System.arraycopy(bytes, offset, copy, 0, size);
-    return new LiteralByteString(copy);
-  }
-
-  /**
-   * Copies the given bytes into a {@code ByteString}.
-   *
-   * @param bytes to copy
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFrom(byte[] bytes) {
-    return copyFrom(bytes, 0, bytes.length);
-  }
-
-  /**
-   * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
-   * a {@code ByteString}.
-   *
-   * @param bytes source buffer
-   * @param size number of bytes to copy
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFrom(ByteBuffer bytes, int size) {
-    byte[] copy = new byte[size];
-    bytes.get(copy);
-    return new LiteralByteString(copy);
-  }
-
-  /**
-   * Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
-   * a {@code ByteString}.
-   *
-   * @param bytes sourceBuffer
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFrom(ByteBuffer bytes) {
-    return copyFrom(bytes, bytes.remaining());
-  }
-
-  /**
-   * Encodes {@code text} into a sequence of bytes using the named charset
-   * and returns the result as a {@code ByteString}.
-   *
-   * @param text source string
-   * @param charsetName encoding to use
-   * @return new {@code ByteString}
-   * @throws UnsupportedEncodingException if the encoding isn't found
-   */
-  public static ByteString copyFrom(String text, String charsetName)
-      throws UnsupportedEncodingException {
-    return new LiteralByteString(text.getBytes(charsetName));
-  }
-
-  /**
-   * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
-   * result as a {@code ByteString}.
-   *
-   * @param text source string
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFromUtf8(String text) {
-    try {
-      return new LiteralByteString(text.getBytes("UTF-8"));
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported?", e);
-    }
-  }
-
-  // =================================================================
-  // InputStream -> ByteString
-
-  /**
-   * Completely reads the given stream's bytes into a
-   * {@code ByteString}, blocking if necessary until all bytes are
-   * read through to the end of the stream.
-   *
-   * <b>Performance notes:</b> The returned {@code ByteString} is an
-   * immutable tree of byte arrays ("chunks") of the stream data.  The
-   * first chunk is small, with subsequent chunks each being double
-   * the size, up to 8K.  If the caller knows the precise length of
-   * the stream and wishes to avoid all unnecessary copies and
-   * allocations, consider using the two-argument version of this
-   * method, below.
-   *
-   * @param streamToDrain The source stream, which is read completely
-   *     but not closed.
-   * @return A new {@code ByteString} which is made up of chunks of
-   *     various sizes, depending on the behavior of the underlying
-   *     stream.
-   * @throws IOException IOException is thrown if there is a problem
-   *     reading the underlying stream.
-   */
-  public static ByteString readFrom(InputStream streamToDrain)
-      throws IOException {
-    return readFrom(
-        streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
-  }
-
-  /**
-   * Completely reads the given stream's bytes into a
-   * {@code ByteString}, blocking if necessary until all bytes are
-   * read through to the end of the stream.
-   *
-   * <b>Performance notes:</b> The returned {@code ByteString} is an
-   * immutable tree of byte arrays ("chunks") of the stream data.  The
-   * chunkSize parameter sets the size of these byte arrays. In
-   * particular, if the chunkSize is precisely the same as the length
-   * of the stream, unnecessary allocations and copies will be
-   * avoided. Otherwise, the chunks will be of the given size, except
-   * for the last chunk, which will be resized (via a reallocation and
-   * copy) to contain the remainder of the stream.
-   *
-   * @param streamToDrain The source stream, which is read completely
-   *     but not closed.
-   * @param chunkSize The size of the chunks in which to read the
-   *     stream.
-   * @return A new {@code ByteString} which is made up of chunks of
-   *     the given size.
-   * @throws IOException IOException is thrown if there is a problem
-   *     reading the underlying stream.
-   */
-  public static ByteString readFrom(InputStream streamToDrain, int chunkSize)
-      throws IOException {
-    return readFrom(streamToDrain, chunkSize, chunkSize);
-  }
-
-  // Helper method that takes the chunk size range as a parameter.
-  public static ByteString readFrom(InputStream streamToDrain, int minChunkSize,
-      int maxChunkSize) throws IOException {
-    Collection<ByteString> results = new ArrayList<ByteString>();
-
-    // copy the inbound bytes into a list of chunks; the chunk size
-    // grows exponentially to support both short and long streams.
-    int chunkSize = minChunkSize;
-    while (true) {
-      ByteString chunk = readChunk(streamToDrain, chunkSize);
-      if (chunk == null) {
-        break;
-      }
-      results.add(chunk);
-      chunkSize = Math.min(chunkSize * 2, maxChunkSize);
-    }
-
-    return ByteString.copyFrom(results);
-  }
-
-  /**
-   * Blocks until a chunk of the given size can be made from the
-   * stream, or EOF is reached.  Calls read() repeatedly in case the
-   * given stream implementation doesn't completely fill the given
-   * buffer in one read() call.
-   *
-   * @return A chunk of the desired size, or else a chunk as large as
-   * was available when end of stream was reached. Returns null if the
-   * given stream had no more data in it.
-   */
-  private static ByteString readChunk(InputStream in, final int chunkSize)
-      throws IOException {
-      final byte[] buf = new byte[chunkSize];
-      int bytesRead = 0;
-      while (bytesRead < chunkSize) {
-        final int count = in.read(buf, bytesRead, chunkSize - bytesRead);
-        if (count == -1) {
-          break;
-        }
-        bytesRead += count;
-      }
-
-      if (bytesRead == 0) {
-        return null;
-      } else {
-        return ByteString.copyFrom(buf, 0, bytesRead);
-      }
-  }
-
-  // =================================================================
-  // Multiple ByteStrings -> One ByteString
-
-  /**
-   * Concatenate the given {@code ByteString} to this one. Short concatenations,
-   * of total size smaller than {@link ByteString#CONCATENATE_BY_COPY_SIZE}, are
-   * produced by copying the underlying bytes (as per Rope.java, <a
-   * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
-   * BAP95 </a>. In general, the concatenate involves no copying.
-   *
-   * @param other string to concatenate
-   * @return a new {@code ByteString} instance
-   */
-  public ByteString concat(ByteString other) {
-    int thisSize = size();
-    int otherSize = other.size();
-    if ((long) thisSize + otherSize >= Integer.MAX_VALUE) {
-      throw new IllegalArgumentException("ByteString would be too long: " +
-                                         thisSize + "+" + otherSize);
-    }
-
-    return RopeByteString.concatenate(this, other);
-  }
-
-  /**
-   * Concatenates all byte strings in the iterable and returns the result.
-   * This is designed to run in O(list size), not O(total bytes).
-   *
-   * <p>The returned {@code ByteString} is not necessarily a unique object.
-   * If the list is empty, the returned object is the singleton empty
-   * {@code ByteString}.  If the list has only one element, that
-   * {@code ByteString} will be returned without copying.
-   *
-   * @param byteStrings strings to be concatenated
-   * @return new {@code ByteString}
-   */
-  public static ByteString copyFrom(Iterable<ByteString> byteStrings) {
-    Collection<ByteString> collection;
-    if (!(byteStrings instanceof Collection)) {
-      collection = new ArrayList<ByteString>();
-      for (ByteString byteString : byteStrings) {
-        collection.add(byteString);
-      }
-    } else {
-      collection = (Collection<ByteString>) byteStrings;
-    }
-    ByteString result;
-    if (collection.isEmpty()) {
-      result = EMPTY;
-    } else {
-      result = balancedConcat(collection.iterator(), collection.size());
-    }
-    return result;
-  }
-
-  // Internal function used by copyFrom(Iterable<ByteString>).
-  // Create a balanced concatenation of the next "length" elements from the
-  // iterable.
-  private static ByteString balancedConcat(Iterator<ByteString> iterator,
-      int length) {
-    assert length >= 1;
-    ByteString result;
-    if (length == 1) {
-      result = iterator.next();
-    } else {
-      int halfLength = length >>> 1;
-      ByteString left = balancedConcat(iterator, halfLength);
-      ByteString right = balancedConcat(iterator, length - halfLength);
-      result = left.concat(right);
-    }
-    return result;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  /**
-   * Copies bytes into a buffer at the given offset.
-   *
-   * @param target buffer to copy into
-   * @param offset in the target buffer
-   * @throws IndexOutOfBoundsException if the offset is negative or too large
-   */
-  public void copyTo(byte[] target, int offset) {
-    copyTo(target, 0, offset, size());
-  }
-
-  /**
-   * Copies bytes into a buffer.
-   *
-   * @param target       buffer to copy into
-   * @param sourceOffset offset within these bytes
-   * @param targetOffset offset within the target buffer
-   * @param numberToCopy number of bytes to copy
-   * @throws IndexOutOfBoundsException if an offset or size is negative or too
-   *     large
-   */
-  public void copyTo(byte[] target, int sourceOffset, int targetOffset,
-      int numberToCopy) {
-    if (sourceOffset < 0) {
-      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
-    }
-    if (targetOffset < 0) {
-      throw new IndexOutOfBoundsException("Target offset < 0: " + targetOffset);
-    }
-    if (numberToCopy < 0) {
-      throw new IndexOutOfBoundsException("Length < 0: " + numberToCopy);
-    }
-    if (sourceOffset + numberToCopy > size()) {
-      throw new IndexOutOfBoundsException(
-          "Source end offset < 0: " + (sourceOffset + numberToCopy));
-    }
-    if (targetOffset + numberToCopy > target.length) {
-      throw new IndexOutOfBoundsException(
-          "Target end offset < 0: " + (targetOffset + numberToCopy));
-    }
-    if (numberToCopy > 0) {
-      copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
-    }
-  }
-
-  /**
-   * Internal (package private) implementation of
-   * @link{#copyTo(byte[],int,int,int}.
-   * It assumes that all error checking has already been performed and that 
-   * @code{numberToCopy > 0}.
-   */
-  protected abstract void copyToInternal(byte[] target, int sourceOffset,
-      int targetOffset, int numberToCopy);
-
-  /**
-   * Copies bytes into a ByteBuffer.
-   *
-   * @param target ByteBuffer to copy into.
-   * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
-   * @throws java.nio.BufferOverflowException if the {@code target}'s
-   *     remaining() space is not large enough to hold the data.
-   */
-  public abstract void copyTo(ByteBuffer target);
-
-  /**
-   * Copies bytes to a {@code byte[]}.
-   *
-   * @return copied bytes
-   */
-  public byte[] toByteArray() {
-    int size = size();
-    if (size == 0) {
-      return Internal.EMPTY_BYTE_ARRAY;
-    }
-    byte[] result = new byte[size];
-    copyToInternal(result, 0, 0, size);
-    return result;
-  }
-
-  /**
-   * Writes the complete contents of this byte string to
-   * the specified output stream argument.
-   *
-   * @param  out  the output stream to which to write the data.
-   * @throws IOException  if an I/O error occurs.
-   */
-  public abstract void writeTo(OutputStream out) throws IOException;
-  
-  /**
-   * Writes a specified part of this byte string to an output stream.
-   *
-   * @param  out  the output stream to which to write the data.
-   * @param  sourceOffset offset within these bytes
-   * @param  numberToWrite number of bytes to write
-   * @throws IOException  if an I/O error occurs.
-   * @throws IndexOutOfBoundsException if an offset or size is negative or too
-   *     large
-   */
-  void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
-      throws IOException {
-    if (sourceOffset < 0) {
-      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
-    }
-    if (numberToWrite < 0) {
-      throw new IndexOutOfBoundsException("Length < 0: " + numberToWrite);
-    }
-    if (sourceOffset + numberToWrite > size()) {
-      throw new IndexOutOfBoundsException(
-          "Source end offset exceeded: " + (sourceOffset + numberToWrite));
-    }
-    if (numberToWrite > 0) {
-      writeToInternal(out, sourceOffset, numberToWrite);
-    }
-    
-  }
-
-  /**
-   * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes
-   * all error checking has already been done.
-   */
-  abstract void writeToInternal(OutputStream out, int sourceOffset,
-      int numberToWrite) throws IOException;
-
-  /**
-   * Constructs a read-only {@code java.nio.ByteBuffer} whose content
-   * is equal to the contents of this byte string.
-   * The result uses the same backing array as the byte string, if possible.
-   *
-   * @return wrapped bytes
-   */
-  public abstract ByteBuffer asReadOnlyByteBuffer();
-
-  /**
-   * Constructs a list of read-only {@code java.nio.ByteBuffer} objects
-   * such that the concatenation of their contents is equal to the contents
-   * of this byte string.  The result uses the same backing arrays as the
-   * byte string.
-   * <p>
-   * By returning a list, implementations of this method may be able to avoid
-   * copying even when there are multiple backing arrays.
-   * 
-   * @return a list of wrapped bytes
-   */
-  public abstract List<ByteBuffer> asReadOnlyByteBufferList();
-
-  /**
-   * Constructs a new {@code String} by decoding the bytes using the
-   * specified charset.
-   *
-   * @param charsetName encode using this charset
-   * @return new string
-   * @throws UnsupportedEncodingException if charset isn't recognized
-   */
-  public abstract String toString(String charsetName)
-      throws UnsupportedEncodingException;
-
-  // =================================================================
-  // UTF-8 decoding
-
-  /**
-   * Constructs a new {@code String} by decoding the bytes as UTF-8.
-   *
-   * @return new string using UTF-8 encoding
-   */
-  public String toStringUtf8() {
-    try {
-      return toString("UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported?", e);
-    }
-  }
-
-  /**
-   * Tells whether this {@code ByteString} represents a well-formed UTF-8
-   * byte sequence, such that the original bytes can be converted to a
-   * String object and then round tripped back to bytes without loss.
-   *
-   * <p>More precisely, returns {@code true} whenever: <pre> {@code
-   * Arrays.equals(byteString.toByteArray(),
-   *     new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
-   * }</pre>
-   *
-   * <p>This method returns {@code false} for "overlong" byte sequences,
-   * as well as for 3-byte sequences that would map to a surrogate
-   * character, in accordance with the restricted definition of UTF-8
-   * introduced in Unicode 3.1.  Note that the UTF-8 decoder included in
-   * Oracle's JDK has been modified to also reject "overlong" byte
-   * sequences, but (as of 2011) still accepts 3-byte surrogate
-   * character byte sequences.
-   *
-   * <p>See the Unicode Standard,</br>
-   * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
-   * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
-   *
-   * @return whether the bytes in this {@code ByteString} are a
-   * well-formed UTF-8 byte sequence
-   */
-  public abstract boolean isValidUtf8();
-
-  /**
-   * Tells whether the given byte sequence is a well-formed, malformed, or
-   * incomplete UTF-8 byte sequence.  This method accepts and returns a partial
-   * state result, allowing the bytes for a complete UTF-8 byte sequence to be
-   * composed from multiple {@code ByteString} segments.
-   *
-   * @param state either {@code 0} (if this is the initial decoding operation)
-   *     or the value returned from a call to a partial decoding method for the
-   *     previous bytes
-   * @param offset offset of the first byte to check
-   * @param length number of bytes to check
-   *
-   * @return {@code -1} if the partial byte sequence is definitely malformed,
-   * {@code 0} if it is well-formed (no additional input needed), or, if the
-   * byte sequence is "incomplete", i.e. apparently terminated in the middle of
-   * a character, an opaque integer "state" value containing enough information
-   * to decode the character when passed to a subsequent invocation of a
-   * partial decoding method.
-   */
-  protected abstract int partialIsValidUtf8(int state, int offset, int length);
-
-  // =================================================================
-  // equals() and hashCode()
-
-  @Override
-  public abstract boolean equals(Object o);
-
-  /**
-   * Return a non-zero hashCode depending only on the sequence of bytes
-   * in this ByteString.
-   *
-   * @return hashCode value for this object
-   */
-  @Override
-  public abstract int hashCode();
-
-  // =================================================================
-  // Input stream
-
-  /**
-   * Creates an {@code InputStream} which can be used to read the bytes.
-   * <p>
-   * The {@link InputStream} returned by this method is guaranteed to be
-   * completely non-blocking.  The method {@link InputStream#available()}
-   * returns the number of bytes remaining in the stream. The methods
-   * {@link InputStream#read(byte[]), {@link InputStream#read(byte[],int,int)}
-   * and {@link InputStream#skip(long)} will read/skip as many bytes as are
-   * available.
-   * <p>
-   * The methods in the returned {@link InputStream} might <b>not</b> be
-   * thread safe.
-   *
-   * @return an input stream that returns the bytes of this byte string.
-   */
-  public abstract InputStream newInput();
-
-  /**
-   * Creates a {@link CodedInputStream} which can be used to read the bytes.
-   * Using this is often more efficient than creating a {@link CodedInputStream}
-   * that wraps the result of {@link #newInput()}.
-   *
-   * @return stream based on wrapped data
-   */
-  public abstract CodedInputStream newCodedInput();
-
-  // =================================================================
-  // Output stream
-
-  /**
-   * Creates a new {@link Output} with the given initial capacity. Call {@link
-   * Output#toByteString()} to create the {@code ByteString} instance.
-   * <p>
-   * A {@link ByteString.Output} offers the same functionality as a
-   * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
-   * rather than a {@code byte} array.
-   *
-   * @param initialCapacity estimate of number of bytes to be written
-   * @return {@code OutputStream} for building a {@code ByteString}
-   */
-  public static Output newOutput(int initialCapacity) {
-    return new Output(initialCapacity);
-  }
-
-  /**
-   * Creates a new {@link Output}. Call {@link Output#toByteString()} to create
-   * the {@code ByteString} instance.
-   * <p>
-   * A {@link ByteString.Output} offers the same functionality as a
-   * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
-   * rather than a {@code byte array}.
-   *
-   * @return {@code OutputStream} for building a {@code ByteString}
-   */
-  public static Output newOutput() {
-    return new Output(CONCATENATE_BY_COPY_SIZE);
-  }
-
-  /**
-   * Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
-   * create the {@code ByteString} instance.
-   */
-  public static final class Output extends OutputStream {
-    // Implementation note.
-    // The public methods of this class must be synchronized.  ByteStrings
-    // are guaranteed to be immutable.  Without some sort of locking, it could
-    // be possible for one thread to call toByteSring(), while another thread
-    // is still modifying the underlying byte array.
-
-    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-    // argument passed by user, indicating initial capacity.
-    private final int initialCapacity;
-    // ByteStrings to be concatenated to create the result
-    private final ArrayList<ByteString> flushedBuffers;
-    // Total number of bytes in the ByteStrings of flushedBuffers
-    private int flushedBuffersTotalBytes;
-    // Current buffer to which we are writing
-    private byte[] buffer;
-    // Location in buffer[] to which we write the next byte.
-    private int bufferPos;
-
-    /**
-     * Creates a new ByteString output stream with the specified
-     * initial capacity.
-     *
-     * @param initialCapacity  the initial capacity of the output stream.
-     */
-    Output(int initialCapacity) {
-      if (initialCapacity < 0) {
-        throw new IllegalArgumentException("Buffer size < 0");
-      }
-      this.initialCapacity = initialCapacity;
-      this.flushedBuffers = new ArrayList<ByteString>();
-      this.buffer = new byte[initialCapacity];
-    }
-
-    @Override
-    public synchronized void write(int b) {
-      if (bufferPos == buffer.length) {
-        flushFullBuffer(1);
-      }
-      buffer[bufferPos++] = (byte)b;
-    }
-
-    @Override
-    public synchronized void write(byte[] b, int offset, int length)  {
-      if (length <= buffer.length - bufferPos) {
-        // The bytes can fit into the current buffer.
-        System.arraycopy(b, offset, buffer, bufferPos, length);
-        bufferPos += length;
-      } else {
-        // Use up the current buffer
-        int copySize  = buffer.length - bufferPos;
-        System.arraycopy(b, offset, buffer, bufferPos, copySize);
-        offset += copySize;
-        length -= copySize;
-        // Flush the buffer, and get a new buffer at least big enough to cover
-        // what we still need to output
-        flushFullBuffer(length);
-        System.arraycopy(b, offset, buffer, 0 /* count */, length);
-        bufferPos = length;
-      }
-    }
-
-    /**
-     * Creates a byte string. Its size is the current size of this output
-     * stream and its output has been copied to it.
-     *
-     * @return  the current contents of this output stream, as a byte string.
-     */
-    public synchronized ByteString toByteString() {
-      flushLastBuffer();
-      return ByteString.copyFrom(flushedBuffers);
-    }
-    
-    /**
-     * Implement java.util.Arrays.copyOf() for jdk 1.5.
-     */
-    private byte[] copyArray(byte[] buffer, int length) {
-      byte[] result = new byte[length];
-      System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length));
-      return result;
-    }
-
-    /**
-     * Writes the complete contents of this byte array output stream to
-     * the specified output stream argument.
-     *
-     * @param out the output stream to which to write the data.
-     * @throws IOException  if an I/O error occurs.
-     */
-    public void writeTo(OutputStream out) throws IOException {
-      ByteString[] cachedFlushBuffers;
-      byte[] cachedBuffer;
-      int cachedBufferPos;
-      synchronized (this) {
-        // Copy the information we need into local variables so as to hold
-        // the lock for as short a time as possible.
-        cachedFlushBuffers =
-            flushedBuffers.toArray(new ByteString[flushedBuffers.size()]);
-        cachedBuffer = buffer;
-        cachedBufferPos = bufferPos;
-      }
-      for (ByteString byteString : cachedFlushBuffers) {
-        byteString.writeTo(out);
-      }
-
-      out.write(copyArray(cachedBuffer, cachedBufferPos));
-    }
-
-    /**
-     * Returns the current size of the output stream.
-     *
-     * @return  the current size of the output stream
-     */
-    public synchronized int size() {
-      return flushedBuffersTotalBytes + bufferPos;
-    }
-
-    /**
-     * Resets this stream, so that all currently accumulated output in the
-     * output stream is discarded. The output stream can be used again,
-     * reusing the already allocated buffer space.
-     */
-    public synchronized void reset() {
-      flushedBuffers.clear();
-      flushedBuffersTotalBytes = 0;
-      bufferPos = 0;
-    }
-
-    @Override
-    public String toString() {
-      return String.format("<ByteString.Output@%s size=%d>",
-          Integer.toHexString(System.identityHashCode(this)), size());
-    }
-
-    /**
-     * Internal function used by writers.  The current buffer is full, and the
-     * writer needs a new buffer whose size is at least the specified minimum
-     * size.
-     */
-    private void flushFullBuffer(int minSize)  {
-      flushedBuffers.add(new LiteralByteString(buffer));
-      flushedBuffersTotalBytes += buffer.length;
-      // We want to increase our total capacity by 50%, but as a minimum,
-      // the new buffer should also at least be >= minSize and
-      // >= initial Capacity.
-      int newSize = Math.max(initialCapacity,
-          Math.max(minSize, flushedBuffersTotalBytes >>> 1));
-      buffer = new byte[newSize];
-      bufferPos = 0;
-    }
-
-    /**
-     * Internal function used by {@link #toByteString()}. The current buffer may
-     * or may not be full, but it needs to be flushed.
-     */
-    private void flushLastBuffer()  {
-      if (bufferPos < buffer.length) {
-        if (bufferPos > 0) {
-          byte[] bufferCopy = copyArray(buffer, bufferPos);
-          flushedBuffers.add(new LiteralByteString(bufferCopy));
-        }
-        // We reuse this buffer for further writes.
-      } else {
-        // Buffer is completely full.  Huzzah.
-        flushedBuffers.add(new LiteralByteString(buffer));
-        // 99% of the time, we're not going to use this OutputStream again.
-        // We set buffer to an empty byte stream so that we're handling this
-        // case without wasting space.  In the rare case that more writes
-        // *do* occur, this empty buffer will be flushed and an appropriately
-        // sized new buffer will be created.
-        buffer = EMPTY_BYTE_ARRAY;
-      }
-      flushedBuffersTotalBytes += bufferPos;
-      bufferPos = 0;
-    }
-  }
-
-  /**
-   * Constructs a new {@code ByteString} builder, which allows you to
-   * efficiently construct a {@code ByteString} by writing to a {@link
-   * CodedOutputStream}. Using this is much more efficient than calling {@code
-   * newOutput()} and wrapping that in a {@code CodedOutputStream}.
-   *
-   * <p>This is package-private because it's a somewhat confusing interface.
-   * Users can call {@link Message#toByteString()} instead of calling this
-   * directly.
-   *
-   * @param size The target byte size of the {@code ByteString}.  You must write
-   *     exactly this many bytes before building the result.
-   * @return the builder
-   */
-  static CodedBuilder newCodedBuilder(int size) {
-    return new CodedBuilder(size);
-  }
-
-  /** See {@link ByteString#newCodedBuilder(int)}. */
-  static final class CodedBuilder {
-    private final CodedOutputStream output;
-    private final byte[] buffer;
-
-    private CodedBuilder(int size) {
-      buffer = new byte[size];
-      output = CodedOutputStream.newInstance(buffer);
-    }
-
-    public ByteString build() {
-      output.checkNoSpaceLeft();
-
-      // We can be confident that the CodedOutputStream will not modify the
-      // underlying bytes anymore because it already wrote all of them.  So,
-      // no need to make a copy.
-      return new LiteralByteString(buffer);
-    }
-
-    public CodedOutputStream getCodedOutput() {
-      return output;
-    }
-  }
-
-  // =================================================================
-  // Methods {@link RopeByteString} needs on instances, which aren't part of the
-  // public API.
-
-  /**
-   * Return the depth of the tree representing this {@code ByteString}, if any,
-   * whose root is this node. If this is a leaf node, return 0.
-   *
-   * @return tree depth or zero
-   */
-  protected abstract int getTreeDepth();
-
-  /**
-   * Return {@code true} if this ByteString is literal (a leaf node) or a
-   * flat-enough tree in the sense of {@link RopeByteString}.
-   *
-   * @return true if the tree is flat enough
-   */
-  protected abstract boolean isBalanced();
-
-  /**
-   * Return the cached hash code if available.
-   *
-   * @return value of cached hash code or 0 if not computed yet
-   */
-  protected abstract int peekCachedHashCode();
-
-  /**
-   * Compute the hash across the value bytes starting with the given hash, and
-   * return the result.  This is used to compute the hash across strings
-   * represented as a set of pieces by allowing the hash computation to be
-   * continued from piece to piece.
-   *
-   * @param h starting hash value
-   * @param offset offset into this value to start looking at data values
-   * @param length number of data values to include in the hash computation
-   * @return ending hash value
-   */
-  protected abstract int partialHash(int h, int offset, int length);
-
-  @Override
-  public String toString() {
-    return String.format("<ByteString@%s size=%d>",
-        Integer.toHexString(System.identityHashCode(this)), size());
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java
deleted file mode 100644
index a00ae86..0000000
--- a/java/src/main/java/com/google/protobuf/CodedInputStream.java
+++ /dev/null
@@ -1,1311 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Reads and decodes protocol message fields.
- *
- * This class contains two kinds of methods:  methods that read specific
- * protocol message constructs and field types (e.g. {@link #readTag()} and
- * {@link #readInt32()}) and methods that read low-level values (e.g.
- * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
- * encoded protocol messages, you should use the former methods, but if you are
- * reading some other format of your own design, use the latter.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class CodedInputStream {
-  /**
-   * Create a new CodedInputStream wrapping the given InputStream.
-   */
-  public static CodedInputStream newInstance(final InputStream input) {
-    return new CodedInputStream(input);
-  }
-
-  /**
-   * Create a new CodedInputStream wrapping the given byte array.
-   */
-  public static CodedInputStream newInstance(final byte[] buf) {
-    return newInstance(buf, 0, buf.length);
-  }
-
-  /**
-   * Create a new CodedInputStream wrapping the given byte array slice.
-   */
-  public static CodedInputStream newInstance(final byte[] buf, final int off,
-                                             final int len) {
-    CodedInputStream result = new CodedInputStream(buf, off, len);
-    try {
-      // Some uses of CodedInputStream can be more efficient if they know
-      // exactly how many bytes are available.  By pushing the end point of the
-      // buffer as a limit, we allow them to get this information via
-      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
-      // the stream can never hurt, since we can never past that point anyway.
-      result.pushLimit(len);
-    } catch (InvalidProtocolBufferException ex) {
-      // The only reason pushLimit() might throw an exception here is if len
-      // is negative. Normally pushLimit()'s parameter comes directly off the
-      // wire, so it's important to catch exceptions in case of corrupt or
-      // malicious data. However, in this case, we expect that len is not a
-      // user-supplied value, so we can assume that it being negative indicates
-      // a programming error. Therefore, throwing an unchecked exception is
-      // appropriate.
-      throw new IllegalArgumentException(ex);
-    }
-    return result;
-  }
-
-  /**
-   * Create a new CodedInputStream wrapping the given ByteBuffer. The data
-   * starting from the ByteBuffer's current position to its limit will be read.
-   * The returned CodedInputStream may or may not share the underlying data
-   * in the ByteBuffer, therefore the ByteBuffer cannot be changed while the
-   * CodedInputStream is in use.
-   * Note that the ByteBuffer's position won't be changed by this function.
-   * Concurrent calls with the same ByteBuffer object are safe if no other
-   * thread is trying to alter the ByteBuffer's status.
-   */
-  public static CodedInputStream newInstance(ByteBuffer buf) {
-    if (buf.hasArray()) {
-      return newInstance(buf.array(), buf.arrayOffset() + buf.position(),
-          buf.remaining());
-    } else {
-      ByteBuffer temp = buf.duplicate();
-      byte[] buffer = new byte[temp.remaining()];
-      temp.get(buffer);
-      return newInstance(buffer);
-    }
-  }
-
-  /**
-   * Create a new CodedInputStream wrapping a LiteralByteString.
-   */
-  static CodedInputStream newInstance(LiteralByteString byteString) {
-    CodedInputStream result = new CodedInputStream(byteString);
-    try {
-      // Some uses of CodedInputStream can be more efficient if they know
-      // exactly how many bytes are available.  By pushing the end point of the
-      // buffer as a limit, we allow them to get this information via
-      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
-      // the stream can never hurt, since we can never past that point anyway.
-      result.pushLimit(byteString.size());
-    } catch (InvalidProtocolBufferException ex) {
-      // The only reason pushLimit() might throw an exception here is if len
-      // is negative. Normally pushLimit()'s parameter comes directly off the
-      // wire, so it's important to catch exceptions in case of corrupt or
-      // malicious data. However, in this case, we expect that len is not a
-      // user-supplied value, so we can assume that it being negative indicates
-      // a programming error. Therefore, throwing an unchecked exception is
-      // appropriate.
-      throw new IllegalArgumentException(ex);
-    }
-    return result;
-  }
-
-  // -----------------------------------------------------------------
-
-  /**
-   * Attempt to read a field tag, returning zero if we have reached EOF.
-   * Protocol message parsers use this to read tags, since a protocol message
-   * may legally end wherever a tag occurs, and zero is not a valid tag number.
-   */
-  public int readTag() throws IOException {
-    if (isAtEnd()) {
-      lastTag = 0;
-      return 0;
-    }
-
-    lastTag = readRawVarint32();
-    if (WireFormat.getTagFieldNumber(lastTag) == 0) {
-      // If we actually read zero (or any tag number corresponding to field
-      // number zero), that's not a valid tag.
-      throw InvalidProtocolBufferException.invalidTag();
-    }
-    return lastTag;
-  }
-
-  /**
-   * Verifies that the last call to readTag() returned the given tag value.
-   * This is used to verify that a nested group ended with the correct
-   * end tag.
-   *
-   * @throws InvalidProtocolBufferException {@code value} does not match the
-   *                                        last tag.
-   */
-  public void checkLastTagWas(final int value)
-                              throws InvalidProtocolBufferException {
-    if (lastTag != value) {
-      throw InvalidProtocolBufferException.invalidEndTag();
-    }
-  }
-
-  public int getLastTag() {
-    return lastTag;
-  }
-
-  /**
-   * Reads and discards a single field, given its tag value.
-   *
-   * @return {@code false} if the tag is an endgroup tag, in which case
-   *         nothing is skipped.  Otherwise, returns {@code true}.
-   */
-  public boolean skipField(final int tag) throws IOException {
-    switch (WireFormat.getTagWireType(tag)) {
-      case WireFormat.WIRETYPE_VARINT:
-        skipRawVarint();
-        return true;
-      case WireFormat.WIRETYPE_FIXED64:
-        skipRawBytes(8);
-        return true;
-      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-        skipRawBytes(readRawVarint32());
-        return true;
-      case WireFormat.WIRETYPE_START_GROUP:
-        skipMessage();
-        checkLastTagWas(
-          WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
-                             WireFormat.WIRETYPE_END_GROUP));
-        return true;
-      case WireFormat.WIRETYPE_END_GROUP:
-        return false;
-      case WireFormat.WIRETYPE_FIXED32:
-        skipRawBytes(4);
-        return true;
-      default:
-        throw InvalidProtocolBufferException.invalidWireType();
-    }
-  }
-
-  /**
-   * Reads a single field and writes it to output in wire format,
-   * given its tag value.
-   *
-   * @return {@code false} if the tag is an endgroup tag, in which case
-   *         nothing is skipped.  Otherwise, returns {@code true}.
-   */
-  public boolean skipField(final int tag, final CodedOutputStream output)
-      throws IOException {
-    switch (WireFormat.getTagWireType(tag)) {
-      case WireFormat.WIRETYPE_VARINT: {
-        long value = readInt64();
-        output.writeRawVarint32(tag);
-        output.writeUInt64NoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_FIXED64: {
-        long value = readRawLittleEndian64();
-        output.writeRawVarint32(tag);
-        output.writeFixed64NoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_LENGTH_DELIMITED: {
-        ByteString value = readBytes();
-        output.writeRawVarint32(tag);
-        output.writeBytesNoTag(value);
-        return true;
-      }
-      case WireFormat.WIRETYPE_START_GROUP: {
-        output.writeRawVarint32(tag);
-        skipMessage(output);
-        int endtag = WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
-                                        WireFormat.WIRETYPE_END_GROUP);
-        checkLastTagWas(endtag);
-        output.writeRawVarint32(endtag);
-        return true;
-      }
-      case WireFormat.WIRETYPE_END_GROUP: {
-        return false;
-      }
-      case WireFormat.WIRETYPE_FIXED32: {
-        int value = readRawLittleEndian32();
-        output.writeRawVarint32(tag);
-        output.writeFixed32NoTag(value);
-        return true;
-      }
-      default:
-        throw InvalidProtocolBufferException.invalidWireType();
-    }
-  }
-
-  /**
-   * Reads and discards an entire message.  This will read either until EOF
-   * or until an endgroup tag, whichever comes first.
-   */
-  public void skipMessage() throws IOException {
-    while (true) {
-      final int tag = readTag();
-      if (tag == 0 || !skipField(tag)) {
-        return;
-      }
-    }
-  }
-
-  /**
-   * Reads an entire message and writes it to output in wire format.
-   * This will read either until EOF or until an endgroup tag,
-   * whichever comes first.
-   */
-  public void skipMessage(CodedOutputStream output) throws IOException {
-    while (true) {
-      final int tag = readTag();
-      if (tag == 0 || !skipField(tag, output)) {
-        return;
-      }
-    }
-  }
-
-  /**
-   * Collects the bytes skipped and returns the data in a ByteBuffer.
-   */
-  private class SkippedDataSink implements RefillCallback {
-    private int lastPos = bufferPos;
-    private ByteArrayOutputStream byteArrayStream;
-
-    @Override
-    public void onRefill() {
-      if (byteArrayStream == null) {
-        byteArrayStream = new ByteArrayOutputStream();
-      }
-      byteArrayStream.write(buffer, lastPos, bufferPos - lastPos);
-      lastPos = 0;
-    }
-
-    /**
-     * Gets skipped data in a ByteBuffer. This method should only be
-     * called once.
-     */
-    ByteBuffer getSkippedData() {
-      if (byteArrayStream == null) {
-        return ByteBuffer.wrap(buffer, lastPos, bufferPos - lastPos);
-      } else {
-        byteArrayStream.write(buffer, lastPos, bufferPos);
-        return ByteBuffer.wrap(byteArrayStream.toByteArray());
-      }
-    }
-  }
-
-
-  // -----------------------------------------------------------------
-
-  /** Read a {@code double} field value from the stream. */
-  public double readDouble() throws IOException {
-    return Double.longBitsToDouble(readRawLittleEndian64());
-  }
-
-  /** Read a {@code float} field value from the stream. */
-  public float readFloat() throws IOException {
-    return Float.intBitsToFloat(readRawLittleEndian32());
-  }
-
-  /** Read a {@code uint64} field value from the stream. */
-  public long readUInt64() throws IOException {
-    return readRawVarint64();
-  }
-
-  /** Read an {@code int64} field value from the stream. */
-  public long readInt64() throws IOException {
-    return readRawVarint64();
-  }
-
-  /** Read an {@code int32} field value from the stream. */
-  public int readInt32() throws IOException {
-    return readRawVarint32();
-  }
-
-  /** Read a {@code fixed64} field value from the stream. */
-  public long readFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
-
-  /** Read a {@code fixed32} field value from the stream. */
-  public int readFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
-
-  /** Read a {@code bool} field value from the stream. */
-  public boolean readBool() throws IOException {
-    return readRawVarint64() != 0;
-  }
-
-  /**
-   * Read a {@code string} field value from the stream.
-   * If the stream contains malformed UTF-8,
-   * replace the offending bytes with the standard UTF-8 replacement character.
-   */
-  public String readString() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      final String result = new String(buffer, bufferPos, size, "UTF-8");
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return "";
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      return new String(readRawBytesSlowPath(size), "UTF-8");
-    }
-  }
-
-  /**
-   * Read a {@code string} field value from the stream.
-   * If the stream contains malformed UTF-8,
-   * throw exception {@link InvalidProtocolBufferException}.
-   */
-  public String readStringRequireUtf8() throws IOException {
-    final int size = readRawVarint32();
-    final byte[] bytes;
-    int pos = bufferPos;
-    if (size <= (bufferSize - pos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      bytes = buffer;
-      bufferPos = pos + size;
-    } else if (size == 0) {
-      return "";
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      bytes = readRawBytesSlowPath(size);
-      pos = 0;
-    }
-    // TODO(martinrb): We could save a pass by validating while decoding.
-    if (!Utf8.isValidUtf8(bytes, pos, pos + size)) {
-      throw InvalidProtocolBufferException.invalidUtf8();
-    }
-    return new String(bytes, pos, size, "UTF-8");
-  }
-
-  /** Read a {@code group} field value from the stream. */
-  public void readGroup(final int fieldNumber,
-                        final MessageLite.Builder builder,
-                        final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    builder.mergeFrom(this, extensionRegistry);
-    checkLastTagWas(
-      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-    --recursionDepth;
-  }
-
-
-  /** Read a {@code group} field value from the stream. */
-  public <T extends MessageLite> T readGroup(
-      final int fieldNumber,
-      final Parser<T> parser,
-      final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    T result = parser.parsePartialFrom(this, extensionRegistry);
-    checkLastTagWas(
-      WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-    --recursionDepth;
-    return result;
-  }
-
-  /**
-   * Reads a {@code group} field value from the stream and merges it into the
-   * given {@link UnknownFieldSet}.
-   *
-   * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
-   *             you can just call {@link #readGroup}.
-   */
-  @Deprecated
-  public void readUnknownGroup(final int fieldNumber,
-                               final MessageLite.Builder builder)
-      throws IOException {
-    // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
-    // is safe to pass null here.  (We can't call
-    // ExtensionRegistry.getEmptyRegistry() because that would make this
-    // class depend on ExtensionRegistry, which is not part of the lite
-    // library.)
-    readGroup(fieldNumber, builder, null);
-  }
-
-  /** Read an embedded message field value from the stream. */
-  public void readMessage(final MessageLite.Builder builder,
-                          final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    final int length = readRawVarint32();
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    final int oldLimit = pushLimit(length);
-    ++recursionDepth;
-    builder.mergeFrom(this, extensionRegistry);
-    checkLastTagWas(0);
-    --recursionDepth;
-    popLimit(oldLimit);
-  }
-
-
-  /** Read an embedded message field value from the stream. */
-  public <T extends MessageLite> T readMessage(
-      final Parser<T> parser,
-      final ExtensionRegistryLite extensionRegistry)
-      throws IOException {
-    int length = readRawVarint32();
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferException.recursionLimitExceeded();
-    }
-    final int oldLimit = pushLimit(length);
-    ++recursionDepth;
-    T result = parser.parsePartialFrom(this, extensionRegistry);
-    checkLastTagWas(0);
-    --recursionDepth;
-    popLimit(oldLimit);
-    return result;
-  }
-
-  /** Read a {@code bytes} field value from the stream. */
-  public ByteString readBytes() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path:  We already have the bytes in a contiguous buffer, so
-      //   just copy directly from it.
-      final ByteString result = bufferIsImmutable && enableAliasing
-          ? new BoundedByteString(buffer, bufferPos, size)
-          : ByteString.copyFrom(buffer, bufferPos, size);
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return ByteString.EMPTY;
-    } else {
-      // Slow path:  Build a byte array first then copy it.
-      return new LiteralByteString(readRawBytesSlowPath(size));
-    }
-  }
-
-  /** Read a {@code bytes} field value from the stream. */
-  public byte[] readByteArray() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path: We already have the bytes in a contiguous buffer, so
-      // just copy directly from it.
-      final byte[] result =
-          Arrays.copyOfRange(buffer, bufferPos, bufferPos + size);
-      bufferPos += size;
-      return result;
-    } else {
-      // Slow path: Build a byte array first then copy it.
-      return readRawBytesSlowPath(size);
-    }
-  }
-
-  /** Read a {@code bytes} field value from the stream. */
-  public ByteBuffer readByteBuffer() throws IOException {
-    final int size = readRawVarint32();
-    if (size <= (bufferSize - bufferPos) && size > 0) {
-      // Fast path: We already have the bytes in a contiguous buffer.
-      // When aliasing is enabled, we can return a ByteBuffer pointing directly
-      // into the underlying byte array without copy if the CodedInputStream is
-      // constructed from a byte array. If aliasing is disabled or the input is
-      // from an InputStream or ByteString, we have to make a copy of the bytes.
-      ByteBuffer result = input == null && !bufferIsImmutable && enableAliasing
-          ? ByteBuffer.wrap(buffer, bufferPos, size).slice()
-          : ByteBuffer.wrap(Arrays.copyOfRange(
-              buffer, bufferPos, bufferPos + size));
-      bufferPos += size;
-      return result;
-    } else if (size == 0) {
-      return Internal.EMPTY_BYTE_BUFFER;
-    } else {
-      // Slow path: Build a byte array first then copy it.
-      return ByteBuffer.wrap(readRawBytesSlowPath(size));
-    }
-  }
-
-  /** Read a {@code uint32} field value from the stream. */
-  public int readUInt32() throws IOException {
-    return readRawVarint32();
-  }
-
-  /**
-   * Read an enum field value from the stream.  Caller is responsible
-   * for converting the numeric value to an actual enum.
-   */
-  public int readEnum() throws IOException {
-    return readRawVarint32();
-  }
-
-  /** Read an {@code sfixed32} field value from the stream. */
-  public int readSFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
-
-  /** Read an {@code sfixed64} field value from the stream. */
-  public long readSFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
-
-  /** Read an {@code sint32} field value from the stream. */
-  public int readSInt32() throws IOException {
-    return decodeZigZag32(readRawVarint32());
-  }
-
-  /** Read an {@code sint64} field value from the stream. */
-  public long readSInt64() throws IOException {
-    return decodeZigZag64(readRawVarint64());
-  }
-
-  // =================================================================
-
-  /**
-   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
-   * upper bits.
-   */
-  public int readRawVarint32() throws IOException {
-    // See implementation notes for readRawVarint64
- fastpath: {
-      int pos = bufferPos;
-
-      if (bufferSize == pos) {
-        break fastpath;
-      }
-
-      final byte[] buffer = this.buffer;
-      int x;
-      if ((x = buffer[pos++]) >= 0) {
-        bufferPos = pos;
-        return x;
-      } else if (bufferSize - pos < 9) {
-        break fastpath;
-      } else if ((x ^= (buffer[pos++] << 7)) < 0L) {
-        x ^= (~0L << 7);
-      } else if ((x ^= (buffer[pos++] << 14)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14);
-      } else if ((x ^= (buffer[pos++] << 21)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21);
-      } else {
-        int y = buffer[pos++];
-        x ^= y << 28;
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
-        if (y < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0 &&
-            buffer[pos++] < 0) {
-          break fastpath;  // Will throw malformedVarint()
-        }
-      }
-      bufferPos = pos;
-      return x;
-    }
-    return (int) readRawVarint64SlowPath();
-  }
-
-  private void skipRawVarint() throws IOException {
-    if (bufferSize - bufferPos >= 10) {
-      final byte[] buffer = this.buffer;
-      int pos = bufferPos;
-      for (int i = 0; i < 10; i++) {
-        if (buffer[pos++] >= 0) {
-          bufferPos = pos;
-          return;
-        }
-      }
-    }
-    skipRawVarintSlowPath();
-  }
-
-  private void skipRawVarintSlowPath() throws IOException {
-    for (int i = 0; i < 10; i++) {
-      if (readRawByte() >= 0) {
-        return;
-      }
-    }
-    throw InvalidProtocolBufferException.malformedVarint();
-  }
-
-  /**
-   * Reads a varint from the input one byte at a time, so that it does not
-   * read any bytes after the end of the varint.  If you simply wrapped the
-   * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
-   * then you would probably end up reading past the end of the varint since
-   * CodedInputStream buffers its input.
-   */
-  static int readRawVarint32(final InputStream input) throws IOException {
-    final int firstByte = input.read();
-    if (firstByte == -1) {
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-    return readRawVarint32(firstByte, input);
-  }
-
-  /**
-   * Like {@link #readRawVarint32(InputStream)}, but expects that the caller
-   * has already read one byte.  This allows the caller to determine if EOF
-   * has been reached before attempting to read.
-   */
-  public static int readRawVarint32(
-      final int firstByte, final InputStream input) throws IOException {
-    if ((firstByte & 0x80) == 0) {
-      return firstByte;
-    }
-
-    int result = firstByte & 0x7f;
-    int offset = 7;
-    for (; offset < 32; offset += 7) {
-      final int b = input.read();
-      if (b == -1) {
-        throw InvalidProtocolBufferException.truncatedMessage();
-      }
-      result |= (b & 0x7f) << offset;
-      if ((b & 0x80) == 0) {
-        return result;
-      }
-    }
-    // Keep reading up to 64 bits.
-    for (; offset < 64; offset += 7) {
-      final int b = input.read();
-      if (b == -1) {
-        throw InvalidProtocolBufferException.truncatedMessage();
-      }
-      if ((b & 0x80) == 0) {
-        return result;
-      }
-    }
-    throw InvalidProtocolBufferException.malformedVarint();
-  }
-
-  /** Read a raw Varint from the stream. */
-  public long readRawVarint64() throws IOException {
-    // Implementation notes:
-    //
-    // Optimized for one-byte values, expected to be common.
-    // The particular code below was selected from various candidates
-    // empirically, by winning VarintBenchmark.
-    //
-    // Sign extension of (signed) Java bytes is usually a nuisance, but
-    // we exploit it here to more easily obtain the sign of bytes read.
-    // Instead of cleaning up the sign extension bits by masking eagerly,
-    // we delay until we find the final (positive) byte, when we clear all
-    // accumulated bits with one xor.  We depend on javac to constant fold.
- fastpath: {
-      int pos = bufferPos;
-
-      if (bufferSize == pos) {
-        break fastpath;
-      }
-
-      final byte[] buffer = this.buffer;
-      long x;
-      int y;
-      if ((y = buffer[pos++]) >= 0) {
-        bufferPos = pos;
-        return y;
-      } else if (bufferSize - pos < 9) {
-        break fastpath;
-      } else if ((x = y ^ (buffer[pos++] << 7)) < 0L) {
-        x ^= (~0L << 7);
-      } else if ((x ^= (buffer[pos++] << 14)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14);
-      } else if ((x ^= (buffer[pos++] << 21)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21);
-      } else if ((x ^= ((long) buffer[pos++] << 28)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28);
-      } else if ((x ^= ((long) buffer[pos++] << 35)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35);
-      } else if ((x ^= ((long) buffer[pos++] << 42)) >= 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42);
-      } else if ((x ^= ((long) buffer[pos++] << 49)) < 0L) {
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
-            ^ (~0L << 49);
-      } else {
-        x ^= ((long) buffer[pos++] << 56);
-        x ^= (~0L << 7) ^ (~0L << 14) ^ (~0L << 21) ^ (~0L << 28) ^ (~0L << 35) ^ (~0L << 42)
-            ^ (~0L << 49) ^ (~0L << 56);
-        if (x < 0L) {
-          if (buffer[pos++] < 0L) {
-            break fastpath;  // Will throw malformedVarint()
-          }
-        }
-      }
-      bufferPos = pos;
-      return x;
-    }
-    return readRawVarint64SlowPath();
-  }
-
-  /** Variant of readRawVarint64 for when uncomfortably close to the limit. */
-  /* Visible for testing */
-  long readRawVarint64SlowPath() throws IOException {
-    long result = 0;
-    for (int shift = 0; shift < 64; shift += 7) {
-      final byte b = readRawByte();
-      result |= (long) (b & 0x7F) << shift;
-      if ((b & 0x80) == 0) {
-        return result;
-      }
-    }
-    throw InvalidProtocolBufferException.malformedVarint();
-  }
-
-  /** Read a 32-bit little-endian integer from the stream. */
-  public int readRawLittleEndian32() throws IOException {
-    int pos = bufferPos;
-
-    // hand-inlined ensureAvailable(4);
-    if (bufferSize - pos < 4) {
-      refillBuffer(4);
-      pos = bufferPos;
-    }
-
-    final byte[] buffer = this.buffer;
-    bufferPos = pos + 4;
-    return (((buffer[pos]     & 0xff))       |
-            ((buffer[pos + 1] & 0xff) <<  8) |
-            ((buffer[pos + 2] & 0xff) << 16) |
-            ((buffer[pos + 3] & 0xff) << 24));
-  }
-
-  /** Read a 64-bit little-endian integer from the stream. */
-  public long readRawLittleEndian64() throws IOException {
-    int pos = bufferPos;
-
-    // hand-inlined ensureAvailable(8);
-    if (bufferSize - pos < 8) {
-      refillBuffer(8);
-      pos = bufferPos;
-    }
-
-    final byte[] buffer = this.buffer;
-    bufferPos = pos + 8;
-    return ((((long) buffer[pos]     & 0xffL))       |
-            (((long) buffer[pos + 1] & 0xffL) <<  8) |
-            (((long) buffer[pos + 2] & 0xffL) << 16) |
-            (((long) buffer[pos + 3] & 0xffL) << 24) |
-            (((long) buffer[pos + 4] & 0xffL) << 32) |
-            (((long) buffer[pos + 5] & 0xffL) << 40) |
-            (((long) buffer[pos + 6] & 0xffL) << 48) |
-            (((long) buffer[pos + 7] & 0xffL) << 56));
-  }
-
-  /**
-   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 32-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 32-bit integer.
-   */
-  public static int decodeZigZag32(final int n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  /**
-   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 64-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 64-bit integer.
-   */
-  public static long decodeZigZag64(final long n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  // -----------------------------------------------------------------
-
-  private final byte[] buffer;
-  private final boolean bufferIsImmutable;
-  private int bufferSize;
-  private int bufferSizeAfterLimit;
-  private int bufferPos;
-  private final InputStream input;
-  private int lastTag;
-  private boolean enableAliasing = false;
-
-  /**
-   * The total number of bytes read before the current buffer.  The total
-   * bytes read up to the current position can be computed as
-   * {@code totalBytesRetired + bufferPos}.  This value may be negative if
-   * reading started in the middle of the current buffer (e.g. if the
-   * constructor that takes a byte array and an offset was used).
-   */
-  private int totalBytesRetired;
-
-  /** The absolute position of the end of the current message. */
-  private int currentLimit = Integer.MAX_VALUE;
-
-  /** See setRecursionLimit() */
-  private int recursionDepth;
-  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
-
-  /** See setSizeLimit() */
-  private int sizeLimit = DEFAULT_SIZE_LIMIT;
-
-  private static final int DEFAULT_RECURSION_LIMIT = 64;
-  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
-  private static final int BUFFER_SIZE = 4096;
-
-  private CodedInputStream(final byte[] buffer, final int off, final int len) {
-    this.buffer = buffer;
-    bufferSize = off + len;
-    bufferPos = off;
-    totalBytesRetired = -off;
-    input = null;
-    bufferIsImmutable = false;
-  }
-
-  private CodedInputStream(final InputStream input) {
-    buffer = new byte[BUFFER_SIZE];
-    bufferSize = 0;
-    bufferPos = 0;
-    totalBytesRetired = 0;
-    this.input = input;
-    bufferIsImmutable = false;
-  }
-
-  private CodedInputStream(final LiteralByteString byteString) {
-    buffer = byteString.bytes;
-    bufferPos = byteString.getOffsetIntoBytes();
-    bufferSize = bufferPos + byteString.size();
-    totalBytesRetired = -bufferPos;
-    input = null;
-    bufferIsImmutable = true;
-  }
-
-  public void enableAliasing(boolean enabled) {
-    this.enableAliasing = enabled;
-  }
-
-  /**
-   * Set the maximum message recursion depth.  In order to prevent malicious
-   * messages from causing stack overflows, {@code CodedInputStream} limits
-   * how deeply messages may be nested.  The default limit is 64.
-   *
-   * @return the old limit.
-   */
-  public int setRecursionLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Recursion limit cannot be negative: " + limit);
-    }
-    final int oldLimit = recursionLimit;
-    recursionLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Set the maximum message size.  In order to prevent malicious
-   * messages from exhausting memory or causing integer overflows,
-   * {@code CodedInputStream} limits how large a message may be.
-   * The default limit is 64MB.  You should set this limit as small
-   * as you can without harming your app's functionality.  Note that
-   * size limits only apply when reading from an {@code InputStream}, not
-   * when constructed around a raw byte array (nor with
-   * {@link ByteString#newCodedInput}).
-   * <p>
-   * If you want to read several messages from a single CodedInputStream, you
-   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
-   * size limit.
-   *
-   * @return the old limit.
-   */
-  public int setSizeLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Size limit cannot be negative: " + limit);
-    }
-    final int oldLimit = sizeLimit;
-    sizeLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
-   */
-  public void resetSizeCounter() {
-    totalBytesRetired = -bufferPos;
-  }
-
-  /**
-   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
-   * is called when descending into a length-delimited embedded message.
-   *
-   * <p>Note that {@code pushLimit()} does NOT affect how many bytes the
-   * {@code CodedInputStream} reads from an underlying {@code InputStream} when
-   * refreshing its buffer.  If you need to prevent reading past a certain
-   * point in the underlying {@code InputStream} (e.g. because you expect it to
-   * contain more data after the end of the message which you need to handle
-   * differently) then you must place a wrapper around your {@code InputStream}
-   * which limits the amount of data that can be read from it.
-   *
-   * @return the old limit.
-   */
-  public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
-    if (byteLimit < 0) {
-      throw InvalidProtocolBufferException.negativeSize();
-    }
-    byteLimit += totalBytesRetired + bufferPos;
-    final int oldLimit = currentLimit;
-    if (byteLimit > oldLimit) {
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-    currentLimit = byteLimit;
-
-    recomputeBufferSizeAfterLimit();
-
-    return oldLimit;
-  }
-
-  private void recomputeBufferSizeAfterLimit() {
-    bufferSize += bufferSizeAfterLimit;
-    final int bufferEnd = totalBytesRetired + bufferSize;
-    if (bufferEnd > currentLimit) {
-      // Limit is in current buffer.
-      bufferSizeAfterLimit = bufferEnd - currentLimit;
-      bufferSize -= bufferSizeAfterLimit;
-    } else {
-      bufferSizeAfterLimit = 0;
-    }
-  }
-
-  /**
-   * Discards the current limit, returning to the previous limit.
-   *
-   * @param oldLimit The old limit, as returned by {@code pushLimit}.
-   */
-  public void popLimit(final int oldLimit) {
-    currentLimit = oldLimit;
-    recomputeBufferSizeAfterLimit();
-  }
-
-  /**
-   * Returns the number of bytes to be read before the current limit.
-   * If no limit is set, returns -1.
-   */
-  public int getBytesUntilLimit() {
-    if (currentLimit == Integer.MAX_VALUE) {
-      return -1;
-    }
-
-    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
-    return currentLimit - currentAbsolutePosition;
-  }
-
-  /**
-   * Returns true if the stream has reached the end of the input.  This is the
-   * case if either the end of the underlying input source has been reached or
-   * if the stream has reached a limit created using {@link #pushLimit(int)}.
-   */
-  public boolean isAtEnd() throws IOException {
-    return bufferPos == bufferSize && !tryRefillBuffer(1);
-  }
-
-  /**
-   * The total bytes read up to the current position. Calling
-   * {@link #resetSizeCounter()} resets this value to zero.
-   */
-  public int getTotalBytesRead() {
-      return totalBytesRetired + bufferPos;
-  }
-
-  private interface RefillCallback {
-    void onRefill();
-  }
-
-  private RefillCallback refillCallback = null;
-
-  /**
-   * Ensures that at least {@code n} bytes are available in the buffer, reading
-   * more bytes from the input if necessary to make it so.  Caller must ensure
-   * that the requested space is less than BUFFER_SIZE.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  private void ensureAvailable(int n) throws IOException {
-    if (bufferSize - bufferPos < n) {
-      refillBuffer(n);
-    }
-  }
-
-  /**
-   * Reads more bytes from the input, making at least {@code n} bytes available
-   * in the buffer.  Caller must ensure that the requested space is not yet
-   * available, and that the requested space is less than BUFFER_SIZE.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  private void refillBuffer(int n) throws IOException {
-    if (!tryRefillBuffer(n)) {
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-  }
-
-  /**
-   * Tries to read more bytes from the input, making at least {@code n} bytes
-   * available in the buffer.  Caller must ensure that the requested space is
-   * not yet available, and that the requested space is less than BUFFER_SIZE.
-   *
-   * @return {@code true} if the bytes could be made available; {@code false}
-   *         if the end of the stream or the current limit was reached.
-   */
-  private boolean tryRefillBuffer(int n) throws IOException {
-    if (bufferPos + n <= bufferSize) {
-      throw new IllegalStateException(
-          "refillBuffer() called when " + n +
-          " bytes were already available in buffer");
-    }
-
-    if (totalBytesRetired + bufferPos + n > currentLimit) {
-      // Oops, we hit a limit.
-      return false;
-    }
-
-    if (refillCallback != null) {
-      refillCallback.onRefill();
-    }
-
-    if (input != null) {
-      int pos = bufferPos;
-      if (pos > 0) {
-        if (bufferSize > pos) {
-          System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
-        }
-        totalBytesRetired += pos;
-        bufferSize -= pos;
-        bufferPos = 0;
-      }
-
-      int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
-      if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
-        throw new IllegalStateException(
-            "InputStream#read(byte[]) returned invalid result: " + bytesRead +
-            "\nThe InputStream implementation is buggy.");
-      }
-      if (bytesRead > 0) {
-        bufferSize += bytesRead;
-        // Integer-overflow-conscious check against sizeLimit
-        if (totalBytesRetired + n - sizeLimit > 0) {
-          throw InvalidProtocolBufferException.sizeLimitExceeded();
-        }
-        recomputeBufferSizeAfterLimit();
-        return (bufferSize >= n) ? true : tryRefillBuffer(n);
-      }
-    }
-
-    return false;
-  }
-
-  /**
-   * Read one byte from the input.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte readRawByte() throws IOException {
-    if (bufferPos == bufferSize) {
-      refillBuffer(1);
-    }
-    return buffer[bufferPos++];
-  }
-
-  /**
-   * Read a fixed size of bytes from the input.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte[] readRawBytes(final int size) throws IOException {
-    final int pos = bufferPos;
-    if (size <= (bufferSize - pos) && size > 0) {
-      bufferPos = pos + size;
-      return Arrays.copyOfRange(buffer, pos, pos + size);
-    } else {
-      return readRawBytesSlowPath(size);
-    }
-  }
-
-  /**
-   * Exactly like readRawBytes, but caller must have already checked the fast
-   * path: (size <= (bufferSize - pos) && size > 0)
-   */
-  private byte[] readRawBytesSlowPath(final int size) throws IOException {
-    if (size <= 0) {
-      if (size == 0) {
-        return Internal.EMPTY_BYTE_ARRAY;
-      } else {
-        throw InvalidProtocolBufferException.negativeSize();
-      }
-    }
-
-    if (totalBytesRetired + bufferPos + size > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
-      // Then fail.
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-
-    if (size < BUFFER_SIZE) {
-      // Reading more bytes than are in the buffer, but not an excessive number
-      // of bytes.  We can safely allocate the resulting array ahead of time.
-
-      // First copy what we have.
-      final byte[] bytes = new byte[size];
-      int pos = bufferSize - bufferPos;
-      System.arraycopy(buffer, bufferPos, bytes, 0, pos);
-      bufferPos = bufferSize;
-
-      // We want to refill the buffer and then copy from the buffer into our
-      // byte array rather than reading directly into our byte array because
-      // the input may be unbuffered.
-      ensureAvailable(size - pos);
-      System.arraycopy(buffer, 0, bytes, pos, size - pos);
-      bufferPos = size - pos;
-
-      return bytes;
-    } else {
-      // The size is very large.  For security reasons, we can't allocate the
-      // entire byte array yet.  The size comes directly from the input, so a
-      // maliciously-crafted message could provide a bogus very large size in
-      // order to trick the app into allocating a lot of memory.  We avoid this
-      // by allocating and reading only a small chunk at a time, so that the
-      // malicious message must actually *be* extremely large to cause
-      // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
-
-      // Remember the buffer markers since we'll have to copy the bytes out of
-      // it later.
-      final int originalBufferPos = bufferPos;
-      final int originalBufferSize = bufferSize;
-
-      // Mark the current buffer consumed.
-      totalBytesRetired += bufferSize;
-      bufferPos = 0;
-      bufferSize = 0;
-
-      // Read all the rest of the bytes we need.
-      int sizeLeft = size - (originalBufferSize - originalBufferPos);
-      final List<byte[]> chunks = new ArrayList<byte[]>();
-
-      while (sizeLeft > 0) {
-        final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
-        int pos = 0;
-        while (pos < chunk.length) {
-          final int n = (input == null) ? -1 :
-            input.read(chunk, pos, chunk.length - pos);
-          if (n == -1) {
-            throw InvalidProtocolBufferException.truncatedMessage();
-          }
-          totalBytesRetired += n;
-          pos += n;
-        }
-        sizeLeft -= chunk.length;
-        chunks.add(chunk);
-      }
-
-      // OK, got everything.  Now concatenate it all into one buffer.
-      final byte[] bytes = new byte[size];
-
-      // Start by copying the leftover bytes from this.buffer.
-      int pos = originalBufferSize - originalBufferPos;
-      System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
-
-      // And now all the chunks.
-      for (final byte[] chunk : chunks) {
-        System.arraycopy(chunk, 0, bytes, pos, chunk.length);
-        pos += chunk.length;
-      }
-
-      // Done.
-      return bytes;
-    }
-  }
-
-  /**
-   * Reads and discards {@code size} bytes.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public void skipRawBytes(final int size) throws IOException {
-    if (size <= (bufferSize - bufferPos) && size >= 0) {
-      // We have all the bytes we need already.
-      bufferPos += size;
-    } else {
-      skipRawBytesSlowPath(size);
-    }
-  }
-
-  /**
-   * Exactly like skipRawBytes, but caller must have already checked the fast
-   * path: (size <= (bufferSize - pos) && size >= 0)
-   */
-  private void skipRawBytesSlowPath(final int size) throws IOException {
-    if (size < 0) {
-      throw InvalidProtocolBufferException.negativeSize();
-    }
-
-    if (totalBytesRetired + bufferPos + size > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
-      // Then fail.
-      throw InvalidProtocolBufferException.truncatedMessage();
-    }
-
-    // Skipping more bytes than are in the buffer.  First skip what we have.
-    int pos = bufferSize - bufferPos;
-    bufferPos = bufferSize;
-
-    // Keep refilling the buffer until we get to the point we wanted to skip to.
-    // This has the side effect of ensuring the limits are updated correctly.
-    refillBuffer(1);
-    while (size - pos > bufferSize) {
-      pos += bufferSize;
-      bufferPos = bufferSize;
-      refillBuffer(1);
-    }
-
-    bufferPos = size - pos;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
deleted file mode 100644
index fafe035..0000000
--- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ /dev/null
@@ -1,1297 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-
-/**
- * Encodes and writes protocol message fields.
- *
- * <p>This class contains two kinds of methods:  methods that write specific
- * protocol message constructs and field types (e.g. {@link #writeTag} and
- * {@link #writeInt32}) and methods that write low-level values (e.g.
- * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
- * writing encoded protocol messages, you should use the former methods, but if
- * you are writing some other format of your own design, use the latter.
- *
- * <p>This class is totally unsynchronized.
- *
- * @author kneton@google.com Kenton Varda
- */
-public final class CodedOutputStream {
-  private final byte[] buffer;
-  private final int limit;
-  private int position;
-  private int totalBytesWritten = 0;
-
-  private final OutputStream output;
-
-  /**
-   * The buffer size used in {@link #newInstance(OutputStream)}.
-   */
-  public static final int DEFAULT_BUFFER_SIZE = 4096;
-
-  /**
-   * Returns the buffer size to efficiently write dataLength bytes to this
-   * CodedOutputStream. Used by AbstractMessageLite.
-   *
-   * @return the buffer size to efficiently write dataLength bytes to this
-   *         CodedOutputStream.
-   */
-  static int computePreferredBufferSize(int dataLength) {
-    if (dataLength > DEFAULT_BUFFER_SIZE) return DEFAULT_BUFFER_SIZE;
-    return dataLength;
-  }
-
-  private CodedOutputStream(final byte[] buffer, final int offset,
-                            final int length) {
-    output = null;
-    this.buffer = buffer;
-    position = offset;
-    limit = offset + length;
-  }
-
-  private CodedOutputStream(final OutputStream output, final byte[] buffer) {
-    this.output = output;
-    this.buffer = buffer;
-    position = 0;
-    limit = buffer.length;
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} wrapping the given
-   * {@code OutputStream}.
-   */
-  public static CodedOutputStream newInstance(final OutputStream output) {
-    return newInstance(output, DEFAULT_BUFFER_SIZE);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} wrapping the given
-   * {@code OutputStream} with a given buffer size.
-   */
-  public static CodedOutputStream newInstance(final OutputStream output,
-      final int bufferSize) {
-    return new CodedOutputStream(output, new byte[bufferSize]);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes directly to the given
-   * byte array.  If more bytes are written than fit in the array,
-   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
-   * array is faster than writing to an {@code OutputStream}.  See also
-   * {@link ByteString#newCodedBuilder}.
-   */
-  public static CodedOutputStream newInstance(final byte[] flatArray) {
-    return newInstance(flatArray, 0, flatArray.length);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes directly to the given
-   * byte array slice.  If more bytes are written than fit in the slice,
-   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
-   * array is faster than writing to an {@code OutputStream}.  See also
-   * {@link ByteString#newCodedBuilder}.
-   */
-  public static CodedOutputStream newInstance(final byte[] flatArray,
-                                              final int offset,
-                                              final int length) {
-    return new CodedOutputStream(flatArray, offset, length);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
-   */
-  public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
-    return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer.
-   */
-  public static CodedOutputStream newInstance(ByteBuffer byteBuffer,
-      int bufferSize) {
-    return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize);
-  }
-  
-  private static class ByteBufferOutputStream extends OutputStream {
-    private final ByteBuffer byteBuffer;
-    public ByteBufferOutputStream(ByteBuffer byteBuffer) {
-      this.byteBuffer = byteBuffer;
-    }
-
-    @Override
-    public void write(int b) throws IOException {
-      byteBuffer.put((byte) b);
-    }
-
-    @Override
-    public void write(byte[] data, int offset, int length) throws IOException {
-      byteBuffer.put(data, offset, length);
-    }
-  }
-
-  // -----------------------------------------------------------------
-
-  /** Write a {@code double} field, including tag, to the stream. */
-  public void writeDouble(final int fieldNumber, final double value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeDoubleNoTag(value);
-  }
-
-  /** Write a {@code float} field, including tag, to the stream. */
-  public void writeFloat(final int fieldNumber, final float value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeFloatNoTag(value);
-  }
-
-  /** Write a {@code uint64} field, including tag, to the stream. */
-  public void writeUInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeUInt64NoTag(value);
-  }
-
-  /** Write an {@code int64} field, including tag, to the stream. */
-  public void writeInt64(final int fieldNumber, final long value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeInt64NoTag(value);
-  }
-
-  /** Write an {@code int32} field, including tag, to the stream. */
-  public void writeInt32(final int fieldNumber, final int value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeInt32NoTag(value);
-  }
-
-  /** Write a {@code fixed64} field, including tag, to the stream. */
-  public void writeFixed64(final int fieldNumber, final long value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeFixed64NoTag(value);
-  }
-
-  /** Write a {@code fixed32} field, including tag, to the stream. */
-  public void writeFixed32(final int fieldNumber, final int value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeFixed32NoTag(value);
-  }
-
-  /** Write a {@code bool} field, including tag, to the stream. */
-  public void writeBool(final int fieldNumber, final boolean value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeBoolNoTag(value);
-  }
-
-  /** Write a {@code string} field, including tag, to the stream. */
-  public void writeString(final int fieldNumber, final String value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeStringNoTag(value);
-  }
-
-  /** Write a {@code group} field, including tag, to the stream. */
-  public void writeGroup(final int fieldNumber, final MessageLite value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
-    writeGroupNoTag(value);
-    writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
-  }
-
-
-  /**
-   * Write a group represented by an {@link UnknownFieldSet}.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #writeGroup}.
-   */
-  @Deprecated
-  public void writeUnknownGroup(final int fieldNumber,
-                                final MessageLite value)
-                                throws IOException {
-    writeGroup(fieldNumber, value);
-  }
-
-  /** Write an embedded message field, including tag, to the stream. */
-  public void writeMessage(final int fieldNumber, final MessageLite value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeMessageNoTag(value);
-  }
-
-
-  /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeBytes(final int fieldNumber, final ByteString value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeBytesNoTag(value);
-  }
-
-  /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeByteArray(final int fieldNumber, final byte[] value)
-                             throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteArrayNoTag(value);
-  }
-
-  /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeByteArray(final int fieldNumber,
-                             final byte[] value,
-                             final int offset,
-                             final int length)
-                             throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteArrayNoTag(value, offset, length);
-  }
-
-  /**
-   * Write a {@code bytes} field, including tag, to the stream.
-   * This method will write all content of the ByteBuffer regardless of the
-   * current position and limit (i.e., the number of bytes to be written is
-   * value.capacity(), not value.remaining()). Furthermore, this method doesn't
-   * alter the state of the passed-in ByteBuffer. Its position, limit, mark,
-   * etc. will remain unchanged. If you only want to write the remaining bytes
-   * of a ByteBuffer, you can call
-   * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}.
-   */
-  public void writeByteBuffer(final int fieldNumber, final ByteBuffer value)
-      throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    writeByteBufferNoTag(value);
-  }
-
-  /** Write a {@code uint32} field, including tag, to the stream. */
-  public void writeUInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeUInt32NoTag(value);
-  }
-
-  /**
-   * Write an enum field, including tag, to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
-   */
-  public void writeEnum(final int fieldNumber, final int value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeEnumNoTag(value);
-  }
-
-  /** Write an {@code sfixed32} field, including tag, to the stream. */
-  public void writeSFixed32(final int fieldNumber, final int value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
-    writeSFixed32NoTag(value);
-  }
-
-  /** Write an {@code sfixed64} field, including tag, to the stream. */
-  public void writeSFixed64(final int fieldNumber, final long value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
-    writeSFixed64NoTag(value);
-  }
-
-  /** Write an {@code sint32} field, including tag, to the stream. */
-  public void writeSInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeSInt32NoTag(value);
-  }
-
-  /** Write an {@code sint64} field, including tag, to the stream. */
-  public void writeSInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
-    writeSInt64NoTag(value);
-  }
-
-  /**
-   * Write a MessageSet extension field to the stream.  For historical reasons,
-   * the wire format differs from normal fields.
-   */
-  public void writeMessageSetExtension(final int fieldNumber,
-                                       final MessageLite value)
-                                       throws IOException {
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
-    writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
-    writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
-  }
-
-  /**
-   * Write an unparsed MessageSet extension field to the stream.  For
-   * historical reasons, the wire format differs from normal fields.
-   */
-  public void writeRawMessageSetExtension(final int fieldNumber,
-                                          final ByteString value)
-                                          throws IOException {
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
-    writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
-    writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
-    writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
-  }
-
-  // -----------------------------------------------------------------
-
-  /** Write a {@code double} field to the stream. */
-  public void writeDoubleNoTag(final double value) throws IOException {
-    writeRawLittleEndian64(Double.doubleToRawLongBits(value));
-  }
-
-  /** Write a {@code float} field to the stream. */
-  public void writeFloatNoTag(final float value) throws IOException {
-    writeRawLittleEndian32(Float.floatToRawIntBits(value));
-  }
-
-  /** Write a {@code uint64} field to the stream. */
-  public void writeUInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
-  /** Write an {@code int64} field to the stream. */
-  public void writeInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
-  /** Write an {@code int32} field to the stream. */
-  public void writeInt32NoTag(final int value) throws IOException {
-    if (value >= 0) {
-      writeRawVarint32(value);
-    } else {
-      // Must sign-extend.
-      writeRawVarint64(value);
-    }
-  }
-
-  /** Write a {@code fixed64} field to the stream. */
-  public void writeFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
-  }
-
-  /** Write a {@code fixed32} field to the stream. */
-  public void writeFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
-  }
-
-  /** Write a {@code bool} field to the stream. */
-  public void writeBoolNoTag(final boolean value) throws IOException {
-    writeRawByte(value ? 1 : 0);
-  }
-
-  /** Write a {@code string} field to the stream. */
-  public void writeStringNoTag(final String value) throws IOException {
-    // Unfortunately there does not appear to be any way to tell Java to encode
-    // UTF-8 directly into our buffer, so we have to let it create its own byte
-    // array and then copy.
-    final byte[] bytes = value.getBytes("UTF-8");
-    writeRawVarint32(bytes.length);
-    writeRawBytes(bytes);
-  }
-
-  /** Write a {@code group} field to the stream. */
-  public void writeGroupNoTag(final MessageLite value) throws IOException {
-    value.writeTo(this);
-  }
-
-
-  /**
-   * Write a group represented by an {@link UnknownFieldSet}.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #writeGroupNoTag}.
-   */
-  @Deprecated
-  public void writeUnknownGroupNoTag(final MessageLite value)
-      throws IOException {
-    writeGroupNoTag(value);
-  }
-
-  /** Write an embedded message field to the stream. */
-  public void writeMessageNoTag(final MessageLite value) throws IOException {
-    writeRawVarint32(value.getSerializedSize());
-    value.writeTo(this);
-  }
-
-
-  /** Write a {@code bytes} field to the stream. */
-  public void writeBytesNoTag(final ByteString value) throws IOException {
-    writeRawVarint32(value.size());
-    writeRawBytes(value);
-  }
-
-  /** Write a {@code bytes} field to the stream. */
-  public void writeByteArrayNoTag(final byte[] value) throws IOException {
-    writeRawVarint32(value.length);
-    writeRawBytes(value);
-  }
-
-  /** Write a {@code bytes} field to the stream. */
-  public void writeByteArrayNoTag(final byte[] value,
-                                  final int offset,
-                                  final int length) throws IOException {
-    writeRawVarint32(length);
-    writeRawBytes(value, offset, length);
-  }
-
-  /**
-   * Write a {@code bytes} field to the stream.  This method will write all
-   * content of the ByteBuffer regardless of the current position and limit
-   * (i.e., the number of bytes to be written is value.capacity(), not
-   * value.remaining()). Furthermore, this method doesn't alter the state of
-   * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain
-   * unchanged. If you only want to write the remaining bytes of a ByteBuffer,
-   * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}.
-   */
-  public void writeByteBufferNoTag(final ByteBuffer value) throws IOException {
-    writeRawVarint32(value.capacity());
-    writeRawBytes(value);
-  }
-
-  /** Write a {@code uint32} field to the stream. */
-  public void writeUInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(value);
-  }
-
-  /**
-   * Write an enum field to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
-   */
-  public void writeEnumNoTag(final int value) throws IOException {
-    writeInt32NoTag(value);
-  }
-
-  /** Write an {@code sfixed32} field to the stream. */
-  public void writeSFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
-  }
-
-  /** Write an {@code sfixed64} field to the stream. */
-  public void writeSFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
-  }
-
-  /** Write an {@code sint32} field to the stream. */
-  public void writeSInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(encodeZigZag32(value));
-  }
-
-  /** Write an {@code sint64} field to the stream. */
-  public void writeSInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(encodeZigZag64(value));
-  }
-
-  // =================================================================
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSize(final int fieldNumber,
-                                      final double value) {
-    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSize(final int fieldNumber, final float value) {
-    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int32} field, including tag.
-   */
-  public static int computeInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field, including tag.
-   */
-  public static int computeFixed64Size(final int fieldNumber,
-                                       final long value) {
-    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed32} field, including tag.
-   */
-  public static int computeFixed32Size(final int fieldNumber,
-                                       final int value) {
-    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bool} field, including tag.
-   */
-  public static int computeBoolSize(final int fieldNumber,
-                                    final boolean value) {
-    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code string} field, including tag.
-   */
-  public static int computeStringSize(final int fieldNumber,
-                                      final String value) {
-    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field, including tag.
-   */
-  public static int computeGroupSize(final int fieldNumber,
-                                     final MessageLite value) {
-    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field represented by an {@code UnknownFieldSet}, including
-   * tag.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #computeGroupSize}.
-   */
-  @Deprecated
-  public static int computeUnknownGroupSize(final int fieldNumber,
-                                            final MessageLite value) {
-    return computeGroupSize(fieldNumber, value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * embedded message field, including tag.
-   */
-  public static int computeMessageSize(final int fieldNumber,
-                                       final MessageLite value) {
-    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeBytesSize(final int fieldNumber,
-                                     final ByteString value) {
-    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeByteArraySize(final int fieldNumber,
-                                         final byte[] value) {
-    return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeByteBufferSize(final int fieldNumber,
-                                         final ByteBuffer value) {
-    return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * embedded message in lazy field, including tag.
-   */
-  public static int computeLazyFieldSize(final int fieldNumber,
-                                         final LazyFieldLite value) {
-    return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint32} field, including tag.
-   */
-  public static int computeUInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * enum field, including tag.  Caller is responsible for converting the
-   * enum value to its numeric value.
-   */
-  public static int computeEnumSize(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed32} field, including tag.
-   */
-  public static int computeSFixed32Size(final int fieldNumber,
-                                        final int value) {
-    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field, including tag.
-   */
-  public static int computeSFixed64Size(final int fieldNumber,
-                                        final long value) {
-    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field, including tag.
-   */
-  public static int computeSInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint64} field, including tag.
-   */
-  public static int computeSInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * MessageSet extension to the stream.  For historical reasons,
-   * the wire format differs from normal fields.
-   */
-  public static int computeMessageSetExtensionSize(
-      final int fieldNumber, final MessageLite value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * unparsed MessageSet extension field to the stream.  For
-   * historical reasons, the wire format differs from normal fields.
-   */
-  public static int computeRawMessageSetExtensionSize(
-      final int fieldNumber, final ByteString value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * lazily parsed MessageSet extension field to the stream.  For
-   * historical reasons, the wire format differs from normal fields.
-   */
-  public static int computeLazyFieldMessageSetExtensionSize(
-      final int fieldNumber, final LazyFieldLite value) {
-    return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
-           computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
-           computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value);
-  }
-  
-  // -----------------------------------------------------------------
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSizeNoTag(final double value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSizeNoTag(final float value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int32} field, including tag.
-   */
-  public static int computeInt32SizeNoTag(final int value) {
-    if (value >= 0) {
-      return computeRawVarint32Size(value);
-    } else {
-      // Must sign-extend.
-      return 10;
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field.
-   */
-  public static int computeFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed32} field.
-   */
-  public static int computeFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bool} field.
-   */
-  public static int computeBoolSizeNoTag(final boolean value) {
-    return 1;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code string} field.
-   */
-  public static int computeStringSizeNoTag(final String value) {
-    try {
-      final byte[] bytes = value.getBytes("UTF-8");
-      return computeRawVarint32Size(bytes.length) +
-             bytes.length;
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported.", e);
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field.
-   */
-  public static int computeGroupSizeNoTag(final MessageLite value) {
-    return value.getSerializedSize();
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field represented by an {@code UnknownFieldSet}, including
-   * tag.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #computeUnknownGroupSizeNoTag}.
-   */
-  @Deprecated
-  public static int computeUnknownGroupSizeNoTag(final MessageLite value) {
-    return computeGroupSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an embedded
-   * message field.
-   */
-  public static int computeMessageSizeNoTag(final MessageLite value) {
-    final int size = value.getSerializedSize();
-    return computeRawVarint32Size(size) + size;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an embedded
-   * message stored in lazy field.
-   */
-  public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) {
-    final int size = value.getSerializedSize();
-    return computeRawVarint32Size(size) + size;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field.
-   */
-  public static int computeBytesSizeNoTag(final ByteString value) {
-    return computeRawVarint32Size(value.size()) +
-           value.size();
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field.
-   */
-  public static int computeByteArraySizeNoTag(final byte[] value) {
-    return computeRawVarint32Size(value.length) + value.length;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field.
-   */
-  public static int computeByteBufferSizeNoTag(final ByteBuffer value) {
-    return computeRawVarint32Size(value.capacity()) + value.capacity();
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint32} field.
-   */
-  public static int computeUInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an enum field.
-   * Caller is responsible for converting the enum value to its numeric value.
-   */
-  public static int computeEnumSizeNoTag(final int value) {
-    return computeInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed32} field.
-   */
-  public static int computeSFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field.
-   */
-  public static int computeSFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field.
-   */
-  public static int computeSInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(encodeZigZag32(value));
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint64} field.
-   */
-  public static int computeSInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(encodeZigZag64(value));
-  }
-
-  // =================================================================
-
-  /**
-   * Internal helper that writes the current buffer to the output. The
-   * buffer position is reset to its initial value when this returns.
-   */
-  private void refreshBuffer() throws IOException {
-    if (output == null) {
-      // We're writing to a single buffer.
-      throw new OutOfSpaceException();
-    }
-
-    // Since we have an output stream, this is our buffer
-    // and buffer offset == 0
-    output.write(buffer, 0, position);
-    position = 0;
-  }
-
-  /**
-   * Flushes the stream and forces any buffered bytes to be written.  This
-   * does not flush the underlying OutputStream.
-   */
-  public void flush() throws IOException {
-    if (output != null) {
-      refreshBuffer();
-    }
-  }
-
-  /**
-   * If writing to a flat array, return the space left in the array.
-   * Otherwise, throws {@code UnsupportedOperationException}.
-   */
-  public int spaceLeft() {
-    if (output == null) {
-      return limit - position;
-    } else {
-      throw new UnsupportedOperationException(
-        "spaceLeft() can only be called on CodedOutputStreams that are " +
-        "writing to a flat array.");
-    }
-  }
-
-  /**
-   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
-   * a byte array that is exactly big enough to hold a message, then write to
-   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
-   * after writing verifies that the message was actually as big as expected,
-   * which can help catch bugs.
-   */
-  public void checkNoSpaceLeft() {
-    if (spaceLeft() != 0) {
-      throw new IllegalStateException(
-        "Did not write as much data as expected.");
-    }
-  }
-
-  /**
-   * If you create a CodedOutputStream around a simple flat array, you must
-   * not attempt to write more bytes than the array has space.  Otherwise,
-   * this exception will be thrown.
-   */
-  public static class OutOfSpaceException extends IOException {
-    private static final long serialVersionUID = -6947486886997889499L;
-
-    OutOfSpaceException() {
-      super("CodedOutputStream was writing to a flat byte array and ran " +
-            "out of space.");
-    }
-  }
-
-  /**
-   * Get the total number of bytes successfully written to this stream.  The
-   * returned value is not guaranteed to be accurate if exceptions have been
-   * found in the middle of writing.
-   */
-  public int getTotalBytesWritten() {
-    return totalBytesWritten;
-  }
-
-  /** Write a single byte. */
-  public void writeRawByte(final byte value) throws IOException {
-    if (position == limit) {
-      refreshBuffer();
-    }
-
-    buffer[position++] = value;
-    ++totalBytesWritten;
-  }
-
-  /** Write a single byte, represented by an integer value. */
-  public void writeRawByte(final int value) throws IOException {
-    writeRawByte((byte) value);
-  }
-
-  /** Write a byte string. */
-  public void writeRawBytes(final ByteString value) throws IOException {
-    writeRawBytes(value, 0, value.size());
-  }
-
-  /** Write an array of bytes. */
-  public void writeRawBytes(final byte[] value) throws IOException {
-    writeRawBytes(value, 0, value.length);
-  }
-
-  /**
-   * Write a ByteBuffer. This method will write all content of the ByteBuffer
-   * regardless of the current position and limit (i.e., the number of bytes
-   * to be written is value.capacity(), not value.remaining()). Furthermore,
-   * this method doesn't alter the state of the passed-in ByteBuffer. Its
-   * position, limit, mark, etc. will remain unchanged. If you only want to
-   * write the remaining bytes of a ByteBuffer, you can call
-   * {@code writeRawBytes(byteBuffer.slice())}.
-   */
-  public void writeRawBytes(final ByteBuffer value) throws IOException {
-    if (value.hasArray()) {
-      writeRawBytes(value.array(), value.arrayOffset(), value.capacity());
-    } else {
-      ByteBuffer duplicated = value.duplicate();
-      duplicated.clear();
-      writeRawBytesInternal(duplicated);
-    }
-  }
-
-  /** Write a ByteBuffer that isn't backed by an array. */
-  private void writeRawBytesInternal(final ByteBuffer value)
-      throws IOException {
-    int length = value.remaining();
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      value.get(buffer, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      value.get(buffer, position, bytesWritten);
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      while (length > limit) {
-        // Copy data into the buffer before writing it to OutputStream.
-        // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy.
-        value.get(buffer, 0, limit);
-        output.write(buffer, 0, limit);
-        length -= limit;
-        totalBytesWritten += limit;
-      }
-      value.get(buffer, 0, length);
-      position = length;
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Write part of an array of bytes. */
-  public void writeRawBytes(final byte[] value, int offset, int length)
-                            throws IOException {
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      System.arraycopy(value, offset, buffer, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      System.arraycopy(value, offset, buffer, position, bytesWritten);
-      offset += bytesWritten;
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      if (length <= limit) {
-        // Fits in new buffer.
-        System.arraycopy(value, offset, buffer, 0, length);
-        position = length;
-      } else {
-        // Write is very big.  Let's do it all at once.
-        output.write(value, offset, length);
-      }
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Write part of a byte string. */
-  public void writeRawBytes(final ByteString value, int offset, int length)
-                            throws IOException {
-    if (limit - position >= length) {
-      // We have room in the current buffer.
-      value.copyTo(buffer, offset, position, length);
-      position += length;
-      totalBytesWritten += length;
-    } else {
-      // Write extends past current buffer.  Fill the rest of this buffer and
-      // flush.
-      final int bytesWritten = limit - position;
-      value.copyTo(buffer, offset, position, bytesWritten);
-      offset += bytesWritten;
-      length -= bytesWritten;
-      position = limit;
-      totalBytesWritten += bytesWritten;
-      refreshBuffer();
-
-      // Now deal with the rest.
-      // Since we have an output stream, this is our buffer
-      // and buffer offset == 0
-      if (length <= limit) {
-        // Fits in new buffer.
-        value.copyTo(buffer, offset, 0, length);
-        position = length;
-      } else {
-        value.writeTo(output, offset, length);
-      }
-      totalBytesWritten += length;
-    }
-  }
-
-  /** Encode and write a tag. */
-  public void writeTag(final int fieldNumber, final int wireType)
-                       throws IOException {
-    writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
-  }
-
-  /** Compute the number of bytes that would be needed to encode a tag. */
-  public static int computeTagSize(final int fieldNumber) {
-    return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
-  }
-
-  /**
-   * Encode and write a varint.  {@code value} is treated as
-   * unsigned, so it won't be sign-extended if negative.
-   */
-  public void writeRawVarint32(int value) throws IOException {
-    while (true) {
-      if ((value & ~0x7F) == 0) {
-        writeRawByte(value);
-        return;
-      } else {
-        writeRawByte((value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a varint.
-   * {@code value} is treated as unsigned, so it won't be sign-extended if
-   * negative.
-   */
-  public static int computeRawVarint32Size(final int value) {
-    if ((value & (0xffffffff <<  7)) == 0) return 1;
-    if ((value & (0xffffffff << 14)) == 0) return 2;
-    if ((value & (0xffffffff << 21)) == 0) return 3;
-    if ((value & (0xffffffff << 28)) == 0) return 4;
-    return 5;
-  }
-
-  /** Encode and write a varint. */
-  public void writeRawVarint64(long value) throws IOException {
-    while (true) {
-      if ((value & ~0x7FL) == 0) {
-        writeRawByte((int)value);
-        return;
-      } else {
-        writeRawByte(((int)value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /** Compute the number of bytes that would be needed to encode a varint. */
-  public static int computeRawVarint64Size(final long value) {
-    if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
-    if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
-    if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
-    if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
-    if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
-    if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
-    if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
-    if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
-    if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
-    return 10;
-  }
-
-  /** Write a little-endian 32-bit integer. */
-  public void writeRawLittleEndian32(final int value) throws IOException {
-    writeRawByte((value      ) & 0xFF);
-    writeRawByte((value >>  8) & 0xFF);
-    writeRawByte((value >> 16) & 0xFF);
-    writeRawByte((value >> 24) & 0xFF);
-  }
-
-  public static final int LITTLE_ENDIAN_32_SIZE = 4;
-
-  /** Write a little-endian 64-bit integer. */
-  public void writeRawLittleEndian64(final long value) throws IOException {
-    writeRawByte((int)(value      ) & 0xFF);
-    writeRawByte((int)(value >>  8) & 0xFF);
-    writeRawByte((int)(value >> 16) & 0xFF);
-    writeRawByte((int)(value >> 24) & 0xFF);
-    writeRawByte((int)(value >> 32) & 0xFF);
-    writeRawByte((int)(value >> 40) & 0xFF);
-    writeRawByte((int)(value >> 48) & 0xFF);
-    writeRawByte((int)(value >> 56) & 0xFF);
-  }
-
-  public static final int LITTLE_ENDIAN_64_SIZE = 8;
-
-  /**
-   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n A signed 32-bit integer.
-   * @return An unsigned 32-bit integer, stored in a signed int because
-   *         Java has no explicit unsigned support.
-   */
-  public static int encodeZigZag32(final int n) {
-    // Note:  the right-shift must be arithmetic
-    return (n << 1) ^ (n >> 31);
-  }
-
-  /**
-   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n A signed 64-bit integer.
-   * @return An unsigned 64-bit integer, stored in a signed int because
-   *         Java has no explicit unsigned support.
-   */
-  public static long encodeZigZag64(final long n) {
-    // Note:  the right-shift must be arithmetic
-    return (n << 1) ^ (n >> 63);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
deleted file mode 100644
index caae0f7..0000000
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ /dev/null
@@ -1,2238 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.DescriptorProtos.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Logger;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Contains a collection of classes which describe protocol message types.
- *
- * Every message type has a {@link Descriptor}, which lists all
- * its fields and other information about a type.  You can get a message
- * type's descriptor by calling {@code MessageType.getDescriptor()}, or
- * (given a message object of the type) {@code message.getDescriptorForType()}.
- * Furthermore, each message is associated with a {@link FileDescriptor} for
- * a relevant {@code .proto} file. You can obtain it by calling
- * {@code Descriptor.getFile()}. A {@link FileDescriptor} contains descriptors
- * for all the messages defined in that file, and file descriptors for all the
- * imported {@code .proto} files.
- *
- * Descriptors are built from DescriptorProtos, as defined in
- * {@code google/protobuf/descriptor.proto}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class Descriptors {
-  private static final Logger logger =
-      Logger.getLogger(Descriptors.class.getName());
-  /**
-   * Describes a {@code .proto} file, including everything defined within.
-   * That includes, in particular, descriptors for all the messages and
-   * file descriptors for all other imported {@code .proto} files
-   * (dependencies).
-   */
-  public static final class FileDescriptor extends GenericDescriptor {
-    /** Convert the descriptor to its protocol message representation. */
-    public FileDescriptorProto toProto() { return proto; }
-
-    /** Get the file name. */
-    public String getName() { return proto.getName(); }
-
-    /** Returns this object. */
-    public FileDescriptor getFile() { return this; }
-
-    /** Returns the same as getName(). */
-    public String getFullName() { return proto.getName(); }
-
-    /**
-     * Get the proto package name.  This is the package name given by the
-     * {@code package} statement in the {@code .proto} file, which differs
-     * from the Java package.
-     */
-    public String getPackage() { return proto.getPackage(); }
-
-    /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
-    public FileOptions getOptions() { return proto.getOptions(); }
-
-    /** Get a list of top-level message types declared in this file. */
-    public List<Descriptor> getMessageTypes() {
-      return Collections.unmodifiableList(Arrays.asList(messageTypes));
-    }
-
-    /** Get a list of top-level enum types declared in this file. */
-    public List<EnumDescriptor> getEnumTypes() {
-      return Collections.unmodifiableList(Arrays.asList(enumTypes));
-    }
-
-    /** Get a list of top-level services declared in this file. */
-    public List<ServiceDescriptor> getServices() {
-      return Collections.unmodifiableList(Arrays.asList(services));
-    }
-
-    /** Get a list of top-level extensions declared in this file. */
-    public List<FieldDescriptor> getExtensions() {
-      return Collections.unmodifiableList(Arrays.asList(extensions));
-    }
-
-    /** Get a list of this file's dependencies (imports). */
-    public List<FileDescriptor> getDependencies() {
-      return Collections.unmodifiableList(Arrays.asList(dependencies));
-    }
-
-    /** Get a list of this file's public dependencies (public imports). */
-    public List<FileDescriptor> getPublicDependencies() {
-      return Collections.unmodifiableList(Arrays.asList(publicDependencies));
-    }
-
-    /**
-     * Find a message type in the file by name.  Does not find nested types.
-     *
-     * @param name The unqualified type name to look for.
-     * @return The message type's descriptor, or {@code null} if not found.
-     */
-    public Descriptor findMessageTypeByName(String name) {
-      // Don't allow looking up nested types.  This will make optimization
-      // easier later.
-      if (name.indexOf('.') != -1) {
-        return null;
-      }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
-      }
-      final GenericDescriptor result = pool.findSymbol(name);
-      if (result != null && result instanceof Descriptor &&
-          result.getFile() == this) {
-        return (Descriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Find an enum type in the file by name.  Does not find nested types.
-     *
-     * @param name The unqualified type name to look for.
-     * @return The enum type's descriptor, or {@code null} if not found.
-     */
-    public EnumDescriptor findEnumTypeByName(String name) {
-      // Don't allow looking up nested types.  This will make optimization
-      // easier later.
-      if (name.indexOf('.') != -1) {
-        return null;
-      }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
-      }
-      final GenericDescriptor result = pool.findSymbol(name);
-      if (result != null && result instanceof EnumDescriptor &&
-          result.getFile() == this) {
-        return (EnumDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Find a service type in the file by name.
-     *
-     * @param name The unqualified type name to look for.
-     * @return The service type's descriptor, or {@code null} if not found.
-     */
-    public ServiceDescriptor findServiceByName(String name) {
-      // Don't allow looking up nested types.  This will make optimization
-      // easier later.
-      if (name.indexOf('.') != -1) {
-        return null;
-      }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
-      }
-      final GenericDescriptor result = pool.findSymbol(name);
-      if (result != null && result instanceof ServiceDescriptor &&
-          result.getFile() == this) {
-        return (ServiceDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Find an extension in the file by name.  Does not find extensions nested
-     * inside message types.
-     *
-     * @param name The unqualified extension name to look for.
-     * @return The extension's descriptor, or {@code null} if not found.
-     */
-    public FieldDescriptor findExtensionByName(String name) {
-      if (name.indexOf('.') != -1) {
-        return null;
-      }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
-      }
-      final GenericDescriptor result = pool.findSymbol(name);
-      if (result != null && result instanceof FieldDescriptor &&
-          result.getFile() == this) {
-        return (FieldDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Construct a {@code FileDescriptor}.
-     *
-     * @param proto The protocol message form of the FileDescriptor.
-     * @param dependencies {@code FileDescriptor}s corresponding to all of
-     *                     the file's dependencies.
-     * @throws DescriptorValidationException {@code proto} is not a valid
-     *           descriptor.  This can occur for a number of reasons, e.g.
-     *           because a field has an undefined type or because two messages
-     *           were defined with the same name.
-     */
-    public static FileDescriptor buildFrom(final FileDescriptorProto proto,
-                                           final FileDescriptor[] dependencies)
-                                    throws DescriptorValidationException {
-      return buildFrom(proto, dependencies, false);
-    }
-    
-
-    /**
-     * Construct a {@code FileDescriptor}.
-     *
-     * @param proto The protocol message form of the FileDescriptor.
-     * @param dependencies {@code FileDescriptor}s corresponding to all of
-     *                     the file's dependencies.
-     * @param allowUnknownDependencies If true, non-exist dependenncies will be
-     *           ignored and undefined message types will be replaced with a
-     *           placeholder type.
-     * @throws DescriptorValidationException {@code proto} is not a valid
-     *           descriptor.  This can occur for a number of reasons, e.g.
-     *           because a field has an undefined type or because two messages
-     *           were defined with the same name.
-     */
-    private static FileDescriptor buildFrom(
-        final FileDescriptorProto proto, final FileDescriptor[] dependencies,
-        final boolean allowUnknownDependencies)
-        throws DescriptorValidationException {
-      // Building descriptors involves two steps:  translating and linking.
-      // In the translation step (implemented by FileDescriptor's
-      // constructor), we build an object tree mirroring the
-      // FileDescriptorProto's tree and put all of the descriptors into the
-      // DescriptorPool's lookup tables.  In the linking step, we look up all
-      // type references in the DescriptorPool, so that, for example, a
-      // FieldDescriptor for an embedded message contains a pointer directly
-      // to the Descriptor for that message's type.  We also detect undefined
-      // types in the linking step.
-      final DescriptorPool pool = new DescriptorPool(
-          dependencies, allowUnknownDependencies);
-      final FileDescriptor result = new FileDescriptor(
-          proto, dependencies, pool, allowUnknownDependencies);
-      result.crossLink();
-      return result;
-    }
-
-    /**
-     * This method is to be called by generated code only.  It is equivalent
-     * to {@code buildFrom} except that the {@code FileDescriptorProto} is
-     * encoded in protocol buffer wire format.
-     */
-    public static void internalBuildGeneratedFileFrom(
-        final String[] descriptorDataParts,
-        final FileDescriptor[] dependencies,
-        final InternalDescriptorAssigner descriptorAssigner) {
-      // Hack:  We can't embed a raw byte array inside generated Java code
-      //   (at least, not efficiently), but we can embed Strings.  So, the
-      //   protocol compiler embeds the FileDescriptorProto as a giant
-      //   string literal which is passed to this function to construct the
-      //   file's FileDescriptor.  The string literal contains only 8-bit
-      //   characters, each one representing a byte of the FileDescriptorProto's
-      //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
-      //   should get the original bytes that we want.
-
-      // descriptorData may contain multiple strings in order to get around the
-      // Java 64k string literal limit.
-      StringBuilder descriptorData = new StringBuilder();
-      for (String part : descriptorDataParts) {
-        descriptorData.append(part);
-      }
-
-      final byte[] descriptorBytes;
-      try {
-        descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
-      } catch (UnsupportedEncodingException e) {
-        throw new RuntimeException(
-          "Standard encoding ISO-8859-1 not supported by JVM.", e);
-      }
-
-      FileDescriptorProto proto;
-      try {
-        proto = FileDescriptorProto.parseFrom(descriptorBytes);
-      } catch (InvalidProtocolBufferException e) {
-        throw new IllegalArgumentException(
-          "Failed to parse protocol buffer descriptor for generated code.", e);
-      }
-
-      final FileDescriptor result;
-      try {
-        // When building descriptors for generated code, we allow unknown
-        // dependencies by default.
-        result = buildFrom(proto, dependencies, true);
-      } catch (DescriptorValidationException e) {
-        throw new IllegalArgumentException(
-          "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
-      }
-
-      final ExtensionRegistry registry =
-          descriptorAssigner.assignDescriptors(result);
-
-      if (registry != null) {
-        // We must re-parse the proto using the registry.
-        try {
-          proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
-        } catch (InvalidProtocolBufferException e) {
-          throw new IllegalArgumentException(
-            "Failed to parse protocol buffer descriptor for generated code.",
-            e);
-        }
-
-        result.setProto(proto);
-      }
-    }
-
-    /**
-     * This method is to be called by generated code only.  It uses Java
-     * reflection to load the dependencies' descriptors.
-     */
-    public static void internalBuildGeneratedFileFrom(
-        final String[] descriptorDataParts,
-        final Class<?> descriptorOuterClass,
-        final String[] dependencies,
-        final String[] dependencyFileNames,
-        final InternalDescriptorAssigner descriptorAssigner) {
-      List<FileDescriptor> descriptors = new ArrayList<FileDescriptor>();
-      for (int i = 0; i < dependencies.length; i++) {
-        try {
-          Class<?> clazz =
-              descriptorOuterClass.getClassLoader().loadClass(dependencies[i]);
-          descriptors.add(
-              (FileDescriptor) clazz.getField("descriptor").get(null));
-        } catch (Exception e) {
-          // We allow unknown dependencies by default. If a dependency cannot
-          // be found we only generate a warning.
-          logger.warning("Descriptors for \"" + dependencyFileNames[i] +
-              "\" can not be found.");
-        }
-      }
-      FileDescriptor[] descriptorArray = new FileDescriptor[descriptors.size()];
-      descriptors.toArray(descriptorArray);
-      internalBuildGeneratedFileFrom(
-          descriptorDataParts, descriptorArray, descriptorAssigner);
-    }
-
-    /**
-     * This method is to be called by generated code only.  It is used to
-     * update the FileDescriptorProto associated with the descriptor by
-     * parsing it again with the given ExtensionRegistry. This is needed to
-     * recognize custom options.
-     */
-    public static void internalUpdateFileDescriptor(
-        final FileDescriptor descriptor,
-        final ExtensionRegistry registry) {
-      ByteString bytes = descriptor.proto.toByteString();
-      FileDescriptorProto proto;
-      try {
-        proto = FileDescriptorProto.parseFrom(bytes, registry);
-      } catch (InvalidProtocolBufferException e) {
-        throw new IllegalArgumentException(
-          "Failed to parse protocol buffer descriptor for generated code.", e);
-      }
-      descriptor.setProto(proto);
-    }
-
-    /**
-     * This class should be used by generated code only.  When calling
-     * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
-     * provides a callback implementing this interface.  The callback is called
-     * after the FileDescriptor has been constructed, in order to assign all
-     * the global variables defined in the generated code which point at parts
-     * of the FileDescriptor.  The callback returns an ExtensionRegistry which
-     * contains any extensions which might be used in the descriptor -- that
-     * is, extensions of the various "Options" messages defined in
-     * descriptor.proto.  The callback may also return null to indicate that
-     * no extensions are used in the descriptor.
-     */
-    public interface InternalDescriptorAssigner {
-      ExtensionRegistry assignDescriptors(FileDescriptor root);
-    }
-
-    private FileDescriptorProto proto;
-    private final Descriptor[] messageTypes;
-    private final EnumDescriptor[] enumTypes;
-    private final ServiceDescriptor[] services;
-    private final FieldDescriptor[] extensions;
-    private final FileDescriptor[] dependencies;
-    private final FileDescriptor[] publicDependencies;
-    private final DescriptorPool pool;
-
-    private FileDescriptor(final FileDescriptorProto proto,
-                           final FileDescriptor[] dependencies,
-                           final DescriptorPool pool,
-                           boolean allowUnknownDependencies)
-                    throws DescriptorValidationException {
-      this.pool = pool;
-      this.proto = proto;
-      this.dependencies = dependencies.clone();
-      HashMap<String, FileDescriptor> nameToFileMap =
-          new HashMap<String, FileDescriptor>();
-      for (FileDescriptor file : dependencies) {
-        nameToFileMap.put(file.getName(), file);
-      }
-      List<FileDescriptor> publicDependencies = new ArrayList<FileDescriptor>();
-      for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
-        int index = proto.getPublicDependency(i);
-        if (index < 0 || index >= proto.getDependencyCount()) {
-          throw new DescriptorValidationException(this,
-              "Invalid public dependency index.");
-        }
-        String name = proto.getDependency(index);
-        FileDescriptor file = nameToFileMap.get(name);
-        if (file == null) {
-          if (!allowUnknownDependencies) {
-            throw new DescriptorValidationException(this,
-                "Invalid public dependency: " + name);
-          }
-          // Ignore unknown dependencies.
-        } else {
-          publicDependencies.add(file);
-        }
-      }
-      this.publicDependencies = new FileDescriptor[publicDependencies.size()];
-      publicDependencies.toArray(this.publicDependencies);
-
-      pool.addPackage(getPackage(), this);
-
-      messageTypes = new Descriptor[proto.getMessageTypeCount()];
-      for (int i = 0; i < proto.getMessageTypeCount(); i++) {
-        messageTypes[i] =
-          new Descriptor(proto.getMessageType(i), this, null, i);
-      }
-
-      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
-      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
-        enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
-      }
-
-      services = new ServiceDescriptor[proto.getServiceCount()];
-      for (int i = 0; i < proto.getServiceCount(); i++) {
-        services[i] = new ServiceDescriptor(proto.getService(i), this, i);
-      }
-
-      extensions = new FieldDescriptor[proto.getExtensionCount()];
-      for (int i = 0; i < proto.getExtensionCount(); i++) {
-        extensions[i] = new FieldDescriptor(
-          proto.getExtension(i), this, null, i, true);
-      }
-    }
-    
-    /**
-     * Create a placeholder FileDescriptor for a message Descriptor. 
-     */
-    FileDescriptor(String packageName, Descriptor message)
-        throws DescriptorValidationException {
-      this.pool = new DescriptorPool(new FileDescriptor[0], true);
-      this.proto = FileDescriptorProto.newBuilder()
-          .setName(message.getFullName() + ".placeholder.proto")
-          .setPackage(packageName).addMessageType(message.toProto()).build();
-      this.dependencies = new FileDescriptor[0];
-      this.publicDependencies = new FileDescriptor[0];
-
-      messageTypes = new Descriptor[] {message};
-      enumTypes = new EnumDescriptor[0];
-      services = new ServiceDescriptor[0];
-      extensions = new FieldDescriptor[0];
-
-      pool.addPackage(packageName, this);
-      pool.addSymbol(message);
-    }
-
-    /** Look up and cross-link all field types, etc. */
-    private void crossLink() throws DescriptorValidationException {
-      for (final Descriptor messageType : messageTypes) {
-        messageType.crossLink();
-      }
-
-      for (final ServiceDescriptor service : services) {
-        service.crossLink();
-      }
-
-      for (final FieldDescriptor extension : extensions) {
-        extension.crossLink();
-      }
-    }
-
-    /**
-     * Replace our {@link FileDescriptorProto} with the given one, which is
-     * identical except that it might contain extensions that weren't present
-     * in the original.  This method is needed for bootstrapping when a file
-     * defines custom options.  The options may be defined in the file itself,
-     * so we can't actually parse them until we've constructed the descriptors,
-     * but to construct the descriptors we have to have parsed the descriptor
-     * protos.  So, we have to parse the descriptor protos a second time after
-     * constructing the descriptors.
-     */
-    private void setProto(final FileDescriptorProto proto) {
-      this.proto = proto;
-
-      for (int i = 0; i < messageTypes.length; i++) {
-        messageTypes[i].setProto(proto.getMessageType(i));
-      }
-
-      for (int i = 0; i < enumTypes.length; i++) {
-        enumTypes[i].setProto(proto.getEnumType(i));
-      }
-
-      for (int i = 0; i < services.length; i++) {
-        services[i].setProto(proto.getService(i));
-      }
-
-      for (int i = 0; i < extensions.length; i++) {
-        extensions[i].setProto(proto.getExtension(i));
-      }
-    }
-  }
-
-  // =================================================================
-
-  /** Describes a message type. */
-  public static final class Descriptor extends GenericDescriptor {
-    /**
-     * Get the index of this descriptor within its parent.  In other words,
-     * given a {@link FileDescriptor} {@code file}, the following is true:
-     * <pre>
-     *   for all i in [0, file.getMessageTypeCount()):
-     *     file.getMessageType(i).getIndex() == i
-     * </pre>
-     * Similarly, for a {@link Descriptor} {@code messageType}:
-     * <pre>
-     *   for all i in [0, messageType.getNestedTypeCount()):
-     *     messageType.getNestedType(i).getIndex() == i
-     * </pre>
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public DescriptorProto toProto() { return proto; }
-
-    /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /**
-     * Get the type's fully-qualified name, within the proto language's
-     * namespace.  This differs from the Java name.  For example, given this
-     * {@code .proto}:
-     * <pre>
-     *   package foo.bar;
-     *   option java_package = "com.example.protos"
-     *   message Baz {}
-     * </pre>
-     * {@code Baz}'s full name is "foo.bar.Baz".
-     */
-    public String getFullName() { return fullName; }
-
-    /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** If this is a nested type, get the outer descriptor, otherwise null. */
-    public Descriptor getContainingType() { return containingType; }
-
-    /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
-    public MessageOptions getOptions() { return proto.getOptions(); }
-
-    /** Get a list of this message type's fields. */
-    public List<FieldDescriptor> getFields() {
-      return Collections.unmodifiableList(Arrays.asList(fields));
-    }
-
-    /** Get a list of this message type's oneofs. */
-    public List<OneofDescriptor> getOneofs() {
-      return Collections.unmodifiableList(Arrays.asList(oneofs));
-    }
-
-    /** Get a list of this message type's extensions. */
-    public List<FieldDescriptor> getExtensions() {
-      return Collections.unmodifiableList(Arrays.asList(extensions));
-    }
-
-    /** Get a list of message types nested within this one. */
-    public List<Descriptor> getNestedTypes() {
-      return Collections.unmodifiableList(Arrays.asList(nestedTypes));
-    }
-
-    /** Get a list of enum types nested within this one. */
-    public List<EnumDescriptor> getEnumTypes() {
-      return Collections.unmodifiableList(Arrays.asList(enumTypes));
-    }
-
-    /** Determines if the given field number is an extension. */
-    public boolean isExtensionNumber(final int number) {
-      for (final DescriptorProto.ExtensionRange range :
-          proto.getExtensionRangeList()) {
-        if (range.getStart() <= number && number < range.getEnd()) {
-          return true;
-        }
-      }
-      return false;
-    }
-
-    /**
-     * Indicates whether the message can be extended.  That is, whether it has
-     * any "extensions x to y" ranges declared on it.
-     */
-    public boolean isExtendable() {
-      return proto.getExtensionRangeList().size() != 0;
-    }
-
-    /**
-     * Finds a field by name.
-     * @param name The unqualified name of the field (e.g. "foo").
-     * @return The field's descriptor, or {@code null} if not found.
-     */
-    public FieldDescriptor findFieldByName(final String name) {
-      final GenericDescriptor result =
-          file.pool.findSymbol(fullName + '.' + name);
-      if (result != null && result instanceof FieldDescriptor) {
-        return (FieldDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Finds a field by field number.
-     * @param number The field number within this message type.
-     * @return The field's descriptor, or {@code null} if not found.
-     */
-    public FieldDescriptor findFieldByNumber(final int number) {
-      return file.pool.fieldsByNumber.get(
-        new DescriptorPool.DescriptorIntPair(this, number));
-    }
-
-    /**
-     * Finds a nested message type by name.
-     * @param name The unqualified name of the nested type (e.g. "Foo").
-     * @return The types's descriptor, or {@code null} if not found.
-     */
-    public Descriptor findNestedTypeByName(final String name) {
-      final GenericDescriptor result =
-          file.pool.findSymbol(fullName + '.' + name);
-      if (result != null && result instanceof Descriptor) {
-        return (Descriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Finds a nested enum type by name.
-     * @param name The unqualified name of the nested type (e.g. "Foo").
-     * @return The types's descriptor, or {@code null} if not found.
-     */
-    public EnumDescriptor findEnumTypeByName(final String name) {
-      final GenericDescriptor result =
-          file.pool.findSymbol(fullName + '.' + name);
-      if (result != null && result instanceof EnumDescriptor) {
-        return (EnumDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    private final int index;
-    private DescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private final Descriptor containingType;
-    private final Descriptor[] nestedTypes;
-    private final EnumDescriptor[] enumTypes;
-    private final FieldDescriptor[] fields;
-    private final FieldDescriptor[] extensions;
-    private final OneofDescriptor[] oneofs;
-
-    // Used to create a placeholder when the type cannot be found.
-    Descriptor(final String fullname) throws DescriptorValidationException {
-      String name = fullname;
-      String packageName = "";
-      int pos = fullname.lastIndexOf('.');
-      if (pos != -1) {
-        name = fullname.substring(pos + 1);
-        packageName = fullname.substring(0, pos);
-      }
-      this.index = 0;
-      this.proto = DescriptorProto.newBuilder().setName(name).addExtensionRange(
-          DescriptorProto.ExtensionRange.newBuilder().setStart(1)
-          .setEnd(536870912).build()).build();
-      this.fullName = fullname;
-      this.containingType = null;
-
-      this.nestedTypes = new Descriptor[0];
-      this.enumTypes = new EnumDescriptor[0];
-      this.fields = new FieldDescriptor[0];
-      this.extensions = new FieldDescriptor[0];
-      this.oneofs = new OneofDescriptor[0];
-      
-      // Create a placeholder FileDescriptor to hold this message.
-      this.file = new FileDescriptor(packageName, this);
-    }
-
-    private Descriptor(final DescriptorProto proto,
-                       final FileDescriptor file,
-                       final Descriptor parent,
-                       final int index)
-                throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      fullName = computeFullName(file, parent, proto.getName());
-      this.file = file;
-      containingType = parent;
-
-      oneofs = new OneofDescriptor[proto.getOneofDeclCount()];
-      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
-        oneofs[i] = new OneofDescriptor(
-          proto.getOneofDecl(i), file, this, i);
-      }
-
-      nestedTypes = new Descriptor[proto.getNestedTypeCount()];
-      for (int i = 0; i < proto.getNestedTypeCount(); i++) {
-        nestedTypes[i] = new Descriptor(
-          proto.getNestedType(i), file, this, i);
-      }
-
-      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
-      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
-        enumTypes[i] = new EnumDescriptor(
-          proto.getEnumType(i), file, this, i);
-      }
-
-      fields = new FieldDescriptor[proto.getFieldCount()];
-      for (int i = 0; i < proto.getFieldCount(); i++) {
-        fields[i] = new FieldDescriptor(
-          proto.getField(i), file, this, i, false);
-      }
-
-      extensions = new FieldDescriptor[proto.getExtensionCount()];
-      for (int i = 0; i < proto.getExtensionCount(); i++) {
-        extensions[i] = new FieldDescriptor(
-          proto.getExtension(i), file, this, i, true);
-      }
-
-      for (int i = 0; i < proto.getOneofDeclCount(); i++) {
-        oneofs[i].fields = new FieldDescriptor[oneofs[i].getFieldCount()];
-        oneofs[i].fieldCount = 0;
-      }
-      for (int i = 0; i < proto.getFieldCount(); i++) {
-        OneofDescriptor oneofDescriptor = fields[i].getContainingOneof();
-        if (oneofDescriptor != null) {
-          oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
-        }
-      }
-
-      file.pool.addSymbol(this);
-    }
-
-    /** Look up and cross-link all field types, etc. */
-    private void crossLink() throws DescriptorValidationException {
-      for (final Descriptor nestedType : nestedTypes) {
-        nestedType.crossLink();
-      }
-
-      for (final FieldDescriptor field : fields) {
-        field.crossLink();
-      }
-
-      for (final FieldDescriptor extension : extensions) {
-        extension.crossLink();
-      }
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final DescriptorProto proto) {
-      this.proto = proto;
-
-      for (int i = 0; i < nestedTypes.length; i++) {
-        nestedTypes[i].setProto(proto.getNestedType(i));
-      }
-
-      for (int i = 0; i < enumTypes.length; i++) {
-        enumTypes[i].setProto(proto.getEnumType(i));
-      }
-
-      for (int i = 0; i < fields.length; i++) {
-        fields[i].setProto(proto.getField(i));
-      }
-
-      for (int i = 0; i < extensions.length; i++) {
-        extensions[i].setProto(proto.getExtension(i));
-      }
-    }
-  }
-
-  // =================================================================
-
-  /** Describes a field of a message type. */
-  public static final class FieldDescriptor
-        extends GenericDescriptor
-        implements Comparable<FieldDescriptor>,
-                 FieldSet.FieldDescriptorLite<FieldDescriptor> {
-    /**
-     * Get the index of this descriptor within its parent.
-     * @see Descriptors.Descriptor#getIndex()
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public FieldDescriptorProto toProto() { return proto; }
-
-    /** Get the field's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /** Get the field's number. */
-    public int getNumber() { return proto.getNumber(); }
-
-    /**
-     * Get the field's fully-qualified name.
-     * @see Descriptors.Descriptor#getFullName()
-     */
-    public String getFullName() { return fullName; }
-
-    /**
-     * Get the field's java type.  This is just for convenience.  Every
-     * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
-     */
-    public JavaType getJavaType() { return type.getJavaType(); }
-
-    /** For internal use only. */
-    public WireFormat.JavaType getLiteJavaType() {
-      return getLiteType().getJavaType();
-    }
-
-    /** Get the {@code FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** Get the field's declared type. */
-    public Type getType() { return type; }
-
-    /** For internal use only. */
-    public WireFormat.FieldType getLiteType() {
-      return table[type.ordinal()];
-    }
-
-    /** For internal use only. */
-    public boolean needsUtf8Check() {
-      return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8());
-    }
-
-    // I'm pretty sure values() constructs a new array every time, since there
-    // is nothing stopping the caller from mutating the array.  Therefore we
-    // make a static copy here.
-    private static final WireFormat.FieldType[] table =
-        WireFormat.FieldType.values();
-
-    /** Is this field declared required? */
-    public boolean isRequired() {
-      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
-    }
-
-    /** Is this field declared optional? */
-    public boolean isOptional() {
-      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
-    }
-
-    /** Is this field declared repeated? */
-    public boolean isRepeated() {
-      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
-    }
-
-    /** Does this field have the {@code [packed = true]} option? */
-    public boolean isPacked() {
-      return getOptions().getPacked();
-    }
-
-    /** Can this field be packed? i.e. is it a repeated primitive field? */
-    public boolean isPackable() {
-      return isRepeated() && getLiteType().isPackable();
-    }
-
-    /** Returns true if the field had an explicitly-defined default value. */
-    public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
-
-    /**
-     * Returns the field's default value.  Valid for all types except for
-     * messages and groups.  For all other types, the object returned is of
-     * the same class that would returned by Message.getField(this).
-     */
-    public Object getDefaultValue() {
-      if (getJavaType() == JavaType.MESSAGE) {
-        throw new UnsupportedOperationException(
-          "FieldDescriptor.getDefaultValue() called on an embedded message " +
-          "field.");
-      }
-      return defaultValue;
-    }
-
-    /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
-    public FieldOptions getOptions() { return proto.getOptions(); }
-
-    /** Is this field an extension? */
-    public boolean isExtension() { return proto.hasExtendee(); }
-
-    /**
-     * Get the field's containing type. For extensions, this is the type being
-     * extended, not the location where the extension was defined.  See
-     * {@link #getExtensionScope()}.
-     */
-    public Descriptor getContainingType() { return containingType; }
-
-    /** Get the field's containing oneof. */
-    public OneofDescriptor getContainingOneof() { return containingOneof; }
-
-    /**
-     * For extensions defined nested within message types, gets the outer
-     * type.  Not valid for non-extension fields.  For example, consider
-     * this {@code .proto} file:
-     * <pre>
-     *   message Foo {
-     *     extensions 1000 to max;
-     *   }
-     *   extend Foo {
-     *     optional int32 baz = 1234;
-     *   }
-     *   message Bar {
-     *     extend Foo {
-     *       optional int32 qux = 4321;
-     *     }
-     *   }
-     * </pre>
-     * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
-     * However, {@code baz}'s extension scope is {@code null} while
-     * {@code qux}'s extension scope is {@code Bar}.
-     */
-    public Descriptor getExtensionScope() {
-      if (!isExtension()) {
-        throw new UnsupportedOperationException(
-          "This field is not an extension.");
-      }
-      return extensionScope;
-    }
-
-    /** For embedded message and group fields, gets the field's type. */
-    public Descriptor getMessageType() {
-      if (getJavaType() != JavaType.MESSAGE) {
-        throw new UnsupportedOperationException(
-          "This field is not of message type.");
-      }
-      return messageType;
-    }
-
-    /** For enum fields, gets the field's type. */
-    public EnumDescriptor getEnumType() {
-      if (getJavaType() != JavaType.ENUM) {
-        throw new UnsupportedOperationException(
-          "This field is not of enum type.");
-      }
-      return enumType;
-    }
-
-    /**
-     * Compare with another {@code FieldDescriptor}.  This orders fields in
-     * "canonical" order, which simply means ascending order by field number.
-     * {@code other} must be a field of the same type -- i.e.
-     * {@code getContainingType()} must return the same {@code Descriptor} for
-     * both fields.
-     *
-     * @return negative, zero, or positive if {@code this} is less than,
-     *         equal to, or greater than {@code other}, respectively.
-     */
-    public int compareTo(final FieldDescriptor other) {
-      if (other.containingType != containingType) {
-        throw new IllegalArgumentException(
-          "FieldDescriptors can only be compared to other FieldDescriptors " +
-          "for fields of the same message type.");
-      }
-      return getNumber() - other.getNumber();
-    }
-
-    private final int index;
-
-    private FieldDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private final Descriptor extensionScope;
-
-    // Possibly initialized during cross-linking.
-    private Type type;
-    private Descriptor containingType;
-    private Descriptor messageType;
-    private OneofDescriptor containingOneof;
-    private EnumDescriptor enumType;
-    private Object defaultValue;
-
-    public enum Type {
-      DOUBLE  (JavaType.DOUBLE     ),
-      FLOAT   (JavaType.FLOAT      ),
-      INT64   (JavaType.LONG       ),
-      UINT64  (JavaType.LONG       ),
-      INT32   (JavaType.INT        ),
-      FIXED64 (JavaType.LONG       ),
-      FIXED32 (JavaType.INT        ),
-      BOOL    (JavaType.BOOLEAN    ),
-      STRING  (JavaType.STRING     ),
-      GROUP   (JavaType.MESSAGE    ),
-      MESSAGE (JavaType.MESSAGE    ),
-      BYTES   (JavaType.BYTE_STRING),
-      UINT32  (JavaType.INT        ),
-      ENUM    (JavaType.ENUM       ),
-      SFIXED32(JavaType.INT        ),
-      SFIXED64(JavaType.LONG       ),
-      SINT32  (JavaType.INT        ),
-      SINT64  (JavaType.LONG       );
-
-      Type(final JavaType javaType) {
-        this.javaType = javaType;
-      }
-
-      private JavaType javaType;
-
-      public FieldDescriptorProto.Type toProto() {
-        return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
-      }
-      public JavaType getJavaType() { return javaType; }
-
-      public static Type valueOf(final FieldDescriptorProto.Type type) {
-        return values()[type.getNumber() - 1];
-      }
-    }
-
-    static {
-      // Refuse to init if someone added a new declared type.
-      if (Type.values().length != FieldDescriptorProto.Type.values().length) {
-        throw new RuntimeException(
-          "descriptor.proto has a new declared type but Desrciptors.java " +
-          "wasn't updated.");
-      }
-    }
-
-    public enum JavaType {
-      INT(0),
-      LONG(0L),
-      FLOAT(0F),
-      DOUBLE(0D),
-      BOOLEAN(false),
-      STRING(""),
-      BYTE_STRING(ByteString.EMPTY),
-      ENUM(null),
-      MESSAGE(null);
-
-      JavaType(final Object defaultDefault) {
-        this.defaultDefault = defaultDefault;
-      }
-
-      /**
-       * The default default value for fields of this type, if it's a primitive
-       * type.  This is meant for use inside this file only, hence is private.
-       */
-      private final Object defaultDefault;
-    }
-
-    private FieldDescriptor(final FieldDescriptorProto proto,
-                            final FileDescriptor file,
-                            final Descriptor parent,
-                            final int index,
-                            final boolean isExtension)
-                     throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      fullName = computeFullName(file, parent, proto.getName());
-      this.file = file;
-
-      if (proto.hasType()) {
-        type = Type.valueOf(proto.getType());
-      }
-
-      if (getNumber() <= 0) {
-        throw new DescriptorValidationException(this,
-          "Field numbers must be positive integers.");
-      }
-
-      if (isExtension) {
-        if (!proto.hasExtendee()) {
-          throw new DescriptorValidationException(this,
-            "FieldDescriptorProto.extendee not set for extension field.");
-        }
-        containingType = null;  // Will be filled in when cross-linking
-        if (parent != null) {
-          extensionScope = parent;
-        } else {
-          extensionScope = null;
-        }
-
-        if (proto.hasOneofIndex()) {
-          throw new DescriptorValidationException(this,
-            "FieldDescriptorProto.oneof_index set for extension field.");
-        }
-        containingOneof = null;
-      } else {
-        if (proto.hasExtendee()) {
-          throw new DescriptorValidationException(this,
-            "FieldDescriptorProto.extendee set for non-extension field.");
-        }
-        containingType = parent;
-
-        if (proto.hasOneofIndex()) {
-          if (proto.getOneofIndex() < 0 ||
-              proto.getOneofIndex() >= parent.toProto().getOneofDeclCount()) {
-            throw new DescriptorValidationException(this,
-              "FieldDescriptorProto.oneof_index is out of range for type "
-              + parent.getName());
-          }
-          containingOneof = parent.getOneofs().get(proto.getOneofIndex());
-          containingOneof.fieldCount++;
-        } else {
-          containingOneof = null;
-        }
-        extensionScope = null;
-      }
-
-      file.pool.addSymbol(this);
-    }
-
-    /** Look up and cross-link all field types, etc. */
-    private void crossLink() throws DescriptorValidationException {
-      if (proto.hasExtendee()) {
-        final GenericDescriptor extendee =
-          file.pool.lookupSymbol(proto.getExtendee(), this,
-              DescriptorPool.SearchFilter.TYPES_ONLY);
-        if (!(extendee instanceof Descriptor)) {
-          throw new DescriptorValidationException(this,
-              '\"' + proto.getExtendee() + "\" is not a message type.");
-        }
-        containingType = (Descriptor)extendee;
-
-        if (!getContainingType().isExtensionNumber(getNumber())) {
-          throw new DescriptorValidationException(this,
-              '\"' + getContainingType().getFullName() +
-              "\" does not declare " + getNumber() +
-              " as an extension number.");
-        }
-      }
-
-      if (proto.hasTypeName()) {
-        final GenericDescriptor typeDescriptor =
-          file.pool.lookupSymbol(proto.getTypeName(), this,
-              DescriptorPool.SearchFilter.TYPES_ONLY);
-
-        if (!proto.hasType()) {
-          // Choose field type based on symbol.
-          if (typeDescriptor instanceof Descriptor) {
-            type = Type.MESSAGE;
-          } else if (typeDescriptor instanceof EnumDescriptor) {
-            type = Type.ENUM;
-          } else {
-            throw new DescriptorValidationException(this,
-                '\"' + proto.getTypeName() + "\" is not a type.");
-          }
-        }
-
-        if (getJavaType() == JavaType.MESSAGE) {
-          if (!(typeDescriptor instanceof Descriptor)) {
-            throw new DescriptorValidationException(this,
-                '\"' + proto.getTypeName() + "\" is not a message type.");
-          }
-          messageType = (Descriptor)typeDescriptor;
-
-          if (proto.hasDefaultValue()) {
-            throw new DescriptorValidationException(this,
-              "Messages can't have default values.");
-          }
-        } else if (getJavaType() == JavaType.ENUM) {
-          if (!(typeDescriptor instanceof EnumDescriptor)) {
-            throw new DescriptorValidationException(this,
-                '\"' + proto.getTypeName() + "\" is not an enum type.");
-          }
-          enumType = (EnumDescriptor)typeDescriptor;
-        } else {
-          throw new DescriptorValidationException(this,
-            "Field with primitive type has type_name.");
-        }
-      } else {
-        if (getJavaType() == JavaType.MESSAGE ||
-            getJavaType() == JavaType.ENUM) {
-          throw new DescriptorValidationException(this,
-            "Field with message or enum type missing type_name.");
-        }
-      }
-
-      // Only repeated primitive fields may be packed.
-      if (proto.getOptions().getPacked() && !isPackable()) {
-        throw new DescriptorValidationException(this,
-          "[packed = true] can only be specified for repeated primitive " +
-          "fields.");
-      }
-
-      // We don't attempt to parse the default value until here because for
-      // enums we need the enum type's descriptor.
-      if (proto.hasDefaultValue()) {
-        if (isRepeated()) {
-          throw new DescriptorValidationException(this,
-            "Repeated fields cannot have default values.");
-        }
-
-        try {
-          switch (getType()) {
-            case INT32:
-            case SINT32:
-            case SFIXED32:
-              defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
-              break;
-            case UINT32:
-            case FIXED32:
-              defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
-              break;
-            case INT64:
-            case SINT64:
-            case SFIXED64:
-              defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
-              break;
-            case UINT64:
-            case FIXED64:
-              defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
-              break;
-            case FLOAT:
-              if (proto.getDefaultValue().equals("inf")) {
-                defaultValue = Float.POSITIVE_INFINITY;
-              } else if (proto.getDefaultValue().equals("-inf")) {
-                defaultValue = Float.NEGATIVE_INFINITY;
-              } else if (proto.getDefaultValue().equals("nan")) {
-                defaultValue = Float.NaN;
-              } else {
-                defaultValue = Float.valueOf(proto.getDefaultValue());
-              }
-              break;
-            case DOUBLE:
-              if (proto.getDefaultValue().equals("inf")) {
-                defaultValue = Double.POSITIVE_INFINITY;
-              } else if (proto.getDefaultValue().equals("-inf")) {
-                defaultValue = Double.NEGATIVE_INFINITY;
-              } else if (proto.getDefaultValue().equals("nan")) {
-                defaultValue = Double.NaN;
-              } else {
-                defaultValue = Double.valueOf(proto.getDefaultValue());
-              }
-              break;
-            case BOOL:
-              defaultValue = Boolean.valueOf(proto.getDefaultValue());
-              break;
-            case STRING:
-              defaultValue = proto.getDefaultValue();
-              break;
-            case BYTES:
-              try {
-                defaultValue =
-                  TextFormat.unescapeBytes(proto.getDefaultValue());
-              } catch (TextFormat.InvalidEscapeSequenceException e) {
-                throw new DescriptorValidationException(this,
-                  "Couldn't parse default value: " + e.getMessage(), e);
-              }
-              break;
-            case ENUM:
-              defaultValue = enumType.findValueByName(proto.getDefaultValue());
-              if (defaultValue == null) {
-                throw new DescriptorValidationException(this,
-                  "Unknown enum default value: \"" +
-                  proto.getDefaultValue() + '\"');
-              }
-              break;
-            case MESSAGE:
-            case GROUP:
-              throw new DescriptorValidationException(this,
-                "Message type had default value.");
-          }
-        } catch (NumberFormatException e) {
-          throw new DescriptorValidationException(this, 
-              "Could not parse default value: \"" + 
-              proto.getDefaultValue() + '\"', e);
-        }
-      } else {
-        // Determine the default default for this field.
-        if (isRepeated()) {
-          defaultValue = Collections.emptyList();
-        } else {
-          switch (getJavaType()) {
-            case ENUM:
-              // We guarantee elsewhere that an enum type always has at least
-              // one possible value.
-              defaultValue = enumType.getValues().get(0);
-              break;
-            case MESSAGE:
-              defaultValue = null;
-              break;
-            default:
-              defaultValue = getJavaType().defaultDefault;
-              break;
-          }
-        }
-      }
-
-      if (!isExtension()) {
-        file.pool.addFieldByNumber(this);
-      }
-
-      if (containingType != null &&
-          containingType.getOptions().getMessageSetWireFormat()) {
-        if (isExtension()) {
-          if (!isOptional() || getType() != Type.MESSAGE) {
-            throw new DescriptorValidationException(this,
-              "Extensions of MessageSets must be optional messages.");
-          }
-        } else {
-          throw new DescriptorValidationException(this,
-            "MessageSets cannot have fields, only extensions.");
-        }
-      }
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final FieldDescriptorProto proto) {
-      this.proto = proto;
-    }
-
-    /**
-     * For internal use only.  This is to satisfy the FieldDescriptorLite
-     * interface.
-     */
-    public MessageLite.Builder internalMergeFrom(
-        MessageLite.Builder to, MessageLite from) {
-      // FieldDescriptors are only used with non-lite messages so we can just
-      // down-cast and call mergeFrom directly.
-      return ((Message.Builder) to).mergeFrom((Message) from);
-    }
-
-  }
-
-  // =================================================================
-
-  /** Describes an enum type. */
-  public static final class EnumDescriptor extends GenericDescriptor
-      implements Internal.EnumLiteMap<EnumValueDescriptor> {
-    /**
-     * Get the index of this descriptor within its parent.
-     * @see Descriptors.Descriptor#getIndex()
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public EnumDescriptorProto toProto() { return proto; }
-
-    /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /**
-     * Get the type's fully-qualified name.
-     * @see Descriptors.Descriptor#getFullName()
-     */
-    public String getFullName() { return fullName; }
-
-    /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** If this is a nested type, get the outer descriptor, otherwise null. */
-    public Descriptor getContainingType() { return containingType; }
-
-    /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
-    public EnumOptions getOptions() { return proto.getOptions(); }
-
-    /** Get a list of defined values for this enum. */
-    public List<EnumValueDescriptor> getValues() {
-      return Collections.unmodifiableList(Arrays.asList(values));
-    }
-
-    /**
-     * Find an enum value by name.
-     * @param name The unqualified name of the value (e.g. "FOO").
-     * @return the value's descriptor, or {@code null} if not found.
-     */
-    public EnumValueDescriptor findValueByName(final String name) {
-      final GenericDescriptor result =
-          file.pool.findSymbol(fullName + '.' + name);
-      if (result != null && result instanceof EnumValueDescriptor) {
-        return (EnumValueDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    /**
-     * Find an enum value by number.  If multiple enum values have the same
-     * number, this returns the first defined value with that number.
-     * @param number The value's number.
-     * @return the value's descriptor, or {@code null} if not found.
-     */
-    public EnumValueDescriptor findValueByNumber(final int number) {
-      return file.pool.enumValuesByNumber.get(
-        new DescriptorPool.DescriptorIntPair(this, number));
-    }
-
-    private final int index;
-    private EnumDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private final Descriptor containingType;
-    private EnumValueDescriptor[] values;
-
-    private EnumDescriptor(final EnumDescriptorProto proto,
-                           final FileDescriptor file,
-                           final Descriptor parent,
-                           final int index)
-                    throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      fullName = computeFullName(file, parent, proto.getName());
-      this.file = file;
-      containingType = parent;
-
-      if (proto.getValueCount() == 0) {
-        // We cannot allow enums with no values because this would mean there
-        // would be no valid default value for fields of this type.
-        throw new DescriptorValidationException(this,
-          "Enums must contain at least one value.");
-      }
-
-      values = new EnumValueDescriptor[proto.getValueCount()];
-      for (int i = 0; i < proto.getValueCount(); i++) {
-        values[i] = new EnumValueDescriptor(
-          proto.getValue(i), file, this, i);
-      }
-
-      file.pool.addSymbol(this);
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final EnumDescriptorProto proto) {
-      this.proto = proto;
-
-      for (int i = 0; i < values.length; i++) {
-        values[i].setProto(proto.getValue(i));
-      }
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * Describes one value within an enum type.  Note that multiple defined
-   * values may have the same number.  In generated Java code, all values
-   * with the same number after the first become aliases of the first.
-   * However, they still have independent EnumValueDescriptors.
-   */
-  public static final class EnumValueDescriptor extends GenericDescriptor
-      implements Internal.EnumLite {
-    /**
-     * Get the index of this descriptor within its parent.
-     * @see Descriptors.Descriptor#getIndex()
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public EnumValueDescriptorProto toProto() { return proto; }
-
-    /** Get the value's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /** Get the value's number. */
-    public int getNumber() { return proto.getNumber(); }
-    
-    @Override
-    public String toString() { return proto.getName(); }
-
-    /**
-     * Get the value's fully-qualified name.
-     * @see Descriptors.Descriptor#getFullName()
-     */
-    public String getFullName() { return fullName; }
-
-    /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** Get the value's enum type. */
-    public EnumDescriptor getType() { return type; }
-
-    /**
-     * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
-     */
-    public EnumValueOptions getOptions() { return proto.getOptions(); }
-
-    private final int index;
-    private EnumValueDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private final EnumDescriptor type;
-
-    private EnumValueDescriptor(final EnumValueDescriptorProto proto,
-                                final FileDescriptor file,
-                                final EnumDescriptor parent,
-                                final int index)
-                         throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      this.file = file;
-      type = parent;
-
-      fullName = parent.getFullName() + '.' + proto.getName();
-
-      file.pool.addSymbol(this);
-      file.pool.addEnumValueByNumber(this);
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final EnumValueDescriptorProto proto) {
-      this.proto = proto;
-    }
-  }
-
-  // =================================================================
-
-  /** Describes a service type. */
-  public static final class ServiceDescriptor extends GenericDescriptor {
-    /**
-     * Get the index of this descriptor within its parent.
-     * * @see Descriptors.Descriptor#getIndex()
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public ServiceDescriptorProto toProto() { return proto; }
-
-    /** Get the type's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /**
-     * Get the type's fully-qualified name.
-     * @see Descriptors.Descriptor#getFullName()
-     */
-    public String getFullName() { return fullName; }
-
-    /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
-    public ServiceOptions getOptions() { return proto.getOptions(); }
-
-    /** Get a list of methods for this service. */
-    public List<MethodDescriptor> getMethods() {
-      return Collections.unmodifiableList(Arrays.asList(methods));
-    }
-
-    /**
-     * Find a method by name.
-     * @param name The unqualified name of the method (e.g. "Foo").
-     * @return the method's descriptor, or {@code null} if not found.
-     */
-    public MethodDescriptor findMethodByName(final String name) {
-      final GenericDescriptor result =
-          file.pool.findSymbol(fullName + '.' + name);
-      if (result != null && result instanceof MethodDescriptor) {
-        return (MethodDescriptor)result;
-      } else {
-        return null;
-      }
-    }
-
-    private final int index;
-    private ServiceDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private MethodDescriptor[] methods;
-
-    private ServiceDescriptor(final ServiceDescriptorProto proto,
-                              final FileDescriptor file,
-                              final int index)
-                       throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      fullName = computeFullName(file, null, proto.getName());
-      this.file = file;
-
-      methods = new MethodDescriptor[proto.getMethodCount()];
-      for (int i = 0; i < proto.getMethodCount(); i++) {
-        methods[i] = new MethodDescriptor(
-          proto.getMethod(i), file, this, i);
-      }
-
-      file.pool.addSymbol(this);
-    }
-
-    private void crossLink() throws DescriptorValidationException {
-      for (final MethodDescriptor method : methods) {
-        method.crossLink();
-      }
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final ServiceDescriptorProto proto) {
-      this.proto = proto;
-
-      for (int i = 0; i < methods.length; i++) {
-        methods[i].setProto(proto.getMethod(i));
-      }
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * Describes one method within a service type.
-   */
-  public static final class MethodDescriptor extends GenericDescriptor {
-    /**
-     * Get the index of this descriptor within its parent.
-     * * @see Descriptors.Descriptor#getIndex()
-     */
-    public int getIndex() { return index; }
-
-    /** Convert the descriptor to its protocol message representation. */
-    public MethodDescriptorProto toProto() { return proto; }
-
-    /** Get the method's unqualified name. */
-    public String getName() { return proto.getName(); }
-
-    /**
-     * Get the method's fully-qualified name.
-     * @see Descriptors.Descriptor#getFullName()
-     */
-    public String getFullName() { return fullName; }
-
-    /** Get the {@link FileDescriptor} containing this descriptor. */
-    public FileDescriptor getFile() { return file; }
-
-    /** Get the method's service type. */
-    public ServiceDescriptor getService() { return service; }
-
-    /** Get the method's input type. */
-    public Descriptor getInputType() { return inputType; }
-
-    /** Get the method's output type. */
-    public Descriptor getOutputType() { return outputType; }
-
-    /**
-     * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
-     */
-    public MethodOptions getOptions() { return proto.getOptions(); }
-
-    private final int index;
-    private MethodDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-    private final ServiceDescriptor service;
-
-    // Initialized during cross-linking.
-    private Descriptor inputType;
-    private Descriptor outputType;
-
-    private MethodDescriptor(final MethodDescriptorProto proto,
-                             final FileDescriptor file,
-                             final ServiceDescriptor parent,
-                             final int index)
-                      throws DescriptorValidationException {
-      this.index = index;
-      this.proto = proto;
-      this.file = file;
-      service = parent;
-
-      fullName = parent.getFullName() + '.' + proto.getName();
-
-      file.pool.addSymbol(this);
-    }
-
-    private void crossLink() throws DescriptorValidationException {
-      final GenericDescriptor input =
-        file.pool.lookupSymbol(proto.getInputType(), this,
-            DescriptorPool.SearchFilter.TYPES_ONLY);
-      if (!(input instanceof Descriptor)) {
-        throw new DescriptorValidationException(this,
-            '\"' + proto.getInputType() + "\" is not a message type.");
-      }
-      inputType = (Descriptor)input;
-
-      final GenericDescriptor output =
-        file.pool.lookupSymbol(proto.getOutputType(), this,
-            DescriptorPool.SearchFilter.TYPES_ONLY);
-      if (!(output instanceof Descriptor)) {
-        throw new DescriptorValidationException(this,
-            '\"' + proto.getOutputType() + "\" is not a message type.");
-      }
-      outputType = (Descriptor)output;
-    }
-
-    /** See {@link FileDescriptor#setProto}. */
-    private void setProto(final MethodDescriptorProto proto) {
-      this.proto = proto;
-    }
-  }
-
-  // =================================================================
-
-  private static String computeFullName(final FileDescriptor file,
-                                        final Descriptor parent,
-                                        final String name) {
-    if (parent != null) {
-      return parent.getFullName() + '.' + name;
-    } else if (file.getPackage().length() > 0) {
-      return file.getPackage() + '.' + name;
-    } else {
-      return name;
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * All descriptors implement this to make it easier to implement tools like
-   * {@code DescriptorPool}.<p>
-   *
-   * This class is public so that the methods it exposes can be called from
-   * outside of this package. However, it should only be subclassed from
-   * nested classes of Descriptors.
-   */
-  public abstract static class GenericDescriptor {
-    public abstract Message toProto();
-    public abstract String getName();
-    public abstract String getFullName();
-    public abstract FileDescriptor getFile();
-  }
-
-  /**
-   * Thrown when building descriptors fails because the source DescriptorProtos
-   * are not valid.
-   */
-  public static class DescriptorValidationException extends Exception {
-    private static final long serialVersionUID = 5750205775490483148L;
-
-    /** Gets the full name of the descriptor where the error occurred. */
-    public String getProblemSymbolName() { return name; }
-
-    /**
-     * Gets the protocol message representation of the invalid descriptor.
-     */
-    public Message getProblemProto() { return proto; }
-
-    /**
-     * Gets a human-readable description of the error.
-     */
-    public String getDescription() { return description; }
-
-    private final String name;
-    private final Message proto;
-    private final String description;
-
-    private DescriptorValidationException(
-        final GenericDescriptor problemDescriptor,
-        final String description) {
-      super(problemDescriptor.getFullName() + ": " + description);
-
-      // Note that problemDescriptor may be partially uninitialized, so we
-      // don't want to expose it directly to the user.  So, we only provide
-      // the name and the original proto.
-      name = problemDescriptor.getFullName();
-      proto = problemDescriptor.toProto();
-      this.description = description;
-    }
-
-    private DescriptorValidationException(
-        final GenericDescriptor problemDescriptor,
-        final String description,
-        final Throwable cause) {
-      this(problemDescriptor, description);
-      initCause(cause);
-    }
-
-    private DescriptorValidationException(
-        final FileDescriptor problemDescriptor,
-        final String description) {
-      super(problemDescriptor.getName() + ": " + description);
-
-      // Note that problemDescriptor may be partially uninitialized, so we
-      // don't want to expose it directly to the user.  So, we only provide
-      // the name and the original proto.
-      name = problemDescriptor.getName();
-      proto = problemDescriptor.toProto();
-      this.description = description;
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * A private helper class which contains lookup tables containing all the
-   * descriptors defined in a particular file.
-   */
-  private static final class DescriptorPool {
-    
-    /** Defines what subclass of descriptors to search in the descriptor pool. 
-     */
-    enum SearchFilter {
-      TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
-    }
-    
-    DescriptorPool(final FileDescriptor[] dependencies,
-        boolean allowUnknownDependencies) {
-      this.dependencies = new HashSet<FileDescriptor>();
-      this.allowUnknownDependencies = allowUnknownDependencies;
-
-      for (int i = 0; i < dependencies.length; i++) {
-        this.dependencies.add(dependencies[i]);
-        importPublicDependencies(dependencies[i]);
-      }
-
-      for (final FileDescriptor dependency : this.dependencies) {
-        try {
-          addPackage(dependency.getPackage(), dependency);
-        } catch (DescriptorValidationException e) {
-          // Can't happen, because addPackage() only fails when the name
-          // conflicts with a non-package, but we have not yet added any
-          // non-packages at this point.
-          assert false;
-        }
-      }
-    }
-
-    /** Find and put public dependencies of the file into dependencies set.*/
-    private void importPublicDependencies(final FileDescriptor file) {
-      for (FileDescriptor dependency : file.getPublicDependencies()) {
-        if (dependencies.add(dependency)) {
-          importPublicDependencies(dependency);
-        }
-      }
-    }
-
-    private final Set<FileDescriptor> dependencies;
-    private boolean allowUnknownDependencies;
-
-    private final Map<String, GenericDescriptor> descriptorsByName =
-      new HashMap<String, GenericDescriptor>();
-    private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
-      new HashMap<DescriptorIntPair, FieldDescriptor>();
-    private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
-        = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
-
-    /** Find a generic descriptor by fully-qualified name. */
-    GenericDescriptor findSymbol(final String fullName) {
-      return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
-    }
-    
-    /** Find a descriptor by fully-qualified name and given option to only 
-     * search valid field type descriptors. 
-     */
-    GenericDescriptor findSymbol(final String fullName,
-                                 final SearchFilter filter) {
-      GenericDescriptor result = descriptorsByName.get(fullName);
-      if (result != null) {
-        if ((filter==SearchFilter.ALL_SYMBOLS) ||
-            ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
-            ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
-          return result;
-        }
-      }
-
-      for (final FileDescriptor dependency : dependencies) {
-        result = dependency.pool.descriptorsByName.get(fullName);
-        if (result != null) {
-          if ((filter==SearchFilter.ALL_SYMBOLS) ||
-              ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
-              ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
-            return result;
-          }
-        }
-      }
-
-      return null;
-    }
-
-    /** Checks if the descriptor is a valid type for a message field. */
-    boolean isType(GenericDescriptor descriptor) {
-      return (descriptor instanceof Descriptor) || 
-        (descriptor instanceof EnumDescriptor);
-    }
-    
-    /** Checks if the descriptor is a valid namespace type. */
-    boolean isAggregate(GenericDescriptor descriptor) {
-      return (descriptor instanceof Descriptor) || 
-        (descriptor instanceof EnumDescriptor) || 
-        (descriptor instanceof PackageDescriptor) || 
-        (descriptor instanceof ServiceDescriptor);
-    }
-       
-    /**
-     * Look up a type descriptor by name, relative to some other descriptor.
-     * The name may be fully-qualified (with a leading '.'),
-     * partially-qualified, or unqualified.  C++-like name lookup semantics
-     * are used to search for the matching descriptor.
-     */
-    GenericDescriptor lookupSymbol(final String name,
-                                   final GenericDescriptor relativeTo,
-                                   final DescriptorPool.SearchFilter filter)
-                            throws DescriptorValidationException {
-      // TODO(kenton):  This could be optimized in a number of ways.
-
-      GenericDescriptor result;
-      String fullname;
-      if (name.startsWith(".")) {
-        // Fully-qualified name.
-        fullname = name.substring(1);
-        result = findSymbol(fullname, filter);
-      } else {
-        // If "name" is a compound identifier, we want to search for the
-        // first component of it, then search within it for the rest.
-        // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
-        // defined in multiple parent scopes, we only want to find "Bar.baz" in
-        // the innermost one.  E.g., the following should produce an error:
-        //   message Bar { message Baz {} }
-        //   message Foo {
-        //     message Bar {
-        //     }
-        //     optional Bar.Baz baz = 1;
-        //   }
-        // So, we look for just "Foo" first, then look for "Bar.baz" within it
-        // if found.
-        final int firstPartLength = name.indexOf('.');
-        final String firstPart;
-        if (firstPartLength == -1) {
-          firstPart = name;
-        } else {
-          firstPart = name.substring(0, firstPartLength);
-        }
-
-        // We will search each parent scope of "relativeTo" looking for the
-        // symbol.
-        final StringBuilder scopeToTry =
-            new StringBuilder(relativeTo.getFullName());
-
-        while (true) {
-          // Chop off the last component of the scope.
-          final int dotpos = scopeToTry.lastIndexOf(".");
-          if (dotpos == -1) {
-            fullname = name;
-            result = findSymbol(name, filter);
-            break;
-          } else {
-            scopeToTry.setLength(dotpos + 1);
-
-            // Append firstPart and try to find
-            scopeToTry.append(firstPart);
-            result = findSymbol(scopeToTry.toString(), 
-                DescriptorPool.SearchFilter.AGGREGATES_ONLY);
-
-            if (result != null) {
-              if (firstPartLength != -1) {
-                // We only found the first part of the symbol.  Now look for
-                // the whole thing.  If this fails, we *don't* want to keep
-                // searching parent scopes.
-                scopeToTry.setLength(dotpos + 1);
-                scopeToTry.append(name);
-                result = findSymbol(scopeToTry.toString(), filter);
-              }
-              fullname = scopeToTry.toString();
-              break;
-            }
-
-            // Not found.  Remove the name so we can try again.
-            scopeToTry.setLength(dotpos);
-          }
-        }
-      }
-
-      if (result == null) {
-        if (allowUnknownDependencies && filter == SearchFilter.TYPES_ONLY) {
-          logger.warning("The descriptor for message type \"" + name +
-              "\" can not be found and a placeholder is created for it");
-          // We create a dummy message descriptor here regardless of the
-          // expected type. If the type should be message, this dummy
-          // descriptor will work well and if the type should be enum, a
-          // DescriptorValidationException will be thrown latter. In either
-          // case, the code works as expected: we allow unknown message types
-          // but not unknwon enum types.
-          result = new Descriptor(fullname);
-          // Add the placeholder file as a dependency so we can find the
-          // placeholder symbol when resolving other references.
-          this.dependencies.add(result.getFile());
-          return result;
-        } else {
-          throw new DescriptorValidationException(relativeTo,
-              '\"' + name + "\" is not defined.");
-        }
-      } else {
-        return result;
-      }
-    }
-
-    /**
-     * Adds a symbol to the symbol table.  If a symbol with the same name
-     * already exists, throws an error.
-     */
-    void addSymbol(final GenericDescriptor descriptor)
-            throws DescriptorValidationException {
-      validateSymbolName(descriptor);
-
-      final String fullName = descriptor.getFullName();
-      final int dotpos = fullName.lastIndexOf('.');
-
-      final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
-      if (old != null) {
-        descriptorsByName.put(fullName, old);
-
-        if (descriptor.getFile() == old.getFile()) {
-          if (dotpos == -1) {
-            throw new DescriptorValidationException(descriptor,
-                '\"' + fullName + "\" is already defined.");
-          } else {
-            throw new DescriptorValidationException(descriptor,
-                '\"' + fullName.substring(dotpos + 1) +
-              "\" is already defined in \"" +
-              fullName.substring(0, dotpos) + "\".");
-          }
-        } else {
-          throw new DescriptorValidationException(descriptor,
-              '\"' + fullName + "\" is already defined in file \"" +
-            old.getFile().getName() + "\".");
-        }
-      }
-    }
-
-    /**
-     * Represents a package in the symbol table.  We use PackageDescriptors
-     * just as placeholders so that someone cannot define, say, a message type
-     * that has the same name as an existing package.
-     */
-    private static final class PackageDescriptor extends GenericDescriptor {
-      public Message toProto()        { return file.toProto(); }
-      public String getName()         { return name;           }
-      public String getFullName()     { return fullName;       }
-      public FileDescriptor getFile() { return file;           }
-
-      PackageDescriptor(final String name, final String fullName,
-                        final FileDescriptor file) {
-        this.file = file;
-        this.fullName = fullName;
-        this.name = name;
-      }
-
-      private final String name;
-      private final String fullName;
-      private final FileDescriptor file;
-    }
-
-    /**
-     * Adds a package to the symbol tables.  If a package by the same name
-     * already exists, that is fine, but if some other kind of symbol exists
-     * under the same name, an exception is thrown.  If the package has
-     * multiple components, this also adds the parent package(s).
-     */
-    void addPackage(final String fullName, final FileDescriptor file)
-             throws DescriptorValidationException {
-      final int dotpos = fullName.lastIndexOf('.');
-      final String name;
-      if (dotpos == -1) {
-        name = fullName;
-      } else {
-        addPackage(fullName.substring(0, dotpos), file);
-        name = fullName.substring(dotpos + 1);
-      }
-
-      final GenericDescriptor old =
-        descriptorsByName.put(fullName,
-          new PackageDescriptor(name, fullName, file));
-      if (old != null) {
-        descriptorsByName.put(fullName, old);
-        if (!(old instanceof PackageDescriptor)) {
-          throw new DescriptorValidationException(file,
-              '\"' + name + "\" is already defined (as something other than a "
-              + "package) in file \"" + old.getFile().getName() + "\".");
-        }
-      }
-    }
-
-    /** A (GenericDescriptor, int) pair, used as a map key. */
-    private static final class DescriptorIntPair {
-      private final GenericDescriptor descriptor;
-      private final int number;
-
-      DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
-        this.descriptor = descriptor;
-        this.number = number;
-      }
-
-      @Override
-      public int hashCode() {
-        return descriptor.hashCode() * ((1 << 16) - 1) + number;
-      }
-      @Override
-      public boolean equals(final Object obj) {
-        if (!(obj instanceof DescriptorIntPair)) {
-          return false;
-        }
-        final DescriptorIntPair other = (DescriptorIntPair)obj;
-        return descriptor == other.descriptor && number == other.number;
-      }
-    }
-
-    /**
-     * Adds a field to the fieldsByNumber table.  Throws an exception if a
-     * field with the same containing type and number already exists.
-     */
-    void addFieldByNumber(final FieldDescriptor field)
-                   throws DescriptorValidationException {
-      final DescriptorIntPair key =
-        new DescriptorIntPair(field.getContainingType(), field.getNumber());
-      final FieldDescriptor old = fieldsByNumber.put(key, field);
-      if (old != null) {
-        fieldsByNumber.put(key, old);
-        throw new DescriptorValidationException(field,
-          "Field number " + field.getNumber() +
-          " has already been used in \"" +
-          field.getContainingType().getFullName() +
-          "\" by field \"" + old.getName() + "\".");
-      }
-    }
-
-    /**
-     * Adds an enum value to the enumValuesByNumber table.  If an enum value
-     * with the same type and number already exists, does nothing.  (This is
-     * allowed; the first value define with the number takes precedence.)
-     */
-    void addEnumValueByNumber(final EnumValueDescriptor value) {
-      final DescriptorIntPair key =
-        new DescriptorIntPair(value.getType(), value.getNumber());
-      final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
-      if (old != null) {
-        enumValuesByNumber.put(key, old);
-        // Not an error:  Multiple enum values may have the same number, but
-        // we only want the first one in the map.
-      }
-    }
-
-    /**
-     * Verifies that the descriptor's name is valid (i.e. it contains only
-     * letters, digits, and underscores, and does not start with a digit).
-     */
-    static void validateSymbolName(final GenericDescriptor descriptor)
-                                   throws DescriptorValidationException {
-      final String name = descriptor.getName();
-      if (name.length() == 0) {
-        throw new DescriptorValidationException(descriptor, "Missing name.");
-      } else {
-        boolean valid = true;
-        for (int i = 0; i < name.length(); i++) {
-          final char c = name.charAt(i);
-          // Non-ASCII characters are not valid in protobuf identifiers, even
-          // if they are letters or digits.
-          if (c >= 128) {
-            valid = false;
-          }
-          // First character must be letter or _.  Subsequent characters may
-          // be letters, numbers, or digits.
-          if (Character.isLetter(c) || c == '_' ||
-              (Character.isDigit(c) && i > 0)) {
-            // Valid
-          } else {
-            valid = false;
-          }
-        }
-        if (!valid) {
-          throw new DescriptorValidationException(descriptor,
-              '\"' + name + "\" is not a valid identifier.");
-        }
-      }
-    }
-  }
-
-  /** Describes an oneof of a message type. */
-  public static final class OneofDescriptor {
-    /** Get the index of this descriptor within its parent. */
-    public int getIndex() { return index; }
-
-    public String getName() { return proto.getName(); }
-
-    public FileDescriptor getFile() { return file; }
-
-    public String getFullName() { return fullName; }
-
-    public Descriptor getContainingType() { return containingType; }
-
-    public int getFieldCount() { return fieldCount; }
-
-    public FieldDescriptor getField(int index) {
-      return fields[index];
-    }
-
-    private OneofDescriptor(final OneofDescriptorProto proto,
-                            final FileDescriptor file,
-                            final Descriptor parent,
-                            final int index)
-                     throws DescriptorValidationException {
-      this.proto = proto;
-      fullName = computeFullName(file, parent, proto.getName());
-      this.file = file;
-      this.index = index;
-
-      containingType = parent;
-      fieldCount = 0;
-    }
-
-    private final int index;
-    private OneofDescriptorProto proto;
-    private final String fullName;
-    private final FileDescriptor file;
-
-    private Descriptor containingType;
-    private int fieldCount;
-    private FieldDescriptor[] fields;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java
deleted file mode 100644
index c9ce667..0000000
--- a/java/src/main/java/com/google/protobuf/DynamicMessage.java
+++ /dev/null
@@ -1,622 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.EnumValueDescriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An implementation of {@link Message} that can represent arbitrary types,
- * given a {@link Descriptors.Descriptor}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class DynamicMessage extends AbstractMessage {
-  private final Descriptor type;
-  private final FieldSet<FieldDescriptor> fields;
-  private final FieldDescriptor[] oneofCases;
-  private final UnknownFieldSet unknownFields;
-  private int memoizedSize = -1;
-
-  /**
-   * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
-   * oneofCases stores the FieldDescriptor for each oneof to indicate
-   * which field is set. Caller should make sure the array is immutable.
-   *
-   * This contructor is package private and will be used in
-   * {@code DynamicMutableMessage} to convert a mutable message to an immutable
-   * message.
-   */
-  DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
-                 FieldDescriptor[] oneofCases,
-                 UnknownFieldSet unknownFields) {
-    this.type = type;
-    this.fields = fields;
-    this.oneofCases = oneofCases;
-    this.unknownFields = unknownFields;
-  }
-
-  /**
-   * Get a {@code DynamicMessage} representing the default instance of the
-   * given type.
-   */
-  public static DynamicMessage getDefaultInstance(Descriptor type) {
-    int oneofDeclCount = type.toProto().getOneofDeclCount();
-    FieldDescriptor[] oneofCases = new FieldDescriptor[oneofDeclCount];
-    return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
-                              oneofCases,
-                              UnknownFieldSet.getDefaultInstance());
-  }
-
-
-  /** Parse a message of the given type from the given input stream. */
-  public static DynamicMessage parseFrom(Descriptor type,
-                                         CodedInputStream input)
-                                         throws IOException {
-    return newBuilder(type).mergeFrom(input).buildParsed();
-  }
-
-  /** Parse a message of the given type from the given input stream. */
-  public static DynamicMessage parseFrom(
-      Descriptor type,
-      CodedInputStream input,
-      ExtensionRegistry extensionRegistry)
-      throws IOException {
-    return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
-  }
-
-  /** Parse {@code data} as a message of the given type and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, ByteString data)
-                                         throws InvalidProtocolBufferException {
-    return newBuilder(type).mergeFrom(data).buildParsed();
-  }
-
-  /** Parse {@code data} as a message of the given type and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, ByteString data,
-                                         ExtensionRegistry extensionRegistry)
-                                         throws InvalidProtocolBufferException {
-    return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
-  }
-
-  /** Parse {@code data} as a message of the given type and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, byte[] data)
-                                         throws InvalidProtocolBufferException {
-    return newBuilder(type).mergeFrom(data).buildParsed();
-  }
-
-  /** Parse {@code data} as a message of the given type and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, byte[] data,
-                                         ExtensionRegistry extensionRegistry)
-                                         throws InvalidProtocolBufferException {
-    return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
-  }
-
-  /** Parse a message of the given type from {@code input} and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, InputStream input)
-                                         throws IOException {
-    return newBuilder(type).mergeFrom(input).buildParsed();
-  }
-
-  /** Parse a message of the given type from {@code input} and return it. */
-  public static DynamicMessage parseFrom(Descriptor type, InputStream input,
-                                         ExtensionRegistry extensionRegistry)
-                                         throws IOException {
-    return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
-  }
-
-  /** Construct a {@link Message.Builder} for the given type. */
-  public static Builder newBuilder(Descriptor type) {
-    return new Builder(type);
-  }
-
-  /**
-   * Construct a {@link Message.Builder} for a message of the same type as
-   * {@code prototype}, and initialize it with {@code prototype}'s contents.
-   */
-  public static Builder newBuilder(Message prototype) {
-    return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
-  }
-
-  // -----------------------------------------------------------------
-  // Implementation of Message interface.
-
-  public Descriptor getDescriptorForType() {
-    return type;
-  }
-
-  public DynamicMessage getDefaultInstanceForType() {
-    return getDefaultInstance(type);
-  }
-
-  public Map<FieldDescriptor, Object> getAllFields() {
-    return fields.getAllFields();
-  }
-
-  public boolean hasOneof(OneofDescriptor oneof) {
-    verifyOneofContainingType(oneof);
-    FieldDescriptor field = oneofCases[oneof.getIndex()];
-    if (field == null) {
-      return false;
-    }
-    return true;
-  }
-
-  public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
-    verifyOneofContainingType(oneof);
-    return oneofCases[oneof.getIndex()];
-  }
-
-  public boolean hasField(FieldDescriptor field) {
-    verifyContainingType(field);
-    return fields.hasField(field);
-  }
-
-  public Object getField(FieldDescriptor field) {
-    verifyContainingType(field);
-    Object result = fields.getField(field);
-    if (result == null) {
-      if (field.isRepeated()) {
-        result = Collections.emptyList();
-      } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        result = getDefaultInstance(field.getMessageType());
-      } else {
-        result = field.getDefaultValue();
-      }
-    }
-    return result;
-  }
-
-  public int getRepeatedFieldCount(FieldDescriptor field) {
-    verifyContainingType(field);
-    return fields.getRepeatedFieldCount(field);
-  }
-
-  public Object getRepeatedField(FieldDescriptor field, int index) {
-    verifyContainingType(field);
-    return fields.getRepeatedField(field, index);
-  }
-
-  public UnknownFieldSet getUnknownFields() {
-    return unknownFields;
-  }
-
-  static boolean isInitialized(Descriptor type,
-                               FieldSet<FieldDescriptor> fields) {
-    // Check that all required fields are present.
-    for (final FieldDescriptor field : type.getFields()) {
-      if (field.isRequired()) {
-        if (!fields.hasField(field)) {
-          return false;
-        }
-      }
-    }
-
-    // Check that embedded messages are initialized.
-    return fields.isInitialized();
-  }
-
-  @Override
-  public boolean isInitialized() {
-    return isInitialized(type, fields);
-  }
-
-  @Override
-  public void writeTo(CodedOutputStream output) throws IOException {
-    if (type.getOptions().getMessageSetWireFormat()) {
-      fields.writeMessageSetTo(output);
-      unknownFields.writeAsMessageSetTo(output);
-    } else {
-      fields.writeTo(output);
-      unknownFields.writeTo(output);
-    }
-  }
-
-  @Override
-  public int getSerializedSize() {
-    int size = memoizedSize;
-    if (size != -1) return size;
-
-    if (type.getOptions().getMessageSetWireFormat()) {
-      size = fields.getMessageSetSerializedSize();
-      size += unknownFields.getSerializedSizeAsMessageSet();
-    } else {
-      size = fields.getSerializedSize();
-      size += unknownFields.getSerializedSize();
-    }
-
-    memoizedSize = size;
-    return size;
-  }
-
-  public Builder newBuilderForType() {
-    return new Builder(type);
-  }
-
-  public Builder toBuilder() {
-    return newBuilderForType().mergeFrom(this);
-  }
-
-  public Parser<DynamicMessage> getParserForType() {
-    return new AbstractParser<DynamicMessage>() {
-      public DynamicMessage parsePartialFrom(
-          CodedInputStream input,
-          ExtensionRegistryLite extensionRegistry)
-          throws InvalidProtocolBufferException {
-        Builder builder = newBuilder(type);
-        try {
-          builder.mergeFrom(input, extensionRegistry);
-        } catch (InvalidProtocolBufferException e) {
-          throw e.setUnfinishedMessage(builder.buildPartial());
-        } catch (IOException e) {
-          throw new InvalidProtocolBufferException(e.getMessage())
-              .setUnfinishedMessage(builder.buildPartial());
-        }
-        return builder.buildPartial();
-      }
-    };
-  }
-
-  /** Verifies that the field is a field of this message. */
-  private void verifyContainingType(FieldDescriptor field) {
-    if (field.getContainingType() != type) {
-      throw new IllegalArgumentException(
-        "FieldDescriptor does not match message type.");
-    }
-  }
-
-  /** Verifies that the oneof is an oneof of this message. */
-  private void verifyOneofContainingType(OneofDescriptor oneof) {
-    if (oneof.getContainingType() != type) {
-      throw new IllegalArgumentException(
-        "OneofDescriptor does not match message type.");
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * Builder for {@link DynamicMessage}s.
-   */
-  public static final class Builder extends AbstractMessage.Builder<Builder> {
-    private final Descriptor type;
-    private FieldSet<FieldDescriptor> fields;
-    private final FieldDescriptor[] oneofCases;
-    private UnknownFieldSet unknownFields;
-
-    /** Construct a {@code Builder} for the given type. */
-    private Builder(Descriptor type) {
-      this.type = type;
-      this.fields = FieldSet.newFieldSet();
-      this.unknownFields = UnknownFieldSet.getDefaultInstance();
-      this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
-    }
-
-    // ---------------------------------------------------------------
-    // Implementation of Message.Builder interface.
-
-    @Override
-    public Builder clear() {
-      if (fields.isImmutable()) {
-        fields = FieldSet.newFieldSet();
-      } else {
-        fields.clear();
-      }
-      unknownFields = UnknownFieldSet.getDefaultInstance();
-      return this;
-    }
-
-    @Override
-    public Builder mergeFrom(Message other) {
-      if (other instanceof DynamicMessage) {
-        // This should be somewhat faster than calling super.mergeFrom().
-        DynamicMessage otherDynamicMessage = (DynamicMessage) other;
-        if (otherDynamicMessage.type != type) {
-          throw new IllegalArgumentException(
-            "mergeFrom(Message) can only merge messages of the same type.");
-        }
-        ensureIsMutable();
-        fields.mergeFrom(otherDynamicMessage.fields);
-        mergeUnknownFields(otherDynamicMessage.unknownFields);
-        for (int i = 0; i < oneofCases.length; i++) {
-          if (oneofCases[i] == null) {
-            oneofCases[i] = otherDynamicMessage.oneofCases[i];
-          } else {
-            if ((otherDynamicMessage.oneofCases[i] != null)
-                && (oneofCases[i] != otherDynamicMessage.oneofCases[i])) {
-              fields.clearField(oneofCases[i]);
-              oneofCases[i] = otherDynamicMessage.oneofCases[i];
-            }
-          }
-        }
-        return this;
-      } else {
-        return super.mergeFrom(other);
-      }
-    }
-
-    public DynamicMessage build() {
-      if (!isInitialized()) {
-        throw newUninitializedMessageException(
-          new DynamicMessage(type, fields,
-              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
-      }
-      return buildPartial();
-    }
-
-    /**
-     * Helper for DynamicMessage.parseFrom() methods to call.  Throws
-     * {@link InvalidProtocolBufferException} instead of
-     * {@link UninitializedMessageException}.
-     */
-    private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
-      if (!isInitialized()) {
-        throw newUninitializedMessageException(
-          new DynamicMessage(type, fields,
-              java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields))
-          .asInvalidProtocolBufferException();
-      }
-      return buildPartial();
-    }
-
-    public DynamicMessage buildPartial() {
-      fields.makeImmutable();
-      DynamicMessage result =
-        new DynamicMessage(type, fields,
-            java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
-      return result;
-    }
-
-    @Override
-    public Builder clone() {
-      Builder result = new Builder(type);
-      result.fields.mergeFrom(fields);
-      result.mergeUnknownFields(unknownFields);
-      System.arraycopy(oneofCases, 0, result.oneofCases, 0 , oneofCases.length);
-      return result;
-    }
-
-    public boolean isInitialized() {
-      return DynamicMessage.isInitialized(type, fields);
-    }
-
-    public Descriptor getDescriptorForType() {
-      return type;
-    }
-
-    public DynamicMessage getDefaultInstanceForType() {
-      return getDefaultInstance(type);
-    }
-
-    public Map<FieldDescriptor, Object> getAllFields() {
-      return fields.getAllFields();
-    }
-
-    public Builder newBuilderForField(FieldDescriptor field) {
-      verifyContainingType(field);
-
-      if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
-        throw new IllegalArgumentException(
-          "newBuilderForField is only valid for fields with message type.");
-      }
-
-      return new Builder(field.getMessageType());
-    }
-
-    public boolean hasOneof(OneofDescriptor oneof) {
-      verifyOneofContainingType(oneof);
-      FieldDescriptor field = oneofCases[oneof.getIndex()];
-      if (field == null) {
-        return false;
-      }
-      return true;
-    }
-
-    public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) {
-      verifyOneofContainingType(oneof);
-      return oneofCases[oneof.getIndex()];
-    }
-
-    public Builder clearOneof(OneofDescriptor oneof) {
-      verifyOneofContainingType(oneof);
-      FieldDescriptor field = oneofCases[oneof.getIndex()];
-      if (field != null) {
-        clearField(field);
-      }
-      return this;
-    }
-
-    public boolean hasField(FieldDescriptor field) {
-      verifyContainingType(field);
-      return fields.hasField(field);
-    }
-
-    public Object getField(FieldDescriptor field) {
-      verifyContainingType(field);
-      Object result = fields.getField(field);
-      if (result == null) {
-        if (field.isRepeated()) {
-          result = Collections.emptyList();
-        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-          result = getDefaultInstance(field.getMessageType());
-        } else {
-          result = field.getDefaultValue();
-        }
-      }
-      return result;
-    }
-
-    public Builder setField(FieldDescriptor field, Object value) {
-      verifyContainingType(field);
-      ensureIsMutable();
-      // TODO(xiaofeng): This check should really be put in FieldSet.setField()
-      // where all other such checks are done. However, currently
-      // FieldSet.setField() permits Integer value for enum fields probably
-      // because of some internal features we support. Should figure it out
-      // and move this check to a more appropriate place.
-      if (field.getType() == FieldDescriptor.Type.ENUM) {
-        ensureEnumValueDescriptor(field, value);
-      }
-      OneofDescriptor oneofDescriptor = field.getContainingOneof();
-      if (oneofDescriptor != null) {
-        int index = oneofDescriptor.getIndex();
-        FieldDescriptor oldField = oneofCases[index];
-        if ((oldField != null) && (oldField != field)) {
-          fields.clearField(oldField);
-        }
-        oneofCases[index] = field;
-      }
-      fields.setField(field, value);
-      return this;
-    }
-
-    public Builder clearField(FieldDescriptor field) {
-      verifyContainingType(field);
-      ensureIsMutable();
-      OneofDescriptor oneofDescriptor = field.getContainingOneof();
-      if (oneofDescriptor != null) {
-        int index = oneofDescriptor.getIndex();
-        if (oneofCases[index] == field) {
-          oneofCases[index] = null;
-        }
-      }
-      fields.clearField(field);
-      return this;
-    }
-
-    public int getRepeatedFieldCount(FieldDescriptor field) {
-      verifyContainingType(field);
-      return fields.getRepeatedFieldCount(field);
-    }
-
-    public Object getRepeatedField(FieldDescriptor field, int index) {
-      verifyContainingType(field);
-      return fields.getRepeatedField(field, index);
-    }
-
-    public Builder setRepeatedField(FieldDescriptor field,
-                                    int index, Object value) {
-      verifyContainingType(field);
-      ensureIsMutable();
-      fields.setRepeatedField(field, index, value);
-      return this;
-    }
-
-    public Builder addRepeatedField(FieldDescriptor field, Object value) {
-      verifyContainingType(field);
-      ensureIsMutable();
-      fields.addRepeatedField(field, value);
-      return this;
-    }
-
-    public UnknownFieldSet getUnknownFields() {
-      return unknownFields;
-    }
-
-    public Builder setUnknownFields(UnknownFieldSet unknownFields) {
-      this.unknownFields = unknownFields;
-      return this;
-    }
-
-    @Override
-    public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
-      this.unknownFields =
-        UnknownFieldSet.newBuilder(this.unknownFields)
-                       .mergeFrom(unknownFields)
-                       .build();
-      return this;
-    }
-
-    /** Verifies that the field is a field of this message. */
-    private void verifyContainingType(FieldDescriptor field) {
-      if (field.getContainingType() != type) {
-        throw new IllegalArgumentException(
-          "FieldDescriptor does not match message type.");
-      }
-    }
-
-    /** Verifies that the oneof is an oneof of this message. */
-    private void verifyOneofContainingType(OneofDescriptor oneof) {
-      if (oneof.getContainingType() != type) {
-        throw new IllegalArgumentException(
-          "OneofDescriptor does not match message type.");
-      }
-    }
-
-    /** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
-    private void ensureSingularEnumValueDescriptor(
-        FieldDescriptor field, Object value) {
-      if (value == null) {
-        throw new NullPointerException();
-      }
-      if (!(value instanceof EnumValueDescriptor)) {
-        throw new IllegalArgumentException(
-          "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
-      }
-      if (field.getEnumType() != ((EnumValueDescriptor) value).getType()) {
-        throw new IllegalArgumentException(
-          "EnumValueDescriptor doesn't much Enum Field.");
-      }
-    }
-
-    /** Verifies the value for an enum field. */
-    private void ensureEnumValueDescriptor(
-        FieldDescriptor field, Object value) {
-      if (field.isRepeated()) {
-        for (Object item : (List) value) {
-          ensureSingularEnumValueDescriptor(field, item);
-        }
-      } else {
-         ensureSingularEnumValueDescriptor(field, value);
-      }
-    }
-
-    private void ensureIsMutable() {
-      if (fields.isImmutable()) {
-        fields = fields.clone();
-      }
-    }
-
-    @Override
-    public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
-      // TODO(xiangl): need implementation for dynamic message
-      throw new UnsupportedOperationException(
-        "getFieldBuilder() called on a dynamic message type.");
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Extension.java b/java/src/main/java/com/google/protobuf/Extension.java
deleted file mode 100644
index 0baa22b..0000000
--- a/java/src/main/java/com/google/protobuf/Extension.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * Interface that generated extensions implement.
- *
- * @author liujisi@google.com (Jisi Liu)
- */
-public abstract class Extension<ContainingType extends MessageLite, Type> {
-  /** Returns the field number of the extension. */
-  public abstract int getNumber();
-
-  /** Returns the type of the field. */
-  public abstract WireFormat.FieldType getLiteType();
-
-  /** Returns whether it is a repeated field. */
-  public abstract boolean isRepeated();
-
-  /** Returns the descriptor of the extension. */
-  public abstract Descriptors.FieldDescriptor getDescriptor();
-
-  /** Returns the default value of the extension field. */
-  public abstract Type getDefaultValue();
-
-  /**
-   * Returns the default instance of the extension field, if it's a message
-   * extension.
-   */
-  public abstract MessageLite getMessageDefaultInstance();
-
-  // All the methods below are extension implementation details.
-
-  /**
-   * The API type that the extension is used for.
-   */
-  protected enum ExtensionType {
-    IMMUTABLE,
-    MUTABLE,
-    PROTO1,
-  }
-
-  protected ExtensionType getExtensionType() {
-    // TODO(liujisi): make this abstract after we fix proto1.
-    return ExtensionType.IMMUTABLE;
-  }
-
-  /**
-   * Type of a message extension.
-   */
-  public enum MessageType {
-    PROTO1,
-    PROTO2,
-  }
-  
-  /**
-   * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
-   * returns the type of the message, otherwise undefined.
-   */
-  public MessageType getMessageType() {
-    return MessageType.PROTO2;
-  }
-
-  protected abstract Object fromReflectionType(Object value);
-  protected abstract Object singularFromReflectionType(Object value);
-  protected abstract Object toReflectionType(Object value);
-  protected abstract Object singularToReflectionType(Object value);
-}
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java
deleted file mode 100644
index 392f4ef..0000000
--- a/java/src/main/java/com/google/protobuf/FieldSet.java
+++ /dev/null
@@ -1,907 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.LazyField.LazyIterator;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class which represents an arbitrary set of fields of some message type.
- * This is used to implement {@link DynamicMessage}, and also to represent
- * extensions in {@link GeneratedMessage}.  This class is package-private,
- * since outside users should probably be using {@link DynamicMessage}.
- *
- * @author kenton@google.com Kenton Varda
- */
-final class FieldSet<FieldDescriptorType extends
-      FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
-  /**
-   * Interface for a FieldDescriptor or lite extension descriptor.  This
-   * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
-   */
-  public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
-      extends Comparable<T> {
-    int getNumber();
-    WireFormat.FieldType getLiteType();
-    WireFormat.JavaType getLiteJavaType();
-    boolean isRepeated();
-    boolean isPacked();
-    Internal.EnumLiteMap<?> getEnumType();
-
-    // If getLiteJavaType() == MESSAGE, this merges a message object of the
-    // type into a builder of the type.  Returns {@code to}.
-    MessageLite.Builder internalMergeFrom(
-        MessageLite.Builder to, MessageLite from);
-  }
-
-  private final SmallSortedMap<FieldDescriptorType, Object> fields;
-  private boolean isImmutable;
-  private boolean hasLazyField = false;
-
-  /** Construct a new FieldSet. */
-  private FieldSet() {
-    this.fields = SmallSortedMap.newFieldMap(16);
-  }
-
-  /**
-   * Construct an empty FieldSet.  This is only used to initialize
-   * DEFAULT_INSTANCE.
-   */
-  private FieldSet(final boolean dummy) {
-    this.fields = SmallSortedMap.newFieldMap(0);
-    makeImmutable();
-  }
-
-  /** Construct a new FieldSet. */
-  public static <T extends FieldSet.FieldDescriptorLite<T>>
-      FieldSet<T> newFieldSet() {
-    return new FieldSet<T>();
-  }
-
-  /** Get an immutable empty FieldSet. */
-  @SuppressWarnings("unchecked")
-  public static <T extends FieldSet.FieldDescriptorLite<T>>
-      FieldSet<T> emptySet() {
-    return DEFAULT_INSTANCE;
-  }
-  @SuppressWarnings("rawtypes")
-  private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
-
-  /** Make this FieldSet immutable from this point forward. */
-  @SuppressWarnings("unchecked")
-  public void makeImmutable() {
-    if (isImmutable) {
-      return;
-    }
-    fields.makeImmutable();
-    isImmutable = true;
-  }
-
-  /**
-   * Returns whether the FieldSet is immutable. This is true if it is the
-   * {@link #emptySet} or if {@link #makeImmutable} were called.
-   *
-   * @return whether the FieldSet is immutable.
-   */
-  public boolean isImmutable() {
-    return isImmutable;
-  }
-
-  /**
-   * Clones the FieldSet. The returned FieldSet will be mutable even if the
-   * original FieldSet was immutable.
-   *
-   * @return the newly cloned FieldSet
-   */
-  @Override
-  public FieldSet<FieldDescriptorType> clone() {
-    // We can't just call fields.clone because List objects in the map
-    // should not be shared.
-    FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
-      FieldDescriptorType descriptor = entry.getKey();
-      clone.setField(descriptor, entry.getValue());
-    }
-    for (Map.Entry<FieldDescriptorType, Object> entry :
-             fields.getOverflowEntries()) {
-      FieldDescriptorType descriptor = entry.getKey();
-      clone.setField(descriptor, entry.getValue());
-    }
-    clone.hasLazyField = hasLazyField;
-    return clone;
-  }
-
-
-  // =================================================================
-
-  /** See {@link Message.Builder#clear()}. */
-  public void clear() {
-    fields.clear();
-    hasLazyField = false;
-  }
-
-  /**
-   * Get a simple map containing all the fields.
-   */
-  public Map<FieldDescriptorType, Object> getAllFields() {
-    if (hasLazyField) {
-      SmallSortedMap<FieldDescriptorType, Object> result =
-          SmallSortedMap.newFieldMap(16);
-      for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-        cloneFieldEntry(result, fields.getArrayEntryAt(i));
-      }
-      for (Map.Entry<FieldDescriptorType, Object> entry :
-          fields.getOverflowEntries()) {
-        cloneFieldEntry(result, entry);
-      }
-      if (fields.isImmutable()) {
-        result.makeImmutable();
-      }
-      return result;
-    }
-    return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
-  }
-
-  private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
-      Map.Entry<FieldDescriptorType, Object> entry) {
-    FieldDescriptorType key = entry.getKey();
-    Object value = entry.getValue();
-    if (value instanceof LazyField) {
-      map.put(key, ((LazyField) value).getValue());
-    } else {
-      map.put(key, value);
-    }
-  }
-
-  /**
-   * Get an iterator to the field map. This iterator should not be leaked out
-   * of the protobuf library as it is not protected from mutation when fields
-   * is not immutable.
-   */
-  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
-    if (hasLazyField) {
-      return new LazyIterator<FieldDescriptorType>(
-          fields.entrySet().iterator());
-    }
-    return fields.entrySet().iterator();
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message#hasField(Descriptors.FieldDescriptor)}.
-   */
-  public boolean hasField(final FieldDescriptorType descriptor) {
-    if (descriptor.isRepeated()) {
-      throw new IllegalArgumentException(
-        "hasField() can only be called on non-repeated fields.");
-    }
-
-    return fields.get(descriptor) != null;
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
-   * returns {@code null} if the field is not set; in this case it is up
-   * to the caller to fetch the field's default value.
-   */
-  public Object getField(final FieldDescriptorType descriptor) {
-    Object o = fields.get(descriptor);
-    if (o instanceof LazyField) {
-      return ((LazyField) o).getValue();
-    }
-    return o;
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
-   */
-  @SuppressWarnings({"unchecked", "rawtypes"})
-  public void setField(final FieldDescriptorType descriptor,
-                       Object value) {
-    if (descriptor.isRepeated()) {
-      if (!(value instanceof List)) {
-        throw new IllegalArgumentException(
-          "Wrong object type used with protocol message reflection.");
-      }
-
-      // Wrap the contents in a new list so that the caller cannot change
-      // the list's contents after setting it.
-      final List newList = new ArrayList();
-      newList.addAll((List) value);
-      for (final Object element : newList) {
-        verifyType(descriptor.getLiteType(), element);
-      }
-      value = newList;
-    } else {
-      verifyType(descriptor.getLiteType(), value);
-    }
-
-    if (value instanceof LazyField) {
-      hasLazyField = true;
-    }
-    fields.put(descriptor, value);
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
-   */
-  public void clearField(final FieldDescriptorType descriptor) {
-    fields.remove(descriptor);
-    if (fields.isEmpty()) {
-      hasLazyField = false;
-    }
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
-   */
-  public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
-    if (!descriptor.isRepeated()) {
-      throw new IllegalArgumentException(
-        "getRepeatedField() can only be called on repeated fields.");
-    }
-
-    final Object value = getField(descriptor);
-    if (value == null) {
-      return 0;
-    } else {
-      return ((List<?>) value).size();
-    }
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
-   */
-  public Object getRepeatedField(final FieldDescriptorType descriptor,
-                                 final int index) {
-    if (!descriptor.isRepeated()) {
-      throw new IllegalArgumentException(
-        "getRepeatedField() can only be called on repeated fields.");
-    }
-
-    final Object value = getField(descriptor);
-
-    if (value == null) {
-      throw new IndexOutOfBoundsException();
-    } else {
-      return ((List<?>) value).get(index);
-    }
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
-   */
-  @SuppressWarnings("unchecked")
-  public void setRepeatedField(final FieldDescriptorType descriptor,
-                               final int index,
-                               final Object value) {
-    if (!descriptor.isRepeated()) {
-      throw new IllegalArgumentException(
-        "getRepeatedField() can only be called on repeated fields.");
-    }
-
-    final Object list = getField(descriptor);
-    if (list == null) {
-      throw new IndexOutOfBoundsException();
-    }
-
-    verifyType(descriptor.getLiteType(), value);
-    ((List<Object>) list).set(index, value);
-  }
-
-  /**
-   * Useful for implementing
-   * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
-   */
-  @SuppressWarnings("unchecked")
-  public void addRepeatedField(final FieldDescriptorType descriptor,
-                               final Object value) {
-    if (!descriptor.isRepeated()) {
-      throw new IllegalArgumentException(
-        "addRepeatedField() can only be called on repeated fields.");
-    }
-
-    verifyType(descriptor.getLiteType(), value);
-
-    final Object existingValue = getField(descriptor);
-    List<Object> list;
-    if (existingValue == null) {
-      list = new ArrayList<Object>();
-      fields.put(descriptor, list);
-    } else {
-      list = (List<Object>) existingValue;
-    }
-
-    list.add(value);
-  }
-
-  /**
-   * Verifies that the given object is of the correct type to be a valid
-   * value for the given field.  (For repeated fields, this checks if the
-   * object is the right type to be one element of the field.)
-   *
-   * @throws IllegalArgumentException The value is not of the right type.
-   */
-  private static void verifyType(final WireFormat.FieldType type,
-                                 final Object value) {
-    if (value == null) {
-      throw new NullPointerException();
-    }
-
-    boolean isValid = false;
-    switch (type.getJavaType()) {
-      case INT:          isValid = value instanceof Integer   ; break;
-      case LONG:         isValid = value instanceof Long      ; break;
-      case FLOAT:        isValid = value instanceof Float     ; break;
-      case DOUBLE:       isValid = value instanceof Double    ; break;
-      case BOOLEAN:      isValid = value instanceof Boolean   ; break;
-      case STRING:       isValid = value instanceof String    ; break;
-      case BYTE_STRING:
-        isValid = value instanceof ByteString || value instanceof byte[];
-        break;
-      case ENUM:
-        // TODO(kenton):  Caller must do type checking here, I guess.
-        isValid =
-            (value instanceof Integer || value instanceof Internal.EnumLite);
-        break;
-      case MESSAGE:
-        // TODO(kenton):  Caller must do type checking here, I guess.
-        isValid =
-            (value instanceof MessageLite) || (value instanceof LazyField);
-        break;
-    }
-
-    if (!isValid) {
-      // TODO(kenton):  When chaining calls to setField(), it can be hard to
-      //   tell from the stack trace which exact call failed, since the whole
-      //   chain is considered one line of code.  It would be nice to print
-      //   more information here, e.g. naming the field.  We used to do that.
-      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
-      //   isn't a big deal, though, since it would only really apply when using
-      //   reflection and generally people don't chain reflection setters.
-      throw new IllegalArgumentException(
-        "Wrong object type used with protocol message reflection.");
-    }
-  }
-
-  // =================================================================
-  // Parsing and serialization
-
-  /**
-   * See {@link Message#isInitialized()}.  Note:  Since {@code FieldSet}
-   * itself does not have any way of knowing about required fields that
-   * aren't actually present in the set, it is up to the caller to check
-   * that all required fields are present.
-   */
-  public boolean isInitialized() {
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      if (!isInitialized(fields.getArrayEntryAt(i))) {
-        return false;
-      }
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-             fields.getOverflowEntries()) {
-      if (!isInitialized(entry)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  @SuppressWarnings("unchecked")
-  private boolean isInitialized(
-      final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
-    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
-      if (descriptor.isRepeated()) {
-        for (final MessageLite element:
-                 (List<MessageLite>) entry.getValue()) {
-          if (!element.isInitialized()) {
-            return false;
-          }
-        }
-      } else {
-        Object value = entry.getValue();
-        if (value instanceof MessageLite) {
-          if (!((MessageLite) value).isInitialized()) {
-            return false;
-          }
-        } else if (value instanceof LazyField) {
-          return true;
-        } else {
-          throw new IllegalArgumentException(
-              "Wrong object type used with protocol message reflection.");
-        }
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Given a field type, return the wire type.
-   *
-   * @returns One of the {@code WIRETYPE_} constants defined in
-   *          {@link WireFormat}.
-   */
-  static int getWireFormatForFieldType(final WireFormat.FieldType type,
-                                       boolean isPacked) {
-    if (isPacked) {
-      return WireFormat.WIRETYPE_LENGTH_DELIMITED;
-    } else {
-      return type.getWireType();
-    }
-  }
-
-  /**
-   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 
-   * {@link FieldSet}.
-   */
-  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
-    for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
-      mergeFromField(other.fields.getArrayEntryAt(i));
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-             other.fields.getOverflowEntries()) {
-      mergeFromField(entry);
-    }
-  }
-
-  private Object cloneIfMutable(Object value) {
-    if (value instanceof byte[]) {
-      byte[] bytes = (byte[]) value;
-      byte[] copy = new byte[bytes.length];
-      System.arraycopy(bytes, 0, copy, 0, bytes.length);
-      return copy;
-    } else {
-      return value;
-    }
-  }
-
-  @SuppressWarnings({"unchecked", "rawtypes"})
-  private void mergeFromField(
-      final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
-    Object otherValue = entry.getValue();
-    if (otherValue instanceof LazyField) {
-      otherValue = ((LazyField) otherValue).getValue();
-    }
-
-    if (descriptor.isRepeated()) {
-      Object value = getField(descriptor);
-      if (value == null) {
-        value = new ArrayList();
-      }
-      for (Object element : (List) otherValue) {
-        ((List) value).add(cloneIfMutable(element));
-      }
-      fields.put(descriptor, value);
-    } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
-      Object value = getField(descriptor);
-      if (value == null) {
-        fields.put(descriptor, cloneIfMutable(otherValue));
-      } else {
-        // Merge the messages.
-          value = descriptor.internalMergeFrom(
-                ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
-                .build();
-
-        fields.put(descriptor, value);
-      }
-    } else {
-      fields.put(descriptor, cloneIfMutable(otherValue));
-    }
-  }
-
-  // TODO(kenton):  Move static parsing and serialization methods into some
-  //   other class.  Probably WireFormat.
-
-  /**
-   * Read a field of any primitive type for immutable messages from a
-   * CodedInputStream. Enums, groups, and embedded messages are not handled by
-   * this method.
-   *
-   * @param input The stream from which to read.
-   * @param type Declared type of the field.
-   * @param checkUtf8 When true, check that the input is valid utf8.
-   * @return An object representing the field's value, of the exact
-   *         type which would be returned by
-   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
-   *         this field.
-   */
-  public static Object readPrimitiveField(
-      CodedInputStream input,
-      final WireFormat.FieldType type,
-      boolean checkUtf8) throws IOException {
-    switch (type) {
-      case DOUBLE  : return input.readDouble  ();
-      case FLOAT   : return input.readFloat   ();
-      case INT64   : return input.readInt64   ();
-      case UINT64  : return input.readUInt64  ();
-      case INT32   : return input.readInt32   ();
-      case FIXED64 : return input.readFixed64 ();
-      case FIXED32 : return input.readFixed32 ();
-      case BOOL    : return input.readBool    ();
-      case STRING  : if (checkUtf8) {
-                       return input.readStringRequireUtf8();
-                     } else {
-                       return input.readString();
-                     }
-      case BYTES   : return input.readBytes   ();
-      case UINT32  : return input.readUInt32  ();
-      case SFIXED32: return input.readSFixed32();
-      case SFIXED64: return input.readSFixed64();
-      case SINT32  : return input.readSInt32  ();
-      case SINT64  : return input.readSInt64  ();
-
-      case GROUP:
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle nested groups.");
-      case MESSAGE:
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle embedded messages.");
-      case ENUM:
-        // We don't handle enums because we don't know what to do if the
-        // value is not recognized.
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle enums.");
-    }
-
-    throw new RuntimeException(
-      "There is no way to get here, but the compiler thinks otherwise.");
-  }
-
-
-  /** See {@link Message#writeTo(CodedOutputStream)}. */
-  public void writeTo(final CodedOutputStream output)
-                      throws IOException {
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      final Map.Entry<FieldDescriptorType, Object> entry =
-          fields.getArrayEntryAt(i);
-      writeField(entry.getKey(), entry.getValue(), output);
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-         fields.getOverflowEntries()) {
-      writeField(entry.getKey(), entry.getValue(), output);
-    }
-  }
-
-  /**
-   * Like {@link #writeTo} but uses MessageSet wire format.
-   */
-  public void writeMessageSetTo(final CodedOutputStream output)
-                                throws IOException {
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      writeMessageSetTo(fields.getArrayEntryAt(i), output);
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-             fields.getOverflowEntries()) {
-      writeMessageSetTo(entry, output);
-    }
-  }
-
-  private void writeMessageSetTo(
-      final Map.Entry<FieldDescriptorType, Object> entry,
-      final CodedOutputStream output) throws IOException {
-    final FieldDescriptorType descriptor = entry.getKey();
-    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
-        !descriptor.isRepeated() && !descriptor.isPacked()) {
-      Object value = entry.getValue();
-      if (value instanceof LazyField) {
-        value = ((LazyField) value).getValue();
-      }
-      output.writeMessageSetExtension(entry.getKey().getNumber(),
-                                      (MessageLite) value);
-    } else {
-      writeField(descriptor, entry.getValue(), output);
-    }
-  }
-
-  /**
-   * Write a single tag-value pair to the stream.
-   *
-   * @param output The output stream.
-   * @param type   The field's type.
-   * @param number The field's number.
-   * @param value  Object representing the field's value.  Must be of the exact
-   *               type which would be returned by
-   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
-   *               this field.
-   */
-  private static void writeElement(final CodedOutputStream output,
-                                   final WireFormat.FieldType type,
-                                   final int number,
-                                   final Object value) throws IOException {
-    // Special case for groups, which need a start and end tag; other fields
-    // can just use writeTag() and writeFieldNoTag().
-    if (type == WireFormat.FieldType.GROUP) {
-        output.writeGroup(number, (MessageLite) value);
-    } else {
-      output.writeTag(number, getWireFormatForFieldType(type, false));
-      writeElementNoTag(output, type, value);
-    }
-  }
-
-  /**
-   * Write a field of arbitrary type, without its tag, to the stream.
-   *
-   * @param output The output stream.
-   * @param type The field's type.
-   * @param value  Object representing the field's value.  Must be of the exact
-   *               type which would be returned by
-   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
-   *               this field.
-   */
-  private static void writeElementNoTag(
-      final CodedOutputStream output,
-      final WireFormat.FieldType type,
-      final Object value) throws IOException {
-    switch (type) {
-      case DOUBLE  : output.writeDoubleNoTag  ((Double     ) value); break;
-      case FLOAT   : output.writeFloatNoTag   ((Float      ) value); break;
-      case INT64   : output.writeInt64NoTag   ((Long       ) value); break;
-      case UINT64  : output.writeUInt64NoTag  ((Long       ) value); break;
-      case INT32   : output.writeInt32NoTag   ((Integer    ) value); break;
-      case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
-      case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
-      case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
-      case STRING  : output.writeStringNoTag  ((String     ) value); break;
-      case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
-      case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
-      case BYTES:
-        if (value instanceof ByteString) {
-          output.writeBytesNoTag((ByteString) value);
-        } else {
-          output.writeByteArrayNoTag((byte[]) value);
-        }
-        break;
-      case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
-      case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
-      case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
-      case SINT32  : output.writeSInt32NoTag  ((Integer    ) value); break;
-      case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
-
-      case ENUM:
-        if (value instanceof Internal.EnumLite) {
-          output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
-        } else {
-          output.writeEnumNoTag(((Integer) value).intValue());
-        }
-        break;
-    }
-  }
-
-  /** Write a single field. */
-  public static void writeField(final FieldDescriptorLite<?> descriptor,
-                                final Object value,
-                                final CodedOutputStream output)
-                                throws IOException {
-    WireFormat.FieldType type = descriptor.getLiteType();
-    int number = descriptor.getNumber();
-    if (descriptor.isRepeated()) {
-      final List<?> valueList = (List<?>)value;
-      if (descriptor.isPacked()) {
-        output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-        // Compute the total data size so the length can be written.
-        int dataSize = 0;
-        for (final Object element : valueList) {
-          dataSize += computeElementSizeNoTag(type, element);
-        }
-        output.writeRawVarint32(dataSize);
-        // Write the data itself, without any tags.
-        for (final Object element : valueList) {
-          writeElementNoTag(output, type, element);
-        }
-      } else {
-        for (final Object element : valueList) {
-          writeElement(output, type, number, element);
-        }
-      }
-    } else {
-      if (value instanceof LazyField) {
-        writeElement(output, type, number, ((LazyField) value).getValue());
-      } else {
-        writeElement(output, type, number, value);
-      }
-    }
-  }
-
-  /**
-   * See {@link Message#getSerializedSize()}.  It's up to the caller to cache
-   * the resulting size if desired.
-   */
-  public int getSerializedSize() {
-    int size = 0;
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      final Map.Entry<FieldDescriptorType, Object> entry =
-          fields.getArrayEntryAt(i);
-      size += computeFieldSize(entry.getKey(), entry.getValue());
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-         fields.getOverflowEntries()) {
-      size += computeFieldSize(entry.getKey(), entry.getValue());
-    }
-    return size;
-  }
-
-  /**
-   * Like {@link #getSerializedSize} but uses MessageSet wire format.
-   */
-  public int getMessageSetSerializedSize() {
-    int size = 0;
-    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
-    }
-    for (final Map.Entry<FieldDescriptorType, Object> entry :
-             fields.getOverflowEntries()) {
-      size += getMessageSetSerializedSize(entry);
-    }
-    return size;
-  }
-
-  private int getMessageSetSerializedSize(
-      final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
-    Object value = entry.getValue();
-    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
-        && !descriptor.isRepeated() && !descriptor.isPacked()) {
-      if (value instanceof LazyField) {
-        return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
-            entry.getKey().getNumber(), (LazyField) value);
-      } else {
-        return CodedOutputStream.computeMessageSetExtensionSize(
-            entry.getKey().getNumber(), (MessageLite) value);
-      }
-    } else {
-      return computeFieldSize(descriptor, value);
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * single tag/value pair of arbitrary type.
-   *
-   * @param type   The field's type.
-   * @param number The field's number.
-   * @param value  Object representing the field's value.  Must be of the exact
-   *               type which would be returned by
-   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
-   *               this field.
-   */
-  private static int computeElementSize(
-      final WireFormat.FieldType type,
-      final int number, final Object value) {
-    int tagSize = CodedOutputStream.computeTagSize(number);
-    if (type == WireFormat.FieldType.GROUP) {
-      // Only count the end group tag for proto2 messages as for proto1 the end
-      // group tag will be counted as a part of getSerializedSize().
-        tagSize *= 2;
-    }
-    return tagSize + computeElementSizeNoTag(type, value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * particular value of arbitrary type, excluding tag.
-   *
-   * @param type   The field's type.
-   * @param value  Object representing the field's value.  Must be of the exact
-   *               type which would be returned by
-   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
-   *               this field.
-   */
-  private static int computeElementSizeNoTag(
-      final WireFormat.FieldType type, final Object value) {
-    switch (type) {
-      // Note:  Minor violation of 80-char limit rule here because this would
-      //   actually be harder to read if we wrapped the lines.
-      case DOUBLE  : return CodedOutputStream.computeDoubleSizeNoTag  ((Double     )value);
-      case FLOAT   : return CodedOutputStream.computeFloatSizeNoTag   ((Float      )value);
-      case INT64   : return CodedOutputStream.computeInt64SizeNoTag   ((Long       )value);
-      case UINT64  : return CodedOutputStream.computeUInt64SizeNoTag  ((Long       )value);
-      case INT32   : return CodedOutputStream.computeInt32SizeNoTag   ((Integer    )value);
-      case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
-      case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
-      case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
-      case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
-      case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
-      case BYTES   :
-        if (value instanceof ByteString) {
-          return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
-        } else {
-          return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
-        }
-      case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
-      case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
-      case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
-      case SINT32  : return CodedOutputStream.computeSInt32SizeNoTag  ((Integer    )value);
-      case SINT64  : return CodedOutputStream.computeSInt64SizeNoTag  ((Long       )value);
-
-      case MESSAGE:
-        if (value instanceof LazyField) {
-          return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
-        } else {
-          return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
-        }
-
-      case ENUM:
-        if (value instanceof Internal.EnumLite) {
-          return CodedOutputStream.computeEnumSizeNoTag(
-              ((Internal.EnumLite) value).getNumber());
-        } else {
-          return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
-        }
-    }
-
-    throw new RuntimeException(
-      "There is no way to get here, but the compiler thinks otherwise.");
-  }
-
-  /**
-   * Compute the number of bytes needed to encode a particular field.
-   */
-  public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
-                                     final Object value) {
-    WireFormat.FieldType type = descriptor.getLiteType();
-    int number = descriptor.getNumber();
-    if (descriptor.isRepeated()) {
-      if (descriptor.isPacked()) {
-        int dataSize = 0;
-        for (final Object element : (List<?>)value) {
-          dataSize += computeElementSizeNoTag(type, element);
-        }
-        return dataSize +
-            CodedOutputStream.computeTagSize(number) +
-            CodedOutputStream.computeRawVarint32Size(dataSize);
-      } else {
-        int size = 0;
-        for (final Object element : (List<?>)value) {
-          size += computeElementSize(type, number, element);
-        }
-        return size;
-      }
-    } else {
-      return computeElementSize(type, number, value);
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
deleted file mode 100644
index a6101cb..0000000
--- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ /dev/null
@@ -1,2213 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.EnumValueDescriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.Descriptors.FileDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-
-import java.io.IOException;
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * All generated protocol message classes extend this class.  This class
- * implements most of the Message and Builder interfaces using Java reflection.
- * Users can ignore this class and pretend that generated messages implement
- * the Message interface directly.
- *
- * @author kenton@google.com Kenton Varda
- */
-public abstract class GeneratedMessage extends AbstractMessage
-    implements Serializable {
-  private static final long serialVersionUID = 1L;
-
-  /**
-   * For testing. Allows a test to disable the optimization that avoids using
-   * field builders for nested messages until they are requested. By disabling
-   * this optimization, existing tests can be reused to test the field builders.
-   */
-  protected static boolean alwaysUseFieldBuilders = false;
-
-  protected GeneratedMessage() {
-  }
-
-  protected GeneratedMessage(Builder<?> builder) {
-  }
-
-  public Parser<? extends GeneratedMessage> getParserForType() {
-    throw new UnsupportedOperationException(
-        "This is supposed to be overridden by subclasses.");
-  }
-
- /**
-  * For testing. Allows a test to disable the optimization that avoids using
-  * field builders for nested messages until they are requested. By disabling
-  * this optimization, existing tests can be reused to test the field builders.
-  * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
-  */
-  static void enableAlwaysUseFieldBuildersForTesting() {
-    alwaysUseFieldBuilders = true;
-  }
-
-  /**
-   * Get the FieldAccessorTable for this type.  We can't have the message
-   * class pass this in to the constructor because of bootstrapping trouble
-   * with DescriptorProtos.
-   */
-  protected abstract FieldAccessorTable internalGetFieldAccessorTable();
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public Descriptor getDescriptorForType() {
-    return internalGetFieldAccessorTable().descriptor;
-  }
-
-  /** Internal helper which returns a mutable map. */
-  private Map<FieldDescriptor, Object> getAllFieldsMutable() {
-    final TreeMap<FieldDescriptor, Object> result =
-      new TreeMap<FieldDescriptor, Object>();
-    final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
-    for (final FieldDescriptor field : descriptor.getFields()) {
-      if (field.isRepeated()) {
-        final List<?> value = (List<?>) getField(field);
-        if (!value.isEmpty()) {
-          result.put(field, value);
-        }
-      } else {
-        if (hasField(field)) {
-          result.put(field, getField(field));
-        }
-      }
-    }
-    return result;
-  }
-
-  @Override
-  public boolean isInitialized() {
-    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
-      // Check that all required fields are present.
-      if (field.isRequired()) {
-        if (!hasField(field)) {
-          return false;
-        }
-      }
-      // Check that embedded messages are initialized.
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (field.isRepeated()) {
-          @SuppressWarnings("unchecked") final
-          List<Message> messageList = (List<Message>) getField(field);
-          for (final Message element : messageList) {
-            if (!element.isInitialized()) {
-              return false;
-            }
-          }
-        } else {
-          if (hasField(field) && !((Message) getField(field)).isInitialized()) {
-            return false;
-          }
-        }
-      }
-    }
-
-    return true;
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public Map<FieldDescriptor, Object> getAllFields() {
-    return Collections.unmodifiableMap(getAllFieldsMutable());
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public boolean hasOneof(final OneofDescriptor oneof) {
-    return internalGetFieldAccessorTable().getOneof(oneof).has(this);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
-    return internalGetFieldAccessorTable().getOneof(oneof).get(this);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public boolean hasField(final FieldDescriptor field) {
-    return internalGetFieldAccessorTable().getField(field).has(this);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public Object getField(final FieldDescriptor field) {
-    return internalGetFieldAccessorTable().getField(field).get(this);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public int getRepeatedFieldCount(final FieldDescriptor field) {
-    return internalGetFieldAccessorTable().getField(field)
-      .getRepeatedCount(this);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public Object getRepeatedField(final FieldDescriptor field, final int index) {
-    return internalGetFieldAccessorTable().getField(field)
-      .getRepeated(this, index);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public UnknownFieldSet getUnknownFields() {
-    throw new UnsupportedOperationException(
-        "This is supposed to be overridden by subclasses.");
-  }
-
-  /**
-   * Called by subclasses to parse an unknown field.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  protected boolean parseUnknownField(
-      CodedInputStream input,
-      UnknownFieldSet.Builder unknownFields,
-      ExtensionRegistryLite extensionRegistry,
-      int tag) throws IOException {
-    return unknownFields.mergeFieldFrom(tag, input);
-  }
-
-
-  /**
-   * Used by parsing constructors in generated classes.
-   */
-  protected void makeExtensionsImmutable() {
-    // Noop for messages without extensions.
-  }
-
-  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
-
-  /**
-   * Interface for the parent of a Builder that allows the builder to
-   * communicate invalidations back to the parent for use when using nested
-   * builders.
-   */
-  protected interface BuilderParent {
-
-    /**
-     * A builder becomes dirty whenever a field is modified -- including fields
-     * in nested builders -- and becomes clean when build() is called.  Thus,
-     * when a builder becomes dirty, all its parents become dirty as well, and
-     * when it becomes clean, all its children become clean.  The dirtiness
-     * state is used to invalidate certain cached values.
-     * <br>
-     * To this end, a builder calls markAsDirty() on its parent whenever it
-     * transitions from clean to dirty.  The parent must propagate this call to
-     * its own parent, unless it was already dirty, in which case the
-     * grandparent must necessarily already be dirty as well.  The parent can
-     * only transition back to "clean" after calling build() on all children.
-     */
-    void markDirty();
-  }
-
-  @SuppressWarnings("unchecked")
-  public abstract static class Builder <BuilderType extends Builder>
-      extends AbstractMessage.Builder<BuilderType> {
-
-    private BuilderParent builderParent;
-
-    private BuilderParentImpl meAsParent;
-
-    // Indicates that we've built a message and so we are now obligated
-    // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
-    private boolean isClean;
-
-    private UnknownFieldSet unknownFields =
-        UnknownFieldSet.getDefaultInstance();
-
-    protected Builder() {
-      this(null);
-    }
-
-    protected Builder(BuilderParent builderParent) {
-      this.builderParent = builderParent;
-    }
-
-    void dispose() {
-      builderParent = null;
-    }
-
-    /**
-     * Called by the subclass when a message is built.
-     */
-    protected void onBuilt() {
-      if (builderParent != null) {
-        markClean();
-      }
-    }
-
-    /**
-     * Called by the subclass or a builder to notify us that a message was
-     * built and may be cached and therefore invalidations are needed.
-     */
-    protected void markClean() {
-      this.isClean = true;
-    }
-
-    /**
-     * Gets whether invalidations are needed
-     *
-     * @return whether invalidations are needed
-     */
-    protected boolean isClean() {
-      return isClean;
-    }
-
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      throw new UnsupportedOperationException(
-          "This is supposed to be overridden by subclasses.");
-    }
-
-    /**
-     * Called by the initialization and clear code paths to allow subclasses to
-     * reset any of their builtin fields back to the initial values.
-     */
-    public BuilderType clear() {
-      unknownFields = UnknownFieldSet.getDefaultInstance();
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    /**
-     * Get the FieldAccessorTable for this type.  We can't have the message
-     * class pass this in to the constructor because of bootstrapping trouble
-     * with DescriptorProtos.
-     */
-    protected abstract FieldAccessorTable internalGetFieldAccessorTable();
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Descriptor getDescriptorForType() {
-      return internalGetFieldAccessorTable().descriptor;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Map<FieldDescriptor, Object> getAllFields() {
-      return Collections.unmodifiableMap(getAllFieldsMutable());
-    }
-
-    /** Internal helper which returns a mutable map. */
-    private Map<FieldDescriptor, Object> getAllFieldsMutable() {
-      final TreeMap<FieldDescriptor, Object> result =
-        new TreeMap<FieldDescriptor, Object>();
-      final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
-      for (final FieldDescriptor field : descriptor.getFields()) {
-        if (field.isRepeated()) {
-          final List value = (List) getField(field);
-          if (!value.isEmpty()) {
-            result.put(field, value);
-          }
-        } else {
-          if (hasField(field)) {
-            result.put(field, getField(field));
-          }
-        }
-      }
-      return result;
-    }
-
-    public Message.Builder newBuilderForField(
-        final FieldDescriptor field) {
-      return internalGetFieldAccessorTable().getField(field).newBuilder();
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
-      return internalGetFieldAccessorTable().getField(field).getBuilder(this);
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public boolean hasOneof(final OneofDescriptor oneof) {
-      return internalGetFieldAccessorTable().getOneof(oneof).has(this);
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
-      return internalGetFieldAccessorTable().getOneof(oneof).get(this);
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public boolean hasField(final FieldDescriptor field) {
-      return internalGetFieldAccessorTable().getField(field).has(this);
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Object getField(final FieldDescriptor field) {
-      Object object = internalGetFieldAccessorTable().getField(field).get(this);
-      if (field.isRepeated()) {
-        // The underlying list object is still modifiable at this point.
-        // Make sure not to expose the modifiable list to the caller.
-        return Collections.unmodifiableList((List) object);
-      } else {
-        return object;
-      }
-    }
-
-    public BuilderType setField(final FieldDescriptor field,
-                                final Object value) {
-      internalGetFieldAccessorTable().getField(field).set(this, value);
-      return (BuilderType) this;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clearField(final FieldDescriptor field) {
-      internalGetFieldAccessorTable().getField(field).clear(this);
-      return (BuilderType) this;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clearOneof(final OneofDescriptor oneof) {
-      internalGetFieldAccessorTable().getOneof(oneof).clear(this);
-      return (BuilderType) this;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public int getRepeatedFieldCount(final FieldDescriptor field) {
-      return internalGetFieldAccessorTable().getField(field)
-          .getRepeatedCount(this);
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Object getRepeatedField(final FieldDescriptor field,
-                                   final int index) {
-      return internalGetFieldAccessorTable().getField(field)
-          .getRepeated(this, index);
-    }
-
-    public BuilderType setRepeatedField(final FieldDescriptor field,
-                                        final int index, final Object value) {
-      internalGetFieldAccessorTable().getField(field)
-        .setRepeated(this, index, value);
-      return (BuilderType) this;
-    }
-
-    public BuilderType addRepeatedField(final FieldDescriptor field,
-                                        final Object value) {
-      internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
-      return (BuilderType) this;
-    }
-
-    public final BuilderType setUnknownFields(
-        final UnknownFieldSet unknownFields) {
-      this.unknownFields = unknownFields;
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    @Override
-    public final BuilderType mergeUnknownFields(
-        final UnknownFieldSet unknownFields) {
-      this.unknownFields =
-        UnknownFieldSet.newBuilder(this.unknownFields)
-                       .mergeFrom(unknownFields)
-                       .build();
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public boolean isInitialized() {
-      for (final FieldDescriptor field : getDescriptorForType().getFields()) {
-        // Check that all required fields are present.
-        if (field.isRequired()) {
-          if (!hasField(field)) {
-            return false;
-          }
-        }
-        // Check that embedded messages are initialized.
-        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-          if (field.isRepeated()) {
-            @SuppressWarnings("unchecked") final
-            List<Message> messageList = (List<Message>) getField(field);
-            for (final Message element : messageList) {
-              if (!element.isInitialized()) {
-                return false;
-              }
-            }
-          } else {
-            if (hasField(field) &&
-                !((Message) getField(field)).isInitialized()) {
-              return false;
-            }
-          }
-        }
-      }
-      return true;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final UnknownFieldSet getUnknownFields() {
-      return unknownFields;
-    }
-
-    /**
-     * Called by subclasses to parse an unknown field.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    protected boolean parseUnknownField(
-        final CodedInputStream input,
-        final UnknownFieldSet.Builder unknownFields,
-        final ExtensionRegistryLite extensionRegistry,
-        final int tag) throws IOException {
-      return unknownFields.mergeFieldFrom(tag, input);
-    }
-
-    /**
-     * Implementation of {@link BuilderParent} for giving to our children. This
-     * small inner class makes it so we don't publicly expose the BuilderParent
-     * methods.
-     */
-    private class BuilderParentImpl implements BuilderParent {
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void markDirty() {
-        onChanged();
-      }
-    }
-
-    /**
-     * Gets the {@link BuilderParent} for giving to our children.
-     * @return The builder parent for our children.
-     */
-    protected BuilderParent getParentForChildren() {
-      if (meAsParent == null) {
-        meAsParent = new BuilderParentImpl();
-      }
-      return meAsParent;
-    }
-
-    /**
-     * Called when a the builder or one of its nested children has changed
-     * and any parent should be notified of its invalidation.
-     */
-    protected final void onChanged() {
-      if (isClean && builderParent != null) {
-        builderParent.markDirty();
-
-        // Don't keep dispatching invalidations until build is called again.
-        isClean = false;
-      }
-    }
-  }
-
-  // =================================================================
-  // Extensions-related stuff
-
-  public interface ExtendableMessageOrBuilder<
-      MessageType extends ExtendableMessage> extends MessageOrBuilder {
-    // Re-define for return type covariance.
-    Message getDefaultInstanceForType();
-
-    /** Check if a singular extension is present. */
-    <Type> boolean hasExtension(
-        Extension<MessageType, Type> extension);
-
-    /** Get the number of elements in a repeated extension. */
-    <Type> int getExtensionCount(
-        Extension<MessageType, List<Type>> extension);
-
-    /** Get the value of an extension. */
-    <Type> Type getExtension(
-        Extension<MessageType, Type> extension);
-
-    /** Get one element of a repeated extension. */
-    <Type> Type getExtension(
-        Extension<MessageType, List<Type>> extension,
-        int index);
-  }
-
-  /**
-   * Generated message classes for message types that contain extension ranges
-   * subclass this.
-   *
-   * <p>This class implements type-safe accessors for extensions.  They
-   * implement all the same operations that you can do with normal fields --
-   * e.g. "has", "get", and "getCount" -- but for extensions.  The extensions
-   * are identified using instances of the class {@link GeneratedExtension};
-   * the protocol compiler generates a static instance of this class for every
-   * extension in its input.  Through the magic of generics, all is made
-   * type-safe.
-   *
-   * <p>For example, imagine you have the {@code .proto} file:
-   *
-   * <pre>
-   * option java_class = "MyProto";
-   *
-   * message Foo {
-   *   extensions 1000 to max;
-   * }
-   *
-   * extend Foo {
-   *   optional int32 bar;
-   * }
-   * </pre>
-   *
-   * <p>Then you might write code like:
-   *
-   * <pre>
-   * MyProto.Foo foo = getFoo();
-   * int i = foo.getExtension(MyProto.bar);
-   * </pre>
-   *
-   * <p>See also {@link ExtendableBuilder}.
-   */
-  public abstract static class ExtendableMessage<
-        MessageType extends ExtendableMessage>
-      extends GeneratedMessage
-      implements ExtendableMessageOrBuilder<MessageType> {
-
-    private final FieldSet<FieldDescriptor> extensions;
-
-    protected ExtendableMessage() {
-      this.extensions = FieldSet.newFieldSet();
-    }
-
-    protected ExtendableMessage(
-        ExtendableBuilder<MessageType, ?> builder) {
-      super(builder);
-      this.extensions = builder.buildExtensions();
-    }
-
-    private void verifyExtensionContainingType(
-        final Extension<MessageType, ?> extension) {
-      if (extension.getDescriptor().getContainingType() !=
-          getDescriptorForType()) {
-        // This can only happen if someone uses unchecked operations.
-        throw new IllegalArgumentException(
-          "Extension is for type \"" +
-          extension.getDescriptor().getContainingType().getFullName() +
-          "\" which does not match message type \"" +
-          getDescriptorForType().getFullName() + "\".");
-      }
-    }
-
-    /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final Extension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.hasField(extension.getDescriptor());
-    }
-
-    /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> int getExtensionCount(
-        final Extension<MessageType, List<Type>> extension) {
-      verifyExtensionContainingType(extension);
-      final FieldDescriptor descriptor = extension.getDescriptor();
-      return extensions.getRepeatedFieldCount(descriptor);
-    }
-
-    /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final Extension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      FieldDescriptor descriptor = extension.getDescriptor();
-      final Object value = extensions.getField(descriptor);
-      if (value == null) {
-        if (descriptor.isRepeated()) {
-          return (Type) Collections.emptyList();
-        } else if (descriptor.getJavaType() ==
-                   FieldDescriptor.JavaType.MESSAGE) {
-          return (Type) extension.getMessageDefaultInstance();
-        } else {
-          return (Type) extension.fromReflectionType(
-              descriptor.getDefaultValue());
-        }
-      } else {
-        return (Type) extension.fromReflectionType(value);
-      }
-    }
-
-    /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final Extension<MessageType, List<Type>> extension,
-        final int index) {
-      verifyExtensionContainingType(extension);
-      FieldDescriptor descriptor = extension.getDescriptor();
-      return (Type) extension.singularFromReflectionType(
-          extensions.getRepeatedField(descriptor, index));
-    }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    @Override
-    public boolean isInitialized() {
-      return super.isInitialized() && extensionsAreInitialized();
-    }
-
-    @Override
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        UnknownFieldSet.Builder unknownFields,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      return MessageReflection.mergeFieldFrom(
-          input, unknownFields, extensionRegistry, getDescriptorForType(),
-          new MessageReflection.ExtensionAdapter(extensions), tag);
-    }
-
-
-    /**
-     * Used by parsing constructors in generated classes.
-     */
-    @Override
-    protected void makeExtensionsImmutable() {
-      extensions.makeImmutable();
-    }
-
-    /**
-     * Used by subclasses to serialize extensions.  Extension ranges may be
-     * interleaved with field numbers, but we must write them in canonical
-     * (sorted by field number) order.  ExtensionWriter helps us write
-     * individual ranges of extensions at once.
-     */
-    protected class ExtensionWriter {
-      // Imagine how much simpler this code would be if Java iterators had
-      // a way to get the next element without advancing the iterator.
-
-      private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
-        extensions.iterator();
-      private Map.Entry<FieldDescriptor, Object> next;
-      private final boolean messageSetWireFormat;
-
-      private ExtensionWriter(final boolean messageSetWireFormat) {
-        if (iter.hasNext()) {
-          next = iter.next();
-        }
-        this.messageSetWireFormat = messageSetWireFormat;
-      }
-
-      public void writeUntil(final int end, final CodedOutputStream output)
-                             throws IOException {
-        while (next != null && next.getKey().getNumber() < end) {
-          FieldDescriptor descriptor = next.getKey();
-          if (messageSetWireFormat && descriptor.getLiteJavaType() ==
-                  WireFormat.JavaType.MESSAGE &&
-              !descriptor.isRepeated()) {
-            if (next instanceof LazyField.LazyEntry<?>) {
-              output.writeRawMessageSetExtension(descriptor.getNumber(),
-                  ((LazyField.LazyEntry<?>) next).getField().toByteString());
-            } else {
-              output.writeMessageSetExtension(descriptor.getNumber(),
-                                              (Message) next.getValue());
-            }
-          } else {
-            // TODO(xiangl): Taken care of following code, it may cause
-            // problem when we use LazyField for normal fields/extensions.
-            // Due to the optional field can be duplicated at the end of
-            // serialized bytes, which will make the serialized size change
-            // after lazy field parsed. So when we use LazyField globally,
-            // we need to change the following write method to write cached
-            // bytes directly rather than write the parsed message.
-            FieldSet.writeField(descriptor, next.getValue(), output);
-          }
-          if (iter.hasNext()) {
-            next = iter.next();
-          } else {
-            next = null;
-          }
-        }
-      }
-    }
-
-    protected ExtensionWriter newExtensionWriter() {
-      return new ExtensionWriter(false);
-    }
-    protected ExtensionWriter newMessageSetExtensionWriter() {
-      return new ExtensionWriter(true);
-    }
-
-    /** Called by subclasses to compute the size of extensions. */
-    protected int extensionsSerializedSize() {
-      return extensions.getSerializedSize();
-    }
-    protected int extensionsSerializedSizeAsMessageSet() {
-      return extensions.getMessageSetSerializedSize();
-    }
-
-    // ---------------------------------------------------------------
-    // Reflection
-
-    protected Map<FieldDescriptor, Object> getExtensionFields() {
-      return extensions.getAllFields();
-    }
-
-    @Override
-    public Map<FieldDescriptor, Object> getAllFields() {
-      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
-      result.putAll(getExtensionFields());
-      return Collections.unmodifiableMap(result);
-    }
-
-    @Override
-    public boolean hasField(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.hasField(field);
-      } else {
-        return super.hasField(field);
-      }
-    }
-
-    @Override
-    public Object getField(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        final Object value = extensions.getField(field);
-        if (value == null) {
-          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-            // Lacking an ExtensionRegistry, we have no way to determine the
-            // extension's real type, so we return a DynamicMessage.
-            return DynamicMessage.getDefaultInstance(field.getMessageType());
-          } else {
-            return field.getDefaultValue();
-          }
-        } else {
-          return value;
-        }
-      } else {
-        return super.getField(field);
-      }
-    }
-
-    @Override
-    public int getRepeatedFieldCount(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.getRepeatedFieldCount(field);
-      } else {
-        return super.getRepeatedFieldCount(field);
-      }
-    }
-
-    @Override
-    public Object getRepeatedField(final FieldDescriptor field,
-                                   final int index) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.getRepeatedField(field, index);
-      } else {
-        return super.getRepeatedField(field, index);
-      }
-    }
-
-    private void verifyContainingType(final FieldDescriptor field) {
-      if (field.getContainingType() != getDescriptorForType()) {
-        throw new IllegalArgumentException(
-          "FieldDescriptor does not match message type.");
-      }
-    }
-  }
-
-  /**
-   * Generated message builders for message types that contain extension ranges
-   * subclass this.
-   *
-   * <p>This class implements type-safe accessors for extensions.  They
-   * implement all the same operations that you can do with normal fields --
-   * e.g. "get", "set", and "add" -- but for extensions.  The extensions are
-   * identified using instances of the class {@link GeneratedExtension}; the
-   * protocol compiler generates a static instance of this class for every
-   * extension in its input.  Through the magic of generics, all is made
-   * type-safe.
-   *
-   * <p>For example, imagine you have the {@code .proto} file:
-   *
-   * <pre>
-   * option java_class = "MyProto";
-   *
-   * message Foo {
-   *   extensions 1000 to max;
-   * }
-   *
-   * extend Foo {
-   *   optional int32 bar;
-   * }
-   * </pre>
-   *
-   * <p>Then you might write code like:
-   *
-   * <pre>
-   * MyProto.Foo foo =
-   *   MyProto.Foo.newBuilder()
-   *     .setExtension(MyProto.bar, 123)
-   *     .build();
-   * </pre>
-   *
-   * <p>See also {@link ExtendableMessage}.
-   */
-  @SuppressWarnings("unchecked")
-  public abstract static class ExtendableBuilder<
-        MessageType extends ExtendableMessage,
-        BuilderType extends ExtendableBuilder>
-      extends Builder<BuilderType>
-      implements ExtendableMessageOrBuilder<MessageType> {
-
-    private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
-
-    protected ExtendableBuilder() {}
-
-    protected ExtendableBuilder(
-        BuilderParent parent) {
-      super(parent);
-    }
-
-    // For immutable message conversion.
-    void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
-      this.extensions = extensions;
-    }
-
-    @Override
-    public BuilderType clear() {
-      extensions = FieldSet.emptySet();
-      return super.clear();
-    }
-
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      throw new UnsupportedOperationException(
-          "This is supposed to be overridden by subclasses.");
-    }
-
-    private void ensureExtensionsIsMutable() {
-      if (extensions.isImmutable()) {
-        extensions = extensions.clone();
-      }
-    }
-
-    private void verifyExtensionContainingType(
-        final Extension<MessageType, ?> extension) {
-      if (extension.getDescriptor().getContainingType() !=
-          getDescriptorForType()) {
-        // This can only happen if someone uses unchecked operations.
-        throw new IllegalArgumentException(
-          "Extension is for type \"" +
-          extension.getDescriptor().getContainingType().getFullName() +
-          "\" which does not match message type \"" +
-          getDescriptorForType().getFullName() + "\".");
-      }
-    }
-
-    /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final Extension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.hasField(extension.getDescriptor());
-    }
-
-    /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> int getExtensionCount(
-        final Extension<MessageType, List<Type>> extension) {
-      verifyExtensionContainingType(extension);
-      final FieldDescriptor descriptor = extension.getDescriptor();
-      return extensions.getRepeatedFieldCount(descriptor);
-    }
-
-    /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> Type getExtension(
-        final Extension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      FieldDescriptor descriptor = extension.getDescriptor();
-      final Object value = extensions.getField(descriptor);
-      if (value == null) {
-        if (descriptor.isRepeated()) {
-          return (Type) Collections.emptyList();
-        } else if (descriptor.getJavaType() ==
-                   FieldDescriptor.JavaType.MESSAGE) {
-          return (Type) extension.getMessageDefaultInstance();
-        } else {
-          return (Type) extension.fromReflectionType(
-              descriptor.getDefaultValue());
-        }
-      } else {
-        return (Type) extension.fromReflectionType(value);
-      }
-    }
-
-    /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> Type getExtension(
-        final Extension<MessageType, List<Type>> extension,
-        final int index) {
-      verifyExtensionContainingType(extension);
-      FieldDescriptor descriptor = extension.getDescriptor();
-      return (Type) extension.singularFromReflectionType(
-          extensions.getRepeatedField(descriptor, index));
-    }
-
-    /** Set the value of an extension. */
-    public final <Type> BuilderType setExtension(
-        final Extension<MessageType, Type> extension,
-        final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      final FieldDescriptor descriptor = extension.getDescriptor();
-      extensions.setField(descriptor, extension.toReflectionType(value));
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    /** Set the value of one element of a repeated extension. */
-    public final <Type> BuilderType setExtension(
-        final Extension<MessageType, List<Type>> extension,
-        final int index, final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      final FieldDescriptor descriptor = extension.getDescriptor();
-      extensions.setRepeatedField(
-        descriptor, index,
-        extension.singularToReflectionType(value));
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    /** Append a value to a repeated extension. */
-    public final <Type> BuilderType addExtension(
-        final Extension<MessageType, List<Type>> extension,
-        final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      final FieldDescriptor descriptor = extension.getDescriptor();
-      extensions.addRepeatedField(
-          descriptor, extension.singularToReflectionType(value));
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    /** Clear an extension. */
-    public final <Type> BuilderType clearExtension(
-        final Extension<MessageType, ?> extension) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      extensions.clearField(extension.getDescriptor());
-      onChanged();
-      return (BuilderType) this;
-    }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    /**
-     * Called by the build code path to create a copy of the extensions for
-     * building the message.
-     */
-    private FieldSet<FieldDescriptor> buildExtensions() {
-      extensions.makeImmutable();
-      return extensions;
-    }
-
-    @Override
-    public boolean isInitialized() {
-      return super.isInitialized() && extensionsAreInitialized();
-    }
-
-    /**
-     * Called by subclasses to parse an unknown field or an extension.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    @Override
-    protected boolean parseUnknownField(
-        final CodedInputStream input,
-        final UnknownFieldSet.Builder unknownFields,
-        final ExtensionRegistryLite extensionRegistry,
-        final int tag) throws IOException {
-      return MessageReflection.mergeFieldFrom(
-          input, unknownFields, extensionRegistry, getDescriptorForType(),
-          new MessageReflection.BuilderAdapter(this), tag);
-    }
-
-    // ---------------------------------------------------------------
-    // Reflection
-
-    @Override
-    public Map<FieldDescriptor, Object> getAllFields() {
-      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
-      result.putAll(extensions.getAllFields());
-      return Collections.unmodifiableMap(result);
-    }
-
-    @Override
-    public Object getField(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        final Object value = extensions.getField(field);
-        if (value == null) {
-          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-            // Lacking an ExtensionRegistry, we have no way to determine the
-            // extension's real type, so we return a DynamicMessage.
-            return DynamicMessage.getDefaultInstance(field.getMessageType());
-          } else {
-            return field.getDefaultValue();
-          }
-        } else {
-          return value;
-        }
-      } else {
-        return super.getField(field);
-      }
-    }
-
-    @Override
-    public int getRepeatedFieldCount(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.getRepeatedFieldCount(field);
-      } else {
-        return super.getRepeatedFieldCount(field);
-      }
-    }
-
-    @Override
-    public Object getRepeatedField(final FieldDescriptor field,
-                                   final int index) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.getRepeatedField(field, index);
-      } else {
-        return super.getRepeatedField(field, index);
-      }
-    }
-
-    @Override
-    public boolean hasField(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        return extensions.hasField(field);
-      } else {
-        return super.hasField(field);
-      }
-    }
-
-    @Override
-    public BuilderType setField(final FieldDescriptor field,
-                                final Object value) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        ensureExtensionsIsMutable();
-        extensions.setField(field, value);
-        onChanged();
-        return (BuilderType) this;
-      } else {
-        return super.setField(field, value);
-      }
-    }
-
-    @Override
-    public BuilderType clearField(final FieldDescriptor field) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        ensureExtensionsIsMutable();
-        extensions.clearField(field);
-        onChanged();
-        return (BuilderType) this;
-      } else {
-        return super.clearField(field);
-      }
-    }
-
-    @Override
-    public BuilderType setRepeatedField(final FieldDescriptor field,
-                                        final int index, final Object value) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        ensureExtensionsIsMutable();
-        extensions.setRepeatedField(field, index, value);
-        onChanged();
-        return (BuilderType) this;
-      } else {
-        return super.setRepeatedField(field, index, value);
-      }
-    }
-
-    @Override
-    public BuilderType addRepeatedField(final FieldDescriptor field,
-                                        final Object value) {
-      if (field.isExtension()) {
-        verifyContainingType(field);
-        ensureExtensionsIsMutable();
-        extensions.addRepeatedField(field, value);
-        onChanged();
-        return (BuilderType) this;
-      } else {
-        return super.addRepeatedField(field, value);
-      }
-    }
-
-    protected final void mergeExtensionFields(final ExtendableMessage other) {
-      ensureExtensionsIsMutable();
-      extensions.mergeFrom(other.extensions);
-      onChanged();
-    }
-
-    private void verifyContainingType(final FieldDescriptor field) {
-      if (field.getContainingType() != getDescriptorForType()) {
-        throw new IllegalArgumentException(
-          "FieldDescriptor does not match message type.");
-      }
-    }
-  }
-
-  // -----------------------------------------------------------------
-
-  /**
-   * Gets the descriptor for an extension. The implementation depends on whether
-   * the extension is scoped in the top level of a file or scoped in a Message.
-   */
-  static interface ExtensionDescriptorRetriever {
-    FieldDescriptor getDescriptor();
-  }
-
-  /** For use by generated code only. */
-  public static <ContainingType extends Message, Type>
-      GeneratedExtension<ContainingType, Type>
-      newMessageScopedGeneratedExtension(final Message scope,
-                                         final int descriptorIndex,
-                                         final Class singularType,
-                                         final Message defaultInstance) {
-    // For extensions scoped within a Message, we use the Message to resolve
-    // the outer class's descriptor, from which the extension descriptor is
-    // obtained.
-    return new GeneratedExtension<ContainingType, Type>(
-        new CachedDescriptorRetriever() {
-          //@Override (Java 1.6 override semantics, but we must support 1.5)
-          public FieldDescriptor loadDescriptor() {
-            return scope.getDescriptorForType().getExtensions()
-                .get(descriptorIndex);
-          }
-        },
-        singularType,
-        defaultInstance,
-        Extension.ExtensionType.IMMUTABLE);
-  }
-
-  /** For use by generated code only. */
-  public static <ContainingType extends Message, Type>
-     GeneratedExtension<ContainingType, Type>
-     newFileScopedGeneratedExtension(final Class singularType,
-                                     final Message defaultInstance) {
-    // For extensions scoped within a file, we rely on the outer class's
-    // static initializer to call internalInit() on the extension when the
-    // descriptor is available.
-    return new GeneratedExtension<ContainingType, Type>(
-        null,  // ExtensionDescriptorRetriever is initialized in internalInit();
-        singularType,
-        defaultInstance,
-        Extension.ExtensionType.IMMUTABLE);
-  }
-
-  private abstract static class CachedDescriptorRetriever
-      implements ExtensionDescriptorRetriever {
-    private volatile FieldDescriptor descriptor;
-    protected abstract FieldDescriptor loadDescriptor();
-    
-    public FieldDescriptor getDescriptor() {
-      if (descriptor == null) {
-        synchronized (this) {
-          if (descriptor == null) {
-            descriptor = loadDescriptor();
-          }
-        }
-      }
-      return descriptor;
-    }
-  }
-
-  /**
-   * Used in proto1 generated code only.
-   *
-   * After enabling bridge, we can define proto2 extensions (the extended type
-   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
-   * we should generate proto2 GeneratedExtensions.
-   */
-  public static <ContainingType extends Message, Type>
-      GeneratedExtension<ContainingType, Type>
-      newMessageScopedGeneratedExtension(
-          final Message scope, final String name,
-          final Class singularType, final Message defaultInstance) {
-    // For extensions scoped within a Message, we use the Message to resolve
-    // the outer class's descriptor, from which the extension descriptor is
-    // obtained.
-    return new GeneratedExtension<ContainingType, Type>(
-        new CachedDescriptorRetriever() {
-          protected FieldDescriptor loadDescriptor() {
-            return scope.getDescriptorForType().findFieldByName(name);
-          }
-        },
-        singularType,
-        defaultInstance,
-        Extension.ExtensionType.MUTABLE);
-  }
-
-  /**
-   * Used in proto1 generated code only.
-   *
-   * After enabling bridge, we can define proto2 extensions (the extended type
-   * is a proto2 mutable message) in a proto1 .proto file. For these extensions
-   * we should generate proto2 GeneratedExtensions.
-   */
-  public static <ContainingType extends Message, Type>
-     GeneratedExtension<ContainingType, Type>
-     newFileScopedGeneratedExtension(
-         final Class singularType, final Message defaultInstance,
-         final String descriptorOuterClass, final String extensionName) {
-    // For extensions scoped within a file, we load the descriptor outer
-    // class and rely on it to get the FileDescriptor which then can be
-    // used to obtain the extension's FieldDescriptor.
-    return new GeneratedExtension<ContainingType, Type>(
-        new CachedDescriptorRetriever() {
-          protected FieldDescriptor loadDescriptor() {
-            try {
-              Class clazz =
-                  singularType.getClassLoader().loadClass(descriptorOuterClass);
-              FileDescriptor file =
-                  (FileDescriptor) clazz.getField("descriptor").get(null);
-              return file.findExtensionByName(extensionName);
-            } catch (Exception e) {
-              throw new RuntimeException(
-                  "Cannot load descriptors: " + descriptorOuterClass +
-                  " is not a valid descriptor class name", e);
-            }
-          }
-        },
-        singularType,
-        defaultInstance,
-        Extension.ExtensionType.MUTABLE);
-  }
-
-  /**
-   * Type used to represent generated extensions.  The protocol compiler
-   * generates a static singleton instance of this class for each extension.
-   *
-   * <p>For example, imagine you have the {@code .proto} file:
-   *
-   * <pre>
-   * option java_class = "MyProto";
-   *
-   * message Foo {
-   *   extensions 1000 to max;
-   * }
-   *
-   * extend Foo {
-   *   optional int32 bar;
-   * }
-   * </pre>
-   *
-   * <p>Then, {@code MyProto.Foo.bar} has type
-   * {@code GeneratedExtension<MyProto.Foo, Integer>}.
-   *
-   * <p>In general, users should ignore the details of this type, and simply use
-   * these static singletons as parameters to the extension accessors defined
-   * in {@link ExtendableMessage} and {@link ExtendableBuilder}.
-   */
-  public static class GeneratedExtension<
-      ContainingType extends Message, Type> extends
-      Extension<ContainingType, Type> {
-    // TODO(kenton):  Find ways to avoid using Java reflection within this
-    //   class.  Also try to avoid suppressing unchecked warnings.
-
-    // We can't always initialize the descriptor of a GeneratedExtension when
-    // we first construct it due to initialization order difficulties (namely,
-    // the descriptor may not have been constructed yet, since it is often
-    // constructed by the initializer of a separate module).
-    //
-    // In the case of nested extensions, we initialize the
-    // ExtensionDescriptorRetriever with an instance that uses the scoping
-    // Message's default instance to retrieve the extension's descriptor.
-    //
-    // In the case of non-nested extensions, we initialize the
-    // ExtensionDescriptorRetriever to null and rely on the outer class's static
-    // initializer to call internalInit() after the descriptor has been parsed.
-    GeneratedExtension(ExtensionDescriptorRetriever descriptorRetriever,
-        Class singularType,
-        Message messageDefaultInstance,
-        ExtensionType extensionType) {
-      if (Message.class.isAssignableFrom(singularType) &&
-          !singularType.isInstance(messageDefaultInstance)) {
-        throw new IllegalArgumentException(
-            "Bad messageDefaultInstance for " + singularType.getName());
-      }
-      this.descriptorRetriever = descriptorRetriever;
-      this.singularType = singularType;
-      this.messageDefaultInstance = messageDefaultInstance;
-
-      if (ProtocolMessageEnum.class.isAssignableFrom(singularType)) {
-        this.enumValueOf = getMethodOrDie(singularType, "valueOf",
-                                          EnumValueDescriptor.class);
-        this.enumGetValueDescriptor =
-            getMethodOrDie(singularType, "getValueDescriptor");
-      } else {
-        this.enumValueOf = null;
-        this.enumGetValueDescriptor = null;
-      }
-      this.extensionType = extensionType;
-    }
-
-    /** For use by generated code only. */
-    public void internalInit(final FieldDescriptor descriptor) {
-      if (descriptorRetriever != null) {
-        throw new IllegalStateException("Already initialized.");
-      }
-      descriptorRetriever = new ExtensionDescriptorRetriever() {
-          //@Override (Java 1.6 override semantics, but we must support 1.5)
-          public FieldDescriptor getDescriptor() {
-            return descriptor;
-          }
-        };
-    }
-
-    private ExtensionDescriptorRetriever descriptorRetriever;
-    private final Class singularType;
-    private final Message messageDefaultInstance;
-    private final Method enumValueOf;
-    private final Method enumGetValueDescriptor;
-    private final ExtensionType extensionType;
-
-    public FieldDescriptor getDescriptor() {
-      if (descriptorRetriever == null) {
-        throw new IllegalStateException(
-            "getDescriptor() called before internalInit()");
-      }
-      return descriptorRetriever.getDescriptor();
-    }
-
-    /**
-     * If the extension is an embedded message or group, returns the default
-     * instance of the message.
-     */
-    public Message getMessageDefaultInstance() {
-      return messageDefaultInstance;
-    }
-
-    protected ExtensionType getExtensionType() {
-      return extensionType;
-    }
-
-    /**
-     * Convert from the type used by the reflection accessors to the type used
-     * by native accessors.  E.g., for enums, the reflection accessors use
-     * EnumValueDescriptors but the native accessors use the generated enum
-     * type.
-     */
-    // @Override
-    @SuppressWarnings("unchecked")
-    protected Object fromReflectionType(final Object value) {
-      FieldDescriptor descriptor = getDescriptor();
-      if (descriptor.isRepeated()) {
-        if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
-            descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
-          // Must convert the whole list.
-          final List result = new ArrayList();
-          for (final Object element : (List) value) {
-            result.add(singularFromReflectionType(element));
-          }
-          return result;
-        } else {
-          return value;
-        }
-      } else {
-        return singularFromReflectionType(value);
-      }
-    }
-
-    /**
-     * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
-     * type, this converts a single element.
-     */
-    // @Override
-    protected Object singularFromReflectionType(final Object value) {
-      FieldDescriptor descriptor = getDescriptor();
-      switch (descriptor.getJavaType()) {
-        case MESSAGE:
-          if (singularType.isInstance(value)) {
-            return value;
-          } else {
-            return messageDefaultInstance.newBuilderForType()
-                .mergeFrom((Message) value).build();
-          }
-        case ENUM:
-          return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
-        default:
-          return value;
-      }
-    }
-
-    /**
-     * Convert from the type used by the native accessors to the type used
-     * by reflection accessors.  E.g., for enums, the reflection accessors use
-     * EnumValueDescriptors but the native accessors use the generated enum
-     * type.
-     */
-    // @Override
-    @SuppressWarnings("unchecked")
-    protected Object toReflectionType(final Object value) {
-      FieldDescriptor descriptor = getDescriptor();
-      if (descriptor.isRepeated()) {
-        if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
-          // Must convert the whole list.
-          final List result = new ArrayList();
-          for (final Object element : (List) value) {
-            result.add(singularToReflectionType(element));
-          }
-          return result;
-        } else {
-          return value;
-        }
-      } else {
-        return singularToReflectionType(value);
-      }
-    }
-
-    /**
-     * Like {@link #toReflectionType(Object)}, but if the type is a repeated
-     * type, this converts a single element.
-     */
-    // @Override
-    protected Object singularToReflectionType(final Object value) {
-      FieldDescriptor descriptor = getDescriptor();
-      switch (descriptor.getJavaType()) {
-        case ENUM:
-          return invokeOrDie(enumGetValueDescriptor, value);
-        default:
-          return value;
-      }
-    }
-
-    // @Override
-    public int getNumber() {
-      return getDescriptor().getNumber();
-    }
-
-    // @Override
-    public WireFormat.FieldType getLiteType() {
-      return getDescriptor().getLiteType();
-    }
-
-    // @Override
-    public boolean isRepeated() {
-      return getDescriptor().isRepeated();
-    }
-
-    // @Override
-    @SuppressWarnings("unchecked")
-    public Type getDefaultValue() {
-      if (isRepeated()) {
-        return (Type) Collections.emptyList();
-      }
-      if (getDescriptor().getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        return (Type) messageDefaultInstance;
-      }
-      return (Type) singularFromReflectionType(
-          getDescriptor().getDefaultValue());
-    }
-  }
-
-  // =================================================================
-
-  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
-  @SuppressWarnings("unchecked")
-  private static Method getMethodOrDie(
-      final Class clazz, final String name, final Class... params) {
-    try {
-      return clazz.getMethod(name, params);
-    } catch (NoSuchMethodException e) {
-      throw new RuntimeException(
-        "Generated message class \"" + clazz.getName() +
-        "\" missing method \"" + name + "\".", e);
-    }
-  }
-
-  /** Calls invoke and throws a RuntimeException if it fails. */
-  private static Object invokeOrDie(
-      final Method method, final Object object, final Object... params) {
-    try {
-      return method.invoke(object, params);
-    } catch (IllegalAccessException e) {
-      throw new RuntimeException(
-        "Couldn't use Java reflection to implement protocol message " +
-        "reflection.", e);
-    } catch (InvocationTargetException e) {
-      final Throwable cause = e.getCause();
-      if (cause instanceof RuntimeException) {
-        throw (RuntimeException) cause;
-      } else if (cause instanceof Error) {
-        throw (Error) cause;
-      } else {
-        throw new RuntimeException(
-          "Unexpected exception thrown by generated accessor method.", cause);
-      }
-    }
-  }
-
-  /**
-   * Users should ignore this class.  This class provides the implementation
-   * with access to the fields of a message object using Java reflection.
-   */
-  public static final class FieldAccessorTable {
-
-    /**
-     * Construct a FieldAccessorTable for a particular message class.  Only
-     * one FieldAccessorTable should ever be constructed per class.
-     *
-     * @param descriptor     The type's descriptor.
-     * @param camelCaseNames The camelcase names of all fields in the message.
-     *                       These are used to derive the accessor method names.
-     * @param messageClass   The message type.
-     * @param builderClass   The builder type.
-     */
-    public FieldAccessorTable(
-        final Descriptor descriptor,
-        final String[] camelCaseNames,
-        final Class<? extends GeneratedMessage> messageClass,
-        final Class<? extends Builder> builderClass) {
-      this(descriptor, camelCaseNames);
-      ensureFieldAccessorsInitialized(messageClass, builderClass);
-    }
-
-    /**
-     * Construct a FieldAccessorTable for a particular message class without
-     * initializing FieldAccessors.
-     */
-    public FieldAccessorTable(
-        final Descriptor descriptor,
-        final String[] camelCaseNames) {
-      this.descriptor = descriptor;
-      this.camelCaseNames = camelCaseNames;
-      fields = new FieldAccessor[descriptor.getFields().size()];
-      oneofs = new OneofAccessor[descriptor.getOneofs().size()];
-      initialized = false;
-    }
-
-    /**
-     * Ensures the field accessors are initialized. This method is thread-safe.
-     *
-     * @param messageClass   The message type.
-     * @param builderClass   The builder type.
-     * @return this
-     */
-    public FieldAccessorTable ensureFieldAccessorsInitialized(
-        Class<? extends GeneratedMessage> messageClass,
-        Class<? extends Builder> builderClass) {
-      if (initialized) { return this; }
-      synchronized (this) {
-        if (initialized) { return this; }
-        int fieldsSize = fields.length;
-        for (int i = 0; i < fieldsSize; i++) {
-          FieldDescriptor field = descriptor.getFields().get(i);
-          String containingOneofCamelCaseName = null;
-          if (field.getContainingOneof() != null) {
-            containingOneofCamelCaseName =
-                camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
-          }
-          if (field.isRepeated()) {
-            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-              fields[i] = new RepeatedMessageFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
-            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
-              fields[i] = new RepeatedEnumFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
-            } else {
-              fields[i] = new RepeatedFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass);
-            }
-          } else {
-            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-              fields[i] = new SingularMessageFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass,
-                  containingOneofCamelCaseName);
-            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
-              fields[i] = new SingularEnumFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass,
-                  containingOneofCamelCaseName);
-            } else {
-              fields[i] = new SingularFieldAccessor(
-                  field, camelCaseNames[i], messageClass, builderClass,
-                  containingOneofCamelCaseName);
-            }
-          }
-        }
-
-        int oneofsSize = oneofs.length;
-        for (int i = 0; i < oneofsSize; i++) {
-          oneofs[i] = new OneofAccessor(
-              descriptor, camelCaseNames[i + fieldsSize],
-              messageClass, builderClass);
-        }
-        initialized = true;
-        camelCaseNames = null;
-        return this;
-      }
-    }
-
-    private final Descriptor descriptor;
-    private final FieldAccessor[] fields;
-    private String[] camelCaseNames;
-    private final OneofAccessor[] oneofs;
-    private volatile boolean initialized;
-
-    /** Get the FieldAccessor for a particular field. */
-    private FieldAccessor getField(final FieldDescriptor field) {
-      if (field.getContainingType() != descriptor) {
-        throw new IllegalArgumentException(
-          "FieldDescriptor does not match message type.");
-      } else if (field.isExtension()) {
-        // If this type had extensions, it would subclass ExtendableMessage,
-        // which overrides the reflection interface to handle extensions.
-        throw new IllegalArgumentException(
-          "This type does not have extensions.");
-      }
-      return fields[field.getIndex()];
-    }
-
-    /** Get the OneofAccessor for a particular oneof. */
-    private OneofAccessor getOneof(final OneofDescriptor oneof) {
-      if (oneof.getContainingType() != descriptor) {
-        throw new IllegalArgumentException(
-          "OneofDescriptor does not match message type.");
-      }
-      return oneofs[oneof.getIndex()];
-    }
-
-    /**
-     * Abstract interface that provides access to a single field.  This is
-     * implemented differently depending on the field type and cardinality.
-     */
-    private interface FieldAccessor {
-      Object get(GeneratedMessage message);
-      Object get(GeneratedMessage.Builder builder);
-      void set(Builder builder, Object value);
-      Object getRepeated(GeneratedMessage message, int index);
-      Object getRepeated(GeneratedMessage.Builder builder, int index);
-      void setRepeated(Builder builder,
-                       int index, Object value);
-      void addRepeated(Builder builder, Object value);
-      boolean has(GeneratedMessage message);
-      boolean has(GeneratedMessage.Builder builder);
-      int getRepeatedCount(GeneratedMessage message);
-      int getRepeatedCount(GeneratedMessage.Builder builder);
-      void clear(Builder builder);
-      Message.Builder newBuilder();
-      Message.Builder getBuilder(GeneratedMessage.Builder builder);
-    }
-
-    /** OneofAccessor provides access to a single oneof. */
-    private static class OneofAccessor {
-      OneofAccessor(
-          final Descriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        this.descriptor = descriptor;
-        caseMethod =
-            getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
-        caseMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
-        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
-      }
-
-      private final Descriptor descriptor;
-      private final Method caseMethod;
-      private final Method caseMethodBuilder;
-      private final Method clearMethod;
-
-      public boolean has(final GeneratedMessage message) {
-        if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
-          return false;
-        }
-        return true;
-      }
-
-      public boolean has(GeneratedMessage.Builder builder) {
-        if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
-          return false;
-        }
-        return true;
-      }
-
-      public FieldDescriptor get(final GeneratedMessage message) {
-        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
-        if (fieldNumber > 0) {
-          return descriptor.findFieldByNumber(fieldNumber);
-        }
-        return null;
-      }
-
-      public FieldDescriptor get(GeneratedMessage.Builder builder) {
-        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
-        if (fieldNumber > 0) {
-          return descriptor.findFieldByNumber(fieldNumber);
-        }
-        return null;
-      }
-
-      public void clear(final Builder builder) {
-        invokeOrDie(clearMethod, builder);
-      }
-    }
-    
-    private static boolean supportFieldPresence(FileDescriptor file) {
-      return true;
-    }
-
-    // ---------------------------------------------------------------
-
-    private static class SingularFieldAccessor implements FieldAccessor {
-      SingularFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass,
-          final String containingOneofCamelCaseName) {
-        field = descriptor;
-        isOneofField = descriptor.getContainingOneof() != null;
-        hasHasMethod = supportFieldPresence(descriptor.getFile())
-            || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
-        getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
-        getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
-        type = getMethod.getReturnType();
-        setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
-        hasMethod =
-            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
-        hasMethodBuilder =
-            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
-        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
-        caseMethod = isOneofField ? getMethodOrDie(
-            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
-        caseMethodBuilder = isOneofField ? getMethodOrDie(
-            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
-      }
-
-      // Note:  We use Java reflection to call public methods rather than
-      //   access private fields directly as this avoids runtime security
-      //   checks.
-      protected final Class<?> type;
-      protected final Method getMethod;
-      protected final Method getMethodBuilder;
-      protected final Method setMethod;
-      protected final Method hasMethod;
-      protected final Method hasMethodBuilder;
-      protected final Method clearMethod;
-      protected final Method caseMethod;
-      protected final Method caseMethodBuilder;
-      protected final FieldDescriptor field;
-      protected final boolean isOneofField;
-      protected final boolean hasHasMethod;
-      
-      private int getOneofFieldNumber(final GeneratedMessage message) {
-        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
-      }
-      
-      private int getOneofFieldNumber(final GeneratedMessage.Builder builder) {
-        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
-      }
-
-      public Object get(final GeneratedMessage message) {
-        return invokeOrDie(getMethod, message);
-      }
-      public Object get(GeneratedMessage.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
-      }
-      public void set(final Builder builder, final Object value) {
-        invokeOrDie(setMethod, builder, value);
-      }
-      public Object getRepeated(final GeneratedMessage message,
-                                final int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedField() called on a singular field.");
-      }
-      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedField() called on a singular field.");
-      }
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
-        throw new UnsupportedOperationException(
-          "setRepeatedField() called on a singular field.");
-      }
-      public void addRepeated(final Builder builder, final Object value) {
-        throw new UnsupportedOperationException(
-          "addRepeatedField() called on a singular field.");
-      }
-      public boolean has(final GeneratedMessage message) {
-        if (!hasHasMethod) {
-          if (isOneofField) {
-            return getOneofFieldNumber(message) == field.getNumber();
-          }
-          return !get(message).equals(field.getDefaultValue());
-        }
-        return (Boolean) invokeOrDie(hasMethod, message);
-      }
-      public boolean has(GeneratedMessage.Builder builder) {
-        if (!hasHasMethod) {
-          if (isOneofField) {
-            return getOneofFieldNumber(builder) == field.getNumber();
-          }
-          return !get(builder).equals(field.getDefaultValue());
-        }
-        return (Boolean) invokeOrDie(hasMethodBuilder, builder);
-      }
-      public int getRepeatedCount(final GeneratedMessage message) {
-        throw new UnsupportedOperationException(
-          "getRepeatedFieldSize() called on a singular field.");
-      }
-      public int getRepeatedCount(GeneratedMessage.Builder builder) {
-        throw new UnsupportedOperationException(
-          "getRepeatedFieldSize() called on a singular field.");
-      }
-      public void clear(final Builder builder) {
-        invokeOrDie(clearMethod, builder);
-      }
-      public Message.Builder newBuilder() {
-        throw new UnsupportedOperationException(
-          "newBuilderForField() called on a non-Message type.");
-      }
-      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
-        throw new UnsupportedOperationException(
-          "getFieldBuilder() called on a non-Message type.");
-      }
-    }
-
-    private static class RepeatedFieldAccessor implements FieldAccessor {
-      protected final Class type;
-      protected final Method getMethod;
-      protected final Method getMethodBuilder;
-      protected final Method getRepeatedMethod;
-      protected final Method getRepeatedMethodBuilder;
-      protected final Method setRepeatedMethod;
-      protected final Method addRepeatedMethod;
-      protected final Method getCountMethod;
-      protected final Method getCountMethodBuilder;
-      protected final Method clearMethod;
-
-      RepeatedFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        getMethod = getMethodOrDie(messageClass,
-                                   "get" + camelCaseName + "List");
-        getMethodBuilder = getMethodOrDie(builderClass,
-                                   "get" + camelCaseName + "List");
-        getRepeatedMethod =
-            getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
-        getRepeatedMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
-        type = getRepeatedMethod.getReturnType();
-        setRepeatedMethod =
-            getMethodOrDie(builderClass, "set" + camelCaseName,
-                           Integer.TYPE, type);
-        addRepeatedMethod =
-            getMethodOrDie(builderClass, "add" + camelCaseName, type);
-        getCountMethod =
-            getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
-        getCountMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
-
-        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
-      }
-
-      public Object get(final GeneratedMessage message) {
-        return invokeOrDie(getMethod, message);
-      }
-      public Object get(GeneratedMessage.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
-      }
-      public void set(final Builder builder, final Object value) {
-        // Add all the elements individually.  This serves two purposes:
-        // 1) Verifies that each element has the correct type.
-        // 2) Insures that the caller cannot modify the list later on and
-        //    have the modifications be reflected in the message.
-        clear(builder);
-        for (final Object element : (List<?>) value) {
-          addRepeated(builder, element);
-        }
-      }
-      public Object getRepeated(final GeneratedMessage message,
-                                final int index) {
-        return invokeOrDie(getRepeatedMethod, message, index);
-      }
-      public Object getRepeated(GeneratedMessage.Builder builder, int index) {
-        return invokeOrDie(getRepeatedMethodBuilder, builder, index);
-      }
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
-        invokeOrDie(setRepeatedMethod, builder, index, value);
-      }
-      public void addRepeated(final Builder builder, final Object value) {
-        invokeOrDie(addRepeatedMethod, builder, value);
-      }
-      public boolean has(final GeneratedMessage message) {
-        throw new UnsupportedOperationException(
-          "hasField() called on a repeated field.");
-      }
-      public boolean has(GeneratedMessage.Builder builder) {
-        throw new UnsupportedOperationException(
-          "hasField() called on a repeated field.");
-      }
-      public int getRepeatedCount(final GeneratedMessage message) {
-        return (Integer) invokeOrDie(getCountMethod, message);
-      }
-      public int getRepeatedCount(GeneratedMessage.Builder builder) {
-        return (Integer) invokeOrDie(getCountMethodBuilder, builder);
-      }
-      public void clear(final Builder builder) {
-        invokeOrDie(clearMethod, builder);
-      }
-      public Message.Builder newBuilder() {
-        throw new UnsupportedOperationException(
-          "newBuilderForField() called on a non-Message type.");
-      }
-      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
-        throw new UnsupportedOperationException(
-          "getFieldBuilder() called on a non-Message type.");
-      }
-    }
-
-    // ---------------------------------------------------------------
-
-    private static final class SingularEnumFieldAccessor
-        extends SingularFieldAccessor {
-      SingularEnumFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass,
-          final String containingOneofCamelCaseName) {
-        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
-
-        valueOfMethod = getMethodOrDie(type, "valueOf",
-                                       EnumValueDescriptor.class);
-        getValueDescriptorMethod =
-          getMethodOrDie(type, "getValueDescriptor");
-      }
-
-      private Method valueOfMethod;
-      private Method getValueDescriptorMethod;
-
-      @Override
-      public Object get(final GeneratedMessage message) {
-        return invokeOrDie(getValueDescriptorMethod, super.get(message));
-      }
-
-      @Override
-      public Object get(final GeneratedMessage.Builder builder) {
-        return invokeOrDie(getValueDescriptorMethod, super.get(builder));
-      }
-
-      @Override
-      public void set(final Builder builder, final Object value) {
-        super.set(builder, invokeOrDie(valueOfMethod, null, value));
-      }
-    }
-
-    private static final class RepeatedEnumFieldAccessor
-        extends RepeatedFieldAccessor {
-      RepeatedEnumFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        super(descriptor, camelCaseName, messageClass, builderClass);
-
-        valueOfMethod = getMethodOrDie(type, "valueOf",
-                                       EnumValueDescriptor.class);
-        getValueDescriptorMethod =
-          getMethodOrDie(type, "getValueDescriptor");
-      }
-
-      private final Method valueOfMethod;
-      private final Method getValueDescriptorMethod;
-
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object get(final GeneratedMessage message) {
-        final List newList = new ArrayList();
-        for (final Object element : (List) super.get(message)) {
-          newList.add(invokeOrDie(getValueDescriptorMethod, element));
-        }
-        return Collections.unmodifiableList(newList);
-      }
-
-      @Override
-      @SuppressWarnings("unchecked")
-      public Object get(final GeneratedMessage.Builder builder) {
-        final List newList = new ArrayList();
-        for (final Object element : (List) super.get(builder)) {
-          newList.add(invokeOrDie(getValueDescriptorMethod, element));
-        }
-        return Collections.unmodifiableList(newList);
-      }
-
-      @Override
-      public Object getRepeated(final GeneratedMessage message,
-                                final int index) {
-        return invokeOrDie(getValueDescriptorMethod,
-          super.getRepeated(message, index));
-      }
-      @Override
-      public Object getRepeated(final GeneratedMessage.Builder builder,
-                                final int index) {
-        return invokeOrDie(getValueDescriptorMethod,
-          super.getRepeated(builder, index));
-      }
-      @Override
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
-        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
-                          value));
-      }
-      @Override
-      public void addRepeated(final Builder builder, final Object value) {
-        super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
-      }
-    }
-
-    // ---------------------------------------------------------------
-
-    private static final class SingularMessageFieldAccessor
-        extends SingularFieldAccessor {
-      SingularMessageFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass,
-          final String containingOneofCamelCaseName) {
-        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
-
-        newBuilderMethod = getMethodOrDie(type, "newBuilder");
-        getBuilderMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
-      }
-
-      private final Method newBuilderMethod;
-      private final Method getBuilderMethodBuilder;
-
-      private Object coerceType(final Object value) {
-        if (type.isInstance(value)) {
-          return value;
-        } else {
-          // The value is not the exact right message type.  However, if it
-          // is an alternative implementation of the same type -- e.g. a
-          // DynamicMessage -- we should accept it.  In this case we can make
-          // a copy of the message.
-          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
-                  .mergeFrom((Message) value).buildPartial();
-        }
-      }
-
-      @Override
-      public void set(final Builder builder, final Object value) {
-        super.set(builder, coerceType(value));
-      }
-      @Override
-      public Message.Builder newBuilder() {
-        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
-      }
-      @Override
-      public Message.Builder getBuilder(GeneratedMessage.Builder builder) {
-        return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
-      }
-    }
-
-    private static final class RepeatedMessageFieldAccessor
-        extends RepeatedFieldAccessor {
-      RepeatedMessageFieldAccessor(
-          final FieldDescriptor descriptor, final String camelCaseName,
-          final Class<? extends GeneratedMessage> messageClass,
-          final Class<? extends Builder> builderClass) {
-        super(descriptor, camelCaseName, messageClass, builderClass);
-
-        newBuilderMethod = getMethodOrDie(type, "newBuilder");
-      }
-
-      private final Method newBuilderMethod;
-
-      private Object coerceType(final Object value) {
-        if (type.isInstance(value)) {
-          return value;
-        } else {
-          // The value is not the exact right message type.  However, if it
-          // is an alternative implementation of the same type -- e.g. a
-          // DynamicMessage -- we should accept it.  In this case we can make
-          // a copy of the message.
-          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
-                  .mergeFrom((Message) value).build();
-        }
-      }
-
-      @Override
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
-        super.setRepeated(builder, index, coerceType(value));
-      }
-      @Override
-      public void addRepeated(final Builder builder, final Object value) {
-        super.addRepeated(builder, coerceType(value));
-      }
-      @Override
-      public Message.Builder newBuilder() {
-        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
-      }
-    }
-  }
-
-  /**
-   * Replaces this object in the output stream with a serialized form.
-   * Part of Java's serialization magic.  Generated sub-classes must override
-   * this method by calling {@code return super.writeReplace();}
-   * @return a SerializedForm of this message
-   */
-  protected Object writeReplace() throws ObjectStreamException {
-    return new GeneratedMessageLite.SerializedForm(this);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
deleted file mode 100644
index 6c5136f..0000000
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ /dev/null
@@ -1,949 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Lite version of {@link GeneratedMessage}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public abstract class GeneratedMessageLite extends AbstractMessageLite
-    implements Serializable {
-  private static final long serialVersionUID = 1L;
-
-  protected GeneratedMessageLite() {
-  }
-
-  protected GeneratedMessageLite(Builder builder) {
-  }
-
-  public Parser<? extends MessageLite> getParserForType() {
-    throw new UnsupportedOperationException(
-        "This is supposed to be overridden by subclasses.");
-  }
-
-  /**
-   * Called by subclasses to parse an unknown field.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  protected boolean parseUnknownField(
-      CodedInputStream input,
-      CodedOutputStream unknownFieldsCodedOutput,
-      ExtensionRegistryLite extensionRegistry,
-      int tag) throws IOException {
-    return input.skipField(tag, unknownFieldsCodedOutput);
-  }
-
-  /**
-   * Used by parsing constructors in generated classes.
-   */
-  protected void makeExtensionsImmutable() {
-    // Noop for messages without extensions.
-  }
-
-  @SuppressWarnings("unchecked")
-  public abstract static class Builder<MessageType extends GeneratedMessageLite,
-                                       BuilderType extends Builder>
-      extends AbstractMessageLite.Builder<BuilderType> {
-    protected Builder() {}
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clear() {
-      unknownFields = ByteString.EMPTY;
-      return (BuilderType) this;
-    }
-
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      throw new UnsupportedOperationException(
-          "This is supposed to be overridden by subclasses.");
-    }
-
-    /** All subclasses implement this. */
-    public abstract BuilderType mergeFrom(MessageType message);
-
-    // Defined here for return type covariance.
-    public abstract MessageType getDefaultInstanceForType();
-
-    /**
-     * Called by subclasses to parse an unknown field.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        CodedOutputStream unknownFieldsCodedOutput,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      return input.skipField(tag, unknownFieldsCodedOutput);
-    }
-
-    public final ByteString getUnknownFields() {
-      return unknownFields;
-    }
-
-    public final BuilderType setUnknownFields(final ByteString unknownFields) {
-      this.unknownFields = unknownFields;
-      return (BuilderType) this;
-    }
-
-    private ByteString unknownFields = ByteString.EMPTY;
-  }
-
-
-  // =================================================================
-  // Extensions-related stuff
-
-  /**
-   * Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
-   */
-  public interface ExtendableMessageOrBuilder<
-      MessageType extends ExtendableMessage> extends MessageLiteOrBuilder {
-
-    /** Check if a singular extension is present. */
-    <Type> boolean hasExtension(
-        GeneratedExtension<MessageType, Type> extension);
-
-    /** Get the number of elements in a repeated extension. */
-    <Type> int getExtensionCount(
-        GeneratedExtension<MessageType, List<Type>> extension);
-
-    /** Get the value of an extension. */
-    <Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
-
-    /** Get one element of a repeated extension. */
-    <Type> Type getExtension(
-        GeneratedExtension<MessageType, List<Type>> extension,
-        int index);
-  }
-
-  /**
-   * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
-   */
-  public abstract static class ExtendableMessage<
-        MessageType extends ExtendableMessage<MessageType>>
-      extends GeneratedMessageLite
-      implements ExtendableMessageOrBuilder<MessageType> {
-
-    private final FieldSet<ExtensionDescriptor> extensions;
-
-    protected ExtendableMessage() {
-      this.extensions = FieldSet.newFieldSet();
-    }
-
-    protected ExtendableMessage(ExtendableBuilder<MessageType, ?> builder) {
-      this.extensions = builder.buildExtensions();
-    }
-
-    private void verifyExtensionContainingType(
-        final GeneratedExtension<MessageType, ?> extension) {
-      if (extension.getContainingTypeDefaultInstance() !=
-          getDefaultInstanceForType()) {
-        // This can only happen if someone uses unchecked operations.
-        throw new IllegalArgumentException(
-          "This extension is for a different message type.  Please make " +
-          "sure that you are not suppressing any generics type warnings.");
-      }
-    }
-
-    /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.hasField(extension.descriptor);
-    }
-
-    /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> int getExtensionCount(
-        final GeneratedExtension<MessageType, List<Type>> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.getRepeatedFieldCount(extension.descriptor);
-    }
-
-    /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      final Object value = extensions.getField(extension.descriptor);
-      if (value == null) {
-        return extension.defaultValue;
-      } else {
-        return (Type) extension.fromFieldSetType(value);
-      }
-    }
-
-    /** Get one element of a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
-        final int index) {
-      verifyExtensionContainingType(extension);
-      return (Type) extension.singularFromFieldSetType(
-          extensions.getRepeatedField(extension.descriptor, index));
-    }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    /**
-     * Called by subclasses to parse an unknown field or an extension.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    @Override
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        CodedOutputStream unknownFieldsCodedOutput,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      return GeneratedMessageLite.parseUnknownField(
-          extensions,
-          getDefaultInstanceForType(),
-          input,
-          unknownFieldsCodedOutput,
-          extensionRegistry,
-          tag);
-    }
-
-
-    /**
-     * Used by parsing constructors in generated classes.
-     */
-    @Override
-    protected void makeExtensionsImmutable() {
-      extensions.makeImmutable();
-    }
-
-    /**
-     * Used by subclasses to serialize extensions.  Extension ranges may be
-     * interleaved with field numbers, but we must write them in canonical
-     * (sorted by field number) order.  ExtensionWriter helps us write
-     * individual ranges of extensions at once.
-     */
-    protected class ExtensionWriter {
-      // Imagine how much simpler this code would be if Java iterators had
-      // a way to get the next element without advancing the iterator.
-
-      private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
-            extensions.iterator();
-      private Map.Entry<ExtensionDescriptor, Object> next;
-      private final boolean messageSetWireFormat;
-
-      private ExtensionWriter(boolean messageSetWireFormat) {
-        if (iter.hasNext()) {
-          next = iter.next();
-        }
-        this.messageSetWireFormat = messageSetWireFormat;
-      }
-
-      public void writeUntil(final int end, final CodedOutputStream output)
-                             throws IOException {
-        while (next != null && next.getKey().getNumber() < end) {
-          ExtensionDescriptor extension = next.getKey();
-          if (messageSetWireFormat && extension.getLiteJavaType() ==
-                  WireFormat.JavaType.MESSAGE &&
-              !extension.isRepeated()) {
-            output.writeMessageSetExtension(extension.getNumber(),
-                                            (MessageLite) next.getValue());
-          } else {
-            FieldSet.writeField(extension, next.getValue(), output);
-          }
-          if (iter.hasNext()) {
-            next = iter.next();
-          } else {
-            next = null;
-          }
-        }
-      }
-    }
-
-    protected ExtensionWriter newExtensionWriter() {
-      return new ExtensionWriter(false);
-    }
-    protected ExtensionWriter newMessageSetExtensionWriter() {
-      return new ExtensionWriter(true);
-    }
-
-    /** Called by subclasses to compute the size of extensions. */
-    protected int extensionsSerializedSize() {
-      return extensions.getSerializedSize();
-    }
-    protected int extensionsSerializedSizeAsMessageSet() {
-      return extensions.getMessageSetSerializedSize();
-    }
-  }
-
-  /**
-   * Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
-   */
-  @SuppressWarnings("unchecked")
-  public abstract static class ExtendableBuilder<
-        MessageType extends ExtendableMessage<MessageType>,
-        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
-      extends Builder<MessageType, BuilderType>
-      implements ExtendableMessageOrBuilder<MessageType> {
-    protected ExtendableBuilder() {}
-
-    private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
-    private boolean extensionsIsMutable;
-
-    // For immutable message conversion.
-    void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
-      this.extensions = extensions;
-    }
-
-    @Override
-    public BuilderType clear() {
-      extensions.clear();
-      extensionsIsMutable = false;
-      return super.clear();
-    }
-
-    private void ensureExtensionsIsMutable() {
-      if (!extensionsIsMutable) {
-        extensions = extensions.clone();
-        extensionsIsMutable = true;
-      }
-    }
-
-    /**
-     * Called by the build code path to create a copy of the extensions for
-     * building the message.
-     */
-    private FieldSet<ExtensionDescriptor> buildExtensions() {
-      extensions.makeImmutable();
-      extensionsIsMutable = false;
-      return extensions;
-    }
-
-    private void verifyExtensionContainingType(
-        final GeneratedExtension<MessageType, ?> extension) {
-      if (extension.getContainingTypeDefaultInstance() !=
-          getDefaultInstanceForType()) {
-        // This can only happen if someone uses unchecked operations.
-        throw new IllegalArgumentException(
-          "This extension is for a different message type.  Please make " +
-          "sure that you are not suppressing any generics type warnings.");
-      }
-    }
-
-    /** Check if a singular extension is present. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> boolean hasExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.hasField(extension.descriptor);
-    }
-
-    /** Get the number of elements in a repeated extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> int getExtensionCount(
-        final GeneratedExtension<MessageType, List<Type>> extension) {
-      verifyExtensionContainingType(extension);
-      return extensions.getRepeatedFieldCount(extension.descriptor);
-    }
-
-    /** Get the value of an extension. */
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    @SuppressWarnings("unchecked")
-    public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, Type> extension) {
-      verifyExtensionContainingType(extension);
-      final Object value = extensions.getField(extension.descriptor);
-      if (value == null) {
-        return extension.defaultValue;
-      } else {
-        return (Type) extension.fromFieldSetType(value);
-      }
-    }
-
-    /** Get one element of a repeated extension. */
-    @SuppressWarnings("unchecked")
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public final <Type> Type getExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
-        final int index) {
-      verifyExtensionContainingType(extension);
-      return (Type) extension.singularFromFieldSetType(
-          extensions.getRepeatedField(extension.descriptor, index));
-    }
-
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      throw new UnsupportedOperationException(
-          "This is supposed to be overridden by subclasses.");
-    }
-
-    /** Set the value of an extension. */
-    public final <Type> BuilderType setExtension(
-        final GeneratedExtension<MessageType, Type> extension,
-        final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      extensions.setField(extension.descriptor,
-                          extension.toFieldSetType(value));
-      return (BuilderType) this;
-    }
-
-    /** Set the value of one element of a repeated extension. */
-    public final <Type> BuilderType setExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
-        final int index, final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      extensions.setRepeatedField(extension.descriptor, index,
-                                  extension.singularToFieldSetType(value));
-      return (BuilderType) this;
-    }
-
-    /** Append a value to a repeated extension. */
-    public final <Type> BuilderType addExtension(
-        final GeneratedExtension<MessageType, List<Type>> extension,
-        final Type value) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      extensions.addRepeatedField(extension.descriptor,
-                                  extension.singularToFieldSetType(value));
-      return (BuilderType) this;
-    }
-
-    /** Clear an extension. */
-    public final <Type> BuilderType clearExtension(
-        final GeneratedExtension<MessageType, ?> extension) {
-      verifyExtensionContainingType(extension);
-      ensureExtensionsIsMutable();
-      extensions.clearField(extension.descriptor);
-      return (BuilderType) this;
-    }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    /**
-     * Called by subclasses to parse an unknown field or an extension.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    @Override
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        CodedOutputStream unknownFieldsCodedOutput,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      ensureExtensionsIsMutable();
-      return GeneratedMessageLite.parseUnknownField(
-          extensions,
-          getDefaultInstanceForType(),
-          input,
-          unknownFieldsCodedOutput,
-          extensionRegistry,
-          tag);
-    }
-
-    protected final void mergeExtensionFields(final MessageType other) {
-      ensureExtensionsIsMutable();
-      extensions.mergeFrom(((ExtendableMessage) other).extensions);
-    }
-  }
-
-  // -----------------------------------------------------------------
-
-  /**
-   * Parse an unknown field or an extension.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  private static <MessageType extends MessageLite>
-      boolean parseUnknownField(
-          FieldSet<ExtensionDescriptor> extensions,
-          MessageType defaultInstance,
-          CodedInputStream input,
-          CodedOutputStream unknownFieldsCodedOutput,
-          ExtensionRegistryLite extensionRegistry,
-          int tag) throws IOException {
-    int wireType = WireFormat.getTagWireType(tag);
-    int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
-    GeneratedExtension<MessageType, ?> extension =
-      extensionRegistry.findLiteExtensionByNumber(
-          defaultInstance, fieldNumber);
-
-    boolean unknown = false;
-    boolean packed = false;
-    if (extension == null) {
-      unknown = true;  // Unknown field.
-    } else if (wireType == FieldSet.getWireFormatForFieldType(
-                 extension.descriptor.getLiteType(),
-                 false  /* isPacked */)) {
-      packed = false;  // Normal, unpacked value.
-    } else if (extension.descriptor.isRepeated &&
-               extension.descriptor.type.isPackable() &&
-               wireType == FieldSet.getWireFormatForFieldType(
-                 extension.descriptor.getLiteType(),
-                 true  /* isPacked */)) {
-      packed = true;  // Packed value.
-    } else {
-      unknown = true;  // Wrong wire type.
-    }
-
-    if (unknown) {  // Unknown field or wrong wire type.  Skip.
-      return input.skipField(tag, unknownFieldsCodedOutput);
-    }
-
-    if (packed) {
-      int length = input.readRawVarint32();
-      int limit = input.pushLimit(length);
-      if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
-        while (input.getBytesUntilLimit() > 0) {
-          int rawValue = input.readEnum();
-          Object value =
-              extension.descriptor.getEnumType().findValueByNumber(rawValue);
-          if (value == null) {
-            // If the number isn't recognized as a valid value for this
-            // enum, drop it (don't even add it to unknownFields).
-            return true;
-          }
-          extensions.addRepeatedField(extension.descriptor,
-                                      extension.singularToFieldSetType(value));
-        }
-      } else {
-        while (input.getBytesUntilLimit() > 0) {
-          Object value =
-              FieldSet.readPrimitiveField(input,
-                                          extension.descriptor.getLiteType(),
-                                          /*checkUtf8=*/ false);
-          extensions.addRepeatedField(extension.descriptor, value);
-        }
-      }
-      input.popLimit(limit);
-    } else {
-      Object value;
-      switch (extension.descriptor.getLiteJavaType()) {
-        case MESSAGE: {
-          MessageLite.Builder subBuilder = null;
-          if (!extension.descriptor.isRepeated()) {
-            MessageLite existingValue =
-                (MessageLite) extensions.getField(extension.descriptor);
-            if (existingValue != null) {
-              subBuilder = existingValue.toBuilder();
-            }
-          }
-          if (subBuilder == null) {
-            subBuilder = extension.getMessageDefaultInstance()
-                .newBuilderForType();
-          }
-          if (extension.descriptor.getLiteType() ==
-              WireFormat.FieldType.GROUP) {
-            input.readGroup(extension.getNumber(),
-                            subBuilder, extensionRegistry);
-          } else {
-            input.readMessage(subBuilder, extensionRegistry);
-          }
-          value = subBuilder.build();
-          break;
-        }
-        case ENUM:
-          int rawValue = input.readEnum();
-          value = extension.descriptor.getEnumType()
-                           .findValueByNumber(rawValue);
-          // If the number isn't recognized as a valid value for this enum,
-          // write it to unknown fields object.
-          if (value == null) {
-            unknownFieldsCodedOutput.writeRawVarint32(tag);
-            unknownFieldsCodedOutput.writeUInt32NoTag(rawValue);
-            return true;
-          }
-          break;
-        default:
-          value = FieldSet.readPrimitiveField(input,
-              extension.descriptor.getLiteType(),
-              /*checkUtf8=*/ false);
-          break;
-      }
-
-      if (extension.descriptor.isRepeated()) {
-        extensions.addRepeatedField(extension.descriptor,
-                                    extension.singularToFieldSetType(value));
-      } else {
-        extensions.setField(extension.descriptor,
-                            extension.singularToFieldSetType(value));
-      }
-    }
-
-    return true;
-  }
-
-  // -----------------------------------------------------------------
-
-  /** For use by generated code only. */
-  public static <ContainingType extends MessageLite, Type>
-      GeneratedExtension<ContainingType, Type>
-          newSingularGeneratedExtension(
-              final ContainingType containingTypeDefaultInstance,
-              final Type defaultValue,
-              final MessageLite messageDefaultInstance,
-              final Internal.EnumLiteMap<?> enumTypeMap,
-              final int number,
-              final WireFormat.FieldType type,
-              final Class singularType) {
-    return new GeneratedExtension<ContainingType, Type>(
-        containingTypeDefaultInstance,
-        defaultValue,
-        messageDefaultInstance,
-        new ExtensionDescriptor(enumTypeMap, number, type,
-                                false /* isRepeated */,
-                                false /* isPacked */),
-        singularType);
-  }
-
-  /** For use by generated code only. */
-  public static <ContainingType extends MessageLite, Type>
-      GeneratedExtension<ContainingType, Type>
-          newRepeatedGeneratedExtension(
-              final ContainingType containingTypeDefaultInstance,
-              final MessageLite messageDefaultInstance,
-              final Internal.EnumLiteMap<?> enumTypeMap,
-              final int number,
-              final WireFormat.FieldType type,
-              final boolean isPacked,
-              final Class singularType) {
-    @SuppressWarnings("unchecked")  // Subclasses ensure Type is a List
-    Type emptyList = (Type) Collections.emptyList();
-    return new GeneratedExtension<ContainingType, Type>(
-        containingTypeDefaultInstance,
-        emptyList,
-        messageDefaultInstance,
-        new ExtensionDescriptor(
-            enumTypeMap, number, type, true /* isRepeated */, isPacked),
-        singularType);
-  }
-
-  static final class ExtensionDescriptor
-      implements FieldSet.FieldDescriptorLite<
-        ExtensionDescriptor> {
-    ExtensionDescriptor(
-        final Internal.EnumLiteMap<?> enumTypeMap,
-        final int number,
-        final WireFormat.FieldType type,
-        final boolean isRepeated,
-        final boolean isPacked) {
-      this.enumTypeMap = enumTypeMap;
-      this.number = number;
-      this.type = type;
-      this.isRepeated = isRepeated;
-      this.isPacked = isPacked;
-    }
-
-    final Internal.EnumLiteMap<?> enumTypeMap;
-    final int number;
-    final WireFormat.FieldType type;
-    final boolean isRepeated;
-    final boolean isPacked;
-
-    public int getNumber() {
-      return number;
-    }
-
-    public WireFormat.FieldType getLiteType() {
-      return type;
-    }
-
-    public WireFormat.JavaType getLiteJavaType() {
-      return type.getJavaType();
-    }
-
-    public boolean isRepeated() {
-      return isRepeated;
-    }
-
-    public boolean isPacked() {
-      return isPacked;
-    }
-
-    public Internal.EnumLiteMap<?> getEnumType() {
-      return enumTypeMap;
-    }
-
-    @SuppressWarnings("unchecked")
-    public MessageLite.Builder internalMergeFrom(
-        MessageLite.Builder to, MessageLite from) {
-      return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
-    }
-
-
-    public int compareTo(ExtensionDescriptor other) {
-      return number - other.number;
-    }
-  }
-
-  // =================================================================
-
-  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
-  @SuppressWarnings("unchecked")
-  static Method getMethodOrDie(Class clazz, String name, Class... params) {
-    try {
-      return clazz.getMethod(name, params);
-    } catch (NoSuchMethodException e) {
-      throw new RuntimeException(
-        "Generated message class \"" + clazz.getName() +
-        "\" missing method \"" + name + "\".", e);
-    }
-  }
-
-  /** Calls invoke and throws a RuntimeException if it fails. */
-  static Object invokeOrDie(Method method, Object object, Object... params) {
-    try {
-      return method.invoke(object, params);
-    } catch (IllegalAccessException e) {
-      throw new RuntimeException(
-        "Couldn't use Java reflection to implement protocol message " +
-        "reflection.", e);
-    } catch (InvocationTargetException e) {
-      final Throwable cause = e.getCause();
-      if (cause instanceof RuntimeException) {
-        throw (RuntimeException) cause;
-      } else if (cause instanceof Error) {
-        throw (Error) cause;
-      } else {
-        throw new RuntimeException(
-          "Unexpected exception thrown by generated accessor method.", cause);
-      }
-    }
-  }
-
-  /**
-   * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
-   *
-   * Users should ignore the contents of this class and only use objects of
-   * this type as parameters to extension accessors and ExtensionRegistry.add().
-   */
-  public static class GeneratedExtension<
-      ContainingType extends MessageLite, Type> {
-
-    /**
-     * Create a new isntance with the given parameters.
-     *
-     * The last parameter {@code singularType} is only needed for enum types.
-     * We store integer values for enum types in a {@link ExtendableMessage}
-     * and use Java reflection to convert an integer value back into a concrete
-     * enum object.
-     */
-    GeneratedExtension(
-        final ContainingType containingTypeDefaultInstance,
-        final Type defaultValue,
-        final MessageLite messageDefaultInstance,
-        final ExtensionDescriptor descriptor,
-        Class singularType) {
-      // Defensive checks to verify the correct initialization order of
-      // GeneratedExtensions and their related GeneratedMessages.
-      if (containingTypeDefaultInstance == null) {
-        throw new IllegalArgumentException(
-            "Null containingTypeDefaultInstance");
-      }
-      if (descriptor.getLiteType() == WireFormat.FieldType.MESSAGE &&
-          messageDefaultInstance == null) {
-        throw new IllegalArgumentException(
-            "Null messageDefaultInstance");
-      }
-      this.containingTypeDefaultInstance = containingTypeDefaultInstance;
-      this.defaultValue = defaultValue;
-      this.messageDefaultInstance = messageDefaultInstance;
-      this.descriptor = descriptor;
-
-      // Use Java reflection to invoke the static method {@code valueOf} of
-      // enum types in order to convert integers to concrete enum objects.
-      this.singularType = singularType;
-      if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
-        this.enumValueOf = getMethodOrDie(
-            singularType, "valueOf", int.class);
-      } else {
-        this.enumValueOf = null;
-      }
-    }
-
-    final ContainingType containingTypeDefaultInstance;
-    final Type defaultValue;
-    final MessageLite messageDefaultInstance;
-    final ExtensionDescriptor descriptor;
-    final Class singularType;
-    final Method enumValueOf;
-
-    /**
-     * Default instance of the type being extended, used to identify that type.
-     */
-    public ContainingType getContainingTypeDefaultInstance() {
-      return containingTypeDefaultInstance;
-    }
-
-    /** Get the field number. */
-    public int getNumber() {
-      return descriptor.getNumber();
-    }
-
-
-    /**
-     * If the extension is an embedded message or group, returns the default
-     * instance of the message.
-     */
-    public MessageLite getMessageDefaultInstance() {
-      return messageDefaultInstance;
-    }
-
-    @SuppressWarnings("unchecked")
-    Object fromFieldSetType(final Object value) {
-      if (descriptor.isRepeated()) {
-        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
-          final List result = new ArrayList();
-          for (final Object element : (List) value) {
-            result.add(singularFromFieldSetType(element));
-          }
-          return result;
-        } else {
-          return value;
-        }
-      } else {
-        return singularFromFieldSetType(value);
-      }
-    }
-
-    Object singularFromFieldSetType(final Object value) {
-      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
-        return invokeOrDie(enumValueOf, null, (Integer) value);
-      } else {
-        return value;
-      }
-    }
-
-    @SuppressWarnings("unchecked")
-    Object toFieldSetType(final Object value) {
-      if (descriptor.isRepeated()) {
-        if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
-          final List result = new ArrayList();
-          for (final Object element : (List) value) {
-            result.add(singularToFieldSetType(element));
-          }
-          return result;
-        } else {
-          return value;
-        }
-      } else {
-        return singularToFieldSetType(value);
-      }
-    }
-
-    Object singularToFieldSetType(final Object value) {
-      if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
-        return ((Internal.EnumLite) value).getNumber();
-      } else {
-        return value;
-      }
-    }
-  }
-
-  /**
-   * A serialized (serializable) form of the generated message.  Stores the
-   * message as a class name and a byte array.
-   */
-  static final class SerializedForm implements Serializable {
-    private static final long serialVersionUID = 0L;
-
-    private String messageClassName;
-    private byte[] asBytes;
-
-    /**
-     * Creates the serialized form by calling {@link com.google.protobuf.MessageLite#toByteArray}.
-     * @param regularForm the message to serialize
-     */
-    SerializedForm(MessageLite regularForm) {
-      messageClassName = regularForm.getClass().getName();
-      asBytes = regularForm.toByteArray();
-    }
-
-    /**
-     * When read from an ObjectInputStream, this method converts this object
-     * back to the regular form.  Part of Java's serialization magic.
-     * @return a GeneratedMessage of the type that was serialized
-     */
-    @SuppressWarnings("unchecked")
-    protected Object readResolve() throws ObjectStreamException {
-      try {
-        Class messageClass = Class.forName(messageClassName);
-        Method newBuilder = messageClass.getMethod("newBuilder");
-        MessageLite.Builder builder =
-            (MessageLite.Builder) newBuilder.invoke(null);
-        builder.mergeFrom(asBytes);
-        return builder.buildPartial();
-      } catch (ClassNotFoundException e) {
-        throw new RuntimeException("Unable to find proto buffer class", e);
-      } catch (NoSuchMethodException e) {
-        throw new RuntimeException("Unable to find newBuilder method", e);
-      } catch (IllegalAccessException e) {
-        throw new RuntimeException("Unable to call newBuilder method", e);
-      } catch (InvocationTargetException e) {
-        throw new RuntimeException("Error calling newBuilder", e.getCause());
-      } catch (InvalidProtocolBufferException e) {
-        throw new RuntimeException("Unable to understand proto buffer", e);
-      }
-    }
-  }
-
-  /**
-   * Replaces this object in the output stream with a serialized form.
-   * Part of Java's serialization magic.  Generated sub-classes must override
-   * this method by calling {@code return super.writeReplace();}
-   * @return a SerializedForm of this message
-   */
-  protected Object writeReplace() throws ObjectStreamException {
-    return new SerializedForm(this);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java
deleted file mode 100644
index 48d29e6..0000000
--- a/java/src/main/java/com/google/protobuf/Internal.java
+++ /dev/null
@@ -1,391 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * The classes contained within are used internally by the Protocol Buffer
- * library and generated message implementations. They are public only because
- * those generated messages do not reside in the {@code protobuf} package.
- * Others should not use this class directly.
- *
- * @author kenton@google.com (Kenton Varda)
- */
-public class Internal {
-  /**
-   * Helper called by generated code to construct default values for string
-   * fields.
-   * <p>
-   * The protocol compiler does not actually contain a UTF-8 decoder -- it
-   * just pushes UTF-8-encoded text around without touching it.  The one place
-   * where this presents a problem is when generating Java string literals.
-   * Unicode characters in the string literal would normally need to be encoded
-   * using a Unicode escape sequence, which would require decoding them.
-   * To get around this, protoc instead embeds the UTF-8 bytes into the
-   * generated code and leaves it to the runtime library to decode them.
-   * <p>
-   * It gets worse, though.  If protoc just generated a byte array, like:
-   *   new byte[] {0x12, 0x34, 0x56, 0x78}
-   * Java actually generates *code* which allocates an array and then fills
-   * in each value.  This is much less efficient than just embedding the bytes
-   * directly into the bytecode.  To get around this, we need another
-   * work-around.  String literals are embedded directly, so protoc actually
-   * generates a string literal corresponding to the bytes.  The easiest way
-   * to do this is to use the ISO-8859-1 character set, which corresponds to
-   * the first 256 characters of the Unicode range.  Protoc can then use
-   * good old CEscape to generate the string.
-   * <p>
-   * So we have a string literal which represents a set of bytes which
-   * represents another string.  This function -- stringDefaultValue --
-   * converts from the generated string to the string we actually want.  The
-   * generated code calls this automatically.
-   */
-  public static String stringDefaultValue(String bytes) {
-    try {
-      return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      // This should never happen since all JVMs are required to implement
-      // both of the above character sets.
-      throw new IllegalStateException(
-          "Java VM does not support a standard character set.", e);
-    }
-  }
-
-  /**
-   * Helper called by generated code to construct default values for bytes
-   * fields.
-   * <p>
-   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
-   * In this case we only need the second of the two hacks -- allowing us to
-   * embed raw bytes as a string literal with ISO-8859-1 encoding.
-   */
-  public static ByteString bytesDefaultValue(String bytes) {
-    try {
-      return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
-    } catch (UnsupportedEncodingException e) {
-      // This should never happen since all JVMs are required to implement
-      // ISO-8859-1.
-      throw new IllegalStateException(
-          "Java VM does not support a standard character set.", e);
-    }
-  }
-  /**
-   * Helper called by generated code to construct default values for bytes
-   * fields.
-   * <p>
-   * This is like {@link #bytesDefaultValue}, but returns a byte array. 
-   */
-  public static byte[] byteArrayDefaultValue(String bytes) {
-    try {
-      return bytes.getBytes("ISO-8859-1");
-    } catch (UnsupportedEncodingException e) {
-      // This should never happen since all JVMs are required to implement
-      // ISO-8859-1.
-      throw new IllegalStateException(
-          "Java VM does not support a standard character set.", e);
-    }
-  }
-
-  /**
-   * Helper called by generated code to construct default values for bytes
-   * fields.
-   * <p>
-   * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer. 
-   */
-  public static ByteBuffer byteBufferDefaultValue(String bytes) {
-    return ByteBuffer.wrap(byteArrayDefaultValue(bytes));
-  }
-
-  /**
-   * Create a new ByteBuffer and copy all the content of {@code source}
-   * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and
-   * capacity will be source.capacity(), and its position will be 0.
-   * Note that the state of {@code source} ByteBuffer won't be changed.
-   */
-  public static ByteBuffer copyByteBuffer(ByteBuffer source) {
-    // Make a duplicate of the source ByteBuffer and read data from the
-    // duplicate. This is to avoid affecting the source ByteBuffer's state.
-    ByteBuffer temp = source.duplicate();
-    // We want to copy all the data in the source ByteBuffer, not just the
-    // remaining bytes.
-    temp.clear();
-    ByteBuffer result = ByteBuffer.allocate(temp.capacity());
-    result.put(temp);
-    result.clear();
-    return result;
-  }
-
-  /**
-   * Helper called by generated code to determine if a byte array is a valid
-   * UTF-8 encoded string such that the original bytes can be converted to
-   * a String object and then back to a byte array round tripping the bytes
-   * without loss.  More precisely, returns {@code true} whenever:
-   * <pre>   {@code
-   * Arrays.equals(byteString.toByteArray(),
-   *     new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
-   * }</pre>
-   *
-   * <p>This method rejects "overlong" byte sequences, as well as
-   * 3-byte sequences that would map to a surrogate character, in
-   * accordance with the restricted definition of UTF-8 introduced in
-   * Unicode 3.1.  Note that the UTF-8 decoder included in Oracle's
-   * JDK has been modified to also reject "overlong" byte sequences,
-   * but currently (2011) still accepts 3-byte surrogate character
-   * byte sequences.
-   *
-   * <p>See the Unicode Standard,</br>
-   * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
-   * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
-   *
-   * <p>As of 2011-02, this method simply returns the result of {@link
-   * ByteString#isValidUtf8()}.  Calling that method directly is preferred.
-   *
-   * @param byteString the string to check
-   * @return whether the byte array is round trippable
-   */
-  public static boolean isValidUtf8(ByteString byteString) {
-    return byteString.isValidUtf8();
-  }
-  
-  /**
-   * Like {@link #isValidUtf8(ByteString)} but for byte arrays.
-   */
-  public static boolean isValidUtf8(byte[] byteArray) {
-    return Utf8.isValidUtf8(byteArray);
-  }
-
-  /**
-   * Helper method to get the UTF-8 bytes of a string.
-   */
-  public static byte[] toByteArray(String value) {
-    try {
-      return value.getBytes("UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported?", e);
-    }
-  }
-  
-  /**
-   * Helper method to convert a byte array to a string using UTF-8 encoding.
-   */
-  public static String toStringUtf8(byte[] bytes) {
-    try {
-      return new String(bytes, "UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported?", e);
-    }
-  }
-
-  /**
-   * Interface for an enum value or value descriptor, to be used in FieldSet.
-   * The lite library stores enum values directly in FieldSets but the full
-   * library stores EnumValueDescriptors in order to better support reflection.
-   */
-  public interface EnumLite {
-    int getNumber();
-  }
-
-  /**
-   * Interface for an object which maps integers to {@link EnumLite}s.
-   * {@link Descriptors.EnumDescriptor} implements this interface by mapping
-   * numbers to {@link Descriptors.EnumValueDescriptor}s.  Additionally,
-   * every generated enum type has a static method internalGetValueMap() which
-   * returns an implementation of this type that maps numbers to enum values.
-   */
-  public interface EnumLiteMap<T extends EnumLite> {
-    T findValueByNumber(int number);
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for longs.
-   * @see Long#hashCode()
-   */
-  public static int hashLong(long n) {
-    return (int) (n ^ (n >>> 32));
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for
-   * booleans.
-   * @see Boolean#hashCode()
-   */
-  public static int hashBoolean(boolean b) {
-    return b ? 1231 : 1237;
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for enums.
-   * <p>
-   * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
-   * need to use the field number as the hash code to ensure compatibility
-   * between statically and dynamically generated enum objects.
-   */
-  public static int hashEnum(EnumLite e) {
-    return e.getNumber();
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for
-   * enum lists.
-   */
-  public static int hashEnumList(List<? extends EnumLite> list) {
-    int hash = 1;
-    for (EnumLite e : list) {
-      hash = 31 * hash + hashEnum(e);
-    }
-    return hash;
-  }
-  
-  /**
-   * Helper method for implementing {@link MessageLite#equals()} for bytes field.
-   */
-  public static boolean equals(List<byte[]> a, List<byte[]> b) {
-    if (a.size() != b.size()) return false;
-    for (int i = 0; i < a.size(); ++i) {
-      if (!Arrays.equals(a.get(i), b.get(i))) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for bytes field.
-   */
-  public static int hashCode(List<byte[]> list) {
-    int hash = 1;
-    for (byte[] bytes : list) {
-      hash = 31 * hash + hashCode(bytes);
-    }
-    return hash;
-  }
-  
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for bytes field.
-   */
-  public static int hashCode(byte[] bytes) {
-    // The hash code for a byte array should be the same as the hash code for a
-    // ByteString with the same content. This is to ensure that the generated
-    // hashCode() method will return the same value as the pure reflection
-    // based hashCode() method.
-    return LiteralByteString.hashCode(bytes);
-  }
-  
-  /**
-   * Helper method for implementing {@link MessageLite#equals()} for bytes
-   * field.
-   */
-  public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) {
-    if (a.capacity() != b.capacity()) {
-      return false;
-    }
-    // ByteBuffer.equals() will only compare the remaining bytes, but we want to
-    // compare all the content.
-    return a.duplicate().clear().equals(b.duplicate().clear());
-  }
-  
-  /**
-   * Helper method for implementing {@link MessageLite#equals()} for bytes
-   * field.
-   */
-  public static boolean equalsByteBuffer(
-      List<ByteBuffer> a, List<ByteBuffer> b) {
-    if (a.size() != b.size()) {
-      return false;
-    }
-    for (int i = 0; i < a.size(); ++i) {
-      if (!equalsByteBuffer(a.get(i), b.get(i))) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for bytes
-   * field.
-   */
-  public static int hashCodeByteBuffer(List<ByteBuffer> list) {
-    int hash = 1;
-    for (ByteBuffer bytes : list) {
-      hash = 31 * hash + hashCodeByteBuffer(bytes);
-    }
-    return hash;
-  }
-  
-  private static final int DEFAULT_BUFFER_SIZE = 4096;
-  
-  /**
-   * Helper method for implementing {@link MessageLite#hashCode()} for bytes
-   * field.
-   */
-  public static int hashCodeByteBuffer(ByteBuffer bytes) {
-    if (bytes.hasArray()) {
-      // Fast path.
-      int h = LiteralByteString.hashCode(bytes.capacity(), bytes.array(),
-          bytes.arrayOffset(), bytes.capacity());
-      return h == 0 ? 1 : h;
-    } else {
-      // Read the data into a temporary byte array before calculating the
-      // hash value.
-      final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE
-          ? DEFAULT_BUFFER_SIZE : bytes.capacity();
-      final byte[] buffer = new byte[bufferSize];
-      final ByteBuffer duplicated = bytes.duplicate();
-      duplicated.clear();
-      int h = bytes.capacity();
-      while (duplicated.remaining() > 0) {
-        final int length = duplicated.remaining() <= bufferSize ?
-            duplicated.remaining() : bufferSize;
-        duplicated.get(buffer, 0, length);
-        h = LiteralByteString.hashCode(h, buffer, 0, length);
-      }
-      return h == 0 ? 1 : h;
-    }
-  }
-  
-  /**
-   * An empty byte array constant used in generated code.
-   */
-  public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-  
-  /**
-   * An empty byte array constant used in generated code.
-   */
-  public static final ByteBuffer EMPTY_BYTE_BUFFER =
-      ByteBuffer.wrap(EMPTY_BYTE_ARRAY);
-
-}
diff --git a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
deleted file mode 100644
index 367fa23..0000000
--- a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ /dev/null
@@ -1,122 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-
-/**
- * Thrown when a protocol message being parsed is invalid in some way,
- * e.g. it contains a malformed varint or a negative byte length.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class InvalidProtocolBufferException extends IOException {
-  private static final long serialVersionUID = -1616151763072450476L;
-  private MessageLite unfinishedMessage = null;
-
-  public InvalidProtocolBufferException(final String description) {
-    super(description);
-  }
-
-  /**
-   * Attaches an unfinished message to the exception to support best-effort
-   * parsing in {@code Parser} interface.
-   *
-   * @return this
-   */
-  public InvalidProtocolBufferException setUnfinishedMessage(
-      MessageLite unfinishedMessage) {
-    this.unfinishedMessage = unfinishedMessage;
-    return this;
-  }
-
-  /**
-   * Returns the unfinished message attached to the exception, or null if
-   * no message is attached.
-   */
-  public MessageLite getUnfinishedMessage() {
-    return unfinishedMessage;
-  }
-
-  static InvalidProtocolBufferException truncatedMessage() {
-    return new InvalidProtocolBufferException(
-      "While parsing a protocol message, the input ended unexpectedly " +
-      "in the middle of a field.  This could mean either than the " +
-      "input has been truncated or that an embedded message " +
-      "misreported its own length.");
-  }
-
-  static InvalidProtocolBufferException negativeSize() {
-    return new InvalidProtocolBufferException(
-      "CodedInputStream encountered an embedded string or message " +
-      "which claimed to have negative size.");
-  }
-
-  static InvalidProtocolBufferException malformedVarint() {
-    return new InvalidProtocolBufferException(
-      "CodedInputStream encountered a malformed varint.");
-  }
-
-  static InvalidProtocolBufferException invalidTag() {
-    return new InvalidProtocolBufferException(
-      "Protocol message contained an invalid tag (zero).");
-  }
-
-  static InvalidProtocolBufferException invalidEndTag() {
-    return new InvalidProtocolBufferException(
-      "Protocol message end-group tag did not match expected tag.");
-  }
-
-  static InvalidProtocolBufferException invalidWireType() {
-    return new InvalidProtocolBufferException(
-      "Protocol message tag had invalid wire type.");
-  }
-
-  static InvalidProtocolBufferException recursionLimitExceeded() {
-    return new InvalidProtocolBufferException(
-      "Protocol message had too many levels of nesting.  May be malicious.  " +
-      "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
-  }
-
-  static InvalidProtocolBufferException sizeLimitExceeded() {
-    return new InvalidProtocolBufferException(
-      "Protocol message was too large.  May be malicious.  " +
-      "Use CodedInputStream.setSizeLimit() to increase the size limit.");
-  }
-
-  static InvalidProtocolBufferException parseFailure() {
-    return new InvalidProtocolBufferException("Failed to parse the message.");
-  }
-
-  static InvalidProtocolBufferException invalidUtf8() {
-    return new InvalidProtocolBufferException("Protocol message had invalid UTF-8.");
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/LazyField.java b/java/src/main/java/com/google/protobuf/LazyField.java
deleted file mode 100644
index 3da8b90..0000000
--- a/java/src/main/java/com/google/protobuf/LazyField.java
+++ /dev/null
@@ -1,154 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.Iterator;
-import java.util.Map.Entry;
-
-/**
- * LazyField encapsulates the logic of lazily parsing message fields. It stores
- * the message in a ByteString initially and then parse it on-demand.
- *
- * Most of key methods are implemented in {@link LazyFieldLite} but this class
- * can contain default instance of the message to provide {@code hashCode()},
- * {@code euqals()} and {@code toString()}.
- *
- * @author xiangl@google.com (Xiang Li)
- */
-public class LazyField extends LazyFieldLite {
-
-  /**
-   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
-   * {@code toString()}.
-   */
-  private final MessageLite defaultInstance;
-
-  public LazyField(MessageLite defaultInstance,
-      ExtensionRegistryLite extensionRegistry, ByteString bytes) {
-    super(extensionRegistry, bytes);
-
-    this.defaultInstance = defaultInstance;
-  }
-
-  @Override
-  public boolean containsDefaultInstance() {
-    return super.containsDefaultInstance() || value == defaultInstance;
-  }
-
-  public MessageLite getValue() {
-    return getValue(defaultInstance);
-  }
-
-  @Override
-  public int hashCode() {
-    return getValue().hashCode();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    return getValue().equals(obj);
-  }
-
-  @Override
-  public String toString() {
-    return getValue().toString();
-  }
-
-  // ====================================================
-
-  /**
-   * LazyEntry and LazyIterator are used to encapsulate the LazyField, when
-   * users iterate all fields from FieldSet.
-   */
-  static class LazyEntry<K> implements Entry<K, Object> {
-    private Entry<K, LazyField> entry;
-
-    private LazyEntry(Entry<K, LazyField> entry) {
-      this.entry = entry;
-    }
-
-    // @Override
-    public K getKey() {
-      return entry.getKey();
-    }
-
-    // @Override
-    public Object getValue() {
-      LazyField field = entry.getValue();
-      if (field == null) {
-        return null;
-      }
-      return field.getValue();
-    }
-
-    public LazyField getField() {
-      return entry.getValue();
-    }
-
-    // @Override
-    public Object setValue(Object value) {
-      if (!(value instanceof MessageLite)) {
-        throw new IllegalArgumentException(
-            "LazyField now only used for MessageSet, "
-            + "and the value of MessageSet must be an instance of MessageLite");
-      }
-      return entry.getValue().setValue((MessageLite) value);
-    }
-  }
-
-  static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
-    private Iterator<Entry<K, Object>> iterator;
-
-    public LazyIterator(Iterator<Entry<K, Object>> iterator) {
-      this.iterator = iterator;
-    }
-
-    // @Override
-    public boolean hasNext() {
-      return iterator.hasNext();
-    }
-
-    @SuppressWarnings("unchecked")
-    // @Override
-    public Entry<K, Object> next() {
-      Entry<K, ?> entry = iterator.next();
-      if (entry.getValue() instanceof LazyField) {
-        return new LazyEntry<K>((Entry<K, LazyField>) entry);
-      }
-      return (Entry<K, Object>) entry;
-    }
-
-    // @Override
-    public void remove() {
-      iterator.remove();
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/src/main/java/com/google/protobuf/LazyFieldLite.java
deleted file mode 100644
index 1fc80e8..0000000
--- a/java/src/main/java/com/google/protobuf/LazyFieldLite.java
+++ /dev/null
@@ -1,176 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-
-/**
- * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
- * the message in a ByteString initially and then parse it on-demand.
- *
- * LazyField is thread-compatible e.g. concurrent read are safe, however,
- * synchronizations are needed under read/write situations.
- *
- * This class is internal implementation detail, so you don't need to use it directly.
- *
- * @author xiangl@google.com (Xiang Li)
- */
-public class LazyFieldLite {
-  private ByteString bytes;
-  private ExtensionRegistryLite extensionRegistry;
-  private volatile boolean isDirty = false;
-
-  protected volatile MessageLite value;
-
-  public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
-    this.extensionRegistry = extensionRegistry;
-    this.bytes = bytes;
-  }
-
-  public LazyFieldLite() {
-  }
-
-  public static LazyFieldLite fromValue(MessageLite value) {
-    LazyFieldLite lf = new LazyFieldLite();
-    lf.setValue(value);
-    return lf;
-  }
-
-  public boolean containsDefaultInstance() {
-    return value == null && bytes == null;
-  }
-
-  public void clear() {
-    bytes = null;
-    value = null;
-    extensionRegistry = null;
-    isDirty = true;
-  }
-
-  /**
-   * Returns message instance. At first time, serialized data is parsed by
-   * {@code defaultInstance.getParserForType()}.
-   *
-   * @param defaultInstance its message's default instance. It's also used to get parser for the
-   * message type.
-   */
-  public MessageLite getValue(MessageLite defaultInstance) {
-    ensureInitialized(defaultInstance);
-    return value;
-  }
-
-  /**
-   * LazyField is not thread-safe for write access. Synchronizations are needed
-   * under read/write situations.
-   */
-  public MessageLite setValue(MessageLite value) {
-    MessageLite originalValue = this.value;
-    this.value = value;
-    bytes = null;
-    isDirty = true;
-    return originalValue;
-  }
-
-  public void merge(LazyFieldLite value) {
-    if (value.containsDefaultInstance()) {
-      return;
-    }
-
-    if (bytes == null) {
-      this.bytes = value.bytes;
-    } else {
-      this.bytes.concat(value.toByteString());
-    }
-    isDirty = false;
-  }
-
-  public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
-    this.bytes = bytes;
-    this.extensionRegistry = extensionRegistry;
-    isDirty = false;
-  }
-
-  public ExtensionRegistryLite getExtensionRegistry() {
-    return extensionRegistry;
-  }
-
-  /**
-   * Due to the optional field can be duplicated at the end of serialized
-   * bytes, which will make the serialized size changed after LazyField
-   * parsed. Be careful when using this method.
-   */
-  public int getSerializedSize() {
-    if (isDirty) {
-      return value.getSerializedSize();
-    }
-    return bytes.size();
-  }
-
-  public ByteString toByteString() {
-    if (!isDirty) {
-      return bytes;
-    }
-    synchronized (this) {
-      if (!isDirty) {
-        return bytes;
-      }
-      if (value == null) {
-        bytes = ByteString.EMPTY;
-      } else {
-        bytes = value.toByteString();
-      }
-      isDirty = false;
-      return bytes;
-    }
-  }
-
-  protected void ensureInitialized(MessageLite defaultInstance) {
-    if (value != null) {
-      return;
-    }
-    synchronized (this) {
-      if (value != null) {
-        return;
-      }
-      try {
-        if (bytes != null) {
-          value = defaultInstance.getParserForType()
-              .parseFrom(bytes, extensionRegistry);
-        } else {
-          value = defaultInstance;
-        }
-      } catch (IOException e) {
-        // TODO(xiangl): Refactory the API to support the exception thrown from
-        // lazily load messages.
-      }
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
deleted file mode 100644
index 61c7e1e..0000000
--- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ /dev/null
@@ -1,367 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.RandomAccess;
-
-/**
- * An implementation of {@link LazyStringList} that wraps an ArrayList. Each
- * element is one of String, ByteString, or byte[]. It caches the last one
- * requested which is most likely the one needed next. This minimizes memory
- * usage while satisfying the most common use cases.
- * <p>
- * <strong>Note that this implementation is not synchronized.</strong>
- * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
- * and at least one of the threads modifies the list structurally, it
- * <i>must</i> be synchronized externally.  (A structural modification is
- * any operation that adds or deletes one or more elements, or explicitly
- * resizes the backing array; merely setting the value of an element is not
- * a structural modification.)  This is typically accomplished by
- * synchronizing on some object that naturally encapsulates the list.
- * <p>
- * If the implementation is accessed via concurrent reads, this is thread safe.
- * Conversions are done in a thread safe manner. It's possible that the
- * conversion may happen more than once if two threads attempt to access the
- * same element and the modifications were not visible to each other, but this
- * will not result in any corruption of the list or change in behavior other
- * than performance.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class LazyStringArrayList extends AbstractList<String>
-    implements LazyStringList, RandomAccess {
-
-  public static final LazyStringList EMPTY =
-      new LazyStringArrayList().getUnmodifiableView();
-
-  private final List<Object> list;
-
-  public LazyStringArrayList() {
-    list = new ArrayList<Object>();
-  }
-
-  public LazyStringArrayList(LazyStringList from) {
-    list = new ArrayList<Object>(from.size());
-    addAll(from);
-  }
-
-  public LazyStringArrayList(List<String> from) {
-    list = new ArrayList<Object>(from);
-  }
-
-  @Override
-  public String get(int index) {
-    Object o = list.get(index);
-    if (o instanceof String) {
-      return (String) o;
-    } else if (o instanceof ByteString) {
-      ByteString bs = (ByteString) o;
-      String s = bs.toStringUtf8();
-      if (bs.isValidUtf8()) {
-        list.set(index, s);
-      }
-      return s;
-    } else {
-      byte[] ba = (byte[]) o;
-      String s = Internal.toStringUtf8(ba);
-      if (Internal.isValidUtf8(ba)) {
-        list.set(index, s);
-      }
-      return s;
-    }
-  }
-
-  @Override
-  public int size() {
-    return list.size();
-  }
-
-  @Override
-  public String set(int index, String s) {
-    Object o = list.set(index, s);
-    return asString(o);
-  }
-
-  @Override
-  public void add(int index, String element) {
-    list.add(index, element);
-    modCount++;
-  }
-
-  @Override
-  public boolean addAll(Collection<? extends String> c) {
-    // The default implementation of AbstractCollection.addAll(Collection)
-    // delegates to add(Object). This implementation instead delegates to
-    // addAll(int, Collection), which makes a special case for Collections
-    // which are instances of LazyStringList.
-    return addAll(size(), c);
-  }
-
-  @Override
-  public boolean addAll(int index, Collection<? extends String> c) {
-    // When copying from another LazyStringList, directly copy the underlying
-    // elements rather than forcing each element to be decoded to a String.
-    Collection<?> collection = c instanceof LazyStringList
-        ? ((LazyStringList) c).getUnderlyingElements() : c;
-    boolean ret = list.addAll(index, collection);
-    modCount++;
-    return ret;
-  }
-
-  // @Override
-  public boolean addAllByteString(Collection<? extends ByteString> values) {
-    boolean ret = list.addAll(values);
-    modCount++;
-    return ret;
-  }
-
-  // @Override
-  public boolean addAllByteArray(Collection<byte[]> c) {
-    boolean ret = list.addAll(c);
-    modCount++;
-    return ret;
-  }
-
-  @Override
-  public String remove(int index) {
-    Object o = list.remove(index);
-    modCount++;
-    return asString(o);
-  }
-
-  @Override
-  public void clear() {
-    list.clear();
-    modCount++;
-  }
-
-  // @Override
-  public void add(ByteString element) {
-    list.add(element);
-    modCount++;
-  }
-  
-  // @Override
-  public void add(byte[] element) {
-    list.add(element);
-    modCount++;
-  }
-
-  // @Override
-  public ByteString getByteString(int index) {
-    Object o = list.get(index);
-    ByteString b = asByteString(o);
-    if (b != o) {
-      list.set(index, b);
-    }
-    return b;
-  }
-  
-  // @Override
-  public byte[] getByteArray(int index) {
-    Object o = list.get(index);
-    byte[] b = asByteArray(o);
-    if (b != o) {
-      list.set(index, b);
-    }
-    return b;
-  }
-
-  // @Override
-  public void set(int index, ByteString s) {
-    list.set(index, s);
-  }
-
-  // @Override
-  public void set(int index, byte[] s) {
-    list.set(index, s);
-  }
-
-
-  private static String asString(Object o) {
-    if (o instanceof String) {
-      return (String) o;
-    } else if (o instanceof ByteString) {
-      return ((ByteString) o).toStringUtf8();
-    } else {
-      return Internal.toStringUtf8((byte[]) o);
-    }
-  }
-  
-  private static ByteString asByteString(Object o) {
-    if (o instanceof ByteString) {
-      return (ByteString) o;
-    } else if (o instanceof String) {
-      return ByteString.copyFromUtf8((String) o);
-    } else {
-      return ByteString.copyFrom((byte[]) o);
-    }
-  }
-  
-  private static byte[] asByteArray(Object o) {
-    if (o instanceof byte[]) {
-      return (byte[]) o;
-    } else if (o instanceof String) {
-      return Internal.toByteArray((String) o);
-    } else {
-      return ((ByteString) o).toByteArray();
-    }
-  }
-
-  // @Override
-  public List<?> getUnderlyingElements() {
-    return Collections.unmodifiableList(list);
-  }
-
-  // @Override
-  public void mergeFrom(LazyStringList other) {
-    for (Object o : other.getUnderlyingElements()) {
-      if (o instanceof byte[]) {
-        byte[] b = (byte[]) o;
-        // Byte array's content is mutable so they should be copied rather than
-        // shared when merging from one message to another.
-        list.add(Arrays.copyOf(b, b.length));
-      } else {
-        list.add(o);
-      }
-    }
-  }
-
-  private static class ByteArrayListView extends AbstractList<byte[]>
-      implements RandomAccess {
-    private final List<Object> list;
-    
-    ByteArrayListView(List<Object> list) {
-      this.list = list;
-    }
-    
-    @Override
-    public byte[] get(int index) {
-      Object o = list.get(index);
-      byte[] b = asByteArray(o);
-      if (b != o) {
-        list.set(index, b);
-      }
-      return b;
-    }
-
-    @Override
-    public int size() {
-      return list.size();
-    }
-
-    @Override
-    public byte[] set(int index, byte[] s) {
-      Object o = list.set(index, s);
-      modCount++;
-      return asByteArray(o);
-    }
-
-    @Override
-    public void add(int index, byte[] s) {
-      list.add(index, s);
-      modCount++;
-    }
-
-    @Override
-    public byte[] remove(int index) {
-      Object o = list.remove(index);
-      modCount++;
-      return asByteArray(o);
-    }
-  }
-  
-  // @Override
-  public List<byte[]> asByteArrayList() {
-    return new ByteArrayListView(list);
-  }
-
-  private static class ByteStringListView extends AbstractList<ByteString>
-      implements RandomAccess {
-    private final List<Object> list;
-
-    ByteStringListView(List<Object> list) {
-      this.list = list;
-    }
-
-    @Override
-    public ByteString get(int index) {
-      Object o = list.get(index);
-      ByteString b = asByteString(o);
-      if (b != o) {
-        list.set(index, b);
-      }
-      return b;
-    }
-
-    @Override
-    public int size() {
-      return list.size();
-    }
-
-    @Override
-    public ByteString set(int index, ByteString s) {
-      Object o = list.set(index, s);
-      modCount++;
-      return asByteString(o);
-    }
-
-    @Override
-    public void add(int index, ByteString s) {
-      list.add(index, s);
-      modCount++;
-    }
-
-    @Override
-    public ByteString remove(int index) {
-      Object o = list.remove(index);
-      modCount++;
-      return asByteString(o);
-    }
-  }
-
-  // @Override
-  public List<ByteString> asByteStringList() {
-    return new ByteStringListView(list);
-  }
-
-  // @Override
-  public LazyStringList getUnmodifiableView() {
-    return new UnmodifiableLazyStringList(this);
-  }
-
-}
diff --git a/java/src/main/java/com/google/protobuf/LazyStringList.java b/java/src/main/java/com/google/protobuf/LazyStringList.java
deleted file mode 100644
index 235126b..0000000
--- a/java/src/main/java/com/google/protobuf/LazyStringList.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * An interface extending {@code List<String>} that also provides access to the
- * items of the list as UTF8-encoded ByteString or byte[] objects. This is
- * used by the protocol buffer implementation to support lazily converting bytes
- * parsed over the wire to String objects until needed and also increases the
- * efficiency of serialization if the String was never requested as the
- * ByteString or byte[] is already cached. The ByteString methods are used in
- * immutable API only and byte[] methods used in mutable API only for they use
- * different representations for string/bytes fields.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public interface LazyStringList extends ProtocolStringList {
-
-  /**
-   * Returns the element at the specified position in this list as a ByteString.
-   *
-   * @param index index of the element to return
-   * @return the element at the specified position in this list
-   * @throws IndexOutOfBoundsException if the index is out of range
-   *         ({@code index < 0 || index >= size()})
-   */
-  ByteString getByteString(int index);
-  
-  /**
-   * Returns the element at the specified position in this list as byte[].
-   *
-   * @param index index of the element to return
-   * @return the element at the specified position in this list
-   * @throws IndexOutOfBoundsException if the index is out of range
-   *         ({@code index < 0 || index >= size()})
-   */
-  byte[] getByteArray(int index);
-
-  /**
-   * Appends the specified element to the end of this list (optional
-   * operation).
-   *
-   * @param element element to be appended to this list
-   * @throws UnsupportedOperationException if the <tt>add</tt> operation
-   *         is not supported by this list
-   */
-  void add(ByteString element);
-
-  /**
-   * Appends the specified element to the end of this list (optional
-   * operation).
-   *
-   * @param element element to be appended to this list
-   * @throws UnsupportedOperationException if the <tt>add</tt> operation
-   *         is not supported by this list
-   */
-  void add(byte[] element);
-
-  /**
-   * Replaces the element at the specified position in this list with the
-   * specified element (optional operation).
-   *
-   * @param index index of the element to replace
-   * @param element the element to be stored at the specified position
-   * @throws UnsupportedOperationException if the <tt>set</tt> operation
-   *         is not supported by this list
-   *         IndexOutOfBoundsException if the index is out of range
-   *         ({@code index < 0 || index >= size()})
-   */
-  void set(int index, ByteString element);
-  
-  /**
-   * Replaces the element at the specified position in this list with the
-   * specified element (optional operation).
-   *
-   * @param index index of the element to replace
-   * @param element the element to be stored at the specified position
-   * @throws UnsupportedOperationException if the <tt>set</tt> operation
-   *         is not supported by this list
-   *         IndexOutOfBoundsException if the index is out of range
-   *         ({@code index < 0 || index >= size()})
-   */
-  void set(int index, byte[] element);
-
-  /**
-   * Appends all elements in the specified ByteString collection to the end of
-   * this list.
-   *
-   * @param c collection whose elements are to be added to this list
-   * @return true if this list changed as a result of the call
-   * @throws UnsupportedOperationException if the <tt>addAllByteString</tt>
-   *         operation is not supported by this list
-   */
-  boolean addAllByteString(Collection<? extends ByteString> c);
-
-  /**
-   * Appends all elements in the specified byte[] collection to the end of
-   * this list.
-   *
-   * @param c collection whose elements are to be added to this list
-   * @return true if this list changed as a result of the call
-   * @throws UnsupportedOperationException if the <tt>addAllByteArray</tt>
-   *         operation is not supported by this list
-   */
-  boolean addAllByteArray(Collection<byte[]> c);
-
-  /**
-   * Returns an unmodifiable List of the underlying elements, each of which is
-   * either a {@code String} or its equivalent UTF-8 encoded {@code ByteString}
-   * or byte[]. It is an error for the caller to modify the returned
-   * List, and attempting to do so will result in an
-   * {@link UnsupportedOperationException}.
-   */
-  List<?> getUnderlyingElements();
-
-  /**
-   * Merges all elements from another LazyStringList into this one. This method
-   * differs from {@link #addAll(Collection)} on that underlying byte arrays are
-   * copied instead of reference shared. Immutable API doesn't need to use this
-   * method as byte[] is not used there at all.
-   */
-  void mergeFrom(LazyStringList other);
-
-  /**
-   * Returns a mutable view of this list. Changes to the view will be made into
-   * the original list. This method is used in mutable API only.
-   */
-  List<byte[]> asByteArrayList();
-
-  /** Returns an unmodifiable view of the list. */
-  LazyStringList getUnmodifiableView();
-}
diff --git a/java/src/main/java/com/google/protobuf/LiteralByteString.java b/java/src/main/java/com/google/protobuf/LiteralByteString.java
deleted file mode 100644
index 83e71e9..0000000
--- a/java/src/main/java/com/google/protobuf/LiteralByteString.java
+++ /dev/null
@@ -1,362 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * This class implements a {@link com.google.protobuf.ByteString} backed by a
- * single array of bytes, contiguous in memory. It supports substring by
- * pointing to only a sub-range of the underlying byte array, meaning that a
- * substring will reference the full byte-array of the string it's made from,
- * exactly as with {@link String}.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-class LiteralByteString extends ByteString {
-
-  protected final byte[] bytes;
-
-  /**
-   * Creates a {@code LiteralByteString} backed by the given array, without
-   * copying.
-   *
-   * @param bytes array to wrap
-   */
-  LiteralByteString(byte[] bytes) {
-    this.bytes = bytes;
-  }
-
-  @Override
-  public byte byteAt(int index) {
-    // Unlike most methods in this class, this one is a direct implementation
-    // ignoring the potential offset because we need to do range-checking in the
-    // substring case anyway.
-    return bytes[index];
-  }
-
-  @Override
-  public int size() {
-    return bytes.length;
-  }
-
-  // =================================================================
-  // ByteString -> substring
-
-  @Override
-  public ByteString substring(int beginIndex, int endIndex) {
-    if (beginIndex < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index: " + beginIndex + " < 0");
-    }
-    if (endIndex > size()) {
-      throw new IndexOutOfBoundsException("End index: " + endIndex + " > " +
-          size());
-    }
-    int substringLength = endIndex - beginIndex;
-    if (substringLength < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index larger than ending index: " + beginIndex + ", "
-              + endIndex);
-    }
-
-    ByteString result;
-    if (substringLength == 0) {
-      result = ByteString.EMPTY;
-    } else {
-      result = new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex,
-          substringLength);
-    }
-    return result;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  @Override
-  protected void copyToInternal(byte[] target, int sourceOffset, 
-      int targetOffset, int numberToCopy) {
-    // Optimized form, not for subclasses, since we don't call
-    // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
-    System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
-  }
-
-  @Override
-  public void copyTo(ByteBuffer target) {
-    target.put(bytes, getOffsetIntoBytes(), size());  // Copies bytes
-  }
-
-  @Override
-  public ByteBuffer asReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer =
-        ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size());
-    return byteBuffer.asReadOnlyBuffer();
-  }
-
-  @Override
-  public List<ByteBuffer> asReadOnlyByteBufferList() {
-    // Return the ByteBuffer generated by asReadOnlyByteBuffer() as a singleton
-    List<ByteBuffer> result = new ArrayList<ByteBuffer>(1);
-    result.add(asReadOnlyByteBuffer());
-    return result;
- }
-
- @Override
-  public void writeTo(OutputStream outputStream) throws IOException {
-    outputStream.write(toByteArray());
-  }
-
-  @Override
-  void writeToInternal(OutputStream outputStream, int sourceOffset,
-      int numberToWrite) throws IOException {
-    outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset,
-        numberToWrite);
-  }
-
-  @Override
-  public String toString(String charsetName)
-      throws UnsupportedEncodingException {
-    return new String(bytes, getOffsetIntoBytes(), size(), charsetName);
-  }
-
-  // =================================================================
-  // UTF-8 decoding
-
-  @Override
-  public boolean isValidUtf8() {
-    int offset = getOffsetIntoBytes();
-    return Utf8.isValidUtf8(bytes, offset, offset + size());
-  }
-
-  @Override
-  protected int partialIsValidUtf8(int state, int offset, int length) {
-    int index = getOffsetIntoBytes() + offset;
-    return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
-  }
-
-  // =================================================================
-  // equals() and hashCode()
-
-  @Override
-  public boolean equals(Object other) {
-    if (other == this) {
-      return true;
-    }
-    if (!(other instanceof ByteString)) {
-      return false;
-    }
-
-    if (size() != ((ByteString) other).size()) {
-      return false;
-    }
-    if (size() == 0) {
-      return true;
-    }
-
-    if (other instanceof LiteralByteString) {
-      return equalsRange((LiteralByteString) other, 0, size());
-    } else if (other instanceof RopeByteString) {
-      return other.equals(this);
-    } else {
-      throw new IllegalArgumentException(
-          "Has a new type of ByteString been created? Found "
-              + other.getClass());
-    }
-  }
-
-  /**
-   * Check equality of the substring of given length of this object starting at
-   * zero with another {@code LiteralByteString} substring starting at offset.
-   *
-   * @param other  what to compare a substring in
-   * @param offset offset into other
-   * @param length number of bytes to compare
-   * @return true for equality of substrings, else false.
-   */
-  boolean equalsRange(LiteralByteString other, int offset, int length) {
-    if (length > other.size()) {
-      throw new IllegalArgumentException(
-          "Length too large: " + length + size());
-    }
-    if (offset + length > other.size()) {
-      throw new IllegalArgumentException(
-          "Ran off end of other: " + offset + ", " + length + ", " +
-              other.size());
-    }
-
-    byte[] thisBytes = bytes;
-    byte[] otherBytes = other.bytes;
-    int thisLimit = getOffsetIntoBytes() + length;
-    for (int thisIndex = getOffsetIntoBytes(), otherIndex =
-        other.getOffsetIntoBytes() + offset;
-        (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
-      if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Cached hash value.  Intentionally accessed via a data race, which
-   * is safe because of the Java Memory Model's "no out-of-thin-air values"
-   * guarantees for ints.
-   */
-  private int hash = 0;
-
-  /**
-   * Compute the hashCode using the traditional algorithm from {@link
-   * ByteString}.
-   *
-   * @return hashCode value
-   */
-  @Override
-  public int hashCode() {
-    int h = hash;
-
-    if (h == 0) {
-      int size = size();
-      h = partialHash(size, 0, size);
-      if (h == 0) {
-        h = 1;
-      }
-      hash = h;
-    }
-    return h;
-  }
-
-  @Override
-  protected int peekCachedHashCode() {
-    return hash;
-  }
-
-  @Override
-  protected int partialHash(int h, int offset, int length) {
-    return hashCode(h, bytes, getOffsetIntoBytes() + offset, length);
-  }
-  
-  static int hashCode(int h, byte[] bytes, int offset, int length) {
-    for (int i = offset; i < offset + length; i++) {
-      h = h * 31 + bytes[i];
-    }
-    return h;
-  }
-  
-  static int hashCode(byte[] bytes) {
-    int h = hashCode(bytes.length, bytes, 0, bytes.length);
-    return h == 0 ? 1 : h;
-  }
-
-  // =================================================================
-  // Input stream
-
-  @Override
-  public InputStream newInput() {
-    return new ByteArrayInputStream(bytes, getOffsetIntoBytes(),
-        size());  // No copy
-  }
-
-  @Override
-  public CodedInputStream newCodedInput() {
-    // We trust CodedInputStream not to modify the bytes, or to give anyone
-    // else access to them.
-    return CodedInputStream.newInstance(this);
-  }
-
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new LiteralByteIterator();
-  }
-
-  private class LiteralByteIterator implements ByteIterator {
-    private int position;
-    private final int limit;
-
-    private LiteralByteIterator() {
-      position = 0;
-      limit = size();
-    }
-
-    public boolean hasNext() {
-      return (position < limit);
-    }
-
-    public Byte next() {
-      // Boxing calls Byte.valueOf(byte), which does not instantiate.
-      return nextByte();
-    }
-
-    public byte nextByte() {
-      try {
-        return bytes[position++];
-      } catch (ArrayIndexOutOfBoundsException e) {
-        throw new NoSuchElementException(e.getMessage());
-      }
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  // =================================================================
-  // Internal methods
-
-  @Override
-  protected int getTreeDepth() {
-    return 0;
-  }
-
-  @Override
-  protected boolean isBalanced() {
-    return true;
-  }
-
-  /**
-   * Offset into {@code bytes[]} to use, non-zero for substrings.
-   *
-   * @return always 0 for this class
-   */
-  protected int getOffsetIntoBytes() {
-    return 0;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java
deleted file mode 100644
index 5673d3b..0000000
--- a/java/src/main/java/com/google/protobuf/Message.java
+++ /dev/null
@@ -1,244 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
-//   mergeFrom*() could return BuilderType for better type-safety.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-
-/**
- * Abstract interface implemented by Protocol Message objects.
- * <p>
- * See also {@link MessageLite}, which defines most of the methods that typical
- * users care about.  {@link Message} adds to it methods that are not available
- * in the "lite" runtime.  The biggest added features are introspection and
- * reflection -- i.e., getting descriptors for the message type and accessing
- * the field values dynamically.
- *
- * @author kenton@google.com Kenton Varda
- */
-public interface Message extends MessageLite, MessageOrBuilder {
-
-  // (From MessageLite, re-declared here only for return type covariance.)
-  Parser<? extends Message> getParserForType();
-
-
-  // -----------------------------------------------------------------
-  // Comparison and hashing
-
-  /**
-   * Compares the specified object with this message for equality.  Returns
-   * {@code true} if the given object is a message of the same type (as
-   * defined by {@code getDescriptorForType()}) and has identical values for
-   * all of its fields.  Subclasses must implement this; inheriting
-   * {@code Object.equals()} is incorrect.
-   *
-   * @param other object to be compared for equality with this message
-   * @return {@code true} if the specified object is equal to this message
-   */
-  @Override
-  boolean equals(Object other);
-
-  /**
-   * Returns the hash code value for this message.  The hash code of a message
-   * should mix the message's type (object identity of the descriptor) with its
-   * contents (known and unknown field values).  Subclasses must implement this;
-   * inheriting {@code Object.hashCode()} is incorrect.
-   *
-   * @return the hash code value for this message
-   * @see Map#hashCode()
-   */
-  @Override
-  int hashCode();
-
-  // -----------------------------------------------------------------
-  // Convenience methods.
-
-  /**
-   * Converts the message to a string in protocol buffer text format. This is
-   * just a trivial wrapper around {@link
-   * TextFormat#printToString(MessageOrBuilder)}.
-   */
-  @Override
-  String toString();
-
-  // =================================================================
-  // Builders
-
-  // (From MessageLite, re-declared here only for return type covariance.)
-  Builder newBuilderForType();
-  Builder toBuilder();
-
-  /**
-   * Abstract interface implemented by Protocol Message builders.
-   */
-  interface Builder extends MessageLite.Builder, MessageOrBuilder {
-    // (From MessageLite.Builder, re-declared here only for return type
-    // covariance.)
-    Builder clear();
-
-    /**
-     * Merge {@code other} into the message being built.  {@code other} must
-     * have the exact same type as {@code this} (i.e.
-     * {@code getDescriptorForType() == other.getDescriptorForType()}).
-     *
-     * Merging occurs as follows.  For each field:<br>
-     * * For singular primitive fields, if the field is set in {@code other},
-     *   then {@code other}'s value overwrites the value in this message.<br>
-     * * For singular message fields, if the field is set in {@code other},
-     *   it is merged into the corresponding sub-message of this message
-     *   using the same merging rules.<br>
-     * * For repeated fields, the elements in {@code other} are concatenated
-     *   with the elements in this message.
-     *
-     * This is equivalent to the {@code Message::MergeFrom} method in C++.
-     */
-    Builder mergeFrom(Message other);
-
-    // (From MessageLite.Builder, re-declared here only for return type
-    // covariance.)
-    Message build();
-    Message buildPartial();
-    Builder clone();
-    Builder mergeFrom(CodedInputStream input) throws IOException;
-    Builder mergeFrom(CodedInputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
-
-    /**
-     * Get the message's type's descriptor.
-     * See {@link Message#getDescriptorForType()}.
-     */
-    Descriptors.Descriptor getDescriptorForType();
-
-    /**
-     * Create a Builder for messages of the appropriate type for the given
-     * field.  Messages built with this can then be passed to setField(),
-     * setRepeatedField(), or addRepeatedField().
-     */
-    Builder newBuilderForField(Descriptors.FieldDescriptor field);
-
-    /**
-     * Get a nested builder instance for the given field.
-     * <p>
-     * Normally, we hold a reference to the immutable message object for the
-     * message type field. Some implementations(the generated message builders),
-     * however, can also hold a reference to the builder object (a nested
-     * builder) for the field.
-     * <p>
-     * If the field is already backed up by a nested builder, the nested builder
-     * will be returned. Otherwise, a new field builder will be created and
-     * returned. The original message field (if exist) will be merged into the
-     * field builder, which will then be nested into its parent builder.
-     * <p>
-     * NOTE: implementations that do not support nested builders will throw
-     * <code>UnsupportedException</code>.
-     */
-    Builder getFieldBuilder(Descriptors.FieldDescriptor field);
-
-    /**
-     * Sets a field to the given value.  The value must be of the correct type
-     * for this field, i.e. the same type that
-     * {@link Message#getField(Descriptors.FieldDescriptor)} would return.
-     */
-    Builder setField(Descriptors.FieldDescriptor field, Object value);
-
-    /**
-     * Clears the field.  This is exactly equivalent to calling the generated
-     * "clear" accessor method corresponding to the field.
-     */
-    Builder clearField(Descriptors.FieldDescriptor field);
-
-    /**
-     * Clears the oneof.  This is exactly equivalent to calling the generated
-     * "clear" accessor method corresponding to the oneof.
-     */
-    Builder clearOneof(Descriptors.OneofDescriptor oneof);
-
-    /**
-     * Sets an element of a repeated field to the given value.  The value must
-     * be of the correct type for this field, i.e. the same type that
-     * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
-     * return.
-     * @throws IllegalArgumentException The field is not a repeated field, or
-     *           {@code field.getContainingType() != getDescriptorForType()}.
-     */
-    Builder setRepeatedField(Descriptors.FieldDescriptor field,
-                             int index, Object value);
-
-    /**
-     * Like {@code setRepeatedField}, but appends the value as a new element.
-     * @throws IllegalArgumentException The field is not a repeated field, or
-     *           {@code field.getContainingType() != getDescriptorForType()}.
-     */
-    Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
-
-    /** Set the {@link UnknownFieldSet} for this message. */
-    Builder setUnknownFields(UnknownFieldSet unknownFields);
-
-    /**
-     * Merge some unknown fields into the {@link UnknownFieldSet} for this
-     * message.
-     */
-    Builder mergeUnknownFields(UnknownFieldSet unknownFields);
-
-    // ---------------------------------------------------------------
-    // Convenience methods.
-
-    // (From MessageLite.Builder, re-declared here only for return type
-    // covariance.)
-    Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
-    Builder mergeFrom(ByteString data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data, int off, int len)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(byte[] data, int off, int len,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-    Builder mergeFrom(InputStream input) throws IOException;
-    Builder mergeFrom(InputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
-    boolean mergeDelimitedFrom(InputStream input)
-                               throws IOException;
-    boolean mergeDelimitedFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-                               throws IOException;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/MessageLite.java b/java/src/main/java/com/google/protobuf/MessageLite.java
deleted file mode 100644
index 798b794..0000000
--- a/java/src/main/java/com/google/protobuf/MessageLite.java
+++ /dev/null
@@ -1,320 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
-//   mergeFrom*() could return BuilderType for better type-safety.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Abstract interface implemented by Protocol Message objects.
- *
- * <p>This interface is implemented by all protocol message objects.  Non-lite
- * messages additionally implement the Message interface, which is a subclass
- * of MessageLite.  Use MessageLite instead when you only need the subset of
- * features which it supports -- namely, nothing that uses descriptors or
- * reflection.  You can instruct the protocol compiler to generate classes
- * which implement only MessageLite, not the full Message interface, by adding
- * the follow line to the .proto file:
- * <pre>
- *   option optimize_for = LITE_RUNTIME;
- * </pre>
- *
- * <p>This is particularly useful on resource-constrained systems where the
- * full protocol buffers runtime library is too big.
- *
- * <p>Note that on non-constrained systems (e.g. servers) when you need to link
- * in lots of protocol definitions, a better way to reduce total code footprint
- * is to use {@code optimize_for = CODE_SIZE}.  This will make the generated
- * code smaller while still supporting all the same features (at the expense of
- * speed).  {@code optimize_for = LITE_RUNTIME} is best when you only have a
- * small number of message types linked into your binary, in which case the
- * size of the protocol buffers runtime itself is the biggest problem.
- *
- * @author kenton@google.com Kenton Varda
- */
-public interface MessageLite extends MessageLiteOrBuilder {
-
-
-  /**
-   * Serializes the message and writes it to {@code output}.  This does not
-   * flush or close the stream.
-   */
-  void writeTo(CodedOutputStream output) throws IOException;
-
-  /**
-   * Get the number of bytes required to encode this message.  The result
-   * is only computed on the first call and memoized after that.
-   */
-  int getSerializedSize();
-
-
-  /**
-   * Gets the parser for a message of the same type as this message.
-   */
-  Parser<? extends MessageLite> getParserForType();
-
-  // -----------------------------------------------------------------
-  // Convenience methods.
-
-  /**
-   * Serializes the message to a {@code ByteString} and returns it. This is
-   * just a trivial wrapper around
-   * {@link #writeTo(CodedOutputStream)}.
-   */
-  ByteString toByteString();
-
-  /**
-   * Serializes the message to a {@code byte} array and returns it.  This is
-   * just a trivial wrapper around
-   * {@link #writeTo(CodedOutputStream)}.
-   */
-  byte[] toByteArray();
-
-  /**
-   * Serializes the message and writes it to {@code output}.  This is just a
-   * trivial wrapper around {@link #writeTo(CodedOutputStream)}.  This does
-   * not flush or close the stream.
-   * <p>
-   * NOTE:  Protocol Buffers are not self-delimiting.  Therefore, if you write
-   * any more data to the stream after the message, you must somehow ensure
-   * that the parser on the receiving end does not interpret this as being
-   * part of the protocol message.  This can be done e.g. by writing the size
-   * of the message before the data, then making sure to limit the input to
-   * that size on the receiving end (e.g. by wrapping the InputStream in one
-   * which limits the input).  Alternatively, just use
-   * {@link #writeDelimitedTo(OutputStream)}.
-   */
-  void writeTo(OutputStream output) throws IOException;
-
-  /**
-   * Like {@link #writeTo(OutputStream)}, but writes the size of the message
-   * as a varint before writing the data.  This allows more data to be written
-   * to the stream after the message without the need to delimit the message
-   * data yourself.  Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
-   * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
-   * to parse messages written by this method.
-   */
-  void writeDelimitedTo(OutputStream output) throws IOException;
-
-
-  // =================================================================
-  // Builders
-
-  /**
-   * Constructs a new builder for a message of the same type as this message.
-   */
-  Builder newBuilderForType();
-
-  /**
-   * Constructs a builder initialized with the current message.  Use this to
-   * derive a new message from the current one.
-   */
-  Builder toBuilder();
-
-  /**
-   * Abstract interface implemented by Protocol Message builders.
-   */
-  interface Builder extends MessageLiteOrBuilder, Cloneable {
-    /** Resets all fields to their default values. */
-    Builder clear();
-
-    /**
-     * Constructs the message based on the state of the Builder. Subsequent
-     * changes to the Builder will not affect the returned message.
-     * @throws UninitializedMessageException The message is missing one or more
-     *         required fields (i.e. {@link #isInitialized()} returns false).
-     *         Use {@link #buildPartial()} to bypass this check.
-     */
-    MessageLite build();
-
-    /**
-     * Like {@link #build()}, but does not throw an exception if the message
-     * is missing required fields.  Instead, a partial message is returned.
-     * Subsequent changes to the Builder will not affect the returned message.
-     */
-    MessageLite buildPartial();
-
-    /**
-     * Clones the Builder.
-     * @see Object#clone()
-     */
-    Builder clone();
-
-    /**
-     * Parses a message of this type from the input and merges it with this
-     * message.
-     *
-     * <p>Warning:  This does not verify that all required fields are present in
-     * the input message.  If you call {@link #build()} without setting all
-     * required fields, it will throw an {@link UninitializedMessageException},
-     * which is a {@code RuntimeException} and thus might not be caught.  There
-     * are a few good ways to deal with this:
-     * <ul>
-     *   <li>Call {@link #isInitialized()} to verify that all required fields
-     *       are set before building.
-     *   <li>Use {@code buildPartial()} to build, which ignores missing
-     *       required fields.
-     * </ul>
-     *
-     * <p>Note:  The caller should call
-     * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
-     * verify that the last tag seen was the appropriate end-group tag,
-     * or zero for EOF.
-     */
-    Builder mergeFrom(CodedInputStream input) throws IOException;
-
-    /**
-     * Like {@link Builder#mergeFrom(CodedInputStream)}, but also
-     * parses extensions.  The extensions that you want to be able to parse
-     * must be registered in {@code extensionRegistry}.  Extensions not in
-     * the registry will be treated as unknown fields.
-     */
-    Builder mergeFrom(CodedInputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
-
-    // ---------------------------------------------------------------
-    // Convenience methods.
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(ByteString data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(byte[] data, int off, int len)
-                      throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(byte[] data,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(byte[] data, int off, int len,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws InvalidProtocolBufferException;
-
-    /**
-     * Parse a message of this type from {@code input} and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.  Note that this method always
-     * reads the <i>entire</i> input (unless it throws an exception).  If you
-     * want it to stop earlier, you will need to wrap your input in some
-     * wrapper stream that limits reading.  Or, use
-     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
-     * and {@link #mergeDelimitedFrom(InputStream)} to read it.
-     * <p>
-     * Despite usually reading the entire input, this does not close the stream.
-     *
-     * @return this
-     */
-    Builder mergeFrom(InputStream input) throws IOException;
-
-    /**
-     * Parse a message of this type from {@code input} and merge it with the
-     * message being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
-     *
-     * @return this
-     */
-    Builder mergeFrom(InputStream input,
-                      ExtensionRegistryLite extensionRegistry)
-                      throws IOException;
-
-    /**
-     * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
-     * Instead, the size of the message (encoded as a varint) is read first,
-     * then the message data.  Use
-     * {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
-     * this format.
-     *
-     * @return True if successful, or false if the stream is at EOF when the
-     *         method starts.  Any other error (including reaching EOF during
-     *         parsing) will cause an exception to be thrown.
-     */
-    boolean mergeDelimitedFrom(InputStream input)
-                               throws IOException;
-
-    /**
-     * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
-     */
-    boolean mergeDelimitedFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-                               throws IOException;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/src/main/java/com/google/protobuf/MessageOrBuilder.java
deleted file mode 100644
index f0fc485..0000000
--- a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Base interface for methods common to {@link Message} and
- * {@link Message.Builder} to provide type equivalency.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public interface MessageOrBuilder extends MessageLiteOrBuilder {
-
-  // (From MessageLite, re-declared here only for return type covariance.)
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  Message getDefaultInstanceForType();
-
-  /**
-   * Returns a list of field paths (e.g. "foo.bar.baz") of required fields
-   * which are not set in this message.  You should call
-   * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
-   * are any missing fields, as that method is likely to be much faster
-   * than this one even when the message is fully-initialized.
-   */
-  List<String> findInitializationErrors();
-
-  /**
-   * Returns a comma-delimited list of required fields which are not set
-   * in this message object.  You should call
-   * {@link MessageLiteOrBuilder#isInitialized()} first to check if there
-   * are any missing fields, as that method is likely to be much faster
-   * than this one even when the message is fully-initialized.
-   */
-  String getInitializationErrorString();
-
-  /**
-   * Get the message's type's descriptor.  This differs from the
-   * {@code getDescriptor()} method of generated message classes in that
-   * this method is an abstract method of the {@code Message} interface
-   * whereas {@code getDescriptor()} is a static method of a specific class.
-   * They return the same thing.
-   */
-  Descriptors.Descriptor getDescriptorForType();
-
-  /**
-   * Returns a collection of all the fields in this message which are set
-   * and their corresponding values.  A singular ("required" or "optional")
-   * field is set iff hasField() returns true for that field.  A "repeated"
-   * field is set iff getRepeatedFieldCount() is greater than zero.  The
-   * values are exactly what would be returned by calling
-   * {@link #getField(Descriptors.FieldDescriptor)} for each field.  The map
-   * is guaranteed to be a sorted map, so iterating over it will return fields
-   * in order by field number.
-   * <br>
-   * If this is for a builder, the returned map may or may not reflect future
-   * changes to the builder.  Either way, the returned map is itself
-   * unmodifiable.
-   */
-  Map<Descriptors.FieldDescriptor, Object> getAllFields();
-
-  /**
-   * Returns true if the given oneof is set.
-   * @throws IllegalArgumentException if
-   *           {@code oneof.getContainingType() != getDescriptorForType()}.
-   */
-  boolean hasOneof(Descriptors.OneofDescriptor oneof);
-
-  /**
-   * Obtains the FieldDescriptor if the given oneof is set. Returns null
-   * if no field is set.
-   */
-  Descriptors.FieldDescriptor getOneofFieldDescriptor(
-      Descriptors.OneofDescriptor oneof);
-
-  /**
-   * Returns true if the given field is set.  This is exactly equivalent to
-   * calling the generated "has" accessor method corresponding to the field.
-   * @throws IllegalArgumentException The field is a repeated field, or
-   *           {@code field.getContainingType() != getDescriptorForType()}.
-   */
-  boolean hasField(Descriptors.FieldDescriptor field);
-
-  /**
-   * Obtains the value of the given field, or the default value if it is
-   * not set.  For primitive fields, the boxed primitive value is returned.
-   * For enum fields, the EnumValueDescriptor for the value is returned. For
-   * embedded message fields, the sub-message is returned.  For repeated
-   * fields, a java.util.List is returned.
-   */
-  Object getField(Descriptors.FieldDescriptor field);
-
-  /**
-   * Gets the number of elements of a repeated field.  This is exactly
-   * equivalent to calling the generated "Count" accessor method corresponding
-   * to the field.
-   * @throws IllegalArgumentException The field is not a repeated field, or
-   *           {@code field.getContainingType() != getDescriptorForType()}.
-   */
-  int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
-
-  /**
-   * Gets an element of a repeated field.  For primitive fields, the boxed
-   * primitive value is returned.  For enum fields, the EnumValueDescriptor
-   * for the value is returned. For embedded message fields, the sub-message
-   * is returned.
-   * @throws IllegalArgumentException The field is not a repeated field, or
-   *           {@code field.getContainingType() != getDescriptorForType()}.
-   */
-  Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
-
-  /** Get the {@link UnknownFieldSet} for this message. */
-  UnknownFieldSet getUnknownFields();
-}
diff --git a/java/src/main/java/com/google/protobuf/MessageReflection.java b/java/src/main/java/com/google/protobuf/MessageReflection.java
deleted file mode 100644
index edb5b5c..0000000
--- a/java/src/main/java/com/google/protobuf/MessageReflection.java
+++ /dev/null
@@ -1,931 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.FieldDescriptor;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Reflection utility methods shared by both mutable and immutable messages.
- *
- * @author liujisi@google.com (Pherl Liu)
- */
-class MessageReflection {
-
-  static void writeMessageTo(Message message, CodedOutputStream output,
-      boolean alwaysWriteRequiredFields)
-      throws IOException {
-    final boolean isMessageSet =
-        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
-
-    Map<FieldDescriptor, Object> fields = message.getAllFields();
-    if (alwaysWriteRequiredFields) {
-      fields = new TreeMap<FieldDescriptor, Object>(fields);
-      for (final FieldDescriptor field :
-          message.getDescriptorForType().getFields()) {
-        if (field.isRequired() && !fields.containsKey(field)) {
-          fields.put(field, message.getField(field));
-        }
-      }
-    }
-    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
-        fields.entrySet()) {
-      final Descriptors.FieldDescriptor field = entry.getKey();
-      final Object value = entry.getValue();
-      if (isMessageSet && field.isExtension() &&
-          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
-          !field.isRepeated()) {
-        output.writeMessageSetExtension(field.getNumber(), (Message) value);
-      } else {
-        FieldSet.writeField(field, value, output);
-      }
-    }
-
-    final UnknownFieldSet unknownFields = message.getUnknownFields();
-    if (isMessageSet) {
-      unknownFields.writeAsMessageSetTo(output);
-    } else {
-      unknownFields.writeTo(output);
-    }
-  }
-
-  static int getSerializedSize(Message message) {
-    int size = 0;
-    final boolean isMessageSet =
-        message.getDescriptorForType().getOptions().getMessageSetWireFormat();
-
-    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
-        message.getAllFields().entrySet()) {
-      final Descriptors.FieldDescriptor field = entry.getKey();
-      final Object value = entry.getValue();
-      if (isMessageSet && field.isExtension() &&
-          field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
-          !field.isRepeated()) {
-        size += CodedOutputStream.computeMessageSetExtensionSize(
-            field.getNumber(), (Message) value);
-      } else {
-        size += FieldSet.computeFieldSize(field, value);
-      }
-    }
-
-    final UnknownFieldSet unknownFields = message.getUnknownFields();
-    if (isMessageSet) {
-      size += unknownFields.getSerializedSizeAsMessageSet();
-    } else {
-      size += unknownFields.getSerializedSize();
-    }
-    return size;
-  }
-
-  static String delimitWithCommas(List<String> parts) {
-    StringBuilder result = new StringBuilder();
-    for (String part : parts) {
-      if (result.length() > 0) {
-        result.append(", ");
-      }
-      result.append(part);
-    }
-    return result.toString();
-  }
-
-  @SuppressWarnings("unchecked")
-  static boolean isInitialized(MessageOrBuilder message) {
-    // Check that all required fields are present.
-    for (final Descriptors.FieldDescriptor field : message
-        .getDescriptorForType()
-        .getFields()) {
-      if (field.isRequired()) {
-        if (!message.hasField(field)) {
-          return false;
-        }
-      }
-    }
-
-    // Check that embedded messages are initialized.
-    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
-        message.getAllFields().entrySet()) {
-      final Descriptors.FieldDescriptor field = entry.getKey();
-      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
-        if (field.isRepeated()) {
-          for (final Message element
-              : (List<Message>) entry.getValue()) {
-            if (!element.isInitialized()) {
-              return false;
-            }
-          }
-        } else {
-          if (!((Message) entry.getValue()).isInitialized()) {
-            return false;
-          }
-        }
-      }
-    }
-
-    return true;
-  }
-
-  private static String subMessagePrefix(final String prefix,
-      final Descriptors.FieldDescriptor field,
-      final int index) {
-    final StringBuilder result = new StringBuilder(prefix);
-    if (field.isExtension()) {
-      result.append('(')
-          .append(field.getFullName())
-          .append(')');
-    } else {
-      result.append(field.getName());
-    }
-    if (index != -1) {
-      result.append('[')
-          .append(index)
-          .append(']');
-    }
-    result.append('.');
-    return result.toString();
-  }
-
-  private static void findMissingFields(final MessageOrBuilder message,
-      final String prefix,
-      final List<String> results) {
-    for (final Descriptors.FieldDescriptor field :
-        message.getDescriptorForType().getFields()) {
-      if (field.isRequired() && !message.hasField(field)) {
-        results.add(prefix + field.getName());
-      }
-    }
-
-    for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
-        message.getAllFields().entrySet()) {
-      final Descriptors.FieldDescriptor field = entry.getKey();
-      final Object value = entry.getValue();
-
-      if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
-        if (field.isRepeated()) {
-          int i = 0;
-          for (final Object element : (List) value) {
-            findMissingFields((MessageOrBuilder) element,
-                subMessagePrefix(prefix, field, i++),
-                results);
-          }
-        } else {
-          if (message.hasField(field)) {
-            findMissingFields((MessageOrBuilder) value,
-                subMessagePrefix(prefix, field, -1),
-                results);
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * Populates {@code this.missingFields} with the full "path" of each missing
-   * required field in the given message.
-   */
-  static List<String> findMissingFields(
-      final MessageOrBuilder message) {
-    final List<String> results = new ArrayList<String>();
-    findMissingFields(message, "", results);
-    return results;
-  }
-
-  static interface MergeTarget {
-    enum ContainerType {
-      MESSAGE, EXTENSION_SET
-    }
-
-    /**
-     * Returns the descriptor for the target.
-     */
-    public Descriptors.Descriptor getDescriptorForType();
-
-    public ContainerType getContainerType();
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByName(
-        ExtensionRegistry registry, String name);
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
-        ExtensionRegistry registry, Descriptors.Descriptor containingType,
-        int fieldNumber);
-
-    /**
-     * Obtains the value of the given field, or the default value if it is not
-     * set.  For primitive fields, the boxed primitive value is returned. For
-     * enum fields, the EnumValueDescriptor for the value is returned. For
-     * embedded message fields, the sub-message is returned.  For repeated
-     * fields, a java.util.List is returned.
-     */
-    public Object getField(Descriptors.FieldDescriptor field);
-
-    /**
-     * Returns true if the given field is set.  This is exactly equivalent to
-     * calling the generated "has" accessor method corresponding to the field.
-     *
-     * @throws IllegalArgumentException The field is a repeated field, or {@code
-     *     field.getContainingType() != getDescriptorForType()}.
-     */
-    boolean hasField(Descriptors.FieldDescriptor field);
-
-    /**
-     * Sets a field to the given value.  The value must be of the correct type
-     * for this field, i.e. the same type that
-     * {@link Message#getField(Descriptors.FieldDescriptor)}
-     * would return.
-     */
-    MergeTarget setField(Descriptors.FieldDescriptor field, Object value);
-
-    /**
-     * Clears the field.  This is exactly equivalent to calling the generated
-     * "clear" accessor method corresponding to the field.
-     */
-    MergeTarget clearField(Descriptors.FieldDescriptor field);
-
-    /**
-     * Sets an element of a repeated field to the given value.  The value must
-     * be of the correct type for this field, i.e. the same type that {@link
-     * Message#getRepeatedField(Descriptors.FieldDescriptor, int)} would return.
-     *
-     * @throws IllegalArgumentException The field is not a repeated field, or
-     *                                  {@code field.getContainingType() !=
-     *                                  getDescriptorForType()}.
-     */
-    MergeTarget setRepeatedField(Descriptors.FieldDescriptor field,
-        int index, Object value);
-
-    /**
-     * Like {@code setRepeatedField}, but appends the value as a new element.
-     *
-     * @throws IllegalArgumentException The field is not a repeated field, or
-     *                                  {@code field.getContainingType() !=
-     *                                  getDescriptorForType()}.
-     */
-    MergeTarget addRepeatedField(Descriptors.FieldDescriptor field,
-        Object value);
-
-    /**
-     * Returns true if the given oneof is set.
-     *
-     * @throws IllegalArgumentException if
-     *           {@code oneof.getContainingType() != getDescriptorForType()}.
-     */
-    boolean hasOneof(Descriptors.OneofDescriptor oneof);
-
-    /**
-     * Clears the oneof.  This is exactly equivalent to calling the generated
-     * "clear" accessor method corresponding to the oneof.
-     */
-    MergeTarget clearOneof(Descriptors.OneofDescriptor oneof);
-
-    /**
-     * Obtains the FieldDescriptor if the given oneof is set. Returns null
-     * if no field is set.
-     */
-    Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof);
-
-    /**
-     * Parse the input stream into a sub field group defined based on either
-     * FieldDescriptor or the default instance.
-     */
-    Object parseGroup(CodedInputStream input, ExtensionRegistryLite registry,
-        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
-        throws IOException;
-
-    /**
-     * Parse the input stream into a sub field message defined based on either
-     * FieldDescriptor or the default instance.
-     */
-    Object parseMessage(CodedInputStream input, ExtensionRegistryLite registry,
-        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
-        throws IOException;
-
-    /**
-     * Parse from a ByteString into a sub field message defined based on either
-     * FieldDescriptor or the default instance.  There isn't a varint indicating
-     * the length of the message at the beginning of the input ByteString.
-     */
-    Object parseMessageFromBytes(
-        ByteString bytes, ExtensionRegistryLite registry,
-        Descriptors.FieldDescriptor descriptor, Message defaultInstance)
-        throws IOException;
-    
-    /**
-     * Read a primitive field from input. Note that builders and mutable
-     * messages may use different Java types to represent a primtive field.
-     */
-    Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException;
-
-    /**
-     * Returns a new merge target for a sub-field. When defaultInstance is
-     * provided, it indicates the descriptor is for an extension type, and
-     * implementations should create a new instance from the defaultInstance
-     * prototype directly.
-     */
-    MergeTarget newMergeTargetForField(
-        Descriptors.FieldDescriptor descriptor,
-        Message defaultInstance);
-
-    /**
-     * Finishes the merge and returns the underlying object.
-     */
-    Object finish();
-  }
-
-  static class BuilderAdapter implements MergeTarget {
-
-    private final Message.Builder builder;
-
-    public Descriptors.Descriptor getDescriptorForType() {
-      return builder.getDescriptorForType();
-    }
-
-    public BuilderAdapter(Message.Builder builder) {
-      this.builder = builder;
-    }
-
-    public Object getField(Descriptors.FieldDescriptor field) {
-      return builder.getField(field);
-    }
-
-    @Override
-    public boolean hasField(Descriptors.FieldDescriptor field) {
-      return builder.hasField(field);
-    }
-
-    public MergeTarget setField(Descriptors.FieldDescriptor field,
-        Object value) {
-      builder.setField(field, value);
-      return this;
-    }
-
-    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
-      builder.clearField(field);
-      return this;
-    }
-
-    public MergeTarget setRepeatedField(
-        Descriptors.FieldDescriptor field, int index, Object value) {
-      builder.setRepeatedField(field, index, value);
-      return this;
-    }
-
-    public MergeTarget addRepeatedField(
-        Descriptors.FieldDescriptor field, Object value) {
-      builder.addRepeatedField(field, value);
-      return this;
-    }
-
-    @Override
-    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
-      return builder.hasOneof(oneof);
-    }
-
-    @Override
-    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
-      builder.clearOneof(oneof);
-      return this;
-    }
-
-    @Override
-    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
-      return builder.getOneofFieldDescriptor(oneof);
-    }
-
-    public ContainerType getContainerType() {
-      return ContainerType.MESSAGE;
-    }
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByName(
-        ExtensionRegistry registry, String name) {
-      return registry.findImmutableExtensionByName(name);
-    }
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
-        ExtensionRegistry registry, Descriptors.Descriptor containingType,
-        int fieldNumber) {
-      return registry.findImmutableExtensionByNumber(containingType,
-          fieldNumber);
-    }
-
-    public Object parseGroup(CodedInputStream input,
-        ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
-        throws IOException {
-      Message.Builder subBuilder;
-      // When default instance is not null. The field is an extension field.
-      if (defaultInstance != null) {
-        subBuilder = defaultInstance.newBuilderForType();
-      } else {
-        subBuilder = builder.newBuilderForField(field);
-      }
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
-      return subBuilder.buildPartial();
-    }
-
-    public Object parseMessage(CodedInputStream input,
-        ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
-        throws IOException {
-      Message.Builder subBuilder;
-      // When default instance is not null. The field is an extension field.
-      if (defaultInstance != null) {
-        subBuilder = defaultInstance.newBuilderForType();
-      } else {
-        subBuilder = builder.newBuilderForField(field);
-      }
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      input.readMessage(subBuilder, extensionRegistry);
-      return subBuilder.buildPartial();
-    }
-
-    public Object parseMessageFromBytes(ByteString bytes,
-        ExtensionRegistryLite extensionRegistry,
-        Descriptors.FieldDescriptor field, Message defaultInstance)
-        throws IOException {
-      Message.Builder subBuilder;
-      // When default instance is not null. The field is an extension field.
-      if (defaultInstance != null) {
-        subBuilder = defaultInstance.newBuilderForType();
-      } else {
-        subBuilder = builder.newBuilderForField(field);
-      }
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      subBuilder.mergeFrom(bytes, extensionRegistry);
-      return subBuilder.buildPartial();
-    }
-
-    public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field,
-        Message defaultInstance) {
-      if (defaultInstance != null) {
-        return new BuilderAdapter(
-            defaultInstance.newBuilderForType());
-      } else {
-        return new BuilderAdapter(builder.newBuilderForField(field));
-      }
-    }
-    
-    public Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException {
-      return FieldSet.readPrimitiveField(input, type, checkUtf8);
-    }
-
-    public Object finish() {
-      return builder.buildPartial();
-    }
-  }
-
-
-  static class ExtensionAdapter implements MergeTarget {
-
-    private final FieldSet<Descriptors.FieldDescriptor> extensions;
-
-    ExtensionAdapter(FieldSet<Descriptors.FieldDescriptor> extensions) {
-      this.extensions = extensions;
-    }
-
-    public Descriptors.Descriptor getDescriptorForType() {
-      throw new UnsupportedOperationException(
-          "getDescriptorForType() called on FieldSet object");
-    }
-
-    public Object getField(Descriptors.FieldDescriptor field) {
-      return extensions.getField(field);
-    }
-
-    public boolean hasField(Descriptors.FieldDescriptor field) {
-      return extensions.hasField(field);
-    }
-
-    public MergeTarget setField(Descriptors.FieldDescriptor field,
-        Object value) {
-      extensions.setField(field, value);
-      return this;
-    }
-
-    public MergeTarget clearField(Descriptors.FieldDescriptor field) {
-      extensions.clearField(field);
-      return this;
-    }
-
-    public MergeTarget setRepeatedField(
-        Descriptors.FieldDescriptor field, int index, Object value) {
-      extensions.setRepeatedField(field, index, value);
-      return this;
-    }
-
-    public MergeTarget addRepeatedField(
-        Descriptors.FieldDescriptor field, Object value) {
-      extensions.addRepeatedField(field, value);
-      return this;
-    }
-
-    @Override
-    public boolean hasOneof(Descriptors.OneofDescriptor oneof) {
-      return false;
-    }
-
-    @Override
-    public MergeTarget clearOneof(Descriptors.OneofDescriptor oneof) {
-      // Nothing to clear.
-      return this;
-    }
-
-    @Override
-    public Descriptors.FieldDescriptor getOneofFieldDescriptor(Descriptors.OneofDescriptor oneof) {
-      return null;
-    }
-
-    public ContainerType getContainerType() {
-      return ContainerType.EXTENSION_SET;
-    }
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByName(
-        ExtensionRegistry registry, String name) {
-      return registry.findImmutableExtensionByName(name);
-    }
-
-    public ExtensionRegistry.ExtensionInfo findExtensionByNumber(
-        ExtensionRegistry registry, Descriptors.Descriptor containingType,
-        int fieldNumber) {
-      return registry.findImmutableExtensionByNumber(containingType,
-          fieldNumber);
-    }
-
-    public Object parseGroup(CodedInputStream input,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
-      Message.Builder subBuilder =
-          defaultInstance.newBuilderForType();
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      input.readGroup(field.getNumber(), subBuilder, registry);
-      return subBuilder.buildPartial();
-    }
-
-    public Object parseMessage(CodedInputStream input,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
-      Message.Builder subBuilder =
-          defaultInstance.newBuilderForType();
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      input.readMessage(subBuilder, registry);
-      return subBuilder.buildPartial();
-    }
-
-    public Object parseMessageFromBytes(ByteString bytes,
-        ExtensionRegistryLite registry, Descriptors.FieldDescriptor field,
-        Message defaultInstance) throws IOException {
-      Message.Builder subBuilder =  defaultInstance.newBuilderForType();
-      if (!field.isRepeated()) {
-        Message originalMessage = (Message) getField(field);
-        if (originalMessage != null) {
-          subBuilder.mergeFrom(originalMessage);
-        }
-      }
-      subBuilder.mergeFrom(bytes, registry);
-      return subBuilder.buildPartial();
-    }
-
-    public MergeTarget newMergeTargetForField(
-        Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
-      throw new UnsupportedOperationException(
-          "newMergeTargetForField() called on FieldSet object");
-    }
-    
-    public Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException {
-      return FieldSet.readPrimitiveField(input, type, checkUtf8);
-    }
-
-    public Object finish() {
-      throw new UnsupportedOperationException(
-          "finish() called on FieldSet object");
-    }
-  }
-
-  /**
-   * Parses a single field into MergeTarget. The target can be Message.Builder,
-   * FieldSet or MutableMessage.
-   *
-   * Package-private because it is used by GeneratedMessage.ExtendableMessage.
-   *
-   * @param tag The tag, which should have already been read.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  static boolean mergeFieldFrom(
-      CodedInputStream input,
-      UnknownFieldSet.Builder unknownFields,
-      ExtensionRegistryLite extensionRegistry,
-      Descriptors.Descriptor type,
-      MergeTarget target,
-      int tag) throws IOException {
-    if (type.getOptions().getMessageSetWireFormat() &&
-        tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
-      mergeMessageSetExtensionFromCodedStream(
-          input, unknownFields, extensionRegistry, type, target);
-      return true;
-    }
-
-    final int wireType = WireFormat.getTagWireType(tag);
-    final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
-    final Descriptors.FieldDescriptor field;
-    Message defaultInstance = null;
-
-    if (type.isExtensionNumber(fieldNumber)) {
-      // extensionRegistry may be either ExtensionRegistry or
-      // ExtensionRegistryLite.  Since the type we are parsing is a full
-      // message, only a full ExtensionRegistry could possibly contain
-      // extensions of it.  Otherwise we will treat the registry as if it
-      // were empty.
-      if (extensionRegistry instanceof ExtensionRegistry) {
-        final ExtensionRegistry.ExtensionInfo extension =
-            target.findExtensionByNumber((ExtensionRegistry) extensionRegistry,
-                type, fieldNumber);
-        if (extension == null) {
-          field = null;
-        } else {
-          field = extension.descriptor;
-          defaultInstance = extension.defaultInstance;
-          if (defaultInstance == null &&
-              field.getJavaType()
-                  == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
-            throw new IllegalStateException(
-                "Message-typed extension lacked default instance: " +
-                    field.getFullName());
-          }
-        }
-      } else {
-        field = null;
-      }
-    } else if (target.getContainerType() == MergeTarget.ContainerType.MESSAGE) {
-      field = type.findFieldByNumber(fieldNumber);
-    } else {
-      field = null;
-    }
-
-    boolean unknown = false;
-    boolean packed = false;
-    if (field == null) {
-      unknown = true;  // Unknown field.
-    } else if (wireType == FieldSet.getWireFormatForFieldType(
-        field.getLiteType(),
-        false  /* isPacked */)) {
-      packed = false;
-    } else if (field.isPackable() &&
-        wireType == FieldSet.getWireFormatForFieldType(
-            field.getLiteType(),
-            true  /* isPacked */)) {
-      packed = true;
-    } else {
-      unknown = true;  // Unknown wire type.
-    }
-
-    if (unknown) {  // Unknown field or wrong wire type.  Skip.
-      return unknownFields.mergeFieldFrom(tag, input);
-    }
-
-    if (packed) {
-      final int length = input.readRawVarint32();
-      final int limit = input.pushLimit(length);
-      if (field.getLiteType() == WireFormat.FieldType.ENUM) {
-        while (input.getBytesUntilLimit() > 0) {
-          final int rawValue = input.readEnum();
-          final Object value = field.getEnumType().findValueByNumber(rawValue);
-          if (value == null) {
-            // If the number isn't recognized as a valid value for this
-            // enum, drop it (don't even add it to unknownFields).
-            return true;
-          }
-          target.addRepeatedField(field, value);
-        }
-      } else {
-        while (input.getBytesUntilLimit() > 0) {
-          final Object value =
-              target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
-          target.addRepeatedField(field, value);
-        }
-      }
-      input.popLimit(limit);
-    } else {
-      final Object value;
-      switch (field.getType()) {
-        case GROUP: {
-          value = target
-              .parseGroup(input, extensionRegistry, field, defaultInstance);
-          break;
-        }
-        case MESSAGE: {
-          value = target
-              .parseMessage(input, extensionRegistry, field, defaultInstance);
-          break;
-        }
-        case ENUM:
-          final int rawValue = input.readEnum();
-          value = field.getEnumType().findValueByNumber(rawValue);
-          // If the number isn't recognized as a valid value for this enum,
-          // drop it.
-          if (value == null) {
-            unknownFields.mergeVarintField(fieldNumber, rawValue);
-            return true;
-          }
-          break;
-        default:
-          value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
-          break;
-      }
-
-      if (field.isRepeated()) {
-        target.addRepeatedField(field, value);
-      } else {
-        target.setField(field, value);
-      }
-    }
-
-    return true;
-  }
-
-  /**
-   * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension into
-   * MergeTarget.
-   */
-  private static void mergeMessageSetExtensionFromCodedStream(
-      CodedInputStream input,
-      UnknownFieldSet.Builder unknownFields,
-      ExtensionRegistryLite extensionRegistry,
-      Descriptors.Descriptor type,
-      MergeTarget target) throws IOException {
-
-    // The wire format for MessageSet is:
-    //   message MessageSet {
-    //     repeated group Item = 1 {
-    //       required int32 typeId = 2;
-    //       required bytes message = 3;
-    //     }
-    //   }
-    // "typeId" is the extension's field number.  The extension can only be
-    // a message type, where "message" contains the encoded bytes of that
-    // message.
-    //
-    // In practice, we will probably never see a MessageSet item in which
-    // the message appears before the type ID, or where either field does not
-    // appear exactly once.  However, in theory such cases are valid, so we
-    // should be prepared to accept them.
-
-    int typeId = 0;
-    ByteString rawBytes = null; // If we encounter "message" before "typeId"
-    ExtensionRegistry.ExtensionInfo extension = null;
-
-    // Read bytes from input, if we get it's type first then parse it eagerly,
-    // otherwise we store the raw bytes in a local variable.
-    while (true) {
-      final int tag = input.readTag();
-      if (tag == 0) {
-        break;
-      }
-
-      if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
-        typeId = input.readUInt32();
-        if (typeId != 0) {
-          // extensionRegistry may be either ExtensionRegistry or
-          // ExtensionRegistryLite. Since the type we are parsing is a full
-          // message, only a full ExtensionRegistry could possibly contain
-          // extensions of it. Otherwise we will treat the registry as if it
-          // were empty.
-          if (extensionRegistry instanceof ExtensionRegistry) {
-            extension = target.findExtensionByNumber(
-                (ExtensionRegistry) extensionRegistry, type, typeId);
-          }
-        }
-
-      } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
-        if (typeId != 0) {
-          if (extension != null &&
-              ExtensionRegistryLite.isEagerlyParseMessageSets()) {
-            // We already know the type, so we can parse directly from the
-            // input with no copying.  Hooray!
-            eagerlyMergeMessageSetExtension(
-                input, extension, extensionRegistry, target);
-            rawBytes = null;
-            continue;
-          }
-        }
-        // We haven't seen a type ID yet or we want parse message lazily.
-        rawBytes = input.readBytes();
-
-      } else { // Unknown tag. Skip it.
-        if (!input.skipField(tag)) {
-          break; // End of group
-        }
-      }
-    }
-    input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
-
-    // Process the raw bytes.
-    if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
-      if (extension != null) { // We known the type
-        mergeMessageSetExtensionFromBytes(
-            rawBytes, extension, extensionRegistry, target);
-      } else { // We don't know how to parse this. Ignore it.
-        if (rawBytes != null) {
-          unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
-              .addLengthDelimited(rawBytes).build());
-        }
-      }
-    }
-  }
-
-  private static void mergeMessageSetExtensionFromBytes(
-      ByteString rawBytes,
-      ExtensionRegistry.ExtensionInfo extension,
-      ExtensionRegistryLite extensionRegistry,
-      MergeTarget target) throws IOException {
-
-    Descriptors.FieldDescriptor field = extension.descriptor;
-    boolean hasOriginalValue = target.hasField(field);
-
-    if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
-      // If the field already exists, we just parse the field.
-      Object value = target.parseMessageFromBytes(
-          rawBytes, extensionRegistry,field, extension.defaultInstance);
-      target.setField(field, value);
-    } else {
-      // Use LazyField to load MessageSet lazily.
-      LazyField lazyField = new LazyField(
-          extension.defaultInstance, extensionRegistry, rawBytes);
-      target.setField(field, lazyField);
-    }
-  }
-
-  private static void eagerlyMergeMessageSetExtension(
-      CodedInputStream input,
-      ExtensionRegistry.ExtensionInfo extension,
-      ExtensionRegistryLite extensionRegistry,
-      MergeTarget target) throws IOException {
-    Descriptors.FieldDescriptor field = extension.descriptor;
-    Object value = target.parseMessage(input, extensionRegistry, field,
-                                       extension.defaultInstance);
-    target.setField(field, value);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Parser.java b/java/src/main/java/com/google/protobuf/Parser.java
deleted file mode 100644
index f636014..0000000
--- a/java/src/main/java/com/google/protobuf/Parser.java
+++ /dev/null
@@ -1,261 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.InputStream;
-
-/**
- * Abstract interface for parsing Protocol Messages.
- *
- * The implementation should be stateless and thread-safe.
- *
- * @author liujisi@google.com (Pherl Liu)
- */
-public interface Parser<MessageType> {
-  /**
-   * Parses a message of {@code MessageType} from the input.
-   *
-   * <p>Note:  The caller should call
-   * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
-   * verify that the last tag seen was the appropriate end-group tag,
-   * or zero for EOF.
-   */
-  public MessageType parseFrom(CodedInputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(CodedInputStream)}, but also parses extensions.
-   * The extensions that you want to be able to parse must be registered in
-   * {@code extensionRegistry}. Extensions not in the registry will be treated
-   * as unknown fields.
-   */
-  public MessageType parseFrom(CodedInputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(CodedInputStream)}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialFrom(CodedInputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialFrom(CodedInputStream input,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  // ---------------------------------------------------------------
-  // Convenience methods.
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
-   */
-  public MessageType parseFrom(ByteString data)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around
-   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
-   */
-  public MessageType parseFrom(ByteString data,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(ByteString)}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialFrom(ByteString data)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialFrom(ByteString data,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
-   */
-  public MessageType parseFrom(byte[] data, int off, int len)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around
-   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
-   */
-  public MessageType parseFrom(byte[] data, int off, int len,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
-   */
-  public MessageType parseFrom(byte[] data)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses {@code data} as a message of {@code MessageType}.
-   * This is just a small wrapper around
-   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
-   */
-  public MessageType parseFrom(byte[] data,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(byte[], int, int)}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialFrom(byte[] data, int off, int len)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialFrom(byte[] data, int off, int len,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(byte[])}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialFrom(byte[] data)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(byte[], ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialFrom(byte[] data,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parse a message of {@code MessageType} from {@code input}.
-   * This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
-   * Note that this method always reads the <i>entire</i> input (unless it
-   * throws an exception).  If you want it to stop earlier, you will need to
-   * wrap your input in some wrapper stream that limits reading.  Or, use
-   * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your
-   * message and {@link #parseDelimitedFrom(InputStream)} to read it.
-   * <p>
-   * Despite usually reading the entire input, this does not close the stream.
-   */
-  public MessageType parseFrom(InputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Parses a message of {@code MessageType} from {@code input}.
-   * This is just a small wrapper around
-   * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
-   */
-  public MessageType parseFrom(InputStream input,
-                               ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(InputStream)}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialFrom(InputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(InputStream, ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialFrom(InputStream input,
-                                      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseFrom(InputStream)}, but does not read util EOF.
-   * Instead, the size of message (encoded as a varint) is read first,
-   * then the message data. Use
-   * {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write
-   * messages in this format.
-   *
-   * @return True if successful, or false if the stream is at EOF when the
-   *         method starts. Any other error (including reaching EOF during
-   *         parsing) will cause an exception to be thrown.
-   */
-  public MessageType parseDelimitedFrom(InputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions.
-   */
-  public MessageType parseDelimitedFrom(InputStream input,
-                                        ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an
-   * exception if the message is missing required fields. Instead, a partial
-   * message is returned.
-   */
-  public MessageType parsePartialDelimitedFrom(InputStream input)
-      throws InvalidProtocolBufferException;
-
-  /**
-   * Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)},
-   * but does not throw an exception if the message is missing required fields.
-   * Instead, a partial message is returned.
-   */
-  public MessageType parsePartialDelimitedFrom(
-      InputStream input,
-      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException;
-}
diff --git a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
deleted file mode 100644
index 0c8df98..0000000
--- a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.EnumDescriptor;
-import com.google.protobuf.Descriptors.EnumValueDescriptor;
-
-/**
- * Interface of useful methods added to all enums generated by the protocol
- * compiler.
- */
-public interface ProtocolMessageEnum extends Internal.EnumLite {
-
-  /**
-   * Return the value's numeric value as defined in the .proto file.
-   */
-  int getNumber();
-
-  /**
-   * Return the value's descriptor, which contains information such as
-   * value name, number, and type.
-   */
-  EnumValueDescriptor getValueDescriptor();
-
-  /**
-   * Return the enum type's descriptor, which contains information
-   * about each defined value, etc.
-   */
-  EnumDescriptor getDescriptorForType();
-}
diff --git a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
deleted file mode 100644
index 22760d3..0000000
--- a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
+++ /dev/null
@@ -1,696 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * {@code RepeatedFieldBuilder} implements a structure that a protocol
- * message uses to hold a repeated field of other protocol messages. It supports
- * the classical use case of adding immutable {@link Message}'s to the
- * repeated field and is highly optimized around this (no extra memory
- * allocations and sharing of immutable arrays).
- * <br>
- * It also supports the additional use case of adding a {@link Message.Builder}
- * to the repeated field and deferring conversion of that {@code Builder}
- * to an immutable {@code Message}. In this way, it's possible to maintain
- * a tree of {@code Builder}'s that acts as a fully read/write data
- * structure.
- * <br>
- * Logically, one can think of a tree of builders as converting the entire tree
- * to messages when build is called on the root or when any method is called
- * that desires a Message instead of a Builder. In terms of the implementation,
- * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
- * classes cache messages that were created so that messages only need to be
- * created when some change occured in its builder or a builder for one of its
- * descendants.
- *
- * @param <MType> the type of message for the field
- * @param <BType> the type of builder for the field
- * @param <IType> the common interface for the message and the builder
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class RepeatedFieldBuilder
-    <MType extends GeneratedMessage,
-     BType extends GeneratedMessage.Builder,
-     IType extends MessageOrBuilder>
-    implements GeneratedMessage.BuilderParent {
-
-  // Parent to send changes to.
-  private GeneratedMessage.BuilderParent parent;
-
-  // List of messages. Never null. It may be immutable, in which case
-  // isMessagesListImmutable will be true. See note below.
-  private List<MType> messages;
-
-  // Whether messages is an mutable array that can be modified.
-  private boolean isMessagesListMutable;
-
-  // List of builders. May be null, in which case, no nested builders were
-  // created. If not null, entries represent the builder for that index.
-  private List<SingleFieldBuilder<MType, BType, IType>> builders;
-
-  // Here are the invariants for messages and builders:
-  // 1. messages is never null and its count corresponds to the number of items
-  //    in the repeated field.
-  // 2. If builders is non-null, messages and builders MUST always
-  //    contain the same number of items.
-  // 3. Entries in either array can be null, but for any index, there MUST be
-  //    either a Message in messages or a builder in builders.
-  // 4. If the builder at an index is non-null, the builder is
-  //    authoritative. This is the case where a Builder was set on the index.
-  //    Any message in the messages array MUST be ignored.
-  // t. If the builder at an index is null, the message in the messages
-  //    list is authoritative. This is the case where a Message (not a Builder)
-  //    was set directly for an index.
-
-  // Indicates that we've built a message and so we are now obligated
-  // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
-  private boolean isClean;
-
-  // A view of this builder that exposes a List interface of messages. This is
-  // initialized on demand. This is fully backed by this object and all changes
-  // are reflected in it. Access to any item converts it to a message if it
-  // was a builder.
-  private MessageExternalList<MType, BType, IType> externalMessageList;
-
-  // A view of this builder that exposes a List interface of builders. This is
-  // initialized on demand. This is fully backed by this object and all changes
-  // are reflected in it. Access to any item converts it to a builder if it
-  // was a message.
-  private BuilderExternalList<MType, BType, IType> externalBuilderList;
-
-  // A view of this builder that exposes a List interface of the interface
-  // implemented by messages and builders. This is initialized on demand. This
-  // is fully backed by this object and all changes are reflected in it.
-  // Access to any item returns either a builder or message depending on
-  // what is most efficient.
-  private MessageOrBuilderExternalList<MType, BType, IType>
-      externalMessageOrBuilderList;
-
-  /**
-   * Constructs a new builder with an empty list of messages.
-   *
-   * @param messages the current list of messages
-   * @param isMessagesListMutable Whether the messages list is mutable
-   * @param parent a listener to notify of changes
-   * @param isClean whether the builder is initially marked clean
-   */
-  public RepeatedFieldBuilder(
-      List<MType> messages,
-      boolean isMessagesListMutable,
-      GeneratedMessage.BuilderParent parent,
-      boolean isClean) {
-    this.messages = messages;
-    this.isMessagesListMutable = isMessagesListMutable;
-    this.parent = parent;
-    this.isClean = isClean;
-  }
-
-  public void dispose() {
-    // Null out parent so we stop sending it invalidations.
-    parent = null;
-  }
-
-  /**
-   * Ensures that the list of messages is mutable so it can be updated. If it's
-   * immutable, a copy is made.
-   */
-  private void ensureMutableMessageList() {
-    if (!isMessagesListMutable) {
-      messages = new ArrayList<MType>(messages);
-      isMessagesListMutable = true;
-    }
-  }
-
-  /**
-   * Ensures that the list of builders is not null. If it's null, the list is
-   * created and initialized to be the same size as the messages list with
-   * null entries.
-   */
-  private void ensureBuilders() {
-    if (this.builders == null) {
-      this.builders =
-          new ArrayList<SingleFieldBuilder<MType, BType, IType>>(
-              messages.size());
-      for (int i = 0; i < messages.size(); i++) {
-        builders.add(null);
-      }
-    }
-  }
-
-  /**
-   * Gets the count of items in the list.
-   *
-   * @return the count of items in the list.
-   */
-  public int getCount() {
-    return messages.size();
-  }
-
-  /**
-   * Gets whether the list is empty.
-   *
-   * @return whether the list is empty
-   */
-  public boolean isEmpty() {
-    return messages.isEmpty();
-  }
-
-  /**
-   * Get the message at the specified index. If the message is currently stored
-   * as a {@code Builder}, it is converted to a {@code Message} by
-   * calling {@link Message.Builder#buildPartial} on it.
-   *
-   * @param index the index of the message to get
-   * @return the message for the specified index
-   */
-  public MType getMessage(int index) {
-    return getMessage(index, false);
-  }
-
-  /**
-   * Get the message at the specified index. If the message is currently stored
-   * as a {@code Builder}, it is converted to a {@code Message} by
-   * calling {@link Message.Builder#buildPartial} on it.
-   *
-   * @param index the index of the message to get
-   * @param forBuild this is being called for build so we want to make sure
-   *     we SingleFieldBuilder.build to send dirty invalidations
-   * @return the message for the specified index
-   */
-  private MType getMessage(int index, boolean forBuild) {
-    if (this.builders == null) {
-      // We don't have any builders -- return the current Message.
-      // This is the case where no builder was created, so we MUST have a
-      // Message.
-      return messages.get(index);
-    }
-
-    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
-    if (builder == null) {
-      // We don't have a builder -- return the current message.
-      // This is the case where no builder was created for the entry at index,
-      // so we MUST have a message.
-      return messages.get(index);
-
-    } else {
-      return forBuild ? builder.build() : builder.getMessage();
-    }
-  }
-
-  /**
-   * Gets a builder for the specified index. If no builder has been created for
-   * that index, a builder is created on demand by calling
-   * {@link Message#toBuilder}.
-   *
-   * @param index the index of the message to get
-   * @return The builder for that index
-   */
-  public BType getBuilder(int index) {
-    ensureBuilders();
-    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
-    if (builder == null) {
-      MType message = messages.get(index);
-      builder = new SingleFieldBuilder<MType, BType, IType>(
-          message, this, isClean);
-      builders.set(index, builder);
-    }
-    return builder.getBuilder();
-  }
-
-  /**
-   * Gets the base class interface for the specified index. This may either be
-   * a builder or a message. It will return whatever is more efficient.
-   *
-   * @param index the index of the message to get
-   * @return the message or builder for the index as the base class interface
-   */
-  @SuppressWarnings("unchecked")
-  public IType getMessageOrBuilder(int index) {
-    if (this.builders == null) {
-      // We don't have any builders -- return the current Message.
-      // This is the case where no builder was created, so we MUST have a
-      // Message.
-      return (IType) messages.get(index);
-    }
-
-    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
-    if (builder == null) {
-      // We don't have a builder -- return the current message.
-      // This is the case where no builder was created for the entry at index,
-      // so we MUST have a message.
-      return (IType) messages.get(index);
-
-    } else {
-      return builder.getMessageOrBuilder();
-    }
-  }
-
-  /**
-   * Sets a  message at the specified index replacing the existing item at
-   * that index.
-   *
-   * @param index the index to set.
-   * @param message the message to set
-   * @return the builder
-   */
-  public RepeatedFieldBuilder<MType, BType, IType> setMessage(
-      int index, MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    ensureMutableMessageList();
-    messages.set(index, message);
-    if (builders != null) {
-      SingleFieldBuilder<MType, BType, IType> entry =
-          builders.set(index, null);
-      if (entry != null) {
-        entry.dispose();
-      }
-    }
-    onChanged();
-    incrementModCounts();
-    return this;
-  }
-
-  /**
-   * Appends the specified element to the end of this list.
-   *
-   * @param message the message to add
-   * @return the builder
-   */
-  public RepeatedFieldBuilder<MType, BType, IType> addMessage(
-      MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    ensureMutableMessageList();
-    messages.add(message);
-    if (builders != null) {
-      builders.add(null);
-    }
-    onChanged();
-    incrementModCounts();
-    return this;
-  }
-
-  /**
-   * Inserts the specified message at the specified position in this list.
-   * Shifts the element currently at that position (if any) and any subsequent
-   * elements to the right (adds one to their indices).
-   *
-   * @param index the index at which to insert the message
-   * @param message the message to add
-   * @return the builder
-   */
-  public RepeatedFieldBuilder<MType, BType, IType> addMessage(
-      int index, MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    ensureMutableMessageList();
-    messages.add(index, message);
-    if (builders != null) {
-      builders.add(index, null);
-    }
-    onChanged();
-    incrementModCounts();
-    return this;
-  }
-
-  /**
-   * Appends all of the messages in the specified collection to the end of
-   * this list, in the order that they are returned by the specified
-   * collection's iterator.
-   *
-   * @param values the messages to add
-   * @return the builder
-   */
-  public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
-      Iterable<? extends MType> values) {
-    for (final MType value : values) {
-      if (value == null) {
-        throw new NullPointerException();
-      }
-    }
-    if (values instanceof Collection) {
-      @SuppressWarnings("unchecked") final
-      Collection<MType> collection = (Collection<MType>) values;
-      if (collection.size() == 0) {
-        return this;
-      }
-      ensureMutableMessageList();
-      for (MType value : values) {
-        addMessage(value);
-      }
-    } else {
-      ensureMutableMessageList();
-      for (MType value : values) {
-        addMessage(value);
-      }
-    }
-    onChanged();
-    incrementModCounts();
-    return this;
-  }
-
-  /**
-   * Appends a new builder to the end of this list and returns the builder.
-   *
-   * @param message the message to add which is the basis of the builder
-   * @return the new builder
-   */
-  public BType addBuilder(MType message) {
-    ensureMutableMessageList();
-    ensureBuilders();
-    SingleFieldBuilder<MType, BType, IType> builder =
-        new SingleFieldBuilder<MType, BType, IType>(
-            message, this, isClean);
-    messages.add(null);
-    builders.add(builder);
-    onChanged();
-    incrementModCounts();
-    return builder.getBuilder();
-  }
-
-  /**
-   * Inserts a new builder at the specified position in this list.
-   * Shifts the element currently at that position (if any) and any subsequent
-   * elements to the right (adds one to their indices).
-   *
-   * @param index the index at which to insert the builder
-   * @param message the message to add which is the basis of the builder
-   * @return the builder
-   */
-  public BType addBuilder(int index, MType message) {
-    ensureMutableMessageList();
-    ensureBuilders();
-    SingleFieldBuilder<MType, BType, IType> builder =
-        new SingleFieldBuilder<MType, BType, IType>(
-            message, this, isClean);
-    messages.add(index, null);
-    builders.add(index, builder);
-    onChanged();
-    incrementModCounts();
-    return builder.getBuilder();
-  }
-
-  /**
-   * Removes the element at the specified position in this list. Shifts any
-   * subsequent elements to the left (subtracts one from their indices).
-   * Returns the element that was removed from the list.
-   *
-   * @param index the index at which to remove the message
-   */
-  public void remove(int index) {
-    ensureMutableMessageList();
-    messages.remove(index);
-    if (builders != null) {
-      SingleFieldBuilder<MType, BType, IType> entry =
-          builders.remove(index);
-      if (entry != null) {
-        entry.dispose();
-      }
-    }
-    onChanged();
-    incrementModCounts();
-  }
-
-  /**
-   * Removes all of the elements from this list.
-   * The list will be empty after this call returns.
-   */
-  public void clear() {
-    messages = Collections.emptyList();
-    isMessagesListMutable = false;
-    if (builders != null) {
-      for (SingleFieldBuilder<MType, BType, IType> entry :
-          builders) {
-        if (entry != null) {
-          entry.dispose();
-        }
-      }
-      builders = null;
-    }
-    onChanged();
-    incrementModCounts();
-  }
-
-  /**
-   * Builds the list of messages from the builder and returns them.
-   *
-   * @return an immutable list of messages
-   */
-  public List<MType> build() {
-    // Now that build has been called, we are required to dispatch
-    // invalidations.
-    isClean = true;
-
-    if (!isMessagesListMutable && builders == null) {
-      // We still have an immutable list and we never created a builder.
-      return messages;
-    }
-
-    boolean allMessagesInSync = true;
-    if (!isMessagesListMutable) {
-      // We still have an immutable list. Let's see if any of them are out
-      // of sync with their builders.
-      for (int i = 0; i < messages.size(); i++) {
-        Message message = messages.get(i);
-        SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
-        if (builder != null) {
-          if (builder.build() != message) {
-            allMessagesInSync = false;
-            break;
-          }
-        }
-      }
-      if (allMessagesInSync) {
-        // Immutable list is still in sync.
-        return messages;
-      }
-    }
-
-    // Need to make sure messages is up to date
-    ensureMutableMessageList();
-    for (int i = 0; i < messages.size(); i++) {
-      messages.set(i, getMessage(i, true));
-    }
-
-    // We're going to return our list as immutable so we mark that we can
-    // no longer update it.
-    messages = Collections.unmodifiableList(messages);
-    isMessagesListMutable = false;
-    return messages;
-  }
-
-  /**
-   * Gets a view of the builder as a list of messages. The returned list is live
-   * and will reflect any changes to the underlying builder.
-   *
-   * @return the messages in the list
-   */
-  public List<MType> getMessageList() {
-    if (externalMessageList == null) {
-      externalMessageList =
-          new MessageExternalList<MType, BType, IType>(this);
-    }
-    return externalMessageList;
-  }
-
-  /**
-   * Gets a view of the builder as a list of builders. This returned list is
-   * live and will reflect any changes to the underlying builder.
-   *
-   * @return the builders in the list
-   */
-  public List<BType> getBuilderList() {
-    if (externalBuilderList == null) {
-      externalBuilderList =
-          new BuilderExternalList<MType, BType, IType>(this);
-    }
-    return externalBuilderList;
-  }
-
-  /**
-   * Gets a view of the builder as a list of MessageOrBuilders. This returned
-   * list is live and will reflect any changes to the underlying builder.
-   *
-   * @return the builders in the list
-   */
-  public List<IType> getMessageOrBuilderList() {
-    if (externalMessageOrBuilderList == null) {
-      externalMessageOrBuilderList =
-          new MessageOrBuilderExternalList<MType, BType, IType>(this);
-    }
-    return externalMessageOrBuilderList;
-  }
-
-  /**
-   * Called when a the builder or one of its nested children has changed
-   * and any parent should be notified of its invalidation.
-   */
-  private void onChanged() {
-    if (isClean && parent != null) {
-      parent.markDirty();
-
-      // Don't keep dispatching invalidations until build is called again.
-      isClean = false;
-    }
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void markDirty() {
-    onChanged();
-  }
-
-  /**
-   * Increments the mod counts so that an ConcurrentModificationException can
-   * be thrown if calling code tries to modify the builder while its iterating
-   * the list.
-   */
-  private void incrementModCounts() {
-    if (externalMessageList != null) {
-      externalMessageList.incrementModCount();
-    }
-    if (externalBuilderList != null) {
-      externalBuilderList.incrementModCount();
-    }
-    if (externalMessageOrBuilderList != null) {
-      externalMessageOrBuilderList.incrementModCount();
-    }
-  }
-
-  /**
-   * Provides a live view of the builder as a list of messages.
-   *
-   * @param <MType> the type of message for the field
-   * @param <BType> the type of builder for the field
-   * @param <IType> the common interface for the message and the builder
-   */
-  private static class MessageExternalList<
-      MType extends GeneratedMessage,
-      BType extends GeneratedMessage.Builder,
-      IType extends MessageOrBuilder>
-      extends AbstractList<MType> implements List<MType> {
-
-    RepeatedFieldBuilder<MType, BType, IType> builder;
-
-    MessageExternalList(
-        RepeatedFieldBuilder<MType, BType, IType> builder) {
-      this.builder = builder;
-    }
-
-    public int size() {
-      return this.builder.getCount();
-    }
-
-    public MType get(int index) {
-      return builder.getMessage(index);
-    }
-
-    void incrementModCount() {
-      modCount++;
-    }
-  }
-
-  /**
-   * Provides a live view of the builder as a list of builders.
-   *
-   * @param <MType> the type of message for the field
-   * @param <BType> the type of builder for the field
-   * @param <IType> the common interface for the message and the builder
-   */
-  private static class BuilderExternalList<
-      MType extends GeneratedMessage,
-      BType extends GeneratedMessage.Builder,
-      IType extends MessageOrBuilder>
-      extends AbstractList<BType> implements List<BType> {
-
-    RepeatedFieldBuilder<MType, BType, IType> builder;
-
-    BuilderExternalList(
-        RepeatedFieldBuilder<MType, BType, IType> builder) {
-      this.builder = builder;
-    }
-
-    public int size() {
-      return this.builder.getCount();
-    }
-
-    public BType get(int index) {
-      return builder.getBuilder(index);
-    }
-
-    void incrementModCount() {
-      modCount++;
-    }
-  }
-
-  /**
-   * Provides a live view of the builder as a list of builders.
-   *
-   * @param <MType> the type of message for the field
-   * @param <BType> the type of builder for the field
-   * @param <IType> the common interface for the message and the builder
-   */
-  private static class MessageOrBuilderExternalList<
-      MType extends GeneratedMessage,
-      BType extends GeneratedMessage.Builder,
-      IType extends MessageOrBuilder>
-      extends AbstractList<IType> implements List<IType> {
-
-    RepeatedFieldBuilder<MType, BType, IType> builder;
-
-    MessageOrBuilderExternalList(
-        RepeatedFieldBuilder<MType, BType, IType> builder) {
-      this.builder = builder;
-    }
-
-    public int size() {
-      return this.builder.getCount();
-    }
-
-    public IType get(int index) {
-      return builder.getMessageOrBuilder(index);
-    }
-
-    void incrementModCount() {
-      modCount++;
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/RopeByteString.java b/java/src/main/java/com/google/protobuf/RopeByteString.java
deleted file mode 100644
index d1655b8..0000000
--- a/java/src/main/java/com/google/protobuf/RopeByteString.java
+++ /dev/null
@@ -1,957 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.io.ByteArrayInputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Stack;
-
-/**
- * Class to represent {@code ByteStrings} formed by concatenation of other
- * ByteStrings, without copying the data in the pieces. The concatenation is
- * represented as a tree whose leaf nodes are each a {@link LiteralByteString}.
- *
- * <p>Most of the operation here is inspired by the now-famous paper <a
- * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
- * BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
- * michael plass
- *
- * <p>The algorithms described in the paper have been implemented for character
- * strings in {@link com.google.common.string.Rope} and in the c++ class {@code
- * cord.cc}.
- *
- * <p>Fundamentally the Rope algorithm represents the collection of pieces as a
- * binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
- * sequence length, sequences that are too short relative to their depth cause a
- * tree rebalance.  More precisely, a tree of depth d is "balanced" in the
- * terminology of BAP95 if its length is at least F(d+2), where F(n) is the
- * n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum
- * lengths 1, 2, 3, 5, 8, 13,...
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-class RopeByteString extends ByteString {
-
-  /**
-   * BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
-   * depth n is "balanced", i.e flat enough, if its length is at least Fn+2,
-   * e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at
-   * least 2, of depth 4 must have length >= 8, etc.
-   *
-   * <p>There's nothing special about using the Fibonacci numbers for this, but
-   * they are a reasonable sequence for encapsulating the idea that we are OK
-   * with longer strings being encoded in deeper binary trees.
-   *
-   * <p>For 32-bit integers, this array has length 46.
-   */
-  private static final int[] minLengthByDepth;
-
-  static {
-    // Dynamically generate the list of Fibonacci numbers the first time this
-    // class is accessed.
-    List<Integer> numbers = new ArrayList<Integer>();
-
-    // we skip the first Fibonacci number (1).  So instead of: 1 1 2 3 5 8 ...
-    // we have: 1 2 3 5 8 ...
-    int f1 = 1;
-    int f2 = 1;
-
-    // get all the values until we roll over.
-    while (f2 > 0) {
-      numbers.add(f2);
-      int temp = f1 + f2;
-      f1 = f2;
-      f2 = temp;
-    }
-
-    // we include this here so that we can index this array to [x + 1] in the
-    // loops below.
-    numbers.add(Integer.MAX_VALUE);
-    minLengthByDepth = new int[numbers.size()];
-    for (int i = 0; i < minLengthByDepth.length; i++) {
-      // unbox all the values
-      minLengthByDepth[i] = numbers.get(i);
-    }
-  }
-
-  private final int totalLength;
-  private final ByteString left;
-  private final ByteString right;
-  private final int leftLength;
-  private final int treeDepth;
-
-  /**
-   * Create a new RopeByteString, which can be thought of as a new tree node, by
-   * recording references to the two given strings.
-   *
-   * @param left  string on the left of this node, should have {@code size() >
-   *              0}
-   * @param right string on the right of this node, should have {@code size() >
-   *              0}
-   */
-  private RopeByteString(ByteString left, ByteString right) {
-    this.left = left;
-    this.right = right;
-    leftLength = left.size();
-    totalLength = leftLength + right.size();
-    treeDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
-  }
-
-  /**
-   * Concatenate the given strings while performing various optimizations to
-   * slow the growth rate of tree depth and tree node count. The result is
-   * either a {@link LiteralByteString} or a {@link RopeByteString}
-   * depending on which optimizations, if any, were applied.
-   *
-   * <p>Small pieces of length less than {@link
-   * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
-   * BAP95.  Large pieces are referenced without copy.
-   *
-   * @param left  string on the left
-   * @param right string on the right
-   * @return concatenation representing the same sequence as the given strings
-   */
-  static ByteString concatenate(ByteString left, ByteString right) {
-    ByteString result;
-    RopeByteString leftRope =
-        (left instanceof RopeByteString) ? (RopeByteString) left : null;
-    if (right.size() == 0) {
-      result = left;
-    } else if (left.size() == 0) {
-      result = right;
-    } else {
-      int newLength = left.size() + right.size();
-      if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
-        // Optimization from BAP95: For short (leaves in paper, but just short
-        // here) total length, do a copy of data to a new leaf.
-        result = concatenateBytes(left, right);
-      } else if (leftRope != null
-          && leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
-        // Optimization from BAP95: As an optimization of the case where the
-        // ByteString is constructed by repeated concatenate, recognize the case
-        // where a short string is concatenated to a left-hand node whose
-        // right-hand branch is short.  In the paper this applies to leaves, but
-        // we just look at the length here. This has the advantage of shedding
-        // references to unneeded data when substrings have been taken.
-        //
-        // When we recognize this case, we do a copy of the data and create a
-        // new parent node so that the depth of the result is the same as the
-        // given left tree.
-        ByteString newRight = concatenateBytes(leftRope.right, right);
-        result = new RopeByteString(leftRope.left, newRight);
-      } else if (leftRope != null
-          && leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
-          && leftRope.getTreeDepth() > right.getTreeDepth()) {
-        // Typically for concatenate-built strings the left-side is deeper than
-        // the right.  This is our final attempt to concatenate without
-        // increasing the tree depth.  We'll redo the the node on the RHS.  This
-        // is yet another optimization for building the string by repeatedly
-        // concatenating on the right.
-        ByteString newRight = new RopeByteString(leftRope.right, right);
-        result = new RopeByteString(leftRope.left, newRight);
-      } else {
-        // Fine, we'll add a node and increase the tree depth--unless we
-        // rebalance ;^)
-        int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
-        if (newLength >= minLengthByDepth[newDepth]) {
-          // The tree is shallow enough, so don't rebalance
-          result = new RopeByteString(left, right);
-        } else {
-          result = new Balancer().balance(left, right);
-        }
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Concatenates two strings by copying data values. This is called in a few
-   * cases in order to reduce the growth of the number of tree nodes.
-   *
-   * @param left  string on the left
-   * @param right string on the right
-   * @return string formed by copying data bytes
-   */
-  private static LiteralByteString concatenateBytes(ByteString left,
-      ByteString right) {
-    int leftSize = left.size();
-    int rightSize = right.size();
-    byte[] bytes = new byte[leftSize + rightSize];
-    left.copyTo(bytes, 0, 0, leftSize);
-    right.copyTo(bytes, 0, leftSize, rightSize);
-    return new LiteralByteString(bytes);  // Constructor wraps bytes
-  }
-
-  /**
-   * Create a new RopeByteString for testing only while bypassing all the
-   * defenses of {@link #concatenate(ByteString, ByteString)}. This allows
-   * testing trees of specific structure. We are also able to insert empty
-   * leaves, though these are dis-allowed, so that we can make sure the
-   * implementation can withstand their presence.
-   *
-   * @param left  string on the left of this node
-   * @param right string on the right of this node
-   * @return an unsafe instance for testing only
-   */
-  static RopeByteString newInstanceForTest(ByteString left, ByteString right) {
-    return new RopeByteString(left, right);
-  }
-
-  /**
-   * Gets the byte at the given index.
-   * Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility
-   * reasons although it would more properly be {@link
-   * IndexOutOfBoundsException}.
-   *
-   * @param index index of byte
-   * @return the value
-   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
-   */
-  @Override
-  public byte byteAt(int index) {
-    if (index < 0) {
-      throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
-    }
-    if (index > totalLength) {
-      throw new ArrayIndexOutOfBoundsException(
-          "Index > length: " + index + ", " + totalLength);
-    }
-
-    byte result;
-    // Find the relevant piece by recursive descent
-    if (index < leftLength) {
-      result = left.byteAt(index);
-    } else {
-      result = right.byteAt(index - leftLength);
-    }
-    return result;
-  }
-
-  @Override
-  public int size() {
-    return totalLength;
-  }
-
-  // =================================================================
-  // Pieces
-
-  @Override
-  protected int getTreeDepth() {
-    return treeDepth;
-  }
-
-  /**
-   * Determines if the tree is balanced according to BAP95, which means the tree
-   * is flat-enough with respect to the bounds. Note that this definition of
-   * balanced is one where sub-trees of balanced trees are not necessarily
-   * balanced.
-   *
-   * @return true if the tree is balanced
-   */
-  @Override
-  protected boolean isBalanced() {
-    return totalLength >= minLengthByDepth[treeDepth];
-  }
-
-  /**
-   * Takes a substring of this one. This involves recursive descent along the
-   * left and right edges of the substring, and referencing any wholly contained
-   * segments in between. Any leaf nodes entirely uninvolved in the substring
-   * will not be referenced by the substring.
-   *
-   * <p>Substrings of {@code length < 2} should result in at most a single
-   * recursive call chain, terminating at a leaf node. Thus the result will be a
-   * {@link LiteralByteString}. {@link #RopeByteString(ByteString,
-   * ByteString)}.
-   *
-   * @param beginIndex start at this index
-   * @param endIndex   the last character is the one before this index
-   * @return substring leaf node or tree
-   */
-  @Override
-  public ByteString substring(int beginIndex, int endIndex) {
-    if (beginIndex < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index: " + beginIndex + " < 0");
-    }
-    if (endIndex > totalLength) {
-      throw new IndexOutOfBoundsException(
-          "End index: " + endIndex + " > " + totalLength);
-    }
-    int substringLength = endIndex - beginIndex;
-    if (substringLength < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index larger than ending index: " + beginIndex + ", "
-              + endIndex);
-    }
-
-    ByteString result;
-    if (substringLength == 0) {
-      // Empty substring
-      result = ByteString.EMPTY;
-    } else if (substringLength == totalLength) {
-      // The whole string
-      result = this;
-    } else {
-      // Proper substring
-      if (endIndex <= leftLength) {
-        // Substring on the left
-        result = left.substring(beginIndex, endIndex);
-      } else if (beginIndex >= leftLength) {
-        // Substring on the right
-        result = right
-            .substring(beginIndex - leftLength, endIndex - leftLength);
-      } else {
-        // Split substring
-        ByteString leftSub = left.substring(beginIndex);
-        ByteString rightSub = right.substring(0, endIndex - leftLength);
-        // Intentionally not rebalancing, since in many cases these two
-        // substrings will already be less deep than the top-level
-        // RopeByteString we're taking a substring of.
-        result = new RopeByteString(leftSub, rightSub);
-      }
-    }
-    return result;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  @Override
-  protected void copyToInternal(byte[] target, int sourceOffset,
-      int targetOffset, int numberToCopy) {
-   if (sourceOffset + numberToCopy <= leftLength) {
-      left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
-    } else if (sourceOffset >= leftLength) {
-      right.copyToInternal(target, sourceOffset - leftLength, targetOffset,
-          numberToCopy);
-    } else {
-      int leftLength = this.leftLength - sourceOffset;
-      left.copyToInternal(target, sourceOffset, targetOffset, leftLength);
-      right.copyToInternal(target, 0, targetOffset + leftLength,
-          numberToCopy - leftLength);
-    }
-  }
-
-  @Override
-  public void copyTo(ByteBuffer target) {
-    left.copyTo(target);
-    right.copyTo(target);
-  }
-
-  @Override
-  public ByteBuffer asReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer = ByteBuffer.wrap(toByteArray());
-    return byteBuffer.asReadOnlyBuffer();
-  }
-
-  @Override
-  public List<ByteBuffer> asReadOnlyByteBufferList() {
-    // Walk through the list of LiteralByteString's that make up this
-    // rope, and add each one as a read-only ByteBuffer.
-    List<ByteBuffer> result = new ArrayList<ByteBuffer>();
-    PieceIterator pieces = new PieceIterator(this);
-    while (pieces.hasNext()) {
-      LiteralByteString byteString = pieces.next();
-      result.add(byteString.asReadOnlyByteBuffer());
-    }
-    return result;
-  }
-
-  @Override
-  public void writeTo(OutputStream outputStream) throws IOException {
-    left.writeTo(outputStream);
-    right.writeTo(outputStream);
-  }
-
-  @Override
-  void writeToInternal(OutputStream out, int sourceOffset,
-      int numberToWrite) throws IOException {
-    if (sourceOffset + numberToWrite <= leftLength) {
-      left.writeToInternal(out, sourceOffset, numberToWrite);
-    } else if (sourceOffset >= leftLength) {
-      right.writeToInternal(out, sourceOffset - leftLength, numberToWrite);
-    } else {
-      int numberToWriteInLeft = leftLength - sourceOffset;
-      left.writeToInternal(out, sourceOffset, numberToWriteInLeft);
-      right.writeToInternal(out, 0, numberToWrite - numberToWriteInLeft);
-    }
-  }
-
-  @Override
-  public String toString(String charsetName)
-      throws UnsupportedEncodingException {
-    return new String(toByteArray(), charsetName);
-  }
-
-  // =================================================================
-  // UTF-8 decoding
-
-  @Override
-  public boolean isValidUtf8() {
-    int leftPartial = left.partialIsValidUtf8(Utf8.COMPLETE, 0, leftLength);
-    int state = right.partialIsValidUtf8(leftPartial, 0, right.size());
-    return state == Utf8.COMPLETE;
-  }
-
-  @Override
-  protected int partialIsValidUtf8(int state, int offset, int length) {
-    int toIndex = offset + length;
-    if (toIndex <= leftLength) {
-      return left.partialIsValidUtf8(state, offset, length);
-    } else if (offset >= leftLength) {
-      return right.partialIsValidUtf8(state, offset - leftLength, length);
-    } else {
-      int leftLength = this.leftLength - offset;
-      int leftPartial = left.partialIsValidUtf8(state, offset, leftLength);
-      return right.partialIsValidUtf8(leftPartial, 0, length - leftLength);
-    }
-  }
-
-  // =================================================================
-  // equals() and hashCode()
-
-  @Override
-  public boolean equals(Object other) {
-    if (other == this) {
-      return true;
-    }
-    if (!(other instanceof ByteString)) {
-      return false;
-    }
-
-    ByteString otherByteString = (ByteString) other;
-    if (totalLength != otherByteString.size()) {
-      return false;
-    }
-    if (totalLength == 0) {
-      return true;
-    }
-
-    // You don't really want to be calling equals on long strings, but since
-    // we cache the hashCode, we effectively cache inequality. We use the cached
-    // hashCode if it's already computed.  It's arguable we should compute the
-    // hashCode here, and if we're going to be testing a bunch of byteStrings,
-    // it might even make sense.
-    if (hash != 0) {
-      int cachedOtherHash = otherByteString.peekCachedHashCode();
-      if (cachedOtherHash != 0 && hash != cachedOtherHash) {
-        return false;
-      }
-    }
-
-    return equalsFragments(otherByteString);
-  }
-
-  /**
-   * Determines if this string is equal to another of the same length by
-   * iterating over the leaf nodes. On each step of the iteration, the
-   * overlapping segments of the leaves are compared.
-   *
-   * @param other string of the same length as this one
-   * @return true if the values of this string equals the value of the given
-   *         one
-   */
-  private boolean equalsFragments(ByteString other) {
-    int thisOffset = 0;
-    Iterator<LiteralByteString> thisIter = new PieceIterator(this);
-    LiteralByteString thisString = thisIter.next();
-
-    int thatOffset = 0;
-    Iterator<LiteralByteString> thatIter = new PieceIterator(other);
-    LiteralByteString thatString = thatIter.next();
-
-    int pos = 0;
-    while (true) {
-      int thisRemaining = thisString.size() - thisOffset;
-      int thatRemaining = thatString.size() - thatOffset;
-      int bytesToCompare = Math.min(thisRemaining, thatRemaining);
-
-      // At least one of the offsets will be zero
-      boolean stillEqual = (thisOffset == 0)
-          ? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
-          : thatString.equalsRange(thisString, thisOffset, bytesToCompare);
-      if (!stillEqual) {
-        return false;
-      }
-
-      pos += bytesToCompare;
-      if (pos >= totalLength) {
-        if (pos == totalLength) {
-          return true;
-        }
-        throw new IllegalStateException();
-      }
-      // We always get to the end of at least one of the pieces
-      if (bytesToCompare == thisRemaining) { // If reached end of this
-        thisOffset = 0;
-        thisString = thisIter.next();
-      } else {
-        thisOffset += bytesToCompare;
-      }
-      if (bytesToCompare == thatRemaining) { // If reached end of that
-        thatOffset = 0;
-        thatString = thatIter.next();
-      } else {
-        thatOffset += bytesToCompare;
-      }
-    }
-  }
-
-  /**
-   * Cached hash value.  Intentionally accessed via a data race, which is safe
-   * because of the Java Memory Model's "no out-of-thin-air values" guarantees
-   * for ints.
-   */
-  private int hash = 0;
-
-  @Override
-  public int hashCode() {
-    int h = hash;
-
-    if (h == 0) {
-      h = totalLength;
-      h = partialHash(h, 0, totalLength);
-      if (h == 0) {
-        h = 1;
-      }
-      hash = h;
-    }
-    return h;
-  }
-
-  @Override
-  protected int peekCachedHashCode() {
-    return hash;
-  }
-
-  @Override
-  protected int partialHash(int h, int offset, int length) {
-    int toIndex = offset + length;
-    if (toIndex <= leftLength) {
-      return left.partialHash(h, offset, length);
-    } else if (offset >= leftLength) {
-      return right.partialHash(h, offset - leftLength, length);
-    } else {
-      int leftLength = this.leftLength - offset;
-      int leftPartial = left.partialHash(h, offset, leftLength);
-      return right.partialHash(leftPartial, 0, length - leftLength);
-    }
-  }
-
-  // =================================================================
-  // Input stream
-
-  @Override
-  public CodedInputStream newCodedInput() {
-    return CodedInputStream.newInstance(new RopeInputStream());
-  }
-
-  @Override
-  public InputStream newInput() {
-    return new RopeInputStream();
-  }
-
-  /**
-   * This class implements the balancing algorithm of BAP95. In the paper the
-   * authors use an array to keep track of pieces, while here we use a stack.
-   * The tree is balanced by traversing subtrees in left to right order, and the
-   * stack always contains the part of the string we've traversed so far.
-   *
-   * <p>One surprising aspect of the algorithm is the result of balancing is not
-   * necessarily balanced, though it is nearly balanced.  For details, see
-   * BAP95.
-   */
-  private static class Balancer {
-    // Stack containing the part of the string, starting from the left, that
-    // we've already traversed.  The final string should be the equivalent of
-    // concatenating the strings on the stack from bottom to top.
-    private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
-
-    private ByteString balance(ByteString left, ByteString right) {
-      doBalance(left);
-      doBalance(right);
-
-      // Sweep stack to gather the result
-      ByteString partialString = prefixesStack.pop();
-      while (!prefixesStack.isEmpty()) {
-        ByteString newLeft = prefixesStack.pop();
-        partialString = new RopeByteString(newLeft, partialString);
-      }
-      // We should end up with a RopeByteString since at a minimum we will
-      // create one from concatenating left and right
-      return partialString;
-    }
-
-    private void doBalance(ByteString root) {
-      // BAP95: Insert balanced subtrees whole. This means the result might not
-      // be balanced, leading to repeated rebalancings on concatenate. However,
-      // these rebalancings are shallow due to ignoring balanced subtrees, and
-      // relatively few calls to insert() result.
-      if (root.isBalanced()) {
-        insert(root);
-      } else if (root instanceof RopeByteString) {
-        RopeByteString rbs = (RopeByteString) root;
-        doBalance(rbs.left);
-        doBalance(rbs.right);
-      } else {
-        throw new IllegalArgumentException(
-            "Has a new type of ByteString been created? Found " +
-                root.getClass());
-      }
-    }
-
-    /**
-     * Push a string on the balance stack (BAP95).  BAP95 uses an array and
-     * calls the elements in the array 'bins'.  We instead use a stack, so the
-     * 'bins' of lengths are represented by differences between the elements of
-     * minLengthByDepth.
-     *
-     * <p>If the length bin for our string, and all shorter length bins, are
-     * empty, we just push it on the stack.  Otherwise, we need to start
-     * concatenating, putting the given string in the "middle" and continuing
-     * until we land in an empty length bin that matches the length of our
-     * concatenation.
-     *
-     * @param byteString string to place on the balance stack
-     */
-    private void insert(ByteString byteString) {
-      int depthBin = getDepthBinForLength(byteString.size());
-      int binEnd = minLengthByDepth[depthBin + 1];
-
-      // BAP95: Concatenate all trees occupying bins representing the length of
-      // our new piece or of shorter pieces, to the extent that is possible.
-      // The goal is to clear the bin which our piece belongs in, but that may
-      // not be entirely possible if there aren't enough longer bins occupied.
-      if (prefixesStack.isEmpty() || prefixesStack.peek().size() >= binEnd) {
-        prefixesStack.push(byteString);
-      } else {
-        int binStart = minLengthByDepth[depthBin];
-
-        // Concatenate the subtrees of shorter length
-        ByteString newTree = prefixesStack.pop();
-        while (!prefixesStack.isEmpty()
-            && prefixesStack.peek().size() < binStart) {
-          ByteString left = prefixesStack.pop();
-          newTree = new RopeByteString(left, newTree);
-        }
-
-        // Concatenate the given string
-        newTree = new RopeByteString(newTree, byteString);
-
-        // Continue concatenating until we land in an empty bin
-        while (!prefixesStack.isEmpty()) {
-          depthBin = getDepthBinForLength(newTree.size());
-          binEnd = minLengthByDepth[depthBin + 1];
-          if (prefixesStack.peek().size() < binEnd) {
-            ByteString left = prefixesStack.pop();
-            newTree = new RopeByteString(left, newTree);
-          } else {
-            break;
-          }
-        }
-        prefixesStack.push(newTree);
-      }
-    }
-
-    private int getDepthBinForLength(int length) {
-      int depth = Arrays.binarySearch(minLengthByDepth, length);
-      if (depth < 0) {
-        // It wasn't an exact match, so convert to the index of the containing
-        // fragment, which is one less even than the insertion point.
-        int insertionPoint = -(depth + 1);
-        depth = insertionPoint - 1;
-      }
-
-      return depth;
-    }
-  }
-
-  /**
-   * This class is a continuable tree traversal, which keeps the state
-   * information which would exist on the stack in a recursive traversal instead
-   * on a stack of "Bread Crumbs". The maximum depth of the stack in this
-   * iterator is the same as the depth of the tree being traversed.
-   *
-   * <p>This iterator is used to implement
-   * {@link RopeByteString#equalsFragments(ByteString)}.
-   */
-  private static class PieceIterator implements Iterator<LiteralByteString> {
-
-    private final Stack<RopeByteString> breadCrumbs =
-        new Stack<RopeByteString>();
-    private LiteralByteString next;
-
-    private PieceIterator(ByteString root) {
-      next = getLeafByLeft(root);
-    }
-
-    private LiteralByteString getLeafByLeft(ByteString root) {
-      ByteString pos = root;
-      while (pos instanceof RopeByteString) {
-        RopeByteString rbs = (RopeByteString) pos;
-        breadCrumbs.push(rbs);
-        pos = rbs.left;
-      }
-      return (LiteralByteString) pos;
-    }
-
-    private LiteralByteString getNextNonEmptyLeaf() {
-      while (true) {
-        // Almost always, we go through this loop exactly once.  However, if
-        // we discover an empty string in the rope, we toss it and try again.
-        if (breadCrumbs.isEmpty()) {
-          return null;
-        } else {
-          LiteralByteString result = getLeafByLeft(breadCrumbs.pop().right);
-          if (!result.isEmpty()) {
-            return result;
-          }
-        }
-      }
-    }
-
-    public boolean hasNext() {
-      return next != null;
-    }
-
-    /**
-     * Returns the next item and advances one {@code LiteralByteString}.
-     *
-     * @return next non-empty LiteralByteString or {@code null}
-     */
-    public LiteralByteString next() {
-      if (next == null) {
-        throw new NoSuchElementException();
-      }
-      LiteralByteString result = next;
-      next = getNextNonEmptyLeaf();
-      return result;
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new RopeByteIterator();
-  }
-
-  private class RopeByteIterator implements ByteString.ByteIterator {
-
-    private final PieceIterator pieces;
-    private ByteIterator bytes;
-    int bytesRemaining;
-
-    private RopeByteIterator() {
-      pieces = new PieceIterator(RopeByteString.this);
-      bytes = pieces.next().iterator();
-      bytesRemaining = size();
-    }
-
-    public boolean hasNext() {
-      return (bytesRemaining > 0);
-    }
-
-    public Byte next() {
-      return nextByte(); // Does not instantiate a Byte
-    }
-
-    public byte nextByte() {
-      if (!bytes.hasNext()) {
-        bytes = pieces.next().iterator();
-      }
-      --bytesRemaining;
-      return bytes.nextByte();
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  /**
-   * This class is the {@link RopeByteString} equivalent for
-   * {@link ByteArrayInputStream}.
-   */
-  private class RopeInputStream extends InputStream {
-    // Iterates through the pieces of the rope
-    private PieceIterator pieceIterator;
-    // The current piece
-    private LiteralByteString currentPiece;
-    // The size of the current piece
-    private int currentPieceSize;
-    // The index of the next byte to read in the current piece
-    private int currentPieceIndex;
-    // The offset of the start of the current piece in the rope byte string
-    private int currentPieceOffsetInRope;
-    // Offset in the buffer at which user called mark();
-    private int mark;
-
-    public RopeInputStream() {
-      initialize();
-    }
-
-    @Override
-    public int read(byte b[], int offset, int length)  {
-      if (b == null) {
-        throw new NullPointerException();
-      } else if (offset < 0 || length < 0 || length > b.length - offset) {
-        throw new IndexOutOfBoundsException();
-      }
-      return readSkipInternal(b, offset, length);
-    }
-
-    @Override
-    public long skip(long length) {
-      if (length < 0) {
-        throw new IndexOutOfBoundsException();
-      } else if (length > Integer.MAX_VALUE) {
-        length = Integer.MAX_VALUE;
-      }
-      return readSkipInternal(null, 0, (int) length);
-    }
-
-    /**
-     * Internal implementation of read and skip.  If b != null, then read the
-     * next {@code length} bytes into the buffer {@code b} at
-     * offset {@code offset}.  If b == null, then skip the next {@code length)
-     * bytes.
-     * <p>
-     * This method assumes that all error checking has already happened.
-     * <p>
-     * Returns the actual number of bytes read or skipped.
-     */
-    private int readSkipInternal(byte b[], int offset, int length)  {
-      int bytesRemaining = length;
-      while (bytesRemaining > 0) {
-        advanceIfCurrentPieceFullyRead();
-        if (currentPiece == null) {
-          if (bytesRemaining == length) {
-             // We didn't manage to read anything
-             return -1;
-           }
-          break;
-        } else {
-          // Copy the bytes from this piece.
-          int currentPieceRemaining = currentPieceSize - currentPieceIndex;
-          int count = Math.min(currentPieceRemaining, bytesRemaining);
-          if (b != null) {
-            currentPiece.copyTo(b, currentPieceIndex, offset, count);
-            offset += count;
-          }
-          currentPieceIndex += count;
-          bytesRemaining -= count;
-        }
-      }
-       // Return the number of bytes read.
-      return length - bytesRemaining;
-    }
-
-    @Override
-    public int read() throws IOException {
-      advanceIfCurrentPieceFullyRead();
-      if (currentPiece == null) {
-        return -1;
-      } else {
-        return currentPiece.byteAt(currentPieceIndex++) & 0xFF;
-      }
-    }
-
-    @Override
-    public int available() throws IOException {
-      int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
-      return RopeByteString.this.size() - bytesRead;
-    }
-
-    @Override
-    public boolean markSupported() {
-      return true;
-    }
-
-    @Override
-    public void mark(int readAheadLimit) {
-      // Set the mark to our position in the byte string
-      mark = currentPieceOffsetInRope + currentPieceIndex;
-    }
-
-    @Override
-    public synchronized void reset() {
-      // Just reinitialize and skip the specified number of bytes.
-      initialize();
-      readSkipInternal(null, 0, mark);
-    }
-
-    /** Common initialization code used by both the constructor and reset() */
-    private void initialize() {
-      pieceIterator = new PieceIterator(RopeByteString.this);
-      currentPiece = pieceIterator.next();
-      currentPieceSize = currentPiece.size();
-      currentPieceIndex = 0;
-      currentPieceOffsetInRope = 0;
-    }
-
-    /**
-     * Skips to the next piece if we have read all the data in the current
-     * piece.  Sets currentPiece to null if we have reached the end of the
-     * input.
-     */
-    private void advanceIfCurrentPieceFullyRead() {
-      if (currentPiece != null && currentPieceIndex == currentPieceSize) {
-        // Generally, we can only go through this loop at most once, since
-        // empty strings can't end up in a rope.  But better to test.
-        currentPieceOffsetInRope += currentPieceSize;
-        currentPieceIndex = 0;
-        if (pieceIterator.hasNext()) {
-          currentPiece = pieceIterator.next();
-          currentPieceSize = currentPiece.size();
-        } else {
-          currentPiece = null;
-          currentPieceSize = 0;
-        }
-      }
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/src/main/java/com/google/protobuf/RpcUtil.java
deleted file mode 100644
index 694b8d1..0000000
--- a/java/src/main/java/com/google/protobuf/RpcUtil.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * Grab-bag of utility functions useful when dealing with RPCs.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class RpcUtil {
-  private RpcUtil() {}
-
-  /**
-   * Take an {@code RpcCallback<Message>} and convert it to an
-   * {@code RpcCallback} accepting a specific message type.  This is always
-   * type-safe (parameter type contravariance).
-   */
-  @SuppressWarnings("unchecked")
-  public static <Type extends Message> RpcCallback<Type>
-  specializeCallback(final RpcCallback<Message> originalCallback) {
-    return (RpcCallback<Type>)originalCallback;
-    // The above cast works, but only due to technical details of the Java
-    // implementation.  A more theoretically correct -- but less efficient --
-    // implementation would be as follows:
-    //   return new RpcCallback<Type>() {
-    //     public void run(Type parameter) {
-    //       originalCallback.run(parameter);
-    //     }
-    //   };
-  }
-
-  /**
-   * Take an {@code RpcCallback} accepting a specific message type and convert
-   * it to an {@code RpcCallback<Message>}.  The generalized callback will
-   * accept any message object which has the same descriptor, and will convert
-   * it to the correct class before calling the original callback.  However,
-   * if the generalized callback is given a message with a different descriptor,
-   * an exception will be thrown.
-   */
-  public static <Type extends Message>
-  RpcCallback<Message> generalizeCallback(
-      final RpcCallback<Type> originalCallback,
-      final Class<Type> originalClass,
-      final Type defaultInstance) {
-    return new RpcCallback<Message>() {
-      public void run(final Message parameter) {
-        Type typedParameter;
-        try {
-          typedParameter = originalClass.cast(parameter);
-        } catch (ClassCastException ignored) {
-          typedParameter = copyAsType(defaultInstance, parameter);
-        }
-        originalCallback.run(typedParameter);
-      }
-    };
-  }
-
-  /**
-   * Creates a new message of type "Type" which is a copy of "source".  "source"
-   * must have the same descriptor but may be a different class (e.g.
-   * DynamicMessage).
-   */
-  @SuppressWarnings("unchecked")
-  private static <Type extends Message> Type copyAsType(
-      final Type typeDefaultInstance, final Message source) {
-    return (Type) typeDefaultInstance
-        .newBuilderForType().mergeFrom(source).build();
-  }
-
-  /**
-   * Creates a callback which can only be called once.  This may be useful for
-   * security, when passing a callback to untrusted code:  most callbacks do
-   * not expect to be called more than once, so doing so may expose bugs if it
-   * is not prevented.
-   */
-  public static <ParameterType>
-    RpcCallback<ParameterType> newOneTimeCallback(
-      final RpcCallback<ParameterType> originalCallback) {
-    return new RpcCallback<ParameterType>() {
-      private boolean alreadyCalled = false;
-
-      public void run(final ParameterType parameter) {
-        synchronized(this) {
-          if (alreadyCalled) {
-            throw new AlreadyCalledException();
-          }
-          alreadyCalled = true;
-        }
-
-        originalCallback.run(parameter);
-      }
-    };
-  }
-
-  /**
-   * Exception thrown when a one-time callback is called more than once.
-   */
-  public static final class AlreadyCalledException extends RuntimeException {
-    private static final long serialVersionUID = 5469741279507848266L;
-
-    public AlreadyCalledException() {
-      super("This RpcCallback was already called and cannot be called " +
-            "multiple times.");
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
deleted file mode 100644
index 13a36d4..0000000
--- a/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
+++ /dev/null
@@ -1,241 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * {@code SingleFieldBuilder} implements a structure that a protocol
- * message uses to hold a single field of another protocol message. It supports
- * the classical use case of setting an immutable {@link Message} as the value
- * of the field and is highly optimized around this.
- * <br>
- * It also supports the additional use case of setting a {@link Message.Builder}
- * as the field and deferring conversion of that {@code Builder}
- * to an immutable {@code Message}. In this way, it's possible to maintain
- * a tree of {@code Builder}'s that acts as a fully read/write data
- * structure.
- * <br>
- * Logically, one can think of a tree of builders as converting the entire tree
- * to messages when build is called on the root or when any method is called
- * that desires a Message instead of a Builder. In terms of the implementation,
- * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
- * classes cache messages that were created so that messages only need to be
- * created when some change occured in its builder or a builder for one of its
- * descendants.
- *
- * @param <MType> the type of message for the field
- * @param <BType> the type of builder for the field
- * @param <IType> the common interface for the message and the builder
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class SingleFieldBuilder
-    <MType extends GeneratedMessage,
-     BType extends GeneratedMessage.Builder,
-     IType extends MessageOrBuilder>
-    implements GeneratedMessage.BuilderParent {
-
-  // Parent to send changes to.
-  private GeneratedMessage.BuilderParent parent;
-
-  // Invariant: one of builder or message fields must be non-null.
-
-  // If set, this is the case where we are backed by a builder. In this case,
-  // message field represents a cached message for the builder (or null if
-  // there is no cached message).
-  private BType builder;
-
-  // If builder is non-null, this represents a cached message from the builder.
-  // If builder is null, this is the authoritative message for the field.
-  private MType message;
-
-  // Indicates that we've built a message and so we are now obligated
-  // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
-  private boolean isClean;
-
-  public SingleFieldBuilder(
-      MType message,
-      GeneratedMessage.BuilderParent parent,
-      boolean isClean) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    this.message = message;
-    this.parent = parent;
-    this.isClean = isClean;
-  }
-
-  public void dispose() {
-    // Null out parent so we stop sending it invalidations.
-    parent = null;
-  }
-
-  /**
-   * Get the message for the field. If the message is currently stored
-   * as a {@code Builder}, it is converted to a {@code Message} by
-   * calling {@link Message.Builder#buildPartial} on it. If no message has
-   * been set, returns the default instance of the message.
-   *
-   * @return the message for the field
-   */
-  @SuppressWarnings("unchecked")
-  public MType getMessage() {
-    if (message == null) {
-      // If message is null, the invariant is that we must be have a builder.
-      message = (MType) builder.buildPartial();
-    }
-    return message;
-  }
-
-  /**
-   * Builds the message and returns it.
-   *
-   * @return the message
-   */
-  public MType build() {
-    // Now that build has been called, we are required to dispatch
-    // invalidations.
-    isClean = true;
-    return getMessage();
-  }
-
-  /**
-   * Gets a builder for the field. If no builder has been created yet, a
-   * builder is created on demand by calling {@link Message#toBuilder}.
-   *
-   * @return The builder for the field
-   */
-  @SuppressWarnings("unchecked")
-  public BType getBuilder() {
-    if (builder == null) {
-      // builder.mergeFrom() on a fresh builder
-      // does not create any sub-objects with independent clean/dirty states,
-      // therefore setting the builder itself to clean without actually calling
-      // build() cannot break any invariants.
-      builder = (BType) message.newBuilderForType(this);
-      builder.mergeFrom(message); // no-op if message is the default message
-      builder.markClean();
-    }
-    return builder;
-  }
-
-  /**
-   * Gets the base class interface for the field. This may either be a builder
-   * or a message. It will return whatever is more efficient.
-   *
-   * @return the message or builder for the field as the base class interface
-   */
-  @SuppressWarnings("unchecked")
-  public IType getMessageOrBuilder() {
-    if (builder != null) {
-      return  (IType) builder;
-    } else {
-      return (IType) message;
-    }
-  }
-
-  /**
-   * Sets a  message for the field replacing any existing value.
-   *
-   * @param message the message to set
-   * @return the builder
-   */
-  public SingleFieldBuilder<MType, BType, IType> setMessage(
-      MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    this.message = message;
-    if (builder != null) {
-      builder.dispose();
-      builder = null;
-    }
-    onChanged();
-    return this;
-  }
-
-  /**
-   * Merges the field from another field.
-   *
-   * @param value the value to merge from
-   * @return the builder
-   */
-  public SingleFieldBuilder<MType, BType, IType> mergeFrom(
-      MType value) {
-    if (builder == null && message == message.getDefaultInstanceForType()) {
-      message = value;
-    } else {
-      getBuilder().mergeFrom(value);
-    }
-    onChanged();
-    return this;
-  }
-
-  /**
-   * Clears the value of the field.
-   *
-   * @return the builder
-   */
-  @SuppressWarnings("unchecked")
-  public SingleFieldBuilder<MType, BType, IType> clear() {
-    message = (MType) (message != null ?
-        message.getDefaultInstanceForType() :
-        builder.getDefaultInstanceForType());
-    if (builder != null) {
-      builder.dispose();
-      builder = null;
-    }
-    onChanged();
-    return this;
-  }
-
-  /**
-   * Called when a the builder or one of its nested children has changed
-   * and any parent should be notified of its invalidation.
-   */
-  private void onChanged() {
-    // If builder is null, this is the case where onChanged is being called
-    // from setMessage or clear.
-    if (builder != null) {
-      message = null;
-    }
-    if (isClean && parent != null) {
-      parent.markDirty();
-
-      // Don't keep dispatching invalidations until build is called again.
-      isClean = false;
-    }
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void markDirty() {
-    onChanged();
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/src/main/java/com/google/protobuf/SmallSortedMap.java
deleted file mode 100644
index 0674d2e..0000000
--- a/java/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ /dev/null
@@ -1,618 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.TreeMap;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.SortedMap;
-
-/**
- * A custom map implementation from FieldDescriptor to Object optimized to
- * minimize the number of memory allocations for instances with a small number
- * of mappings. The implementation stores the first {@code k} mappings in an
- * array for a configurable value of {@code k}, allowing direct access to the
- * corresponding {@code Entry}s without the need to create an Iterator. The
- * remaining entries are stored in an overflow map. Iteration over the entries
- * in the map should be done as follows:
- *
- * <pre>   {@code
- * for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
- *   process(fieldMap.getArrayEntryAt(i));
- * }
- * for (Map.Entry<K, V> entry : fieldMap.getOverflowEntries()) {
- *   process(entry);
- * }
- * }</pre>
- *
- * The resulting iteration is in order of ascending field tag number. The
- * object returned by {@link #entrySet()} adheres to the same contract but is
- * less efficient as it necessarily involves creating an object for iteration.
- * <p>
- * The tradeoff for this memory efficiency is that the worst case running time
- * of the {@code put()} operation is {@code O(k + lg n)}, which happens when
- * entries are added in descending order. {@code k} should be chosen such that
- * it covers enough common cases without adversely affecting larger maps. In
- * practice, the worst case scenario does not happen for extensions because
- * extension fields are serialized and deserialized in order of ascending tag
- * number, but the worst case scenario can happen for DynamicMessages.
- * <p>
- * The running time for all other operations is similar to that of
- * {@code TreeMap}.
- * <p>
- * Instances are not thread-safe until {@link #makeImmutable()} is called,
- * after which any modifying operation will result in an
- * {@link UnsupportedOperationException}.
- *
- * @author darick@google.com Darick Tong
- */
-// This class is final for all intents and purposes because the constructor is
-// private. However, the FieldDescriptor-specific logic is encapsulated in
-// a subclass to aid testability of the core logic.
-class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
-
-  /**
-   * Creates a new instance for mapping FieldDescriptors to their values.
-   * The {@link #makeImmutable()} implementation will convert the List values
-   * of any repeated fields to unmodifiable lists.
-   *
-   * @param arraySize The size of the entry array containing the
-   *        lexicographically smallest mappings.
-   */
-  static <FieldDescriptorType extends
-      FieldSet.FieldDescriptorLite<FieldDescriptorType>>
-      SmallSortedMap<FieldDescriptorType, Object> newFieldMap(int arraySize) {
-    return new SmallSortedMap<FieldDescriptorType, Object>(arraySize) {
-      @Override
-      @SuppressWarnings("unchecked")
-      public void makeImmutable() {
-        if (!isImmutable()) {
-          for (int i = 0; i < getNumArrayEntries(); i++) {
-            final Map.Entry<FieldDescriptorType, Object> entry =
-                getArrayEntryAt(i);
-            if (entry.getKey().isRepeated()) {
-              final List value = (List) entry.getValue();
-              entry.setValue(Collections.unmodifiableList(value));
-            }
-          }
-          for (Map.Entry<FieldDescriptorType, Object> entry :
-                   getOverflowEntries()) {
-            if (entry.getKey().isRepeated()) {
-              final List value = (List) entry.getValue();
-              entry.setValue(Collections.unmodifiableList(value));
-            }
-          }
-        }
-        super.makeImmutable();
-      }
-    };
-  }
-
-  /**
-   * Creates a new instance for testing.
-   *
-   * @param arraySize The size of the entry array containing the
-   *        lexicographically smallest mappings.
-   */
-  static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest(
-      int arraySize) {
-    return new SmallSortedMap<K, V>(arraySize);
-  }
-
-  private final int maxArraySize;
-  // The "entry array" is actually a List because generic arrays are not
-  // allowed. ArrayList also nicely handles the entry shifting on inserts and
-  // removes.
-  private List<Entry> entryList;
-  private Map<K, V> overflowEntries;
-  private boolean isImmutable;
-  // The EntrySet is a stateless view of the Map. It's initialized the first
-  // time it is requested and reused henceforth.
-  private volatile EntrySet lazyEntrySet;
-
-  /**
-   * @code arraySize Size of the array in which the lexicographically smallest
-   *       mappings are stored. (i.e. the {@code k} referred to in the class
-   *       documentation).
-   */
-  private SmallSortedMap(int arraySize) {
-    this.maxArraySize = arraySize;
-    this.entryList = Collections.emptyList();
-    this.overflowEntries = Collections.emptyMap();
-  }
-
-  /** Make this map immutable from this point forward. */
-  public void makeImmutable() {
-    if (!isImmutable) {
-      // Note: There's no need to wrap the entryList in an unmodifiableList
-      // because none of the list's accessors are exposed. The iterator() of
-      // overflowEntries, on the other hand, is exposed so it must be made
-      // unmodifiable.
-      overflowEntries = overflowEntries.isEmpty() ?
-          Collections.<K, V>emptyMap() :
-          Collections.unmodifiableMap(overflowEntries);
-      isImmutable = true;
-    }
-  }
-
-  /** @return Whether {@link #makeImmutable()} has been called. */
-  public boolean isImmutable() {
-    return isImmutable;
-  }
-
-  /** @return The number of entries in the entry array. */
-  public int getNumArrayEntries() {
-    return entryList.size();
-  }
-
-  /** @return The array entry at the given {@code index}. */
-  public Map.Entry<K, V> getArrayEntryAt(int index) {
-    return entryList.get(index);
-  }
-
-  /** @return There number of overflow entries. */
-  public int getNumOverflowEntries() {
-    return overflowEntries.size();
-  }
-
-  /** @return An iterable over the overflow entries. */
-  public Iterable<Map.Entry<K, V>> getOverflowEntries() {
-    return overflowEntries.isEmpty() ?
-        EmptySet.<Map.Entry<K, V>>iterable() :
-        overflowEntries.entrySet();
-  }
-
-  @Override
-  public int size() {
-    return entryList.size() + overflowEntries.size();
-  }
-
-  /**
-   * The implementation throws a {@code ClassCastException} if o is not an
-   * object of type {@code K}.
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean containsKey(Object o) {
-    @SuppressWarnings("unchecked")
-    final K key = (K) o;
-    return binarySearchInArray(key) >= 0 || overflowEntries.containsKey(key);
-  }
-
-  /**
-   * The implementation throws a {@code ClassCastException} if o is not an
-   * object of type {@code K}.
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public V get(Object o) {
-    @SuppressWarnings("unchecked")
-    final K key = (K) o;
-    final int index = binarySearchInArray(key);
-    if (index >= 0) {
-      return entryList.get(index).getValue();
-    }
-    return overflowEntries.get(key);
-  }
-
-  @Override
-  public V put(K key, V value) {
-    checkMutable();
-    final int index = binarySearchInArray(key);
-    if (index >= 0) {
-      // Replace existing array entry.
-      return entryList.get(index).setValue(value);
-    }
-    ensureEntryArrayMutable();
-    final int insertionPoint = -(index + 1);
-    if (insertionPoint >= maxArraySize) {
-      // Put directly in overflow.
-      return getOverflowEntriesMutable().put(key, value);
-    }
-    // Insert new Entry in array.
-    if (entryList.size() == maxArraySize) {
-      // Shift the last array entry into overflow.
-      final Entry lastEntryInArray = entryList.remove(maxArraySize - 1);
-      getOverflowEntriesMutable().put(lastEntryInArray.getKey(),
-                                      lastEntryInArray.getValue());
-    }
-    entryList.add(insertionPoint, new Entry(key, value));
-    return null;
-  }
-
-  @Override
-  public void clear() {
-    checkMutable();
-    if (!entryList.isEmpty()) {
-      entryList.clear();
-    }
-    if (!overflowEntries.isEmpty()) {
-      overflowEntries.clear();
-    }
-  }
-
-  /**
-   * The implementation throws a {@code ClassCastException} if o is not an
-   * object of type {@code K}.
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public V remove(Object o) {
-    checkMutable();
-    @SuppressWarnings("unchecked")
-    final K key = (K) o;
-    final int index = binarySearchInArray(key);
-    if (index >= 0) {
-      return removeArrayEntryAt(index);
-    }
-    // overflowEntries might be Collections.unmodifiableMap(), so only
-    // call remove() if it is non-empty.
-    if (overflowEntries.isEmpty()) {
-      return null;
-    } else {
-      return overflowEntries.remove(key);
-    }
-  }
-
-  private V removeArrayEntryAt(int index) {
-    checkMutable();
-    final V removed = entryList.remove(index).getValue();
-    if (!overflowEntries.isEmpty()) {
-      // Shift the first entry in the overflow to be the last entry in the
-      // array.
-      final Iterator<Map.Entry<K, V>> iterator =
-          getOverflowEntriesMutable().entrySet().iterator();
-      entryList.add(new Entry(iterator.next()));
-      iterator.remove();
-    }
-    return removed;
-  }
-
-  /**
-   * @param key The key to find in the entry array.
-   * @return The returned integer position follows the same semantics as the
-   *     value returned by {@link java.util.Arrays#binarySearch()}.
-   */
-  private int binarySearchInArray(K key) {
-    int left = 0;
-    int right = entryList.size() - 1;
-
-    // Optimization: For the common case in which entries are added in
-    // ascending tag order, check the largest element in the array before
-    // doing a full binary search.
-    if (right >= 0) {
-      int cmp = key.compareTo(entryList.get(right).getKey());
-      if (cmp > 0) {
-        return -(right + 2);  // Insert point is after "right".
-      } else if (cmp == 0) {
-        return right;
-      }
-    }
-
-    while (left <= right) {
-      int mid = (left + right) / 2;
-      int cmp = key.compareTo(entryList.get(mid).getKey());
-      if (cmp < 0) {
-        right = mid - 1;
-      } else if (cmp > 0) {
-        left = mid + 1;
-      } else {
-        return mid;
-      }
-    }
-    return -(left + 1);
-  }
-
-  /**
-   * Similar to the AbstractMap implementation of {@code keySet()} and
-   * {@code values()}, the entry set is created the first time this method is
-   * called, and returned in response to all subsequent calls.
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public Set<Map.Entry<K, V>> entrySet() {
-    if (lazyEntrySet == null) {
-      lazyEntrySet = new EntrySet();
-    }
-    return lazyEntrySet;
-  }
-
-  /**
-   * @throws UnsupportedOperationException if {@link #makeImmutable()} has
-   *         has been called.
-   */
-  private void checkMutable() {
-    if (isImmutable) {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  /**
-   * @return a {@link SortedMap} to which overflow entries mappings can be
-   *         added or removed.
-   * @throws UnsupportedOperationException if {@link #makeImmutable()} has been
-   *         called.
-   */
-  @SuppressWarnings("unchecked")
-  private SortedMap<K, V> getOverflowEntriesMutable() {
-    checkMutable();
-    if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) {
-      overflowEntries = new TreeMap<K, V>();
-    }
-    return (SortedMap<K, V>) overflowEntries;
-  }
-
-  /**
-   * Lazily creates the entry list. Any code that adds to the list must first
-   * call this method.
-   */
-  private void ensureEntryArrayMutable() {
-    checkMutable();
-    if (entryList.isEmpty() && !(entryList instanceof ArrayList)) {
-      entryList = new ArrayList<Entry>(maxArraySize);
-    }
-  }
-
-  /**
-   * Entry implementation that implements Comparable in order to support
-   * binary search within the entry array. Also checks mutability in
-   * {@link #setValue()}.
-   */
-  private class Entry implements Map.Entry<K, V>, Comparable<Entry> {
-
-    private final K key;
-    private V value;
-
-    Entry(Map.Entry<K, V> copy) {
-      this(copy.getKey(), copy.getValue());
-    }
-
-    Entry(K key, V value) {
-      this.key = key;
-      this.value = value;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public K getKey() {
-      return key;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public V getValue() {
-      return value;
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public int compareTo(Entry other) {
-      return getKey().compareTo(other.getKey());
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public V setValue(V newValue) {
-      checkMutable();
-      final V oldValue = this.value;
-      this.value = newValue;
-      return oldValue;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (!(o instanceof Map.Entry)) {
-        return false;
-      }
-      @SuppressWarnings("unchecked")
-      Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
-      return equals(key, other.getKey()) && equals(value, other.getValue());
-    }
-
-    @Override
-    public int hashCode() {
-      return (key == null ? 0 : key.hashCode()) ^
-          (value == null ? 0 : value.hashCode());
-    }
-
-    @Override
-    public String toString() {
-      return key + "=" + value;
-    }
-
-    /** equals() that handles null values. */
-    private boolean equals(Object o1, Object o2) {
-      return o1 == null ? o2 == null : o1.equals(o2);
-    }
-  }
-
-  /**
-   * Stateless view of the entries in the field map.
-   */
-  private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
-
-    @Override
-    public Iterator<Map.Entry<K, V>> iterator() {
-      return new EntryIterator();
-    }
-
-    @Override
-    public int size() {
-      return SmallSortedMap.this.size();
-    }
-
-    /**
-     * Throws a {@link ClassCastException} if o is not of the expected type.
-     *
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean contains(Object o) {
-      @SuppressWarnings("unchecked")
-      final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
-      final V existing = get(entry.getKey());
-      final V value = entry.getValue();
-      return existing == value ||
-          (existing != null && existing.equals(value));
-    }
-
-    @Override
-    public boolean add(Map.Entry<K, V> entry) {
-      if (!contains(entry)) {
-        put(entry.getKey(), entry.getValue());
-        return true;
-      }
-      return false;
-    }
-
-    /**
-     * Throws a {@link ClassCastException} if o is not of the expected type.
-     *
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean remove(Object o) {
-      @SuppressWarnings("unchecked")
-      final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
-      if (contains(entry)) {
-        SmallSortedMap.this.remove(entry.getKey());
-        return true;
-      }
-      return false;
-    }
-
-    @Override
-    public void clear() {
-      SmallSortedMap.this.clear();
-    }
-  }
-
-  /**
-   * Iterator implementation that switches from the entry array to the overflow
-   * entries appropriately.
-   */
-  private class EntryIterator implements Iterator<Map.Entry<K, V>> {
-
-    private int pos = -1;
-    private boolean nextCalledBeforeRemove;
-    private Iterator<Map.Entry<K, V>> lazyOverflowIterator;
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public boolean hasNext() {
-      return (pos + 1) < entryList.size() ||
-          getOverflowIterator().hasNext();
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public Map.Entry<K, V> next() {
-      nextCalledBeforeRemove = true;
-      // Always increment pos so that we know whether the last returned value
-      // was from the array or from overflow.
-      if (++pos < entryList.size()) {
-        return entryList.get(pos);
-      }
-      return getOverflowIterator().next();
-    }
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public void remove() {
-      if (!nextCalledBeforeRemove) {
-        throw new IllegalStateException("remove() was called before next()");
-      }
-      nextCalledBeforeRemove = false;
-      checkMutable();
-
-      if (pos < entryList.size()) {
-        removeArrayEntryAt(pos--);
-      } else {
-        getOverflowIterator().remove();
-      }
-    }
-
-    /**
-     * It is important to create the overflow iterator only after the array
-     * entries have been iterated over because the overflow entry set changes
-     * when the client calls remove() on the array entries, which invalidates
-     * any existing iterators.
-     */
-    private Iterator<Map.Entry<K, V>> getOverflowIterator() {
-      if (lazyOverflowIterator == null) {
-        lazyOverflowIterator = overflowEntries.entrySet().iterator();
-      }
-      return lazyOverflowIterator;
-    }
-  }
-
-  /**
-   * Helper class that holds immutable instances of an Iterable/Iterator that
-   * we return when the overflow entries is empty. This eliminates the creation
-   * of an Iterator object when there is nothing to iterate over.
-   */
-  private static class EmptySet {
-
-    private static final Iterator<Object> ITERATOR = new Iterator<Object>() {
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public boolean hasNext() {
-        return false;
-      }
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public Object next() {
-        throw new NoSuchElementException();
-      }
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-    };
-
-    private static final Iterable<Object> ITERABLE = new Iterable<Object>() {
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public Iterator<Object> iterator() {
-        return ITERATOR;
-      }
-    };
-
-    @SuppressWarnings("unchecked")
-    static <T> Iterable<T> iterable() {
-      return (Iterable<T>) ITERABLE;
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
deleted file mode 100644
index 57d0ca6..0000000
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ /dev/null
@@ -1,1984 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.EnumDescriptor;
-import com.google.protobuf.Descriptors.EnumValueDescriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.CharBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Provide text parsing and formatting support for proto2 instances.
- * The implementation largely follows google/protobuf/text_format.cc.
- *
- * @author wenboz@google.com Wenbo Zhu
- * @author kenton@google.com Kenton Varda
- */
-public final class TextFormat {
-  private TextFormat() {}
-
-  private static final Logger logger =
-      Logger.getLogger(TextFormat.class.getName());
-
-  private static final Printer DEFAULT_PRINTER = new Printer();
-  private static final Printer SINGLE_LINE_PRINTER =
-      (new Printer()).setSingleLineMode(true);
-  private static final Printer UNICODE_PRINTER =
-      (new Printer()).setEscapeNonAscii(false);
-
-  /**
-   * Outputs a textual representation of the Protocol Message supplied into
-   * the parameter output. (This representation is the new version of the
-   * classic "ProtocolPrinter" output from the original Protocol Buffer system)
-   */
-  public static void print(
-      final MessageOrBuilder message, final Appendable output)
-      throws IOException {
-    DEFAULT_PRINTER.print(message, new TextGenerator(output));
-  }
-
-  /** Outputs a textual representation of {@code fields} to {@code output}. */
-  public static void print(final UnknownFieldSet fields,
-                           final Appendable output)
-                           throws IOException {
-    DEFAULT_PRINTER.printUnknownFields(fields, new TextGenerator(output));
-  }
-
-  /**
-   * Same as {@code print()}, except that non-ASCII characters are not
-   * escaped.
-   */
-  public static void printUnicode(
-      final MessageOrBuilder message, final Appendable output)
-      throws IOException {
-    UNICODE_PRINTER.print(message, new TextGenerator(output));
-  }
-
-  /**
-   * Same as {@code print()}, except that non-ASCII characters are not
-   * escaped.
-   */
-  public static void printUnicode(final UnknownFieldSet fields,
-                                  final Appendable output)
-                                  throws IOException {
-    UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
-  }
-
-  /**
-   * Generates a human readable form of this message, useful for debugging and
-   * other purposes, with no newline characters.
-   */
-  public static String shortDebugString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder sb = new StringBuilder();
-      SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb));
-      // Single line mode currently might have an extra space at the end.
-      return sb.toString().trim();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Generates a human readable form of the unknown fields, useful for debugging
-   * and other purposes, with no newline characters.
-   */
-  public static String shortDebugString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder sb = new StringBuilder();
-      SINGLE_LINE_PRINTER.printUnknownFields(fields, new TextGenerator(sb));
-      // Single line mode currently might have an extra space at the end.
-      return sb.toString().trim();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Like {@code print()}, but writes directly to a {@code String} and
-   * returns it.
-   */
-  public static String printToString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      print(message, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Like {@code print()}, but writes directly to a {@code String} and
-   * returns it.
-   */
-  public static String printToString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      print(fields, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Same as {@code printToString()}, except that non-ASCII characters
-   * in string type fields are not escaped in backslash+octals.
-   */
-  public static String printToUnicodeString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      UNICODE_PRINTER.print(message, new TextGenerator(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Same as {@code printToString()}, except that non-ASCII characters
-   * in string type fields are not escaped in backslash+octals.
-   */
-  public static String printToUnicodeString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  public static void printField(final FieldDescriptor field,
-                                final Object value,
-                                final Appendable output)
-                                throws IOException {
-    DEFAULT_PRINTER.printField(field, value, new TextGenerator(output));
-  }
-
-  public static String printFieldToString(final FieldDescriptor field,
-                                          final Object value) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      printField(field, value, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  /**
-   * Outputs a textual representation of the value of given field value.
-   *
-   * @param field the descriptor of the field
-   * @param value the value of the field
-   * @param output the output to which to append the formatted value
-   * @throws ClassCastException if the value is not appropriate for the
-   *     given field descriptor
-   * @throws IOException if there is an exception writing to the output
-   */
-  public static void printFieldValue(final FieldDescriptor field,
-                                     final Object value,
-                                     final Appendable output)
-                                     throws IOException {
-    DEFAULT_PRINTER.printFieldValue(field, value, new TextGenerator(output));
-  }
-
-  /**
-   * Outputs a textual representation of the value of an unknown field.
-   *
-   * @param tag the field's tag number
-   * @param value the value of the field
-   * @param output the output to which to append the formatted value
-   * @throws ClassCastException if the value is not appropriate for the
-   *     given field descriptor
-   * @throws IOException if there is an exception writing to the output
-   */
-  public static void printUnknownFieldValue(final int tag,
-                                            final Object value,
-                                            final Appendable output)
-                                            throws IOException {
-    printUnknownFieldValue(tag, value, new TextGenerator(output));
-  }
-
-  private static void printUnknownFieldValue(final int tag,
-                                             final Object value,
-                                             final TextGenerator generator)
-                                             throws IOException {
-    switch (WireFormat.getTagWireType(tag)) {
-      case WireFormat.WIRETYPE_VARINT:
-        generator.print(unsignedToString((Long) value));
-        break;
-      case WireFormat.WIRETYPE_FIXED32:
-        generator.print(
-            String.format((Locale) null, "0x%08x", (Integer) value));
-        break;
-      case WireFormat.WIRETYPE_FIXED64:
-        generator.print(String.format((Locale) null, "0x%016x", (Long) value));
-        break;
-      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-        generator.print("\"");
-        generator.print(escapeBytes((ByteString) value));
-        generator.print("\"");
-        break;
-      case WireFormat.WIRETYPE_START_GROUP:
-        DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator);
-        break;
-      default:
-        throw new IllegalArgumentException("Bad tag: " + tag);
-    }
-  }
-
-  /** Helper class for converting protobufs to text. */
-  private static final class Printer {
-    /** Whether to omit newlines from the output. */
-    boolean singleLineMode = false;
-
-    /** Whether to escape non ASCII characters with backslash and octal. */
-    boolean escapeNonAscii = true;
-
-    private Printer() {}
-
-    /** Setter of singleLineMode */
-    private Printer setSingleLineMode(boolean singleLineMode) {
-      this.singleLineMode = singleLineMode;
-      return this;
-    }
-
-    /** Setter of escapeNonAscii */
-    private Printer setEscapeNonAscii(boolean escapeNonAscii) {
-      this.escapeNonAscii = escapeNonAscii;
-      return this;
-    }
-
-    private void print(
-        final MessageOrBuilder message, final TextGenerator generator)
-        throws IOException {
-      for (Map.Entry<FieldDescriptor, Object> field
-          : message.getAllFields().entrySet()) {
-        printField(field.getKey(), field.getValue(), generator);
-      }
-      printUnknownFields(message.getUnknownFields(), generator);
-    }
-
-    private void printField(final FieldDescriptor field, final Object value,
-        final TextGenerator generator) throws IOException {
-      if (field.isRepeated()) {
-        // Repeated field.  Print each element.
-        for (Object element : (List<?>) value) {
-          printSingleField(field, element, generator);
-        }
-      } else {
-        printSingleField(field, value, generator);
-      }
-    }
-
-    private void printSingleField(final FieldDescriptor field,
-                                  final Object value,
-                                  final TextGenerator generator)
-                                  throws IOException {
-      if (field.isExtension()) {
-        generator.print("[");
-        // We special-case MessageSet elements for compatibility with proto1.
-        if (field.getContainingType().getOptions().getMessageSetWireFormat()
-            && (field.getType() == FieldDescriptor.Type.MESSAGE)
-            && (field.isOptional())
-            // object equality
-            && (field.getExtensionScope() == field.getMessageType())) {
-          generator.print(field.getMessageType().getFullName());
-        } else {
-          generator.print(field.getFullName());
-        }
-        generator.print("]");
-      } else {
-        if (field.getType() == FieldDescriptor.Type.GROUP) {
-          // Groups must be serialized with their original capitalization.
-          generator.print(field.getMessageType().getName());
-        } else {
-          generator.print(field.getName());
-        }
-      }
-
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (singleLineMode) {
-          generator.print(" { ");
-        } else {
-          generator.print(" {\n");
-          generator.indent();
-        }
-      } else {
-        generator.print(": ");
-      }
-
-      printFieldValue(field, value, generator);
-
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        if (singleLineMode) {
-          generator.print("} ");
-        } else {
-          generator.outdent();
-          generator.print("}\n");
-        }
-      } else {
-        if (singleLineMode) {
-          generator.print(" ");
-        } else {
-          generator.print("\n");
-        }
-      }
-    }
-
-    private void printFieldValue(final FieldDescriptor field,
-                                 final Object value,
-                                 final TextGenerator generator)
-                                 throws IOException {
-      switch (field.getType()) {
-        case INT32:
-        case SINT32:
-        case SFIXED32:
-          generator.print(((Integer) value).toString());
-          break;
-
-        case INT64:
-        case SINT64:
-        case SFIXED64:
-          generator.print(((Long) value).toString());
-          break;
-
-        case BOOL:
-          generator.print(((Boolean) value).toString());
-          break;
-
-        case FLOAT:
-          generator.print(((Float) value).toString());
-          break;
-
-        case DOUBLE:
-          generator.print(((Double) value).toString());
-          break;
-
-        case UINT32:
-        case FIXED32:
-          generator.print(unsignedToString((Integer) value));
-          break;
-
-        case UINT64:
-        case FIXED64:
-          generator.print(unsignedToString((Long) value));
-          break;
-
-        case STRING:
-          generator.print("\"");
-          generator.print(escapeNonAscii ?
-              escapeText((String) value) :
-              escapeDoubleQuotesAndBackslashes((String) value));
-          generator.print("\"");
-          break;
-
-        case BYTES:
-          generator.print("\"");
-          if (value instanceof ByteString) {
-            generator.print(escapeBytes((ByteString) value));
-          } else {
-            generator.print(escapeBytes((byte[]) value));
-          }
-          generator.print("\"");
-          break;
-
-        case ENUM:
-          generator.print(((EnumValueDescriptor) value).getName());
-          break;
-
-        case MESSAGE:
-        case GROUP:
-          print((Message) value, generator);
-          break;
-      }
-    }
-
-    private void printUnknownFields(final UnknownFieldSet unknownFields,
-                                    final TextGenerator generator)
-                                    throws IOException {
-      for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
-               unknownFields.asMap().entrySet()) {
-        final int number = entry.getKey();
-        final UnknownFieldSet.Field field = entry.getValue();
-        printUnknownField(number, WireFormat.WIRETYPE_VARINT,
-            field.getVarintList(), generator);
-        printUnknownField(number, WireFormat.WIRETYPE_FIXED32,
-            field.getFixed32List(), generator);
-        printUnknownField(number, WireFormat.WIRETYPE_FIXED64,
-            field.getFixed64List(), generator);
-        printUnknownField(number, WireFormat.WIRETYPE_LENGTH_DELIMITED,
-            field.getLengthDelimitedList(), generator);
-        for (final UnknownFieldSet value : field.getGroupList()) {
-          generator.print(entry.getKey().toString());
-          if (singleLineMode) {
-            generator.print(" { ");
-          } else {
-            generator.print(" {\n");
-            generator.indent();
-          }
-          printUnknownFields(value, generator);
-          if (singleLineMode) {
-            generator.print("} ");
-          } else {
-            generator.outdent();
-            generator.print("}\n");
-          }
-        }
-      }
-    }
-
-    private void printUnknownField(final int number,
-                                   final int wireType,
-                                   final List<?> values,
-                                   final TextGenerator generator)
-                                   throws IOException {
-      for (final Object value : values) {
-        generator.print(String.valueOf(number));
-        generator.print(": ");
-        printUnknownFieldValue(wireType, value, generator);
-        generator.print(singleLineMode ? " " : "\n");
-      }
-    }
-  }
-
-  /** Convert an unsigned 32-bit integer to a string. */
-  public static String unsignedToString(final int value) {
-    if (value >= 0) {
-      return Integer.toString(value);
-    } else {
-      return Long.toString(value & 0x00000000FFFFFFFFL);
-    }
-  }
-
-  /** Convert an unsigned 64-bit integer to a string. */
-  public static String unsignedToString(final long value) {
-    if (value >= 0) {
-      return Long.toString(value);
-    } else {
-      // Pull off the most-significant bit so that BigInteger doesn't think
-      // the number is negative, then set it again using setBit().
-      return BigInteger.valueOf(value & 0x7FFFFFFFFFFFFFFFL)
-                       .setBit(63).toString();
-    }
-  }
-
-  /**
-   * An inner class for writing text to the output stream.
-   */
-  private static final class TextGenerator {
-    private final Appendable output;
-    private final StringBuilder indent = new StringBuilder();
-    private boolean atStartOfLine = true;
-
-    private TextGenerator(final Appendable output) {
-      this.output = output;
-    }
-
-    /**
-     * Indent text by two spaces.  After calling Indent(), two spaces will be
-     * inserted at the beginning of each line of text.  Indent() may be called
-     * multiple times to produce deeper indents.
-     */
-    public void indent() {
-      indent.append("  ");
-    }
-
-    /**
-     * Reduces the current indent level by two spaces, or crashes if the indent
-     * level is zero.
-     */
-    public void outdent() {
-      final int length = indent.length();
-      if (length == 0) {
-        throw new IllegalArgumentException(
-            " Outdent() without matching Indent().");
-      }
-      indent.delete(length - 2, length);
-    }
-
-    /**
-     * Print text to the output stream.
-     */
-    public void print(final CharSequence text) throws IOException {
-      final int size = text.length();
-      int pos = 0;
-
-      for (int i = 0; i < size; i++) {
-        if (text.charAt(i) == '\n') {
-          write(text.subSequence(pos, i + 1));
-          pos = i + 1;
-          atStartOfLine = true;
-        }
-      }
-      write(text.subSequence(pos, size));
-    }
-
-    private void write(final CharSequence data) throws IOException {
-      if (data.length() == 0) {
-        return;
-      }
-      if (atStartOfLine) {
-        atStartOfLine = false;
-        output.append(indent);
-      }
-      output.append(data);
-    }
-  }
-
-  // =================================================================
-  // Parsing
-
-  /**
-   * Represents a stream of tokens parsed from a {@code String}.
-   *
-   * <p>The Java standard library provides many classes that you might think
-   * would be useful for implementing this, but aren't.  For example:
-   *
-   * <ul>
-   * <li>{@code java.io.StreamTokenizer}:  This almost does what we want -- or,
-   *   at least, something that would get us close to what we want -- except
-   *   for one fatal flaw:  It automatically un-escapes strings using Java
-   *   escape sequences, which do not include all the escape sequences we
-   *   need to support (e.g. '\x').
-   * <li>{@code java.util.Scanner}:  This seems like a great way at least to
-   *   parse regular expressions out of a stream (so we wouldn't have to load
-   *   the entire input into a single string before parsing).  Sadly,
-   *   {@code Scanner} requires that tokens be delimited with some delimiter.
-   *   Thus, although the text "foo:" should parse to two tokens ("foo" and
-   *   ":"), {@code Scanner} would recognize it only as a single token.
-   *   Furthermore, {@code Scanner} provides no way to inspect the contents
-   *   of delimiters, making it impossible to keep track of line and column
-   *   numbers.
-   * </ul>
-   *
-   * <p>Luckily, Java's regular expression support does manage to be useful to
-   * us.  (Barely:  We need {@code Matcher.usePattern()}, which is new in
-   * Java 1.5.)  So, we can use that, at least.  Unfortunately, this implies
-   * that we need to have the entire input in one contiguous string.
-   */
-  private static final class Tokenizer {
-    private final CharSequence text;
-    private final Matcher matcher;
-    private String currentToken;
-
-    // The character index within this.text at which the current token begins.
-    private int pos = 0;
-
-    // The line and column numbers of the current token.
-    private int line = 0;
-    private int column = 0;
-
-    // The line and column numbers of the previous token (allows throwing
-    // errors *after* consuming).
-    private int previousLine = 0;
-    private int previousColumn = 0;
-
-    // We use possessive quantifiers (*+ and ++) because otherwise the Java
-    // regex matcher has stack overflows on large inputs.
-    private static final Pattern WHITESPACE =
-      Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
-    private static final Pattern TOKEN = Pattern.compile(
-      "[a-zA-Z_][0-9a-zA-Z_+-]*+|" +                // an identifier
-      "[.]?[0-9+-][0-9a-zA-Z_.+-]*+|" +             // a number
-      "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" +       // a double-quoted string
-      "\'([^\'\n\\\\]|\\\\.)*+(\'|\\\\?$)",         // a single-quoted string
-      Pattern.MULTILINE);
-
-    private static final Pattern DOUBLE_INFINITY = Pattern.compile(
-      "-?inf(inity)?",
-      Pattern.CASE_INSENSITIVE);
-    private static final Pattern FLOAT_INFINITY = Pattern.compile(
-      "-?inf(inity)?f?",
-      Pattern.CASE_INSENSITIVE);
-    private static final Pattern FLOAT_NAN = Pattern.compile(
-      "nanf?",
-      Pattern.CASE_INSENSITIVE);
-
-    /** Construct a tokenizer that parses tokens from the given text. */
-    private Tokenizer(final CharSequence text) {
-      this.text = text;
-      this.matcher = WHITESPACE.matcher(text);
-      skipWhitespace();
-      nextToken();
-    }
-
-    /** Are we at the end of the input? */
-    public boolean atEnd() {
-      return currentToken.length() == 0;
-    }
-
-    /** Advance to the next token. */
-    public void nextToken() {
-      previousLine = line;
-      previousColumn = column;
-
-      // Advance the line counter to the current position.
-      while (pos < matcher.regionStart()) {
-        if (text.charAt(pos) == '\n') {
-          ++line;
-          column = 0;
-        } else {
-          ++column;
-        }
-        ++pos;
-      }
-
-      // Match the next token.
-      if (matcher.regionStart() == matcher.regionEnd()) {
-        // EOF
-        currentToken = "";
-      } else {
-        matcher.usePattern(TOKEN);
-        if (matcher.lookingAt()) {
-          currentToken = matcher.group();
-          matcher.region(matcher.end(), matcher.regionEnd());
-        } else {
-          // Take one character.
-          currentToken = String.valueOf(text.charAt(pos));
-          matcher.region(pos + 1, matcher.regionEnd());
-        }
-
-        skipWhitespace();
-      }
-    }
-
-    /**
-     * Skip over any whitespace so that the matcher region starts at the next
-     * token.
-     */
-    private void skipWhitespace() {
-      matcher.usePattern(WHITESPACE);
-      if (matcher.lookingAt()) {
-        matcher.region(matcher.end(), matcher.regionEnd());
-      }
-    }
-
-    /**
-     * If the next token exactly matches {@code token}, consume it and return
-     * {@code true}.  Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsume(final String token) {
-      if (currentToken.equals(token)) {
-        nextToken();
-        return true;
-      } else {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token exactly matches {@code token}, consume it.  Otherwise,
-     * throw a {@link ParseException}.
-     */
-    public void consume(final String token) throws ParseException {
-      if (!tryConsume(token)) {
-        throw parseException("Expected \"" + token + "\".");
-      }
-    }
-
-    /**
-     * Returns {@code true} if the next token is an integer, but does
-     * not consume it.
-     */
-    public boolean lookingAtInteger() {
-      if (currentToken.length() == 0) {
-        return false;
-      }
-
-      final char c = currentToken.charAt(0);
-      return ('0' <= c && c <= '9') ||
-             c == '-' || c == '+';
-    }
-
-    /**
-     * Returns {@code true} if the current token's text is equal to that
-     * specified.
-     */
-    public boolean lookingAt(String text) {
-      return currentToken.equals(text);
-    }
-
-    /**
-     * If the next token is an identifier, consume it and return its value.
-     * Otherwise, throw a {@link ParseException}.
-     */
-    public String consumeIdentifier() throws ParseException {
-      for (int i = 0; i < currentToken.length(); i++) {
-        final char c = currentToken.charAt(i);
-        if (('a' <= c && c <= 'z') ||
-            ('A' <= c && c <= 'Z') ||
-            ('0' <= c && c <= '9') ||
-            (c == '_') || (c == '.')) {
-          // OK
-        } else {
-          throw parseException(
-              "Expected identifier. Found '" + currentToken + "'");
-        }
-      }
-
-      final String result = currentToken;
-      nextToken();
-      return result;
-    }
-
-    /**
-     * If the next token is an identifier, consume it and return {@code true}.
-     * Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsumeIdentifier() {
-      try {
-        consumeIdentifier();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a 32-bit signed integer, consume it and return its
-     * value.  Otherwise, throw a {@link ParseException}.
-     */
-    public int consumeInt32() throws ParseException {
-      try {
-        final int result = parseInt32(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw integerParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a 32-bit unsigned integer, consume it and return its
-     * value.  Otherwise, throw a {@link ParseException}.
-     */
-    public int consumeUInt32() throws ParseException {
-      try {
-        final int result = parseUInt32(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw integerParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a 64-bit signed integer, consume it and return its
-     * value.  Otherwise, throw a {@link ParseException}.
-     */
-    public long consumeInt64() throws ParseException {
-      try {
-        final long result = parseInt64(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw integerParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a 64-bit signed integer, consume it and return
-     * {@code true}.  Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsumeInt64() {
-      try {
-        consumeInt64();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a 64-bit unsigned integer, consume it and return its
-     * value.  Otherwise, throw a {@link ParseException}.
-     */
-    public long consumeUInt64() throws ParseException {
-      try {
-        final long result = parseUInt64(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw integerParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a 64-bit unsigned integer, consume it and return
-     * {@code true}.  Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsumeUInt64() {
-      try {
-        consumeUInt64();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a double, consume it and return its value.
-     * Otherwise, throw a {@link ParseException}.
-     */
-    public double consumeDouble() throws ParseException {
-      // We need to parse infinity and nan separately because
-      // Double.parseDouble() does not accept "inf", "infinity", or "nan".
-      if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
-        final boolean negative = currentToken.startsWith("-");
-        nextToken();
-        return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-      }
-      if (currentToken.equalsIgnoreCase("nan")) {
-        nextToken();
-        return Double.NaN;
-      }
-      try {
-        final double result = Double.parseDouble(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw floatParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a double, consume it and return {@code true}.
-     * Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsumeDouble() {
-      try {
-        consumeDouble();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a float, consume it and return its value.
-     * Otherwise, throw a {@link ParseException}.
-     */
-    public float consumeFloat() throws ParseException {
-      // We need to parse infinity and nan separately because
-      // Float.parseFloat() does not accept "inf", "infinity", or "nan".
-      if (FLOAT_INFINITY.matcher(currentToken).matches()) {
-        final boolean negative = currentToken.startsWith("-");
-        nextToken();
-        return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
-      }
-      if (FLOAT_NAN.matcher(currentToken).matches()) {
-        nextToken();
-        return Float.NaN;
-      }
-      try {
-        final float result = Float.parseFloat(currentToken);
-        nextToken();
-        return result;
-      } catch (NumberFormatException e) {
-        throw floatParseException(e);
-      }
-    }
-
-    /**
-     * If the next token is a float, consume it and return {@code true}.
-     * Otherwise, return {@code false} without doing anything.
-     */
-    public boolean tryConsumeFloat() {
-      try {
-        consumeFloat();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a boolean, consume it and return its value.
-     * Otherwise, throw a {@link ParseException}.
-     */
-    public boolean consumeBoolean() throws ParseException {
-      if (currentToken.equals("true") ||
-          currentToken.equals("t") ||
-          currentToken.equals("1")) {
-        nextToken();
-        return true;
-      } else if (currentToken.equals("false") ||
-                 currentToken.equals("f") ||
-                 currentToken.equals("0")) {
-        nextToken();
-        return false;
-      } else {
-        throw parseException("Expected \"true\" or \"false\".");
-      }
-    }
-
-    /**
-     * If the next token is a string, consume it and return its (unescaped)
-     * value.  Otherwise, throw a {@link ParseException}.
-     */
-    public String consumeString() throws ParseException {
-      return consumeByteString().toStringUtf8();
-    }
-
-    /**
-     * If the next token is a string, consume it and return true.  Otherwise,
-     * return false.
-     */
-    public boolean tryConsumeString() {
-      try {
-        consumeString();
-        return true;
-      } catch (ParseException e) {
-        return false;
-      }
-    }
-
-    /**
-     * If the next token is a string, consume it, unescape it as a
-     * {@link ByteString}, and return it.  Otherwise, throw a
-     * {@link ParseException}.
-     */
-    public ByteString consumeByteString() throws ParseException {
-      List<ByteString> list = new ArrayList<ByteString>();
-      consumeByteString(list);
-      while (currentToken.startsWith("'") || currentToken.startsWith("\"")) {
-        consumeByteString(list);
-      }
-      return ByteString.copyFrom(list);
-    }
-
-    /**
-     * Like {@link #consumeByteString()} but adds each token of the string to
-     * the given list.  String literals (whether bytes or text) may come in
-     * multiple adjacent tokens which are automatically concatenated, like in
-     * C or Python.
-     */
-    private void consumeByteString(List<ByteString> list)
-        throws ParseException {
-      final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
-                                                   : '\0';
-      if (quote != '\"' && quote != '\'') {
-        throw parseException("Expected string.");
-      }
-
-      if (currentToken.length() < 2 ||
-          currentToken.charAt(currentToken.length() - 1) != quote) {
-        throw parseException("String missing ending quote.");
-      }
-
-      try {
-        final String escaped =
-            currentToken.substring(1, currentToken.length() - 1);
-        final ByteString result = unescapeBytes(escaped);
-        nextToken();
-        list.add(result);
-      } catch (InvalidEscapeSequenceException e) {
-        throw parseException(e.getMessage());
-      }
-    }
-
-    /**
-     * Returns a {@link ParseException} with the current line and column
-     * numbers in the description, suitable for throwing.
-     */
-    public ParseException parseException(final String description) {
-      // Note:  People generally prefer one-based line and column numbers.
-      return new ParseException(
-        line + 1, column + 1, description);
-    }
-
-    /**
-     * Returns a {@link ParseException} with the line and column numbers of
-     * the previous token in the description, suitable for throwing.
-     */
-    public ParseException parseExceptionPreviousToken(
-        final String description) {
-      // Note:  People generally prefer one-based line and column numbers.
-      return new ParseException(
-        previousLine + 1, previousColumn + 1, description);
-    }
-
-    /**
-     * Constructs an appropriate {@link ParseException} for the given
-     * {@code NumberFormatException} when trying to parse an integer.
-     */
-    private ParseException integerParseException(
-        final NumberFormatException e) {
-      return parseException("Couldn't parse integer: " + e.getMessage());
-    }
-
-    /**
-     * Constructs an appropriate {@link ParseException} for the given
-     * {@code NumberFormatException} when trying to parse a float or double.
-     */
-    private ParseException floatParseException(final NumberFormatException e) {
-      return parseException("Couldn't parse number: " + e.getMessage());
-    }
-  }
-
-  /** Thrown when parsing an invalid text format message. */
-  public static class ParseException extends IOException {
-    private static final long serialVersionUID = 3196188060225107702L;
-
-    private final int line;
-    private final int column;
-
-    /** Create a new instance, with -1 as the line and column numbers. */
-    public ParseException(final String message) {
-      this(-1, -1, message);
-    }
-
-    /**
-     * Create a new instance
-     *
-     * @param line the line number where the parse error occurred,
-     * using 1-offset.
-     * @param column the column number where the parser error occurred,
-     * using 1-offset.
-     */
-    public ParseException(final int line, final int column,
-        final String message) {
-      super(Integer.toString(line) + ":" + column + ": " + message);
-      this.line = line;
-      this.column = column;
-    }
-
-    /**
-     * Return the line where the parse exception occurred, or -1 when
-     * none is provided. The value is specified as 1-offset, so the first
-     * line is line 1.
-     */
-    public int getLine() {
-      return line;
-    }
-
-    /**
-     * Return the column where the parse exception occurred, or -1 when
-     * none is provided. The value is specified as 1-offset, so the first
-     * line is line 1.
-     */
-    public int getColumn() {
-      return column;
-    }
-  }
-
-  private static final Parser PARSER = Parser.newBuilder().build();
-
-  /**
-   * Return a {@link Parser} instance which can parse text-format
-   * messages. The returned instance is thread-safe.
-   */
-  public static Parser getParser() {
-    return PARSER;
-  }
-
-  /**
-   * Parse a text-format message from {@code input} and merge the contents
-   * into {@code builder}.
-   */
-  public static void merge(final Readable input,
-                           final Message.Builder builder)
-                           throws IOException {
-    PARSER.merge(input, builder);
-  }
-
-  /**
-   * Parse a text-format message from {@code input} and merge the contents
-   * into {@code builder}.
-   */
-  public static void merge(final CharSequence input,
-                           final Message.Builder builder)
-                           throws ParseException {
-    PARSER.merge(input, builder);
-  }
-
-  /**
-   * Parse a text-format message from {@code input} and merge the contents
-   * into {@code builder}.  Extensions will be recognized if they are
-   * registered in {@code extensionRegistry}.
-   */
-  public static void merge(final Readable input,
-                           final ExtensionRegistry extensionRegistry,
-                           final Message.Builder builder)
-                           throws IOException {
-    PARSER.merge(input, extensionRegistry, builder);
-  }
-
-
-  /**
-   * Parse a text-format message from {@code input} and merge the contents
-   * into {@code builder}.  Extensions will be recognized if they are
-   * registered in {@code extensionRegistry}.
-   */
-  public static void merge(final CharSequence input,
-                           final ExtensionRegistry extensionRegistry,
-                           final Message.Builder builder)
-                           throws ParseException {
-    PARSER.merge(input, extensionRegistry, builder);
-  }
-
-
-  /**
-   * Parser for text-format proto2 instances. This class is thread-safe.
-   * The implementation largely follows google/protobuf/text_format.cc.
-   *
-   * <p>Use {@link TextFormat#getParser()} to obtain the default parser, or
-   * {@link Builder} to control the parser behavior.
-   */
-  public static class Parser {
-    /**
-     * Determines if repeated values for non-repeated fields and
-     * oneofs are permitted. For example, given required/optional field "foo"
-     * and a oneof containing "baz" and "qux":
-     * <li>
-     * <ul>"foo: 1 foo: 2"
-     * <ul>"baz: 1 qux: 2"
-     * <ul>merging "foo: 2" into a proto in which foo is already set, or
-     * <ul>merging "qux: 2" into a proto in which baz is already set.
-     * </li>
-     */
-    public enum SingularOverwritePolicy {
-      /** The last value is retained. */
-      ALLOW_SINGULAR_OVERWRITES,
-      /** An error is issued. */
-      FORBID_SINGULAR_OVERWRITES
-    }
-
-    private final boolean allowUnknownFields;
-    private final SingularOverwritePolicy singularOverwritePolicy;
-
-    private Parser(boolean allowUnknownFields,
-        SingularOverwritePolicy singularOverwritePolicy) {
-      this.allowUnknownFields = allowUnknownFields;
-      this.singularOverwritePolicy = singularOverwritePolicy;
-    }
-
-    /**
-     * Returns a new instance of {@link Builder}.
-     */
-    public static Builder newBuilder() {
-      return new Builder();
-    }
-
-    /**
-     * Builder that can be used to obtain new instances of {@link Parser}.
-     */
-    public static class Builder {
-      private boolean allowUnknownFields = false;
-      private SingularOverwritePolicy singularOverwritePolicy =
-          SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
-
-      /**
-       * Sets parser behavior when a non-repeated field appears more than once.
-       */
-      public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
-        this.singularOverwritePolicy = p;
-        return this;
-      }
-
-      public Parser build() {
-        return new Parser(allowUnknownFields, singularOverwritePolicy);
-      }
-    }
-
-    /**
-     * Parse a text-format message from {@code input} and merge the contents
-     * into {@code builder}.
-     */
-    public void merge(final Readable input,
-                      final Message.Builder builder)
-                      throws IOException {
-      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
-    }
-
-    /**
-     * Parse a text-format message from {@code input} and merge the contents
-     * into {@code builder}.
-     */
-    public void merge(final CharSequence input,
-                      final Message.Builder builder)
-                      throws ParseException {
-      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
-    }
-
-    /**
-     * Parse a text-format message from {@code input} and merge the contents
-     * into {@code builder}.  Extensions will be recognized if they are
-     * registered in {@code extensionRegistry}.
-     */
-    public void merge(final Readable input,
-                      final ExtensionRegistry extensionRegistry,
-                      final Message.Builder builder)
-                      throws IOException {
-      // Read the entire input to a String then parse that.
-
-      // If StreamTokenizer were not quite so crippled, or if there were a kind
-      // of Reader that could read in chunks that match some particular regex,
-      // or if we wanted to write a custom Reader to tokenize our stream, then
-      // we would not have to read to one big String.  Alas, none of these is
-      // the case.  Oh well.
-
-      merge(toStringBuilder(input), extensionRegistry, builder);
-    }
-
-
-    private static final int BUFFER_SIZE = 4096;
-
-    // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
-    // overhead is worthwhile
-    private static StringBuilder toStringBuilder(final Readable input)
-        throws IOException {
-      final StringBuilder text = new StringBuilder();
-      final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
-      while (true) {
-        final int n = input.read(buffer);
-        if (n == -1) {
-          break;
-        }
-        buffer.flip();
-        text.append(buffer, 0, n);
-      }
-      return text;
-    }
-
-    /**
-     * Parse a text-format message from {@code input} and merge the contents
-     * into {@code builder}.  Extensions will be recognized if they are
-     * registered in {@code extensionRegistry}.
-     */
-    public void merge(final CharSequence input,
-                      final ExtensionRegistry extensionRegistry,
-                      final Message.Builder builder)
-                      throws ParseException {
-      final Tokenizer tokenizer = new Tokenizer(input);
-      MessageReflection.BuilderAdapter target =
-          new MessageReflection.BuilderAdapter(builder);
-
-      while (!tokenizer.atEnd()) {
-        mergeField(tokenizer, extensionRegistry, target);
-      }
-    }
-
-
-    /**
-     * Parse a single field from {@code tokenizer} and merge it into
-     * {@code builder}.
-     */
-    private void mergeField(final Tokenizer tokenizer,
-                            final ExtensionRegistry extensionRegistry,
-                            final MessageReflection.MergeTarget target)
-                            throws ParseException {
-      FieldDescriptor field = null;
-      final Descriptor type = target.getDescriptorForType();
-      ExtensionRegistry.ExtensionInfo extension = null;
-
-      if (tokenizer.tryConsume("[")) {
-        // An extension.
-        final StringBuilder name =
-            new StringBuilder(tokenizer.consumeIdentifier());
-        while (tokenizer.tryConsume(".")) {
-          name.append('.');
-          name.append(tokenizer.consumeIdentifier());
-        }
-
-        extension = target.findExtensionByName(
-            extensionRegistry, name.toString());
-
-        if (extension == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.parseExceptionPreviousToken(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          } else {
-            logger.warning(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          }
-        } else {
-          if (extension.descriptor.getContainingType() != type) {
-            throw tokenizer.parseExceptionPreviousToken(
-              "Extension \"" + name + "\" does not extend message type \"" +
-              type.getFullName() + "\".");
-          }
-          field = extension.descriptor;
-        }
-
-        tokenizer.consume("]");
-      } else {
-        final String name = tokenizer.consumeIdentifier();
-        field = type.findFieldByName(name);
-
-        // Group names are expected to be capitalized as they appear in the
-        // .proto file, which actually matches their type names, not their field
-        // names.
-        if (field == null) {
-          // Explicitly specify US locale so that this code does not break when
-          // executing in Turkey.
-          final String lowerName = name.toLowerCase(Locale.US);
-          field = type.findFieldByName(lowerName);
-          // If the case-insensitive match worked but the field is NOT a group,
-          if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
-            field = null;
-          }
-        }
-        // Again, special-case group names as described above.
-        if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
-            !field.getMessageType().getName().equals(name)) {
-          field = null;
-        }
-
-        if (field == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.parseExceptionPreviousToken(
-              "Message type \"" + type.getFullName() +
-              "\" has no field named \"" + name + "\".");
-          } else {
-            logger.warning(
-              "Message type \"" + type.getFullName() +
-              "\" has no field named \"" + name + "\".");
-          }
-        }
-      }
-
-      // Skips unknown fields.
-      if (field == null) {
-        // Try to guess the type of this field.
-        // If this field is not a message, there should be a ":" between the
-        // field name and the field value and also the field value should not
-        // start with "{" or "<" which indicates the begining of a message body.
-        // If there is no ":" or there is a "{" or "<" after ":", this field has
-        // to be a message or the input is ill-formed.
-        if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("{") &&
-            !tokenizer.lookingAt("<")) {
-          skipFieldValue(tokenizer);
-        } else {
-          skipFieldMessage(tokenizer);
-        }
-        return;
-      }
-
-      // Handle potential ':'.
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        tokenizer.tryConsume(":");  // optional
-      } else {
-        tokenizer.consume(":");  // required
-      }
-      // Support specifying repeated field values as a comma-separated list.
-      // Ex."foo: [1, 2, 3]"
-      if (field.isRepeated() && tokenizer.tryConsume("[")) {
-        while (true) {
-          consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
-          if (tokenizer.tryConsume("]")) {
-            // End of list.
-            break;
-          }
-          tokenizer.consume(",");
-        }
-      } else {
-        consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
-      }
-    }
-
-    /**
-     * Parse a single field value from {@code tokenizer} and merge it into
-     * {@code builder}.
-     */
-    private void consumeFieldValue(
-        final Tokenizer tokenizer,
-        final ExtensionRegistry extensionRegistry,
-        final MessageReflection.MergeTarget target,
-        final FieldDescriptor field,
-        final ExtensionRegistry.ExtensionInfo extension)
-        throws ParseException {
-      Object value = null;
-
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        final String endToken;
-        if (tokenizer.tryConsume("<")) {
-          endToken = ">";
-        } else {
-          tokenizer.consume("{");
-          endToken = "}";
-        }
-
-        final MessageReflection.MergeTarget subField;
-        subField = target.newMergeTargetForField(field,
-            (extension == null) ? null : extension.defaultInstance);
-
-        while (!tokenizer.tryConsume(endToken)) {
-          if (tokenizer.atEnd()) {
-            throw tokenizer.parseException(
-              "Expected \"" + endToken + "\".");
-          }
-          mergeField(tokenizer, extensionRegistry, subField);
-        }
-
-        value = subField.finish();
-
-      } else {
-        switch (field.getType()) {
-          case INT32:
-          case SINT32:
-          case SFIXED32:
-            value = tokenizer.consumeInt32();
-            break;
-
-          case INT64:
-          case SINT64:
-          case SFIXED64:
-            value = tokenizer.consumeInt64();
-            break;
-
-          case UINT32:
-          case FIXED32:
-            value = tokenizer.consumeUInt32();
-            break;
-
-          case UINT64:
-          case FIXED64:
-            value = tokenizer.consumeUInt64();
-            break;
-
-          case FLOAT:
-            value = tokenizer.consumeFloat();
-            break;
-
-          case DOUBLE:
-            value = tokenizer.consumeDouble();
-            break;
-
-          case BOOL:
-            value = tokenizer.consumeBoolean();
-            break;
-
-          case STRING:
-            value = tokenizer.consumeString();
-            break;
-
-          case BYTES:
-            value = tokenizer.consumeByteString();
-            break;
-
-          case ENUM:
-            final EnumDescriptor enumType = field.getEnumType();
-
-            if (tokenizer.lookingAtInteger()) {
-              final int number = tokenizer.consumeInt32();
-              value = enumType.findValueByNumber(number);
-              if (value == null) {
-                throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName() +
-                  "\" has no value with number " + number + '.');
-              }
-            } else {
-              final String id = tokenizer.consumeIdentifier();
-              value = enumType.findValueByName(id);
-              if (value == null) {
-                throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName() +
-                  "\" has no value named \"" + id + "\".");
-              }
-            }
-
-            break;
-
-          case MESSAGE:
-          case GROUP:
-            throw new RuntimeException("Can't get here.");
-        }
-      }
-
-      if (field.isRepeated()) {
-        target.addRepeatedField(field, value);
-      } else if ((singularOverwritePolicy
-              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
-          && target.hasField(field)) {
-        throw tokenizer.parseExceptionPreviousToken("Non-repeated field \""
-            + field.getFullName() + "\" cannot be overwritten.");
-      } else if ((singularOverwritePolicy
-              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
-          && field.getContainingOneof() != null
-          && target.hasOneof(field.getContainingOneof())) {
-        Descriptors.OneofDescriptor oneof = field.getContainingOneof();
-        throw tokenizer.parseExceptionPreviousToken("Field \""
-            + field.getFullName() + "\" is specified along with field \""
-            + target.getOneofFieldDescriptor(oneof).getFullName()
-            + "\", another member of oneof \"" + oneof.getName() + "\".");
-      } else {
-        target.setField(field, value);
-      }
-    }
-
-    /**
-     * Skips the next field including the field's name and value.
-     */
-    private void skipField(Tokenizer tokenizer) throws ParseException {
-      if (tokenizer.tryConsume("[")) {
-        // Extension name.
-        do {
-          tokenizer.consumeIdentifier();
-        } while (tokenizer.tryConsume("."));
-        tokenizer.consume("]");
-      } else {
-        tokenizer.consumeIdentifier();
-      }
-
-      // Try to guess the type of this field.
-      // If this field is not a message, there should be a ":" between the
-      // field name and the field value and also the field value should not
-      // start with "{" or "<" which indicates the begining of a message body.
-      // If there is no ":" or there is a "{" or "<" after ":", this field has
-      // to be a message or the input is ill-formed.
-      if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("<") &&
-          !tokenizer.lookingAt("{")) {
-        skipFieldValue(tokenizer);
-      } else {
-        skipFieldMessage(tokenizer);
-      }
-      // For historical reasons, fields may optionally be separated by commas or
-      // semicolons.
-      if (!tokenizer.tryConsume(";")) {
-        tokenizer.tryConsume(",");
-      }
-    }
-
-    /**
-     * Skips the whole body of a message including the beginning delimeter and
-     * the ending delimeter.
-     */
-    private void skipFieldMessage(Tokenizer tokenizer) throws ParseException {
-      final String delimiter;
-      if (tokenizer.tryConsume("<")) {
-        delimiter = ">";
-      } else {
-        tokenizer.consume("{");
-        delimiter = "}";
-      }
-      while (!tokenizer.lookingAt(">") && !tokenizer.lookingAt("}")) {
-        skipField(tokenizer);
-      }
-      tokenizer.consume(delimiter);
-    }
-
-    /**
-     * Skips a field value.
-     */
-    private void skipFieldValue(Tokenizer tokenizer) throws ParseException {
-      if (tokenizer.tryConsumeString()) {
-        while (tokenizer.tryConsumeString()) {}
-        return;
-      }
-      if (!tokenizer.tryConsumeIdentifier() &&  // includes enum & boolean
-          !tokenizer.tryConsumeInt64() &&       // includes int32
-          !tokenizer.tryConsumeUInt64() &&      // includes uint32
-          !tokenizer.tryConsumeDouble() &&
-          !tokenizer.tryConsumeFloat()) {
-        throw tokenizer.parseException(
-            "Invalid field value: " + tokenizer.currentToken);
-      }
-    }
-  }
-
-  // =================================================================
-  // Utility functions
-  //
-  // Some of these methods are package-private because Descriptors.java uses
-  // them.
-
-  private interface ByteSequence {
-    int size();
-    byte byteAt(int offset);
-  }
-
-  /**
-   * Escapes bytes in the format used in protocol buffer text format, which
-   * is the same as the format used for C string literals.  All bytes
-   * that are not printable 7-bit ASCII characters are escaped, as well as
-   * backslash, single-quote, and double-quote characters.  Characters for
-   * which no defined short-hand escape sequence is defined will be escaped
-   * using 3-digit octal sequences.
-   */
-  private static String escapeBytes(final ByteSequence input) {
-    final StringBuilder builder = new StringBuilder(input.size());
-    for (int i = 0; i < input.size(); i++) {
-      final byte b = input.byteAt(i);
-      switch (b) {
-        // Java does not recognize \a or \v, apparently.
-        case 0x07: builder.append("\\a" ); break;
-        case '\b': builder.append("\\b" ); break;
-        case '\f': builder.append("\\f" ); break;
-        case '\n': builder.append("\\n" ); break;
-        case '\r': builder.append("\\r" ); break;
-        case '\t': builder.append("\\t" ); break;
-        case 0x0b: builder.append("\\v" ); break;
-        case '\\': builder.append("\\\\"); break;
-        case '\'': builder.append("\\\'"); break;
-        case '"' : builder.append("\\\""); break;
-        default:
-          // Note:  Bytes with the high-order bit set should be escaped.  Since
-          //   bytes are signed, such bytes will compare less than 0x20, hence
-          //   the following line is correct.
-          if (b >= 0x20) {
-            builder.append((char) b);
-          } else {
-            builder.append('\\');
-            builder.append((char) ('0' + ((b >>> 6) & 3)));
-            builder.append((char) ('0' + ((b >>> 3) & 7)));
-            builder.append((char) ('0' + (b & 7)));
-          }
-          break;
-      }
-    }
-    return builder.toString();
-  }
-
-  /**
-   * Escapes bytes in the format used in protocol buffer text format, which
-   * is the same as the format used for C string literals.  All bytes
-   * that are not printable 7-bit ASCII characters are escaped, as well as
-   * backslash, single-quote, and double-quote characters.  Characters for
-   * which no defined short-hand escape sequence is defined will be escaped
-   * using 3-digit octal sequences.
-   */
-  static String escapeBytes(final ByteString input) {
-    return escapeBytes(new ByteSequence() {
-      public int size() {
-        return input.size();
-      }
-      public byte byteAt(int offset) {
-        return input.byteAt(offset);
-      }
-    });
-  }
-
-  /**
-   * Like {@link #escapeBytes(ByteString)}, but used for byte array.
-   */
-  static String escapeBytes(final byte[] input) {
-    return escapeBytes(new ByteSequence() {
-      public int size() {
-        return input.length;
-      }
-      public byte byteAt(int offset) {
-        return input[offset];
-      }
-    });
-  }
-
-  /**
-   * Un-escape a byte sequence as escaped using
-   * {@link #escapeBytes(ByteString)}.  Two-digit hex escapes (starting with
-   * "\x") are also recognized.
-   */
-  static ByteString unescapeBytes(final CharSequence charString)
-      throws InvalidEscapeSequenceException {
-    // First convert the Java character sequence to UTF-8 bytes.
-    ByteString input = ByteString.copyFromUtf8(charString.toString());
-    // Then unescape certain byte sequences introduced by ASCII '\\'.  The valid
-    // escapes can all be expressed with ASCII characters, so it is safe to
-    // operate on bytes here.
-    //
-    // Unescaping the input byte array will result in a byte sequence that's no
-    // longer than the input.  That's because each escape sequence is between
-    // two and four bytes long and stands for a single byte.
-    final byte[] result = new byte[input.size()];
-    int pos = 0;
-    for (int i = 0; i < input.size(); i++) {
-      byte c = input.byteAt(i);
-      if (c == '\\') {
-        if (i + 1 < input.size()) {
-          ++i;
-          c = input.byteAt(i);
-          if (isOctal(c)) {
-            // Octal escape.
-            int code = digitValue(c);
-            if (i + 1 < input.size() && isOctal(input.byteAt(i + 1))) {
-              ++i;
-              code = code * 8 + digitValue(input.byteAt(i));
-            }
-            if (i + 1 < input.size() && isOctal(input.byteAt(i + 1))) {
-              ++i;
-              code = code * 8 + digitValue(input.byteAt(i));
-            }
-            // TODO: Check that 0 <= code && code <= 0xFF.
-            result[pos++] = (byte)code;
-          } else {
-            switch (c) {
-              case 'a' : result[pos++] = 0x07; break;
-              case 'b' : result[pos++] = '\b'; break;
-              case 'f' : result[pos++] = '\f'; break;
-              case 'n' : result[pos++] = '\n'; break;
-              case 'r' : result[pos++] = '\r'; break;
-              case 't' : result[pos++] = '\t'; break;
-              case 'v' : result[pos++] = 0x0b; break;
-              case '\\': result[pos++] = '\\'; break;
-              case '\'': result[pos++] = '\''; break;
-              case '"' : result[pos++] = '\"'; break;
-
-              case 'x':
-                // hex escape
-                int code = 0;
-                if (i + 1 < input.size() && isHex(input.byteAt(i + 1))) {
-                  ++i;
-                  code = digitValue(input.byteAt(i));
-                } else {
-                  throw new InvalidEscapeSequenceException(
-                      "Invalid escape sequence: '\\x' with no digits");
-                }
-                if (i + 1 < input.size() && isHex(input.byteAt(i + 1))) {
-                  ++i;
-                  code = code * 16 + digitValue(input.byteAt(i));
-                }
-                result[pos++] = (byte)code;
-                break;
-
-              default:
-                throw new InvalidEscapeSequenceException(
-                    "Invalid escape sequence: '\\" + (char)c + '\'');
-            }
-          }
-        } else {
-          throw new InvalidEscapeSequenceException(
-              "Invalid escape sequence: '\\' at end of string.");
-        }
-      } else {
-        result[pos++] = c;
-      }
-    }
-
-    return ByteString.copyFrom(result, 0, pos);
-  }
-
-  /**
-   * Thrown by {@link TextFormat#unescapeBytes} and
-   * {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
-   */
-  static class InvalidEscapeSequenceException extends IOException {
-    private static final long serialVersionUID = -8164033650142593304L;
-
-    InvalidEscapeSequenceException(final String description) {
-      super(description);
-    }
-  }
-
-  /**
-   * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
-   * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
-   * individually as a 3-digit octal escape.  Yes, it's weird.
-   */
-  static String escapeText(final String input) {
-    return escapeBytes(ByteString.copyFromUtf8(input));
-  }
-
-  /**
-   * Escape double quotes and backslashes in a String for unicode output of a message.
-   */
-  public static String escapeDoubleQuotesAndBackslashes(final String input) {
-    return input.replace("\\", "\\\\").replace("\"", "\\\"");
-  }
-
-  /**
-   * Un-escape a text string as escaped using {@link #escapeText(String)}.
-   * Two-digit hex escapes (starting with "\x") are also recognized.
-   */
-  static String unescapeText(final String input)
-                             throws InvalidEscapeSequenceException {
-    return unescapeBytes(input).toStringUtf8();
-  }
-
-  /** Is this an octal digit? */
-  private static boolean isOctal(final byte c) {
-    return '0' <= c && c <= '7';
-  }
-
-  /** Is this a hex digit? */
-  private static boolean isHex(final byte c) {
-    return ('0' <= c && c <= '9') ||
-           ('a' <= c && c <= 'f') ||
-           ('A' <= c && c <= 'F');
-  }
-
-  /**
-   * Interpret a character as a digit (in any base up to 36) and return the
-   * numeric value.  This is like {@code Character.digit()} but we don't accept
-   * non-ASCII digits.
-   */
-  private static int digitValue(final byte c) {
-    if ('0' <= c && c <= '9') {
-      return c - '0';
-    } else if ('a' <= c && c <= 'z') {
-      return c - 'a' + 10;
-    } else {
-      return c - 'A' + 10;
-    }
-  }
-
-  /**
-   * Parse a 32-bit signed integer from the text.  Unlike the Java standard
-   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
-   * and "0" to signify hexadecimal and octal numbers, respectively.
-   */
-  static int parseInt32(final String text) throws NumberFormatException {
-    return (int) parseInteger(text, true, false);
-  }
-
-  /**
-   * Parse a 32-bit unsigned integer from the text.  Unlike the Java standard
-   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
-   * and "0" to signify hexadecimal and octal numbers, respectively.  The
-   * result is coerced to a (signed) {@code int} when returned since Java has
-   * no unsigned integer type.
-   */
-  static int parseUInt32(final String text) throws NumberFormatException {
-    return (int) parseInteger(text, false, false);
-  }
-
-  /**
-   * Parse a 64-bit signed integer from the text.  Unlike the Java standard
-   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
-   * and "0" to signify hexadecimal and octal numbers, respectively.
-   */
-  static long parseInt64(final String text) throws NumberFormatException {
-    return parseInteger(text, true, true);
-  }
-
-  /**
-   * Parse a 64-bit unsigned integer from the text.  Unlike the Java standard
-   * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
-   * and "0" to signify hexadecimal and octal numbers, respectively.  The
-   * result is coerced to a (signed) {@code long} when returned since Java has
-   * no unsigned long type.
-   */
-  static long parseUInt64(final String text) throws NumberFormatException {
-    return parseInteger(text, false, true);
-  }
-
-  private static long parseInteger(final String text,
-                                   final boolean isSigned,
-                                   final boolean isLong)
-                                   throws NumberFormatException {
-    int pos = 0;
-
-    boolean negative = false;
-    if (text.startsWith("-", pos)) {
-      if (!isSigned) {
-        throw new NumberFormatException("Number must be positive: " + text);
-      }
-      ++pos;
-      negative = true;
-    }
-
-    int radix = 10;
-    if (text.startsWith("0x", pos)) {
-      pos += 2;
-      radix = 16;
-    } else if (text.startsWith("0", pos)) {
-      radix = 8;
-    }
-
-    final String numberText = text.substring(pos);
-
-    long result = 0;
-    if (numberText.length() < 16) {
-      // Can safely assume no overflow.
-      result = Long.parseLong(numberText, radix);
-      if (negative) {
-        result = -result;
-      }
-
-      // Check bounds.
-      // No need to check for 64-bit numbers since they'd have to be 16 chars
-      // or longer to overflow.
-      if (!isLong) {
-        if (isSigned) {
-          if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
-            throw new NumberFormatException(
-              "Number out of range for 32-bit signed integer: " + text);
-          }
-        } else {
-          if (result >= (1L << 32) || result < 0) {
-            throw new NumberFormatException(
-              "Number out of range for 32-bit unsigned integer: " + text);
-          }
-        }
-      }
-    } else {
-      BigInteger bigValue = new BigInteger(numberText, radix);
-      if (negative) {
-        bigValue = bigValue.negate();
-      }
-
-      // Check bounds.
-      if (!isLong) {
-        if (isSigned) {
-          if (bigValue.bitLength() > 31) {
-            throw new NumberFormatException(
-              "Number out of range for 32-bit signed integer: " + text);
-          }
-        } else {
-          if (bigValue.bitLength() > 32) {
-            throw new NumberFormatException(
-              "Number out of range for 32-bit unsigned integer: " + text);
-          }
-        }
-      } else {
-        if (isSigned) {
-          if (bigValue.bitLength() > 63) {
-            throw new NumberFormatException(
-              "Number out of range for 64-bit signed integer: " + text);
-          }
-        } else {
-          if (bigValue.bitLength() > 64) {
-            throw new NumberFormatException(
-              "Number out of range for 64-bit unsigned integer: " + text);
-          }
-        }
-      }
-
-      result = bigValue.longValue();
-    }
-
-    return result;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
deleted file mode 100644
index 99de373..0000000
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ /dev/null
@@ -1,995 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * {@code UnknownFieldSet} is used to keep track of fields which were seen when
- * parsing a protocol message but whose field numbers or types are unrecognized.
- * This most frequently occurs when new fields are added to a message type
- * and then messages containing those fields are read by old software that was
- * compiled before the new types were added.
- *
- * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
- * {@link Message.Builder} contains an {@link Builder}).
- *
- * <p>Most users will never need to use this class.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class UnknownFieldSet implements MessageLite {
-  private UnknownFieldSet() {}
-
-  /** Create a new {@link Builder}. */
-  public static Builder newBuilder() {
-    return Builder.create();
-  }
-
-  /**
-   * Create a new {@link Builder} and initialize it to be a copy
-   * of {@code copyFrom}.
-   */
-  public static Builder newBuilder(final UnknownFieldSet copyFrom) {
-    return newBuilder().mergeFrom(copyFrom);
-  }
-
-  /** Get an empty {@code UnknownFieldSet}. */
-  public static UnknownFieldSet getDefaultInstance() {
-    return defaultInstance;
-  }
-  public UnknownFieldSet getDefaultInstanceForType() {
-    return defaultInstance;
-  }
-  private static final UnknownFieldSet defaultInstance =
-    new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
-
-  /**
-   * Construct an {@code UnknownFieldSet} around the given map.  The map is
-   * expected to be immutable.
-   */
-  private UnknownFieldSet(final Map<Integer, Field> fields) {
-    this.fields = fields;
-  }
-  private Map<Integer, Field> fields;
-
-
-  @Override
-  public boolean equals(final Object other) {
-    if (this == other) {
-      return true;
-    }
-    return (other instanceof UnknownFieldSet) &&
-           fields.equals(((UnknownFieldSet) other).fields);
-  }
-
-  @Override
-  public int hashCode() {
-    return fields.hashCode();
-  }
-
-  /** Get a map of fields in the set by number. */
-  public Map<Integer, Field> asMap() {
-    return fields;
-  }
-
-  /** Check if the given field number is present in the set. */
-  public boolean hasField(final int number) {
-    return fields.containsKey(number);
-  }
-
-  /**
-   * Get a field by number.  Returns an empty field if not present.  Never
-   * returns {@code null}.
-   */
-  public Field getField(final int number) {
-    final Field result = fields.get(number);
-    return (result == null) ? Field.getDefaultInstance() : result;
-  }
-
-  /** Serializes the set and writes it to {@code output}. */
-  public void writeTo(final CodedOutputStream output) throws IOException {
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      entry.getValue().writeTo(entry.getKey(), output);
-    }
-  }
-
-  /**
-   * Converts the set to a string in protocol buffer text format. This is
-   * just a trivial wrapper around
-   * {@link TextFormat#printToString(UnknownFieldSet)}.
-   */
-  @Override
-  public String toString() {
-    return TextFormat.printToString(this);
-  }
-
-  /**
-   * Serializes the message to a {@code ByteString} and returns it. This is
-   * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
-   */
-  public ByteString toByteString() {
-    try {
-      final ByteString.CodedBuilder out =
-        ByteString.newCodedBuilder(getSerializedSize());
-      writeTo(out.getCodedOutput());
-      return out.build();
-    } catch (final IOException e) {
-      throw new RuntimeException(
-        "Serializing to a ByteString threw an IOException (should " +
-        "never happen).", e);
-    }
-  }
-
-  /**
-   * Serializes the message to a {@code byte} array and returns it.  This is
-   * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
-   */
-  public byte[] toByteArray() {
-    try {
-      final byte[] result = new byte[getSerializedSize()];
-      final CodedOutputStream output = CodedOutputStream.newInstance(result);
-      writeTo(output);
-      output.checkNoSpaceLeft();
-      return result;
-    } catch (final IOException e) {
-      throw new RuntimeException(
-        "Serializing to a byte array threw an IOException " +
-        "(should never happen).", e);
-    }
-  }
-
-  /**
-   * Serializes the message and writes it to {@code output}.  This is just a
-   * trivial wrapper around {@link #writeTo(CodedOutputStream)}.
-   */
-  public void writeTo(final OutputStream output) throws IOException {
-    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
-    writeTo(codedOutput);
-    codedOutput.flush();
-  }
-
-  public void writeDelimitedTo(OutputStream output) throws IOException {
-    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
-    codedOutput.writeRawVarint32(getSerializedSize());
-    writeTo(codedOutput);
-    codedOutput.flush();
-  }
-
-  /** Get the number of bytes required to encode this set. */
-  public int getSerializedSize() {
-    int result = 0;
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      result += entry.getValue().getSerializedSize(entry.getKey());
-    }
-    return result;
-  }
-
-  /**
-   * Serializes the set and writes it to {@code output} using
-   * {@code MessageSet} wire format.
-   */
-  public void writeAsMessageSetTo(final CodedOutputStream output)
-      throws IOException {
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      entry.getValue().writeAsMessageSetExtensionTo(
-        entry.getKey(), output);
-    }
-  }
-
-  /**
-   * Get the number of bytes required to encode this set using
-   * {@code MessageSet} wire format.
-   */
-  public int getSerializedSizeAsMessageSet() {
-    int result = 0;
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      result += entry.getValue().getSerializedSizeAsMessageSetExtension(
-        entry.getKey());
-    }
-    return result;
-  }
-
-  public boolean isInitialized() {
-    // UnknownFieldSets do not have required fields, so they are always
-    // initialized.
-    return true;
-  }
-
-  /** Parse an {@code UnknownFieldSet} from the given input stream. */
-  public static UnknownFieldSet parseFrom(final CodedInputStream input)
-                                          throws IOException {
-    return newBuilder().mergeFrom(input).build();
-  }
-
-  /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(final ByteString data)
-      throws InvalidProtocolBufferException {
-    return newBuilder().mergeFrom(data).build();
-  }
-
-  /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(final byte[] data)
-      throws InvalidProtocolBufferException {
-    return newBuilder().mergeFrom(data).build();
-  }
-
-  /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
-  public static UnknownFieldSet parseFrom(final InputStream input)
-                                          throws IOException {
-    return newBuilder().mergeFrom(input).build();
-  }
-
-  public Builder newBuilderForType() {
-    return newBuilder();
-  }
-
-  public Builder toBuilder() {
-    return newBuilder().mergeFrom(this);
-  }
-
-  /**
-   * Builder for {@link UnknownFieldSet}s.
-   *
-   * <p>Note that this class maintains {@link Field.Builder}s for all fields
-   * in the set.  Thus, adding one element to an existing {@link Field} does not
-   * require making a copy.  This is important for efficient parsing of
-   * unknown repeated fields.  However, it implies that {@link Field}s cannot
-   * be constructed independently, nor can two {@link UnknownFieldSet}s share
-   * the same {@code Field} object.
-   *
-   * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
-   */
-  public static final class Builder implements MessageLite.Builder {
-    // This constructor should never be called directly (except from 'create').
-    private Builder() {}
-
-    private Map<Integer, Field> fields;
-
-    // Optimization:  We keep around a builder for the last field that was
-    //   modified so that we can efficiently add to it multiple times in a
-    //   row (important when parsing an unknown repeated field).
-    private int lastFieldNumber;
-    private Field.Builder lastField;
-
-    private static Builder create() {
-      Builder builder = new Builder();
-      builder.reinitialize();
-      return builder;
-    }
-
-    /**
-     * Get a field builder for the given field number which includes any
-     * values that already exist.
-     */
-    private Field.Builder getFieldBuilder(final int number) {
-      if (lastField != null) {
-        if (number == lastFieldNumber) {
-          return lastField;
-        }
-        // Note:  addField() will reset lastField and lastFieldNumber.
-        addField(lastFieldNumber, lastField.build());
-      }
-      if (number == 0) {
-        return null;
-      } else {
-        final Field existing = fields.get(number);
-        lastFieldNumber = number;
-        lastField = Field.newBuilder();
-        if (existing != null) {
-          lastField.mergeFrom(existing);
-        }
-        return lastField;
-      }
-    }
-
-    /**
-     * Build the {@link UnknownFieldSet} and return it.
-     *
-     * <p>Once {@code build()} has been called, the {@code Builder} will no
-     * longer be usable.  Calling any method after {@code build()} will result
-     * in undefined behavior and can cause a {@code NullPointerException} to be
-     * thrown.
-     */
-    public UnknownFieldSet build() {
-      getFieldBuilder(0);  // Force lastField to be built.
-      final UnknownFieldSet result;
-      if (fields.isEmpty()) {
-        result = getDefaultInstance();
-      } else {
-        result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
-      }
-      fields = null;
-      return result;
-    }
-
-    public UnknownFieldSet buildPartial() {
-      // No required fields, so this is the same as build().
-      return build();
-    }
-
-    @Override
-    public Builder clone() {
-      getFieldBuilder(0);  // Force lastField to be built.
-      return UnknownFieldSet.newBuilder().mergeFrom(
-          new UnknownFieldSet(fields));
-    }
-
-    public UnknownFieldSet getDefaultInstanceForType() {
-      return UnknownFieldSet.getDefaultInstance();
-    }
-
-    private void reinitialize() {
-      fields = Collections.emptyMap();
-      lastFieldNumber = 0;
-      lastField = null;
-    }
-
-    /** Reset the builder to an empty set. */
-    public Builder clear() {
-      reinitialize();
-      return this;
-    }
-    
-    /** Clear fields from the set with a given field number. */
-    public Builder clearField(final int number) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      if (lastField != null && lastFieldNumber == number) {
-        // Discard this.
-        lastField = null;
-        lastFieldNumber = 0;
-      }
-      if (fields.containsKey(number)) {
-        fields.remove(number);
-      }
-      return this;
-    }
-
-    /**
-     * Merge the fields from {@code other} into this set.  If a field number
-     * exists in both sets, {@code other}'s values for that field will be
-     * appended to the values in this set.
-     */
-    public Builder mergeFrom(final UnknownFieldSet other) {
-      if (other != getDefaultInstance()) {
-        for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
-          mergeField(entry.getKey(), entry.getValue());
-        }
-      }
-      return this;
-    }
-
-    /**
-     * Add a field to the {@code UnknownFieldSet}.  If a field with the same
-     * number already exists, the two are merged.
-     */
-    public Builder mergeField(final int number, final Field field) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      if (hasField(number)) {
-        getFieldBuilder(number).mergeFrom(field);
-      } else {
-        // Optimization:  We could call getFieldBuilder(number).mergeFrom(field)
-        // in this case, but that would create a copy of the Field object.
-        // We'd rather reuse the one passed to us, so call addField() instead.
-        addField(number, field);
-      }
-      return this;
-    }
-
-    /**
-     * Convenience method for merging a new field containing a single varint
-     * value.  This is used in particular when an unknown enum value is
-     * encountered.
-     */
-    public Builder mergeVarintField(final int number, final int value) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      getFieldBuilder(number).addVarint(value);
-      return this;
-    }
-
-    /** Check if the given field number is present in the set. */
-    public boolean hasField(final int number) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      return number == lastFieldNumber || fields.containsKey(number);
-    }
-
-    /**
-     * Add a field to the {@code UnknownFieldSet}.  If a field with the same
-     * number already exists, it is removed.
-     */
-    public Builder addField(final int number, final Field field) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      if (lastField != null && lastFieldNumber == number) {
-        // Discard this.
-        lastField = null;
-        lastFieldNumber = 0;
-      }
-      if (fields.isEmpty()) {
-        fields = new TreeMap<Integer,Field>();
-      }
-      fields.put(number, field);
-      return this;
-    }
-
-    /**
-     * Get all present {@code Field}s as an immutable {@code Map}.  If more
-     * fields are added, the changes may or may not be reflected in this map.
-     */
-    public Map<Integer, Field> asMap() {
-      getFieldBuilder(0);  // Force lastField to be built.
-      return Collections.unmodifiableMap(fields);
-    }
-
-    /**
-     * Parse an entire message from {@code input} and merge its fields into
-     * this set.
-     */
-    public Builder mergeFrom(final CodedInputStream input) throws IOException {
-      while (true) {
-        final int tag = input.readTag();
-        if (tag == 0 || !mergeFieldFrom(tag, input)) {
-          break;
-        }
-      }
-      return this;
-    }
-
-    /**
-     * Parse a single field from {@code input} and merge it into this set.
-     * @param tag The field's tag number, which was already parsed.
-     * @return {@code false} if the tag is an end group tag.
-     */
-    public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
-                                  throws IOException {
-      final int number = WireFormat.getTagFieldNumber(tag);
-      switch (WireFormat.getTagWireType(tag)) {
-        case WireFormat.WIRETYPE_VARINT:
-          getFieldBuilder(number).addVarint(input.readInt64());
-          return true;
-        case WireFormat.WIRETYPE_FIXED64:
-          getFieldBuilder(number).addFixed64(input.readFixed64());
-          return true;
-        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-          getFieldBuilder(number).addLengthDelimited(input.readBytes());
-          return true;
-        case WireFormat.WIRETYPE_START_GROUP:
-          final Builder subBuilder = newBuilder();
-          input.readGroup(number, subBuilder,
-                          ExtensionRegistry.getEmptyRegistry());
-          getFieldBuilder(number).addGroup(subBuilder.build());
-          return true;
-        case WireFormat.WIRETYPE_END_GROUP:
-          return false;
-        case WireFormat.WIRETYPE_FIXED32:
-          getFieldBuilder(number).addFixed32(input.readFixed32());
-          return true;
-        default:
-          throw InvalidProtocolBufferException.invalidWireType();
-      }
-    }
-
-    /**
-     * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
-     * set being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     */
-    public Builder mergeFrom(final ByteString data)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input = data.newCodedInput();
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return this;
-      } catch (final InvalidProtocolBufferException e) {
-        throw e;
-      } catch (final IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    /**
-     * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
-     * set being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     */
-    public Builder mergeFrom(final byte[] data)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input = CodedInputStream.newInstance(data);
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return this;
-      } catch (final InvalidProtocolBufferException e) {
-        throw e;
-      } catch (final IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    /**
-     * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
-     * set being built.  This is just a small wrapper around
-     * {@link #mergeFrom(CodedInputStream)}.
-     */
-    public Builder mergeFrom(final InputStream input) throws IOException {
-      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
-      mergeFrom(codedInput);
-      codedInput.checkLastTagWas(0);
-      return this;
-    }
-
-    public boolean mergeDelimitedFrom(InputStream input)
-        throws IOException {
-      final int firstByte = input.read();
-      if (firstByte == -1) {
-        return false;
-      }
-      final int size = CodedInputStream.readRawVarint32(firstByte, input);
-      final InputStream limitedInput = new LimitedInputStream(input, size);
-      mergeFrom(limitedInput);
-      return true;
-    }
-
-    public boolean mergeDelimitedFrom(
-        InputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
-      // UnknownFieldSet has no extensions.
-      return mergeDelimitedFrom(input);
-    }
-
-    public Builder mergeFrom(
-        CodedInputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
-      // UnknownFieldSet has no extensions.
-      return mergeFrom(input);
-    }
-
-    public Builder mergeFrom(
-        ByteString data,
-        ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      // UnknownFieldSet has no extensions.
-      return mergeFrom(data);
-    }
-
-    public Builder mergeFrom(byte[] data, int off, int len)
-        throws InvalidProtocolBufferException {
-      try {
-        final CodedInputStream input =
-            CodedInputStream.newInstance(data, off, len);
-        mergeFrom(input);
-        input.checkLastTagWas(0);
-        return this;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
-      }
-    }
-
-    public Builder mergeFrom(
-        byte[] data,
-        ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      // UnknownFieldSet has no extensions.
-      return mergeFrom(data);
-    }
-
-    public Builder mergeFrom(
-        byte[] data, int off, int len,
-        ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      // UnknownFieldSet has no extensions.
-      return mergeFrom(data, off, len);
-    }
-
-    public Builder mergeFrom(
-        InputStream input,
-        ExtensionRegistryLite extensionRegistry) throws IOException {
-      // UnknownFieldSet has no extensions.
-      return mergeFrom(input);
-    }
-
-    public boolean isInitialized() {
-      // UnknownFieldSets do not have required fields, so they are always
-      // initialized.
-      return true;
-    }
-  }
-
-  /**
-   * Represents a single field in an {@code UnknownFieldSet}.
-   *
-   * <p>A {@code Field} consists of five lists of values.  The lists correspond
-   * to the five "wire types" used in the protocol buffer binary format.
-   * The wire type of each field can be determined from the encoded form alone,
-   * without knowing the field's declared type.  So, we are able to parse
-   * unknown values at least this far and separate them.  Normally, only one
-   * of the five lists will contain any values, since it is impossible to
-   * define a valid message type that declares two different types for the
-   * same field number.  However, the code is designed to allow for the case
-   * where the same unknown field number is encountered using multiple different
-   * wire types.
-   *
-   * <p>{@code Field} is an immutable class.  To construct one, you must use a
-   * {@link Builder}.
-   *
-   * @see UnknownFieldSet
-   */
-  public static final class Field {
-    private Field() {}
-
-    /** Construct a new {@link Builder}. */
-    public static Builder newBuilder() {
-      return Builder.create();
-    }
-
-    /**
-     * Construct a new {@link Builder} and initialize it to a copy of
-     * {@code copyFrom}.
-     */
-    public static Builder newBuilder(final Field copyFrom) {
-      return newBuilder().mergeFrom(copyFrom);
-    }
-
-    /** Get an empty {@code Field}. */
-    public static Field getDefaultInstance() {
-      return fieldDefaultInstance;
-    }
-    private static final Field fieldDefaultInstance = newBuilder().build();
-
-    /** Get the list of varint values for this field. */
-    public List<Long> getVarintList()               { return varint;          }
-
-    /** Get the list of fixed32 values for this field. */
-    public List<Integer> getFixed32List()           { return fixed32;         }
-
-    /** Get the list of fixed64 values for this field. */
-    public List<Long> getFixed64List()              { return fixed64;         }
-
-    /** Get the list of length-delimited values for this field. */
-    public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
-
-    /**
-     * Get the list of embedded group values for this field.  These are
-     * represented using {@link UnknownFieldSet}s rather than {@link Message}s
-     * since the group's type is presumably unknown.
-     */
-    public List<UnknownFieldSet> getGroupList()      { return group;           }
-
-    @Override
-    public boolean equals(final Object other) {
-      if (this == other) {
-        return true;
-      }
-      if (!(other instanceof Field)) {
-        return false;
-      }
-      return Arrays.equals(getIdentityArray(),
-          ((Field) other).getIdentityArray());
-    }
-
-    @Override
-    public int hashCode() {
-      return Arrays.hashCode(getIdentityArray());
-    }
-
-    /**
-     * Returns the array of objects to be used to uniquely identify this
-     * {@link Field} instance.
-     */
-    private Object[] getIdentityArray() {
-      return new Object[] {
-          varint,
-          fixed32,
-          fixed64,
-          lengthDelimited,
-          group};
-    }
-
-    /**
-     * Serializes the field, including field number, and writes it to
-     * {@code output}.
-     */
-    public void writeTo(final int fieldNumber, final CodedOutputStream output)
-                        throws IOException {
-      for (final long value : varint) {
-        output.writeUInt64(fieldNumber, value);
-      }
-      for (final int value : fixed32) {
-        output.writeFixed32(fieldNumber, value);
-      }
-      for (final long value : fixed64) {
-        output.writeFixed64(fieldNumber, value);
-      }
-      for (final ByteString value : lengthDelimited) {
-        output.writeBytes(fieldNumber, value);
-      }
-      for (final UnknownFieldSet value : group) {
-        output.writeGroup(fieldNumber, value);
-      }
-    }
-
-    /**
-     * Get the number of bytes required to encode this field, including field
-     * number.
-     */
-    public int getSerializedSize(final int fieldNumber) {
-      int result = 0;
-      for (final long value : varint) {
-        result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
-      }
-      for (final int value : fixed32) {
-        result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
-      }
-      for (final long value : fixed64) {
-        result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
-      }
-      for (final ByteString value : lengthDelimited) {
-        result += CodedOutputStream.computeBytesSize(fieldNumber, value);
-      }
-      for (final UnknownFieldSet value : group) {
-        result += CodedOutputStream.computeGroupSize(fieldNumber, value);
-      }
-      return result;
-    }
-
-    /**
-     * Serializes the field, including field number, and writes it to
-     * {@code output}, using {@code MessageSet} wire format.
-     */
-    public void writeAsMessageSetExtensionTo(
-        final int fieldNumber,
-        final CodedOutputStream output)
-        throws IOException {
-      for (final ByteString value : lengthDelimited) {
-        output.writeRawMessageSetExtension(fieldNumber, value);
-      }
-    }
-
-    /**
-     * Get the number of bytes required to encode this field, including field
-     * number, using {@code MessageSet} wire format.
-     */
-    public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
-      int result = 0;
-      for (final ByteString value : lengthDelimited) {
-        result += CodedOutputStream.computeRawMessageSetExtensionSize(
-          fieldNumber, value);
-      }
-      return result;
-    }
-
-    private List<Long> varint;
-    private List<Integer> fixed32;
-    private List<Long> fixed64;
-    private List<ByteString> lengthDelimited;
-    private List<UnknownFieldSet> group;
-
-    /**
-     * Used to build a {@link Field} within an {@link UnknownFieldSet}.
-     *
-     * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
-     */
-    public static final class Builder {
-      // This constructor should never be called directly (except from 'create').
-      private Builder() {}
-
-      private static Builder create() {
-        Builder builder = new Builder();
-        builder.result = new Field();
-        return builder;
-      }
-
-      private Field result;
-
-      /**
-       * Build the field.  After {@code build()} has been called, the
-       * {@code Builder} is no longer usable.  Calling any other method will
-       * result in undefined behavior and can cause a
-       * {@code NullPointerException} to be thrown.
-       */
-      public Field build() {
-        if (result.varint == null) {
-          result.varint = Collections.emptyList();
-        } else {
-          result.varint = Collections.unmodifiableList(result.varint);
-        }
-        if (result.fixed32 == null) {
-          result.fixed32 = Collections.emptyList();
-        } else {
-          result.fixed32 = Collections.unmodifiableList(result.fixed32);
-        }
-        if (result.fixed64 == null) {
-          result.fixed64 = Collections.emptyList();
-        } else {
-          result.fixed64 = Collections.unmodifiableList(result.fixed64);
-        }
-        if (result.lengthDelimited == null) {
-          result.lengthDelimited = Collections.emptyList();
-        } else {
-          result.lengthDelimited =
-            Collections.unmodifiableList(result.lengthDelimited);
-        }
-        if (result.group == null) {
-          result.group = Collections.emptyList();
-        } else {
-          result.group = Collections.unmodifiableList(result.group);
-        }
-
-        final Field returnMe = result;
-        result = null;
-        return returnMe;
-      }
-
-      /** Discard the field's contents. */
-      public Builder clear() {
-        result = new Field();
-        return this;
-      }
-
-      /**
-       * Merge the values in {@code other} into this field.  For each list
-       * of values, {@code other}'s values are append to the ones in this
-       * field.
-       */
-      public Builder mergeFrom(final Field other) {
-        if (!other.varint.isEmpty()) {
-          if (result.varint == null) {
-            result.varint = new ArrayList<Long>();
-          }
-          result.varint.addAll(other.varint);
-        }
-        if (!other.fixed32.isEmpty()) {
-          if (result.fixed32 == null) {
-            result.fixed32 = new ArrayList<Integer>();
-          }
-          result.fixed32.addAll(other.fixed32);
-        }
-        if (!other.fixed64.isEmpty()) {
-          if (result.fixed64 == null) {
-            result.fixed64 = new ArrayList<Long>();
-          }
-          result.fixed64.addAll(other.fixed64);
-        }
-        if (!other.lengthDelimited.isEmpty()) {
-          if (result.lengthDelimited == null) {
-            result.lengthDelimited = new ArrayList<ByteString>();
-          }
-          result.lengthDelimited.addAll(other.lengthDelimited);
-        }
-        if (!other.group.isEmpty()) {
-          if (result.group == null) {
-            result.group = new ArrayList<UnknownFieldSet>();
-          }
-          result.group.addAll(other.group);
-        }
-        return this;
-      }
-
-      /** Add a varint value. */
-      public Builder addVarint(final long value) {
-        if (result.varint == null) {
-          result.varint = new ArrayList<Long>();
-        }
-        result.varint.add(value);
-        return this;
-      }
-
-      /** Add a fixed32 value. */
-      public Builder addFixed32(final int value) {
-        if (result.fixed32 == null) {
-          result.fixed32 = new ArrayList<Integer>();
-        }
-        result.fixed32.add(value);
-        return this;
-      }
-
-      /** Add a fixed64 value. */
-      public Builder addFixed64(final long value) {
-        if (result.fixed64 == null) {
-          result.fixed64 = new ArrayList<Long>();
-        }
-        result.fixed64.add(value);
-        return this;
-      }
-
-      /** Add a length-delimited value. */
-      public Builder addLengthDelimited(final ByteString value) {
-        if (result.lengthDelimited == null) {
-          result.lengthDelimited = new ArrayList<ByteString>();
-        }
-        result.lengthDelimited.add(value);
-        return this;
-      }
-
-      /** Add an embedded group. */
-      public Builder addGroup(final UnknownFieldSet value) {
-        if (result.group == null) {
-          result.group = new ArrayList<UnknownFieldSet>();
-        }
-        result.group.add(value);
-        return this;
-      }
-    }
-  }
-
-  /**
-   * Parser to implement MessageLite interface.
-   */
-  public static final class Parser extends AbstractParser<UnknownFieldSet> {
-    public UnknownFieldSet parsePartialFrom(
-        CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-        throws InvalidProtocolBufferException {
-      Builder builder = newBuilder();
-      try {
-        builder.mergeFrom(input);
-      } catch (InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(builder.buildPartial());
-      } catch (IOException e) {
-        throw new InvalidProtocolBufferException(e.getMessage())
-            .setUnfinishedMessage(builder.buildPartial());
-      }
-      return builder.buildPartial();
-    }
-  }
-
-  private static final Parser PARSER = new Parser();
-  public final Parser getParserForType() {
-    return PARSER;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
deleted file mode 100644
index 5cc005d..0000000
--- a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.util.AbstractList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.RandomAccess;
-
-/**
- * An implementation of {@link LazyStringList} that wraps another
- * {@link LazyStringList} such that it cannot be modified via the wrapper.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class UnmodifiableLazyStringList extends AbstractList<String>
-    implements LazyStringList, RandomAccess {
-
-  private final LazyStringList list;
-
-  public UnmodifiableLazyStringList(LazyStringList list) {
-    this.list = list;
-  }
-
-  @Override
-  public String get(int index) {
-    return list.get(index);
-  }
-
-  @Override
-  public int size() {
-    return list.size();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public ByteString getByteString(int index) {
-    return list.getByteString(index);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void add(ByteString element) {
-    throw new UnsupportedOperationException();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void set(int index, ByteString element) {
-    throw new UnsupportedOperationException();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public boolean addAllByteString(Collection<? extends ByteString> element) {
-    throw new UnsupportedOperationException();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public byte[] getByteArray(int index) {
-    return list.getByteArray(index);
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void add(byte[] element) {
-    throw new UnsupportedOperationException();
-  }
-  
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void set(int index, byte[] element) {
-    throw new UnsupportedOperationException();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public boolean addAllByteArray(Collection<byte[]> element) {
-    throw new UnsupportedOperationException();
-  }
-
-  @Override
-  public ListIterator<String> listIterator(final int index) {
-    return new ListIterator<String>() {
-      ListIterator<String> iter = list.listIterator(index);
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public boolean hasNext() {
-        return iter.hasNext();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public String next() {
-        return iter.next();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public boolean hasPrevious() {
-        return iter.hasPrevious();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public String previous() {
-        return iter.previous();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public int nextIndex() {
-        return iter.nextIndex();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public int previousIndex() {
-        return iter.previousIndex();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void set(String o) {
-        throw new UnsupportedOperationException();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void add(String o) {
-        throw new UnsupportedOperationException();
-      }
-    };
-  }
-
-  @Override
-  public Iterator<String> iterator() {
-    return new Iterator<String>() {
-      Iterator<String> iter = list.iterator();
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public boolean hasNext() {
-        return iter.hasNext();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public String next() {
-        return iter.next();
-      }
-
-      //@Override (Java 1.6 override semantics, but we must support 1.5)
-      public void remove() {
-        throw new UnsupportedOperationException();
-      }
-    };
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public List<?> getUnderlyingElements() {
-    // The returned value is already unmodifiable.
-    return list.getUnderlyingElements();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void mergeFrom(LazyStringList other) {
-    throw new UnsupportedOperationException();
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public List<byte[]> asByteArrayList() {
-    return Collections.unmodifiableList(list.asByteArrayList());
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public List<ByteString> asByteStringList() {
-    return Collections.unmodifiableList(list.asByteStringList());
-  }
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public LazyStringList getUnmodifiableView() {
-    return this;
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/src/main/java/com/google/protobuf/Utf8.java
deleted file mode 100644
index 4d0ef53..0000000
--- a/java/src/main/java/com/google/protobuf/Utf8.java
+++ /dev/null
@@ -1,349 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * A set of low-level, high-performance static utility methods related
- * to the UTF-8 character encoding.  This class has no dependencies
- * outside of the core JDK libraries.
- *
- * <p>There are several variants of UTF-8.  The one implemented by
- * this class is the restricted definition of UTF-8 introduced in
- * Unicode 3.1, which mandates the rejection of "overlong" byte
- * sequences as well as rejection of 3-byte surrogate codepoint byte
- * sequences.  Note that the UTF-8 decoder included in Oracle's JDK
- * has been modified to also reject "overlong" byte sequences, but (as
- * of 2011) still accepts 3-byte surrogate codepoint byte sequences.
- *
- * <p>The byte sequences considered valid by this class are exactly
- * those that can be roundtrip converted to Strings and back to bytes
- * using the UTF-8 charset, without loss: <pre> {@code
- * Arrays.equals(bytes, new String(bytes, "UTF-8").getBytes("UTF-8"))
- * }</pre>
- *
- * <p>See the Unicode Standard,</br>
- * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
- * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
- *
- * <p>This class supports decoding of partial byte sequences, so that the
- * bytes in a complete UTF-8 byte sequences can be stored in multiple
- * segments.  Methods typically return {@link #MALFORMED} if the partial
- * byte sequence is definitely not well-formed, {@link #COMPLETE} if it is
- * well-formed in the absence of additional input, or if the byte sequence
- * apparently terminated in the middle of a character, an opaque integer
- * "state" value containing enough information to decode the character when
- * passed to a subsequent invocation of a partial decoding method.
- *
- * @author martinrb@google.com (Martin Buchholz)
- */
-final class Utf8 {
-  private Utf8() {}
-
-  /**
-   * State value indicating that the byte sequence is well-formed and
-   * complete (no further bytes are needed to complete a character).
-   */
-  public static final int COMPLETE = 0;
-
-  /**
-   * State value indicating that the byte sequence is definitely not
-   * well-formed.
-   */
-  public static final int MALFORMED = -1;
-
-  // Other state values include the partial bytes of the incomplete
-  // character to be decoded in the simplest way: we pack the bytes
-  // into the state int in little-endian order.  For example:
-  //
-  // int state = byte1 ^ (byte2 << 8) ^ (byte3 << 16);
-  //
-  // Such a state is unpacked thus (note the ~ operation for byte2 to
-  // undo byte1's sign-extension bits):
-  //
-  // int byte1 = (byte) state;
-  // int byte2 = (byte) ~(state >> 8);
-  // int byte3 = (byte) (state >> 16);
-  //
-  // We cannot store a zero byte in the state because it would be
-  // indistinguishable from the absence of a byte.  But we don't need
-  // to, because partial bytes must always be negative.  When building
-  // a state, we ensure that byte1 is negative and subsequent bytes
-  // are valid trailing bytes.
-
-  /**
-   * Returns {@code true} if the given byte array is a well-formed
-   * UTF-8 byte sequence.
-   *
-   * <p>This is a convenience method, equivalent to a call to {@code
-   * isValidUtf8(bytes, 0, bytes.length)}.
-   */
-  public static boolean isValidUtf8(byte[] bytes) {
-    return isValidUtf8(bytes, 0, bytes.length);
-  }
-
-  /**
-   * Returns {@code true} if the given byte array slice is a
-   * well-formed UTF-8 byte sequence.  The range of bytes to be
-   * checked extends from index {@code index}, inclusive, to {@code
-   * limit}, exclusive.
-   *
-   * <p>This is a convenience method, equivalent to {@code
-   * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
-   */
-  public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
-    return partialIsValidUtf8(bytes, index, limit) == COMPLETE;
-  }
-
-  /**
-   * Tells whether the given byte array slice is a well-formed,
-   * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
-   * to be checked extends from index {@code index}, inclusive, to
-   * {@code limit}, exclusive.
-   *
-   * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
-   * operation) or the value returned from a call to a partial decoding method
-   * for the previous bytes
-   *
-   * @return {@link #MALFORMED} if the partial byte sequence is
-   * definitely not well-formed, {@link #COMPLETE} if it is well-formed
-   * (no additional input needed), or if the byte sequence is
-   * "incomplete", i.e. apparently terminated in the middle of a character,
-   * an opaque integer "state" value containing enough information to
-   * decode the character when passed to a subsequent invocation of a
-   * partial decoding method.
-   */
-  public static int partialIsValidUtf8(
-      int state, byte[] bytes, int index, int limit) {
-    if (state != COMPLETE) {
-      // The previous decoding operation was incomplete (or malformed).
-      // We look for a well-formed sequence consisting of bytes from
-      // the previous decoding operation (stored in state) together
-      // with bytes from the array slice.
-      //
-      // We expect such "straddler characters" to be rare.
-
-      if (index >= limit) {  // No bytes? No progress.
-        return state;
-      }
-      int byte1 = (byte) state;
-      // byte1 is never ASCII.
-      if (byte1 < (byte) 0xE0) {
-        // two-byte form
-
-        // Simultaneously checks for illegal trailing-byte in
-        // leading position and overlong 2-byte form.
-        if (byte1 < (byte) 0xC2 ||
-            // byte2 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else if (byte1 < (byte) 0xF0) {
-        // three-byte form
-
-        // Get byte2 from saved state or array
-        int byte2 = (byte) ~(state >> 8);
-        if (byte2 == 0) {
-          byte2 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2);
-          }
-        }
-        if (byte2 > (byte) 0xBF ||
-            // overlong? 5 most significant bits must not all be zero
-            (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
-            // illegal surrogate codepoint?
-            (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else {
-        // four-byte form
-
-        // Get byte2 and byte3 from saved state or array
-        int byte2 = (byte) ~(state >> 8);
-        int byte3 = 0;
-        if (byte2 == 0) {
-          byte2 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2);
-          }
-        } else {
-          byte3 = (byte) (state >> 16);
-        }
-        if (byte3 == 0) {
-          byte3 = bytes[index++];
-          if (index >= limit) {
-            return incompleteStateFor(byte1, byte2, byte3);
-          }
-        }
-
-        // If we were called with state == MALFORMED, then byte1 is 0xFF,
-        // which never occurs in well-formed UTF-8, and so we will return
-        // MALFORMED again below.
-
-        if (byte2 > (byte) 0xBF ||
-            // Check that 1 <= plane <= 16.  Tricky optimized form of:
-            // if (byte1 > (byte) 0xF4 ||
-            //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
-            //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
-            (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
-            // byte3 trailing-byte test
-            byte3 > (byte) 0xBF ||
-            // byte4 trailing-byte test
-             bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      }
-    }
-
-    return partialIsValidUtf8(bytes, index, limit);
-  }
-
-  /**
-   * Tells whether the given byte array slice is a well-formed,
-   * malformed, or incomplete UTF-8 byte sequence.  The range of bytes
-   * to be checked extends from index {@code index}, inclusive, to
-   * {@code limit}, exclusive.
-   *
-   * <p>This is a convenience method, equivalent to a call to {@code
-   * partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}.
-   *
-   * @return {@link #MALFORMED} if the partial byte sequence is
-   * definitely not well-formed, {@link #COMPLETE} if it is well-formed
-   * (no additional input needed), or if the byte sequence is
-   * "incomplete", i.e. apparently terminated in the middle of a character,
-   * an opaque integer "state" value containing enough information to
-   * decode the character when passed to a subsequent invocation of a
-   * partial decoding method.
-   */
-  public static int partialIsValidUtf8(
-      byte[] bytes, int index, int limit) {
-    // Optimize for 100% ASCII.
-    // Hotspot loves small simple top-level loops like this.
-    while (index < limit && bytes[index] >= 0) {
-      index++;
-    }
-
-    return (index >= limit) ? COMPLETE :
-        partialIsValidUtf8NonAscii(bytes, index, limit);
-  }
-
-  private static int partialIsValidUtf8NonAscii(
-      byte[] bytes, int index, int limit) {
-    for (;;) {
-      int byte1, byte2;
-
-      // Optimize for interior runs of ASCII bytes.
-      do {
-        if (index >= limit) {
-          return COMPLETE;
-        }
-      } while ((byte1 = bytes[index++]) >= 0);
-
-      if (byte1 < (byte) 0xE0) {
-        // two-byte form
-
-        if (index >= limit) {
-          return byte1;
-        }
-
-        // Simultaneously checks for illegal trailing-byte in
-        // leading position and overlong 2-byte form.
-        if (byte1 < (byte) 0xC2 ||
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else if (byte1 < (byte) 0xF0) {
-        // three-byte form
-
-        if (index >= limit - 1) { // incomplete sequence
-          return incompleteStateFor(bytes, index, limit);
-        }
-        if ((byte2 = bytes[index++]) > (byte) 0xBF ||
-            // overlong? 5 most significant bits must not all be zero
-            (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
-            // check for illegal surrogate codepoints
-            (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      } else {
-        // four-byte form
-
-        if (index >= limit - 2) {  // incomplete sequence
-          return incompleteStateFor(bytes, index, limit);
-        }
-        if ((byte2 = bytes[index++]) > (byte) 0xBF ||
-            // Check that 1 <= plane <= 16.  Tricky optimized form of:
-            // if (byte1 > (byte) 0xF4 ||
-            //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
-            //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
-            (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
-            // byte3 trailing-byte test
-            bytes[index++] > (byte) 0xBF ||
-            // byte4 trailing-byte test
-            bytes[index++] > (byte) 0xBF) {
-          return MALFORMED;
-        }
-      }
-    }
-  }
-
-  private static int incompleteStateFor(int byte1) {
-    return (byte1 > (byte) 0xF4) ?
-        MALFORMED : byte1;
-  }
-
-  private static int incompleteStateFor(int byte1, int byte2) {
-    return (byte1 > (byte) 0xF4 ||
-            byte2 > (byte) 0xBF) ?
-        MALFORMED : byte1 ^ (byte2 << 8);
-  }
-
-  private static int incompleteStateFor(int byte1, int byte2, int byte3) {
-    return (byte1 > (byte) 0xF4 ||
-            byte2 > (byte) 0xBF ||
-            byte3 > (byte) 0xBF) ?
-        MALFORMED : byte1 ^ (byte2 << 8) ^ (byte3 << 16);
-  }
-
-  private static int incompleteStateFor(byte[] bytes, int index, int limit) {
-    int byte1 = bytes[index - 1];
-    switch (limit - index) {
-      case 0: return incompleteStateFor(byte1);
-      case 1: return incompleteStateFor(byte1, bytes[index]);
-      case 2: return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
-      default: throw new AssertionError();
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java
deleted file mode 100644
index eba2528..0000000
--- a/java/src/main/java/com/google/protobuf/WireFormat.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * This class is used internally by the Protocol Buffer library and generated
- * message implementations.  It is public only because those generated messages
- * do not reside in the {@code protobuf} package.  Others should not use this
- * class directly.
- *
- * This class contains constants and helper functions useful for dealing with
- * the Protocol Buffer wire format.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class WireFormat {
-  // Do not allow instantiation.
-  private WireFormat() {}
-
-  public static final int WIRETYPE_VARINT           = 0;
-  public static final int WIRETYPE_FIXED64          = 1;
-  public static final int WIRETYPE_LENGTH_DELIMITED = 2;
-  public static final int WIRETYPE_START_GROUP      = 3;
-  public static final int WIRETYPE_END_GROUP        = 4;
-  public static final int WIRETYPE_FIXED32          = 5;
-
-  static final int TAG_TYPE_BITS = 3;
-  static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
-
-  /** Given a tag value, determines the wire type (the lower 3 bits). */
-  static int getTagWireType(final int tag) {
-    return tag & TAG_TYPE_MASK;
-  }
-
-  /** Given a tag value, determines the field number (the upper 29 bits). */
-  public static int getTagFieldNumber(final int tag) {
-    return tag >>> TAG_TYPE_BITS;
-  }
-
-  /** Makes a tag value given a field number and wire type. */
-  static int makeTag(final int fieldNumber, final int wireType) {
-    return (fieldNumber << TAG_TYPE_BITS) | wireType;
-  }
-
-  /**
-   * Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}.  This is
-   * only here to support the lite runtime and should not be used by users.
-   */
-  public enum JavaType {
-    INT(0),
-    LONG(0L),
-    FLOAT(0F),
-    DOUBLE(0D),
-    BOOLEAN(false),
-    STRING(""),
-    BYTE_STRING(ByteString.EMPTY),
-    ENUM(null),
-    MESSAGE(null);
-
-    JavaType(final Object defaultDefault) {
-      this.defaultDefault = defaultDefault;
-    }
-
-    /**
-     * The default default value for fields of this type, if it's a primitive
-     * type.
-     */
-    Object getDefaultDefault() {
-      return defaultDefault;
-    }
-
-    private final Object defaultDefault;
-  }
-
-  /**
-   * Lite equivalent to {@link Descriptors.FieldDescriptor.Type}.  This is
-   * only here to support the lite runtime and should not be used by users.
-   */
-  public enum FieldType {
-    DOUBLE  (JavaType.DOUBLE     , WIRETYPE_FIXED64         ),
-    FLOAT   (JavaType.FLOAT      , WIRETYPE_FIXED32         ),
-    INT64   (JavaType.LONG       , WIRETYPE_VARINT          ),
-    UINT64  (JavaType.LONG       , WIRETYPE_VARINT          ),
-    INT32   (JavaType.INT        , WIRETYPE_VARINT          ),
-    FIXED64 (JavaType.LONG       , WIRETYPE_FIXED64         ),
-    FIXED32 (JavaType.INT        , WIRETYPE_FIXED32         ),
-    BOOL    (JavaType.BOOLEAN    , WIRETYPE_VARINT          ),
-    STRING  (JavaType.STRING     , WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
-    },
-    GROUP   (JavaType.MESSAGE    , WIRETYPE_START_GROUP     ) {
-      public boolean isPackable() { return false; }
-    },
-    MESSAGE (JavaType.MESSAGE    , WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
-    },
-    BYTES   (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
-      public boolean isPackable() { return false; }
-    },
-    UINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
-    ENUM    (JavaType.ENUM       , WIRETYPE_VARINT          ),
-    SFIXED32(JavaType.INT        , WIRETYPE_FIXED32         ),
-    SFIXED64(JavaType.LONG       , WIRETYPE_FIXED64         ),
-    SINT32  (JavaType.INT        , WIRETYPE_VARINT          ),
-    SINT64  (JavaType.LONG       , WIRETYPE_VARINT          );
-
-    FieldType(final JavaType javaType, final int wireType) {
-      this.javaType = javaType;
-      this.wireType = wireType;
-    }
-
-    private final JavaType javaType;
-    private final int wireType;
-
-    public JavaType getJavaType() { return javaType; }
-    public int getWireType() { return wireType; }
-
-    public boolean isPackable() { return true; }
-  }
-
-  // Field numbers for fields in MessageSet wire format.
-  static final int MESSAGE_SET_ITEM    = 1;
-  static final int MESSAGE_SET_TYPE_ID = 2;
-  static final int MESSAGE_SET_MESSAGE = 3;
-
-  // Tag numbers.
-  static final int MESSAGE_SET_ITEM_TAG =
-    makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
-  static final int MESSAGE_SET_ITEM_END_TAG =
-    makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
-  static final int MESSAGE_SET_TYPE_ID_TAG =
-    makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
-  static final int MESSAGE_SET_MESSAGE_TAG =
-    makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
deleted file mode 100644
index 844d0a8..0000000
--- a/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
+++ /dev/null
@@ -1,658 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-
-/**
- * Reads and decodes protocol message fields.
- *
- * This class contains two kinds of methods:  methods that read specific
- * protocol message constructs and field types (e.g. {@link #readTag()} and
- * {@link #readInt32()}) and methods that read low-level values (e.g.
- * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
- * encoded protocol messages, you should use the former methods, but if you are
- * reading some other format of your own design, use the latter.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class CodedInputByteBufferNano {
-  /**
-   * Create a new CodedInputStream wrapping the given byte array.
-   */
-  public static CodedInputByteBufferNano newInstance(final byte[] buf) {
-    return newInstance(buf, 0, buf.length);
-  }
-
-  /**
-   * Create a new CodedInputStream wrapping the given byte array slice.
-   */
-  public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
-                                             final int len) {
-    return new CodedInputByteBufferNano(buf, off, len);
-  }
-
-  // -----------------------------------------------------------------
-
-  /**
-   * Attempt to read a field tag, returning zero if we have reached EOF.
-   * Protocol message parsers use this to read tags, since a protocol message
-   * may legally end wherever a tag occurs, and zero is not a valid tag number.
-   */
-  public int readTag() throws IOException {
-    if (isAtEnd()) {
-      lastTag = 0;
-      return 0;
-    }
-
-    lastTag = readRawVarint32();
-    if (lastTag == 0) {
-      // If we actually read zero, that's not a valid tag.
-      throw InvalidProtocolBufferNanoException.invalidTag();
-    }
-    return lastTag;
-  }
-
-  /**
-   * Verifies that the last call to readTag() returned the given tag value.
-   * This is used to verify that a nested group ended with the correct
-   * end tag.
-   *
-   * @throws InvalidProtocolBufferNanoException {@code value} does not match the
-   *                                        last tag.
-   */
-  public void checkLastTagWas(final int value)
-                              throws InvalidProtocolBufferNanoException {
-    if (lastTag != value) {
-      throw InvalidProtocolBufferNanoException.invalidEndTag();
-    }
-  }
-
-  /**
-   * Reads and discards a single field, given its tag value.
-   *
-   * @return {@code false} if the tag is an endgroup tag, in which case
-   *         nothing is skipped.  Otherwise, returns {@code true}.
-   */
-  public boolean skipField(final int tag) throws IOException {
-    switch (WireFormatNano.getTagWireType(tag)) {
-      case WireFormatNano.WIRETYPE_VARINT:
-        readInt32();
-        return true;
-      case WireFormatNano.WIRETYPE_FIXED64:
-        readRawLittleEndian64();
-        return true;
-      case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
-        skipRawBytes(readRawVarint32());
-        return true;
-      case WireFormatNano.WIRETYPE_START_GROUP:
-        skipMessage();
-        checkLastTagWas(
-          WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
-                             WireFormatNano.WIRETYPE_END_GROUP));
-        return true;
-      case WireFormatNano.WIRETYPE_END_GROUP:
-        return false;
-      case WireFormatNano.WIRETYPE_FIXED32:
-        readRawLittleEndian32();
-        return true;
-      default:
-        throw InvalidProtocolBufferNanoException.invalidWireType();
-    }
-  }
-
-  /**
-   * Reads and discards an entire message.  This will read either until EOF
-   * or until an endgroup tag, whichever comes first.
-   */
-  public void skipMessage() throws IOException {
-    while (true) {
-      final int tag = readTag();
-      if (tag == 0 || !skipField(tag)) {
-        return;
-      }
-    }
-  }
-
-  // -----------------------------------------------------------------
-
-  /** Read a {@code double} field value from the stream. */
-  public double readDouble() throws IOException {
-    return Double.longBitsToDouble(readRawLittleEndian64());
-  }
-
-  /** Read a {@code float} field value from the stream. */
-  public float readFloat() throws IOException {
-    return Float.intBitsToFloat(readRawLittleEndian32());
-  }
-
-  /** Read a {@code uint64} field value from the stream. */
-  public long readUInt64() throws IOException {
-    return readRawVarint64();
-  }
-
-  /** Read an {@code int64} field value from the stream. */
-  public long readInt64() throws IOException {
-    return readRawVarint64();
-  }
-
-  /** Read an {@code int32} field value from the stream. */
-  public int readInt32() throws IOException {
-    return readRawVarint32();
-  }
-
-  /** Read a {@code fixed64} field value from the stream. */
-  public long readFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
-
-  /** Read a {@code fixed32} field value from the stream. */
-  public int readFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
-
-  /** Read a {@code bool} field value from the stream. */
-  public boolean readBool() throws IOException {
-    return readRawVarint32() != 0;
-  }
-
-  /** Read a {@code string} field value from the stream. */
-  public String readString() throws IOException {
-    final int size = readRawVarint32();
-    if (size < 0) {
-      throw InvalidProtocolBufferNanoException.negativeSize();
-    }
-    if (size > (bufferSize - bufferPos)) {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-
-    final String result = new String(buffer, bufferPos, size, "UTF-8");
-    bufferPos += size;
-    return result;
-  }
-
-  /** Read a {@code group} field value from the stream. */
-  public void readGroup(final MessageNano msg, final int fieldNumber)
-      throws IOException {
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
-    }
-    ++recursionDepth;
-    msg.mergeFrom(this);
-    checkLastTagWas(
-      WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
-    --recursionDepth;
-  }
-
-  public void readMessage(final MessageNano msg)
-      throws IOException {
-    final int length = readRawVarint32();
-    if (recursionDepth >= recursionLimit) {
-      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
-    }
-    final int oldLimit = pushLimit(length);
-    ++recursionDepth;
-    msg.mergeFrom(this);
-    checkLastTagWas(0);
-    --recursionDepth;
-    popLimit(oldLimit);
-  }
-
-  /** Read a {@code bytes} field value from the stream. */
-  public byte[] readBytes() throws IOException {
-    final int size = readRawVarint32();
-    if (size < 0) {
-      throw InvalidProtocolBufferNanoException.negativeSize();
-    }
-    if (size == 0) {
-      return WireFormatNano.EMPTY_BYTES;
-    }
-    if (size > (bufferSize - bufferPos)) {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-
-    final byte[] result = new byte[size];
-    System.arraycopy(buffer, bufferPos, result, 0, size);
-    bufferPos += size;
-    return result;
-  }
-
-  /** Read a {@code uint32} field value from the stream. */
-  public int readUInt32() throws IOException {
-    return readRawVarint32();
-  }
-
-  /**
-   * Read an enum field value from the stream.  Caller is responsible
-   * for converting the numeric value to an actual enum.
-   */
-  public int readEnum() throws IOException {
-    return readRawVarint32();
-  }
-
-  /** Read an {@code sfixed32} field value from the stream. */
-  public int readSFixed32() throws IOException {
-    return readRawLittleEndian32();
-  }
-
-  /** Read an {@code sfixed64} field value from the stream. */
-  public long readSFixed64() throws IOException {
-    return readRawLittleEndian64();
-  }
-
-  /** Read an {@code sint32} field value from the stream. */
-  public int readSInt32() throws IOException {
-    return decodeZigZag32(readRawVarint32());
-  }
-
-  /** Read an {@code sint64} field value from the stream. */
-  public long readSInt64() throws IOException {
-    return decodeZigZag64(readRawVarint64());
-  }
-
-  // =================================================================
-
-  /**
-   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
-   * upper bits.
-   */
-  public int readRawVarint32() throws IOException {
-    byte tmp = readRawByte();
-    if (tmp >= 0) {
-      return tmp;
-    }
-    int result = tmp & 0x7f;
-    if ((tmp = readRawByte()) >= 0) {
-      result |= tmp << 7;
-    } else {
-      result |= (tmp & 0x7f) << 7;
-      if ((tmp = readRawByte()) >= 0) {
-        result |= tmp << 14;
-      } else {
-        result |= (tmp & 0x7f) << 14;
-        if ((tmp = readRawByte()) >= 0) {
-          result |= tmp << 21;
-        } else {
-          result |= (tmp & 0x7f) << 21;
-          result |= (tmp = readRawByte()) << 28;
-          if (tmp < 0) {
-            // Discard upper 32 bits.
-            for (int i = 0; i < 5; i++) {
-              if (readRawByte() >= 0) {
-                return result;
-              }
-            }
-            throw InvalidProtocolBufferNanoException.malformedVarint();
-          }
-        }
-      }
-    }
-    return result;
-  }
-
-  /** Read a raw Varint from the stream. */
-  public long readRawVarint64() throws IOException {
-    int shift = 0;
-    long result = 0;
-    while (shift < 64) {
-      final byte b = readRawByte();
-      result |= (long)(b & 0x7F) << shift;
-      if ((b & 0x80) == 0) {
-        return result;
-      }
-      shift += 7;
-    }
-    throw InvalidProtocolBufferNanoException.malformedVarint();
-  }
-
-  /** Read a 32-bit little-endian integer from the stream. */
-  public int readRawLittleEndian32() throws IOException {
-    final byte b1 = readRawByte();
-    final byte b2 = readRawByte();
-    final byte b3 = readRawByte();
-    final byte b4 = readRawByte();
-    return ((b1 & 0xff)      ) |
-           ((b2 & 0xff) <<  8) |
-           ((b3 & 0xff) << 16) |
-           ((b4 & 0xff) << 24);
-  }
-
-  /** Read a 64-bit little-endian integer from the stream. */
-  public long readRawLittleEndian64() throws IOException {
-    final byte b1 = readRawByte();
-    final byte b2 = readRawByte();
-    final byte b3 = readRawByte();
-    final byte b4 = readRawByte();
-    final byte b5 = readRawByte();
-    final byte b6 = readRawByte();
-    final byte b7 = readRawByte();
-    final byte b8 = readRawByte();
-    return (((long)b1 & 0xff)      ) |
-           (((long)b2 & 0xff) <<  8) |
-           (((long)b3 & 0xff) << 16) |
-           (((long)b4 & 0xff) << 24) |
-           (((long)b5 & 0xff) << 32) |
-           (((long)b6 & 0xff) << 40) |
-           (((long)b7 & 0xff) << 48) |
-           (((long)b8 & 0xff) << 56);
-  }
-
-  /**
-   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 32-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 32-bit integer.
-   */
-  public static int decodeZigZag32(final int n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  /**
-   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n An unsigned 64-bit integer, stored in a signed int because
-   *          Java has no explicit unsigned support.
-   * @return A signed 64-bit integer.
-   */
-  public static long decodeZigZag64(final long n) {
-    return (n >>> 1) ^ -(n & 1);
-  }
-
-  // -----------------------------------------------------------------
-
-  private final byte[] buffer;
-  private int bufferStart;
-  private int bufferSize;
-  private int bufferSizeAfterLimit;
-  private int bufferPos;
-  private int lastTag;
-
-  /** The absolute position of the end of the current message. */
-  private int currentLimit = Integer.MAX_VALUE;
-
-  /** See setRecursionLimit() */
-  private int recursionDepth;
-  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
-
-  /** See setSizeLimit() */
-  private int sizeLimit = DEFAULT_SIZE_LIMIT;
-
-  private static final int DEFAULT_RECURSION_LIMIT = 64;
-  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
-
-  private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
-    this.buffer = buffer;
-    bufferStart = off;
-    bufferSize = off + len;
-    bufferPos = off;
-  }
-
-  /**
-   * Set the maximum message recursion depth.  In order to prevent malicious
-   * messages from causing stack overflows, {@code CodedInputStream} limits
-   * how deeply messages may be nested.  The default limit is 64.
-   *
-   * @return the old limit.
-   */
-  public int setRecursionLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Recursion limit cannot be negative: " + limit);
-    }
-    final int oldLimit = recursionLimit;
-    recursionLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Set the maximum message size.  In order to prevent malicious
-   * messages from exhausting memory or causing integer overflows,
-   * {@code CodedInputStream} limits how large a message may be.
-   * The default limit is 64MB.  You should set this limit as small
-   * as you can without harming your app's functionality.  Note that
-   * size limits only apply when reading from an {@code InputStream}, not
-   * when constructed around a raw byte array.
-   * <p>
-   * If you want to read several messages from a single CodedInputStream, you
-   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
-   * size limit.
-   *
-   * @return the old limit.
-   */
-  public int setSizeLimit(final int limit) {
-    if (limit < 0) {
-      throw new IllegalArgumentException(
-        "Size limit cannot be negative: " + limit);
-    }
-    final int oldLimit = sizeLimit;
-    sizeLimit = limit;
-    return oldLimit;
-  }
-
-  /**
-   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
-   */
-  public void resetSizeCounter() {
-  }
-
-  /**
-   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
-   * is called when descending into a length-delimited embedded message.
-   *
-   * @return the old limit.
-   */
-  public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
-    if (byteLimit < 0) {
-      throw InvalidProtocolBufferNanoException.negativeSize();
-    }
-    byteLimit += bufferPos;
-    final int oldLimit = currentLimit;
-    if (byteLimit > oldLimit) {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-    currentLimit = byteLimit;
-
-    recomputeBufferSizeAfterLimit();
-
-    return oldLimit;
-  }
-
-  private void recomputeBufferSizeAfterLimit() {
-    bufferSize += bufferSizeAfterLimit;
-    final int bufferEnd = bufferSize;
-    if (bufferEnd > currentLimit) {
-      // Limit is in current buffer.
-      bufferSizeAfterLimit = bufferEnd - currentLimit;
-      bufferSize -= bufferSizeAfterLimit;
-    } else {
-      bufferSizeAfterLimit = 0;
-    }
-  }
-
-  /**
-   * Discards the current limit, returning to the previous limit.
-   *
-   * @param oldLimit The old limit, as returned by {@code pushLimit}.
-   */
-  public void popLimit(final int oldLimit) {
-    currentLimit = oldLimit;
-    recomputeBufferSizeAfterLimit();
-  }
-
-  /**
-   * Returns the number of bytes to be read before the current limit.
-   * If no limit is set, returns -1.
-   */
-  public int getBytesUntilLimit() {
-    if (currentLimit == Integer.MAX_VALUE) {
-      return -1;
-    }
-
-    final int currentAbsolutePosition = bufferPos;
-    return currentLimit - currentAbsolutePosition;
-  }
-
-  /**
-   * Returns true if the stream has reached the end of the input.  This is the
-   * case if either the end of the underlying input source has been reached or
-   * if the stream has reached a limit created using {@link #pushLimit(int)}.
-   */
-  public boolean isAtEnd() {
-    return bufferPos == bufferSize;
-  }
-
-  /**
-   * Get current position in buffer relative to beginning offset.
-   */
-  public int getPosition() {
-    return bufferPos - bufferStart;
-  }
-
-  /**
-   * Get current (absolute) position in buffer.
-   */
-  public int getAbsolutePosition() {
-    return bufferPos;
-  }
-
-  /**
-   * Return the raw underlying data in the buffer, directly.
-   */
-  public byte[] getBuffer() {
-    return buffer;
-  }
-
-  /**
-   * Retrieves a subset of data in the buffer. The returned array is not backed by the original
-   * buffer array.
-   *
-   * @param offset the position (relative to the buffer start position) to start at.
-   * @param length the number of bytes to retrieve.
-   */
-  public byte[] getData(int offset, int length) {
-    if (length == 0) {
-      return WireFormatNano.EMPTY_BYTES;
-    }
-    byte[] copy = new byte[length];
-    int start = bufferStart + offset;
-    System.arraycopy(buffer, start, copy, 0, length);
-    return copy;
-  }
-
-  /**
-   * Rewind to previous position. Cannot go forward.
-   */
-  public void rewindToPosition(int position) {
-    if (position > bufferPos - bufferStart) {
-      throw new IllegalArgumentException(
-              "Position " + position + " is beyond current " + (bufferPos - bufferStart));
-    }
-    if (position < 0) {
-      throw new IllegalArgumentException("Bad position " + position);
-    }
-    bufferPos = bufferStart + position;
-  }
-
-  /**
-   * Read one byte from the input.
-   *
-   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte readRawByte() throws IOException {
-    if (bufferPos == bufferSize) {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-    return buffer[bufferPos++];
-  }
-
-  /**
-   * Read a fixed size of bytes from the input.
-   *
-   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public byte[] readRawBytes(final int size) throws IOException {
-    if (size < 0) {
-      throw InvalidProtocolBufferNanoException.negativeSize();
-    }
-
-    if (bufferPos + size > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - bufferPos);
-      // Then fail.
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-
-    if (size <= bufferSize - bufferPos) {
-      // We have all the bytes we need already.
-      final byte[] bytes = new byte[size];
-      System.arraycopy(buffer, bufferPos, bytes, 0, size);
-      bufferPos += size;
-      return bytes;
-    } else {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-  }
-
-  /**
-   * Reads and discards {@code size} bytes.
-   *
-   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  public void skipRawBytes(final int size) throws IOException {
-    if (size < 0) {
-      throw InvalidProtocolBufferNanoException.negativeSize();
-    }
-
-    if (bufferPos + size > currentLimit) {
-      // Read to the end of the stream anyway.
-      skipRawBytes(currentLimit - bufferPos);
-      // Then fail.
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-
-    if (size <= bufferSize - bufferPos) {
-      // We have all the bytes we need already.
-      bufferPos += size;
-    } else {
-      throw InvalidProtocolBufferNanoException.truncatedMessage();
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
deleted file mode 100644
index 662f0fa..0000000
--- a/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
+++ /dev/null
@@ -1,1128 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ReadOnlyBufferException;
-
-/**
- * Encodes and writes protocol message fields.
- *
- * <p>This class contains two kinds of methods:  methods that write specific
- * protocol message constructs and field types (e.g. {@link #writeTag} and
- * {@link #writeInt32}) and methods that write low-level values (e.g.
- * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
- * writing encoded protocol messages, you should use the former methods, but if
- * you are writing some other format of your own design, use the latter.
- *
- * <p>This class is totally unsynchronized.
- *
- * @author kneton@google.com Kenton Varda
- */
-public final class CodedOutputByteBufferNano {
-  /* max bytes per java UTF-16 char in UTF-8 */
-  private static final int MAX_UTF8_EXPANSION = 3;
-  private final ByteBuffer buffer;
-
-  private CodedOutputByteBufferNano(final byte[] buffer, final int offset,
-                            final int length) {
-    this(ByteBuffer.wrap(buffer, offset, length));
-  }
-
-  private CodedOutputByteBufferNano(final ByteBuffer buffer) {
-    this.buffer = buffer;
-    this.buffer.order(ByteOrder.LITTLE_ENDIAN);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes directly to the given
-   * byte array.  If more bytes are written than fit in the array,
-   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
-   * array is faster than writing to an {@code OutputStream}.
-   */
-  public static CodedOutputByteBufferNano newInstance(final byte[] flatArray) {
-    return newInstance(flatArray, 0, flatArray.length);
-  }
-
-  /**
-   * Create a new {@code CodedOutputStream} that writes directly to the given
-   * byte array slice.  If more bytes are written than fit in the slice,
-   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
-   * array is faster than writing to an {@code OutputStream}.
-   */
-  public static CodedOutputByteBufferNano newInstance(final byte[] flatArray,
-                                              final int offset,
-                                              final int length) {
-    return new CodedOutputByteBufferNano(flatArray, offset, length);
-  }
-
-  // -----------------------------------------------------------------
-
-  /** Write a {@code double} field, including tag, to the stream. */
-  public void writeDouble(final int fieldNumber, final double value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
-    writeDoubleNoTag(value);
-  }
-
-  /** Write a {@code float} field, including tag, to the stream. */
-  public void writeFloat(final int fieldNumber, final float value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
-    writeFloatNoTag(value);
-  }
-
-  /** Write a {@code uint64} field, including tag, to the stream. */
-  public void writeUInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeUInt64NoTag(value);
-  }
-
-  /** Write an {@code int64} field, including tag, to the stream. */
-  public void writeInt64(final int fieldNumber, final long value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeInt64NoTag(value);
-  }
-
-  /** Write an {@code int32} field, including tag, to the stream. */
-  public void writeInt32(final int fieldNumber, final int value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeInt32NoTag(value);
-  }
-
-  /** Write a {@code fixed64} field, including tag, to the stream. */
-  public void writeFixed64(final int fieldNumber, final long value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
-    writeFixed64NoTag(value);
-  }
-
-  /** Write a {@code fixed32} field, including tag, to the stream. */
-  public void writeFixed32(final int fieldNumber, final int value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
-    writeFixed32NoTag(value);
-  }
-
-  /** Write a {@code bool} field, including tag, to the stream. */
-  public void writeBool(final int fieldNumber, final boolean value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeBoolNoTag(value);
-  }
-
-  /** Write a {@code string} field, including tag, to the stream. */
-  public void writeString(final int fieldNumber, final String value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
-    writeStringNoTag(value);
-  }
-
-  /** Write a {@code group} field, including tag, to the stream. */
-  public void writeGroup(final int fieldNumber, final MessageNano value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_START_GROUP);
-    writeGroupNoTag(value);
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
-  }
-
-  /** Write an embedded message field, including tag, to the stream. */
-  public void writeMessage(final int fieldNumber, final MessageNano value)
-                           throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
-    writeMessageNoTag(value);
-  }
-
-  /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeBytes(final int fieldNumber, final byte[] value)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
-    writeBytesNoTag(value);
-  }
-
-  /** Write a {@code bytes} field, including tag, to the stream. */
-  public void writeBytes(final int fieldNumber, final byte[] value,
-                         final int offset, final int length)
-                         throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
-    writeBytesNoTag(value, offset, length);
-  }
-
-  /** Write a {@code uint32} field, including tag, to the stream. */
-  public void writeUInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeUInt32NoTag(value);
-  }
-
-  /**
-   * Write an enum field, including tag, to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
-   */
-  public void writeEnum(final int fieldNumber, final int value)
-                        throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeEnumNoTag(value);
-  }
-
-  /** Write an {@code sfixed32} field, including tag, to the stream. */
-  public void writeSFixed32(final int fieldNumber, final int value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
-    writeSFixed32NoTag(value);
-  }
-
-  /** Write an {@code sfixed64} field, including tag, to the stream. */
-  public void writeSFixed64(final int fieldNumber, final long value)
-                            throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
-    writeSFixed64NoTag(value);
-  }
-
-  /** Write an {@code sint32} field, including tag, to the stream. */
-  public void writeSInt32(final int fieldNumber, final int value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeSInt32NoTag(value);
-  }
-
-  /** Write an {@code sint64} field, including tag, to the stream. */
-  public void writeSInt64(final int fieldNumber, final long value)
-                          throws IOException {
-    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
-    writeSInt64NoTag(value);
-  }
-
-  /**
-   * Write a MessageSet extension field to the stream.  For historical reasons,
-   * the wire format differs from normal fields.
-   */
-//  public void writeMessageSetExtension(final int fieldNumber,
-//                                       final MessageMicro value)
-//                                       throws IOException {
-//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
-//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
-//    writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
-//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
-//  }
-
-  /**
-   * Write an unparsed MessageSet extension field to the stream.  For
-   * historical reasons, the wire format differs from normal fields.
-   */
-//  public void writeRawMessageSetExtension(final int fieldNumber,
-//                                          final ByteStringMicro value)
-//                                          throws IOException {
-//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
-//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
-//    writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
-//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
-//  }
-
-  // -----------------------------------------------------------------
-
-  /** Write a {@code double} field to the stream. */
-  public void writeDoubleNoTag(final double value) throws IOException {
-    writeRawLittleEndian64(Double.doubleToLongBits(value));
-  }
-
-  /** Write a {@code float} field to the stream. */
-  public void writeFloatNoTag(final float value) throws IOException {
-    writeRawLittleEndian32(Float.floatToIntBits(value));
-  }
-
-  /** Write a {@code uint64} field to the stream. */
-  public void writeUInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
-  /** Write an {@code int64} field to the stream. */
-  public void writeInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(value);
-  }
-
-  /** Write an {@code int32} field to the stream. */
-  public void writeInt32NoTag(final int value) throws IOException {
-    if (value >= 0) {
-      writeRawVarint32(value);
-    } else {
-      // Must sign-extend.
-      writeRawVarint64(value);
-    }
-  }
-
-  /** Write a {@code fixed64} field to the stream. */
-  public void writeFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
-  }
-
-  /** Write a {@code fixed32} field to the stream. */
-  public void writeFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
-  }
-
-  /** Write a {@code bool} field to the stream. */
-  public void writeBoolNoTag(final boolean value) throws IOException {
-    writeRawByte(value ? 1 : 0);
-  }
-
-  /** Write a {@code string} field to the stream. */
-  public void writeStringNoTag(final String value) throws IOException {
-    // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
-    // and at most 3 times of it. Optimize for the case where we know this length results in a
-    // constant varint length - saves measuring length of the string.
-    try {
-      final int minLengthVarIntSize = computeRawVarint32Size(value.length());
-      final int maxLengthVarIntSize = computeRawVarint32Size(value.length() * MAX_UTF8_EXPANSION);
-      if (minLengthVarIntSize == maxLengthVarIntSize) {
-        int oldPosition = buffer.position();
-        // Buffer.position, when passed a position that is past its limit, throws
-        // IllegalArgumentException, and this class is documented to throw
-        // OutOfSpaceException instead.
-        if (buffer.remaining() < minLengthVarIntSize) {
-          throw new OutOfSpaceException(oldPosition + minLengthVarIntSize, buffer.limit());
-        }
-        buffer.position(oldPosition + minLengthVarIntSize);
-        encode(value, buffer);
-        int newPosition = buffer.position();
-        buffer.position(oldPosition);
-        writeRawVarint32(newPosition - oldPosition - minLengthVarIntSize);
-        buffer.position(newPosition);
-      } else {
-        writeRawVarint32(encodedLength(value));
-        encode(value, buffer);
-      }
-    } catch (BufferOverflowException e) {
-      final OutOfSpaceException outOfSpaceException = new OutOfSpaceException(buffer.position(),
-          buffer.limit());
-      outOfSpaceException.initCause(e);
-      throw outOfSpaceException;
-    }
-  }
-
-  // These UTF-8 handling methods are copied from Guava's Utf8 class.
-  /**
-   * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
-   * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
-   * both time and space.
-   *
-   * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
-   *     surrogates)
-   */
-  private static int encodedLength(CharSequence sequence) {
-    // Warning to maintainers: this implementation is highly optimized.
-    int utf16Length = sequence.length();
-    int utf8Length = utf16Length;
-    int i = 0;
-
-    // This loop optimizes for pure ASCII.
-    while (i < utf16Length && sequence.charAt(i) < 0x80) {
-      i++;
-    }
-
-    // This loop optimizes for chars less than 0x800.
-    for (; i < utf16Length; i++) {
-      char c = sequence.charAt(i);
-      if (c < 0x800) {
-        utf8Length += ((0x7f - c) >>> 31);  // branch free!
-      } else {
-        utf8Length += encodedLengthGeneral(sequence, i);
-        break;
-      }
-    }
-
-    if (utf8Length < utf16Length) {
-      // Necessary and sufficient condition for overflow because of maximum 3x expansion
-      throw new IllegalArgumentException("UTF-8 length does not fit in int: "
-              + (utf8Length + (1L << 32)));
-    }
-    return utf8Length;
-  }
-
-  private static int encodedLengthGeneral(CharSequence sequence, int start) {
-    int utf16Length = sequence.length();
-    int utf8Length = 0;
-    for (int i = start; i < utf16Length; i++) {
-      char c = sequence.charAt(i);
-      if (c < 0x800) {
-        utf8Length += (0x7f - c) >>> 31; // branch free!
-      } else {
-        utf8Length += 2;
-        // jdk7+: if (Character.isSurrogate(c)) {
-        if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
-          // Check that we have a well-formed surrogate pair.
-          int cp = Character.codePointAt(sequence, i);
-          if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
-            throw new IllegalArgumentException("Unpaired surrogate at index " + i);
-          }
-          i++;
-        }
-      }
-    }
-    return utf8Length;
-  }
-
-  /**
-   * Encodes {@code sequence} into UTF-8, in {@code byteBuffer}. For a string, this method is
-   * equivalent to {@code buffer.put(string.getBytes(UTF_8))}, but is more efficient in both time
-   * and space. Bytes are written starting at the current position. This method requires paired
-   * surrogates, and therefore does not support chunking.
-   *
-   * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
-   * compute the exact amount needed, or leave room for {@code 3 * sequence.length()}, which is the
-   * largest possible number of bytes that any input can be encoded to.
-   *
-   * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
-   *     surrogates)
-   * @throws BufferOverflowException if {@code sequence} encoded in UTF-8 does not fit in
-   *     {@code byteBuffer}'s remaining space.
-   * @throws ReadOnlyBufferException if {@code byteBuffer} is a read-only buffer.
-   */
-  private static void encode(CharSequence sequence, ByteBuffer byteBuffer) {
-    if (byteBuffer.isReadOnly()) {
-      throw new ReadOnlyBufferException();
-    } else if (byteBuffer.hasArray()) {
-      try {
-        int encoded = encode(sequence,
-                byteBuffer.array(),
-                byteBuffer.arrayOffset() + byteBuffer.position(),
-                byteBuffer.remaining());
-        byteBuffer.position(encoded - byteBuffer.arrayOffset());
-      } catch (ArrayIndexOutOfBoundsException e) {
-        BufferOverflowException boe = new BufferOverflowException();
-        boe.initCause(e);
-        throw boe;
-      }
-    } else {
-      encodeDirect(sequence, byteBuffer);
-    }
-  }
-
-  private static void encodeDirect(CharSequence sequence, ByteBuffer byteBuffer) {
-    int utf16Length = sequence.length();
-    for (int i = 0; i < utf16Length; i++) {
-      final char c = sequence.charAt(i);
-      if (c < 0x80) { // ASCII
-        byteBuffer.put((byte) c);
-      } else if (c < 0x800) { // 11 bits, two UTF-8 bytes
-        byteBuffer.put((byte) ((0xF << 6) | (c >>> 6)));
-        byteBuffer.put((byte) (0x80 | (0x3F & c)));
-      } else if (c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) {
-        // Maximium single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
-        byteBuffer.put((byte) ((0xF << 5) | (c >>> 12)));
-        byteBuffer.put((byte) (0x80 | (0x3F & (c >>> 6))));
-        byteBuffer.put((byte) (0x80 | (0x3F & c)));
-      } else {
-        final char low;
-        if (i + 1 == sequence.length()
-                || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
-          throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
-        }
-        int codePoint = Character.toCodePoint(c, low);
-        byteBuffer.put((byte) ((0xF << 4) | (codePoint >>> 18)));
-        byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 12))));
-        byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 6))));
-        byteBuffer.put((byte) (0x80 | (0x3F & codePoint)));
-      }
-    }
-  }
-
-  private static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
-    int utf16Length = sequence.length();
-    int j = offset;
-    int i = 0;
-    int limit = offset + length;
-    // Designed to take advantage of
-    // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
-    for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
-      bytes[j + i] = (byte) c;
-    }
-    if (i == utf16Length) {
-      return j + utf16Length;
-    }
-    j += i;
-    for (char c; i < utf16Length; i++) {
-      c = sequence.charAt(i);
-      if (c < 0x80 && j < limit) {
-        bytes[j++] = (byte) c;
-      } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
-        bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
-        bytes[j++] = (byte) (0x80 | (0x3F & c));
-      } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
-        // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
-        bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
-        bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
-        bytes[j++] = (byte) (0x80 | (0x3F & c));
-      } else if (j <= limit - 4) {
-        // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
-        final char low;
-        if (i + 1 == sequence.length()
-                || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
-          throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
-        }
-        int codePoint = Character.toCodePoint(c, low);
-        bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
-        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
-        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
-        bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
-      } else {
-        // If we are surrogates and we're not a surrogate pair, always throw an
-        // IllegalArgumentException instead of an ArrayOutOfBoundsException.
-        if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
-            && (i + 1 == sequence.length()
-                || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
-          throw new IllegalArgumentException("Unpaired surrogate at index " + i);
-        }
-        throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
-      }
-    }
-    return j;
-  }
-
-  // End guava UTF-8 methods
-
-  /** Write a {@code group} field to the stream. */
-  public void writeGroupNoTag(final MessageNano value) throws IOException {
-    value.writeTo(this);
-  }
-
-  /** Write an embedded message field to the stream. */
-  public void writeMessageNoTag(final MessageNano value) throws IOException {
-    writeRawVarint32(value.getCachedSize());
-    value.writeTo(this);
-  }
-
-  /** Write a {@code bytes} field to the stream. */
-  public void writeBytesNoTag(final byte[] value) throws IOException {
-    writeRawVarint32(value.length);
-    writeRawBytes(value);
-  }
-
-  /** Write a {@code bytes} field to the stream. */
-  public void writeBytesNoTag(final byte[] value, final int offset, final int length)
-                              throws IOException {
-    writeRawVarint32(length);
-    writeRawBytes(value, offset, length);
-  }
-
-  /** Write a {@code uint32} field to the stream. */
-  public void writeUInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(value);
-  }
-
-  /**
-   * Write an enum field to the stream.  Caller is responsible
-   * for converting the enum value to its numeric value.
-   */
-  public void writeEnumNoTag(final int value) throws IOException {
-    writeRawVarint32(value);
-  }
-
-  /** Write an {@code sfixed32} field to the stream. */
-  public void writeSFixed32NoTag(final int value) throws IOException {
-    writeRawLittleEndian32(value);
-  }
-
-  /** Write an {@code sfixed64} field to the stream. */
-  public void writeSFixed64NoTag(final long value) throws IOException {
-    writeRawLittleEndian64(value);
-  }
-
-  /** Write an {@code sint32} field to the stream. */
-  public void writeSInt32NoTag(final int value) throws IOException {
-    writeRawVarint32(encodeZigZag32(value));
-  }
-
-  /** Write an {@code sint64} field to the stream. */
-  public void writeSInt64NoTag(final long value) throws IOException {
-    writeRawVarint64(encodeZigZag64(value));
-  }
-
-  // =================================================================
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSize(final int fieldNumber,
-                                      final double value) {
-    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSize(final int fieldNumber, final float value) {
-    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int32} field, including tag.
-   */
-  public static int computeInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field, including tag.
-   */
-  public static int computeFixed64Size(final int fieldNumber,
-                                       final long value) {
-    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed32} field, including tag.
-   */
-  public static int computeFixed32Size(final int fieldNumber,
-                                       final int value) {
-    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bool} field, including tag.
-   */
-  public static int computeBoolSize(final int fieldNumber,
-                                    final boolean value) {
-    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code string} field, including tag.
-   */
-  public static int computeStringSize(final int fieldNumber,
-                                      final String value) {
-    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field, including tag.
-   */
-  public static int computeGroupSize(final int fieldNumber,
-                                     final MessageNano value) {
-    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * embedded message field, including tag.
-   */
-  public static int computeMessageSize(final int fieldNumber,
-                                       final MessageNano value) {
-    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field, including tag.
-   */
-  public static int computeBytesSize(final int fieldNumber,
-                                     final byte[] value) {
-    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field of the given length, including tag.
-   */
-  public static int computeBytesSize(final int fieldNumber,
-                                     final int length) {
-    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(length);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint32} field, including tag.
-   */
-  public static int computeUInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * enum field, including tag.  Caller is responsible for converting the
-   * enum value to its numeric value.
-   */
-  public static int computeEnumSize(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed32} field, including tag.
-   */
-  public static int computeSFixed32Size(final int fieldNumber,
-                                        final int value) {
-    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field, including tag.
-   */
-  public static int computeSFixed64Size(final int fieldNumber,
-                                        final long value) {
-    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field, including tag.
-   */
-  public static int computeSInt32Size(final int fieldNumber, final int value) {
-    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint64} field, including tag.
-   */
-  public static int computeSInt64Size(final int fieldNumber, final long value) {
-    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * MessageSet extension to the stream.  For historical reasons,
-   * the wire format differs from normal fields.
-   */
-//  public static int computeMessageSetExtensionSize(
-//      final int fieldNumber, final MessageMicro value) {
-//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
-//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
-//           computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
-//  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * unparsed MessageSet extension field to the stream.  For
-   * historical reasons, the wire format differs from normal fields.
-   */
-//  public static int computeRawMessageSetExtensionSize(
-//      final int fieldNumber, final ByteStringMicro value) {
-//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
-//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
-//           computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
-//  }
-
-  // -----------------------------------------------------------------
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code double} field, including tag.
-   */
-  public static int computeDoubleSizeNoTag(final double value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code float} field, including tag.
-   */
-  public static int computeFloatSizeNoTag(final float value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint64} field, including tag.
-   */
-  public static int computeUInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int64} field, including tag.
-   */
-  public static int computeInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code int32} field, including tag.
-   */
-  public static int computeInt32SizeNoTag(final int value) {
-    if (value >= 0) {
-      return computeRawVarint32Size(value);
-    } else {
-      // Must sign-extend.
-      return 10;
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed64} field.
-   */
-  public static int computeFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code fixed32} field.
-   */
-  public static int computeFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bool} field.
-   */
-  public static int computeBoolSizeNoTag(final boolean value) {
-    return 1;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code string} field.
-   */
-  public static int computeStringSizeNoTag(final String value) {
-    final int length = encodedLength(value);
-    return computeRawVarint32Size(length) + length;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field.
-   */
-  public static int computeGroupSizeNoTag(final MessageNano value) {
-    return value.getSerializedSize();
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an embedded
-   * message field.
-   */
-  public static int computeMessageSizeNoTag(final MessageNano value) {
-    final int size = value.getSerializedSize();
-    return computeRawVarint32Size(size) + size;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field.
-   */
-  public static int computeBytesSizeNoTag(final byte[] value) {
-    return computeRawVarint32Size(value.length) + value.length;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code bytes} field of the given length.
-   */
-  public static int computeBytesSizeNoTag(final int length) {
-    return computeRawVarint32Size(length) + length;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code uint32} field.
-   */
-  public static int computeUInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an enum field.
-   * Caller is responsible for converting the enum value to its numeric value.
-   */
-  public static int computeEnumSizeNoTag(final int value) {
-    return computeRawVarint32Size(value);
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed32} field.
-   */
-  public static int computeSFixed32SizeNoTag(final int value) {
-    return LITTLE_ENDIAN_32_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sfixed64} field.
-   */
-  public static int computeSFixed64SizeNoTag(final long value) {
-    return LITTLE_ENDIAN_64_SIZE;
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint32} field.
-   */
-  public static int computeSInt32SizeNoTag(final int value) {
-    return computeRawVarint32Size(encodeZigZag32(value));
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode an
-   * {@code sint64} field.
-   */
-  public static int computeSInt64SizeNoTag(final long value) {
-    return computeRawVarint64Size(encodeZigZag64(value));
-  }
-
-  // =================================================================
-
-  /**
-   * If writing to a flat array, return the space left in the array.
-   * Otherwise, throws {@code UnsupportedOperationException}.
-   */
-  public int spaceLeft() {
-    return buffer.remaining();
-  }
-
-  /**
-   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
-   * a byte array that is exactly big enough to hold a message, then write to
-   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
-   * after writing verifies that the message was actually as big as expected,
-   * which can help catch bugs.
-   */
-  public void checkNoSpaceLeft() {
-    if (spaceLeft() != 0) {
-      throw new IllegalStateException(
-        "Did not write as much data as expected.");
-    }
-  }
-
-  /**
-   * Returns the position within the internal buffer.
-   */
-  public int position() {
-    return buffer.position();
-  }
-
-  /**
-   * Resets the position within the internal buffer to zero.
-   *
-   * @see #position
-   * @see #spaceLeft
-   */
-  public void reset() {
-    buffer.clear();
-  }
-
-  /**
-   * If you create a CodedOutputStream around a simple flat array, you must
-   * not attempt to write more bytes than the array has space.  Otherwise,
-   * this exception will be thrown.
-   */
-  public static class OutOfSpaceException extends IOException {
-    private static final long serialVersionUID = -6947486886997889499L;
-
-    OutOfSpaceException(int position, int limit) {
-      super("CodedOutputStream was writing to a flat byte array and ran " +
-            "out of space (pos " + position + " limit " + limit + ").");
-    }
-  }
-
-  /** Write a single byte. */
-  public void writeRawByte(final byte value) throws IOException {
-    if (!buffer.hasRemaining()) {
-      // We're writing to a single buffer.
-      throw new OutOfSpaceException(buffer.position(), buffer.limit());
-    }
-
-    buffer.put(value);
-  }
-
-  /** Write a single byte, represented by an integer value. */
-  public void writeRawByte(final int value) throws IOException {
-    writeRawByte((byte) value);
-  }
-
-  /** Write an array of bytes. */
-  public void writeRawBytes(final byte[] value) throws IOException {
-    writeRawBytes(value, 0, value.length);
-  }
-
-  /** Write part of an array of bytes. */
-  public void writeRawBytes(final byte[] value, int offset, int length)
-                            throws IOException {
-    if (buffer.remaining() >= length) {
-      buffer.put(value, offset, length);
-    } else {
-      // We're writing to a single buffer.
-      throw new OutOfSpaceException(buffer.position(), buffer.limit());
-    }
-  }
-
-  /** Encode and write a tag. */
-  public void writeTag(final int fieldNumber, final int wireType)
-                       throws IOException {
-    writeRawVarint32(WireFormatNano.makeTag(fieldNumber, wireType));
-  }
-
-  /** Compute the number of bytes that would be needed to encode a tag. */
-  public static int computeTagSize(final int fieldNumber) {
-    return computeRawVarint32Size(WireFormatNano.makeTag(fieldNumber, 0));
-  }
-
-  /**
-   * Encode and write a varint.  {@code value} is treated as
-   * unsigned, so it won't be sign-extended if negative.
-   */
-  public void writeRawVarint32(int value) throws IOException {
-    while (true) {
-      if ((value & ~0x7F) == 0) {
-        writeRawByte(value);
-        return;
-      } else {
-        writeRawByte((value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /**
-   * Compute the number of bytes that would be needed to encode a varint.
-   * {@code value} is treated as unsigned, so it won't be sign-extended if
-   * negative.
-   */
-  public static int computeRawVarint32Size(final int value) {
-    if ((value & (0xffffffff <<  7)) == 0) return 1;
-    if ((value & (0xffffffff << 14)) == 0) return 2;
-    if ((value & (0xffffffff << 21)) == 0) return 3;
-    if ((value & (0xffffffff << 28)) == 0) return 4;
-    return 5;
-  }
-
-  /** Encode and write a varint. */
-  public void writeRawVarint64(long value) throws IOException {
-    while (true) {
-      if ((value & ~0x7FL) == 0) {
-        writeRawByte((int)value);
-        return;
-      } else {
-        writeRawByte(((int)value & 0x7F) | 0x80);
-        value >>>= 7;
-      }
-    }
-  }
-
-  /** Compute the number of bytes that would be needed to encode a varint. */
-  public static int computeRawVarint64Size(final long value) {
-    if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
-    if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
-    if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
-    if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
-    if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
-    if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
-    if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
-    if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
-    if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
-    return 10;
-  }
-
-  /** Write a little-endian 32-bit integer. */
-  public void writeRawLittleEndian32(final int value) throws IOException {
-    if (buffer.remaining() < 4) {
-      throw new OutOfSpaceException(buffer.position(), buffer.limit());
-    }
-    buffer.putInt(value);
-  }
-
-  public static final int LITTLE_ENDIAN_32_SIZE = 4;
-
-  /** Write a little-endian 64-bit integer. */
-  public void writeRawLittleEndian64(final long value) throws IOException {
-    if (buffer.remaining() < 8) {
-      throw new OutOfSpaceException(buffer.position(), buffer.limit());
-    }
-    buffer.putLong(value);
-  }
-
-  public static final int LITTLE_ENDIAN_64_SIZE = 8;
-
-  /**
-   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n A signed 32-bit integer.
-   * @return An unsigned 32-bit integer, stored in a signed int because
-   *         Java has no explicit unsigned support.
-   */
-  public static int encodeZigZag32(final int n) {
-    // Note:  the right-shift must be arithmetic
-    return (n << 1) ^ (n >> 31);
-  }
-
-  /**
-   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
-   * into values that can be efficiently encoded with varint.  (Otherwise,
-   * negative values must be sign-extended to 64 bits to be varint encoded,
-   * thus always taking 10 bytes on the wire.)
-   *
-   * @param n A signed 64-bit integer.
-   * @return An unsigned 64-bit integer, stored in a signed int because
-   *         Java has no explicit unsigned support.
-   */
-  public static long encodeZigZag64(final long n) {
-    // Note:  the right-shift must be arithmetic
-    return (n << 1) ^ (n >> 63);
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
deleted file mode 100644
index 4fe8dce..0000000
--- a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-
-/**
- * Base class of those Protocol Buffer messages that need to store unknown fields,
- * such as extensions.
- */
-public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
-        extends MessageNano {
-    /**
-     * A container for fields unknown to the message, including extensions. Extension fields can
-     * can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
-     */
-    protected FieldArray unknownFieldData;
-
-    @Override
-    protected int computeSerializedSize() {
-        int size = 0;
-        if (unknownFieldData != null) {
-            for (int i = 0; i < unknownFieldData.size(); i++) {
-                FieldData field = unknownFieldData.dataAt(i);
-                size += field.computeSerializedSize();
-            }
-        }
-        return size;
-    }
-
-    @Override
-    public void writeTo(CodedOutputByteBufferNano output) throws IOException {
-        if (unknownFieldData == null) {
-            return;
-        }
-        for (int i = 0; i < unknownFieldData.size(); i++) {
-            FieldData field = unknownFieldData.dataAt(i);
-            field.writeTo(output);
-        }
-    }
-
-    /**
-     * Checks if there is a value stored for the specified extension in this
-     * message.
-     */
-    public final boolean hasExtension(Extension<M, ?> extension) {
-        if (unknownFieldData == null) {
-            return false;
-        }
-        FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
-        return field != null;
-    }
-
-    /**
-     * Gets the value stored in the specified extension of this message.
-     */
-    public final <T> T getExtension(Extension<M, T> extension) {
-        if (unknownFieldData == null) {
-            return null;
-        }
-        FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
-        return field == null ? null : field.getValue(extension);
-    }
-
-    /**
-     * Sets the value of the specified extension of this message.
-     */
-    public final <T> M setExtension(Extension<M, T> extension, T value) {
-        int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag);
-        if (value == null) {
-            if (unknownFieldData != null) {
-                unknownFieldData.remove(fieldNumber);
-                if (unknownFieldData.isEmpty()) {
-                    unknownFieldData = null;
-                }
-            }
-        } else {
-            FieldData field = null;
-            if (unknownFieldData == null) {
-                unknownFieldData = new FieldArray();
-            } else {
-                field = unknownFieldData.get(fieldNumber);
-            }
-            if (field == null) {
-                unknownFieldData.put(fieldNumber, new FieldData(extension, value));
-            } else {
-                field.setValue(extension, value);
-            }
-        }
-
-        @SuppressWarnings("unchecked") // Generated code should guarantee type safety
-        M typedThis = (M) this;
-        return typedThis;
-    }
-
-    /**
-     * Stores the binary data of an unknown field.
-     *
-     * <p>Generated messages will call this for unknown fields if the store_unknown_fields
-     * option is on.
-     *
-     * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
-     * which case we do not want to add an unknown field entry.
-     *
-     * @param input the input buffer.
-     * @param tag the tag of the field.
-
-     * @return {@literal true} unless the tag is an end-group tag.
-     */
-    protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag)
-            throws IOException {
-        int startPos = input.getPosition();
-        if (!input.skipField(tag)) {
-            return false;  // This wasn't an unknown field, it's an end-group tag.
-        }
-        int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
-        int endPos = input.getPosition();
-        byte[] bytes = input.getData(startPos, endPos - startPos);
-        UnknownFieldData unknownField = new UnknownFieldData(tag, bytes);
-
-        FieldData field = null;
-        if (unknownFieldData == null) {
-            unknownFieldData = new FieldArray();
-        } else {
-            field = unknownFieldData.get(fieldNumber);
-        }
-        if (field == null) {
-            field = new FieldData();
-            unknownFieldData.put(fieldNumber, field);
-        }
-        field.addUnknownField(unknownField);
-        return true;
-    }
-
-    @Override
-    public M clone() throws CloneNotSupportedException {
-        M cloned = (M) super.clone();
-        InternalNano.cloneUnknownFieldData(this, cloned);
-        return cloned;
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/Extension.java b/java/src/main/java/com/google/protobuf/nano/Extension.java
deleted file mode 100644
index 6e2202e..0000000
--- a/java/src/main/java/com/google/protobuf/nano/Extension.java
+++ /dev/null
@@ -1,741 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents an extension.
- *
- * @author bduff@google.com (Brian Duff)
- * @author maxtroy@google.com (Max Cai)
- * @param <M> the type of the extendable message this extension is for.
- * @param <T> the Java type of the extension; see {@link #clazz}.
- */
-public class Extension<M extends ExtendableMessageNano<M>, T> {
-
-    /*
-     * Because we typically only define message-typed extensions, the Extension class hierarchy is
-     * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
-     *
-     *            Extension          // ready to use for message/group typed extensions
-     *                Δ
-     *                |
-     *       PrimitiveExtension      // for primitive/enum typed extensions
-     */
-
-    public static final int TYPE_DOUBLE   = 1;
-    public static final int TYPE_FLOAT    = 2;
-    public static final int TYPE_INT64    = 3;
-    public static final int TYPE_UINT64   = 4;
-    public static final int TYPE_INT32    = 5;
-    public static final int TYPE_FIXED64  = 6;
-    public static final int TYPE_FIXED32  = 7;
-    public static final int TYPE_BOOL     = 8;
-    public static final int TYPE_STRING   = 9;
-    public static final int TYPE_GROUP    = 10;
-    public static final int TYPE_MESSAGE  = 11;
-    public static final int TYPE_BYTES    = 12;
-    public static final int TYPE_UINT32   = 13;
-    public static final int TYPE_ENUM     = 14;
-    public static final int TYPE_SFIXED32 = 15;
-    public static final int TYPE_SFIXED64 = 16;
-    public static final int TYPE_SINT32   = 17;
-    public static final int TYPE_SINT64   = 18;
-
-    /**
-     * Creates an {@code Extension} of the given message type and tag number.
-     * Should be used by the generated code only.
-     *
-     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
-     * @deprecated use {@link #createMessageTyped(int, Class, long)} instead.
-     */
-    @Deprecated
-    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
-            Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
-        return new Extension<M, T>(type, clazz, tag, false);
-    }
-
-    // Note: these create...() methods take a long for the tag parameter,
-    // because tags are represented as unsigned ints, and these values exist
-    // in generated code as long values. However, they can fit in 32-bits, so
-    // it's safe to cast them to int without loss of precision.
-
-    /**
-     * Creates an {@code Extension} of the given message type and tag number.
-     * Should be used by the generated code only.
-     *
-     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
-     */
-    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
-            Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) {
-        return new Extension<M, T>(type, clazz, (int) tag, false);
-    }
-
-    /**
-     * Creates a repeated {@code Extension} of the given message type and tag number.
-     * Should be used by the generated code only.
-     *
-     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
-     */
-    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
-            Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) {
-        return new Extension<M, T[]>(type, clazz, (int) tag, true);
-    }
-
-    /**
-     * Creates an {@code Extension} of the given primitive type and tag number.
-     * Should be used by the generated code only.
-     *
-     * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
-     * @param clazz the boxed Java type of this extension
-     */
-    public static <M extends ExtendableMessageNano<M>, T>
-            Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) {
-        return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0);
-    }
-
-    /**
-     * Creates a repeated {@code Extension} of the given primitive type and tag number.
-     * Should be used by the generated code only.
-     *
-     * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
-     * @param clazz the Java array type of this extension, with an unboxed component type
-     */
-    public static <M extends ExtendableMessageNano<M>, T>
-            Extension<M, T> createRepeatedPrimitiveTyped(
-                    int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) {
-        return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true,
-            (int) nonPackedTag, (int) packedTag);
-    }
-
-    /**
-     * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
-     */
-    protected final int type;
-
-    /**
-     * Java type of this extension. For a singular extension, this is the boxed Java type for the
-     * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
-     * component type is the unboxed Java type for {@link #type}. For example, for a singular
-     * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
-     * repeated {@code int32} extension, this equals {@code int[].class}.
-     */
-    protected final Class<T> clazz;
-
-    /**
-     * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
-     */
-    public final int tag;
-
-    /**
-     * Whether this extension is repeated.
-     */
-    protected final boolean repeated;
-
-    private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
-        this.type = type;
-        this.clazz = clazz;
-        this.tag = tag;
-        this.repeated = repeated;
-    }
-
-    /**
-     * Returns the value of this extension stored in the given list of unknown fields, or
-     * {@code null} if no unknown fields matches this extension.
-     *
-     * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
-     *                      that matches this Extension's tag.
-     *
-     */
-    final T getValueFrom(List<UnknownFieldData> unknownFields) {
-        if (unknownFields == null) {
-            return null;
-        }
-        return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
-    }
-
-    private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
-        // For repeated extensions, read all matching unknown fields in their original order.
-        List<Object> resultList = new ArrayList<Object>();
-        for (int i = 0; i < unknownFields.size(); i++) {
-            UnknownFieldData data = unknownFields.get(i);
-            if (data.bytes.length != 0) {
-                readDataInto(data, resultList);
-            }
-        }
-
-        int resultSize = resultList.size();
-        if (resultSize == 0) {
-            return null;
-        } else {
-            T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
-            for (int i = 0; i < resultSize; i++) {
-                Array.set(result, i, resultList.get(i));
-            }
-            return result;
-        }
-    }
-
-    private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
-        // For singular extensions, get the last piece of data stored under this extension.
-        if (unknownFields.isEmpty()) {
-            return null;
-        }
-        UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
-        return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
-    }
-
-    protected Object readData(CodedInputByteBufferNano input) {
-        // This implementation is for message/group extensions.
-        Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
-        try {
-            switch (type) {
-                case TYPE_GROUP:
-                    MessageNano group = (MessageNano) messageType.newInstance();
-                    input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
-                    return group;
-                case TYPE_MESSAGE:
-                    MessageNano message = (MessageNano) messageType.newInstance();
-                    input.readMessage(message);
-                    return message;
-                default:
-                    throw new IllegalArgumentException("Unknown type " + type);
-            }
-        } catch (InstantiationException e) {
-            throw new IllegalArgumentException(
-                    "Error creating instance of class " + messageType, e);
-        } catch (IllegalAccessException e) {
-            throw new IllegalArgumentException(
-                    "Error creating instance of class " + messageType, e);
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Error reading extension field", e);
-        }
-    }
-
-    protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
-        // This implementation is for message/group extensions.
-        resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
-    }
-
-    void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
-        if (repeated) {
-            writeRepeatedData(value, output);
-        } else {
-            writeSingularData(value, output);
-        }
-    }
-
-    protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
-        // This implementation is for message/group extensions.
-        try {
-            out.writeRawVarint32(tag);
-            switch (type) {
-                case TYPE_GROUP:
-                    MessageNano groupValue = (MessageNano) value;
-                    int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
-                    out.writeGroupNoTag(groupValue);
-                    // The endgroup tag must be included in the data payload.
-                    out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
-                    break;
-                case TYPE_MESSAGE:
-                    MessageNano messageValue = (MessageNano) value;
-                    out.writeMessageNoTag(messageValue);
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unknown type " + type);
-            }
-        } catch (IOException e) {
-            // Should not happen
-            throw new IllegalStateException(e);
-        }
-    }
-
-    protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
-        // This implementation is for non-packed extensions.
-        int arrayLength = Array.getLength(array);
-        for (int i = 0; i < arrayLength; i++) {
-            Object element = Array.get(array, i);
-            if (element != null) {
-                writeSingularData(element, output);
-            }
-        }
-    }
-
-    int computeSerializedSize(Object value) {
-        if (repeated) {
-            return computeRepeatedSerializedSize(value);
-        } else {
-            return computeSingularSerializedSize(value);
-        }
-    }
-
-    protected int computeRepeatedSerializedSize(Object array) {
-        // This implementation is for non-packed extensions.
-        int size = 0;
-        int arrayLength = Array.getLength(array);
-        for (int i = 0; i < arrayLength; i++) {
-            Object element = Array.get(array, i);
-            if (element != null) {
-                size += computeSingularSerializedSize(Array.get(array, i));
-            }
-        }
-        return size;
-    }
-
-    protected int computeSingularSerializedSize(Object value) {
-        // This implementation is for message/group extensions.
-        int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
-        switch (type) {
-            case TYPE_GROUP:
-                MessageNano groupValue = (MessageNano) value;
-                return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
-            case TYPE_MESSAGE:
-                MessageNano messageValue = (MessageNano) value;
-                return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
-            default:
-                throw new IllegalArgumentException("Unknown type " + type);
-        }
-    }
-
-    /**
-     * Represents an extension of a primitive (including enum) type. If there is no primitive
-     * extensions, this subclass will be removable by ProGuard.
-     */
-    private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
-            extends Extension<M, T> {
-
-        /**
-         * Tag of a piece of non-packed data from the wire compatible with this extension.
-         */
-        private final int nonPackedTag;
-
-        /**
-         * Tag of a piece of packed data from the wire compatible with this extension.
-         * 0 if the type of this extension is not packable.
-         */
-        private final int packedTag;
-
-        public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
-                int nonPackedTag, int packedTag) {
-            super(type, clazz, tag, repeated);
-            this.nonPackedTag = nonPackedTag;
-            this.packedTag = packedTag;
-        }
-
-        @Override
-        protected Object readData(CodedInputByteBufferNano input) {
-            try {
-                switch (type) {
-                    case TYPE_DOUBLE:
-                        return input.readDouble();
-                    case TYPE_FLOAT:
-                        return input.readFloat();
-                    case TYPE_INT64:
-                        return input.readInt64();
-                    case TYPE_UINT64:
-                        return input.readUInt64();
-                    case TYPE_INT32:
-                        return input.readInt32();
-                    case TYPE_FIXED64:
-                        return input.readFixed64();
-                    case TYPE_FIXED32:
-                        return input.readFixed32();
-                    case TYPE_BOOL:
-                        return input.readBool();
-                    case TYPE_STRING:
-                        return input.readString();
-                    case TYPE_BYTES:
-                        return input.readBytes();
-                    case TYPE_UINT32:
-                        return input.readUInt32();
-                    case TYPE_ENUM:
-                        return input.readEnum();
-                    case TYPE_SFIXED32:
-                        return input.readSFixed32();
-                    case TYPE_SFIXED64:
-                        return input.readSFixed64();
-                    case TYPE_SINT32:
-                        return input.readSInt32();
-                    case TYPE_SINT64:
-                        return input.readSInt64();
-                    default:
-                        throw new IllegalArgumentException("Unknown type " + type);
-                }
-            } catch (IOException e) {
-                throw new IllegalArgumentException("Error reading extension field", e);
-            }
-        }
-
-        @Override
-        protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
-            // This implementation is for primitive typed extensions,
-            // which can read both packed and non-packed data.
-            if (data.tag == nonPackedTag) {
-                resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
-            } else {
-                CodedInputByteBufferNano buffer =
-                        CodedInputByteBufferNano.newInstance(data.bytes);
-                try {
-                    buffer.pushLimit(buffer.readRawVarint32()); // length limit
-                } catch (IOException e) {
-                    throw new IllegalArgumentException("Error reading extension field", e);
-                }
-                while (!buffer.isAtEnd()) {
-                    resultList.add(readData(buffer));
-                }
-            }
-        }
-
-        @Override
-        protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
-            try {
-                output.writeRawVarint32(tag);
-                switch (type) {
-                    case TYPE_DOUBLE:
-                        Double doubleValue = (Double) value;
-                        output.writeDoubleNoTag(doubleValue);
-                        break;
-                    case TYPE_FLOAT:
-                        Float floatValue = (Float) value;
-                        output.writeFloatNoTag(floatValue);
-                        break;
-                    case TYPE_INT64:
-                        Long int64Value = (Long) value;
-                        output.writeInt64NoTag(int64Value);
-                        break;
-                    case TYPE_UINT64:
-                        Long uint64Value = (Long) value;
-                        output.writeUInt64NoTag(uint64Value);
-                        break;
-                    case TYPE_INT32:
-                        Integer int32Value = (Integer) value;
-                        output.writeInt32NoTag(int32Value);
-                        break;
-                    case TYPE_FIXED64:
-                        Long fixed64Value = (Long) value;
-                        output.writeFixed64NoTag(fixed64Value);
-                        break;
-                    case TYPE_FIXED32:
-                        Integer fixed32Value = (Integer) value;
-                        output.writeFixed32NoTag(fixed32Value);
-                        break;
-                    case TYPE_BOOL:
-                        Boolean boolValue = (Boolean) value;
-                        output.writeBoolNoTag(boolValue);
-                        break;
-                    case TYPE_STRING:
-                        String stringValue = (String) value;
-                        output.writeStringNoTag(stringValue);
-                        break;
-                    case TYPE_BYTES:
-                        byte[] bytesValue = (byte[]) value;
-                        output.writeBytesNoTag(bytesValue);
-                        break;
-                    case TYPE_UINT32:
-                        Integer uint32Value = (Integer) value;
-                        output.writeUInt32NoTag(uint32Value);
-                        break;
-                    case TYPE_ENUM:
-                        Integer enumValue = (Integer) value;
-                        output.writeEnumNoTag(enumValue);
-                        break;
-                    case TYPE_SFIXED32:
-                        Integer sfixed32Value = (Integer) value;
-                        output.writeSFixed32NoTag(sfixed32Value);
-                        break;
-                    case TYPE_SFIXED64:
-                        Long sfixed64Value = (Long) value;
-                        output.writeSFixed64NoTag(sfixed64Value);
-                        break;
-                    case TYPE_SINT32:
-                        Integer sint32Value = (Integer) value;
-                        output.writeSInt32NoTag(sint32Value);
-                        break;
-                    case TYPE_SINT64:
-                        Long sint64Value = (Long) value;
-                        output.writeSInt64NoTag(sint64Value);
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Unknown type " + type);
-                }
-            } catch (IOException e) {
-                // Should not happen
-                throw new IllegalStateException(e);
-            }
-        }
-
-        @Override
-        protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
-            if (tag == nonPackedTag) {
-                // Use base implementation for non-packed data
-                super.writeRepeatedData(array, output);
-            } else if (tag == packedTag) {
-                // Packed. Note that the array element type is guaranteed to be primitive, so there
-                // won't be any null elements, so no null check in this block.
-                int arrayLength = Array.getLength(array);
-                int dataSize = computePackedDataSize(array);
-
-                try {
-                    output.writeRawVarint32(tag);
-                    output.writeRawVarint32(dataSize);
-                    switch (type) {
-                        case TYPE_BOOL:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeBoolNoTag(Array.getBoolean(array, i));
-                            }
-                            break;
-                        case TYPE_FIXED32:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeFixed32NoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        case TYPE_SFIXED32:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeSFixed32NoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        case TYPE_FLOAT:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeFloatNoTag(Array.getFloat(array, i));
-                            }
-                            break;
-                        case TYPE_FIXED64:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeFixed64NoTag(Array.getLong(array, i));
-                            }
-                            break;
-                        case TYPE_SFIXED64:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeSFixed64NoTag(Array.getLong(array, i));
-                            }
-                            break;
-                        case TYPE_DOUBLE:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeDoubleNoTag(Array.getDouble(array, i));
-                            }
-                            break;
-                        case TYPE_INT32:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeInt32NoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        case TYPE_SINT32:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeSInt32NoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        case TYPE_UINT32:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeUInt32NoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        case TYPE_INT64:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeInt64NoTag(Array.getLong(array, i));
-                            }
-                            break;
-                        case TYPE_SINT64:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeSInt64NoTag(Array.getLong(array, i));
-                            }
-                            break;
-                        case TYPE_UINT64:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeUInt64NoTag(Array.getLong(array, i));
-                            }
-                            break;
-                        case TYPE_ENUM:
-                            for (int i = 0; i < arrayLength; i++) {
-                                output.writeEnumNoTag(Array.getInt(array, i));
-                            }
-                            break;
-                        default:
-                            throw new IllegalArgumentException("Unpackable type " + type);
-                    }
-                } catch (IOException e) {
-                    // Should not happen.
-                    throw new IllegalStateException(e);
-                }
-            } else {
-                throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
-                        + ", unequal to both non-packed variant " + nonPackedTag
-                        + " and packed variant " + packedTag);
-            }
-        }
-
-        private int computePackedDataSize(Object array) {
-            int dataSize = 0;
-            int arrayLength = Array.getLength(array);
-            switch (type) {
-                case TYPE_BOOL:
-                    // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
-                    dataSize = arrayLength;
-                    break;
-                case TYPE_FIXED32:
-                case TYPE_SFIXED32:
-                case TYPE_FLOAT:
-                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
-                    break;
-                case TYPE_FIXED64:
-                case TYPE_SFIXED64:
-                case TYPE_DOUBLE:
-                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
-                    break;
-                case TYPE_INT32:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
-                                Array.getInt(array, i));
-                    }
-                    break;
-                case TYPE_SINT32:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
-                                Array.getInt(array, i));
-                    }
-                    break;
-                case TYPE_UINT32:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
-                                Array.getInt(array, i));
-                    }
-                    break;
-                case TYPE_INT64:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
-                                Array.getLong(array, i));
-                    }
-                    break;
-                case TYPE_SINT64:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
-                                Array.getLong(array, i));
-                    }
-                    break;
-                case TYPE_UINT64:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
-                                Array.getLong(array, i));
-                    }
-                    break;
-                case TYPE_ENUM:
-                    for (int i = 0; i < arrayLength; i++) {
-                        dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
-                                Array.getInt(array, i));
-                    }
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unexpected non-packable type " + type);
-            }
-            return dataSize;
-        }
-
-        @Override
-        protected int computeRepeatedSerializedSize(Object array) {
-            if (tag == nonPackedTag) {
-                // Use base implementation for non-packed data
-                return super.computeRepeatedSerializedSize(array);
-            } else if (tag == packedTag) {
-                // Packed.
-                int dataSize = computePackedDataSize(array);
-                int payloadSize =
-                        dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
-                return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
-            } else {
-                throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
-                        + ", unequal to both non-packed variant " + nonPackedTag
-                        + " and packed variant " + packedTag);
-            }
-        }
-
-        @Override
-        protected final int computeSingularSerializedSize(Object value) {
-            int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
-            switch (type) {
-                case TYPE_DOUBLE:
-                    Double doubleValue = (Double) value;
-                    return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
-                case TYPE_FLOAT:
-                    Float floatValue = (Float) value;
-                    return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
-                case TYPE_INT64:
-                    Long int64Value = (Long) value;
-                    return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
-                case TYPE_UINT64:
-                    Long uint64Value = (Long) value;
-                    return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
-                case TYPE_INT32:
-                    Integer int32Value = (Integer) value;
-                    return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
-                case TYPE_FIXED64:
-                    Long fixed64Value = (Long) value;
-                    return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
-                case TYPE_FIXED32:
-                    Integer fixed32Value = (Integer) value;
-                    return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
-                case TYPE_BOOL:
-                    Boolean boolValue = (Boolean) value;
-                    return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
-                case TYPE_STRING:
-                    String stringValue = (String) value;
-                    return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
-                case TYPE_BYTES:
-                    byte[] bytesValue = (byte[]) value;
-                    return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
-                case TYPE_UINT32:
-                    Integer uint32Value = (Integer) value;
-                    return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
-                case TYPE_ENUM:
-                    Integer enumValue = (Integer) value;
-                    return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
-                case TYPE_SFIXED32:
-                    Integer sfixed32Value = (Integer) value;
-                    return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
-                            sfixed32Value);
-                case TYPE_SFIXED64:
-                    Long sfixed64Value = (Long) value;
-                    return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
-                            sfixed64Value);
-                case TYPE_SINT32:
-                    Integer sint32Value = (Integer) value;
-                    return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
-                case TYPE_SINT64:
-                    Long sint64Value = (Long) value;
-                    return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
-                default:
-                    throw new IllegalArgumentException("Unknown type " + type);
-            }
-        }
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/FieldArray.java b/java/src/main/java/com/google/protobuf/nano/FieldArray.java
deleted file mode 100644
index 5e8856d..0000000
--- a/java/src/main/java/com/google/protobuf/nano/FieldArray.java
+++ /dev/null
@@ -1,291 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2014 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-
-/**
- * A custom version of {@link android.util.SparseArray} with the minimal API
- * for storing {@link FieldData} objects.
- *
- * <p>This class is an internal implementation detail of nano and should not
- * be called directly by clients.
- *
- * Based on {@link android.support.v4.util.SpareArrayCompat}.
- */
-public final class FieldArray implements Cloneable {
-    private static final FieldData DELETED = new FieldData();
-    private boolean mGarbage = false;
-
-    private int[] mFieldNumbers;
-    private FieldData[] mData;
-    private int mSize;
-
-    /**
-     * Creates a new FieldArray containing no fields.
-     */
-    FieldArray() {
-        this(10);
-    }
-
-    /**
-     * Creates a new FieldArray containing no mappings that will not
-     * require any additional memory allocation to store the specified
-     * number of mappings.
-     */
-    FieldArray(int initialCapacity) {
-        initialCapacity = idealIntArraySize(initialCapacity);
-        mFieldNumbers = new int[initialCapacity];
-        mData = new FieldData[initialCapacity];
-        mSize = 0;
-    }
-
-    /**
-     * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
-     * if no such mapping has been made.
-     */
-    FieldData get(int fieldNumber) {
-        int i = binarySearch(fieldNumber);
-
-        if (i < 0 || mData[i] == DELETED) {
-            return null;
-        } else {
-            return mData[i];
-        }
-    }
-
-    /**
-     * Removes the data from the specified fieldNumber, if there was any.
-     */
-    void remove(int fieldNumber) {
-        int i = binarySearch(fieldNumber);
-
-        if (i >= 0 && mData[i] != DELETED) {
-            mData[i] = DELETED;
-            mGarbage = true;
-        }
-    }
-
-    private void gc() {
-        int n = mSize;
-        int o = 0;
-        int[] keys = mFieldNumbers;
-        FieldData[] values = mData;
-
-        for (int i = 0; i < n; i++) {
-            FieldData val = values[i];
-
-            if (val != DELETED) {
-                if (i != o) {
-                    keys[o] = keys[i];
-                    values[o] = val;
-                    values[i] = null;
-                }
-
-                o++;
-            }
-        }
-
-        mGarbage = false;
-        mSize = o;
-    }
-
-    /**
-     * Adds a mapping from the specified fieldNumber to the specified data,
-     * replacing the previous mapping if there was one.
-     */
-    void put(int fieldNumber, FieldData data) {
-        int i = binarySearch(fieldNumber);
-
-        if (i >= 0) {
-            mData[i] = data;
-        } else {
-            i = ~i;
-
-            if (i < mSize && mData[i] == DELETED) {
-                mFieldNumbers[i] = fieldNumber;
-                mData[i] = data;
-                return;
-            }
-
-            if (mGarbage && mSize >= mFieldNumbers.length) {
-                gc();
-
-                // Search again because indices may have changed.
-                i = ~ binarySearch(fieldNumber);
-            }
-
-            if (mSize >= mFieldNumbers.length) {
-                int n = idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                FieldData[] nvalues = new FieldData[n];
-
-                System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
-                System.arraycopy(mData, 0, nvalues, 0, mData.length);
-
-                mFieldNumbers = nkeys;
-                mData = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
-                System.arraycopy(mData, i, mData, i + 1, mSize - i);
-            }
-
-            mFieldNumbers[i] = fieldNumber;
-            mData[i] = data;
-            mSize++;
-        }
-    }
-
-    /**
-     * Returns the number of key-value mappings that this FieldArray
-     * currently stores.
-     */
-    int size() {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mSize;
-    }
-
-    public boolean isEmpty() {
-        return size() == 0;
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the value from the <code>index</code>th key-value mapping that this
-     * FieldArray stores.
-     */
-    FieldData dataAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mData[index];
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (!(o instanceof FieldArray)) {
-            return false;
-        }
-
-        FieldArray other = (FieldArray) o;
-        if (size() != other.size()) {  // size() will call gc() if necessary.
-            return false;
-        }
-        return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
-                arrayEquals(mData, other.mData, mSize);
-    }
-
-    @Override
-    public int hashCode() {
-        if (mGarbage) {
-            gc();
-        }
-        int result = 17;
-        for (int i = 0; i < mSize; i++) {
-            result = 31 * result + mFieldNumbers[i];
-            result = 31 * result + mData[i].hashCode();
-        }
-        return result;
-    }
-
-    private int idealIntArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
-    }
-
-    private int idealByteArraySize(int need) {
-        for (int i = 4; i < 32; i++)
-            if (need <= (1 << i) - 12)
-                return (1 << i) - 12;
-
-        return need;
-    }
-
-    private int binarySearch(int value) {
-        int lo = 0;
-        int hi = mSize - 1;
-
-        while (lo <= hi) {
-            int mid = (lo + hi) >>> 1;
-            int midVal = mFieldNumbers[mid];
-
-            if (midVal < value) {
-                lo = mid + 1;
-            } else if (midVal > value) {
-                hi = mid - 1;
-            } else {
-                return mid; // value found
-            }
-        }
-        return ~lo; // value not present
-    }
-
-    private boolean arrayEquals(int[] a, int[] b, int size) {
-        for (int i = 0; i < size; i++) {
-            if (a[i] != b[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
-        for (int i = 0; i < size; i++) {
-            if (!a[i].equals(b[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public final FieldArray clone() {
-        // Trigger GC so we compact and don't copy DELETED elements.
-        int size = size();
-        FieldArray clone = new FieldArray(size);
-        System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size);
-        for (int i = 0; i < size; i++) {
-            if (mData[i] != null) {
-                clone.mData[i] = mData[i].clone();
-            }
-        }
-        clone.mSize = size;
-        return clone;
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/FieldData.java b/java/src/main/java/com/google/protobuf/nano/FieldData.java
deleted file mode 100644
index 20a5142..0000000
--- a/java/src/main/java/com/google/protobuf/nano/FieldData.java
+++ /dev/null
@@ -1,240 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2014 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Stores unknown fields. These might be extensions or fields that the generated API doesn't
- * know about yet.
- */
-class FieldData implements Cloneable {
-    private Extension<?, ?> cachedExtension;
-    private Object value;
-    /** The serialised values for this object. Will be cleared if getValue is called */
-    private List<UnknownFieldData> unknownFieldData;
-
-    <T> FieldData(Extension<?, T> extension, T newValue) {
-        cachedExtension = extension;
-        value = newValue;
-    }
-
-    FieldData() {
-        unknownFieldData = new ArrayList<UnknownFieldData>();
-    }
-
-    void addUnknownField(UnknownFieldData unknownField) {
-        unknownFieldData.add(unknownField);
-    }
-
-    UnknownFieldData getUnknownField(int index) {
-        if (unknownFieldData == null) {
-            return null;
-        }
-        if (index < unknownFieldData.size()) {
-            return unknownFieldData.get(index);
-        }
-        return null;
-    }
-
-    int getUnknownFieldSize() {
-        if (unknownFieldData == null) {
-            return 0;
-        }
-        return unknownFieldData.size();
-    }
-
-    <T> T getValue(Extension<?, T> extension) {
-        if (value != null){
-            if (cachedExtension != extension) {  // Extension objects are singletons.
-                throw new IllegalStateException(
-                        "Tried to getExtension with a differernt Extension.");
-            }
-        } else {
-            cachedExtension = extension;
-            value = extension.getValueFrom(unknownFieldData);
-            unknownFieldData = null;
-        }
-        return (T) value;
-    }
-
-    <T> void setValue(Extension<?, T> extension, T newValue) {
-        cachedExtension = extension;
-        value = newValue;
-        unknownFieldData = null;
-    }
-
-    int computeSerializedSize() {
-        int size = 0;
-        if (value != null) {
-            size = cachedExtension.computeSerializedSize(value);
-        } else {
-            for (UnknownFieldData unknownField : unknownFieldData) {
-                size += unknownField.computeSerializedSize();
-            }
-        }
-        return size;
-    }
-
-    void writeTo(CodedOutputByteBufferNano output) throws IOException {
-        if (value != null) {
-            cachedExtension.writeTo(value, output);
-        } else {
-            for (UnknownFieldData unknownField : unknownFieldData) {
-                unknownField.writeTo(output);
-            }
-        }
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (!(o instanceof FieldData)) {
-            return false;
-        }
-
-        FieldData other = (FieldData) o;
-        if (value != null && other.value != null) {
-            // If both objects have deserialized values, compare those.
-            // Since unknown fields are only compared if messages have generated equals methods
-            // we know this will be a meaningful comparison (not identity) for all values.
-            if (cachedExtension != other.cachedExtension) {  // Extension objects are singletons.
-                return false;
-            }
-            if (!cachedExtension.clazz.isArray()) {
-                // Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]'
-                return value.equals(other.value);
-            }
-            if (value instanceof byte[]) {
-                return Arrays.equals((byte[]) value, (byte[]) other.value);
-            } else if (value instanceof int[]) {
-                return Arrays.equals((int[]) value, (int[]) other.value);
-            } else if (value instanceof long[]) {
-                return Arrays.equals((long[]) value, (long[]) other.value);
-            } else if (value instanceof float[]) {
-                return Arrays.equals((float[]) value, (float[]) other.value);
-            } else if (value instanceof double[]) {
-                return Arrays.equals((double[]) value, (double[]) other.value);
-            } else if (value instanceof boolean[]) {
-                return Arrays.equals((boolean[]) value, (boolean[]) other.value);
-            } else {
-                return Arrays.deepEquals((Object[]) value, (Object[]) other.value);
-            }
-        }
-        if (unknownFieldData != null && other.unknownFieldData != null) {
-            // If both objects have byte arrays compare those directly.
-            return unknownFieldData.equals(other.unknownFieldData);
-        }
-        try {
-            // As a last resort, serialize and compare the resulting byte arrays.
-            return Arrays.equals(toByteArray(), other.toByteArray());
-        } catch (IOException e) {
-            // Should not happen.
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        try {
-            // The only way to generate a consistent hash is to use the serialized form.
-            result = 31 * result + Arrays.hashCode(toByteArray());
-        } catch (IOException e) {
-            // Should not happen.
-            throw new IllegalStateException(e);
-        }
-        return result;
-    }
-
-    private byte[] toByteArray() throws IOException {
-        byte[] result = new byte[computeSerializedSize()];
-        CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(result);
-        writeTo(output);
-        return result;
-    }
-
-    @Override
-    public final FieldData clone() {
-        FieldData clone = new FieldData();
-        try {
-            clone.cachedExtension = cachedExtension;
-            if (unknownFieldData == null) {
-                clone.unknownFieldData = null;
-            } else {
-                clone.unknownFieldData.addAll(unknownFieldData);
-            }
-
-            // Whether we need to deep clone value depends on its type. Primitive reference types
-            // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays
-            // and messages.
-            if (value == null) {
-                // No cloning required.
-            } else if (value instanceof MessageNano) {
-                clone.value = ((MessageNano) value).clone();
-            } else if (value instanceof byte[]) {
-                clone.value = ((byte[]) value).clone();
-            } else if (value instanceof byte[][]) {
-                byte[][] valueArray = (byte[][]) value;
-                byte[][] cloneArray = new byte[valueArray.length][];
-                clone.value = cloneArray;
-                for (int i = 0; i < valueArray.length; i++) {
-                    cloneArray[i] = valueArray[i].clone();
-                }
-            } else if (value instanceof boolean[]) {
-                clone.value = ((boolean[]) value).clone();
-            } else if (value instanceof int[]) {
-                clone.value = ((int[]) value).clone();
-            } else if (value instanceof long[]) {
-                clone.value = ((long[]) value).clone();
-            } else if (value instanceof float[]) {
-                clone.value = ((float[]) value).clone();
-            } else if (value instanceof double[]) {
-                clone.value = ((double[]) value).clone();
-            } else if (value instanceof MessageNano[]) {
-                MessageNano[] valueArray = (MessageNano[]) value;
-                MessageNano[] cloneArray = new MessageNano[valueArray.length];
-                clone.value = cloneArray;
-                for (int i = 0; i < valueArray.length; i++) {
-                    cloneArray[i] = valueArray[i].clone();
-                }
-            }
-            return clone;
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError(e);
-        }
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/InternalNano.java b/java/src/main/java/com/google/protobuf/nano/InternalNano.java
deleted file mode 100644
index c4adfa5..0000000
--- a/java/src/main/java/com/google/protobuf/nano/InternalNano.java
+++ /dev/null
@@ -1,341 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-
-/**
- * The classes contained within are used internally by the Protocol Buffer
- * library and generated message implementations. They are public only because
- * those generated messages do not reside in the {@code protobuf} package.
- * Others should not use this class directly.
- *
- * @author kenton@google.com (Kenton Varda)
- */
-public final class InternalNano {
-
-  private InternalNano() {}
-
-  /**
-   * An object to provide synchronization when lazily initializing static fields
-   * of {@link MessageNano} subclasses.
-   * <p>
-   * To enable earlier versions of ProGuard to inline short methods from a
-   * generated MessageNano subclass to the call sites, that class must not have
-   * a class initializer, which will be created if there is any static variable
-   * initializers. To lazily initialize the static variables in a thread-safe
-   * manner, the initialization code will synchronize on this object.
-   */
-  public static final Object LAZY_INIT_LOCK = new Object();
-
-  /**
-   * Helper called by generated code to construct default values for string
-   * fields.
-   * <p>
-   * The protocol compiler does not actually contain a UTF-8 decoder -- it
-   * just pushes UTF-8-encoded text around without touching it.  The one place
-   * where this presents a problem is when generating Java string literals.
-   * Unicode characters in the string literal would normally need to be encoded
-   * using a Unicode escape sequence, which would require decoding them.
-   * To get around this, protoc instead embeds the UTF-8 bytes into the
-   * generated code and leaves it to the runtime library to decode them.
-   * <p>
-   * It gets worse, though.  If protoc just generated a byte array, like:
-   *   new byte[] {0x12, 0x34, 0x56, 0x78}
-   * Java actually generates *code* which allocates an array and then fills
-   * in each value.  This is much less efficient than just embedding the bytes
-   * directly into the bytecode.  To get around this, we need another
-   * work-around.  String literals are embedded directly, so protoc actually
-   * generates a string literal corresponding to the bytes.  The easiest way
-   * to do this is to use the ISO-8859-1 character set, which corresponds to
-   * the first 256 characters of the Unicode range.  Protoc can then use
-   * good old CEscape to generate the string.
-   * <p>
-   * So we have a string literal which represents a set of bytes which
-   * represents another string.  This function -- stringDefaultValue --
-   * converts from the generated string to the string we actually want.  The
-   * generated code calls this automatically.
-   */
-  public static String stringDefaultValue(String bytes) {
-    try {
-      return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      // This should never happen since all JVMs are required to implement
-      // both of the above character sets.
-      throw new IllegalStateException(
-          "Java VM does not support a standard character set.", e);
-    }
-  }
-
-  /**
-   * Helper called by generated code to construct default values for bytes
-   * fields.
-   * <p>
-   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
-   * In this case we only need the second of the two hacks -- allowing us to
-   * embed raw bytes as a string literal with ISO-8859-1 encoding.
-   */
-  public static byte[] bytesDefaultValue(String bytes) {
-    try {
-      return bytes.getBytes("ISO-8859-1");
-    } catch (UnsupportedEncodingException e) {
-      // This should never happen since all JVMs are required to implement
-      // ISO-8859-1.
-      throw new IllegalStateException(
-          "Java VM does not support a standard character set.", e);
-    }
-  }
-
-  /**
-   * Helper function to convert a string into UTF-8 while turning the
-   * UnsupportedEncodingException to a RuntimeException.
-   */
-  public static byte[] copyFromUtf8(final String text) {
-    try {
-      return text.getBytes("UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported?");
-    }
-  }
-
-  /**
-   * Checks repeated int field equality; null-value and 0-length fields are
-   * considered equal.
-   */
-  public static boolean equals(int[] field1, int[] field2) {
-    if (field1 == null || field1.length == 0) {
-      return field2 == null || field2.length == 0;
-    } else {
-      return Arrays.equals(field1, field2);
-    }
-  }
-
-  /**
-   * Checks repeated long field equality; null-value and 0-length fields are
-   * considered equal.
-   */
-  public static boolean equals(long[] field1, long[] field2) {
-    if (field1 == null || field1.length == 0) {
-      return field2 == null || field2.length == 0;
-    } else {
-      return Arrays.equals(field1, field2);
-    }
-  }
-
-  /**
-   * Checks repeated float field equality; null-value and 0-length fields are
-   * considered equal.
-   */
-  public static boolean equals(float[] field1, float[] field2) {
-    if (field1 == null || field1.length == 0) {
-      return field2 == null || field2.length == 0;
-    } else {
-      return Arrays.equals(field1, field2);
-    }
-  }
-
-  /**
-   * Checks repeated double field equality; null-value and 0-length fields are
-   * considered equal.
-   */
-  public static boolean equals(double[] field1, double[] field2) {
-    if (field1 == null || field1.length == 0) {
-      return field2 == null || field2.length == 0;
-    } else {
-      return Arrays.equals(field1, field2);
-    }
-  }
-
-  /**
-   * Checks repeated boolean field equality; null-value and 0-length fields are
-   * considered equal.
-   */
-  public static boolean equals(boolean[] field1, boolean[] field2) {
-    if (field1 == null || field1.length == 0) {
-      return field2 == null || field2.length == 0;
-    } else {
-      return Arrays.equals(field1, field2);
-    }
-  }
-
-  /**
-   * Checks repeated bytes field equality. Only non-null elements are tested.
-   * Returns true if the two fields have the same sequence of non-null
-   * elements. Null-value fields and fields of any length with only null
-   * elements are considered equal.
-   */
-  public static boolean equals(byte[][] field1, byte[][] field2) {
-    int index1 = 0;
-    int length1 = field1 == null ? 0 : field1.length;
-    int index2 = 0;
-    int length2 = field2 == null ? 0 : field2.length;
-    while (true) {
-      while (index1 < length1 && field1[index1] == null) {
-        index1++;
-      }
-      while (index2 < length2 && field2[index2] == null) {
-        index2++;
-      }
-      boolean atEndOf1 = index1 >= length1;
-      boolean atEndOf2 = index2 >= length2;
-      if (atEndOf1 && atEndOf2) {
-        // no more non-null elements to test in both arrays
-        return true;
-      } else if (atEndOf1 != atEndOf2) {
-        // one of the arrays have extra non-null elements
-        return false;
-      } else if (!Arrays.equals(field1[index1], field2[index2])) {
-        // element mismatch
-        return false;
-      }
-      index1++;
-      index2++;
-    }
-  }
-
-  /**
-   * Checks repeated string/message field equality. Only non-null elements are
-   * tested. Returns true if the two fields have the same sequence of non-null
-   * elements. Null-value fields and fields of any length with only null
-   * elements are considered equal.
-   */
-  public static boolean equals(Object[] field1, Object[] field2) {
-    int index1 = 0;
-    int length1 = field1 == null ? 0 : field1.length;
-    int index2 = 0;
-    int length2 = field2 == null ? 0 : field2.length;
-    while (true) {
-      while (index1 < length1 && field1[index1] == null) {
-        index1++;
-      }
-      while (index2 < length2 && field2[index2] == null) {
-        index2++;
-      }
-      boolean atEndOf1 = index1 >= length1;
-      boolean atEndOf2 = index2 >= length2;
-      if (atEndOf1 && atEndOf2) {
-        // no more non-null elements to test in both arrays
-        return true;
-      } else if (atEndOf1 != atEndOf2) {
-        // one of the arrays have extra non-null elements
-        return false;
-      } else if (!field1[index1].equals(field2[index2])) {
-        // element mismatch
-        return false;
-      }
-      index1++;
-      index2++;
-    }
-  }
-
-  /**
-   * Computes the hash code of a repeated int field. Null-value and 0-length
-   * fields have the same hash code.
-   */
-  public static int hashCode(int[] field) {
-    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
-  }
-
-  /**
-   * Computes the hash code of a repeated long field. Null-value and 0-length
-   * fields have the same hash code.
-   */
-  public static int hashCode(long[] field) {
-    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
-  }
-
-  /**
-   * Computes the hash code of a repeated float field. Null-value and 0-length
-   * fields have the same hash code.
-   */
-  public static int hashCode(float[] field) {
-    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
-  }
-
-  /**
-   * Computes the hash code of a repeated double field. Null-value and 0-length
-   * fields have the same hash code.
-   */
-  public static int hashCode(double[] field) {
-    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
-  }
-
-  /**
-   * Computes the hash code of a repeated boolean field. Null-value and 0-length
-   * fields have the same hash code.
-   */
-  public static int hashCode(boolean[] field) {
-    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
-  }
-
-  /**
-   * Computes the hash code of a repeated bytes field. Only the sequence of all
-   * non-null elements are used in the computation. Null-value fields and fields
-   * of any length with only null elements have the same hash code.
-   */
-  public static int hashCode(byte[][] field) {
-    int result = 0;
-    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
-      byte[] element = field[i];
-      if (element != null) {
-        result = 31 * result + Arrays.hashCode(element);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Computes the hash code of a repeated string/message field. Only the
-   * sequence of all non-null elements are used in the computation. Null-value
-   * fields and fields of any length with only null elements have the same hash
-   * code.
-   */
-  public static int hashCode(Object[] field) {
-    int result = 0;
-    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
-      Object element = field[i];
-      if (element != null) {
-        result = 31 * result + element.hashCode();
-      }
-    }
-    return result;
-  }
-
-  // This avoids having to make FieldArray public.
-  public static void cloneUnknownFieldData(ExtendableMessageNano original,
-      ExtendableMessageNano cloned) {
-    if (original.unknownFieldData != null) {
-      cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone();
-    }
-  }
-
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java b/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
deleted file mode 100644
index ff0af9d..0000000
--- a/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-
-/**
- * Thrown when a protocol message being parsed is invalid in some way,
- * e.g. it contains a malformed varint or a negative byte length.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class InvalidProtocolBufferNanoException extends IOException {
-  private static final long serialVersionUID = -1616151763072450476L;
-
-  public InvalidProtocolBufferNanoException(final String description) {
-    super(description);
-  }
-
-  static InvalidProtocolBufferNanoException truncatedMessage() {
-    return new InvalidProtocolBufferNanoException(
-      "While parsing a protocol message, the input ended unexpectedly " +
-      "in the middle of a field.  This could mean either than the " +
-      "input has been truncated or that an embedded message " +
-      "misreported its own length.");
-  }
-
-  static InvalidProtocolBufferNanoException negativeSize() {
-    return new InvalidProtocolBufferNanoException(
-      "CodedInputStream encountered an embedded string or message " +
-      "which claimed to have negative size.");
-  }
-
-  static InvalidProtocolBufferNanoException malformedVarint() {
-    return new InvalidProtocolBufferNanoException(
-      "CodedInputStream encountered a malformed varint.");
-  }
-
-  static InvalidProtocolBufferNanoException invalidTag() {
-    return new InvalidProtocolBufferNanoException(
-      "Protocol message contained an invalid tag (zero).");
-  }
-
-  static InvalidProtocolBufferNanoException invalidEndTag() {
-    return new InvalidProtocolBufferNanoException(
-      "Protocol message end-group tag did not match expected tag.");
-  }
-
-  static InvalidProtocolBufferNanoException invalidWireType() {
-    return new InvalidProtocolBufferNanoException(
-      "Protocol message tag had invalid wire type.");
-  }
-
-  static InvalidProtocolBufferNanoException recursionLimitExceeded() {
-    return new InvalidProtocolBufferNanoException(
-      "Protocol message had too many levels of nesting.  May be malicious.  " +
-      "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
-  }
-
-  static InvalidProtocolBufferNanoException sizeLimitExceeded() {
-    return new InvalidProtocolBufferNanoException(
-      "Protocol message was too large.  May be malicious.  " +
-      "Use CodedInputStream.setSizeLimit() to increase the size limit.");
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/MessageNano.java b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
deleted file mode 100644
index ea91b21..0000000
--- a/java/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ /dev/null
@@ -1,198 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * Abstract interface implemented by Protocol Message objects.
- *
- * @author wink@google.com Wink Saville
- */
-public abstract class MessageNano {
-    protected volatile int cachedSize = -1;
-
-    /**
-     * Get the number of bytes required to encode this message.
-     * Returns the cached size or calls getSerializedSize which
-     * sets the cached size. This is used internally when serializing
-     * so the size is only computed once. If a member is modified
-     * then this could be stale call getSerializedSize if in doubt.
-     */
-    public int getCachedSize() {
-        if (cachedSize < 0) {
-            // getSerializedSize sets cachedSize
-            getSerializedSize();
-        }
-        return cachedSize;
-    }
-
-    /**
-     * Computes the number of bytes required to encode this message.
-     * The size is cached and the cached result can be retrieved
-     * using getCachedSize().
-     */
-    public int getSerializedSize() {
-        int size = computeSerializedSize();
-        cachedSize = size;
-        return size;
-    }
-
-    /**
-     * Computes the number of bytes required to encode this message. This does not update the
-     * cached size.
-     */
-    protected int computeSerializedSize() {
-      // This is overridden if the generated message has serialized fields.
-      return 0;
-    }
-
-    /**
-     * Serializes the message and writes it to {@code output}.
-     *
-     * @param output the output to receive the serialized form.
-     * @throws IOException if an error occurred writing to {@code output}.
-     */
-    public void writeTo(CodedOutputByteBufferNano output) throws IOException {
-        // Does nothing by default. Overridden by subclasses which have data to write.
-    }
-
-    /**
-     * Parse {@code input} as a message of this type and merge it with the
-     * message being built.
-     */
-    public abstract MessageNano mergeFrom(CodedInputByteBufferNano input) throws IOException;
-
-    /**
-     * Serialize to a byte array.
-     * @return byte array with the serialized data.
-     */
-    public static final byte[] toByteArray(MessageNano msg) {
-        final byte[] result = new byte[msg.getSerializedSize()];
-        toByteArray(msg, result, 0, result.length);
-        return result;
-    }
-
-    /**
-     * Serialize to a byte array starting at offset through length. The
-     * method getSerializedSize must have been called prior to calling
-     * this method so the proper length is know.  If an attempt to
-     * write more than length bytes OutOfSpaceException will be thrown
-     * and if length bytes are not written then IllegalStateException
-     * is thrown.
-     */
-    public static final void toByteArray(MessageNano msg, byte[] data, int offset, int length) {
-        try {
-            final CodedOutputByteBufferNano output =
-                CodedOutputByteBufferNano.newInstance(data, offset, length);
-            msg.writeTo(output);
-            output.checkNoSpaceLeft();
-        } catch (IOException e) {
-            throw new RuntimeException("Serializing to a byte array threw an IOException "
-                    + "(should never happen).", e);
-        }
-    }
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.
-     */
-    public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data)
-        throws InvalidProtocolBufferNanoException {
-        return mergeFrom(msg, data, 0, data.length);
-    }
-
-    /**
-     * Parse {@code data} as a message of this type and merge it with the
-     * message being built.
-     */
-    public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data,
-            final int off, final int len) throws InvalidProtocolBufferNanoException {
-        try {
-            final CodedInputByteBufferNano input =
-                CodedInputByteBufferNano.newInstance(data, off, len);
-            msg.mergeFrom(input);
-            input.checkLastTagWas(0);
-            return msg;
-        } catch (InvalidProtocolBufferNanoException e) {
-            throw e;
-        } catch (IOException e) {
-            throw new RuntimeException("Reading from a byte array threw an IOException (should "
-                    + "never happen).");
-        }
-    }
-
-    /**
-     * Compares two {@code MessageNano}s and returns true if the message's are the same class and
-     * have serialized form equality (i.e. all of the field values are the same).
-     */
-    public static final boolean messageNanoEquals(MessageNano a, MessageNano b) {
-        if (a == b) {
-            return true;
-        }
-        if (a == null || b == null) {
-            return false;
-        }
-        if (a.getClass() != b.getClass()) {
-          return false;
-        }
-        final int serializedSize = a.getSerializedSize();
-        if (b.getSerializedSize() != serializedSize) {
-            return false;
-        }
-        final byte[] aByteArray = new byte[serializedSize];
-        final byte[] bByteArray = new byte[serializedSize];
-        toByteArray(a, aByteArray, 0, serializedSize);
-        toByteArray(b, bByteArray, 0, serializedSize);
-        return Arrays.equals(aByteArray, bByteArray);
-    }
-
-    /**
-     * Returns a string that is (mostly) compatible with ProtoBuffer's TextFormat. Note that groups
-     * (which are deprecated) are not serialized with the correct field name.
-     *
-     * <p>This is implemented using reflection, so it is not especially fast nor is it guaranteed
-     * to find all fields if you have method removal turned on for proguard.
-     */
-    @Override
-    public String toString() {
-        return MessageNanoPrinter.print(this);
-    }
-
-    /**
-     * Provides support for cloning. This only works if you specify the generate_clone method.
-     */
-    @Override
-    public MessageNano clone() throws CloneNotSupportedException {
-        return (MessageNano) super.clone();
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
deleted file mode 100644
index a30f2f3..0000000
--- a/java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
+++ /dev/null
@@ -1,261 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-/**
- * Static helper methods for printing nano protos.
- *
- * @author flynn@google.com Andrew Flynn
- */
-public final class MessageNanoPrinter {
-    // Do not allow instantiation
-    private MessageNanoPrinter() {}
-
-    private static final String INDENT = "  ";
-    private static final int MAX_STRING_LEN = 200;
-
-    /**
-     * Returns an text representation of a MessageNano suitable for debugging. The returned string
-     * is mostly compatible with Protocol Buffer's TextFormat (as provided by non-nano protocol
-     * buffers) -- groups (which are deprecated) are output with an underscore name (e.g. foo_bar
-     * instead of FooBar) and will thus not parse.
-     *
-     * <p>Employs Java reflection on the given object and recursively prints primitive fields,
-     * groups, and messages.</p>
-     */
-    public static <T extends MessageNano> String print(T message) {
-        if (message == null) {
-            return "";
-        }
-
-        StringBuffer buf = new StringBuffer();
-        try {
-            print(null, message, new StringBuffer(), buf);
-        } catch (IllegalAccessException e) {
-            return "Error printing proto: " + e.getMessage();
-        } catch (InvocationTargetException e) {
-            return "Error printing proto: " + e.getMessage();
-        }
-        return buf.toString();
-    }
-
-    /**
-     * Function that will print the given message/field into the StringBuffer.
-     * Meant to be called recursively.
-     *
-     * @param identifier the identifier to use, or {@code null} if this is the root message to
-     *        print.
-     * @param object the value to print. May in fact be a primitive value or byte array and not a
-     *        message.
-     * @param indentBuf the indentation each line should begin with.
-     * @param buf the output buffer.
-     */
-    private static void print(String identifier, Object object,
-            StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException,
-            InvocationTargetException {
-        if (object == null) {
-            // This can happen if...
-            //   - we're about to print a message, String, or byte[], but it not present;
-            //   - we're about to print a primitive, but "reftype" optional style is enabled, and
-            //     the field is unset.
-            // In both cases the appropriate behavior is to output nothing.
-        } else if (object instanceof MessageNano) {  // Nano proto message
-            int origIndentBufLength = indentBuf.length();
-            if (identifier != null) {
-                buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
-                indentBuf.append(INDENT);
-            }
-            Class<?> clazz = object.getClass();
-
-            // Proto fields follow one of two formats:
-            //
-            // 1) Public, non-static variables that do not begin or end with '_'
-            // Find and print these using declared public fields
-            for (Field field : clazz.getFields()) {
-                int modifiers = field.getModifiers();
-                String fieldName = field.getName();
-                if ("cachedSize".equals(fieldName)) {
-                    // TODO(bduff): perhaps cachedSize should have a more obscure name.
-                    continue;
-                }
-
-                if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
-                        && (modifiers & Modifier.STATIC) != Modifier.STATIC
-                        && !fieldName.startsWith("_")
-                        && !fieldName.endsWith("_")) {
-                    Class<?> fieldType = field.getType();
-                    Object value = field.get(object);
-
-                    if (fieldType.isArray()) {
-                        Class<?> arrayType = fieldType.getComponentType();
-
-                        // bytes is special since it's not repeated, but is represented by an array
-                        if (arrayType == byte.class) {
-                            print(fieldName, value, indentBuf, buf);
-                        } else {
-                            int len = value == null ? 0 : Array.getLength(value);
-                            for (int i = 0; i < len; i++) {
-                                Object elem = Array.get(value, i);
-                                print(fieldName, elem, indentBuf, buf);
-                            }
-                        }
-                    } else {
-                        print(fieldName, value, indentBuf, buf);
-                    }
-                }
-            }
-
-            // 2) Fields that are accessed via getter methods (when accessors
-            //    mode is turned on)
-            // Find and print these using getter methods.
-            for (Method method : clazz.getMethods()) {
-                String name = method.getName();
-                // Check for the setter accessor method since getters and hazzers both have
-                // non-proto-field name collisions (hashCode() and getSerializedSize())
-                if (name.startsWith("set")) {
-                    String subfieldName = name.substring(3);
-
-                    Method hazzer = null;
-                    try {
-                        hazzer = clazz.getMethod("has" + subfieldName);
-                    } catch (NoSuchMethodException e) {
-                        continue;
-                    }
-                    // If hazzer does't exist or returns false, no need to continue
-                    if (!(Boolean) hazzer.invoke(object)) {
-                        continue;
-                    }
-
-                    Method getter = null;
-                    try {
-                        getter = clazz.getMethod("get" + subfieldName);
-                    } catch (NoSuchMethodException e) {
-                        continue;
-                    }
-
-                    print(subfieldName, getter.invoke(object), indentBuf, buf);
-                }
-            }
-            if (identifier != null) {
-                indentBuf.setLength(origIndentBufLength);
-                buf.append(indentBuf).append(">\n");
-            }
-        } else {
-            // Non-null primitive value
-            identifier = deCamelCaseify(identifier);
-            buf.append(indentBuf).append(identifier).append(": ");
-            if (object instanceof String) {
-                String stringMessage = sanitizeString((String) object);
-                buf.append("\"").append(stringMessage).append("\"");
-            } else if (object instanceof byte[]) {
-                appendQuotedBytes((byte[]) object, buf);
-            } else {
-                buf.append(object);
-            }
-            buf.append("\n");
-        }
-    }
-
-    /**
-     * Converts an identifier of the format "FieldName" into "field_name".
-     */
-    private static String deCamelCaseify(String identifier) {
-        StringBuffer out = new StringBuffer();
-        for (int i = 0; i < identifier.length(); i++) {
-            char currentChar = identifier.charAt(i);
-            if (i == 0) {
-                out.append(Character.toLowerCase(currentChar));
-            } else if (Character.isUpperCase(currentChar)) {
-                out.append('_').append(Character.toLowerCase(currentChar));
-            } else {
-                out.append(currentChar);
-            }
-        }
-        return out.toString();
-    }
-
-    /**
-     * Shortens and escapes the given string.
-     */
-    private static String sanitizeString(String str) {
-        if (!str.startsWith("http") && str.length() > MAX_STRING_LEN) {
-            // Trim non-URL strings.
-            str = str.substring(0, MAX_STRING_LEN) + "[...]";
-        }
-        return escapeString(str);
-    }
-
-    /**
-     * Escape everything except for low ASCII code points.
-     */
-    private static String escapeString(String str) {
-        int strLen = str.length();
-        StringBuilder b = new StringBuilder(strLen);
-        for (int i = 0; i < strLen; i++) {
-            char original = str.charAt(i);
-            if (original >= ' ' && original <= '~' && original != '"' && original != '\'') {
-                b.append(original);
-            } else {
-                b.append(String.format("\\u%04x", (int) original));
-            }
-        }
-        return b.toString();
-    }
-
-    /**
-     * Appends a quoted byte array to the provided {@code StringBuffer}.
-     */
-    private static void appendQuotedBytes(byte[] bytes, StringBuffer builder) {
-        if (bytes == null) {
-            builder.append("\"\"");
-            return;
-        }
-
-        builder.append('"');
-        for (int i = 0; i < bytes.length; ++i) {
-            int ch = bytes[i] & 0xff;
-            if (ch == '\\' || ch == '"') {
-                builder.append('\\').append((char) ch);
-            } else if (ch >= 32 && ch < 127) {
-                builder.append((char) ch);
-            } else {
-                builder.append(String.format("\\%03o", ch));
-            }
-        }
-        builder.append('"');
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
deleted file mode 100644
index bf34bed..0000000
--- a/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * Stores unknown fields. These might be extensions or fields that the generated
- * API doesn't know about yet.
- *
- * @author bduff@google.com (Brian Duff)
- */
-final class UnknownFieldData {
-
-    final int tag;
-    /**
-     * Important: this should be treated as immutable, even though it's possible
-     * to change the array values.
-     */
-    final byte[] bytes;
-
-    UnknownFieldData(int tag, byte[] bytes) {
-        this.tag = tag;
-        this.bytes = bytes;
-    }
-
-    int computeSerializedSize() {
-        int size = 0;
-        size += CodedOutputByteBufferNano.computeRawVarint32Size(tag);
-        size += bytes.length;
-        return size;
-    }
-
-    void writeTo(CodedOutputByteBufferNano output) throws IOException {
-        output.writeRawVarint32(tag);
-        output.writeRawBytes(bytes);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (!(o instanceof UnknownFieldData)) {
-            return false;
-        }
-
-        UnknownFieldData other = (UnknownFieldData) o;
-        return tag == other.tag && Arrays.equals(bytes, other.bytes);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + tag;
-        result = 31 * result + Arrays.hashCode(bytes);
-        return result;
-    }
-}
diff --git a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
deleted file mode 100644
index a3405e5..0000000
--- a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.nano;
-
-import java.io.IOException;
-
-/**
- * This class is used internally by the Protocol Buffer library and generated
- * message implementations.  It is public only because those generated messages
- * do not reside in the {@code protobuf} package.  Others should not use this
- * class directly.
- *
- * This class contains constants and helper functions useful for dealing with
- * the Protocol Buffer wire format.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class WireFormatNano {
-  // Do not allow instantiation.
-  private WireFormatNano() {}
-
-  static final int WIRETYPE_VARINT           = 0;
-  static final int WIRETYPE_FIXED64          = 1;
-  static final int WIRETYPE_LENGTH_DELIMITED = 2;
-  static final int WIRETYPE_START_GROUP      = 3;
-  static final int WIRETYPE_END_GROUP        = 4;
-  static final int WIRETYPE_FIXED32          = 5;
-
-  static final int TAG_TYPE_BITS = 3;
-  static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
-
-  /** Given a tag value, determines the wire type (the lower 3 bits). */
-  static int getTagWireType(final int tag) {
-    return tag & TAG_TYPE_MASK;
-  }
-
-  /** Given a tag value, determines the field number (the upper 29 bits). */
-  public static int getTagFieldNumber(final int tag) {
-    return tag >>> TAG_TYPE_BITS;
-  }
-
-  /** Makes a tag value given a field number and wire type. */
-  static int makeTag(final int fieldNumber, final int wireType) {
-    return (fieldNumber << TAG_TYPE_BITS) | wireType;
-  }
-
-  public static final int EMPTY_INT_ARRAY[] = {};
-  public static final long EMPTY_LONG_ARRAY[] = {};
-  public static final float EMPTY_FLOAT_ARRAY[] = {};
-  public static final double EMPTY_DOUBLE_ARRAY[] = {};
-  public static final boolean EMPTY_BOOLEAN_ARRAY[] = {};
-  public static final String EMPTY_STRING_ARRAY[] = {};
-  public static final byte[] EMPTY_BYTES_ARRAY[] = {};
-  public static final byte[] EMPTY_BYTES = {};
-
-  /**
-   * Parses an unknown field. This implementation skips the field.
-   *
-   * <p>Generated messages will call this for unknown fields if the store_unknown_fields
-   * option is off.
-   *
-   * @return {@literal true} unless the tag is an end-group tag.
-   */
-  public static boolean parseUnknownField(
-      final CodedInputByteBufferNano input,
-      final int tag) throws IOException {
-    return input.skipField(tag);
-  }
-
-  /**
-   * Computes the array length of a repeated field. We assume that in the common case repeated
-   * fields are contiguously serialized but we still correctly handle interspersed values of a
-   * repeated field (but with extra allocations).
-   *
-   * Rewinds to current input position before returning.
-   *
-   * @param input stream input, pointing to the byte after the first tag
-   * @param tag repeated field tag just read
-   * @return length of array
-   * @throws IOException
-   */
-  public static final int getRepeatedFieldArrayLength(
-      final CodedInputByteBufferNano input,
-      final int tag) throws IOException {
-    int arrayLength = 1;
-    int startPos = input.getPosition();
-    input.skipField(tag);
-    while (input.readTag() == tag) {
-      input.skipField(tag);
-      arrayLength++;
-    }
-    input.rewindToPosition(startPos);
-    return arrayLength;
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
deleted file mode 100644
index d964ef5..0000000
--- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ /dev/null
@@ -1,527 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
-import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto.TestRequiredForeign;
-import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-
-import junit.framework.TestCase;
-
-import java.util.Map;
-
-/**
- * Unit test for {@link AbstractMessage}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class AbstractMessageTest extends TestCase {
-  /**
-   * Extends AbstractMessage and wraps some other message object.  The methods
-   * of the Message interface which aren't explicitly implemented by
-   * AbstractMessage are forwarded to the wrapped object.  This allows us to
-   * test that AbstractMessage's implementations work even if the wrapped
-   * object does not use them.
-   */
-  private static class AbstractMessageWrapper extends AbstractMessage {
-    private final Message wrappedMessage;
-
-    public AbstractMessageWrapper(Message wrappedMessage) {
-      this.wrappedMessage = wrappedMessage;
-    }
-
-    public Descriptors.Descriptor getDescriptorForType() {
-      return wrappedMessage.getDescriptorForType();
-    }
-    public AbstractMessageWrapper getDefaultInstanceForType() {
-      return new AbstractMessageWrapper(
-        wrappedMessage.getDefaultInstanceForType());
-    }
-    public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
-      return wrappedMessage.getAllFields();
-    }
-    public boolean hasField(Descriptors.FieldDescriptor field) {
-      return wrappedMessage.hasField(field);
-    }
-    public Object getField(Descriptors.FieldDescriptor field) {
-      return wrappedMessage.getField(field);
-    }
-    public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
-      return wrappedMessage.getRepeatedFieldCount(field);
-    }
-    public Object getRepeatedField(
-        Descriptors.FieldDescriptor field, int index) {
-      return wrappedMessage.getRepeatedField(field, index);
-    }
-    public UnknownFieldSet getUnknownFields() {
-      return wrappedMessage.getUnknownFields();
-    }
-    public Builder newBuilderForType() {
-      return new Builder(wrappedMessage.newBuilderForType());
-    }
-    public Builder toBuilder() {
-      return new Builder(wrappedMessage.toBuilder());
-    }
-
-    static class Builder extends AbstractMessage.Builder<Builder> {
-      private final Message.Builder wrappedBuilder;
-
-      public Builder(Message.Builder wrappedBuilder) {
-        this.wrappedBuilder = wrappedBuilder;
-      }
-
-      public AbstractMessageWrapper build() {
-        return new AbstractMessageWrapper(wrappedBuilder.build());
-      }
-      public AbstractMessageWrapper buildPartial() {
-        return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
-      }
-      public Builder clone() {
-        return new Builder(wrappedBuilder.clone());
-      }
-      public boolean isInitialized() {
-        return clone().buildPartial().isInitialized();
-      }
-      public Descriptors.Descriptor getDescriptorForType() {
-        return wrappedBuilder.getDescriptorForType();
-      }
-      public AbstractMessageWrapper getDefaultInstanceForType() {
-        return new AbstractMessageWrapper(
-          wrappedBuilder.getDefaultInstanceForType());
-      }
-      public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
-        return wrappedBuilder.getAllFields();
-      }
-      public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
-        return new Builder(wrappedBuilder.newBuilderForField(field));
-      }
-      public boolean hasField(Descriptors.FieldDescriptor field) {
-        return wrappedBuilder.hasField(field);
-      }
-      public Object getField(Descriptors.FieldDescriptor field) {
-        return wrappedBuilder.getField(field);
-      }
-      public Builder setField(Descriptors.FieldDescriptor field, Object value) {
-        wrappedBuilder.setField(field, value);
-        return this;
-      }
-      public Builder clearField(Descriptors.FieldDescriptor field) {
-        wrappedBuilder.clearField(field);
-        return this;
-      }
-      public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
-        return wrappedBuilder.getRepeatedFieldCount(field);
-      }
-      public Object getRepeatedField(
-          Descriptors.FieldDescriptor field, int index) {
-        return wrappedBuilder.getRepeatedField(field, index);
-      }
-      public Builder setRepeatedField(Descriptors.FieldDescriptor field,
-                                      int index, Object value) {
-        wrappedBuilder.setRepeatedField(field, index, value);
-        return this;
-      }
-      public Builder addRepeatedField(
-          Descriptors.FieldDescriptor field, Object value) {
-        wrappedBuilder.addRepeatedField(field, value);
-        return this;
-      }
-      public UnknownFieldSet getUnknownFields() {
-        return wrappedBuilder.getUnknownFields();
-      }
-      public Builder setUnknownFields(UnknownFieldSet unknownFields) {
-        wrappedBuilder.setUnknownFields(unknownFields);
-        return this;
-      }
-      @Override
-      public Message.Builder getFieldBuilder(FieldDescriptor field) {
-        return wrappedBuilder.getFieldBuilder(field);
-      }
-    }
-    public Parser<? extends Message> getParserForType() {
-      return wrappedMessage.getParserForType();
-    }
-  }
-
-  // =================================================================
-
-  TestUtil.ReflectionTester reflectionTester =
-    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
-
-  TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
-
-  public void testClear() throws Exception {
-    AbstractMessageWrapper message =
-      new AbstractMessageWrapper.Builder(
-          TestAllTypes.newBuilder(TestUtil.getAllSet()))
-        .clear().build();
-    TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
-  }
-
-  public void testCopy() throws Exception {
-    AbstractMessageWrapper message =
-      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
-        .mergeFrom(TestUtil.getAllSet()).build();
-    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
-  }
-
-  public void testSerializedSize() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
-
-    assertEquals(message.getSerializedSize(),
-                 abstractMessage.getSerializedSize());
-  }
-
-  public void testSerialization() throws Exception {
-    Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
-
-    TestUtil.assertAllFieldsSet(
-      TestAllTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getAllSet().toByteString(),
-                 abstractMessage.toByteString());
-  }
-
-  public void testParsing() throws Exception {
-    AbstractMessageWrapper.Builder builder =
-      new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
-    AbstractMessageWrapper message =
-      builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
-    TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
-  }
-
-  public void testParsingUninitialized() throws Exception {
-    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
-    builder.getOptionalMessageBuilder().setDummy2(10);
-    ByteString bytes = builder.buildPartial().toByteString();
-    Message.Builder abstractMessageBuilder =
-        new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
-    // mergeFrom() should not throw initialization error.
-    abstractMessageBuilder.mergeFrom(bytes).buildPartial();
-    try {
-      abstractMessageBuilder.mergeFrom(bytes).build();
-      fail();
-    } catch (UninitializedMessageException ex) {
-      // pass
-    }
-
-    // test DynamicMessage directly.
-    Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
-        TestRequiredForeign.getDescriptor());
-    // mergeFrom() should not throw initialization error.
-    dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
-    try {
-      dynamicMessageBuilder.mergeFrom(bytes).build();
-      fail();
-    } catch (UninitializedMessageException ex) {
-      // pass
-    }
-  }
-
-  public void testPackedSerialization() throws Exception {
-    Message abstractMessage =
-        new AbstractMessageWrapper(TestUtil.getPackedSet());
-
-    TestUtil.assertPackedFieldsSet(
-      TestPackedTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getPackedSet().toByteString(),
-                 abstractMessage.toByteString());
-  }
-
-  public void testPackedParsing() throws Exception {
-    AbstractMessageWrapper.Builder builder =
-      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
-    AbstractMessageWrapper message =
-      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
-    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
-  }
-
-  public void testUnpackedSerialization() throws Exception {
-    Message abstractMessage =
-      new AbstractMessageWrapper(TestUtil.getUnpackedSet());
-
-    TestUtil.assertUnpackedFieldsSet(
-      TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
-
-    assertEquals(TestUtil.getUnpackedSet().toByteString(),
-                 abstractMessage.toByteString());
-  }
-
-  public void testParsePackedToUnpacked() throws Exception {
-    AbstractMessageWrapper.Builder builder =
-      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
-    AbstractMessageWrapper message =
-      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
-    TestUtil.assertUnpackedFieldsSet(
-      (TestUnpackedTypes) message.wrappedMessage);
-  }
-
-  public void testParseUnpackedToPacked() throws Exception {
-    AbstractMessageWrapper.Builder builder =
-      new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
-    AbstractMessageWrapper message =
-      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
-    TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
-  }
-
-  public void testUnpackedParsing() throws Exception {
-    AbstractMessageWrapper.Builder builder =
-      new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
-    AbstractMessageWrapper message =
-      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
-    TestUtil.assertUnpackedFieldsSet(
-      (TestUnpackedTypes) message.wrappedMessage);
-  }
-
-  public void testOptimizedForSize() throws Exception {
-    // We're mostly only checking that this class was compiled successfully.
-    TestOptimizedForSize message =
-      TestOptimizedForSize.newBuilder().setI(1).build();
-    message = TestOptimizedForSize.parseFrom(message.toByteString());
-    assertEquals(2, message.getSerializedSize());
-  }
-
-  // -----------------------------------------------------------------
-  // Tests for isInitialized().
-
-  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
-    TestRequired.getDefaultInstance();
-  private static final TestRequired TEST_REQUIRED_INITIALIZED =
-    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
-
-  public void testIsInitialized() throws Exception {
-    TestRequired.Builder builder = TestRequired.newBuilder();
-    AbstractMessageWrapper.Builder abstractBuilder =
-      new AbstractMessageWrapper.Builder(builder);
-
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
-    builder.setA(1);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("b, c", abstractBuilder.getInitializationErrorString());
-    builder.setB(1);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals("c", abstractBuilder.getInitializationErrorString());
-    builder.setC(1);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
-  }
-
-  public void testForeignIsInitialized() throws Exception {
-    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
-    AbstractMessageWrapper.Builder abstractBuilder =
-      new AbstractMessageWrapper.Builder(builder);
-
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
-
-    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals(
-        "optional_message.a, optional_message.b, optional_message.c",
-        abstractBuilder.getInitializationErrorString());
-
-    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
-
-    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(abstractBuilder.isInitialized());
-    assertEquals(
-        "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
-        abstractBuilder.getInitializationErrorString());
-
-    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(abstractBuilder.isInitialized());
-    assertEquals("", abstractBuilder.getInitializationErrorString());
-  }
-
-  // -----------------------------------------------------------------
-  // Tests for mergeFrom
-
-  static final TestAllTypes MERGE_SOURCE =
-    TestAllTypes.newBuilder()
-      .setOptionalInt32(1)
-      .setOptionalString("foo")
-      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
-      .addRepeatedString("bar")
-      .build();
-
-  static final TestAllTypes MERGE_DEST =
-    TestAllTypes.newBuilder()
-      .setOptionalInt64(2)
-      .setOptionalString("baz")
-      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
-      .addRepeatedString("qux")
-      .build();
-
-  static final String MERGE_RESULT_TEXT =
-      "optional_int32: 1\n" +
-      "optional_int64: 2\n" +
-      "optional_string: \"foo\"\n" +
-      "optional_foreign_message {\n" +
-      "  c: 3\n" +
-      "}\n" +
-      "repeated_string: \"qux\"\n" +
-      "repeated_string: \"bar\"\n";
-
-  public void testMergeFrom() throws Exception {
-    AbstractMessageWrapper result =
-      new AbstractMessageWrapper.Builder(
-        TestAllTypes.newBuilder(MERGE_DEST))
-      .mergeFrom(MERGE_SOURCE).build();
-
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
-  }
-
-  // -----------------------------------------------------------------
-  // Tests for equals and hashCode
-
-  public void testEqualsAndHashCode() throws Exception {
-    TestAllTypes a = TestUtil.getAllSet();
-    TestAllTypes b = TestAllTypes.newBuilder().build();
-    TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
-    TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
-    TestAllExtensions e = TestUtil.getAllExtensionsSet();
-    TestAllExtensions f = TestAllExtensions.newBuilder(e)
-        .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
-
-    checkEqualsIsConsistent(a);
-    checkEqualsIsConsistent(b);
-    checkEqualsIsConsistent(c);
-    checkEqualsIsConsistent(d);
-    checkEqualsIsConsistent(e);
-    checkEqualsIsConsistent(f);
-
-    checkNotEqual(a, b);
-    checkNotEqual(a, c);
-    checkNotEqual(a, d);
-    checkNotEqual(a, e);
-    checkNotEqual(a, f);
-
-    checkNotEqual(b, c);
-    checkNotEqual(b, d);
-    checkNotEqual(b, e);
-    checkNotEqual(b, f);
-
-    checkNotEqual(c, d);
-    checkNotEqual(c, e);
-    checkNotEqual(c, f);
-
-    checkNotEqual(d, e);
-    checkNotEqual(d, f);
-
-    checkNotEqual(e, f);
-
-    // Deserializing into the TestEmptyMessage such that every field
-    // is an {@link UnknownFieldSet.Field}.
-    UnittestProto.TestEmptyMessage eUnknownFields =
-        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
-    UnittestProto.TestEmptyMessage fUnknownFields =
-        UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
-    checkNotEqual(eUnknownFields, fUnknownFields);
-    checkEqualsIsConsistent(eUnknownFields);
-    checkEqualsIsConsistent(fUnknownFields);
-
-    // Subsequent reconstitutions should be identical
-    UnittestProto.TestEmptyMessage eUnknownFields2 =
-        UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
-    checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
-  }
-
-
-  /**
-   * Asserts that the given proto has symmetric equals and hashCode methods.
-   */
-  private void checkEqualsIsConsistent(Message message) {
-    // Object should be equal to itself.
-    assertEquals(message, message);
-
-    // Object should be equal to a dynamic copy of itself.
-    DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
-    checkEqualsIsConsistent(message, dynamic);
-  }
-
-  /**
-   * Asserts that the given protos are equal and have the same hash code.
-   */
-  private void checkEqualsIsConsistent(Message message1, Message message2) {
-    assertEquals(message1, message2);
-    assertEquals(message2, message1);
-    assertEquals(message2.hashCode(), message1.hashCode());
-  }
-
-  /**
-   * Asserts that the given protos are not equal and have different hash codes.
-   *
-   * @warning It's valid for non-equal objects to have the same hash code, so
-   *   this test is stricter than it needs to be. However, this should happen
-   *   relatively rarely.
-   */
-  private void checkNotEqual(Message m1, Message m2) {
-    String equalsError = String.format("%s should not be equal to %s", m1, m2);
-    assertFalse(equalsError, m1.equals(m2));
-    assertFalse(equalsError, m2.equals(m1));
-
-    assertFalse(
-        String.format("%s should have a different hash code from %s", m1, m2),
-        m1.hashCode() == m2.hashCode());
-  }
-
-  public void testCheckByteStringIsUtf8OnUtf8() {
-    ByteString byteString = ByteString.copyFromUtf8("some text");
-    AbstractMessageLite.checkByteStringIsUtf8(byteString);
-    // No exception thrown.
-  }
-
-  public void testCheckByteStringIsUtf8OnNonUtf8() {
-    ByteString byteString =
-        ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
-    try {
-      AbstractMessageLite.checkByteStringIsUtf8(byteString);
-      fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
deleted file mode 100644
index 2b71cfb..0000000
--- a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
- * by inheriting the tests from {@link LiteralByteStringTest}.  The only method which
- * is strange enough that it needs to be overridden here is {@link #testToString()}.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-public class BoundedByteStringTest extends LiteralByteStringTest {
-
-  @Override
-  protected void setUp() throws Exception {
-    classUnderTest = "BoundedByteString";
-    byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
-    int from = 100;
-    int to = sourceBytes.length - 100;
-    stringUnderTest = ByteString.copyFrom(sourceBytes).substring(from, to);
-    referenceBytes = new byte[to - from];
-    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
-    expectedHashCode = 727575887;
-  }
-
-  @Override
-  public void testToString() throws UnsupportedEncodingException {
-    String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
-    ByteString chopped = unicode.substring(2, unicode.size() - 6);
-    assertEquals(classUnderTest + ".substring() must have the expected type",
-        classUnderTest, getActualClassName(chopped));
-
-    String roundTripString = chopped.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match",
-        testString.substring(2, testString.length() - 6), roundTripString);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/ByteStringTest.java b/java/src/test/java/com/google/protobuf/ByteStringTest.java
deleted file mode 100644
index 15de17c..0000000
--- a/java/src/test/java/com/google/protobuf/ByteStringTest.java
+++ /dev/null
@@ -1,759 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.ByteString.Output;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Random;
-
-/**
- * Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
- * tests.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-public class ByteStringTest extends TestCase {
-
-  private static final String UTF_16 = "UTF-16";
-
-  static byte[] getTestBytes(int size, long seed) {
-    Random random = new Random(seed);
-    byte[] result = new byte[size];
-    random.nextBytes(result);
-    return result;
-  }
-
-  private byte[] getTestBytes(int size) {
-    return getTestBytes(size, 445566L);
-  }
-
-  private byte[] getTestBytes() {
-    return getTestBytes(1000);
-  }
-
-  // Compare the entire left array with a subset of the right array.
-  private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
-    boolean stillEqual = (left.length == length);
-    for (int i = 0; (stillEqual && i < length); ++i) {
-      stillEqual = (left[i] == right[rightOffset + i]);
-    }
-    return stillEqual;
-  }
-
-  // Returns true only if the given two arrays have identical contents.
-  private boolean isArray(byte[] left, byte[] right) {
-    return left.length == right.length && isArrayRange(left, right, 0, left.length);
-  }
-
-  public void testSubstring_BeginIndex() {
-    byte[] bytes = getTestBytes();
-    ByteString substring = ByteString.copyFrom(bytes).substring(500);
-    assertTrue("substring must contain the tail of the string",
-        isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
-  }
-
-  public void testCopyFrom_BytesOffsetSize() {
-    byte[] bytes = getTestBytes();
-    ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
-    assertTrue("copyFrom sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
-  }
-
-  public void testCopyFrom_Bytes() {
-    byte[] bytes = getTestBytes();
-    ByteString byteString = ByteString.copyFrom(bytes);
-    assertTrue("copyFrom must contain the expected bytes",
-        isArray(byteString.toByteArray(), bytes));
-  }
-
-  public void testCopyFrom_ByteBufferSize() {
-    byte[] bytes = getTestBytes();
-    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
-    byteBuffer.put(bytes);
-    byteBuffer.position(500);
-    ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
-    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, 200));
-  }
-
-  public void testCopyFrom_ByteBuffer() {
-    byte[] bytes = getTestBytes();
-    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
-    byteBuffer.put(bytes);
-    byteBuffer.position(500);
-    ByteString byteString = ByteString.copyFrom(byteBuffer);
-    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
-  }
-
-  public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
-    String testString = "I love unicode \u1234\u5678 characters";
-    ByteString byteString = ByteString.copyFrom(testString, UTF_16);
-    byte[] testBytes = testString.getBytes(UTF_16);
-    assertTrue("copyFrom string must respect the charset",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
-  }
-
-  public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
-    String testString = "I love unicode \u1234\u5678 characters";
-    ByteString byteString = ByteString.copyFromUtf8(testString);
-    byte[] testBytes = testString.getBytes("UTF-8");
-    assertTrue("copyFromUtf8 string must respect the charset",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
-  }
-
-  public void testCopyFrom_Iterable() {
-    byte[] testBytes = getTestBytes(77777, 113344L);
-    final List<ByteString> pieces = makeConcretePieces(testBytes);
-    // Call copyFrom() on a Collection
-    ByteString byteString = ByteString.copyFrom(pieces);
-    assertTrue("copyFrom a List must contain the expected bytes",
-        isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
-    // Call copyFrom on an iteration that's not a collection
-    ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
-      public Iterator<ByteString> iterator() {
-        return pieces.iterator();
-      }
-    });
-    assertEquals("copyFrom from an Iteration must contain the expected bytes",
-        byteString, byteStringAlt);
-  }
-
-  public void testCopyTo_TargetOffset() {
-    byte[] bytes = getTestBytes();
-    ByteString byteString = ByteString.copyFrom(bytes);
-    byte[] target = new byte[bytes.length + 1000];
-    byteString.copyTo(target, 400);
-    assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
-        isArrayRange(bytes, target, 400, bytes.length));
-  }
-
-  public void testReadFrom_emptyStream() throws IOException {
-    ByteString byteString =
-        ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
-    assertSame("reading an empty stream must result in the EMPTY constant "
-        + "byte string", ByteString.EMPTY, byteString);
-  }
-
-  public void testReadFrom_smallStream() throws IOException {
-    assertReadFrom(getTestBytes(10));
-  }
-
-  public void testReadFrom_mutating() throws IOException {
-    byte[] capturedArray = null;
-    EvilInputStream eis = new EvilInputStream();
-    ByteString byteString = ByteString.readFrom(eis);
-
-    capturedArray = eis.capturedArray;
-    byte[] originalValue = byteString.toByteArray();
-    for (int x = 0; x < capturedArray.length; ++x) {
-      capturedArray[x] = (byte) 0;
-    }
-
-    byte[] newValue = byteString.toByteArray();
-    assertTrue("copyFrom byteBuffer must not grant access to underlying array",
-        Arrays.equals(originalValue, newValue));
-  }
-
-  // Tests sizes that are near the rope copy-out threshold.
-  public void testReadFrom_mediumStream() throws IOException {
-    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
-    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
-    assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1));
-    assertReadFrom(getTestBytes(200));
-  }
-
-  // Tests sizes that are over multi-segment rope threshold.
-  public void testReadFrom_largeStream() throws IOException {
-    assertReadFrom(getTestBytes(0x100));
-    assertReadFrom(getTestBytes(0x101));
-    assertReadFrom(getTestBytes(0x110));
-    assertReadFrom(getTestBytes(0x1000));
-    assertReadFrom(getTestBytes(0x1001));
-    assertReadFrom(getTestBytes(0x1010));
-    assertReadFrom(getTestBytes(0x10000));
-    assertReadFrom(getTestBytes(0x10001));
-    assertReadFrom(getTestBytes(0x10010));
-  }
-
-  // Tests sizes that are near the read buffer size.
-  public void testReadFrom_byteBoundaries() throws IOException {
-    final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
-    final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
-
-    assertReadFrom(getTestBytes(min - 1));
-    assertReadFrom(getTestBytes(min));
-    assertReadFrom(getTestBytes(min + 1));
-
-    assertReadFrom(getTestBytes(min * 2 - 1));
-    assertReadFrom(getTestBytes(min * 2));
-    assertReadFrom(getTestBytes(min * 2 + 1));
-
-    assertReadFrom(getTestBytes(min * 4 - 1));
-    assertReadFrom(getTestBytes(min * 4));
-    assertReadFrom(getTestBytes(min * 4 + 1));
-
-    assertReadFrom(getTestBytes(min * 8 - 1));
-    assertReadFrom(getTestBytes(min * 8));
-    assertReadFrom(getTestBytes(min * 8 + 1));
-
-    assertReadFrom(getTestBytes(max - 1));
-    assertReadFrom(getTestBytes(max));
-    assertReadFrom(getTestBytes(max + 1));
-
-    assertReadFrom(getTestBytes(max * 2 - 1));
-    assertReadFrom(getTestBytes(max * 2));
-    assertReadFrom(getTestBytes(max * 2 + 1));
-  }
-
-  // Tests that IOExceptions propagate through ByteString.readFrom().
-  public void testReadFrom_IOExceptions() {
-    try {
-      ByteString.readFrom(new FailStream());
-      fail("readFrom must throw the underlying IOException");
-
-    } catch (IOException e) {
-      assertEquals("readFrom must throw the expected exception",
-                   "synthetic failure", e.getMessage());
-    }
-  }
-
-  // Tests that ByteString.readFrom works with streams that don't
-  // always fill their buffers.
-  public void testReadFrom_reluctantStream() throws IOException {
-    final byte[] data = getTestBytes(0x1000);
-
-    ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
-    assertTrue("readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), data));
-
-    // Same test as above, but with some specific chunk sizes.
-    assertReadFromReluctantStream(data, 100);
-    assertReadFromReluctantStream(data, 248);
-    assertReadFromReluctantStream(data, 249);
-    assertReadFromReluctantStream(data, 250);
-    assertReadFromReluctantStream(data, 251);
-    assertReadFromReluctantStream(data, 0x1000);
-    assertReadFromReluctantStream(data, 0x1001);
-  }
-
-  // Fails unless ByteString.readFrom reads the bytes correctly from a
-  // reluctant stream with the given chunkSize parameter.
-  private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
-      throws IOException {
-    ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
-    assertTrue("readFrom byte stream must contain the expected bytes",
-        isArray(b.toByteArray(), bytes));
-  }
-
-  // Tests that ByteString.readFrom works with streams that implement
-  // available().
-  public void testReadFrom_available() throws IOException {
-    final byte[] data = getTestBytes(0x1001);
-
-    ByteString byteString = ByteString.readFrom(new AvailableStream(data));
-    assertTrue("readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), data));
-  }
-
-  // Fails unless ByteString.readFrom reads the bytes correctly.
-  private void assertReadFrom(byte[] bytes) throws IOException {
-    ByteString byteString =
-        ByteString.readFrom(new ByteArrayInputStream(bytes));
-    assertTrue("readFrom byte stream must contain the expected bytes",
-        isArray(byteString.toByteArray(), bytes));
-  }
-
-  // A stream that fails when read.
-  private static final class FailStream extends InputStream {
-    @Override public int read() throws IOException {
-      throw new IOException("synthetic failure");
-    }
-  }
-
-  // A stream that simulates blocking by only producing 250 characters
-  // per call to read(byte[]).
-  private static class ReluctantStream extends InputStream {
-    protected final byte[] data;
-    protected int pos = 0;
-
-    public ReluctantStream(byte[] data) {
-      this.data = data;
-    }
-
-    @Override public int read() {
-      if (pos == data.length) {
-        return -1;
-      } else {
-        return data[pos++];
-      }
-    }
-
-    @Override public int read(byte[] buf) {
-      return read(buf, 0, buf.length);
-    }
-
-    @Override public int read(byte[] buf, int offset, int size) {
-      if (pos == data.length) {
-        return -1;
-      }
-      int count = Math.min(Math.min(size, data.length - pos), 250);
-      System.arraycopy(data, pos, buf, offset, count);
-      pos += count;
-      return count;
-    }
-  }
-
-  // Same as above, but also implements available().
-  private static final class AvailableStream extends ReluctantStream {
-    public AvailableStream(byte[] data) {
-      super(data);
-    }
-
-    @Override public int available() {
-      return Math.min(250, data.length - pos);
-    }
-  }
-
-  // A stream which exposes the byte array passed into read(byte[], int, int).
-  private static class EvilInputStream extends InputStream {
-    public byte[] capturedArray = null;
-
-    @Override
-    public int read(byte[] buf, int off, int len) {
-      if (capturedArray != null) {
-        return -1;
-      } else {
-        capturedArray = buf;
-        for (int x = 0; x < len; ++x) {
-          buf[x] = (byte) x;
-        }
-        return len;
-      }
-    }
-
-    @Override
-    public int read() {
-      // Purposefully do nothing.
-      return -1;
-    }
-  }
-  
-  // A stream which exposes the byte array passed into write(byte[], int, int).
-  private static class EvilOutputStream extends OutputStream {
-    public byte[] capturedArray = null;
-
-    @Override
-    public void write(byte[] buf, int off, int len) {
-      if (capturedArray == null) {
-        capturedArray = buf;
-      }
-    }
-
-    @Override
-    public void write(int ignored) {
-      // Purposefully do nothing.
-    }
-  }
-
-  public void testToStringUtf8() throws UnsupportedEncodingException {
-    String testString = "I love unicode \u1234\u5678 characters";
-    byte[] testBytes = testString.getBytes("UTF-8");
-    ByteString byteString = ByteString.copyFrom(testBytes);
-    assertEquals("copyToStringUtf8 must respect the charset",
-        testString, byteString.toStringUtf8());
-  }
-
-  public void testNewOutput_InitialCapacity() throws IOException {
-    byte[] bytes = getTestBytes();
-    ByteString.Output output = ByteString.newOutput(bytes.length + 100);
-    output.write(bytes);
-    ByteString byteString = output.toByteString();
-    assertTrue(
-        "String built from newOutput(int) must contain the expected bytes",
-        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
-  }
-
-  // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
-  // write sizes
-  public void testNewOutput_ArrayWrite() throws IOException {
-    byte[] bytes = getTestBytes();
-    int length = bytes.length;
-    int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
-                         2 * length, 3 * length};
-    int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
-
-    for (int bufferSize : bufferSizes) {
-      for (int writeSize : writeSizes) {
-        // Test writing the entire output writeSize bytes at a time.
-        ByteString.Output output = ByteString.newOutput(bufferSize);
-        for (int i = 0; i < length; i += writeSize) {
-          output.write(bytes, i, Math.min(writeSize, length - i));
-        }
-        ByteString byteString = output.toByteString();
-        assertTrue("String built from newOutput() must contain the expected bytes",
-            isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
-      }
-    }
-  }
-
-  // Test newOutput() using a variety of buffer sizes, but writing all the
-  // characters using write(byte);
-  public void testNewOutput_WriteChar() throws IOException {
-    byte[] bytes = getTestBytes();
-    int length = bytes.length;
-    int[] bufferSizes = {0, 1, 128, 256, length / 2,
-                         length - 1, length, length + 1,
-                         2 * length, 3 * length};
-    for (int bufferSize : bufferSizes) {
-      ByteString.Output output = ByteString.newOutput(bufferSize);
-      for (byte byteValue : bytes) {
-        output.write(byteValue);
-      }
-      ByteString byteString = output.toByteString();
-      assertTrue("String built from newOutput() must contain the expected bytes",
-          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
-    }
-  }
-
-  // Test newOutput() in which we write the bytes using a variety of methods
-  // and sizes, and in which we repeatedly call toByteString() in the middle.
-  public void testNewOutput_Mixed() throws IOException {
-    Random rng = new Random(1);
-    byte[] bytes = getTestBytes();
-    int length = bytes.length;
-    int[] bufferSizes = {0, 1, 128, 256, length / 2,
-                         length - 1, length, length + 1,
-                         2 * length, 3 * length};
-
-    for (int bufferSize : bufferSizes) {
-      // Test writing the entire output using a mixture of write sizes and
-      // methods;
-      ByteString.Output output = ByteString.newOutput(bufferSize);
-      int position = 0;
-      while (position < bytes.length) {
-        if (rng.nextBoolean()) {
-          int count = 1 + rng.nextInt(bytes.length - position);
-          output.write(bytes, position, count);
-          position += count;
-        } else {
-          output.write(bytes[position]);
-          position++;
-        }
-        assertEquals("size() returns the right value", position, output.size());
-        assertTrue("newOutput() substring must have correct bytes",
-            isArrayRange(output.toByteString().toByteArray(),
-                bytes, 0, position));
-      }
-      ByteString byteString = output.toByteString();
-      assertTrue("String built from newOutput() must contain the expected bytes",
-          isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
-    }
-  }
-  
-  public void testNewOutputEmpty() throws IOException {
-    // Make sure newOutput() correctly builds empty byte strings
-    ByteString byteString = ByteString.newOutput().toByteString();
-    assertEquals(ByteString.EMPTY, byteString);
-  }
-  
-  public void testNewOutput_Mutating() throws IOException {
-    Output os = ByteString.newOutput(5);
-    os.write(new byte[] {1, 2, 3, 4, 5});
-    EvilOutputStream eos = new EvilOutputStream();
-    os.writeTo(eos);
-    byte[] capturedArray = eos.capturedArray;
-    ByteString byteString = os.toByteString();
-    byte[] oldValue = byteString.toByteArray();
-    Arrays.fill(capturedArray, (byte) 0);
-    byte[] newValue = byteString.toByteArray();
-    assertTrue("Output must not provide access to the underlying byte array",
-        Arrays.equals(oldValue, newValue));
-  }
-
-  public void testNewCodedBuilder() throws IOException {
-    byte[] bytes = getTestBytes();
-    ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
-    builder.getCodedOutput().writeRawBytes(bytes);
-    ByteString byteString = builder.build();
-    assertTrue("String built from newCodedBuilder() must contain the expected bytes",
-        isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
-  }
-
-  public void testSubstringParity() {
-    byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
-    int start = 512 * 1024 - 3333;
-    int end   = 512 * 1024 + 7777;
-    ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
-    boolean ok = true;
-    for (int i = start; ok && i < end; ++i) {
-      ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
-    }
-    assertTrue("Concrete substring didn't capture the right bytes", ok);
-
-    ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
-    assertTrue("Substring must be equal to literal string",
-        concreteSubstring.equals(literalString));
-    assertEquals("Substring must have same hashcode as literal string",
-        literalString.hashCode(), concreteSubstring.hashCode());
-  }
-
-  public void testCompositeSubstring() {
-    byte[] referenceBytes = getTestBytes(77748, 113344L);
-
-    List<ByteString> pieces = makeConcretePieces(referenceBytes);
-    ByteString listString = ByteString.copyFrom(pieces);
-
-    int from = 1000;
-    int to = 40000;
-    ByteString compositeSubstring = listString.substring(from, to);
-    byte[] substringBytes = compositeSubstring.toByteArray();
-    boolean stillEqual = true;
-    for (int i = 0; stillEqual && i < to - from; ++i) {
-      stillEqual = referenceBytes[from + i] == substringBytes[i];
-    }
-    assertTrue("Substring must return correct bytes", stillEqual);
-
-    stillEqual = true;
-    for (int i = 0; stillEqual && i < to - from; ++i) {
-      stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
-    }
-    assertTrue("Substring must support byteAt() correctly", stillEqual);
-
-    ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
-    assertTrue("Composite substring must equal a literal substring over the same bytes",
-        compositeSubstring.equals(literalSubstring));
-    assertTrue("Literal substring must equal a composite substring over the same bytes",
-        literalSubstring.equals(compositeSubstring));
-
-    assertEquals("We must get the same hashcodes for composite and literal substrings",
-        literalSubstring.hashCode(), compositeSubstring.hashCode());
-
-    assertFalse("We can't be equal to a proper substring",
-        compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
-  }
-
-  public void testCopyFromList() {
-    byte[] referenceBytes = getTestBytes(77748, 113344L);
-    ByteString literalString = ByteString.copyFrom(referenceBytes);
-
-    List<ByteString> pieces = makeConcretePieces(referenceBytes);
-    ByteString listString = ByteString.copyFrom(pieces);
-
-    assertTrue("Composite string must be equal to literal string",
-        listString.equals(literalString));
-    assertEquals("Composite string must have same hashcode as literal string",
-        literalString.hashCode(), listString.hashCode());
-  }
-
-  public void testConcat() {
-    byte[] referenceBytes = getTestBytes(77748, 113344L);
-    ByteString literalString = ByteString.copyFrom(referenceBytes);
-
-    List<ByteString> pieces = makeConcretePieces(referenceBytes);
-
-    Iterator<ByteString> iter = pieces.iterator();
-    ByteString concatenatedString = iter.next();
-    while (iter.hasNext()) {
-      concatenatedString = concatenatedString.concat(iter.next());
-    }
-
-    assertTrue("Concatenated string must be equal to literal string",
-        concatenatedString.equals(literalString));
-    assertEquals("Concatenated string must have same hashcode as literal string",
-        literalString.hashCode(), concatenatedString.hashCode());
-  }
-
-  /**
-   * Test the Rope implementation can deal with Empty nodes, even though we
-   * guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
-   */
-  public void testConcat_empty() {
-    byte[] referenceBytes = getTestBytes(7748, 113344L);
-    ByteString literalString = ByteString.copyFrom(referenceBytes);
-
-    ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
-    ByteString temp = RopeByteString.newInstanceForTest(
-        RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
-        RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
-    ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
-
-    assertTrue("String with concatenated nulls must equal simple concatenate",
-        duo.equals(quintet));
-    assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
-        duo.hashCode(), quintet.hashCode());
-
-    ByteString.ByteIterator duoIter = duo.iterator();
-    ByteString.ByteIterator quintetIter = quintet.iterator();
-    boolean stillEqual = true;
-    while (stillEqual && quintetIter.hasNext()) {
-      stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
-    }
-    assertTrue("We must get the same characters by iterating", stillEqual);
-    assertFalse("Iterator must be exhausted", duoIter.hasNext());
-    try {
-      duoIter.nextByte();
-      fail("Should have thrown an exception.");
-    } catch (NoSuchElementException e) {
-      // This is success
-    }
-    try {
-      quintetIter.nextByte();
-      fail("Should have thrown an exception.");
-    } catch (NoSuchElementException e) {
-      // This is success
-    }
-
-    // Test that even if we force empty strings in as rope leaves in this
-    // configuration, we always get a (possibly Bounded) LiteralByteString
-    // for a length 1 substring.
-    //
-    // It is possible, using the testing factory method to create deeply nested
-    // trees of empty leaves, to make a string that will fail this test.
-    for (int i = 1; i < duo.size(); ++i) {
-      assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
-          duo.substring(i - 1, i) instanceof LiteralByteString);
-    }
-    for (int i = 1; i < quintet.size(); ++i) {
-      assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
-          quintet.substring(i - 1, i) instanceof LiteralByteString);
-    }
-  }
-
-  public void testStartsWith() {
-    byte[] bytes = getTestBytes(1000, 1234L);
-    ByteString string = ByteString.copyFrom(bytes);
-    ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
-    ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
-    assertTrue(string.startsWith(ByteString.EMPTY));
-    assertTrue(string.startsWith(string));
-    assertTrue(string.startsWith(prefix));
-    assertFalse(string.startsWith(suffix));
-    assertFalse(prefix.startsWith(suffix));
-    assertFalse(suffix.startsWith(prefix));
-    assertFalse(ByteString.EMPTY.startsWith(prefix));
-    assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
-  }
-
-  public void testEndsWith() {
-    byte[] bytes = getTestBytes(1000, 1234L);
-    ByteString string = ByteString.copyFrom(bytes);
-    ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
-    ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
-    assertTrue(string.endsWith(ByteString.EMPTY));
-    assertTrue(string.endsWith(string));
-    assertTrue(string.endsWith(suffix));
-    assertFalse(string.endsWith(prefix));
-    assertFalse(suffix.endsWith(prefix));
-    assertFalse(prefix.endsWith(suffix));
-    assertFalse(ByteString.EMPTY.endsWith(suffix));
-    assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY));
-  }
-
-  static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
-    List<ByteString> pieces = new ArrayList<ByteString>();
-    // Starting length should be small enough that we'll do some concatenating by
-    // copying if we just concatenate all these pieces together.
-    for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
-      length = (length << 1) - 1;
-      if (start + length > referenceBytes.length) {
-        length = referenceBytes.length - start;
-      }
-      pieces.add(ByteString.copyFrom(referenceBytes, start, length));
-    }
-    return pieces;
-  }
-  
-  private byte[] substringUsingWriteTo(
-      ByteString data, int offset, int length) throws IOException {
-    ByteArrayOutputStream output = new ByteArrayOutputStream();
-    data.writeTo(output, offset, length);
-    return output.toByteArray();
-  }
-  
-  public void testWriteToOutputStream() throws Exception {
-    // Choose a size large enough so when two ByteStrings are concatenated they
-    // won't be merged into one byte array due to some optimizations.
-    final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1;
-    byte[] data1 = new byte[dataSize];
-    for (int i = 0; i < data1.length; i++) {
-      data1[i] = (byte) 1;
-    }
-    data1[1] = (byte) 11;
-    // Test LiteralByteString.writeTo(OutputStream,int,int)
-    LiteralByteString left = new LiteralByteString(data1);
-    byte[] result = substringUsingWriteTo(left, 1, 1);
-    assertEquals(1, result.length);
-    assertEquals((byte) 11, result[0]);
-    
-    byte[] data2 = new byte[dataSize];
-    for (int i = 0; i < data1.length; i++) {
-      data2[i] = (byte) 2;
-    }
-    LiteralByteString right = new LiteralByteString(data2);
-    // Concatenate two ByteStrings to create a RopeByteString.
-    ByteString root = left.concat(right);
-    // Make sure we are actually testing a RopeByteString with a simple tree
-    // structure.
-    assertEquals(1, root.getTreeDepth());
-    // Write parts of the left node.
-    result = substringUsingWriteTo(root, 0, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 1, result[0]);
-    assertEquals((byte) 1, result[dataSize - 1]);
-    // Write parts of the right node.
-    result = substringUsingWriteTo(root, dataSize, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 2, result[0]);
-    assertEquals((byte) 2, result[dataSize - 1]);
-    // Write a segment of bytes that runs across both nodes.
-    result = substringUsingWriteTo(root, dataSize / 2, dataSize);
-    assertEquals(dataSize, result.length);
-    assertEquals((byte) 1, result[0]);
-    assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]);
-    assertEquals((byte) 2, result[dataSize - dataSize / 2]);
-    assertEquals((byte) 2, result[dataSize - 1]);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java
deleted file mode 100644
index 6470e9c..0000000
--- a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java
+++ /dev/null
@@ -1,141 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
-import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
-import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
-import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
-import junit.framework.TestCase;
-
-/**
- * Test that protos generated with file option java_string_check_utf8 do in
- * fact perform appropriate UTF-8 checks.
- *
- * @author jbaum@google.com (Jacob Butcher)
- */
-public class CheckUtf8Test extends TestCase {
-
-  private static final String UTF8_BYTE_STRING_TEXT = "some text";
-  private static final ByteString UTF8_BYTE_STRING =
-      ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
-  private static final ByteString NON_UTF8_BYTE_STRING =
-      ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte.
-
-  public void testBuildRequiredStringWithGoodUtf8() throws Exception {
-    assertEquals(UTF8_BYTE_STRING_TEXT,
-                 StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq());
-  }
-
-  public void testParseRequiredStringWithGoodUtf8() throws Exception {
-    ByteString serialized =
-        BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
-    assertEquals(UTF8_BYTE_STRING_TEXT,
-                 StringWrapper.PARSER.parseFrom(serialized).getReq());
-  }
-
-  public void testBuildRequiredStringWithBadUtf8() throws Exception {
-    try {
-      StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testBuildOptionalStringWithBadUtf8() throws Exception {
-    try {
-      StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testBuildRepeatedStringWithBadUtf8() throws Exception {
-    try {
-      StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testParseRequiredStringWithBadUtf8() throws Exception {
-    ByteString serialized =
-        BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
-    try {
-      StringWrapper.PARSER.parseFrom(serialized);
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
-    try {
-      StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testBuildOptionalStringWithBadUtf8Size() throws Exception {
-    try {
-      StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testBuildRepeatedStringWithBadUtf8Size() throws Exception {
-    try {
-      StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING);
-      fail("Expected IllegalArgumentException for non UTF-8 byte string.");
-    } catch (IllegalArgumentException exception) {
-      assertEquals("Byte string is not UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testParseRequiredStringWithBadUtf8Size() throws Exception {
-    ByteString serialized =
-        BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
-    try {
-      StringWrapperSize.PARSER.parseFrom(serialized);
-      fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
-    }
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
deleted file mode 100644
index 3f656e2..0000000
--- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ /dev/null
@@ -1,769 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.BoolMessage;
-import protobuf_unittest.UnittestProto.Int32Message;
-import protobuf_unittest.UnittestProto.Int64Message;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestRecursiveMessage;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-/**
- * Unit test for {@link CodedInputStream}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class CodedInputStreamTest extends TestCase {
-  /**
-   * Helper to construct a byte array from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
-   */
-  private byte[] bytes(int... bytesAsInts) {
-    byte[] bytes = new byte[bytesAsInts.length];
-    for (int i = 0; i < bytesAsInts.length; i++) {
-      bytes[i] = (byte) bytesAsInts[i];
-    }
-    return bytes;
-  }
-
-  /**
-   * An InputStream which limits the number of bytes it reads at a time.
-   * We use this to make sure that CodedInputStream doesn't screw up when
-   * reading in small blocks.
-   */
-  private static final class SmallBlockInputStream extends FilterInputStream {
-    private final int blockSize;
-
-    public SmallBlockInputStream(byte[] data, int blockSize) {
-      this(new ByteArrayInputStream(data), blockSize);
-    }
-
-    public SmallBlockInputStream(InputStream in, int blockSize) {
-      super(in);
-      this.blockSize = blockSize;
-    }
-
-    public int read(byte[] b) throws IOException {
-      return super.read(b, 0, Math.min(b.length, blockSize));
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-      return super.read(b, off, Math.min(len, blockSize));
-    }
-  }
-
-  private void assertDataConsumed(byte[] data, CodedInputStream input)
-      throws IOException {
-    assertEquals(data.length, input.getTotalBytesRead());
-    assertTrue(input.isAtEnd());
-  }
-
-  /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * checks that the result matches the given value.
-   */
-  private void assertReadVarint(byte[] data, long value) throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals((int) value, input.readRawVarint32());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawVarint64SlowPath());
-    assertDataConsumed(data, input);
-
-    input = CodedInputStream.newInstance(data);
-    assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-    assertDataConsumed(data, input);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals((int) value, input.readRawVarint32());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawVarint64SlowPath());
-      assertDataConsumed(data, input);
-
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
-      assertDataConsumed(data, input);
-    }
-
-    // Try reading direct from an InputStream.  We want to verify that it
-    // doesn't read past the end of the input, so we copy to a new, bigger
-    // array first.
-    byte[] longerData = new byte[data.length + 1];
-    System.arraycopy(data, 0, longerData, 0, data.length);
-    InputStream rawInput = new ByteArrayInputStream(longerData);
-    assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
-    assertEquals(1, rawInput.available());
-  }
-
-  /**
-   * Parses the given bytes using readRawVarint32() and readRawVarint64() and
-   * expects them to fail with an InvalidProtocolBufferException whose
-   * description matches the given one.
-   */
-  private void assertReadVarintFailure(
-      InvalidProtocolBufferException expected, byte[] data)
-      throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint32();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    input = CodedInputStream.newInstance(data);
-    try {
-      input.readRawVarint64SlowPath();
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-
-    // Make sure we get the same error when reading direct from an InputStream.
-    try {
-      CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(expected.getMessage(), e.getMessage());
-    }
-  }
-
-  /** Tests readRawVarint32() and readRawVarint64(). */
-  public void testReadVarint() throws Exception {
-    assertReadVarint(bytes(0x00), 0);
-    assertReadVarint(bytes(0x01), 1);
-    assertReadVarint(bytes(0x7f), 127);
-    // 14882
-    assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
-    // 2961488830
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x0bL << 28));
-
-    // 64-bit
-    // 7256456126
-    assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x1bL << 28));
-    // 41256202580718336
-    assertReadVarint(
-      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
-      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
-      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
-    // 11964378330978735131
-    assertReadVarint(
-      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
-      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
-      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
-      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
-
-    // Failures
-    assertReadVarintFailure(
-      InvalidProtocolBufferException.malformedVarint(),
-      bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-            0x00));
-    assertReadVarintFailure(
-      InvalidProtocolBufferException.truncatedMessage(),
-      bytes(0x80));
-  }
-
-  /**
-   * Parses the given bytes using readRawLittleEndian32() and checks
-   * that the result matches the given value.
-   */
-  private void assertReadLittleEndian32(byte[] data, int value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian32());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian32());
-      assertTrue(input.isAtEnd());
-    }
-  }
-
-  /**
-   * Parses the given bytes using readRawLittleEndian64() and checks
-   * that the result matches the given value.
-   */
-  private void assertReadLittleEndian64(byte[] data, long value)
-                                        throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(data);
-    assertEquals(value, input.readRawLittleEndian64());
-    assertTrue(input.isAtEnd());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(data, blockSize));
-      assertEquals(value, input.readRawLittleEndian64());
-      assertTrue(input.isAtEnd());
-    }
-  }
-
-  /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
-  public void testReadLittleEndian() throws Exception {
-    assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
-    assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
-
-    assertReadLittleEndian64(
-      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
-      0x123456789abcdef0L);
-    assertReadLittleEndian64(
-      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
-      0x9abcdef012345678L);
-  }
-
-  /** Test decodeZigZag32() and decodeZigZag64(). */
-  public void testDecodeZigZag() throws Exception {
-    assertEquals( 0, CodedInputStream.decodeZigZag32(0));
-    assertEquals(-1, CodedInputStream.decodeZigZag32(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag32(2));
-    assertEquals(-2, CodedInputStream.decodeZigZag32(3));
-    assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
-    assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
-    assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
-    assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
-
-    assertEquals( 0, CodedInputStream.decodeZigZag64(0));
-    assertEquals(-1, CodedInputStream.decodeZigZag64(1));
-    assertEquals( 1, CodedInputStream.decodeZigZag64(2));
-    assertEquals(-2, CodedInputStream.decodeZigZag64(3));
-    assertEquals(0x000000003FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
-    assertEquals(0xFFFFFFFFC0000000L,
-                 CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
-    assertEquals(0x000000007FFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
-    assertEquals(0xFFFFFFFF80000000L,
-                 CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
-    assertEquals(0x7FFFFFFFFFFFFFFFL,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
-    assertEquals(0x8000000000000000L,
-                 CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
-  }
-
-  /** Tests reading and parsing a whole message with every field type. */
-  public void testReadWholeMessage() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-
-    byte[] rawBytes = message.toByteArray();
-    assertEquals(rawBytes.length, message.getSerializedSize());
-
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-    TestUtil.assertAllFieldsSet(message2);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
-      message2 = TestAllTypes.parseFrom(
-        new SmallBlockInputStream(rawBytes, blockSize));
-      TestUtil.assertAllFieldsSet(message2);
-    }
-  }
-
-  /** Tests skipField(). */
-  public void testSkipWholeMessage() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-    byte[] rawBytes = message.toByteArray();
-
-    // Create two parallel inputs.  Parse one as unknown fields while using
-    // skipField() to skip each field on the other.  Expect the same tags.
-    CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
-    CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
-    UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
-
-    while (true) {
-      int tag = input1.readTag();
-      assertEquals(tag, input2.readTag());
-      if (tag == 0) {
-        break;
-      }
-      unknownFields.mergeFieldFrom(tag, input1);
-      input2.skipField(tag);
-    }
-  }
-
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * exactly up to a limit, this should not break things.
-   */
-  public void testSkipRawBytesBug() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2 };
-    CodedInputStream input = CodedInputStream.newInstance(rawBytes);
-
-    int limit = input.pushLimit(1);
-    input.skipRawBytes(1);
-    input.popLimit(limit);
-    assertEquals(2, input.readRawByte());
-  }
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * past the end of a buffer with a limit that has been set past the end of
-   * that buffer, this should not break things.
-   */
-  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(rawBytes, 3));
-
-    int limit = input.pushLimit(4);
-    // In order to expose the bug we need to read at least one byte to prime the
-    // buffer inside the CodedInputStream.
-    assertEquals(1, input.readRawByte());
-    // Skip to the end of the limit.
-    input.skipRawBytes(3);
-    assertTrue(input.isAtEnd());
-    input.popLimit(limit);
-    assertEquals(5, input.readRawByte());
-  }
-
-  public void testReadHugeBlob() throws Exception {
-    // Allocate and initialize a 1MB blob.
-    byte[] blob = new byte[1 << 20];
-    for (int i = 0; i < blob.length; i++) {
-      blob[i] = (byte) i;
-    }
-
-    // Make a message containing it.
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    builder.setOptionalBytes(ByteString.copyFrom(blob));
-    TestAllTypes message = builder.build();
-
-    // Serialize and parse it.  Make sure to parse from an InputStream, not
-    // directly from a ByteString, so that CodedInputStream uses buffered
-    // reading.
-    TestAllTypes message2 =
-      TestAllTypes.parseFrom(message.toByteString().newInput());
-
-    assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
-
-    // Make sure all the other fields were parsed correctly.
-    TestAllTypes message3 = TestAllTypes.newBuilder(message2)
-      .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
-      .build();
-    TestUtil.assertAllFieldsSet(message3);
-  }
-
-  public void testReadMaliciouslyLargeBlob() throws Exception {
-    ByteString.Output rawOutput = ByteString.newOutput();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-
-    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(0x7FFFFFFF);
-    output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
-    output.flush();
-
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-
-    try {
-      input.readBytes();
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
-    }
-  }
-
-  private TestRecursiveMessage makeRecursiveMessage(int depth) {
-    if (depth == 0) {
-      return TestRecursiveMessage.newBuilder().setI(5).build();
-    } else {
-      return TestRecursiveMessage.newBuilder()
-        .setA(makeRecursiveMessage(depth - 1)).build();
-    }
-  }
-
-  private void assertMessageDepth(TestRecursiveMessage message, int depth) {
-    if (depth == 0) {
-      assertFalse(message.hasA());
-      assertEquals(5, message.getI());
-    } else {
-      assertTrue(message.hasA());
-      assertMessageDepth(message.getA(), depth - 1);
-    }
-  }
-
-  public void testMaliciousRecursion() throws Exception {
-    ByteString data64 = makeRecursiveMessage(64).toByteString();
-    ByteString data65 = makeRecursiveMessage(65).toByteString();
-
-    assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64);
-
-    try {
-      TestRecursiveMessage.parseFrom(data65);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
-    }
-
-    CodedInputStream input = data64.newCodedInput();
-    input.setRecursionLimit(8);
-    try {
-      TestRecursiveMessage.parseFrom(input);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException e) {
-      // success.
-    }
-  }
-
-  private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
-      assertEquals(
-          InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
-          e.getMessage());
-  }
-
-  public void testSizeLimit() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(
-            TestUtil.getAllSet().toByteString().newInput(), 16));
-    input.setSizeLimit(16);
-
-    try {
-      TestAllTypes.parseFrom(input);
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException expected) {
-      checkSizeLimitExceeded(expected);
-    }
-  }
-
-  public void testResetSizeCounter() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(new byte[256], 8));
-    input.setSizeLimit(16);
-    input.readRawBytes(16);
-    assertEquals(16, input.getTotalBytesRead());
-
-    try {
-      input.readRawByte();
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException expected) {
-      checkSizeLimitExceeded(expected);
-    }
-
-    input.resetSizeCounter();
-    assertEquals(0, input.getTotalBytesRead());
-    input.readRawByte();  // No exception thrown.
-    input.resetSizeCounter();
-    assertEquals(0, input.getTotalBytesRead());
-    input.readRawBytes(16);
-    assertEquals(16, input.getTotalBytesRead());
-    input.resetSizeCounter();
-
-    try {
-      input.readRawBytes(17);  // Hits limit again.
-      fail("Should have thrown an exception!");
-    } catch (InvalidProtocolBufferException expected) {
-      checkSizeLimitExceeded(expected);
-    }
-  }
-
-  public void testSizeLimitMultipleMessages() throws Exception {
-    byte[] bytes = new byte[256];
-    for (int i = 0; i < bytes.length; i++) {
-      bytes[i] = (byte) i;
-    }
-    CodedInputStream input = CodedInputStream.newInstance(
-        new SmallBlockInputStream(bytes, 7));
-    input.setSizeLimit(16);
-    for (int i = 0; i < 256 / 16; i++) {
-      byte[] message = input.readRawBytes(16);
-      for (int j = 0; j < message.length; j++) {
-        assertEquals(i * 16 + j, message[j] & 0xff);
-      }
-      assertEquals(16, input.getTotalBytesRead());
-      input.resetSizeCounter();
-      assertEquals(0, input.getTotalBytesRead());
-    }
-  }
-
-  /**
-   * Tests that if we readString invalid UTF-8 bytes, no exception
-   * is thrown.  Instead, the invalid bytes are replaced with the Unicode
-   * "replacement character" U+FFFD.
-   */
-  public void testReadStringInvalidUtf8() throws Exception {
-    ByteString.Output rawOutput = ByteString.newOutput();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-
-    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
-    output.flush();
-
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    String text = input.readString();
-    assertEquals(0xfffd, text.charAt(0));
-  }
-
-  /**
-   * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
-   * InvalidProtocolBufferException is thrown.
-   */
-  public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
-    ByteString.Output rawOutput = ByteString.newOutput();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-
-    int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 0x80 });
-    output.flush();
-
-    CodedInputStream input = rawOutput.toByteString().newCodedInput();
-    assertEquals(tag, input.readTag());
-    try {
-      input.readStringRequireUtf8();
-      fail("Expected invalid UTF-8 exception.");
-    } catch (InvalidProtocolBufferException exception) {
-      assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
-    }
-  }
-
-  public void testReadFromSlice() throws Exception {
-    byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-    CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
-    assertEquals(0, in.getTotalBytesRead());
-    for (int i = 3; i < 8; i++) {
-      assertEquals(i, in.readRawByte());
-      assertEquals(i - 2, in.getTotalBytesRead());
-    }
-    // eof
-    assertEquals(0, in.readTag());
-    assertEquals(5, in.getTotalBytesRead());
-  }
-
-  public void testInvalidTag() throws Exception {
-    // Any tag number which corresponds to field number zero is invalid and
-    // should throw InvalidProtocolBufferException.
-    for (int i = 0; i < 8; i++) {
-      try {
-        CodedInputStream.newInstance(bytes(i)).readTag();
-        fail("Should have thrown an exception.");
-      } catch (InvalidProtocolBufferException e) {
-        assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
-                     e.getMessage());
-      }
-    }
-  }
-
-  public void testReadByteArray() throws Exception {
-    ByteString.Output rawOutput = ByteString.newOutput();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    // Zero-sized bytes field.
-    output.writeRawVarint32(0);
-    // One one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 23 });
-    // Another one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[] { (byte) 45 });
-    // A bytes field large enough that won't fit into the 4K buffer.
-    final int bytesLength = 16 * 1024;
-    byte[] bytes = new byte[bytesLength];
-    bytes[0] = (byte) 67;
-    bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
-    output.writeRawBytes(bytes);
-
-    output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
-
-    byte[] result = inputStream.readByteArray();
-    assertEquals(0, result.length);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 23, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(1, result.length);
-    assertEquals((byte) 45, result[0]);
-    result = inputStream.readByteArray();
-    assertEquals(bytesLength, result.length);
-    assertEquals((byte) 67, result[0]);
-    assertEquals((byte) 89, result[bytesLength - 1]);
-  }
-
-  public void testReadByteBuffer() throws Exception {
-    ByteString.Output rawOutput = ByteString.newOutput();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    // Zero-sized bytes field.
-    output.writeRawVarint32(0);
-    // One one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
-    // Another one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
-    // A bytes field large enough that won't fit into the 4K buffer.
-    final int bytesLength = 16 * 1024;
-    byte[] bytes = new byte[bytesLength];
-    bytes[0] = (byte) 67;
-    bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
-    output.writeRawBytes(bytes);
-
-    output.flush();
-    CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
-
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
-  }
-
-  public void testReadByteBufferAliasing() throws Exception {
-    ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
-    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
-    // Zero-sized bytes field.
-    output.writeRawVarint32(0);
-    // One one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 23});
-    // Another one-byte bytes field
-    output.writeRawVarint32(1);
-    output.writeRawBytes(new byte[]{(byte) 45});
-    // A bytes field large enough that won't fit into the 4K buffer.
-    final int bytesLength = 16 * 1024;
-    byte[] bytes = new byte[bytesLength];
-    bytes[0] = (byte) 67;
-    bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
-    output.writeRawBytes(bytes);
-    output.flush();
-    byte[] data = byteArrayStream.toByteArray();
-
-    // Without aliasing
-    CodedInputStream inputStream = CodedInputStream.newInstance(data);
-    ByteBuffer result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() != data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
-
-    // Enable aliasing
-    inputStream = CodedInputStream.newInstance(data);
-    inputStream.enableAliasing(true);
-    result = inputStream.readByteBuffer();
-    assertEquals(0, result.capacity());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 23, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(1, result.capacity());
-    assertEquals((byte) 45, result.get());
-    result = inputStream.readByteBuffer();
-    assertTrue(result.array() == data);
-    assertEquals(bytesLength, result.capacity());
-    assertEquals((byte) 67, result.get());
-    result.position(bytesLength - 1);
-    assertEquals((byte) 89, result.get());
-  }
-
-  public void testCompatibleTypes() throws Exception {
-    long data = 0x100000000L;
-    Int64Message message = Int64Message.newBuilder().setData(data).build();
-    ByteString serialized = message.toByteString();
-
-    // Test int64(long) is compatible with bool(boolean)
-    BoolMessage msg2 = BoolMessage.parseFrom(serialized);
-    assertTrue(msg2.getData());
-
-    // Test int64(long) is compatible with int32(int)
-    Int32Message msg3 = Int32Message.parseFrom(serialized);
-    assertEquals((int) data, msg3.getData());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
deleted file mode 100644
index 0785cc9..0000000
--- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ /dev/null
@@ -1,401 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.SparseEnumMessage;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestProto.TestSparseEnum;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit test for {@link CodedOutputStream}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class CodedOutputStreamTest extends TestCase {
-  /**
-   * Helper to construct a byte array from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
-   */
-  private byte[] bytes(int... bytesAsInts) {
-    byte[] bytes = new byte[bytesAsInts.length];
-    for (int i = 0; i < bytesAsInts.length; i++) {
-      bytes[i] = (byte) bytesAsInts[i];
-    }
-    return bytes;
-  }
-
-  /** Arrays.asList() does not work with arrays of primitives.  :( */
-  private List<Byte> toList(byte[] bytes) {
-    List<Byte> result = new ArrayList<Byte>();
-    for (byte b : bytes) {
-      result.add(b);
-    }
-    return result;
-  }
-
-  private void assertEqualBytes(byte[] a, byte[] b) {
-    assertEquals(toList(a), toList(b));
-  }
-
-  /**
-   * Writes the given value using writeRawVarint32() and writeRawVarint64() and
-   * checks that the result matches the given bytes.
-   */
-  private void assertWriteVarint(byte[] data, long value) throws Exception {
-    // Only do 32-bit write if the value fits in 32 bits.
-    if ((value >>> 32) == 0) {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint32((int) value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-
-      // Also try computing size.
-      assertEquals(data.length,
-                   CodedOutputStream.computeRawVarint32Size((int) value));
-    }
-
-    {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-      output.writeRawVarint64(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-
-      // Also try computing size.
-      assertEquals(data.length,
-                   CodedOutputStream.computeRawVarint64Size(value));
-    }
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      // Only do 32-bit write if the value fits in 32 bits.
-      if ((value >>> 32) == 0) {
-        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-        CodedOutputStream output =
-          CodedOutputStream.newInstance(rawOutput, blockSize);
-        output.writeRawVarint32((int) value);
-        output.flush();
-        assertEqualBytes(data, rawOutput.toByteArray());
-      }
-
-      {
-        ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-        CodedOutputStream output =
-          CodedOutputStream.newInstance(rawOutput, blockSize);
-        output.writeRawVarint64(value);
-        output.flush();
-        assertEqualBytes(data, rawOutput.toByteArray());
-      }
-    }
-  }
-
-  /** Tests writeRawVarint32() and writeRawVarint64(). */
-  public void testWriteVarint() throws Exception {
-    assertWriteVarint(bytes(0x00), 0);
-    assertWriteVarint(bytes(0x01), 1);
-    assertWriteVarint(bytes(0x7f), 127);
-    // 14882
-    assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
-    // 2961488830
-    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x0bL << 28));
-
-    // 64-bit
-    // 7256456126
-    assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
-      (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
-      (0x1bL << 28));
-    // 41256202580718336
-    assertWriteVarint(
-      bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
-      (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
-      (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
-    // 11964378330978735131
-    assertWriteVarint(
-      bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
-      (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
-      (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
-      (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
-  }
-
-  /**
-   * Parses the given bytes using writeRawLittleEndian32() and checks
-   * that the result matches the given value.
-   */
-  private void assertWriteLittleEndian32(byte[] data, int value)
-                                         throws Exception {
-    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawLittleEndian32(value);
-    output.flush();
-    assertEqualBytes(data, rawOutput.toByteArray());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      rawOutput = new ByteArrayOutputStream();
-      output = CodedOutputStream.newInstance(rawOutput, blockSize);
-      output.writeRawLittleEndian32(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-    }
-  }
-
-  /**
-   * Parses the given bytes using writeRawLittleEndian64() and checks
-   * that the result matches the given value.
-   */
-  private void assertWriteLittleEndian64(byte[] data, long value)
-                                         throws Exception {
-    ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-    CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawLittleEndian64(value);
-    output.flush();
-    assertEqualBytes(data, rawOutput.toByteArray());
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      rawOutput = new ByteArrayOutputStream();
-      output = CodedOutputStream.newInstance(rawOutput, blockSize);
-      output.writeRawLittleEndian64(value);
-      output.flush();
-      assertEqualBytes(data, rawOutput.toByteArray());
-    }
-  }
-
-  /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
-  public void testWriteLittleEndian() throws Exception {
-    assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
-    assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
-
-    assertWriteLittleEndian64(
-      bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
-      0x123456789abcdef0L);
-    assertWriteLittleEndian64(
-      bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
-      0x9abcdef012345678L);
-  }
-
-  /** Test encodeZigZag32() and encodeZigZag64(). */
-  public void testEncodeZigZag() throws Exception {
-    assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
-    assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
-    assertEquals(2, CodedOutputStream.encodeZigZag32( 1));
-    assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
-    assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
-    assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
-    assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
-    assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
-
-    assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
-    assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
-    assertEquals(2, CodedOutputStream.encodeZigZag64( 1));
-    assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
-    assertEquals(0x000000007FFFFFFEL,
-                 CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
-    assertEquals(0x000000007FFFFFFFL,
-                 CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
-    assertEquals(0x00000000FFFFFFFEL,
-                 CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
-    assertEquals(0x00000000FFFFFFFFL,
-                 CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
-    assertEquals(0xFFFFFFFFFFFFFFFEL,
-                 CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
-    assertEquals(0xFFFFFFFFFFFFFFFFL,
-                 CodedOutputStream.encodeZigZag64(0x8000000000000000L));
-
-    // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
-    // were chosen semi-randomly via keyboard bashing.
-    assertEquals(0,
-      CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
-    assertEquals(1,
-      CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
-    assertEquals(-1,
-      CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
-    assertEquals(14927,
-      CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
-    assertEquals(-3612,
-      CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
-
-    assertEquals(0,
-      CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
-    assertEquals(1,
-      CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
-    assertEquals(-1,
-      CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
-    assertEquals(14927,
-      CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
-    assertEquals(-3612,
-      CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
-
-    assertEquals(856912304801416L,
-      CodedOutputStream.encodeZigZag64(
-        CodedInputStream.decodeZigZag64(
-          856912304801416L)));
-    assertEquals(-75123905439571256L,
-      CodedOutputStream.encodeZigZag64(
-        CodedInputStream.decodeZigZag64(
-          -75123905439571256L)));
-  }
-
-  /** Tests writing a whole message with every field type. */
-  public void testWriteWholeMessage() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-
-    byte[] rawBytes = message.toByteArray();
-    assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
-
-    // Try different block sizes.
-    for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
-      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
-      CodedOutputStream output =
-        CodedOutputStream.newInstance(rawOutput, blockSize);
-      message.writeTo(output);
-      output.flush();
-      assertEqualBytes(rawBytes, rawOutput.toByteArray());
-    }
-  }
-
-  /** Tests writing a whole message with every packed field type. Ensures the
-   * wire format of packed fields is compatible with C++. */
-  public void testWriteWholePackedFieldsMessage() throws Exception {
-    TestPackedTypes message = TestUtil.getPackedSet();
-
-    byte[] rawBytes = message.toByteArray();
-    assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
-                     rawBytes);
-  }
-
-  /** Test writing a message containing a negative enum value. This used to
-   * fail because the size was not properly computed as a sign-extended varint.
-   */
-  public void testWriteMessageWithNegativeEnumValue() throws Exception {
-    SparseEnumMessage message = SparseEnumMessage.newBuilder()
-        .setSparseEnum(TestSparseEnum.SPARSE_E) .build();
-    assertTrue(message.getSparseEnum().getNumber() < 0);
-    byte[] rawBytes = message.toByteArray();
-    SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
-    assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
-  }
-
-  /** Test getTotalBytesWritten() */
-  public void testGetTotalBytesWritten() throws Exception {
-    final int BUFFER_SIZE = 4 * 1024;
-    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE);
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
-    byte[] value = "abcde".getBytes("UTF-8");
-    for (int i = 0; i < 1024; ++i) {
-      codedStream.writeRawBytes(value, 0, value.length);
-    }
-    // Make sure we have written more bytes than the buffer could hold. This is
-    // to make the test complete.
-    assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
-    assertEquals(value.length * 1024, codedStream.getTotalBytesWritten());
-  }
-  
-  public void testWriteToByteBuffer() throws Exception {
-    final int bufferSize = 16 * 1024;
-    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(buffer);
-    // Write raw bytes into the ByteBuffer.
-    final int length1 = 5000;
-    for (int i = 0; i < length1; i++) {
-      codedStream.writeRawByte((byte) 1);
-    }
-    final int length2 = 8 * 1024;
-    byte[] data = new byte[length2];
-    for (int i = 0; i < length2; i++) {
-      data[i] = (byte) 2;
-    }
-    codedStream.writeRawBytes(data);
-    final int length3 = bufferSize - length1 - length2;
-    for (int i = 0; i < length3; i++) {
-      codedStream.writeRawByte((byte) 3);
-    }
-    codedStream.flush();
-    
-    // Check that data is correctly written to the ByteBuffer.
-    assertEquals(0, buffer.remaining());
-    buffer.flip();
-    for (int i = 0; i < length1; i++) {
-      assertEquals((byte) 1, buffer.get());
-    }
-    for (int i = 0; i < length2; i++) {
-      assertEquals((byte) 2, buffer.get());
-    }
-    for (int i = 0; i < length3; i++) {
-      assertEquals((byte) 3, buffer.get());
-    }
-  }
-  
-  public void testWriteByteBuffer() throws Exception {
-    byte[] value = "abcde".getBytes("UTF-8");
-    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream);
-    ByteBuffer byteBuffer = ByteBuffer.wrap(value, 0, 1);
-    // This will actually write 5 bytes into the CodedOutputStream as the
-    // ByteBuffer's capacity() is 5.
-    codedStream.writeRawBytes(byteBuffer);
-    // The above call shouldn't affect the ByteBuffer's state.
-    assertEquals(0, byteBuffer.position());
-    assertEquals(1, byteBuffer.limit());
-    
-    // The correct way to write part of an array using ByteBuffer.
-    codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice());
-    
-    codedStream.flush();
-    byte[] result = outputStream.toByteArray();
-    assertEquals(6, result.length);
-    for (int i = 0; i < 5; i++) {
-      assertEquals(value[i], result[i]);
-    }
-    assertEquals(value[2], result[5]);
-  }
-
-  public void testWriteByteArrayWithOffsets() throws Exception {
-    byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
-    byte[] destination = new byte[4];
-    CodedOutputStream codedStream = CodedOutputStream.newInstance(destination);
-    codedStream.writeByteArrayNoTag(fullArray, 2, 2);
-    assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
-    assertEquals(3, codedStream.getTotalBytesWritten());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
deleted file mode 100644
index e7905f7..0000000
--- a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestDeprecatedFields;
-
-import junit.framework.TestCase;
-
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Method;
-/**
- * Test field deprecation
- * 
- * @author birdo@google.com (Roberto Scaramuzzi)
- */
-public class DeprecatedFieldTest extends TestCase {
-  private String[] deprecatedGetterNames = {
-      "hasDeprecatedInt32",
-      "getDeprecatedInt32"};
-  
-  private String[] deprecatedBuilderGetterNames = {
-      "hasDeprecatedInt32",
-      "getDeprecatedInt32",
-      "clearDeprecatedInt32"};
-  
-  private String[] deprecatedBuilderSetterNames = {
-      "setDeprecatedInt32"}; 
-  
-  public void testDeprecatedField() throws Exception {
-    Class<?> deprecatedFields = TestDeprecatedFields.class;
-    Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
-    for (String name : deprecatedGetterNames) {
-      Method method = deprecatedFields.getMethod(name);
-      assertTrue("Method " + name + " should be deprecated",
-          isDeprecated(method));
-    }
-    for (String name : deprecatedBuilderGetterNames) {
-      Method method = deprecatedFieldsBuilder.getMethod(name);
-      assertTrue("Method " + name + " should be deprecated",
-          isDeprecated(method));
-    }
-    for (String name : deprecatedBuilderSetterNames) {
-      Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
-      assertTrue("Method " + name + " should be deprecated",
-          isDeprecated(method));
-    }
-  }
-  
-  private boolean isDeprecated(AnnotatedElement annotated) {
-    return annotated.isAnnotationPresent(Deprecated.class);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
deleted file mode 100644
index 0092771..0000000
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ /dev/null
@@ -1,735 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.DescriptorProtos.DescriptorProto;
-import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
-import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
-import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
-import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
-import com.google.protobuf.Descriptors.DescriptorValidationException;
-import com.google.protobuf.Descriptors.FileDescriptor;
-import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-import com.google.protobuf.Descriptors.EnumDescriptor;
-import com.google.protobuf.Descriptors.EnumValueDescriptor;
-import com.google.protobuf.Descriptors.ServiceDescriptor;
-import com.google.protobuf.Descriptors.MethodDescriptor;
-
-import com.google.protobuf.test.UnittestImport;
-import com.google.protobuf.test.UnittestImport.ImportEnum;
-import com.google.protobuf.test.UnittestImport.ImportMessage;
-import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
-import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
-import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto.TestService;
-import protobuf_unittest.UnittestCustomOptions;
-
-import protobuf_unittest.TestCustomOptions;
-
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Unit test for {@link Descriptors}.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class DescriptorsTest extends TestCase {
-
-  // Regression test for bug where referencing a FieldDescriptor.Type value
-  // before a FieldDescriptorProto.Type value would yield a
-  // ExceptionInInitializerError.
-  @SuppressWarnings("unused")
-  private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
-
-  public void testFieldTypeEnumMapping() throws Exception {
-    assertEquals(FieldDescriptor.Type.values().length,
-        FieldDescriptorProto.Type.values().length);
-    for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
-      FieldDescriptorProto.Type protoType = type.toProto();
-      assertEquals("TYPE_" + type.name(), protoType.name());
-      assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
-    }
-  }
-
-  public void testFileDescriptor() throws Exception {
-    FileDescriptor file = UnittestProto.getDescriptor();
-
-    assertEquals("google/protobuf/unittest.proto", file.getName());
-    assertEquals("protobuf_unittest", file.getPackage());
-
-    assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
-    assertEquals("google/protobuf/unittest.proto",
-                 file.toProto().getName());
-
-    assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
-                 file.getDependencies());
-
-    Descriptor messageType = TestAllTypes.getDescriptor();
-    assertEquals(messageType, file.getMessageTypes().get(0));
-    assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
-    assertNull(file.findMessageTypeByName("NoSuchType"));
-    assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
-    for (int i = 0; i < file.getMessageTypes().size(); i++) {
-      assertEquals(i, file.getMessageTypes().get(i).getIndex());
-    }
-
-    EnumDescriptor enumType = ForeignEnum.getDescriptor();
-    assertEquals(enumType, file.getEnumTypes().get(0));
-    assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
-    assertNull(file.findEnumTypeByName("NoSuchType"));
-    assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
-    assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
-                 UnittestImport.getDescriptor().getEnumTypes());
-    for (int i = 0; i < file.getEnumTypes().size(); i++) {
-      assertEquals(i, file.getEnumTypes().get(i).getIndex());
-    }
-
-    ServiceDescriptor service = TestService.getDescriptor();
-    assertEquals(service, file.getServices().get(0));
-    assertEquals(service, file.findServiceByName("TestService"));
-    assertNull(file.findServiceByName("NoSuchType"));
-    assertNull(file.findServiceByName("protobuf_unittest.TestService"));
-    assertEquals(Collections.emptyList(),
-                 UnittestImport.getDescriptor().getServices());
-    for (int i = 0; i < file.getServices().size(); i++) {
-      assertEquals(i, file.getServices().get(i).getIndex());
-    }
-
-    FieldDescriptor extension =
-      UnittestProto.optionalInt32Extension.getDescriptor();
-    assertEquals(extension, file.getExtensions().get(0));
-    assertEquals(extension,
-                 file.findExtensionByName("optional_int32_extension"));
-    assertNull(file.findExtensionByName("no_such_ext"));
-    assertNull(file.findExtensionByName(
-      "protobuf_unittest.optional_int32_extension"));
-    assertEquals(Collections.emptyList(),
-                 UnittestImport.getDescriptor().getExtensions());
-    for (int i = 0; i < file.getExtensions().size(); i++) {
-      assertEquals(i, file.getExtensions().get(i).getIndex());
-    }
-  }
-
-  public void testDescriptor() throws Exception {
-    Descriptor messageType = TestAllTypes.getDescriptor();
-    Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
-
-    assertEquals("TestAllTypes", messageType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
-    assertNull(messageType.getContainingType());
-    assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
-                 messageType.getOptions());
-    assertEquals("TestAllTypes", messageType.toProto().getName());
-
-    assertEquals("NestedMessage", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
-                 nestedType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
-    assertEquals(messageType, nestedType.getContainingType());
-
-    FieldDescriptor field = messageType.getFields().get(0);
-    assertEquals("optional_int32", field.getName());
-    assertEquals(field, messageType.findFieldByName("optional_int32"));
-    assertNull(messageType.findFieldByName("no_such_field"));
-    assertEquals(field, messageType.findFieldByNumber(1));
-    assertNull(messageType.findFieldByNumber(571283));
-    for (int i = 0; i < messageType.getFields().size(); i++) {
-      assertEquals(i, messageType.getFields().get(i).getIndex());
-    }
-
-    assertEquals(nestedType, messageType.getNestedTypes().get(0));
-    assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
-    assertNull(messageType.findNestedTypeByName("NoSuchType"));
-    for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
-      assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
-    }
-
-    EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
-    assertEquals(enumType, messageType.getEnumTypes().get(0));
-    assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
-    assertNull(messageType.findEnumTypeByName("NoSuchType"));
-    for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
-      assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
-    }
-  }
-
-  public void testFieldDescriptor() throws Exception {
-    Descriptor messageType = TestAllTypes.getDescriptor();
-    FieldDescriptor primitiveField =
-      messageType.findFieldByName("optional_int32");
-    FieldDescriptor enumField =
-      messageType.findFieldByName("optional_nested_enum");
-    FieldDescriptor messageField =
-      messageType.findFieldByName("optional_foreign_message");
-    FieldDescriptor cordField =
-      messageType.findFieldByName("optional_cord");
-    FieldDescriptor extension =
-      UnittestProto.optionalInt32Extension.getDescriptor();
-    FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
-
-    assertEquals("optional_int32", primitiveField.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
-                 primitiveField.getFullName());
-    assertEquals(1, primitiveField.getNumber());
-    assertEquals(messageType, primitiveField.getContainingType());
-    assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
-    assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
-    assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
-                 primitiveField.getOptions());
-    assertFalse(primitiveField.isExtension());
-    assertEquals("optional_int32", primitiveField.toProto().getName());
-
-    assertEquals("optional_nested_enum", enumField.getName());
-    assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
-    assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
-    assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
-                 enumField.getEnumType());
-
-    assertEquals("optional_foreign_message", messageField.getName());
-    assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
-    assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
-    assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
-
-    assertEquals("optional_cord", cordField.getName());
-    assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
-    assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
-                 cordField.getOptions().getCtype());
-
-    assertEquals("optional_int32_extension", extension.getName());
-    assertEquals("protobuf_unittest.optional_int32_extension",
-                 extension.getFullName());
-    assertEquals(1, extension.getNumber());
-    assertEquals(TestAllExtensions.getDescriptor(),
-                 extension.getContainingType());
-    assertEquals(UnittestProto.getDescriptor(), extension.getFile());
-    assertEquals(FieldDescriptor.Type.INT32, extension.getType());
-    assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
-                 extension.getOptions());
-    assertTrue(extension.isExtension());
-    assertEquals(null, extension.getExtensionScope());
-    assertEquals("optional_int32_extension", extension.toProto().getName());
-
-    assertEquals("single", nestedExtension.getName());
-    assertEquals("protobuf_unittest.TestRequired.single",
-                 nestedExtension.getFullName());
-    assertEquals(TestRequired.getDescriptor(),
-                 nestedExtension.getExtensionScope());
-  }
-
-  public void testFieldDescriptorLabel() throws Exception {
-    FieldDescriptor requiredField =
-      TestRequired.getDescriptor().findFieldByName("a");
-    FieldDescriptor optionalField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_int32");
-    FieldDescriptor repeatedField =
-      TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
-
-    assertTrue(requiredField.isRequired());
-    assertFalse(requiredField.isRepeated());
-    assertFalse(optionalField.isRequired());
-    assertFalse(optionalField.isRepeated());
-    assertFalse(repeatedField.isRequired());
-    assertTrue(repeatedField.isRepeated());
-  }
-
-  public void testFieldDescriptorDefault() throws Exception {
-    Descriptor d = TestAllTypes.getDescriptor();
-    assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
-    assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
-    assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
-    assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
-
-    d = TestExtremeDefaultValues.getDescriptor();
-    assertEquals(
-      ByteString.copyFrom(
-        "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
-      d.findFieldByName("escaped_bytes").getDefaultValue());
-    assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
-    assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
-  }
-
-  public void testEnumDescriptor() throws Exception {
-    EnumDescriptor enumType = ForeignEnum.getDescriptor();
-    EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
-
-    assertEquals("ForeignEnum", enumType.getName());
-    assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
-    assertNull(enumType.getContainingType());
-    assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
-                 enumType.getOptions());
-
-    assertEquals("NestedEnum", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
-                 nestedType.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
-    assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
-
-    EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
-    assertEquals(value, enumType.getValues().get(0));
-    assertEquals("FOREIGN_FOO", value.getName());
-    assertEquals("FOREIGN_FOO", value.toString());
-    assertEquals(4, value.getNumber());
-    assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
-    assertEquals(value, enumType.findValueByNumber(4));
-    assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
-    for (int i = 0; i < enumType.getValues().size(); i++) {
-      assertEquals(i, enumType.getValues().get(i).getIndex());
-    }
-  }
-
-  public void testServiceDescriptor() throws Exception {
-    ServiceDescriptor service = TestService.getDescriptor();
-
-    assertEquals("TestService", service.getName());
-    assertEquals("protobuf_unittest.TestService", service.getFullName());
-    assertEquals(UnittestProto.getDescriptor(), service.getFile());
-
-
-    MethodDescriptor fooMethod = service.getMethods().get(0);
-    assertEquals("Foo", fooMethod.getName());
-    assertEquals(UnittestProto.FooRequest.getDescriptor(),
-                 fooMethod.getInputType());
-    assertEquals(UnittestProto.FooResponse.getDescriptor(),
-                 fooMethod.getOutputType());
-    assertEquals(fooMethod, service.findMethodByName("Foo"));
-
-    MethodDescriptor barMethod = service.getMethods().get(1);
-    assertEquals("Bar", barMethod.getName());
-    assertEquals(UnittestProto.BarRequest.getDescriptor(),
-                 barMethod.getInputType());
-    assertEquals(UnittestProto.BarResponse.getDescriptor(),
-                 barMethod.getOutputType());
-    assertEquals(barMethod, service.findMethodByName("Bar"));
-
-    assertNull(service.findMethodByName("NoSuchMethod"));
-
-    for (int i = 0; i < service.getMethods().size(); i++) {
-      assertEquals(i, service.getMethods().get(i).getIndex());
-    }
-  }
-
-
-  public void testCustomOptions() throws Exception {
-    // Get the descriptor indirectly from a dependent proto class. This is to
-    // ensure that when a proto class is loaded, custom options defined in its
-    // dependencies are also properly initialized.
-    Descriptor descriptor =
-        TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
-        .findFieldByName("field").getMessageType();
-
-    assertTrue(
-      descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
-    assertEquals(Integer.valueOf(-56),
-      descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
-
-    FieldDescriptor field = descriptor.findFieldByName("field1");
-    assertNotNull(field);
-
-    assertTrue(
-      field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
-    assertEquals(Long.valueOf(8765432109L),
-      field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
-
-    EnumDescriptor enumType =
-      UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
-
-    assertTrue(
-      enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
-    assertEquals(Integer.valueOf(-789),
-      enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
-
-    ServiceDescriptor service =
-      UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
-
-    assertTrue(
-      service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
-    assertEquals(Long.valueOf(-9876543210L),
-      service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
-
-    MethodDescriptor method = service.findMethodByName("Foo");
-    assertNotNull(method);
-
-    assertTrue(
-      method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
-    assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
-      method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
-  }
-
-  /**
-   * Test that the FieldDescriptor.Type enum is the same as the
-   * WireFormat.FieldType enum.
-   */
-  public void testFieldTypeTablesMatch() throws Exception {
-    FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
-    WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
-
-    assertEquals(values1.length, values2.length);
-
-    for (int i = 0; i < values1.length; i++) {
-      assertEquals(values1[i].toString(), values2[i].toString());
-    }
-  }
-
-  /**
-   * Test that the FieldDescriptor.JavaType enum is the same as the
-   * WireFormat.JavaType enum.
-   */
-  public void testJavaTypeTablesMatch() throws Exception {
-    FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
-    WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
-
-    assertEquals(values1.length, values2.length);
-
-    for (int i = 0; i < values1.length; i++) {
-      assertEquals(values1[i].toString(), values2[i].toString());
-    }
-  }
-
-  public void testEnormousDescriptor() throws Exception {
-    // The descriptor for this file is larger than 64k, yet it did not cause
-    // a compiler error due to an over-long string literal.
-    assertTrue(
-        UnittestEnormousDescriptor.getDescriptor()
-          .toProto().getSerializedSize() > 65536);
-  }
-
-  /**
-   * Tests that the DescriptorValidationException works as intended.
-   */
-  public void testDescriptorValidatorException() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-      .setName("foo.proto")
-      .addMessageType(DescriptorProto.newBuilder()
-      .setName("Foo")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setType(FieldDescriptorProto.Type.TYPE_INT32)
-          .setName("foo")
-          .setNumber(1)
-          .setDefaultValue("invalid")
-          .build())
-        .build())
-      .build();
-    try {
-      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
-          new FileDescriptor[0]);
-      fail("DescriptorValidationException expected");
-    } catch (DescriptorValidationException e) {
-      // Expected; check that the error message contains some useful hints
-      assertTrue(e.getMessage().indexOf("foo") != -1);
-      assertTrue(e.getMessage().indexOf("Foo") != -1);
-      assertTrue(e.getMessage().indexOf("invalid") != -1);
-      assertTrue(e.getCause() instanceof NumberFormatException);
-      assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
-    }
-  }
-
-  /**
-   * Tests the translate/crosslink for an example where a message field's name
-   * and type name are the same.
-   */
-  public void testDescriptorComplexCrosslink() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-      .setName("foo.proto")
-      .addMessageType(DescriptorProto.newBuilder()
-        .setName("Foo")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setType(FieldDescriptorProto.Type.TYPE_INT32)
-          .setName("foo")
-          .setNumber(1)
-          .build())
-        .build())
-      .addMessageType(DescriptorProto.newBuilder()
-        .setName("Bar")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setTypeName("Foo")
-          .setName("Foo")
-          .setNumber(1)
-          .build())
-        .build())
-      .build();
-    // translate and crosslink
-    FileDescriptor file =
-      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, 
-          new FileDescriptor[0]);
-    // verify resulting descriptors
-    assertNotNull(file);
-    List<Descriptor> msglist = file.getMessageTypes();
-    assertNotNull(msglist);
-    assertTrue(msglist.size() == 2);
-    boolean barFound = false;
-    for (Descriptor desc : msglist) {
-      if (desc.getName().equals("Bar")) {
-        barFound = true;
-        assertNotNull(desc.getFields());
-        List<FieldDescriptor> fieldlist = desc.getFields();
-        assertNotNull(fieldlist);
-        assertTrue(fieldlist.size() == 1);
-        assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
-        assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
-      }
-    }
-    assertTrue(barFound);
-  }
-  
-  public void testDependencyOrder() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto").build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addDependency("foo.proto")
-        .build();
-    FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
-        .setName("baz.proto")
-        .addDependency("foo.proto")
-        .addDependency("bar.proto")
-        .addPublicDependency(0)
-        .addPublicDependency(1)
-        .build();
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
-        new FileDescriptor[0]);
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
-        new FileDescriptor[] {fooFile});
-    
-    // Items in the FileDescriptor array can be in any order. 
-    Descriptors.FileDescriptor.buildFrom(bazProto,
-        new FileDescriptor[] {fooFile, barFile});
-    Descriptors.FileDescriptor.buildFrom(bazProto,
-        new FileDescriptor[] {barFile, fooFile});
-  }
-  
-  public void testInvalidPublicDependency() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto").build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("boo.proto")
-        .addDependency("foo.proto")
-        .addPublicDependency(1)  // Error, should be 0.
-        .build();
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
-        new FileDescriptor[0]);
-    try {
-      Descriptors.FileDescriptor.buildFrom(barProto,
-          new FileDescriptor[] {fooFile});
-      fail("DescriptorValidationException expected");
-    } catch (DescriptorValidationException e) {
-      assertTrue(
-          e.getMessage().indexOf("Invalid public dependency index.") != -1);
-    }
-  }
-
-  public void testHiddenDependency() throws Exception {
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
-        .build();
-    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
-        .setName("forward.proto")
-        .addDependency("bar.proto")
-        .build();
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("forward.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[0]);
-    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
-        forwardProto, new FileDescriptor[] {barFile});
-
-    try {
-      Descriptors.FileDescriptor.buildFrom(
-          fooProto, new FileDescriptor[] {forwardFile});
-      fail("DescriptorValidationException expected");
-    } catch (DescriptorValidationException e) {
-      assertTrue(e.getMessage().indexOf("Bar") != -1);
-      assertTrue(e.getMessage().indexOf("is not defined") != -1);
-    }
-  }
-
-  public void testPublicDependency() throws Exception {
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
-        .build();
-    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
-        .setName("forward.proto")
-        .addDependency("bar.proto")
-        .addPublicDependency(0)
-        .build();
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("forward.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[0]);
-    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
-        forwardProto, new FileDescriptor[]{barFile});
-    Descriptors.FileDescriptor.buildFrom(
-        fooProto, new FileDescriptor[] {forwardFile});
-  }
-  
-  /**
-   * Tests the translate/crosslink for an example with a more complex namespace
-   * referencing.
-   */
-  public void testComplexNamespacePublicDependency() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .setPackage("a.b.c.d.bar.shared")
-        .addEnumType(EnumDescriptorProto.newBuilder()
-            .setName("MyEnum")
-            .addValue(EnumValueDescriptorProto.newBuilder()
-                .setName("BLAH")
-                .setNumber(1)))
-        .build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("bar.proto")
-        .setPackage("a.b.c.d.foo.shared")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("MyMessage")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
-                .setTypeName("bar.shared.MyEnum")
-                .setName("MyField")
-                .setNumber(1)))
-        .build();
-    // translate and crosslink
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
-        fooProto, new FileDescriptor[0]);
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[]{fooFile});
-    // verify resulting descriptors
-    assertNotNull(barFile);
-    List<Descriptor> msglist = barFile.getMessageTypes();
-    assertNotNull(msglist);
-    assertTrue(msglist.size() == 1);
-    Descriptor desc = msglist.get(0);
-    if (desc.getName().equals("MyMessage")) {
-      assertNotNull(desc.getFields());
-      List<FieldDescriptor> fieldlist = desc.getFields();
-      assertNotNull(fieldlist);
-      assertTrue(fieldlist.size() == 1);
-      FieldDescriptor field = fieldlist.get(0);
-      assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
-      assertTrue(field.getEnumType().getName().equals("MyEnum"));
-      assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
-      assertTrue(field.getEnumType().getFile().getPackage().equals(
-          "a.b.c.d.bar.shared"));
-    }   
-  }
-
-  public void testOneofDescriptor() throws Exception {
-    Descriptor messageType = TestAllTypes.getDescriptor();
-    FieldDescriptor field =
-        messageType.findFieldByName("oneof_nested_message");
-    OneofDescriptor oneofDescriptor = field.getContainingOneof();
-    assertNotNull(oneofDescriptor);
-    assertSame(oneofDescriptor, messageType.getOneofs().get(0));
-    assertEquals("oneof_field", oneofDescriptor.getName());
-
-    assertEquals(4, oneofDescriptor.getFieldCount());
-    assertSame(oneofDescriptor.getField(1), field);
-  }
-
-  public void testMessageDescriptorExtensions() throws Exception {
-    assertFalse(TestAllTypes.getDescriptor().isExtendable());
-    assertTrue(TestAllExtensions.getDescriptor().isExtendable());
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
-
-    assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
-    assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
-    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
-    assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
-    assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
-  }
-
-  public void testPackedEnumField() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addEnumType(EnumDescriptorProto.newBuilder()
-          .setName("Enum")
-          .addValue(EnumValueDescriptorProto.newBuilder()
-            .setName("FOO")
-            .setNumber(1)
-            .build())
-          .build())
-        .addMessageType(DescriptorProto.newBuilder()
-          .setName("Message")
-          .addField(FieldDescriptorProto.newBuilder()
-            .setName("foo")
-            .setTypeName("Enum")
-            .setNumber(1)
-            .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
-            .setOptions(DescriptorProtos.FieldOptions.newBuilder()
-              .setPacked(true)
-              .build())
-            .build())
-          .build())
-        .build();
-    Descriptors.FileDescriptor.buildFrom(
-        fileDescriptorProto, new FileDescriptor[0]);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
deleted file mode 100644
index 55144e7..0000000
--- a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ /dev/null
@@ -1,326 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.EnumDescriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.Descriptors.OneofDescriptor;
-
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestEmptyMessage;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-
-import junit.framework.TestCase;
-import java.util.Arrays;
-
-/**
- * Unit test for {@link DynamicMessage}.  See also {@link MessageTest}, which
- * tests some {@link DynamicMessage} functionality.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class DynamicMessageTest extends TestCase {
-  TestUtil.ReflectionTester reflectionTester =
-    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
-
-  TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
-  TestUtil.ReflectionTester packedReflectionTester =
-    new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
-
-  public void testDynamicMessageAccessors() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.setAllFieldsViaReflection(builder);
-    Message message = builder.build();
-    reflectionTester.assertAllFieldsSetViaReflection(message);
-  }
-
-  public void testSettersAfterBuild() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    Message firstMessage = builder.build();
-    // double build()
-    builder.build();
-    // clear() after build()
-    builder.clear();
-    // setters after build()
-    reflectionTester.setAllFieldsViaReflection(builder);
-    Message message = builder.build();
-    reflectionTester.assertAllFieldsSetViaReflection(message);
-    // repeated setters after build()
-    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
-    message = builder.build();
-    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
-    // firstMessage shouldn't have been modified.
-    reflectionTester.assertClearViaReflection(firstMessage);
-  }
-
-  public void testUnknownFields() throws Exception {
-    Message.Builder builder =
-        DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
-    builder.setUnknownFields(UnknownFieldSet.newBuilder()
-        .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
-        .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
-        .build());
-    Message message = builder.build();
-    assertEquals(2, message.getUnknownFields().asMap().size());
-    // clone() with unknown fields
-    Message.Builder newBuilder = builder.clone();
-    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
-    // clear() with unknown fields
-    newBuilder.clear();
-    assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
-    // serialize/parse with unknown fields
-    newBuilder.mergeFrom(message.toByteString());
-    assertEquals(2, newBuilder.getUnknownFields().asMap().size());
-  }
-
-  public void testDynamicMessageSettersRejectNull() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.assertReflectionSettersRejectNull(builder);
-  }
-
-  public void testDynamicMessageExtensionAccessors() throws Exception {
-    // We don't need to extensively test DynamicMessage's handling of
-    // extensions because, frankly, it doesn't do anything special with them.
-    // It treats them just like any other fields.
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
-    extensionsReflectionTester.setAllFieldsViaReflection(builder);
-    Message message = builder.build();
-    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
-  }
-
-  public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
-    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
-  }
-
-  public void testDynamicMessageRepeatedSetters() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.setAllFieldsViaReflection(builder);
-    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
-    Message message = builder.build();
-    reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
-  }
-
-  public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
-  }
-
-  public void testDynamicMessageDefaults() throws Exception {
-    reflectionTester.assertClearViaReflection(
-      DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
-    reflectionTester.assertClearViaReflection(
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
-  }
-
-  public void testDynamicMessageSerializedSize() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-
-    Message.Builder dynamicBuilder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
-    Message dynamicMessage = dynamicBuilder.build();
-
-    assertEquals(message.getSerializedSize(),
-                 dynamicMessage.getSerializedSize());
-  }
-
-  public void testDynamicMessageSerialization() throws Exception {
-    Message.Builder builder =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.setAllFieldsViaReflection(builder);
-    Message message = builder.build();
-
-    ByteString rawBytes = message.toByteString();
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
-    TestUtil.assertAllFieldsSet(message2);
-
-    // In fact, the serialized forms should be exactly the same, byte-for-byte.
-    assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
-  }
-
-  public void testDynamicMessageParsing() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestAllTypes message = builder.build();
-
-    ByteString rawBytes = message.toByteString();
-
-    Message message2 =
-      DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
-    reflectionTester.assertAllFieldsSetViaReflection(message2);
-
-    // Test Parser interface.
-    Message message3 = message2.getParserForType().parseFrom(rawBytes);
-    reflectionTester.assertAllFieldsSetViaReflection(message3);
-  }
-
-  public void testDynamicMessageExtensionParsing() throws Exception {
-    ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
-    Message message = DynamicMessage.parseFrom(
-        TestAllExtensions.getDescriptor(), rawBytes,
-        TestUtil.getExtensionRegistry());
-    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
-
-    // Test Parser interface.
-    Message message2 = message.getParserForType().parseFrom(
-        rawBytes, TestUtil.getExtensionRegistry());
-    extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
-  }
-
-  public void testDynamicMessagePackedSerialization() throws Exception {
-    Message.Builder builder =
-        DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
-    packedReflectionTester.setPackedFieldsViaReflection(builder);
-    Message message = builder.build();
-
-    ByteString rawBytes = message.toByteString();
-    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
-
-    TestUtil.assertPackedFieldsSet(message2);
-
-    // In fact, the serialized forms should be exactly the same, byte-for-byte.
-    assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
-  }
-
-  public void testDynamicMessagePackedParsing() throws Exception {
-    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
-    TestUtil.setPackedFields(builder);
-    TestPackedTypes message = builder.build();
-
-    ByteString rawBytes = message.toByteString();
-
-    Message message2 =
-      DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
-    packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
-
-    // Test Parser interface.
-    Message message3 = message2.getParserForType().parseFrom(rawBytes);
-    packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
-  }
-
-  public void testDynamicMessageCopy() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestAllTypes message = builder.build();
-
-    DynamicMessage copy = DynamicMessage.newBuilder(message).build();
-    reflectionTester.assertAllFieldsSetViaReflection(copy);
-
-    // Test oneof behavior
-    FieldDescriptor bytesField =
-        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
-    FieldDescriptor uint32Field =
-        TestAllTypes.getDescriptor().findFieldByName("oneof_uint32");
-    assertTrue(copy.hasField(bytesField));
-    assertFalse(copy.hasField(uint32Field));
-    DynamicMessage copy2 =
-        DynamicMessage.newBuilder(message).setField(uint32Field, 123).build();
-    assertFalse(copy2.hasField(bytesField));
-    assertTrue(copy2.hasField(uint32Field));
-    assertEquals(123, copy2.getField(uint32Field));
-  }
-
-  public void testToBuilder() throws Exception {
-    DynamicMessage.Builder builder =
-        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    reflectionTester.setAllFieldsViaReflection(builder);
-    int unknownFieldNum = 9;
-    long unknownFieldVal = 90;
-    builder.setUnknownFields(UnknownFieldSet.newBuilder()
-        .addField(unknownFieldNum,
-            UnknownFieldSet.Field.newBuilder()
-                .addVarint(unknownFieldVal).build())
-        .build());
-    DynamicMessage message = builder.build();
-
-    DynamicMessage derived = message.toBuilder().build();
-    reflectionTester.assertAllFieldsSetViaReflection(derived);
-    assertEquals(Arrays.asList(unknownFieldVal),
-        derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
-  }
-
-  public void testDynamicOneofMessage() throws Exception {
-    DynamicMessage.Builder builder =
-        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0);
-    assertFalse(builder.hasOneof(oneof));
-    assertSame(null, builder.getOneofFieldDescriptor(oneof));
-
-    reflectionTester.setAllFieldsViaReflection(builder);
-    assertTrue(builder.hasOneof(oneof));
-    FieldDescriptor field = oneof.getField(3);
-    assertSame(field, builder.getOneofFieldDescriptor(oneof));
-
-    DynamicMessage message = builder.buildPartial();
-    assertTrue(message.hasOneof(oneof));
-
-    DynamicMessage.Builder mergedBuilder =
-        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    FieldDescriptor mergedField = oneof.getField(0);
-    mergedBuilder.setField(mergedField, 123);
-    assertTrue(mergedBuilder.hasField(mergedField));
-    mergedBuilder.mergeFrom(message);
-    assertTrue(mergedBuilder.hasField(field));
-    assertFalse(mergedBuilder.hasField(mergedField));
-
-    builder.clearOneof(oneof);
-    assertSame(null, builder.getOneofFieldDescriptor(oneof));
-    message = builder.build();
-    assertSame(null, message.getOneofFieldDescriptor(oneof));
-  }
-
-  // Regression test for a bug that makes setField() not work for repeated
-  // enum fields.
-  public void testSettersForRepeatedEnumField() throws Exception {
-    DynamicMessage.Builder builder =
-        DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
-    FieldDescriptor repeatedEnumField =
-        TestAllTypes.getDescriptor().findFieldByName(
-            "repeated_nested_enum");
-    EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor();
-    builder.setField(repeatedEnumField, enumDescriptor.getValues());
-    DynamicMessage message = builder.build();
-    assertEquals(
-        enumDescriptor.getValues(), message.getField(repeatedEnumField));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
deleted file mode 100644
index a92ba37..0000000
--- a/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-/**
- * A prerun for a test suite that allows running the full protocol buffer
- * tests in a mode that disables the optimization for not using
- * {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are
- * requested. This allows us to run all the tests through both code paths
- * and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
-
-  //@Override (Java 1.6 override semantics, but we must support 1.5)
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
deleted file mode 100644
index 0b3482c..0000000
--- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ /dev/null
@@ -1,1515 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.Descriptor;
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.test.UnittestImport;
-import protobuf_unittest.EnumWithNoOuter;
-import protobuf_unittest.MessageWithNoOuter;
-import protobuf_unittest.MultipleFilesTestProto;
-import protobuf_unittest.NestedExtension.MyNestedExtension;
-import protobuf_unittest.NestedExtensionLite.MyNestedExtensionLite;
-import protobuf_unittest.NonNestedExtension;
-import protobuf_unittest.NonNestedExtension.MessageToBeExtended;
-import protobuf_unittest.NonNestedExtension.MyNonNestedExtension;
-import protobuf_unittest.NonNestedExtensionLite;
-import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended;
-import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite;
-import protobuf_unittest.OuterClassNameTest2OuterClass;
-import protobuf_unittest.OuterClassNameTest3OuterClass;
-import protobuf_unittest.OuterClassNameTestOuterClass;
-import protobuf_unittest.ServiceWithNoOuter;
-import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
-import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
-import protobuf_unittest.UnittestProto.TestOneof2;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Unit test for generated messages and generated code.  See also
- * {@link MessageTest}, which tests some generated message functionality.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class GeneratedMessageTest extends TestCase {
-  TestUtil.ReflectionTester reflectionTester =
-    new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
-
-  public void testDefaultInstance() throws Exception {
-    assertSame(TestAllTypes.getDefaultInstance(),
-               TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
-    assertSame(TestAllTypes.getDefaultInstance(),
-               TestAllTypes.newBuilder().getDefaultInstanceForType());
-  }
-
-  public void testMessageOrBuilder() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestAllTypes message = builder.build();
-    TestUtil.assertAllFieldsSet(message);
-  }
-
-  public void testUsingBuilderMultipleTimes() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    // primitive field scalar and repeated
-    builder.setOptionalSfixed64(100);
-    builder.addRepeatedInt32(100);
-    // enum field scalar and repeated
-    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
-    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
-    // proto field scalar and repeated
-    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(1));
-    builder.addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(1));
-
-    TestAllTypes value1 = builder.build();
-
-    assertEquals(100, value1.getOptionalSfixed64());
-    assertEquals(100, value1.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
-        value1.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
-        value1.getRepeatedImportEnum(0));
-    assertEquals(1, value1.getOptionalForeignMessage().getC());
-    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
-
-    // Make sure that builder didn't update previously created values
-    builder.setOptionalSfixed64(200);
-    builder.setRepeatedInt32(0, 200);
-    builder.setOptionalImportEnum(UnittestImport.ImportEnum.IMPORT_FOO);
-    builder.setRepeatedImportEnum(0, UnittestImport.ImportEnum.IMPORT_FOO);
-    builder.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(2));
-    builder.setRepeatedForeignMessage(0, ForeignMessage.newBuilder().setC(2));
-
-    TestAllTypes value2 = builder.build();
-
-    // Make sure value1 didn't change.
-    assertEquals(100, value1.getOptionalSfixed64());
-    assertEquals(100, value1.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
-        value1.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_BAR,
-        value1.getRepeatedImportEnum(0));
-    assertEquals(1, value1.getOptionalForeignMessage().getC());
-    assertEquals(1, value1.getRepeatedForeignMessage(0).getC());
-
-    // Make sure value2 is correct
-    assertEquals(200, value2.getOptionalSfixed64());
-    assertEquals(200, value2.getRepeatedInt32(0));
-    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO,
-        value2.getOptionalImportEnum());
-    assertEquals(UnittestImport.ImportEnum.IMPORT_FOO,
-        value2.getRepeatedImportEnum(0));
-    assertEquals(2, value2.getOptionalForeignMessage().getC());
-    assertEquals(2, value2.getRepeatedForeignMessage(0).getC());
-  }
-
-  public void testProtosShareRepeatedArraysIfDidntChange() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    builder.addRepeatedInt32(100);
-    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
-    builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance());
-
-    TestAllTypes value1 = builder.build();
-    TestAllTypes value2 = value1.toBuilder().build();
-
-    assertSame(value1.getRepeatedInt32List(), value2.getRepeatedInt32List());
-    assertSame(value1.getRepeatedImportEnumList(),
-        value2.getRepeatedImportEnumList());
-    assertSame(value1.getRepeatedForeignMessageList(),
-        value2.getRepeatedForeignMessageList());
-  }
-
-  public void testRepeatedArraysAreImmutable() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    builder.addRepeatedInt32(100);
-    builder.addRepeatedImportEnum(UnittestImport.ImportEnum.IMPORT_BAR);
-    builder.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance());
-    assertIsUnmodifiable(builder.getRepeatedInt32List());
-    assertIsUnmodifiable(builder.getRepeatedImportEnumList());
-    assertIsUnmodifiable(builder.getRepeatedForeignMessageList());
-    assertIsUnmodifiable(builder.getRepeatedFloatList());
-
-
-    TestAllTypes value = builder.build();
-    assertIsUnmodifiable(value.getRepeatedInt32List());
-    assertIsUnmodifiable(value.getRepeatedImportEnumList());
-    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
-    assertIsUnmodifiable(value.getRepeatedFloatList());
-  }
-
-  public void testParsedMessagesAreImmutable() throws Exception {
-    TestAllTypes value = TestAllTypes.PARSER.parseFrom(
-        TestUtil.getAllSet().toByteString());
-    assertIsUnmodifiable(value.getRepeatedInt32List());
-    assertIsUnmodifiable(value.getRepeatedInt64List());
-    assertIsUnmodifiable(value.getRepeatedUint32List());
-    assertIsUnmodifiable(value.getRepeatedUint64List());
-    assertIsUnmodifiable(value.getRepeatedSint32List());
-    assertIsUnmodifiable(value.getRepeatedSint64List());
-    assertIsUnmodifiable(value.getRepeatedFixed32List());
-    assertIsUnmodifiable(value.getRepeatedFixed64List());
-    assertIsUnmodifiable(value.getRepeatedSfixed32List());
-    assertIsUnmodifiable(value.getRepeatedSfixed64List());
-    assertIsUnmodifiable(value.getRepeatedFloatList());
-    assertIsUnmodifiable(value.getRepeatedDoubleList());
-    assertIsUnmodifiable(value.getRepeatedBoolList());
-    assertIsUnmodifiable(value.getRepeatedStringList());
-    assertIsUnmodifiable(value.getRepeatedBytesList());
-    assertIsUnmodifiable(value.getRepeatedGroupList());
-    assertIsUnmodifiable(value.getRepeatedNestedMessageList());
-    assertIsUnmodifiable(value.getRepeatedForeignMessageList());
-    assertIsUnmodifiable(value.getRepeatedImportMessageList());
-    assertIsUnmodifiable(value.getRepeatedNestedEnumList());
-    assertIsUnmodifiable(value.getRepeatedForeignEnumList());
-    assertIsUnmodifiable(value.getRepeatedImportEnumList());
-  }
-
-  private void assertIsUnmodifiable(List<?> list) {
-    if (list == Collections.emptyList()) {
-      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
-    } else {
-      try {
-        list.clear();
-        fail("List wasn't immutable");
-      } catch (UnsupportedOperationException e) {
-        // good
-      }
-    }
-  }
-
-  public void testSettersRejectNull() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    try {
-      builder.setOptionalString(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.setOptionalBytes(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.setOptionalNestedMessage(
-          (TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.setOptionalNestedEnum(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.addRepeatedString(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.addRepeatedBytes(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.addRepeatedNestedMessage(
-          (TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.addRepeatedNestedEnum(null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-  }
-
-  public void testRepeatedSetters() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestUtil.modifyRepeatedFields(builder);
-    TestAllTypes message = builder.build();
-    TestUtil.assertRepeatedFieldsModified(message);
-  }
-
-  public void testRepeatedSettersRejectNull() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-
-    builder.addRepeatedString("one");
-    builder.addRepeatedString("two");
-    try {
-      builder.setRepeatedString(1, null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    builder.addRepeatedBytes(TestUtil.toBytes("one"));
-    builder.addRepeatedBytes(TestUtil.toBytes("two"));
-    try {
-      builder.setRepeatedBytes(1, null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    builder.addRepeatedNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
-    builder.addRepeatedNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(456).build());
-    try {
-      builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.setRepeatedNestedMessage(
-          1, (TestAllTypes.NestedMessage.Builder) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.FOO);
-    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
-    try {
-      builder.setRepeatedNestedEnum(1, null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-  }
-
-  public void testRepeatedAppend() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-
-    builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
-    builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
-
-    ForeignMessage foreignMessage =
-        ForeignMessage.newBuilder().setC(12).build();
-    builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
-
-    TestAllTypes message = builder.build();
-    assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
-    assertEquals(message.getRepeatedForeignEnumList(),
-        Arrays.asList(ForeignEnum.FOREIGN_BAZ));
-    assertEquals(1, message.getRepeatedForeignMessageCount());
-    assertEquals(12, message.getRepeatedForeignMessage(0).getC());
-  }
-
-  public void testRepeatedAppendRejectsNull() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-
-    ForeignMessage foreignMessage =
-        ForeignMessage.newBuilder().setC(12).build();
-    try {
-      builder.addAllRepeatedForeignMessage(
-          Arrays.asList(foreignMessage, (ForeignMessage) null));
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    try {
-      builder.addAllRepeatedForeignEnum(
-          Arrays.asList(ForeignEnum.FOREIGN_BAZ, null));
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    try {
-      builder.addAllRepeatedString(Arrays.asList("one", null));
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-
-    try {
-      builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null));
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-  }
-  
-  public void testRepeatedAppendIterateOnlyOnce() throws Exception {
-    // Create a Iterable that can only be iterated once.
-    Iterable<String> stringIterable = new Iterable<String>() {
-      private boolean called = false;
-      @Override
-      public Iterator<String> iterator() {
-        if (called) {
-          throw new IllegalStateException();
-        }
-        called = true;
-        return Arrays.asList("one", "two", "three").iterator();
-      }
-    };
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    builder.addAllRepeatedString(stringIterable);
-    assertEquals(3, builder.getRepeatedStringCount());
-    assertEquals("one", builder.getRepeatedString(0));
-    assertEquals("two", builder.getRepeatedString(1));
-    assertEquals("three", builder.getRepeatedString(2));
-
-    try {
-      builder.addAllRepeatedString(stringIterable);
-      fail("Exception was not thrown");
-    } catch (IllegalStateException e) {
-      // We expect this exception.
-    }
-  }
-
-  public void testMergeFromOtherRejectsNull() throws Exception {
-    try {
-      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      builder.mergeFrom((TestAllTypes) null);
-      fail("Exception was not thrown");
-    } catch (NullPointerException e) {
-      // We expect this exception.
-    }
-  }
-
-  public void testSettingForeignMessageUsingBuilder() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        // Pass builder for foreign message instance.
-        .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123))
-        .build();
-    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
-        // Create expected version passing foreign message instance explicitly.
-        .setOptionalForeignMessage(
-            ForeignMessage.newBuilder().setC(123).build())
-        .build();
-    // TODO(ngd): Upgrade to using real #equals method once implemented
-    assertEquals(expectedMessage.toString(), message.toString());
-  }
-
-  public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        // Pass builder for foreign message instance.
-        .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456))
-        .build();
-    TestAllTypes expectedMessage = TestAllTypes.newBuilder()
-        // Create expected version passing foreign message instance explicitly.
-        .addRepeatedForeignMessage(
-            ForeignMessage.newBuilder().setC(456).build())
-        .build();
-    assertEquals(expectedMessage.toString(), message.toString());
-  }
-
-  public void testDefaults() throws Exception {
-    TestUtil.assertClear(TestAllTypes.getDefaultInstance());
-    TestUtil.assertClear(TestAllTypes.newBuilder().build());
-
-    TestExtremeDefaultValues message =
-        TestExtremeDefaultValues.getDefaultInstance();
-    assertEquals("\u1234", message.getUtf8String());
-    assertEquals(Double.POSITIVE_INFINITY, message.getInfDouble());
-    assertEquals(Double.NEGATIVE_INFINITY, message.getNegInfDouble());
-    assertTrue(Double.isNaN(message.getNanDouble()));
-    assertEquals(Float.POSITIVE_INFINITY, message.getInfFloat());
-    assertEquals(Float.NEGATIVE_INFINITY, message.getNegInfFloat());
-    assertTrue(Float.isNaN(message.getNanFloat()));
-    assertEquals("? ? ?? ?? ??? ??/ ??-", message.getCppTrigraph());
-  }
-
-  public void testClear() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.assertClear(builder);
-    TestUtil.setAllFields(builder);
-    builder.clear();
-    TestUtil.assertClear(builder);
-  }
-
-  public void testReflectionGetters() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    reflectionTester.assertAllFieldsSetViaReflection(builder);
-
-    TestAllTypes message = builder.build();
-    reflectionTester.assertAllFieldsSetViaReflection(message);
-  }
-
-  public void testReflectionSetters() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.setAllFieldsViaReflection(builder);
-    TestUtil.assertAllFieldsSet(builder);
-
-    TestAllTypes message = builder.build();
-    TestUtil.assertAllFieldsSet(message);
-  }
-
-  public void testReflectionSettersRejectNull() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.assertReflectionSettersRejectNull(builder);
-  }
-
-  public void testReflectionRepeatedSetters() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.setAllFieldsViaReflection(builder);
-    reflectionTester.modifyRepeatedFieldsViaReflection(builder);
-    TestUtil.assertRepeatedFieldsModified(builder);
-
-    TestAllTypes message = builder.build();
-    TestUtil.assertRepeatedFieldsModified(message);
-  }
-
-  public void testReflectionRepeatedSettersRejectNull() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
-  }
-
-  public void testReflectionDefaults() throws Exception {
-    reflectionTester.assertClearViaReflection(
-      TestAllTypes.getDefaultInstance());
-    reflectionTester.assertClearViaReflection(
-      TestAllTypes.newBuilder().build());
-  }
-
-  public void testReflectionGetOneof() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.setAllFieldsViaReflection(builder);
-    Descriptors.OneofDescriptor oneof =
-        TestAllTypes.getDescriptor().getOneofs().get(0);
-    Descriptors.FieldDescriptor field =
-        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
-    assertSame(field, builder.getOneofFieldDescriptor(oneof));
-
-    TestAllTypes message = builder.build();
-    assertSame(field, message.getOneofFieldDescriptor(oneof));
-  }
-
-  public void testReflectionClearOneof() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    reflectionTester.setAllFieldsViaReflection(builder);
-    Descriptors.OneofDescriptor oneof =
-        TestAllTypes.getDescriptor().getOneofs().get(0);
-    Descriptors.FieldDescriptor field =
-        TestAllTypes.getDescriptor().findFieldByName("oneof_bytes");
-
-    assertTrue(builder.hasOneof(oneof));
-    assertTrue(builder.hasField(field));
-    builder.clearOneof(oneof);
-    assertFalse(builder.hasOneof(oneof));
-    assertFalse(builder.hasField(field));
-  }
-
-  public void testEnumInterface() throws Exception {
-    assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
-        instanceof ProtocolMessageEnum);
-  }
-
-  public void testEnumMap() throws Exception {
-    Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
-
-    for (ForeignEnum value : ForeignEnum.values()) {
-      assertEquals(value, map.findValueByNumber(value.getNumber()));
-    }
-
-    assertTrue(map.findValueByNumber(12345) == null);
-  }
-
-  public void testParsePackedToUnpacked() throws Exception {
-    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
-    TestUnpackedTypes message =
-      builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
-    TestUtil.assertUnpackedFieldsSet(message);
-  }
-
-  public void testParseUnpackedToPacked() throws Exception {
-    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
-    TestPackedTypes message =
-      builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
-    TestUtil.assertPackedFieldsSet(message);
-  }
-
-  // =================================================================
-  // Extensions.
-
-  TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
-
-  public void testExtensionMessageOrBuilder() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestAllExtensions message = builder.build();
-    TestUtil.assertAllExtensionsSet(message);
-  }
-
-  public void testExtensionRepeatedSetters() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestUtil.modifyRepeatedExtensions(builder);
-    TestAllExtensions message = builder.build();
-    TestUtil.assertRepeatedExtensionsModified(message);
-  }
-
-  public void testExtensionDefaults() throws Exception {
-    TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
-    TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
-  }
-
-  public void testExtensionReflectionGetters() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    extensionsReflectionTester.assertAllFieldsSetViaReflection(builder);
-
-    TestAllExtensions message = builder.build();
-    extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
-  }
-
-  public void testExtensionReflectionSetters() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    extensionsReflectionTester.setAllFieldsViaReflection(builder);
-    TestUtil.assertAllExtensionsSet(builder);
-
-    TestAllExtensions message = builder.build();
-    TestUtil.assertAllExtensionsSet(message);
-  }
-
-  public void testExtensionReflectionSettersRejectNull() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
-  }
-
-  public void testExtensionReflectionRepeatedSetters() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    extensionsReflectionTester.setAllFieldsViaReflection(builder);
-    extensionsReflectionTester.modifyRepeatedFieldsViaReflection(builder);
-    TestUtil.assertRepeatedExtensionsModified(builder);
-
-    TestAllExtensions message = builder.build();
-    TestUtil.assertRepeatedExtensionsModified(message);
-  }
-
-  public void testExtensionReflectionRepeatedSettersRejectNull()
-      throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull(
-        builder);
-  }
-
-  public void testExtensionReflectionDefaults() throws Exception {
-    extensionsReflectionTester.assertClearViaReflection(
-      TestAllExtensions.getDefaultInstance());
-    extensionsReflectionTester.assertClearViaReflection(
-      TestAllExtensions.newBuilder().build());
-  }
-
-  public void testClearExtension() throws Exception {
-    // clearExtension() is not actually used in TestUtil, so try it manually.
-    assertFalse(
-      TestAllExtensions.newBuilder()
-        .setExtension(UnittestProto.optionalInt32Extension, 1)
-        .clearExtension(UnittestProto.optionalInt32Extension)
-        .hasExtension(UnittestProto.optionalInt32Extension));
-    assertEquals(0,
-      TestAllExtensions.newBuilder()
-        .addExtension(UnittestProto.repeatedInt32Extension, 1)
-        .clearExtension(UnittestProto.repeatedInt32Extension)
-        .getExtensionCount(UnittestProto.repeatedInt32Extension));
-  }
-
-  public void testExtensionCopy() throws Exception {
-    TestAllExtensions original = TestUtil.getAllExtensionsSet();
-    TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
-    TestUtil.assertAllExtensionsSet(copy);
-  }
-
-  public void testExtensionMergeFrom() throws Exception {
-    TestAllExtensions original =
-      TestAllExtensions.newBuilder()
-        .setExtension(UnittestProto.optionalInt32Extension, 1).build();
-    TestAllExtensions merged =
-        TestAllExtensions.newBuilder().mergeFrom(original).build();
-    assertTrue(merged.hasExtension(UnittestProto.optionalInt32Extension));
-    assertEquals(
-        1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
-  }
-
-  // =================================================================
-  // Lite Extensions.
-
-  // We test lite extensions directly because they have a separate
-  // implementation from full extensions.  In contrast, we do not test
-  // lite fields directly since they are implemented exactly the same as
-  // regular fields.
-
-  public void testLiteExtensionMessageOrBuilder() throws Exception {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestUtil.assertAllExtensionsSet(builder);
-
-    TestAllExtensionsLite message = builder.build();
-    TestUtil.assertAllExtensionsSet(message);
-  }
-
-  public void testLiteExtensionRepeatedSetters() throws Exception {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    TestUtil.setAllExtensions(builder);
-    TestUtil.modifyRepeatedExtensions(builder);
-    TestUtil.assertRepeatedExtensionsModified(builder);
-
-    TestAllExtensionsLite message = builder.build();
-    TestUtil.assertRepeatedExtensionsModified(message);
-  }
-
-  public void testLiteExtensionDefaults() throws Exception {
-    TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
-    TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
-  }
-
-  public void testClearLiteExtension() throws Exception {
-    // clearExtension() is not actually used in TestUtil, so try it manually.
-    assertFalse(
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
-        .clearExtension(UnittestLite.optionalInt32ExtensionLite)
-        .hasExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(0,
-      TestAllExtensionsLite.newBuilder()
-        .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
-        .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
-        .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
-  }
-
-  public void testLiteExtensionCopy() throws Exception {
-    TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
-    TestAllExtensionsLite copy =
-        TestAllExtensionsLite.newBuilder(original).build();
-    TestUtil.assertAllExtensionsSet(copy);
-  }
-
-  public void testLiteExtensionMergeFrom() throws Exception {
-    TestAllExtensionsLite original =
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
-    TestAllExtensionsLite merged =
-        TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
-    assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(
-        1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
-  }
-
-  // =================================================================
-  // multiple_files_test
-
-  // Test that custom options of an file level enum are properly initialized.
-  // This test needs to be put before any other access to MultipleFilesTestProto
-  // or messages defined in multiple_files_test.proto because the class loading
-  // order affects initialization process of custom options.
-  public void testEnumValueOptionsInMultipleFilesMode() throws Exception {
-    assertEquals(12345, EnumWithNoOuter.FOO.getValueDescriptor().getOptions()
-        .getExtension(MultipleFilesTestProto.enumValueOption).intValue());
-  }
-
-  public void testMultipleFilesOption() throws Exception {
-    // We mostly just want to check that things compile.
-    MessageWithNoOuter message =
-      MessageWithNoOuter.newBuilder()
-        .setNested(MessageWithNoOuter.NestedMessage.newBuilder().setI(1))
-        .addForeign(TestAllTypes.newBuilder().setOptionalInt32(1))
-        .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
-        .setForeignEnum(EnumWithNoOuter.BAR)
-        .build();
-    assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
-
-    assertEquals(MultipleFilesTestProto.getDescriptor(),
-                 MessageWithNoOuter.getDescriptor().getFile());
-
-    Descriptors.FieldDescriptor field =
-      MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
-    assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(),
-                 message.getField(field));
-
-    assertEquals(MultipleFilesTestProto.getDescriptor(),
-                 ServiceWithNoOuter.getDescriptor().getFile());
-
-    assertFalse(
-      TestAllExtensions.getDefaultInstance().hasExtension(
-        MultipleFilesTestProto.extensionWithOuter));
-  }
-
-  public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize()
-    throws Exception {
-    TestOptionalOptimizedForSize message =
-        TestOptionalOptimizedForSize.getDefaultInstance();
-    assertTrue(message.isInitialized());
-
-    message = TestOptionalOptimizedForSize.newBuilder().setO(
-        TestRequiredOptimizedForSize.newBuilder().buildPartial()
-        ).buildPartial();
-    assertFalse(message.isInitialized());
-
-    message = TestOptionalOptimizedForSize.newBuilder().setO(
-        TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial()
-        ).buildPartial();
-    assertTrue(message.isInitialized());
-  }
-
-  public void testUninitializedExtensionInOptimizedForSize()
-      throws Exception {
-    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
-    builder.setExtension(TestOptimizedForSize.testExtension2,
-        TestRequiredOptimizedForSize.newBuilder().buildPartial());
-    assertFalse(builder.isInitialized());
-    assertFalse(builder.buildPartial().isInitialized());
-
-    builder = TestOptimizedForSize.newBuilder();
-    builder.setExtension(TestOptimizedForSize.testExtension2,
-        TestRequiredOptimizedForSize.newBuilder().setX(10).buildPartial());
-    assertTrue(builder.isInitialized());
-    assertTrue(builder.buildPartial().isInitialized());
-  }
-
-  public void testToBuilder() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestAllTypes message = builder.build();
-    TestUtil.assertAllFieldsSet(message);
-    TestUtil.assertAllFieldsSet(message.toBuilder().build());
-  }
-
-  public void testFieldConstantValues() throws Exception {
-    assertEquals(TestAllTypes.NestedMessage.BB_FIELD_NUMBER, 1);
-    assertEquals(TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 1);
-    assertEquals(TestAllTypes.OPTIONALGROUP_FIELD_NUMBER, 16);
-    assertEquals(TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER, 18);
-    assertEquals(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 21);
-    assertEquals(TestAllTypes.REPEATED_INT32_FIELD_NUMBER, 31);
-    assertEquals(TestAllTypes.REPEATEDGROUP_FIELD_NUMBER, 46);
-    assertEquals(TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER, 48);
-    assertEquals(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 51);
-  }
-
-  public void testExtensionConstantValues() throws Exception {
-    assertEquals(UnittestProto.TestRequired.SINGLE_FIELD_NUMBER, 1000);
-    assertEquals(UnittestProto.TestRequired.MULTI_FIELD_NUMBER, 1001);
-    assertEquals(UnittestProto.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER, 1);
-    assertEquals(UnittestProto.OPTIONALGROUP_EXTENSION_FIELD_NUMBER, 16);
-    assertEquals(
-      UnittestProto.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 18);
-    assertEquals(UnittestProto.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 21);
-    assertEquals(UnittestProto.REPEATED_INT32_EXTENSION_FIELD_NUMBER, 31);
-    assertEquals(UnittestProto.REPEATEDGROUP_EXTENSION_FIELD_NUMBER, 46);
-    assertEquals(
-      UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48);
-    assertEquals(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 51);
-  }
-
-  public void testRecursiveMessageDefaultInstance() throws Exception {
-    UnittestProto.TestRecursiveMessage message =
-        UnittestProto.TestRecursiveMessage.getDefaultInstance();
-    assertTrue(message != null);
-    assertNotNull(message.getA());
-    assertTrue(message.getA() == message);
-  }
-
-  public void testSerialize() throws Exception {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestUtil.setAllFields(builder);
-    TestAllTypes expected = builder.build();
-    ObjectOutputStream out = new ObjectOutputStream(baos);
-    try {
-      out.writeObject(expected);
-    } finally {
-      out.close();
-    }
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    ObjectInputStream in = new ObjectInputStream(bais);
-    TestAllTypes actual = (TestAllTypes) in.readObject();
-    assertEquals(expected, actual);
-  }
-
-  public void testSerializePartial() throws Exception {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestAllTypes expected = builder.buildPartial();
-    ObjectOutputStream out = new ObjectOutputStream(baos);
-    try {
-      out.writeObject(expected);
-    } finally {
-      out.close();
-    }
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    ObjectInputStream in = new ObjectInputStream(bais);
-    TestAllTypes actual = (TestAllTypes) in.readObject();
-    assertEquals(expected, actual);
-  }
-
-  public void testEnumValues() {
-     assertEquals(
-         TestAllTypes.NestedEnum.BAR.getNumber(),
-         TestAllTypes.NestedEnum.BAR_VALUE);
-    assertEquals(
-        TestAllTypes.NestedEnum.BAZ.getNumber(),
-        TestAllTypes.NestedEnum.BAZ_VALUE);
-    assertEquals(
-        TestAllTypes.NestedEnum.FOO.getNumber(),
-        TestAllTypes.NestedEnum.FOO_VALUE);
-  }
-
-  public void testNonNestedExtensionInitialization() {
-    assertTrue(NonNestedExtension.nonNestedExtension
-               .getMessageDefaultInstance() instanceof MyNonNestedExtension);
-    assertEquals("nonNestedExtension",
-                 NonNestedExtension.nonNestedExtension.getDescriptor().getName());
-  }
-
-  public void testNestedExtensionInitialization() {
-    assertTrue(MyNestedExtension.recursiveExtension.getMessageDefaultInstance()
-               instanceof MessageToBeExtended);
-    assertEquals("recursiveExtension",
-                 MyNestedExtension.recursiveExtension.getDescriptor().getName());
-  }
-
-  public void testNonNestedExtensionLiteInitialization() {
-    assertTrue(NonNestedExtensionLite.nonNestedExtensionLite
-               .getMessageDefaultInstance() instanceof MyNonNestedExtensionLite);
-  }
-
-  public void testNestedExtensionLiteInitialization() {
-    assertTrue(MyNestedExtensionLite.recursiveExtensionLite
-               .getMessageDefaultInstance() instanceof MessageLiteToBeExtended);
-  }
-
-  public void testInvalidations() throws Exception {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-    TestAllTypes.NestedMessage nestedMessage1 =
-        TestAllTypes.NestedMessage.newBuilder().build();
-    TestAllTypes.NestedMessage nestedMessage2 =
-        TestAllTypes.NestedMessage.newBuilder().build();
-
-    // Set all three flavors (enum, primitive, message and singular/repeated)
-    // and verify no invalidations fired
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-
-    TestAllTypes.Builder builder = (TestAllTypes.Builder)
-        ((GeneratedMessage) TestAllTypes.getDefaultInstance()).
-            newBuilderForType(mockParent);
-    builder.setOptionalInt32(1);
-    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
-    builder.setOptionalNestedMessage(nestedMessage1);
-    builder.addRepeatedInt32(1);
-    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
-    builder.addRepeatedNestedMessage(nestedMessage1);
-    assertEquals(0, mockParent.getInvalidationCount());
-
-    // Now tell it we want changes and make sure it's only fired once
-    // And do this for each flavor
-
-    // primitive single
-    builder.buildPartial();
-    builder.setOptionalInt32(2);
-    builder.setOptionalInt32(3);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-    // enum single
-    builder.buildPartial();
-    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ);
-    builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
-    assertEquals(2, mockParent.getInvalidationCount());
-
-    // message single
-    builder.buildPartial();
-    builder.setOptionalNestedMessage(nestedMessage2);
-    builder.setOptionalNestedMessage(nestedMessage1);
-    assertEquals(3, mockParent.getInvalidationCount());
-
-    // primitive repeated
-    builder.buildPartial();
-    builder.addRepeatedInt32(2);
-    builder.addRepeatedInt32(3);
-    assertEquals(4, mockParent.getInvalidationCount());
-
-    // enum repeated
-    builder.buildPartial();
-    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
-    builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
-    assertEquals(5, mockParent.getInvalidationCount());
-
-    // message repeated
-    builder.buildPartial();
-    builder.addRepeatedNestedMessage(nestedMessage2);
-    builder.addRepeatedNestedMessage(nestedMessage1);
-    assertEquals(6, mockParent.getInvalidationCount());
-
-  }
-
-  public void testInvalidations_Extensions() throws Exception {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-
-    TestAllExtensions.Builder builder = (TestAllExtensions.Builder)
-        ((GeneratedMessage) TestAllExtensions.getDefaultInstance()).
-            newBuilderForType(mockParent);
-
-    builder.addExtension(UnittestProto.repeatedInt32Extension, 1);
-    builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 2);
-    builder.clearExtension(UnittestProto.repeatedInt32Extension);
-    assertEquals(0, mockParent.getInvalidationCount());
-
-    // Now tell it we want changes and make sure it's only fired once
-    builder.buildPartial();
-    builder.addExtension(UnittestProto.repeatedInt32Extension, 2);
-    builder.addExtension(UnittestProto.repeatedInt32Extension, 3);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-    builder.buildPartial();
-    builder.setExtension(UnittestProto.repeatedInt32Extension, 0, 4);
-    builder.setExtension(UnittestProto.repeatedInt32Extension, 1, 5);
-    assertEquals(2, mockParent.getInvalidationCount());
-
-    builder.buildPartial();
-    builder.clearExtension(UnittestProto.repeatedInt32Extension);
-    builder.clearExtension(UnittestProto.repeatedInt32Extension);
-    assertEquals(3, mockParent.getInvalidationCount());
-  }
-
-  public void testBaseMessageOrBuilder() {
-    // Mostly just makes sure the base interface exists and has some methods.
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestAllTypes message = builder.buildPartial();
-    TestAllTypesOrBuilder builderAsInterface = (TestAllTypesOrBuilder) builder;
-    TestAllTypesOrBuilder messageAsInterface = (TestAllTypesOrBuilder) message;
-
-    assertEquals(
-        messageAsInterface.getDefaultBool(),
-        messageAsInterface.getDefaultBool());
-    assertEquals(
-        messageAsInterface.getOptionalDouble(),
-        messageAsInterface.getOptionalDouble());
-  }
-
-  public void testMessageOrBuilderGetters() {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-
-    // single fields
-    assertSame(ForeignMessage.getDefaultInstance(),
-        builder.getOptionalForeignMessageOrBuilder());
-    ForeignMessage.Builder subBuilder =
-        builder.getOptionalForeignMessageBuilder();
-    assertSame(subBuilder, builder.getOptionalForeignMessageOrBuilder());
-
-    // repeated fields
-    ForeignMessage m0 = ForeignMessage.newBuilder().buildPartial();
-    ForeignMessage m1 = ForeignMessage.newBuilder().buildPartial();
-    ForeignMessage m2 = ForeignMessage.newBuilder().buildPartial();
-    builder.addRepeatedForeignMessage(m0);
-    builder.addRepeatedForeignMessage(m1);
-    builder.addRepeatedForeignMessage(m2);
-    assertSame(m0, builder.getRepeatedForeignMessageOrBuilder(0));
-    assertSame(m1, builder.getRepeatedForeignMessageOrBuilder(1));
-    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
-    ForeignMessage.Builder b0 = builder.getRepeatedForeignMessageBuilder(0);
-    ForeignMessage.Builder b1 = builder.getRepeatedForeignMessageBuilder(1);
-    assertSame(b0, builder.getRepeatedForeignMessageOrBuilder(0));
-    assertSame(b1, builder.getRepeatedForeignMessageOrBuilder(1));
-    assertSame(m2, builder.getRepeatedForeignMessageOrBuilder(2));
-
-    List<? extends ForeignMessageOrBuilder> messageOrBuilderList =
-        builder.getRepeatedForeignMessageOrBuilderList();
-    assertSame(b0, messageOrBuilderList.get(0));
-    assertSame(b1, messageOrBuilderList.get(1));
-    assertSame(m2, messageOrBuilderList.get(2));
-  }
-
-  public void testGetFieldBuilder() {
-    Descriptor descriptor = TestAllTypes.getDescriptor();
-
-    FieldDescriptor fieldDescriptor =
-        descriptor.findFieldByName("optional_nested_message");
-    FieldDescriptor foreignFieldDescriptor =
-        descriptor.findFieldByName("optional_foreign_message");
-    FieldDescriptor importFieldDescriptor =
-        descriptor.findFieldByName("optional_import_message");
-
-    // Mutate the message with new field builder
-    // Mutate nested message
-    TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
-    Message.Builder fieldBuilder1 = builder1.newBuilderForField(fieldDescriptor)
-        .mergeFrom((Message) builder1.getField(fieldDescriptor));
-    FieldDescriptor subFieldDescriptor1 =
-        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder1.setField(subFieldDescriptor1, 1);
-    builder1.setField(fieldDescriptor, fieldBuilder1.build());
-
-    // Mutate foreign message
-    Message.Builder foreignFieldBuilder1 = builder1.newBuilderForField(
-        foreignFieldDescriptor)
-        .mergeFrom((Message) builder1.getField(foreignFieldDescriptor));
-    FieldDescriptor subForeignFieldDescriptor1 =
-        foreignFieldBuilder1.getDescriptorForType().findFieldByName("c");
-    foreignFieldBuilder1.setField(subForeignFieldDescriptor1, 2);
-    builder1.setField(foreignFieldDescriptor, foreignFieldBuilder1.build());
-
-    // Mutate import message
-    Message.Builder importFieldBuilder1 = builder1.newBuilderForField(
-        importFieldDescriptor)
-        .mergeFrom((Message) builder1.getField(importFieldDescriptor));
-    FieldDescriptor subImportFieldDescriptor1 =
-        importFieldBuilder1.getDescriptorForType().findFieldByName("d");
-    importFieldBuilder1.setField(subImportFieldDescriptor1, 3);
-    builder1.setField(importFieldDescriptor, importFieldBuilder1.build());
-
-    Message newMessage1 = builder1.build();
-
-    // Mutate the message with existing field builder
-    // Mutate nested message
-    TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
-    Message.Builder fieldBuilder2 = builder2.getFieldBuilder(fieldDescriptor);
-    FieldDescriptor subFieldDescriptor2 =
-        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder2.setField(subFieldDescriptor2, 1);
-    builder2.setField(fieldDescriptor, fieldBuilder2.build());
-
-    // Mutate foreign message
-    Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(
-        foreignFieldDescriptor)
-        .mergeFrom((Message) builder2.getField(foreignFieldDescriptor));
-    FieldDescriptor subForeignFieldDescriptor2 =
-        foreignFieldBuilder2.getDescriptorForType().findFieldByName("c");
-    foreignFieldBuilder2.setField(subForeignFieldDescriptor2, 2);
-    builder2.setField(foreignFieldDescriptor, foreignFieldBuilder2.build());
-
-    // Mutate import message
-    Message.Builder importFieldBuilder2 = builder2.newBuilderForField(
-        importFieldDescriptor)
-        .mergeFrom((Message) builder2.getField(importFieldDescriptor));
-    FieldDescriptor subImportFieldDescriptor2 =
-        importFieldBuilder2.getDescriptorForType().findFieldByName("d");
-    importFieldBuilder2.setField(subImportFieldDescriptor2, 3);
-    builder2.setField(importFieldDescriptor, importFieldBuilder2.build());
-
-    Message newMessage2 = builder2.build();
-
-    // These two messages should be equal.
-    assertEquals(newMessage1, newMessage2);
-  }
-
-  public void testGetFieldBuilderWithInitializedValue() {
-    Descriptor descriptor = TestAllTypes.getDescriptor();
-    FieldDescriptor fieldDescriptor =
-        descriptor.findFieldByName("optional_nested_message");
-
-    // Before setting field, builder is initialized by default value. 
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    NestedMessage.Builder fieldBuilder =
-        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
-    assertEquals(0, fieldBuilder.getBb());
-
-    // Setting field value with new field builder instance.
-    builder = TestAllTypes.newBuilder();
-    NestedMessage.Builder newFieldBuilder =
-        builder.getOptionalNestedMessageBuilder();
-    newFieldBuilder.setBb(2);
-    // Then get the field builder instance by getFieldBuilder().
-    fieldBuilder =
-        (NestedMessage.Builder) builder.getFieldBuilder(fieldDescriptor);
-    // It should contain new value.
-    assertEquals(2, fieldBuilder.getBb());
-    // These two builder should be equal.
-    assertSame(fieldBuilder, newFieldBuilder);
-  }
-
-  public void testGetFieldBuilderNotSupportedException() {
-    Descriptor descriptor = TestAllTypes.getDescriptor();
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    try {
-      builder.getFieldBuilder(descriptor.findFieldByName("optional_int32"));
-      fail("Exception was not thrown");
-    } catch (UnsupportedOperationException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.getFieldBuilder(
-          descriptor.findFieldByName("optional_nested_enum"));
-      fail("Exception was not thrown");
-    } catch (UnsupportedOperationException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.getFieldBuilder(descriptor.findFieldByName("repeated_int32"));
-      fail("Exception was not thrown");
-    } catch (UnsupportedOperationException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.getFieldBuilder(
-          descriptor.findFieldByName("repeated_nested_enum"));
-      fail("Exception was not thrown");
-    } catch (UnsupportedOperationException e) {
-      // We expect this exception.
-    }
-    try {
-      builder.getFieldBuilder(
-          descriptor.findFieldByName("repeated_nested_message"));
-      fail("Exception was not thrown");
-    } catch (UnsupportedOperationException e) {
-      // We expect this exception.
-    }
-  }
-
-  // Test that when the default outer class name conflicts with another type
-  // defined in the proto the compiler will append a suffix to avoid the
-  // conflict.
-  public void testConflictingOuterClassName() {
-    // We just need to make sure we can refer to the outer class with the
-    // expected name. There is nothing else to test.
-    OuterClassNameTestOuterClass.OuterClassNameTest message =
-        OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build();
-    assertTrue(message.getDescriptorForType() ==
-        OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor());
-
-    OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2
-        message2 = OuterClassNameTest2OuterClass.TestMessage2.NestedMessage
-            .OuterClassNameTest2.newBuilder().build();
-    assertEquals(0, message2.getSerializedSize());
-
-    OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3
-        enumValue = OuterClassNameTest3OuterClass.TestMessage3.NestedMessage
-            .OuterClassNameTest3.DUMMY_VALUE;
-    assertEquals(1, enumValue.getNumber());
-  }
-
-  // =================================================================
-  // oneof generated code test
-  public void testOneofEnumCase() throws Exception {
-    TestOneof2 message = TestOneof2.newBuilder()
-        .setFooInt(123).setFooString("foo").setFooCord("bar").build();
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-  }
-
-  public void testClearOneof() throws Exception {
-    TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123);
-    assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase());
-    builder.clearFoo();
-    assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase());
-  }
-
-  public void testSetOneofClearsOthers() throws Exception {
-    TestOneof2.Builder builder = TestOneof2.newBuilder();
-    TestOneof2 message =
-        builder.setFooInt(123).setFooString("foo").buildPartial();
-    assertTrue(message.hasFooString());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooCord("bar").buildPartial();
-    assertTrue(message.hasFooCord());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooStringPiece("baz").buildPartial();
-    assertTrue(message.hasFooStringPiece());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial();
-    assertTrue(message.hasFooBytes());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial();
-    assertTrue(message.hasFooEnum());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooMessage(
-        TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).buildPartial();
-    assertTrue(message.hasFooMessage());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-
-    message = builder.setFooInt(123).buildPartial();
-    assertTrue(message.hasFooInt());
-    TestUtil.assertAtMostOneFieldSetOneof(message);
-  }
-
-  public void testOneofTypes() throws Exception {
-    // Primitive
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooInt(), 0);
-      assertFalse(builder.hasFooInt());
-      assertTrue(builder.setFooInt(123).hasFooInt());
-      assertEquals(builder.getFooInt(), 123);
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooInt());
-      assertEquals(message.getFooInt(), 123);
-
-      assertFalse(builder.clearFooInt().hasFooInt());
-      TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 0);
-    }
-
-    // Enum
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO);
-      assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
-      assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR);
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooEnum());
-      assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR);
-
-      assertFalse(builder.clearFooEnum().hasFooEnum());
-      TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO);
-    }
-
-    // String
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooString(), "");
-      builder.setFooString("foo");
-      assertTrue(builder.hasFooString());
-      assertEquals(builder.getFooString(), "foo");
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooString());
-      assertEquals(message.getFooString(), "foo");
-      assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
-
-      assertFalse(builder.clearFooString().hasFooString());
-      TestOneof2 message2 = builder.buildPartial();
-      assertFalse(message2.hasFooString());
-      assertEquals(message2.getFooString(), "");
-      assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
-
-      // Get method should not change the oneof value.
-      builder.setFooInt(123);
-      assertEquals(builder.getFooString(), "");
-      assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
-      assertEquals(123, builder.getFooInt());
-
-      message = builder.build();
-      assertEquals(message.getFooString(), "");
-      assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
-      assertEquals(123, message.getFooInt());
-    }
-
-    // Cord
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooCord(), "");
-      builder.setFooCord("foo");
-      assertTrue(builder.hasFooCord());
-      assertEquals(builder.getFooCord(), "foo");
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooCord());
-      assertEquals(message.getFooCord(), "foo");
-      assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
-
-      assertFalse(builder.clearFooCord().hasFooCord());
-      TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooCord());
-      assertEquals(message2.getFooCord(), "");
-      assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
-    }
-
-    // StringPiece
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooStringPiece(), "");
-      builder.setFooStringPiece("foo");
-      assertTrue(builder.hasFooStringPiece());
-      assertEquals(builder.getFooStringPiece(), "foo");
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooStringPiece());
-      assertEquals(message.getFooStringPiece(), "foo");
-      assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
-
-      assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
-      TestOneof2 message2 = builder.build();
-      assertFalse(message2.hasFooStringPiece());
-      assertEquals(message2.getFooStringPiece(), "");
-      assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
-    }
-
-    // Message
-    {
-      // set
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      assertEquals(builder.getFooMessage().getQuxInt(), 0);
-      builder.setFooMessage(
-          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
-      assertTrue(builder.hasFooMessage());
-      assertEquals(builder.getFooMessage().getQuxInt(), 234);
-      TestOneof2 message = builder.buildPartial();
-      assertTrue(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 234);
-
-      // clear
-      assertFalse(builder.clearFooMessage().hasFooString());
-      message = builder.build();
-      assertFalse(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 0);
-
-      // nested builder
-      builder = TestOneof2.newBuilder();
-      assertSame(builder.getFooMessageOrBuilder(),
-          TestOneof2.NestedMessage.getDefaultInstance());
-      assertFalse(builder.hasFooMessage());
-      builder.getFooMessageBuilder().setQuxInt(123);
-      assertTrue(builder.hasFooMessage());
-      assertEquals(builder.getFooMessage().getQuxInt(), 123);
-      message = builder.build();
-      assertTrue(message.hasFooMessage());
-      assertEquals(message.getFooMessage().getQuxInt(), 123);
-    }
-
-    // LazyMessage is tested in LazyMessageLiteTest.java
-  }
-
-  public void testOneofMerge() throws Exception {
-    // Primitive Type
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooInt(123).build();
-      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 123);
-    }
-
-    // String
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooString("foo").build();
-      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooString());
-      assertEquals(message2.getFooString(), "foo");
-    }
-
-    // Enum
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
-      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
-    }
-
-    // Message
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooMessage(
-          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
-      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertTrue(message2.hasFooMessage());
-      assertEquals(message2.getFooMessage().getQuxInt(), 234);
-    }
-  }
-
-  public void testOneofSerialization() throws Exception {
-    // Primitive Type
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooInt(123).build();
-      ByteString serialized = message.toByteString();
-      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooInt());
-      assertEquals(message2.getFooInt(), 123);
-    }
-
-    // String
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooString("foo").build();
-      ByteString serialized = message.toByteString();
-      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooString());
-      assertEquals(message2.getFooString(), "foo");
-    }
-
-    // Enum
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
-      ByteString serialized = message.toByteString();
-      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooEnum());
-      assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR);
-    }
-
-    // Message
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message = builder.setFooMessage(
-          TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
-      ByteString serialized = message.toByteString();
-      TestOneof2 message2 = TestOneof2.parseFrom(serialized);
-      assertTrue(message2.hasFooMessage());
-      assertEquals(message2.getFooMessage().getQuxInt(), 234);
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java
deleted file mode 100644
index 89b6451..0000000
--- a/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ /dev/null
@@ -1,180 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.IsValidUtf8TestUtil.Shard;
-
-import junit.framework.TestCase;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Tests cases for {@link ByteString#isValidUtf8()}. This includes three
- * brute force tests that actually test every permutation of one byte, two byte,
- * and three byte sequences to ensure that the method produces the right result
- * for every possible byte encoding where "right" means it's consistent with
- * java's UTF-8 string encoding/decoding such that the method returns true for
- * any sequence that will round trip when converted to a String and then back to
- * bytes and will return false for any sequence that will not round trip.
- * See also {@link IsValidUtf8FourByteTest}. It also includes some
- * other more targeted tests.
- *
- * @author jonp@google.com (Jon Perlow)
- * @author martinrb@google.com (Martin Buchholz)
- */
-public class IsValidUtf8Test extends TestCase {
-
-  /**
-   * Tests that round tripping of all two byte permutations work.
-   */
-  public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException {
-    IsValidUtf8TestUtil.testBytes(1,
-        IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
-  }
-
-  /**
-   * Tests that round tripping of all two byte permutations work.
-   */
-  public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException {
-    IsValidUtf8TestUtil.testBytes(2,
-        IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
-  }
-
-  /**
-   * Tests that round tripping of all three byte permutations work.
-   */
-  public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException {
-    IsValidUtf8TestUtil.testBytes(3,
-        IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
-  }
-
-  /**
-   * Tests that round tripping of a sample of four byte permutations work.
-   * All permutations are prohibitively expensive to test for automated runs;
-   * {@link IsValidUtf8FourByteTest} is used for full coverage. This method
-   * tests specific four-byte cases.
-   */
-  public void testIsValidUtf8_4BytesSamples()
-      throws UnsupportedEncodingException {
-    // Valid 4 byte.
-    assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
-
-    // Bad trailing bytes
-    assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0x7F);
-    assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0xC0);
-
-    // Special cases for byte2
-    assertInvalidUtf8(0xF0, 0x8F, 0xAD, 0xA2);
-    assertInvalidUtf8(0xF4, 0x90, 0xAD, 0xA2);
-  }
-
-  /**
-   * Tests some hard-coded test cases.
-   */
-  public void testSomeSequences() {
-    // Empty
-    assertTrue(asBytes("").isValidUtf8());
-
-    // One-byte characters, including control characters
-    assertTrue(asBytes("\u0000abc\u007f").isValidUtf8());
-
-    // Two-byte characters
-    assertTrue(asBytes("\u00a2\u00a2").isValidUtf8());
-
-    // Three-byte characters
-    assertTrue(asBytes("\u020ac\u020ac").isValidUtf8());
-
-    // Four-byte characters
-    assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
-
-    // Mixed string
-    assertTrue(
-        asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62")
-        .isValidUtf8());
-
-    // Not a valid string
-    assertInvalidUtf8(-1, 0, -1, 0);
-  }
-
-  private byte[] toByteArray(int... bytes) {
-    byte[] realBytes = new byte[bytes.length];
-    for (int i = 0; i < bytes.length; i++) {
-      realBytes[i] = (byte) bytes[i];
-    }
-    return realBytes;
-  }
-
-  private ByteString toByteString(int... bytes) {
-    return ByteString.copyFrom(toByteArray(bytes));
-  }
-
-  private void assertValidUtf8(int[] bytes, boolean not) {
-    byte[] realBytes = toByteArray(bytes);
-    assertTrue(not ^ Utf8.isValidUtf8(realBytes));
-    assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
-    ByteString lit = ByteString.copyFrom(realBytes);
-    ByteString sub = lit.substring(0, bytes.length);
-    assertTrue(not ^ lit.isValidUtf8());
-    assertTrue(not ^ sub.isValidUtf8());
-    ByteString[] ropes = {
-      RopeByteString.newInstanceForTest(ByteString.EMPTY, lit),
-      RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
-      RopeByteString.newInstanceForTest(lit, ByteString.EMPTY),
-      RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
-      RopeByteString.newInstanceForTest(sub, lit)
-    };
-    for (ByteString rope : ropes) {
-      assertTrue(not ^ rope.isValidUtf8());
-    }
-  }
-
-  private void assertValidUtf8(int... bytes) {
-    assertValidUtf8(bytes, false);
-  }
-
-  private void assertInvalidUtf8(int... bytes) {
-    assertValidUtf8(bytes, true);
-  }
-
-  private static ByteString asBytes(String s) {
-    return ByteString.copyFromUtf8(s);
-  }
-
-  public void testShardsHaveExpectedRoundTrippables() {
-    // A sanity check.
-    int actual = 0;
-    for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
-      actual += shard.expected;
-    }
-    assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT,
-        actual);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
deleted file mode 100644
index f41595e..0000000
--- a/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ /dev/null
@@ -1,421 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static junit.framework.Assert.*;
-
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.logging.Logger;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.Charset;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-
-/**
- * Shared testing code for {@link IsValidUtf8Test} and
- * {@link IsValidUtf8FourByteTest}.
- *
- * @author jonp@google.com (Jon Perlow)
- * @author martinrb@google.com (Martin Buchholz)
- */
-class IsValidUtf8TestUtil {
-  private static Logger logger = Logger.getLogger(
-      IsValidUtf8TestUtil.class.getName());
-
-  // 128 - [chars 0x0000 to 0x007f]
-  static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
-
-  // 128
-  static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT =
-      ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
-
-  // 1920 [chars 0x0080 to 0x07FF]
-  static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
-
-  // 18,304
-  static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
-      // Both bytes are one byte characters
-      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
-      // The possible number of two byte characters
-      TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
-
-  // 2048
-  static long THREE_BYTE_SURROGATES = 2 * 1024;
-
-  // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
-  static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
-      0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
-
-  // 2,650,112
-  static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
-      // All one byte characters
-      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
-      // One two byte character and a one byte character
-      2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
-       // Three byte characters
-      THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
-
-  // 1,048,576 [chars 0x10000L to 0x10FFFF]
-  static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
-
-  // 289,571,839
-  static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
-      // All one byte characters
-      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
-      // One and three byte characters
-      2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
-      // Two two byte characters
-      TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
-      // Permutations of one and two byte characters
-      3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
-          ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
-      // Four byte characters
-      FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
-
-  static class Shard {
-    final long index;
-    final long start;
-    final long lim;
-    final long expected;
-
-
-    public Shard(long index, long start, long lim, long expected) {
-      assertTrue(start < lim);
-      this.index = index;
-      this.start = start;
-      this.lim = lim;
-      this.expected = expected;
-    }
-  }
-
-  static final long[] FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES =
-      generateFourByteShardsExpectedRunnables();
-
-  private static long[] generateFourByteShardsExpectedRunnables() {
-    long[] expected = new long[128];
-
-    // 0-63 are all 5300224
-    for (int i = 0; i <= 63; i++) {
-      expected[i] = 5300224;
-    }
-
-    // 97-111 are all 2342912
-    for (int i = 97; i <= 111; i++) {
-     expected[i] = 2342912;
-    }
-
-    // 113-117 are all 1048576
-    for (int i = 113; i <= 117; i++) {
-      expected[i] = 1048576;
-    }
-
-    // One offs
-    expected[112] = 786432;
-    expected[118] = 786432;
-    expected[119] = 1048576;
-    expected[120] = 458752;
-    expected[121] = 524288;
-    expected[122] = 65536;
-
-    // Anything not assigned was the default 0.
-    return expected;
-  }
-
-  static final List<Shard> FOUR_BYTE_SHARDS = generateFourByteShards(
-      128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
-
-
-  private static List<Shard> generateFourByteShards(
-      int numShards, long[] expected) {
-    assertEquals(numShards, expected.length);
-    List<Shard> shards = new ArrayList<Shard>(numShards);
-    long LIM = 1L << 32;
-    long increment = LIM / numShards;
-    assertTrue(LIM % numShards == 0);
-    for (int i = 0; i < numShards; i++) {
-      shards.add(new Shard(i,
-          increment * i,
-          increment * (i + 1),
-          expected[i]));
-    }
-    return shards;
-  }
-
-  /**
-   * Helper to run the loop to test all the permutations for the number of bytes
-   * specified.
-   *
-   * @param numBytes the number of bytes in the byte array
-   * @param expectedCount the expected number of roundtrippable permutations
-   */
-  static void testBytes(int numBytes, long expectedCount)
-      throws UnsupportedEncodingException {
-    testBytes(numBytes, expectedCount, 0, -1);
-  }
-
-  /**
-   * Helper to run the loop to test all the permutations for the number of bytes
-   * specified. This overload is useful for debugging to get the loop to start
-   * at a certain character.
-   *
-   * @param numBytes the number of bytes in the byte array
-   * @param expectedCount the expected number of roundtrippable permutations
-   * @param start the starting bytes encoded as a long as big-endian
-   * @param lim the limit of bytes to process encoded as a long as big-endian,
-   *     or -1 to mean the max limit for numBytes
-   */
-  static void testBytes(int numBytes, long expectedCount, long start, long lim)
-      throws UnsupportedEncodingException {
-    Random rnd = new Random();
-    byte[] bytes = new byte[numBytes];
-
-    if (lim == -1) {
-      lim = 1L << (numBytes * 8);
-    }
-    long count = 0;
-    long countRoundTripped = 0;
-    for (long byteChar = start; byteChar < lim; byteChar++) {
-      long tmpByteChar = byteChar;
-      for (int i = 0; i < numBytes; i++) {
-        bytes[bytes.length - i - 1] = (byte) tmpByteChar;
-        tmpByteChar = tmpByteChar >> 8;
-      }
-      ByteString bs = ByteString.copyFrom(bytes);
-      boolean isRoundTrippable = bs.isValidUtf8();
-      String s = new String(bytes, "UTF-8");
-      byte[] bytesReencoded = s.getBytes("UTF-8");
-      boolean bytesEqual = Arrays.equals(bytes, bytesReencoded);
-
-      if (bytesEqual != isRoundTrippable) {
-        outputFailure(byteChar, bytes, bytesReencoded);
-      }
-
-      // Check agreement with static Utf8 methods.
-      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
-      assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
-
-      // Test partial sequences.
-      // Partition numBytes into three segments (not necessarily non-empty).
-      int i = rnd.nextInt(numBytes);
-      int j = rnd.nextInt(numBytes);
-      if (j < i) {
-        int tmp = i; i = j; j = tmp;
-      }
-      int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
-      int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
-      int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
-      if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
-        System.out.printf("state=%04x %04x %04x i=%d j=%d%n",
-                          state1, state2, state3, i, j);
-        outputFailure(byteChar, bytes, bytesReencoded);
-      }
-      assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
-
-      // Test ropes built out of small partial sequences
-      ByteString rope = RopeByteString.newInstanceForTest(
-          bs.substring(0, i),
-          RopeByteString.newInstanceForTest(
-              bs.substring(i, j),
-              bs.substring(j, numBytes)));
-      assertSame(RopeByteString.class, rope.getClass());
-
-      ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope };
-      for (ByteString x : byteStrings) {
-        assertEquals(isRoundTrippable,
-                     x.isValidUtf8());
-        assertEquals(state3,
-                     x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
-
-        assertEquals(state1,
-                     x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
-        assertEquals(state1,
-                     x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
-        assertEquals(state2,
-                     x.partialIsValidUtf8(state1, i, j - i));
-        assertEquals(state2,
-                     x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
-        assertEquals(state3,
-                     x.partialIsValidUtf8(state2, j, numBytes - j));
-        assertEquals(state3,
-                     x.substring(j, numBytes)
-                     .partialIsValidUtf8(state2, 0, numBytes - j));
-      }
-
-      // ByteString reduplication should not affect its UTF-8 validity.
-      ByteString ropeADope =
-          RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
-      assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
-
-      if (isRoundTrippable) {
-        countRoundTripped++;
-      }
-      count++;
-      if (byteChar != 0 && byteChar % 1000000L == 0) {
-        logger.info("Processed " + (byteChar / 1000000L) +
-            " million characters");
-      }
-    }
-    logger.info("Round tripped " + countRoundTripped + " of " + count);
-    assertEquals(expectedCount, countRoundTripped);
-  }
-
-  /**
-   * Variation of {@link #testBytes} that does less allocation using the
-   * low-level encoders/decoders directly. Checked in because it's useful for
-   * debugging when trying to process bytes faster, but since it doesn't use the
-   * actual String class, it's possible for incompatibilities to develop
-   * (although unlikely).
-   *
-   * @param numBytes the number of bytes in the byte array
-   * @param expectedCount the expected number of roundtrippable permutations
-   * @param start the starting bytes encoded as a long as big-endian
-   * @param lim the limit of bytes to process encoded as a long as big-endian,
-   *     or -1 to mean the max limit for numBytes
-   */
-  void testBytesUsingByteBuffers(
-      int numBytes, long expectedCount, long start, long lim)
-      throws UnsupportedEncodingException {
-    CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder()
-        .onMalformedInput(CodingErrorAction.REPLACE)
-        .onUnmappableCharacter(CodingErrorAction.REPLACE);
-    CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder()
-        .onMalformedInput(CodingErrorAction.REPLACE)
-        .onUnmappableCharacter(CodingErrorAction.REPLACE);
-    byte[] bytes = new byte[numBytes];
-    int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
-    char[] charsDecoded =
-        new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
-    int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
-    byte[] bytesReencoded = new byte[maxBytes];
-
-    ByteBuffer bb = ByteBuffer.wrap(bytes);
-    CharBuffer cb = CharBuffer.wrap(charsDecoded);
-    ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded);
-    if (lim == -1) {
-      lim = 1L << (numBytes * 8);
-    }
-    long count = 0;
-    long countRoundTripped = 0;
-    for (long byteChar = start; byteChar < lim; byteChar++) {
-      bb.rewind();
-      bb.limit(bytes.length);
-      cb.rewind();
-      cb.limit(charsDecoded.length);
-      bbReencoded.rewind();
-      bbReencoded.limit(bytesReencoded.length);
-      encoder.reset();
-      decoder.reset();
-      long tmpByteChar = byteChar;
-      for (int i = 0; i < bytes.length; i++) {
-        bytes[bytes.length - i - 1] = (byte) tmpByteChar;
-        tmpByteChar = tmpByteChar >> 8;
-      }
-      boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8();
-      CoderResult result = decoder.decode(bb, cb, true);
-      assertFalse(result.isError());
-      result = decoder.flush(cb);
-      assertFalse(result.isError());
-
-      int charLen = cb.position();
-      cb.rewind();
-      cb.limit(charLen);
-      result = encoder.encode(cb, bbReencoded, true);
-      assertFalse(result.isError());
-      result = encoder.flush(bbReencoded);
-      assertFalse(result.isError());
-
-      boolean bytesEqual = true;
-      int bytesLen = bbReencoded.position();
-      if (bytesLen != numBytes) {
-        bytesEqual = false;
-      } else {
-        for (int i = 0; i < numBytes; i++) {
-          if (bytes[i] != bytesReencoded[i]) {
-            bytesEqual = false;
-            break;
-          }
-        }
-      }
-      if (bytesEqual != isRoundTrippable) {
-        outputFailure(byteChar, bytes, bytesReencoded, bytesLen);
-      }
-
-      count++;
-      if (isRoundTrippable) {
-        countRoundTripped++;
-      }
-      if (byteChar != 0 && byteChar % 1000000 == 0) {
-        logger.info("Processed " + (byteChar / 1000000) +
-            " million characters");
-      }
-    }
-    logger.info("Round tripped " + countRoundTripped + " of " + count);
-    assertEquals(expectedCount, countRoundTripped);
-  }
-
-  private static void outputFailure(long byteChar, byte[] bytes, byte[] after) {
-    outputFailure(byteChar, bytes, after, after.length);
-  }
-
-  private static void outputFailure(long byteChar, byte[] bytes, byte[] after,
-      int len) {
-    fail("Failure: (" + Long.toHexString(byteChar) + ") " +
-        toHexString(bytes) + " => " + toHexString(after, len));
-  }
-
-  private static String toHexString(byte[] b) {
-    return toHexString(b, b.length);
-  }
-
-  private static String toHexString(byte[] b, int len) {
-    StringBuilder s = new StringBuilder();
-    s.append("\"");
-    for (int i = 0; i < len; i++) {
-      if (i > 0) {
-        s.append(" ");
-      }
-      s.append(String.format("%02x", b[i] & 0xFF));
-    }
-    s.append("\"");
-    return s.toString();
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
deleted file mode 100644
index e67c6d2..0000000
--- a/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-
-import java.io.IOException;
-import junit.framework.TestCase;
-
-/**
- * Unit test for {@link LazyFieldLite}.
- *
- * @author xiangl@google.com (Xiang Li)
- */
-public class LazyFieldLiteTest extends TestCase {
-
-  public void testGetValue() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
-  }
-
-  public void testGetValueEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
-  }
-
-  public void testSetValue() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
-    message = lazyField.getValue(TestAllTypes.getDefaultInstance());
-    changeValue(lazyField);
-    assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance()));
-  }
-
-  public void testSetValueEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
-    MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance());
-    changeValue(lazyField);
-    assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance()));
-  }
-
-  public void testGetSerializedSize() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
-    changeValue(lazyField);
-    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
-  }
-
-  public void testGetSerializedSizeEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.getSerializedSize(), lazyField.getSerializedSize());
-    changeValue(lazyField);
-    assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize());
-  }
-
-  public void testGetByteString() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.toByteString(), lazyField.toByteString());
-    changeValue(lazyField);
-    assertNotEqual(message.toByteString(), lazyField.toByteString());
-  }
-
-  public void testGetByteStringEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message);
-    assertEquals(message.toByteString(), lazyField.toByteString());
-    changeValue(lazyField);
-    assertNotEqual(message.toByteString(), lazyField.toByteString());
-  }
-
-
-  // Help methods.
-
-  private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
-    ByteString bytes = message.toByteString();
-    return new LazyFieldLite(TestUtil.getExtensionRegistry(), bytes);
-  }
-
-  private void changeValue(LazyFieldLite lazyField) {
-    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
-    builder.addRepeatedBool(true);
-    MessageLite newMessage = builder.build();
-    lazyField.setValue(newMessage);
-  }
-
-  private void assertNotEqual(Object unexpected, Object actual) {
-    assertFalse(unexpected == actual
-        || (unexpected != null && unexpected.equals(actual)));
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/src/test/java/com/google/protobuf/LazyFieldTest.java
deleted file mode 100644
index 2b90006..0000000
--- a/java/src/test/java/com/google/protobuf/LazyFieldTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-
-import java.io.IOException;
-import junit.framework.TestCase;
-
-/**
- * Unit test for {@link LazyField}.
- *
- * @author xiangl@google.com (Xiang Li)
- */
-public class LazyFieldTest extends TestCase {
-  public void testHashCode() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyField lazyField =
-        createLazyFieldFromMessage(message);
-    assertEquals(message.hashCode(), lazyField.hashCode());
-    lazyField.getValue();
-    assertEquals(message.hashCode(), lazyField.hashCode());
-    changeValue(lazyField);
-    // make sure two messages have different hash code
-    assertNotEqual(message.hashCode(), lazyField.hashCode());
-  }
-
-  public void testHashCodeEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message.hashCode(), lazyField.hashCode());
-    lazyField.getValue();
-    assertEquals(message.hashCode(), lazyField.hashCode());
-    changeValue(lazyField);
-    // make sure two messages have different hash code
-    assertNotEqual(message.hashCode(), lazyField.hashCode());
-  }
-
-  public void testGetValue() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message, lazyField.getValue());
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue());
-  }
-
-  public void testGetValueEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyField lazyField = createLazyFieldFromMessage(message);
-    assertEquals(message, lazyField.getValue());
-    changeValue(lazyField);
-    assertNotEqual(message, lazyField.getValue());
-  }
-
-  public void testEqualsObject() {
-    MessageLite message = TestUtil.getAllSet();
-    LazyField lazyField = createLazyFieldFromMessage(message);
-    assertTrue(lazyField.equals(message));
-    changeValue(lazyField);
-    assertFalse(lazyField.equals(message));
-    assertFalse(message.equals(lazyField.getValue()));
-  }
-
-  public void testEqualsObjectEx() throws Exception {
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    LazyField lazyField = createLazyFieldFromMessage(message);
-    assertTrue(lazyField.equals(message));
-    changeValue(lazyField);
-    assertFalse(lazyField.equals(message));
-    assertFalse(message.equals(lazyField.getValue()));
-  }
-
-  // Help methods.
-
-  private LazyField createLazyFieldFromMessage(MessageLite message) {
-    ByteString bytes = message.toByteString();
-    return new LazyField(message.getDefaultInstanceForType(),
-        TestUtil.getExtensionRegistry(), bytes);
-  }
-
-  private void changeValue(LazyField lazyField) {
-    TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder();
-    builder.addRepeatedBool(true);
-    MessageLite newMessage = builder.build();
-    lazyField.setValue(newMessage);
-  }
-
-  private void assertNotEqual(Object unexpected, Object actual) {
-    assertFalse(unexpected == actual
-        || (unexpected != null && unexpected.equals(actual)));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
deleted file mode 100644
index 00e3a84..0000000
--- a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
-import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
-import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
-
-import junit.framework.TestCase;
-
-import org.easymock.classextension.EasyMock;
-
-import java.util.ArrayList;
-
-/**
- * Unit test for messages with lazy fields.
- *
- * @author niwasaki@google.com (Naoki Iwasaki)
- */
-public class LazyMessageLiteTest extends TestCase {
-
-  private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser;
-
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
-
-    originalLazyInnerMessageLiteParser = LazyInnerMessageLite.PARSER;
-  }
-
-  @Override
-  protected void tearDown() throws Exception {
-    LazyInnerMessageLite.PARSER = originalLazyInnerMessageLiteParser;
-
-    super.tearDown();
-  }
-
-  public void testSetValues() {
-    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
-        .setNum(3)
-        .build();
-    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
-        .setNum(2)
-        .setNested(nested)
-        .build();
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .setNum(1)
-        .setInner(inner)
-        .setOneofNum(123)
-        .setOneofInner(inner)
-        .build();
-
-    assertEquals(1, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-
-    assertEquals(2, outer.getInner().getNum());
-    assertEquals(42, outer.getInner().getNumWithDefault());
-
-    assertEquals(3, outer.getInner().getNested().getNum());
-    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
-
-    assertFalse(outer.hasOneofNum());
-    assertTrue(outer.hasOneofInner());
-
-    assertEquals(2, outer.getOneofInner().getNum());
-    assertEquals(42, outer.getOneofInner().getNumWithDefault());
-    assertEquals(3, outer.getOneofInner().getNested().getNum());
-    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
-  }
-
-  public void testSetRepeatedValues() {
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .setNum(1)
-        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
-        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
-        .build();
-
-    assertEquals(1, outer.getNum());
-    assertEquals(2, outer.getRepeatedInnerCount());
-    assertEquals(119, outer.getRepeatedInner(0).getNum());
-    assertEquals(122, outer.getRepeatedInner(1).getNum());
-  }
-
-  public void testAddAll() {
-    ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();
-    int count = 4;
-    for (int i = 0; i < count; i++) {
-      LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
-          .setNum(i)
-          .build();
-      inners.add(inner);
-    }
-
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .addAllRepeatedInner(inners)
-        .build();
-    assertEquals(count, outer.getRepeatedInnerCount());
-    for (int i = 0; i < count; i++) {
-      assertEquals(i, outer.getRepeatedInner(i).getNum());
-    }
-  }
-
-  public void testGetDefaultValues() {
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .build();
-
-    assertEquals(0, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-
-    assertEquals(0, outer.getInner().getNum());
-    assertEquals(42, outer.getInner().getNumWithDefault());
-
-    assertEquals(0, outer.getInner().getNested().getNum());
-    assertEquals(4, outer.getInner().getNested().getNumWithDefault());
-
-    assertEquals(0, outer.getOneofNum());
-
-    assertEquals(0, outer.getOneofInner().getNum());
-    assertEquals(42, outer.getOneofInner().getNumWithDefault());
-    assertEquals(0, outer.getOneofInner().getNested().getNum());
-    assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault());
-  }
-
-  public void testClearValues() {
-    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
-        .setNum(115)
-        .build();
-
-    LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder();
-
-    assertEquals(0, outerBuilder.build().getNum());
-
-
-    // Set/Clear num
-    outerBuilder.setNum(100);
-
-    assertEquals(100, outerBuilder.build().getNum());
-    assertEquals(421, outerBuilder.build().getNumWithDefault());
-    assertFalse(outerBuilder.build().hasInner());
-
-    outerBuilder.clearNum();
-
-    assertEquals(0, outerBuilder.build().getNum());
-    assertEquals(421, outerBuilder.build().getNumWithDefault());
-    assertFalse(outerBuilder.build().hasInner());
-
-
-    // Set/Clear all
-    outerBuilder.setNum(100)
-        .setInner(inner)
-        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
-        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
-        .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123));
-
-    LazyMessageLite outer = outerBuilder.build();
-    assertEquals(100, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-    assertTrue(outer.hasInner());
-    assertEquals(115, outer.getInner().getNum());
-    assertEquals(2, outer.getRepeatedInnerCount());
-    assertEquals(119, outer.getRepeatedInner(0).getNum());
-    assertEquals(122, outer.getRepeatedInner(1).getNum());
-    assertTrue(outer.hasOneofInner());
-    assertEquals(123, outer.getOneofInner().getNum());
-
-    outerBuilder.clear();
-
-    outer = outerBuilder.build();
-
-    assertEquals(0, outer.getNum());
-    assertEquals(421, outer.getNumWithDefault());
-    assertFalse(outer.hasInner());
-    assertEquals(0, outer.getRepeatedInnerCount());
-    assertFalse(outer.hasOneofInner());
-    assertEquals(0, outer.getOneofInner().getNum());
-  }
-
-  public void testMergeValues() {
-    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
-        .setNumWithDefault(122)
-        .build();
-
-    LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder()
-        .setNum(115)
-        .build();
-    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
-        .setNum(119)
-        .setInner(innerMerging)
-        .setOneofInner(innerMerging)
-        .build();
-
-    LazyMessageLite merged = LazyMessageLite
-        .newBuilder(outerBase)
-        .mergeFrom(outerMerging)
-        .build();
-    assertEquals(119, merged.getNum());
-    assertEquals(122, merged.getNumWithDefault());
-    assertEquals(115, merged.getInner().getNum());
-    assertEquals(42, merged.getInner().getNumWithDefault());
-    assertEquals(115, merged.getOneofInner().getNum());
-    assertEquals(42, merged.getOneofInner().getNumWithDefault());
-  }
-
-  public void testMergeDefaultValues() {
-    LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder()
-        .setNum(115)
-        .build();
-    LazyMessageLite outerBase = LazyMessageLite.newBuilder()
-        .setNum(119)
-        .setNumWithDefault(122)
-        .setInner(innerBase)
-        .setOneofInner(innerBase)
-        .build();
-
-    LazyMessageLite outerMerging = LazyMessageLite.newBuilder()
-        .build();
-
-    LazyMessageLite merged = LazyMessageLite
-        .newBuilder(outerBase)
-        .mergeFrom(outerMerging)
-        .build();
-    // Merging default-instance shouldn't overwrite values in the base message.
-    assertEquals(119, merged.getNum());
-    assertEquals(122, merged.getNumWithDefault());
-    assertEquals(115, merged.getInner().getNum());
-    assertEquals(42, merged.getInner().getNumWithDefault());
-    assertEquals(115, merged.getOneofInner().getNum());
-    assertEquals(42, merged.getOneofInner().getNumWithDefault());
-  }
-
-  public void testSerialize() throws InvalidProtocolBufferException {
-    LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
-        .setNum(3)
-        .build();
-    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
-        .setNum(2)
-        .setNested(nested)
-        .build();
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .setNum(1)
-        .setInner(inner)
-        .setOneofInner(inner)
-        .build();
-
-    ByteString bytes = outer.toByteString();
-    assertEquals(bytes.size(), outer.getSerializedSize());
-
-    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
-
-    assertEquals(1, deserialized.getNum());
-    assertEquals(421,  deserialized.getNumWithDefault());
-
-    assertEquals(2,  deserialized.getInner().getNum());
-    assertEquals(42,  deserialized.getInner().getNumWithDefault());
-
-    assertEquals(3,  deserialized.getInner().getNested().getNum());
-    assertEquals(4,  deserialized.getInner().getNested().getNumWithDefault());
-
-    assertEquals(2,  deserialized.getOneofInner().getNum());
-    assertEquals(42,  deserialized.getOneofInner().getNumWithDefault());
-    assertEquals(3,  deserialized.getOneofInner().getNested().getNum());
-    assertEquals(4,  deserialized.getOneofInner().getNested().getNumWithDefault());
-
-    assertEquals(bytes, deserialized.toByteString());
-  }
-
-  public void testLaziness() throws InvalidProtocolBufferException {
-    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder()
-        .setNum(2)
-        .build();
-    LazyMessageLite outer = LazyMessageLite.newBuilder()
-        .setNum(1)
-        .setInner(inner)
-        .setOneofInner(inner)
-        .build();
-    ByteString bytes = outer.toByteString();
-
-
-    // The parser for inner / oneofInner message shouldn't be used if
-    // getInner / getOneofInner is not called.
-    LazyInnerMessageLite.PARSER = EasyMock.createStrictMock(Parser.class);
-
-    EasyMock.replay(LazyInnerMessageLite.PARSER);
-
-    LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes);
-    assertEquals(1, deserialized.getNum());
-    assertEquals(421,  deserialized.getNumWithDefault());
-
-    EasyMock.verify(LazyInnerMessageLite.PARSER);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
deleted file mode 100644
index f3012b9..0000000
--- a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link LazyStringArrayList}.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class LazyStringArrayListTest extends TestCase {
-
-  private static String STRING_A = "A";
-  private static String STRING_B = "B";
-  private static String STRING_C = "C";
-
-  private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
-  private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
-  private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
-
-  public void testJustStrings() {
-    LazyStringArrayList list = new LazyStringArrayList();
-    list.add(STRING_A);
-    list.add(STRING_B);
-    list.add(STRING_C);
-
-    assertEquals(3, list.size());
-    assertSame(STRING_A, list.get(0));
-    assertSame(STRING_B, list.get(1));
-    assertSame(STRING_C, list.get(2));
-
-    list.set(1, STRING_C);
-    assertSame(STRING_C, list.get(1));
-
-    list.remove(1);
-    assertSame(STRING_A, list.get(0));
-    assertSame(STRING_C, list.get(1));
-
-    List<ByteString> byteStringList = list.asByteStringList();
-    assertEquals(BYTE_STRING_A, byteStringList.get(0));
-    assertEquals(BYTE_STRING_C, byteStringList.get(1));
-
-    // Underlying list should be transformed.
-    assertSame(byteStringList.get(0), list.getByteString(0));
-    assertSame(byteStringList.get(1), list.getByteString(1));
-  }
-
-  public void testJustByteString() {
-    LazyStringArrayList list = new LazyStringArrayList();
-    list.add(BYTE_STRING_A);
-    list.add(BYTE_STRING_B);
-    list.add(BYTE_STRING_C);
-
-    assertEquals(3, list.size());
-    assertSame(BYTE_STRING_A, list.getByteString(0));
-    assertSame(BYTE_STRING_B, list.getByteString(1));
-    assertSame(BYTE_STRING_C, list.getByteString(2));
-
-    list.remove(1);
-    assertSame(BYTE_STRING_A, list.getByteString(0));
-    assertSame(BYTE_STRING_C, list.getByteString(1));
-
-    List<ByteString> byteStringList = list.asByteStringList();
-    assertSame(BYTE_STRING_A, byteStringList.get(0));
-    assertSame(BYTE_STRING_C, byteStringList.get(1));
-  }
-
-  public void testConversionBackAndForth() {
-    LazyStringArrayList list = new LazyStringArrayList();
-    list.add(STRING_A);
-    list.add(BYTE_STRING_B);
-    list.add(BYTE_STRING_C);
-
-    // String a should be the same because it was originally a string
-    assertSame(STRING_A, list.get(0));
-
-    // String b and c should be different because the string has to be computed
-    // from the ByteString
-    String bPrime = list.get(1);
-    assertNotSame(STRING_B, bPrime);
-    assertEquals(STRING_B, bPrime);
-    String cPrime = list.get(2);
-    assertNotSame(STRING_C, cPrime);
-    assertEquals(STRING_C, cPrime);
-
-    // String c and c should stay the same once cached.
-    assertSame(bPrime, list.get(1));
-    assertSame(cPrime, list.get(2));
-
-    // ByteString needs to be computed from string for both a and b
-    ByteString aPrimeByteString = list.getByteString(0);
-    assertEquals(BYTE_STRING_A, aPrimeByteString);
-    ByteString bPrimeByteString = list.getByteString(1);
-    assertNotSame(BYTE_STRING_B, bPrimeByteString);
-    assertEquals(BYTE_STRING_B, list.getByteString(1));
-
-    // Once cached, ByteString should stay cached.
-    assertSame(aPrimeByteString, list.getByteString(0));
-    assertSame(bPrimeByteString, list.getByteString(1));
-  }
-
-  public void testCopyConstructorCopiesByReference() {
-    LazyStringArrayList list1 = new LazyStringArrayList();
-    list1.add(STRING_A);
-    list1.add(BYTE_STRING_B);
-    list1.add(BYTE_STRING_C);
-
-    LazyStringArrayList list2 = new LazyStringArrayList(list1);
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(BYTE_STRING_B, list2.getByteString(1));
-    assertSame(BYTE_STRING_C, list2.getByteString(2));
-  }
-
-  public void testListCopyConstructor() {
-    List<String> list1 = new ArrayList<String>();
-    list1.add(STRING_A);
-    list1.add(STRING_B);
-    list1.add(STRING_C);
-
-    LazyStringArrayList list2 = new LazyStringArrayList(list1);
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(STRING_B, list2.get(1));
-    assertSame(STRING_C, list2.get(2));
-  }
-
-  public void testAddAllCopiesByReferenceIfPossible() {
-    LazyStringArrayList list1 = new LazyStringArrayList();
-    list1.add(STRING_A);
-    list1.add(BYTE_STRING_B);
-    list1.add(BYTE_STRING_C);
-
-    LazyStringArrayList list2 = new LazyStringArrayList();
-    list2.addAll(list1);
-
-    assertEquals(3, list2.size());
-    assertSame(STRING_A, list2.get(0));
-    assertSame(BYTE_STRING_B, list2.getByteString(1));
-    assertSame(BYTE_STRING_C, list2.getByteString(2));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
deleted file mode 100644
index acd1800..0000000
--- a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-
-import protobuf_unittest.UnittestProto;
-
-import junit.framework.TestCase;
-
-import java.io.IOException;
-
-/**
- * Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
- * strings works correctly.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class LazyStringEndToEndTest extends TestCase {
-
-  private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
-      ByteString.copyFrom(new byte[] {
-          114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
-          0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
-
-  private ByteString encodedTestAllTypes;
-
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
-    this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
-        .setOptionalString("foo")
-        .addRepeatedString("bar")
-        .addRepeatedString("baz")
-        .build()
-        .toByteString();
-  }
-
-  /**
-   * Tests that an invalid UTF8 string will roundtrip through a parse
-   * and serialization.
-   */
-  public void testParseAndSerialize() throws InvalidProtocolBufferException {
-    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
-        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
-    ByteString bytes = tV2.toByteString();
-    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
-
-    tV2.getOptionalString();
-    bytes = tV2.toByteString();
-    assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
-  }
-
-  public void testParseAndWrite() throws IOException {
-    UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
-        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
-    byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()];
-    CodedOutputStream outputStream = CodedOutputStream.newInstance(sink);
-    tV2.writeTo(outputStream);
-    outputStream.flush();
-    assertEquals(
-        TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
-        ByteString.copyFrom(sink));
-  }
-
-  public void testCaching() {
-    String a = "a";
-    String b = "b";
-    String c = "c";
-    UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.newBuilder()
-        .setOptionalString(a)
-        .addRepeatedString(b)
-        .addRepeatedString(c)
-        .build();
-
-    // String should be the one we passed it.
-    assertSame(a, proto.getOptionalString());
-    assertSame(b, proto.getRepeatedString(0));
-    assertSame(c, proto.getRepeatedString(1));
-
-
-    // There's no way to directly observe that the ByteString is cached
-    // correctly on serialization, but we can observe that it had to recompute
-    // the string after serialization.
-    proto.toByteString();
-    String aPrime = proto.getOptionalString();
-    assertNotSame(a, aPrime);
-    assertEquals(a, aPrime);
-    String bPrime = proto.getRepeatedString(0);
-    assertNotSame(b, bPrime);
-    assertEquals(b, bPrime);
-    String cPrime = proto.getRepeatedString(1);
-    assertNotSame(c, cPrime);
-    assertEquals(c, cPrime);
-
-    // And now the string should stay cached.
-    assertSame(aPrime, proto.getOptionalString());
-    assertSame(bPrime, proto.getRepeatedString(0));
-    assertSame(cPrime, proto.getRepeatedString(1));
-  }
-
-  public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
-    UnittestProto.TestAllTypes proto =
-        UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
-    ByteString optional = proto.getOptionalStringBytes();
-    assertSame(optional, proto.getOptionalStringBytes());
-    assertSame(optional, proto.toBuilder().getOptionalStringBytes());
-
-    ByteString repeated0 = proto.getRepeatedStringBytes(0);
-    ByteString repeated1 = proto.getRepeatedStringBytes(1);
-    assertSame(repeated0, proto.getRepeatedStringBytes(0));
-    assertSame(repeated1, proto.getRepeatedStringBytes(1));
-    assertSame(repeated0, proto.toBuilder().getRepeatedStringBytes(0));
-    assertSame(repeated1, proto.toBuilder().getRepeatedStringBytes(1));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
deleted file mode 100644
index 94f4fcf..0000000
--- a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
-import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
-
-import junit.framework.TestCase;
-
-/**
- * Test generate equal and hash methods for the lite runtime.
- *
- * @author pbogle@google.com Phil Bogle
- */
-public class LiteEqualsAndHashTest extends TestCase {
-
-  public void testEquals() throws Exception {
-    // Since the generated equals and hashCode methods for lite messages are a
-    // mostly complete subset of those for regular messages, we can mostly assume
-    // that the generated methods are already thoroughly tested by the regular tests.
-
-    // This test mostly just verifies is that a proto with
-    // optimize_for = LITE_RUNTIME and java_generates_equals_and_hash_compiles
-    // correctly when linked only against the lite library.
-
-    // We do however do some basic testing to make sure that equals is actually
-    // overriden to test for value equality rather than simple object equality.
-
-    // Check that two identical objs are equal.
-    Foo foo1a = Foo.newBuilder()
-        .setValue(1)
-        .addBar(Bar.newBuilder().setName("foo1"))
-        .build();
-    Foo foo1b = Foo.newBuilder()
-        .setValue(1)
-        .addBar(Bar.newBuilder().setName("foo1"))
-        .build();
-    Foo foo2 = Foo.newBuilder()
-        .setValue(1)
-        .addBar(Bar.newBuilder().setName("foo2"))
-        .build();
-
-    // Check that equals is doing value rather than object equality.
-    assertEquals(foo1a, foo1b);
-    assertEquals(foo1a.hashCode(), foo1b.hashCode());
-
-    // Check that a diffeent object is not equal.
-    assertFalse(foo1a.equals(foo2));
-
-    // Check that two objects which have different types but the same field values are not
-    // considered to be equal.
-    Bar bar = Bar.newBuilder().setName("bar").build();
-    BarPrime barPrime = BarPrime.newBuilder().setName("bar").build();
-    assertFalse(bar.equals(barPrime));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java
deleted file mode 100644
index 8bb30ad..0000000
--- a/java/src/test/java/com/google/protobuf/LiteTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.UnittestLite;
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-/**
- * Test lite runtime.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class LiteTest extends TestCase {
-  public void setUp() throws Exception {
-    // Test that nested extensions are initialized correctly even if the outer
-    // class has not been accessed directly.  This was once a bug with lite
-    // messages.
-    //
-    // We put this in setUp() rather than in its own test method because we
-    // need to make sure it runs before any actual tests.
-    assertTrue(TestNestedExtensionLite.nestedExtension != null);
-  }
-
-  public void testLite() throws Exception {
-    // Since lite messages are a subset of regular messages, we can mostly
-    // assume that the functionality of lite messages is already thoroughly
-    // tested by the regular tests.  All this test really verifies is that
-    // a proto with optimize_for = LITE_RUNTIME compiles correctly when
-    // linked only against the lite library.  That is all tested at compile
-    // time, leaving not much to do in this method.  Let's just do some random
-    // stuff to make sure the lite message is actually here and usable.
-
-    TestAllTypesLite message =
-      TestAllTypesLite.newBuilder()
-                      .setOptionalInt32(123)
-                      .addRepeatedString("hello")
-                      .setOptionalNestedMessage(
-                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
-                      .build();
-
-    ByteString data = message.toByteString();
-
-    TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
-
-    assertEquals(123, message2.getOptionalInt32());
-    assertEquals(1, message2.getRepeatedStringCount());
-    assertEquals("hello", message2.getRepeatedString(0));
-    assertEquals(7, message2.getOptionalNestedMessage().getBb());
-  }
-
-  public void testLiteExtensions() throws Exception {
-    // TODO(kenton):  Unlike other features of the lite library, extensions are
-    //   implemented completely differently from the regular library.  We
-    //   should probably test them more thoroughly.
-
-    TestAllExtensionsLite message =
-      TestAllExtensionsLite.newBuilder()
-        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
-        .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
-        .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
-            TestAllTypesLite.NestedEnum.BAZ)
-        .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
-            TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
-        .build();
-
-    // Test copying a message, since coping extensions actually does use a
-    // different code path between lite and regular libraries, and as of this
-    // writing, parsing hasn't been implemented yet.
-    TestAllExtensionsLite message2 = message.toBuilder().build();
-
-    assertEquals(123, (int) message2.getExtension(
-        UnittestLite.optionalInt32ExtensionLite));
-    assertEquals(1, message2.getExtensionCount(
-        UnittestLite.repeatedStringExtensionLite));
-    assertEquals(1, message2.getExtension(
-        UnittestLite.repeatedStringExtensionLite).size());
-    assertEquals("hello", message2.getExtension(
-        UnittestLite.repeatedStringExtensionLite, 0));
-    assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
-        UnittestLite.optionalNestedEnumExtensionLite));
-    assertEquals(7, message2.getExtension(
-        UnittestLite.optionalNestedMessageExtensionLite).getBb());
-  }
-
-  public void testSerialize() throws Exception {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    TestAllTypesLite expected =
-      TestAllTypesLite.newBuilder()
-                      .setOptionalInt32(123)
-                      .addRepeatedString("hello")
-                      .setOptionalNestedMessage(
-                          TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
-                      .build();
-    ObjectOutputStream out = new ObjectOutputStream(baos);
-    try {
-      out.writeObject(expected);
-    } finally {
-      out.close();
-    }
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    ObjectInputStream in = new ObjectInputStream(bais);
-    TestAllTypesLite actual = (TestAllTypesLite) in.readObject();
-    assertEquals(expected.getOptionalInt32(), actual.getOptionalInt32());
-    assertEquals(expected.getRepeatedStringCount(),
-        actual.getRepeatedStringCount());
-    assertEquals(expected.getRepeatedString(0),
-        actual.getRepeatedString(0));
-    assertEquals(expected.getOptionalNestedMessage().getBb(),
-        actual.getOptionalNestedMessage().getBb());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
deleted file mode 100644
index 475f7ff..0000000
--- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ /dev/null
@@ -1,396 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
- * This class is designed to be extended for testing extensions of {@link LiteralByteString}
- * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-public class LiteralByteStringTest extends TestCase {
-  protected static final String UTF_8 = "UTF-8";
-
-  protected String classUnderTest;
-  protected byte[] referenceBytes;
-  protected ByteString stringUnderTest;
-  protected int expectedHashCode;
-
-  @Override
-  protected void setUp() throws Exception {
-    classUnderTest = "LiteralByteString";
-    referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
-    stringUnderTest = ByteString.copyFrom(referenceBytes);
-    expectedHashCode = 331161852;
-  }
-
-  public void testExpectedType() {
-    String actualClassName = getActualClassName(stringUnderTest);
-    assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName);
-  }
-
-  protected String getActualClassName(Object object) {
-    String actualClassName = object.getClass().getName();
-    actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
-    return actualClassName;
-  }
-
-  public void testByteAt() {
-    boolean stillEqual = true;
-    for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
-      stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i));
-    }
-    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
-  }
-
-  public void testByteIterator() {
-    boolean stillEqual = true;
-    ByteString.ByteIterator iter = stringUnderTest.iterator();
-    for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
-      stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte());
-    }
-    assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
-    assertFalse(classUnderTest + " must have exhausted the itertor", iter.hasNext());
-
-    try {
-      iter.nextByte();
-      fail("Should have thrown an exception.");
-    } catch (NoSuchElementException e) {
-      // This is success
-    }
-  }
-
-  public void testByteIterable() {
-    boolean stillEqual = true;
-    int j = 0;
-    for (byte quantum : stringUnderTest) {
-      stillEqual = (referenceBytes[j] == quantum);
-      ++j;
-    }
-    assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
-    assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
-  }
-
-  public void testSize() {
-    assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
-        stringUnderTest.size());
-  }
-
-  public void testGetTreeDepth() {
-    assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth());
-  }
-
-  public void testIsBalanced() {
-    assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced());
-  }
-
-  public void testCopyTo_ByteArrayOffsetLength() {
-    int destinationOffset = 50;
-    int length = 100;
-    byte[] destination = new byte[destinationOffset + length];
-    int sourceOffset = 213;
-    stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length);
-    boolean stillEqual = true;
-    for (int i = 0; stillEqual && i < length; ++i) {
-      stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset];
-    }
-    assertTrue(classUnderTest + ".copyTo(4 arg) must give the expected bytes", stillEqual);
-  }
-
-  public void testCopyTo_ByteArrayOffsetLengthErrors() {
-    int destinationOffset = 50;
-    int length = 100;
-    byte[] destination = new byte[destinationOffset + length];
-
-    try {
-      // Copy one too many bytes
-      stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length,
-          destinationOffset, length);
-      fail("Should have thrown an exception when copying too many bytes of a "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-
-    try {
-      // Copy with illegal negative sourceOffset
-      stringUnderTest.copyTo(destination, -1, destinationOffset, length);
-      fail("Should have thrown an exception when given a negative sourceOffset in "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-
-    try {
-      // Copy with illegal negative destinationOffset
-      stringUnderTest.copyTo(destination, 0, -1, length);
-      fail("Should have thrown an exception when given a negative destinationOffset in "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-
-    try {
-      // Copy with illegal negative size
-      stringUnderTest.copyTo(destination, 0, 0, -1);
-      fail("Should have thrown an exception when given a negative size in "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-
-    try {
-      // Copy with illegal too-large sourceOffset
-      stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
-      fail("Should have thrown an exception when the destinationOffset is too large in "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-
-    try {
-      // Copy with illegal too-large destinationOffset
-      stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
-      fail("Should have thrown an exception when the destinationOffset is too large in "
-          + classUnderTest);
-    } catch (IndexOutOfBoundsException expected) {
-      // This is success
-    }
-  }
-
-  public void testCopyTo_ByteBuffer() {
-    ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
-    stringUnderTest.copyTo(myBuffer);
-    assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
-        Arrays.equals(referenceBytes, myBuffer.array()));
-  }
-
-  public void testAsReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
-    byte[] roundTripBytes = new byte[referenceBytes.length];
-    assertTrue(byteBuffer.remaining() == referenceBytes.length);
-    assertTrue(byteBuffer.isReadOnly());
-    byteBuffer.get(roundTripBytes);
-    assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
-  }
-
-  public void testAsReadOnlyByteBufferList() {
-    List<ByteBuffer> byteBuffers = stringUnderTest.asReadOnlyByteBufferList();
-    int bytesSeen = 0;
-    byte[] roundTripBytes = new byte[referenceBytes.length];
-    for (ByteBuffer byteBuffer : byteBuffers) {
-      int thisLength = byteBuffer.remaining();
-      assertTrue(byteBuffer.isReadOnly());
-      assertTrue(bytesSeen + thisLength <= referenceBytes.length);
-      byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
-      bytesSeen += thisLength;
-    }
-    assertTrue(bytesSeen == referenceBytes.length);
-    assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
-  }
-
-  public void testToByteArray() {
-    byte[] roundTripBytes = stringUnderTest.toByteArray();
-    assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
-  }
-
-  public void testWriteTo() throws IOException {
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    stringUnderTest.writeTo(bos);
-    byte[] roundTripBytes = bos.toByteArray();
-    assertTrue(classUnderTest + ".writeTo() must give back the same bytes",
-        Arrays.equals(referenceBytes, roundTripBytes));
-  }
-  
-  public void testWriteTo_mutating() throws IOException {
-    OutputStream os = new OutputStream() {
-      @Override
-      public void write(byte[] b, int off, int len) {
-        for (int x = 0; x < len; ++x) {
-          b[off + x] = (byte) 0;
-        }
-      }
-
-      @Override
-      public void write(int b) {
-        // Purposefully left blank.
-      }
-    };
-
-    stringUnderTest.writeTo(os);
-    byte[] newBytes = stringUnderTest.toByteArray();
-    assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
-        Arrays.equals(referenceBytes, newBytes));
-  }
-
-  public void testNewOutput() throws IOException {
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    ByteString.Output output = ByteString.newOutput();
-    stringUnderTest.writeTo(output);
-    assertEquals("Output Size returns correct result",
-        output.size(), stringUnderTest.size());
-    output.writeTo(bos);
-    assertTrue("Output.writeTo() must give back the same bytes",
-        Arrays.equals(referenceBytes, bos.toByteArray()));
-
-    // write the output stream to itself! This should cause it to double
-    output.writeTo(output);
-    assertEquals("Writing an output stream to itself is successful",
-        stringUnderTest.concat(stringUnderTest), output.toByteString());
-
-    output.reset();
-    assertEquals("Output.reset() resets the output", 0, output.size());
-    assertEquals("Output.reset() resets the output",
-        ByteString.EMPTY, output.toByteString());
-    
-  }
-
-  public void testToString() throws UnsupportedEncodingException {
-    String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
-    String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
-  }
-
-  public void testEquals() {
-    assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
-    assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
-    assertFalse(classUnderTest + " must not equal the empty string",
-        stringUnderTest.equals(ByteString.EMPTY));
-    assertEquals(classUnderTest + " empty strings must be equal",
-        new LiteralByteString(new byte[]{}), stringUnderTest.substring(55, 55));
-    assertEquals(classUnderTest + " must equal another string with the same value",
-        stringUnderTest, new LiteralByteString(referenceBytes));
-
-    byte[] mungedBytes = new byte[referenceBytes.length];
-    System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
-    mungedBytes[mungedBytes.length - 5] ^= 0xFF;
-    assertFalse(classUnderTest + " must not equal every string with the same length",
-        stringUnderTest.equals(new LiteralByteString(mungedBytes)));
-  }
-
-  public void testHashCode() {
-    int hash = stringUnderTest.hashCode();
-    assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
-  }
-
-  public void testPeekCachedHashCode() {
-    assertEquals(classUnderTest + ".peekCachedHashCode() should return zero at first", 0,
-        stringUnderTest.peekCachedHashCode());
-    stringUnderTest.hashCode();
-    assertEquals(classUnderTest + ".peekCachedHashCode should return zero at first",
-        expectedHashCode, stringUnderTest.peekCachedHashCode());
-  }
-
-  public void testPartialHash() {
-    // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
-    // This test would fail if the expected hash were 1.  It's not.
-    int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
-    assertEquals(classUnderTest + ".partialHash() must yield expected hashCode",
-        expectedHashCode, hash);
-  }
-
-  public void testNewInput() throws IOException {
-    InputStream input = stringUnderTest.newInput();
-    assertEquals("InputStream.available() returns correct value",
-        stringUnderTest.size(), input.available());
-    boolean stillEqual = true;
-    for (byte referenceByte : referenceBytes) {
-      int expectedInt = (referenceByte & 0xFF);
-      stillEqual = (expectedInt == input.read());
-    }
-    assertEquals("InputStream.available() returns correct value",
-        0, input.available());
-    assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
-    assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
-  }
-
-  public void testNewInput_skip() throws IOException {
-    InputStream input = stringUnderTest.newInput();
-    int stringSize = stringUnderTest.size();
-    int nearEndIndex = stringSize * 2 / 3;
-    long skipped1 = input.skip(nearEndIndex);
-    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
-    assertEquals("InputStream.available()",
-        stringSize - skipped1, input.available());
-    assertTrue("InputStream.mark() is available", input.markSupported());
-    input.mark(0);
-    assertEquals("InputStream.skip(), read()",
-        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
-    assertEquals("InputStream.available()",
-                 stringSize - skipped1 - 1, input.available());
-    long skipped2 = input.skip(stringSize);
-    assertEquals("InputStream.skip() incomplete",
-        skipped2, stringSize - skipped1 - 1);
-    assertEquals("InputStream.skip(), no more input", 0, input.available());
-    assertEquals("InputStream.skip(), no more input", -1, input.read());
-    input.reset();
-    assertEquals("InputStream.reset() succeded",
-                 stringSize - skipped1, input.available());
-    assertEquals("InputStream.reset(), read()",
-        stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
-  }
-
-  public void testNewCodedInput() throws IOException {
-    CodedInputStream cis = stringUnderTest.newCodedInput();
-    byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
-    assertTrue(classUnderTest + " must give the same bytes back from the CodedInputStream",
-        Arrays.equals(referenceBytes, roundTripBytes));
-    assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
-  }
-
-  /**
-   * Make sure we keep things simple when concatenating with empty. See also
-   * {@link ByteStringTest#testConcat_empty()}.
-   */
-  public void testConcat_empty() {
-    assertSame(classUnderTest + " concatenated with empty must give " + classUnderTest,
-        stringUnderTest.concat(ByteString.EMPTY), stringUnderTest);
-    assertSame("empty concatenated with " + classUnderTest + " must give " + classUnderTest,
-        ByteString.EMPTY.concat(stringUnderTest), stringUnderTest);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/MessageTest.java b/java/src/test/java/com/google/protobuf/MessageTest.java
deleted file mode 100644
index abcd3a1..0000000
--- a/java/src/test/java/com/google/protobuf/MessageTest.java
+++ /dev/null
@@ -1,353 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto.TestRequiredForeign;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-
-/**
- * Misc. unit tests for message operations that apply to both generated
- * and dynamic messages.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class MessageTest extends TestCase {
-  // =================================================================
-  // Message-merging tests.
-
-  static final TestAllTypes MERGE_SOURCE =
-    TestAllTypes.newBuilder()
-      .setOptionalInt32(1)
-      .setOptionalString("foo")
-      .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
-      .addRepeatedString("bar")
-      .build();
-
-  static final TestAllTypes MERGE_DEST =
-    TestAllTypes.newBuilder()
-      .setOptionalInt64(2)
-      .setOptionalString("baz")
-      .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
-      .addRepeatedString("qux")
-      .build();
-
-  static final String MERGE_RESULT_TEXT =
-      "optional_int32: 1\n" +
-      "optional_int64: 2\n" +
-      "optional_string: \"foo\"\n" +
-      "optional_foreign_message {\n" +
-      "  c: 3\n" +
-      "}\n" +
-      "repeated_string: \"qux\"\n" +
-      "repeated_string: \"bar\"\n";
-
-  public void testMergeFrom() throws Exception {
-    TestAllTypes result =
-      TestAllTypes.newBuilder(MERGE_DEST)
-        .mergeFrom(MERGE_SOURCE).build();
-
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
-  }
-
-  /**
-   * Test merging a DynamicMessage into a GeneratedMessage.  As long as they
-   * have the same descriptor, this should work, but it is an entirely different
-   * code path.
-   */
-  public void testMergeFromDynamic() throws Exception {
-    TestAllTypes result =
-      TestAllTypes.newBuilder(MERGE_DEST)
-        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
-        .build();
-
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
-  }
-
-  /** Test merging two DynamicMessages. */
-  public void testDynamicMergeFrom() throws Exception {
-    DynamicMessage result =
-      DynamicMessage.newBuilder(MERGE_DEST)
-        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
-        .build();
-
-    assertEquals(MERGE_RESULT_TEXT, result.toString());
-  }
-
-  // =================================================================
-  // Required-field-related tests.
-
-  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
-    TestRequired.getDefaultInstance();
-  private static final TestRequired TEST_REQUIRED_INITIALIZED =
-    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
-
-  public void testRequired() throws Exception {
-    TestRequired.Builder builder = TestRequired.newBuilder();
-
-    assertFalse(builder.isInitialized());
-    builder.setA(1);
-    assertFalse(builder.isInitialized());
-    builder.setB(1);
-    assertFalse(builder.isInitialized());
-    builder.setC(1);
-    assertTrue(builder.isInitialized());
-  }
-
-  public void testRequiredForeign() throws Exception {
-    TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
-
-    assertTrue(builder.isInitialized());
-
-    builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-
-    builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-  }
-
-  public void testRequiredExtension() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-
-    assertTrue(builder.isInitialized());
-
-    builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-
-    builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-  }
-
-  public void testRequiredDynamic() throws Exception {
-    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
-    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
-
-    assertFalse(builder.isInitialized());
-    builder.setField(descriptor.findFieldByName("a"), 1);
-    assertFalse(builder.isInitialized());
-    builder.setField(descriptor.findFieldByName("b"), 1);
-    assertFalse(builder.isInitialized());
-    builder.setField(descriptor.findFieldByName("c"), 1);
-    assertTrue(builder.isInitialized());
-  }
-
-  public void testRequiredDynamicForeign() throws Exception {
-    Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
-    DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
-
-    assertTrue(builder.isInitialized());
-
-    builder.setField(descriptor.findFieldByName("optional_message"),
-                     TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setField(descriptor.findFieldByName("optional_message"),
-                     TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-
-    builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
-                             TEST_REQUIRED_UNINITIALIZED);
-    assertFalse(builder.isInitialized());
-
-    builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
-                             TEST_REQUIRED_INITIALIZED);
-    assertTrue(builder.isInitialized());
-  }
-
-  public void testUninitializedException() throws Exception {
-    try {
-      TestRequired.newBuilder().build();
-      fail("Should have thrown an exception.");
-    } catch (UninitializedMessageException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
-    }
-  }
-
-  public void testBuildPartial() throws Exception {
-    // We're mostly testing that no exception is thrown.
-    TestRequired message = TestRequired.newBuilder().buildPartial();
-    assertFalse(message.isInitialized());
-  }
-
-  public void testNestedUninitializedException() throws Exception {
-    try {
-      TestRequiredForeign.newBuilder()
-        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .build();
-      fail("Should have thrown an exception.");
-    } catch (UninitializedMessageException e) {
-      assertEquals(
-        "Message missing required fields: " +
-        "optional_message.a, " +
-        "optional_message.b, " +
-        "optional_message.c, " +
-        "repeated_message[0].a, " +
-        "repeated_message[0].b, " +
-        "repeated_message[0].c, " +
-        "repeated_message[1].a, " +
-        "repeated_message[1].b, " +
-        "repeated_message[1].c",
-        e.getMessage());
-    }
-  }
-
-  public void testBuildNestedPartial() throws Exception {
-    // We're mostly testing that no exception is thrown.
-    TestRequiredForeign message =
-      TestRequiredForeign.newBuilder()
-        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .buildPartial();
-    assertFalse(message.isInitialized());
-  }
-
-  public void testParseUnititialized() throws Exception {
-    try {
-      TestRequired.parseFrom(ByteString.EMPTY);
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
-    }
-  }
-
-  public void testParseNestedUnititialized() throws Exception {
-    ByteString data =
-      TestRequiredForeign.newBuilder()
-        .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
-        .buildPartial().toByteString();
-
-    try {
-      TestRequiredForeign.parseFrom(data);
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals(
-        "Message missing required fields: " +
-        "optional_message.a, " +
-        "optional_message.b, " +
-        "optional_message.c, " +
-        "repeated_message[0].a, " +
-        "repeated_message[0].b, " +
-        "repeated_message[0].c, " +
-        "repeated_message[1].a, " +
-        "repeated_message[1].b, " +
-        "repeated_message[1].c",
-        e.getMessage());
-    }
-  }
-
-  public void testDynamicUninitializedException() throws Exception {
-    try {
-      DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
-      fail("Should have thrown an exception.");
-    } catch (UninitializedMessageException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
-    }
-  }
-
-  public void testDynamicBuildPartial() throws Exception {
-    // We're mostly testing that no exception is thrown.
-    DynamicMessage message =
-      DynamicMessage.newBuilder(TestRequired.getDescriptor())
-        .buildPartial();
-    assertFalse(message.isInitialized());
-  }
-
-  public void testDynamicParseUnititialized() throws Exception {
-    try {
-      Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
-      DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
-      fail("Should have thrown an exception.");
-    } catch (InvalidProtocolBufferException e) {
-      assertEquals("Message missing required fields: a, b, c", e.getMessage());
-    }
-  }
-  
-  /** Test reading unset repeated message from DynamicMessage. */
-  public void testDynamicRepeatedMessageNull() throws Exception {
-    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
-    DynamicMessage result =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
-        .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
-        .build();
-
-    assertTrue(result.getField(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
-    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")), 0);
-  }
-  
-  /** Test reading repeated message from DynamicMessage. */
-  public void testDynamicRepeatedMessageNotNull() throws Exception {
-
-    TestAllTypes REPEATED_NESTED =
-      TestAllTypes.newBuilder()
-        .setOptionalInt32(1)
-        .setOptionalString("foo")
-        .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
-        .addRepeatedString("bar")
-        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
-        .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
-        .build();
-    Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
-    DynamicMessage result =
-      DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
-        .mergeFrom(DynamicMessage.newBuilder(REPEATED_NESTED).build())
-        .build();
-
-    assertTrue(result.getField(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")) instanceof List<?>);
-    assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
-        .findFieldByName("repeated_foreign_message")), 2);
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/MicroTest.java b/java/src/test/java/com/google/protobuf/MicroTest.java
deleted file mode 100644
index 1e43f07..0000000
--- a/java/src/test/java/com/google/protobuf/MicroTest.java
+++ /dev/null
@@ -1,2273 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf;
-
-import com.google.protobuf.micro.ByteStringMicro;
-import com.google.protobuf.micro.CodedInputStreamMicro;
-import com.google.protobuf.micro.FileScopeEnumRefMicro;
-import com.google.protobuf.micro.MessageScopeEnumRefMicro;
-import com.google.protobuf.micro.MicroOuterClass;
-import com.google.protobuf.micro.MicroOuterClass.TestAllTypesMicro;
-import com.google.protobuf.micro.MultipleImportingNonMultipleMicro1;
-import com.google.protobuf.micro.MultipleImportingNonMultipleMicro2;
-import com.google.protobuf.micro.MultipleNameClashMicro;
-import com.google.protobuf.micro.UnittestImportMicro;
-import com.google.protobuf.micro.UnittestMultipleMicro;
-import com.google.protobuf.micro.UnittestRecursiveMicro.RecursiveMessageMicro;
-import com.google.protobuf.micro.UnittestSimpleMicro.SimpleMessageMicro;
-import com.google.protobuf.micro.UnittestSingleMicro.SingleMessageMicro;
-import com.google.protobuf.micro.UnittestStringutf8Micro.StringUtf8;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * Test micro runtime.
- *
- * @author wink@google.com Wink Saville
- */
-public class MicroTest extends TestCase {
-  public void setUp() throws Exception {
-  }
-
-  public void testSimpleMessageMicro() throws Exception {
-    SimpleMessageMicro msg = new SimpleMessageMicro();
-    assertFalse(msg.hasD());
-    assertEquals(123, msg.getD());
-    assertFalse(msg.hasNestedMsg());
-    assertEquals(null, msg.getNestedMsg());
-    assertFalse(msg.hasDefaultNestedEnum());
-    assertEquals(SimpleMessageMicro.BAZ, msg.getDefaultNestedEnum());
-
-    msg.setD(456);
-    assertTrue(msg.hasD());
-    assertEquals(456, msg.getD());
-    msg.clearD()
-       .setD(456);
-    assertTrue(msg.hasD());
-
-    SimpleMessageMicro.NestedMessage nestedMsg = new SimpleMessageMicro.NestedMessage()
-      .setBb(2);
-    assertTrue(nestedMsg.hasBb());
-    assertEquals(2, nestedMsg.getBb());
-    msg.setNestedMsg(nestedMsg);
-    assertTrue(msg.hasNestedMsg());
-    assertEquals(2, msg.getNestedMsg().getBb());
-
-    msg.setDefaultNestedEnum(SimpleMessageMicro.BAR);
-    assertTrue(msg.hasDefaultNestedEnum());
-    assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum());
-
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    SimpleMessageMicro newMsg = SimpleMessageMicro.parseFrom(result);
-    assertTrue(newMsg.hasD());
-    assertTrue(newMsg.hasNestedMsg());
-    assertTrue(newMsg.hasDefaultNestedEnum());
-    assertEquals(456, newMsg.getD());
-    assertEquals(2, msg.getNestedMsg().getBb());
-    assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum());
-  }
-
-  public void testRecursiveMessageMicro() throws Exception {
-    RecursiveMessageMicro msg = new RecursiveMessageMicro();
-    assertFalse(msg.hasId());
-    assertFalse(msg.hasNestedMessage());
-    assertFalse(msg.hasOptionalRecursiveMessageMicro());
-    assertEquals(0, msg.getRepeatedRecursiveMessageMicroCount());
-
-    RecursiveMessageMicro msg1 = new RecursiveMessageMicro();
-    msg1.setId(1);
-    assertEquals(1, msg1.getId());
-    RecursiveMessageMicro msg2 = new RecursiveMessageMicro();
-    msg2.setId(2);
-    RecursiveMessageMicro msg3 = new RecursiveMessageMicro();
-    msg3.setId(3);
-
-    RecursiveMessageMicro.NestedMessage nestedMsg = new RecursiveMessageMicro.NestedMessage();
-    nestedMsg.setA(msg1);
-    assertEquals(1, nestedMsg.getA().getId());
-
-    msg.setId(0);
-    msg.setNestedMessage(nestedMsg);
-    msg.setOptionalRecursiveMessageMicro(msg2);
-    msg.addRepeatedRecursiveMessageMicro(msg3);
-
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    RecursiveMessageMicro newMsg = RecursiveMessageMicro.parseFrom(result);
-    assertTrue(newMsg.hasId());
-    assertTrue(newMsg.hasNestedMessage());
-    assertTrue(newMsg.hasOptionalRecursiveMessageMicro());
-    assertEquals(1, newMsg.getRepeatedRecursiveMessageMicroCount());
-
-    assertEquals(0, newMsg.getId());
-    assertEquals(1, newMsg.getNestedMessage().getA().getId());
-    assertEquals(2, newMsg.getOptionalRecursiveMessageMicro().getId());
-    assertEquals(3, newMsg.getRepeatedRecursiveMessageMicro(0).getId());
-  }
-
-  public void testMicroRequiredInt32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasId());
-    assertFalse(msg.isInitialized());
-    msg.setId(123);
-    assertTrue(msg.hasId());
-    assertTrue(msg.isInitialized());
-    assertEquals(123, msg.getId());
-    msg.clearId();
-    assertFalse(msg.hasId());
-    assertFalse(msg.isInitialized());
-    msg.clearId()
-       .setId(456);
-    assertTrue(msg.hasId());
-    msg.clear();
-    assertFalse(msg.hasId());
-    assertFalse(msg.isInitialized());
-
-    msg.setId(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasId());
-    assertTrue(newMsg.isInitialized());
-    assertEquals(123, newMsg.getId());
-  }
-
-  public void testMicroOptionalInt32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalInt32());
-    msg.setOptionalInt32(123);
-    assertTrue(msg.hasOptionalInt32());
-    assertEquals(123, msg.getOptionalInt32());
-    msg.clearOptionalInt32();
-    assertFalse(msg.hasOptionalInt32());
-    msg.clearOptionalInt32()
-       .setOptionalInt32(456);
-    assertTrue(msg.hasOptionalInt32());
-    msg.clear();
-    assertFalse(msg.hasOptionalInt32());
-
-    msg.setOptionalInt32(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 2);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalInt32());
-    assertEquals(123, newMsg.getOptionalInt32());
-  }
-
-  public void testMicroOptionalInt64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalInt64());
-    msg.setOptionalInt64(123);
-    assertTrue(msg.hasOptionalInt64());
-    assertEquals(123, msg.getOptionalInt64());
-    msg.clearOptionalInt64();
-    assertFalse(msg.hasOptionalInt64());
-    msg.clearOptionalInt64()
-       .setOptionalInt64(456);
-    assertTrue(msg.hasOptionalInt64());
-    msg.clear();
-    assertFalse(msg.hasOptionalInt64());
-
-    msg.setOptionalInt64(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 2);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalInt64());
-    assertEquals(123, newMsg.getOptionalInt64());
-  }
-
-  public void testMicroOptionalUint32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalUint32());
-    msg.setOptionalUint32(123);
-    assertTrue(msg.hasOptionalUint32());
-    assertEquals(123, msg.getOptionalUint32());
-    msg.clearOptionalUint32();
-    assertFalse(msg.hasOptionalUint32());
-    msg.clearOptionalUint32()
-       .setOptionalUint32(456);
-    assertTrue(msg.hasOptionalUint32());
-    msg.clear();
-    assertFalse(msg.hasOptionalUint32());
-
-    msg.setOptionalUint32(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 2);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalUint32());
-    assertEquals(123, newMsg.getOptionalUint32());
-  }
-
-  public void testMicroOptionalUint64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalUint64());
-    msg.setOptionalUint64(123);
-    assertTrue(msg.hasOptionalUint64());
-    assertEquals(123, msg.getOptionalUint64());
-    msg.clearOptionalUint64();
-    assertFalse(msg.hasOptionalUint64());
-    msg.clearOptionalUint64()
-       .setOptionalUint64(456);
-    assertTrue(msg.hasOptionalUint64());
-    msg.clear();
-    assertFalse(msg.hasOptionalUint64());
-
-    msg.setOptionalUint64(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 2);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalUint64());
-    assertEquals(123, newMsg.getOptionalUint64());
-  }
-
-  public void testMicroOptionalSint32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalSint32());
-    msg.setOptionalSint32(123);
-    assertTrue(msg.hasOptionalSint32());
-    assertEquals(123, msg.getOptionalSint32());
-    msg.clearOptionalSint32();
-    assertFalse(msg.hasOptionalSint32());
-    msg.clearOptionalSint32()
-       .setOptionalSint32(456);
-    assertTrue(msg.hasOptionalSint32());
-    msg.clear();
-    assertFalse(msg.hasOptionalSint32());
-
-    msg.setOptionalSint32(-123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalSint32());
-    assertEquals(-123, newMsg.getOptionalSint32());
-  }
-
-  public void testMicroOptionalSint64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalSint64());
-    msg.setOptionalSint64(123);
-    assertTrue(msg.hasOptionalSint64());
-    assertEquals(123, msg.getOptionalSint64());
-    msg.clearOptionalSint64();
-    assertFalse(msg.hasOptionalSint64());
-    msg.clearOptionalSint64()
-       .setOptionalSint64(456);
-    assertTrue(msg.hasOptionalSint64());
-    msg.clear();
-    assertFalse(msg.hasOptionalSint64());
-
-    msg.setOptionalSint64(-123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalSint64());
-    assertEquals(-123, newMsg.getOptionalSint64());
-  }
-
-  public void testMicroOptionalFixed32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalFixed32());
-    msg.setOptionalFixed32(123);
-    assertTrue(msg.hasOptionalFixed32());
-    assertEquals(123, msg.getOptionalFixed32());
-    msg.clearOptionalFixed32();
-    assertFalse(msg.hasOptionalFixed32());
-    msg.clearOptionalFixed32()
-       .setOptionalFixed32(456);
-    assertTrue(msg.hasOptionalFixed32());
-    msg.clear();
-    assertFalse(msg.hasOptionalFixed32());
-
-    msg.setOptionalFixed32(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalFixed32());
-    assertEquals(123, newMsg.getOptionalFixed32());
-  }
-
-  public void testMicroOptionalFixed64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalFixed64());
-    msg.setOptionalFixed64(123);
-    assertTrue(msg.hasOptionalFixed64());
-    assertEquals(123, msg.getOptionalFixed64());
-    msg.clearOptionalFixed64();
-    assertFalse(msg.hasOptionalFixed64());
-    msg.clearOptionalFixed64()
-       .setOptionalFixed64(456);
-    assertTrue(msg.hasOptionalFixed64());
-    msg.clear();
-    assertFalse(msg.hasOptionalFixed64());
-
-    msg.setOptionalFixed64(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalFixed64());
-    assertEquals(123, newMsg.getOptionalFixed64());
-  }
-  public void testMicroOptionalSfixed32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalSfixed32());
-    msg.setOptionalSfixed32(123);
-    assertTrue(msg.hasOptionalSfixed32());
-    assertEquals(123, msg.getOptionalSfixed32());
-    msg.clearOptionalSfixed32();
-    assertFalse(msg.hasOptionalSfixed32());
-    msg.clearOptionalSfixed32()
-       .setOptionalSfixed32(456);
-    assertTrue(msg.hasOptionalSfixed32());
-    msg.clear();
-    assertFalse(msg.hasOptionalSfixed32());
-
-    msg.setOptionalSfixed32(123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalSfixed32());
-    assertEquals(123, newMsg.getOptionalSfixed32());
-  }
-
-  public void testMicroOptionalSfixed64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalSfixed64());
-    msg.setOptionalSfixed64(123);
-    assertTrue(msg.hasOptionalSfixed64());
-    assertEquals(123, msg.getOptionalSfixed64());
-    msg.clearOptionalSfixed64();
-    assertFalse(msg.hasOptionalSfixed64());
-    msg.clearOptionalSfixed64()
-       .setOptionalSfixed64(456);
-    assertTrue(msg.hasOptionalSfixed64());
-    msg.clear();
-    assertFalse(msg.hasOptionalSfixed64());
-
-    msg.setOptionalSfixed64(-123);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalSfixed64());
-    assertEquals(-123, newMsg.getOptionalSfixed64());
-  }
-
-  public void testMicroOptionalFloat() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalFloat());
-    msg.setOptionalFloat(123f);
-    assertTrue(msg.hasOptionalFloat());
-    assertTrue(123.0f == msg.getOptionalFloat());
-    msg.clearOptionalFloat();
-    assertFalse(msg.hasOptionalFloat());
-    msg.clearOptionalFloat()
-       .setOptionalFloat(456.0f);
-    assertTrue(msg.hasOptionalFloat());
-    msg.clear();
-    assertFalse(msg.hasOptionalFloat());
-
-    msg.setOptionalFloat(-123.456f);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalFloat());
-    assertTrue(-123.456f == newMsg.getOptionalFloat());
-  }
-
-  public void testMicroOptionalDouble() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalDouble());
-    msg.setOptionalDouble(123);
-    assertTrue(msg.hasOptionalDouble());
-    assertTrue(123.0 == msg.getOptionalDouble());
-    msg.clearOptionalDouble();
-    assertFalse(msg.hasOptionalDouble());
-    msg.clearOptionalDouble()
-       .setOptionalDouble(456.0);
-    assertTrue(msg.hasOptionalDouble());
-    msg.clear();
-    assertFalse(msg.hasOptionalDouble());
-
-    msg.setOptionalDouble(-123.456);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalDouble());
-    assertTrue(-123.456 == newMsg.getOptionalDouble());
-  }
-
-  public void testMicroOptionalBool() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalBool());
-    msg.setOptionalBool(true);
-    assertTrue(msg.hasOptionalBool());
-    assertEquals(true, msg.getOptionalBool());
-    msg.clearOptionalBool();
-    assertFalse(msg.hasOptionalBool());
-    msg.clearOptionalBool()
-       .setOptionalBool(true);
-    assertTrue(msg.hasOptionalBool());
-    msg.clear();
-    assertFalse(msg.hasOptionalBool());
-
-    msg.setOptionalBool(false);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 2);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalBool());
-    assertEquals(false, newMsg.getOptionalBool());
-  }
-
-  public void testMicroOptionalString() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalString());
-    msg.setOptionalString("hello");
-    assertTrue(msg.hasOptionalString());
-    assertEquals("hello", msg.getOptionalString());
-    msg.clearOptionalString();
-    assertFalse(msg.hasOptionalString());
-    msg.clearOptionalString()
-       .setOptionalString("hello");
-    assertTrue(msg.hasOptionalString());
-    msg.clear();
-    assertFalse(msg.hasOptionalString());
-
-    msg.setOptionalString("bye");
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalString());
-    assertEquals("bye", newMsg.getOptionalString());
-  }
-
-  public void testMicroOptionalBytes() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalBytes());
-    msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("hello"));
-    assertTrue(msg.hasOptionalBytes());
-    assertEquals("hello", msg.getOptionalBytes().toStringUtf8());
-    msg.clearOptionalBytes();
-    assertFalse(msg.hasOptionalBytes());
-    msg.clearOptionalBytes()
-       .setOptionalBytes(ByteStringMicro.copyFromUtf8("hello"));
-    assertTrue(msg.hasOptionalBytes());
-    msg.clear();
-    assertFalse(msg.hasOptionalBytes());
-
-    msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("bye"));
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalBytes());
-    assertEquals("bye", newMsg.getOptionalBytes().toStringUtf8());
-  }
-
-  public void testMicroOptionalGroup() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    TestAllTypesMicro.OptionalGroup grp = new TestAllTypesMicro.OptionalGroup();
-    grp.setA(1);
-    assertFalse(msg.hasOptionalGroup());
-    msg.setOptionalGroup(grp);
-    assertTrue(msg.hasOptionalGroup());
-    assertEquals(1, msg.getOptionalGroup().getA());
-    msg.clearOptionalGroup();
-    assertFalse(msg.hasOptionalGroup());
-    msg.clearOptionalGroup()
-       .setOptionalGroup(new TestAllTypesMicro.OptionalGroup().setA(2));
-    assertTrue(msg.hasOptionalGroup());
-    msg.clear();
-    assertFalse(msg.hasOptionalGroup());
-
-    msg.setOptionalGroup(grp);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalGroup());
-    assertEquals(1, newMsg.getOptionalGroup().getA());
-  }
-
-  public void testMicroOptionalNestedMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    TestAllTypesMicro.NestedMessage nestedMsg = new TestAllTypesMicro.NestedMessage();
-    nestedMsg.setBb(1);
-    assertFalse(msg.hasOptionalNestedMessage());
-    msg.setOptionalNestedMessage(nestedMsg);
-    assertTrue(msg.hasOptionalNestedMessage());
-    assertEquals(1, msg.getOptionalNestedMessage().getBb());
-    msg.clearOptionalNestedMessage();
-    assertFalse(msg.hasOptionalNestedMessage());
-    msg.clearOptionalNestedMessage()
-       .setOptionalNestedMessage(new TestAllTypesMicro.NestedMessage().setBb(2));
-    assertTrue(msg.hasOptionalNestedMessage());
-    msg.clear();
-    assertFalse(msg.hasOptionalNestedMessage());
-
-    msg.setOptionalNestedMessage(nestedMsg);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalNestedMessage());
-    assertEquals(1, newMsg.getOptionalNestedMessage().getBb());
-  }
-
-  public void testMicroOptionalForeignMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    MicroOuterClass.ForeignMessageMicro foreignMsg =
-        new MicroOuterClass.ForeignMessageMicro();
-    assertFalse(foreignMsg.hasC());
-    foreignMsg.setC(1);
-    assertTrue(foreignMsg.hasC());
-    assertFalse(msg.hasOptionalForeignMessage());
-    msg.setOptionalForeignMessage(foreignMsg);
-    assertTrue(msg.hasOptionalForeignMessage());
-    assertEquals(1, msg.getOptionalForeignMessage().getC());
-    msg.clearOptionalForeignMessage();
-    assertFalse(msg.hasOptionalForeignMessage());
-    msg.clearOptionalForeignMessage()
-       .setOptionalForeignMessage(new MicroOuterClass.ForeignMessageMicro().setC(2));
-    assertTrue(msg.hasOptionalForeignMessage());
-    msg.clear();
-    assertFalse(msg.hasOptionalForeignMessage());
-
-    msg.setOptionalForeignMessage(foreignMsg);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalForeignMessage());
-    assertEquals(1, newMsg.getOptionalForeignMessage().getC());
-  }
-
-  public void testMicroOptionalImportMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    UnittestImportMicro.ImportMessageMicro importMsg =
-        new UnittestImportMicro.ImportMessageMicro();
-    assertFalse(importMsg.hasD());
-    importMsg.setD(1);
-    assertTrue(importMsg.hasD());
-    assertFalse(msg.hasOptionalImportMessage());
-    msg.setOptionalImportMessage(importMsg);
-    assertTrue(msg.hasOptionalImportMessage());
-    assertEquals(1, msg.getOptionalImportMessage().getD());
-    msg.clearOptionalImportMessage();
-    assertFalse(msg.hasOptionalImportMessage());
-    msg.clearOptionalImportMessage()
-       .setOptionalImportMessage(new UnittestImportMicro.ImportMessageMicro().setD(2));
-    assertTrue(msg.hasOptionalImportMessage());
-    msg.clear();
-    assertFalse(msg.hasOptionalImportMessage());
-
-    msg.setOptionalImportMessage(importMsg);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalImportMessage());
-    assertEquals(1, newMsg.getOptionalImportMessage().getD());
-  }
-
-  public void testMicroOptionalNestedEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.setOptionalNestedEnum(TestAllTypesMicro.BAR);
-    assertTrue(msg.hasOptionalNestedEnum());
-    assertEquals(TestAllTypesMicro.BAR, msg.getOptionalNestedEnum());
-    msg.clearOptionalNestedEnum();
-    assertFalse(msg.hasOptionalNestedEnum());
-    msg.clearOptionalNestedEnum()
-       .setOptionalNestedEnum(TestAllTypesMicro.BAZ);
-    assertTrue(msg.hasOptionalNestedEnum());
-    msg.clear();
-    assertFalse(msg.hasOptionalNestedEnum());
-
-    msg.setOptionalNestedEnum(TestAllTypesMicro.BAR);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalNestedEnum());
-    assertEquals(TestAllTypesMicro.BAR, newMsg.getOptionalNestedEnum());
-  }
-
-  public void testMicroOptionalForeignEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
-    assertTrue(msg.hasOptionalForeignEnum());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR,
-        msg.getOptionalForeignEnum());
-    msg.clearOptionalForeignEnum();
-    assertFalse(msg.hasOptionalForeignEnum());
-    msg.clearOptionalForeignEnum()
-       .setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAZ);
-    assertTrue(msg.hasOptionalForeignEnum());
-    msg.clear();
-    assertFalse(msg.hasOptionalForeignEnum());
-
-    msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalForeignEnum());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR,
-        newMsg.getOptionalForeignEnum());
-  }
-
-  public void testMicroOptionalImportEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
-    assertTrue(msg.hasOptionalImportEnum());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR,
-        msg.getOptionalImportEnum());
-    msg.clearOptionalImportEnum();
-    assertFalse(msg.hasOptionalImportEnum());
-    msg.clearOptionalImportEnum()
-       .setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAZ);
-    assertTrue(msg.hasOptionalImportEnum());
-    msg.clear();
-    assertFalse(msg.hasOptionalImportEnum());
-
-    msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalImportEnum());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR,
-        newMsg.getOptionalImportEnum());
-  }
-
-  public void testMicroOptionalStringPiece() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalStringPiece());
-    msg.setOptionalStringPiece("hello");
-    assertTrue(msg.hasOptionalStringPiece());
-    assertEquals("hello", msg.getOptionalStringPiece());
-    msg.clearOptionalStringPiece();
-    assertFalse(msg.hasOptionalStringPiece());
-    msg.clearOptionalStringPiece()
-       .setOptionalStringPiece("hello");
-    assertTrue(msg.hasOptionalStringPiece());
-    msg.clear();
-    assertFalse(msg.hasOptionalStringPiece());
-
-    msg.setOptionalStringPiece("bye");
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalStringPiece());
-    assertEquals("bye", newMsg.getOptionalStringPiece());
-  }
-
-  public void testMicroOptionalCord() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasOptionalCord());
-    msg.setOptionalCord("hello");
-    assertTrue(msg.hasOptionalCord());
-    assertEquals("hello", msg.getOptionalCord());
-    msg.clearOptionalCord();
-    assertFalse(msg.hasOptionalCord());
-    msg.clearOptionalCord()
-      .setOptionalCord("hello");
-    assertTrue(msg.hasOptionalCord());
-    msg.clear();
-    assertFalse(msg.hasOptionalCord());
-
-    msg.setOptionalCord("bye");
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertTrue(newMsg.hasOptionalCord());
-    assertEquals("bye", newMsg.getOptionalCord());
-  }
-
-  public void testMicroRepeatedInt32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedInt32Count());
-    msg.addRepeatedInt32(123);
-    assertEquals(1, msg.getRepeatedInt32Count());
-    assertEquals(123, msg.getRepeatedInt32(0));
-    msg.addRepeatedInt32(456);
-    assertEquals(2, msg.getRepeatedInt32Count());
-    assertEquals(123, msg.getRepeatedInt32(0));
-    assertEquals(456, msg.getRepeatedInt32(1));
-    msg.setRepeatedInt32(0, 789);
-    assertEquals(2, msg.getRepeatedInt32Count());
-    assertEquals(789, msg.getRepeatedInt32(0));
-    assertEquals(456, msg.getRepeatedInt32(1));
-    msg.clearRepeatedInt32();
-    assertEquals(0, msg.getRepeatedInt32Count());
-    msg.clearRepeatedInt32()
-       .addRepeatedInt32(456);
-    assertEquals(1, msg.getRepeatedInt32Count());
-    assertEquals(456, msg.getRepeatedInt32(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedInt32Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedInt32(123);
-    assertEquals(1, msg.getRepeatedInt32Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedInt32Count());
-    assertEquals(123, newMsg.getRepeatedInt32(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedInt32(123)
-       .addRepeatedInt32(456);
-    assertEquals(2, msg.getRepeatedInt32Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedInt32Count());
-    assertEquals(123, newMsg.getRepeatedInt32(0));
-    assertEquals(456, newMsg.getRepeatedInt32(1));
-  }
-
-  public void testMicroRepeatedInt64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedInt64Count());
-    msg.addRepeatedInt64(123);
-    assertEquals(1, msg.getRepeatedInt64Count());
-    assertEquals(123, msg.getRepeatedInt64(0));
-    msg.addRepeatedInt64(456);
-    assertEquals(2, msg.getRepeatedInt64Count());
-    assertEquals(123, msg.getRepeatedInt64(0));
-    assertEquals(456, msg.getRepeatedInt64(1));
-    msg.setRepeatedInt64(0, 789);
-    assertEquals(2, msg.getRepeatedInt64Count());
-    assertEquals(789, msg.getRepeatedInt64(0));
-    assertEquals(456, msg.getRepeatedInt64(1));
-    msg.clearRepeatedInt64();
-    assertEquals(0, msg.getRepeatedInt64Count());
-    msg.clearRepeatedInt64()
-       .addRepeatedInt64(456);
-    assertEquals(1, msg.getRepeatedInt64Count());
-    assertEquals(456, msg.getRepeatedInt64(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedInt64Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedInt64(123);
-    assertEquals(1, msg.getRepeatedInt64Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedInt64Count());
-    assertEquals(123, newMsg.getRepeatedInt64(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedInt64(123)
-       .addRepeatedInt64(456);
-    assertEquals(2, msg.getRepeatedInt64Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedInt64Count());
-    assertEquals(123, newMsg.getRepeatedInt64(0));
-    assertEquals(456, newMsg.getRepeatedInt64(1));
-  }
-
-  public void testMicroRepeatedUint32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedUint32Count());
-    msg.addRepeatedUint32(123);
-    assertEquals(1, msg.getRepeatedUint32Count());
-    assertEquals(123, msg.getRepeatedUint32(0));
-    msg.addRepeatedUint32(456);
-    assertEquals(2, msg.getRepeatedUint32Count());
-    assertEquals(123, msg.getRepeatedUint32(0));
-    assertEquals(456, msg.getRepeatedUint32(1));
-    msg.setRepeatedUint32(0, 789);
-    assertEquals(2, msg.getRepeatedUint32Count());
-    assertEquals(789, msg.getRepeatedUint32(0));
-    assertEquals(456, msg.getRepeatedUint32(1));
-    msg.clearRepeatedUint32();
-    assertEquals(0, msg.getRepeatedUint32Count());
-    msg.clearRepeatedUint32()
-       .addRepeatedUint32(456);
-    assertEquals(1, msg.getRepeatedUint32Count());
-    assertEquals(456, msg.getRepeatedUint32(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedUint32Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedUint32(123);
-    assertEquals(1, msg.getRepeatedUint32Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedUint32Count());
-    assertEquals(123, newMsg.getRepeatedUint32(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedUint32(123)
-       .addRepeatedUint32(456);
-    assertEquals(2, msg.getRepeatedUint32Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedUint32Count());
-    assertEquals(123, newMsg.getRepeatedUint32(0));
-    assertEquals(456, newMsg.getRepeatedUint32(1));
-  }
-
-  public void testMicroRepeatedUint64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedUint64Count());
-    msg.addRepeatedUint64(123);
-    assertEquals(1, msg.getRepeatedUint64Count());
-    assertEquals(123, msg.getRepeatedUint64(0));
-    msg.addRepeatedUint64(456);
-    assertEquals(2, msg.getRepeatedUint64Count());
-    assertEquals(123, msg.getRepeatedUint64(0));
-    assertEquals(456, msg.getRepeatedUint64(1));
-    msg.setRepeatedUint64(0, 789);
-    assertEquals(2, msg.getRepeatedUint64Count());
-    assertEquals(789, msg.getRepeatedUint64(0));
-    assertEquals(456, msg.getRepeatedUint64(1));
-    msg.clearRepeatedUint64();
-    assertEquals(0, msg.getRepeatedUint64Count());
-    msg.clearRepeatedUint64()
-       .addRepeatedUint64(456);
-    assertEquals(1, msg.getRepeatedUint64Count());
-    assertEquals(456, msg.getRepeatedUint64(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedUint64Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedUint64(123);
-    assertEquals(1, msg.getRepeatedUint64Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedUint64Count());
-    assertEquals(123, newMsg.getRepeatedUint64(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedUint64(123)
-       .addRepeatedUint64(456);
-    assertEquals(2, msg.getRepeatedUint64Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedUint64Count());
-    assertEquals(123, newMsg.getRepeatedUint64(0));
-    assertEquals(456, newMsg.getRepeatedUint64(1));
-  }
-
-  public void testMicroRepeatedSint32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedSint32Count());
-    msg.addRepeatedSint32(123);
-    assertEquals(1, msg.getRepeatedSint32Count());
-    assertEquals(123, msg.getRepeatedSint32(0));
-    msg.addRepeatedSint32(456);
-    assertEquals(2, msg.getRepeatedSint32Count());
-    assertEquals(123, msg.getRepeatedSint32(0));
-    assertEquals(456, msg.getRepeatedSint32(1));
-    msg.setRepeatedSint32(0, 789);
-    assertEquals(2, msg.getRepeatedSint32Count());
-    assertEquals(789, msg.getRepeatedSint32(0));
-    assertEquals(456, msg.getRepeatedSint32(1));
-    msg.clearRepeatedSint32();
-    assertEquals(0, msg.getRepeatedSint32Count());
-    msg.clearRepeatedSint32()
-       .addRepeatedSint32(456);
-    assertEquals(1, msg.getRepeatedSint32Count());
-    assertEquals(456, msg.getRepeatedSint32(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedSint32Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedSint32(123);
-    assertEquals(1, msg.getRepeatedSint32Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 4);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedSint32Count());
-    assertEquals(123, newMsg.getRepeatedSint32(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedSint32(123)
-       .addRepeatedSint32(456);
-    assertEquals(2, msg.getRepeatedSint32Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedSint32Count());
-    assertEquals(123, newMsg.getRepeatedSint32(0));
-    assertEquals(456, newMsg.getRepeatedSint32(1));
-  }
-
-  public void testMicroRepeatedSint64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedSint64Count());
-    msg.addRepeatedSint64(123);
-    assertEquals(1, msg.getRepeatedSint64Count());
-    assertEquals(123, msg.getRepeatedSint64(0));
-    msg.addRepeatedSint64(456);
-    assertEquals(2, msg.getRepeatedSint64Count());
-    assertEquals(123, msg.getRepeatedSint64(0));
-    assertEquals(456, msg.getRepeatedSint64(1));
-    msg.setRepeatedSint64(0, 789);
-    assertEquals(2, msg.getRepeatedSint64Count());
-    assertEquals(789, msg.getRepeatedSint64(0));
-    assertEquals(456, msg.getRepeatedSint64(1));
-    msg.clearRepeatedSint64();
-    assertEquals(0, msg.getRepeatedSint64Count());
-    msg.clearRepeatedSint64()
-       .addRepeatedSint64(456);
-    assertEquals(1, msg.getRepeatedSint64Count());
-    assertEquals(456, msg.getRepeatedSint64(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedSint64Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedSint64(123);
-    assertEquals(1, msg.getRepeatedSint64Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 4);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedSint64Count());
-    assertEquals(123, newMsg.getRepeatedSint64(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedSint64(123)
-       .addRepeatedSint64(456);
-    assertEquals(2, msg.getRepeatedSint64Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedSint64Count());
-    assertEquals(123, newMsg.getRepeatedSint64(0));
-    assertEquals(456, newMsg.getRepeatedSint64(1));
-  }
-
-  public void testMicroRepeatedFixed32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedFixed32Count());
-    msg.addRepeatedFixed32(123);
-    assertEquals(1, msg.getRepeatedFixed32Count());
-    assertEquals(123, msg.getRepeatedFixed32(0));
-    msg.addRepeatedFixed32(456);
-    assertEquals(2, msg.getRepeatedFixed32Count());
-    assertEquals(123, msg.getRepeatedFixed32(0));
-    assertEquals(456, msg.getRepeatedFixed32(1));
-    msg.setRepeatedFixed32(0, 789);
-    assertEquals(2, msg.getRepeatedFixed32Count());
-    assertEquals(789, msg.getRepeatedFixed32(0));
-    assertEquals(456, msg.getRepeatedFixed32(1));
-    msg.clearRepeatedFixed32();
-    assertEquals(0, msg.getRepeatedFixed32Count());
-    msg.clearRepeatedFixed32()
-       .addRepeatedFixed32(456);
-    assertEquals(1, msg.getRepeatedFixed32Count());
-    assertEquals(456, msg.getRepeatedFixed32(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedFixed32Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedFixed32(123);
-    assertEquals(1, msg.getRepeatedFixed32Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedFixed32Count());
-    assertEquals(123, newMsg.getRepeatedFixed32(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedFixed32(123)
-       .addRepeatedFixed32(456);
-    assertEquals(2, msg.getRepeatedFixed32Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedFixed32Count());
-    assertEquals(123, newMsg.getRepeatedFixed32(0));
-    assertEquals(456, newMsg.getRepeatedFixed32(1));
-  }
-
-  public void testMicroRepeatedFixed64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedFixed64Count());
-    msg.addRepeatedFixed64(123);
-    assertEquals(1, msg.getRepeatedFixed64Count());
-    assertEquals(123, msg.getRepeatedFixed64(0));
-    msg.addRepeatedFixed64(456);
-    assertEquals(2, msg.getRepeatedFixed64Count());
-    assertEquals(123, msg.getRepeatedFixed64(0));
-    assertEquals(456, msg.getRepeatedFixed64(1));
-    msg.setRepeatedFixed64(0, 789);
-    assertEquals(2, msg.getRepeatedFixed64Count());
-    assertEquals(789, msg.getRepeatedFixed64(0));
-    assertEquals(456, msg.getRepeatedFixed64(1));
-    msg.clearRepeatedFixed64();
-    assertEquals(0, msg.getRepeatedFixed64Count());
-    msg.clearRepeatedFixed64()
-       .addRepeatedFixed64(456);
-    assertEquals(1, msg.getRepeatedFixed64Count());
-    assertEquals(456, msg.getRepeatedFixed64(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedFixed64Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedFixed64(123);
-    assertEquals(1, msg.getRepeatedFixed64Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedFixed64Count());
-    assertEquals(123, newMsg.getRepeatedFixed64(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedFixed64(123)
-       .addRepeatedFixed64(456);
-    assertEquals(2, msg.getRepeatedFixed64Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 20);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedFixed64Count());
-    assertEquals(123, newMsg.getRepeatedFixed64(0));
-    assertEquals(456, newMsg.getRepeatedFixed64(1));
-  }
-
-  public void testMicroRepeatedSfixed32() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedSfixed32Count());
-    msg.addRepeatedSfixed32(123);
-    assertEquals(1, msg.getRepeatedSfixed32Count());
-    assertEquals(123, msg.getRepeatedSfixed32(0));
-    msg.addRepeatedSfixed32(456);
-    assertEquals(2, msg.getRepeatedSfixed32Count());
-    assertEquals(123, msg.getRepeatedSfixed32(0));
-    assertEquals(456, msg.getRepeatedSfixed32(1));
-    msg.setRepeatedSfixed32(0, 789);
-    assertEquals(2, msg.getRepeatedSfixed32Count());
-    assertEquals(789, msg.getRepeatedSfixed32(0));
-    assertEquals(456, msg.getRepeatedSfixed32(1));
-    msg.clearRepeatedSfixed32();
-    assertEquals(0, msg.getRepeatedSfixed32Count());
-    msg.clearRepeatedSfixed32()
-       .addRepeatedSfixed32(456);
-    assertEquals(1, msg.getRepeatedSfixed32Count());
-    assertEquals(456, msg.getRepeatedSfixed32(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedSfixed32Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedSfixed32(123);
-    assertEquals(1, msg.getRepeatedSfixed32Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedSfixed32Count());
-    assertEquals(123, newMsg.getRepeatedSfixed32(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedSfixed32(123)
-       .addRepeatedSfixed32(456);
-    assertEquals(2, msg.getRepeatedSfixed32Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedSfixed32Count());
-    assertEquals(123, newMsg.getRepeatedSfixed32(0));
-    assertEquals(456, newMsg.getRepeatedSfixed32(1));
-  }
-
-  public void testMicroRepeatedSfixed64() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedSfixed64Count());
-    msg.addRepeatedSfixed64(123);
-    assertEquals(1, msg.getRepeatedSfixed64Count());
-    assertEquals(123, msg.getRepeatedSfixed64(0));
-    msg.addRepeatedSfixed64(456);
-    assertEquals(2, msg.getRepeatedSfixed64Count());
-    assertEquals(123, msg.getRepeatedSfixed64(0));
-    assertEquals(456, msg.getRepeatedSfixed64(1));
-    msg.setRepeatedSfixed64(0, 789);
-    assertEquals(2, msg.getRepeatedSfixed64Count());
-    assertEquals(789, msg.getRepeatedSfixed64(0));
-    assertEquals(456, msg.getRepeatedSfixed64(1));
-    msg.clearRepeatedSfixed64();
-    assertEquals(0, msg.getRepeatedSfixed64Count());
-    msg.clearRepeatedSfixed64()
-       .addRepeatedSfixed64(456);
-    assertEquals(1, msg.getRepeatedSfixed64Count());
-    assertEquals(456, msg.getRepeatedSfixed64(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedSfixed64Count());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedSfixed64(123);
-    assertEquals(1, msg.getRepeatedSfixed64Count());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedSfixed64Count());
-    assertEquals(123, newMsg.getRepeatedSfixed64(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedSfixed64(123)
-       .addRepeatedSfixed64(456);
-    assertEquals(2, msg.getRepeatedSfixed64Count());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 20);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedSfixed64Count());
-    assertEquals(123, newMsg.getRepeatedSfixed64(0));
-    assertEquals(456, newMsg.getRepeatedSfixed64(1));
-  }
-
-  public void testMicroRepeatedFloat() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedFloatCount());
-    msg.addRepeatedFloat(123f);
-    assertEquals(1, msg.getRepeatedFloatCount());
-    assertTrue(123f == msg.getRepeatedFloat(0));
-    msg.addRepeatedFloat(456f);
-    assertEquals(2, msg.getRepeatedFloatCount());
-    assertTrue(123f == msg.getRepeatedFloat(0));
-    assertTrue(456f == msg.getRepeatedFloat(1));
-    msg.setRepeatedFloat(0, 789f);
-    assertEquals(2, msg.getRepeatedFloatCount());
-    assertTrue(789f == msg.getRepeatedFloat(0));
-    assertTrue(456f == msg.getRepeatedFloat(1));
-    msg.clearRepeatedFloat();
-    assertEquals(0, msg.getRepeatedFloatCount());
-    msg.clearRepeatedFloat()
-       .addRepeatedFloat(456f);
-    assertEquals(1, msg.getRepeatedFloatCount());
-    assertTrue(456f == msg.getRepeatedFloat(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedFloatCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedFloat(123f);
-    assertEquals(1, msg.getRepeatedFloatCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedFloatCount());
-    assertTrue(123f == newMsg.getRepeatedFloat(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedFloat(123f)
-       .addRepeatedFloat(456f);
-    assertEquals(2, msg.getRepeatedFloatCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedFloatCount());
-    assertTrue(123f == newMsg.getRepeatedFloat(0));
-    assertTrue(456f == newMsg.getRepeatedFloat(1));
-  }
-
-  public void testMicroRepeatedDouble() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedDoubleCount());
-    msg.addRepeatedDouble(123.0);
-    assertEquals(1, msg.getRepeatedDoubleCount());
-    assertTrue(123.0 == msg.getRepeatedDouble(0));
-    msg.addRepeatedDouble(456.0);
-    assertEquals(2, msg.getRepeatedDoubleCount());
-    assertTrue(123.0 == msg.getRepeatedDouble(0));
-    assertTrue(456.0 == msg.getRepeatedDouble(1));
-    msg.setRepeatedDouble(0, 789.0);
-    assertEquals(2, msg.getRepeatedDoubleCount());
-    assertTrue(789.0 == msg.getRepeatedDouble(0));
-    assertTrue(456.0 == msg.getRepeatedDouble(1));
-    msg.clearRepeatedDouble();
-    assertEquals(0, msg.getRepeatedDoubleCount());
-    msg.clearRepeatedDouble()
-       .addRepeatedDouble(456.0);
-    assertEquals(1, msg.getRepeatedDoubleCount());
-    assertTrue(456.0 == msg.getRepeatedDouble(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedDoubleCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedDouble(123.0);
-    assertEquals(1, msg.getRepeatedDoubleCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedDoubleCount());
-    assertTrue(123.0 == newMsg.getRepeatedDouble(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedDouble(123.0)
-       .addRepeatedDouble(456.0);
-    assertEquals(2, msg.getRepeatedDoubleCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 20);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedDoubleCount());
-    assertTrue(123.0 == newMsg.getRepeatedDouble(0));
-    assertTrue(456.0 == newMsg.getRepeatedDouble(1));
-  }
-
-  public void testMicroRepeatedBool() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedBoolCount());
-    msg.addRepeatedBool(true);
-    assertEquals(1, msg.getRepeatedBoolCount());
-    assertEquals(true, msg.getRepeatedBool(0));
-    msg.addRepeatedBool(false);
-    assertEquals(2, msg.getRepeatedBoolCount());
-    assertEquals(true, msg.getRepeatedBool(0));
-    assertEquals(false, msg.getRepeatedBool(1));
-    msg.setRepeatedBool(0, false);
-    assertEquals(2, msg.getRepeatedBoolCount());
-    assertEquals(false, msg.getRepeatedBool(0));
-    assertEquals(false, msg.getRepeatedBool(1));
-    msg.clearRepeatedBool();
-    assertEquals(0, msg.getRepeatedBoolCount());
-    msg.clearRepeatedBool()
-       .addRepeatedBool(true);
-    assertEquals(1, msg.getRepeatedBoolCount());
-    assertEquals(true, msg.getRepeatedBool(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedBoolCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedBool(false);
-    assertEquals(1, msg.getRepeatedBoolCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedBoolCount());
-    assertEquals(false, newMsg.getRepeatedBool(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedBool(true)
-       .addRepeatedBool(false);
-    assertEquals(2, msg.getRepeatedBoolCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedBoolCount());
-    assertEquals(true, newMsg.getRepeatedBool(0));
-    assertEquals(false, newMsg.getRepeatedBool(1));
-  }
-
-  public void testMicroRepeatedString() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedStringCount());
-    msg.addRepeatedString("hello");
-    assertEquals(1, msg.getRepeatedStringCount());
-    assertEquals("hello", msg.getRepeatedString(0));
-    msg.addRepeatedString("bye");
-    assertEquals(2, msg.getRepeatedStringCount());
-    assertEquals("hello", msg.getRepeatedString(0));
-    assertEquals("bye", msg.getRepeatedString(1));
-    msg.setRepeatedString(0, "boo");
-    assertEquals(2, msg.getRepeatedStringCount());
-    assertEquals("boo", msg.getRepeatedString(0));
-    assertEquals("bye", msg.getRepeatedString(1));
-    msg.clearRepeatedString();
-    assertEquals(0, msg.getRepeatedStringCount());
-    msg.clearRepeatedString()
-       .addRepeatedString("hello");
-    assertEquals(1, msg.getRepeatedStringCount());
-    assertEquals("hello", msg.getRepeatedString(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedStringCount());
-
-    // Test 1 entry and an empty string
-    msg.clear()
-       .addRepeatedString("");
-    assertEquals(1, msg.getRepeatedStringCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedStringCount());
-    assertEquals("", newMsg.getRepeatedString(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedString("hello")
-       .addRepeatedString("world");
-    assertEquals(2, msg.getRepeatedStringCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedStringCount());
-    assertEquals("hello", newMsg.getRepeatedString(0));
-    assertEquals("world", newMsg.getRepeatedString(1));
-  }
-
-  public void testMicroRepeatedBytes() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedBytesCount());
-    msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"));
-    assertEquals(1, msg.getRepeatedBytesCount());
-    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
-    msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("bye"));
-    assertEquals(2, msg.getRepeatedBytesCount());
-    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
-    assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8());
-    msg.setRepeatedBytes(0, ByteStringMicro.copyFromUtf8("boo"));
-    assertEquals(2, msg.getRepeatedBytesCount());
-    assertEquals("boo", msg.getRepeatedBytes(0).toStringUtf8());
-    assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8());
-    msg.clearRepeatedBytes();
-    assertEquals(0, msg.getRepeatedBytesCount());
-    msg.clearRepeatedBytes()
-       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"));
-    assertEquals(1, msg.getRepeatedBytesCount());
-    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
-    msg.clear();
-    assertEquals(0, msg.getRepeatedBytesCount());
-
-    // Test 1 entry and an empty byte array can be serialized
-    msg.clear()
-       .addRepeatedBytes(ByteStringMicro.copyFromUtf8(""));
-    assertEquals(1, msg.getRepeatedBytesCount());
-    assertEquals("", msg.getRepeatedBytes(0).toStringUtf8());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedBytesCount());
-    assertEquals("", newMsg.getRepeatedBytes(0).toStringUtf8());
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"))
-       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("world"));
-    assertEquals(2, msg.getRepeatedBytesCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedBytesCount());
-    assertEquals("hello", newMsg.getRepeatedBytes(0).toStringUtf8());
-    assertEquals("world", newMsg.getRepeatedBytes(1).toStringUtf8());
-  }
-
-  public void testMicroRepeatedGroup() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    TestAllTypesMicro.RepeatedGroup group0 =
-      new TestAllTypesMicro.RepeatedGroup().setA(0);
-    TestAllTypesMicro.RepeatedGroup group1 =
-      new TestAllTypesMicro.RepeatedGroup().setA(1);
-    TestAllTypesMicro.RepeatedGroup group2 =
-      new TestAllTypesMicro.RepeatedGroup().setA(2);
-
-    msg.addRepeatedGroup(group0);
-    assertEquals(1, msg.getRepeatedGroupCount());
-    assertEquals(0, msg.getRepeatedGroup(0).getA());
-    msg.addRepeatedGroup(group1);
-    assertEquals(2, msg.getRepeatedGroupCount());
-    assertEquals(0, msg.getRepeatedGroup(0).getA());
-    assertEquals(1, msg.getRepeatedGroup(1).getA());
-    msg.setRepeatedGroup(0, group2);
-    assertEquals(2, msg.getRepeatedGroupCount());
-    assertEquals(2, msg.getRepeatedGroup(0).getA());
-    assertEquals(1, msg.getRepeatedGroup(1).getA());
-    msg.clearRepeatedGroup();
-    assertEquals(0, msg.getRepeatedGroupCount());
-    msg.clearRepeatedGroup()
-       .addRepeatedGroup(group1);
-    assertEquals(1, msg.getRepeatedGroupCount());
-    assertEquals(1, msg.getRepeatedGroup(0).getA());
-    msg.clear();
-    assertEquals(0, msg.getRepeatedGroupCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedGroup(group0);
-    assertEquals(1, msg.getRepeatedGroupCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedGroupCount());
-    assertEquals(0, newMsg.getRepeatedGroup(0).getA());
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedGroup(group0)
-       .addRepeatedGroup(group1);
-    assertEquals(2, msg.getRepeatedGroupCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 14);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedGroupCount());
-    assertEquals(0, newMsg.getRepeatedGroup(0).getA());
-    assertEquals(1, newMsg.getRepeatedGroup(1).getA());
-  }
-
-
-  public void testMicroRepeatedNestedMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    TestAllTypesMicro.NestedMessage nestedMsg0 =
-      new TestAllTypesMicro.NestedMessage().setBb(0);
-    TestAllTypesMicro.NestedMessage nestedMsg1 =
-      new TestAllTypesMicro.NestedMessage().setBb(1);
-    TestAllTypesMicro.NestedMessage nestedMsg2 =
-      new TestAllTypesMicro.NestedMessage().setBb(2);
-
-    msg.addRepeatedNestedMessage(nestedMsg0);
-    assertEquals(1, msg.getRepeatedNestedMessageCount());
-    assertEquals(0, msg.getRepeatedNestedMessage(0).getBb());
-    msg.addRepeatedNestedMessage(nestedMsg1);
-    assertEquals(2, msg.getRepeatedNestedMessageCount());
-    assertEquals(0, msg.getRepeatedNestedMessage(0).getBb());
-    assertEquals(1, msg.getRepeatedNestedMessage(1).getBb());
-    msg.setRepeatedNestedMessage(0, nestedMsg2);
-    assertEquals(2, msg.getRepeatedNestedMessageCount());
-    assertEquals(2, msg.getRepeatedNestedMessage(0).getBb());
-    assertEquals(1, msg.getRepeatedNestedMessage(1).getBb());
-    msg.clearRepeatedNestedMessage();
-    assertEquals(0, msg.getRepeatedNestedMessageCount());
-    msg.clearRepeatedNestedMessage()
-       .addRepeatedNestedMessage(nestedMsg1);
-    assertEquals(1, msg.getRepeatedNestedMessageCount());
-    assertEquals(1, msg.getRepeatedNestedMessage(0).getBb());
-    msg.clear();
-    assertEquals(0, msg.getRepeatedNestedMessageCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedNestedMessage(nestedMsg0);
-    assertEquals(1, msg.getRepeatedNestedMessageCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedNestedMessageCount());
-    assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb());
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedNestedMessage(nestedMsg0)
-       .addRepeatedNestedMessage(nestedMsg1);
-    assertEquals(2, msg.getRepeatedNestedMessageCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedNestedMessageCount());
-    assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb());
-    assertEquals(1, newMsg.getRepeatedNestedMessage(1).getBb());
-  }
-
-  public void testMicroRepeatedForeignMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    MicroOuterClass.ForeignMessageMicro foreignMsg0 =
-      new MicroOuterClass.ForeignMessageMicro().setC(0);
-    MicroOuterClass.ForeignMessageMicro foreignMsg1 =
-      new MicroOuterClass.ForeignMessageMicro().setC(1);
-    MicroOuterClass.ForeignMessageMicro foreignMsg2 =
-      new MicroOuterClass.ForeignMessageMicro().setC(2);
-
-    msg.addRepeatedForeignMessage(foreignMsg0);
-    assertEquals(1, msg.getRepeatedForeignMessageCount());
-    assertEquals(0, msg.getRepeatedForeignMessage(0).getC());
-    msg.addRepeatedForeignMessage(foreignMsg1);
-    assertEquals(2, msg.getRepeatedForeignMessageCount());
-    assertEquals(0, msg.getRepeatedForeignMessage(0).getC());
-    assertEquals(1, msg.getRepeatedForeignMessage(1).getC());
-    msg.setRepeatedForeignMessage(0, foreignMsg2);
-    assertEquals(2, msg.getRepeatedForeignMessageCount());
-    assertEquals(2, msg.getRepeatedForeignMessage(0).getC());
-    assertEquals(1, msg.getRepeatedForeignMessage(1).getC());
-    msg.clearRepeatedForeignMessage();
-    assertEquals(0, msg.getRepeatedForeignMessageCount());
-    msg.clearRepeatedForeignMessage()
-       .addRepeatedForeignMessage(foreignMsg1);
-    assertEquals(1, msg.getRepeatedForeignMessageCount());
-    assertEquals(1, msg.getRepeatedForeignMessage(0).getC());
-    msg.clear();
-    assertEquals(0, msg.getRepeatedForeignMessageCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedForeignMessage(foreignMsg0);
-    assertEquals(1, msg.getRepeatedForeignMessageCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedForeignMessageCount());
-    assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC());
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedForeignMessage(foreignMsg0)
-       .addRepeatedForeignMessage(foreignMsg1);
-    assertEquals(2, msg.getRepeatedForeignMessageCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedForeignMessageCount());
-    assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC());
-    assertEquals(1, newMsg.getRepeatedForeignMessage(1).getC());
-  }
-
-  public void testMicroRepeatedImportMessage() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    UnittestImportMicro.ImportMessageMicro importMsg0 =
-      new UnittestImportMicro.ImportMessageMicro().setD(0);
-    UnittestImportMicro.ImportMessageMicro importMsg1 =
-      new UnittestImportMicro.ImportMessageMicro().setD(1);
-    UnittestImportMicro.ImportMessageMicro importMsg2 =
-      new UnittestImportMicro.ImportMessageMicro().setD(2);
-
-    msg.addRepeatedImportMessage(importMsg0);
-    assertEquals(1, msg.getRepeatedImportMessageCount());
-    assertEquals(0, msg.getRepeatedImportMessage(0).getD());
-    msg.addRepeatedImportMessage(importMsg1);
-    assertEquals(2, msg.getRepeatedImportMessageCount());
-    assertEquals(0, msg.getRepeatedImportMessage(0).getD());
-    assertEquals(1, msg.getRepeatedImportMessage(1).getD());
-    msg.setRepeatedImportMessage(0, importMsg2);
-    assertEquals(2, msg.getRepeatedImportMessageCount());
-    assertEquals(2, msg.getRepeatedImportMessage(0).getD());
-    assertEquals(1, msg.getRepeatedImportMessage(1).getD());
-    msg.clearRepeatedImportMessage();
-    assertEquals(0, msg.getRepeatedImportMessageCount());
-    msg.clearRepeatedImportMessage()
-       .addRepeatedImportMessage(importMsg1);
-    assertEquals(1, msg.getRepeatedImportMessageCount());
-    assertEquals(1, msg.getRepeatedImportMessage(0).getD());
-    msg.clear();
-    assertEquals(0, msg.getRepeatedImportMessageCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedImportMessage(importMsg0);
-    assertEquals(1, msg.getRepeatedImportMessageCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedImportMessageCount());
-    assertEquals(0, newMsg.getRepeatedImportMessage(0).getD());
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedImportMessage(importMsg0)
-       .addRepeatedImportMessage(importMsg1);
-    assertEquals(2, msg.getRepeatedImportMessageCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedImportMessageCount());
-    assertEquals(0, newMsg.getRepeatedImportMessage(0).getD());
-    assertEquals(1, newMsg.getRepeatedImportMessage(1).getD());
-  }
-
-  public void testMicroRepeatedNestedEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.addRepeatedNestedEnum(TestAllTypesMicro.FOO);
-    assertEquals(1, msg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
-    msg.addRepeatedNestedEnum(TestAllTypesMicro.BAR);
-    assertEquals(2, msg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
-    msg.setRepeatedNestedEnum(0, TestAllTypesMicro.BAZ);
-    assertEquals(2, msg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.BAZ, msg.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
-    msg.clearRepeatedNestedEnum();
-    assertEquals(0, msg.getRepeatedNestedEnumCount());
-    msg.clearRepeatedNestedEnum()
-       .addRepeatedNestedEnum(TestAllTypesMicro.BAR);
-    assertEquals(1, msg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedNestedEnumCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedNestedEnum(TestAllTypesMicro.FOO);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedNestedEnum(TestAllTypesMicro.FOO)
-       .addRepeatedNestedEnum(TestAllTypesMicro.BAR);
-    assertEquals(2, msg.getRepeatedNestedEnumCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedNestedEnumCount());
-    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
-    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
-  }
-
-  public void testMicroRepeatedForeignEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO);
-    assertEquals(1, msg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
-    msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
-    assertEquals(2, msg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
-    msg.setRepeatedForeignEnum(0, MicroOuterClass.FOREIGN_MICRO_BAZ);
-    assertEquals(2, msg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAZ, msg.getRepeatedForeignEnum(0));
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
-    msg.clearRepeatedForeignEnum();
-    assertEquals(0, msg.getRepeatedForeignEnumCount());
-    msg.clearRepeatedForeignEnum()
-       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
-    assertEquals(1, msg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedForeignEnumCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO)
-       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
-    assertEquals(2, msg.getRepeatedForeignEnumCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedForeignEnumCount());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
-  }
-
-  public void testMicroRepeatedImportEnum() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO);
-    assertEquals(1, msg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
-    msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
-    assertEquals(2, msg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
-    msg.setRepeatedImportEnum(0, UnittestImportMicro.IMPORT_MICRO_BAZ);
-    assertEquals(2, msg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAZ, msg.getRepeatedImportEnum(0));
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
-    msg.clearRepeatedImportEnum();
-    assertEquals(0, msg.getRepeatedImportEnumCount());
-    msg.clearRepeatedImportEnum()
-       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
-    assertEquals(1, msg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedImportEnumCount());
-
-    // Test 1 entry
-    msg.clear()
-       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO);
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO)
-       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
-    assertEquals(2, msg.getRepeatedImportEnumCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedImportEnumCount());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
-  }
-
-  public void testMicroRepeatedStringPiece() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedStringPieceCount());
-    msg.addRepeatedStringPiece("hello");
-    assertEquals(1, msg.getRepeatedStringPieceCount());
-    assertEquals("hello", msg.getRepeatedStringPiece(0));
-    msg.addRepeatedStringPiece("bye");
-    assertEquals(2, msg.getRepeatedStringPieceCount());
-    assertEquals("hello", msg.getRepeatedStringPiece(0));
-    assertEquals("bye", msg.getRepeatedStringPiece(1));
-    msg.setRepeatedStringPiece(0, "boo");
-    assertEquals(2, msg.getRepeatedStringPieceCount());
-    assertEquals("boo", msg.getRepeatedStringPiece(0));
-    assertEquals("bye", msg.getRepeatedStringPiece(1));
-    msg.clearRepeatedStringPiece();
-    assertEquals(0, msg.getRepeatedStringPieceCount());
-    msg.clearRepeatedStringPiece()
-       .addRepeatedStringPiece("hello");
-    assertEquals(1, msg.getRepeatedStringPieceCount());
-    assertEquals("hello", msg.getRepeatedStringPiece(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedStringPieceCount());
-
-    // Test 1 entry and an empty string
-    msg.clear()
-       .addRepeatedStringPiece("");
-    assertEquals(1, msg.getRepeatedStringPieceCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedStringPieceCount());
-    assertEquals("", newMsg.getRepeatedStringPiece(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedStringPiece("hello")
-       .addRepeatedStringPiece("world");
-    assertEquals(2, msg.getRepeatedStringPieceCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedStringPieceCount());
-    assertEquals("hello", newMsg.getRepeatedStringPiece(0));
-    assertEquals("world", newMsg.getRepeatedStringPiece(1));
-  }
-
-  public void testMicroRepeatedCord() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertEquals(0, msg.getRepeatedCordCount());
-    msg.addRepeatedCord("hello");
-    assertEquals(1, msg.getRepeatedCordCount());
-    assertEquals("hello", msg.getRepeatedCord(0));
-    msg.addRepeatedCord("bye");
-    assertEquals(2, msg.getRepeatedCordCount());
-    assertEquals("hello", msg.getRepeatedCord(0));
-    assertEquals("bye", msg.getRepeatedCord(1));
-    msg.setRepeatedCord(0, "boo");
-    assertEquals(2, msg.getRepeatedCordCount());
-    assertEquals("boo", msg.getRepeatedCord(0));
-    assertEquals("bye", msg.getRepeatedCord(1));
-    msg.clearRepeatedCord();
-    assertEquals(0, msg.getRepeatedCordCount());
-    msg.clearRepeatedCord()
-       .addRepeatedCord("hello");
-    assertEquals(1, msg.getRepeatedCordCount());
-    assertEquals("hello", msg.getRepeatedCord(0));
-    msg.clear();
-    assertEquals(0, msg.getRepeatedCordCount());
-
-    // Test 1 entry and an empty string
-    msg.clear()
-       .addRepeatedCord("");
-    assertEquals(1, msg.getRepeatedCordCount());
-    byte [] result = msg.toByteArray();
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(1, newMsg.getRepeatedCordCount());
-    assertEquals("", newMsg.getRepeatedCord(0));
-
-    // Test 2 entries
-    msg.clear()
-       .addRepeatedCord("hello")
-       .addRepeatedCord("world");
-    assertEquals(2, msg.getRepeatedCordCount());
-    result = msg.toByteArray();
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesMicro.parseFrom(result);
-    assertEquals(2, newMsg.getRepeatedCordCount());
-    assertEquals("hello", newMsg.getRepeatedCord(0));
-    assertEquals("world", newMsg.getRepeatedCord(1));
-  }
-
-  /**
-   * Tests that code generation correctly wraps a single message into its outer
-   * class. The class {@code SingleMessageMicro} is imported from the outer
-   * class {@code UnittestSingleMicro}, whose name is implicit. Any error would
-   * cause this method to fail compilation.
-   */
-  public void testMicroSingle() throws Exception {
-    SingleMessageMicro msg = new SingleMessageMicro();
-  }
-
-  /**
-   * Tests that code generation correctly skips generating the outer class if
-   * unnecessary, letting a file-scope entity have the same name. The class
-   * {@code MultipleNameClashMicro} shares the same name with the file's outer
-   * class defined explicitly, but the file contains no other entities and has
-   * java_multiple_files set. Any error would cause this method to fail
-   * compilation.
-   */
-  public void testMicroMultipleNameClash() throws Exception {
-    MultipleNameClashMicro msg = new MultipleNameClashMicro();
-    msg.setField(0);
-  }
-
-  /**
-   * Tests that code generation correctly handles enums in different scopes in
-   * a source file with the option java_multiple_files set to true. Any error
-   * would cause this method to fail compilation.
-   */
-  public void testMicroMultipleEnumScoping() throws Exception {
-    FileScopeEnumRefMicro msg1 = new FileScopeEnumRefMicro();
-    msg1.setEnumField(UnittestMultipleMicro.ONE);
-    MessageScopeEnumRefMicro msg2 = new MessageScopeEnumRefMicro();
-    msg2.setEnumField(MessageScopeEnumRefMicro.TWO);
-  }
-
-  /**
-   * Tests that code generation with mixed values of the java_multiple_files
-   * options between the main source file and the imported source files would
-   * generate correct references. Any error would cause this method to fail
-   * compilation.
-   */
-  public void testMicroMultipleImportingNonMultiple() throws Exception {
-    UnittestImportMicro.ImportMessageMicro importMsg =
-        new UnittestImportMicro.ImportMessageMicro();
-    MultipleImportingNonMultipleMicro1 micro1 = new MultipleImportingNonMultipleMicro1();
-    micro1.setField(importMsg);
-    MultipleImportingNonMultipleMicro2 micro2 = new MultipleImportingNonMultipleMicro2();
-    micro2.setMicro1(micro1);
-  }
-
-  public void testMicroDefaults() throws Exception {
-    TestAllTypesMicro msg = new TestAllTypesMicro();
-    assertFalse(msg.hasDefaultInt32());
-    assertEquals(41, msg.getDefaultInt32());
-    assertFalse(msg.hasDefaultInt64());
-    assertEquals(42, msg.getDefaultInt64());
-    assertFalse(msg.hasDefaultUint32());
-    assertEquals(43, msg.getDefaultUint32());
-    assertFalse(msg.hasDefaultUint64());
-    assertEquals(44, msg.getDefaultUint64());
-    assertFalse(msg.hasDefaultSint32());
-    assertEquals(-45, msg.getDefaultSint32());
-    assertFalse(msg.hasDefaultSint64());
-    assertEquals(46, msg.getDefaultSint64());
-    assertFalse(msg.hasDefaultFixed32());
-    assertEquals(47, msg.getDefaultFixed32());
-    assertFalse(msg.hasDefaultFixed64());
-    assertEquals(48, msg.getDefaultFixed64());
-    assertFalse(msg.hasDefaultSfixed32());
-    assertEquals(49, msg.getDefaultSfixed32());
-    assertFalse(msg.hasDefaultSfixed64());
-    assertEquals(-50, msg.getDefaultSfixed64());
-    assertFalse(msg.hasDefaultFloat());
-    assertTrue(51.5f == msg.getDefaultFloat());
-    assertFalse(msg.hasDefaultDouble());
-    assertTrue(52.0e3 == msg.getDefaultDouble());
-    assertFalse(msg.hasDefaultBool());
-    assertEquals(true, msg.getDefaultBool());
-    assertFalse(msg.hasDefaultString());
-    assertEquals("hello", msg.getDefaultString());
-    assertFalse(msg.hasDefaultBytes());
-    assertEquals("world", msg.getDefaultBytes().toStringUtf8());
-    assertFalse(msg.hasDefaultNestedEnum());
-    assertEquals(TestAllTypesMicro.BAR, msg.getDefaultNestedEnum());
-    assertFalse(msg.hasDefaultForeignEnum());
-    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getDefaultForeignEnum());
-    assertFalse(msg.hasDefaultImportEnum());
-    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getDefaultImportEnum());
-    assertFalse(msg.hasDefaultFloatInf());
-    assertEquals(Float.POSITIVE_INFINITY, msg.getDefaultFloatInf());
-    assertFalse(msg.hasDefaultFloatNegInf());
-    assertEquals(Float.NEGATIVE_INFINITY, msg.getDefaultFloatNegInf());
-    assertFalse(msg.hasDefaultFloatNan());
-    assertEquals(Float.NaN, msg.getDefaultFloatNan());
-    assertFalse(msg.hasDefaultDoubleInf());
-    assertEquals(Double.POSITIVE_INFINITY, msg.getDefaultDoubleInf());
-    assertFalse(msg.hasDefaultDoubleNegInf());
-    assertEquals(Double.NEGATIVE_INFINITY, msg.getDefaultDoubleNegInf());
-    assertFalse(msg.hasDefaultDoubleNan());
-    assertEquals(Double.NaN, msg.getDefaultDoubleNan());
-  }
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * exactly up to a limit, this should not break things.
-   */
-  public void testSkipRawBytesBug() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2 };
-    CodedInputStreamMicro input = CodedInputStreamMicro.newInstance(rawBytes);
-
-    int limit = input.pushLimit(1);
-    input.skipRawBytes(1);
-    input.popLimit(limit);
-    assertEquals(2, input.readRawByte());
-  }
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * past the end of a buffer with a limit that has been set past the end of
-   * that buffer, this should not break things.
-   */
-  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
-    CodedInputStreamMicro input = CodedInputStreamMicro.newInstance(
-        new SmallBlockInputStream(rawBytes, 3));
-
-    int limit = input.pushLimit(4);
-    // In order to expose the bug we need to read at least one byte to prime the
-    // buffer inside the CodedInputStream.
-    assertEquals(1, input.readRawByte());
-    // Skip to the end of the limit.
-    input.skipRawBytes(3);
-    assertTrue(input.isAtEnd());
-    input.popLimit(limit);
-    assertEquals(5, input.readRawByte());
-  }
-
-  /**
-   * An InputStream which limits the number of bytes it reads at a time.
-   * We use this to make sure that CodedInputStream doesn't screw up when
-   * reading in small blocks.
-   */
-  private static final class SmallBlockInputStream extends FilterInputStream {
-    private final int blockSize;
-
-    public SmallBlockInputStream(byte[] data, int blockSize) {
-      this(new ByteArrayInputStream(data), blockSize);
-    }
-
-    public SmallBlockInputStream(InputStream in, int blockSize) {
-      super(in);
-      this.blockSize = blockSize;
-    }
-
-    public int read(byte[] b) throws IOException {
-      return super.read(b, 0, Math.min(b.length, blockSize));
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-      return super.read(b, off, Math.min(len, blockSize));
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java
deleted file mode 100644
index 42b1793..0000000
--- a/java/src/test/java/com/google/protobuf/NanoTest.java
+++ /dev/null
@@ -1,3962 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2013 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf;
-
-import com.google.protobuf.nano.BytesOffsetLengthTestNanoOuterClass.BytesOffsetLengthTestNano;
-import com.google.protobuf.nano.CodedInputByteBufferNano;
-import com.google.protobuf.nano.CodedOutputByteBufferNano;
-import com.google.protobuf.nano.EnumClassNanoMultiple;
-import com.google.protobuf.nano.EnumClassNanos;
-import com.google.protobuf.nano.EnumValidity;
-import com.google.protobuf.nano.EnumValidityAccessors;
-import com.google.protobuf.nano.FileScopeEnumMultiple;
-import com.google.protobuf.nano.FileScopeEnumRefNano;
-import com.google.protobuf.nano.InternalNano;
-import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
-import com.google.protobuf.nano.MessageNano;
-import com.google.protobuf.nano.MessageScopeEnumRefNano;
-import com.google.protobuf.nano.MultipleImportingNonMultipleNano1;
-import com.google.protobuf.nano.MultipleImportingNonMultipleNano2;
-import com.google.protobuf.nano.MultipleNameClashNano;
-import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
-import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
-import com.google.protobuf.nano.NanoOuterClass;
-import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
-import com.google.protobuf.nano.NanoReferenceTypes;
-import com.google.protobuf.nano.NanoReferenceTypesCompat;
-import com.google.protobuf.nano.NanoRepeatedPackables;
-import com.google.protobuf.nano.PackedExtensions;
-import com.google.protobuf.nano.RepeatedExtensions;
-import com.google.protobuf.nano.SingularExtensions;
-import com.google.protobuf.nano.TestRepeatedMergeNano;
-import com.google.protobuf.nano.UnittestMultipleNano;
-import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
-import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
-import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
-import com.google.protobuf.nano.UnknownEnumValuesNanoOuterClass.StandardVersion;
-import com.google.protobuf.nano.UnknownEnumValuesNanoOuterClass.VersionWithoutVal3;
-import com.google.protobuf.nano.testext.Extensions;
-import com.google.protobuf.nano.testext.Extensions.AnotherMessage;
-import com.google.protobuf.nano.testext.Extensions.MessageWithGroup;
-import com.google.protobuf.nano.testimport.UnittestImportNano;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-import java.util.HashMap;
-
-/**
- * Test nano runtime.
- *
- * @author ulas@google.com Ulas Kirazci
- */
-public class NanoTest extends TestCase {
-  @Override
-  public void setUp() throws Exception {
-  }
-
-  public void testSimpleMessageNano() throws Exception {
-    SimpleMessageNano msg = new SimpleMessageNano();
-    assertEquals(123, msg.d);
-    assertEquals(null, msg.nestedMsg);
-    assertEquals(SimpleMessageNano.BAZ, msg.defaultNestedEnum);
-
-    msg.d = 456;
-    assertEquals(456, msg.d);
-
-    SimpleMessageNano.NestedMessage nestedMsg = new SimpleMessageNano.NestedMessage();
-    nestedMsg.bb = 2;
-    assertEquals(2, nestedMsg.bb);
-    msg.nestedMsg = nestedMsg;
-    assertEquals(2, msg.nestedMsg.bb);
-
-    msg.defaultNestedEnum = SimpleMessageNano.BAR;
-    assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    SimpleMessageNano newMsg = SimpleMessageNano.parseFrom(result);
-    assertEquals(456, newMsg.d);
-    assertEquals(2, msg.nestedMsg.bb);
-    assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
-
-    msg.nestedMsg = null;
-    assertTrue(msgSerializedSize != msg.getSerializedSize());
-
-    msg.clear();
-    assertEquals(0, msg.getSerializedSize());
-  }
-
-  public void testRecursiveMessageNano() throws Exception {
-    RecursiveMessageNano msg = new RecursiveMessageNano();
-    assertTrue(msg.repeatedRecursiveMessageNano.length == 0);
-
-    RecursiveMessageNano msg1 = new RecursiveMessageNano();
-    msg1.id = 1;
-    assertEquals(1, msg1.id);
-    RecursiveMessageNano msg2 = new RecursiveMessageNano();
-    msg2.id = 2;
-    RecursiveMessageNano msg3 = new RecursiveMessageNano();
-    msg3.id = 3;
-
-    RecursiveMessageNano.NestedMessage nestedMsg = new RecursiveMessageNano.NestedMessage();
-    nestedMsg.a = msg1;
-    assertEquals(1, nestedMsg.a.id);
-
-    msg.id = 0;
-    msg.nestedMessage = nestedMsg;
-    msg.optionalRecursiveMessageNano = msg2;
-    msg.repeatedRecursiveMessageNano = new RecursiveMessageNano[] { msg3 };
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 16);
-    assertEquals(result.length, msgSerializedSize);
-
-    RecursiveMessageNano newMsg = RecursiveMessageNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedRecursiveMessageNano.length);
-
-    assertEquals(0, newMsg.id);
-    assertEquals(1, newMsg.nestedMessage.a.id);
-    assertEquals(2, newMsg.optionalRecursiveMessageNano.id);
-    assertEquals(3, newMsg.repeatedRecursiveMessageNano[0].id);
-  }
-
-  public void testMessageNoFields() {
-    SingleMessageNano msg = new SingleMessageNano();
-    assertEquals(0, msg.getSerializedSize());
-    assertEquals(0, MessageNano.toByteArray(msg).length);
-  }
-
-  public void testNanoRequiredInt32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.id = 123;
-    assertEquals(123, msg.id);
-    msg.clear().id = 456;
-    assertEquals(456, msg.id);
-    msg.clear();
-
-    msg.id = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 3);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.id);
-  }
-
-  public void testNanoOptionalInt32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalInt32 = 123;
-    assertEquals(123, msg.optionalInt32);
-    msg.clear()
-       .optionalInt32 = 456;
-    assertEquals(456, msg.optionalInt32);
-    msg.clear();
-
-    msg.optionalInt32 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalInt32);
-  }
-
-  public void testNanoOptionalInt64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalInt64 = 123;
-    assertEquals(123, msg.optionalInt64);
-    msg.clear()
-       .optionalInt64 = 456;
-    assertEquals(456, msg.optionalInt64);
-    msg.clear();
-    assertEquals(0, msg.optionalInt64);
-
-    msg.optionalInt64 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalInt64);
-  }
-
-  public void testNanoOptionalUint32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalUint32 = 123;
-    assertEquals(123, msg.optionalUint32);
-    msg.clear()
-       .optionalUint32 = 456;
-    assertEquals(456, msg.optionalUint32);
-    msg.clear();
-    assertEquals(0, msg.optionalUint32);
-
-    msg.optionalUint32 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalUint32);
-  }
-
-  public void testNanoOptionalUint64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalUint64 = 123;
-    assertEquals(123, msg.optionalUint64);
-    msg.clear()
-       .optionalUint64 = 456;
-    assertEquals(456, msg.optionalUint64);
-    msg.clear();
-    assertEquals(0, msg.optionalUint64);
-
-    msg.optionalUint64 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalUint64);
-  }
-
-  public void testNanoOptionalSint32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalSint32 = 123;
-    assertEquals(123, msg.optionalSint32);
-    msg.clear()
-       .optionalSint32 = 456;
-    assertEquals(456, msg.optionalSint32);
-    msg.clear();
-    assertEquals(0, msg.optionalSint32);
-
-    msg.optionalSint32 = -123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(-123, newMsg.optionalSint32);
-  }
-
-  public void testNanoOptionalSint64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalSint64 = 123;
-    assertEquals(123, msg.optionalSint64);
-    msg.clear()
-       .optionalSint64 = 456;
-    assertEquals(456, msg.optionalSint64);
-    msg.clear();
-    assertEquals(0, msg.optionalSint64);
-
-    msg.optionalSint64 = -123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(-123, newMsg.optionalSint64);
-  }
-
-  public void testNanoOptionalFixed32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalFixed32 = 123;
-    assertEquals(123, msg.optionalFixed32);
-    msg.clear()
-       .optionalFixed32 = 456;
-    assertEquals(456, msg.optionalFixed32);
-    msg.clear();
-    assertEquals(0, msg.optionalFixed32);
-
-    msg.optionalFixed32 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalFixed32);
-  }
-
-  public void testNanoOptionalFixed64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalFixed64 = 123;
-    assertEquals(123, msg.optionalFixed64);
-    msg.clear()
-       .optionalFixed64 = 456;
-    assertEquals(456, msg.optionalFixed64);
-    msg.clear();
-    assertEquals(0, msg.optionalFixed64);
-
-    msg.optionalFixed64 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalFixed64);
-  }
-
-  public void testNanoOptionalSfixed32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalSfixed32 = 123;
-    assertEquals(123, msg.optionalSfixed32);
-    msg.clear()
-       .optionalSfixed32 = 456;
-    assertEquals(456, msg.optionalSfixed32);
-    msg.clear();
-    assertEquals(0, msg.optionalSfixed32);
-
-    msg.optionalSfixed32 = 123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(123, newMsg.optionalSfixed32);
-  }
-
-  public void testNanoOptionalSfixed64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalSfixed64 = 123;
-    assertEquals(123, msg.optionalSfixed64);
-    msg.clear()
-       .optionalSfixed64 = 456;
-    assertEquals(456, msg.optionalSfixed64);
-    msg.clear();
-    assertEquals(0, msg.optionalSfixed64);
-
-    msg.optionalSfixed64 = -123;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(-123, newMsg.optionalSfixed64);
-  }
-
-  public void testNanoOptionalFloat() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalFloat = 123f;
-    assertTrue(123.0f == msg.optionalFloat);
-    msg.clear()
-       .optionalFloat = 456.0f;
-    assertTrue(456.0f == msg.optionalFloat);
-    msg.clear();
-    assertTrue(0.0f == msg.optionalFloat);
-
-    msg.optionalFloat = -123.456f;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(-123.456f == newMsg.optionalFloat);
-  }
-
-  public void testNanoOptionalDouble() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalDouble = 123;
-    assertTrue(123.0 == msg.optionalDouble);
-    msg.clear()
-       .optionalDouble = 456.0;
-    assertTrue(456.0 == msg.optionalDouble);
-    msg.clear();
-    assertTrue(0.0 == msg.optionalDouble);
-
-    msg.optionalDouble = -123.456;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 12);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(-123.456 == newMsg.optionalDouble);
-  }
-
-  public void testNanoOptionalBool() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalBool = true;
-    assertTrue(msg.optionalBool);
-    msg.clear()
-       .optionalBool = true;
-    assertTrue(msg.optionalBool);
-    msg.clear();
-    assertFalse(msg.optionalBool);
-
-    msg.optionalBool = true;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 5);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalBool);
-  }
-
-  public void testNanoOptionalString() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalString = "hello";
-    assertEquals("hello", msg.optionalString);
-    msg.clear();
-    assertTrue(msg.optionalString.isEmpty());
-    msg.clear()
-       .optionalString = "hello2";
-    assertEquals("hello2", msg.optionalString);
-    msg.clear();
-    assertTrue(msg.optionalString.isEmpty());
-
-    msg.optionalString = "bye";
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalString != null);
-    assertEquals("bye", newMsg.optionalString);
-  }
-
-  public void testNanoOptionalBytes() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertFalse(msg.optionalBytes.length > 0);
-    msg.optionalBytes = InternalNano.copyFromUtf8("hello");
-    assertTrue(msg.optionalBytes.length > 0);
-    assertEquals("hello", new String(msg.optionalBytes, "UTF-8"));
-    msg.clear();
-    assertFalse(msg.optionalBytes.length > 0);
-    msg.clear()
-       .optionalBytes = InternalNano.copyFromUtf8("hello");
-    assertTrue(msg.optionalBytes.length > 0);
-    msg.clear();
-    assertFalse(msg.optionalBytes.length > 0);
-
-    msg.optionalBytes = InternalNano.copyFromUtf8("bye");
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalBytes.length > 0);
-    assertEquals("bye", new String(newMsg.optionalBytes, "UTF-8"));
-  }
-
-  public void testNanoOptionalGroup() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    TestAllTypesNano.OptionalGroup grp = new TestAllTypesNano.OptionalGroup();
-    grp.a = 1;
-    assertFalse(msg.optionalGroup != null);
-    msg.optionalGroup = grp;
-    assertTrue(msg.optionalGroup != null);
-    assertEquals(1, msg.optionalGroup.a);
-    msg.clear();
-    assertFalse(msg.optionalGroup != null);
-    msg.clear()
-       .optionalGroup = new TestAllTypesNano.OptionalGroup();
-    msg.optionalGroup.a = 2;
-    assertTrue(msg.optionalGroup != null);
-    msg.clear();
-    assertFalse(msg.optionalGroup != null);
-
-    msg.optionalGroup = grp;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalGroup != null);
-    assertEquals(1, newMsg.optionalGroup.a);
-  }
-
-  public void testNanoOptionalGroupWithUnknownFieldsEnabled() throws Exception {
-    MessageWithGroup msg = new MessageWithGroup();
-    MessageWithGroup.Group grp = new MessageWithGroup.Group();
-    grp.a = 1;
-    msg.group = grp;
-    byte [] serialized = MessageNano.toByteArray(msg);
-
-    MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
-    assertEquals(1, parsed.group.a);
-
-    byte [] serialized2 = MessageNano.toByteArray(parsed);
-    assertEquals(serialized.length, serialized2.length);
-    MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
-    assertEquals(1, parsed2.group.a);
-  }
-
-  public void testNanoOptionalNestedMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    TestAllTypesNano.NestedMessage nestedMsg = new TestAllTypesNano.NestedMessage();
-    nestedMsg.bb = 1;
-    assertFalse(msg.optionalNestedMessage != null);
-    msg.optionalNestedMessage = nestedMsg;
-    assertTrue(msg.optionalNestedMessage != null);
-    assertEquals(1, msg.optionalNestedMessage.bb);
-    msg.clear();
-    assertFalse(msg.optionalNestedMessage != null);
-    msg.clear()
-       .optionalNestedMessage = new TestAllTypesNano.NestedMessage();
-    msg.optionalNestedMessage.bb = 2;
-    assertTrue(msg.optionalNestedMessage != null);
-    msg.clear();
-    assertFalse(msg.optionalNestedMessage != null);
-
-    msg.optionalNestedMessage = nestedMsg;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalNestedMessage != null);
-    assertEquals(1, newMsg.optionalNestedMessage.bb);
-  }
-
-  public void testNanoOptionalForeignMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    NanoOuterClass.ForeignMessageNano nestedMsg = new NanoOuterClass.ForeignMessageNano();
-    nestedMsg.c = 1;
-    assertFalse(msg.optionalForeignMessage != null);
-    msg.optionalForeignMessage = nestedMsg;
-    assertTrue(msg.optionalForeignMessage != null);
-    assertEquals(1, msg.optionalForeignMessage.c);
-    msg.clear();
-    assertFalse(msg.optionalForeignMessage != null);
-    msg.clear()
-       .optionalForeignMessage = new NanoOuterClass.ForeignMessageNano();
-    msg.optionalForeignMessage.c = 2;
-    assertTrue(msg.optionalForeignMessage != null);
-    msg.clear();
-    assertFalse(msg.optionalForeignMessage != null);
-
-    msg.optionalForeignMessage = nestedMsg;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalForeignMessage != null);
-    assertEquals(1, newMsg.optionalForeignMessage.c);
-  }
-
-  public void testNanoOptionalImportMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    UnittestImportNano.ImportMessageNano nestedMsg = new UnittestImportNano.ImportMessageNano();
-    nestedMsg.d = 1;
-    assertFalse(msg.optionalImportMessage != null);
-    msg.optionalImportMessage = nestedMsg;
-    assertTrue(msg.optionalImportMessage != null);
-    assertEquals(1, msg.optionalImportMessage.d);
-    msg.clear();
-    assertFalse(msg.optionalImportMessage != null);
-    msg.clear()
-       .optionalImportMessage = new UnittestImportNano.ImportMessageNano();
-    msg.optionalImportMessage.d = 2;
-    assertTrue(msg.optionalImportMessage != null);
-    msg.clear();
-    assertFalse(msg.optionalImportMessage != null);
-
-    msg.optionalImportMessage = nestedMsg;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalImportMessage != null);
-    assertEquals(1, newMsg.optionalImportMessage.d);
-  }
-
-  public void testNanoOptionalNestedEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalNestedEnum = TestAllTypesNano.BAR;
-    assertEquals(TestAllTypesNano.BAR, msg.optionalNestedEnum);
-    msg.clear()
-       .optionalNestedEnum = TestAllTypesNano.BAZ;
-    assertEquals(TestAllTypesNano.BAZ, msg.optionalNestedEnum);
-    msg.clear();
-    assertEquals(TestAllTypesNano.FOO, msg.optionalNestedEnum);
-
-    msg.optionalNestedEnum = TestAllTypesNano.BAR;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(TestAllTypesNano.BAR, newMsg.optionalNestedEnum);
-  }
-
-  public void testNanoOptionalForeignEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.optionalForeignEnum);
-    msg.clear()
-       .optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAZ;
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.optionalForeignEnum);
-    msg.clear();
-    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.optionalForeignEnum);
-
-    msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, newMsg.optionalForeignEnum);
-  }
-
-  public void testNanoOptionalImportEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.optionalImportEnum);
-    msg.clear()
-       .optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAZ;
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.optionalImportEnum);
-    msg.clear();
-    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.optionalImportEnum);
-
-    msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, newMsg.optionalImportEnum);
-  }
-
-  public void testNanoOptionalStringPiece() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalStringPiece = "hello";
-    assertEquals("hello", msg.optionalStringPiece);
-    msg.clear();
-    assertTrue(msg.optionalStringPiece.isEmpty());
-    msg.clear()
-       .optionalStringPiece = "hello2";
-    assertEquals("hello2", msg.optionalStringPiece);
-    msg.clear();
-    assertTrue(msg.optionalStringPiece.isEmpty());
-
-    msg.optionalStringPiece = "bye";
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalStringPiece != null);
-    assertEquals("bye", newMsg.optionalStringPiece);
-  }
-
-  public void testNanoOptionalCord() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalCord = "hello";
-    assertEquals("hello", msg.optionalCord);
-    msg.clear();
-    assertTrue(msg.optionalCord.isEmpty());
-    msg.clear()
-       .optionalCord = "hello2";
-    assertEquals("hello2", msg.optionalCord);
-    msg.clear();
-    assertTrue(msg.optionalCord.isEmpty());
-
-    msg.optionalCord = "bye";
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertTrue(newMsg.optionalCord != null);
-    assertEquals("bye", newMsg.optionalCord);
-  }
-
-  public void testNanoRepeatedInt32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedInt32.length);
-    msg.repeatedInt32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedInt32[1]);
-    assertEquals(456, msg.repeatedInt32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedInt32.length);
-    msg.clear()
-       .repeatedInt32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedInt32.length);
-    assertEquals(456, msg.repeatedInt32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedInt32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedInt32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedInt32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedInt32.length);
-    assertEquals(123, newMsg.repeatedInt32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedInt32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedInt32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedInt32.length);
-    assertEquals(123, newMsg.repeatedInt32[0]);
-    assertEquals(456, newMsg.repeatedInt32[1]);
-  }
-
-  public void testNanoRepeatedInt64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedInt64.length);
-    msg.repeatedInt64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedInt64[1]);
-    assertEquals(456, msg.repeatedInt64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedInt64.length);
-    msg.clear()
-       .repeatedInt64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedInt64.length);
-    assertEquals(456, msg.repeatedInt64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedInt64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedInt64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedInt64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedInt64.length);
-    assertEquals(123, newMsg.repeatedInt64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedInt64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedInt64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedInt64.length);
-    assertEquals(123, newMsg.repeatedInt64[0]);
-    assertEquals(456, newMsg.repeatedInt64[1]);
-  }
-
-  public void testNanoRepeatedUint32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedUint32.length);
-    msg.repeatedUint32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedUint32[1]);
-    assertEquals(456, msg.repeatedUint32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedUint32.length);
-    msg.clear()
-       .repeatedUint32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedUint32.length);
-    assertEquals(456, msg.repeatedUint32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedUint32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedUint32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedUint32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedUint32.length);
-    assertEquals(123, newMsg.repeatedUint32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedUint32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedUint32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedUint32.length);
-    assertEquals(123, newMsg.repeatedUint32[0]);
-    assertEquals(456, newMsg.repeatedUint32[1]);
-  }
-
-  public void testNanoRepeatedUint64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedUint64.length);
-    msg.repeatedUint64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedUint64[1]);
-    assertEquals(456, msg.repeatedUint64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedUint64.length);
-    msg.clear()
-       .repeatedUint64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedUint64.length);
-    assertEquals(456, msg.repeatedUint64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedUint64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedUint64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedUint64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedUint64.length);
-    assertEquals(123, newMsg.repeatedUint64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedUint64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedUint64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedUint64.length);
-    assertEquals(123, newMsg.repeatedUint64[0]);
-    assertEquals(456, newMsg.repeatedUint64[1]);
-  }
-
-  public void testNanoRepeatedSint32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedSint32.length);
-    msg.repeatedSint32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedSint32[1]);
-    assertEquals(456, msg.repeatedSint32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSint32.length);
-    msg.clear()
-       .repeatedSint32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedSint32.length);
-    assertEquals(456, msg.repeatedSint32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSint32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedSint32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedSint32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedSint32.length);
-    assertEquals(123, newMsg.repeatedSint32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedSint32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedSint32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedSint32.length);
-    assertEquals(123, newMsg.repeatedSint32[0]);
-    assertEquals(456, newMsg.repeatedSint32[1]);
-  }
-
-  public void testNanoRepeatedSint64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedSint64.length);
-    msg.repeatedSint64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedSint64[1]);
-    assertEquals(456, msg.repeatedSint64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSint64.length);
-    msg.clear()
-       .repeatedSint64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedSint64.length);
-    assertEquals(456, msg.repeatedSint64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSint64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedSint64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedSint64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedSint64.length);
-    assertEquals(123, newMsg.repeatedSint64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedSint64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedSint64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedSint64.length);
-    assertEquals(123, newMsg.repeatedSint64[0]);
-    assertEquals(456, newMsg.repeatedSint64[1]);
-  }
-
-  public void testNanoRepeatedFixed32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedFixed32.length);
-    msg.repeatedFixed32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedFixed32[1]);
-    assertEquals(456, msg.repeatedFixed32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFixed32.length);
-    msg.clear()
-       .repeatedFixed32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedFixed32.length);
-    assertEquals(456, msg.repeatedFixed32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFixed32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedFixed32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedFixed32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedFixed32.length);
-    assertEquals(123, newMsg.repeatedFixed32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedFixed32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedFixed32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 15);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedFixed32.length);
-    assertEquals(123, newMsg.repeatedFixed32[0]);
-    assertEquals(456, newMsg.repeatedFixed32[1]);
-  }
-
-  public void testNanoRepeatedFixed64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedFixed64.length);
-    msg.repeatedFixed64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedFixed64[1]);
-    assertEquals(456, msg.repeatedFixed64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFixed64.length);
-    msg.clear()
-       .repeatedFixed64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedFixed64.length);
-    assertEquals(456, msg.repeatedFixed64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFixed64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedFixed64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedFixed64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 13);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedFixed64.length);
-    assertEquals(123, newMsg.repeatedFixed64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedFixed64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedFixed64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 23);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedFixed64.length);
-    assertEquals(123, newMsg.repeatedFixed64[0]);
-    assertEquals(456, newMsg.repeatedFixed64[1]);
-  }
-
-  public void testNanoRepeatedSfixed32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedSfixed32.length);
-    msg.repeatedSfixed32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedSfixed32[1]);
-    assertEquals(456, msg.repeatedSfixed32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSfixed32.length);
-    msg.clear()
-       .repeatedSfixed32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedSfixed32.length);
-    assertEquals(456, msg.repeatedSfixed32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSfixed32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedSfixed32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedSfixed32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedSfixed32.length);
-    assertEquals(123, newMsg.repeatedSfixed32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedSfixed32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedSfixed32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 15);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedSfixed32.length);
-    assertEquals(123, newMsg.repeatedSfixed32[0]);
-    assertEquals(456, newMsg.repeatedSfixed32[1]);
-  }
-
-  public void testNanoRepeatedSfixed64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedSfixed64.length);
-    msg.repeatedSfixed64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedSfixed64[1]);
-    assertEquals(456, msg.repeatedSfixed64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSfixed64.length);
-    msg.clear()
-       .repeatedSfixed64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedSfixed64.length);
-    assertEquals(456, msg.repeatedSfixed64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedSfixed64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedSfixed64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedSfixed64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 13);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedSfixed64.length);
-    assertEquals(123, newMsg.repeatedSfixed64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedSfixed64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedSfixed64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 23);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedSfixed64.length);
-    assertEquals(123, newMsg.repeatedSfixed64[0]);
-    assertEquals(456, newMsg.repeatedSfixed64[1]);
-  }
-
-  public void testNanoRepeatedFloat() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedFloat.length);
-    msg.repeatedFloat = new float[] { 123f, 789f, 456f };
-    assertEquals(789f, msg.repeatedFloat[1]);
-    assertEquals(456f, msg.repeatedFloat[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFloat.length);
-    msg.clear()
-       .repeatedFloat = new float[] { 456f };
-    assertEquals(1, msg.repeatedFloat.length);
-    assertEquals(456f, msg.repeatedFloat[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedFloat.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedFloat = new float[] { 123f };
-    assertEquals(1, msg.repeatedFloat.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedFloat.length);
-    assertEquals(123f, newMsg.repeatedFloat[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedFloat = new float[] { 123f, 456f };
-    assertEquals(2, msg.repeatedFloat.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 15);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedFloat.length);
-    assertEquals(123f, newMsg.repeatedFloat[0]);
-    assertEquals(456f, newMsg.repeatedFloat[1]);
-  }
-
-  public void testNanoRepeatedDouble() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedDouble.length);
-    msg.repeatedDouble = new double[] { 123.0, 789.0, 456.0 };
-    assertEquals(789.0, msg.repeatedDouble[1]);
-    assertEquals(456.0, msg.repeatedDouble[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedDouble.length);
-    msg.clear()
-       .repeatedDouble = new double[] { 456.0 };
-    assertEquals(1, msg.repeatedDouble.length);
-    assertEquals(456.0, msg.repeatedDouble[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedDouble.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedDouble = new double[] { 123.0 };
-    assertEquals(1, msg.repeatedDouble.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 13);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedDouble.length);
-    assertEquals(123.0, newMsg.repeatedDouble[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedDouble = new double[] { 123.0, 456.0 };
-    assertEquals(2, msg.repeatedDouble.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 23);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedDouble.length);
-    assertEquals(123.0, newMsg.repeatedDouble[0]);
-    assertEquals(456.0, newMsg.repeatedDouble[1]);
-  }
-
-  public void testNanoRepeatedBool() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedBool.length);
-    msg.repeatedBool = new boolean[] { false, true, false };
-    assertTrue(msg.repeatedBool[1]);
-    assertFalse(msg.repeatedBool[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedBool.length);
-    msg.clear()
-       .repeatedBool = new boolean[] { true };
-    assertEquals(1, msg.repeatedBool.length);
-    assertTrue(msg.repeatedBool[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedBool.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedBool = new boolean[] { false };
-    assertEquals(1, msg.repeatedBool.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedBool.length);
-    assertFalse(newMsg.repeatedBool[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedBool = new boolean[] { true, false };
-    assertEquals(2, msg.repeatedBool.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedBool.length);
-    assertTrue(newMsg.repeatedBool[0]);
-    assertFalse(newMsg.repeatedBool[1]);
-  }
-
-  public void testNanoRepeatedString() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedString.length);
-    msg.repeatedString = new String[] { "hello", "bye", "boo" };
-    assertEquals("bye", msg.repeatedString[1]);
-    assertEquals("boo", msg.repeatedString[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedString.length);
-    msg.clear()
-       .repeatedString = new String[] { "boo" };
-    assertEquals(1, msg.repeatedString.length);
-    assertEquals("boo", msg.repeatedString[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedString.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedString = new String[] { "" };
-    assertEquals(1, msg.repeatedString.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedString.length);
-    assertTrue(newMsg.repeatedString[0].isEmpty());
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedString = new String[] { "hello", "world" };
-    assertEquals(2, msg.repeatedString.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 19);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedString.length);
-    assertEquals("hello", newMsg.repeatedString[0]);
-    assertEquals("world", newMsg.repeatedString[1]);
-  }
-
-  public void testNanoRepeatedBytes() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedBytes.length);
-    msg.repeatedBytes = new byte[][] {
-        InternalNano.copyFromUtf8("hello"),
-        InternalNano.copyFromUtf8("bye"),
-        InternalNano.copyFromUtf8("boo")
-    };
-    assertEquals("bye", new String(msg.repeatedBytes[1], "UTF-8"));
-    assertEquals("boo", new String(msg.repeatedBytes[2], "UTF-8"));
-    msg.clear();
-    assertEquals(0, msg.repeatedBytes.length);
-    msg.clear()
-       .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("boo") };
-    assertEquals(1, msg.repeatedBytes.length);
-    assertEquals("boo", new String(msg.repeatedBytes[0], "UTF-8"));
-    msg.clear();
-    assertEquals(0, msg.repeatedBytes.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("") };
-    assertEquals(1, msg.repeatedBytes.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedBytes.length);
-    assertTrue(newMsg.repeatedBytes[0].length == 0);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedBytes = new byte[][] {
-      InternalNano.copyFromUtf8("hello"),
-      InternalNano.copyFromUtf8("world")
-    };
-    assertEquals(2, msg.repeatedBytes.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 19);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedBytes.length);
-    assertEquals("hello", new String(newMsg.repeatedBytes[0], "UTF-8"));
-    assertEquals("world", new String(newMsg.repeatedBytes[1], "UTF-8"));
-  }
-
-  public void testNanoRepeatedGroup() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    TestAllTypesNano.RepeatedGroup group0 =
-      new TestAllTypesNano.RepeatedGroup();
-    group0.a = 0;
-    TestAllTypesNano.RepeatedGroup group1 =
-      new TestAllTypesNano.RepeatedGroup();
-    group1.a = 1;
-    TestAllTypesNano.RepeatedGroup group2 =
-      new TestAllTypesNano.RepeatedGroup();
-    group2.a = 2;
-
-    msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1, group2 };
-    assertEquals(3, msg.repeatedGroup.length);
-    assertEquals(0, msg.repeatedGroup[0].a);
-    assertEquals(1, msg.repeatedGroup[1].a);
-    assertEquals(2, msg.repeatedGroup[2].a);
-    msg.clear();
-    assertEquals(0, msg.repeatedGroup.length);
-    msg.clear()
-       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group1 };
-    assertEquals(1, msg.repeatedGroup.length);
-    assertEquals(1, msg.repeatedGroup[0].a);
-    msg.clear();
-    assertEquals(0, msg.repeatedGroup.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0 };
-    assertEquals(1, msg.repeatedGroup.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedGroup.length);
-    assertEquals(0, newMsg.repeatedGroup[0].a);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1 };
-    assertEquals(2, msg.repeatedGroup.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 14);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedGroup.length);
-    assertEquals(0, newMsg.repeatedGroup[0].a);
-    assertEquals(1, newMsg.repeatedGroup[1].a);
-  }
-
-  public void testNanoRepeatedNestedMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    TestAllTypesNano.NestedMessage nestedMsg0 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg0.bb = 0;
-    TestAllTypesNano.NestedMessage nestedMsg1 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg1.bb = 1;
-    TestAllTypesNano.NestedMessage nestedMsg2 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg2.bb = 2;
-
-    msg.repeatedNestedMessage =
-        new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1, nestedMsg2 };
-    assertEquals(3, msg.repeatedNestedMessage.length);
-    assertEquals(0, msg.repeatedNestedMessage[0].bb);
-    assertEquals(1, msg.repeatedNestedMessage[1].bb);
-    assertEquals(2, msg.repeatedNestedMessage[2].bb);
-    msg.clear();
-    assertEquals(0, msg.repeatedNestedMessage.length);
-    msg.clear()
-       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg1 };
-    assertEquals(1, msg.repeatedNestedMessage.length);
-    assertEquals(1, msg.repeatedNestedMessage[0].bb);
-    msg.clear();
-    assertEquals(0, msg.repeatedNestedMessage.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
-    assertEquals(1, msg.repeatedNestedMessage.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedNestedMessage.length);
-    assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1 };
-    assertEquals(2, msg.repeatedNestedMessage.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedNestedMessage.length);
-    assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
-    assertEquals(1, newMsg.repeatedNestedMessage[1].bb);
-  }
-
-  public void testNanoRepeatedForeignMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    NanoOuterClass.ForeignMessageNano foreignMsg0 =
-      new NanoOuterClass.ForeignMessageNano();
-    foreignMsg0.c = 0;
-    NanoOuterClass.ForeignMessageNano foreignMsg1 =
-      new NanoOuterClass.ForeignMessageNano();
-    foreignMsg1.c = 1;
-    NanoOuterClass.ForeignMessageNano foreignMsg2 =
-      new NanoOuterClass.ForeignMessageNano();
-    foreignMsg2.c = 2;
-
-    msg.repeatedForeignMessage =
-        new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
-    assertEquals(3, msg.repeatedForeignMessage.length);
-    assertEquals(0, msg.repeatedForeignMessage[0].c);
-    assertEquals(1, msg.repeatedForeignMessage[1].c);
-    assertEquals(2, msg.repeatedForeignMessage[2].c);
-    msg.clear();
-    assertEquals(0, msg.repeatedForeignMessage.length);
-    msg.clear()
-       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg1 };
-    assertEquals(1, msg.repeatedForeignMessage.length);
-    assertEquals(1, msg.repeatedForeignMessage[0].c);
-    msg.clear();
-    assertEquals(0, msg.repeatedForeignMessage.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0 };
-    assertEquals(1, msg.repeatedForeignMessage.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedForeignMessage.length);
-    assertEquals(0, newMsg.repeatedForeignMessage[0].c);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1 };
-    assertEquals(2, msg.repeatedForeignMessage.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedForeignMessage.length);
-    assertEquals(0, newMsg.repeatedForeignMessage[0].c);
-    assertEquals(1, newMsg.repeatedForeignMessage[1].c);
-  }
-
-  public void testNanoRepeatedImportMessage() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    UnittestImportNano.ImportMessageNano foreignMsg0 =
-      new UnittestImportNano.ImportMessageNano();
-    foreignMsg0.d = 0;
-    UnittestImportNano.ImportMessageNano foreignMsg1 =
-      new UnittestImportNano.ImportMessageNano();
-    foreignMsg1.d = 1;
-    UnittestImportNano.ImportMessageNano foreignMsg2 =
-      new UnittestImportNano.ImportMessageNano();
-    foreignMsg2.d = 2;
-
-    msg.repeatedImportMessage =
-        new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
-    assertEquals(3, msg.repeatedImportMessage.length);
-    assertEquals(0, msg.repeatedImportMessage[0].d);
-    assertEquals(1, msg.repeatedImportMessage[1].d);
-    assertEquals(2, msg.repeatedImportMessage[2].d);
-    msg.clear();
-    assertEquals(0, msg.repeatedImportMessage.length);
-    msg.clear()
-       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg1 };
-    assertEquals(1, msg.repeatedImportMessage.length);
-    assertEquals(1, msg.repeatedImportMessage[0].d);
-    msg.clear();
-    assertEquals(0, msg.repeatedImportMessage.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0 };
-    assertEquals(1, msg.repeatedImportMessage.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedImportMessage.length);
-    assertEquals(0, newMsg.repeatedImportMessage[0].d);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1 };
-    assertEquals(2, msg.repeatedImportMessage.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedImportMessage.length);
-    assertEquals(0, newMsg.repeatedImportMessage[0].d);
-    assertEquals(1, newMsg.repeatedImportMessage[1].d);
-  }
-
-  public void testNanoRepeatedNestedEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedNestedEnum = new int[] {
-        TestAllTypesNano.FOO,
-        TestAllTypesNano.BAR,
-        TestAllTypesNano.BAZ
-    };
-    assertEquals(3, msg.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
-    assertEquals(TestAllTypesNano.BAZ, msg.repeatedNestedEnum[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedNestedEnum.length);
-    msg.clear()
-       .repeatedNestedEnum = new int[] { TestAllTypesNano.BAR };
-    assertEquals(1, msg.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedNestedEnum.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
-    assertEquals(2, msg.repeatedNestedEnum.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
-  }
-
-  public void testNanoRepeatedForeignEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedForeignEnum = new int[] {
-        NanoOuterClass.FOREIGN_NANO_FOO,
-        NanoOuterClass.FOREIGN_NANO_BAR,
-        NanoOuterClass.FOREIGN_NANO_BAZ
-    };
-    assertEquals(3, msg.repeatedForeignEnum.length);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.repeatedForeignEnum[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedForeignEnum.length);
-    msg.clear()
-       .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_BAR };
-    assertEquals(1, msg.repeatedForeignEnum.length);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedForeignEnum.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_FOO };
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedForeignEnum.length);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedForeignEnum = new int[] {
-      NanoOuterClass.FOREIGN_NANO_FOO,
-      NanoOuterClass.FOREIGN_NANO_BAR
-    };
-    assertEquals(2, msg.repeatedForeignEnum.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedForeignEnum.length);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
-    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
-  }
-
-  public void testNanoRepeatedImportEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedImportEnum = new int[] {
-        UnittestImportNano.IMPORT_NANO_FOO,
-        UnittestImportNano.IMPORT_NANO_BAR,
-        UnittestImportNano.IMPORT_NANO_BAZ
-    };
-    assertEquals(3, msg.repeatedImportEnum.length);
-    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.repeatedImportEnum[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedImportEnum.length);
-    msg.clear()
-       .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_BAR };
-    assertEquals(1, msg.repeatedImportEnum.length);
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedImportEnum.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_FOO };
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedImportEnum.length);
-    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedImportEnum = new int[] {
-      UnittestImportNano.IMPORT_NANO_FOO,
-      UnittestImportNano.IMPORT_NANO_BAR
-    };
-    assertEquals(2, msg.repeatedImportEnum.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedImportEnum.length);
-    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
-    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
-  }
-
-  public void testNanoRepeatedStringPiece() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedStringPiece.length);
-    msg.repeatedStringPiece = new String[] { "hello", "bye", "boo" };
-    assertEquals("bye", msg.repeatedStringPiece[1]);
-    assertEquals("boo", msg.repeatedStringPiece[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedStringPiece.length);
-    msg.clear()
-       .repeatedStringPiece = new String[] { "boo" };
-    assertEquals(1, msg.repeatedStringPiece.length);
-    assertEquals("boo", msg.repeatedStringPiece[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedStringPiece.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedStringPiece = new String[] { "" };
-    assertEquals(1, msg.repeatedStringPiece.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedStringPiece.length);
-    assertTrue(newMsg.repeatedStringPiece[0].isEmpty());
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedStringPiece = new String[] { "hello", "world" };
-    assertEquals(2, msg.repeatedStringPiece.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 19);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedStringPiece.length);
-    assertEquals("hello", newMsg.repeatedStringPiece[0]);
-    assertEquals("world", newMsg.repeatedStringPiece[1]);
-  }
-
-  public void testNanoRepeatedCord() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedCord.length);
-    msg.repeatedCord = new String[] { "hello", "bye", "boo" };
-    assertEquals("bye", msg.repeatedCord[1]);
-    assertEquals("boo", msg.repeatedCord[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedCord.length);
-    msg.clear()
-       .repeatedCord = new String[] { "boo" };
-    assertEquals(1, msg.repeatedCord.length);
-    assertEquals("boo", msg.repeatedCord[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedCord.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedCord = new String[] { "" };
-    assertEquals(1, msg.repeatedCord.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 6);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedCord.length);
-    assertTrue(newMsg.repeatedCord[0].isEmpty());
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedCord = new String[] { "hello", "world" };
-    assertEquals(2, msg.repeatedCord.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 19);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedCord.length);
-    assertEquals("hello", newMsg.repeatedCord[0]);
-    assertEquals("world", newMsg.repeatedCord[1]);
-  }
-
-  public void testNanoRepeatedPackedInt32() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedPackedInt32.length);
-    msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedPackedInt32[1]);
-    assertEquals(456, msg.repeatedPackedInt32[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedInt32.length);
-    msg.clear()
-       .repeatedPackedInt32 = new int[] { 456 };
-    assertEquals(1, msg.repeatedPackedInt32.length);
-    assertEquals(456, msg.repeatedPackedInt32[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedInt32.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedPackedInt32 = new int[] { 123 };
-    assertEquals(1, msg.repeatedPackedInt32.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedPackedInt32.length);
-    assertEquals(123, newMsg.repeatedPackedInt32[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedPackedInt32 = new int[] { 123, 456 };
-    assertEquals(2, msg.repeatedPackedInt32.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 9);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedPackedInt32.length);
-    assertEquals(123, newMsg.repeatedPackedInt32[0]);
-    assertEquals(456, newMsg.repeatedPackedInt32[1]);
-  }
-
-  public void testNanoRepeatedPackedSfixed64() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    assertEquals(0, msg.repeatedPackedSfixed64.length);
-    msg.repeatedPackedSfixed64 = new long[] { 123, 789, 456 };
-    assertEquals(789, msg.repeatedPackedSfixed64[1]);
-    assertEquals(456, msg.repeatedPackedSfixed64[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedSfixed64.length);
-    msg.clear()
-       .repeatedPackedSfixed64 = new long[] { 456 };
-    assertEquals(1, msg.repeatedPackedSfixed64.length);
-    assertEquals(456, msg.repeatedPackedSfixed64[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedSfixed64.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedPackedSfixed64 = new long[] { 123 };
-    assertEquals(1, msg.repeatedPackedSfixed64.length);
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 14);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedPackedSfixed64.length);
-    assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedPackedSfixed64 = new long[] { 123, 456 };
-    assertEquals(2, msg.repeatedPackedSfixed64.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 22);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedPackedSfixed64.length);
-    assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
-    assertEquals(456, newMsg.repeatedPackedSfixed64[1]);
-  }
-
-  public void testNanoRepeatedPackedNestedEnum() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedPackedNestedEnum = new int[] {
-        TestAllTypesNano.FOO,
-        TestAllTypesNano.BAR,
-        TestAllTypesNano.BAZ
-    };
-    assertEquals(3, msg.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
-    assertEquals(TestAllTypesNano.BAZ, msg.repeatedPackedNestedEnum[2]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedNestedEnum.length);
-    msg.clear()
-       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.BAR };
-    assertEquals(1, msg.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[0]);
-    msg.clear();
-    assertEquals(0, msg.repeatedPackedNestedEnum.length);
-
-    // Test 1 entry
-    msg.clear()
-       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO };
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 7);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(1, newMsg.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
-
-    // Test 2 entries
-    msg.clear()
-       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
-    assertEquals(2, msg.repeatedPackedNestedEnum.length);
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 8);
-    assertEquals(result.length, msgSerializedSize);
-
-    newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(2, newMsg.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
-  }
-
-  public void testNanoRepeatedPackedSerializedSize() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
-    int msgSerializedSize = msg.getSerializedSize();
-    byte [] result = MessageNano.toByteArray(msg);
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 11);
-    assertEquals(result.length, msgSerializedSize);
-    TestAllTypesNano msg2 = new TestAllTypesNano();
-    msg2.repeatedPackedInt32 = new int[] { 123, 789, 456 };
-    byte [] result2 = new byte[msgSerializedSize];
-    MessageNano.toByteArray(msg2, result2, 0, msgSerializedSize);
-
-    // Check equal size and content.
-    assertEquals(msgSerializedSize, msg2.getSerializedSize());
-    assertTrue(Arrays.equals(result, result2));
-  }
-
-  public void testNanoRepeatedInt32ReMerge() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedInt32 = new int[] { 234 };
-    byte [] result1 = MessageNano.toByteArray(msg);
-
-    msg.clear().optionalInt32 = 789;
-    byte [] result2 = MessageNano.toByteArray(msg);
-
-    msg.clear().repeatedInt32 = new int[] { 123, 456 };
-    byte [] result3 = MessageNano.toByteArray(msg);
-
-    // Concatenate the three serializations and read as one message.
-    byte [] result = new byte[result1.length + result2.length + result3.length];
-    System.arraycopy(result1, 0, result, 0, result1.length);
-    System.arraycopy(result2, 0, result, result1.length, result2.length);
-    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(789, newMsg.optionalInt32);
-    assertEquals(3, newMsg.repeatedInt32.length);
-    assertEquals(234, newMsg.repeatedInt32[0]);
-    assertEquals(123, newMsg.repeatedInt32[1]);
-    assertEquals(456, newMsg.repeatedInt32[2]);
-  }
-
-  public void testNanoRepeatedNestedEnumReMerge() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
-    byte [] result1 = MessageNano.toByteArray(msg);
-
-    msg.clear().optionalInt32 = 789;
-    byte [] result2 = MessageNano.toByteArray(msg);
-
-    msg.clear().repeatedNestedEnum = new int[] { TestAllTypesNano.BAR, TestAllTypesNano.FOO };
-    byte [] result3 = MessageNano.toByteArray(msg);
-
-    // Concatenate the three serializations and read as one message.
-    byte [] result = new byte[result1.length + result2.length + result3.length];
-    System.arraycopy(result1, 0, result, 0, result1.length);
-    System.arraycopy(result2, 0, result, result1.length, result2.length);
-    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(789, newMsg.optionalInt32);
-    assertEquals(3, newMsg.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.BAR, newMsg.repeatedNestedEnum[1]);
-    assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[2]);
-  }
-
-  public void testNanoRepeatedNestedMessageReMerge() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    TestAllTypesNano.NestedMessage nestedMsg0 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg0.bb = 0;
-    TestAllTypesNano.NestedMessage nestedMsg1 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg1.bb = 1;
-    TestAllTypesNano.NestedMessage nestedMsg2 =
-      new TestAllTypesNano.NestedMessage();
-    nestedMsg2.bb = 2;
-
-    msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
-    byte [] result1 = MessageNano.toByteArray(msg);
-
-    msg.clear().optionalInt32 = 789;
-    byte [] result2 = MessageNano.toByteArray(msg);
-
-    msg.clear().repeatedNestedMessage =
-        new TestAllTypesNano.NestedMessage[] { nestedMsg1, nestedMsg2 };
-    byte [] result3 = MessageNano.toByteArray(msg);
-
-    // Concatenate the three serializations and read as one message.
-    byte [] result = new byte[result1.length + result2.length + result3.length];
-    System.arraycopy(result1, 0, result, 0, result1.length);
-    System.arraycopy(result2, 0, result, result1.length, result2.length);
-    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
-
-    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
-    assertEquals(789, newMsg.optionalInt32);
-    assertEquals(3, newMsg.repeatedNestedMessage.length);
-    assertEquals(nestedMsg0.bb, newMsg.repeatedNestedMessage[0].bb);
-    assertEquals(nestedMsg1.bb, newMsg.repeatedNestedMessage[1].bb);
-    assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb);
-  }
-
-  /**
-   * Tests that invalid enum values from the wire are not accepted.
-   */
-  public void testNanoEnumValidity() throws Exception {
-    final int invalid = 120;
-    final int alsoInvalid = 121;
-
-    EnumValidity.M m = new EnumValidity.M();
-    // Sanity check & baseline of the assertions for the first case below.
-    assertEquals(EnumValidity.E.default_, m.optionalE);
-    assertEquals(EnumValidity.E.BAZ, m.defaultE);
-
-    m.optionalE = invalid;
-    m.defaultE = invalid;
-    // E contains all valid values
-    m.repeatedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR};
-    m.packedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ};
-    // E2 contains some invalid values
-    m.repeatedE2 = new int[] {invalid, EnumValidity.E.BAR, alsoInvalid};
-    m.packedE2 = new int[] {EnumValidity.E.FOO, invalid, alsoInvalid};
-    // E3 contains all invalid values
-    m.repeatedE3 = new int[] {invalid, invalid};
-    m.packedE3 = new int[] {alsoInvalid, alsoInvalid};
-    byte[] serialized = MessageNano.toByteArray(m);
-    // Sanity check that we do have all data in the byte array.
-    assertEquals(31, serialized.length);
-
-    // Test 1: tests that invalid values aren't included in the deserialized message.
-    EnumValidity.M deserialized = MessageNano.mergeFrom(new EnumValidity.M(), serialized);
-    assertEquals(EnumValidity.E.default_, deserialized.optionalE);
-    assertEquals(EnumValidity.E.BAZ, deserialized.defaultE);
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR}, deserialized.repeatedE));
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ}, deserialized.packedE));
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.BAR}, deserialized.repeatedE2));
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.FOO}, deserialized.packedE2));
-    assertEquals(0, deserialized.repeatedE3.length);
-    assertEquals(0, deserialized.packedE3.length);
-
-    // Test 2: tests that invalid values do not override previous values in the field, including
-    // arrays, including pre-existing invalid values.
-    deserialized.optionalE = EnumValidity.E.BAR;
-    deserialized.defaultE = alsoInvalid;
-    deserialized.repeatedE = new int[] {EnumValidity.E.BAZ};
-    deserialized.packedE = new int[] {EnumValidity.E.BAZ, alsoInvalid};
-    deserialized.repeatedE2 = new int[] {invalid, alsoInvalid};
-    deserialized.packedE2 = null;
-    deserialized.repeatedE3 = null;
-    deserialized.packedE3 = new int[0];
-    MessageNano.mergeFrom(deserialized, serialized);
-    assertEquals(EnumValidity.E.BAR, deserialized.optionalE);
-    assertEquals(alsoInvalid, deserialized.defaultE);
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.BAZ, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAR},
-        deserialized.repeatedE));
-    assertTrue(Arrays.equals(
-        new int[] {EnumValidity.E.BAZ, alsoInvalid, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAZ},
-        deserialized.packedE));
-    assertTrue(Arrays.equals(
-        new int[] {invalid, alsoInvalid, /* + */ EnumValidity.E.BAR},
-        deserialized.repeatedE2));
-    assertTrue(Arrays.equals(
-        new int[] {/* <null> + */ EnumValidity.E.FOO},
-        deserialized.packedE2));
-    assertNull(deserialized.repeatedE3); // null + all invalid == null
-    assertEquals(0, deserialized.packedE3.length); // empty + all invalid == empty
-
-    // Test 3: reading by alternative forms
-    EnumValidity.Alt alt = MessageNano.mergeFrom(new EnumValidity.Alt(), serialized);
-    assertEquals(EnumValidity.E.BAR, // last valid value in m.repeatedE2
-        alt.repeatedE2AsOptional);
-    assertTrue(Arrays.equals(new int[] {EnumValidity.E.FOO}, alt.packedE2AsNonPacked));
-    assertEquals(0, alt.nonPackedE3AsPacked.length);
-  }
-
-  /**
-   * Tests the same as {@link #testNanoEnumValidity()} with accessor style. Repeated fields are
-   * not re-tested here because they are not affected by the accessor style.
-   */
-  public void testNanoEnumValidityAccessors() throws Exception {
-    final int invalid = 120;
-    final int alsoInvalid = 121;
-
-    EnumValidityAccessors.M m = new EnumValidityAccessors.M();
-    // Sanity check & baseline of the assertions for the first case below.
-    assertEquals(EnumValidityAccessors.default_, m.getOptionalE());
-    assertEquals(EnumValidityAccessors.BAZ, m.getDefaultE());
-
-    m.setOptionalE(invalid);
-    m.setDefaultE(invalid);
-    // Set repeatedE2 for Alt.repeatedE2AsOptional
-    m.repeatedE2 = new int[] {invalid, EnumValidityAccessors.BAR, alsoInvalid};
-    byte[] serialized = MessageNano.toByteArray(m);
-    // Sanity check that we do have all data in the byte array.
-    assertEquals(10, serialized.length);
-
-    // Test 1: tests that invalid values aren't included in the deserialized message.
-    EnumValidityAccessors.M deserialized =
-        MessageNano.mergeFrom(new EnumValidityAccessors.M(), serialized);
-    assertEquals(EnumValidityAccessors.default_, deserialized.getOptionalE());
-    assertEquals(EnumValidityAccessors.BAZ, deserialized.getDefaultE());
-
-    // Test 2: tests that invalid values do not override previous values in the field, including
-    // pre-existing invalid values.
-    deserialized.setOptionalE(EnumValidityAccessors.BAR);
-    deserialized.setDefaultE(alsoInvalid);
-    MessageNano.mergeFrom(deserialized, serialized);
-    assertEquals(EnumValidityAccessors.BAR, deserialized.getOptionalE());
-    assertEquals(alsoInvalid, deserialized.getDefaultE());
-
-    // Test 3: reading by alternative forms
-    EnumValidityAccessors.Alt alt =
-        MessageNano.mergeFrom(new EnumValidityAccessors.Alt(), serialized);
-    assertEquals(EnumValidityAccessors.BAR, // last valid value in m.repeatedE2
-        alt.getRepeatedE2AsOptional());
-  }
-
-  /**
-   * Tests that code generation correctly wraps a single message into its outer
-   * class. The class {@code SingleMessageNano} is imported from the outer
-   * class {@code UnittestSingleNano}, whose name is implicit. Any error would
-   * cause this method to fail compilation.
-   */
-  public void testNanoSingle() throws Exception {
-    SingleMessageNano msg = new SingleMessageNano();
-    assertNotNull(msg);
-  }
-
-  /**
-   * Tests that code generation correctly skips generating the outer class if
-   * unnecessary, letting a file-scope entity have the same name. The class
-   * {@code MultipleNameClashNano} shares the same name with the file's outer
-   * class defined explicitly, but the file contains no other entities and has
-   * java_multiple_files set. Any error would cause this method to fail
-   * compilation.
-   */
-  public void testNanoMultipleNameClash() throws Exception {
-    MultipleNameClashNano msg = new MultipleNameClashNano();
-    msg.field = 0;
-  }
-
-  /**
-   * Tests that code generation correctly handles enums in different scopes in
-   * a source file with the option java_multiple_files set to true. Any error
-   * would cause this method to fail compilation.
-   */
-  public void testNanoMultipleEnumScoping() throws Exception {
-    FileScopeEnumRefNano msg1 = new FileScopeEnumRefNano();
-    msg1.enumField = UnittestMultipleNano.ONE;
-    MessageScopeEnumRefNano msg2 = new MessageScopeEnumRefNano();
-    msg2.enumField = MessageScopeEnumRefNano.TWO;
-  }
-
-  /**
-   * Tests that code generation with mixed values of the java_multiple_files
-   * options between the main source file and the imported source files would
-   * generate correct references. Any error would cause this method to fail
-   * compilation.
-   */
-  public void testNanoMultipleImportingNonMultiple() throws Exception {
-    UnittestImportNano.ImportMessageNano importMsg = new UnittestImportNano.ImportMessageNano();
-    MultipleImportingNonMultipleNano1 nano1 = new MultipleImportingNonMultipleNano1();
-    nano1.field = importMsg;
-    MultipleImportingNonMultipleNano2 nano2 = new MultipleImportingNonMultipleNano2();
-    nano2.nano1 = nano1;
-  }
-
-  public void testNanoDefaults() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    for (int i = 0; i < 2; i++) {
-      assertEquals(41, msg.defaultInt32);
-      assertEquals(42, msg.defaultInt64);
-      assertEquals(43, msg.defaultUint32);
-      assertEquals(44, msg.defaultUint64);
-      assertEquals(-45, msg.defaultSint32);
-      assertEquals(46, msg.defaultSint64);
-      assertEquals(47, msg.defaultFixed32);
-      assertEquals(48, msg.defaultFixed64);
-      assertEquals(49, msg.defaultSfixed32);
-      assertEquals(-50, msg.defaultSfixed64);
-      assertTrue(51.5f == msg.defaultFloat);
-      assertTrue(52.0e3 == msg.defaultDouble);
-      assertEquals(true, msg.defaultBool);
-      assertEquals("hello", msg.defaultString);
-      assertEquals("world", new String(msg.defaultBytes, "UTF-8"));
-      assertEquals("dünya", msg.defaultStringNonascii);
-      assertEquals("dünyab", new String(msg.defaultBytesNonascii, "UTF-8"));
-      assertEquals(TestAllTypesNano.BAR, msg.defaultNestedEnum);
-      assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.defaultForeignEnum);
-      assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.defaultImportEnum);
-      assertEquals(Float.POSITIVE_INFINITY, msg.defaultFloatInf);
-      assertEquals(Float.NEGATIVE_INFINITY, msg.defaultFloatNegInf);
-      assertEquals(Float.NaN, msg.defaultFloatNan);
-      assertEquals(Double.POSITIVE_INFINITY, msg.defaultDoubleInf);
-      assertEquals(Double.NEGATIVE_INFINITY, msg.defaultDoubleNegInf);
-      assertEquals(Double.NaN, msg.defaultDoubleNan);
-
-      // Default values are not output, except for required fields.
-      byte [] result = MessageNano.toByteArray(msg);
-      int msgSerializedSize = msg.getSerializedSize();
-      //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-      assertTrue(msgSerializedSize == 3);
-      assertEquals(result.length, msgSerializedSize);
-      msg.clear();
-    }
-  }
-
-  public void testDifferentStringLengthsNano() throws Exception {
-    // Test string serialization roundtrip using strings of the following lengths,
-    // with ASCII and Unicode characters requiring different UTF-8 byte counts per
-    // char, hence causing the length delimiter varint to sometimes require more
-    // bytes for the Unicode strings than the ASCII string of the same length.
-    int[] lengths = new int[] {
-            0,
-            1,
-            (1 << 4) - 1,  // 1 byte for ASCII and Unicode
-            (1 << 7) - 1,  // 1 byte for ASCII, 2 bytes for Unicode
-            (1 << 11) - 1, // 2 bytes for ASCII and Unicode
-            (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
-            (1 << 17) - 1, // 3 bytes for ASCII and Unicode
-    };
-    for (int i : lengths) {
-      testEncodingOfString('q', i);      // 1 byte per char
-      testEncodingOfString('\u07FF', i); // 2 bytes per char
-      testEncodingOfString('\u0981', i); // 3 bytes per char
-    }
-  }
-
-  /** Regression test for https://github.com/google/protobuf/issues/292 */
-  public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
-    String testCase = "Foooooooo";
-    assertEquals(CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length()),
-            CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length() * 3));
-    assertEquals(11, CodedOutputByteBufferNano.computeStringSize(1, testCase));
-    // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
-    // An array of size 1 will cause a failure when trying to write the varint.
-    for (int i = 0; i < 11; i++) {
-      CodedOutputByteBufferNano bufferNano = CodedOutputByteBufferNano.newInstance(new byte[i]);
-      try {
-        bufferNano.writeString(1, testCase);
-        fail("Should have thrown an out of space exception");
-      } catch (CodedOutputByteBufferNano.OutOfSpaceException expected) {}
-    }
-  }
-
-  private void testEncodingOfString(char c, int length) throws InvalidProtocolBufferNanoException {
-    TestAllTypesNano testAllTypesNano = new TestAllTypesNano();
-    final String fullString = fullString(c, length);
-    testAllTypesNano.optionalString = fullString;
-    final TestAllTypesNano resultNano = new TestAllTypesNano();
-    MessageNano.mergeFrom(resultNano, MessageNano.toByteArray(testAllTypesNano));
-    assertEquals(fullString, resultNano.optionalString);
-  }
-
-  private String fullString(char c, int length) {
-    char[] result = new char[length];
-    Arrays.fill(result, c);
-    return new String(result);
-  }
-
-  public void testNanoWithHasParseFrom() throws Exception {
-    TestAllTypesNanoHas msg = null;
-    // Test false on creation, after clear and upon empty parse.
-    for (int i = 0; i < 3; i++) {
-      if (i == 0) {
-        msg = new TestAllTypesNanoHas();
-      } else if (i == 1) {
-        msg.clear();
-      } else if (i == 2) {
-        msg = TestAllTypesNanoHas.parseFrom(new byte[0]);
-      }
-      assertFalse(msg.hasOptionalInt32);
-      assertFalse(msg.hasOptionalString);
-      assertFalse(msg.hasOptionalBytes);
-      assertFalse(msg.hasOptionalNestedEnum);
-      assertFalse(msg.hasDefaultInt32);
-      assertFalse(msg.hasDefaultString);
-      assertFalse(msg.hasDefaultBytes);
-      assertFalse(msg.hasDefaultFloatNan);
-      assertFalse(msg.hasDefaultNestedEnum);
-      assertFalse(msg.hasId);
-      assertFalse(msg.hasRequiredEnum);
-      msg.optionalInt32 = 123;
-      msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
-      msg.optionalNestedMessage.bb = 2;
-      msg.optionalNestedEnum = TestAllTypesNano.BAZ;
-    }
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 10);
-    assertEquals(result.length, msgSerializedSize);
-
-    // Has fields true upon parse.
-    TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
-    assertEquals(123, newMsg.optionalInt32);
-    assertTrue(newMsg.hasOptionalInt32);
-    assertEquals(2, newMsg.optionalNestedMessage.bb);
-    assertTrue(newMsg.optionalNestedMessage.hasBb);
-    assertEquals(TestAllTypesNanoHas.BAZ, newMsg.optionalNestedEnum);
-    assertTrue(newMsg.hasOptionalNestedEnum);
-  }
-
-  public void testNanoWithHasSerialize() throws Exception {
-    TestAllTypesNanoHas msg = new TestAllTypesNanoHas();
-    msg.hasOptionalInt32 = true;
-    msg.hasOptionalString = true;
-    msg.hasOptionalBytes = true;
-    msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
-    msg.optionalNestedMessage.hasBb = true;
-    msg.hasOptionalNestedEnum = true;
-    msg.hasDefaultInt32 = true;
-    msg.hasDefaultString = true;
-    msg.hasDefaultBytes = true;
-    msg.hasDefaultFloatNan = true;
-    msg.hasDefaultNestedEnum = true;
-    msg.hasId = true;
-    msg.hasRequiredEnum = true;
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    assertEquals(result.length, msgSerializedSize);
-
-    // Now deserialize and find that all fields are set and equal to their defaults.
-    TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
-    assertTrue(newMsg.hasOptionalInt32);
-    assertTrue(newMsg.hasOptionalString);
-    assertTrue(newMsg.hasOptionalBytes);
-    assertTrue(newMsg.optionalNestedMessage.hasBb);
-    assertTrue(newMsg.hasOptionalNestedEnum);
-    assertTrue(newMsg.hasDefaultInt32);
-    assertTrue(newMsg.hasDefaultString);
-    assertTrue(newMsg.hasDefaultBytes);
-    assertTrue(newMsg.hasDefaultFloatNan);
-    assertTrue(newMsg.hasDefaultNestedEnum);
-    assertTrue(newMsg.hasId);
-    assertTrue(newMsg.hasRequiredEnum);
-    assertEquals(0, newMsg.optionalInt32);
-    assertEquals(0, newMsg.optionalString.length());
-    assertEquals(0, newMsg.optionalBytes.length);
-    assertEquals(0, newMsg.optionalNestedMessage.bb);
-    assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum);
-    assertEquals(41, newMsg.defaultInt32);
-    assertEquals("hello", newMsg.defaultString);
-    assertEquals("world", new String(newMsg.defaultBytes, "UTF-8"));
-    assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum);
-    assertEquals(Float.NaN, newMsg.defaultFloatNan);
-    assertEquals(0, newMsg.id);
-    assertEquals(TestAllTypesNanoHas.FOO, newMsg.requiredEnum);
-  }
-
-  public void testNanoWithAccessorsBasic() throws Exception {
-    TestNanoAccessors msg = new TestNanoAccessors();
-
-    // Makes sure required, repeated, and message fields are still public
-    msg.id = 3;
-    msg.repeatedBytes = new byte[2][3];
-    msg.optionalNestedMessage = null;
-
-    // Test accessors
-    assertEquals(0, msg.getOptionalInt32());
-    assertFalse(msg.hasOptionalInt32());
-    msg.setOptionalInt32(135);
-    assertEquals(135, msg.getOptionalInt32());
-    assertTrue(msg.hasOptionalInt32());
-    msg.clearOptionalInt32();
-    assertFalse(msg.hasOptionalInt32());
-    msg.setOptionalInt32(0); // default value
-    assertTrue(msg.hasOptionalInt32());
-
-    // Test NPE
-    try {
-      msg.setOptionalBytes(null);
-      fail();
-    } catch (NullPointerException expected) {}
-    try {
-      msg.setOptionalString(null);
-      fail();
-    } catch (NullPointerException expected) {}
-
-    // Test has bit on bytes field with defaults and clear() re-clones the default array
-    assertFalse(msg.hasDefaultBytes());
-    byte[] defaultBytes = msg.getDefaultBytes();
-    msg.setDefaultBytes(defaultBytes);
-    assertTrue(msg.hasDefaultBytes());
-    msg.clearDefaultBytes();
-    assertFalse(msg.hasDefaultBytes());
-    defaultBytes[0]++; // modify original array
-    assertFalse(Arrays.equals(defaultBytes, msg.getDefaultBytes()));
-
-    // Test has bits that require additional bit fields
-    assertFalse(msg.hasBitFieldCheck());
-    msg.setBitFieldCheck(0);
-    assertTrue(msg.hasBitFieldCheck());
-    assertFalse(msg.hasBeforeBitFieldCheck()); // checks bit field does not leak
-    assertFalse(msg.hasAfterBitFieldCheck());
-
-    // Test clear() clears has bits
-    msg.setOptionalString("hi");
-    msg.setDefaultString("there");
-    msg.clear();
-    assertFalse(msg.hasOptionalString());
-    assertFalse(msg.hasDefaultString());
-    assertFalse(msg.hasBitFieldCheck());
-
-    // Test set() and clear() returns itself (compiles = success)
-    msg.clear()
-        .setOptionalInt32(3)
-        .clearDefaultBytes()
-        .setOptionalString("4");
-  }
-
-  public void testNanoWithAccessorsParseFrom() throws Exception {
-    TestNanoAccessors msg = null;
-    // Test false on creation, after clear and upon empty parse.
-    for (int i = 0; i < 3; i++) {
-      if (i == 0) {
-        msg = new TestNanoAccessors();
-      } else if (i == 1) {
-        msg.clear();
-      } else if (i == 2) {
-        msg = TestNanoAccessors.parseFrom(new byte[0]);
-      }
-      assertFalse(msg.hasOptionalInt32());
-      assertFalse(msg.hasOptionalString());
-      assertFalse(msg.hasOptionalBytes());
-      assertFalse(msg.hasOptionalNestedEnum());
-      assertFalse(msg.hasDefaultInt32());
-      assertFalse(msg.hasDefaultString());
-      assertFalse(msg.hasDefaultBytes());
-      assertFalse(msg.hasDefaultFloatNan());
-      assertFalse(msg.hasDefaultNestedEnum());
-      msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
-      msg.optionalNestedMessage.setBb(2);
-      msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
-      msg.setDefaultInt32(msg.getDefaultInt32());
-    }
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
-    assertTrue(msgSerializedSize == 14);
-    assertEquals(result.length, msgSerializedSize);
-
-    // Has fields true upon parse.
-    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
-    assertEquals(2, newMsg.optionalNestedMessage.getBb());
-    assertTrue(newMsg.optionalNestedMessage.hasBb());
-    assertEquals(TestNanoAccessors.BAZ, newMsg.getOptionalNestedEnum());
-    assertTrue(newMsg.hasOptionalNestedEnum());
-
-    // Has field true on fields with explicit default values from wire.
-    assertTrue(newMsg.hasDefaultInt32());
-    assertEquals(41, newMsg.getDefaultInt32());
-  }
-
-  public void testNanoWithAccessorsPublicFieldTypes() throws Exception {
-    TestNanoAccessors msg = new TestNanoAccessors();
-    assertNull(msg.optionalNestedMessage);
-    assertEquals(0, msg.id);
-    assertEquals(0, msg.repeatedNestedEnum.length);
-
-    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(MessageNano.toByteArray(msg));
-    assertNull(newMsg.optionalNestedMessage);
-    assertEquals(0, newMsg.id);
-    assertEquals(0, newMsg.repeatedNestedEnum.length);
-
-    TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
-    nestedMessage.setBb(5);
-    newMsg.optionalNestedMessage = nestedMessage;
-    newMsg.id = -1;
-    newMsg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
-
-    TestNanoAccessors newMsg2 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg));
-    assertEquals(nestedMessage.getBb(), newMsg2.optionalNestedMessage.getBb());
-    assertEquals(-1, newMsg2.id);
-    assertEquals(TestAllTypesNano.FOO, newMsg2.repeatedNestedEnum[0]);
-
-    newMsg2.optionalNestedMessage = null;
-    newMsg2.id = 0;
-    newMsg2.repeatedNestedEnum = null;
-
-    TestNanoAccessors newMsg3 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg2));
-    assertNull(newMsg3.optionalNestedMessage);
-    assertEquals(0, newMsg3.id);
-    assertEquals(0, newMsg3.repeatedNestedEnum.length);
-  }
-
-  public void testNanoWithAccessorsSerialize() throws Exception {
-    TestNanoAccessors msg = new TestNanoAccessors();
-    msg.setOptionalInt32(msg.getOptionalInt32());
-    msg.setOptionalString(msg.getOptionalString());
-    msg.setOptionalBytes(msg.getOptionalBytes());
-    TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
-    nestedMessage.setBb(nestedMessage.getBb());
-    msg.optionalNestedMessage = nestedMessage;
-    msg.setOptionalNestedEnum(msg.getOptionalNestedEnum());
-    msg.setDefaultInt32(msg.getDefaultInt32());
-    msg.setDefaultString(msg.getDefaultString());
-    msg.setDefaultBytes(msg.getDefaultBytes());
-    msg.setDefaultFloatNan(msg.getDefaultFloatNan());
-    msg.setDefaultNestedEnum(msg.getDefaultNestedEnum());
-
-    byte [] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    assertEquals(result.length, msgSerializedSize);
-
-    // Now deserialize and find that all fields are set and equal to their defaults.
-    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
-    assertTrue(newMsg.hasOptionalInt32());
-    assertTrue(newMsg.hasOptionalString());
-    assertTrue(newMsg.hasOptionalBytes());
-    assertTrue(newMsg.optionalNestedMessage.hasBb());
-    assertTrue(newMsg.hasOptionalNestedEnum());
-    assertTrue(newMsg.hasDefaultInt32());
-    assertTrue(newMsg.hasDefaultString());
-    assertTrue(newMsg.hasDefaultBytes());
-    assertTrue(newMsg.hasDefaultFloatNan());
-    assertTrue(newMsg.hasDefaultNestedEnum());
-    assertEquals(0, newMsg.getOptionalInt32());
-    assertEquals(0, newMsg.getOptionalString().length());
-    assertEquals(0, newMsg.getOptionalBytes().length);
-    assertEquals(0, newMsg.optionalNestedMessage.getBb());
-    assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
-    assertEquals(41, newMsg.getDefaultInt32());
-    assertEquals("hello", newMsg.getDefaultString());
-    assertEquals("world", new String(newMsg.getDefaultBytes(), "UTF-8"));
-    assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
-    assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
-    assertEquals(0, newMsg.id);
-  }
-
-  public void testNanoJavaEnumStyle() throws Exception {
-    EnumClassNanos.EnumClassNano msg = new EnumClassNanos.EnumClassNano();
-    assertEquals(EnumClassNanos.FileScopeEnum.ONE, msg.one);
-    assertEquals(EnumClassNanos.EnumClassNano.MessageScopeEnum.TWO, msg.two);
-
-    EnumClassNanoMultiple msg2 = new EnumClassNanoMultiple();
-    assertEquals(FileScopeEnumMultiple.THREE, msg2.three);
-    assertEquals(EnumClassNanoMultiple.MessageScopeEnumMultiple.FOUR, msg2.four);
-  }
-
-  /**
-   * Tests that fields with a default value of NaN are not serialized when
-   * set to NaN. This is a special case as NaN != NaN, so normal equality
-   * checks don't work.
-   */
-  public void testNanoNotANumberDefaults() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.defaultDoubleNan = 0;
-    msg.defaultFloatNan = 0;
-    byte[] result = MessageNano.toByteArray(msg);
-    int msgSerializedSize = msg.getSerializedSize();
-    assertTrue(result.length == msgSerializedSize);
-    assertTrue(msgSerializedSize > 3);
-
-    msg.defaultDoubleNan = Double.NaN;
-    msg.defaultFloatNan = Float.NaN;
-    result = MessageNano.toByteArray(msg);
-    msgSerializedSize = msg.getSerializedSize();
-    assertEquals(3, result.length);
-    assertEquals(3, msgSerializedSize);
-  }
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * exactly up to a limit, this should not break things.
-   */
-  public void testSkipRawBytesBug() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2 };
-    CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
-
-    int limit = input.pushLimit(1);
-    input.skipRawBytes(1);
-    input.popLimit(limit);
-    assertEquals(2, input.readRawByte());
-  }
-
-  /**
-   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
-   * past the end of a buffer with a limit that has been set past the end of
-   * that buffer, this should not break things.
-   */
-  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
-    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
-    CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
-
-    int limit = input.pushLimit(4);
-    // In order to expose the bug we need to read at least one byte to prime the
-    // buffer inside the CodedInputStream.
-    assertEquals(1, input.readRawByte());
-    // Skip to the end of the limit.
-    input.skipRawBytes(3);
-    assertTrue(input.isAtEnd());
-    input.popLimit(limit);
-    assertEquals(5, input.readRawByte());
-  }
-
-  // Test a smattering of various proto types for printing
-  public void testMessageNanoPrinter() {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.optionalInt32 = 14;
-    msg.optionalFloat = 42.3f;
-    msg.optionalString = "String \"with' both quotes";
-    msg.optionalBytes = new byte[] {'"', '\0', 1, 8};
-    msg.optionalGroup = new TestAllTypesNano.OptionalGroup();
-    msg.optionalGroup.a = 15;
-    msg.repeatedInt64 = new long[2];
-    msg.repeatedInt64[0] = 1L;
-    msg.repeatedInt64[1] = -1L;
-    msg.repeatedBytes = new byte[2][];
-    msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
-    msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[2];
-    msg.repeatedGroup[0] = new TestAllTypesNano.RepeatedGroup();
-    msg.repeatedGroup[0].a = -27;
-    msg.repeatedGroup[1] = new TestAllTypesNano.RepeatedGroup();
-    msg.repeatedGroup[1].a = -72;
-    msg.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
-    msg.optionalNestedMessage.bb = 7;
-    msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[2];
-    msg.repeatedNestedMessage[0] = new TestAllTypesNano.NestedMessage();
-    msg.repeatedNestedMessage[0].bb = 77;
-    msg.repeatedNestedMessage[1] = new TestAllTypesNano.NestedMessage();
-    msg.repeatedNestedMessage[1].bb = 88;
-    msg.optionalNestedEnum = TestAllTypesNano.BAZ;
-    msg.repeatedNestedEnum = new int[2];
-    msg.repeatedNestedEnum[0] = TestAllTypesNano.BAR;
-    msg.repeatedNestedEnum[1] = TestAllTypesNano.FOO;
-    msg.repeatedStringPiece = new String[] {null, "world"};
-
-    String protoPrint = msg.toString();
-    assertTrue(protoPrint.contains("optional_int32: 14"));
-    assertTrue(protoPrint.contains("optional_float: 42.3"));
-    assertTrue(protoPrint.contains("optional_double: 0.0"));
-    assertTrue(protoPrint.contains("optional_string: \"String \\u0022with\\u0027 both quotes\""));
-    assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
-    assertTrue(protoPrint.contains("optional_group <\n  a: 15\n>"));
-
-    assertTrue(protoPrint.contains("repeated_int64: 1\nrepeated_int64: -1"));
-    assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
-    assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
-    assertTrue(protoPrint.contains("repeated_group <\n  a: -27\n>\n"
-            + "repeated_group <\n  a: -72\n>"));
-    assertTrue(protoPrint.contains("optional_nested_message <\n  bb: 7\n>"));
-    assertTrue(protoPrint.contains("repeated_nested_message <\n  bb: 77\n>\n"
-            + "repeated_nested_message <\n  bb: 88\n>"));
-    assertTrue(protoPrint.contains("optional_nested_enum: 3"));
-    assertTrue(protoPrint.contains("repeated_nested_enum: 2\nrepeated_nested_enum: 1"));
-    assertTrue(protoPrint.contains("default_int32: 41"));
-    assertTrue(protoPrint.contains("default_string: \"hello\""));
-    assertFalse(protoPrint.contains("repeated_string_piece: \"\""));  // null should be dropped
-    assertTrue(protoPrint.contains("repeated_string_piece: \"world\""));
-  }
-
-  public void testMessageNanoPrinterAccessors() throws Exception {
-    TestNanoAccessors msg = new TestNanoAccessors();
-    msg.setOptionalInt32(13);
-    msg.setOptionalString("foo");
-    msg.setOptionalBytes(new byte[] {'"', '\0', 1, 8});
-    msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
-    msg.optionalNestedMessage.setBb(7);
-    msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
-    msg.repeatedInt32 = new int[] { 1, -1 };
-    msg.repeatedString = new String[] { "Hello", "world" };
-    msg.repeatedBytes = new byte[2][];
-    msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
-    msg.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[2];
-    msg.repeatedNestedMessage[0] = new TestNanoAccessors.NestedMessage();
-    msg.repeatedNestedMessage[0].setBb(5);
-    msg.repeatedNestedMessage[1] = new TestNanoAccessors.NestedMessage();
-    msg.repeatedNestedMessage[1].setBb(6);
-    msg.repeatedNestedEnum = new int[] { TestNanoAccessors.FOO, TestNanoAccessors.BAR };
-    msg.id = 33;
-
-    String protoPrint = msg.toString();
-    assertTrue(protoPrint.contains("optional_int32: 13"));
-    assertTrue(protoPrint.contains("optional_string: \"foo\""));
-    assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
-    assertTrue(protoPrint.contains("optional_nested_message <\n  bb: 7\n>"));
-    assertTrue(protoPrint.contains("optional_nested_enum: 3"));
-    assertTrue(protoPrint.contains("repeated_int32: 1\nrepeated_int32: -1"));
-    assertTrue(protoPrint.contains("repeated_string: \"Hello\"\nrepeated_string: \"world\""));
-    assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
-    assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
-    assertTrue(protoPrint.contains("repeated_nested_message <\n  bb: 5\n>\n"
-            + "repeated_nested_message <\n  bb: 6\n>"));
-    assertTrue(protoPrint.contains("repeated_nested_enum: 1\nrepeated_nested_enum: 2"));
-    assertTrue(protoPrint.contains("id: 33"));
-  }
-
-  public void testExtensions() throws Exception {
-    Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
-    message.field = 5;
-    int[] int32s = {1, 2};
-    int[] uint32s = {3, 4};
-    int[] sint32s = {-5, -6};
-    long[] int64s = {7, 8};
-    long[] uint64s = {9, 10};
-    long[] sint64s = {-11, -12};
-    int[] fixed32s = {13, 14};
-    int[] sfixed32s = {-15, -16};
-    long[] fixed64s = {17, 18};
-    long[] sfixed64s = {-19, -20};
-    boolean[] bools = {true, false};
-    float[] floats = {2.1f, 2.2f};
-    double[] doubles = {2.3, 2.4};
-    int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
-    String[] strings = {"vijfentwintig", "twenty-six"};
-    byte[][] bytess = {{2, 7}, {2, 8}};
-    AnotherMessage another1 = new AnotherMessage();
-    another1.string = "er shi jiu";
-    another1.value = false;
-    AnotherMessage another2 = new AnotherMessage();
-    another2.string = "trente";
-    another2.value = true;
-    AnotherMessage[] messages = {another1, another2};
-    RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
-    group1.a = 31;
-    RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
-    group2.a = 32;
-    RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt32));
-    message.setExtension(RepeatedExtensions.repeatedInt32, int32s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt32));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint32));
-    message.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint32));
-    message.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt64));
-    message.setExtension(RepeatedExtensions.repeatedInt64, int64s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt64));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint64));
-    message.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint64));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSint64));
-    message.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSint64));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed32));
-    message.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed32));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
-    message.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed64));
-    message.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed64));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
-    message.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedBool));
-    message.setExtension(RepeatedExtensions.repeatedBool, bools);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedBool));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFloat));
-    message.setExtension(RepeatedExtensions.repeatedFloat, floats);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFloat));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedDouble));
-    message.setExtension(RepeatedExtensions.repeatedDouble, doubles);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedDouble));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedEnum));
-    message.setExtension(RepeatedExtensions.repeatedEnum, enums);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedEnum));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedString));
-    message.setExtension(RepeatedExtensions.repeatedString, strings);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedString));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedBytes));
-    message.setExtension(RepeatedExtensions.repeatedBytes, bytess);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedBytes));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedMessage));
-    message.setExtension(RepeatedExtensions.repeatedMessage, messages);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedMessage));
-    assertFalse(message.hasExtension(RepeatedExtensions.repeatedGroup));
-    message.setExtension(RepeatedExtensions.repeatedGroup, groups);
-    assertTrue(message.hasExtension(RepeatedExtensions.repeatedGroup));
-
-    byte[] data = MessageNano.toByteArray(message);
-    message = Extensions.ExtendableMessage.parseFrom(data);
-    assertEquals(5, message.field);
-
-    // Test reading back using SingularExtensions: the retrieved value should equal the last
-    // in each array.
-    assertEquals(int32s[1], (int) message.getExtension(SingularExtensions.someInt32));
-    assertEquals(uint32s[1], (int) message.getExtension(SingularExtensions.someUint32));
-    assertEquals(sint32s[1], (int) message.getExtension(SingularExtensions.someSint32));
-    assertEquals(int64s[1], (long) message.getExtension(SingularExtensions.someInt64));
-    assertEquals(uint64s[1], (long) message.getExtension(SingularExtensions.someUint64));
-    assertEquals(sint64s[1], (long) message.getExtension(SingularExtensions.someSint64));
-    assertEquals(fixed32s[1], (int) message.getExtension(SingularExtensions.someFixed32));
-    assertEquals(sfixed32s[1], (int) message.getExtension(SingularExtensions.someSfixed32));
-    assertEquals(fixed64s[1], (long) message.getExtension(SingularExtensions.someFixed64));
-    assertEquals(sfixed64s[1], (long) message.getExtension(SingularExtensions.someSfixed64));
-    assertEquals(bools[1], (boolean) message.getExtension(SingularExtensions.someBool));
-    assertEquals(floats[1], (float) message.getExtension(SingularExtensions.someFloat));
-    assertEquals(doubles[1], (double) message.getExtension(SingularExtensions.someDouble));
-    assertEquals(enums[1], (int) message.getExtension(SingularExtensions.someEnum));
-    assertEquals(strings[1], message.getExtension(SingularExtensions.someString));
-    assertTrue(Arrays.equals(bytess[1], message.getExtension(SingularExtensions.someBytes)));
-    AnotherMessage deserializedMessage = message.getExtension(SingularExtensions.someMessage);
-    assertEquals(another2.string, deserializedMessage.string);
-    assertEquals(another2.value, deserializedMessage.value);
-    assertEquals(group2.a, message.getExtension(SingularExtensions.someGroup).a);
-
-    // Test reading back using RepeatedExtensions: the arrays should be equal.
-    message = Extensions.ExtendableMessage.parseFrom(data);
-    assertEquals(5, message.field);
-    assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
-    assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
-    assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
-    assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
-    assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
-    assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
-    assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
-    assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
-    assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
-    assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
-    assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
-    assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
-    assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
-    assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
-    assertTrue(Arrays.equals(strings, message.getExtension(RepeatedExtensions.repeatedString)));
-    byte[][] deserializedRepeatedBytes = message.getExtension(RepeatedExtensions.repeatedBytes);
-    assertEquals(2, deserializedRepeatedBytes.length);
-    assertTrue(Arrays.equals(bytess[0], deserializedRepeatedBytes[0]));
-    assertTrue(Arrays.equals(bytess[1], deserializedRepeatedBytes[1]));
-    AnotherMessage[] deserializedRepeatedMessage =
-        message.getExtension(RepeatedExtensions.repeatedMessage);
-    assertEquals(2, deserializedRepeatedMessage.length);
-    assertEquals(another1.string, deserializedRepeatedMessage[0].string);
-    assertEquals(another1.value, deserializedRepeatedMessage[0].value);
-    assertEquals(another2.string, deserializedRepeatedMessage[1].string);
-    assertEquals(another2.value, deserializedRepeatedMessage[1].value);
-    RepeatedExtensions.RepeatedGroup[] deserializedRepeatedGroup =
-        message.getExtension(RepeatedExtensions.repeatedGroup);
-    assertEquals(2, deserializedRepeatedGroup.length);
-    assertEquals(group1.a, deserializedRepeatedGroup[0].a);
-    assertEquals(group2.a, deserializedRepeatedGroup[1].a);
-
-    message = Extensions.ExtendableMessage.parseFrom(data);
-    assertEquals(5, message.field);
-    // Test hasExtension using PackedExtensions.
-    assertTrue(message.hasExtension(PackedExtensions.packedInt32));
-    assertTrue(message.hasExtension(PackedExtensions.packedUint32));
-    assertTrue(message.hasExtension(PackedExtensions.packedSint32));
-    assertTrue(message.hasExtension(PackedExtensions.packedInt64));
-    assertTrue(message.hasExtension(PackedExtensions.packedUint64));
-    assertTrue(message.hasExtension(PackedExtensions.packedSint64));
-    assertTrue(message.hasExtension(PackedExtensions.packedFixed32));
-    assertTrue(message.hasExtension(PackedExtensions.packedSfixed32));
-    assertTrue(message.hasExtension(PackedExtensions.packedFixed64));
-    assertTrue(message.hasExtension(PackedExtensions.packedSfixed64));
-    assertTrue(message.hasExtension(PackedExtensions.packedBool));
-    assertTrue(message.hasExtension(PackedExtensions.packedFloat));
-    assertTrue(message.hasExtension(PackedExtensions.packedDouble));
-    assertTrue(message.hasExtension(PackedExtensions.packedEnum));
-
-    // Test reading back using PackedExtensions: the arrays should be equal, even the fields
-    // are non-packed.
-    assertTrue(Arrays.equals(int32s, message.getExtension(PackedExtensions.packedInt32)));
-    assertTrue(Arrays.equals(uint32s, message.getExtension(PackedExtensions.packedUint32)));
-    assertTrue(Arrays.equals(sint32s, message.getExtension(PackedExtensions.packedSint32)));
-    assertTrue(Arrays.equals(int64s, message.getExtension(PackedExtensions.packedInt64)));
-    assertTrue(Arrays.equals(uint64s, message.getExtension(PackedExtensions.packedUint64)));
-    assertTrue(Arrays.equals(sint64s, message.getExtension(PackedExtensions.packedSint64)));
-    assertTrue(Arrays.equals(fixed32s, message.getExtension(PackedExtensions.packedFixed32)));
-    assertTrue(Arrays.equals(sfixed32s, message.getExtension(PackedExtensions.packedSfixed32)));
-    assertTrue(Arrays.equals(fixed64s, message.getExtension(PackedExtensions.packedFixed64)));
-    assertTrue(Arrays.equals(sfixed64s, message.getExtension(PackedExtensions.packedSfixed64)));
-    assertTrue(Arrays.equals(bools, message.getExtension(PackedExtensions.packedBool)));
-    assertTrue(Arrays.equals(floats, message.getExtension(PackedExtensions.packedFloat)));
-    assertTrue(Arrays.equals(doubles, message.getExtension(PackedExtensions.packedDouble)));
-    assertTrue(Arrays.equals(enums, message.getExtension(PackedExtensions.packedEnum)));
-
-    // Now set the packable extension values using PackedExtensions so they're serialized packed.
-    message.setExtension(PackedExtensions.packedInt32, int32s);
-    message.setExtension(PackedExtensions.packedUint32, uint32s);
-    message.setExtension(PackedExtensions.packedSint32, sint32s);
-    message.setExtension(PackedExtensions.packedInt64, int64s);
-    message.setExtension(PackedExtensions.packedUint64, uint64s);
-    message.setExtension(PackedExtensions.packedSint64, sint64s);
-    message.setExtension(PackedExtensions.packedFixed32, fixed32s);
-    message.setExtension(PackedExtensions.packedSfixed32, sfixed32s);
-    message.setExtension(PackedExtensions.packedFixed64, fixed64s);
-    message.setExtension(PackedExtensions.packedSfixed64, sfixed64s);
-    message.setExtension(PackedExtensions.packedBool, bools);
-    message.setExtension(PackedExtensions.packedFloat, floats);
-    message.setExtension(PackedExtensions.packedDouble, doubles);
-    message.setExtension(PackedExtensions.packedEnum, enums);
-
-    // And read back using non-packed RepeatedExtensions.
-    byte[] data2 = MessageNano.toByteArray(message);
-    message = MessageNano.mergeFrom(new Extensions.ExtendableMessage(), data2);
-    assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
-    assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
-    assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
-    assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
-    assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
-    assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
-    assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
-    assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
-    assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
-    assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
-    assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
-    assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
-    assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
-    assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
-
-    // Clone the message and ensure it's still equal.
-    Extensions.ExtendableMessage clone = message.clone();
-    assertEquals(clone, message);
-  }
-
-  public void testNullExtensions() throws Exception {
-    // Check that clearing the extension on an empty message is a no-op.
-    Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
-    assertFalse(message.hasExtension(SingularExtensions.someMessage));
-    message.setExtension(SingularExtensions.someMessage, null);
-    assertFalse(message.hasExtension(SingularExtensions.someMessage));
-    assertEquals(0, MessageNano.toByteArray(message).length);
-
-    // Check that the message is empty after setting and clearing an extension.
-    AnotherMessage another = new AnotherMessage();
-    assertFalse(message.hasExtension(SingularExtensions.someMessage));
-    message.setExtension(SingularExtensions.someMessage, another);
-    assertTrue(message.hasExtension(SingularExtensions.someMessage));
-    assertTrue(MessageNano.toByteArray(message).length > 0);
-    message.setExtension(SingularExtensions.someMessage, null);
-    assertFalse(message.hasExtension(SingularExtensions.someMessage));
-    assertEquals(0, MessageNano.toByteArray(message).length);
-  }
-
-  public void testExtensionsMutation() {
-    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
-    extendableMessage.setExtension(SingularExtensions.someMessage,
-        new Extensions.AnotherMessage());
-
-    extendableMessage.getExtension(SingularExtensions.someMessage).string = "not empty";
-
-    assertEquals("not empty",
-        extendableMessage.getExtension(SingularExtensions.someMessage).string);
-  }
-
-  public void testExtensionsMutation_Equals() throws InvalidProtocolBufferNanoException {
-    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
-    extendableMessage.field = 5;
-    int int32 = 42;
-    int[] uint32s = {3, 4};
-    int[] sint32s = {-5, -6};
-    long[] int64s = {7, 8};
-    long[] uint64s = {9, 10};
-    long[] sint64s = {-11, -12};
-    int[] fixed32s = {13, 14};
-    int[] sfixed32s = {-15, -16};
-    long[] fixed64s = {17, 18};
-    long[] sfixed64s = {-19, -20};
-    boolean[] bools = {true, false};
-    float[] floats = {2.1f, 2.2f};
-    double[] doubles = {2.3, 2.4};
-    int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
-    String[] strings = {"vijfentwintig", "twenty-six"};
-    byte[][] bytess = {{2, 7}, {2, 8}};
-    AnotherMessage another1 = new AnotherMessage();
-    another1.string = "er shi jiu";
-    another1.value = false;
-    AnotherMessage another2 = new AnotherMessage();
-    another2.string = "trente";
-    another2.value = true;
-    AnotherMessage[] messages = {another1, another2};
-    RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
-    group1.a = 31;
-    RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
-    group2.a = 32;
-    RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
-    extendableMessage.setExtension(SingularExtensions.someInt32, int32);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedInt64, int64s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedBool, bools);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedFloat, floats);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedDouble, doubles);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedEnum, enums);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedString, strings);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedBytes, bytess);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedMessage, messages);
-    extendableMessage.setExtension(RepeatedExtensions.repeatedGroup, groups);
-
-    byte[] data = MessageNano.toByteArray(extendableMessage);
-
-    extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
-    Extensions.ExtendableMessage messageCopy = Extensions.ExtendableMessage.parseFrom(data);
-
-    // Without deserialising.
-    assertEquals(extendableMessage, messageCopy);
-    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
-
-    // Only one deserialized.
-    extendableMessage.getExtension(SingularExtensions.someInt32);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedUint32);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedSint32);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedInt64);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedUint64);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedSint64);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedFixed32);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed32);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedFixed64);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed64);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedBool);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedFloat);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedDouble);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedEnum);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedString);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedBytes);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedMessage);
-    extendableMessage.getExtension(RepeatedExtensions.repeatedGroup);
-    assertEquals(extendableMessage, messageCopy);
-    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
-
-    // Both deserialized.
-    messageCopy.getExtension(SingularExtensions.someInt32);
-    messageCopy.getExtension(RepeatedExtensions.repeatedUint32);
-    messageCopy.getExtension(RepeatedExtensions.repeatedSint32);
-    messageCopy.getExtension(RepeatedExtensions.repeatedInt64);
-    messageCopy.getExtension(RepeatedExtensions.repeatedUint64);
-    messageCopy.getExtension(RepeatedExtensions.repeatedSint64);
-    messageCopy.getExtension(RepeatedExtensions.repeatedFixed32);
-    messageCopy.getExtension(RepeatedExtensions.repeatedSfixed32);
-    messageCopy.getExtension(RepeatedExtensions.repeatedFixed64);
-    messageCopy.getExtension(RepeatedExtensions.repeatedSfixed64);
-    messageCopy.getExtension(RepeatedExtensions.repeatedBool);
-    messageCopy.getExtension(RepeatedExtensions.repeatedFloat);
-    messageCopy.getExtension(RepeatedExtensions.repeatedDouble);
-    messageCopy.getExtension(RepeatedExtensions.repeatedEnum);
-    messageCopy.getExtension(RepeatedExtensions.repeatedString);
-    messageCopy.getExtension(RepeatedExtensions.repeatedBytes);
-    messageCopy.getExtension(RepeatedExtensions.repeatedMessage);
-    messageCopy.getExtension(RepeatedExtensions.repeatedGroup);
-    assertEquals(extendableMessage, messageCopy);
-    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
-
-    // Change one, make sure they are still different.
-    messageCopy.getExtension(RepeatedExtensions.repeatedMessage)[0].string = "not empty";
-    assertFalse(extendableMessage.equals(messageCopy));
-
-    // Even if the extension hasn't been deserialized.
-    extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
-    assertFalse(extendableMessage.equals(messageCopy));
-  }
-
-  public void testExtensionsCaching() {
-    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
-    extendableMessage.setExtension(SingularExtensions.someMessage,
-        new Extensions.AnotherMessage());
-    assertSame("Consecutive calls to getExtensions should return the same object",
-        extendableMessage.getExtension(SingularExtensions.someMessage),
-        extendableMessage.getExtension(SingularExtensions.someMessage));
-  }
-
-  public void testUnknownFields() throws Exception {
-    // Check that we roundtrip (serialize and deserialize) unrecognized fields.
-    AnotherMessage message = new AnotherMessage();
-    message.string = "Hello World";
-    message.value = false;
-
-    byte[] bytes = MessageNano.toByteArray(message);
-    int extraFieldSize = CodedOutputStream.computeStringSize(1001, "This is an unknown field");
-    byte[] newBytes = new byte[bytes.length + extraFieldSize];
-    System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
-    CodedOutputStream.newInstance(newBytes, bytes.length, extraFieldSize).writeString(1001,
-        "This is an unknown field");
-
-    // Deserialize with an unknown field.
-    AnotherMessage deserialized = AnotherMessage.parseFrom(newBytes);
-    byte[] serialized = MessageNano.toByteArray(deserialized);
-
-    assertEquals(newBytes.length, serialized.length);
-
-    // Clear, and make sure it clears everything.
-    deserialized.clear();
-    assertEquals(0, MessageNano.toByteArray(deserialized).length);
-  }
-
-  public void testMergeFrom() throws Exception {
-    SimpleMessageNano message = new SimpleMessageNano();
-    message.d = 123;
-    byte[] bytes = MessageNano.toByteArray(message);
-
-    SimpleMessageNano newMessage = MessageNano.mergeFrom(new SimpleMessageNano(), bytes);
-    assertEquals(message.d, newMessage.d);
-  }
-
-  public void testJavaKeyword() throws Exception {
-    TestAllTypesNano msg = new TestAllTypesNano();
-    msg.synchronized_ = 123;
-    assertEquals(123, msg.synchronized_);
-  }
-
-  public void testReferenceTypesForPrimitives() throws Exception {
-    NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
-
-    // Base check - when nothing is set, we serialize nothing.
-    assertHasWireData(message, false);
-
-    message.defaultBool = true;
-    assertHasWireData(message, true);
-
-    message.defaultBool = false;
-    assertHasWireData(message, true);
-
-    message.defaultBool = null;
-    assertHasWireData(message, false);
-
-    message.defaultInt32 = 5;
-    assertHasWireData(message, true);
-
-    message.defaultInt32 = null;
-    assertHasWireData(message, false);
-
-    message.defaultInt64 = 123456L;
-    assertHasWireData(message, true);
-
-    message.defaultInt64 = null;
-    assertHasWireData(message, false);
-
-    message.defaultFloat = 1f;
-    assertHasWireData(message, true);
-
-    message.defaultFloat = null;
-    assertHasWireData(message, false);
-
-    message.defaultDouble = 2.1;
-    assertHasWireData(message, true);
-
-    message.defaultDouble = null;
-    assertHasWireData(message, false);
-
-    message.defaultString = "hello";
-    assertHasWireData(message, true);
-
-    message.defaultString = null;
-    assertHasWireData(message, false);
-
-    message.defaultBytes = new byte[] { 1, 2, 3 };
-    assertHasWireData(message, true);
-
-    message.defaultBytes = null;
-    assertHasWireData(message, false);
-  }
-
-  public void testHashCodeEquals() throws Exception {
-    // Complete equality:
-    TestAllTypesNano a = createMessageForHashCodeEqualsTest();
-    TestAllTypesNano aEquivalent = createMessageForHashCodeEqualsTest();
-
-    assertTrue(MessageNano.messageNanoEquals(a, aEquivalent));
-    assertFalse(MessageNano.messageNanoEquals(a, new TestAllTypesNano()));
-
-    // Null and empty array for repeated fields equality:
-    TestAllTypesNano b = createMessageForHashCodeEqualsTest();
-    b.repeatedBool = null;
-    b.repeatedFloat = new float[0];
-    TestAllTypesNano bEquivalent = createMessageForHashCodeEqualsTest();
-    bEquivalent.repeatedBool = new boolean[0];
-    bEquivalent.repeatedFloat = null;
-
-    // Ref-element-type repeated fields use non-null subsequence equality:
-    TestAllTypesNano c = createMessageForHashCodeEqualsTest();
-    c.repeatedString = null;
-    c.repeatedStringPiece = new String[] {null, "one", null, "two"};
-    c.repeatedBytes = new byte[][] {{3, 4}, null};
-    TestAllTypesNano cEquivalent = createMessageForHashCodeEqualsTest();
-    cEquivalent.repeatedString = new String[3];
-    cEquivalent.repeatedStringPiece = new String[] {"one", "two", null};
-    cEquivalent.repeatedBytes = new byte[][] {{3, 4}};
-
-    // Complete equality for messages with has fields:
-    TestAllTypesNanoHas d = createMessageWithHasForHashCodeEqualsTest();
-    TestAllTypesNanoHas dEquivalent = createMessageWithHasForHashCodeEqualsTest();
-
-    // If has-fields exist, fields with the same default values but
-    // different has-field values are different.
-    TestAllTypesNanoHas e = createMessageWithHasForHashCodeEqualsTest();
-    e.optionalInt32++; // make different from d
-    e.hasDefaultString = false;
-    TestAllTypesNanoHas eDifferent = createMessageWithHasForHashCodeEqualsTest();
-    eDifferent.optionalInt32 = e.optionalInt32;
-    eDifferent.hasDefaultString = true;
-
-    // Complete equality for messages with accessors:
-    TestNanoAccessors f = createMessageWithAccessorsForHashCodeEqualsTest();
-    TestNanoAccessors fEquivalent = createMessageWithAccessorsForHashCodeEqualsTest();
-
-    // If using accessors, explicitly setting a field to its default value
-    // should make the message different.
-    TestNanoAccessors g = createMessageWithAccessorsForHashCodeEqualsTest();
-    g.setOptionalInt32(g.getOptionalInt32() + 1); // make different from f
-    g.clearDefaultString();
-    TestNanoAccessors gDifferent = createMessageWithAccessorsForHashCodeEqualsTest();
-    gDifferent.setOptionalInt32(g.getOptionalInt32());
-    gDifferent.setDefaultString(g.getDefaultString());
-
-    // Complete equality for reference typed messages:
-    NanoReferenceTypes.TestAllTypesNano h = createRefTypedMessageForHashCodeEqualsTest();
-    NanoReferenceTypes.TestAllTypesNano hEquivalent = createRefTypedMessageForHashCodeEqualsTest();
-
-    // Inequality of null and default value for reference typed messages:
-    NanoReferenceTypes.TestAllTypesNano i = createRefTypedMessageForHashCodeEqualsTest();
-    i.optionalInt32 = 1; // make different from h
-    i.optionalFloat = null;
-    NanoReferenceTypes.TestAllTypesNano iDifferent = createRefTypedMessageForHashCodeEqualsTest();
-    iDifferent.optionalInt32 = i.optionalInt32;
-    iDifferent.optionalFloat = 0.0f;
-
-    HashMap<MessageNano, String> hashMap = new HashMap<MessageNano, String>();
-    hashMap.put(a, "a");
-    hashMap.put(b, "b");
-    hashMap.put(c, "c");
-    hashMap.put(d, "d");
-    hashMap.put(e, "e");
-    hashMap.put(f, "f");
-    hashMap.put(g, "g");
-    hashMap.put(h, "h");
-    hashMap.put(i, "i");
-
-    assertEquals(9, hashMap.size()); // a-i should be different from each other.
-
-    assertEquals("a", hashMap.get(a));
-    assertEquals("a", hashMap.get(aEquivalent));
-
-    assertEquals("b", hashMap.get(b));
-    assertEquals("b", hashMap.get(bEquivalent));
-
-    assertEquals("c", hashMap.get(c));
-    assertEquals("c", hashMap.get(cEquivalent));
-
-    assertEquals("d", hashMap.get(d));
-    assertEquals("d", hashMap.get(dEquivalent));
-
-    assertEquals("e", hashMap.get(e));
-    assertNull(hashMap.get(eDifferent));
-
-    assertEquals("f", hashMap.get(f));
-    assertEquals("f", hashMap.get(fEquivalent));
-
-    assertEquals("g", hashMap.get(g));
-    assertNull(hashMap.get(gDifferent));
-
-    assertEquals("h", hashMap.get(h));
-    assertEquals("h", hashMap.get(hEquivalent));
-
-    assertEquals("i", hashMap.get(i));
-    assertNull(hashMap.get(iDifferent));
-  }
-
-  private TestAllTypesNano createMessageForHashCodeEqualsTest() {
-    TestAllTypesNano message = new TestAllTypesNano();
-    message.optionalInt32 = 5;
-    message.optionalInt64 = 777;
-    message.optionalFloat = 1.0f;
-    message.optionalDouble = 2.0;
-    message.optionalBool = true;
-    message.optionalString = "Hello";
-    message.optionalBytes = new byte[] { 1, 2, 3 };
-    message.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
-    message.optionalNestedMessage.bb = 27;
-    message.optionalNestedEnum = TestAllTypesNano.BAR;
-    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
-    message.repeatedInt64 = new long[] { 27L, 28L, 29L };
-    message.repeatedFloat = new float[] { 5.0f, 6.0f };
-    message.repeatedDouble = new double[] { 99.1, 22.5 };
-    message.repeatedBool = new boolean[] { true, false, true };
-    message.repeatedString = new String[] { "One", "Two" };
-    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
-    message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
-      message.optionalNestedMessage,
-      message.optionalNestedMessage
-    };
-    message.repeatedNestedEnum = new int[] {
-      TestAllTypesNano.BAR,
-      TestAllTypesNano.BAZ
-    };
-    return message;
-  }
-
-  private TestAllTypesNanoHas createMessageWithHasForHashCodeEqualsTest() {
-    TestAllTypesNanoHas message = new TestAllTypesNanoHas();
-    message.optionalInt32 = 5;
-    message.optionalString = "Hello";
-    message.optionalBytes = new byte[] { 1, 2, 3 };
-    message.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
-    message.optionalNestedMessage.bb = 27;
-    message.optionalNestedEnum = TestAllTypesNano.BAR;
-    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
-    message.repeatedString = new String[] { "One", "Two" };
-    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
-    message.repeatedNestedMessage = new TestAllTypesNanoHas.NestedMessage[] {
-      message.optionalNestedMessage,
-      message.optionalNestedMessage
-    };
-    message.repeatedNestedEnum = new int[] {
-      TestAllTypesNano.BAR,
-      TestAllTypesNano.BAZ
-    };
-    return message;
-  }
-
-  private TestNanoAccessors createMessageWithAccessorsForHashCodeEqualsTest() {
-    TestNanoAccessors message = new TestNanoAccessors()
-        .setOptionalInt32(5)
-        .setOptionalString("Hello")
-        .setOptionalBytes(new byte[] {1, 2, 3})
-        .setOptionalNestedEnum(TestNanoAccessors.BAR);
-    message.optionalNestedMessage = new TestNanoAccessors.NestedMessage().setBb(27);
-    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
-    message.repeatedString = new String[] { "One", "Two" };
-    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
-    message.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[] {
-      message.optionalNestedMessage,
-      message.optionalNestedMessage
-    };
-    message.repeatedNestedEnum = new int[] {
-      TestAllTypesNano.BAR,
-      TestAllTypesNano.BAZ
-    };
-    return message;
-  }
-
-  private NanoReferenceTypes.TestAllTypesNano createRefTypedMessageForHashCodeEqualsTest() {
-    NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
-    message.optionalInt32 = 5;
-    message.optionalInt64 = 777L;
-    message.optionalFloat = 1.0f;
-    message.optionalDouble = 2.0;
-    message.optionalBool = true;
-    message.optionalString = "Hello";
-    message.optionalBytes = new byte[] { 1, 2, 3 };
-    message.optionalNestedMessage =
-        new NanoReferenceTypes.TestAllTypesNano.NestedMessage();
-    message.optionalNestedMessage.foo = 27;
-    message.optionalNestedEnum = NanoReferenceTypes.TestAllTypesNano.BAR;
-    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
-    message.repeatedInt64 = new long[] { 27L, 28L, 29L };
-    message.repeatedFloat = new float[] { 5.0f, 6.0f };
-    message.repeatedDouble = new double[] { 99.1, 22.5 };
-    message.repeatedBool = new boolean[] { true, false, true };
-    message.repeatedString = new String[] { "One", "Two" };
-    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
-    message.repeatedNestedMessage =
-        new NanoReferenceTypes.TestAllTypesNano.NestedMessage[] {
-          message.optionalNestedMessage,
-          message.optionalNestedMessage
-        };
-    message.repeatedNestedEnum = new int[] {
-      NanoReferenceTypes.TestAllTypesNano.BAR,
-      NanoReferenceTypes.TestAllTypesNano.BAZ
-    };
-    return message;
-  }
-
-  public void testEqualsWithSpecialFloatingPointValues() throws Exception {
-    // Checks that the nano implementation complies with Object.equals() when treating
-    // floating point numbers, i.e. NaN == NaN and +0.0 != -0.0.
-    // This test assumes that the generated equals() implementations are symmetric, so
-    // there will only be one direction for each equality check.
-
-    TestAllTypesNano m1 = new TestAllTypesNano();
-    m1.optionalFloat = Float.NaN;
-    m1.optionalDouble = Double.NaN;
-    TestAllTypesNano m2 = new TestAllTypesNano();
-    m2.optionalFloat = Float.NaN;
-    m2.optionalDouble = Double.NaN;
-    assertTrue(m1.equals(m2));
-    assertTrue(m1.equals(
-        MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
-
-    m1.optionalFloat = +0f;
-    m2.optionalFloat = -0f;
-    assertFalse(m1.equals(m2));
-
-    m1.optionalFloat = -0f;
-    m1.optionalDouble = +0d;
-    m2.optionalDouble = -0d;
-    assertFalse(m1.equals(m2));
-
-    m1.optionalDouble = -0d;
-    assertTrue(m1.equals(m2));
-    assertFalse(m1.equals(new TestAllTypesNano())); // -0 does not equals() the default +0
-    assertTrue(m1.equals(
-        MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
-
-    // -------
-
-    TestAllTypesNanoHas m3 = new TestAllTypesNanoHas();
-    m3.optionalFloat = Float.NaN;
-    m3.hasOptionalFloat = true;
-    m3.optionalDouble = Double.NaN;
-    m3.hasOptionalDouble = true;
-    TestAllTypesNanoHas m4 = new TestAllTypesNanoHas();
-    m4.optionalFloat = Float.NaN;
-    m4.hasOptionalFloat = true;
-    m4.optionalDouble = Double.NaN;
-    m4.hasOptionalDouble = true;
-    assertTrue(m3.equals(m4));
-    assertTrue(m3.equals(
-        MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
-
-    m3.optionalFloat = +0f;
-    m4.optionalFloat = -0f;
-    assertFalse(m3.equals(m4));
-
-    m3.optionalFloat = -0f;
-    m3.optionalDouble = +0d;
-    m4.optionalDouble = -0d;
-    assertFalse(m3.equals(m4));
-
-    m3.optionalDouble = -0d;
-    m3.hasOptionalFloat = false;  // -0 does not equals() the default +0,
-    m3.hasOptionalDouble = false; // so these incorrect 'has' flags should be disregarded.
-    assertTrue(m3.equals(m4));    // note: m4 has the 'has' flags set.
-    assertFalse(m3.equals(new TestAllTypesNanoHas())); // note: the new message has +0 defaults
-    assertTrue(m3.equals(
-        MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
-                                  // note: the deserialized message has the 'has' flags set.
-
-    // -------
-
-    TestNanoAccessors m5 = new TestNanoAccessors();
-    m5.setOptionalFloat(Float.NaN);
-    m5.setOptionalDouble(Double.NaN);
-    TestNanoAccessors m6 = new TestNanoAccessors();
-    m6.setOptionalFloat(Float.NaN);
-    m6.setOptionalDouble(Double.NaN);
-    assertTrue(m5.equals(m6));
-    assertTrue(m5.equals(
-        MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
-
-    m5.setOptionalFloat(+0f);
-    m6.setOptionalFloat(-0f);
-    assertFalse(m5.equals(m6));
-
-    m5.setOptionalFloat(-0f);
-    m5.setOptionalDouble(+0d);
-    m6.setOptionalDouble(-0d);
-    assertFalse(m5.equals(m6));
-
-    m5.setOptionalDouble(-0d);
-    assertTrue(m5.equals(m6));
-    assertFalse(m5.equals(new TestNanoAccessors()));
-    assertTrue(m5.equals(
-        MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
-
-    // -------
-
-    NanoReferenceTypes.TestAllTypesNano m7 = new NanoReferenceTypes.TestAllTypesNano();
-    m7.optionalFloat = Float.NaN;
-    m7.optionalDouble = Double.NaN;
-    NanoReferenceTypes.TestAllTypesNano m8 = new NanoReferenceTypes.TestAllTypesNano();
-    m8.optionalFloat = Float.NaN;
-    m8.optionalDouble = Double.NaN;
-    assertTrue(m7.equals(m8));
-    assertTrue(m7.equals(MessageNano.mergeFrom(
-        new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
-
-    m7.optionalFloat = +0f;
-    m8.optionalFloat = -0f;
-    assertFalse(m7.equals(m8));
-
-    m7.optionalFloat = -0f;
-    m7.optionalDouble = +0d;
-    m8.optionalDouble = -0d;
-    assertFalse(m7.equals(m8));
-
-    m7.optionalDouble = -0d;
-    assertTrue(m7.equals(m8));
-    assertFalse(m7.equals(new NanoReferenceTypes.TestAllTypesNano()));
-    assertTrue(m7.equals(MessageNano.mergeFrom(
-        new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
-  }
-
-  public void testNullRepeatedFields() throws Exception {
-    // Check that serialization after explicitly setting a repeated field
-    // to null doesn't NPE.
-    TestAllTypesNano message = new TestAllTypesNano();
-    message.repeatedInt32 = null;
-    MessageNano.toByteArray(message);  // should not NPE
-    message.toString(); // should not NPE
-
-    message.repeatedNestedEnum = null;
-    MessageNano.toByteArray(message);  // should not NPE
-    message.toString(); // should not NPE
-
-    message.repeatedBytes = null;
-    MessageNano.toByteArray(message); // should not NPE
-    message.toString(); // should not NPE
-
-    message.repeatedNestedMessage = null;
-    MessageNano.toByteArray(message); // should not NPE
-    message.toString(); // should not NPE
-
-    message.repeatedPackedInt32 = null;
-    MessageNano.toByteArray(message); // should not NPE
-    message.toString(); // should not NPE
-
-    message.repeatedPackedNestedEnum = null;
-    MessageNano.toByteArray(message); // should not NPE
-    message.toString(); // should not NPE
-
-    // Create a second message to merge into message.
-    TestAllTypesNano secondMessage = new TestAllTypesNano();
-    secondMessage.repeatedInt32 = new int[] {1, 2, 3};
-    secondMessage.repeatedNestedEnum = new int[] {
-      TestAllTypesNano.FOO, TestAllTypesNano.BAR
-    };
-    secondMessage.repeatedBytes = new byte[][] {{1, 2}, {3, 4}};
-    TestAllTypesNano.NestedMessage nested =
-        new TestAllTypesNano.NestedMessage();
-    nested.bb = 55;
-    secondMessage.repeatedNestedMessage =
-        new TestAllTypesNano.NestedMessage[] {nested};
-    secondMessage.repeatedPackedInt32 = new int[] {1, 2, 3};
-    secondMessage.repeatedPackedNestedEnum = new int[] {
-        TestAllTypesNano.FOO, TestAllTypesNano.BAR
-      };
-
-    // Should not NPE
-    message.mergeFrom(CodedInputByteBufferNano.newInstance(
-        MessageNano.toByteArray(secondMessage)));
-    assertEquals(3, message.repeatedInt32.length);
-    assertEquals(3, message.repeatedInt32[2]);
-    assertEquals(2, message.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.FOO, message.repeatedNestedEnum[0]);
-    assertEquals(2, message.repeatedBytes.length);
-    assertEquals(4, message.repeatedBytes[1][1]);
-    assertEquals(1, message.repeatedNestedMessage.length);
-    assertEquals(55, message.repeatedNestedMessage[0].bb);
-    assertEquals(3, message.repeatedPackedInt32.length);
-    assertEquals(2, message.repeatedPackedInt32[1]);
-    assertEquals(2, message.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.BAR, message.repeatedPackedNestedEnum[1]);
-  }
-
-  public void testNullRepeatedFieldElements() throws Exception {
-    // Check that serialization with null array elements doesn't NPE.
-    String string1 = "1";
-    String string2 = "2";
-    byte[] bytes1 = {3, 4};
-    byte[] bytes2 = {5, 6};
-    TestAllTypesNano.NestedMessage msg1 = new TestAllTypesNano.NestedMessage();
-    msg1.bb = 7;
-    TestAllTypesNano.NestedMessage msg2 = new TestAllTypesNano.NestedMessage();
-    msg2.bb = 8;
-
-    TestAllTypesNano message = new TestAllTypesNano();
-    message.repeatedString = new String[] {null, string1, string2};
-    message.repeatedBytes = new byte[][] {bytes1, null, bytes2};
-    message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {msg1, msg2, null};
-    message.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] {null, null, null};
-
-    byte[] serialized = MessageNano.toByteArray(message); // should not NPE
-    TestAllTypesNano deserialized = MessageNano.mergeFrom(new TestAllTypesNano(), serialized);
-    assertEquals(2, deserialized.repeatedString.length);
-    assertEquals(string1, deserialized.repeatedString[0]);
-    assertEquals(string2, deserialized.repeatedString[1]);
-    assertEquals(2, deserialized.repeatedBytes.length);
-    assertTrue(Arrays.equals(bytes1, deserialized.repeatedBytes[0]));
-    assertTrue(Arrays.equals(bytes2, deserialized.repeatedBytes[1]));
-    assertEquals(2, deserialized.repeatedNestedMessage.length);
-    assertEquals(msg1.bb, deserialized.repeatedNestedMessage[0].bb);
-    assertEquals(msg2.bb, deserialized.repeatedNestedMessage[1].bb);
-    assertEquals(0, deserialized.repeatedGroup.length);
-  }
-
-  public void testRepeatedMerge() throws Exception {
-    // Check that merging repeated fields cause the arrays to expand with
-    // new data.
-    TestAllTypesNano first = new TestAllTypesNano();
-    first.repeatedInt32 = new int[] {1, 2, 3};
-    TestAllTypesNano second = new TestAllTypesNano();
-    second.repeatedInt32 = new int[] {4, 5};
-    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
-    assertEquals(5, first.repeatedInt32.length);
-    assertEquals(1, first.repeatedInt32[0]);
-    assertEquals(4, first.repeatedInt32[3]);
-
-    first = new TestAllTypesNano();
-    first.repeatedNestedEnum = new int[] {TestAllTypesNano.BAR};
-    second = new TestAllTypesNano();
-    second.repeatedNestedEnum = new int[] {TestAllTypesNano.FOO};
-    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
-    assertEquals(2, first.repeatedNestedEnum.length);
-    assertEquals(TestAllTypesNano.BAR, first.repeatedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.FOO, first.repeatedNestedEnum[1]);
-
-    first = new TestAllTypesNano();
-    first.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
-      new TestAllTypesNano.NestedMessage()
-    };
-    first.repeatedNestedMessage[0].bb = 3;
-    second = new TestAllTypesNano();
-    second.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
-      new TestAllTypesNano.NestedMessage()
-    };
-    second.repeatedNestedMessage[0].bb = 5;
-    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
-    assertEquals(2, first.repeatedNestedMessage.length);
-    assertEquals(3, first.repeatedNestedMessage[0].bb);
-    assertEquals(5, first.repeatedNestedMessage[1].bb);
-
-    first = new TestAllTypesNano();
-    first.repeatedPackedSfixed64 = new long[] {-1, -2, -3};
-    second = new TestAllTypesNano();
-    second.repeatedPackedSfixed64 = new long[] {-4, -5};
-    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
-    assertEquals(5, first.repeatedPackedSfixed64.length);
-    assertEquals(-1, first.repeatedPackedSfixed64[0]);
-    assertEquals(-4, first.repeatedPackedSfixed64[3]);
-
-    first = new TestAllTypesNano();
-    first.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.BAR};
-    second = new TestAllTypesNano();
-    second.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.FOO};
-    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
-    assertEquals(2, first.repeatedPackedNestedEnum.length);
-    assertEquals(TestAllTypesNano.BAR, first.repeatedPackedNestedEnum[0]);
-    assertEquals(TestAllTypesNano.FOO, first.repeatedPackedNestedEnum[1]);
-
-    // Now test repeated merging in a nested scope
-    TestRepeatedMergeNano firstContainer = new TestRepeatedMergeNano();
-    firstContainer.contained = new TestAllTypesNano();
-    firstContainer.contained.repeatedInt32 = new int[] {10, 20};
-    TestRepeatedMergeNano secondContainer = new TestRepeatedMergeNano();
-    secondContainer.contained = new TestAllTypesNano();
-    secondContainer.contained.repeatedInt32 = new int[] {30};
-    MessageNano.mergeFrom(firstContainer, MessageNano.toByteArray(secondContainer));
-    assertEquals(3, firstContainer.contained.repeatedInt32.length);
-    assertEquals(20, firstContainer.contained.repeatedInt32[1]);
-    assertEquals(30, firstContainer.contained.repeatedInt32[2]);
-  }
-
-  public void testRepeatedPackables() throws Exception {
-    // Check that repeated fields with packable types can accept both packed and unpacked
-    // serialized forms.
-    NanoRepeatedPackables.NonPacked nonPacked = new NanoRepeatedPackables.NonPacked();
-    // Exaggerates the first values of varint-typed arrays. This is to test that the parsing code
-    // of packed fields handles non-packed data correctly. If the code incorrectly thinks it is
-    // reading from a packed tag, it will read the first value as the byte length of the field,
-    // and the large number will cause the input to go out of bounds, thus capturing the error.
-    nonPacked.int32S = new int[] {1000, 2, 3};
-    nonPacked.int64S = new long[] {4000, 5, 6};
-    nonPacked.uint32S = new int[] {7000, 8, 9};
-    nonPacked.uint64S = new long[] {10000, 11, 12};
-    nonPacked.sint32S = new int[] {13000, 14, 15};
-    nonPacked.sint64S = new long[] {16000, 17, 18};
-    nonPacked.fixed32S = new int[] {19, 20, 21};
-    nonPacked.fixed64S = new long[] {22, 23, 24};
-    nonPacked.sfixed32S = new int[] {25, 26, 27};
-    nonPacked.sfixed64S = new long[] {28, 29, 30};
-    nonPacked.floats = new float[] {31, 32, 33};
-    nonPacked.doubles = new double[] {34, 35, 36};
-    nonPacked.bools = new boolean[] {false, true};
-    nonPacked.enums = new int[] {
-      NanoRepeatedPackables.Enum.OPTION_ONE,
-      NanoRepeatedPackables.Enum.OPTION_TWO,
-    };
-    nonPacked.noise = 13579;
-
-    byte[] nonPackedSerialized = MessageNano.toByteArray(nonPacked);
-
-    NanoRepeatedPackables.Packed packed =
-        MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), nonPackedSerialized);
-    assertRepeatedPackablesEqual(nonPacked, packed);
-
-    byte[] packedSerialized = MessageNano.toByteArray(packed);
-    // Just a cautious check that the two serialized forms are different,
-    // to make sure the remaining of this test is useful:
-    assertFalse(Arrays.equals(nonPackedSerialized, packedSerialized));
-
-    nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), packedSerialized);
-    assertRepeatedPackablesEqual(nonPacked, packed);
-
-    // Test mixed serialized form.
-    byte[] mixedSerialized = new byte[nonPackedSerialized.length + packedSerialized.length];
-    System.arraycopy(nonPackedSerialized, 0, mixedSerialized, 0, nonPackedSerialized.length);
-    System.arraycopy(packedSerialized, 0,
-        mixedSerialized, nonPackedSerialized.length, packedSerialized.length);
-
-    nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), mixedSerialized);
-    packed = MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), mixedSerialized);
-    assertRepeatedPackablesEqual(nonPacked, packed);
-    assertTrue(Arrays.equals(new int[] {1000, 2, 3, 1000, 2, 3}, nonPacked.int32S));
-    assertTrue(Arrays.equals(new int[] {13000, 14, 15, 13000, 14, 15}, nonPacked.sint32S));
-    assertTrue(Arrays.equals(new int[] {25, 26, 27, 25, 26, 27}, nonPacked.sfixed32S));
-    assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
-  }
-
-  public void testRepeatedFieldInitializedInReftypesCompatMode() {
-    NanoReferenceTypesCompat.TestAllTypesNano proto = new NanoReferenceTypesCompat.TestAllTypesNano();
-    assertNotNull(proto.repeatedString);
-  }
-
-  private void assertRepeatedPackablesEqual(
-      NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
-    // Not using MessageNano.equals() -- that belongs to a separate test.
-    assertTrue(Arrays.equals(nonPacked.int32S, packed.int32S));
-    assertTrue(Arrays.equals(nonPacked.int64S, packed.int64S));
-    assertTrue(Arrays.equals(nonPacked.uint32S, packed.uint32S));
-    assertTrue(Arrays.equals(nonPacked.uint64S, packed.uint64S));
-    assertTrue(Arrays.equals(nonPacked.sint32S, packed.sint32S));
-    assertTrue(Arrays.equals(nonPacked.sint64S, packed.sint64S));
-    assertTrue(Arrays.equals(nonPacked.fixed32S, packed.fixed32S));
-    assertTrue(Arrays.equals(nonPacked.fixed64S, packed.fixed64S));
-    assertTrue(Arrays.equals(nonPacked.sfixed32S, packed.sfixed32S));
-    assertTrue(Arrays.equals(nonPacked.sfixed64S, packed.sfixed64S));
-    assertTrue(Arrays.equals(nonPacked.floats, packed.floats));
-    assertTrue(Arrays.equals(nonPacked.doubles, packed.doubles));
-    assertTrue(Arrays.equals(nonPacked.bools, packed.bools));
-    assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
-  }
-
-  public void testClone() throws Exception {
-    // A simple message.
-    AnotherMessage anotherMessage = new AnotherMessage();
-    anotherMessage.string = "Hello";
-    anotherMessage.value = true;
-    anotherMessage.integers = new int[] { 1, 2, 3 };
-
-    AnotherMessage clone = anotherMessage.clone();
-    assertEquals(clone, anotherMessage);
-
-    // Verify it was a deep clone - changes to the clone shouldn't affect the
-    // original.
-    clone.integers[1] = 100;
-    assertFalse(clone.equals(anotherMessage));
-  }
-
-  public void testBytesOffsetLength() throws Exception {
-    BytesOffsetLengthTestNano msg = new BytesOffsetLengthTestNano();
-    msg.fooBuffer = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    msg.fooOffset = 2;
-    msg.fooLength = 3;
-    msg.barBuffer = msg.fooBuffer;
-    msg.barOffset = 7;
-    msg.barLength = 1;
-
-    byte[] bytes = MessageNano.toByteArray(msg);
-    // Two tags + two lengths + the arrays
-    assertEquals("Unexpected size of encoded proto", 8, bytes.length);
-
-    msg = BytesOffsetLengthTestNano.parseFrom(bytes);
-    byte[] foo = new byte[msg.fooLength];
-    System.arraycopy(msg.fooBuffer, msg.fooOffset, foo, 0, msg.fooLength);
-    assertTrue("foo was not deserialized correctly", Arrays.equals(new byte[] { 2, 3, 4 }, foo));
-    byte[] bar = new byte[msg.barLength];
-    System.arraycopy(msg.barBuffer, msg.barOffset, bar, 0, msg.barLength);
-    assertTrue("bar was not deserialized correctly", Arrays.equals(new byte[] { 7 }, bar));
-  }
-
-  public void testUnknownOptionalEnumValue() throws Exception {
-    StandardVersion standardMsg = new StandardVersion();
-    standardMsg.optionalField = StandardVersion.VAL_3;
-    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
-
-    // When parsing and reading, the unknown value appears as UNKNOWN.
-    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
-    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
-    assertEquals(VersionWithoutVal3.UNKNOWN, withoutVal3Msg.optionalField);
-
-    // When serializing and reparsing as the standard version, the old, unknown value wins out (even
-    // if a new one is set).
-    withoutVal3Msg.optionalField = VersionWithoutVal3.VAL_2;
-    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
-    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
-    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
-    assertEquals(StandardVersion.VAL_3, standardMsgFromWithoutVal3Msg.optionalField);
-  }
-
-  public void testUnknownRepeatedEnumValue() throws Exception {
-    StandardVersion standardMsg = new StandardVersion();
-    standardMsg.repeatedField = new int[] { StandardVersion.VAL_3, StandardVersion.VAL_2 };
-    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
-
-    // When parsing and reading, the unknown value is stripped out.
-    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
-    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
-    assertTrue(Arrays.equals(new int[] { VersionWithoutVal3.VAL_2 }, withoutVal3Msg.repeatedField));
-
-    // When serializing and reparsing as the standard version, the old, unknown value reappears, but
-    // at the end of all entries (including any newly added ones).
-    withoutVal3Msg.repeatedField = new int[] { VersionWithoutVal3.VAL_2, VersionWithoutVal3.VAL_1 };
-    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
-    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
-    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
-    assertTrue(Arrays.equals(
-            new int[] { StandardVersion.VAL_2, StandardVersion.VAL_1, StandardVersion.VAL_3 },
-            standardMsgFromWithoutVal3Msg.repeatedField));
-  }
-
-  public void testUnknownRepeatedPackedEnumValue() throws Exception {
-    StandardVersion standardMsg = new StandardVersion();
-    standardMsg.packedField = new int[] { StandardVersion.VAL_3, StandardVersion.VAL_2 };
-    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
-
-    // When parsing and reading, the unknown value is stripped out.
-    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
-    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
-    assertTrue(Arrays.equals(new int[] { VersionWithoutVal3.VAL_2 }, withoutVal3Msg.packedField));
-
-    // When serializing and reparsing as the standard version, the old, unknown value reappears, but
-    // at the end of all entries (including any newly added ones).
-    withoutVal3Msg.packedField = new int[] { VersionWithoutVal3.VAL_2, VersionWithoutVal3.VAL_1 };
-    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
-    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
-    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
-    assertTrue(Arrays.equals(
-            new int[] { StandardVersion.VAL_2, StandardVersion.VAL_1, StandardVersion.VAL_3 },
-            standardMsgFromWithoutVal3Msg.packedField));
-  }
-
-  private void assertHasWireData(MessageNano message, boolean expected) {
-    byte[] bytes = MessageNano.toByteArray(message);
-    int wireLength = bytes.length;
-    if (expected) {
-      assertFalse(wireLength == 0);
-    } else {
-      if (wireLength != 0) {
-        fail("Expected no wire data for message \n" + message
-            + "\nBut got:\n"
-            + hexDump(bytes));
-      }
-    }
-  }
-
-  private static String hexDump(byte[] bytes) {
-    StringBuilder sb = new StringBuilder();
-    for (byte b : bytes) {
-      sb.append(String.format("%02x ", b));
-    }
-    return sb.toString();
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/src/test/java/com/google/protobuf/NestedBuildersTest.java
deleted file mode 100644
index 2365312..0000000
--- a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.Vehicle;
-import protobuf_unittest.Wheel;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * Test cases that exercise end-to-end use cases involving
- * {@link SingleFieldBuilder} and {@link RepeatedFieldBuilder}.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class NestedBuildersTest extends TestCase {
-
-  public void testMessagesAndBuilders() {
-    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(4)
-        .setWidth(1);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(4)
-        .setWidth(2);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(4)
-        .setWidth(3);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(4)
-        .setWidth(4);
-    vehicleBuilder.getEngineBuilder()
-        .setLiters(10);
-
-    Vehicle vehicle = vehicleBuilder.build();
-    assertEquals(4, vehicle.getWheelCount());
-    for (int i = 0; i < 4; i++) {
-      Wheel wheel = vehicle.getWheel(i);
-      assertEquals(4, wheel.getRadius());
-      assertEquals(i + 1, wheel.getWidth());
-    }
-    assertEquals(10, vehicle.getEngine().getLiters());
-
-    for (int i = 0; i < 4; i++) {
-      vehicleBuilder.getWheelBuilder(i)
-          .setRadius(5)
-          .setWidth(i + 10);
-    }
-    vehicleBuilder.getEngineBuilder().setLiters(20);
-
-    vehicle = vehicleBuilder.build();
-    for (int i = 0; i < 4; i++) {
-      Wheel wheel = vehicle.getWheel(i);
-      assertEquals(5, wheel.getRadius());
-      assertEquals(i + 10, wheel.getWidth());
-    }
-    assertEquals(20, vehicle.getEngine().getLiters());
-    assertTrue(vehicle.hasEngine());
-  }
-
-  public void testMessagesAreCached() {
-    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(1)
-        .setWidth(2);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(3)
-        .setWidth(4);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(5)
-        .setWidth(6);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(7)
-        .setWidth(8);
-
-    // Make sure messages are cached.
-    List<Wheel> wheels = new ArrayList<Wheel>(vehicleBuilder.getWheelList());
-    for (int i = 0; i < wheels.size(); i++) {
-      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
-    }
-
-    // Now get builders and check they didn't change.
-    for (int i = 0; i < wheels.size(); i++) {
-      vehicleBuilder.getWheel(i);
-    }
-    for (int i = 0; i < wheels.size(); i++) {
-      assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
-    }
-
-    // Change just one
-    vehicleBuilder.getWheelBuilder(3)
-        .setRadius(20).setWidth(20);
-
-    // Now get wheels and check that only that one changed
-    for (int i = 0; i < wheels.size(); i++) {
-      if (i < 3) {
-        assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
-      } else {
-        assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i));
-      }
-    }
-  }
-
-  public void testRemove_WithNestedBuilders() {
-    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(1)
-        .setWidth(1);
-    vehicleBuilder.addWheelBuilder()
-        .setRadius(2)
-        .setWidth(2);
-    vehicleBuilder.removeWheel(0);
-
-    assertEquals(1, vehicleBuilder.getWheelCount());
-    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
-  }
-
-  public void testRemove_WithNestedMessages() {
-    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
-    vehicleBuilder.addWheel(Wheel.newBuilder()
-        .setRadius(1)
-        .setWidth(1));
-    vehicleBuilder.addWheel(Wheel.newBuilder()
-        .setRadius(2)
-        .setWidth(2));
-    vehicleBuilder.removeWheel(0);
-
-    assertEquals(1, vehicleBuilder.getWheelCount());
-    assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
-  }
-
-  public void testMerge() {
-    Vehicle vehicle1 = Vehicle.newBuilder()
-        .addWheel(Wheel.newBuilder().setRadius(1).build())
-        .addWheel(Wheel.newBuilder().setRadius(2).build())
-        .build();
-
-    Vehicle vehicle2 = Vehicle.newBuilder()
-        .mergeFrom(vehicle1)
-        .build();
-    // List should be the same -- no allocation
-    assertSame(vehicle1.getWheelList(), vehicle2.getWheelList());
-
-    Vehicle vehicle3 = vehicle1.toBuilder().build();
-    assertSame(vehicle1.getWheelList(), vehicle3.getWheelList());
-  }
-
-  public void testGettingBuilderMarksFieldAsHaving() {
-    Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
-    vehicleBuilder.getEngineBuilder();
-    Vehicle vehicle = vehicleBuilder.buildPartial();
-    assertTrue(vehicle.hasEngine());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/ParserTest.java b/java/src/test/java/com/google/protobuf/ParserTest.java
deleted file mode 100644
index b11d8cb..0000000
--- a/java/src/test/java/com/google/protobuf/ParserTest.java
+++ /dev/null
@@ -1,381 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-import com.google.protobuf.UnittestLite.TestParsingMergeLite;
-import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
-import protobuf_unittest.UnittestOptimizeFor;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestEmptyMessage;
-import protobuf_unittest.UnittestProto.TestParsingMerge;
-import protobuf_unittest.UnittestProto.TestRequired;
-import protobuf_unittest.UnittestProto;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Unit test for {@link Parser}.
- *
- * @author liujisi@google.com (Pherl Liu)
- */
-public class ParserTest extends TestCase {
-  public void testGeneratedMessageParserSingleton() throws Exception {
-    for (int i = 0; i < 10; i++) {
-      assertEquals(TestAllTypes.PARSER,
-                   TestUtil.getAllSet().getParserForType());
-    }
-  }
-
-  private void assertRoundTripEquals(MessageLite message,
-                                     ExtensionRegistryLite registry)
-      throws Exception {
-    final byte[] data = message.toByteArray();
-    final int offset = 20;
-    final int length = data.length;
-    final int padding = 30;
-    Parser<? extends MessageLite> parser = message.getParserForType();
-    assertMessageEquals(message, parser.parseFrom(data, registry));
-    assertMessageEquals(message, parser.parseFrom(
-        generatePaddingArray(data, offset, padding),
-        offset, length, registry));
-    assertMessageEquals(message, parser.parseFrom(
-        message.toByteString(), registry));
-    assertMessageEquals(message, parser.parseFrom(
-        new ByteArrayInputStream(data), registry));
-    assertMessageEquals(message, parser.parseFrom(
-        CodedInputStream.newInstance(data), registry));
-  }
-
-  @SuppressWarnings("unchecked")
-  private void assertRoundTripEquals(MessageLite message) throws Exception {
-    final byte[] data = message.toByteArray();
-    final int offset = 20;
-    final int length = data.length;
-    final int padding = 30;
-
-    Parser<MessageLite> parser =
-        (Parser<MessageLite>) message.getParserForType();
-    assertMessageEquals(message, parser.parseFrom(data));
-    assertMessageEquals(message, parser.parseFrom(
-        generatePaddingArray(data, offset, padding),
-        offset, length));
-    assertMessageEquals(message, parser.parseFrom(message.toByteString()));
-    assertMessageEquals(message, parser.parseFrom(
-        new ByteArrayInputStream(data)));
-    assertMessageEquals(message, parser.parseFrom(
-        CodedInputStream.newInstance(data)));
-  }
-
-  private void assertMessageEquals(
-      MessageLite expected, MessageLite actual)
-      throws Exception {
-    if (expected instanceof Message) {
-      assertEquals(expected, actual);
-    } else {
-      assertEquals(expected.toByteString(), actual.toByteString());
-    }
-  }
-
-  private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
-    byte[] result = new byte[offset + data.length + padding];
-    System.arraycopy(data, 0, result, offset, data.length);
-    return result;
-  }
-
-  public void testNormalMessage() throws Exception {
-    assertRoundTripEquals(TestUtil.getAllSet());
-  }
-
-
-  public void testParsePartial() throws Exception {
-    assertParsePartial(TestRequired.PARSER,
-        TestRequired.newBuilder().setA(1).buildPartial());
-  }
-
-  private <T extends MessageLite> void assertParsePartial(
-      Parser<T> parser, T partialMessage) throws Exception {
-    final String errorString =
-        "Should throw exceptions when the parsed message isn't initialized.";
-
-    // parsePartialFrom should pass.
-    byte[] data = partialMessage.toByteArray();
-    assertEquals(partialMessage, parser.parsePartialFrom(data));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        partialMessage.toByteString()));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        new ByteArrayInputStream(data)));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        CodedInputStream.newInstance(data)));
-
-    // parseFrom(ByteArray)
-    try {
-      parser.parseFrom(partialMessage.toByteArray());
-      fail(errorString);
-    } catch (InvalidProtocolBufferException e) {
-      // pass.
-    }
-
-    // parseFrom(ByteString)
-    try {
-      parser.parseFrom(partialMessage.toByteString());
-      fail(errorString);
-    } catch (InvalidProtocolBufferException e) {
-      // pass.
-    }
-
-    // parseFrom(InputStream)
-    try {
-      parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
-      fail(errorString);
-    } catch (IOException e) {
-      // pass.
-    }
-
-    // parseFrom(CodedInputStream)
-    try {
-      parser.parseFrom(CodedInputStream.newInstance(
-          partialMessage.toByteArray()));
-      fail(errorString);
-    } catch (IOException e) {
-      // pass.
-    }
-  }
-
-  public void testParseExtensions() throws Exception {
-    assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
-                          TestUtil.getExtensionRegistry());
-    assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(),
-                          TestUtil.getExtensionRegistryLite());
-  }
-
-  public void testParsePacked() throws Exception {
-    assertRoundTripEquals(TestUtil.getPackedSet());
-    assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
-                          TestUtil.getExtensionRegistry());
-    assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(),
-                          TestUtil.getExtensionRegistryLite());
-  }
-
-  public void testParseDelimitedTo() throws Exception {
-    // Write normal Message.
-    TestAllTypes normalMessage = TestUtil.getAllSet();
-    ByteArrayOutputStream output = new ByteArrayOutputStream();
-    normalMessage.writeDelimitedTo(output);
-
-    // Write MessageLite with packed extension fields.
-    TestPackedExtensionsLite packedMessage =
-        TestUtil.getLitePackedExtensionsSet();
-    packedMessage.writeDelimitedTo(output);
-
-    InputStream input = new ByteArrayInputStream(output.toByteArray());
-    assertMessageEquals(
-        normalMessage,
-        normalMessage.getParserForType().parseDelimitedFrom(input));
-    assertMessageEquals(
-        packedMessage,
-        packedMessage.getParserForType().parseDelimitedFrom(
-            input, TestUtil.getExtensionRegistryLite()));
-  }
-
-  public void testParseUnknownFields() throws Exception {
-    // All fields will be treated as unknown fields in emptyMessage.
-    TestEmptyMessage emptyMessage = TestEmptyMessage.PARSER.parseFrom(
-        TestUtil.getAllSet().toByteString());
-    assertEquals(
-        TestUtil.getAllSet().toByteString(),
-        emptyMessage.toByteString());
-  }
-
-
-  public void testOptimizeForSize() throws Exception {
-    TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
-    builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
-    builder.setExtension(TestOptimizedForSize.testExtension, 56);
-    builder.setExtension(TestOptimizedForSize.testExtension2,
-        TestRequiredOptimizedForSize.newBuilder().setX(78).build());
-
-    TestOptimizedForSize message = builder.build();
-    ExtensionRegistry registry = ExtensionRegistry.newInstance();
-    UnittestOptimizeFor.registerAllExtensions(registry);
-
-    assertRoundTripEquals(message, registry);
-  }
-
-  /** Helper method for {@link #testParsingMerge()}.*/
-  private void assertMessageMerged(TestAllTypes allTypes)
-      throws Exception {
-    assertEquals(3, allTypes.getOptionalInt32());
-    assertEquals(2, allTypes.getOptionalInt64());
-    assertEquals("hello", allTypes.getOptionalString());
-  }
-
-  /** Helper method for {@link #testParsingMergeLite()}.*/
-  private void assertMessageMerged(TestAllTypesLite allTypes)
-      throws Exception {
-    assertEquals(3, allTypes.getOptionalInt32());
-    assertEquals(2, allTypes.getOptionalInt64());
-    assertEquals("hello", allTypes.getOptionalString());
-  }
-
-  public void testParsingMerge() throws Exception {
-    // Build messages.
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TestAllTypes msg1 = builder.setOptionalInt32(1).build();
-    builder.clear();
-    TestAllTypes msg2 = builder.setOptionalInt64(2).build();
-    builder.clear();
-    TestAllTypes msg3 = builder.setOptionalInt32(3)
-        .setOptionalString("hello").build();
-
-    // Build groups.
-    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg3).build();
-    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg3).build();
-
-    // Assign and serialize RepeatedFieldsGenerator.
-    ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
-        .addField1(msg1).addField1(msg2).addField1(msg3)
-        .addField2(msg1).addField2(msg2).addField2(msg3)
-        .addField3(msg1).addField3(msg2).addField3(msg3)
-        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
-        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
-        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
-        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
-        .build().toByteString();
-
-    // Parse TestParsingMerge.
-    ExtensionRegistry registry = ExtensionRegistry.newInstance();
-    UnittestProto.registerAllExtensions(registry);
-    TestParsingMerge parsingMerge =
-        TestParsingMerge.PARSER.parseFrom(data, registry);
-
-    // Required and optional fields should be merged.
-    assertMessageMerged(parsingMerge.getRequiredAllTypes());
-    assertMessageMerged(parsingMerge.getOptionalAllTypes());
-    assertMessageMerged(
-        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
-    assertMessageMerged(parsingMerge.getExtension(
-        TestParsingMerge.optionalExt));
-
-    // Repeated fields should not be merged.
-    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
-    assertEquals(3, parsingMerge.getRepeatedGroupCount());
-    assertEquals(3, parsingMerge.getExtensionCount(
-        TestParsingMerge.repeatedExt));
-  }
-
-  public void testParsingMergeLite() throws Exception {
-    // Build messages.
-    TestAllTypesLite.Builder builder =
-        TestAllTypesLite.newBuilder();
-    TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
-    builder.clear();
-    TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
-    builder.clear();
-    TestAllTypesLite msg3 = builder.setOptionalInt32(3)
-        .setOptionalString("hello").build();
-
-    // Build groups.
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg3).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg1).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg2).build();
-    TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
-        TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg3).build();
-
-    // Assign and serialize RepeatedFieldsGenerator.
-    ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
-        .addField1(msg1).addField1(msg2).addField1(msg3)
-        .addField2(msg1).addField2(msg2).addField2(msg3)
-        .addField3(msg1).addField3(msg2).addField3(msg3)
-        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
-        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
-        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
-        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
-        .build().toByteString();
-
-    // Parse TestParsingMergeLite.
-    ExtensionRegistry registry = ExtensionRegistry.newInstance();
-    UnittestLite.registerAllExtensions(registry);
-    TestParsingMergeLite parsingMerge =
-        TestParsingMergeLite.PARSER.parseFrom(data, registry);
-
-    // Required and optional fields should be merged.
-    assertMessageMerged(parsingMerge.getRequiredAllTypes());
-    assertMessageMerged(parsingMerge.getOptionalAllTypes());
-    assertMessageMerged(
-        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
-    assertMessageMerged(parsingMerge.getExtension(
-        TestParsingMergeLite.optionalExt));
-
-    // Repeated fields should not be merged.
-    assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
-    assertEquals(3, parsingMerge.getRepeatedGroupCount());
-    assertEquals(3, parsingMerge.getExtensionCount(
-        TestParsingMergeLite.repeatedExt));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java b/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
deleted file mode 100644
index 212f8d6..0000000
--- a/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Iterator;
-
-/**
- * This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from
- * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.  
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-public class RopeByteStringSubstringTest extends LiteralByteStringTest {
-
-  @Override
-  protected void setUp() throws Exception {
-    classUnderTest = "RopeByteString";
-    byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
-    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
-    ByteString sourceString = iter.next();
-    while (iter.hasNext()) {
-      sourceString = sourceString.concat(iter.next());
-    }
-
-    int from = 1130;
-    int to = sourceBytes.length - 5555;
-    stringUnderTest = sourceString.substring(from, to);
-    referenceBytes = new byte[to - from];
-    System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
-    expectedHashCode = -1259260680;
-  }
-
-  @Override
-  public void testGetTreeDepth() {
-    assertEquals(classUnderTest + " must have the expected tree depth",
-        3, stringUnderTest.getTreeDepth());
-  }
-
-  @Override
-  public void testToString() throws UnsupportedEncodingException {
-    String sourceString = "I love unicode \u1234\u5678 characters";
-    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
-    int copies = 250;
-
-    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
-    StringBuilder builder = new StringBuilder(copies * sourceString.length());
-    ByteString unicode = ByteString.EMPTY;
-    for (int i = 0; i < copies; ++i) {
-      builder.append(sourceString);
-      unicode = RopeByteString.concatenate(unicode, sourceByteString);
-    }
-    String testString = builder.toString();
-
-    // Do the substring part
-    testString = testString.substring(2, testString.length() - 6);
-    unicode = unicode.substring(2, unicode.size() - 6);
-
-    assertEquals(classUnderTest + " from string must have the expected type",
-        classUnderTest, getActualClassName(unicode));
-    String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match",
-        testString, roundTripString);
-    ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(), unicode.hashCode());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/src/test/java/com/google/protobuf/RopeByteStringTest.java
deleted file mode 100644
index 9676f52..0000000
--- a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.Iterator;
-
-/**
- * This class tests {@link RopeByteString} by inheriting the tests from
- * {@link LiteralByteStringTest}.  Only a couple of methods are overridden.
- * 
- * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
- * separate class {@link RopeByteStringSubstringTest}.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-public class RopeByteStringTest extends LiteralByteStringTest {
-
-  @Override
-  protected void setUp() throws Exception {
-    classUnderTest = "RopeByteString";
-    referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
-    Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
-    stringUnderTest = iter.next();
-    while (iter.hasNext()) {
-      stringUnderTest = stringUnderTest.concat(iter.next());
-    }
-    expectedHashCode = -1214197238;
-  }
-
-  @Override
-  public void testGetTreeDepth() {
-    assertEquals(classUnderTest + " must have the expected tree depth",
-        4, stringUnderTest.getTreeDepth());
-  }
-
-  public void testBalance() {
-    int numberOfPieces = 10000;
-    int pieceSize = 64;
-    byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L);
-
-    // Build up a big ByteString from smaller pieces to force a rebalance
-    ByteString concatenated = ByteString.EMPTY;
-    for (int i = 0; i < numberOfPieces; ++i) {
-      concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize));
-    }
-
-    assertEquals(classUnderTest + " from string must have the expected type",
-        classUnderTest, getActualClassName(concatenated));
-    assertTrue(classUnderTest + " underlying bytes must match after balancing",
-        Arrays.equals(testBytes, concatenated.toByteArray()));
-    ByteString testString = ByteString.copyFrom(testBytes);
-    assertTrue(classUnderTest + " balanced string must equal flat string",
-        concatenated.equals(testString));
-    assertTrue(classUnderTest + " flat string must equal balanced string",
-        testString.equals(concatenated));
-    assertEquals(classUnderTest + " balanced string must have same hash code as flat string",
-        testString.hashCode(), concatenated.hashCode());
-  }
-
-  @Override
-  public void testToString() throws UnsupportedEncodingException {
-    String sourceString = "I love unicode \u1234\u5678 characters";
-    ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
-    int copies = 250;
-
-    // By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
-    StringBuilder builder = new StringBuilder(copies * sourceString.length());
-    ByteString unicode = ByteString.EMPTY;
-    for (int i = 0; i < copies; ++i) {
-      builder.append(sourceString);
-      unicode = RopeByteString.concatenate(unicode, sourceByteString);
-    }
-    String testString = builder.toString();
-
-    assertEquals(classUnderTest + " from string must have the expected type",
-        classUnderTest, getActualClassName(unicode));
-    String roundTripString = unicode.toString(UTF_8);
-    assertEquals(classUnderTest + " unicode bytes must match",
-        testString, roundTripString);
-    ByteString flatString = ByteString.copyFromUtf8(testString);
-    assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
-    assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
-        flatString.hashCode(), unicode.hashCode());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java
deleted file mode 100644
index ff980d6..0000000
--- a/java/src/test/java/com/google/protobuf/ServiceTest.java
+++ /dev/null
@@ -1,320 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.FileDescriptor;
-import com.google.protobuf.Descriptors.MethodDescriptor;
-import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
-import protobuf_unittest.MessageWithNoOuter;
-import protobuf_unittest.ServiceWithNoOuter;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestService;
-import protobuf_unittest.UnittestProto.FooRequest;
-import protobuf_unittest.UnittestProto.FooResponse;
-import protobuf_unittest.UnittestProto.BarRequest;
-import protobuf_unittest.UnittestProto.BarResponse;
-
-import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
-import org.easymock.IArgumentMatcher;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-/**
- * Tests services and stubs.
- *
- * @author kenton@google.com Kenton Varda
- */
-public class ServiceTest extends TestCase {
-  private IMocksControl control;
-  private RpcController mockController;
-
-  private final Descriptors.MethodDescriptor fooDescriptor =
-    TestService.getDescriptor().getMethods().get(0);
-  private final Descriptors.MethodDescriptor barDescriptor =
-    TestService.getDescriptor().getMethods().get(1);
-
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
-    control = EasyMock.createStrictControl();
-    mockController = control.createMock(RpcController.class);
-  }
-
-  // =================================================================
-
-  /** Tests Service.callMethod(). */
-  public void testCallMethod() throws Exception {
-    FooRequest fooRequest = FooRequest.newBuilder().build();
-    BarRequest barRequest = BarRequest.newBuilder().build();
-    MockCallback<Message> fooCallback = new MockCallback<Message>();
-    MockCallback<Message> barCallback = new MockCallback<Message>();
-    TestService mockService = control.createMock(TestService.class);
-
-    mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
-                    this.<FooResponse>wrapsCallback(fooCallback));
-    mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
-                    this.<BarResponse>wrapsCallback(barCallback));
-    control.replay();
-
-    mockService.callMethod(fooDescriptor, mockController,
-                           fooRequest, fooCallback);
-    mockService.callMethod(barDescriptor, mockController,
-                           barRequest, barCallback);
-    control.verify();
-  }
-
-  /** Tests Service.get{Request,Response}Prototype(). */
-  public void testGetPrototype() throws Exception {
-    TestService mockService = control.createMock(TestService.class);
-
-    assertSame(mockService.getRequestPrototype(fooDescriptor),
-               FooRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(fooDescriptor),
-               FooResponse.getDefaultInstance());
-    assertSame(mockService.getRequestPrototype(barDescriptor),
-               BarRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(barDescriptor),
-               BarResponse.getDefaultInstance());
-  }
-
-  /** Tests generated stubs. */
-  public void testStub() throws Exception {
-    FooRequest fooRequest = FooRequest.newBuilder().build();
-    BarRequest barRequest = BarRequest.newBuilder().build();
-    MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
-    MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
-    RpcChannel mockChannel = control.createMock(RpcChannel.class);
-    TestService stub = TestService.newStub(mockChannel);
-
-    mockChannel.callMethod(
-      EasyMock.same(fooDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(fooRequest),
-      EasyMock.same(FooResponse.getDefaultInstance()),
-      this.<Message>wrapsCallback(fooCallback));
-    mockChannel.callMethod(
-      EasyMock.same(barDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(barRequest),
-      EasyMock.same(BarResponse.getDefaultInstance()),
-      this.<Message>wrapsCallback(barCallback));
-    control.replay();
-
-    stub.foo(mockController, fooRequest, fooCallback);
-    stub.bar(mockController, barRequest, barCallback);
-    control.verify();
-  }
-
-  /** Tests generated blocking stubs. */
-  public void testBlockingStub() throws Exception {
-    FooRequest fooRequest = FooRequest.newBuilder().build();
-    BarRequest barRequest = BarRequest.newBuilder().build();
-    BlockingRpcChannel mockChannel =
-        control.createMock(BlockingRpcChannel.class);
-    TestService.BlockingInterface stub =
-        TestService.newBlockingStub(mockChannel);
-
-    FooResponse fooResponse = FooResponse.newBuilder().build();
-    BarResponse barResponse = BarResponse.newBuilder().build();
-
-    EasyMock.expect(mockChannel.callBlockingMethod(
-      EasyMock.same(fooDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(fooRequest),
-      EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
-    EasyMock.expect(mockChannel.callBlockingMethod(
-      EasyMock.same(barDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(barRequest),
-      EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
-    control.replay();
-
-    assertSame(fooResponse, stub.foo(mockController, fooRequest));
-    assertSame(barResponse, stub.bar(mockController, barRequest));
-    control.verify();
-  }
-
-  public void testNewReflectiveService() {
-    ServiceWithNoOuter.Interface impl =
-        control.createMock(ServiceWithNoOuter.Interface.class);
-    RpcController controller = control.createMock(RpcController.class);
-    Service service = ServiceWithNoOuter.newReflectiveService(impl);
-
-    MethodDescriptor fooMethod =
-        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
-    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
-    RpcCallback<Message> callback = new RpcCallback<Message>() {
-      public void run(Message parameter) {
-        // No reason this should be run.
-        fail();
-      }
-    };
-    RpcCallback<TestAllTypes> specializedCallback =
-        RpcUtil.specializeCallback(callback);
-
-    impl.foo(EasyMock.same(controller), EasyMock.same(request),
-        EasyMock.same(specializedCallback));
-    EasyMock.expectLastCall();
-
-    control.replay();
-
-    service.callMethod(fooMethod, controller, request, callback);
-
-    control.verify();
-  }
-
-  public void testNewReflectiveBlockingService() throws ServiceException {
-    ServiceWithNoOuter.BlockingInterface impl =
-        control.createMock(ServiceWithNoOuter.BlockingInterface.class);
-    RpcController controller = control.createMock(RpcController.class);
-    BlockingService service =
-        ServiceWithNoOuter.newReflectiveBlockingService(impl);
-
-    MethodDescriptor fooMethod =
-        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
-    MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
-
-    TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
-    EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
-        .andReturn(expectedResponse);
-
-    control.replay();
-
-    Message response =
-        service.callBlockingMethod(fooMethod, controller, request);
-    assertEquals(expectedResponse, response);
-
-    control.verify();
-  }
-
-  public void testNoGenericServices() throws Exception {
-    // Non-services should be usable.
-    UnittestNoGenericServices.TestMessage message =
-      UnittestNoGenericServices.TestMessage.newBuilder()
-        .setA(123)
-        .setExtension(UnittestNoGenericServices.testExtension, 456)
-        .build();
-    assertEquals(123, message.getA());
-    assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
-
-    // Build a list of the class names nested in UnittestNoGenericServices.
-    String outerName = "google.protobuf.no_generic_services_test." +
-                       "UnittestNoGenericServices";
-    Class<?> outerClass = Class.forName(outerName);
-
-    Set<String> innerClassNames = new HashSet<String>();
-    for (Class<?> innerClass : outerClass.getClasses()) {
-      String fullName = innerClass.getName();
-      // Figure out the unqualified name of the inner class.
-      // Note:  Surprisingly, the full name of an inner class will be separated
-      //   from the outer class name by a '$' rather than a '.'.  This is not
-      //   mentioned in the documentation for java.lang.Class.  I don't want to
-      //   make assumptions, so I'm just going to accept any character as the
-      //   separator.
-      assertTrue(fullName.startsWith(outerName));
-
-      if (!Service.class.isAssignableFrom(innerClass) &&
-          !Message.class.isAssignableFrom(innerClass) &&
-          !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
-        // Ignore any classes not generated by the base code generator.
-        continue;
-      }
-
-      innerClassNames.add(fullName.substring(outerName.length() + 1));
-    }
-
-    // No service class should have been generated.
-    assertTrue(innerClassNames.contains("TestMessage"));
-    assertTrue(innerClassNames.contains("TestEnum"));
-    assertFalse(innerClassNames.contains("TestService"));
-
-    // But descriptors are there.
-    FileDescriptor file = UnittestNoGenericServices.getDescriptor();
-    assertEquals(1, file.getServices().size());
-    assertEquals("TestService", file.getServices().get(0).getName());
-    assertEquals(1, file.getServices().get(0).getMethods().size());
-    assertEquals("Foo",
-        file.getServices().get(0).getMethods().get(0).getName());
-  }
-
-  // =================================================================
-
-  /**
-   * wrapsCallback() is an EasyMock argument predicate.  wrapsCallback(c)
-   * matches a callback if calling that callback causes c to be called.
-   * In other words, c wraps the given callback.
-   */
-  private <Type extends Message> RpcCallback<Type> wrapsCallback(
-      MockCallback<?> callback) {
-    EasyMock.reportMatcher(new WrapsCallback(callback));
-    return null;
-  }
-
-  /** The parameter to wrapsCallback() must be a MockCallback. */
-  private static class MockCallback<Type extends Message>
-      implements RpcCallback<Type> {
-    private boolean called = false;
-
-    public boolean isCalled() { return called; }
-
-    public void reset() { called = false; }
-    public void run(Type message) { called = true; }
-  }
-
-  /** Implementation of the wrapsCallback() argument matcher. */
-  private static class WrapsCallback implements IArgumentMatcher {
-    private MockCallback<?> callback;
-
-    public WrapsCallback(MockCallback<?> callback) {
-      this.callback = callback;
-    }
-
-    @SuppressWarnings("unchecked")
-    public boolean matches(Object actual) {
-      if (!(actual instanceof RpcCallback)) {
-        return false;
-      }
-      RpcCallback actualCallback = (RpcCallback)actual;
-
-      callback.reset();
-      actualCallback.run(null);
-      return callback.isCalled();
-    }
-
-    public void appendTo(StringBuffer buffer) {
-      buffer.append("wrapsCallback(mockCallback)");
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
deleted file mode 100644
index 366086d..0000000
--- a/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
+++ /dev/null
@@ -1,420 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * @author darick@google.com Darick Tong
- */
-public class SmallSortedMapTest extends TestCase {
-  // java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it
-  // here for JDK 1.5 users.
-  private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
-    private final K key;
-    private V value;
-
-    SimpleEntry(K key, V value) {
-      this.key = key;
-      this.value = value;
-    }
-
-    public K getKey() {
-      return key;
-    }
-
-    public V getValue() {
-      return value;
-    }
-
-    public V setValue(V value) {
-      V oldValue = this.value;
-      this.value = value;
-      return oldValue;
-    }
-
-    private static boolean eq(Object o1, Object o2) {
-      return o1 == null ? o2 == null : o1.equals(o2);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (!(o instanceof Map.Entry))
-        return false;
-      Map.Entry e = (Map.Entry) o;
-      return eq(key, e.getKey()) && eq(value, e.getValue());
-    }
-
-    @Override
-    public int hashCode() {
-      return ((key == null) ? 0 : key.hashCode()) ^
-          ((value == null) ? 0 : value.hashCode());
-    }
-  }
-
-  public void testPutAndGetArrayEntriesOnly() {
-    runPutAndGetTest(3);
-  }
-
-  public void testPutAndGetOverflowEntries() {
-    runPutAndGetTest(6);
-  }
-
-  private void runPutAndGetTest(int numElements) {
-    // Test with even and odd arraySize
-    SmallSortedMap<Integer, Integer> map1 =
-        SmallSortedMap.newInstanceForTest(3);
-    SmallSortedMap<Integer, Integer> map2 =
-        SmallSortedMap.newInstanceForTest(4);
-    SmallSortedMap<Integer, Integer> map3 =
-        SmallSortedMap.newInstanceForTest(3);
-    SmallSortedMap<Integer, Integer> map4 =
-        SmallSortedMap.newInstanceForTest(4);
-
-    // Test with puts in ascending order.
-    for (int i = 0; i < numElements; i++) {
-      assertNull(map1.put(i, i + 1));
-      assertNull(map2.put(i, i + 1));
-    }
-    // Test with puts in descending order.
-    for (int i = numElements - 1; i >= 0; i--) {
-      assertNull(map3.put(i, i + 1));
-      assertNull(map4.put(i, i + 1));
-    }
-
-    assertEquals(Math.min(3, numElements), map1.getNumArrayEntries());
-    assertEquals(Math.min(4, numElements), map2.getNumArrayEntries());
-    assertEquals(Math.min(3, numElements), map3.getNumArrayEntries());
-    assertEquals(Math.min(4, numElements), map4.getNumArrayEntries());
-
-    List<SmallSortedMap<Integer, Integer>> allMaps =
-        new ArrayList<SmallSortedMap<Integer, Integer>>();
-    allMaps.add(map1);
-    allMaps.add(map2);
-    allMaps.add(map3);
-    allMaps.add(map4);
-
-    for (SmallSortedMap<Integer, Integer> map : allMaps) {
-      assertEquals(numElements, map.size());
-      for (int i = 0; i < numElements; i++) {
-        assertEquals(new Integer(i + 1), map.get(i));
-      }
-    }
-
-    assertEquals(map1, map2);
-    assertEquals(map2, map3);
-    assertEquals(map3, map4);
-  }
-
-  public void testReplacingPut() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-      assertNull(map.remove(i + 1));
-    }
-    for (int i = 0; i < 6; i++) {
-      assertEquals(new Integer(i + 1), map.put(i, i + 2));
-    }
-  }
-
-  public void testRemove() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-      assertNull(map.remove(i + 1));
-    }
-
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(3, map.getNumOverflowEntries());
-    assertEquals(6,  map.size());
-    assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet());
-
-    assertEquals(new Integer(2), map.remove(1));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(2, map.getNumOverflowEntries());
-    assertEquals(5,  map.size());
-    assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet());
-
-    assertEquals(new Integer(5), map.remove(4));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(1, map.getNumOverflowEntries());
-    assertEquals(4,  map.size());
-    assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet());
-
-    assertEquals(new Integer(4), map.remove(3));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(3, map.size());
-    assertEquals(makeSortedKeySet(0, 2, 5), map.keySet());
-
-    assertNull(map.remove(3));
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(3, map.size());
-
-    assertEquals(new Integer(1), map.remove(0));
-    assertEquals(2, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(2, map.size());
-  }
-
-  public void testClear() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    map.clear();
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
-  }
-
-  public void testGetArrayEntryAndOverflowEntries() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    assertEquals(3, map.getNumArrayEntries());
-    for (int i = 0; i < 3; i++) {
-      Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i);
-      assertEquals(new Integer(i), entry.getKey());
-      assertEquals(new Integer(i + 1), entry.getValue());
-    }
-    Iterator<Map.Entry<Integer, Integer>> it =
-        map.getOverflowEntries().iterator();
-    for (int i = 3; i < 6; i++) {
-      assertTrue(it.hasNext());
-      Map.Entry<Integer, Integer> entry = it.next();
-      assertEquals(new Integer(i), entry.getKey());
-      assertEquals(new Integer(i + 1), entry.getValue());
-    }
-    assertFalse(it.hasNext());
-  }
-
-  public void testEntrySetContains() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
-    for (int i = 0; i < 6; i++) {
-      assertTrue(
-          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1)));
-      assertFalse(
-          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i)));
-    }
-  }
-
-  public void testEntrySetAdd() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
-    for (int i = 0; i < 6; i++) {
-      Map.Entry<Integer, Integer> entry =
-          new SimpleEntry<Integer, Integer>(i, i + 1);
-      assertTrue(entrySet.add(entry));
-      assertFalse(entrySet.add(entry));
-    }
-    for (int i = 0; i < 6; i++) {
-      assertEquals(new Integer(i + 1), map.get(i));
-    }
-    assertEquals(3, map.getNumArrayEntries());
-    assertEquals(3, map.getNumOverflowEntries());
-    assertEquals(6, map.size());
-  }
-
-  public void testEntrySetRemove() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    for (int i = 0; i < 6; i++) {
-      Map.Entry<Integer, Integer> entry =
-          new SimpleEntry<Integer, Integer>(i, i + 1);
-      assertTrue(entrySet.remove(entry));
-      assertFalse(entrySet.remove(entry));
-    }
-    assertTrue(map.isEmpty());
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
-  }
-
-  public void testEntrySetClear() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    map.entrySet().clear();
-    assertTrue(map.isEmpty());
-    assertEquals(0, map.getNumArrayEntries());
-    assertEquals(0, map.getNumOverflowEntries());
-    assertEquals(0, map.size());
-  }
-
-  public void testEntrySetIteratorNext() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
-    for (int i = 0; i < 6; i++) {
-      assertTrue(it.hasNext());
-      Map.Entry<Integer, Integer> entry = it.next();
-      assertEquals(new Integer(i), entry.getKey());
-      assertEquals(new Integer(i + 1), entry.getValue());
-    }
-    assertFalse(it.hasNext());
-  }
-
-  public void testEntrySetIteratorRemove() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
-    for (int i = 0; i < 6; i++) {
-      assertTrue(map.containsKey(i));
-      it.next();
-      it.remove();
-      assertFalse(map.containsKey(i));
-      assertEquals(6 - i - 1, map.size());
-    }
-  }
-
-  public void testMapEntryModification() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
-    for (int i = 0; i < 6; i++) {
-      Map.Entry<Integer, Integer> entry = it.next();
-      entry.setValue(i + 23);
-    }
-    for (int i = 0; i < 6; i++) {
-      assertEquals(new Integer(i + 23), map.get(i));
-    }
-  }
-
-  public void testMakeImmutable() {
-    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
-    for (int i = 0; i < 6; i++) {
-      assertNull(map.put(i, i + 1));
-    }
-    map.makeImmutable();
-    assertEquals(new Integer(1), map.get(0));
-    assertEquals(6, map.size());
-
-    try {
-      map.put(23, 23);
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    Map<Integer, Integer> other = new HashMap<Integer, Integer>();
-    other.put(23, 23);
-    try {
-      map.putAll(other);
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    try {
-      map.remove(0);
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    try {
-      map.clear();
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
-    try {
-      entrySet.clear();
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator();
-    while (it.hasNext()) {
-      Map.Entry<Integer, Integer> entry = it.next();
-      try {
-        entry.setValue(0);
-        fail("Expected UnsupportedOperationException");
-      } catch (UnsupportedOperationException expected) {
-      }
-      try {
-        it.remove();
-        fail("Expected UnsupportedOperationException");
-      } catch (UnsupportedOperationException expected) {
-      }
-    }
-
-    Set<Integer> keySet = map.keySet();
-    try {
-      keySet.clear();
-      fail("Expected UnsupportedOperationException");
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    Iterator<Integer> keys = keySet.iterator();
-    while (keys.hasNext()) {
-      Integer key = keys.next();
-      try {
-        keySet.remove(key);
-        fail("Expected UnsupportedOperationException");
-      } catch (UnsupportedOperationException expected) {
-      }
-      try {
-        keys.remove();
-        fail("Expected UnsupportedOperationException");
-      } catch (UnsupportedOperationException expected) {
-      }
-    }
-  }
-
-  private Set<Integer> makeSortedKeySet(Integer... keys) {
-    return new TreeSet<Integer>(Arrays.<Integer>asList(keys));
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
deleted file mode 100644
index 614ac7f..0000000
--- a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import junit.framework.TestCase;
-
-/**
- * Tests that proto2 api generation doesn't cause compile errors when
- * compiling protocol buffers that have names that would otherwise conflict
- * if not fully qualified (like @Deprecated and @Override).
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class TestBadIdentifiers extends TestCase {
-
-  public void testCompilation() {
-    // If this compiles, it means the generation was correct.
-    TestBadIdentifiersProto.Deprecated.newBuilder();
-    TestBadIdentifiersProto.Override.newBuilder();
-  }
-
-  public void testGetDescriptor() {
-    Descriptors.FileDescriptor fileDescriptor =
-        TestBadIdentifiersProto.getDescriptor();
-    String descriptorField = TestBadIdentifiersProto.Descriptor
-        .getDefaultInstance().getDescriptor();
-    Descriptors.Descriptor protoDescriptor = TestBadIdentifiersProto.Descriptor
-        .getDefaultInstance().getDescriptorForType();
-    String nestedDescriptorField = TestBadIdentifiersProto.Descriptor
-        .NestedDescriptor.getDefaultInstance().getDescriptor();
-    Descriptors.Descriptor nestedProtoDescriptor = TestBadIdentifiersProto
-        .Descriptor.NestedDescriptor.getDefaultInstance()
-        .getDescriptorForType();
-  }
-
-  public void testConflictingFieldNames() throws Exception {
-    TestBadIdentifiersProto.TestConflictingFieldNames message =
-        TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
-    // Make sure generated accessors are properly named.
-    assertEquals(0, message.getInt32Field1Count());
-    assertEquals(0, message.getEnumField2Count());
-    assertEquals(0, message.getStringField3Count());
-    assertEquals(0, message.getBytesField4Count());
-    assertEquals(0, message.getMessageField5Count());
-
-    assertEquals(0, message.getInt32FieldCount11());
-    assertEquals(1, message.getEnumFieldCount12().getNumber());
-    assertEquals("", message.getStringFieldCount13());
-    assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
-    assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
-
-    assertEquals(0, message.getInt32Field21Count());
-    assertEquals(0, message.getEnumField22Count());
-    assertEquals(0, message.getStringField23Count());
-    assertEquals(0, message.getBytesField24Count());
-    assertEquals(0, message.getMessageField25Count());
-
-    assertEquals(0, message.getInt32Field1List().size());
-    assertEquals(0, message.getInt32FieldList31());
-
-    assertEquals(0, message.getInt64FieldCount());
-    assertEquals(0L, message.getExtension(
-        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
-    assertEquals(0L, message.getExtension(
-        TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
-
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java
deleted file mode 100644
index 135a117..0000000
--- a/java/src/test/java/com/google/protobuf/TestUtil.java
+++ /dev/null
@@ -1,4124 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto;
-import com.google.protobuf.UnittestLite;
-
-// The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
-// import static protobuf_unittest.UnittestProto.*;
-import static protobuf_unittest.UnittestProto.defaultInt32Extension;
-import static protobuf_unittest.UnittestProto.defaultInt64Extension;
-import static protobuf_unittest.UnittestProto.defaultUint32Extension;
-import static protobuf_unittest.UnittestProto.defaultUint64Extension;
-import static protobuf_unittest.UnittestProto.defaultSint32Extension;
-import static protobuf_unittest.UnittestProto.defaultSint64Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
-import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
-import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
-import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
-import static protobuf_unittest.UnittestProto.defaultFloatExtension;
-import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
-import static protobuf_unittest.UnittestProto.defaultBoolExtension;
-import static protobuf_unittest.UnittestProto.defaultStringExtension;
-import static protobuf_unittest.UnittestProto.defaultBytesExtension;
-import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
-import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
-import static protobuf_unittest.UnittestProto.defaultCordExtension;
-
-import static protobuf_unittest.UnittestProto.oneofUint32Extension;
-import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension;
-import static protobuf_unittest.UnittestProto.oneofStringExtension;
-import static protobuf_unittest.UnittestProto.oneofBytesExtension;
-
-import static protobuf_unittest.UnittestProto.optionalInt32Extension;
-import static protobuf_unittest.UnittestProto.optionalInt64Extension;
-import static protobuf_unittest.UnittestProto.optionalUint32Extension;
-import static protobuf_unittest.UnittestProto.optionalUint64Extension;
-import static protobuf_unittest.UnittestProto.optionalSint32Extension;
-import static protobuf_unittest.UnittestProto.optionalSint64Extension;
-import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
-import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
-import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
-import static protobuf_unittest.UnittestProto.optionalFloatExtension;
-import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
-import static protobuf_unittest.UnittestProto.optionalBoolExtension;
-import static protobuf_unittest.UnittestProto.optionalStringExtension;
-import static protobuf_unittest.UnittestProto.optionalBytesExtension;
-import static protobuf_unittest.UnittestProto.optionalGroupExtension;
-import static protobuf_unittest.UnittestProto.optionalCordExtension;
-import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
-import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension;
-import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
-
-import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
-import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
-import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
-import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
-import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
-import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
-import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
-import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
-import static protobuf_unittest.UnittestProto.repeatedStringExtension;
-import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
-import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
-import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension;
-import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
-import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
-import static protobuf_unittest.UnittestProto.repeatedCordExtension;
-
-import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
-import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
-
-import static protobuf_unittest.UnittestProto.packedInt32Extension;
-import static protobuf_unittest.UnittestProto.packedInt64Extension;
-import static protobuf_unittest.UnittestProto.packedUint32Extension;
-import static protobuf_unittest.UnittestProto.packedUint64Extension;
-import static protobuf_unittest.UnittestProto.packedSint32Extension;
-import static protobuf_unittest.UnittestProto.packedSint64Extension;
-import static protobuf_unittest.UnittestProto.packedFixed32Extension;
-import static protobuf_unittest.UnittestProto.packedFixed64Extension;
-import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
-import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
-import static protobuf_unittest.UnittestProto.packedFloatExtension;
-import static protobuf_unittest.UnittestProto.packedDoubleExtension;
-import static protobuf_unittest.UnittestProto.packedBoolExtension;
-import static protobuf_unittest.UnittestProto.packedEnumExtension;
-
-import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofStringExtensionLite;
-import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite;
-
-import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
-import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
-
-import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
-import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
-
-import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
-import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
-import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
-import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
-import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
-
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-import protobuf_unittest.UnittestProto.TestOneof2;
-import protobuf_unittest.UnittestProto.TestPackedExtensions;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestProto.TestUnpackedTypes;
-import protobuf_unittest.UnittestProto.ForeignMessage;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import com.google.protobuf.test.UnittestImport.ImportEnum;
-import com.google.protobuf.test.UnittestImport.ImportMessage;
-import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
-
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-import com.google.protobuf.UnittestLite.ForeignMessageLite;
-import com.google.protobuf.UnittestLite.ForeignEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportEnumLite;
-import com.google.protobuf.UnittestImportLite.ImportMessageLite;
-import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
-
-import junit.framework.Assert;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Contains methods for setting all fields of {@code TestAllTypes} to
- * some values as well as checking that all the fields are set to those values.
- * These are useful for testing various protocol message features, e.g.
- * set all fields of a message, serialize it, parse it, and check that all
- * fields are set.
- *
- * <p>This code is not to be used outside of {@code com.google.protobuf} and
- * subpackages.
- *
- * @author kenton@google.com Kenton Varda
- */
-public final class TestUtil {
-  private TestUtil() {}
-
-  /** Helper to convert a String to ByteString. */
-  static ByteString toBytes(String str) {
-    try {
-      return ByteString.copyFrom(str.getBytes("UTF-8"));
-    } catch(java.io.UnsupportedEncodingException e) {
-      throw new RuntimeException("UTF-8 not supported.", e);
-    }
-  }
-
-  /**
-   * Get a {@code TestAllTypes} with all fields set as they would be by
-   * {@link #setAllFields(TestAllTypes.Builder)}.
-   */
-  public static TestAllTypes getAllSet() {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    setAllFields(builder);
-    return builder.build();
-  }
-
-  /**
-   * Get a {@code TestAllTypes.Builder} with all fields set as they would be by
-   * {@link #setAllFields(TestAllTypes.Builder)}.
-   */
-  public static TestAllTypes.Builder getAllSetBuilder() {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    setAllFields(builder);
-    return builder;
-  }
-
-  /**
-   * Get a {@code TestAllExtensions} with all fields set as they would be by
-   * {@link #setAllExtensions(TestAllExtensions.Builder)}.
-   */
-  public static TestAllExtensions getAllExtensionsSet() {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    setAllExtensions(builder);
-    return builder.build();
-  }
-
-  public static TestAllExtensionsLite getAllLiteExtensionsSet() {
-    TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
-    setAllExtensions(builder);
-    return builder.build();
-  }
-
-  public static TestPackedTypes getPackedSet() {
-    TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
-    setPackedFields(builder);
-    return builder.build();
-  }
-
-  public static TestUnpackedTypes getUnpackedSet() {
-    TestUnpackedTypes.Builder builder = TestUnpackedTypes.newBuilder();
-    setUnpackedFields(builder);
-    return builder.build();
-  }
-
-  public static TestPackedExtensions getPackedExtensionsSet() {
-    TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder();
-    setPackedExtensions(builder);
-    return builder.build();
-  }
-
-  public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
-    TestPackedExtensionsLite.Builder builder =
-        TestPackedExtensionsLite.newBuilder();
-    setPackedExtensions(builder);
-    return builder.build();
-  }
-
-  /**
-   * Set every field of {@code message} to the values expected by
-   * {@code assertAllFieldsSet()}.
-   */
-  public static void setAllFields(TestAllTypes.Builder message) {
-    message.setOptionalInt32   (101);
-    message.setOptionalInt64   (102);
-    message.setOptionalUint32  (103);
-    message.setOptionalUint64  (104);
-    message.setOptionalSint32  (105);
-    message.setOptionalSint64  (106);
-    message.setOptionalFixed32 (107);
-    message.setOptionalFixed64 (108);
-    message.setOptionalSfixed32(109);
-    message.setOptionalSfixed64(110);
-    message.setOptionalFloat   (111);
-    message.setOptionalDouble  (112);
-    message.setOptionalBool    (true);
-    message.setOptionalString  ("115");
-    message.setOptionalBytes   (toBytes("116"));
-
-    message.setOptionalGroup(
-      TestAllTypes.OptionalGroup.newBuilder().setA(117).build());
-    message.setOptionalNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
-    message.setOptionalForeignMessage(
-      ForeignMessage.newBuilder().setC(119).build());
-    message.setOptionalImportMessage(
-      ImportMessage.newBuilder().setD(120).build());
-    message.setOptionalPublicImportMessage(
-      PublicImportMessage.newBuilder().setE(126).build());
-    message.setOptionalLazyMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
-
-    message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
-    message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
-    message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
-
-    message.setOptionalStringPiece("124");
-    message.setOptionalCord("125");
-
-    // -----------------------------------------------------------------
-
-    message.addRepeatedInt32   (201);
-    message.addRepeatedInt64   (202);
-    message.addRepeatedUint32  (203);
-    message.addRepeatedUint64  (204);
-    message.addRepeatedSint32  (205);
-    message.addRepeatedSint64  (206);
-    message.addRepeatedFixed32 (207);
-    message.addRepeatedFixed64 (208);
-    message.addRepeatedSfixed32(209);
-    message.addRepeatedSfixed64(210);
-    message.addRepeatedFloat   (211);
-    message.addRepeatedDouble  (212);
-    message.addRepeatedBool    (true);
-    message.addRepeatedString  ("215");
-    message.addRepeatedBytes   (toBytes("216"));
-
-    message.addRepeatedGroup(
-      TestAllTypes.RepeatedGroup.newBuilder().setA(217).build());
-    message.addRepeatedNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
-    message.addRepeatedForeignMessage(
-      ForeignMessage.newBuilder().setC(219).build());
-    message.addRepeatedImportMessage(
-      ImportMessage.newBuilder().setD(220).build());
-    message.addRepeatedLazyMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
-
-    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
-    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
-    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAR);
-
-    message.addRepeatedStringPiece("224");
-    message.addRepeatedCord("225");
-
-    // Add a second one of each field.
-    message.addRepeatedInt32   (301);
-    message.addRepeatedInt64   (302);
-    message.addRepeatedUint32  (303);
-    message.addRepeatedUint64  (304);
-    message.addRepeatedSint32  (305);
-    message.addRepeatedSint64  (306);
-    message.addRepeatedFixed32 (307);
-    message.addRepeatedFixed64 (308);
-    message.addRepeatedSfixed32(309);
-    message.addRepeatedSfixed64(310);
-    message.addRepeatedFloat   (311);
-    message.addRepeatedDouble  (312);
-    message.addRepeatedBool    (false);
-    message.addRepeatedString  ("315");
-    message.addRepeatedBytes   (toBytes("316"));
-
-    message.addRepeatedGroup(
-      TestAllTypes.RepeatedGroup.newBuilder().setA(317).build());
-    message.addRepeatedNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
-    message.addRepeatedForeignMessage(
-      ForeignMessage.newBuilder().setC(319).build());
-    message.addRepeatedImportMessage(
-      ImportMessage.newBuilder().setD(320).build());
-    message.addRepeatedLazyMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
-
-    message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
-    message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
-    message.addRepeatedImportEnum (ImportEnum.IMPORT_BAZ);
-
-    message.addRepeatedStringPiece("324");
-    message.addRepeatedCord("325");
-
-    // -----------------------------------------------------------------
-
-    message.setDefaultInt32   (401);
-    message.setDefaultInt64   (402);
-    message.setDefaultUint32  (403);
-    message.setDefaultUint64  (404);
-    message.setDefaultSint32  (405);
-    message.setDefaultSint64  (406);
-    message.setDefaultFixed32 (407);
-    message.setDefaultFixed64 (408);
-    message.setDefaultSfixed32(409);
-    message.setDefaultSfixed64(410);
-    message.setDefaultFloat   (411);
-    message.setDefaultDouble  (412);
-    message.setDefaultBool    (false);
-    message.setDefaultString  ("415");
-    message.setDefaultBytes   (toBytes("416"));
-
-    message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
-    message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
-    message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
-
-    message.setDefaultStringPiece("424");
-    message.setDefaultCord("425");
-
-    message.setOneofUint32(601);
-    message.setOneofNestedMessage(
-      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
-    message.setOneofString("603");
-    message.setOneofBytes(toBytes("604"));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Modify the repeated fields of {@code message} to contain the values
-   * expected by {@code assertRepeatedFieldsModified()}.
-   */
-  public static void modifyRepeatedFields(TestAllTypes.Builder message) {
-    message.setRepeatedInt32   (1, 501);
-    message.setRepeatedInt64   (1, 502);
-    message.setRepeatedUint32  (1, 503);
-    message.setRepeatedUint64  (1, 504);
-    message.setRepeatedSint32  (1, 505);
-    message.setRepeatedSint64  (1, 506);
-    message.setRepeatedFixed32 (1, 507);
-    message.setRepeatedFixed64 (1, 508);
-    message.setRepeatedSfixed32(1, 509);
-    message.setRepeatedSfixed64(1, 510);
-    message.setRepeatedFloat   (1, 511);
-    message.setRepeatedDouble  (1, 512);
-    message.setRepeatedBool    (1, true);
-    message.setRepeatedString  (1, "515");
-    message.setRepeatedBytes   (1, toBytes("516"));
-
-    message.setRepeatedGroup(1,
-      TestAllTypes.RepeatedGroup.newBuilder().setA(517).build());
-    message.setRepeatedNestedMessage(1,
-      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
-    message.setRepeatedForeignMessage(1,
-      ForeignMessage.newBuilder().setC(519).build());
-    message.setRepeatedImportMessage(1,
-      ImportMessage.newBuilder().setD(520).build());
-    message.setRepeatedLazyMessage(1,
-      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
-
-    message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
-    message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
-    message.setRepeatedImportEnum (1, ImportEnum.IMPORT_FOO);
-
-    message.setRepeatedStringPiece(1, "524");
-    message.setRepeatedCord(1, "525");
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are set to the values assigned by {@code setAllFields}.
-   */
-  public static void assertAllFieldsSet(TestAllTypesOrBuilder message) {
-    Assert.assertTrue(message.hasOptionalInt32   ());
-    Assert.assertTrue(message.hasOptionalInt64   ());
-    Assert.assertTrue(message.hasOptionalUint32  ());
-    Assert.assertTrue(message.hasOptionalUint64  ());
-    Assert.assertTrue(message.hasOptionalSint32  ());
-    Assert.assertTrue(message.hasOptionalSint64  ());
-    Assert.assertTrue(message.hasOptionalFixed32 ());
-    Assert.assertTrue(message.hasOptionalFixed64 ());
-    Assert.assertTrue(message.hasOptionalSfixed32());
-    Assert.assertTrue(message.hasOptionalSfixed64());
-    Assert.assertTrue(message.hasOptionalFloat   ());
-    Assert.assertTrue(message.hasOptionalDouble  ());
-    Assert.assertTrue(message.hasOptionalBool    ());
-    Assert.assertTrue(message.hasOptionalString  ());
-    Assert.assertTrue(message.hasOptionalBytes   ());
-
-    Assert.assertTrue(message.hasOptionalGroup         ());
-    Assert.assertTrue(message.hasOptionalNestedMessage ());
-    Assert.assertTrue(message.hasOptionalForeignMessage());
-    Assert.assertTrue(message.hasOptionalImportMessage ());
-
-    Assert.assertTrue(message.getOptionalGroup         ().hasA());
-    Assert.assertTrue(message.getOptionalNestedMessage ().hasBb());
-    Assert.assertTrue(message.getOptionalForeignMessage().hasC());
-    Assert.assertTrue(message.getOptionalImportMessage ().hasD());
-
-    Assert.assertTrue(message.hasOptionalNestedEnum ());
-    Assert.assertTrue(message.hasOptionalForeignEnum());
-    Assert.assertTrue(message.hasOptionalImportEnum ());
-
-    Assert.assertTrue(message.hasOptionalStringPiece());
-    Assert.assertTrue(message.hasOptionalCord());
-
-    Assert.assertEquals(101  , message.getOptionalInt32   ());
-    Assert.assertEquals(102  , message.getOptionalInt64   ());
-    Assert.assertEquals(103  , message.getOptionalUint32  ());
-    Assert.assertEquals(104  , message.getOptionalUint64  ());
-    Assert.assertEquals(105  , message.getOptionalSint32  ());
-    Assert.assertEquals(106  , message.getOptionalSint64  ());
-    Assert.assertEquals(107  , message.getOptionalFixed32 ());
-    Assert.assertEquals(108  , message.getOptionalFixed64 ());
-    Assert.assertEquals(109  , message.getOptionalSfixed32());
-    Assert.assertEquals(110  , message.getOptionalSfixed64());
-    Assert.assertEquals(111  , message.getOptionalFloat   (), 0.0);
-    Assert.assertEquals(112  , message.getOptionalDouble  (), 0.0);
-    Assert.assertEquals(true , message.getOptionalBool    ());
-    Assert.assertEquals("115", message.getOptionalString  ());
-    Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
-
-    Assert.assertEquals(117, message.getOptionalGroup              ().getA());
-    Assert.assertEquals(118, message.getOptionalNestedMessage      ().getBb());
-    Assert.assertEquals(119, message.getOptionalForeignMessage     ().getC());
-    Assert.assertEquals(120, message.getOptionalImportMessage      ().getD());
-    Assert.assertEquals(126, message.getOptionalPublicImportMessage().getE());
-    Assert.assertEquals(127, message.getOptionalLazyMessage        ().getBb());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
-    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
-
-    Assert.assertEquals("124", message.getOptionalStringPiece());
-    Assert.assertEquals("125", message.getOptionalCord());
-
-    // -----------------------------------------------------------------
-
-    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
-    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
-    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
-    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
-    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
-    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
-    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
-    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
-    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
-    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
-    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
-    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
-    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
-    Assert.assertEquals(2, message.getRepeatedStringCount  ());
-    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
-
-    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
-    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
-    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
-    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
-    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
-    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
-    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
-    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
-
-    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
-    Assert.assertEquals(2, message.getRepeatedCordCount());
-
-    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
-    Assert.assertEquals(202  , message.getRepeatedInt64   (0));
-    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
-    Assert.assertEquals(204  , message.getRepeatedUint64  (0));
-    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
-    Assert.assertEquals(206  , message.getRepeatedSint64  (0));
-    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
-    Assert.assertEquals(208  , message.getRepeatedFixed64 (0));
-    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
-    Assert.assertEquals(210  , message.getRepeatedSfixed64(0));
-    Assert.assertEquals(211  , message.getRepeatedFloat   (0), 0.0);
-    Assert.assertEquals(212  , message.getRepeatedDouble  (0), 0.0);
-    Assert.assertEquals(true , message.getRepeatedBool    (0));
-    Assert.assertEquals("215", message.getRepeatedString  (0));
-    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
-
-    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
-    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
-    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
-    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
-    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
-    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
-
-    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
-    Assert.assertEquals("225", message.getRepeatedCord(0));
-
-    Assert.assertEquals(301  , message.getRepeatedInt32   (1));
-    Assert.assertEquals(302  , message.getRepeatedInt64   (1));
-    Assert.assertEquals(303  , message.getRepeatedUint32  (1));
-    Assert.assertEquals(304  , message.getRepeatedUint64  (1));
-    Assert.assertEquals(305  , message.getRepeatedSint32  (1));
-    Assert.assertEquals(306  , message.getRepeatedSint64  (1));
-    Assert.assertEquals(307  , message.getRepeatedFixed32 (1));
-    Assert.assertEquals(308  , message.getRepeatedFixed64 (1));
-    Assert.assertEquals(309  , message.getRepeatedSfixed32(1));
-    Assert.assertEquals(310  , message.getRepeatedSfixed64(1));
-    Assert.assertEquals(311  , message.getRepeatedFloat   (1), 0.0);
-    Assert.assertEquals(312  , message.getRepeatedDouble  (1), 0.0);
-    Assert.assertEquals(false, message.getRepeatedBool    (1));
-    Assert.assertEquals("315", message.getRepeatedString  (1));
-    Assert.assertEquals(toBytes("316"), message.getRepeatedBytes(1));
-
-    Assert.assertEquals(317, message.getRepeatedGroup         (1).getA());
-    Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
-    Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
-    Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
-    Assert.assertEquals(327, message.getRepeatedLazyMessage   (1).getBb());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
-    Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnum(1));
-
-    Assert.assertEquals("324", message.getRepeatedStringPiece(1));
-    Assert.assertEquals("325", message.getRepeatedCord(1));
-
-    // -----------------------------------------------------------------
-
-    Assert.assertTrue(message.hasDefaultInt32   ());
-    Assert.assertTrue(message.hasDefaultInt64   ());
-    Assert.assertTrue(message.hasDefaultUint32  ());
-    Assert.assertTrue(message.hasDefaultUint64  ());
-    Assert.assertTrue(message.hasDefaultSint32  ());
-    Assert.assertTrue(message.hasDefaultSint64  ());
-    Assert.assertTrue(message.hasDefaultFixed32 ());
-    Assert.assertTrue(message.hasDefaultFixed64 ());
-    Assert.assertTrue(message.hasDefaultSfixed32());
-    Assert.assertTrue(message.hasDefaultSfixed64());
-    Assert.assertTrue(message.hasDefaultFloat   ());
-    Assert.assertTrue(message.hasDefaultDouble  ());
-    Assert.assertTrue(message.hasDefaultBool    ());
-    Assert.assertTrue(message.hasDefaultString  ());
-    Assert.assertTrue(message.hasDefaultBytes   ());
-
-    Assert.assertTrue(message.hasDefaultNestedEnum ());
-    Assert.assertTrue(message.hasDefaultForeignEnum());
-    Assert.assertTrue(message.hasDefaultImportEnum ());
-
-    Assert.assertTrue(message.hasDefaultStringPiece());
-    Assert.assertTrue(message.hasDefaultCord());
-
-    Assert.assertEquals(401  , message.getDefaultInt32   ());
-    Assert.assertEquals(402  , message.getDefaultInt64   ());
-    Assert.assertEquals(403  , message.getDefaultUint32  ());
-    Assert.assertEquals(404  , message.getDefaultUint64  ());
-    Assert.assertEquals(405  , message.getDefaultSint32  ());
-    Assert.assertEquals(406  , message.getDefaultSint64  ());
-    Assert.assertEquals(407  , message.getDefaultFixed32 ());
-    Assert.assertEquals(408  , message.getDefaultFixed64 ());
-    Assert.assertEquals(409  , message.getDefaultSfixed32());
-    Assert.assertEquals(410  , message.getDefaultSfixed64());
-    Assert.assertEquals(411  , message.getDefaultFloat   (), 0.0);
-    Assert.assertEquals(412  , message.getDefaultDouble  (), 0.0);
-    Assert.assertEquals(false, message.getDefaultBool    ());
-    Assert.assertEquals("415", message.getDefaultString  ());
-    Assert.assertEquals(toBytes("416"), message.getDefaultBytes());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
-    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
-    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
-
-    Assert.assertEquals("424", message.getDefaultStringPiece());
-    Assert.assertEquals("425", message.getDefaultCord());
-
-    Assert.assertFalse(message.hasOneofUint32());
-    Assert.assertFalse(message.hasOneofNestedMessage());
-    Assert.assertFalse(message.hasOneofString());
-    Assert.assertTrue(message.hasOneofBytes());
-
-    Assert.assertEquals(toBytes("604"), message.getOneofBytes());
-  }
-
-  // -------------------------------------------------------------------
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are cleared, and that getting the fields returns their
-   * default values.
-   */
-  public static void assertClear(TestAllTypesOrBuilder message) {
-    // hasBlah() should initially be false for all optional fields.
-    Assert.assertFalse(message.hasOptionalInt32   ());
-    Assert.assertFalse(message.hasOptionalInt64   ());
-    Assert.assertFalse(message.hasOptionalUint32  ());
-    Assert.assertFalse(message.hasOptionalUint64  ());
-    Assert.assertFalse(message.hasOptionalSint32  ());
-    Assert.assertFalse(message.hasOptionalSint64  ());
-    Assert.assertFalse(message.hasOptionalFixed32 ());
-    Assert.assertFalse(message.hasOptionalFixed64 ());
-    Assert.assertFalse(message.hasOptionalSfixed32());
-    Assert.assertFalse(message.hasOptionalSfixed64());
-    Assert.assertFalse(message.hasOptionalFloat   ());
-    Assert.assertFalse(message.hasOptionalDouble  ());
-    Assert.assertFalse(message.hasOptionalBool    ());
-    Assert.assertFalse(message.hasOptionalString  ());
-    Assert.assertFalse(message.hasOptionalBytes   ());
-
-    Assert.assertFalse(message.hasOptionalGroup         ());
-    Assert.assertFalse(message.hasOptionalNestedMessage ());
-    Assert.assertFalse(message.hasOptionalForeignMessage());
-    Assert.assertFalse(message.hasOptionalImportMessage ());
-
-    Assert.assertFalse(message.hasOptionalNestedEnum ());
-    Assert.assertFalse(message.hasOptionalForeignEnum());
-    Assert.assertFalse(message.hasOptionalImportEnum ());
-
-    Assert.assertFalse(message.hasOptionalStringPiece());
-    Assert.assertFalse(message.hasOptionalCord());
-
-    // Optional fields without defaults are set to zero or something like it.
-    Assert.assertEquals(0    , message.getOptionalInt32   ());
-    Assert.assertEquals(0    , message.getOptionalInt64   ());
-    Assert.assertEquals(0    , message.getOptionalUint32  ());
-    Assert.assertEquals(0    , message.getOptionalUint64  ());
-    Assert.assertEquals(0    , message.getOptionalSint32  ());
-    Assert.assertEquals(0    , message.getOptionalSint64  ());
-    Assert.assertEquals(0    , message.getOptionalFixed32 ());
-    Assert.assertEquals(0    , message.getOptionalFixed64 ());
-    Assert.assertEquals(0    , message.getOptionalSfixed32());
-    Assert.assertEquals(0    , message.getOptionalSfixed64());
-    Assert.assertEquals(0    , message.getOptionalFloat   (), 0.0);
-    Assert.assertEquals(0    , message.getOptionalDouble  (), 0.0);
-    Assert.assertEquals(false, message.getOptionalBool    ());
-    Assert.assertEquals(""   , message.getOptionalString  ());
-    Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
-
-    // Embedded messages should also be clear.
-    Assert.assertFalse(message.getOptionalGroup              ().hasA());
-    Assert.assertFalse(message.getOptionalNestedMessage      ().hasBb());
-    Assert.assertFalse(message.getOptionalForeignMessage     ().hasC());
-    Assert.assertFalse(message.getOptionalImportMessage      ().hasD());
-    Assert.assertFalse(message.getOptionalPublicImportMessage().hasE());
-    Assert.assertFalse(message.getOptionalLazyMessage        ().hasBb());
-
-    Assert.assertEquals(0, message.getOptionalGroup              ().getA());
-    Assert.assertEquals(0, message.getOptionalNestedMessage      ().getBb());
-    Assert.assertEquals(0, message.getOptionalForeignMessage     ().getC());
-    Assert.assertEquals(0, message.getOptionalImportMessage      ().getD());
-    Assert.assertEquals(0, message.getOptionalPublicImportMessage().getE());
-    Assert.assertEquals(0, message.getOptionalLazyMessage        ().getBb());
-
-    // Enums without defaults are set to the first value in the enum.
-    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
-    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getOptionalForeignEnum());
-    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getOptionalImportEnum());
-
-    Assert.assertEquals("", message.getOptionalStringPiece());
-    Assert.assertEquals("", message.getOptionalCord());
-
-    // Repeated fields are empty.
-    Assert.assertEquals(0, message.getRepeatedInt32Count   ());
-    Assert.assertEquals(0, message.getRepeatedInt64Count   ());
-    Assert.assertEquals(0, message.getRepeatedUint32Count  ());
-    Assert.assertEquals(0, message.getRepeatedUint64Count  ());
-    Assert.assertEquals(0, message.getRepeatedSint32Count  ());
-    Assert.assertEquals(0, message.getRepeatedSint64Count  ());
-    Assert.assertEquals(0, message.getRepeatedFixed32Count ());
-    Assert.assertEquals(0, message.getRepeatedFixed64Count ());
-    Assert.assertEquals(0, message.getRepeatedSfixed32Count());
-    Assert.assertEquals(0, message.getRepeatedSfixed64Count());
-    Assert.assertEquals(0, message.getRepeatedFloatCount   ());
-    Assert.assertEquals(0, message.getRepeatedDoubleCount  ());
-    Assert.assertEquals(0, message.getRepeatedBoolCount    ());
-    Assert.assertEquals(0, message.getRepeatedStringCount  ());
-    Assert.assertEquals(0, message.getRepeatedBytesCount   ());
-
-    Assert.assertEquals(0, message.getRepeatedGroupCount         ());
-    Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
-    Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
-    Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
-    Assert.assertEquals(0, message.getRepeatedLazyMessageCount   ());
-    Assert.assertEquals(0, message.getRepeatedNestedEnumCount    ());
-    Assert.assertEquals(0, message.getRepeatedForeignEnumCount   ());
-    Assert.assertEquals(0, message.getRepeatedImportEnumCount    ());
-
-    Assert.assertEquals(0, message.getRepeatedStringPieceCount());
-    Assert.assertEquals(0, message.getRepeatedCordCount());
-
-    // hasBlah() should also be false for all default fields.
-    Assert.assertFalse(message.hasDefaultInt32   ());
-    Assert.assertFalse(message.hasDefaultInt64   ());
-    Assert.assertFalse(message.hasDefaultUint32  ());
-    Assert.assertFalse(message.hasDefaultUint64  ());
-    Assert.assertFalse(message.hasDefaultSint32  ());
-    Assert.assertFalse(message.hasDefaultSint64  ());
-    Assert.assertFalse(message.hasDefaultFixed32 ());
-    Assert.assertFalse(message.hasDefaultFixed64 ());
-    Assert.assertFalse(message.hasDefaultSfixed32());
-    Assert.assertFalse(message.hasDefaultSfixed64());
-    Assert.assertFalse(message.hasDefaultFloat   ());
-    Assert.assertFalse(message.hasDefaultDouble  ());
-    Assert.assertFalse(message.hasDefaultBool    ());
-    Assert.assertFalse(message.hasDefaultString  ());
-    Assert.assertFalse(message.hasDefaultBytes   ());
-
-    Assert.assertFalse(message.hasDefaultNestedEnum ());
-    Assert.assertFalse(message.hasDefaultForeignEnum());
-    Assert.assertFalse(message.hasDefaultImportEnum ());
-
-    Assert.assertFalse(message.hasDefaultStringPiece());
-    Assert.assertFalse(message.hasDefaultCord());
-
-    // Fields with defaults have their default values (duh).
-    Assert.assertEquals( 41    , message.getDefaultInt32   ());
-    Assert.assertEquals( 42    , message.getDefaultInt64   ());
-    Assert.assertEquals( 43    , message.getDefaultUint32  ());
-    Assert.assertEquals( 44    , message.getDefaultUint64  ());
-    Assert.assertEquals(-45    , message.getDefaultSint32  ());
-    Assert.assertEquals( 46    , message.getDefaultSint64  ());
-    Assert.assertEquals( 47    , message.getDefaultFixed32 ());
-    Assert.assertEquals( 48    , message.getDefaultFixed64 ());
-    Assert.assertEquals( 49    , message.getDefaultSfixed32());
-    Assert.assertEquals(-50    , message.getDefaultSfixed64());
-    Assert.assertEquals( 51.5  , message.getDefaultFloat   (), 0.0);
-    Assert.assertEquals( 52e3  , message.getDefaultDouble  (), 0.0);
-    Assert.assertEquals(true   , message.getDefaultBool    ());
-    Assert.assertEquals("hello", message.getDefaultString  ());
-    Assert.assertEquals(toBytes("world"), message.getDefaultBytes());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
-    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
-
-    Assert.assertEquals("abc", message.getDefaultStringPiece());
-    Assert.assertEquals("123", message.getDefaultCord());
-
-    Assert.assertFalse(message.hasOneofUint32());
-    Assert.assertFalse(message.hasOneofNestedMessage());
-    Assert.assertFalse(message.hasOneofString());
-    Assert.assertFalse(message.hasOneofBytes());
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are set to the values assigned by {@code setAllFields}
-   * followed by {@code modifyRepeatedFields}.
-   */
-  public static void assertRepeatedFieldsModified(
-      TestAllTypesOrBuilder message) {
-    // ModifyRepeatedFields only sets the second repeated element of each
-    // field.  In addition to verifying this, we also verify that the first
-    // element and size were *not* modified.
-    Assert.assertEquals(2, message.getRepeatedInt32Count   ());
-    Assert.assertEquals(2, message.getRepeatedInt64Count   ());
-    Assert.assertEquals(2, message.getRepeatedUint32Count  ());
-    Assert.assertEquals(2, message.getRepeatedUint64Count  ());
-    Assert.assertEquals(2, message.getRepeatedSint32Count  ());
-    Assert.assertEquals(2, message.getRepeatedSint64Count  ());
-    Assert.assertEquals(2, message.getRepeatedFixed32Count ());
-    Assert.assertEquals(2, message.getRepeatedFixed64Count ());
-    Assert.assertEquals(2, message.getRepeatedSfixed32Count());
-    Assert.assertEquals(2, message.getRepeatedSfixed64Count());
-    Assert.assertEquals(2, message.getRepeatedFloatCount   ());
-    Assert.assertEquals(2, message.getRepeatedDoubleCount  ());
-    Assert.assertEquals(2, message.getRepeatedBoolCount    ());
-    Assert.assertEquals(2, message.getRepeatedStringCount  ());
-    Assert.assertEquals(2, message.getRepeatedBytesCount   ());
-
-    Assert.assertEquals(2, message.getRepeatedGroupCount         ());
-    Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
-    Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
-    Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
-    Assert.assertEquals(2, message.getRepeatedLazyMessageCount   ());
-    Assert.assertEquals(2, message.getRepeatedNestedEnumCount    ());
-    Assert.assertEquals(2, message.getRepeatedForeignEnumCount   ());
-    Assert.assertEquals(2, message.getRepeatedImportEnumCount    ());
-
-    Assert.assertEquals(2, message.getRepeatedStringPieceCount());
-    Assert.assertEquals(2, message.getRepeatedCordCount());
-
-    Assert.assertEquals(201  , message.getRepeatedInt32   (0));
-    Assert.assertEquals(202L , message.getRepeatedInt64   (0));
-    Assert.assertEquals(203  , message.getRepeatedUint32  (0));
-    Assert.assertEquals(204L , message.getRepeatedUint64  (0));
-    Assert.assertEquals(205  , message.getRepeatedSint32  (0));
-    Assert.assertEquals(206L , message.getRepeatedSint64  (0));
-    Assert.assertEquals(207  , message.getRepeatedFixed32 (0));
-    Assert.assertEquals(208L , message.getRepeatedFixed64 (0));
-    Assert.assertEquals(209  , message.getRepeatedSfixed32(0));
-    Assert.assertEquals(210L , message.getRepeatedSfixed64(0));
-    Assert.assertEquals(211F , message.getRepeatedFloat   (0));
-    Assert.assertEquals(212D , message.getRepeatedDouble  (0));
-    Assert.assertEquals(true , message.getRepeatedBool    (0));
-    Assert.assertEquals("215", message.getRepeatedString  (0));
-    Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
-
-    Assert.assertEquals(217, message.getRepeatedGroup         (0).getA());
-    Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
-    Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
-    Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
-    Assert.assertEquals(227, message.getRepeatedLazyMessage   (0).getBb());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
-    Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
-
-    Assert.assertEquals("224", message.getRepeatedStringPiece(0));
-    Assert.assertEquals("225", message.getRepeatedCord(0));
-
-    // Actually verify the second (modified) elements now.
-    Assert.assertEquals(501  , message.getRepeatedInt32   (1));
-    Assert.assertEquals(502L , message.getRepeatedInt64   (1));
-    Assert.assertEquals(503  , message.getRepeatedUint32  (1));
-    Assert.assertEquals(504L , message.getRepeatedUint64  (1));
-    Assert.assertEquals(505  , message.getRepeatedSint32  (1));
-    Assert.assertEquals(506L , message.getRepeatedSint64  (1));
-    Assert.assertEquals(507  , message.getRepeatedFixed32 (1));
-    Assert.assertEquals(508L , message.getRepeatedFixed64 (1));
-    Assert.assertEquals(509  , message.getRepeatedSfixed32(1));
-    Assert.assertEquals(510L , message.getRepeatedSfixed64(1));
-    Assert.assertEquals(511F , message.getRepeatedFloat   (1));
-    Assert.assertEquals(512D , message.getRepeatedDouble  (1));
-    Assert.assertEquals(true , message.getRepeatedBool    (1));
-    Assert.assertEquals("515", message.getRepeatedString  (1));
-    Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
-
-    Assert.assertEquals(517, message.getRepeatedGroup         (1).getA());
-    Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
-    Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
-    Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
-    Assert.assertEquals(527, message.getRepeatedLazyMessage   (1).getBb());
-
-    Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
-    Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
-    Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnum(1));
-
-    Assert.assertEquals("524", message.getRepeatedStringPiece(1));
-    Assert.assertEquals("525", message.getRepeatedCord(1));
-  }
-
-  /**
-   * Set every field of {@code message} to a unique value.
-   */
-  public static void setPackedFields(TestPackedTypes.Builder message) {
-    message.addPackedInt32   (601);
-    message.addPackedInt64   (602);
-    message.addPackedUint32  (603);
-    message.addPackedUint64  (604);
-    message.addPackedSint32  (605);
-    message.addPackedSint64  (606);
-    message.addPackedFixed32 (607);
-    message.addPackedFixed64 (608);
-    message.addPackedSfixed32(609);
-    message.addPackedSfixed64(610);
-    message.addPackedFloat   (611);
-    message.addPackedDouble  (612);
-    message.addPackedBool    (true);
-    message.addPackedEnum    (ForeignEnum.FOREIGN_BAR);
-    // Add a second one of each field.
-    message.addPackedInt32   (701);
-    message.addPackedInt64   (702);
-    message.addPackedUint32  (703);
-    message.addPackedUint64  (704);
-    message.addPackedSint32  (705);
-    message.addPackedSint64  (706);
-    message.addPackedFixed32 (707);
-    message.addPackedFixed64 (708);
-    message.addPackedSfixed32(709);
-    message.addPackedSfixed64(710);
-    message.addPackedFloat   (711);
-    message.addPackedDouble  (712);
-    message.addPackedBool    (false);
-    message.addPackedEnum    (ForeignEnum.FOREIGN_BAZ);
-  }
-
-  /**
-   * Set every field of {@code message} to a unique value. Must correspond with
-   * the values applied by {@code setPackedFields}.
-   */
-  public static void setUnpackedFields(TestUnpackedTypes.Builder message) {
-    message.addUnpackedInt32   (601);
-    message.addUnpackedInt64   (602);
-    message.addUnpackedUint32  (603);
-    message.addUnpackedUint64  (604);
-    message.addUnpackedSint32  (605);
-    message.addUnpackedSint64  (606);
-    message.addUnpackedFixed32 (607);
-    message.addUnpackedFixed64 (608);
-    message.addUnpackedSfixed32(609);
-    message.addUnpackedSfixed64(610);
-    message.addUnpackedFloat   (611);
-    message.addUnpackedDouble  (612);
-    message.addUnpackedBool    (true);
-    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAR);
-    // Add a second one of each field.
-    message.addUnpackedInt32   (701);
-    message.addUnpackedInt64   (702);
-    message.addUnpackedUint32  (703);
-    message.addUnpackedUint64  (704);
-    message.addUnpackedSint32  (705);
-    message.addUnpackedSint64  (706);
-    message.addUnpackedFixed32 (707);
-    message.addUnpackedFixed64 (708);
-    message.addUnpackedSfixed32(709);
-    message.addUnpackedSfixed64(710);
-    message.addUnpackedFloat   (711);
-    message.addUnpackedDouble  (712);
-    message.addUnpackedBool    (false);
-    message.addUnpackedEnum    (ForeignEnum.FOREIGN_BAZ);
-  }
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are set to the values assigned by {@code setPackedFields}.
-   */
-  public static void assertPackedFieldsSet(TestPackedTypes message) {
-    Assert.assertEquals(2, message.getPackedInt32Count   ());
-    Assert.assertEquals(2, message.getPackedInt64Count   ());
-    Assert.assertEquals(2, message.getPackedUint32Count  ());
-    Assert.assertEquals(2, message.getPackedUint64Count  ());
-    Assert.assertEquals(2, message.getPackedSint32Count  ());
-    Assert.assertEquals(2, message.getPackedSint64Count  ());
-    Assert.assertEquals(2, message.getPackedFixed32Count ());
-    Assert.assertEquals(2, message.getPackedFixed64Count ());
-    Assert.assertEquals(2, message.getPackedSfixed32Count());
-    Assert.assertEquals(2, message.getPackedSfixed64Count());
-    Assert.assertEquals(2, message.getPackedFloatCount   ());
-    Assert.assertEquals(2, message.getPackedDoubleCount  ());
-    Assert.assertEquals(2, message.getPackedBoolCount    ());
-    Assert.assertEquals(2, message.getPackedEnumCount   ());
-    Assert.assertEquals(601  , message.getPackedInt32   (0));
-    Assert.assertEquals(602  , message.getPackedInt64   (0));
-    Assert.assertEquals(603  , message.getPackedUint32  (0));
-    Assert.assertEquals(604  , message.getPackedUint64  (0));
-    Assert.assertEquals(605  , message.getPackedSint32  (0));
-    Assert.assertEquals(606  , message.getPackedSint64  (0));
-    Assert.assertEquals(607  , message.getPackedFixed32 (0));
-    Assert.assertEquals(608  , message.getPackedFixed64 (0));
-    Assert.assertEquals(609  , message.getPackedSfixed32(0));
-    Assert.assertEquals(610  , message.getPackedSfixed64(0));
-    Assert.assertEquals(611  , message.getPackedFloat   (0), 0.0);
-    Assert.assertEquals(612  , message.getPackedDouble  (0), 0.0);
-    Assert.assertEquals(true , message.getPackedBool    (0));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
-    Assert.assertEquals(701  , message.getPackedInt32   (1));
-    Assert.assertEquals(702  , message.getPackedInt64   (1));
-    Assert.assertEquals(703  , message.getPackedUint32  (1));
-    Assert.assertEquals(704  , message.getPackedUint64  (1));
-    Assert.assertEquals(705  , message.getPackedSint32  (1));
-    Assert.assertEquals(706  , message.getPackedSint64  (1));
-    Assert.assertEquals(707  , message.getPackedFixed32 (1));
-    Assert.assertEquals(708  , message.getPackedFixed64 (1));
-    Assert.assertEquals(709  , message.getPackedSfixed32(1));
-    Assert.assertEquals(710  , message.getPackedSfixed64(1));
-    Assert.assertEquals(711  , message.getPackedFloat   (1), 0.0);
-    Assert.assertEquals(712  , message.getPackedDouble  (1), 0.0);
-    Assert.assertEquals(false, message.getPackedBool    (1));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
-  }
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all fields of
-   * {@code message} are set to the values assigned by {@code setUnpackedFields}.
-   */
-  public static void assertUnpackedFieldsSet(TestUnpackedTypes message) {
-    Assert.assertEquals(2, message.getUnpackedInt32Count   ());
-    Assert.assertEquals(2, message.getUnpackedInt64Count   ());
-    Assert.assertEquals(2, message.getUnpackedUint32Count  ());
-    Assert.assertEquals(2, message.getUnpackedUint64Count  ());
-    Assert.assertEquals(2, message.getUnpackedSint32Count  ());
-    Assert.assertEquals(2, message.getUnpackedSint64Count  ());
-    Assert.assertEquals(2, message.getUnpackedFixed32Count ());
-    Assert.assertEquals(2, message.getUnpackedFixed64Count ());
-    Assert.assertEquals(2, message.getUnpackedSfixed32Count());
-    Assert.assertEquals(2, message.getUnpackedSfixed64Count());
-    Assert.assertEquals(2, message.getUnpackedFloatCount   ());
-    Assert.assertEquals(2, message.getUnpackedDoubleCount  ());
-    Assert.assertEquals(2, message.getUnpackedBoolCount    ());
-    Assert.assertEquals(2, message.getUnpackedEnumCount   ());
-    Assert.assertEquals(601  , message.getUnpackedInt32   (0));
-    Assert.assertEquals(602  , message.getUnpackedInt64   (0));
-    Assert.assertEquals(603  , message.getUnpackedUint32  (0));
-    Assert.assertEquals(604  , message.getUnpackedUint64  (0));
-    Assert.assertEquals(605  , message.getUnpackedSint32  (0));
-    Assert.assertEquals(606  , message.getUnpackedSint64  (0));
-    Assert.assertEquals(607  , message.getUnpackedFixed32 (0));
-    Assert.assertEquals(608  , message.getUnpackedFixed64 (0));
-    Assert.assertEquals(609  , message.getUnpackedSfixed32(0));
-    Assert.assertEquals(610  , message.getUnpackedSfixed64(0));
-    Assert.assertEquals(611  , message.getUnpackedFloat   (0), 0.0);
-    Assert.assertEquals(612  , message.getUnpackedDouble  (0), 0.0);
-    Assert.assertEquals(true , message.getUnpackedBool    (0));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getUnpackedEnum(0));
-    Assert.assertEquals(701  , message.getUnpackedInt32   (1));
-    Assert.assertEquals(702  , message.getUnpackedInt64   (1));
-    Assert.assertEquals(703  , message.getUnpackedUint32  (1));
-    Assert.assertEquals(704  , message.getUnpackedUint64  (1));
-    Assert.assertEquals(705  , message.getUnpackedSint32  (1));
-    Assert.assertEquals(706  , message.getUnpackedSint64  (1));
-    Assert.assertEquals(707  , message.getUnpackedFixed32 (1));
-    Assert.assertEquals(708  , message.getUnpackedFixed64 (1));
-    Assert.assertEquals(709  , message.getUnpackedSfixed32(1));
-    Assert.assertEquals(710  , message.getUnpackedSfixed64(1));
-    Assert.assertEquals(711  , message.getUnpackedFloat   (1), 0.0);
-    Assert.assertEquals(712  , message.getUnpackedDouble  (1), 0.0);
-    Assert.assertEquals(false, message.getUnpackedBool    (1));
-    Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getUnpackedEnum(1));
-  }
-
-  // ===================================================================
-  // Like above, but for extensions
-
-  // Java gets confused with things like assertEquals(int, Integer):  it can't
-  // decide whether to call assertEquals(int, int) or assertEquals(Object,
-  // Object).  So we define these methods to help it.
-  private static void assertEqualsExactType(int a, int b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(long a, long b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(float a, float b) {
-    Assert.assertEquals(a, b, 0.0);
-  }
-  private static void assertEqualsExactType(double a, double b) {
-    Assert.assertEquals(a, b, 0.0);
-  }
-  private static void assertEqualsExactType(boolean a, boolean b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(String a, String b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(ByteString a, ByteString b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
-                                            TestAllTypes.NestedEnum b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(TestAllTypesLite.NestedEnum a,
-                                            TestAllTypesLite.NestedEnum b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(ForeignEnumLite a,
-                                            ForeignEnumLite b) {
-    Assert.assertEquals(a, b);
-  }
-  private static void assertEqualsExactType(ImportEnumLite a,
-                                            ImportEnumLite b) {
-    Assert.assertEquals(a, b);
-  }
-
-  /**
-   * Get an unmodifiable {@link ExtensionRegistry} containing all the
-   * extensions of {@code TestAllExtensions}.
-   */
-  public static ExtensionRegistry getExtensionRegistry() {
-    ExtensionRegistry registry = ExtensionRegistry.newInstance();
-    registerAllExtensions(registry);
-    return registry.getUnmodifiable();
-  }
-
-  public static ExtensionRegistryLite getExtensionRegistryLite() {
-    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
-    registerAllExtensionsLite(registry);
-    return registry.getUnmodifiable();
-  }
-
-  /**
-   * Register all of {@code TestAllExtensions}'s extensions with the
-   * given {@link ExtensionRegistry}.
-   */
-  public static void registerAllExtensions(ExtensionRegistry registry) {
-    UnittestProto.registerAllExtensions(registry);
-    registerAllExtensionsLite(registry);
-  }
-
-  public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
-    UnittestLite.registerAllExtensions(registry);
-  }
-
-  /**
-   * Set every field of {@code message} to the values expected by
-   * {@code assertAllExtensionsSet()}.
-   */
-  public static void setAllExtensions(TestAllExtensions.Builder message) {
-    message.setExtension(optionalInt32Extension   , 101);
-    message.setExtension(optionalInt64Extension   , 102L);
-    message.setExtension(optionalUint32Extension  , 103);
-    message.setExtension(optionalUint64Extension  , 104L);
-    message.setExtension(optionalSint32Extension  , 105);
-    message.setExtension(optionalSint64Extension  , 106L);
-    message.setExtension(optionalFixed32Extension , 107);
-    message.setExtension(optionalFixed64Extension , 108L);
-    message.setExtension(optionalSfixed32Extension, 109);
-    message.setExtension(optionalSfixed64Extension, 110L);
-    message.setExtension(optionalFloatExtension   , 111F);
-    message.setExtension(optionalDoubleExtension  , 112D);
-    message.setExtension(optionalBoolExtension    , true);
-    message.setExtension(optionalStringExtension  , "115");
-    message.setExtension(optionalBytesExtension   , toBytes("116"));
-
-    message.setExtension(optionalGroupExtension,
-      OptionalGroup_extension.newBuilder().setA(117).build());
-    message.setExtension(optionalNestedMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
-    message.setExtension(optionalForeignMessageExtension,
-      ForeignMessage.newBuilder().setC(119).build());
-    message.setExtension(optionalImportMessageExtension,
-      ImportMessage.newBuilder().setD(120).build());
-    message.setExtension(optionalPublicImportMessageExtension,
-      PublicImportMessage.newBuilder().setE(126).build());
-    message.setExtension(optionalLazyMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(127).build());
-
-    message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
-    message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
-    message.setExtension(optionalImportEnumExtension, ImportEnum.IMPORT_BAZ);
-
-    message.setExtension(optionalStringPieceExtension, "124");
-    message.setExtension(optionalCordExtension, "125");
-
-    // -----------------------------------------------------------------
-
-    message.addExtension(repeatedInt32Extension   , 201);
-    message.addExtension(repeatedInt64Extension   , 202L);
-    message.addExtension(repeatedUint32Extension  , 203);
-    message.addExtension(repeatedUint64Extension  , 204L);
-    message.addExtension(repeatedSint32Extension  , 205);
-    message.addExtension(repeatedSint64Extension  , 206L);
-    message.addExtension(repeatedFixed32Extension , 207);
-    message.addExtension(repeatedFixed64Extension , 208L);
-    message.addExtension(repeatedSfixed32Extension, 209);
-    message.addExtension(repeatedSfixed64Extension, 210L);
-    message.addExtension(repeatedFloatExtension   , 211F);
-    message.addExtension(repeatedDoubleExtension  , 212D);
-    message.addExtension(repeatedBoolExtension    , true);
-    message.addExtension(repeatedStringExtension  , "215");
-    message.addExtension(repeatedBytesExtension   , toBytes("216"));
-
-    message.addExtension(repeatedGroupExtension,
-      RepeatedGroup_extension.newBuilder().setA(217).build());
-    message.addExtension(repeatedNestedMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
-    message.addExtension(repeatedForeignMessageExtension,
-      ForeignMessage.newBuilder().setC(219).build());
-    message.addExtension(repeatedImportMessageExtension,
-      ImportMessage.newBuilder().setD(220).build());
-    message.addExtension(repeatedLazyMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(227).build());
-
-    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR);
-    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR);
-    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAR);
-
-    message.addExtension(repeatedStringPieceExtension, "224");
-    message.addExtension(repeatedCordExtension, "225");
-
-    // Add a second one of each field.
-    message.addExtension(repeatedInt32Extension   , 301);
-    message.addExtension(repeatedInt64Extension   , 302L);
-    message.addExtension(repeatedUint32Extension  , 303);
-    message.addExtension(repeatedUint64Extension  , 304L);
-    message.addExtension(repeatedSint32Extension  , 305);
-    message.addExtension(repeatedSint64Extension  , 306L);
-    message.addExtension(repeatedFixed32Extension , 307);
-    message.addExtension(repeatedFixed64Extension , 308L);
-    message.addExtension(repeatedSfixed32Extension, 309);
-    message.addExtension(repeatedSfixed64Extension, 310L);
-    message.addExtension(repeatedFloatExtension   , 311F);
-    message.addExtension(repeatedDoubleExtension  , 312D);
-    message.addExtension(repeatedBoolExtension    , false);
-    message.addExtension(repeatedStringExtension  , "315");
-    message.addExtension(repeatedBytesExtension   , toBytes("316"));
-
-    message.addExtension(repeatedGroupExtension,
-      RepeatedGroup_extension.newBuilder().setA(317).build());
-    message.addExtension(repeatedNestedMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
-    message.addExtension(repeatedForeignMessageExtension,
-      ForeignMessage.newBuilder().setC(319).build());
-    message.addExtension(repeatedImportMessageExtension,
-      ImportMessage.newBuilder().setD(320).build());
-    message.addExtension(repeatedLazyMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(327).build());
-
-    message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
-    message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
-    message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAZ);
-
-    message.addExtension(repeatedStringPieceExtension, "324");
-    message.addExtension(repeatedCordExtension, "325");
-
-    // -----------------------------------------------------------------
-
-    message.setExtension(defaultInt32Extension   , 401);
-    message.setExtension(defaultInt64Extension   , 402L);
-    message.setExtension(defaultUint32Extension  , 403);
-    message.setExtension(defaultUint64Extension  , 404L);
-    message.setExtension(defaultSint32Extension  , 405);
-    message.setExtension(defaultSint64Extension  , 406L);
-    message.setExtension(defaultFixed32Extension , 407);
-    message.setExtension(defaultFixed64Extension , 408L);
-    message.setExtension(defaultSfixed32Extension, 409);
-    message.setExtension(defaultSfixed64Extension, 410L);
-    message.setExtension(defaultFloatExtension   , 411F);
-    message.setExtension(defaultDoubleExtension  , 412D);
-    message.setExtension(defaultBoolExtension    , false);
-    message.setExtension(defaultStringExtension  , "415");
-    message.setExtension(defaultBytesExtension   , toBytes("416"));
-
-    message.setExtension(defaultNestedEnumExtension, TestAllTypes.NestedEnum.FOO);
-    message.setExtension(defaultForeignEnumExtension, ForeignEnum.FOREIGN_FOO);
-    message.setExtension(defaultImportEnumExtension, ImportEnum.IMPORT_FOO);
-
-    message.setExtension(defaultStringPieceExtension, "424");
-    message.setExtension(defaultCordExtension, "425");
-
-    message.setExtension(oneofUint32Extension, 601);
-    message.setExtension(oneofNestedMessageExtension,
-      TestAllTypes.NestedMessage.newBuilder().setBb(602).build());
-    message.setExtension(oneofStringExtension, "603");
-    message.setExtension(oneofBytesExtension, toBytes("604"));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Modify the repeated extensions of {@code message} to contain the values
-   * expected by {@code assertRepeatedExtensionsModified()}.
-   */
-  public static void modifyRepeatedExtensions(
-      TestAllExtensions.Builder message) {
-    message.setExtension(repeatedInt32Extension   , 1, 501);
-    message.setExtension(repeatedInt64Extension   , 1, 502L);
-    message.setExtension(repeatedUint32Extension  , 1, 503);
-    message.setExtension(repeatedUint64Extension  , 1, 504L);
-    message.setExtension(repeatedSint32Extension  , 1, 505);
-    message.setExtension(repeatedSint64Extension  , 1, 506L);
-    message.setExtension(repeatedFixed32Extension , 1, 507);
-    message.setExtension(repeatedFixed64Extension , 1, 508L);
-    message.setExtension(repeatedSfixed32Extension, 1, 509);
-    message.setExtension(repeatedSfixed64Extension, 1, 510L);
-    message.setExtension(repeatedFloatExtension   , 1, 511F);
-    message.setExtension(repeatedDoubleExtension  , 1, 512D);
-    message.setExtension(repeatedBoolExtension    , 1, true);
-    message.setExtension(repeatedStringExtension  , 1, "515");
-    message.setExtension(repeatedBytesExtension   , 1, toBytes("516"));
-
-    message.setExtension(repeatedGroupExtension, 1,
-      RepeatedGroup_extension.newBuilder().setA(517).build());
-    message.setExtension(repeatedNestedMessageExtension, 1,
-      TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
-    message.setExtension(repeatedForeignMessageExtension, 1,
-      ForeignMessage.newBuilder().setC(519).build());
-    message.setExtension(repeatedImportMessageExtension, 1,
-      ImportMessage.newBuilder().setD(520).build());
-    message.setExtension(repeatedLazyMessageExtension, 1,
-      TestAllTypes.NestedMessage.newBuilder().setBb(527).build());
-
-    message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO);
-    message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO);
-    message.setExtension(repeatedImportEnumExtension , 1, ImportEnum.IMPORT_FOO);
-
-    message.setExtension(repeatedStringPieceExtension, 1, "524");
-    message.setExtension(repeatedCordExtension, 1, "525");
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are set to the values assigned by {@code setAllExtensions}.
-   */
-  public static void assertAllExtensionsSet(
-      TestAllExtensionsOrBuilder message) {
-    Assert.assertTrue(message.hasExtension(optionalInt32Extension   ));
-    Assert.assertTrue(message.hasExtension(optionalInt64Extension   ));
-    Assert.assertTrue(message.hasExtension(optionalUint32Extension  ));
-    Assert.assertTrue(message.hasExtension(optionalUint64Extension  ));
-    Assert.assertTrue(message.hasExtension(optionalSint32Extension  ));
-    Assert.assertTrue(message.hasExtension(optionalSint64Extension  ));
-    Assert.assertTrue(message.hasExtension(optionalFixed32Extension ));
-    Assert.assertTrue(message.hasExtension(optionalFixed64Extension ));
-    Assert.assertTrue(message.hasExtension(optionalSfixed32Extension));
-    Assert.assertTrue(message.hasExtension(optionalSfixed64Extension));
-    Assert.assertTrue(message.hasExtension(optionalFloatExtension   ));
-    Assert.assertTrue(message.hasExtension(optionalDoubleExtension  ));
-    Assert.assertTrue(message.hasExtension(optionalBoolExtension    ));
-    Assert.assertTrue(message.hasExtension(optionalStringExtension  ));
-    Assert.assertTrue(message.hasExtension(optionalBytesExtension   ));
-
-    Assert.assertTrue(message.hasExtension(optionalGroupExtension         ));
-    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtension ));
-    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtension));
-    Assert.assertTrue(message.hasExtension(optionalImportMessageExtension ));
-
-    Assert.assertTrue(message.getExtension(optionalGroupExtension         ).hasA());
-    Assert.assertTrue(message.getExtension(optionalNestedMessageExtension ).hasBb());
-    Assert.assertTrue(message.getExtension(optionalForeignMessageExtension).hasC());
-    Assert.assertTrue(message.getExtension(optionalImportMessageExtension ).hasD());
-
-    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtension ));
-    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtension));
-    Assert.assertTrue(message.hasExtension(optionalImportEnumExtension ));
-
-    Assert.assertTrue(message.hasExtension(optionalStringPieceExtension));
-    Assert.assertTrue(message.hasExtension(optionalCordExtension));
-
-    assertEqualsExactType(101  , message.getExtension(optionalInt32Extension   ));
-    assertEqualsExactType(102L , message.getExtension(optionalInt64Extension   ));
-    assertEqualsExactType(103  , message.getExtension(optionalUint32Extension  ));
-    assertEqualsExactType(104L , message.getExtension(optionalUint64Extension  ));
-    assertEqualsExactType(105  , message.getExtension(optionalSint32Extension  ));
-    assertEqualsExactType(106L , message.getExtension(optionalSint64Extension  ));
-    assertEqualsExactType(107  , message.getExtension(optionalFixed32Extension ));
-    assertEqualsExactType(108L , message.getExtension(optionalFixed64Extension ));
-    assertEqualsExactType(109  , message.getExtension(optionalSfixed32Extension));
-    assertEqualsExactType(110L , message.getExtension(optionalSfixed64Extension));
-    assertEqualsExactType(111F , message.getExtension(optionalFloatExtension   ));
-    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtension  ));
-    assertEqualsExactType(true , message.getExtension(optionalBoolExtension    ));
-    assertEqualsExactType("115", message.getExtension(optionalStringExtension  ));
-    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension));
-
-    assertEqualsExactType(117, message.getExtension(optionalGroupExtension              ).getA());
-    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension      ).getBb());
-    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension     ).getC());
-    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension      ).getD());
-    assertEqualsExactType(126, message.getExtension(optionalPublicImportMessageExtension).getE());
-    assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtension        ).getBb());
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
-      message.getExtension(optionalNestedEnumExtension));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
-      message.getExtension(optionalForeignEnumExtension));
-    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
-      message.getExtension(optionalImportEnumExtension));
-
-    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtension));
-    assertEqualsExactType("125", message.getExtension(optionalCordExtension));
-
-    // -----------------------------------------------------------------
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
-
-    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
-    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
-    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
-    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
-    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
-    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
-    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
-    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
-    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
-    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
-    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
-    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
-    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
-    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
-
-    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
-    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
-    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
-    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
-    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
-      message.getExtension(repeatedNestedEnumExtension, 0));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
-      message.getExtension(repeatedForeignEnumExtension, 0));
-    assertEqualsExactType(ImportEnum.IMPORT_BAR,
-      message.getExtension(repeatedImportEnumExtension, 0));
-
-    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
-    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
-
-    assertEqualsExactType(301  , message.getExtension(repeatedInt32Extension   , 1));
-    assertEqualsExactType(302L , message.getExtension(repeatedInt64Extension   , 1));
-    assertEqualsExactType(303  , message.getExtension(repeatedUint32Extension  , 1));
-    assertEqualsExactType(304L , message.getExtension(repeatedUint64Extension  , 1));
-    assertEqualsExactType(305  , message.getExtension(repeatedSint32Extension  , 1));
-    assertEqualsExactType(306L , message.getExtension(repeatedSint64Extension  , 1));
-    assertEqualsExactType(307  , message.getExtension(repeatedFixed32Extension , 1));
-    assertEqualsExactType(308L , message.getExtension(repeatedFixed64Extension , 1));
-    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32Extension, 1));
-    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64Extension, 1));
-    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtension   , 1));
-    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtension  , 1));
-    assertEqualsExactType(false, message.getExtension(repeatedBoolExtension    , 1));
-    assertEqualsExactType("315", message.getExtension(repeatedStringExtension  , 1));
-    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtension, 1));
-
-    assertEqualsExactType(317, message.getExtension(repeatedGroupExtension         , 1).getA());
-    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
-    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC());
-    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD());
-    assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
-      message.getExtension(repeatedNestedEnumExtension, 1));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
-      message.getExtension(repeatedForeignEnumExtension, 1));
-    assertEqualsExactType(ImportEnum.IMPORT_BAZ,
-      message.getExtension(repeatedImportEnumExtension, 1));
-
-    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtension, 1));
-    assertEqualsExactType("325", message.getExtension(repeatedCordExtension, 1));
-
-    // -----------------------------------------------------------------
-
-    Assert.assertTrue(message.hasExtension(defaultInt32Extension   ));
-    Assert.assertTrue(message.hasExtension(defaultInt64Extension   ));
-    Assert.assertTrue(message.hasExtension(defaultUint32Extension  ));
-    Assert.assertTrue(message.hasExtension(defaultUint64Extension  ));
-    Assert.assertTrue(message.hasExtension(defaultSint32Extension  ));
-    Assert.assertTrue(message.hasExtension(defaultSint64Extension  ));
-    Assert.assertTrue(message.hasExtension(defaultFixed32Extension ));
-    Assert.assertTrue(message.hasExtension(defaultFixed64Extension ));
-    Assert.assertTrue(message.hasExtension(defaultSfixed32Extension));
-    Assert.assertTrue(message.hasExtension(defaultSfixed64Extension));
-    Assert.assertTrue(message.hasExtension(defaultFloatExtension   ));
-    Assert.assertTrue(message.hasExtension(defaultDoubleExtension  ));
-    Assert.assertTrue(message.hasExtension(defaultBoolExtension    ));
-    Assert.assertTrue(message.hasExtension(defaultStringExtension  ));
-    Assert.assertTrue(message.hasExtension(defaultBytesExtension   ));
-
-    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtension ));
-    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtension));
-    Assert.assertTrue(message.hasExtension(defaultImportEnumExtension ));
-
-    Assert.assertTrue(message.hasExtension(defaultStringPieceExtension));
-    Assert.assertTrue(message.hasExtension(defaultCordExtension));
-
-    assertEqualsExactType(401  , message.getExtension(defaultInt32Extension   ));
-    assertEqualsExactType(402L , message.getExtension(defaultInt64Extension   ));
-    assertEqualsExactType(403  , message.getExtension(defaultUint32Extension  ));
-    assertEqualsExactType(404L , message.getExtension(defaultUint64Extension  ));
-    assertEqualsExactType(405  , message.getExtension(defaultSint32Extension  ));
-    assertEqualsExactType(406L , message.getExtension(defaultSint64Extension  ));
-    assertEqualsExactType(407  , message.getExtension(defaultFixed32Extension ));
-    assertEqualsExactType(408L , message.getExtension(defaultFixed64Extension ));
-    assertEqualsExactType(409  , message.getExtension(defaultSfixed32Extension));
-    assertEqualsExactType(410L , message.getExtension(defaultSfixed64Extension));
-    assertEqualsExactType(411F , message.getExtension(defaultFloatExtension   ));
-    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtension  ));
-    assertEqualsExactType(false, message.getExtension(defaultBoolExtension    ));
-    assertEqualsExactType("415", message.getExtension(defaultStringExtension  ));
-    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtension));
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
-      message.getExtension(defaultNestedEnumExtension ));
-    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
-      message.getExtension(defaultForeignEnumExtension));
-    assertEqualsExactType(ImportEnum.IMPORT_FOO,
-      message.getExtension(defaultImportEnumExtension));
-
-    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
-    assertEqualsExactType("425", message.getExtension(defaultCordExtension));
-
-    Assert.assertTrue(message.hasExtension(oneofBytesExtension));
-
-    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtension));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are cleared, and that getting the extensions returns their
-   * default values.
-   */
-  public static void assertExtensionsClear(TestAllExtensionsOrBuilder message) {
-    // hasBlah() should initially be false for all optional fields.
-    Assert.assertFalse(message.hasExtension(optionalInt32Extension   ));
-    Assert.assertFalse(message.hasExtension(optionalInt64Extension   ));
-    Assert.assertFalse(message.hasExtension(optionalUint32Extension  ));
-    Assert.assertFalse(message.hasExtension(optionalUint64Extension  ));
-    Assert.assertFalse(message.hasExtension(optionalSint32Extension  ));
-    Assert.assertFalse(message.hasExtension(optionalSint64Extension  ));
-    Assert.assertFalse(message.hasExtension(optionalFixed32Extension ));
-    Assert.assertFalse(message.hasExtension(optionalFixed64Extension ));
-    Assert.assertFalse(message.hasExtension(optionalSfixed32Extension));
-    Assert.assertFalse(message.hasExtension(optionalSfixed64Extension));
-    Assert.assertFalse(message.hasExtension(optionalFloatExtension   ));
-    Assert.assertFalse(message.hasExtension(optionalDoubleExtension  ));
-    Assert.assertFalse(message.hasExtension(optionalBoolExtension    ));
-    Assert.assertFalse(message.hasExtension(optionalStringExtension  ));
-    Assert.assertFalse(message.hasExtension(optionalBytesExtension   ));
-
-    Assert.assertFalse(message.hasExtension(optionalGroupExtension         ));
-    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtension ));
-    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtension));
-    Assert.assertFalse(message.hasExtension(optionalImportMessageExtension ));
-
-    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtension ));
-    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtension));
-    Assert.assertFalse(message.hasExtension(optionalImportEnumExtension ));
-
-    Assert.assertFalse(message.hasExtension(optionalStringPieceExtension));
-    Assert.assertFalse(message.hasExtension(optionalCordExtension));
-
-    // Optional fields without defaults are set to zero or something like it.
-    assertEqualsExactType(0    , message.getExtension(optionalInt32Extension   ));
-    assertEqualsExactType(0L   , message.getExtension(optionalInt64Extension   ));
-    assertEqualsExactType(0    , message.getExtension(optionalUint32Extension  ));
-    assertEqualsExactType(0L   , message.getExtension(optionalUint64Extension  ));
-    assertEqualsExactType(0    , message.getExtension(optionalSint32Extension  ));
-    assertEqualsExactType(0L   , message.getExtension(optionalSint64Extension  ));
-    assertEqualsExactType(0    , message.getExtension(optionalFixed32Extension ));
-    assertEqualsExactType(0L   , message.getExtension(optionalFixed64Extension ));
-    assertEqualsExactType(0    , message.getExtension(optionalSfixed32Extension));
-    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64Extension));
-    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtension   ));
-    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtension  ));
-    assertEqualsExactType(false, message.getExtension(optionalBoolExtension    ));
-    assertEqualsExactType(""   , message.getExtension(optionalStringExtension  ));
-    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtension));
-
-    // Embedded messages should also be clear.
-    Assert.assertFalse(message.getExtension(optionalGroupExtension         ).hasA());
-    Assert.assertFalse(message.getExtension(optionalNestedMessageExtension ).hasBb());
-    Assert.assertFalse(message.getExtension(optionalForeignMessageExtension).hasC());
-    Assert.assertFalse(message.getExtension(optionalImportMessageExtension ).hasD());
-
-    assertEqualsExactType(0, message.getExtension(optionalGroupExtension         ).getA());
-    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtension ).getBb());
-    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtension).getC());
-    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtension ).getD());
-
-    // Enums without defaults are set to the first value in the enum.
-    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
-      message.getExtension(optionalNestedEnumExtension ));
-    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
-      message.getExtension(optionalForeignEnumExtension));
-    assertEqualsExactType(ImportEnum.IMPORT_FOO,
-      message.getExtension(optionalImportEnumExtension));
-
-    assertEqualsExactType("", message.getExtension(optionalStringPieceExtension));
-    assertEqualsExactType("", message.getExtension(optionalCordExtension));
-
-    // Repeated fields are empty.
-    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32Extension   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64Extension   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32Extension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64Extension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32Extension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64Extension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32Extension ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64Extension ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32Extension));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64Extension));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtension   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtension    ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtension  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtension   ));
-
-    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtension         ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtension   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension    ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension    ));
-
-    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtension));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtension));
-
-    // Repeated fields are empty via getExtension().size().
-    Assert.assertEquals(0, message.getExtension(repeatedInt32Extension   ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedInt64Extension   ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedUint32Extension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedUint64Extension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedSint32Extension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedSint64Extension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedFixed32Extension ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedFixed64Extension ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedSfixed32Extension).size());
-    Assert.assertEquals(0, message.getExtension(repeatedSfixed64Extension).size());
-    Assert.assertEquals(0, message.getExtension(repeatedFloatExtension   ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedDoubleExtension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedBoolExtension    ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedStringExtension  ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedBytesExtension   ).size());
-
-    Assert.assertEquals(0, message.getExtension(repeatedGroupExtension         ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedNestedMessageExtension ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedForeignMessageExtension).size());
-    Assert.assertEquals(0, message.getExtension(repeatedImportMessageExtension ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedLazyMessageExtension   ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedNestedEnumExtension    ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedForeignEnumExtension   ).size());
-    Assert.assertEquals(0, message.getExtension(repeatedImportEnumExtension    ).size());
-
-    Assert.assertEquals(0, message.getExtension(repeatedStringPieceExtension).size());
-    Assert.assertEquals(0, message.getExtension(repeatedCordExtension).size());
-
-    // hasBlah() should also be false for all default fields.
-    Assert.assertFalse(message.hasExtension(defaultInt32Extension   ));
-    Assert.assertFalse(message.hasExtension(defaultInt64Extension   ));
-    Assert.assertFalse(message.hasExtension(defaultUint32Extension  ));
-    Assert.assertFalse(message.hasExtension(defaultUint64Extension  ));
-    Assert.assertFalse(message.hasExtension(defaultSint32Extension  ));
-    Assert.assertFalse(message.hasExtension(defaultSint64Extension  ));
-    Assert.assertFalse(message.hasExtension(defaultFixed32Extension ));
-    Assert.assertFalse(message.hasExtension(defaultFixed64Extension ));
-    Assert.assertFalse(message.hasExtension(defaultSfixed32Extension));
-    Assert.assertFalse(message.hasExtension(defaultSfixed64Extension));
-    Assert.assertFalse(message.hasExtension(defaultFloatExtension   ));
-    Assert.assertFalse(message.hasExtension(defaultDoubleExtension  ));
-    Assert.assertFalse(message.hasExtension(defaultBoolExtension    ));
-    Assert.assertFalse(message.hasExtension(defaultStringExtension  ));
-    Assert.assertFalse(message.hasExtension(defaultBytesExtension   ));
-
-    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtension ));
-    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtension));
-    Assert.assertFalse(message.hasExtension(defaultImportEnumExtension ));
-
-    Assert.assertFalse(message.hasExtension(defaultStringPieceExtension));
-    Assert.assertFalse(message.hasExtension(defaultCordExtension));
-
-    // Fields with defaults have their default values (duh).
-    assertEqualsExactType( 41    , message.getExtension(defaultInt32Extension   ));
-    assertEqualsExactType( 42L   , message.getExtension(defaultInt64Extension   ));
-    assertEqualsExactType( 43    , message.getExtension(defaultUint32Extension  ));
-    assertEqualsExactType( 44L   , message.getExtension(defaultUint64Extension  ));
-    assertEqualsExactType(-45    , message.getExtension(defaultSint32Extension  ));
-    assertEqualsExactType( 46L   , message.getExtension(defaultSint64Extension  ));
-    assertEqualsExactType( 47    , message.getExtension(defaultFixed32Extension ));
-    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64Extension ));
-    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32Extension));
-    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64Extension));
-    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtension   ));
-    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtension  ));
-    assertEqualsExactType(true   , message.getExtension(defaultBoolExtension    ));
-    assertEqualsExactType("hello", message.getExtension(defaultStringExtension  ));
-    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtension));
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
-      message.getExtension(defaultNestedEnumExtension ));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
-      message.getExtension(defaultForeignEnumExtension));
-    assertEqualsExactType(ImportEnum.IMPORT_BAR,
-      message.getExtension(defaultImportEnumExtension));
-
-    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
-    assertEqualsExactType("123", message.getExtension(defaultCordExtension));
-
-    Assert.assertFalse(message.hasExtension(oneofUint32Extension));
-    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtension));
-    Assert.assertFalse(message.hasExtension(oneofStringExtension));
-    Assert.assertFalse(message.hasExtension(oneofBytesExtension));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are set to the values assigned by {@code setAllExtensions}
-   * followed by {@code modifyRepeatedExtensions}.
-   */
-  public static void assertRepeatedExtensionsModified(
-      TestAllExtensionsOrBuilder message) {
-    // ModifyRepeatedFields only sets the second repeated element of each
-    // field.  In addition to verifying this, we also verify that the first
-    // element and size were *not* modified.
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension   ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension         ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension    ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
-
-    assertEqualsExactType(201  , message.getExtension(repeatedInt32Extension   , 0));
-    assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension   , 0));
-    assertEqualsExactType(203  , message.getExtension(repeatedUint32Extension  , 0));
-    assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension  , 0));
-    assertEqualsExactType(205  , message.getExtension(repeatedSint32Extension  , 0));
-    assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension  , 0));
-    assertEqualsExactType(207  , message.getExtension(repeatedFixed32Extension , 0));
-    assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
-    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32Extension, 0));
-    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
-    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension   , 0));
-    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension  , 0));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 0));
-    assertEqualsExactType("215", message.getExtension(repeatedStringExtension  , 0));
-    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
-
-    assertEqualsExactType(217, message.getExtension(repeatedGroupExtension         , 0).getA());
-    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
-    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
-    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
-    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtension   , 0).getBb());
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
-      message.getExtension(repeatedNestedEnumExtension, 0));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
-      message.getExtension(repeatedForeignEnumExtension, 0));
-    assertEqualsExactType(ImportEnum.IMPORT_BAR,
-      message.getExtension(repeatedImportEnumExtension, 0));
-
-    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
-    assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
-
-    // Actually verify the second (modified) elements now.
-    assertEqualsExactType(501  , message.getExtension(repeatedInt32Extension   , 1));
-    assertEqualsExactType(502L , message.getExtension(repeatedInt64Extension   , 1));
-    assertEqualsExactType(503  , message.getExtension(repeatedUint32Extension  , 1));
-    assertEqualsExactType(504L , message.getExtension(repeatedUint64Extension  , 1));
-    assertEqualsExactType(505  , message.getExtension(repeatedSint32Extension  , 1));
-    assertEqualsExactType(506L , message.getExtension(repeatedSint64Extension  , 1));
-    assertEqualsExactType(507  , message.getExtension(repeatedFixed32Extension , 1));
-    assertEqualsExactType(508L , message.getExtension(repeatedFixed64Extension , 1));
-    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32Extension, 1));
-    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64Extension, 1));
-    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtension   , 1));
-    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtension  , 1));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtension    , 1));
-    assertEqualsExactType("515", message.getExtension(repeatedStringExtension  , 1));
-    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtension, 1));
-
-    assertEqualsExactType(517, message.getExtension(repeatedGroupExtension         , 1).getA());
-    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
-    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC());
-    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD());
-    assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtension   , 1).getBb());
-
-    assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
-      message.getExtension(repeatedNestedEnumExtension, 1));
-    assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
-      message.getExtension(repeatedForeignEnumExtension, 1));
-    assertEqualsExactType(ImportEnum.IMPORT_FOO,
-      message.getExtension(repeatedImportEnumExtension, 1));
-
-    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtension, 1));
-    assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1));
-  }
-
-  public static void setPackedExtensions(TestPackedExtensions.Builder message) {
-    message.addExtension(packedInt32Extension   , 601);
-    message.addExtension(packedInt64Extension   , 602L);
-    message.addExtension(packedUint32Extension  , 603);
-    message.addExtension(packedUint64Extension  , 604L);
-    message.addExtension(packedSint32Extension  , 605);
-    message.addExtension(packedSint64Extension  , 606L);
-    message.addExtension(packedFixed32Extension , 607);
-    message.addExtension(packedFixed64Extension , 608L);
-    message.addExtension(packedSfixed32Extension, 609);
-    message.addExtension(packedSfixed64Extension, 610L);
-    message.addExtension(packedFloatExtension   , 611F);
-    message.addExtension(packedDoubleExtension  , 612D);
-    message.addExtension(packedBoolExtension    , true);
-    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAR);
-    // Add a second one of each field.
-    message.addExtension(packedInt32Extension   , 701);
-    message.addExtension(packedInt64Extension   , 702L);
-    message.addExtension(packedUint32Extension  , 703);
-    message.addExtension(packedUint64Extension  , 704L);
-    message.addExtension(packedSint32Extension  , 705);
-    message.addExtension(packedSint64Extension  , 706L);
-    message.addExtension(packedFixed32Extension , 707);
-    message.addExtension(packedFixed64Extension , 708L);
-    message.addExtension(packedSfixed32Extension, 709);
-    message.addExtension(packedSfixed64Extension, 710L);
-    message.addExtension(packedFloatExtension   , 711F);
-    message.addExtension(packedDoubleExtension  , 712D);
-    message.addExtension(packedBoolExtension    , false);
-    message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAZ);
-  }
-
-  public static void assertPackedExtensionsSet(TestPackedExtensions message) {
-    Assert.assertEquals(2, message.getExtensionCount(packedInt32Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedInt64Extension   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedUint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedUint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSint32Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSint64Extension  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedFixed32Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(packedFixed64Extension ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32Extension));
-    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64Extension));
-    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtension   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtension  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtension    ));
-    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtension));
-    assertEqualsExactType(601  , message.getExtension(packedInt32Extension   , 0));
-    assertEqualsExactType(602L , message.getExtension(packedInt64Extension   , 0));
-    assertEqualsExactType(603  , message.getExtension(packedUint32Extension  , 0));
-    assertEqualsExactType(604L , message.getExtension(packedUint64Extension  , 0));
-    assertEqualsExactType(605  , message.getExtension(packedSint32Extension  , 0));
-    assertEqualsExactType(606L , message.getExtension(packedSint64Extension  , 0));
-    assertEqualsExactType(607  , message.getExtension(packedFixed32Extension , 0));
-    assertEqualsExactType(608L , message.getExtension(packedFixed64Extension , 0));
-    assertEqualsExactType(609  , message.getExtension(packedSfixed32Extension, 0));
-    assertEqualsExactType(610L , message.getExtension(packedSfixed64Extension, 0));
-    assertEqualsExactType(611F , message.getExtension(packedFloatExtension   , 0));
-    assertEqualsExactType(612D , message.getExtension(packedDoubleExtension  , 0));
-    assertEqualsExactType(true , message.getExtension(packedBoolExtension    , 0));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
-                          message.getExtension(packedEnumExtension, 0));
-    assertEqualsExactType(701  , message.getExtension(packedInt32Extension   , 1));
-    assertEqualsExactType(702L , message.getExtension(packedInt64Extension   , 1));
-    assertEqualsExactType(703  , message.getExtension(packedUint32Extension  , 1));
-    assertEqualsExactType(704L , message.getExtension(packedUint64Extension  , 1));
-    assertEqualsExactType(705  , message.getExtension(packedSint32Extension  , 1));
-    assertEqualsExactType(706L , message.getExtension(packedSint64Extension  , 1));
-    assertEqualsExactType(707  , message.getExtension(packedFixed32Extension , 1));
-    assertEqualsExactType(708L , message.getExtension(packedFixed64Extension , 1));
-    assertEqualsExactType(709  , message.getExtension(packedSfixed32Extension, 1));
-    assertEqualsExactType(710L , message.getExtension(packedSfixed64Extension, 1));
-    assertEqualsExactType(711F , message.getExtension(packedFloatExtension   , 1));
-    assertEqualsExactType(712D , message.getExtension(packedDoubleExtension  , 1));
-    assertEqualsExactType(false, message.getExtension(packedBoolExtension    , 1));
-    assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
-                          message.getExtension(packedEnumExtension, 1));
-  }
-
-  // ===================================================================
-  // Lite extensions
-
-  /**
-   * Set every field of {@code message} to the values expected by
-   * {@code assertAllExtensionsSet()}.
-   */
-  public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
-    message.setExtension(optionalInt32ExtensionLite   , 101);
-    message.setExtension(optionalInt64ExtensionLite   , 102L);
-    message.setExtension(optionalUint32ExtensionLite  , 103);
-    message.setExtension(optionalUint64ExtensionLite  , 104L);
-    message.setExtension(optionalSint32ExtensionLite  , 105);
-    message.setExtension(optionalSint64ExtensionLite  , 106L);
-    message.setExtension(optionalFixed32ExtensionLite , 107);
-    message.setExtension(optionalFixed64ExtensionLite , 108L);
-    message.setExtension(optionalSfixed32ExtensionLite, 109);
-    message.setExtension(optionalSfixed64ExtensionLite, 110L);
-    message.setExtension(optionalFloatExtensionLite   , 111F);
-    message.setExtension(optionalDoubleExtensionLite  , 112D);
-    message.setExtension(optionalBoolExtensionLite    , true);
-    message.setExtension(optionalStringExtensionLite  , "115");
-    message.setExtension(optionalBytesExtensionLite   , toBytes("116"));
-
-    message.setExtension(optionalGroupExtensionLite,
-      OptionalGroup_extension_lite.newBuilder().setA(117).build());
-    message.setExtension(optionalNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
-    message.setExtension(optionalForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(119).build());
-    message.setExtension(optionalImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(120).build());
-    message.setExtension(optionalPublicImportMessageExtensionLite,
-      PublicImportMessageLite.newBuilder().setE(126).build());
-    message.setExtension(optionalLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
-
-    message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
-    message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-    message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
-    message.setExtension(optionalStringPieceExtensionLite, "124");
-    message.setExtension(optionalCordExtensionLite, "125");
-
-    // -----------------------------------------------------------------
-
-    message.addExtension(repeatedInt32ExtensionLite   , 201);
-    message.addExtension(repeatedInt64ExtensionLite   , 202L);
-    message.addExtension(repeatedUint32ExtensionLite  , 203);
-    message.addExtension(repeatedUint64ExtensionLite  , 204L);
-    message.addExtension(repeatedSint32ExtensionLite  , 205);
-    message.addExtension(repeatedSint64ExtensionLite  , 206L);
-    message.addExtension(repeatedFixed32ExtensionLite , 207);
-    message.addExtension(repeatedFixed64ExtensionLite , 208L);
-    message.addExtension(repeatedSfixed32ExtensionLite, 209);
-    message.addExtension(repeatedSfixed64ExtensionLite, 210L);
-    message.addExtension(repeatedFloatExtensionLite   , 211F);
-    message.addExtension(repeatedDoubleExtensionLite  , 212D);
-    message.addExtension(repeatedBoolExtensionLite    , true);
-    message.addExtension(repeatedStringExtensionLite  , "215");
-    message.addExtension(repeatedBytesExtensionLite   , toBytes("216"));
-
-    message.addExtension(repeatedGroupExtensionLite,
-      RepeatedGroup_extension_lite.newBuilder().setA(217).build());
-    message.addExtension(repeatedNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
-    message.addExtension(repeatedForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(219).build());
-    message.addExtension(repeatedImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(220).build());
-    message.addExtension(repeatedLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
-
-    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
-    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
-    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
-
-    message.addExtension(repeatedStringPieceExtensionLite, "224");
-    message.addExtension(repeatedCordExtensionLite, "225");
-
-    // Add a second one of each field.
-    message.addExtension(repeatedInt32ExtensionLite   , 301);
-    message.addExtension(repeatedInt64ExtensionLite   , 302L);
-    message.addExtension(repeatedUint32ExtensionLite  , 303);
-    message.addExtension(repeatedUint64ExtensionLite  , 304L);
-    message.addExtension(repeatedSint32ExtensionLite  , 305);
-    message.addExtension(repeatedSint64ExtensionLite  , 306L);
-    message.addExtension(repeatedFixed32ExtensionLite , 307);
-    message.addExtension(repeatedFixed64ExtensionLite , 308L);
-    message.addExtension(repeatedSfixed32ExtensionLite, 309);
-    message.addExtension(repeatedSfixed64ExtensionLite, 310L);
-    message.addExtension(repeatedFloatExtensionLite   , 311F);
-    message.addExtension(repeatedDoubleExtensionLite  , 312D);
-    message.addExtension(repeatedBoolExtensionLite    , false);
-    message.addExtension(repeatedStringExtensionLite  , "315");
-    message.addExtension(repeatedBytesExtensionLite   , toBytes("316"));
-
-    message.addExtension(repeatedGroupExtensionLite,
-      RepeatedGroup_extension_lite.newBuilder().setA(317).build());
-    message.addExtension(repeatedNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
-    message.addExtension(repeatedForeignMessageExtensionLite,
-      ForeignMessageLite.newBuilder().setC(319).build());
-    message.addExtension(repeatedImportMessageExtensionLite,
-      ImportMessageLite.newBuilder().setD(320).build());
-    message.addExtension(repeatedLazyMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
-
-    message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
-    message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-    message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
-
-    message.addExtension(repeatedStringPieceExtensionLite, "324");
-    message.addExtension(repeatedCordExtensionLite, "325");
-
-    // -----------------------------------------------------------------
-
-    message.setExtension(defaultInt32ExtensionLite   , 401);
-    message.setExtension(defaultInt64ExtensionLite   , 402L);
-    message.setExtension(defaultUint32ExtensionLite  , 403);
-    message.setExtension(defaultUint64ExtensionLite  , 404L);
-    message.setExtension(defaultSint32ExtensionLite  , 405);
-    message.setExtension(defaultSint64ExtensionLite  , 406L);
-    message.setExtension(defaultFixed32ExtensionLite , 407);
-    message.setExtension(defaultFixed64ExtensionLite , 408L);
-    message.setExtension(defaultSfixed32ExtensionLite, 409);
-    message.setExtension(defaultSfixed64ExtensionLite, 410L);
-    message.setExtension(defaultFloatExtensionLite   , 411F);
-    message.setExtension(defaultDoubleExtensionLite  , 412D);
-    message.setExtension(defaultBoolExtensionLite    , false);
-    message.setExtension(defaultStringExtensionLite  , "415");
-    message.setExtension(defaultBytesExtensionLite   , toBytes("416"));
-
-    message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
-    message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
-    message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
-
-    message.setExtension(defaultStringPieceExtensionLite, "424");
-    message.setExtension(defaultCordExtensionLite, "425");
-
-    message.setExtension(oneofUint32ExtensionLite, 601);
-    message.setExtension(oneofNestedMessageExtensionLite,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
-    message.setExtension(oneofStringExtensionLite, "603");
-    message.setExtension(oneofBytesExtensionLite, toBytes("604"));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Modify the repeated extensions of {@code message} to contain the values
-   * expected by {@code assertRepeatedExtensionsModified()}.
-   */
-  public static void modifyRepeatedExtensions(
-      TestAllExtensionsLite.Builder message) {
-    message.setExtension(repeatedInt32ExtensionLite   , 1, 501);
-    message.setExtension(repeatedInt64ExtensionLite   , 1, 502L);
-    message.setExtension(repeatedUint32ExtensionLite  , 1, 503);
-    message.setExtension(repeatedUint64ExtensionLite  , 1, 504L);
-    message.setExtension(repeatedSint32ExtensionLite  , 1, 505);
-    message.setExtension(repeatedSint64ExtensionLite  , 1, 506L);
-    message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
-    message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
-    message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
-    message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
-    message.setExtension(repeatedFloatExtensionLite   , 1, 511F);
-    message.setExtension(repeatedDoubleExtensionLite  , 1, 512D);
-    message.setExtension(repeatedBoolExtensionLite    , 1, true);
-    message.setExtension(repeatedStringExtensionLite  , 1, "515");
-    message.setExtension(repeatedBytesExtensionLite   , 1, toBytes("516"));
-
-    message.setExtension(repeatedGroupExtensionLite, 1,
-      RepeatedGroup_extension_lite.newBuilder().setA(517).build());
-    message.setExtension(repeatedNestedMessageExtensionLite, 1,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
-    message.setExtension(repeatedForeignMessageExtensionLite, 1,
-      ForeignMessageLite.newBuilder().setC(519).build());
-    message.setExtension(repeatedImportMessageExtensionLite, 1,
-      ImportMessageLite.newBuilder().setD(520).build());
-    message.setExtension(repeatedLazyMessageExtensionLite, 1,
-      TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build());
-
-    message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
-    message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
-    message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
-
-    message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
-    message.setExtension(repeatedCordExtensionLite, 1, "525");
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are set to the values assigned by {@code setAllExtensions}.
-   */
-  public static void assertAllExtensionsSet(
-      TestAllExtensionsLiteOrBuilder message) {
-    Assert.assertTrue(message.hasExtension(optionalInt32ExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(optionalInt64ExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(optionalUint32ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalUint64ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalSint32ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalSint64ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalFixed32ExtensionLite ));
-    Assert.assertTrue(message.hasExtension(optionalFixed64ExtensionLite ));
-    Assert.assertTrue(message.hasExtension(optionalSfixed32ExtensionLite));
-    Assert.assertTrue(message.hasExtension(optionalSfixed64ExtensionLite));
-    Assert.assertTrue(message.hasExtension(optionalFloatExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(optionalDoubleExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalBoolExtensionLite    ));
-    Assert.assertTrue(message.hasExtension(optionalStringExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(optionalBytesExtensionLite   ));
-
-    Assert.assertTrue(message.hasExtension(optionalGroupExtensionLite         ));
-    Assert.assertTrue(message.hasExtension(optionalNestedMessageExtensionLite ));
-    Assert.assertTrue(message.hasExtension(optionalForeignMessageExtensionLite));
-    Assert.assertTrue(message.hasExtension(optionalImportMessageExtensionLite ));
-
-    Assert.assertTrue(message.getExtension(optionalGroupExtensionLite         ).hasA());
-    Assert.assertTrue(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
-    Assert.assertTrue(message.getExtension(optionalForeignMessageExtensionLite).hasC());
-    Assert.assertTrue(message.getExtension(optionalImportMessageExtensionLite ).hasD());
-
-    Assert.assertTrue(message.hasExtension(optionalNestedEnumExtensionLite ));
-    Assert.assertTrue(message.hasExtension(optionalForeignEnumExtensionLite));
-    Assert.assertTrue(message.hasExtension(optionalImportEnumExtensionLite ));
-
-    Assert.assertTrue(message.hasExtension(optionalStringPieceExtensionLite));
-    Assert.assertTrue(message.hasExtension(optionalCordExtensionLite));
-
-    assertEqualsExactType(101  , message.getExtension(optionalInt32ExtensionLite   ));
-    assertEqualsExactType(102L , message.getExtension(optionalInt64ExtensionLite   ));
-    assertEqualsExactType(103  , message.getExtension(optionalUint32ExtensionLite  ));
-    assertEqualsExactType(104L , message.getExtension(optionalUint64ExtensionLite  ));
-    assertEqualsExactType(105  , message.getExtension(optionalSint32ExtensionLite  ));
-    assertEqualsExactType(106L , message.getExtension(optionalSint64ExtensionLite  ));
-    assertEqualsExactType(107  , message.getExtension(optionalFixed32ExtensionLite ));
-    assertEqualsExactType(108L , message.getExtension(optionalFixed64ExtensionLite ));
-    assertEqualsExactType(109  , message.getExtension(optionalSfixed32ExtensionLite));
-    assertEqualsExactType(110L , message.getExtension(optionalSfixed64ExtensionLite));
-    assertEqualsExactType(111F , message.getExtension(optionalFloatExtensionLite   ));
-    assertEqualsExactType(112D , message.getExtension(optionalDoubleExtensionLite  ));
-    assertEqualsExactType(true , message.getExtension(optionalBoolExtensionLite    ));
-    assertEqualsExactType("115", message.getExtension(optionalStringExtensionLite  ));
-    assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtensionLite));
-
-    assertEqualsExactType(117, message.getExtension(optionalGroupExtensionLite         ).getA());
-    assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
-    assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtensionLite).getC());
-    assertEqualsExactType(120, message.getExtension(optionalImportMessageExtensionLite ).getD());
-    assertEqualsExactType(126, message.getExtension(
-        optionalPublicImportMessageExtensionLite).getE());
-    assertEqualsExactType(127, message.getExtension(optionalLazyMessageExtensionLite).getBb());
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
-      message.getExtension(optionalNestedEnumExtensionLite));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
-      message.getExtension(optionalForeignEnumExtensionLite));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
-      message.getExtension(optionalImportEnumExtensionLite));
-
-    assertEqualsExactType("124", message.getExtension(optionalStringPieceExtensionLite));
-    assertEqualsExactType("125", message.getExtension(optionalCordExtensionLite));
-
-    // -----------------------------------------------------------------
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
-
-    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
-    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
-    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
-    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
-    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
-    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
-    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
-    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
-    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
-    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
-    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
-    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
-    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
-    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
-
-    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
-    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
-    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
-    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
-    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite   ,0).getBb());
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
-      message.getExtension(repeatedNestedEnumExtensionLite, 0));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
-      message.getExtension(repeatedForeignEnumExtensionLite, 0));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
-      message.getExtension(repeatedImportEnumExtensionLite, 0));
-
-    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
-    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
-
-    assertEqualsExactType(301  , message.getExtension(repeatedInt32ExtensionLite   , 1));
-    assertEqualsExactType(302L , message.getExtension(repeatedInt64ExtensionLite   , 1));
-    assertEqualsExactType(303  , message.getExtension(repeatedUint32ExtensionLite  , 1));
-    assertEqualsExactType(304L , message.getExtension(repeatedUint64ExtensionLite  , 1));
-    assertEqualsExactType(305  , message.getExtension(repeatedSint32ExtensionLite  , 1));
-    assertEqualsExactType(306L , message.getExtension(repeatedSint64ExtensionLite  , 1));
-    assertEqualsExactType(307  , message.getExtension(repeatedFixed32ExtensionLite , 1));
-    assertEqualsExactType(308L , message.getExtension(repeatedFixed64ExtensionLite , 1));
-    assertEqualsExactType(309  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
-    assertEqualsExactType(310L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
-    assertEqualsExactType(311F , message.getExtension(repeatedFloatExtensionLite   , 1));
-    assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtensionLite  , 1));
-    assertEqualsExactType(false, message.getExtension(repeatedBoolExtensionLite    , 1));
-    assertEqualsExactType("315", message.getExtension(repeatedStringExtensionLite  , 1));
-    assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtensionLite, 1));
-
-    assertEqualsExactType(317, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
-    assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
-    assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
-    assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
-    assertEqualsExactType(327, message.getExtension(repeatedLazyMessageExtensionLite   ,1).getBb());
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
-      message.getExtension(repeatedNestedEnumExtensionLite, 1));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
-      message.getExtension(repeatedForeignEnumExtensionLite, 1));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
-      message.getExtension(repeatedImportEnumExtensionLite, 1));
-
-    assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtensionLite, 1));
-    assertEqualsExactType("325", message.getExtension(repeatedCordExtensionLite, 1));
-
-    // -----------------------------------------------------------------
-
-    Assert.assertTrue(message.hasExtension(defaultInt32ExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(defaultInt64ExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(defaultUint32ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultUint64ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultSint32ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultSint64ExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultFixed32ExtensionLite ));
-    Assert.assertTrue(message.hasExtension(defaultFixed64ExtensionLite ));
-    Assert.assertTrue(message.hasExtension(defaultSfixed32ExtensionLite));
-    Assert.assertTrue(message.hasExtension(defaultSfixed64ExtensionLite));
-    Assert.assertTrue(message.hasExtension(defaultFloatExtensionLite   ));
-    Assert.assertTrue(message.hasExtension(defaultDoubleExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultBoolExtensionLite    ));
-    Assert.assertTrue(message.hasExtension(defaultStringExtensionLite  ));
-    Assert.assertTrue(message.hasExtension(defaultBytesExtensionLite   ));
-
-    Assert.assertTrue(message.hasExtension(defaultNestedEnumExtensionLite ));
-    Assert.assertTrue(message.hasExtension(defaultForeignEnumExtensionLite));
-    Assert.assertTrue(message.hasExtension(defaultImportEnumExtensionLite ));
-
-    Assert.assertTrue(message.hasExtension(defaultStringPieceExtensionLite));
-    Assert.assertTrue(message.hasExtension(defaultCordExtensionLite));
-
-    assertEqualsExactType(401  , message.getExtension(defaultInt32ExtensionLite   ));
-    assertEqualsExactType(402L , message.getExtension(defaultInt64ExtensionLite   ));
-    assertEqualsExactType(403  , message.getExtension(defaultUint32ExtensionLite  ));
-    assertEqualsExactType(404L , message.getExtension(defaultUint64ExtensionLite  ));
-    assertEqualsExactType(405  , message.getExtension(defaultSint32ExtensionLite  ));
-    assertEqualsExactType(406L , message.getExtension(defaultSint64ExtensionLite  ));
-    assertEqualsExactType(407  , message.getExtension(defaultFixed32ExtensionLite ));
-    assertEqualsExactType(408L , message.getExtension(defaultFixed64ExtensionLite ));
-    assertEqualsExactType(409  , message.getExtension(defaultSfixed32ExtensionLite));
-    assertEqualsExactType(410L , message.getExtension(defaultSfixed64ExtensionLite));
-    assertEqualsExactType(411F , message.getExtension(defaultFloatExtensionLite   ));
-    assertEqualsExactType(412D , message.getExtension(defaultDoubleExtensionLite  ));
-    assertEqualsExactType(false, message.getExtension(defaultBoolExtensionLite    ));
-    assertEqualsExactType("415", message.getExtension(defaultStringExtensionLite  ));
-    assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtensionLite));
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
-      message.getExtension(defaultNestedEnumExtensionLite ));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
-      message.getExtension(defaultForeignEnumExtensionLite));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
-      message.getExtension(defaultImportEnumExtensionLite));
-
-    assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
-    assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
-
-    Assert.assertTrue(message.hasExtension(oneofBytesExtensionLite));
-
-    assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtensionLite));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are cleared, and that getting the extensions returns their
-   * default values.
-   */
-  public static void assertExtensionsClear(
-      TestAllExtensionsLiteOrBuilder message) {
-    // hasBlah() should initially be false for all optional fields.
-    Assert.assertFalse(message.hasExtension(optionalInt32ExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(optionalInt64ExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(optionalUint32ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalUint64ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalSint32ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalSint64ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalFixed32ExtensionLite ));
-    Assert.assertFalse(message.hasExtension(optionalFixed64ExtensionLite ));
-    Assert.assertFalse(message.hasExtension(optionalSfixed32ExtensionLite));
-    Assert.assertFalse(message.hasExtension(optionalSfixed64ExtensionLite));
-    Assert.assertFalse(message.hasExtension(optionalFloatExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(optionalDoubleExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalBoolExtensionLite    ));
-    Assert.assertFalse(message.hasExtension(optionalStringExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(optionalBytesExtensionLite   ));
-
-    Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite              ));
-    Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite      ));
-    Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite     ));
-    Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite      ));
-    Assert.assertFalse(message.hasExtension(optionalPublicImportMessageExtensionLite));
-    Assert.assertFalse(message.hasExtension(optionalLazyMessageExtensionLite        ));
-
-    Assert.assertFalse(message.hasExtension(optionalNestedEnumExtensionLite ));
-    Assert.assertFalse(message.hasExtension(optionalForeignEnumExtensionLite));
-    Assert.assertFalse(message.hasExtension(optionalImportEnumExtensionLite ));
-
-    Assert.assertFalse(message.hasExtension(optionalStringPieceExtensionLite));
-    Assert.assertFalse(message.hasExtension(optionalCordExtensionLite));
-
-    // Optional fields without defaults are set to zero or something like it.
-    assertEqualsExactType(0    , message.getExtension(optionalInt32ExtensionLite   ));
-    assertEqualsExactType(0L   , message.getExtension(optionalInt64ExtensionLite   ));
-    assertEqualsExactType(0    , message.getExtension(optionalUint32ExtensionLite  ));
-    assertEqualsExactType(0L   , message.getExtension(optionalUint64ExtensionLite  ));
-    assertEqualsExactType(0    , message.getExtension(optionalSint32ExtensionLite  ));
-    assertEqualsExactType(0L   , message.getExtension(optionalSint64ExtensionLite  ));
-    assertEqualsExactType(0    , message.getExtension(optionalFixed32ExtensionLite ));
-    assertEqualsExactType(0L   , message.getExtension(optionalFixed64ExtensionLite ));
-    assertEqualsExactType(0    , message.getExtension(optionalSfixed32ExtensionLite));
-    assertEqualsExactType(0L   , message.getExtension(optionalSfixed64ExtensionLite));
-    assertEqualsExactType(0F   , message.getExtension(optionalFloatExtensionLite   ));
-    assertEqualsExactType(0D   , message.getExtension(optionalDoubleExtensionLite  ));
-    assertEqualsExactType(false, message.getExtension(optionalBoolExtensionLite    ));
-    assertEqualsExactType(""   , message.getExtension(optionalStringExtensionLite  ));
-    assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtensionLite));
-
-    // Embedded messages should also be clear.
-    Assert.assertFalse(message.getExtension(optionalGroupExtensionLite              ).hasA());
-    Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite      ).hasBb());
-    Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite     ).hasC());
-    Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite      ).hasD());
-    Assert.assertFalse(message.getExtension(optionalPublicImportMessageExtensionLite).hasE());
-    Assert.assertFalse(message.getExtension(optionalLazyMessageExtensionLite        ).hasBb());
-
-    assertEqualsExactType(0, message.getExtension(optionalGroupExtensionLite         ).getA());
-    assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
-    assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtensionLite).getC());
-    assertEqualsExactType(0, message.getExtension(optionalImportMessageExtensionLite ).getD());
-    assertEqualsExactType(0, message.getExtension(
-        optionalPublicImportMessageExtensionLite).getE());
-    assertEqualsExactType(0, message.getExtension(optionalLazyMessageExtensionLite   ).getBb());
-
-    // Enums without defaults are set to the first value in the enum.
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
-      message.getExtension(optionalNestedEnumExtensionLite ));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
-      message.getExtension(optionalForeignEnumExtensionLite));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
-      message.getExtension(optionalImportEnumExtensionLite));
-
-    assertEqualsExactType("", message.getExtension(optionalStringPieceExtensionLite));
-    assertEqualsExactType("", message.getExtension(optionalCordExtensionLite));
-
-    // Repeated fields are empty.
-    Assert.assertEquals(0, message.getExtensionCount(repeatedInt32ExtensionLite   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedInt64ExtensionLite   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedUint32ExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedUint64ExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSint32ExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSint64ExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32ExtensionLite ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64ExtensionLite ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32ExtensionLite));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64ExtensionLite));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtensionLite   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtensionLite    ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtensionLite  ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtensionLite   ));
-
-    Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtensionLite         ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtensionLite));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtensionLite ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
-
-    Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtensionLite));
-    Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtensionLite));
-
-    // hasBlah() should also be false for all default fields.
-    Assert.assertFalse(message.hasExtension(defaultInt32ExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(defaultInt64ExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(defaultUint32ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultUint64ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultSint32ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultSint64ExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultFixed32ExtensionLite ));
-    Assert.assertFalse(message.hasExtension(defaultFixed64ExtensionLite ));
-    Assert.assertFalse(message.hasExtension(defaultSfixed32ExtensionLite));
-    Assert.assertFalse(message.hasExtension(defaultSfixed64ExtensionLite));
-    Assert.assertFalse(message.hasExtension(defaultFloatExtensionLite   ));
-    Assert.assertFalse(message.hasExtension(defaultDoubleExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultBoolExtensionLite    ));
-    Assert.assertFalse(message.hasExtension(defaultStringExtensionLite  ));
-    Assert.assertFalse(message.hasExtension(defaultBytesExtensionLite   ));
-
-    Assert.assertFalse(message.hasExtension(defaultNestedEnumExtensionLite ));
-    Assert.assertFalse(message.hasExtension(defaultForeignEnumExtensionLite));
-    Assert.assertFalse(message.hasExtension(defaultImportEnumExtensionLite ));
-
-    Assert.assertFalse(message.hasExtension(defaultStringPieceExtensionLite));
-    Assert.assertFalse(message.hasExtension(defaultCordExtensionLite));
-
-    // Fields with defaults have their default values (duh).
-    assertEqualsExactType( 41    , message.getExtension(defaultInt32ExtensionLite   ));
-    assertEqualsExactType( 42L   , message.getExtension(defaultInt64ExtensionLite   ));
-    assertEqualsExactType( 43    , message.getExtension(defaultUint32ExtensionLite  ));
-    assertEqualsExactType( 44L   , message.getExtension(defaultUint64ExtensionLite  ));
-    assertEqualsExactType(-45    , message.getExtension(defaultSint32ExtensionLite  ));
-    assertEqualsExactType( 46L   , message.getExtension(defaultSint64ExtensionLite  ));
-    assertEqualsExactType( 47    , message.getExtension(defaultFixed32ExtensionLite ));
-    assertEqualsExactType( 48L   , message.getExtension(defaultFixed64ExtensionLite ));
-    assertEqualsExactType( 49    , message.getExtension(defaultSfixed32ExtensionLite));
-    assertEqualsExactType(-50L   , message.getExtension(defaultSfixed64ExtensionLite));
-    assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtensionLite   ));
-    assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtensionLite  ));
-    assertEqualsExactType(true   , message.getExtension(defaultBoolExtensionLite    ));
-    assertEqualsExactType("hello", message.getExtension(defaultStringExtensionLite  ));
-    assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtensionLite));
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
-      message.getExtension(defaultNestedEnumExtensionLite ));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
-      message.getExtension(defaultForeignEnumExtensionLite));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
-      message.getExtension(defaultImportEnumExtensionLite));
-
-    assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
-    assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
-
-    Assert.assertFalse(message.hasExtension(oneofUint32ExtensionLite));
-    Assert.assertFalse(message.hasExtension(oneofNestedMessageExtensionLite));
-    Assert.assertFalse(message.hasExtension(oneofStringExtensionLite));
-    Assert.assertFalse(message.hasExtension(oneofBytesExtensionLite));
-  }
-
-  // -------------------------------------------------------------------
-
-  /**
-   * Assert (using {@code junit.framework.Assert}} that all extensions of
-   * {@code message} are set to the values assigned by {@code setAllExtensions}
-   * followed by {@code modifyRepeatedExtensions}.
-   */
-  public static void assertRepeatedExtensionsModified(
-      TestAllExtensionsLiteOrBuilder message) {
-    // ModifyRepeatedFields only sets the second repeated element of each
-    // field.  In addition to verifying this, we also verify that the first
-    // element and size were *not* modified.
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite   ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite         ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedLazyMessageExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite    ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite    ));
-
-    Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
-
-    assertEqualsExactType(201  , message.getExtension(repeatedInt32ExtensionLite   , 0));
-    assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite   , 0));
-    assertEqualsExactType(203  , message.getExtension(repeatedUint32ExtensionLite  , 0));
-    assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite  , 0));
-    assertEqualsExactType(205  , message.getExtension(repeatedSint32ExtensionLite  , 0));
-    assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite  , 0));
-    assertEqualsExactType(207  , message.getExtension(repeatedFixed32ExtensionLite , 0));
-    assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
-    assertEqualsExactType(209  , message.getExtension(repeatedSfixed32ExtensionLite, 0));
-    assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
-    assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite   , 0));
-    assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite  , 0));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 0));
-    assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite  , 0));
-    assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
-
-    assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite         ,0).getA());
-    assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
-    assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
-    assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
-    assertEqualsExactType(227, message.getExtension(repeatedLazyMessageExtensionLite   ,0).getBb());
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
-      message.getExtension(repeatedNestedEnumExtensionLite, 0));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
-      message.getExtension(repeatedForeignEnumExtensionLite, 0));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
-      message.getExtension(repeatedImportEnumExtensionLite, 0));
-
-    assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
-    assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
-
-    // Actually verify the second (modified) elements now.
-    assertEqualsExactType(501  , message.getExtension(repeatedInt32ExtensionLite   , 1));
-    assertEqualsExactType(502L , message.getExtension(repeatedInt64ExtensionLite   , 1));
-    assertEqualsExactType(503  , message.getExtension(repeatedUint32ExtensionLite  , 1));
-    assertEqualsExactType(504L , message.getExtension(repeatedUint64ExtensionLite  , 1));
-    assertEqualsExactType(505  , message.getExtension(repeatedSint32ExtensionLite  , 1));
-    assertEqualsExactType(506L , message.getExtension(repeatedSint64ExtensionLite  , 1));
-    assertEqualsExactType(507  , message.getExtension(repeatedFixed32ExtensionLite , 1));
-    assertEqualsExactType(508L , message.getExtension(repeatedFixed64ExtensionLite , 1));
-    assertEqualsExactType(509  , message.getExtension(repeatedSfixed32ExtensionLite, 1));
-    assertEqualsExactType(510L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
-    assertEqualsExactType(511F , message.getExtension(repeatedFloatExtensionLite   , 1));
-    assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtensionLite  , 1));
-    assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite    , 1));
-    assertEqualsExactType("515", message.getExtension(repeatedStringExtensionLite  , 1));
-    assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtensionLite, 1));
-
-    assertEqualsExactType(517, message.getExtension(repeatedGroupExtensionLite         ,1).getA());
-    assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
-    assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
-    assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
-    assertEqualsExactType(527, message.getExtension(repeatedLazyMessageExtensionLite   ,1).getBb());
-
-    assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
-      message.getExtension(repeatedNestedEnumExtensionLite, 1));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
-      message.getExtension(repeatedForeignEnumExtensionLite, 1));
-    assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
-      message.getExtension(repeatedImportEnumExtensionLite, 1));
-
-    assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtensionLite, 1));
-    assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
-  }
-
-  public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
-    message.addExtension(packedInt32ExtensionLite   , 601);
-    message.addExtension(packedInt64ExtensionLite   , 602L);
-    message.addExtension(packedUint32ExtensionLite  , 603);
-    message.addExtension(packedUint64ExtensionLite  , 604L);
-    message.addExtension(packedSint32ExtensionLite  , 605);
-    message.addExtension(packedSint64ExtensionLite  , 606L);
-    message.addExtension(packedFixed32ExtensionLite , 607);
-    message.addExtension(packedFixed64ExtensionLite , 608L);
-    message.addExtension(packedSfixed32ExtensionLite, 609);
-    message.addExtension(packedSfixed64ExtensionLite, 610L);
-    message.addExtension(packedFloatExtensionLite   , 611F);
-    message.addExtension(packedDoubleExtensionLite  , 612D);
-    message.addExtension(packedBoolExtensionLite    , true);
-    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
-    // Add a second one of each field.
-    message.addExtension(packedInt32ExtensionLite   , 701);
-    message.addExtension(packedInt64ExtensionLite   , 702L);
-    message.addExtension(packedUint32ExtensionLite  , 703);
-    message.addExtension(packedUint64ExtensionLite  , 704L);
-    message.addExtension(packedSint32ExtensionLite  , 705);
-    message.addExtension(packedSint64ExtensionLite  , 706L);
-    message.addExtension(packedFixed32ExtensionLite , 707);
-    message.addExtension(packedFixed64ExtensionLite , 708L);
-    message.addExtension(packedSfixed32ExtensionLite, 709);
-    message.addExtension(packedSfixed64ExtensionLite, 710L);
-    message.addExtension(packedFloatExtensionLite   , 711F);
-    message.addExtension(packedDoubleExtensionLite  , 712D);
-    message.addExtension(packedBoolExtensionLite    , false);
-    message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
-  }
-
-  public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
-    Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedUint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedUint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSint32ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSint64ExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedFixed32ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(packedFixed64ExtensionLite ));
-    Assert.assertEquals(2, message.getExtensionCount(packedSfixed32ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(packedSfixed64ExtensionLite));
-    Assert.assertEquals(2, message.getExtensionCount(packedFloatExtensionLite   ));
-    Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtensionLite  ));
-    Assert.assertEquals(2, message.getExtensionCount(packedBoolExtensionLite    ));
-    Assert.assertEquals(2, message.getExtensionCount(packedEnumExtensionLite));
-    assertEqualsExactType(601  , message.getExtension(packedInt32ExtensionLite   , 0));
-    assertEqualsExactType(602L , message.getExtension(packedInt64ExtensionLite   , 0));
-    assertEqualsExactType(603  , message.getExtension(packedUint32ExtensionLite  , 0));
-    assertEqualsExactType(604L , message.getExtension(packedUint64ExtensionLite  , 0));
-    assertEqualsExactType(605  , message.getExtension(packedSint32ExtensionLite  , 0));
-    assertEqualsExactType(606L , message.getExtension(packedSint64ExtensionLite  , 0));
-    assertEqualsExactType(607  , message.getExtension(packedFixed32ExtensionLite , 0));
-    assertEqualsExactType(608L , message.getExtension(packedFixed64ExtensionLite , 0));
-    assertEqualsExactType(609  , message.getExtension(packedSfixed32ExtensionLite, 0));
-    assertEqualsExactType(610L , message.getExtension(packedSfixed64ExtensionLite, 0));
-    assertEqualsExactType(611F , message.getExtension(packedFloatExtensionLite   , 0));
-    assertEqualsExactType(612D , message.getExtension(packedDoubleExtensionLite  , 0));
-    assertEqualsExactType(true , message.getExtension(packedBoolExtensionLite    , 0));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
-                          message.getExtension(packedEnumExtensionLite, 0));
-    assertEqualsExactType(701  , message.getExtension(packedInt32ExtensionLite   , 1));
-    assertEqualsExactType(702L , message.getExtension(packedInt64ExtensionLite   , 1));
-    assertEqualsExactType(703  , message.getExtension(packedUint32ExtensionLite  , 1));
-    assertEqualsExactType(704L , message.getExtension(packedUint64ExtensionLite  , 1));
-    assertEqualsExactType(705  , message.getExtension(packedSint32ExtensionLite  , 1));
-    assertEqualsExactType(706L , message.getExtension(packedSint64ExtensionLite  , 1));
-    assertEqualsExactType(707  , message.getExtension(packedFixed32ExtensionLite , 1));
-    assertEqualsExactType(708L , message.getExtension(packedFixed64ExtensionLite , 1));
-    assertEqualsExactType(709  , message.getExtension(packedSfixed32ExtensionLite, 1));
-    assertEqualsExactType(710L , message.getExtension(packedSfixed64ExtensionLite, 1));
-    assertEqualsExactType(711F , message.getExtension(packedFloatExtensionLite   , 1));
-    assertEqualsExactType(712D , message.getExtension(packedDoubleExtensionLite  , 1));
-    assertEqualsExactType(false, message.getExtension(packedBoolExtensionLite    , 1));
-    assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
-                          message.getExtension(packedEnumExtensionLite, 1));
-  }
-
-  // ===================================================================
-  // oneof
-  public static void setOneof(TestOneof2.Builder message) {
-    message.setFooLazyMessage(
-        TestOneof2.NestedMessage.newBuilder().setQuxInt(100).build());
-    message.setBarString("101");
-    message.setBazInt(102);
-    message.setBazString("103");
-  }
-
-  public static void assertOneofSet(TestOneof2 message) {
-    Assert.assertTrue(message.hasFooLazyMessage            ());
-    Assert.assertTrue(message.getFooLazyMessage().hasQuxInt());
-
-    Assert.assertTrue(message.hasBarString());
-    Assert.assertTrue(message.hasBazInt   ());
-    Assert.assertTrue(message.hasBazString());
-
-    Assert.assertEquals(100  , message.getFooLazyMessage().getQuxInt());
-    Assert.assertEquals("101", message.getBarString                 ());
-    Assert.assertEquals(102  , message.getBazInt                    ());
-    Assert.assertEquals("103", message.getBazString                 ());
-  }
-
-  public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
-    int count = 0;
-    if (message.hasFooInt()) { ++count; }
-    if (message.hasFooString()) { ++count; }
-    if (message.hasFooCord()) { ++count; }
-    if (message.hasFooStringPiece()) { ++count; }
-    if (message.hasFooBytes()) { ++count; }
-    if (message.hasFooEnum()) { ++count; }
-    if (message.hasFooMessage()) { ++count; }
-    if (message.hasFooGroup()) { ++count; }
-    if (message.hasFooLazyMessage()) { ++count; }
-    Assert.assertTrue(count <= 1);
-
-    count = 0;
-    if (message.hasBarInt()) { ++count; }
-    if (message.hasBarString()) { ++count; }
-    if (message.hasBarCord()) { ++count; }
-    if (message.hasBarStringPiece()) { ++count; }
-    if (message.hasBarBytes()) { ++count; }
-    if (message.hasBarEnum()) { ++count; }
-    Assert.assertTrue(count <= 1);
-
-    switch (message.getFooCase()) {
-      case FOO_INT:
-        Assert.assertTrue(message.hasFooInt());
-        break;
-      case FOO_STRING:
-        Assert.assertTrue(message.hasFooString());
-        break;
-      case FOO_CORD:
-        Assert.assertTrue(message.hasFooCord());
-        break;
-      case FOO_BYTES:
-        Assert.assertTrue(message.hasFooBytes());
-        break;
-      case FOO_ENUM:
-        Assert.assertTrue(message.hasFooEnum());
-        break;
-      case FOO_MESSAGE:
-        Assert.assertTrue(message.hasFooMessage());
-        break;
-      case FOOGROUP:
-        Assert.assertTrue(message.hasFooGroup());
-        break;
-      case FOO_LAZY_MESSAGE:
-        Assert.assertTrue(message.hasFooLazyMessage());
-        break;
-      case FOO_NOT_SET:
-        break;
-    }
-  }
-
-  // =================================================================
-
-  /**
-   * Performs the same things that the methods of {@code TestUtil} do, but
-   * via the reflection interface.  This is its own class because it needs
-   * to know what descriptor to use.
-   */
-  public static class ReflectionTester {
-    private final Descriptors.Descriptor baseDescriptor;
-    private final ExtensionRegistry extensionRegistry;
-
-    private final Descriptors.FileDescriptor file;
-    private final Descriptors.FileDescriptor importFile;
-    private final Descriptors.FileDescriptor publicImportFile;
-
-    private final Descriptors.Descriptor optionalGroup;
-    private final Descriptors.Descriptor repeatedGroup;
-    private final Descriptors.Descriptor nestedMessage;
-    private final Descriptors.Descriptor foreignMessage;
-    private final Descriptors.Descriptor importMessage;
-    private final Descriptors.Descriptor publicImportMessage;
-
-    private final Descriptors.FieldDescriptor groupA;
-    private final Descriptors.FieldDescriptor repeatedGroupA;
-    private final Descriptors.FieldDescriptor nestedB;
-    private final Descriptors.FieldDescriptor foreignC;
-    private final Descriptors.FieldDescriptor importD;
-    private final Descriptors.FieldDescriptor importE;
-
-    private final Descriptors.EnumDescriptor nestedEnum;
-    private final Descriptors.EnumDescriptor foreignEnum;
-    private final Descriptors.EnumDescriptor importEnum;
-
-    private final Descriptors.EnumValueDescriptor nestedFoo;
-    private final Descriptors.EnumValueDescriptor nestedBar;
-    private final Descriptors.EnumValueDescriptor nestedBaz;
-    private final Descriptors.EnumValueDescriptor foreignFoo;
-    private final Descriptors.EnumValueDescriptor foreignBar;
-    private final Descriptors.EnumValueDescriptor foreignBaz;
-    private final Descriptors.EnumValueDescriptor importFoo;
-    private final Descriptors.EnumValueDescriptor importBar;
-    private final Descriptors.EnumValueDescriptor importBaz;
-
-    /**
-     * Construct a {@code ReflectionTester} that will expect messages using
-     * the given descriptor.
-     *
-     * Normally {@code baseDescriptor} should be a descriptor for the type
-     * {@code TestAllTypes}, defined in
-     * {@code google/protobuf/unittest.proto}.  However, if
-     * {@code extensionRegistry} is non-null, then {@code baseDescriptor} should
-     * be for {@code TestAllExtensions} instead, and instead of reading and
-     * writing normal fields, the tester will read and write extensions.
-     * All of {@code TestAllExtensions}' extensions must be registered in the
-     * registry.
-     */
-    public ReflectionTester(Descriptors.Descriptor baseDescriptor,
-                            ExtensionRegistry extensionRegistry) {
-      this.baseDescriptor = baseDescriptor;
-      this.extensionRegistry = extensionRegistry;
-
-      this.file = baseDescriptor.getFile();
-      Assert.assertEquals(1, file.getDependencies().size());
-      this.importFile = file.getDependencies().get(0);
-      this.publicImportFile = importFile.getDependencies().get(0);
-
-      Descriptors.Descriptor testAllTypes;
-      if (baseDescriptor.getName() == "TestAllTypes") {
-        testAllTypes = baseDescriptor;
-      } else {
-        testAllTypes = file.findMessageTypeByName("TestAllTypes");
-        Assert.assertNotNull(testAllTypes);
-      }
-
-      if (extensionRegistry == null) {
-        // Use testAllTypes, rather than baseDescriptor, to allow
-        // initialization using TestPackedTypes descriptors. These objects
-        // won't be used by the methods for packed fields.
-        this.optionalGroup =
-          testAllTypes.findNestedTypeByName("OptionalGroup");
-        this.repeatedGroup =
-          testAllTypes.findNestedTypeByName("RepeatedGroup");
-      } else {
-        this.optionalGroup =
-          file.findMessageTypeByName("OptionalGroup_extension");
-        this.repeatedGroup =
-          file.findMessageTypeByName("RepeatedGroup_extension");
-      }
-      this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
-      this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
-      this.importMessage = importFile.findMessageTypeByName("ImportMessage");
-      this.publicImportMessage = publicImportFile.findMessageTypeByName(
-          "PublicImportMessage");
-
-      this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
-      this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
-      this.importEnum = importFile.findEnumTypeByName("ImportEnum");
-
-      Assert.assertNotNull(optionalGroup );
-      Assert.assertNotNull(repeatedGroup );
-      Assert.assertNotNull(nestedMessage );
-      Assert.assertNotNull(foreignMessage);
-      Assert.assertNotNull(importMessage );
-      Assert.assertNotNull(nestedEnum    );
-      Assert.assertNotNull(foreignEnum   );
-      Assert.assertNotNull(importEnum    );
-
-      this.nestedB  = nestedMessage .findFieldByName("bb");
-      this.foreignC = foreignMessage.findFieldByName("c");
-      this.importD  = importMessage .findFieldByName("d");
-      this.importE  = publicImportMessage.findFieldByName("e");
-      this.nestedFoo = nestedEnum.findValueByName("FOO");
-      this.nestedBar = nestedEnum.findValueByName("BAR");
-      this.nestedBaz = nestedEnum.findValueByName("BAZ");
-      this.foreignFoo = foreignEnum.findValueByName("FOREIGN_FOO");
-      this.foreignBar = foreignEnum.findValueByName("FOREIGN_BAR");
-      this.foreignBaz = foreignEnum.findValueByName("FOREIGN_BAZ");
-      this.importFoo = importEnum.findValueByName("IMPORT_FOO");
-      this.importBar = importEnum.findValueByName("IMPORT_BAR");
-      this.importBaz = importEnum.findValueByName("IMPORT_BAZ");
-
-      this.groupA = optionalGroup.findFieldByName("a");
-      this.repeatedGroupA = repeatedGroup.findFieldByName("a");
-
-      Assert.assertNotNull(groupA        );
-      Assert.assertNotNull(repeatedGroupA);
-      Assert.assertNotNull(nestedB       );
-      Assert.assertNotNull(foreignC      );
-      Assert.assertNotNull(importD       );
-      Assert.assertNotNull(importE       );
-      Assert.assertNotNull(nestedFoo     );
-      Assert.assertNotNull(nestedBar     );
-      Assert.assertNotNull(nestedBaz     );
-      Assert.assertNotNull(foreignFoo    );
-      Assert.assertNotNull(foreignBar    );
-      Assert.assertNotNull(foreignBaz    );
-      Assert.assertNotNull(importFoo     );
-      Assert.assertNotNull(importBar     );
-      Assert.assertNotNull(importBaz     );
-    }
-
-    /**
-     * Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
-     */
-    private Descriptors.FieldDescriptor f(String name) {
-      Descriptors.FieldDescriptor result;
-      if (extensionRegistry == null) {
-        result = baseDescriptor.findFieldByName(name);
-      } else {
-        result = file.findExtensionByName(name + "_extension");
-      }
-      Assert.assertNotNull(result);
-      return result;
-    }
-
-    /**
-     * Calls {@code parent.newBuilderForField()} or uses the
-     * {@code ExtensionRegistry} to find an appropriate builder, depending
-     * on what type is being tested.
-     */
-    private Message.Builder newBuilderForField(
-        Message.Builder parent, Descriptors.FieldDescriptor field) {
-      if (extensionRegistry == null) {
-        return parent.newBuilderForField(field);
-      } else {
-        ExtensionRegistry.ExtensionInfo extension =
-          extensionRegistry.findImmutableExtensionByNumber(
-              field.getContainingType(), field.getNumber());
-        Assert.assertNotNull(extension);
-        Assert.assertNotNull(extension.defaultInstance);
-        return extension.defaultInstance.newBuilderForType();
-      }
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
-     * Set every field of {@code message} to the values expected by
-     * {@code assertAllFieldsSet()}, using the {@link Message.Builder}
-     * reflection interface.
-     */
-    void setAllFieldsViaReflection(Message.Builder message) {
-      message.setField(f("optional_int32"   ), 101 );
-      message.setField(f("optional_int64"   ), 102L);
-      message.setField(f("optional_uint32"  ), 103 );
-      message.setField(f("optional_uint64"  ), 104L);
-      message.setField(f("optional_sint32"  ), 105 );
-      message.setField(f("optional_sint64"  ), 106L);
-      message.setField(f("optional_fixed32" ), 107 );
-      message.setField(f("optional_fixed64" ), 108L);
-      message.setField(f("optional_sfixed32"), 109 );
-      message.setField(f("optional_sfixed64"), 110L);
-      message.setField(f("optional_float"   ), 111F);
-      message.setField(f("optional_double"  ), 112D);
-      message.setField(f("optional_bool"    ), true);
-      message.setField(f("optional_string"  ), "115");
-      message.setField(f("optional_bytes"   ), toBytes("116"));
-
-      message.setField(f("optionalgroup"),
-        newBuilderForField(message, f("optionalgroup"))
-               .setField(groupA, 117).build());
-      message.setField(f("optional_nested_message"),
-        newBuilderForField(message, f("optional_nested_message"))
-               .setField(nestedB, 118).build());
-      message.setField(f("optional_foreign_message"),
-        newBuilderForField(message, f("optional_foreign_message"))
-               .setField(foreignC, 119).build());
-      message.setField(f("optional_import_message"),
-        newBuilderForField(message, f("optional_import_message"))
-               .setField(importD, 120).build());
-      message.setField(f("optional_public_import_message"),
-        newBuilderForField(message, f("optional_public_import_message"))
-               .setField(importE, 126).build());
-      message.setField(f("optional_lazy_message"),
-        newBuilderForField(message, f("optional_lazy_message"))
-               .setField(nestedB, 127).build());
-
-      message.setField(f("optional_nested_enum" ),  nestedBaz);
-      message.setField(f("optional_foreign_enum"), foreignBaz);
-      message.setField(f("optional_import_enum" ),  importBaz);
-
-      message.setField(f("optional_string_piece" ), "124");
-      message.setField(f("optional_cord" ), "125");
-
-      // -----------------------------------------------------------------
-
-      message.addRepeatedField(f("repeated_int32"   ), 201 );
-      message.addRepeatedField(f("repeated_int64"   ), 202L);
-      message.addRepeatedField(f("repeated_uint32"  ), 203 );
-      message.addRepeatedField(f("repeated_uint64"  ), 204L);
-      message.addRepeatedField(f("repeated_sint32"  ), 205 );
-      message.addRepeatedField(f("repeated_sint64"  ), 206L);
-      message.addRepeatedField(f("repeated_fixed32" ), 207 );
-      message.addRepeatedField(f("repeated_fixed64" ), 208L);
-      message.addRepeatedField(f("repeated_sfixed32"), 209 );
-      message.addRepeatedField(f("repeated_sfixed64"), 210L);
-      message.addRepeatedField(f("repeated_float"   ), 211F);
-      message.addRepeatedField(f("repeated_double"  ), 212D);
-      message.addRepeatedField(f("repeated_bool"    ), true);
-      message.addRepeatedField(f("repeated_string"  ), "215");
-      message.addRepeatedField(f("repeated_bytes"   ), toBytes("216"));
-
-      message.addRepeatedField(f("repeatedgroup"),
-        newBuilderForField(message, f("repeatedgroup"))
-               .setField(repeatedGroupA, 217).build());
-      message.addRepeatedField(f("repeated_nested_message"),
-        newBuilderForField(message, f("repeated_nested_message"))
-               .setField(nestedB, 218).build());
-      message.addRepeatedField(f("repeated_foreign_message"),
-        newBuilderForField(message, f("repeated_foreign_message"))
-               .setField(foreignC, 219).build());
-      message.addRepeatedField(f("repeated_import_message"),
-        newBuilderForField(message, f("repeated_import_message"))
-               .setField(importD, 220).build());
-      message.addRepeatedField(f("repeated_lazy_message"),
-        newBuilderForField(message, f("repeated_lazy_message"))
-               .setField(nestedB, 227).build());
-
-      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBar);
-      message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
-      message.addRepeatedField(f("repeated_import_enum" ),  importBar);
-
-      message.addRepeatedField(f("repeated_string_piece" ), "224");
-      message.addRepeatedField(f("repeated_cord" ), "225");
-
-      // Add a second one of each field.
-      message.addRepeatedField(f("repeated_int32"   ), 301 );
-      message.addRepeatedField(f("repeated_int64"   ), 302L);
-      message.addRepeatedField(f("repeated_uint32"  ), 303 );
-      message.addRepeatedField(f("repeated_uint64"  ), 304L);
-      message.addRepeatedField(f("repeated_sint32"  ), 305 );
-      message.addRepeatedField(f("repeated_sint64"  ), 306L);
-      message.addRepeatedField(f("repeated_fixed32" ), 307 );
-      message.addRepeatedField(f("repeated_fixed64" ), 308L);
-      message.addRepeatedField(f("repeated_sfixed32"), 309 );
-      message.addRepeatedField(f("repeated_sfixed64"), 310L);
-      message.addRepeatedField(f("repeated_float"   ), 311F);
-      message.addRepeatedField(f("repeated_double"  ), 312D);
-      message.addRepeatedField(f("repeated_bool"    ), false);
-      message.addRepeatedField(f("repeated_string"  ), "315");
-      message.addRepeatedField(f("repeated_bytes"   ), toBytes("316"));
-
-      message.addRepeatedField(f("repeatedgroup"),
-        newBuilderForField(message, f("repeatedgroup"))
-               .setField(repeatedGroupA, 317).build());
-      message.addRepeatedField(f("repeated_nested_message"),
-        newBuilderForField(message, f("repeated_nested_message"))
-               .setField(nestedB, 318).build());
-      message.addRepeatedField(f("repeated_foreign_message"),
-        newBuilderForField(message, f("repeated_foreign_message"))
-               .setField(foreignC, 319).build());
-      message.addRepeatedField(f("repeated_import_message"),
-        newBuilderForField(message, f("repeated_import_message"))
-               .setField(importD, 320).build());
-      message.addRepeatedField(f("repeated_lazy_message"),
-        newBuilderForField(message, f("repeated_lazy_message"))
-               .setField(nestedB, 327).build());
-
-      message.addRepeatedField(f("repeated_nested_enum" ),  nestedBaz);
-      message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
-      message.addRepeatedField(f("repeated_import_enum" ),  importBaz);
-
-      message.addRepeatedField(f("repeated_string_piece" ), "324");
-      message.addRepeatedField(f("repeated_cord" ), "325");
-
-      // -----------------------------------------------------------------
-
-      message.setField(f("default_int32"   ), 401 );
-      message.setField(f("default_int64"   ), 402L);
-      message.setField(f("default_uint32"  ), 403 );
-      message.setField(f("default_uint64"  ), 404L);
-      message.setField(f("default_sint32"  ), 405 );
-      message.setField(f("default_sint64"  ), 406L);
-      message.setField(f("default_fixed32" ), 407 );
-      message.setField(f("default_fixed64" ), 408L);
-      message.setField(f("default_sfixed32"), 409 );
-      message.setField(f("default_sfixed64"), 410L);
-      message.setField(f("default_float"   ), 411F);
-      message.setField(f("default_double"  ), 412D);
-      message.setField(f("default_bool"    ), false);
-      message.setField(f("default_string"  ), "415");
-      message.setField(f("default_bytes"   ), toBytes("416"));
-
-      message.setField(f("default_nested_enum" ),  nestedFoo);
-      message.setField(f("default_foreign_enum"), foreignFoo);
-      message.setField(f("default_import_enum" ),  importFoo);
-
-      message.setField(f("default_string_piece" ), "424");
-      message.setField(f("default_cord" ), "425");
-
-      message.setField(f("oneof_uint32" ), 601);
-      message.setField(f("oneof_nested_message"),
-        newBuilderForField(message, f("oneof_nested_message"))
-          .setField(nestedB, 602).build());
-      message.setField(f("oneof_string" ), "603");
-      message.setField(f("oneof_bytes" ), toBytes("604"));
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
-     * Modify the repeated fields of {@code message} to contain the values
-     * expected by {@code assertRepeatedFieldsModified()}, using the
-     * {@link Message.Builder} reflection interface.
-     */
-    void modifyRepeatedFieldsViaReflection(Message.Builder message) {
-      message.setRepeatedField(f("repeated_int32"   ), 1, 501 );
-      message.setRepeatedField(f("repeated_int64"   ), 1, 502L);
-      message.setRepeatedField(f("repeated_uint32"  ), 1, 503 );
-      message.setRepeatedField(f("repeated_uint64"  ), 1, 504L);
-      message.setRepeatedField(f("repeated_sint32"  ), 1, 505 );
-      message.setRepeatedField(f("repeated_sint64"  ), 1, 506L);
-      message.setRepeatedField(f("repeated_fixed32" ), 1, 507 );
-      message.setRepeatedField(f("repeated_fixed64" ), 1, 508L);
-      message.setRepeatedField(f("repeated_sfixed32"), 1, 509 );
-      message.setRepeatedField(f("repeated_sfixed64"), 1, 510L);
-      message.setRepeatedField(f("repeated_float"   ), 1, 511F);
-      message.setRepeatedField(f("repeated_double"  ), 1, 512D);
-      message.setRepeatedField(f("repeated_bool"    ), 1, true);
-      message.setRepeatedField(f("repeated_string"  ), 1, "515");
-      message.setRepeatedField(f("repeated_bytes"   ), 1, toBytes("516"));
-
-      message.setRepeatedField(f("repeatedgroup"), 1,
-        newBuilderForField(message, f("repeatedgroup"))
-               .setField(repeatedGroupA, 517).build());
-      message.setRepeatedField(f("repeated_nested_message"), 1,
-        newBuilderForField(message, f("repeated_nested_message"))
-               .setField(nestedB, 518).build());
-      message.setRepeatedField(f("repeated_foreign_message"), 1,
-        newBuilderForField(message, f("repeated_foreign_message"))
-               .setField(foreignC, 519).build());
-      message.setRepeatedField(f("repeated_import_message"), 1,
-        newBuilderForField(message, f("repeated_import_message"))
-               .setField(importD, 520).build());
-      message.setRepeatedField(f("repeated_lazy_message"), 1,
-        newBuilderForField(message, f("repeated_lazy_message"))
-               .setField(nestedB, 527).build());
-
-      message.setRepeatedField(f("repeated_nested_enum" ), 1,  nestedFoo);
-      message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
-      message.setRepeatedField(f("repeated_import_enum" ), 1,  importFoo);
-
-      message.setRepeatedField(f("repeated_string_piece"), 1, "524");
-      message.setRepeatedField(f("repeated_cord"), 1, "525");
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
-     * Assert (using {@code junit.framework.Assert}} that all fields of
-     * {@code message} are set to the values assigned by {@code setAllFields},
-     * using the {@link Message} reflection interface.
-     */
-    public void assertAllFieldsSetViaReflection(MessageOrBuilder message) {
-      Assert.assertTrue(message.hasField(f("optional_int32"   )));
-      Assert.assertTrue(message.hasField(f("optional_int64"   )));
-      Assert.assertTrue(message.hasField(f("optional_uint32"  )));
-      Assert.assertTrue(message.hasField(f("optional_uint64"  )));
-      Assert.assertTrue(message.hasField(f("optional_sint32"  )));
-      Assert.assertTrue(message.hasField(f("optional_sint64"  )));
-      Assert.assertTrue(message.hasField(f("optional_fixed32" )));
-      Assert.assertTrue(message.hasField(f("optional_fixed64" )));
-      Assert.assertTrue(message.hasField(f("optional_sfixed32")));
-      Assert.assertTrue(message.hasField(f("optional_sfixed64")));
-      Assert.assertTrue(message.hasField(f("optional_float"   )));
-      Assert.assertTrue(message.hasField(f("optional_double"  )));
-      Assert.assertTrue(message.hasField(f("optional_bool"    )));
-      Assert.assertTrue(message.hasField(f("optional_string"  )));
-      Assert.assertTrue(message.hasField(f("optional_bytes"   )));
-
-      Assert.assertTrue(message.hasField(f("optionalgroup"           )));
-      Assert.assertTrue(message.hasField(f("optional_nested_message" )));
-      Assert.assertTrue(message.hasField(f("optional_foreign_message")));
-      Assert.assertTrue(message.hasField(f("optional_import_message" )));
-
-      Assert.assertTrue(
-        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
-      Assert.assertTrue(
-        ((Message)message.getField(f("optional_nested_message")))
-                         .hasField(nestedB));
-      Assert.assertTrue(
-        ((Message)message.getField(f("optional_foreign_message")))
-                         .hasField(foreignC));
-      Assert.assertTrue(
-        ((Message)message.getField(f("optional_import_message")))
-                         .hasField(importD));
-
-      Assert.assertTrue(message.hasField(f("optional_nested_enum" )));
-      Assert.assertTrue(message.hasField(f("optional_foreign_enum")));
-      Assert.assertTrue(message.hasField(f("optional_import_enum" )));
-
-      Assert.assertTrue(message.hasField(f("optional_string_piece")));
-      Assert.assertTrue(message.hasField(f("optional_cord")));
-
-      Assert.assertEquals(101  , message.getField(f("optional_int32"   )));
-      Assert.assertEquals(102L , message.getField(f("optional_int64"   )));
-      Assert.assertEquals(103  , message.getField(f("optional_uint32"  )));
-      Assert.assertEquals(104L , message.getField(f("optional_uint64"  )));
-      Assert.assertEquals(105  , message.getField(f("optional_sint32"  )));
-      Assert.assertEquals(106L , message.getField(f("optional_sint64"  )));
-      Assert.assertEquals(107  , message.getField(f("optional_fixed32" )));
-      Assert.assertEquals(108L , message.getField(f("optional_fixed64" )));
-      Assert.assertEquals(109  , message.getField(f("optional_sfixed32")));
-      Assert.assertEquals(110L , message.getField(f("optional_sfixed64")));
-      Assert.assertEquals(111F , message.getField(f("optional_float"   )));
-      Assert.assertEquals(112D , message.getField(f("optional_double"  )));
-      Assert.assertEquals(true , message.getField(f("optional_bool"    )));
-      Assert.assertEquals("115", message.getField(f("optional_string"  )));
-      Assert.assertEquals(toBytes("116"), message.getField(f("optional_bytes")));
-
-      Assert.assertEquals(117,
-        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
-      Assert.assertEquals(118,
-        ((Message)message.getField(f("optional_nested_message")))
-                         .getField(nestedB));
-      Assert.assertEquals(119,
-        ((Message)message.getField(f("optional_foreign_message")))
-                         .getField(foreignC));
-      Assert.assertEquals(120,
-        ((Message)message.getField(f("optional_import_message")))
-                         .getField(importD));
-      Assert.assertEquals(126,
-        ((Message)message.getField(f("optional_public_import_message")))
-                         .getField(importE));
-      Assert.assertEquals(127,
-        ((Message)message.getField(f("optional_lazy_message")))
-                         .getField(nestedB));
-
-      Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
-      Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
-      Assert.assertEquals( importBaz, message.getField(f("optional_import_enum" )));
-
-      Assert.assertEquals("124", message.getField(f("optional_string_piece")));
-      Assert.assertEquals("125", message.getField(f("optional_cord")));
-
-      // -----------------------------------------------------------------
-
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
-
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
-
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
-
-      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
-      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
-      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
-      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
-      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
-      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
-      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
-      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
-      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
-      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
-      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
-      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
-      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
-      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
-      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
-
-      Assert.assertEquals(217,
-        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
-                         .getField(repeatedGroupA));
-      Assert.assertEquals(218,
-        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
-                         .getField(nestedB));
-      Assert.assertEquals(219,
-        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
-                         .getField(foreignC));
-      Assert.assertEquals(220,
-        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
-                         .getField(importD));
-      Assert.assertEquals(227,
-        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
-                         .getField(nestedB));
-
-      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
-      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
-      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
-
-      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
-      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
-
-      Assert.assertEquals(301  , message.getRepeatedField(f("repeated_int32"   ), 1));
-      Assert.assertEquals(302L , message.getRepeatedField(f("repeated_int64"   ), 1));
-      Assert.assertEquals(303  , message.getRepeatedField(f("repeated_uint32"  ), 1));
-      Assert.assertEquals(304L , message.getRepeatedField(f("repeated_uint64"  ), 1));
-      Assert.assertEquals(305  , message.getRepeatedField(f("repeated_sint32"  ), 1));
-      Assert.assertEquals(306L , message.getRepeatedField(f("repeated_sint64"  ), 1));
-      Assert.assertEquals(307  , message.getRepeatedField(f("repeated_fixed32" ), 1));
-      Assert.assertEquals(308L , message.getRepeatedField(f("repeated_fixed64" ), 1));
-      Assert.assertEquals(309  , message.getRepeatedField(f("repeated_sfixed32"), 1));
-      Assert.assertEquals(310L , message.getRepeatedField(f("repeated_sfixed64"), 1));
-      Assert.assertEquals(311F , message.getRepeatedField(f("repeated_float"   ), 1));
-      Assert.assertEquals(312D , message.getRepeatedField(f("repeated_double"  ), 1));
-      Assert.assertEquals(false, message.getRepeatedField(f("repeated_bool"    ), 1));
-      Assert.assertEquals("315", message.getRepeatedField(f("repeated_string"  ), 1));
-      Assert.assertEquals(toBytes("316"), message.getRepeatedField(f("repeated_bytes"), 1));
-
-      Assert.assertEquals(317,
-        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
-                         .getField(repeatedGroupA));
-      Assert.assertEquals(318,
-        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
-                         .getField(nestedB));
-      Assert.assertEquals(319,
-        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
-                         .getField(foreignC));
-      Assert.assertEquals(320,
-        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
-                         .getField(importD));
-      Assert.assertEquals(327,
-        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
-                         .getField(nestedB));
-
-      Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
-      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
-      Assert.assertEquals( importBaz, message.getRepeatedField(f("repeated_import_enum" ),1));
-
-      Assert.assertEquals("324", message.getRepeatedField(f("repeated_string_piece"), 1));
-      Assert.assertEquals("325", message.getRepeatedField(f("repeated_cord"), 1));
-
-      // -----------------------------------------------------------------
-
-      Assert.assertTrue(message.hasField(f("default_int32"   )));
-      Assert.assertTrue(message.hasField(f("default_int64"   )));
-      Assert.assertTrue(message.hasField(f("default_uint32"  )));
-      Assert.assertTrue(message.hasField(f("default_uint64"  )));
-      Assert.assertTrue(message.hasField(f("default_sint32"  )));
-      Assert.assertTrue(message.hasField(f("default_sint64"  )));
-      Assert.assertTrue(message.hasField(f("default_fixed32" )));
-      Assert.assertTrue(message.hasField(f("default_fixed64" )));
-      Assert.assertTrue(message.hasField(f("default_sfixed32")));
-      Assert.assertTrue(message.hasField(f("default_sfixed64")));
-      Assert.assertTrue(message.hasField(f("default_float"   )));
-      Assert.assertTrue(message.hasField(f("default_double"  )));
-      Assert.assertTrue(message.hasField(f("default_bool"    )));
-      Assert.assertTrue(message.hasField(f("default_string"  )));
-      Assert.assertTrue(message.hasField(f("default_bytes"   )));
-
-      Assert.assertTrue(message.hasField(f("default_nested_enum" )));
-      Assert.assertTrue(message.hasField(f("default_foreign_enum")));
-      Assert.assertTrue(message.hasField(f("default_import_enum" )));
-
-      Assert.assertTrue(message.hasField(f("default_string_piece")));
-      Assert.assertTrue(message.hasField(f("default_cord")));
-
-      Assert.assertEquals(401  , message.getField(f("default_int32"   )));
-      Assert.assertEquals(402L , message.getField(f("default_int64"   )));
-      Assert.assertEquals(403  , message.getField(f("default_uint32"  )));
-      Assert.assertEquals(404L , message.getField(f("default_uint64"  )));
-      Assert.assertEquals(405  , message.getField(f("default_sint32"  )));
-      Assert.assertEquals(406L , message.getField(f("default_sint64"  )));
-      Assert.assertEquals(407  , message.getField(f("default_fixed32" )));
-      Assert.assertEquals(408L , message.getField(f("default_fixed64" )));
-      Assert.assertEquals(409  , message.getField(f("default_sfixed32")));
-      Assert.assertEquals(410L , message.getField(f("default_sfixed64")));
-      Assert.assertEquals(411F , message.getField(f("default_float"   )));
-      Assert.assertEquals(412D , message.getField(f("default_double"  )));
-      Assert.assertEquals(false, message.getField(f("default_bool"    )));
-      Assert.assertEquals("415", message.getField(f("default_string"  )));
-      Assert.assertEquals(toBytes("416"), message.getField(f("default_bytes")));
-
-      Assert.assertEquals( nestedFoo, message.getField(f("default_nested_enum" )));
-      Assert.assertEquals(foreignFoo, message.getField(f("default_foreign_enum")));
-      Assert.assertEquals( importFoo, message.getField(f("default_import_enum" )));
-
-      Assert.assertEquals("424", message.getField(f("default_string_piece")));
-      Assert.assertEquals("425", message.getField(f("default_cord")));
-
-      Assert.assertTrue(message.hasField(f("oneof_bytes")));
-      Assert.assertEquals(toBytes("604"), message.getField(f("oneof_bytes")));
-
-      if (extensionRegistry == null) {
-        Assert.assertFalse(message.hasField(f("oneof_uint32")));
-        Assert.assertFalse(message.hasField(f("oneof_nested_message")));
-        Assert.assertFalse(message.hasField(f("oneof_string")));
-      } else {
-        Assert.assertTrue(message.hasField(f("oneof_uint32")));
-        Assert.assertTrue(message.hasField(f("oneof_nested_message")));
-        Assert.assertTrue(message.hasField(f("oneof_string")));
-        Assert.assertEquals(601, message.getField(f("oneof_uint32")));
-        Assert.assertEquals(602,
-            ((MessageOrBuilder) message.getField(f("oneof_nested_message")))
-            .getField(nestedB));
-        Assert.assertEquals("603", message.getField(f("oneof_string")));
-      }
-    }
-
-    // -------------------------------------------------------------------
-
-    /**
-     * Assert (using {@code junit.framework.Assert}} that all fields of
-     * {@code message} are cleared, and that getting the fields returns their
-     * default values, using the {@link Message} reflection interface.
-     */
-    public void assertClearViaReflection(MessageOrBuilder message) {
-      // has_blah() should initially be false for all optional fields.
-      Assert.assertFalse(message.hasField(f("optional_int32"   )));
-      Assert.assertFalse(message.hasField(f("optional_int64"   )));
-      Assert.assertFalse(message.hasField(f("optional_uint32"  )));
-      Assert.assertFalse(message.hasField(f("optional_uint64"  )));
-      Assert.assertFalse(message.hasField(f("optional_sint32"  )));
-      Assert.assertFalse(message.hasField(f("optional_sint64"  )));
-      Assert.assertFalse(message.hasField(f("optional_fixed32" )));
-      Assert.assertFalse(message.hasField(f("optional_fixed64" )));
-      Assert.assertFalse(message.hasField(f("optional_sfixed32")));
-      Assert.assertFalse(message.hasField(f("optional_sfixed64")));
-      Assert.assertFalse(message.hasField(f("optional_float"   )));
-      Assert.assertFalse(message.hasField(f("optional_double"  )));
-      Assert.assertFalse(message.hasField(f("optional_bool"    )));
-      Assert.assertFalse(message.hasField(f("optional_string"  )));
-      Assert.assertFalse(message.hasField(f("optional_bytes"   )));
-
-      Assert.assertFalse(message.hasField(f("optionalgroup"           )));
-      Assert.assertFalse(message.hasField(f("optional_nested_message" )));
-      Assert.assertFalse(message.hasField(f("optional_foreign_message")));
-      Assert.assertFalse(message.hasField(f("optional_import_message" )));
-
-      Assert.assertFalse(message.hasField(f("optional_nested_enum" )));
-      Assert.assertFalse(message.hasField(f("optional_foreign_enum")));
-      Assert.assertFalse(message.hasField(f("optional_import_enum" )));
-
-      Assert.assertFalse(message.hasField(f("optional_string_piece")));
-      Assert.assertFalse(message.hasField(f("optional_cord")));
-
-      // Optional fields without defaults are set to zero or something like it.
-      Assert.assertEquals(0    , message.getField(f("optional_int32"   )));
-      Assert.assertEquals(0L   , message.getField(f("optional_int64"   )));
-      Assert.assertEquals(0    , message.getField(f("optional_uint32"  )));
-      Assert.assertEquals(0L   , message.getField(f("optional_uint64"  )));
-      Assert.assertEquals(0    , message.getField(f("optional_sint32"  )));
-      Assert.assertEquals(0L   , message.getField(f("optional_sint64"  )));
-      Assert.assertEquals(0    , message.getField(f("optional_fixed32" )));
-      Assert.assertEquals(0L   , message.getField(f("optional_fixed64" )));
-      Assert.assertEquals(0    , message.getField(f("optional_sfixed32")));
-      Assert.assertEquals(0L   , message.getField(f("optional_sfixed64")));
-      Assert.assertEquals(0F   , message.getField(f("optional_float"   )));
-      Assert.assertEquals(0D   , message.getField(f("optional_double"  )));
-      Assert.assertEquals(false, message.getField(f("optional_bool"    )));
-      Assert.assertEquals(""   , message.getField(f("optional_string"  )));
-      Assert.assertEquals(ByteString.EMPTY, message.getField(f("optional_bytes")));
-
-      // Embedded messages should also be clear.
-      Assert.assertFalse(
-        ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
-      Assert.assertFalse(
-        ((Message)message.getField(f("optional_nested_message")))
-                         .hasField(nestedB));
-      Assert.assertFalse(
-        ((Message)message.getField(f("optional_foreign_message")))
-                         .hasField(foreignC));
-      Assert.assertFalse(
-        ((Message)message.getField(f("optional_import_message")))
-                         .hasField(importD));
-      Assert.assertFalse(
-        ((Message)message.getField(f("optional_public_import_message")))
-                         .hasField(importE));
-      Assert.assertFalse(
-        ((Message)message.getField(f("optional_lazy_message")))
-                         .hasField(nestedB));
-
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optionalgroup"))).getField(groupA));
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optional_nested_message")))
-                         .getField(nestedB));
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optional_foreign_message")))
-                         .getField(foreignC));
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optional_import_message")))
-                         .getField(importD));
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optional_public_import_message")))
-                         .getField(importE));
-      Assert.assertEquals(0,
-        ((Message)message.getField(f("optional_lazy_message")))
-                         .getField(nestedB));
-
-      // Enums without defaults are set to the first value in the enum.
-      Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
-      Assert.assertEquals(foreignFoo, message.getField(f("optional_foreign_enum")));
-      Assert.assertEquals( importFoo, message.getField(f("optional_import_enum" )));
-
-      Assert.assertEquals("", message.getField(f("optional_string_piece")));
-      Assert.assertEquals("", message.getField(f("optional_cord")));
-
-      // Repeated fields are empty.
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int32"   )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int64"   )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint32"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint64"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint32"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint64"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed32" )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed64" )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed32")));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed64")));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_float"   )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_double"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bool"    )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string"  )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bytes"   )));
-
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeatedgroup"           )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
-
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string_piece")));
-      Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_cord")));
-
-      // has_blah() should also be false for all default fields.
-      Assert.assertFalse(message.hasField(f("default_int32"   )));
-      Assert.assertFalse(message.hasField(f("default_int64"   )));
-      Assert.assertFalse(message.hasField(f("default_uint32"  )));
-      Assert.assertFalse(message.hasField(f("default_uint64"  )));
-      Assert.assertFalse(message.hasField(f("default_sint32"  )));
-      Assert.assertFalse(message.hasField(f("default_sint64"  )));
-      Assert.assertFalse(message.hasField(f("default_fixed32" )));
-      Assert.assertFalse(message.hasField(f("default_fixed64" )));
-      Assert.assertFalse(message.hasField(f("default_sfixed32")));
-      Assert.assertFalse(message.hasField(f("default_sfixed64")));
-      Assert.assertFalse(message.hasField(f("default_float"   )));
-      Assert.assertFalse(message.hasField(f("default_double"  )));
-      Assert.assertFalse(message.hasField(f("default_bool"    )));
-      Assert.assertFalse(message.hasField(f("default_string"  )));
-      Assert.assertFalse(message.hasField(f("default_bytes"   )));
-
-      Assert.assertFalse(message.hasField(f("default_nested_enum" )));
-      Assert.assertFalse(message.hasField(f("default_foreign_enum")));
-      Assert.assertFalse(message.hasField(f("default_import_enum" )));
-
-      Assert.assertFalse(message.hasField(f("default_string_piece" )));
-      Assert.assertFalse(message.hasField(f("default_cord" )));
-
-      // Fields with defaults have their default values (duh).
-      Assert.assertEquals( 41    , message.getField(f("default_int32"   )));
-      Assert.assertEquals( 42L   , message.getField(f("default_int64"   )));
-      Assert.assertEquals( 43    , message.getField(f("default_uint32"  )));
-      Assert.assertEquals( 44L   , message.getField(f("default_uint64"  )));
-      Assert.assertEquals(-45    , message.getField(f("default_sint32"  )));
-      Assert.assertEquals( 46L   , message.getField(f("default_sint64"  )));
-      Assert.assertEquals( 47    , message.getField(f("default_fixed32" )));
-      Assert.assertEquals( 48L   , message.getField(f("default_fixed64" )));
-      Assert.assertEquals( 49    , message.getField(f("default_sfixed32")));
-      Assert.assertEquals(-50L   , message.getField(f("default_sfixed64")));
-      Assert.assertEquals( 51.5F , message.getField(f("default_float"   )));
-      Assert.assertEquals( 52e3D , message.getField(f("default_double"  )));
-      Assert.assertEquals(true   , message.getField(f("default_bool"    )));
-      Assert.assertEquals("hello", message.getField(f("default_string"  )));
-      Assert.assertEquals(toBytes("world"), message.getField(f("default_bytes")));
-
-      Assert.assertEquals( nestedBar, message.getField(f("default_nested_enum" )));
-      Assert.assertEquals(foreignBar, message.getField(f("default_foreign_enum")));
-      Assert.assertEquals( importBar, message.getField(f("default_import_enum" )));
-
-      Assert.assertEquals("abc", message.getField(f("default_string_piece")));
-      Assert.assertEquals("123", message.getField(f("default_cord")));
-
-      Assert.assertFalse(message.hasField(f("oneof_uint32")));
-      Assert.assertFalse(message.hasField(f("oneof_nested_message")));
-      Assert.assertFalse(message.hasField(f("oneof_string")));
-      Assert.assertFalse(message.hasField(f("oneof_bytes")));
-
-      Assert.assertEquals(0, message.getField(f("oneof_uint32")));
-      Assert.assertEquals("", message.getField(f("oneof_string")));
-      Assert.assertEquals(toBytes(""), message.getField(f("oneof_bytes")));
-    }
-
-
-    // ---------------------------------------------------------------
-
-    public void assertRepeatedFieldsModifiedViaReflection(
-        MessageOrBuilder message) {
-      // ModifyRepeatedFields only sets the second repeated element of each
-      // field.  In addition to verifying this, we also verify that the first
-      // element and size were *not* modified.
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool"    )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes"   )));
-
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup"           )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_lazy_message"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum"    )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum"    )));
-
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
-
-      Assert.assertEquals(201  , message.getRepeatedField(f("repeated_int32"   ), 0));
-      Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64"   ), 0));
-      Assert.assertEquals(203  , message.getRepeatedField(f("repeated_uint32"  ), 0));
-      Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64"  ), 0));
-      Assert.assertEquals(205  , message.getRepeatedField(f("repeated_sint32"  ), 0));
-      Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64"  ), 0));
-      Assert.assertEquals(207  , message.getRepeatedField(f("repeated_fixed32" ), 0));
-      Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
-      Assert.assertEquals(209  , message.getRepeatedField(f("repeated_sfixed32"), 0));
-      Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
-      Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float"   ), 0));
-      Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double"  ), 0));
-      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 0));
-      Assert.assertEquals("215", message.getRepeatedField(f("repeated_string"  ), 0));
-      Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
-
-      Assert.assertEquals(217,
-        ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
-                         .getField(repeatedGroupA));
-      Assert.assertEquals(218,
-        ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
-                         .getField(nestedB));
-      Assert.assertEquals(219,
-        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
-                         .getField(foreignC));
-      Assert.assertEquals(220,
-        ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
-                         .getField(importD));
-      Assert.assertEquals(227,
-        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 0))
-                         .getField(nestedB));
-
-      Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
-      Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
-      Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
-
-      Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
-      Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
-
-      Assert.assertEquals(501  , message.getRepeatedField(f("repeated_int32"   ), 1));
-      Assert.assertEquals(502L , message.getRepeatedField(f("repeated_int64"   ), 1));
-      Assert.assertEquals(503  , message.getRepeatedField(f("repeated_uint32"  ), 1));
-      Assert.assertEquals(504L , message.getRepeatedField(f("repeated_uint64"  ), 1));
-      Assert.assertEquals(505  , message.getRepeatedField(f("repeated_sint32"  ), 1));
-      Assert.assertEquals(506L , message.getRepeatedField(f("repeated_sint64"  ), 1));
-      Assert.assertEquals(507  , message.getRepeatedField(f("repeated_fixed32" ), 1));
-      Assert.assertEquals(508L , message.getRepeatedField(f("repeated_fixed64" ), 1));
-      Assert.assertEquals(509  , message.getRepeatedField(f("repeated_sfixed32"), 1));
-      Assert.assertEquals(510L , message.getRepeatedField(f("repeated_sfixed64"), 1));
-      Assert.assertEquals(511F , message.getRepeatedField(f("repeated_float"   ), 1));
-      Assert.assertEquals(512D , message.getRepeatedField(f("repeated_double"  ), 1));
-      Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool"    ), 1));
-      Assert.assertEquals("515", message.getRepeatedField(f("repeated_string"  ), 1));
-      Assert.assertEquals(toBytes("516"), message.getRepeatedField(f("repeated_bytes"), 1));
-
-      Assert.assertEquals(517,
-        ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
-                         .getField(repeatedGroupA));
-      Assert.assertEquals(518,
-        ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
-                         .getField(nestedB));
-      Assert.assertEquals(519,
-        ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
-                         .getField(foreignC));
-      Assert.assertEquals(520,
-        ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
-                         .getField(importD));
-      Assert.assertEquals(527,
-        ((Message)message.getRepeatedField(f("repeated_lazy_message"), 1))
-                         .getField(nestedB));
-
-      Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
-      Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
-      Assert.assertEquals( importFoo, message.getRepeatedField(f("repeated_import_enum" ),1));
-
-      Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1));
-      Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1));
-    }
-
-    public void setPackedFieldsViaReflection(Message.Builder message) {
-      message.addRepeatedField(f("packed_int32"   ), 601 );
-      message.addRepeatedField(f("packed_int64"   ), 602L);
-      message.addRepeatedField(f("packed_uint32"  ), 603 );
-      message.addRepeatedField(f("packed_uint64"  ), 604L);
-      message.addRepeatedField(f("packed_sint32"  ), 605 );
-      message.addRepeatedField(f("packed_sint64"  ), 606L);
-      message.addRepeatedField(f("packed_fixed32" ), 607 );
-      message.addRepeatedField(f("packed_fixed64" ), 608L);
-      message.addRepeatedField(f("packed_sfixed32"), 609 );
-      message.addRepeatedField(f("packed_sfixed64"), 610L);
-      message.addRepeatedField(f("packed_float"   ), 611F);
-      message.addRepeatedField(f("packed_double"  ), 612D);
-      message.addRepeatedField(f("packed_bool"    ), true);
-      message.addRepeatedField(f("packed_enum" ),  foreignBar);
-      // Add a second one of each field.
-      message.addRepeatedField(f("packed_int32"   ), 701 );
-      message.addRepeatedField(f("packed_int64"   ), 702L);
-      message.addRepeatedField(f("packed_uint32"  ), 703 );
-      message.addRepeatedField(f("packed_uint64"  ), 704L);
-      message.addRepeatedField(f("packed_sint32"  ), 705 );
-      message.addRepeatedField(f("packed_sint64"  ), 706L);
-      message.addRepeatedField(f("packed_fixed32" ), 707 );
-      message.addRepeatedField(f("packed_fixed64" ), 708L);
-      message.addRepeatedField(f("packed_sfixed32"), 709 );
-      message.addRepeatedField(f("packed_sfixed64"), 710L);
-      message.addRepeatedField(f("packed_float"   ), 711F);
-      message.addRepeatedField(f("packed_double"  ), 712D);
-      message.addRepeatedField(f("packed_bool"    ), false);
-      message.addRepeatedField(f("packed_enum" ),  foreignBaz);
-    }
-
-    public void assertPackedFieldsSetViaReflection(MessageOrBuilder message) {
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int32"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int64"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint32"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint64"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed32" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed64" )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed32")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed64")));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_float"   )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_double"  )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_bool"    )));
-      Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_enum"   )));
-      Assert.assertEquals(601  , message.getRepeatedField(f("packed_int32"   ), 0));
-      Assert.assertEquals(602L , message.getRepeatedField(f("packed_int64"   ), 0));
-      Assert.assertEquals(603  , message.getRepeatedField(f("packed_uint32"  ), 0));
-      Assert.assertEquals(604L , message.getRepeatedField(f("packed_uint64"  ), 0));
-      Assert.assertEquals(605  , message.getRepeatedField(f("packed_sint32"  ), 0));
-      Assert.assertEquals(606L , message.getRepeatedField(f("packed_sint64"  ), 0));
-      Assert.assertEquals(607  , message.getRepeatedField(f("packed_fixed32" ), 0));
-      Assert.assertEquals(608L , message.getRepeatedField(f("packed_fixed64" ), 0));
-      Assert.assertEquals(609  , message.getRepeatedField(f("packed_sfixed32"), 0));
-      Assert.assertEquals(610L , message.getRepeatedField(f("packed_sfixed64"), 0));
-      Assert.assertEquals(611F , message.getRepeatedField(f("packed_float"   ), 0));
-      Assert.assertEquals(612D , message.getRepeatedField(f("packed_double"  ), 0));
-      Assert.assertEquals(true , message.getRepeatedField(f("packed_bool"    ), 0));
-      Assert.assertEquals(foreignBar, message.getRepeatedField(f("packed_enum" ),0));
-      Assert.assertEquals(701  , message.getRepeatedField(f("packed_int32"   ), 1));
-      Assert.assertEquals(702L , message.getRepeatedField(f("packed_int64"   ), 1));
-      Assert.assertEquals(703  , message.getRepeatedField(f("packed_uint32"  ), 1));
-      Assert.assertEquals(704L , message.getRepeatedField(f("packed_uint64"  ), 1));
-      Assert.assertEquals(705  , message.getRepeatedField(f("packed_sint32"  ), 1));
-      Assert.assertEquals(706L , message.getRepeatedField(f("packed_sint64"  ), 1));
-      Assert.assertEquals(707  , message.getRepeatedField(f("packed_fixed32" ), 1));
-      Assert.assertEquals(708L , message.getRepeatedField(f("packed_fixed64" ), 1));
-      Assert.assertEquals(709  , message.getRepeatedField(f("packed_sfixed32"), 1));
-      Assert.assertEquals(710L , message.getRepeatedField(f("packed_sfixed64"), 1));
-      Assert.assertEquals(711F , message.getRepeatedField(f("packed_float"   ), 1));
-      Assert.assertEquals(712D , message.getRepeatedField(f("packed_double"  ), 1));
-      Assert.assertEquals(false, message.getRepeatedField(f("packed_bool"    ), 1));
-      Assert.assertEquals(foreignBaz, message.getRepeatedField(f("packed_enum" ),1));
-    }
-
-    /**
-     * Verifies that the reflection setters for the given.Builder object throw a
-     * NullPointerException if they are passed a null value.  Uses Assert to throw an
-     * appropriate assertion failure, if the condition is not verified.
-     */
-    public void assertReflectionSettersRejectNull(Message.Builder builder)
-        throws Exception {
-      try {
-        builder.setField(f("optional_string"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.setField(f("optional_bytes"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.setField(f("optional_nested_enum"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.setField(f("optional_nested_message"),
-                         (TestAllTypes.NestedMessage) null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.setField(f("optional_nested_message"),
-                         (TestAllTypes.NestedMessage.Builder) null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-
-      try {
-        builder.addRepeatedField(f("repeated_string"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.addRepeatedField(f("repeated_bytes"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.addRepeatedField(f("repeated_nested_enum"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-      try {
-        builder.addRepeatedField(f("repeated_nested_message"), null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-    }
-
-    /**
-     * Verifies that the reflection repeated setters for the given Builder object throw a
-     * NullPointerException if they are passed a null value.  Uses Assert to throw an appropriate
-     * assertion failure, if the condition is not verified.
-     */
-    public void assertReflectionRepeatedSettersRejectNull(Message.Builder builder)
-        throws Exception {
-      builder.addRepeatedField(f("repeated_string"), "one");
-      try {
-        builder.setRepeatedField(f("repeated_string"), 0, null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-
-      builder.addRepeatedField(f("repeated_bytes"), toBytes("one"));
-      try {
-        builder.setRepeatedField(f("repeated_bytes"), 0, null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-
-      builder.addRepeatedField(f("repeated_nested_enum"), nestedBaz);
-      try {
-        builder.setRepeatedField(f("repeated_nested_enum"), 0, null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-
-      builder.addRepeatedField(
-          f("repeated_nested_message"),
-          TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
-      try {
-        builder.setRepeatedField(f("repeated_nested_message"), 0, null);
-        Assert.fail("Exception was not thrown");
-      } catch (NullPointerException e) {
-        // We expect this exception.
-      }
-    }
-  }
-
-  /**
-   * @param filePath The path relative to
-   * {@link #getTestDataDir}.
-   */
-  public static String readTextFromFile(String filePath) {
-    return readBytesFromFile(filePath).toStringUtf8();
-  }
-
-  private static File getTestDataDir() {
-    // Search each parent directory looking for "src/google/protobuf".
-    File ancestor = new File(".");
-    try {
-      ancestor = ancestor.getCanonicalFile();
-    } catch (IOException e) {
-      throw new RuntimeException(
-        "Couldn't get canonical name of working directory.", e);
-    }
-    while (ancestor != null && ancestor.exists()) {
-      if (new File(ancestor, "src/google/protobuf").exists()) {
-        return new File(ancestor, "src/google/protobuf/testdata");
-      }
-      ancestor = ancestor.getParentFile();
-    }
-
-    throw new RuntimeException(
-      "Could not find golden files.  This test must be run from within the " +
-      "protobuf source package so that it can read test data files from the " +
-      "C++ source tree.");
-  }
-
-  /**
-   * @param filename The path relative to
-   * {@link #getTestDataDir}.
-   */
-  public static ByteString readBytesFromFile(String filename) {
-    File fullPath = new File(getTestDataDir(), filename);
-    try {
-      RandomAccessFile file = new RandomAccessFile(fullPath, "r");
-      byte[] content = new byte[(int) file.length()];
-      file.readFully(content);
-      return ByteString.copyFrom(content);
-    } catch (IOException e) {
-      // Throw a RuntimeException here so that we can call this function from
-      // static initializers.
-      throw new IllegalArgumentException(
-        "Couldn't read file: " + fullPath.getPath(), e);
-    }
-  }
-
-  /**
-   * Get the bytes of the "golden message".  This is a serialized TestAllTypes
-   * with all fields set as they would be by
-   * {@link #setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
-   * on disk rather than generated dynamically.  The file is actually generated
-   * by C++ code, so testing against it verifies compatibility with C++.
-   */
-  public static ByteString getGoldenMessage() {
-    if (goldenMessage == null) {
-      goldenMessage = readBytesFromFile("golden_message_oneof_implemented");
-    }
-    return goldenMessage;
-  }
-  private static ByteString goldenMessage = null;
-
-  /**
-   * Get the bytes of the "golden packed fields message".  This is a serialized
-   * TestPackedTypes with all fields set as they would be by
-   * {@link #setPackedFields(TestPackedTypes.Builder)}, but it is loaded from a
-   * file on disk rather than generated dynamically.  The file is actually
-   * generated by C++ code, so testing against it verifies compatibility with
-   * C++.
-   */
-  public static ByteString getGoldenPackedFieldsMessage() {
-    if (goldenPackedFieldsMessage == null) {
-      goldenPackedFieldsMessage =
-          readBytesFromFile("golden_packed_fields_message");
-    }
-    return goldenPackedFieldsMessage;
-  }
-  private static ByteString goldenPackedFieldsMessage = null;
-
-  /**
-   * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
-   *
-   * @author jonp@google.com (Jon Perlow)
-   */
-  public static class MockBuilderParent
-      implements GeneratedMessage.BuilderParent {
-
-    private int invalidations;
-
-    //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public void markDirty() {
-      invalidations++;
-    }
-
-    public int getInvalidationCount() {
-      return invalidations;
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
deleted file mode 100644
index 152bdad..0000000
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ /dev/null
@@ -1,994 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import com.google.protobuf.Descriptors.FieldDescriptor;
-import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
-import protobuf_unittest.UnittestMset.TestMessageSet;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
-import protobuf_unittest.UnittestProto.OneString;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
-import protobuf_unittest.UnittestProto.TestEmptyMessage;
-import protobuf_unittest.UnittestProto.TestOneof2;
-
-import junit.framework.TestCase;
-
-import java.io.StringReader;
-
-/**
- * Test case for {@link TextFormat}.
- *
- * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
- *
- * @author wenboz@google.com (Wenbo Zhu)
- */
-public class TextFormatTest extends TestCase {
-
-  // A basic string with different escapable characters for testing.
-  private final static String kEscapeTestString =
-      "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
-          + "slashes \\";
-
-  // A representation of the above string with all the characters escaped.
-  private final static String kEscapeTestStringEscaped =
-      "\\\"A string with \\' characters \\n and \\r newlines "
-          + "and \\t tabs and \\001 slashes \\\\";
-
-  private static String allFieldsSetText = TestUtil.readTextFromFile(
-    "text_format_unittest_data_oneof_implemented.txt");
-  private static String allExtensionsSetText = TestUtil.readTextFromFile(
-    "text_format_unittest_extensions_data.txt");
-
-  private static String exoticText =
-    "repeated_int32: -1\n" +
-    "repeated_int32: -2147483648\n" +
-    "repeated_int64: -1\n" +
-    "repeated_int64: -9223372036854775808\n" +
-    "repeated_uint32: 4294967295\n" +
-    "repeated_uint32: 2147483648\n" +
-    "repeated_uint64: 18446744073709551615\n" +
-    "repeated_uint64: 9223372036854775808\n" +
-    "repeated_double: 123.0\n" +
-    "repeated_double: 123.5\n" +
-    "repeated_double: 0.125\n" +
-    "repeated_double: .125\n" +
-    "repeated_double: -.125\n" +
-    "repeated_double: 1.23E17\n" +
-    "repeated_double: 1.23E+17\n" +
-    "repeated_double: -1.23e-17\n" +
-    "repeated_double: .23e+17\n" +
-    "repeated_double: -.23E17\n" +
-    "repeated_double: 1.235E22\n" +
-    "repeated_double: 1.235E-18\n" +
-    "repeated_double: 123.456789\n" +
-    "repeated_double: Infinity\n" +
-    "repeated_double: -Infinity\n" +
-    "repeated_double: NaN\n" +
-    "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
-      "\\341\\210\\264\"\n" +
-    "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
-
-  private static String canonicalExoticText =
-      exoticText.replace(": .", ": 0.").replace(": -.", ": -0.")   // short-form double
-      .replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16");
-
-  private String messageSetText =
-    "[protobuf_unittest.TestMessageSetExtension1] {\n" +
-    "  i: 123\n" +
-    "}\n" +
-    "[protobuf_unittest.TestMessageSetExtension2] {\n" +
-    "  str: \"foo\"\n" +
-    "}\n";
-
-  private String messageSetTextWithRepeatedExtension =
-      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
-      "  i: 123\n" +
-      "}\n" +
-      "[protobuf_unittest.TestMessageSetExtension1] {\n" +
-      "  i: 456\n" +
-      "}\n";
-
-  private final TextFormat.Parser parserWithOverwriteForbidden =
-      TextFormat.Parser.newBuilder()
-          .setSingularOverwritePolicy(
-              SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
-          .build();
-
-  private final TextFormat.Parser defaultParser =
-      TextFormat.Parser.newBuilder().build();
-
-  /** Print TestAllTypes and compare with golden file. */
-  public void testPrintMessage() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllSet());
-
-    // Java likes to add a trailing ".0" to floats and doubles.  C printf
-    // (with %g format) does not.  Our golden files are used for both
-    // C++ and Java TextFormat classes, so we need to conform.
-    javaText = javaText.replace(".0\n", "\n");
-
-    assertEquals(allFieldsSetText, javaText);
-  }
-
-  /** Print TestAllTypes as Builder and compare with golden file. */
-  public void testPrintMessageBuilder() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
-
-    // Java likes to add a trailing ".0" to floats and doubles.  C printf
-    // (with %g format) does not.  Our golden files are used for both
-    // C++ and Java TextFormat classes, so we need to conform.
-    javaText = javaText.replace(".0\n", "\n");
-
-    assertEquals(allFieldsSetText, javaText);
-  }
-
-  /** Print TestAllExtensions and compare with golden file. */
-  public void testPrintExtensions() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
-
-    // Java likes to add a trailing ".0" to floats and doubles.  C printf
-    // (with %g format) does not.  Our golden files are used for both
-    // C++ and Java TextFormat classes, so we need to conform.
-    javaText = javaText.replace(".0\n", "\n");
-
-    assertEquals(allExtensionsSetText, javaText);
-  }
-
-  // Creates an example unknown field set.
-  private UnknownFieldSet makeUnknownFieldSet() {
-    return UnknownFieldSet.newBuilder()
-        .addField(5,
-            UnknownFieldSet.Field.newBuilder()
-            .addVarint(1)
-            .addFixed32(2)
-            .addFixed64(3)
-            .addLengthDelimited(ByteString.copyFromUtf8("4"))
-            .addGroup(
-                UnknownFieldSet.newBuilder()
-                .addField(10,
-                    UnknownFieldSet.Field.newBuilder()
-                    .addVarint(5)
-                    .build())
-                .build())
-            .build())
-        .addField(8,
-            UnknownFieldSet.Field.newBuilder()
-            .addVarint(1)
-            .addVarint(2)
-            .addVarint(3)
-            .build())
-        .addField(15,
-            UnknownFieldSet.Field.newBuilder()
-            .addVarint(0xABCDEF1234567890L)
-            .addFixed32(0xABCD1234)
-            .addFixed64(0xABCDEF1234567890L)
-            .build())
-        .build();
-  }
-
-  public void testPrintUnknownFields() throws Exception {
-    // Test printing of unknown fields in a message.
-
-    TestEmptyMessage message =
-      TestEmptyMessage.newBuilder()
-        .setUnknownFields(makeUnknownFieldSet())
-        .build();
-
-    assertEquals(
-      "5: 1\n" +
-      "5: 0x00000002\n" +
-      "5: 0x0000000000000003\n" +
-      "5: \"4\"\n" +
-      "5 {\n" +
-      "  10: 5\n" +
-      "}\n" +
-      "8: 1\n" +
-      "8: 2\n" +
-      "8: 3\n" +
-      "15: 12379813812177893520\n" +
-      "15: 0xabcd1234\n" +
-      "15: 0xabcdef1234567890\n",
-      TextFormat.printToString(message));
-  }
-
-  public void testPrintField() throws Exception {
-    final FieldDescriptor dataField =
-      OneString.getDescriptor().findFieldByName("data");
-    assertEquals(
-      "data: \"test data\"\n",
-      TextFormat.printFieldToString(dataField, "test data"));
-
-    final FieldDescriptor optionalField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
-    final Object value = NestedMessage.newBuilder().setBb(42).build();
-
-    assertEquals(
-      "optional_nested_message {\n  bb: 42\n}\n",
-      TextFormat.printFieldToString(optionalField, value));
-  }
-
-  /**
-   * Helper to construct a ByteString from a String containing only 8-bit
-   * characters.  The characters are converted directly to bytes, *not*
-   * encoded using UTF-8.
-   */
-  private ByteString bytes(String str) throws Exception {
-    return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
-  }
-
-  /**
-   * Helper to construct a ByteString from a bunch of bytes.  The inputs are
-   * actually ints so that I can use hex notation and not get stupid errors
-   * about precision.
-   */
-  private ByteString bytes(int... bytesAsInts) {
-    byte[] bytes = new byte[bytesAsInts.length];
-    for (int i = 0; i < bytesAsInts.length; i++) {
-      bytes[i] = (byte) bytesAsInts[i];
-    }
-    return ByteString.copyFrom(bytes);
-  }
-
-  public void testPrintExotic() throws Exception {
-    Message message = TestAllTypes.newBuilder()
-      // Signed vs. unsigned numbers.
-      .addRepeatedInt32 (-1)
-      .addRepeatedUint32(-1)
-      .addRepeatedInt64 (-1)
-      .addRepeatedUint64(-1)
-
-      .addRepeatedInt32 (1  << 31)
-      .addRepeatedUint32(1  << 31)
-      .addRepeatedInt64 (1L << 63)
-      .addRepeatedUint64(1L << 63)
-
-      // Floats of various precisions and exponents.
-      .addRepeatedDouble(123)
-      .addRepeatedDouble(123.5)
-      .addRepeatedDouble(0.125)
-      .addRepeatedDouble(.125)
-      .addRepeatedDouble(-.125)
-      .addRepeatedDouble(123e15)
-      .addRepeatedDouble(123e15)
-      .addRepeatedDouble(-1.23e-17)
-      .addRepeatedDouble(.23e17)
-      .addRepeatedDouble(-23e15)
-      .addRepeatedDouble(123.5e20)
-      .addRepeatedDouble(123.5e-20)
-      .addRepeatedDouble(123.456789)
-      .addRepeatedDouble(Double.POSITIVE_INFINITY)
-      .addRepeatedDouble(Double.NEGATIVE_INFINITY)
-      .addRepeatedDouble(Double.NaN)
-
-      // Strings and bytes that needing escaping.
-      .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
-      .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
-      .build();
-
-    assertEquals(canonicalExoticText, message.toString());
-  }
-
-  public void testPrintMessageSet() throws Exception {
-    TestMessageSet messageSet =
-      TestMessageSet.newBuilder()
-        .setExtension(
-          TestMessageSetExtension1.messageSetExtension,
-          TestMessageSetExtension1.newBuilder().setI(123).build())
-        .setExtension(
-          TestMessageSetExtension2.messageSetExtension,
-          TestMessageSetExtension2.newBuilder().setStr("foo").build())
-        .build();
-
-    assertEquals(messageSetText, messageSet.toString());
-  }
-
-  // =================================================================
-
-  public void testParse() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(allFieldsSetText, builder);
-    TestUtil.assertAllFieldsSet(builder.build());
-  }
-
-  public void testParseReader() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(new StringReader(allFieldsSetText), builder);
-    TestUtil.assertAllFieldsSet(builder.build());
-  }
-
-  public void testParseExtensions() throws Exception {
-    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TextFormat.merge(allExtensionsSetText,
-                     TestUtil.getExtensionRegistry(),
-                     builder);
-    TestUtil.assertAllExtensionsSet(builder.build());
-  }
-
-  public void testParseCompatibility() throws Exception {
-    String original = "repeated_float: inf\n" +
-                      "repeated_float: -inf\n" +
-                      "repeated_float: nan\n" +
-                      "repeated_float: inff\n" +
-                      "repeated_float: -inff\n" +
-                      "repeated_float: nanf\n" +
-                      "repeated_float: 1.0f\n" +
-                      "repeated_float: infinityf\n" +
-                      "repeated_float: -Infinityf\n" +
-                      "repeated_double: infinity\n" +
-                      "repeated_double: -infinity\n" +
-                      "repeated_double: nan\n";
-    String canonical =  "repeated_float: Infinity\n" +
-                        "repeated_float: -Infinity\n" +
-                        "repeated_float: NaN\n" +
-                        "repeated_float: Infinity\n" +
-                        "repeated_float: -Infinity\n" +
-                        "repeated_float: NaN\n" +
-                        "repeated_float: 1.0\n" +
-                        "repeated_float: Infinity\n" +
-                        "repeated_float: -Infinity\n" +
-                        "repeated_double: Infinity\n" +
-                        "repeated_double: -Infinity\n" +
-                        "repeated_double: NaN\n";
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(original, builder);
-    assertEquals(canonical, builder.build().toString());
-  }
-
-  public void testParseExotic() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(exoticText, builder);
-
-    // Too lazy to check things individually.  Don't try to debug this
-    // if testPrintExotic() is failing.
-    assertEquals(canonicalExoticText, builder.build().toString());
-  }
-
-  public void testParseMessageSet() throws Exception {
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
-
-    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
-    TextFormat.merge(messageSetText, extensionRegistry, builder);
-    TestMessageSet messageSet = builder.build();
-
-    assertTrue(messageSet.hasExtension(
-      TestMessageSetExtension1.messageSetExtension));
-    assertEquals(123, messageSet.getExtension(
-      TestMessageSetExtension1.messageSetExtension).getI());
-    assertTrue(messageSet.hasExtension(
-      TestMessageSetExtension2.messageSetExtension));
-    assertEquals("foo", messageSet.getExtension(
-      TestMessageSetExtension2.messageSetExtension).getStr());
-
-    builder = TestMessageSet.newBuilder();
-    TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry,
-        builder);
-    messageSet = builder.build();
-    assertEquals(456, messageSet.getExtension(
-      TestMessageSetExtension1.messageSetExtension).getI());
-  }
-
-  public void testParseMessageSetWithOverwriteForbidden() throws Exception {
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
-
-    TestMessageSet.Builder builder = TestMessageSet.newBuilder();
-    parserWithOverwriteForbidden.merge(
-        messageSetText, extensionRegistry, builder);
-    TestMessageSet messageSet = builder.build();
-    assertEquals(123, messageSet.getExtension(
-        TestMessageSetExtension1.messageSetExtension).getI());
-    assertEquals("foo", messageSet.getExtension(
-      TestMessageSetExtension2.messageSetExtension).getStr());
-
-    builder = TestMessageSet.newBuilder();
-    try {
-      parserWithOverwriteForbidden.merge(
-          messageSetTextWithRepeatedExtension, extensionRegistry, builder);
-      fail("expected parse exception");
-    } catch (TextFormat.ParseException e) {
-      assertEquals("6:1: Non-repeated field "
-          + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
-          + " cannot be overwritten.",
-          e.getMessage());
-    }
-  }
-
-  public void testParseNumericEnum() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge("optional_nested_enum: 2", builder);
-    assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
-  }
-
-  public void testParseAngleBrackets() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge("OptionalGroup: < a: 1 >", builder);
-    assertTrue(builder.hasOptionalGroup());
-    assertEquals(1, builder.getOptionalGroup().getA());
-  }
-
-  public void testParseComment() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(
-      "# this is a comment\n" +
-      "optional_int32: 1  # another comment\n" +
-      "optional_int64: 2\n" +
-      "# EOF comment", builder);
-    assertEquals(1, builder.getOptionalInt32());
-    assertEquals(2, builder.getOptionalInt64());
-  }
-
-  private void assertParseError(String error, String text) {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    try {
-      TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
-      fail("Expected parse exception.");
-    } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
-    }
-  }
-
-  private void assertParseErrorWithOverwriteForbidden(String error,
-      String text) {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    try {
-      parserWithOverwriteForbidden.merge(
-          text, TestUtil.getExtensionRegistry(), builder);
-      fail("Expected parse exception.");
-    } catch (TextFormat.ParseException e) {
-      assertEquals(error, e.getMessage());
-    }
-  }
-
-  private TestAllTypes assertParseSuccessWithOverwriteForbidden(
-      String text) throws TextFormat.ParseException {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    parserWithOverwriteForbidden.merge(
-        text, TestUtil.getExtensionRegistry(), builder);
-    return builder.build();
-  }
-
-  public void testParseErrors() throws Exception {
-    assertParseError(
-      "1:16: Expected \":\".",
-      "optional_int32 123");
-    assertParseError(
-      "1:23: Expected identifier. Found '?'",
-      "optional_nested_enum: ?");
-    assertParseError(
-      "1:18: Couldn't parse integer: Number must be positive: -1",
-      "optional_uint32: -1");
-    assertParseError(
-      "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
-        "integer: 82301481290849012385230157",
-      "optional_int32: 82301481290849012385230157");
-    assertParseError(
-      "1:16: Expected \"true\" or \"false\".",
-      "optional_bool: maybe");
-    assertParseError(
-      "1:16: Expected \"true\" or \"false\".",
-      "optional_bool: 2");
-    assertParseError(
-      "1:18: Expected string.",
-      "optional_string: 123");
-    assertParseError(
-      "1:18: String missing ending quote.",
-      "optional_string: \"ueoauaoe");
-    assertParseError(
-      "1:18: String missing ending quote.",
-      "optional_string: \"ueoauaoe\n" +
-      "optional_int32: 123");
-    assertParseError(
-      "1:18: Invalid escape sequence: '\\z'",
-      "optional_string: \"\\z\"");
-    assertParseError(
-      "1:18: String missing ending quote.",
-      "optional_string: \"ueoauaoe\n" +
-      "optional_int32: 123");
-    assertParseError(
-      "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
-      "[nosuchext]: 123");
-    assertParseError(
-      "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
-        "not extend message type \"protobuf_unittest.TestAllTypes\".",
-      "[protobuf_unittest.optional_int32_extension]: 123");
-    assertParseError(
-      "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
-        "named \"nosuchfield\".",
-      "nosuchfield: 123");
-    assertParseError(
-      "1:21: Expected \">\".",
-      "OptionalGroup < a: 1");
-    assertParseError(
-      "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
-        "value named \"NO_SUCH_VALUE\".",
-      "optional_nested_enum: NO_SUCH_VALUE");
-    assertParseError(
-      "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
-        "value with number 123.",
-      "optional_nested_enum: 123");
-
-    // Delimiters must match.
-    assertParseError(
-      "1:22: Expected identifier. Found '}'",
-      "OptionalGroup < a: 1 }");
-    assertParseError(
-      "1:22: Expected identifier. Found '>'",
-      "OptionalGroup { a: 1 >");
-  }
-
-  // =================================================================
-
-  public void testEscape() throws Exception {
-    // Escape sequences.
-    assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
-      TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"")));
-    assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
-      TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\""));
-    assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
-      TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
-    assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
-      TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
-    assertEquals(kEscapeTestStringEscaped,
-      TextFormat.escapeText(kEscapeTestString));
-    assertEquals(kEscapeTestString,
-      TextFormat.unescapeText(kEscapeTestStringEscaped));
-
-    // Unicode handling.
-    assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
-    assertEquals("\\341\\210\\264",
-                 TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
-    assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4),
-                 TextFormat.unescapeBytes("\\341\\210\\264"));
-    assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
-    assertEquals(bytes(0xe1, 0x88, 0xb4),
-                 TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
-
-    // Handling of strings with unescaped Unicode characters > 255.
-    final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
-    ByteString zhByteString = ByteString.copyFromUtf8(zh);
-    assertEquals(zhByteString, TextFormat.unescapeBytes(zh));
-
-    // Errors.
-    try {
-      TextFormat.unescapeText("\\x");
-      fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequenceException e) {
-      // success
-    }
-
-    try {
-      TextFormat.unescapeText("\\z");
-      fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequenceException e) {
-      // success
-    }
-
-    try {
-      TextFormat.unescapeText("\\");
-      fail("Should have thrown an exception.");
-    } catch (TextFormat.InvalidEscapeSequenceException e) {
-      // success
-    }
-  }
-
-  public void testParseInteger() throws Exception {
-    assertEquals(          0, TextFormat.parseInt32(          "0"));
-    assertEquals(          1, TextFormat.parseInt32(          "1"));
-    assertEquals(         -1, TextFormat.parseInt32(         "-1"));
-    assertEquals(      12345, TextFormat.parseInt32(      "12345"));
-    assertEquals(     -12345, TextFormat.parseInt32(     "-12345"));
-    assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
-    assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
-
-    assertEquals(                0, TextFormat.parseUInt32(         "0"));
-    assertEquals(                1, TextFormat.parseUInt32(         "1"));
-    assertEquals(            12345, TextFormat.parseUInt32(     "12345"));
-    assertEquals(       2147483647, TextFormat.parseUInt32("2147483647"));
-    assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
-    assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
-
-    assertEquals(          0L, TextFormat.parseInt64(          "0"));
-    assertEquals(          1L, TextFormat.parseInt64(          "1"));
-    assertEquals(         -1L, TextFormat.parseInt64(         "-1"));
-    assertEquals(      12345L, TextFormat.parseInt64(      "12345"));
-    assertEquals(     -12345L, TextFormat.parseInt64(     "-12345"));
-    assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
-    assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
-    assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
-    assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
-    assertEquals(9223372036854775807L,
-                 TextFormat.parseInt64("9223372036854775807"));
-    assertEquals(-9223372036854775808L,
-                 TextFormat.parseInt64("-9223372036854775808"));
-
-    assertEquals(          0L, TextFormat.parseUInt64(          "0"));
-    assertEquals(          1L, TextFormat.parseUInt64(          "1"));
-    assertEquals(      12345L, TextFormat.parseUInt64(      "12345"));
-    assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
-    assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
-    assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
-    assertEquals(9223372036854775807L,
-                 TextFormat.parseUInt64("9223372036854775807"));
-    assertEquals(-9223372036854775808L,
-                 TextFormat.parseUInt64("9223372036854775808"));
-    assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
-
-    // Hex
-    assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
-    assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
-    assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
-    assertEquals(0x7fffffffffffffffL,
-                 TextFormat.parseInt64("0x7fffffffffffffff"));
-
-    // Octal
-    assertEquals(01234567, TextFormat.parseInt32("01234567"));
-
-    // Out-of-range
-    try {
-      TextFormat.parseInt32("2147483648");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseInt32("-2147483649");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseUInt32("4294967296");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseUInt32("-1");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseInt64("9223372036854775808");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseInt64("-9223372036854775809");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseUInt64("18446744073709551616");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    try {
-      TextFormat.parseUInt64("-1");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-
-    // Not a number.
-    try {
-      TextFormat.parseInt32("abcd");
-      fail("Should have thrown an exception.");
-    } catch (NumberFormatException e) {
-      // success
-    }
-  }
-
-  public void testParseString() throws Exception {
-    final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge("optional_string: \"" + zh + "\"", builder);
-    assertEquals(zh, builder.getOptionalString());
-  }
-
-  public void testParseLongString() throws Exception {
-    String longText =
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890" +
-      "123456789012345678901234567890123456789012345678901234567890";
-
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge("optional_string: \"" + longText + "\"", builder);
-    assertEquals(longText, builder.getOptionalString());
-  }
-
-  public void testParseBoolean() throws Exception {
-    String goodText =
-        "repeated_bool: t  repeated_bool : 0\n" +
-        "repeated_bool :f repeated_bool:1";
-    String goodTextCanonical =
-        "repeated_bool: true\n" +
-        "repeated_bool: false\n" +
-        "repeated_bool: false\n" +
-        "repeated_bool: true\n";
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(goodText, builder);
-    assertEquals(goodTextCanonical, builder.build().toString());
-
-    try {
-      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
-      TextFormat.merge("optional_bool:2", badBuilder);
-      fail("Should have thrown an exception.");
-    } catch (TextFormat.ParseException e) {
-      // success
-    }
-    try {
-      TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
-      TextFormat.merge("optional_bool: foo", badBuilder);
-      fail("Should have thrown an exception.");
-    } catch (TextFormat.ParseException e) {
-      // success
-    }
-  }
-
-  public void testParseAdjacentStringLiterals() throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
-    assertEquals("foocorgegrault", builder.getOptionalString());
-  }
-
-  public void testPrintFieldValue() throws Exception {
-    assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
-    assertPrintFieldValue("123.0",  123f, "repeated_float");
-    assertPrintFieldValue("123.0",  123d, "repeated_double");
-    assertPrintFieldValue("123",  123, "repeated_int32");
-    assertPrintFieldValue("123",  123L, "repeated_int64");
-    assertPrintFieldValue("true",  true, "repeated_bool");
-    assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32");
-    assertPrintFieldValue("18446744073709551615",  0xFFFFFFFFFFFFFFFFL,
-        "repeated_uint64");
-    assertPrintFieldValue("\"\\001\\002\\003\"",
-        ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes");
-  }
-
-  private void assertPrintFieldValue(String expect, Object value,
-      String fieldName) throws Exception {
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    StringBuilder sb = new StringBuilder();
-    TextFormat.printFieldValue(
-        TestAllTypes.getDescriptor().findFieldByName(fieldName),
-        value, sb);
-    assertEquals(expect, sb.toString());
-  }
-
-  public void testShortDebugString() {
-    assertEquals("optional_nested_message { bb: 42 } repeated_int32: 1"
-        + " repeated_uint32: 2",
-        TextFormat.shortDebugString(TestAllTypes.newBuilder()
-            .addRepeatedInt32(1)
-            .addRepeatedUint32(2)
-            .setOptionalNestedMessage(
-                NestedMessage.newBuilder().setBb(42).build())
-            .build()));
-  }
-
-  public void testShortDebugString_unknown() {
-    assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
-        + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
-        + " 0xabcdef1234567890",
-        TextFormat.shortDebugString(makeUnknownFieldSet()));
-  }
-
-  public void testPrintToUnicodeString() throws Exception {
-    assertEquals(
-        "optional_string: \"abc\u3042efg\"\n" +
-        "optional_bytes: \"\\343\\201\\202\"\n" +
-        "repeated_string: \"\u3093XYZ\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("abc\u3042efg")
-            .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
-            .addRepeatedString("\u3093XYZ")
-            .build()));
-
-    // Double quotes and backslashes should be escaped
-    assertEquals(
-        "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("a\\bc\"ef\"g")
-            .build()));
-
-    // Test escaping roundtrip
-    TestAllTypes message = TestAllTypes.newBuilder()
-        .setOptionalString("a\\bc\\\"ef\"g")
-        .build();
-    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
-    assertEquals(message.getOptionalString(), builder.getOptionalString());
-  }
-  
-  public void testPrintToUnicodeStringWithNewlines() {
-    // No newlines at start and end
-    assertEquals("optional_string: \"test newlines\n\nin\nstring\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("test newlines\n\nin\nstring")
-            .build()));
-
-    // Newlines at start and end
-    assertEquals("optional_string: \"\ntest\nnewlines\n\nin\nstring\n\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
-            .build()));
-
-    // Strings with 0, 1 and 2 newlines.
-    assertEquals("optional_string: \"\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("")
-            .build()));
-    assertEquals("optional_string: \"\n\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("\n")
-            .build()));
-    assertEquals("optional_string: \"\n\n\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
-            .setOptionalString("\n\n")
-            .build()));
-  }
-
-  public void testPrintToUnicodeString_unknown() {
-    assertEquals(
-        "1: \"\\343\\201\\202\"\n",
-        TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder()
-            .addField(1,
-                UnknownFieldSet.Field.newBuilder()
-                .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
-            .build()));
-  }
-
-  public void testParseNonRepeatedFields() throws Exception {
-    assertParseSuccessWithOverwriteForbidden(
-        "repeated_int32: 1\n" +
-        "repeated_int32: 2\n");
-    assertParseSuccessWithOverwriteForbidden(
-        "RepeatedGroup { a: 1 }\n" +
-        "RepeatedGroup { a: 2 }\n");
-    assertParseSuccessWithOverwriteForbidden(
-        "repeated_nested_message { bb: 1 }\n" +
-        "repeated_nested_message { bb: 2 }\n");
-    assertParseErrorWithOverwriteForbidden(
-        "3:17: Non-repeated field " +
-        "\"protobuf_unittest.TestAllTypes.optional_int32\" " +
-        "cannot be overwritten.",
-        "optional_int32: 1\n" +
-        "optional_bool: true\n" +
-        "optional_int32: 1\n");
-    assertParseErrorWithOverwriteForbidden(
-        "2:17: Non-repeated field " +
-        "\"protobuf_unittest.TestAllTypes.optionalgroup\" " +
-        "cannot be overwritten.",
-        "OptionalGroup { a: 1 }\n" +
-        "OptionalGroup { }\n");
-    assertParseErrorWithOverwriteForbidden(
-        "2:33: Non-repeated field " +
-        "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " +
-        "cannot be overwritten.",
-        "optional_nested_message { }\n" +
-        "optional_nested_message { bb: 3 }\n");
-    assertParseErrorWithOverwriteForbidden(
-        "2:16: Non-repeated field " +
-        "\"protobuf_unittest.TestAllTypes.default_int32\" " +
-        "cannot be overwritten.",
-        "default_int32: 41\n" +  // the default value
-        "default_int32: 41\n");
-    assertParseErrorWithOverwriteForbidden(
-        "2:17: Non-repeated field " +
-        "\"protobuf_unittest.TestAllTypes.default_string\" " +
-        "cannot be overwritten.",
-        "default_string: \"zxcv\"\n" +
-        "default_string: \"asdf\"\n");
-  }
-
-  public void testParseShortRepeatedFormOfRepeatedFields() throws Exception {
-    assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]");
-    assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
-    assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
-    assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
-  }
-
-  public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
-    assertParseErrorWithOverwriteForbidden(
-        "1:17: Couldn't parse integer: For input string: \"[\"",
-        "optional_int32: [1]\n");
-  }
-
-  // =======================================================================
-  // test oneof
-
-  public void testOneofTextFormat() throws Exception {
-    TestOneof2.Builder builder = TestOneof2.newBuilder();
-    TestUtil.setOneof(builder);
-    TestOneof2 message = builder.build();
-    TestOneof2.Builder dest = TestOneof2.newBuilder();
-    TextFormat.merge(TextFormat.printToUnicodeString(message), dest);
-    TestUtil.assertOneofSet(dest.build());
-  }
-
-  public void testOneofOverwriteForbidden() throws Exception {
-    String input = "foo_string: \"stringvalue\" foo_int: 123";
-    TestOneof2.Builder builder = TestOneof2.newBuilder();
-    try {
-      parserWithOverwriteForbidden.merge(
-          input, TestUtil.getExtensionRegistry(), builder);
-      fail("Expected parse exception.");
-    } catch (TextFormat.ParseException e) {
-      assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
-                   + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
-                   + " another member of oneof \"foo\".", e.getMessage());
-    }
-  }
-
-  public void testOneofOverwriteAllowed() throws Exception {
-    String input = "foo_string: \"stringvalue\" foo_int: 123";
-    TestOneof2.Builder builder = TestOneof2.newBuilder();
-    defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder);
-    // Only the last value sticks.
-    TestOneof2 oneof = builder.build();
-    assertFalse(oneof.hasFooString());
-    assertTrue(oneof.hasFooInt());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
deleted file mode 100644
index 93a5ee2..0000000
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ /dev/null
@@ -1,653 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.ForeignEnum;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestEmptyMessage;
-import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
-import protobuf_unittest.UnittestProto.TestPackedExtensions;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-
-import junit.framework.TestCase;
-
-import java.util.Arrays;
-import java.util.Map;
-
-/**
- * Tests related to unknown field handling.
- *
- * @author kenton@google.com (Kenton Varda)
- */
-public class UnknownFieldSetTest extends TestCase {
-  public void setUp() throws Exception {
-    descriptor = TestAllTypes.getDescriptor();
-    allFields = TestUtil.getAllSet();
-    allFieldsData = allFields.toByteString();
-    emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
-    unknownFields = emptyMessage.getUnknownFields();
-  }
-
-  UnknownFieldSet.Field getField(String name) {
-    Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
-    assertNotNull(field);
-    return unknownFields.getField(field.getNumber());
-  }
-
-  // Constructs a protocol buffer which contains fields with all the same
-  // numbers as allFieldsData except that each field is some other wire
-  // type.
-  ByteString getBizarroData() throws Exception {
-    UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
-
-    UnknownFieldSet.Field varintField =
-      UnknownFieldSet.Field.newBuilder().addVarint(1).build();
-    UnknownFieldSet.Field fixed32Field =
-      UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
-
-    for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
-         unknownFields.asMap().entrySet()) {
-      if (entry.getValue().getVarintList().isEmpty()) {
-        // Original field is not a varint, so use a varint.
-        bizarroFields.addField(entry.getKey(), varintField);
-      } else {
-        // Original field *is* a varint, so use something else.
-        bizarroFields.addField(entry.getKey(), fixed32Field);
-      }
-    }
-
-    return bizarroFields.build().toByteString();
-  }
-
-  Descriptors.Descriptor descriptor;
-  TestAllTypes allFields;
-  ByteString allFieldsData;
-
-  // An empty message that has been parsed from allFieldsData.  So, it has
-  // unknown fields of every type.
-  TestEmptyMessage emptyMessage;
-  UnknownFieldSet unknownFields;
-
-  // =================================================================
-
-  public void testVarint() throws Exception {
-    UnknownFieldSet.Field field = getField("optional_int32");
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(allFields.getOptionalInt32(),
-                 (long) field.getVarintList().get(0));
-  }
-
-  public void testFixed32() throws Exception {
-    UnknownFieldSet.Field field = getField("optional_fixed32");
-    assertEquals(1, field.getFixed32List().size());
-    assertEquals(allFields.getOptionalFixed32(),
-                 (int) field.getFixed32List().get(0));
-  }
-
-  public void testFixed64() throws Exception {
-    UnknownFieldSet.Field field = getField("optional_fixed64");
-    assertEquals(1, field.getFixed64List().size());
-    assertEquals(allFields.getOptionalFixed64(),
-                 (long) field.getFixed64List().get(0));
-  }
-
-  public void testLengthDelimited() throws Exception {
-    UnknownFieldSet.Field field = getField("optional_bytes");
-    assertEquals(1, field.getLengthDelimitedList().size());
-    assertEquals(allFields.getOptionalBytes(),
-                 field.getLengthDelimitedList().get(0));
-  }
-
-  public void testGroup() throws Exception {
-    Descriptors.FieldDescriptor nestedFieldDescriptor =
-      TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
-    assertNotNull(nestedFieldDescriptor);
-
-    UnknownFieldSet.Field field = getField("optionalgroup");
-    assertEquals(1, field.getGroupList().size());
-
-    UnknownFieldSet group = field.getGroupList().get(0);
-    assertEquals(1, group.asMap().size());
-    assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
-
-    UnknownFieldSet.Field nestedField =
-      group.getField(nestedFieldDescriptor.getNumber());
-    assertEquals(1, nestedField.getVarintList().size());
-    assertEquals(allFields.getOptionalGroup().getA(),
-                 (long) nestedField.getVarintList().get(0));
-  }
-
-  public void testSerialize() throws Exception {
-    // Check that serializing the UnknownFieldSet produces the original data
-    // again.
-    ByteString data = emptyMessage.toByteString();
-    assertEquals(allFieldsData, data);
-  }
-
-  public void testCopyFrom() throws Exception {
-    TestEmptyMessage message =
-      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
-
-    assertEquals(emptyMessage.toString(), message.toString());
-  }
-
-  public void testMergeFrom() throws Exception {
-    TestEmptyMessage source =
-      TestEmptyMessage.newBuilder()
-        .setUnknownFields(
-          UnknownFieldSet.newBuilder()
-            .addField(2,
-              UnknownFieldSet.Field.newBuilder()
-                .addVarint(2).build())
-            .addField(3,
-              UnknownFieldSet.Field.newBuilder()
-                .addVarint(4).build())
-            .build())
-        .build();
-    TestEmptyMessage destination =
-      TestEmptyMessage.newBuilder()
-        .setUnknownFields(
-          UnknownFieldSet.newBuilder()
-            .addField(1,
-              UnknownFieldSet.Field.newBuilder()
-                .addVarint(1).build())
-            .addField(3,
-              UnknownFieldSet.Field.newBuilder()
-                .addVarint(3).build())
-            .build())
-        .mergeFrom(source)
-        .build();
-
-    assertEquals(
-      "1: 1\n" +
-      "2: 2\n" +
-      "3: 3\n" +
-      "3: 4\n",
-      destination.toString());
-  }
-
-  public void testClear() throws Exception {
-    UnknownFieldSet fields =
-      UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
-    assertTrue(fields.asMap().isEmpty());
-  }
-
-  public void testClearMessage() throws Exception {
-    TestEmptyMessage message =
-      TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
-    assertEquals(0, message.getSerializedSize());
-  }
-  
-  public void testClearField() throws Exception {
-    int fieldNumber = unknownFields.asMap().keySet().iterator().next();
-    UnknownFieldSet fields =
-        UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
-    assertFalse(fields.hasField(fieldNumber));
-  }
-
-  public void testParseKnownAndUnknown() throws Exception {
-    // Test mixing known and unknown fields when parsing.
-
-    UnknownFieldSet fields =
-      UnknownFieldSet.newBuilder(unknownFields)
-        .addField(123456,
-          UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
-        .build();
-
-    ByteString data = fields.toByteString();
-    TestAllTypes destination = TestAllTypes.parseFrom(data);
-
-    TestUtil.assertAllFieldsSet(destination);
-    assertEquals(1, destination.getUnknownFields().asMap().size());
-
-    UnknownFieldSet.Field field =
-      destination.getUnknownFields().getField(123456);
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(654321, (long) field.getVarintList().get(0));
-  }
-
-  public void testWrongTypeTreatedAsUnknown() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
-    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
-
-    // All fields should have been interpreted as unknown, so the debug strings
-    // should be the same.
-    assertEquals(emptyMessage.toString(), allTypesMessage.toString());
-  }
-
-  public void testUnknownExtensions() throws Exception {
-    // Make sure fields are properly parsed to the UnknownFieldSet even when
-    // they are declared as extension numbers.
-
-    TestEmptyMessageWithExtensions message =
-      TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
-
-    assertEquals(unknownFields.asMap().size(),
-                 message.getUnknownFields().asMap().size());
-    assertEquals(allFieldsData, message.toByteString());
-  }
-
-  public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing extensions.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllExtensions allExtensionsMessage =
-      TestAllExtensions.parseFrom(bizarroData);
-    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
-
-    // All fields should have been interpreted as unknown, so the debug strings
-    // should be the same.
-    assertEquals(emptyMessage.toString(),
-                 allExtensionsMessage.toString());
-  }
-
-  public void testParseUnknownEnumValue() throws Exception {
-    Descriptors.FieldDescriptor singularField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
-    Descriptors.FieldDescriptor repeatedField =
-      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
-    assertNotNull(singularField);
-    assertNotNull(repeatedField);
-
-    ByteString data =
-      UnknownFieldSet.newBuilder()
-        .addField(singularField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
-            .addVarint(5)   // not valid
-            .build())
-        .addField(repeatedField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
-            .addVarint(4)   // not valid
-            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
-            .addVarint(6)   // not valid
-            .build())
-        .build()
-        .toByteString();
-
-    {
-      TestAllTypes message = TestAllTypes.parseFrom(data);
-      assertEquals(TestAllTypes.NestedEnum.BAR,
-                   message.getOptionalNestedEnum());
-      assertEquals(
-        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-        message.getRepeatedNestedEnumList());
-      assertEquals(Arrays.asList(5L),
-                   message.getUnknownFields()
-                          .getField(singularField.getNumber())
-                          .getVarintList());
-      assertEquals(Arrays.asList(4L, 6L),
-                   message.getUnknownFields()
-                          .getField(repeatedField.getNumber())
-                          .getVarintList());
-    }
-
-    {
-      TestAllExtensions message =
-        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-      assertEquals(TestAllTypes.NestedEnum.BAR,
-        message.getExtension(UnittestProto.optionalNestedEnumExtension));
-      assertEquals(
-        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-        message.getExtension(UnittestProto.repeatedNestedEnumExtension));
-      assertEquals(Arrays.asList(5L),
-                   message.getUnknownFields()
-                          .getField(singularField.getNumber())
-                          .getVarintList());
-      assertEquals(Arrays.asList(4L, 6L),
-                   message.getUnknownFields()
-                          .getField(repeatedField.getNumber())
-                          .getVarintList());
-    }
-  }
-
-  public void testLargeVarint() throws Exception {
-    ByteString data =
-      UnknownFieldSet.newBuilder()
-        .addField(1,
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(0x7FFFFFFFFFFFFFFFL)
-            .build())
-        .build()
-        .toByteString();
-    UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
-    UnknownFieldSet.Field field = parsed.getField(1);
-    assertEquals(1, field.getVarintList().size());
-    assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
-  }
-
-  public void testEqualsAndHashCode() {
-    UnknownFieldSet.Field fixed32Field =
-        UnknownFieldSet.Field.newBuilder()
-            .addFixed32(1)
-            .build();
-    UnknownFieldSet.Field fixed64Field =
-        UnknownFieldSet.Field.newBuilder()
-            .addFixed64(1)
-            .build();
-    UnknownFieldSet.Field varIntField =
-        UnknownFieldSet.Field.newBuilder()
-            .addVarint(1)
-            .build();
-    UnknownFieldSet.Field lengthDelimitedField =
-        UnknownFieldSet.Field.newBuilder()
-            .addLengthDelimited(ByteString.EMPTY)
-            .build();
-    UnknownFieldSet.Field groupField =
-        UnknownFieldSet.Field.newBuilder()
-            .addGroup(unknownFields)
-            .build();
-
-    UnknownFieldSet a =
-        UnknownFieldSet.newBuilder()
-            .addField(1, fixed32Field)
-            .build();
-    UnknownFieldSet b =
-        UnknownFieldSet.newBuilder()
-            .addField(1, fixed64Field)
-            .build();
-    UnknownFieldSet c =
-        UnknownFieldSet.newBuilder()
-            .addField(1, varIntField)
-            .build();
-    UnknownFieldSet d =
-        UnknownFieldSet.newBuilder()
-            .addField(1, lengthDelimitedField)
-            .build();
-    UnknownFieldSet e =
-        UnknownFieldSet.newBuilder()
-            .addField(1, groupField)
-            .build();
-
-    checkEqualsIsConsistent(a);
-    checkEqualsIsConsistent(b);
-    checkEqualsIsConsistent(c);
-    checkEqualsIsConsistent(d);
-    checkEqualsIsConsistent(e);
-
-    checkNotEqual(a, b);
-    checkNotEqual(a, c);
-    checkNotEqual(a, d);
-    checkNotEqual(a, e);
-    checkNotEqual(b, c);
-    checkNotEqual(b, d);
-    checkNotEqual(b, e);
-    checkNotEqual(c, d);
-    checkNotEqual(c, e);
-    checkNotEqual(d, e);
-  }
-
-  /**
-   * Asserts that the given field sets are not equal and have different
-   * hash codes.
-   *
-   * @warning It's valid for non-equal objects to have the same hash code, so
-   *   this test is stricter than it needs to be. However, this should happen
-   *   relatively rarely.
-   */
-  private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
-    String equalsError = String.format("%s should not be equal to %s", s1, s2);
-    assertFalse(equalsError, s1.equals(s2));
-    assertFalse(equalsError, s2.equals(s1));
-
-    assertFalse(
-        String.format("%s should have a different hash code from %s", s1, s2),
-        s1.hashCode() == s2.hashCode());
-  }
-
-  /**
-   * Asserts that the given field sets are equal and have identical hash codes.
-   */
-  private void checkEqualsIsConsistent(UnknownFieldSet set) {
-    // Object should be equal to itself.
-    assertEquals(set, set);
-
-    // Object should be equal to a copy of itself.
-    UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
-    assertEquals(set, copy);
-    assertEquals(copy, set);
-    assertEquals(set.hashCode(), copy.hashCode());
-  }
-
-  // =================================================================
-
-  public void testSerializeLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize());
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllTypes message = TestAllTypes.parseFrom(data);
-    TestUtil.assertAllFieldsSet(message);
-    assertEquals(allFieldsData, data);
-  }
-
-  public void testAllExtensionsLite() throws Exception {
-    TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
-    ByteString allExtensionsData = allExtensions.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllExtensions message =
-        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertAllExtensionsSet(message);
-    assertEquals(allExtensionsData, data);
-  }
-
-  public void testAllPackedFieldsLite() throws Exception {
-    TestPackedTypes allPackedFields = TestUtil.getPackedSet();
-    ByteString allPackedData = allPackedFields.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestPackedTypes message =
-        TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertPackedFieldsSet(message);
-    assertEquals(allPackedData, data);
-  }
-
-  public void testAllPackedExtensionsLite() throws Exception {
-    TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet();
-    ByteString allPackedExtensionsData = allPackedExtensions.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestPackedExtensions message =
-        TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-    TestUtil.assertPackedExtensionsSet(message);
-    assertEquals(allPackedExtensionsData, data);
-  }
-
-  public void testCopyFromLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.newBuilder()
-        .mergeFrom(emptyMessageLite).build();
-    assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString());
-  }
-
-  public void testMergeFromLite() throws Exception {
-    TestAllTypes message1 = TestAllTypes.newBuilder()
-        .setOptionalInt32(1)
-        .setOptionalString("foo")
-        .addRepeatedString("bar")
-        .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ)
-        .build();
-
-    TestAllTypes message2 = TestAllTypes.newBuilder()
-        .setOptionalInt64(2)
-        .setOptionalString("baz")
-        .addRepeatedString("qux")
-        .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ)
-        .build();
-
-    ByteString data1 = message1.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data1);
-    ByteString data2 = message2.toByteString();
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data2);
-
-    message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build();
-    emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1)
-                        .mergeFrom(emptyMessageLite2).build();
-
-    data1 = emptyMessageLite1.toByteString();
-    message2 = TestAllTypes.parseFrom(data1);
-
-    assertEquals(message1, message2);
-  }
-
-  public void testWrongTypeTreatedAsUnknownLite() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
-    ByteString data = emptyMessageLite.toByteString();
-    TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data);
-
-    assertEquals(allTypesMessage.toString(), allTypesMessage2.toString());
-  }
-
-  public void testUnknownExtensionsLite() throws Exception {
-    // Make sure fields are properly parsed to the UnknownFieldSet even when
-    // they are declared as extension numbers.
-
-    UnittestLite.TestEmptyMessageWithExtensionsLite message =
-      UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData);
-
-    assertEquals(allFieldsData, message.toByteString());
-  }
-
-  public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception {
-    // Test that fields of the wrong wire type are treated like unknown fields
-    // when parsing extensions.
-
-    ByteString bizarroData = getBizarroData();
-    TestAllExtensions allExtensionsMessage =
-      TestAllExtensions.parseFrom(bizarroData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData);
-
-    // All fields should have been interpreted as unknown, so the byte strings
-    // should be the same.
-    assertEquals(emptyMessageLite.toByteString(),
-                 allExtensionsMessage.toByteString());
-  }
-
-  public void testParseUnknownEnumValueLite() throws Exception {
-    Descriptors.FieldDescriptor singularField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
-    Descriptors.FieldDescriptor repeatedField =
-      TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
-    assertNotNull(singularField);
-    assertNotNull(repeatedField);
-
-    ByteString data =
-      UnknownFieldSet.newBuilder()
-        .addField(singularField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
-            .addVarint(5)   // not valid
-            .build())
-        .addField(repeatedField.getNumber(),
-          UnknownFieldSet.Field.newBuilder()
-            .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
-            .addVarint(4)   // not valid
-            .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
-            .addVarint(6)   // not valid
-            .build())
-        .build()
-        .toByteString();
-
-    UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.parseFrom(data);
-    data = emptyMessageLite.toByteString();
-
-    {
-      TestAllTypes message = TestAllTypes.parseFrom(data);
-      assertEquals(TestAllTypes.NestedEnum.BAR,
-                   message.getOptionalNestedEnum());
-      assertEquals(
-        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-        message.getRepeatedNestedEnumList());
-      assertEquals(Arrays.asList(5L),
-                   message.getUnknownFields()
-                          .getField(singularField.getNumber())
-                          .getVarintList());
-      assertEquals(Arrays.asList(4L, 6L),
-                   message.getUnknownFields()
-                          .getField(repeatedField.getNumber())
-                          .getVarintList());
-    }
-
-    {
-      TestAllExtensions message =
-        TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
-      assertEquals(TestAllTypes.NestedEnum.BAR,
-        message.getExtension(UnittestProto.optionalNestedEnumExtension));
-      assertEquals(
-        Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
-        message.getExtension(UnittestProto.repeatedNestedEnumExtension));
-      assertEquals(Arrays.asList(5L),
-                   message.getUnknownFields()
-                          .getField(singularField.getNumber())
-                          .getVarintList());
-      assertEquals(Arrays.asList(4L, 6L),
-                   message.getUnknownFields()
-                          .getField(repeatedField.getNumber())
-                          .getVarintList());
-    }
-  }
-
-  public void testClearLite() throws Exception {
-    UnittestLite.TestEmptyMessageLite emptyMessageLite1 =
-        UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData);
-    UnittestLite.TestEmptyMessageLite emptyMessageLite2 =
-        UnittestLite.TestEmptyMessageLite.newBuilder()
-        .mergeFrom(emptyMessageLite1).clear().build();
-    assertEquals(0, emptyMessageLite2.getSerializedSize());
-    ByteString data = emptyMessageLite2.toByteString();
-    assertEquals(0, data.size());
-  }
-
-}
diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java
deleted file mode 100644
index 6858524..0000000
--- a/java/src/test/java/com/google/protobuf/WireFormatTest.java
+++ /dev/null
@@ -1,606 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.List;
-
-import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestFieldOrderings;
-import protobuf_unittest.UnittestProto.TestOneof2;
-import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
-import protobuf_unittest.UnittestProto.TestPackedExtensions;
-import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestMset.TestMessageSet;
-import protobuf_unittest.UnittestMset.RawMessageSet;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
-import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
-import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
-import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
-
-/**
- * Tests related to parsing and serialization.
- *
- * @author kenton@google.com (Kenton Varda)
- */
-public class WireFormatTest extends TestCase {
-  public void testSerialization() throws Exception {
-    TestAllTypes message = TestUtil.getAllSet();
-
-    ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
-    TestUtil.assertAllFieldsSet(message2);
-  }
-
-  public void testSerializationPacked() throws Exception {
-    TestPackedTypes message = TestUtil.getPackedSet();
-
-    ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
-
-    TestUtil.assertPackedFieldsSet(message2);
-  }
-
-  public void testSerializeExtensions() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
-    // it should work.
-
-    TestAllExtensions message = TestUtil.getAllExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
-    TestUtil.assertAllFieldsSet(message2);
-  }
-
-  public void testSerializePackedExtensions() throws Exception {
-    // TestPackedTypes and TestPackedExtensions should have compatible wire
-    // formats; check that they serialize to the same string.
-    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    TestPackedTypes message2 = TestUtil.getPackedSet();
-    ByteString rawBytes2 = message2.toByteString();
-
-    assertEquals(rawBytes, rawBytes2);
-  }
-
-  public void testSerializationPackedWithoutGetSerializedSize()
-      throws Exception {
-    // Write directly to an OutputStream, without invoking getSerializedSize()
-    // This used to be a bug where the size of a packed field was incorrect,
-    // since getSerializedSize() was never invoked.
-    TestPackedTypes message = TestUtil.getPackedSet();
-
-    // Directly construct a CodedOutputStream around the actual OutputStream,
-    // in case writeTo(OutputStream output) invokes getSerializedSize();
-    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-    CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
-
-    message.writeTo(codedOutput);
-
-    codedOutput.flush();
-
-    TestPackedTypes message2 = TestPackedTypes.parseFrom(
-        outputStream.toByteArray());
-
-    TestUtil.assertPackedFieldsSet(message2);
-  }
-
-  public void testSerializeExtensionsLite() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
-    // it should work.
-
-    TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
-
-    TestUtil.assertAllFieldsSet(message2);
-  }
-
-  public void testSerializePackedExtensionsLite() throws Exception {
-    // TestPackedTypes and TestPackedExtensions should have compatible wire
-    // formats; check that they serialize to the same string.
-    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    TestPackedTypes message2 = TestUtil.getPackedSet();
-    ByteString rawBytes2 = message2.toByteString();
-
-    assertEquals(rawBytes, rawBytes2);
-  }
-
-  public void testParseExtensions() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
-    // it should work.
-
-    TestAllTypes message = TestUtil.getAllSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
-
-    TestAllExtensions message2 =
-      TestAllExtensions.parseFrom(rawBytes, registry);
-
-    TestUtil.assertAllExtensionsSet(message2);
-  }
-
-  public void testParsePackedExtensions() throws Exception {
-    // Ensure that packed extensions can be properly parsed.
-    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
-
-    TestPackedExtensions message2 =
-        TestPackedExtensions.parseFrom(rawBytes, registry);
-
-    TestUtil.assertPackedExtensionsSet(message2);
-  }
-
-  public void testParseExtensionsLite() throws Exception {
-    // TestAllTypes and TestAllExtensions should have compatible wire formats,
-    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
-    // it should work.
-
-    TestAllTypes message = TestUtil.getAllSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
-
-    TestAllExtensionsLite message2 =
-      TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
-
-    TestUtil.assertAllExtensionsSet(message2);
-
-    // Try again using a full extension registry.
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
-
-    TestAllExtensionsLite message3 =
-      TestAllExtensionsLite.parseFrom(rawBytes, registry);
-
-    TestUtil.assertAllExtensionsSet(message3);
-  }
-
-  public void testParsePackedExtensionsLite() throws Exception {
-    // Ensure that packed extensions can be properly parsed.
-    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
-    ByteString rawBytes = message.toByteString();
-
-    ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
-
-    TestPackedExtensionsLite message2 =
-        TestPackedExtensionsLite.parseFrom(rawBytes, registry);
-
-    TestUtil.assertPackedExtensionsSet(message2);
-  }
-
-  public void testExtensionsSerializedSize() throws Exception {
-    assertNotSame(TestUtil.getAllSet().getSerializedSize(),
-                  TestUtil.getAllExtensionsSet().getSerializedSize());
-  }
-
-  public void testSerializeDelimited() throws Exception {
-    ByteArrayOutputStream output = new ByteArrayOutputStream();
-    TestUtil.getAllSet().writeDelimitedTo(output);
-    output.write(12);
-    TestUtil.getPackedSet().writeDelimitedTo(output);
-    output.write(34);
-
-    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
-
-    TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
-    assertEquals(12, input.read());
-    TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
-    assertEquals(34, input.read());
-    assertEquals(-1, input.read());
-
-    // We're at EOF, so parsing again should return null.
-    assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
-  }
-
-  private void assertFieldsInOrder(ByteString data) throws Exception {
-    CodedInputStream input = data.newCodedInput();
-    int previousTag = 0;
-
-    while (true) {
-      int tag = input.readTag();
-      if (tag == 0) {
-        break;
-      }
-
-      assertTrue(tag > previousTag);
-      previousTag = tag;
-      input.skipField(tag);
-    }
-  }
-
-  public void testInterleavedFieldsAndExtensions() throws Exception {
-    // Tests that fields are written in order even when extension ranges
-    // are interleaved with field numbers.
-    ByteString data =
-      TestFieldOrderings.newBuilder()
-        .setMyInt(1)
-        .setMyString("foo")
-        .setMyFloat(1.0F)
-        .setExtension(UnittestProto.myExtensionInt, 23)
-        .setExtension(UnittestProto.myExtensionString, "bar")
-        .build().toByteString();
-    assertFieldsInOrder(data);
-
-    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
-    ByteString dynamic_data =
-      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
-        .setField(descriptor.findFieldByName("my_int"), 1L)
-        .setField(descriptor.findFieldByName("my_string"), "foo")
-        .setField(descriptor.findFieldByName("my_float"), 1.0F)
-        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
-        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
-        .build().toByteString();
-    assertFieldsInOrder(dynamic_data);
-  }
-
-  private ExtensionRegistry getTestFieldOrderingsRegistry() {
-    ExtensionRegistry result = ExtensionRegistry.newInstance();
-    result.add(UnittestProto.myExtensionInt);
-    result.add(UnittestProto.myExtensionString);
-    return result;
-  }
-
-  public void testParseMultipleExtensionRanges() throws Exception {
-    // Make sure we can parse a message that contains multiple extensions
-    // ranges.
-    TestFieldOrderings source =
-      TestFieldOrderings.newBuilder()
-        .setMyInt(1)
-        .setMyString("foo")
-        .setMyFloat(1.0F)
-        .setExtension(UnittestProto.myExtensionInt, 23)
-        .setExtension(UnittestProto.myExtensionString, "bar")
-        .build();
-    TestFieldOrderings dest =
-      TestFieldOrderings.parseFrom(source.toByteString(),
-                                   getTestFieldOrderingsRegistry());
-    assertEquals(source, dest);
-  }
-
-  public void testParseMultipleExtensionRangesDynamic() throws Exception {
-    // Same as above except with DynamicMessage.
-    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
-    DynamicMessage source =
-      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
-        .setField(descriptor.findFieldByName("my_int"), 1L)
-        .setField(descriptor.findFieldByName("my_string"), "foo")
-        .setField(descriptor.findFieldByName("my_float"), 1.0F)
-        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
-        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
-        .build();
-    DynamicMessage dest =
-      DynamicMessage.parseFrom(descriptor, source.toByteString(),
-                               getTestFieldOrderingsRegistry());
-    assertEquals(source, dest);
-  }
-
-  private static final int UNKNOWN_TYPE_ID = 1550055;
-  private static final int TYPE_ID_1 =
-    TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
-  private static final int TYPE_ID_2 =
-    TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
-
-  public void testSerializeMessageSetEagerly() throws Exception {
-    testSerializeMessageSetWithFlag(true);
-  }
-
-  public void testSerializeMessageSetNotEagerly() throws Exception {
-    testSerializeMessageSetWithFlag(false);
-  }
-
-  private void testSerializeMessageSetWithFlag(boolean eagerParsing)
-      throws Exception {
-    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
-    // Set up a TestMessageSet with two known messages and an unknown one.
-    TestMessageSet messageSet =
-      TestMessageSet.newBuilder()
-        .setExtension(
-          TestMessageSetExtension1.messageSetExtension,
-          TestMessageSetExtension1.newBuilder().setI(123).build())
-        .setExtension(
-          TestMessageSetExtension2.messageSetExtension,
-          TestMessageSetExtension2.newBuilder().setStr("foo").build())
-        .setUnknownFields(
-          UnknownFieldSet.newBuilder()
-            .addField(UNKNOWN_TYPE_ID,
-              UnknownFieldSet.Field.newBuilder()
-                .addLengthDelimited(ByteString.copyFromUtf8("bar"))
-                .build())
-            .build())
-        .build();
-
-    ByteString data = messageSet.toByteString();
-
-    // Parse back using RawMessageSet and check the contents.
-    RawMessageSet raw = RawMessageSet.parseFrom(data);
-
-    assertTrue(raw.getUnknownFields().asMap().isEmpty());
-
-    assertEquals(3, raw.getItemCount());
-    assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
-    assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
-    assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
-
-    TestMessageSetExtension1 message1 =
-      TestMessageSetExtension1.parseFrom(
-        raw.getItem(0).getMessage().toByteArray());
-    assertEquals(123, message1.getI());
-
-    TestMessageSetExtension2 message2 =
-      TestMessageSetExtension2.parseFrom(
-        raw.getItem(1).getMessage().toByteArray());
-    assertEquals("foo", message2.getStr());
-
-    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
-  }
-
-  public void testParseMessageSetEagerly() throws Exception {
-    testParseMessageSetWithFlag(true);
-  }
-
-  public void testParseMessageSetNotEagerly()throws Exception {
-    testParseMessageSetWithFlag(false);
-  }
-
-  private void testParseMessageSetWithFlag(boolean eagerParsing)
-      throws Exception {
-    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
-
-    // Set up a RawMessageSet with two known messages and an unknown one.
-    RawMessageSet raw =
-      RawMessageSet.newBuilder()
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(TYPE_ID_1)
-            .setMessage(
-              TestMessageSetExtension1.newBuilder()
-                .setI(123)
-                .build().toByteString())
-            .build())
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(TYPE_ID_2)
-            .setMessage(
-              TestMessageSetExtension2.newBuilder()
-                .setStr("foo")
-                .build().toByteString())
-            .build())
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(UNKNOWN_TYPE_ID)
-            .setMessage(ByteString.copyFromUtf8("bar"))
-            .build())
-        .build();
-
-    ByteString data = raw.toByteString();
-
-    // Parse as a TestMessageSet and check the contents.
-    TestMessageSet messageSet =
-      TestMessageSet.parseFrom(data, extensionRegistry);
-
-    assertEquals(123, messageSet.getExtension(
-      TestMessageSetExtension1.messageSetExtension).getI());
-    assertEquals("foo", messageSet.getExtension(
-      TestMessageSetExtension2.messageSetExtension).getStr());
-
-    // Check for unknown field with type LENGTH_DELIMITED,
-    //   number UNKNOWN_TYPE_ID, and contents "bar".
-    UnknownFieldSet unknownFields = messageSet.getUnknownFields();
-    assertEquals(1, unknownFields.asMap().size());
-    assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
-
-    UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
-    assertEquals(1, field.getLengthDelimitedList().size());
-    assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
-  }
-
-  public void testParseMessageSetExtensionEagerly() throws Exception {
-    testParseMessageSetExtensionWithFlag(true);
-  }
-
-  public void testParseMessageSetExtensionNotEagerly() throws Exception {
-    testParseMessageSetExtensionWithFlag(false);
-  }
-
-  private void testParseMessageSetExtensionWithFlag(boolean eagerParsing)
-      throws Exception {
-    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-
-    // Set up a RawMessageSet with a known messages.
-    int TYPE_ID_1 =
-        TestMessageSetExtension1
-            .getDescriptor().getExtensions().get(0).getNumber();
-    RawMessageSet raw =
-      RawMessageSet.newBuilder()
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(TYPE_ID_1)
-            .setMessage(
-              TestMessageSetExtension1.newBuilder()
-                .setI(123)
-                .build().toByteString())
-            .build())
-        .build();
-
-    ByteString data = raw.toByteString();
-
-    // Parse as a TestMessageSet and check the contents.
-    TestMessageSet messageSet =
-        TestMessageSet.parseFrom(data, extensionRegistry);
-    assertEquals(123, messageSet.getExtension(
-        TestMessageSetExtension1.messageSetExtension).getI());
-  }
-
-  public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
-    testMergeLazyMessageSetExtensionWithFlag(true);
-  }
-
-  public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
-    testMergeLazyMessageSetExtensionWithFlag(false);
-  }
-
-  private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)
-      throws Exception {
-    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-
-    // Set up a RawMessageSet with a known messages.
-    int TYPE_ID_1 =
-        TestMessageSetExtension1
-            .getDescriptor().getExtensions().get(0).getNumber();
-    RawMessageSet raw =
-      RawMessageSet.newBuilder()
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(TYPE_ID_1)
-            .setMessage(
-              TestMessageSetExtension1.newBuilder()
-                .setI(123)
-                .build().toByteString())
-            .build())
-        .build();
-
-    ByteString data = raw.toByteString();
-
-    // Parse as a TestMessageSet and store value into lazy field
-    TestMessageSet messageSet =
-        TestMessageSet.parseFrom(data, extensionRegistry);
-    // Merge lazy field check the contents.
-    messageSet =
-        messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(
-        TestMessageSetExtension1.messageSetExtension).getI());
-  }
-
-  public void testMergeMessageSetExtensionEagerly() throws Exception {
-    testMergeMessageSetExtensionWithFlag(true);
-  }
-
-  public void testMergeMessageSetExtensionNotEagerly() throws Exception {
-    testMergeMessageSetExtensionWithFlag(false);
-  }
-
-  private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing)
-      throws Exception {
-    ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
-    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
-    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
-
-    // Set up a RawMessageSet with a known messages.
-    int TYPE_ID_1 =
-        TestMessageSetExtension1
-            .getDescriptor().getExtensions().get(0).getNumber();
-    RawMessageSet raw =
-      RawMessageSet.newBuilder()
-        .addItem(
-          RawMessageSet.Item.newBuilder()
-            .setTypeId(TYPE_ID_1)
-            .setMessage(
-              TestMessageSetExtension1.newBuilder()
-                .setI(123)
-                .build().toByteString())
-            .build())
-        .build();
-
-    // Serialize RawMessageSet unnormally (message value before type id)
-    ByteString.CodedBuilder out = ByteString.newCodedBuilder(
-        raw.getSerializedSize());
-    CodedOutputStream output = out.getCodedOutput();
-    List<RawMessageSet.Item> items = raw.getItemList();
-    for (int i = 0; i < items.size(); i++) {
-      RawMessageSet.Item item = items.get(i);
-      output.writeTag(1, WireFormat.WIRETYPE_START_GROUP);
-      output.writeBytes(3, item.getMessage());
-      output.writeInt32(2, item.getTypeId());
-      output.writeTag(1, WireFormat.WIRETYPE_END_GROUP);
-    }
-    ByteString data = out.build();
-
-    // Merge bytes into TestMessageSet and check the contents.
-    TestMessageSet messageSet =
-        TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
-    assertEquals(123, messageSet.getExtension(
-        TestMessageSetExtension1.messageSetExtension).getI());
-  }
-
-  // ================================================================
-  // oneof
-  public void testOneofWireFormat() throws Exception {
-    TestOneof2.Builder builder = TestOneof2.newBuilder();
-    TestUtil.setOneof(builder);
-    TestOneof2 message = builder.build();
-    ByteString rawBytes = message.toByteString();
-
-    assertEquals(rawBytes.size(), message.getSerializedSize());
-
-    TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
-    TestUtil.assertOneofSet(message2);
-  }
-
-  public void testOneofOnlyLastSet() throws Exception {
-    TestOneofBackwardsCompatible source = TestOneofBackwardsCompatible
-        .newBuilder().setFooInt(100).setFooString("101").build();
-
-    ByteString rawBytes = source.toByteString();
-    TestOneof2 message = TestOneof2.parseFrom(rawBytes);
-    assertFalse(message.hasFooInt());
-    assertTrue(message.hasFooString());
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
deleted file mode 100644
index baed4e1..0000000
--- a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
+++ /dev/null
@@ -1,61 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Naoki Iwasaki (niwasaki@google.com)
-//
-// A proto file with lazy fields
-
-
-package protobuf_unittest;
-
-option optimize_for = LITE_RUNTIME;
-
-message LazyMessageLite {
-  optional int32 num = 1;
-  optional int32 num_with_default = 2 [default = 421];
-  optional LazyInnerMessageLite inner = 3 [lazy = true];
-  repeated LazyInnerMessageLite repeated_inner = 4 [lazy = true];
-
-  oneof oneof_field {
-    int32 oneof_num = 5;
-    LazyInnerMessageLite oneof_inner = 6 [lazy = true];
-  }
-}
-
-message LazyInnerMessageLite {
-  optional int32 num = 1;
-  optional int32 num_with_default = 2 [default = 42];
-  optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
-}
-
-message LazyNestedInnerMessageLite {
-  optional int32 num = 1;
-  optional int32 num_with_default = 2 [default = 4];
-}
diff --git a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
deleted file mode 100644
index 6861567..0000000
--- a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
+++ /dev/null
@@ -1,55 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: pbogle@google.com (Phil Bogle)
-
-
-package protobuf_unittest.lite_equals_and_hash;
-
-// This proto definition is used to test that java_generate_equals_and_hash
-// works correctly with the LITE_RUNTIME.
-option java_generate_equals_and_hash = true;
-option optimize_for = LITE_RUNTIME;
-
-message Foo {
-  optional int32 value = 1;
-  repeated Bar bar = 2;
-}
-
-message Bar {
-  optional string name = 1;
-}
-
-message BarPrime {
-  optional string name = 1;
-}
-
-message Empty {
-}
diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/src/test/java/com/google/protobuf/multiple_files_test.proto
deleted file mode 100644
index 7ec89a0..0000000
--- a/java/src/test/java/com/google/protobuf/multiple_files_test.proto
+++ /dev/null
@@ -1,77 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: kenton@google.com (Kenton Varda)
-//
-// A proto file which tests the java_multiple_files option.
-
-
-// Some generic_services option(s) added automatically.
-// See:  http://go/proto2-generic-services-default
-option java_generic_services = true;   // auto-added
-
-import "google/protobuf/unittest.proto";
-import "google/protobuf/descriptor.proto";
-
-package protobuf_unittest;
-
-option java_multiple_files = true;
-option java_outer_classname = "MultipleFilesTestProto";
-
-
-message MessageWithNoOuter {
-  message NestedMessage {
-    optional int32 i = 1;
-  }
-  enum NestedEnum {
-    BAZ = 3;
-  }
-  optional NestedMessage nested = 1;
-  repeated TestAllTypes foreign = 2;
-  optional NestedEnum nested_enum = 3;
-  optional EnumWithNoOuter foreign_enum = 4;
-}
-
-extend google.protobuf.EnumValueOptions {
-  optional int32 enum_value_option = 7654321;
-}
-
-enum EnumWithNoOuter {
-  FOO = 1 [(enum_value_option) = 12345];
-  BAR = 2;
-}
-
-service ServiceWithNoOuter {
-  rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
-}
-
-extend TestAllExtensions {
-  optional int32 extension_with_outer = 1234567;
-}
diff --git a/java/src/test/java/com/google/protobuf/nested_builders_test.proto b/java/src/test/java/com/google/protobuf/nested_builders_test.proto
deleted file mode 100644
index 8ab4a43..0000000
--- a/java/src/test/java/com/google/protobuf/nested_builders_test.proto
+++ /dev/null
@@ -1,53 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: jonp@google.com (Jon Perlow)
-//
-
-package protobuf_unittest;
-
-option java_multiple_files = true;
-option java_outer_classname = "NestedBuilders";
-
-
-message Vehicle {
-  optional Engine engine = 1;
-  repeated Wheel wheel = 2;
-}
-
-message Engine {
-  optional int32 cylinder = 1;
-  optional int32 liters = 2;
-}
-
-message Wheel {
-  optional int32 radius = 1;
-  optional int32 width = 2;
-}
diff --git a/java/src/test/java/com/google/protobuf/nested_extension.proto b/java/src/test/java/com/google/protobuf/nested_extension.proto
deleted file mode 100644
index 8649286..0000000
--- a/java/src/test/java/com/google/protobuf/nested_extension.proto
+++ /dev/null
@@ -1,46 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Darick Tong (darick@google.com)
-//
-// A proto file with nested extensions. Note that this must be defined in
-// a separate file to properly test the initialization of the outer class.
-
-
-import "com/google/protobuf/non_nested_extension.proto";
-
-package protobuf_unittest;
-
-
-message MyNestedExtension {
-  extend MessageToBeExtended {
-    optional MessageToBeExtended recursiveExtension = 2;
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto b/java/src/test/java/com/google/protobuf/nested_extension_lite.proto
deleted file mode 100644
index 9c68682..0000000
--- a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto
+++ /dev/null
@@ -1,48 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Darick Tong (darick@google.com)
-//
-// A proto file with nested extensions for a MessageLite messages. Note that
-// this must be defined in a separate file to properly test the initialization
-// of the outer class.
-
-
-package protobuf_unittest;
-
-option optimize_for = LITE_RUNTIME;
-
-import "com/google/protobuf/non_nested_extension_lite.proto";
-
-message MyNestedExtensionLite {
-  extend MessageLiteToBeExtended {
-    optional MessageLiteToBeExtended recursiveExtensionLite = 3;
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension.proto b/java/src/test/java/com/google/protobuf/non_nested_extension.proto
deleted file mode 100644
index cb2f8b0..0000000
--- a/java/src/test/java/com/google/protobuf/non_nested_extension.proto
+++ /dev/null
@@ -1,49 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Darick Tong (darick@google.com)
-//
-// A proto file with extensions.
-
-
-package protobuf_unittest;
-
-
-message MessageToBeExtended {
-  extensions 1 to max;
-}
-
-message MyNonNestedExtension {
-}
-
-extend MessageToBeExtended {
-  optional MyNonNestedExtension nonNestedExtension = 1;
-}
-
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto b/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto
deleted file mode 100644
index c1f744b..0000000
--- a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto
+++ /dev/null
@@ -1,50 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Darick Tong (darick@google.com)
-//
-// A proto file with extensions for a MessageLite messages.
-
-
-package protobuf_unittest;
-
-option optimize_for = LITE_RUNTIME;
-
-message MessageLiteToBeExtended {
-  extensions 1 to max;
-}
-
-message MyNonNestedExtensionLite {
-}
-
-extend MessageLiteToBeExtended {
-  optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
-}
-
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto
deleted file mode 100644
index c5114f8..0000000
--- a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package protobuf_unittest;
-
-
-// This message's name is the same with the default outer class name of this
-// proto file. It's used to test if the compiler can avoid this conflict
-// correctly.
-message OuterClassNameTest {
-}
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
deleted file mode 100644
index 741cd28..0000000
--- a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
+++ /dev/null
@@ -1,42 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package protobuf_unittest;
-
-
-message TestMessage2 {
-  message NestedMessage {
-    // This message's name is the same with the default outer class name of this
-    // proto file. It's used to test if the compiler can avoid this conflict
-    // correctly.
-    message OuterClassNameTest2 {
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto
deleted file mode 100644
index 5d5d4ac..0000000
--- a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package protobuf_unittest;
-
-
-message TestMessage3 {
-  message NestedMessage {
-    // This enum's name is the same with the default outer class name of this
-    // proto file. It's used to test if the compiler can avoid this conflict
-    // correctly.
-    enum OuterClassNameTest3 {
-      DUMMY_VALUE = 1;
-    }
-  }
-}
diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
deleted file mode 100644
index 202e8c9..0000000
--- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
+++ /dev/null
@@ -1,157 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: jonp@google.com (Jon Perlow)
-
-// This file tests that various identifiers work as field and type names even
-// though the same identifiers are used internally by the java code generator.
-
-
-// Some generic_services option(s) added automatically.
-// See:  http://go/proto2-generic-services-default
-option java_generic_services = true;   // auto-added
-
-package io_protocol_tests;
-
-option java_package = "com.google.protobuf";
-option java_outer_classname = "TestBadIdentifiersProto";
-option java_generate_equals_and_hash = true;
-
-message TestMessage {
-  optional string cached_size = 1;
-  optional string serialized_size = 2;
-  optional string class = 3;
-}
-
-message Descriptor {
-  option no_standard_descriptor_accessor = true;
-  optional string descriptor = 1;
-  message NestedDescriptor {
-    option no_standard_descriptor_accessor = true;
-    optional string descriptor = 1;
-  }
-  optional NestedDescriptor nested_descriptor = 2;
-  enum NestedEnum {
-    FOO = 1;
-  }
-}
-
-message Parser {
-  enum ParserEnum {
-    PARSER = 1;
-  }
-  optional ParserEnum parser = 1;
-}
-
-message Deprecated {
-  enum TestEnum {
-    FOO = 1;
-
-    // Test if @Deprecated annotation conflicts with Deprecated message name.
-    BAR = 2 [ deprecated = true ];
-  }
-
-  optional int32 field1 = 1 [deprecated=true];
-  optional TestEnum field2 = 2 [deprecated=true];
-  optional TestMessage field3 = 3 [deprecated=true];
-}
-
-message Override {
-  optional int32 override = 1;
-}
-
-message Object {
-  optional int32 object = 1;
-  optional string string_object = 2;
-}
-
-message String {
-  optional string string = 1;
-}
-
-message Integer {
-  optional int32 integer = 1;
-}
-
-message Long {
-  optional int32 long = 1;
-}
-
-message Float {
-  optional float float = 1;
-}
-
-message Double {
-  optional double double = 1;
-}
-
-service TestConflictingMethodNames {
-  rpc Override(TestMessage) returns (TestMessage);
-}
-
-message TestConflictingFieldNames {
-  enum TestEnum {
-    FOO = 1;
-  }
-  message TestMessage {
-  }
-  repeated int32 int32_field = 1;
-  repeated TestEnum enum_field = 2;
-  repeated string string_field = 3;
-  repeated bytes bytes_field = 4;
-  repeated TestMessage message_field = 5;
-
-  optional int32 int32_field_count = 11;
-  optional TestEnum enum_field_count = 12;
-  optional string string_field_count = 13;
-  optional bytes bytes_field_count = 14;
-  optional TestMessage message_field_count = 15;
-
-  repeated int32 Int32Field = 21;
-  repeated TestEnum EnumField = 22;
-  repeated string StringField = 23;
-  repeated bytes BytesField = 24;
-  repeated TestMessage MessageField = 25;
-
-  // This field conflicts with "int32_field" as they both generate
-  // the method getInt32FieldList().
-  required int32 int32_field_list = 31;
-
-  extensions 1000 to max;
-
-  repeated int64 int64_field = 41;
-  extend TestConflictingFieldNames {
-    // We don't generate accessors for extensions so the following extension
-    // fields don't conflict with the repeated field "int64_field".
-    optional int64 int64_field_count = 1001;
-    optional int64 int64_field_list = 1002;
-  }
-}
-
diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8.proto b/java/src/test/java/com/google/protobuf/test_check_utf8.proto
deleted file mode 100644
index 206946d..0000000
--- a/java/src/test/java/com/google/protobuf/test_check_utf8.proto
+++ /dev/null
@@ -1,50 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Jacob Butcher (jbaum@google.com)
-//
-// Test file option java_string_check_utf8.
-
-package proto2_test_check_utf8;
-
-option java_outer_classname = "TestCheckUtf8";
-option java_string_check_utf8 = true;
-
-message StringWrapper {
-  required string req = 1;
-  optional string opt = 2;
-  repeated string rep = 3;
-}
-
-message BytesWrapper {
-  required bytes req = 1;
-  optional bytes opt = 2;
-  repeated bytes rep = 3;
-}
diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
deleted file mode 100644
index fa057a8..0000000
--- a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
+++ /dev/null
@@ -1,51 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Jacob Butcher (jbaum@google.com)
-//
-// Test file option java_string_check_utf8.
-
-package proto2_test_check_utf8_size;
-
-option java_outer_classname = "TestCheckUtf8Size";
-option java_string_check_utf8 = true;
-option optimize_for = CODE_SIZE;
-
-message StringWrapperSize {
-  required string req = 1;
-  optional string opt = 2;
-  repeated string rep = 3;
-}
-
-message BytesWrapperSize {
-  required bytes req = 1;
-  optional bytes opt = 2;
-  repeated bytes rep = 3;
-}
diff --git a/java/src/test/java/com/google/protobuf/test_custom_options.proto b/java/src/test/java/com/google/protobuf/test_custom_options.proto
deleted file mode 100644
index f6a5ecd..0000000
--- a/java/src/test/java/com/google/protobuf/test_custom_options.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Feng Xiao (xiaofeng@google.com)
-//
-// Test that custom options defined in a proto file's dependencies are properly
-// initialized.
-
-package protobuf_unittest;
-
-
-import "google/protobuf/unittest_custom_options.proto";
-
-message TestMessageWithCustomOptionsContainer {
-  optional TestMessageWithCustomOptions field = 1;
-}
diff --git a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto b/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto
deleted file mode 100644
index 72e05a3..0000000
--- a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto
+++ /dev/null
@@ -1,60 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Author: Darick Tong (darick@google.com)
-
-package protobuf_unittest;
-
-message Proto1 {
-  option experimental_java_message_interface =
-      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
-
-  option experimental_java_interface_extends =
-      "com.google.protobuf.ExtraInterfaces.HasByteValue";
-
-  option experimental_java_message_interface =
-      "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>";
-
-  option experimental_java_builder_interface =
-      "com.google.protobuf.ExtraInterfaces.HasStringValueBuilder"
-      "<Proto1, Builder>";
-
-  optional string string_value = 1;
-  optional bool bool_value = 2;
-  optional bytes byte_value = 3;
-  optional int32 int_value = 4;
-}
-
-message Proto2 {
-  option experimental_java_message_interface =
-      "com.google.protobuf.ExtraInterfaces.HasBoolValue";
-
-  optional bool bool_value = 1;
-}
diff --git a/java/util/pom.xml b/java/util/pom.xml
new file mode 100644
index 0000000..9236f90
--- /dev/null
+++ b/java/util/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-3</version>
+  </parent>
+
+  <artifactId>protobuf-java-util</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Protocol Buffers [Util]</name>
+  <description>Utilities for Protocol Buffers</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.3</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <!-- Use the core proto dir so that we can call the core generation script -->
+    <test.proto.dir>../core/src/test/proto</test.proto.dir>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate the test protos -->
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <target>
+                <!-- Generate all of the test protos from the core module -->
+                <ant antfile="../core/generate-test-sources-build.xml"/>
+
+                <!-- Generate additional test protos for this module -->
+                <exec executable="${protoc}">
+                  <arg value="--java_out=${generated.testsources.dir}" />
+                  <arg value="--proto_path=${protobuf.source.dir}" />
+                  <arg value="--proto_path=src/test/proto" />
+                  <arg value="src/test/proto/com/google/protobuf/util/json_test.proto" />
+                </exec>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <!-- Add the generated test sources to the build -->
+          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+        </configuration>
+      </plugin>
+
+      <!-- Configure the OSGI bundle -->
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+            <Bundle-SymbolicName>com.google.protobuf.util</Bundle-SymbolicName>
+            <Export-Package>com.google.protobuf.util;version=${project.version}</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+
+      <!-- Configure the fat jar to include all dependencies -->
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
new file mode 100644
index 0000000..668d65a
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -0,0 +1,276 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.Message;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+
+/**
+ * A tree representation of a FieldMask. Each leaf node in this tree represent
+ * a field path in the FieldMask.
+ *
+ * <p>For example, FieldMask "foo.bar,foo.baz,bar.baz" as a tree will be:
+ * <pre>
+ *   [root] -+- foo -+- bar
+ *           |       |
+ *           |       +- baz
+ *           |
+ *           +- bar --- baz
+ * </pre>
+ *
+ * <p>By representing FieldMasks with this tree structure we can easily convert
+ * a FieldMask to a canonical form, merge two FieldMasks, calculate the
+ * intersection to two FieldMasks and traverse all fields specified by the
+ * FieldMask in a message tree.
+ */
+class FieldMaskTree {
+  private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
+
+  private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
+
+  private static class Node {
+    public TreeMap<String, Node> children = new TreeMap<String, Node>();
+  }
+
+  private final Node root = new Node();
+
+  /** Creates an empty FieldMaskTree. */
+  public FieldMaskTree() {}
+
+  /** Creates a FieldMaskTree for a given FieldMask. */
+  public FieldMaskTree(FieldMask mask) {
+    mergeFromFieldMask(mask);
+  }
+
+  @Override
+  public String toString() {
+    return FieldMaskUtil.toString(toFieldMask());
+  }
+
+  /**
+   * Adds a field path to the tree. In a FieldMask, every field path matches the
+   * specified field as well as all its sub-fields. For example, a field path
+   * "foo.bar" matches field "foo.bar" and also "foo.bar.baz", etc. When adding
+   * a field path to the tree, redundant sub-paths will be removed. That is,
+   * after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it
+   * exists, which will turn the tree node for "foo.bar" to a leaf node.
+   * Likewise, if the field path to add is a sub-path of an existing leaf node,
+   * nothing will be changed in the tree.
+   */
+  public FieldMaskTree addFieldPath(String path) {
+    String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
+    if (parts.length == 0) {
+      return this;
+    }
+    Node node = root;
+    boolean createNewBranch = false;
+    // Find the matching node in the tree.
+    for (String part : parts) {
+      // Check whether the path matches an existing leaf node.
+      if (!createNewBranch && node != root && node.children.isEmpty()) {
+        // The path to add is a sub-path of an existing leaf node.
+        return this;
+      }
+      if (node.children.containsKey(part)) {
+        node = node.children.get(part);
+      } else {
+        createNewBranch = true;
+        Node tmp = new Node();
+        node.children.put(part, tmp);
+        node = tmp;
+      }
+    }
+    // Turn the matching node into a leaf node (i.e., remove sub-paths).
+    node.children.clear();
+    return this;
+  }
+
+  /**
+   * Merges all field paths in a FieldMask into this tree.
+   */
+  public FieldMaskTree mergeFromFieldMask(FieldMask mask) {
+    for (String path : mask.getPathsList()) {
+      addFieldPath(path);
+    }
+    return this;
+  }
+
+  /** Converts this tree to a FieldMask. */
+  public FieldMask toFieldMask() {
+    if (root.children.isEmpty()) {
+      return FieldMask.getDefaultInstance();
+    }
+    List<String> paths = new ArrayList<String>();
+    getFieldPaths(root, "", paths);
+    return FieldMask.newBuilder().addAllPaths(paths).build();
+  }
+
+  /** Gathers all field paths in a sub-tree. */
+  private void getFieldPaths(Node node, String path, List<String> paths) {
+    if (node.children.isEmpty()) {
+      paths.add(path);
+      return;
+    }
+    for (Entry<String, Node> entry : node.children.entrySet()) {
+      String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
+      getFieldPaths(entry.getValue(), childPath, paths);
+    }
+  }
+
+  /**
+   * Adds the intersection of this tree with the given {@code path} to
+   * {@code output}.
+   */
+  public void intersectFieldPath(String path, FieldMaskTree output) {
+    if (root.children.isEmpty()) {
+      return;
+    }
+    String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
+    if (parts.length == 0) {
+      return;
+    }
+    Node node = root;
+    for (String part : parts) {
+      if (node != root && node.children.isEmpty()) {
+        // The given path is a sub-path of an existing leaf node in the tree.
+        output.addFieldPath(path);
+        return;
+      }
+      if (node.children.containsKey(part)) {
+        node = node.children.get(part);
+      } else {
+        return;
+      }
+    }
+    // We found a matching node for the path. All leaf children of this matching
+    // node is in the intersection.
+    List<String> paths = new ArrayList<String>();
+    getFieldPaths(node, path, paths);
+    for (String value : paths) {
+      output.addFieldPath(value);
+    }
+  }
+
+  /**
+   * Merges all fields specified by this FieldMaskTree from {@code source} to
+   * {@code destination}.
+   */
+  public void merge(
+      Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
+    if (source.getDescriptorForType() != destination.getDescriptorForType()) {
+      throw new IllegalArgumentException("Cannot merge messages of different types.");
+    }
+    if (root.children.isEmpty()) {
+      return;
+    }
+    merge(root, "", source, destination, options);
+  }
+
+  /** Merges all fields specified by a sub-tree from {@code source} to
+   * {@code destination}.
+   */
+  private void merge(
+      Node node,
+      String path,
+      Message source,
+      Message.Builder destination,
+      FieldMaskUtil.MergeOptions options) {
+    assert source.getDescriptorForType() == destination.getDescriptorForType();
+
+    Descriptor descriptor = source.getDescriptorForType();
+    for (Entry<String, Node> entry : node.children.entrySet()) {
+      FieldDescriptor field = descriptor.findFieldByName(entry.getKey());
+      if (field == null) {
+        logger.warning(
+            "Cannot find field \""
+                + entry.getKey()
+                + "\" in message type "
+                + descriptor.getFullName());
+        continue;
+      }
+      if (!entry.getValue().children.isEmpty()) {
+        if (field.isRepeated() || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+          logger.warning(
+              "Field \""
+                  + field.getFullName()
+                  + "\" is not a "
+                  + "singluar message field and cannot have sub-fields.");
+          continue;
+        }
+        String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
+        merge(
+            entry.getValue(),
+            childPath,
+            (Message) source.getField(field),
+            destination.getFieldBuilder(field),
+            options);
+        continue;
+      }
+      if (field.isRepeated()) {
+        if (options.replaceRepeatedFields()) {
+          destination.setField(field, source.getField(field));
+        } else {
+          for (Object element : (List) source.getField(field)) {
+            destination.addRepeatedField(field, element);
+          }
+        }
+      } else {
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (options.replaceMessageFields()) {
+            if (!source.hasField(field)) {
+              destination.clearField(field);
+            } else {
+              destination.setField(field, source.getField(field));
+            }
+          } else {
+            if (source.hasField(field)) {
+              destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field));
+            }
+          }
+        } else {
+          if (source.hasField(field) || !options.replacePrimitiveFields()) {
+            destination.setField(field, source.getField(field));
+          } else {
+            destination.clearField(field);
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
new file mode 100644
index 0000000..9696152
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -0,0 +1,314 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.primitives.Ints;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.Internal;
+import com.google.protobuf.Message;
+
+import java.util.Arrays;
+
+/**
+ * Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
+ */
+public class FieldMaskUtil {
+  private static final String FIELD_PATH_SEPARATOR = ",";
+  private static final String FIELD_PATH_SEPARATOR_REGEX = ",";
+  private static final String FIELD_SEPARATOR_REGEX = "\\.";
+  
+  private FieldMaskUtil() {}
+
+  /**
+   * Converts a FieldMask to a string.
+   */
+  public static String toString(FieldMask fieldMask) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Joiner here instead.
+    StringBuilder result = new StringBuilder();
+    boolean first = true;
+    for (String value : fieldMask.getPathsList()) {
+      if (value.isEmpty()) {
+        // Ignore empty paths.
+        continue;
+      }
+      if (first) {
+        first = false;
+      } else {
+        result.append(FIELD_PATH_SEPARATOR);
+      }
+      result.append(value);
+    }
+    return result.toString();
+  }
+
+  /**
+   * Parses from a string to a FieldMask.
+   */
+  public static FieldMask fromString(String value) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
+    return fromStringList(
+        null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+  }
+
+  /**
+   * Parses from a string to a FieldMask and validates all field paths.
+   * 
+   * @throws IllegalArgumentException if any of the field path is invalid.
+   */
+  public static FieldMask fromString(Class<? extends Message> type, String value) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
+    return fromStringList(
+        type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+  }
+
+  /**
+   * Constructs a FieldMask for a list of field paths in a certain type.
+   *
+   * @throws IllegalArgumentException if any of the field path is not valid.
+   */
+  // TODO(xiaofeng): Consider renaming fromStrings()
+  public static FieldMask fromStringList(
+      Class<? extends Message> type, Iterable<String> paths) {
+    FieldMask.Builder builder = FieldMask.newBuilder();
+    for (String path : paths) {
+      if (path.isEmpty()) {
+        // Ignore empty field paths.
+        continue;
+      }
+      if (type != null && !isValid(type, path)) {
+        throw new IllegalArgumentException(
+            path + " is not a valid path for " + type);
+      }
+      builder.addPaths(path);
+    }
+    return builder.build();
+  }
+
+  /**
+   * Constructs a FieldMask from the passed field numbers.
+   *
+   * @throws IllegalArgumentException if any of the fields are invalid for the message.
+   */
+  public static FieldMask fromFieldNumbers(Class<? extends Message> type, int... fieldNumbers) {
+    return fromFieldNumbers(type, Ints.asList(fieldNumbers));
+  }
+
+  /**
+   * Constructs a FieldMask from the passed field numbers.
+   *
+   * @throws IllegalArgumentException if any of the fields are invalid for the message.
+   */
+  public static FieldMask fromFieldNumbers(
+      Class<? extends Message> type, Iterable<Integer> fieldNumbers) {
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
+    FieldMask.Builder builder = FieldMask.newBuilder();
+    for (Integer fieldNumber : fieldNumbers) {
+      FieldDescriptor field = descriptor.findFieldByNumber(fieldNumber);
+      checkArgument(
+          field != null,
+          String.format("%s is not a valid field number for %s.", fieldNumber, type));
+      builder.addPaths(field.getName());
+    }
+    return builder.build();
+  }
+
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Class<? extends Message> type, FieldMask fieldMask) {
+    Descriptor descriptor =
+        Internal.getDefaultInstance(type).getDescriptorForType();
+    
+    return isValid(descriptor, fieldMask);
+  }
+  
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Descriptor descriptor, FieldMask fieldMask) {
+    for (String path : fieldMask.getPathsList()) {
+      if (!isValid(descriptor, path)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Checks whether a given field path is valid.
+   */
+  public static boolean isValid(Class<? extends Message> type, String path) {
+    Descriptor descriptor =
+        Internal.getDefaultInstance(type).getDescriptorForType();
+    
+    return isValid(descriptor, path);
+  }
+
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Descriptor descriptor, String path) {
+    String[] parts = path.split(FIELD_SEPARATOR_REGEX);
+    if (parts.length == 0) {
+      return false;
+    }
+    for (String name : parts) {
+      if (descriptor == null) {
+        return false;
+      }
+      FieldDescriptor field = descriptor.findFieldByName(name);
+      if (field == null) {
+        return false;
+      }
+      if (!field.isRepeated()
+          && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        descriptor = field.getMessageType();
+      } else {
+        descriptor = null;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Converts a FieldMask to its canonical form. In the canonical form of a
+   * FieldMask, all field paths are sorted alphabetically and redundant field
+   * paths are moved.
+   */
+  public static FieldMask normalize(FieldMask mask) {
+    return new FieldMaskTree(mask).toFieldMask();
+  }
+
+  /**
+   * Creates a union of two or more FieldMasks.
+   */
+  public static FieldMask union(
+      FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) {
+    FieldMaskTree maskTree = new FieldMaskTree(firstMask).mergeFromFieldMask(secondMask);
+    for (FieldMask mask : otherMasks) {
+      maskTree.mergeFromFieldMask(mask);
+    }
+    return maskTree.toFieldMask();
+  }
+
+  /**
+   * Calculates the intersection of two FieldMasks.
+   */
+  public static FieldMask intersection(FieldMask mask1, FieldMask mask2) {
+    FieldMaskTree tree = new FieldMaskTree(mask1);
+    FieldMaskTree result = new FieldMaskTree();
+    for (String path : mask2.getPathsList()) {
+      tree.intersectFieldPath(path, result);
+    }
+    return result.toFieldMask();
+  }
+
+  /**
+   * Options to customize merging behavior.
+   */
+  public static final class MergeOptions {
+    private boolean replaceMessageFields = false;
+    private boolean replaceRepeatedFields = false;
+    // TODO(b/28277137): change the default behavior to always replace primitive fields after
+    // fixing all failing TAP tests.
+    private boolean replacePrimitiveFields = false;
+
+    /**
+     * Whether to replace message fields (i.e., discard existing content in
+     * destination message fields) when merging.
+     * Default behavior is to merge the source message field into the
+     * destination message field.
+     */ 
+    public boolean replaceMessageFields() {
+      return replaceMessageFields;
+    }
+
+    /**
+     * Whether to replace repeated fields (i.e., discard existing content in
+     * destination repeated fields) when merging.
+     * Default behavior is to append elements from source repeated field to the
+     * destination repeated field.
+     */
+    public boolean replaceRepeatedFields() {
+      return replaceRepeatedFields;
+    }
+
+    /**
+     * Whether to replace primitive (non-repeated and non-message) fields in
+     * destination message fields with the source primitive fields (i.e., if the
+     * field is set in the source, the value is copied to the
+     * destination; if the field is unset in the source, the field is cleared
+     * from the destination) when merging.
+     *
+     * <p>Default behavior is to always set the value of the source primitive
+     * field to the destination primitive field, and if the source field is
+     * unset, the default value of the source field is copied to the
+     * destination.
+     */
+    public boolean replacePrimitiveFields() {
+      return replacePrimitiveFields;
+    }
+
+    public void setReplaceMessageFields(boolean value) {
+      replaceMessageFields = value;
+    }
+
+    public void setReplaceRepeatedFields(boolean value) {
+      replaceRepeatedFields = value;
+    }
+
+    public void setReplacePrimitiveFields(boolean value) {
+      replacePrimitiveFields = value;
+    }
+  }
+
+  /**
+   * Merges fields specified by a FieldMask from one message to another with the
+   * specified merge options.
+   */
+  public static void merge(FieldMask mask, Message source,
+      Message.Builder destination, MergeOptions options) {
+    new FieldMaskTree(mask).merge(source, destination, options);
+  }
+
+  /**
+   * Merges fields specified by a FieldMask from one message to another.
+   */
+  public static void merge(FieldMask mask, Message source,
+      Message.Builder destination) {
+    merge(mask, source, destination, new MergeOptions());
+  }
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
new file mode 100644
index 0000000..76f3437
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -0,0 +1,1678 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.common.io.BaseEncoding;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.stream.JsonReader;
+import com.google.protobuf.Any;
+import com.google.protobuf.BoolValue;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.BytesValue;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.DoubleValue;
+import com.google.protobuf.Duration;
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.FieldMask;
+import com.google.protobuf.FloatValue;
+import com.google.protobuf.Int32Value;
+import com.google.protobuf.Int64Value;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.ListValue;
+import com.google.protobuf.Message;
+import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.StringValue;
+import com.google.protobuf.Struct;
+import com.google.protobuf.Timestamp;
+import com.google.protobuf.UInt32Value;
+import com.google.protobuf.UInt64Value;
+import com.google.protobuf.Value;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+
+/**
+ * Utility classes to convert protobuf messages to/from JSON format. The JSON
+ * format follows Proto3 JSON specification and only proto3 features are
+ * supported. Proto2 only features (e.g., extensions and unknown fields) will
+ * be discarded in the conversion. That is, when converting proto2 messages
+ * to JSON format, extensions and unknown fields will be treated as if they
+ * do not exist. This applies to proto2 messages embedded in proto3 messages
+ * as well.
+ */
+public class JsonFormat {
+  private static final Logger logger =
+      Logger.getLogger(JsonFormat.class.getName());
+
+  private JsonFormat() {}
+  
+  /**
+   * Creates a {@link Printer} with default configurations.
+   */
+  public static Printer printer() {
+    return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
+  }
+  
+  /**
+   * A Printer converts protobuf message to JSON format.
+   */
+  public static class Printer {
+    private final TypeRegistry registry;
+    private final boolean includingDefaultValueFields;
+    private final boolean preservingProtoFieldNames;
+
+    private Printer(
+        TypeRegistry registry,
+        boolean includingDefaultValueFields,
+        boolean preservingProtoFieldNames) {
+      this.registry = registry;
+      this.includingDefaultValueFields = includingDefaultValueFields;
+      this.preservingProtoFieldNames = preservingProtoFieldNames;
+    }
+    
+    /**
+     * Creates a new {@link Printer} using the given registry. The new Printer
+     * clones all other configurations from the current {@link Printer}.
+     * 
+     * @throws IllegalArgumentException if a registry is already set.
+     */
+    public Printer usingTypeRegistry(TypeRegistry registry) {
+      if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
+        throw new IllegalArgumentException("Only one registry is allowed.");
+      }
+      return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames);
+    }
+
+    /**
+     * Creates a new {@link Printer} that will also print fields set to their
+     * defaults. Empty repeated fields and map fields will be printed as well.
+     * The new Printer clones all other configurations from the current
+     * {@link Printer}.
+     */
+    public Printer includingDefaultValueFields() {
+      return new Printer(registry, true, preservingProtoFieldNames);
+    }
+
+    /**
+     * Creates a new {@link Printer} that is configured to use the original proto
+     * field names as defined in the .proto file rather than converting them to
+     * lowerCamelCase. The new Printer clones all other configurations from the
+     * current {@link Printer}.
+     */
+    public Printer preservingProtoFieldNames() {
+      return new Printer(registry, includingDefaultValueFields, true);
+    }
+    
+    /**
+     * Converts a protobuf message to JSON format.
+     * 
+     * @throws InvalidProtocolBufferException if the message contains Any types
+     *         that can't be resolved.
+     * @throws IOException if writing to the output fails.
+     */
+    public void appendTo(MessageOrBuilder message, Appendable output)
+        throws IOException {
+      // TODO(xiaofeng): Investigate the allocation overhead and optimize for
+      // mobile.
+      new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
+          .print(message);
+    }
+
+    /**
+     * Converts a protobuf message to JSON format. Throws exceptions if there
+     * are unknown Any types in the message. 
+     */
+    public String print(MessageOrBuilder message)
+        throws InvalidProtocolBufferException {
+      try {
+        StringBuilder builder = new StringBuilder();
+        appendTo(message, builder);
+        return builder.toString();
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (IOException e) {
+        // Unexpected IOException.
+        throw new IllegalStateException(e);
+      }
+    }
+  }
+
+  /**
+   * Creates a {@link Parser} with default configuration.
+   */
+  public static Parser parser() {
+    return new Parser(TypeRegistry.getEmptyTypeRegistry());
+  }
+  
+  /**
+   * A Parser parses JSON to protobuf message.
+   */
+  public static class Parser {
+    private final TypeRegistry registry;
+    
+    private Parser(TypeRegistry registry) {
+      this.registry = registry; 
+    }
+    
+    /**
+     * Creates a new {@link Parser} using the given registry. The new Parser
+     * clones all other configurations from this Parser.
+     * 
+     * @throws IllegalArgumentException if a registry is already set.
+     */
+    public Parser usingTypeRegistry(TypeRegistry registry) {
+      if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
+        throw new IllegalArgumentException("Only one registry is allowed.");
+      }
+      return new Parser(registry);
+    }
+    
+    /**
+     * Parses from JSON into a protobuf message.
+     * 
+     * @throws InvalidProtocolBufferException if the input is not valid JSON
+     *         format or there are unknown fields in the input.
+     */
+    public void merge(String json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      // TODO(xiaofeng): Investigate the allocation overhead and optimize for
+      // mobile.
+      new ParserImpl(registry).merge(json, builder);
+    }
+    
+    /**
+     * Parses from JSON into a protobuf message.
+     * 
+     * @throws InvalidProtocolBufferException if the input is not valid JSON
+     *         format or there are unknown fields in the input.
+     * @throws IOException if reading from the input throws.
+     */
+    public void merge(Reader json, Message.Builder builder)
+        throws IOException {
+      // TODO(xiaofeng): Investigate the allocation overhead and optimize for
+      // mobile.
+      new ParserImpl(registry).merge(json, builder);
+    }
+  }
+
+  /**
+   * A TypeRegistry is used to resolve Any messages in the JSON conversion.
+   * You must provide a TypeRegistry containing all message types used in
+   * Any message fields, or the JSON conversion will fail because data
+   * in Any message fields is unrecognizable. You don't need to supply a
+   * TypeRegistry if you don't use Any message fields.
+   */
+  public static class TypeRegistry {
+    private static class EmptyTypeRegistryHolder {
+      private static final TypeRegistry EMPTY = new TypeRegistry(
+          Collections.<String, Descriptor>emptyMap());
+    }
+
+    public static TypeRegistry getEmptyTypeRegistry() {
+      return EmptyTypeRegistryHolder.EMPTY;
+    }
+
+    public static Builder newBuilder() {
+      return new Builder();
+    }
+
+    /**
+     * Find a type by its full name. Returns null if it cannot be found in
+     * this {@link TypeRegistry}.
+     */
+    public Descriptor find(String name) {
+      return types.get(name);
+    }
+
+    private final Map<String, Descriptor> types;
+
+    private TypeRegistry(Map<String, Descriptor> types) {
+      this.types = types;
+    }
+
+    /**
+     * A Builder is used to build {@link TypeRegistry}.
+     */
+    public static class Builder {
+      private Builder() {}
+
+      /**
+       * Adds a message type and all types defined in the same .proto file as
+       * well as all transitively imported .proto files to this {@link Builder}.
+       */
+      public Builder add(Descriptor messageType) {
+        if (types == null) {
+          throw new IllegalStateException(
+              "A TypeRegistry.Builer can only be used once.");
+        }
+        addFile(messageType.getFile());
+        return this;
+      }
+
+      /**
+       * Adds message types and all types defined in the same .proto file as
+       * well as all transitively imported .proto files to this {@link Builder}.
+       */
+      public Builder add(Iterable<Descriptor> messageTypes) {
+        if (types == null) {
+          throw new IllegalStateException(
+              "A TypeRegistry.Builer can only be used once.");
+        }
+        for (Descriptor type : messageTypes) {
+          addFile(type.getFile());
+        }
+        return this;
+      }
+
+      /**
+       * Builds a {@link TypeRegistry}. This method can only be called once for
+       * one Builder.
+       */
+      public TypeRegistry build() {
+        TypeRegistry result = new TypeRegistry(types);
+        // Make sure the built {@link TypeRegistry} is immutable.
+        types = null;
+        return result;
+      }
+
+      private void addFile(FileDescriptor file) {
+        // Skip the file if it's already added.
+        if (!files.add(file.getFullName())) {
+          return;
+        }
+        for (FileDescriptor dependency : file.getDependencies()) {
+          addFile(dependency);
+        }
+        for (Descriptor message : file.getMessageTypes()) {
+          addMessage(message);
+        }
+      }
+
+      private void addMessage(Descriptor message) {
+        for (Descriptor nestedType : message.getNestedTypes()) {
+          addMessage(nestedType);
+        }
+
+        if (types.containsKey(message.getFullName())) {
+          logger.warning("Type " + message.getFullName()
+              + " is added multiple times.");
+          return;
+        }
+
+        types.put(message.getFullName(), message);
+      }
+
+      private final Set<String> files = new HashSet<String>();
+      private Map<String, Descriptor> types =
+          new HashMap<String, Descriptor>();
+    }
+  }
+
+  /**
+   * A TextGenerator adds indentation when writing formatted text.
+   */
+  private static final class TextGenerator {
+    private final Appendable output;
+    private final StringBuilder indent = new StringBuilder();
+    private boolean atStartOfLine = true;
+
+    private TextGenerator(final Appendable output) {
+      this.output = output;
+    }
+
+    /**
+     * Indent text by two spaces.  After calling Indent(), two spaces will be
+     * inserted at the beginning of each line of text.  Indent() may be called
+     * multiple times to produce deeper indents.
+     */
+    public void indent() {
+      indent.append("  ");
+    }
+
+    /**
+     * Reduces the current indent level by two spaces, or crashes if the indent
+     * level is zero.
+     */
+    public void outdent() {
+      final int length = indent.length();
+      if (length < 2) {
+        throw new IllegalArgumentException(
+            " Outdent() without matching Indent().");
+      }
+      indent.delete(length - 2, length);
+    }
+
+    /**
+     * Print text to the output stream.
+     */
+    public void print(final CharSequence text) throws IOException {
+      final int size = text.length();
+      int pos = 0;
+
+      for (int i = 0; i < size; i++) {
+        if (text.charAt(i) == '\n') {
+          write(text.subSequence(pos, i + 1));
+          pos = i + 1;
+          atStartOfLine = true;
+        }
+      }
+      write(text.subSequence(pos, size));
+    }
+
+    private void write(final CharSequence data) throws IOException {
+      if (data.length() == 0) {
+        return;
+      }
+      if (atStartOfLine) {
+        atStartOfLine = false;
+        output.append(indent);
+      }
+      output.append(data);
+    }
+  }
+
+  /**
+   * A Printer converts protobuf messages to JSON format.
+   */
+  private static final class PrinterImpl {
+    private final TypeRegistry registry;
+    private final boolean includingDefaultValueFields;
+    private final boolean preservingProtoFieldNames;
+    private final TextGenerator generator;
+    // We use Gson to help handle string escapes.
+    private final Gson gson;
+
+    private static class GsonHolder {
+      private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
+    }
+
+    PrinterImpl(
+        TypeRegistry registry,
+        boolean includingDefaultValueFields,
+        boolean preservingProtoFieldNames,
+        Appendable jsonOutput) {
+      this.registry = registry;
+      this.includingDefaultValueFields = includingDefaultValueFields;
+      this.preservingProtoFieldNames = preservingProtoFieldNames;
+      this.generator = new TextGenerator(jsonOutput);
+      this.gson = GsonHolder.DEFAULT_GSON;
+    }
+
+    void print(MessageOrBuilder message) throws IOException {
+      WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get(
+          message.getDescriptorForType().getFullName());
+      if (specialPrinter != null) {
+        specialPrinter.print(this, message);
+        return;
+      }
+      print(message, null);
+    }
+    
+    private interface WellKnownTypePrinter {
+      void print(PrinterImpl printer, MessageOrBuilder message)
+          throws IOException;
+    }
+    
+    private static final Map<String, WellKnownTypePrinter>
+    wellKnownTypePrinters = buildWellKnownTypePrinters();
+    
+    private static Map<String, WellKnownTypePrinter>
+    buildWellKnownTypePrinters() {
+      Map<String, WellKnownTypePrinter> printers =
+          new HashMap<String, WellKnownTypePrinter>();
+      // Special-case Any.
+      printers.put(Any.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printAny(message);
+        }
+      });
+      // Special-case wrapper types.
+      WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printWrapper(message);
+          
+        }
+      };
+      printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
+      printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
+      // Special-case Timestamp.
+      printers.put(Timestamp.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printTimestamp(message);
+        }
+      });
+      // Special-case Duration.
+      printers.put(Duration.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printDuration(message);
+        }
+      });
+      // Special-case FieldMask.
+      printers.put(FieldMask.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printFieldMask(message);
+        }
+      });
+      // Special-case Struct.
+      printers.put(Struct.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printStruct(message);
+        }
+      });
+      // Special-case Value.
+      printers.put(Value.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printValue(message);
+        }
+      });
+      // Special-case ListValue.
+      printers.put(ListValue.getDescriptor().getFullName(),
+          new WellKnownTypePrinter() {
+        @Override
+        public void print(PrinterImpl printer, MessageOrBuilder message)
+            throws IOException {
+          printer.printListValue(message);
+        }
+      });
+      return printers;
+    }
+    
+    /** Prints google.protobuf.Any */
+    private void printAny(MessageOrBuilder message) throws IOException {
+      Descriptor descriptor = message.getDescriptorForType();
+      FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
+      FieldDescriptor valueField = descriptor.findFieldByName("value");
+      // Validates type of the message. Note that we can't just cast the message
+      // to com.google.protobuf.Any because it might be a DynamicMessage. 
+      if (typeUrlField == null || valueField == null
+          || typeUrlField.getType() != FieldDescriptor.Type.STRING
+          || valueField.getType() != FieldDescriptor.Type.BYTES) {
+        throw new InvalidProtocolBufferException("Invalid Any type.");
+      }
+      String typeUrl = (String) message.getField(typeUrlField);
+      String typeName = getTypeName(typeUrl);
+      Descriptor type = registry.find(typeName);
+      if (type == null) {
+        throw new InvalidProtocolBufferException(
+            "Cannot find type for url: " + typeUrl);
+      }
+      ByteString content = (ByteString) message.getField(valueField);
+      Message contentMessage = DynamicMessage.getDefaultInstance(type)
+          .getParserForType().parseFrom(content);
+      WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
+      if (printer != null) {
+        // If the type is one of the well-known types, we use a special
+        // formatting.
+        generator.print("{\n");
+        generator.indent();
+        generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n");
+        generator.print("\"value\": ");
+        printer.print(this, contentMessage);
+        generator.print("\n");
+        generator.outdent();
+        generator.print("}");
+      } else {
+        // Print the content message instead (with a "@type" field added).
+        print(contentMessage, typeUrl);
+      }
+    }
+    
+    /** Prints wrapper types (e.g., google.protobuf.Int32Value) */
+    private void printWrapper(MessageOrBuilder message) throws IOException {
+      Descriptor descriptor = message.getDescriptorForType();
+      FieldDescriptor valueField = descriptor.findFieldByName("value");
+      if (valueField == null) {
+        throw new InvalidProtocolBufferException("Invalid Wrapper type.");
+      }
+      // When formatting wrapper types, we just print its value field instead of
+      // the whole message.
+      printSingleFieldValue(valueField, message.getField(valueField));
+    }
+    
+    private ByteString toByteString(MessageOrBuilder message) {
+      if (message instanceof Message) {
+        return ((Message) message).toByteString();
+      } else {
+        return ((Message.Builder) message).build().toByteString();
+      }
+    }
+    
+    /** Prints google.protobuf.Timestamp */
+    private void printTimestamp(MessageOrBuilder message) throws IOException {
+      Timestamp value = Timestamp.parseFrom(toByteString(message));
+      generator.print("\"" + TimeUtil.toString(value) + "\"");
+    }
+    
+    /** Prints google.protobuf.Duration */
+    private void printDuration(MessageOrBuilder message) throws IOException {
+      Duration value = Duration.parseFrom(toByteString(message));
+      generator.print("\"" + TimeUtil.toString(value) + "\"");
+      
+    }
+    
+    /** Prints google.protobuf.FieldMask */
+    private void printFieldMask(MessageOrBuilder message) throws IOException {
+      FieldMask value = FieldMask.parseFrom(toByteString(message));
+      generator.print("\"" + FieldMaskUtil.toString(value) + "\"");
+    }
+    
+    /** Prints google.protobuf.Struct */
+    private void printStruct(MessageOrBuilder message) throws IOException {
+      Descriptor descriptor = message.getDescriptorForType();
+      FieldDescriptor field = descriptor.findFieldByName("fields");
+      if (field == null) {
+        throw new InvalidProtocolBufferException("Invalid Struct type.");
+      }
+      // Struct is formatted as a map object.
+      printMapFieldValue(field, message.getField(field));
+    }
+    
+    /** Prints google.protobuf.Value */
+    private void printValue(MessageOrBuilder message) throws IOException {
+      // For a Value message, only the value of the field is formatted.
+      Map<FieldDescriptor, Object> fields = message.getAllFields();
+      if (fields.isEmpty()) {
+        // No value set.
+        generator.print("null");
+        return;
+      }
+      // A Value message can only have at most one field set (it only contains
+      // an oneof).
+      if (fields.size() != 1) {
+        throw new InvalidProtocolBufferException("Invalid Value type.");
+      }
+      for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
+        printSingleFieldValue(entry.getKey(), entry.getValue());
+      }
+    }
+    
+    /** Prints google.protobuf.ListValue */
+    private void printListValue(MessageOrBuilder message) throws IOException {
+      Descriptor descriptor = message.getDescriptorForType();
+      FieldDescriptor field = descriptor.findFieldByName("values");
+      if (field == null) {
+        throw new InvalidProtocolBufferException("Invalid ListValue type.");
+      }
+      printRepeatedFieldValue(field, message.getField(field));
+    }
+
+    /** Prints a regular message with an optional type URL. */
+    private void print(MessageOrBuilder message, String typeUrl)
+        throws IOException {
+      generator.print("{\n");
+      generator.indent();
+
+      boolean printedField = false;
+      if (typeUrl != null) {
+        generator.print("\"@type\": " + gson.toJson(typeUrl));
+        printedField = true;
+      }
+      Map<FieldDescriptor, Object> fieldsToPrint = null;
+      if (includingDefaultValueFields) {
+        fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
+        for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
+          if (field.isOptional()
+              && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
+              && !message.hasField(field)) {
+            // Always skip empty optional message fields. If not we will recurse indefinitely if
+            // a message has itself as a sub-field.
+            continue;
+          }
+          fieldsToPrint.put(field, message.getField(field));
+        }
+      } else {
+        fieldsToPrint = message.getAllFields();
+      }
+      for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) {
+        if (printedField) {
+          // Add line-endings for the previous field.
+          generator.print(",\n");
+        } else {
+          printedField = true;
+        }
+        printField(field.getKey(), field.getValue());
+      }
+      
+      // Add line-endings for the last field.
+      if (printedField) {
+        generator.print("\n");
+      }
+      generator.outdent();
+      generator.print("}");
+    }
+
+    private void printField(FieldDescriptor field, Object value)
+        throws IOException {
+      if (preservingProtoFieldNames) {
+        generator.print("\"" + field.getName() + "\": ");
+      } else {
+        generator.print("\"" + field.getJsonName() + "\": ");
+      }
+      if (field.isMapField()) {
+        printMapFieldValue(field, value);
+      } else if (field.isRepeated()) {
+        printRepeatedFieldValue(field, value);
+      } else {
+        printSingleFieldValue(field, value);
+      }
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private void printRepeatedFieldValue(FieldDescriptor field, Object value)
+        throws IOException {
+      generator.print("[");
+      boolean printedElement = false;
+      for (Object element : (List) value) {
+        if (printedElement) {
+          generator.print(", ");
+        } else {
+          printedElement = true;
+        }
+        printSingleFieldValue(field, element);
+      }
+      generator.print("]");
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private void printMapFieldValue(FieldDescriptor field, Object value)
+        throws IOException {
+      Descriptor type = field.getMessageType();
+      FieldDescriptor keyField = type.findFieldByName("key");
+      FieldDescriptor valueField = type.findFieldByName("value");
+      if (keyField == null || valueField == null) {
+        throw new InvalidProtocolBufferException("Invalid map field.");
+      }
+      generator.print("{\n");
+      generator.indent();
+      boolean printedElement = false;
+      for (Object element : (List) value) {
+        Message entry = (Message) element;
+        Object entryKey = entry.getField(keyField);
+        Object entryValue = entry.getField(valueField);
+        if (printedElement) {
+          generator.print(",\n");
+        } else {
+          printedElement = true;
+        }
+        // Key fields are always double-quoted.
+        printSingleFieldValue(keyField, entryKey, true);
+        generator.print(": ");
+        printSingleFieldValue(valueField, entryValue);
+      }
+      if (printedElement) {
+        generator.print("\n");
+      }
+      generator.outdent();
+      generator.print("}");
+    }
+    
+    private void printSingleFieldValue(FieldDescriptor field, Object value)
+        throws IOException {
+      printSingleFieldValue(field, value, false);
+    }
+
+    /**
+     * Prints a field's value in JSON format.
+     * 
+     * @param alwaysWithQuotes whether to always add double-quotes to primitive
+     *        types.
+     */
+    private void printSingleFieldValue(
+        final FieldDescriptor field, final Object value,
+        boolean alwaysWithQuotes) throws IOException {
+      switch (field.getType()) {
+        case INT32:
+        case SINT32:
+        case SFIXED32:
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          generator.print(((Integer) value).toString());
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          break;
+
+        case INT64:
+        case SINT64:
+        case SFIXED64:
+          generator.print("\"" + ((Long) value).toString() + "\"");
+          break;
+
+        case BOOL:
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          if (((Boolean) value).booleanValue()) {
+            generator.print("true");
+          } else {
+            generator.print("false");
+          }
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          break;
+
+        case FLOAT:
+          Float floatValue = (Float) value;
+          if (floatValue.isNaN()) {
+            generator.print("\"NaN\"");
+          } else if (floatValue.isInfinite()) {
+            if (floatValue < 0) {
+              generator.print("\"-Infinity\"");
+            } else {
+              generator.print("\"Infinity\"");
+            }
+          } else {
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+            generator.print(floatValue.toString());
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+          }
+          break;
+          
+        case DOUBLE:
+          Double doubleValue = (Double) value;
+          if (doubleValue.isNaN()) {
+            generator.print("\"NaN\"");
+          } else if (doubleValue.isInfinite()) {
+            if (doubleValue < 0) {
+              generator.print("\"-Infinity\"");
+            } else {
+              generator.print("\"Infinity\"");
+            }
+          } else {
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+            generator.print(doubleValue.toString());
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+          }
+          break;
+
+        case UINT32:
+        case FIXED32:
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          generator.print(unsignedToString((Integer) value));
+          if (alwaysWithQuotes) {
+            generator.print("\"");
+          }
+          break;
+
+        case UINT64:
+        case FIXED64:
+          generator.print("\"" + unsignedToString((Long) value) + "\"");
+          break;
+
+        case STRING:
+          generator.print(gson.toJson(value));
+          break;
+
+        case BYTES:
+          generator.print("\"");
+          generator.print(
+              BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
+          generator.print("\"");
+          break;
+
+        case ENUM:
+          // Special-case google.protobuf.NullValue (it's an Enum).
+          if (field.getEnumType().getFullName().equals(
+                  "google.protobuf.NullValue")) {
+            // No matter what value it contains, we always print it as "null".
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+            generator.print("null");
+            if (alwaysWithQuotes) {
+              generator.print("\"");
+            }
+          } else {
+            if (((EnumValueDescriptor) value).getIndex() == -1) {
+              generator.print(
+                  String.valueOf(((EnumValueDescriptor) value).getNumber()));
+            } else {
+              generator.print(
+                  "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+            }
+          }
+          break;
+
+        case MESSAGE:
+        case GROUP:
+          print((Message) value);
+          break;
+      }
+    }
+  }
+
+  /** Convert an unsigned 32-bit integer to a string. */
+  private static String unsignedToString(final int value) {
+    if (value >= 0) {
+      return Integer.toString(value);
+    } else {
+      return Long.toString(value & 0x00000000FFFFFFFFL);
+    }
+  }
+
+  /** Convert an unsigned 64-bit integer to a string. */
+  private static String unsignedToString(final long value) {
+    if (value >= 0) {
+      return Long.toString(value);
+    } else {
+      // Pull off the most-significant bit so that BigInteger doesn't think
+      // the number is negative, then set it again using setBit().
+      return BigInteger.valueOf(value & Long.MAX_VALUE)
+                       .setBit(Long.SIZE - 1).toString();
+    }
+  }
+  
+
+  private static String getTypeName(String typeUrl)
+      throws InvalidProtocolBufferException {
+    String[] parts = typeUrl.split("/");
+    if (parts.length == 1) {
+      throw new InvalidProtocolBufferException(
+          "Invalid type url found: " + typeUrl);
+    }
+    return parts[parts.length - 1];
+  }
+  
+  private static class ParserImpl {
+    private final TypeRegistry registry;
+    private final JsonParser jsonParser;
+    
+    ParserImpl(TypeRegistry registry) {
+      this.registry = registry;
+      this.jsonParser = new JsonParser();
+    }
+    
+    void merge(Reader json, Message.Builder builder)
+        throws IOException {
+      JsonReader reader = new JsonReader(json);
+      reader.setLenient(false);
+      merge(jsonParser.parse(reader), builder);
+    }
+    
+    void merge(String json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      try {
+        JsonReader reader = new JsonReader(new StringReader(json));
+        reader.setLenient(false);
+        merge(jsonParser.parse(reader), builder);
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        // We convert all exceptions from JSON parsing to our own exceptions.
+        throw new InvalidProtocolBufferException(e.getMessage());
+      }
+    }
+    
+    private interface WellKnownTypeParser {
+      void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+          throws InvalidProtocolBufferException;
+    }
+    
+    private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers =
+        buildWellKnownTypeParsers();
+    
+    private static Map<String, WellKnownTypeParser>
+    buildWellKnownTypeParsers() {
+      Map<String, WellKnownTypeParser> parsers =
+          new HashMap<String, WellKnownTypeParser>();
+      // Special-case Any.
+      parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeAny(json, builder);
+        }
+      });
+      // Special-case wrapper types.
+      WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeWrapper(json, builder);
+        }
+      };
+      parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
+      parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
+      // Special-case Timestamp.
+      parsers.put(Timestamp.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeTimestamp(json, builder);
+        }
+      });
+      // Special-case Duration.
+      parsers.put(Duration.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeDuration(json, builder);
+        }
+      });
+      // Special-case FieldMask.
+      parsers.put(FieldMask.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeFieldMask(json, builder);
+        }
+      });
+      // Special-case Struct.
+      parsers.put(Struct.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeStruct(json, builder);
+        }
+      });
+      // Special-case ListValue.
+      parsers.put(ListValue.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeListValue(json, builder);
+        }
+      });
+      // Special-case Value.
+      parsers.put(Value.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+        @Override
+        public void merge(ParserImpl parser, JsonElement json,
+            Message.Builder builder) throws InvalidProtocolBufferException {
+          parser.mergeValue(json, builder);
+        }
+      });
+      return parsers;
+    }
+    
+    private void merge(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      WellKnownTypeParser specialParser = wellKnownTypeParsers.get(
+          builder.getDescriptorForType().getFullName());
+      if (specialParser != null) {
+        specialParser.merge(this, json, builder);
+        return;
+      }
+      mergeMessage(json, builder, false);
+    }
+    
+    // Maps from camel-case field names to FieldDescriptor.
+    private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps =
+        new HashMap<Descriptor, Map<String, FieldDescriptor>>();
+    
+    private Map<String, FieldDescriptor> getFieldNameMap(
+        Descriptor descriptor) {
+      if (!fieldNameMaps.containsKey(descriptor)) {
+        Map<String, FieldDescriptor> fieldNameMap =
+            new HashMap<String, FieldDescriptor>();
+        for (FieldDescriptor field : descriptor.getFields()) {
+          fieldNameMap.put(field.getName(), field);
+          fieldNameMap.put(field.getJsonName(), field);
+        }
+        fieldNameMaps.put(descriptor, fieldNameMap);
+        return fieldNameMap;
+      }
+      return fieldNameMaps.get(descriptor);
+    }
+    
+    private void mergeMessage(JsonElement json, Message.Builder builder,
+        boolean skipTypeUrl) throws InvalidProtocolBufferException {
+      if (!(json instanceof JsonObject)) {
+        throw new InvalidProtocolBufferException(
+            "Expect message object but got: " + json);
+      }
+      JsonObject object = (JsonObject) json;
+      Map<String, FieldDescriptor> fieldNameMap =
+          getFieldNameMap(builder.getDescriptorForType());
+      for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
+        if (skipTypeUrl && entry.getKey().equals("@type")) {
+          continue;
+        }
+        FieldDescriptor field = fieldNameMap.get(entry.getKey());
+        if (field == null) {
+          throw new InvalidProtocolBufferException(
+              "Cannot find field: " + entry.getKey() + " in message "
+              + builder.getDescriptorForType().getFullName());
+        }
+        mergeField(field, entry.getValue(), builder);
+      }
+    }
+    
+    private void mergeAny(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor descriptor = builder.getDescriptorForType();
+      FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
+      FieldDescriptor valueField = descriptor.findFieldByName("value");
+      // Validates type of the message. Note that we can't just cast the message
+      // to com.google.protobuf.Any because it might be a DynamicMessage. 
+      if (typeUrlField == null || valueField == null
+          || typeUrlField.getType() != FieldDescriptor.Type.STRING
+          || valueField.getType() != FieldDescriptor.Type.BYTES) {
+        throw new InvalidProtocolBufferException("Invalid Any type.");
+      }
+      
+      if (!(json instanceof JsonObject)) {
+        throw new InvalidProtocolBufferException(
+            "Expect message object but got: " + json);
+      }
+      JsonObject object = (JsonObject) json;
+      JsonElement typeUrlElement = object.get("@type");
+      if (typeUrlElement == null) {
+        throw new InvalidProtocolBufferException(
+            "Missing type url when parsing: " + json);
+      }
+      String typeUrl = typeUrlElement.getAsString();
+      Descriptor contentType = registry.find(getTypeName(typeUrl));
+      if (contentType == null) {
+        throw new InvalidProtocolBufferException(
+            "Cannot resolve type: " + typeUrl);
+      }
+      builder.setField(typeUrlField, typeUrl);
+      Message.Builder contentBuilder =
+          DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
+      WellKnownTypeParser specialParser =
+          wellKnownTypeParsers.get(contentType.getFullName());
+      if (specialParser != null) {
+        JsonElement value = object.get("value");
+        if (value != null) {
+          specialParser.merge(this, value, contentBuilder);
+        }
+      } else {
+        mergeMessage(json, contentBuilder, true);
+      }
+      builder.setField(valueField, contentBuilder.build().toByteString());
+    }
+    
+    private void mergeFieldMask(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      FieldMask value = FieldMaskUtil.fromString(json.getAsString());
+      builder.mergeFrom(value.toByteString());
+    }
+    
+    private void mergeTimestamp(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      try {
+        Timestamp value = TimeUtil.parseTimestamp(json.getAsString());
+        builder.mergeFrom(value.toByteString());
+      } catch (ParseException e) {
+        throw new InvalidProtocolBufferException(
+            "Failed to parse timestamp: " + json);
+      }
+    }
+    
+    private void mergeDuration(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      try {
+        Duration value = TimeUtil.parseDuration(json.getAsString());
+        builder.mergeFrom(value.toByteString());
+      } catch (ParseException e) {
+        throw new InvalidProtocolBufferException(
+            "Failed to parse duration: " + json);
+      }
+    }
+    
+    private void mergeStruct(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor descriptor = builder.getDescriptorForType();
+      FieldDescriptor field = descriptor.findFieldByName("fields");
+      if (field == null) {
+        throw new InvalidProtocolBufferException("Invalid Struct type.");
+      }
+      mergeMapField(field, json, builder);
+    }
+
+    private void mergeListValue(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor descriptor = builder.getDescriptorForType();
+      FieldDescriptor field = descriptor.findFieldByName("values");
+      if (field == null) {
+        throw new InvalidProtocolBufferException("Invalid ListValue type.");
+      }
+      mergeRepeatedField(field, json, builder);
+    }
+    
+    private void mergeValue(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor type = builder.getDescriptorForType();
+      if (json instanceof JsonPrimitive) {
+        JsonPrimitive primitive = (JsonPrimitive) json;
+        if (primitive.isBoolean()) {
+          builder.setField(type.findFieldByName("bool_value"),
+              primitive.getAsBoolean());
+        } else if (primitive.isNumber()) {
+          builder.setField(type.findFieldByName("number_value"),
+              primitive.getAsDouble());
+        } else {
+          builder.setField(type.findFieldByName("string_value"),
+              primitive.getAsString());
+        }
+      } else if (json instanceof JsonObject) {
+        FieldDescriptor field = type.findFieldByName("struct_value");
+        Message.Builder structBuilder = builder.newBuilderForField(field);
+        merge(json, structBuilder);
+        builder.setField(field, structBuilder.build());
+      } else if (json instanceof JsonArray) {
+        FieldDescriptor field = type.findFieldByName("list_value");
+        Message.Builder listBuilder = builder.newBuilderForField(field);
+        merge(json, listBuilder);
+        builder.setField(field, listBuilder.build());
+      } else {
+        throw new IllegalStateException("Unexpected json data: " + json);
+      }
+    }
+    
+    private void mergeWrapper(JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
+      Descriptor type = builder.getDescriptorForType();
+      FieldDescriptor field = type.findFieldByName("value");
+      if (field == null) {
+        throw new InvalidProtocolBufferException(
+            "Invalid wrapper type: " + type.getFullName());
+      }
+      builder.setField(field, parseFieldValue(field, json, builder));
+    }
+    
+    private void mergeField(FieldDescriptor field, JsonElement json,
+        Message.Builder builder) throws InvalidProtocolBufferException {
+      if (field.isRepeated()) {
+        if (builder.getRepeatedFieldCount(field) > 0) {
+          throw new InvalidProtocolBufferException(
+              "Field " + field.getFullName() + " has already been set.");
+        }
+      } else {
+        if (builder.hasField(field)) {
+          throw new InvalidProtocolBufferException(
+              "Field " + field.getFullName() + " has already been set.");
+        }
+        if (field.getContainingOneof() != null
+            && builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
+          FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
+          throw new InvalidProtocolBufferException(
+              "Cannot set field " + field.getFullName() + " because another field "
+              + other.getFullName() + " belonging to the same oneof has already been set ");
+        }
+      }
+      if (field.isRepeated() && json instanceof JsonNull) {
+        // We allow "null" as value for all field types and treat it as if the
+        // field is not present.
+        return;
+      }
+      if (field.isMapField()) {
+        mergeMapField(field, json, builder);
+      } else if (field.isRepeated()) {
+        mergeRepeatedField(field, json, builder);
+      } else {
+        Object value = parseFieldValue(field, json, builder);
+        if (value != null) {
+          builder.setField(field, value);
+        }
+      }
+    }
+    
+    private void mergeMapField(FieldDescriptor field, JsonElement json,
+        Message.Builder builder) throws InvalidProtocolBufferException {
+      if (!(json instanceof JsonObject)) {
+        throw new InvalidProtocolBufferException(
+            "Expect a map object but found: " + json);
+      }
+      Descriptor type = field.getMessageType();
+      FieldDescriptor keyField = type.findFieldByName("key");
+      FieldDescriptor valueField = type.findFieldByName("value");
+      if (keyField == null || valueField == null) {
+        throw new InvalidProtocolBufferException(
+            "Invalid map field: " + field.getFullName());
+      }
+      JsonObject object = (JsonObject) json;
+      for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
+        Message.Builder entryBuilder = builder.newBuilderForField(field);
+        Object key = parseFieldValue(
+            keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
+        Object value = parseFieldValue(
+            valueField, entry.getValue(), entryBuilder);
+        if (value == null) {
+          throw new InvalidProtocolBufferException(
+              "Map value cannot be null.");
+        }
+        entryBuilder.setField(keyField, key);
+        entryBuilder.setField(valueField, value);
+        builder.addRepeatedField(field, entryBuilder.build());
+      }
+    }
+    
+    /**
+     * Gets the default value for a field type. Note that we use proto3
+     * language defaults and ignore any default values set through the
+     * proto "default" option. 
+     */
+    private Object getDefaultValue(FieldDescriptor field,
+        Message.Builder builder) {
+      switch (field.getType()) {
+        case INT32:
+        case SINT32:
+        case SFIXED32:
+        case UINT32:
+        case FIXED32:
+          return 0;
+        case INT64:
+        case SINT64:
+        case SFIXED64:
+        case UINT64:
+        case FIXED64:
+          return 0L;
+        case FLOAT:
+          return 0.0f;
+        case DOUBLE:
+          return 0.0;
+        case BOOL:
+          return false;
+        case STRING:
+          return "";
+        case BYTES:
+          return ByteString.EMPTY;
+        case ENUM:
+          return field.getEnumType().getValues().get(0);
+        case MESSAGE:
+        case GROUP:
+          return builder.newBuilderForField(field).getDefaultInstanceForType();
+        default:
+          throw new IllegalStateException(
+              "Invalid field type: " + field.getType());
+      }
+    }
+    
+    private void mergeRepeatedField(FieldDescriptor field, JsonElement json,
+        Message.Builder builder) throws InvalidProtocolBufferException {
+      if (!(json instanceof JsonArray)) {
+        throw new InvalidProtocolBufferException(
+            "Expect an array but found: " + json);
+      }
+      JsonArray array = (JsonArray) json;
+      for (int i = 0; i < array.size(); ++i) {
+        Object value = parseFieldValue(field, array.get(i), builder);
+        if (value == null) {
+          throw new InvalidProtocolBufferException(
+              "Repeated field elements cannot be null");
+        }
+        builder.addRepeatedField(field, value);
+      }
+    }
+    
+    private int parseInt32(JsonElement json)
+        throws InvalidProtocolBufferException {
+      try {
+        return Integer.parseInt(json.getAsString());
+      } catch (Exception e) {
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal value = new BigDecimal(json.getAsString());
+        return value.intValueExact();
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException("Not an int32 value: " + json);
+      }
+    }
+    
+    private long parseInt64(JsonElement json)
+        throws InvalidProtocolBufferException {
+      try {
+        return Long.parseLong(json.getAsString());
+      } catch (Exception e) {
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal value = new BigDecimal(json.getAsString());
+        return value.longValueExact();
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException("Not an int32 value: " + json);
+      }
+    }
+    
+    private int parseUint32(JsonElement json)
+        throws InvalidProtocolBufferException {
+      try {
+        long result = Long.parseLong(json.getAsString());
+        if (result < 0 || result > 0xFFFFFFFFL) {
+          throw new InvalidProtocolBufferException(
+              "Out of range uint32 value: " + json);
+        }
+        return (int) result;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal decimalValue = new BigDecimal(json.getAsString());
+        BigInteger value = decimalValue.toBigIntegerExact();
+        if (value.signum() < 0 || value.compareTo(new BigInteger("FFFFFFFF", 16)) > 0) {
+          throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
+        }
+        return value.intValue();
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException(
+            "Not an uint32 value: " + json);
+      }
+    }
+    
+    private static final BigInteger MAX_UINT64 =
+        new BigInteger("FFFFFFFFFFFFFFFF", 16);
+    
+    private long parseUint64(JsonElement json)
+        throws InvalidProtocolBufferException {
+      try {
+        BigDecimal decimalValue = new BigDecimal(json.getAsString());
+        BigInteger value = decimalValue.toBigIntegerExact();
+        if (value.compareTo(BigInteger.ZERO) < 0
+            || value.compareTo(MAX_UINT64) > 0) {
+          throw new InvalidProtocolBufferException(
+              "Out of range uint64 value: " + json);
+        }
+        return value.longValue();
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException(
+            "Not an uint64 value: " + json);
+      }
+    }
+    
+    private boolean parseBool(JsonElement json)
+        throws InvalidProtocolBufferException {
+      if (json.getAsString().equals("true")) {
+        return true;
+      }
+      if (json.getAsString().equals("false")) {
+        return false;
+      }
+      throw new InvalidProtocolBufferException("Invalid bool value: " + json);
+    }
+    
+    private static final double EPSILON = 1e-6;
+    
+    private float parseFloat(JsonElement json)
+        throws InvalidProtocolBufferException {
+      if (json.getAsString().equals("NaN")) {
+        return Float.NaN;
+      } else if (json.getAsString().equals("Infinity")) {
+        return Float.POSITIVE_INFINITY;
+      } else if (json.getAsString().equals("-Infinity")) {
+        return Float.NEGATIVE_INFINITY;
+      }
+      try {
+        // We don't use Float.parseFloat() here because that function simply
+        // accepts all double values. Here we parse the value into a Double
+        // and do explicit range check on it.
+        double value = Double.parseDouble(json.getAsString());
+        // When a float value is printed, the printed value might be a little
+        // larger or smaller due to precision loss. Here we need to add a bit
+        // of tolerance when checking whether the float value is in range.
+        if (value > Float.MAX_VALUE * (1.0 + EPSILON)
+            || value < -Float.MAX_VALUE * (1.0 + EPSILON)) {
+          throw new InvalidProtocolBufferException(
+              "Out of range float value: " + json);
+        }
+        return (float) value;
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException("Not a float value: " + json);
+      }
+    }
+    
+    private static final BigDecimal MORE_THAN_ONE = new BigDecimal(
+        String.valueOf(1.0 + EPSILON));
+    // When a float value is printed, the printed value might be a little
+    // larger or smaller due to precision loss. Here we need to add a bit
+    // of tolerance when checking whether the float value is in range.
+    private static final BigDecimal MAX_DOUBLE = new BigDecimal(
+        String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+    private static final BigDecimal MIN_DOUBLE = new BigDecimal(
+        String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+    
+    private double parseDouble(JsonElement json)
+        throws InvalidProtocolBufferException {
+      if (json.getAsString().equals("NaN")) {
+        return Double.NaN;
+      } else if (json.getAsString().equals("Infinity")) {
+        return Double.POSITIVE_INFINITY;
+      } else if (json.getAsString().equals("-Infinity")) {
+        return Double.NEGATIVE_INFINITY;
+      }
+      try {
+        // We don't use Double.parseDouble() here because that function simply
+        // accepts all values. Here we parse the value into a BigDecimal and do
+        // explicit range check on it.
+        BigDecimal value = new BigDecimal(json.getAsString());
+        if (value.compareTo(MAX_DOUBLE) > 0
+            || value.compareTo(MIN_DOUBLE) < 0) {
+          throw new InvalidProtocolBufferException(
+              "Out of range double value: " + json);
+        }
+        return value.doubleValue();
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException(
+            "Not an double value: " + json);
+      }
+    }
+    
+    private String parseString(JsonElement json) {
+      return json.getAsString();
+    }
+    
+    private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
+      String encoded = json.getAsString();
+      if (encoded.length() % 4 != 0) {
+        throw new InvalidProtocolBufferException(
+            "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
+      }
+      return ByteString.copyFrom(
+          BaseEncoding.base64().decode(json.getAsString()));
+    }
+    
+    private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor,
+        JsonElement json) throws InvalidProtocolBufferException {
+      String value = json.getAsString();
+      EnumValueDescriptor result = enumDescriptor.findValueByName(value);
+      if (result == null) {
+        // Try to interpret the value as a number.
+        try {
+          int numericValue = parseInt32(json);
+          if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
+            result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericValue);
+          } else {
+            result = enumDescriptor.findValueByNumber(numericValue);
+          }
+        } catch (InvalidProtocolBufferException e) {
+          // Fall through. This exception is about invalid int32 value we get from parseInt32() but
+          // that's not the exception we want the user to see. Since result == null, we will throw
+          // an exception later.
+        }
+        
+        if (result == null) {
+          throw new InvalidProtocolBufferException(
+              "Invalid enum value: " + value + " for enum type: "
+              + enumDescriptor.getFullName());
+        }
+      }
+      return result;
+    }
+    
+    private Object parseFieldValue(FieldDescriptor field, JsonElement json,
+        Message.Builder builder) throws InvalidProtocolBufferException {
+      if (json instanceof JsonNull) {
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
+            && field.getMessageType().getFullName().equals(
+                   Value.getDescriptor().getFullName())) {
+          // For every other type, "null" means absence, but for the special
+          // Value message, it means the "null_value" field has been set.
+          Value value = Value.newBuilder().setNullValueValue(0).build();
+          return builder.newBuilderForField(field).mergeFrom(
+              value.toByteString()).build();
+        }
+        return null;
+      }
+      switch (field.getType()) {
+        case INT32:
+        case SINT32:
+        case SFIXED32:
+          return parseInt32(json);
+
+        case INT64:
+        case SINT64:
+        case SFIXED64:
+          return parseInt64(json);
+
+        case BOOL:
+          return parseBool(json);
+
+        case FLOAT:
+          return parseFloat(json);
+          
+        case DOUBLE:
+          return parseDouble(json);
+
+        case UINT32:
+        case FIXED32:
+          return parseUint32(json);
+
+        case UINT64:
+        case FIXED64:
+          return parseUint64(json);
+
+        case STRING:
+          return parseString(json);
+
+        case BYTES:
+          return parseBytes(json);
+
+        case ENUM:
+          return parseEnum(field.getEnumType(), json);
+
+        case MESSAGE:
+        case GROUP:
+          Message.Builder subBuilder = builder.newBuilderForField(field);
+          merge(json, subBuilder);
+          return subBuilder.build();
+          
+        default:
+          throw new InvalidProtocolBufferException(
+              "Invalid field type: " + field.getType());
+      } 
+    }
+  }
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
new file mode 100644
index 0000000..3033182
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -0,0 +1,549 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+
+import java.math.BigInteger;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * Utilities to help create/manipulate Timestamp/Duration
+ */
+public class TimeUtil {
+  // Timestamp for "0001-01-01T00:00:00Z"
+  public static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
+
+  // Timestamp for "9999-12-31T23:59:59Z"
+  public static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
+  public static final long DURATION_SECONDS_MIN = -315576000000L;
+  public static final long DURATION_SECONDS_MAX = 315576000000L;
+
+  private static final long NANOS_PER_SECOND = 1000000000;
+  private static final long NANOS_PER_MILLISECOND = 1000000;
+  private static final long NANOS_PER_MICROSECOND = 1000;
+  private static final long MILLIS_PER_SECOND = 1000;
+  private static final long MICROS_PER_SECOND = 1000000;
+
+  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
+      new ThreadLocal<SimpleDateFormat>() {
+        protected SimpleDateFormat initialValue() {
+          return createTimestampFormat();
+        }
+      };
+
+  private static SimpleDateFormat createTimestampFormat() {
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+    GregorianCalendar calendar =
+      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
+    // backwards to year one) for timestamp formating.
+    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
+    sdf.setCalendar(calendar);
+    return sdf;
+  }
+
+  private TimeUtil() {}
+
+  /**
+   * Convert Timestamp to RFC 3339 date string format. The output will always
+   * be Z-normalized and uses 3, 6 or 9 fractional digits as required to
+   * represent the exact value. Note that Timestamp can only represent time
+   * from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. See
+   * https://www.ietf.org/rfc/rfc3339.txt
+   *
+   * <p>Example of generated format: "1972-01-01T10:00:20.021Z"
+   *
+   * @return The string representation of the given timestamp.
+   * @throws IllegalArgumentException if the given timestamp is not in the
+   *         valid range.
+   */
+  public static String toString(Timestamp timestamp)
+    throws IllegalArgumentException {
+    StringBuilder result = new StringBuilder();
+    // Format the seconds part.
+    if (timestamp.getSeconds() < TIMESTAMP_SECONDS_MIN
+        || timestamp.getSeconds() > TIMESTAMP_SECONDS_MAX) {
+      throw new IllegalArgumentException("Timestamp is out of range.");
+    }
+    Date date = new Date(timestamp.getSeconds() * MILLIS_PER_SECOND);
+    result.append(timestampFormat.get().format(date));
+    // Format the nanos part.
+    if (timestamp.getNanos() < 0 || timestamp.getNanos() >= NANOS_PER_SECOND) {
+      throw new IllegalArgumentException("Timestamp has invalid nanos value.");
+    }
+    if (timestamp.getNanos() != 0) {
+      result.append(".");
+      result.append(formatNanos(timestamp.getNanos()));
+    }
+    result.append("Z");
+    return result.toString();
+  }
+
+  /**
+   * Parse from RFC 3339 date string to Timestamp. This method accepts all
+   * outputs of {@link #toString(Timestamp)} and it also accepts any fractional
+   * digits (or none) and any offset as long as they fit into nano-seconds
+   * precision.
+   *
+   * <p>Example of accepted format: "1972-01-01T10:00:20.021-05:00"
+   *
+   * @return A Timestamp parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+
+  public static Timestamp parseTimestamp(String value) throws ParseException {
+    int dayOffset = value.indexOf('T');
+    if (dayOffset == -1) {
+      throw new ParseException(
+        "Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
+    }
+    int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('+', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('-', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      throw new ParseException(
+        "Failed to parse timestamp: missing valid timezone offset.", 0);
+    }
+    // Parse seconds and nanos.
+    String timeValue = value.substring(0, timezoneOffsetPosition);
+    String secondValue = timeValue;
+    String nanoValue = "";
+    int pointPosition = timeValue.indexOf('.');
+    if (pointPosition != -1) {
+      secondValue = timeValue.substring(0, pointPosition);
+      nanoValue = timeValue.substring(pointPosition + 1);
+    }
+    Date date = timestampFormat.get().parse(secondValue);
+    long seconds = date.getTime() / MILLIS_PER_SECOND;
+    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
+    // Parse timezone offsets.
+    if (value.charAt(timezoneOffsetPosition) == 'Z') {
+      if (value.length() != timezoneOffsetPosition + 1) {
+        throw new ParseException(
+          "Failed to parse timestamp: invalid trailing data \""
+          + value.substring(timezoneOffsetPosition) + "\"", 0);
+      }
+    } else {
+      String offsetValue = value.substring(timezoneOffsetPosition + 1);
+      long offset = parseTimezoneOffset(offsetValue);
+      if (value.charAt(timezoneOffsetPosition) == '+') {
+        seconds -= offset;
+      } else {
+        seconds += offset;
+      }
+    }
+    try {
+      return normalizedTimestamp(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException(
+        "Failed to parse timestmap: timestamp is out of range.", 0);
+    }
+  }
+
+  /**
+   * Convert Duration to string format. The string format will contains 3, 6,
+   * or 9 fractional digits depending on the precision required to represent
+   * the exact Duration value. For example: "1s", "1.010s", "1.000000100s",
+   * "-3.100s" The range that can be represented by Duration is from
+   * -315,576,000,000 to +315,576,000,000 inclusive (in seconds).
+   *
+   * @return The string representation of the given duration.
+   * @throws IllegalArgumentException if the given duration is not in the valid
+   *         range.
+   */
+  public static String toString(Duration duration)
+    throws IllegalArgumentException {
+    if (duration.getSeconds() < DURATION_SECONDS_MIN
+      || duration.getSeconds() > DURATION_SECONDS_MAX) {
+      throw new IllegalArgumentException("Duration is out of valid range.");
+    }
+    StringBuilder result = new StringBuilder();
+    long seconds = duration.getSeconds();
+    int nanos = duration.getNanos();
+    if (seconds < 0 || nanos < 0) {
+      if (seconds > 0 || nanos > 0) {
+        throw new IllegalArgumentException(
+            "Invalid duration: seconds value and nanos value must have the same"
+            + "sign.");
+      }
+      result.append("-");
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    result.append(seconds);
+    if (nanos != 0) {
+      result.append(".");
+      result.append(formatNanos(nanos));
+    }
+    result.append("s");
+    return result.toString();
+  }
+
+  /**
+   * Parse from a string to produce a duration.
+   *
+   * @return A Duration parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+  public static Duration parseDuration(String value) throws ParseException {
+    // Must ended with "s".
+    if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    boolean negative = false;
+    if (value.charAt(0) == '-') {
+      negative = true;
+      value = value.substring(1);
+    }
+    String secondValue = value.substring(0, value.length() - 1);
+    String nanoValue = "";
+    int pointPosition = secondValue.indexOf('.');
+    if (pointPosition != -1) {
+      nanoValue = secondValue.substring(pointPosition + 1);
+      secondValue = secondValue.substring(0, pointPosition);
+    }
+    long seconds = Long.parseLong(secondValue);
+    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
+    if (seconds < 0) {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    if (negative) {
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    try {
+      return normalizedDuration(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException("Duration value is out of range.", 0);
+    }
+  }
+
+  /**
+   * Create a Timestamp from the number of milliseconds elapsed from the epoch.
+   */
+  public static Timestamp createTimestampFromMillis(long milliseconds) {
+    return normalizedTimestamp(milliseconds / MILLIS_PER_SECOND,
+      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Create a Duration from the number of milliseconds.
+   */
+  public static Duration createDurationFromMillis(long milliseconds) {
+    return normalizedDuration(milliseconds / MILLIS_PER_SECOND,
+      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of milliseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest millisecond. E.g., if the
+   * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
+   * to -1 millisecond.
+   */
+  public static long toMillis(Timestamp timestamp) {
+    return timestamp.getSeconds() * MILLIS_PER_SECOND + timestamp.getNanos()
+      / NANOS_PER_MILLISECOND;
+  }
+
+  /**
+   * Convert a Duration to the number of milliseconds.The result will be
+   * rounded towards 0 to the nearest millisecond. E.g., if the duration
+   * represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMillis(Duration duration) {
+    return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos()
+      / NANOS_PER_MILLISECOND;
+  }
+
+  /**
+   * Create a Timestamp from the number of microseconds elapsed from the epoch.
+   */
+  public static Timestamp createTimestampFromMicros(long microseconds) {
+    return normalizedTimestamp(microseconds / MICROS_PER_SECOND,
+      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Create a Duration from the number of microseconds.
+   */
+  public static Duration createDurationFromMicros(long microseconds) {
+    return normalizedDuration(microseconds / MICROS_PER_SECOND,
+      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of microseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest microsecond. E.g., if the
+   * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
+   * to -1 millisecond.
+   */
+  public static long toMicros(Timestamp timestamp) {
+    return timestamp.getSeconds() * MICROS_PER_SECOND + timestamp.getNanos()
+      / NANOS_PER_MICROSECOND;
+  }
+
+  /**
+   * Convert a Duration to the number of microseconds.The result will be
+   * rounded towards 0 to the nearest microseconds. E.g., if the duration
+   * represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMicros(Duration duration) {
+    return duration.getSeconds() * MICROS_PER_SECOND + duration.getNanos()
+      / NANOS_PER_MICROSECOND;
+  }
+
+  /**
+   * Create a Timestamp from the number of nanoseconds elapsed from the epoch.
+   */
+  public static Timestamp createTimestampFromNanos(long nanoseconds) {
+    return normalizedTimestamp(nanoseconds / NANOS_PER_SECOND,
+      (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /**
+   * Create a Duration from the number of nanoseconds.
+   */
+  public static Duration createDurationFromNanos(long nanoseconds) {
+    return normalizedDuration(nanoseconds / NANOS_PER_SECOND,
+      (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of nanoseconds elapsed from the epoch.
+   */
+  public static long toNanos(Timestamp timestamp) {
+    return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
+  }
+
+  /**
+   * Convert a Duration to the number of nanoseconds.
+   */
+  public static long toNanos(Duration duration) {
+    return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
+  }
+
+  /**
+   * Get the current time.
+   */
+  public static Timestamp getCurrentTime() {
+    return createTimestampFromMillis(System.currentTimeMillis());
+  }
+
+  /**
+   * Get the epoch.
+   */
+  public static Timestamp getEpoch() {
+    return Timestamp.getDefaultInstance();
+  }
+
+  /**
+   * Calculate the difference between two timestamps.
+   */
+  public static Duration distance(Timestamp from, Timestamp to) {
+    return normalizedDuration(to.getSeconds() - from.getSeconds(),
+      to.getNanos() - from.getNanos());
+  }
+
+  /**
+   * Add a duration to a timestamp.
+   */
+  public static Timestamp add(Timestamp start, Duration length) {
+    return normalizedTimestamp(start.getSeconds() + length.getSeconds(),
+      start.getNanos() + length.getNanos());
+  }
+
+  /**
+   * Subtract a duration from a timestamp.
+   */
+  public static Timestamp subtract(Timestamp start, Duration length) {
+    return normalizedTimestamp(start.getSeconds() - length.getSeconds(),
+      start.getNanos() - length.getNanos());
+  }
+
+  /**
+   * Add two durations.
+   */
+  public static Duration add(Duration d1, Duration d2) {
+    return normalizedDuration(d1.getSeconds() + d2.getSeconds(),
+      d1.getNanos() + d2.getNanos());
+  }
+
+  /**
+   * Subtract a duration from another.
+   */
+  public static Duration subtract(Duration d1, Duration d2) {
+    return normalizedDuration(d1.getSeconds() - d2.getSeconds(),
+      d1.getNanos() - d2.getNanos());
+  }
+
+  // Multiplications and divisions.
+
+  public static Duration multiply(Duration duration, double times) {
+    double result = duration.getSeconds() * times + duration.getNanos() * times
+      / 1000000000.0;
+    if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {
+      throw new IllegalArgumentException("Result is out of valid range.");
+    }
+    long seconds = (long) result;
+    int nanos = (int) ((result - seconds) * 1000000000);
+    return normalizedDuration(seconds, nanos);
+  }
+  
+  public static Duration divide(Duration duration, double value) {
+    return multiply(duration, 1.0 / value);
+  }
+  
+  public static Duration multiply(Duration duration, long times) {
+    return createDurationFromBigInteger(
+      toBigInteger(duration).multiply(toBigInteger(times)));
+  }
+  
+  public static Duration divide(Duration duration, long times) {
+    return createDurationFromBigInteger(
+      toBigInteger(duration).divide(toBigInteger(times)));
+  }
+  
+  public static long divide(Duration d1, Duration d2) {
+    return toBigInteger(d1).divide(toBigInteger(d2)).longValue();
+  }
+  
+  public static Duration remainder(Duration d1, Duration d2) {
+    return createDurationFromBigInteger(
+      toBigInteger(d1).remainder(toBigInteger(d2)));
+  }
+  
+  private static final BigInteger NANOS_PER_SECOND_BIG_INTEGER =
+      new BigInteger(String.valueOf(NANOS_PER_SECOND));
+  
+  private static BigInteger toBigInteger(Duration duration) {
+    return toBigInteger(duration.getSeconds())
+      .multiply(NANOS_PER_SECOND_BIG_INTEGER)
+      .add(toBigInteger(duration.getNanos()));
+  }
+  
+  private static BigInteger toBigInteger(long value) {
+    return new BigInteger(String.valueOf(value));
+  }
+  
+  private static Duration createDurationFromBigInteger(BigInteger value) {
+    long seconds = value.divide(
+      new BigInteger(String.valueOf(NANOS_PER_SECOND))).longValue();
+    int nanos = value.remainder(
+      new BigInteger(String.valueOf(NANOS_PER_SECOND))).intValue();
+    return normalizedDuration(seconds, nanos);
+    
+  }
+
+  private static Duration normalizedDuration(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds += nanos / NANOS_PER_SECOND;
+      nanos %= NANOS_PER_SECOND;
+    }
+    if (seconds > 0 && nanos < 0) {
+      nanos += NANOS_PER_SECOND;
+      seconds -= 1;
+    }
+    if (seconds < 0 && nanos > 0) {
+      nanos -= NANOS_PER_SECOND;
+      seconds += 1;
+    }
+    if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
+      throw new IllegalArgumentException("Duration is out of valid range.");
+    }
+    return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+  }
+
+  private static Timestamp normalizedTimestamp(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds += nanos / NANOS_PER_SECOND;
+      nanos %= NANOS_PER_SECOND;
+    }
+    if (nanos < 0) {
+      nanos += NANOS_PER_SECOND;
+      seconds -= 1;
+    }
+    if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
+      throw new IllegalArgumentException("Timestamp is out of valid range.");
+    }
+    return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+  }
+
+  /**
+   * Format the nano part of a timestamp or a duration.
+   */
+  private static String formatNanos(int nanos) {
+    assert nanos >= 1 && nanos <= 999999999;
+    // Determine whether to use 3, 6, or 9 digits for the nano part.
+    if (nanos % NANOS_PER_MILLISECOND == 0) {
+      return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);
+    } else if (nanos % NANOS_PER_MICROSECOND == 0) {
+      return String.format("%1$06d", nanos / NANOS_PER_MICROSECOND);
+    } else {
+      return String.format("%1$09d", nanos);
+    }
+  }
+
+  private static int parseNanos(String value) throws ParseException {
+    int result = 0;
+    for (int i = 0; i < 9; ++i) {
+      result = result * 10;
+      if (i < value.length()) {
+        if (value.charAt(i) < '0' || value.charAt(i) > '9') {
+          throw new ParseException("Invalid nanosecnds.", 0);
+        }
+        result += value.charAt(i) - '0';
+      }
+    }
+    return result;
+  }
+
+  private static long parseTimezoneOffset(String value) throws ParseException {
+    int pos = value.indexOf(':');
+    if (pos == -1) {
+      throw new ParseException("Invalid offset value: " + value, 0);
+    }
+    String hours = value.substring(0, pos);
+    String minutes = value.substring(pos + 1);
+    return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
+  }
+}
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
new file mode 100644
index 0000000..3ee0fc6
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
@@ -0,0 +1,261 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import protobuf_unittest.UnittestProto.NestedTestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+
+import junit.framework.TestCase;
+
+public class FieldMaskTreeTest extends TestCase {
+  public void testAddFieldPath() throws Exception {
+    FieldMaskTree tree = new FieldMaskTree();
+    assertEquals("", tree.toString());
+    tree.addFieldPath("");
+    assertEquals("", tree.toString());
+    // New branch.
+    tree.addFieldPath("foo");
+    assertEquals("foo", tree.toString());
+    // Redundant path.
+    tree.addFieldPath("foo");
+    assertEquals("foo", tree.toString());
+    // New branch.
+    tree.addFieldPath("bar.baz");
+    assertEquals("bar.baz,foo", tree.toString());
+    // Redundant sub-path.
+    tree.addFieldPath("foo.bar");
+    assertEquals("bar.baz,foo", tree.toString());
+    // New branch from a non-root node.
+    tree.addFieldPath("bar.quz");
+    assertEquals("bar.baz,bar.quz,foo", tree.toString());
+    // A path that matches several existing sub-paths.
+    tree.addFieldPath("bar");
+    assertEquals("bar,foo", tree.toString());
+  }
+
+  public void testMergeFromFieldMask() throws Exception {
+    FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+    assertEquals("bar.baz,bar.quz,foo", tree.toString());
+    tree.mergeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar"));
+    assertEquals("bar,foo", tree.toString());
+  }
+
+  public void testIntersectFieldPath() throws Exception {
+    FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz"));
+    FieldMaskTree result = new FieldMaskTree();
+    // Empty path.
+    tree.intersectFieldPath("", result);
+    assertEquals("", result.toString());
+    // Non-exist path.
+    tree.intersectFieldPath("quz", result);
+    assertEquals("", result.toString());
+    // Sub-path of an existing leaf.
+    tree.intersectFieldPath("foo.bar", result);
+    assertEquals("foo.bar", result.toString());
+    // Match an existing leaf node.
+    tree.intersectFieldPath("foo", result);
+    assertEquals("foo", result.toString());
+    // Non-exist path.
+    tree.intersectFieldPath("bar.foo", result);
+    assertEquals("foo", result.toString());
+    // Match a non-leaf node.
+    tree.intersectFieldPath("bar", result);
+    assertEquals("bar.baz,bar.quz,foo", result.toString());
+  }
+
+  public void testMerge() throws Exception {
+    TestAllTypes value =
+        TestAllTypes.newBuilder()
+            .setOptionalInt32(1234)
+            .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678))
+            .addRepeatedInt32(4321)
+            .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765))
+            .build();
+    NestedTestAllTypes source =
+        NestedTestAllTypes.newBuilder()
+            .setPayload(value)
+            .setChild(NestedTestAllTypes.newBuilder().setPayload(value))
+            .build();
+    // Now we have a message source with the following structure:
+    //   [root] -+- payload -+- optional_int32
+    //           |           +- optional_nested_message
+    //           |           +- repeated_int32
+    //           |           +- repeated_nested_message
+    //           |
+    //           +- child --- payload -+- optional_int32
+    //                                 +- optional_nested_message
+    //                                 +- repeated_int32
+    //                                 +- repeated_nested_message
+
+    FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions();
+
+    // Test merging each individual field.
+    NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options);
+    NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
+    expected.getPayloadBuilder().setOptionalInt32(1234);
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_nested_message")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected.getPayloadBuilder().addRepeatedInt32(4321);
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.repeated_nested_message")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("child.payload.optional_int32")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("child.payload.optional_nested_message")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected
+        .getChildBuilder()
+        .getPayloadBuilder()
+        .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("child.payload.repeated_int32")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
+    assertEquals(expected.build(), builder.build());
+
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("child.payload.repeated_nested_message")
+        .merge(source, builder, options);
+    expected = NestedTestAllTypes.newBuilder();
+    expected
+        .getChildBuilder()
+        .getPayloadBuilder()
+        .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
+    assertEquals(expected.build(), builder.build());
+
+    // Test merging all fields.
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree()
+        .addFieldPath("child")
+        .addFieldPath("payload")
+        .merge(source, builder, options);
+    assertEquals(source, builder.build());
+
+    // Test repeated options.
+    builder = NestedTestAllTypes.newBuilder();
+    builder.getPayloadBuilder().addRepeatedInt32(1000);
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    // Default behavior is to append repeated fields.
+    assertEquals(2, builder.getPayload().getRepeatedInt32Count());
+    assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
+    assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
+    // Change to replace repeated fields.
+    options.setReplaceRepeatedFields(true);
+    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    assertEquals(1, builder.getPayload().getRepeatedInt32Count());
+    assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
+
+    // Test message options.
+    builder = NestedTestAllTypes.newBuilder();
+    builder.getPayloadBuilder().setOptionalInt32(1000);
+    builder.getPayloadBuilder().setOptionalUint32(2000);
+    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
+    // Default behavior is to merge message fields.
+    assertEquals(1234, builder.getPayload().getOptionalInt32());
+    assertEquals(2000, builder.getPayload().getOptionalUint32());
+
+    // Test merging unset message fields.
+    NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
+    builder = NestedTestAllTypes.newBuilder();
+    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    assertEquals(false, builder.hasPayload());
+
+    // Change to replace message fields.
+    options.setReplaceMessageFields(true);
+    builder = NestedTestAllTypes.newBuilder();
+    builder.getPayloadBuilder().setOptionalInt32(1000);
+    builder.getPayloadBuilder().setOptionalUint32(2000);
+    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
+    assertEquals(1234, builder.getPayload().getOptionalInt32());
+    assertEquals(0, builder.getPayload().getOptionalUint32());
+
+    // Test merging unset message fields.
+    builder = NestedTestAllTypes.newBuilder();
+    builder.getPayloadBuilder().setOptionalInt32(1000);
+    builder.getPayloadBuilder().setOptionalUint32(2000);
+    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    assertEquals(false, builder.hasPayload());
+
+    // Test merging unset primitive fields.
+    builder = source.toBuilder();
+    builder.getPayloadBuilder().clearOptionalInt32();
+    NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build();
+    builder = source.toBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_int32")
+        .merge(sourceWithPayloadInt32Unset, builder, options);
+    assertEquals(true, builder.getPayload().hasOptionalInt32());
+    assertEquals(0, builder.getPayload().getOptionalInt32());
+
+    // Change to clear unset primitive fields.
+    options.setReplacePrimitiveFields(true);
+    builder = source.toBuilder();
+    new FieldMaskTree()
+        .addFieldPath("payload.optional_int32")
+        .merge(sourceWithPayloadInt32Unset, builder, options);
+    assertEquals(true, builder.hasPayload());
+    assertEquals(false, builder.getPayload().hasOptionalInt32());
+  }
+}
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
new file mode 100644
index 0000000..194f7b9
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -0,0 +1,184 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.protobuf.FieldMask;
+import protobuf_unittest.UnittestProto.NestedTestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+
+import junit.framework.TestCase;
+
+/** Unit tests for {@link FieldMaskUtil}. */
+public class FieldMaskUtilTest extends TestCase {
+  public void testIsValid() throws Exception {
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist"));
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.optional_int32"));
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.repeated_int32"));
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.optional_nested_message"));
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.repeated_nested_message"));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.nonexist"));
+    
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")));
+    
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist"));
+    
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
+    
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
+    // Repeated fields cannot have sub-paths.
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
+    // Non-message fields cannot have sub-paths.
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, "payload.optional_int32.bb"));
+  }
+  
+  public void testToString() throws Exception {
+    assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance()));
+    FieldMask mask = FieldMask.newBuilder().addPaths("foo").build();
+    assertEquals("foo", FieldMaskUtil.toString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build();
+    assertEquals("foo,bar", FieldMaskUtil.toString(mask));
+    
+    // Empty field paths are ignored.
+    mask = FieldMask.newBuilder().addPaths("").addPaths("foo").addPaths("").
+      addPaths("bar").addPaths("").build();
+    assertEquals("foo,bar", FieldMaskUtil.toString(mask));
+  }
+
+  public void testFromString() throws Exception {
+    FieldMask mask = FieldMaskUtil.fromString("");
+    assertEquals(0, mask.getPathsCount());
+    mask = FieldMaskUtil.fromString("foo");
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    mask = FieldMaskUtil.fromString("foo,bar.baz");
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    assertEquals("bar.baz", mask.getPaths(1));
+
+    // Empty field paths are ignore.
+    mask = FieldMaskUtil.fromString(",foo,,bar,");
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    assertEquals("bar", mask.getPaths(1));
+
+    // Check whether the field paths are valid if a class parameter is provided.
+    mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
+
+    try {
+      mask = FieldMaskUtil.fromString(
+          NestedTestAllTypes.class, "payload,nonexist");
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+  }
+
+  public void testFromFieldNumbers() throws Exception {
+    FieldMask mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class);
+    assertEquals(0, mask.getPathsCount());
+    mask =
+        FieldMaskUtil.fromFieldNumbers(
+            TestAllTypes.class, TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER);
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("optional_int32", mask.getPaths(0));
+    mask =
+        FieldMaskUtil.fromFieldNumbers(
+            TestAllTypes.class,
+            TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER,
+            TestAllTypes.OPTIONAL_INT64_FIELD_NUMBER);
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("optional_int32", mask.getPaths(0));
+    assertEquals("optional_int64", mask.getPaths(1));
+
+    try {
+      int invalidFieldNumber = 1000;
+      mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class, invalidFieldNumber);
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+  
+  public void testUnion() throws Exception {
+    // Only test a simple case here and expect
+    // {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios.
+    FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
+    FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
+    FieldMask result = FieldMaskUtil.union(mask1, mask2);
+    assertEquals("bar,foo", FieldMaskUtil.toString(result));
+  }
+
+  public void testUnion_usingVarArgs() throws Exception {
+    FieldMask mask1 = FieldMaskUtil.fromString("foo");
+    FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz");
+    FieldMask mask3 = FieldMaskUtil.fromString("bar.quz");
+    FieldMask mask4 = FieldMaskUtil.fromString("bar");
+    FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4);
+    assertEquals("bar,foo", FieldMaskUtil.toString(result));
+  }
+  
+  public void testIntersection() throws Exception {
+    // Only test a simple case here and expect
+    // {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios.
+    FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz");
+    FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar");
+    FieldMask result = FieldMaskUtil.intersection(mask1, mask2);
+    assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result));
+  }
+  
+  public void testMerge() throws Exception {
+    // Only test a simple case here and expect
+    // {@link FieldMaskTreeTest#testMerge} to cover all scenarios.
+    NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
+        .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
+        .build();
+    NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
+    FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder);
+    assertEquals(1234, builder.getPayload().getOptionalInt32());
+  }
+}
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
new file mode 100644
index 0000000..d95b626
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -0,0 +1,1174 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.BoolValue;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.BytesValue;
+import com.google.protobuf.DoubleValue;
+import com.google.protobuf.FloatValue;
+import com.google.protobuf.Int32Value;
+import com.google.protobuf.Int64Value;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.ListValue;
+import com.google.protobuf.Message;
+import com.google.protobuf.StringValue;
+import com.google.protobuf.Struct;
+import com.google.protobuf.UInt32Value;
+import com.google.protobuf.UInt64Value;
+import com.google.protobuf.Value;
+import com.google.protobuf.util.JsonFormat.TypeRegistry;
+import com.google.protobuf.util.JsonTestProto.TestAllTypes;
+import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedEnum;
+import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedMessage;
+import com.google.protobuf.util.JsonTestProto.TestAny;
+import com.google.protobuf.util.JsonTestProto.TestCustomJsonName;
+import com.google.protobuf.util.JsonTestProto.TestDuration;
+import com.google.protobuf.util.JsonTestProto.TestFieldMask;
+import com.google.protobuf.util.JsonTestProto.TestMap;
+import com.google.protobuf.util.JsonTestProto.TestOneof;
+import com.google.protobuf.util.JsonTestProto.TestStruct;
+import com.google.protobuf.util.JsonTestProto.TestTimestamp;
+import com.google.protobuf.util.JsonTestProto.TestWrappers;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonFormatTest extends TestCase {
+  private void setAllFields(TestAllTypes.Builder builder) {
+    builder.setOptionalInt32(1234);
+    builder.setOptionalInt64(1234567890123456789L);
+    builder.setOptionalUint32(5678);
+    builder.setOptionalUint64(2345678901234567890L);
+    builder.setOptionalSint32(9012);
+    builder.setOptionalSint64(3456789012345678901L);
+    builder.setOptionalFixed32(3456);
+    builder.setOptionalFixed64(4567890123456789012L);
+    builder.setOptionalSfixed32(7890);
+    builder.setOptionalSfixed64(5678901234567890123L);
+    builder.setOptionalFloat(1.5f);
+    builder.setOptionalDouble(1.25);
+    builder.setOptionalBool(true);
+    builder.setOptionalString("Hello world!");
+    builder.setOptionalBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.setOptionalNestedEnum(NestedEnum.BAR);
+    builder.getOptionalNestedMessageBuilder().setValue(100);
+
+    builder.addRepeatedInt32(1234);
+    builder.addRepeatedInt64(1234567890123456789L);
+    builder.addRepeatedUint32(5678);
+    builder.addRepeatedUint64(2345678901234567890L);
+    builder.addRepeatedSint32(9012);
+    builder.addRepeatedSint64(3456789012345678901L);
+    builder.addRepeatedFixed32(3456);
+    builder.addRepeatedFixed64(4567890123456789012L);
+    builder.addRepeatedSfixed32(7890);
+    builder.addRepeatedSfixed64(5678901234567890123L);
+    builder.addRepeatedFloat(1.5f);
+    builder.addRepeatedDouble(1.25);
+    builder.addRepeatedBool(true);
+    builder.addRepeatedString("Hello world!");
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.addRepeatedNestedEnum(NestedEnum.BAR);
+    builder.addRepeatedNestedMessageBuilder().setValue(100);
+
+    builder.addRepeatedInt32(234);
+    builder.addRepeatedInt64(234567890123456789L);
+    builder.addRepeatedUint32(678);
+    builder.addRepeatedUint64(345678901234567890L);
+    builder.addRepeatedSint32(012);
+    builder.addRepeatedSint64(456789012345678901L);
+    builder.addRepeatedFixed32(456);
+    builder.addRepeatedFixed64(567890123456789012L);
+    builder.addRepeatedSfixed32(890);
+    builder.addRepeatedSfixed64(678901234567890123L);
+    builder.addRepeatedFloat(11.5f);
+    builder.addRepeatedDouble(11.25);
+    builder.addRepeatedBool(true);
+    builder.addRepeatedString("ello world!");
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{1, 2}));
+    builder.addRepeatedNestedEnum(NestedEnum.BAZ);
+    builder.addRepeatedNestedMessageBuilder().setValue(200);
+  }
+
+  private void assertRoundTripEquals(Message message) throws Exception {
+    assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry());
+  }
+
+  private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception {
+    JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
+    JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
+    Message.Builder builder = message.newBuilderForType();
+    parser.merge(printer.print(message), builder);
+    Message parsedMessage = builder.build();
+    assertEquals(message.toString(), parsedMessage.toString());
+  }
+
+  private String toJsonString(Message message) throws IOException {
+    return JsonFormat.printer().print(message);
+  }
+
+  private void mergeFromJson(String json, Message.Builder builder) throws IOException {
+    JsonFormat.parser().merge(json, builder);
+  }
+
+  public void testAllFields() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    setAllFields(builder);
+    TestAllTypes message = builder.build();
+
+    assertEquals(
+        "{\n"
+            + "  \"optionalInt32\": 1234,\n"
+            + "  \"optionalInt64\": \"1234567890123456789\",\n"
+            + "  \"optionalUint32\": 5678,\n"
+            + "  \"optionalUint64\": \"2345678901234567890\",\n"
+            + "  \"optionalSint32\": 9012,\n"
+            + "  \"optionalSint64\": \"3456789012345678901\",\n"
+            + "  \"optionalFixed32\": 3456,\n"
+            + "  \"optionalFixed64\": \"4567890123456789012\",\n"
+            + "  \"optionalSfixed32\": 7890,\n"
+            + "  \"optionalSfixed64\": \"5678901234567890123\",\n"
+            + "  \"optionalFloat\": 1.5,\n"
+            + "  \"optionalDouble\": 1.25,\n"
+            + "  \"optionalBool\": true,\n"
+            + "  \"optionalString\": \"Hello world!\",\n"
+            + "  \"optionalBytes\": \"AAEC\",\n"
+            + "  \"optionalNestedMessage\": {\n"
+            + "    \"value\": 100\n"
+            + "  },\n"
+            + "  \"optionalNestedEnum\": \"BAR\",\n"
+            + "  \"repeatedInt32\": [1234, 234],\n"
+            + "  \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n"
+            + "  \"repeatedUint32\": [5678, 678],\n"
+            + "  \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n"
+            + "  \"repeatedSint32\": [9012, 10],\n"
+            + "  \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n"
+            + "  \"repeatedFixed32\": [3456, 456],\n"
+            + "  \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n"
+            + "  \"repeatedSfixed32\": [7890, 890],\n"
+            + "  \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n"
+            + "  \"repeatedFloat\": [1.5, 11.5],\n"
+            + "  \"repeatedDouble\": [1.25, 11.25],\n"
+            + "  \"repeatedBool\": [true, true],\n"
+            + "  \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n"
+            + "  \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n"
+            + "  \"repeatedNestedMessage\": [{\n"
+            + "    \"value\": 100\n"
+            + "  }, {\n"
+            + "    \"value\": 200\n"
+            + "  }],\n"
+            + "  \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n"
+            + "}",
+        toJsonString(message));
+
+    assertRoundTripEquals(message);
+  }
+
+  public void testUnknownEnumValues() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        .setOptionalNestedEnumValue(12345)
+        .addRepeatedNestedEnumValue(12345)
+        .addRepeatedNestedEnumValue(0)
+        .build();
+    assertEquals(
+        "{\n"
+        + "  \"optionalNestedEnum\": 12345,\n"
+        + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
+    mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
+    TestMap mapMessage = mapBuilder.build();
+    assertEquals(
+        "{\n"
+            + "  \"int32ToEnumMap\": {\n"
+            + "    \"1\": \"FOO\",\n"
+            + "    \"2\": 12345\n"
+            + "  }\n"
+            + "}",
+        toJsonString(mapMessage));
+    assertRoundTripEquals(mapMessage);
+  }
+
+  public void testSpecialFloatValues() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder()
+        .addRepeatedFloat(Float.NaN)
+        .addRepeatedFloat(Float.POSITIVE_INFINITY)
+        .addRepeatedFloat(Float.NEGATIVE_INFINITY)
+        .addRepeatedDouble(Double.NaN)
+        .addRepeatedDouble(Double.POSITIVE_INFINITY)
+        .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+        .build();
+    assertEquals(
+        "{\n"
+        + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
+        + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
+        + "}", toJsonString(message));
+
+    assertRoundTripEquals(message);
+  }
+
+  public void testParserAcceptStringForNumbericField() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    mergeFromJson(
+        "{\n"
+        + "  \"optionalInt32\": \"1234\",\n"
+        + "  \"optionalUint32\": \"5678\",\n"
+        + "  \"optionalSint32\": \"9012\",\n"
+        + "  \"optionalFixed32\": \"3456\",\n"
+        + "  \"optionalSfixed32\": \"7890\",\n"
+        + "  \"optionalFloat\": \"1.5\",\n"
+        + "  \"optionalDouble\": \"1.25\",\n"
+        + "  \"optionalBool\": \"true\"\n"
+        + "}", builder);
+    TestAllTypes message = builder.build();
+    assertEquals(1234, message.getOptionalInt32());
+    assertEquals(5678, message.getOptionalUint32());
+    assertEquals(9012, message.getOptionalSint32());
+    assertEquals(3456, message.getOptionalFixed32());
+    assertEquals(7890, message.getOptionalSfixed32());
+    assertEquals(1.5f, message.getOptionalFloat());
+    assertEquals(1.25, message.getOptionalDouble());
+    assertEquals(true, message.getOptionalBool());
+  }
+
+  public void testParserAcceptFloatingPointValueForIntegerField() throws Exception {
+    // Test that numeric values like "1.000", "1e5" will also be accepted.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    mergeFromJson(
+        "{\n"
+            + "  \"repeatedInt32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n"
+            + "}", builder);
+    int[] expectedValues = new int[]{1, 100000, 1, 100000};
+    assertEquals(4, builder.getRepeatedInt32Count());
+    assertEquals(4, builder.getRepeatedUint32Count());
+    assertEquals(4, builder.getRepeatedInt64Count());
+    assertEquals(4, builder.getRepeatedUint64Count());
+    for (int i = 0; i < 4; ++i) {
+      assertEquals(expectedValues[i], builder.getRepeatedInt32(i));
+      assertEquals(expectedValues[i], builder.getRepeatedUint32(i));
+      assertEquals(expectedValues[i], builder.getRepeatedInt64(i));
+      assertEquals(expectedValues[i], builder.getRepeatedUint64(i));
+    }
+
+    // Non-integers will still be rejected.
+    assertRejects("optionalInt32", "1.5");
+    assertRejects("optionalUint32", "1.5");
+    assertRejects("optionalInt64", "1.5");
+    assertRejects("optionalUint64", "1.5");
+  }
+
+  private void assertRejects(String name, String value) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      // Numeric form is rejected.
+      mergeFromJson("{\"" + name + "\":" + value + "}", builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+    try {
+      // String form is also rejected.
+      mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+  }
+
+  private void assertAccepts(String name, String value) throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    // Both numeric form and string form are accepted.
+    mergeFromJson("{\"" + name + "\":" + value + "}", builder);
+    builder.clear();
+    mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
+  }
+
+  public void testParserRejectOutOfRangeNumericValues() throws Exception {
+    assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE));
+    assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE));
+    assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L));
+    assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L));
+
+    assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L));
+    assertRejects("optionalUint32", "123456789012345");
+    assertRejects("optionalUint32", "-1");
+
+    BigInteger one = new BigInteger("1");
+    BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE));
+    BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE));
+    assertAccepts("optionalInt64", maxLong.toString());
+    assertAccepts("optionalInt64", minLong.toString());
+    assertRejects("optionalInt64", maxLong.add(one).toString());
+    assertRejects("optionalInt64", minLong.subtract(one).toString());
+
+    assertAccepts("optionalUint64", maxLong.add(one).toString());
+    assertRejects("optionalUint64", "1234567890123456789012345");
+    assertRejects("optionalUint64", "-1");
+
+    assertAccepts("optionalBool", "true");
+    assertRejects("optionalBool", "1");
+    assertRejects("optionalBool", "0");
+
+    assertAccepts("optionalFloat", String.valueOf(Float.MAX_VALUE));
+    assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE));
+    assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE));
+    assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE));
+
+    BigDecimal moreThanOne = new BigDecimal("1.000001");
+    BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE);
+    BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE);
+    assertAccepts("optionalDouble", maxDouble.toString());
+    assertAccepts("optionalDouble", minDouble.toString());
+    assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString());
+    assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString());
+  }
+
+  public void testParserAcceptNull() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    mergeFromJson(
+        "{\n"
+        + "  \"optionalInt32\": null,\n"
+        + "  \"optionalInt64\": null,\n"
+        + "  \"optionalUint32\": null,\n"
+        + "  \"optionalUint64\": null,\n"
+        + "  \"optionalSint32\": null,\n"
+        + "  \"optionalSint64\": null,\n"
+        + "  \"optionalFixed32\": null,\n"
+        + "  \"optionalFixed64\": null,\n"
+        + "  \"optionalSfixed32\": null,\n"
+        + "  \"optionalSfixed64\": null,\n"
+        + "  \"optionalFloat\": null,\n"
+        + "  \"optionalDouble\": null,\n"
+        + "  \"optionalBool\": null,\n"
+        + "  \"optionalString\": null,\n"
+        + "  \"optionalBytes\": null,\n"
+        + "  \"optionalNestedMessage\": null,\n"
+        + "  \"optionalNestedEnum\": null,\n"
+        + "  \"repeatedInt32\": null,\n"
+        + "  \"repeatedInt64\": null,\n"
+        + "  \"repeatedUint32\": null,\n"
+        + "  \"repeatedUint64\": null,\n"
+        + "  \"repeatedSint32\": null,\n"
+        + "  \"repeatedSint64\": null,\n"
+        + "  \"repeatedFixed32\": null,\n"
+        + "  \"repeatedFixed64\": null,\n"
+        + "  \"repeatedSfixed32\": null,\n"
+        + "  \"repeatedSfixed64\": null,\n"
+        + "  \"repeatedFloat\": null,\n"
+        + "  \"repeatedDouble\": null,\n"
+        + "  \"repeatedBool\": null,\n"
+        + "  \"repeatedString\": null,\n"
+        + "  \"repeatedBytes\": null,\n"
+        + "  \"repeatedNestedMessage\": null,\n"
+        + "  \"repeatedNestedEnum\": null\n"
+        + "}", builder);
+    TestAllTypes message = builder.build();
+    assertEquals(TestAllTypes.getDefaultInstance(), message);
+
+    // Repeated field elements cannot be null.
+    try {
+      builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedInt32\": [null, null],\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+
+    try {
+      builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedNestedMessage\": [null, null],\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+  }
+
+  public void testParserRejectDuplicatedFields() throws Exception {
+    // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last
+    // one if multiple entries have the same name. This is not the desired behavior but it can
+    // only be fixed by using our own parser. Here we only test the cases where the names are
+    // different but still referring to the same field.
+
+    // Duplicated optional fields.
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+              + "  \"optionalNestedMessage\": {},\n"
+              + "  \"optional_nested_message\": {}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+
+    // Duplicated repeated fields.
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedNestedMessage\": [null, null],\n"
+          + "  \"repeated_nested_message\": [null, null]\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+
+    // Duplicated oneof fields.
+    try {
+      TestOneof.Builder builder = TestOneof.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"oneofInt32\": 1,\n"
+          + "  \"oneof_int32\": 2\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+  }
+
+  public void testMapFields() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.getMutableInt32ToInt32Map().put(1, 10);
+    builder.getMutableInt64ToInt32Map().put(1234567890123456789L, 10);
+    builder.getMutableUint32ToInt32Map().put(2, 20);
+    builder.getMutableUint64ToInt32Map().put(2234567890123456789L, 20);
+    builder.getMutableSint32ToInt32Map().put(3, 30);
+    builder.getMutableSint64ToInt32Map().put(3234567890123456789L, 30);
+    builder.getMutableFixed32ToInt32Map().put(4, 40);
+    builder.getMutableFixed64ToInt32Map().put(4234567890123456789L, 40);
+    builder.getMutableSfixed32ToInt32Map().put(5, 50);
+    builder.getMutableSfixed64ToInt32Map().put(5234567890123456789L, 50);
+    builder.getMutableBoolToInt32Map().put(false, 6);
+    builder.getMutableStringToInt32Map().put("Hello", 10);
+
+    builder.getMutableInt32ToInt64Map().put(1, 1234567890123456789L);
+    builder.getMutableInt32ToUint32Map().put(2, 20);
+    builder.getMutableInt32ToUint64Map().put(2, 2234567890123456789L);
+    builder.getMutableInt32ToSint32Map().put(3, 30);
+    builder.getMutableInt32ToSint64Map().put(3, 3234567890123456789L);
+    builder.getMutableInt32ToFixed32Map().put(4, 40);
+    builder.getMutableInt32ToFixed64Map().put(4, 4234567890123456789L);
+    builder.getMutableInt32ToSfixed32Map().put(5, 50);
+    builder.getMutableInt32ToSfixed64Map().put(5, 5234567890123456789L);
+    builder.getMutableInt32ToFloatMap().put(6, 1.5f);
+    builder.getMutableInt32ToDoubleMap().put(6, 1.25);
+    builder.getMutableInt32ToBoolMap().put(7, false);
+    builder.getMutableInt32ToStringMap().put(7, "World");
+    builder.getMutableInt32ToBytesMap().put(
+        8, ByteString.copyFrom(new byte[]{1, 2, 3}));
+    builder.getMutableInt32ToMessageMap().put(
+        8, NestedMessage.newBuilder().setValue(1234).build());
+    builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR);
+    TestMap message = builder.build();
+
+    assertEquals(
+        "{\n"
+        + "  \"int32ToInt32Map\": {\n"
+        + "    \"1\": 10\n"
+        + "  },\n"
+        + "  \"int64ToInt32Map\": {\n"
+        + "    \"1234567890123456789\": 10\n"
+        + "  },\n"
+        + "  \"uint32ToInt32Map\": {\n"
+        + "    \"2\": 20\n"
+        + "  },\n"
+        + "  \"uint64ToInt32Map\": {\n"
+        + "    \"2234567890123456789\": 20\n"
+        + "  },\n"
+        + "  \"sint32ToInt32Map\": {\n"
+        + "    \"3\": 30\n"
+        + "  },\n"
+        + "  \"sint64ToInt32Map\": {\n"
+        + "    \"3234567890123456789\": 30\n"
+        + "  },\n"
+        + "  \"fixed32ToInt32Map\": {\n"
+        + "    \"4\": 40\n"
+        + "  },\n"
+        + "  \"fixed64ToInt32Map\": {\n"
+        + "    \"4234567890123456789\": 40\n"
+        + "  },\n"
+        + "  \"sfixed32ToInt32Map\": {\n"
+        + "    \"5\": 50\n"
+        + "  },\n"
+        + "  \"sfixed64ToInt32Map\": {\n"
+        + "    \"5234567890123456789\": 50\n"
+        + "  },\n"
+        + "  \"boolToInt32Map\": {\n"
+        + "    \"false\": 6\n"
+        + "  },\n"
+        + "  \"stringToInt32Map\": {\n"
+        + "    \"Hello\": 10\n"
+        + "  },\n"
+        + "  \"int32ToInt64Map\": {\n"
+        + "    \"1\": \"1234567890123456789\"\n"
+        + "  },\n"
+        + "  \"int32ToUint32Map\": {\n"
+        + "    \"2\": 20\n"
+        + "  },\n"
+        + "  \"int32ToUint64Map\": {\n"
+        + "    \"2\": \"2234567890123456789\"\n"
+        + "  },\n"
+        + "  \"int32ToSint32Map\": {\n"
+        + "    \"3\": 30\n"
+        + "  },\n"
+        + "  \"int32ToSint64Map\": {\n"
+        + "    \"3\": \"3234567890123456789\"\n"
+        + "  },\n"
+        + "  \"int32ToFixed32Map\": {\n"
+        + "    \"4\": 40\n"
+        + "  },\n"
+        + "  \"int32ToFixed64Map\": {\n"
+        + "    \"4\": \"4234567890123456789\"\n"
+        + "  },\n"
+        + "  \"int32ToSfixed32Map\": {\n"
+        + "    \"5\": 50\n"
+        + "  },\n"
+        + "  \"int32ToSfixed64Map\": {\n"
+        + "    \"5\": \"5234567890123456789\"\n"
+        + "  },\n"
+        + "  \"int32ToFloatMap\": {\n"
+        + "    \"6\": 1.5\n"
+        + "  },\n"
+        + "  \"int32ToDoubleMap\": {\n"
+        + "    \"6\": 1.25\n"
+        + "  },\n"
+        + "  \"int32ToBoolMap\": {\n"
+        + "    \"7\": false\n"
+        + "  },\n"
+        + "  \"int32ToStringMap\": {\n"
+        + "    \"7\": \"World\"\n"
+        + "  },\n"
+        + "  \"int32ToBytesMap\": {\n"
+        + "    \"8\": \"AQID\"\n"
+        + "  },\n"
+        + "  \"int32ToMessageMap\": {\n"
+        + "    \"8\": {\n"
+        + "      \"value\": 1234\n"
+        + "    }\n"
+        + "  },\n"
+        + "  \"int32ToEnumMap\": {\n"
+        + "    \"9\": \"BAR\"\n"
+        + "  }\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    // Test multiple entries.
+    builder = TestMap.newBuilder();
+    builder.getMutableInt32ToInt32Map().put(1, 2);
+    builder.getMutableInt32ToInt32Map().put(3, 4);
+    message = builder.build();
+
+    assertEquals(
+        "{\n"
+        + "  \"int32ToInt32Map\": {\n"
+        + "    \"1\": 2,\n"
+        + "    \"3\": 4\n"
+        + "  }\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testMapNullValueIsRejected() throws Exception {
+    try {
+      TestMap.Builder builder = TestMap.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"int32ToInt32Map\": {null: 1},\n"
+          + "  \"int32ToMessageMap\": {null: 2}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+
+    try {
+      TestMap.Builder builder = TestMap.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"int32ToInt32Map\": {\"1\": null},\n"
+          + "  \"int32ToMessageMap\": {\"2\": null}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+  }
+
+  public void testParserAcceptNonQuotedObjectKey() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    mergeFromJson(
+        "{\n"
+        + "  int32ToInt32Map: {1: 2},\n"
+        + "  stringToInt32Map: {hello: 3}\n"
+        + "}", builder);
+    TestMap message = builder.build();
+    assertEquals(2, message.getInt32ToInt32Map().get(1).intValue());
+    assertEquals(3, message.getStringToInt32Map().get("hello").intValue());
+  }
+
+  public void testWrappers() throws Exception {
+    TestWrappers.Builder builder = TestWrappers.newBuilder();
+    builder.getBoolValueBuilder().setValue(false);
+    builder.getInt32ValueBuilder().setValue(0);
+    builder.getInt64ValueBuilder().setValue(0);
+    builder.getUint32ValueBuilder().setValue(0);
+    builder.getUint64ValueBuilder().setValue(0);
+    builder.getFloatValueBuilder().setValue(0.0f);
+    builder.getDoubleValueBuilder().setValue(0.0);
+    builder.getStringValueBuilder().setValue("");
+    builder.getBytesValueBuilder().setValue(ByteString.EMPTY);
+    TestWrappers message = builder.build();
+
+    assertEquals(
+        "{\n"
+        + "  \"int32Value\": 0,\n"
+        + "  \"uint32Value\": 0,\n"
+        + "  \"int64Value\": \"0\",\n"
+        + "  \"uint64Value\": \"0\",\n"
+        + "  \"floatValue\": 0.0,\n"
+        + "  \"doubleValue\": 0.0,\n"
+        + "  \"boolValue\": false,\n"
+        + "  \"stringValue\": \"\",\n"
+        + "  \"bytesValue\": \"\"\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    builder = TestWrappers.newBuilder();
+    builder.getBoolValueBuilder().setValue(true);
+    builder.getInt32ValueBuilder().setValue(1);
+    builder.getInt64ValueBuilder().setValue(2);
+    builder.getUint32ValueBuilder().setValue(3);
+    builder.getUint64ValueBuilder().setValue(4);
+    builder.getFloatValueBuilder().setValue(5.0f);
+    builder.getDoubleValueBuilder().setValue(6.0);
+    builder.getStringValueBuilder().setValue("7");
+    builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8}));
+    message = builder.build();
+
+    assertEquals(
+        "{\n"
+        + "  \"int32Value\": 1,\n"
+        + "  \"uint32Value\": 3,\n"
+        + "  \"int64Value\": \"2\",\n"
+        + "  \"uint64Value\": \"4\",\n"
+        + "  \"floatValue\": 5.0,\n"
+        + "  \"doubleValue\": 6.0,\n"
+        + "  \"boolValue\": true,\n"
+        + "  \"stringValue\": \"7\",\n"
+        + "  \"bytesValue\": \"CA==\"\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testTimestamp() throws Exception {
+    TestTimestamp message = TestTimestamp.newBuilder()
+        .setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z"))
+        .build();
+
+    assertEquals(
+        "{\n"
+        + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testDuration() throws Exception {
+    TestDuration message = TestDuration.newBuilder()
+        .setDurationValue(TimeUtil.parseDuration("12345s"))
+        .build();
+
+    assertEquals(
+        "{\n"
+        + "  \"durationValue\": \"12345s\"\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testFieldMask() throws Exception {
+    TestFieldMask message = TestFieldMask.newBuilder()
+        .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz"))
+        .build();
+
+    assertEquals(
+        "{\n"
+        + "  \"fieldMaskValue\": \"foo.bar,baz\"\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testStruct() throws Exception {
+    // Build a struct with all possible values.
+    TestStruct.Builder builder = TestStruct.newBuilder();
+    Struct.Builder structBuilder = builder.getStructValueBuilder();
+    structBuilder.getMutableFields().put(
+        "null_value", Value.newBuilder().setNullValueValue(0).build());
+    structBuilder.getMutableFields().put(
+        "number_value", Value.newBuilder().setNumberValue(1.25).build());
+    structBuilder.getMutableFields().put(
+        "string_value", Value.newBuilder().setStringValue("hello").build());
+    Struct.Builder subStructBuilder = Struct.newBuilder();
+    subStructBuilder.getMutableFields().put(
+        "number_value", Value.newBuilder().setNumberValue(1234).build());
+    structBuilder.getMutableFields().put(
+        "struct_value", Value.newBuilder().setStructValue(subStructBuilder.build()).build());
+    ListValue.Builder listBuilder = ListValue.newBuilder();
+    listBuilder.addValues(Value.newBuilder().setNumberValue(1.125).build());
+    listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
+    structBuilder.getMutableFields().put(
+        "list_value", Value.newBuilder().setListValue(listBuilder.build()).build());
+    TestStruct message = builder.build();
+
+    assertEquals(
+        "{\n"
+        + "  \"structValue\": {\n"
+        + "    \"null_value\": null,\n"
+        + "    \"number_value\": 1.25,\n"
+        + "    \"string_value\": \"hello\",\n"
+        + "    \"struct_value\": {\n"
+        + "      \"number_value\": 1234.0\n"
+        + "    },\n"
+        + "    \"list_value\": [1.125, null]\n"
+        + "  }\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    builder = TestStruct.newBuilder();
+    builder.setValue(Value.newBuilder().setNullValueValue(0).build());
+    message = builder.build();
+    assertEquals(
+        "{\n"
+        + "  \"value\": null\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+
+    builder = TestStruct.newBuilder();
+    listBuilder = builder.getListValueBuilder();
+    listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build());
+    listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
+    message = builder.build();
+    assertEquals(
+        "{\n"
+        + "  \"listValue\": [31831.125, null]\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testAnyFields() throws Exception {
+    TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
+    TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
+
+    // A TypeRegistry must be provided in order to convert Any types.
+    try {
+      toJsonString(message);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+
+    JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder()
+        .add(TestAllTypes.getDescriptor()).build();
+    JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
+
+    assertEquals(
+        "{\n"
+        + "  \"anyValue\": {\n"
+        + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+        + "    \"optionalInt32\": 1234\n"
+        + "  }\n"
+        + "}" , printer.print(message));
+    assertRoundTripEquals(message, registry);
+
+
+    // Well-known types have a special formatting when embedded in Any.
+    //
+    // 1. Any in Any.
+    Any anyMessage = Any.pack(Any.pack(content));
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+        + "  \"value\": {\n"
+        + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+        + "    \"optionalInt32\": 1234\n"
+        + "  }\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 2. Wrappers in Any.
+    anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+        + "  \"value\": 12345\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
+        + "  \"value\": 12345\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+        + "  \"value\": \"12345\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
+        + "  \"value\": \"12345\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
+        + "  \"value\": 12345.0\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
+        + "  \"value\": 12345.0\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+        + "  \"value\": true\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
+        + "  \"value\": \"Hello\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    anyMessage = Any.pack(BytesValue.newBuilder().setValue(
+        ByteString.copyFrom(new byte[]{1, 2})).build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
+        + "  \"value\": \"AQI=\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 3. Timestamp in Any.
+    anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z"));
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+        + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 4. Duration in Any
+    anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s"));
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+        + "  \"value\": \"12345.100s\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 5. FieldMask in Any
+    anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz"));
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+        + "  \"value\": \"foo.bar,baz\"\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+
+    // 6. Struct in Any
+    Struct.Builder structBuilder = Struct.newBuilder();
+    structBuilder.getMutableFields().put(
+        "number", Value.newBuilder().setNumberValue(1.125).build());
+    anyMessage = Any.pack(structBuilder.build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+        + "  \"value\": {\n"
+        + "    \"number\": 1.125\n"
+        + "  }\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+    Value.Builder valueBuilder = Value.newBuilder();
+    valueBuilder.setNumberValue(1);
+    anyMessage = Any.pack(valueBuilder.build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+        + "  \"value\": 1.0\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+  }
+
+  public void testParserMissingTypeUrl() throws Exception {
+    try {
+      Any.Builder builder = Any.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"optionalInt32\": 1234\n"
+          + "}", builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+  }
+
+  public void testParserUnexpectedTypeUrl() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+          + "  \"optionalInt32\": 12345\n"
+          + "}", builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+  }
+
+  public void testParserRejectTrailingComma() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"optionalInt32\": 12345,\n"
+          + "}", builder);
+      fail("Exception is expected.");
+    } catch (IOException e) {
+      // Expected.
+    }
+
+    // TODO(xiaofeng): GSON allows trailing comma in arrays even after I set
+    // the JsonReader to non-lenient mode. If we want to enforce strict JSON
+    // compliance, we might want to switch to a different JSON parser or
+    // implement one by ourselves.
+    // try {
+    //   TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    //   JsonFormat.merge(
+    //       "{\n"
+    //       + "  \"repeatedInt32\": [12345,]\n"
+    //       + "}", builder);
+    //   fail("Exception is expected.");
+    // } catch (IOException e) {
+    //   // Expected.
+    // }
+  }
+
+  public void testParserRejectInvalidBase64() throws Exception {
+    assertRejects("optionalBytes", "!@#$");
+    // We use standard BASE64 with paddings.
+    assertRejects("optionalBytes", "AQI");
+  }
+
+  public void testParserRejectInvalidEnumValue() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"optionalNestedEnum\": \"XXX\"\n"
+          + "}", builder);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+
+  public void testCustomJsonName() throws Exception {
+    TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
+    assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testDefaultGsonDoesNotHtmlEscape() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build();
+    assertEquals(
+        "{\n" + "  \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message));
+  }
+
+  public void testIncludingDefaultValueFields() throws Exception {
+    TestAllTypes message = TestAllTypes.getDefaultInstance();
+    assertEquals("{\n}", JsonFormat.printer().print(message));
+    assertEquals(
+        "{\n"
+            + "  \"optionalInt32\": 0,\n"
+            + "  \"optionalInt64\": \"0\",\n"
+            + "  \"optionalUint32\": 0,\n"
+            + "  \"optionalUint64\": \"0\",\n"
+            + "  \"optionalSint32\": 0,\n"
+            + "  \"optionalSint64\": \"0\",\n"
+            + "  \"optionalFixed32\": 0,\n"
+            + "  \"optionalFixed64\": \"0\",\n"
+            + "  \"optionalSfixed32\": 0,\n"
+            + "  \"optionalSfixed64\": \"0\",\n"
+            + "  \"optionalFloat\": 0.0,\n"
+            + "  \"optionalDouble\": 0.0,\n"
+            + "  \"optionalBool\": false,\n"
+            + "  \"optionalString\": \"\",\n"
+            + "  \"optionalBytes\": \"\",\n"
+            + "  \"optionalNestedEnum\": \"FOO\",\n"
+            + "  \"repeatedInt32\": [],\n"
+            + "  \"repeatedInt64\": [],\n"
+            + "  \"repeatedUint32\": [],\n"
+            + "  \"repeatedUint64\": [],\n"
+            + "  \"repeatedSint32\": [],\n"
+            + "  \"repeatedSint64\": [],\n"
+            + "  \"repeatedFixed32\": [],\n"
+            + "  \"repeatedFixed64\": [],\n"
+            + "  \"repeatedSfixed32\": [],\n"
+            + "  \"repeatedSfixed64\": [],\n"
+            + "  \"repeatedFloat\": [],\n"
+            + "  \"repeatedDouble\": [],\n"
+            + "  \"repeatedBool\": [],\n"
+            + "  \"repeatedString\": [],\n"
+            + "  \"repeatedBytes\": [],\n"
+            + "  \"repeatedNestedMessage\": [],\n"
+            + "  \"repeatedNestedEnum\": []\n"
+            + "}",
+        JsonFormat.printer().includingDefaultValueFields().print(message));
+
+    TestMap mapMessage = TestMap.getDefaultInstance();
+    assertEquals("{\n}", JsonFormat.printer().print(mapMessage));
+    assertEquals(
+        "{\n"
+            + "  \"int32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"int64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"uint32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"uint64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sint32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sint64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"fixed32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"fixed64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sfixed32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sfixed64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"boolToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"stringToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToInt64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToUint32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToUint64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSint32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSint64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFixed32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFixed64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSfixed32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSfixed64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFloatMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToDoubleMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToBoolMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToStringMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToBytesMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToMessageMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToEnumMap\": {\n"
+            + "  }\n"
+            + "}",
+        JsonFormat.printer().includingDefaultValueFields().print(mapMessage));
+  }
+
+  public void testPreservingProtoFieldNames() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
+    assertEquals("{\n" + "  \"optionalInt32\": 12345\n" + "}", JsonFormat.printer().print(message));
+    assertEquals(
+        "{\n" + "  \"optional_int32\": 12345\n" + "}",
+        JsonFormat.printer().preservingProtoFieldNames().print(message));
+
+    // The json_name field option is ignored when configured to use original proto field names.
+    TestCustomJsonName messageWithCustomJsonName =
+        TestCustomJsonName.newBuilder().setValue(12345).build();
+    assertEquals(
+        "{\n" + "  \"value\": 12345\n" + "}",
+        JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName));
+
+    // Parsers accept both original proto field names and lowerCamelCase names.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    JsonFormat.parser().merge("{\"optionalInt32\": 12345}", builder);
+    assertEquals(12345, builder.getOptionalInt32());
+    builder.clear();
+    JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder);
+    assertEquals(54321, builder.getOptionalInt32());
+  }
+}
diff --git a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
new file mode 100644
index 0000000..4c31b2b
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
@@ -0,0 +1,506 @@
+// 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.
+
+package com.google.protobuf.util;
+
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+
+import junit.framework.TestCase;
+
+import org.junit.Assert;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Unit tests for {@link TimeUtil}. */
+public class TimeUtilTest extends TestCase {
+  public void testTimestampStringFormat() throws Exception {
+    Timestamp start = TimeUtil.parseTimestamp("0001-01-01T00:00:00Z");
+    Timestamp end = TimeUtil.parseTimestamp("9999-12-31T23:59:59.999999999Z");
+    assertEquals(TimeUtil.TIMESTAMP_SECONDS_MIN, start.getSeconds());
+    assertEquals(0, start.getNanos());
+    assertEquals(TimeUtil.TIMESTAMP_SECONDS_MAX, end.getSeconds());
+    assertEquals(999999999, end.getNanos());
+    assertEquals("0001-01-01T00:00:00Z", TimeUtil.toString(start));
+    assertEquals("9999-12-31T23:59:59.999999999Z", TimeUtil.toString(end));
+
+    Timestamp value = TimeUtil.parseTimestamp("1970-01-01T00:00:00Z");
+    assertEquals(0, value.getSeconds());
+    assertEquals(0, value.getNanos());
+
+    // Test negative timestamps.
+    value = TimeUtil.parseTimestamp("1969-12-31T23:59:59.999Z");
+    assertEquals(-1, value.getSeconds());
+    // Nano part is in the range of [0, 999999999] for Timestamp.
+    assertEquals(999000000, value.getNanos());
+
+    // Test that 3, 6, or 9 digits are used for the fractional part.
+    value = Timestamp.newBuilder().setNanos(10).build();
+    assertEquals("1970-01-01T00:00:00.000000010Z", TimeUtil.toString(value));
+    value = Timestamp.newBuilder().setNanos(10000).build();
+    assertEquals("1970-01-01T00:00:00.000010Z", TimeUtil.toString(value));
+    value = Timestamp.newBuilder().setNanos(10000000).build();
+    assertEquals("1970-01-01T00:00:00.010Z", TimeUtil.toString(value));
+
+    // Test that parsing accepts timezone offsets.
+    value = TimeUtil.parseTimestamp("1970-01-01T00:00:00.010+08:00");
+    assertEquals("1969-12-31T16:00:00.010Z", TimeUtil.toString(value));
+    value = TimeUtil.parseTimestamp("1970-01-01T00:00:00.010-08:00");
+    assertEquals("1970-01-01T08:00:00.010Z", TimeUtil.toString(value));
+  }
+
+  private volatile boolean stopParsingThreads = false;
+  private volatile String errorMessage = "";
+
+  private class ParseTimestampThread extends Thread {
+    private final String[] strings;
+    private final Timestamp[] values;
+    public ParseTimestampThread(String[] strings, Timestamp[] values) {
+      this.strings = strings;
+      this.values = values;
+    }
+
+    @Override
+    public void run() {
+      int index = 0;
+      while (!stopParsingThreads) {
+        Timestamp result;
+        try {
+          result = TimeUtil.parseTimestamp(strings[index]);
+        } catch (ParseException e) {
+          errorMessage = "Failed to parse timestamp: " + strings[index];
+          break;
+        }
+        if (result.getSeconds() != values[index].getSeconds()
+            || result.getNanos() != values[index].getNanos()) {
+          errorMessage = "Actual result: " + result.toString() + ", expected: "
+              + values[index].toString();
+          break;
+        }
+        index = (index + 1) % strings.length;
+      }
+    }
+  }
+
+  public void testTimestampConcurrentParsing() throws Exception {
+    String[] timestampStrings = new String[]{
+      "0001-01-01T00:00:00Z",
+      "9999-12-31T23:59:59.999999999Z",
+      "1970-01-01T00:00:00Z",
+      "1969-12-31T23:59:59.999Z",
+    };
+    Timestamp[] timestampValues = new Timestamp[timestampStrings.length];
+    for (int i = 0; i < timestampStrings.length; i++) {
+      timestampValues[i] = TimeUtil.parseTimestamp(timestampStrings[i]);
+    }
+
+    final int THREAD_COUNT = 16;
+    final int RUNNING_TIME = 5000;  // in milliseconds.
+    final List<Thread> threads = new ArrayList<Thread>();
+
+    stopParsingThreads = false;
+    errorMessage = "";
+    for (int i = 0; i < THREAD_COUNT; i++) {
+      Thread thread = new ParseTimestampThread(
+          timestampStrings, timestampValues);
+      thread.start();
+      threads.add(thread);
+    }
+    Thread.sleep(RUNNING_TIME);
+    stopParsingThreads = true;
+    for (Thread thread : threads) {
+      thread.join();
+    }
+    Assert.assertEquals("", errorMessage);
+  }
+
+  public void testTimetampInvalidFormat() throws Exception {
+    try {
+      // Value too small.
+      Timestamp value = Timestamp.newBuilder()
+        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MIN - 1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Value too large.
+      Timestamp value = Timestamp.newBuilder()
+        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MAX + 1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+    
+    try {
+      // Invalid nanos value.
+      Timestamp value = Timestamp.newBuilder().setNanos(-1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid nanos value.
+      Timestamp value = Timestamp.newBuilder().setNanos(1000000000).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Value to small.
+      TimeUtil.parseTimestamp("0000-01-01T00:00:00Z");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Value to large.
+      TimeUtil.parseTimestamp("10000-01-01T00:00:00Z");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Missing 'T'.
+      TimeUtil.parseTimestamp("1970-01-01 00:00:00Z");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Missing 'Z'.
+      TimeUtil.parseTimestamp("1970-01-01T00:00:00");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid offset.
+      TimeUtil.parseTimestamp("1970-01-01T00:00:00+0000");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Trailing text.
+      TimeUtil.parseTimestamp("1970-01-01T00:00:00Z0");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid nanosecond value.
+      TimeUtil.parseTimestamp("1970-01-01T00:00:00.ABCZ");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+  }
+
+  public void testDurationStringFormat() throws Exception {
+    Timestamp start = TimeUtil.parseTimestamp("0001-01-01T00:00:00Z");
+    Timestamp end = TimeUtil.parseTimestamp("9999-12-31T23:59:59.999999999Z");
+    Duration duration = TimeUtil.distance(start, end);
+    assertEquals("315537897599.999999999s", TimeUtil.toString(duration));
+    duration = TimeUtil.distance(end, start);
+    assertEquals("-315537897599.999999999s", TimeUtil.toString(duration));
+
+    // Generated output should contain 3, 6, or 9 fractional digits.
+    duration = Duration.newBuilder().setSeconds(1).build();
+    assertEquals("1s", TimeUtil.toString(duration));
+    duration = Duration.newBuilder().setNanos(10000000).build();
+    assertEquals("0.010s", TimeUtil.toString(duration));
+    duration = Duration.newBuilder().setNanos(10000).build();
+    assertEquals("0.000010s", TimeUtil.toString(duration));
+    duration = Duration.newBuilder().setNanos(10).build();
+    assertEquals("0.000000010s", TimeUtil.toString(duration));
+
+    // Parsing accepts an fractional digits as long as they fit into nano
+    // precision.
+    duration = TimeUtil.parseDuration("0.1s");
+    assertEquals(100000000, duration.getNanos());
+    duration = TimeUtil.parseDuration("0.0001s");
+    assertEquals(100000, duration.getNanos());
+    duration = TimeUtil.parseDuration("0.0000001s");
+    assertEquals(100, duration.getNanos());
+
+    // Duration must support range from -315,576,000,000s to +315576000000s
+    // which includes negative values.
+    duration = TimeUtil.parseDuration("315576000000.999999999s");
+    assertEquals(315576000000L, duration.getSeconds());
+    assertEquals(999999999, duration.getNanos());
+    duration = TimeUtil.parseDuration("-315576000000.999999999s");
+    assertEquals(-315576000000L, duration.getSeconds());
+    assertEquals(-999999999, duration.getNanos());
+  }
+
+  public void testDurationInvalidFormat() throws Exception {
+    try {
+      // Value too small.
+      Duration value = Duration.newBuilder()
+        .setSeconds(TimeUtil.DURATION_SECONDS_MIN - 1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Value too large.
+      Duration value = Duration.newBuilder()
+        .setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+    
+    try {
+      // Invalid nanos value.
+      Duration value = Duration.newBuilder().setSeconds(1).setNanos(-1)
+          .build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid nanos value.
+      Duration value = Duration.newBuilder().setSeconds(-1).setNanos(1)
+          .build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Value too small.
+      TimeUtil.parseDuration("-315576000001s");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Value too large.
+      TimeUtil.parseDuration("315576000001s");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Empty.
+      TimeUtil.parseDuration("");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Missing "s".
+      TimeUtil.parseDuration("0");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid trailing data.
+      TimeUtil.parseDuration("0s0");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid prefix.
+      TimeUtil.parseDuration("--1s");
+      Assert.fail("Exception is expected.");
+    } catch (ParseException e) {
+      // Expected.
+    }
+  }
+
+  public void testTimestampConversion() throws Exception {
+    Timestamp timestamp =
+      TimeUtil.parseTimestamp("1970-01-01T00:00:01.111111111Z");
+    assertEquals(1111111111, TimeUtil.toNanos(timestamp));
+    assertEquals(1111111, TimeUtil.toMicros(timestamp));
+    assertEquals(1111, TimeUtil.toMillis(timestamp));
+    timestamp = TimeUtil.createTimestampFromNanos(1111111111);
+    assertEquals("1970-01-01T00:00:01.111111111Z", TimeUtil.toString(timestamp));
+    timestamp = TimeUtil.createTimestampFromMicros(1111111);
+    assertEquals("1970-01-01T00:00:01.111111Z", TimeUtil.toString(timestamp));
+    timestamp = TimeUtil.createTimestampFromMillis(1111);
+    assertEquals("1970-01-01T00:00:01.111Z", TimeUtil.toString(timestamp));
+    
+    timestamp = TimeUtil.parseTimestamp("1969-12-31T23:59:59.111111111Z");
+    assertEquals(-888888889, TimeUtil.toNanos(timestamp));
+    assertEquals(-888889, TimeUtil.toMicros(timestamp));
+    assertEquals(-889, TimeUtil.toMillis(timestamp));
+    timestamp = TimeUtil.createTimestampFromNanos(-888888889);
+    assertEquals("1969-12-31T23:59:59.111111111Z", TimeUtil.toString(timestamp));
+    timestamp = TimeUtil.createTimestampFromMicros(-888889);
+    assertEquals("1969-12-31T23:59:59.111111Z", TimeUtil.toString(timestamp));
+    timestamp = TimeUtil.createTimestampFromMillis(-889);
+    assertEquals("1969-12-31T23:59:59.111Z", TimeUtil.toString(timestamp));
+  }
+
+  public void testDurationConversion() throws Exception {
+    Duration duration = TimeUtil.parseDuration("1.111111111s");
+    assertEquals(1111111111, TimeUtil.toNanos(duration));
+    assertEquals(1111111, TimeUtil.toMicros(duration));
+    assertEquals(1111, TimeUtil.toMillis(duration));
+    duration = TimeUtil.createDurationFromNanos(1111111111);
+    assertEquals("1.111111111s", TimeUtil.toString(duration));
+    duration = TimeUtil.createDurationFromMicros(1111111);
+    assertEquals("1.111111s", TimeUtil.toString(duration));
+    duration = TimeUtil.createDurationFromMillis(1111);
+    assertEquals("1.111s", TimeUtil.toString(duration));
+    
+    duration = TimeUtil.parseDuration("-1.111111111s");
+    assertEquals(-1111111111, TimeUtil.toNanos(duration));
+    assertEquals(-1111111, TimeUtil.toMicros(duration));
+    assertEquals(-1111, TimeUtil.toMillis(duration));
+    duration = TimeUtil.createDurationFromNanos(-1111111111);
+    assertEquals("-1.111111111s", TimeUtil.toString(duration));
+    duration = TimeUtil.createDurationFromMicros(-1111111);
+    assertEquals("-1.111111s", TimeUtil.toString(duration));
+    duration = TimeUtil.createDurationFromMillis(-1111);
+    assertEquals("-1.111s", TimeUtil.toString(duration));
+  }
+
+  public void testTimeOperations() throws Exception {
+    Timestamp start = TimeUtil.parseTimestamp("0001-01-01T00:00:00Z");
+    Timestamp end = TimeUtil.parseTimestamp("9999-12-31T23:59:59.999999999Z");
+
+    Duration duration = TimeUtil.distance(start, end);
+    assertEquals("315537897599.999999999s", TimeUtil.toString(duration));
+    Timestamp value = TimeUtil.add(start, duration);
+    assertEquals(end, value);
+    value = TimeUtil.subtract(end, duration);
+    assertEquals(start, value);
+
+    duration = TimeUtil.distance(end, start);
+    assertEquals("-315537897599.999999999s", TimeUtil.toString(duration));
+    value = TimeUtil.add(end, duration);
+    assertEquals(start, value);
+    value = TimeUtil.subtract(start, duration);
+    assertEquals(end, value);
+
+    // Result is larger than Long.MAX_VALUE.
+    try {
+      duration = TimeUtil.parseDuration("315537897599.999999999s");
+      duration = TimeUtil.multiply(duration, 315537897599.999999999);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    // Result is lesser than Long.MIN_VALUE.
+    try {
+      duration = TimeUtil.parseDuration("315537897599.999999999s");
+      duration = TimeUtil.multiply(duration, -315537897599.999999999);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    duration = TimeUtil.parseDuration("-1.125s");
+    duration = TimeUtil.divide(duration, 2.0);
+    assertEquals("-0.562500s", TimeUtil.toString(duration));
+    duration = TimeUtil.multiply(duration, 2.0);
+    assertEquals("-1.125s", TimeUtil.toString(duration));
+
+    duration = TimeUtil.add(duration, duration);
+    assertEquals("-2.250s", TimeUtil.toString(duration));
+    
+    duration = TimeUtil.subtract(duration, TimeUtil.parseDuration("-1s"));
+    assertEquals("-1.250s", TimeUtil.toString(duration));
+    
+    // Multiplications (with results larger than Long.MAX_VALUE in nanoseconds).
+    duration = TimeUtil.parseDuration("0.999999999s");
+    assertEquals("315575999684.424s",
+      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    duration = TimeUtil.parseDuration("-0.999999999s");
+    assertEquals("-315575999684.424s",
+      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    assertEquals("315575999684.424s",
+      TimeUtil.toString(TimeUtil.multiply(duration, -315576000000L)));
+    
+    // Divisions (with values larger than Long.MAX_VALUE in nanoseconds).
+    Duration d1 = TimeUtil.parseDuration("315576000000s");
+    Duration d2 = TimeUtil.subtract(d1, TimeUtil.createDurationFromNanos(1));
+    assertEquals(1, TimeUtil.divide(d1, d2));
+    assertEquals(0, TimeUtil.divide(d2, d1));
+    assertEquals("0.000000001s", TimeUtil.toString(TimeUtil.remainder(d1, d2)));
+    assertEquals("315575999999.999999999s",
+      TimeUtil.toString(TimeUtil.remainder(d2, d1)));
+    
+    // Divisions involving negative values.
+    //
+    // (-5) / 2 = -2, remainder = -1
+    d1 = TimeUtil.parseDuration("-5s");
+    d2 = TimeUtil.parseDuration("2s");
+    assertEquals(-2, TimeUtil.divide(d1, d2));
+    assertEquals(-2, TimeUtil.divide(d1, 2).getSeconds());
+    assertEquals(-1, TimeUtil.remainder(d1, d2).getSeconds());
+    // (-5) / (-2) = 2, remainder = -1
+    d1 = TimeUtil.parseDuration("-5s");
+    d2 = TimeUtil.parseDuration("-2s");
+    assertEquals(2, TimeUtil.divide(d1, d2));
+    assertEquals(2, TimeUtil.divide(d1, -2).getSeconds());
+    assertEquals(-1, TimeUtil.remainder(d1, d2).getSeconds());
+    // 5 / (-2) = -2, remainder = 1
+    d1 = TimeUtil.parseDuration("5s");
+    d2 = TimeUtil.parseDuration("-2s");
+    assertEquals(-2, TimeUtil.divide(d1, d2));
+    assertEquals(-2, TimeUtil.divide(d1, -2).getSeconds());
+    assertEquals(1, TimeUtil.remainder(d1, d2).getSeconds());
+  }
+}
diff --git a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
new file mode 100644
index 0000000..686edc4
--- /dev/null
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
@@ -0,0 +1,201 @@
+// 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.
+
+// 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.
+
+syntax = "proto3";
+
+package json_test;
+
+option java_package = "com.google.protobuf.util";
+option java_outer_classname = "JsonTestProto";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/wrappers.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/struct.proto";
+
+message TestAllTypes {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  message NestedMessage {
+    int32 value = 1;
+  }
+
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  sint32 optional_sint32 = 5;
+  sint64 optional_sint64 = 6;
+  fixed32 optional_fixed32 = 7;
+  fixed64 optional_fixed64 = 8;
+  sfixed32 optional_sfixed32 = 9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float = 11;
+  double optional_double = 12;
+  bool optional_bool = 13;
+  string optional_string = 14;
+  bytes optional_bytes = 15;
+  NestedMessage optional_nested_message = 18;
+  NestedEnum optional_nested_enum = 21;
+
+  // Repeated
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
+  repeated NestedMessage repeated_nested_message = 48;
+  repeated NestedEnum repeated_nested_enum = 51;
+}
+
+message TestOneof {
+  oneof oneof_field {
+    int32 oneof_int32 = 1;
+    TestAllTypes.NestedMessage oneof_nested_message = 2;
+  }
+}
+
+message TestMap {
+  // Instead of testing all combinations (too many), we only make sure all
+  // valid types have been used at least in one field as key and in one
+  // field as value.
+  map<int32, int32> int32_to_int32_map = 1;
+  map<int64, int32> int64_to_int32_map = 2;
+  map<uint32, int32> uint32_to_int32_map = 3;
+  map<uint64, int32> uint64_to_int32_map = 4;
+  map<sint32, int32> sint32_to_int32_map = 5;
+  map<sint64, int32> sint64_to_int32_map = 6;
+  map<fixed32, int32> fixed32_to_int32_map = 7;
+  map<fixed64, int32> fixed64_to_int32_map = 8;
+  map<sfixed32, int32> sfixed32_to_int32_map = 9;
+  map<sfixed64, int32> sfixed64_to_int32_map = 10;
+  map<bool, int32> bool_to_int32_map = 11;
+  map<string, int32> string_to_int32_map = 12;
+
+  map<int32, int64> int32_to_int64_map = 101;
+  map<int32, uint32> int32_to_uint32_map = 102;
+  map<int32, uint64> int32_to_uint64_map = 103;
+  map<int32, sint32> int32_to_sint32_map = 104;
+  map<int32, sint64> int32_to_sint64_map = 105;
+  map<int32, fixed32> int32_to_fixed32_map = 106;
+  map<int32, fixed64> int32_to_fixed64_map = 107;
+  map<int32, sfixed32> int32_to_sfixed32_map = 108;
+  map<int32, sfixed64> int32_to_sfixed64_map = 109;
+  map<int32, float> int32_to_float_map = 110;
+  map<int32, double> int32_to_double_map = 111;
+  map<int32, bool> int32_to_bool_map = 112;
+  map<int32, string> int32_to_string_map = 113;
+  map<int32, bytes> int32_to_bytes_map = 114;
+  map<int32, TestAllTypes.NestedMessage> int32_to_message_map = 115;
+  map<int32, TestAllTypes.NestedEnum> int32_to_enum_map = 116;
+}
+
+message TestWrappers {
+  google.protobuf.Int32Value int32_value = 1;
+  google.protobuf.UInt32Value uint32_value = 2;
+  google.protobuf.Int64Value int64_value = 3;
+  google.protobuf.UInt64Value uint64_value = 4;
+  google.protobuf.FloatValue float_value = 5;
+  google.protobuf.DoubleValue double_value = 6;
+  google.protobuf.BoolValue bool_value = 7;
+  google.protobuf.StringValue string_value = 8;
+  google.protobuf.BytesValue bytes_value = 9;
+}
+
+message TestTimestamp {
+  google.protobuf.Timestamp timestamp_value = 1;
+}
+
+message TestDuration {
+  google.protobuf.Duration duration_value = 1;
+}
+
+message TestFieldMask {
+  google.protobuf.FieldMask field_mask_value = 1;
+}
+
+message TestStruct {
+  google.protobuf.Struct struct_value = 1;
+  google.protobuf.Value value = 2;
+  google.protobuf.ListValue list_value = 3;
+}
+
+message TestAny {
+  google.protobuf.Any any_value = 1;
+}
+
+message TestCustomJsonName {
+  int32 value = 1 [json_name = "@value"];
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java b/javamicro/src/main/java/com/google/protobuf/micro/ByteStringMicro.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java
rename to javamicro/src/main/java/com/google/protobuf/micro/ByteStringMicro.java
diff --git a/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java b/javamicro/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java
rename to javamicro/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java
diff --git a/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java b/javamicro/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java
rename to javamicro/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java
diff --git a/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java b/javamicro/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java
rename to javamicro/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java
diff --git a/java/src/main/java/com/google/protobuf/micro/MessageMicro.java b/javamicro/src/main/java/com/google/protobuf/micro/MessageMicro.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/MessageMicro.java
rename to javamicro/src/main/java/com/google/protobuf/micro/MessageMicro.java
diff --git a/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java b/javamicro/src/main/java/com/google/protobuf/micro/WireFormatMicro.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java
rename to javamicro/src/main/java/com/google/protobuf/micro/WireFormatMicro.java
diff --git a/javanano/README.md b/javanano/README.md
new file mode 100644
index 0000000..e19b90b
--- /dev/null
+++ b/javanano/README.md
@@ -0,0 +1,398 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers Nano runtime library.
+
+Installation - With Maven
+-------------------------
+
+The Protocol Buffers build is managed using Maven.  If you would
+rather build without Maven, see below.
+
+1) Install Apache Maven if you don't have it:
+
+     http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc.  If
+   you install a binary distribution, make sure that it is the same
+   version as this package.  If in doubt, run:
+
+     $ protoc --version
+
+   You will need to place the protoc executable in ../src.  (If you
+   built it yourself, it should already be there.)
+
+3) Run the tests:
+
+     $ mvn test
+
+   If some tests fail, this library may not work correctly on your
+   system.  Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+     $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+   .jar file to use:
+
+     $ mvn package
+
+   The .jar will be placed in the "target" directory.
+
+Installation - Without Maven
+----------------------------
+
+If you would rather not install Maven to build the library, you may
+follow these instructions instead.  Note that these instructions skip
+running unit tests.
+
+1) Build the C++ code, or obtain a binary distribution of protoc.  If
+   you install a binary distribution, make sure that it is the same
+   version as this package.  If in doubt, run:
+
+     $ protoc --version
+
+   If you built the C++ code without installing, the compiler binary
+   should be located in ../src.
+
+2) Invoke protoc to build DescriptorProtos.java:
+
+     $ protoc --java_out=src/main/java -I../src \
+         ../src/google/protobuf/descriptor.proto
+
+3) Compile the code in src/main/java using whatever means you prefer.
+
+4) Install the classes wherever you prefer.
+
+Nano version
+------------
+
+JavaNano is a special code generator and runtime library designed specially for
+resource-restricted systems, like Android. It is very resource-friendly in both
+the amount of code and the runtime overhead. Here is an overview of JavaNano
+features compared with the official Java protobuf:
+
+- No descriptors or message builders.
+- All messages are mutable; fields are public Java fields.
+- For optional fields only, encapsulation behind setter/getter/hazzer/
+  clearer functions is opt-in, which provide proper 'has' state support.
+- For proto2, if not opted in, has state (field presence) is not available.
+  Serialization outputs all fields not equal to their defaults
+  (see important implications below).
+  The behavior is consistent with proto3 semantics.
+- Required fields (proto2 only) are always serialized.
+- Enum constants are integers; protection against invalid values only
+  when parsing from the wire.
+- Enum constants can be generated into container interfaces bearing
+  the enum's name (so the referencing code is in Java style).
+- CodedInputByteBufferNano can only take byte[] (not InputStream).
+- Similarly CodedOutputByteBufferNano can only write to byte[].
+- Repeated fields are in arrays, not ArrayList or Vector. Null array
+  elements are allowed and silently ignored.
+- Full support for serializing/deserializing repeated packed fields.
+- Support  extensions (in proto2).
+- Unset messages/groups are null, not an immutable empty default
+  instance.
+- toByteArray(...) and mergeFrom(...) are now static functions of
+  MessageNano.
+- The 'bytes' type translates to the Java type byte[].
+
+The generated messages are not thread-safe for writes, but may be
+used simultaneously from multiple threads in a read-only manner.
+In other words, an appropriate synchronization mechanism (such as
+a ReadWriteLock) must be used to ensure that a message, its
+ancestors, and descendants are not accessed by any other threads
+while the message is being modified. Field reads, getter methods
+(but not getExtension(...)), toByteArray(...), writeTo(...),
+getCachedSize(), and getSerializedSize() are all considered read-only
+operations.
+
+IMPORTANT: If you have fields with defaults and opt out of accessors
+
+How fields with defaults are serialized has changed. Because we don't
+keep "has" state, any field equal to its default is assumed to be not
+set and therefore is not serialized. Consider the situation where we
+change the default value of a field. Senders compiled against an older
+version of the proto continue to match against the old default, and
+don't send values to the receiver even though the receiver assumes the
+new default value. Therefore, think carefully about the implications
+of changing the default value. Alternatively, turn on accessors and
+enjoy the benefit of the explicit has() checks.
+
+IMPORTANT: If you have "bytes" fields with non-empty defaults
+
+Because the byte buffer is now of mutable type byte[], the default
+static final cannot be exposed through a public field. Each time a
+message's constructor or clear() function is called, the default value
+(kept in a private byte[]) is cloned. This causes a small memory
+penalty. This is not a problem if the field has no default or is an
+empty default.
+
+Nano Generator options
+----------------------
+
+```
+java_package           -> <file-name>|<package-name>
+java_outer_classname   -> <file-name>|<package-name>
+java_multiple_files    -> true or false
+java_nano_generate_has -> true or false [DEPRECATED]
+optional_field_style   -> default or accessors
+enum_style             -> c or java
+ignore_services        -> true or false
+parcelable_messages    -> true or false
+generate_intdefs       -> true or false
+```
+
+**java_package=\<file-name\>|\<package-name\>** (no default)
+
+  This allows overriding the 'java_package' option value
+  for the given file from the command line. Use multiple
+  java_package options to override the option for multiple
+  files. The final Java package for each file is the value
+  of this command line option if present, or the value of
+  the same option defined in the file if present, or the
+  proto package if present, or the default Java package.
+
+**java_outer_classname=\<file-name\>|\<outer-classname\>** (no default)
+
+  This allows overriding the 'java_outer_classname' option
+  for the given file from the command line. Use multiple
+  java_outer_classname options to override the option for
+  multiple files. The final Java outer class name for each
+  file is the value of this command line option if present,
+  or the value of the same option defined in the file if
+  present, or the file name converted to CamelCase. This
+  outer class will nest all classes and integer constants
+  generated from file-scope messages and enums.
+
+**java_multiple_files={true,false}** (no default)
+
+  This allows overriding the 'java_multiple_files' option
+  in all source files and their imported files from the
+  command line. The final value of this option for each
+  file is the value defined in this command line option, or
+  the value of the same option defined in the file if
+  present, or false. This specifies whether to generate
+  package-level classes for the file-scope messages in the
+  same Java package as the outer class (instead of nested
+  classes in the outer class). File-scope enum constants
+  are still generated as integer constants in the outer
+  class. This affects the fully qualified references in the
+  Java code. NOTE: because the command line option
+  overrides the value for all files and their imported
+  files, using this option inconsistently may result in
+  incorrect references to the imported messages and enum
+  constants.
+
+**java_nano_generate_has={true,false}** (default: false)
+
+  DEPRECATED. Use optional_field_style=accessors.
+
+  If true, generates a public boolean variable has\<fieldname\>
+  accompanying each optional or required field (not present for
+  repeated fields, groups or messages). It is set to false initially
+  and upon clear(). If parseFrom(...) reads the field from the wire,
+  it is set to true. This is a way for clients to inspect the "has"
+  value upon parse. If it is set to true, writeTo(...) will ALWAYS
+  output that field (even if field value is equal to its
+  default).
+
+  IMPORTANT: This option costs an extra 4 bytes per primitive field in
+  the message. Think carefully about whether you really need this. In
+  many cases reading the default works and determining whether the
+  field was received over the wire is irrelevant.
+
+**optional_field_style={default,accessors,reftypes}** (default: default)
+
+  Defines the style of the generated code for fields.
+
+  * default
+
+  In the default style, optional fields translate into public mutable
+  Java fields, and the serialization process is as discussed in the
+  "IMPORTANT" section above.
+
+  * accessors
+
+  When set to 'accessors', each optional field is encapsulated behind
+  4 accessors, namely get\<fieldname\>(), set\<fieldname\>(), has\<fieldname\>()
+  and clear\<fieldname\>() methods, with the standard semantics. The hazzer's
+  return value determines whether a field is serialized, so this style is
+  useful when you need to serialize a field with the default value, or check
+  if a field has been explicitly set to its default value from the wire.
+
+  In the 'accessors' style, required and nested message fields are still
+  translated to one public mutable Java field each, repeated fields are still
+  translated to arrays. No accessors are generated for them.
+
+  IMPORTANT: When using the 'accessors' style, ProGuard should always
+  be enabled with optimization (don't use -dontoptimize) and allowing
+  access modification (use -allowaccessmodification). This removes the
+  unused accessors and maybe inline the rest at the call sites,
+  reducing the final code size.
+  TODO(maxtroy): find ProGuard config that would work the best.
+
+  * reftypes
+
+  When set to 'reftypes', each proto field is generated as a public Java
+  field. For primitive types, these fields use the Java reference types
+  such as java.lang.Integer instead of primitive types such as int.
+
+  In the 'reftypes' style, fields are initialized to null (or empty
+  arrays for repeated fields), and their default values are not available.
+  They are serialized over the wire based on equality to null.
+
+  The 'reftypes' mode has some additional cost due to autoboxing and usage
+  of reference types. In practice, many boxed types are cached, and so don't
+  result in object creation. However, references do take slightly more memory
+  than primitives.
+
+  The 'reftypes' mode is useful when you want to be able to serialize fields
+  with default values, or check if a field has been explicitly set to the
+  default over the wire without paying the extra method cost of the
+  'accessors' mode.
+
+  Note that if you attempt to write null to a required field in the reftypes
+  mode, serialization of the proto will cause a NullPointerException. This is
+  an intentional indicator that you must set required fields.
+
+  NOTE
+  optional_field_style=accessors or reftypes cannot be used together with
+  java_nano_generate_has=true. If you need the 'has' flag for any
+  required field (you have no reason to), you can only use
+  java_nano_generate_has=true.
+
+**enum_style={c,java}** (default: c)
+
+  Defines where to put the int constants generated from enum members.
+
+  * c
+
+  Use C-style, so the enum constants are available at the scope where
+  the enum is defined. A file-scope enum's members are referenced like
+  'FileOuterClass.ENUM_VALUE'; a message-scope enum's members are
+  referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
+  This complies with the Micro code generator's behavior.
+
+  * java
+
+  Use Java-style, so the enum constants are available under the enum
+  name and referenced like 'EnumName.ENUM_VALUE' (they are still int
+  constants). The enum name becomes the name of a public interface, at
+  the scope where the enum is defined. If the enum is file-scope and
+  the java_multiple_files option is on, the interface will be defined
+  in its own file. To reduce code size, this interface should not be
+  implemented and ProGuard shrinking should be used, so after the Java
+  compiler inlines all referenced enum constants into the call sites,
+  the interface remains unused and can be removed by ProGuard.
+
+**ignore_services={true,false}** (default: false)
+
+  Skips services definitions.
+
+  Nano doesn't support services. By default, if a service is defined
+  it will generate a compilation error. If this flag is set to true,
+  services will be silently ignored, instead.
+
+**parcelable_messages={true,false}** (default: false)
+
+  Android-specific option to generate Parcelable messages.
+
+**generate_intdefs={true,false}** (default: false)
+  Android-specific option to generate @IntDef annotations for enums.
+
+  If turned on, an '@IntDef' annotation (a public @interface) will be
+  generated for each enum, and every integer parameter and return
+  value in the generated code meant for this enum will be annotated
+  with it. This interface is generated with the same name and at the
+  same place as the enum members' container interfaces described
+  above under 'enum_style=java', regardless of the enum_style option
+  used. When this is combined with enum_style=java, the interface
+  will be both the '@IntDef' annotation and the container of the enum
+  members; otherwise the interface has an empty body.
+
+  Your app must declare a compile-time dependency on the
+  android-support-annotations library.
+
+  For more information on how these @IntDef annotations help with
+  compile-time type safety, see:
+  https://sites.google.com/a/android.com/tools/tech-docs/support-annotations
+  and
+  https://developer.android.com/reference/android/support/annotation/IntDef.html
+
+
+To use nano protobufs within the Android repo:
+----------------------------------------------
+
+- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
+  When building a Java library or an app (package) target, the build
+  system will add the Java nano runtime library to the
+  LOCAL_STATIC_JAVA_LIBRARIES variable, so you don't need to.
+- Set 'LOCAL_PROTO_JAVA_OUTPUT_PARAMS := ...' in your local .mk file
+  for any command-line options you need. Use commas to join multiple
+  options. In the nano flavor only, whitespace surrounding the option
+  names and values are ignored, so you can use backslash-newline or
+  '+=' to structure your make files nicely.
+- The options will be applied to *all* proto files in LOCAL_SRC_FILES
+  when you build a Java library or package. In case different options
+  are needed for different proto files, build separate Java libraries
+  and reference them in your main target. Note: you should make sure
+  that, for each separate target, all proto files imported from any
+  proto file in LOCAL_SRC_FILES are included in LOCAL_SRC_FILES. This
+  is because the generator has to assume that the imported files are
+  built using the same options, and will generate code that reference
+  the fields and enums from the imported files using the same code
+  style.
+- Hint: 'include $(CLEAR_VARS)' resets all LOCAL_ variables, including
+  the two above.
+
+To use nano protobufs outside of Android repo:
+----------------------------------------------
+
+- Link with the generated jar file
+  \<protobuf-root\>java/target/protobuf-java-2.3.0-nano.jar.
+- Invoke with --javanano_out, e.g.:
+```
+./protoc '--javanano_out=\
+    java_package=src/proto/simple-data.proto|my_package,\
+    java_outer_classname=src/proto/simple-data.proto|OuterName\
+  :.' src/proto/simple-data.proto
+```
+
+Contributing to nano:
+---------------------
+
+Please add/edit tests in NanoTest.java.
+
+Please run the following steps to test:
+
+- cd external/protobuf
+- ./configure
+- Run "make -j12 check" and verify all tests pass.
+- cd java
+- Run "mvn test" and verify all tests pass.
+- cd ../../..
+- . build/envsetup.sh
+- lunch 1
+- "make -j12 aprotoc libprotobuf-java-2.3.0-nano aprotoc-test-nano-params NanoAndroidTest" and
+  check for build errors.
+- Plug in an Android device or start an emulator.
+- adb install -r out/target/product/generic/data/app/NanoAndroidTest.apk
+- Run:
+  "adb shell am instrument -w com.google.protobuf.nano.test/android.test.InstrumentationTestRunner"
+  and verify all tests pass.
+- repo sync -c -j256
+- "make -j12" and check for build errors
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/javanano/pom.xml b/javanano/pom.xml
new file mode 100644
index 0000000..309b6c3
--- /dev/null
+++ b/javanano/pom.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google</groupId>
+    <artifactId>google</artifactId>
+    <version>1</version>
+  </parent>
+  <groupId>com.google.protobuf.nano</groupId>
+  <artifactId>protobuf-javanano</artifactId>
+  <version>3.0.0-alpha-6</version>
+  <packaging>bundle</packaging>
+  <name>Protocol Buffer JavaNano API</name>
+  <description>
+    Protocol Buffers are a way of encoding structured data in an efficient yet
+    extensible format.
+  </description>
+  <inceptionYear>2008</inceptionYear>
+  <url>https://developers.google.com/protocol-buffers/</url>
+  <licenses>
+    <license>
+      <name>New BSD license</name>
+      <url>http://www.opensource.org/licenses/bsd-license.php</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <url>https://github.com/google/protobuf</url>
+    <connection>
+      scm:git:https://github.com/google/protobuf.git
+    </connection>
+  </scm>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.4</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>2.2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+      <version>2.2.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>**/*Test.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <tasks>
+                <mkdir dir="target/generated-test-sources" />
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=generate_equals=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_import_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_single_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/map_test.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=store_unknown_fields=true,generate_clone=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/unittest_unknown_enum_values_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_has_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=optional_field_style=accessors,generate_equals=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=enum_style=java:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=
+                                  optional_field_style=accessors,
+                                  java_outer_classname=google/protobuf/nano/unittest_enum_validity_nano.proto|EnumValidityAccessors
+                                :target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=optional_field_style=reftypes,generate_equals=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=
+                                  optional_field_style=reftypes_compat_mode,
+                                  generate_equals=true,
+                                  java_outer_classname=google/protobuf/nano/unittest_reference_types_nano.proto|NanoReferenceTypesCompat
+                                  :target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
+                </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javanano_out=bytes_offset_length=true:target/generated-test-sources" />
+                  <arg value="--proto_path=src/test/java/com" />
+                  <arg value="src/test/google/protobuf/unittest_bytes_offset_length_nano.proto" />
+                </exec>
+              </tasks>
+              <testSourceRoot>target/generated-test-sources</testSourceRoot>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+            <Export-Package>com.google.protobuf;version=3.0.0-alpha-5</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>release</id>
+      <distributionManagement>
+        <snapshotRepository>
+          <id>sonatype-nexus-staging</id>
+          <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+        </snapshotRepository>
+        <repository>
+          <id>sonatype-nexus-staging</id>
+          <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+        </repository>
+      </distributionManagement>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.2.1</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar-no-fork</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.9.1</version>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.5</version>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.sonatype.plugins</groupId>
+            <artifactId>nexus-staging-maven-plugin</artifactId>
+            <version>1.6.3</version>
+            <extensions>true</extensions>
+            <configuration>
+               <serverId>sonatype-nexus-staging</serverId>
+               <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+               <autoReleaseAfterClose>false</autoReleaseAfterClose>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableExtendableMessageNano.java b/javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableExtendableMessageNano.java
similarity index 100%
rename from java/src/device/main/java/com/google/protobuf/nano/android/ParcelableExtendableMessageNano.java
rename to javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableExtendableMessageNano.java
diff --git a/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNano.java b/javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNano.java
similarity index 100%
rename from java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNano.java
rename to javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNano.java
diff --git a/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNanoCreator.java b/javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNanoCreator.java
similarity index 100%
rename from java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNanoCreator.java
rename to javanano/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNanoCreator.java
diff --git a/java/src/device/test/AndroidManifest.xml b/javanano/src/device/test/AndroidManifest.xml
similarity index 100%
rename from java/src/device/test/AndroidManifest.xml
rename to javanano/src/device/test/AndroidManifest.xml
diff --git a/javanano/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java b/javanano/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java
new file mode 100644
index 0000000..0a1cb2f
--- /dev/null
+++ b/javanano/src/device/test/java/com/google/protobuf/nano/NanoAndroidTest.java
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+package com.google.protobuf.nano;
+
+import android.os.Parcel;
+
+import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
+import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano.NestedMessage;
+import com.google.protobuf.nano.testext.nano.Extensions.ContainerMessage;
+import com.google.protobuf.nano.testext.nano.Extensions.ExtendableMessage;
+
+import junit.framework.TestCase;
+
+public class NanoAndroidTest extends TestCase {
+    public void testParceling() {
+        SimpleMessageNano message = new SimpleMessageNano();
+        message.d = 54321;
+        message.nestedMsg = new NestedMessage();
+        message.nestedMsg.bb = 12345;
+        message.defaultNestedEnum = SimpleMessageNano.FOO;
+
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            parcel.writeParcelable(message, 0);
+            parcel.setDataPosition(0);
+            message = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+
+        assertEquals(54321, message.d);
+        assertEquals(12345, message.nestedMsg.bb);
+        assertEquals(SimpleMessageNano.FOO, message.defaultNestedEnum);
+    }
+
+    public void testExtendableParceling() {
+        ExtendableMessage message = new ExtendableMessage();
+        message.field = 12345;
+        message.setExtension(ContainerMessage.anotherThing, true);
+
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            parcel.writeParcelable(message, 0);
+            parcel.setDataPosition(0);
+            message = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+
+        assertEquals(12345, message.field);
+        assertTrue((boolean) message.getExtension(ContainerMessage.anotherThing));
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
new file mode 100644
index 0000000..0ce5713
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -0,0 +1,697 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods:  methods that read specific
+ * protocol message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputByteBufferNano {
+  /**
+   * Create a new CodedInputStream wrapping the given byte array.
+   */
+  public static CodedInputByteBufferNano newInstance(final byte[] buf) {
+    return newInstance(buf, 0, buf.length);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off,
+                                             final int len) {
+    return new CodedInputByteBufferNano(buf, off, len);
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Attempt to read a field tag, returning zero if we have reached EOF.
+   * Protocol message parsers use this to read tags, since a protocol message
+   * may legally end wherever a tag occurs, and zero is not a valid tag number.
+   */
+  public int readTag() throws IOException {
+    if (isAtEnd()) {
+      lastTag = 0;
+      return 0;
+    }
+
+    lastTag = readRawVarint32();
+    if (lastTag == 0) {
+      // If we actually read zero, that's not a valid tag.
+      throw InvalidProtocolBufferNanoException.invalidTag();
+    }
+    return lastTag;
+  }
+
+  /**
+   * Verifies that the last call to readTag() returned the given tag value.
+   * This is used to verify that a nested group ended with the correct
+   * end tag.
+   *
+   * @throws InvalidProtocolBufferNanoException {@code value} does not match the
+   *                                        last tag.
+   */
+  public void checkLastTagWas(final int value)
+                              throws InvalidProtocolBufferNanoException {
+    if (lastTag != value) {
+      throw InvalidProtocolBufferNanoException.invalidEndTag();
+    }
+  }
+
+  /**
+   * Reads and discards a single field, given its tag value.
+   *
+   * @return {@code false} if the tag is an endgroup tag, in which case
+   *         nothing is skipped.  Otherwise, returns {@code true}.
+   */
+  public boolean skipField(final int tag) throws IOException {
+    switch (WireFormatNano.getTagWireType(tag)) {
+      case WireFormatNano.WIRETYPE_VARINT:
+        readInt32();
+        return true;
+      case WireFormatNano.WIRETYPE_FIXED64:
+        readRawLittleEndian64();
+        return true;
+      case WireFormatNano.WIRETYPE_LENGTH_DELIMITED:
+        skipRawBytes(readRawVarint32());
+        return true;
+      case WireFormatNano.WIRETYPE_START_GROUP:
+        skipMessage();
+        checkLastTagWas(
+          WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag),
+                             WireFormatNano.WIRETYPE_END_GROUP));
+        return true;
+      case WireFormatNano.WIRETYPE_END_GROUP:
+        return false;
+      case WireFormatNano.WIRETYPE_FIXED32:
+        readRawLittleEndian32();
+        return true;
+      default:
+        throw InvalidProtocolBufferNanoException.invalidWireType();
+    }
+  }
+
+  /**
+   * Reads and discards an entire message.  This will read either until EOF
+   * or until an endgroup tag, whichever comes first.
+   */
+  public void skipMessage() throws IOException {
+    while (true) {
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag)) {
+        return;
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Read a {@code double} field value from the stream. */
+  public double readDouble() throws IOException {
+    return Double.longBitsToDouble(readRawLittleEndian64());
+  }
+
+  /** Read a {@code float} field value from the stream. */
+  public float readFloat() throws IOException {
+    return Float.intBitsToFloat(readRawLittleEndian32());
+  }
+
+  /** Read a {@code uint64} field value from the stream. */
+  public long readUInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int64} field value from the stream. */
+  public long readInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int32} field value from the stream. */
+  public int readInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read a {@code fixed64} field value from the stream. */
+  public long readFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read a {@code fixed32} field value from the stream. */
+  public int readFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read a {@code bool} field value from the stream. */
+  public boolean readBool() throws IOException {
+    return readRawVarint32() != 0;
+  }
+
+  /** Read a {@code string} field value from the stream. */
+  public String readString() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final String result = new String(buffer, bufferPos, size, InternalNano.UTF_8);
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return new String(readRawBytes(size), InternalNano.UTF_8);
+    }
+  }
+
+  /** Read a {@code group} field value from the stream. */
+  public void readGroup(final MessageNano msg, final int fieldNumber)
+      throws IOException {
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
+    }
+    ++recursionDepth;
+    msg.mergeFrom(this);
+    checkLastTagWas(
+      WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP));
+    --recursionDepth;
+  }
+
+  public void readMessage(final MessageNano msg)
+      throws IOException {
+    final int length = readRawVarint32();
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferNanoException.recursionLimitExceeded();
+    }
+    final int oldLimit = pushLimit(length);
+    ++recursionDepth;
+    msg.mergeFrom(this);
+    checkLastTagWas(0);
+    --recursionDepth;
+    popLimit(oldLimit);
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public byte[] readBytes() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final byte[] result = new byte[size];
+      System.arraycopy(buffer, bufferPos, result, 0, size);
+      bufferPos += size;
+      return result;
+    } else if (size == 0) {
+      return WireFormatNano.EMPTY_BYTES;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return readRawBytes(size);
+    }
+  }
+
+  /** Read a {@code uint32} field value from the stream. */
+  public int readUInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /**
+   * Read an enum field value from the stream.  Caller is responsible
+   * for converting the numeric value to an actual enum.
+   */
+  public int readEnum() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read an {@code sfixed32} field value from the stream. */
+  public int readSFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read an {@code sfixed64} field value from the stream. */
+  public long readSFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read an {@code sint32} field value from the stream. */
+  public int readSInt32() throws IOException {
+    return decodeZigZag32(readRawVarint32());
+  }
+
+  /** Read an {@code sint64} field value from the stream. */
+  public long readSInt64() throws IOException {
+    return decodeZigZag64(readRawVarint64());
+  }
+
+  // =================================================================
+
+  /**
+   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
+   * upper bits.
+   */
+  public int readRawVarint32() throws IOException {
+    byte tmp = readRawByte();
+    if (tmp >= 0) {
+      return tmp;
+    }
+    int result = tmp & 0x7f;
+    if ((tmp = readRawByte()) >= 0) {
+      result |= tmp << 7;
+    } else {
+      result |= (tmp & 0x7f) << 7;
+      if ((tmp = readRawByte()) >= 0) {
+        result |= tmp << 14;
+      } else {
+        result |= (tmp & 0x7f) << 14;
+        if ((tmp = readRawByte()) >= 0) {
+          result |= tmp << 21;
+        } else {
+          result |= (tmp & 0x7f) << 21;
+          result |= (tmp = readRawByte()) << 28;
+          if (tmp < 0) {
+            // Discard upper 32 bits.
+            for (int i = 0; i < 5; i++) {
+              if (readRawByte() >= 0) {
+                return result;
+              }
+            }
+            throw InvalidProtocolBufferNanoException.malformedVarint();
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  /** Read a raw Varint from the stream. */
+  public long readRawVarint64() throws IOException {
+    int shift = 0;
+    long result = 0;
+    while (shift < 64) {
+      final byte b = readRawByte();
+      result |= (long)(b & 0x7F) << shift;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+      shift += 7;
+    }
+    throw InvalidProtocolBufferNanoException.malformedVarint();
+  }
+
+  /** Read a 32-bit little-endian integer from the stream. */
+  public int readRawLittleEndian32() throws IOException {
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
+    return ((b1 & 0xff)      ) |
+           ((b2 & 0xff) <<  8) |
+           ((b3 & 0xff) << 16) |
+           ((b4 & 0xff) << 24);
+  }
+
+  /** Read a 64-bit little-endian integer from the stream. */
+  public long readRawLittleEndian64() throws IOException {
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
+    final byte b5 = readRawByte();
+    final byte b6 = readRawByte();
+    final byte b7 = readRawByte();
+    final byte b8 = readRawByte();
+    return (((long)b1 & 0xff)      ) |
+           (((long)b2 & 0xff) <<  8) |
+           (((long)b3 & 0xff) << 16) |
+           (((long)b4 & 0xff) << 24) |
+           (((long)b5 & 0xff) << 32) |
+           (((long)b6 & 0xff) << 40) |
+           (((long)b7 & 0xff) << 48) |
+           (((long)b8 & 0xff) << 56);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 32-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 32-bit integer.
+   */
+  public static int decodeZigZag32(final int n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 64-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 64-bit integer.
+   */
+  public static long decodeZigZag64(final long n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  // -----------------------------------------------------------------
+
+  private final byte[] buffer;
+  private int bufferStart;
+  private int bufferSize;
+  private int bufferSizeAfterLimit;
+  private int bufferPos;
+  private int lastTag;
+
+  /** The absolute position of the end of the current message. */
+  private int currentLimit = Integer.MAX_VALUE;
+
+  /** See setRecursionLimit() */
+  private int recursionDepth;
+  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+  /** See setSizeLimit() */
+  private int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+  private static final int DEFAULT_RECURSION_LIMIT = 64;
+  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
+
+  private CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) {
+    this.buffer = buffer;
+    bufferStart = off;
+    bufferSize = off + len;
+    bufferPos = off;
+  }
+
+  /**
+   * Set the maximum message recursion depth.  In order to prevent malicious
+   * messages from causing stack overflows, {@code CodedInputStream} limits
+   * how deeply messages may be nested.  The default limit is 64.
+   *
+   * @return the old limit.
+   */
+  public int setRecursionLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Recursion limit cannot be negative: " + limit);
+    }
+    final int oldLimit = recursionLimit;
+    recursionLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Set the maximum message size.  In order to prevent malicious
+   * messages from exhausting memory or causing integer overflows,
+   * {@code CodedInputStream} limits how large a message may be.
+   * The default limit is 64MB.  You should set this limit as small
+   * as you can without harming your app's functionality.  Note that
+   * size limits only apply when reading from an {@code InputStream}, not
+   * when constructed around a raw byte array.
+   * <p>
+   * If you want to read several messages from a single CodedInputStream, you
+   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
+   * size limit.
+   *
+   * @return the old limit.
+   */
+  public int setSizeLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Size limit cannot be negative: " + limit);
+    }
+    final int oldLimit = sizeLimit;
+    sizeLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
+   */
+  public void resetSizeCounter() {
+  }
+
+  /**
+   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
+   * is called when descending into a length-delimited embedded message.
+   *
+   * @return the old limit.
+   */
+  public int pushLimit(int byteLimit) throws InvalidProtocolBufferNanoException {
+    if (byteLimit < 0) {
+      throw InvalidProtocolBufferNanoException.negativeSize();
+    }
+    byteLimit += bufferPos;
+    final int oldLimit = currentLimit;
+    if (byteLimit > oldLimit) {
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+    currentLimit = byteLimit;
+
+    recomputeBufferSizeAfterLimit();
+
+    return oldLimit;
+  }
+
+  private void recomputeBufferSizeAfterLimit() {
+    bufferSize += bufferSizeAfterLimit;
+    final int bufferEnd = bufferSize;
+    if (bufferEnd > currentLimit) {
+      // Limit is in current buffer.
+      bufferSizeAfterLimit = bufferEnd - currentLimit;
+      bufferSize -= bufferSizeAfterLimit;
+    } else {
+      bufferSizeAfterLimit = 0;
+    }
+  }
+
+  /**
+   * Discards the current limit, returning to the previous limit.
+   *
+   * @param oldLimit The old limit, as returned by {@code pushLimit}.
+   */
+  public void popLimit(final int oldLimit) {
+    currentLimit = oldLimit;
+    recomputeBufferSizeAfterLimit();
+  }
+
+  /**
+   * Returns the number of bytes to be read before the current limit.
+   * If no limit is set, returns -1.
+   */
+  public int getBytesUntilLimit() {
+    if (currentLimit == Integer.MAX_VALUE) {
+      return -1;
+    }
+
+    final int currentAbsolutePosition = bufferPos;
+    return currentLimit - currentAbsolutePosition;
+  }
+
+  /**
+   * Returns true if the stream has reached the end of the input.  This is the
+   * case if either the end of the underlying input source has been reached or
+   * if the stream has reached a limit created using {@link #pushLimit(int)}.
+   */
+  public boolean isAtEnd() {
+    return bufferPos == bufferSize;
+  }
+
+  /**
+   * Get current position in buffer relative to beginning offset.
+   */
+  public int getPosition() {
+    return bufferPos - bufferStart;
+  }
+
+  /**
+   * Get current (absolute) position in buffer.
+   */
+  public int getAbsolutePosition() {
+    return bufferPos;
+  }
+
+  /**
+   * Return the raw underlying data in the buffer, directly.
+   */
+  public byte[] getBuffer() {
+    return buffer;
+  }
+
+  /**
+   * Retrieves a subset of data in the buffer. The returned array is not backed by the original
+   * buffer array.
+   *
+   * @param offset the position (relative to the buffer start position) to start at.
+   * @param length the number of bytes to retrieve.
+   */
+  public byte[] getData(int offset, int length) {
+    if (length == 0) {
+      return WireFormatNano.EMPTY_BYTES;
+    }
+    byte[] copy = new byte[length];
+    int start = bufferStart + offset;
+    System.arraycopy(buffer, start, copy, 0, length);
+    return copy;
+  }
+
+  /**
+   * Rewind to previous position. Cannot go forward.
+   */
+  public void rewindToPosition(int position) {
+    if (position > bufferPos - bufferStart) {
+      throw new IllegalArgumentException(
+              "Position " + position + " is beyond current " + (bufferPos - bufferStart));
+    }
+    if (position < 0) {
+      throw new IllegalArgumentException("Bad position " + position);
+    }
+    bufferPos = bufferStart + position;
+  }
+
+  /**
+   * Read one byte from the input.
+   *
+   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte readRawByte() throws IOException {
+    if (bufferPos == bufferSize) {
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+    return buffer[bufferPos++];
+  }
+
+  /**
+   * Read a fixed size of bytes from the input.
+   *
+   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte[] readRawBytes(final int size) throws IOException {
+    if (size < 0) {
+      throw InvalidProtocolBufferNanoException.negativeSize();
+    }
+
+    if (bufferPos + size > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - bufferPos);
+      // Then fail.
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+
+    if (size <= bufferSize - bufferPos) {
+      // We have all the bytes we need already.
+      final byte[] bytes = new byte[size];
+      System.arraycopy(buffer, bufferPos, bytes, 0, size);
+      bufferPos += size;
+      return bytes;
+    } else {
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+  }
+
+  /**
+   * Reads and discards {@code size} bytes.
+   *
+   * @throws InvalidProtocolBufferNanoException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public void skipRawBytes(final int size) throws IOException {
+    if (size < 0) {
+      throw InvalidProtocolBufferNanoException.negativeSize();
+    }
+
+    if (bufferPos + size > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - bufferPos);
+      // Then fail.
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+
+    if (size <= bufferSize - bufferPos) {
+      // We have all the bytes we need already.
+      bufferPos += size;
+    } else {
+      throw InvalidProtocolBufferNanoException.truncatedMessage();
+    }
+  }
+
+  // Read a primitive type.
+  Object readPrimitiveField(int type) throws IOException {
+    switch (type) {
+      case InternalNano.TYPE_DOUBLE:
+          return readDouble();
+      case InternalNano.TYPE_FLOAT:
+          return readFloat();
+      case InternalNano.TYPE_INT64:
+          return readInt64();
+      case InternalNano.TYPE_UINT64:
+          return readUInt64();
+      case InternalNano.TYPE_INT32:
+          return readInt32();
+      case InternalNano.TYPE_FIXED64:
+          return readFixed64();
+      case InternalNano.TYPE_FIXED32:
+          return readFixed32();
+      case InternalNano.TYPE_BOOL:
+          return readBool();
+      case InternalNano.TYPE_STRING:
+          return readString();
+      case InternalNano.TYPE_BYTES:
+          return readBytes();
+      case InternalNano.TYPE_UINT32:
+          return readUInt32();
+      case InternalNano.TYPE_ENUM:
+          return readEnum();
+      case InternalNano.TYPE_SFIXED32:
+          return readSFixed32();
+      case InternalNano.TYPE_SFIXED64:
+          return readSFixed64();
+      case InternalNano.TYPE_SINT32:
+          return readSInt32();
+      case InternalNano.TYPE_SINT64:
+          return readSInt64();
+      default:
+          throw new IllegalArgumentException("Unknown type " + type);
+    }
+  }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
new file mode 100644
index 0000000..8ff3e79
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -0,0 +1,1246 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ReadOnlyBufferException;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ * <p>This class contains two kinds of methods:  methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputByteBufferNano {
+  /* max bytes per java UTF-16 char in UTF-8 */
+  private static final int MAX_UTF8_EXPANSION = 3;
+  private final ByteBuffer buffer;
+
+  private CodedOutputByteBufferNano(final byte[] buffer, final int offset,
+                            final int length) {
+    this(ByteBuffer.wrap(buffer, offset, length));
+  }
+
+  private CodedOutputByteBufferNano(final ByteBuffer buffer) {
+    this.buffer = buffer;
+    this.buffer.order(ByteOrder.LITTLE_ENDIAN);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array.  If more bytes are written than fit in the array,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.
+   */
+  public static CodedOutputByteBufferNano newInstance(final byte[] flatArray) {
+    return newInstance(flatArray, 0, flatArray.length);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array slice.  If more bytes are written than fit in the slice,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.
+   */
+  public static CodedOutputByteBufferNano newInstance(final byte[] flatArray,
+                                              final int offset,
+                                              final int length) {
+    return new CodedOutputByteBufferNano(flatArray, offset, length);
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Write a {@code double} field, including tag, to the stream. */
+  public void writeDouble(final int fieldNumber, final double value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+    writeDoubleNoTag(value);
+  }
+
+  /** Write a {@code float} field, including tag, to the stream. */
+  public void writeFloat(final int fieldNumber, final float value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+    writeFloatNoTag(value);
+  }
+
+  /** Write a {@code uint64} field, including tag, to the stream. */
+  public void writeUInt64(final int fieldNumber, final long value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeUInt64NoTag(value);
+  }
+
+  /** Write an {@code int64} field, including tag, to the stream. */
+  public void writeInt64(final int fieldNumber, final long value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeInt64NoTag(value);
+  }
+
+  /** Write an {@code int32} field, including tag, to the stream. */
+  public void writeInt32(final int fieldNumber, final int value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeInt32NoTag(value);
+  }
+
+  /** Write a {@code fixed64} field, including tag, to the stream. */
+  public void writeFixed64(final int fieldNumber, final long value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+    writeFixed64NoTag(value);
+  }
+
+  /** Write a {@code fixed32} field, including tag, to the stream. */
+  public void writeFixed32(final int fieldNumber, final int value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+    writeFixed32NoTag(value);
+  }
+
+  /** Write a {@code bool} field, including tag, to the stream. */
+  public void writeBool(final int fieldNumber, final boolean value)
+                        throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeBoolNoTag(value);
+  }
+
+  /** Write a {@code string} field, including tag, to the stream. */
+  public void writeString(final int fieldNumber, final String value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    writeStringNoTag(value);
+  }
+
+  /** Write a {@code group} field, including tag, to the stream. */
+  public void writeGroup(final int fieldNumber, final MessageNano value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_START_GROUP);
+    writeGroupNoTag(value);
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+  }
+
+  /** Write an embedded message field, including tag, to the stream. */
+  public void writeMessage(final int fieldNumber, final MessageNano value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    writeMessageNoTag(value);
+  }
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  public void writeBytes(final int fieldNumber, final byte[] value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    writeBytesNoTag(value);
+  }
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  public void writeBytes(final int fieldNumber, final byte[] value,
+                         final int offset, final int length)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    writeBytesNoTag(value, offset, length);
+  }
+
+  /** Write a {@code uint32} field, including tag, to the stream. */
+  public void writeUInt32(final int fieldNumber, final int value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeUInt32NoTag(value);
+  }
+
+  /**
+   * Write an enum field, including tag, to the stream.  Caller is responsible
+   * for converting the enum value to its numeric value.
+   */
+  public void writeEnum(final int fieldNumber, final int value)
+                        throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeEnumNoTag(value);
+  }
+
+  /** Write an {@code sfixed32} field, including tag, to the stream. */
+  public void writeSFixed32(final int fieldNumber, final int value)
+                            throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED32);
+    writeSFixed32NoTag(value);
+  }
+
+  /** Write an {@code sfixed64} field, including tag, to the stream. */
+  public void writeSFixed64(final int fieldNumber, final long value)
+                            throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_FIXED64);
+    writeSFixed64NoTag(value);
+  }
+
+  /** Write an {@code sint32} field, including tag, to the stream. */
+  public void writeSInt32(final int fieldNumber, final int value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeSInt32NoTag(value);
+  }
+
+  /** Write an {@code sint64} field, including tag, to the stream. */
+  public void writeSInt64(final int fieldNumber, final long value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatNano.WIRETYPE_VARINT);
+    writeSInt64NoTag(value);
+  }
+
+  /**
+   * Write a MessageSet extension field to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+//  public void writeMessageSetExtension(final int fieldNumber,
+//                                       final MessageMicro value)
+//                                       throws IOException {
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+//    writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+//  }
+
+  /**
+   * Write an unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+//  public void writeRawMessageSetExtension(final int fieldNumber,
+//                                          final ByteStringMicro value)
+//                                          throws IOException {
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+//    writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+//  }
+
+  // -----------------------------------------------------------------
+
+  /** Write a {@code double} field to the stream. */
+  public void writeDoubleNoTag(final double value) throws IOException {
+    writeRawLittleEndian64(Double.doubleToLongBits(value));
+  }
+
+  /** Write a {@code float} field to the stream. */
+  public void writeFloatNoTag(final float value) throws IOException {
+    writeRawLittleEndian32(Float.floatToIntBits(value));
+  }
+
+  /** Write a {@code uint64} field to the stream. */
+  public void writeUInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(value);
+  }
+
+  /** Write an {@code int64} field to the stream. */
+  public void writeInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(value);
+  }
+
+  /** Write an {@code int32} field to the stream. */
+  public void writeInt32NoTag(final int value) throws IOException {
+    if (value >= 0) {
+      writeRawVarint32(value);
+    } else {
+      // Must sign-extend.
+      writeRawVarint64(value);
+    }
+  }
+
+  /** Write a {@code fixed64} field to the stream. */
+  public void writeFixed64NoTag(final long value) throws IOException {
+    writeRawLittleEndian64(value);
+  }
+
+  /** Write a {@code fixed32} field to the stream. */
+  public void writeFixed32NoTag(final int value) throws IOException {
+    writeRawLittleEndian32(value);
+  }
+
+  /** Write a {@code bool} field to the stream. */
+  public void writeBoolNoTag(final boolean value) throws IOException {
+    writeRawByte(value ? 1 : 0);
+  }
+
+  /** Write a {@code string} field to the stream. */
+  public void writeStringNoTag(final String value) throws IOException {
+    // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
+    // and at most 3 times of it. Optimize for the case where we know this length results in a
+    // constant varint length - saves measuring length of the string.
+    try {
+      final int minLengthVarIntSize = computeRawVarint32Size(value.length());
+      final int maxLengthVarIntSize = computeRawVarint32Size(value.length() * MAX_UTF8_EXPANSION);
+      if (minLengthVarIntSize == maxLengthVarIntSize) {
+        int oldPosition = buffer.position();
+        // Buffer.position, when passed a position that is past its limit, throws
+        // IllegalArgumentException, and this class is documented to throw
+        // OutOfSpaceException instead.
+        if (buffer.remaining() < minLengthVarIntSize) {
+          throw new OutOfSpaceException(oldPosition + minLengthVarIntSize, buffer.limit());
+        }
+        buffer.position(oldPosition + minLengthVarIntSize);
+        encode(value, buffer);
+        int newPosition = buffer.position();
+        buffer.position(oldPosition);
+        writeRawVarint32(newPosition - oldPosition - minLengthVarIntSize);
+        buffer.position(newPosition);
+      } else {
+        writeRawVarint32(encodedLength(value));
+        encode(value, buffer);
+      }
+    } catch (BufferOverflowException e) {
+      final OutOfSpaceException outOfSpaceException = new OutOfSpaceException(buffer.position(),
+          buffer.limit());
+      outOfSpaceException.initCause(e);
+      throw outOfSpaceException;
+    }
+  }
+
+  // These UTF-8 handling methods are copied from Guava's Utf8 class.
+  /**
+   * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
+   * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
+   * both time and space.
+   *
+   * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+   *     surrogates)
+   */
+  private static int encodedLength(CharSequence sequence) {
+    // Warning to maintainers: this implementation is highly optimized.
+    int utf16Length = sequence.length();
+    int utf8Length = utf16Length;
+    int i = 0;
+
+    // This loop optimizes for pure ASCII.
+    while (i < utf16Length && sequence.charAt(i) < 0x80) {
+      i++;
+    }
+
+    // This loop optimizes for chars less than 0x800.
+    for (; i < utf16Length; i++) {
+      char c = sequence.charAt(i);
+      if (c < 0x800) {
+        utf8Length += ((0x7f - c) >>> 31);  // branch free!
+      } else {
+        utf8Length += encodedLengthGeneral(sequence, i);
+        break;
+      }
+    }
+
+    if (utf8Length < utf16Length) {
+      // Necessary and sufficient condition for overflow because of maximum 3x expansion
+      throw new IllegalArgumentException("UTF-8 length does not fit in int: "
+              + (utf8Length + (1L << 32)));
+    }
+    return utf8Length;
+  }
+
+  private static int encodedLengthGeneral(CharSequence sequence, int start) {
+    int utf16Length = sequence.length();
+    int utf8Length = 0;
+    for (int i = start; i < utf16Length; i++) {
+      char c = sequence.charAt(i);
+      if (c < 0x800) {
+        utf8Length += (0x7f - c) >>> 31; // branch free!
+      } else {
+        utf8Length += 2;
+        // jdk7+: if (Character.isSurrogate(c)) {
+        if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
+          // Check that we have a well-formed surrogate pair.
+          int cp = Character.codePointAt(sequence, i);
+          if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            throw new IllegalArgumentException("Unpaired surrogate at index " + i);
+          }
+          i++;
+        }
+      }
+    }
+    return utf8Length;
+  }
+
+  /**
+   * Encodes {@code sequence} into UTF-8, in {@code byteBuffer}. For a string, this method is
+   * equivalent to {@code buffer.put(string.getBytes(UTF_8))}, but is more efficient in both time
+   * and space. Bytes are written starting at the current position. This method requires paired
+   * surrogates, and therefore does not support chunking.
+   *
+   * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to
+   * compute the exact amount needed, or leave room for {@code 3 * sequence.length()}, which is the
+   * largest possible number of bytes that any input can be encoded to.
+   *
+   * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+   *     surrogates)
+   * @throws BufferOverflowException if {@code sequence} encoded in UTF-8 does not fit in
+   *     {@code byteBuffer}'s remaining space.
+   * @throws ReadOnlyBufferException if {@code byteBuffer} is a read-only buffer.
+   */
+  private static void encode(CharSequence sequence, ByteBuffer byteBuffer) {
+    if (byteBuffer.isReadOnly()) {
+      throw new ReadOnlyBufferException();
+    } else if (byteBuffer.hasArray()) {
+      try {
+        int encoded = encode(sequence,
+                byteBuffer.array(),
+                byteBuffer.arrayOffset() + byteBuffer.position(),
+                byteBuffer.remaining());
+        byteBuffer.position(encoded - byteBuffer.arrayOffset());
+      } catch (ArrayIndexOutOfBoundsException e) {
+        BufferOverflowException boe = new BufferOverflowException();
+        boe.initCause(e);
+        throw boe;
+      }
+    } else {
+      encodeDirect(sequence, byteBuffer);
+    }
+  }
+
+  private static void encodeDirect(CharSequence sequence, ByteBuffer byteBuffer) {
+    int utf16Length = sequence.length();
+    for (int i = 0; i < utf16Length; i++) {
+      final char c = sequence.charAt(i);
+      if (c < 0x80) { // ASCII
+        byteBuffer.put((byte) c);
+      } else if (c < 0x800) { // 11 bits, two UTF-8 bytes
+        byteBuffer.put((byte) ((0xF << 6) | (c >>> 6)));
+        byteBuffer.put((byte) (0x80 | (0x3F & c)));
+      } else if (c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) {
+        // Maximium single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+        byteBuffer.put((byte) ((0xF << 5) | (c >>> 12)));
+        byteBuffer.put((byte) (0x80 | (0x3F & (c >>> 6))));
+        byteBuffer.put((byte) (0x80 | (0x3F & c)));
+      } else {
+        final char low;
+        if (i + 1 == sequence.length()
+                || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
+          throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
+        }
+        int codePoint = Character.toCodePoint(c, low);
+        byteBuffer.put((byte) ((0xF << 4) | (codePoint >>> 18)));
+        byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 12))));
+        byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 6))));
+        byteBuffer.put((byte) (0x80 | (0x3F & codePoint)));
+      }
+    }
+  }
+
+  private static int encode(CharSequence sequence, byte[] bytes, int offset, int length) {
+    int utf16Length = sequence.length();
+    int j = offset;
+    int i = 0;
+    int limit = offset + length;
+    // Designed to take advantage of
+    // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+    for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) {
+      bytes[j + i] = (byte) c;
+    }
+    if (i == utf16Length) {
+      return j + utf16Length;
+    }
+    j += i;
+    for (char c; i < utf16Length; i++) {
+      c = sequence.charAt(i);
+      if (c < 0x80 && j < limit) {
+        bytes[j++] = (byte) c;
+      } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+        bytes[j++] = (byte) ((0xF << 6) | (c >>> 6));
+        bytes[j++] = (byte) (0x80 | (0x3F & c));
+      } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+        // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+        bytes[j++] = (byte) ((0xF << 5) | (c >>> 12));
+        bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+        bytes[j++] = (byte) (0x80 | (0x3F & c));
+      } else if (j <= limit - 4) {
+        // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes
+        final char low;
+        if (i + 1 == sequence.length()
+                || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
+          throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1));
+        }
+        int codePoint = Character.toCodePoint(c, low);
+        bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+        bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+        bytes[j++] = (byte) (0x80 | (0x3F & codePoint));
+      } else {
+        throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+      }
+    }
+    return j;
+  }
+
+  // End guava UTF-8 methods
+
+
+  /** Write a {@code group} field to the stream. */
+  public void writeGroupNoTag(final MessageNano value) throws IOException {
+    value.writeTo(this);
+  }
+
+  /** Write an embedded message field to the stream. */
+  public void writeMessageNoTag(final MessageNano value) throws IOException {
+    writeRawVarint32(value.getCachedSize());
+    value.writeTo(this);
+  }
+
+  /** Write a {@code bytes} field to the stream. */
+  public void writeBytesNoTag(final byte[] value) throws IOException {
+    writeRawVarint32(value.length);
+    writeRawBytes(value);
+  }
+
+  /** Write a {@code bytes} field to the stream. */
+  public void writeBytesNoTag(final byte[] value, final int offset, final int length)
+                              throws IOException {
+    writeRawVarint32(length);
+    writeRawBytes(value, offset, length);
+  }
+
+  /** Write a {@code uint32} field to the stream. */
+  public void writeUInt32NoTag(final int value) throws IOException {
+    writeRawVarint32(value);
+  }
+
+  /**
+   * Write an enum field to the stream.  Caller is responsible
+   * for converting the enum value to its numeric value.
+   */
+  public void writeEnumNoTag(final int value) throws IOException {
+    writeRawVarint32(value);
+  }
+
+  /** Write an {@code sfixed32} field to the stream. */
+  public void writeSFixed32NoTag(final int value) throws IOException {
+    writeRawLittleEndian32(value);
+  }
+
+  /** Write an {@code sfixed64} field to the stream. */
+  public void writeSFixed64NoTag(final long value) throws IOException {
+    writeRawLittleEndian64(value);
+  }
+
+  /** Write an {@code sint32} field to the stream. */
+  public void writeSInt32NoTag(final int value) throws IOException {
+    writeRawVarint32(encodeZigZag32(value));
+  }
+
+  /** Write an {@code sint64} field to the stream. */
+  public void writeSInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(encodeZigZag64(value));
+  }
+
+  // =================================================================
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSize(final int fieldNumber,
+                                      final double value) {
+    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSize(final int fieldNumber, final float value) {
+    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field, including tag.
+   */
+  public static int computeFixed64Size(final int fieldNumber,
+                                       final long value) {
+    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field, including tag.
+   */
+  public static int computeFixed32Size(final int fieldNumber,
+                                       final int value) {
+    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field, including tag.
+   */
+  public static int computeBoolSize(final int fieldNumber,
+                                    final boolean value) {
+    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field, including tag.
+   */
+  public static int computeStringSize(final int fieldNumber,
+                                      final String value) {
+    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field, including tag.
+   */
+  public static int computeGroupSize(final int fieldNumber,
+                                     final MessageNano value) {
+    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message field, including tag.
+   */
+  public static int computeMessageSize(final int fieldNumber,
+                                       final MessageNano value) {
+    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeBytesSize(final int fieldNumber,
+                                     final byte[] value) {
+    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field of the given length, including tag.
+   */
+  public static int computeBytesSize(final int fieldNumber,
+                                     final int length) {
+    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(length);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field, including tag.
+   */
+  public static int computeUInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * enum field, including tag.  Caller is responsible for converting the
+   * enum value to its numeric value.
+   */
+  public static int computeEnumSize(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field, including tag.
+   */
+  public static int computeSFixed32Size(final int fieldNumber,
+                                        final int value) {
+    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field, including tag.
+   */
+  public static int computeSFixed64Size(final int fieldNumber,
+                                        final long value) {
+    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field, including tag.
+   */
+  public static int computeSInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field, including tag.
+   */
+  public static int computeSInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * MessageSet extension to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+//  public static int computeMessageSetExtensionSize(
+//      final int fieldNumber, final MessageMicro value) {
+//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+//           computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+//  public static int computeRawMessageSetExtensionSize(
+//      final int fieldNumber, final ByteStringMicro value) {
+//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+//           computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSizeNoTag(final double value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSizeNoTag(final float value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32SizeNoTag(final int value) {
+    if (value >= 0) {
+      return computeRawVarint32Size(value);
+    } else {
+      // Must sign-extend.
+      return 10;
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field.
+   */
+  public static int computeFixed64SizeNoTag(final long value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field.
+   */
+  public static int computeFixed32SizeNoTag(final int value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field.
+   */
+  public static int computeBoolSizeNoTag(final boolean value) {
+    return 1;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field.
+   */
+  public static int computeStringSizeNoTag(final String value) {
+    final int length = encodedLength(value);
+    return computeRawVarint32Size(length) + length;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field.
+   */
+  public static int computeGroupSizeNoTag(final MessageNano value) {
+    return value.getSerializedSize();
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an embedded
+   * message field.
+   */
+  public static int computeMessageSizeNoTag(final MessageNano value) {
+    final int size = value.getSerializedSize();
+    return computeRawVarint32Size(size) + size;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeBytesSizeNoTag(final byte[] value) {
+    return computeRawVarint32Size(value.length) + value.length;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field of the given length.
+   */
+  public static int computeBytesSizeNoTag(final int length) {
+    return computeRawVarint32Size(length) + length;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field.
+   */
+  public static int computeUInt32SizeNoTag(final int value) {
+    return computeRawVarint32Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an enum field.
+   * Caller is responsible for converting the enum value to its numeric value.
+   */
+  public static int computeEnumSizeNoTag(final int value) {
+    return computeRawVarint32Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field.
+   */
+  public static int computeSFixed32SizeNoTag(final int value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field.
+   */
+  public static int computeSFixed64SizeNoTag(final long value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field.
+   */
+  public static int computeSInt32SizeNoTag(final int value) {
+    return computeRawVarint32Size(encodeZigZag32(value));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field.
+   */
+  public static int computeSInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(encodeZigZag64(value));
+  }
+
+  // =================================================================
+
+  /**
+   * If writing to a flat array, return the space left in the array.
+   * Otherwise, throws {@code UnsupportedOperationException}.
+   */
+  public int spaceLeft() {
+    return buffer.remaining();
+  }
+
+  /**
+   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
+   * a byte array that is exactly big enough to hold a message, then write to
+   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
+   * after writing verifies that the message was actually as big as expected,
+   * which can help catch bugs.
+   */
+  public void checkNoSpaceLeft() {
+    if (spaceLeft() != 0) {
+      throw new IllegalStateException(
+        "Did not write as much data as expected.");
+    }
+  }
+
+  /**
+   * Returns the position within the internal buffer.
+   */
+  public int position() {
+    return buffer.position();
+  }
+
+  /**
+   * Resets the position within the internal buffer to zero.
+   *
+   * @see #position
+   * @see #spaceLeft
+   */
+  public void reset() {
+    buffer.clear();
+  }
+
+  /**
+   * If you create a CodedOutputStream around a simple flat array, you must
+   * not attempt to write more bytes than the array has space.  Otherwise,
+   * this exception will be thrown.
+   */
+  public static class OutOfSpaceException extends IOException {
+    private static final long serialVersionUID = -6947486886997889499L;
+
+    OutOfSpaceException(int position, int limit) {
+      super("CodedOutputStream was writing to a flat byte array and ran " +
+            "out of space (pos " + position + " limit " + limit + ").");
+    }
+  }
+
+  /** Write a single byte. */
+  public void writeRawByte(final byte value) throws IOException {
+    if (!buffer.hasRemaining()) {
+      // We're writing to a single buffer.
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
+    }
+
+    buffer.put(value);
+  }
+
+  /** Write a single byte, represented by an integer value. */
+  public void writeRawByte(final int value) throws IOException {
+    writeRawByte((byte) value);
+  }
+
+  /** Write an array of bytes. */
+  public void writeRawBytes(final byte[] value) throws IOException {
+    writeRawBytes(value, 0, value.length);
+  }
+
+  /** Write part of an array of bytes. */
+  public void writeRawBytes(final byte[] value, int offset, int length)
+                            throws IOException {
+    if (buffer.remaining() >= length) {
+      buffer.put(value, offset, length);
+    } else {
+      // We're writing to a single buffer.
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
+    }
+  }
+
+  /** Encode and write a tag. */
+  public void writeTag(final int fieldNumber, final int wireType)
+                       throws IOException {
+    writeRawVarint32(WireFormatNano.makeTag(fieldNumber, wireType));
+  }
+
+  /** Compute the number of bytes that would be needed to encode a tag. */
+  public static int computeTagSize(final int fieldNumber) {
+    return computeRawVarint32Size(WireFormatNano.makeTag(fieldNumber, 0));
+  }
+
+  /**
+   * Encode and write a varint.  {@code value} is treated as
+   * unsigned, so it won't be sign-extended if negative.
+   */
+  public void writeRawVarint32(int value) throws IOException {
+    while (true) {
+      if ((value & ~0x7F) == 0) {
+        writeRawByte(value);
+        return;
+      } else {
+        writeRawByte((value & 0x7F) | 0x80);
+        value >>>= 7;
+      }
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   * {@code value} is treated as unsigned, so it won't be sign-extended if
+   * negative.
+   */
+  public static int computeRawVarint32Size(final int value) {
+    if ((value & (0xffffffff <<  7)) == 0) return 1;
+    if ((value & (0xffffffff << 14)) == 0) return 2;
+    if ((value & (0xffffffff << 21)) == 0) return 3;
+    if ((value & (0xffffffff << 28)) == 0) return 4;
+    return 5;
+  }
+
+  /** Encode and write a varint. */
+  public void writeRawVarint64(long value) throws IOException {
+    while (true) {
+      if ((value & ~0x7FL) == 0) {
+        writeRawByte((int)value);
+        return;
+      } else {
+        writeRawByte(((int)value & 0x7F) | 0x80);
+        value >>>= 7;
+      }
+    }
+  }
+
+  /** Compute the number of bytes that would be needed to encode a varint. */
+  public static int computeRawVarint64Size(final long value) {
+    if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
+    if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+    if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+    if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+    if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+    if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+    if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+    if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+    if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+    return 10;
+  }
+
+  /** Write a little-endian 32-bit integer. */
+  public void writeRawLittleEndian32(final int value) throws IOException {
+    if (buffer.remaining() < 4) {
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
+    }
+    buffer.putInt(value);
+  }
+
+  public static final int LITTLE_ENDIAN_32_SIZE = 4;
+
+  /** Write a little-endian 64-bit integer. */
+  public void writeRawLittleEndian64(final long value) throws IOException {
+    if (buffer.remaining() < 8) {
+      throw new OutOfSpaceException(buffer.position(), buffer.limit());
+    }
+    buffer.putLong(value);
+  }
+
+  public static final int LITTLE_ENDIAN_64_SIZE = 8;
+
+  /**
+   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 32-bit integer.
+   * @return An unsigned 32-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static int encodeZigZag32(final int n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 31);
+  }
+
+  /**
+   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 64-bit integer.
+   * @return An unsigned 64-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static long encodeZigZag64(final long n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 63);
+  }
+
+  static int computeFieldSize(int number, int type, Object object) {
+    switch (type) {
+      case InternalNano.TYPE_BOOL:
+        return computeBoolSize(number, (Boolean) object);
+      case InternalNano.TYPE_BYTES:
+        return computeBytesSize(number, (byte[]) object);
+      case InternalNano.TYPE_STRING:
+        return computeStringSize(number, (String) object);
+      case InternalNano.TYPE_FLOAT:
+        return computeFloatSize(number, (Float) object);
+      case InternalNano.TYPE_DOUBLE:
+        return computeDoubleSize(number, (Double) object);
+      case InternalNano.TYPE_ENUM:
+        return computeEnumSize(number, (Integer) object);
+      case InternalNano.TYPE_FIXED32:
+        return computeFixed32Size(number, (Integer) object);
+      case InternalNano.TYPE_INT32:
+        return computeInt32Size(number, (Integer) object);
+      case InternalNano.TYPE_UINT32:
+        return computeUInt32Size(number, (Integer) object);
+      case InternalNano.TYPE_SINT32:
+        return computeSInt32Size(number, (Integer) object);
+      case InternalNano.TYPE_SFIXED32:
+        return computeSFixed32Size(number, (Integer) object);
+      case InternalNano.TYPE_INT64:
+        return computeInt64Size(number, (Long) object);
+      case InternalNano.TYPE_UINT64:
+        return computeUInt64Size(number, (Long) object);
+      case InternalNano.TYPE_SINT64:
+        return computeSInt64Size(number, (Long) object);
+      case InternalNano.TYPE_FIXED64:
+        return computeFixed64Size(number, (Long) object);
+      case InternalNano.TYPE_SFIXED64:
+        return computeSFixed64Size(number, (Long) object);
+      case InternalNano.TYPE_MESSAGE:
+        return computeMessageSize(number, (MessageNano) object);
+      case InternalNano.TYPE_GROUP:
+        return computeGroupSize(number, (MessageNano) object);
+      default:
+        throw new IllegalArgumentException("Unknown type: " + type);
+    }
+  }
+
+  void writeField(int number, int type, Object value)
+      throws IOException {
+    switch (type) {
+      case InternalNano.TYPE_DOUBLE:
+        Double doubleValue = (Double) value;
+        writeDouble(number, doubleValue);
+        break;
+      case InternalNano.TYPE_FLOAT:
+        Float floatValue = (Float) value;
+        writeFloat(number, floatValue);
+        break;
+      case InternalNano.TYPE_INT64:
+        Long int64Value = (Long) value;
+        writeInt64(number, int64Value);
+        break;
+      case InternalNano.TYPE_UINT64:
+        Long uint64Value = (Long) value;
+        writeUInt64(number, uint64Value);
+        break;
+      case InternalNano.TYPE_INT32:
+        Integer int32Value = (Integer) value;
+        writeInt32(number, int32Value);
+        break;
+      case InternalNano.TYPE_FIXED64:
+        Long fixed64Value = (Long) value;
+        writeFixed64(number, fixed64Value);
+        break;
+      case InternalNano.TYPE_FIXED32:
+        Integer fixed32Value = (Integer) value;
+        writeFixed32(number, fixed32Value);
+        break;
+      case InternalNano.TYPE_BOOL:
+        Boolean boolValue = (Boolean) value;
+        writeBool(number, boolValue);
+        break;
+      case InternalNano.TYPE_STRING:
+        String stringValue = (String) value;
+        writeString(number, stringValue);
+        break;
+      case InternalNano.TYPE_BYTES:
+        byte[] bytesValue = (byte[]) value;
+        writeBytes(number, bytesValue);
+        break;
+      case InternalNano.TYPE_UINT32:
+        Integer uint32Value = (Integer) value;
+        writeUInt32(number, uint32Value);
+        break;
+      case InternalNano.TYPE_ENUM:
+        Integer enumValue = (Integer) value;
+        writeEnum(number, enumValue);
+        break;
+      case InternalNano.TYPE_SFIXED32:
+        Integer sfixed32Value = (Integer) value;
+        writeSFixed32(number, sfixed32Value);
+        break;
+      case InternalNano.TYPE_SFIXED64:
+        Long sfixed64Value = (Long) value;
+        writeSFixed64(number, sfixed64Value);
+        break;
+      case InternalNano.TYPE_SINT32:
+        Integer sint32Value = (Integer) value;
+        writeSInt32(number, sint32Value);
+        break;
+      case InternalNano.TYPE_SINT64:
+        Long sint64Value = (Long) value;
+        writeSInt64(number, sint64Value);
+        break;
+      case InternalNano.TYPE_MESSAGE:
+        MessageNano messageValue = (MessageNano) value;
+        writeMessage(number, messageValue);
+        break;
+      case InternalNano.TYPE_GROUP:
+        MessageNano groupValue = (MessageNano) value;
+        writeGroup(number, groupValue);
+        break;
+      default:
+        throw new IOException("Unknown type: " + type);
+    }
+  }
+
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
new file mode 100644
index 0000000..87973d7
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -0,0 +1,169 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+
+/**
+ * Base class of those Protocol Buffer messages that need to store unknown fields,
+ * such as extensions.
+ */
+public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
+        extends MessageNano {
+    /**
+     * A container for fields unknown to the message, including extensions. Extension fields can
+     * can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
+     */
+    protected FieldArray unknownFieldData;
+
+    @Override
+    protected int computeSerializedSize() {
+        int size = 0;
+        if (unknownFieldData != null) {
+            for (int i = 0; i < unknownFieldData.size(); i++) {
+                FieldData field = unknownFieldData.dataAt(i);
+                size += field.computeSerializedSize();
+            }
+        }
+        return size;
+    }
+
+    @Override
+    public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+        if (unknownFieldData == null) {
+            return;
+        }
+        for (int i = 0; i < unknownFieldData.size(); i++) {
+            FieldData field = unknownFieldData.dataAt(i);
+            field.writeTo(output);
+        }
+    }
+
+    /**
+     * Checks if there is a value stored for the specified extension in this
+     * message.
+     */
+    public final boolean hasExtension(Extension<M, ?> extension) {
+        if (unknownFieldData == null) {
+            return false;
+        }
+        FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+        return field != null;
+    }
+
+    /**
+     * Gets the value stored in the specified extension of this message.
+     */
+    public final <T> T getExtension(Extension<M, T> extension) {
+        if (unknownFieldData == null) {
+            return null;
+        }
+        FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+        return field == null ? null : field.getValue(extension);
+    }
+
+    /**
+     * Sets the value of the specified extension of this message.
+     */
+    public final <T> M setExtension(Extension<M, T> extension, T value) {
+        int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag);
+        if (value == null) {
+            if (unknownFieldData != null) {
+                unknownFieldData.remove(fieldNumber);
+                if (unknownFieldData.isEmpty()) {
+                    unknownFieldData = null;
+                }
+            }
+        } else {
+            FieldData field = null;
+            if (unknownFieldData == null) {
+                unknownFieldData = new FieldArray();
+            } else {
+                field = unknownFieldData.get(fieldNumber);
+            }
+            if (field == null) {
+                unknownFieldData.put(fieldNumber, new FieldData(extension, value));
+            } else {
+                field.setValue(extension, value);
+            }
+        }
+
+        @SuppressWarnings("unchecked") // Generated code should guarantee type safety
+        M typedThis = (M) this;
+        return typedThis;
+    }
+
+    /**
+     * Stores the binary data of an unknown field.
+     *
+     * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+     * option is on.
+     *
+     * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
+     * which case we do not want to add an unknown field entry.
+     *
+     * @param input the input buffer.
+     * @param tag the tag of the field.
+
+     * @return {@literal true} unless the tag is an end-group tag.
+     */
+    protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag)
+            throws IOException {
+        int startPos = input.getPosition();
+        if (!input.skipField(tag)) {
+            return false;  // This wasn't an unknown field, it's an end-group tag.
+        }
+        int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+        int endPos = input.getPosition();
+        byte[] bytes = input.getData(startPos, endPos - startPos);
+        UnknownFieldData unknownField = new UnknownFieldData(tag, bytes);
+
+        FieldData field = null;
+        if (unknownFieldData == null) {
+            unknownFieldData = new FieldArray();
+        } else {
+            field = unknownFieldData.get(fieldNumber);
+        }
+        if (field == null) {
+            field = new FieldData();
+            unknownFieldData.put(fieldNumber, field);
+        }
+        field.addUnknownField(unknownField);
+        return true;
+    }
+
+    @Override
+    public M clone() throws CloneNotSupportedException {
+        M cloned = (M) super.clone();
+        InternalNano.cloneUnknownFieldData(this, cloned);
+        return cloned;
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
new file mode 100644
index 0000000..c458f9b
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -0,0 +1,706 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an extension.
+ *
+ * @author bduff@google.com (Brian Duff)
+ * @author maxtroy@google.com (Max Cai)
+ * @param <M> the type of the extendable message this extension is for.
+ * @param <T> the Java type of the extension; see {@link #clazz}.
+ */
+public class Extension<M extends ExtendableMessageNano<M>, T> {
+
+    /*
+     * Because we typically only define message-typed extensions, the Extension class hierarchy is
+     * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
+     *
+     *            Extension          // ready to use for message/group typed extensions
+     *                Δ
+     *                |
+     *       PrimitiveExtension      // for primitive/enum typed extensions
+     */
+
+    public static final int TYPE_DOUBLE   = InternalNano.TYPE_DOUBLE;
+    public static final int TYPE_FLOAT    = InternalNano.TYPE_FLOAT;
+    public static final int TYPE_INT64    = InternalNano.TYPE_INT64;
+    public static final int TYPE_UINT64   = InternalNano.TYPE_UINT64;
+    public static final int TYPE_INT32    = InternalNano.TYPE_INT32;
+    public static final int TYPE_FIXED64  = InternalNano.TYPE_FIXED64;
+    public static final int TYPE_FIXED32  = InternalNano.TYPE_FIXED32;
+    public static final int TYPE_BOOL     = InternalNano.TYPE_BOOL;
+    public static final int TYPE_STRING   = InternalNano.TYPE_STRING;
+    public static final int TYPE_GROUP    = InternalNano.TYPE_GROUP;
+    public static final int TYPE_MESSAGE  = InternalNano.TYPE_MESSAGE;
+    public static final int TYPE_BYTES    = InternalNano.TYPE_BYTES;
+    public static final int TYPE_UINT32   = InternalNano.TYPE_UINT32;
+    public static final int TYPE_ENUM     = InternalNano.TYPE_ENUM;
+    public static final int TYPE_SFIXED32 = InternalNano.TYPE_SFIXED32;
+    public static final int TYPE_SFIXED64 = InternalNano.TYPE_SFIXED64;
+    public static final int TYPE_SINT32   = InternalNano.TYPE_SINT32;
+    public static final int TYPE_SINT64   = InternalNano.TYPE_SINT64;
+
+    /**
+     * Creates an {@code Extension} of the given message type and tag number.
+     * Should be used by the generated code only.
+     *
+     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+     * @deprecated use {@link #createMessageTyped(int, Class, long)} instead.
+     */
+    @Deprecated
+    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+            Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
+        return new Extension<M, T>(type, clazz, tag, false);
+    }
+
+    // Note: these create...() methods take a long for the tag parameter,
+    // because tags are represented as unsigned ints, and these values exist
+    // in generated code as long values. However, they can fit in 32-bits, so
+    // it's safe to cast them to int without loss of precision.
+
+    /**
+     * Creates an {@code Extension} of the given message type and tag number.
+     * Should be used by the generated code only.
+     *
+     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+     */
+    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+            Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) {
+        return new Extension<M, T>(type, clazz, (int) tag, false);
+    }
+
+    /**
+     * Creates a repeated {@code Extension} of the given message type and tag number.
+     * Should be used by the generated code only.
+     *
+     * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+     */
+    public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+            Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) {
+        return new Extension<M, T[]>(type, clazz, (int) tag, true);
+    }
+
+    /**
+     * Creates an {@code Extension} of the given primitive type and tag number.
+     * Should be used by the generated code only.
+     *
+     * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+     * @param clazz the boxed Java type of this extension
+     */
+    public static <M extends ExtendableMessageNano<M>, T>
+            Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) {
+        return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0);
+    }
+
+    /**
+     * Creates a repeated {@code Extension} of the given primitive type and tag number.
+     * Should be used by the generated code only.
+     *
+     * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+     * @param clazz the Java array type of this extension, with an unboxed component type
+     */
+    public static <M extends ExtendableMessageNano<M>, T>
+            Extension<M, T> createRepeatedPrimitiveTyped(
+                    int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) {
+        return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true,
+            (int) nonPackedTag, (int) packedTag);
+    }
+
+    /**
+     * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
+     */
+    protected final int type;
+
+    /**
+     * Java type of this extension. For a singular extension, this is the boxed Java type for the
+     * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
+     * component type is the unboxed Java type for {@link #type}. For example, for a singular
+     * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
+     * repeated {@code int32} extension, this equals {@code int[].class}.
+     */
+    protected final Class<T> clazz;
+
+    /**
+     * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
+     */
+    public final int tag;
+
+    /**
+     * Whether this extension is repeated.
+     */
+    protected final boolean repeated;
+
+    private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
+        this.type = type;
+        this.clazz = clazz;
+        this.tag = tag;
+        this.repeated = repeated;
+    }
+
+    /**
+     * Returns the value of this extension stored in the given list of unknown fields, or
+     * {@code null} if no unknown fields matches this extension.
+     *
+     * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
+     *                      that matches this Extension's tag.
+     *
+     */
+    final T getValueFrom(List<UnknownFieldData> unknownFields) {
+        if (unknownFields == null) {
+            return null;
+        }
+        return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
+    }
+
+    private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
+        // For repeated extensions, read all matching unknown fields in their original order.
+        List<Object> resultList = new ArrayList<Object>();
+        for (int i = 0; i < unknownFields.size(); i++) {
+            UnknownFieldData data = unknownFields.get(i);
+            if (data.bytes.length != 0) {
+                readDataInto(data, resultList);
+            }
+        }
+
+        int resultSize = resultList.size();
+        if (resultSize == 0) {
+            return null;
+        } else {
+            T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
+            for (int i = 0; i < resultSize; i++) {
+                Array.set(result, i, resultList.get(i));
+            }
+            return result;
+        }
+    }
+
+    private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
+        // For singular extensions, get the last piece of data stored under this extension.
+        if (unknownFields.isEmpty()) {
+            return null;
+        }
+        UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
+        return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
+    }
+
+    protected Object readData(CodedInputByteBufferNano input) {
+        // This implementation is for message/group extensions.
+        Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
+        try {
+            switch (type) {
+                case TYPE_GROUP:
+                    MessageNano group = (MessageNano) messageType.newInstance();
+                    input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
+                    return group;
+                case TYPE_MESSAGE:
+                    MessageNano message = (MessageNano) messageType.newInstance();
+                    input.readMessage(message);
+                    return message;
+                default:
+                    throw new IllegalArgumentException("Unknown type " + type);
+            }
+        } catch (InstantiationException e) {
+            throw new IllegalArgumentException(
+                    "Error creating instance of class " + messageType, e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException(
+                    "Error creating instance of class " + messageType, e);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Error reading extension field", e);
+        }
+    }
+
+    protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+        // This implementation is for message/group extensions.
+        resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+    }
+
+    void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
+        if (repeated) {
+            writeRepeatedData(value, output);
+        } else {
+            writeSingularData(value, output);
+        }
+    }
+
+    protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
+        // This implementation is for message/group extensions.
+        try {
+            out.writeRawVarint32(tag);
+            switch (type) {
+                case TYPE_GROUP:
+                    MessageNano groupValue = (MessageNano) value;
+                    int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+                    out.writeGroupNoTag(groupValue);
+                    // The endgroup tag must be included in the data payload.
+                    out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+                    break;
+                case TYPE_MESSAGE:
+                    MessageNano messageValue = (MessageNano) value;
+                    out.writeMessageNoTag(messageValue);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown type " + type);
+            }
+        } catch (IOException e) {
+            // Should not happen
+            throw new IllegalStateException(e);
+        }
+    }
+
+    protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+        // This implementation is for non-packed extensions.
+        int arrayLength = Array.getLength(array);
+        for (int i = 0; i < arrayLength; i++) {
+            Object element = Array.get(array, i);
+            if (element != null) {
+                writeSingularData(element, output);
+            }
+        }
+    }
+
+    int computeSerializedSize(Object value) {
+        if (repeated) {
+            return computeRepeatedSerializedSize(value);
+        } else {
+            return computeSingularSerializedSize(value);
+        }
+    }
+
+    protected int computeRepeatedSerializedSize(Object array) {
+        // This implementation is for non-packed extensions.
+        int size = 0;
+        int arrayLength = Array.getLength(array);
+        for (int i = 0; i < arrayLength; i++) {
+            Object element = Array.get(array, i);
+            if (element != null) {
+                size += computeSingularSerializedSize(Array.get(array, i));
+            }
+        }
+        return size;
+    }
+
+    protected int computeSingularSerializedSize(Object value) {
+        // This implementation is for message/group extensions.
+        int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+        switch (type) {
+            case TYPE_GROUP:
+                MessageNano groupValue = (MessageNano) value;
+                return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
+            case TYPE_MESSAGE:
+                MessageNano messageValue = (MessageNano) value;
+                return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
+            default:
+                throw new IllegalArgumentException("Unknown type " + type);
+        }
+    }
+
+    /**
+     * Represents an extension of a primitive (including enum) type. If there is no primitive
+     * extensions, this subclass will be removable by ProGuard.
+     */
+    private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
+            extends Extension<M, T> {
+
+        /**
+         * Tag of a piece of non-packed data from the wire compatible with this extension.
+         */
+        private final int nonPackedTag;
+
+        /**
+         * Tag of a piece of packed data from the wire compatible with this extension.
+         * 0 if the type of this extension is not packable.
+         */
+        private final int packedTag;
+
+        public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
+                int nonPackedTag, int packedTag) {
+            super(type, clazz, tag, repeated);
+            this.nonPackedTag = nonPackedTag;
+            this.packedTag = packedTag;
+        }
+
+        @Override
+        protected Object readData(CodedInputByteBufferNano input) {
+            try {
+              return input.readPrimitiveField(type);
+            } catch (IOException e) {
+                throw new IllegalArgumentException("Error reading extension field", e);
+            }
+        }
+
+        @Override
+        protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+            // This implementation is for primitive typed extensions,
+            // which can read both packed and non-packed data.
+            if (data.tag == nonPackedTag) {
+                resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+            } else {
+                CodedInputByteBufferNano buffer =
+                        CodedInputByteBufferNano.newInstance(data.bytes);
+                try {
+                    buffer.pushLimit(buffer.readRawVarint32()); // length limit
+                } catch (IOException e) {
+                    throw new IllegalArgumentException("Error reading extension field", e);
+                }
+                while (!buffer.isAtEnd()) {
+                    resultList.add(readData(buffer));
+                }
+            }
+        }
+
+        @Override
+        protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
+            try {
+                output.writeRawVarint32(tag);
+                switch (type) {
+                    case TYPE_DOUBLE:
+                        Double doubleValue = (Double) value;
+                        output.writeDoubleNoTag(doubleValue);
+                        break;
+                    case TYPE_FLOAT:
+                        Float floatValue = (Float) value;
+                        output.writeFloatNoTag(floatValue);
+                        break;
+                    case TYPE_INT64:
+                        Long int64Value = (Long) value;
+                        output.writeInt64NoTag(int64Value);
+                        break;
+                    case TYPE_UINT64:
+                        Long uint64Value = (Long) value;
+                        output.writeUInt64NoTag(uint64Value);
+                        break;
+                    case TYPE_INT32:
+                        Integer int32Value = (Integer) value;
+                        output.writeInt32NoTag(int32Value);
+                        break;
+                    case TYPE_FIXED64:
+                        Long fixed64Value = (Long) value;
+                        output.writeFixed64NoTag(fixed64Value);
+                        break;
+                    case TYPE_FIXED32:
+                        Integer fixed32Value = (Integer) value;
+                        output.writeFixed32NoTag(fixed32Value);
+                        break;
+                    case TYPE_BOOL:
+                        Boolean boolValue = (Boolean) value;
+                        output.writeBoolNoTag(boolValue);
+                        break;
+                    case TYPE_STRING:
+                        String stringValue = (String) value;
+                        output.writeStringNoTag(stringValue);
+                        break;
+                    case TYPE_BYTES:
+                        byte[] bytesValue = (byte[]) value;
+                        output.writeBytesNoTag(bytesValue);
+                        break;
+                    case TYPE_UINT32:
+                        Integer uint32Value = (Integer) value;
+                        output.writeUInt32NoTag(uint32Value);
+                        break;
+                    case TYPE_ENUM:
+                        Integer enumValue = (Integer) value;
+                        output.writeEnumNoTag(enumValue);
+                        break;
+                    case TYPE_SFIXED32:
+                        Integer sfixed32Value = (Integer) value;
+                        output.writeSFixed32NoTag(sfixed32Value);
+                        break;
+                    case TYPE_SFIXED64:
+                        Long sfixed64Value = (Long) value;
+                        output.writeSFixed64NoTag(sfixed64Value);
+                        break;
+                    case TYPE_SINT32:
+                        Integer sint32Value = (Integer) value;
+                        output.writeSInt32NoTag(sint32Value);
+                        break;
+                    case TYPE_SINT64:
+                        Long sint64Value = (Long) value;
+                        output.writeSInt64NoTag(sint64Value);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Unknown type " + type);
+                }
+            } catch (IOException e) {
+                // Should not happen
+                throw new IllegalStateException(e);
+            }
+        }
+
+        @Override
+        protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+            if (tag == nonPackedTag) {
+                // Use base implementation for non-packed data
+                super.writeRepeatedData(array, output);
+            } else if (tag == packedTag) {
+                // Packed. Note that the array element type is guaranteed to be primitive, so there
+                // won't be any null elements, so no null check in this block.
+                int arrayLength = Array.getLength(array);
+                int dataSize = computePackedDataSize(array);
+
+                try {
+                    output.writeRawVarint32(tag);
+                    output.writeRawVarint32(dataSize);
+                    switch (type) {
+                        case TYPE_BOOL:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeBoolNoTag(Array.getBoolean(array, i));
+                            }
+                            break;
+                        case TYPE_FIXED32:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeFixed32NoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        case TYPE_SFIXED32:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeSFixed32NoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        case TYPE_FLOAT:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeFloatNoTag(Array.getFloat(array, i));
+                            }
+                            break;
+                        case TYPE_FIXED64:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeFixed64NoTag(Array.getLong(array, i));
+                            }
+                            break;
+                        case TYPE_SFIXED64:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeSFixed64NoTag(Array.getLong(array, i));
+                            }
+                            break;
+                        case TYPE_DOUBLE:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeDoubleNoTag(Array.getDouble(array, i));
+                            }
+                            break;
+                        case TYPE_INT32:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeInt32NoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        case TYPE_SINT32:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeSInt32NoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        case TYPE_UINT32:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeUInt32NoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        case TYPE_INT64:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeInt64NoTag(Array.getLong(array, i));
+                            }
+                            break;
+                        case TYPE_SINT64:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeSInt64NoTag(Array.getLong(array, i));
+                            }
+                            break;
+                        case TYPE_UINT64:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeUInt64NoTag(Array.getLong(array, i));
+                            }
+                            break;
+                        case TYPE_ENUM:
+                            for (int i = 0; i < arrayLength; i++) {
+                                output.writeEnumNoTag(Array.getInt(array, i));
+                            }
+                            break;
+                        default:
+                            throw new IllegalArgumentException("Unpackable type " + type);
+                    }
+                } catch (IOException e) {
+                    // Should not happen.
+                    throw new IllegalStateException(e);
+                }
+            } else {
+                throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+                        + ", unequal to both non-packed variant " + nonPackedTag
+                        + " and packed variant " + packedTag);
+            }
+        }
+
+        private int computePackedDataSize(Object array) {
+            int dataSize = 0;
+            int arrayLength = Array.getLength(array);
+            switch (type) {
+                case TYPE_BOOL:
+                    // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
+                    dataSize = arrayLength;
+                    break;
+                case TYPE_FIXED32:
+                case TYPE_SFIXED32:
+                case TYPE_FLOAT:
+                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
+                    break;
+                case TYPE_FIXED64:
+                case TYPE_SFIXED64:
+                case TYPE_DOUBLE:
+                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
+                    break;
+                case TYPE_INT32:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
+                                Array.getInt(array, i));
+                    }
+                    break;
+                case TYPE_SINT32:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
+                                Array.getInt(array, i));
+                    }
+                    break;
+                case TYPE_UINT32:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
+                                Array.getInt(array, i));
+                    }
+                    break;
+                case TYPE_INT64:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
+                                Array.getLong(array, i));
+                    }
+                    break;
+                case TYPE_SINT64:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
+                                Array.getLong(array, i));
+                    }
+                    break;
+                case TYPE_UINT64:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
+                                Array.getLong(array, i));
+                    }
+                    break;
+                case TYPE_ENUM:
+                    for (int i = 0; i < arrayLength; i++) {
+                        dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
+                                Array.getInt(array, i));
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unexpected non-packable type " + type);
+            }
+            return dataSize;
+        }
+
+        @Override
+        protected int computeRepeatedSerializedSize(Object array) {
+            if (tag == nonPackedTag) {
+                // Use base implementation for non-packed data
+                return super.computeRepeatedSerializedSize(array);
+            } else if (tag == packedTag) {
+                // Packed.
+                int dataSize = computePackedDataSize(array);
+                int payloadSize =
+                        dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
+                return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+            } else {
+                throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+                        + ", unequal to both non-packed variant " + nonPackedTag
+                        + " and packed variant " + packedTag);
+            }
+        }
+
+        @Override
+        protected final int computeSingularSerializedSize(Object value) {
+            int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+            switch (type) {
+                case TYPE_DOUBLE:
+                    Double doubleValue = (Double) value;
+                    return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
+                case TYPE_FLOAT:
+                    Float floatValue = (Float) value;
+                    return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
+                case TYPE_INT64:
+                    Long int64Value = (Long) value;
+                    return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
+                case TYPE_UINT64:
+                    Long uint64Value = (Long) value;
+                    return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
+                case TYPE_INT32:
+                    Integer int32Value = (Integer) value;
+                    return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
+                case TYPE_FIXED64:
+                    Long fixed64Value = (Long) value;
+                    return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
+                case TYPE_FIXED32:
+                    Integer fixed32Value = (Integer) value;
+                    return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
+                case TYPE_BOOL:
+                    Boolean boolValue = (Boolean) value;
+                    return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
+                case TYPE_STRING:
+                    String stringValue = (String) value;
+                    return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
+                case TYPE_BYTES:
+                    byte[] bytesValue = (byte[]) value;
+                    return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
+                case TYPE_UINT32:
+                    Integer uint32Value = (Integer) value;
+                    return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
+                case TYPE_ENUM:
+                    Integer enumValue = (Integer) value;
+                    return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
+                case TYPE_SFIXED32:
+                    Integer sfixed32Value = (Integer) value;
+                    return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
+                            sfixed32Value);
+                case TYPE_SFIXED64:
+                    Long sfixed64Value = (Long) value;
+                    return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
+                            sfixed64Value);
+                case TYPE_SINT32:
+                    Integer sint32Value = (Integer) value;
+                    return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
+                case TYPE_SINT64:
+                    Long sint64Value = (Long) value;
+                    return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
+                default:
+                    throw new IllegalArgumentException("Unknown type " + type);
+            }
+        }
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
new file mode 100644
index 0000000..b49a97f
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -0,0 +1,291 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+package com.google.protobuf.nano;
+
+
+/**
+ * A custom version of {@code android.util.SparseArray} with the minimal API
+ * for storing {@link FieldData} objects.
+ *
+ * <p>This class is an internal implementation detail of nano and should not
+ * be called directly by clients.
+ *
+ * Based on {@code android.support.v4.util.SpareArrayCompat}.
+ */
+public final class FieldArray implements Cloneable {
+    private static final FieldData DELETED = new FieldData();
+    private boolean mGarbage = false;
+
+    private int[] mFieldNumbers;
+    private FieldData[] mData;
+    private int mSize;
+
+    /**
+     * Creates a new FieldArray containing no fields.
+     */
+    FieldArray() {
+        this(10);
+    }
+
+    /**
+     * Creates a new FieldArray containing no mappings that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.
+     */
+    FieldArray(int initialCapacity) {
+        initialCapacity = idealIntArraySize(initialCapacity);
+        mFieldNumbers = new int[initialCapacity];
+        mData = new FieldData[initialCapacity];
+        mSize = 0;
+    }
+
+    /**
+     * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
+     * if no such mapping has been made.
+     */
+    FieldData get(int fieldNumber) {
+        int i = binarySearch(fieldNumber);
+
+        if (i < 0 || mData[i] == DELETED) {
+            return null;
+        } else {
+            return mData[i];
+        }
+    }
+
+    /**
+     * Removes the data from the specified fieldNumber, if there was any.
+     */
+    void remove(int fieldNumber) {
+        int i = binarySearch(fieldNumber);
+
+        if (i >= 0 && mData[i] != DELETED) {
+            mData[i] = DELETED;
+            mGarbage = true;
+        }
+    }
+
+    private void gc() {
+        int n = mSize;
+        int o = 0;
+        int[] keys = mFieldNumbers;
+        FieldData[] values = mData;
+
+        for (int i = 0; i < n; i++) {
+            FieldData val = values[i];
+
+            if (val != DELETED) {
+                if (i != o) {
+                    keys[o] = keys[i];
+                    values[o] = val;
+                    values[i] = null;
+                }
+
+                o++;
+            }
+        }
+
+        mGarbage = false;
+        mSize = o;
+    }
+
+    /**
+     * Adds a mapping from the specified fieldNumber to the specified data,
+     * replacing the previous mapping if there was one.
+     */
+    void put(int fieldNumber, FieldData data) {
+        int i = binarySearch(fieldNumber);
+
+        if (i >= 0) {
+            mData[i] = data;
+        } else {
+            i = ~i;
+
+            if (i < mSize && mData[i] == DELETED) {
+                mFieldNumbers[i] = fieldNumber;
+                mData[i] = data;
+                return;
+            }
+
+            if (mGarbage && mSize >= mFieldNumbers.length) {
+                gc();
+
+                // Search again because indices may have changed.
+                i = ~ binarySearch(fieldNumber);
+            }
+
+            if (mSize >= mFieldNumbers.length) {
+                int n = idealIntArraySize(mSize + 1);
+
+                int[] nkeys = new int[n];
+                FieldData[] nvalues = new FieldData[n];
+
+                System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
+                System.arraycopy(mData, 0, nvalues, 0, mData.length);
+
+                mFieldNumbers = nkeys;
+                mData = nvalues;
+            }
+
+            if (mSize - i != 0) {
+                System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
+                System.arraycopy(mData, i, mData, i + 1, mSize - i);
+            }
+
+            mFieldNumbers[i] = fieldNumber;
+            mData[i] = data;
+            mSize++;
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings that this FieldArray
+     * currently stores.
+     */
+    int size() {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mSize;
+    }
+
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * FieldArray stores.
+     */
+    FieldData dataAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mData[index];
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof FieldArray)) {
+            return false;
+        }
+
+        FieldArray other = (FieldArray) o;
+        if (size() != other.size()) {  // size() will call gc() if necessary.
+            return false;
+        }
+        return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
+                arrayEquals(mData, other.mData, mSize);
+    }
+
+    @Override
+    public int hashCode() {
+        if (mGarbage) {
+            gc();
+        }
+        int result = 17;
+        for (int i = 0; i < mSize; i++) {
+            result = 31 * result + mFieldNumbers[i];
+            result = 31 * result + mData[i].hashCode();
+        }
+        return result;
+    }
+
+    private int idealIntArraySize(int need) {
+        return idealByteArraySize(need * 4) / 4;
+    }
+
+    private int idealByteArraySize(int need) {
+        for (int i = 4; i < 32; i++)
+            if (need <= (1 << i) - 12)
+                return (1 << i) - 12;
+
+        return need;
+    }
+
+    private int binarySearch(int value) {
+        int lo = 0;
+        int hi = mSize - 1;
+
+        while (lo <= hi) {
+            int mid = (lo + hi) >>> 1;
+            int midVal = mFieldNumbers[mid];
+
+            if (midVal < value) {
+                lo = mid + 1;
+            } else if (midVal > value) {
+                hi = mid - 1;
+            } else {
+                return mid; // value found
+            }
+        }
+        return ~lo; // value not present
+    }
+
+    private boolean arrayEquals(int[] a, int[] b, int size) {
+        for (int i = 0; i < size; i++) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
+        for (int i = 0; i < size; i++) {
+            if (!a[i].equals(b[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public final FieldArray clone() {
+        // Trigger GC so we compact and don't copy DELETED elements.
+        int size = size();
+        FieldArray clone = new FieldArray(size);
+        System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size);
+        for (int i = 0; i < size; i++) {
+            if (mData[i] != null) {
+                clone.mData[i] = mData[i].clone();
+            }
+        }
+        clone.mSize = size;
+        return clone;
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
new file mode 100644
index 0000000..ebebabc
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -0,0 +1,240 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated API doesn't
+ * know about yet.
+ */
+class FieldData implements Cloneable {
+    private Extension<?, ?> cachedExtension;
+    private Object value;
+    /** The serialised values for this object. Will be cleared if getValue is called */
+    private List<UnknownFieldData> unknownFieldData;
+
+    <T> FieldData(Extension<?, T> extension, T newValue) {
+        cachedExtension = extension;
+        value = newValue;
+    }
+
+    FieldData() {
+        unknownFieldData = new ArrayList<UnknownFieldData>();
+    }
+
+    void addUnknownField(UnknownFieldData unknownField) {
+        unknownFieldData.add(unknownField);
+    }
+
+    UnknownFieldData getUnknownField(int index) {
+        if (unknownFieldData == null) {
+            return null;
+        }
+        if (index < unknownFieldData.size()) {
+            return unknownFieldData.get(index);
+        }
+        return null;
+    }
+
+    int getUnknownFieldSize() {
+        if (unknownFieldData == null) {
+            return 0;
+        }
+        return unknownFieldData.size();
+    }
+
+    <T> T getValue(Extension<?, T> extension) {
+        if (value != null){
+            if (cachedExtension != extension) {  // Extension objects are singletons.
+                throw new IllegalStateException(
+                        "Tried to getExtension with a differernt Extension.");
+            }
+        } else {
+            cachedExtension = extension;
+            value = extension.getValueFrom(unknownFieldData);
+            unknownFieldData = null;
+        }
+        return (T) value;
+    }
+
+    <T> void setValue(Extension<?, T> extension, T newValue) {
+        cachedExtension = extension;
+        value = newValue;
+        unknownFieldData = null;
+    }
+
+    int computeSerializedSize() {
+        int size = 0;
+        if (value != null) {
+            size = cachedExtension.computeSerializedSize(value);
+        } else {
+            for (UnknownFieldData unknownField : unknownFieldData) {
+                size += unknownField.computeSerializedSize();
+            }
+        }
+        return size;
+    }
+
+    void writeTo(CodedOutputByteBufferNano output) throws IOException {
+        if (value != null) {
+            cachedExtension.writeTo(value, output);
+        } else {
+            for (UnknownFieldData unknownField : unknownFieldData) {
+                unknownField.writeTo(output);
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof FieldData)) {
+            return false;
+        }
+
+        FieldData other = (FieldData) o;
+        if (value != null && other.value != null) {
+            // If both objects have deserialized values, compare those.
+            // Since unknown fields are only compared if messages have generated equals methods
+            // we know this will be a meaningful comparison (not identity) for all values.
+            if (cachedExtension != other.cachedExtension) {  // Extension objects are singletons.
+                return false;
+            }
+            if (!cachedExtension.clazz.isArray()) {
+                // Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]'
+                return value.equals(other.value);
+            }
+            if (value instanceof byte[]) {
+                return Arrays.equals((byte[]) value, (byte[]) other.value);
+            } else if (value instanceof int[]) {
+                return Arrays.equals((int[]) value, (int[]) other.value);
+            } else if (value instanceof long[]) {
+                return Arrays.equals((long[]) value, (long[]) other.value);
+            } else if (value instanceof float[]) {
+                return Arrays.equals((float[]) value, (float[]) other.value);
+            } else if (value instanceof double[]) {
+                return Arrays.equals((double[]) value, (double[]) other.value);
+            } else if (value instanceof boolean[]) {
+                return Arrays.equals((boolean[]) value, (boolean[]) other.value);
+            } else {
+                return Arrays.deepEquals((Object[]) value, (Object[]) other.value);
+            }
+        }
+        if (unknownFieldData != null && other.unknownFieldData != null) {
+            // If both objects have byte arrays compare those directly.
+            return unknownFieldData.equals(other.unknownFieldData);
+        }
+        try {
+            // As a last resort, serialize and compare the resulting byte arrays.
+            return Arrays.equals(toByteArray(), other.toByteArray());
+        } catch (IOException e) {
+            // Should not happen.
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        try {
+            // The only way to generate a consistent hash is to use the serialized form.
+            result = 31 * result + Arrays.hashCode(toByteArray());
+        } catch (IOException e) {
+            // Should not happen.
+            throw new IllegalStateException(e);
+        }
+        return result;
+    }
+
+    private byte[] toByteArray() throws IOException {
+        byte[] result = new byte[computeSerializedSize()];
+        CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(result);
+        writeTo(output);
+        return result;
+    }
+
+    @Override
+    public final FieldData clone() {
+        FieldData clone = new FieldData();
+        try {
+            clone.cachedExtension = cachedExtension;
+            if (unknownFieldData == null) {
+                clone.unknownFieldData = null;
+            } else {
+                clone.unknownFieldData.addAll(unknownFieldData);
+            }
+
+            // Whether we need to deep clone value depends on its type. Primitive reference types
+            // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays
+            // and messages.
+            if (value == null) {
+                // No cloning required.
+            } else if (value instanceof MessageNano) {
+                clone.value = ((MessageNano) value).clone();
+            } else if (value instanceof byte[]) {
+                clone.value = ((byte[]) value).clone();
+            } else if (value instanceof byte[][]) {
+                byte[][] valueArray = (byte[][]) value;
+                byte[][] cloneArray = new byte[valueArray.length][];
+                clone.value = cloneArray;
+                for (int i = 0; i < valueArray.length; i++) {
+                    cloneArray[i] = valueArray[i].clone();
+                }
+            } else if (value instanceof boolean[]) {
+                clone.value = ((boolean[]) value).clone();
+            } else if (value instanceof int[]) {
+                clone.value = ((int[]) value).clone();
+            } else if (value instanceof long[]) {
+                clone.value = ((long[]) value).clone();
+            } else if (value instanceof float[]) {
+                clone.value = ((float[]) value).clone();
+            } else if (value instanceof double[]) {
+                clone.value = ((double[]) value).clone();
+            } else if (value instanceof MessageNano[]) {
+                MessageNano[] valueArray = (MessageNano[]) value;
+                MessageNano[] cloneArray = new MessageNano[valueArray.length];
+                clone.value = cloneArray;
+                for (int i = 0; i < valueArray.length; i++) {
+                    cloneArray[i] = valueArray[i].clone();
+                }
+            }
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
new file mode 100644
index 0000000..f1263df
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -0,0 +1,547 @@
+// 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.
+
+package com.google.protobuf.nano;
+
+import com.google.protobuf.nano.MapFactories.MapFactory;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * The classes contained within are used internally by the Protocol Buffer
+ * library and generated message implementations. They are public only because
+ * those generated messages do not reside in the {@code protobuf} package.
+ * Others should not use this class directly.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public final class InternalNano {
+
+  public static final int TYPE_DOUBLE   = 1;
+  public static final int TYPE_FLOAT    = 2;
+  public static final int TYPE_INT64    = 3;
+  public static final int TYPE_UINT64   = 4;
+  public static final int TYPE_INT32    = 5;
+  public static final int TYPE_FIXED64  = 6;
+  public static final int TYPE_FIXED32  = 7;
+  public static final int TYPE_BOOL     = 8;
+  public static final int TYPE_STRING   = 9;
+  public static final int TYPE_GROUP    = 10;
+  public static final int TYPE_MESSAGE  = 11;
+  public static final int TYPE_BYTES    = 12;
+  public static final int TYPE_UINT32   = 13;
+  public static final int TYPE_ENUM     = 14;
+  public static final int TYPE_SFIXED32 = 15;
+  public static final int TYPE_SFIXED64 = 16;
+  public static final int TYPE_SINT32   = 17;
+  public static final int TYPE_SINT64   = 18;
+
+  protected static final Charset UTF_8 = Charset.forName("UTF-8");
+  protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+  private InternalNano() {}
+
+  /**
+   * An object to provide synchronization when lazily initializing static fields
+   * of {@link MessageNano} subclasses.
+   * <p>
+   * To enable earlier versions of ProGuard to inline short methods from a
+   * generated MessageNano subclass to the call sites, that class must not have
+   * a class initializer, which will be created if there is any static variable
+   * initializers. To lazily initialize the static variables in a thread-safe
+   * manner, the initialization code will synchronize on this object.
+   */
+  public static final Object LAZY_INIT_LOCK = new Object();
+
+  /**
+   * Helper called by generated code to construct default values for string
+   * fields.
+   * <p>
+   * The protocol compiler does not actually contain a UTF-8 decoder -- it
+   * just pushes UTF-8-encoded text around without touching it.  The one place
+   * where this presents a problem is when generating Java string literals.
+   * Unicode characters in the string literal would normally need to be encoded
+   * using a Unicode escape sequence, which would require decoding them.
+   * To get around this, protoc instead embeds the UTF-8 bytes into the
+   * generated code and leaves it to the runtime library to decode them.
+   * <p>
+   * It gets worse, though.  If protoc just generated a byte array, like:
+   *   new byte[] {0x12, 0x34, 0x56, 0x78}
+   * Java actually generates *code* which allocates an array and then fills
+   * in each value.  This is much less efficient than just embedding the bytes
+   * directly into the bytecode.  To get around this, we need another
+   * work-around.  String literals are embedded directly, so protoc actually
+   * generates a string literal corresponding to the bytes.  The easiest way
+   * to do this is to use the ISO-8859-1 character set, which corresponds to
+   * the first 256 characters of the Unicode range.  Protoc can then use
+   * good old CEscape to generate the string.
+   * <p>
+   * So we have a string literal which represents a set of bytes which
+   * represents another string.  This function -- stringDefaultValue --
+   * converts from the generated string to the string we actually want.  The
+   * generated code calls this automatically.
+   */
+  public static String stringDefaultValue(String bytes) {
+    return new String(bytes.getBytes(ISO_8859_1), InternalNano.UTF_8);
+  }
+
+  /**
+   * Helper called by generated code to construct default values for bytes
+   * fields.
+   * <p>
+   * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+   * In this case we only need the second of the two hacks -- allowing us to
+   * embed raw bytes as a string literal with ISO-8859-1 encoding.
+   */
+  public static byte[] bytesDefaultValue(String bytes) {
+    return bytes.getBytes(ISO_8859_1);
+  }
+
+  /**
+   * Helper function to convert a string into UTF-8 while turning the
+   * UnsupportedEncodingException to a RuntimeException.
+   */
+  public static byte[] copyFromUtf8(final String text) {
+    return text.getBytes(InternalNano.UTF_8);
+  }
+
+  /**
+   * Checks repeated int field equality; null-value and 0-length fields are
+   * considered equal.
+   */
+  public static boolean equals(int[] field1, int[] field2) {
+    if (field1 == null || field1.length == 0) {
+      return field2 == null || field2.length == 0;
+    } else {
+      return Arrays.equals(field1, field2);
+    }
+  }
+
+  /**
+   * Checks repeated long field equality; null-value and 0-length fields are
+   * considered equal.
+   */
+  public static boolean equals(long[] field1, long[] field2) {
+    if (field1 == null || field1.length == 0) {
+      return field2 == null || field2.length == 0;
+    } else {
+      return Arrays.equals(field1, field2);
+    }
+  }
+
+  /**
+   * Checks repeated float field equality; null-value and 0-length fields are
+   * considered equal.
+   */
+  public static boolean equals(float[] field1, float[] field2) {
+    if (field1 == null || field1.length == 0) {
+      return field2 == null || field2.length == 0;
+    } else {
+      return Arrays.equals(field1, field2);
+    }
+  }
+
+  /**
+   * Checks repeated double field equality; null-value and 0-length fields are
+   * considered equal.
+   */
+  public static boolean equals(double[] field1, double[] field2) {
+    if (field1 == null || field1.length == 0) {
+      return field2 == null || field2.length == 0;
+    } else {
+      return Arrays.equals(field1, field2);
+    }
+  }
+
+  /**
+   * Checks repeated boolean field equality; null-value and 0-length fields are
+   * considered equal.
+   */
+  public static boolean equals(boolean[] field1, boolean[] field2) {
+    if (field1 == null || field1.length == 0) {
+      return field2 == null || field2.length == 0;
+    } else {
+      return Arrays.equals(field1, field2);
+    }
+  }
+
+  /**
+   * Checks repeated bytes field equality. Only non-null elements are tested.
+   * Returns true if the two fields have the same sequence of non-null
+   * elements. Null-value fields and fields of any length with only null
+   * elements are considered equal.
+   */
+  public static boolean equals(byte[][] field1, byte[][] field2) {
+    int index1 = 0;
+    int length1 = field1 == null ? 0 : field1.length;
+    int index2 = 0;
+    int length2 = field2 == null ? 0 : field2.length;
+    while (true) {
+      while (index1 < length1 && field1[index1] == null) {
+        index1++;
+      }
+      while (index2 < length2 && field2[index2] == null) {
+        index2++;
+      }
+      boolean atEndOf1 = index1 >= length1;
+      boolean atEndOf2 = index2 >= length2;
+      if (atEndOf1 && atEndOf2) {
+        // no more non-null elements to test in both arrays
+        return true;
+      } else if (atEndOf1 != atEndOf2) {
+        // one of the arrays have extra non-null elements
+        return false;
+      } else if (!Arrays.equals(field1[index1], field2[index2])) {
+        // element mismatch
+        return false;
+      }
+      index1++;
+      index2++;
+    }
+  }
+
+  /**
+   * Checks repeated string/message field equality. Only non-null elements are
+   * tested. Returns true if the two fields have the same sequence of non-null
+   * elements. Null-value fields and fields of any length with only null
+   * elements are considered equal.
+   */
+  public static boolean equals(Object[] field1, Object[] field2) {
+    int index1 = 0;
+    int length1 = field1 == null ? 0 : field1.length;
+    int index2 = 0;
+    int length2 = field2 == null ? 0 : field2.length;
+    while (true) {
+      while (index1 < length1 && field1[index1] == null) {
+        index1++;
+      }
+      while (index2 < length2 && field2[index2] == null) {
+        index2++;
+      }
+      boolean atEndOf1 = index1 >= length1;
+      boolean atEndOf2 = index2 >= length2;
+      if (atEndOf1 && atEndOf2) {
+        // no more non-null elements to test in both arrays
+        return true;
+      } else if (atEndOf1 != atEndOf2) {
+        // one of the arrays have extra non-null elements
+        return false;
+      } else if (!field1[index1].equals(field2[index2])) {
+        // element mismatch
+        return false;
+      }
+      index1++;
+      index2++;
+    }
+  }
+
+  /**
+   * Computes the hash code of a repeated int field. Null-value and 0-length
+   * fields have the same hash code.
+   */
+  public static int hashCode(int[] field) {
+    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+  }
+
+  /**
+   * Computes the hash code of a repeated long field. Null-value and 0-length
+   * fields have the same hash code.
+   */
+  public static int hashCode(long[] field) {
+    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+  }
+
+  /**
+   * Computes the hash code of a repeated float field. Null-value and 0-length
+   * fields have the same hash code.
+   */
+  public static int hashCode(float[] field) {
+    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+  }
+
+  /**
+   * Computes the hash code of a repeated double field. Null-value and 0-length
+   * fields have the same hash code.
+   */
+  public static int hashCode(double[] field) {
+    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+  }
+
+  /**
+   * Computes the hash code of a repeated boolean field. Null-value and 0-length
+   * fields have the same hash code.
+   */
+  public static int hashCode(boolean[] field) {
+    return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+  }
+
+  /**
+   * Computes the hash code of a repeated bytes field. Only the sequence of all
+   * non-null elements are used in the computation. Null-value fields and fields
+   * of any length with only null elements have the same hash code.
+   */
+  public static int hashCode(byte[][] field) {
+    int result = 0;
+    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+      byte[] element = field[i];
+      if (element != null) {
+        result = 31 * result + Arrays.hashCode(element);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Computes the hash code of a repeated string/message field. Only the
+   * sequence of all non-null elements are used in the computation. Null-value
+   * fields and fields of any length with only null elements have the same hash
+   * code.
+   */
+  public static int hashCode(Object[] field) {
+    int result = 0;
+    for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+      Object element = field[i];
+      if (element != null) {
+        result = 31 * result + element.hashCode();
+      }
+    }
+    return result;
+  }
+  private static Object primitiveDefaultValue(int type) {
+    switch (type) {
+      case TYPE_BOOL:
+        return Boolean.FALSE;
+      case TYPE_BYTES:
+        return WireFormatNano.EMPTY_BYTES;
+      case TYPE_STRING:
+        return "";
+      case TYPE_FLOAT:
+        return Float.valueOf(0);
+      case TYPE_DOUBLE:
+        return Double.valueOf(0);
+      case TYPE_ENUM:
+      case TYPE_FIXED32:
+      case TYPE_INT32:
+      case TYPE_UINT32:
+      case TYPE_SINT32:
+      case TYPE_SFIXED32:
+        return Integer.valueOf(0);
+      case TYPE_INT64:
+      case TYPE_UINT64:
+      case TYPE_SINT64:
+      case TYPE_FIXED64:
+      case TYPE_SFIXED64:
+        return Long.valueOf(0L);
+      case TYPE_MESSAGE:
+      case TYPE_GROUP:
+      default:
+        throw new IllegalArgumentException(
+            "Type: " + type + " is not a primitive type.");
+    }
+  }
+
+  /**
+   * Merges the map entry into the map field. Note this is only supposed to
+   * be called by generated messages.
+   *
+   * @param map the map field; may be null, in which case a map will be
+   *        instantiated using the {@link MapFactories.MapFactory}
+   * @param input the input byte buffer
+   * @param keyType key type, as defined in InternalNano.TYPE_*
+   * @param valueType value type, as defined in InternalNano.TYPE_*
+   * @param value an new instance of the value, if the value is a TYPE_MESSAGE;
+   *        otherwise this parameter can be null and will be ignored.
+   * @param keyTag wire tag for the key
+   * @param valueTag wire tag for the value
+   * @return the map field
+   * @throws IOException
+   */
+  @SuppressWarnings("unchecked")
+  public static final <K, V> Map<K, V> mergeMapEntry(
+      CodedInputByteBufferNano input,
+      Map<K, V> map,
+      MapFactory mapFactory,
+      int keyType,
+      int valueType,
+      V value,
+      int keyTag,
+      int valueTag) throws IOException {
+    map = mapFactory.forMap(map);
+    final int length = input.readRawVarint32();
+    final int oldLimit = input.pushLimit(length);
+    K key = null;
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+      if (tag == keyTag) {
+        key = (K) input.readPrimitiveField(keyType);
+      } else if (tag == valueTag) {
+        if (valueType == TYPE_MESSAGE) {
+          input.readMessage((MessageNano) value);
+        } else {
+          value = (V) input.readPrimitiveField(valueType);
+        }
+      } else {
+        if (!input.skipField(tag)) {
+          break;
+        }
+      }
+    }
+    input.checkLastTagWas(0);
+    input.popLimit(oldLimit);
+
+    if (key == null) {
+      // key can only be primitive types.
+      key = (K) primitiveDefaultValue(keyType);
+    }
+
+    if (value == null) {
+      // message type value will be initialized by code-gen.
+      value = (V) primitiveDefaultValue(valueType);
+    }
+
+    map.put(key, value);
+    return map;
+  }
+
+  public static <K, V> void serializeMapField(
+      CodedOutputByteBufferNano output,
+      Map<K, V> map, int number, int keyType, int valueType)
+          throws IOException {
+    for (Entry<K, V> entry: map.entrySet()) {
+      K key = entry.getKey();
+      V value = entry.getValue();
+      if (key == null || value == null) {
+        throw new IllegalStateException(
+            "keys and values in maps cannot be null");
+      }
+      int entrySize =
+          CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+          CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+      output.writeTag(number, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+      output.writeRawVarint32(entrySize);
+      output.writeField(1, keyType, key);
+      output.writeField(2, valueType, value);
+    }
+  }
+
+  public static <K, V> int computeMapFieldSize(
+      Map<K, V> map, int number, int keyType, int valueType) {
+    int size = 0;
+    int tagSize = CodedOutputByteBufferNano.computeTagSize(number);
+    for (Entry<K, V> entry: map.entrySet()) {
+      K key = entry.getKey();
+      V value = entry.getValue();
+      if (key == null || value == null) {
+        throw new IllegalStateException(
+            "keys and values in maps cannot be null");
+      }
+      int entrySize =
+          CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+          CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+      size += tagSize + entrySize
+          + CodedOutputByteBufferNano.computeRawVarint32Size(entrySize);
+    }
+    return size;
+  }
+
+  /**
+   * Checks whether two {@link Map} are equal. We don't use the default equals
+   * method of {@link Map} because it compares by identity not by content for
+   * byte arrays.
+   */
+  public static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
+    if (a == b) {
+      return true;
+    }
+    if (a == null) {
+      return b.size() == 0;
+    }
+    if (b == null) {
+      return a.size() == 0;
+    }
+    if (a.size() != b.size()) {
+      return false;
+    }
+    for (Entry<K, V> entry : a.entrySet()) {
+      if (!b.containsKey(entry.getKey())) {
+        return false;
+      }
+      if (!equalsMapValue(entry.getValue(), b.get(entry.getKey()))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static boolean equalsMapValue(Object a, Object b) {
+    if (a == null || b == null) {
+      throw new IllegalStateException(
+          "keys and values in maps cannot be null");
+    }
+    if (a instanceof byte[] && b instanceof byte[]) {
+      return Arrays.equals((byte[]) a, (byte[]) b);
+    }
+    return a.equals(b);
+  }
+
+  public static <K, V> int hashCode(Map<K, V> map) {
+    if (map == null) {
+      return 0;
+    }
+    int result = 0;
+    for (Entry<K, V> entry : map.entrySet()) {
+      result += hashCodeForMap(entry.getKey())
+          ^ hashCodeForMap(entry.getValue());
+    }
+    return result;
+  }
+
+  private static int hashCodeForMap(Object o) {
+    if (o instanceof byte[]) {
+      return Arrays.hashCode((byte[]) o);
+    }
+    return o.hashCode();
+  }
+
+  // This avoids having to make FieldArray public.
+  public static void cloneUnknownFieldData(ExtendableMessageNano original,
+      ExtendableMessageNano cloned) {
+    if (original.unknownFieldData != null) {
+      cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone();
+    }
+  }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java b/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
new file mode 100644
index 0000000..3864d38
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way,
+ * e.g. it contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferNanoException extends IOException {
+  private static final long serialVersionUID = -1616151763072450476L;
+
+  public InvalidProtocolBufferNanoException(final String description) {
+    super(description);
+  }
+
+  static InvalidProtocolBufferNanoException truncatedMessage() {
+    return new InvalidProtocolBufferNanoException(
+      "While parsing a protocol message, the input ended unexpectedly " +
+      "in the middle of a field.  This could mean either than the " +
+      "input has been truncated or that an embedded message " +
+      "misreported its own length.");
+  }
+
+  static InvalidProtocolBufferNanoException negativeSize() {
+    return new InvalidProtocolBufferNanoException(
+      "CodedInputStream encountered an embedded string or message " +
+      "which claimed to have negative size.");
+  }
+
+  static InvalidProtocolBufferNanoException malformedVarint() {
+    return new InvalidProtocolBufferNanoException(
+      "CodedInputStream encountered a malformed varint.");
+  }
+
+  static InvalidProtocolBufferNanoException invalidTag() {
+    return new InvalidProtocolBufferNanoException(
+      "Protocol message contained an invalid tag (zero).");
+  }
+
+  static InvalidProtocolBufferNanoException invalidEndTag() {
+    return new InvalidProtocolBufferNanoException(
+      "Protocol message end-group tag did not match expected tag.");
+  }
+
+  static InvalidProtocolBufferNanoException invalidWireType() {
+    return new InvalidProtocolBufferNanoException(
+      "Protocol message tag had invalid wire type.");
+  }
+
+  static InvalidProtocolBufferNanoException recursionLimitExceeded() {
+    return new InvalidProtocolBufferNanoException(
+      "Protocol message had too many levels of nesting.  May be malicious.  " +
+      "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+  }
+
+  static InvalidProtocolBufferNanoException sizeLimitExceeded() {
+    return new InvalidProtocolBufferNanoException(
+      "Protocol message was too large.  May be malicious.  " +
+      "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+  }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
new file mode 100644
index 0000000..98fa487
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class for maps support.
+ */
+public final class MapFactories {
+  public static interface MapFactory {
+    <K, V> Map<K, V> forMap(Map<K, V> oldMap);
+  }
+
+  // NOTE(liujisi): The factory setter is temporarily marked as package private.
+  // The way to provide customized implementations of maps for different
+  // platforms are still under discussion.  Mark it as private to avoid exposing
+  // the API in proto3 alpha release.
+  /* public */ static void setMapFactory(MapFactory newMapFactory) {
+    mapFactory = newMapFactory;
+  }
+
+  public static MapFactory getMapFactory() {
+    return mapFactory;
+  }
+
+  private static class DefaultMapFactory implements MapFactory {
+    public <K, V> Map<K, V> forMap(Map<K, V> oldMap) {
+      if (oldMap == null) {
+        return new HashMap<K, V>();
+      }
+      return oldMap;
+    }
+  }
+  private static volatile MapFactory mapFactory = new DefaultMapFactory();
+
+  private MapFactories() {}
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
new file mode 100644
index 0000000..2347502
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -0,0 +1,198 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public abstract class MessageNano {
+    protected volatile int cachedSize = -1;
+
+    /**
+     * Get the number of bytes required to encode this message.
+     * Returns the cached size or calls getSerializedSize which
+     * sets the cached size. This is used internally when serializing
+     * so the size is only computed once. If a member is modified
+     * then this could be stale call getSerializedSize if in doubt.
+     */
+    public int getCachedSize() {
+        if (cachedSize < 0) {
+            // getSerializedSize sets cachedSize
+            getSerializedSize();
+        }
+        return cachedSize;
+    }
+
+    /**
+     * Computes the number of bytes required to encode this message.
+     * The size is cached and the cached result can be retrieved
+     * using getCachedSize().
+     */
+    public int getSerializedSize() {
+        int size = computeSerializedSize();
+        cachedSize = size;
+        return size;
+    }
+
+    /**
+     * Computes the number of bytes required to encode this message. This does not update the
+     * cached size.
+     */
+    protected int computeSerializedSize() {
+      // This is overridden if the generated message has serialized fields.
+      return 0;
+    }
+
+    /**
+     * Serializes the message and writes it to {@code output}.
+     *
+     * @param output the output to receive the serialized form.
+     * @throws IOException if an error occurred writing to {@code output}.
+     */
+    public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+        // Does nothing by default. Overridden by subclasses which have data to write.
+    }
+
+    /**
+     * Parse {@code input} as a message of this type and merge it with the
+     * message being built.
+     */
+    public abstract MessageNano mergeFrom(CodedInputByteBufferNano input) throws IOException;
+
+    /**
+     * Serialize to a byte array.
+     * @return byte array with the serialized data.
+     */
+    public static final byte[] toByteArray(MessageNano msg) {
+        final byte[] result = new byte[msg.getSerializedSize()];
+        toByteArray(msg, result, 0, result.length);
+        return result;
+    }
+
+    /**
+     * Serialize to a byte array starting at offset through length. The
+     * method getSerializedSize must have been called prior to calling
+     * this method so the proper length is know.  If an attempt to
+     * write more than length bytes OutOfSpaceException will be thrown
+     * and if length bytes are not written then IllegalStateException
+     * is thrown.
+     */
+    public static final void toByteArray(MessageNano msg, byte[] data, int offset, int length) {
+        try {
+            final CodedOutputByteBufferNano output =
+                CodedOutputByteBufferNano.newInstance(data, offset, length);
+            msg.writeTo(output);
+            output.checkNoSpaceLeft();
+        } catch (IOException e) {
+            throw new RuntimeException("Serializing to a byte array threw an IOException "
+                    + "(should never happen).", e);
+        }
+    }
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.
+     */
+    public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data)
+        throws InvalidProtocolBufferNanoException {
+        return mergeFrom(msg, data, 0, data.length);
+    }
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.
+     */
+    public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data,
+            final int off, final int len) throws InvalidProtocolBufferNanoException {
+        try {
+            final CodedInputByteBufferNano input =
+                CodedInputByteBufferNano.newInstance(data, off, len);
+            msg.mergeFrom(input);
+            input.checkLastTagWas(0);
+            return msg;
+        } catch (InvalidProtocolBufferNanoException e) {
+            throw e;
+        } catch (IOException e) {
+            throw new RuntimeException("Reading from a byte array threw an IOException (should "
+                    + "never happen).");
+        }
+    }
+
+    /**
+     * Compares two {@code MessageNano}s and returns true if the message's are the same class and
+     * have serialized form equality (i.e. all of the field values are the same).
+     */
+    public static final boolean messageNanoEquals(MessageNano a, MessageNano b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null || b == null) {
+            return false;
+        }
+        if (a.getClass() != b.getClass()) {
+          return false;
+        }
+        final int serializedSize = a.getSerializedSize();
+        if (b.getSerializedSize() != serializedSize) {
+            return false;
+        }
+        final byte[] aByteArray = new byte[serializedSize];
+        final byte[] bByteArray = new byte[serializedSize];
+        toByteArray(a, aByteArray, 0, serializedSize);
+        toByteArray(b, bByteArray, 0, serializedSize);
+        return Arrays.equals(aByteArray, bByteArray);
+    }
+
+    /**
+     * Returns a string that is (mostly) compatible with ProtoBuffer's TextFormat. Note that groups
+     * (which are deprecated) are not serialized with the correct field name.
+     *
+     * <p>This is implemented using reflection, so it is not especially fast nor is it guaranteed
+     * to find all fields if you have method removal turned on for proguard.
+     */
+    @Override
+    public String toString() {
+        return MessageNanoPrinter.print(this);
+    }
+
+    /**
+     * Provides support for cloning. This only works if you specify the generate_clone method.
+     */
+    @Override
+    public MessageNano clone() throws CloneNotSupportedException {
+        return (MessageNano) super.clone();
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
new file mode 100644
index 0000000..d9500bb
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -0,0 +1,275 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+/**
+ * Static helper methods for printing nano protos.
+ *
+ * @author flynn@google.com Andrew Flynn
+ */
+public final class MessageNanoPrinter {
+    // Do not allow instantiation
+    private MessageNanoPrinter() {}
+
+    private static final String INDENT = "  ";
+    private static final int MAX_STRING_LEN = 200;
+
+    /**
+     * Returns an text representation of a MessageNano suitable for debugging. The returned string
+     * is mostly compatible with Protocol Buffer's TextFormat (as provided by non-nano protocol
+     * buffers) -- groups (which are deprecated) are output with an underscore name (e.g. foo_bar
+     * instead of FooBar) and will thus not parse.
+     *
+     * <p>Employs Java reflection on the given object and recursively prints primitive fields,
+     * groups, and messages.</p>
+     */
+    public static <T extends MessageNano> String print(T message) {
+        if (message == null) {
+            return "";
+        }
+
+        StringBuffer buf = new StringBuffer();
+        try {
+            print(null, message, new StringBuffer(), buf);
+        } catch (IllegalAccessException e) {
+            return "Error printing proto: " + e.getMessage();
+        } catch (InvocationTargetException e) {
+            return "Error printing proto: " + e.getMessage();
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Function that will print the given message/field into the StringBuffer.
+     * Meant to be called recursively.
+     *
+     * @param identifier the identifier to use, or {@code null} if this is the root message to
+     *        print.
+     * @param object the value to print. May in fact be a primitive value or byte array and not a
+     *        message.
+     * @param indentBuf the indentation each line should begin with.
+     * @param buf the output buffer.
+     */
+    private static void print(String identifier, Object object,
+            StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException,
+            InvocationTargetException {
+        if (object == null) {
+            // This can happen if...
+            //   - we're about to print a message, String, or byte[], but it not present;
+            //   - we're about to print a primitive, but "reftype" optional style is enabled, and
+            //     the field is unset.
+            // In both cases the appropriate behavior is to output nothing.
+        } else if (object instanceof MessageNano) {  // Nano proto message
+            int origIndentBufLength = indentBuf.length();
+            if (identifier != null) {
+                buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
+                indentBuf.append(INDENT);
+            }
+            Class<?> clazz = object.getClass();
+
+            // Proto fields follow one of two formats:
+            //
+            // 1) Public, non-static variables that do not begin or end with '_'
+            // Find and print these using declared public fields
+            for (Field field : clazz.getFields()) {
+                int modifiers = field.getModifiers();
+                String fieldName = field.getName();
+                if ("cachedSize".equals(fieldName)) {
+                    // TODO(bduff): perhaps cachedSize should have a more obscure name.
+                    continue;
+                }
+
+                if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
+                        && (modifiers & Modifier.STATIC) != Modifier.STATIC
+                        && !fieldName.startsWith("_")
+                        && !fieldName.endsWith("_")) {
+                    Class<?> fieldType = field.getType();
+                    Object value = field.get(object);
+
+                    if (fieldType.isArray()) {
+                        Class<?> arrayType = fieldType.getComponentType();
+
+                        // bytes is special since it's not repeated, but is represented by an array
+                        if (arrayType == byte.class) {
+                            print(fieldName, value, indentBuf, buf);
+                        } else {
+                            int len = value == null ? 0 : Array.getLength(value);
+                            for (int i = 0; i < len; i++) {
+                                Object elem = Array.get(value, i);
+                                print(fieldName, elem, indentBuf, buf);
+                            }
+                        }
+                    } else {
+                        print(fieldName, value, indentBuf, buf);
+                    }
+                }
+            }
+
+            // 2) Fields that are accessed via getter methods (when accessors
+            //    mode is turned on)
+            // Find and print these using getter methods.
+            for (Method method : clazz.getMethods()) {
+                String name = method.getName();
+                // Check for the setter accessor method since getters and hazzers both have
+                // non-proto-field name collisions (hashCode() and getSerializedSize())
+                if (name.startsWith("set")) {
+                    String subfieldName = name.substring(3);
+
+                    Method hazzer = null;
+                    try {
+                        hazzer = clazz.getMethod("has" + subfieldName);
+                    } catch (NoSuchMethodException e) {
+                        continue;
+                    }
+                    // If hazzer does't exist or returns false, no need to continue
+                    if (!(Boolean) hazzer.invoke(object)) {
+                        continue;
+                    }
+
+                    Method getter = null;
+                    try {
+                        getter = clazz.getMethod("get" + subfieldName);
+                    } catch (NoSuchMethodException e) {
+                        continue;
+                    }
+
+                    print(subfieldName, getter.invoke(object), indentBuf, buf);
+                }
+            }
+            if (identifier != null) {
+                indentBuf.setLength(origIndentBufLength);
+                buf.append(indentBuf).append(">\n");
+            }
+        } else if (object instanceof Map) {
+          Map<?,?> map = (Map<?,?>) object;
+          identifier = deCamelCaseify(identifier);
+
+          for (Map.Entry<?,?> entry : map.entrySet()) {
+            buf.append(indentBuf).append(identifier).append(" <\n");
+            int origIndentBufLength = indentBuf.length();
+            indentBuf.append(INDENT);
+            print("key", entry.getKey(), indentBuf, buf);
+            print("value", entry.getValue(), indentBuf, buf);
+            indentBuf.setLength(origIndentBufLength);
+            buf.append(indentBuf).append(">\n");
+          }
+        } else {
+            // Non-null primitive value
+            identifier = deCamelCaseify(identifier);
+            buf.append(indentBuf).append(identifier).append(": ");
+            if (object instanceof String) {
+                String stringMessage = sanitizeString((String) object);
+                buf.append("\"").append(stringMessage).append("\"");
+            } else if (object instanceof byte[]) {
+                appendQuotedBytes((byte[]) object, buf);
+            } else {
+                buf.append(object);
+            }
+            buf.append("\n");
+        }
+    }
+
+    /**
+     * Converts an identifier of the format "FieldName" into "field_name".
+     */
+    private static String deCamelCaseify(String identifier) {
+        StringBuffer out = new StringBuffer();
+        for (int i = 0; i < identifier.length(); i++) {
+            char currentChar = identifier.charAt(i);
+            if (i == 0) {
+                out.append(Character.toLowerCase(currentChar));
+            } else if (Character.isUpperCase(currentChar)) {
+                out.append('_').append(Character.toLowerCase(currentChar));
+            } else {
+                out.append(currentChar);
+            }
+        }
+        return out.toString();
+    }
+
+    /**
+     * Shortens and escapes the given string.
+     */
+    private static String sanitizeString(String str) {
+        if (!str.startsWith("http") && str.length() > MAX_STRING_LEN) {
+            // Trim non-URL strings.
+            str = str.substring(0, MAX_STRING_LEN) + "[...]";
+        }
+        return escapeString(str);
+    }
+
+    /**
+     * Escape everything except for low ASCII code points.
+     */
+    private static String escapeString(String str) {
+        int strLen = str.length();
+        StringBuilder b = new StringBuilder(strLen);
+        for (int i = 0; i < strLen; i++) {
+            char original = str.charAt(i);
+            if (original >= ' ' && original <= '~' && original != '"' && original != '\'') {
+                b.append(original);
+            } else {
+                b.append(String.format("\\u%04x", (int) original));
+            }
+        }
+        return b.toString();
+    }
+
+    /**
+     * Appends a quoted byte array to the provided {@code StringBuffer}.
+     */
+    private static void appendQuotedBytes(byte[] bytes, StringBuffer builder) {
+        if (bytes == null) {
+            builder.append("\"\"");
+            return;
+        }
+
+        builder.append('"');
+        for (int i = 0; i < bytes.length; ++i) {
+            int ch = bytes[i] & 0xff;
+            if (ch == '\\' || ch == '"') {
+                builder.append('\\').append((char) ch);
+            } else if (ch >= 32 && ch < 127) {
+                builder.append((char) ch);
+            } else {
+                builder.append(String.format("\\%03o", ch));
+            }
+        }
+        builder.append('"');
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
new file mode 100644
index 0000000..b1678d1
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -0,0 +1,88 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated
+ * API doesn't know about yet.
+ *
+ * @author bduff@google.com (Brian Duff)
+ */
+final class UnknownFieldData {
+
+    final int tag;
+    /**
+     * Important: this should be treated as immutable, even though it's possible
+     * to change the array values.
+     */
+    final byte[] bytes;
+
+    UnknownFieldData(int tag, byte[] bytes) {
+        this.tag = tag;
+        this.bytes = bytes;
+    }
+
+    int computeSerializedSize() {
+        int size = 0;
+        size += CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+        size += bytes.length;
+        return size;
+    }
+
+    void writeTo(CodedOutputByteBufferNano output) throws IOException {
+        output.writeRawVarint32(tag);
+        output.writeRawBytes(bytes);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof UnknownFieldData)) {
+            return false;
+        }
+
+        UnknownFieldData other = (UnknownFieldData) o;
+        return tag == other.tag && Arrays.equals(bytes, other.bytes);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + tag;
+        result = 31 * result + Arrays.hashCode(bytes);
+        return result;
+    }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
new file mode 100644
index 0000000..bbb6370
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
@@ -0,0 +1,124 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import java.io.IOException;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations.  It is public only because those generated messages
+ * do not reside in the {@code protobuf} package.  Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormatNano {
+  // Do not allow instantiation.
+  private WireFormatNano() {}
+
+  static final int WIRETYPE_VARINT           = 0;
+  static final int WIRETYPE_FIXED64          = 1;
+  static final int WIRETYPE_LENGTH_DELIMITED = 2;
+  static final int WIRETYPE_START_GROUP      = 3;
+  static final int WIRETYPE_END_GROUP        = 4;
+  static final int WIRETYPE_FIXED32          = 5;
+
+  static final int TAG_TYPE_BITS = 3;
+  static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+  /** Given a tag value, determines the wire type (the lower 3 bits). */
+  static int getTagWireType(final int tag) {
+    return tag & TAG_TYPE_MASK;
+  }
+
+  /** Given a tag value, determines the field number (the upper 29 bits). */
+  public static int getTagFieldNumber(final int tag) {
+    return tag >>> TAG_TYPE_BITS;
+  }
+
+  /** Makes a tag value given a field number and wire type. */
+  static int makeTag(final int fieldNumber, final int wireType) {
+    return (fieldNumber << TAG_TYPE_BITS) | wireType;
+  }
+
+  public static final int EMPTY_INT_ARRAY[] = {};
+  public static final long EMPTY_LONG_ARRAY[] = {};
+  public static final float EMPTY_FLOAT_ARRAY[] = {};
+  public static final double EMPTY_DOUBLE_ARRAY[] = {};
+  public static final boolean EMPTY_BOOLEAN_ARRAY[] = {};
+  public static final String EMPTY_STRING_ARRAY[] = {};
+  public static final byte[] EMPTY_BYTES_ARRAY[] = {};
+  public static final byte[] EMPTY_BYTES = {};
+
+  /**
+   * Parses an unknown field. This implementation skips the field.
+   *
+   * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+   * option is off.
+   *
+   * @return {@literal true} unless the tag is an end-group tag.
+   */
+  public static boolean parseUnknownField(
+      final CodedInputByteBufferNano input,
+      final int tag) throws IOException {
+    return input.skipField(tag);
+  }
+
+  /**
+   * Computes the array length of a repeated field. We assume that in the common case repeated
+   * fields are contiguously serialized but we still correctly handle interspersed values of a
+   * repeated field (but with extra allocations).
+   *
+   * Rewinds to current input position before returning.
+   *
+   * @param input stream input, pointing to the byte after the first tag
+   * @param tag repeated field tag just read
+   * @return length of array
+   * @throws IOException
+   */
+  public static final int getRepeatedFieldArrayLength(
+      final CodedInputByteBufferNano input,
+      final int tag) throws IOException {
+    int arrayLength = 1;
+    int startPos = input.getPosition();
+    input.skipField(tag);
+    while (input.readTag() == tag) {
+      input.skipField(tag);
+      arrayLength++;
+    }
+    input.rewindToPosition(startPos);
+    return arrayLength;
+  }
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
new file mode 100644
index 0000000..44544f4
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -0,0 +1,4555 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.
+
+package com.google.protobuf.nano;
+
+import com.google.protobuf.nano.MapTestProto.TestMap;
+import com.google.protobuf.nano.BytesOffsetLengthTestNanoOuterClass.BytesOffsetLengthTestNano;
+import com.google.protobuf.nano.CodedInputByteBufferNano;
+import com.google.protobuf.nano.CodedOutputByteBufferNano;
+import com.google.protobuf.nano.MapTestProto.TestMap.MessageValue;
+import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
+import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
+import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
+import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
+import com.google.protobuf.nano.NanoReferenceTypesCompat;
+import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
+import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
+import com.google.protobuf.nano.UnknownEnumValuesNanoOuterClass.StandardVersion;
+import com.google.protobuf.nano.UnknownEnumValuesNanoOuterClass.VersionWithoutVal3;
+import com.google.protobuf.nano.testext.nano.Extensions;
+import com.google.protobuf.nano.testext.nano.Extensions.AnotherMessage;
+import com.google.protobuf.nano.testext.nano.Extensions.MessageWithGroup;
+import com.google.protobuf.nano.testimport.nano.UnittestImportNano;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Test nano runtime.
+ *
+ * @author ulas@google.com Ulas Kirazci
+ */
+public class NanoTest extends TestCase {
+  @Override
+  public void setUp() throws Exception {
+  }
+
+  public void testSimpleMessageNano() throws Exception {
+    SimpleMessageNano msg = new SimpleMessageNano();
+    assertEquals(123, msg.d);
+    assertEquals(null, msg.nestedMsg);
+    assertEquals(SimpleMessageNano.BAZ, msg.defaultNestedEnum);
+
+    msg.d = 456;
+    assertEquals(456, msg.d);
+
+    SimpleMessageNano.NestedMessage nestedMsg = new SimpleMessageNano.NestedMessage();
+    nestedMsg.bb = 2;
+    assertEquals(2, nestedMsg.bb);
+    msg.nestedMsg = nestedMsg;
+    assertEquals(2, msg.nestedMsg.bb);
+
+    msg.defaultNestedEnum = SimpleMessageNano.BAR;
+    assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    SimpleMessageNano newMsg = SimpleMessageNano.parseFrom(result);
+    assertEquals(456, newMsg.d);
+    assertEquals(2, msg.nestedMsg.bb);
+    assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum);
+
+    msg.nestedMsg = null;
+    assertTrue(msgSerializedSize != msg.getSerializedSize());
+
+    msg.clear();
+    assertEquals(0, msg.getSerializedSize());
+  }
+
+  public void testRecursiveMessageNano() throws Exception {
+    RecursiveMessageNano msg = new RecursiveMessageNano();
+    assertTrue(msg.repeatedRecursiveMessageNano.length == 0);
+
+    RecursiveMessageNano msg1 = new RecursiveMessageNano();
+    msg1.id = 1;
+    assertEquals(1, msg1.id);
+    RecursiveMessageNano msg2 = new RecursiveMessageNano();
+    msg2.id = 2;
+    RecursiveMessageNano msg3 = new RecursiveMessageNano();
+    msg3.id = 3;
+
+    RecursiveMessageNano.NestedMessage nestedMsg = new RecursiveMessageNano.NestedMessage();
+    nestedMsg.a = msg1;
+    assertEquals(1, nestedMsg.a.id);
+
+    msg.id = 0;
+    msg.nestedMessage = nestedMsg;
+    msg.optionalRecursiveMessageNano = msg2;
+    msg.repeatedRecursiveMessageNano = new RecursiveMessageNano[] { msg3 };
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    RecursiveMessageNano newMsg = RecursiveMessageNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedRecursiveMessageNano.length);
+
+    assertEquals(0, newMsg.id);
+    assertEquals(1, newMsg.nestedMessage.a.id);
+    assertEquals(2, newMsg.optionalRecursiveMessageNano.id);
+    assertEquals(3, newMsg.repeatedRecursiveMessageNano[0].id);
+  }
+
+  public void testMessageNoFields() {
+    SingleMessageNano msg = new SingleMessageNano();
+    assertEquals(0, msg.getSerializedSize());
+    assertEquals(0, MessageNano.toByteArray(msg).length);
+  }
+
+  public void testNanoRequiredInt32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.id = 123;
+    assertEquals(123, msg.id);
+    msg.clear().id = 456;
+    assertEquals(456, msg.id);
+    msg.clear();
+
+    msg.id = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.id);
+  }
+
+  public void testNanoOptionalInt32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalInt32 = 123;
+    assertEquals(123, msg.optionalInt32);
+    msg.clear()
+       .optionalInt32 = 456;
+    assertEquals(456, msg.optionalInt32);
+    msg.clear();
+
+    msg.optionalInt32 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalInt32);
+  }
+
+  public void testNanoOptionalInt64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalInt64 = 123;
+    assertEquals(123, msg.optionalInt64);
+    msg.clear()
+       .optionalInt64 = 456;
+    assertEquals(456, msg.optionalInt64);
+    msg.clear();
+    assertEquals(0, msg.optionalInt64);
+
+    msg.optionalInt64 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalInt64);
+  }
+
+  public void testNanoOptionalUint32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalUint32 = 123;
+    assertEquals(123, msg.optionalUint32);
+    msg.clear()
+       .optionalUint32 = 456;
+    assertEquals(456, msg.optionalUint32);
+    msg.clear();
+    assertEquals(0, msg.optionalUint32);
+
+    msg.optionalUint32 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalUint32);
+  }
+
+  public void testNanoOptionalUint64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalUint64 = 123;
+    assertEquals(123, msg.optionalUint64);
+    msg.clear()
+       .optionalUint64 = 456;
+    assertEquals(456, msg.optionalUint64);
+    msg.clear();
+    assertEquals(0, msg.optionalUint64);
+
+    msg.optionalUint64 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalUint64);
+  }
+
+  public void testNanoOptionalSint32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalSint32 = 123;
+    assertEquals(123, msg.optionalSint32);
+    msg.clear()
+       .optionalSint32 = 456;
+    assertEquals(456, msg.optionalSint32);
+    msg.clear();
+    assertEquals(0, msg.optionalSint32);
+
+    msg.optionalSint32 = -123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(-123, newMsg.optionalSint32);
+  }
+
+  public void testNanoOptionalSint64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalSint64 = 123;
+    assertEquals(123, msg.optionalSint64);
+    msg.clear()
+       .optionalSint64 = 456;
+    assertEquals(456, msg.optionalSint64);
+    msg.clear();
+    assertEquals(0, msg.optionalSint64);
+
+    msg.optionalSint64 = -123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(-123, newMsg.optionalSint64);
+  }
+
+  public void testNanoOptionalFixed32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalFixed32 = 123;
+    assertEquals(123, msg.optionalFixed32);
+    msg.clear()
+       .optionalFixed32 = 456;
+    assertEquals(456, msg.optionalFixed32);
+    msg.clear();
+    assertEquals(0, msg.optionalFixed32);
+
+    msg.optionalFixed32 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalFixed32);
+  }
+
+  public void testNanoOptionalFixed64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalFixed64 = 123;
+    assertEquals(123, msg.optionalFixed64);
+    msg.clear()
+       .optionalFixed64 = 456;
+    assertEquals(456, msg.optionalFixed64);
+    msg.clear();
+    assertEquals(0, msg.optionalFixed64);
+
+    msg.optionalFixed64 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalFixed64);
+  }
+
+  public void testNanoOptionalSfixed32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalSfixed32 = 123;
+    assertEquals(123, msg.optionalSfixed32);
+    msg.clear()
+       .optionalSfixed32 = 456;
+    assertEquals(456, msg.optionalSfixed32);
+    msg.clear();
+    assertEquals(0, msg.optionalSfixed32);
+
+    msg.optionalSfixed32 = 123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(123, newMsg.optionalSfixed32);
+  }
+
+  public void testNanoOptionalSfixed64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalSfixed64 = 123;
+    assertEquals(123, msg.optionalSfixed64);
+    msg.clear()
+       .optionalSfixed64 = 456;
+    assertEquals(456, msg.optionalSfixed64);
+    msg.clear();
+    assertEquals(0, msg.optionalSfixed64);
+
+    msg.optionalSfixed64 = -123;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(-123, newMsg.optionalSfixed64);
+  }
+
+  public void testNanoOptionalFloat() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalFloat = 123f;
+    assertTrue(123.0f == msg.optionalFloat);
+    msg.clear()
+       .optionalFloat = 456.0f;
+    assertTrue(456.0f == msg.optionalFloat);
+    msg.clear();
+    assertTrue(0.0f == msg.optionalFloat);
+
+    msg.optionalFloat = -123.456f;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(-123.456f == newMsg.optionalFloat);
+  }
+
+  public void testNanoOptionalDouble() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalDouble = 123;
+    assertTrue(123.0 == msg.optionalDouble);
+    msg.clear()
+       .optionalDouble = 456.0;
+    assertTrue(456.0 == msg.optionalDouble);
+    msg.clear();
+    assertTrue(0.0 == msg.optionalDouble);
+
+    msg.optionalDouble = -123.456;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(-123.456 == newMsg.optionalDouble);
+  }
+
+  public void testNanoOptionalBool() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalBool = true;
+    assertTrue(msg.optionalBool);
+    msg.clear()
+       .optionalBool = true;
+    assertTrue(msg.optionalBool);
+    msg.clear();
+    assertFalse(msg.optionalBool);
+
+    msg.optionalBool = true;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalBool);
+  }
+
+  public void testNanoOptionalString() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalString = "hello";
+    assertEquals("hello", msg.optionalString);
+    msg.clear();
+    assertTrue(msg.optionalString.isEmpty());
+    msg.clear()
+       .optionalString = "hello2";
+    assertEquals("hello2", msg.optionalString);
+    msg.clear();
+    assertTrue(msg.optionalString.isEmpty());
+
+    msg.optionalString = "bye";
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalString != null);
+    assertEquals("bye", newMsg.optionalString);
+  }
+
+  public void testNanoOptionalBytes() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertFalse(msg.optionalBytes.length > 0);
+    msg.optionalBytes = InternalNano.copyFromUtf8("hello");
+    assertTrue(msg.optionalBytes.length > 0);
+    assertEquals("hello", new String(msg.optionalBytes, InternalNano.UTF_8));
+    msg.clear();
+    assertFalse(msg.optionalBytes.length > 0);
+    msg.clear()
+       .optionalBytes = InternalNano.copyFromUtf8("hello");
+    assertTrue(msg.optionalBytes.length > 0);
+    msg.clear();
+    assertFalse(msg.optionalBytes.length > 0);
+
+    msg.optionalBytes = InternalNano.copyFromUtf8("bye");
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalBytes.length > 0);
+    assertEquals("bye", new String(newMsg.optionalBytes, InternalNano.UTF_8));
+  }
+
+  public void testNanoOptionalGroup() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    TestAllTypesNano.OptionalGroup grp = new TestAllTypesNano.OptionalGroup();
+    grp.a = 1;
+    assertFalse(msg.optionalGroup != null);
+    msg.optionalGroup = grp;
+    assertTrue(msg.optionalGroup != null);
+    assertEquals(1, msg.optionalGroup.a);
+    msg.clear();
+    assertFalse(msg.optionalGroup != null);
+    msg.clear()
+       .optionalGroup = new TestAllTypesNano.OptionalGroup();
+    msg.optionalGroup.a = 2;
+    assertTrue(msg.optionalGroup != null);
+    msg.clear();
+    assertFalse(msg.optionalGroup != null);
+
+    msg.optionalGroup = grp;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalGroup != null);
+    assertEquals(1, newMsg.optionalGroup.a);
+  }
+
+  public void testNanoOptionalGroupWithUnknownFieldsEnabled() throws Exception {
+    MessageWithGroup msg = new MessageWithGroup();
+    MessageWithGroup.Group grp = new MessageWithGroup.Group();
+    grp.a = 1;
+    msg.group = grp;
+    byte [] serialized = MessageNano.toByteArray(msg);
+
+    MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
+    assertEquals(1, parsed.group.a);
+
+    byte [] serialized2 = MessageNano.toByteArray(parsed);
+    assertEquals(serialized.length, serialized2.length);
+    MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
+    assertEquals(1, parsed2.group.a);
+  }
+
+  public void testNanoOptionalNestedMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    TestAllTypesNano.NestedMessage nestedMsg = new TestAllTypesNano.NestedMessage();
+    nestedMsg.bb = 1;
+    assertFalse(msg.optionalNestedMessage != null);
+    msg.optionalNestedMessage = nestedMsg;
+    assertTrue(msg.optionalNestedMessage != null);
+    assertEquals(1, msg.optionalNestedMessage.bb);
+    msg.clear();
+    assertFalse(msg.optionalNestedMessage != null);
+    msg.clear()
+       .optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+    msg.optionalNestedMessage.bb = 2;
+    assertTrue(msg.optionalNestedMessage != null);
+    msg.clear();
+    assertFalse(msg.optionalNestedMessage != null);
+
+    msg.optionalNestedMessage = nestedMsg;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalNestedMessage != null);
+    assertEquals(1, newMsg.optionalNestedMessage.bb);
+  }
+
+  public void testNanoOptionalForeignMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    NanoOuterClass.ForeignMessageNano nestedMsg = new NanoOuterClass.ForeignMessageNano();
+    nestedMsg.c = 1;
+    assertFalse(msg.optionalForeignMessage != null);
+    msg.optionalForeignMessage = nestedMsg;
+    assertTrue(msg.optionalForeignMessage != null);
+    assertEquals(1, msg.optionalForeignMessage.c);
+    msg.clear();
+    assertFalse(msg.optionalForeignMessage != null);
+    msg.clear()
+       .optionalForeignMessage = new NanoOuterClass.ForeignMessageNano();
+    msg.optionalForeignMessage.c = 2;
+    assertTrue(msg.optionalForeignMessage != null);
+    msg.clear();
+    assertFalse(msg.optionalForeignMessage != null);
+
+    msg.optionalForeignMessage = nestedMsg;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalForeignMessage != null);
+    assertEquals(1, newMsg.optionalForeignMessage.c);
+  }
+
+  public void testNanoOptionalImportMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    UnittestImportNano.ImportMessageNano nestedMsg = new UnittestImportNano.ImportMessageNano();
+    nestedMsg.d = 1;
+    assertFalse(msg.optionalImportMessage != null);
+    msg.optionalImportMessage = nestedMsg;
+    assertTrue(msg.optionalImportMessage != null);
+    assertEquals(1, msg.optionalImportMessage.d);
+    msg.clear();
+    assertFalse(msg.optionalImportMessage != null);
+    msg.clear()
+       .optionalImportMessage = new UnittestImportNano.ImportMessageNano();
+    msg.optionalImportMessage.d = 2;
+    assertTrue(msg.optionalImportMessage != null);
+    msg.clear();
+    assertFalse(msg.optionalImportMessage != null);
+
+    msg.optionalImportMessage = nestedMsg;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalImportMessage != null);
+    assertEquals(1, newMsg.optionalImportMessage.d);
+  }
+
+  public void testNanoOptionalNestedEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalNestedEnum = TestAllTypesNano.BAR;
+    assertEquals(TestAllTypesNano.BAR, msg.optionalNestedEnum);
+    msg.clear()
+       .optionalNestedEnum = TestAllTypesNano.BAZ;
+    assertEquals(TestAllTypesNano.BAZ, msg.optionalNestedEnum);
+    msg.clear();
+    assertEquals(TestAllTypesNano.FOO, msg.optionalNestedEnum);
+
+    msg.optionalNestedEnum = TestAllTypesNano.BAR;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(TestAllTypesNano.BAR, newMsg.optionalNestedEnum);
+  }
+
+  public void testNanoOptionalForeignEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.optionalForeignEnum);
+    msg.clear()
+       .optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAZ;
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.optionalForeignEnum);
+    msg.clear();
+    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.optionalForeignEnum);
+
+    msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, newMsg.optionalForeignEnum);
+  }
+
+  public void testNanoOptionalImportEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.optionalImportEnum);
+    msg.clear()
+       .optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAZ;
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.optionalImportEnum);
+    msg.clear();
+    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.optionalImportEnum);
+
+    msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR;
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, newMsg.optionalImportEnum);
+  }
+
+  public void testNanoOptionalStringPiece() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalStringPiece = "hello";
+    assertEquals("hello", msg.optionalStringPiece);
+    msg.clear();
+    assertTrue(msg.optionalStringPiece.isEmpty());
+    msg.clear()
+       .optionalStringPiece = "hello2";
+    assertEquals("hello2", msg.optionalStringPiece);
+    msg.clear();
+    assertTrue(msg.optionalStringPiece.isEmpty());
+
+    msg.optionalStringPiece = "bye";
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalStringPiece != null);
+    assertEquals("bye", newMsg.optionalStringPiece);
+  }
+
+  public void testNanoOptionalCord() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalCord = "hello";
+    assertEquals("hello", msg.optionalCord);
+    msg.clear();
+    assertTrue(msg.optionalCord.isEmpty());
+    msg.clear()
+       .optionalCord = "hello2";
+    assertEquals("hello2", msg.optionalCord);
+    msg.clear();
+    assertTrue(msg.optionalCord.isEmpty());
+
+    msg.optionalCord = "bye";
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertTrue(newMsg.optionalCord != null);
+    assertEquals("bye", newMsg.optionalCord);
+  }
+
+  public void testNanoRepeatedInt32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedInt32.length);
+    msg.repeatedInt32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedInt32[1]);
+    assertEquals(456, msg.repeatedInt32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedInt32.length);
+    msg.clear()
+       .repeatedInt32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedInt32.length);
+    assertEquals(456, msg.repeatedInt32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedInt32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedInt32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedInt32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedInt32.length);
+    assertEquals(123, newMsg.repeatedInt32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedInt32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedInt32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedInt32.length);
+    assertEquals(123, newMsg.repeatedInt32[0]);
+    assertEquals(456, newMsg.repeatedInt32[1]);
+  }
+
+  public void testNanoRepeatedInt64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedInt64.length);
+    msg.repeatedInt64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedInt64[1]);
+    assertEquals(456, msg.repeatedInt64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedInt64.length);
+    msg.clear()
+       .repeatedInt64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedInt64.length);
+    assertEquals(456, msg.repeatedInt64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedInt64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedInt64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedInt64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedInt64.length);
+    assertEquals(123, newMsg.repeatedInt64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedInt64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedInt64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedInt64.length);
+    assertEquals(123, newMsg.repeatedInt64[0]);
+    assertEquals(456, newMsg.repeatedInt64[1]);
+  }
+
+  public void testNanoRepeatedUint32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedUint32.length);
+    msg.repeatedUint32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedUint32[1]);
+    assertEquals(456, msg.repeatedUint32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedUint32.length);
+    msg.clear()
+       .repeatedUint32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedUint32.length);
+    assertEquals(456, msg.repeatedUint32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedUint32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedUint32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedUint32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedUint32.length);
+    assertEquals(123, newMsg.repeatedUint32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedUint32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedUint32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedUint32.length);
+    assertEquals(123, newMsg.repeatedUint32[0]);
+    assertEquals(456, newMsg.repeatedUint32[1]);
+  }
+
+  public void testNanoRepeatedUint64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedUint64.length);
+    msg.repeatedUint64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedUint64[1]);
+    assertEquals(456, msg.repeatedUint64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedUint64.length);
+    msg.clear()
+       .repeatedUint64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedUint64.length);
+    assertEquals(456, msg.repeatedUint64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedUint64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedUint64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedUint64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedUint64.length);
+    assertEquals(123, newMsg.repeatedUint64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedUint64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedUint64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedUint64.length);
+    assertEquals(123, newMsg.repeatedUint64[0]);
+    assertEquals(456, newMsg.repeatedUint64[1]);
+  }
+
+  public void testNanoRepeatedSint32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedSint32.length);
+    msg.repeatedSint32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedSint32[1]);
+    assertEquals(456, msg.repeatedSint32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSint32.length);
+    msg.clear()
+       .repeatedSint32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedSint32.length);
+    assertEquals(456, msg.repeatedSint32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSint32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedSint32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedSint32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedSint32.length);
+    assertEquals(123, newMsg.repeatedSint32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedSint32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedSint32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedSint32.length);
+    assertEquals(123, newMsg.repeatedSint32[0]);
+    assertEquals(456, newMsg.repeatedSint32[1]);
+  }
+
+  public void testNanoRepeatedSint64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedSint64.length);
+    msg.repeatedSint64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedSint64[1]);
+    assertEquals(456, msg.repeatedSint64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSint64.length);
+    msg.clear()
+       .repeatedSint64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedSint64.length);
+    assertEquals(456, msg.repeatedSint64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSint64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedSint64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedSint64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedSint64.length);
+    assertEquals(123, newMsg.repeatedSint64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedSint64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedSint64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedSint64.length);
+    assertEquals(123, newMsg.repeatedSint64[0]);
+    assertEquals(456, newMsg.repeatedSint64[1]);
+  }
+
+  public void testNanoRepeatedFixed32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedFixed32.length);
+    msg.repeatedFixed32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedFixed32[1]);
+    assertEquals(456, msg.repeatedFixed32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFixed32.length);
+    msg.clear()
+       .repeatedFixed32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedFixed32.length);
+    assertEquals(456, msg.repeatedFixed32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFixed32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedFixed32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedFixed32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedFixed32.length);
+    assertEquals(123, newMsg.repeatedFixed32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedFixed32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedFixed32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 15);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedFixed32.length);
+    assertEquals(123, newMsg.repeatedFixed32[0]);
+    assertEquals(456, newMsg.repeatedFixed32[1]);
+  }
+
+  public void testNanoRepeatedFixed64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedFixed64.length);
+    msg.repeatedFixed64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedFixed64[1]);
+    assertEquals(456, msg.repeatedFixed64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFixed64.length);
+    msg.clear()
+       .repeatedFixed64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedFixed64.length);
+    assertEquals(456, msg.repeatedFixed64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFixed64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedFixed64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedFixed64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 13);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedFixed64.length);
+    assertEquals(123, newMsg.repeatedFixed64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedFixed64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedFixed64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 23);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedFixed64.length);
+    assertEquals(123, newMsg.repeatedFixed64[0]);
+    assertEquals(456, newMsg.repeatedFixed64[1]);
+  }
+
+  public void testNanoRepeatedSfixed32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedSfixed32.length);
+    msg.repeatedSfixed32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedSfixed32[1]);
+    assertEquals(456, msg.repeatedSfixed32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSfixed32.length);
+    msg.clear()
+       .repeatedSfixed32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedSfixed32.length);
+    assertEquals(456, msg.repeatedSfixed32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSfixed32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedSfixed32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedSfixed32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedSfixed32.length);
+    assertEquals(123, newMsg.repeatedSfixed32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedSfixed32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedSfixed32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 15);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedSfixed32.length);
+    assertEquals(123, newMsg.repeatedSfixed32[0]);
+    assertEquals(456, newMsg.repeatedSfixed32[1]);
+  }
+
+  public void testNanoRepeatedSfixed64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedSfixed64.length);
+    msg.repeatedSfixed64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedSfixed64[1]);
+    assertEquals(456, msg.repeatedSfixed64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSfixed64.length);
+    msg.clear()
+       .repeatedSfixed64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedSfixed64.length);
+    assertEquals(456, msg.repeatedSfixed64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedSfixed64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedSfixed64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedSfixed64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 13);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedSfixed64.length);
+    assertEquals(123, newMsg.repeatedSfixed64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedSfixed64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedSfixed64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 23);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedSfixed64.length);
+    assertEquals(123, newMsg.repeatedSfixed64[0]);
+    assertEquals(456, newMsg.repeatedSfixed64[1]);
+  }
+
+  public void testNanoRepeatedFloat() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedFloat.length);
+    msg.repeatedFloat = new float[] { 123f, 789f, 456f };
+    assertEquals(789f, msg.repeatedFloat[1]);
+    assertEquals(456f, msg.repeatedFloat[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFloat.length);
+    msg.clear()
+       .repeatedFloat = new float[] { 456f };
+    assertEquals(1, msg.repeatedFloat.length);
+    assertEquals(456f, msg.repeatedFloat[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedFloat.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedFloat = new float[] { 123f };
+    assertEquals(1, msg.repeatedFloat.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedFloat.length);
+    assertEquals(123f, newMsg.repeatedFloat[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedFloat = new float[] { 123f, 456f };
+    assertEquals(2, msg.repeatedFloat.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 15);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedFloat.length);
+    assertEquals(123f, newMsg.repeatedFloat[0]);
+    assertEquals(456f, newMsg.repeatedFloat[1]);
+  }
+
+  public void testNanoRepeatedDouble() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedDouble.length);
+    msg.repeatedDouble = new double[] { 123.0, 789.0, 456.0 };
+    assertEquals(789.0, msg.repeatedDouble[1]);
+    assertEquals(456.0, msg.repeatedDouble[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedDouble.length);
+    msg.clear()
+       .repeatedDouble = new double[] { 456.0 };
+    assertEquals(1, msg.repeatedDouble.length);
+    assertEquals(456.0, msg.repeatedDouble[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedDouble.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedDouble = new double[] { 123.0 };
+    assertEquals(1, msg.repeatedDouble.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 13);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedDouble.length);
+    assertEquals(123.0, newMsg.repeatedDouble[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedDouble = new double[] { 123.0, 456.0 };
+    assertEquals(2, msg.repeatedDouble.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 23);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedDouble.length);
+    assertEquals(123.0, newMsg.repeatedDouble[0]);
+    assertEquals(456.0, newMsg.repeatedDouble[1]);
+  }
+
+  public void testNanoRepeatedBool() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedBool.length);
+    msg.repeatedBool = new boolean[] { false, true, false };
+    assertTrue(msg.repeatedBool[1]);
+    assertFalse(msg.repeatedBool[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedBool.length);
+    msg.clear()
+       .repeatedBool = new boolean[] { true };
+    assertEquals(1, msg.repeatedBool.length);
+    assertTrue(msg.repeatedBool[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedBool.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedBool = new boolean[] { false };
+    assertEquals(1, msg.repeatedBool.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedBool.length);
+    assertFalse(newMsg.repeatedBool[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedBool = new boolean[] { true, false };
+    assertEquals(2, msg.repeatedBool.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedBool.length);
+    assertTrue(newMsg.repeatedBool[0]);
+    assertFalse(newMsg.repeatedBool[1]);
+  }
+
+  public void testNanoRepeatedString() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedString.length);
+    msg.repeatedString = new String[] { "hello", "bye", "boo" };
+    assertEquals("bye", msg.repeatedString[1]);
+    assertEquals("boo", msg.repeatedString[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedString.length);
+    msg.clear()
+       .repeatedString = new String[] { "boo" };
+    assertEquals(1, msg.repeatedString.length);
+    assertEquals("boo", msg.repeatedString[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedString.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedString = new String[] { "" };
+    assertEquals(1, msg.repeatedString.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedString.length);
+    assertTrue(newMsg.repeatedString[0].isEmpty());
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedString = new String[] { "hello", "world" };
+    assertEquals(2, msg.repeatedString.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 19);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedString.length);
+    assertEquals("hello", newMsg.repeatedString[0]);
+    assertEquals("world", newMsg.repeatedString[1]);
+  }
+
+  public void testNanoRepeatedBytes() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedBytes.length);
+    msg.repeatedBytes = new byte[][] {
+        InternalNano.copyFromUtf8("hello"),
+        InternalNano.copyFromUtf8("bye"),
+        InternalNano.copyFromUtf8("boo")
+    };
+    assertEquals("bye", new String(msg.repeatedBytes[1], InternalNano.UTF_8));
+    assertEquals("boo", new String(msg.repeatedBytes[2], InternalNano.UTF_8));
+    msg.clear();
+    assertEquals(0, msg.repeatedBytes.length);
+    msg.clear()
+       .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("boo") };
+    assertEquals(1, msg.repeatedBytes.length);
+    assertEquals("boo", new String(msg.repeatedBytes[0], InternalNano.UTF_8));
+    msg.clear();
+    assertEquals(0, msg.repeatedBytes.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("") };
+    assertEquals(1, msg.repeatedBytes.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedBytes.length);
+    assertTrue(newMsg.repeatedBytes[0].length == 0);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedBytes = new byte[][] {
+      InternalNano.copyFromUtf8("hello"),
+      InternalNano.copyFromUtf8("world")
+    };
+    assertEquals(2, msg.repeatedBytes.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 19);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedBytes.length);
+    assertEquals("hello", new String(newMsg.repeatedBytes[0], InternalNano.UTF_8));
+    assertEquals("world", new String(newMsg.repeatedBytes[1], InternalNano.UTF_8));
+  }
+
+  public void testNanoRepeatedGroup() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    TestAllTypesNano.RepeatedGroup group0 =
+      new TestAllTypesNano.RepeatedGroup();
+    group0.a = 0;
+    TestAllTypesNano.RepeatedGroup group1 =
+      new TestAllTypesNano.RepeatedGroup();
+    group1.a = 1;
+    TestAllTypesNano.RepeatedGroup group2 =
+      new TestAllTypesNano.RepeatedGroup();
+    group2.a = 2;
+
+    msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1, group2 };
+    assertEquals(3, msg.repeatedGroup.length);
+    assertEquals(0, msg.repeatedGroup[0].a);
+    assertEquals(1, msg.repeatedGroup[1].a);
+    assertEquals(2, msg.repeatedGroup[2].a);
+    msg.clear();
+    assertEquals(0, msg.repeatedGroup.length);
+    msg.clear()
+       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group1 };
+    assertEquals(1, msg.repeatedGroup.length);
+    assertEquals(1, msg.repeatedGroup[0].a);
+    msg.clear();
+    assertEquals(0, msg.repeatedGroup.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0 };
+    assertEquals(1, msg.repeatedGroup.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedGroup.length);
+    assertEquals(0, newMsg.repeatedGroup[0].a);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1 };
+    assertEquals(2, msg.repeatedGroup.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 14);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedGroup.length);
+    assertEquals(0, newMsg.repeatedGroup[0].a);
+    assertEquals(1, newMsg.repeatedGroup[1].a);
+  }
+
+  public void testNanoRepeatedNestedMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    TestAllTypesNano.NestedMessage nestedMsg0 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg0.bb = 0;
+    TestAllTypesNano.NestedMessage nestedMsg1 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg1.bb = 1;
+    TestAllTypesNano.NestedMessage nestedMsg2 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg2.bb = 2;
+
+    msg.repeatedNestedMessage =
+        new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1, nestedMsg2 };
+    assertEquals(3, msg.repeatedNestedMessage.length);
+    assertEquals(0, msg.repeatedNestedMessage[0].bb);
+    assertEquals(1, msg.repeatedNestedMessage[1].bb);
+    assertEquals(2, msg.repeatedNestedMessage[2].bb);
+    msg.clear();
+    assertEquals(0, msg.repeatedNestedMessage.length);
+    msg.clear()
+       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg1 };
+    assertEquals(1, msg.repeatedNestedMessage.length);
+    assertEquals(1, msg.repeatedNestedMessage[0].bb);
+    msg.clear();
+    assertEquals(0, msg.repeatedNestedMessage.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
+    assertEquals(1, msg.repeatedNestedMessage.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedNestedMessage.length);
+    assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1 };
+    assertEquals(2, msg.repeatedNestedMessage.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedNestedMessage.length);
+    assertEquals(0, newMsg.repeatedNestedMessage[0].bb);
+    assertEquals(1, newMsg.repeatedNestedMessage[1].bb);
+  }
+
+  public void testNanoRepeatedForeignMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    NanoOuterClass.ForeignMessageNano foreignMsg0 =
+      new NanoOuterClass.ForeignMessageNano();
+    foreignMsg0.c = 0;
+    NanoOuterClass.ForeignMessageNano foreignMsg1 =
+      new NanoOuterClass.ForeignMessageNano();
+    foreignMsg1.c = 1;
+    NanoOuterClass.ForeignMessageNano foreignMsg2 =
+      new NanoOuterClass.ForeignMessageNano();
+    foreignMsg2.c = 2;
+
+    msg.repeatedForeignMessage =
+        new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
+    assertEquals(3, msg.repeatedForeignMessage.length);
+    assertEquals(0, msg.repeatedForeignMessage[0].c);
+    assertEquals(1, msg.repeatedForeignMessage[1].c);
+    assertEquals(2, msg.repeatedForeignMessage[2].c);
+    msg.clear();
+    assertEquals(0, msg.repeatedForeignMessage.length);
+    msg.clear()
+       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg1 };
+    assertEquals(1, msg.repeatedForeignMessage.length);
+    assertEquals(1, msg.repeatedForeignMessage[0].c);
+    msg.clear();
+    assertEquals(0, msg.repeatedForeignMessage.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0 };
+    assertEquals(1, msg.repeatedForeignMessage.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedForeignMessage.length);
+    assertEquals(0, newMsg.repeatedForeignMessage[0].c);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1 };
+    assertEquals(2, msg.repeatedForeignMessage.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedForeignMessage.length);
+    assertEquals(0, newMsg.repeatedForeignMessage[0].c);
+    assertEquals(1, newMsg.repeatedForeignMessage[1].c);
+  }
+
+  public void testNanoRepeatedImportMessage() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    UnittestImportNano.ImportMessageNano foreignMsg0 =
+      new UnittestImportNano.ImportMessageNano();
+    foreignMsg0.d = 0;
+    UnittestImportNano.ImportMessageNano foreignMsg1 =
+      new UnittestImportNano.ImportMessageNano();
+    foreignMsg1.d = 1;
+    UnittestImportNano.ImportMessageNano foreignMsg2 =
+      new UnittestImportNano.ImportMessageNano();
+    foreignMsg2.d = 2;
+
+    msg.repeatedImportMessage =
+        new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 };
+    assertEquals(3, msg.repeatedImportMessage.length);
+    assertEquals(0, msg.repeatedImportMessage[0].d);
+    assertEquals(1, msg.repeatedImportMessage[1].d);
+    assertEquals(2, msg.repeatedImportMessage[2].d);
+    msg.clear();
+    assertEquals(0, msg.repeatedImportMessage.length);
+    msg.clear()
+       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg1 };
+    assertEquals(1, msg.repeatedImportMessage.length);
+    assertEquals(1, msg.repeatedImportMessage[0].d);
+    msg.clear();
+    assertEquals(0, msg.repeatedImportMessage.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0 };
+    assertEquals(1, msg.repeatedImportMessage.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedImportMessage.length);
+    assertEquals(0, newMsg.repeatedImportMessage[0].d);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1 };
+    assertEquals(2, msg.repeatedImportMessage.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedImportMessage.length);
+    assertEquals(0, newMsg.repeatedImportMessage[0].d);
+    assertEquals(1, newMsg.repeatedImportMessage[1].d);
+  }
+
+  public void testNanoRepeatedNestedEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedNestedEnum = new int[] {
+        TestAllTypesNano.FOO,
+        TestAllTypesNano.BAR,
+        TestAllTypesNano.BAZ
+    };
+    assertEquals(3, msg.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
+    assertEquals(TestAllTypesNano.BAZ, msg.repeatedNestedEnum[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedNestedEnum.length);
+    msg.clear()
+       .repeatedNestedEnum = new int[] { TestAllTypesNano.BAR };
+    assertEquals(1, msg.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedNestedEnum.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
+    assertEquals(2, msg.repeatedNestedEnum.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]);
+  }
+
+  public void testNanoRepeatedForeignEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedForeignEnum = new int[] {
+        NanoOuterClass.FOREIGN_NANO_FOO,
+        NanoOuterClass.FOREIGN_NANO_BAR,
+        NanoOuterClass.FOREIGN_NANO_BAZ
+    };
+    assertEquals(3, msg.repeatedForeignEnum.length);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.repeatedForeignEnum[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedForeignEnum.length);
+    msg.clear()
+       .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_BAR };
+    assertEquals(1, msg.repeatedForeignEnum.length);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedForeignEnum.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_FOO };
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedForeignEnum.length);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedForeignEnum = new int[] {
+      NanoOuterClass.FOREIGN_NANO_FOO,
+      NanoOuterClass.FOREIGN_NANO_BAR
+    };
+    assertEquals(2, msg.repeatedForeignEnum.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedForeignEnum.length);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]);
+    assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]);
+  }
+
+  public void testNanoRepeatedImportEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedImportEnum = new int[] {
+        UnittestImportNano.IMPORT_NANO_FOO,
+        UnittestImportNano.IMPORT_NANO_BAR,
+        UnittestImportNano.IMPORT_NANO_BAZ
+    };
+    assertEquals(3, msg.repeatedImportEnum.length);
+    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.repeatedImportEnum[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedImportEnum.length);
+    msg.clear()
+       .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_BAR };
+    assertEquals(1, msg.repeatedImportEnum.length);
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedImportEnum.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_FOO };
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedImportEnum.length);
+    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedImportEnum = new int[] {
+      UnittestImportNano.IMPORT_NANO_FOO,
+      UnittestImportNano.IMPORT_NANO_BAR
+    };
+    assertEquals(2, msg.repeatedImportEnum.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedImportEnum.length);
+    assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]);
+    assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]);
+  }
+
+  public void testNanoRepeatedStringPiece() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedStringPiece.length);
+    msg.repeatedStringPiece = new String[] { "hello", "bye", "boo" };
+    assertEquals("bye", msg.repeatedStringPiece[1]);
+    assertEquals("boo", msg.repeatedStringPiece[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedStringPiece.length);
+    msg.clear()
+       .repeatedStringPiece = new String[] { "boo" };
+    assertEquals(1, msg.repeatedStringPiece.length);
+    assertEquals("boo", msg.repeatedStringPiece[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedStringPiece.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedStringPiece = new String[] { "" };
+    assertEquals(1, msg.repeatedStringPiece.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedStringPiece.length);
+    assertTrue(newMsg.repeatedStringPiece[0].isEmpty());
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedStringPiece = new String[] { "hello", "world" };
+    assertEquals(2, msg.repeatedStringPiece.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 19);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedStringPiece.length);
+    assertEquals("hello", newMsg.repeatedStringPiece[0]);
+    assertEquals("world", newMsg.repeatedStringPiece[1]);
+  }
+
+  public void testNanoRepeatedCord() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedCord.length);
+    msg.repeatedCord = new String[] { "hello", "bye", "boo" };
+    assertEquals("bye", msg.repeatedCord[1]);
+    assertEquals("boo", msg.repeatedCord[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedCord.length);
+    msg.clear()
+       .repeatedCord = new String[] { "boo" };
+    assertEquals(1, msg.repeatedCord.length);
+    assertEquals("boo", msg.repeatedCord[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedCord.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedCord = new String[] { "" };
+    assertEquals(1, msg.repeatedCord.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedCord.length);
+    assertTrue(newMsg.repeatedCord[0].isEmpty());
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedCord = new String[] { "hello", "world" };
+    assertEquals(2, msg.repeatedCord.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 19);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedCord.length);
+    assertEquals("hello", newMsg.repeatedCord[0]);
+    assertEquals("world", newMsg.repeatedCord[1]);
+  }
+
+  public void testNanoRepeatedPackedInt32() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedPackedInt32.length);
+    msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedPackedInt32[1]);
+    assertEquals(456, msg.repeatedPackedInt32[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedInt32.length);
+    msg.clear()
+       .repeatedPackedInt32 = new int[] { 456 };
+    assertEquals(1, msg.repeatedPackedInt32.length);
+    assertEquals(456, msg.repeatedPackedInt32[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedInt32.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedPackedInt32 = new int[] { 123 };
+    assertEquals(1, msg.repeatedPackedInt32.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedPackedInt32.length);
+    assertEquals(123, newMsg.repeatedPackedInt32[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedPackedInt32 = new int[] { 123, 456 };
+    assertEquals(2, msg.repeatedPackedInt32.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedPackedInt32.length);
+    assertEquals(123, newMsg.repeatedPackedInt32[0]);
+    assertEquals(456, newMsg.repeatedPackedInt32[1]);
+  }
+
+  public void testNanoRepeatedPackedSfixed64() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    assertEquals(0, msg.repeatedPackedSfixed64.length);
+    msg.repeatedPackedSfixed64 = new long[] { 123, 789, 456 };
+    assertEquals(789, msg.repeatedPackedSfixed64[1]);
+    assertEquals(456, msg.repeatedPackedSfixed64[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedSfixed64.length);
+    msg.clear()
+       .repeatedPackedSfixed64 = new long[] { 456 };
+    assertEquals(1, msg.repeatedPackedSfixed64.length);
+    assertEquals(456, msg.repeatedPackedSfixed64[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedSfixed64.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedPackedSfixed64 = new long[] { 123 };
+    assertEquals(1, msg.repeatedPackedSfixed64.length);
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 14);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedPackedSfixed64.length);
+    assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedPackedSfixed64 = new long[] { 123, 456 };
+    assertEquals(2, msg.repeatedPackedSfixed64.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 22);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedPackedSfixed64.length);
+    assertEquals(123, newMsg.repeatedPackedSfixed64[0]);
+    assertEquals(456, newMsg.repeatedPackedSfixed64[1]);
+  }
+
+  public void testNanoRepeatedPackedNestedEnum() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedPackedNestedEnum = new int[] {
+        TestAllTypesNano.FOO,
+        TestAllTypesNano.BAR,
+        TestAllTypesNano.BAZ
+    };
+    assertEquals(3, msg.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
+    assertEquals(TestAllTypesNano.BAZ, msg.repeatedPackedNestedEnum[2]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedNestedEnum.length);
+    msg.clear()
+       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.BAR };
+    assertEquals(1, msg.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[0]);
+    msg.clear();
+    assertEquals(0, msg.repeatedPackedNestedEnum.length);
+
+    // Test 1 entry
+    msg.clear()
+       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO };
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(1, newMsg.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+
+    // Test 2 entries
+    msg.clear()
+       .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR };
+    assertEquals(2, msg.repeatedPackedNestedEnum.length);
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(2, newMsg.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]);
+  }
+
+  public void testNanoRepeatedPackedSerializedSize() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+    int msgSerializedSize = msg.getSerializedSize();
+    byte [] result = MessageNano.toByteArray(msg);
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 11);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesNano msg2 = new TestAllTypesNano();
+    msg2.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+    byte [] result2 = new byte[msgSerializedSize];
+    MessageNano.toByteArray(msg2, result2, 0, msgSerializedSize);
+
+    // Check equal size and content.
+    assertEquals(msgSerializedSize, msg2.getSerializedSize());
+    assertTrue(Arrays.equals(result, result2));
+  }
+
+  public void testNanoRepeatedInt32ReMerge() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedInt32 = new int[] { 234 };
+    byte [] result1 = MessageNano.toByteArray(msg);
+
+    msg.clear().optionalInt32 = 789;
+    byte [] result2 = MessageNano.toByteArray(msg);
+
+    msg.clear().repeatedInt32 = new int[] { 123, 456 };
+    byte [] result3 = MessageNano.toByteArray(msg);
+
+    // Concatenate the three serializations and read as one message.
+    byte [] result = new byte[result1.length + result2.length + result3.length];
+    System.arraycopy(result1, 0, result, 0, result1.length);
+    System.arraycopy(result2, 0, result, result1.length, result2.length);
+    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(789, newMsg.optionalInt32);
+    assertEquals(3, newMsg.repeatedInt32.length);
+    assertEquals(234, newMsg.repeatedInt32[0]);
+    assertEquals(123, newMsg.repeatedInt32[1]);
+    assertEquals(456, newMsg.repeatedInt32[2]);
+  }
+
+  public void testNanoRepeatedNestedEnumReMerge() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+    byte [] result1 = MessageNano.toByteArray(msg);
+
+    msg.clear().optionalInt32 = 789;
+    byte [] result2 = MessageNano.toByteArray(msg);
+
+    msg.clear().repeatedNestedEnum = new int[] { TestAllTypesNano.BAR, TestAllTypesNano.FOO };
+    byte [] result3 = MessageNano.toByteArray(msg);
+
+    // Concatenate the three serializations and read as one message.
+    byte [] result = new byte[result1.length + result2.length + result3.length];
+    System.arraycopy(result1, 0, result, 0, result1.length);
+    System.arraycopy(result2, 0, result, result1.length, result2.length);
+    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(789, newMsg.optionalInt32);
+    assertEquals(3, newMsg.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.BAR, newMsg.repeatedNestedEnum[1]);
+    assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[2]);
+  }
+
+  public void testNanoRepeatedNestedMessageReMerge() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    TestAllTypesNano.NestedMessage nestedMsg0 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg0.bb = 0;
+    TestAllTypesNano.NestedMessage nestedMsg1 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg1.bb = 1;
+    TestAllTypesNano.NestedMessage nestedMsg2 =
+      new TestAllTypesNano.NestedMessage();
+    nestedMsg2.bb = 2;
+
+    msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 };
+    byte [] result1 = MessageNano.toByteArray(msg);
+
+    msg.clear().optionalInt32 = 789;
+    byte [] result2 = MessageNano.toByteArray(msg);
+
+    msg.clear().repeatedNestedMessage =
+        new TestAllTypesNano.NestedMessage[] { nestedMsg1, nestedMsg2 };
+    byte [] result3 = MessageNano.toByteArray(msg);
+
+    // Concatenate the three serializations and read as one message.
+    byte [] result = new byte[result1.length + result2.length + result3.length];
+    System.arraycopy(result1, 0, result, 0, result1.length);
+    System.arraycopy(result2, 0, result, result1.length, result2.length);
+    System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length);
+
+    TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result);
+    assertEquals(789, newMsg.optionalInt32);
+    assertEquals(3, newMsg.repeatedNestedMessage.length);
+    assertEquals(nestedMsg0.bb, newMsg.repeatedNestedMessage[0].bb);
+    assertEquals(nestedMsg1.bb, newMsg.repeatedNestedMessage[1].bb);
+    assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb);
+  }
+
+  /**
+   * Tests that invalid enum values from the wire are not accepted.
+   */
+  public void testNanoEnumValidity() throws Exception {
+    final int invalid = 120;
+    final int alsoInvalid = 121;
+
+    EnumValidity.M m = new EnumValidity.M();
+    // Sanity check & baseline of the assertions for the first case below.
+    assertEquals(EnumValidity.E.default_, m.optionalE);
+    assertEquals(EnumValidity.E.BAZ, m.defaultE);
+
+    m.optionalE = invalid;
+    m.defaultE = invalid;
+    // E contains all valid values
+    m.repeatedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR};
+    m.packedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ};
+    // E2 contains some invalid values
+    m.repeatedE2 = new int[] {invalid, EnumValidity.E.BAR, alsoInvalid};
+    m.packedE2 = new int[] {EnumValidity.E.FOO, invalid, alsoInvalid};
+    // E3 contains all invalid values
+    m.repeatedE3 = new int[] {invalid, invalid};
+    m.packedE3 = new int[] {alsoInvalid, alsoInvalid};
+    byte[] serialized = MessageNano.toByteArray(m);
+    // Sanity check that we do have all data in the byte array.
+    assertEquals(31, serialized.length);
+
+    // Test 1: tests that invalid values aren't included in the deserialized message.
+    EnumValidity.M deserialized = MessageNano.mergeFrom(new EnumValidity.M(), serialized);
+    assertEquals(EnumValidity.E.default_, deserialized.optionalE);
+    assertEquals(EnumValidity.E.BAZ, deserialized.defaultE);
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR}, deserialized.repeatedE));
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ}, deserialized.packedE));
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.BAR}, deserialized.repeatedE2));
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.FOO}, deserialized.packedE2));
+    assertEquals(0, deserialized.repeatedE3.length);
+    assertEquals(0, deserialized.packedE3.length);
+
+    // Test 2: tests that invalid values do not override previous values in the field, including
+    // arrays, including pre-existing invalid values.
+    deserialized.optionalE = EnumValidity.E.BAR;
+    deserialized.defaultE = alsoInvalid;
+    deserialized.repeatedE = new int[] {EnumValidity.E.BAZ};
+    deserialized.packedE = new int[] {EnumValidity.E.BAZ, alsoInvalid};
+    deserialized.repeatedE2 = new int[] {invalid, alsoInvalid};
+    deserialized.packedE2 = null;
+    deserialized.repeatedE3 = null;
+    deserialized.packedE3 = new int[0];
+    MessageNano.mergeFrom(deserialized, serialized);
+    assertEquals(EnumValidity.E.BAR, deserialized.optionalE);
+    assertEquals(alsoInvalid, deserialized.defaultE);
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.BAZ, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAR},
+        deserialized.repeatedE));
+    assertTrue(Arrays.equals(
+        new int[] {EnumValidity.E.BAZ, alsoInvalid, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAZ},
+        deserialized.packedE));
+    assertTrue(Arrays.equals(
+        new int[] {invalid, alsoInvalid, /* + */ EnumValidity.E.BAR},
+        deserialized.repeatedE2));
+    assertTrue(Arrays.equals(
+        new int[] {/* <null> + */ EnumValidity.E.FOO},
+        deserialized.packedE2));
+    assertNull(deserialized.repeatedE3); // null + all invalid == null
+    assertEquals(0, deserialized.packedE3.length); // empty + all invalid == empty
+
+    // Test 3: reading by alternative forms
+    EnumValidity.Alt alt = MessageNano.mergeFrom(new EnumValidity.Alt(), serialized);
+    assertEquals(EnumValidity.E.BAR, // last valid value in m.repeatedE2
+        alt.repeatedE2AsOptional);
+    assertTrue(Arrays.equals(new int[] {EnumValidity.E.FOO}, alt.packedE2AsNonPacked));
+    assertEquals(0, alt.nonPackedE3AsPacked.length);
+  }
+
+  /**
+   * Tests the same as {@link #testNanoEnumValidity()} with accessor style. Repeated fields are
+   * not re-tested here because they are not affected by the accessor style.
+   */
+  public void testNanoEnumValidityAccessors() throws Exception {
+    final int invalid = 120;
+    final int alsoInvalid = 121;
+
+    EnumValidityAccessors.M m = new EnumValidityAccessors.M();
+    // Sanity check & baseline of the assertions for the first case below.
+    assertEquals(EnumValidityAccessors.default_, m.getOptionalE());
+    assertEquals(EnumValidityAccessors.BAZ, m.getDefaultE());
+
+    m.setOptionalE(invalid);
+    m.setDefaultE(invalid);
+    // Set repeatedE2 for Alt.repeatedE2AsOptional
+    m.repeatedE2 = new int[] {invalid, EnumValidityAccessors.BAR, alsoInvalid};
+    byte[] serialized = MessageNano.toByteArray(m);
+    // Sanity check that we do have all data in the byte array.
+    assertEquals(10, serialized.length);
+
+    // Test 1: tests that invalid values aren't included in the deserialized message.
+    EnumValidityAccessors.M deserialized =
+        MessageNano.mergeFrom(new EnumValidityAccessors.M(), serialized);
+    assertEquals(EnumValidityAccessors.default_, deserialized.getOptionalE());
+    assertEquals(EnumValidityAccessors.BAZ, deserialized.getDefaultE());
+
+    // Test 2: tests that invalid values do not override previous values in the field, including
+    // pre-existing invalid values.
+    deserialized.setOptionalE(EnumValidityAccessors.BAR);
+    deserialized.setDefaultE(alsoInvalid);
+    MessageNano.mergeFrom(deserialized, serialized);
+    assertEquals(EnumValidityAccessors.BAR, deserialized.getOptionalE());
+    assertEquals(alsoInvalid, deserialized.getDefaultE());
+
+    // Test 3: reading by alternative forms
+    EnumValidityAccessors.Alt alt =
+        MessageNano.mergeFrom(new EnumValidityAccessors.Alt(), serialized);
+    assertEquals(EnumValidityAccessors.BAR, // last valid value in m.repeatedE2
+        alt.getRepeatedE2AsOptional());
+  }
+
+  /**
+   * Tests that code generation correctly wraps a single message into its outer
+   * class. The class {@code SingleMessageNano} is imported from the outer
+   * class {@code UnittestSingleNano}, whose name is implicit. Any error would
+   * cause this method to fail compilation.
+   */
+  public void testNanoSingle() throws Exception {
+    SingleMessageNano msg = new SingleMessageNano();
+    assertNotNull(msg);
+  }
+
+  /**
+   * Tests that code generation correctly skips generating the outer class if
+   * unnecessary, letting a file-scope entity have the same name. The class
+   * {@code MultipleNameClashNano} shares the same name with the file's outer
+   * class defined explicitly, but the file contains no other entities and has
+   * java_multiple_files set. Any error would cause this method to fail
+   * compilation.
+   */
+  public void testNanoMultipleNameClash() throws Exception {
+    MultipleNameClashNano msg = new MultipleNameClashNano();
+    msg.field = 0;
+  }
+
+  /**
+   * Tests that code generation correctly handles enums in different scopes in
+   * a source file with the option java_multiple_files set to true. Any error
+   * would cause this method to fail compilation.
+   */
+  public void testNanoMultipleEnumScoping() throws Exception {
+    FileScopeEnumRefNano msg1 = new FileScopeEnumRefNano();
+    msg1.enumField = UnittestMultipleNano.ONE;
+    MessageScopeEnumRefNano msg2 = new MessageScopeEnumRefNano();
+    msg2.enumField = MessageScopeEnumRefNano.TWO;
+  }
+
+  /**
+   * Tests that code generation with mixed values of the java_multiple_files
+   * options between the main source file and the imported source files would
+   * generate correct references. Any error would cause this method to fail
+   * compilation.
+   */
+  public void testNanoMultipleImportingNonMultiple() throws Exception {
+    UnittestImportNano.ImportMessageNano importMsg = new UnittestImportNano.ImportMessageNano();
+    MultipleImportingNonMultipleNano1 nano1 = new MultipleImportingNonMultipleNano1();
+    nano1.field = importMsg;
+    MultipleImportingNonMultipleNano2 nano2 = new MultipleImportingNonMultipleNano2();
+    nano2.nano1 = nano1;
+  }
+
+  public void testNanoDefaults() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    for (int i = 0; i < 2; i++) {
+      assertEquals(41, msg.defaultInt32);
+      assertEquals(42, msg.defaultInt64);
+      assertEquals(43, msg.defaultUint32);
+      assertEquals(44, msg.defaultUint64);
+      assertEquals(-45, msg.defaultSint32);
+      assertEquals(46, msg.defaultSint64);
+      assertEquals(47, msg.defaultFixed32);
+      assertEquals(48, msg.defaultFixed64);
+      assertEquals(49, msg.defaultSfixed32);
+      assertEquals(-50, msg.defaultSfixed64);
+      assertTrue(51.5f == msg.defaultFloat);
+      assertTrue(52.0e3 == msg.defaultDouble);
+      assertEquals(true, msg.defaultBool);
+      assertEquals("hello", msg.defaultString);
+      assertEquals("world", new String(msg.defaultBytes, InternalNano.UTF_8));
+      assertEquals("dünya", msg.defaultStringNonascii);
+      assertEquals("dünyab", new String(msg.defaultBytesNonascii, InternalNano.UTF_8));
+      assertEquals(TestAllTypesNano.BAR, msg.defaultNestedEnum);
+      assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.defaultForeignEnum);
+      assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.defaultImportEnum);
+      assertEquals(Float.POSITIVE_INFINITY, msg.defaultFloatInf);
+      assertEquals(Float.NEGATIVE_INFINITY, msg.defaultFloatNegInf);
+      assertEquals(Float.NaN, msg.defaultFloatNan);
+      assertEquals(Double.POSITIVE_INFINITY, msg.defaultDoubleInf);
+      assertEquals(Double.NEGATIVE_INFINITY, msg.defaultDoubleNegInf);
+      assertEquals(Double.NaN, msg.defaultDoubleNan);
+
+      // Default values are not output, except for required fields.
+      byte [] result = MessageNano.toByteArray(msg);
+      int msgSerializedSize = msg.getSerializedSize();
+      //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+      assertTrue(msgSerializedSize == 3);
+      assertEquals(result.length, msgSerializedSize);
+      msg.clear();
+    }
+  }
+
+  public void testDifferentStringLengthsNano() throws Exception {
+    // Test string serialization roundtrip using strings of the following lengths,
+    // with ASCII and Unicode characters requiring different UTF-8 byte counts per
+    // char, hence causing the length delimiter varint to sometimes require more
+    // bytes for the Unicode strings than the ASCII string of the same length.
+    int[] lengths = new int[] {
+            0,
+            1,
+            (1 << 4) - 1,  // 1 byte for ASCII and Unicode
+            (1 << 7) - 1,  // 1 byte for ASCII, 2 bytes for Unicode
+            (1 << 11) - 1, // 2 bytes for ASCII and Unicode
+            (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode
+            (1 << 17) - 1, // 3 bytes for ASCII and Unicode
+    };
+    for (int i : lengths) {
+      testEncodingOfString('q', i);      // 1 byte per char
+      testEncodingOfString('\u07FF', i); // 2 bytes per char
+      testEncodingOfString('\u0981', i); // 3 bytes per char
+    }
+  }
+
+  /** Regression test for https://github.com/google/protobuf/issues/292 */
+  public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception {
+    String testCase = "Foooooooo";
+    assertEquals(CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length()),
+            CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length() * 3));
+    assertEquals(11, CodedOutputByteBufferNano.computeStringSize(1, testCase));
+    // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes.
+    // An array of size 1 will cause a failure when trying to write the varint.
+    for (int i = 0; i < 11; i++) {
+      CodedOutputByteBufferNano bufferNano = CodedOutputByteBufferNano.newInstance(new byte[i]);
+      try {
+        bufferNano.writeString(1, testCase);
+        fail("Should have thrown an out of space exception");
+      } catch (CodedOutputByteBufferNano.OutOfSpaceException expected) {}
+    }
+  }
+
+  private void testEncodingOfString(char c, int length) throws InvalidProtocolBufferNanoException {
+    TestAllTypesNano testAllTypesNano = new TestAllTypesNano();
+    final String fullString = fullString(c, length);
+    testAllTypesNano.optionalString = fullString;
+    final TestAllTypesNano resultNano = new TestAllTypesNano();
+    MessageNano.mergeFrom(resultNano, MessageNano.toByteArray(testAllTypesNano));
+    assertEquals(fullString, resultNano.optionalString);
+  }
+
+  private String fullString(char c, int length) {
+    char[] result = new char[length];
+    Arrays.fill(result, c);
+    return new String(result);
+  }
+
+  public void testNanoWithHasParseFrom() throws Exception {
+    TestAllTypesNanoHas msg = null;
+    // Test false on creation, after clear and upon empty parse.
+    for (int i = 0; i < 3; i++) {
+      if (i == 0) {
+        msg = new TestAllTypesNanoHas();
+      } else if (i == 1) {
+        msg.clear();
+      } else if (i == 2) {
+        msg = TestAllTypesNanoHas.parseFrom(new byte[0]);
+      }
+      assertFalse(msg.hasOptionalInt32);
+      assertFalse(msg.hasOptionalString);
+      assertFalse(msg.hasOptionalBytes);
+      assertFalse(msg.hasOptionalNestedEnum);
+      assertFalse(msg.hasDefaultInt32);
+      assertFalse(msg.hasDefaultString);
+      assertFalse(msg.hasDefaultBytes);
+      assertFalse(msg.hasDefaultFloatNan);
+      assertFalse(msg.hasDefaultNestedEnum);
+      assertFalse(msg.hasId);
+      assertFalse(msg.hasRequiredEnum);
+      msg.optionalInt32 = 123;
+      msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+      msg.optionalNestedMessage.bb = 2;
+      msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+    }
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    // Has fields true upon parse.
+    TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+    assertEquals(123, newMsg.optionalInt32);
+    assertTrue(newMsg.hasOptionalInt32);
+    assertEquals(2, newMsg.optionalNestedMessage.bb);
+    assertTrue(newMsg.optionalNestedMessage.hasBb);
+    assertEquals(TestAllTypesNanoHas.BAZ, newMsg.optionalNestedEnum);
+    assertTrue(newMsg.hasOptionalNestedEnum);
+  }
+
+  public void testNanoWithHasSerialize() throws Exception {
+    TestAllTypesNanoHas msg = new TestAllTypesNanoHas();
+    msg.hasOptionalInt32 = true;
+    msg.hasOptionalString = true;
+    msg.hasOptionalBytes = true;
+    msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+    msg.optionalNestedMessage.hasBb = true;
+    msg.hasOptionalNestedEnum = true;
+    msg.hasDefaultInt32 = true;
+    msg.hasDefaultString = true;
+    msg.hasDefaultBytes = true;
+    msg.hasDefaultFloatNan = true;
+    msg.hasDefaultNestedEnum = true;
+    msg.hasId = true;
+    msg.hasRequiredEnum = true;
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    assertEquals(result.length, msgSerializedSize);
+
+    // Now deserialize and find that all fields are set and equal to their defaults.
+    TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+    assertTrue(newMsg.hasOptionalInt32);
+    assertTrue(newMsg.hasOptionalString);
+    assertTrue(newMsg.hasOptionalBytes);
+    assertTrue(newMsg.optionalNestedMessage.hasBb);
+    assertTrue(newMsg.hasOptionalNestedEnum);
+    assertTrue(newMsg.hasDefaultInt32);
+    assertTrue(newMsg.hasDefaultString);
+    assertTrue(newMsg.hasDefaultBytes);
+    assertTrue(newMsg.hasDefaultFloatNan);
+    assertTrue(newMsg.hasDefaultNestedEnum);
+    assertTrue(newMsg.hasId);
+    assertTrue(newMsg.hasRequiredEnum);
+    assertEquals(0, newMsg.optionalInt32);
+    assertEquals(0, newMsg.optionalString.length());
+    assertEquals(0, newMsg.optionalBytes.length);
+    assertEquals(0, newMsg.optionalNestedMessage.bb);
+    assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum);
+    assertEquals(41, newMsg.defaultInt32);
+    assertEquals("hello", newMsg.defaultString);
+    assertEquals("world", new String(newMsg.defaultBytes, InternalNano.UTF_8));
+    assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum);
+    assertEquals(Float.NaN, newMsg.defaultFloatNan);
+    assertEquals(0, newMsg.id);
+    assertEquals(TestAllTypesNanoHas.FOO, newMsg.requiredEnum);
+  }
+
+  public void testNanoWithAccessorsBasic() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+
+    // Makes sure required, repeated, and message fields are still public
+    msg.id = 3;
+    msg.repeatedBytes = new byte[2][3];
+    msg.optionalNestedMessage = null;
+
+    // Test accessors
+    assertEquals(0, msg.getOptionalInt32());
+    assertFalse(msg.hasOptionalInt32());
+    msg.setOptionalInt32(135);
+    assertEquals(135, msg.getOptionalInt32());
+    assertTrue(msg.hasOptionalInt32());
+    msg.clearOptionalInt32();
+    assertFalse(msg.hasOptionalInt32());
+    msg.setOptionalInt32(0); // default value
+    assertTrue(msg.hasOptionalInt32());
+
+    // Test NPE
+    try {
+      msg.setOptionalBytes(null);
+      fail();
+    } catch (NullPointerException expected) {}
+    try {
+      msg.setOptionalString(null);
+      fail();
+    } catch (NullPointerException expected) {}
+
+    // Test has bit on bytes field with defaults and clear() re-clones the default array
+    assertFalse(msg.hasDefaultBytes());
+    byte[] defaultBytes = msg.getDefaultBytes();
+    msg.setDefaultBytes(defaultBytes);
+    assertTrue(msg.hasDefaultBytes());
+    msg.clearDefaultBytes();
+    assertFalse(msg.hasDefaultBytes());
+    defaultBytes[0]++; // modify original array
+    assertFalse(Arrays.equals(defaultBytes, msg.getDefaultBytes()));
+
+    // Test has bits that require additional bit fields
+    assertFalse(msg.hasBitFieldCheck());
+    msg.setBitFieldCheck(0);
+    assertTrue(msg.hasBitFieldCheck());
+    assertFalse(msg.hasBeforeBitFieldCheck()); // checks bit field does not leak
+    assertFalse(msg.hasAfterBitFieldCheck());
+
+    // Test clear() clears has bits
+    msg.setOptionalString("hi");
+    msg.setDefaultString("there");
+    msg.clear();
+    assertFalse(msg.hasOptionalString());
+    assertFalse(msg.hasDefaultString());
+    assertFalse(msg.hasBitFieldCheck());
+
+    // Test set() and clear() returns itself (compiles = success)
+    msg.clear()
+        .setOptionalInt32(3)
+        .clearDefaultBytes()
+        .setOptionalString("4");
+  }
+
+  public void testNanoWithAccessorsParseFrom() throws Exception {
+    TestNanoAccessors msg = null;
+    // Test false on creation, after clear and upon empty parse.
+    for (int i = 0; i < 3; i++) {
+      if (i == 0) {
+        msg = new TestNanoAccessors();
+      } else if (i == 1) {
+        msg.clear();
+      } else if (i == 2) {
+        msg = TestNanoAccessors.parseFrom(new byte[0]);
+      }
+      assertFalse(msg.hasOptionalInt32());
+      assertFalse(msg.hasOptionalString());
+      assertFalse(msg.hasOptionalBytes());
+      assertFalse(msg.hasOptionalNestedEnum());
+      assertFalse(msg.hasDefaultInt32());
+      assertFalse(msg.hasDefaultString());
+      assertFalse(msg.hasDefaultBytes());
+      assertFalse(msg.hasDefaultFloatNan());
+      assertFalse(msg.hasDefaultNestedEnum());
+      msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+      msg.optionalNestedMessage.setBb(2);
+      msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+      msg.setDefaultInt32(msg.getDefaultInt32());
+    }
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 14);
+    assertEquals(result.length, msgSerializedSize);
+
+    // Has fields true upon parse.
+    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+    assertEquals(2, newMsg.optionalNestedMessage.getBb());
+    assertTrue(newMsg.optionalNestedMessage.hasBb());
+    assertEquals(TestNanoAccessors.BAZ, newMsg.getOptionalNestedEnum());
+    assertTrue(newMsg.hasOptionalNestedEnum());
+
+    // Has field true on fields with explicit default values from wire.
+    assertTrue(newMsg.hasDefaultInt32());
+    assertEquals(41, newMsg.getDefaultInt32());
+  }
+
+  public void testNanoWithAccessorsPublicFieldTypes() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+    assertNull(msg.optionalNestedMessage);
+    assertEquals(0, msg.id);
+    assertEquals(0, msg.repeatedNestedEnum.length);
+
+    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(MessageNano.toByteArray(msg));
+    assertNull(newMsg.optionalNestedMessage);
+    assertEquals(0, newMsg.id);
+    assertEquals(0, newMsg.repeatedNestedEnum.length);
+
+    TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+    nestedMessage.setBb(5);
+    newMsg.optionalNestedMessage = nestedMessage;
+    newMsg.id = -1;
+    newMsg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+
+    TestNanoAccessors newMsg2 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg));
+    assertEquals(nestedMessage.getBb(), newMsg2.optionalNestedMessage.getBb());
+    assertEquals(-1, newMsg2.id);
+    assertEquals(TestAllTypesNano.FOO, newMsg2.repeatedNestedEnum[0]);
+
+    newMsg2.optionalNestedMessage = null;
+    newMsg2.id = 0;
+    newMsg2.repeatedNestedEnum = null;
+
+    TestNanoAccessors newMsg3 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg2));
+    assertNull(newMsg3.optionalNestedMessage);
+    assertEquals(0, newMsg3.id);
+    assertEquals(0, newMsg3.repeatedNestedEnum.length);
+  }
+
+  public void testNanoWithAccessorsSerialize() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+    msg.setOptionalInt32(msg.getOptionalInt32());
+    msg.setOptionalString(msg.getOptionalString());
+    msg.setOptionalBytes(msg.getOptionalBytes());
+    TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+    nestedMessage.setBb(nestedMessage.getBb());
+    msg.optionalNestedMessage = nestedMessage;
+    msg.setOptionalNestedEnum(msg.getOptionalNestedEnum());
+    msg.setDefaultInt32(msg.getDefaultInt32());
+    msg.setDefaultString(msg.getDefaultString());
+    msg.setDefaultBytes(msg.getDefaultBytes());
+    msg.setDefaultFloatNan(msg.getDefaultFloatNan());
+    msg.setDefaultNestedEnum(msg.getDefaultNestedEnum());
+
+    byte [] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    assertEquals(result.length, msgSerializedSize);
+
+    // Now deserialize and find that all fields are set and equal to their defaults.
+    TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+    assertTrue(newMsg.hasOptionalInt32());
+    assertTrue(newMsg.hasOptionalString());
+    assertTrue(newMsg.hasOptionalBytes());
+    assertTrue(newMsg.optionalNestedMessage.hasBb());
+    assertTrue(newMsg.hasOptionalNestedEnum());
+    assertTrue(newMsg.hasDefaultInt32());
+    assertTrue(newMsg.hasDefaultString());
+    assertTrue(newMsg.hasDefaultBytes());
+    assertTrue(newMsg.hasDefaultFloatNan());
+    assertTrue(newMsg.hasDefaultNestedEnum());
+    assertEquals(0, newMsg.getOptionalInt32());
+    assertEquals(0, newMsg.getOptionalString().length());
+    assertEquals(0, newMsg.getOptionalBytes().length);
+    assertEquals(0, newMsg.optionalNestedMessage.getBb());
+    assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
+    assertEquals(41, newMsg.getDefaultInt32());
+    assertEquals("hello", newMsg.getDefaultString());
+    assertEquals("world", new String(newMsg.getDefaultBytes(), InternalNano.UTF_8));
+    assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
+    assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
+    assertEquals(0, newMsg.id);
+  }
+
+  public void testNanoJavaEnumStyle() throws Exception {
+    EnumClassNanos.EnumClassNano msg = new EnumClassNanos.EnumClassNano();
+    assertEquals(EnumClassNanos.FileScopeEnum.ONE, msg.one);
+    assertEquals(EnumClassNanos.EnumClassNano.MessageScopeEnum.TWO, msg.two);
+
+    EnumClassNanoMultiple msg2 = new EnumClassNanoMultiple();
+    assertEquals(FileScopeEnumMultiple.THREE, msg2.three);
+    assertEquals(EnumClassNanoMultiple.MessageScopeEnumMultiple.FOUR, msg2.four);
+  }
+
+  /**
+   * Tests that fields with a default value of NaN are not serialized when
+   * set to NaN. This is a special case as NaN != NaN, so normal equality
+   * checks don't work.
+   */
+  public void testNanoNotANumberDefaults() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.defaultDoubleNan = 0;
+    msg.defaultFloatNan = 0;
+    byte[] result = MessageNano.toByteArray(msg);
+    int msgSerializedSize = msg.getSerializedSize();
+    assertTrue(result.length == msgSerializedSize);
+    assertTrue(msgSerializedSize > 3);
+
+    msg.defaultDoubleNan = Double.NaN;
+    msg.defaultFloatNan = Float.NaN;
+    result = MessageNano.toByteArray(msg);
+    msgSerializedSize = msg.getSerializedSize();
+    assertEquals(3, result.length);
+    assertEquals(3, msgSerializedSize);
+  }
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * exactly up to a limit, this should not break things.
+   */
+  public void testSkipRawBytesBug() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2 };
+    CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
+
+    int limit = input.pushLimit(1);
+    input.skipRawBytes(1);
+    input.popLimit(limit);
+    assertEquals(2, input.readRawByte());
+  }
+
+  /**
+   * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
+   * past the end of a buffer with a limit that has been set past the end of
+   * that buffer, this should not break things.
+   */
+  public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
+    byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
+    CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes);
+
+    int limit = input.pushLimit(4);
+    // In order to expose the bug we need to read at least one byte to prime the
+    // buffer inside the CodedInputStream.
+    assertEquals(1, input.readRawByte());
+    // Skip to the end of the limit.
+    input.skipRawBytes(3);
+    assertTrue(input.isAtEnd());
+    input.popLimit(limit);
+    assertEquals(5, input.readRawByte());
+  }
+
+  // Test a smattering of various proto types for printing
+  public void testMessageNanoPrinter() {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.optionalInt32 = 14;
+    msg.optionalFloat = 42.3f;
+    msg.optionalString = "String \"with' both quotes";
+    msg.optionalBytes = new byte[] {'"', '\0', 1, 8};
+    msg.optionalGroup = new TestAllTypesNano.OptionalGroup();
+    msg.optionalGroup.a = 15;
+    msg.repeatedInt64 = new long[2];
+    msg.repeatedInt64[0] = 1L;
+    msg.repeatedInt64[1] = -1L;
+    msg.repeatedBytes = new byte[2][];
+    msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+    msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[2];
+    msg.repeatedGroup[0] = new TestAllTypesNano.RepeatedGroup();
+    msg.repeatedGroup[0].a = -27;
+    msg.repeatedGroup[1] = new TestAllTypesNano.RepeatedGroup();
+    msg.repeatedGroup[1].a = -72;
+    msg.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+    msg.optionalNestedMessage.bb = 7;
+    msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[2];
+    msg.repeatedNestedMessage[0] = new TestAllTypesNano.NestedMessage();
+    msg.repeatedNestedMessage[0].bb = 77;
+    msg.repeatedNestedMessage[1] = new TestAllTypesNano.NestedMessage();
+    msg.repeatedNestedMessage[1].bb = 88;
+    msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+    msg.repeatedNestedEnum = new int[2];
+    msg.repeatedNestedEnum[0] = TestAllTypesNano.BAR;
+    msg.repeatedNestedEnum[1] = TestAllTypesNano.FOO;
+    msg.repeatedStringPiece = new String[] {null, "world"};
+    msg.setOneofString("hello");
+
+    String protoPrint = msg.toString();
+    assertTrue(protoPrint.contains("optional_int32: 14"));
+    assertTrue(protoPrint.contains("optional_float: 42.3"));
+    assertTrue(protoPrint.contains("optional_double: 0.0"));
+    assertTrue(protoPrint.contains("optional_string: \"String \\u0022with\\u0027 both quotes\""));
+    assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+    assertTrue(protoPrint.contains("optional_group <\n  a: 15\n>"));
+
+    assertTrue(protoPrint.contains("repeated_int64: 1\nrepeated_int64: -1"));
+    assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+    assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+    assertTrue(protoPrint.contains("repeated_group <\n  a: -27\n>\n"
+            + "repeated_group <\n  a: -72\n>"));
+    assertTrue(protoPrint.contains("optional_nested_message <\n  bb: 7\n>"));
+    assertTrue(protoPrint.contains("repeated_nested_message <\n  bb: 77\n>\n"
+            + "repeated_nested_message <\n  bb: 88\n>"));
+    assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+    assertTrue(protoPrint.contains("repeated_nested_enum: 2\nrepeated_nested_enum: 1"));
+    assertTrue(protoPrint.contains("default_int32: 41"));
+    assertTrue(protoPrint.contains("default_string: \"hello\""));
+    assertFalse(protoPrint.contains("repeated_string_piece: \"\""));  // null should be dropped
+    assertTrue(protoPrint.contains("repeated_string_piece: \"world\""));
+    assertTrue(protoPrint.contains("oneof_string: \"hello\""));
+  }
+
+  public void testMessageNanoPrinterAccessors() throws Exception {
+    TestNanoAccessors msg = new TestNanoAccessors();
+    msg.setOptionalInt32(13);
+    msg.setOptionalString("foo");
+    msg.setOptionalBytes(new byte[] {'"', '\0', 1, 8});
+    msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+    msg.optionalNestedMessage.setBb(7);
+    msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+    msg.repeatedInt32 = new int[] { 1, -1 };
+    msg.repeatedString = new String[] { "Hello", "world" };
+    msg.repeatedBytes = new byte[2][];
+    msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+    msg.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[2];
+    msg.repeatedNestedMessage[0] = new TestNanoAccessors.NestedMessage();
+    msg.repeatedNestedMessage[0].setBb(5);
+    msg.repeatedNestedMessage[1] = new TestNanoAccessors.NestedMessage();
+    msg.repeatedNestedMessage[1].setBb(6);
+    msg.repeatedNestedEnum = new int[] { TestNanoAccessors.FOO, TestNanoAccessors.BAR };
+    msg.id = 33;
+
+    String protoPrint = msg.toString();
+    assertTrue(protoPrint.contains("optional_int32: 13"));
+    assertTrue(protoPrint.contains("optional_string: \"foo\""));
+    assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+    assertTrue(protoPrint.contains("optional_nested_message <\n  bb: 7\n>"));
+    assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+    assertTrue(protoPrint.contains("repeated_int32: 1\nrepeated_int32: -1"));
+    assertTrue(protoPrint.contains("repeated_string: \"Hello\"\nrepeated_string: \"world\""));
+    assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+    assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+    assertTrue(protoPrint.contains("repeated_nested_message <\n  bb: 5\n>\n"
+            + "repeated_nested_message <\n  bb: 6\n>"));
+    assertTrue(protoPrint.contains("repeated_nested_enum: 1\nrepeated_nested_enum: 2"));
+    assertTrue(protoPrint.contains("id: 33"));
+  }
+
+  public void testMessageNanoPrinterForMaps() throws Exception {
+    TestMap msg = new TestMap();
+    MessageValue msgValues[] = new MessageValue[] {
+      new MessageValue(), new MessageValue()
+    };
+    msgValues[0].value = 1;
+    msgValues[1].value = 2;
+    msg.int32ToBytesField = new HashMap<Integer, byte[]>();
+    msg.int32ToBytesField.put(1, new byte[] {'"', '\0'});
+    msg.int32ToBytesField.put(2, new byte[] {1, 8});
+    msg.stringToInt32Field = new HashMap<String, Integer>();
+    msg.stringToInt32Field.put("hello", 1);
+    msg.stringToInt32Field.put("world", 2);
+    msg.int32ToMessageField = new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    msg.int32ToMessageField.put(0, msgValues[0]);
+    msg.int32ToMessageField.put(1, msgValues[1]);
+    msg.int32ToEnumField = new HashMap<Integer, Integer>();
+    msg.int32ToEnumField.put(1, 2);
+    msg.int32ToEnumField.put(2, 3);
+    String protoPrint = msg.toString();
+
+    assertTrue(protoPrint.contains(
+        "int32_to_bytes_field <\n  key: 1\n  value: \"\\\"\\000\"\n>"));
+    assertTrue(protoPrint.contains(
+        "int32_to_bytes_field <\n  key: 2\n  value: \"\\001\\010\"\n>"));
+    assertTrue(protoPrint.contains(
+        "string_to_int32_field <\n  key: \"hello\"\n  value: 1\n>"));
+    assertTrue(protoPrint.contains(
+        "string_to_int32_field <\n  key: \"world\"\n  value: 2\n>"));
+    assertTrue(protoPrint.contains(
+        "int32_to_message_field <\n  key: 0\n  value <\n    value: 1\n"));
+    assertTrue(protoPrint.contains(
+        "int32_to_message_field <\n  key: 1\n  value <\n    value: 2\n"));
+    assertTrue(protoPrint.contains(
+        "int32_to_enum_field <\n  key: 1\n  value: 2\n>"));
+    assertTrue(protoPrint.contains(
+        "int32_to_enum_field <\n  key: 2\n  value: 3\n>"));
+  }
+
+  public void testExtensions() throws Exception {
+    Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+    message.field = 5;
+    int[] int32s = {1, 2};
+    int[] uint32s = {3, 4};
+    int[] sint32s = {-5, -6};
+    long[] int64s = {7, 8};
+    long[] uint64s = {9, 10};
+    long[] sint64s = {-11, -12};
+    int[] fixed32s = {13, 14};
+    int[] sfixed32s = {-15, -16};
+    long[] fixed64s = {17, 18};
+    long[] sfixed64s = {-19, -20};
+    boolean[] bools = {true, false};
+    float[] floats = {2.1f, 2.2f};
+    double[] doubles = {2.3, 2.4};
+    int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+    String[] strings = {"vijfentwintig", "twenty-six"};
+    byte[][] bytess = {{2, 7}, {2, 8}};
+    AnotherMessage another1 = new AnotherMessage();
+    another1.string = "er shi jiu";
+    another1.value = false;
+    AnotherMessage another2 = new AnotherMessage();
+    another2.string = "trente";
+    another2.value = true;
+    AnotherMessage[] messages = {another1, another2};
+    RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+    group1.a = 31;
+    RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+    group2.a = 32;
+    RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt32));
+    message.setExtension(RepeatedExtensions.repeatedInt32, int32s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt32));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint32));
+    message.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint32));
+    message.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt64));
+    message.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt64));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint64));
+    message.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint64));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSint64));
+    message.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSint64));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+    message.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+    message.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+    message.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+    message.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedBool));
+    message.setExtension(RepeatedExtensions.repeatedBool, bools);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedBool));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedFloat));
+    message.setExtension(RepeatedExtensions.repeatedFloat, floats);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedFloat));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedDouble));
+    message.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedDouble));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedEnum));
+    message.setExtension(RepeatedExtensions.repeatedEnum, enums);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedEnum));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedString));
+    message.setExtension(RepeatedExtensions.repeatedString, strings);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedString));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedBytes));
+    message.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedBytes));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedMessage));
+    message.setExtension(RepeatedExtensions.repeatedMessage, messages);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedMessage));
+    assertFalse(message.hasExtension(RepeatedExtensions.repeatedGroup));
+    message.setExtension(RepeatedExtensions.repeatedGroup, groups);
+    assertTrue(message.hasExtension(RepeatedExtensions.repeatedGroup));
+
+    byte[] data = MessageNano.toByteArray(message);
+    message = Extensions.ExtendableMessage.parseFrom(data);
+    assertEquals(5, message.field);
+
+    // Test reading back using SingularExtensions: the retrieved value should equal the last
+    // in each array.
+    assertEquals(int32s[1], (int) message.getExtension(SingularExtensions.someInt32));
+    assertEquals(uint32s[1], (int) message.getExtension(SingularExtensions.someUint32));
+    assertEquals(sint32s[1], (int) message.getExtension(SingularExtensions.someSint32));
+    assertEquals(int64s[1], (long) message.getExtension(SingularExtensions.someInt64));
+    assertEquals(uint64s[1], (long) message.getExtension(SingularExtensions.someUint64));
+    assertEquals(sint64s[1], (long) message.getExtension(SingularExtensions.someSint64));
+    assertEquals(fixed32s[1], (int) message.getExtension(SingularExtensions.someFixed32));
+    assertEquals(sfixed32s[1], (int) message.getExtension(SingularExtensions.someSfixed32));
+    assertEquals(fixed64s[1], (long) message.getExtension(SingularExtensions.someFixed64));
+    assertEquals(sfixed64s[1], (long) message.getExtension(SingularExtensions.someSfixed64));
+    assertEquals(bools[1], (boolean) message.getExtension(SingularExtensions.someBool));
+    assertEquals(floats[1], (float) message.getExtension(SingularExtensions.someFloat));
+    assertEquals(doubles[1], (double) message.getExtension(SingularExtensions.someDouble));
+    assertEquals(enums[1], (int) message.getExtension(SingularExtensions.someEnum));
+    assertEquals(strings[1], message.getExtension(SingularExtensions.someString));
+    assertTrue(Arrays.equals(bytess[1], message.getExtension(SingularExtensions.someBytes)));
+    AnotherMessage deserializedMessage = message.getExtension(SingularExtensions.someMessage);
+    assertEquals(another2.string, deserializedMessage.string);
+    assertEquals(another2.value, deserializedMessage.value);
+    assertEquals(group2.a, message.getExtension(SingularExtensions.someGroup).a);
+
+    // Test reading back using RepeatedExtensions: the arrays should be equal.
+    message = Extensions.ExtendableMessage.parseFrom(data);
+    assertEquals(5, message.field);
+    assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+    assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+    assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+    assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+    assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+    assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+    assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+    assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+    assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+    assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+    assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+    assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+    assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+    assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+    assertTrue(Arrays.equals(strings, message.getExtension(RepeatedExtensions.repeatedString)));
+    byte[][] deserializedRepeatedBytes = message.getExtension(RepeatedExtensions.repeatedBytes);
+    assertEquals(2, deserializedRepeatedBytes.length);
+    assertTrue(Arrays.equals(bytess[0], deserializedRepeatedBytes[0]));
+    assertTrue(Arrays.equals(bytess[1], deserializedRepeatedBytes[1]));
+    AnotherMessage[] deserializedRepeatedMessage =
+        message.getExtension(RepeatedExtensions.repeatedMessage);
+    assertEquals(2, deserializedRepeatedMessage.length);
+    assertEquals(another1.string, deserializedRepeatedMessage[0].string);
+    assertEquals(another1.value, deserializedRepeatedMessage[0].value);
+    assertEquals(another2.string, deserializedRepeatedMessage[1].string);
+    assertEquals(another2.value, deserializedRepeatedMessage[1].value);
+    RepeatedExtensions.RepeatedGroup[] deserializedRepeatedGroup =
+        message.getExtension(RepeatedExtensions.repeatedGroup);
+    assertEquals(2, deserializedRepeatedGroup.length);
+    assertEquals(group1.a, deserializedRepeatedGroup[0].a);
+    assertEquals(group2.a, deserializedRepeatedGroup[1].a);
+
+    message = Extensions.ExtendableMessage.parseFrom(data);
+    assertEquals(5, message.field);
+    // Test hasExtension using PackedExtensions.
+    assertTrue(message.hasExtension(PackedExtensions.packedInt32));
+    assertTrue(message.hasExtension(PackedExtensions.packedUint32));
+    assertTrue(message.hasExtension(PackedExtensions.packedSint32));
+    assertTrue(message.hasExtension(PackedExtensions.packedInt64));
+    assertTrue(message.hasExtension(PackedExtensions.packedUint64));
+    assertTrue(message.hasExtension(PackedExtensions.packedSint64));
+    assertTrue(message.hasExtension(PackedExtensions.packedFixed32));
+    assertTrue(message.hasExtension(PackedExtensions.packedSfixed32));
+    assertTrue(message.hasExtension(PackedExtensions.packedFixed64));
+    assertTrue(message.hasExtension(PackedExtensions.packedSfixed64));
+    assertTrue(message.hasExtension(PackedExtensions.packedBool));
+    assertTrue(message.hasExtension(PackedExtensions.packedFloat));
+    assertTrue(message.hasExtension(PackedExtensions.packedDouble));
+    assertTrue(message.hasExtension(PackedExtensions.packedEnum));
+
+    // Test reading back using PackedExtensions: the arrays should be equal, even the fields
+    // are non-packed.
+    assertTrue(Arrays.equals(int32s, message.getExtension(PackedExtensions.packedInt32)));
+    assertTrue(Arrays.equals(uint32s, message.getExtension(PackedExtensions.packedUint32)));
+    assertTrue(Arrays.equals(sint32s, message.getExtension(PackedExtensions.packedSint32)));
+    assertTrue(Arrays.equals(int64s, message.getExtension(PackedExtensions.packedInt64)));
+    assertTrue(Arrays.equals(uint64s, message.getExtension(PackedExtensions.packedUint64)));
+    assertTrue(Arrays.equals(sint64s, message.getExtension(PackedExtensions.packedSint64)));
+    assertTrue(Arrays.equals(fixed32s, message.getExtension(PackedExtensions.packedFixed32)));
+    assertTrue(Arrays.equals(sfixed32s, message.getExtension(PackedExtensions.packedSfixed32)));
+    assertTrue(Arrays.equals(fixed64s, message.getExtension(PackedExtensions.packedFixed64)));
+    assertTrue(Arrays.equals(sfixed64s, message.getExtension(PackedExtensions.packedSfixed64)));
+    assertTrue(Arrays.equals(bools, message.getExtension(PackedExtensions.packedBool)));
+    assertTrue(Arrays.equals(floats, message.getExtension(PackedExtensions.packedFloat)));
+    assertTrue(Arrays.equals(doubles, message.getExtension(PackedExtensions.packedDouble)));
+    assertTrue(Arrays.equals(enums, message.getExtension(PackedExtensions.packedEnum)));
+
+    // Now set the packable extension values using PackedExtensions so they're serialized packed.
+    message.setExtension(PackedExtensions.packedInt32, int32s);
+    message.setExtension(PackedExtensions.packedUint32, uint32s);
+    message.setExtension(PackedExtensions.packedSint32, sint32s);
+    message.setExtension(PackedExtensions.packedInt64, int64s);
+    message.setExtension(PackedExtensions.packedUint64, uint64s);
+    message.setExtension(PackedExtensions.packedSint64, sint64s);
+    message.setExtension(PackedExtensions.packedFixed32, fixed32s);
+    message.setExtension(PackedExtensions.packedSfixed32, sfixed32s);
+    message.setExtension(PackedExtensions.packedFixed64, fixed64s);
+    message.setExtension(PackedExtensions.packedSfixed64, sfixed64s);
+    message.setExtension(PackedExtensions.packedBool, bools);
+    message.setExtension(PackedExtensions.packedFloat, floats);
+    message.setExtension(PackedExtensions.packedDouble, doubles);
+    message.setExtension(PackedExtensions.packedEnum, enums);
+
+    // And read back using non-packed RepeatedExtensions.
+    byte[] data2 = MessageNano.toByteArray(message);
+    message = MessageNano.mergeFrom(new Extensions.ExtendableMessage(), data2);
+    assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+    assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+    assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+    assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+    assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+    assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+    assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+    assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+    assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+    assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+    assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+    assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+    assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+    assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+
+    // Clone the message and ensure it's still equal.
+    Extensions.ExtendableMessage clone = message.clone();
+    assertEquals(clone, message);
+  }
+
+  public void testNullExtensions() throws Exception {
+    // Check that clearing the extension on an empty message is a no-op.
+    Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+    assertFalse(message.hasExtension(SingularExtensions.someMessage));
+    message.setExtension(SingularExtensions.someMessage, null);
+    assertFalse(message.hasExtension(SingularExtensions.someMessage));
+    assertEquals(0, MessageNano.toByteArray(message).length);
+
+    // Check that the message is empty after setting and clearing an extension.
+    AnotherMessage another = new AnotherMessage();
+    assertFalse(message.hasExtension(SingularExtensions.someMessage));
+    message.setExtension(SingularExtensions.someMessage, another);
+    assertTrue(message.hasExtension(SingularExtensions.someMessage));
+    assertTrue(MessageNano.toByteArray(message).length > 0);
+    message.setExtension(SingularExtensions.someMessage, null);
+    assertFalse(message.hasExtension(SingularExtensions.someMessage));
+    assertEquals(0, MessageNano.toByteArray(message).length);
+  }
+
+  public void testExtensionsMutation() {
+    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+    extendableMessage.setExtension(SingularExtensions.someMessage,
+        new Extensions.AnotherMessage());
+
+    extendableMessage.getExtension(SingularExtensions.someMessage).string = "not empty";
+
+    assertEquals("not empty",
+        extendableMessage.getExtension(SingularExtensions.someMessage).string);
+  }
+
+  public void testExtensionsMutation_Equals() throws InvalidProtocolBufferNanoException {
+    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+    extendableMessage.field = 5;
+    int int32 = 42;
+    int[] uint32s = {3, 4};
+    int[] sint32s = {-5, -6};
+    long[] int64s = {7, 8};
+    long[] uint64s = {9, 10};
+    long[] sint64s = {-11, -12};
+    int[] fixed32s = {13, 14};
+    int[] sfixed32s = {-15, -16};
+    long[] fixed64s = {17, 18};
+    long[] sfixed64s = {-19, -20};
+    boolean[] bools = {true, false};
+    float[] floats = {2.1f, 2.2f};
+    double[] doubles = {2.3, 2.4};
+    int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+    String[] strings = {"vijfentwintig", "twenty-six"};
+    byte[][] bytess = {{2, 7}, {2, 8}};
+    AnotherMessage another1 = new AnotherMessage();
+    another1.string = "er shi jiu";
+    another1.value = false;
+    AnotherMessage another2 = new AnotherMessage();
+    another2.string = "trente";
+    another2.value = true;
+    AnotherMessage[] messages = {another1, another2};
+    RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+    group1.a = 31;
+    RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+    group2.a = 32;
+    RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+    extendableMessage.setExtension(SingularExtensions.someInt32, int32);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedBool, bools);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedFloat, floats);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedEnum, enums);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedString, strings);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedMessage, messages);
+    extendableMessage.setExtension(RepeatedExtensions.repeatedGroup, groups);
+
+    byte[] data = MessageNano.toByteArray(extendableMessage);
+
+    extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+    Extensions.ExtendableMessage messageCopy = Extensions.ExtendableMessage.parseFrom(data);
+
+    // Without deserialising.
+    assertEquals(extendableMessage, messageCopy);
+    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+    // Only one deserialized.
+    extendableMessage.getExtension(SingularExtensions.someInt32);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedUint32);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedSint32);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedInt64);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedUint64);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedSint64);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedFixed32);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed32);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedFixed64);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed64);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedBool);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedFloat);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedDouble);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedEnum);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedString);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedBytes);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedMessage);
+    extendableMessage.getExtension(RepeatedExtensions.repeatedGroup);
+    assertEquals(extendableMessage, messageCopy);
+    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+    // Both deserialized.
+    messageCopy.getExtension(SingularExtensions.someInt32);
+    messageCopy.getExtension(RepeatedExtensions.repeatedUint32);
+    messageCopy.getExtension(RepeatedExtensions.repeatedSint32);
+    messageCopy.getExtension(RepeatedExtensions.repeatedInt64);
+    messageCopy.getExtension(RepeatedExtensions.repeatedUint64);
+    messageCopy.getExtension(RepeatedExtensions.repeatedSint64);
+    messageCopy.getExtension(RepeatedExtensions.repeatedFixed32);
+    messageCopy.getExtension(RepeatedExtensions.repeatedSfixed32);
+    messageCopy.getExtension(RepeatedExtensions.repeatedFixed64);
+    messageCopy.getExtension(RepeatedExtensions.repeatedSfixed64);
+    messageCopy.getExtension(RepeatedExtensions.repeatedBool);
+    messageCopy.getExtension(RepeatedExtensions.repeatedFloat);
+    messageCopy.getExtension(RepeatedExtensions.repeatedDouble);
+    messageCopy.getExtension(RepeatedExtensions.repeatedEnum);
+    messageCopy.getExtension(RepeatedExtensions.repeatedString);
+    messageCopy.getExtension(RepeatedExtensions.repeatedBytes);
+    messageCopy.getExtension(RepeatedExtensions.repeatedMessage);
+    messageCopy.getExtension(RepeatedExtensions.repeatedGroup);
+    assertEquals(extendableMessage, messageCopy);
+    assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+    // Change one, make sure they are still different.
+    messageCopy.getExtension(RepeatedExtensions.repeatedMessage)[0].string = "not empty";
+    assertFalse(extendableMessage.equals(messageCopy));
+
+    // Even if the extension hasn't been deserialized.
+    extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+    assertFalse(extendableMessage.equals(messageCopy));
+  }
+
+  public void testExtensionsCaching() {
+    Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+    extendableMessage.setExtension(SingularExtensions.someMessage,
+        new Extensions.AnotherMessage());
+    assertSame("Consecutive calls to getExtensions should return the same object",
+        extendableMessage.getExtension(SingularExtensions.someMessage),
+        extendableMessage.getExtension(SingularExtensions.someMessage));
+  }
+
+  public void testUnknownFields() throws Exception {
+    // Check that we roundtrip (serialize and deserialize) unrecognized fields.
+    AnotherMessage message = new AnotherMessage();
+    message.string = "Hello World";
+    message.value = false;
+
+    byte[] bytes = MessageNano.toByteArray(message);
+    int extraFieldSize = CodedOutputByteBufferNano.computeStringSize(
+        1001, "This is an unknown field");
+    byte[] newBytes = new byte[bytes.length + extraFieldSize];
+    System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
+    CodedOutputByteBufferNano.newInstance(newBytes, bytes.length, extraFieldSize)
+        .writeString(1001, "This is an unknown field");
+
+    // Deserialize with an unknown field.
+    AnotherMessage deserialized = AnotherMessage.parseFrom(newBytes);
+    byte[] serialized = MessageNano.toByteArray(deserialized);
+
+    assertEquals(newBytes.length, serialized.length);
+
+    // Clear, and make sure it clears everything.
+    deserialized.clear();
+    assertEquals(0, MessageNano.toByteArray(deserialized).length);
+  }
+
+  public void testMergeFrom() throws Exception {
+    SimpleMessageNano message = new SimpleMessageNano();
+    message.d = 123;
+    byte[] bytes = MessageNano.toByteArray(message);
+
+    SimpleMessageNano newMessage = MessageNano.mergeFrom(new SimpleMessageNano(), bytes);
+    assertEquals(message.d, newMessage.d);
+  }
+
+  public void testJavaKeyword() throws Exception {
+    TestAllTypesNano msg = new TestAllTypesNano();
+    msg.synchronized_ = 123;
+    assertEquals(123, msg.synchronized_);
+  }
+
+  public void testReferenceTypesForPrimitives() throws Exception {
+    NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+
+    // Base check - when nothing is set, we serialize nothing.
+    assertHasWireData(message, false);
+
+    message.defaultBool = true;
+    assertHasWireData(message, true);
+
+    message.defaultBool = false;
+    assertHasWireData(message, true);
+
+    message.defaultBool = null;
+    assertHasWireData(message, false);
+
+    message.defaultInt32 = 5;
+    assertHasWireData(message, true);
+
+    message.defaultInt32 = null;
+    assertHasWireData(message, false);
+
+    message.defaultInt64 = 123456L;
+    assertHasWireData(message, true);
+
+    message.defaultInt64 = null;
+    assertHasWireData(message, false);
+
+    message.defaultFloat = 1f;
+    assertHasWireData(message, true);
+
+    message.defaultFloat = null;
+    assertHasWireData(message, false);
+
+    message.defaultDouble = 2.1;
+    assertHasWireData(message, true);
+
+    message.defaultDouble = null;
+    assertHasWireData(message, false);
+
+    message.defaultString = "hello";
+    assertHasWireData(message, true);
+
+    message.defaultString = null;
+    assertHasWireData(message, false);
+
+    message.defaultBytes = new byte[] { 1, 2, 3 };
+    assertHasWireData(message, true);
+
+    message.defaultBytes = null;
+    assertHasWireData(message, false);
+  }
+
+  public void testHashCodeEquals() throws Exception {
+    // Complete equality:
+    TestAllTypesNano a = createMessageForHashCodeEqualsTest();
+    TestAllTypesNano aEquivalent = createMessageForHashCodeEqualsTest();
+
+    assertTrue(MessageNano.messageNanoEquals(a, aEquivalent));
+    assertFalse(MessageNano.messageNanoEquals(a, new TestAllTypesNano()));
+
+    // Null and empty array for repeated fields equality:
+    TestAllTypesNano b = createMessageForHashCodeEqualsTest();
+    b.repeatedBool = null;
+    b.repeatedFloat = new float[0];
+    TestAllTypesNano bEquivalent = createMessageForHashCodeEqualsTest();
+    bEquivalent.repeatedBool = new boolean[0];
+    bEquivalent.repeatedFloat = null;
+
+    // Ref-element-type repeated fields use non-null subsequence equality:
+    TestAllTypesNano c = createMessageForHashCodeEqualsTest();
+    c.repeatedString = null;
+    c.repeatedStringPiece = new String[] {null, "one", null, "two"};
+    c.repeatedBytes = new byte[][] {{3, 4}, null};
+    TestAllTypesNano cEquivalent = createMessageForHashCodeEqualsTest();
+    cEquivalent.repeatedString = new String[3];
+    cEquivalent.repeatedStringPiece = new String[] {"one", "two", null};
+    cEquivalent.repeatedBytes = new byte[][] {{3, 4}};
+
+    // Complete equality for messages with has fields:
+    TestAllTypesNanoHas d = createMessageWithHasForHashCodeEqualsTest();
+    TestAllTypesNanoHas dEquivalent = createMessageWithHasForHashCodeEqualsTest();
+
+    // If has-fields exist, fields with the same default values but
+    // different has-field values are different.
+    TestAllTypesNanoHas e = createMessageWithHasForHashCodeEqualsTest();
+    e.optionalInt32++; // make different from d
+    e.hasDefaultString = false;
+    TestAllTypesNanoHas eDifferent = createMessageWithHasForHashCodeEqualsTest();
+    eDifferent.optionalInt32 = e.optionalInt32;
+    eDifferent.hasDefaultString = true;
+
+    // Complete equality for messages with accessors:
+    TestNanoAccessors f = createMessageWithAccessorsForHashCodeEqualsTest();
+    TestNanoAccessors fEquivalent = createMessageWithAccessorsForHashCodeEqualsTest();
+
+    // If using accessors, explicitly setting a field to its default value
+    // should make the message different.
+    TestNanoAccessors g = createMessageWithAccessorsForHashCodeEqualsTest();
+    g.setOptionalInt32(g.getOptionalInt32() + 1); // make different from f
+    g.clearDefaultString();
+    TestNanoAccessors gDifferent = createMessageWithAccessorsForHashCodeEqualsTest();
+    gDifferent.setOptionalInt32(g.getOptionalInt32());
+    gDifferent.setDefaultString(g.getDefaultString());
+
+    // Complete equality for reference typed messages:
+    NanoReferenceTypes.TestAllTypesNano h = createRefTypedMessageForHashCodeEqualsTest();
+    NanoReferenceTypes.TestAllTypesNano hEquivalent = createRefTypedMessageForHashCodeEqualsTest();
+
+    // Inequality of null and default value for reference typed messages:
+    NanoReferenceTypes.TestAllTypesNano i = createRefTypedMessageForHashCodeEqualsTest();
+    i.optionalInt32 = 1; // make different from h
+    i.optionalFloat = null;
+    NanoReferenceTypes.TestAllTypesNano iDifferent = createRefTypedMessageForHashCodeEqualsTest();
+    iDifferent.optionalInt32 = i.optionalInt32;
+    iDifferent.optionalFloat = 0.0f;
+
+    HashMap<MessageNano, String> hashMap = new HashMap<MessageNano, String>();
+    hashMap.put(a, "a");
+    hashMap.put(b, "b");
+    hashMap.put(c, "c");
+    hashMap.put(d, "d");
+    hashMap.put(e, "e");
+    hashMap.put(f, "f");
+    hashMap.put(g, "g");
+    hashMap.put(h, "h");
+    hashMap.put(i, "i");
+
+    assertEquals(9, hashMap.size()); // a-i should be different from each other.
+
+    assertEquals("a", hashMap.get(a));
+    assertEquals("a", hashMap.get(aEquivalent));
+
+    assertEquals("b", hashMap.get(b));
+    assertEquals("b", hashMap.get(bEquivalent));
+
+    assertEquals("c", hashMap.get(c));
+    assertEquals("c", hashMap.get(cEquivalent));
+
+    assertEquals("d", hashMap.get(d));
+    assertEquals("d", hashMap.get(dEquivalent));
+
+    assertEquals("e", hashMap.get(e));
+    assertNull(hashMap.get(eDifferent));
+
+    assertEquals("f", hashMap.get(f));
+    assertEquals("f", hashMap.get(fEquivalent));
+
+    assertEquals("g", hashMap.get(g));
+    assertNull(hashMap.get(gDifferent));
+
+    assertEquals("h", hashMap.get(h));
+    assertEquals("h", hashMap.get(hEquivalent));
+
+    assertEquals("i", hashMap.get(i));
+    assertNull(hashMap.get(iDifferent));
+  }
+
+  private TestAllTypesNano createMessageForHashCodeEqualsTest() {
+    TestAllTypesNano message = new TestAllTypesNano();
+    message.optionalInt32 = 5;
+    message.optionalInt64 = 777;
+    message.optionalFloat = 1.0f;
+    message.optionalDouble = 2.0;
+    message.optionalBool = true;
+    message.optionalString = "Hello";
+    message.optionalBytes = new byte[] { 1, 2, 3 };
+    message.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+    message.optionalNestedMessage.bb = 27;
+    message.optionalNestedEnum = TestAllTypesNano.BAR;
+    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+    message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+    message.repeatedFloat = new float[] { 5.0f, 6.0f };
+    message.repeatedDouble = new double[] { 99.1, 22.5 };
+    message.repeatedBool = new boolean[] { true, false, true };
+    message.repeatedString = new String[] { "One", "Two" };
+    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+    message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+      message.optionalNestedMessage,
+      message.optionalNestedMessage
+    };
+    message.repeatedNestedEnum = new int[] {
+      TestAllTypesNano.BAR,
+      TestAllTypesNano.BAZ
+    };
+    message.setOneofUint32(3);
+    return message;
+  }
+
+  private TestAllTypesNanoHas createMessageWithHasForHashCodeEqualsTest() {
+    TestAllTypesNanoHas message = new TestAllTypesNanoHas();
+    message.optionalInt32 = 5;
+    message.optionalString = "Hello";
+    message.optionalBytes = new byte[] { 1, 2, 3 };
+    message.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+    message.optionalNestedMessage.bb = 27;
+    message.optionalNestedEnum = TestAllTypesNano.BAR;
+    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+    message.repeatedString = new String[] { "One", "Two" };
+    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+    message.repeatedNestedMessage = new TestAllTypesNanoHas.NestedMessage[] {
+      message.optionalNestedMessage,
+      message.optionalNestedMessage
+    };
+    message.repeatedNestedEnum = new int[] {
+      TestAllTypesNano.BAR,
+      TestAllTypesNano.BAZ
+    };
+    return message;
+  }
+
+  private TestNanoAccessors createMessageWithAccessorsForHashCodeEqualsTest() {
+    TestNanoAccessors message = new TestNanoAccessors()
+        .setOptionalInt32(5)
+        .setOptionalString("Hello")
+        .setOptionalBytes(new byte[] {1, 2, 3})
+        .setOptionalNestedEnum(TestNanoAccessors.BAR);
+    message.optionalNestedMessage = new TestNanoAccessors.NestedMessage().setBb(27);
+    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+    message.repeatedString = new String[] { "One", "Two" };
+    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+    message.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[] {
+      message.optionalNestedMessage,
+      message.optionalNestedMessage
+    };
+    message.repeatedNestedEnum = new int[] {
+      TestAllTypesNano.BAR,
+      TestAllTypesNano.BAZ
+    };
+    return message;
+  }
+
+  private NanoReferenceTypes.TestAllTypesNano createRefTypedMessageForHashCodeEqualsTest() {
+    NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+    message.optionalInt32 = 5;
+    message.optionalInt64 = 777L;
+    message.optionalFloat = 1.0f;
+    message.optionalDouble = 2.0;
+    message.optionalBool = true;
+    message.optionalString = "Hello";
+    message.optionalBytes = new byte[] { 1, 2, 3 };
+    message.optionalNestedMessage =
+        new NanoReferenceTypes.TestAllTypesNano.NestedMessage();
+    message.optionalNestedMessage.foo = 27;
+    message.optionalNestedEnum = NanoReferenceTypes.TestAllTypesNano.BAR;
+    message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+    message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+    message.repeatedFloat = new float[] { 5.0f, 6.0f };
+    message.repeatedDouble = new double[] { 99.1, 22.5 };
+    message.repeatedBool = new boolean[] { true, false, true };
+    message.repeatedString = new String[] { "One", "Two" };
+    message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+    message.repeatedNestedMessage =
+        new NanoReferenceTypes.TestAllTypesNano.NestedMessage[] {
+          message.optionalNestedMessage,
+          message.optionalNestedMessage
+        };
+    message.repeatedNestedEnum = new int[] {
+      NanoReferenceTypes.TestAllTypesNano.BAR,
+      NanoReferenceTypes.TestAllTypesNano.BAZ
+    };
+    return message;
+  }
+
+  public void testEqualsWithSpecialFloatingPointValues() throws Exception {
+    // Checks that the nano implementation complies with Object.equals() when treating
+    // floating point numbers, i.e. NaN == NaN and +0.0 != -0.0.
+    // This test assumes that the generated equals() implementations are symmetric, so
+    // there will only be one direction for each equality check.
+
+    TestAllTypesNano m1 = new TestAllTypesNano();
+    m1.optionalFloat = Float.NaN;
+    m1.optionalDouble = Double.NaN;
+    TestAllTypesNano m2 = new TestAllTypesNano();
+    m2.optionalFloat = Float.NaN;
+    m2.optionalDouble = Double.NaN;
+    assertTrue(m1.equals(m2));
+    assertTrue(m1.equals(
+        MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+    m1.optionalFloat = +0f;
+    m2.optionalFloat = -0f;
+    assertFalse(m1.equals(m2));
+
+    m1.optionalFloat = -0f;
+    m1.optionalDouble = +0d;
+    m2.optionalDouble = -0d;
+    assertFalse(m1.equals(m2));
+
+    m1.optionalDouble = -0d;
+    assertTrue(m1.equals(m2));
+    assertFalse(m1.equals(new TestAllTypesNano())); // -0 does not equals() the default +0
+    assertTrue(m1.equals(
+        MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+    // -------
+
+    TestAllTypesNanoHas m3 = new TestAllTypesNanoHas();
+    m3.optionalFloat = Float.NaN;
+    m3.hasOptionalFloat = true;
+    m3.optionalDouble = Double.NaN;
+    m3.hasOptionalDouble = true;
+    TestAllTypesNanoHas m4 = new TestAllTypesNanoHas();
+    m4.optionalFloat = Float.NaN;
+    m4.hasOptionalFloat = true;
+    m4.optionalDouble = Double.NaN;
+    m4.hasOptionalDouble = true;
+    assertTrue(m3.equals(m4));
+    assertTrue(m3.equals(
+        MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+
+    m3.optionalFloat = +0f;
+    m4.optionalFloat = -0f;
+    assertFalse(m3.equals(m4));
+
+    m3.optionalFloat = -0f;
+    m3.optionalDouble = +0d;
+    m4.optionalDouble = -0d;
+    assertFalse(m3.equals(m4));
+
+    m3.optionalDouble = -0d;
+    m3.hasOptionalFloat = false;  // -0 does not equals() the default +0,
+    m3.hasOptionalDouble = false; // so these incorrect 'has' flags should be disregarded.
+    assertTrue(m3.equals(m4));    // note: m4 has the 'has' flags set.
+    assertFalse(m3.equals(new TestAllTypesNanoHas())); // note: the new message has +0 defaults
+    assertTrue(m3.equals(
+        MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+                                  // note: the deserialized message has the 'has' flags set.
+
+    // -------
+
+    TestNanoAccessors m5 = new TestNanoAccessors();
+    m5.setOptionalFloat(Float.NaN);
+    m5.setOptionalDouble(Double.NaN);
+    TestNanoAccessors m6 = new TestNanoAccessors();
+    m6.setOptionalFloat(Float.NaN);
+    m6.setOptionalDouble(Double.NaN);
+    assertTrue(m5.equals(m6));
+    assertTrue(m5.equals(
+        MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+    m5.setOptionalFloat(+0f);
+    m6.setOptionalFloat(-0f);
+    assertFalse(m5.equals(m6));
+
+    m5.setOptionalFloat(-0f);
+    m5.setOptionalDouble(+0d);
+    m6.setOptionalDouble(-0d);
+    assertFalse(m5.equals(m6));
+
+    m5.setOptionalDouble(-0d);
+    assertTrue(m5.equals(m6));
+    assertFalse(m5.equals(new TestNanoAccessors()));
+    assertTrue(m5.equals(
+        MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+    // -------
+
+    NanoReferenceTypes.TestAllTypesNano m7 = new NanoReferenceTypes.TestAllTypesNano();
+    m7.optionalFloat = Float.NaN;
+    m7.optionalDouble = Double.NaN;
+    NanoReferenceTypes.TestAllTypesNano m8 = new NanoReferenceTypes.TestAllTypesNano();
+    m8.optionalFloat = Float.NaN;
+    m8.optionalDouble = Double.NaN;
+    assertTrue(m7.equals(m8));
+    assertTrue(m7.equals(MessageNano.mergeFrom(
+        new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+
+    m7.optionalFloat = +0f;
+    m8.optionalFloat = -0f;
+    assertFalse(m7.equals(m8));
+
+    m7.optionalFloat = -0f;
+    m7.optionalDouble = +0d;
+    m8.optionalDouble = -0d;
+    assertFalse(m7.equals(m8));
+
+    m7.optionalDouble = -0d;
+    assertTrue(m7.equals(m8));
+    assertFalse(m7.equals(new NanoReferenceTypes.TestAllTypesNano()));
+    assertTrue(m7.equals(MessageNano.mergeFrom(
+        new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+  }
+
+  private static TestAllTypesNano generateMessageForOneof(int caseNumber) {
+    TestAllTypesNano result = new TestAllTypesNano();
+    TestAllTypesNano.NestedMessage nested =
+        new TestAllTypesNano.NestedMessage();
+    nested.bb = 2;
+    switch (caseNumber) {
+      case TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER:
+        result.setOneofUint32(1);
+        break;
+      case TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER:
+        result.setOneofEnum(TestAllTypesNano.BAR);
+        break;
+      case TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER:
+        result.setOneofNestedMessage(nested);
+        break;
+      case TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER:
+        result.setOneofBytes(new byte[] {1, 2});
+        break;
+      case TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER:
+        result.setOneofString("hello");
+        break;
+      case TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER:
+        result.setOneofFixed64(-1L);
+        break;
+      default:
+        throw new RuntimeException("unexpected case number: " + caseNumber);
+    }
+    return result;
+  }
+
+  public void testOneofHashCodeEquals() throws Exception {
+    TestAllTypesNano m1 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+    assertEquals(m1, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER));
+    assertFalse(m1.equals(new TestAllTypesNano()));
+
+    TestAllTypesNano m2 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+    assertEquals(m2, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER));
+    assertFalse(m2.equals(new TestAllTypesNano()));
+
+    TestAllTypesNano m3 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+    assertEquals(m3, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER));
+    assertFalse(m3.equals(new TestAllTypesNano()));
+
+    TestAllTypesNano m4 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+    assertEquals(m4, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER));
+    assertFalse(m4.equals(new TestAllTypesNano()));
+
+    TestAllTypesNano m5 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+    assertEquals(m5, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER));
+    assertFalse(m5.equals(new TestAllTypesNano()));
+
+    TestAllTypesNano m6 = generateMessageForOneof(
+        TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+    assertEquals(m6, generateMessageForOneof(
+        TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER));
+    assertFalse(m6.equals(new TestAllTypesNano()));
+
+    Map<TestAllTypesNano, Integer> map =
+        new HashMap<TestAllTypesNano, Integer>();
+    map.put(m1, 1);
+    map.put(m2, 2);
+    map.put(m3, 3);
+    map.put(m4, 4);
+    map.put(m5, 5);
+    map.put(m6, 6);
+
+    assertEquals(6, map.size());
+  }
+
+  private void checkOneofCase(TestAllTypesNano nano, int field)
+      throws Exception {
+    assertEquals(field, nano.getOneofFieldCase());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER,
+        nano.hasOneofBytes());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER,
+        nano.hasOneofEnum());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER,
+        nano.hasOneofFixed64());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER,
+        nano.hasOneofNestedMessage());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER,
+        nano.hasOneofString());
+    assertEquals(
+        field == TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER,
+        nano.hasOneofUint32());
+
+  }
+
+  public void testOneofDefault() throws Exception {
+    TestAllTypesNano m1 = new TestAllTypesNano();
+    checkOneofCase(m1, 0);
+    assertEquals(WireFormatNano.EMPTY_BYTES, m1.getOneofBytes());
+    assertEquals(TestAllTypesNano.FOO, m1.getOneofEnum());
+    assertEquals(0L, m1.getOneofFixed64());
+    assertEquals(null, m1.getOneofNestedMessage());
+    assertEquals("", m1.getOneofString());
+    assertEquals(0, m1.getOneofUint32());
+  }
+
+  public void testOneofExclusiveness() throws Exception {
+    TestAllTypesNano m = new TestAllTypesNano();
+    checkOneofCase(m, 0);
+
+    m.setOneofBytes(new byte[]{0, 1});
+    checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+    assertTrue(Arrays.equals(new byte[]{0,  1}, m.getOneofBytes()));
+
+    m.setOneofEnum(TestAllTypesNano.BAZ);
+    checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+    assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+    assertEquals(WireFormatNano.EMPTY_BYTES, m.getOneofBytes());
+
+    m.setOneofFixed64(-1L);
+    checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+    assertEquals(-1L, m.getOneofFixed64());
+    assertEquals(TestAllTypesNano.FOO, m.getOneofEnum());
+
+    m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+    checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+    assertEquals(
+        new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+    assertEquals(0L, m.getOneofFixed64());
+
+    m.setOneofString("hello");
+    checkOneofCase(m, TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+    assertEquals("hello", m.getOneofString());
+    assertNull(m.getOneofNestedMessage());
+
+    m.setOneofUint32(10);
+    checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+    assertEquals(10, m.getOneofUint32());
+    assertEquals("", m.getOneofString());
+
+    m.setOneofBytes(new byte[]{0, 1});
+    checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+    assertTrue(Arrays.equals(new byte[]{0,  1}, m.getOneofBytes()));
+    assertEquals(0, m.getOneofUint32());
+  }
+
+  public void testOneofClear() throws Exception {
+    TestAllTypesNano m = new TestAllTypesNano();
+    m.setOneofBytes(new byte[]{0, 1});
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+
+    m.setOneofEnum(TestAllTypesNano.BAZ);
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+
+    m.setOneofFixed64(-1L);
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+
+    m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+
+    m.setOneofString("hello");
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+
+    m.setOneofUint32(10);
+    m.clearOneofField();
+    checkOneofCase(m, 0);
+  }
+
+  public void testOneofMarshaling() throws Exception {
+    TestAllTypesNano m = new TestAllTypesNano();
+    TestAllTypesNano parsed = new TestAllTypesNano();
+    {
+      m.setOneofBytes(new byte[]{0, 1});
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(parsed, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+      assertTrue(Arrays.equals(new byte[]{0, 1}, parsed.getOneofBytes()));
+    }
+    {
+      m.setOneofEnum(TestAllTypesNano.BAZ);
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+      assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+    }
+    {
+      m.setOneofEnum(TestAllTypesNano.BAZ);
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+      assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+    }
+    {
+      m.setOneofFixed64(-1L);
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+      assertEquals(-1L, m.getOneofFixed64());
+    }
+    {
+      m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+      assertEquals(
+          new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+    }
+    {
+      m.setOneofString("hello");
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      assertEquals("hello", m.getOneofString());
+      assertNull(m.getOneofNestedMessage());
+    }
+    {
+      m.setOneofUint32(10);
+      byte[] serialized = MessageNano.toByteArray(m);
+      MessageNano.mergeFrom(parsed, serialized);
+      checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+      assertEquals(10, m.getOneofUint32());
+    }
+  }
+
+  public void testOneofSerializedConcat() throws Exception {
+    TestAllTypesNano m1 = new TestAllTypesNano();
+    m1.setOneofBytes(new byte[] {0, 1});
+    byte[] b1 = MessageNano.toByteArray(m1);
+    TestAllTypesNano m2 = new TestAllTypesNano();
+    m2.setOneofEnum(TestAllTypesNano.BAZ);
+    byte[] b2 = MessageNano.toByteArray(m2);
+    byte[] b3 = new byte[b1.length + b2.length];
+    System.arraycopy(b1, 0, b3, 0, b1.length);
+    System.arraycopy(b2, 0, b3, b1.length, b2.length);
+    TestAllTypesNano parsed = new TestAllTypesNano();
+    MessageNano.mergeFrom(parsed, b3);
+    // the last on the wire wins.
+    checkOneofCase(parsed, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+    assertEquals(TestAllTypesNano.BAZ, parsed.getOneofEnum());
+  }
+
+  public void testNullRepeatedFields() throws Exception {
+    // Check that serialization after explicitly setting a repeated field
+    // to null doesn't NPE.
+    TestAllTypesNano message = new TestAllTypesNano();
+    message.repeatedInt32 = null;
+    MessageNano.toByteArray(message);  // should not NPE
+    message.toString(); // should not NPE
+
+    message.repeatedNestedEnum = null;
+    MessageNano.toByteArray(message);  // should not NPE
+    message.toString(); // should not NPE
+
+    message.repeatedBytes = null;
+    MessageNano.toByteArray(message); // should not NPE
+    message.toString(); // should not NPE
+
+    message.repeatedNestedMessage = null;
+    MessageNano.toByteArray(message); // should not NPE
+    message.toString(); // should not NPE
+
+    message.repeatedPackedInt32 = null;
+    MessageNano.toByteArray(message); // should not NPE
+    message.toString(); // should not NPE
+
+    message.repeatedPackedNestedEnum = null;
+    MessageNano.toByteArray(message); // should not NPE
+    message.toString(); // should not NPE
+
+    // Create a second message to merge into message.
+    TestAllTypesNano secondMessage = new TestAllTypesNano();
+    secondMessage.repeatedInt32 = new int[] {1, 2, 3};
+    secondMessage.repeatedNestedEnum = new int[] {
+      TestAllTypesNano.FOO, TestAllTypesNano.BAR
+    };
+    secondMessage.repeatedBytes = new byte[][] {{1, 2}, {3, 4}};
+    TestAllTypesNano.NestedMessage nested =
+        new TestAllTypesNano.NestedMessage();
+    nested.bb = 55;
+    secondMessage.repeatedNestedMessage =
+        new TestAllTypesNano.NestedMessage[] {nested};
+    secondMessage.repeatedPackedInt32 = new int[] {1, 2, 3};
+    secondMessage.repeatedPackedNestedEnum = new int[] {
+        TestAllTypesNano.FOO, TestAllTypesNano.BAR
+      };
+
+    // Should not NPE
+    message.mergeFrom(CodedInputByteBufferNano.newInstance(
+        MessageNano.toByteArray(secondMessage)));
+    assertEquals(3, message.repeatedInt32.length);
+    assertEquals(3, message.repeatedInt32[2]);
+    assertEquals(2, message.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.FOO, message.repeatedNestedEnum[0]);
+    assertEquals(2, message.repeatedBytes.length);
+    assertEquals(4, message.repeatedBytes[1][1]);
+    assertEquals(1, message.repeatedNestedMessage.length);
+    assertEquals(55, message.repeatedNestedMessage[0].bb);
+    assertEquals(3, message.repeatedPackedInt32.length);
+    assertEquals(2, message.repeatedPackedInt32[1]);
+    assertEquals(2, message.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.BAR, message.repeatedPackedNestedEnum[1]);
+  }
+
+  public void testNullRepeatedFieldElements() throws Exception {
+    // Check that serialization with null array elements doesn't NPE.
+    String string1 = "1";
+    String string2 = "2";
+    byte[] bytes1 = {3, 4};
+    byte[] bytes2 = {5, 6};
+    TestAllTypesNano.NestedMessage msg1 = new TestAllTypesNano.NestedMessage();
+    msg1.bb = 7;
+    TestAllTypesNano.NestedMessage msg2 = new TestAllTypesNano.NestedMessage();
+    msg2.bb = 8;
+
+    TestAllTypesNano message = new TestAllTypesNano();
+    message.repeatedString = new String[] {null, string1, string2};
+    message.repeatedBytes = new byte[][] {bytes1, null, bytes2};
+    message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {msg1, msg2, null};
+    message.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] {null, null, null};
+
+    byte[] serialized = MessageNano.toByteArray(message); // should not NPE
+    TestAllTypesNano deserialized = MessageNano.mergeFrom(new TestAllTypesNano(), serialized);
+    assertEquals(2, deserialized.repeatedString.length);
+    assertEquals(string1, deserialized.repeatedString[0]);
+    assertEquals(string2, deserialized.repeatedString[1]);
+    assertEquals(2, deserialized.repeatedBytes.length);
+    assertTrue(Arrays.equals(bytes1, deserialized.repeatedBytes[0]));
+    assertTrue(Arrays.equals(bytes2, deserialized.repeatedBytes[1]));
+    assertEquals(2, deserialized.repeatedNestedMessage.length);
+    assertEquals(msg1.bb, deserialized.repeatedNestedMessage[0].bb);
+    assertEquals(msg2.bb, deserialized.repeatedNestedMessage[1].bb);
+    assertEquals(0, deserialized.repeatedGroup.length);
+  }
+
+  public void testRepeatedMerge() throws Exception {
+    // Check that merging repeated fields cause the arrays to expand with
+    // new data.
+    TestAllTypesNano first = new TestAllTypesNano();
+    first.repeatedInt32 = new int[] {1, 2, 3};
+    TestAllTypesNano second = new TestAllTypesNano();
+    second.repeatedInt32 = new int[] {4, 5};
+    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+    assertEquals(5, first.repeatedInt32.length);
+    assertEquals(1, first.repeatedInt32[0]);
+    assertEquals(4, first.repeatedInt32[3]);
+
+    first = new TestAllTypesNano();
+    first.repeatedNestedEnum = new int[] {TestAllTypesNano.BAR};
+    second = new TestAllTypesNano();
+    second.repeatedNestedEnum = new int[] {TestAllTypesNano.FOO};
+    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+    assertEquals(2, first.repeatedNestedEnum.length);
+    assertEquals(TestAllTypesNano.BAR, first.repeatedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.FOO, first.repeatedNestedEnum[1]);
+
+    first = new TestAllTypesNano();
+    first.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+      new TestAllTypesNano.NestedMessage()
+    };
+    first.repeatedNestedMessage[0].bb = 3;
+    second = new TestAllTypesNano();
+    second.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+      new TestAllTypesNano.NestedMessage()
+    };
+    second.repeatedNestedMessage[0].bb = 5;
+    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+    assertEquals(2, first.repeatedNestedMessage.length);
+    assertEquals(3, first.repeatedNestedMessage[0].bb);
+    assertEquals(5, first.repeatedNestedMessage[1].bb);
+
+    first = new TestAllTypesNano();
+    first.repeatedPackedSfixed64 = new long[] {-1, -2, -3};
+    second = new TestAllTypesNano();
+    second.repeatedPackedSfixed64 = new long[] {-4, -5};
+    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+    assertEquals(5, first.repeatedPackedSfixed64.length);
+    assertEquals(-1, first.repeatedPackedSfixed64[0]);
+    assertEquals(-4, first.repeatedPackedSfixed64[3]);
+
+    first = new TestAllTypesNano();
+    first.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.BAR};
+    second = new TestAllTypesNano();
+    second.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.FOO};
+    MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+    assertEquals(2, first.repeatedPackedNestedEnum.length);
+    assertEquals(TestAllTypesNano.BAR, first.repeatedPackedNestedEnum[0]);
+    assertEquals(TestAllTypesNano.FOO, first.repeatedPackedNestedEnum[1]);
+
+    // Now test repeated merging in a nested scope
+    TestRepeatedMergeNano firstContainer = new TestRepeatedMergeNano();
+    firstContainer.contained = new TestAllTypesNano();
+    firstContainer.contained.repeatedInt32 = new int[] {10, 20};
+    TestRepeatedMergeNano secondContainer = new TestRepeatedMergeNano();
+    secondContainer.contained = new TestAllTypesNano();
+    secondContainer.contained.repeatedInt32 = new int[] {30};
+    MessageNano.mergeFrom(firstContainer, MessageNano.toByteArray(secondContainer));
+    assertEquals(3, firstContainer.contained.repeatedInt32.length);
+    assertEquals(20, firstContainer.contained.repeatedInt32[1]);
+    assertEquals(30, firstContainer.contained.repeatedInt32[2]);
+  }
+
+  public void testRepeatedPackables() throws Exception {
+    // Check that repeated fields with packable types can accept both packed and unpacked
+    // serialized forms.
+    NanoRepeatedPackables.NonPacked nonPacked = new NanoRepeatedPackables.NonPacked();
+    // Exaggerates the first values of varint-typed arrays. This is to test that the parsing code
+    // of packed fields handles non-packed data correctly. If the code incorrectly thinks it is
+    // reading from a packed tag, it will read the first value as the byte length of the field,
+    // and the large number will cause the input to go out of bounds, thus capturing the error.
+    nonPacked.int32S = new int[] {1000, 2, 3};
+    nonPacked.int64S = new long[] {4000, 5, 6};
+    nonPacked.uint32S = new int[] {7000, 8, 9};
+    nonPacked.uint64S = new long[] {10000, 11, 12};
+    nonPacked.sint32S = new int[] {13000, 14, 15};
+    nonPacked.sint64S = new long[] {16000, 17, 18};
+    nonPacked.fixed32S = new int[] {19, 20, 21};
+    nonPacked.fixed64S = new long[] {22, 23, 24};
+    nonPacked.sfixed32S = new int[] {25, 26, 27};
+    nonPacked.sfixed64S = new long[] {28, 29, 30};
+    nonPacked.floats = new float[] {31, 32, 33};
+    nonPacked.doubles = new double[] {34, 35, 36};
+    nonPacked.bools = new boolean[] {false, true};
+    nonPacked.enums = new int[] {
+      NanoRepeatedPackables.Enum.OPTION_ONE,
+      NanoRepeatedPackables.Enum.OPTION_TWO,
+    };
+    nonPacked.noise = 13579;
+
+    byte[] nonPackedSerialized = MessageNano.toByteArray(nonPacked);
+
+    NanoRepeatedPackables.Packed packed =
+        MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), nonPackedSerialized);
+    assertRepeatedPackablesEqual(nonPacked, packed);
+
+    byte[] packedSerialized = MessageNano.toByteArray(packed);
+    // Just a cautious check that the two serialized forms are different,
+    // to make sure the remaining of this test is useful:
+    assertFalse(Arrays.equals(nonPackedSerialized, packedSerialized));
+
+    nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), packedSerialized);
+    assertRepeatedPackablesEqual(nonPacked, packed);
+
+    // Test mixed serialized form.
+    byte[] mixedSerialized = new byte[nonPackedSerialized.length + packedSerialized.length];
+    System.arraycopy(nonPackedSerialized, 0, mixedSerialized, 0, nonPackedSerialized.length);
+    System.arraycopy(packedSerialized, 0,
+        mixedSerialized, nonPackedSerialized.length, packedSerialized.length);
+
+    nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), mixedSerialized);
+    packed = MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), mixedSerialized);
+    assertRepeatedPackablesEqual(nonPacked, packed);
+    assertTrue(Arrays.equals(new int[] {1000, 2, 3, 1000, 2, 3}, nonPacked.int32S));
+    assertTrue(Arrays.equals(new int[] {13000, 14, 15, 13000, 14, 15}, nonPacked.sint32S));
+    assertTrue(Arrays.equals(new int[] {25, 26, 27, 25, 26, 27}, nonPacked.sfixed32S));
+    assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
+  }
+
+  public void testMapsSerializeAndParse() throws Exception {
+    TestMap origin = new TestMap();
+    setMapMessage(origin);
+    assertMapMessageSet(origin);
+
+    byte[] output = MessageNano.toByteArray(origin);
+    TestMap parsed = new TestMap();
+    MessageNano.mergeFrom(parsed, output);
+  }
+
+  public void testMapSerializeRejectNull() throws Exception {
+    TestMap primitiveMap = new TestMap();
+    primitiveMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+    primitiveMap.int32ToInt32Field.put(null, 1);
+    try {
+      MessageNano.toByteArray(primitiveMap);
+      fail("should reject null keys");
+    } catch (IllegalStateException e) {
+      // pass.
+    }
+
+    TestMap messageMap = new TestMap();
+    messageMap.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    messageMap.int32ToMessageField.put(0, null);
+    try {
+      MessageNano.toByteArray(messageMap);
+      fail("should reject null values");
+    } catch (IllegalStateException e) {
+      // pass.
+    }
+  }
+
+  /**
+   * Tests that merging bytes containing conflicting keys with override the
+   * message value instead of merging the message value into the existing entry.
+   */
+  public void testMapMergeOverrideMessageValues() throws Exception {
+    TestMap.MessageValue origValue = new TestMap.MessageValue();
+    origValue.value = 1;
+    origValue.value2 = 2;
+    TestMap.MessageValue newValue = new TestMap.MessageValue();
+    newValue.value = 3;
+
+    TestMap origMessage = new TestMap();
+    origMessage.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    origMessage.int32ToMessageField.put(1, origValue);
+
+    TestMap newMessage = new TestMap();
+    newMessage.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    newMessage.int32ToMessageField.put(1, newValue);
+    MessageNano.mergeFrom(origMessage,
+        MessageNano.toByteArray(newMessage));
+    TestMap.MessageValue mergedValue = origMessage.int32ToMessageField.get(1);
+    assertEquals(3, mergedValue.value);
+    assertEquals(0, mergedValue.value2);
+  }
+
+  /**
+   * Tests that when merging with empty entries,
+   * we will use default for the key and value, instead of null.
+   */
+  public void testMapMergeEmptyEntry() throws Exception {
+    TestMap testMap = new TestMap();
+    byte[] buffer = new byte[1024];
+    CodedOutputByteBufferNano output =
+        CodedOutputByteBufferNano.newInstance(buffer);
+    // An empty entry for int32_to_int32 map.
+    output.writeTag(1, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(0);
+    // An empty entry for int32_to_message map.
+    output.writeTag(5, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+    output.writeRawVarint32(0);
+
+    CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(
+        buffer, 0, buffer.length - output.spaceLeft());
+    testMap.mergeFrom(input);
+    assertNotNull(testMap.int32ToInt32Field);;
+    assertEquals(1, testMap.int32ToInt32Field.size());
+    assertEquals(Integer.valueOf(0), testMap.int32ToInt32Field.get(0));
+    assertNotNull(testMap.int32ToMessageField);
+    assertEquals(1, testMap.int32ToMessageField.size());
+    TestMap.MessageValue messageValue = testMap.int32ToMessageField.get(0);
+    assertNotNull(messageValue);
+    assertEquals(0, messageValue.value);
+    assertEquals(0, messageValue.value2);
+  }
+
+  public void testMapEquals() throws Exception {
+    TestMap a = new TestMap();
+    TestMap b = new TestMap();
+
+    // empty and null map fields are equal.
+    assertTestMapEqual(a, b);
+    a.int32ToBytesField = new HashMap<Integer, byte[]>();
+    assertTestMapEqual(a, b);
+
+    a.int32ToInt32Field = new HashMap<Integer, Integer>();
+    b.int32ToInt32Field = new HashMap<Integer, Integer>();
+    setMap(a.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+    setMap(b.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+    assertTestMapEqual(a, b);
+
+    a.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    b.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    setMap(a.int32ToMessageField,
+        deepCopy(int32Values), deepCopy(messageValues));
+    setMap(b.int32ToMessageField,
+        deepCopy(int32Values), deepCopy(messageValues));
+    assertTestMapEqual(a, b);
+
+    a.stringToInt32Field = new HashMap<String, Integer>();
+    b.stringToInt32Field = new HashMap<String, Integer>();
+    setMap(a.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+    setMap(b.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+    assertTestMapEqual(a, b);
+
+    a.int32ToBytesField = new HashMap<Integer, byte[]>();
+    b.int32ToBytesField = new HashMap<Integer, byte[]>();
+    setMap(a.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+    setMap(b.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+    assertTestMapEqual(a, b);
+
+    // Make sure the map implementation does not matter.
+    a.int32ToStringField = new TreeMap<Integer, String>();
+    b.int32ToStringField = new HashMap<Integer, String>();
+    setMap(a.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+    setMap(b.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+    assertTestMapEqual(a, b);
+
+    a.clear();
+    b.clear();
+
+    // unequal cases: different value
+    a.int32ToInt32Field = new HashMap<Integer, Integer>();
+    b.int32ToInt32Field = new HashMap<Integer, Integer>();
+    a.int32ToInt32Field.put(1, 1);
+    b.int32ToInt32Field.put(1, 2);
+    assertTestMapUnequal(a, b);
+    // unequal case: additional entry
+    b.int32ToInt32Field.put(1, 1);
+    b.int32ToInt32Field.put(2, 1);
+    assertTestMapUnequal(a, b);
+    a.int32ToInt32Field.put(2, 1);
+    assertTestMapEqual(a, b);
+
+    // unequal case: different message value.
+    a.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    b.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    MessageValue va = new MessageValue();
+    va.value = 1;
+    MessageValue vb = new MessageValue();
+    vb.value = 1;
+    a.int32ToMessageField.put(1, va);
+    b.int32ToMessageField.put(1, vb);
+    assertTestMapEqual(a, b);
+    vb.value = 2;
+    assertTestMapUnequal(a, b);
+  }
+
+  private static void assertTestMapEqual(TestMap a, TestMap b)
+      throws Exception {
+    assertEquals(a.hashCode(), b.hashCode());
+    assertTrue(a.equals(b));
+    assertTrue(b.equals(a));
+  }
+
+  private static void assertTestMapUnequal(TestMap a, TestMap b)
+      throws Exception {
+    assertFalse(a.equals(b));
+    assertFalse(b.equals(a));
+  }
+
+  private static final Integer[] int32Values = new Integer[] {
+    0, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE,
+  };
+
+  private static final Long[] int64Values = new Long[] {
+    0L, 1L, -1L, Long.MAX_VALUE, Long.MIN_VALUE,
+  };
+
+  private static final String[] stringValues = new String[] {
+    "", "hello", "world", "foo", "bar",
+  };
+
+  private static final byte[][] bytesValues = new byte[][] {
+    new byte[] {},
+    new byte[] {0},
+    new byte[] {1, -1},
+    new byte[] {127, -128},
+    new byte[] {'a', 'b', '0', '1'},
+  };
+
+  private static final Boolean[] boolValues = new Boolean[] {
+    false, true,
+  };
+
+  private static final Integer[] enumValues = new Integer[] {
+    TestMap.FOO, TestMap.BAR, TestMap.BAZ, TestMap.QUX,
+    Integer.MAX_VALUE /* unknown */,
+  };
+
+  private static final TestMap.MessageValue[] messageValues =
+      new TestMap.MessageValue[] {
+    newMapValueMessage(0),
+    newMapValueMessage(1),
+    newMapValueMessage(-1),
+    newMapValueMessage(Integer.MAX_VALUE),
+    newMapValueMessage(Integer.MIN_VALUE),
+  };
+
+  private static TestMap.MessageValue newMapValueMessage(int value) {
+    TestMap.MessageValue result = new TestMap.MessageValue();
+    result.value = value;
+    return result;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static <T> T[] deepCopy(T[] orig) throws Exception {
+    if (orig instanceof MessageValue[]) {
+      MessageValue[] result = new MessageValue[orig.length];
+      for (int i = 0; i < orig.length; i++) {
+        result[i] = new MessageValue();
+        MessageNano.mergeFrom(
+            result[i], MessageNano.toByteArray((MessageValue) orig[i]));
+      }
+      return (T[]) result;
+    }
+    if (orig instanceof byte[][]) {
+      byte[][] result = new byte[orig.length][];
+      for (int i = 0; i < orig.length; i++) {
+        byte[] origBytes = (byte[]) orig[i];
+        result[i] = Arrays.copyOf(origBytes, origBytes.length);
+      }
+    }
+    return Arrays.copyOf(orig, orig.length);
+  }
+
+  private <K, V> void setMap(Map<K, V> map, K[] keys, V[] values) {
+    assert(keys.length == values.length);
+    for (int i = 0; i < keys.length; i++) {
+      map.put(keys[i], values[i]);
+    }
+  }
+
+  private <K, V> void assertMapSet(
+      Map<K, V> map, K[] keys, V[] values) throws Exception {
+    assert(keys.length == values.length);
+    for (int i = 0; i < values.length; i++) {
+      assertEquals(values[i], map.get(keys[i]));
+    }
+    assertEquals(keys.length, map.size());
+  }
+
+  private void setMapMessage(TestMap testMap) {
+    testMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+    testMap.int32ToBytesField = new HashMap<Integer, byte[]>();
+    testMap.int32ToEnumField = new HashMap<Integer, Integer>();
+    testMap.int32ToMessageField =
+        new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+    testMap.int32ToStringField = new HashMap<Integer, String>();
+    testMap.stringToInt32Field = new HashMap<String, Integer>();
+    testMap.boolToBoolField = new HashMap<Boolean, Boolean>();
+    testMap.uint32ToUint32Field = new HashMap<Integer, Integer>();
+    testMap.sint32ToSint32Field = new HashMap<Integer, Integer>();
+    testMap.fixed32ToFixed32Field = new HashMap<Integer, Integer>();
+    testMap.sfixed32ToSfixed32Field = new HashMap<Integer, Integer>();
+    testMap.int64ToInt64Field = new HashMap<Long, Long>();
+    testMap.uint64ToUint64Field = new HashMap<Long, Long>();
+    testMap.sint64ToSint64Field = new HashMap<Long, Long>();
+    testMap.fixed64ToFixed64Field = new HashMap<Long, Long>();
+    testMap.sfixed64ToSfixed64Field = new HashMap<Long, Long>();
+    setMap(testMap.int32ToInt32Field, int32Values, int32Values);
+    setMap(testMap.int32ToBytesField, int32Values, bytesValues);
+    setMap(testMap.int32ToEnumField, int32Values, enumValues);
+    setMap(testMap.int32ToMessageField, int32Values, messageValues);
+    setMap(testMap.int32ToStringField, int32Values, stringValues);
+    setMap(testMap.stringToInt32Field, stringValues, int32Values);
+    setMap(testMap.boolToBoolField, boolValues, boolValues);
+    setMap(testMap.uint32ToUint32Field, int32Values, int32Values);
+    setMap(testMap.sint32ToSint32Field, int32Values, int32Values);
+    setMap(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+    setMap(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+    setMap(testMap.int64ToInt64Field, int64Values, int64Values);
+    setMap(testMap.uint64ToUint64Field, int64Values, int64Values);
+    setMap(testMap.sint64ToSint64Field, int64Values, int64Values);
+    setMap(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+    setMap(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+  }
+  private void assertMapMessageSet(TestMap testMap) throws Exception {
+    assertMapSet(testMap.int32ToInt32Field, int32Values, int32Values);
+    assertMapSet(testMap.int32ToBytesField, int32Values, bytesValues);
+    assertMapSet(testMap.int32ToEnumField, int32Values, enumValues);
+    assertMapSet(testMap.int32ToMessageField, int32Values, messageValues);
+    assertMapSet(testMap.int32ToStringField, int32Values, stringValues);
+    assertMapSet(testMap.stringToInt32Field, stringValues, int32Values);
+    assertMapSet(testMap.boolToBoolField, boolValues, boolValues);
+    assertMapSet(testMap.uint32ToUint32Field, int32Values, int32Values);
+    assertMapSet(testMap.sint32ToSint32Field, int32Values, int32Values);
+    assertMapSet(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+    assertMapSet(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+    assertMapSet(testMap.int64ToInt64Field, int64Values, int64Values);
+    assertMapSet(testMap.uint64ToUint64Field, int64Values, int64Values);
+    assertMapSet(testMap.sint64ToSint64Field, int64Values, int64Values);
+    assertMapSet(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+    assertMapSet(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+  }
+
+  public void testRepeatedFieldInitializedInReftypesCompatMode() {
+    NanoReferenceTypesCompat.TestAllTypesNano proto = new NanoReferenceTypesCompat.TestAllTypesNano();
+    assertNotNull(proto.repeatedString);
+  }
+
+  private void assertRepeatedPackablesEqual(
+      NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
+    // Not using MessageNano.equals() -- that belongs to a separate test.
+    assertTrue(Arrays.equals(nonPacked.int32S, packed.int32S));
+    assertTrue(Arrays.equals(nonPacked.int64S, packed.int64S));
+    assertTrue(Arrays.equals(nonPacked.uint32S, packed.uint32S));
+    assertTrue(Arrays.equals(nonPacked.uint64S, packed.uint64S));
+    assertTrue(Arrays.equals(nonPacked.sint32S, packed.sint32S));
+    assertTrue(Arrays.equals(nonPacked.sint64S, packed.sint64S));
+    assertTrue(Arrays.equals(nonPacked.fixed32S, packed.fixed32S));
+    assertTrue(Arrays.equals(nonPacked.fixed64S, packed.fixed64S));
+    assertTrue(Arrays.equals(nonPacked.sfixed32S, packed.sfixed32S));
+    assertTrue(Arrays.equals(nonPacked.sfixed64S, packed.sfixed64S));
+    assertTrue(Arrays.equals(nonPacked.floats, packed.floats));
+    assertTrue(Arrays.equals(nonPacked.doubles, packed.doubles));
+    assertTrue(Arrays.equals(nonPacked.bools, packed.bools));
+    assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
+  }
+
+  public void testClone() throws Exception {
+    // A simple message.
+    AnotherMessage anotherMessage = new AnotherMessage();
+    anotherMessage.string = "Hello";
+    anotherMessage.value = true;
+    anotherMessage.integers = new int[] { 1, 2, 3 };
+
+    AnotherMessage clone = anotherMessage.clone();
+    assertEquals(clone, anotherMessage);
+
+    // Verify it was a deep clone - changes to the clone shouldn't affect the
+    // original.
+    clone.integers[1] = 100;
+    assertFalse(clone.equals(anotherMessage));
+  }
+
+  public void testBytesOffsetLength() throws Exception {
+    BytesOffsetLengthTestNano msg = new BytesOffsetLengthTestNano();
+    msg.fooBuffer = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    msg.fooOffset = 2;
+    msg.fooLength = 3;
+    msg.barBuffer = msg.fooBuffer;
+    msg.barOffset = 7;
+    msg.barLength = 1;
+
+    byte[] bytes = MessageNano.toByteArray(msg);
+    // Two tags + two lengths + the arrays
+    assertEquals("Unexpected size of encoded proto", 8, bytes.length);
+
+    msg = BytesOffsetLengthTestNano.parseFrom(bytes);
+    byte[] foo = new byte[msg.fooLength];
+    System.arraycopy(msg.fooBuffer, msg.fooOffset, foo, 0, msg.fooLength);
+    assertTrue("foo was not deserialized correctly", Arrays.equals(new byte[] { 2, 3, 4 }, foo));
+    byte[] bar = new byte[msg.barLength];
+    System.arraycopy(msg.barBuffer, msg.barOffset, bar, 0, msg.barLength);
+    assertTrue("bar was not deserialized correctly", Arrays.equals(new byte[] { 7 }, bar));
+  }
+
+  public void testUnknownOptionalEnumValue() throws Exception {
+    StandardVersion standardMsg = new StandardVersion();
+    standardMsg.optionalField = StandardVersion.VAL_3;
+    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
+
+    // When parsing and reading, the unknown value appears as UNKNOWN.
+    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
+    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
+    assertEquals(VersionWithoutVal3.UNKNOWN, withoutVal3Msg.optionalField);
+
+    // When serializing and reparsing as the standard version, the old, unknown value wins out (even
+    // if a new one is set).
+    withoutVal3Msg.optionalField = VersionWithoutVal3.VAL_2;
+    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
+    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
+    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
+    assertEquals(StandardVersion.VAL_3, standardMsgFromWithoutVal3Msg.optionalField);
+  }
+
+  public void testUnknownRepeatedEnumValue() throws Exception {
+    StandardVersion standardMsg = new StandardVersion();
+    standardMsg.repeatedField = new int[] { StandardVersion.VAL_3, StandardVersion.VAL_2 };
+    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
+
+    // When parsing and reading, the unknown value is stripped out.
+    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
+    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
+    assertTrue(Arrays.equals(new int[] { VersionWithoutVal3.VAL_2 }, withoutVal3Msg.repeatedField));
+
+    // When serializing and reparsing as the standard version, the old, unknown value reappears, but
+    // at the end of all entries (including any newly added ones).
+    withoutVal3Msg.repeatedField = new int[] { VersionWithoutVal3.VAL_2, VersionWithoutVal3.VAL_1 };
+    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
+    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
+    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
+    assertTrue(Arrays.equals(
+            new int[] { StandardVersion.VAL_2, StandardVersion.VAL_1, StandardVersion.VAL_3 },
+            standardMsgFromWithoutVal3Msg.repeatedField));
+  }
+
+  public void testUnknownRepeatedPackedEnumValue() throws Exception {
+    StandardVersion standardMsg = new StandardVersion();
+    standardMsg.packedField = new int[] { StandardVersion.VAL_3, StandardVersion.VAL_2 };
+    byte[] standardMsgBytes = MessageNano.toByteArray(standardMsg);
+
+    // When parsing and reading, the unknown value is stripped out.
+    VersionWithoutVal3 withoutVal3Msg = new VersionWithoutVal3();
+    MessageNano.mergeFrom(withoutVal3Msg, standardMsgBytes);
+    assertTrue(Arrays.equals(new int[] { VersionWithoutVal3.VAL_2 }, withoutVal3Msg.packedField));
+
+    // When serializing and reparsing as the standard version, the old, unknown value reappears, but
+    // at the end of all entries (including any newly added ones).
+    withoutVal3Msg.packedField = new int[] { VersionWithoutVal3.VAL_2, VersionWithoutVal3.VAL_1 };
+    byte[] withoutVal3MsgBytes = MessageNano.toByteArray(withoutVal3Msg);
+    StandardVersion standardMsgFromWithoutVal3Msg = new StandardVersion();
+    MessageNano.mergeFrom(standardMsgFromWithoutVal3Msg, withoutVal3MsgBytes);
+    assertTrue(Arrays.equals(
+            new int[] { StandardVersion.VAL_2, StandardVersion.VAL_1, StandardVersion.VAL_3 },
+            standardMsgFromWithoutVal3Msg.packedField));
+  }
+
+  private void assertHasWireData(MessageNano message, boolean expected) {
+    byte[] bytes = MessageNano.toByteArray(message);
+    int wireLength = bytes.length;
+    if (expected) {
+      assertFalse(wireLength == 0);
+    } else {
+      if (wireLength != 0) {
+        fail("Expected no wire data for message \n" + message
+            + "\nBut got:\n"
+            + hexDump(bytes));
+      }
+    }
+  }
+
+  private static String hexDump(byte[] bytes) {
+    StringBuilder sb = new StringBuilder();
+    for (byte b : bytes) {
+      sb.append(String.format("%02x ", b));
+    }
+    return sb.toString();
+  }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/map_test.proto b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
new file mode 100644
index 0000000..51498a4
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
@@ -0,0 +1,70 @@
+// 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.
+
+syntax = "proto3";
+
+package map_test;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "MapTestProto";
+
+message TestMap {
+  message MessageValue {
+    int32 value = 1;
+    int32 value2 = 2;
+  }
+  enum EnumValue {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+
+  map<int32, int32>        int32_to_int32_field = 1;
+  map<int32, string>       int32_to_string_field = 2;
+  map<int32, bytes>        int32_to_bytes_field = 3;
+  map<int32, EnumValue>    int32_to_enum_field = 4;
+  map<int32, MessageValue> int32_to_message_field = 5;
+  map<string, int32>       string_to_int32_field = 6;
+  map<bool, bool>          bool_to_bool_field = 7;
+
+  // Test all the other primitive types. As the key and value are not coupled in
+  // the implementation, we do not test all the combinations of key/value pairs,
+  // so that we can keep the number of test cases manageable
+  map<uint32, uint32>      uint32_to_uint32_field = 11;
+  map<sint32, sint32>      sint32_to_sint32_field = 12;
+  map<fixed32, fixed32>    fixed32_to_fixed32_field = 13;
+  map<sfixed32, sfixed32>  sfixed32_to_sfixed32_field = 14;
+  map<int64, int64>        int64_to_int64_field = 15;
+  map<uint64, uint64>      uint64_to_uint64_field = 16;
+  map<sint64, sint64>      sint64_to_sint64_field = 17;
+  map<fixed64, fixed64>    fixed64_to_fixed64_field = 18;
+  map<sfixed64, sfixed64>  sfixed64_to_sfixed64_field = 19;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
new file mode 100644
index 0000000..6511e47
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
@@ -0,0 +1,118 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "NanoAccessorsOuterClass";
+
+message TestNanoAccessors {
+
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional int32  optional_int32    =  1;
+  optional float  optional_float    = 11;
+  optional double optional_double   = 12;
+  optional string optional_string   = 14;
+  optional bytes  optional_bytes    = 15;
+
+  optional NestedMessage optional_nested_message = 18;
+
+  optional NestedEnum optional_nested_enum = 21;
+
+  // Repeated
+  repeated int32  repeated_int32    = 31;
+  repeated string repeated_string   = 44;
+  repeated bytes  repeated_bytes    = 45;
+
+  repeated NestedMessage repeated_nested_message  = 48;
+
+  repeated NestedEnum repeated_nested_enum  = 51;
+
+  // Singular with defaults
+  optional int32  default_int32    = 61 [default =  41    ];
+  optional string default_string   = 74 [default = "hello"];
+  optional bytes  default_bytes    = 75 [default = "world"];
+
+  optional float default_float_nan = 99  [default =  nan];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+  // Required
+  required int32 id = 86;
+
+  // Add enough optional fields to make 2 bit fields in total
+  optional int32 filler100 = 100;
+  optional int32 filler101 = 101;
+  optional int32 filler102 = 102;
+  optional int32 filler103 = 103;
+  optional int32 filler104 = 104;
+  optional int32 filler105 = 105;
+  optional int32 filler106 = 106;
+  optional int32 filler107 = 107;
+  optional int32 filler108 = 108;
+  optional int32 filler109 = 109;
+  optional int32 filler110 = 110;
+  optional int32 filler111 = 111;
+  optional int32 filler112 = 112;
+  optional int32 filler113 = 113;
+  optional int32 filler114 = 114;
+  optional int32 filler115 = 115;
+  optional int32 filler116 = 116;
+  optional int32 filler117 = 117;
+  optional int32 filler118 = 118;
+  optional int32 filler119 = 119;
+  optional int32 filler120 = 120;
+  optional int32 filler121 = 121;
+  optional int32 filler122 = 122;
+  optional int32 filler123 = 123;
+  optional int32 filler124 = 124;
+  optional int32 filler125 = 125;
+  optional int32 filler126 = 126;
+  optional int32 filler127 = 127;
+  optional int32 filler128 = 128;
+  optional int32 filler129 = 129;
+  optional int32 filler130 = 130;
+
+  optional int32 before_bit_field_check = 139;
+  optional int32 bit_field_check = 140;
+  optional int32 after_bit_field_check = 141;
+}
diff --git a/src/google/protobuf/unittest_bytes_offset_length_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_bytes_offset_length_nano.proto
similarity index 100%
rename from src/google/protobuf/unittest_bytes_offset_length_nano.proto
rename to javanano/src/test/java/com/google/protobuf/nano/unittest_bytes_offset_length_nano.proto
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
new file mode 100644
index 0000000..958e1f1
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
@@ -0,0 +1,48 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_multiple_files = true;
+
+enum FileScopeEnumMultiple {
+  THREE = 3;
+}
+
+message EnumClassNanoMultiple {
+  enum MessageScopeEnumMultiple {
+    FOUR = 4;
+  }
+  optional FileScopeEnumMultiple three = 3 [ default = THREE ];
+  optional MessageScopeEnumMultiple four = 4 [ default = FOUR ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
new file mode 100644
index 0000000..3a1e07f
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
@@ -0,0 +1,48 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EnumClassNanos";
+
+enum FileScopeEnum {
+  ONE = 1;
+}
+
+message EnumClassNano {
+  enum MessageScopeEnum {
+    TWO = 2;
+  }
+  optional FileScopeEnum one = 1 [ default = ONE ];
+  optional MessageScopeEnum two = 2 [ default = TWO ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
new file mode 100644
index 0000000..c0da8b4
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
@@ -0,0 +1,28 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EnumValidity";
+
+enum E {
+  default = 1; // test java keyword renaming
+  FOO = 2;
+  BAR = 3;
+  BAZ = 4;
+}
+
+message M {
+  optional E optional_e = 1;
+  optional E default_e = 2 [ default = BAZ ];
+  repeated E repeated_e = 3;
+  repeated E packed_e = 4 [ packed = true ];
+  repeated E repeated_e2 = 5;
+  repeated E packed_e2 = 6 [ packed = true ];
+  repeated E repeated_e3 = 7;
+  repeated E packed_e3 = 8 [ packed = true ];
+}
+
+message Alt {
+  optional E repeated_e2_as_optional = 5;
+  repeated E packed_e2_as_non_packed = 6;
+  repeated E non_packed_e3_as_packed = 7 [ packed = true ];
+}
diff --git a/src/google/protobuf/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
similarity index 100%
rename from src/google/protobuf/unittest_extension_nano.proto
rename to javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
new file mode 100644
index 0000000..3b7a004
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message PackedExtensions {
+  extend ExtendableMessage {
+    repeated int32    packed_int32    = 10 [ packed = true ];
+    repeated uint32   packed_uint32   = 11 [ packed = true ];
+    repeated sint32   packed_sint32   = 12 [ packed = true ];
+    repeated int64    packed_int64    = 13 [ packed = true ];
+    repeated uint64   packed_uint64   = 14 [ packed = true ];
+    repeated sint64   packed_sint64   = 15 [ packed = true ];
+    repeated fixed32  packed_fixed32  = 16 [ packed = true ];
+    repeated sfixed32 packed_sfixed32 = 17 [ packed = true ];
+    repeated fixed64  packed_fixed64  = 18 [ packed = true ];
+    repeated sfixed64 packed_sfixed64 = 19 [ packed = true ];
+    repeated bool     packed_bool     = 20 [ packed = true ];
+    repeated float    packed_float    = 21 [ packed = true ];
+    repeated double   packed_double   = 22 [ packed = true ];
+    repeated AnEnum   packed_enum     = 23 [ packed = true ];
+    // Non-packable types omitted.
+  }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
new file mode 100644
index 0000000..e533c65
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message RepeatedExtensions {
+  extend ExtendableMessage {
+    repeated int32          repeated_int32    = 10;
+    repeated uint32         repeated_uint32   = 11;
+    repeated sint32         repeated_sint32   = 12;
+    repeated int64          repeated_int64    = 13;
+    repeated uint64         repeated_uint64   = 14;
+    repeated sint64         repeated_sint64   = 15;
+    repeated fixed32        repeated_fixed32  = 16;
+    repeated sfixed32       repeated_sfixed32 = 17;
+    repeated fixed64        repeated_fixed64  = 18;
+    repeated sfixed64       repeated_sfixed64 = 19;
+    repeated bool           repeated_bool     = 20;
+    repeated float          repeated_float    = 21;
+    repeated double         repeated_double   = 22;
+    repeated AnEnum         repeated_enum     = 23;
+    repeated string         repeated_string   = 24;
+    repeated bytes          repeated_bytes    = 25;
+    repeated AnotherMessage repeated_message  = 26;
+    repeated group          RepeatedGroup     = 27 {
+      optional int32 a = 1;
+    }
+  }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
new file mode 100644
index 0000000..8b2d965
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message SingularExtensions {
+  extend ExtendableMessage {
+    optional int32          some_int32    = 10;
+    optional uint32         some_uint32   = 11;
+    optional sint32         some_sint32   = 12;
+    optional int64          some_int64    = 13;
+    optional uint64         some_uint64   = 14;
+    optional sint64         some_sint64   = 15;
+    optional fixed32        some_fixed32  = 16;
+    optional sfixed32       some_sfixed32 = 17;
+    optional fixed64        some_fixed64  = 18;
+    optional sfixed64       some_sfixed64 = 19;
+    optional bool           some_bool     = 20;
+    optional float          some_float    = 21;
+    optional double         some_double   = 22;
+    optional AnEnum         some_enum     = 23;
+    optional string         some_string   = 24;
+    optional bytes          some_bytes    = 25;
+    optional AnotherMessage some_message  = 26;
+    optional group          SomeGroup     = 27 {
+      optional int32 a = 1;
+    }
+  }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
new file mode 100644
index 0000000..fe7d179
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
@@ -0,0 +1,82 @@
+// 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.
+
+// Author: ulas@google.com (Ulas Kirazci)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "NanoHasOuterClass";
+
+message TestAllTypesNanoHas {
+
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional int32  optional_int32    =  1;
+  optional float  optional_float    = 11;
+  optional double optional_double   = 12;
+  optional string optional_string   = 14;
+  optional bytes  optional_bytes    = 15;
+
+  optional NestedMessage optional_nested_message = 18;
+
+  optional NestedEnum optional_nested_enum = 21;
+
+  // Repeated
+  repeated int32  repeated_int32    = 31;
+  repeated string repeated_string   = 44;
+  repeated bytes  repeated_bytes    = 45;
+
+  repeated NestedMessage repeated_nested_message  = 48;
+
+  repeated NestedEnum repeated_nested_enum  = 51;
+
+  // Singular with defaults
+  optional int32  default_int32    = 61 [default =  41    ];
+  optional string default_string   = 74 [default = "hello"];
+  optional bytes  default_bytes    = 75 [default = "world"];
+
+  optional float default_float_nan = 99  [default =  nan];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+  required int32 id = 86;
+  required NestedEnum required_enum = 87;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
new file mode 100644
index 0000000..1a3ddc5
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
@@ -0,0 +1,48 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest_import.proto but with optimize_for = NANO_RUNTIME.
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano.testimport";
+option java_outer_classname = "UnittestImportNano";
+
+message ImportMessageNano {
+  optional int32 d = 1;
+}
+
+enum ImportEnumNano {
+  IMPORT_NANO_FOO = 7;
+  IMPORT_NANO_BAR = 8;
+  IMPORT_NANO_BAZ = 9;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto
new file mode 100644
index 0000000..b31c439
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto
@@ -0,0 +1,41 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "MultipleNameClashNano";
+option java_multiple_files = true;
+
+message MultipleNameClashNano {
+  optional int32 field = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto
new file mode 100644
index 0000000..406ab77
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto
@@ -0,0 +1,63 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+import "google/protobuf/nano/unittest_import_nano.proto";
+
+option java_package = "com.google.protobuf";
+option java_multiple_files = true;
+
+enum FileScopeEnum {
+  ONE = 1;
+  TWO = 2;
+}
+
+message FileScopeEnumRefNano {
+  optional FileScopeEnum enum_field = 1;
+}
+
+message MessageScopeEnumRefNano {
+  enum MessageScopeEnum {
+    ONE = 1;
+    TWO = 2;
+  }
+  optional MessageScopeEnum enum_field = 1;
+}
+
+message MultipleImportingNonMultipleNano1 {
+  optional ImportMessageNano field = 1;
+}
+
+message MultipleImportingNonMultipleNano2 {
+  optional MultipleImportingNonMultipleNano1 nano1 = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
new file mode 100644
index 0000000..3fff24c
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
@@ -0,0 +1,195 @@
+// 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.
+
+// Author: wink@google.com (Wink Saville)
+
+package protobuf_unittest;
+
+import "google/protobuf/nano/unittest_import_nano.proto";
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "NanoOuterClass";
+
+// Same as TestAllTypes but with the nano runtime.
+message TestAllTypesNano {
+
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+  optional ForeignMessageNano optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessageNano
+    optional_import_message = 20;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+  optional ForeignEnumNano optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnumNano optional_import_enum = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+  repeated ForeignMessageNano repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessageNano
+    repeated_import_message = 50;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+  repeated ForeignEnumNano repeated_foreign_enum = 52;
+  repeated protobuf_unittest_import.ImportEnumNano repeated_import_enum = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  // Repeated packed
+  repeated    int32 repeated_packed_int32    = 87 [packed=true];
+  repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
+
+  repeated NestedEnum repeated_packed_nested_enum  = 89 [packed=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional string default_string_nonascii = 76 [default = "dünya"];
+  optional  bytes default_bytes_nonascii  = 77 [default = "dünyab"];
+
+  optional  float default_float_inf      = 97  [default =  inf];
+  optional  float default_float_neg_inf  = 98  [default = -inf];
+  optional  float default_float_nan      = 99  [default =  nan];
+  optional double default_double_inf     = 100 [default =  inf];
+  optional double default_double_neg_inf = 101 [default = -inf];
+  optional double default_double_nan     = 102 [default =  nan];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+  optional ForeignEnumNano default_foreign_enum = 82
+      [default = FOREIGN_NANO_BAR];
+  optional protobuf_unittest_import.ImportEnumNano
+      default_import_enum = 83 [default = IMPORT_NANO_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+
+  required int32 id = 86;
+
+  // Try to cause conflicts.
+  optional int32 tag = 93;
+  optional int32 get_serialized_size = 94;
+  optional int32 write_to = 95;
+
+  // Try to fail with java reserved keywords
+  optional int32 synchronized = 96;
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 123;
+    bytes oneof_bytes = 124;
+    fixed64 oneof_fixed64 = 115;
+    NestedEnum oneof_enum = 116;
+  }
+}
+
+message ForeignMessageNano {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+  FOREIGN_NANO_FOO = 4;
+  FOREIGN_NANO_BAR = 5;
+  FOREIGN_NANO_BAZ = 6;
+}
+
+// Test that deprecated fields work.  We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedNano {
+  optional int32 deprecated_field = 1 [deprecated = true];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
new file mode 100644
index 0000000..29b944f
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
@@ -0,0 +1,49 @@
+// 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.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestRecursiveNano";
+
+message RecursiveMessageNano {
+  message NestedMessage {
+    optional RecursiveMessageNano a = 1;
+  }
+
+  required int32 id = 1;
+  optional NestedMessage nested_message = 2;
+  optional RecursiveMessageNano optional_recursive_message_nano = 3;
+  repeated RecursiveMessageNano repeated_recursive_message_nano = 4;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
new file mode 100644
index 0000000..82eb8d1
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
@@ -0,0 +1,116 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "NanoReferenceTypes";
+
+message TestAllTypesNano {
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  message NestedMessage {
+    optional int32 foo = 1;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  // Repeated packed
+  repeated    int32 repeated_packed_int32    = 87 [packed=true];
+  repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
+
+  repeated NestedEnum repeated_packed_nested_enum  = 89 [packed=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+
+  optional  float default_float_inf      = 97  [default =  inf];
+  optional  float default_float_neg_inf  = 98  [default = -inf];
+  optional  float default_float_nan      = 99  [default =  nan];
+  optional double default_double_inf     = 100 [default =  inf];
+  optional double default_double_neg_inf = 101 [default = -inf];
+  optional double default_double_nan     = 102 [default =  nan];
+
+}
+
+message ForeignMessageNano {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+  FOREIGN_NANO_FOO = 4;
+  FOREIGN_NANO_BAR = 5;
+  FOREIGN_NANO_BAZ = 6;
+}
+
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto
new file mode 100644
index 0000000..ef4e2d2
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto
@@ -0,0 +1,47 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+import "google/protobuf/nano/unittest_nano.proto";
+
+option java_package = "com.google.protobuf";
+option java_multiple_files = true;
+
+// A container message for testing the merging of repeated fields at a
+// nested level. Other tests will be done using the repeated fields in
+// TestAllTypesNano.
+message TestRepeatedMergeNano {
+
+  optional TestAllTypesNano contained = 1;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
new file mode 100644
index 0000000..96af885
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
@@ -0,0 +1,95 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "NanoRepeatedPackables";
+
+enum Enum {
+  OPTION_ONE = 1;
+  OPTION_TWO = 2;
+}
+
+// Two almost identical messages with all packable repeated field types.
+// One with none marked as packed and the other all packed. For
+// compatibility, they should be able to parse each other's serialized
+// forms.
+
+message NonPacked {
+
+  // All packable types, none marked as packed.
+
+  repeated    int32 int32s    = 1;
+  repeated    int64 int64s    = 2;
+  repeated   uint32 uint32s   = 3;
+  repeated   uint64 uint64s   = 4;
+  repeated   sint32 sint32s   = 5;
+  repeated   sint64 sint64s   = 6;
+  repeated  fixed32 fixed32s  = 7;
+  repeated  fixed64 fixed64s  = 8;
+  repeated sfixed32 sfixed32s = 9;
+  repeated sfixed64 sfixed64s = 10;
+  repeated    float floats    = 11;
+  repeated   double doubles   = 12;
+  repeated     bool bools     = 13;
+  repeated     Enum enums     = 14;
+
+  // Noise for testing merged deserialization.
+  optional int32 noise = 15;
+
+}
+
+message Packed {
+
+  // All packable types, all matching the field numbers in NonPacked,
+  // all marked as packed.
+
+  repeated    int32 int32s    = 1  [ packed = true ];
+  repeated    int64 int64s    = 2  [ packed = true ];
+  repeated   uint32 uint32s   = 3  [ packed = true ];
+  repeated   uint64 uint64s   = 4  [ packed = true ];
+  repeated   sint32 sint32s   = 5  [ packed = true ];
+  repeated   sint64 sint64s   = 6  [ packed = true ];
+  repeated  fixed32 fixed32s  = 7  [ packed = true ];
+  repeated  fixed64 fixed64s  = 8  [ packed = true ];
+  repeated sfixed32 sfixed32s = 9  [ packed = true ];
+  repeated sfixed64 sfixed64s = 10 [ packed = true ];
+  repeated    float floats    = 11 [ packed = true ];
+  repeated   double doubles   = 12 [ packed = true ];
+  repeated     bool bools     = 13 [ packed = true ];
+  repeated     Enum enums     = 14 [ packed = true ];
+
+  // Noise for testing merged deserialization.
+  optional int32 noise = 15;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
new file mode 100644
index 0000000..25786cc
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
@@ -0,0 +1,54 @@
+// 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.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestSimpleNano";
+
+message SimpleMessageNano {
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  optional int32 d = 1 [default = 123];
+  optional NestedMessage nested_msg = 2;
+  optional NestedEnum default_nested_enum = 3 [default = BAZ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
new file mode 100644
index 0000000..7de30c8
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
@@ -0,0 +1,38 @@
+// 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.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf";
+
+message SingleMessageNano {
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
new file mode 100644
index 0000000..bbd677c
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
@@ -0,0 +1,43 @@
+// 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.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestStringutf8Nano";
+
+message StringUtf8 {
+  optional string id = 1;
+  repeated string rs = 2;
+}
diff --git a/src/google/protobuf/unittest_unknown_enum_values_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_unknown_enum_values.proto
similarity index 100%
rename from src/google/protobuf/unittest_unknown_enum_values_nano.proto
rename to javanano/src/test/java/com/google/protobuf/nano/unittest_unknown_enum_values.proto
diff --git a/jenkins/README.md b/jenkins/README.md
new file mode 100644
index 0000000..29f664f
--- /dev/null
+++ b/jenkins/README.md
@@ -0,0 +1,6 @@
+
+Jenkins Infrastructure
+----------------------
+
+The scripts in this directory serve as plumbing for running the protobuf
+tests under Jenkins.
diff --git a/jenkins/build_and_run_docker.sh b/jenkins/build_and_run_docker.sh
new file mode 100755
index 0000000..abc6f05
--- /dev/null
+++ b/jenkins/build_and_run_docker.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Builds docker image and runs a command under it.
+# This is a generic script that is configured with the following variables:
+#
+# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
+# DOCKER_RUN_SCRIPT - Script to run under docker (relative to protobuf repo root)
+# OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
+# $@ - Extra args to pass to docker run
+
+
+set -ex
+
+cd $(dirname $0)/..
+git_root=$(pwd)
+cd -
+
+# Use image name based on Dockerfile location checksum
+DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+
+# Make sure docker image has been built. Should be instantaneous if so.
+docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR
+
+# Ensure existence of ccache directory
+CCACHE_DIR=/tmp/protobuf-ccache
+mkdir -p $CCACHE_DIR
+
+# Choose random name for docker container
+CONTAINER_NAME="build_and_run_docker_$(uuidgen)"
+
+# Run command inside docker
+docker run \
+  "$@" \
+  -e CCACHE_DIR=$CCACHE_DIR \
+  -e EXTERNAL_GIT_ROOT="/var/local/jenkins/protobuf" \
+  -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+  -v "$git_root:/var/local/jenkins/protobuf:ro" \
+  -v $CCACHE_DIR:$CCACHE_DIR \
+  -w /var/local/git/protobuf \
+  --name=$CONTAINER_NAME \
+  $DOCKER_IMAGE_NAME \
+  bash -l "/var/local/jenkins/protobuf/$DOCKER_RUN_SCRIPT" || FAILED="true"
+
+# Copy output artifacts
+if [ "$OUTPUT_DIR" != "" ]
+then
+  docker cp "$CONTAINER_NAME:/var/local/git/protobuf/$OUTPUT_DIR" "$git_root" || FAILED="true"
+fi
+
+# remove the container, possibly killing it first
+docker rm -f $CONTAINER_NAME || true
+
+if [ "$FAILED" != "" ]
+then
+  exit 1
+fi
diff --git a/jenkins/buildcmds/README.md b/jenkins/buildcmds/README.md
new file mode 100644
index 0000000..7a48f2d
--- /dev/null
+++ b/jenkins/buildcmds/README.md
@@ -0,0 +1,6 @@
+
+Jenkins Build Commands
+----------------------
+
+The scripts in this directory are designed to be top-level entry points for
+Jenkins projects.
diff --git a/jenkins/buildcmds/pull_request.sh b/jenkins/buildcmds/pull_request.sh
new file mode 100755
index 0000000..01fda79
--- /dev/null
+++ b/jenkins/buildcmds/pull_request.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# This is the top-level script we give to Jenkins as the entry point for
+# running the "pull request" project:
+#
+#   https://grpc-testing.appspot.com/view/Protocol%20Buffers/job/protobuf_pull_request/
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image.  Then we delegate to the general
+# build_and_run_docker.sh script.
+
+export DOCKERFILE_DIR=jenkins/docker
+export DOCKER_RUN_SCRIPT=jenkins/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+./jenkins/build_and_run_docker.sh
diff --git a/jenkins/docker/Dockerfile b/jenkins/docker/Dockerfile
new file mode 100644
index 0000000..8467aef
--- /dev/null
+++ b/jenkins/docker/Dockerfile
@@ -0,0 +1,130 @@
+# This Dockerfile specifies the recipe for creating an image for the tests
+# to run in.
+#
+# We install as many test dependencies here as we can, because these setup
+# steps can be cached.  They do *not* run every time we run the build.
+# The Docker image is only rebuilt when the Dockerfile (ie. this file)
+# changes.
+
+# Base Dockerfile for gRPC dev images
+FROM debian:latest
+
+# Apt source for old Python versions.
+RUN echo 'deb http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main' > /etc/apt/sources.list.d/deadsnakes.list && \
+  apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DB82666C
+
+# Apt source for Oracle Java.
+run echo 'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' > /etc/apt/sources.list.d/webupd8team-java-trusty.list && \
+  apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886 && \
+  echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections
+
+# Apt source for Mono
+run echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list && \
+  echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list && \
+  apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  # -- For csharp --
+  mono-devel \
+  referenceassemblies-pcl \
+  nunit \
+  # -- For all Java builds -- \
+  maven \
+  # -- For java_jdk6 -- \
+  #   oops! not in jessie. too old? openjdk-6-jdk \
+  # -- For java_jdk7 -- \
+  openjdk-7-jdk \
+  # -- For java_oracle7 -- \
+  oracle-java7-installer \
+  # -- For python / python_cpp -- \
+  python-setuptools \
+  python-pip \
+  python-dev \
+  python2.6-dev \
+  python3.3-dev \
+  python3.4-dev \
+  # -- For Ruby --
+  ruby \
+  && apt-get clean
+
+##################
+# C# dependencies
+
+RUN wget www.nuget.org/NuGet.exe -O /usr/local/bin/nuget.exe
+
+##################
+# Python dependencies
+
+# These packages exist in apt-get, but their versions are too old, so we have
+# to get updates from pip.
+
+RUN pip install pip --upgrade
+RUN pip install virtualenv tox yattag
+
+
+##################
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+##################
+# Java dependencies
+
+# This step requires compiling protoc. :(
+
+ENV MAVEN_REPO /var/maven_local_repository
+ENV MVN mvn --batch-mode
+
+RUN cd /tmp && \
+  git clone https://github.com/google/protobuf.git && \
+  cd protobuf && \
+  ./autogen.sh && \
+  ./configure && \
+  make -j6 && \
+  cd java && \
+  $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO -P lite && \
+  $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO && \
+  cd ../javanano && \
+  $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO
+
+##################
+# Prepare ccache
+
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+# Define the default command.
+CMD ["bash"]
diff --git a/jenkins/make_test_output.py b/jenkins/make_test_output.py
new file mode 100644
index 0000000..b1f2e2c
--- /dev/null
+++ b/jenkins/make_test_output.py
@@ -0,0 +1,91 @@
+"""Gathers output from test runs and create an XML file in JUnit format.
+
+The output files from the individual tests have been written in a directory
+structure like:
+
+  $DIR/joblog  (output from "parallel --joblog joblog")
+  $DIR/logs/1/cpp/stdout
+  $DIR/logs/1/cpp/stderr
+  $DIR/logs/1/csharp/stdout
+  $DIR/logs/1/csharp/stderr
+  $DIR/logs/1/java_jdk7/stdout
+  $DIR/logs/1/java_jdk7/stderr
+  etc.
+
+This script bundles them into a single output XML file so Jenkins can show
+detailed test results.  It runs as the last step before the Jenkins build
+finishes.
+"""
+
+import os;
+import sys;
+from yattag import Doc
+from collections import defaultdict
+
+def readtests(basedir):
+  tests = defaultdict(dict)
+
+  # Sample input (note: separators are tabs).
+  #
+  # Seq	Host	Starttime	Runtime	Send	Receive	Exitval	Signal	Command
+  # 1	:	1456263838.313	0.005	0	0	0	0	echo A
+  with open(basedir + "/joblog") as jobs:
+    firstline = next(jobs)
+    for line in jobs:
+      values = line.split("\t")
+
+      name = values[8].split()[-1]
+      test = tests[name]
+      test["name"] = name
+      test["time"] = values[3]
+
+      exitval = values[6]
+      if int(exitval):
+        # We don't have a more specific message.  User should look at stderr.
+        test["failure"] = "TEST FAILURE"
+      else:
+        test["failure"] = False
+
+  for testname in os.listdir(basedir + "/logs/1"):
+    test = tests[testname]
+
+    with open(basedir + "/logs/1/" + testname + "/stdout") as f:
+      test["stdout"] = f.read()
+
+    with open(basedir + "/logs/1/" + testname + "/stderr") as f:
+      test["stderr"] = f.read()
+
+  # The cpp test is special since it doesn't run under parallel so doesn't show
+  # up in the job log.
+  tests["cpp"]["name"] = "cpp"
+
+  with open(basedir + '/logs/1/cpp/build_time', 'r') as f:
+    tests["cpp"]["time"] = f.read().strip()
+  tests["cpp"]["failure"] = False
+
+  ret = tests.values()
+  ret.sort(key=lambda x: x["name"])
+
+  return ret
+
+def genxml(tests):
+  doc, tag, text = Doc().tagtext()
+
+  with tag("testsuites"):
+    with tag("testsuite", name="Protobuf Tests"):
+      for test in tests:
+        with tag("testcase", name=test["name"], classname=test["name"],
+                             time=test["time"]):
+          with tag("system-out"):
+            text(test["stdout"])
+          with tag("system-err"):
+            text(test["stderr"])
+          if test["failure"]:
+            with tag("failure"):
+              text(test["failure"])
+
+  return doc.getvalue()
+
+sys.stderr.write("make_test_output.py: writing XML from directory: " +
+                 sys.argv[1] + "\n");
+print genxml(readtests(sys.argv[1]))
diff --git a/jenkins/pull_request_in_docker.sh b/jenkins/pull_request_in_docker.sh
new file mode 100755
index 0000000..887f97c
--- /dev/null
+++ b/jenkins/pull_request_in_docker.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# This is the script that runs inside Docker, once the image has been built,
+# to execute all tests for the "pull request" project.
+
+WORKSPACE_BASE=`pwd`
+MY_DIR="$(dirname "$0")"
+TEST_SCRIPT=$MY_DIR/../tests.sh
+BUILD_DIR=/tmp/protobuf
+
+set -e  # exit immediately on error
+set -x  # display all commands
+
+# The protobuf repository is mounted into our Docker image, but read-only.
+# We clone into a directory inside Docker (this is faster than cp).
+rm -rf $BUILD_DIR
+mkdir -p $BUILD_DIR
+cd $BUILD_DIR
+git clone /var/local/jenkins/protobuf
+cd protobuf
+
+# Set up the directory where our test output is going to go.
+OUTPUT_DIR=`mktemp -d`
+LOG_OUTPUT_DIR=$OUTPUT_DIR/logs
+mkdir -p $LOG_OUTPUT_DIR/1/cpp
+
+################################################################################
+# cpp build needs to run first, non-parallelized, so that protoc is available
+# for other builds.
+
+# Output filenames to follow the overall scheme used by parallel, ie:
+#  $DIR/logs/1/cpp/stdout
+#  $DIR/logs/1/cpp/stderr
+#  $DIR/logs/1/csharp/stdout
+#  $DIR/logs/1/csharp/stderr
+#  $DIR/logs/1/java_jdk7/stdout
+#  $DIR/logs/1/java_jdk7/stderr
+CPP_STDOUT=$LOG_OUTPUT_DIR/1/cpp/stdout
+CPP_STDERR=$LOG_OUTPUT_DIR/1/cpp/stderr
+
+# Time the C++ build, so we can put this info in the test output.
+# It's important that we get /usr/bin/time (which supports -f and -o) and not
+# the bash builtin "time" which doesn't.
+TIME_CMD="/usr/bin/time -f %e -o $LOG_OUTPUT_DIR/1/cpp/build_time"
+
+$TIME_CMD $TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2)
+
+# Other tests are run in parallel.
+
+parallel --results $LOG_OUTPUT_DIR --joblog $OUTPUT_DIR/joblog $TEST_SCRIPT ::: \
+  csharp \
+  java_jdk7 \
+  javanano_jdk7 \
+  java_oracle7 \
+  javanano_oracle7 \
+  python \
+  python_cpp \
+  ruby21 \
+  || true  # Process test results even if tests fail.
+
+cat $OUTPUT_DIR/joblog
+
+# The directory that is copied from Docker back into the Jenkins workspace.
+COPY_FROM_DOCKER=/var/local/git/protobuf/testoutput
+mkdir -p $COPY_FROM_DOCKER
+TESTOUTPUT_XML_FILE=$COPY_FROM_DOCKER/testresults.xml
+
+# Process all the output files from "parallel" and package them into a single
+# .xml file with detailed, broken-down test output.
+python $MY_DIR/make_test_output.py $OUTPUT_DIR > $TESTOUTPUT_XML_FILE
+
+ls -l $TESTOUTPUT_XML_FILE
diff --git a/js/README.md b/js/README.md
new file mode 100644
index 0000000..15d48c8
--- /dev/null
+++ b/js/README.md
@@ -0,0 +1,159 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the JavaScript Protocol Buffers runtime library.
+
+The library is currently compatible with:
+
+1. CommonJS-style imports (eg. `var protos = require('my-protos');`)
+2. Closure-style imports (eg. `goog.require('my.package.MyProto');`)
+
+Support for ES6-style imports is not implemented yet.  Browsers can
+be supported by using Browserify, webpack, Closure Compiler, etc. to
+resolve imports at compile time.
+
+To use Protocol Buffers with JavaScript, you need two main components:
+
+1. The protobuf runtime library.  You can install this with
+   `npm install google-protobuf`, or use the files in this directory.
+2. The Protocol Compiler `protoc`.  This translates `.proto` files
+   into `.js` files.  The compiler is not currently available via
+   npm, but you can download a pre-built binary
+   [on GitHub](https://github.com/google/protobuf/releases)
+   (look for the `protoc-*.zip` files under **Downloads**).
+
+
+Setup
+=====
+
+First, obtain the Protocol Compiler.  The easiest way is to download
+a pre-built binary from [https://github.com/google/protobuf/releases](https://github.com/google/protobuf/releases).
+
+If you want, you can compile `protoc` from source instead.  To do this
+follow the instructions in [the top-level
+README](https://github.com/google/protobuf/blob/master/src/README.md).
+
+Once you have `protoc` compiled, you can run the tests by typing:
+
+    $ cd js
+    $ npm install
+    $ npm test
+
+    # If your protoc is somewhere else than ../src/protoc, instead do this.
+    # But make sure your protoc is the same version as this (or compatible)!
+    $ PROTOC=/usr/local/bin/protoc npm test
+
+This will run two separate copies of the tests: one that uses
+Closure Compiler style imports and one that uses CommonJS imports.
+You can see all the CommonJS files in `commonjs_out/`.
+If all of these tests pass, you know you have a working setup.
+
+
+Using Protocol Buffers in your own project
+==========================================
+
+To use Protocol Buffers in your own project, you need to integrate
+the Protocol Compiler into your build system.  The details are a
+little different depending on whether you are using Closure imports
+or CommonJS imports:
+
+Closure Imports
+---------------
+
+If you want to use Closure imports, your build should run a command
+like this:
+
+    $ protoc --js_out=library=myproto_libs,binary:. messages.proto base.proto
+
+For Closure imports, `protoc` will generate a single output file
+(`myproto_libs.js` in this example).  The generated file will `goog.provide()`
+all of the types defined in your .proto files.  For example, for the unit
+tests the generated files contain many `goog.provide` statements like:
+
+    goog.provide('proto.google.protobuf.DescriptorProto');
+    goog.provide('proto.google.protobuf.DescriptorProto.ExtensionRange');
+    goog.provide('proto.google.protobuf.DescriptorProto.ReservedRange');
+    goog.provide('proto.google.protobuf.EnumDescriptorProto');
+    goog.provide('proto.google.protobuf.EnumOptions');
+
+The generated code will also `goog.require()` many types in the core library,
+and they will require many types in the Google Closure library.  So make sure
+that your `goog.provide()` / `goog.require()` setup can find all of your
+generated code, the core library `.js` files in this directory, and the
+Google Closure library itself.
+
+Once you've done this, you should be able to import your types with
+statements like:
+
+    goog.require('proto.my.package.MyMessage');
+
+    var message = proto.my.package.MyMessage();
+
+CommonJS imports
+----------------
+
+If you want to use CommonJS imports, your build should run a command
+like this:
+
+    $ protoc --js_out=import_style=commonjs,binary:. messages.proto base.proto
+
+For CommonJS imports, `protoc` will spit out one file per input file
+(so `messages_pb.js` and `base_pb.js` in this example).  The generated
+code will depend on the core runtime, which should be in a file called
+`google-protobuf.js`.  If you are installing from `npm`, this file should
+already be built and available.  If you are running from GitHub, you need
+to build it first by running:
+
+    $ gulp dist
+
+Once you've done this, you should be able to import your types with
+statements like:
+
+    var messages = require('./messages_pb');
+
+    var message = new messages.MyMessage();
+
+The `--js_out` flag
+-------------------
+
+The syntax of the `--js_out` flag is:
+
+    --js_out=[OPTIONS:]output_dir
+
+Where `OPTIONS` are separated by commas.  Options are either `opt=val` or
+just `opt` (for options that don't take a value).  The available options
+are specified and documented in the `GeneratorOptions` struct in
+[src/google/protobuf/compiler/js/js_generator.h](https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/js/js_generator.h#L53).
+
+Some examples:
+
+- `--js_out=library=myprotos_lib.js,binary:.`: this contains the options
+  `library=myprotos.lib.js` and `binary` and outputs to the current directory.
+  The `import_style` option is left to the default, which is `closure`.
+- `--js_out=import_style=commonjs,binary:protos`: this contains the options
+  `import_style=commonjs` and `binary` and outputs to the directory `protos`.
+
+API
+===
+
+The API is not well-documented yet.  Here is a quick example to give you an
+idea of how the library generally works:
+
+    var message = new MyMessage();
+
+    message.setName("John Doe");
+    message.setAge(25);
+    message.setPhoneNumbers(["800-555-1212", "800-555-0000"]);
+
+    // Serializes to a UInt8Array.
+    bytes = message.serializeBinary();
+
+    var message2 = new MyMessage();
+    message2.deserializeBinary(bytes);
+
+For more examples, see the tests.  You can also look at the generated code
+to see what methods are defined for your generated messages.
diff --git a/js/binary/arith.js b/js/binary/arith.js
new file mode 100644
index 0000000..70257de
--- /dev/null
+++ b/js/binary/arith.js
@@ -0,0 +1,413 @@
+// 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.
+
+/**
+ * @fileoverview This file contains helper code used by jspb.utils to
+ * handle 64-bit integer conversion to/from strings.
+ *
+ * @author cfallin@google.com (Chris Fallin)
+ *
+ * TODO(haberman): move this to javascript/closure/math?
+ */
+
+goog.provide('jspb.arith.Int64');
+goog.provide('jspb.arith.UInt64');
+
+/**
+ * UInt64 implements some 64-bit arithmetic routines necessary for properly
+ * handling 64-bit integer fields. It implements lossless integer arithmetic on
+ * top of JavaScript's number type, which has only 53 bits of precision, by
+ * representing 64-bit integers as two 32-bit halves.
+ *
+ * @param {number} lo The low 32 bits.
+ * @param {number} hi The high 32 bits.
+ * @constructor
+ */
+jspb.arith.UInt64 = function(lo, hi) {
+  /**
+   * The low 32 bits.
+   * @public {number}
+   */
+  this.lo = lo;
+  /**
+   * The high 32 bits.
+   * @public {number}
+   */
+  this.hi = hi;
+};
+
+
+/**
+ * Compare two 64-bit numbers. Returns -1 if the first is
+ * less, +1 if the first is greater, or 0 if both are equal.
+ * @param {!jspb.arith.UInt64} other
+ * @return {number}
+ */
+jspb.arith.UInt64.prototype.cmp = function(other) {
+  if (this.hi < other.hi || (this.hi == other.hi && this.lo < other.lo)) {
+    return -1;
+  } else if (this.hi == other.hi && this.lo == other.lo) {
+    return 0;
+  } else {
+    return 1;
+  }
+};
+
+
+/**
+ * Right-shift this number by one bit.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.rightShift = function() {
+  var hi = this.hi >>> 1;
+  var lo = (this.lo >>> 1) | ((this.hi & 1) << 31);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Left-shift this number by one bit.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.leftShift = function() {
+  var lo = this.lo << 1;
+  var hi = (this.hi << 1) | (this.lo >>> 31);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Test the MSB.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.msb = function() {
+  return !!(this.hi & 0x80000000);
+};
+
+
+/**
+ * Test the LSB.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.lsb = function() {
+  return !!(this.lo & 1);
+};
+
+
+/**
+ * Test whether this number is zero.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.zero = function() {
+  return this.lo == 0 && this.hi == 0;
+};
+
+
+/**
+ * Add two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.UInt64} other
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.add = function(other) {
+  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
+      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Subtract two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.UInt64} other
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.sub = function(other) {
+  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
+      (((this.lo - other.lo) < 0) ? 1 : 0);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Multiply two 32-bit numbers to produce a 64-bit number.
+ * @param {number} a The first integer:  must be in [0, 2^32-1).
+ * @param {number} b The second integer: must be in [0, 2^32-1).
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.mul32x32 = function(a, b) {
+  // Directly multiplying two 32-bit numbers may produce up to 64 bits of
+  // precision, thus losing precision because of the 53-bit mantissa of
+  // JavaScript numbers. So we multiply with 16-bit digits (radix 65536)
+  // instead.
+  var aLow = (a & 0xffff);
+  var aHigh = (a >>> 16);
+  var bLow = (b & 0xffff);
+  var bHigh = (b >>> 16);
+  var productLow =
+      // 32-bit result, result bits 0-31, take all 32 bits
+      (aLow * bLow) +
+      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
+      ((aLow * bHigh) & 0xffff) * 0x10000 +
+      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
+      ((aHigh * bLow) & 0xffff) * 0x10000;
+  var productHigh =
+      // 32-bit result, result bits 32-63, take all 32 bits
+      (aHigh * bHigh) +
+      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
+      ((aLow * bHigh) >>> 16) +
+      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
+      ((aHigh * bLow) >>> 16);
+
+  // Carry. Note that we actually have up to *two* carries due to addition of
+  // three terms.
+  while (productLow >= 0x100000000) {
+    productLow -= 0x100000000;
+    productHigh += 1;
+  }
+
+  return new jspb.arith.UInt64(productLow >>> 0, productHigh >>> 0);
+};
+
+
+/**
+ * Multiply this number by a 32-bit number, producing a 96-bit number, then
+ * truncate the top 32 bits.
+ * @param {number} a The multiplier.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.mul = function(a) {
+  // Produce two parts: at bits 0-63, and 32-95.
+  var lo = jspb.arith.UInt64.mul32x32(this.lo, a);
+  var hi = jspb.arith.UInt64.mul32x32(this.hi, a);
+  // Left-shift hi by 32 bits, truncating its top bits. The parts will then be
+  // aligned for addition.
+  hi.hi = hi.lo;
+  hi.lo = 0;
+  return lo.add(hi);
+};
+
+
+/**
+ * Divide a 64-bit number by a 32-bit number to produce a
+ * 64-bit quotient and a 32-bit remainder.
+ * @param {number} _divisor
+ * @return {Array.<jspb.arith.UInt64>} array of [quotient, remainder],
+ * unless divisor is 0, in which case an empty array is returned.
+ */
+jspb.arith.UInt64.prototype.div = function(_divisor) {
+  if (_divisor == 0) {
+    return [];
+  }
+
+  // We perform long division using a radix-2 algorithm, for simplicity (i.e.,
+  // one bit at a time). TODO: optimize to a radix-2^32 algorithm, taking care
+  // to get the variable shifts right.
+  var quotient = new jspb.arith.UInt64(0, 0);
+  var remainder = new jspb.arith.UInt64(this.lo, this.hi);
+  var divisor = new jspb.arith.UInt64(_divisor, 0);
+  var unit = new jspb.arith.UInt64(1, 0);
+
+  // Left-shift the divisor and unit until the high bit of divisor is set.
+  while (!divisor.msb()) {
+    divisor = divisor.leftShift();
+    unit = unit.leftShift();
+  }
+
+  // Perform long division one bit at a time.
+  while (!unit.zero()) {
+    // If divisor < remainder, add unit to quotient and subtract divisor from
+    // remainder.
+    if (divisor.cmp(remainder) <= 0) {
+      quotient = quotient.add(unit);
+      remainder = remainder.sub(divisor);
+    }
+    // Right-shift the divisor and unit.
+    divisor = divisor.rightShift();
+    unit = unit.rightShift();
+  }
+
+  return [quotient, remainder];
+};
+
+
+/**
+ * Convert a 64-bit number to a string.
+ * @return {string}
+ * @override
+ */
+jspb.arith.UInt64.prototype.toString = function() {
+  var result = '';
+  var num = this;
+  while (!num.zero()) {
+    var divResult = num.div(10);
+    var quotient = divResult[0], remainder = divResult[1];
+    result = remainder.lo + result;
+    num = quotient;
+  }
+  if (result == '') {
+    result = '0';
+  }
+  return result;
+};
+
+
+/**
+ * Parse a string into a 64-bit number. Returns `null` on a parse error.
+ * @param {string} s
+ * @return {?jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.fromString = function(s) {
+  var result = new jspb.arith.UInt64(0, 0);
+  // optimization: reuse this instance for each digit.
+  var digit64 = new jspb.arith.UInt64(0, 0);
+  for (var i = 0; i < s.length; i++) {
+    if (s[i] < '0' || s[i] > '9') {
+      return null;
+    }
+    var digit = parseInt(s[i], 10);
+    digit64.lo = digit;
+    result = result.mul(10).add(digit64);
+  }
+  return result;
+};
+
+
+/**
+ * Make a copy of the uint64.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.clone = function() {
+  return new jspb.arith.UInt64(this.lo, this.hi);
+};
+
+
+/**
+ * Int64 is like UInt64, but modifies string conversions to interpret the stored
+ * 64-bit value as a twos-complement-signed integer. It does *not* support the
+ * full range of operations that UInt64 does: only add, subtract, and string
+ * conversions.
+ *
+ * N.B. that multiply and divide routines are *NOT* supported. They will throw
+ * exceptions. (They are not necessary to implement string conversions, which
+ * are the only operations we really need in jspb.)
+ *
+ * @param {number} lo The low 32 bits.
+ * @param {number} hi The high 32 bits.
+ * @constructor
+ */
+jspb.arith.Int64 = function(lo, hi) {
+  /**
+   * The low 32 bits.
+   * @public {number}
+   */
+  this.lo = lo;
+  /**
+   * The high 32 bits.
+   * @public {number}
+   */
+  this.hi = hi;
+};
+
+
+/**
+ * Add two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.Int64} other
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.add = function(other) {
+  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
+      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
+  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Subtract two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.Int64} other
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.sub = function(other) {
+  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
+      (((this.lo - other.lo) < 0) ? 1 : 0);
+  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Make a copy of the int64.
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.clone = function() {
+  return new jspb.arith.Int64(this.lo, this.hi);
+};
+
+
+/**
+ * Convert a 64-bit number to a string.
+ * @return {string}
+ * @override
+ */
+jspb.arith.Int64.prototype.toString = function() {
+  // If the number is negative, find its twos-complement inverse.
+  var sign = (this.hi & 0x80000000) != 0;
+  var num = new jspb.arith.UInt64(this.lo, this.hi);
+  if (sign) {
+    num = new jspb.arith.UInt64(0, 0).sub(num);
+  }
+  return (sign ? '-' : '') + num.toString();
+};
+
+
+/**
+ * Parse a string into a 64-bit number. Returns `null` on a parse error.
+ * @param {string} s
+ * @return {?jspb.arith.Int64}
+ */
+jspb.arith.Int64.fromString = function(s) {
+  var hasNegative = (s.length > 0 && s[0] == '-');
+  if (hasNegative) {
+    s = s.substring(1);
+  }
+  var num = jspb.arith.UInt64.fromString(s);
+  if (num === null) {
+    return null;
+  }
+  if (hasNegative) {
+    num = new jspb.arith.UInt64(0, 0).sub(num);
+  }
+  return new jspb.arith.Int64(num.lo, num.hi);
+};
diff --git a/js/binary/arith_test.js b/js/binary/arith_test.js
new file mode 100644
index 0000000..89796bf
--- /dev/null
+++ b/js/binary/arith_test.js
@@ -0,0 +1,355 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for Int64-manipulation functions.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author cfallin@google.com (Chris Fallin)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.arith.Int64');
+goog.require('jspb.arith.UInt64');
+
+
+describe('binaryArithTest', function() {
+  /**
+   * Tests comparison operations.
+   */
+  it('testCompare', function() {
+    var a = new jspb.arith.UInt64(1234, 5678);
+    var b = new jspb.arith.UInt64(1234, 5678);
+    assertEquals(a.cmp(b), 0);
+    assertEquals(b.cmp(a), 0);
+    b.lo -= 1;
+    assertEquals(a.cmp(b), 1);
+    assertEquals(b.cmp(a), -1);
+    b.lo += 2;
+    assertEquals(a.cmp(b), -1);
+    assertEquals(b.cmp(a), 1);
+    b.lo = a.lo;
+    b.hi = a.hi - 1;
+    assertEquals(a.cmp(b), 1);
+    assertEquals(b.cmp(a), -1);
+
+    assertEquals(a.zero(), false);
+    assertEquals(a.msb(), false);
+    assertEquals(a.lsb(), false);
+    a.hi = 0;
+    a.lo = 0;
+    assertEquals(a.zero(), true);
+    a.hi = 0x80000000;
+    assertEquals(a.zero(), false);
+    assertEquals(a.msb(), true);
+    a.lo = 0x00000001;
+    assertEquals(a.lsb(), true);
+  });
+
+
+  /**
+   * Tests shifts.
+   */
+  it('testShifts', function() {
+    var a = new jspb.arith.UInt64(1, 0);
+    assertEquals(a.lo, 1);
+    assertEquals(a.hi, 0);
+    var orig = a;
+    a = a.leftShift();
+    assertEquals(orig.lo, 1);  // original unmodified.
+    assertEquals(orig.hi, 0);
+    assertEquals(a.lo, 2);
+    assertEquals(a.hi, 0);
+    a = a.leftShift();
+    assertEquals(a.lo, 4);
+    assertEquals(a.hi, 0);
+    for (var i = 0; i < 29; i++) {
+      a = a.leftShift();
+    }
+    assertEquals(a.lo, 0x80000000);
+    assertEquals(a.hi, 0);
+    a = a.leftShift();
+    assertEquals(a.lo, 0);
+    assertEquals(a.hi, 1);
+    a = a.leftShift();
+    assertEquals(a.lo, 0);
+    assertEquals(a.hi, 2);
+    a = a.rightShift();
+    a = a.rightShift();
+    assertEquals(a.lo, 0x80000000);
+    assertEquals(a.hi, 0);
+    a = a.rightShift();
+    assertEquals(a.lo, 0x40000000);
+    assertEquals(a.hi, 0);
+  });
+
+
+  /**
+   * Tests additions.
+   */
+  it('testAdd', function() {
+    var a = new jspb.arith.UInt64(/* lo = */ 0x89abcdef,
+                                         /* hi = */ 0x01234567);
+    var b = new jspb.arith.UInt64(/* lo = */ 0xff52ab91,
+                                         /* hi = */ 0x92fa2123);
+    // Addition with carry.
+    var c = a.add(b);
+    assertEquals(a.lo, 0x89abcdef);  // originals unmodified.
+    assertEquals(a.hi, 0x01234567);
+    assertEquals(b.lo, 0xff52ab91);
+    assertEquals(b.hi, 0x92fa2123);
+    assertEquals(c.lo, 0x88fe7980);
+    assertEquals(c.hi, 0x941d668b);
+
+    // Simple addition without carry.
+    a.lo = 2;
+    a.hi = 0;
+    b.lo = 3;
+    b.hi = 0;
+    c = a.add(b);
+    assertEquals(c.lo, 5);
+    assertEquals(c.hi, 0);
+  });
+
+
+  /**
+   * Test subtractions.
+   */
+  it('testSub', function() {
+    var kLength = 10;
+    var hiValues = [0x1682ef32,
+                    0x583902f7,
+                    0xb62f5955,
+                    0x6ea99bbf,
+                    0x25a39c20,
+                    0x0700a08b,
+                    0x00f7304d,
+                    0x91a5b5af,
+                    0x89077fd2,
+                    0xe09e347c];
+    var loValues = [0xe1538b18,
+                    0xbeacd556,
+                    0x74100758,
+                    0x96e3cb26,
+                    0x56c37c3f,
+                    0xe00b3f7d,
+                    0x859f25d7,
+                    0xc2ee614a,
+                    0xe1d21cd7,
+                    0x30aae6a4];
+    for (var i = 0; i < kLength; i++) {
+      for (var j = 0; j < kLength; j++) {
+        var a = new jspb.arith.UInt64(loValues[i], hiValues[j]);
+        var b = new jspb.arith.UInt64(loValues[j], hiValues[i]);
+        var c = a.add(b).sub(b);
+        assertEquals(c.hi, a.hi);
+        assertEquals(c.lo, a.lo);
+      }
+    }
+  });
+
+
+  /**
+   * Tests 32-by-32 multiplication.
+   */
+  it('testMul32x32', function() {
+    var testData = [
+      // a        b          low(a*b)   high(a*b)
+      [0xc0abe2f8, 0x1607898a, 0x5de711b0, 0x109471b8],
+      [0x915eb3cb, 0x4fb66d0e, 0xbd0d441a, 0x2d43d0bc],
+      [0xfe4efe70, 0x80b48c37, 0xbcddea10, 0x7fdada0c],
+      [0xe222fd4a, 0xe43d524a, 0xd5e0eb64, 0xc99d549c],
+      [0xd171f469, 0xb94ebd01, 0x4be17969, 0x979bc4fa],
+      [0x829cc1df, 0xe2598b38, 0xf4157dc8, 0x737c12ad],
+      [0xf10c3767, 0x8382881e, 0x942b3612, 0x7bd428b8],
+      [0xb0f6dd24, 0x232597e1, 0x079c98a4, 0x184bbce7],
+      [0xfcdb05a7, 0x902f55bc, 0x636199a4, 0x8e69f412],
+      [0x0dd0bfa9, 0x916e27b1, 0x6e2542d9, 0x07d92e65]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = testData[i][0] >>> 0;
+      var b = testData[i][1] >>> 0;
+      var cLow = testData[i][2] >>> 0;
+      var cHigh = testData[i][3] >>> 0;
+      var c = jspb.arith.UInt64.mul32x32(a, b);
+      assertEquals(c.lo, cLow);
+      assertEquals(c.hi, cHigh);
+    }
+  });
+
+
+  /**
+   * Tests 64-by-32 multiplication.
+   */
+  it('testMul', function() {
+    // 64x32 bits produces 96 bits of product. The multiplication function under
+    // test truncates the top 32 bits, so we compare against a 64-bit expected
+    // product.
+    var testData = [
+      // low(a)   high(a)               low(a*b)   high(a*b)
+      [0xec10955b, 0x360eb168, 0x4b7f3f5b, 0xbfcb7c59, 0x9517da5f],
+      [0x42b000fc, 0x9d101642, 0x6fa1ab72, 0x2584c438, 0x6a9e6d2b],
+      [0xf42d4fb4, 0xae366403, 0xa65a1000, 0x92434000, 0x1ff978df],
+      [0x17e2f56b, 0x25487693, 0xf13f98c7, 0x73794e2d, 0xa96b0c6a],
+      [0x492f241f, 0x76c0eb67, 0x7377ac44, 0xd4336c3c, 0xfc4b1ebe],
+      [0xd6b92321, 0xe184fa48, 0xd6e76904, 0x93141584, 0xcbf44da1],
+      [0x4bf007ea, 0x968c0a9e, 0xf5e4026a, 0x4fdb1ae4, 0x61b9fb7d],
+      [0x10a83be7, 0x2d685ba6, 0xc9e5fb7f, 0x2ad43499, 0x3742473d],
+      [0x2f261829, 0x1aca681a, 0x3d3494e3, 0x8213205b, 0x283719f8],
+      [0xe4f2ce21, 0x2e74b7bd, 0xd801b38b, 0xbc17feeb, 0xc6c44e0f]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var prod = a.mul(testData[i][2]);
+      assertEquals(prod.lo, testData[i][3]);
+      assertEquals(prod.hi, testData[i][4]);
+    }
+  });
+
+
+  /**
+   * Tests 64-div-by-32 division.
+   */
+  it('testDiv', function() {
+    // Compute a/b, yielding quot = a/b and rem = a%b.
+    var testData = [
+      // --- divisors in (0, 2^32-1) to test full divisor range
+      // low(a)   high(a)    b          low(quot)  high(quot) rem
+      [0x712443f1, 0xe85cefcc, 0xc1a7050b, 0x332c79ad, 0x00000001, 0x92ffa882],
+      [0x11912915, 0xb2699eb5, 0x30467cbe, 0xb21b4be4, 0x00000003, 0x283465dd],
+      [0x0d917982, 0x201f2a6e, 0x3f35bf03, 0x8217c8e4, 0x00000000, 0x153402d6],
+      [0xa072c108, 0x74020c96, 0xc60568fd, 0x95f9613e, 0x00000000, 0x3f4676c2],
+      [0xd845d5d8, 0xcdd235c4, 0x20426475, 0x6154e78b, 0x00000006, 0x202fb751],
+      [0xa4dbf71f, 0x9e90465e, 0xf08e022f, 0xa8be947f, 0x00000000, 0xbe43b5ce],
+      [0x3dbe627f, 0xa791f4b9, 0x28a5bd89, 0x1f5dfe93, 0x00000004, 0x02bf9ed4],
+      [0x5c1c53ee, 0xccf5102e, 0x198576e7, 0x07e3ae31, 0x00000008, 0x02ea8fb7],
+      [0xfef1e581, 0x04714067, 0xca6540c1, 0x059e73ec, 0x00000000, 0x31658095],
+      [0x1e2dd90c, 0x13dd6667, 0x8b2184c3, 0x248d1a42, 0x00000000, 0x4ca6d0c6],
+      // --- divisors in (0, 2^16-1) to test larger quotient high-words
+      // low(a)   high(a)    b          low(quot)  high(quot) rem
+      [0x86722b47, 0x2cd57c9a, 0x00003123, 0x2ae41b7a, 0x0000e995, 0x00000f99],
+      [0x1dd7884c, 0xf5e839bc, 0x00009eeb, 0x5c886242, 0x00018c21, 0x000099b6],
+      [0x5c53d625, 0x899fc7e5, 0x000087d7, 0xd625007a, 0x0001035c, 0x000019af],
+      [0x6932d932, 0x9d0a5488, 0x000051fb, 0x9d976143, 0x0001ea63, 0x00004981],
+      [0x4d18bb85, 0x0c92fb31, 0x00001d9f, 0x03265ab4, 0x00006cac, 0x000001b9],
+      [0xbe756768, 0xdea67ccb, 0x00008a03, 0x58add442, 0x00019cff, 0x000056a2],
+      [0xe2466f9a, 0x2521f114, 0x0000c350, 0xa0c0860d, 0x000030ab, 0x0000a48a],
+      [0xf00ddad1, 0xe2f5446a, 0x00002cfc, 0x762697a6, 0x00050b96, 0x00000b69],
+      [0xa879152a, 0x0a70e0a5, 0x00007cdf, 0xb44151b3, 0x00001567, 0x0000363d],
+      [0x7179a74c, 0x46083fff, 0x0000253c, 0x4d39ba6e, 0x0001e17f, 0x00000f84]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var result = a.div(testData[i][2]);
+      var quotient = result[0];
+      var remainder = result[1];
+      assertEquals(quotient.lo, testData[i][3]);
+      assertEquals(quotient.hi, testData[i][4]);
+      assertEquals(remainder.lo, testData[i][5]);
+    }
+  });
+
+
+  /**
+   * Tests .toString() and .fromString().
+   */
+  it('testStrings', function() {
+    var testData = [
+        [0x5e84c935, 0xcae33d0e, '14619595947299359029'],
+        [0x62b3b8b8, 0x93480544, '10612738313170434232'],
+        [0x319bfb13, 0xc01c4172, '13843011313344445203'],
+        [0x5b8a65fb, 0xa5885b31, '11927883880638080507'],
+        [0x6bdb80f1, 0xb0d1b16b, '12741159895737008369'],
+        [0x4b82b442, 0x2e0d8c97, '3318463081876730946'],
+        [0x780d5208, 0x7d76752c, '9040542135845999112'],
+        [0x2e46800f, 0x0993778d, '690026616168284175'],
+        [0xf00a7e32, 0xcd8e3931, '14811839111111540274'],
+        [0x1baeccd6, 0x923048c4, '10533999535534820566'],
+        [0x03669d29, 0xbff3ab72, '13831587386756603177'],
+        [0x2526073e, 0x01affc81, '121593346566522686'],
+        [0xc24244e0, 0xd7f40d0e, '15561076969511732448'],
+        [0xc56a341e, 0xa68b66a7, '12000798502816461854'],
+        [0x8738d64d, 0xbfe78604, '13828168534871037517'],
+        [0x5baff03b, 0xd7572aea, '15516918227177304123'],
+        [0x4a843d8a, 0x864e132b, '9677693725920476554'],
+        [0x25b4e94d, 0x22b54dc6, '2500990681505655117'],
+        [0x6bbe664b, 0x55a5cc0e, '6171563226690381387'],
+        [0xee916c81, 0xb00aabb3, '12685140089732426881']
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var roundtrip = jspb.arith.UInt64.fromString(a.toString());
+      assertEquals(roundtrip.lo, a.lo);
+      assertEquals(roundtrip.hi, a.hi);
+      assertEquals(a.toString(), testData[i][2]);
+    }
+  });
+
+
+  /**
+   * Tests signed Int64s. These are built on UInt64s, so we only need to test
+   * the explicit overrides: .toString() and .fromString().
+   */
+  it('testSignedInt64', function() {
+    var testStrings = [
+        '-7847499644178593666',
+        '3771946501229139523',
+        '2872856549054995060',
+        '-5780049594274350904',
+        '3383785956695105201',
+        '2973055184857072610',
+        '-3879428459215627206',
+        '4589812431064156631',
+        '8484075557333689940',
+        '1075325817098092407',
+        '-4346697501012292314',
+        '2488620459718316637',
+        '6112655187423520672',
+        '-3655278273928612104',
+        '3439154019435803196',
+        '1004112478843763757',
+        '-6587790776614368413',
+        '664320065099714586',
+        '4760412909973292912',
+        '-7911903989602274672'
+    ];
+
+    for (var i = 0; i < testStrings.length; i++) {
+      var roundtrip =
+          jspb.arith.Int64.fromString(testStrings[i]).toString();
+      assertEquals(roundtrip, testStrings[i]);
+    }
+  });
+});
diff --git a/js/binary/constants.js b/js/binary/constants.js
new file mode 100644
index 0000000..836216b
--- /dev/null
+++ b/js/binary/constants.js
@@ -0,0 +1,360 @@
+// 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.
+
+/**
+ * @fileoverview This file contains constants and typedefs used by
+ * jspb.BinaryReader and BinaryWriter.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.AnyFieldType');
+goog.provide('jspb.BinaryConstants');
+goog.provide('jspb.BinaryMessage');
+goog.provide('jspb.BuilderFunction');
+goog.provide('jspb.ByteSource');
+goog.provide('jspb.ClonerFunction');
+goog.provide('jspb.ComparerFunction');
+goog.provide('jspb.ConstBinaryMessage');
+goog.provide('jspb.PrunerFunction');
+goog.provide('jspb.ReaderFunction');
+goog.provide('jspb.RecyclerFunction');
+goog.provide('jspb.RepeatedFieldType');
+goog.provide('jspb.ScalarFieldType');
+goog.provide('jspb.WriterFunction');
+
+
+goog.forwardDeclare('jspb.Message');
+goog.forwardDeclare('jsproto.BinaryExtension');
+
+
+
+/**
+ * Base interface class for all const messages. Does __not__ define any
+ * methods, as doing so on a widely-used interface defeats dead-code
+ * elimination.
+ * @interface
+ */
+jspb.ConstBinaryMessage = function() {};
+
+
+
+/**
+ * Base interface class for all messages. Does __not__ define any methods, as
+ * doing so on a widely-used interface defeats dead-code elimination.
+ * @interface
+ * @extends {jspb.ConstBinaryMessage}
+ */
+jspb.BinaryMessage = function() {};
+
+
+/**
+ * The types convertible to Uint8Arrays. Strings are assumed to be
+ * base64-encoded.
+ * @typedef {ArrayBuffer|Uint8Array|Array<number>|string}
+ */
+jspb.ByteSource;
+
+
+/**
+ * A scalar field in jspb can be a boolean, number, or string.
+ * @typedef {boolean|number|string}
+ */
+jspb.ScalarFieldType;
+
+
+/**
+ * A repeated field in jspb is an array of scalars, blobs, or messages.
+ * @typedef {!Array<jspb.ScalarFieldType>|
+             !Array<!Uint8Array>|
+             !Array<!jspb.BinaryMessage>}
+ */
+jspb.RepeatedFieldType;
+
+
+/**
+ * A field in jspb can be a scalar, a block of bytes, another proto, or an
+ * array of any of the above.
+ * @typedef {jspb.ScalarFieldType|
+             jspb.RepeatedFieldType|
+             !Uint8Array|
+             !jspb.BinaryMessage|
+             !jsproto.BinaryExtension}
+ */
+jspb.AnyFieldType;
+
+
+/**
+ * A builder function creates an instance of a message object.
+ * @typedef {function():!jspb.BinaryMessage}
+ */
+jspb.BuilderFunction;
+
+
+/**
+ * A cloner function creates a deep copy of a message object.
+ * @typedef {function(jspb.ConstBinaryMessage):jspb.BinaryMessage}
+ */
+jspb.ClonerFunction;
+
+
+/**
+ * A recycler function destroys an instance of a message object.
+ * @typedef {function(!jspb.BinaryMessage):void}
+ */
+jspb.RecyclerFunction;
+
+
+/**
+ * A reader function initializes a message using data from a BinaryReader.
+ * @typedef {function(!jspb.BinaryMessage, !jspb.BinaryReader):void}
+ */
+jspb.ReaderFunction;
+
+
+/**
+ * A writer function serializes a message to a BinaryWriter.
+ * @typedef {!function(!jspb.Message, !jspb.BinaryWriter):void |
+ *           !function(!jspb.ConstBinaryMessage, !jspb.BinaryWriter):void}
+ */
+jspb.WriterFunction;
+
+
+/**
+ * A pruner function removes default-valued fields and empty submessages from a
+ * message and returns either the pruned message or null if the entire message
+ * was pruned away.
+ * @typedef {function(?jspb.BinaryMessage):?jspb.BinaryMessage}
+ */
+jspb.PrunerFunction;
+
+
+/**
+ * A comparer function returns true if two protos are equal.
+ * @typedef {!function(?jspb.ConstBinaryMessage,
+ *                     ?jspb.ConstBinaryMessage):boolean}
+ */
+jspb.ComparerFunction;
+
+
+/**
+ * Field type codes, taken from proto2/public/wire_format_lite.h.
+ * @enum {number}
+ */
+jspb.BinaryConstants.FieldType = {
+  INVALID: -1,
+  DOUBLE: 1,
+  FLOAT: 2,
+  INT64: 3,
+  UINT64: 4,
+  INT32: 5,
+  FIXED64: 6,
+  FIXED32: 7,
+  BOOL: 8,
+  STRING: 9,
+  GROUP: 10,
+  MESSAGE: 11,
+  BYTES: 12,
+  UINT32: 13,
+  ENUM: 14,
+  SFIXED32: 15,
+  SFIXED64: 16,
+  SINT32: 17,
+  SINT64: 18,
+
+  // Extended types for Javascript
+
+  FHASH64: 30, // 64-bit hash string, fixed-length encoding.
+  VHASH64: 31  // 64-bit hash string, varint encoding.
+};
+
+
+/**
+ * Wire-format type codes, taken from proto2/public/wire_format_lite.h.
+ * @enum {number}
+ */
+jspb.BinaryConstants.WireType = {
+  INVALID: -1,
+  VARINT: 0,
+  FIXED64: 1,
+  DELIMITED: 2,
+  START_GROUP: 3,
+  END_GROUP: 4,
+  FIXED32: 5
+};
+
+
+/**
+ * Translates field type to wire type.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @return {jspb.BinaryConstants.WireType}
+ */
+jspb.BinaryConstants.FieldTypeToWireType = function(fieldType) {
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  var wireTypes = jspb.BinaryConstants.WireType;
+  switch (fieldType) {
+    case fieldTypes.INT32:
+    case fieldTypes.INT64:
+    case fieldTypes.UINT32:
+    case fieldTypes.UINT64:
+    case fieldTypes.SINT32:
+    case fieldTypes.SINT64:
+    case fieldTypes.BOOL:
+    case fieldTypes.ENUM:
+    case fieldTypes.VHASH64:
+      return wireTypes.VARINT;
+
+    case fieldTypes.DOUBLE:
+    case fieldTypes.FIXED64:
+    case fieldTypes.SFIXED64:
+    case fieldTypes.FHASH64:
+      return wireTypes.FIXED64;
+
+    case fieldTypes.STRING:
+    case fieldTypes.MESSAGE:
+    case fieldTypes.BYTES:
+      return wireTypes.DELIMITED;
+
+    case fieldTypes.FLOAT:
+    case fieldTypes.FIXED32:
+    case fieldTypes.SFIXED32:
+      return wireTypes.FIXED32;
+
+    case fieldTypes.INVALID:
+    case fieldTypes.GROUP:
+    default:
+      return wireTypes.INVALID;
+  }
+};
+
+
+/**
+ * Flag to indicate a missing field.
+ * @const {number}
+ */
+jspb.BinaryConstants.INVALID_FIELD_NUMBER = -1;
+
+
+/**
+ * The smallest denormal float32 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_EPS = 1.401298464324817e-45;
+
+
+/**
+ * The smallest normal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_MIN = 1.1754943508222875e-38;
+
+
+/**
+ * The largest finite float32 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_MAX = 3.4028234663852886e+38;
+
+
+/**
+ * The smallest denormal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_EPS = 5e-324;
+
+
+/**
+ * The smallest normal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_MIN = 2.2250738585072014e-308;
+
+
+/**
+ * The largest finite float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_MAX = 1.7976931348623157e+308;
+
+
+/**
+ * Convenience constant equal to 2^20.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_20 = 1048576;
+
+
+/**
+ * Convenience constant equal to 2^23.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_23 = 8388608;
+
+
+/**
+ * Convenience constant equal to 2^31.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_31 = 2147483648;
+
+
+/**
+ * Convenience constant equal to 2^32.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_32 = 4294967296;
+
+
+/**
+ * Convenience constant equal to 2^52.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_52 = 4503599627370496;
+
+
+/**
+ * Convenience constant equal to 2^63.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_63 = 9223372036854775808;
+
+
+/**
+ * Convenience constant equal to 2^64.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_64 = 18446744073709551616;
+
+
+/**
+ * Eight-character string of zeros, used as the default 64-bit hash value.
+ * @const {string}
+ */
+jspb.BinaryConstants.ZERO_HASH = '\0\0\0\0\0\0\0\0';
diff --git a/js/binary/decoder.js b/js/binary/decoder.js
new file mode 100644
index 0000000..41094a3
--- /dev/null
+++ b/js/binary/decoder.js
@@ -0,0 +1,1007 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for decoding primitive values
+ * (signed and unsigned integers, varints, booleans, enums, hashes, strings,
+ * and raw bytes) embedded in Uint8Arrays into their corresponding Javascript
+ * types.
+ *
+ * Major caveat - Javascript is unable to accurately represent integers larger
+ * than 2^53 due to its use of a double-precision floating point format or all
+ * numbers. If you need to guarantee that 64-bit values survive with all bits
+ * intact, you _must_ read them using one of the Hash64 methods, which return
+ * an 8-character string.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryDecoder');
+goog.provide('jspb.BinaryIterator');
+
+goog.require('goog.asserts');
+goog.require('jspb.utils');
+
+
+
+/**
+ * Simple helper class for traversing the contents of repeated scalar fields.
+ * that may or may not have been packed into a wire-format blob.
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @constructor
+ * @struct
+ */
+jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
+  /** @private {jspb.BinaryDecoder} */
+  this.decoder_ = null;
+
+  /**
+   * The BinaryDecoder member function used when iterating over packed data.
+   * @private {?function(this:jspb.BinaryDecoder):(number|boolean|string)}
+   */
+  this.nextMethod_ = null;
+
+  /** @private {Array.<number>} */
+  this.elements_ = null;
+
+  /** @private {number} */
+  this.cursor_ = 0;
+
+  /** @private {number|boolean|string|null} */
+  this.nextValue_ = null;
+
+  /** @private {boolean} */
+  this.atEnd_ = true;
+
+  this.init_(opt_decoder, opt_next, opt_elements);
+};
+
+
+/**
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @private
+ */
+jspb.BinaryIterator.prototype.init_ =
+    function(opt_decoder, opt_next, opt_elements) {
+  if (opt_decoder && opt_next) {
+    this.decoder_ = opt_decoder;
+    this.nextMethod_ = opt_next;
+  }
+  this.elements_ = opt_elements ? opt_elements : null;
+  this.cursor_ = 0;
+  this.nextValue_ = null;
+  this.atEnd_ = !this.decoder_ && !this.elements_;
+
+  this.next();
+};
+
+
+/**
+ * Global pool of BinaryIterator instances.
+ * @private {!Array.<!jspb.BinaryIterator>}
+ */
+jspb.BinaryIterator.instanceCache_ = [];
+
+
+/**
+ * Allocates a BinaryIterator from the cache, creating a new one if the cache
+ * is empty.
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @return {!jspb.BinaryIterator}
+ */
+jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
+  if (jspb.BinaryIterator.instanceCache_.length) {
+    var iterator = jspb.BinaryIterator.instanceCache_.pop();
+    iterator.init_(opt_decoder, opt_next, opt_elements);
+    return iterator;
+  } else {
+    return new jspb.BinaryIterator(opt_decoder, opt_next, opt_elements);
+  }
+};
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryIterator.prototype.free = function() {
+  this.clear();
+  if (jspb.BinaryIterator.instanceCache_.length < 100) {
+    jspb.BinaryIterator.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Clears the iterator.
+ */
+jspb.BinaryIterator.prototype.clear = function() {
+  if (this.decoder_) {
+    this.decoder_.free();
+  }
+  this.decoder_ = null;
+  this.nextMethod_ = null;
+  this.elements_ = null;
+  this.cursor_ = 0;
+  this.nextValue_ = null;
+  this.atEnd_ = true;
+};
+
+
+/**
+ * Returns the element at the iterator, or null if the iterator is invalid or
+ * past the end of the decoder/array.
+ * @return {number|boolean|string|null}
+ */
+jspb.BinaryIterator.prototype.get = function() {
+  return this.nextValue_;
+};
+
+
+/**
+ * Returns true if the iterator is at the end of the decoder/array.
+ * @return {boolean}
+ */
+jspb.BinaryIterator.prototype.atEnd = function() {
+  return this.atEnd_;
+};
+
+
+/**
+ * Returns the element at the iterator and steps to the next element,
+ * equivalent to '*pointer++' in C.
+ * @return {number|boolean|string|null}
+ */
+jspb.BinaryIterator.prototype.next = function() {
+  var lastValue = this.nextValue_;
+  if (this.decoder_) {
+    if (this.decoder_.atEnd()) {
+      this.nextValue_ = null;
+      this.atEnd_ = true;
+    } else {
+      this.nextValue_ = this.nextMethod_.call(this.decoder_);
+    }
+  } else if (this.elements_) {
+    if (this.cursor_ == this.elements_.length) {
+      this.nextValue_ = null;
+      this.atEnd_ = true;
+    } else {
+      this.nextValue_ = this.elements_[this.cursor_++];
+    }
+  }
+  return lastValue;
+};
+
+
+
+/**
+ * BinaryDecoder implements the decoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @constructor
+ * @struct
+ */
+jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
+  /**
+   * Typed byte-wise view of the source buffer.
+   * @private {?Uint8Array}
+   */
+  this.bytes_ = null;
+
+  /**
+   * Start point of the block to read.
+   * @private {number}
+   */
+  this.start_ = 0;
+
+  /**
+   * End point of the block to read.
+   * @private {number}
+   */
+  this.end_ = 0;
+
+  /**
+   * Current read location in bytes_.
+   * @private {number}
+   */
+  this.cursor_ = 0;
+
+  /**
+   * Temporary storage for the low 32 bits of 64-bit data types that we're
+   * decoding.
+   * @private {number}
+   */
+  this.tempLow_ = 0;
+
+  /**
+   * Temporary storage for the high 32 bits of 64-bit data types that we're
+   * decoding.
+   * @private {number}
+   */
+  this.tempHigh_ = 0;
+
+  /**
+   * Set to true if this decoder encountered an error due to corrupt data.
+   * @private {boolean}
+   */
+  this.error_ = false;
+
+  if (opt_bytes) {
+    this.setBlock(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Global pool of BinaryDecoder instances.
+ * @private {!Array.<!jspb.BinaryDecoder>}
+ */
+jspb.BinaryDecoder.instanceCache_ = [];
+
+
+/**
+ * Pops an instance off the instance cache, or creates one if the cache is
+ * empty.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryDecoder.alloc = function(opt_bytes, opt_start, opt_length) {
+  if (jspb.BinaryDecoder.instanceCache_.length) {
+    var newDecoder = jspb.BinaryDecoder.instanceCache_.pop();
+    if (opt_bytes) {
+      newDecoder.setBlock(opt_bytes, opt_start, opt_length);
+    }
+    return newDecoder;
+  } else {
+    return new jspb.BinaryDecoder(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryDecoder.prototype.free = function() {
+  this.clear();
+  if (jspb.BinaryDecoder.instanceCache_.length < 100) {
+    jspb.BinaryDecoder.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Makes a copy of this decoder.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryDecoder.prototype.clone = function() {
+  return jspb.BinaryDecoder.alloc(this.bytes_,
+      this.start_, this.end_ - this.start_);
+};
+
+
+/**
+ * Clears the decoder.
+ */
+jspb.BinaryDecoder.prototype.clear = function() {
+  this.bytes_ = null;
+  this.start_ = 0;
+  this.end_ = 0;
+  this.cursor_ = 0;
+  this.error_ = false;
+};
+
+
+/**
+ * Returns the raw buffer.
+ * @return {?Uint8Array} The raw buffer.
+ */
+jspb.BinaryDecoder.prototype.getBuffer = function() {
+  return this.bytes_;
+};
+
+
+/**
+ * Changes the block of bytes we're decoding.
+ * @param {!jspb.ByteSource} data The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ */
+jspb.BinaryDecoder.prototype.setBlock =
+    function(data, opt_start, opt_length) {
+  this.bytes_ = jspb.utils.byteSourceToUint8Array(data);
+  this.start_ = goog.isDef(opt_start) ? opt_start : 0;
+  this.end_ =
+      goog.isDef(opt_length) ? this.start_ + opt_length : this.bytes_.length;
+  this.cursor_ = this.start_;
+};
+
+
+/**
+ * @return {number}
+ */
+jspb.BinaryDecoder.prototype.getEnd = function() {
+  return this.end_;
+};
+
+
+/**
+ * @param {number} end
+ */
+jspb.BinaryDecoder.prototype.setEnd = function(end) {
+  this.end_ = end;
+};
+
+
+/**
+ * Moves the read cursor back to the start of the block.
+ */
+jspb.BinaryDecoder.prototype.reset = function() {
+  this.cursor_ = this.start_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryDecoder.prototype.getCursor = function() {
+  return this.cursor_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @param {number} cursor The new cursor.
+ */
+jspb.BinaryDecoder.prototype.setCursor = function(cursor) {
+  this.cursor_ = cursor;
+};
+
+
+/**
+ * Advances the stream cursor by the given number of bytes.
+ * @param {number} count The number of bytes to advance by.
+ */
+jspb.BinaryDecoder.prototype.advance = function(count) {
+  this.cursor_ += count;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+};
+
+
+/**
+ * Returns true if this decoder is at the end of the block.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.atEnd = function() {
+  return this.cursor_ == this.end_;
+};
+
+
+/**
+ * Returns true if this decoder is at the end of the block.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.pastEnd = function() {
+  return this.cursor_ > this.end_;
+};
+
+
+/**
+ * Returns true if this decoder encountered an error due to corrupt data.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.getError = function() {
+  return this.error_ ||
+         (this.cursor_ < 0) ||
+         (this.cursor_ > this.end_);
+};
+
+
+/**
+ * Reads an unsigned varint from the binary stream and stores it as a split
+ * 64-bit integer. Since this does not convert the value to a number, no
+ * precision is lost.
+ *
+ * It's possible for an unsigned varint to be incorrectly encoded - more than
+ * 64 bits' worth of data could be present. If this happens, this method will
+ * throw an error.
+ *
+ * Decoding varints requires doing some funny base-128 math - for more
+ * details on the format, see
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @private
+ */
+jspb.BinaryDecoder.prototype.readSplitVarint64_ = function() {
+  var temp;
+  var lowBits = 0;
+  var highBits = 0;
+
+  // Read the first four bytes of the varint, stopping at the terminator if we
+  // see it.
+  for (var i = 0; i < 4; i++) {
+    temp = this.bytes_[this.cursor_++];
+    lowBits |= (temp & 0x7F) << (i * 7);
+    if (temp < 128) {
+      this.tempLow_ = lowBits >>> 0;
+      this.tempHigh_ = 0;
+      return;
+    }
+  }
+
+  // Read the fifth byte, which straddles the low and high dwords.
+  temp = this.bytes_[this.cursor_++];
+  lowBits |= (temp & 0x7F) << 28;
+  highBits |= (temp & 0x7F) >> 4;
+  if (temp < 128) {
+    this.tempLow_ = lowBits >>> 0;
+    this.tempHigh_ = highBits >>> 0;
+    return;
+  }
+
+  // Read the sixth through tenth byte.
+  for (var i = 0; i < 5; i++) {
+    temp = this.bytes_[this.cursor_++];
+    highBits |= (temp & 0x7F) << (i * 7 + 3);
+    if (temp < 128) {
+      this.tempLow_ = lowBits >>> 0;
+      this.tempHigh_ = highBits >>> 0;
+      return;
+    }
+  }
+
+  // If we did not see the terminator, the encoding was invalid.
+  goog.asserts.fail('Failed to read varint, encoding is invalid.');
+  this.error_ = true;
+};
+
+
+/**
+ * Skips over a varint in the block without decoding it.
+ */
+jspb.BinaryDecoder.prototype.skipVarint = function() {
+  while (this.bytes_[this.cursor_] & 0x80) {
+    this.cursor_++;
+  }
+  this.cursor_++;
+};
+
+
+/**
+ * Skips backwards over a varint in the block - to do this correctly, we have
+ * to know the value we're skipping backwards over or things are ambiguous.
+ * @param {number} value The varint value to unskip.
+ */
+jspb.BinaryDecoder.prototype.unskipVarint = function(value) {
+  while (value > 128) {
+    this.cursor_--;
+    value = value >>> 7;
+  }
+  this.cursor_--;
+};
+
+
+/**
+ * Reads a 32-bit varint from the binary stream. Due to a quirk of the encoding
+ * format and Javascript's handling of bitwise math, this actually works
+ * correctly for both signed and unsigned 32-bit varints.
+ *
+ * This function is called vastly more frequently than any other in
+ * BinaryDecoder, so it has been unrolled and tweaked for performance.
+ *
+ * If there are more than 32 bits of data in the varint, it _must_ be due to
+ * sign-extension. If we're in debug mode and the high 32 bits don't match the
+ * expected sign extension, this method will throw an error.
+ *
+ * Decoding varints requires doing some funny base-128 math - for more
+ * details on the format, see
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded unsigned 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() {
+  var temp;
+  var bytes = this.bytes_;
+
+  temp = bytes[this.cursor_ + 0];
+  var x = (temp & 0x7F);
+  if (temp < 128) {
+    this.cursor_ += 1;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 1];
+  x |= (temp & 0x7F) << 7;
+  if (temp < 128) {
+    this.cursor_ += 2;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 2];
+  x |= (temp & 0x7F) << 14;
+  if (temp < 128) {
+    this.cursor_ += 3;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 3];
+  x |= (temp & 0x7F) << 21;
+  if (temp < 128) {
+    this.cursor_ += 4;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 4];
+  x |= (temp & 0x0F) << 28;
+  if (temp < 128) {
+    // We're reading the high bits of an unsigned varint. The byte we just read
+    // also contains bits 33 through 35, which we're going to discard. Those
+    // bits _must_ be zero, or the encoding is invalid.
+    goog.asserts.assert((temp & 0xF0) == 0);
+    this.cursor_ += 5;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x >>> 0;
+  }
+
+  // If we get here, we're reading the sign extension of a negative 32-bit int.
+  // We can skip these bytes, as we know in advance that they have to be all
+  // 1's if the varint is correctly encoded. Since we also know the value is
+  // negative, we don't have to coerce it to unsigned before we return it.
+
+  goog.asserts.assert((temp & 0xF0) == 0xF0);
+  goog.asserts.assert(bytes[this.cursor_ + 5] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 6] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 7] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 8] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 9] == 0x01);
+
+  this.cursor_ += 10;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return x;
+};
+
+
+/**
+ * The readUnsignedVarint32 above deals with signed 32-bit varints correctly,
+ * so this is just an alias.
+ *
+ * @return {number} The decoded signed 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint32 =
+    jspb.BinaryDecoder.prototype.readUnsignedVarint32;
+
+
+/**
+ * Reads a 32-bit unsigned variant and returns its value as a string.
+ *
+ * @return {string} The decoded unsigned 32-bit varint as a string.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() {
+  // 32-bit integers fit in JavaScript numbers without loss of precision, so
+  // string variants of 32-bit varint readers can simply delegate then convert
+  // to string.
+  var value = this.readUnsignedVarint32();
+  return value.toString();
+};
+
+
+/**
+ * Reads a 32-bit signed variant and returns its value as a string.
+ *
+ * @return {string} The decoded signed 32-bit varint as a string.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
+  // 32-bit integers fit in JavaScript numbers without loss of precision, so
+  // string variants of 32-bit varint readers can simply delegate then convert
+  // to string.
+  var value = this.readSignedVarint32();
+  return value.toString();
+};
+
+
+/**
+ * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
+ *
+ * Zigzag encoding is a modification of varint encoding that reduces the
+ * storage overhead for small negative integers - for more details on the
+ * format, see https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
+  var result = this.readUnsignedVarint32();
+  return (result >>> 1) ^ - (result & 1);
+};
+
+
+/**
+ * Reads an unsigned 64-bit varint from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the varint is larger than 2^53.
+ *
+ * @return {number} The decoded unsigned varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads an unsigned 64-bit varint from the binary stream and returns the value
+ * as a decimal string.
+ *
+ * @return {string} The decoded unsigned varint as a decimal string.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a signed 64-bit varint from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the varint is larger than 2^53.
+ *
+ * @return {number} The decoded signed varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads an signed 64-bit varint from the binary stream and returns the value
+ * as a decimal string.
+ *
+ * @return {string} The decoded signed varint as a decimal string.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
+ * that since Javascript represents all numbers as double-precision floats,
+ * there will be precision lost if the absolute value of the varint is larger
+ * than 2^53.
+ *
+ * Zigzag encoding is a modification of varint encoding that reduces the
+ * storage overhead for small negative integers - for more details on the
+ * format, see https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded zigzag varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a raw unsigned 8-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 8-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint8 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  this.cursor_ += 1;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return a;
+};
+
+
+/**
+ * Reads a raw unsigned 16-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 16-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint16 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  this.cursor_ += 2;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 0) | (b << 8);
+};
+
+
+/**
+ * Reads a raw unsigned 32-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 32-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint32 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  var c = this.bytes_[this.cursor_ + 2];
+  var d = this.bytes_[this.cursor_ + 3];
+  this.cursor_ += 4;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
+};
+
+
+/**
+ * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the integer is larger than 2^53.
+ *
+ * @return {number} The unsigned 64-bit integer read from the binary stream.
+ *     Precision will be lost if the integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readUint64 = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinUint64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a raw signed 8-bit integer from the binary stream.
+ *
+ * @return {number} The signed 8-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt8 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  this.cursor_ += 1;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 24) >> 24;
+};
+
+
+/**
+ * Reads a raw signed 16-bit integer from the binary stream.
+ *
+ * @return {number} The signed 16-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt16 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  this.cursor_ += 2;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (((a << 0) | (b << 8)) << 16) >> 16;
+};
+
+
+/**
+ * Reads a raw signed 32-bit integer from the binary stream.
+ *
+ * @return {number} The signed 32-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt32 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  var c = this.bytes_[this.cursor_ + 2];
+  var d = this.bytes_[this.cursor_ + 3];
+  this.cursor_ += 4;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 0) | (b << 8) | (c << 16) | (d << 24);
+};
+
+
+/**
+ * Reads a raw signed 64-bit integer from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute vlaue of the integer is larger than 2^53.
+ *
+ * @return {number} The signed 64-bit integer read from the binary stream.
+ *     Precision will be lost if the integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readInt64 = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinInt64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a 32-bit floating-point number from the binary stream, using the
+ * temporary buffer to realign the data.
+ *
+ * @return {number} The float read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readFloat = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = 0;
+  return jspb.utils.joinFloat32(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a 64-bit floating-point number from the binary stream, using the
+ * temporary buffer to realign the data.
+ *
+ * @return {number} The double read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readDouble = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinFloat64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a boolean value from the binary stream.
+ * @return {boolean} The boolean read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readBool = function() {
+  return !!this.bytes_[this.cursor_++];
+};
+
+
+/**
+ * Reads an enum value from the binary stream, which are always encoded as
+ * signed varints.
+ * @return {number} The enum value read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readEnum = function() {
+  return this.readSignedVarint32();
+};
+
+
+/**
+ * Reads and parses a UTF-8 encoded unicode string from the stream.
+ * The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with
+ * the exception that the implementation here does not get confused if it
+ * encounters characters longer than three bytes. These characters are ignored
+ * though, as they are extremely rare: three UTF-8 bytes cover virtually all
+ * characters in common use (http://en.wikipedia.org/wiki/UTF-8).
+ * @param {number} length The length of the string to read.
+ * @return {string} The decoded string.
+ */
+jspb.BinaryDecoder.prototype.readString = function(length) {
+  var bytes = this.bytes_;
+  var cursor = this.cursor_;
+  var end = cursor + length;
+  var chars = [];
+
+  while (cursor < end) {
+    var c = bytes[cursor++];
+    if (c < 128) { // Regular 7-bit ASCII.
+      chars.push(c);
+    } else if (c < 192) {
+      // UTF-8 continuation mark. We are out of sync. This
+      // might happen if we attempted to read a character
+      // with more than three bytes.
+      continue;
+    } else if (c < 224) { // UTF-8 with two bytes.
+      var c2 = bytes[cursor++];
+      chars.push(((c & 31) << 6) | (c2 & 63));
+    } else if (c < 240) { // UTF-8 with three bytes.
+      var c2 = bytes[cursor++];
+      var c3 = bytes[cursor++];
+      chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+    }
+  }
+
+  // String.fromCharCode.apply is faster than manually appending characters on
+  // Chrome 25+, and generates no additional cons string garbage.
+  var result = String.fromCharCode.apply(null, chars);
+  this.cursor_ = cursor;
+  return result;
+};
+
+
+/**
+ * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
+ * the stream.
+ * @return {string} The decoded string.
+ */
+jspb.BinaryDecoder.prototype.readStringWithLength = function() {
+  var length = this.readUnsignedVarint32();
+  return this.readString(length);
+};
+
+
+/**
+ * Reads a block of raw bytes from the binary stream.
+ *
+ * @param {number} length The number of bytes to read.
+ * @return {!Uint8Array} The decoded block of bytes, or an empty block if the
+ *     length was invalid.
+ */
+jspb.BinaryDecoder.prototype.readBytes = function(length) {
+  if (length < 0 ||
+      this.cursor_ + length > this.bytes_.length) {
+    this.error_ = true;
+    goog.asserts.fail('Invalid byte length!');
+    return new Uint8Array(0);
+  }
+
+  var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
+
+  this.cursor_ += length;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return result;
+};
+
+
+/**
+ * Reads a 64-bit varint from the stream and returns it as an 8-character
+ * Unicode string for use as a hash table key.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a 64-bit fixed-width value from the stream and returns it as an
+ * 8-character Unicode string for use as a hash table key.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
+  var bytes = this.bytes_;
+  var cursor = this.cursor_;
+
+  var a = bytes[cursor + 0];
+  var b = bytes[cursor + 1];
+  var c = bytes[cursor + 2];
+  var d = bytes[cursor + 3];
+  var e = bytes[cursor + 4];
+  var f = bytes[cursor + 5];
+  var g = bytes[cursor + 6];
+  var h = bytes[cursor + 7];
+
+  this.cursor_ += 8;
+
+  return String.fromCharCode(a, b, c, d, e, f, g, h);
+};
diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js
new file mode 100644
index 0000000..d045e91
--- /dev/null
+++ b/js/binary/decoder_test.js
@@ -0,0 +1,335 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer decoder.
+ *
+ * There are two particular magic numbers that need to be pointed out -
+ * 2^64-1025 is the largest number representable as both a double and an
+ * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
+ * both a double and a signed 64-bit integer.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+goog.require('jspb.BinaryEncoder');
+
+
+/**
+ * Tests encoding and decoding of unsigned types.
+ * @param {Function} readValue
+ * @param {Function} writeValue
+ * @param {number} epsilon
+ * @param {number} upperLimit
+ * @param {Function} filter
+ * @suppress {missingProperties|visibility}
+ */
+function doTestUnsignedValue(readValue,
+    writeValue, epsilon, upperLimit, filter) {
+  var encoder = new jspb.BinaryEncoder();
+
+  // Encode zero and limits.
+  writeValue.call(encoder, filter(0));
+  writeValue.call(encoder, filter(epsilon));
+  writeValue.call(encoder, filter(upperLimit));
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    writeValue.call(encoder, filter(cursor));
+  }
+
+  var decoder = jspb.BinaryDecoder.alloc(encoder.end());
+
+  // Check zero and limits.
+  assertEquals(filter(0), readValue.call(decoder));
+  assertEquals(filter(epsilon), readValue.call(decoder));
+  assertEquals(filter(upperLimit), readValue.call(decoder));
+
+  // Check positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    if (filter(cursor) != readValue.call(decoder)) throw 'fail!';
+  }
+
+  // Encoding values outside the valid range should assert.
+  assertThrows(function() {writeValue.call(encoder, -1);});
+  assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);});
+}
+
+
+/**
+ * Tests encoding and decoding of signed types.
+ * @param {Function} readValue
+ * @param {Function} writeValue
+ * @param {number} epsilon
+ * @param {number} lowerLimit
+ * @param {number} upperLimit
+ * @param {Function} filter
+ * @suppress {missingProperties}
+ */
+function doTestSignedValue(readValue,
+    writeValue, epsilon, lowerLimit, upperLimit, filter) {
+  var encoder = new jspb.BinaryEncoder();
+
+  // Encode zero and limits.
+  writeValue.call(encoder, filter(lowerLimit));
+  writeValue.call(encoder, filter(-epsilon));
+  writeValue.call(encoder, filter(0));
+  writeValue.call(encoder, filter(epsilon));
+  writeValue.call(encoder, filter(upperLimit));
+
+  var inputValues = [];
+
+  // Encode negative values.
+  for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(encoder, val);
+    inputValues.push(val);
+  }
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(encoder, val);
+    inputValues.push(val);
+  }
+
+  var decoder = jspb.BinaryDecoder.alloc(encoder.end());
+
+  // Check zero and limits.
+  assertEquals(filter(lowerLimit), readValue.call(decoder));
+  assertEquals(filter(-epsilon), readValue.call(decoder));
+  assertEquals(filter(0), readValue.call(decoder));
+  assertEquals(filter(epsilon), readValue.call(decoder));
+  assertEquals(filter(upperLimit), readValue.call(decoder));
+
+  // Verify decoded values.
+  for (var i = 0; i < inputValues.length; i++) {
+    assertEquals(inputValues[i], readValue.call(decoder));
+  }
+
+  // Encoding values outside the valid range should assert.
+  assertThrows(function() {writeValue.call(encoder, lowerLimit * 1.1);});
+  assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);});
+}
+
+describe('binaryDecoderTest', function() {
+  /**
+   * Tests the decoder instance cache.
+   * @suppress {visibility}
+   */
+  it('testInstanceCache', function() {
+    // Empty the instance caches.
+    jspb.BinaryDecoder.instanceCache_ = [];
+
+    // Allocating and then freeing a decoder should put it in the instance
+    // cache.
+    jspb.BinaryDecoder.alloc().free();
+
+    assertEquals(1, jspb.BinaryDecoder.instanceCache_.length);
+
+    // Allocating and then freeing three decoders should leave us with three in
+    // the cache.
+
+    var decoder1 = jspb.BinaryDecoder.alloc();
+    var decoder2 = jspb.BinaryDecoder.alloc();
+    var decoder3 = jspb.BinaryDecoder.alloc();
+    decoder1.free();
+    decoder2.free();
+    decoder3.free();
+
+    assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
+  });
+
+
+  /**
+   * Tests reading 64-bit integers as hash strings.
+   */
+  it('testHashStrings', function() {
+    var encoder = new jspb.BinaryEncoder();
+
+    var hashA = String.fromCharCode(0x00, 0x00, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00);
+    var hashB = String.fromCharCode(0x12, 0x34, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00);
+    var hashC = String.fromCharCode(0x12, 0x34, 0x56, 0x78,
+                                    0x87, 0x65, 0x43, 0x21);
+    var hashD = String.fromCharCode(0xFF, 0xFF, 0xFF, 0xFF,
+                                    0xFF, 0xFF, 0xFF, 0xFF);
+
+    encoder.writeVarintHash64(hashA);
+    encoder.writeVarintHash64(hashB);
+    encoder.writeVarintHash64(hashC);
+    encoder.writeVarintHash64(hashD);
+
+    encoder.writeFixedHash64(hashA);
+    encoder.writeFixedHash64(hashB);
+    encoder.writeFixedHash64(hashC);
+    encoder.writeFixedHash64(hashD);
+
+    var decoder = jspb.BinaryDecoder.alloc(encoder.end());
+
+    assertEquals(hashA, decoder.readVarintHash64());
+    assertEquals(hashB, decoder.readVarintHash64());
+    assertEquals(hashC, decoder.readVarintHash64());
+    assertEquals(hashD, decoder.readVarintHash64());
+
+    assertEquals(hashA, decoder.readFixedHash64());
+    assertEquals(hashB, decoder.readFixedHash64());
+    assertEquals(hashC, decoder.readFixedHash64());
+    assertEquals(hashD, decoder.readFixedHash64());
+  });
+
+
+  /**
+   * Verifies that misuse of the decoder class triggers assertions.
+   * @suppress {checkTypes|visibility}
+   */
+  it('testDecodeErrors', function() {
+    // Reading a value past the end of the stream should trigger an assertion.
+    var decoder = jspb.BinaryDecoder.alloc([0, 1, 2]);
+    assertThrows(function() {decoder.readUint64()});
+
+    // Overlong varints should trigger assertions.
+    decoder.setBlock([255, 255, 255, 255, 255, 255,
+                      255, 255, 255, 255, 255, 0]);
+    assertThrows(function() {decoder.readUnsignedVarint64()});
+    decoder.reset();
+    assertThrows(function() {decoder.readSignedVarint64()});
+    decoder.reset();
+    assertThrows(function() {decoder.readZigzagVarint64()});
+
+    // Positive 32-bit varints encoded with 1 bits in positions 33 through 35
+    // should trigger assertions.
+    decoder.setBlock([255, 255, 255, 255, 0x1F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 0x2F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 0x4F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    // Negative 32-bit varints encoded with non-1 bits in the high dword should
+    // trigger assertions.
+    decoder.setBlock([255, 255, 255, 255, 255, 255, 0, 255, 255, 1]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 255, 255, 255, 255, 255, 0]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+  });
+
+
+  /**
+   * Tests encoding and decoding of unsigned integers.
+   */
+  it('testUnsignedIntegers', function() {
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint8,
+        jspb.BinaryEncoder.prototype.writeUint8,
+        1, 0xFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint16,
+        jspb.BinaryEncoder.prototype.writeUint16,
+        1, 0xFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint32,
+        jspb.BinaryEncoder.prototype.writeUint32,
+        1, 0xFFFFFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint64,
+        jspb.BinaryEncoder.prototype.writeUint64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+  });
+
+
+  /**
+   * Tests encoding and decoding of signed integers.
+   */
+  it('testSignedIntegers', function() {
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt8,
+        jspb.BinaryEncoder.prototype.writeInt8,
+        1, -0x80, 0x7F, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt16,
+        jspb.BinaryEncoder.prototype.writeInt16,
+        1, -0x8000, 0x7FFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt32,
+        jspb.BinaryEncoder.prototype.writeInt32,
+        1, -0x80000000, 0x7FFFFFFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt64,
+        jspb.BinaryEncoder.prototype.writeInt64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests encoding and decoding of floats.
+   */
+  it('testFloats', function() {
+    /**
+     * @param {number} x
+     * @return {number}
+     */
+    function truncate(x) {
+      var temp = new Float32Array(1);
+      temp[0] = x;
+      return temp[0];
+    }
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readFloat,
+        jspb.BinaryEncoder.prototype.writeFloat,
+        jspb.BinaryConstants.FLOAT32_EPS,
+        -jspb.BinaryConstants.FLOAT32_MAX,
+        jspb.BinaryConstants.FLOAT32_MAX,
+        truncate);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readDouble,
+        jspb.BinaryEncoder.prototype.writeDouble,
+        jspb.BinaryConstants.FLOAT64_EPS * 10,
+        -jspb.BinaryConstants.FLOAT64_MAX,
+        jspb.BinaryConstants.FLOAT64_MAX,
+        function(x) { return x; });
+  });
+});
diff --git a/js/binary/encoder.js b/js/binary/encoder.js
new file mode 100644
index 0000000..c9b0c2a
--- /dev/null
+++ b/js/binary/encoder.js
@@ -0,0 +1,430 @@
+// 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.
+
+/**
+ * @fileoverview BinaryEncode defines methods for encoding Javascript values
+ * into arrays of bytes compatible with the Protocol Buffer wire format.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryEncoder');
+
+goog.require('goog.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.utils');
+
+
+
+/**
+ * BinaryEncoder implements encoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @constructor
+ * @struct
+ */
+jspb.BinaryEncoder = function() {
+  /** @private {!Array.<number>} */
+  this.buffer_ = [];
+};
+
+
+/**
+ * @return {number}
+ */
+jspb.BinaryEncoder.prototype.length = function() {
+  return this.buffer_.length;
+};
+
+
+/**
+ * @return {!Array.<number>}
+ */
+jspb.BinaryEncoder.prototype.end = function() {
+  var buffer = this.buffer_;
+  this.buffer_ = [];
+  return buffer;
+};
+
+
+/**
+ * Encodes a 64-bit integer in 32:32 split representation into its wire-format
+ * varint representation and stores it in the buffer.
+ * @param {number} lowBits The low 32 bits of the int.
+ * @param {number} highBits The high 32 bits of the int.
+ */
+jspb.BinaryEncoder.prototype.writeSplitVarint64 = function(lowBits, highBits) {
+  goog.asserts.assert(lowBits == Math.floor(lowBits));
+  goog.asserts.assert(highBits == Math.floor(highBits));
+  goog.asserts.assert((lowBits >= 0) &&
+                      (lowBits < jspb.BinaryConstants.TWO_TO_32));
+  goog.asserts.assert((highBits >= 0) &&
+                      (highBits < jspb.BinaryConstants.TWO_TO_32));
+
+  // Break the binary representation into chunks of 7 bits, set the 8th bit
+  // in each chunk if it's not the final chunk, and append to the result.
+  while (highBits > 0 || lowBits > 127) {
+    this.buffer_.push((lowBits & 0x7f) | 0x80);
+    lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0;
+    highBits = highBits >>> 7;
+  }
+  this.buffer_.push(lowBits);
+};
+
+
+/**
+ * Encodes a 32-bit unsigned integer into its wire-format varint representation
+ * and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeUnsignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+
+  while (value > 127) {
+    this.buffer_.push((value & 0x7f) | 0x80);
+    value = value >>> 7;
+  }
+
+  this.buffer_.push(value);
+};
+
+
+/**
+ * Encodes a 32-bit signed integer into its wire-format varint representation
+ * and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeSignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+
+  // Use the unsigned version if the value is not negative.
+  if (value >= 0) {
+    this.writeUnsignedVarint32(value);
+    return;
+  }
+
+  // Write nine bytes with a _signed_ right shift so we preserve the sign bit.
+  for (var i = 0; i < 9; i++) {
+    this.buffer_.push((value & 0x7f) | 0x80);
+    value = value >> 7;
+  }
+
+  // The above loop writes out 63 bits, so the last byte is always the sign bit
+  // which is always set for negative numbers.
+  this.buffer_.push(1);
+};
+
+
+/**
+ * Encodes a 64-bit unsigned integer into its wire-format varint representation
+ * and stores it in the buffer. Integers that are not representable in 64 bits
+ * will be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeUnsignedVarint64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  jspb.utils.splitInt64(value);
+  this.writeSplitVarint64(jspb.utils.split64Low,
+                          jspb.utils.split64High);
+};
+
+
+/**
+ * Encodes a 64-bit signed integer into its wire-format varint representation
+ * and stores it in the buffer. Integers that are not representable in 64 bits
+ * will be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeSignedVarint64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  jspb.utils.splitInt64(value);
+  this.writeSplitVarint64(jspb.utils.split64Low,
+                          jspb.utils.split64High);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
+ * representation and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeZigzagVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeUnsignedVarint32(((value << 1) ^ (value >> 31)) >>> 0);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
+ * representation and stores it in the buffer. Integers not representable in 64
+ * bits will be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeZigzagVarint64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  jspb.utils.splitZigzag64(value);
+  this.writeSplitVarint64(jspb.utils.split64Low,
+                          jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a 8-bit unsigned integer to the buffer. Numbers outside the range
+ * [0,2^8) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeUint8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 256));
+  this.buffer_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a 16-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^16) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeUint16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 65536));
+  this.buffer_.push((value >>> 0) & 0xFF);
+  this.buffer_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a 32-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^32) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeUint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.buffer_.push((value >>> 0) & 0xFF);
+  this.buffer_.push((value >>> 8) & 0xFF);
+  this.buffer_.push((value >>> 16) & 0xFF);
+  this.buffer_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a 64-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^64) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeUint64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  jspb.utils.splitUint64(value);
+  this.writeUint32(jspb.utils.split64Low);
+  this.writeUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a 8-bit integer to the buffer. Numbers outside the range
+ * [-2^7,2^7) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeInt8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -128) && (value < 128));
+  this.buffer_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a 16-bit integer to the buffer. Numbers outside the range
+ * [-2^15,2^15) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeInt16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -32768) && (value < 32768));
+  this.buffer_.push((value >>> 0) & 0xFF);
+  this.buffer_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a 32-bit integer to the buffer. Numbers outside the range
+ * [-2^31,2^31) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeInt32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.buffer_.push((value >>> 0) & 0xFF);
+  this.buffer_.push((value >>> 8) & 0xFF);
+  this.buffer_.push((value >>> 16) & 0xFF);
+  this.buffer_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a 64-bit integer to the buffer. Numbers outside the range
+ * [-2^63,2^63) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeInt64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  jspb.utils.splitInt64(value);
+  this.writeUint32(jspb.utils.split64Low);
+  this.writeUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a single-precision floating point value to the buffer. Numbers
+ * requiring more than 32 bits of precision will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeFloat = function(value) {
+  goog.asserts.assert((value >= -jspb.BinaryConstants.FLOAT32_MAX) &&
+                      (value <= jspb.BinaryConstants.FLOAT32_MAX));
+  jspb.utils.splitFloat32(value);
+  this.writeUint32(jspb.utils.split64Low);
+};
+
+
+/**
+ * Writes a double-precision floating point value to the buffer. As this is
+ * the native format used by JavaScript, no precision will be lost.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeDouble = function(value) {
+  goog.asserts.assert((value >= -jspb.BinaryConstants.FLOAT64_MAX) &&
+                      (value <= jspb.BinaryConstants.FLOAT64_MAX));
+  jspb.utils.splitFloat64(value);
+  this.writeUint32(jspb.utils.split64Low);
+  this.writeUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a boolean value to the buffer as a varint.
+ * @param {boolean} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeBool = function(value) {
+  goog.asserts.assert(goog.isBoolean(value));
+  this.buffer_.push(value ? 1 : 0);
+};
+
+
+/**
+ * Writes an enum value to the buffer as a varint.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeEnum = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeSignedVarint32(value);
+};
+
+
+/**
+ * Writes an arbitrary byte array to the buffer.
+ * @param {!Uint8Array} bytes The array of bytes to write.
+ */
+jspb.BinaryEncoder.prototype.writeBytes = function(bytes) {
+  this.buffer_.push.apply(this.buffer_, bytes);
+};
+
+
+/**
+ * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
+ * buffer as a varint.
+ * @param {string} hash The hash to write.
+ */
+jspb.BinaryEncoder.prototype.writeVarintHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.writeSplitVarint64(jspb.utils.split64Low,
+                          jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
+ * buffer as a fixed64.
+ * @param {string} hash The hash to write.
+ */
+jspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.writeUint32(jspb.utils.split64Low);
+  this.writeUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a UTF16 Javascript string to the buffer encoded as UTF8.
+ * TODO(aappleby): Add support for surrogate pairs, reject unpaired surrogates.
+ * @param {string} value The string to write.
+ * @return {number} The number of bytes used to encode the string.
+ */
+jspb.BinaryEncoder.prototype.writeString = function(value) {
+  var oldLength = this.buffer_.length;
+
+  // UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray.
+  for (var i = 0; i < value.length; i++) {
+    var c = value.charCodeAt(i);
+    if (c < 128) {
+      this.buffer_.push(c);
+    } else if (c < 2048) {
+      this.buffer_.push((c >> 6) | 192);
+      this.buffer_.push((c & 63) | 128);
+    } else {
+      this.buffer_.push((c >> 12) | 224);
+      this.buffer_.push(((c >> 6) & 63) | 128);
+      this.buffer_.push((c & 63) | 128);
+    }
+  }
+
+  var length = this.buffer_.length - oldLength;
+  return length;
+};
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
new file mode 100644
index 0000000..14d0f42
--- /dev/null
+++ b/js/binary/proto_test.js
@@ -0,0 +1,628 @@
+// 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.
+
+// Test suite is written using Jasmine -- see http://jasmine.github.io/
+
+goog.require('goog.crypt.base64');
+goog.require('goog.testing.asserts');
+goog.require('jspb.Message');
+
+// CommonJS-LoadFromFile: ../testbinary_pb proto.jspb.test
+goog.require('proto.jspb.test.ExtendsWithMessage');
+goog.require('proto.jspb.test.ForeignEnum');
+goog.require('proto.jspb.test.ForeignMessage');
+goog.require('proto.jspb.test.TestAllTypes');
+goog.require('proto.jspb.test.TestExtendable');
+goog.require('proto.jspb.test.extendOptionalBool');
+goog.require('proto.jspb.test.extendOptionalBytes');
+goog.require('proto.jspb.test.extendOptionalDouble');
+goog.require('proto.jspb.test.extendOptionalFixed32');
+goog.require('proto.jspb.test.extendOptionalFixed64');
+goog.require('proto.jspb.test.extendOptionalFloat');
+goog.require('proto.jspb.test.extendOptionalForeignEnum');
+goog.require('proto.jspb.test.extendOptionalInt32');
+goog.require('proto.jspb.test.extendOptionalInt64');
+goog.require('proto.jspb.test.extendOptionalSfixed32');
+goog.require('proto.jspb.test.extendOptionalSfixed64');
+goog.require('proto.jspb.test.extendOptionalSint32');
+goog.require('proto.jspb.test.extendOptionalSint64');
+goog.require('proto.jspb.test.extendOptionalString');
+goog.require('proto.jspb.test.extendOptionalUint32');
+goog.require('proto.jspb.test.extendOptionalUint64');
+goog.require('proto.jspb.test.extendPackedRepeatedBoolList');
+goog.require('proto.jspb.test.extendPackedRepeatedDoubleList');
+goog.require('proto.jspb.test.extendPackedRepeatedFixed32List');
+goog.require('proto.jspb.test.extendPackedRepeatedFixed64List');
+goog.require('proto.jspb.test.extendPackedRepeatedFloatList');
+goog.require('proto.jspb.test.extendPackedRepeatedForeignEnumList');
+goog.require('proto.jspb.test.extendPackedRepeatedInt32List');
+goog.require('proto.jspb.test.extendPackedRepeatedInt64List');
+goog.require('proto.jspb.test.extendPackedRepeatedSfixed32List');
+goog.require('proto.jspb.test.extendPackedRepeatedSfixed64List');
+goog.require('proto.jspb.test.extendPackedRepeatedSint32List');
+goog.require('proto.jspb.test.extendPackedRepeatedSint64List');
+goog.require('proto.jspb.test.extendPackedRepeatedUint32List');
+goog.require('proto.jspb.test.extendPackedRepeatedUint64List');
+goog.require('proto.jspb.test.extendRepeatedBoolList');
+goog.require('proto.jspb.test.extendRepeatedBytesList');
+goog.require('proto.jspb.test.extendRepeatedDoubleList');
+goog.require('proto.jspb.test.extendRepeatedFixed32List');
+goog.require('proto.jspb.test.extendRepeatedFixed64List');
+goog.require('proto.jspb.test.extendRepeatedFloatList');
+goog.require('proto.jspb.test.extendRepeatedForeignEnumList');
+goog.require('proto.jspb.test.extendRepeatedInt32List');
+goog.require('proto.jspb.test.extendRepeatedInt64List');
+goog.require('proto.jspb.test.extendRepeatedSfixed32List');
+goog.require('proto.jspb.test.extendRepeatedSfixed64List');
+goog.require('proto.jspb.test.extendRepeatedSint32List');
+goog.require('proto.jspb.test.extendRepeatedSint64List');
+goog.require('proto.jspb.test.extendRepeatedStringList');
+goog.require('proto.jspb.test.extendRepeatedUint32List');
+goog.require('proto.jspb.test.extendRepeatedUint64List');
+
+
+var suite = {};
+
+var BYTES = new Uint8Array([1, 2, 8, 9]);
+
+var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
+
+
+/**
+ * Helper: fill all fields on a TestAllTypes message.
+ * @param {proto.jspb.test.TestAllTypes} msg
+ */
+function fillAllFields(msg) {
+  msg.setOptionalInt32(-42);
+  // can be exactly represented by JS number (64-bit double, i.e., 52-bit
+  // mantissa).
+  msg.setOptionalInt64(-0x7fffffff00000000);
+  msg.setOptionalUint32(0x80000000);
+  msg.setOptionalUint64(0xf000000000000000);
+  msg.setOptionalSint32(-100);
+  msg.setOptionalSint64(-0x8000000000000000);
+  msg.setOptionalFixed32(1234);
+  msg.setOptionalFixed64(0x1234567800000000);
+  msg.setOptionalSfixed32(-1234);
+  msg.setOptionalSfixed64(-0x1234567800000000);
+  msg.setOptionalFloat(1.5);
+  msg.setOptionalDouble(-1.5);
+  msg.setOptionalBool(true);
+  msg.setOptionalString('hello world');
+  msg.setOptionalBytes(BYTES);
+  msg.setOptionalGroup(new proto.jspb.test.TestAllTypes.OptionalGroup());
+  msg.getOptionalGroup().setA(100);
+  var submsg = new proto.jspb.test.ForeignMessage();
+  submsg.setC(16);
+  msg.setOptionalForeignMessage(submsg);
+  msg.setOptionalForeignEnum(proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+  msg.setOneofString('oneof');
+
+
+  msg.setRepeatedInt32List([-42]);
+  msg.setRepeatedInt64List([-0x7fffffff00000000]);
+  msg.setRepeatedUint32List([0x80000000]);
+  msg.setRepeatedUint64List([0xf000000000000000]);
+  msg.setRepeatedSint32List([-100]);
+  msg.setRepeatedSint64List([-0x8000000000000000]);
+  msg.setRepeatedFixed32List([1234]);
+  msg.setRepeatedFixed64List([0x1234567800000000]);
+  msg.setRepeatedSfixed32List([-1234]);
+  msg.setRepeatedSfixed64List([-0x1234567800000000]);
+  msg.setRepeatedFloatList([1.5]);
+  msg.setRepeatedDoubleList([-1.5]);
+  msg.setRepeatedBoolList([true]);
+  msg.setRepeatedStringList(['hello world']);
+  msg.setRepeatedBytesList([BYTES, BYTES]);
+  msg.setRepeatedGroupList([new proto.jspb.test.TestAllTypes.RepeatedGroup()]);
+  msg.getRepeatedGroupList()[0].setA(100);
+  submsg = new proto.jspb.test.ForeignMessage();
+  submsg.setC(1000);
+  msg.setRepeatedForeignMessageList([submsg]);
+  msg.setRepeatedForeignEnumList([proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  msg.setPackedRepeatedInt32List([-42]);
+  msg.setPackedRepeatedInt64List([-0x7fffffff00000000]);
+  msg.setPackedRepeatedUint32List([0x80000000]);
+  msg.setPackedRepeatedUint64List([0xf000000000000000]);
+  msg.setPackedRepeatedSint32List([-100]);
+  msg.setPackedRepeatedSint64List([-0x8000000000000000]);
+  msg.setPackedRepeatedFixed32List([1234]);
+  msg.setPackedRepeatedFixed64List([0x1234567800000000]);
+  msg.setPackedRepeatedSfixed32List([-1234]);
+  msg.setPackedRepeatedSfixed64List([-0x1234567800000000]);
+  msg.setPackedRepeatedFloatList([1.5]);
+  msg.setPackedRepeatedDoubleList([-1.5]);
+  msg.setPackedRepeatedBoolList([true]);
+
+}
+
+
+/**
+ * Helper: compare a bytes field to an expected value
+ * @param {Uint8Array|string} arr
+ * @param {Uint8Array} expected
+ * @return {boolean}
+ */
+function bytesCompare(arr, expected) {
+  if (goog.isString(arr)) {
+    arr = goog.crypt.base64.decodeStringToUint8Array(arr);
+  }
+  if (arr.length != expected.length) {
+    return false;
+  }
+  for (var i = 0; i < arr.length; i++) {
+    if (arr[i] != expected[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+/**
+ * Helper: verify contents of given TestAllTypes message as set by
+ * fillAllFields().
+ * @param {proto.jspb.test.TestAllTypes} original
+ * @param {proto.jspb.test.TestAllTypes} copy
+ */
+function checkAllFields(original, copy) {
+  assertTrue(jspb.Message.equals(original, copy));
+
+  assertEquals(copy.getOptionalInt32(), -42);
+  assertEquals(copy.getOptionalInt64(), -0x7fffffff00000000);
+  assertEquals(copy.getOptionalUint32(), 0x80000000);
+  assertEquals(copy.getOptionalUint64(), 0xf000000000000000);
+  assertEquals(copy.getOptionalSint32(), -100);
+  assertEquals(copy.getOptionalSint64(), -0x8000000000000000);
+  assertEquals(copy.getOptionalFixed32(), 1234);
+  assertEquals(copy.getOptionalFixed64(), 0x1234567800000000);
+  assertEquals(copy.getOptionalSfixed32(), -1234);
+  assertEquals(copy.getOptionalSfixed64(), -0x1234567800000000);
+  assertEquals(copy.getOptionalFloat(), 1.5);
+  assertEquals(copy.getOptionalDouble(), -1.5);
+  assertEquals(copy.getOptionalBool(), true);
+  assertEquals(copy.getOptionalString(), 'hello world');
+  assertEquals(true, bytesCompare(copy.getOptionalBytes(), BYTES));
+  assertEquals(true, bytesCompare(copy.getOptionalBytes_asU8(), BYTES));
+  assertEquals(
+      copy.getOptionalBytes_asB64(), goog.crypt.base64.encodeByteArray(BYTES));
+
+  assertEquals(copy.getOptionalGroup().getA(), 100);
+  assertEquals(copy.getOptionalForeignMessage().getC(), 16);
+  assertEquals(copy.getOptionalForeignEnum(),
+      proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+
+
+  assertEquals(copy.getOneofString(), 'oneof');
+  assertEquals(copy.getOneofFieldCase(),
+      proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING);
+
+  assertElementsEquals(copy.getRepeatedInt32List(), [-42]);
+  assertElementsEquals(copy.getRepeatedInt64List(), [-0x7fffffff00000000]);
+  assertElementsEquals(copy.getRepeatedUint32List(), [0x80000000]);
+  assertElementsEquals(copy.getRepeatedUint64List(), [0xf000000000000000]);
+  assertElementsEquals(copy.getRepeatedSint32List(), [-100]);
+  assertElementsEquals(copy.getRepeatedSint64List(), [-0x8000000000000000]);
+  assertElementsEquals(copy.getRepeatedFixed32List(), [1234]);
+  assertElementsEquals(copy.getRepeatedFixed64List(), [0x1234567800000000]);
+  assertElementsEquals(copy.getRepeatedSfixed32List(), [-1234]);
+  assertElementsEquals(copy.getRepeatedSfixed64List(), [-0x1234567800000000]);
+  assertElementsEquals(copy.getRepeatedFloatList(), [1.5]);
+  assertElementsEquals(copy.getRepeatedDoubleList(), [-1.5]);
+  assertElementsEquals(copy.getRepeatedBoolList(), [true]);
+  assertElementsEquals(copy.getRepeatedStringList(), ['hello world']);
+  assertEquals(copy.getRepeatedBytesList().length, 2);
+  assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[0], BYTES));
+  assertEquals(true, bytesCompare(copy.getRepeatedBytesList()[0], BYTES));
+  assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[1], BYTES));
+  assertEquals(copy.getRepeatedBytesList_asB64()[0], BYTES_B64);
+  assertEquals(copy.getRepeatedBytesList_asB64()[1], BYTES_B64);
+  assertEquals(copy.getRepeatedGroupList().length, 1);
+  assertEquals(copy.getRepeatedGroupList()[0].getA(), 100);
+  assertEquals(copy.getRepeatedForeignMessageList().length, 1);
+  assertEquals(copy.getRepeatedForeignMessageList()[0].getC(), 1000);
+  assertElementsEquals(copy.getRepeatedForeignEnumList(),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  assertElementsEquals(copy.getPackedRepeatedInt32List(), [-42]);
+  assertElementsEquals(copy.getPackedRepeatedInt64List(),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(copy.getPackedRepeatedUint32List(), [0x80000000]);
+  assertElementsEquals(copy.getPackedRepeatedUint64List(),
+      [0xf000000000000000]);
+  assertElementsEquals(copy.getPackedRepeatedSint32List(), [-100]);
+  assertElementsEquals(copy.getPackedRepeatedSint64List(),
+      [-0x8000000000000000]);
+  assertElementsEquals(copy.getPackedRepeatedFixed32List(), [1234]);
+  assertElementsEquals(copy.getPackedRepeatedFixed64List(),
+      [0x1234567800000000]);
+  assertElementsEquals(copy.getPackedRepeatedSfixed32List(), [-1234]);
+  assertElementsEquals(copy.getPackedRepeatedSfixed64List(),
+      [-0x1234567800000000]);
+  assertElementsEquals(copy.getPackedRepeatedFloatList(), [1.5]);
+  assertElementsEquals(copy.getPackedRepeatedDoubleList(), [-1.5]);
+
+}
+
+
+/**
+ * Helper: verify that all expected extensions are present.
+ * @param {!proto.jspb.test.TestExtendable} msg
+ */
+function checkExtensions(msg) {
+  assertEquals(-42,
+      msg.getExtension(proto.jspb.test.extendOptionalInt32));
+  assertEquals(-0x7fffffff00000000,
+      msg.getExtension(proto.jspb.test.extendOptionalInt64));
+  assertEquals(0x80000000,
+      msg.getExtension(proto.jspb.test.extendOptionalUint32));
+  assertEquals(0xf000000000000000,
+      msg.getExtension(proto.jspb.test.extendOptionalUint64));
+  assertEquals(-100,
+      msg.getExtension(proto.jspb.test.extendOptionalSint32));
+  assertEquals(-0x8000000000000000,
+      msg.getExtension(proto.jspb.test.extendOptionalSint64));
+  assertEquals(1234,
+      msg.getExtension(proto.jspb.test.extendOptionalFixed32));
+  assertEquals(0x1234567800000000,
+      msg.getExtension(proto.jspb.test.extendOptionalFixed64));
+  assertEquals(-1234,
+      msg.getExtension(proto.jspb.test.extendOptionalSfixed32));
+  assertEquals(-0x1234567800000000,
+      msg.getExtension(proto.jspb.test.extendOptionalSfixed64));
+  assertEquals(1.5,
+      msg.getExtension(proto.jspb.test.extendOptionalFloat));
+  assertEquals(-1.5,
+      msg.getExtension(proto.jspb.test.extendOptionalDouble));
+  assertEquals(true,
+      msg.getExtension(proto.jspb.test.extendOptionalBool));
+  assertEquals('hello world',
+      msg.getExtension(proto.jspb.test.extendOptionalString));
+  assertEquals(
+      true, bytesCompare(
+                msg.getExtension(proto.jspb.test.extendOptionalBytes), BYTES));
+  assertEquals(16,
+      msg.getExtension(
+          proto.jspb.test.ExtendsWithMessage.optionalExtension).getFoo());
+
+
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedInt32List),
+      [-42]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedInt64List),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedUint32List),
+      [0x80000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedUint64List),
+      [0xf000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSint32List),
+      [-100]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSint64List),
+      [-0x8000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFixed32List),
+      [1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFixed64List),
+      [0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSfixed32List),
+      [-1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSfixed64List),
+      [-0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFloatList),
+      [1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedDoubleList),
+      [-1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedBoolList),
+      [true]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedStringList),
+      ['hello world']);
+  assertEquals(
+      true,
+      bytesCompare(
+          msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0], BYTES));
+  assertEquals(1000,
+      msg.getExtension(
+          proto.jspb.test.ExtendsWithMessage.repeatedExtensionList)[0]
+      .getFoo());
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedForeignEnumList),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedInt32List),
+      [-42]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedInt64List),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedUint32List),
+      [0x80000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedUint64List),
+      [0xf000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSint32List),
+      [-100]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSint64List),
+      [-0x8000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed32List),
+      [1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed64List),
+      [0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed32List),
+      [-1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed64List),
+      [-0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFloatList),
+      [1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedDoubleList),
+      [-1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedBoolList),
+      [true]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+}
+
+
+describe('protoBinaryTest', function() {
+  /**
+   * Tests a basic serialization-deserializaton round-trip with all supported
+   * field types (on the TestAllTypes message type).
+   */
+  it('testRoundTrip', function() {
+    var msg = new proto.jspb.test.TestAllTypes();
+    fillAllFields(msg);
+    var encoded = msg.serializeBinary();
+    var decoded = proto.jspb.test.TestAllTypes.deserializeBinary(encoded);
+    checkAllFields(msg, decoded);
+  });
+
+  /**
+   * Test that base64 string and Uint8Array are interchangeable in bytes fields.
+   */
+  it('testBytesFieldsGettersInterop', function() {
+    var msg = new proto.jspb.test.TestAllTypes();
+    // Set from a base64 string and check all the getters work.
+    msg.setOptionalBytes(BYTES_B64);
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+    // Test binary serialize round trip doesn't break it.
+    msg = proto.jspb.test.TestAllTypes.deserializeBinary(msg.serializeBinary());
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+    msg = new proto.jspb.test.TestAllTypes();
+    // Set from a Uint8Array and check all the getters work.
+    msg.setOptionalBytes(BYTES);
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+  });
+
+  /**
+   * Test that bytes setters will receive result of any of the getters.
+   */
+  it('testBytesFieldsSettersInterop', function() {
+    var msg = new proto.jspb.test.TestAllTypes();
+    msg.setOptionalBytes(BYTES);
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+    msg.setOptionalBytes(msg.getOptionalBytes());
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+    msg.setOptionalBytes(msg.getOptionalBytes_asB64());
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+    msg.setOptionalBytes(msg.getOptionalBytes_asU8());
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+  });
+
+  /**
+   * Test that bytes setters will receive result of any of the getters.
+   */
+  it('testRepeatedBytesGetters', function() {
+    var msg = new proto.jspb.test.TestAllTypes();
+
+    function assertGetters() {
+      assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[0]));
+      assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[1]));
+      assertTrue(msg.getRepeatedBytesList_asU8()[0] instanceof Uint8Array);
+      assertTrue(msg.getRepeatedBytesList_asU8()[1] instanceof Uint8Array);
+
+      assertTrue(bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
+      assertTrue(bytesCompare(msg.getRepeatedBytesList()[1], BYTES));
+      assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[0], BYTES));
+      assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[1], BYTES));
+      assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[0], BYTES));
+      assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[1], BYTES));
+    }
+
+    msg.setRepeatedBytesList([BYTES, BYTES]);
+    assertGetters();
+
+    msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]);
+    assertGetters();
+
+    msg.setRepeatedBytesList(null);
+    assertEquals(0, msg.getRepeatedBytesList().length);
+    assertEquals(0, msg.getRepeatedBytesList_asB64().length);
+    assertEquals(0, msg.getRepeatedBytesList_asU8().length);
+  });
+
+  /**
+   * Helper: fill all extension values.
+   * @param {proto.jspb.test.TestExtendable} msg
+   */
+  function fillExtensions(msg) {
+    msg.setExtension(
+        proto.jspb.test.extendOptionalInt32, -42);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalUint32, 0x80000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalUint64, 0xf000000000000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSint32, -100);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSint64, -0x8000000000000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFixed32, 1234);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFixed64, 0x1234567800000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSfixed32, -1234);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSfixed64, -0x1234567800000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFloat, 1.5);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalDouble, -1.5);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalBool, true);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalString, 'hello world');
+    msg.setExtension(proto.jspb.test.extendOptionalBytes, BYTES);
+    var submsg = new proto.jspb.test.ExtendsWithMessage();
+    submsg.setFoo(16);
+    msg.setExtension(
+        proto.jspb.test.ExtendsWithMessage.optionalExtension, submsg);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalForeignEnum,
+        proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+
+
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedInt32List, [-42]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedInt64List, [-0x7fffffff00000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedUint32List, [0x80000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedUint64List, [0xf000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSint32List, [-100]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSint64List, [-0x8000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFixed32List, [1234]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFixed64List, [0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSfixed32List, [-1234]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSfixed64List, [-0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFloatList, [1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedDoubleList, [-1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedBoolList, [true]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedStringList, ['hello world']);
+    msg.setExtension(proto.jspb.test.extendRepeatedBytesList, [BYTES]);
+    submsg = new proto.jspb.test.ExtendsWithMessage();
+    submsg.setFoo(1000);
+    msg.setExtension(
+        proto.jspb.test.ExtendsWithMessage.repeatedExtensionList, [submsg]);
+    msg.setExtension(proto.jspb.test.extendRepeatedForeignEnumList,
+        [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedInt32List, [-42]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedInt64List, [-0x7fffffff00000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedUint32List, [0x80000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedUint64List, [0xf000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSint32List, [-100]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSint64List, [-0x8000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFixed32List, [1234]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFixed64List, [0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSfixed32List, [-1234]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSfixed64List,
+        [-0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFloatList, [1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedDoubleList, [-1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedBoolList, [true]);
+    msg.setExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList,
+        [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  }
+
+
+  /**
+   * Tests extension serialization and deserialization.
+   */
+  it('testExtensions', function() {
+    var msg = new proto.jspb.test.TestExtendable();
+    fillExtensions(msg);
+    var encoded = msg.serializeBinary();
+    var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
+    checkExtensions(decoded);
+  });
+});
diff --git a/js/binary/reader.js b/js/binary/reader.js
new file mode 100644
index 0000000..15f9043
--- /dev/null
+++ b/js/binary/reader.js
@@ -0,0 +1,1127 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for converting binary,
+ * wire-format protocol buffers into Javascript data structures.
+ *
+ * jspb's BinaryReader class wraps the BinaryDecoder class to add methods
+ * that understand the protocol buffer syntax and can do the type checking and
+ * bookkeeping necessary to parse trees of nested messages.
+ *
+ * Major caveat - Users of this library _must_ keep their Javascript proto
+ * parsing code in sync with the original .proto file - presumably you'll be
+ * using the typed jspb code generator, but if you bypass that you'll need
+ * to keep things in sync by hand.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryReader');
+
+goog.require('goog.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+
+
+
+/**
+ * BinaryReader implements the decoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @constructor
+ * @struct
+ */
+jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
+  /**
+   * Wire-format decoder.
+   * @private {!jspb.BinaryDecoder}
+   */
+  this.decoder_ = jspb.BinaryDecoder.alloc(opt_bytes, opt_start, opt_length);
+
+  /**
+   * Cursor immediately before the field tag.
+   * @private {number}
+   */
+  this.fieldCursor_ = this.decoder_.getCursor();
+
+  /**
+   * Field number of the next field in the buffer, filled in by nextField().
+   * @private {number}
+   */
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+
+  /**
+   * Wire type of the next proto field in the buffer, filled in by
+   * nextField().
+   * @private {jspb.BinaryConstants.WireType}
+   */
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+
+  /**
+   * Set to true if this reader encountered an error due to corrupt data.
+   * @private {boolean}
+   */
+  this.error_ = false;
+
+  /**
+   * User-defined reader callbacks.
+   * @private {Object.<string, function(!jspb.BinaryReader):*>}
+   */
+  this.readCallbacks_ = null;
+};
+
+
+/**
+ * Global pool of BinaryReader instances.
+ * @private {!Array.<!jspb.BinaryReader>}
+ */
+jspb.BinaryReader.instanceCache_ = [];
+
+
+/**
+ * Pops an instance off the instance cache, or creates one if the cache is
+ * empty.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryReader}
+ */
+jspb.BinaryReader.alloc =
+    function(opt_bytes, opt_start, opt_length) {
+  if (jspb.BinaryReader.instanceCache_.length) {
+    var newReader = jspb.BinaryReader.instanceCache_.pop();
+    if (opt_bytes) {
+      newReader.decoder_.setBlock(opt_bytes, opt_start, opt_length);
+    }
+    return newReader;
+  } else {
+    return new jspb.BinaryReader(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Alias for the above method.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryReader}
+ */
+jspb.BinaryReader.prototype.alloc = jspb.BinaryReader.alloc;
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryReader.prototype.free = function() {
+  this.decoder_.clear();
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+  this.error_ = false;
+  this.readCallbacks_ = null;
+
+  if (jspb.BinaryReader.instanceCache_.length < 100) {
+    jspb.BinaryReader.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Returns the cursor immediately before the current field's tag.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryReader.prototype.getFieldCursor = function() {
+  return this.fieldCursor_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryReader.prototype.getCursor = function() {
+  return this.decoder_.getCursor();
+};
+
+
+/**
+ * Returns the raw buffer.
+ * @return {?Uint8Array} The raw buffer.
+ */
+jspb.BinaryReader.prototype.getBuffer = function() {
+  return this.decoder_.getBuffer();
+};
+
+
+/**
+ * @return {number} The field number of the next field in the buffer, or
+ *     INVALID_FIELD_NUMBER if there is no next field.
+ */
+jspb.BinaryReader.prototype.getFieldNumber = function() {
+  return this.nextField_;
+};
+
+
+/**
+ * @return {jspb.BinaryConstants.WireType} The wire type of the next field
+ *     in the stream, or WireType.INVALID if there is no next field.
+ */
+jspb.BinaryReader.prototype.getWireType = function() {
+  return this.nextWireType_;
+};
+
+
+/**
+ * @return {boolean} Whether the current wire type is an end-group tag. Used as
+ * an exit condition in decoder loops in generated code.
+ */
+jspb.BinaryReader.prototype.isEndGroup = function() {
+  return this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP;
+};
+
+
+/**
+ * Returns true if this reader hit an error due to corrupt data.
+ * @return {boolean}
+ */
+jspb.BinaryReader.prototype.getError = function() {
+  return this.error_ || this.decoder_.getError();
+};
+
+
+/**
+ * Points this reader at a new block of bytes.
+ * @param {!Uint8Array} bytes The block of bytes we're reading from.
+ * @param {number} start The offset to start reading at.
+ * @param {number} length The length of the block to read.
+ */
+jspb.BinaryReader.prototype.setBlock = function(bytes, start, length) {
+  this.decoder_.setBlock(bytes, start, length);
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+};
+
+
+/**
+ * Rewinds the stream cursor to the beginning of the buffer and resets all
+ * internal state.
+ */
+jspb.BinaryReader.prototype.reset = function() {
+  this.decoder_.reset();
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+};
+
+
+/**
+ * Advances the stream cursor by the given number of bytes.
+ * @param {number} count The number of bytes to advance by.
+ */
+jspb.BinaryReader.prototype.advance = function(count) {
+  this.decoder_.advance(count);
+};
+
+
+/**
+ * Reads the next field header in the stream if there is one, returns true if
+ * we saw a valid field header or false if we've read the whole stream.
+ * Throws an error if we encountered a deprecated START_GROUP/END_GROUP field.
+ * @return {boolean} True if the stream contains more fields.
+ */
+jspb.BinaryReader.prototype.nextField = function() {
+  // If we're at the end of the block, there are no more fields.
+  if (this.decoder_.atEnd()) {
+    return false;
+  }
+
+  // If we hit an error decoding the previous field, stop now before we
+  // try to decode anything else
+  if (this.getError()) {
+    goog.asserts.fail('Decoder hit an error');
+    return false;
+  }
+
+  // Otherwise just read the header of the next field.
+  this.fieldCursor_ = this.decoder_.getCursor();
+  var header = this.decoder_.readUnsignedVarint32();
+
+  var nextField = header >>> 3;
+  var nextWireType = /** @type {jspb.BinaryConstants.WireType} */
+      (header & 0x7);
+
+  // If the wire type isn't one of the valid ones, something's broken.
+  if (nextWireType != jspb.BinaryConstants.WireType.VARINT &&
+      nextWireType != jspb.BinaryConstants.WireType.FIXED32 &&
+      nextWireType != jspb.BinaryConstants.WireType.FIXED64 &&
+      nextWireType != jspb.BinaryConstants.WireType.DELIMITED &&
+      nextWireType != jspb.BinaryConstants.WireType.START_GROUP &&
+      nextWireType != jspb.BinaryConstants.WireType.END_GROUP) {
+    goog.asserts.fail('Invalid wire type');
+    this.error_ = true;
+    return false;
+  }
+
+  this.nextField_ = nextField;
+  this.nextWireType_ = nextWireType;
+
+  return true;
+};
+
+
+/**
+ * Winds the reader back to just before this field's header.
+ */
+jspb.BinaryReader.prototype.unskipHeader = function() {
+  this.decoder_.unskipVarint((this.nextField_ << 3) | this.nextWireType_);
+};
+
+
+/**
+ * Skips all contiguous fields whose header matches the one we just read.
+ */
+jspb.BinaryReader.prototype.skipMatchingFields = function() {
+  var field = this.nextField_;
+  this.unskipHeader();
+
+  while (this.nextField() && (this.getFieldNumber() == field)) {
+    this.skipField();
+  }
+
+  if (!this.decoder_.atEnd()) {
+    this.unskipHeader();
+  }
+};
+
+
+/**
+ * Skips over the next varint field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipVarintField = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.VARINT) {
+    goog.asserts.fail('Invalid wire type for skipVarintField');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.skipVarint();
+};
+
+
+/**
+ * Skips over the next delimited field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipDelimitedField = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.DELIMITED) {
+    goog.asserts.fail('Invalid wire type for skipDelimitedField');
+    this.skipField();
+    return;
+  }
+
+  var length = this.decoder_.readUnsignedVarint32();
+  this.decoder_.advance(length);
+};
+
+
+/**
+ * Skips over the next fixed32 field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipFixed32Field = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED32) {
+    goog.asserts.fail('Invalid wire type for skipFixed32Field');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.advance(4);
+};
+
+
+/**
+ * Skips over the next fixed64 field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipFixed64Field = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED64) {
+    goog.asserts.fail('Invalid wire type for skipFixed64Field');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.advance(8);
+};
+
+
+/**
+ * Skips over the next group field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipGroup = function() {
+  // Keep a stack of start-group tags that must be matched by end-group tags.
+  var nestedGroups = [this.nextField_];
+  do {
+    if (!this.nextField()) {
+      goog.asserts.fail('Unmatched start-group tag: stream EOF');
+      this.error_ = true;
+      return;
+    }
+    if (this.nextWireType_ ==
+        jspb.BinaryConstants.WireType.START_GROUP) {
+      // Nested group start.
+      nestedGroups.push(this.nextField_);
+    } else if (this.nextWireType_ ==
+               jspb.BinaryConstants.WireType.END_GROUP) {
+      // Group end: check that it matches top-of-stack.
+      if (this.nextField_ != nestedGroups.pop()) {
+        goog.asserts.fail('Unmatched end-group tag');
+        this.error_ = true;
+        return;
+      }
+    }
+  } while (nestedGroups.length > 0);
+};
+
+
+/**
+ * Skips over the next field in the binary stream - this is useful if we're
+ * decoding a message that contain unknown fields.
+ */
+jspb.BinaryReader.prototype.skipField = function() {
+  switch (this.nextWireType_) {
+    case jspb.BinaryConstants.WireType.VARINT:
+      this.skipVarintField();
+      break;
+    case jspb.BinaryConstants.WireType.FIXED64:
+      this.skipFixed64Field();
+      break;
+    case jspb.BinaryConstants.WireType.DELIMITED:
+      this.skipDelimitedField();
+      break;
+    case jspb.BinaryConstants.WireType.FIXED32:
+      this.skipFixed32Field();
+      break;
+    case jspb.BinaryConstants.WireType.START_GROUP:
+      this.skipGroup();
+      break;
+    default:
+      goog.asserts.fail('Invalid wire encoding for field.');
+  }
+};
+
+
+/**
+ * Registers a user-defined read callback.
+ * @param {string} callbackName
+ * @param {function(!jspb.BinaryReader):*} callback
+ */
+jspb.BinaryReader.prototype.registerReadCallback =
+    function(callbackName, callback) {
+  if (goog.isNull(this.readCallbacks_)) {
+    this.readCallbacks_ = {};
+  }
+  goog.asserts.assert(!this.readCallbacks_[callbackName]);
+  this.readCallbacks_[callbackName] = callback;
+};
+
+
+/**
+ * Runs a registered read callback.
+ * @param {string} callbackName The name the callback is registered under.
+ * @return {*} The value returned by the callback.
+ */
+jspb.BinaryReader.prototype.runReadCallback = function(callbackName) {
+  goog.asserts.assert(!goog.isNull(this.readCallbacks_));
+  var callback = this.readCallbacks_[callbackName];
+  goog.asserts.assert(callback);
+  return callback(this);
+};
+
+
+/**
+ * Reads a field of any valid non-message type from the binary stream.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @return {jspb.AnyFieldType}
+ */
+jspb.BinaryReader.prototype.readAny = function(fieldType) {
+  this.nextWireType_ = jspb.BinaryConstants.FieldTypeToWireType(fieldType);
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  switch (fieldType) {
+    case fieldTypes.DOUBLE:
+      return this.readDouble();
+    case fieldTypes.FLOAT:
+      return this.readFloat();
+    case fieldTypes.INT64:
+      return this.readInt64();
+    case fieldTypes.UINT64:
+      return this.readUint64();
+    case fieldTypes.INT32:
+      return this.readInt32();
+    case fieldTypes.FIXED64:
+      return this.readFixed64();
+    case fieldTypes.FIXED32:
+      return this.readFixed32();
+    case fieldTypes.BOOL:
+      return this.readBool();
+    case fieldTypes.STRING:
+      return this.readString();
+    case fieldTypes.GROUP:
+      goog.asserts.fail('Group field type not supported in readAny()');
+    case fieldTypes.MESSAGE:
+      goog.asserts.fail('Message field type not supported in readAny()');
+    case fieldTypes.BYTES:
+      return this.readBytes();
+    case fieldTypes.UINT32:
+      return this.readUint32();
+    case fieldTypes.ENUM:
+      return this.readEnum();
+    case fieldTypes.SFIXED32:
+      return this.readSfixed32();
+    case fieldTypes.SFIXED64:
+      return this.readSfixed64();
+    case fieldTypes.SINT32:
+      return this.readSint32();
+    case fieldTypes.SINT64:
+      return this.readSint64();
+    case fieldTypes.FHASH64:
+      return this.readFixedHash64();
+    case fieldTypes.VHASH64:
+      return this.readVarintHash64();
+    default:
+      goog.asserts.fail('Invalid field type in readAny()');
+  }
+  return 0;
+};
+
+
+/**
+ * Deserialize a proto into the provided message object using the provided
+ * reader function. This function is templated as we currently have one client
+ * who is using manual deserialization instead of the code-generated versions.
+ * @template T
+ * @param {T} message
+ * @param {function(T, !jspb.BinaryReader)} reader
+ */
+jspb.BinaryReader.prototype.readMessage = function(message, reader) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+
+  // Save the current endpoint of the decoder and move it to the end of the
+  // embedded message.
+  var oldEnd = this.decoder_.getEnd();
+  var length = this.decoder_.readUnsignedVarint32();
+  var newEnd = this.decoder_.getCursor() + length;
+  this.decoder_.setEnd(newEnd);
+
+  // Deserialize the embedded message.
+  reader(message, this);
+
+  // Advance the decoder past the embedded message and restore the endpoint.
+  this.decoder_.setCursor(newEnd);
+  this.decoder_.setEnd(oldEnd);
+};
+
+
+/**
+ * Deserialize a proto into the provided message object using the provided
+ * reader function, assuming that the message is serialized as a group
+ * with the given tag.
+ * @template T
+ * @param {number} field
+ * @param {T} message
+ * @param {function(T, !jspb.BinaryReader)} reader
+ */
+jspb.BinaryReader.prototype.readGroup =
+    function(field, message, reader) {
+  // Ensure that the wire type is correct.
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.START_GROUP);
+  // Ensure that the field number is correct.
+  goog.asserts.assert(this.nextField_ == field);
+
+  // Deserialize the message. The deserialization will stop at an END_GROUP tag.
+  reader(message, this);
+
+  if (!this.error_ &&
+      this.nextWireType_ != jspb.BinaryConstants.WireType.END_GROUP) {
+    goog.asserts.fail('Group submessage did not end with an END_GROUP tag');
+    this.error_ = true;
+  }
+};
+
+
+/**
+ * Return a decoder that wraps the current delimited field.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryReader.prototype.getFieldDecoder = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+
+  var length = this.decoder_.readUnsignedVarint32();
+  var start = this.decoder_.getCursor();
+  var end = start + length;
+
+  var innerDecoder =
+      jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(), start, length);
+  this.decoder_.setCursor(end);
+  return innerDecoder;
+};
+
+
+/**
+ * Reads a signed 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the signed 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readInt32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint32();
+};
+
+
+/**
+ * Reads a signed 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the signed 32-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readInt32String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint32String();
+};
+
+
+/**
+ * Reads a signed 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the signed 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readInt64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64();
+};
+
+
+/**
+ * Reads a signed 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the signed 64-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readInt64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64String();
+};
+
+
+/**
+ * Reads an unsigned 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the unsigned 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readUint32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint32();
+};
+
+
+/**
+ * Reads an unsigned 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the unsigned 32-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readUint32String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint32String();
+};
+
+
+/**
+ * Reads an unsigned 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the unsigned 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readUint64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint64();
+};
+
+
+/**
+ * Reads an unsigned 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the unsigned 64-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readUint64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint64String();
+};
+
+
+/**
+ * Reads a signed zigzag-encoded 32-bit integer field from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the signed 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readSint32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readZigzagVarint32();
+};
+
+
+/**
+ * Reads a signed zigzag-encoded 64-bit integer field from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the signed 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readSint64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readZigzagVarint64();
+};
+
+
+/**
+ * Reads an unsigned 32-bit fixed-length integer fiield from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readFixed32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readUint32();
+};
+
+
+/**
+ * Reads an unsigned 64-bit fixed-length integer fiield from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readFixed64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readUint64();
+};
+
+
+/**
+ * Reads a signed 32-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readSfixed32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readInt32();
+};
+
+
+/**
+ * Reads a signed 64-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readSfixed64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readInt64();
+};
+
+
+/**
+ * Reads a 32-bit floating-point field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readFloat = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readFloat();
+};
+
+
+/**
+ * Reads a 64-bit floating-point field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readDouble = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readDouble();
+};
+
+
+/**
+ * Reads a boolean field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {boolean} The value of the boolean field.
+ */
+jspb.BinaryReader.prototype.readBool = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return !!this.decoder_.readUnsignedVarint32();
+};
+
+
+/**
+ * Reads an enum field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the enum field.
+ */
+jspb.BinaryReader.prototype.readEnum = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64();
+};
+
+
+/**
+ * Reads a string field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {string} The value of the string field.
+ */
+jspb.BinaryReader.prototype.readString = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  return this.decoder_.readString(length);
+};
+
+
+/**
+ * Reads a length-prefixed block of bytes from the binary stream, or returns
+ * null if the next field in the stream has an invalid length value.
+ *
+ * @return {!Uint8Array} The block of bytes.
+ */
+jspb.BinaryReader.prototype.readBytes = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  return this.decoder_.readBytes(length);
+};
+
+
+/**
+ * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
+ * 8-character Unicode string for use as a hash table key, or throws an error
+ * if the next field in the stream is not of the correct wire type.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryReader.prototype.readVarintHash64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readVarintHash64();
+};
+
+
+/**
+ * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
+ * 8-character Unicode string for use as a hash table key, or throws an error
+ * if the next field in the stream is not of the correct wire type.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryReader.prototype.readFixedHash64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readFixedHash64();
+};
+
+
+/**
+ * Reads a packed scalar field using the supplied raw reader function.
+ * @param {function()} decodeMethod
+ * @return {!Array}
+ * @private
+ */
+jspb.BinaryReader.prototype.readPackedField_ = function(decodeMethod) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  var end = this.decoder_.getCursor() + length;
+  var result = [];
+  while (this.decoder_.getCursor() < end) {
+    // TODO(aappleby): .call is slow
+    result.push(decodeMethod.call(this.decoder_));
+  }
+  return result;
+};
+
+
+/**
+ * Reads a packed int32 field, which consists of a length header and a list of
+ * signed varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedInt32 = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint32);
+};
+
+
+/**
+ * Reads a packed int32 field, which consists of a length header and a list of
+ * signed varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedInt32String = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint32String);
+};
+
+
+/**
+ * Reads a packed int64 field, which consists of a length header and a list of
+ * signed varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedInt64 = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint64);
+};
+
+
+/**
+ * Reads a packed int64 field, which consists of a length header and a list of
+ * signed varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedInt64String = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint64String);
+};
+
+
+/**
+ * Reads a packed uint32 field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedUint32 = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint32);
+};
+
+
+/**
+ * Reads a packed uint32 field, which consists of a length header and a list of
+ * unsigned varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedUint32String = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint32String);
+};
+
+
+/**
+ * Reads a packed uint64 field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedUint64 = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint64);
+};
+
+
+/**
+ * Reads a packed uint64 field, which consists of a length header and a list of
+ * unsigned varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedUint64String = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint64String);
+};
+
+
+/**
+ * Reads a packed sint32 field, which consists of a length header and a list of
+ * zigzag varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSint32 = function() {
+  return this.readPackedField_(this.decoder_.readZigzagVarint32);
+};
+
+
+/**
+ * Reads a packed sint64 field, which consists of a length header and a list of
+ * zigzag varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSint64 = function() {
+  return this.readPackedField_(this.decoder_.readZigzagVarint64);
+};
+
+
+/**
+ * Reads a packed fixed32 field, which consists of a length header and a list
+ * of unsigned 32-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFixed32 = function() {
+  return this.readPackedField_(this.decoder_.readUint32);
+};
+
+
+/**
+ * Reads a packed fixed64 field, which consists of a length header and a list
+ * of unsigned 64-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFixed64 = function() {
+  return this.readPackedField_(this.decoder_.readUint64);
+};
+
+
+/**
+ * Reads a packed sfixed32 field, which consists of a length header and a list
+ * of 32-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
+  return this.readPackedField_(this.decoder_.readInt32);
+};
+
+
+/**
+ * Reads a packed sfixed64 field, which consists of a length header and a list
+ * of 64-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
+  return this.readPackedField_(this.decoder_.readInt64);
+};
+
+
+/**
+ * Reads a packed float field, which consists of a length header and a list of
+ * floats.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFloat = function() {
+  return this.readPackedField_(this.decoder_.readFloat);
+};
+
+
+/**
+ * Reads a packed double field, which consists of a length header and a list of
+ * doubles.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedDouble = function() {
+  return this.readPackedField_(this.decoder_.readDouble);
+};
+
+
+/**
+ * Reads a packed bool field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<boolean>}
+ */
+jspb.BinaryReader.prototype.readPackedBool = function() {
+  return this.readPackedField_(this.decoder_.readBool);
+};
+
+
+/**
+ * Reads a packed enum field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedEnum = function() {
+  return this.readPackedField_(this.decoder_.readEnum);
+};
+
+
+/**
+ * Reads a packed varint hash64 field, which consists of a length header and a
+ * list of varint hash64s.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
+  return this.readPackedField_(this.decoder_.readVarintHash64);
+};
+
+
+/**
+ * Reads a packed fixed hash64 field, which consists of a length header and a
+ * list of fixed hash64s.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
+  return this.readPackedField_(this.decoder_.readFixedHash64);
+};
diff --git a/js/binary/reader_test.js b/js/binary/reader_test.js
new file mode 100644
index 0000000..6f7e5d4
--- /dev/null
+++ b/js/binary/reader_test.js
@@ -0,0 +1,873 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer reader.
+ *
+ * There are two particular magic numbers that need to be pointed out -
+ * 2^64-1025 is the largest number representable as both a double and an
+ * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
+ * both a double and a signed 64-bit integer.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+goog.require('jspb.BinaryReader');
+goog.require('jspb.BinaryWriter');
+
+
+
+describe('binaryReaderTest', function() {
+  /**
+   * Tests the reader instance cache.
+   * @suppress {visibility}
+   */
+  it('testInstanceCaches', function() {
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+    writer.writeMessage(1, dummyMessage, goog.nullFunction);
+    writer.writeMessage(2, dummyMessage, goog.nullFunction);
+
+    var buffer = writer.getResultBuffer();
+
+    // Empty the instance caches.
+    jspb.BinaryReader.instanceCache_ = [];
+
+    // Allocating and then freeing three decoders should leave us with three in
+    // the cache.
+
+    var decoder1 = jspb.BinaryDecoder.alloc();
+    var decoder2 = jspb.BinaryDecoder.alloc();
+    var decoder3 = jspb.BinaryDecoder.alloc();
+    decoder1.free();
+    decoder2.free();
+    decoder3.free();
+
+    assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Allocating and then freeing a reader should remove one decoder from its
+    // cache, but it should stay stuck to the reader afterwards since we can't
+    // have a reader without a decoder.
+    jspb.BinaryReader.alloc().free();
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(1, jspb.BinaryReader.instanceCache_.length);
+
+    // Allocating a reader should remove a reader from the cache.
+    var reader = jspb.BinaryReader.alloc(buffer);
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Processing the message reuses the current reader.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+    });
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+    });
+
+    assertEquals(false, reader.nextField());
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Freeing the reader should put it back into the cache.
+    reader.free();
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(1, jspb.BinaryReader.instanceCache_.length);
+  });
+
+
+  /**
+   * @param {number} x
+   * @return {number}
+   */
+  function truncate(x) {
+    var temp = new Float32Array(1);
+    temp[0] = x;
+    return temp[0];
+  }
+
+
+  /**
+   * Verifies that misuse of the reader class triggers assertions.
+   * @suppress {checkTypes|visibility}
+   */
+  it('testReadErrors', function() {
+    // Calling readMessage on a non-delimited field should trigger an
+    // assertion.
+    var reader = jspb.BinaryReader.alloc([8, 1]);
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+    reader.nextField();
+    assertThrows(function() {
+      reader.readMessage(dummyMessage, goog.nullFunction);
+    });
+
+    // Reading past the end of the stream should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([9, 1]);
+    reader.nextField();
+    assertThrows(function() {reader.readFixed64()});
+
+    // Reading past the end of a submessage should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
+    reader.nextField();
+    reader.readMessage(dummyMessage, function() {
+      reader.nextField();
+      assertThrows(function() {reader.readFixed32()});
+    });
+
+    // Skipping an invalid field should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([12, 1]);
+    reader.nextWireType_ = 1000;
+    assertThrows(function() {reader.skipField()});
+
+    // Reading fields with the wrong wire type should assert.
+    reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
+    reader.nextField();
+    assertThrows(function() {reader.readInt32()});
+    assertThrows(function() {reader.readInt32String()});
+    assertThrows(function() {reader.readInt64()});
+    assertThrows(function() {reader.readInt64String()});
+    assertThrows(function() {reader.readUint32()});
+    assertThrows(function() {reader.readUint32String()});
+    assertThrows(function() {reader.readUint64()});
+    assertThrows(function() {reader.readUint64String()});
+    assertThrows(function() {reader.readSint32()});
+    assertThrows(function() {reader.readBool()});
+    assertThrows(function() {reader.readEnum()});
+
+    reader = jspb.BinaryReader.alloc([8, 1]);
+    reader.nextField();
+    assertThrows(function() {reader.readFixed32()});
+    assertThrows(function() {reader.readFixed64()});
+    assertThrows(function() {reader.readSfixed32()});
+    assertThrows(function() {reader.readSfixed64()});
+    assertThrows(function() {reader.readFloat()});
+    assertThrows(function() {reader.readDouble()});
+
+    assertThrows(function() {reader.readString()});
+    assertThrows(function() {reader.readBytes()});
+  });
+
+
+  /**
+   * Tests encoding and decoding of unsigned field types.
+   * @param {Function} readField
+   * @param {Function} writeField
+   * @param {number} epsilon
+   * @param {number} upperLimit
+   * @param {Function} filter
+   * @private
+   * @suppress {missingProperties}
+   */
+  function doTestUnsignedField_(readField,
+      writeField, epsilon, upperLimit, filter) {
+    assertNotNull(readField);
+    assertNotNull(writeField);
+
+    var writer = new jspb.BinaryWriter();
+
+    // Encode zero and limits.
+    writeField.call(writer, 1, filter(0));
+    writeField.call(writer, 2, filter(epsilon));
+    writeField.call(writer, 3, filter(upperLimit));
+
+    // Encode positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      writeField.call(writer, 4, filter(cursor));
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Check zero and limits.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(filter(0), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(filter(epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(filter(upperLimit), readField.call(reader));
+
+    // Check positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      reader.nextField();
+      if (4 != reader.getFieldNumber()) throw 'fail!';
+      if (filter(cursor) != readField.call(reader)) throw 'fail!';
+    }
+  };
+
+
+  /**
+   * Tests encoding and decoding of signed field types.
+   * @param {Function} readField
+   * @param {Function} writeField
+   * @param {number} epsilon
+   * @param {number} lowerLimit
+   * @param {number} upperLimit
+   * @param {Function} filter
+   * @private
+   * @suppress {missingProperties}
+   */
+  function doTestSignedField_(readField,
+      writeField, epsilon, lowerLimit, upperLimit, filter) {
+    var writer = new jspb.BinaryWriter();
+
+    // Encode zero and limits.
+    writeField.call(writer, 1, filter(lowerLimit));
+    writeField.call(writer, 2, filter(-epsilon));
+    writeField.call(writer, 3, filter(0));
+    writeField.call(writer, 4, filter(epsilon));
+    writeField.call(writer, 5, filter(upperLimit));
+
+    var inputValues = [];
+
+    // Encode negative values.
+    for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
+      var val = filter(cursor);
+      writeField.call(writer, 6, val);
+      inputValues.push({
+        fieldNumber: 6,
+        value: val
+      });
+    }
+
+    // Encode positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      var val = filter(cursor);
+      writeField.call(writer, 7, val);
+      inputValues.push({
+        fieldNumber: 7,
+        value: val
+      });
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Check zero and limits.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(filter(lowerLimit), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(filter(-epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(filter(0), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(4, reader.getFieldNumber());
+    assertEquals(filter(epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(5, reader.getFieldNumber());
+    assertEquals(filter(upperLimit), readField.call(reader));
+
+    for (var i = 0; i < inputValues.length; i++) {
+      var expected = inputValues[i];
+      reader.nextField();
+      assertEquals(expected.fieldNumber, reader.getFieldNumber());
+      assertEquals(expected.value, readField.call(reader));
+    }
+  };
+
+
+  /**
+   * Tests fields that use varint encoding.
+   */
+  it('testVarintFields', function() {
+    assertNotNull(jspb.BinaryReader.prototype.readUint32);
+    assertNotNull(jspb.BinaryReader.prototype.writeUint32);
+    assertNotNull(jspb.BinaryReader.prototype.readUint64);
+    assertNotNull(jspb.BinaryReader.prototype.writeUint64);
+    assertNotNull(jspb.BinaryReader.prototype.readBool);
+    assertNotNull(jspb.BinaryReader.prototype.writeBool);
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readUint32,
+        jspb.BinaryWriter.prototype.writeUint32,
+        1, Math.pow(2, 32) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readUint64,
+        jspb.BinaryWriter.prototype.writeUint64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readInt32,
+        jspb.BinaryWriter.prototype.writeInt32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readInt64,
+        jspb.BinaryWriter.prototype.writeInt64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readEnum,
+        jspb.BinaryWriter.prototype.writeEnum,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readBool,
+        jspb.BinaryWriter.prototype.writeBool,
+        1, 1, function(x) { return !!x; });
+  });
+
+
+  /**
+   * Tests 64-bit fields that are handled as strings.
+   */
+  it('testStringInt64Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var testSignedData = [
+      '2730538252207801776',
+      '-2688470994844604560',
+      '3398529779486536359',
+      '3568577411627971000',
+      '272477188847484900',
+      '-6649058714086158188',
+      '-7695254765712060806',
+      '-4525541438037104029',
+      '-4993706538836508568',
+      '4990160321893729138'
+    ];
+    var testUnsignedData = [
+      '7822732630241694882',
+      '6753602971916687352',
+      '2399935075244442116',
+      '8724292567325338867',
+      '16948784802625696584',
+      '4136275908516066934',
+      '3575388346793700364',
+      '5167142028379259461',
+      '1557573948689737699',
+      '17100725280812548567'
+    ];
+
+    for (var i = 0; i < testSignedData.length; i++) {
+      writer.writeInt64String(2 * i + 1, testSignedData[i]);
+      writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    for (var i = 0; i < testSignedData.length; i++) {
+      reader.nextField();
+      assertEquals(2 * i + 1, reader.getFieldNumber());
+      assertEquals(testSignedData[i], reader.readInt64String());
+      reader.nextField();
+      assertEquals(2 * i + 2, reader.getFieldNumber());
+      assertEquals(testUnsignedData[i], reader.readUint64String());
+    }
+  });
+
+
+  /**
+   * Tests fields that use zigzag encoding.
+   */
+  it('testZigzagFields', function() {
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSint32,
+        jspb.BinaryWriter.prototype.writeSint32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSint64,
+        jspb.BinaryWriter.prototype.writeSint64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests fields that use fixed-length encoding.
+   */
+  it('testFixedFields', function() {
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readFixed32,
+        jspb.BinaryWriter.prototype.writeFixed32,
+        1, Math.pow(2, 32) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readFixed64,
+        jspb.BinaryWriter.prototype.writeFixed64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSfixed32,
+        jspb.BinaryWriter.prototype.writeSfixed32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSfixed64,
+        jspb.BinaryWriter.prototype.writeSfixed64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests floating point fields.
+   */
+  it('testFloatFields', function() {
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readFloat,
+        jspb.BinaryWriter.prototype.writeFloat,
+        jspb.BinaryConstants.FLOAT32_MIN,
+        -jspb.BinaryConstants.FLOAT32_MAX,
+        jspb.BinaryConstants.FLOAT32_MAX,
+        truncate);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readDouble,
+        jspb.BinaryWriter.prototype.writeDouble,
+        jspb.BinaryConstants.FLOAT64_EPS * 10,
+        -jspb.BinaryConstants.FLOAT64_MIN,
+        jspb.BinaryConstants.FLOAT64_MIN,
+        function(x) { return x; });
+  });
+
+
+  /**
+   * Tests length-delimited string fields.
+   */
+  it('testStringFields', function() {
+    var s1 = 'The quick brown fox jumps over the lazy dog.';
+    var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
+
+    var writer = new jspb.BinaryWriter();
+
+    writer.writeString(1, s1);
+    writer.writeString(2, s2);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(s1, reader.readString());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(s2, reader.readString());
+  });
+
+
+  /**
+   * Tests length-delimited byte fields.
+   */
+  it('testByteFields', function() {
+    var message = [];
+    var lowerLimit = 1;
+    var upperLimit = 256;
+    var scale = 1.1;
+
+    var writer = new jspb.BinaryWriter();
+
+    for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
+      var len = Math.round(cursor);
+      var bytes = [];
+      for (var i = 0; i < len; i++) bytes.push(i % 256);
+
+      writer.writeBytes(len, bytes);
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
+      var len = Math.round(cursor);
+      if (len != reader.getFieldNumber()) throw 'fail!';
+
+      var bytes = reader.readBytes();
+      if (len != bytes.length) throw 'fail!';
+      for (var i = 0; i < bytes.length; i++) {
+        if (i % 256 != bytes[i]) throw 'fail!';
+      }
+    }
+  });
+
+
+  /**
+   * Tests nested messages.
+   */
+  it('testNesting', function() {
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    writer.writeInt32(1, 100);
+
+    // Add one message with 3 int fields.
+    writer.writeMessage(2, dummyMessage, function() {
+      writer.writeInt32(3, 300);
+      writer.writeInt32(4, 400);
+      writer.writeInt32(5, 500);
+    });
+
+    // Add one empty message.
+    writer.writeMessage(6, dummyMessage, goog.nullFunction);
+
+    writer.writeInt32(7, 700);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Validate outermost message.
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(100, reader.readInt32());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Validate embedded message 1.
+      reader.nextField();
+      assertEquals(3, reader.getFieldNumber());
+      assertEquals(300, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(4, reader.getFieldNumber());
+      assertEquals(400, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(5, reader.getFieldNumber());
+      assertEquals(500, reader.readInt32());
+
+      assertEquals(false, reader.nextField());
+    });
+
+    reader.nextField();
+    assertEquals(6, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Validate embedded message 2.
+
+      assertEquals(false, reader.nextField());
+    });
+
+    reader.nextField();
+    assertEquals(7, reader.getFieldNumber());
+    assertEquals(700, reader.readInt32());
+
+    assertEquals(false, reader.nextField());
+  });
+
+  /**
+   * Tests skipping fields of each type by interleaving them with sentinel
+   * values and skipping everything that's not a sentinel.
+   */
+  it('testSkipField', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var sentinel = 123456789;
+
+    // Write varint fields of different sizes.
+    writer.writeInt32(1, sentinel);
+    writer.writeInt32(1, 1);
+    writer.writeInt32(1, 1000);
+    writer.writeInt32(1, 1000000);
+    writer.writeInt32(1, 1000000000);
+
+    // Write fixed 64-bit encoded fields.
+    writer.writeInt32(2, sentinel);
+    writer.writeDouble(2, 1);
+    writer.writeFixed64(2, 1);
+    writer.writeSfixed64(2, 1);
+
+    // Write fixed 32-bit encoded fields.
+    writer.writeInt32(3, sentinel);
+    writer.writeFloat(3, 1);
+    writer.writeFixed32(3, 1);
+    writer.writeSfixed32(3, 1);
+
+    // Write delimited fields.
+    writer.writeInt32(4, sentinel);
+    writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
+
+    // Write a group with a nested group inside.
+    writer.writeInt32(5, sentinel);
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+    writer.writeGroup(5, dummyMessage, function() {
+      writer.writeInt64(42, 42);
+      writer.writeGroup(6, dummyMessage, function() {
+        writer.writeInt64(84, 42);
+      });
+    });
+
+    // Write final sentinel.
+    writer.writeInt32(6, sentinel);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    function skip(field, count) {
+      for (var i = 0; i < count; i++) {
+        reader.nextField();
+        if (field != reader.getFieldNumber()) throw 'fail!';
+        reader.skipField();
+      }
+    }
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(1, 4);
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(2, 3);
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(3, 3);
+
+    reader.nextField();
+    assertEquals(4, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(4, 2);
+
+    reader.nextField();
+    assertEquals(5, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(5, 1);
+
+    reader.nextField();
+    assertEquals(6, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+  });
+
+
+  /**
+   * Tests packed fields.
+   */
+  it('testPackedFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var sentinel = 123456789;
+
+    var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
+    var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
+    var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
+    var boolData = [true, false, true, true, false, false, true, false];
+
+    for (var i = 0; i < floatData.length; i++) {
+      floatData[i] = truncate(floatData[i]);
+    }
+
+    writer.writeInt32(1, sentinel);
+
+    writer.writePackedInt32(2, signedData);
+    writer.writePackedInt64(2, signedData);
+    writer.writePackedUint32(2, unsignedData);
+    writer.writePackedUint64(2, unsignedData);
+    writer.writePackedSint32(2, signedData);
+    writer.writePackedSint64(2, signedData);
+    writer.writePackedFixed32(2, unsignedData);
+    writer.writePackedFixed64(2, unsignedData);
+    writer.writePackedSfixed32(2, signedData);
+    writer.writePackedSfixed64(2, signedData);
+    writer.writePackedFloat(2, floatData);
+    writer.writePackedDouble(2, doubleData);
+    writer.writePackedBool(2, boolData);
+    writer.writePackedEnum(2, unsignedData);
+
+    writer.writeInt32(3, sentinel);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    reader.nextField();
+    assertEquals(sentinel, reader.readInt32());
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedInt32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedInt64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedUint32(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedUint64(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSint32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSint64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFixed32(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFixed64(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSfixed32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSfixed64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFloat(), floatData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedDouble(), doubleData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedBool(), boolData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedEnum(), unsignedData);
+
+    reader.nextField();
+    assertEquals(sentinel, reader.readInt32());
+  });
+
+
+  /**
+   * Byte blobs inside nested messages should always have their byte offset set
+   * relative to the start of the outermost blob, not the start of their parent
+   * blob.
+   */
+  it('testNestedBlobs', function() {
+    // Create a proto consisting of two nested messages, with the inner one
+    // containing a blob of bytes.
+
+    var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
+    var blob = [1, 2, 3, 4, 5];
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    writer.writeMessage(1, dummyMessage, function() {
+      writer.writeMessage(1, dummyMessage, function() {
+        writer.writeBytes(1, blob);
+      });
+    });
+
+    // Peel off the outer two message layers. Each layer should have two bytes
+    // of overhead, one for the field tag and one for the length of the inner
+    // blob.
+
+    var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
+    assertEquals(fieldTag, decoder1.readUnsignedVarint32());
+    assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
+
+    var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
+    assertEquals(fieldTag, decoder2.readUnsignedVarint32());
+    assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
+
+    assertEquals(fieldTag, decoder2.readUnsignedVarint32());
+    assertEquals(blob.length, decoder2.readUnsignedVarint32());
+    var bytes = decoder2.readBytes(blob.length);
+
+    assertElementsEquals(bytes, blob);
+  });
+
+
+  /**
+   * Tests read callbacks.
+   */
+  it('testReadCallbacks', function() {
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    // Add an int, a submessage, and another int.
+    writer.writeInt32(1, 100);
+
+    writer.writeMessage(2, dummyMessage, function() {
+      writer.writeInt32(3, 300);
+      writer.writeInt32(4, 400);
+      writer.writeInt32(5, 500);
+    });
+
+    writer.writeInt32(7, 700);
+
+    // Create the reader and register a custom read callback.
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    /**
+     * @param {!jspb.BinaryReader} reader
+     * @return {*}
+     */
+    function readCallback(reader) {
+      reader.nextField();
+      assertEquals(3, reader.getFieldNumber());
+      assertEquals(300, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(4, reader.getFieldNumber());
+      assertEquals(400, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(5, reader.getFieldNumber());
+      assertEquals(500, reader.readInt32());
+
+      assertEquals(false, reader.nextField());
+    };
+
+    reader.registerReadCallback('readCallback', readCallback);
+
+    // Read the container message.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(100, reader.readInt32());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Decode the embedded message using the registered callback.
+      reader.runReadCallback('readCallback');
+    });
+
+    reader.nextField();
+    assertEquals(7, reader.getFieldNumber());
+    assertEquals(700, reader.readInt32());
+
+    assertEquals(false, reader.nextField());
+  });
+});
diff --git a/js/binary/utils.js b/js/binary/utils.js
new file mode 100644
index 0000000..5140555
--- /dev/null
+++ b/js/binary/utils.js
@@ -0,0 +1,975 @@
+// 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.
+
+/**
+ * @fileoverview This file contains helper code used by jspb.BinaryReader
+ * and BinaryWriter.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.utils');
+
+goog.require('goog.asserts');
+goog.require('goog.crypt.base64');
+goog.require('goog.string');
+goog.require('jspb.BinaryConstants');
+
+
+/**
+ * Javascript can't natively handle 64-bit data types, so to manipulate them we
+ * have to split them into two 32-bit halves and do the math manually.
+ *
+ * Instead of instantiating and passing small structures around to do this, we
+ * instead just use two global temporary values. This one stores the low 32
+ * bits of a split value - for example, if the original value was a 64-bit
+ * integer, this temporary value will contain the low 32 bits of that integer.
+ * If the original value was a double, this temporary value will contain the
+ * low 32 bits of the binary representation of that double, etcetera.
+ * @type {number}
+ */
+jspb.utils.split64Low = 0;
+
+
+/**
+ * And correspondingly, this temporary variable will contain the high 32 bits
+ * of whatever value was split.
+ * @type {number}
+ */
+jspb.utils.split64High = 0;
+
+
+/**
+ * Splits an unsigned Javascript integer into two 32-bit halves and stores it
+ * in the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitUint64 = function(value) {
+  // Extract low 32 bits and high 32 bits as unsigned integers.
+  var lowBits = value >>> 0;
+  var highBits = Math.floor((value - lowBits) /
+                            jspb.BinaryConstants.TWO_TO_32) >>> 0;
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Splits a signed Javascript integer into two 32-bit halves and stores it in
+ * the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitInt64 = function(value) {
+  // Convert to sign-magnitude representation.
+  var sign = (value < 0);
+  value = Math.abs(value);
+
+  // Extract low 32 bits and high 32 bits as unsigned integers.
+  var lowBits = value >>> 0;
+  var highBits = Math.floor((value - lowBits) /
+                            jspb.BinaryConstants.TWO_TO_32);
+  highBits = highBits >>> 0;
+
+  // Perform two's complement conversion if the sign bit was set.
+  if (sign) {
+    highBits = ~highBits >>> 0;
+    lowBits = ~lowBits >>> 0;
+    lowBits += 1;
+    if (lowBits > 0xFFFFFFFF) {
+      lowBits = 0;
+      highBits++;
+      if (highBits > 0xFFFFFFFF) highBits = 0;
+    }
+  }
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Convers a signed Javascript integer into zigzag format, splits it into two
+ * 32-bit halves, and stores it in the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitZigzag64 = function(value) {
+  // Convert to sign-magnitude and scale by 2 before we split the value.
+  var sign = (value < 0);
+  value = Math.abs(value) * 2;
+
+  jspb.utils.splitUint64(value);
+  var lowBits = jspb.utils.split64Low;
+  var highBits = jspb.utils.split64High;
+
+  // If the value is negative, subtract 1 from the split representation so we
+  // don't lose the sign bit due to precision issues.
+  if (sign) {
+    if (lowBits == 0) {
+      if (highBits == 0) {
+        lowBits = 0xFFFFFFFF;
+        highBits = 0xFFFFFFFF;
+      } else {
+        highBits--;
+        lowBits = 0xFFFFFFFF;
+      }
+    } else {
+      lowBits--;
+    }
+  }
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Converts a floating-point number into 32-bit IEEE representation and stores
+ * it in the temp values above.
+ * @param {number} value
+ */
+jspb.utils.splitFloat32 = function(value) {
+  var sign = (value < 0) ? 1 : 0;
+  value = sign ? -value : value;
+  var exp;
+  var mant;
+
+  // Handle zeros.
+  if (value === 0) {
+    if ((1 / value) > 0) {
+      // Positive zero.
+      jspb.utils.split64High = 0;
+      jspb.utils.split64Low = 0x00000000;
+    } else {
+      // Negative zero.
+      jspb.utils.split64High = 0;
+      jspb.utils.split64Low = 0x80000000;
+    }
+    return;
+  }
+
+  // Handle nans.
+  if (isNaN(value)) {
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = 0x7FFFFFFF;
+    return;
+  }
+
+  // Handle infinities.
+  if (value > jspb.BinaryConstants.FLOAT32_MAX) {
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = ((sign << 31) | (0x7F800000)) >>> 0;
+    return;
+  }
+
+  // Handle denormals.
+  if (value < jspb.BinaryConstants.FLOAT32_MIN) {
+    // Number is a denormal.
+    mant = Math.round(value / Math.pow(2, -149));
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = ((sign << 31) | mant) >>> 0;
+    return;
+  }
+
+  exp = Math.floor(Math.log(value) / Math.LN2);
+  mant = value * Math.pow(2, -exp);
+  mant = Math.round(mant * jspb.BinaryConstants.TWO_TO_23) & 0x7FFFFF;
+
+  jspb.utils.split64High = 0;
+  jspb.utils.split64Low = ((sign << 31) | ((exp + 127) << 23) | mant) >>> 0;
+};
+
+
+/**
+ * Converts a floating-point number into 64-bit IEEE representation and stores
+ * it in the temp values above.
+ * @param {number} value
+ */
+jspb.utils.splitFloat64 = function(value) {
+  var sign = (value < 0) ? 1 : 0;
+  value = sign ? -value : value;
+
+  // Handle zeros.
+  if (value === 0) {
+    if ((1 / value) > 0) {
+      // Positive zero.
+      jspb.utils.split64High = 0x00000000;
+      jspb.utils.split64Low = 0x00000000;
+    } else {
+      // Negative zero.
+      jspb.utils.split64High = 0x80000000;
+      jspb.utils.split64Low = 0x00000000;
+    }
+    return;
+  }
+
+  // Handle nans.
+  if (isNaN(value)) {
+    jspb.utils.split64High = 0x7FFFFFFF;
+    jspb.utils.split64Low = 0xFFFFFFFF;
+    return;
+  }
+
+  // Handle infinities.
+  if (value > jspb.BinaryConstants.FLOAT64_MAX) {
+    jspb.utils.split64High = ((sign << 31) | (0x7FF00000)) >>> 0;
+    jspb.utils.split64Low = 0;
+    return;
+  }
+
+  // Handle denormals.
+  if (value < jspb.BinaryConstants.FLOAT64_MIN) {
+    // Number is a denormal.
+    var mant = value / Math.pow(2, -1074);
+    var mantHigh = (mant / jspb.BinaryConstants.TWO_TO_32);
+    jspb.utils.split64High = ((sign << 31) | mantHigh) >>> 0;
+    jspb.utils.split64Low = (mant >>> 0);
+    return;
+  }
+
+  var exp = Math.floor(Math.log(value) / Math.LN2);
+  if (exp == 1024) exp = 1023;
+  var mant = value * Math.pow(2, -exp);
+
+  var mantHigh = (mant * jspb.BinaryConstants.TWO_TO_20) & 0xFFFFF;
+  var mantLow = (mant * jspb.BinaryConstants.TWO_TO_52) >>> 0;
+
+  jspb.utils.split64High =
+      ((sign << 31) | ((exp + 1023) << 20) | mantHigh) >>> 0;
+  jspb.utils.split64Low = mantLow;
+};
+
+
+/**
+ * Converts an 8-character hash string into two 32-bit numbers and stores them
+ * in the temp values above.
+ * @param {string} hash
+ */
+jspb.utils.splitHash64 = function(hash) {
+  var a = hash.charCodeAt(0);
+  var b = hash.charCodeAt(1);
+  var c = hash.charCodeAt(2);
+  var d = hash.charCodeAt(3);
+  var e = hash.charCodeAt(4);
+  var f = hash.charCodeAt(5);
+  var g = hash.charCodeAt(6);
+  var h = hash.charCodeAt(7);
+
+  jspb.utils.split64Low = (a + (b << 8) + (c << 16) + (d << 24)) >>> 0;
+  jspb.utils.split64High = (e + (f << 8) + (g << 16) + (h << 24)) >>> 0;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit unsigned integer. Precision will be
+ * lost if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinUint64 = function(bitsLow, bitsHigh) {
+  return bitsHigh * jspb.BinaryConstants.TWO_TO_32 + bitsLow;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit signed integer. Precision will be lost
+ * if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinInt64 = function(bitsLow, bitsHigh) {
+  // If the high bit is set, do a manual two's complement conversion.
+  var sign = (bitsHigh & 0x80000000);
+  if (sign) {
+    bitsLow = (~bitsLow + 1) >>> 0;
+    bitsHigh = ~bitsHigh >>> 0;
+    if (bitsLow == 0) {
+      bitsHigh = (bitsHigh + 1) >>> 0;
+    }
+  }
+
+  var result = jspb.utils.joinUint64(bitsLow, bitsHigh);
+  return sign ? -result : result;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit unsigned integer and applies zigzag
+ * decoding. Precision will be lost if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinZigzag64 = function(bitsLow, bitsHigh) {
+  // Extract the sign bit and shift right by one.
+  var sign = bitsLow & 1;
+  bitsLow = ((bitsLow >>> 1) | (bitsHigh << 31)) >>> 0;
+  bitsHigh = bitsHigh >>> 1;
+
+  // Increment the split value if the sign bit was set.
+  if (sign) {
+    bitsLow = (bitsLow + 1) >>> 0;
+    if (bitsLow == 0) {
+      bitsHigh = (bitsHigh + 1) >>> 0;
+    }
+  }
+
+  var result = jspb.utils.joinUint64(bitsLow, bitsHigh);
+  return sign ? -result : result;
+};
+
+
+/**
+ * Joins two 32-bit values into a 32-bit IEEE floating point number and
+ * converts it back into a Javascript number.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {number}
+ */
+jspb.utils.joinFloat32 = function(bitsLow, bitsHigh) {
+  var sign = ((bitsLow >> 31) * 2 + 1);
+  var exp = (bitsLow >>> 23) & 0xFF;
+  var mant = bitsLow & 0x7FFFFF;
+
+  if (exp == 0xFF) {
+    if (mant) {
+      return NaN;
+    } else {
+      return sign * Infinity;
+    }
+  }
+
+  if (exp == 0) {
+    // Denormal.
+    return sign * Math.pow(2, -149) * mant;
+  } else {
+    return sign * Math.pow(2, exp - 150) *
+           (mant + Math.pow(2, 23));
+  }
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit IEEE floating point number and
+ * converts it back into a Javascript number.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {number}
+ */
+jspb.utils.joinFloat64 = function(bitsLow, bitsHigh) {
+  var sign = ((bitsHigh >> 31) * 2 + 1);
+  var exp = (bitsHigh >>> 20) & 0x7FF;
+  var mant = jspb.BinaryConstants.TWO_TO_32 * (bitsHigh & 0xFFFFF) + bitsLow;
+
+  if (exp == 0x7FF) {
+    if (mant) {
+      return NaN;
+    } else {
+      return sign * Infinity;
+    }
+  }
+
+  if (exp == 0) {
+    // Denormal.
+    return sign * Math.pow(2, -1074) * mant;
+  } else {
+    return sign * Math.pow(2, exp - 1075) *
+           (mant + jspb.BinaryConstants.TWO_TO_52);
+  }
+};
+
+
+/**
+ * Joins two 32-bit values into an 8-character hash string.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {string}
+ */
+jspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
+  var a = (bitsLow >>> 0) & 0xFF;
+  var b = (bitsLow >>> 8) & 0xFF;
+  var c = (bitsLow >>> 16) & 0xFF;
+  var d = (bitsLow >>> 24) & 0xFF;
+  var e = (bitsHigh >>> 0) & 0xFF;
+  var f = (bitsHigh >>> 8) & 0xFF;
+  var g = (bitsHigh >>> 16) & 0xFF;
+  var h = (bitsHigh >>> 24) & 0xFF;
+
+  return String.fromCharCode(a, b, c, d, e, f, g, h);
+};
+
+
+/**
+ * Individual digits for number->string conversion.
+ * @const {!Array.<number>}
+ */
+jspb.utils.DIGITS = [
+  '0', '1', '2', '3', '4', '5', '6', '7',
+  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+];
+
+
+/**
+ * Losslessly converts a 64-bit unsigned integer in 32:32 split representation
+ * into a decimal string.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {string} The binary number represented as a string.
+ */
+jspb.utils.joinUnsignedDecimalString = function(bitsLow, bitsHigh) {
+  // Skip the expensive conversion if the number is small enough to use the
+  // built-in conversions.
+  if (bitsHigh <= 0x1FFFFF) {
+    return '' + (jspb.BinaryConstants.TWO_TO_32 * bitsHigh + bitsLow);
+  }
+
+  // What this code is doing is essentially converting the input number from
+  // base-2 to base-1e7, which allows us to represent the 64-bit range with
+  // only 3 (very large) digits. Those digits are then trivial to convert to
+  // a base-10 string.
+
+  // The magic numbers used here are -
+  // 2^24 = 16777216 = (1,6777216) in base-1e7.
+  // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
+
+  // Split 32:32 representation into 16:24:24 representation so our
+  // intermediate digits don't overflow.
+  var low = bitsLow & 0xFFFFFF;
+  var mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF;
+  var high = (bitsHigh >> 16) & 0xFFFF;
+
+  // Assemble our three base-1e7 digits, ignoring carries. The maximum
+  // value in a digit at this step is representable as a 48-bit integer, which
+  // can be stored in a 64-bit floating point number.
+  var digitA = low + (mid * 6777216) + (high * 6710656);
+  var digitB = mid + (high * 8147497);
+  var digitC = (high * 2);
+
+  // Apply carries from A to B and from B to C.
+  var base = 10000000;
+  if (digitA >= base) {
+    digitB += Math.floor(digitA / base);
+    digitA %= base;
+  }
+
+  if (digitB >= base) {
+    digitC += Math.floor(digitB / base);
+    digitB %= base;
+  }
+
+  // Convert base-1e7 digits to base-10, omitting leading zeroes.
+  var table = jspb.utils.DIGITS;
+  var start = false;
+  var result = '';
+
+  function emit(digit) {
+    var temp = base;
+    for (var i = 0; i < 7; i++) {
+      temp /= 10;
+      var decimalDigit = ((digit / temp) % 10) >>> 0;
+      if ((decimalDigit == 0) && !start) continue;
+      start = true;
+      result += table[decimalDigit];
+    }
+  }
+
+  if (digitC || start) emit(digitC);
+  if (digitB || start) emit(digitB);
+  if (digitA || start) emit(digitA);
+
+  return result;
+};
+
+
+/**
+ * Losslessly converts a 64-bit signed integer in 32:32 split representation
+ * into a decimal string.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {string} The binary number represented as a string.
+ */
+jspb.utils.joinSignedDecimalString = function(bitsLow, bitsHigh) {
+  // If we're treating the input as a signed value and the high bit is set, do
+  // a manual two's complement conversion before the decimal conversion.
+  var negative = (bitsHigh & 0x80000000);
+  if (negative) {
+    bitsLow = (~bitsLow + 1) >>> 0;
+    var carry = (bitsLow == 0) ? 1 : 0;
+    bitsHigh = (~bitsHigh + carry) >>> 0;
+  }
+
+  var result = jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
+  return negative ? '-' + result : result;
+};
+
+
+/**
+ * Convert an 8-character hash string representing either a signed or unsigned
+ * 64-bit integer into its decimal representation without losing accuracy.
+ * @param {string} hash The hash string to convert.
+ * @param {boolean} signed True if we should treat the hash string as encoding
+ *     a signed integer.
+ * @return {string}
+ */
+jspb.utils.hash64ToDecimalString = function(hash, signed) {
+  jspb.utils.splitHash64(hash);
+  var bitsLow = jspb.utils.split64Low;
+  var bitsHigh = jspb.utils.split64High;
+  return signed ?
+      jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh) :
+      jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Converts an array of 8-character hash strings into their decimal
+ * representations.
+ * @param {!Array.<string>} hashes The array of hash strings to convert.
+ * @param {boolean} signed True if we should treat the hash string as encoding
+ *     a signed integer.
+ * @return {!Array.<string>}
+ */
+jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) {
+  var result = new Array(hashes.length);
+  for (var i = 0; i < hashes.length; i++) {
+    result[i] = jspb.utils.hash64ToDecimalString(hashes[i], signed);
+  }
+  return result;
+};
+
+
+/**
+ * Converts a signed or unsigned decimal string into its hash string
+ * representation.
+ * @param {string} dec
+ * @return {string}
+ */
+jspb.utils.decimalStringToHash64 = function(dec) {
+  goog.asserts.assert(dec.length > 0);
+
+  // Check for minus sign.
+  var minus = false;
+  if (dec[0] === '-') {
+    minus = true;
+    dec = dec.slice(1);
+  }
+
+  // Store result as a byte array.
+  var resultBytes = [0, 0, 0, 0, 0, 0, 0, 0];
+
+  // Set result to m*result + c.
+  function muladd(m, c) {
+    for (var i = 0; i < 8 && (m !== 1 || c > 0); i++) {
+      var r = m * resultBytes[i] + c;
+      resultBytes[i] = r & 0xFF;
+      c = r >>> 8;
+    }
+  }
+
+  // Negate the result bits.
+  function neg() {
+    for (var i = 0; i < 8; i++) {
+      resultBytes[i] = (~resultBytes[i]) & 0xFF;
+    }
+  }
+
+  // For each decimal digit, set result to 10*result + digit.
+  for (var i = 0; i < dec.length; i++) {
+    muladd(10, jspb.utils.DIGITS.indexOf(dec[i]));
+  }
+
+  // If there's a minus sign, convert into two's complement.
+  if (minus) {
+    neg();
+    muladd(1, 1);
+  }
+
+  return String.fromCharCode.apply(null, resultBytes);
+};
+
+
+/**
+ * Converts an 8-character hash string into its hexadecimal representation.
+ * @param {string} hash
+ * @return {string}
+ */
+jspb.utils.hash64ToHexString = function(hash) {
+  var temp = new Array(18);
+  temp[0] = '0';
+  temp[1] = 'x';
+
+  for (var i = 0; i < 8; i++) {
+    var c = hash.charCodeAt(7 - i);
+    temp[i * 2 + 2] = jspb.utils.DIGITS[c >> 4];
+    temp[i * 2 + 3] = jspb.utils.DIGITS[c & 0xF];
+  }
+
+  var result = temp.join('');
+  return result;
+};
+
+
+/**
+ * Converts a '0x<16 digits>' hex string into its hash string representation.
+ * @param {string} hex
+ * @return {string}
+ */
+jspb.utils.hexStringToHash64 = function(hex) {
+  hex = hex.toLowerCase();
+  goog.asserts.assert(hex.length == 18);
+  goog.asserts.assert(hex[0] == '0');
+  goog.asserts.assert(hex[1] == 'x');
+
+  var result = '';
+  for (var i = 0; i < 8; i++) {
+    var hi = jspb.utils.DIGITS.indexOf(hex[i * 2 + 2]);
+    var lo = jspb.utils.DIGITS.indexOf(hex[i * 2 + 3]);
+    result = String.fromCharCode(hi * 16 + lo) + result;
+  }
+
+  return result;
+};
+
+
+/**
+ * Convert an 8-character hash string representing either a signed or unsigned
+ * 64-bit integer into a Javascript number. Will lose accuracy if the result is
+ * larger than 2^52.
+ * @param {string} hash The hash string to convert.
+ * @param {boolean} signed True if the has should be interpreted as a signed
+ *     number.
+ * @return {number}
+ */
+jspb.utils.hash64ToNumber = function(hash, signed) {
+  jspb.utils.splitHash64(hash);
+  var bitsLow = jspb.utils.split64Low;
+  var bitsHigh = jspb.utils.split64High;
+  return signed ? jspb.utils.joinInt64(bitsLow, bitsHigh) :
+                  jspb.utils.joinUint64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Convert a Javascript number into an 8-character hash string. Will lose
+ * precision if the value is non-integral or greater than 2^64.
+ * @param {number} value The integer to convert.
+ * @return {string}
+ */
+jspb.utils.numberToHash64 = function(value) {
+  jspb.utils.splitInt64(value);
+  return jspb.utils.joinHash64(jspb.utils.split64Low,
+                                  jspb.utils.split64High);
+};
+
+
+/**
+ * Counts the number of contiguous varints in a buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @return {number} The number of varints in the buffer.
+ */
+jspb.utils.countVarints = function(buffer, start, end) {
+  // Count how many high bits of each byte were set in the buffer.
+  var count = 0;
+  for (var i = start; i < end; i++) {
+    count += buffer[i] >> 7;
+  }
+
+  // The number of varints in the buffer equals the size of the buffer minus
+  // the number of non-terminal bytes in the buffer (those with the high bit
+  // set).
+  return (end - start) - count;
+};
+
+
+/**
+ * Counts the number of contiguous varint fields with the given field number in
+ * the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countVarintFields = function(buffer, start, end, field) {
+  var count = 0;
+  var cursor = start;
+  var tag = field * 8 + jspb.BinaryConstants.WireType.VARINT;
+
+  if (tag < 128) {
+    // Single-byte field tag, we can use a slightly quicker count.
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      if (buffer[cursor++] != tag) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the varint.
+      while (1) {
+        var x = buffer[cursor++];
+        if ((x & 0x80) == 0) break;
+      }
+    }
+  } else {
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      var temp = tag;
+      while (temp > 128) {
+        if (buffer[cursor] != ((temp & 0x7F) | 0x80)) return count;
+        cursor++;
+        temp >>= 7;
+      }
+      if (buffer[cursor++] != temp) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the varint.
+      while (1) {
+        var x = buffer[cursor++];
+        if ((x & 0x80) == 0) break;
+      }
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Counts the number of contiguous fixed32 fields with the given tag in the
+ * buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} tag The tag value to count.
+ * @param {number} stride The number of bytes to skip per field.
+ * @return {number} The number of fields with a matching tag in the buffer.
+ * @private
+ */
+jspb.utils.countFixedFields_ =
+    function(buffer, start, end, tag, stride) {
+  var count = 0;
+  var cursor = start;
+
+  if (tag < 128) {
+    // Single-byte field tag, we can use a slightly quicker count.
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      if (buffer[cursor++] != tag) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the value.
+      cursor += stride;
+    }
+  } else {
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      var temp = tag;
+      while (temp > 128) {
+        if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
+        temp >>= 7;
+      }
+      if (buffer[cursor++] != temp) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the value.
+      cursor += stride;
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Counts the number of contiguous fixed32 fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countFixed32Fields = function(buffer, start, end, field) {
+  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED32;
+  return jspb.utils.countFixedFields_(buffer, start, end, tag, 4);
+};
+
+
+/**
+ * Counts the number of contiguous fixed64 fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countFixed64Fields = function(buffer, start, end, field) {
+  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED64;
+  return jspb.utils.countFixedFields_(buffer, start, end, tag, 8);
+};
+
+
+/**
+ * Counts the number of contiguous delimited fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countDelimitedFields = function(buffer, start, end, field) {
+  var count = 0;
+  var cursor = start;
+  var tag = field * 8 + jspb.BinaryConstants.WireType.DELIMITED;
+
+  while (cursor < end) {
+    // Skip the field tag, or exit if we find a non-matching tag.
+    var temp = tag;
+    while (temp > 128) {
+      if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
+      temp >>= 7;
+    }
+    if (buffer[cursor++] != temp) return count;
+
+    // Field tag matches, we've found a valid field.
+    count++;
+
+    // Decode the length prefix.
+    var length = 0;
+    var shift = 1;
+    while (1) {
+      temp = buffer[cursor++];
+      length += (temp & 0x7f) * shift;
+      shift *= 128;
+      if ((temp & 0x80) == 0) break;
+    }
+
+    // Advance the cursor past the blob.
+    cursor += length;
+  }
+  return count;
+};
+
+
+/**
+ * String-ify bytes for text format. Should be optimized away in non-debug.
+ * The returned string uses \xXX escapes for all values and is itself quoted.
+ * [1, 31] serializes to '"\x01\x1f"'.
+ * @param {jspb.ByteSource} byteSource The bytes to serialize.
+ * @return {string} Stringified bytes for text format.
+ */
+jspb.utils.debugBytesToTextFormat = function(byteSource) {
+  var s = '"';
+  if (byteSource) {
+    var bytes = jspb.utils.byteSourceToUint8Array(byteSource);
+    for (var i = 0; i < bytes.length; i++) {
+      s += '\\x';
+      if (bytes[i] < 16) s += '0';
+      s += bytes[i].toString(16);
+    }
+  }
+  return s + '"';
+};
+
+
+/**
+ * String-ify a scalar for text format. Should be optimized away in non-debug.
+ * @param {string|number|boolean} scalar The scalar to stringify.
+ * @return {string} Stringified scalar for text format.
+ */
+jspb.utils.debugScalarToTextFormat = function(scalar) {
+  if (goog.isString(scalar)) {
+    return goog.string.quote(scalar);
+  } else {
+    return scalar.toString();
+  }
+};
+
+
+/**
+ * Utility function: convert a string with codepoints 0--255 inclusive to a
+ * Uint8Array. If any codepoints greater than 255 exist in the string, throws an
+ * exception.
+ * @param {string} str
+ * @return {!Uint8Array}
+ */
+jspb.utils.stringToByteArray = function(str) {
+  var arr = new Uint8Array(str.length);
+  for (var i = 0; i < str.length; i++) {
+    var codepoint = str.charCodeAt(i);
+    if (codepoint > 255) {
+      throw new Error('Conversion error: string contains codepoint ' +
+                      'outside of byte range');
+    }
+    arr[i] = codepoint;
+  }
+  return arr;
+};
+
+
+/**
+ * Converts any type defined in jspb.ByteSource into a Uint8Array.
+ * @param {!jspb.ByteSource} data
+ * @return {!Uint8Array}
+ * @suppress {invalidCasts}
+ */
+jspb.utils.byteSourceToUint8Array = function(data) {
+  if (data.constructor === Uint8Array) {
+    return /** @type {!Uint8Array} */(data);
+  }
+
+  if (data.constructor === ArrayBuffer) {
+    data = /** @type {!ArrayBuffer} */(data);
+    return /** @type {!Uint8Array} */(new Uint8Array(data));
+  }
+
+  if (data.constructor === Array) {
+    data = /** @type {!Array.<number>} */(data);
+    return /** @type {!Uint8Array} */(new Uint8Array(data));
+  }
+
+  if (data.constructor === String) {
+    data = /** @type {string} */(data);
+    return goog.crypt.base64.decodeStringToUint8Array(data);
+  }
+
+  goog.asserts.fail('Type not convertible to Uint8Array.');
+  return /** @type {!Uint8Array} */(new Uint8Array(0));
+};
diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js
new file mode 100644
index 0000000..d27e5ea
--- /dev/null
+++ b/js/binary/utils_test.js
@@ -0,0 +1,668 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's helper functions.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.crypt.base64');
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryWriter');
+goog.require('jspb.utils');
+
+
+/**
+ * @param {number} x
+ * @return {number}
+ */
+function truncate(x) {
+  var temp = new Float32Array(1);
+  temp[0] = x;
+  return temp[0];
+}
+
+
+/**
+ * Converts an 64-bit integer in split representation to a 64-bit hash string
+ * (8 bits encoded per character).
+ * @param {number} bitsLow The low 32 bits of the split 64-bit integer.
+ * @param {number} bitsHigh The high 32 bits of the split 64-bit integer.
+ * @return {string} The encoded hash string, 8 bits per character.
+ */
+function toHashString(bitsLow, bitsHigh) {
+  return String.fromCharCode((bitsLow >>> 0) & 0xFF,
+                             (bitsLow >>> 8) & 0xFF,
+                             (bitsLow >>> 16) & 0xFF,
+                             (bitsLow >>> 24) & 0xFF,
+                             (bitsHigh >>> 0) & 0xFF,
+                             (bitsHigh >>> 8) & 0xFF,
+                             (bitsHigh >>> 16) & 0xFF,
+                             (bitsHigh >>> 24) & 0xFF);
+}
+
+
+describe('binaryUtilsTest', function() {
+  /**
+   * Tests lossless binary-to-decimal conversion.
+   */
+  it('testDecimalConversion', function() {
+    // Check some magic numbers.
+    var result =
+        jspb.utils.joinUnsignedDecimalString(0x89e80001, 0x8ac72304);
+    assertEquals('10000000000000000001', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xacd05f15, 0x1b69b4b);
+    assertEquals('123456789123456789', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xeb1f0ad2, 0xab54a98c);
+    assertEquals('12345678901234567890', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xe3b70cb1, 0x891087b8);
+    assertEquals('9876543210987654321', result);
+
+    // Check limits.
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00000000);
+    assertEquals('0', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xFFFFFFFF, 0xFFFFFFFF);
+    assertEquals('18446744073709551615', result);
+
+    // Check each bit of the low dword.
+    for (var i = 0; i < 32; i++) {
+      var low = (1 << i) >>> 0;
+      result = jspb.utils.joinUnsignedDecimalString(low, 0);
+      assertEquals('' + Math.pow(2, i), result);
+    }
+
+    // Check the first 20 bits of the high dword.
+    for (var i = 0; i < 20; i++) {
+      var high = (1 << i) >>> 0;
+      result = jspb.utils.joinUnsignedDecimalString(0, high);
+      assertEquals('' + Math.pow(2, 32 + i), result);
+    }
+
+    // V8's internal double-to-string conversion is inaccurate for values above
+    // 2^52, even if they're representable integers - check the rest of the bits
+    // manually against the correct string representations of 2^N.
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00100000);
+    assertEquals('4503599627370496', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00200000);
+    assertEquals('9007199254740992', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00400000);
+    assertEquals('18014398509481984', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00800000);
+    assertEquals('36028797018963968', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x01000000);
+    assertEquals('72057594037927936', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x02000000);
+    assertEquals('144115188075855872', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x04000000);
+    assertEquals('288230376151711744', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x08000000);
+    assertEquals('576460752303423488', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x10000000);
+    assertEquals('1152921504606846976', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x20000000);
+    assertEquals('2305843009213693952', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x40000000);
+    assertEquals('4611686018427387904', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x80000000);
+    assertEquals('9223372036854775808', result);
+  });
+
+
+  /**
+   * Going from hash strings to decimal strings should also be lossless.
+   */
+  it('testHashToDecimalConversion', function() {
+    var result;
+    var convert = jspb.utils.hash64ToDecimalString;
+
+    result = convert(toHashString(0x00000000, 0x00000000), false);
+    assertEquals('0', result);
+
+    result = convert(toHashString(0x00000000, 0x00000000), true);
+    assertEquals('0', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), false);
+    assertEquals('18446744073709551615', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), true);
+    assertEquals('-1', result);
+
+    result = convert(toHashString(0x00000000, 0x80000000), false);
+    assertEquals('9223372036854775808', result);
+
+    result = convert(toHashString(0x00000000, 0x80000000), true);
+    assertEquals('-9223372036854775808', result);
+
+    result = convert(toHashString(0xacd05f15, 0x01b69b4b), false);
+    assertEquals('123456789123456789', result);
+
+    result = convert(toHashString(~0xacd05f15 + 1, ~0x01b69b4b), true);
+    assertEquals('-123456789123456789', result);
+
+    // And converting arrays of hashes should work the same way.
+    result = jspb.utils.hash64ArrayToDecimalStrings([
+      toHashString(0xFFFFFFFF, 0xFFFFFFFF),
+      toHashString(0x00000000, 0x80000000),
+      toHashString(0xacd05f15, 0x01b69b4b)], false);
+    assertEquals(3, result.length);
+    assertEquals('18446744073709551615', result[0]);
+    assertEquals('9223372036854775808', result[1]);
+    assertEquals('123456789123456789', result[2]);
+  });
+
+  /*
+   * Going from decimal strings to hash strings should be lossless.
+   */
+  it('testDecimalToHashConversion', function() {
+    var result;
+    var convert = jspb.utils.decimalStringToHash64;
+
+    result = convert('0');
+    assertEquals(String.fromCharCode.apply(null,
+      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
+
+    result = convert('-1');
+    assertEquals(String.fromCharCode.apply(null,
+      [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+
+    result = convert('18446744073709551615');
+    assertEquals(String.fromCharCode.apply(null,
+      [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+
+    result = convert('9223372036854775808');
+    assertEquals(String.fromCharCode.apply(null,
+      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
+
+    result = convert('-9223372036854775808');
+    assertEquals(String.fromCharCode.apply(null,
+      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
+
+    result = convert('123456789123456789');
+    assertEquals(String.fromCharCode.apply(null,
+      [0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]), result);
+
+    result = convert('-123456789123456789');
+    assertEquals(String.fromCharCode.apply(null,
+      [0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]), result);
+  });
+
+  /**
+   * Going from hash strings to hex strings should be lossless.
+   */
+  it('testHashToHexConversion', function() {
+    var result;
+    var convert = jspb.utils.hash64ToHexString;
+
+    result = convert(toHashString(0x00000000, 0x00000000));
+    assertEquals('0x0000000000000000', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF));
+    assertEquals('0xffffffffffffffff', result);
+
+    result = convert(toHashString(0x12345678, 0x9ABCDEF0));
+    assertEquals('0x9abcdef012345678', result);
+  });
+
+
+  /**
+   * Going from hex strings to hash strings should be lossless.
+   */
+  it('testHexToHashConversion', function() {
+    var result;
+    var convert = jspb.utils.hexStringToHash64;
+
+    result = convert('0x0000000000000000');
+    assertEquals(String.fromCharCode.apply(null,
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
+
+    result = convert('0xffffffffffffffff');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+
+    // Hex string is big-endian, hash string is little-endian.
+    result = convert('0x123456789ABCDEF0');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]), result);
+
+    // Capitalization should not matter.
+    result = convert('0x0000abcdefABCDEF');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB, 0x00, 0x00]), result);
+  });
+
+
+  /**
+   * Going from numbers to hash strings should be lossless for up to 53 bits of
+   * precision.
+   */
+  it('testNumberToHashConversion', function() {
+    var result;
+    var convert = jspb.utils.numberToHash64;
+
+    result = convert(0x0000000000000);
+    assertEquals('0x0000000000000000', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0xFFFFFFFFFFFFF);
+    assertEquals('0x000fffffffffffff', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0x123456789ABCD);
+    assertEquals('0x000123456789abcd', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0xDCBA987654321);
+    assertEquals('0x000dcba987654321', jspb.utils.hash64ToHexString(result));
+
+    // 53 bits of precision should not be truncated.
+    result = convert(0x10000000000001);
+    assertEquals('0x0010000000000001', jspb.utils.hash64ToHexString(result));
+
+    // 54 bits of precision should be truncated.
+    result = convert(0x20000000000001);
+    assertNotEquals(
+        '0x0020000000000001', jspb.utils.hash64ToHexString(result));
+  });
+
+
+  /**
+   * Sanity check the behavior of Javascript's strings when doing funny things
+   * with unicode characters.
+   */
+  it('sanityCheckUnicodeStrings', function() {
+    var strings = new Array(65536);
+
+    // All possible unsigned 16-bit values should be storable in a string, they
+    // shouldn't do weird things with the length of the string, and they should
+    // come back out of the string unchanged.
+    for (var i = 0; i < 65536; i++) {
+      strings[i] = 'a' + String.fromCharCode(i) + 'a';
+      if (3 != strings[i].length) throw 'fail!';
+      if (i != strings[i].charCodeAt(1)) throw 'fail!';
+    }
+
+    // Each unicode character should compare equal to itself and not equal to a
+    // different unicode character.
+    for (var i = 0; i < 65536; i++) {
+      if (strings[i] != strings[i]) throw 'fail!';
+      if (strings[i] == strings[(i + 1) % 65536]) throw 'fail!';
+    }
+  });
+
+
+  /**
+   * Tests conversion from 32-bit floating point numbers to split64 numbers.
+   */
+  it('testFloat32ToSplit64', function() {
+    var f32_eps = jspb.BinaryConstants.FLOAT32_EPS;
+    var f32_min = jspb.BinaryConstants.FLOAT32_MIN;
+    var f32_max = jspb.BinaryConstants.FLOAT32_MAX;
+
+    // NaN.
+    jspb.utils.splitFloat32(NaN);
+    if (!isNaN(jspb.utils.joinFloat32(jspb.utils.split64Low,
+                                      jspb.utils.split64High))) {
+      throw 'fail!';
+    }
+
+    /**
+     * @param {number} x
+     * @param {number=} opt_bits
+     */
+    function test(x, opt_bits) {
+      jspb.utils.splitFloat32(x);
+      if (goog.isDef(opt_bits)) {
+        if (opt_bits != jspb.utils.split64Low) throw 'fail!';
+      }
+      if (truncate(x) != jspb.utils.joinFloat32(jspb.utils.split64Low,
+          jspb.utils.split64High)) {
+        throw 'fail!';
+      }
+    }
+
+    // Positive and negative infinity.
+    test(Infinity, 0x7f800000);
+    test(-Infinity, 0xff800000);
+
+    // Positive and negative zero.
+    test(0, 0x00000000);
+    test(-0, 0x80000000);
+
+    // Positive and negative epsilon.
+    test(f32_eps, 0x00000001);
+    test(-f32_eps, 0x80000001);
+
+    // Positive and negative min.
+    test(f32_min, 0x00800000);
+    test(-f32_min, 0x80800000);
+
+    // Positive and negative max.
+    test(f32_max, 0x7F7FFFFF);
+    test(-f32_max, 0xFF7FFFFF);
+
+    // Various positive values.
+    var cursor = f32_eps * 10;
+    while (cursor != Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+
+    // Various negative values.
+    cursor = -f32_eps * 10;
+    while (cursor != -Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+  });
+
+
+  /**
+   * Tests conversion from 64-bit floating point numbers to split64 numbers.
+   */
+  it('testFloat64ToSplit64', function() {
+    var f64_eps = jspb.BinaryConstants.FLOAT64_EPS;
+    var f64_min = jspb.BinaryConstants.FLOAT64_MIN;
+    var f64_max = jspb.BinaryConstants.FLOAT64_MAX;
+
+    // NaN.
+    jspb.utils.splitFloat64(NaN);
+    if (!isNaN(jspb.utils.joinFloat64(jspb.utils.split64Low,
+        jspb.utils.split64High))) {
+      throw 'fail!';
+    }
+
+    /**
+     * @param {number} x
+     * @param {number=} opt_highBits
+     * @param {number=} opt_lowBits
+     */
+    function test(x, opt_highBits, opt_lowBits) {
+      jspb.utils.splitFloat64(x);
+      if (goog.isDef(opt_highBits)) {
+        if (opt_highBits != jspb.utils.split64High) throw 'fail!';
+      }
+      if (goog.isDef(opt_lowBits)) {
+        if (opt_lowBits != jspb.utils.split64Low) throw 'fail!';
+      }
+      if (x != jspb.utils.joinFloat64(jspb.utils.split64Low,
+          jspb.utils.split64High)) {
+        throw 'fail!';
+      }
+    }
+
+    // Positive and negative infinity.
+    test(Infinity, 0x7ff00000, 0x00000000);
+    test(-Infinity, 0xfff00000, 0x00000000);
+
+    // Positive and negative zero.
+    test(0, 0x00000000, 0x00000000);
+    test(-0, 0x80000000, 0x00000000);
+
+    // Positive and negative epsilon.
+    test(f64_eps, 0x00000000, 0x00000001);
+    test(-f64_eps, 0x80000000, 0x00000001);
+
+    // Positive and negative min.
+    test(f64_min, 0x00100000, 0x00000000);
+    test(-f64_min, 0x80100000, 0x00000000);
+
+    // Positive and negative max.
+    test(f64_max, 0x7FEFFFFF, 0xFFFFFFFF);
+    test(-f64_max, 0xFFEFFFFF, 0xFFFFFFFF);
+
+    // Various positive values.
+    var cursor = f64_eps * 10;
+    while (cursor != Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+
+    // Various negative values.
+    cursor = -f64_eps * 10;
+    while (cursor != -Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+  });
+
+
+  /**
+   * Tests counting packed varints.
+   */
+  it('testCountVarints', function() {
+    var values = [];
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      values.push(Math.floor(i));
+    }
+
+    var writer = new jspb.BinaryWriter();
+    writer.writePackedUint64(1, values);
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+
+    // We should have two more varints than we started with - one for the field
+    // tag, one for the packed length.
+    assertEquals(values.length + 2,
+                 jspb.utils.countVarints(buffer, 0, buffer.length));
+  });
+
+
+  /**
+   * Tests counting matching varint fields.
+   */
+  it('testCountVarintFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeUint64(1, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countVarintFields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeUint64(123456789, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countVarintFields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching fixed32 fields.
+   */
+  it('testCountFixed32Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeFixed32(1, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeFixed32(123456789, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching fixed64 fields.
+   */
+  it('testCountFixed64Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeDouble(1, i);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeDouble(123456789, i);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching delimited fields.
+   */
+  it('testCountDelimitedFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000; i *= 1.1) {
+      writer.writeBytes(1, [Math.floor(i)]);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000; i *= 1.1) {
+      writer.writeBytes(123456789, [Math.floor(i)]);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests byte format for debug strings.
+   */
+  it('testDebugBytesToTextFormat', function() {
+    assertEquals('""', jspb.utils.debugBytesToTextFormat(null));
+    assertEquals('"\\x00\\x10\\xff"',
+        jspb.utils.debugBytesToTextFormat([0, 16, 255]));
+  });
+
+
+  /**
+   * Tests converting byte blob sources into byte blobs.
+   */
+  it('testByteSourceToUint8Array', function() {
+    var convert = jspb.utils.byteSourceToUint8Array;
+
+    var sourceData = [];
+    for (var i = 0; i < 256; i++) {
+      sourceData.push(i);
+    }
+
+    var sourceBytes = new Uint8Array(sourceData);
+    var sourceBuffer = sourceBytes.buffer;
+    var sourceBase64 = goog.crypt.base64.encodeByteArray(sourceData);
+    var sourceString = String.fromCharCode.apply(null, sourceData);
+
+    function check(result) {
+      assertEquals(Uint8Array, result.constructor);
+      assertEquals(sourceData.length, result.length);
+      for (var i = 0; i < result.length; i++) {
+        assertEquals(sourceData[i], result[i]);
+      }
+    }
+
+    // Converting Uint8Arrays into Uint8Arrays should be a no-op.
+    assertEquals(sourceBytes, convert(sourceBytes));
+
+    // Converting Array.<numbers> into Uint8Arrays should work.
+    check(convert(sourceData));
+
+    // Converting ArrayBuffers into Uint8Arrays should work.
+    check(convert(sourceBuffer));
+
+    // Converting base64-encoded strings into Uint8Arrays should work.
+    check(convert(sourceBase64));
+  });
+});
diff --git a/js/binary/writer.js b/js/binary/writer.js
new file mode 100644
index 0000000..be4478e
--- /dev/null
+++ b/js/binary/writer.js
@@ -0,0 +1,1561 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for encoding Javascript objects
+ * into binary, wire-format protocol buffers (in the form of Uint8Arrays) that
+ * a server can consume directly.
+ *
+ * jspb's BinaryWriter class defines methods for efficiently encoding
+ * Javascript objects into binary, wire-format protocol buffers and supports
+ * all the fundamental field types used in protocol buffers.
+ *
+ * Major caveat 1 - Users of this library _must_ keep their Javascript proto
+ * parsing code in sync with the original .proto file - presumably you'll be
+ * using the typed jspb code generator, but if you bypass that you'll need
+ * to keep things in sync by hand.
+ *
+ * Major caveat 2 - Javascript is unable to accurately represent integers
+ * larger than 2^53 due to its use of a double-precision floating point format
+ * for all numbers. BinaryWriter does not make any special effort to preserve
+ * precision for values above this limit - if you need to pass 64-bit integers
+ * (hash codes, for example) between the client and server without precision
+ * loss, do _not_ use this library.
+ *
+ * Major caveat 3 - This class uses typed arrays and must not be used on older
+ * browsers that do not support them.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryWriter');
+
+goog.require('goog.asserts');
+goog.require('goog.crypt.base64');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryEncoder');
+goog.require('jspb.arith.Int64');
+goog.require('jspb.arith.UInt64');
+goog.require('jspb.utils');
+
+
+
+/**
+ * BinaryWriter implements encoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @constructor
+ * @struct
+ */
+jspb.BinaryWriter = function() {
+  /**
+   * Blocks of serialized data that will be concatenated once all messages have
+   * been written.
+   * @private {!Array<!Uint8Array|!Array<number>>}
+   */
+  this.blocks_ = [];
+
+  /**
+   * Total number of bytes in the blocks_ array. Does _not_ include bytes in
+   * the encoder below.
+   * @private {number}
+   */
+  this.totalLength_ = 0;
+
+  /**
+   * Binary encoder holding pieces of a message that we're still serializing.
+   * When we get to a stopping point (either the start of a new submessage, or
+   * when we need to append a raw Uint8Array), the encoder's buffer will be
+   * added to the block array above and the encoder will be reset.
+   * @private {!jspb.BinaryEncoder}
+   */
+  this.encoder_ = new jspb.BinaryEncoder();
+
+  /**
+   * A stack of bookmarks containing the parent blocks for each message started
+   * via beginSubMessage(), needed as bookkeeping for endSubMessage().
+   * TODO(aappleby): Deprecated, users should be calling writeMessage().
+   * @private {!Array.<!Array.<number>>}
+   */
+  this.bookmarks_ = [];
+};
+
+
+/**
+ * Append a typed array of bytes onto the buffer.
+ *
+ * @param {!Uint8Array} arr The byte array to append.
+ * @private
+ */
+jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
+  var temp = this.encoder_.end();
+  this.blocks_.push(temp);
+  this.blocks_.push(arr);
+  this.totalLength_ += temp.length + arr.length;
+};
+
+
+/**
+ * Begins a new message by writing the field header and returning a bookmark
+ * which we will use to patch in the message length to in endDelimited_ below.
+ * @param {number} field
+ * @return {!Array.<number>}
+ * @private
+ */
+jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  var bookmark = this.encoder_.end();
+  this.blocks_.push(bookmark);
+  this.totalLength_ += bookmark.length;
+  bookmark.push(this.totalLength_);
+  return bookmark;
+};
+
+
+/**
+ * Ends a message by encoding the _change_ in length of the buffer to the
+ * parent block and adds the number of bytes needed to encode that length to
+ * the total byte length.
+ * @param {!Array.<number>} bookmark
+ * @private
+ */
+jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
+  var oldLength = bookmark.pop();
+  var messageLength = this.totalLength_ + this.encoder_.length() - oldLength;
+  goog.asserts.assert(messageLength >= 0);
+
+  while (messageLength > 127) {
+    bookmark.push((messageLength & 0x7f) | 0x80);
+    messageLength = messageLength >>> 7;
+    this.totalLength_++;
+  }
+
+  bookmark.push(messageLength);
+  this.totalLength_++;
+};
+
+
+/**
+ * Writes a pre-serialized message to the buffer.
+ * @param {!Uint8Array} bytes The array of bytes to write.
+ * @param {number} start The start of the range to write.
+ * @param {number} end The end of the range to write.
+ */
+jspb.BinaryWriter.prototype.writeSerializedMessage = function(
+    bytes, start, end) {
+  this.appendUint8Array_(bytes.subarray(start, end));
+};
+
+
+/**
+ * Writes a pre-serialized message to the buffer if the message and endpoints
+ * are non-null.
+ * @param {?Uint8Array} bytes The array of bytes to write.
+ * @param {?number} start The start of the range to write.
+ * @param {?number} end The end of the range to write.
+ */
+jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function(
+    bytes, start, end) {
+  if (bytes != null && start != null && end != null) {
+    this.writeSerializedMessage(bytes, start, end);
+  }
+};
+
+
+/**
+ * Resets the writer, throwing away any accumulated buffers.
+ */
+jspb.BinaryWriter.prototype.reset = function() {
+  this.blocks_ = [];
+  this.encoder_.end();
+  this.totalLength_ = 0;
+  this.bookmarks_ = [];
+};
+
+
+/**
+ * Converts the encoded data into a Uint8Array.
+ * @return {!Uint8Array}
+ */
+jspb.BinaryWriter.prototype.getResultBuffer = function() {
+  goog.asserts.assert(this.bookmarks_.length == 0);
+
+  var flat = new Uint8Array(this.totalLength_ + this.encoder_.length());
+
+  var blocks = this.blocks_;
+  var blockCount = blocks.length;
+  var offset = 0;
+
+  for (var i = 0; i < blockCount; i++) {
+    var block = blocks[i];
+    flat.set(block, offset);
+    offset += block.length;
+  }
+
+  var tail = this.encoder_.end();
+  flat.set(tail, offset);
+  offset += tail.length;
+
+  // Post condition: `flattened` must have had every byte written.
+  goog.asserts.assert(offset == flat.length);
+
+  // Replace our block list with the flattened block, which lets GC reclaim
+  // the temp blocks sooner.
+  this.blocks_ = [flat];
+
+  return flat;
+};
+
+
+/**
+ * Converts the encoded data into a bas64-encoded string.
+ * @return {string}
+ */
+jspb.BinaryWriter.prototype.getResultBase64String = function() {
+  return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
+};
+
+
+/**
+ * Begins a new sub-message. The client must call endSubMessage() when they're
+ * done.
+ * TODO(aappleby): Deprecated. Move callers to writeMessage().
+ * @param {number} field The field number of the sub-message.
+ */
+jspb.BinaryWriter.prototype.beginSubMessage = function(field) {
+  this.bookmarks_.push(this.beginDelimited_(field));
+};
+
+
+/**
+ * Finishes a sub-message and packs it into the parent messages' buffer.
+ * TODO(aappleby): Deprecated. Move callers to writeMessage().
+ */
+jspb.BinaryWriter.prototype.endSubMessage = function() {
+  goog.asserts.assert(this.bookmarks_.length >= 0);
+  this.endDelimited_(this.bookmarks_.pop());
+};
+
+
+/**
+ * Encodes a (field number, wire type) tuple into a wire-format field header
+ * and stores it in the buffer as a varint.
+ * @param {number} field The field number.
+ * @param {number} wireType The wire-type of the field, as specified in the
+ *     protocol buffer documentation.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeFieldHeader_ =
+    function(field, wireType) {
+  goog.asserts.assert(field >= 1 && field == Math.floor(field));
+  var x = field * 8 + wireType;
+  this.encoder_.writeUnsignedVarint32(x);
+};
+
+
+/**
+ * Writes a field of any valid scalar type to the binary stream.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @param {number} field
+ * @param {jspb.AnyFieldType} value
+ */
+jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) {
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  switch (fieldType) {
+    case fieldTypes.DOUBLE:
+      this.writeDouble(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FLOAT:
+      this.writeFloat(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.INT64:
+      this.writeInt64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.UINT64:
+      this.writeUint64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.INT32:
+      this.writeInt32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FIXED64:
+      this.writeFixed64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FIXED32:
+      this.writeFixed32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.BOOL:
+      this.writeBool(field, /** @type {boolean} */(value));
+      return;
+    case fieldTypes.STRING:
+      this.writeString(field, /** @type {string} */(value));
+      return;
+    case fieldTypes.GROUP:
+      goog.asserts.fail('Group field type not supported in writeAny()');
+      return;
+    case fieldTypes.MESSAGE:
+      goog.asserts.fail('Message field type not supported in writeAny()');
+      return;
+    case fieldTypes.BYTES:
+      this.writeBytes(field, /** @type {?Uint8Array} */(value));
+      return;
+    case fieldTypes.UINT32:
+      this.writeUint32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.ENUM:
+      this.writeEnum(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SFIXED32:
+      this.writeSfixed32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SFIXED64:
+      this.writeSfixed64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SINT32:
+      this.writeSint32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SINT64:
+      this.writeSint64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FHASH64:
+      this.writeFixedHash64(field, /** @type {string} */(value));
+      return;
+    case fieldTypes.VHASH64:
+      this.writeVarintHash64(field, /** @type {string} */(value));
+      return;
+    default:
+      goog.asserts.fail('Invalid field type in writeAny()');
+      return;
+  }
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeUnsignedVarint32(value);
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSignedVarint32(value);
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeUnsignedVarint64(value);
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSignedVarint64(value);
+};
+
+
+/**
+ * Writes a zigzag varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeZigzagVarint32(value);
+};
+
+
+/**
+ * Writes a zigzag varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeZigzagVarint64(value);
+};
+
+
+/**
+ * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeSignedVarint32_(field, value);
+};
+
+
+/**
+ * Writes an int32 field represented as a string to the buffer. Numbers outside
+ * the range [-2^31,2^31) will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
+  if (value == null) return;
+  var intValue = /** {number} */ parseInt(value, 10);
+  goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (intValue < jspb.BinaryConstants.TWO_TO_31));
+  this.writeSignedVarint32_(field, intValue);
+};
+
+
+/**
+ * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeSignedVarint64_(field, value);
+};
+
+
+/**
+ * Writes a int64 field (with value as a string) to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.Int64.fromString(value);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSplitVarint64(num.lo, num.hi);
+};
+
+
+/**
+ * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.writeUnsignedVarint32_(field, value);
+};
+
+
+/**
+ * Writes a uint32 field represented as a string to the buffer. Numbers outside
+ * the range [0,2^32) will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
+  if (value == null) return;
+  var intValue = /** {number} */ parseInt(value, 10);
+  goog.asserts.assert((intValue >= 0) &&
+                      (intValue < jspb.BinaryConstants.TWO_TO_32));
+  this.writeUnsignedVarint32_(field, intValue);
+};
+
+
+/**
+ * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  this.writeUnsignedVarint64_(field, value);
+};
+
+
+/**
+ * Writes a uint64 field (with value as a string) to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.UInt64.fromString(value);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSplitVarint64(num.lo, num.hi);
+};
+
+
+/**
+ * Writes a sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeZigzagVarint32_(field, value);
+};
+
+
+/**
+ * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeZigzagVarint64_(field, value);
+};
+
+
+/**
+ * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.encoder_.writeUint32(value);
+};
+
+
+/**
+ * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeUint64(value);
+};
+
+
+/**
+ * Writes a sfixed32 field to the buffer. Numbers outside the range
+ * [-2^31,2^31) will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.encoder_.writeInt32(value);
+};
+
+
+/**
+ * Writes a sfixed64 field to the buffer. Numbers outside the range
+ * [-2^63,2^63) will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeInt64(value);
+};
+
+
+/**
+ * Writes a single-precision floating point field to the buffer. Numbers
+ * requiring more than 32 bits of precision will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.encoder_.writeFloat(value);
+};
+
+
+/**
+ * Writes a double-precision floating point field to the buffer. As this is the
+ * native format used by JavaScript, no precision will be lost.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeDouble(value);
+};
+
+
+/**
+ * Writes a boolean field to the buffer.
+ * @param {number} field The field number.
+ * @param {boolean?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeBool = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(goog.isBoolean(value));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeBool(value);
+};
+
+
+/**
+ * Writes an enum field to the buffer.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSignedVarint32(value);
+};
+
+
+/**
+ * Writes a string field to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The string to write.
+ */
+jspb.BinaryWriter.prototype.writeString = function(field, value) {
+  if (value == null) return;
+  var bookmark = this.beginDelimited_(field);
+  this.encoder_.writeString(value);
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an arbitrary byte field to the buffer. Note - to match the behavior
+ * of the C++ implementation, empty byte arrays _are_ serialized.
+ * @param {number} field The field number.
+ * @param {?jspb.ByteSource} value The array of bytes to write.
+ */
+jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
+  if (value == null) return;
+  var bytes = jspb.utils.byteSourceToUint8Array(value);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(bytes.length);
+  this.appendUint8Array_(bytes);
+};
+
+
+/**
+ * Writes a message to the buffer.
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?MessageType} value The message to write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeMessage = function(
+    field, value, writerCallback) {
+  if (value == null) return;
+  var bookmark = this.beginDelimited_(field);
+  writerCallback(value, this);
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes a group message to the buffer.
+ *
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?MessageType} value The message to write, wrapped with START_GROUP /
+ *     END_GROUP tags. Will be a no-op if 'value' is null.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeGroup = function(
+    field, value, writerCallback) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
+  writerCallback(value, this);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The hash string.
+ */
+jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(value.length == 8);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeFixedHash64(value);
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The hash string.
+ */
+jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(value.length == 8);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeVarintHash64(value);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUnsignedVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSignedVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUnsignedVarint64_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSignedVarint64_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint64_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt32 =
+    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt32String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeInt32String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt64 =
+    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt64String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeInt64String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
+ *     field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint32 =
+    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * unsigned 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint32String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUint32String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
+ *     field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint64 =
+    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * unsigned 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint64String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUint64String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSint32 =
+    jspb.BinaryWriter.prototype.writeRepeatedZigzag32_;
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSint64 =
+    jspb.BinaryWriter.prototype.writeRepeatedZigzag_;
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated fixed32 field. This
+ * works for both signed and unsigned fixed32s.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixed32(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated fixed64 field. This
+ * works for both signed and unsigned fixed64s.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixed64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated sfixed32 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSfixed32(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated sfixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSfixed64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated float field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFloat(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated double field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeDouble(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of booleans to the buffer as a repeated bool field.
+ * @param {number} field The field number.
+ * @param {?Array.<boolean>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeBool(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of enums to the buffer as a repeated enum field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeEnum(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of strings to the buffer as a repeated string field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of strings to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeString(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of arbitrary byte fields to the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<!jspb.ByteSource>} value The arrays of arrays of bytes to
+ *     write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeBytes(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of messages to the buffer.
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?Array.<MessageType>} value The array of messages to
+ *    write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
+    field, value, writerCallback) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    var bookmark = this.beginDelimited_(field);
+    writerCallback(value[i], this);
+    this.endDelimited_(bookmark);
+  }
+};
+
+
+/**
+ * Writes an array of group messages to the buffer.
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?Array.<MessageType>} value The array of messages to
+ *    write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
+    field, value, writerCallback) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
+    writerCallback(value[i], this);
+    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixedHash64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
+ * each) to the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeVarintHash64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = function(
+    field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeUnsignedVarint32(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = function(
+    field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeSignedVarint32(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_ = function(
+    field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeUnsignedVarint64(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedSignedVarint64_ = function(
+    field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeSignedVarint64(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedZigzag32_ = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeZigzagVarint32(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedZigzag64_ = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeZigzagVarint64(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedInt32 =
+    jspb.BinaryWriter.prototype.writePackedSignedVarint32_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedInt64 =
+    jspb.BinaryWriter.prototype.writePackedSignedVarint64_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 64-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedInt64String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    var num = jspb.arith.Int64.fromString(value[i]);
+    this.encoder_.writeSplitVarint64(num.lo, num.hi);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedUint32 =
+    jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * unsigned 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedUint32String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedUint64 =
+    jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * unsigned 64-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedUint64String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    var num = jspb.arith.UInt64.fromString(value[i]);
+    this.encoder_.writeSplitVarint64(num.lo, num.hi);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedSint32 =
+    jspb.BinaryWriter.prototype.writePackedZigzag32_;
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedSint64 =
+    jspb.BinaryWriter.prototype.writePackedZigzag64_;
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed32 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 4);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeUint32(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeUint64(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed32 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 4);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeInt32(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeInt64(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed float field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 4);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeFloat(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed double field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeDouble(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of booleans to the buffer as a packed bool field.
+ * @param {number} field The field number.
+ * @param {?Array.<boolean>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeBool(value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of enums to the buffer as a packed enum field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeEnum(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeFixedHash64(value[i]);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeVarintHash64(value[i]);
+  }
+  this.endDelimited_(bookmark);
+};
diff --git a/js/binary/writer_test.js b/js/binary/writer_test.js
new file mode 100644
index 0000000..54d37a2
--- /dev/null
+++ b/js/binary/writer_test.js
@@ -0,0 +1,123 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer writer. In
+ * practice BinaryWriter is used to drive the Decoder and Reader test cases,
+ * so only writer-specific tests are here.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.crypt');
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryWriter');
+
+
+/**
+ * @param {function()} func This function should throw an error when run.
+ */
+function assertFails(func) {
+  var e = assertThrows(func);
+  console.log(e);
+  //assertNotNull(e.toString().match(/Error/));
+}
+
+
+describe('binaryWriterTest', function() {
+  /**
+   * Verifies that misuse of the writer class triggers assertions.
+   */
+  it('testWriteErrors', function() {
+    // Submessages with invalid field indices should assert.
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    assertFails(function() {
+      writer.writeMessage(-1, dummyMessage, goog.nullFunction);
+    });
+
+    // Writing invalid field indices should assert.
+    writer = new jspb.BinaryWriter();
+    assertFails(function() {writer.writeUint64(-1, 1);});
+
+    // Writing out-of-range field values should assert.
+    writer = new jspb.BinaryWriter();
+
+    assertFails(function() {writer.writeInt32(1, -Infinity);});
+    assertFails(function() {writer.writeInt32(1, Infinity);});
+
+    assertFails(function() {writer.writeInt64(1, -Infinity);});
+    assertFails(function() {writer.writeInt64(1, Infinity);});
+
+    assertFails(function() {writer.writeUint32(1, -1);});
+    assertFails(function() {writer.writeUint32(1, Infinity);});
+
+    assertFails(function() {writer.writeUint64(1, -1);});
+    assertFails(function() {writer.writeUint64(1, Infinity);});
+
+    assertFails(function() {writer.writeSint32(1, -Infinity);});
+    assertFails(function() {writer.writeSint32(1, Infinity);});
+
+    assertFails(function() {writer.writeSint64(1, -Infinity);});
+    assertFails(function() {writer.writeSint64(1, Infinity);});
+
+    assertFails(function() {writer.writeFixed32(1, -1);});
+    assertFails(function() {writer.writeFixed32(1, Infinity);});
+
+    assertFails(function() {writer.writeFixed64(1, -1);});
+    assertFails(function() {writer.writeFixed64(1, Infinity);});
+
+    assertFails(function() {writer.writeSfixed32(1, -Infinity);});
+    assertFails(function() {writer.writeSfixed32(1, Infinity);});
+
+    assertFails(function() {writer.writeSfixed64(1, -Infinity);});
+    assertFails(function() {writer.writeSfixed64(1, Infinity);});
+  });
+
+
+  /**
+   * Basic test of retrieving the result as a Uint8Array buffer
+   */
+  it('testGetResultBuffer', function() {
+    var expected = '0864120b48656c6c6f20776f726c641a0301020320c801';
+
+    var writer = new jspb.BinaryWriter();
+    writer.writeUint32(1, 100);
+    writer.writeString(2, 'Hello world');
+    writer.writeBytes(3, new Uint8Array([1, 2, 3]));
+    writer.writeUint32(4, 200);
+
+    var buffer = writer.getResultBuffer();
+    assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
+  });
+});
diff --git a/js/commonjs/export.js b/js/commonjs/export.js
new file mode 100644
index 0000000..a3cfbd6
--- /dev/null
+++ b/js/commonjs/export.js
@@ -0,0 +1,22 @@
+/**
+ * @fileoverview Export symbols needed by generated code in CommonJS style.
+ *
+ * This effectively is our canonical list of what we publicly export from
+ * the google-protobuf.js file that we build at distribution time.
+ */
+
+goog.require('goog.object');
+goog.require('jspb.BinaryReader');
+goog.require('jspb.BinaryWriter');
+goog.require('jspb.ExtensionFieldInfo');
+goog.require('jspb.Message');
+
+exports.Message = jspb.Message;
+exports.BinaryReader = jspb.BinaryReader;
+exports.BinaryWriter = jspb.BinaryWriter;
+exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
+
+// These are used by generated code but should not be used directly by clients.
+exports.exportSymbol = goog.exportSymbol;
+exports.inherits = goog.inherits;
+exports.object = {extend: goog.object.extend};
diff --git a/js/commonjs/export_asserts.js b/js/commonjs/export_asserts.js
new file mode 100644
index 0000000..5219d12
--- /dev/null
+++ b/js/commonjs/export_asserts.js
@@ -0,0 +1,37 @@
+/**
+ * @fileoverview Exports symbols needed only by tests.
+ *
+ * This file exports several Closure Library symbols that are only
+ * used by tests.  It is used to generate a file
+ * closure_asserts_commonjs.js that is only used at testing time.
+ */
+
+goog.require('goog.testing.asserts');
+
+var global = Function('return this')();
+
+// All of the closure "assert" functions are exported at the global level.
+//
+// The Google Closure assert functions start with assert, eg.
+//   assertThrows
+//   assertNotThrows
+//   assertTrue
+//   ...
+//
+// The one exception is the "fail" function.
+function shouldExport(str) {
+  return str.lastIndexOf('assert') === 0 || str == 'fail';
+}
+
+for (var key in global) {
+  if ((typeof key == "string") && global.hasOwnProperty(key) &&
+      shouldExport(key)) {
+    exports[key] = global[key];
+  }
+}
+
+// The COMPILED variable is set by Closure compiler to "true" when it compiles
+// JavaScript, so in practice this is equivalent to "exports.COMPILED = true".
+// This will disable some debugging functionality in debug.js.  We could
+// investigate whether this can/should be enabled in CommonJS builds.
+exports.COMPILED = COMPILED
diff --git a/js/commonjs/export_testdeps.js b/js/commonjs/export_testdeps.js
new file mode 100644
index 0000000..59c77ca
--- /dev/null
+++ b/js/commonjs/export_testdeps.js
@@ -0,0 +1,18 @@
+/**
+ * @fileoverview Export symbols needed by tests in CommonJS style.
+ *
+ * This file is like export.js, but for symbols that are only used by tests.
+ * However we exclude assert functions here, because they are exported into
+ * the global namespace, so those are handled as a special case in
+ * export_asserts.js.
+ */
+
+goog.require('goog.crypt.base64');
+goog.require('jspb.arith.Int64');
+goog.require('jspb.arith.UInt64');
+goog.require('jspb.BinaryEncoder');
+goog.require('jspb.BinaryDecoder');
+goog.require('jspb.utils');
+
+exports.goog = goog;
+exports.jspb = jspb;
diff --git a/js/commonjs/import_test.js b/js/commonjs/import_test.js
new file mode 100644
index 0000000..ffa34fe
--- /dev/null
+++ b/js/commonjs/import_test.js
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+
+// Test suite is written using Jasmine -- see http://jasmine.github.io/
+
+
+
+var googleProtobuf = require('google-protobuf');
+var asserts = require('closure_asserts_commonjs');
+var global = Function('return this')();
+
+// Bring asserts into the global namespace.
+googleProtobuf.object.extend(global, asserts);
+googleProtobuf.exportSymbol('jspb.Message', googleProtobuf.Message, global);
+
+var test7_pb = require('./test7/test7_pb');
+googleProtobuf.exportSymbol('proto.jspb.test.framing.FramingMessage', test7_pb.FramingMessage, global);
+
+describe('Import test suite', function() {
+  it('testImportedMessage', function() {
+    var framing1 = new proto.jspb.test.framing.FramingMessage([]);
+    var framing2 = new proto.jspb.test.framing.FramingMessage([]);
+    assertObjectEquals(framing1.toObject(), framing2.toObject());
+  });
+});
diff --git a/js/commonjs/jasmine.json b/js/commonjs/jasmine.json
new file mode 100644
index 0000000..666b8ed
--- /dev/null
+++ b/js/commonjs/jasmine.json
@@ -0,0 +1,9 @@
+{
+    "spec_dir": "",
+    "spec_files": [
+        "*_test.js",
+        "binary/proto_test.js"
+    ],
+    "helpers": [
+    ]
+}
diff --git a/js/commonjs/rewrite_tests_for_commonjs.js b/js/commonjs/rewrite_tests_for_commonjs.js
new file mode 100644
index 0000000..b6d90d2
--- /dev/null
+++ b/js/commonjs/rewrite_tests_for_commonjs.js
@@ -0,0 +1,97 @@
+/**
+ * @fileoverview Utility to translate test files to CommonJS imports.
+ *
+ * This is a somewhat hacky tool designed to do one very specific thing.
+ * All of the test files in *_test.js are written with Closure-style
+ * imports (goog.require()).  This works great for running the tests
+ * against Closure-style generated code, but we also want to run the
+ * tests against CommonJS-style generated code without having to fork
+ * the tests.
+ *
+ * Closure-style imports import each individual type by name.  This is
+ * very different than CommonJS imports which are by file.  So we put
+ * special comments in these tests like:
+ *
+ * // CommonJS-LoadFromFile: test_pb
+ * goog.require('proto.jspb.test.CloneExtension');
+ * goog.require('proto.jspb.test.Complex');
+ * goog.require('proto.jspb.test.DefaultValues');
+ *
+ * This script parses that special comment and uses it to generate proper
+ * CommonJS require() statements so that the tests can run and pass using
+ * CommonJS imports.  The script will change the above statements into:
+ *
+ *   var test_pb = require('test_pb');
+ *   googleProtobuf.exportSymbol('proto.jspb.test.CloneExtension', test_pb.CloneExtension, global);
+ *   googleProtobuf.exportSymbol('proto.jspb.test.Complex', test_pb.Complex, global);
+ *   googleProtobuf.exportSymbol('proto.jspb.test.DefaultValues', test_pb.DefaultValues, global);
+ *
+ * (The "exportSymbol" function will define the given names in the global
+ * namespace, taking care not to overwrite any previous value for
+ * "proto.jspb.test").
+ */
+
+var lineReader = require('readline').createInterface({
+  input: process.stdin,
+  output: process.stdout
+});
+
+function tryStripPrefix(str, prefix) {
+  if (str.lastIndexOf(prefix) !== 0) {
+    throw "String: " + str + " didn't start with: " + prefix;
+  }
+  return str.substr(prefix.length);
+}
+
+function camelCase(str) {
+  var ret = '';
+  var ucaseNext = false;
+  for (var i = 0; i < str.length; i++) {
+    if (str[i] == '-') {
+      ucaseNext = true;
+    } else if (ucaseNext) {
+      ret += str[i].toUpperCase();
+      ucaseNext = false;
+    } else {
+      ret += str[i];
+    }
+  }
+  return ret;
+}
+
+var module = null;
+var pkg = null;
+
+// Header: goes in every file at the top.
+console.log("var global = Function('return this')();");
+console.log("var googleProtobuf = require('google-protobuf');");
+console.log("var testdeps = require('testdeps_commonjs');");
+console.log("global.goog = testdeps.goog;");
+console.log("global.jspb = testdeps.jspb;");
+console.log("var asserts = require('closure_asserts_commonjs');");
+console.log("");
+console.log("// Bring asserts into the global namespace.");
+console.log("googleProtobuf.object.extend(global, asserts);");
+
+lineReader.on('line', function(line) {
+  var isRequire = line.match(/goog\.require\('([^']*)'\)/);
+  var isLoadFromFile = line.match(/CommonJS-LoadFromFile: (\S*) (.*)/);
+  var isSetTestOnly = line.match(/goog.setTestOnly()/);
+  if (isRequire) {
+    if (module) {  // Skip goog.require() lines before the first directive.
+      var fullSym = isRequire[1];
+      var sym = tryStripPrefix(fullSym, pkg);
+      console.log("googleProtobuf.exportSymbol('" + fullSym + "', " + module + sym + ', global);');
+    }
+  } else if (isLoadFromFile) {
+    var module_path = isLoadFromFile[1].split('/');
+    module = camelCase(module_path[module_path.length - 1]);
+    pkg = isLoadFromFile[2];
+
+    if (module != "googleProtobuf") {  // We unconditionally require this in the header.
+      console.log("var " + module + " = require('./" + isLoadFromFile[1] + "');");
+    }
+  } else if (!isSetTestOnly) {  // Remove goog.setTestOnly() lines.
+    console.log(line);
+  }
+});
diff --git a/js/commonjs/test6/test6.proto b/js/commonjs/test6/test6.proto
new file mode 100644
index 0000000..a060925
--- /dev/null
+++ b/js/commonjs/test6/test6.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+
+syntax = "proto3";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.test.importing;
+
+message ImportedMessage {
+  string string_value = 1;
+}
diff --git a/js/commonjs/test7/test7.proto b/js/commonjs/test7/test7.proto
new file mode 100644
index 0000000..f5574a3
--- /dev/null
+++ b/js/commonjs/test7/test7.proto
@@ -0,0 +1,42 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+
+syntax = "proto3";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.test.framing;
+
+import "test6/test6.proto";
+
+message FramingMessage {
+  jspb.test.importing.ImportedMessage imported_message = 1;
+}
diff --git a/js/data.proto b/js/data.proto
new file mode 100644
index 0000000..74a8a99
--- /dev/null
+++ b/js/data.proto
@@ -0,0 +1,51 @@
+// 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.
+
+// Author: mwr@google.com (Mark Rawling)
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.test;
+
+// legacy data, must be nested
+message data {
+  message NestedData {
+    required string str = 1;
+  }
+}
+
+// new data, does not require nesting
+message UnnestedData {
+  required string str = 1;
+}
+
diff --git a/js/debug.js b/js/debug.js
new file mode 100644
index 0000000..3701a09
--- /dev/null
+++ b/js/debug.js
@@ -0,0 +1,140 @@
+// 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.
+
+/**
+ * @fileoverview Utilities to debug JSPB based proto objects.
+ */
+
+goog.provide('jspb.debug');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.object');
+goog.require('jspb.Message');
+
+
+/**
+ * Turns a proto into a human readable object that can i.e. be written to the
+ * console: {@code console.log(jspb.debug.dump(myProto))}.
+ * This function makes a best effort and may not work in all cases. It will not
+ * work in obfuscated and or optimized code.
+ * Use this in environments where {@see jspb.Message.prototype.toObject} is
+ * not available for code size reasons.
+ * @param {jspb.Message} message A jspb.Message.
+ * @return {Object}
+ */
+jspb.debug.dump = function(message) {
+  if (!goog.DEBUG) {
+    return null;
+  }
+  goog.asserts.assert(message instanceof jspb.Message,
+      'jspb.Message instance expected');
+  /** @type {Object} */
+  var object = message;
+  goog.asserts.assert(object['getExtension'],
+      'Only unobfuscated and unoptimized compilation modes supported.');
+  return /** @type {Object} */ (jspb.debug.dump_(message));
+};
+
+
+/**
+ * Recursively introspects a message and the values its getters return to
+ * make a best effort in creating a human readable representation of the
+ * message.
+ * @param {?} thing A jspb.Message, Array or primitive type to dump.
+ * @return {*}
+ * @private
+ */
+jspb.debug.dump_ = function(thing) {
+  var type = goog.typeOf(thing);
+  if (type == 'number' || type == 'string' || type == 'boolean' ||
+      type == 'null' || type == 'undefined') {
+    return thing;
+  }
+  if (type == 'array') {
+    goog.asserts.assertArray(thing);
+    return goog.array.map(thing, jspb.debug.dump_);
+  }
+  var message = thing;  // Copy because we don't want type inference on thing.
+  goog.asserts.assert(message instanceof jspb.Message,
+      'Only messages expected: ' + thing);
+  var ctor = message.constructor;
+  var messageName = ctor.name || ctor.displayName;
+  var object = {
+    '$name': messageName
+  };
+  for (var name in ctor.prototype) {
+    var match = /^get([A-Z]\w*)/.exec(name);
+    if (match && name != 'getExtension' &&
+        name != 'getJsPbMessageId') {
+      var val = thing[name]();
+      if (val != null) {
+        object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val);
+      }
+    }
+  }
+  if (COMPILED && thing['extensionObject_']) {
+    object['$extensions'] = 'Recursive dumping of extensions not supported ' +
+        'in compiled code. Switch to uncompiled or dump extension object ' +
+        'directly';
+    return object;
+  }
+  var extensionsObject;
+  for (var id in ctor['extensions']) {
+    if (/^\d+$/.test(id)) {
+      var ext = ctor['extensions'][id];
+      var extVal = thing.getExtension(ext);
+      var fieldName = goog.object.getKeys(ext.fieldName)[0];
+      if (extVal != null) {
+        if (!extensionsObject) {
+          extensionsObject = object['$extensions'] = {};
+        }
+        extensionsObject[jspb.debug.formatFieldName_(fieldName)] =
+            jspb.debug.dump_(extVal);
+      }
+    }
+  }
+  return object;
+};
+
+
+/**
+ * Formats a field name for output as camelCase.
+ *
+ * @param {string} name Name of the field.
+ * @return {string}
+ * @private
+ */
+jspb.debug.formatFieldName_ = function(name) {
+  // Name may be in TitleCase.
+  return name.replace(/^[A-Z]/, function(c) {
+    return c.toLowerCase();
+  });
+};
diff --git a/js/debug_test.js b/js/debug_test.js
new file mode 100644
index 0000000..01cbf89
--- /dev/null
+++ b/js/debug_test.js
@@ -0,0 +1,105 @@
+// 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.
+
+goog.setTestOnly();
+
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: google-protobuf
+goog.require('jspb.debug');
+
+// CommonJS-LoadFromFile: test_pb
+goog.require('proto.jspb.test.HasExtensions');
+goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.Simple1');
+
+
+
+describe('debugTest', function() {
+  it('testSimple1', function() {
+    if (COMPILED) {
+      return;
+    }
+    var message = new proto.jspb.test.Simple1();
+    message.setAString('foo');
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aString': 'foo',
+      'aRepeatedStringList': []
+    }, jspb.debug.dump(message));
+
+    message.setABoolean(true);
+    message.setARepeatedStringList(['1', '2']);
+
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aString': 'foo',
+      'aRepeatedStringList': ['1', '2'],
+      'aBoolean': true
+    }, jspb.debug.dump(message));
+
+    message.setAString(undefined);
+
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aRepeatedStringList': ['1', '2'],
+      'aBoolean': true
+    }, jspb.debug.dump(message));
+  });
+
+
+  it('testExtensions', function() {
+    if (COMPILED) {
+      return;
+    }
+    var extension = new proto.jspb.test.IsExtension();
+    extension.setExt1('ext1field');
+    var extendable = new proto.jspb.test.HasExtensions();
+    extendable.setStr1('v1');
+    extendable.setStr2('v2');
+    extendable.setStr3('v3');
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension);
+
+    assertObjectEquals({
+      '$name': 'proto.jspb.test.HasExtensions',
+      'str1': 'v1',
+      'str2': 'v2',
+      'str3': 'v3',
+      '$extensions': {
+        'extField': {
+          '$name': 'proto.jspb.test.IsExtension',
+          'ext1': 'ext1field'
+        },
+        'repeatedSimpleList': []
+      }
+    }, jspb.debug.dump(extendable));
+  });
+
+});
diff --git a/js/gulpfile.js b/js/gulpfile.js
new file mode 100644
index 0000000..c522015
--- /dev/null
+++ b/js/gulpfile.js
@@ -0,0 +1,110 @@
+var gulp = require('gulp');
+var execFile = require('child_process').execFile;
+var glob = require('glob');
+
+function exec(command, cb) {
+  execFile('sh', ['-c', command], cb);
+}
+
+var protoc = process.env.PROTOC || '../src/protoc';
+
+gulp.task('genproto_closure', function (cb) {
+  exec(protoc + ' --js_out=library=testproto_libs,binary:.  -I ../src -I . *.proto ../src/google/protobuf/descriptor.proto',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('genproto_commonjs', function (cb) {
+  exec('mkdir -p commonjs_out && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out -I ../src -I commonjs -I . *.proto commonjs/test*/*.proto ../src/google/protobuf/descriptor.proto',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('dist', function (cb) {
+  // TODO(haberman): minify this more aggressively.
+  // Will require proper externs/exports.
+  exec('./node_modules/google-closure-library/closure/bin/calcdeps.py -i message.js -i binary/reader.js -i binary/writer.js -i commonjs/export.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > google-protobuf.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('commonjs_asserts', function (cb) {
+  exec('mkdir -p commonjs_out/test_node_modules && ./node_modules/google-closure-library/closure/bin/calcdeps.py -i commonjs/export_asserts.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > commonjs_out/test_node_modules/closure_asserts_commonjs.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('commonjs_testdeps', function (cb) {
+  exec('mkdir -p commonjs_out/test_node_modules && ./node_modules/google-closure-library/closure/bin/calcdeps.py -i commonjs/export_testdeps.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > commonjs_out/test_node_modules/testdeps_commonjs.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('make_commonjs_out', ['dist', 'genproto_commonjs', 'commonjs_asserts', 'commonjs_testdeps'], function (cb) {
+  // TODO(haberman): minify this more aggressively.
+  // Will require proper externs/exports.
+  var cmd = "mkdir -p commonjs_out/binary && mkdir -p commonjs_out/test_node_modules && ";
+  function addTestFile(file) {
+    cmd += 'node commonjs/rewrite_tests_for_commonjs.js < ' + file +
+           ' > commonjs_out/' + file + '&& ';
+  }
+
+  glob.sync('*_test.js').forEach(addTestFile);
+  glob.sync('binary/*_test.js').forEach(addTestFile);
+
+  exec(cmd +
+       'cp commonjs/jasmine.json commonjs_out/jasmine.json && ' +
+       'cp google-protobuf.js commonjs_out/test_node_modules && ' +
+       'cp commonjs/import_test.js commonjs_out/import_test.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('deps', ['genproto_closure'], function (cb) {
+  exec('./node_modules/google-closure-library/closure/bin/build/depswriter.py *.js binary/*.js > deps.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test_closure', ['genproto_closure', 'deps'], function (cb) {
+  exec('JASMINE_CONFIG_PATH=jasmine.json ./node_modules/.bin/jasmine',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test_commonjs', ['make_commonjs_out'], function (cb) {
+  exec('cd commonjs_out && JASMINE_CONFIG_PATH=jasmine.json NODE_PATH=test_node_modules ../node_modules/.bin/jasmine',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test', ['test_closure', 'test_commonjs'], function(cb) {
+  cb();
+});
diff --git a/js/jasmine.json b/js/jasmine.json
new file mode 100644
index 0000000..f83c54c
--- /dev/null
+++ b/js/jasmine.json
@@ -0,0 +1,12 @@
+{
+    "spec_dir": "",
+    "spec_files": [
+        "*_test.js",
+        "binary/*_test.js"
+    ],
+    "helpers": [
+        "node_modules/google-closure-library/closure/goog/bootstrap/nodejs.js",
+        "node_loader.js",
+        "deps.js"
+    ]
+}
diff --git a/js/message.js b/js/message.js
new file mode 100644
index 0000000..813e6b8
--- /dev/null
+++ b/js/message.js
@@ -0,0 +1,1337 @@
+// 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.
+
+/**
+ * @fileoverview Definition of jspb.Message.
+ *
+ * @author mwr@google.com (Mark Rawling)
+ */
+
+goog.provide('jspb.ExtensionFieldInfo');
+goog.provide('jspb.Message');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.crypt.base64');
+goog.require('goog.json');
+
+// Not needed in compilation units that have no protos with xids.
+goog.forwardDeclare('xid.String');
+
+
+
+/**
+ * Stores information for a single extension field.
+ *
+ * For example, an extension field defined like so:
+ *
+ *     extend BaseMessage {
+ *       optional MyMessage my_field = 123;
+ *     }
+ *
+ * will result in an ExtensionFieldInfo object with these properties:
+ *
+ *     {
+ *       fieldIndex: 123,
+ *       fieldName: {my_field_renamed: 0},
+ *       ctor: proto.example.MyMessage,
+ *       toObjectFn: proto.example.MyMessage.toObject,
+ *       isRepeated: 0
+ *     }
+ *
+ * We include `toObjectFn` to allow the JSCompiler to perform dead-code removal
+ * on unused toObject() methods.
+ *
+ * If an extension field is primitive, ctor and toObjectFn will be null.
+ * isRepeated should be 0 or 1.
+ *
+ * binary{Reader,Writer}Fn and (if message type) binaryMessageSerializeFn are
+ * always provided. binaryReaderFn and binaryWriterFn are references to the
+ * appropriate methods on BinaryReader/BinaryWriter to read/write the value of
+ * this extension, and binaryMessageSerializeFn is a reference to the message
+ * class's .serializeBinary method, if available.
+ *
+ * @param {number} fieldNumber
+ * @param {Object} fieldName This has the extension field name as a property.
+ * @param {?function(new: jspb.Message, Array=)} ctor
+ * @param {?function((boolean|undefined),!jspb.Message):!Object} toObjectFn
+ * @param {number} isRepeated
+ * @param {?function(number,?)=} opt_binaryReaderFn
+ * @param {?function(number,?)|function(number,?,?,?,?,?)=} opt_binaryWriterFn
+ * @param {?function(?,?)=} opt_binaryMessageSerializeFn
+ * @param {?function(?,?)=} opt_binaryMessageDeserializeFn
+ * @param {?boolean=} opt_isPacked
+ * @constructor
+ * @struct
+ * @template T
+ */
+jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
+    isRepeated, opt_binaryReaderFn, opt_binaryWriterFn,
+    opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn,
+    opt_isPacked) {
+  /** @const */
+  this.fieldIndex = fieldNumber;
+  /** @const */
+  this.fieldName = fieldName;
+  /** @const */
+  this.ctor = ctor;
+  /** @const */
+  this.toObjectFn = toObjectFn;
+  /** @const */
+  this.binaryReaderFn = opt_binaryReaderFn;
+  /** @const */
+  this.binaryWriterFn = opt_binaryWriterFn;
+  /** @const */
+  this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn;
+  /** @const */
+  this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn;
+  /** @const */
+  this.isRepeated = isRepeated;
+  /** @const */
+  this.isPacked = opt_isPacked;
+};
+
+
+/**
+ * @return {boolean} Does this field represent a sub Message?
+ */
+jspb.ExtensionFieldInfo.prototype.isMessageType = function() {
+  return !!this.ctor;
+};
+
+
+/**
+ * Base class for all JsPb messages.
+ * @constructor
+ * @struct
+ */
+jspb.Message = function() {
+};
+
+
+/**
+ * @define {boolean} Whether to generate toObject methods for objects. Turn
+ *     this off, if you do not want toObject to be ever used in your project.
+ *     When turning off this flag, consider adding a conformance test that bans
+ *     calling toObject. Enabling this will disable the JSCompiler's ability to
+ *     dead code eliminate fields used in protocol buffers that are never used
+ *     in an application.
+ */
+goog.define('jspb.Message.GENERATE_TO_OBJECT', true);
+
+
+/**
+ * @define {boolean} Whether to generate fromObject methods for objects. Turn
+ *     this off, if you do not want fromObject to be ever used in your project.
+ *     When turning off this flag, consider adding a conformance test that bans
+ *     calling fromObject. Enabling this might disable the JSCompiler's ability
+ *     to dead code eliminate fields used in protocol buffers that are never
+ *     used in an application.
+ *     NOTE: By default no protos actually have a fromObject method. You need to
+ *     add the jspb.generate_from_object options to the proto definition to
+ *     activate the feature.
+ *     By default this is enabled for test code only.
+ */
+goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
+
+
+/**
+ * @define {boolean} Turning on this flag does NOT change the behavior of JSPB
+ *     and only affects private internal state. It may, however, break some
+ *     tests that use naive deeply-equals algorithms, because using a proto
+ *     mutates its internal state.
+ *     Projects are advised to turn this flag always on.
+ */
+goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', COMPILED);
+// TODO(b/19419436) Turn this on by default.
+
+
+/**
+ * Does this browser support Uint8Aray typed arrays?
+ * @type {boolean}
+ * @private
+ */
+jspb.Message.SUPPORTS_UINT8ARRAY_ = (typeof Uint8Array == 'function');
+
+
+/**
+ * The internal data array.
+ * @type {!Array}
+ * @protected
+ */
+jspb.Message.prototype.array;
+
+
+/**
+ * Wrappers are the constructed instances of message-type fields. They are built
+ * on demand from the raw array data. Includes message fields, repeated message
+ * fields and extension message fields. Indexed by field number.
+ * @type {Object}
+ * @private
+ */
+jspb.Message.prototype.wrappers_;
+
+
+/**
+ * The object that contains extension fields, if any. This is an object that
+ * maps from a proto field number to the field's value.
+ * @type {Object}
+ * @private
+ */
+jspb.Message.prototype.extensionObject_;
+
+
+/**
+ * Non-extension fields with a field number at or above the pivot are
+ * stored in the extension object (in addition to all extension fields).
+ * @type {number}
+ * @private
+ */
+jspb.Message.prototype.pivot_;
+
+
+/**
+ * The JsPb message_id of this proto.
+ * @type {string|undefined} the message id or undefined if this message
+ *     has no id.
+ * @private
+ */
+jspb.Message.prototype.messageId_;
+
+
+/**
+ * Repeated float or double fields which have been converted to include only
+ * numbers and not strings holding "NaN", "Infinity" and "-Infinity".
+ * @private {!Object<number,boolean>|undefined}
+ */
+jspb.Message.prototype.convertedFloatingPointFields_;
+
+
+/**
+ * The xid of this proto type (The same for all instances of a proto). Provides
+ * a way to identify a proto by stable obfuscated name.
+ * @see {xid}.
+ * Available if {@link jspb.generate_xid} is added as a Message option to
+ * a protocol buffer.
+ * @const {!xid.String|undefined} The xid or undefined if message is
+ *     annotated to generate the xid.
+ */
+jspb.Message.prototype.messageXid;
+
+
+
+/**
+ * Returns the JsPb message_id of this proto.
+ * @return {string|undefined} the message id or undefined if this message
+ *     has no id.
+ */
+jspb.Message.prototype.getJsPbMessageId = function() {
+  return this.messageId_;
+};
+
+
+/**
+ * An offset applied to lookups into this.array to account for the presence or
+ * absence of a messageId at position 0. For response messages, this will be 0.
+ * Otherwise, it will be -1 so that the first array position is not wasted.
+ * @type {number}
+ * @private
+ */
+jspb.Message.prototype.arrayIndexOffset_;
+
+
+/**
+ * Returns the index into msg.array at which the proto field with tag number
+ * fieldNumber will be located.
+ * @param {!jspb.Message} msg Message for which we're calculating an index.
+ * @param {number} fieldNumber The field number.
+ * @return {number} The index.
+ * @private
+ */
+jspb.Message.getIndex_ = function(msg, fieldNumber) {
+  return fieldNumber + msg.arrayIndexOffset_;
+};
+
+
+/**
+ * Initializes a JsPb Message.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @param {Array|undefined} data An initial data array.
+ * @param {string|number} messageId For response messages, the message id or ''
+ *     if no message id is specified. For non-response messages, 0.
+ * @param {number} suggestedPivot The field number at which to start putting
+ *     fields into the extension object. This is only used if data does not
+ *     contain an extension object already. -1 if no extension object is
+ *     required for this message type.
+ * @param {Array<number>} repeatedFields The message's repeated fields.
+ * @param {Array<!Array<number>>=} opt_oneofFields The fields belonging to
+ *     each of the message's oneof unions.
+ * @protected
+ */
+jspb.Message.initialize = function(
+    msg, data, messageId, suggestedPivot, repeatedFields, opt_oneofFields) {
+  msg.wrappers_ = jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ? null : {};
+  if (!data) {
+    data = messageId ? [messageId] : [];
+  }
+  msg.messageId_ = messageId ? String(messageId) : undefined;
+  // If the messageId is 0, this message is not a response message, so we shift
+  // array indices down by 1 so as not to waste the first position in the array,
+  // which would otherwise go unused.
+  msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0;
+  msg.array = data;
+  jspb.Message.materializeExtensionObject_(msg, suggestedPivot);
+  msg.convertedFloatingPointFields_ = {};
+
+  if (repeatedFields) {
+    for (var i = 0; i < repeatedFields.length; i++) {
+      var fieldNumber = repeatedFields[i];
+      if (fieldNumber < msg.pivot_) {
+        var index = jspb.Message.getIndex_(msg, fieldNumber);
+        msg.array[index] = msg.array[index] ||
+            (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
+                jspb.Message.EMPTY_LIST_SENTINEL_ :
+                []);
+      } else {
+        msg.extensionObject_[fieldNumber] =
+            msg.extensionObject_[fieldNumber] ||
+            (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
+                jspb.Message.EMPTY_LIST_SENTINEL_ :
+                []);
+      }
+    }
+  }
+
+  if (opt_oneofFields && opt_oneofFields.length) {
+    // Compute the oneof case for each union. This ensures only one value is
+    // set in the union.
+    goog.array.forEach(
+        opt_oneofFields, goog.partial(jspb.Message.computeOneofCase, msg));
+  }
+};
+
+
+/**
+ * Used to mark empty repeated fields. Serializes to null when serialized
+ * to JSON.
+ * When reading a repeated field readers must check the return value against
+ * this value and return and replace it with a new empty array if it is
+ * present.
+ * @private @const {!Object}
+ */
+jspb.Message.EMPTY_LIST_SENTINEL_ = goog.DEBUG && Object.freeze ?
+    Object.freeze([]) :
+    [];
+
+
+/**
+ * Ensures that the array contains an extension object if necessary.
+ * If the array contains an extension object in its last position, then the
+ * object is kept in place and its position is used as the pivot.  If not, then
+ * create an extension object using suggestedPivot.  If suggestedPivot is -1,
+ * we don't have an extension object at all, in which case all fields are stored
+ * in the array.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @param {number} suggestedPivot See description for initialize().
+ * @private
+ */
+jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) {
+  if (msg.array.length) {
+    var foundIndex = msg.array.length - 1;
+    var obj = msg.array[foundIndex];
+    // Normal fields are never objects, so we can be sure that if we find an
+    // object here, then it's the extension object. However, we must ensure that
+    // the object is not an array, since arrays are valid field values.
+    // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
+    // in Safari on iOS 8. See the description of CL/86511464 for details.
+    if (obj && typeof obj == 'object' && !goog.isArray(obj)) {
+      msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
+      msg.extensionObject_ = obj;
+      return;
+    }
+  }
+  // This complexity exists because we keep all extension fields in the
+  // extensionObject_ regardless of proto field number. Changing this would
+  // simplify the code here, but it would require changing the serialization
+  // format from the server, which is not backwards compatible.
+  // TODO(jshneier): Should we just treat extension fields the same as
+  // non-extension fields, and select whether they appear in the object or in
+  // the array purely based on tag number? This would allow simplifying all the
+  // get/setExtension logic, but it would require the breaking change described
+  // above.
+  if (suggestedPivot > -1) {
+    msg.pivot_ = suggestedPivot;
+    var pivotIndex = jspb.Message.getIndex_(msg, suggestedPivot);
+    if (!jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) {
+      msg.extensionObject_ = msg.array[pivotIndex] = {};
+    } else {
+      // Initialize to null to avoid changing the shape of the proto when it
+      // gets eventually set.
+      msg.extensionObject_ = null;
+    }
+  } else {
+    msg.pivot_ = Number.MAX_VALUE;
+  }
+};
+
+
+/**
+ * Creates an empty extensionObject_ if non exists.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @private
+ */
+jspb.Message.maybeInitEmptyExtensionObject_ = function(msg) {
+  var pivotIndex = jspb.Message.getIndex_(msg, msg.pivot_);
+  if (!msg.array[pivotIndex]) {
+    msg.extensionObject_ = msg.array[pivotIndex] = {};
+  }
+};
+
+
+/**
+ * Converts a JsPb repeated message field into an object list.
+ * @param {!Array<T>} field The repeated message field to be
+ *     converted.
+ * @param {?function(boolean=): Object|
+ *     function((boolean|undefined),T): Object} toObjectFn The toObject
+ *     function for this field.  We need to pass this for effective dead code
+ *     removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Array<Object>} An array of converted message objects.
+ * @template T
+ */
+jspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) {
+  // Not using goog.array.map in the generated code to keep it small.
+  // And not using it here to avoid a function call.
+  var result = [];
+  for (var i = 0; i < field.length; i++) {
+    result[i] = toObjectFn.call(field[i], opt_includeInstance,
+      /** @type {!jspb.Message} */ (field[i]));
+  }
+  return result;
+};
+
+
+/**
+ * Adds a proto's extension data to a Soy rendering object.
+ * @param {!jspb.Message} proto The proto whose extensions to convert.
+ * @param {!Object} obj The Soy object to add converted extension data to.
+ * @param {!Object} extensions The proto class' registered extensions.
+ * @param {function(this:?, jspb.ExtensionFieldInfo) : *} getExtensionFn
+ *     The proto class' getExtension function. Passed for effective dead code
+ *     removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ */
+jspb.Message.toObjectExtension = function(proto, obj, extensions,
+    getExtensionFn, opt_includeInstance) {
+  for (var fieldNumber in extensions) {
+    var fieldInfo = extensions[fieldNumber];
+    var value = getExtensionFn.call(proto, fieldInfo);
+    if (value) {
+      for (var name in fieldInfo.fieldName) {
+        if (fieldInfo.fieldName.hasOwnProperty(name)) {
+          break; // the compiled field name
+        }
+      }
+      if (!fieldInfo.toObjectFn) {
+        obj[name] = value;
+      } else {
+        if (fieldInfo.isRepeated) {
+          obj[name] = jspb.Message.toObjectList(
+              /** @type {!Array<jspb.Message>} */ (value),
+              fieldInfo.toObjectFn, opt_includeInstance);
+        } else {
+          obj[name] = fieldInfo.toObjectFn(opt_includeInstance, value);
+        }
+      }
+    }
+  }
+};
+
+
+/**
+ * Writes a proto's extension data to a binary-format output stream.
+ * @param {!jspb.Message} proto The proto whose extensions to convert.
+ * @param {*} writer The binary-format writer to write to.
+ * @param {!Object} extensions The proto class' registered extensions.
+ * @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
+ *     class' getExtension function. Passed for effective dead code removal.
+ */
+jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
+    getExtensionFn) {
+  for (var fieldNumber in extensions) {
+    var fieldInfo = extensions[fieldNumber];
+    // The old codegen doesn't add the extra fields to ExtensionFieldInfo, so we
+    // need to gracefully error-out here rather than produce a null dereference
+    // below.
+    if (!fieldInfo.binaryWriterFn) {
+      throw new Error('Message extension present that was generated ' +
+                      'without binary serialization support');
+    }
+    var value = getExtensionFn.call(proto, fieldInfo);
+    if (value) {
+      if (fieldInfo.isMessageType()) {
+        // If the message type of the extension was generated without binary
+        // support, there may not be a binary message serializer function, and
+        // we can't know when we codegen the extending message that the extended
+        // message may require binary support, so we can *only* catch this error
+        // here, at runtime (and this decoupled codegen is the whole point of
+        // extensions!).
+        if (fieldInfo.binaryMessageSerializeFn) {
+          fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
+              value, fieldInfo.binaryMessageSerializeFn);
+        } else {
+          throw new Error('Message extension present holding submessage ' +
+                          'without binary support enabled, and message is ' +
+                          'being serialized to binary format');
+        }
+      } else {
+        fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex, value);
+      }
+    }
+  }
+};
+
+
+/**
+ * Reads an extension field from the given reader and, if a valid extension,
+ * sets the extension value.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {{skipField:function(),getFieldNumber:function():number}} reader
+ * @param {!Object} extensions The extensions object.
+ * @param {function(jspb.ExtensionFieldInfo)} getExtensionFn
+ * @param {function(jspb.ExtensionFieldInfo, ?)} setExtensionFn
+ */
+jspb.Message.readBinaryExtension = function(msg, reader, extensions,
+    getExtensionFn, setExtensionFn) {
+  var fieldInfo = extensions[reader.getFieldNumber()];
+  if (!fieldInfo) {
+    reader.skipField();
+    return;
+  }
+  if (!fieldInfo.binaryReaderFn) {
+    throw new Error('Deserializing extension whose generated code does not ' +
+                    'support binary format');
+  }
+
+  var value;
+  if (fieldInfo.isMessageType()) {
+    value = new fieldInfo.ctor();
+    fieldInfo.binaryReaderFn.call(
+        reader, value, fieldInfo.binaryMessageDeserializeFn);
+  } else {
+    // All other types.
+    value = fieldInfo.binaryReaderFn.call(reader);
+  }
+
+  if (fieldInfo.isRepeated && !fieldInfo.isPacked) {
+    var currentList = getExtensionFn.call(msg, fieldInfo);
+    if (!currentList) {
+      setExtensionFn.call(msg, fieldInfo, [value]);
+    } else {
+      currentList.push(value);
+    }
+  } else {
+    setExtensionFn.call(msg, fieldInfo, value);
+  }
+};
+
+
+/**
+ * Gets the value of a non-extension field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {string|number|boolean|Uint8Array|Array|null|undefined}
+ * The field's value.
+ * @protected
+ */
+jspb.Message.getField = function(msg, fieldNumber) {
+  if (fieldNumber < msg.pivot_) {
+    var index = jspb.Message.getIndex_(msg, fieldNumber);
+    var val = msg.array[index];
+    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
+      return msg.array[index] = [];
+    }
+    return val;
+  } else {
+    var val = msg.extensionObject_[fieldNumber];
+    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
+      return msg.extensionObject_[fieldNumber] = [];
+    }
+    return val;
+  }
+};
+
+
+/**
+ * Gets the value of an optional float or double field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {?number|undefined} The field's value.
+ * @protected
+ */
+jspb.Message.getOptionalFloatingPointField = function(msg, fieldNumber) {
+  var value = jspb.Message.getField(msg, fieldNumber);
+  // Converts "NaN", "Infinity" and "-Infinity" to their corresponding numbers.
+  return value == null ? value : +value;
+};
+
+
+/**
+ * Gets the value of a repeated float or double field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {!Array<number>} The field's value.
+ * @protected
+ */
+jspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) {
+  var values = jspb.Message.getField(msg, fieldNumber);
+  if (!msg.convertedFloatingPointFields_) {
+    msg.convertedFloatingPointFields_ = {};
+  }
+  if (!msg.convertedFloatingPointFields_[fieldNumber]) {
+    for (var i = 0; i < values.length; i++) {
+      // Converts "NaN", "Infinity" and "-Infinity" to their corresponding
+      // numbers.
+      values[i] = +values[i];
+    }
+    msg.convertedFloatingPointFields_[fieldNumber] = true;
+  }
+  return /** @type {!Array<number>} */ (values);
+};
+
+
+/**
+ * Coerce a 'bytes' field to a base 64 string.
+ * @param {string|Uint8Array|null} value
+ * @return {?string} The field's coerced value.
+ */
+jspb.Message.bytesAsB64 = function(value) {
+  if (value == null || goog.isString(value)) {
+    return value;
+  }
+  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && value instanceof Uint8Array) {
+    return goog.crypt.base64.encodeByteArray(value);
+  }
+  goog.asserts.fail('Cannot coerce to b64 string: ' + goog.typeOf(value));
+  return null;
+};
+
+
+/**
+ * Coerce a 'bytes' field to a Uint8Array byte buffer.
+ * Note that Uint8Array is not supported on IE versions before 10 nor on Opera
+ * Mini. @see http://caniuse.com/Uint8Array
+ * @param {string|Uint8Array|null} value
+ * @return {?Uint8Array} The field's coerced value.
+ */
+jspb.Message.bytesAsU8 = function(value) {
+  if (value == null || value instanceof Uint8Array) {
+    return value;
+  }
+  if (goog.isString(value)) {
+    return goog.crypt.base64.decodeStringToUint8Array(value);
+  }
+  goog.asserts.fail('Cannot coerce to Uint8Array: ' + goog.typeOf(value));
+  return null;
+};
+
+
+/**
+ * Coerce a repeated 'bytes' field to an array of base 64 strings.
+ * Note: the returned array should be treated as immutable.
+ * @param {!Array<string>|!Array<!Uint8Array>} value
+ * @return {!Array<string?>} The field's coerced value.
+ */
+jspb.Message.bytesListAsB64 = function(value) {
+  jspb.Message.assertConsistentTypes_(value);
+  if (!value.length || goog.isString(value[0])) {
+    return /** @type {!Array<string>} */ (value);
+  }
+  return goog.array.map(value, jspb.Message.bytesAsB64);
+};
+
+
+/**
+ * Coerce a repeated 'bytes' field to an array of Uint8Array byte buffers.
+ * Note: the returned array should be treated as immutable.
+ * Note that Uint8Array is not supported on IE versions before 10 nor on Opera
+ * Mini. @see http://caniuse.com/Uint8Array
+ * @param {!Array<string>|!Array<!Uint8Array>} value
+ * @return {!Array<Uint8Array?>} The field's coerced value.
+ */
+jspb.Message.bytesListAsU8 = function(value) {
+  jspb.Message.assertConsistentTypes_(value);
+  if (!value.length || value[0] instanceof Uint8Array) {
+    return /** @type {!Array<!Uint8Array>} */ (value);
+  }
+  return goog.array.map(value, jspb.Message.bytesAsU8);
+};
+
+
+/**
+ * Asserts that all elements of an array are of the same type.
+ * @param {Array?} array The array to test.
+ * @private
+ */
+jspb.Message.assertConsistentTypes_ = function(array) {
+  if (goog.DEBUG && array && array.length > 1) {
+    var expected = goog.typeOf(array[0]);
+    goog.array.forEach(array, function(e) {
+      if (goog.typeOf(e) != expected) {
+        goog.asserts.fail('Inconsistent type in JSPB repeated field array. ' +
+            'Got ' + goog.typeOf(e) + ' expected ' + expected);
+      }
+    });
+  }
+};
+
+
+/**
+ * Gets the value of a non-extension primitive field, with proto3 (non-nullable
+ * primitives) semantics. Returns `defaultValue` if the field is not otherwise
+ * set.
+ * @template T
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {T} defaultValue The default value.
+ * @return {T} The field's value.
+ * @protected
+ */
+jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
+  var value = jspb.Message.getField(msg, fieldNumber);
+  if (value == null) {
+    return defaultValue;
+  } else {
+    return value;
+  }
+};
+
+
+/**
+ * Sets the value of a non-extension field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @protected
+ */
+jspb.Message.setField = function(msg, fieldNumber, value) {
+  if (fieldNumber < msg.pivot_) {
+    msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value;
+  } else {
+    msg.extensionObject_[fieldNumber] = value;
+  }
+};
+
+
+/**
+ * Sets the value of a field in a oneof union and clears all other fields in
+ * the union.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {!Array<number>} oneof The fields belonging to the union.
+ * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @protected
+ */
+jspb.Message.setOneofField = function(msg, fieldNumber, oneof, value) {
+  var currentCase = jspb.Message.computeOneofCase(msg, oneof);
+  if (currentCase && currentCase !== fieldNumber && value !== undefined) {
+    if (msg.wrappers_ && currentCase in msg.wrappers_) {
+      msg.wrappers_[currentCase] = undefined;
+    }
+    jspb.Message.setField(msg, currentCase, undefined);
+  }
+  jspb.Message.setField(msg, fieldNumber, value);
+};
+
+
+/**
+ * Computes the selection in a oneof group for the given message, ensuring
+ * only one field is set in the process.
+ *
+ * According to the protobuf language guide (
+ * https://developers.google.com/protocol-buffers/docs/proto#oneof), "if the
+ * parser encounters multiple members of the same oneof on the wire, only the
+ * last member seen is used in the parsed message." Since JSPB serializes
+ * messages to a JSON array, the "last member seen" will always be the field
+ * with the greatest field number (directly corresponding to the greatest
+ * array index).
+ *
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {!Array<number>} oneof The field numbers belonging to the union.
+ * @return {number} The field number currently set in the union, or 0 if none.
+ * @protected
+ */
+jspb.Message.computeOneofCase = function(msg, oneof) {
+  var oneofField;
+  var oneofValue;
+
+  goog.array.forEach(oneof, function(fieldNumber) {
+    var value = jspb.Message.getField(msg, fieldNumber);
+    if (goog.isDefAndNotNull(value)) {
+      oneofField = fieldNumber;
+      oneofValue = value;
+      jspb.Message.setField(msg, fieldNumber, undefined);
+    }
+  });
+
+  if (oneofField) {
+    // NB: We know the value is unique, so we can call jspb.Message.setField
+    // directly instead of jpsb.Message.setOneofField. Also, setOneofField
+    // calls this function.
+    jspb.Message.setField(msg, oneofField, oneofValue);
+    return oneofField;
+  }
+
+  return 0;
+};
+
+
+/**
+ * Gets and wraps a proto field on access.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
+ * @param {number} fieldNumber The field number.
+ * @param {number=} opt_required True (1) if this is a required field.
+ * @return {jspb.Message} The field as a jspb proto.
+ * @protected
+ */
+jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
+  // TODO(mwr): Consider copying data and/or arrays.
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  if (!msg.wrappers_[fieldNumber]) {
+    var data = /** @type {Array} */ (jspb.Message.getField(msg, fieldNumber));
+    if (opt_required || data) {
+      // TODO(mwr): Remove existence test for always valid default protos.
+      msg.wrappers_[fieldNumber] = new ctor(data);
+    }
+  }
+  return /** @type {jspb.Message} */ (msg.wrappers_[fieldNumber]);
+};
+
+
+/**
+ * Gets and wraps a repeated proto field on access.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
+ * @param {number} fieldNumber The field number.
+ * @return {Array<!jspb.Message>} The repeated field as an array of protos.
+ * @protected
+ */
+jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  if (!msg.wrappers_[fieldNumber]) {
+    var data = jspb.Message.getField(msg, fieldNumber);
+    for (var wrappers = [], i = 0; i < data.length; i++) {
+      wrappers[i] = new ctor(data[i]);
+    }
+    msg.wrappers_[fieldNumber] = wrappers;
+  }
+  var val = msg.wrappers_[fieldNumber];
+  if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
+    val = msg.wrappers_[fieldNumber] = [];
+  }
+  return /** @type {Array<!jspb.Message>} */ (val);
+};
+
+
+/**
+ * Sets a proto field and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @protected
+ */
+jspb.Message.setWrapperField = function(msg, fieldNumber, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  var data = value ? value.toArray() : value;
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setField(msg, fieldNumber, data);
+};
+
+
+/**
+ * Sets a proto field in a oneof union and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {!Array<number>} oneof The fields belonging to the union.
+ * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @protected
+ */
+jspb.Message.setOneofWrapperField = function(msg, fieldNumber, oneof, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  var data = value ? value.toArray() : value;
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setOneofField(msg, fieldNumber, oneof, data);
+};
+
+
+/**
+ * Sets a repeated proto field and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {Array<!jspb.Message>|undefined} value An array of protos.
+ * @protected
+ */
+jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  value = value || [];
+  for (var data = [], i = 0; i < value.length; i++) {
+    data[i] = value[i].toArray();
+  }
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setField(msg, fieldNumber, data);
+};
+
+
+/**
+ * Converts a JsPb repeated message field into a map. The map will contain
+ * protos unless an optional toObject function is given, in which case it will
+ * contain objects suitable for Soy rendering.
+ * @param {!Array<T>} field The repeated message field to be
+ *     converted.
+ * @param {function() : string?} mapKeyGetterFn The function to get the key of
+ *     the map.
+ * @param {?function(boolean=): Object|
+ *     function((boolean|undefined),T): Object} opt_toObjectFn The
+ *     toObject function for this field. We need to pass this for effective
+ *     dead code removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object.<string, Object>} A map of proto or Soy objects.
+ * @template T
+ */
+jspb.Message.toMap = function(
+    field, mapKeyGetterFn, opt_toObjectFn, opt_includeInstance) {
+  var result = {};
+  for (var i = 0; i < field.length; i++) {
+    result[mapKeyGetterFn.call(field[i])] = opt_toObjectFn ?
+        opt_toObjectFn.call(field[i], opt_includeInstance,
+            /** @type {!jspb.Message} */ (field[i])) : field[i];
+  }
+  return result;
+};
+
+
+/**
+ * Returns the internal array of this proto.
+ * <p>Note: If you use this array to construct a second proto, the content
+ * would then be partially shared between the two protos.
+ * @return {!Array} The proto represented as an array.
+ */
+jspb.Message.prototype.toArray = function() {
+  return this.array;
+};
+
+
+
+
+/**
+ * Creates a string representation of the internal data array of this proto.
+ * <p>NOTE: This string is *not* suitable for use in server requests.
+ * @return {string} A string representation of this proto.
+ * @override
+ */
+jspb.Message.prototype.toString = function() {
+  return this.array.toString();
+};
+
+
+/**
+ * Gets the value of the extension field from the extended object.
+ * @param {jspb.ExtensionFieldInfo.<T>} fieldInfo Specifies the field to get.
+ * @return {T} The value of the field.
+ * @template T
+ */
+jspb.Message.prototype.getExtension = function(fieldInfo) {
+  if (!this.extensionObject_) {
+    return undefined;
+  }
+  if (!this.wrappers_) {
+    this.wrappers_ = {};
+  }
+  var fieldNumber = fieldInfo.fieldIndex;
+  if (fieldInfo.isRepeated) {
+    if (fieldInfo.isMessageType()) {
+      if (!this.wrappers_[fieldNumber]) {
+        this.wrappers_[fieldNumber] =
+            goog.array.map(this.extensionObject_[fieldNumber] || [],
+                function(arr) {
+                  return new fieldInfo.ctor(arr);
+                });
+      }
+      return this.wrappers_[fieldNumber];
+    } else {
+      return this.extensionObject_[fieldNumber];
+    }
+  } else {
+    if (fieldInfo.isMessageType()) {
+      if (!this.wrappers_[fieldNumber] && this.extensionObject_[fieldNumber]) {
+        this.wrappers_[fieldNumber] = new fieldInfo.ctor(
+            /** @type {Array|undefined} */ (
+                this.extensionObject_[fieldNumber]));
+      }
+      return this.wrappers_[fieldNumber];
+    } else {
+      return this.extensionObject_[fieldNumber];
+    }
+  }
+};
+
+
+/**
+ * Sets the value of the extension field in the extended object.
+ * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set.
+ * @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value
+ *     to set.
+ */
+jspb.Message.prototype.setExtension = function(fieldInfo, value) {
+  if (!this.wrappers_) {
+    this.wrappers_ = {};
+  }
+  jspb.Message.maybeInitEmptyExtensionObject_(this);
+  var fieldNumber = fieldInfo.fieldIndex;
+  if (fieldInfo.isRepeated) {
+    value = value || [];
+    if (fieldInfo.isMessageType()) {
+      this.wrappers_[fieldNumber] = value;
+      this.extensionObject_[fieldNumber] = goog.array.map(
+          /** @type {Array<jspb.Message>} */ (value), function(msg) {
+        return msg.toArray();
+      });
+    } else {
+      this.extensionObject_[fieldNumber] = value;
+    }
+  } else {
+    if (fieldInfo.isMessageType()) {
+      this.wrappers_[fieldNumber] = value;
+      this.extensionObject_[fieldNumber] = value ? value.toArray() : value;
+    } else {
+      this.extensionObject_[fieldNumber] = value;
+    }
+  }
+};
+
+
+/**
+ * Creates a difference object between two messages.
+ *
+ * The result will contain the top-level fields of m2 that differ from those of
+ * m1 at any level of nesting. No data is cloned, the result object will
+ * share its top-level elements with m2 (but not with m1).
+ *
+ * Note that repeated fields should not have null/undefined elements, but if
+ * they do, this operation will treat repeated fields of different length as
+ * the same if the only difference between them is due to trailing
+ * null/undefined values.
+ *
+ * @param {!jspb.Message} m1 The first message object.
+ * @param {!jspb.Message} m2 The second message object.
+ * @return {!jspb.Message} The difference returned as a proto message.
+ *     Note that the returned message may be missing required fields. This is
+ *     currently tolerated in Js, but would cause an error if you tried to
+ *     send such a proto to the server. You can access the raw difference
+ *     array with result.toArray().
+ * @throws {Error} If the messages are responses with different types.
+ */
+jspb.Message.difference = function(m1, m2) {
+  if (!(m1 instanceof m2.constructor)) {
+    throw new Error('Messages have different types.');
+  }
+  var arr1 = m1.toArray();
+  var arr2 = m2.toArray();
+  var res = [];
+  var start = 0;
+  var length = arr1.length > arr2.length ? arr1.length : arr2.length;
+  if (m1.getJsPbMessageId()) {
+    res[0] = m1.getJsPbMessageId();
+    start = 1;
+  }
+  for (var i = start; i < length; i++) {
+    if (!jspb.Message.compareFields(arr1[i], arr2[i])) {
+      res[i] = arr2[i];
+    }
+  }
+  return new m1.constructor(res);
+};
+
+
+/**
+ * Tests whether two messages are equal.
+ * @param {jspb.Message|undefined} m1 The first message object.
+ * @param {jspb.Message|undefined} m2 The second message object.
+ * @return {boolean} true if both messages are null/undefined, or if both are
+ *     of the same type and have the same field values.
+ */
+jspb.Message.equals = function(m1, m2) {
+  return m1 == m2 || (!!(m1 && m2) && (m1 instanceof m2.constructor) &&
+      jspb.Message.compareFields(m1.toArray(), m2.toArray()));
+};
+
+
+/**
+ * Compares two message extension fields recursively.
+ * @param {!Object} extension1 The first field.
+ * @param {!Object} extension2 The second field.
+ * @return {boolean} true if the extensions are null/undefined, or otherwise
+ *     equal.
+ */
+jspb.Message.compareExtensions = function(extension1, extension2) {
+  extension1 = extension1 || {};
+  extension2 = extension2 || {};
+
+  var keys = {};
+  for (var name in extension1) {
+    keys[name] = 0;
+  }
+  for (var name in extension2) {
+    keys[name] = 0;
+  }
+  for (name in keys) {
+    if (!jspb.Message.compareFields(extension1[name], extension2[name])) {
+      return false;
+    }
+  }
+  return true;
+};
+
+
+/**
+ * Compares two message fields recursively.
+ * @param {*} field1 The first field.
+ * @param {*} field2 The second field.
+ * @return {boolean} true if the fields are null/undefined, or otherwise equal.
+ */
+jspb.Message.compareFields = function(field1, field2) {
+  // If the fields are trivially equal, they're equal.
+  if (field1 == field2) return true;
+
+  // If the fields aren't trivially equal and one of them isn't an object,
+  // they can't possibly be equal.
+  if (!goog.isObject(field1) || !goog.isObject(field2)) {
+    return false;
+  }
+
+  // We have two objects. If they're different types, they're not equal.
+  field1 = /** @type {!Object} */(field1);
+  field2 = /** @type {!Object} */(field2);
+  if (field1.constructor != field2.constructor) return false;
+
+  // If both are Uint8Arrays, compare them element-by-element.
+  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && field1.constructor === Uint8Array) {
+    var bytes1 = /** @type {!Uint8Array} */(field1);
+    var bytes2 = /** @type {!Uint8Array} */(field2);
+    if (bytes1.length != bytes2.length) return false;
+    for (var i = 0; i < bytes1.length; i++) {
+      if (bytes1[i] != bytes2[i]) return false;
+    }
+    return true;
+  }
+
+  // If they're both Arrays, compare them element by element except for the
+  // optional extension objects at the end, which we compare separately.
+  if (field1.constructor === Array) {
+    var extension1 = undefined;
+    var extension2 = undefined;
+
+    var length = Math.max(field1.length, field2.length);
+    for (var i = 0; i < length; i++) {
+      var val1 = field1[i];
+      var val2 = field2[i];
+
+      if (val1 && (val1.constructor == Object)) {
+        goog.asserts.assert(extension1 === undefined);
+        goog.asserts.assert(i === field1.length - 1);
+        extension1 = val1;
+        val1 = undefined;
+      }
+
+      if (val2 && (val2.constructor == Object)) {
+        goog.asserts.assert(extension2 === undefined);
+        goog.asserts.assert(i === field2.length - 1);
+        extension2 = val2;
+        val2 = undefined;
+      }
+
+      if (!jspb.Message.compareFields(val1, val2)) {
+        return false;
+      }
+    }
+
+    if (extension1 || extension2) {
+      extension1 = extension1 || {};
+      extension2 = extension2 || {};
+      return jspb.Message.compareExtensions(extension1, extension2);
+    }
+
+    return true;
+  }
+
+  // If they're both plain Objects (i.e. extensions), compare them as
+  // extensions.
+  if (field1.constructor === Object) {
+    return jspb.Message.compareExtensions(field1, field2);
+  }
+
+  throw new Error('Invalid type in JSPB array');
+};
+
+
+/**
+ * Static clone function. NOTE: A type-safe method called "cloneMessage" exists
+ * on each generated JsPb class. Do not call this function directly.
+ * @param {!jspb.Message} msg A message to clone.
+ * @return {!jspb.Message} A deep clone of the given message.
+ */
+jspb.Message.clone = function(msg) {
+  // Although we could include the wrappers, we leave them out here.
+  return jspb.Message.cloneMessage(msg);
+};
+
+
+/**
+ * @param {!jspb.Message} msg A message to clone.
+ * @return {!jspb.Message} A deep clone of the given message.
+ * @protected
+ */
+jspb.Message.cloneMessage = function(msg) {
+  // Although we could include the wrappers, we leave them out here.
+  return new msg.constructor(jspb.Message.clone_(msg.toArray()));
+};
+
+
+/**
+ * Takes 2 messages of the same type and copies the contents of the first
+ * message into the second. After this the 2 messages will equals in terms of
+ * value semantics but share no state. All data in the destination message will
+ * be overridden.
+ *
+ * @param {MESSAGE} fromMessage Message that will be copied into toMessage.
+ * @param {MESSAGE} toMessage Message which will receive a copy of fromMessage
+ *     as its contents.
+ * @template MESSAGE
+ */
+jspb.Message.copyInto = function(fromMessage, toMessage) {
+  goog.asserts.assertInstanceof(fromMessage, jspb.Message);
+  goog.asserts.assertInstanceof(toMessage, jspb.Message);
+  goog.asserts.assert(fromMessage.constructor == toMessage.constructor,
+      'Copy source and target message should have the same type.');
+  var copyOfFrom = jspb.Message.clone(fromMessage);
+
+  var to = toMessage.toArray();
+  var from = copyOfFrom.toArray();
+
+  // Empty destination in case it has more values at the end of the array.
+  to.length = 0;
+  // and then copy everything from the new to the existing message.
+  for (var i = 0; i < from.length; i++) {
+    to[i] = from[i];
+  }
+
+  // This is either null or empty for a fresh copy.
+  toMessage.wrappers_ = copyOfFrom.wrappers_;
+  // Just a reference into the shared array.
+  toMessage.extensionObject_ = copyOfFrom.extensionObject_;
+};
+
+
+/**
+ * Helper for cloning an internal JsPb object.
+ * @param {!Object} obj A JsPb object, eg, a field, to be cloned.
+ * @return {!Object} A clone of the input object.
+ * @private
+ */
+jspb.Message.clone_ = function(obj) {
+  var o;
+  if (goog.isArray(obj)) {
+    // Allocate array of correct size.
+    var clonedArray = new Array(obj.length);
+    // Use array iteration where possible because it is faster than for-in.
+    for (var i = 0; i < obj.length; i++) {
+      if ((o = obj[i]) != null) {
+        clonedArray[i] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+      }
+    }
+    return clonedArray;
+  }
+  var clone = {};
+  for (var key in obj) {
+    if ((o = obj[key]) != null) {
+      clone[key] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+    }
+  }
+  return clone;
+};
+
+
+/**
+ * Registers a JsPb message type id with its constructor.
+ * @param {string} id The id for this type of message.
+ * @param {Function} constructor The message constructor.
+ */
+jspb.Message.registerMessageType = function(id, constructor) {
+  jspb.Message.registry_[id] = constructor;
+  // This is needed so we can later access messageId directly on the contructor,
+  // otherwise it is not available due to 'property collapsing' by the compiler.
+  constructor.messageId = id;
+};
+
+
+/**
+ * The registry of message ids to message constructors.
+ * @private
+ */
+jspb.Message.registry_ = {};
+
+
+/**
+ * The extensions registered on MessageSet. This is a map of extension
+ * field number to field info object. This should be considered as a
+ * private API.
+ *
+ * This is similar to [jspb class name].extensions object for
+ * non-MessageSet. We special case MessageSet so that we do not need
+ * to goog.require MessageSet from classes that extends MessageSet.
+ *
+ * @type {!Object.<number, jspb.ExtensionFieldInfo>}
+ */
+jspb.Message.messageSetExtensions = {};
diff --git a/js/message_test.js b/js/message_test.js
new file mode 100644
index 0000000..01add5f
--- /dev/null
+++ b/js/message_test.js
@@ -0,0 +1,1010 @@
+// 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.
+
+// Test suite is written using Jasmine -- see http://jasmine.github.io/
+
+goog.setTestOnly();
+
+goog.require('goog.json');
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: google-protobuf jspb
+goog.require('jspb.Message');
+
+// CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta
+goog.require('proto.jspb.exttest.beta.floatingStrField');
+
+// CommonJS-LoadFromFile: test3_pb proto.jspb.exttest
+goog.require('proto.jspb.exttest.floatingMsgField');
+
+// CommonJS-LoadFromFile: test4_pb proto.jspb.exttest
+goog.require('proto.jspb.exttest.floatingMsgFieldTwo');
+
+// CommonJS-LoadFromFile: test_pb proto.jspb.test
+goog.require('proto.jspb.test.CloneExtension');
+goog.require('proto.jspb.test.Complex');
+goog.require('proto.jspb.test.DefaultValues');
+goog.require('proto.jspb.test.Empty');
+goog.require('proto.jspb.test.EnumContainer');
+goog.require('proto.jspb.test.floatingMsgField');
+goog.require('proto.jspb.test.FloatingPointFields');
+goog.require('proto.jspb.test.floatingStrField');
+goog.require('proto.jspb.test.HasExtensions');
+goog.require('proto.jspb.test.IndirectExtension');
+goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.OptionalFields');
+goog.require('proto.jspb.test.OuterEnum');
+goog.require('proto.jspb.test.OuterMessage.Complex');
+goog.require('proto.jspb.test.Simple1');
+goog.require('proto.jspb.test.Simple2');
+goog.require('proto.jspb.test.SpecialCases');
+goog.require('proto.jspb.test.TestClone');
+goog.require('proto.jspb.test.TestGroup');
+goog.require('proto.jspb.test.TestGroup1');
+goog.require('proto.jspb.test.TestMessageWithOneof');
+goog.require('proto.jspb.test.TestReservedNames');
+goog.require('proto.jspb.test.TestReservedNamesExtension');
+
+// CommonJS-LoadFromFile: test2_pb proto.jspb.test
+goog.require('proto.jspb.test.ExtensionMessage');
+goog.require('proto.jspb.test.TestExtensionsMessage');
+
+
+
+
+describe('Message test suite', function() {
+  it('testEmptyProto', function() {
+    var empty1 = new proto.jspb.test.Empty([]);
+    var empty2 = new proto.jspb.test.Empty([]);
+    assertObjectEquals({}, empty1.toObject());
+    assertObjectEquals('Message should not be corrupted:', empty2, empty1);
+  });
+
+  it('testTopLevelEnum', function() {
+    var response = new proto.jspb.test.EnumContainer([]);
+    response.setOuterEnum(proto.jspb.test.OuterEnum.FOO);
+    assertEquals(proto.jspb.test.OuterEnum.FOO, response.getOuterEnum());
+  });
+
+  it('testByteStrings', function() {
+    var data = new proto.jspb.test.DefaultValues([]);
+    data.setBytesField('some_bytes');
+    assertEquals('some_bytes', data.getBytesField());
+  });
+
+  it('testComplexConversion', function() {
+    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var data2 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var foo = new proto.jspb.test.Complex(data1);
+    var bar = new proto.jspb.test.Complex(data2);
+    var result = foo.toObject();
+    assertObjectEquals({
+      aString: 'a',
+      anOutOfOrderBool: 1,
+      aNestedMessage: {
+        anInt: 11
+      },
+      aRepeatedMessageList: [{anInt: 22}, {anInt: 33}],
+      aRepeatedStringList: ['s1', 's2']
+    }, result);
+
+    // Now test with the jspb instances included.
+    result = foo.toObject(true /* opt_includeInstance */);
+    assertObjectEquals({
+      aString: 'a',
+      anOutOfOrderBool: 1,
+      aNestedMessage: {
+        anInt: 11,
+        $jspbMessageInstance: foo.getANestedMessage()
+      },
+      aRepeatedMessageList: [
+        {anInt: 22, $jspbMessageInstance: foo.getARepeatedMessageList()[0]},
+        {anInt: 33, $jspbMessageInstance: foo.getARepeatedMessageList()[1]}
+      ],
+      aRepeatedStringList: ['s1', 's2'],
+      $jspbMessageInstance: foo
+    }, result);
+
+  });
+
+  it('testMissingFields', function() {
+    var foo = new proto.jspb.test.Complex([
+        undefined, undefined, undefined, [],
+        undefined, undefined, undefined, undefined]);
+    var bar = new proto.jspb.test.Complex([
+        undefined, undefined, undefined, [],
+        undefined, undefined, undefined, undefined]);
+    var result = foo.toObject();
+    assertObjectEquals({
+      aString: undefined,
+      anOutOfOrderBool: undefined,
+      aNestedMessage: {
+        anInt: undefined
+      },
+      // Note: JsPb converts undefined repeated fields to empty arrays.
+      aRepeatedMessageList: [],
+      aRepeatedStringList: []
+    }, result);
+
+  });
+
+  it('testNestedComplexMessage', function() {
+    // Instantiate the message and set a unique field, just to ensure that we
+    // are not getting jspb.test.Complex instead.
+    var msg = new proto.jspb.test.OuterMessage.Complex();
+    msg.setInnerComplexField(5);
+  });
+
+  it('testSpecialCases', function() {
+    // Note: Some property names are reserved in JavaScript.
+    // These names are converted to the Js property named pb_<reserved_name>.
+    var special =
+        new proto.jspb.test.SpecialCases(['normal', 'default', 'function',
+        'var']);
+    var result = special.toObject();
+    assertObjectEquals({
+      normal: 'normal',
+      pb_default: 'default',
+      pb_function: 'function',
+      pb_var: 'var'
+    }, result);
+  });
+
+  it('testDefaultValues', function() {
+    var defaultString = "default<>\'\"abc";
+    var response = new proto.jspb.test.DefaultValues();
+
+    // Test toObject
+    var expectedObject = {
+      stringField: defaultString,
+      boolField: true,
+      intField: 11,
+      enumField: 13,
+      emptyField: '',
+      bytesField: 'bW9v'
+    };
+    assertObjectEquals(expectedObject, response.toObject());
+
+
+    // Test getters
+    response = new proto.jspb.test.DefaultValues();
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+    assertEquals('', response.getEmptyField());
+    assertEquals('bW9v', response.getBytesField());
+
+    function makeDefault(values) {
+      return new proto.jspb.test.DefaultValues(values);
+    }
+
+    // Test with undefined values,
+    // Use push to workaround IE treating undefined array elements as holes.
+    response = makeDefault([undefined, undefined, undefined, undefined]);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test with null values, as would be returned by a JSON serializer.
+    response = makeDefault([null, null, null, null]);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test with false-like values.
+    response = makeDefault(['', false, 0, 0]);
+    assertEquals('', response.getStringField());
+    assertEquals(false, response.getBoolField());
+    assertEquals(true, response.getIntField() == 0);
+    assertEquals(true, response.getEnumField() == 0);
+
+    // Test that clearing the values reverts them to the default state.
+    response = makeDefault(['blah', false, 111, 77]);
+    response.clearStringField(); response.clearBoolField();
+    response.clearIntField(); response.clearEnumField();
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test that setFoo(null) clears the values.
+    response = makeDefault(['blah', false, 111, 77]);
+    response.setStringField(null); response.setBoolField(null);
+    response.setIntField(undefined); response.setEnumField(undefined);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+  });
+
+  it('testMessageRegistration', function() {
+    // goog.require(SomeResponse) will include its library, which will in
+    // turn add SomeResponse to the message registry.
+    assertEquals(jspb.Message.registry_['res'], proto.jspb.test.SomeResponse);
+  });
+
+  it('testClearFields', function() {
+    // We don't set 'proper' defaults, rather, bools, strings,
+    // etc, are cleared to undefined or null and take on the Javascript
+    // meaning for that value. Repeated fields are set to [] when cleared.
+    var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
+    var foo = new proto.jspb.test.OptionalFields(data);
+    foo.clearAString();
+    foo.clearABool();
+    foo.clearANestedMessage();
+    foo.clearARepeatedMessageList();
+    foo.clearARepeatedStringList();
+    assertUndefined(foo.getAString());
+    assertUndefined(foo.getABool());
+    assertUndefined(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    // NOTE: We want the missing fields in 'expected' to be undefined,
+    // but we actually get a sparse array instead. We could use something
+    // like [1,undefined,2] to avoid this, except that this is still
+    // sparse on IE. No comment...
+    var expected = [,,, [], []];
+    expected[0] = expected[1] = expected[2] = undefined;
+    assertObjectEquals(expected, foo.toArray());
+
+    // Test set(null). We could deprecated this in favor of clear(), but
+    // it's also convenient to have.
+    data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
+    foo = new proto.jspb.test.OptionalFields(data);
+    foo.setAString(null);
+    foo.setABool(null);
+    foo.setANestedMessage(null);
+    foo.setARepeatedMessageList(null);
+    foo.setARepeatedStringList(null);
+    assertNull(foo.getAString());
+    assertNull(foo.getABool());
+    assertNull(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    assertObjectEquals([null, null, null, [], []], foo.toArray());
+
+    // Test set(undefined). Again, not something we really need, and not
+    // supported directly by our typing, but it should 'do the right thing'.
+    data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
+    foo = new proto.jspb.test.OptionalFields(data);
+    foo.setAString(undefined);
+    foo.setABool(undefined);
+    foo.setANestedMessage(undefined);
+    foo.setARepeatedMessageList(undefined);
+    foo.setARepeatedStringList(undefined);
+    assertUndefined(foo.getAString());
+    assertUndefined(foo.getABool());
+    assertUndefined(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    expected = [,,, [], []];
+    expected[0] = expected[1] = expected[2] = undefined;
+    assertObjectEquals(expected, foo.toArray());
+  });
+
+  it('testDifferenceRawObject', function() {
+    var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
+    var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
+                                               {1000: 'unique'}]);
+    var diff = /** @type {proto.jspb.test.HasExtensions} */
+        (jspb.Message.difference(p1, p2));
+    assertUndefined(diff.getStr1());
+    assertEquals('what', diff.getStr2());
+    assertUndefined(diff.getStr3());
+    assertEquals('unique', diff.extensionObject_[1000]);
+  });
+
+  it('testEqualsSimple', function() {
+    var s1 = new proto.jspb.test.Simple1(['hi']);
+    assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
+    assertFalse(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['bye'])));
+    var s1b = new proto.jspb.test.Simple1(['hi', ['hello']]);
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', ['hello']])));
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', ['hello', undefined,
+                                            undefined, undefined]])));
+    assertFalse(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['no', ['hello']])));
+    // Test with messages of different types
+    var s2 = new proto.jspb.test.Simple2(['hi']);
+    assertFalse(jspb.Message.equals(s1, s2));
+  });
+
+  it('testEquals_softComparison', function() {
+    var s1 = new proto.jspb.test.Simple1(['hi', [], null]);
+    assertTrue(jspb.Message.equals(s1,
+        new proto.jspb.test.Simple1(['hi', []])));
+
+    var s1b = new proto.jspb.test.Simple1(['hi', [], true]);
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', [], 1])));
+  });
+
+  it('testEqualsComplex', function() {
+    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var data2 = ['a',,, [, 11], [[, 22], [, 34]],, ['s1', 's2'],, 1];
+    var data3 = ['a',,, [, 11], [[, 22]],, ['s1', 's2'],, 1];
+    var data4 = ['hi'];
+    var c1a = new proto.jspb.test.Complex(data1);
+    var c1b = new proto.jspb.test.Complex(data1);
+    var c2 = new proto.jspb.test.Complex(data2);
+    var c3 = new proto.jspb.test.Complex(data3);
+    var s1 = new proto.jspb.test.Simple1(data4);
+
+    assertTrue(jspb.Message.equals(c1a, c1b));
+    assertFalse(jspb.Message.equals(c1a, c2));
+    assertFalse(jspb.Message.equals(c2, c3));
+    assertFalse(jspb.Message.equals(c1a, s1));
+  });
+
+  it('testEqualsExtensionsConstructed', function() {
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([]),
+        new proto.jspb.test.HasExtensions([{}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
+    ));
+    assertFalse(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'b'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
+    ));
+  });
+
+  it('testEqualsExtensionsUnconstructed', function() {
+    assertTrue(jspb.Message.compareFields([], [{}]));
+    assertTrue(jspb.Message.compareFields([,,, {}], []));
+    assertTrue(jspb.Message.compareFields([,,, {}], [,, {}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
+    assertFalse(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi', {100: [{200: 'b'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [{100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [{100: [{200: 'a'}]}], [,,, {100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [,,, {100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi',,, {100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
+  });
+
+  it('testToMap', function() {
+    var p1 = new proto.jspb.test.Simple1(['k', ['v']]);
+    var p2 = new proto.jspb.test.Simple1(['k1', ['v1', 'v2']]);
+    var soymap = jspb.Message.toMap([p1, p2],
+        proto.jspb.test.Simple1.prototype.getAString,
+        proto.jspb.test.Simple1.prototype.toObject);
+    assertEquals('k', soymap['k'].aString);
+    assertArrayEquals(['v'], soymap['k'].aRepeatedStringList);
+    var protomap = jspb.Message.toMap([p1, p2],
+        proto.jspb.test.Simple1.prototype.getAString);
+    assertEquals('k', protomap['k'].getAString());
+    assertArrayEquals(['v'], protomap['k'].getARepeatedStringList());
+  });
+
+  it('testClone', function() {
+    var original = new proto.jspb.test.TestClone();
+    original.setStr('v1');
+    var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
+    var simple2 = new proto.jspb.test.Simple1(['x2', ['y2', 'z2']]);
+    var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
+    original.setSimple1(simple1);
+    original.setSimple2List([simple2, simple3]);
+    var extension = new proto.jspb.test.CloneExtension();
+    extension.setExt('e1');
+    original.setExtension(proto.jspb.test.IsExtension.extField, extension);
+    var clone = original.cloneMessage();
+    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+        clone.toArray());
+    clone.setStr('v2');
+    var simple4 = new proto.jspb.test.Simple1(['a1', ['b1', 'c1']]);
+    var simple5 = new proto.jspb.test.Simple1(['a2', ['b2', 'c2']]);
+    var simple6 = new proto.jspb.test.Simple1(['a3', ['b3', 'c3']]);
+    clone.setSimple1(simple4);
+    clone.setSimple2List([simple5, simple6]);
+    var newExtension = new proto.jspb.test.CloneExtension();
+    newExtension.setExt('e2');
+    clone.setExtension(proto.jspb.test.CloneExtension.extField, newExtension);
+    assertArrayEquals(['v2',, ['a1', ['b1', 'c1']],,
+      [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]],,, { 100: [, 'e2'] }],
+        clone.toArray());
+    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+        original.toArray());
+  });
+
+  it('testCopyInto', function() {
+    var original = new proto.jspb.test.TestClone();
+    original.setStr('v1');
+    var dest = new proto.jspb.test.TestClone();
+    dest.setStr('override');
+    var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
+    var simple2 = new proto.jspb.test.Simple1(['x2', ['y2', 'z2']]);
+    var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
+    var destSimple1 = new proto.jspb.test.Simple1(['ox1', ['oy1', 'oz1']]);
+    var destSimple2 = new proto.jspb.test.Simple1(['ox2', ['oy2', 'oz2']]);
+    var destSimple3 = new proto.jspb.test.Simple1(['ox3', ['oy3', 'oz3']]);
+    original.setSimple1(simple1);
+    original.setSimple2List([simple2, simple3]);
+    dest.setSimple1(destSimple1);
+    dest.setSimple2List([destSimple2, destSimple3]);
+    var extension = new proto.jspb.test.CloneExtension();
+    extension.setExt('e1');
+    original.setExtension(proto.jspb.test.CloneExtension.extField, extension);
+
+    jspb.Message.copyInto(original, dest);
+    assertArrayEquals(original.toArray(), dest.toArray());
+    assertEquals('x1', dest.getSimple1().getAString());
+    assertEquals('e1',
+        dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt());
+    dest.getSimple1().setAString('new value');
+    assertNotEquals(dest.getSimple1().getAString(),
+        original.getSimple1().getAString());
+    dest.getExtension(proto.jspb.test.CloneExtension.extField).
+        setExt('new value');
+    assertNotEquals(
+        dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt(),
+        original.getExtension(
+            proto.jspb.test.CloneExtension.extField).getExt());
+  });
+
+  it('testCopyInto_notSameType', function() {
+    var a = new proto.jspb.test.TestClone();
+    var b = new proto.jspb.test.Simple1(['str', ['s1', 's2']]);
+
+    var e = assertThrows(function() {
+      jspb.Message.copyInto(a, b);
+    });
+    assertContains('should have the same type', e.message);
+  });
+
+  it('testExtensions', function() {
+    var extension1 = new proto.jspb.test.IsExtension(['ext1field']);
+    var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2']]);
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
+                            extension2);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
+    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
+        ['a', 'b']);
+    var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
+    var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2']]);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList,
+        [s1, s2]);
+    assertObjectEquals(extension1,
+        extendable.getExtension(proto.jspb.test.IsExtension.extField));
+    assertObjectEquals(extension2,
+        extendable.getExtension(proto.jspb.test.IndirectExtension.simple));
+    assertObjectEquals('xyzzy',
+        extendable.getExtension(proto.jspb.test.IndirectExtension.str));
+    assertObjectEquals(['a', 'b'], extendable.getExtension(
+        proto.jspb.test.IndirectExtension.repeatedStrList));
+    assertObjectEquals([s1, s2], extendable.getExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList));
+    // Not supported yet, but it should work...
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple, null);
+    assertNull(
+        extendable.getExtension(proto.jspb.test.IndirectExtension.simple));
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, null);
+    assertNull(extendable.getExtension(proto.jspb.test.IndirectExtension.str));
+
+
+    // Extension fields with jspb.ignore = true are ignored.
+    assertUndefined(proto.jspb.test.IndirectExtension['ignored']);
+    assertUndefined(proto.jspb.test.HasExtensions['ignoredFloating']);
+  });
+
+  it('testFloatingExtensions', function() {
+    // From an autogenerated container.
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    var extension = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
+    extendable.setExtension(proto.jspb.test.simple1, extension);
+    assertObjectEquals(extension,
+        extendable.getExtension(proto.jspb.test.simple1));
+
+    // From _lib mode.
+    extension = new proto.jspb.test.ExtensionMessage(['s1']);
+    extendable = new proto.jspb.test.TestExtensionsMessage([16]);
+    extendable.setExtension(proto.jspb.test.floatingMsgField, extension);
+    extendable.setExtension(proto.jspb.test.floatingStrField, 's2');
+    assertObjectEquals(extension,
+        extendable.getExtension(proto.jspb.test.floatingMsgField));
+    assertObjectEquals('s2',
+        extendable.getExtension(proto.jspb.test.floatingStrField));
+    assertNotUndefined(proto.jspb.exttest.floatingMsgField);
+    assertNotUndefined(proto.jspb.exttest.floatingMsgFieldTwo);
+    assertNotUndefined(proto.jspb.exttest.beta.floatingStrField);
+  });
+
+  it('testToObject_extendedObject', function() {
+    var extension1 = new proto.jspb.test.IsExtension(['ext1field']);
+    var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2'], true]);
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
+                            extension2);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
+    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
+        ['a', 'b']);
+    var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2'], true]);
+    var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2'], false]);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList,
+        [s1, s2]);
+    assertObjectEquals({
+      str1: 'v1', str2: 'v2', str3: 'v3',
+      extField: { ext1: 'ext1field' },
+      simple: {
+        aString: 'str', aRepeatedStringList: ['s1', 's2'], aBoolean: true
+      },
+      str: 'xyzzy',
+      repeatedStrList: ['a', 'b'],
+      repeatedSimpleList: [
+        { aString: 'foo', aRepeatedStringList: ['s1', 's2'], aBoolean: true},
+        { aString: 'bar', aRepeatedStringList: ['t1', 't2'], aBoolean: false}
+      ]
+    }, extendable.toObject());
+
+    // Now, with instances included.
+    assertObjectEquals({
+      str1: 'v1', str2: 'v2', str3: 'v3',
+      extField: {
+        ext1: 'ext1field',
+        $jspbMessageInstance:
+            extendable.getExtension(proto.jspb.test.IsExtension.extField)
+      },
+      simple: {
+        aString: 'str',
+        aRepeatedStringList: ['s1', 's2'],
+        aBoolean: true,
+        $jspbMessageInstance:
+            extendable.getExtension(proto.jspb.test.IndirectExtension.simple)
+      },
+      str: 'xyzzy',
+      repeatedStrList: ['a', 'b'],
+      repeatedSimpleList: [{
+        aString: 'foo',
+        aRepeatedStringList: ['s1', 's2'],
+        aBoolean: true,
+        $jspbMessageInstance: s1
+      }, {
+        aString: 'bar',
+        aRepeatedStringList: ['t1', 't2'],
+        aBoolean: false,
+        $jspbMessageInstance: s2
+      }],
+      $jspbMessageInstance: extendable
+    }, extendable.toObject(true /* opt_includeInstance */));
+  });
+
+  it('testInitialization_emptyArray', function() {
+    var msg = new proto.jspb.test.HasExtensions([]);
+    if (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) {
+      assertArrayEquals([], msg.toArray());
+    } else {
+      // Extension object is created past all regular fields.
+      assertArrayEquals([,,, {}], msg.toArray());
+    }
+  });
+
+  it('testInitialization_justExtensionObject', function() {
+    var msg = new proto.jspb.test.Empty([{1: 'hi'}]);
+    // The extensionObject is not moved from its original location.
+    assertArrayEquals([{1: 'hi'}], msg.toArray());
+  });
+
+  it('testInitialization_incompleteList', function() {
+    var msg = new proto.jspb.test.Empty([1, {4: 'hi'}]);
+    // The extensionObject is not moved from its original location.
+    assertArrayEquals([1, {4: 'hi'}], msg.toArray());
+  });
+
+  it('testInitialization_forwardCompatible', function() {
+    var msg = new proto.jspb.test.Empty([1, 2, 3, {1: 'hi'}]);
+    assertArrayEquals([1, 2, 3, {1: 'hi'}], msg.toArray());
+  });
+
+  it('testExtendedMessageEnsureObject', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1',
+        {'a_key': 'an_object'}]);
+    assertEquals('an_object', data.extensionObject_['a_key']);
+  });
+
+  it('testToObject_hasExtensionField', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);
+    var obj = data.toObject();
+    assertEquals('str1', obj.str1);
+    assertEquals('ext1', obj.extField.ext1);
+  });
+
+  it('testGetExtension', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);
+    assertEquals('str1', data.getStr1());
+    var extension = data.getExtension(proto.jspb.test.IsExtension.extField);
+    assertNotNull(extension);
+    assertEquals('ext1', extension.getExt1());
+  });
+
+  it('testSetExtension', function() {
+    var data = new proto.jspb.test.HasExtensions();
+    var extensionMessage = new proto.jspb.test.IsExtension(['is_extension']);
+    data.setExtension(proto.jspb.test.IsExtension.extField, extensionMessage);
+    var obj = data.toObject();
+    assertNotNull(
+        data.getExtension(proto.jspb.test.IsExtension.extField));
+    assertEquals('is_extension', obj.extField.ext1);
+  });
+
+  /**
+   * Note that group is long deprecated, we only support it because JsPb has
+   * a goal of being able to generate JS classes for all proto descriptors.
+   */
+  it('testGroups', function() {
+    var group = new proto.jspb.test.TestGroup();
+    var someGroup = new proto.jspb.test.TestGroup.RepeatedGroup();
+    someGroup.setId('g1');
+    someGroup.setSomeBoolList([true, false]);
+    group.setRepeatedGroupList([someGroup]);
+    var groups = group.getRepeatedGroupList();
+    assertEquals('g1', groups[0].getId());
+    assertObjectEquals([true, false], groups[0].getSomeBoolList());
+    assertObjectEquals({id: 'g1', someBoolList: [true, false]},
+        groups[0].toObject());
+    assertObjectEquals({
+      repeatedGroupList: [{id: 'g1', someBoolList: [true, false]}],
+      requiredGroup: {id: undefined},
+      optionalGroup: undefined,
+      requiredSimple: {aRepeatedStringList: [], aString: undefined},
+      optionalSimple: undefined,
+      id: undefined
+    }, group.toObject());
+    var group1 = new proto.jspb.test.TestGroup1();
+    group1.setGroup(someGroup);
+    assertEquals(someGroup, group1.getGroup());
+  });
+
+  it('testNonExtensionFieldsAfterExtensionRange', function() {
+    var data = [{'1': 'a_string'}];
+    var message = new proto.jspb.test.Complex(data);
+    assertArrayEquals([], message.getARepeatedStringList());
+  });
+
+  it('testReservedGetterNames', function() {
+    var message = new proto.jspb.test.TestReservedNames();
+    message.setExtension$(11);
+    message.setExtension(proto.jspb.test.TestReservedNamesExtension.foo, 12);
+    assertEquals(11, message.getExtension$());
+    assertEquals(12, message.getExtension(
+        proto.jspb.test.TestReservedNamesExtension.foo));
+    assertObjectEquals({extension: 11, foo: 12}, message.toObject());
+  });
+
+  it('testInitializeMessageWithUnsetOneof', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([]);
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
+            RECURSIVE_ONEOF_NOT_SET,
+        message.getRecursiveOneofCase());
+  });
+
+  it('testInitializeMessageWithSingleValueSetInOneof', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
+
+    assertEquals('x', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+  });
+
+  it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
+
+    assertUndefined('x', message.getPone());
+    assertEquals('y', message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
+        message.getPartialOneofCase());
+  });
+
+  it('testSettingOneofFieldClearsOthers', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getPone());
+    assertUndefined(message.getPthree());
+
+    message.setPone('hi');
+    assertEquals('hi', message.getPone());
+    assertUndefined(message.getPthree());
+
+    message.setPthree('bye');
+    assertUndefined(message.getPone());
+    assertEquals('bye', message.getPthree());
+  });
+
+  it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
+    var other = new proto.jspb.test.TestMessageWithOneof;
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getPone());
+    assertUndefined(message.getPthree());
+    assertUndefined(message.getRone());
+
+    message.setPone('hi');
+    message.setRone(other);
+    assertEquals('hi', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(other, message.getRone());
+
+    message.setPthree('bye');
+    assertUndefined(message.getPone());
+    assertEquals('bye', message.getPthree());
+    assertEquals(other, message.getRone());
+  });
+
+  it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+
+    message.setPone('hi');
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+
+    message.clearPone();
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+  });
+
+  it('testMessageWithDefaultOneofValues', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(1234, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
+            .DEFAULT_ONEOF_A_NOT_SET,
+        message.getDefaultOneofACase());
+
+    message.setAone(567);
+    assertEquals(567, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
+        message.getDefaultOneofACase());
+
+    message.setAtwo(890);
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+
+    message.clearAtwo();
+    assertEquals(1234, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
+            .DEFAULT_ONEOF_A_NOT_SET,
+        message.getDefaultOneofACase());
+  });
+
+  it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
+            .DEFAULT_ONEOF_B_NOT_SET,
+        message.getDefaultOneofBCase());
+
+    message.setBone(2);
+    assertEquals(2, message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
+        message.getDefaultOneofBCase());
+
+    message.setBtwo(3);
+    assertUndefined(message.getBone());
+    assertEquals(3, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+        message.getDefaultOneofBCase());
+
+    message.clearBtwo();
+    assertUndefined(message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
+            .DEFAULT_ONEOF_B_NOT_SET,
+        message.getDefaultOneofBCase());
+  });
+
+  it('testInitializeMessageWithOneofDefaults', function() {
+    var message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567));
+    assertEquals(567, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
+        message.getDefaultOneofACase());
+
+    message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(10).concat(890));
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+
+    message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567, 890));
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+  });
+
+  it('testInitializeMessageWithOneofDefaults_defaultNotSetOnFirstField',
+      function() {
+        var message;
+
+        message =
+            new proto.jspb.test.TestMessageWithOneof(new Array(11).concat(567));
+        assertEquals(567, message.getBone());
+        assertEquals(1234, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
+            message.getDefaultOneofBCase());
+
+        message =
+            new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890));
+        assertUndefined(message.getBone());
+        assertEquals(890, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+            message.getDefaultOneofBCase());
+
+        message = new proto.jspb.test.TestMessageWithOneof(
+            new Array(11).concat(567, 890));
+        assertUndefined(message.getBone());
+        assertEquals(890, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+            message.getDefaultOneofBCase());
+      });
+
+  it('testOneofContainingAnotherMessage', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
+            RECURSIVE_ONEOF_NOT_SET,
+        message.getRecursiveOneofCase());
+
+    var other = new proto.jspb.test.TestMessageWithOneof;
+    message.setRone(other);
+    assertEquals(other, message.getRone());
+    assertUndefined(message.getRtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
+        message.getRecursiveOneofCase());
+
+    message.setRtwo('hi');
+    assertUndefined(message.getRone());
+    assertEquals('hi', message.getRtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RTWO,
+        message.getRecursiveOneofCase());
+  });
+
+  it('testQueryingOneofCaseEnsuresOnlyOneFieldIsSetInUnderlyingArray',
+     function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    message.setPone('x');
+    assertEquals('x', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+
+    var array = message.toArray();
+    assertEquals('x', array[2]);
+    assertUndefined(array[4]);
+    array[4] = 'y';
+
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
+        message.getPartialOneofCase());
+    assertUndefined(array[2]);
+    assertEquals('y', array[4]);
+  });
+
+  it('testFloatingPointFieldsSupportNan', function() {
+    var assertNan = function(x) {
+      assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
+          goog.isNumber(x) && isNaN(x));
+    };
+
+    var message = new proto.jspb.test.FloatingPointFields([
+      'NaN', 'NaN', ['NaN', 'NaN'], 'NaN',
+      'NaN', 'NaN', ['NaN', 'NaN'], 'NaN'
+    ]);
+    assertNan(message.getOptionalFloatField());
+    assertNan(message.getRequiredFloatField());
+    assertNan(message.getRepeatedFloatFieldList()[0]);
+    assertNan(message.getRepeatedFloatFieldList()[1]);
+    assertNan(message.getDefaultFloatField());
+    assertNan(message.getOptionalDoubleField());
+    assertNan(message.getRequiredDoubleField());
+    assertNan(message.getRepeatedDoubleFieldList()[0]);
+    assertNan(message.getRepeatedDoubleFieldList()[1]);
+    assertNan(message.getDefaultDoubleField());
+  });
+
+});
diff --git a/js/node_loader.js b/js/node_loader.js
new file mode 100644
index 0000000..79211ad
--- /dev/null
+++ b/js/node_loader.js
@@ -0,0 +1,49 @@
+// 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.
+
+/**
+ * @fileoverview Loader that handles goog.require() for Node.JS.
+ */
+
+var oldLoader = goog.global.CLOSURE_IMPORT_SCRIPT;
+
+goog.global.CLOSURE_IMPORT_SCRIPT = function(src, opt_sourceText) {
+  if (opt_sourceText === undefined) {
+    try {
+      // Load from the current directory.
+      require("./" + src);
+      return true;
+    } catch (e) {
+      // Fall back to the Closure loader.
+    }
+  }
+
+  return oldLoader(src, opt_sourceText);
+};
diff --git a/js/package.json b/js/package.json
new file mode 100644
index 0000000..ae05722
--- /dev/null
+++ b/js/package.json
@@ -0,0 +1,24 @@
+{
+  "name": "google-protobuf",
+  "version": "3.0.0-alpha.6",
+  "description": "Protocol Buffers for JavaScript",
+  "main": "google-protobuf.js",
+  "dependencies": {
+    "google-closure-library": "~20160125.0.0",
+    "gulp": "~3.9.0",
+    "jasmine": "~2.4.1"
+  },
+  "devDependencies": {
+    "google-closure-compiler": "~20151216.2.0",
+    "glob": "~6.0.4"
+  },
+  "scripts": {
+    "test": "node ./node_modules/gulp/bin/gulp.js test"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/google/protobuf/tree/master/js"
+  },
+  "author": "",
+  "license": "Apache-2.0"
+}
diff --git a/js/proto3_test.js b/js/proto3_test.js
new file mode 100644
index 0000000..4dd7790
--- /dev/null
+++ b/js/proto3_test.js
@@ -0,0 +1,314 @@
+// 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.
+
+goog.require('goog.crypt.base64');
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
+goog.require('proto.jspb.test.ForeignMessage');
+
+// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
+goog.require('proto.jspb.test.Proto3Enum');
+goog.require('proto.jspb.test.TestProto3');
+
+
+var BYTES = new Uint8Array([1, 2, 8, 9]);
+var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
+
+
+/**
+ * Helper: compare a bytes field to an expected value
+ * @param {Uint8Array|string} arr
+ * @param {Uint8Array} expected
+ * @return {boolean}
+ */
+function bytesCompare(arr, expected) {
+  if (goog.isString(arr)) {
+    arr = goog.crypt.base64.decodeStringToUint8Array(arr);
+  }
+  if (arr.length != expected.length) {
+    return false;
+  }
+  for (var i = 0; i < arr.length; i++) {
+    if (arr[i] != expected[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+describe('proto3Test', function() {
+  /**
+   * Test defaults for proto3 message fields.
+   */
+  it('testProto3FieldDefaults', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    assertEquals(msg.getOptionalInt32(), 0);
+    assertEquals(msg.getOptionalInt64(), 0);
+    assertEquals(msg.getOptionalUint32(), 0);
+    assertEquals(msg.getOptionalUint64(), 0);
+    assertEquals(msg.getOptionalSint32(), 0);
+    assertEquals(msg.getOptionalSint64(), 0);
+    assertEquals(msg.getOptionalFixed32(), 0);
+    assertEquals(msg.getOptionalFixed64(), 0);
+    assertEquals(msg.getOptionalSfixed32(), 0);
+    assertEquals(msg.getOptionalSfixed64(), 0);
+    assertEquals(msg.getOptionalFloat(), 0);
+    assertEquals(msg.getOptionalDouble(), 0);
+    assertEquals(msg.getOptionalString(), '');
+
+    // TODO(b/26173701): when we change bytes fields default getter to return
+    // Uint8Array, we'll want to switch this assertion to match the u8 case.
+    assertEquals(typeof msg.getOptionalBytes(), 'string');
+    assertEquals(msg.getOptionalBytes_asU8() instanceof Uint8Array, true);
+    assertEquals(typeof msg.getOptionalBytes_asB64(), 'string');
+    assertEquals(msg.getOptionalBytes().length, 0);
+    assertEquals(msg.getOptionalBytes_asU8().length, 0);
+    assertEquals(msg.getOptionalBytes_asB64(), '');
+
+    assertEquals(msg.getOptionalForeignEnum(),
+                 proto.jspb.test.Proto3Enum.PROTO3_FOO);
+    assertEquals(msg.getOptionalForeignMessage(), undefined);
+    assertEquals(msg.getOptionalForeignMessage(), undefined);
+
+    assertEquals(msg.getRepeatedInt32List().length, 0);
+    assertEquals(msg.getRepeatedInt64List().length, 0);
+    assertEquals(msg.getRepeatedUint32List().length, 0);
+    assertEquals(msg.getRepeatedUint64List().length, 0);
+    assertEquals(msg.getRepeatedSint32List().length, 0);
+    assertEquals(msg.getRepeatedSint64List().length, 0);
+    assertEquals(msg.getRepeatedFixed32List().length, 0);
+    assertEquals(msg.getRepeatedFixed64List().length, 0);
+    assertEquals(msg.getRepeatedSfixed32List().length, 0);
+    assertEquals(msg.getRepeatedSfixed64List().length, 0);
+    assertEquals(msg.getRepeatedFloatList().length, 0);
+    assertEquals(msg.getRepeatedDoubleList().length, 0);
+    assertEquals(msg.getRepeatedStringList().length, 0);
+    assertEquals(msg.getRepeatedBytesList().length, 0);
+    assertEquals(msg.getRepeatedForeignEnumList().length, 0);
+    assertEquals(msg.getRepeatedForeignMessageList().length, 0);
+
+  });
+
+
+  /**
+   * Test that all fields can be set and read via a serialization roundtrip.
+   */
+  it('testProto3FieldSetGet', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    msg.setOptionalInt32(-42);
+    msg.setOptionalInt64(-0x7fffffff00000000);
+    msg.setOptionalUint32(0x80000000);
+    msg.setOptionalUint64(0xf000000000000000);
+    msg.setOptionalSint32(-100);
+    msg.setOptionalSint64(-0x8000000000000000);
+    msg.setOptionalFixed32(1234);
+    msg.setOptionalFixed64(0x1234567800000000);
+    msg.setOptionalSfixed32(-1234);
+    msg.setOptionalSfixed64(-0x1234567800000000);
+    msg.setOptionalFloat(1.5);
+    msg.setOptionalDouble(-1.5);
+    msg.setOptionalBool(true);
+    msg.setOptionalString('hello world');
+    msg.setOptionalBytes(BYTES);
+    var submsg = new proto.jspb.test.ForeignMessage();
+    submsg.setC(16);
+    msg.setOptionalForeignMessage(submsg);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
+
+    msg.setRepeatedInt32List([-42]);
+    msg.setRepeatedInt64List([-0x7fffffff00000000]);
+    msg.setRepeatedUint32List([0x80000000]);
+    msg.setRepeatedUint64List([0xf000000000000000]);
+    msg.setRepeatedSint32List([-100]);
+    msg.setRepeatedSint64List([-0x8000000000000000]);
+    msg.setRepeatedFixed32List([1234]);
+    msg.setRepeatedFixed64List([0x1234567800000000]);
+    msg.setRepeatedSfixed32List([-1234]);
+    msg.setRepeatedSfixed64List([-0x1234567800000000]);
+    msg.setRepeatedFloatList([1.5]);
+    msg.setRepeatedDoubleList([-1.5]);
+    msg.setRepeatedBoolList([true]);
+    msg.setRepeatedStringList(['hello world']);
+    msg.setRepeatedBytesList([BYTES]);
+    submsg = new proto.jspb.test.ForeignMessage();
+    submsg.setC(1000);
+    msg.setRepeatedForeignMessageList([submsg]);
+    msg.setRepeatedForeignEnumList([proto.jspb.test.Proto3Enum.PROTO3_BAR]);
+
+    msg.setOneofString('asdf');
+
+    var serialized = msg.serializeBinary();
+    msg = proto.jspb.test.TestProto3.deserializeBinary(serialized);
+
+    assertEquals(msg.getOptionalInt32(), -42);
+    assertEquals(msg.getOptionalInt64(), -0x7fffffff00000000);
+    assertEquals(msg.getOptionalUint32(), 0x80000000);
+    assertEquals(msg.getOptionalUint64(), 0xf000000000000000);
+    assertEquals(msg.getOptionalSint32(), -100);
+    assertEquals(msg.getOptionalSint64(), -0x8000000000000000);
+    assertEquals(msg.getOptionalFixed32(), 1234);
+    assertEquals(msg.getOptionalFixed64(), 0x1234567800000000);
+    assertEquals(msg.getOptionalSfixed32(), -1234);
+    assertEquals(msg.getOptionalSfixed64(), -0x1234567800000000);
+    assertEquals(msg.getOptionalFloat(), 1.5);
+    assertEquals(msg.getOptionalDouble(), -1.5);
+    assertEquals(msg.getOptionalBool(), true);
+    assertEquals(msg.getOptionalString(), 'hello world');
+    assertEquals(true, bytesCompare(msg.getOptionalBytes(), BYTES));
+    assertEquals(msg.getOptionalForeignMessage().getC(), 16);
+    assertEquals(msg.getOptionalForeignEnum(),
+        proto.jspb.test.Proto3Enum.PROTO3_BAR);
+
+    assertElementsEquals(msg.getRepeatedInt32List(), [-42]);
+    assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]);
+    assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]);
+    assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]);
+    assertElementsEquals(msg.getRepeatedSint32List(), [-100]);
+    assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]);
+    assertElementsEquals(msg.getRepeatedFixed32List(), [1234]);
+    assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]);
+    assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]);
+    assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]);
+    assertElementsEquals(msg.getRepeatedFloatList(), [1.5]);
+    assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]);
+    assertElementsEquals(msg.getRepeatedBoolList(), [true]);
+    assertElementsEquals(msg.getRepeatedStringList(), ['hello world']);
+    assertEquals(msg.getRepeatedBytesList().length, 1);
+    assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
+    assertEquals(msg.getRepeatedForeignMessageList().length, 1);
+    assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
+    assertElementsEquals(msg.getRepeatedForeignEnumList(),
+        [proto.jspb.test.Proto3Enum.PROTO3_BAR]);
+
+    assertEquals(msg.getOneofString(), 'asdf');
+  });
+
+
+  /**
+   * Test that oneofs continue to have a notion of field presence.
+   */
+  it('testOneofs', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofUint32(42);
+    assertEquals(msg.getOneofUint32(), 42);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+
+    var submsg = new proto.jspb.test.ForeignMessage();
+    msg.setOneofForeignMessage(submsg);
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), submsg);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofString('hello');
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), 'hello');
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes_asB64(),
+        goog.crypt.base64.encodeString('\u00FF\u00FF'));
+  });
+
+
+  /**
+   * Test that "default"-valued primitive fields are not emitted on the wire.
+   */
+  it('testNoSerializeDefaults', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    // Set each primitive to a non-default value, then back to its default, to
+    // ensure that the serialization is actually checking the value and not just
+    // whether it has ever been set.
+    msg.setOptionalInt32(42);
+    msg.setOptionalInt32(0);
+    msg.setOptionalDouble(3.14);
+    msg.setOptionalDouble(0.0);
+    msg.setOptionalBool(true);
+    msg.setOptionalBool(false);
+    msg.setOptionalString('hello world');
+    msg.setOptionalString('');
+    msg.setOptionalBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
+    msg.setOptionalBytes('');
+    msg.setOptionalForeignMessage(new proto.jspb.test.ForeignMessage());
+    msg.setOptionalForeignMessage(null);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO);
+    msg.setOneofUint32(32);
+    msg.setOneofUint32(null);
+
+
+    var serialized = msg.serializeBinary();
+    assertEquals(0, serialized.length);
+  });
+
+  /**
+   * Test that base64 string and Uint8Array are interchangeable in bytes fields.
+   */
+  it('testBytesFieldsInterop', function() {
+    var msg = new proto.jspb.test.TestProto3();
+    // Set as a base64 string and check all the getters work.
+    msg.setOptionalBytes(BYTES_B64);
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+    // Test binary serialize round trip doesn't break it.
+    msg = proto.jspb.test.TestProto3.deserializeBinary(msg.serializeBinary());
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+    msg = new proto.jspb.test.TestProto3();
+    // Set as a Uint8Array and check all the getters work.
+    msg.setOptionalBytes(BYTES);
+    assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
+    assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
+
+  });
+});
diff --git a/js/proto3_test.proto b/js/proto3_test.proto
new file mode 100644
index 0000000..acb6716
--- /dev/null
+++ b/js/proto3_test.proto
@@ -0,0 +1,89 @@
+// 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.
+
+syntax = "proto3";
+
+import "testbinary.proto";
+
+package jspb.test;
+
+message TestProto3 {
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  ForeignMessage optional_foreign_message = 19;
+  Proto3Enum     optional_foreign_enum    = 22;
+
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated Proto3Enum     repeated_foreign_enum    = 52;
+
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    ForeignMessage oneof_foreign_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+enum Proto3Enum {
+  PROTO3_FOO = 0;
+  PROTO3_BAR = 1;
+  PROTO3_BAZ = 2;
+}
diff --git a/js/test.proto b/js/test.proto
new file mode 100644
index 0000000..6b9dc89
--- /dev/null
+++ b/js/test.proto
@@ -0,0 +1,230 @@
+// 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.
+
+// Author: mwr@google.com (Mark Rawling)
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+import "google/protobuf/descriptor.proto";
+
+package jspb.test;
+
+message Empty {
+}
+
+enum OuterEnum {
+  FOO = 1;
+  BAR = 2;
+}
+
+message EnumContainer {
+  optional OuterEnum outer_enum = 1;
+}
+
+message Simple1 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+  optional bool a_boolean = 3;
+}
+
+// A message that differs from Simple1 only by name
+message Simple2 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+}
+
+message SpecialCases {
+  required string normal = 1;
+  // Examples of Js reserved names that are converted to pb_<name>.
+  required string default = 2;
+  required string function = 3;
+  required string var = 4;
+}
+
+message OptionalFields {
+  message Nested {
+    optional int32 an_int = 1;
+  }
+  optional string a_string = 1;
+  required bool a_bool = 2;
+  optional Nested a_nested_message = 3;
+  repeated Nested a_repeated_message = 4;
+  repeated string a_repeated_string = 5;
+}
+
+message HasExtensions {
+  optional string str1 = 1;
+  optional string str2 = 2;
+  optional string str3 = 3;
+  extensions 10 to max;
+}
+
+message Complex {
+  message Nested {
+    required int32 an_int = 2;
+  }
+  required string a_string = 1;
+  required bool an_out_of_order_bool = 9;
+  optional Nested a_nested_message = 4;
+  repeated Nested a_repeated_message = 5;
+  repeated string a_repeated_string = 7;
+}
+
+message OuterMessage {
+  // Make sure this doesn't conflict with the other Complex message.
+  message Complex {
+    optional int32 inner_complex_field = 1;
+  }
+}
+
+message IsExtension {
+  extend HasExtensions {
+    optional IsExtension ext_field = 100;
+  }
+  optional string ext1 = 1;
+
+  // Extensions of proto2 Descriptor messages will be ignored.
+  extend google.protobuf.EnumOptions {
+    optional string simple_option = 42113038;
+  }
+}
+
+message IndirectExtension {
+  extend HasExtensions {
+    optional Simple1 simple = 101;
+    optional string str = 102;
+    repeated string repeated_str = 103;
+    repeated Simple1 repeated_simple = 104;
+  }
+}
+
+extend HasExtensions {
+  optional Simple1 simple1 = 105;
+}
+
+message DefaultValues {
+  enum Enum {
+    E1 = 13;
+    E2 = 77;
+  }
+  optional string string_field = 1 [default="default<>\'\"abc"];
+  optional bool bool_field = 2 [default=true];
+  optional int64 int_field = 3 [default=11];
+  optional Enum enum_field = 4 [default=E1];
+  optional string empty_field = 6 [default=""];
+  optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v"
+}
+
+message FloatingPointFields {
+  optional float optional_float_field = 1;
+  required float required_float_field = 2;
+  repeated float repeated_float_field = 3;
+  optional float default_float_field = 4 [default = 2.0];
+  optional double optional_double_field = 5;
+  required double required_double_field = 6;
+  repeated double repeated_double_field = 7;
+  optional double default_double_field = 8 [default = 2.0];
+}
+
+message TestClone {
+  optional string str = 1;
+  optional Simple1 simple1 = 3;
+  repeated Simple1 simple2 = 5;
+  optional string unused = 7;
+  extensions 10 to max;
+}
+
+message CloneExtension {
+  extend TestClone {
+    optional CloneExtension ext_field = 100;
+  }
+  optional string ext = 2;
+}
+
+message TestGroup {
+  repeated group RepeatedGroup = 1 {
+    required string id = 1;
+    repeated bool some_bool = 2;
+  }
+  required group RequiredGroup = 2 {
+    required string id = 1;
+  }
+  optional group OptionalGroup = 3 {
+    required string id = 1;
+  }
+  optional string id = 4;
+  required Simple2 required_simple = 5;
+  optional Simple2 optional_simple = 6;
+}
+
+message TestGroup1 {
+  optional TestGroup.RepeatedGroup group = 1;
+}
+
+message TestReservedNames {
+  optional int32 extension = 1;
+  extensions 10 to max;
+}
+
+message TestReservedNamesExtension {
+  extend TestReservedNames {
+    optional int32 foo = 10;
+  }
+}
+
+message TestMessageWithOneof {
+
+  oneof partial_oneof {
+    string pone = 3;
+    string pthree = 5;
+  }
+
+  oneof recursive_oneof {
+    TestMessageWithOneof rone = 6;
+    string rtwo = 7;
+  }
+
+  optional bool normal_field = 8;
+  repeated string repeated_field = 9;
+
+  oneof default_oneof_a {
+    int32 aone = 10 [default = 1234];
+    int32 atwo = 11;
+  }
+
+  oneof default_oneof_b {
+    int32 bone = 12;
+    int32 btwo = 13 [default = 1234];
+  }
+}
+
diff --git a/js/test2.proto b/js/test2.proto
new file mode 100644
index 0000000..44e55ef
--- /dev/null
+++ b/js/test2.proto
@@ -0,0 +1,54 @@
+// 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.
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.test;
+
+message TestExtensionsMessage {
+  optional int32 intfield = 1;
+  extensions 100 to max;
+}
+
+message ExtensionMessage {
+  extend TestExtensionsMessage {
+    optional ExtensionMessage ext_field = 100;
+  }
+  optional string ext1 = 1;
+}
+
+// Floating extensions are only supported when generating a _lib.js library.
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field = 101;
+  optional string floating_str_field = 102;
+}
diff --git a/js/test3.proto b/js/test3.proto
new file mode 100644
index 0000000..940a552
--- /dev/null
+++ b/js/test3.proto
@@ -0,0 +1,53 @@
+// 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.
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.exttest;
+
+message TestExtensionsMessage {
+  optional int32 intfield = 1;
+  extensions 100 to max;
+}
+
+message ExtensionMessage {
+  extend TestExtensionsMessage {
+    optional ExtensionMessage ext_field = 100;
+  }
+  optional string ext1 = 1;
+}
+
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field = 101;
+  optional string floating_str_field = 102;
+}
diff --git a/js/test4.proto b/js/test4.proto
new file mode 100644
index 0000000..cf2451e
--- /dev/null
+++ b/js/test4.proto
@@ -0,0 +1,42 @@
+// 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.
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.exttest;
+
+import "test3.proto";
+
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field_two = 103;
+}
diff --git a/js/test5.proto b/js/test5.proto
new file mode 100644
index 0000000..3497951
--- /dev/null
+++ b/js/test5.proto
@@ -0,0 +1,44 @@
+// 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.
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.exttest.beta;
+
+message TestBetaExtensionsMessage {
+  extensions 100 to max;
+}
+
+extend TestBetaExtensionsMessage {
+  optional string floating_str_field = 101;
+}
diff --git a/js/test_bootstrap.js b/js/test_bootstrap.js
new file mode 100644
index 0000000..9d00a1c
--- /dev/null
+++ b/js/test_bootstrap.js
@@ -0,0 +1,41 @@
+// 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.
+
+/**
+ * @fileoverview Sets flags for uncompiled JSUnit tests.
+ */
+
+/**
+ * Set uncompiled flags.
+ */
+var CLOSURE_DEFINES = {
+    // Enable the fromObject method on the message class.
+    'jspb.Message.GENERATE_FROM_OBJECT': true
+};
diff --git a/js/testbinary.proto b/js/testbinary.proto
new file mode 100644
index 0000000..60c7019
--- /dev/null
+++ b/js/testbinary.proto
@@ -0,0 +1,185 @@
+// 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.
+
+// LINT: ALLOW_GROUPS
+
+syntax = "proto2";
+
+
+package jspb.test;
+
+// These types are borrowed from `unittest.proto` in the protobuf tree. We want
+// to ensure that the binary-format support will handle all field types
+// properly.
+message TestAllTypes {
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Packed repeated
+  repeated    int32 packed_repeated_int32    = 61 [packed=true];
+  repeated    int64 packed_repeated_int64    = 62 [packed=true];
+  repeated   uint32 packed_repeated_uint32   = 63 [packed=true];
+  repeated   uint64 packed_repeated_uint64   = 64 [packed=true];
+  repeated   sint32 packed_repeated_sint32   = 65 [packed=true];
+  repeated   sint64 packed_repeated_sint64   = 66 [packed=true];
+  repeated  fixed32 packed_repeated_fixed32  = 67 [packed=true];
+  repeated  fixed64 packed_repeated_fixed64  = 68 [packed=true];
+  repeated sfixed32 packed_repeated_sfixed32 = 69 [packed=true];
+  repeated sfixed64 packed_repeated_sfixed64 = 70 [packed=true];
+  repeated    float packed_repeated_float    = 71 [packed=true];
+  repeated   double packed_repeated_double   = 72 [packed=true];
+  repeated     bool packed_repeated_bool     = 73 [packed=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    ForeignMessage oneof_foreign_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+
+}
+
+message ForeignMessage {
+  optional int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestExtendable {
+  extensions 1 to max;
+}
+
+message ExtendsWithMessage {
+  extend TestExtendable {
+    optional ExtendsWithMessage optional_extension = 19;
+    repeated ExtendsWithMessage repeated_extension = 49;
+  }
+  optional int32 foo = 1;
+}
+
+extend TestExtendable {
+  optional    int32 extend_optional_int32    =  1;
+  optional    int64 extend_optional_int64    =  2;
+  optional   uint32 extend_optional_uint32   =  3;
+  optional   uint64 extend_optional_uint64   =  4;
+  optional   sint32 extend_optional_sint32   =  5;
+  optional   sint64 extend_optional_sint64   =  6;
+  optional  fixed32 extend_optional_fixed32  =  7;
+  optional  fixed64 extend_optional_fixed64  =  8;
+  optional sfixed32 extend_optional_sfixed32 =  9;
+  optional sfixed64 extend_optional_sfixed64 = 10;
+  optional    float extend_optional_float    = 11;
+  optional   double extend_optional_double   = 12;
+  optional     bool extend_optional_bool     = 13;
+  optional   string extend_optional_string   = 14;
+  optional    bytes extend_optional_bytes    = 15;
+  optional ForeignEnum extend_optional_foreign_enum    = 22;
+
+  repeated    int32 extend_repeated_int32    = 31;
+  repeated    int64 extend_repeated_int64    = 32;
+  repeated   uint32 extend_repeated_uint32   = 33;
+  repeated   uint64 extend_repeated_uint64   = 34;
+  repeated   sint32 extend_repeated_sint32   = 35;
+  repeated   sint64 extend_repeated_sint64   = 36;
+  repeated  fixed32 extend_repeated_fixed32  = 37;
+  repeated  fixed64 extend_repeated_fixed64  = 38;
+  repeated sfixed32 extend_repeated_sfixed32 = 39;
+  repeated sfixed64 extend_repeated_sfixed64 = 40;
+  repeated    float extend_repeated_float    = 41;
+  repeated   double extend_repeated_double   = 42;
+  repeated     bool extend_repeated_bool     = 43;
+  repeated   string extend_repeated_string   = 44;
+  repeated    bytes extend_repeated_bytes    = 45;
+  repeated ForeignEnum extend_repeated_foreign_enum    = 52;
+
+  repeated    int32 extend_packed_repeated_int32    = 61 [packed=true];
+  repeated    int64 extend_packed_repeated_int64    = 62 [packed=true];
+  repeated   uint32 extend_packed_repeated_uint32   = 63 [packed=true];
+  repeated   uint64 extend_packed_repeated_uint64   = 64 [packed=true];
+  repeated   sint32 extend_packed_repeated_sint32   = 65 [packed=true];
+  repeated   sint64 extend_packed_repeated_sint64   = 66 [packed=true];
+  repeated  fixed32 extend_packed_repeated_fixed32  = 67 [packed=true];
+  repeated  fixed64 extend_packed_repeated_fixed64  = 68 [packed=true];
+  repeated sfixed32 extend_packed_repeated_sfixed32 = 69 [packed=true];
+  repeated sfixed64 extend_packed_repeated_sfixed64 = 70 [packed=true];
+  repeated    float extend_packed_repeated_float    = 71 [packed=true];
+  repeated   double extend_packed_repeated_double   = 72 [packed=true];
+  repeated     bool extend_packed_repeated_bool     = 73 [packed=true];
+  repeated ForeignEnum extend_packed_repeated_foreign_enum    = 82
+      [packed=true];
+
+}
diff --git a/js/testempty.proto b/js/testempty.proto
new file mode 100644
index 0000000..960bce4
--- /dev/null
+++ b/js/testempty.proto
@@ -0,0 +1,34 @@
+// 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.
+
+syntax = "proto2";
+
+package javatests.com.google.apps.jspb;
+
diff --git a/m4/acx_check_suncc.m4 b/m4/acx_check_suncc.m4
index 8918593..8bc0a89 100644
--- a/m4/acx_check_suncc.m4
+++ b/m4/acx_check_suncc.m4
@@ -42,7 +42,6 @@
 
         AS_IF([test "x$ac_enable_64bit" = "xyes"],[
 
-          AC_DEFINE([SOLARIS_64BIT_ENABLED], [1], [64bit enabled])
           AS_IF([test "x$libdir" = "x\${exec_prefix}/lib"],[
            dnl The user hasn't overridden the default libdir, so we'll
            dnl the dir suffix to match solaris 32/64-bit policy
@@ -52,17 +51,13 @@
           dnl This should just be set in CPPFLAGS and in LDFLAGS, but libtool
           dnl does the wrong thing if you don't put it into CXXFLAGS. sigh.
           dnl (It also needs it in CFLAGS, or it does a different wrong thing!)
-          AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"],[
-            CXXFLAGS="${CXXFLAGS} -m64"
-            ac_cv_env_CXXFLAGS_set=set
-            ac_cv_env_CXXFLAGS_value='-m64'
-          ])
+          CXXFLAGS="${CXXFLAGS} -m64"
+          ac_cv_env_CXXFLAGS_set=set
+          ac_cv_env_CXXFLAGS_value='-m64'
 
-          AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"],[
-            CFLAGS="${CFLAGS} -m64"
-            ac_cv_env_CFLAGS_set=set
-            ac_cv_env_CFLAGS_value='-m64'
-          ])
+          CFLAGS="${CFLAGS} -m64"
+          ac_cv_env_CFLAGS_set=set
+          ac_cv_env_CFLAGS_value='-m64'
 
           AS_IF([test "$target_cpu" = "sparc" -a "x$SUNCC" = "xyes" ],[
             CXXFLAGS="-xmemalign=8s ${CXXFLAGS}"
diff --git a/m4/libtool.m4 b/m4/libtool.m4
deleted file mode 100644
index d7c043f..0000000
--- a/m4/libtool.m4
+++ /dev/null
@@ -1,7997 +0,0 @@
-# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-#
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-#                 Foundation, Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-m4_define([_LT_COPYING], [dnl
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-#                 Foundation, Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-#   This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING.  If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-])
-
-# serial 57 LT_INIT
-
-
-# LT_PREREQ(VERSION)
-# ------------------
-# Complain and exit if this libtool version is less that VERSION.
-m4_defun([LT_PREREQ],
-[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
-       [m4_default([$3],
-		   [m4_fatal([Libtool version $1 or higher is required],
-		             63)])],
-       [$2])])
-
-
-# _LT_CHECK_BUILDDIR
-# ------------------
-# Complain if the absolute build directory name contains unusual characters
-m4_defun([_LT_CHECK_BUILDDIR],
-[case `pwd` in
-  *\ * | *\	*)
-    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
-esac
-])
-
-
-# LT_INIT([OPTIONS])
-# ------------------
-AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
-AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-AC_BEFORE([$0], [LT_LANG])dnl
-AC_BEFORE([$0], [LT_OUTPUT])dnl
-AC_BEFORE([$0], [LTDL_INIT])dnl
-m4_require([_LT_CHECK_BUILDDIR])dnl
-
-dnl Autoconf doesn't catch unexpanded LT_ macros by default:
-m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
-m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
-dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
-dnl unless we require an AC_DEFUNed macro:
-AC_REQUIRE([LTOPTIONS_VERSION])dnl
-AC_REQUIRE([LTSUGAR_VERSION])dnl
-AC_REQUIRE([LTVERSION_VERSION])dnl
-AC_REQUIRE([LTOBSOLETE_VERSION])dnl
-m4_require([_LT_PROG_LTMAIN])dnl
-
-_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
-
-dnl Parse OPTIONS
-_LT_SET_OPTIONS([$0], [$1])
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-_LT_SETUP
-
-# Only expand once:
-m4_define([LT_INIT])
-])# LT_INIT
-
-# Old names:
-AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
-AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
-dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
-
-
-# _LT_CC_BASENAME(CC)
-# -------------------
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
-m4_defun([_LT_CC_BASENAME],
-[for cc_temp in $1""; do
-  case $cc_temp in
-    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
-    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
-    \-*) ;;
-    *) break;;
-  esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-])
-
-
-# _LT_FILEUTILS_DEFAULTS
-# ----------------------
-# It is okay to use these file commands and assume they have been set
-# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
-m4_defun([_LT_FILEUTILS_DEFAULTS],
-[: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-])# _LT_FILEUTILS_DEFAULTS
-
-
-# _LT_SETUP
-# ---------
-m4_defun([_LT_SETUP],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-
-_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
-dnl
-_LT_DECL([], [host_alias], [0], [The host system])dnl
-_LT_DECL([], [host], [0])dnl
-_LT_DECL([], [host_os], [0])dnl
-dnl
-_LT_DECL([], [build_alias], [0], [The build system])dnl
-_LT_DECL([], [build], [0])dnl
-_LT_DECL([], [build_os], [0])dnl
-dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-test -z "$LN_S" && LN_S="ln -s"
-_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
-dnl
-AC_REQUIRE([LT_CMD_MAX_LEN])dnl
-_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
-_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
-dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
-m4_require([_LT_CMD_RELOAD])dnl
-m4_require([_LT_CHECK_MAGIC_METHOD])dnl
-m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
-m4_require([_LT_CMD_OLD_ARCHIVE])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_WITH_SYSROOT])dnl
-
-_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options which allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
-   setopt NO_GLOB_SUBST
-fi
-])
-if test -n "${ZSH_VERSION+set}" ; then
-   setopt NO_GLOB_SUBST
-fi
-
-_LT_CHECK_OBJDIR
-
-m4_require([_LT_TAG_COMPILER])dnl
-
-case $host_os in
-aix3*)
-  # AIX sometimes has problems with the GCC collect2 program.  For some
-  # reason, if we set the COLLECT_NAMES environment variable, the problems
-  # vanish in a puff of smoke.
-  if test "X${COLLECT_NAMES+set}" != Xset; then
-    COLLECT_NAMES=
-    export COLLECT_NAMES
-  fi
-  ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-_LT_CC_BASENAME([$compiler])
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
-  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    _LT_PATH_MAGIC
-  fi
-  ;;
-esac
-
-# Use C for the default configuration in the libtool script
-LT_SUPPORTED_TAG([CC])
-_LT_LANG_C_CONFIG
-_LT_LANG_DEFAULT_CONFIG
-_LT_CONFIG_COMMANDS
-])# _LT_SETUP
-
-
-# _LT_PREPARE_SED_QUOTE_VARS
-# --------------------------
-# Define a few sed substitution that help us do robust quoting.
-m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
-[# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([["`\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-])
-
-# _LT_PROG_LTMAIN
-# ---------------
-# Note that this code is called both from `configure', and `config.status'
-# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
-# `config.status' has no value for ac_aux_dir unless we are using Automake,
-# so we pass a copy along to make sure it has a sensible value anyway.
-m4_defun([_LT_PROG_LTMAIN],
-[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
-_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain="$ac_aux_dir/ltmain.sh"
-])# _LT_PROG_LTMAIN
-
-
-## ------------------------------------- ##
-## Accumulate code for creating libtool. ##
-## ------------------------------------- ##
-
-# So that we can recreate a full libtool script including additional
-# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the `libtool'
-# label.
-
-
-# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
-# ----------------------------------------
-# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL_INIT],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_INIT])
-
-
-# _LT_CONFIG_LIBTOOL([COMMANDS])
-# ------------------------------
-# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
-
-
-# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
-# -----------------------------------------------------
-m4_defun([_LT_CONFIG_SAVE_COMMANDS],
-[_LT_CONFIG_LIBTOOL([$1])
-_LT_CONFIG_LIBTOOL_INIT([$2])
-])
-
-
-# _LT_FORMAT_COMMENT([COMMENT])
-# -----------------------------
-# Add leading comment marks to the start of each line, and a trailing
-# full-stop to the whole comment if one is not present already.
-m4_define([_LT_FORMAT_COMMENT],
-[m4_ifval([$1], [
-m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
-              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
-)])
-
-
-
-## ------------------------ ##
-## FIXME: Eliminate VARNAME ##
-## ------------------------ ##
-
-
-# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
-# -------------------------------------------------------------------
-# CONFIGNAME is the name given to the value in the libtool script.
-# VARNAME is the (base) name used in the configure script.
-# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
-# VARNAME.  Any other value will be used directly.
-m4_define([_LT_DECL],
-[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
-    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
-	[m4_ifval([$1], [$1], [$2])])
-    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
-    m4_ifval([$4],
-	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
-    lt_dict_add_subkey([lt_decl_dict], [$2],
-	[tagged?], [m4_ifval([$5], [yes], [no])])])
-])
-
-
-# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
-# --------------------------------------------------------
-m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
-
-
-# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_tag_varnames],
-[_lt_decl_filter([tagged?], [yes], $@)])
-
-
-# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
-# ---------------------------------------------------------
-m4_define([_lt_decl_filter],
-[m4_case([$#],
-  [0], [m4_fatal([$0: too few arguments: $#])],
-  [1], [m4_fatal([$0: too few arguments: $#: $1])],
-  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
-  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
-  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
-])
-
-
-# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
-# --------------------------------------------------
-m4_define([lt_decl_quote_varnames],
-[_lt_decl_filter([value], [1], $@)])
-
-
-# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_dquote_varnames],
-[_lt_decl_filter([value], [2], $@)])
-
-
-# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_varnames_tagged],
-[m4_assert([$# <= 2])dnl
-_$0(m4_quote(m4_default([$1], [[, ]])),
-    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
-    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
-m4_define([_lt_decl_varnames_tagged],
-[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
-
-
-# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_all_varnames],
-[_$0(m4_quote(m4_default([$1], [[, ]])),
-     m4_if([$2], [],
-	   m4_quote(lt_decl_varnames),
-	m4_quote(m4_shift($@))))[]dnl
-])
-m4_define([_lt_decl_all_varnames],
-[lt_join($@, lt_decl_varnames_tagged([$1],
-			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
-])
-
-
-# _LT_CONFIG_STATUS_DECLARE([VARNAME])
-# ------------------------------------
-# Quote a variable value, and forward it to `config.status' so that its
-# declaration there will have the same value as in `configure'.  VARNAME
-# must have a single quote delimited value for this to work.
-m4_define([_LT_CONFIG_STATUS_DECLARE],
-[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
-
-
-# _LT_CONFIG_STATUS_DECLARATIONS
-# ------------------------------
-# We delimit libtool config variables with single quotes, so when
-# we write them to config.status, we have to be sure to quote all
-# embedded single quotes properly.  In configure, this macro expands
-# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
-#
-#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
-m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
-    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAGS
-# ----------------
-# Output comment and list of tags supported by the script
-m4_defun([_LT_LIBTOOL_TAGS],
-[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags="_LT_TAGS"dnl
-])
-
-
-# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
-# -----------------------------------
-# Extract the dictionary values for VARNAME (optionally with TAG) and
-# expand to a commented shell variable setting:
-#
-#    # Some comment about what VAR is for.
-#    visible_name=$lt_internal_name
-m4_define([_LT_LIBTOOL_DECLARE],
-[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
-					   [description])))[]dnl
-m4_pushdef([_libtool_name],
-    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
-m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
-    [0], [_libtool_name=[$]$1],
-    [1], [_libtool_name=$lt_[]$1],
-    [2], [_libtool_name=$lt_[]$1],
-    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
-m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
-])
-
-
-# _LT_LIBTOOL_CONFIG_VARS
-# -----------------------
-# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
-# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
-# section) are produced by _LT_LIBTOOL_TAG_VARS.
-m4_defun([_LT_LIBTOOL_CONFIG_VARS],
-[m4_foreach([_lt_var],
-    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAG_VARS(TAG)
-# -------------------------
-m4_define([_LT_LIBTOOL_TAG_VARS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
-
-
-# _LT_TAGVAR(VARNAME, [TAGNAME])
-# ------------------------------
-m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
-
-
-# _LT_CONFIG_COMMANDS
-# -------------------
-# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
-# variables for single and double quote escaping we saved from calls
-# to _LT_DECL, we can put quote escaped variables declarations
-# into `config.status', and then the shell code to quote escape them in
-# for loops in `config.status'.  Finally, any additional code accumulated
-# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
-m4_defun([_LT_CONFIG_COMMANDS],
-[AC_PROVIDE_IFELSE([LT_OUTPUT],
-	dnl If the libtool generation code has been placed in $CONFIG_LT,
-	dnl instead of duplicating it all over again into config.status,
-	dnl then we will have config.status run $CONFIG_LT later, so it
-	dnl needs to know what name is stored there:
-        [AC_CONFIG_COMMANDS([libtool],
-            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
-    dnl If the libtool generation code is destined for config.status,
-    dnl expand the accumulated commands and init code now:
-    [AC_CONFIG_COMMANDS([libtool],
-        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
-])#_LT_CONFIG_COMMANDS
-
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
-[
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-_LT_CONFIG_STATUS_DECLARATIONS
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-\$[]1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_quote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-# Double-quote double-evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_dquote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-_LT_OUTPUT_LIBTOOL_INIT
-])
-
-# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
-# ------------------------------------
-# Generate a child script FILE with all initialization necessary to
-# reuse the environment learned by the parent script, and make the
-# file executable.  If COMMENT is supplied, it is inserted after the
-# `#!' sequence but before initialization text begins.  After this
-# macro, additional text can be appended to FILE to form the body of
-# the child script.  The macro ends with non-zero status if the
-# file could not be fully written (such as if the disk is full).
-m4_ifdef([AS_INIT_GENERATED],
-[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
-[m4_defun([_LT_GENERATED_FILE_INIT],
-[m4_require([AS_PREPARE])]dnl
-[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
-[lt_write_fail=0
-cat >$1 <<_ASEOF || lt_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-$2
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$1 <<\_ASEOF || lt_write_fail=1
-AS_SHELL_SANITIZE
-_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-_ASEOF
-test $lt_write_fail = 0 && chmod +x $1[]dnl
-m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
-
-# LT_OUTPUT
-# ---------
-# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
-# tests.
-AC_DEFUN([LT_OUTPUT],
-[: ${CONFIG_LT=./config.lt}
-AC_MSG_NOTICE([creating $CONFIG_LT])
-_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
-[# Run this file to recreate a libtool stub with the current configuration.])
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-lt_cl_silent=false
-exec AS_MESSAGE_LOG_FD>>config.log
-{
-  echo
-  AS_BOX([Running $as_me.])
-} >&AS_MESSAGE_LOG_FD
-
-lt_cl_help="\
-\`$as_me' creates a local libtool stub from the current configuration,
-for use in further configure time tests before the real libtool is
-generated.
-
-Usage: $[0] [[OPTIONS]]
-
-  -h, --help      print this help, then exit
-  -V, --version   print version number, then exit
-  -q, --quiet     do not print progress messages
-  -d, --debug     don't remove temporary files
-
-Report bugs to <bug-libtool@gnu.org>."
-
-lt_cl_version="\
-m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
-m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
-configured by $[0], generated by m4_PACKAGE_STRING.
-
-Copyright (C) 2011 Free Software Foundation, Inc.
-This config.lt script is free software; the Free Software Foundation
-gives unlimited permision to copy, distribute and modify it."
-
-while test $[#] != 0
-do
-  case $[1] in
-    --version | --v* | -V )
-      echo "$lt_cl_version"; exit 0 ;;
-    --help | --h* | -h )
-      echo "$lt_cl_help"; exit 0 ;;
-    --debug | --d* | -d )
-      debug=: ;;
-    --quiet | --q* | --silent | --s* | -q )
-      lt_cl_silent=: ;;
-
-    -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try \`$[0] --help' for more information.]) ;;
-
-    *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try \`$[0] --help' for more information.]) ;;
-  esac
-  shift
-done
-
-if $lt_cl_silent; then
-  exec AS_MESSAGE_FD>/dev/null
-fi
-_LTEOF
-
-cat >>"$CONFIG_LT" <<_LTEOF
-_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
-_LTEOF
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-AC_MSG_NOTICE([creating $ofile])
-_LT_OUTPUT_LIBTOOL_COMMANDS
-AS_EXIT(0)
-_LTEOF
-chmod +x "$CONFIG_LT"
-
-# configure is writing to config.log, but config.lt does its own redirection,
-# appending to config.log, which fails on DOS, as config.log is still kept
-# open by configure.  Here we exec the FD to /dev/null, effectively closing
-# config.log, so it can be properly (re)opened and appended to by config.lt.
-lt_cl_success=:
-test "$silent" = yes &&
-  lt_config_lt_args="$lt_config_lt_args --quiet"
-exec AS_MESSAGE_LOG_FD>/dev/null
-$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
-exec AS_MESSAGE_LOG_FD>>config.log
-$lt_cl_success || AS_EXIT(1)
-])# LT_OUTPUT
-
-
-# _LT_CONFIG(TAG)
-# ---------------
-# If TAG is the built-in tag, create an initial libtool script with a
-# default configuration from the untagged config vars.  Otherwise add code
-# to config.status for appending the configuration named by TAG from the
-# matching tagged config vars.
-m4_defun([_LT_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_CONFIG_SAVE_COMMANDS([
-  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
-  m4_if(_LT_TAG, [C], [
-    # See if we are running on zsh, and set the options which allow our
-    # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}" ; then
-      setopt NO_GLOB_SUBST
-    fi
-
-    cfgfile="${ofile}T"
-    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
-    $RM "$cfgfile"
-
-    cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
-_LT_COPYING
-_LT_LIBTOOL_TAGS
-
-# ### BEGIN LIBTOOL CONFIG
-_LT_LIBTOOL_CONFIG_VARS
-_LT_LIBTOOL_TAG_VARS
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
-  case $host_os in
-  aix3*)
-    cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program.  For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
-  COLLECT_NAMES=
-  export COLLECT_NAMES
-fi
-_LT_EOF
-    ;;
-  esac
-
-  _LT_PROG_LTMAIN
-
-  # We use sed instead of cat because bash on DJGPP gets confused if
-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
-  # text mode, it properly converts lines to CR/LF.  This bash problem
-  # is reportedly fixed, but why not run on old versions too?
-  sed '$q' "$ltmain" >> "$cfgfile" \
-     || (rm -f "$cfgfile"; exit 1)
-
-  _LT_PROG_REPLACE_SHELLFNS
-
-   mv -f "$cfgfile" "$ofile" ||
-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
-  chmod +x "$ofile"
-],
-[cat <<_LT_EOF >> "$ofile"
-
-dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
-dnl in a comment (ie after a #).
-# ### BEGIN LIBTOOL TAG CONFIG: $1
-_LT_LIBTOOL_TAG_VARS(_LT_TAG)
-# ### END LIBTOOL TAG CONFIG: $1
-_LT_EOF
-])dnl /m4_if
-],
-[m4_if([$1], [], [
-    PACKAGE='$PACKAGE'
-    VERSION='$VERSION'
-    TIMESTAMP='$TIMESTAMP'
-    RM='$RM'
-    ofile='$ofile'], [])
-])dnl /_LT_CONFIG_SAVE_COMMANDS
-])# _LT_CONFIG
-
-
-# LT_SUPPORTED_TAG(TAG)
-# ---------------------
-# Trace this macro to discover what tags are supported by the libtool
-# --tag option, using:
-#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
-AC_DEFUN([LT_SUPPORTED_TAG], [])
-
-
-# C support is built-in for now
-m4_define([_LT_LANG_C_enabled], [])
-m4_define([_LT_TAGS], [])
-
-
-# LT_LANG(LANG)
-# -------------
-# Enable libtool support for the given language if not already enabled.
-AC_DEFUN([LT_LANG],
-[AC_BEFORE([$0], [LT_OUTPUT])dnl
-m4_case([$1],
-  [C],			[_LT_LANG(C)],
-  [C++],		[_LT_LANG(CXX)],
-  [Go],			[_LT_LANG(GO)],
-  [Java],		[_LT_LANG(GCJ)],
-  [Fortran 77],		[_LT_LANG(F77)],
-  [Fortran],		[_LT_LANG(FC)],
-  [Windows Resource],	[_LT_LANG(RC)],
-  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
-    [_LT_LANG($1)],
-    [m4_fatal([$0: unsupported language: "$1"])])])dnl
-])# LT_LANG
-
-
-# _LT_LANG(LANGNAME)
-# ------------------
-m4_defun([_LT_LANG],
-[m4_ifdef([_LT_LANG_]$1[_enabled], [],
-  [LT_SUPPORTED_TAG([$1])dnl
-  m4_append([_LT_TAGS], [$1 ])dnl
-  m4_define([_LT_LANG_]$1[_enabled], [])dnl
-  _LT_LANG_$1_CONFIG($1)])dnl
-])# _LT_LANG
-
-
-m4_ifndef([AC_PROG_GO], [
-############################################################
-# NOTE: This macro has been submitted for inclusion into   #
-#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
-#  a released version of Autoconf we should remove this    #
-#  macro and use it instead.                               #
-############################################################
-m4_defun([AC_PROG_GO],
-[AC_LANG_PUSH(Go)dnl
-AC_ARG_VAR([GOC],     [Go compiler command])dnl
-AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
-_AC_ARG_VAR_LDFLAGS()dnl
-AC_CHECK_TOOL(GOC, gccgo)
-if test -z "$GOC"; then
-  if test -n "$ac_tool_prefix"; then
-    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
-  fi
-fi
-if test -z "$GOC"; then
-  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
-fi
-])#m4_defun
-])#m4_ifndef
-
-
-# _LT_LANG_DEFAULT_CONFIG
-# -----------------------
-m4_defun([_LT_LANG_DEFAULT_CONFIG],
-[AC_PROVIDE_IFELSE([AC_PROG_CXX],
-  [LT_LANG(CXX)],
-  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_F77],
-  [LT_LANG(F77)],
-  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_FC],
-  [LT_LANG(FC)],
-  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
-
-dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
-dnl pulling things in needlessly.
-AC_PROVIDE_IFELSE([AC_PROG_GCJ],
-  [LT_LANG(GCJ)],
-  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
-    [LT_LANG(GCJ)],
-    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
-      [LT_LANG(GCJ)],
-      [m4_ifdef([AC_PROG_GCJ],
-	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([A][M_PROG_GCJ],
-	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([LT_PROG_GCJ],
-	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
-
-AC_PROVIDE_IFELSE([AC_PROG_GO],
-  [LT_LANG(GO)],
-  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
-
-AC_PROVIDE_IFELSE([LT_PROG_RC],
-  [LT_LANG(RC)],
-  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
-])# _LT_LANG_DEFAULT_CONFIG
-
-# Obsolete macros:
-AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
-AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
-AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
-AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
-AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
-dnl AC_DEFUN([AC_LIBTOOL_F77], [])
-dnl AC_DEFUN([AC_LIBTOOL_FC], [])
-dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
-dnl AC_DEFUN([AC_LIBTOOL_RC], [])
-
-
-# _LT_TAG_COMPILER
-# ----------------
-m4_defun([_LT_TAG_COMPILER],
-[AC_REQUIRE([AC_PROG_CC])dnl
-
-_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
-_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
-_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-])# _LT_TAG_COMPILER
-
-
-# _LT_COMPILER_BOILERPLATE
-# ------------------------
-# Check for compiler boilerplate output or warnings with
-# the simple compiler test code.
-m4_defun([_LT_COMPILER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-])# _LT_COMPILER_BOILERPLATE
-
-
-# _LT_LINKER_BOILERPLATE
-# ----------------------
-# Check for linker boilerplate output or warnings with
-# the simple link test code.
-m4_defun([_LT_LINKER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-])# _LT_LINKER_BOILERPLATE
-
-# _LT_REQUIRED_DARWIN_CHECKS
-# -------------------------
-m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
-  case $host_os in
-    rhapsody* | darwin*)
-    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
-    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
-    AC_CHECK_TOOL([LIPO], [lipo], [:])
-    AC_CHECK_TOOL([OTOOL], [otool], [:])
-    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
-    _LT_DECL([], [DSYMUTIL], [1],
-      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
-    _LT_DECL([], [NMEDIT], [1],
-      [Tool to change global to local symbols on Mac OS X])
-    _LT_DECL([], [LIPO], [1],
-      [Tool to manipulate fat objects and archives on Mac OS X])
-    _LT_DECL([], [OTOOL], [1],
-      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
-    _LT_DECL([], [OTOOL64], [1],
-      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
-
-    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
-      [lt_cv_apple_cc_single_mod=no
-      if test -z "${LT_MULTI_MODULE}"; then
-	# By default we will add the -single_module flag. You can override
-	# by either setting the environment variable LT_MULTI_MODULE
-	# non-empty at configure time, or by adding -multi_module to the
-	# link flags.
-	rm -rf libconftest.dylib*
-	echo "int foo(void){return 1;}" > conftest.c
-	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
-	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
-        _lt_result=$?
-	# If there is a non-empty error log, and "single_module"
-	# appears in it, assume the flag caused a linker warning
-        if test -s conftest.err && $GREP single_module conftest.err; then
-	  cat conftest.err >&AS_MESSAGE_LOG_FD
-	# Otherwise, if the output was created with a 0 exit code from
-	# the compiler, it worked.
-	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
-	  lt_cv_apple_cc_single_mod=yes
-	else
-	  cat conftest.err >&AS_MESSAGE_LOG_FD
-	fi
-	rm -rf libconftest.dylib*
-	rm -f conftest.*
-      fi])
-
-    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
-      [lt_cv_ld_exported_symbols_list],
-      [lt_cv_ld_exported_symbols_list=no
-      save_LDFLAGS=$LDFLAGS
-      echo "_main" > conftest.sym
-      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
-      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-	[lt_cv_ld_exported_symbols_list=yes],
-	[lt_cv_ld_exported_symbols_list=no])
-	LDFLAGS="$save_LDFLAGS"
-    ])
-
-    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
-      [lt_cv_ld_force_load=no
-      cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
-      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
-      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
-      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
-      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
-      cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
-      _lt_result=$?
-      if test -s conftest.err && $GREP force_load conftest.err; then
-	cat conftest.err >&AS_MESSAGE_LOG_FD
-      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
-	lt_cv_ld_force_load=yes
-      else
-	cat conftest.err >&AS_MESSAGE_LOG_FD
-      fi
-        rm -f conftest.err libconftest.a conftest conftest.c
-        rm -rf conftest.dSYM
-    ])
-    case $host_os in
-    rhapsody* | darwin1.[[012]])
-      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
-    darwin1.*)
-      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-    darwin*) # darwin 5.x on
-      # if running on 10.5 or later, the deployment target defaults
-      # to the OS version, if on x86, and 10.4, the deployment
-      # target defaults to 10.4. Don't you love it?
-      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-	10.[[012]]*)
-	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-	10.*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-      esac
-    ;;
-  esac
-    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
-      _lt_dar_single_mod='$single_module'
-    fi
-    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
-      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
-    else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
-    fi
-    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
-      _lt_dsymutil='~$DSYMUTIL $lib || :'
-    else
-      _lt_dsymutil=
-    fi
-    ;;
-  esac
-])
-
-
-# _LT_DARWIN_LINKER_FEATURES([TAG])
-# ---------------------------------
-# Checks for linker and compiler features on darwin
-m4_defun([_LT_DARWIN_LINKER_FEATURES],
-[
-  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_automatic, $1)=yes
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  if test "$lt_cv_ld_force_load" = "yes"; then
-    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
-    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
-                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
-  else
-    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
-  fi
-  _LT_TAGVAR(link_all_deplibs, $1)=yes
-  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
-  case $cc_basename in
-     ifort*) _lt_dar_can_shared=yes ;;
-     *) _lt_dar_can_shared=$GCC ;;
-  esac
-  if test "$_lt_dar_can_shared" = "yes"; then
-    output_verbose_link_cmd=func_echo_all
-    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
-    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
-    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
-    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
-    m4_if([$1], [CXX],
-[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
-      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
-      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
-    fi
-],[])
-  else
-  _LT_TAGVAR(ld_shlibs, $1)=no
-  fi
-])
-
-# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
-# ----------------------------------
-# Links a minimal program and checks the executable
-# for the system default hardcoded library path. In most cases,
-# this is /usr/lib:/lib, but when the MPI compilers are used
-# the location of the communication and MPI libs are included too.
-# If we don't find anything, use the default library path according
-# to the aix ld manual.
-# Store the results from the different compilers for each TAGNAME.
-# Allow to override them for all tags through lt_cv_aix_libpath.
-m4_defun([_LT_SYS_MODULE_PATH_AIX],
-[m4_require([_LT_DECL_SED])dnl
-if test "${lt_cv_aix_libpath+set}" = set; then
-  aix_libpath=$lt_cv_aix_libpath
-else
-  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
-  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
-  lt_aix_libpath_sed='[
-      /Import File Strings/,/^$/ {
-	  /^0/ {
-	      s/^0  *\([^ ]*\) *$/\1/
-	      p
-	  }
-      }]'
-  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  # Check for a 64-bit object if we didn't find anything.
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  fi],[])
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
-  fi
-  ])
-  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
-fi
-])# _LT_SYS_MODULE_PATH_AIX
-
-
-# _LT_SHELL_INIT(ARG)
-# -------------------
-m4_define([_LT_SHELL_INIT],
-[m4_divert_text([M4SH-INIT], [$1
-])])# _LT_SHELL_INIT
-
-
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# Find how we can fake an echo command that does not interpret backslash.
-# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script which will find a shell with a builtin
-# printf (which we can use as an echo command).
-m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-AC_MSG_CHECKING([how to print strings])
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
-   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='printf %s\n'
-else
-  # Use this function as a fallback that always works.
-  func_fallback_echo ()
-  {
-    eval 'cat <<_LTECHO_EOF
-$[]1
-_LTECHO_EOF'
-  }
-  ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO "$*" 
-}
-
-case "$ECHO" in
-  printf*) AC_MSG_RESULT([printf]) ;;
-  print*) AC_MSG_RESULT([print -r]) ;;
-  *) AC_MSG_RESULT([cat]) ;;
-esac
-
-m4_ifdef([_AS_DETECT_SUGGESTED],
-[_AS_DETECT_SUGGESTED([
-  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
-    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-    PATH=/empty FPATH=/empty; export PATH FPATH
-    test "X`printf %s $ECHO`" = "X$ECHO" \
-      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
-
-_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
-])# _LT_PROG_ECHO_BACKSLASH
-
-
-# _LT_WITH_SYSROOT
-# ----------------
-AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
-AC_ARG_WITH([sysroot],
-[  --with-sysroot[=DIR] Search for dependent libraries within DIR
-                        (or the compiler's sysroot if not specified).],
-[], [with_sysroot=no])
-
-dnl lt_sysroot will always be passed unquoted.  We quote it here
-dnl in case the user passed a directory name.
-lt_sysroot=
-case ${with_sysroot} in #(
- yes)
-   if test "$GCC" = yes; then
-     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
-   fi
-   ;; #(
- /*)
-   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
-   ;; #(
- no|'')
-   ;; #(
- *)
-   AC_MSG_RESULT([${with_sysroot}])
-   AC_MSG_ERROR([The sysroot must be an absolute path.])
-   ;;
-esac
-
- AC_MSG_RESULT([${lt_sysroot:-no}])
-_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and in which our libraries should be installed.])])
-
-# _LT_ENABLE_LOCK
-# ---------------
-m4_defun([_LT_ENABLE_LOCK],
-[AC_ARG_ENABLE([libtool-lock],
-  [AS_HELP_STRING([--disable-libtool-lock],
-    [avoid locking (might break parallel builds)])])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.$ac_objext` in
-      *ELF-32*)
-	HPUX_IA64_MODE="32"
-	;;
-      *ELF-64*)
-	HPUX_IA64_MODE="64"
-	;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-*-*-irix6*)
-  # Find out which ABI we are using.
-  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    if test "$lt_cv_prog_gnu_ld" = yes; then
-      case `/usr/bin/file conftest.$ac_objext` in
-	*32-bit*)
-	  LD="${LD-ld} -melf32bsmip"
-	  ;;
-	*N32*)
-	  LD="${LD-ld} -melf32bmipn32"
-	  ;;
-	*64-bit*)
-	  LD="${LD-ld} -melf64bmip"
-	;;
-      esac
-    else
-      case `/usr/bin/file conftest.$ac_objext` in
-	*32-bit*)
-	  LD="${LD-ld} -32"
-	  ;;
-	*N32*)
-	  LD="${LD-ld} -n32"
-	  ;;
-	*64-bit*)
-	  LD="${LD-ld} -64"
-	  ;;
-      esac
-    fi
-  fi
-  rm -rf conftest*
-  ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-      *32-bit*)
-	case $host in
-	  x86_64-*kfreebsd*-gnu)
-	    LD="${LD-ld} -m elf_i386_fbsd"
-	    ;;
-	  x86_64-*linux*)
-	    case `/usr/bin/file conftest.o` in
-	      *x86-64*)
-		LD="${LD-ld} -m elf32_x86_64"
-		;;
-	      *)
-		LD="${LD-ld} -m elf_i386"
-		;;
-	    esac
-	    ;;
-	  powerpc64le-*)
-	    LD="${LD-ld} -m elf32lppclinux"
-	    ;;
-	  powerpc64-*)
-	    LD="${LD-ld} -m elf32ppclinux"
-	    ;;
-	  s390x-*linux*)
-	    LD="${LD-ld} -m elf_s390"
-	    ;;
-	  sparc64-*linux*)
-	    LD="${LD-ld} -m elf32_sparc"
-	    ;;
-	esac
-	;;
-      *64-bit*)
-	case $host in
-	  x86_64-*kfreebsd*-gnu)
-	    LD="${LD-ld} -m elf_x86_64_fbsd"
-	    ;;
-	  x86_64-*linux*)
-	    LD="${LD-ld} -m elf_x86_64"
-	    ;;
-	  powerpcle-*)
-	    LD="${LD-ld} -m elf64lppc"
-	    ;;
-	  powerpc-*)
-	    LD="${LD-ld} -m elf64ppc"
-	    ;;
-	  s390*-*linux*|s390*-*tpf*)
-	    LD="${LD-ld} -m elf64_s390"
-	    ;;
-	  sparc*-*linux*)
-	    LD="${LD-ld} -m elf64_sparc"
-	    ;;
-	esac
-	;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-
-*-*-sco3.2v5*)
-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -belf"
-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
-    [AC_LANG_PUSH(C)
-     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
-     AC_LANG_POP])
-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS="$SAVE_CFLAGS"
-  fi
-  ;;
-*-*solaris*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-    *64-bit*)
-      case $lt_cv_prog_gnu_ld in
-      yes*)
-        case $host in
-        i?86-*-solaris*)
-          LD="${LD-ld} -m elf_x86_64"
-          ;;
-        sparc*-*-solaris*)
-          LD="${LD-ld} -m elf64_sparc"
-          ;;
-        esac
-        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
-        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
-          LD="${LD-ld}_sol2"
-        fi
-        ;;
-      *)
-	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
-	  LD="${LD-ld} -64"
-	fi
-	;;
-      esac
-      ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-esac
-
-need_locks="$enable_libtool_lock"
-])# _LT_ENABLE_LOCK
-
-
-# _LT_PROG_AR
-# -----------
-m4_defun([_LT_PROG_AR],
-[AC_CHECK_TOOLS(AR, [ar], false)
-: ${AR=ar}
-: ${AR_FLAGS=cru}
-_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
-
-AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
-  [lt_cv_ar_at_file=no
-   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
-     [echo conftest.$ac_objext > conftest.lst
-      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
-      AC_TRY_EVAL([lt_ar_try])
-      if test "$ac_status" -eq 0; then
-	# Ensure the archiver fails upon bogus file names.
-	rm -f conftest.$ac_objext libconftest.a
-	AC_TRY_EVAL([lt_ar_try])
-	if test "$ac_status" -ne 0; then
-          lt_cv_ar_at_file=@
-        fi
-      fi
-      rm -f conftest.* libconftest.a
-     ])
-  ])
-
-if test "x$lt_cv_ar_at_file" = xno; then
-  archiver_list_spec=
-else
-  archiver_list_spec=$lt_cv_ar_at_file
-fi
-_LT_DECL([], [archiver_list_spec], [1],
-  [How to feed a file listing to the archiver])
-])# _LT_PROG_AR
-
-
-# _LT_CMD_OLD_ARCHIVE
-# -------------------
-m4_defun([_LT_CMD_OLD_ARCHIVE],
-[_LT_PROG_AR
-
-AC_CHECK_TOOL(STRIP, strip, :)
-test -z "$STRIP" && STRIP=:
-_LT_DECL([], [STRIP], [1], [A symbol stripping program])
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-test -z "$RANLIB" && RANLIB=:
-_LT_DECL([], [RANLIB], [1],
-    [Commands used to install an old-style archive])
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
-  case $host_os in
-  openbsd*)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
-    ;;
-  *)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
-    ;;
-  esac
-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
-  darwin*)
-    lock_old_archive_extraction=yes ;;
-  *)
-    lock_old_archive_extraction=no ;;
-esac
-_LT_DECL([], [old_postinstall_cmds], [2])
-_LT_DECL([], [old_postuninstall_cmds], [2])
-_LT_TAGDECL([], [old_archive_cmds], [2],
-    [Commands used to build an old-style archive])
-_LT_DECL([], [lock_old_archive_extraction], [0],
-    [Whether to use a lock for old archive extraction])
-])# _LT_CMD_OLD_ARCHIVE
-
-
-# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------------------
-# Check whether the given compiler option works
-AC_DEFUN([_LT_COMPILER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$3"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   # The option is referenced via a variable to avoid confusing sed.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>conftest.err)
-   ac_status=$?
-   cat conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s "$ac_outfile"; then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings other than the usual output.
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
-       $2=yes
-     fi
-   fi
-   $RM conftest*
-])
-
-if test x"[$]$2" = xyes; then
-    m4_if([$5], , :, [$5])
-else
-    m4_if([$6], , :, [$6])
-fi
-])# _LT_COMPILER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
-
-
-# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#                  [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------
-# Check whether the given linker option works
-AC_DEFUN([_LT_LINKER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   save_LDFLAGS="$LDFLAGS"
-   LDFLAGS="$LDFLAGS $3"
-   echo "$lt_simple_link_test_code" > conftest.$ac_ext
-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
-     # The linker can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     if test -s conftest.err; then
-       # Append any errors to the config.log.
-       cat conftest.err 1>&AS_MESSAGE_LOG_FD
-       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-       if diff conftest.exp conftest.er2 >/dev/null; then
-         $2=yes
-       fi
-     else
-       $2=yes
-     fi
-   fi
-   $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
-])
-
-if test x"[$]$2" = xyes; then
-    m4_if([$4], , :, [$4])
-else
-    m4_if([$5], , :, [$5])
-fi
-])# _LT_LINKER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
-
-
-# LT_CMD_MAX_LEN
-#---------------
-AC_DEFUN([LT_CMD_MAX_LEN],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-# find the maximum length of command line arguments
-AC_MSG_CHECKING([the maximum length of command line arguments])
-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
-  i=0
-  teststring="ABCD"
-
-  case $build_os in
-  msdosdjgpp*)
-    # On DJGPP, this test can blow up pretty badly due to problems in libc
-    # (any single argument exceeding 2000 bytes causes a buffer overrun
-    # during glob expansion).  Even if it were fixed, the result of this
-    # check would be larger than it should be.
-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
-    ;;
-
-  gnu*)
-    # Under GNU Hurd, this test is not required because there is
-    # no limit to the length of command line arguments.
-    # Libtool will interpret -1 as no limit whatsoever
-    lt_cv_sys_max_cmd_len=-1;
-    ;;
-
-  cygwin* | mingw* | cegcc*)
-    # On Win9x/ME, this test blows up -- it succeeds, but takes
-    # about 5 minutes as the teststring grows exponentially.
-    # Worse, since 9x/ME are not pre-emptively multitasking,
-    # you end up with a "frozen" computer, even though with patience
-    # the test eventually succeeds (with a max line length of 256k).
-    # Instead, let's just punt: use the minimum linelength reported by
-    # all of the supported platforms: 8192 (on NT/2K/XP).
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  mint*)
-    # On MiNT this can take a long time and run out of memory.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  amigaos*)
-    # On AmigaOS with pdksh, this test takes hours, literally.
-    # So we just punt and use a minimum line length of 8192.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
-    # This has been around since 386BSD, at least.  Likely further.
-    if test -x /sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
-    elif test -x /usr/sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
-    else
-      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
-    fi
-    # And add a safety zone
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    ;;
-
-  interix*)
-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
-    lt_cv_sys_max_cmd_len=196608
-    ;;
-
-  os2*)
-    # The test takes a long time on OS/2.
-    lt_cv_sys_max_cmd_len=8192
-    ;;
-
-  osf*)
-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
-    # nice to cause kernel panics so lets avoid the loop below.
-    # First set a reasonable default.
-    lt_cv_sys_max_cmd_len=16384
-    #
-    if test -x /sbin/sysconfig; then
-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
-      esac
-    fi
-    ;;
-  sco3.2v5*)
-    lt_cv_sys_max_cmd_len=102400
-    ;;
-  sysv5* | sco5v6* | sysv4.2uw2*)
-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
-    if test -n "$kargmax"; then
-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
-    else
-      lt_cv_sys_max_cmd_len=32768
-    fi
-    ;;
-  *)
-    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
-    if test -n "$lt_cv_sys_max_cmd_len" && \
-	test undefined != "$lt_cv_sys_max_cmd_len"; then
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    else
-      # Make teststring a little bigger before we do anything with it.
-      # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8 ; do
-        teststring=$teststring$teststring
-      done
-      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
-      # If test is not a shell built-in, we'll probably end up computing a
-      # maximum length that is only half of the actual maximum length, but
-      # we can't tell.
-      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
-	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-	      test $i != 17 # 1/2 MB should be enough
-      do
-        i=`expr $i + 1`
-        teststring=$teststring$teststring
-      done
-      # Only check the string length outside the loop.
-      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
-      teststring=
-      # Add a significant safety factor because C++ compilers can tack on
-      # massive amounts of additional arguments before passing them to the
-      # linker.  It appears as though 1/2 is a usable value.
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
-    fi
-    ;;
-  esac
-])
-if test -n $lt_cv_sys_max_cmd_len ; then
-  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
-else
-  AC_MSG_RESULT(none)
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-_LT_DECL([], [max_cmd_len], [0],
-    [What is the maximum length of a command?])
-])# LT_CMD_MAX_LEN
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
-
-
-# _LT_HEADER_DLFCN
-# ----------------
-m4_defun([_LT_HEADER_DLFCN],
-[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
-])# _LT_HEADER_DLFCN
-
-
-# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ----------------------------------------------------------------
-m4_defun([_LT_TRY_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test "$cross_compiling" = yes; then :
-  [$4]
-else
-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-  lt_status=$lt_dlunknown
-  cat > conftest.$ac_ext <<_LT_EOF
-[#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-#  define LT_DLGLOBAL		RTLD_GLOBAL
-#else
-#  ifdef DL_GLOBAL
-#    define LT_DLGLOBAL		DL_GLOBAL
-#  else
-#    define LT_DLGLOBAL		0
-#  endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
-   find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-#  ifdef RTLD_LAZY
-#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
-#  else
-#    ifdef DL_LAZY
-#      define LT_DLLAZY_OR_NOW		DL_LAZY
-#    else
-#      ifdef RTLD_NOW
-#        define LT_DLLAZY_OR_NOW	RTLD_NOW
-#      else
-#        ifdef DL_NOW
-#          define LT_DLLAZY_OR_NOW	DL_NOW
-#        else
-#          define LT_DLLAZY_OR_NOW	0
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-
-/* When -fvisbility=hidden is used, assume the code has been annotated
-   correspondingly for the symbols needed.  */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
-  int status = $lt_dlunknown;
-
-  if (self)
-    {
-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else
-        {
-	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
-          else puts (dlerror ());
-	}
-      /* dlclose (self); */
-    }
-  else
-    puts (dlerror ());
-
-  return status;
-}]
-_LT_EOF
-  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
-    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
-    lt_status=$?
-    case x$lt_status in
-      x$lt_dlno_uscore) $1 ;;
-      x$lt_dlneed_uscore) $2 ;;
-      x$lt_dlunknown|x*) $3 ;;
-    esac
-  else :
-    # compilation failed
-    $3
-  fi
-fi
-rm -fr conftest*
-])# _LT_TRY_DLOPEN_SELF
-
-
-# LT_SYS_DLOPEN_SELF
-# ------------------
-AC_DEFUN([LT_SYS_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test "x$enable_dlopen" != xyes; then
-  enable_dlopen=unknown
-  enable_dlopen_self=unknown
-  enable_dlopen_self_static=unknown
-else
-  lt_cv_dlopen=no
-  lt_cv_dlopen_libs=
-
-  case $host_os in
-  beos*)
-    lt_cv_dlopen="load_add_on"
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ;;
-
-  mingw* | pw32* | cegcc*)
-    lt_cv_dlopen="LoadLibrary"
-    lt_cv_dlopen_libs=
-    ;;
-
-  cygwin*)
-    lt_cv_dlopen="dlopen"
-    lt_cv_dlopen_libs=
-    ;;
-
-  darwin*)
-  # if libdl is installed we need to link against it
-    AC_CHECK_LIB([dl], [dlopen],
-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
-    lt_cv_dlopen="dyld"
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ])
-    ;;
-
-  *)
-    AC_CHECK_FUNC([shl_load],
-	  [lt_cv_dlopen="shl_load"],
-      [AC_CHECK_LIB([dld], [shl_load],
-	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
-	[AC_CHECK_FUNC([dlopen],
-	      [lt_cv_dlopen="dlopen"],
-	  [AC_CHECK_LIB([dl], [dlopen],
-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
-	    [AC_CHECK_LIB([svld], [dlopen],
-		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
-	      [AC_CHECK_LIB([dld], [dld_link],
-		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
-	      ])
-	    ])
-	  ])
-	])
-      ])
-    ;;
-  esac
-
-  if test "x$lt_cv_dlopen" != xno; then
-    enable_dlopen=yes
-  else
-    enable_dlopen=no
-  fi
-
-  case $lt_cv_dlopen in
-  dlopen)
-    save_CPPFLAGS="$CPPFLAGS"
-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
-    save_LDFLAGS="$LDFLAGS"
-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
-    save_LIBS="$LIBS"
-    LIBS="$lt_cv_dlopen_libs $LIBS"
-
-    AC_CACHE_CHECK([whether a program can dlopen itself],
-	  lt_cv_dlopen_self, [dnl
-	  _LT_TRY_DLOPEN_SELF(
-	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
-	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
-    ])
-
-    if test "x$lt_cv_dlopen_self" = xyes; then
-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
-      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
-	  lt_cv_dlopen_self_static, [dnl
-	  _LT_TRY_DLOPEN_SELF(
-	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
-	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
-      ])
-    fi
-
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-    LIBS="$save_LIBS"
-    ;;
-  esac
-
-  case $lt_cv_dlopen_self in
-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
-  *) enable_dlopen_self=unknown ;;
-  esac
-
-  case $lt_cv_dlopen_self_static in
-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
-  *) enable_dlopen_self_static=unknown ;;
-  esac
-fi
-_LT_DECL([dlopen_support], [enable_dlopen], [0],
-	 [Whether dlopen is supported])
-_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
-	 [Whether dlopen of programs is supported])
-_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
-	 [Whether dlopen of statically linked programs is supported])
-])# LT_SYS_DLOPEN_SELF
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
-
-
-# _LT_COMPILER_C_O([TAGNAME])
-# ---------------------------
-# Check to see if options -c and -o are simultaneously supported by compiler.
-# This macro does not hard code the compiler like AC_PROG_CC_C_O.
-m4_defun([_LT_COMPILER_C_O],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
-   $RM -r conftest 2>/dev/null
-   mkdir conftest
-   cd conftest
-   mkdir out
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-   lt_compiler_flag="-o out/conftest2.$ac_objext"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>out/conftest.err)
-   ac_status=$?
-   cat out/conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
-   then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
-       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-     fi
-   fi
-   chmod u+w . 2>&AS_MESSAGE_LOG_FD
-   $RM conftest*
-   # SGI C++ compiler will create directory out/ii_files/ for
-   # template instantiation
-   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
-   $RM out/* && rmdir out
-   cd ..
-   $RM -r conftest
-   $RM conftest*
-])
-_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
-	[Does compiler simultaneously support -c and -o options?])
-])# _LT_COMPILER_C_O
-
-
-# _LT_COMPILER_FILE_LOCKS([TAGNAME])
-# ----------------------------------
-# Check to see if we can do hard links to lock some files if needed
-m4_defun([_LT_COMPILER_FILE_LOCKS],
-[m4_require([_LT_ENABLE_LOCK])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_COMPILER_C_O([$1])
-
-hard_links="nottested"
-if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
-  # do not overwrite the value of need_locks provided by the user
-  AC_MSG_CHECKING([if we can lock with hard links])
-  hard_links=yes
-  $RM conftest*
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  touch conftest.a
-  ln conftest.a conftest.b 2>&5 || hard_links=no
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  AC_MSG_RESULT([$hard_links])
-  if test "$hard_links" = no; then
-    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
-    need_locks=warn
-  fi
-else
-  need_locks=no
-fi
-_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
-])# _LT_COMPILER_FILE_LOCKS
-
-
-# _LT_CHECK_OBJDIR
-# ----------------
-m4_defun([_LT_CHECK_OBJDIR],
-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
-[rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
-  lt_cv_objdir=.libs
-else
-  # MS-DOS does not allow filenames that begin with a dot.
-  lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null])
-objdir=$lt_cv_objdir
-_LT_DECL([], [objdir], [0],
-         [The name of the directory that contains temporary libtool files])dnl
-m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
-  [Define to the sub-directory in which libtool stores uninstalled libraries.])
-])# _LT_CHECK_OBJDIR
-
-
-# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
-# --------------------------------------
-# Check hardcoding attributes.
-m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
-[AC_MSG_CHECKING([how to hardcode library paths into programs])
-_LT_TAGVAR(hardcode_action, $1)=
-if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
-   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
-   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
-
-  # We can hardcode non-existent directories.
-  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
-     # have to relink, otherwise we might link with an installed library
-     # when we should be linking with a yet-to-be-installed one
-     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
-     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
-    # Linking always hardcodes the temporary library directory.
-    _LT_TAGVAR(hardcode_action, $1)=relink
-  else
-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
-    _LT_TAGVAR(hardcode_action, $1)=immediate
-  fi
-else
-  # We cannot hardcode anything, or else we can only hardcode existing
-  # directories.
-  _LT_TAGVAR(hardcode_action, $1)=unsupported
-fi
-AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-
-if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
-   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
-  # Fast installation is not supported
-  enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
-  # Fast installation is not necessary
-  enable_fast_install=needless
-fi
-_LT_TAGDECL([], [hardcode_action], [0],
-    [How to hardcode a shared library path into an executable])
-])# _LT_LINKER_HARDCODE_LIBPATH
-
-
-# _LT_CMD_STRIPLIB
-# ----------------
-m4_defun([_LT_CMD_STRIPLIB],
-[m4_require([_LT_DECL_EGREP])
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  AC_MSG_RESULT([yes])
-else
-# FIXME - insert some real tests, host_os isn't really good enough
-  case $host_os in
-  darwin*)
-    if test -n "$STRIP" ; then
-      striplib="$STRIP -x"
-      old_striplib="$STRIP -S"
-      AC_MSG_RESULT([yes])
-    else
-      AC_MSG_RESULT([no])
-    fi
-    ;;
-  *)
-    AC_MSG_RESULT([no])
-    ;;
-  esac
-fi
-_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
-_LT_DECL([], [striplib], [1])
-])# _LT_CMD_STRIPLIB
-
-
-# _LT_SYS_DYNAMIC_LINKER([TAG])
-# -----------------------------
-# PORTME Fill in your ld.so characteristics
-m4_defun([_LT_SYS_DYNAMIC_LINKER],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_OBJDUMP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-AC_MSG_CHECKING([dynamic linker characteristics])
-m4_if([$1],
-	[], [
-if test "$GCC" = yes; then
-  case $host_os in
-    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
-    *) lt_awk_arg="/^libraries:/" ;;
-  esac
-  case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
-    *) lt_sed_strip_eq="s,=/,/,g" ;;
-  esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
-  case $lt_search_path_spec in
-  *\;*)
-    # if the path contains ";" then we assume it to be the separator
-    # otherwise default to the standard path separator (i.e. ":") - it is
-    # assumed that no part of a normal pathname contains ";" but that should
-    # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
-    ;;
-  *)
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
-    ;;
-  esac
-  # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary.
-  lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
-  for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
-    else
-      test -d "$lt_sys_path" && \
-	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
-    fi
-  done
-  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
-  lt_foo="";
-  lt_count=0;
-  for (lt_i = NF; lt_i > 0; lt_i--) {
-    if ($lt_i != "" && $lt_i != ".") {
-      if ($lt_i == "..") {
-        lt_count++;
-      } else {
-        if (lt_count == 0) {
-          lt_foo="/" $lt_i lt_foo;
-        } else {
-          lt_count--;
-        }
-      }
-    }
-  }
-  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
-  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
-}'`
-  # AWK program above erroneously prepends '/' to C:/dos/paths
-  # for these hosts.
-  case $host_os in
-    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
-  esac
-  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=".so"
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-case $host_os in
-aix3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
-  shlibpath_var=LIBPATH
-
-  # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}${shared_ext}$major'
-  ;;
-
-aix[[4-9]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  hardcode_into_libs=yes
-  if test "$host_cpu" = ia64; then
-    # AIX 5 supports IA64
-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
-    shlibpath_var=LD_LIBRARY_PATH
-  else
-    # With GCC up to 2.95.x, collect2 would create an import file
-    # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
-    # development snapshots of GCC prior to 3.0.
-    case $host_os in
-      aix4 | aix4.[[01]] | aix4.[[01]].*)
-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
-	   echo ' yes '
-	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
-	:
-      else
-	can_build_shared=no
-      fi
-      ;;
-    esac
-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
-    # soname into executable. Probably we can add versioning support to
-    # collect2, so additional links can be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
-      # instead of lib<name>.a to let people know that these are not
-      # typical AIX shared libraries.
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    else
-      # We preserve .a as extension for shared libraries through AIX4.2
-      # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}${shared_ext}$major'
-    fi
-    shlibpath_var=LIBPATH
-  fi
-  ;;
-
-amigaos*)
-  case $host_cpu in
-  powerpc)
-    # Since July 2007 AmigaOS4 officially supports .so libraries.
-    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    ;;
-  m68k)
-    library_names_spec='$libname.ixlibrary $libname.a'
-    # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
-    ;;
-  esac
-  ;;
-
-beos*)
-  library_names_spec='${libname}${shared_ext}'
-  dynamic_linker="$host_os ld.so"
-  shlibpath_var=LIBRARY_PATH
-  ;;
-
-bsdi[[45]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
-  # the default ld.so.conf also contains /usr/contrib/lib and
-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
-  # libtool to hard-code these into programs
-  ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
-  version_type=windows
-  shrext_cmds=".dll"
-  need_version=no
-  need_lib_prefix=no
-
-  case $GCC,$cc_basename in
-  yes,*)
-    # gcc
-    library_names_spec='$libname.dll.a'
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname~
-      chmod a+x \$dldir/$dlname~
-      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-      fi'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-
-    case $host_os in
-    cygwin*)
-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-m4_if([$1], [],[
-      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
-      ;;
-    mingw* | cegcc*)
-      # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      ;;
-    pw32*)
-      # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      ;;
-    esac
-    dynamic_linker='Win32 ld.exe'
-    ;;
-
-  *,cl*)
-    # Native MSVC
-    libname_spec='$name'
-    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-    library_names_spec='${libname}.dll.lib'
-
-    case $build_os in
-    mingw*)
-      sys_lib_search_path_spec=
-      lt_save_ifs=$IFS
-      IFS=';'
-      for lt_path in $LIB
-      do
-        IFS=$lt_save_ifs
-        # Let DOS variable expansion print the short 8.3 style file name.
-        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
-        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
-      done
-      IFS=$lt_save_ifs
-      # Convert to MSYS style.
-      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
-      ;;
-    cygwin*)
-      # Convert to unix form, then to dos form, then back to unix form
-      # but this time dos style (no spaces!) so that the unix form looks
-      # like /cygdrive/c/PROGRA~1:/cygdr...
-      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
-      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
-      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      ;;
-    *)
-      sys_lib_search_path_spec="$LIB"
-      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
-        # It is most probably a Windows format PATH.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      fi
-      # FIXME: find the short name or the path components, as spaces are
-      # common. (e.g. "Program Files" -> "PROGRA~1")
-      ;;
-    esac
-
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-    dynamic_linker='Win32 link.exe'
-    ;;
-
-  *)
-    # Assume MSVC wrapper
-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
-    dynamic_linker='Win32 ld.exe'
-    ;;
-  esac
-  # FIXME: first we should search . and the directory the executable is in
-  shlibpath_var=PATH
-  ;;
-
-darwin* | rhapsody*)
-  dynamic_linker="$host_os dyld"
-  version_type=darwin
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
-  soname_spec='${libname}${release}${major}$shared_ext'
-  shlibpath_overrides_runpath=yes
-  shlibpath_var=DYLD_LIBRARY_PATH
-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-m4_if([$1], [],[
-  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
-  ;;
-
-dgux*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-freebsd* | dragonfly*)
-  # DragonFly does not have aout.  When/if they implement a new
-  # versioning mechanism, adjust this.
-  if test -x /usr/bin/objformat; then
-    objformat=`/usr/bin/objformat`
-  else
-    case $host_os in
-    freebsd[[23]].*) objformat=aout ;;
-    *) objformat=elf ;;
-    esac
-  fi
-  version_type=freebsd-$objformat
-  case $version_type in
-    freebsd-elf*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-      need_version=no
-      need_lib_prefix=no
-      ;;
-    freebsd-*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
-      need_version=yes
-      ;;
-  esac
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_os in
-  freebsd2.*)
-    shlibpath_overrides_runpath=yes
-    ;;
-  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
-  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
-    shlibpath_overrides_runpath=no
-    hardcode_into_libs=yes
-    ;;
-  *) # from 4.6 on, and DragonFly
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  esac
-  ;;
-
-haiku*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  dynamic_linker="$host_os runtime_loader"
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
-  hardcode_into_libs=yes
-  ;;
-
-hpux9* | hpux10* | hpux11*)
-  # Give a soname corresponding to the major version so that dld.sl refuses to
-  # link against other versions.
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  case $host_cpu in
-  ia64*)
-    shrext_cmds='.so'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.so"
-    shlibpath_var=LD_LIBRARY_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    if test "X$HPUX_IA64_MODE" = X32; then
-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
-    else
-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
-    fi
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  hppa*64*)
-    shrext_cmds='.sl'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  *)
-    shrext_cmds='.sl'
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=SHLIB_PATH
-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    ;;
-  esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
-  postinstall_cmds='chmod 555 $lib'
-  # or fails outright, so override atomically:
-  install_override_mode=555
-  ;;
-
-interix[[3-9]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $host_os in
-    nonstopux*) version_type=nonstopux ;;
-    *)
-	if test "$lt_cv_prog_gnu_ld" = yes; then
-		version_type=linux # correct to gnu/linux during the next big refactor
-	else
-		version_type=irix
-	fi ;;
-  esac
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
-  case $host_os in
-  irix5* | nonstopux*)
-    libsuff= shlibsuff=
-    ;;
-  *)
-    case $LD in # libtool.m4 will add one of these switches to LD
-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
-      libsuff= shlibsuff= libmagic=32-bit;;
-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
-      libsuff=32 shlibsuff=N32 libmagic=N32;;
-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
-    *) libsuff= shlibsuff= libmagic=never-match;;
-    esac
-    ;;
-  esac
-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
-  hardcode_into_libs=yes
-  ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
-  dynamic_linker=no
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-
-  # Some binutils ld are patched to set DT_RUNPATH
-  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
-    [lt_cv_shlibpath_overrides_runpath=no
-    save_LDFLAGS=$LDFLAGS
-    save_libdir=$libdir
-    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
-	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
-	 [lt_cv_shlibpath_overrides_runpath=yes])])
-    LDFLAGS=$save_LDFLAGS
-    libdir=$save_libdir
-    ])
-  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  # Append ld.so.conf contents to the search path
-  if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
-  fi
-
-  # We used to test for /lib/ld.so.1 and disable shared libraries on
-  # powerpc, because MkLinux only supported shared libraries with the
-  # GNU dynamic linker.  Since this was broken with cross compilers,
-  # most powerpc-linux boxes support dynamic linking these days and
-  # people can always --disable-shared, the test was removed, and we
-  # assume the GNU/Linux dynamic linker is in use.
-  dynamic_linker='GNU/Linux ld.so'
-  ;;
-
-netbsdelf*-gnu)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='NetBSD ld.elf_so'
-  ;;
-
-netbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-    dynamic_linker='NetBSD (a.out) ld.so'
-  else
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    dynamic_linker='NetBSD ld.elf_so'
-  fi
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  ;;
-
-newsos6)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-*nto* | *qnx*)
-  version_type=qnx
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='ldqnx.so'
-  ;;
-
-openbsd*)
-  version_type=sunos
-  sys_lib_dlsearch_path_spec="/usr/lib"
-  need_lib_prefix=no
-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
-  case $host_os in
-    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
-    *)				need_version=no  ;;
-  esac
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case $host_os in
-      openbsd2.[[89]] | openbsd2.[[89]].*)
-	shlibpath_overrides_runpath=no
-	;;
-      *)
-	shlibpath_overrides_runpath=yes
-	;;
-      esac
-  else
-    shlibpath_overrides_runpath=yes
-  fi
-  ;;
-
-os2*)
-  libname_spec='$name'
-  shrext_cmds=".dll"
-  need_lib_prefix=no
-  library_names_spec='$libname${shared_ext} $libname.a'
-  dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
-  ;;
-
-osf3* | osf4* | osf5*)
-  version_type=osf
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
-  ;;
-
-rdos*)
-  dynamic_linker=no
-  ;;
-
-solaris*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  # ldd complains unless libraries are executable
-  postinstall_cmds='chmod +x $lib'
-  ;;
-
-sunos4*)
-  version_type=sunos
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
-    need_lib_prefix=no
-  fi
-  need_version=yes
-  ;;
-
-sysv4 | sysv4.3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_vendor in
-    sni)
-      shlibpath_overrides_runpath=no
-      need_lib_prefix=no
-      runpath_var=LD_RUN_PATH
-      ;;
-    siemens)
-      need_lib_prefix=no
-      ;;
-    motorola)
-      need_lib_prefix=no
-      need_version=no
-      shlibpath_overrides_runpath=no
-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
-      ;;
-  esac
-  ;;
-
-sysv4*MP*)
-  if test -d /usr/nec ;then
-    version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
-    soname_spec='$libname${shared_ext}.$major'
-    shlibpath_var=LD_LIBRARY_PATH
-  fi
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=freebsd-elf
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  if test "$with_gnu_ld" = yes; then
-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
-  else
-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
-    case $host_os in
-      sco3.2v5*)
-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
-	;;
-    esac
-  fi
-  sys_lib_dlsearch_path_spec='/usr/lib'
-  ;;
-
-tpf*)
-  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-uts4*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-*)
-  dynamic_linker=no
-  ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
-  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
-fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
-  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
-fi
-
-_LT_DECL([], [variables_saved_for_relink], [1],
-    [Variables whose values should be saved in libtool wrapper scripts and
-    restored at link time])
-_LT_DECL([], [need_lib_prefix], [0],
-    [Do we need the "lib" prefix for modules?])
-_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
-_LT_DECL([], [version_type], [0], [Library versioning type])
-_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
-_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
-_LT_DECL([], [shlibpath_overrides_runpath], [0],
-    [Is shlibpath searched before the hard-coded library search path?])
-_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
-_LT_DECL([], [library_names_spec], [1],
-    [[List of archive names.  First name is the real one, the rest are links.
-    The last name is the one that the linker finds with -lNAME]])
-_LT_DECL([], [soname_spec], [1],
-    [[The coded name of the library, if different from the real name]])
-_LT_DECL([], [install_override_mode], [1],
-    [Permission mode override for installation of shared libraries])
-_LT_DECL([], [postinstall_cmds], [2],
-    [Command to use after installation of a shared archive])
-_LT_DECL([], [postuninstall_cmds], [2],
-    [Command to use after uninstallation of a shared archive])
-_LT_DECL([], [finish_cmds], [2],
-    [Commands used to finish a libtool library installation in a directory])
-_LT_DECL([], [finish_eval], [1],
-    [[As "finish_cmds", except a single script fragment to be evaled but
-    not shown]])
-_LT_DECL([], [hardcode_into_libs], [0],
-    [Whether we should hardcode library paths into libraries])
-_LT_DECL([], [sys_lib_search_path_spec], [2],
-    [Compile-time system search path for libraries])
-_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
-    [Run-time system search path for libraries])
-])# _LT_SYS_DYNAMIC_LINKER
-
-
-# _LT_PATH_TOOL_PREFIX(TOOL)
-# --------------------------
-# find a file program which can recognize shared library
-AC_DEFUN([_LT_PATH_TOOL_PREFIX],
-[m4_require([_LT_DECL_EGREP])dnl
-AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
-[[\\/*] |  ?:[\\/]*])
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
-  ;;
-*)
-  lt_save_MAGIC_CMD="$MAGIC_CMD"
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word.  This closes a longstanding sh security hole.
-  ac_dummy="m4_if([$2], , $PATH, [$2])"
-  for ac_dir in $ac_dummy; do
-    IFS="$lt_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$1; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
-      if test -n "$file_magic_test_file"; then
-	case $deplibs_check_method in
-	"file_magic "*)
-	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-	    $EGREP "$file_magic_regex" > /dev/null; then
-	    :
-	  else
-	    cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
-	  fi ;;
-	esac
-      fi
-      break
-    fi
-  done
-  IFS="$lt_save_ifs"
-  MAGIC_CMD="$lt_save_MAGIC_CMD"
-  ;;
-esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
-  AC_MSG_RESULT($MAGIC_CMD)
-else
-  AC_MSG_RESULT(no)
-fi
-_LT_DECL([], [MAGIC_CMD], [0],
-	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
-])# _LT_PATH_TOOL_PREFIX
-
-# Old name:
-AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
-
-
-# _LT_PATH_MAGIC
-# --------------
-# find a file program which can recognize a shared library
-m4_defun([_LT_PATH_MAGIC],
-[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
-  if test -n "$ac_tool_prefix"; then
-    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
-  else
-    MAGIC_CMD=:
-  fi
-fi
-])# _LT_PATH_MAGIC
-
-
-# LT_PATH_LD
-# ----------
-# find the pathname to the GNU or non-GNU linker
-AC_DEFUN([LT_PATH_LD],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
-
-AC_ARG_WITH([gnu-ld],
-    [AS_HELP_STRING([--with-gnu-ld],
-	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
-    [test "$withval" = no || with_gnu_ld=yes],
-    [with_gnu_ld=no])dnl
-
-ac_prog=ld
-if test "$GCC" = yes; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  AC_MSG_CHECKING([for ld used by $CC])
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [[\\/]]* | ?:[[\\/]]*)
-      re_direlt='/[[^/]][[^/]]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
-      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
-	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD="$ac_prog"
-      ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test "$with_gnu_ld" = yes; then
-  AC_MSG_CHECKING([for GNU ld])
-else
-  AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-	test "$with_gnu_ld" != no && break
-	;;
-      *)
-	test "$with_gnu_ld" != yes && break
-	;;
-      esac
-    fi
-  done
-  IFS="$lt_save_ifs"
-else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
-  AC_MSG_RESULT($LD)
-else
-  AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-_LT_PATH_LD_GNU
-AC_SUBST([LD])
-
-_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
-])# LT_PATH_LD
-
-# Old names:
-AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
-AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_LD], [])
-dnl AC_DEFUN([AC_PROG_LD], [])
-
-
-# _LT_PATH_LD_GNU
-#- --------------
-m4_defun([_LT_PATH_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
-  lt_cv_prog_gnu_ld=yes
-  ;;
-*)
-  lt_cv_prog_gnu_ld=no
-  ;;
-esac])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])# _LT_PATH_LD_GNU
-
-
-# _LT_CMD_RELOAD
-# --------------
-# find reload flag for linker
-#   -- PORTME Some linkers may need a different reload flag.
-m4_defun([_LT_CMD_RELOAD],
-[AC_CACHE_CHECK([for $LD option to reload object files],
-  lt_cv_ld_reload_flag,
-  [lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    if test "$GCC" != yes; then
-      reload_cmds=false
-    fi
-    ;;
-  darwin*)
-    if test "$GCC" = yes; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
-    else
-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
-    fi
-    ;;
-esac
-_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
-_LT_TAGDECL([], [reload_cmds], [2])dnl
-])# _LT_CMD_RELOAD
-
-
-# _LT_CHECK_MAGIC_METHOD
-# ----------------------
-# how to check for library dependencies
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_MAGIC_METHOD],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-AC_CACHE_CHECK([how to recognize dependent libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[[4-9]]*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-beos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-bsdi[[45]]*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  ;;
-
-cygwin*)
-  # func_win32_libid is a shell function defined in ltmain.sh
-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-  lt_cv_file_magic_cmd='func_win32_libid'
-  ;;
-
-mingw* | pw32*)
-  # Base MSYS/MinGW do not provide the 'file' command needed by
-  # func_win32_libid shell function, so use a weaker test based on 'objdump',
-  # unless we find 'file', for example because we are cross-compiling.
-  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
-  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
-    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-    lt_cv_file_magic_cmd='func_win32_libid'
-  else
-    # Keep this pattern in sync with the one in func_win32_libid.
-    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
-    lt_cv_file_magic_cmd='$OBJDUMP -f'
-  fi
-  ;;
-
-cegcc*)
-  # use the weaker test based on 'objdump'. See mingw*.
-  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
-  lt_cv_file_magic_cmd='$OBJDUMP -f'
-  ;;
-
-darwin* | rhapsody*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-freebsd* | dragonfly*)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    case $host_cpu in
-    i*86 )
-      # Not sure whether the presence of OpenBSD here was a mistake.
-      # Let's accept both of them until this is cleared up.
-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
-      lt_cv_file_magic_cmd=/usr/bin/file
-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
-      ;;
-    esac
-  else
-    lt_cv_deplibs_check_method=pass_all
-  fi
-  ;;
-
-haiku*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-hpux10.20* | hpux11*)
-  lt_cv_file_magic_cmd=/usr/bin/file
-  case $host_cpu in
-  ia64*)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
-    ;;
-  hppa*64*)
-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
-    ;;
-  *)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
-    ;;
-  esac
-  ;;
-
-interix[[3-9]]*)
-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
-  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $LD in
-  *-32|*"-32 ") libmagic=32-bit;;
-  *-n32|*"-n32 ") libmagic=N32;;
-  *-64|*"-64 ") libmagic=64-bit;;
-  *) libmagic=never-match;;
-  esac
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-netbsd* | netbsdelf*-gnu)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
-  fi
-  ;;
-
-newos6*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
-  ;;
-
-*nto* | *qnx*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-openbsd*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  fi
-  ;;
-
-osf3* | osf4* | osf5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-rdos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-solaris*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv4 | sysv4.3*)
-  case $host_vendor in
-  motorola)
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
-    ;;
-  ncr)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  sequent)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
-    ;;
-  sni)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
-    lt_cv_file_magic_test_file=/lib/libc.so
-    ;;
-  siemens)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  pc)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  esac
-  ;;
-
-tpf*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-esac
-])
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
-  case $host_os in
-  mingw* | pw32*)
-    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
-      want_nocaseglob=yes
-    else
-      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
-    fi
-    ;;
-  esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-_LT_DECL([], [deplibs_check_method], [1],
-    [Method to check whether dependent libraries are shared objects])
-_LT_DECL([], [file_magic_cmd], [1],
-    [Command to use when deplibs_check_method = "file_magic"])
-_LT_DECL([], [file_magic_glob], [1],
-    [How to find potential files when deplibs_check_method = "file_magic"])
-_LT_DECL([], [want_nocaseglob], [1],
-    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
-])# _LT_CHECK_MAGIC_METHOD
-
-
-# LT_PATH_NM
-# ----------
-# find the pathname to a BSD- or MS-compatible name lister
-AC_DEFUN([LT_PATH_NM],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
-[if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM="$NM"
-else
-  lt_nm_to_check="${ac_tool_prefix}nm"
-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
-    lt_nm_to_check="$lt_nm_to_check nm"
-  fi
-  for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS="$lt_save_ifs"
-      test -z "$ac_dir" && ac_dir=.
-      tmp_nm="$ac_dir/$lt_tmp_nm"
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
-	# Check to see if the nm accepts a BSD-compat flag.
-	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
-	#   nm: unknown option "B" ignored
-	# Tru64's nm complains that /dev/null is an invalid object file
-	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
-	*/dev/null* | *'Invalid file or object type'*)
-	  lt_cv_path_NM="$tmp_nm -B"
-	  break
-	  ;;
-	*)
-	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
-	  */dev/null*)
-	    lt_cv_path_NM="$tmp_nm -p"
-	    break
-	    ;;
-	  *)
-	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-	    continue # so that we can try to find one that supports BSD flags
-	    ;;
-	  esac
-	  ;;
-	esac
-      fi
-    done
-    IFS="$lt_save_ifs"
-  done
-  : ${lt_cv_path_NM=no}
-fi])
-if test "$lt_cv_path_NM" != "no"; then
-  NM="$lt_cv_path_NM"
-else
-  # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$DUMPBIN"; then :
-    # Let the user override the test.
-  else
-    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
-    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
-    *COFF*)
-      DUMPBIN="$DUMPBIN -symbols"
-      ;;
-    *)
-      DUMPBIN=:
-      ;;
-    esac
-  fi
-  AC_SUBST([DUMPBIN])
-  if test "$DUMPBIN" != ":"; then
-    NM="$DUMPBIN"
-  fi
-fi
-test -z "$NM" && NM=nm
-AC_SUBST([NM])
-_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
-
-AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
-  [lt_cv_nm_interface="BSD nm"
-  echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$ac_compile" 2>conftest.err)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
-  cat conftest.out >&AS_MESSAGE_LOG_FD
-  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
-    lt_cv_nm_interface="MS dumpbin"
-  fi
-  rm -f conftest*])
-])# LT_PATH_NM
-
-# Old names:
-AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
-AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_NM], [])
-dnl AC_DEFUN([AC_PROG_NM], [])
-
-# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-# --------------------------------
-# how to determine the name of the shared library
-# associated with a specific link library.
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-m4_require([_LT_DECL_DLLTOOL])
-AC_CACHE_CHECK([how to associate runtime and link libraries],
-lt_cv_sharedlib_from_linklib_cmd,
-[lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh
-  # decide which to use based on capabilities of $DLLTOOL
-  case `$DLLTOOL --help 2>&1` in
-  *--identify-strict*)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
-    ;;
-  *)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
-    ;;
-  esac
-  ;;
-*)
-  # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
-  ;;
-esac
-])
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
-    [Command to associate shared and link libraries])
-])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-
-
-# _LT_PATH_MANIFEST_TOOL
-# ----------------------
-# locate the manifest tool
-m4_defun([_LT_PATH_MANIFEST_TOOL],
-[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
-  [lt_cv_path_mainfest_tool=no
-  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
-  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
-    lt_cv_path_mainfest_tool=yes
-  fi
-  rm -f conftest*])
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
-  MANIFEST_TOOL=:
-fi
-_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
-])# _LT_PATH_MANIFEST_TOOL
-
-
-# LT_LIB_M
-# --------
-# check for math library
-AC_DEFUN([LT_LIB_M],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
-  # These system don't have libm, or don't need it
-  ;;
-*-ncr-sysv4.3*)
-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
-  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
-  ;;
-*)
-  AC_CHECK_LIB(m, cos, LIBM="-lm")
-  ;;
-esac
-AC_SUBST([LIBM])
-])# LT_LIB_M
-
-# Old name:
-AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_CHECK_LIBM], [])
-
-
-# _LT_COMPILER_NO_RTTI([TAGNAME])
-# -------------------------------
-m4_defun([_LT_COMPILER_NO_RTTI],
-[m4_require([_LT_TAG_COMPILER])dnl
-
-_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-
-if test "$GCC" = yes; then
-  case $cc_basename in
-  nvcc*)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
-  esac
-
-  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
-    lt_cv_prog_compiler_rtti_exceptions,
-    [-fno-rtti -fno-exceptions], [],
-    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
-fi
-_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
-	[Compiler flag to turn off builtin functions])
-])# _LT_COMPILER_NO_RTTI
-
-
-# _LT_CMD_GLOBAL_SYMBOLS
-# ----------------------
-m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
-[
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
-  symcode='[[BCDT]]'
-  ;;
-cygwin* | mingw* | pw32* | cegcc*)
-  symcode='[[ABCDGISTW]]'
-  ;;
-hpux*)
-  if test "$host_cpu" = ia64; then
-    symcode='[[ABCDEGRST]]'
-  fi
-  ;;
-irix* | nonstopux*)
-  symcode='[[BCDEGRST]]'
-  ;;
-osf*)
-  symcode='[[BCDEGQRST]]'
-  ;;
-solaris*)
-  symcode='[[BDRT]]'
-  ;;
-sco3.2v5*)
-  symcode='[[DT]]'
-  ;;
-sysv4.2uw2*)
-  symcode='[[DT]]'
-  ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
-  symcode='[[ABDT]]'
-  ;;
-sysv4)
-  symcode='[[DFNSTU]]'
-  ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
-  symcode='[[ABCDGIRSTW]]' ;;
-esac
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
-  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
-  ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
-  symxfrm="\\1 $ac_symprfx\\2 \\2"
-
-  # Write the raw and C identifiers.
-  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function
-    # and D for any global variable.
-    # Also find C++ and __fastcall symbols from MSVC++,
-    # which start with @ or ?.
-    lt_cv_sys_global_symbol_pipe="$AWK ['"\
-"     {last_section=section; section=\$ 3};"\
-"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
-"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-"     \$ 0!~/External *\|/{next};"\
-"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-"     {if(hide[section]) next};"\
-"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
-"     ' prfx=^$ac_symprfx]"
-  else
-    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
-  fi
-  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
-  # Check to see that the pipe works correctly.
-  pipe_works=no
-
-  rm -f conftest*
-  cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
-  if AC_TRY_EVAL(ac_compile); then
-    # Now try to grab the symbols.
-    nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
-      # Try sorting and uniquifying the output.
-      if sort "$nlist" | uniq > "$nlist"T; then
-	mv -f "$nlist"T "$nlist"
-      else
-	rm -f "$nlist"T
-      fi
-
-      # Make sure that we snagged all the symbols we need.
-      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
-	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
-	  cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
-   relocations are performed -- see ld's documentation on pseudo-relocs.  */
-# define LT@&t@_DLSYM_CONST
-#elif defined(__osf__)
-/* This system does not cope well with relocations in const data.  */
-# define LT@&t@_DLSYM_CONST
-#else
-# define LT@&t@_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
-	  # Now generate the symbol file.
-	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
-	  cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols.  */
-LT@&t@_DLSYM_CONST struct {
-  const char *name;
-  void       *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[[]] =
-{
-  { "@PROGRAM@", (void *) 0 },
-_LT_EOF
-	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
-	  cat <<\_LT_EOF >> conftest.$ac_ext
-  {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
-  return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
-	  # Now try linking the two files.
-	  mv conftest.$ac_objext conftstm.$ac_objext
-	  lt_globsym_save_LIBS=$LIBS
-	  lt_globsym_save_CFLAGS=$CFLAGS
-	  LIBS="conftstm.$ac_objext"
-	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
-	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
-	    pipe_works=yes
-	  fi
-	  LIBS=$lt_globsym_save_LIBS
-	  CFLAGS=$lt_globsym_save_CFLAGS
-	else
-	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
-	fi
-      else
-	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
-      fi
-    else
-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
-    fi
-  else
-    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
-    cat conftest.$ac_ext >&5
-  fi
-  rm -rf conftest* conftst*
-
-  # Do not use the global_symbol_pipe unless it works.
-  if test "$pipe_works" = yes; then
-    break
-  else
-    lt_cv_sys_global_symbol_pipe=
-  fi
-done
-])
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
-  lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
-  AC_MSG_RESULT(failed)
-else
-  AC_MSG_RESULT(ok)
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
-  nm_file_list_spec='@'
-fi
-
-_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
-    [Take the output of nm and produce a listing of raw symbols and C names])
-_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
-    [Transform the output of nm in a proper C declaration])
-_LT_DECL([global_symbol_to_c_name_address],
-    [lt_cv_sys_global_symbol_to_c_name_address], [1],
-    [Transform the output of nm in a C name address pair])
-_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
-    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
-    [Transform the output of nm in a C name address pair when lib prefix is needed])
-_LT_DECL([], [nm_file_list_spec], [1],
-    [Specify filename containing input files for $NM])
-]) # _LT_CMD_GLOBAL_SYMBOLS
-
-
-# _LT_COMPILER_PIC([TAGNAME])
-# ---------------------------
-m4_defun([_LT_COMPILER_PIC],
-[m4_require([_LT_TAG_COMPILER])dnl
-_LT_TAGVAR(lt_prog_compiler_wl, $1)=
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-_LT_TAGVAR(lt_prog_compiler_static, $1)=
-
-m4_if([$1], [CXX], [
-  # C++ specific cases for pic, static, wl, etc.
-  if test "$GXX" = yes; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-    aix*)
-      # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
-	# AIX 5 now supports IA64 processor
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-    mingw* | cygwin* | os2* | pw32* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-    *djgpp*)
-      # DJGPP does not support shared libraries at all
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-      ;;
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-    sysv4*MP*)
-      if test -d /usr/nec; then
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-	;;
-      *)
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	;;
-      esac
-      ;;
-    *qnx* | *nto*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-  else
-    case $host_os in
-      aix[[4-9]]*)
-	# All AIX code is PIC.
-	if test "$host_cpu" = ia64; then
-	  # AIX 5 now supports IA64 processor
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	else
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-	fi
-	;;
-      chorus*)
-	case $cc_basename in
-	cxch68*)
-	  # Green Hills C++ Compiler
-	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
-	  ;;
-	esac
-	;;
-      mingw* | cygwin* | os2* | pw32* | cegcc*)
-	# This hack is so that the source file can tell whether it is being
-	# built for inclusion in a dll (and should export symbols for example).
-	m4_if([$1], [GCJ], [],
-	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-	;;
-      dgux*)
-	case $cc_basename in
-	  ec++*)
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	    ;;
-	  ghcx*)
-	    # Green Hills C++ Compiler
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      freebsd* | dragonfly*)
-	# FreeBSD uses GNU C++
-	;;
-      hpux9* | hpux10* | hpux11*)
-	case $cc_basename in
-	  CC*)
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-	    if test "$host_cpu" != ia64; then
-	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-	    fi
-	    ;;
-	  aCC*)
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-	    case $host_cpu in
-	    hppa*64*|ia64*)
-	      # +Z the default
-	      ;;
-	    *)
-	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-	      ;;
-	    esac
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      interix*)
-	# This is c89, which is MS Visual C++ (no shared libs)
-	# Anyone wants to do a port?
-	;;
-      irix5* | irix6* | nonstopux*)
-	case $cc_basename in
-	  CC*)
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-	    # CC pic flag -KPIC is the default.
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-	case $cc_basename in
-	  KCC*)
-	    # KAI C++ Compiler
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	    ;;
-	  ecpc* )
-	    # old Intel C++ for x86_64 which still supported -KPIC.
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-	    ;;
-	  icpc* )
-	    # Intel C++, used to be incompatible with GCC.
-	    # ICC 10 doesn't accept -KPIC any more.
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-	    ;;
-	  pgCC* | pgcpp*)
-	    # Portland Group C++ compiler
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	    ;;
-	  cxx*)
-	    # Compaq C++
-	    # Make sure the PIC flag is empty.  It appears that all Alpha
-	    # Linux and Compaq Tru64 Unix objects are PIC.
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-	    ;;
-	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
-	    # IBM XL 8.0, 9.0 on PPC and BlueGene
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-	    ;;
-	  *)
-	    case `$CC -V 2>&1 | sed 5q` in
-	    *Sun\ C*)
-	      # Sun C++ 5.9
-	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-	      ;;
-	    esac
-	    ;;
-	esac
-	;;
-      lynxos*)
-	;;
-      m88k*)
-	;;
-      mvs*)
-	case $cc_basename in
-	  cxx*)
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      netbsd* | netbsdelf*-gnu)
-	;;
-      *qnx* | *nto*)
-        # QNX uses GNU C++, but need to define -shared option too, otherwise
-        # it will coredump.
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-        ;;
-      osf3* | osf4* | osf5*)
-	case $cc_basename in
-	  KCC*)
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-	    ;;
-	  RCC*)
-	    # Rational C++ 2.4.1
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-	    ;;
-	  cxx*)
-	    # Digital/Compaq C++
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    # Make sure the PIC flag is empty.  It appears that all Alpha
-	    # Linux and Compaq Tru64 Unix objects are PIC.
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      psos*)
-	;;
-      solaris*)
-	case $cc_basename in
-	  CC* | sunCC*)
-	    # Sun C++ 4.2, 5.x and Centerline C++
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-	    ;;
-	  gcx*)
-	    # Green Hills C++ Compiler
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      sunos4*)
-	case $cc_basename in
-	  CC*)
-	    # Sun C++ 4.x
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	    ;;
-	  lcc*)
-	    # Lucid
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-	case $cc_basename in
-	  CC*)
-	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	    ;;
-	esac
-	;;
-      tandem*)
-	case $cc_basename in
-	  NCC*)
-	    # NonStop-UX NCC 3.20
-	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	    ;;
-	  *)
-	    ;;
-	esac
-	;;
-      vxworks*)
-	;;
-      *)
-	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-	;;
-    esac
-  fi
-],
-[
-  if test "$GCC" = yes; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-      aix*)
-      # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
-	# AIX 5 now supports IA64 processor
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-	# +Z the default
-	;;
-      *)
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	;;
-      esac
-      ;;
-
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-
-    msdosdjgpp*)
-      # Just because we use GCC doesn't mean we suddenly get shared libraries
-      # on systems that don't support them.
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      enable_shared=no
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-
-    case $cc_basename in
-    nvcc*) # Cuda Compiler Driver 2.2
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
-      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
-      fi
-      ;;
-    esac
-  else
-    # PORTME Check for flag to pass linker flags through the system compiler.
-    case $host_os in
-    aix*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      if test "$host_cpu" = ia64; then
-	# AIX 5 now supports IA64 processor
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      else
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-      fi
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      m4_if([$1], [GCJ], [],
-	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-
-    hpux9* | hpux10* | hpux11*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
-      # not for PA HP-UX.
-      case $host_cpu in
-      hppa*64*|ia64*)
-	# +Z the default
-	;;
-      *)
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-	;;
-      esac
-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC (with -KPIC) is the default.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-      case $cc_basename in
-      # old Intel for x86_64 which still supported -KPIC.
-      ecc*)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # icc used to be incompatible with GCC.
-      # ICC 10 doesn't accept -KPIC any more.
-      icc* | ifort*)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # Lahey Fortran 8.1.
-      lf95*)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
-	;;
-      nagfor*)
-	# NAG Fortran compiler
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	;;
-      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
-        # Portland Group compilers (*not* the Pentium gcc compiler,
-	# which looks to be a dead project)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-        ;;
-      ccc*)
-        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-        # All Alpha code is PIC.
-        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-        ;;
-      xl* | bgxl* | bgf* | mpixl*)
-	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-	;;
-      *)
-	case `$CC -V 2>&1 | sed 5q` in
-	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
-	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
-	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
-	  ;;
-	*Sun\ F* | *Sun*Fortran*)
-	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-	  ;;
-	*Sun\ C*)
-	  # Sun C 5.9
-	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	  ;;
-        *Intel*\ [[CF]]*Compiler*)
-	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-	  ;;
-	*Portland\ Group*)
-	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-	  ;;
-	esac
-	;;
-      esac
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    osf3* | osf4* | osf5*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # All OSF/1 code is PIC.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    rdos*)
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      case $cc_basename in
-      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
-      *)
-	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4 | sysv4.2uw2* | sysv4.3*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec ;then
-	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
-	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    unicos*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-    esac
-  fi
-])
-case $host_os in
-  # For platforms which do not support PIC, -DPIC is meaningless:
-  *djgpp*)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-    ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
-    ;;
-esac
-
-AC_CACHE_CHECK([for $compiler option to produce PIC],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
-  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
-    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
-    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
-    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
-     "" | " "*) ;;
-     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
-     esac],
-    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
-fi
-_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
-	[Additional compiler flags for building library objects])
-
-_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
-	[How to pass a linker flag through the compiler])
-#
-# Check to make sure the static flag actually works.
-#
-wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
-_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
-  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
-  $lt_tmp_static_flag,
-  [],
-  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
-_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
-	[Compiler flag to prevent dynamic linking])
-])# _LT_COMPILER_PIC
-
-
-# _LT_LINKER_SHLIBS([TAGNAME])
-# ----------------------------
-# See if the linker supports building shared libraries.
-m4_defun([_LT_LINKER_SHLIBS],
-[AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-m4_if([$1], [CXX], [
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  case $host_os in
-  aix[[4-9]]*)
-    # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
-    # Also, AIX nm treats weak defined symbols like other global defined
-    # symbols, whereas GNU nm marks them as "W".
-    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-    else
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-    fi
-    ;;
-  pw32*)
-    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
-    ;;
-  cygwin* | mingw* | cegcc*)
-    case $cc_basename in
-    cl*)
-      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
-      ;;
-    *)
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-      ;;
-    esac
-    ;;
-  linux* | k*bsd*-gnu | gnu*)
-    _LT_TAGVAR(link_all_deplibs, $1)=no
-    ;;
-  *)
-    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-    ;;
-  esac
-], [
-  runpath_var=
-  _LT_TAGVAR(allow_undefined_flag, $1)=
-  _LT_TAGVAR(always_export_symbols, $1)=no
-  _LT_TAGVAR(archive_cmds, $1)=
-  _LT_TAGVAR(archive_expsym_cmds, $1)=
-  _LT_TAGVAR(compiler_needs_object, $1)=no
-  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(hardcode_automatic, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
-  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-  _LT_TAGVAR(hardcode_libdir_separator, $1)=
-  _LT_TAGVAR(hardcode_minus_L, $1)=no
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  _LT_TAGVAR(inherit_rpath, $1)=no
-  _LT_TAGVAR(link_all_deplibs, $1)=unknown
-  _LT_TAGVAR(module_cmds, $1)=
-  _LT_TAGVAR(module_expsym_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
-  _LT_TAGVAR(thread_safe_flag_spec, $1)=
-  _LT_TAGVAR(whole_archive_flag_spec, $1)=
-  # include_expsyms should be a list of space-separated symbols to be *always*
-  # included in the symbol list
-  _LT_TAGVAR(include_expsyms, $1)=
-  # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-  # as well as any symbol that contains `d'.
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-  # platforms (ab)use it in PIC code, but their linkers get confused if
-  # the symbol is explicitly referenced.  Since portable code cannot
-  # rely on this symbol name, it's probably fine to never include it in
-  # preloaded symbol tables.
-  # Exclude shared library initialization/finalization symbols.
-dnl Note also adjust exclude_expsyms for C++ above.
-  extract_expsyms_cmds=
-
-  case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
-    # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
-    if test "$GCC" != yes; then
-      with_gnu_ld=no
-    fi
-    ;;
-  interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++)
-    with_gnu_ld=yes
-    ;;
-  openbsd*)
-    with_gnu_ld=no
-    ;;
-  linux* | k*bsd*-gnu | gnu*)
-    _LT_TAGVAR(link_all_deplibs, $1)=no
-    ;;
-  esac
-
-  _LT_TAGVAR(ld_shlibs, $1)=yes
-
-  # On some targets, GNU ld is compatible enough with the native linker
-  # that we're better off using the native interface for both.
-  lt_use_gnu_ld_interface=no
-  if test "$with_gnu_ld" = yes; then
-    case $host_os in
-      aix*)
-	# The AIX port of GNU ld has always aspired to compatibility
-	# with the native linker.  However, as the warning in the GNU ld
-	# block says, versions before 2.19.5* couldn't really create working
-	# shared libraries, regardless of the interface used.
-	case `$LD -v 2>&1` in
-	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
-	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
-	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
-	  *)
-	    lt_use_gnu_ld_interface=yes
-	    ;;
-	esac
-	;;
-      *)
-	lt_use_gnu_ld_interface=yes
-	;;
-    esac
-  fi
-
-  if test "$lt_use_gnu_ld_interface" = yes; then
-    # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='${wl}'
-
-    # Set some defaults for GNU ld with shared library support. These
-    # are reset later if shared libraries are not supported. Putting them
-    # here allows them to be overridden if necessary.
-    runpath_var=LD_RUN_PATH
-    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-    # ancient GNU ld didn't support --whole-archive et. al.
-    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-    else
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-    supports_anon_versioning=no
-    case `$LD -v 2>&1` in
-      *GNU\ gold*) supports_anon_versioning=yes ;;
-      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
-      *\ 2.11.*) ;; # other 2.11 versions
-      *) supports_anon_versioning=yes ;;
-    esac
-
-    # See if GNU ld supports shared libraries.
-    case $host_os in
-    aix[[3-9]]*)
-      # On AIX/PPC, the GNU linker is very broken
-      if test "$host_cpu" != ia64; then
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    beos*)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-	# support --undefined.  This deserves some investigation.  FIXME
-	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      else
-	_LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-      # as there is no search path for DLLs.
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=no
-      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-
-      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	# If the export-symbols file already is a .def file (1st line
-	# is EXPORTS), use it as is; otherwise, prepend...
-	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	  cp $export_symbols $output_objdir/$soname.def;
-	else
-	  echo EXPORTS > $output_objdir/$soname.def;
-	  cat $export_symbols >> $output_objdir/$soname.def;
-	fi~
-	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-      else
-	_LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    haiku*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    interix[[3-9]]*)
-      _LT_TAGVAR(hardcode_direct, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-      # Instead, shared libraries are loaded at an image base (0x10000000 by
-      # default) and relocated if they conflict, which is a slow very memory
-      # consuming and fragmenting process.  To avoid this, we pick a random,
-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      ;;
-
-    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
-      tmp_diet=no
-      if test "$host_os" = linux-dietlibc; then
-	case $cc_basename in
-	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
-	esac
-      fi
-      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-	 && test "$tmp_diet" = no
-      then
-	tmp_addflag=' $pic_flag'
-	tmp_sharedflag='-shared'
-	case $cc_basename,$host_cpu in
-        pgcc*)				# Portland Group C compiler
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-	  tmp_addflag=' $pic_flag'
-	  ;;
-	pgf77* | pgf90* | pgf95* | pgfortran*)
-					# Portland Group f77 and f90 compilers
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-	  tmp_addflag=' $pic_flag -Mnomain' ;;
-	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
-	  tmp_addflag=' -i_dynamic' ;;
-	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
-	  tmp_addflag=' -i_dynamic -nofor_main' ;;
-	ifc* | ifort*)			# Intel Fortran compiler
-	  tmp_addflag=' -nofor_main' ;;
-	lf95*)				# Lahey Fortran 8.1
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
-	  tmp_sharedflag='--shared' ;;
-	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
-	  tmp_sharedflag='-qmkshrobj'
-	  tmp_addflag= ;;
-	nvcc*)	# Cuda Compiler Driver 2.2
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-	  _LT_TAGVAR(compiler_needs_object, $1)=yes
-	  ;;
-	esac
-	case `$CC -V 2>&1 | sed 5q` in
-	*Sun\ C*)			# Sun C 5.9
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-	  _LT_TAGVAR(compiler_needs_object, $1)=yes
-	  tmp_sharedflag='-G' ;;
-	*Sun\ F*)			# Sun Fortran 8.3
-	  tmp_sharedflag='-G' ;;
-	esac
-	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-
-        if test "x$supports_anon_versioning" = xyes; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	    echo "local: *; };" >> $output_objdir/$libname.ver~
-	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
-        fi
-
-	case $cc_basename in
-	xlf* | bgf* | bgxlf* | mpixlf*)
-	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-	  if test "x$supports_anon_versioning" = xyes; then
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	      echo "local: *; };" >> $output_objdir/$libname.ver~
-	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
-	  fi
-	  ;;
-	esac
-      else
-        _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
-	wlarc=
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      fi
-      ;;
-
-    solaris*)
-      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-	_LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
-      case `$LD -v 2>&1` in
-        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
-*** reliably create shared libraries on SCO systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-	;;
-	*)
-	  # For security reasons, it is highly recommended that you always
-	  # use absolute paths for naming shared libraries, and exclude the
-	  # DT_RUNPATH tag from executables and libraries.  But doing so
-	  # requires that you compile everything twice, which is a pain.
-	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-	  else
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	  fi
-	;;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      wlarc=
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-	_LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-    esac
-
-    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
-      runpath_var=
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-  else
-    # PORTME fill in a description of your system's linker (not GNU ld)
-    case $host_os in
-    aix3*)
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
-      # Note: this linker hardcodes the directories in LIBPATH if there
-      # are no directories specified by -L.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
-	# Neither direct hardcoding nor static linking is supported with a
-	# broken collect2.
-	_LT_TAGVAR(hardcode_direct, $1)=unsupported
-      fi
-      ;;
-
-    aix[[4-9]]*)
-      if test "$host_cpu" = ia64; then
-	# On IA64, the linker does run time linking by default, so we don't
-	# have to do anything special.
-	aix_use_runtimelinking=no
-	exp_sym_flag='-Bexport'
-	no_entry_flag=""
-      else
-	# If we're using GNU nm, then we don't want the "-C" option.
-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
-	# Also, AIX nm treats weak defined symbols like other global
-	# defined symbols, whereas GNU nm marks them as "W".
-	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-	else
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-	fi
-	aix_use_runtimelinking=no
-
-	# Test if we are trying to use run time linking or normal
-	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
-	# need to do runtime linking.
-	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-	  for ld_flag in $LDFLAGS; do
-	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
-	    aix_use_runtimelinking=yes
-	    break
-	  fi
-	  done
-	  ;;
-	esac
-
-	exp_sym_flag='-bexport'
-	no_entry_flag='-bnoentry'
-      fi
-
-      # When large executables or shared objects are built, AIX ld can
-      # have problems creating the table of contents.  If linking a library
-      # or program results in "error TOC overflow" add -mminimal-toc to
-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-      _LT_TAGVAR(archive_cmds, $1)=''
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
-
-      if test "$GCC" = yes; then
-	case $host_os in aix4.[[012]]|aix4.[[012]].*)
-	# We only want to do this on AIX 4.2 and lower, the check
-	# below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
-	  if test -f "$collect2name" &&
-	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-	  then
-	  # We have reworked collect2
-	  :
-	  else
-	  # We have old collect2
-	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
-	  # It fails to find uninstalled libraries when the uninstalled
-	  # path is not listed in the libpath.  Setting hardcode_minus_L
-	  # to unsupported forces relinking
-	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
-	  fi
-	  ;;
-	esac
-	shared_flag='-shared'
-	if test "$aix_use_runtimelinking" = yes; then
-	  shared_flag="$shared_flag "'${wl}-G'
-	fi
-	_LT_TAGVAR(link_all_deplibs, $1)=no
-      else
-	# not using gcc
-	if test "$host_cpu" = ia64; then
-	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-	# chokes on -Wl,-G. The following line is correct:
-	  shared_flag='-G'
-	else
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag='${wl}-G'
-	  else
-	    shared_flag='${wl}-bM:SRE'
-	  fi
-	fi
-      fi
-
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
-      # It seems that -bexpall does not export symbols beginning with
-      # underscore (_), so it is better to generate a list of symbols to export.
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      if test "$aix_use_runtimelinking" = yes; then
-	# Warning - without using the other runtime loading flags (-brtl),
-	# -berok will link without error, but may produce a broken library.
-	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
-      else
-	if test "$host_cpu" = ia64; then
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
-	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
-	else
-	 # Determine the default libpath from the value encoded in an
-	 # empty executable.
-	 _LT_SYS_MODULE_PATH_AIX([$1])
-	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-	  # Warning - without using the other run time loading flags,
-	  # -berok will link without error, but may produce a broken library.
-	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-	  if test "$with_gnu_ld" = yes; then
-	    # We only use this code for GNU lds that support --whole-archive.
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-	  else
-	    # Exported symbols can be pulled into shared objects from archives
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-	  fi
-	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	  # This is similar to how AIX traditionally builds its shared libraries.
-	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
-	fi
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    bsdi[[45]]*)
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++.
-      # hardcode_libdir_flag_spec is actually meaningless, as there is
-      # no search path for DLLs.
-      case $cc_basename in
-      cl*)
-	# Native MSVC
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	_LT_TAGVAR(always_export_symbols, $1)=yes
-	_LT_TAGVAR(file_list_spec, $1)='@'
-	# Tell ltmain to make .lib files, not .a files.
-	libext=lib
-	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
-	# FIXME: Setting linknames here is a bad hack.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	  else
-	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	  fi~
-	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	  linknames='
-	# The linker will not automatically build a static lib if we build a DLL.
-	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
-	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
-	# Don't use ranlib
-	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-	  lt_tool_outputfile="@TOOL_OUTPUT@"~
-	  case $lt_outputfile in
-	    *.exe|*.EXE) ;;
-	    *)
-	      lt_outputfile="$lt_outputfile.exe"
-	      lt_tool_outputfile="$lt_tool_outputfile.exe"
-	      ;;
-	  esac~
-	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	    $RM "$lt_outputfile.manifest";
-	  fi'
-	;;
-      *)
-	# Assume MSVC wrapper
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	# Tell ltmain to make .lib files, not .a files.
-	libext=lib
-	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
-	# FIXME: Setting linknames here is a bad hack.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
-	# The linker will automatically build a .lib file if we build a DLL.
-	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-	# FIXME: Should let the user specify the lib program.
-	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
-	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-	;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-      _LT_DARWIN_LINKER_FEATURES($1)
-      ;;
-
-    dgux*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
-    # support.  Future versions do this automatically, but an explicit c++rt0.o
-    # does not break anything, and helps significantly (at the cost of a little
-    # extra space).
-    freebsd2.2*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
-    freebsd2.*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
-    freebsd* | dragonfly*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    hpux9*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-
-      # hardcode_minus_L: Not really in the search PATH,
-      # but as the default location of the library.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-      ;;
-
-    hpux10*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      if test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
-	_LT_TAGVAR(hardcode_direct, $1)=yes
-	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-	# hardcode_minus_L: Not really in the search PATH,
-	# but as the default location of the library.
-	_LT_TAGVAR(hardcode_minus_L, $1)=yes
-      fi
-      ;;
-
-    hpux11*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-	case $host_cpu in
-	hppa*64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	ia64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	esac
-      else
-	case $host_cpu in
-	hppa*64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	ia64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	*)
-	m4_if($1, [], [
-	  # Older versions of the 11.00 compiler do not understand -b yet
-	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
-	  _LT_LINKER_OPTION([if $CC understands -b],
-	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
-	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
-	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
-	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
-	  ;;
-	esac
-      fi
-      if test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-	case $host_cpu in
-	hppa*64*|ia64*)
-	  _LT_TAGVAR(hardcode_direct, $1)=no
-	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	  ;;
-	*)
-	  _LT_TAGVAR(hardcode_direct, $1)=yes
-	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-
-	  # hardcode_minus_L: Not really in the search PATH,
-	  # but as the default location of the library.
-	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
-	  ;;
-	esac
-      fi
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-	# Try to use the -exported_symbol ld option, if it does not
-	# work, assume that -exports_file does not work either and
-	# implicitly export all symbols.
-	# This should be the same for all languages, so no per-tag cache variable.
-	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
-	  [lt_cv_irix_exported_symbol],
-	  [save_LDFLAGS="$LDFLAGS"
-	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
-	   AC_LINK_IFELSE(
-	     [AC_LANG_SOURCE(
-	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
-			      [C++], [[int foo (void) { return 0; }]],
-			      [Fortran 77], [[
-      subroutine foo
-      end]],
-			      [Fortran], [[
-      subroutine foo
-      end]])])],
-	      [lt_cv_irix_exported_symbol=yes],
-	      [lt_cv_irix_exported_symbol=no])
-           LDFLAGS="$save_LDFLAGS"])
-	if test "$lt_cv_irix_exported_symbol" = yes; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
-	fi
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(inherit_rpath, $1)=yes
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *nto* | *qnx*)
-      ;;
-
-    openbsd*)
-      if test -f /usr/libexec/ld.so; then
-	_LT_TAGVAR(hardcode_direct, $1)=yes
-	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-	else
-	  case $host_os in
-	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
-	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	     ;;
-	   *)
-	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	     ;;
-	  esac
-	fi
-      else
-	_LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    os2*)
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
-      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
-      ;;
-
-    osf3*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-      else
-	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    osf4* | osf5*)	# as osf3* with the addition of -msym flag
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      else
-	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
-
-	# Both c and cxx compiler support -rpath directly
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
-      if test "$GCC" = yes; then
-	wlarc='${wl}'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-      else
-	case `$CC -V 2>&1` in
-	*"Compilers 5.0"*)
-	  wlarc=''
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
-	  ;;
-	*)
-	  wlarc='${wl}'
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-	  ;;
-	esac
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      case $host_os in
-      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-      *)
-	# The compiler driver will combine and reorder linker options,
-	# but understands `-z linker_flag'.  GCC discards it without `$wl',
-	# but is careful enough not to reorder.
-	# Supported since Solaris 2.6 (maybe 2.5.1?)
-	if test "$GCC" = yes; then
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
-	else
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-	fi
-	;;
-      esac
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    sunos4*)
-      if test "x$host_vendor" = xsequent; then
-	# Use $CC to link under sequent, because it throws in some extra .o
-	# files that make .init and .fini sections work.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4)
-      case $host_vendor in
-	sni)
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
-	;;
-	siemens)
-	  ## LD is ld it makes a PLAMLIB
-	  ## CC just makes a GrossModule.
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
-	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
-	  _LT_TAGVAR(hardcode_direct, $1)=no
-        ;;
-	motorola)
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
-	;;
-      esac
-      runpath_var='LD_RUN_PATH'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4.3*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	runpath_var=LD_RUN_PATH
-	hardcode_runpath_var=yes
-	_LT_TAGVAR(ld_shlibs, $1)=yes
-      fi
-      ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We can NOT use -z defs as we might desire, because we do not
-      # link with -lc, and that would cause any symbols used from libc to
-      # always be unresolved, which means just about no library would
-      # ever link correctly.  If we're not using GNU ld we use -z text
-      # though, which does catch some bad symbols but isn't as heavy-handed
-      # as -z defs.
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
-      runpath_var='LD_RUN_PATH'
-
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      _LT_TAGVAR(ld_shlibs, $1)=no
-      ;;
-    esac
-
-    if test x$host_vendor = xsni; then
-      case $host in
-      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
-	;;
-      esac
-    fi
-  fi
-])
-AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-
-_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
-
-_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
-_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
-_LT_DECL([], [extract_expsyms_cmds], [2],
-    [The commands to extract the exported symbol list from a shared archive])
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
-x|xyes)
-  # Assume -lc should be added
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-
-  if test "$enable_shared" = yes && test "$GCC" = yes; then
-    case $_LT_TAGVAR(archive_cmds, $1) in
-    *'~'*)
-      # FIXME: we may have to deal with multi-command sequences.
-      ;;
-    '$CC '*)
-      # Test whether the compiler implicitly links with -lc since on some
-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
-      # to ld, don't add -lc before -lgcc.
-      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
-	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
-	[$RM conftest*
-	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
-	  soname=conftest
-	  lib=conftest
-	  libobjs=conftest.$ac_objext
-	  deplibs=
-	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
-	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
-	  compiler_flags=-v
-	  linker_flags=-v
-	  verstring=
-	  output_objdir=.
-	  libname=conftest
-	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
-	  _LT_TAGVAR(allow_undefined_flag, $1)=
-	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
-	  then
-	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-	  else
-	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	  fi
-	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
-	else
-	  cat conftest.err 1>&5
-	fi
-	$RM conftest*
-	])
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
-      ;;
-    esac
-  fi
-  ;;
-esac
-
-_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
-    [Whether or not to add -lc for building shared libraries])
-_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
-    [enable_shared_with_static_runtimes], [0],
-    [Whether or not to disallow shared libs when runtime libs are static])
-_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
-    [Compiler flag to allow reflexive dlopens])
-_LT_TAGDECL([], [whole_archive_flag_spec], [1],
-    [Compiler flag to generate shared objects directly from archives])
-_LT_TAGDECL([], [compiler_needs_object], [1],
-    [Whether the compiler copes with passing no objects directly])
-_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
-    [Create an old-style archive from a shared archive])
-_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
-    [Create a temporary old-style archive to link instead of a shared archive])
-_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
-_LT_TAGDECL([], [archive_expsym_cmds], [2])
-_LT_TAGDECL([], [module_cmds], [2],
-    [Commands used to build a loadable module if different from building
-    a shared archive.])
-_LT_TAGDECL([], [module_expsym_cmds], [2])
-_LT_TAGDECL([], [with_gnu_ld], [1],
-    [Whether we are building with GNU ld or not])
-_LT_TAGDECL([], [allow_undefined_flag], [1],
-    [Flag that allows shared libraries with undefined symbols to be built])
-_LT_TAGDECL([], [no_undefined_flag], [1],
-    [Flag that enforces no undefined symbols])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
-    [Flag to hardcode $libdir into a binary during linking.
-    This must work even if $libdir does not exist])
-_LT_TAGDECL([], [hardcode_libdir_separator], [1],
-    [Whether we need a single "-rpath" flag with a separated argument])
-_LT_TAGDECL([], [hardcode_direct], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
-    DIR into the resulting binary])
-_LT_TAGDECL([], [hardcode_direct_absolute], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
-    DIR into the resulting binary and the resulting library dependency is
-    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
-    library is relocated])
-_LT_TAGDECL([], [hardcode_minus_L], [0],
-    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
-    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_automatic], [0],
-    [Set to "yes" if building a shared library automatically hardcodes DIR
-    into the library and all subsequent libraries and executables linked
-    against it])
-_LT_TAGDECL([], [inherit_rpath], [0],
-    [Set to yes if linker adds runtime paths of dependent libraries
-    to runtime path list])
-_LT_TAGDECL([], [link_all_deplibs], [0],
-    [Whether libtool must link a program against all its dependency libraries])
-_LT_TAGDECL([], [always_export_symbols], [0],
-    [Set to "yes" if exported symbols are required])
-_LT_TAGDECL([], [export_symbols_cmds], [2],
-    [The commands to list exported symbols])
-_LT_TAGDECL([], [exclude_expsyms], [1],
-    [Symbols that should not be listed in the preloaded symbols])
-_LT_TAGDECL([], [include_expsyms], [1],
-    [Symbols that must always be exported])
-_LT_TAGDECL([], [prelink_cmds], [2],
-    [Commands necessary for linking programs (against libraries) with templates])
-_LT_TAGDECL([], [postlink_cmds], [2],
-    [Commands necessary for finishing linking programs])
-_LT_TAGDECL([], [file_list_spec], [1],
-    [Specify filename containing input files])
-dnl FIXME: Not yet implemented
-dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
-dnl    [Compiler flag to generate thread safe objects])
-])# _LT_LINKER_SHLIBS
-
-
-# _LT_LANG_C_CONFIG([TAG])
-# ------------------------
-# Ensure that the configuration variables for a C compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_C_CONFIG],
-[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC="$CC"
-AC_LANG_PUSH(C)
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-_LT_TAG_COMPILER
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_SYS_DYNAMIC_LINKER($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-  LT_SYS_DLOPEN_SELF
-  _LT_CMD_STRIPLIB
-
-  # Report which library types will actually be built
-  AC_MSG_CHECKING([if libtool supports shared libraries])
-  AC_MSG_RESULT([$can_build_shared])
-
-  AC_MSG_CHECKING([whether to build shared libraries])
-  test "$can_build_shared" = "no" && enable_shared=no
-
-  # On AIX, shared libraries and static libraries use the same namespace, and
-  # are all built from PIC.
-  case $host_os in
-  aix3*)
-    test "$enable_shared" = yes && enable_static=no
-    if test -n "$RANLIB"; then
-      archive_cmds="$archive_cmds~\$RANLIB \$lib"
-      postinstall_cmds='$RANLIB $lib'
-    fi
-    ;;
-
-  aix[[4-9]]*)
-    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-      test "$enable_shared" = yes && enable_static=no
-    fi
-    ;;
-  esac
-  AC_MSG_RESULT([$enable_shared])
-
-  AC_MSG_CHECKING([whether to build static libraries])
-  # Make sure either enable_shared or enable_static is yes.
-  test "$enable_shared" = yes || enable_static=yes
-  AC_MSG_RESULT([$enable_static])
-
-  _LT_CONFIG($1)
-fi
-AC_LANG_POP
-CC="$lt_save_CC"
-])# _LT_LANG_C_CONFIG
-
-
-# _LT_LANG_CXX_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a C++ compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_CXX_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
-    (test "X$CXX" != "Xg++"))) ; then
-  AC_PROG_CXXCPP
-else
-  _lt_caught_CXX_error=yes
-fi
-
-AC_LANG_PUSH(C++)
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(compiler_needs_object, $1)=no
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for C++ test sources.
-ac_ext=cpp
-
-# Object file extension for compiled C++ test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the CXX compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="int some_variable = 0;"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC=$CC
-  lt_save_CFLAGS=$CFLAGS
-  lt_save_LD=$LD
-  lt_save_GCC=$GCC
-  GCC=$GXX
-  lt_save_with_gnu_ld=$with_gnu_ld
-  lt_save_path_LD=$lt_cv_path_LD
-  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
-    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
-  else
-    $as_unset lt_cv_prog_gnu_ld
-  fi
-  if test -n "${lt_cv_path_LDCXX+set}"; then
-    lt_cv_path_LD=$lt_cv_path_LDCXX
-  else
-    $as_unset lt_cv_path_LD
-  fi
-  test -z "${LDCXX+set}" || LD=$LDCXX
-  CC=${CXX-"c++"}
-  CFLAGS=$CXXFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    # We don't want -fno-exception when compiling C++ code, so set the
-    # no_builtin_flag separately
-    if test "$GXX" = yes; then
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
-    else
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-    fi
-
-    if test "$GXX" = yes; then
-      # Set up default GNU C++ configuration
-
-      LT_PATH_LD
-
-      # Check if GNU C++ uses GNU ld as the underlying linker, since the
-      # archiving commands below assume that GNU ld is being used.
-      if test "$with_gnu_ld" = yes; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-
-        # If archive_cmds runs LD, not CC, wlarc should be empty
-        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
-        #     investigate it a little bit more. (MM)
-        wlarc='${wl}'
-
-        # ancient GNU ld didn't support --whole-archive et. al.
-        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
-	  $GREP 'no-whole-archive' > /dev/null; then
-          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-        else
-          _LT_TAGVAR(whole_archive_flag_spec, $1)=
-        fi
-      else
-        with_gnu_ld=no
-        wlarc=
-
-        # A generic and very simple default shared library creation
-        # command for GNU C++ for the case where it uses the native
-        # linker, instead of GNU ld.  If possible, this setting should
-        # overridden to take advantage of the native linker features on
-        # the platform it is being used on.
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-      fi
-
-      # Commands to make compiler produce verbose output that lists
-      # what "hidden" libraries, object files and flags are used when
-      # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-    else
-      GXX=no
-      with_gnu_ld=no
-      wlarc=
-    fi
-
-    # PORTME: fill in a description of your system's C++ link characteristics
-    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-    _LT_TAGVAR(ld_shlibs, $1)=yes
-    case $host_os in
-      aix3*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-      aix[[4-9]]*)
-        if test "$host_cpu" = ia64; then
-          # On IA64, the linker does run time linking by default, so we don't
-          # have to do anything special.
-          aix_use_runtimelinking=no
-          exp_sym_flag='-Bexport'
-          no_entry_flag=""
-        else
-          aix_use_runtimelinking=no
-
-          # Test if we are trying to use run time linking or normal
-          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # need to do runtime linking.
-          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-	    for ld_flag in $LDFLAGS; do
-	      case $ld_flag in
-	      *-brtl*)
-	        aix_use_runtimelinking=yes
-	        break
-	        ;;
-	      esac
-	    done
-	    ;;
-          esac
-
-          exp_sym_flag='-bexport'
-          no_entry_flag='-bnoentry'
-        fi
-
-        # When large executables or shared objects are built, AIX ld can
-        # have problems creating the table of contents.  If linking a library
-        # or program results in "error TOC overflow" add -mminimal-toc to
-        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-        _LT_TAGVAR(archive_cmds, $1)=''
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
-
-        if test "$GXX" = yes; then
-          case $host_os in aix4.[[012]]|aix4.[[012]].*)
-          # We only want to do this on AIX 4.2 and lower, the check
-          # below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
-	  if test -f "$collect2name" &&
-	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-	  then
-	    # We have reworked collect2
-	    :
-	  else
-	    # We have old collect2
-	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
-	    # It fails to find uninstalled libraries when the uninstalled
-	    # path is not listed in the libpath.  Setting hardcode_minus_L
-	    # to unsupported forces relinking
-	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
-	  fi
-          esac
-          shared_flag='-shared'
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag="$shared_flag "'${wl}-G'
-	  fi
-        else
-          # not using gcc
-          if test "$host_cpu" = ia64; then
-	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-	  # chokes on -Wl,-G. The following line is correct:
-	  shared_flag='-G'
-          else
-	    if test "$aix_use_runtimelinking" = yes; then
-	      shared_flag='${wl}-G'
-	    else
-	      shared_flag='${wl}-bM:SRE'
-	    fi
-          fi
-        fi
-
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
-        # It seems that -bexpall does not export symbols beginning with
-        # underscore (_), so it is better to generate a list of symbols to
-	# export.
-        _LT_TAGVAR(always_export_symbols, $1)=yes
-        if test "$aix_use_runtimelinking" = yes; then
-          # Warning - without using the other runtime loading flags (-brtl),
-          # -berok will link without error, but may produce a broken library.
-          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
-          # Determine the default libpath from the value encoded in an empty
-          # executable.
-          _LT_SYS_MODULE_PATH_AIX([$1])
-          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
-        else
-          if test "$host_cpu" = ia64; then
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
-	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
-          else
-	    # Determine the default libpath from the value encoded in an
-	    # empty executable.
-	    _LT_SYS_MODULE_PATH_AIX([$1])
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-	    # Warning - without using the other run time loading flags,
-	    # -berok will link without error, but may produce a broken library.
-	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-	    if test "$with_gnu_ld" = yes; then
-	      # We only use this code for GNU lds that support --whole-archive.
-	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-	    else
-	      # Exported symbols can be pulled into shared objects from archives
-	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-	    fi
-	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	    # This is similar to how AIX traditionally builds its shared
-	    # libraries.
-	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
-          fi
-        fi
-        ;;
-
-      beos*)
-	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-	  # support --undefined.  This deserves some investigation.  FIXME
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	else
-	  _LT_TAGVAR(ld_shlibs, $1)=no
-	fi
-	;;
-
-      chorus*)
-        case $cc_basename in
-          *)
-	  # FIXME: insert proper C++ library support
-	  _LT_TAGVAR(ld_shlibs, $1)=no
-	  ;;
-        esac
-        ;;
-
-      cygwin* | mingw* | pw32* | cegcc*)
-	case $GXX,$cc_basename in
-	,cl* | no,cl*)
-	  # Native MSVC
-	  # hardcode_libdir_flag_spec is actually meaningless, as there is
-	  # no search path for DLLs.
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	  _LT_TAGVAR(always_export_symbols, $1)=yes
-	  _LT_TAGVAR(file_list_spec, $1)='@'
-	  # Tell ltmain to make .lib files, not .a files.
-	  libext=lib
-	  # Tell ltmain to make .dll files, not .so files.
-	  shrext_cmds=".dll"
-	  # FIXME: Setting linknames here is a bad hack.
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	    else
-	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	    fi~
-	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	    linknames='
-	  # The linker will not automatically build a static lib if we build a DLL.
-	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-	  # Don't use ranlib
-	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-	    lt_tool_outputfile="@TOOL_OUTPUT@"~
-	    case $lt_outputfile in
-	      *.exe|*.EXE) ;;
-	      *)
-		lt_outputfile="$lt_outputfile.exe"
-		lt_tool_outputfile="$lt_tool_outputfile.exe"
-		;;
-	    esac~
-	    func_to_tool_file "$lt_outputfile"~
-	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	      $RM "$lt_outputfile.manifest";
-	    fi'
-	  ;;
-	*)
-	  # g++
-	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-	  # as there is no search path for DLLs.
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
-	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-	  _LT_TAGVAR(always_export_symbols, $1)=no
-	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-
-	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	    # If the export-symbols file already is a .def file (1st line
-	    # is EXPORTS), use it as is; otherwise, prepend...
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      cp $export_symbols $output_objdir/$soname.def;
-	    else
-	      echo EXPORTS > $output_objdir/$soname.def;
-	      cat $export_symbols >> $output_objdir/$soname.def;
-	    fi~
-	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	  else
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	  fi
-	  ;;
-	esac
-	;;
-      darwin* | rhapsody*)
-        _LT_DARWIN_LINKER_FEATURES($1)
-	;;
-
-      dgux*)
-        case $cc_basename in
-          ec++*)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          ghcx*)
-	    # Green Hills C++ Compiler
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          *)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-        esac
-        ;;
-
-      freebsd2.*)
-        # C++ shared libraries reported to be fairly broken before
-	# switch to ELF
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      freebsd-elf*)
-        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-        ;;
-
-      freebsd* | dragonfly*)
-        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
-        # conventions
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-        ;;
-
-      haiku*)
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        ;;
-
-      hpux9*)
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-				             # but as the default
-				             # location of the library.
-
-        case $cc_basename in
-          CC*)
-            # FIXME: insert proper C++ library support
-            _LT_TAGVAR(ld_shlibs, $1)=no
-            ;;
-          aCC*)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-            # Commands to make compiler produce verbose output that lists
-            # what "hidden" libraries, object files and flags are used when
-            # linking a shared library.
-            #
-            # There doesn't appear to be a way to prevent this compiler from
-            # explicitly linking system object files so we need to strip them
-            # from the output so that they don't get included in the library
-            # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-            ;;
-          *)
-            if test "$GXX" = yes; then
-              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-            else
-              # FIXME: insert proper C++ library support
-              _LT_TAGVAR(ld_shlibs, $1)=no
-            fi
-            ;;
-        esac
-        ;;
-
-      hpux10*|hpux11*)
-        if test $with_gnu_ld = no; then
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-          case $host_cpu in
-            hppa*64*|ia64*)
-              ;;
-            *)
-	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-              ;;
-          esac
-        fi
-        case $host_cpu in
-          hppa*64*|ia64*)
-            _LT_TAGVAR(hardcode_direct, $1)=no
-            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-            ;;
-          *)
-            _LT_TAGVAR(hardcode_direct, $1)=yes
-            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-					         # but as the default
-					         # location of the library.
-            ;;
-        esac
-
-        case $cc_basename in
-          CC*)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          aCC*)
-	    case $host_cpu in
-	      hppa*64*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	        ;;
-	      ia64*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	        ;;
-	      *)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	        ;;
-	    esac
-	    # Commands to make compiler produce verbose output that lists
-	    # what "hidden" libraries, object files and flags are used when
-	    # linking a shared library.
-	    #
-	    # There doesn't appear to be a way to prevent this compiler from
-	    # explicitly linking system object files so we need to strip them
-	    # from the output so that they don't get included in the library
-	    # dependencies.
-	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-	    ;;
-          *)
-	    if test "$GXX" = yes; then
-	      if test $with_gnu_ld = no; then
-	        case $host_cpu in
-	          hppa*64*)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	            ;;
-	          ia64*)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	            ;;
-	          *)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	            ;;
-	        esac
-	      fi
-	    else
-	      # FIXME: insert proper C++ library support
-	      _LT_TAGVAR(ld_shlibs, $1)=no
-	    fi
-	    ;;
-        esac
-        ;;
-
-      interix[[3-9]]*)
-	_LT_TAGVAR(hardcode_direct, $1)=no
-	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-	# Instead, shared libraries are loaded at an image base (0x10000000 by
-	# default) and relocated if they conflict, which is a slow very memory
-	# consuming and fragmenting process.  To avoid this, we pick a random,
-	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-	;;
-      irix5* | irix6*)
-        case $cc_basename in
-          CC*)
-	    # SGI C++
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-
-	    # Archives containing C++ object files must be created using
-	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
-	    # necessary to make sure instantiated templates are included
-	    # in the archive.
-	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
-	    ;;
-          *)
-	    if test "$GXX" = yes; then
-	      if test "$with_gnu_ld" = no; then
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-	      else
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
-	      fi
-	    fi
-	    _LT_TAGVAR(link_all_deplibs, $1)=yes
-	    ;;
-        esac
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(inherit_rpath, $1)=yes
-        ;;
-
-      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-        case $cc_basename in
-          KCC*)
-	    # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-	    # KCC will only create a shared library if the output file
-	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
-	    # to its proper name (with version) after linking.
-	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
-	    # Commands to make compiler produce verbose output that lists
-	    # what "hidden" libraries, object files and flags are used when
-	    # linking a shared library.
-	    #
-	    # There doesn't appear to be a way to prevent this compiler from
-	    # explicitly linking system object files so we need to strip them
-	    # from the output so that they don't get included in the library
-	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-
-	    # Archives containing C++ object files must be created using
-	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
-	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
-	    ;;
-	  icpc* | ecpc* )
-	    # Intel C++
-	    with_gnu_ld=yes
-	    # version 8.0 and above of icpc choke on multiply defined symbols
-	    # if we add $predep_objects and $postdep_objects, however 7.1 and
-	    # earlier do not add the objects themselves.
-	    case `$CC -V 2>&1` in
-	      *"Version 7."*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-		;;
-	      *)  # Version 8.0 or newer
-	        tmp_idyn=
-	        case $host_cpu in
-		  ia64*) tmp_idyn=' -i_dynamic';;
-		esac
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-		;;
-	    esac
-	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-	    ;;
-          pgCC* | pgcpp*)
-            # Portland Group C++ compiler
-	    case `$CC -V` in
-	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
-	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
-	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
-		$RANLIB $oldlib'
-	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
-	      ;;
-	    *) # Version 6 and above use weak symbols
-	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
-	      ;;
-	    esac
-
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-            ;;
-	  cxx*)
-	    # Compaq C++
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
-
-	    runpath_var=LD_RUN_PATH
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-	    # Commands to make compiler produce verbose output that lists
-	    # what "hidden" libraries, object files and flags are used when
-	    # linking a shared library.
-	    #
-	    # There doesn't appear to be a way to prevent this compiler from
-	    # explicitly linking system object files so we need to strip them
-	    # from the output so that they don't get included in the library
-	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
-	    ;;
-	  xl* | mpixl* | bgxl*)
-	    # IBM XL 8.0 on PPC, with GNU ld
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    if test "x$supports_anon_versioning" = xyes; then
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-		echo "local: *; };" >> $output_objdir/$libname.ver~
-		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
-	    fi
-	    ;;
-	  *)
-	    case `$CC -V 2>&1 | sed 5q` in
-	    *Sun\ C*)
-	      # Sun C++ 5.9
-	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
-	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-	      _LT_TAGVAR(compiler_needs_object, $1)=yes
-
-	      # Not sure whether something based on
-	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
-	      # would be better.
-	      output_verbose_link_cmd='func_echo_all'
-
-	      # Archives containing C++ object files must be created using
-	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-	      # necessary to make sure instantiated templates are included
-	      # in the archive.
-	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-	      ;;
-	    esac
-	    ;;
-	esac
-	;;
-
-      lynxos*)
-        # FIXME: insert proper C++ library support
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	;;
-
-      m88k*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-	;;
-
-      mvs*)
-        case $cc_basename in
-          cxx*)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-	  *)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-	esac
-	;;
-
-      netbsd*)
-        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
-	  wlarc=
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	  _LT_TAGVAR(hardcode_direct, $1)=yes
-	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	fi
-	# Workaround some broken pre-1.5 toolchains
-	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
-	;;
-
-      *nto* | *qnx*)
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-	;;
-
-      openbsd2*)
-        # C++ shared libraries are fairly broken
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	;;
-
-      openbsd*)
-	if test -f /usr/libexec/ld.so; then
-	  _LT_TAGVAR(hardcode_direct, $1)=yes
-	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-	  fi
-	  output_verbose_link_cmd=func_echo_all
-	else
-	  _LT_TAGVAR(ld_shlibs, $1)=no
-	fi
-	;;
-
-      osf3* | osf4* | osf5*)
-        case $cc_basename in
-          KCC*)
-	    # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-	    # KCC will only create a shared library if the output file
-	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
-	    # to its proper name (with version) after linking.
-	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-	    # Archives containing C++ object files must be created using
-	    # the KAI C++ compiler.
-	    case $host in
-	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
-	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
-	    esac
-	    ;;
-          RCC*)
-	    # Rational C++ 2.4.1
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          cxx*)
-	    case $host in
-	      osf3*)
-	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-		;;
-	      *)
-	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
-	          echo "-hidden">> $lib.exp~
-	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
-	          $RM $lib.exp'
-	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-		;;
-	    esac
-
-	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-	    # Commands to make compiler produce verbose output that lists
-	    # what "hidden" libraries, object files and flags are used when
-	    # linking a shared library.
-	    #
-	    # There doesn't appear to be a way to prevent this compiler from
-	    # explicitly linking system object files so we need to strip them
-	    # from the output so that they don't get included in the library
-	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-	    ;;
-	  *)
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	      case $host in
-	        osf3*)
-	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-		  ;;
-	        *)
-	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-		  ;;
-	      esac
-
-	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-	      # Commands to make compiler produce verbose output that lists
-	      # what "hidden" libraries, object files and flags are used when
-	      # linking a shared library.
-	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-	    else
-	      # FIXME: insert proper C++ library support
-	      _LT_TAGVAR(ld_shlibs, $1)=no
-	    fi
-	    ;;
-        esac
-        ;;
-
-      psos*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      sunos4*)
-        case $cc_basename in
-          CC*)
-	    # Sun C++ 4.x
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          lcc*)
-	    # Lucid
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          *)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-        esac
-        ;;
-
-      solaris*)
-        case $cc_basename in
-          CC* | sunCC*)
-	    # Sun C++ 4.2, 5.x and Centerline C++
-            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
-	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	    case $host_os in
-	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-	      *)
-		# The compiler driver will combine and reorder linker options,
-		# but understands `-z linker_flag'.
-	        # Supported since Solaris 2.6 (maybe 2.5.1?)
-		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-	        ;;
-	    esac
-	    _LT_TAGVAR(link_all_deplibs, $1)=yes
-
-	    output_verbose_link_cmd='func_echo_all'
-
-	    # Archives containing C++ object files must be created using
-	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-	    # necessary to make sure instantiated templates are included
-	    # in the archive.
-	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-	    ;;
-          gcx*)
-	    # Green Hills C++ Compiler
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-
-	    # The C++ compiler must be used to create the archive.
-	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
-	    ;;
-          *)
-	    # GNU C++ compiler with Solaris linker
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
-	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-	        # Commands to make compiler produce verbose output that lists
-	        # what "hidden" libraries, object files and flags are used when
-	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-	      else
-	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
-	        # platform.
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-	        # Commands to make compiler produce verbose output that lists
-	        # what "hidden" libraries, object files and flags are used when
-	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-	      fi
-
-	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
-	      case $host_os in
-		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-		*)
-		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
-		  ;;
-	      esac
-	    fi
-	    ;;
-        esac
-        ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      case $cc_basename in
-        CC*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-	*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  ;;
-      esac
-      ;;
-
-      sysv5* | sco3.2v5* | sco5v6*)
-	# Note: We can NOT use -z defs as we might desire, because we do not
-	# link with -lc, and that would cause any symbols used from libc to
-	# always be unresolved, which means just about no library would
-	# ever link correctly.  If we're not using GNU ld we use -z text
-	# though, which does catch some bad symbols but isn't as heavy-handed
-	# as -z defs.
-	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
-	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
-	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-	_LT_TAGVAR(link_all_deplibs, $1)=yes
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
-	runpath_var='LD_RUN_PATH'
-
-	case $cc_basename in
-          CC*)
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
-	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
-	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
-	      '"$_LT_TAGVAR(reload_cmds, $1)"
-	    ;;
-	  *)
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    ;;
-	esac
-      ;;
-
-      tandem*)
-        case $cc_basename in
-          NCC*)
-	    # NonStop-UX NCC 3.20
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-          *)
-	    # FIXME: insert proper C++ library support
-	    _LT_TAGVAR(ld_shlibs, $1)=no
-	    ;;
-        esac
-        ;;
-
-      vxworks*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      *)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-    esac
-
-    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-
-    _LT_TAGVAR(GCC, $1)="$GXX"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-  LDCXX=$LD
-  LD=$lt_save_LD
-  GCC=$lt_save_GCC
-  with_gnu_ld=$lt_save_with_gnu_ld
-  lt_cv_path_LDCXX=$lt_cv_path_LD
-  lt_cv_path_LD=$lt_save_path_LD
-  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
-  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
-
-AC_LANG_POP
-])# _LT_LANG_CXX_CONFIG
-
-
-# _LT_FUNC_STRIPNAME_CNF
-# ----------------------
-# func_stripname_cnf prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-#
-# This function is identical to the (non-XSI) version of func_stripname,
-# except this one can be used by m4 code that may be executed by configure,
-# rather than the libtool script.
-m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
-AC_REQUIRE([_LT_DECL_SED])
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
-func_stripname_cnf ()
-{
-  case ${2} in
-  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
-  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
-  esac
-} # func_stripname_cnf
-])# _LT_FUNC_STRIPNAME_CNF
-
-# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
-# ---------------------------------
-# Figure out "hidden" library dependencies from verbose
-# compiler output when linking a shared library.
-# Parse the compiler output and extract the necessary
-# objects, libraries and library flags.
-m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
-# Dependencies to place before and after the object being linked:
-_LT_TAGVAR(predep_objects, $1)=
-_LT_TAGVAR(postdep_objects, $1)=
-_LT_TAGVAR(predeps, $1)=
-_LT_TAGVAR(postdeps, $1)=
-_LT_TAGVAR(compiler_lib_search_path, $1)=
-
-dnl we can't use the lt_simple_compile_test_code here,
-dnl because it contains code intended for an executable,
-dnl not a library.  It's possible we should let each
-dnl tag define a new lt_????_link_test_code variable,
-dnl but it's only used here...
-m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
-int a;
-void foo (void) { a = 0; }
-_LT_EOF
-], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
-class Foo
-{
-public:
-  Foo (void) { a = 0; }
-private:
-  int a;
-};
-_LT_EOF
-], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer*4 a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
-public class foo {
-  private int a;
-  public void bar (void) {
-    a = 0;
-  }
-};
-_LT_EOF
-], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
-package foo
-func foo() {
-}
-_LT_EOF
-])
-
-_lt_libdeps_save_CFLAGS=$CFLAGS
-case "$CC $CFLAGS " in #(
-*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
-*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
-*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
-esac
-
-dnl Parse the compiler output and extract the necessary
-dnl objects, libraries and library flags.
-if AC_TRY_EVAL(ac_compile); then
-  # Parse the compiler output and extract the necessary
-  # objects, libraries and library flags.
-
-  # Sentinel used to keep track of whether or not we are before
-  # the conftest object file.
-  pre_test_object_deps_done=no
-
-  for p in `eval "$output_verbose_link_cmd"`; do
-    case ${prev}${p} in
-
-    -L* | -R* | -l*)
-       # Some compilers place space between "-{L,R}" and the path.
-       # Remove the space.
-       if test $p = "-L" ||
-          test $p = "-R"; then
-	 prev=$p
-	 continue
-       fi
-
-       # Expand the sysroot to ease extracting the directories later.
-       if test -z "$prev"; then
-         case $p in
-         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
-         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
-         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
-         esac
-       fi
-       case $p in
-       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
-       esac
-       if test "$pre_test_object_deps_done" = no; then
-	 case ${prev} in
-	 -L | -R)
-	   # Internal compiler library paths should come after those
-	   # provided the user.  The postdeps already come after the
-	   # user supplied libs so there is no need to process them.
-	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
-	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
-	   else
-	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
-	   fi
-	   ;;
-	 # The "-l" case would never come before the object being
-	 # linked, so don't bother handling this case.
-	 esac
-       else
-	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
-	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
-	 else
-	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
-	 fi
-       fi
-       prev=
-       ;;
-
-    *.lto.$objext) ;; # Ignore GCC LTO objects
-    *.$objext)
-       # This assumes that the test object file only shows up
-       # once in the compiler output.
-       if test "$p" = "conftest.$objext"; then
-	 pre_test_object_deps_done=yes
-	 continue
-       fi
-
-       if test "$pre_test_object_deps_done" = no; then
-	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
-	   _LT_TAGVAR(predep_objects, $1)="$p"
-	 else
-	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
-	 fi
-       else
-	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
-	   _LT_TAGVAR(postdep_objects, $1)="$p"
-	 else
-	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
-	 fi
-       fi
-       ;;
-
-    *) ;; # Ignore the rest.
-
-    esac
-  done
-
-  # Clean up.
-  rm -f a.out a.exe
-else
-  echo "libtool.m4: error: problem compiling $1 test program"
-fi
-
-$RM -f confest.$objext
-CFLAGS=$_lt_libdeps_save_CFLAGS
-
-# PORTME: override above test on systems where it is broken
-m4_if([$1], [CXX],
-[case $host_os in
-interix[[3-9]]*)
-  # Interix 3.5 installs completely hosed .la files for C++, so rather than
-  # hack all around it, let's just trust "g++" to DTRT.
-  _LT_TAGVAR(predep_objects,$1)=
-  _LT_TAGVAR(postdep_objects,$1)=
-  _LT_TAGVAR(postdeps,$1)=
-  ;;
-
-linux*)
-  case `$CC -V 2>&1 | sed 5q` in
-  *Sun\ C*)
-    # Sun C++ 5.9
-
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-
-solaris*)
-  case $cc_basename in
-  CC* | sunCC*)
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    # Adding this requires a known-good setup of shared libraries for
-    # Sun compiler versions before 5.6, else PIC objects from an old
-    # archive will be linked into the output, leading to subtle bugs.
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-esac
-])
-
-case " $_LT_TAGVAR(postdeps, $1) " in
-*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
-esac
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=
-if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
-fi
-_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
-    [The directories searched by this compiler when creating a shared library])
-_LT_TAGDECL([], [predep_objects], [1],
-    [Dependencies to place before and after the objects being linked to
-    create a shared library])
-_LT_TAGDECL([], [postdep_objects], [1])
-_LT_TAGDECL([], [predeps], [1])
-_LT_TAGDECL([], [postdeps], [1])
-_LT_TAGDECL([], [compiler_lib_search_path], [1],
-    [The library search path used internally by the compiler when linking
-    a shared library])
-])# _LT_SYS_HIDDEN_LIBDEPS
-
-
-# _LT_LANG_F77_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a Fortran 77 compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_F77_CONFIG],
-[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test "X$F77" = "Xno"; then
-  _lt_disable_F77=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for f77 test sources.
-ac_ext=f
-
-# Object file extension for compiled f77 test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the F77 compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_F77" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${F77-"f77"}
-  CFLAGS=$FFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-  GCC=$G77
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test "$enable_shared" = yes && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-	  test "$enable_shared" = yes && enable_static=no
-	fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)="$G77"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC="$lt_save_CC"
-  CFLAGS="$lt_save_CFLAGS"
-fi # test "$_lt_disable_F77" != yes
-
-AC_LANG_POP
-])# _LT_LANG_F77_CONFIG
-
-
-# _LT_LANG_FC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for a Fortran compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_FC_CONFIG],
-[AC_LANG_PUSH(Fortran)
-
-if test -z "$FC" || test "X$FC" = "Xno"; then
-  _lt_disable_FC=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for fc test sources.
-ac_ext=${ac_fc_srcext-f}
-
-# Object file extension for compiled fc test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the FC compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_FC" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${FC-"f95"}
-  CFLAGS=$FCFLAGS
-  compiler=$CC
-  GCC=$ac_cv_fc_compiler_gnu
-
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test "$enable_shared" = yes && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-	  test "$enable_shared" = yes && enable_static=no
-	fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-fi # test "$_lt_disable_FC" != yes
-
-AC_LANG_POP
-])# _LT_LANG_FC_CONFIG
-
-
-# _LT_LANG_GCJ_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Java Compiler compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_GCJ_CONFIG],
-[AC_REQUIRE([LT_PROG_GCJ])dnl
-AC_LANG_SAVE
-
-# Source file extension for Java test sources.
-ac_ext=java
-
-# Object file extension for compiled Java test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="class foo {}"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GCJ-"gcj"}
-CFLAGS=$GCJFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
-_LT_CC_BASENAME([$compiler])
-
-# GCJ did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-
-  _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GCJ_CONFIG
-
-
-# _LT_LANG_GO_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Go compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_GO_CONFIG],
-[AC_REQUIRE([LT_PROG_GO])dnl
-AC_LANG_SAVE
-
-# Source file extension for Go test sources.
-ac_ext=go
-
-# Object file extension for compiled Go test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="package main; func main() { }"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='package main; func main() { }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GOC-"gccgo"}
-CFLAGS=$GOFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
-_LT_CC_BASENAME([$compiler])
-
-# Go did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-
-  _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GO_CONFIG
-
-
-# _LT_LANG_RC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for the Windows resource compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_RC_CONFIG],
-[AC_REQUIRE([LT_PROG_RC])dnl
-AC_LANG_SAVE
-
-# Source file extension for RC test sources.
-ac_ext=rc
-
-# Object file extension for compiled RC test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
-
-# Code to be used in simple link tests
-lt_simple_link_test_code="$lt_simple_compile_test_code"
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC="$CC"
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=
-CC=${RC-"windres"}
-CFLAGS=
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_CC_BASENAME([$compiler])
-_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-
-if test -n "$compiler"; then
-  :
-  _LT_CONFIG($1)
-fi
-
-GCC=$lt_save_GCC
-AC_LANG_RESTORE
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_RC_CONFIG
-
-
-# LT_PROG_GCJ
-# -----------
-AC_DEFUN([LT_PROG_GCJ],
-[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
-  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
-    [AC_CHECK_TOOL(GCJ, gcj,)
-      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
-      AC_SUBST(GCJFLAGS)])])[]dnl
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
-
-
-# LT_PROG_GO
-# ----------
-AC_DEFUN([LT_PROG_GO],
-[AC_CHECK_TOOL(GOC, gccgo,)
-])
-
-
-# LT_PROG_RC
-# ----------
-AC_DEFUN([LT_PROG_RC],
-[AC_CHECK_TOOL(RC, windres,)
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_RC], [])
-
-
-# _LT_DECL_EGREP
-# --------------
-# If we don't have a new enough Autoconf to choose the best grep
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_EGREP],
-[AC_REQUIRE([AC_PROG_EGREP])dnl
-AC_REQUIRE([AC_PROG_FGREP])dnl
-test -z "$GREP" && GREP=grep
-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
-_LT_DECL([], [EGREP], [1], [An ERE matcher])
-_LT_DECL([], [FGREP], [1], [A literal string matcher])
-dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
-AC_SUBST([GREP])
-])
-
-
-# _LT_DECL_OBJDUMP
-# --------------
-# If we don't have a new enough Autoconf to choose the best objdump
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_OBJDUMP],
-[AC_CHECK_TOOL(OBJDUMP, objdump, false)
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
-AC_SUBST([OBJDUMP])
-])
-
-# _LT_DECL_DLLTOOL
-# ----------------
-# Ensure DLLTOOL variable is set.
-m4_defun([_LT_DECL_DLLTOOL],
-[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
-AC_SUBST([DLLTOOL])
-])
-
-# _LT_DECL_SED
-# ------------
-# Check for a fully-functional sed program, that truncates
-# as few characters as possible.  Prefer GNU sed if found.
-m4_defun([_LT_DECL_SED],
-[AC_PROG_SED
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
-_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
-    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
-])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-############################################################
-# NOTE: This macro has been submitted for inclusion into   #
-#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
-#  a released version of Autoconf we should remove this    #
-#  macro and use it instead.                               #
-############################################################
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for lt_ac_prog in sed gsed; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
-        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
-      fi
-    done
-  done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-lt_ac_count=0
-# Add /usr/xpg4/bin/sed as it is typically found on Solaris
-# along with /bin/sed that truncates output.
-for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
-  test ! -f $lt_ac_sed && continue
-  cat /dev/null > conftest.in
-  lt_ac_count=0
-  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
-  # Check for GNU sed and select it if it is found.
-  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
-    lt_cv_path_SED=$lt_ac_sed
-    break
-  fi
-  while true; do
-    cat conftest.in conftest.in >conftest.tmp
-    mv conftest.tmp conftest.in
-    cp conftest.in conftest.nl
-    echo >>conftest.nl
-    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
-    cmp -s conftest.out conftest.nl || break
-    # 10000 chars as input seems more than enough
-    test $lt_ac_count -gt 10 && break
-    lt_ac_count=`expr $lt_ac_count + 1`
-    if test $lt_ac_count -gt $lt_ac_max; then
-      lt_ac_max=$lt_ac_count
-      lt_cv_path_SED=$lt_ac_sed
-    fi
-  done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_SED], [])
-
-
-# _LT_CHECK_SHELL_FEATURES
-# ------------------------
-# Find out whether the shell is Bourne or XSI compatible,
-# or has some other useful features.
-m4_defun([_LT_CHECK_SHELL_FEATURES],
-[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
-  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
-      = c,a/b,b/c, \
-    && eval 'test $(( 1 + 1 )) -eq 2 \
-    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
-  && xsi_shell=yes
-AC_MSG_RESULT([$xsi_shell])
-_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
-
-AC_MSG_CHECKING([whether the shell understands "+="])
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
-    >/dev/null 2>&1 \
-  && lt_shell_append=yes
-AC_MSG_RESULT([$lt_shell_append])
-_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  lt_unset=unset
-else
-  lt_unset=false
-fi
-_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
-    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
-  lt_SP2NL='tr \040 \012'
-  lt_NL2SP='tr \015\012 \040\040'
-  ;;
- *) # EBCDIC based system
-  lt_SP2NL='tr \100 \n'
-  lt_NL2SP='tr \r\n \100\100'
-  ;;
-esac
-_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
-_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
-])# _LT_CHECK_SHELL_FEATURES
-
-
-# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
-# ------------------------------------------------------
-# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
-# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
-m4_defun([_LT_PROG_FUNCTION_REPLACE],
-[dnl {
-sed -e '/^$1 ()$/,/^} # $1 /c\
-$1 ()\
-{\
-m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
-} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-])
-
-
-# _LT_PROG_REPLACE_SHELLFNS
-# -------------------------
-# Replace existing portable implementations of several shell functions with
-# equivalent extended shell implementations where those features are available..
-m4_defun([_LT_PROG_REPLACE_SHELLFNS],
-[if test x"$xsi_shell" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
-    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
-    # positional parameters, so assign one to ordinary parameter first.
-    func_stripname_result=${3}
-    func_stripname_result=${func_stripname_result#"${1}"}
-    func_stripname_result=${func_stripname_result%"${2}"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
-    func_split_long_opt_name=${1%%=*}
-    func_split_long_opt_arg=${1#*=}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
-    func_split_short_opt_arg=${1#??}
-    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
-    case ${1} in
-      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
-      *)    func_lo2o_result=${1} ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
-
-  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
-
-  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
-fi
-
-if test x"$lt_shell_append" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
-    func_quote_for_eval "${2}"
-dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
-    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
-
-  # Save a `func_append' function call where possible by direct use of '+='
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-else
-  # Save a `func_append' function call even when '+=' is not available
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
-  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
-fi
-])
-
-# _LT_PATH_CONVERSION_FUNCTIONS
-# -----------------------------
-# Determine which file name conversion functions should be used by
-# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
-# for certain cross-compile configurations and native mingw.
-m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_MSG_CHECKING([how to convert $build file names to $host format])
-AC_CACHE_VAL(lt_cv_to_host_file_cmd,
-[case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
-        ;;
-    esac
-    ;;
-  *-*-cygwin* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_noop
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
-        ;;
-    esac
-    ;;
-  * ) # unhandled hosts (and "normal" native builds)
-    lt_cv_to_host_file_cmd=func_convert_file_noop
-    ;;
-esac
-])
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
-_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
-         [0], [convert $build file names to $host format])dnl
-
-AC_MSG_CHECKING([how to convert $build file names to toolchain format])
-AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
-[#assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
-        ;;
-    esac
-    ;;
-esac
-])
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
-_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
-         [0], [convert $build files to toolchain format])dnl
-])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
deleted file mode 100644
index 5d9acd8..0000000
--- a/m4/ltoptions.m4
+++ /dev/null
@@ -1,384 +0,0 @@
-# Helper functions for option handling.                    -*- Autoconf -*-
-#
-#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
-#   Inc.
-#   Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 7 ltoptions.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
-
-
-# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
-# ------------------------------------------
-m4_define([_LT_MANGLE_OPTION],
-[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
-
-
-# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
-# ---------------------------------------
-# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
-# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
-# saved as a flag.
-m4_define([_LT_SET_OPTION],
-[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
-m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
-        _LT_MANGLE_DEFUN([$1], [$2]),
-    [m4_warning([Unknown $1 option `$2'])])[]dnl
-])
-
-
-# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
-# ------------------------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-m4_define([_LT_IF_OPTION],
-[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
-
-
-# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
-# -------------------------------------------------------
-# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
-# are set.
-m4_define([_LT_UNLESS_OPTIONS],
-[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
-		      [m4_define([$0_found])])])[]dnl
-m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
-])[]dnl
-])
-
-
-# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
-# ----------------------------------------
-# OPTION-LIST is a space-separated list of Libtool options associated
-# with MACRO-NAME.  If any OPTION has a matching handler declared with
-# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
-# the unknown option and exit.
-m4_defun([_LT_SET_OPTIONS],
-[# Set options
-m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-    [_LT_SET_OPTION([$1], _LT_Option)])
-
-m4_if([$1],[LT_INIT],[
-  dnl
-  dnl Simply set some default values (i.e off) if boolean options were not
-  dnl specified:
-  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
-  ])
-  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
-  ])
-  dnl
-  dnl If no reference was made to various pairs of opposing options, then
-  dnl we run the default mode handler for the pair.  For example, if neither
-  dnl `shared' nor `disable-shared' was passed, we enable building of shared
-  dnl archives by default:
-  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
-  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
-  		   [_LT_ENABLE_FAST_INSTALL])
-  ])
-])# _LT_SET_OPTIONS
-
-
-## --------------------------------- ##
-## Macros to handle LT_INIT options. ##
-## --------------------------------- ##
-
-# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
-# -----------------------------------------
-m4_define([_LT_MANGLE_DEFUN],
-[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
-
-
-# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
-# -----------------------------------------------
-m4_define([LT_OPTION_DEFINE],
-[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
-])# LT_OPTION_DEFINE
-
-
-# dlopen
-# ------
-LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
-])
-
-AU_DEFUN([AC_LIBTOOL_DLOPEN],
-[_LT_SET_OPTION([LT_INIT], [dlopen])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `dlopen' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
-
-
-# win32-dll
-# ---------
-# Declare package support for building win32 dll's.
-LT_OPTION_DEFINE([LT_INIT], [win32-dll],
-[enable_win32_dll=yes
-
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
-  AC_CHECK_TOOL(AS, as, false)
-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
-  ;;
-esac
-
-test -z "$AS" && AS=as
-_LT_DECL([], [AS],      [1], [Assembler program])dnl
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
-])# win32-dll
-
-AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-_LT_SET_OPTION([LT_INIT], [win32-dll])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `win32-dll' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
-
-
-# _LT_ENABLE_SHARED([DEFAULT])
-# ----------------------------
-# implement the --enable-shared flag, and supports the `shared' and
-# `disable-shared' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_SHARED],
-[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([shared],
-    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
-	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_shared=yes ;;
-    no) enable_shared=no ;;
-    *)
-      enable_shared=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-	IFS="$lt_save_ifs"
-	if test "X$pkg" = "X$p"; then
-	  enable_shared=yes
-	fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
-
-    _LT_DECL([build_libtool_libs], [enable_shared], [0],
-	[Whether or not to build shared libraries])
-])# _LT_ENABLE_SHARED
-
-LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
-])
-
-AC_DEFUN([AC_DISABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], [disable-shared])
-])
-
-AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_SHARED], [])
-dnl AC_DEFUN([AM_DISABLE_SHARED], [])
-
-
-
-# _LT_ENABLE_STATIC([DEFAULT])
-# ----------------------------
-# implement the --enable-static flag, and support the `static' and
-# `disable-static' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_STATIC],
-[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([static],
-    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
-	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-	IFS="$lt_save_ifs"
-	if test "X$pkg" = "X$p"; then
-	  enable_static=yes
-	fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
-
-    _LT_DECL([build_old_libs], [enable_static], [0],
-	[Whether or not to build static libraries])
-])# _LT_ENABLE_STATIC
-
-LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
-])
-
-AC_DEFUN([AC_DISABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], [disable-static])
-])
-
-AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_STATIC], [])
-dnl AC_DEFUN([AM_DISABLE_STATIC], [])
-
-
-
-# _LT_ENABLE_FAST_INSTALL([DEFAULT])
-# ----------------------------------
-# implement the --enable-fast-install flag, and support the `fast-install'
-# and `disable-fast-install' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_FAST_INSTALL],
-[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([fast-install],
-    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
-    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_fast_install=yes ;;
-    no) enable_fast_install=no ;;
-    *)
-      enable_fast_install=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-	IFS="$lt_save_ifs"
-	if test "X$pkg" = "X$p"; then
-	  enable_fast_install=yes
-	fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
-
-_LT_DECL([fast_install], [enable_fast_install], [0],
-	 [Whether or not to optimize for fast installation])dnl
-])# _LT_ENABLE_FAST_INSTALL
-
-LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
-
-# Old names:
-AU_DEFUN([AC_ENABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `fast-install' option into LT_INIT's first parameter.])
-])
-
-AU_DEFUN([AC_DISABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `disable-fast-install' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
-dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
-
-
-# _LT_WITH_PIC([MODE])
-# --------------------
-# implement the --with-pic flag, and support the `pic-only' and `no-pic'
-# LT_INIT options.
-# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
-m4_define([_LT_WITH_PIC],
-[AC_ARG_WITH([pic],
-    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
-	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
-    [lt_p=${PACKAGE-default}
-    case $withval in
-    yes|no) pic_mode=$withval ;;
-    *)
-      pic_mode=default
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for lt_pkg in $withval; do
-	IFS="$lt_save_ifs"
-	if test "X$lt_pkg" = "X$lt_p"; then
-	  pic_mode=yes
-	fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [pic_mode=default])
-
-test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
-
-_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
-])# _LT_WITH_PIC
-
-LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
-
-# Old name:
-AU_DEFUN([AC_LIBTOOL_PICMODE],
-[_LT_SET_OPTION([LT_INIT], [pic-only])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `pic-only' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
-
-## ----------------- ##
-## LTDL_INIT Options ##
-## ----------------- ##
-
-m4_define([_LTDL_MODE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
-		 [m4_define([_LTDL_MODE], [nonrecursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [recursive],
-		 [m4_define([_LTDL_MODE], [recursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [subproject],
-		 [m4_define([_LTDL_MODE], [subproject])])
-
-m4_define([_LTDL_TYPE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [installable],
-		 [m4_define([_LTDL_TYPE], [installable])])
-LT_OPTION_DEFINE([LTDL_INIT], [convenience],
-		 [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
deleted file mode 100644
index 9000a05..0000000
--- a/m4/ltsugar.m4
+++ /dev/null
@@ -1,123 +0,0 @@
-# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
-#
-# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
-# Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 6 ltsugar.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
-
-
-# lt_join(SEP, ARG1, [ARG2...])
-# -----------------------------
-# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
-# associated separator.
-# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
-# versions in m4sugar had bugs.
-m4_define([lt_join],
-[m4_if([$#], [1], [],
-       [$#], [2], [[$2]],
-       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
-m4_define([_lt_join],
-[m4_if([$#$2], [2], [],
-       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
-
-
-# lt_car(LIST)
-# lt_cdr(LIST)
-# ------------
-# Manipulate m4 lists.
-# These macros are necessary as long as will still need to support
-# Autoconf-2.59 which quotes differently.
-m4_define([lt_car], [[$1]])
-m4_define([lt_cdr],
-[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
-       [$#], 1, [],
-       [m4_dquote(m4_shift($@))])])
-m4_define([lt_unquote], $1)
-
-
-# lt_append(MACRO-NAME, STRING, [SEPARATOR])
-# ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
-# Note that neither SEPARATOR nor STRING are expanded; they are appended
-# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
-# No SEPARATOR is output if MACRO-NAME was previously undefined (different
-# than defined and empty).
-#
-# This macro is needed until we can rely on Autoconf 2.62, since earlier
-# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
-m4_define([lt_append],
-[m4_define([$1],
-	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
-
-
-
-# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
-# ----------------------------------------------------------
-# Produce a SEP delimited list of all paired combinations of elements of
-# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
-# has the form PREFIXmINFIXSUFFIXn.
-# Needed until we can rely on m4_combine added in Autoconf 2.62.
-m4_define([lt_combine],
-[m4_if(m4_eval([$# > 3]), [1],
-       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
-[[m4_foreach([_Lt_prefix], [$2],
-	     [m4_foreach([_Lt_suffix],
-		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
-	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
-
-
-# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
-# -----------------------------------------------------------------------
-# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
-# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
-m4_define([lt_if_append_uniq],
-[m4_ifdef([$1],
-	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
-		 [lt_append([$1], [$2], [$3])$4],
-		 [$5])],
-	  [lt_append([$1], [$2], [$3])$4])])
-
-
-# lt_dict_add(DICT, KEY, VALUE)
-# -----------------------------
-m4_define([lt_dict_add],
-[m4_define([$1($2)], [$3])])
-
-
-# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
-# --------------------------------------------
-m4_define([lt_dict_add_subkey],
-[m4_define([$1($2:$3)], [$4])])
-
-
-# lt_dict_fetch(DICT, KEY, [SUBKEY])
-# ----------------------------------
-m4_define([lt_dict_fetch],
-[m4_ifval([$3],
-	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
-    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
-
-
-# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
-# -----------------------------------------------------------------
-m4_define([lt_if_dict_fetch],
-[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
-	[$5],
-    [$6])])
-
-
-# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
-# --------------------------------------------------------------
-m4_define([lt_dict_filter],
-[m4_if([$5], [], [],
-  [lt_join(m4_quote(m4_default([$4], [[, ]])),
-           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
-		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
-])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
deleted file mode 100644
index 07a8602..0000000
--- a/m4/ltversion.m4
+++ /dev/null
@@ -1,23 +0,0 @@
-# ltversion.m4 -- version numbers			-*- Autoconf -*-
-#
-#   Copyright (C) 2004 Free Software Foundation, Inc.
-#   Written by Scott James Remnant, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# @configure_input@
-
-# serial 3337 ltversion.m4
-# This file is part of GNU Libtool
-
-m4_define([LT_PACKAGE_VERSION], [2.4.2])
-m4_define([LT_PACKAGE_REVISION], [1.3337])
-
-AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.2'
-macro_revision='1.3337'
-_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
-_LT_DECL(, macro_revision, 0)
-])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
deleted file mode 100644
index c573da9..0000000
--- a/m4/lt~obsolete.m4
+++ /dev/null
@@ -1,98 +0,0 @@
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
-#
-#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
-#   Written by Scott James Remnant, 2004.
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
-# which have later been changed to m4_define as they aren't part of the
-# exported API, or moved to Autoconf or Automake where they belong.
-#
-# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# included after everything else.  This provides aclocal with the
-# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
-# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
-#
-# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
-# Yes, that means every name once taken will need to remain here until
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
-
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
diff --git a/m4/stl_hash.m4 b/m4/stl_hash.m4
index 0722b14..d7def1a 100644
--- a/m4/stl_hash.m4
+++ b/m4/stl_hash.m4
@@ -4,8 +4,7 @@
 # include AC_TRY_COMPILE for all the combinations we've seen in the
 # wild.  We define HASH_MAP_H to the location of the header file, and
 # HASH_NAMESPACE to the namespace the class (unordered_map or
-# hash_map) is in.  We define HAVE_UNORDERED_MAP if the class we found
-# is named unordered_map, or leave it undefined if not.
+# hash_map) is in.
 
 # This also checks if unordered map exists.
 AC_DEFUN([AC_CXX_STL_HASH],
diff --git a/objectivec/DevTools/check_version_stamps.sh b/objectivec/DevTools/check_version_stamps.sh
new file mode 100755
index 0000000..325b71d
--- /dev/null
+++ b/objectivec/DevTools/check_version_stamps.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+# This script checks that the runtime version number constant in the compiler
+# source and in the runtime source is the same.
+#
+# A distro can be made of the protobuf sources with only a subset of the
+# languages, so if the compiler depended on the Objective C runtime, those
+# builds would break. At the same time, we don't want the runtime source
+# depending on the compiler sources; so two copies of the constant are needed.
+
+set -eu
+
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/../.."
+
+die() {
+    echo "Error: $1"
+    exit 1
+}
+
+readonly ConstantName=GOOGLE_PROTOBUF_OBJC_GEN_VERSION
+
+# Collect version from plugin sources.
+
+readonly PluginSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc"
+readonly PluginVersion=$( \
+    cat "${PluginSrc}" \
+        | sed -n -e "s:const int32 ${ConstantName} = \([0-9]*\);:\1:p"
+)
+
+if [[ -z "${PluginVersion}" ]] ; then
+    die "Failed to find ${ConstantName} in the plugin source (${PluginSrc})."
+fi
+
+# Collect version from runtime sources.
+
+readonly RuntimeSrc="${ProtoRootDir}/objectivec/GPBBootstrap.h"
+readonly RuntimeVersion=$( \
+    cat "${RuntimeSrc}" \
+        | sed -n -e "s:#define ${ConstantName} \([0-9]*\):\1:p"
+)
+
+if [[ -z "${RuntimeVersion}" ]] ; then
+    die "Failed to find ${ConstantName} in the runtime source (${RuntimeSrc})."
+fi
+
+# Compare them.
+
+if [[ "${PluginVersion}" != "${RuntimeVersion}" ]] ; then
+    die "Versions don't match!
+   Plugin: ${PluginVersion} from ${PluginSrc}
+  Runtime: ${RuntimeVersion} from ${RuntimeSrc}
+"
+fi
+
+# Success
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh
new file mode 100755
index 0000000..8295313
--- /dev/null
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -0,0 +1,124 @@
+#!/bin/bash
+
+# Invoked by the Xcode projects to build the protos needed for the unittests.
+
+set -eu
+
+readonly OUTPUT_DIR="${PROJECT_DERIVED_FILE_DIR}/protos"
+
+# Helper for bailing.
+die() {
+  echo "Error: $1"
+  exit 2
+}
+
+# What to do.
+case "${ACTION}" in
+  "")
+    # Build, fall thru
+    ;;
+  "clean")
+    rm -rf "${OUTPUT_DIR}"
+    exit 0
+    ;;
+  *)
+    die "Unknown action requested: ${ACTION}"
+    ;;
+esac
+
+# Move to the top of the protobuf directories.
+cd "${SRCROOT}/.."
+
+[[ -x src/protoc ]] || \
+  die "Could not find the protoc binary; make sure you have built it (objectivec/DevTools/full_mac_build.sh -h)."
+
+RUN_PROTOC=no
+if [[ ! -d "${OUTPUT_DIR}" ]] ; then
+  RUN_PROTOC=yes
+else
+  # Find the newest input file (protos, compiler, and this script).
+  # (these patterns catch some extra stuff, but better to over sample than
+  # under)
+  readonly NewestInput=$(find \
+     src/google/protobuf/*.proto \
+     objectivec/Tests/*.proto \
+     src/.libs src/*.la src/protoc \
+     objectivec/DevTools/compile_testing_protos.sh \
+        -type f -print0 \
+        | xargs -0 stat -f "%m %N" \
+        | sort -n | tail -n1 | cut -f2- -d" ")
+  # Find the oldest output file.
+  readonly OldestOutput=$(find \
+        "${OUTPUT_DIR}" \
+        -type f -print0 \
+        | xargs -0 stat -f "%m %N" \
+        | sort -n -r | tail -n1 | cut -f2- -d" ")
+  # If the newest input is newer than the oldest output, regenerate.
+  if [[ "${NewestInput}" -nt "${OldestOutput}" ]] ; then
+    RUN_PROTOC=yes
+  fi
+fi
+
+if [[ "${RUN_PROTOC}" != "yes" ]] ; then
+  # Up to date.
+  exit 0
+fi
+
+# Ensure the output dir exists
+mkdir -p "${OUTPUT_DIR}/google/protobuf"
+
+CORE_PROTO_FILES=(
+  src/google/protobuf/unittest_arena.proto
+  src/google/protobuf/unittest_custom_options.proto
+  src/google/protobuf/unittest_enormous_descriptor.proto
+  src/google/protobuf/unittest_embed_optimize_for.proto
+  src/google/protobuf/unittest_empty.proto
+  src/google/protobuf/unittest_import.proto
+  src/google/protobuf/unittest_import_lite.proto
+  src/google/protobuf/unittest_lite.proto
+  src/google/protobuf/unittest_mset.proto
+  src/google/protobuf/unittest_mset_wire_format.proto
+  src/google/protobuf/unittest_no_arena.proto
+  src/google/protobuf/unittest_no_arena_import.proto
+  src/google/protobuf/unittest_no_generic_services.proto
+  src/google/protobuf/unittest_optimize_for.proto
+  src/google/protobuf/unittest.proto
+  src/google/protobuf/unittest_import_public.proto
+  src/google/protobuf/unittest_import_public_lite.proto
+  src/google/protobuf/unittest_drop_unknown_fields.proto
+  src/google/protobuf/unittest_preserve_unknown_enum.proto
+  src/google/protobuf/map_lite_unittest.proto
+  src/google/protobuf/map_proto2_unittest.proto
+  src/google/protobuf/map_unittest.proto
+)
+
+# The unittest_custom_options.proto extends the messages in descriptor.proto
+# so we build it in to test extending in general. The library doesn't provide
+# a descriptor as it doesn't use the classes/enums.
+CORE_PROTO_FILES+=(
+  src/google/protobuf/descriptor.proto
+)
+
+compile_proto() {
+  src/protoc                                   \
+    --objc_out="${OUTPUT_DIR}/google/protobuf" \
+    --proto_path=src/google/protobuf/          \
+    --proto_path=src                           \
+    $*
+}
+
+for a_proto in "${CORE_PROTO_FILES[@]}" ; do
+  compile_proto "${a_proto}"
+done
+
+OBJC_PROTO_FILES=(
+  objectivec/Tests/unittest_cycle.proto
+  objectivec/Tests/unittest_runtime_proto2.proto
+  objectivec/Tests/unittest_runtime_proto3.proto
+  objectivec/Tests/unittest_objc.proto
+  objectivec/Tests/unittest_objc_startup.proto
+)
+
+for a_proto in "${OBJC_PROTO_FILES[@]}" ; do
+  compile_proto --proto_path="objectivec/Tests" "${a_proto}"
+done
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
new file mode 100755
index 0000000..ff51d9f
--- /dev/null
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -0,0 +1,271 @@
+#!/bin/bash
+#
+# Helper to do build so you don't have to remember all the steps/args.
+
+
+set -eu
+
+# Some base locations.
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/../.."
+
+printUsage() {
+  NAME=$(basename "${0}")
+  cat << EOF
+usage: ${NAME} [OPTIONS]
+
+This script does the common build steps needed.
+
+OPTIONS:
+
+ General:
+
+   -h, --help
+         Show this message
+   -c, --clean
+         Issue a clean before the normal build.
+   -a, --autogen
+         Start by rerunning autogen & configure.
+   -r, --regenerate-descriptors
+         Run generate_descriptor_proto.sh to regenerate all the checked in
+         proto sources.
+   -j #, --jobs #
+         Force the number of parallel jobs (useful for debugging build issues).
+   --core-only
+         Skip some of the core protobuf build/checks to shorten the build time.
+   --skip-xcode
+         Skip the invoke of Xcode to test the runtime on both iOS and OS X.
+   --skip-xcode-ios
+         Skip the invoke of Xcode to test the runtime on iOS.
+   --skip-xcode-osx
+         Skip the invoke of Xcode to test the runtime on OS X.
+   --skip-objc-conformance
+         Skip the Objective C conformance tests (run on OS X).
+
+EOF
+}
+
+header() {
+  echo ""
+  echo "========================================================================"
+  echo "    ${@}"
+  echo "========================================================================"
+}
+
+# Thanks to libtool, builds can fail in odd ways and since it eats some output
+# it can be hard to spot, so force error output if make exits with a non zero.
+wrapped_make() {
+  set +e  # Don't stop if the command fails.
+  make $*
+  MAKE_EXIT_STATUS=$?
+  if [ ${MAKE_EXIT_STATUS} -ne 0 ]; then
+    echo "Error: 'make $*' exited with status ${MAKE_EXIT_STATUS}"
+    exit ${MAKE_EXIT_STATUS}
+  fi
+  set -e
+}
+
+NUM_MAKE_JOBS=$(/usr/sbin/sysctl -n hw.ncpu)
+if [[ "${NUM_MAKE_JOBS}" -lt 4 ]] ; then
+  NUM_MAKE_JOBS=4
+fi
+
+DO_AUTOGEN=no
+DO_CLEAN=no
+REGEN_DESCRIPTORS=no
+CORE_ONLY=no
+DO_XCODE_IOS_TESTS=yes
+DO_XCODE_OSX_TESTS=yes
+DO_OBJC_CONFORMANCE_TESTS=yes
+while [[ $# != 0 ]]; do
+  case "${1}" in
+    -h | --help )
+      printUsage
+      exit 0
+      ;;
+    -c | --clean )
+      DO_CLEAN=yes
+      ;;
+    -a | --autogen )
+      DO_AUTOGEN=yes
+      ;;
+    -r | --regenerate-descriptors )
+      REGEN_DESCRIPTORS=yes
+      ;;
+    -j | --jobs )
+      shift
+      NUM_MAKE_JOBS="${1}"
+      ;;
+    --core-only )
+      CORE_ONLY=yes
+      ;;
+    --skip-xcode )
+      DO_XCODE_IOS_TESTS=no
+      DO_XCODE_OSX_TESTS=no
+      ;;
+    --skip-xcode-ios )
+      DO_XCODE_IOS_TESTS=no
+      ;;
+    --skip-xcode-osx )
+      DO_XCODE_OSX_TESTS=no
+      ;;
+    --skip-objc-conformance )
+      DO_OBJC_CONFORMANCE_TESTS=no
+      ;;
+    -*)
+      echo "ERROR: Unknown option: ${1}" 1>&2
+      printUsage
+      exit 1
+      ;;
+    *)
+      echo "ERROR: Unknown argument: ${1}" 1>&2
+      printUsage
+      exit 1
+      ;;
+  esac
+  shift
+done
+
+# Into the proto dir.
+cd "${ProtoRootDir}"
+
+# if no Makefile, force the autogen.
+if [[ ! -f Makefile ]] ; then
+  DO_AUTOGEN=yes
+fi
+
+if [[ "${DO_AUTOGEN}" == "yes" ]] ; then
+  header "Running autogen & configure"
+  ./autogen.sh
+  ./configure \
+    CPPFLAGS="-mmacosx-version-min=10.9 -Wunused-const-variable -Wunused-function" \
+    CXXFLAGS="-Wnon-virtual-dtor -Woverloaded-virtual"
+fi
+
+if [[ "${DO_CLEAN}" == "yes" ]] ; then
+  header "Cleaning"
+  wrapped_make clean
+  if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
+    XCODEBUILD_CLEAN_BASE_IOS=(
+      xcodebuild
+        -project objectivec/ProtocolBuffers_iOS.xcodeproj
+        -scheme ProtocolBuffers
+    )
+  "${XCODEBUILD_CLEAN_BASE_IOS[@]}" -configuration Debug clean
+  "${XCODEBUILD_CLEAN_BASE_IOS[@]}" -configuration Release clean
+  fi
+  if [[ "${DO_XCODE_OSX_TESTS}" == "yes" ]] ; then
+    XCODEBUILD_CLEAN_BASE_OSX=(
+      xcodebuild
+        -project objectivec/ProtocolBuffers_OSX.xcodeproj
+        -scheme ProtocolBuffers
+    )
+  "${XCODEBUILD_CLEAN_BASE_OSX[@]}" -configuration Debug clean
+  "${XCODEBUILD_CLEAN_BASE_OSX[@]}" -configuration Release clean
+  fi
+fi
+
+if [[ "${REGEN_DESCRIPTORS}" == "yes" ]] ; then
+  header "Regenerating the descriptor sources."
+  ./generate_descriptor_proto.sh -j "${NUM_MAKE_JOBS}"
+fi
+
+if [[ "${CORE_ONLY}" == "yes" ]] ; then
+  header "Building core Only"
+  wrapped_make -j "${NUM_MAKE_JOBS}"
+else
+  header "Building"
+  # Can't issue these together, when fully parallel, something sometimes chokes
+  # at random.
+  wrapped_make -j "${NUM_MAKE_JOBS}" all
+  wrapped_make -j "${NUM_MAKE_JOBS}" check
+  # Fire off the conformance tests also.
+  cd conformance
+  wrapped_make -j "${NUM_MAKE_JOBS}" test_cpp
+  cd ..
+fi
+
+# Ensure the WKT sources checked in are current.
+objectivec/generate_well_known_types.sh --check-only -j "${NUM_MAKE_JOBS}"
+
+header "Checking on the ObjC Runtime Code"
+objectivec/DevTools/pddm_tests.py
+if ! objectivec/DevTools/pddm.py --dry-run objectivec/*.[hm] objectivec/Tests/*.[hm] ; then
+  echo ""
+  echo "Update by running:"
+  echo "   objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]"
+  exit 1
+fi
+
+if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
+  XCODEBUILD_TEST_BASE_IOS=(
+    xcodebuild
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj
+      -scheme ProtocolBuffers
+  )
+  # Don't need to worry about form factors or retina/non retina;
+  # just pick a mix of OS Versions and 32/64 bit.
+  # NOTE: Different Xcode have different simulated hardware/os support.
+  readonly XCODE_VERSION_LINE="$(xcodebuild -version | grep Xcode\  )"
+  readonly XCODE_VERSION="${XCODE_VERSION_LINE/Xcode /}"  # drop the prefix.
+  IOS_SIMULATOR_NAME="Simulator"
+  case "${XCODE_VERSION}" in
+    6.* )
+      echo "ERROR: Xcode 6.3/6.4 no longer supported for building, please use 7.0 or higher." 1>&2
+      exit 10
+      ;;
+    7.1* )
+      XCODEBUILD_TEST_BASE_IOS+=(
+          -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPhone 6,OS=9.0" # 64bit
+          -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPad Air,OS=9.0" # 64bit
+      )
+      ;;
+    7.3* )
+      XCODEBUILD_TEST_BASE_IOS+=(
+          -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPhone 6,OS=9.3" # 64bit
+          -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPad Air,OS=9.3" # 64bit
+      )
+      ;;
+    7.* )
+      XCODEBUILD_TEST_BASE_IOS+=(
+          -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
+          -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
+      )
+      ;;
+    * )
+      echo "Time to update the simulator targets for Xcode ${XCODE_VERSION}"
+      exit 2
+      ;;
+  esac
+  header "Doing Xcode iOS build/tests - Debug"
+  "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Debug test
+  header "Doing Xcode iOS build/tests - Release"
+  "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Release test
+  # Don't leave the simulator in the developer's face.
+  killall "${IOS_SIMULATOR_NAME}"
+fi
+if [[ "${DO_XCODE_OSX_TESTS}" == "yes" ]] ; then
+  XCODEBUILD_TEST_BASE_OSX=(
+    xcodebuild
+      -project objectivec/ProtocolBuffers_OSX.xcodeproj
+      -scheme ProtocolBuffers
+      # Since the ObjC 2.0 Runtime is required, 32bit OS X isn't supported.
+      -destination "platform=OS X,arch=x86_64" # 64bit
+  )
+  header "Doing Xcode OS X build/tests - Debug"
+  "${XCODEBUILD_TEST_BASE_OSX[@]}" -configuration Debug test
+  header "Doing Xcode OS X build/tests - Release"
+  "${XCODEBUILD_TEST_BASE_OSX[@]}" -configuration Release test
+fi
+
+if [[ "${DO_OBJC_CONFORMANCE_TESTS}" == "yes" ]] ; then
+  cd conformance
+  wrapped_make -j "${NUM_MAKE_JOBS}" test_objc
+  cd ..
+fi
diff --git a/objectivec/DevTools/pddm.py b/objectivec/DevTools/pddm.py
new file mode 100755
index 0000000..9a11fec
--- /dev/null
+++ b/objectivec/DevTools/pddm.py
@@ -0,0 +1,686 @@
+#! /usr/bin/python
+#
+# 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.
+
+"""PDDM - Poor Developers' Debug-able Macros
+
+A simple markup that can be added in comments of source so they can then be
+expanded out into code. Most of this could be done with CPP macros, but then
+developers can't really step through them in the debugger, this way they are
+expanded to the same code, but you can debug them.
+
+Any file can be processed, but the syntax is designed around a C based compiler.
+Processed lines start with "//%".  There are three types of sections you can
+create: Text (left alone), Macro Definitions, and Macro Expansions.  There is
+no order required between definitions and expansions, all definitions are read
+before any expansions are processed (thus, if desired, definitions can be put
+at the end of the file to keep them out of the way of the code).
+
+Macro Definitions are started with "//%PDDM-DEFINE Name(args)" and all lines
+afterwards that start with "//%" are included in the definition.  Multiple
+macros can be defined in one block by just using a another "//%PDDM-DEFINE"
+line to start the next macro.  Optionally, a macro can be ended with
+"//%PDDM-DEFINE-END", this can be useful when you want to make it clear that
+trailing blank lines are included in the macro.  You can also end a definition
+with an expansion.
+
+Macro Expansions are started by single lines containing
+"//%PDDM-EXPAND Name(args)" and then with "//%PDDM-EXPAND-END" or another
+expansions.  All lines in-between are replaced by the result of the expansion.
+The first line of the expansion is always a blank like just for readability.
+
+Expansion itself is pretty simple, one macro can invoke another macro, but
+you cannot nest the invoke of a macro in another macro (i.e. - can't do
+"foo(bar(a))", but you can define foo(a) and bar(b) where bar invokes foo()
+within its expansion.
+
+When macros are expanded, the arg references can also add "$O" suffix to the
+name (i.e. - "NAME$O") to specify an option to be applied. The options are:
+
+    $S - Replace each character in the value with a space.
+    $l - Lowercase the first letter of the value.
+    $L - Lowercase the whole value.
+    $u - Uppercase the first letter of the value.
+    $U - Uppercase the whole value.
+
+Within a macro you can use ## to cause things to get joined together after
+expansion (i.e. - "a##b" within a macro will become "ab").
+
+Example:
+
+    int foo(MyEnum x) {
+    switch (x) {
+    //%PDDM-EXPAND case(Enum_Left, 1)
+    //%PDDM-EXPAND case(Enum_Center, 2)
+    //%PDDM-EXPAND case(Enum_Right, 3)
+    //%PDDM-EXPAND-END
+    }
+
+    //%PDDM-DEFINE case(_A, _B)
+    //%  case _A:
+    //%    return _B;
+
+  A macro ends at the start of the next one, or an optional %PDDM-DEFINE-END
+  can be used to avoid adding extra blank lines/returns (or make it clear when
+  it is desired).
+
+  One macro can invoke another by simply using its name NAME(ARGS). You cannot
+  nest an invoke inside another (i.e. - NAME1(NAME2(ARGS)) isn't supported).
+
+  Within a macro you can use ## to cause things to get joined together after
+  processing (i.e. - "a##b" within a macro will become "ab").
+
+
+"""
+
+import optparse
+import os
+import re
+import sys
+
+
+# Regex for macro definition.
+_MACRO_RE = re.compile(r'(?P<name>\w+)\((?P<args>.*?)\)')
+# Regex for macro's argument definition.
+_MACRO_ARG_NAME_RE = re.compile(r'^\w+$')
+
+# Line inserted after each EXPAND.
+_GENERATED_CODE_LINE = (
+  '// This block of code is generated, do not edit it directly.'
+)
+
+
+def _MacroRefRe(macro_names):
+  # Takes in a list of macro names and makes a regex that will match invokes
+  # of those macros.
+  return re.compile(r'\b(?P<macro_ref>(?P<name>(%s))\((?P<args>.*?)\))' %
+                    '|'.join(macro_names))
+
+def _MacroArgRefRe(macro_arg_names):
+  # Takes in a list of macro arg names and makes a regex that will match
+  # uses of those args.
+  return re.compile(r'\b(?P<name>(%s))(\$(?P<option>.))?\b' %
+                    '|'.join(macro_arg_names))
+
+
+class PDDMError(Exception):
+  """Error thrown by pddm."""
+  pass
+
+
+class MacroCollection(object):
+  """Hold a set of macros and can resolve/expand them."""
+
+  def __init__(self, a_file=None):
+    """Initializes the collection.
+
+    Args:
+      a_file: The file like stream to parse.
+
+    Raises:
+      PDDMError if there are any issues.
+    """
+    self._macros = dict()
+    if a_file:
+      self.ParseInput(a_file)
+
+  class MacroDefinition(object):
+    """Holds a macro definition."""
+
+    def __init__(self, name, arg_names):
+      self._name = name
+      self._args = tuple(arg_names)
+      self._body = ''
+      self._needNewLine = False
+
+    def AppendLine(self, line):
+      if self._needNewLine:
+        self._body += '\n'
+      self._body += line
+      self._needNewLine = not line.endswith('\n')
+
+    @property
+    def name(self):
+      return self._name
+
+    @property
+    def args(self):
+      return self._args
+
+    @property
+    def body(self):
+      return self._body
+
+  def ParseInput(self, a_file):
+    """Consumes input extracting definitions.
+
+    Args:
+      a_file: The file like stream to parse.
+
+    Raises:
+      PDDMError if there are any issues.
+    """
+    input_lines = a_file.read().splitlines()
+    self.ParseLines(input_lines)
+
+  def ParseLines(self, input_lines):
+    """Parses list of lines.
+
+    Args:
+      input_lines: A list of strings of input to parse (no newlines on the
+                   strings).
+
+    Raises:
+      PDDMError if there are any issues.
+    """
+    current_macro = None
+    for line in input_lines:
+      if line.startswith('PDDM-'):
+        directive = line.split(' ', 1)[0]
+        if directive == 'PDDM-DEFINE':
+          name, args = self._ParseDefineLine(line)
+          if self._macros.get(name):
+            raise PDDMError('Attempt to redefine macro: "%s"' % line)
+          current_macro = self.MacroDefinition(name, args)
+          self._macros[name] = current_macro
+          continue
+        if directive == 'PDDM-DEFINE-END':
+          if not current_macro:
+            raise PDDMError('Got DEFINE-END directive without an active macro:'
+                            ' "%s"' % line)
+          current_macro = None
+          continue
+        raise PDDMError('Hit a line with an unknown directive: "%s"' % line)
+
+      if current_macro:
+        current_macro.AppendLine(line)
+        continue
+
+      # Allow blank lines between macro definitions.
+      if line.strip() == '':
+        continue
+
+      raise PDDMError('Hit a line that wasn\'t a directive and no open macro'
+                      ' definition: "%s"' % line)
+
+  def _ParseDefineLine(self, input_line):
+    assert input_line.startswith('PDDM-DEFINE')
+    line = input_line[12:].strip()
+    match = _MACRO_RE.match(line)
+    # Must match full line
+    if match is None or match.group(0) != line:
+      raise PDDMError('Failed to parse macro definition: "%s"' % input_line)
+    name = match.group('name')
+    args_str = match.group('args').strip()
+    args = []
+    if args_str:
+      for part in args_str.split(','):
+        arg = part.strip()
+        if arg == '':
+          raise PDDMError('Empty arg name in macro definition: "%s"'
+                          % input_line)
+        if not _MACRO_ARG_NAME_RE.match(arg):
+          raise PDDMError('Invalid arg name "%s" in macro definition: "%s"'
+                          % (arg, input_line))
+        if arg in args:
+          raise PDDMError('Arg name "%s" used more than once in macro'
+                          ' definition: "%s"' % (arg, input_line))
+        args.append(arg)
+    return (name, tuple(args))
+
+  def Expand(self, macro_ref_str):
+    """Expands the macro reference.
+
+    Args:
+      macro_ref_str: String of a macro reference (i.e. foo(a, b)).
+
+    Returns:
+      The text from the expansion.
+
+    Raises:
+      PDDMError if there are any issues.
+    """
+    match = _MACRO_RE.match(macro_ref_str)
+    if match is None or match.group(0) != macro_ref_str:
+      raise PDDMError('Failed to parse macro reference: "%s"' % macro_ref_str)
+    if match.group('name') not in self._macros:
+      raise PDDMError('No macro named "%s".' % match.group('name'))
+    return self._Expand(match, [], macro_ref_str)
+
+  def _FormatStack(self, macro_ref_stack):
+    result = ''
+    for _, macro_ref in reversed(macro_ref_stack):
+      result += '\n...while expanding "%s".' % macro_ref
+    return result
+
+  def _Expand(self, macro_ref_match, macro_stack, macro_ref_str=None):
+    if macro_ref_str is None:
+      macro_ref_str = macro_ref_match.group('macro_ref')
+    name = macro_ref_match.group('name')
+    for prev_name, prev_macro_ref in macro_stack:
+      if name == prev_name:
+        raise PDDMError('Found macro recusion, invoking "%s":%s' %
+                        (macro_ref_str, self._FormatStack(macro_stack)))
+    macro = self._macros[name]
+    args_str = macro_ref_match.group('args').strip()
+    args = []
+    if args_str or len(macro.args):
+      args = [x.strip() for x in args_str.split(',')]
+    if len(args) != len(macro.args):
+      raise PDDMError('Expected %d args, got: "%s".%s' %
+                      (len(macro.args), macro_ref_str,
+                       self._FormatStack(macro_stack)))
+    # Replace args usages.
+    result = self._ReplaceArgValues(macro, args, macro_ref_str, macro_stack)
+    # Expand any macro invokes.
+    new_macro_stack = macro_stack + [(name, macro_ref_str)]
+    while True:
+      eval_result = self._EvalMacrosRefs(result, new_macro_stack)
+      # Consume all ## directives to glue things together.
+      eval_result = eval_result.replace('##', '')
+      if eval_result == result:
+        break
+      result = eval_result
+    return result
+
+  def _ReplaceArgValues(self,
+                        macro, arg_values, macro_ref_to_report, macro_stack):
+    if len(arg_values) == 0:
+      # Nothing to do
+      return macro.body
+    assert len(arg_values) == len(macro.args)
+    args = dict(zip(macro.args, arg_values))
+    def _lookupArg(match):
+      val = args[match.group('name')]
+      opt = match.group('option')
+      if opt:
+        if opt == 'S': # Spaces for the length
+          return ' ' * len(val)
+        elif opt == 'l': # Lowercase first character
+          if val:
+            return val[0].lower() + val[1:]
+          else:
+            return val
+        elif opt == 'L': # All Lowercase
+          return val.lower()
+        elif opt == 'u': # Uppercase first character
+          if val:
+            return val[0].upper() + val[1:]
+          else:
+            return val
+        elif opt == 'U': # All Uppercase
+          return val.upper()
+        else:
+          raise PDDMError('Unknown arg option "%s$%s" while expanding "%s".%s'
+                          % (match.group('name'), match.group('option'),
+                             macro_ref_to_report,
+                             self._FormatStack(macro_stack)))
+      return val
+    # Let the regex do the work!
+    macro_arg_ref_re = _MacroArgRefRe(macro.args)
+    return macro_arg_ref_re.sub(_lookupArg, macro.body)
+
+  def _EvalMacrosRefs(self, text, macro_stack):
+    macro_ref_re = _MacroRefRe(self._macros.keys())
+    def _resolveMacro(match):
+      return self._Expand(match, macro_stack)
+    return macro_ref_re.sub(_resolveMacro, text)
+
+
+class SourceFile(object):
+  """Represents a source file with PDDM directives in it."""
+
+  def __init__(self, a_file, import_resolver=None):
+    """Initializes the file reading in the file.
+
+    Args:
+      a_file: The file to read in.
+      import_resolver: a function that given a path will return a stream for
+        the contents.
+
+    Raises:
+      PDDMError if there are any issues.
+    """
+    self._sections = []
+    self._original_content = a_file.read()
+    self._import_resolver = import_resolver
+    self._processed_content = None
+
+  class SectionBase(object):
+
+    def __init__(self, first_line_num):
+      self._lines = []
+      self._first_line_num = first_line_num
+
+    def TryAppend(self, line, line_num):
+      """Try appending a line.
+
+      Args:
+        line: The line to append.
+        line_num: The number of the line.
+
+      Returns:
+        A tuple of (SUCCESS, CAN_ADD_MORE).  If SUCCESS if False, the line
+        wasn't append.  If SUCCESS is True, then CAN_ADD_MORE is True/False to
+        indicate if more lines can be added after this one.
+      """
+      assert False, "sublcass should have overridden"
+      return (False, False)
+
+    def HitEOF(self):
+      """Called when the EOF was reached for for a given section."""
+      pass
+
+    def BindMacroCollection(self, macro_collection):
+      """Binds the chunk to a macro collection.
+
+      Args:
+        macro_collection: The collection to bind too.
+      """
+      pass
+
+    def Append(self, line):
+      self._lines.append(line)
+
+    @property
+    def lines(self):
+      return self._lines
+
+    @property
+    def num_lines_captured(self):
+      return len(self._lines)
+
+    @property
+    def first_line_num(self):
+      return self._first_line_num
+
+    @property
+    def first_line(self):
+      if not self._lines:
+        return ''
+      return self._lines[0]
+
+    @property
+    def text(self):
+      return '\n'.join(self.lines) + '\n'
+
+  class TextSection(SectionBase):
+    """Text section that is echoed out as is."""
+
+    def TryAppend(self, line, line_num):
+      if line.startswith('//%PDDM'):
+        return (False, False)
+      self.Append(line)
+      return (True, True)
+
+  class ExpansionSection(SectionBase):
+    """Section that is the result of an macro expansion."""
+
+    def __init__(self, first_line_num):
+      SourceFile.SectionBase.__init__(self, first_line_num)
+      self._macro_collection = None
+
+    def TryAppend(self, line, line_num):
+      if line.startswith('//%PDDM'):
+        directive = line.split(' ', 1)[0]
+        if directive == '//%PDDM-EXPAND':
+          self.Append(line)
+          return (True, True)
+        if directive == '//%PDDM-EXPAND-END':
+          assert self.num_lines_captured > 0
+          return (True, False)
+        raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' %
+                        (directive, line_num, self.first_line))
+      # Eat other lines.
+      return (True, True)
+
+    def HitEOF(self):
+      raise PDDMError('Hit the end of the file while in "%s".' %
+                      self.first_line)
+
+    def BindMacroCollection(self, macro_collection):
+      self._macro_collection = macro_collection
+
+    @property
+    def lines(self):
+      captured_lines = SourceFile.SectionBase.lines.fget(self)
+      directive_len = len('//%PDDM-EXPAND')
+      result = []
+      for line in captured_lines:
+        result.append(line)
+        if self._macro_collection:
+          # Always add a blank line, seems to read better. (If need be, add an
+          # option to the EXPAND to indicate if this should be done.)
+          result.extend([_GENERATED_CODE_LINE, ''])
+          macro = line[directive_len:].strip()
+          try:
+            expand_result = self._macro_collection.Expand(macro)
+            # Since expansions are line oriented, strip trailing whitespace
+            # from the lines.
+            lines = [x.rstrip() for x in expand_result.split('\n')]
+            result.append('\n'.join(lines))
+          except PDDMError as e:
+            raise PDDMError('%s\n...while expanding "%s" from the section'
+                            ' that started:\n   Line %d: %s' %
+                            (e.message, macro,
+                             self.first_line_num, self.first_line))
+
+      # Add the ending marker.
+      if len(captured_lines) == 1:
+        result.append('//%%PDDM-EXPAND-END %s' %
+                       captured_lines[0][directive_len:].strip())
+      else:
+        result.append('//%%PDDM-EXPAND-END (%s expansions)' % len(captured_lines))
+
+      return result
+
+  class DefinitionSection(SectionBase):
+    """Section containing macro definitions"""
+
+    def TryAppend(self, line, line_num):
+      if not line.startswith('//%'):
+        return (False, False)
+      if line.startswith('//%PDDM'):
+        directive = line.split(' ', 1)[0]
+        if directive == "//%PDDM-EXPAND":
+          return False, False
+        if directive not in ('//%PDDM-DEFINE', '//%PDDM-DEFINE-END'):
+          raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' %
+                          (directive, line_num, self.first_line))
+      self.Append(line)
+      return (True, True)
+
+    def BindMacroCollection(self, macro_collection):
+      if macro_collection:
+        try:
+          # Parse the lines after stripping the prefix.
+          macro_collection.ParseLines([x[3:] for x in self.lines])
+        except PDDMError as e:
+          raise PDDMError('%s\n...while parsing section that started:\n'
+                          '  Line %d: %s' %
+                          (e.message, self.first_line_num, self.first_line))
+
+  class ImportDefinesSection(SectionBase):
+    """Section containing an import of PDDM-DEFINES from an external file."""
+
+    def __init__(self, first_line_num, import_resolver):
+      SourceFile.SectionBase.__init__(self, first_line_num)
+      self._import_resolver = import_resolver
+
+    def TryAppend(self, line, line_num):
+      if not line.startswith('//%PDDM-IMPORT-DEFINES '):
+        return (False, False)
+      assert self.num_lines_captured == 0
+      self.Append(line)
+      return (True, False)
+
+    def BindMacroCollection(self, macro_colletion):
+      if not macro_colletion:
+        return
+      if self._import_resolver is None:
+        raise PDDMError('Got an IMPORT-DEFINES without a resolver (line %d):'
+                        ' "%s".' % (self.first_line_num, self.first_line))
+      import_name = self.first_line.split(' ', 1)[1].strip()
+      imported_file = self._import_resolver(import_name)
+      if imported_file is None:
+        raise PDDMError('Resolver failed to find "%s" (line %d):'
+                        ' "%s".' %
+                        (import_name, self.first_line_num, self.first_line))
+      try:
+        imported_src_file = SourceFile(imported_file, self._import_resolver)
+        imported_src_file._ParseFile()
+        for section in imported_src_file._sections:
+          section.BindMacroCollection(macro_colletion)
+      except PDDMError as e:
+        raise PDDMError('%s\n...while importing defines:\n'
+                        '  Line %d: %s' %
+                        (e.message, self.first_line_num, self.first_line))
+
+  def _ParseFile(self):
+    self._sections = []
+    lines = self._original_content.splitlines()
+    cur_section = None
+    for line_num, line in enumerate(lines, 1):
+      if not cur_section:
+        cur_section = self._MakeSection(line, line_num)
+      was_added, accept_more = cur_section.TryAppend(line, line_num)
+      if not was_added:
+        cur_section = self._MakeSection(line, line_num)
+        was_added, accept_more = cur_section.TryAppend(line, line_num)
+        assert was_added
+      if not accept_more:
+        cur_section = None
+
+    if cur_section:
+      cur_section.HitEOF()
+
+  def _MakeSection(self, line, line_num):
+    if not line.startswith('//%PDDM'):
+      section = self.TextSection(line_num)
+    else:
+      directive = line.split(' ', 1)[0]
+      if directive == '//%PDDM-EXPAND':
+        section = self.ExpansionSection(line_num)
+      elif directive == '//%PDDM-DEFINE':
+        section = self.DefinitionSection(line_num)
+      elif directive == '//%PDDM-IMPORT-DEFINES':
+        section = self.ImportDefinesSection(line_num, self._import_resolver)
+      else:
+        raise PDDMError('Unexpected line %d: "%s".' % (line_num, line))
+    self._sections.append(section)
+    return section
+
+  def ProcessContent(self, strip_expansion=False):
+    """Processes the file contents."""
+    self._ParseFile()
+    if strip_expansion:
+      # Without a collection the expansions become blank, removing them.
+      collection = None
+    else:
+      collection = MacroCollection()
+    for section in self._sections:
+      section.BindMacroCollection(collection)
+    result = ''
+    for section in self._sections:
+      result += section.text
+    self._processed_content = result
+
+  @property
+  def original_content(self):
+    return self._original_content
+
+  @property
+  def processed_content(self):
+    return self._processed_content
+
+
+def main(args):
+  usage = '%prog [OPTIONS] PATH ...'
+  description = (
+      'Processes PDDM directives in the given paths and write them back out.'
+  )
+  parser = optparse.OptionParser(usage=usage, description=description)
+  parser.add_option('--dry-run',
+                    default=False, action='store_true',
+                    help='Don\'t write back to the file(s), just report if the'
+                    ' contents needs an update and exit with a value of 1.')
+  parser.add_option('--verbose',
+                    default=False, action='store_true',
+                    help='Reports is a file is already current.')
+  parser.add_option('--collapse',
+                    default=False, action='store_true',
+                    help='Removes all the generated code.')
+  opts, extra_args = parser.parse_args(args)
+
+  if not extra_args:
+    parser.error('Need atleast one file to process')
+
+  result = 0
+  for a_path in extra_args:
+    if not os.path.exists(a_path):
+      sys.stderr.write('ERROR: File not found: %s\n' % a_path)
+      return 100
+
+    def _ImportResolver(name):
+      # resolve based on the file being read.
+      a_dir = os.path.dirname(a_path)
+      import_path = os.path.join(a_dir, name)
+      if not os.path.exists(import_path):
+        return None
+      return open(import_path, 'r')
+
+    with open(a_path, 'r') as f:
+      src_file = SourceFile(f, _ImportResolver)
+
+    try:
+      src_file.ProcessContent(strip_expansion=opts.collapse)
+    except PDDMError as e:
+      sys.stderr.write('ERROR: %s\n...While processing "%s"\n' %
+                       (e.message, a_path))
+      return 101
+
+    if src_file.processed_content != src_file.original_content:
+      if not opts.dry_run:
+        print 'Updating for "%s".' % a_path
+        with open(a_path, 'w') as f:
+          f.write(src_file.processed_content)
+      else:
+        # Special result to indicate things need updating.
+        print 'Update needed for "%s".' % a_path
+        result = 1
+    elif opts.verbose:
+      print 'No update for "%s".' % a_path
+
+  return result
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/objectivec/DevTools/pddm_tests.py b/objectivec/DevTools/pddm_tests.py
new file mode 100755
index 0000000..8a73b84
--- /dev/null
+++ b/objectivec/DevTools/pddm_tests.py
@@ -0,0 +1,515 @@
+#! /usr/bin/python
+#
+# 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.
+
+"""Tests for pddm.py."""
+
+import io
+import unittest
+
+import pddm
+
+
+class TestParsingMacros(unittest.TestCase):
+
+  def testParseEmpty(self):
+    f = io.StringIO(u'')
+    result = pddm.MacroCollection(f)
+    self.assertEqual(len(result._macros), 0)
+
+  def testParseOne(self):
+    f = io.StringIO(u"""PDDM-DEFINE foo( )
+body""")
+    result = pddm.MacroCollection(f)
+    self.assertEqual(len(result._macros), 1)
+    macro = result._macros.get('foo')
+    self.assertIsNotNone(macro)
+    self.assertEquals(macro.name, 'foo')
+    self.assertEquals(macro.args, tuple())
+    self.assertEquals(macro.body, 'body')
+
+  def testParseGeneral(self):
+    # Tests multiple defines, spaces in all places, etc.
+    f = io.StringIO(u"""
+PDDM-DEFINE noArgs( )
+body1
+body2
+
+PDDM-DEFINE-END
+
+PDDM-DEFINE oneArg(foo)
+body3
+PDDM-DEFINE  twoArgs( bar_ , baz )
+body4
+body5""")
+    result = pddm.MacroCollection(f)
+    self.assertEqual(len(result._macros), 3)
+    macro = result._macros.get('noArgs')
+    self.assertIsNotNone(macro)
+    self.assertEquals(macro.name, 'noArgs')
+    self.assertEquals(macro.args, tuple())
+    self.assertEquals(macro.body, 'body1\nbody2\n')
+    macro = result._macros.get('oneArg')
+    self.assertIsNotNone(macro)
+    self.assertEquals(macro.name, 'oneArg')
+    self.assertEquals(macro.args, ('foo',))
+    self.assertEquals(macro.body, 'body3')
+    macro = result._macros.get('twoArgs')
+    self.assertIsNotNone(macro)
+    self.assertEquals(macro.name, 'twoArgs')
+    self.assertEquals(macro.args, ('bar_', 'baz'))
+    self.assertEquals(macro.body, 'body4\nbody5')
+    # Add into existing collection
+    f = io.StringIO(u"""
+PDDM-DEFINE another(a,b,c)
+body1
+body2""")
+    result.ParseInput(f)
+    self.assertEqual(len(result._macros), 4)
+    macro = result._macros.get('another')
+    self.assertIsNotNone(macro)
+    self.assertEquals(macro.name, 'another')
+    self.assertEquals(macro.args, ('a', 'b', 'c'))
+    self.assertEquals(macro.body, 'body1\nbody2')
+
+  def testParseDirectiveIssues(self):
+    test_list = [
+      # Unknown directive
+      (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINED foo\nbaz',
+       'Hit a line with an unknown directive: '),
+      # End without begin
+      (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nPDDM-DEFINE-END\n',
+       'Got DEFINE-END directive without an active macro: '),
+      # Line not in macro block
+      (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nmumble\n',
+       'Hit a line that wasn\'t a directive and no open macro definition: '),
+      # Redefine macro
+      (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE foo(a)\nmumble\n',
+       'Attempt to redefine macro: '),
+    ]
+    for idx, (input_str, expected_prefix) in enumerate(test_list, 1):
+      f = io.StringIO(input_str)
+      try:
+        result = pddm.MacroCollection(f)
+        self.fail('Should throw exception, entry %d' % idx)
+      except pddm.PDDMError as e:
+        self.assertTrue(e.message.startswith(expected_prefix),
+                        'Entry %d failed: %r' % (idx, e))
+
+  def testParseBeginIssues(self):
+    test_list = [
+      # 1. No name
+      (u'PDDM-DEFINE\nmumble',
+       'Failed to parse macro definition: '),
+      # 2. No name (with spaces)
+      (u'PDDM-DEFINE  \nmumble',
+       'Failed to parse macro definition: '),
+      # 3. No open paren
+      (u'PDDM-DEFINE  foo\nmumble',
+       'Failed to parse macro definition: '),
+      # 4. No close paren
+      (u'PDDM-DEFINE foo(\nmumble',
+       'Failed to parse macro definition: '),
+      # 5. No close paren (with args)
+      (u'PDDM-DEFINE foo(a, b\nmumble',
+       'Failed to parse macro definition: '),
+      # 6. No name before args
+      (u'PDDM-DEFINE  (a, b)\nmumble',
+       'Failed to parse macro definition: '),
+      # 7. No name before args
+      (u'PDDM-DEFINE foo bar(a, b)\nmumble',
+       'Failed to parse macro definition: '),
+      # 8. Empty arg name
+      (u'PDDM-DEFINE foo(a, ,b)\nmumble',
+       'Empty arg name in macro definition: '),
+      (u'PDDM-DEFINE foo(a,,b)\nmumble',
+       'Empty arg name in macro definition: '),
+      # 10. Duplicate name
+      (u'PDDM-DEFINE foo(a,b,a,c)\nmumble',
+       'Arg name "a" used more than once in macro definition: '),
+      # 11. Invalid arg name
+      (u'PDDM-DEFINE foo(a b,c)\nmumble',
+       'Invalid arg name "a b" in macro definition: '),
+      (u'PDDM-DEFINE foo(a.b,c)\nmumble',
+       'Invalid arg name "a.b" in macro definition: '),
+      (u'PDDM-DEFINE foo(a-b,c)\nmumble',
+       'Invalid arg name "a-b" in macro definition: '),
+      (u'PDDM-DEFINE foo(a,b,c.)\nmumble',
+       'Invalid arg name "c." in macro definition: '),
+      # 15. Extra stuff after the name
+      (u'PDDM-DEFINE foo(a,c) foo\nmumble',
+       'Failed to parse macro definition: '),
+      (u'PDDM-DEFINE foo(a,c) foo)\nmumble',
+       'Failed to parse macro definition: '),
+    ]
+    for idx, (input_str, expected_prefix) in enumerate(test_list, 1):
+      f = io.StringIO(input_str)
+      try:
+        result = pddm.MacroCollection(f)
+        self.fail('Should throw exception, entry %d' % idx)
+      except pddm.PDDMError as e:
+        self.assertTrue(e.message.startswith(expected_prefix),
+                        'Entry %d failed: %r' % (idx, e))
+
+
+class TestExpandingMacros(unittest.TestCase):
+
+  def testExpandBasics(self):
+    f = io.StringIO(u"""
+PDDM-DEFINE noArgs( )
+body1
+body2
+
+PDDM-DEFINE-END
+
+PDDM-DEFINE oneArg(a)
+body3 a
+
+PDDM-DEFINE-END
+
+PDDM-DEFINE twoArgs(b,c)
+body4 b c
+body5
+PDDM-DEFINE-END
+
+""")
+    mc = pddm.MacroCollection(f)
+    test_list = [
+      (u'noArgs()',
+       'body1\nbody2\n'),
+      (u'oneArg(wee)',
+       'body3 wee\n'),
+      (u'twoArgs(having some, fun)',
+       'body4 having some fun\nbody5'),
+      # One arg, pass empty.
+      (u'oneArg()',
+       'body3 \n'),
+      # Two args, gets empty in each slot.
+      (u'twoArgs(, empty)',
+       'body4  empty\nbody5'),
+      (u'twoArgs(empty, )',
+       'body4 empty \nbody5'),
+      (u'twoArgs(, )',
+       'body4  \nbody5'),
+    ]
+    for idx, (input_str, expected) in enumerate(test_list, 1):
+      result = mc.Expand(input_str)
+      self.assertEqual(result, expected,
+                       'Entry %d --\n       Result: %r\n     Expected: %r' %
+                       (idx, result, expected))
+
+  def testExpandArgOptions(self):
+    f = io.StringIO(u"""
+PDDM-DEFINE bar(a)
+a-a$S-a$l-a$L-a$u-a$U
+PDDM-DEFINE-END
+""")
+    mc = pddm.MacroCollection(f)
+
+    self.assertEqual(mc.Expand('bar(xYz)'), 'xYz-   -xYz-xyz-XYz-XYZ')
+    self.assertEqual(mc.Expand('bar(MnoP)'), 'MnoP-    -mnoP-mnop-MnoP-MNOP')
+    # Test empty
+    self.assertEqual(mc.Expand('bar()'), '-----')
+
+  def testExpandSimpleMacroErrors(self):
+    f = io.StringIO(u"""
+PDDM-DEFINE foo(a, b)
+<a-z>
+PDDM-DEFINE baz(a)
+a - a$z
+""")
+    mc = pddm.MacroCollection(f)
+    test_list = [
+      # 1. Unknown macro
+      (u'bar()',
+       'No macro named "bar".'),
+      (u'bar(a)',
+       'No macro named "bar".'),
+      # 3. Arg mismatch
+      (u'foo()',
+       'Expected 2 args, got: "foo()".'),
+      (u'foo(a b)',
+       'Expected 2 args, got: "foo(a b)".'),
+      (u'foo(a,b,c)',
+       'Expected 2 args, got: "foo(a,b,c)".'),
+      # 6. Unknown option in expansion
+      (u'baz(mumble)',
+       'Unknown arg option "a$z" while expanding "baz(mumble)".'),
+    ]
+    for idx, (input_str, expected_err) in enumerate(test_list, 1):
+      try:
+        result = mc.Expand(input_str)
+        self.fail('Should throw exception, entry %d' % idx)
+      except pddm.PDDMError as e:
+        self.assertEqual(e.message, expected_err,
+                        'Entry %d failed: %r' % (idx, e))
+
+  def testExpandReferences(self):
+    f = io.StringIO(u"""
+PDDM-DEFINE StartIt()
+foo(abc, def)
+foo(ghi, jkl)
+PDDM-DEFINE foo(a, b)
+bar(a, int)
+bar(b, NSString *)
+PDDM-DEFINE bar(n, t)
+- (t)n;
+- (void)set##n$u##:(t)value;
+
+""")
+    mc = pddm.MacroCollection(f)
+    expected = """- (int)abc;
+- (void)setAbc:(int)value;
+
+- (NSString *)def;
+- (void)setDef:(NSString *)value;
+
+- (int)ghi;
+- (void)setGhi:(int)value;
+
+- (NSString *)jkl;
+- (void)setJkl:(NSString *)value;
+"""
+    self.assertEqual(mc.Expand('StartIt()'), expected)
+
+  def testCatchRecursion(self):
+    f = io.StringIO(u"""
+PDDM-DEFINE foo(a, b)
+bar(1, a)
+bar(2, b)
+PDDM-DEFINE bar(x, y)
+foo(x, y)
+""")
+    mc = pddm.MacroCollection(f)
+    try:
+      result = mc.Expand('foo(A,B)')
+      self.fail('Should throw exception, entry %d' % idx)
+    except pddm.PDDMError as e:
+      self.assertEqual(e.message,
+                       'Found macro recusion, invoking "foo(1, A)":\n...while expanding "bar(1, A)".\n...while expanding "foo(A,B)".')
+
+
+class TestParsingSource(unittest.TestCase):
+
+  def testBasicParse(self):
+    test_list = [
+      # 1. no directives
+      (u'a\nb\nc',
+       (3,) ),
+      # 2. One define
+      (u'a\n//%PDDM-DEFINE foo()\n//%body\nc',
+       (1, 2, 1) ),
+      # 3. Two defines
+      (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE bar()\n//%body2\nc',
+       (1, 4, 1) ),
+      # 4. Two defines with ends
+      (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE-END\n'
+       u'//%PDDM-DEFINE bar()\n//%body2\n//%PDDM-DEFINE-END\nc',
+       (1, 6, 1) ),
+      # 5. One expand, one define (that runs to end of file)
+      (u'a\n//%PDDM-EXPAND foo()\nbody\n//%PDDM-EXPAND-END\n'
+       u'//%PDDM-DEFINE bar()\n//%body2\n',
+       (1, 1, 2) ),
+      # 6. One define ended with an expand.
+      (u'a\nb\n//%PDDM-DEFINE bar()\n//%body2\n'
+       u'//%PDDM-EXPAND bar()\nbody2\n//%PDDM-EXPAND-END\n',
+       (2, 2, 1) ),
+      # 7. Two expands (one end), one define.
+      (u'a\n//%PDDM-EXPAND foo(1)\nbody\n//%PDDM-EXPAND foo(2)\nbody2\n//%PDDM-EXPAND-END\n'
+       u'//%PDDM-DEFINE foo()\n//%body2\n',
+       (1, 2, 2) ),
+    ]
+    for idx, (input_str, line_counts) in enumerate(test_list, 1):
+      f = io.StringIO(input_str)
+      sf = pddm.SourceFile(f)
+      sf._ParseFile()
+      self.assertEqual(len(sf._sections), len(line_counts),
+                       'Entry %d -- %d != %d' %
+                       (idx, len(sf._sections), len(line_counts)))
+      for idx2, (sec, expected) in enumerate(zip(sf._sections, line_counts), 1):
+        self.assertEqual(sec.num_lines_captured, expected,
+                         'Entry %d, section %d -- %d != %d' %
+                         (idx, idx2, sec.num_lines_captured, expected))
+
+  def testErrors(self):
+    test_list = [
+      # 1. Directive within expansion
+      (u'//%PDDM-EXPAND a()\n//%PDDM-BOGUS',
+       'Ran into directive ("//%PDDM-BOGUS", line 2) while in "//%PDDM-EXPAND a()".'),
+      (u'//%PDDM-EXPAND a()\n//%PDDM-DEFINE a()\n//%body\n',
+       'Ran into directive ("//%PDDM-DEFINE", line 2) while in "//%PDDM-EXPAND a()".'),
+      # 3. Expansion ran off end of file
+      (u'//%PDDM-EXPAND a()\na\nb\n',
+       'Hit the end of the file while in "//%PDDM-EXPAND a()".'),
+      # 4. Directive within define
+      (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-BOGUS',
+       'Ran into directive ("//%PDDM-BOGUS", line 3) while in "//%PDDM-DEFINE a()".'),
+      (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-EXPAND-END a()',
+       'Ran into directive ("//%PDDM-EXPAND-END", line 3) while in "//%PDDM-DEFINE a()".'),
+      # 6. Directives that shouldn't start sections
+      (u'a\n//%PDDM-DEFINE-END a()\n//a\n',
+       'Unexpected line 2: "//%PDDM-DEFINE-END a()".'),
+      (u'a\n//%PDDM-EXPAND-END a()\n//a\n',
+       'Unexpected line 2: "//%PDDM-EXPAND-END a()".'),
+      (u'//%PDDM-BOGUS\n//a\n',
+       'Unexpected line 1: "//%PDDM-BOGUS".'),
+    ]
+    for idx, (input_str, expected_err) in enumerate(test_list, 1):
+      f = io.StringIO(input_str)
+      try:
+        pddm.SourceFile(f)._ParseFile()
+        self.fail('Should throw exception, entry %d' % idx)
+      except pddm.PDDMError as e:
+        self.assertEqual(e.message, expected_err,
+                        'Entry %d failed: %r' % (idx, e))
+
+class TestProcessingSource(unittest.TestCase):
+
+  def testBasics(self):
+    input_str = u"""
+//%PDDM-IMPORT-DEFINES ImportFile
+foo
+//%PDDM-EXPAND mumble(abc)
+//%PDDM-EXPAND-END
+bar
+//%PDDM-EXPAND mumble(def)
+//%PDDM-EXPAND mumble(ghi)
+//%PDDM-EXPAND-END
+baz
+//%PDDM-DEFINE mumble(a_)
+//%a_: getName(a_)
+"""
+    input_str2 = u"""
+//%PDDM-DEFINE getName(x_)
+//%do##x_$u##(int x_);
+
+"""
+    expected = u"""
+//%PDDM-IMPORT-DEFINES ImportFile
+foo
+//%PDDM-EXPAND mumble(abc)
+// This block of code is generated, do not edit it directly.
+
+abc: doAbc(int abc);
+//%PDDM-EXPAND-END mumble(abc)
+bar
+//%PDDM-EXPAND mumble(def)
+// This block of code is generated, do not edit it directly.
+
+def: doDef(int def);
+//%PDDM-EXPAND mumble(ghi)
+// This block of code is generated, do not edit it directly.
+
+ghi: doGhi(int ghi);
+//%PDDM-EXPAND-END (2 expansions)
+baz
+//%PDDM-DEFINE mumble(a_)
+//%a_: getName(a_)
+"""
+    expected_stripped = u"""
+//%PDDM-IMPORT-DEFINES ImportFile
+foo
+//%PDDM-EXPAND mumble(abc)
+//%PDDM-EXPAND-END mumble(abc)
+bar
+//%PDDM-EXPAND mumble(def)
+//%PDDM-EXPAND mumble(ghi)
+//%PDDM-EXPAND-END (2 expansions)
+baz
+//%PDDM-DEFINE mumble(a_)
+//%a_: getName(a_)
+"""
+    def _Resolver(name):
+      self.assertEqual(name, 'ImportFile')
+      return io.StringIO(input_str2)
+    f = io.StringIO(input_str)
+    sf = pddm.SourceFile(f, _Resolver)
+    sf.ProcessContent()
+    self.assertEqual(sf.processed_content, expected)
+    # Feed it through and nothing should change.
+    f2 = io.StringIO(sf.processed_content)
+    sf2 = pddm.SourceFile(f2, _Resolver)
+    sf2.ProcessContent()
+    self.assertEqual(sf2.processed_content, expected)
+    self.assertEqual(sf2.processed_content, sf.processed_content)
+    # Test stripping (with the original input and expanded version).
+    f2 = io.StringIO(input_str)
+    sf2 = pddm.SourceFile(f2)
+    sf2.ProcessContent(strip_expansion=True)
+    self.assertEqual(sf2.processed_content, expected_stripped)
+    f2 = io.StringIO(sf.processed_content)
+    sf2 = pddm.SourceFile(f2, _Resolver)
+    sf2.ProcessContent(strip_expansion=True)
+    self.assertEqual(sf2.processed_content, expected_stripped)
+
+  def testProcessFileWithMacroParseError(self):
+    input_str = u"""
+foo
+//%PDDM-DEFINE mumble(a_)
+//%body
+//%PDDM-DEFINE mumble(x_)
+//%body2
+
+"""
+    f = io.StringIO(input_str)
+    sf = pddm.SourceFile(f)
+    try:
+      sf.ProcessContent()
+      self.fail('Should throw exception, entry %d' % idx)
+    except pddm.PDDMError as e:
+      self.assertEqual(e.message,
+                       'Attempt to redefine macro: "PDDM-DEFINE mumble(x_)"\n'
+                       '...while parsing section that started:\n'
+                       '  Line 3: //%PDDM-DEFINE mumble(a_)')
+
+  def testProcessFileWithExpandError(self):
+    input_str = u"""
+foo
+//%PDDM-DEFINE mumble(a_)
+//%body
+//%PDDM-EXPAND foobar(x_)
+//%PDDM-EXPAND-END
+
+"""
+    f = io.StringIO(input_str)
+    sf = pddm.SourceFile(f)
+    try:
+      sf.ProcessContent()
+      self.fail('Should throw exception, entry %d' % idx)
+    except pddm.PDDMError as e:
+      self.assertEqual(e.message,
+                       'No macro named "foobar".\n'
+                       '...while expanding "foobar(x_)" from the section that'
+                       ' started:\n   Line 5: //%PDDM-EXPAND foobar(x_)')
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/objectivec/GPBArray.h b/objectivec/GPBArray.h
new file mode 100644
index 0000000..afda57f
--- /dev/null
+++ b/objectivec/GPBArray.h
@@ -0,0 +1,549 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRuntimeTypes.h"
+
+// These classes are used for repeated fields of basic data types. They are used because
+// they perform better than boxing into NSNumbers in NSArrays.
+
+// Note: These are not meant to be subclassed.
+
+NS_ASSUME_NONNULL_BEGIN
+
+//%PDDM-EXPAND DECLARE_ARRAYS()
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int32
+
+@interface GPBInt32Array : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(int32_t)value;
++ (instancetype)arrayWithValueArray:(GPBInt32Array *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const int32_t [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBInt32Array *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (int32_t)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(int32_t)value;
+- (void)addValues:(const int32_t [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBInt32Array *)array;
+
+- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - UInt32
+
+@interface GPBUInt32Array : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(uint32_t)value;
++ (instancetype)arrayWithValueArray:(GPBUInt32Array *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const uint32_t [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBUInt32Array *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (uint32_t)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(uint32_t)value;
+- (void)addValues:(const uint32_t [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBUInt32Array *)array;
+
+- (void)insertValue:(uint32_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint32_t)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - Int64
+
+@interface GPBInt64Array : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(int64_t)value;
++ (instancetype)arrayWithValueArray:(GPBInt64Array *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const int64_t [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBInt64Array *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (int64_t)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(int64_t)value;
+- (void)addValues:(const int64_t [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBInt64Array *)array;
+
+- (void)insertValue:(int64_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int64_t)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - UInt64
+
+@interface GPBUInt64Array : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(uint64_t)value;
++ (instancetype)arrayWithValueArray:(GPBUInt64Array *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const uint64_t [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBUInt64Array *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (uint64_t)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(uint64_t)value;
+- (void)addValues:(const uint64_t [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBUInt64Array *)array;
+
+- (void)insertValue:(uint64_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint64_t)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - Float
+
+@interface GPBFloatArray : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(float)value;
++ (instancetype)arrayWithValueArray:(GPBFloatArray *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const float [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBFloatArray *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (float)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(float)value;
+- (void)addValues:(const float [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBFloatArray *)array;
+
+- (void)insertValue:(float)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(float)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - Double
+
+@interface GPBDoubleArray : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(double)value;
++ (instancetype)arrayWithValueArray:(GPBDoubleArray *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const double [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBDoubleArray *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (double)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(double)value;
+- (void)addValues:(const double [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBDoubleArray *)array;
+
+- (void)insertValue:(double)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(double)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - Bool
+
+@interface GPBBoolArray : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)array;
++ (instancetype)arrayWithValue:(BOOL)value;
++ (instancetype)arrayWithValueArray:(GPBBoolArray *)array;
++ (instancetype)arrayWithCapacity:(NSUInteger)count;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+// Initializes the array, copying the values.
+- (instancetype)initWithValues:(const BOOL [])values
+                         count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBBoolArray *)array;
+- (instancetype)initWithCapacity:(NSUInteger)count;
+
+- (BOOL)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block;
+
+- (void)addValue:(BOOL)value;
+- (void)addValues:(const BOOL [])values count:(NSUInteger)count;
+- (void)addValuesFromArray:(GPBBoolArray *)array;
+
+- (void)insertValue:(BOOL)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(BOOL)value;
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+#pragma mark - Enum
+
+@interface GPBEnumArray : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)array;
++ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                   rawValue:(int32_t)value;
++ (instancetype)arrayWithValueArray:(GPBEnumArray *)array;
++ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                   capacity:(NSUInteger)count;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+    NS_DESIGNATED_INITIALIZER;
+
+// Initializes the array, copying the values.
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                     count:(NSUInteger)count;
+- (instancetype)initWithValueArray:(GPBEnumArray *)array;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)count;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value at index is not a
+// valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (int32_t)valueAtIndex:(NSUInteger)index;
+
+- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (int32_t)rawValueAtIndex:(NSUInteger)index;
+
+- (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
+                           usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)addValue:(int32_t)value;
+- (void)addValues:(const int32_t [])values count:(NSUInteger)count;
+
+- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;
+
+// These methods bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+
+- (void)addRawValue:(int32_t)value;
+- (void)addRawValuesFromArray:(GPBEnumArray *)array;
+- (void)addRawValues:(const int32_t [])values count:(NSUInteger)count;
+
+- (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)index;
+
+- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)value;
+
+// No validation applies to these methods.
+
+- (void)removeValueAtIndex:(NSUInteger)index;
+- (void)removeAll;
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2;
+
+@end
+
+//%PDDM-EXPAND-END DECLARE_ARRAYS()
+
+NS_ASSUME_NONNULL_END
+
+//%PDDM-DEFINE DECLARE_ARRAYS()
+//%ARRAY_INTERFACE_SIMPLE(Int32, int32_t)
+//%ARRAY_INTERFACE_SIMPLE(UInt32, uint32_t)
+//%ARRAY_INTERFACE_SIMPLE(Int64, int64_t)
+//%ARRAY_INTERFACE_SIMPLE(UInt64, uint64_t)
+//%ARRAY_INTERFACE_SIMPLE(Float, float)
+//%ARRAY_INTERFACE_SIMPLE(Double, double)
+//%ARRAY_INTERFACE_SIMPLE(Bool, BOOL)
+//%ARRAY_INTERFACE_ENUM(Enum, int32_t)
+
+//
+// The common case (everything but Enum)
+//
+
+//%PDDM-DEFINE ARRAY_INTERFACE_SIMPLE(NAME, TYPE)
+//%#pragma mark - NAME
+//%
+//%@interface GPB##NAME##Array : NSObject <NSCopying>
+//%
+//%@property(nonatomic, readonly) NSUInteger count;
+//%
+//%+ (instancetype)array;
+//%+ (instancetype)arrayWithValue:(TYPE)value;
+//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array;
+//%+ (instancetype)arrayWithCapacity:(NSUInteger)count;
+//%
+//%- (instancetype)init NS_DESIGNATED_INITIALIZER;
+//%// Initializes the array, copying the values.
+//%- (instancetype)initWithValues:(const TYPE [])values
+//%                         count:(NSUInteger)count;
+//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array;
+//%- (instancetype)initWithCapacity:(NSUInteger)count;
+//%
+//%ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, Basic)
+//%
+//%ARRAY_MUTABLE_INTERFACE(NAME, TYPE, Basic)
+//%
+//%@end
+//%
+
+//
+// Macros specific to Enums (to tweak their interface).
+//
+
+//%PDDM-DEFINE ARRAY_INTERFACE_ENUM(NAME, TYPE)
+//%#pragma mark - NAME
+//%
+//%@interface GPB##NAME##Array : NSObject <NSCopying>
+//%
+//%@property(nonatomic, readonly) NSUInteger count;
+//%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+//%
+//%+ (instancetype)array;
+//%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                   rawValue:(TYPE)value;
+//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array;
+//%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                   capacity:(NSUInteger)count;
+//%
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%    NS_DESIGNATED_INITIALIZER;
+//%
+//%// Initializes the array, copying the values.
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                 rawValues:(const TYPE [])values
+//%                                     count:(NSUInteger)count;
+//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array;
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                  capacity:(NSUInteger)count;
+//%
+//%// These will return kGPBUnrecognizedEnumeratorValue if the value at index is not a
+//%// valid enumerator as defined by validationFunc. If the actual value is
+//%// desired, use "raw" version of the method.
+//%
+//%ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, NAME)
+//%
+//%// These methods bypass the validationFunc to provide access to values that were not
+//%// known at the time the binary was compiled.
+//%
+//%- (TYPE)rawValueAtIndex:(NSUInteger)index;
+//%
+//%- (void)enumerateRawValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+//%- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
+//%                           usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+//%
+//%// If value is not a valid enumerator as defined by validationFunc, these
+//%// methods will assert in debug, and will log in release and assign the value
+//%// to the default value. Use the rawValue methods below to assign non enumerator
+//%// values.
+//%
+//%ARRAY_MUTABLE_INTERFACE(NAME, TYPE, NAME)
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME)
+//%- (TYPE)valueAtIndex:(NSUInteger)index;
+//%
+//%- (void)enumerateValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+//%- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+//%                        usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+
+//%PDDM-DEFINE ARRAY_MUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME)
+//%- (void)addValue:(TYPE)value;
+//%- (void)addValues:(const TYPE [])values count:(NSUInteger)count;
+//%ARRAY_EXTRA_MUTABLE_METHODS1_##HELPER_NAME(NAME, TYPE)
+//%- (void)insertValue:(TYPE)value atIndex:(NSUInteger)index;
+//%
+//%- (void)replaceValueAtIndex:(NSUInteger)index withValue:(TYPE)value;
+//%ARRAY_EXTRA_MUTABLE_METHODS2_##HELPER_NAME(NAME, TYPE)
+//%- (void)removeValueAtIndex:(NSUInteger)index;
+//%- (void)removeAll;
+//%
+//%- (void)exchangeValueAtIndex:(NSUInteger)idx1
+//%            withValueAtIndex:(NSUInteger)idx2;
+
+//
+// These are hooks invoked by the above to do insert as needed.
+//
+
+//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS1_Basic(NAME, TYPE)
+//%- (void)addValuesFromArray:(GPB##NAME##Array *)array;
+//%
+//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS2_Basic(NAME, TYPE)
+// Empty
+//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS1_Enum(NAME, TYPE)
+// Empty
+//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS2_Enum(NAME, TYPE)
+//%
+//%// These methods bypass the validationFunc to provide setting of values that were not
+//%// known at the time the binary was compiled.
+//%
+//%- (void)addRawValue:(TYPE)value;
+//%- (void)addRawValuesFromArray:(GPB##NAME##Array *)array;
+//%- (void)addRawValues:(const TYPE [])values count:(NSUInteger)count;
+//%
+//%- (void)insertRawValue:(TYPE)value atIndex:(NSUInteger)index;
+//%
+//%- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(TYPE)value;
+//%
+//%// No validation applies to these methods.
+//%
diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m
new file mode 100644
index 0000000..426c7cb
--- /dev/null
+++ b/objectivec/GPBArray.m
@@ -0,0 +1,2534 @@
+// 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.
+
+#import "GPBArray_PackagePrivate.h"
+
+#import "GPBMessage_PackagePrivate.h"
+
+// Mutable arrays use an internal buffer that can always hold a multiple of this elements.
+#define kChunkSize 16
+#define CapacityFromCount(x) (((x / kChunkSize) + 1) * kChunkSize)
+
+static BOOL ArrayDefault_IsValidValue(int32_t value) {
+  // Anything but the bad value marker is allowed.
+  return (value != kGPBUnrecognizedEnumeratorValue);
+}
+
+//%PDDM-DEFINE VALIDATE_RANGE(INDEX, COUNT)
+//%  if (INDEX >= COUNT) {
+//%    [NSException raise:NSRangeException
+//%                format:@"Index (%lu) beyond bounds (%lu)",
+//%                       (unsigned long)INDEX, (unsigned long)COUNT];
+//%  }
+//%PDDM-DEFINE MAYBE_GROW_TO_SET_COUNT(NEW_COUNT)
+//%  if (NEW_COUNT > _capacity) {
+//%    [self internalResizeToCapacity:CapacityFromCount(NEW_COUNT)];
+//%  }
+//%  _count = NEW_COUNT;
+//%PDDM-DEFINE SET_COUNT_AND_MAYBE_SHRINK(NEW_COUNT)
+//%  _count = NEW_COUNT;
+//%  if ((NEW_COUNT + (2 * kChunkSize)) < _capacity) {
+//%    [self internalResizeToCapacity:CapacityFromCount(NEW_COUNT)];
+//%  }
+
+//
+// Macros for the common basic cases.
+//
+
+//%PDDM-DEFINE ARRAY_INTERFACE_SIMPLE(NAME, TYPE, FORMAT)
+//%#pragma mark - NAME
+//%
+//%@implementation GPB##NAME##Array {
+//% @package
+//%  TYPE *_values;
+//%  NSUInteger _count;
+//%  NSUInteger _capacity;
+//%}
+//%
+//%@synthesize count = _count;
+//%
+//%+ (instancetype)array {
+//%  return [[[self alloc] init] autorelease];
+//%}
+//%
+//%+ (instancetype)arrayWithValue:(TYPE)value {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+//%  // the type correct.
+//%  return [[(GPB##NAME##Array*)[self alloc] initWithValues:&value count:1] autorelease];
+//%}
+//%
+//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array {
+//%  return [[(GPB##NAME##Array*)[self alloc] initWithValueArray:array] autorelease];
+//%}
+//%
+//%+ (instancetype)arrayWithCapacity:(NSUInteger)count {
+//%  return [[[self alloc] initWithCapacity:count] autorelease];
+//%}
+//%
+//%- (instancetype)init {
+//%  self = [super init];
+//%  // No work needed;
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array {
+//%  return [self initWithValues:array->_values count:array->_count];
+//%}
+//%
+//%- (instancetype)initWithValues:(const TYPE [])values count:(NSUInteger)count {
+//%  self = [self init];
+//%  if (self) {
+//%    if (count && values) {
+//%      _values = reallocf(_values, count * sizeof(TYPE));
+//%      if (_values != NULL) {
+//%        _capacity = count;
+//%        memcpy(_values, values, count * sizeof(TYPE));
+//%        _count = count;
+//%      } else {
+//%        [self release];
+//%        [NSException raise:NSMallocException
+//%                    format:@"Failed to allocate %lu bytes",
+//%                           (unsigned long)(count * sizeof(TYPE))];
+//%      }
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithCapacity:(NSUInteger)count {
+//%  self = [self initWithValues:NULL count:0];
+//%  if (self && count) {
+//%    [self internalResizeToCapacity:count];
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)copyWithZone:(NSZone *)zone {
+//%  return [[GPB##NAME##Array allocWithZone:zone] initWithValues:_values count:_count];
+//%}
+//%
+//%ARRAY_IMMUTABLE_CORE(NAME, TYPE, , FORMAT)
+//%
+//%- (TYPE)valueAtIndex:(NSUInteger)index {
+//%VALIDATE_RANGE(index, _count)
+//%  return _values[index];
+//%}
+//%
+//%ARRAY_MUTABLE_CORE(NAME, TYPE, , FORMAT)
+//%@end
+//%
+
+//
+// Some core macros used for both the simple types and Enums.
+//
+
+//%PDDM-DEFINE ARRAY_IMMUTABLE_CORE(NAME, TYPE, ACCESSOR_NAME, FORMAT)
+//%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
+//%  free(_values);
+//%  [super dealloc];
+//%}
+//%
+//%- (BOOL)isEqual:(GPB##NAME##Array *)other {
+//%  if (self == other) {
+//%    return YES;
+//%  }
+//%  if (![other isKindOfClass:[GPB##NAME##Array class]]) {
+//%    return NO;
+//%  }
+//%  return (_count == other->_count
+//%          && memcmp(_values, other->_values, (_count * sizeof(TYPE))) == 0);
+//%}
+//%
+//%- (NSUInteger)hash {
+//%  // Follow NSArray's lead, and use the count as the hash.
+//%  return _count;
+//%}
+//%
+//%- (NSString *)description {
+//%  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+//%  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+//%    if (i == 0) {
+//%      [result appendFormat:@"##FORMAT##", _values[i]];
+//%    } else {
+//%      [result appendFormat:@", ##FORMAT##", _values[i]];
+//%    }
+//%  }
+//%  [result appendFormat:@" }"];
+//%  return result;
+//%}
+//%
+//%- (void)enumerate##ACCESSOR_NAME##ValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block {
+//%  [self enumerate##ACCESSOR_NAME##ValuesWithOptions:0 usingBlock:block];
+//%}
+//%
+//%- (void)enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)opts
+//%                  ACCESSOR_NAME$S      usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block {
+//%  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+//%  BOOL stop = NO;
+//%  if ((opts & NSEnumerationReverse) == 0) {
+//%    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+//%      block(_values[i], i, &stop);
+//%      if (stop) break;
+//%    }
+//%  } else if (_count > 0) {
+//%    for (NSUInteger i = _count; i > 0; --i) {
+//%      block(_values[i - 1], (i - 1), &stop);
+//%      if (stop) break;
+//%    }
+//%  }
+//%}
+
+//%PDDM-DEFINE MUTATION_HOOK_None()
+//%PDDM-DEFINE MUTATION_METHODS(NAME, TYPE, ACCESSOR_NAME, HOOK_1, HOOK_2)
+//%- (void)add##ACCESSOR_NAME##Value:(TYPE)value {
+//%  [self add##ACCESSOR_NAME##Values:&value count:1];
+//%}
+//%
+//%- (void)add##ACCESSOR_NAME##Values:(const TYPE [])values count:(NSUInteger)count {
+//%  if (values == NULL || count == 0) return;
+//%MUTATION_HOOK_##HOOK_1()  NSUInteger initialCount = _count;
+//%  NSUInteger newCount = initialCount + count;
+//%MAYBE_GROW_TO_SET_COUNT(newCount)
+//%  memcpy(&_values[initialCount], values, count * sizeof(TYPE));
+//%  if (_autocreator) {
+//%    GPBAutocreatedArrayModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%- (void)insert##ACCESSOR_NAME##Value:(TYPE)value atIndex:(NSUInteger)index {
+//%VALIDATE_RANGE(index, _count + 1)
+//%MUTATION_HOOK_##HOOK_2()  NSUInteger initialCount = _count;
+//%  NSUInteger newCount = initialCount + 1;
+//%MAYBE_GROW_TO_SET_COUNT(newCount)
+//%  if (index != initialCount) {
+//%    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(TYPE));
+//%  }
+//%  _values[index] = value;
+//%  if (_autocreator) {
+//%    GPBAutocreatedArrayModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%- (void)replaceValueAtIndex:(NSUInteger)index with##ACCESSOR_NAME##Value:(TYPE)value {
+//%VALIDATE_RANGE(index, _count)
+//%MUTATION_HOOK_##HOOK_2()  _values[index] = value;
+//%}
+
+//%PDDM-DEFINE ARRAY_MUTABLE_CORE(NAME, TYPE, ACCESSOR_NAME, FORMAT)
+//%- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+//%  _values = reallocf(_values, newCapacity * sizeof(TYPE));
+//%  if (_values == NULL) {
+//%    _capacity = 0;
+//%    _count = 0;
+//%    [NSException raise:NSMallocException
+//%                format:@"Failed to allocate %lu bytes",
+//%                       (unsigned long)(newCapacity * sizeof(TYPE))];
+//%  }
+//%  _capacity = newCapacity;
+//%}
+//%
+//%MUTATION_METHODS(NAME, TYPE, ACCESSOR_NAME, None, None)
+//%
+//%- (void)add##ACCESSOR_NAME##ValuesFromArray:(GPB##NAME##Array *)array {
+//%  [self add##ACCESSOR_NAME##Values:array->_values count:array->_count];
+//%}
+//%
+//%- (void)removeValueAtIndex:(NSUInteger)index {
+//%VALIDATE_RANGE(index, _count)
+//%  NSUInteger newCount = _count - 1;
+//%  if (index != newCount) {
+//%    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(TYPE));
+//%  }
+//%SET_COUNT_AND_MAYBE_SHRINK(newCount)
+//%}
+//%
+//%- (void)removeAll {
+//%SET_COUNT_AND_MAYBE_SHRINK(0)
+//%}
+//%
+//%- (void)exchangeValueAtIndex:(NSUInteger)idx1
+//%            withValueAtIndex:(NSUInteger)idx2 {
+//%VALIDATE_RANGE(idx1, _count)
+//%VALIDATE_RANGE(idx2, _count)
+//%  TYPE temp = _values[idx1];
+//%  _values[idx1] = _values[idx2];
+//%  _values[idx2] = temp;
+//%}
+//%
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Int32, int32_t, %d)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int32
+
+@implementation GPBInt32Array {
+ @package
+  int32_t *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(int32_t)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBInt32Array*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBInt32Array *)array {
+  return [[(GPBInt32Array*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBInt32Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(int32_t));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(int32_t));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(int32_t))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32Array allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBInt32Array *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32Array class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(int32_t))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%d", _values[i]];
+    } else {
+      [result appendFormat:@", %d", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (int32_t)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(int32_t));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(int32_t))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(int32_t)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const int32_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(int32_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBInt32Array *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int32_t));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  int32_t temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(UInt32, uint32_t, %u)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt32
+
+@implementation GPBUInt32Array {
+ @package
+  uint32_t *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(uint32_t)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBUInt32Array*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBUInt32Array *)array {
+  return [[(GPBUInt32Array*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBUInt32Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(uint32_t));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(uint32_t));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(uint32_t))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32Array allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBUInt32Array *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32Array class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(uint32_t))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%u", _values[i]];
+    } else {
+      [result appendFormat:@", %u", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (uint32_t)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(uint32_t));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(uint32_t))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(uint32_t)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const uint32_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(uint32_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(uint32_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint32_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint32_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBUInt32Array *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(uint32_t));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  uint32_t temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Int64, int64_t, %lld)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int64
+
+@implementation GPBInt64Array {
+ @package
+  int64_t *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(int64_t)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBInt64Array*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBInt64Array *)array {
+  return [[(GPBInt64Array*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBInt64Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(int64_t));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(int64_t));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(int64_t))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64Array allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBInt64Array *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64Array class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(int64_t))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%lld", _values[i]];
+    } else {
+      [result appendFormat:@", %lld", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (int64_t)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(int64_t));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(int64_t))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(int64_t)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const int64_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(int64_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(int64_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int64_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int64_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBInt64Array *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int64_t));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  int64_t temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(UInt64, uint64_t, %llu)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt64
+
+@implementation GPBUInt64Array {
+ @package
+  uint64_t *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(uint64_t)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBUInt64Array*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBUInt64Array *)array {
+  return [[(GPBUInt64Array*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBUInt64Array *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(uint64_t));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(uint64_t));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(uint64_t))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64Array allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBUInt64Array *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64Array class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(uint64_t))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%llu", _values[i]];
+    } else {
+      [result appendFormat:@", %llu", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (uint64_t)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(uint64_t));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(uint64_t))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(uint64_t)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const uint64_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(uint64_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(uint64_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint64_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint64_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBUInt64Array *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(uint64_t));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  uint64_t temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Float, float, %f)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Float
+
+@implementation GPBFloatArray {
+ @package
+  float *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(float)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBFloatArray*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBFloatArray *)array {
+  return [[(GPBFloatArray*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBFloatArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const float [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(float));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(float));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(float))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBFloatArray allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBFloatArray *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBFloatArray class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(float))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%f", _values[i]];
+    } else {
+      [result appendFormat:@", %f", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (float)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(float));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(float))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(float)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const float [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(float));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(float)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(float));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(float)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBFloatArray *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(float));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  float temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Double, double, %lf)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Double
+
+@implementation GPBDoubleArray {
+ @package
+  double *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(double)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBDoubleArray*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBDoubleArray *)array {
+  return [[(GPBDoubleArray*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBDoubleArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const double [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(double));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(double));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(double))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBDoubleArray allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBDoubleArray *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBDoubleArray class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(double))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%lf", _values[i]];
+    } else {
+      [result appendFormat:@", %lf", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (double)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(double));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(double))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(double)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const double [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(double));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(double)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(double));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(double)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBDoubleArray *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(double));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  double temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Bool, BOOL, %d)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool
+
+@implementation GPBBoolArray {
+ @package
+  BOOL *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+
++ (instancetype)array {
+  return [[[self alloc] init] autorelease];
+}
+
++ (instancetype)arrayWithValue:(BOOL)value {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get
+  // the type correct.
+  return [[(GPBBoolArray*)[self alloc] initWithValues:&value count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBBoolArray *)array {
+  return [[(GPBBoolArray*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithCapacity:(NSUInteger)count {
+  return [[[self alloc] initWithCapacity:count] autorelease];
+}
+
+- (instancetype)init {
+  self = [super init];
+  // No work needed;
+  return self;
+}
+
+- (instancetype)initWithValueArray:(GPBBoolArray *)array {
+  return [self initWithValues:array->_values count:array->_count];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values count:(NSUInteger)count {
+  self = [self init];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(BOOL));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(BOOL));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(BOOL))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)count {
+  self = [self initWithValues:NULL count:0];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolArray allocWithZone:zone] initWithValues:_values count:_count];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBBoolArray *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolArray class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(BOOL))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%d", _values[i]];
+    } else {
+      [result appendFormat:@", %d", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+
+- (BOOL)valueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  return _values[index];
+}
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(BOOL));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(BOOL))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addValue:(BOOL)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const BOOL [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(BOOL));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(BOOL)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(BOOL));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(BOOL)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addValuesFromArray:(GPBBoolArray *)array {
+  [self addValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(BOOL));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  BOOL temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+@end
+
+//%PDDM-EXPAND-END (7 expansions)
+
+#pragma mark - Enum
+
+@implementation GPBEnumArray {
+ @package
+  GPBEnumValidationFunc _validationFunc;
+  int32_t *_values;
+  NSUInteger _count;
+  NSUInteger _capacity;
+}
+
+@synthesize count = _count;
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)array {
+  return [[[self alloc] initWithValidationFunction:NULL] autorelease];
+}
+
++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func] autorelease];
+}
+
++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func
+                                   rawValue:(int32_t)value {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:&value
+                                             count:1] autorelease];
+}
+
++ (instancetype)arrayWithValueArray:(GPBEnumArray *)array {
+  return [[(GPBEnumArray*)[self alloc] initWithValueArray:array] autorelease];
+}
+
++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func
+                                   capacity:(NSUInteger)count {
+  return [[[self alloc] initWithValidationFunction:func capacity:count] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL];
+}
+
+- (instancetype)initWithValueArray:(GPBEnumArray *)array {
+  return [self initWithValidationFunction:array->_validationFunc
+                                rawValues:array->_values
+                                    count:array->_count];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  self = [super init];
+  if (self) {
+    _validationFunc = (func != NULL ? func : ArrayDefault_IsValidValue);
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                     count:(NSUInteger)count {
+  self = [self initWithValidationFunction:func];
+  if (self) {
+    if (count && values) {
+      _values = reallocf(_values, count * sizeof(int32_t));
+      if (_values != NULL) {
+        _capacity = count;
+        memcpy(_values, values, count * sizeof(int32_t));
+        _count = count;
+      } else {
+        [self release];
+        [NSException raise:NSMallocException
+                    format:@"Failed to allocate %lu bytes",
+                           (unsigned long)(count * sizeof(int32_t))];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)count {
+  self = [self initWithValidationFunction:func];
+  if (self && count) {
+    [self internalResizeToCapacity:count];
+  }
+  return self;
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBEnumArray allocWithZone:zone]
+             initWithValidationFunction:_validationFunc
+                              rawValues:_values
+                                  count:_count];
+}
+
+//%PDDM-EXPAND ARRAY_IMMUTABLE_CORE(Enum, int32_t, Raw, %d)
+// This block of code is generated, do not edit it directly.
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  free(_values);
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(GPBEnumArray *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBEnumArray class]]) {
+    return NO;
+  }
+  return (_count == other->_count
+          && memcmp(_values, other->_values, (_count * sizeof(int32_t))) == 0);
+}
+
+- (NSUInteger)hash {
+  // Follow NSArray's lead, and use the count as the hash.
+  return _count;
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self];
+  for (NSUInteger i = 0, count = _count; i < count; ++i) {
+    if (i == 0) {
+      [result appendFormat:@"%d", _values[i]];
+    } else {
+      [result appendFormat:@", %d", _values[i]];
+    }
+  }
+  [result appendFormat:@" }"];
+  return result;
+}
+
+- (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateRawValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
+                           usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  if ((opts & NSEnumerationReverse) == 0) {
+    for (NSUInteger i = 0, count = _count; i < count; ++i) {
+      block(_values[i], i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    for (NSUInteger i = _count; i > 0; --i) {
+      block(_values[i - 1], (i - 1), &stop);
+      if (stop) break;
+    }
+  }
+}
+//%PDDM-EXPAND-END ARRAY_IMMUTABLE_CORE(Enum, int32_t, Raw, %d)
+
+- (int32_t)valueAtIndex:(NSUInteger)index {
+//%PDDM-EXPAND VALIDATE_RANGE(index, _count)
+// This block of code is generated, do not edit it directly.
+
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+//%PDDM-EXPAND-END VALIDATE_RANGE(index, _count)
+  int32_t result = _values[index];
+  if (!_validationFunc(result)) {
+    result = kGPBUnrecognizedEnumeratorValue;
+  }
+  return result;
+}
+
+- (int32_t)rawValueAtIndex:(NSUInteger)index {
+//%PDDM-EXPAND VALIDATE_RANGE(index, _count)
+// This block of code is generated, do not edit it directly.
+
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+//%PDDM-EXPAND-END VALIDATE_RANGE(index, _count)
+  return _values[index];
+}
+
+- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  [self enumerateValuesWithOptions:0 usingBlock:block];
+}
+
+- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
+                        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
+  // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok).
+  BOOL stop = NO;
+  GPBEnumValidationFunc func = _validationFunc;
+  if ((opts & NSEnumerationReverse) == 0) {
+    int32_t *scan = _values;
+    int32_t *end = scan + _count;
+    for (NSUInteger i = 0; scan < end; ++i, ++scan) {
+      int32_t value = *scan;
+      if (!func(value)) {
+        value = kGPBUnrecognizedEnumeratorValue;
+      }
+      block(value, i, &stop);
+      if (stop) break;
+    }
+  } else if (_count > 0) {
+    int32_t *end = _values;
+    int32_t *scan = end + (_count - 1);
+    for (NSUInteger i = (_count - 1); scan >= end; --i, --scan) {
+      int32_t value = *scan;
+      if (!func(value)) {
+        value = kGPBUnrecognizedEnumeratorValue;
+      }
+      block(value, i, &stop);
+      if (stop) break;
+    }
+  }
+}
+
+//%PDDM-EXPAND ARRAY_MUTABLE_CORE(Enum, int32_t, Raw, %d)
+// This block of code is generated, do not edit it directly.
+
+- (void)internalResizeToCapacity:(NSUInteger)newCapacity {
+  _values = reallocf(_values, newCapacity * sizeof(int32_t));
+  if (_values == NULL) {
+    _capacity = 0;
+    _count = 0;
+    [NSException raise:NSMallocException
+                format:@"Failed to allocate %lu bytes",
+                       (unsigned long)(newCapacity * sizeof(int32_t))];
+  }
+  _capacity = newCapacity;
+}
+
+- (void)addRawValue:(int32_t)value {
+  [self addRawValues:&value count:1];
+}
+
+- (void)addRawValues:(const int32_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(int32_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  _values[index] = value;
+}
+
+- (void)addRawValuesFromArray:(GPBEnumArray *)array {
+  [self addRawValues:array->_values count:array->_count];
+}
+
+- (void)removeValueAtIndex:(NSUInteger)index {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  NSUInteger newCount = _count - 1;
+  if (index != newCount) {
+    memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int32_t));
+  }
+  _count = newCount;
+  if ((newCount + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+}
+
+- (void)removeAll {
+  _count = 0;
+  if ((0 + (2 * kChunkSize)) < _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(0)];
+  }
+}
+
+- (void)exchangeValueAtIndex:(NSUInteger)idx1
+            withValueAtIndex:(NSUInteger)idx2 {
+  if (idx1 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx1, (unsigned long)_count];
+  }
+  if (idx2 >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)idx2, (unsigned long)_count];
+  }
+  int32_t temp = _values[idx1];
+  _values[idx1] = _values[idx2];
+  _values[idx2] = temp;
+}
+
+//%PDDM-EXPAND MUTATION_METHODS(Enum, int32_t, , EnumValidationList, EnumValidationOne)
+// This block of code is generated, do not edit it directly.
+
+- (void)addValue:(int32_t)value {
+  [self addValues:&value count:1];
+}
+
+- (void)addValues:(const int32_t [])values count:(NSUInteger)count {
+  if (values == NULL || count == 0) return;
+  GPBEnumValidationFunc func = _validationFunc;
+  for (NSUInteger i = 0; i < count; ++i) {
+    if (!func(values[i])) {
+      [NSException raise:NSInvalidArgumentException
+                  format:@"%@: Attempt to set an unknown enum value (%d)",
+                         [self class], values[i]];
+    }
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + count;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  memcpy(&_values[initialCount], values, count * sizeof(int32_t));
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index {
+  if (index >= _count + 1) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count + 1];
+  }
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@: Attempt to set an unknown enum value (%d)",
+                       [self class], value];
+  }
+  NSUInteger initialCount = _count;
+  NSUInteger newCount = initialCount + 1;
+  if (newCount > _capacity) {
+    [self internalResizeToCapacity:CapacityFromCount(newCount)];
+  }
+  _count = newCount;
+  if (index != initialCount) {
+    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
+  }
+  _values[index] = value;
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value {
+  if (index >= _count) {
+    [NSException raise:NSRangeException
+                format:@"Index (%lu) beyond bounds (%lu)",
+                       (unsigned long)index, (unsigned long)_count];
+  }
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@: Attempt to set an unknown enum value (%d)",
+                       [self class], value];
+  }
+  _values[index] = value;
+}
+//%PDDM-EXPAND-END (2 expansions)
+
+//%PDDM-DEFINE MUTATION_HOOK_EnumValidationList()
+//%  GPBEnumValidationFunc func = _validationFunc;
+//%  for (NSUInteger i = 0; i < count; ++i) {
+//%    if (!func(values[i])) {
+//%      [NSException raise:NSInvalidArgumentException
+//%                  format:@"%@: Attempt to set an unknown enum value (%d)",
+//%                         [self class], values[i]];
+//%    }
+//%  }
+//%
+//%PDDM-DEFINE MUTATION_HOOK_EnumValidationOne()
+//%  if (!_validationFunc(value)) {
+//%    [NSException raise:NSInvalidArgumentException
+//%                format:@"%@: Attempt to set an unknown enum value (%d)",
+//%                       [self class], value];
+//%  }
+//%
+
+@end
+
+#pragma mark - NSArray Subclass
+
+@implementation GPBAutocreatedArray {
+  NSMutableArray *_array;
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_array release];
+  [super dealloc];
+}
+
+#pragma mark Required NSArray overrides
+
+- (NSUInteger)count {
+  return [_array count];
+}
+
+- (id)objectAtIndex:(NSUInteger)idx {
+  return [_array objectAtIndex:idx];
+}
+
+#pragma mark Required NSMutableArray overrides
+
+// Only need to call GPBAutocreatedArrayModified() when adding things since
+// we only autocreate empty arrays.
+
+- (void)insertObject:(id)anObject atIndex:(NSUInteger)idx {
+  if (_array == nil) {
+    _array = [[NSMutableArray alloc] init];
+  }
+  [_array insertObject:anObject atIndex:idx];
+
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)removeObject:(id)anObject {
+  [_array removeObject:anObject];
+}
+
+- (void)removeObjectAtIndex:(NSUInteger)idx {
+  [_array removeObjectAtIndex:idx];
+}
+
+- (void)addObject:(id)anObject {
+  if (_array == nil) {
+    _array = [[NSMutableArray alloc] init];
+  }
+  [_array addObject:anObject];
+
+  if (_autocreator) {
+    GPBAutocreatedArrayModified(_autocreator, self);
+  }
+}
+
+- (void)removeLastObject {
+  [_array removeLastObject];
+}
+
+- (void)replaceObjectAtIndex:(NSUInteger)idx withObject:(id)anObject {
+  [_array replaceObjectAtIndex:idx withObject:anObject];
+}
+
+#pragma mark Extra things hooked
+
+- (id)copyWithZone:(NSZone *)zone {
+  if (_array == nil) {
+    _array = [[NSMutableArray alloc] init];
+  }
+  return [_array copyWithZone:zone];
+}
+
+- (id)mutableCopyWithZone:(NSZone *)zone {
+  if (_array == nil) {
+    _array = [[NSMutableArray alloc] init];
+  }
+  return [_array mutableCopyWithZone:zone];
+}
+
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
+                                  objects:(id __unsafe_unretained [])buffer
+                                    count:(NSUInteger)len {
+  return [_array countByEnumeratingWithState:state objects:buffer count:len];
+}
+
+- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
+  [_array enumerateObjectsUsingBlock:block];
+}
+
+- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts
+                         usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
+  [_array enumerateObjectsWithOptions:opts usingBlock:block];
+}
+
+@end
diff --git a/objectivec/GPBArray_PackagePrivate.h b/objectivec/GPBArray_PackagePrivate.h
new file mode 100644
index 0000000..35a4538
--- /dev/null
+++ b/objectivec/GPBArray_PackagePrivate.h
@@ -0,0 +1,130 @@
+// 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.
+
+#import "GPBArray.h"
+
+@class GPBMessage;
+
+//%PDDM-DEFINE DECLARE_ARRAY_EXTRAS()
+//%ARRAY_INTERFACE_EXTRAS(Int32, int32_t)
+//%ARRAY_INTERFACE_EXTRAS(UInt32, uint32_t)
+//%ARRAY_INTERFACE_EXTRAS(Int64, int64_t)
+//%ARRAY_INTERFACE_EXTRAS(UInt64, uint64_t)
+//%ARRAY_INTERFACE_EXTRAS(Float, float)
+//%ARRAY_INTERFACE_EXTRAS(Double, double)
+//%ARRAY_INTERFACE_EXTRAS(Bool, BOOL)
+//%ARRAY_INTERFACE_EXTRAS(Enum, int32_t)
+
+//%PDDM-DEFINE ARRAY_INTERFACE_EXTRAS(NAME, TYPE)
+//%#pragma mark - NAME
+//%
+//%@interface GPB##NAME##Array () {
+//% @package
+//%  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+//%}
+//%@end
+//%
+
+//%PDDM-EXPAND DECLARE_ARRAY_EXTRAS()
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int32
+
+@interface GPBInt32Array () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - UInt32
+
+@interface GPBUInt32Array () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Int64
+
+@interface GPBInt64Array () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - UInt64
+
+@interface GPBUInt64Array () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Float
+
+@interface GPBFloatArray () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Double
+
+@interface GPBDoubleArray () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Bool
+
+@interface GPBBoolArray () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Enum
+
+@interface GPBEnumArray () {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+//%PDDM-EXPAND-END DECLARE_ARRAY_EXTRAS()
+
+#pragma mark - NSArray Subclass
+
+@interface GPBAutocreatedArray : NSMutableArray {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
new file mode 100644
index 0000000..ffefa77
--- /dev/null
+++ b/objectivec/GPBBootstrap.h
@@ -0,0 +1,85 @@
+// 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.
+
+// The Objective C runtime has complete enough info that most protos don’t end
+// up using this, so leaving it on is no cost or very little cost.  If you
+// happen to see it causing bloat, this is the way to disable it. If you do
+// need to disable it, try only disabling it for Release builds as having
+// full TextFormat can be useful for debugging.
+#ifndef GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+#define GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS 0
+#endif
+
+// Used in the generated code to give sizes to enums. int32_t was chosen based
+// on the fact that Protocol Buffers enums are limited to this range.
+#if !__has_feature(objc_fixed_enum)
+ #error All supported Xcode versions should support objc_fixed_enum.
+#endif
+// If the headers are imported into Objective-C++, we can run into an issue
+// where the defintion of NS_ENUM (really CF_ENUM) changes based on the C++
+// standard that is in effect.  If it isn't C++11 or higher, the definition
+// doesn't allow us to forward declare. We work around this one case by
+// providing a local definition. The default case has to use NS_ENUM for the
+// magic that is Swift bridging of enums.
+#if (__cplusplus && __cplusplus < 201103L)
+ #define GPB_ENUM(X) enum X : int32_t X; enum X : int32_t
+#else
+ #define GPB_ENUM(X) NS_ENUM(int32_t, X)
+#endif
+// GPB_ENUM_FWD_DECLARE is used for forward declaring enums, ex:
+//   GPB_ENUM_FWD_DECLARE(Foo_Enum)
+//   @property (nonatomic) Foo_Enum value;
+#define GPB_ENUM_FWD_DECLARE(X) enum X : int32_t
+
+// Based upon CF_INLINE. Forces inlining in release.
+#if !defined(DEBUG)
+#define GPB_INLINE static __inline__ __attribute__((always_inline))
+#else
+#define GPB_INLINE static __inline__
+#endif
+
+// For use in public headers that might need to deal with ARC.
+#ifndef GPB_UNSAFE_UNRETAINED
+#if __has_feature(objc_arc)
+#define GPB_UNSAFE_UNRETAINED __unsafe_unretained
+#else
+#define GPB_UNSAFE_UNRETAINED
+#endif
+#endif
+
+// If property name starts with init we need to annotate it to get past ARC.
+// http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+#define GPB_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
+
+// The protoc-gen-objc version which works with the current version of the
+// generated Objective C sources.  In general we don't want to change the
+// runtime interfaces (or this version) as it means everything has to be
+// regenerated.
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h
new file mode 100644
index 0000000..d64b64e
--- /dev/null
+++ b/objectivec/GPBCodedInputStream.h
@@ -0,0 +1,130 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+@class GPBMessage;
+@class GPBExtensionRegistry;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Reads and decodes protocol message fields.
+///
+/// The common uses of protocol buffers shouldn't need to use this class.
+/// @c GPBMessage's provide a @c +parseFromData:error: and @c
+/// +parseFromData:extensionRegistry:error: method that will decode a
+/// message for you.
+///
+/// @note Subclassing of GPBCodedInputStream is NOT supported.
+@interface GPBCodedInputStream : NSObject
+
+/// Creates a new stream wrapping some data.
++ (instancetype)streamWithData:(NSData *)data;
+
+/// Initializes a stream wrapping some data.
+- (instancetype)initWithData:(NSData *)data;
+
+/// Attempt to read a field tag, returning zero if we have reached EOF.
+/// Protocol message parsers use this to read tags, since a protocol message
+/// may legally end wherever a tag occurs, and zero is not a valid tag number.
+- (int32_t)readTag;
+
+/// Read and return a double.
+- (double)readDouble;
+/// Read and return a float.
+- (float)readFloat;
+/// Read and return a uint64.
+- (uint64_t)readUInt64;
+/// Read and return a uint32.
+- (uint32_t)readUInt32;
+/// Read and return an int64.
+- (int64_t)readInt64;
+/// Read and return an int32.
+- (int32_t)readInt32;
+/// Read and return a fixed64.
+- (uint64_t)readFixed64;
+/// Read and return a fixed32.
+- (uint32_t)readFixed32;
+/// Read and return an enum (int).
+- (int32_t)readEnum;
+/// Read and return a sfixed32.
+- (int32_t)readSFixed32;
+/// Read and return a sfixed64.
+- (int64_t)readSFixed64;
+/// Read and return a sint32.
+- (int32_t)readSInt32;
+/// Read and return a sint64.
+- (int64_t)readSInt64;
+/// Read and return a boolean.
+- (BOOL)readBool;
+/// Read and return a string.
+- (NSString *)readString;
+/// Read and return length delimited data.
+- (NSData *)readBytes;
+
+/// Read an embedded message field value from the stream.
+///
+/// @param message           The message to set fields on as they are read.
+/// @param extensionRegistry An optional extension registry to use to lookup
+///                          extensions for @message.
+- (void)readMessage:(GPBMessage *)message
+  extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry;
+
+/// Reads and discards a single field, given its tag value.
+///
+/// @param tag The tag number of the field to skip.
+///
+/// @return NO if the tag is an endgroup tag (in which case nothing is skipped),
+///         YES in all other cases.
+- (BOOL)skipField:(int32_t)tag;
+
+/// Reads and discards an entire message.  This will read either until EOF
+/// or until an endgroup tag, whichever comes first.
+- (void)skipMessage;
+
+/// Check to see if the logical end of the stream has been reached.
+///
+/// This can return NO when there is no more data, but the current parsing
+/// expected more data.
+- (BOOL)isAtEnd;
+
+/// The offset into the stream.
+- (size_t)position;
+
+/// Verifies that the last call to @c -readTag returned the given tag value.
+/// This is used to verify that a nested group ended with the correct end tag.
+/// Throws @c NSParseErrorException if value does not match the last tag.
+///
+/// @param expected The tag that was expected.
+- (void)checkLastTagWas:(int32_t)expected;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
new file mode 100644
index 0000000..319ec15
--- /dev/null
+++ b/objectivec/GPBCodedInputStream.m
@@ -0,0 +1,499 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBCodedInputStream_PackagePrivate.h"
+
+#import "GPBDictionary_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+#import "GPBWireFormat.h"
+
+static const NSUInteger kDefaultRecursionLimit = 64;
+
+static void CheckSize(GPBCodedInputStreamState *state, size_t size) {
+  size_t newSize = state->bufferPos + size;
+  if (newSize > state->bufferSize) {
+    [NSException raise:NSParseErrorException format:@""];
+  }
+  if (newSize > state->currentLimit) {
+    // Fast forward to end of currentLimit;
+    state->bufferPos = state->currentLimit;
+    [NSException raise:NSParseErrorException format:@""];
+  }
+}
+
+static int8_t ReadRawByte(GPBCodedInputStreamState *state) {
+  CheckSize(state, sizeof(int8_t));
+  return ((int8_t *)state->bytes)[state->bufferPos++];
+}
+
+static int32_t ReadRawLittleEndian32(GPBCodedInputStreamState *state) {
+  CheckSize(state, sizeof(int32_t));
+  int32_t value = OSReadLittleInt32(state->bytes, state->bufferPos);
+  state->bufferPos += sizeof(int32_t);
+  return value;
+}
+
+static int64_t ReadRawLittleEndian64(GPBCodedInputStreamState *state) {
+  CheckSize(state, sizeof(int64_t));
+  int64_t value = OSReadLittleInt64(state->bytes, state->bufferPos);
+  state->bufferPos += sizeof(int64_t);
+  return value;
+}
+
+static int32_t ReadRawVarint32(GPBCodedInputStreamState *state) {
+  int8_t tmp = ReadRawByte(state);
+  if (tmp >= 0) {
+    return tmp;
+  }
+  int32_t result = tmp & 0x7f;
+  if ((tmp = ReadRawByte(state)) >= 0) {
+    result |= tmp << 7;
+  } else {
+    result |= (tmp & 0x7f) << 7;
+    if ((tmp = ReadRawByte(state)) >= 0) {
+      result |= tmp << 14;
+    } else {
+      result |= (tmp & 0x7f) << 14;
+      if ((tmp = ReadRawByte(state)) >= 0) {
+        result |= tmp << 21;
+      } else {
+        result |= (tmp & 0x7f) << 21;
+        result |= (tmp = ReadRawByte(state)) << 28;
+        if (tmp < 0) {
+          // Discard upper 32 bits.
+          for (int i = 0; i < 5; i++) {
+            if (ReadRawByte(state) >= 0) {
+              return result;
+            }
+          }
+          [NSException raise:NSParseErrorException
+                      format:@"Unable to read varint32"];
+        }
+      }
+    }
+  }
+  return result;
+}
+
+static int64_t ReadRawVarint64(GPBCodedInputStreamState *state) {
+  int32_t shift = 0;
+  int64_t result = 0;
+  while (shift < 64) {
+    int8_t b = ReadRawByte(state);
+    result |= (int64_t)(b & 0x7F) << shift;
+    if ((b & 0x80) == 0) {
+      return result;
+    }
+    shift += 7;
+  }
+  [NSException raise:NSParseErrorException format:@"Unable to read varint64"];
+  return 0;
+}
+
+static void SkipRawData(GPBCodedInputStreamState *state, size_t size) {
+  CheckSize(state, size);
+  state->bufferPos += size;
+}
+
+double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state) {
+  int64_t value = ReadRawLittleEndian64(state);
+  return GPBConvertInt64ToDouble(value);
+}
+
+float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state) {
+  int32_t value = ReadRawLittleEndian32(state);
+  return GPBConvertInt32ToFloat(value);
+}
+
+uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state) {
+  uint64_t value = ReadRawVarint64(state);
+  return value;
+}
+
+uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state) {
+  uint32_t value = ReadRawVarint32(state);
+  return value;
+}
+
+int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state) {
+  int64_t value = ReadRawVarint64(state);
+  return value;
+}
+
+int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state) {
+  int32_t value = ReadRawVarint32(state);
+  return value;
+}
+
+uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state) {
+  uint64_t value = ReadRawLittleEndian64(state);
+  return value;
+}
+
+uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state) {
+  uint32_t value = ReadRawLittleEndian32(state);
+  return value;
+}
+
+int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state) {
+  int32_t value = ReadRawVarint32(state);
+  return value;
+}
+
+int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state) {
+  int32_t value = ReadRawLittleEndian32(state);
+  return value;
+}
+
+int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state) {
+  int64_t value = ReadRawLittleEndian64(state);
+  return value;
+}
+
+int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state) {
+  int32_t value = GPBDecodeZigZag32(ReadRawVarint32(state));
+  return value;
+}
+
+int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state) {
+  int64_t value = GPBDecodeZigZag64(ReadRawVarint64(state));
+  return value;
+}
+
+BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state) {
+  return ReadRawVarint32(state) != 0;
+}
+
+int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
+  if (GPBCodedInputStreamIsAtEnd(state)) {
+    state->lastTag = 0;
+    return 0;
+  }
+
+  state->lastTag = ReadRawVarint32(state);
+  if (state->lastTag == 0) {
+    // If we actually read zero, that's not a valid tag.
+    [NSException raise:NSParseErrorException
+                format:@"Invalid last tag %d", state->lastTag];
+  }
+  return state->lastTag;
+}
+
+NSString *GPBCodedInputStreamReadRetainedString(
+    GPBCodedInputStreamState *state) {
+  int32_t size = ReadRawVarint32(state);
+  NSString *result;
+  if (size == 0) {
+    result = @"";
+  } else {
+    CheckSize(state, size);
+    result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
+                                      length:size
+                                    encoding:NSUTF8StringEncoding];
+    state->bufferPos += size;
+    if (!result) {
+#ifdef DEBUG
+      // https://developers.google.com/protocol-buffers/docs/proto#scalar
+      NSLog(@"UTF-8 failure, is some field type 'string' when it should be "
+            @"'bytes'?");
+#endif
+      [NSException raise:NSParseErrorException
+                  format:@"Invalid UTF-8 for a 'string'"];
+    }
+  }
+  return result;
+}
+
+NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
+  int32_t size = ReadRawVarint32(state);
+  if (size < 0) return nil;
+  CheckSize(state, size);
+  NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos
+                                          length:size];
+  state->bufferPos += size;
+  return result;
+}
+
+NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(
+    GPBCodedInputStreamState *state) {
+  int32_t size = ReadRawVarint32(state);
+  if (size < 0) return nil;
+  CheckSize(state, size);
+  // Cast is safe because freeWhenDone is NO.
+  NSData *result = [[NSData alloc]
+      initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
+                   length:size
+             freeWhenDone:NO];
+  state->bufferPos += size;
+  return result;
+}
+
+size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state,
+                                    size_t byteLimit) {
+  byteLimit += state->bufferPos;
+  size_t oldLimit = state->currentLimit;
+  if (byteLimit > oldLimit) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"byteLimit > oldLimit: %tu > %tu", byteLimit, oldLimit];
+  }
+  state->currentLimit = byteLimit;
+  return oldLimit;
+}
+
+void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state,
+                                 size_t oldLimit) {
+  state->currentLimit = oldLimit;
+}
+
+size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) {
+  return state->currentLimit - state->bufferPos;
+}
+
+BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) {
+  return (state->bufferPos == state->bufferSize) ||
+         (state->bufferPos == state->currentLimit);
+}
+
+void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state,
+                                        int32_t value) {
+  if (state->lastTag != value) {
+    [NSException raise:NSParseErrorException
+                format:@"Last tag: %d should be %d", state->lastTag, value];
+  }
+}
+
+@implementation GPBCodedInputStream
+
++ (instancetype)streamWithData:(NSData *)data {
+  return [[[self alloc] initWithData:data] autorelease];
+}
+
+- (instancetype)initWithData:(NSData *)data {
+  if ((self = [super init])) {
+#ifdef DEBUG
+    NSCAssert([self class] == [GPBCodedInputStream class],
+              @"Subclassing of GPBCodedInputStream is not allowed.");
+#endif
+    buffer_ = [data retain];
+    state_.bytes = (const uint8_t *)[data bytes];
+    state_.bufferSize = [data length];
+    state_.currentLimit = state_.bufferSize;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [buffer_ release];
+  [super dealloc];
+}
+
+- (int32_t)readTag {
+  return GPBCodedInputStreamReadTag(&state_);
+}
+
+- (void)checkLastTagWas:(int32_t)value {
+  GPBCodedInputStreamCheckLastTagWas(&state_, value);
+}
+
+- (BOOL)skipField:(int32_t)tag {
+  switch (GPBWireFormatGetTagWireType(tag)) {
+    case GPBWireFormatVarint:
+      GPBCodedInputStreamReadInt32(&state_);
+      return YES;
+    case GPBWireFormatFixed64:
+      SkipRawData(&state_, sizeof(int64_t));
+      return YES;
+    case GPBWireFormatLengthDelimited:
+      SkipRawData(&state_, ReadRawVarint32(&state_));
+      return YES;
+    case GPBWireFormatStartGroup:
+      [self skipMessage];
+      GPBCodedInputStreamCheckLastTagWas(
+          &state_, GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag),
+                                        GPBWireFormatEndGroup));
+      return YES;
+    case GPBWireFormatEndGroup:
+      return NO;
+    case GPBWireFormatFixed32:
+      SkipRawData(&state_, sizeof(int32_t));
+      return YES;
+  }
+  [NSException raise:NSParseErrorException format:@"Invalid tag %d", tag];
+  return NO;
+}
+
+- (void)skipMessage {
+  while (YES) {
+    int32_t tag = GPBCodedInputStreamReadTag(&state_);
+    if (tag == 0 || ![self skipField:tag]) {
+      return;
+    }
+  }
+}
+
+- (BOOL)isAtEnd {
+  return GPBCodedInputStreamIsAtEnd(&state_);
+}
+
+- (size_t)position {
+  return state_.bufferPos;
+}
+
+- (double)readDouble {
+  return GPBCodedInputStreamReadDouble(&state_);
+}
+
+- (float)readFloat {
+  return GPBCodedInputStreamReadFloat(&state_);
+}
+
+- (uint64_t)readUInt64 {
+  return GPBCodedInputStreamReadUInt64(&state_);
+}
+
+- (int64_t)readInt64 {
+  return GPBCodedInputStreamReadInt64(&state_);
+}
+
+- (int32_t)readInt32 {
+  return GPBCodedInputStreamReadInt32(&state_);
+}
+
+- (uint64_t)readFixed64 {
+  return GPBCodedInputStreamReadFixed64(&state_);
+}
+
+- (uint32_t)readFixed32 {
+  return GPBCodedInputStreamReadFixed32(&state_);
+}
+
+- (BOOL)readBool {
+  return GPBCodedInputStreamReadBool(&state_);
+}
+
+- (NSString *)readString {
+  return [GPBCodedInputStreamReadRetainedString(&state_) autorelease];
+}
+
+- (void)readGroup:(int32_t)fieldNumber
+              message:(GPBMessage *)message
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  if (state_.recursionDepth >= kDefaultRecursionLimit) {
+    [NSException raise:NSParseErrorException
+                format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth,
+                       kDefaultRecursionLimit];
+  }
+  ++state_.recursionDepth;
+  [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
+  GPBCodedInputStreamCheckLastTagWas(
+      &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup));
+  --state_.recursionDepth;
+}
+
+- (void)readUnknownGroup:(int32_t)fieldNumber
+                 message:(GPBUnknownFieldSet *)message {
+  if (state_.recursionDepth >= kDefaultRecursionLimit) {
+    [NSException raise:NSParseErrorException
+                format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth,
+                       kDefaultRecursionLimit];
+  }
+  ++state_.recursionDepth;
+  [message mergeFromCodedInputStream:self];
+  GPBCodedInputStreamCheckLastTagWas(
+      &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup));
+  --state_.recursionDepth;
+}
+
+- (void)readMessage:(GPBMessage *)message
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  int32_t length = ReadRawVarint32(&state_);
+  if (state_.recursionDepth >= kDefaultRecursionLimit) {
+    [NSException raise:NSParseErrorException
+                format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth,
+                       kDefaultRecursionLimit];
+  }
+  size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
+  ++state_.recursionDepth;
+  [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
+  GPBCodedInputStreamCheckLastTagWas(&state_, 0);
+  --state_.recursionDepth;
+  GPBCodedInputStreamPopLimit(&state_, oldLimit);
+}
+
+- (void)readMapEntry:(id)mapDictionary
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                field:(GPBFieldDescriptor *)field
+        parentMessage:(GPBMessage *)parentMessage {
+  int32_t length = ReadRawVarint32(&state_);
+  if (state_.recursionDepth >= kDefaultRecursionLimit) {
+    [NSException raise:NSParseErrorException
+                format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth,
+                       kDefaultRecursionLimit];
+  }
+  size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
+  ++state_.recursionDepth;
+  GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field,
+                         parentMessage);
+  GPBCodedInputStreamCheckLastTagWas(&state_, 0);
+  --state_.recursionDepth;
+  GPBCodedInputStreamPopLimit(&state_, oldLimit);
+}
+
+- (NSData *)readBytes {
+  return [GPBCodedInputStreamReadRetainedBytes(&state_) autorelease];
+}
+
+- (uint32_t)readUInt32 {
+  return GPBCodedInputStreamReadUInt32(&state_);
+}
+
+- (int32_t)readEnum {
+  return GPBCodedInputStreamReadEnum(&state_);
+}
+
+- (int32_t)readSFixed32 {
+  return GPBCodedInputStreamReadSFixed32(&state_);
+}
+
+- (int64_t)readSFixed64 {
+  return GPBCodedInputStreamReadSFixed64(&state_);
+}
+
+- (int32_t)readSInt32 {
+  return GPBCodedInputStreamReadSInt32(&state_);
+}
+
+- (int64_t)readSInt64 {
+  return GPBCodedInputStreamReadSInt64(&state_);
+}
+
+@end
diff --git a/objectivec/GPBCodedInputStream_PackagePrivate.h b/objectivec/GPBCodedInputStream_PackagePrivate.h
new file mode 100644
index 0000000..90bd0c9
--- /dev/null
+++ b/objectivec/GPBCodedInputStream_PackagePrivate.h
@@ -0,0 +1,114 @@
+// 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.
+
+// This header is private to the ProtobolBuffers library and must NOT be
+// included by any sources outside this library. The contents of this file are
+// subject to change at any time without notice.
+
+#import "GPBCodedInputStream.h"
+
+#import <libkern/OSAtomic.h>
+
+@class GPBUnknownFieldSet;
+@class GPBFieldDescriptor;
+
+typedef struct GPBCodedInputStreamState {
+  const uint8_t *bytes;
+  size_t bufferSize;
+  size_t bufferPos;
+
+  // For parsing subsections of an input stream you can put a hard limit on
+  // how much should be read. Normally the limit is the end of the stream,
+  // but you can adjust it to anywhere, and if you hit it you will be at the
+  // end of the stream, until you adjust the limit.
+  size_t currentLimit;
+  int32_t lastTag;
+  NSUInteger recursionDepth;
+} GPBCodedInputStreamState;
+
+@interface GPBCodedInputStream () {
+ @package
+  struct GPBCodedInputStreamState state_;
+  NSData *buffer_;
+}
+
+// Group support is deprecated, so we hide this interface from users, but
+// support for older data.
+- (void)readGroup:(int32_t)fieldNumber
+              message:(GPBMessage *)message
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
+
+// Reads a group field value from the stream and merges it into the given
+// UnknownFieldSet.
+- (void)readUnknownGroup:(int32_t)fieldNumber
+                 message:(GPBUnknownFieldSet *)message;
+
+// Reads a map entry.
+- (void)readMapEntry:(id)mapDictionary
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                field:(GPBFieldDescriptor *)field
+        parentMessage:(GPBMessage *)parentMessage;
+@end
+
+CF_EXTERN_C_BEGIN
+
+int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state);
+
+double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state);
+float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state);
+uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state);
+uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state);
+int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state);
+int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state);
+uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state);
+uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state);
+int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state);
+int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state);
+int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state);
+int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state);
+int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state);
+BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state);
+NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state)
+    __attribute((ns_returns_retained));
+NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state)
+    __attribute((ns_returns_retained));
+NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(
+    GPBCodedInputStreamState *state) __attribute((ns_returns_retained));
+
+size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state,
+                                    size_t byteLimit);
+void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state,
+                                 size_t oldLimit);
+size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state);
+BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state);
+void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state,
+                                        int32_t value);
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h
new file mode 100644
index 0000000..8272880
--- /dev/null
+++ b/objectivec/GPBCodedOutputStream.h
@@ -0,0 +1,344 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRuntimeTypes.h"
+#import "GPBWireFormat.h"
+
+@class GPBBoolArray;
+@class GPBDoubleArray;
+@class GPBEnumArray;
+@class GPBFloatArray;
+@class GPBMessage;
+@class GPBInt32Array;
+@class GPBInt64Array;
+@class GPBUInt32Array;
+@class GPBUInt64Array;
+@class GPBUnknownFieldSet;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Writes out protocol message fields.
+///
+/// The common uses of protocol buffers shouldn't need to use this class.
+/// @c GPBMessage's provide a @c -data method that will serialize the message
+/// for you.
+///
+/// @note Subclassing of GPBCodedOutputStream is NOT supported.
+@interface GPBCodedOutputStream : NSObject
+
+/// Creates a stream to fill in the given data. Data must be sized to fit or
+/// an error will be raised when out of space.
++ (instancetype)streamWithData:(NSMutableData *)data;
+
+/// Creates a stream to write into the given @c NSOutputStream.
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output;
+
+/// Initializes a stream to fill in the given data. Data must be sized to fit
+/// or an error will be raised when out of space.
+- (instancetype)initWithData:(NSMutableData *)data;
+
+/// Initializes a stream to write into the given @c NSOutputStream.
+- (instancetype)initWithOutputStream:(NSOutputStream *)output;
+
+/// Flush any buffered data out.
+- (void)flush;
+
+/// Write the raw byte out.
+- (void)writeRawByte:(uint8_t)value;
+
+/// Write the tag for the given field number and wire format.
+///
+/// @param fieldNumber The field number.
+/// @param format      The wire format the data for the field will be in.
+- (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format;
+
+/// Write a 32bit value out in little endian format.
+- (void)writeRawLittleEndian32:(int32_t)value;
+/// Write a 64bit value out in little endian format.
+- (void)writeRawLittleEndian64:(int64_t)value;
+
+/// Write a 32bit value out in varint format.
+- (void)writeRawVarint32:(int32_t)value;
+/// Write a 64bit value out in varint format.
+- (void)writeRawVarint64:(int64_t)value;
+
+/// Write a size_t out as a 32bit varint value.
+///
+/// @note This will truncate 64 bit values to 32.
+- (void)writeRawVarintSizeTAs32:(size_t)value;
+
+/// Writes the contents of an @c NSData out.
+- (void)writeRawData:(NSData *)data;
+/// Writes out the given data.
+///
+/// @param data   The data blob to write out.
+/// @param offset The offset into the blob to start writing out.
+/// @param length The number of bytes from the blob to write out.
+- (void)writeRawPtr:(const void *)data
+             offset:(size_t)offset
+             length:(size_t)length;
+
+//%PDDM-EXPAND _WRITE_DECLS()
+// This block of code is generated, do not edit it directly.
+
+/// Write a double for the given field number.
+- (void)writeDouble:(int32_t)fieldNumber value:(double)value;
+/// Write a packed array of double for the given field number.
+- (void)writeDoubleArray:(int32_t)fieldNumber
+                  values:(GPBDoubleArray *)values
+                     tag:(uint32_t)tag;
+/// Write a double without any tag.
+- (void)writeDoubleNoTag:(double)value;
+
+/// Write a float for the given field number.
+- (void)writeFloat:(int32_t)fieldNumber value:(float)value;
+/// Write a packed array of float for the given field number.
+- (void)writeFloatArray:(int32_t)fieldNumber
+                 values:(GPBFloatArray *)values
+                    tag:(uint32_t)tag;
+/// Write a float without any tag.
+- (void)writeFloatNoTag:(float)value;
+
+/// Write a uint64_t for the given field number.
+- (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value;
+/// Write a packed array of uint64_t for the given field number.
+- (void)writeUInt64Array:(int32_t)fieldNumber
+                  values:(GPBUInt64Array *)values
+                     tag:(uint32_t)tag;
+/// Write a uint64_t without any tag.
+- (void)writeUInt64NoTag:(uint64_t)value;
+
+/// Write a int64_t for the given field number.
+- (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value;
+/// Write a packed array of int64_t for the given field number.
+- (void)writeInt64Array:(int32_t)fieldNumber
+                 values:(GPBInt64Array *)values
+                    tag:(uint32_t)tag;
+/// Write a int64_t without any tag.
+- (void)writeInt64NoTag:(int64_t)value;
+
+/// Write a int32_t for the given field number.
+- (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value;
+/// Write a packed array of int32_t for the given field number.
+- (void)writeInt32Array:(int32_t)fieldNumber
+                 values:(GPBInt32Array *)values
+                    tag:(uint32_t)tag;
+/// Write a int32_t without any tag.
+- (void)writeInt32NoTag:(int32_t)value;
+
+/// Write a uint32_t for the given field number.
+- (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value;
+/// Write a packed array of uint32_t for the given field number.
+- (void)writeUInt32Array:(int32_t)fieldNumber
+                  values:(GPBUInt32Array *)values
+                     tag:(uint32_t)tag;
+/// Write a uint32_t without any tag.
+- (void)writeUInt32NoTag:(uint32_t)value;
+
+/// Write a uint64_t for the given field number.
+- (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value;
+/// Write a packed array of uint64_t for the given field number.
+- (void)writeFixed64Array:(int32_t)fieldNumber
+                   values:(GPBUInt64Array *)values
+                      tag:(uint32_t)tag;
+/// Write a uint64_t without any tag.
+- (void)writeFixed64NoTag:(uint64_t)value;
+
+/// Write a uint32_t for the given field number.
+- (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value;
+/// Write a packed array of uint32_t for the given field number.
+- (void)writeFixed32Array:(int32_t)fieldNumber
+                   values:(GPBUInt32Array *)values
+                      tag:(uint32_t)tag;
+/// Write a uint32_t without any tag.
+- (void)writeFixed32NoTag:(uint32_t)value;
+
+/// Write a int32_t for the given field number.
+- (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value;
+/// Write a packed array of int32_t for the given field number.
+- (void)writeSInt32Array:(int32_t)fieldNumber
+                  values:(GPBInt32Array *)values
+                     tag:(uint32_t)tag;
+/// Write a int32_t without any tag.
+- (void)writeSInt32NoTag:(int32_t)value;
+
+/// Write a int64_t for the given field number.
+- (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value;
+/// Write a packed array of int64_t for the given field number.
+- (void)writeSInt64Array:(int32_t)fieldNumber
+                  values:(GPBInt64Array *)values
+                     tag:(uint32_t)tag;
+/// Write a int64_t without any tag.
+- (void)writeSInt64NoTag:(int64_t)value;
+
+/// Write a int64_t for the given field number.
+- (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value;
+/// Write a packed array of int64_t for the given field number.
+- (void)writeSFixed64Array:(int32_t)fieldNumber
+                    values:(GPBInt64Array *)values
+                       tag:(uint32_t)tag;
+/// Write a int64_t without any tag.
+- (void)writeSFixed64NoTag:(int64_t)value;
+
+/// Write a int32_t for the given field number.
+- (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value;
+/// Write a packed array of int32_t for the given field number.
+- (void)writeSFixed32Array:(int32_t)fieldNumber
+                    values:(GPBInt32Array *)values
+                       tag:(uint32_t)tag;
+/// Write a int32_t without any tag.
+- (void)writeSFixed32NoTag:(int32_t)value;
+
+/// Write a BOOL for the given field number.
+- (void)writeBool:(int32_t)fieldNumber value:(BOOL)value;
+/// Write a packed array of BOOL for the given field number.
+- (void)writeBoolArray:(int32_t)fieldNumber
+                values:(GPBBoolArray *)values
+                   tag:(uint32_t)tag;
+/// Write a BOOL without any tag.
+- (void)writeBoolNoTag:(BOOL)value;
+
+/// Write a int32_t for the given field number.
+- (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value;
+/// Write a packed array of int32_t for the given field number.
+- (void)writeEnumArray:(int32_t)fieldNumber
+                values:(GPBEnumArray *)values
+                   tag:(uint32_t)tag;
+/// Write a int32_t without any tag.
+- (void)writeEnumNoTag:(int32_t)value;
+
+/// Write a NSString for the given field number.
+- (void)writeString:(int32_t)fieldNumber value:(NSString *)value;
+/// Write an array of NSString for the given field number.
+- (void)writeStringArray:(int32_t)fieldNumber values:(NSArray<NSString*> *)values;
+/// Write a NSString without any tag.
+- (void)writeStringNoTag:(NSString *)value;
+
+/// Write a GPBMessage for the given field number.
+- (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value;
+/// Write an array of GPBMessage for the given field number.
+- (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
+/// Write a GPBMessage without any tag.
+- (void)writeMessageNoTag:(GPBMessage *)value;
+
+/// Write a NSData for the given field number.
+- (void)writeBytes:(int32_t)fieldNumber value:(NSData *)value;
+/// Write an array of NSData for the given field number.
+- (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray<NSData*> *)values;
+/// Write a NSData without any tag.
+- (void)writeBytesNoTag:(NSData *)value;
+
+/// Write a GPBMessage for the given field number.
+- (void)writeGroup:(int32_t)fieldNumber
+             value:(GPBMessage *)value;
+/// Write an array of GPBMessage for the given field number.
+- (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
+/// Write a GPBMessage without any tag (but does write the endGroup tag).
+- (void)writeGroupNoTag:(int32_t)fieldNumber
+                  value:(GPBMessage *)value;
+
+/// Write a GPBUnknownFieldSet for the given field number.
+- (void)writeUnknownGroup:(int32_t)fieldNumber
+                    value:(GPBUnknownFieldSet *)value;
+/// Write an array of GPBUnknownFieldSet for the given field number.
+- (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray<GPBUnknownFieldSet*> *)values;
+/// Write a GPBUnknownFieldSet without any tag (but does write the endGroup tag).
+- (void)writeUnknownGroupNoTag:(int32_t)fieldNumber
+                         value:(GPBUnknownFieldSet *)value;
+
+//%PDDM-EXPAND-END _WRITE_DECLS()
+
+/// Write a MessageSet extension field to the stream. For historical reasons,
+/// the wire format differs from normal fields.
+- (void)writeMessageSetExtension:(int32_t)fieldNumber value:(GPBMessage *)value;
+
+/// Write an unparsed MessageSet extension field to the stream. For
+/// historical reasons, the wire format differs from normal fields.
+- (void)writeRawMessageSetExtension:(int32_t)fieldNumber value:(NSData *)value;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+// Write methods for types that can be in packed arrays.
+//%PDDM-DEFINE _WRITE_PACKABLE_DECLS(NAME, ARRAY_TYPE, TYPE)
+//%/// Write a TYPE for the given field number.
+//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value;
+//%/// Write a packed array of TYPE for the given field number.
+//%- (void)write##NAME##Array:(int32_t)fieldNumber
+//%       NAME$S     values:(GPB##ARRAY_TYPE##Array *)values
+//%       NAME$S        tag:(uint32_t)tag;
+//%/// Write a TYPE without any tag.
+//%- (void)write##NAME##NoTag:(TYPE)value;
+//%
+// Write methods for types that aren't in packed arrays.
+//%PDDM-DEFINE _WRITE_UNPACKABLE_DECLS(NAME, TYPE)
+//%/// Write a TYPE for the given field number.
+//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE *)value;
+//%/// Write an array of TYPE for the given field number.
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
+//%/// Write a TYPE without any tag.
+//%- (void)write##NAME##NoTag:(TYPE *)value;
+//%
+// Special write methods for Groups.
+//%PDDM-DEFINE _WRITE_GROUP_DECLS(NAME, TYPE)
+//%/// Write a TYPE for the given field number.
+//%- (void)write##NAME:(int32_t)fieldNumber
+//%       NAME$S value:(TYPE *)value;
+//%/// Write an array of TYPE for the given field number.
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
+//%/// Write a TYPE without any tag (but does write the endGroup tag).
+//%- (void)write##NAME##NoTag:(int32_t)fieldNumber
+//%            NAME$S value:(TYPE *)value;
+//%
+
+// One macro to hide it all up above.
+//%PDDM-DEFINE _WRITE_DECLS()
+//%_WRITE_PACKABLE_DECLS(Double, Double, double)
+//%_WRITE_PACKABLE_DECLS(Float, Float, float)
+//%_WRITE_PACKABLE_DECLS(UInt64, UInt64, uint64_t)
+//%_WRITE_PACKABLE_DECLS(Int64, Int64, int64_t)
+//%_WRITE_PACKABLE_DECLS(Int32, Int32, int32_t)
+//%_WRITE_PACKABLE_DECLS(UInt32, UInt32, uint32_t)
+//%_WRITE_PACKABLE_DECLS(Fixed64, UInt64, uint64_t)
+//%_WRITE_PACKABLE_DECLS(Fixed32, UInt32, uint32_t)
+//%_WRITE_PACKABLE_DECLS(SInt32, Int32, int32_t)
+//%_WRITE_PACKABLE_DECLS(SInt64, Int64, int64_t)
+//%_WRITE_PACKABLE_DECLS(SFixed64, Int64, int64_t)
+//%_WRITE_PACKABLE_DECLS(SFixed32, Int32, int32_t)
+//%_WRITE_PACKABLE_DECLS(Bool, Bool, BOOL)
+//%_WRITE_PACKABLE_DECLS(Enum, Enum, int32_t)
+//%_WRITE_UNPACKABLE_DECLS(String, NSString)
+//%_WRITE_UNPACKABLE_DECLS(Message, GPBMessage)
+//%_WRITE_UNPACKABLE_DECLS(Bytes, NSData)
+//%_WRITE_GROUP_DECLS(Group, GPBMessage)
+//%_WRITE_GROUP_DECLS(UnknownGroup, GPBUnknownFieldSet)
diff --git a/objectivec/GPBCodedOutputStream.m b/objectivec/GPBCodedOutputStream.m
new file mode 100644
index 0000000..fd9ed66
--- /dev/null
+++ b/objectivec/GPBCodedOutputStream.m
@@ -0,0 +1,1221 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBCodedOutputStream_PackagePrivate.h"
+
+#import <mach/vm_param.h>
+
+#import "GPBArray.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+// Structure for containing state of a GPBCodedInputStream. Brought out into
+// a struct so that we can inline several common functions instead of dealing
+// with overhead of ObjC dispatch.
+typedef struct GPBOutputBufferState {
+  uint8_t *bytes;
+  size_t size;
+  size_t position;
+  NSOutputStream *output;
+} GPBOutputBufferState;
+
+@implementation GPBCodedOutputStream {
+  GPBOutputBufferState state_;
+  NSMutableData *buffer_;
+}
+
+static const int32_t LITTLE_ENDIAN_32_SIZE = sizeof(uint32_t);
+static const int32_t LITTLE_ENDIAN_64_SIZE = sizeof(uint64_t);
+
+// Internal helper that writes the current buffer to the output. The
+// buffer position is reset to its initial value when this returns.
+static void GPBRefreshBuffer(GPBOutputBufferState *state) {
+  if (state->output == nil) {
+    // We're writing to a single buffer.
+    [NSException raise:@"OutOfSpace" format:@""];
+  }
+  if (state->position != 0) {
+    NSInteger written =
+        [state->output write:state->bytes maxLength:state->position];
+    if (written != (NSInteger)state->position) {
+      [NSException raise:@"WriteFailed" format:@""];
+    }
+    state->position = 0;
+  }
+}
+
+static void GPBWriteRawByte(GPBOutputBufferState *state, uint8_t value) {
+  if (state->position == state->size) {
+    GPBRefreshBuffer(state);
+  }
+  state->bytes[state->position++] = value;
+}
+
+static void GPBWriteRawVarint32(GPBOutputBufferState *state, int32_t value) {
+  while (YES) {
+    if ((value & ~0x7F) == 0) {
+      uint8_t val = (uint8_t)value;
+      GPBWriteRawByte(state, val);
+      return;
+    } else {
+      GPBWriteRawByte(state, (value & 0x7F) | 0x80);
+      value = GPBLogicalRightShift32(value, 7);
+    }
+  }
+}
+
+static void GPBWriteRawVarint64(GPBOutputBufferState *state, int64_t value) {
+  while (YES) {
+    if ((value & ~0x7FL) == 0) {
+      uint8_t val = (uint8_t)value;
+      GPBWriteRawByte(state, val);
+      return;
+    } else {
+      GPBWriteRawByte(state, ((int32_t)value & 0x7F) | 0x80);
+      value = GPBLogicalRightShift64(value, 7);
+    }
+  }
+}
+
+static void GPBWriteInt32NoTag(GPBOutputBufferState *state, int32_t value) {
+  if (value >= 0) {
+    GPBWriteRawVarint32(state, value);
+  } else {
+    // Must sign-extend
+    GPBWriteRawVarint64(state, value);
+  }
+}
+
+static void GPBWriteUInt32(GPBOutputBufferState *state, int32_t fieldNumber,
+                           uint32_t value) {
+  GPBWriteTagWithFormat(state, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint32(state, value);
+}
+
+static void GPBWriteTagWithFormat(GPBOutputBufferState *state,
+                                  uint32_t fieldNumber, GPBWireFormat format) {
+  GPBWriteRawVarint32(state, GPBWireFormatMakeTag(fieldNumber, format));
+}
+
+static void GPBWriteRawLittleEndian32(GPBOutputBufferState *state,
+                                      int32_t value) {
+  GPBWriteRawByte(state, (value)&0xFF);
+  GPBWriteRawByte(state, (value >> 8) & 0xFF);
+  GPBWriteRawByte(state, (value >> 16) & 0xFF);
+  GPBWriteRawByte(state, (value >> 24) & 0xFF);
+}
+
+static void GPBWriteRawLittleEndian64(GPBOutputBufferState *state,
+                                      int64_t value) {
+  GPBWriteRawByte(state, (int32_t)(value)&0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 8) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 16) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 24) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 32) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 40) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 48) & 0xFF);
+  GPBWriteRawByte(state, (int32_t)(value >> 56) & 0xFF);
+}
+
+#if DEBUG && !defined(NS_BLOCK_ASSERTIONS)
++ (void)load {
+  // This test exists to verify that CFStrings with embedded NULLs will work
+  // for us. If this Assert fails, all code below that depends on
+  // CFStringGetCStringPtr will NOT work properly on strings that contain
+  // embedded NULLs, and we do get that in some protobufs.
+  // Note that this will not be compiled in release.
+  // We didn't feel that just keeping it in a unit test was sufficient because
+  // the Protobuf unit tests are only run when somebody is actually working
+  // on protobufs.
+  CFStringRef zeroTest = CFSTR("Test\0String");
+  const char *cString = CFStringGetCStringPtr(zeroTest, kCFStringEncodingUTF8);
+  NSAssert(cString == NULL, @"Serious Error");
+}
+#endif  // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+
+- (void)dealloc {
+  [self flush];
+  [state_.output close];
+  [state_.output release];
+  [buffer_ release];
+
+  [super dealloc];
+}
+
+- (instancetype)initWithOutputStream:(NSOutputStream *)output {
+  NSMutableData *data = [NSMutableData dataWithLength:PAGE_SIZE];
+  return [self initWithOutputStream:output data:data];
+}
+
+- (instancetype)initWithData:(NSMutableData *)data {
+  return [self initWithOutputStream:nil data:data];
+}
+
+// This initializer isn't exposed, but it is the designated initializer.
+// Setting OutputStream and NSData is to control the buffering behavior/size
+// of the work, but that is more obvious via the bufferSize: version.
+- (instancetype)initWithOutputStream:(NSOutputStream *)output
+                                data:(NSMutableData *)data {
+  if ((self = [super init])) {
+    buffer_ = [data retain];
+    [output open];
+    state_.bytes = [data mutableBytes];
+    state_.size = [data length];
+    state_.output = [output retain];
+  }
+  return self;
+}
+
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output {
+  NSMutableData *data = [NSMutableData dataWithLength:PAGE_SIZE];
+  return [[[self alloc] initWithOutputStream:output
+                                        data:data] autorelease];
+}
+
++ (instancetype)streamWithData:(NSMutableData *)data {
+  return [[[self alloc] initWithData:data] autorelease];
+}
+
+- (void)writeDoubleNoTag:(double)value {
+  GPBWriteRawLittleEndian64(&state_, GPBConvertDoubleToInt64(value));
+}
+
+- (void)writeDouble:(int32_t)fieldNumber value:(double)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64);
+  GPBWriteRawLittleEndian64(&state_, GPBConvertDoubleToInt64(value));
+}
+
+- (void)writeFloatNoTag:(float)value {
+  GPBWriteRawLittleEndian32(&state_, GPBConvertFloatToInt32(value));
+}
+
+- (void)writeFloat:(int32_t)fieldNumber value:(float)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32);
+  GPBWriteRawLittleEndian32(&state_, GPBConvertFloatToInt32(value));
+}
+
+- (void)writeUInt64NoTag:(uint64_t)value {
+  GPBWriteRawVarint64(&state_, value);
+}
+
+- (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint64(&state_, value);
+}
+
+- (void)writeInt64NoTag:(int64_t)value {
+  GPBWriteRawVarint64(&state_, value);
+}
+
+- (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint64(&state_, value);
+}
+
+- (void)writeInt32NoTag:(int32_t)value {
+  GPBWriteInt32NoTag(&state_, value);
+}
+
+- (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteInt32NoTag(&state_, value);
+}
+
+- (void)writeFixed64NoTag:(uint64_t)value {
+  GPBWriteRawLittleEndian64(&state_, value);
+}
+
+- (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64);
+  GPBWriteRawLittleEndian64(&state_, value);
+}
+
+- (void)writeFixed32NoTag:(uint32_t)value {
+  GPBWriteRawLittleEndian32(&state_, value);
+}
+
+- (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32);
+  GPBWriteRawLittleEndian32(&state_, value);
+}
+
+- (void)writeBoolNoTag:(BOOL)value {
+  GPBWriteRawByte(&state_, (value ? 1 : 0));
+}
+
+- (void)writeBool:(int32_t)fieldNumber value:(BOOL)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawByte(&state_, (value ? 1 : 0));
+}
+
+- (void)writeStringNoTag:(const NSString *)value {
+  // If you are concerned about embedded NULLs see the test in
+  // +load above.
+  const char *quickString =
+      CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8);
+  size_t length = (quickString != NULL)
+                      ? strlen(quickString)
+                      : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+  GPBWriteRawVarint32(&state_, (int32_t)length);
+
+  if (length == 0) {
+    return;
+  }
+
+  // Fast path: Most strings are short, if the buffer already has space,
+  // add to it directly.
+  NSUInteger bufferBytesLeft = state_.size - state_.position;
+  if (bufferBytesLeft >= length) {
+    NSUInteger usedBufferLength = 0;
+    BOOL result;
+    if (quickString != NULL) {
+      memcpy(state_.bytes + state_.position, quickString, length);
+      usedBufferLength = length;
+      result = YES;
+    } else {
+      result = [value getBytes:state_.bytes + state_.position
+                     maxLength:bufferBytesLeft
+                    usedLength:&usedBufferLength
+                      encoding:NSUTF8StringEncoding
+                       options:0
+                         range:NSMakeRange(0, [value length])
+                remainingRange:NULL];
+    }
+    if (result) {
+      NSAssert2((usedBufferLength == length),
+                @"Our UTF8 calc was wrong? %tu vs %zd", usedBufferLength,
+                length);
+      state_.position += usedBufferLength;
+      return;
+    }
+  } else if (quickString != NULL) {
+    [self writeRawPtr:quickString offset:0 length:length];
+  } else {
+    // Slow path: just get it as data and write it out.
+    NSData *utf8Data = [value dataUsingEncoding:NSUTF8StringEncoding];
+    NSAssert2(([utf8Data length] == length),
+              @"Strings UTF8 length was wrong? %tu vs %zd", [utf8Data length],
+              length);
+    [self writeRawData:utf8Data];
+  }
+}
+
+- (void)writeString:(int32_t)fieldNumber value:(NSString *)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited);
+  [self writeStringNoTag:value];
+}
+
+- (void)writeGroupNoTag:(int32_t)fieldNumber value:(GPBMessage *)value {
+  [value writeToCodedOutputStream:self];
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatEndGroup);
+}
+
+- (void)writeGroup:(int32_t)fieldNumber value:(GPBMessage *)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatStartGroup);
+  [self writeGroupNoTag:fieldNumber value:value];
+}
+
+- (void)writeUnknownGroupNoTag:(int32_t)fieldNumber
+                         value:(const GPBUnknownFieldSet *)value {
+  [value writeToCodedOutputStream:self];
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatEndGroup);
+}
+
+- (void)writeUnknownGroup:(int32_t)fieldNumber
+                    value:(GPBUnknownFieldSet *)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatStartGroup);
+  [self writeUnknownGroupNoTag:fieldNumber value:value];
+}
+
+- (void)writeMessageNoTag:(GPBMessage *)value {
+  GPBWriteRawVarint32(&state_, (int32_t)[value serializedSize]);
+  [value writeToCodedOutputStream:self];
+}
+
+- (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited);
+  [self writeMessageNoTag:value];
+}
+
+- (void)writeBytesNoTag:(NSData *)value {
+  GPBWriteRawVarint32(&state_, (int32_t)[value length]);
+  [self writeRawData:value];
+}
+
+- (void)writeBytes:(int32_t)fieldNumber value:(NSData *)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited);
+  [self writeBytesNoTag:value];
+}
+
+- (void)writeUInt32NoTag:(uint32_t)value {
+  GPBWriteRawVarint32(&state_, value);
+}
+
+- (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value {
+  GPBWriteUInt32(&state_, fieldNumber, value);
+}
+
+- (void)writeEnumNoTag:(int32_t)value {
+  GPBWriteRawVarint32(&state_, value);
+}
+
+- (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint32(&state_, value);
+}
+
+- (void)writeSFixed32NoTag:(int32_t)value {
+  GPBWriteRawLittleEndian32(&state_, value);
+}
+
+- (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32);
+  GPBWriteRawLittleEndian32(&state_, value);
+}
+
+- (void)writeSFixed64NoTag:(int64_t)value {
+  GPBWriteRawLittleEndian64(&state_, value);
+}
+
+- (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64);
+  GPBWriteRawLittleEndian64(&state_, value);
+}
+
+- (void)writeSInt32NoTag:(int32_t)value {
+  GPBWriteRawVarint32(&state_, GPBEncodeZigZag32(value));
+}
+
+- (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint32(&state_, GPBEncodeZigZag32(value));
+}
+
+- (void)writeSInt64NoTag:(int64_t)value {
+  GPBWriteRawVarint64(&state_, GPBEncodeZigZag64(value));
+}
+
+- (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value {
+  GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint);
+  GPBWriteRawVarint64(&state_, GPBEncodeZigZag64(value));
+}
+
+//%PDDM-DEFINE WRITE_PACKABLE_DEFNS(NAME, ARRAY_TYPE, TYPE, ACCESSOR_NAME)
+//%- (void)write##NAME##Array:(int32_t)fieldNumber
+//%       NAME$S     values:(GPB##ARRAY_TYPE##Array *)values
+//%       NAME$S        tag:(uint32_t)tag {
+//%  if (tag != 0) {
+//%    if (values.count == 0) return;
+//%    __block size_t dataSize = 0;
+//%    [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%#pragma unused(idx, stop)
+//%      dataSize += GPBCompute##NAME##SizeNoTag(value);
+//%    }];
+//%    GPBWriteRawVarint32(&state_, tag);
+//%    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+//%    [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%#pragma unused(idx, stop)
+//%      [self write##NAME##NoTag:value];
+//%    }];
+//%  } else {
+//%    [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%#pragma unused(idx, stop)
+//%      [self write##NAME:fieldNumber value:value];
+//%    }];
+//%  }
+//%}
+//%
+//%PDDM-DEFINE WRITE_UNPACKABLE_DEFNS(NAME, TYPE)
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray *)values {
+//%  for (TYPE *value in values) {
+//%    [self write##NAME:fieldNumber value:value];
+//%  }
+//%}
+//%
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Double, Double, double, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeDoubleArray:(int32_t)fieldNumber
+                  values:(GPBDoubleArray *)values
+                     tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeDoubleSizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeDoubleNoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeDouble:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Float, Float, float, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeFloatArray:(int32_t)fieldNumber
+                 values:(GPBFloatArray *)values
+                    tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeFloatSizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFloatNoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFloat:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(UInt64, UInt64, uint64_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeUInt64Array:(int32_t)fieldNumber
+                  values:(GPBUInt64Array *)values
+                     tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeUInt64SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeUInt64NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeUInt64:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Int64, Int64, int64_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeInt64Array:(int32_t)fieldNumber
+                 values:(GPBInt64Array *)values
+                    tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeInt64SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeInt64NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeInt64:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Int32, Int32, int32_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeInt32Array:(int32_t)fieldNumber
+                 values:(GPBInt32Array *)values
+                    tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeInt32SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeInt32NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeInt32:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(UInt32, UInt32, uint32_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeUInt32Array:(int32_t)fieldNumber
+                  values:(GPBUInt32Array *)values
+                     tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeUInt32SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeUInt32NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeUInt32:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Fixed64, UInt64, uint64_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeFixed64Array:(int32_t)fieldNumber
+                   values:(GPBUInt64Array *)values
+                      tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeFixed64SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFixed64NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFixed64:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Fixed32, UInt32, uint32_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeFixed32Array:(int32_t)fieldNumber
+                   values:(GPBUInt32Array *)values
+                      tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeFixed32SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFixed32NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeFixed32:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SInt32, Int32, int32_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeSInt32Array:(int32_t)fieldNumber
+                  values:(GPBInt32Array *)values
+                     tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeSInt32SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSInt32NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSInt32:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SInt64, Int64, int64_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeSInt64Array:(int32_t)fieldNumber
+                  values:(GPBInt64Array *)values
+                     tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeSInt64SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSInt64NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSInt64:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SFixed64, Int64, int64_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeSFixed64Array:(int32_t)fieldNumber
+                    values:(GPBInt64Array *)values
+                       tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeSFixed64SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSFixed64NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSFixed64:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SFixed32, Int32, int32_t, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeSFixed32Array:(int32_t)fieldNumber
+                    values:(GPBInt32Array *)values
+                       tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeSFixed32SizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSFixed32NoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeSFixed32:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Bool, Bool, BOOL, )
+// This block of code is generated, do not edit it directly.
+
+- (void)writeBoolArray:(int32_t)fieldNumber
+                values:(GPBBoolArray *)values
+                   tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeBoolSizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeBoolNoTag:value];
+    }];
+  } else {
+    [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeBool:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Enum, Enum, int32_t, Raw)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeEnumArray:(int32_t)fieldNumber
+                values:(GPBEnumArray *)values
+                   tag:(uint32_t)tag {
+  if (tag != 0) {
+    if (values.count == 0) return;
+    __block size_t dataSize = 0;
+    [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      dataSize += GPBComputeEnumSizeNoTag(value);
+    }];
+    GPBWriteRawVarint32(&state_, tag);
+    GPBWriteRawVarint32(&state_, (int32_t)dataSize);
+    [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeEnumNoTag:value];
+    }];
+  } else {
+    [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+      [self writeEnum:fieldNumber value:value];
+    }];
+  }
+}
+
+//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(String, NSString)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeStringArray:(int32_t)fieldNumber values:(NSArray *)values {
+  for (NSString *value in values) {
+    [self writeString:fieldNumber value:value];
+  }
+}
+
+//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Message, GPBMessage)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray *)values {
+  for (GPBMessage *value in values) {
+    [self writeMessage:fieldNumber value:value];
+  }
+}
+
+//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Bytes, NSData)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray *)values {
+  for (NSData *value in values) {
+    [self writeBytes:fieldNumber value:value];
+  }
+}
+
+//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Group, GPBMessage)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray *)values {
+  for (GPBMessage *value in values) {
+    [self writeGroup:fieldNumber value:value];
+  }
+}
+
+//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(UnknownGroup, GPBUnknownFieldSet)
+// This block of code is generated, do not edit it directly.
+
+- (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray *)values {
+  for (GPBUnknownFieldSet *value in values) {
+    [self writeUnknownGroup:fieldNumber value:value];
+  }
+}
+
+//%PDDM-EXPAND-END (19 expansions)
+
+- (void)writeMessageSetExtension:(int32_t)fieldNumber
+                           value:(GPBMessage *)value {
+  GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem,
+                        GPBWireFormatStartGroup);
+  GPBWriteUInt32(&state_, GPBWireFormatMessageSetTypeId, fieldNumber);
+  [self writeMessage:GPBWireFormatMessageSetMessage value:value];
+  GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem,
+                        GPBWireFormatEndGroup);
+}
+
+- (void)writeRawMessageSetExtension:(int32_t)fieldNumber value:(NSData *)value {
+  GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem,
+                        GPBWireFormatStartGroup);
+  GPBWriteUInt32(&state_, GPBWireFormatMessageSetTypeId, fieldNumber);
+  [self writeBytes:GPBWireFormatMessageSetMessage value:value];
+  GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem,
+                        GPBWireFormatEndGroup);
+}
+
+- (void)flush {
+  if (state_.output != nil) {
+    GPBRefreshBuffer(&state_);
+  }
+}
+
+- (void)writeRawByte:(uint8_t)value {
+  GPBWriteRawByte(&state_, value);
+}
+
+- (void)writeRawData:(const NSData *)data {
+  [self writeRawPtr:[data bytes] offset:0 length:[data length]];
+}
+
+- (void)writeRawPtr:(const void *)value
+             offset:(size_t)offset
+             length:(size_t)length {
+  if (value == nil || length == 0) {
+    return;
+  }
+
+  NSUInteger bufferLength = state_.size;
+  NSUInteger bufferBytesLeft = bufferLength - state_.position;
+  if (bufferBytesLeft >= length) {
+    // We have room in the current buffer.
+    memcpy(state_.bytes + state_.position, ((uint8_t *)value) + offset, length);
+    state_.position += length;
+  } else {
+    // Write extends past current buffer.  Fill the rest of this buffer and
+    // flush.
+    size_t bytesWritten = bufferBytesLeft;
+    memcpy(state_.bytes + state_.position, ((uint8_t *)value) + offset,
+           bytesWritten);
+    offset += bytesWritten;
+    length -= bytesWritten;
+    state_.position = bufferLength;
+    GPBRefreshBuffer(&state_);
+    bufferLength = state_.size;
+
+    // Now deal with the rest.
+    // Since we have an output stream, this is our buffer
+    // and buffer offset == 0
+    if (length <= bufferLength) {
+      // Fits in new buffer.
+      memcpy(state_.bytes, ((uint8_t *)value) + offset, length);
+      state_.position = length;
+    } else {
+      // Write is very big.  Let's do it all at once.
+      [state_.output write:((uint8_t *)value) + offset maxLength:length];
+    }
+  }
+}
+
+- (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format {
+  GPBWriteTagWithFormat(&state_, fieldNumber, format);
+}
+
+- (void)writeRawVarint32:(int32_t)value {
+  GPBWriteRawVarint32(&state_, value);
+}
+
+- (void)writeRawVarintSizeTAs32:(size_t)value {
+  // Note the truncation.
+  GPBWriteRawVarint32(&state_, (int32_t)value);
+}
+
+- (void)writeRawVarint64:(int64_t)value {
+  GPBWriteRawVarint64(&state_, value);
+}
+
+- (void)writeRawLittleEndian32:(int32_t)value {
+  GPBWriteRawLittleEndian32(&state_, value);
+}
+
+- (void)writeRawLittleEndian64:(int64_t)value {
+  GPBWriteRawLittleEndian64(&state_, value);
+}
+
+@end
+
+size_t GPBComputeDoubleSizeNoTag(Float64 value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_64_SIZE;
+}
+
+size_t GPBComputeFloatSizeNoTag(Float32 value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_32_SIZE;
+}
+
+size_t GPBComputeUInt64SizeNoTag(uint64_t value) {
+  return GPBComputeRawVarint64Size(value);
+}
+
+size_t GPBComputeInt64SizeNoTag(int64_t value) {
+  return GPBComputeRawVarint64Size(value);
+}
+
+size_t GPBComputeInt32SizeNoTag(int32_t value) {
+  if (value >= 0) {
+    return GPBComputeRawVarint32Size(value);
+  } else {
+    // Must sign-extend.
+    return 10;
+  }
+}
+
+size_t GPBComputeSizeTSizeAsInt32NoTag(size_t value) {
+  return GPBComputeInt32SizeNoTag((int32_t)value);
+}
+
+size_t GPBComputeFixed64SizeNoTag(uint64_t value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_64_SIZE;
+}
+
+size_t GPBComputeFixed32SizeNoTag(uint32_t value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_32_SIZE;
+}
+
+size_t GPBComputeBoolSizeNoTag(BOOL value) {
+#pragma unused(value)
+  return 1;
+}
+
+size_t GPBComputeStringSizeNoTag(NSString *value) {
+  // If you are concerned about embedded NULLs see the test in
+  // +load above.
+  const char *quickString =
+      CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8);
+  NSUInteger length =
+      (quickString != NULL)
+          ? strlen(quickString)
+          : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+  return GPBComputeRawVarint32SizeForInteger(length) + length;
+}
+
+size_t GPBComputeGroupSizeNoTag(GPBMessage *value) {
+  return [value serializedSize];
+}
+
+size_t GPBComputeUnknownGroupSizeNoTag(GPBUnknownFieldSet *value) {
+  return value.serializedSize;
+}
+
+size_t GPBComputeMessageSizeNoTag(GPBMessage *value) {
+  size_t size = [value serializedSize];
+  return GPBComputeRawVarint32SizeForInteger(size) + size;
+}
+
+size_t GPBComputeBytesSizeNoTag(NSData *value) {
+  NSUInteger valueLength = [value length];
+  return GPBComputeRawVarint32SizeForInteger(valueLength) + valueLength;
+}
+
+size_t GPBComputeUInt32SizeNoTag(int32_t value) {
+  return GPBComputeRawVarint32Size(value);
+}
+
+size_t GPBComputeEnumSizeNoTag(int32_t value) {
+  return GPBComputeRawVarint32Size(value);
+}
+
+size_t GPBComputeSFixed32SizeNoTag(int32_t value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_32_SIZE;
+}
+
+size_t GPBComputeSFixed64SizeNoTag(int64_t value) {
+#pragma unused(value)
+  return LITTLE_ENDIAN_64_SIZE;
+}
+
+size_t GPBComputeSInt32SizeNoTag(int32_t value) {
+  return GPBComputeRawVarint32Size(GPBEncodeZigZag32(value));
+}
+
+size_t GPBComputeSInt64SizeNoTag(int64_t value) {
+  return GPBComputeRawVarint64Size(GPBEncodeZigZag64(value));
+}
+
+size_t GPBComputeDoubleSize(int32_t fieldNumber, double value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeDoubleSizeNoTag(value);
+}
+
+size_t GPBComputeFloatSize(int32_t fieldNumber, float value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeFloatSizeNoTag(value);
+}
+
+size_t GPBComputeUInt64Size(int32_t fieldNumber, uint64_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeUInt64SizeNoTag(value);
+}
+
+size_t GPBComputeInt64Size(int32_t fieldNumber, int64_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeInt64SizeNoTag(value);
+}
+
+size_t GPBComputeInt32Size(int32_t fieldNumber, int32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeInt32SizeNoTag(value);
+}
+
+size_t GPBComputeFixed64Size(int32_t fieldNumber, uint64_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeFixed64SizeNoTag(value);
+}
+
+size_t GPBComputeFixed32Size(int32_t fieldNumber, uint32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeFixed32SizeNoTag(value);
+}
+
+size_t GPBComputeBoolSize(int32_t fieldNumber, BOOL value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeBoolSizeNoTag(value);
+}
+
+size_t GPBComputeStringSize(int32_t fieldNumber, NSString *value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeStringSizeNoTag(value);
+}
+
+size_t GPBComputeGroupSize(int32_t fieldNumber, GPBMessage *value) {
+  return GPBComputeTagSize(fieldNumber) * 2 + GPBComputeGroupSizeNoTag(value);
+}
+
+size_t GPBComputeUnknownGroupSize(int32_t fieldNumber,
+                                  GPBUnknownFieldSet *value) {
+  return GPBComputeTagSize(fieldNumber) * 2 +
+         GPBComputeUnknownGroupSizeNoTag(value);
+}
+
+size_t GPBComputeMessageSize(int32_t fieldNumber, GPBMessage *value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeMessageSizeNoTag(value);
+}
+
+size_t GPBComputeBytesSize(int32_t fieldNumber, NSData *value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeBytesSizeNoTag(value);
+}
+
+size_t GPBComputeUInt32Size(int32_t fieldNumber, uint32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeUInt32SizeNoTag(value);
+}
+
+size_t GPBComputeEnumSize(int32_t fieldNumber, int32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeEnumSizeNoTag(value);
+}
+
+size_t GPBComputeSFixed32Size(int32_t fieldNumber, int32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeSFixed32SizeNoTag(value);
+}
+
+size_t GPBComputeSFixed64Size(int32_t fieldNumber, int64_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeSFixed64SizeNoTag(value);
+}
+
+size_t GPBComputeSInt32Size(int32_t fieldNumber, int32_t value) {
+  return GPBComputeTagSize(fieldNumber) + GPBComputeSInt32SizeNoTag(value);
+}
+
+size_t GPBComputeSInt64Size(int32_t fieldNumber, int64_t value) {
+  return GPBComputeTagSize(fieldNumber) +
+         GPBComputeRawVarint64Size(GPBEncodeZigZag64(value));
+}
+
+size_t GPBComputeMessageSetExtensionSize(int32_t fieldNumber,
+                                         GPBMessage *value) {
+  return GPBComputeTagSize(GPBWireFormatMessageSetItem) * 2 +
+         GPBComputeUInt32Size(GPBWireFormatMessageSetTypeId, fieldNumber) +
+         GPBComputeMessageSize(GPBWireFormatMessageSetMessage, value);
+}
+
+size_t GPBComputeRawMessageSetExtensionSize(int32_t fieldNumber,
+                                            NSData *value) {
+  return GPBComputeTagSize(GPBWireFormatMessageSetItem) * 2 +
+         GPBComputeUInt32Size(GPBWireFormatMessageSetTypeId, fieldNumber) +
+         GPBComputeBytesSize(GPBWireFormatMessageSetMessage, value);
+}
+
+size_t GPBComputeTagSize(int32_t fieldNumber) {
+  return GPBComputeRawVarint32Size(
+      GPBWireFormatMakeTag(fieldNumber, GPBWireFormatVarint));
+}
+
+size_t GPBComputeWireFormatTagSize(int field_number, GPBDataType dataType) {
+  size_t result = GPBComputeTagSize(field_number);
+  if (dataType == GPBDataTypeGroup) {
+    // Groups have both a start and an end tag.
+    return result * 2;
+  } else {
+    return result;
+  }
+}
+
+size_t GPBComputeRawVarint32Size(int32_t value) {
+  // value is treated as unsigned, so it won't be sign-extended if negative.
+  if ((value & (0xffffffff << 7)) == 0) return 1;
+  if ((value & (0xffffffff << 14)) == 0) return 2;
+  if ((value & (0xffffffff << 21)) == 0) return 3;
+  if ((value & (0xffffffff << 28)) == 0) return 4;
+  return 5;
+}
+
+size_t GPBComputeRawVarint32SizeForInteger(NSInteger value) {
+  // Note the truncation.
+  return GPBComputeRawVarint32Size((int32_t)value);
+}
+
+size_t GPBComputeRawVarint64Size(int64_t value) {
+  if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
+  if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+  if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+  if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+  if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+  if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+  if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+  if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+  if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+  return 10;
+}
diff --git a/objectivec/GPBCodedOutputStream_PackagePrivate.h b/objectivec/GPBCodedOutputStream_PackagePrivate.h
new file mode 100644
index 0000000..2e7bb4c
--- /dev/null
+++ b/objectivec/GPBCodedOutputStream_PackagePrivate.h
@@ -0,0 +1,126 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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 "GPBCodedOutputStream.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+CF_EXTERN_C_BEGIN
+
+size_t GPBComputeDoubleSize(int32_t fieldNumber, double value)
+    __attribute__((const));
+size_t GPBComputeFloatSize(int32_t fieldNumber, float value)
+    __attribute__((const));
+size_t GPBComputeUInt64Size(int32_t fieldNumber, uint64_t value)
+    __attribute__((const));
+size_t GPBComputeInt64Size(int32_t fieldNumber, int64_t value)
+    __attribute__((const));
+size_t GPBComputeInt32Size(int32_t fieldNumber, int32_t value)
+    __attribute__((const));
+size_t GPBComputeFixed64Size(int32_t fieldNumber, uint64_t value)
+    __attribute__((const));
+size_t GPBComputeFixed32Size(int32_t fieldNumber, uint32_t value)
+    __attribute__((const));
+size_t GPBComputeBoolSize(int32_t fieldNumber, BOOL value)
+    __attribute__((const));
+size_t GPBComputeStringSize(int32_t fieldNumber, NSString *value)
+    __attribute__((const));
+size_t GPBComputeGroupSize(int32_t fieldNumber, GPBMessage *value)
+    __attribute__((const));
+size_t GPBComputeUnknownGroupSize(int32_t fieldNumber,
+                                  GPBUnknownFieldSet *value)
+    __attribute__((const));
+size_t GPBComputeMessageSize(int32_t fieldNumber, GPBMessage *value)
+    __attribute__((const));
+size_t GPBComputeBytesSize(int32_t fieldNumber, NSData *value)
+    __attribute__((const));
+size_t GPBComputeUInt32Size(int32_t fieldNumber, uint32_t value)
+    __attribute__((const));
+size_t GPBComputeSFixed32Size(int32_t fieldNumber, int32_t value)
+    __attribute__((const));
+size_t GPBComputeSFixed64Size(int32_t fieldNumber, int64_t value)
+    __attribute__((const));
+size_t GPBComputeSInt32Size(int32_t fieldNumber, int32_t value)
+    __attribute__((const));
+size_t GPBComputeSInt64Size(int32_t fieldNumber, int64_t value)
+    __attribute__((const));
+size_t GPBComputeTagSize(int32_t fieldNumber) __attribute__((const));
+size_t GPBComputeWireFormatTagSize(int field_number, GPBDataType dataType)
+    __attribute__((const));
+
+size_t GPBComputeDoubleSizeNoTag(double value) __attribute__((const));
+size_t GPBComputeFloatSizeNoTag(float value) __attribute__((const));
+size_t GPBComputeUInt64SizeNoTag(uint64_t value) __attribute__((const));
+size_t GPBComputeInt64SizeNoTag(int64_t value) __attribute__((const));
+size_t GPBComputeInt32SizeNoTag(int32_t value) __attribute__((const));
+size_t GPBComputeFixed64SizeNoTag(uint64_t value) __attribute__((const));
+size_t GPBComputeFixed32SizeNoTag(uint32_t value) __attribute__((const));
+size_t GPBComputeBoolSizeNoTag(BOOL value) __attribute__((const));
+size_t GPBComputeStringSizeNoTag(NSString *value) __attribute__((const));
+size_t GPBComputeGroupSizeNoTag(GPBMessage *value) __attribute__((const));
+size_t GPBComputeUnknownGroupSizeNoTag(GPBUnknownFieldSet *value)
+    __attribute__((const));
+size_t GPBComputeMessageSizeNoTag(GPBMessage *value) __attribute__((const));
+size_t GPBComputeBytesSizeNoTag(NSData *value) __attribute__((const));
+size_t GPBComputeUInt32SizeNoTag(int32_t value) __attribute__((const));
+size_t GPBComputeEnumSizeNoTag(int32_t value) __attribute__((const));
+size_t GPBComputeSFixed32SizeNoTag(int32_t value) __attribute__((const));
+size_t GPBComputeSFixed64SizeNoTag(int64_t value) __attribute__((const));
+size_t GPBComputeSInt32SizeNoTag(int32_t value) __attribute__((const));
+size_t GPBComputeSInt64SizeNoTag(int64_t value) __attribute__((const));
+
+// Note that this will calculate the size of 64 bit values truncated to 32.
+size_t GPBComputeSizeTSizeAsInt32NoTag(size_t value) __attribute__((const));
+
+size_t GPBComputeRawVarint32Size(int32_t value) __attribute__((const));
+size_t GPBComputeRawVarint64Size(int64_t value) __attribute__((const));
+
+// Note that this will calculate the size of 64 bit values truncated to 32.
+size_t GPBComputeRawVarint32SizeForInteger(NSInteger value)
+    __attribute__((const));
+
+// Compute the number of bytes that would be needed to encode a
+// MessageSet extension to the stream.  For historical reasons,
+// the wire format differs from normal fields.
+size_t GPBComputeMessageSetExtensionSize(int32_t fieldNumber, GPBMessage *value)
+    __attribute__((const));
+
+// Compute the number of bytes that would be needed to encode an
+// unparsed MessageSet extension field to the stream.  For
+// historical reasons, the wire format differs from normal fields.
+size_t GPBComputeRawMessageSetExtensionSize(int32_t fieldNumber, NSData *value)
+    __attribute__((const));
+
+size_t GPBComputeEnumSize(int32_t fieldNumber, int32_t value)
+    __attribute__((const));
+
+CF_EXTERN_C_END
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
new file mode 100644
index 0000000..a6eff0f
--- /dev/null
+++ b/objectivec/GPBDescriptor.h
@@ -0,0 +1,141 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRuntimeTypes.h"
+
+@class GPBEnumDescriptor;
+@class GPBFieldDescriptor;
+@class GPBFileDescriptor;
+@class GPBOneofDescriptor;
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(uint8_t, GPBFileSyntax) {
+  GPBFileSyntaxUnknown = 0,
+  GPBFileSyntaxProto2 = 2,
+  GPBFileSyntaxProto3 = 3,
+};
+
+typedef NS_ENUM(uint8_t, GPBFieldType) {
+  GPBFieldTypeSingle,    // optional/required
+  GPBFieldTypeRepeated,  // repeated
+  GPBFieldTypeMap,       // map<K,V>
+};
+
+@interface GPBDescriptor : NSObject<NSCopying>
+
+@property(nonatomic, readonly, copy) NSString *name;
+@property(nonatomic, readonly, strong, nullable) NSArray<GPBFieldDescriptor*> *fields;
+@property(nonatomic, readonly, strong, nullable) NSArray<GPBOneofDescriptor*> *oneofs;
+@property(nonatomic, readonly, nullable) const GPBExtensionRange *extensionRanges;
+@property(nonatomic, readonly) uint32_t extensionRangesCount;
+@property(nonatomic, readonly, assign) GPBFileDescriptor *file;
+
+@property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
+@property(nonatomic, readonly) Class messageClass;
+
+- (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber;
+- (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name;
+- (nullable GPBOneofDescriptor *)oneofWithName:(NSString *)name;
+
+@end
+
+@interface GPBFileDescriptor : NSObject
+
+@property(nonatomic, readonly, copy) NSString *package;
+@property(nonatomic, readonly) GPBFileSyntax syntax;
+
+@end
+
+@interface GPBOneofDescriptor : NSObject
+@property(nonatomic, readonly) NSString *name;
+@property(nonatomic, readonly) NSArray<GPBFieldDescriptor*> *fields;
+
+- (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber;
+- (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name;
+@end
+
+@interface GPBFieldDescriptor : NSObject
+
+@property(nonatomic, readonly, copy) NSString *name;
+@property(nonatomic, readonly) uint32_t number;
+@property(nonatomic, readonly) GPBDataType dataType;
+@property(nonatomic, readonly) BOOL hasDefaultValue;
+@property(nonatomic, readonly) GPBGenericValue defaultValue;
+@property(nonatomic, readonly, getter=isRequired) BOOL required;
+@property(nonatomic, readonly, getter=isOptional) BOOL optional;
+@property(nonatomic, readonly) GPBFieldType fieldType;
+// If it is a map, the value type is in -type.
+@property(nonatomic, readonly) GPBDataType mapKeyDataType;
+@property(nonatomic, readonly, getter=isPackable) BOOL packable;
+
+@property(nonatomic, readonly, assign, nullable) GPBOneofDescriptor *containingOneof;
+
+// Message properties
+@property(nonatomic, readonly, assign, nullable) Class msgClass;
+
+// Enum properties
+@property(nonatomic, readonly, strong, nullable) GPBEnumDescriptor *enumDescriptor;
+
+- (BOOL)isValidEnumValue:(int32_t)value;
+
+// For now, this will return nil if it doesn't know the name to use for
+// TextFormat.
+- (nullable NSString *)textFormatName;
+
+@end
+
+@interface GPBEnumDescriptor : NSObject
+
+@property(nonatomic, readonly, copy) NSString *name;
+@property(nonatomic, readonly) GPBEnumValidationFunc enumVerifier;
+
+- (nullable NSString *)enumNameForValue:(int32_t)number;
+- (BOOL)getValue:(nullable int32_t *)outValue forEnumName:(NSString *)name;
+
+- (nullable NSString *)textFormatNameForValue:(int32_t)number;
+
+@end
+
+@interface GPBExtensionDescriptor : NSObject<NSCopying>
+@property(nonatomic, readonly) uint32_t fieldNumber;
+@property(nonatomic, readonly) Class containingMessageClass;
+@property(nonatomic, readonly) GPBDataType dataType;
+@property(nonatomic, readonly, getter=isRepeated) BOOL repeated;
+@property(nonatomic, readonly, getter=isPackable) BOOL packable;
+@property(nonatomic, readonly, assign) Class msgClass;
+@property(nonatomic, readonly) NSString *singletonName;
+@property(nonatomic, readonly, strong, nullable) GPBEnumDescriptor *enumDescriptor;
+@property(nonatomic, readonly) id defaultValue;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
new file mode 100644
index 0000000..2709737
--- /dev/null
+++ b/objectivec/GPBDescriptor.m
@@ -0,0 +1,963 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBDescriptor_PackagePrivate.h"
+
+#import <objc/runtime.h>
+
+#import "GPBUtilities_PackagePrivate.h"
+#import "GPBWireFormat.h"
+#import "GPBMessage_PackagePrivate.h"
+
+// The address of this variable is used as a key for obj_getAssociatedObject.
+static const char kTextFormatExtraValueKey = 0;
+
+// Utility function to generate selectors on the fly.
+static SEL SelFromStrings(const char *prefix, const char *middle,
+                          const char *suffix, BOOL takesArg) {
+  if (prefix == NULL && suffix == NULL && !takesArg) {
+    return sel_getUid(middle);
+  }
+  const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0;
+  const size_t middleLen = strlen(middle);
+  const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0;
+  size_t totalLen =
+      prefixLen + middleLen + suffixLen + 1;  // include space for null on end.
+  if (takesArg) {
+    totalLen += 1;
+  }
+  char buffer[totalLen];
+  if (prefix != NULL) {
+    memcpy(buffer, prefix, prefixLen);
+    memcpy(buffer + prefixLen, middle, middleLen);
+    buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
+  } else {
+    memcpy(buffer, middle, middleLen);
+  }
+  if (suffix != NULL) {
+    memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
+  }
+  if (takesArg) {
+    buffer[totalLen - 2] = ':';
+  }
+  // Always null terminate it.
+  buffer[totalLen - 1] = 0;
+
+  SEL result = sel_getUid(buffer);
+  return result;
+}
+
+static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
+                                          NSArray *allMessageFields)
+    __attribute__((ns_returns_retained));
+
+static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
+                                          NSArray *allMessageFields) {
+  NSMutableArray *result = [[NSMutableArray alloc] init];
+  for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
+    if (fieldDesc->description_->hasIndex == hasIndex) {
+      [result addObject:fieldDesc];
+    }
+  }
+  return result;
+}
+
+@implementation GPBDescriptor {
+  Class messageClass_;
+  GPBFileDescriptor *file_;
+  BOOL wireFormat_;
+}
+
+@synthesize messageClass = messageClass_;
+@synthesize fields = fields_;
+@synthesize oneofs = oneofs_;
+@synthesize extensionRanges = extensionRanges_;
+@synthesize extensionRangesCount = extensionRangesCount_;
+@synthesize file = file_;
+@synthesize wireFormat = wireFormat_;
+
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(void *)fieldDescriptions
+                 fieldCount:(uint32_t)fieldCount
+                storageSize:(uint32_t)storageSize
+                      flags:(GPBDescriptorInitializationFlags)flags {
+  // The rootClass is no longer used, but it is passed in to ensure it
+  // was started up during initialization also.
+  (void)rootClass;
+  NSMutableArray *fields = nil;
+  GPBFileSyntax syntax = file.syntax;
+  BOOL fieldsIncludeDefault =
+      (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
+
+  void *desc;
+  for (uint32_t i = 0; i < fieldCount; ++i) {
+    if (fields == nil) {
+      fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
+    }
+    // Need correctly typed pointer for array indexing below to work.
+    if (fieldsIncludeDefault) {
+      GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions;
+      desc = &(fieldDescWithDefault[i]);
+    } else {
+      GPBMessageFieldDescription *fieldDesc = fieldDescriptions;
+      desc = &(fieldDesc[i]);
+    }
+    GPBFieldDescriptor *fieldDescriptor =
+        [[GPBFieldDescriptor alloc] initWithFieldDescription:desc
+                                             includesDefault:fieldsIncludeDefault
+                                                      syntax:syntax];
+    [fields addObject:fieldDescriptor];
+    [fieldDescriptor release];
+  }
+
+  BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
+  GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
+                                                     file:file
+                                                   fields:fields
+                                              storageSize:storageSize
+                                               wireFormat:wireFormat];
+  [fields release];
+  return descriptor;
+}
+
+- (instancetype)initWithClass:(Class)messageClass
+                         file:(GPBFileDescriptor *)file
+                       fields:(NSArray *)fields
+                  storageSize:(uint32_t)storageSize
+                   wireFormat:(BOOL)wireFormat {
+  if ((self = [super init])) {
+    messageClass_ = messageClass;
+    file_ = file;
+    fields_ = [fields retain];
+    storageSize_ = storageSize;
+    wireFormat_ = wireFormat;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [fields_ release];
+  [oneofs_ release];
+  [super dealloc];
+}
+
+- (void)setupOneofs:(const char **)oneofNames
+              count:(uint32_t)count
+      firstHasIndex:(int32_t)firstHasIndex {
+  NSCAssert(firstHasIndex < 0, @"Should always be <0");
+  NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
+    const char *name = oneofNames[i];
+    NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
+    NSCAssert(fieldsForOneof.count > 0,
+              @"No fields for this oneof? (%s:%d)", name, hasIndex);
+    GPBOneofDescriptor *oneofDescriptor =
+        [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof];
+    [oneofs addObject:oneofDescriptor];
+    [oneofDescriptor release];
+    [fieldsForOneof release];
+  }
+  oneofs_ = oneofs;
+}
+
+- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
+  // Extra info is a compile time option, so skip the work if not needed.
+  if (extraTextFormatInfo) {
+    NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
+    for (GPBFieldDescriptor *fieldDescriptor in fields_) {
+      if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
+        objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey,
+                                 extraInfoValue,
+                                 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+      }
+    }
+  }
+}
+
+- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
+  extensionRanges_ = ranges;
+  extensionRangesCount_ = count;
+}
+
+- (NSString *)name {
+  return NSStringFromClass(messageClass_);
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+#pragma unused(zone)
+  return [self retain];
+}
+
+- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
+  for (GPBFieldDescriptor *descriptor in fields_) {
+    if (GPBFieldNumber(descriptor) == fieldNumber) {
+      return descriptor;
+    }
+  }
+  return nil;
+}
+
+- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
+  for (GPBFieldDescriptor *descriptor in fields_) {
+    if ([descriptor.name isEqual:name]) {
+      return descriptor;
+    }
+  }
+  return nil;
+}
+
+- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
+  for (GPBOneofDescriptor *descriptor in oneofs_) {
+    if ([descriptor.name isEqual:name]) {
+      return descriptor;
+    }
+  }
+  return nil;
+}
+
+@end
+
+@implementation GPBFileDescriptor {
+  NSString *package_;
+  GPBFileSyntax syntax_;
+}
+
+@synthesize package = package_;
+@synthesize syntax = syntax_;
+
+- (instancetype)initWithPackage:(NSString *)package
+                         syntax:(GPBFileSyntax)syntax {
+  self = [super init];
+  if (self) {
+    package_ = [package copy];
+    syntax_ = syntax;
+  }
+  return self;
+}
+
+@end
+
+@implementation GPBOneofDescriptor
+
+@synthesize fields = fields_;
+
+- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
+  self = [super init];
+  if (self) {
+    name_ = name;
+    fields_ = [fields retain];
+    for (GPBFieldDescriptor *fieldDesc in fields) {
+      fieldDesc->containingOneof_ = self;
+    }
+
+    caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [fields_ release];
+  [super dealloc];
+}
+
+- (NSString *)name {
+  return @(name_);
+}
+
+- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
+  for (GPBFieldDescriptor *descriptor in fields_) {
+    if (GPBFieldNumber(descriptor) == fieldNumber) {
+      return descriptor;
+    }
+  }
+  return nil;
+}
+
+- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
+  for (GPBFieldDescriptor *descriptor in fields_) {
+    if ([descriptor.name isEqual:name]) {
+      return descriptor;
+    }
+  }
+  return nil;
+}
+
+@end
+
+uint32_t GPBFieldTag(GPBFieldDescriptor *self) {
+  GPBMessageFieldDescription *description = self->description_;
+  GPBWireFormat format;
+  if ((description->flags & GPBFieldMapKeyMask) != 0) {
+    // Maps are repeated messages on the wire.
+    format = GPBWireFormatForType(GPBDataTypeMessage, NO);
+  } else {
+    format = GPBWireFormatForType(description->dataType,
+                                  ((description->flags & GPBFieldPacked) != 0));
+  }
+  return GPBWireFormatMakeTag(description->number, format);
+}
+
+uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
+  GPBMessageFieldDescription *description = self->description_;
+  NSCAssert((description->flags & GPBFieldRepeated) != 0,
+            @"Only valid on repeated fields");
+  GPBWireFormat format =
+      GPBWireFormatForType(description->dataType,
+                           ((description->flags & GPBFieldPacked) == 0));
+  return GPBWireFormatMakeTag(description->number, format);
+}
+
+@implementation GPBFieldDescriptor {
+  GPBGenericValue defaultValue_;
+
+  // Message ivars
+  Class msgClass_;
+
+  // Enum ivars.
+  // If protos are generated with GenerateEnumDescriptors on then it will
+  // be a enumDescriptor, otherwise it will be a enumVerifier.
+  union {
+    GPBEnumDescriptor *enumDescriptor_;
+    GPBEnumValidationFunc enumVerifier_;
+  } enumHandling_;
+}
+
+@synthesize msgClass = msgClass_;
+@synthesize containingOneof = containingOneof_;
+
+- (instancetype)init {
+  // Throw an exception if people attempt to not use the designated initializer.
+  self = [super init];
+  if (self != nil) {
+    [self doesNotRecognizeSelector:_cmd];
+    self = nil;
+  }
+  return self;
+}
+
+- (instancetype)initWithFieldDescription:(void *)description
+                         includesDefault:(BOOL)includesDefault
+                                  syntax:(GPBFileSyntax)syntax {
+  if ((self = [super init])) {
+    GPBMessageFieldDescription *coreDesc;
+    if (includesDefault) {
+      coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
+    } else {
+      coreDesc = description;
+    }
+    description_ = coreDesc;
+    getSel_ = sel_getUid(coreDesc->name);
+    setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
+
+    GPBDataType dataType = coreDesc->dataType;
+    BOOL isMessage = GPBDataTypeIsMessage(dataType);
+    BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
+
+    if (isMapOrArray) {
+      // map<>/repeated fields get a *Count property (inplace of a has*) to
+      // support checking if there are any entries without triggering
+      // autocreation.
+      hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
+    } else {
+      // If there is a positive hasIndex, then:
+      //   - All fields types for proto2 messages get has* selectors.
+      //   - Only message fields for proto3 messages get has* selectors.
+      // Note: the positive check is to handle oneOfs, we can't check
+      // containingOneof_ because it isn't set until after initialization.
+      if ((coreDesc->hasIndex >= 0) &&
+          (coreDesc->hasIndex != GPBNoHasBit) &&
+          ((syntax != GPBFileSyntaxProto3) || isMessage)) {
+        hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
+        setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
+      }
+    }
+
+    // Extra type specific data.
+    if (isMessage) {
+      const char *className = coreDesc->dataTypeSpecific.className;
+      msgClass_ = objc_getClass(className);
+      NSAssert(msgClass_, @"Class %s not defined", className);
+    } else if (dataType == GPBDataTypeEnum) {
+      if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) {
+        enumHandling_.enumDescriptor_ =
+            coreDesc->dataTypeSpecific.enumDescFunc();
+      } else {
+        enumHandling_.enumVerifier_ =
+            coreDesc->dataTypeSpecific.enumVerifier;
+      }
+    }
+
+    // Non map<>/repeated fields can have defaults in proto2 syntax.
+    if (!isMapOrArray && includesDefault) {
+      defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
+      if (dataType == GPBDataTypeBytes) {
+        // Data stored as a length prefixed (network byte order) c-string in
+        // descriptor structure.
+        const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
+        if (bytes) {
+          uint32_t length = *((uint32_t *)bytes);
+          length = ntohl(length);
+          bytes += sizeof(length);
+          defaultValue_.valueData =
+              [[NSData alloc] initWithBytes:bytes length:length];
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (description_->dataType == GPBDataTypeBytes &&
+      !(description_->flags & GPBFieldRepeated)) {
+    [defaultValue_.valueData release];
+  }
+  [super dealloc];
+}
+
+- (GPBDataType)dataType {
+  return description_->dataType;
+}
+
+- (BOOL)hasDefaultValue {
+  return (description_->flags & GPBFieldHasDefaultValue) != 0;
+}
+
+- (uint32_t)number {
+  return description_->number;
+}
+
+- (NSString *)name {
+  return @(description_->name);
+}
+
+- (BOOL)isRequired {
+  return (description_->flags & GPBFieldRequired) != 0;
+}
+
+- (BOOL)isOptional {
+  return (description_->flags & GPBFieldOptional) != 0;
+}
+
+- (GPBFieldType)fieldType {
+  GPBFieldFlags flags = description_->flags;
+  if ((flags & GPBFieldRepeated) != 0) {
+    return GPBFieldTypeRepeated;
+  } else if ((flags & GPBFieldMapKeyMask) != 0) {
+    return GPBFieldTypeMap;
+  } else {
+    return GPBFieldTypeSingle;
+  }
+}
+
+- (GPBDataType)mapKeyDataType {
+  switch (description_->flags & GPBFieldMapKeyMask) {
+    case GPBFieldMapKeyInt32:
+      return GPBDataTypeInt32;
+    case GPBFieldMapKeyInt64:
+      return GPBDataTypeInt64;
+    case GPBFieldMapKeyUInt32:
+      return GPBDataTypeUInt32;
+    case GPBFieldMapKeyUInt64:
+      return GPBDataTypeUInt64;
+    case GPBFieldMapKeySInt32:
+      return GPBDataTypeSInt32;
+    case GPBFieldMapKeySInt64:
+      return GPBDataTypeSInt64;
+    case GPBFieldMapKeyFixed32:
+      return GPBDataTypeFixed32;
+    case GPBFieldMapKeyFixed64:
+      return GPBDataTypeFixed64;
+    case GPBFieldMapKeySFixed32:
+      return GPBDataTypeSFixed32;
+    case GPBFieldMapKeySFixed64:
+      return GPBDataTypeSFixed64;
+    case GPBFieldMapKeyBool:
+      return GPBDataTypeBool;
+    case GPBFieldMapKeyString:
+      return GPBDataTypeString;
+
+    default:
+      NSAssert(0, @"Not a map type");
+      return GPBDataTypeInt32;  // For lack of anything better.
+  }
+}
+
+- (BOOL)isPackable {
+  return (description_->flags & GPBFieldPacked) != 0;
+}
+
+- (BOOL)isValidEnumValue:(int32_t)value {
+  NSAssert(description_->dataType == GPBDataTypeEnum,
+           @"Field Must be of type GPBDataTypeEnum");
+  if (description_->flags & GPBFieldHasEnumDescriptor) {
+    return enumHandling_.enumDescriptor_.enumVerifier(value);
+  } else {
+    return enumHandling_.enumVerifier_(value);
+  }
+}
+
+- (GPBEnumDescriptor *)enumDescriptor {
+  if (description_->flags & GPBFieldHasEnumDescriptor) {
+    return enumHandling_.enumDescriptor_;
+  } else {
+    return nil;
+  }
+}
+
+- (GPBGenericValue)defaultValue {
+  // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
+  // to an actual defaultValue in our initializer.
+  GPBGenericValue value = defaultValue_;
+
+  if (!(description_->flags & GPBFieldRepeated)) {
+    // We special handle data and strings. If they are nil, we replace them
+    // with empty string/empty data.
+    GPBDataType type = description_->dataType;
+    if (type == GPBDataTypeBytes && value.valueData == nil) {
+      value.valueData = GPBEmptyNSData();
+    } else if (type == GPBDataTypeString && value.valueString == nil) {
+      value.valueString = @"";
+    }
+  }
+  return value;
+}
+
+- (NSString *)textFormatName {
+  if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
+    NSValue *extraInfoValue =
+        objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
+    // Support can be left out at generation time.
+    if (!extraInfoValue) {
+      return nil;
+    }
+    const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
+    return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self),
+                                   self.name);
+  }
+
+  // The logic here has to match SetCommonFieldVariables() from
+  // objectivec_field.cc in the proto compiler.
+  NSString *name = self.name;
+  NSUInteger len = [name length];
+
+  // Remove the "_p" added to reserved names.
+  if ([name hasSuffix:@"_p"]) {
+    name = [name substringToIndex:(len - 2)];
+    len = [name length];
+  }
+
+  // Remove "Array" from the end for repeated fields.
+  if (((description_->flags & GPBFieldRepeated) != 0) &&
+      [name hasSuffix:@"Array"]) {
+    name = [name substringToIndex:(len - 5)];
+    len = [name length];
+  }
+
+  // Groups vs. other fields.
+  if (description_->dataType == GPBDataTypeGroup) {
+    // Just capitalize the first letter.
+    unichar firstChar = [name characterAtIndex:0];
+    if (firstChar >= 'a' && firstChar <= 'z') {
+      NSString *firstCharString =
+          [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
+      NSString *result =
+          [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
+                                        withString:firstCharString];
+      return result;
+    }
+    return name;
+
+  } else {
+    // Undo the CamelCase.
+    NSMutableString *result = [NSMutableString stringWithCapacity:len];
+    for (uint32_t i = 0; i < len; i++) {
+      unichar c = [name characterAtIndex:i];
+      if (c >= 'A' && c <= 'Z') {
+        if (i > 0) {
+          [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
+        } else {
+          [result appendFormat:@"%C", c];
+        }
+      } else {
+        [result appendFormat:@"%C", c];
+      }
+    }
+    return result;
+  }
+}
+
+@end
+
+@implementation GPBEnumDescriptor {
+  NSString *name_;
+  // valueNames_ is a single c string with all of the value names appended
+  // together, each null terminated.  -calcValueNameOffsets fills in
+  // nameOffsets_ with the offsets to allow quicker access to the individual
+  // names.
+  const char *valueNames_;
+  const int32_t *values_;
+  GPBEnumValidationFunc enumVerifier_;
+  const uint8_t *extraTextFormatInfo_;
+  uint32_t *nameOffsets_;
+  uint32_t valueCount_;
+}
+
+@synthesize name = name_;
+@synthesize enumVerifier = enumVerifier_;
+
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                valueNames:(const char *)valueNames
+                    values:(const int32_t *)values
+                     count:(uint32_t)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier {
+  GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
+                                                  valueNames:valueNames
+                                                      values:values
+                                                       count:valueCount
+                                                enumVerifier:enumVerifier];
+  return descriptor;
+}
+
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                valueNames:(const char *)valueNames
+                    values:(const int32_t *)values
+                     count:(uint32_t)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier
+       extraTextFormatInfo:(const char *)extraTextFormatInfo {
+  // Call the common case.
+  GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
+                                                    valueNames:valueNames
+                                                        values:values
+                                                         count:valueCount
+                                                  enumVerifier:enumVerifier];
+  // Set the extra info.
+  descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
+  return descriptor;
+}
+
+- (instancetype)initWithName:(NSString *)name
+                  valueNames:(const char *)valueNames
+                      values:(const int32_t *)values
+                       count:(uint32_t)valueCount
+                enumVerifier:(GPBEnumValidationFunc)enumVerifier {
+  if ((self = [super init])) {
+    name_ = [name copy];
+    valueNames_ = valueNames;
+    values_ = values;
+    valueCount_ = valueCount;
+    enumVerifier_ = enumVerifier;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [name_ release];
+  if (nameOffsets_) free(nameOffsets_);
+  [super dealloc];
+}
+
+- (void)calcValueNameOffsets {
+  @synchronized(self) {
+    if (nameOffsets_ != NULL) {
+      return;
+    }
+    uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
+    const char *scan = valueNames_;
+    for (uint32_t i = 0; i < valueCount_; ++i) {
+      offsets[i] = (uint32_t)(scan - valueNames_);
+      while (*scan != '\0') ++scan;
+      ++scan;  // Step over the null.
+    }
+    nameOffsets_ = offsets;
+  }
+}
+
+- (NSString *)enumNameForValue:(int32_t)number {
+  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
+
+  for (uint32_t i = 0; i < valueCount_; ++i) {
+    if (values_[i] == number) {
+      const char *valueName = valueNames_ + nameOffsets_[i];
+      NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
+      return fullName;
+    }
+  }
+  return nil;
+}
+
+- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
+  // Must have the prefix.
+  NSUInteger prefixLen = name_.length + 1;
+  if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
+      ([name characterAtIndex:prefixLen - 1] != '_')) {
+    return NO;
+  }
+
+  // Skip over the prefix.
+  const char *nameAsCStr = [name UTF8String];
+  nameAsCStr += prefixLen;
+
+  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
+
+  // Find it.
+  for (uint32_t i = 0; i < valueCount_; ++i) {
+    const char *valueName = valueNames_ + nameOffsets_[i];
+    if (strcmp(nameAsCStr, valueName) == 0) {
+      if (outValue) {
+        *outValue = values_[i];
+      }
+      return YES;
+    }
+  }
+  return NO;
+}
+
+- (NSString *)textFormatNameForValue:(int32_t)number {
+  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
+
+  // Find the EnumValue descriptor and its index.
+  BOOL foundIt = NO;
+  uint32_t valueDescriptorIndex;
+  for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_;
+       ++valueDescriptorIndex) {
+    if (values_[valueDescriptorIndex] == number) {
+      foundIt = YES;
+      break;
+    }
+  }
+
+  if (!foundIt) {
+    return nil;
+  }
+
+  NSString *result = nil;
+  // Naming adds an underscore between enum name and value name, skip that also.
+  const char *valueName = valueNames_ + nameOffsets_[valueDescriptorIndex];
+  NSString *shortName = @(valueName);
+
+  // See if it is in the map of special format handling.
+  if (extraTextFormatInfo_) {
+    result = GPBDecodeTextFormatName(extraTextFormatInfo_,
+                                     (int32_t)valueDescriptorIndex, shortName);
+  }
+  // Logic here needs to match what objectivec_enum.cc does in the proto
+  // compiler.
+  if (result == nil) {
+    NSUInteger len = [shortName length];
+    NSMutableString *worker = [NSMutableString stringWithCapacity:len];
+    for (NSUInteger i = 0; i < len; i++) {
+      unichar c = [shortName characterAtIndex:i];
+      if (i > 0 && c >= 'A' && c <= 'Z') {
+        [worker appendString:@"_"];
+      }
+      [worker appendFormat:@"%c", toupper((char)c)];
+    }
+    result = worker;
+  }
+  return result;
+}
+
+@end
+
+@implementation GPBExtensionDescriptor {
+  GPBGenericValue defaultValue_;
+}
+
+@synthesize containingMessageClass = containingMessageClass_;
+
+- (instancetype)initWithExtensionDescription:
+        (GPBExtensionDescription *)description {
+  if ((self = [super init])) {
+    description_ = description;
+
+#if DEBUG
+    const char *className = description->messageOrGroupClassName;
+    if (className) {
+      NSAssert(objc_lookUpClass(className) != Nil,
+               @"Class %s not defined", className);
+    }
+#endif
+
+    if (description->extendedClass) {
+      Class containingClass = objc_lookUpClass(description->extendedClass);
+      NSAssert(containingClass, @"Class %s not defined",
+               description->extendedClass);
+      containingMessageClass_ = containingClass;
+    }
+
+    GPBDataType type = description_->dataType;
+    if (type == GPBDataTypeBytes) {
+      // Data stored as a length prefixed c-string in descriptor records.
+      const uint8_t *bytes =
+          (const uint8_t *)description->defaultValue.valueData;
+      if (bytes) {
+        uint32_t length = *((uint32_t *)bytes);
+        // The length is stored in network byte order.
+        length = ntohl(length);
+        bytes += sizeof(length);
+        defaultValue_.valueData =
+            [[NSData alloc] initWithBytes:bytes length:length];
+      }
+    } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
+      // The default is looked up in -defaultValue instead since extensions
+      // aren't common, we avoid the hit startup hit and it avoid initialization
+      // order issues.
+    } else {
+      defaultValue_ = description->defaultValue;
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if ((description_->dataType == GPBDataTypeBytes) &&
+      !GPBExtensionIsRepeated(description_)) {
+    [defaultValue_.valueData release];
+  }
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+#pragma unused(zone)
+  // Immutable.
+  return [self retain];
+}
+
+- (NSString *)singletonName {
+  return @(description_->singletonName);
+}
+
+- (const char *)singletonNameC {
+  return description_->singletonName;
+}
+
+- (uint32_t)fieldNumber {
+  return description_->fieldNumber;
+}
+
+- (GPBDataType)dataType {
+  return description_->dataType;
+}
+
+- (GPBWireFormat)wireType {
+  return GPBWireFormatForType(description_->dataType,
+                              GPBExtensionIsPacked(description_));
+}
+
+- (GPBWireFormat)alternateWireType {
+  NSAssert(GPBExtensionIsRepeated(description_),
+           @"Only valid on repeated extensions");
+  return GPBWireFormatForType(description_->dataType,
+                              !GPBExtensionIsPacked(description_));
+}
+
+- (BOOL)isRepeated {
+  return GPBExtensionIsRepeated(description_);
+}
+
+- (BOOL)isMap {
+  return (description_->options & GPBFieldMapKeyMask) != 0;
+}
+
+- (BOOL)isPackable {
+  return GPBExtensionIsPacked(description_);
+}
+
+- (Class)msgClass {
+  return objc_getClass(description_->messageOrGroupClassName);
+}
+
+- (GPBEnumDescriptor *)enumDescriptor {
+  if (description_->dataType == GPBDataTypeEnum) {
+    GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
+    return enumDescriptor;
+  }
+  return nil;
+}
+
+- (id)defaultValue {
+  if (GPBExtensionIsRepeated(description_)) {
+    return nil;
+  }
+
+  switch (description_->dataType) {
+    case GPBDataTypeBool:
+      return @(defaultValue_.valueBool);
+    case GPBDataTypeFloat:
+      return @(defaultValue_.valueFloat);
+    case GPBDataTypeDouble:
+      return @(defaultValue_.valueDouble);
+    case GPBDataTypeInt32:
+    case GPBDataTypeSInt32:
+    case GPBDataTypeEnum:
+    case GPBDataTypeSFixed32:
+      return @(defaultValue_.valueInt32);
+    case GPBDataTypeInt64:
+    case GPBDataTypeSInt64:
+    case GPBDataTypeSFixed64:
+      return @(defaultValue_.valueInt64);
+    case GPBDataTypeUInt32:
+    case GPBDataTypeFixed32:
+      return @(defaultValue_.valueUInt32);
+    case GPBDataTypeUInt64:
+    case GPBDataTypeFixed64:
+      return @(defaultValue_.valueUInt64);
+    case GPBDataTypeBytes:
+      // Like message fields, the default is zero length data.
+      return (defaultValue_.valueData ? defaultValue_.valueData
+                                      : GPBEmptyNSData());
+    case GPBDataTypeString:
+      // Like message fields, the default is zero length string.
+      return (defaultValue_.valueString ? defaultValue_.valueString : @"");
+    case GPBDataTypeGroup:
+    case GPBDataTypeMessage:
+      return nil;
+  }
+}
+
+- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
+  int32_t selfNumber = description_->fieldNumber;
+  int32_t otherNumber = other->description_->fieldNumber;
+  if (selfNumber < otherNumber) {
+    return NSOrderedAscending;
+  } else if (selfNumber == otherNumber) {
+    return NSOrderedSame;
+  } else {
+    return NSOrderedDescending;
+  }
+}
+
+@end
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
new file mode 100644
index 0000000..e3d0a80
--- /dev/null
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -0,0 +1,313 @@
+// 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.
+
+// This header is private to the ProtobolBuffers library and must NOT be
+// included by any sources outside this library. The contents of this file are
+// subject to change at any time without notice.
+
+#import "GPBDescriptor.h"
+#import "GPBWireFormat.h"
+
+// Describes attributes of the field.
+typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
+  // These map to standard protobuf concepts.
+  GPBFieldRequired        = 1 << 0,
+  GPBFieldRepeated        = 1 << 1,
+  GPBFieldPacked          = 1 << 2,
+  GPBFieldOptional        = 1 << 3,
+  GPBFieldHasDefaultValue = 1 << 4,
+
+  // Indicates the field needs custom handling for the TextFormat name, if not
+  // set, the name can be derived from the ObjC name.
+  GPBFieldTextFormatNameCustom = 1 << 6,
+  // Indicates the field has an enum descriptor.
+  GPBFieldHasEnumDescriptor = 1 << 7,
+
+  // These are not standard protobuf concepts, they are specific to the
+  // Objective C runtime.
+
+  // These bits are used to mark the field as a map and what the key
+  // type is.
+  GPBFieldMapKeyMask     = 0xF << 8,
+  GPBFieldMapKeyInt32    =  1 << 8,
+  GPBFieldMapKeyInt64    =  2 << 8,
+  GPBFieldMapKeyUInt32   =  3 << 8,
+  GPBFieldMapKeyUInt64   =  4 << 8,
+  GPBFieldMapKeySInt32   =  5 << 8,
+  GPBFieldMapKeySInt64   =  6 << 8,
+  GPBFieldMapKeyFixed32  =  7 << 8,
+  GPBFieldMapKeyFixed64  =  8 << 8,
+  GPBFieldMapKeySFixed32 =  9 << 8,
+  GPBFieldMapKeySFixed64 = 10 << 8,
+  GPBFieldMapKeyBool     = 11 << 8,
+  GPBFieldMapKeyString   = 12 << 8,
+};
+
+// NOTE: The structures defined here have their members ordered to minimize
+// their size. This directly impacts the size of apps since these exist per
+// field/extension.
+
+// Describes a single field in a protobuf as it is represented as an ivar.
+typedef struct GPBMessageFieldDescription {
+  // Name of ivar.
+  const char *name;
+  union {
+    const char *className;  // Name for message class.
+    // For enums only: If EnumDescriptors are compiled in, it will be that,
+    // otherwise it will be the verifier.
+    GPBEnumDescriptorFunc enumDescFunc;
+    GPBEnumValidationFunc enumVerifier;
+  } dataTypeSpecific;
+  // The field number for the ivar.
+  uint32_t number;
+  // The index (in bits) into _has_storage_.
+  //   >= 0: the bit to use for a value being set.
+  //   = GPBNoHasBit(INT32_MAX): no storage used.
+  //   < 0: in a oneOf, use a full int32 to record the field active.
+  int32_t hasIndex;
+  // Offset of the variable into it's structure struct.
+  uint32_t offset;
+  // Field flags. Use accessor functions below.
+  GPBFieldFlags flags;
+  // Data type of the ivar.
+  GPBDataType dataType;
+} GPBMessageFieldDescription;
+
+// Fields in messages defined in a 'proto2' syntax file can provide a default
+// value. This struct provides the default along with the field info.
+typedef struct GPBMessageFieldDescriptionWithDefault {
+  // Default value for the ivar.
+  GPBGenericValue defaultValue;
+
+  GPBMessageFieldDescription core;
+} GPBMessageFieldDescriptionWithDefault;
+
+// Describes attributes of the extension.
+typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) {
+  // These map to standard protobuf concepts.
+  GPBExtensionRepeated      = 1 << 0,
+  GPBExtensionPacked        = 1 << 1,
+  GPBExtensionSetWireFormat = 1 << 2,
+};
+
+// An extension
+typedef struct GPBExtensionDescription {
+  GPBGenericValue defaultValue;
+  const char *singletonName;
+  const char *extendedClass;
+  const char *messageOrGroupClassName;
+  GPBEnumDescriptorFunc enumDescriptorFunc;
+  int32_t fieldNumber;
+  GPBDataType dataType;
+  GPBExtensionOptions options;
+} GPBExtensionDescription;
+
+typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
+  GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0,
+  GPBDescriptorInitializationFlag_WireFormat        = 1 << 1,
+};
+
+@interface GPBDescriptor () {
+ @package
+  NSArray *fields_;
+  NSArray *oneofs_;
+  uint32_t storageSize_;
+}
+
+// fieldDescriptions have to be long lived, they are held as raw pointers.
++ (instancetype)
+    allocDescriptorForClass:(Class)messageClass
+                  rootClass:(Class)rootClass
+                       file:(GPBFileDescriptor *)file
+                     fields:(void *)fieldDescriptions
+                 fieldCount:(uint32_t)fieldCount
+                storageSize:(uint32_t)storageSize
+                      flags:(GPBDescriptorInitializationFlags)flags;
+
+- (instancetype)initWithClass:(Class)messageClass
+                         file:(GPBFileDescriptor *)file
+                       fields:(NSArray *)fields
+                  storageSize:(uint32_t)storage
+                   wireFormat:(BOOL)wireFormat;
+
+// Called right after init to provide extra information to avoid init having
+// an explosion of args. These pointers are recorded, so they are expected
+// to live for the lifetime of the app.
+- (void)setupOneofs:(const char **)oneofNames
+              count:(uint32_t)count
+      firstHasIndex:(int32_t)firstHasIndex;
+- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
+- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+
+@end
+
+@interface GPBFileDescriptor ()
+- (instancetype)initWithPackage:(NSString *)package
+                         syntax:(GPBFileSyntax)syntax;
+@end
+
+@interface GPBOneofDescriptor () {
+ @package
+  const char *name_;
+  NSArray *fields_;
+  SEL caseSel_;
+}
+// name must be long lived.
+- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields;
+@end
+
+@interface GPBFieldDescriptor () {
+ @package
+  GPBMessageFieldDescription *description_;
+  GPB_UNSAFE_UNRETAINED GPBOneofDescriptor *containingOneof_;
+
+  SEL getSel_;
+  SEL setSel_;
+  SEL hasOrCountSel_;  // *Count for map<>/repeated fields, has* otherwise.
+  SEL setHasSel_;
+}
+
+// Single initializer
+// description has to be long lived, it is held as a raw pointer.
+- (instancetype)initWithFieldDescription:(void *)description
+                         includesDefault:(BOOL)includesDefault
+                                  syntax:(GPBFileSyntax)syntax;
+@end
+
+@interface GPBEnumDescriptor ()
+// valueNames, values and extraTextFormatInfo have to be long lived, they are
+// held as raw pointers.
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                valueNames:(const char *)valueNames
+                    values:(const int32_t *)values
+                     count:(uint32_t)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier;
++ (instancetype)
+    allocDescriptorForName:(NSString *)name
+                valueNames:(const char *)valueNames
+                    values:(const int32_t *)values
+                     count:(uint32_t)valueCount
+              enumVerifier:(GPBEnumValidationFunc)enumVerifier
+       extraTextFormatInfo:(const char *)extraTextFormatInfo;
+
+- (instancetype)initWithName:(NSString *)name
+                  valueNames:(const char *)valueNames
+                      values:(const int32_t *)values
+                       count:(uint32_t)valueCount
+                enumVerifier:(GPBEnumValidationFunc)enumVerifier;
+@end
+
+@interface GPBExtensionDescriptor () {
+ @package
+  GPBExtensionDescription *description_;
+}
+@property(nonatomic, readonly) GPBWireFormat wireType;
+
+// For repeated extensions, alternateWireType is the wireType with the opposite
+// value for the packable property.  i.e. - if the extension was marked packed
+// it would be the wire type for unpacked; if the extension was marked unpacked,
+// it would be the wire type for packed.
+@property(nonatomic, readonly) GPBWireFormat alternateWireType;
+
+// description has to be long lived, it is held as a raw pointer.
+- (instancetype)initWithExtensionDescription:
+    (GPBExtensionDescription *)description;
+- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other;
+@end
+
+CF_EXTERN_C_BEGIN
+
+GPB_INLINE BOOL GPBFieldIsMapOrArray(GPBFieldDescriptor *field) {
+  return (field->description_->flags &
+          (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0;
+}
+
+GPB_INLINE GPBDataType GPBGetFieldDataType(GPBFieldDescriptor *field) {
+  return field->description_->dataType;
+}
+
+GPB_INLINE int32_t GPBFieldHasIndex(GPBFieldDescriptor *field) {
+  return field->description_->hasIndex;
+}
+
+GPB_INLINE uint32_t GPBFieldNumber(GPBFieldDescriptor *field) {
+  return field->description_->number;
+}
+
+uint32_t GPBFieldTag(GPBFieldDescriptor *self);
+
+// For repeated fields, alternateWireType is the wireType with the opposite
+// value for the packable property.  i.e. - if the field was marked packed it
+// would be the wire type for unpacked; if the field was marked unpacked, it
+// would be the wire type for packed.
+uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self);
+
+GPB_INLINE BOOL GPBPreserveUnknownFields(GPBFileSyntax syntax) {
+  return syntax != GPBFileSyntaxProto3;
+}
+
+GPB_INLINE BOOL GPBHasPreservingUnknownEnumSemantics(GPBFileSyntax syntax) {
+  return syntax == GPBFileSyntaxProto3;
+}
+
+GPB_INLINE BOOL GPBExtensionIsRepeated(GPBExtensionDescription *description) {
+  return (description->options & GPBExtensionRepeated) != 0;
+}
+
+GPB_INLINE BOOL GPBExtensionIsPacked(GPBExtensionDescription *description) {
+  return (description->options & GPBExtensionPacked) != 0;
+}
+
+GPB_INLINE BOOL GPBExtensionIsWireFormat(GPBExtensionDescription *description) {
+  return (description->options & GPBExtensionSetWireFormat) != 0;
+}
+
+// Helper for compile time assets.
+#ifndef _GPBCompileAssert
+  #if __has_feature(c_static_assert) || __has_extension(c_static_assert)
+    #define _GPBCompileAssert(test, msg) _Static_assert((test), #msg)
+  #else
+    // Pre-Xcode 7 support.
+    #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg
+    #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg)
+    #define _GPBCompileAssert(test, msg) \
+        typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
+  #endif  // __has_feature(c_static_assert) || __has_extension(c_static_assert)
+#endif // _GPBCompileAssert
+
+// Sanity check that there isn't padding between the field description
+// structures with and without a default.
+_GPBCompileAssert(sizeof(GPBMessageFieldDescriptionWithDefault) ==
+                  (sizeof(GPBGenericValue) +
+                   sizeof(GPBMessageFieldDescription)),
+                  DescriptionsWithDefault_different_size_than_expected);
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBDictionary.h b/objectivec/GPBDictionary.h
new file mode 100644
index 0000000..3120814
--- /dev/null
+++ b/objectivec/GPBDictionary.h
@@ -0,0 +1,2243 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRuntimeTypes.h"
+
+// These classes are used for map fields of basic data types. They are used because
+// they perform better than boxing into NSNumbers in NSDictionaries.
+
+// Note: These are not meant to be subclassed.
+
+NS_ASSUME_NONNULL_BEGIN
+
+//%PDDM-EXPAND DECLARE_DICTIONARIES()
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt32 -> UInt32
+
+@interface GPBUInt32UInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Int32
+
+@interface GPBUInt32Int32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32Int32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> UInt64
+
+@interface GPBUInt32UInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Int64
+
+@interface GPBUInt32Int64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32Int64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Bool
+
+@interface GPBUInt32BoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32BoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Float
+
+@interface GPBUInt32FloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32FloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Double
+
+@interface GPBUInt32DoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32DoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(uint32_t)key;
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Enum
+
+@interface GPBUInt32EnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(uint32_t)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const uint32_t [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32EnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const uint32_t [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32EnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(uint32_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(uint32_t)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(uint32_t)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(uint32_t)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt32 -> Object
+
+@interface GPBUInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(uint32_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint32_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (ObjectType)objectForKey:(uint32_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint32_t key, ObjectType object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(ObjectType)object forKey:(uint32_t)key;
+
+- (void)removeObjectForKey:(uint32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> UInt32
+
+@interface GPBInt32UInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32UInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Int32
+
+@interface GPBInt32Int32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32Int32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> UInt64
+
+@interface GPBInt32UInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32UInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Int64
+
+@interface GPBInt32Int64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32Int64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Bool
+
+@interface GPBInt32BoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32BoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Float
+
+@interface GPBInt32FloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32FloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Double
+
+@interface GPBInt32DoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(int32_t)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32DoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(int32_t)key;
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Enum
+
+@interface GPBInt32EnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(int32_t)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const int32_t [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32EnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const int32_t [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32EnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(int32_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(int32_t)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(int32_t key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(int32_t)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(int32_t)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int32 -> Object
+
+@interface GPBInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(int32_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int32_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (ObjectType)objectForKey:(int32_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int32_t key, ObjectType object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(ObjectType)object forKey:(int32_t)key;
+
+- (void)removeObjectForKey:(int32_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> UInt32
+
+@interface GPBUInt64UInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Int32
+
+@interface GPBUInt64Int32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64Int32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> UInt64
+
+@interface GPBUInt64UInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Int64
+
+@interface GPBUInt64Int64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64Int64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Bool
+
+@interface GPBUInt64BoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64BoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Float
+
+@interface GPBUInt64FloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64FloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Double
+
+@interface GPBUInt64DoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64DoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(uint64_t)key;
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Enum
+
+@interface GPBUInt64EnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(uint64_t)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const uint64_t [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64EnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const uint64_t [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64EnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(uint64_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(uint64_t)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(uint64_t)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(uint64_t)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - UInt64 -> Object
+
+@interface GPBUInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(uint64_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint64_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (ObjectType)objectForKey:(uint64_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint64_t key, ObjectType object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(ObjectType)object forKey:(uint64_t)key;
+
+- (void)removeObjectForKey:(uint64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> UInt32
+
+@interface GPBInt64UInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64UInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Int32
+
+@interface GPBInt64Int32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64Int32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> UInt64
+
+@interface GPBInt64UInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64UInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Int64
+
+@interface GPBInt64Int64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64Int64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Bool
+
+@interface GPBInt64BoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64BoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Float
+
+@interface GPBInt64FloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64FloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Double
+
+@interface GPBInt64DoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(int64_t)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64DoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(int64_t)key;
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Enum
+
+@interface GPBInt64EnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(int64_t)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const int64_t [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64EnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const int64_t [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64EnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(int64_t)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(int64_t)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(int64_t key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(int64_t)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(int64_t)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Int64 -> Object
+
+@interface GPBInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(int64_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int64_t [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (ObjectType)objectForKey:(int64_t)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int64_t key, ObjectType object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary;
+
+- (void)setObject:(ObjectType)object forKey:(int64_t)key;
+
+- (void)removeObjectForKey:(int64_t)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> UInt32
+
+@interface GPBBoolUInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolUInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolUInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Int32
+
+@interface GPBBoolInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> UInt64
+
+@interface GPBBoolUInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolUInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolUInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Int64
+
+@interface GPBBoolInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Bool
+
+@interface GPBBoolBoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolBoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolBoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Float
+
+@interface GPBBoolFloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolFloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolFloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Double
+
+@interface GPBBoolDoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(BOOL)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolDoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolDoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(BOOL)key;
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Enum
+
+@interface GPBBoolEnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(BOOL)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const BOOL [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolEnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const BOOL [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolEnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(BOOL)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(BOOL)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(BOOL key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBBoolEnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(BOOL)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - Bool -> Object
+
+@interface GPBBoolObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(BOOL)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const BOOL [])keys
+                                count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const BOOL [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (ObjectType)objectForKey:(BOOL)key;
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(BOOL key, ObjectType object, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary;
+
+- (void)setObject:(ObjectType)object forKey:(BOOL)key;
+
+- (void)removeObjectForKey:(BOOL)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> UInt32
+
+@interface GPBStringUInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringUInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable uint32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, uint32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(uint32_t)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Int32
+
+@interface GPBStringInt32Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringInt32Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int32_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary;
+
+- (void)setValue:(int32_t)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> UInt64
+
+@interface GPBStringUInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringUInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable uint64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, uint64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(uint64_t)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Int64
+
+@interface GPBStringInt64Dictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringInt64Dictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable int64_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int64_t value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary;
+
+- (void)setValue:(int64_t)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Bool
+
+@interface GPBStringBoolDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringBoolDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable BOOL *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, BOOL value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary;
+
+- (void)setValue:(BOOL)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Float
+
+@interface GPBStringFloatDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringFloatDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable float *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, float value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary;
+
+- (void)setValue:(float)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Double
+
+@interface GPBStringDoubleDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(NSString *)key;
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary;
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringDoubleDictionary *)dictionary;
+- (instancetype)initWithCapacity:(NSUInteger)numItems;
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable double *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, double value, BOOL *stop))block;
+
+- (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary;
+
+- (void)setValue:(double)value forKey:(NSString *)key;
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+#pragma mark - String -> Enum
+
+@interface GPBStringEnumDictionary : NSObject <NSCopying>
+
+@property(nonatomic, readonly) NSUInteger count;
+@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+
++ (instancetype)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(NSString *)key;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                                           count:(NSUInteger)count;
++ (instancetype)dictionaryWithDictionary:(GPBStringEnumDictionary *)dictionary;
++ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems;
+
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])values
+                                   forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
+                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDictionary:(GPBStringEnumDictionary *)dictionary;
+- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems;
+
+// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+// is not a valid enumerator as defined by validationFunc. If the actual value is
+// desired, use "raw" version of the method.
+
+- (BOOL)valueForKey:(NSString *)key value:(nullable int32_t *)value;
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int32_t value, BOOL *stop))block;
+
+// These methods bypass the validationFunc to provide access to values that were not
+// known at the time the binary was compiled.
+
+- (BOOL)valueForKey:(NSString *)key rawValue:(nullable int32_t *)rawValue;
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(NSString *key, int32_t rawValue, BOOL *stop))block;
+
+- (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary;
+
+// If value is not a valid enumerator as defined by validationFunc, these
+// methods will assert in debug, and will log in release and assign the value
+// to the default value. Use the rawValue methods below to assign non enumerator
+// values.
+
+- (void)setValue:(int32_t)value forKey:(NSString *)key;
+
+// This method bypass the validationFunc to provide setting of values that were not
+// known at the time the binary was compiled.
+- (void)setRawValue:(int32_t)rawValue forKey:(NSString *)key;
+
+// No validation applies to these methods.
+
+- (void)removeValueForKey:(NSString *)aKey;
+- (void)removeAll;
+
+@end
+
+//%PDDM-EXPAND-END DECLARE_DICTIONARIES()
+
+NS_ASSUME_NONNULL_END
+
+//%PDDM-DEFINE DECLARE_DICTIONARIES()
+//%DICTIONARY_INTERFACES_FOR_POD_KEY(UInt32, uint32_t)
+//%DICTIONARY_INTERFACES_FOR_POD_KEY(Int32, int32_t)
+//%DICTIONARY_INTERFACES_FOR_POD_KEY(UInt64, uint64_t)
+//%DICTIONARY_INTERFACES_FOR_POD_KEY(Int64, int64_t)
+//%DICTIONARY_INTERFACES_FOR_POD_KEY(Bool, BOOL)
+//%DICTIONARY_POD_INTERFACES_FOR_KEY(String, NSString, *, OBJECT)
+//%PDDM-DEFINE DICTIONARY_INTERFACES_FOR_POD_KEY(KEY_NAME, KEY_TYPE)
+//%DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, , POD)
+//%DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, Object, ObjectType)
+//%PDDM-DEFINE DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, KisP, KHELPER)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, UInt32, uint32_t)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Int32, int32_t)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, UInt64, uint64_t)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Int64, int64_t)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Bool, BOOL)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Float, float)
+//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Double, double)
+//%DICTIONARY_KEY_TO_ENUM_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Enum, int32_t)
+//%PDDM-DEFINE DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, POD, value)
+//%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, , POD, VALUE_NAME, VALUE_TYPE, OBJECT, object)
+//%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE)
+//%- (BOOL)valueForKey:(KEY_TYPE)key value:(nullable VALUE_TYPE *)value;
+//%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_TYPE)
+//%- (VALUE_TYPE)objectForKey:(KEY_TYPE)key;
+//%PDDM-DEFINE VALUE_FOR_KEY_Enum(KEY_TYPE, VALUE_TYPE)
+//%VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE)
+//%PDDM-DEFINE ARRAY_ARG_MODIFIERPOD()
+// Nothing
+//%PDDM-DEFINE ARRAY_ARG_MODIFIEREnum()
+// Nothing
+//%PDDM-DEFINE ARRAY_ARG_MODIFIEROBJECT()
+//%GPB_UNSAFE_UNRETAINED ##
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLPOD(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLEnum(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLOBJECT(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary<__covariant VALUE_TYPE>
+//%PDDM-DEFINE DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@interface DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) : NSObject <NSCopying>
+//%
+//%@property(nonatomic, readonly) NSUInteger count;
+//%
+//%+ (instancetype)dictionary;
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)##VNAME
+//%                       ##VNAME$S## forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count;
+//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
+//%
+//%- (instancetype)initWith##VNAME$u##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME##s
+//%                ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                ##VNAME$S##    count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%- (instancetype)initWithCapacity:(NSUInteger)numItems;
+//%
+//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%
+//%- (void)addEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary;
+//%
+//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_KEY_TO_ENUM_INTERFACE2(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, Enum)
+//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_INTERFACE2(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : NSObject <NSCopying>
+//%
+//%@property(nonatomic, readonly) NSUInteger count;
+//%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
+//%
+//%+ (instancetype)dictionary;
+//%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                        rawValue:(VALUE_TYPE)rawValue
+//%                                          forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                       rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values
+//%                                         forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                                           count:(NSUInteger)count;
+//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                        capacity:(NSUInteger)numItems;
+//%
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                 rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values
+//%                                   forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
+//%                                  capacity:(NSUInteger)numItems;
+//%
+//%// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
+//%// is not a valid enumerator as defined by validationFunc. If the actual value is
+//%// desired, use "raw" version of the method.
+//%
+//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, value)
+//%
+//%// These methods bypass the validationFunc to provide access to values that were not
+//%// known at the time the binary was compiled.
+//%
+//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key rawValue:(nullable VALUE_TYPE *)rawValue;
+//%
+//%- (void)enumerateKeysAndRawValuesUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE rawValue, BOOL *stop))block;
+//%
+//%- (void)addRawEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary;
+//%
+//%// If value is not a valid enumerator as defined by validationFunc, these
+//%// methods will assert in debug, and will log in release and assign the value
+//%// to the default value. Use the rawValue methods below to assign non enumerator
+//%// values.
+//%
+//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, value)
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_TYPE)
+//%
+//%- (void)enumerateKeysAnd##VNAME$u##sUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop))block;
+
+//%PDDM-DEFINE DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%- (void)set##VNAME$u##:(VALUE_TYPE)##VNAME forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%DICTIONARY_EXTRA_MUTABLE_METHODS_##VHELPER(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
+//%- (void)remove##VNAME$u##ForKey:(KEY_TYPE##KisP$S##KisP)aKey;
+//%- (void)removeAll;
+
+//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_POD(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
+// Empty
+//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_OBJECT(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
+// Empty
+//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_Enum(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
+//%
+//%// This method bypass the validationFunc to provide setting of values that were not
+//%// known at the time the binary was compiled.
+//%- (void)setRawValue:(VALUE_TYPE)rawValue forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%
+//%// No validation applies to these methods.
+//%
diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m
new file mode 100644
index 0000000..3bd146e
--- /dev/null
+++ b/objectivec/GPBDictionary.m
@@ -0,0 +1,13555 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBDictionary_PackagePrivate.h"
+
+#import "GPBCodedInputStream_PackagePrivate.h"
+#import "GPBCodedOutputStream_PackagePrivate.h"
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+// ------------------------------ NOTE ------------------------------
+// At the moment, this is all using NSNumbers in NSDictionaries under
+// the hood, but it is all hidden so we can come back and optimize
+// with direct CFDictionary usage later.  The reason that wasn't
+// done yet is needing to support 32bit iOS builds.  Otherwise
+// it would be pretty simple to store all this data in CFDictionaries
+// directly.
+// ------------------------------------------------------------------
+
+// Used to include code only visible to specific versions of the static
+// analyzer. Useful for wrapping code that only exists to silence the analyzer.
+// Determine the values you want to use for BEGIN_APPLE_BUILD_VERSION,
+// END_APPLE_BUILD_VERSION using:
+//   xcrun clang -dM -E -x c /dev/null | grep __apple_build_version__
+// Example usage:
+//  #if GPB_STATIC_ANALYZER_ONLY(5621, 5623) ... #endif
+#define GPB_STATIC_ANALYZER_ONLY(BEGIN_APPLE_BUILD_VERSION, END_APPLE_BUILD_VERSION) \
+    (defined(__clang_analyzer__) && \
+     (__apple_build_version__ >= BEGIN_APPLE_BUILD_VERSION && \
+      __apple_build_version__ <= END_APPLE_BUILD_VERSION))
+
+enum {
+  kMapKeyFieldNumber = 1,
+  kMapValueFieldNumber = 2,
+};
+
+static BOOL DictDefault_IsValidValue(int32_t value) {
+  // Anything but the bad value marker is allowed.
+  return (value != kGPBUnrecognizedEnumeratorValue);
+}
+
+//%PDDM-DEFINE SERIALIZE_SUPPORT_2_TYPE(VALUE_NAME, VALUE_TYPE, GPBDATATYPE_NAME1, GPBDATATYPE_NAME2)
+//%static size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBDataType dataType) {
+//%  if (dataType == GPBDataType##GPBDATATYPE_NAME1) {
+//%    return GPBCompute##GPBDATATYPE_NAME1##Size(fieldNum, value);
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME2) {
+//%    return GPBCompute##GPBDATATYPE_NAME2##Size(fieldNum, value);
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", dataType);
+//%    return 0;
+//%  }
+//%}
+//%
+//%static void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBDataType dataType) {
+//%  if (dataType == GPBDataType##GPBDATATYPE_NAME1) {
+//%    [stream write##GPBDATATYPE_NAME1##:fieldNum value:value];
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME2) {
+//%    [stream write##GPBDATATYPE_NAME2##:fieldNum value:value];
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", dataType);
+//%  }
+//%}
+//%
+//%PDDM-DEFINE SERIALIZE_SUPPORT_3_TYPE(VALUE_NAME, VALUE_TYPE, GPBDATATYPE_NAME1, GPBDATATYPE_NAME2, GPBDATATYPE_NAME3)
+//%static size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBDataType dataType) {
+//%  if (dataType == GPBDataType##GPBDATATYPE_NAME1) {
+//%    return GPBCompute##GPBDATATYPE_NAME1##Size(fieldNum, value);
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME2) {
+//%    return GPBCompute##GPBDATATYPE_NAME2##Size(fieldNum, value);
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME3) {
+//%    return GPBCompute##GPBDATATYPE_NAME3##Size(fieldNum, value);
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", dataType);
+//%    return 0;
+//%  }
+//%}
+//%
+//%static void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBDataType dataType) {
+//%  if (dataType == GPBDataType##GPBDATATYPE_NAME1) {
+//%    [stream write##GPBDATATYPE_NAME1##:fieldNum value:value];
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME2) {
+//%    [stream write##GPBDATATYPE_NAME2##:fieldNum value:value];
+//%  } else if (dataType == GPBDataType##GPBDATATYPE_NAME3) {
+//%    [stream write##GPBDATATYPE_NAME3##:fieldNum value:value];
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", dataType);
+//%  }
+//%}
+//%
+//%PDDM-DEFINE SIMPLE_SERIALIZE_SUPPORT(VALUE_NAME, VALUE_TYPE, VisP)
+//%static size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE VisP##value, uint32_t fieldNum, GPBDataType dataType) {
+//%  NSCAssert(dataType == GPBDataType##VALUE_NAME, @"bad type: %d", dataType);
+//%  #pragma unused(dataType)  // For when asserts are off in release.
+//%  return GPBCompute##VALUE_NAME##Size(fieldNum, value);
+//%}
+//%
+//%static void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE VisP##value, uint32_t fieldNum, GPBDataType dataType) {
+//%  NSCAssert(dataType == GPBDataType##VALUE_NAME, @"bad type: %d", dataType);
+//%  #pragma unused(dataType)  // For when asserts are off in release.
+//%  [stream write##VALUE_NAME##:fieldNum value:value];
+//%}
+//%
+//%PDDM-DEFINE SERIALIZE_SUPPORT_HELPERS()
+//%SERIALIZE_SUPPORT_3_TYPE(Int32, int32_t, Int32, SInt32, SFixed32)
+//%SERIALIZE_SUPPORT_2_TYPE(UInt32, uint32_t, UInt32, Fixed32)
+//%SERIALIZE_SUPPORT_3_TYPE(Int64, int64_t, Int64, SInt64, SFixed64)
+//%SERIALIZE_SUPPORT_2_TYPE(UInt64, uint64_t, UInt64, Fixed64)
+//%SIMPLE_SERIALIZE_SUPPORT(Bool, BOOL, )
+//%SIMPLE_SERIALIZE_SUPPORT(Enum, int32_t, )
+//%SIMPLE_SERIALIZE_SUPPORT(Float, float, )
+//%SIMPLE_SERIALIZE_SUPPORT(Double, double, )
+//%SIMPLE_SERIALIZE_SUPPORT(String, NSString, *)
+//%SERIALIZE_SUPPORT_3_TYPE(Object, id, Message, String, Bytes)
+//%PDDM-EXPAND SERIALIZE_SUPPORT_HELPERS()
+// This block of code is generated, do not edit it directly.
+
+static size_t ComputeDictInt32FieldSize(int32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeInt32) {
+    return GPBComputeInt32Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeSInt32) {
+    return GPBComputeSInt32Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeSFixed32) {
+    return GPBComputeSFixed32Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+    return 0;
+  }
+}
+
+static void WriteDictInt32Field(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeInt32) {
+    [stream writeInt32:fieldNum value:value];
+  } else if (dataType == GPBDataTypeSInt32) {
+    [stream writeSInt32:fieldNum value:value];
+  } else if (dataType == GPBDataTypeSFixed32) {
+    [stream writeSFixed32:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+  }
+}
+
+static size_t ComputeDictUInt32FieldSize(uint32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeUInt32) {
+    return GPBComputeUInt32Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeFixed32) {
+    return GPBComputeFixed32Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+    return 0;
+  }
+}
+
+static void WriteDictUInt32Field(GPBCodedOutputStream *stream, uint32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeUInt32) {
+    [stream writeUInt32:fieldNum value:value];
+  } else if (dataType == GPBDataTypeFixed32) {
+    [stream writeFixed32:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+  }
+}
+
+static size_t ComputeDictInt64FieldSize(int64_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeInt64) {
+    return GPBComputeInt64Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeSInt64) {
+    return GPBComputeSInt64Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeSFixed64) {
+    return GPBComputeSFixed64Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+    return 0;
+  }
+}
+
+static void WriteDictInt64Field(GPBCodedOutputStream *stream, int64_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeInt64) {
+    [stream writeInt64:fieldNum value:value];
+  } else if (dataType == GPBDataTypeSInt64) {
+    [stream writeSInt64:fieldNum value:value];
+  } else if (dataType == GPBDataTypeSFixed64) {
+    [stream writeSFixed64:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+  }
+}
+
+static size_t ComputeDictUInt64FieldSize(uint64_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeUInt64) {
+    return GPBComputeUInt64Size(fieldNum, value);
+  } else if (dataType == GPBDataTypeFixed64) {
+    return GPBComputeFixed64Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+    return 0;
+  }
+}
+
+static void WriteDictUInt64Field(GPBCodedOutputStream *stream, uint64_t value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeUInt64) {
+    [stream writeUInt64:fieldNum value:value];
+  } else if (dataType == GPBDataTypeFixed64) {
+    [stream writeFixed64:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+  }
+}
+
+static size_t ComputeDictBoolFieldSize(BOOL value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeBool, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  return GPBComputeBoolSize(fieldNum, value);
+}
+
+static void WriteDictBoolField(GPBCodedOutputStream *stream, BOOL value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeBool, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  [stream writeBool:fieldNum value:value];
+}
+
+static size_t ComputeDictEnumFieldSize(int32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeEnum, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  return GPBComputeEnumSize(fieldNum, value);
+}
+
+static void WriteDictEnumField(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeEnum, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  [stream writeEnum:fieldNum value:value];
+}
+
+static size_t ComputeDictFloatFieldSize(float value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeFloat, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  return GPBComputeFloatSize(fieldNum, value);
+}
+
+static void WriteDictFloatField(GPBCodedOutputStream *stream, float value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeFloat, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  [stream writeFloat:fieldNum value:value];
+}
+
+static size_t ComputeDictDoubleFieldSize(double value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeDouble, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  return GPBComputeDoubleSize(fieldNum, value);
+}
+
+static void WriteDictDoubleField(GPBCodedOutputStream *stream, double value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeDouble, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  [stream writeDouble:fieldNum value:value];
+}
+
+static size_t ComputeDictStringFieldSize(NSString *value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeString, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  return GPBComputeStringSize(fieldNum, value);
+}
+
+static void WriteDictStringField(GPBCodedOutputStream *stream, NSString *value, uint32_t fieldNum, GPBDataType dataType) {
+  NSCAssert(dataType == GPBDataTypeString, @"bad type: %d", dataType);
+  #pragma unused(dataType)  // For when asserts are off in release.
+  [stream writeString:fieldNum value:value];
+}
+
+static size_t ComputeDictObjectFieldSize(id value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeMessage) {
+    return GPBComputeMessageSize(fieldNum, value);
+  } else if (dataType == GPBDataTypeString) {
+    return GPBComputeStringSize(fieldNum, value);
+  } else if (dataType == GPBDataTypeBytes) {
+    return GPBComputeBytesSize(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+    return 0;
+  }
+}
+
+static void WriteDictObjectField(GPBCodedOutputStream *stream, id value, uint32_t fieldNum, GPBDataType dataType) {
+  if (dataType == GPBDataTypeMessage) {
+    [stream writeMessage:fieldNum value:value];
+  } else if (dataType == GPBDataTypeString) {
+    [stream writeString:fieldNum value:value];
+  } else if (dataType == GPBDataTypeBytes) {
+    [stream writeBytes:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", dataType);
+  }
+}
+
+//%PDDM-EXPAND-END SERIALIZE_SUPPORT_HELPERS()
+
+size_t GPBDictionaryComputeSizeInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) {
+  GPBDataType mapValueType = GPBGetFieldDataType(field);
+  __block size_t result = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = GPBComputeStringSize(kMapKeyFieldNumber, key);
+    msgSize += ComputeDictObjectFieldSize(obj, kMapValueFieldNumber, mapValueType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * dict.count;
+  return result;
+}
+
+void GPBDictionaryWriteToStreamInternalHelper(GPBCodedOutputStream *outputStream,
+                                              NSDictionary *dict,
+                                              GPBFieldDescriptor *field) {
+  NSCAssert(field.mapKeyDataType == GPBDataTypeString, @"Unexpected key type");
+  GPBDataType mapValueType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = GPBComputeStringSize(kMapKeyFieldNumber, key);
+    msgSize += ComputeDictObjectFieldSize(obj, kMapValueFieldNumber, mapValueType);
+
+    // Write the size and fields.
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    [outputStream writeString:kMapKeyFieldNumber value:key];
+    WriteDictObjectField(outputStream, obj, kMapValueFieldNumber, mapValueType);
+  }];
+}
+
+BOOL GPBDictionaryIsInitializedInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) {
+  NSCAssert(field.mapKeyDataType == GPBDataTypeString, @"Unexpected key type");
+  NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeMessage, @"Unexpected value type");
+  #pragma unused(field)  // For when asserts are off in release.
+  for (GPBMessage *msg in [dict objectEnumerator]) {
+    if (!msg.initialized) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+// Note: if the type is an object, it the retain pass back to the caller.
+static void ReadValue(GPBCodedInputStream *stream,
+                      GPBGenericValue *valueToFill,
+                      GPBDataType type,
+                      GPBExtensionRegistry *registry,
+                      GPBFieldDescriptor *field) {
+  switch (type) {
+    case GPBDataTypeBool:
+      valueToFill->valueBool = GPBCodedInputStreamReadBool(&stream->state_);
+      break;
+    case GPBDataTypeFixed32:
+      valueToFill->valueUInt32 = GPBCodedInputStreamReadFixed32(&stream->state_);
+      break;
+    case GPBDataTypeSFixed32:
+      valueToFill->valueInt32 = GPBCodedInputStreamReadSFixed32(&stream->state_);
+      break;
+    case GPBDataTypeFloat:
+      valueToFill->valueFloat = GPBCodedInputStreamReadFloat(&stream->state_);
+      break;
+    case GPBDataTypeFixed64:
+      valueToFill->valueUInt64 = GPBCodedInputStreamReadFixed64(&stream->state_);
+      break;
+    case GPBDataTypeSFixed64:
+      valueToFill->valueInt64 = GPBCodedInputStreamReadSFixed64(&stream->state_);
+      break;
+    case GPBDataTypeDouble:
+      valueToFill->valueDouble = GPBCodedInputStreamReadDouble(&stream->state_);
+      break;
+    case GPBDataTypeInt32:
+      valueToFill->valueInt32 = GPBCodedInputStreamReadInt32(&stream->state_);
+      break;
+    case GPBDataTypeInt64:
+      valueToFill->valueInt64 = GPBCodedInputStreamReadInt32(&stream->state_);
+      break;
+    case GPBDataTypeSInt32:
+      valueToFill->valueInt32 = GPBCodedInputStreamReadSInt32(&stream->state_);
+      break;
+    case GPBDataTypeSInt64:
+      valueToFill->valueInt64 = GPBCodedInputStreamReadSInt64(&stream->state_);
+      break;
+    case GPBDataTypeUInt32:
+      valueToFill->valueUInt32 = GPBCodedInputStreamReadUInt32(&stream->state_);
+      break;
+    case GPBDataTypeUInt64:
+      valueToFill->valueUInt64 = GPBCodedInputStreamReadUInt64(&stream->state_);
+      break;
+    case GPBDataTypeBytes:
+      [valueToFill->valueData release];
+      valueToFill->valueData = GPBCodedInputStreamReadRetainedBytes(&stream->state_);
+      break;
+    case GPBDataTypeString:
+      [valueToFill->valueString release];
+      valueToFill->valueString = GPBCodedInputStreamReadRetainedString(&stream->state_);
+      break;
+    case GPBDataTypeMessage: {
+      GPBMessage *message = [[field.msgClass alloc] init];
+      [stream readMessage:message extensionRegistry:registry];
+      [valueToFill->valueMessage release];
+      valueToFill->valueMessage = message;
+      break;
+    }
+    case GPBDataTypeGroup:
+      NSCAssert(NO, @"Can't happen");
+      break;
+    case GPBDataTypeEnum:
+      valueToFill->valueEnum = GPBCodedInputStreamReadEnum(&stream->state_);
+      break;
+  }
+}
+
+void GPBDictionaryReadEntry(id mapDictionary,
+                            GPBCodedInputStream *stream,
+                            GPBExtensionRegistry *registry,
+                            GPBFieldDescriptor *field,
+                            GPBMessage *parentMessage) {
+  GPBDataType keyDataType = field.mapKeyDataType;
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+
+  GPBGenericValue key;
+  GPBGenericValue value;
+  // Zero them (but pick up any enum default for proto2).
+  key.valueString = value.valueString = nil;
+  if (valueDataType == GPBDataTypeEnum) {
+    value = field.defaultValue;
+  }
+
+  GPBCodedInputStreamState *state = &stream->state_;
+  uint32_t keyTag =
+      GPBWireFormatMakeTag(kMapKeyFieldNumber, GPBWireFormatForType(keyDataType, NO));
+  uint32_t valueTag =
+      GPBWireFormatMakeTag(kMapValueFieldNumber, GPBWireFormatForType(valueDataType, NO));
+
+  BOOL hitError = NO;
+  while (YES) {
+    uint32_t tag = GPBCodedInputStreamReadTag(state);
+    if (tag == keyTag) {
+      ReadValue(stream, &key, keyDataType, registry, field);
+    } else if (tag == valueTag) {
+      ReadValue(stream, &value, valueDataType, registry, field);
+    } else if (tag == 0) {
+      // zero signals EOF / limit reached
+      break;
+    } else {  // Unknown
+      if (![stream skipField:tag]){
+        hitError = YES;
+        break;
+      }
+    }
+  }
+
+  if (!hitError) {
+    // Handle the special defaults and/or missing key/value.
+    if ((keyDataType == GPBDataTypeString) && (key.valueString == nil)) {
+      key.valueString = [@"" retain];
+    }
+    if (GPBDataTypeIsObject(valueDataType) && value.valueString == nil) {
+      switch (valueDataType) {
+        case GPBDataTypeString:
+          value.valueString = [@"" retain];
+          break;
+        case GPBDataTypeBytes:
+          value.valueData = [GPBEmptyNSData() retain];
+          break;
+#if defined(__clang_analyzer__)
+        case GPBDataTypeGroup:
+          // Maps can't really have Groups as the value type, but this case is needed
+          // so the analyzer won't report the posibility of send nil in for the value
+          // in the NSMutableDictionary case below.
+#endif
+        case GPBDataTypeMessage: {
+          value.valueMessage = [[field.msgClass alloc] init];
+          break;
+        }
+        default:
+          // Nothing
+          break;
+      }
+    }
+
+    if ((keyDataType == GPBDataTypeString) && GPBDataTypeIsObject(valueDataType)) {
+#if GPB_STATIC_ANALYZER_ONLY(6020053, 7000181)
+     // Limited to Xcode 6.4 - 7.2, are known to fail here. The upper end can
+     // be raised as needed for new Xcodes.
+     //
+     // This is only needed on a "shallow" analyze; on a "deep" analyze, the
+     // existing code path gets this correct. In shallow, the analyzer decides
+     // GPBDataTypeIsObject(valueDataType) is both false and true on a single
+     // path through this function, allowing nil to be used for the
+     // setObject:forKey:.
+     if (value.valueString == nil) {
+       value.valueString = [@"" retain];
+     }
+#endif
+      // mapDictionary is an NSMutableDictionary
+      [(NSMutableDictionary *)mapDictionary setObject:value.valueString
+                                               forKey:key.valueString];
+    } else {
+      if (valueDataType == GPBDataTypeEnum) {
+        if (GPBHasPreservingUnknownEnumSemantics([parentMessage descriptor].file.syntax) ||
+            [field isValidEnumValue:value.valueEnum]) {
+          [mapDictionary setGPBGenericValue:&value forGPBGenericValueKey:&key];
+        } else {
+          NSData *data = [mapDictionary serializedDataForUnknownValue:value.valueEnum
+                                                               forKey:&key
+                                                          keyDataType:keyDataType];
+          [parentMessage addUnknownMapEntry:GPBFieldNumber(field) value:data];
+        }
+      } else {
+        [mapDictionary setGPBGenericValue:&value forGPBGenericValueKey:&key];
+      }
+    }
+  }
+
+  if (GPBDataTypeIsObject(keyDataType)) {
+    [key.valueString release];
+  }
+  if (GPBDataTypeIsObject(valueDataType)) {
+    [value.valueString release];
+  }
+}
+
+//
+// Macros for the common basic cases.
+//
+
+//%PDDM-DEFINE DICTIONARY_IMPL_FOR_POD_KEY(KEY_NAME, KEY_TYPE)
+//%DICTIONARY_POD_IMPL_FOR_KEY(KEY_NAME, KEY_TYPE, , POD)
+//%DICTIONARY_POD_KEY_TO_OBJECT_IMPL(KEY_NAME, KEY_TYPE, Object, id)
+
+//%PDDM-DEFINE DICTIONARY_POD_IMPL_FOR_KEY(KEY_NAME, KEY_TYPE, KisP, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, UInt32, uint32_t, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Int32, int32_t, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, UInt64, uint64_t, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Int64, int64_t, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Bool, BOOL, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Float, float, KHELPER)
+//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Double, double, KHELPER)
+//%DICTIONARY_KEY_TO_ENUM_IMPL(KEY_NAME, KEY_TYPE, KisP, Enum, int32_t, KHELPER)
+
+//%PDDM-DEFINE DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER)
+//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD, value)
+
+//%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_IMPL(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, , VALUE_NAME, VALUE_TYPE, POD, OBJECT, object)
+
+//%PDDM-DEFINE DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@implementation GPB##KEY_NAME##VALUE_NAME##Dictionary {
+//% @package
+//%  NSMutableDictionary *_dictionary;
+//%}
+//%
+//%+ (instancetype)dictionary {
+//%  return [[[self alloc] initWith##VNAME$u##s:NULL forKeys:NULL count:0] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)##VNAME
+//%                      ##VNAME$S##  forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:&##VNAME
+//%               KEY_NAME$S VALUE_NAME$S                        ##VNAME$S##  forKeys:&key
+//%               KEY_NAME$S VALUE_NAME$S                        ##VNAME$S##    count:1] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:##VNAME##s
+//%               KEY_NAME$S VALUE_NAME$S                               forKeys:keys
+//%               KEY_NAME$S VALUE_NAME$S                                 count:count] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+//%  return [[[self alloc] initWithCapacity:numItems] autorelease];
+//%}
+//%
+//%- (instancetype)init {
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
+//%}
+//%
+//%- (instancetype)initWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                ##VNAME$S##    count:(NSUInteger)count {
+//%  self = [super init];
+//%  if (self) {
+//%    _dictionary = [[NSMutableDictionary alloc] init];
+//%    if (count && VNAME##s && keys) {
+//%      for (NSUInteger i = 0; i < count; ++i) {
+//%DICTIONARY_VALIDATE_VALUE_##VHELPER(VNAME##s[i], ______)##DICTIONARY_VALIDATE_KEY_##KHELPER(keys[i], ______)        [_dictionary setObject:WRAPPED##VHELPER(VNAME##s[i]) forKey:WRAPPED##KHELPER(keys[i])];
+//%      }
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
+//%  self = [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
+//%  if (self) {
+//%    if (dictionary) {
+//%      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithCapacity:(NSUInteger)numItems {
+//%  #pragma unused(numItems)
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
+//%}
+//%
+//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, )
+//%
+//%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_NAME, VALUE_TYPE, KHELPER)
+//%
+//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, )
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER)
+//%DICTIONARY_KEY_TO_ENUM_IMPL2(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD)
+//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_IMPL2(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@implementation GPB##KEY_NAME##VALUE_NAME##Dictionary {
+//% @package
+//%  NSMutableDictionary *_dictionary;
+//%  GPBEnumValidationFunc _validationFunc;
+//%}
+//%
+//%@synthesize validationFunc = _validationFunc;
+//%
+//%+ (instancetype)dictionary {
+//%  return [[[self alloc] initWithValidationFunction:NULL
+//%                                         rawValues:NULL
+//%                                           forKeys:NULL
+//%                                             count:0] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+//%  return [[[self alloc] initWithValidationFunction:func
+//%                                         rawValues:NULL
+//%                                           forKeys:NULL
+//%                                             count:0] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+//%                                        rawValue:(VALUE_TYPE)rawValue
+//%                                          forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValidationFunction:func
+//%               KEY_NAME$S VALUE_NAME$S                                         rawValues:&rawValue
+//%               KEY_NAME$S VALUE_NAME$S                                           forKeys:&key
+//%               KEY_NAME$S VALUE_NAME$S                                             count:1] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+//%                                       rawValues:(const VALUE_TYPE [])rawValues
+//%                                         forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                                           count:(NSUInteger)count {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValidationFunction:func
+//%               KEY_NAME$S VALUE_NAME$S                                         rawValues:rawValues
+//%               KEY_NAME$S VALUE_NAME$S                                           forKeys:keys
+//%               KEY_NAME$S VALUE_NAME$S                                             count:count] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+//%                                        capacity:(NSUInteger)numItems {
+//%  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+//%}
+//%
+//%- (instancetype)init {
+//%  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+//%}
+//%
+//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+//%  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+//%}
+//%
+//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+//%                                 rawValues:(const VALUE_TYPE [])rawValues
+//%                                   forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                                     count:(NSUInteger)count {
+//%  self = [super init];
+//%  if (self) {
+//%    _dictionary = [[NSMutableDictionary alloc] init];
+//%    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+//%    if (count && rawValues && keys) {
+//%      for (NSUInteger i = 0; i < count; ++i) {
+//%DICTIONARY_VALIDATE_KEY_##KHELPER(keys[i], ______)        [_dictionary setObject:WRAPPED##VHELPER(rawValues[i]) forKey:WRAPPED##KHELPER(keys[i])];
+//%      }
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
+//%  self = [self initWithValidationFunction:dictionary.validationFunc
+//%                                rawValues:NULL
+//%                                  forKeys:NULL
+//%                                    count:0];
+//%  if (self) {
+//%    if (dictionary) {
+//%      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+//%                                  capacity:(NSUInteger)numItems {
+//%  #pragma unused(numItems)
+//%  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+//%}
+//%
+//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, value, Raw)
+//%
+//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key value:(VALUE_TYPE *)value {
+//%  NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
+//%  if (wrapped && value) {
+//%    VALUE_TYPE result = UNWRAP##VALUE_NAME(wrapped);
+//%    if (!_validationFunc(result)) {
+//%      result = kGPBUnrecognizedEnumeratorValue;
+//%    }
+//%    *value = result;
+//%  }
+//%  return (wrapped != NULL);
+//%}
+//%
+//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key rawValue:(VALUE_TYPE *)rawValue {
+//%  NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
+//%  if (wrapped && rawValue) {
+//%    *rawValue = UNWRAP##VALUE_NAME(wrapped);
+//%  }
+//%  return (wrapped != NULL);
+//%}
+//%
+//%- (void)enumerateKeysAndValuesUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block {
+//%  GPBEnumValidationFunc func = _validationFunc;
+//%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue,
+//%                                                   BOOL *stop) {
+//%      VALUE_TYPE unwrapped = UNWRAP##VALUE_NAME(aValue);
+//%      if (!func(unwrapped)) {
+//%        unwrapped = kGPBUnrecognizedEnumeratorValue;
+//%      }
+//%      block(UNWRAP##KEY_NAME(aKey), unwrapped, stop);
+//%  }];
+//%}
+//%
+//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, value, Raw)
+//%
+//%- (void)setValue:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%DICTIONARY_VALIDATE_KEY_##KHELPER(key, )  if (!_validationFunc(value)) {
+//%    [NSException raise:NSInvalidArgumentException
+//%                format:@"GPB##KEY_NAME##VALUE_NAME##Dictionary: Attempt to set an unknown enum value (%d)",
+//%                       value];
+//%  }
+//%
+//%  [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, ACCESSOR_NAME)
+//%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
+//%  [_dictionary release];
+//%  [super dealloc];
+//%}
+//%
+//%- (instancetype)copyWithZone:(NSZone *)zone {
+//%  return [[GPB##KEY_NAME##VALUE_NAME##Dictionary allocWithZone:zone] initWithDictionary:self];
+//%}
+//%
+//%- (BOOL)isEqual:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)other {
+//%  if (self == other) {
+//%    return YES;
+//%  }
+//%  if (![other isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]) {
+//%    return NO;
+//%  }
+//%  return [_dictionary isEqual:other->_dictionary];
+//%}
+//%
+//%- (NSUInteger)hash {
+//%  return _dictionary.count;
+//%}
+//%
+//%- (NSString *)description {
+//%  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+//%}
+//%
+//%- (NSUInteger)count {
+//%  return _dictionary.count;
+//%}
+//%
+//%- (void)enumerateKeysAnd##ACCESSOR_NAME##VNAME$u##sUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop))block {
+//%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u,
+//%                                                   BOOL *stop) {
+//%      block(UNWRAP##KEY_NAME(aKey), UNWRAP##VALUE_NAME(a##VNAME$u), stop);
+//%  }];
+//%}
+//%
+//%EXTRA_METHODS_##VHELPER(KEY_NAME, VALUE_NAME)- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+//%  NSUInteger count = _dictionary.count;
+//%  if (count == 0) {
+//%    return 0;
+//%  }
+//%
+//%  GPBDataType valueDataType = GPBGetFieldDataType(field);
+//%  GPBDataType keyDataType = field.mapKeyDataType;
+//%  __block size_t result = 0;
+//%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u##,
+//%                                                   BOOL *stop) {
+//%    #pragma unused(stop)
+//%    size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
+//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
+//%    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+//%  }];
+//%  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+//%  result += tagSize * count;
+//%  return result;
+//%}
+//%
+//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+//%                         asField:(GPBFieldDescriptor *)field {
+//%  GPBDataType valueDataType = GPBGetFieldDataType(field);
+//%  GPBDataType keyDataType = field.mapKeyDataType;
+//%  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+//%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u,
+//%                                                   BOOL *stop) {
+//%    #pragma unused(stop)
+//%    // Write the tag.
+//%    [outputStream writeInt32NoTag:tag];
+//%    // Write the size of the message.
+//%    size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
+//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
+//%    [outputStream writeInt32NoTag:(int32_t)msgSize];
+//%    // Write the fields.
+//%    WriteDict##KEY_NAME##Field(outputStream, UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
+//%    WriteDict##VALUE_NAME##Field(outputStream, UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
+//%  }];
+//%}
+//%
+//%SERIAL_DATA_FOR_ENTRY_##VHELPER(KEY_NAME, VALUE_NAME)- (void)setGPBGenericValue:(GPBGenericValue *)value
+//%     forGPBGenericValueKey:(GPBGenericValue *)key {
+//%  [_dictionary setObject:WRAPPED##VHELPER(value->##GPBVALUE_##VHELPER(VALUE_NAME)##) forKey:WRAPPED##KHELPER(key->value##KEY_NAME)];
+//%}
+//%
+//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+//%  [self enumerateKeysAnd##ACCESSOR_NAME##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop) {
+//%      #pragma unused(stop)
+//%      block(TEXT_FORMAT_OBJ##KEY_NAME(key), TEXT_FORMAT_OBJ##VALUE_NAME(VNAME));
+//%  }];
+//%}
+//%PDDM-DEFINE DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, ACCESSOR_NAME)
+//%- (void)add##ACCESSOR_NAME##EntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary {
+//%  if (otherDictionary) {
+//%    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
+//%  }
+//%}
+//%
+//%- (void)set##ACCESSOR_NAME##VNAME$u##:(VALUE_TYPE)VNAME forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%DICTIONARY_VALIDATE_VALUE_##VHELPER(VNAME, )##DICTIONARY_VALIDATE_KEY_##KHELPER(key, )  [_dictionary setObject:WRAPPED##VHELPER(VNAME) forKey:WRAPPED##KHELPER(key)];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%- (void)remove##VNAME$u##ForKey:(KEY_TYPE##KisP$S##KisP)aKey {
+//%  [_dictionary removeObjectForKey:WRAPPED##KHELPER(aKey)];
+//%}
+//%
+//%- (void)removeAll {
+//%  [_dictionary removeAllObjects];
+//%}
+
+//
+// Custom Generation for Bool keys
+//
+
+//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_POD_IMPL(VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, POD, value)
+//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_OBJECT_IMPL(VALUE_NAME, VALUE_TYPE)
+//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, OBJECT, object)
+
+//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, HELPER, VNAME)
+//%#pragma mark - Bool -> VALUE_NAME
+//%
+//%@implementation GPBBool##VALUE_NAME##Dictionary {
+//% @package
+//%  VALUE_TYPE _values[2];
+//%BOOL_DICT_HAS_STORAGE_##HELPER()}
+//%
+//%+ (instancetype)dictionary {
+//%  return [[[self alloc] initWith##VNAME$u##s:NULL forKeys:NULL count:0] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)VNAME
+//%                      ##VNAME$S##  forKey:(BOOL)key {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:&##VNAME
+//%                    VALUE_NAME$S                        ##VNAME$S##  forKeys:&key
+//%                    VALUE_NAME$S                        ##VNAME$S##    count:1] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const BOOL [])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
+//%  // on to get the type correct.
+//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:##VNAME##s
+//%                    VALUE_NAME$S                        ##VNAME$S##  forKeys:keys
+//%                    VALUE_NAME$S                        ##VNAME$S##    count:count] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary {
+//%  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+//%  // on to get the type correct.
+//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+//%}
+//%
+//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+//%  return [[[self alloc] initWithCapacity:numItems] autorelease];
+//%}
+//%
+//%- (instancetype)init {
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
+//%}
+//%
+//%BOOL_DICT_INITS_##HELPER(VALUE_NAME, VALUE_TYPE)
+//%
+//%- (instancetype)initWithCapacity:(NSUInteger)numItems {
+//%  #pragma unused(numItems)
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
+//%}
+//%
+//%BOOL_DICT_DEALLOC##HELPER()
+//%
+//%- (instancetype)copyWithZone:(NSZone *)zone {
+//%  return [[GPBBool##VALUE_NAME##Dictionary allocWithZone:zone] initWithDictionary:self];
+//%}
+//%
+//%- (BOOL)isEqual:(GPBBool##VALUE_NAME##Dictionary *)other {
+//%  if (self == other) {
+//%    return YES;
+//%  }
+//%  if (![other isKindOfClass:[GPBBool##VALUE_NAME##Dictionary class]]) {
+//%    return NO;
+//%  }
+//%  if ((BOOL_DICT_W_HAS##HELPER(0, ) != BOOL_DICT_W_HAS##HELPER(0, other->)) ||
+//%      (BOOL_DICT_W_HAS##HELPER(1, ) != BOOL_DICT_W_HAS##HELPER(1, other->))) {
+//%    return NO;
+//%  }
+//%  if ((BOOL_DICT_W_HAS##HELPER(0, ) && (NEQ_##HELPER(_values[0], other->_values[0]))) ||
+//%      (BOOL_DICT_W_HAS##HELPER(1, ) && (NEQ_##HELPER(_values[1], other->_values[1])))) {
+//%    return NO;
+//%  }
+//%  return YES;
+//%}
+//%
+//%- (NSUInteger)hash {
+//%  return (BOOL_DICT_W_HAS##HELPER(0, ) ? 1 : 0) + (BOOL_DICT_W_HAS##HELPER(1, ) ? 1 : 0);
+//%}
+//%
+//%- (NSString *)description {
+//%  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+//%  if (BOOL_DICT_W_HAS##HELPER(0, )) {
+//%    [result appendFormat:@"NO: STR_FORMAT_##HELPER(VALUE_NAME)", _values[0]];
+//%  }
+//%  if (BOOL_DICT_W_HAS##HELPER(1, )) {
+//%    [result appendFormat:@"YES: STR_FORMAT_##HELPER(VALUE_NAME)", _values[1]];
+//%  }
+//%  [result appendString:@" }"];
+//%  return result;
+//%}
+//%
+//%- (NSUInteger)count {
+//%  return (BOOL_DICT_W_HAS##HELPER(0, ) ? 1 : 0) + (BOOL_DICT_W_HAS##HELPER(1, ) ? 1 : 0);
+//%}
+//%
+//%BOOL_VALUE_FOR_KEY_##HELPER(VALUE_TYPE)
+//%
+//%BOOL_SET_GPBVALUE_FOR_KEY_##HELPER(VALUE_NAME, VALUE_TYPE, VisP)
+//%
+//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+//%  if (BOOL_DICT_HAS##HELPER(0, )) {
+//%    block(@"false", TEXT_FORMAT_OBJ##VALUE_NAME(_values[0]));
+//%  }
+//%  if (BOOL_DICT_W_HAS##HELPER(1, )) {
+//%    block(@"true", TEXT_FORMAT_OBJ##VALUE_NAME(_values[1]));
+//%  }
+//%}
+//%
+//%- (void)enumerateKeysAnd##VNAME$u##sUsingBlock:
+//%    (void (^)(BOOL key, VALUE_TYPE VNAME, BOOL *stop))block {
+//%  BOOL stop = NO;
+//%  if (BOOL_DICT_HAS##HELPER(0, )) {
+//%    block(NO, _values[0], &stop);
+//%  }
+//%  if (!stop && BOOL_DICT_W_HAS##HELPER(1, )) {
+//%    block(YES, _values[1], &stop);
+//%  }
+//%}
+//%
+//%BOOL_EXTRA_METHODS_##HELPER(Bool, VALUE_NAME)- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+//%  GPBDataType valueDataType = GPBGetFieldDataType(field);
+//%  NSUInteger count = 0;
+//%  size_t result = 0;
+//%  for (int i = 0; i < 2; ++i) {
+//%    if (BOOL_DICT_HAS##HELPER(i, )) {
+//%      ++count;
+//%      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+//%      msgSize += ComputeDict##VALUE_NAME##FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+//%      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+//%    }
+//%  }
+//%  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+//%  result += tagSize * count;
+//%  return result;
+//%}
+//%
+//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+//%                         asField:(GPBFieldDescriptor *)field {
+//%  GPBDataType valueDataType = GPBGetFieldDataType(field);
+//%  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+//%  for (int i = 0; i < 2; ++i) {
+//%    if (BOOL_DICT_HAS##HELPER(i, )) {
+//%      // Write the tag.
+//%      [outputStream writeInt32NoTag:tag];
+//%      // Write the size of the message.
+//%      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+//%      msgSize += ComputeDict##VALUE_NAME##FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+//%      [outputStream writeInt32NoTag:(int32_t)msgSize];
+//%      // Write the fields.
+//%      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+//%      WriteDict##VALUE_NAME##Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+//%    }
+//%  }
+//%}
+//%
+//%BOOL_DICT_MUTATIONS_##HELPER(VALUE_NAME, VALUE_TYPE)
+//%
+//%@end
+//%
+
+
+//
+// Helpers for PODs
+//
+
+//%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_NAME, VALUE_TYPE, KHELPER)
+//%- (BOOL)valueForKey:(KEY_TYPE)key value:(VALUE_TYPE *)value {
+//%  NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
+//%  if (wrapped && value) {
+//%    *value = UNWRAP##VALUE_NAME(wrapped);
+//%  }
+//%  return (wrapped != NULL);
+//%}
+//%PDDM-DEFINE WRAPPEDPOD(VALUE)
+//%@(VALUE)
+//%PDDM-DEFINE UNWRAPUInt32(VALUE)
+//%[VALUE unsignedIntValue]
+//%PDDM-DEFINE UNWRAPInt32(VALUE)
+//%[VALUE intValue]
+//%PDDM-DEFINE UNWRAPUInt64(VALUE)
+//%[VALUE unsignedLongLongValue]
+//%PDDM-DEFINE UNWRAPInt64(VALUE)
+//%[VALUE longLongValue]
+//%PDDM-DEFINE UNWRAPBool(VALUE)
+//%[VALUE boolValue]
+//%PDDM-DEFINE UNWRAPFloat(VALUE)
+//%[VALUE floatValue]
+//%PDDM-DEFINE UNWRAPDouble(VALUE)
+//%[VALUE doubleValue]
+//%PDDM-DEFINE UNWRAPEnum(VALUE)
+//%[VALUE intValue]
+//%PDDM-DEFINE TEXT_FORMAT_OBJUInt32(VALUE)
+//%[NSString stringWithFormat:@"%u", VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJInt32(VALUE)
+//%[NSString stringWithFormat:@"%d", VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJUInt64(VALUE)
+//%[NSString stringWithFormat:@"%llu", VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJInt64(VALUE)
+//%[NSString stringWithFormat:@"%lld", VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJBool(VALUE)
+//%(VALUE ? @"true" : @"false")
+//%PDDM-DEFINE TEXT_FORMAT_OBJFloat(VALUE)
+//%[NSString stringWithFormat:@"%.*g", FLT_DIG, VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJDouble(VALUE)
+//%[NSString stringWithFormat:@"%.*lg", DBL_DIG, VALUE]
+//%PDDM-DEFINE TEXT_FORMAT_OBJEnum(VALUE)
+//%@(VALUE)
+//%PDDM-DEFINE ENUM_TYPEPOD(TYPE)
+//%NSNumber *
+//%PDDM-DEFINE NEQ_POD(VAL1, VAL2)
+//%VAL1 != VAL2
+//%PDDM-DEFINE EXTRA_METHODS_POD(KEY_NAME, VALUE_NAME)
+// Empty
+//%PDDM-DEFINE BOOL_EXTRA_METHODS_POD(KEY_NAME, VALUE_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD(KEY_NAME, VALUE_NAME)
+//%SERIAL_DATA_FOR_ENTRY_POD_##VALUE_NAME(KEY_NAME)
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_UInt32(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Int32(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_UInt64(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Int64(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Bool(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Float(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Double(KEY_NAME)
+// Empty
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Enum(KEY_NAME)
+//%- (NSData *)serializedDataForUnknownValue:(int32_t)value
+//%                                   forKey:(GPBGenericValue *)key
+//%                              keyDataType:(GPBDataType)keyDataType {
+//%  size_t msgSize = ComputeDict##KEY_NAME##FieldSize(key->value##KEY_NAME, kMapKeyFieldNumber, keyDataType);
+//%  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+//%  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+//%  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+//%  WriteDict##KEY_NAME##Field(outputStream, key->value##KEY_NAME, kMapKeyFieldNumber, keyDataType);
+//%  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+//%  [outputStream release];
+//%  return data;
+//%}
+//%
+//%PDDM-DEFINE GPBVALUE_POD(VALUE_NAME)
+//%value##VALUE_NAME
+//%PDDM-DEFINE DICTIONARY_VALIDATE_VALUE_POD(VALUE_NAME, EXTRA_INDENT)
+// Empty
+//%PDDM-DEFINE DICTIONARY_VALIDATE_KEY_POD(KEY_NAME, EXTRA_INDENT)
+// Empty
+
+//%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_POD()
+//%  BOOL _valueSet[2];
+//%
+//%PDDM-DEFINE BOOL_DICT_INITS_POD(VALUE_NAME, VALUE_TYPE)
+//%- (instancetype)initWithValues:(const VALUE_TYPE [])values
+//%                       forKeys:(const BOOL [])keys
+//%                         count:(NSUInteger)count {
+//%  self = [super init];
+//%  if (self) {
+//%    for (NSUInteger i = 0; i < count; ++i) {
+//%      int idx = keys[i] ? 1 : 0;
+//%      _values[idx] = values[i];
+//%      _valueSet[idx] = YES;
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary {
+//%  self = [self initWithValues:NULL forKeys:NULL count:0];
+//%  if (self) {
+//%    if (dictionary) {
+//%      for (int i = 0; i < 2; ++i) {
+//%        if (dictionary->_valueSet[i]) {
+//%          _values[i] = dictionary->_values[i];
+//%          _valueSet[i] = YES;
+//%        }
+//%      }
+//%    }
+//%  }
+//%  return self;
+//%}
+//%PDDM-DEFINE BOOL_DICT_DEALLOCPOD()
+//%#if !defined(NS_BLOCK_ASSERTIONS)
+//%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
+//%  [super dealloc];
+//%}
+//%#endif  // !defined(NS_BLOCK_ASSERTIONS)
+//%PDDM-DEFINE BOOL_DICT_W_HASPOD(IDX, REF)
+//%BOOL_DICT_HASPOD(IDX, REF)
+//%PDDM-DEFINE BOOL_DICT_HASPOD(IDX, REF)
+//%REF##_valueSet[IDX]
+//%PDDM-DEFINE BOOL_VALUE_FOR_KEY_POD(VALUE_TYPE)
+//%- (BOOL)valueForKey:(BOOL)key value:(VALUE_TYPE *)value {
+//%  int idx = (key ? 1 : 0);
+//%  if (_valueSet[idx]) {
+//%    if (value) {
+//%      *value = _values[idx];
+//%    }
+//%    return YES;
+//%  }
+//%  return NO;
+//%}
+//%PDDM-DEFINE BOOL_SET_GPBVALUE_FOR_KEY_POD(VALUE_NAME, VALUE_TYPE, VisP)
+//%- (void)setGPBGenericValue:(GPBGenericValue *)value
+//%     forGPBGenericValueKey:(GPBGenericValue *)key {
+//%  int idx = (key->valueBool ? 1 : 0);
+//%  _values[idx] = value->value##VALUE_NAME;
+//%  _valueSet[idx] = YES;
+//%}
+//%PDDM-DEFINE BOOL_DICT_MUTATIONS_POD(VALUE_NAME, VALUE_TYPE)
+//%- (void)addEntriesFromDictionary:(GPBBool##VALUE_NAME##Dictionary *)otherDictionary {
+//%  if (otherDictionary) {
+//%    for (int i = 0; i < 2; ++i) {
+//%      if (otherDictionary->_valueSet[i]) {
+//%        _valueSet[i] = YES;
+//%        _values[i] = otherDictionary->_values[i];
+//%      }
+//%    }
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
+//%  }
+//%}
+//%
+//%- (void)setValue:(VALUE_TYPE)value forKey:(BOOL)key {
+//%  int idx = (key ? 1 : 0);
+//%  _values[idx] = value;
+//%  _valueSet[idx] = YES;
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%- (void)removeValueForKey:(BOOL)aKey {
+//%  _valueSet[aKey ? 1 : 0] = NO;
+//%}
+//%
+//%- (void)removeAll {
+//%  _valueSet[0] = NO;
+//%  _valueSet[1] = NO;
+//%}
+//%PDDM-DEFINE STR_FORMAT_POD(VALUE_NAME)
+//%STR_FORMAT_##VALUE_NAME()
+//%PDDM-DEFINE STR_FORMAT_UInt32()
+//%%u
+//%PDDM-DEFINE STR_FORMAT_Int32()
+//%%d
+//%PDDM-DEFINE STR_FORMAT_UInt64()
+//%%llu
+//%PDDM-DEFINE STR_FORMAT_Int64()
+//%%lld
+//%PDDM-DEFINE STR_FORMAT_Bool()
+//%%d
+//%PDDM-DEFINE STR_FORMAT_Float()
+//%%f
+//%PDDM-DEFINE STR_FORMAT_Double()
+//%%lf
+
+//
+// Helpers for Objects
+//
+
+//%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_NAME, VALUE_TYPE, KHELPER)
+//%- (VALUE_TYPE)objectForKey:(KEY_TYPE)key {
+//%  VALUE_TYPE result = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
+//%  return result;
+//%}
+//%PDDM-DEFINE WRAPPEDOBJECT(VALUE)
+//%VALUE
+//%PDDM-DEFINE UNWRAPString(VALUE)
+//%VALUE
+//%PDDM-DEFINE UNWRAPObject(VALUE)
+//%VALUE
+//%PDDM-DEFINE TEXT_FORMAT_OBJString(VALUE)
+//%VALUE
+//%PDDM-DEFINE TEXT_FORMAT_OBJObject(VALUE)
+//%VALUE
+//%PDDM-DEFINE ENUM_TYPEOBJECT(TYPE)
+//%ENUM_TYPEOBJECT_##TYPE()
+//%PDDM-DEFINE ENUM_TYPEOBJECT_NSString()
+//%NSString *
+//%PDDM-DEFINE ENUM_TYPEOBJECT_id()
+//%id ##
+//%PDDM-DEFINE NEQ_OBJECT(VAL1, VAL2)
+//%![VAL1 isEqual:VAL2]
+//%PDDM-DEFINE EXTRA_METHODS_OBJECT(KEY_NAME, VALUE_NAME)
+//%- (BOOL)isInitialized {
+//%  for (GPBMessage *msg in [_dictionary objectEnumerator]) {
+//%    if (!msg.initialized) {
+//%      return NO;
+//%    }
+//%  }
+//%  return YES;
+//%}
+//%
+//%- (instancetype)deepCopyWithZone:(NSZone *)zone {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *newDict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey,
+//%                                                   GPBMessage *msg,
+//%                                                   BOOL *stop) {
+//%    #pragma unused(stop)
+//%    GPBMessage *copiedMsg = [msg copyWithZone:zone];
+//%    [newDict->_dictionary setObject:copiedMsg forKey:aKey];
+//%    [copiedMsg release];
+//%  }];
+//%  return newDict;
+//%}
+//%
+//%
+//%PDDM-DEFINE BOOL_EXTRA_METHODS_OBJECT(KEY_NAME, VALUE_NAME)
+//%- (BOOL)isInitialized {
+//%  if (_values[0] && ![_values[0] isInitialized]) {
+//%    return NO;
+//%  }
+//%  if (_values[1] && ![_values[1] isInitialized]) {
+//%    return NO;
+//%  }
+//%  return YES;
+//%}
+//%
+//%- (instancetype)deepCopyWithZone:(NSZone *)zone {
+//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *newDict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  for (int i = 0; i < 2; ++i) {
+//%    if (_values[i] != nil) {
+//%      newDict->_values[i] = [_values[i] copyWithZone:zone];
+//%    }
+//%  }
+//%  return newDict;
+//%}
+//%
+//%
+//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_OBJECT(KEY_NAME, VALUE_NAME)
+// Empty
+//%PDDM-DEFINE GPBVALUE_OBJECT(VALUE_NAME)
+//%valueString
+//%PDDM-DEFINE DICTIONARY_VALIDATE_VALUE_OBJECT(VALUE_NAME, EXTRA_INDENT)
+//%##EXTRA_INDENT$S##  if (!##VALUE_NAME) {
+//%##EXTRA_INDENT$S##    [NSException raise:NSInvalidArgumentException
+//%##EXTRA_INDENT$S##                format:@"Attempting to add nil object to a Dictionary"];
+//%##EXTRA_INDENT$S##  }
+//%
+//%PDDM-DEFINE DICTIONARY_VALIDATE_KEY_OBJECT(KEY_NAME, EXTRA_INDENT)
+//%##EXTRA_INDENT$S##  if (!##KEY_NAME) {
+//%##EXTRA_INDENT$S##    [NSException raise:NSInvalidArgumentException
+//%##EXTRA_INDENT$S##                format:@"Attempting to add nil key to a Dictionary"];
+//%##EXTRA_INDENT$S##  }
+//%
+
+//%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_OBJECT()
+// Empty
+//%PDDM-DEFINE BOOL_DICT_INITS_OBJECT(VALUE_NAME, VALUE_TYPE)
+//%- (instancetype)initWithObjects:(const VALUE_TYPE [])objects
+//%                        forKeys:(const BOOL [])keys
+//%                          count:(NSUInteger)count {
+//%  self = [super init];
+//%  if (self) {
+//%    for (NSUInteger i = 0; i < count; ++i) {
+//%      if (!objects[i]) {
+//%        [NSException raise:NSInvalidArgumentException
+//%                    format:@"Attempting to add nil object to a Dictionary"];
+//%      }
+//%      int idx = keys[i] ? 1 : 0;
+//%      [_values[idx] release];
+//%      _values[idx] = (VALUE_TYPE)[objects[i] retain];
+//%    }
+//%  }
+//%  return self;
+//%}
+//%
+//%- (instancetype)initWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary {
+//%  self = [self initWithObjects:NULL forKeys:NULL count:0];
+//%  if (self) {
+//%    if (dictionary) {
+//%      _values[0] = [dictionary->_values[0] retain];
+//%      _values[1] = [dictionary->_values[1] retain];
+//%    }
+//%  }
+//%  return self;
+//%}
+//%PDDM-DEFINE BOOL_DICT_DEALLOCOBJECT()
+//%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
+//%  [_values[0] release];
+//%  [_values[1] release];
+//%  [super dealloc];
+//%}
+//%PDDM-DEFINE BOOL_DICT_W_HASOBJECT(IDX, REF)
+//%(BOOL_DICT_HASOBJECT(IDX, REF))
+//%PDDM-DEFINE BOOL_DICT_HASOBJECT(IDX, REF)
+//%REF##_values[IDX] != nil
+//%PDDM-DEFINE BOOL_VALUE_FOR_KEY_OBJECT(VALUE_TYPE)
+//%- (VALUE_TYPE)objectForKey:(BOOL)key {
+//%  return _values[key ? 1 : 0];
+//%}
+//%PDDM-DEFINE BOOL_SET_GPBVALUE_FOR_KEY_OBJECT(VALUE_NAME, VALUE_TYPE, VisP)
+//%- (void)setGPBGenericValue:(GPBGenericValue *)value
+//%     forGPBGenericValueKey:(GPBGenericValue *)key {
+//%  int idx = (key->valueBool ? 1 : 0);
+//%  [_values[idx] release];
+//%  _values[idx] = [value->valueString retain];
+//%}
+
+//%PDDM-DEFINE BOOL_DICT_MUTATIONS_OBJECT(VALUE_NAME, VALUE_TYPE)
+//%- (void)addEntriesFromDictionary:(GPBBool##VALUE_NAME##Dictionary *)otherDictionary {
+//%  if (otherDictionary) {
+//%    for (int i = 0; i < 2; ++i) {
+//%      if (otherDictionary->_values[i] != nil) {
+//%        [_values[i] release];
+//%        _values[i] = [otherDictionary->_values[i] retain];
+//%      }
+//%    }
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
+//%  }
+//%}
+//%
+//%- (void)setObject:(VALUE_TYPE)object forKey:(BOOL)key {
+//%  if (!object) {
+//%    [NSException raise:NSInvalidArgumentException
+//%                format:@"Attempting to add nil object to a Dictionary"];
+//%  }
+//%  int idx = (key ? 1 : 0);
+//%  [_values[idx] release];
+//%  _values[idx] = [object retain];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
+//%}
+//%
+//%- (void)removeObjectForKey:(BOOL)aKey {
+//%  int idx = (aKey ? 1 : 0);
+//%  [_values[idx] release];
+//%  _values[idx] = nil;
+//%}
+//%
+//%- (void)removeAll {
+//%  for (int i = 0; i < 2; ++i) {
+//%    [_values[i] release];
+//%    _values[i] = nil;
+//%  }
+//%}
+//%PDDM-DEFINE STR_FORMAT_OBJECT(VALUE_NAME)
+//%%@
+
+
+//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(UInt32, uint32_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt32 -> UInt32
+
+@implementation GPBUInt32UInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32UInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32UInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32UInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, uint32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue unsignedIntValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, uint32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%u", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(uint32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedIntValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Int32
+
+@implementation GPBUInt32Int32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32Int32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32Int32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32Int32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32Int32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%d", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> UInt64
+
+@implementation GPBUInt32UInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32UInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32UInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32UInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, uint64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue unsignedLongLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, uint64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%llu", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(uint64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedLongLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Int64
+
+@implementation GPBUInt32Int64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32Int64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32Int64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32Int64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32Int64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue longLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, int64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%lld", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(int64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped longLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Bool
+
+@implementation GPBUInt32BoolDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32BoolDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32BoolDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32BoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32BoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32BoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32BoolDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, BOOL value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue boolValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueBool) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, BOOL value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], (value ? @"true" : @"false"));
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(BOOL *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped boolValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Float
+
+@implementation GPBUInt32FloatDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32FloatDictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32FloatDictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32FloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32FloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32FloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32FloatDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, float value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue floatValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, float value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(float *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped floatValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Double
+
+@implementation GPBUInt32DoubleDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const uint32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32DoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32DoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32DoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32DoubleDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, double value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue doubleValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, double value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(double *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped doubleValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt32 -> Enum
+
+@implementation GPBUInt32EnumDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+  GPBEnumValidationFunc _validationFunc;
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:&rawValue
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])rawValues
+                                         forKeys:(const uint32_t [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:rawValues
+                                                                     forKeys:keys
+                                                                       count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32EnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])rawValues
+                                   forKeys:(const uint32_t [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    if (count && rawValues && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32EnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32EnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32EnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32EnumDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictUInt32FieldSize(key->valueUInt32, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictUInt32Field(outputStream, key->valueUInt32, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndRawValuesUsingBlock:^(uint32_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], @(value));
+  }];
+}
+
+- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    int32_t result = [wrapped intValue];
+    if (!_validationFunc(result)) {
+      result = kGPBUnrecognizedEnumeratorValue;
+    }
+    *value = result;
+  }
+  return (wrapped != NULL);
+}
+
+- (BOOL)valueForKey:(uint32_t)key rawValue:(int32_t *)rawValue {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && rawValue) {
+    *rawValue = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint32_t key, int32_t value, BOOL *stop))block {
+  GPBEnumValidationFunc func = _validationFunc;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      int32_t unwrapped = [aValue intValue];
+      if (!func(unwrapped)) {
+        unwrapped = kGPBUnrecognizedEnumeratorValue;
+      }
+      block([aKey unsignedIntValue], unwrapped, stop);
+  }];
+}
+
+- (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setRawValue:(int32_t)value forKey:(uint32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+- (void)setValue:(int32_t)value forKey:(uint32_t)key {
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBUInt32EnumDictionary: Attempt to set an unknown enum value (%d)",
+                       value];
+  }
+
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+@end
+
+#pragma mark - UInt32 -> Object
+
+@implementation GPBUInt32ObjectDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                            forKeys:&key
+                                                              count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const uint32_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithObjects:objects
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const uint32_t [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && objects && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary {
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt32ObjectDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt32ObjectDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt32ObjectDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint32_t key, id object, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+      block([aKey unsignedIntValue], aObject, stop);
+  }];
+}
+
+- (BOOL)isInitialized {
+  for (GPBMessage *msg in [_dictionary objectEnumerator]) {
+    if (!msg.initialized) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+- (instancetype)deepCopyWithZone:(NSZone *)zone {
+  GPBUInt32ObjectDictionary *newDict =
+      [[GPBUInt32ObjectDictionary alloc] init];
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey,
+                                                   GPBMessage *msg,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    GPBMessage *copiedMsg = [msg copyWithZone:zone];
+    [newDict->_dictionary setObject:copiedMsg forKey:aKey];
+    [copiedMsg release];
+  }];
+  return newDict;
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:value->valueString forKey:@(key->valueUInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndObjectsUsingBlock:^(uint32_t key, id object, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%u", key], object);
+  }];
+}
+
+- (id)objectForKey:(uint32_t)key {
+  id result = [_dictionary objectForKey:@(key)];
+  return result;
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setObject:(id)object forKey:(uint32_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(uint32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(Int32, int32_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int32 -> UInt32
+
+@implementation GPBInt32UInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32UInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32UInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32UInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32UInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, uint32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue unsignedIntValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, uint32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%u", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(uint32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedIntValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Int32
+
+@implementation GPBInt32Int32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32Int32Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32Int32Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32Int32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32Int32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32Int32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32Int32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%d", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> UInt64
+
+@implementation GPBInt32UInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32UInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32UInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32UInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32UInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, uint64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue unsignedLongLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, uint64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%llu", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(uint64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedLongLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Int64
+
+@implementation GPBInt32Int64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32Int64Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32Int64Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32Int64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32Int64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32Int64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32Int64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue longLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, int64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%lld", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(int64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped longLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Bool
+
+@implementation GPBInt32BoolDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32BoolDictionary*)[self alloc] initWithValues:&value
+                                                        forKeys:&key
+                                                          count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32BoolDictionary*)[self alloc] initWithValues:values
+                                                        forKeys:keys
+                                                          count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32BoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32BoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32BoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32BoolDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, BOOL value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue boolValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueBool) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, BOOL value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], (value ? @"true" : @"false"));
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(BOOL *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped boolValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Float
+
+@implementation GPBInt32FloatDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32FloatDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32FloatDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32FloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32FloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32FloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32FloatDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, float value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue floatValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, float value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(float *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped floatValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Double
+
+@implementation GPBInt32DoubleDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32DoubleDictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const int32_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32DoubleDictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32DoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32DoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32DoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32DoubleDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, double value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue doubleValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, double value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(double *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped doubleValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int32 -> Enum
+
+@implementation GPBInt32EnumDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+  GPBEnumValidationFunc _validationFunc;
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                  rawValues:&rawValue
+                                                                    forKeys:&key
+                                                                      count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])rawValues
+                                         forKeys:(const int32_t [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                  rawValues:rawValues
+                                                                    forKeys:keys
+                                                                      count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32EnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])rawValues
+                                   forKeys:(const int32_t [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    if (count && rawValues && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32EnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32EnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32EnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32EnumDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(int32_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey intValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictInt32FieldSize(key->valueInt32, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictInt32Field(outputStream, key->valueInt32, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndRawValuesUsingBlock:^(int32_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], @(value));
+  }];
+}
+
+- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    int32_t result = [wrapped intValue];
+    if (!_validationFunc(result)) {
+      result = kGPBUnrecognizedEnumeratorValue;
+    }
+    *value = result;
+  }
+  return (wrapped != NULL);
+}
+
+- (BOOL)valueForKey:(int32_t)key rawValue:(int32_t *)rawValue {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && rawValue) {
+    *rawValue = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int32_t key, int32_t value, BOOL *stop))block {
+  GPBEnumValidationFunc func = _validationFunc;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      int32_t unwrapped = [aValue intValue];
+      if (!func(unwrapped)) {
+        unwrapped = kGPBUnrecognizedEnumeratorValue;
+      }
+      block([aKey intValue], unwrapped, stop);
+  }];
+}
+
+- (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setRawValue:(int32_t)value forKey:(int32_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+- (void)setValue:(int32_t)value forKey:(int32_t)key {
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBInt32EnumDictionary: Attempt to set an unknown enum value (%d)",
+                       value];
+  }
+
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+@end
+
+#pragma mark - Int32 -> Object
+
+@implementation GPBInt32ObjectDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const int32_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithObjects:objects
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const int32_t [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && objects && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary {
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt32ObjectDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt32ObjectDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt32ObjectDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int32_t key, id object, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+      block([aKey intValue], aObject, stop);
+  }];
+}
+
+- (BOOL)isInitialized {
+  for (GPBMessage *msg in [_dictionary objectEnumerator]) {
+    if (!msg.initialized) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+- (instancetype)deepCopyWithZone:(NSZone *)zone {
+  GPBInt32ObjectDictionary *newDict =
+      [[GPBInt32ObjectDictionary alloc] init];
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey,
+                                                   GPBMessage *msg,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    GPBMessage *copiedMsg = [msg copyWithZone:zone];
+    [newDict->_dictionary setObject:copiedMsg forKey:aKey];
+    [copiedMsg release];
+  }];
+  return newDict;
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:value->valueString forKey:@(key->valueInt32)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndObjectsUsingBlock:^(int32_t key, id object, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%d", key], object);
+  }];
+}
+
+- (id)objectForKey:(int32_t)key {
+  id result = [_dictionary objectForKey:@(key)];
+  return result;
+}
+
+- (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setObject:(id)object forKey:(int32_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(int32_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(UInt64, uint64_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt64 -> UInt32
+
+@implementation GPBUInt64UInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64UInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64UInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64UInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, uint32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue unsignedIntValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, uint32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%u", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(uint32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedIntValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Int32
+
+@implementation GPBUInt64Int32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64Int32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64Int32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64Int32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64Int32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%d", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> UInt64
+
+@implementation GPBUInt64UInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64UInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64UInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64UInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, uint64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue unsignedLongLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, uint64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%llu", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(uint64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedLongLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Int64
+
+@implementation GPBUInt64Int64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64Int64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64Int64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64Int64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64Int64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue longLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, int64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%lld", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(int64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped longLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Bool
+
+@implementation GPBUInt64BoolDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64BoolDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64BoolDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64BoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64BoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64BoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64BoolDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, BOOL value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue boolValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueBool) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, BOOL value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], (value ? @"true" : @"false"));
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(BOOL *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped boolValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Float
+
+@implementation GPBUInt64FloatDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64FloatDictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64FloatDictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64FloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64FloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64FloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64FloatDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, float value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue floatValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, float value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(float *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped floatValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Double
+
+@implementation GPBUInt64DoubleDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const uint64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64DoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64DoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64DoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64DoubleDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, double value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue doubleValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, double value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(double *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped doubleValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - UInt64 -> Enum
+
+@implementation GPBUInt64EnumDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+  GPBEnumValidationFunc _validationFunc;
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:&rawValue
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])rawValues
+                                         forKeys:(const uint64_t [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:rawValues
+                                                                     forKeys:keys
+                                                                       count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64EnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])rawValues
+                                   forKeys:(const uint64_t [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    if (count && rawValues && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64EnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64EnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64EnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64EnumDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictUInt64FieldSize(key->valueUInt64, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictUInt64Field(outputStream, key->valueUInt64, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndRawValuesUsingBlock:^(uint64_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], @(value));
+  }];
+}
+
+- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    int32_t result = [wrapped intValue];
+    if (!_validationFunc(result)) {
+      result = kGPBUnrecognizedEnumeratorValue;
+    }
+    *value = result;
+  }
+  return (wrapped != NULL);
+}
+
+- (BOOL)valueForKey:(uint64_t)key rawValue:(int32_t *)rawValue {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && rawValue) {
+    *rawValue = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(uint64_t key, int32_t value, BOOL *stop))block {
+  GPBEnumValidationFunc func = _validationFunc;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      int32_t unwrapped = [aValue intValue];
+      if (!func(unwrapped)) {
+        unwrapped = kGPBUnrecognizedEnumeratorValue;
+      }
+      block([aKey unsignedLongLongValue], unwrapped, stop);
+  }];
+}
+
+- (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setRawValue:(int32_t)value forKey:(uint64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+- (void)setValue:(int32_t)value forKey:(uint64_t)key {
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBUInt64EnumDictionary: Attempt to set an unknown enum value (%d)",
+                       value];
+  }
+
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+@end
+
+#pragma mark - UInt64 -> Object
+
+@implementation GPBUInt64ObjectDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                            forKeys:&key
+                                                              count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const uint64_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithObjects:objects
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const uint64_t [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && objects && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary {
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBUInt64ObjectDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBUInt64ObjectDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBUInt64ObjectDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint64_t key, id object, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+      block([aKey unsignedLongLongValue], aObject, stop);
+  }];
+}
+
+- (BOOL)isInitialized {
+  for (GPBMessage *msg in [_dictionary objectEnumerator]) {
+    if (!msg.initialized) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+- (instancetype)deepCopyWithZone:(NSZone *)zone {
+  GPBUInt64ObjectDictionary *newDict =
+      [[GPBUInt64ObjectDictionary alloc] init];
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey,
+                                                   GPBMessage *msg,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    GPBMessage *copiedMsg = [msg copyWithZone:zone];
+    [newDict->_dictionary setObject:copiedMsg forKey:aKey];
+    [copiedMsg release];
+  }];
+  return newDict;
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:value->valueString forKey:@(key->valueUInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndObjectsUsingBlock:^(uint64_t key, id object, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%llu", key], object);
+  }];
+}
+
+- (id)objectForKey:(uint64_t)key {
+  id result = [_dictionary objectForKey:@(key)];
+  return result;
+}
+
+- (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setObject:(id)object forKey:(uint64_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(uint64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(Int64, int64_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int64 -> UInt32
+
+@implementation GPBInt64UInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64UInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64UInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64UInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64UInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, uint32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue unsignedIntValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, uint32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%u", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(uint32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedIntValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Int32
+
+@implementation GPBInt64Int32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64Int32Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64Int32Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64Int32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64Int32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64Int32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64Int32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%d", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> UInt64
+
+@implementation GPBInt64UInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64UInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64UInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64UInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64UInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, uint64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue unsignedLongLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, uint64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%llu", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(uint64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped unsignedLongLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Int64
+
+@implementation GPBInt64Int64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64Int64Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64Int64Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64Int64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64Int64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64Int64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64Int64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue longLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, int64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%lld", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(int64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped longLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Bool
+
+@implementation GPBInt64BoolDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64BoolDictionary*)[self alloc] initWithValues:&value
+                                                        forKeys:&key
+                                                          count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64BoolDictionary*)[self alloc] initWithValues:values
+                                                        forKeys:keys
+                                                          count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64BoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64BoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64BoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64BoolDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, BOOL value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue boolValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueBool) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, BOOL value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], (value ? @"true" : @"false"));
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(BOOL *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped boolValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Float
+
+@implementation GPBInt64FloatDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64FloatDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64FloatDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64FloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64FloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64FloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64FloatDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, float value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue floatValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, float value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(float *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped floatValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Double
+
+@implementation GPBInt64DoubleDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64DoubleDictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const int64_t [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64DoubleDictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(values[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64DoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64DoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64DoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64DoubleDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, double value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue doubleValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, double value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(double *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    *value = [wrapped doubleValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - Int64 -> Enum
+
+@implementation GPBInt64EnumDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+  GPBEnumValidationFunc _validationFunc;
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                  rawValues:&rawValue
+                                                                    forKeys:&key
+                                                                      count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])rawValues
+                                         forKeys:(const int64_t [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                  rawValues:rawValues
+                                                                    forKeys:keys
+                                                                      count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64EnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])rawValues
+                                   forKeys:(const int64_t [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    if (count && rawValues && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64EnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64EnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64EnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64EnumDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(int64_t key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictInt64FieldSize(key->valueInt64, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictInt64Field(outputStream, key->valueInt64, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndRawValuesUsingBlock:^(int64_t key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], @(value));
+  }];
+}
+
+- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && value) {
+    int32_t result = [wrapped intValue];
+    if (!_validationFunc(result)) {
+      result = kGPBUnrecognizedEnumeratorValue;
+    }
+    *value = result;
+  }
+  return (wrapped != NULL);
+}
+
+- (BOOL)valueForKey:(int64_t)key rawValue:(int32_t *)rawValue {
+  NSNumber *wrapped = [_dictionary objectForKey:@(key)];
+  if (wrapped && rawValue) {
+    *rawValue = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(int64_t key, int32_t value, BOOL *stop))block {
+  GPBEnumValidationFunc func = _validationFunc;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      int32_t unwrapped = [aValue intValue];
+      if (!func(unwrapped)) {
+        unwrapped = kGPBUnrecognizedEnumeratorValue;
+      }
+      block([aKey longLongValue], unwrapped, stop);
+  }];
+}
+
+- (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setRawValue:(int32_t)value forKey:(int64_t)key {
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+- (void)setValue:(int32_t)value forKey:(int64_t)key {
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBInt64EnumDictionary: Attempt to set an unknown enum value (%d)",
+                       value];
+  }
+
+  [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+@end
+
+#pragma mark - Int64 -> Object
+
+@implementation GPBInt64ObjectDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const int64_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithObjects:objects
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const int64_t [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && objects && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary {
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBInt64ObjectDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBInt64ObjectDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBInt64ObjectDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int64_t key, id object, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+      block([aKey longLongValue], aObject, stop);
+  }];
+}
+
+- (BOOL)isInitialized {
+  for (GPBMessage *msg in [_dictionary objectEnumerator]) {
+    if (!msg.initialized) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+- (instancetype)deepCopyWithZone:(NSZone *)zone {
+  GPBInt64ObjectDictionary *newDict =
+      [[GPBInt64ObjectDictionary alloc] init];
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey,
+                                                   GPBMessage *msg,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    GPBMessage *copiedMsg = [msg copyWithZone:zone];
+    [newDict->_dictionary setObject:copiedMsg forKey:aKey];
+    [copiedMsg release];
+  }];
+  return newDict;
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
+                                                   id aObject,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:value->valueString forKey:@(key->valueInt64)];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndObjectsUsingBlock:^(int64_t key, id object, BOOL *stop) {
+      #pragma unused(stop)
+      block([NSString stringWithFormat:@"%lld", key], object);
+  }];
+}
+
+- (id)objectForKey:(int64_t)key {
+  id result = [_dictionary objectForKey:@(key)];
+  return result;
+}
+
+- (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setObject:(id)object forKey:(int64_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(int64_t)aKey {
+  [_dictionary removeObjectForKey:@(aKey)];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_POD_IMPL_FOR_KEY(String, NSString, *, OBJECT)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - String -> UInt32
+
+@implementation GPBStringUInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringUInt32Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringUInt32Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringUInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringUInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringUInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringUInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, uint32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue unsignedIntValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt32) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, uint32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%u", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(uint32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped unsignedIntValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Int32
+
+@implementation GPBStringInt32Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringInt32Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringInt32Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringInt32Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt32) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%d", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> UInt64
+
+@implementation GPBStringUInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringUInt64Dictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringUInt64Dictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringUInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringUInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringUInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringUInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, uint64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue unsignedLongLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueUInt64) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, uint64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%llu", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(uint64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped unsignedLongLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Int64
+
+@implementation GPBStringInt64Dictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringInt64Dictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringInt64Dictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringInt64Dictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int64_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue longLongValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueInt64) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, int64_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%lld", value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(int64_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped longLongValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Bool
+
+@implementation GPBStringBoolDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringBoolDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringBoolDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringBoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringBoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringBoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringBoolDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, BOOL value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue boolValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueBool) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, BOOL value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, (value ? @"true" : @"false"));
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(BOOL *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped boolValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Float
+
+@implementation GPBStringFloatDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringFloatDictionary*)[self alloc] initWithValues:&value
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringFloatDictionary*)[self alloc] initWithValues:values
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringFloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringFloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringFloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringFloatDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, float value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue floatValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueFloat) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, float value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%.*g", FLT_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(float *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped floatValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Double
+
+@implementation GPBStringDoubleDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringDoubleDictionary*)[self alloc] initWithValues:&value
+                                                           forKeys:&key
+                                                             count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const NSString * [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringDoubleDictionary*)[self alloc] initWithValues:values
+                                                           forKeys:keys
+                                                             count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBStringDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    if (count && values && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(values[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringDoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringDoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringDoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringDoubleDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, double value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue doubleValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueDouble) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndValuesUsingBlock:^(NSString *key, double value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]);
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(double *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    *value = [wrapped doubleValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+@end
+
+#pragma mark - String -> Enum
+
+@implementation GPBStringEnumDictionary {
+ @package
+  NSMutableDictionary *_dictionary;
+  GPBEnumValidationFunc _validationFunc;
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        rawValue:(int32_t)rawValue
+                                          forKey:(NSString *)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:&rawValue
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])rawValues
+                                         forKeys:(const NSString * [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                   rawValues:rawValues
+                                                                     forKeys:keys
+                                                                       count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBStringEnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBStringEnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                 rawValues:(const int32_t [])rawValues
+                                   forKeys:(const NSString * [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    if (count && rawValues && keys) {
+      for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
+        [_dictionary setObject:@(rawValues[i]) forKey:keys[i]];
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBStringEnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBStringEnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBStringEnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBStringEnumDictionary class]]) {
+    return NO;
+  }
+  return [_dictionary isEqual:other->_dictionary];
+}
+
+- (NSUInteger)hash {
+  return _dictionary.count;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary];
+}
+
+- (NSUInteger)count {
+  return _dictionary.count;
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(NSString *key, int32_t value, BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      block(aKey, [aValue intValue], stop);
+  }];
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  NSUInteger count = _dictionary.count;
+  if (count == 0) {
+    return 0;
+  }
+
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  __block size_t result = 0;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+  }];
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  GPBDataType keyDataType = field.mapKeyDataType;
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+    #pragma unused(stop)
+    // Write the tag.
+    [outputStream writeInt32NoTag:tag];
+    // Write the size of the message.
+    size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyDataType);
+    msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueDataType);
+    [outputStream writeInt32NoTag:(int32_t)msgSize];
+    // Write the fields.
+    WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyDataType);
+    WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueDataType);
+  }];
+}
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictStringFieldSize(key->valueString, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictStringField(outputStream, key->valueString, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  [_dictionary setObject:@(value->valueEnum) forKey:key->valueString];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  [self enumerateKeysAndRawValuesUsingBlock:^(NSString *key, int32_t value, BOOL *stop) {
+      #pragma unused(stop)
+      block(key, @(value));
+  }];
+}
+
+- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && value) {
+    int32_t result = [wrapped intValue];
+    if (!_validationFunc(result)) {
+      result = kGPBUnrecognizedEnumeratorValue;
+    }
+    *value = result;
+  }
+  return (wrapped != NULL);
+}
+
+- (BOOL)valueForKey:(NSString *)key rawValue:(int32_t *)rawValue {
+  NSNumber *wrapped = [_dictionary objectForKey:key];
+  if (wrapped && rawValue) {
+    *rawValue = [wrapped intValue];
+  }
+  return (wrapped != NULL);
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(NSString *key, int32_t value, BOOL *stop))block {
+  GPBEnumValidationFunc func = _validationFunc;
+  [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey,
+                                                   NSNumber *aValue,
+                                                   BOOL *stop) {
+      int32_t unwrapped = [aValue intValue];
+      if (!func(unwrapped)) {
+        unwrapped = kGPBUnrecognizedEnumeratorValue;
+      }
+      block(aKey, unwrapped, stop);
+  }];
+}
+
+- (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setRawValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(NSString *)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+- (void)removeAll {
+  [_dictionary removeAllObjects];
+}
+
+- (void)setValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBStringEnumDictionary: Attempt to set an unknown enum value (%d)",
+                       value];
+  }
+
+  [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+@end
+
+//%PDDM-EXPAND-END (5 expansions)
+
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(UInt32, uint32_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> UInt32
+
+@implementation GPBBoolUInt32Dictionary {
+ @package
+  uint32_t _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint32_t)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint32_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint32_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolUInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolUInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolUInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolUInt32Dictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %u", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %u", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(uint32_t *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueUInt32;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%u", _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%u", _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, uint32_t value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictUInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictUInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictUInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolUInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint32_t)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Int32, int32_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Int32
+
+@implementation GPBBoolInt32Dictionary {
+ @package
+  int32_t _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int32_t)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolInt32Dictionary*)[self alloc] initWithValues:&value
+                                                        forKeys:&key
+                                                          count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int32_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolInt32Dictionary*)[self alloc] initWithValues:values
+                                                        forKeys:keys
+                                                          count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolInt32Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolInt32Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolInt32Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolInt32Dictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %d", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %d", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(int32_t *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueInt32;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%d", _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%d", _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int32_t value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolInt32Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(UInt64, uint64_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> UInt64
+
+@implementation GPBBoolUInt64Dictionary {
+ @package
+  uint64_t _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(uint64_t)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const uint64_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const uint64_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolUInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolUInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolUInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolUInt64Dictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %llu", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %llu", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(uint64_t *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueUInt64;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%llu", _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%llu", _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, uint64_t value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictUInt64FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictUInt64FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictUInt64Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolUInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(uint64_t)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Int64, int64_t)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Int64
+
+@implementation GPBBoolInt64Dictionary {
+ @package
+  int64_t _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(int64_t)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolInt64Dictionary*)[self alloc] initWithValues:&value
+                                                        forKeys:&key
+                                                          count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const int64_t [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolInt64Dictionary*)[self alloc] initWithValues:values
+                                                        forKeys:keys
+                                                          count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const int64_t [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolInt64Dictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolInt64Dictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolInt64Dictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolInt64Dictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %lld", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %lld", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(int64_t *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueInt64;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%lld", _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%lld", _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int64_t value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt64FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt64FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictInt64Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolInt64Dictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int64_t)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Bool, BOOL)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Bool
+
+@implementation GPBBoolBoolDictionary {
+ @package
+  BOOL _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(BOOL)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolBoolDictionary*)[self alloc] initWithValues:&value
+                                                       forKeys:&key
+                                                         count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const BOOL [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolBoolDictionary*)[self alloc] initWithValues:values
+                                                       forKeys:keys
+                                                         count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const BOOL [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolBoolDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolBoolDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolBoolDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolBoolDictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %d", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %d", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(BOOL *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueBool;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", (_values[0] ? @"true" : @"false"));
+  }
+  if (_valueSet[1]) {
+    block(@"true", (_values[1] ? @"true" : @"false"));
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, BOOL value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictBoolFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictBoolFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictBoolField(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolBoolDictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(BOOL)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Float, float)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Float
+
+@implementation GPBBoolFloatDictionary {
+ @package
+  float _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(float)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolFloatDictionary*)[self alloc] initWithValues:&value
+                                                        forKeys:&key
+                                                          count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const float [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolFloatDictionary*)[self alloc] initWithValues:values
+                                                        forKeys:keys
+                                                          count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const float [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolFloatDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolFloatDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolFloatDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolFloatDictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %f", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %f", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(float *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueFloat;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%.*g", FLT_DIG, _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%.*g", FLT_DIG, _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, float value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictFloatFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictFloatFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictFloatField(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolFloatDictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(float)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Double, double)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Double
+
+@implementation GPBBoolDoubleDictionary {
+ @package
+  double _values[2];
+  BOOL _valueSet[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValue:(double)value
+                             forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolDoubleDictionary*)[self alloc] initWithValues:&value
+                                                         forKeys:&key
+                                                           count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValues:(const double [])values
+                             forKeys:(const BOOL [])keys
+                               count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolDoubleDictionary*)[self alloc] initWithValues:values
+                                                         forKeys:keys
+                                                           count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValues:(const double [])values
+                       forKeys:(const BOOL [])keys
+                         count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = values[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolDoubleDictionary *)dictionary {
+  self = [self initWithValues:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolDoubleDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolDoubleDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolDoubleDictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %lf", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %lf", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(double *)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      *value = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueDouble;
+  _valueSet[idx] = YES;
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", [NSString stringWithFormat:@"%.*lg", DBL_DIG, _values[0]]);
+  }
+  if (_valueSet[1]) {
+    block(@"true", [NSString stringWithFormat:@"%.*lg", DBL_DIG, _values[1]]);
+  }
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, double value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictDoubleFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictDoubleFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictDoubleField(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolDoubleDictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(double)value forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_OBJECT_IMPL(Object, id)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Object
+
+@implementation GPBBoolObjectDictionary {
+ @package
+  id _values[2];
+}
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolObjectDictionary*)[self alloc] initWithObjects:&object
+                                                          forKeys:&key
+                                                            count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const BOOL [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolObjectDictionary*)[self alloc] initWithObjects:objects
+                                                          forKeys:keys
+                                                            count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
+  // on to get the type correct.
+  return [[(GPBBoolObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithCapacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const BOOL [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    for (NSUInteger i = 0; i < count; ++i) {
+      if (!objects[i]) {
+        [NSException raise:NSInvalidArgumentException
+                    format:@"Attempting to add nil object to a Dictionary"];
+      }
+      int idx = keys[i] ? 1 : 0;
+      [_values[idx] release];
+      _values[idx] = (id)[objects[i] retain];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary {
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
+  if (self) {
+    if (dictionary) {
+      _values[0] = [dictionary->_values[0] retain];
+      _values[1] = [dictionary->_values[1] retain];
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+  #pragma unused(numItems)
+  return [self initWithObjects:NULL forKeys:NULL count:0];
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_values[0] release];
+  [_values[1] release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolObjectDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolObjectDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolObjectDictionary class]]) {
+    return NO;
+  }
+  if (((_values[0] != nil) != (other->_values[0] != nil)) ||
+      ((_values[1] != nil) != (other->_values[1] != nil))) {
+    return NO;
+  }
+  if (((_values[0] != nil) && (![_values[0] isEqual:other->_values[0]])) ||
+      ((_values[1] != nil) && (![_values[1] isEqual:other->_values[1]]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return ((_values[0] != nil) ? 1 : 0) + ((_values[1] != nil) ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if ((_values[0] != nil)) {
+    [result appendFormat:@"NO: %@", _values[0]];
+  }
+  if ((_values[1] != nil)) {
+    [result appendFormat:@"YES: %@", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return ((_values[0] != nil) ? 1 : 0) + ((_values[1] != nil) ? 1 : 0);
+}
+
+- (id)objectForKey:(BOOL)key {
+  return _values[key ? 1 : 0];
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  [_values[idx] release];
+  _values[idx] = [value->valueString retain];
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_values[0] != nil) {
+    block(@"false", _values[0]);
+  }
+  if ((_values[1] != nil)) {
+    block(@"true", _values[1]);
+  }
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(BOOL key, id object, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_values[0] != nil) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && (_values[1] != nil)) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (BOOL)isInitialized {
+  if (_values[0] && ![_values[0] isInitialized]) {
+    return NO;
+  }
+  if (_values[1] && ![_values[1] isInitialized]) {
+    return NO;
+  }
+  return YES;
+}
+
+- (instancetype)deepCopyWithZone:(NSZone *)zone {
+  GPBBoolObjectDictionary *newDict =
+      [[GPBBoolObjectDictionary alloc] init];
+  for (int i = 0; i < 2; ++i) {
+    if (_values[i] != nil) {
+      newDict->_values[i] = [_values[i] copyWithZone:zone];
+    }
+  }
+  return newDict;
+}
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_values[i] != nil) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictObjectFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_values[i] != nil) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictObjectFieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictObjectField(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_values[i] != nil) {
+        [_values[i] release];
+        _values[i] = [otherDictionary->_values[i] retain];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setObject:(id)object forKey:(BOOL)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  int idx = (key ? 1 : 0);
+  [_values[idx] release];
+  _values[idx] = [object retain];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(BOOL)aKey {
+  int idx = (aKey ? 1 : 0);
+  [_values[idx] release];
+  _values[idx] = nil;
+}
+
+- (void)removeAll {
+  for (int i = 0; i < 2; ++i) {
+    [_values[i] release];
+    _values[i] = nil;
+  }
+}
+
+@end
+
+//%PDDM-EXPAND-END (8 expansions)
+
+#pragma mark - Bool -> Enum
+
+@implementation GPBBoolEnumDictionary {
+ @package
+  GPBEnumValidationFunc _validationFunc;
+  int32_t _values[2];
+  BOOL _valueSet[2];
+}
+
+@synthesize validationFunc = _validationFunc;
+
++ (instancetype)dictionary {
+  return [[[self alloc] initWithValidationFunction:NULL
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [[[self alloc] initWithValidationFunction:func
+                                         rawValues:NULL
+                                           forKeys:NULL
+                                             count:0] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValue:(int32_t)rawValue
+                                          forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolEnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                 rawValues:&rawValue
+                                                                   forKeys:&key
+                                                                     count:1] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                       rawValues:(const int32_t [])values
+                                         forKeys:(const BOOL [])keys
+                                           count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolEnumDictionary*)[self alloc] initWithValidationFunction:func
+                                                                 rawValues:values
+                                                                   forKeys:keys
+                                                                     count:count] autorelease];
+}
+
++ (instancetype)dictionaryWithDictionary:(GPBBoolEnumDictionary *)dictionary {
+  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // on to get the type correct.
+  return [[(GPBBoolEnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
+}
+
++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func
+                                        capacity:(NSUInteger)numItems {
+  return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease];
+}
+
+- (instancetype)init {
+  return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func {
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                rawValues:(const int32_t [])rawValues
+                                   forKeys:(const BOOL [])keys
+                                     count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
+    for (NSUInteger i = 0; i < count; ++i) {
+      int idx = keys[i] ? 1 : 0;
+      _values[idx] = rawValues[i];
+      _valueSet[idx] = YES;
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithDictionary:(GPBBoolEnumDictionary *)dictionary {
+  self = [self initWithValidationFunction:dictionary.validationFunc
+                                rawValues:NULL
+                                  forKeys:NULL
+                                    count:0];
+  if (self) {
+    if (dictionary) {
+      for (int i = 0; i < 2; ++i) {
+        if (dictionary->_valueSet[i]) {
+          _values[i] = dictionary->_values[i];
+          _valueSet[i] = YES;
+        }
+      }
+    }
+  }
+  return self;
+}
+
+- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func
+                                  capacity:(NSUInteger)numItems {
+#pragma unused(numItems)
+  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
+}
+
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  return [[GPBBoolEnumDictionary allocWithZone:zone] initWithDictionary:self];
+}
+
+- (BOOL)isEqual:(GPBBoolEnumDictionary *)other {
+  if (self == other) {
+    return YES;
+  }
+  if (![other isKindOfClass:[GPBBoolEnumDictionary class]]) {
+    return NO;
+  }
+  if ((_valueSet[0] != other->_valueSet[0]) ||
+      (_valueSet[1] != other->_valueSet[1])) {
+    return NO;
+  }
+  if ((_valueSet[0] && (_values[0] != other->_values[0])) ||
+      (_valueSet[1] && (_values[1] != other->_values[1]))) {
+    return NO;
+  }
+  return YES;
+}
+
+- (NSUInteger)hash {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (NSString *)description {
+  NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self];
+  if (_valueSet[0]) {
+    [result appendFormat:@"NO: %d", _values[0]];
+  }
+  if (_valueSet[1]) {
+    [result appendFormat:@"YES: %d", _values[1]];
+  }
+  [result appendString:@" }"];
+  return result;
+}
+
+- (NSUInteger)count {
+  return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0);
+}
+
+- (BOOL)valueForKey:(BOOL)key value:(int32_t*)value {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (value) {
+      int32_t result = _values[idx];
+      if (!_validationFunc(result)) {
+        result = kGPBUnrecognizedEnumeratorValue;
+      }
+      *value = result;
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (BOOL)valueForKey:(BOOL)key rawValue:(int32_t*)rawValue {
+  int idx = (key ? 1 : 0);
+  if (_valueSet[idx]) {
+    if (rawValue) {
+      *rawValue = _values[idx];
+    }
+    return YES;
+  }
+  return NO;
+}
+
+- (void)enumerateKeysAndValuesUsingBlock:
+    (void (^)(BOOL key, int32_t value, BOOL *stop))block {
+  BOOL stop = NO;
+  if (_valueSet[0]) {
+    block(NO, _values[0], &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    block(YES, _values[1], &stop);
+  }
+}
+
+- (void)enumerateKeysAndRawValuesUsingBlock:
+    (void (^)(BOOL key, int32_t rawValue, BOOL *stop))block {
+  BOOL stop = NO;
+  GPBEnumValidationFunc func = _validationFunc;
+  int32_t validatedValue;
+  if (_valueSet[0]) {
+    validatedValue = _values[0];
+    if (!func(validatedValue)) {
+      validatedValue = kGPBUnrecognizedEnumeratorValue;
+    }
+    block(NO, validatedValue, &stop);
+  }
+  if (!stop && _valueSet[1]) {
+    validatedValue = _values[1];
+    if (!func(validatedValue)) {
+      validatedValue = kGPBUnrecognizedEnumeratorValue;
+    }
+    block(YES, validatedValue, &stop);
+  }
+}
+
+//%PDDM-EXPAND SERIAL_DATA_FOR_ENTRY_POD_Enum(Bool)
+// This block of code is generated, do not edit it directly.
+
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType {
+  size_t msgSize = ComputeDictBoolFieldSize(key->valueBool, kMapKeyFieldNumber, keyDataType);
+  msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBDataTypeEnum);
+  NSMutableData *data = [NSMutableData dataWithLength:msgSize];
+  GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data];
+  WriteDictBoolField(outputStream, key->valueBool, kMapKeyFieldNumber, keyDataType);
+  WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum);
+  [outputStream release];
+  return data;
+}
+
+//%PDDM-EXPAND-END SERIAL_DATA_FOR_ENTRY_POD_Enum(Bool)
+
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  NSUInteger count = 0;
+  size_t result = 0;
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      ++count;
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
+    }
+  }
+  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
+  result += tagSize * count;
+  return result;
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field {
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
+  for (int i = 0; i < 2; ++i) {
+    if (_valueSet[i]) {
+      // Write the tag.
+      [outputStream writeInt32NoTag:tag];
+      // Write the size of the message.
+      size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueDataType);
+      [outputStream writeInt32NoTag:(int32_t)msgSize];
+      // Write the fields.
+      WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBDataTypeBool);
+      WriteDictInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueDataType);
+    }
+  }
+}
+
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
+  if (_valueSet[0]) {
+    block(@"false", @(_values[0]));
+  }
+  if (_valueSet[1]) {
+    block(@"true", @(_values[1]));
+  }
+}
+
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key {
+  int idx = (key->valueBool ? 1 : 0);
+  _values[idx] = value->valueInt32;
+  _valueSet[idx] = YES;
+}
+
+- (void)addRawEntriesFromDictionary:(GPBBoolEnumDictionary *)otherDictionary {
+  if (otherDictionary) {
+    for (int i = 0; i < 2; ++i) {
+      if (otherDictionary->_valueSet[i]) {
+        _valueSet[i] = YES;
+        _values[i] = otherDictionary->_values[i];
+      }
+    }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
+  }
+}
+
+- (void)setValue:(int32_t)value forKey:(BOOL)key {
+  if (!_validationFunc(value)) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"GPBBoolEnumDictionary: Attempt to set an unknown enum value (%d)",
+     value];
+  }
+  int idx = (key ? 1 : 0);
+  _values[idx] = value;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key {
+  int idx = (key ? 1 : 0);
+  _values[idx] = rawValue;
+  _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeValueForKey:(BOOL)aKey {
+  _valueSet[aKey ? 1 : 0] = NO;
+}
+
+- (void)removeAll {
+  _valueSet[0] = NO;
+  _valueSet[1] = NO;
+}
+
+@end
+
+#pragma mark - NSDictionary Subclass
+
+@implementation GPBAutocreatedDictionary {
+  NSMutableDictionary *_dictionary;
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+#pragma mark Required NSDictionary overrides
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const id<NSCopying> [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] initWithObjects:objects
+                                                       forKeys:keys
+                                                         count:count];
+  }
+  return self;
+}
+
+- (NSUInteger)count {
+  return [_dictionary count];
+}
+
+- (id)objectForKey:(id)aKey {
+  return [_dictionary objectForKey:aKey];
+}
+
+- (NSEnumerator *)keyEnumerator {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary keyEnumerator];
+}
+
+#pragma mark Required NSMutableDictionary overrides
+
+// Only need to call GPBAutocreatedDictionaryModified() when adding things
+// since we only autocreate empty dictionaries.
+
+- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  [_dictionary setObject:anObject forKey:aKey];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(id)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+#pragma mark Extra things hooked
+
+- (id)copyWithZone:(NSZone *)zone {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary copyWithZone:zone];
+}
+
+- (id)mutableCopyWithZone:(NSZone *)zone {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary mutableCopyWithZone:zone];
+}
+
+- (id)objectForKeyedSubscript:(id)key {
+  return [_dictionary objectForKeyedSubscript:key];
+}
+
+- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  [_dictionary setObject:obj forKeyedSubscript:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key,
+                                                    id obj,
+                                                    BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:block];
+}
+
+- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts
+                                usingBlock:(void (^)(id key,
+                                                     id obj,
+                                                     BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsWithOptions:opts usingBlock:block];
+}
+
+@end
diff --git a/objectivec/GPBDictionary_PackagePrivate.h b/objectivec/GPBDictionary_PackagePrivate.h
new file mode 100644
index 0000000..7b921e8
--- /dev/null
+++ b/objectivec/GPBDictionary_PackagePrivate.h
@@ -0,0 +1,488 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBDictionary.h"
+
+@class GPBCodedInputStream;
+@class GPBCodedOutputStream;
+@class GPBExtensionRegistry;
+@class GPBFieldDescriptor;
+
+@protocol GPBDictionaryInternalsProtocol
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field;
+- (void)setGPBGenericValue:(GPBGenericValue *)value
+     forGPBGenericValueKey:(GPBGenericValue *)key;
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@end
+
+//%PDDM-DEFINE DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(KEY_NAME)
+//%DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(KEY_NAME)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Object, Object)
+//%PDDM-DEFINE DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(KEY_NAME)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, UInt32, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Int32, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, UInt64, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Int64, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Bool, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Float, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Double, Basic)
+//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Enum, Enum)
+
+//%PDDM-DEFINE DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, VALUE_NAME, HELPER)
+//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary () <GPBDictionaryInternalsProtocol> {
+//% @package
+//%  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+//%}
+//%EXTRA_DICTIONARY_PRIVATE_INTERFACES_##HELPER()@end
+//%
+
+//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Basic()
+// Empty
+//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Object()
+//%- (BOOL)isInitialized;
+//%- (instancetype)deepCopyWithZone:(NSZone *)zone
+//%    __attribute__((ns_returns_retained));
+//%
+//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Enum()
+//%- (NSData *)serializedDataForUnknownValue:(int32_t)value
+//%                                   forKey:(GPBGenericValue *)key
+//%                              keyDataType:(GPBDataType)keyDataType;
+//%
+
+//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt32)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBUInt32UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt32EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+@interface GPBUInt32ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (BOOL)isInitialized;
+- (instancetype)deepCopyWithZone:(NSZone *)zone
+    __attribute__((ns_returns_retained));
+@end
+
+//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int32)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBInt32UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt32EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+@interface GPBInt32ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (BOOL)isInitialized;
+- (instancetype)deepCopyWithZone:(NSZone *)zone
+    __attribute__((ns_returns_retained));
+@end
+
+//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt64)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBUInt64UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBUInt64EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+@interface GPBUInt64ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (BOOL)isInitialized;
+- (instancetype)deepCopyWithZone:(NSZone *)zone
+    __attribute__((ns_returns_retained));
+@end
+
+//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int64)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBInt64UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBInt64EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+@interface GPBInt64ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (BOOL)isInitialized;
+- (instancetype)deepCopyWithZone:(NSZone *)zone
+    __attribute__((ns_returns_retained));
+@end
+
+//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Bool)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBBoolUInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolUInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolBoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolFloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolDoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBBoolEnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+@interface GPBBoolObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (BOOL)isInitialized;
+- (instancetype)deepCopyWithZone:(NSZone *)zone
+    __attribute__((ns_returns_retained));
+@end
+
+//%PDDM-EXPAND DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(String)
+// This block of code is generated, do not edit it directly.
+
+@interface GPBStringUInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringUInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringBoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringFloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringDoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+@interface GPBStringEnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+- (NSData *)serializedDataForUnknownValue:(int32_t)value
+                                   forKey:(GPBGenericValue *)key
+                              keyDataType:(GPBDataType)keyDataType;
+@end
+
+//%PDDM-EXPAND-END (6 expansions)
+
+#pragma mark - NSDictionary Subclass
+
+@interface GPBAutocreatedDictionary : NSMutableDictionary {
+  @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Helpers
+
+CF_EXTERN_C_BEGIN
+
+// Helper to compute size when an NSDictionary is used for the map instead
+// of a custom type.
+size_t GPBDictionaryComputeSizeInternalHelper(NSDictionary *dict,
+                                              GPBFieldDescriptor *field);
+
+// Helper to write out when an NSDictionary is used for the map instead
+// of a custom type.
+void GPBDictionaryWriteToStreamInternalHelper(
+    GPBCodedOutputStream *outputStream, NSDictionary *dict,
+    GPBFieldDescriptor *field);
+
+// Helper to check message initialization when an NSDictionary is used for
+// the map instead of a custom type.
+BOOL GPBDictionaryIsInitializedInternalHelper(NSDictionary *dict,
+                                              GPBFieldDescriptor *field);
+
+// Helper to read a map instead.
+void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream,
+                            GPBExtensionRegistry *registry,
+                            GPBFieldDescriptor *field,
+                            GPBMessage *parentMessage);
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBExtensionInternals.h b/objectivec/GPBExtensionInternals.h
new file mode 100644
index 0000000..2b980ae
--- /dev/null
+++ b/objectivec/GPBExtensionInternals.h
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBDescriptor.h"
+
+@class GPBCodedInputStream;
+@class GPBCodedOutputStream;
+@class GPBExtensionRegistry;
+
+void GPBExtensionMergeFromInputStream(GPBExtensionDescriptor *extension,
+                                      BOOL isPackedOnStream,
+                                      GPBCodedInputStream *input,
+                                      GPBExtensionRegistry *extensionRegistry,
+                                      GPBMessage *message);
+
+size_t GPBComputeExtensionSerializedSizeIncludingTag(
+    GPBExtensionDescriptor *extension, id value);
+
+void GPBWriteExtensionValueToOutputStream(GPBExtensionDescriptor *extension,
+                                          id value,
+                                          GPBCodedOutputStream *output);
diff --git a/objectivec/GPBExtensionInternals.m b/objectivec/GPBExtensionInternals.m
new file mode 100644
index 0000000..7d0dcb2
--- /dev/null
+++ b/objectivec/GPBExtensionInternals.m
@@ -0,0 +1,380 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBExtensionInternals.h"
+
+#import <objc/runtime.h>
+
+#import "GPBCodedInputStream_PackagePrivate.h"
+#import "GPBCodedOutputStream_PackagePrivate.h"
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
+                                        GPBCodedInputStream *input,
+                                        GPBExtensionRegistry *extensionRegistry,
+                                        GPBMessage *existingValue)
+    __attribute__((ns_returns_retained));
+
+GPB_INLINE size_t DataTypeSize(GPBDataType dataType) {
+  switch (dataType) {
+    case GPBDataTypeBool:
+      return 1;
+    case GPBDataTypeFixed32:
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeFloat:
+      return 4;
+    case GPBDataTypeFixed64:
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeDouble:
+      return 8;
+    default:
+      return 0;
+  }
+}
+
+static size_t ComputePBSerializedSizeNoTagOfObject(GPBDataType dataType, id object) {
+#define FIELD_CASE(TYPE, ACCESSOR)                                     \
+  case GPBDataType##TYPE:                                              \
+    return GPBCompute##TYPE##SizeNoTag([(NSNumber *)object ACCESSOR]);
+#define FIELD_CASE2(TYPE)                                              \
+  case GPBDataType##TYPE:                                              \
+    return GPBCompute##TYPE##SizeNoTag(object);
+  switch (dataType) {
+    FIELD_CASE(Bool, boolValue)
+    FIELD_CASE(Float, floatValue)
+    FIELD_CASE(Double, doubleValue)
+    FIELD_CASE(Int32, intValue)
+    FIELD_CASE(SFixed32, intValue)
+    FIELD_CASE(SInt32, intValue)
+    FIELD_CASE(Enum, intValue)
+    FIELD_CASE(Int64, longLongValue)
+    FIELD_CASE(SInt64, longLongValue)
+    FIELD_CASE(SFixed64, longLongValue)
+    FIELD_CASE(UInt32, unsignedIntValue)
+    FIELD_CASE(Fixed32, unsignedIntValue)
+    FIELD_CASE(UInt64, unsignedLongLongValue)
+    FIELD_CASE(Fixed64, unsignedLongLongValue)
+    FIELD_CASE2(Bytes)
+    FIELD_CASE2(String)
+    FIELD_CASE2(Message)
+    FIELD_CASE2(Group)
+  }
+#undef FIELD_CASE
+#undef FIELD_CASE2
+}
+
+static size_t ComputeSerializedSizeIncludingTagOfObject(
+    GPBExtensionDescription *description, id object) {
+#define FIELD_CASE(TYPE, ACCESSOR)                                   \
+  case GPBDataType##TYPE:                                            \
+    return GPBCompute##TYPE##Size(description->fieldNumber,          \
+                                  [(NSNumber *)object ACCESSOR]);
+#define FIELD_CASE2(TYPE)                                            \
+  case GPBDataType##TYPE:                                            \
+    return GPBCompute##TYPE##Size(description->fieldNumber, object);
+  switch (description->dataType) {
+    FIELD_CASE(Bool, boolValue)
+    FIELD_CASE(Float, floatValue)
+    FIELD_CASE(Double, doubleValue)
+    FIELD_CASE(Int32, intValue)
+    FIELD_CASE(SFixed32, intValue)
+    FIELD_CASE(SInt32, intValue)
+    FIELD_CASE(Enum, intValue)
+    FIELD_CASE(Int64, longLongValue)
+    FIELD_CASE(SInt64, longLongValue)
+    FIELD_CASE(SFixed64, longLongValue)
+    FIELD_CASE(UInt32, unsignedIntValue)
+    FIELD_CASE(Fixed32, unsignedIntValue)
+    FIELD_CASE(UInt64, unsignedLongLongValue)
+    FIELD_CASE(Fixed64, unsignedLongLongValue)
+    FIELD_CASE2(Bytes)
+    FIELD_CASE2(String)
+    FIELD_CASE2(Group)
+    case GPBDataTypeMessage:
+      if (GPBExtensionIsWireFormat(description)) {
+        return GPBComputeMessageSetExtensionSize(description->fieldNumber,
+                                                 object);
+      } else {
+        return GPBComputeMessageSize(description->fieldNumber, object);
+      }
+  }
+#undef FIELD_CASE
+#undef FIELD_CASE2
+}
+
+static size_t ComputeSerializedSizeIncludingTagOfArray(
+    GPBExtensionDescription *description, NSArray *values) {
+  if (GPBExtensionIsPacked(description)) {
+    size_t size = 0;
+    size_t typeSize = DataTypeSize(description->dataType);
+    if (typeSize != 0) {
+      size = values.count * typeSize;
+    } else {
+      for (id value in values) {
+        size +=
+            ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
+      }
+    }
+    return size + GPBComputeTagSize(description->fieldNumber) +
+           GPBComputeRawVarint32SizeForInteger(size);
+  } else {
+    size_t size = 0;
+    for (id value in values) {
+      size += ComputeSerializedSizeIncludingTagOfObject(description, value);
+    }
+    return size;
+  }
+}
+
+static void WriteObjectIncludingTagToCodedOutputStream(
+    id object, GPBExtensionDescription *description,
+    GPBCodedOutputStream *output) {
+#define FIELD_CASE(TYPE, ACCESSOR)                      \
+  case GPBDataType##TYPE:                               \
+    [output write##TYPE:description->fieldNumber        \
+                  value:[(NSNumber *)object ACCESSOR]]; \
+    return;
+#define FIELD_CASE2(TYPE)                                       \
+  case GPBDataType##TYPE:                                       \
+    [output write##TYPE:description->fieldNumber value:object]; \
+    return;
+  switch (description->dataType) {
+    FIELD_CASE(Bool, boolValue)
+    FIELD_CASE(Float, floatValue)
+    FIELD_CASE(Double, doubleValue)
+    FIELD_CASE(Int32, intValue)
+    FIELD_CASE(SFixed32, intValue)
+    FIELD_CASE(SInt32, intValue)
+    FIELD_CASE(Enum, intValue)
+    FIELD_CASE(Int64, longLongValue)
+    FIELD_CASE(SInt64, longLongValue)
+    FIELD_CASE(SFixed64, longLongValue)
+    FIELD_CASE(UInt32, unsignedIntValue)
+    FIELD_CASE(Fixed32, unsignedIntValue)
+    FIELD_CASE(UInt64, unsignedLongLongValue)
+    FIELD_CASE(Fixed64, unsignedLongLongValue)
+    FIELD_CASE2(Bytes)
+    FIELD_CASE2(String)
+    FIELD_CASE2(Group)
+    case GPBDataTypeMessage:
+      if (GPBExtensionIsWireFormat(description)) {
+        [output writeMessageSetExtension:description->fieldNumber value:object];
+      } else {
+        [output writeMessage:description->fieldNumber value:object];
+      }
+      return;
+  }
+#undef FIELD_CASE
+#undef FIELD_CASE2
+}
+
+static void WriteObjectNoTagToCodedOutputStream(
+    id object, GPBExtensionDescription *description,
+    GPBCodedOutputStream *output) {
+#define FIELD_CASE(TYPE, ACCESSOR)                             \
+  case GPBDataType##TYPE:                                      \
+    [output write##TYPE##NoTag:[(NSNumber *)object ACCESSOR]]; \
+    return;
+#define FIELD_CASE2(TYPE)               \
+  case GPBDataType##TYPE:               \
+    [output write##TYPE##NoTag:object]; \
+    return;
+  switch (description->dataType) {
+    FIELD_CASE(Bool, boolValue)
+    FIELD_CASE(Float, floatValue)
+    FIELD_CASE(Double, doubleValue)
+    FIELD_CASE(Int32, intValue)
+    FIELD_CASE(SFixed32, intValue)
+    FIELD_CASE(SInt32, intValue)
+    FIELD_CASE(Enum, intValue)
+    FIELD_CASE(Int64, longLongValue)
+    FIELD_CASE(SInt64, longLongValue)
+    FIELD_CASE(SFixed64, longLongValue)
+    FIELD_CASE(UInt32, unsignedIntValue)
+    FIELD_CASE(Fixed32, unsignedIntValue)
+    FIELD_CASE(UInt64, unsignedLongLongValue)
+    FIELD_CASE(Fixed64, unsignedLongLongValue)
+    FIELD_CASE2(Bytes)
+    FIELD_CASE2(String)
+    FIELD_CASE2(Message)
+    case GPBDataTypeGroup:
+      [output writeGroupNoTag:description->fieldNumber value:object];
+      return;
+  }
+#undef FIELD_CASE
+#undef FIELD_CASE2
+}
+
+static void WriteArrayIncludingTagsToCodedOutputStream(
+    NSArray *values, GPBExtensionDescription *description,
+    GPBCodedOutputStream *output) {
+  if (GPBExtensionIsPacked(description)) {
+    [output writeTag:description->fieldNumber
+              format:GPBWireFormatLengthDelimited];
+    size_t dataSize = 0;
+    size_t typeSize = DataTypeSize(description->dataType);
+    if (typeSize != 0) {
+      dataSize = values.count * typeSize;
+    } else {
+      for (id value in values) {
+        dataSize +=
+            ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
+      }
+    }
+    [output writeRawVarintSizeTAs32:dataSize];
+    for (id value in values) {
+      WriteObjectNoTagToCodedOutputStream(value, description, output);
+    }
+  } else {
+    for (id value in values) {
+      WriteObjectIncludingTagToCodedOutputStream(value, description, output);
+    }
+  }
+}
+
+void GPBExtensionMergeFromInputStream(GPBExtensionDescriptor *extension,
+                                      BOOL isPackedOnStream,
+                                      GPBCodedInputStream *input,
+                                      GPBExtensionRegistry *extensionRegistry,
+                                      GPBMessage *message) {
+  GPBExtensionDescription *description = extension->description_;
+  GPBCodedInputStreamState *state = &input->state_;
+  if (isPackedOnStream) {
+    NSCAssert(GPBExtensionIsRepeated(description),
+              @"How was it packed if it isn't repeated?");
+    int32_t length = GPBCodedInputStreamReadInt32(state);
+    size_t limit = GPBCodedInputStreamPushLimit(state, length);
+    while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
+      id value = NewSingleValueFromInputStream(extension,
+                                               input,
+                                               extensionRegistry,
+                                               nil);
+      [message addExtension:extension value:value];
+      [value release];
+    }
+    GPBCodedInputStreamPopLimit(state, limit);
+  } else {
+    id existingValue = nil;
+    BOOL isRepeated = GPBExtensionIsRepeated(description);
+    if (!isRepeated && GPBDataTypeIsMessage(description->dataType)) {
+      existingValue = [message getExistingExtension:extension];
+    }
+    id value = NewSingleValueFromInputStream(extension,
+                                             input,
+                                             extensionRegistry,
+                                             existingValue);
+    if (isRepeated) {
+      [message addExtension:extension value:value];
+    } else {
+      [message setExtension:extension value:value];
+    }
+    [value release];
+  }
+}
+
+void GPBWriteExtensionValueToOutputStream(GPBExtensionDescriptor *extension,
+                                          id value,
+                                          GPBCodedOutputStream *output) {
+  GPBExtensionDescription *description = extension->description_;
+  if (GPBExtensionIsRepeated(description)) {
+    WriteArrayIncludingTagsToCodedOutputStream(value, description, output);
+  } else {
+    WriteObjectIncludingTagToCodedOutputStream(value, description, output);
+  }
+}
+
+size_t GPBComputeExtensionSerializedSizeIncludingTag(
+    GPBExtensionDescriptor *extension, id value) {
+  GPBExtensionDescription *description = extension->description_;
+  if (GPBExtensionIsRepeated(description)) {
+    return ComputeSerializedSizeIncludingTagOfArray(description, value);
+  } else {
+    return ComputeSerializedSizeIncludingTagOfObject(description, value);
+  }
+}
+
+// Note that this returns a retained value intentionally.
+static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
+                                        GPBCodedInputStream *input,
+                                        GPBExtensionRegistry *extensionRegistry,
+                                        GPBMessage *existingValue) {
+  GPBExtensionDescription *description = extension->description_;
+  GPBCodedInputStreamState *state = &input->state_;
+  switch (description->dataType) {
+    case GPBDataTypeBool:     return [[NSNumber alloc] initWithBool:GPBCodedInputStreamReadBool(state)];
+    case GPBDataTypeFixed32:  return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadFixed32(state)];
+    case GPBDataTypeSFixed32: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSFixed32(state)];
+    case GPBDataTypeFloat:    return [[NSNumber alloc] initWithFloat:GPBCodedInputStreamReadFloat(state)];
+    case GPBDataTypeFixed64:  return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadFixed64(state)];
+    case GPBDataTypeSFixed64: return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSFixed64(state)];
+    case GPBDataTypeDouble:   return [[NSNumber alloc] initWithDouble:GPBCodedInputStreamReadDouble(state)];
+    case GPBDataTypeInt32:    return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadInt32(state)];
+    case GPBDataTypeInt64:    return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadInt64(state)];
+    case GPBDataTypeSInt32:   return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSInt32(state)];
+    case GPBDataTypeSInt64:   return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSInt64(state)];
+    case GPBDataTypeUInt32:   return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadUInt32(state)];
+    case GPBDataTypeUInt64:   return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadUInt64(state)];
+    case GPBDataTypeBytes:    return GPBCodedInputStreamReadRetainedBytes(state);
+    case GPBDataTypeString:   return GPBCodedInputStreamReadRetainedString(state);
+    case GPBDataTypeEnum:     return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadEnum(state)];
+    case GPBDataTypeGroup:
+    case GPBDataTypeMessage: {
+      GPBMessage *message;
+      if (existingValue) {
+        message = [existingValue retain];
+      } else {
+        GPBDescriptor *decriptor = [extension.msgClass descriptor];
+        message = [[decriptor.messageClass alloc] init];
+      }
+
+      if (description->dataType == GPBDataTypeGroup) {
+        [input readGroup:description->fieldNumber
+                 message:message
+            extensionRegistry:extensionRegistry];
+      } else {
+        // description->dataType == GPBDataTypeMessage
+        if (GPBExtensionIsWireFormat(description)) {
+          // For MessageSet fields the message length will have already been
+          // read.
+          [message mergeFromCodedInputStream:input
+                           extensionRegistry:extensionRegistry];
+        } else {
+          [input readMessage:message extensionRegistry:extensionRegistry];
+        }
+      }
+
+      return message;
+    }
+  }
+
+  return nil;
+}
diff --git a/objectivec/GPBExtensionRegistry.h b/objectivec/GPBExtensionRegistry.h
new file mode 100644
index 0000000..08a6472
--- /dev/null
+++ b/objectivec/GPBExtensionRegistry.h
@@ -0,0 +1,82 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+@class GPBDescriptor;
+@class GPBExtensionDescriptor;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A table of known extensions, searchable by name or field number.  When
+/// parsing a protocol message that might have extensions, you must provide a
+/// @c GPBExtensionRegistry in which you have registered any extensions that you
+/// want to be able to parse. Otherwise, those extensions will just be treated
+/// like unknown fields.
+///
+/// The @c *Root classes provide @c +extensionRegistry for the extensions defined
+/// in a given file *and* all files it imports. You can also create a
+/// @c GPBExtensionRegistry, and merge those registries to handle parsing
+/// extensions defined from non overlapping files.
+///
+/// @code
+/// GPBExtensionRegistry *registry =
+///     [[[MyProtoFileRoot extensionRegistry] copy] autorelease];
+/// [registry addExtension:[OtherMessage neededExtension];  // Not in MyProtoFile
+/// NSError *parseError = nil;
+/// MyMessage *msg = [MyMessage parseData:data
+///                     extensionRegistry:registry
+///                                 error:&parseError];
+/// @endcode
+@interface GPBExtensionRegistry : NSObject<NSCopying>
+
+/// Add the given @c GPBExtensionDescriptor to this registry.
+///
+/// @param extension The extension description to add.
+- (void)addExtension:(GPBExtensionDescriptor *)extension;
+
+/// Adds all the extensions from another registry to this registry.
+///
+/// @param registry The registry to merge into this registry.
+- (void)addExtensions:(GPBExtensionRegistry *)registry;
+
+/// Looks for the extension registered for the given field number on a given
+/// @c GPBDescriptor.
+///
+/// @param descriptor  The descriptor to look for a registered extension on.
+/// @param fieldNumber The field number of an extension to look for.
+///
+/// @return The registered @c GPBExtensionDescripto or nil if none was found.
+- (nullable GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
+                                                fieldNumber:(NSInteger)fieldNumber;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBExtensionRegistry.m b/objectivec/GPBExtensionRegistry.m
new file mode 100644
index 0000000..df61a17
--- /dev/null
+++ b/objectivec/GPBExtensionRegistry.m
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBExtensionRegistry.h"
+
+#import "GPBBootstrap.h"
+#import "GPBDescriptor.h"
+
+@implementation GPBExtensionRegistry {
+  // TODO(dmaclach): Reimplement with CFDictionaries that don't use
+  // objects as keys.
+  NSMutableDictionary *mutableClassMap_;
+}
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    mutableClassMap_ = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [mutableClassMap_ release];
+  [super dealloc];
+}
+
+- (instancetype)copyWithZone:(NSZone *)zone {
+  GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
+  if (result && mutableClassMap_.count) {
+    [result->mutableClassMap_ addEntriesFromDictionary:mutableClassMap_];
+  }
+  return result;
+}
+
+- (NSMutableDictionary *)extensionMapForContainingMessageClass:
+        (Class)containingMessageClass {
+  NSMutableDictionary *extensionMap =
+      [mutableClassMap_ objectForKey:containingMessageClass];
+  if (extensionMap == nil) {
+    extensionMap = [NSMutableDictionary dictionary];
+    [mutableClassMap_ setObject:extensionMap
+                         forKey:(id<NSCopying>)containingMessageClass];
+  }
+  return extensionMap;
+}
+
+- (void)addExtension:(GPBExtensionDescriptor *)extension {
+  if (extension == nil) {
+    return;
+  }
+
+  Class containingMessageClass = extension.containingMessageClass;
+  NSMutableDictionary *extensionMap =
+      [self extensionMapForContainingMessageClass:containingMessageClass];
+  [extensionMap setObject:extension forKey:@(extension.fieldNumber)];
+}
+
+- (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
+                                       fieldNumber:(NSInteger)fieldNumber {
+  Class messageClass = descriptor.messageClass;
+  NSDictionary *extensionMap =
+      [mutableClassMap_ objectForKey:messageClass];
+  return [extensionMap objectForKey:@(fieldNumber)];
+}
+
+- (void)addExtensions:(GPBExtensionRegistry *)registry {
+  if (registry == nil) {
+    // In the case where there are no extensions just ignore.
+    return;
+  }
+  NSMutableDictionary *otherClassMap = registry->mutableClassMap_;
+  for (Class containingMessageClass in otherClassMap) {
+    NSMutableDictionary *extensionMap =
+        [self extensionMapForContainingMessageClass:containingMessageClass];
+    NSMutableDictionary *otherExtensionMap =
+        [registry extensionMapForContainingMessageClass:containingMessageClass];
+    [extensionMap addEntriesFromDictionary:otherExtensionMap];
+  }
+}
+
+@end
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
new file mode 100644
index 0000000..58c42d0
--- /dev/null
+++ b/objectivec/GPBMessage.h
@@ -0,0 +1,308 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBBootstrap.h"
+
+@class GPBDescriptor;
+@class GPBCodedInputStream;
+@class GPBCodedOutputStream;
+@class GPBExtensionDescriptor;
+@class GPBExtensionRegistry;
+@class GPBFieldDescriptor;
+@class GPBUnknownFieldSet;
+
+NS_ASSUME_NONNULL_BEGIN
+
+CF_EXTERN_C_BEGIN
+
+/// NSError domain used for errors.
+extern NSString *const GPBMessageErrorDomain;
+
+/// Error code for NSError with GPBMessageErrorDomain.
+typedef NS_ENUM(NSInteger, GPBMessageErrorCode) {
+  /// The data being parsed is bad and a message can not be created from it.
+  GPBMessageErrorCodeMalformedData = -100,
+  /// A message can't be serialized because it is missing required fields.
+  GPBMessageErrorCodeMissingRequiredField = -101,
+};
+
+#ifdef DEBUG
+/// In DEBUG ONLY, an NSException is thrown when a parsed message doesn't
+/// contain required fields. This key allows you to retrieve the parsed message
+/// from the exception's @c userInfo dictionary.
+extern NSString *const GPBExceptionMessageKey;
+#endif  // DEBUG
+
+CF_EXTERN_C_END
+
+/// Base class for all of the generated message classes.
+@interface GPBMessage : NSObject<NSSecureCoding, NSCopying>
+
+// NOTE: If you add a instance method/property to this class that may conflict
+// with methods declared in protos, you need to update objective_helpers.cc.
+// The main cases are methods that take no arguments, or setFoo:/hasFoo: type
+// methods.
+
+/// The unknown fields for this message.
+///
+/// Only messages from proto files declared with "proto2" syntax support unknown
+/// fields. For "proto3" syntax, any unknown fields found while parsing are
+/// dropped.
+@property(nonatomic, copy, nullable) GPBUnknownFieldSet *unknownFields;
+
+/// Are all required fields set in the message and all embedded messages.
+@property(nonatomic, readonly, getter=isInitialized) BOOL initialized;
+
+/// Returns an autoreleased instance.
++ (instancetype)message;
+
+/// Creates a new instance by parsing the data. This method should be sent to
+/// the generated message class that the data should be interpreted as. If
+/// there is an error the method returns nil and the error is returned in
+/// errorPtr (when provided).
+///
+/// @note In DEBUG builds, the parsed message is checked to be sure all required
+///       fields were provided, and the parse will fail if some are missing.
+///
+/// @param data     The data to parse.
+/// @param errorPtr An optional error pointer to fill in with a failure reason if
+///                 the data can not be parsed.
+///
+/// @return A new instance of the class messaged.
++ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr;
+
+/// Creates a new instance by parsing the data. This method should be sent to
+/// the generated message class that the data should be interpreted as. If
+/// there is an error the method returns nil and the error is returned in
+/// errorPtr (when provided).
+///
+/// @note In DEBUG builds, the parsed message is checked to be sure all required
+///       fields were provided, and the parse will fail if some are missing.
+///
+/// @param data              The data to parse.
+/// @param extensionRegistry The extension registry to use to look up extensions.
+/// @param errorPtr          An optional error pointer to fill in with a failure
+///                          reason if the data can not be parsed.
+///
+/// @return A new instance of the class messaged.
++ (instancetype)parseFromData:(NSData *)data
+            extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
+                        error:(NSError **)errorPtr;
+
+/// Creates a new instance by parsing the data from the given input stream. This
+/// method should be sent to the generated message class that the data should
+/// be interpreted as. If there is an error the method returns nil and the error
+/// is returned in errorPtr (when provided).
+///
+/// @note In DEBUG builds, the parsed message is checked to be sure all required
+///       fields were provided, and the parse will fail if some are missing.
+///
+/// @param input             The stream to read data from.
+/// @param extensionRegistry The extension registry to use to look up extensions.
+/// @param errorPtr          An optional error pointer to fill in with a failure
+///                          reason if the data can not be parsed.
+///
+/// @return A new instance of the class messaged.
++ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
+                        extensionRegistry:
+                            (nullable GPBExtensionRegistry *)extensionRegistry
+                                    error:(NSError **)errorPtr;
+
+/// Creates a new instance by parsing the data from the given input stream. This
+/// method should be sent to the generated message class that the data should
+/// be interpreted as. If there is an error the method returns nil and the error
+/// is returned in errorPtr (when provided).
+///
+/// @note Unlike the parseFrom... methods, this never checks to see if all of
+///       the required fields are set. So this method can be used to reload
+///       messages that may not be complete.
+///
+/// @param input             The stream to read data from.
+/// @param extensionRegistry The extension registry to use to look up extensions.
+/// @param errorPtr          An optional error pointer to fill in with a failure
+///                          reason if the data can not be parsed.
+///
+/// @return A new instance of the class messaged.
++ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
+                                 extensionRegistry:
+                                     (nullable GPBExtensionRegistry *)extensionRegistry
+                                             error:(NSError **)errorPtr;
+
+/// Initializes an instance by parsing the data. This method should be sent to
+/// the generated message class that the data should be interpreted as. If
+/// there is an error the method returns nil and the error is returned in
+/// errorPtr (when provided).
+///
+/// @note In DEBUG builds, the parsed message is checked to be sure all required
+///       fields were provided, and the parse will fail if some are missing.
+///
+/// @param data     The data to parse.
+/// @param errorPtr An optional error pointer to fill in with a failure reason if
+///                 the data can not be parsed.
+- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr;
+
+/// Initializes an instance by parsing the data. This method should be sent to
+/// the generated message class that the data should be interpreted as. If
+/// there is an error the method returns nil and the error is returned in
+/// errorPtr (when provided).
+///
+/// @note In DEBUG builds, the parsed message is checked to be sure all required
+///       fields were provided, and the parse will fail if some are missing.
+///
+/// @param data              The data to parse.
+/// @param extensionRegistry The extension registry to use to look up extensions.
+/// @param errorPtr          An optional error pointer to fill in with a failure
+///                          reason if the data can not be parsed.
+- (instancetype)initWithData:(NSData *)data
+           extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
+                       error:(NSError **)errorPtr;
+
+/// Initializes an instance by parsing the data from the given input stream. This
+/// method should be sent to the generated message class that the data should
+/// be interpreted as. If there is an error the method returns nil and the error
+/// is returned in errorPtr (when provided).
+///
+/// @note Unlike the parseFrom... methods, this never checks to see if all of
+///       the required fields are set. So this method can be used to reload
+///       messages that may not be complete.
+///
+/// @param input             The stream to read data from.
+/// @param extensionRegistry The extension registry to use to look up extensions.
+/// @param errorPtr          An optional error pointer to fill in with a failure
+///                          reason if the data can not be parsed.
+- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
+                       extensionRegistry:
+                           (nullable GPBExtensionRegistry *)extensionRegistry
+                                   error:(NSError **)errorPtr;
+
+/// Writes out the message to the given output stream.
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
+/// Writes out the message to the given output stream.
+- (void)writeToOutputStream:(NSOutputStream *)output;
+
+/// Writes out a varint for the message size followed by the the message to
+/// the given output stream.
+- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
+/// Writes out a varint for the message size followed by the the message to
+/// the given output stream.
+- (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
+
+/// Serializes the message to a @c NSData.
+///
+/// If there is an error while generating the data, nil is returned.
+///
+/// @note This value is not cached, so if you are using it repeatedly, cache
+///       it yourself.
+///
+/// @note In DEBUG ONLY, the message is also checked for all required field,
+///       if one is missing, nil will be returned.
+- (nullable NSData *)data;
+
+/// Serializes a varint with the message size followed by the message data,
+/// returning that as a @c NSData.
+///
+/// @note This value is not cached, so if you are using it repeatedly, cache
+///       it yourself.
+- (NSData *)delimitedData;
+
+/// Calculates the size of the object if it were serialized.
+///
+/// This is not a cached value. If you are following a pattern like this:
+/// @code
+///   size_t size = [aMsg serializedSize];
+///   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+///   [foo writeSize:size];
+///   [foo appendData:[aMsg data]];
+/// @endcode
+/// you would be better doing:
+/// @code
+///   NSData *data = [aMsg data];
+///   NSUInteger size = [aMsg length];
+///   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+///   [foo writeSize:size];
+///   [foo appendData:data];
+/// @endcode
+- (size_t)serializedSize;
+
+/// Return the descriptor for the message class.
++ (GPBDescriptor *)descriptor;
+/// Return the descriptor for the message.
+- (GPBDescriptor *)descriptor;
+
+/// Test to see if the given extension is set on the message.
+- (BOOL)hasExtension:(GPBExtensionDescriptor *)extension;
+
+/// Fetches the given extension's value for this message.
+///
+/// Extensions use boxed values (NSNumbers) for PODs and NSMutableArrays for
+/// repeated fields. If the extension is a Message one will be auto created for you
+/// and returned similar to fields.
+- (nullable id)getExtension:(GPBExtensionDescriptor *)extension;
+
+/// Sets the given extension's value for this message. This is only for single
+/// field extensions (i.e. - not repeated fields).
+///
+/// Extensions use boxed values (@c NSNumbers).
+- (void)setExtension:(GPBExtensionDescriptor *)extension value:(nullable id)value;
+
+/// Adds the given value to the extension for this message. This is only for
+/// repeated field extensions. If the field is a repeated POD type the @c value
+/// is a @c NSNumber.
+- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value;
+
+/// Replaces the given value at an index for the extension on this message. This
+/// is only for repeated field extensions. If the field is a repeated POD type
+/// the @c value is a @c NSNumber.
+- (void)setExtension:(GPBExtensionDescriptor *)extension
+               index:(NSUInteger)index
+               value:(id)value;
+
+/// Clears the given extension for this message.
+- (void)clearExtension:(GPBExtensionDescriptor *)extension;
+
+/// Resets all of the fields of this message to their default values.
+- (void)clear;
+
+/// Parses a message of this type from the input and merges it with this
+/// message.
+///
+/// @note This will throw if there is an error parsing the data.
+- (void)mergeFromData:(NSData *)data
+    extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry;
+
+/// Merges the fields from another message (of the same type) into this
+/// message.
+- (void)mergeFrom:(GPBMessage *)other;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
new file mode 100644
index 0000000..8134e25
--- /dev/null
+++ b/objectivec/GPBMessage.m
@@ -0,0 +1,3184 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBMessage_PackagePrivate.h"
+
+#import <objc/runtime.h>
+#import <objc/message.h>
+
+#import "GPBArray_PackagePrivate.h"
+#import "GPBCodedInputStream_PackagePrivate.h"
+#import "GPBCodedOutputStream_PackagePrivate.h"
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBDictionary_PackagePrivate.h"
+#import "GPBExtensionInternals.h"
+#import "GPBExtensionRegistry.h"
+#import "GPBRootObject_PackagePrivate.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+NSString *const GPBMessageErrorDomain =
+    GPBNSStringifySymbol(GPBMessageErrorDomain);
+
+#ifdef DEBUG
+NSString *const GPBExceptionMessageKey =
+    GPBNSStringifySymbol(GPBExceptionMessage);
+#endif  // DEBUG
+
+static NSString *const kGPBDataCoderKey = @"GPBData";
+
+//
+// PLEASE REMEMBER:
+//
+// This is the base class for *all* messages generated, so any selector defined,
+// *public* or *private* could end up colliding with a proto message field. So
+// avoid using selectors that could match a property, use C functions to hide
+// them, etc.
+//
+
+@interface GPBMessage () {
+ @package
+  GPBUnknownFieldSet *unknownFields_;
+  NSMutableDictionary *extensionMap_;
+  NSMutableDictionary *autocreatedExtensionMap_;
+
+  // If the object was autocreated, we remember the creator so that if we get
+  // mutated, we can inform the creator to make our field visible.
+  GPBMessage *autocreator_;
+  GPBFieldDescriptor *autocreatorField_;
+  GPBExtensionDescriptor *autocreatorExtension_;
+}
+@end
+
+static id CreateArrayForField(GPBFieldDescriptor *field,
+                              GPBMessage *autocreator)
+    __attribute__((ns_returns_retained));
+static id GetOrCreateArrayIvarWithField(GPBMessage *self,
+                                        GPBFieldDescriptor *field,
+                                        GPBFileSyntax syntax);
+static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
+static id CreateMapForField(GPBFieldDescriptor *field,
+                            GPBMessage *autocreator)
+    __attribute__((ns_returns_retained));
+static id GetOrCreateMapIvarWithField(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      GPBFileSyntax syntax);
+static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
+static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
+                                              NSZone *zone)
+    __attribute__((ns_returns_retained));
+
+static NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
+  return [NSError errorWithDomain:GPBMessageErrorDomain
+                             code:code
+                         userInfo:userInfo];
+}
+
+static NSError *MessageErrorWithReason(NSInteger code, NSString *reason) {
+  NSDictionary *userInfo = nil;
+  if ([reason length]) {
+    userInfo = @{ @"Reason" : reason };
+  }
+  return MessageError(code, userInfo);
+}
+
+
+static void CheckExtension(GPBMessage *self,
+                           GPBExtensionDescriptor *extension) {
+  if ([self class] != extension.containingMessageClass) {
+    [NSException
+         raise:NSInvalidArgumentException
+        format:@"Extension %@ used on wrong class (%@ instead of %@)",
+               extension.singletonName,
+               [self class], extension.containingMessageClass];
+  }
+}
+
+static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
+                                              NSZone *zone) {
+  if (extensionMap.count == 0) {
+    return nil;
+  }
+  NSMutableDictionary *result = [[NSMutableDictionary allocWithZone:zone]
+      initWithCapacity:extensionMap.count];
+
+  for (GPBExtensionDescriptor *extension in extensionMap) {
+    id value = [extensionMap objectForKey:extension];
+    BOOL isMessageExtension = GPBExtensionIsMessage(extension);
+
+    if (extension.repeated) {
+      if (isMessageExtension) {
+        NSMutableArray *list =
+            [[NSMutableArray alloc] initWithCapacity:[value count]];
+        for (GPBMessage *listValue in value) {
+          GPBMessage *copiedValue = [listValue copyWithZone:zone];
+          [list addObject:copiedValue];
+          [copiedValue release];
+        }
+        [result setObject:list forKey:extension];
+        [list release];
+      } else {
+        NSMutableArray *copiedValue = [value mutableCopyWithZone:zone];
+        [result setObject:copiedValue forKey:extension];
+        [copiedValue release];
+      }
+    } else {
+      if (isMessageExtension) {
+        GPBMessage *copiedValue = [value copyWithZone:zone];
+        [result setObject:copiedValue forKey:extension];
+        [copiedValue release];
+      } else {
+        [result setObject:value forKey:extension];
+      }
+    }
+  }
+
+  return result;
+}
+
+static id CreateArrayForField(GPBFieldDescriptor *field,
+                              GPBMessage *autocreator) {
+  id result;
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  switch (fieldDataType) {
+    case GPBDataTypeBool:
+      result = [[GPBBoolArray alloc] init];
+      break;
+    case GPBDataTypeFixed32:
+    case GPBDataTypeUInt32:
+      result = [[GPBUInt32Array alloc] init];
+      break;
+    case GPBDataTypeInt32:
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeSInt32:
+      result = [[GPBInt32Array alloc] init];
+      break;
+    case GPBDataTypeFixed64:
+    case GPBDataTypeUInt64:
+      result = [[GPBUInt64Array alloc] init];
+      break;
+    case GPBDataTypeInt64:
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeSInt64:
+      result = [[GPBInt64Array alloc] init];
+      break;
+    case GPBDataTypeFloat:
+      result = [[GPBFloatArray alloc] init];
+      break;
+    case GPBDataTypeDouble:
+      result = [[GPBDoubleArray alloc] init];
+      break;
+
+    case GPBDataTypeEnum:
+      result = [[GPBEnumArray alloc]
+                  initWithValidationFunction:field.enumDescriptor.enumVerifier];
+      break;
+
+    case GPBDataTypeBytes:
+    case GPBDataTypeGroup:
+    case GPBDataTypeMessage:
+    case GPBDataTypeString:
+      if (autocreator) {
+        result = [[GPBAutocreatedArray alloc] init];
+      } else {
+        result = [[NSMutableArray alloc] init];
+      }
+      break;
+  }
+
+  if (autocreator) {
+    if (GPBDataTypeIsObject(fieldDataType)) {
+      GPBAutocreatedArray *autoArray = result;
+      autoArray->_autocreator =  autocreator;
+    } else {
+      GPBInt32Array *gpbArray = result;
+      gpbArray->_autocreator = autocreator;
+    }
+  }
+
+  return result;
+}
+
+static id CreateMapForField(GPBFieldDescriptor *field,
+                            GPBMessage *autocreator) {
+  id result;
+  GPBDataType keyDataType = field.mapKeyDataType;
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  switch (keyDataType) {
+    case GPBDataTypeBool:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBBoolBoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBBoolUInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBBoolInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBBoolUInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBBoolInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBBoolFloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBBoolDoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBBoolEnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          result = [[GPBBoolObjectDictionary alloc] init];
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBDataTypeFixed32:
+    case GPBDataTypeUInt32:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBUInt32BoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBUInt32UInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBUInt32Int32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBUInt32UInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBUInt32Int64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBUInt32FloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBUInt32DoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBUInt32EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          result = [[GPBUInt32ObjectDictionary alloc] init];
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBDataTypeInt32:
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeSInt32:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBInt32BoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBInt32UInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBInt32Int32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBInt32UInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBInt32Int64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBInt32FloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBInt32DoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBInt32EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          result = [[GPBInt32ObjectDictionary alloc] init];
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBDataTypeFixed64:
+    case GPBDataTypeUInt64:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBUInt64BoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBUInt64UInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBUInt64Int32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBUInt64UInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBUInt64Int64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBUInt64FloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBUInt64DoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBUInt64EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          result = [[GPBUInt64ObjectDictionary alloc] init];
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBDataTypeInt64:
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeSInt64:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBInt64BoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBInt64UInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBInt64Int32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBInt64UInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBInt64Int64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBInt64FloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBInt64DoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBInt64EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          result = [[GPBInt64ObjectDictionary alloc] init];
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBDataTypeString:
+      switch (valueDataType) {
+        case GPBDataTypeBool:
+          result = [[GPBStringBoolDictionary alloc] init];
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          result = [[GPBStringUInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt32:
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeSInt32:
+          result = [[GPBStringInt32Dictionary alloc] init];
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          result = [[GPBStringUInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeInt64:
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeSInt64:
+          result = [[GPBStringInt64Dictionary alloc] init];
+          break;
+        case GPBDataTypeFloat:
+          result = [[GPBStringFloatDictionary alloc] init];
+          break;
+        case GPBDataTypeDouble:
+          result = [[GPBStringDoubleDictionary alloc] init];
+          break;
+        case GPBDataTypeEnum:
+          result = [[GPBStringEnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeMessage:
+        case GPBDataTypeString:
+          if (autocreator) {
+            result = [[GPBAutocreatedDictionary alloc] init];
+          } else {
+            result = [[NSMutableDictionary alloc] init];
+          }
+          break;
+        case GPBDataTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+
+    case GPBDataTypeFloat:
+    case GPBDataTypeDouble:
+    case GPBDataTypeEnum:
+    case GPBDataTypeBytes:
+    case GPBDataTypeGroup:
+    case GPBDataTypeMessage:
+      NSCAssert(NO, @"shouldn't happen");
+      return nil;
+  }
+
+  if (autocreator) {
+    if ((keyDataType == GPBDataTypeString) &&
+        GPBDataTypeIsObject(valueDataType)) {
+      GPBAutocreatedDictionary *autoDict = result;
+      autoDict->_autocreator =  autocreator;
+    } else {
+      GPBInt32Int32Dictionary *gpbDict = result;
+      gpbDict->_autocreator = autocreator;
+    }
+  }
+
+  return result;
+}
+
+#if !defined(__clang_analyzer__)
+// These functions are blocked from the analyzer because the analyzer sees the
+// GPBSetRetainedObjectIvarWithFieldInternal() call as consuming the array/map,
+// so use of the array/map after the call returns is flagged as a use after
+// free.
+// But GPBSetRetainedObjectIvarWithFieldInternal() is "consuming" the retain
+// count be holding onto the object (it is transfering it), the object is
+// still valid after returning from the call.  The other way to avoid this
+// would be to add a -retain/-autorelease, but that would force every
+// repeated/map field parsed into the autorelease pool which is both a memory
+// and performance hit.
+
+static id GetOrCreateArrayIvarWithField(GPBMessage *self,
+                                        GPBFieldDescriptor *field,
+                                        GPBFileSyntax syntax) {
+  id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!array) {
+    // No lock needed, this is called from places expecting to mutate
+    // so no threading protection is needed.
+    array = CreateArrayForField(field, nil);
+    GPBSetRetainedObjectIvarWithFieldInternal(self, field, array, syntax);
+  }
+  return array;
+}
+
+// This is like GPBGetObjectIvarWithField(), but for arrays, it should
+// only be used to wire the method into the class.
+static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
+  id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!array) {
+    // Check again after getting the lock.
+    GPBPrepareReadOnlySemaphore(self);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
+    array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+    if (!array) {
+      array = CreateArrayForField(field, self);
+      GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array);
+    }
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
+  }
+  return array;
+}
+
+static id GetOrCreateMapIvarWithField(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      GPBFileSyntax syntax) {
+  id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!dict) {
+    // No lock needed, this is called from places expecting to mutate
+    // so no threading protection is needed.
+    dict = CreateMapForField(field, nil);
+    GPBSetRetainedObjectIvarWithFieldInternal(self, field, dict, syntax);
+  }
+  return dict;
+}
+
+// This is like GPBGetObjectIvarWithField(), but for maps, it should
+// only be used to wire the method into the class.
+static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
+  id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!dict) {
+    // Check again after getting the lock.
+    GPBPrepareReadOnlySemaphore(self);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
+    dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+    if (!dict) {
+      dict = CreateMapForField(field, self);
+      GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict);
+    }
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
+  }
+  return dict;
+}
+
+#endif  // !defined(__clang_analyzer__)
+
+GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
+                                            GPBMessage *autocreator,
+                                            GPBFieldDescriptor *field) {
+  GPBMessage *message = [[msgClass alloc] init];
+  message->autocreator_ = autocreator;
+  message->autocreatorField_ = [field retain];
+  return message;
+}
+
+static GPBMessage *CreateMessageWithAutocreatorForExtension(
+    Class msgClass, GPBMessage *autocreator, GPBExtensionDescriptor *extension)
+    __attribute__((ns_returns_retained));
+
+static GPBMessage *CreateMessageWithAutocreatorForExtension(
+    Class msgClass, GPBMessage *autocreator,
+    GPBExtensionDescriptor *extension) {
+  GPBMessage *message = [[msgClass alloc] init];
+  message->autocreator_ = autocreator;
+  message->autocreatorExtension_ = [extension retain];
+  return message;
+}
+
+BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) {
+  return (message->autocreator_ == parent);
+}
+
+void GPBBecomeVisibleToAutocreator(GPBMessage *self) {
+  // Message objects that are implicitly created by accessing a message field
+  // are initially not visible via the hasX selector. This method makes them
+  // visible.
+  if (self->autocreator_) {
+    // This will recursively make all parent messages visible until it reaches a
+    // super-creator that's visible.
+    if (self->autocreatorField_) {
+      GPBFileSyntax syntax = [self->autocreator_ descriptor].file.syntax;
+      GPBSetObjectIvarWithFieldInternal(self->autocreator_,
+                                        self->autocreatorField_, self, syntax);
+    } else {
+      [self->autocreator_ setExtension:self->autocreatorExtension_ value:self];
+    }
+  }
+}
+
+void GPBAutocreatedArrayModified(GPBMessage *self, id array) {
+  // When one of our autocreated arrays adds elements, make it visible.
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (field.fieldType == GPBFieldTypeRepeated) {
+      id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      if (curArray == array) {
+        if (GPBFieldDataTypeIsObject(field)) {
+          GPBAutocreatedArray *autoArray = array;
+          autoArray->_autocreator = nil;
+        } else {
+          GPBInt32Array *gpbArray = array;
+          gpbArray->_autocreator = nil;
+        }
+        GPBBecomeVisibleToAutocreator(self);
+        return;
+      }
+    }
+  }
+  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self);
+}
+
+void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) {
+  // When one of our autocreated dicts adds elements, make it visible.
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (field.fieldType == GPBFieldTypeMap) {
+      id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      if (curDict == dictionary) {
+        if ((field.mapKeyDataType == GPBDataTypeString) &&
+            GPBFieldDataTypeIsObject(field)) {
+          GPBAutocreatedDictionary *autoDict = dictionary;
+          autoDict->_autocreator = nil;
+        } else {
+          GPBInt32Int32Dictionary *gpbDict = dictionary;
+          gpbDict->_autocreator = nil;
+        }
+        GPBBecomeVisibleToAutocreator(self);
+        return;
+      }
+    }
+  }
+  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self);
+}
+
+void GPBClearMessageAutocreator(GPBMessage *self) {
+  if ((self == nil) || !self->autocreator_) {
+    return;
+  }
+
+#if DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+  // Either the autocreator must have its "has" flag set to YES, or it must be
+  // NO and not equal to ourselves.
+  BOOL autocreatorHas =
+      (self->autocreatorField_
+           ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_)
+           : [self->autocreator_ hasExtension:self->autocreatorExtension_]);
+  GPBMessage *autocreatorFieldValue =
+      (self->autocreatorField_
+           ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_,
+                                                   self->autocreatorField_)
+           : [self->autocreator_->autocreatedExtensionMap_
+                 objectForKey:self->autocreatorExtension_]);
+  NSCAssert(autocreatorHas || autocreatorFieldValue != self,
+            @"Cannot clear autocreator because it still refers to self, self: %@.",
+            self);
+
+#endif  // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+
+  self->autocreator_ = nil;
+  [self->autocreatorField_ release];
+  self->autocreatorField_ = nil;
+  [self->autocreatorExtension_ release];
+  self->autocreatorExtension_ = nil;
+}
+
+static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
+  if (!self->unknownFields_) {
+    self->unknownFields_ = [[GPBUnknownFieldSet alloc] init];
+    GPBBecomeVisibleToAutocreator(self);
+  }
+  return self->unknownFields_;
+}
+
+@implementation GPBMessage
+
++ (void)initialize {
+  Class pbMessageClass = [GPBMessage class];
+  if ([self class] == pbMessageClass) {
+    // This is here to start up the "base" class descriptor.
+    [self descriptor];
+    // Message shares extension method resolving with GPBRootObject so insure
+    // it is started up at the same time.
+    (void)[GPBRootObject class];
+  } else if ([self superclass] == pbMessageClass) {
+    // This is here to start up all the "message" subclasses. Just needs to be
+    // done for the messages, not any of the subclasses.
+    // This must be done in initialize to enforce thread safety of start up of
+    // the protocol buffer library.
+    // Note: The generated code for -descriptor calls
+    // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject
+    // subclass for the file.  That call chain is what ensures that *Root class
+    // is started up to support extension resolution off the message class
+    // (+resolveClassMethod: below) in a thread safe manner.
+    [self descriptor];
+  }
+}
+
++ (instancetype)allocWithZone:(NSZone *)zone {
+  // Override alloc to allocate our classes with the additional storage
+  // required for the instance variables.
+  GPBDescriptor *descriptor = [self descriptor];
+  return NSAllocateObject(self, descriptor->storageSize_, zone);
+}
+
++ (instancetype)alloc {
+  return [self allocWithZone:nil];
+}
+
++ (GPBDescriptor *)descriptor {
+  // This is thread safe because it is called from +initialize.
+  static GPBDescriptor *descriptor = NULL;
+  static GPBFileDescriptor *fileDescriptor = NULL;
+  if (!descriptor) {
+    // Use a dummy file that marks it as proto2 syntax so when used generically
+    // it supports unknowns/etc.
+    fileDescriptor =
+        [[GPBFileDescriptor alloc] initWithPackage:@"internal"
+                                            syntax:GPBFileSyntaxProto2];
+
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessage class]
+                                              rootClass:Nil
+                                                   file:fileDescriptor
+                                                 fields:NULL
+                                             fieldCount:0
+                                            storageSize:0
+                                                  flags:0];
+  }
+  return descriptor;
+}
+
++ (instancetype)message {
+  return [[[self alloc] init] autorelease];
+}
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    messageStorage_ = (GPBMessage_StoragePtr)(
+        ((uint8_t *)self) + class_getInstanceSize([self class]));
+  }
+
+  return self;
+}
+
+- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr {
+  return [self initWithData:data extensionRegistry:nil error:errorPtr];
+}
+
+- (instancetype)initWithData:(NSData *)data
+           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                       error:(NSError **)errorPtr {
+  if ((self = [self init])) {
+    @try {
+      [self mergeFromData:data extensionRegistry:extensionRegistry];
+      if (errorPtr) {
+        *errorPtr = nil;
+      }
+    }
+    @catch (NSException *exception) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                           exception.reason);
+      }
+    }
+#ifdef DEBUG
+    if (self && !self.initialized) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+      }
+    }
+#endif
+  }
+  return self;
+}
+
+- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
+                       extensionRegistry:
+                           (GPBExtensionRegistry *)extensionRegistry
+                                   error:(NSError **)errorPtr {
+  if ((self = [self init])) {
+    @try {
+      [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+      if (errorPtr) {
+        *errorPtr = nil;
+      }
+    }
+    @catch (NSException *exception) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                           exception.reason);
+      }
+    }
+#ifdef DEBUG
+    if (self && !self.initialized) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+      }
+    }
+#endif
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self internalClear:NO];
+  NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
+  if (readOnlySemaphore_) {
+    dispatch_release(readOnlySemaphore_);
+  }
+  [super dealloc];
+}
+
+- (void)copyFieldsInto:(GPBMessage *)message
+                  zone:(NSZone *)zone
+            descriptor:(GPBDescriptor *)descriptor {
+  // Copy all the storage...
+  memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_);
+
+  GPBFileSyntax syntax = descriptor.file.syntax;
+
+  // Loop over the fields doing fixup...
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (GPBFieldIsMapOrArray(field)) {
+      id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      if (value) {
+        // We need to copy the array/map, but the catch is for message fields,
+        // we also need to ensure all the messages as those need copying also.
+        id newValue;
+        if (GPBFieldDataTypeIsMessage(field)) {
+          if (field.fieldType == GPBFieldTypeRepeated) {
+            NSArray *existingArray = (NSArray *)value;
+            NSMutableArray *newArray =
+                [[NSMutableArray alloc] initWithCapacity:existingArray.count];
+            newValue = newArray;
+            for (GPBMessage *msg in existingArray) {
+              GPBMessage *copiedMsg = [msg copyWithZone:zone];
+              [newArray addObject:copiedMsg];
+              [copiedMsg release];
+            }
+          } else {
+            if (field.mapKeyDataType == GPBDataTypeString) {
+              // Map is an NSDictionary.
+              NSDictionary *existingDict = value;
+              NSMutableDictionary *newDict = [[NSMutableDictionary alloc]
+                  initWithCapacity:existingDict.count];
+              newValue = newDict;
+              [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key,
+                                                                GPBMessage *msg,
+                                                                BOOL *stop) {
+#pragma unused(stop)
+                GPBMessage *copiedMsg = [msg copyWithZone:zone];
+                [newDict setObject:copiedMsg forKey:key];
+                [copiedMsg release];
+              }];
+            } else {
+              // Is one of the GPB*ObjectDictionary classes.  Type doesn't
+              // matter, just need one to invoke the selector.
+              GPBInt32ObjectDictionary *existingDict = value;
+              newValue = [existingDict deepCopyWithZone:zone];
+            }
+          }
+        } else {
+          // Not messages (but is a map/array)...
+          if (field.fieldType == GPBFieldTypeRepeated) {
+            if (GPBFieldDataTypeIsObject(field)) {
+              // NSArray
+              newValue = [value mutableCopyWithZone:zone];
+            } else {
+              // GPB*Array
+              newValue = [value copyWithZone:zone];
+            }
+          } else {
+            if (field.mapKeyDataType == GPBDataTypeString) {
+              // NSDictionary
+              newValue = [value mutableCopyWithZone:zone];
+            } else {
+              // Is one of the GPB*Dictionary classes.  Type doesn't matter,
+              // just need one to invoke the selector.
+              GPBInt32Int32Dictionary *existingDict = value;
+              newValue = [existingDict copyWithZone:zone];
+            }
+          }
+        }
+        // We retain here because the memcpy picked up the pointer value and
+        // the next call to SetRetainedObject... will release the current value.
+        [value retain];
+        GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
+                                                  syntax);
+      }
+    } else if (GPBFieldDataTypeIsMessage(field)) {
+      // For object types, if we have a value, copy it.  If we don't,
+      // zero it to remove the pointer to something that was autocreated
+      // (and the ptr just got memcpyed).
+      if (GPBGetHasIvarField(self, field)) {
+        GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBMessage *newValue = [value copyWithZone:zone];
+        // We retain here because the memcpy picked up the pointer value and
+        // the next call to SetRetainedObject... will release the current value.
+        [value retain];
+        GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
+                                                  syntax);
+      } else {
+        uint8_t *storage = (uint8_t *)message->messageStorage_;
+        id *typePtr = (id *)&storage[field->description_->offset];
+        *typePtr = NULL;
+      }
+    } else if (GPBFieldDataTypeIsObject(field) &&
+               GPBGetHasIvarField(self, field)) {
+      // A set string/data value (message picked off above), copy it.
+      id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      id newValue = [value copyWithZone:zone];
+      // We retain here because the memcpy picked up the pointer value and
+      // the next call to SetRetainedObject... will release the current value.
+      [value retain];
+      GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue,
+                                                syntax);
+    } else {
+      // memcpy took care of the rest of the primitive fields if they were set.
+    }
+  }  // for (field in descriptor->fields_)
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  GPBDescriptor *descriptor = [self descriptor];
+  GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init];
+
+  [self copyFieldsInto:result zone:zone descriptor:descriptor];
+  // Make immutable copies of the extra bits.
+  result->unknownFields_ = [unknownFields_ copyWithZone:zone];
+  result->extensionMap_ = CloneExtensionMap(extensionMap_, zone);
+  return result;
+}
+
+- (void)clear {
+  [self internalClear:YES];
+}
+
+- (void)internalClear:(BOOL)zeroStorage {
+  GPBDescriptor *descriptor = [self descriptor];
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (GPBFieldIsMapOrArray(field)) {
+      id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      if (arrayOrMap) {
+        if (field.fieldType == GPBFieldTypeRepeated) {
+          if (GPBFieldDataTypeIsObject(field)) {
+            GPBAutocreatedArray *autoArray = arrayOrMap;
+            if (autoArray->_autocreator == self) {
+              autoArray->_autocreator = nil;
+            }
+          } else {
+            // Type doesn't matter, it is a GPB*Array.
+            GPBInt32Array *gpbArray = arrayOrMap;
+            if (gpbArray->_autocreator == self) {
+              gpbArray->_autocreator = nil;
+            }
+          }
+        } else {
+          if ((field.mapKeyDataType == GPBDataTypeString) &&
+              GPBFieldDataTypeIsObject(field)) {
+            GPBAutocreatedDictionary *autoDict = arrayOrMap;
+            if (autoDict->_autocreator == self) {
+              autoDict->_autocreator = nil;
+            }
+          } else {
+            // Type doesn't matter, it is a GPB*Dictionary.
+            GPBInt32Int32Dictionary *gpbDict = arrayOrMap;
+            if (gpbDict->_autocreator == self) {
+              gpbDict->_autocreator = nil;
+            }
+          }
+        }
+        [arrayOrMap release];
+      }
+    } else if (GPBFieldDataTypeIsMessage(field)) {
+      GPBClearAutocreatedMessageIvarWithField(self, field);
+      GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      [value release];
+    } else if (GPBFieldDataTypeIsObject(field) &&
+               GPBGetHasIvarField(self, field)) {
+      id value = GPBGetObjectIvarWithField(self, field);
+      [value release];
+    }
+  }
+
+  // GPBClearMessageAutocreator() expects that its caller has already been
+  // removed from autocreatedExtensionMap_ so we set to nil first.
+  NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues];
+  [autocreatedExtensionMap_ release];
+  autocreatedExtensionMap_ = nil;
+
+  // Since we're clearing all of our extensions, make sure that we clear the
+  // autocreator on any that we've created so they no longer refer to us.
+  for (GPBMessage *value in autocreatedValues) {
+    NSCAssert(GPBWasMessageAutocreatedBy(value, self),
+              @"Autocreated extension does not refer back to self.");
+    GPBClearMessageAutocreator(value);
+  }
+
+  [extensionMap_ release];
+  extensionMap_ = nil;
+  [unknownFields_ release];
+  unknownFields_ = nil;
+
+  // Note that clearing does not affect autocreator_. If we are being cleared
+  // because of a dealloc, then autocreator_ should be nil anyway. If we are
+  // being cleared because someone explicitly clears us, we don't want to
+  // sever our relationship with our autocreator.
+
+  if (zeroStorage) {
+    memset(messageStorage_, 0, descriptor->storageSize_);
+  }
+}
+
+- (BOOL)isInitialized {
+  GPBDescriptor *descriptor = [self descriptor];
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (field.isRequired) {
+      if (!GPBGetHasIvarField(self, field)) {
+        return NO;
+      }
+    }
+    if (GPBFieldDataTypeIsMessage(field)) {
+      GPBFieldType fieldType = field.fieldType;
+      if (fieldType == GPBFieldTypeSingle) {
+        if (field.isRequired) {
+          GPBMessage *message = GPBGetMessageMessageField(self, field);
+          if (!message.initialized) {
+            return NO;
+          }
+        } else {
+          NSAssert(field.isOptional,
+                   @"%@: Single message field %@ not required or optional?",
+                   [self class], field.name);
+          if (GPBGetHasIvarField(self, field)) {
+            GPBMessage *message = GPBGetMessageMessageField(self, field);
+            if (!message.initialized) {
+              return NO;
+            }
+          }
+        }
+      } else if (fieldType == GPBFieldTypeRepeated) {
+        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        for (GPBMessage *message in array) {
+          if (!message.initialized) {
+            return NO;
+          }
+        }
+      } else {  // fieldType == GPBFieldTypeMap
+        if (field.mapKeyDataType == GPBDataTypeString) {
+          NSDictionary *map =
+              GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+          if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) {
+            return NO;
+          }
+        } else {
+          // Real type is GPB*ObjectDictionary, exact type doesn't matter.
+          GPBInt32ObjectDictionary *map =
+              GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+          if (map && ![map isInitialized]) {
+            return NO;
+          }
+        }
+      }
+    }
+  }
+
+  __block BOOL result = YES;
+  [extensionMap_
+      enumerateKeysAndObjectsUsingBlock:^(GPBExtensionDescriptor *extension,
+                                          id obj,
+                                          BOOL *stop) {
+        if (GPBExtensionIsMessage(extension)) {
+          if (extension.isRepeated) {
+            for (GPBMessage *msg in obj) {
+              if (!msg.initialized) {
+                result = NO;
+                *stop = YES;
+                break;
+              }
+            }
+          } else {
+            GPBMessage *asMsg = obj;
+            if (!asMsg.initialized) {
+              result = NO;
+              *stop = YES;
+            }
+          }
+        }
+      }];
+  return result;
+}
+
+- (GPBDescriptor *)descriptor {
+  return [[self class] descriptor];
+}
+
+- (NSData *)data {
+#ifdef DEBUG
+  if (!self.initialized) {
+    return nil;
+  }
+#endif
+  NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]];
+  GPBCodedOutputStream *stream =
+      [[GPBCodedOutputStream alloc] initWithData:data];
+  @try {
+    [self writeToCodedOutputStream:stream];
+  }
+  @catch (NSException *exception) {
+    // This really shouldn't happen. The only way writeToCodedOutputStream:
+    // could throw is if something in the library has a bug and the
+    // serializedSize was wrong.
+#ifdef DEBUG
+    NSLog(@"%@: Internal exception while building message data: %@",
+          [self class], exception);
+#endif
+    data = nil;
+  }
+  [stream release];
+  return data;
+}
+
+- (NSData *)delimitedData {
+  size_t serializedSize = [self serializedSize];
+  size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize);
+  NSMutableData *data =
+      [NSMutableData dataWithLength:(serializedSize + varintSize)];
+  GPBCodedOutputStream *stream =
+      [[GPBCodedOutputStream alloc] initWithData:data];
+  @try {
+    [self writeDelimitedToCodedOutputStream:stream];
+  }
+  @catch (NSException *exception) {
+    // This really shouldn't happen.  The only way writeToCodedOutputStream:
+    // could throw is if something in the library has a bug and the
+    // serializedSize was wrong.
+#ifdef DEBUG
+    NSLog(@"%@: Internal exception while building message delimitedData: %@",
+          [self class], exception);
+#endif
+    // If it happens, truncate.
+    data.length = 0;
+  }
+  [stream release];
+  return data;
+}
+
+- (void)writeToOutputStream:(NSOutputStream *)output {
+  GPBCodedOutputStream *stream =
+      [[GPBCodedOutputStream alloc] initWithOutputStream:output];
+  [self writeToCodedOutputStream:stream];
+  [stream release];
+}
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
+  GPBDescriptor *descriptor = [self descriptor];
+  NSArray *fieldsArray = descriptor->fields_;
+  NSUInteger fieldCount = fieldsArray.count;
+  const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
+  NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
+  for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
+    if (i == fieldCount) {
+      [self writeExtensionsToCodedOutputStream:output
+                                         range:extensionRanges[j++]];
+    } else if (j == extensionRangesCount ||
+               GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
+      [self writeField:fieldsArray[i++] toCodedOutputStream:output];
+    } else {
+      [self writeExtensionsToCodedOutputStream:output
+                                         range:extensionRanges[j++]];
+    }
+  }
+  if (descriptor.isWireFormat) {
+    [unknownFields_ writeAsMessageSetTo:output];
+  } else {
+    [unknownFields_ writeToCodedOutputStream:output];
+  }
+}
+
+- (void)writeDelimitedToOutputStream:(NSOutputStream *)output {
+  GPBCodedOutputStream *codedOutput =
+      [[GPBCodedOutputStream alloc] initWithOutputStream:output];
+  [self writeDelimitedToCodedOutputStream:codedOutput];
+  [codedOutput release];
+}
+
+- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output {
+  [output writeRawVarintSizeTAs32:[self serializedSize]];
+  [self writeToCodedOutputStream:output];
+}
+
+- (void)writeField:(GPBFieldDescriptor *)field
+    toCodedOutputStream:(GPBCodedOutputStream *)output {
+  GPBFieldType fieldType = field.fieldType;
+  if (fieldType == GPBFieldTypeSingle) {
+    BOOL has = GPBGetHasIvarField(self, field);
+    if (!has) {
+      return;
+    }
+  }
+  uint32_t fieldNumber = GPBFieldNumber(field);
+
+//%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE)
+//%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE)
+//%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE)
+//%    case GPBDataType##TYPE:
+//%      if (fieldType == GPBFieldTypeRepeated) {
+//%        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+//%        GPB##ARRAY_TYPE##Array *array =
+//%            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+//%        [output write##TYPE##Array:fieldNumber values:array tag:tag];
+//%      } else if (fieldType == GPBFieldTypeSingle) {
+//%        [output write##TYPE:fieldNumber
+//%              TYPE$S  value:GPBGetMessage##REAL_TYPE##Field(self, field)];
+//%      } else {  // fieldType == GPBFieldTypeMap
+//%        // Exact type here doesn't matter.
+//%        GPBInt32##ARRAY_TYPE##Dictionary *dict =
+//%            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+//%        [dict writeToCodedOutputStream:output asField:field];
+//%      }
+//%      break;
+//%
+//%PDDM-DEFINE FIELD_CASE2(TYPE)
+//%    case GPBDataType##TYPE:
+//%      if (fieldType == GPBFieldTypeRepeated) {
+//%        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+//%        [output write##TYPE##Array:fieldNumber values:array];
+//%      } else if (fieldType == GPBFieldTypeSingle) {
+//%        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
+//%        // again.
+//%        [output write##TYPE:fieldNumber
+//%              TYPE$S  value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
+//%      } else {  // fieldType == GPBFieldTypeMap
+//%        // Exact type here doesn't matter.
+//%        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+//%        GPBDataType mapKeyDataType = field.mapKeyDataType;
+//%        if (mapKeyDataType == GPBDataTypeString) {
+//%          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
+//%        } else {
+//%          [dict writeToCodedOutputStream:output asField:field];
+//%        }
+//%      }
+//%      break;
+//%
+
+  switch (GPBGetFieldDataType(field)) {
+
+//%PDDM-EXPAND FIELD_CASE(Bool, Bool)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeBool:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBBoolArray *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeBoolArray:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeBool:fieldNumber
+                    value:GPBGetMessageBoolField(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32BoolDictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeFixed32:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBUInt32Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeFixed32Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeFixed32:fieldNumber
+                       value:GPBGetMessageUInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32UInt32Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(SFixed32, Int32)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeSFixed32:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt32Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeSFixed32Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeSFixed32:fieldNumber
+                        value:GPBGetMessageInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int32Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Float, Float)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeFloat:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBFloatArray *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeFloatArray:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeFloat:fieldNumber
+                     value:GPBGetMessageFloatField(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32FloatDictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeFixed64:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBUInt64Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeFixed64Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeFixed64:fieldNumber
+                       value:GPBGetMessageUInt64Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32UInt64Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(SFixed64, Int64)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeSFixed64:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt64Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeSFixed64Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeSFixed64:fieldNumber
+                        value:GPBGetMessageInt64Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int64Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Double, Double)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeDouble:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBDoubleArray *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeDoubleArray:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeDouble:fieldNumber
+                      value:GPBGetMessageDoubleField(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32DoubleDictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Int32, Int32)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeInt32:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt32Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeInt32Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeInt32:fieldNumber
+                     value:GPBGetMessageInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int32Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(Int64, Int64)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeInt64:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt64Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeInt64Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeInt64:fieldNumber
+                     value:GPBGetMessageInt64Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int64Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(SInt32, Int32)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeSInt32:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt32Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeSInt32Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeSInt32:fieldNumber
+                      value:GPBGetMessageInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int32Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(SInt64, Int64)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeSInt64:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBInt64Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeSInt64Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeSInt64:fieldNumber
+                      value:GPBGetMessageInt64Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32Int64Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(UInt32, UInt32)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeUInt32:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBUInt32Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeUInt32Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeUInt32:fieldNumber
+                      value:GPBGetMessageUInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32UInt32Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE(UInt64, UInt64)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeUInt64:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBUInt64Array *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeUInt64Array:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeUInt64:fieldNumber
+                      value:GPBGetMessageUInt64Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32UInt64Dictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeEnum:
+      if (fieldType == GPBFieldTypeRepeated) {
+        uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
+        GPBEnumArray *array =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeEnumArray:fieldNumber values:array tag:tag];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        [output writeEnum:fieldNumber
+                    value:GPBGetMessageInt32Field(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        GPBInt32EnumDictionary *dict =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [dict writeToCodedOutputStream:output asField:field];
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE2(Bytes)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeBytes:
+      if (fieldType == GPBFieldTypeRepeated) {
+        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeBytesArray:fieldNumber values:array];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
+        // again.
+        [output writeBytes:fieldNumber
+                     value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBDataType mapKeyDataType = field.mapKeyDataType;
+        if (mapKeyDataType == GPBDataTypeString) {
+          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
+        } else {
+          [dict writeToCodedOutputStream:output asField:field];
+        }
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE2(String)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeString:
+      if (fieldType == GPBFieldTypeRepeated) {
+        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeStringArray:fieldNumber values:array];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
+        // again.
+        [output writeString:fieldNumber
+                      value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBDataType mapKeyDataType = field.mapKeyDataType;
+        if (mapKeyDataType == GPBDataTypeString) {
+          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
+        } else {
+          [dict writeToCodedOutputStream:output asField:field];
+        }
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE2(Message)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeMessage:
+      if (fieldType == GPBFieldTypeRepeated) {
+        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeMessageArray:fieldNumber values:array];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
+        // again.
+        [output writeMessage:fieldNumber
+                       value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBDataType mapKeyDataType = field.mapKeyDataType;
+        if (mapKeyDataType == GPBDataTypeString) {
+          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
+        } else {
+          [dict writeToCodedOutputStream:output asField:field];
+        }
+      }
+      break;
+
+//%PDDM-EXPAND FIELD_CASE2(Group)
+// This block of code is generated, do not edit it directly.
+
+    case GPBDataTypeGroup:
+      if (fieldType == GPBFieldTypeRepeated) {
+        NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [output writeGroupArray:fieldNumber values:array];
+      } else if (fieldType == GPBFieldTypeSingle) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
+        // again.
+        [output writeGroup:fieldNumber
+                     value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
+      } else {  // fieldType == GPBFieldTypeMap
+        // Exact type here doesn't matter.
+        id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        GPBDataType mapKeyDataType = field.mapKeyDataType;
+        if (mapKeyDataType == GPBDataTypeString) {
+          GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
+        } else {
+          [dict writeToCodedOutputStream:output asField:field];
+        }
+      }
+      break;
+
+//%PDDM-EXPAND-END (18 expansions)
+  }
+}
+
+#pragma mark - Extensions
+
+- (id)getExtension:(GPBExtensionDescriptor *)extension {
+  CheckExtension(self, extension);
+  id value = [extensionMap_ objectForKey:extension];
+  if (value != nil) {
+    return value;
+  }
+
+  // No default for repeated.
+  if (extension.isRepeated) {
+    return nil;
+  }
+  // Non messages get their default.
+  if (!GPBExtensionIsMessage(extension)) {
+    return extension.defaultValue;
+  }
+
+  // Check for an autocreated value.
+  GPBPrepareReadOnlySemaphore(self);
+  dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
+  value = [autocreatedExtensionMap_ objectForKey:extension];
+  if (!value) {
+    // Auto create the message extensions to match normal fields.
+    value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
+                                                     extension);
+
+    if (autocreatedExtensionMap_ == nil) {
+      autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
+    }
+
+    // We can't simply call setExtension here because that would clear the new
+    // value's autocreator.
+    [autocreatedExtensionMap_ setObject:value forKey:extension];
+    [value release];
+  }
+
+  dispatch_semaphore_signal(readOnlySemaphore_);
+  return value;
+}
+
+- (id)getExistingExtension:(GPBExtensionDescriptor *)extension {
+  // This is an internal method so we don't need to call CheckExtension().
+  return [extensionMap_ objectForKey:extension];
+}
+
+- (BOOL)hasExtension:(GPBExtensionDescriptor *)extension {
+#if DEBUG
+  CheckExtension(self, extension);
+#endif  // DEBUG
+  return nil != [extensionMap_ objectForKey:extension];
+}
+
+- (NSArray *)extensionsCurrentlySet {
+  return [extensionMap_ allKeys];
+}
+
+- (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output
+                                     range:(GPBExtensionRange)range {
+  NSArray *sortedExtensions = [[extensionMap_ allKeys]
+      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
+  uint32_t start = range.start;
+  uint32_t end = range.end;
+  for (GPBExtensionDescriptor *extension in sortedExtensions) {
+    uint32_t fieldNumber = extension.fieldNumber;
+    if (fieldNumber >= start && fieldNumber < end) {
+      id value = [extensionMap_ objectForKey:extension];
+      GPBWriteExtensionValueToOutputStream(extension, value, output);
+    }
+  }
+}
+
+- (NSArray *)sortedExtensionsInUse {
+  return [[extensionMap_ allKeys]
+      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
+}
+
+- (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
+  if (!value) {
+    [self clearExtension:extension];
+    return;
+  }
+
+  CheckExtension(self, extension);
+
+  if (extension.repeated) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Must call addExtension() for repeated types."];
+  }
+
+  if (extensionMap_ == nil) {
+    extensionMap_ = [[NSMutableDictionary alloc] init];
+  }
+
+  // This pointless cast is for CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION.
+  // Without it, the compiler complains we're passing an id nullable when
+  // setObject:forKey: requires a id nonnull for the value. The check for
+  // !value at the start of the method ensures it isn't nil, but the check
+  // isn't smart enough to realize that.
+  [extensionMap_ setObject:(id)value forKey:extension];
+
+  GPBExtensionDescriptor *descriptor = extension;
+
+  if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
+    GPBMessage *autocreatedValue =
+        [[autocreatedExtensionMap_ objectForKey:extension] retain];
+    // Must remove from the map before calling GPBClearMessageAutocreator() so
+    // that GPBClearMessageAutocreator() knows its safe to clear.
+    [autocreatedExtensionMap_ removeObjectForKey:extension];
+    GPBClearMessageAutocreator(autocreatedValue);
+    [autocreatedValue release];
+  }
+
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
+  CheckExtension(self, extension);
+
+  if (!extension.repeated) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Must call setExtension() for singular types."];
+  }
+
+  if (extensionMap_ == nil) {
+    extensionMap_ = [[NSMutableDictionary alloc] init];
+  }
+  NSMutableArray *list = [extensionMap_ objectForKey:extension];
+  if (list == nil) {
+    list = [NSMutableArray array];
+    [extensionMap_ setObject:list forKey:extension];
+  }
+
+  [list addObject:value];
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+- (void)setExtension:(GPBExtensionDescriptor *)extension
+               index:(NSUInteger)idx
+               value:(id)value {
+  CheckExtension(self, extension);
+
+  if (!extension.repeated) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Must call setExtension() for singular types."];
+  }
+
+  if (extensionMap_ == nil) {
+    extensionMap_ = [[NSMutableDictionary alloc] init];
+  }
+
+  NSMutableArray *list = [extensionMap_ objectForKey:extension];
+
+  [list replaceObjectAtIndex:idx withObject:value];
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+- (void)clearExtension:(GPBExtensionDescriptor *)extension {
+  CheckExtension(self, extension);
+
+  // Only become visible if there was actually a value to clear.
+  if ([extensionMap_ objectForKey:extension]) {
+    [extensionMap_ removeObjectForKey:extension];
+    GPBBecomeVisibleToAutocreator(self);
+  }
+}
+
+#pragma mark - mergeFrom
+
+- (void)mergeFromData:(NSData *)data
+    extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
+  [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+  [input checkLastTagWas:0];
+  [input release];
+}
+
+#pragma mark - mergeDelimitedFrom
+
+- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
+                         extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  GPBCodedInputStreamState *state = &input->state_;
+  if (GPBCodedInputStreamIsAtEnd(state)) {
+    return;
+  }
+  NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
+  if (data == nil) {
+    return;
+  }
+  [self mergeFromData:data extensionRegistry:extensionRegistry];
+  [data release];
+}
+
+#pragma mark - Parse From Data Support
+
++ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr {
+  return [self parseFromData:data extensionRegistry:nil error:errorPtr];
+}
+
++ (instancetype)parseFromData:(NSData *)data
+            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                        error:(NSError **)errorPtr {
+  return [[[self alloc] initWithData:data
+                   extensionRegistry:extensionRegistry
+                               error:errorPtr] autorelease];
+}
+
++ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
+                        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                                    error:(NSError **)errorPtr {
+  return
+      [[[self alloc] initWithCodedInputStream:input
+                            extensionRegistry:extensionRegistry
+                                        error:errorPtr] autorelease];
+}
+
+#pragma mark - Parse Delimited From Data Support
+
++ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
+                                 extensionRegistry:
+                                     (GPBExtensionRegistry *)extensionRegistry
+                                             error:(NSError **)errorPtr {
+  GPBMessage *message = [[[self alloc] init] autorelease];
+  @try {
+    [message mergeDelimitedFromCodedInputStream:input
+                              extensionRegistry:extensionRegistry];
+    if (errorPtr) {
+      *errorPtr = nil;
+    }
+  }
+  @catch (NSException *exception) {
+    message = nil;
+    if (errorPtr) {
+      *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                         exception.reason);
+    }
+  }
+#ifdef DEBUG
+  if (message && !message.initialized) {
+    message = nil;
+    if (errorPtr) {
+      *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+    }
+  }
+#endif
+  return message;
+}
+
+#pragma mark - Unknown Field Support
+
+- (GPBUnknownFieldSet *)unknownFields {
+  return unknownFields_;
+}
+
+- (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields {
+  if (unknownFields != unknownFields_) {
+    [unknownFields_ release];
+    unknownFields_ = [unknownFields copy];
+    GPBBecomeVisibleToAutocreator(self);
+  }
+}
+
+- (void)parseMessageSet:(GPBCodedInputStream *)input
+      extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  uint32_t typeId = 0;
+  NSData *rawBytes = nil;
+  GPBExtensionDescriptor *extension = nil;
+  GPBCodedInputStreamState *state = &input->state_;
+  while (true) {
+    uint32_t tag = GPBCodedInputStreamReadTag(state);
+    if (tag == 0) {
+      break;
+    }
+
+    if (tag == GPBWireFormatMessageSetTypeIdTag) {
+      typeId = GPBCodedInputStreamReadUInt32(state);
+      if (typeId != 0) {
+        extension = [extensionRegistry extensionForDescriptor:[self descriptor]
+                                                  fieldNumber:typeId];
+      }
+    } else if (tag == GPBWireFormatMessageSetMessageTag) {
+      rawBytes =
+          [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
+    } else {
+      if (![input skipField:tag]) {
+        break;
+      }
+    }
+  }
+
+  [input checkLastTagWas:GPBWireFormatMessageSetItemEndTag];
+
+  if (rawBytes != nil && typeId != 0) {
+    if (extension != nil) {
+      GPBCodedInputStream *newInput =
+          [[GPBCodedInputStream alloc] initWithData:rawBytes];
+      GPBExtensionMergeFromInputStream(extension,
+                                       extension.packable,
+                                       newInput,
+                                       extensionRegistry,
+                                       self);
+      [newInput release];
+    } else {
+      GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+      [unknownFields mergeMessageSetMessage:typeId data:rawBytes];
+    }
+  }
+}
+
+- (BOOL)parseUnknownField:(GPBCodedInputStream *)input
+        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                      tag:(uint32_t)tag {
+  GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag);
+  int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
+
+  GPBDescriptor *descriptor = [self descriptor];
+  GPBExtensionDescriptor *extension =
+      [extensionRegistry extensionForDescriptor:descriptor
+                                    fieldNumber:fieldNumber];
+  if (extension == nil) {
+    if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
+      [self parseMessageSet:input extensionRegistry:extensionRegistry];
+      return YES;
+    }
+  } else {
+    if (extension.wireType == wireType) {
+      GPBExtensionMergeFromInputStream(extension,
+                                       extension.packable,
+                                       input,
+                                       extensionRegistry,
+                                       self);
+      return YES;
+    }
+    // Primitive, repeated types can be packed on unpacked on the wire, and are
+    // parsed either way.
+    if ([extension isRepeated] &&
+        !GPBDataTypeIsObject(extension->description_->dataType) &&
+        (extension.alternateWireType == wireType)) {
+      GPBExtensionMergeFromInputStream(extension,
+                                       !extension.packable,
+                                       input,
+                                       extensionRegistry,
+                                       self);
+      return YES;
+    }
+  }
+  if ([GPBUnknownFieldSet isFieldTag:tag]) {
+    GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+    return [unknownFields mergeFieldFrom:tag input:input];
+  } else {
+    return NO;
+  }
+}
+
+- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
+  GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+  [unknownFields addUnknownMapEntry:fieldNum value:data];
+}
+
+#pragma mark - MergeFromCodedInputStream Support
+
+static void MergeSingleFieldFromCodedInputStream(
+    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
+    GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  switch (fieldDataType) {
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                             \
+    case GPBDataType##NAME: {                                              \
+      TYPE val = GPBCodedInputStreamRead##NAME(&input->state_);            \
+      GPBSet##FUNC_TYPE##IvarWithFieldInternal(self, field, val, syntax);  \
+      break;                                                               \
+            }
+#define CASE_SINGLE_OBJECT(NAME)                                           \
+    case GPBDataType##NAME: {                                              \
+      id val = GPBCodedInputStreamReadRetained##NAME(&input->state_);      \
+      GPBSetRetainedObjectIvarWithFieldInternal(self, field, val, syntax); \
+      break;                                                               \
+    }
+      CASE_SINGLE_POD(Bool, BOOL, Bool)
+      CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+      CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+      CASE_SINGLE_POD(Float, float, Float)
+      CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+      CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+      CASE_SINGLE_POD(Double, double, Double)
+      CASE_SINGLE_POD(Int32, int32_t, Int32)
+      CASE_SINGLE_POD(Int64, int64_t, Int64)
+      CASE_SINGLE_POD(SInt32, int32_t, Int32)
+      CASE_SINGLE_POD(SInt64, int64_t, Int64)
+      CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+      CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+      CASE_SINGLE_OBJECT(Bytes)
+      CASE_SINGLE_OBJECT(String)
+#undef CASE_SINGLE_POD
+#undef CASE_SINGLE_OBJECT
+
+    case GPBDataTypeMessage: {
+      if (GPBGetHasIvarField(self, field)) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
+        // check again.
+        GPBMessage *message =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [input readMessage:message extensionRegistry:extensionRegistry];
+      } else {
+        GPBMessage *message = [[field.msgClass alloc] init];
+        [input readMessage:message extensionRegistry:extensionRegistry];
+        GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax);
+      }
+      break;
+    }
+
+    case GPBDataTypeGroup: {
+      if (GPBGetHasIvarField(self, field)) {
+        // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
+        // check again.
+        GPBMessage *message =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+        [input readGroup:GPBFieldNumber(field)
+                      message:message
+            extensionRegistry:extensionRegistry];
+      } else {
+        GPBMessage *message = [[field.msgClass alloc] init];
+        [input readGroup:GPBFieldNumber(field)
+                      message:message
+            extensionRegistry:extensionRegistry];
+        GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax);
+      }
+      break;
+    }
+
+    case GPBDataTypeEnum: {
+      int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
+      if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
+          [field isValidEnumValue:val]) {
+        GPBSetInt32IvarWithFieldInternal(self, field, val, syntax);
+      } else {
+        GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+        [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
+      }
+    }
+  }  // switch
+}
+
+static void MergeRepeatedPackedFieldFromCodedInputStream(
+    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
+    GPBCodedInputStream *input) {
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  GPBCodedInputStreamState *state = &input->state_;
+  id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax);
+  int32_t length = GPBCodedInputStreamReadInt32(state);
+  size_t limit = GPBCodedInputStreamPushLimit(state, length);
+  while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
+    switch (fieldDataType) {
+#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE)      \
+     case GPBDataType##NAME: {                                \
+       TYPE val = GPBCodedInputStreamRead##NAME(state);       \
+       [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+       break;                                                 \
+     }
+        CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
+        CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
+        CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
+        CASE_REPEATED_PACKED_POD(Float, float, Float)
+        CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
+        CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
+        CASE_REPEATED_PACKED_POD(Double, double, Double)
+        CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
+        CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
+        CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
+        CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
+        CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
+        CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
+#undef CASE_REPEATED_PACKED_POD
+
+      case GPBDataTypeBytes:
+      case GPBDataTypeString:
+      case GPBDataTypeMessage:
+      case GPBDataTypeGroup:
+        NSCAssert(NO, @"Non primitive types can't be packed");
+        break;
+
+      case GPBDataTypeEnum: {
+        int32_t val = GPBCodedInputStreamReadEnum(state);
+        if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
+            [field isValidEnumValue:val]) {
+          [(GPBEnumArray*)genericArray addRawValue:val];
+        } else {
+          GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+          [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
+        }
+        break;
+      }
+    }  // switch
+  }  // while(BytesUntilLimit() > 0)
+  GPBCodedInputStreamPopLimit(state, limit);
+}
+
+static void MergeRepeatedNotPackedFieldFromCodedInputStream(
+    GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax,
+    GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) {
+  GPBCodedInputStreamState *state = &input->state_;
+  id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax);
+  switch (GPBGetFieldDataType(field)) {
+#define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
+   case GPBDataType##NAME: {                                 \
+     TYPE val = GPBCodedInputStreamRead##NAME(state);        \
+     [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val];  \
+     break;                                                  \
+   }
+#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME)                \
+   case GPBDataType##NAME: {                                 \
+     id val = GPBCodedInputStreamReadRetained##NAME(state);  \
+     [(NSMutableArray*)genericArray addObject:val];          \
+     [val release];                                          \
+     break;                                                  \
+   }
+      CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
+      CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
+      CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
+      CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
+      CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
+      CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
+      CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
+      CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
+      CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
+      CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
+      CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
+      CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
+      CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
+      CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
+      CASE_REPEATED_NOT_PACKED_OBJECT(String)
+#undef CASE_REPEATED_NOT_PACKED_POD
+#undef CASE_NOT_PACKED_OBJECT
+    case GPBDataTypeMessage: {
+      GPBMessage *message = [[field.msgClass alloc] init];
+      [input readMessage:message extensionRegistry:extensionRegistry];
+      [(NSMutableArray*)genericArray addObject:message];
+      [message release];
+      break;
+    }
+    case GPBDataTypeGroup: {
+      GPBMessage *message = [[field.msgClass alloc] init];
+      [input readGroup:GPBFieldNumber(field)
+                    message:message
+          extensionRegistry:extensionRegistry];
+      [(NSMutableArray*)genericArray addObject:message];
+      [message release];
+      break;
+    }
+    case GPBDataTypeEnum: {
+      int32_t val = GPBCodedInputStreamReadEnum(state);
+      if (GPBHasPreservingUnknownEnumSemantics(syntax) ||
+          [field isValidEnumValue:val]) {
+        [(GPBEnumArray*)genericArray addRawValue:val];
+      } else {
+        GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
+        [unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
+      }
+      break;
+    }
+  }  // switch
+}
+
+- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
+                extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+  GPBDescriptor *descriptor = [self descriptor];
+  GPBFileSyntax syntax = descriptor.file.syntax;
+  GPBCodedInputStreamState *state = &input->state_;
+  uint32_t tag = 0;
+  NSUInteger startingIndex = 0;
+  NSArray *fields = descriptor->fields_;
+  NSUInteger numFields = fields.count;
+  while (YES) {
+    BOOL merged = NO;
+    tag = GPBCodedInputStreamReadTag(state);
+    for (NSUInteger i = 0; i < numFields; ++i) {
+      if (startingIndex >= numFields) startingIndex = 0;
+      GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
+      if (GPBFieldTag(fieldDescriptor) == tag) {
+        GPBFieldType fieldType = fieldDescriptor.fieldType;
+        if (fieldType == GPBFieldTypeSingle) {
+          MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax,
+                                               input, extensionRegistry);
+          // Well formed protos will only have a single field once, advance
+          // the starting index to the next field.
+          startingIndex += 1;
+        } else if (fieldType == GPBFieldTypeRepeated) {
+          if (fieldDescriptor.isPackable) {
+            MergeRepeatedPackedFieldFromCodedInputStream(
+                self, fieldDescriptor, syntax, input);
+            // Well formed protos will only have a repeated field that is
+            // packed once, advance the starting index to the next field.
+            startingIndex += 1;
+          } else {
+            MergeRepeatedNotPackedFieldFromCodedInputStream(
+                self, fieldDescriptor, syntax, input, extensionRegistry);
+          }
+        } else {  // fieldType == GPBFieldTypeMap
+          // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
+          // point.
+          id map = GetOrCreateMapIvarWithField(self, fieldDescriptor, syntax);
+          [input readMapEntry:map
+            extensionRegistry:extensionRegistry
+                        field:fieldDescriptor
+                parentMessage:self];
+        }
+        merged = YES;
+        break;
+      } else {
+        startingIndex += 1;
+      }
+    }  // for(i < numFields)
+
+    if (!merged) {
+      // Primitive, repeated types can be packed on unpacked on the wire, and
+      // are parsed either way.  The above loop covered tag in the preferred
+      // for, so this need to check the alternate form.
+      for (NSUInteger i = 0; i < numFields; ++i) {
+        if (startingIndex >= numFields) startingIndex = 0;
+        GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
+        if ((fieldDescriptor.fieldType == GPBFieldTypeRepeated) &&
+            !GPBFieldDataTypeIsObject(fieldDescriptor) &&
+            (GPBFieldAlternateTag(fieldDescriptor) == tag)) {
+          BOOL alternateIsPacked = !fieldDescriptor.isPackable;
+          if (alternateIsPacked) {
+            MergeRepeatedPackedFieldFromCodedInputStream(
+                self, fieldDescriptor, syntax, input);
+            // Well formed protos will only have a repeated field that is
+            // packed once, advance the starting index to the next field.
+            startingIndex += 1;
+          } else {
+            MergeRepeatedNotPackedFieldFromCodedInputStream(
+                self, fieldDescriptor, syntax, input, extensionRegistry);
+          }
+          merged = YES;
+          break;
+        } else {
+          startingIndex += 1;
+        }
+      }
+    }
+
+    if (!merged) {
+      if (tag == 0) {
+        // zero signals EOF / limit reached
+        return;
+      } else {
+        if (GPBPreserveUnknownFields(syntax)) {
+          if (![self parseUnknownField:input
+                     extensionRegistry:extensionRegistry
+                                   tag:tag]) {
+            // it's an endgroup tag
+            return;
+          }
+        } else {
+          if (![input skipField:tag]) {
+            return;
+          }
+        }
+      }
+    }  // if(!merged)
+
+  }  // while(YES)
+}
+
+#pragma mark - MergeFrom Support
+
+- (void)mergeFrom:(GPBMessage *)other {
+  Class selfClass = [self class];
+  Class otherClass = [other class];
+  if (!([selfClass isSubclassOfClass:otherClass] ||
+        [otherClass isSubclassOfClass:selfClass])) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Classes must match %@ != %@", selfClass, otherClass];
+  }
+
+  // We assume something will be done and become visible.
+  GPBBecomeVisibleToAutocreator(self);
+
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  GPBFileSyntax syntax = descriptor.file.syntax;
+
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    GPBFieldType fieldType = field.fieldType;
+    if (fieldType == GPBFieldTypeSingle) {
+      int32_t hasIndex = GPBFieldHasIndex(field);
+      uint32_t fieldNumber = GPBFieldNumber(field);
+      if (!GPBGetHasIvar(other, hasIndex, fieldNumber)) {
+        // Other doesn't have the field set, on to the next.
+        continue;
+      }
+      GPBDataType fieldDataType = GPBGetFieldDataType(field);
+      switch (fieldDataType) {
+        case GPBDataTypeBool:
+          GPBSetBoolIvarWithFieldInternal(
+              self, field, GPBGetMessageBoolField(other, field), syntax);
+          break;
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeEnum:
+        case GPBDataTypeInt32:
+        case GPBDataTypeSInt32:
+          GPBSetInt32IvarWithFieldInternal(
+              self, field, GPBGetMessageInt32Field(other, field), syntax);
+          break;
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+          GPBSetUInt32IvarWithFieldInternal(
+              self, field, GPBGetMessageUInt32Field(other, field), syntax);
+          break;
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeInt64:
+        case GPBDataTypeSInt64:
+          GPBSetInt64IvarWithFieldInternal(
+              self, field, GPBGetMessageInt64Field(other, field), syntax);
+          break;
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+          GPBSetUInt64IvarWithFieldInternal(
+              self, field, GPBGetMessageUInt64Field(other, field), syntax);
+          break;
+        case GPBDataTypeFloat:
+          GPBSetFloatIvarWithFieldInternal(
+              self, field, GPBGetMessageFloatField(other, field), syntax);
+          break;
+        case GPBDataTypeDouble:
+          GPBSetDoubleIvarWithFieldInternal(
+              self, field, GPBGetMessageDoubleField(other, field), syntax);
+          break;
+        case GPBDataTypeBytes:
+        case GPBDataTypeString: {
+          id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+          GPBSetObjectIvarWithFieldInternal(self, field, otherVal, syntax);
+          break;
+        }
+        case GPBDataTypeMessage:
+        case GPBDataTypeGroup: {
+          id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+          if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
+            GPBMessage *message =
+                GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+            [message mergeFrom:otherVal];
+          } else {
+            GPBMessage *message = [otherVal copy];
+            GPBSetRetainedObjectIvarWithFieldInternal(self, field, message,
+                                                      syntax);
+          }
+          break;
+        }
+      } // switch()
+    } else if (fieldType == GPBFieldTypeRepeated) {
+      // In the case of a list, they need to be appended, and there is no
+      // _hasIvar to worry about setting.
+      id otherArray =
+          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+      if (otherArray) {
+        GPBDataType fieldDataType = field->description_->dataType;
+        if (GPBDataTypeIsObject(fieldDataType)) {
+          NSMutableArray *resultArray =
+              GetOrCreateArrayIvarWithField(self, field, syntax);
+          [resultArray addObjectsFromArray:otherArray];
+        } else if (fieldDataType == GPBDataTypeEnum) {
+          GPBEnumArray *resultArray =
+              GetOrCreateArrayIvarWithField(self, field, syntax);
+          [resultArray addRawValuesFromArray:otherArray];
+        } else {
+          // The array type doesn't matter, that all implment
+          // -addValuesFromArray:.
+          GPBInt32Array *resultArray =
+              GetOrCreateArrayIvarWithField(self, field, syntax);
+          [resultArray addValuesFromArray:otherArray];
+        }
+      }
+    } else {  // fieldType = GPBFieldTypeMap
+      // In the case of a map, they need to be merged, and there is no
+      // _hasIvar to worry about setting.
+      id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+      if (otherDict) {
+        GPBDataType keyDataType = field.mapKeyDataType;
+        GPBDataType valueDataType = field->description_->dataType;
+        if (GPBDataTypeIsObject(keyDataType) &&
+            GPBDataTypeIsObject(valueDataType)) {
+          NSMutableDictionary *resultDict =
+              GetOrCreateMapIvarWithField(self, field, syntax);
+          [resultDict addEntriesFromDictionary:otherDict];
+        } else if (valueDataType == GPBDataTypeEnum) {
+          // The exact type doesn't matter, just need to know it is a
+          // GPB*EnumDictionary.
+          GPBInt32EnumDictionary *resultDict =
+              GetOrCreateMapIvarWithField(self, field, syntax);
+          [resultDict addRawEntriesFromDictionary:otherDict];
+        } else {
+          // The exact type doesn't matter, they all implement
+          // -addEntriesFromDictionary:.
+          GPBInt32Int32Dictionary *resultDict =
+              GetOrCreateMapIvarWithField(self, field, syntax);
+          [resultDict addEntriesFromDictionary:otherDict];
+        }
+      }
+    }  // if (fieldType)..else if...else
+  }  // for(fields)
+
+  // Unknown fields.
+  if (!unknownFields_) {
+    [self setUnknownFields:other.unknownFields];
+  } else {
+    [unknownFields_ mergeUnknownFields:other.unknownFields];
+  }
+
+  // Extensions
+
+  if (other->extensionMap_.count == 0) {
+    return;
+  }
+
+  if (extensionMap_ == nil) {
+    extensionMap_ =
+        CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
+  } else {
+    for (GPBExtensionDescriptor *extension in other->extensionMap_) {
+      id otherValue = [other->extensionMap_ objectForKey:extension];
+      id value = [extensionMap_ objectForKey:extension];
+      BOOL isMessageExtension = GPBExtensionIsMessage(extension);
+
+      if (extension.repeated) {
+        NSMutableArray *list = value;
+        if (list == nil) {
+          list = [[NSMutableArray alloc] init];
+          [extensionMap_ setObject:list forKey:extension];
+          [list release];
+        }
+        if (isMessageExtension) {
+          for (GPBMessage *otherListValue in otherValue) {
+            GPBMessage *copiedValue = [otherListValue copy];
+            [list addObject:copiedValue];
+            [copiedValue release];
+          }
+        } else {
+          [list addObjectsFromArray:otherValue];
+        }
+      } else {
+        if (isMessageExtension) {
+          if (value) {
+            [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue];
+          } else {
+            GPBMessage *copiedValue = [otherValue copy];
+            [extensionMap_ setObject:copiedValue forKey:extension];
+            [copiedValue release];
+          }
+        } else {
+          [extensionMap_ setObject:otherValue forKey:extension];
+        }
+      }
+
+      if (isMessageExtension && !extension.isRepeated) {
+        GPBMessage *autocreatedValue =
+            [[autocreatedExtensionMap_ objectForKey:extension] retain];
+        // Must remove from the map before calling GPBClearMessageAutocreator()
+        // so that GPBClearMessageAutocreator() knows its safe to clear.
+        [autocreatedExtensionMap_ removeObjectForKey:extension];
+        GPBClearMessageAutocreator(autocreatedValue);
+        [autocreatedValue release];
+      }
+    }
+  }
+}
+
+#pragma mark - isEqual: & hash Support
+
+- (BOOL)isEqual:(GPBMessage *)other {
+  if (other == self) {
+    return YES;
+  }
+  if (![other isKindOfClass:[self class]] &&
+      ![self isKindOfClass:[other class]]) {
+    return NO;
+  }
+
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  uint8_t *selfStorage = (uint8_t *)messageStorage_;
+  uint8_t *otherStorage = (uint8_t *)other->messageStorage_;
+
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (GPBFieldIsMapOrArray(field)) {
+      // In the case of a list or map, there is no _hasIvar to worry about.
+      // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
+      // the type doesn't really matter as the objects all support -count and
+      // -isEqual:.
+      NSArray *resultMapOrArray =
+          GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      NSArray *otherMapOrArray =
+          GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+      // nil and empty are equal
+      if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
+        if (![resultMapOrArray isEqual:otherMapOrArray]) {
+          return NO;
+        }
+      }
+    } else {  // Single field
+      int32_t hasIndex = GPBFieldHasIndex(field);
+      uint32_t fieldNum = GPBFieldNumber(field);
+      BOOL selfHas = GPBGetHasIvar(self, hasIndex, fieldNum);
+      BOOL otherHas = GPBGetHasIvar(other, hasIndex, fieldNum);
+      if (selfHas != otherHas) {
+        return NO;  // Differing has values, not equal.
+      }
+      if (!selfHas) {
+        // Same has values, was no, nothing else to check for this field.
+        continue;
+      }
+      // Now compare the values.
+      GPBDataType fieldDataType = GPBGetFieldDataType(field);
+      size_t fieldOffset = field->description_->offset;
+      switch (fieldDataType) {
+        case GPBDataTypeBool: {
+          // Bools are stored in has_bits to avoid needing explicit space in
+          // the storage structure.
+          // (the field number passed to the HasIvar helper doesn't really
+          // matter since the offset is never negative)
+          BOOL selfValue = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
+          BOOL otherValue = GPBGetHasIvar(other, (int32_t)(fieldOffset), 0);
+          if (selfValue != otherValue) {
+            return NO;
+          }
+          break;
+        }
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeInt32:
+        case GPBDataTypeSInt32:
+        case GPBDataTypeEnum:
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+        case GPBDataTypeFloat: {
+          _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
+          // These are all 32bit, signed/unsigned doesn't matter for equality.
+          uint32_t *selfValPtr = (uint32_t *)&selfStorage[fieldOffset];
+          uint32_t *otherValPtr = (uint32_t *)&otherStorage[fieldOffset];
+          if (*selfValPtr != *otherValPtr) {
+            return NO;
+          }
+          break;
+        }
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeInt64:
+        case GPBDataTypeSInt64:
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+        case GPBDataTypeDouble: {
+          _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
+          // These are all 64bit, signed/unsigned doesn't matter for equality.
+          uint64_t *selfValPtr = (uint64_t *)&selfStorage[fieldOffset];
+          uint64_t *otherValPtr = (uint64_t *)&otherStorage[fieldOffset];
+          if (*selfValPtr != *otherValPtr) {
+            return NO;
+          }
+          break;
+        }
+        case GPBDataTypeBytes:
+        case GPBDataTypeString:
+        case GPBDataTypeMessage:
+        case GPBDataTypeGroup: {
+          // Type doesn't matter here, they all implement -isEqual:.
+          id *selfValPtr = (id *)&selfStorage[fieldOffset];
+          id *otherValPtr = (id *)&otherStorage[fieldOffset];
+          if (![*selfValPtr isEqual:*otherValPtr]) {
+            return NO;
+          }
+          break;
+        }
+      } // switch()
+    }   // if(mapOrArray)...else
+  }  // for(fields)
+
+  // nil and empty are equal
+  if (extensionMap_.count != 0 || other->extensionMap_.count != 0) {
+    if (![extensionMap_ isEqual:other->extensionMap_]) {
+      return NO;
+    }
+  }
+
+  // nil and empty are equal
+  GPBUnknownFieldSet *otherUnknowns = other->unknownFields_;
+  if ([unknownFields_ countOfFields] != 0 ||
+      [otherUnknowns countOfFields] != 0) {
+    if (![unknownFields_ isEqual:otherUnknowns]) {
+      return NO;
+    }
+  }
+
+  return YES;
+}
+
+// It is very difficult to implement a generic hash for ProtoBuf messages that
+// will perform well. If you need hashing on your ProtoBufs (eg you are using
+// them as dictionary keys) you will probably want to implement a ProtoBuf
+// message specific hash as a category on your protobuf class. Do not make it a
+// category on GPBMessage as you will conflict with this hash, and will possibly
+// override hash for all generated protobufs. A good implementation of hash will
+// be really fast, so we would recommend only hashing protobufs that have an
+// identifier field of some kind that you can easily hash. If you implement
+// hash, we would strongly recommend overriding isEqual: in your category as
+// well, as the default implementation of isEqual: is extremely slow, and may
+// drastically affect performance in large sets.
+- (NSUInteger)hash {
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  const NSUInteger prime = 19;
+  uint8_t *storage = (uint8_t *)messageStorage_;
+
+  // Start with the descriptor and then mix it with some instance info.
+  // Hopefully that will give a spread based on classes and what fields are set.
+  NSUInteger result = (NSUInteger)descriptor;
+
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (GPBFieldIsMapOrArray(field)) {
+      // Exact type doesn't matter, just check if there are any elements.
+      NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      NSUInteger count = mapOrArray.count;
+      if (count) {
+        // NSArray/NSDictionary use count, use the field number and the count.
+        result = prime * result + GPBFieldNumber(field);
+        result = prime * result + count;
+      }
+    } else if (GPBGetHasIvarField(self, field)) {
+      // Just using the field number seemed simple/fast, but then a small
+      // message class where all the same fields are always set (to different
+      // things would end up all with the same hash, so pull in some data).
+      GPBDataType fieldDataType = GPBGetFieldDataType(field);
+      size_t fieldOffset = field->description_->offset;
+      switch (fieldDataType) {
+        case GPBDataTypeBool: {
+          // Bools are stored in has_bits to avoid needing explicit space in
+          // the storage structure.
+          // (the field number passed to the HasIvar helper doesn't really
+          // matter since the offset is never negative)
+          BOOL value = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
+          result = prime * result + value;
+          break;
+        }
+        case GPBDataTypeSFixed32:
+        case GPBDataTypeInt32:
+        case GPBDataTypeSInt32:
+        case GPBDataTypeEnum:
+        case GPBDataTypeFixed32:
+        case GPBDataTypeUInt32:
+        case GPBDataTypeFloat: {
+          _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
+          // These are all 32bit, just mix it in.
+          uint32_t *valPtr = (uint32_t *)&storage[fieldOffset];
+          result = prime * result + *valPtr;
+          break;
+        }
+        case GPBDataTypeSFixed64:
+        case GPBDataTypeInt64:
+        case GPBDataTypeSInt64:
+        case GPBDataTypeFixed64:
+        case GPBDataTypeUInt64:
+        case GPBDataTypeDouble: {
+          _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
+          // These are all 64bit, just mix what fits into an NSUInteger in.
+          uint64_t *valPtr = (uint64_t *)&storage[fieldOffset];
+          result = prime * result + (NSUInteger)(*valPtr);
+          break;
+        }
+        case GPBDataTypeBytes:
+        case GPBDataTypeString: {
+          // Type doesn't matter here, they both implement -hash:.
+          id *valPtr = (id *)&storage[fieldOffset];
+          result = prime * result + [*valPtr hash];
+          break;
+        }
+
+        case GPBDataTypeMessage:
+        case GPBDataTypeGroup: {
+          GPBMessage **valPtr = (GPBMessage **)&storage[fieldOffset];
+          // Could call -hash on the sub message, but that could recurse pretty
+          // deep; follow the lead of NSArray/NSDictionary and don't really
+          // recurse for hash, instead use the field number and the descriptor
+          // of the sub message.  Yes, this could suck for a bunch of messages
+          // where they all only differ in the sub messages, but if you are
+          // using a message with sub messages for something that needs -hash,
+          // odds are you are also copying them as keys, and that deep copy
+          // will also suck.
+          result = prime * result + GPBFieldNumber(field);
+          result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
+          break;
+        }
+      } // switch()
+    }
+  }
+
+  // Unknowns and extensions are not included.
+
+  return result;
+}
+
+#pragma mark - Description Support
+
+- (NSString *)description {
+  NSString *textFormat = GPBTextFormatForMessage(self, @"    ");
+  NSString *description = [NSString
+      stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
+  return description;
+}
+
+#if DEBUG
+
+// Xcode 5.1 added support for custom quick look info.
+// https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/CustomClassDisplay_in_QuickLook/CH01-quick_look_for_custom_objects/CH01-quick_look_for_custom_objects.html#//apple_ref/doc/uid/TP40014001-CH2-SW1
+- (id)debugQuickLookObject {
+  return GPBTextFormatForMessage(self, nil);
+}
+
+#endif  // DEBUG
+
+#pragma mark - SerializedSize
+
+- (size_t)serializedSize {
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  size_t result = 0;
+
+  // Has check is done explicitly, so GPBGetObjectIvarWithFieldNoAutocreate()
+  // avoids doing the has check again.
+
+  // Fields.
+  for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) {
+    GPBFieldType fieldType = fieldDescriptor.fieldType;
+    GPBDataType fieldDataType = GPBGetFieldDataType(fieldDescriptor);
+
+    // Single Fields
+    if (fieldType == GPBFieldTypeSingle) {
+      BOOL selfHas = GPBGetHasIvarField(self, fieldDescriptor);
+      if (!selfHas) {
+        continue;  // Nothing to do.
+      }
+
+      uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
+
+      switch (fieldDataType) {
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE)                                \
+        case GPBDataType##NAME: {                                             \
+          TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
+          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
+          break;                                                              \
+        }
+#define CASE_SINGLE_OBJECT(NAME)                                              \
+        case GPBDataType##NAME: {                                             \
+          id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
+          result += GPBCompute##NAME##Size(fieldNumber, fieldVal);            \
+          break;                                                              \
+        }
+          CASE_SINGLE_POD(Bool, BOOL, Bool)
+          CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+          CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+          CASE_SINGLE_POD(Float, float, Float)
+          CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+          CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+          CASE_SINGLE_POD(Double, double, Double)
+          CASE_SINGLE_POD(Int32, int32_t, Int32)
+          CASE_SINGLE_POD(Int64, int64_t, Int64)
+          CASE_SINGLE_POD(SInt32, int32_t, Int32)
+          CASE_SINGLE_POD(SInt64, int64_t, Int64)
+          CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+          CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+          CASE_SINGLE_OBJECT(Bytes)
+          CASE_SINGLE_OBJECT(String)
+          CASE_SINGLE_OBJECT(Message)
+          CASE_SINGLE_OBJECT(Group)
+          CASE_SINGLE_POD(Enum, int32_t, Int32)
+#undef CASE_SINGLE_POD
+#undef CASE_SINGLE_OBJECT
+      }
+
+    // Repeated Fields
+    } else if (fieldType == GPBFieldTypeRepeated) {
+      id genericArray =
+          GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+      NSUInteger count = [genericArray count];
+      if (count == 0) {
+        continue;  // Nothing to add.
+      }
+      __block size_t dataSize = 0;
+
+      switch (fieldDataType) {
+#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE)                             \
+    CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
+#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME)  \
+        case GPBDataType##NAME: {                                             \
+          GPB##ARRAY_TYPE##Array *array = genericArray;                       \
+          [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { \
+            _Pragma("unused(idx, stop)");                                     \
+            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
+          }];                                                                 \
+          break;                                                              \
+        }
+#define CASE_REPEATED_OBJECT(NAME)                                            \
+        case GPBDataType##NAME: {                                             \
+          for (id value in genericArray) {                                    \
+            dataSize += GPBCompute##NAME##SizeNoTag(value);                   \
+          }                                                                   \
+          break;                                                              \
+        }
+          CASE_REPEATED_POD(Bool, BOOL, Bool)
+          CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
+          CASE_REPEATED_POD(SFixed32, int32_t, Int32)
+          CASE_REPEATED_POD(Float, float, Float)
+          CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
+          CASE_REPEATED_POD(SFixed64, int64_t, Int64)
+          CASE_REPEATED_POD(Double, double, Double)
+          CASE_REPEATED_POD(Int32, int32_t, Int32)
+          CASE_REPEATED_POD(Int64, int64_t, Int64)
+          CASE_REPEATED_POD(SInt32, int32_t, Int32)
+          CASE_REPEATED_POD(SInt64, int64_t, Int64)
+          CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
+          CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
+          CASE_REPEATED_OBJECT(Bytes)
+          CASE_REPEATED_OBJECT(String)
+          CASE_REPEATED_OBJECT(Message)
+          CASE_REPEATED_OBJECT(Group)
+          CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
+#undef CASE_REPEATED_POD
+#undef CASE_REPEATED_POD_EXTRA
+#undef CASE_REPEATED_OBJECT
+      }  // switch
+      result += dataSize;
+      size_t tagSize = GPBComputeTagSize(GPBFieldNumber(fieldDescriptor));
+      if (fieldDataType == GPBDataTypeGroup) {
+        // Groups have both a start and an end tag.
+        tagSize *= 2;
+      }
+      if (fieldDescriptor.isPackable) {
+        result += tagSize;
+        result += GPBComputeSizeTSizeAsInt32NoTag(dataSize);
+      } else {
+        result += count * tagSize;
+      }
+
+    // Map<> Fields
+    } else {  // fieldType == GPBFieldTypeMap
+      if (GPBDataTypeIsObject(fieldDataType) &&
+          (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
+        // If key type was string, then the map is an NSDictionary.
+        NSDictionary *map =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+        if (map) {
+          result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
+        }
+      } else {
+        // Type will be GPB*GroupDictionary, exact type doesn't matter.
+        GPBInt32Int32Dictionary *map =
+            GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+        result += [map computeSerializedSizeAsField:fieldDescriptor];
+      }
+    }
+  }  // for(fields)
+
+  // Add any unknown fields.
+  if (descriptor.wireFormat) {
+    result += [unknownFields_ serializedSizeAsMessageSet];
+  } else {
+    result += [unknownFields_ serializedSize];
+  }
+
+  // Add any extensions.
+  for (GPBExtensionDescriptor *extension in extensionMap_) {
+    id value = [extensionMap_ objectForKey:extension];
+    result += GPBComputeExtensionSerializedSizeIncludingTag(extension, value);
+  }
+
+  return result;
+}
+
+#pragma mark - Resolve Methods Support
+
+typedef struct ResolveIvarAccessorMethodResult {
+  IMP impToAdd;
+  SEL encodingSelector;
+} ResolveIvarAccessorMethodResult;
+
+static void ResolveIvarGet(GPBFieldDescriptor *field,
+                           ResolveIvarAccessorMethodResult *result) {
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  switch (fieldDataType) {
+#define CASE_GET(NAME, TYPE, TRUE_NAME)                          \
+    case GPBDataType##NAME: {                                    \
+      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+        return GPBGetMessage##TRUE_NAME##Field(obj, field);      \
+       });                                                       \
+      result->encodingSelector = @selector(get##NAME);           \
+      break;                                                     \
+    }
+#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME)                   \
+    case GPBDataType##NAME: {                                    \
+      result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+        return GPBGetObjectIvarWithField(obj, field);            \
+       });                                                       \
+      result->encodingSelector = @selector(get##NAME);           \
+      break;                                                     \
+    }
+      CASE_GET(Bool, BOOL, Bool)
+      CASE_GET(Fixed32, uint32_t, UInt32)
+      CASE_GET(SFixed32, int32_t, Int32)
+      CASE_GET(Float, float, Float)
+      CASE_GET(Fixed64, uint64_t, UInt64)
+      CASE_GET(SFixed64, int64_t, Int64)
+      CASE_GET(Double, double, Double)
+      CASE_GET(Int32, int32_t, Int32)
+      CASE_GET(Int64, int64_t, Int64)
+      CASE_GET(SInt32, int32_t, Int32)
+      CASE_GET(SInt64, int64_t, Int64)
+      CASE_GET(UInt32, uint32_t, UInt32)
+      CASE_GET(UInt64, uint64_t, UInt64)
+      CASE_GET_OBJECT(Bytes, id, Object)
+      CASE_GET_OBJECT(String, id, Object)
+      CASE_GET_OBJECT(Message, id, Object)
+      CASE_GET_OBJECT(Group, id, Object)
+      CASE_GET(Enum, int32_t, Enum)
+#undef CASE_GET
+  }
+}
+
+static void ResolveIvarSet(GPBFieldDescriptor *field,
+                           GPBFileSyntax syntax,
+                           ResolveIvarAccessorMethodResult *result) {
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  switch (fieldDataType) {
+#define CASE_SET(NAME, TYPE, TRUE_NAME)                                       \
+    case GPBDataType##NAME: {                                                 \
+      result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) {  \
+        return GPBSet##TRUE_NAME##IvarWithFieldInternal(obj, field, value, syntax); \
+      });                                                                     \
+      result->encodingSelector = @selector(set##NAME:);                       \
+      break;                                                                  \
+    }
+      CASE_SET(Bool, BOOL, Bool)
+      CASE_SET(Fixed32, uint32_t, UInt32)
+      CASE_SET(SFixed32, int32_t, Int32)
+      CASE_SET(Float, float, Float)
+      CASE_SET(Fixed64, uint64_t, UInt64)
+      CASE_SET(SFixed64, int64_t, Int64)
+      CASE_SET(Double, double, Double)
+      CASE_SET(Int32, int32_t, Int32)
+      CASE_SET(Int64, int64_t, Int64)
+      CASE_SET(SInt32, int32_t, Int32)
+      CASE_SET(SInt64, int64_t, Int64)
+      CASE_SET(UInt32, uint32_t, UInt32)
+      CASE_SET(UInt64, uint64_t, UInt64)
+      CASE_SET(Bytes, id, Object)
+      CASE_SET(String, id, Object)
+      CASE_SET(Message, id, Object)
+      CASE_SET(Group, id, Object)
+      CASE_SET(Enum, int32_t, Enum)
+#undef CASE_SET
+  }
+}
+
++ (BOOL)resolveInstanceMethod:(SEL)sel {
+  const GPBDescriptor *descriptor = [self descriptor];
+  if (!descriptor) {
+    return NO;
+  }
+
+  // NOTE: hasOrCountSel_/setHasSel_ will be NULL if the field for the given
+  // message should not have has support (done in GPBDescriptor.m), so there is
+  // no need for checks here to see if has*/setHas* are allowed.
+
+  ResolveIvarAccessorMethodResult result = {NULL, NULL};
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
+    if (!isMapOrArray) {
+      // Single fields.
+      if (sel == field->getSel_) {
+        ResolveIvarGet(field, &result);
+        break;
+      } else if (sel == field->setSel_) {
+        ResolveIvarSet(field, descriptor.file.syntax, &result);
+        break;
+      } else if (sel == field->hasOrCountSel_) {
+        int32_t index = GPBFieldHasIndex(field);
+        uint32_t fieldNum = GPBFieldNumber(field);
+        result.impToAdd = imp_implementationWithBlock(^(id obj) {
+          return GPBGetHasIvar(obj, index, fieldNum);
+        });
+        result.encodingSelector = @selector(getBool);
+        break;
+      } else if (sel == field->setHasSel_) {
+        result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
+          if (value) {
+            [NSException raise:NSInvalidArgumentException
+                        format:@"%@: %@ can only be set to NO (to clear field).",
+                               [obj class],
+                               NSStringFromSelector(field->setHasSel_)];
+          }
+          GPBClearMessageField(obj, field);
+        });
+        result.encodingSelector = @selector(setBool:);
+        break;
+      } else {
+        GPBOneofDescriptor *oneof = field->containingOneof_;
+        if (oneof && (sel == oneof->caseSel_)) {
+          int32_t index = GPBFieldHasIndex(field);
+          result.impToAdd = imp_implementationWithBlock(^(id obj) {
+            return GPBGetHasOneof(obj, index);
+          });
+          result.encodingSelector = @selector(getEnum);
+          break;
+        }
+      }
+    } else {
+      // map<>/repeated fields.
+      if (sel == field->getSel_) {
+        if (field.fieldType == GPBFieldTypeRepeated) {
+          result.impToAdd = imp_implementationWithBlock(^(id obj) {
+            return GetArrayIvarWithField(obj, field);
+          });
+        } else {
+          result.impToAdd = imp_implementationWithBlock(^(id obj) {
+            return GetMapIvarWithField(obj, field);
+          });
+        }
+        result.encodingSelector = @selector(getArray);
+        break;
+      } else if (sel == field->setSel_) {
+        // Local for syntax so the block can directly capture it and not the
+        // full lookup.
+        const GPBFileSyntax syntax = descriptor.file.syntax;
+        result.impToAdd = imp_implementationWithBlock(^(id obj, id value) {
+          return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax);
+        });
+        result.encodingSelector = @selector(setArray:);
+        break;
+      } else if (sel == field->hasOrCountSel_) {
+        result.impToAdd = imp_implementationWithBlock(^(id obj) {
+          // Type doesn't matter, all *Array and *Dictionary types support
+          // -count.
+          NSArray *arrayOrMap =
+              GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
+          return [arrayOrMap count];
+        });
+        result.encodingSelector = @selector(getArrayCount);
+        break;
+      }
+    }
+  }
+  if (result.impToAdd) {
+    const char *encoding =
+        GPBMessageEncodingForSelector(result.encodingSelector, YES);
+    BOOL methodAdded = class_addMethod(descriptor.messageClass, sel,
+                                       result.impToAdd, encoding);
+    return methodAdded;
+  }
+  return [super resolveInstanceMethod:sel];
+}
+
++ (BOOL)resolveClassMethod:(SEL)sel {
+  // Extensions scoped to a Message and looked up via class methods.
+  if (GPBResolveExtensionClassMethod(self, sel)) {
+    return YES;
+  }
+  return [super resolveClassMethod:sel];
+}
+
+#pragma mark - NSCoding Support
+
++ (BOOL)supportsSecureCoding {
+  return YES;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+  self = [self init];
+  if (self) {
+    NSData *data =
+        [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
+    if (data.length) {
+      [self mergeFromData:data extensionRegistry:nil];
+    }
+  }
+  return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+  NSData *data = [self data];
+  if (data.length) {
+    [aCoder encodeObject:data forKey:kGPBDataCoderKey];
+  }
+}
+
+#pragma mark - KVC Support
+
++ (BOOL)accessInstanceVariablesDirectly {
+  // Make sure KVC doesn't use instance variables.
+  return NO;
+}
+
+@end
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
new file mode 100644
index 0000000..478db2c
--- /dev/null
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -0,0 +1,143 @@
+// 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.
+
+// This header is private to the ProtobolBuffers library and must NOT be
+// included by any sources outside this library. The contents of this file are
+// subject to change at any time without notice.
+
+#import "GPBMessage.h"
+
+#import <libkern/OSAtomic.h>
+
+#import "GPBBootstrap.h"
+
+typedef struct GPBMessage_Storage {
+  uint32_t _has_storage_[0];
+} GPBMessage_Storage;
+
+typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
+
+@interface GPBMessage () {
+ @package
+  // NOTE: Because of the +allocWithZone code using NSAllocateObject(),
+  // this structure should ideally always be kept pointer aligned where the
+  // real storage starts is also pointer aligned. The compiler/runtime already
+  // do this, but it may not be documented.
+
+  // A pointer to the actual fields of the subclasses. The actual structure
+  // pointed to by this pointer will depend on the subclass.
+  // All of the actual structures will start the same as
+  // GPBMessage_Storage with _has_storage__ as the first field.
+  // Kept public because static functions need to access it.
+  GPBMessage_StoragePtr messageStorage_;
+
+  // A lock to provide mutual exclusion from internal data that can be modified
+  // by *read* operations such as getters (autocreation of message fields and
+  // message extensions, not setting of values). Used to guarantee thread safety
+  // for concurrent reads on the message.
+  // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+  // pointed out that they are vulnerable to live locking on iOS in cases of
+  // priority inversion:
+  //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+  //   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+  // Use of readOnlySemaphore_ must be prefaced by a call to
+  // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows
+  // readOnlySemaphore_ to be only created when actually needed.
+  dispatch_once_t readOnlySemaphoreCreationOnce_;
+  dispatch_semaphore_t readOnlySemaphore_;
+}
+
+// Gets an extension value without autocreating the result if not found. (i.e.
+// returns nil if the extension is not set)
+- (id)getExistingExtension:(GPBExtensionDescriptor *)extension;
+
+// Returns an array of GPBExtensionDescriptor* for all the extensions currently
+// in use on the message.  They are sorted by field number.
+- (NSArray *)sortedExtensionsInUse;
+
+// Parses a message of this type from the input and merges it with this
+// message.
+//
+// Warning:  This does not verify that all required fields are present in
+// the input message.
+// Note:  The caller should call
+// -[CodedInputStream checkLastTagWas:] after calling this to
+// verify that the last tag seen was the appropriate end-group tag,
+// or zero for EOF.
+// NOTE: This will throw if there is an error while parsing.
+- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
+                extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
+
+// Parses the next delimited message of this type from the input and merges it
+// with this message.
+- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
+                         extensionRegistry:
+                             (GPBExtensionRegistry *)extensionRegistry;
+
+- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data;
+
+@end
+
+CF_EXTERN_C_BEGIN
+
+
+// Call this before using the readOnlySemaphore_. This ensures it is created only once.
+NS_INLINE void GPBPrepareReadOnlySemaphore(GPBMessage *self) {
+  dispatch_once(&self->readOnlySemaphoreCreationOnce_, ^{
+    self->readOnlySemaphore_ = dispatch_semaphore_create(1);
+  });
+}
+
+// Returns a new instance that was automatically created by |autocreator| for
+// its field |field|.
+GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
+                                            GPBMessage *autocreator,
+                                            GPBFieldDescriptor *field)
+    __attribute__((ns_returns_retained));
+
+// Returns whether |message| autocreated this message. This is NO if the message
+// was not autocreated by |message| or if it has been mutated since
+// autocreation.
+BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent);
+
+// Call this when you mutate a message. It will cause the message to become
+// visible to its autocreator.
+void GPBBecomeVisibleToAutocreator(GPBMessage *self);
+
+// Call this when an array/dictionary is mutated so the parent message that
+// autocreated it can react.
+void GPBAutocreatedArrayModified(GPBMessage *self, id array);
+void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary);
+
+// Clear the autocreator, if any. Asserts if the autocreator still has an
+// autocreated reference to this message.
+void GPBClearMessageAutocreator(GPBMessage *self);
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBProtocolBuffers.h b/objectivec/GPBProtocolBuffers.h
new file mode 100644
index 0000000..677903e
--- /dev/null
+++ b/objectivec/GPBProtocolBuffers.h
@@ -0,0 +1,57 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBBootstrap.h"
+
+#import "GPBArray.h"
+#import "GPBCodedInputStream.h"
+#import "GPBCodedOutputStream.h"
+#import "GPBDescriptor.h"
+#import "GPBDictionary.h"
+#import "GPBExtensionRegistry.h"
+#import "GPBMessage.h"
+#import "GPBRootObject.h"
+#import "GPBUnknownField.h"
+#import "GPBUnknownFieldSet.h"
+#import "GPBUtilities.h"
+#import "GPBWellKnownTypes.h"
+#import "GPBWireFormat.h"
+
+// Well-known proto types
+#import "google/protobuf/Any.pbobjc.h"
+#import "google/protobuf/Api.pbobjc.h"
+#import "google/protobuf/Duration.pbobjc.h"
+#import "google/protobuf/Empty.pbobjc.h"
+#import "google/protobuf/FieldMask.pbobjc.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+#import "google/protobuf/Struct.pbobjc.h"
+#import "google/protobuf/Timestamp.pbobjc.h"
+#import "google/protobuf/Type.pbobjc.h"
+#import "google/protobuf/Wrappers.pbobjc.h"
diff --git a/objectivec/GPBProtocolBuffers.m b/objectivec/GPBProtocolBuffers.m
new file mode 100644
index 0000000..8512af7
--- /dev/null
+++ b/objectivec/GPBProtocolBuffers.m
@@ -0,0 +1,60 @@
+// 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.
+
+// If you want to build protocol buffers in your own project without adding the
+// project dependency, you can just add this file.
+
+#import "GPBArray.m"
+#import "GPBCodedInputStream.m"
+#import "GPBCodedOutputStream.m"
+#import "GPBDescriptor.m"
+#import "GPBDictionary.m"
+#import "GPBExtensionInternals.m"
+#import "GPBExtensionRegistry.m"
+#import "GPBMessage.m"
+#import "GPBRootObject.m"
+#import "GPBUnknownField.m"
+#import "GPBUnknownFieldSet.m"
+#import "GPBUtilities.m"
+#import "GPBWellKnownTypes.m"
+#import "GPBWireFormat.m"
+
+// Duration and Timestamp are #imported into GPBWellKnownTypes.m to the
+// Objective C categories added will always be linked in with the classes.
+#import "google/protobuf/Any.pbobjc.m"
+#import "google/protobuf/Api.pbobjc.m"
+// #import "google/protobuf/Duration.pbobjc.m"
+#import "google/protobuf/Empty.pbobjc.m"
+#import "google/protobuf/FieldMask.pbobjc.m"
+#import "google/protobuf/SourceContext.pbobjc.m"
+#import "google/protobuf/Struct.pbobjc.m"
+// #import "google/protobuf/Timestamp.pbobjc.m"
+#import "google/protobuf/Type.pbobjc.m"
+#import "google/protobuf/Wrappers.pbobjc.m"
diff --git a/objectivec/GPBProtocolBuffers_RuntimeSupport.h b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
new file mode 100644
index 0000000..fea75b9
--- /dev/null
+++ b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
@@ -0,0 +1,40 @@
+// 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.
+
+// This header is meant to only be used by the generated source, it should not
+// be included in code using protocol buffers.
+
+#import "GPBProtocolBuffers.h"
+
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBExtensionInternals.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBRootObject_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
diff --git a/objectivec/GPBRootObject.h b/objectivec/GPBRootObject.h
new file mode 100644
index 0000000..c05b5c6
--- /dev/null
+++ b/objectivec/GPBRootObject.h
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+@class GPBExtensionRegistry;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Every generated proto file defines a local "Root" class that exposes a
+/// @c GPBExtensionRegistry for all the extensions defined by that file and
+/// the files it depends on.
+@interface GPBRootObject : NSObject
+
+/// An extension registry for the given file and all the files it depends on.
++ (GPBExtensionRegistry *)extensionRegistry;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m
new file mode 100644
index 0000000..4570716
--- /dev/null
+++ b/objectivec/GPBRootObject.m
@@ -0,0 +1,230 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBRootObject_PackagePrivate.h"
+
+#import <objc/runtime.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import "GPBDescriptor.h"
+#import "GPBExtensionRegistry.h"
+#import "GPBUtilities_PackagePrivate.h"
+
+@interface GPBExtensionDescriptor (GPBRootObject)
+// Get singletonName as a c string.
+- (const char *)singletonNameC;
+@end
+
+@implementation GPBRootObject
+
+// Taken from http://www.burtleburtle.net/bob/hash/doobs.html
+// Public Domain
+static uint32_t jenkins_one_at_a_time_hash(const char *key) {
+  uint32_t hash = 0;
+  for (uint32_t i = 0; key[i] != '\0'; ++i) {
+    hash += key[i];
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+  }
+  hash += (hash << 3);
+  hash ^= (hash >> 11);
+  hash += (hash << 15);
+  return hash;
+}
+
+// Key methods for our custom CFDictionary.
+// Note that the dictionary lasts for the lifetime of our app, so no need
+// to worry about deallocation. All of the items are added to it at
+// startup, and so the keys don't need to be retained/released.
+// Keys are NULL terminated char *.
+static const void *GPBRootExtensionKeyRetain(CFAllocatorRef allocator,
+                                             const void *value) {
+#pragma unused(allocator)
+  return value;
+}
+
+static void GPBRootExtensionKeyRelease(CFAllocatorRef allocator,
+                                       const void *value) {
+#pragma unused(allocator)
+#pragma unused(value)
+}
+
+static CFStringRef GPBRootExtensionCopyKeyDescription(const void *value) {
+  const char *key = (const char *)value;
+  return CFStringCreateWithCString(kCFAllocatorDefault, key,
+                                   kCFStringEncodingUTF8);
+}
+
+static Boolean GPBRootExtensionKeyEqual(const void *value1,
+                                        const void *value2) {
+  const char *key1 = (const char *)value1;
+  const char *key2 = (const char *)value2;
+  return strcmp(key1, key2) == 0;
+}
+
+static CFHashCode GPBRootExtensionKeyHash(const void *value) {
+  const char *key = (const char *)value;
+  return jenkins_one_at_a_time_hash(key);
+}
+
+// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+// pointed out that they are vulnerable to live locking on iOS in cases of
+// priority inversion:
+//   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+//   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+static dispatch_semaphore_t gExtensionSingletonDictionarySemaphore;
+static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL;
+static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
+
++ (void)initialize {
+  // Ensure the global is started up.
+  if (!gExtensionSingletonDictionary) {
+    gExtensionSingletonDictionarySemaphore = dispatch_semaphore_create(1);
+    CFDictionaryKeyCallBacks keyCallBacks = {
+      // See description above for reason for using custom dictionary.
+      0,
+      GPBRootExtensionKeyRetain,
+      GPBRootExtensionKeyRelease,
+      GPBRootExtensionCopyKeyDescription,
+      GPBRootExtensionKeyEqual,
+      GPBRootExtensionKeyHash,
+    };
+    gExtensionSingletonDictionary =
+        CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks,
+                                  &kCFTypeDictionaryValueCallBacks);
+    gDefaultExtensionRegistry = [[GPBExtensionRegistry alloc] init];
+  }
+
+  if ([self superclass] == [GPBRootObject class]) {
+    // This is here to start up all the per file "Root" subclasses.
+    // This must be done in initialize to enforce thread safety of start up of
+    // the protocol buffer library.
+    [self extensionRegistry];
+  }
+}
+
++ (GPBExtensionRegistry *)extensionRegistry {
+  // Is overridden in all the subclasses that provide extensions to provide the
+  // per class one.
+  return gDefaultExtensionRegistry;
+}
+
++ (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field {
+  const char *key = [field singletonNameC];
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
+  CFDictionarySetValue(gExtensionSingletonDictionary, key, field);
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
+}
+
+static id ExtensionForName(id self, SEL _cmd) {
+  // Really fast way of doing "classname_selName".
+  // This came up as a hotspot (creation of NSString *) when accessing a
+  // lot of extensions.
+  const char *selName = sel_getName(_cmd);
+  if (selName[0] == '_') {
+    return nil;  // Apple internal selector.
+  }
+  size_t selNameLen = 0;
+  while (1) {
+    char c = selName[selNameLen];
+    if (c == '\0') {  // String end.
+      break;
+    }
+    if (c == ':') {
+      return nil;  // Selector took an arg, not one of the runtime methods.
+    }
+    ++selNameLen;
+  }
+
+  const char *className = class_getName(self);
+  size_t classNameLen = strlen(className);
+  char key[classNameLen + selNameLen + 2];
+  memcpy(key, className, classNameLen);
+  key[classNameLen] = '_';
+  memcpy(&key[classNameLen + 1], selName, selNameLen);
+  key[classNameLen + 1 + selNameLen] = '\0';
+
+  // NOTE: Even though this method is called from another C function,
+  // gExtensionSingletonDictionarySemaphore and gExtensionSingletonDictionary
+  // will always be initialized. This is because this call flow is just to
+  // lookup the Extension, meaning the code is calling an Extension class
+  // message on a Message or Root class. This guarantees that the class was
+  // initialized and Message classes ensure their Root was also initialized.
+  NSAssert(gExtensionSingletonDictionary, @"Startup order broken!");
+
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
+  id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
+  if (extension) {
+    // The method is getting wired in to the class, so no need to keep it in
+    // the dictionary.
+    CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
+  }
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
+  return extension;
+}
+
+BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) {
+  // Another option would be to register the extensions with the class at
+  // globallyRegisterExtension:
+  // Timing the two solutions, this solution turned out to be much faster
+  // and reduced startup time, and runtime memory.
+  // The advantage to globallyRegisterExtension is that it would reduce the
+  // size of the protos somewhat because the singletonNameC wouldn't need
+  // to include the class name. For a class with a lot of extensions it
+  // can add up. You could also significantly reduce the code complexity of this
+  // file.
+  id extension = ExtensionForName(self, sel);
+  if (extension != nil) {
+    const char *encoding =
+        GPBMessageEncodingForSelector(@selector(getClassValue), NO);
+    Class metaClass = objc_getMetaClass(class_getName(self));
+    IMP imp = imp_implementationWithBlock(^(id obj) {
+#pragma unused(obj)
+      return extension;
+    });
+    if (class_addMethod(metaClass, sel, imp, encoding)) {
+      return YES;
+    }
+  }
+  return NO;
+}
+
+
++ (BOOL)resolveClassMethod:(SEL)sel {
+  if (GPBResolveExtensionClassMethod(self, sel)) {
+    return YES;
+  }
+  return [super resolveClassMethod:sel];
+}
+
+@end
diff --git a/objectivec/GPBRootObject_PackagePrivate.h b/objectivec/GPBRootObject_PackagePrivate.h
new file mode 100644
index 0000000..3c8f09c
--- /dev/null
+++ b/objectivec/GPBRootObject_PackagePrivate.h
@@ -0,0 +1,46 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBRootObject.h"
+
+@class GPBExtensionDescriptor;
+
+@interface GPBRootObject ()
+
+// Globally register.
++ (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field;
+
+@end
+
+// Returns YES if the selector was resolved and added to the class,
+// NO otherwise.
+BOOL GPBResolveExtensionClassMethod(Class self, SEL sel);
diff --git a/objectivec/GPBRuntimeTypes.h b/objectivec/GPBRuntimeTypes.h
new file mode 100644
index 0000000..0a38b11
--- /dev/null
+++ b/objectivec/GPBRuntimeTypes.h
@@ -0,0 +1,102 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBBootstrap.h"
+
+@class GPBEnumDescriptor;
+@class GPBMessage;
+@class GPBInt32Array;
+
+// Function used to verify that a given value can be represented by an
+// enum type.
+typedef BOOL (*GPBEnumValidationFunc)(int32_t);
+
+// Function used to fetch an EnumDescriptor.
+typedef GPBEnumDescriptor *(*GPBEnumDescriptorFunc)(void);
+
+// Magic values used for when an the at runtime to indicate an enum value
+// that wasn't know at compile time.
+enum {
+  kGPBUnrecognizedEnumeratorValue = (int32_t)0xFBADBEEF,
+};
+
+// A union for storing all possible Protobuf values.
+// Note that owner is responsible for memory management of object types.
+typedef union {
+  BOOL valueBool;
+  int32_t valueInt32;
+  int64_t valueInt64;
+  uint32_t valueUInt32;
+  uint64_t valueUInt64;
+  float valueFloat;
+  double valueDouble;
+  GPB_UNSAFE_UNRETAINED NSData *valueData;
+  GPB_UNSAFE_UNRETAINED NSString *valueString;
+  GPB_UNSAFE_UNRETAINED GPBMessage *valueMessage;
+  int32_t valueEnum;
+} GPBGenericValue;
+
+// Do not change the order of this enum (or add things to it) without thinking
+// about it very carefully. There are several things that depend on the order.
+typedef NS_ENUM(uint8_t, GPBDataType) {
+  GPBDataTypeBool = 0,
+  GPBDataTypeFixed32,
+  GPBDataTypeSFixed32,
+  GPBDataTypeFloat,
+  GPBDataTypeFixed64,
+  GPBDataTypeSFixed64,
+  GPBDataTypeDouble,
+  GPBDataTypeInt32,
+  GPBDataTypeInt64,
+  GPBDataTypeSInt32,
+  GPBDataTypeSInt64,
+  GPBDataTypeUInt32,
+  GPBDataTypeUInt64,
+  GPBDataTypeBytes,
+  GPBDataTypeString,
+  GPBDataTypeMessage,
+  GPBDataTypeGroup,
+  GPBDataTypeEnum,
+};
+
+enum {
+  // A count of the number of types in GPBDataType. Separated out from the
+  // GPBDataType enum to avoid warnings regarding not handling
+  // GPBDataType_Count in switch statements.
+  GPBDataType_Count = GPBDataTypeEnum + 1
+};
+
+// An extension range.
+typedef struct GPBExtensionRange {
+  uint32_t start;  // inclusive
+  uint32_t end;    // exclusive
+} GPBExtensionRange;
diff --git a/objectivec/GPBUnknownField.h b/objectivec/GPBUnknownField.h
new file mode 100644
index 0000000..0f301e4
--- /dev/null
+++ b/objectivec/GPBUnknownField.h
@@ -0,0 +1,89 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+@class GPBCodedOutputStream;
+@class GPBUInt32Array;
+@class GPBUInt64Array;
+@class GPBUnknownFieldSet;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Store an unknown field. These are used in conjunction with @c GPBUnknownFieldSet
+@interface GPBUnknownField : NSObject<NSCopying>
+
+/// The field number the data is stored under.
+@property(nonatomic, readonly, assign) int32_t number;
+
+/// An array of varint values for this field.
+@property(nonatomic, readonly, strong) GPBUInt64Array *varintList;
+
+/// An array of fixed32 values for this field.
+@property(nonatomic, readonly, strong) GPBUInt32Array *fixed32List;
+
+/// An array of fixed64 values for this field.
+@property(nonatomic, readonly, strong) GPBUInt64Array *fixed64List;
+
+/// An array of data values for this field.
+@property(nonatomic, readonly, strong) NSArray<NSData*> *lengthDelimitedList;
+
+/// An array of groups of values for this field.
+@property(nonatomic, readonly, strong) NSArray<GPBUnknownFieldSet*> *groupList;
+
+
+/// Add a value to the varintList.
+///
+/// @param value The value to add.
+- (void)addVarint:(uint64_t)value;
+
+/// Add a value to the fixed32List.
+///
+/// @param value The value to add.
+- (void)addFixed32:(uint32_t)value;
+
+/// Add a value to the fixed64List.
+///
+/// @param value The value to add.
+- (void)addFixed64:(uint64_t)value;
+
+/// Add a value to the lengthDelimitedList.
+///
+/// @param value The value to add.
+- (void)addLengthDelimited:(NSData *)value;
+
+/// Add a value to the groupList.
+///
+/// @param value The value to add.
+- (void)addGroup:(GPBUnknownFieldSet *)value;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBUnknownField.m b/objectivec/GPBUnknownField.m
new file mode 100644
index 0000000..0e29bde
--- /dev/null
+++ b/objectivec/GPBUnknownField.m
@@ -0,0 +1,326 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBUnknownField_PackagePrivate.h"
+
+#import "GPBArray.h"
+#import "GPBCodedOutputStream_PackagePrivate.h"
+
+@implementation GPBUnknownField {
+ @protected
+  int32_t number_;
+  GPBUInt64Array *mutableVarintList_;
+  GPBUInt32Array *mutableFixed32List_;
+  GPBUInt64Array *mutableFixed64List_;
+  NSMutableArray<NSData*> *mutableLengthDelimitedList_;
+  NSMutableArray<GPBUnknownFieldSet*> *mutableGroupList_;
+}
+
+@synthesize number = number_;
+@synthesize varintList = mutableVarintList_;
+@synthesize fixed32List = mutableFixed32List_;
+@synthesize fixed64List = mutableFixed64List_;
+@synthesize lengthDelimitedList = mutableLengthDelimitedList_;
+@synthesize groupList = mutableGroupList_;
+
+- (instancetype)initWithNumber:(int32_t)number {
+  if ((self = [super init])) {
+    number_ = number;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [mutableVarintList_ release];
+  [mutableFixed32List_ release];
+  [mutableFixed64List_ release];
+  [mutableLengthDelimitedList_ release];
+  [mutableGroupList_ release];
+
+  [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  GPBUnknownField *result =
+      [[GPBUnknownField allocWithZone:zone] initWithNumber:number_];
+  result->mutableFixed32List_ = [mutableFixed32List_ copyWithZone:zone];
+  result->mutableFixed64List_ = [mutableFixed64List_ copyWithZone:zone];
+  result->mutableLengthDelimitedList_ =
+      [mutableLengthDelimitedList_ copyWithZone:zone];
+  result->mutableVarintList_ = [mutableVarintList_ copyWithZone:zone];
+  if (mutableGroupList_.count) {
+    result->mutableGroupList_ = [[NSMutableArray allocWithZone:zone]
+        initWithCapacity:mutableGroupList_.count];
+    for (GPBUnknownFieldSet *group in mutableGroupList_) {
+      GPBUnknownFieldSet *copied = [group copyWithZone:zone];
+      [result->mutableGroupList_ addObject:copied];
+      [copied release];
+    }
+  }
+  return result;
+}
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) return YES;
+  if (![object isKindOfClass:[GPBUnknownField class]]) return NO;
+  GPBUnknownField *field = (GPBUnknownField *)object;
+  BOOL equalVarint =
+      (mutableVarintList_.count == 0 && field->mutableVarintList_.count == 0) ||
+      [mutableVarintList_ isEqual:field->mutableVarintList_];
+  if (!equalVarint) return NO;
+  BOOL equalFixed32 = (mutableFixed32List_.count == 0 &&
+                       field->mutableFixed32List_.count == 0) ||
+                      [mutableFixed32List_ isEqual:field->mutableFixed32List_];
+  if (!equalFixed32) return NO;
+  BOOL equalFixed64 = (mutableFixed64List_.count == 0 &&
+                       field->mutableFixed64List_.count == 0) ||
+                      [mutableFixed64List_ isEqual:field->mutableFixed64List_];
+  if (!equalFixed64) return NO;
+  BOOL equalLDList =
+      (mutableLengthDelimitedList_.count == 0 &&
+       field->mutableLengthDelimitedList_.count == 0) ||
+      [mutableLengthDelimitedList_ isEqual:field->mutableLengthDelimitedList_];
+  if (!equalLDList) return NO;
+  BOOL equalGroupList =
+      (mutableGroupList_.count == 0 && field->mutableGroupList_.count == 0) ||
+      [mutableGroupList_ isEqual:field->mutableGroupList_];
+  if (!equalGroupList) return NO;
+  return YES;
+}
+
+- (NSUInteger)hash {
+  // Just mix the hashes of the possible sub arrays.
+  const int prime = 31;
+  NSUInteger result = prime + [mutableVarintList_ hash];
+  result = prime * result + [mutableFixed32List_ hash];
+  result = prime * result + [mutableFixed64List_ hash];
+  result = prime * result + [mutableLengthDelimitedList_ hash];
+  result = prime * result + [mutableGroupList_ hash];
+  return result;
+}
+
+- (void)writeToOutput:(GPBCodedOutputStream *)output {
+  NSUInteger count = mutableVarintList_.count;
+  if (count > 0) {
+    [output writeUInt64Array:number_ values:mutableVarintList_ tag:0];
+  }
+  count = mutableFixed32List_.count;
+  if (count > 0) {
+    [output writeFixed32Array:number_ values:mutableFixed32List_ tag:0];
+  }
+  count = mutableFixed64List_.count;
+  if (count > 0) {
+    [output writeFixed64Array:number_ values:mutableFixed64List_ tag:0];
+  }
+  count = mutableLengthDelimitedList_.count;
+  if (count > 0) {
+    [output writeBytesArray:number_ values:mutableLengthDelimitedList_];
+  }
+  count = mutableGroupList_.count;
+  if (count > 0) {
+    [output writeUnknownGroupArray:number_ values:mutableGroupList_];
+  }
+}
+
+- (size_t)serializedSize {
+  __block size_t result = 0;
+  int32_t number = number_;
+  [mutableVarintList_
+      enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        result += GPBComputeUInt64Size(number, value);
+      }];
+
+  [mutableFixed32List_
+      enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        result += GPBComputeFixed32Size(number, value);
+      }];
+
+  [mutableFixed64List_
+      enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        result += GPBComputeFixed64Size(number, value);
+      }];
+
+  for (NSData *data in mutableLengthDelimitedList_) {
+    result += GPBComputeBytesSize(number, data);
+  }
+
+  for (GPBUnknownFieldSet *set in mutableGroupList_) {
+    result += GPBComputeUnknownGroupSize(number, set);
+  }
+
+  return result;
+}
+
+- (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output {
+  for (NSData *data in mutableLengthDelimitedList_) {
+    [output writeRawMessageSetExtension:number_ value:data];
+  }
+}
+
+- (size_t)serializedSizeAsMessageSetExtension {
+  size_t result = 0;
+  for (NSData *data in mutableLengthDelimitedList_) {
+    result += GPBComputeRawMessageSetExtensionSize(number_, data);
+  }
+  return result;
+}
+
+- (NSString *)description {
+  NSMutableString *description = [NSMutableString
+      stringWithFormat:@"<%@ %p>: Field: %d {\n", [self class], self, number_];
+  [mutableVarintList_
+      enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        [description appendFormat:@"\t%llu\n", value];
+      }];
+
+  [mutableFixed32List_
+      enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        [description appendFormat:@"\t%u\n", value];
+      }];
+
+  [mutableFixed64List_
+      enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+#pragma unused(idx, stop)
+        [description appendFormat:@"\t%llu\n", value];
+      }];
+
+  for (NSData *data in mutableLengthDelimitedList_) {
+    [description appendFormat:@"\t%@\n", data];
+  }
+
+  for (GPBUnknownFieldSet *set in mutableGroupList_) {
+    [description appendFormat:@"\t%@\n", set];
+  }
+  [description appendString:@"}"];
+  return description;
+}
+
+- (void)mergeFromField:(GPBUnknownField *)other {
+  GPBUInt64Array *otherVarintList = other.varintList;
+  if (otherVarintList.count > 0) {
+    if (mutableVarintList_ == nil) {
+      mutableVarintList_ = [otherVarintList copy];
+    } else {
+      [mutableVarintList_ addValuesFromArray:otherVarintList];
+    }
+  }
+
+  GPBUInt32Array *otherFixed32List = other.fixed32List;
+  if (otherFixed32List.count > 0) {
+    if (mutableFixed32List_ == nil) {
+      mutableFixed32List_ = [otherFixed32List copy];
+    } else {
+      [mutableFixed32List_ addValuesFromArray:otherFixed32List];
+    }
+  }
+
+  GPBUInt64Array *otherFixed64List = other.fixed64List;
+  if (otherFixed64List.count > 0) {
+    if (mutableFixed64List_ == nil) {
+      mutableFixed64List_ = [otherFixed64List copy];
+    } else {
+      [mutableFixed64List_ addValuesFromArray:otherFixed64List];
+    }
+  }
+
+  NSArray *otherLengthDelimitedList = other.lengthDelimitedList;
+  if (otherLengthDelimitedList.count > 0) {
+    if (mutableLengthDelimitedList_ == nil) {
+      mutableLengthDelimitedList_ = [otherLengthDelimitedList mutableCopy];
+    } else {
+      [mutableLengthDelimitedList_
+          addObjectsFromArray:otherLengthDelimitedList];
+    }
+  }
+
+  NSArray *otherGroupList = other.groupList;
+  if (otherGroupList.count > 0) {
+    if (mutableGroupList_ == nil) {
+      mutableGroupList_ =
+          [[NSMutableArray alloc] initWithCapacity:otherGroupList.count];
+    }
+    // Make our own mutable copies.
+    for (GPBUnknownFieldSet *group in otherGroupList) {
+      GPBUnknownFieldSet *copied = [group copy];
+      [mutableGroupList_ addObject:copied];
+      [copied release];
+    }
+  }
+}
+
+- (void)addVarint:(uint64_t)value {
+  if (mutableVarintList_ == nil) {
+    mutableVarintList_ = [[GPBUInt64Array alloc] initWithValues:&value count:1];
+  } else {
+    [mutableVarintList_ addValue:value];
+  }
+}
+
+- (void)addFixed32:(uint32_t)value {
+  if (mutableFixed32List_ == nil) {
+    mutableFixed32List_ =
+        [[GPBUInt32Array alloc] initWithValues:&value count:1];
+  } else {
+    [mutableFixed32List_ addValue:value];
+  }
+}
+
+- (void)addFixed64:(uint64_t)value {
+  if (mutableFixed64List_ == nil) {
+    mutableFixed64List_ =
+        [[GPBUInt64Array alloc] initWithValues:&value count:1];
+  } else {
+    [mutableFixed64List_ addValue:value];
+  }
+}
+
+- (void)addLengthDelimited:(NSData *)value {
+  if (mutableLengthDelimitedList_ == nil) {
+    mutableLengthDelimitedList_ =
+        [[NSMutableArray alloc] initWithObjects:&value count:1];
+  } else {
+    [mutableLengthDelimitedList_ addObject:value];
+  }
+}
+
+- (void)addGroup:(GPBUnknownFieldSet *)value {
+  if (mutableGroupList_ == nil) {
+    mutableGroupList_ = [[NSMutableArray alloc] initWithObjects:&value count:1];
+  } else {
+    [mutableGroupList_ addObject:value];
+  }
+}
+
+@end
diff --git a/objectivec/GPBUnknownFieldSet.h b/objectivec/GPBUnknownFieldSet.h
new file mode 100644
index 0000000..cf61299
--- /dev/null
+++ b/objectivec/GPBUnknownFieldSet.h
@@ -0,0 +1,65 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+@class GPBUnknownField;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A collection of unknown fields.
+@interface GPBUnknownFieldSet : NSObject<NSCopying>
+
+/// Tests to see if the given field number has a value.
+///
+/// @param number The field number to check.
+///
+/// @return YES if there is an unknown field for the given field number.
+- (BOOL)hasField:(int32_t)number;
+
+/// Fetches the @c GPBUnknownField for the given field number.
+///
+/// @param number The field number to look up.
+///
+/// @return The @c GPBUnknownField or nil.
+- (nullable GPBUnknownField *)getField:(int32_t)number;
+
+/// Returns the number of fields in this set.
+- (NSUInteger)countOfFields;
+
+/// Adds the given field to the set.
+- (void)addField:(GPBUnknownField *)field;
+
+/// Returns an NSArray of the @c GPBUnknownFields sorted by the field numbers.
+- (NSArray<GPBUnknownField*> *)sortedFields;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m
new file mode 100644
index 0000000..4ddc0d2
--- /dev/null
+++ b/objectivec/GPBUnknownFieldSet.m
@@ -0,0 +1,423 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+
+#import "GPBCodedInputStream_PackagePrivate.h"
+#import "GPBCodedOutputStream.h"
+#import "GPBUnknownField_PackagePrivate.h"
+#import "GPBUtilities.h"
+#import "GPBWireFormat.h"
+
+#pragma mark CFDictionaryKeyCallBacks
+
+// We use a custom dictionary here because our keys are numbers and
+// conversion back and forth from NSNumber was costing us performance.
+// If/when we move to C++ this could be done using a std::map and some
+// careful retain/release calls.
+
+static const void *GPBUnknownFieldSetKeyRetain(CFAllocatorRef allocator,
+                                               const void *value) {
+#pragma unused(allocator)
+  return value;
+}
+
+static void GPBUnknownFieldSetKeyRelease(CFAllocatorRef allocator,
+                                         const void *value) {
+#pragma unused(allocator)
+#pragma unused(value)
+}
+
+static CFStringRef GPBUnknownFieldSetCopyKeyDescription(const void *value) {
+  return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"),
+                                  (int)value);
+}
+
+static Boolean GPBUnknownFieldSetKeyEqual(const void *value1,
+                                          const void *value2) {
+  return value1 == value2;
+}
+
+static CFHashCode GPBUnknownFieldSetKeyHash(const void *value) {
+  return (CFHashCode)value;
+}
+
+#pragma mark Helpers
+
+static void checkNumber(int32_t number) {
+  if (number == 0) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Zero is not a valid field number."];
+  }
+}
+
+@implementation GPBUnknownFieldSet {
+ @package
+  CFMutableDictionaryRef fields_;
+}
+
+static void CopyWorker(const void *key, const void *value, void *context) {
+#pragma unused(key)
+  GPBUnknownField *field = value;
+  GPBUnknownFieldSet *result = context;
+
+  GPBUnknownField *copied = [field copy];
+  [result addField:copied];
+  [copied release];
+}
+
+- (id)copyWithZone:(NSZone *)zone {
+  GPBUnknownFieldSet *result = [[GPBUnknownFieldSet allocWithZone:zone] init];
+  if (fields_) {
+    CFDictionaryApplyFunction(fields_, CopyWorker, result);
+  }
+  return result;
+}
+
+- (void)dealloc {
+  if (fields_) {
+    CFRelease(fields_);
+  }
+  [super dealloc];
+}
+
+- (BOOL)isEqual:(id)object {
+  BOOL equal = NO;
+  if ([object isKindOfClass:[GPBUnknownFieldSet class]]) {
+    GPBUnknownFieldSet *set = (GPBUnknownFieldSet *)object;
+    if ((fields_ == NULL) && (set->fields_ == NULL)) {
+      equal = YES;
+    } else if ((fields_ != NULL) && (set->fields_ != NULL)) {
+      equal = CFEqual(fields_, set->fields_);
+    }
+  }
+  return equal;
+}
+
+- (NSUInteger)hash {
+  // Return the hash of the fields dictionary (or just some value).
+  if (fields_) {
+    return CFHash(fields_);
+  }
+  return (NSUInteger)[GPBUnknownFieldSet class];
+}
+
+#pragma mark - Public Methods
+
+- (BOOL)hasField:(int32_t)number {
+  ssize_t key = number;
+  return fields_ ? (CFDictionaryGetValue(fields_, (void *)key) != nil) : NO;
+}
+
+- (GPBUnknownField *)getField:(int32_t)number {
+  ssize_t key = number;
+  GPBUnknownField *result =
+      fields_ ? CFDictionaryGetValue(fields_, (void *)key) : nil;
+  return result;
+}
+
+- (NSUInteger)countOfFields {
+  return fields_ ? CFDictionaryGetCount(fields_) : 0;
+}
+
+- (NSArray *)sortedFields {
+  if (!fields_) return nil;
+  size_t count = CFDictionaryGetCount(fields_);
+  ssize_t keys[count];
+  GPBUnknownField *values[count];
+  CFDictionaryGetKeysAndValues(fields_, (const void **)keys,
+                               (const void **)values);
+  struct GPBFieldPair {
+    ssize_t key;
+    GPBUnknownField *value;
+  } pairs[count];
+  for (size_t i = 0; i < count; ++i) {
+    pairs[i].key = keys[i];
+    pairs[i].value = values[i];
+  };
+  qsort_b(pairs, count, sizeof(struct GPBFieldPair),
+          ^(const void *first, const void *second) {
+            const struct GPBFieldPair *a = first;
+            const struct GPBFieldPair *b = second;
+            return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1);
+          });
+  for (size_t i = 0; i < count; ++i) {
+    values[i] = pairs[i].value;
+  };
+  return [NSArray arrayWithObjects:values count:count];
+}
+
+#pragma mark - Internal Methods
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
+  if (!fields_) return;
+  size_t count = CFDictionaryGetCount(fields_);
+  ssize_t keys[count];
+  GPBUnknownField *values[count];
+  CFDictionaryGetKeysAndValues(fields_, (const void **)keys,
+                               (const void **)values);
+  if (count > 1) {
+    struct GPBFieldPair {
+      ssize_t key;
+      GPBUnknownField *value;
+    } pairs[count];
+
+    for (size_t i = 0; i < count; ++i) {
+      pairs[i].key = keys[i];
+      pairs[i].value = values[i];
+    };
+    qsort_b(pairs, count, sizeof(struct GPBFieldPair),
+            ^(const void *first, const void *second) {
+              const struct GPBFieldPair *a = first;
+              const struct GPBFieldPair *b = second;
+              return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1);
+            });
+    for (size_t i = 0; i < count; ++i) {
+      GPBUnknownField *value = pairs[i].value;
+      [value writeToOutput:output];
+    }
+  } else {
+    [values[0] writeToOutput:output];
+  }
+}
+
+- (NSString *)description {
+  NSMutableString *description = [NSMutableString
+      stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self];
+  NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @"  ");
+  [description appendString:textFormat];
+  [description appendString:@"}"];
+  return description;
+}
+
+static void GPBUnknownFieldSetSerializedSize(const void *key, const void *value,
+                                             void *context) {
+#pragma unused(key)
+  GPBUnknownField *field = value;
+  size_t *result = context;
+  *result += [field serializedSize];
+}
+
+- (size_t)serializedSize {
+  size_t result = 0;
+  if (fields_) {
+    CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetSerializedSize,
+                              &result);
+  }
+  return result;
+}
+
+static void GPBUnknownFieldSetWriteAsMessageSetTo(const void *key,
+                                                  const void *value,
+                                                  void *context) {
+#pragma unused(key)
+  GPBUnknownField *field = value;
+  GPBCodedOutputStream *output = context;
+  [field writeAsMessageSetExtensionToOutput:output];
+}
+
+- (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output {
+  if (fields_) {
+    CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetWriteAsMessageSetTo,
+                              output);
+  }
+}
+
+static void GPBUnknownFieldSetSerializedSizeAsMessageSet(const void *key,
+                                                         const void *value,
+                                                         void *context) {
+#pragma unused(key)
+  GPBUnknownField *field = value;
+  size_t *result = context;
+  *result += [field serializedSizeAsMessageSetExtension];
+}
+
+- (size_t)serializedSizeAsMessageSet {
+  size_t result = 0;
+  if (fields_) {
+    CFDictionaryApplyFunction(
+        fields_, GPBUnknownFieldSetSerializedSizeAsMessageSet, &result);
+  }
+  return result;
+}
+
+- (NSData *)data {
+  NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize];
+  GPBCodedOutputStream *output =
+      [[GPBCodedOutputStream alloc] initWithData:data];
+  [self writeToCodedOutputStream:output];
+  [output release];
+  return data;
+}
+
++ (BOOL)isFieldTag:(int32_t)tag {
+  return GPBWireFormatGetTagWireType(tag) != GPBWireFormatEndGroup;
+}
+
+- (void)addField:(GPBUnknownField *)field {
+  int32_t number = [field number];
+  checkNumber(number);
+  if (!fields_) {
+    CFDictionaryKeyCallBacks keyCallBacks = {
+        // See description above for reason for using custom dictionary.
+        0, GPBUnknownFieldSetKeyRetain, GPBUnknownFieldSetKeyRelease,
+        GPBUnknownFieldSetCopyKeyDescription, GPBUnknownFieldSetKeyEqual,
+        GPBUnknownFieldSetKeyHash,
+    };
+    fields_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks,
+                                        &kCFTypeDictionaryValueCallBacks);
+  }
+  ssize_t key = number;
+  CFDictionarySetValue(fields_, (const void *)key, field);
+}
+
+- (GPBUnknownField *)mutableFieldForNumber:(int32_t)number create:(BOOL)create {
+  ssize_t key = number;
+  GPBUnknownField *existing =
+      fields_ ? CFDictionaryGetValue(fields_, (const void *)key) : nil;
+  if (!existing && create) {
+    existing = [[GPBUnknownField alloc] initWithNumber:number];
+    // This retains existing.
+    [self addField:existing];
+    [existing release];
+  }
+  return existing;
+}
+
+static void GPBUnknownFieldSetMergeUnknownFields(const void *key,
+                                                 const void *value,
+                                                 void *context) {
+#pragma unused(key)
+  GPBUnknownField *field = value;
+  GPBUnknownFieldSet *self = context;
+
+  int32_t number = [field number];
+  checkNumber(number);
+  GPBUnknownField *oldField = [self mutableFieldForNumber:number create:NO];
+  if (oldField) {
+    [oldField mergeFromField:field];
+  } else {
+    // Merge only comes from GPBMessage's mergeFrom:, so it means we are on
+    // mutable message and are an mutable instance, so make sure we need
+    // mutable fields.
+    GPBUnknownField *fieldCopy = [field copy];
+    [self addField:fieldCopy];
+    [fieldCopy release];
+  }
+}
+
+- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other {
+  if (other && other->fields_) {
+    CFDictionaryApplyFunction(other->fields_,
+                              GPBUnknownFieldSetMergeUnknownFields, self);
+  }
+}
+
+- (void)mergeFromData:(NSData *)data {
+  GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
+  [self mergeFromCodedInputStream:input];
+  [input checkLastTagWas:0];
+  [input release];
+}
+
+- (void)mergeVarintField:(int32_t)number value:(int32_t)value {
+  checkNumber(number);
+  [[self mutableFieldForNumber:number create:YES] addVarint:value];
+}
+
+- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input {
+  int32_t number = GPBWireFormatGetTagFieldNumber(tag);
+  GPBCodedInputStreamState *state = &input->state_;
+  switch (GPBWireFormatGetTagWireType(tag)) {
+    case GPBWireFormatVarint: {
+      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
+      [field addVarint:GPBCodedInputStreamReadInt64(state)];
+      return YES;
+    }
+    case GPBWireFormatFixed64: {
+      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
+      [field addFixed64:GPBCodedInputStreamReadFixed64(state)];
+      return YES;
+    }
+    case GPBWireFormatLengthDelimited: {
+      NSData *data = GPBCodedInputStreamReadRetainedBytes(state);
+      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
+      [field addLengthDelimited:data];
+      [data release];
+      return YES;
+    }
+    case GPBWireFormatStartGroup: {
+      GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init];
+      [input readUnknownGroup:number message:unknownFieldSet];
+      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
+      [field addGroup:unknownFieldSet];
+      [unknownFieldSet release];
+      return YES;
+    }
+    case GPBWireFormatEndGroup:
+      return NO;
+    case GPBWireFormatFixed32: {
+      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
+      [field addFixed32:GPBCodedInputStreamReadFixed32(state)];
+      return YES;
+    }
+  }
+}
+
+- (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData {
+  [[self mutableFieldForNumber:number create:YES]
+      addLengthDelimited:messageData];
+}
+
+- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
+  GPBUnknownField *field = [self mutableFieldForNumber:fieldNum create:YES];
+  [field addLengthDelimited:data];
+}
+
+- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input {
+  while (YES) {
+    int32_t tag = GPBCodedInputStreamReadTag(&input->state_);
+    if (tag == 0 || ![self mergeFieldFrom:tag input:input]) {
+      break;
+    }
+  }
+}
+
+- (void)getTags:(int32_t *)tags {
+  if (!fields_) return;
+  size_t count = CFDictionaryGetCount(fields_);
+  ssize_t keys[count];
+  CFDictionaryGetKeysAndValues(fields_, (const void **)keys, NULL);
+  for (size_t i = 0; i < count; ++i) {
+    tags[i] = (int32_t)keys[i];
+  }
+}
+
+@end
diff --git a/objectivec/GPBUnknownFieldSet_PackagePrivate.h b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
new file mode 100644
index 0000000..e27127a
--- /dev/null
+++ b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
@@ -0,0 +1,61 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBUnknownFieldSet.h"
+
+@class GPBCodedOutputStream;
+@class GPBCodedInputStream;
+
+@interface GPBUnknownFieldSet ()
+
++ (BOOL)isFieldTag:(int32_t)tag;
+
+- (NSData *)data;
+
+- (size_t)serializedSize;
+- (size_t)serializedSizeAsMessageSet;
+
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
+- (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output;
+
+- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other;
+
+- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input;
+- (void)mergeFromData:(NSData *)data;
+
+- (void)mergeVarintField:(int32_t)number value:(int32_t)value;
+- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input;
+- (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData;
+
+- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data;
+
+@end
diff --git a/objectivec/GPBUnknownField_PackagePrivate.h b/objectivec/GPBUnknownField_PackagePrivate.h
new file mode 100644
index 0000000..1fbce0f
--- /dev/null
+++ b/objectivec/GPBUnknownField_PackagePrivate.h
@@ -0,0 +1,49 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBUnknownField.h"
+
+@class GPBCodedOutputStream;
+
+@interface GPBUnknownField ()
+
+- (instancetype)initWithNumber:(int32_t)number;
+
+- (void)writeToOutput:(GPBCodedOutputStream *)output;
+- (size_t)serializedSize;
+
+- (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output;
+- (size_t)serializedSizeAsMessageSetExtension;
+
+- (void)mergeFromField:(GPBUnknownField *)other;
+
+@end
diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h
new file mode 100644
index 0000000..b720932
--- /dev/null
+++ b/objectivec/GPBUtilities.h
@@ -0,0 +1,257 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBArray.h"
+#import "GPBMessage.h"
+#import "GPBRuntimeTypes.h"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Generates a string that should be a valid "Text Format" for the C++ version
+/// of Protocol Buffers.
+///
+///  @param message    The message to generate from.
+///  @param lineIndent A string to use as the prefix for all lines generated. Can
+///                    be nil if no extra indent is needed.
+///
+/// @return A @c NSString with the Text Format of the message.
+NSString *GPBTextFormatForMessage(GPBMessage *message,
+                                  NSString * __nullable lineIndent);
+
+/// Generates a string that should be a valid "Text Format" for the C++ version
+/// of Protocol Buffers.
+///
+///  @param unknownSet The unknown field set to generate from.
+///  @param lineIndent A string to use as the prefix for all lines generated. Can
+///                    be nil if no extra indent is needed.
+///
+/// @return A @c NSString with the Text Format of the unknown field set.
+NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet * __nullable unknownSet,
+                                          NSString * __nullable lineIndent);
+
+/// Test if the given field is set on a message.
+BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber);
+/// Test if the given field is set on a message.
+BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field);
+
+/// Clear the given field of a message.
+void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field);
+
+//%PDDM-EXPAND GPB_ACCESSORS()
+// This block of code is generated, do not edit it directly.
+
+
+//
+// Get/Set the given field of a message.
+//
+
+// Single Fields
+
+/// Gets the value of a bytes field.
+NSData *GPBGetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a bytes field.
+void GPBSetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field, NSData *value);
+
+/// Gets the value of a string field.
+NSString *GPBGetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a string field.
+void GPBSetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field, NSString *value);
+
+/// Gets the value of a message field.
+GPBMessage *GPBGetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a message field.
+void GPBSetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
+
+/// Gets the value of a group field.
+GPBMessage *GPBGetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a group field.
+void GPBSetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
+
+/// Gets the value of a bool field.
+BOOL GPBGetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a bool field.
+void GPBSetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field, BOOL value);
+
+/// Gets the value of an int32 field.
+int32_t GPBGetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of an int32 field.
+void GPBSetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+
+/// Gets the value of an uint32 field.
+uint32_t GPBGetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of an uint32 field.
+void GPBSetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field, uint32_t value);
+
+/// Gets the value of an int64 field.
+int64_t GPBGetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of an int64 field.
+void GPBSetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field, int64_t value);
+
+/// Gets the value of an uint64 field.
+uint64_t GPBGetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of an uint64 field.
+void GPBSetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field, uint64_t value);
+
+/// Gets the value of a float field.
+float GPBGetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a float field.
+void GPBSetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field, float value);
+
+/// Gets the value of a double field.
+double GPBGetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a double field.
+void GPBSetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field, double value);
+
+/// Get the given enum field of a message. For proto3, if the value isn't a
+/// member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
+/// GPBGetMessageRawEnumField will bypass the check and return whatever value
+/// was set.
+int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Set the given enum field of a message. You can only set values that are
+/// members of the enum.
+void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+/// Get the given enum field of a message. No check is done to ensure the value
+/// was defined in the enum.
+int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Set the given enum field of a message. You can set the value to anything,
+/// even a value that is not a member of the enum.
+void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+
+// Repeated Fields
+
+/// Gets the value of a repeated field.
+///
+/// The result will be @c GPB*Array or @c NSMutableArray based on the
+/// field's type.
+id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a repeated field.
+///
+/// The value should be @c GPB*Array or @c NSMutableArray based on the
+/// field's type.
+void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+
+// Map Fields
+
+/// Gets the value of a map<> field.
+///
+/// The result will be @c GPB*Dictionary or @c NSMutableDictionary based on
+/// the field's type.
+id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
+/// Sets the value of a map<> field.
+///
+/// The object should be @c GPB*Dictionary or @c NSMutableDictionary based
+/// on the field's type.
+void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary);
+
+//%PDDM-EXPAND-END GPB_ACCESSORS()
+
+// Returns an empty NSData to assign to byte fields when you wish
+// to assign them to empty. Prevents allocating a lot of little [NSData data]
+// objects.
+NSData *GPBEmptyNSData(void) __attribute__((pure));
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+
+//%PDDM-DEFINE GPB_ACCESSORS()
+//%
+//%//
+//%// Get/Set the given field of a message.
+//%//
+//%
+//%// Single Fields
+//%
+//%GPB_ACCESSOR_SINGLE_FULL(Bytes, NSData, , *)
+//%GPB_ACCESSOR_SINGLE_FULL(String, NSString, , *)
+//%GPB_ACCESSOR_SINGLE_FULL(Message, GPBMessage, , *)
+//%GPB_ACCESSOR_SINGLE_FULL(Group, GPBMessage, , *)
+//%GPB_ACCESSOR_SINGLE(Bool, BOOL, )
+//%GPB_ACCESSOR_SINGLE(Int32, int32_t, n)
+//%GPB_ACCESSOR_SINGLE(UInt32, uint32_t, n)
+//%GPB_ACCESSOR_SINGLE(Int64, int64_t, n)
+//%GPB_ACCESSOR_SINGLE(UInt64, uint64_t, n)
+//%GPB_ACCESSOR_SINGLE(Float, float, )
+//%GPB_ACCESSOR_SINGLE(Double, double, )
+//%/// Get the given enum field of a message. For proto3, if the value isn't a
+//%/// member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
+//%/// GPBGetMessageRawEnumField will bypass the check and return whatever value
+//%/// was set.
+//%int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+//%/// Set the given enum field of a message. You can only set values that are
+//%/// members of the enum.
+//%void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+//%/// Get the given enum field of a message. No check is done to ensure the value
+//%/// was defined in the enum.
+//%int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
+//%/// Set the given enum field of a message. You can set the value to anything,
+//%/// even a value that is not a member of the enum.
+//%void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+//%
+//%// Repeated Fields
+//%
+//%/// Gets the value of a repeated field.
+//%///
+//%/// The result will be @c GPB*Array or @c NSMutableArray based on the
+//%/// field's type.
+//%id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
+//%/// Sets the value of a repeated field.
+//%///
+//%/// The value should be @c GPB*Array or @c NSMutableArray based on the
+//%/// field's type.
+//%void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+//%
+//%// Map Fields
+//%
+//%/// Gets the value of a map<> field.
+//%///
+//%/// The result will be @c GPB*Dictionary or @c NSMutableDictionary based on
+//%/// the field's type.
+//%id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
+//%/// Sets the value of a map<> field.
+//%///
+//%/// The object should be @c GPB*Dictionary or @c NSMutableDictionary based
+//%/// on the field's type.
+//%void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary);
+//%
+
+//%PDDM-DEFINE GPB_ACCESSOR_SINGLE(NAME, TYPE, AN)
+//%GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, AN, )
+//%PDDM-DEFINE GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, AN, TisP)
+//%/// Gets the value of a##AN NAME$L field.
+//%TYPE TisP##GPBGetMessage##NAME##Field(GPBMessage *self, GPBFieldDescriptor *field);
+//%/// Sets the value of a##AN NAME$L field.
+//%void GPBSetMessage##NAME##Field(GPBMessage *self, GPBFieldDescriptor *field, TYPE TisP##value);
+//%
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
new file mode 100644
index 0000000..447c749
--- /dev/null
+++ b/objectivec/GPBUtilities.m
@@ -0,0 +1,1717 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBUtilities_PackagePrivate.h"
+
+#import <objc/runtime.h>
+
+#import "GPBArray_PackagePrivate.h"
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBDictionary_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUnknownField.h"
+#import "GPBUnknownFieldSet.h"
+
+static void AppendTextFormatForMessage(GPBMessage *message,
+                                       NSMutableString *toStr,
+                                       NSString *lineIndent);
+
+NSData *GPBEmptyNSData(void) {
+  static dispatch_once_t onceToken;
+  static NSData *defaultNSData = nil;
+  dispatch_once(&onceToken, ^{
+    defaultNSData = [[NSData alloc] init];
+  });
+  return defaultNSData;
+}
+
+void GPBCheckRuntimeVersionInternal(int32_t version) {
+  if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) {
+    [NSException raise:NSInternalInconsistencyException
+                format:@"Linked to ProtocolBuffer runtime version %d,"
+                       @" but code compiled with version %d!",
+                       GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version];
+  }
+}
+
+BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) {
+  GPBDescriptor *descriptor = [self descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber];
+  return GPBMessageHasFieldSet(self, field);
+}
+
+BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) {
+  if (self == nil || field == nil) return NO;
+
+  // Repeated/Map don't use the bit, they check the count.
+  if (GPBFieldIsMapOrArray(field)) {
+    // Array/map type doesn't matter, since GPB*Array/NSArray and
+    // GPB*Dictionary/NSDictionary all support -count;
+    NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+    return (arrayOrMap.count > 0);
+  } else {
+    return GPBGetHasIvarField(self, field);
+  }
+}
+
+void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) {
+  // If not set, nothing to do.
+  if (!GPBGetHasIvarField(self, field)) {
+    return;
+  }
+
+  if (GPBFieldStoresObject(field)) {
+    // Object types are handled slightly differently, they need to be released.
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    id *typePtr = (id *)&storage[field->description_->offset];
+    [*typePtr release];
+    *typePtr = nil;
+  } else {
+    // POD types just need to clear the has bit as the Get* method will
+    // fetch the default when needed.
+  }
+  GPBSetHasIvarField(self, field, NO);
+}
+
+BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+  if (idx < 0) {
+    NSCAssert(fieldNumber != 0, @"Invalid field number.");
+    BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber);
+    return hasIvar;
+  } else {
+    NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
+    uint32_t byteIndex = idx / 32;
+    uint32_t bitMask = (1 << (idx % 32));
+    BOOL hasIvar =
+        (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO;
+    return hasIvar;
+  }
+}
+
+uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) {
+  NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.",
+            [self class], idx);
+  uint32_t result = self->messageStorage_->_has_storage_[-idx];
+  return result;
+}
+
+void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
+                   BOOL value) {
+  if (idx < 0) {
+    NSCAssert(fieldNumber != 0, @"Invalid field number.");
+    uint32_t *has_storage = self->messageStorage_->_has_storage_;
+    has_storage[-idx] = (value ? fieldNumber : 0);
+  } else {
+    NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
+    uint32_t *has_storage = self->messageStorage_->_has_storage_;
+    uint32_t byte = idx / 32;
+    uint32_t bitMask = (1 << (idx % 32));
+    if (value) {
+      has_storage[byte] |= bitMask;
+    } else {
+      has_storage[byte] &= ~bitMask;
+    }
+  }
+}
+
+void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
+                        int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
+  uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex);
+  if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) {
+    // Do nothing/nothing set in the oneof.
+    return;
+  }
+
+  // Like GPBClearMessageField(), free the memory if an objecttype is set,
+  // pod types don't need to do anything.
+  GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet];
+  NSCAssert(fieldSet,
+            @"%@: oneof set to something (%u) not in the oneof?",
+            [self class], fieldNumberSet);
+  if (fieldSet && GPBFieldStoresObject(fieldSet)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    id *typePtr = (id *)&storage[fieldSet->description_->offset];
+    [*typePtr release];
+    *typePtr = nil;
+  }
+
+  // Set to nothing stored in the oneof.
+  // (field number doesn't matter since setting to nothing).
+  GPBSetHasIvar(self, oneofHasIndex, 1, NO);
+}
+
+#pragma mark - IVar accessors
+
+//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
+//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
+//% TYPE$S            NAME$S       GPBFieldDescriptor *field) {
+//%  if (GPBGetHasIvarField(self, field)) {
+//%    uint8_t *storage = (uint8_t *)self->messageStorage_;
+//%    TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
+//%    return *typePtr;
+//%  } else {
+//%    return field.defaultValue.value##NAME;
+//%  }
+//%}
+//%
+//%// Only exists for public api, no core code should use this.
+//%void GPBSetMessage##NAME##Field(GPBMessage *self,
+//%                   NAME$S     GPBFieldDescriptor *field,
+//%                   NAME$S     TYPE value) {
+//%  if (self == nil || field == nil) return;
+//%  GPBFileSyntax syntax = [self descriptor].file.syntax;
+//%  GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
+//%}
+//%
+//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
+//%            NAME$S                     GPBFieldDescriptor *field,
+//%            NAME$S                     TYPE value,
+//%            NAME$S                     GPBFileSyntax syntax) {
+//%  GPBOneofDescriptor *oneof = field->containingOneof_;
+//%  if (oneof) {
+//%    GPBMessageFieldDescription *fieldDesc = field->description_;
+//%    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+//%  }
+//%  NSCAssert(self->messageStorage_ != NULL,
+//%            @"%@: All messages should have storage (from init)",
+//%            [self class]);
+//%#if defined(__clang_analyzer__)
+//%  if (self->messageStorage_ == NULL) return;
+//%#endif
+//%  uint8_t *storage = (uint8_t *)self->messageStorage_;
+//%  TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
+//%  *typePtr = value;
+//%  // proto2: any value counts as having been set; proto3, it
+//%  // has to be a non zero value.
+//%  BOOL hasValue =
+//%    (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0);
+//%  GPBSetHasIvarField(self, field, hasValue);
+//%  GPBBecomeVisibleToAutocreator(self);
+//%}
+//%
+//%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE)
+//%// Only exists for public api, no core code should use this.
+//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
+//% TYPE$S             NAME$S       GPBFieldDescriptor *field) {
+//%  return (TYPE *)GPBGetObjectIvarWithField(self, field);
+//%}
+//%
+//%// Only exists for public api, no core code should use this.
+//%void GPBSetMessage##NAME##Field(GPBMessage *self,
+//%                   NAME$S     GPBFieldDescriptor *field,
+//%                   NAME$S     TYPE *value) {
+//%  GPBSetObjectIvarWithField(self, field, (id)value);
+//%}
+//%
+
+// Object types are handled slightly differently, they need to be released
+// and retained.
+
+void GPBSetAutocreatedRetainedObjectIvarWithField(
+    GPBMessage *self, GPBFieldDescriptor *field,
+    id __attribute__((ns_consumed)) value) {
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  id *typePtr = (id *)&storage[field->description_->offset];
+  NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once.");
+  *typePtr = value;
+}
+
+void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
+                                             GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    return;
+  }
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  id *typePtr = (id *)&storage[field->description_->offset];
+  GPBMessage *oldValue = *typePtr;
+  *typePtr = NULL;
+  GPBClearMessageAutocreator(oldValue);
+  [oldValue release];
+}
+
+// This exists only for briging some aliased types, nothing else should use it.
+static void GPBSetObjectIvarWithField(GPBMessage *self,
+                                      GPBFieldDescriptor *field, id value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
+                                            syntax);
+}
+
+void GPBSetObjectIvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field, id value,
+                                       GPBFileSyntax syntax) {
+  GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
+                                            syntax);
+}
+
+void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
+                                               GPBFieldDescriptor *field,
+                                               id value, GPBFileSyntax syntax) {
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  GPBDataType fieldType = GPBGetFieldDataType(field);
+  BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
+  BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
+#ifdef DEBUG
+  if (value == nil && !isMapOrArray && !fieldIsMessage &&
+      field.hasDefaultValue) {
+    // Setting a message to nil is an obvious way to "clear" the value
+    // as there is no way to set a non-empty default value for messages.
+    //
+    // For Strings and Bytes that have default values set it is not clear what
+    // should be done when their value is set to nil. Is the intention just to
+    // clear the set value and reset to default, or is the intention to set the
+    // value to the empty string/data? Arguments can be made for both cases.
+    // 'nil' has been abused as a replacement for an empty string/data in ObjC.
+    // We decided to be consistent with all "object" types and clear the has
+    // field, and fall back on the default value. The warning below will only
+    // appear in debug, but the could should be changed so the intention is
+    // clear.
+    NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_);
+    NSString *propName = field.name;
+    NSString *className = self.descriptor.name;
+    NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with "
+          @"default values. Please use '%@.%@ = %@' if you want to set it to "
+          @"empty, or call '%@.%@ = NO' to reset it to it's default value of "
+          @"'%@'. Defaulting to resetting default value.",
+          className, propName, className, propName,
+          (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()",
+          className, hasSel, field.defaultValue.valueString);
+    // Note: valueString, depending on the type, it could easily be
+    // valueData/valueMessage.
+  }
+#endif  // DEBUG
+  if (!isMapOrArray) {
+    // Non repeated/map can be in an oneof, clear any existing value from the
+    // oneof.
+    GPBOneofDescriptor *oneof = field->containingOneof_;
+    if (oneof) {
+      GPBMessageFieldDescription *fieldDesc = field->description_;
+      GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+    }
+    // Clear "has" if they are being set to nil.
+    BOOL setHasValue = (value != nil);
+    // Under proto3, Bytes & String fields get cleared by resetting them to
+    // their default (empty) values, so if they are set to something of length
+    // zero, they are being cleared.
+    if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
+        ([value length] == 0)) {
+      setHasValue = NO;
+      value = nil;
+    }
+    GPBSetHasIvarField(self, field, setHasValue);
+  }
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  id *typePtr = (id *)&storage[field->description_->offset];
+
+  id oldValue = *typePtr;
+
+  *typePtr = value;
+
+  if (oldValue) {
+    if (isMapOrArray) {
+      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;
+          }
+        } else {
+          // Type doesn't matter, it is a GPB*Array.
+          GPBInt32Array *gpbArray = oldValue;
+          if (gpbArray->_autocreator == self) {
+            gpbArray->_autocreator = nil;
+          }
+        }
+      } else { // GPBFieldTypeMap
+        // 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;
+          }
+        } else {
+          // Type doesn't matter, it is a GPB*Dictionary.
+          GPBInt32Int32Dictionary *gpbDict = oldValue;
+          if (gpbDict->_autocreator == self) {
+            gpbDict->_autocreator = nil;
+          }
+        }
+      }
+    } else if (fieldIsMessage) {
+      // If the old message value was autocreated by us, then clear it.
+      GPBMessage *oldMessageValue = oldValue;
+      if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) {
+        GPBClearMessageAutocreator(oldMessageValue);
+      }
+    }
+    [oldValue release];
+  }
+
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
+                                         GPBFieldDescriptor *field) {
+  if (self->messageStorage_ == nil) {
+    return nil;
+  }
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  id *typePtr = (id *)&storage[field->description_->offset];
+  return *typePtr;
+}
+
+id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
+  NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    id *typePtr = (id *)&storage[field->description_->offset];
+    return *typePtr;
+  }
+  // Not set...
+
+  // Non messages (string/data), get their default.
+  if (!GPBFieldDataTypeIsMessage(field)) {
+    return field.defaultValue.valueMessage;
+  }
+
+  GPBPrepareReadOnlySemaphore(self);
+  dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
+  GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!result) {
+    // For non repeated messages, create the object, set it and return it.
+    // This object will not initially be visible via GPBGetHasIvar, so
+    // we save its creator so it can become visible if it's mutated later.
+    result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
+    GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
+  }
+  dispatch_semaphore_signal(self->readOnlySemaphore_);
+  return result;
+}
+
+// Only exists for public api, no core code should use this.
+int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  return GPBGetEnumIvarWithFieldInternal(self, field, syntax);
+}
+
+int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
+                                        GPBFieldDescriptor *field,
+                                        GPBFileSyntax syntax) {
+  int32_t result = GPBGetMessageInt32Field(self, field);
+  // If this is presevering unknown enums, make sure the value is valid before
+  // returning it.
+  if (GPBHasPreservingUnknownEnumSemantics(syntax) &&
+      ![field isValidEnumValue:result]) {
+    result = kGPBUnrecognizedEnumeratorValue;
+  }
+  return result;
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
+                            int32_t value) {
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
+                                     GPBFieldDescriptor *field, int32_t value,
+                                     GPBFileSyntax syntax) {
+  // Don't allow in unknown values.  Proto3 can use the Raw method.
+  if (![field isValidEnumValue:value]) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@: Attempt to set an unknown enum value (%d)",
+                       [self class], field.name, value];
+  }
+  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+// Only exists for public api, no core code should use this.
+int32_t GPBGetMessageRawEnumField(GPBMessage *self,
+                                  GPBFieldDescriptor *field) {
+  int32_t result = GPBGetMessageInt32Field(self, field);
+  return result;
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
+                               int32_t value) {
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+BOOL GPBGetMessageBoolField(GPBMessage *self,
+                            GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    // Bools are stored in the has bits to avoid needing explicit space in the
+    // storage structure.
+    // (the field number passed to the HasIvar helper doesn't really matter
+    // since the offset is never negative)
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
+  } else {
+    return field.defaultValue.valueBool;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageBoolField(GPBMessage *self,
+                            GPBFieldDescriptor *field,
+                            BOOL value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetBoolIvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
+                                     GPBFieldDescriptor *field,
+                                     BOOL value,
+                                     GPBFileSyntax syntax) {
+  GPBMessageFieldDescription *fieldDesc = field->description_;
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+
+  // Bools are stored in the has bits to avoid needing explicit space in the
+  // storage structure.
+  // (the field number passed to the HasIvar helper doesn't really matter since
+  // the offset is never negative)
+  GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
+
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t)
+// This block of code is generated, do not edit it directly.
+
+int32_t GPBGetMessageInt32Field(GPBMessage *self,
+                                GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueInt32;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageInt32Field(GPBMessage *self,
+                             GPBFieldDescriptor *field,
+                             int32_t value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int32_t value,
+                                      GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t)
+// This block of code is generated, do not edit it directly.
+
+uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
+                                  GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueUInt32;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageUInt32Field(GPBMessage *self,
+                              GPBFieldDescriptor *field,
+                              uint32_t value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint32_t value,
+                                       GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t)
+// This block of code is generated, do not edit it directly.
+
+int64_t GPBGetMessageInt64Field(GPBMessage *self,
+                                GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueInt64;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageInt64Field(GPBMessage *self,
+                             GPBFieldDescriptor *field,
+                             int64_t value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int64_t value,
+                                      GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t)
+// This block of code is generated, do not edit it directly.
+
+uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
+                                  GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueUInt64;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageUInt64Field(GPBMessage *self,
+                              GPBFieldDescriptor *field,
+                              uint64_t value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint64_t value,
+                                       GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float)
+// This block of code is generated, do not edit it directly.
+
+float GPBGetMessageFloatField(GPBMessage *self,
+                              GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    float *typePtr = (float *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueFloat;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageFloatField(GPBMessage *self,
+                             GPBFieldDescriptor *field,
+                             float value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      float value,
+                                      GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  float *typePtr = (float *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (float)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double)
+// This block of code is generated, do not edit it directly.
+
+double GPBGetMessageDoubleField(GPBMessage *self,
+                                GPBFieldDescriptor *field) {
+  if (GPBGetHasIvarField(self, field)) {
+    uint8_t *storage = (uint8_t *)self->messageStorage_;
+    double *typePtr = (double *)&storage[field->description_->offset];
+    return *typePtr;
+  } else {
+    return field.defaultValue.valueDouble;
+  }
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageDoubleField(GPBMessage *self,
+                              GPBFieldDescriptor *field,
+                              double value) {
+  if (self == nil || field == nil) return;
+  GPBFileSyntax syntax = [self descriptor].file.syntax;
+  GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
+}
+
+void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       double value,
+                                       GPBFileSyntax syntax) {
+  GPBOneofDescriptor *oneof = field->containingOneof_;
+  if (oneof) {
+    GPBMessageFieldDescription *fieldDesc = field->description_;
+    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
+  }
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
+#if defined(__clang_analyzer__)
+  if (self->messageStorage_ == NULL) return;
+#endif
+  uint8_t *storage = (uint8_t *)self->messageStorage_;
+  double *typePtr = (double *)&storage[field->description_->offset];
+  *typePtr = value;
+  // proto2: any value counts as having been set; proto3, it
+  // has to be a non zero value.
+  BOOL hasValue =
+    (syntax == GPBFileSyntaxProto2) || (value != (double)0);
+  GPBSetHasIvarField(self, field, hasValue);
+  GPBBecomeVisibleToAutocreator(self);
+}
+
+//%PDDM-EXPAND-END (6 expansions)
+
+// Aliases are function calls that are virtually the same.
+
+//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(String, NSString)
+// This block of code is generated, do not edit it directly.
+
+// Only exists for public api, no core code should use this.
+NSString *GPBGetMessageStringField(GPBMessage *self,
+                                   GPBFieldDescriptor *field) {
+  return (NSString *)GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageStringField(GPBMessage *self,
+                              GPBFieldDescriptor *field,
+                              NSString *value) {
+  GPBSetObjectIvarWithField(self, field, (id)value);
+}
+
+//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Bytes, NSData)
+// This block of code is generated, do not edit it directly.
+
+// Only exists for public api, no core code should use this.
+NSData *GPBGetMessageBytesField(GPBMessage *self,
+                                GPBFieldDescriptor *field) {
+  return (NSData *)GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageBytesField(GPBMessage *self,
+                             GPBFieldDescriptor *field,
+                             NSData *value) {
+  GPBSetObjectIvarWithField(self, field, (id)value);
+}
+
+//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage)
+// This block of code is generated, do not edit it directly.
+
+// Only exists for public api, no core code should use this.
+GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
+                                      GPBFieldDescriptor *field) {
+  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageMessageField(GPBMessage *self,
+                               GPBFieldDescriptor *field,
+                               GPBMessage *value) {
+  GPBSetObjectIvarWithField(self, field, (id)value);
+}
+
+//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage)
+// This block of code is generated, do not edit it directly.
+
+// Only exists for public api, no core code should use this.
+GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
+                                    GPBFieldDescriptor *field) {
+  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageGroupField(GPBMessage *self,
+                             GPBFieldDescriptor *field,
+                             GPBMessage *value) {
+  GPBSetObjectIvarWithField(self, field, (id)value);
+}
+
+//%PDDM-EXPAND-END (4 expansions)
+
+// Only exists for public api, no core code should use this.
+id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) {
+#if DEBUG
+  if (field.fieldType != GPBFieldTypeRepeated) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@ is not a repeated field.",
+                       [self class], field.name];
+  }
+#endif
+  return GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
+#if DEBUG
+  if (field.fieldType != GPBFieldTypeRepeated) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@ is not a repeated field.",
+                       [self class], field.name];
+  }
+  Class expectedClass = Nil;
+  switch (GPBGetFieldDataType(field)) {
+    case GPBDataTypeBool:
+      expectedClass = [GPBBoolArray class];
+      break;
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeInt32:
+    case GPBDataTypeSInt32:
+      expectedClass = [GPBInt32Array class];
+      break;
+    case GPBDataTypeFixed32:
+    case GPBDataTypeUInt32:
+      expectedClass = [GPBUInt32Array class];
+      break;
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeInt64:
+    case GPBDataTypeSInt64:
+      expectedClass = [GPBInt64Array class];
+      break;
+    case GPBDataTypeFixed64:
+    case GPBDataTypeUInt64:
+      expectedClass = [GPBUInt64Array class];
+      break;
+    case GPBDataTypeFloat:
+      expectedClass = [GPBFloatArray class];
+      break;
+    case GPBDataTypeDouble:
+      expectedClass = [GPBDoubleArray class];
+      break;
+    case GPBDataTypeBytes:
+    case GPBDataTypeString:
+    case GPBDataTypeMessage:
+    case GPBDataTypeGroup:
+      expectedClass = [NSMutableDictionary class];
+      break;
+    case GPBDataTypeEnum:
+      expectedClass = [GPBBoolArray class];
+      break;
+  }
+  if (array && ![array isKindOfClass:expectedClass]) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@: Expected %@ object, got %@.",
+                       [self class], field.name, expectedClass, [array class]];
+  }
+#endif
+  GPBSetObjectIvarWithField(self, field, array);
+}
+
+#if DEBUG
+static NSString *TypeToStr(GPBDataType dataType) {
+  switch (dataType) {
+    case GPBDataTypeBool:
+      return @"Bool";
+    case GPBDataTypeSFixed32:
+    case GPBDataTypeInt32:
+    case GPBDataTypeSInt32:
+      return @"Int32";
+    case GPBDataTypeFixed32:
+    case GPBDataTypeUInt32:
+      return @"UInt32";
+    case GPBDataTypeSFixed64:
+    case GPBDataTypeInt64:
+    case GPBDataTypeSInt64:
+      return @"Int64";
+    case GPBDataTypeFixed64:
+    case GPBDataTypeUInt64:
+      return @"UInt64";
+    case GPBDataTypeFloat:
+      return @"Float";
+    case GPBDataTypeDouble:
+      return @"Double";
+    case GPBDataTypeBytes:
+    case GPBDataTypeString:
+    case GPBDataTypeMessage:
+    case GPBDataTypeGroup:
+      return @"Object";
+    case GPBDataTypeEnum:
+      return @"Bool";
+  }
+}
+#endif
+
+// Only exists for public api, no core code should use this.
+id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
+#if DEBUG
+  if (field.fieldType != GPBFieldTypeMap) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@ is not a map<> field.",
+                       [self class], field.name];
+  }
+#endif
+  return GPBGetObjectIvarWithField(self, field);
+}
+
+// Only exists for public api, no core code should use this.
+void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
+                           id dictionary) {
+#if DEBUG
+  if (field.fieldType != GPBFieldTypeMap) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"%@.%@ is not a map<> field.",
+                       [self class], field.name];
+  }
+  if (dictionary) {
+    GPBDataType keyDataType = field.mapKeyDataType;
+    GPBDataType valueDataType = GPBGetFieldDataType(field);
+    NSString *keyStr = TypeToStr(keyDataType);
+    NSString *valueStr = TypeToStr(valueDataType);
+    if (keyDataType == GPBDataTypeString) {
+      keyStr = @"String";
+    }
+    Class expectedClass = Nil;
+    if ((keyDataType == GPBDataTypeString) &&
+        GPBDataTypeIsObject(valueDataType)) {
+      expectedClass = [NSMutableDictionary class];
+    } else {
+      NSString *className =
+          [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr];
+      expectedClass = NSClassFromString(className);
+      NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass);
+    }
+    if (![dictionary isKindOfClass:expectedClass]) {
+      [NSException raise:NSInvalidArgumentException
+                  format:@"%@.%@: Expected %@ object, got %@.",
+                         [self class], field.name, expectedClass,
+                         [dictionary class]];
+    }
+  }
+#endif
+  GPBSetObjectIvarWithField(self, field, dictionary);
+}
+
+#pragma mark - Misc Dynamic Runtime Utils
+
+const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
+  Protocol *protocol =
+      objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
+  struct objc_method_description description =
+      protocol_getMethodDescription(protocol, selector, NO, instanceSel);
+  return description.types;
+}
+
+#pragma mark - Text Format Support
+
+static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
+  [destStr appendString:@"\""];
+  NSUInteger len = [toPrint length];
+  for (NSUInteger i = 0; i < len; ++i) {
+    unichar aChar = [toPrint characterAtIndex:i];
+    switch (aChar) {
+      case '\n': [destStr appendString:@"\\n"];  break;
+      case '\r': [destStr appendString:@"\\r"];  break;
+      case '\t': [destStr appendString:@"\\t"];  break;
+      case '\"': [destStr appendString:@"\\\""]; break;
+      case '\'': [destStr appendString:@"\\\'"]; break;
+      case '\\': [destStr appendString:@"\\\\"]; break;
+      default:
+        [destStr appendFormat:@"%C", aChar];
+        break;
+    }
+  }
+  [destStr appendString:@"\""];
+}
+
+static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) {
+  const char *src = (const char *)[buffer bytes];
+  size_t srcLen = [buffer length];
+  [destStr appendString:@"\""];
+  for (const char *srcEnd = src + srcLen; src < srcEnd; src++) {
+    switch (*src) {
+      case '\n': [destStr appendString:@"\\n"];  break;
+      case '\r': [destStr appendString:@"\\r"];  break;
+      case '\t': [destStr appendString:@"\\t"];  break;
+      case '\"': [destStr appendString:@"\\\""]; break;
+      case '\'': [destStr appendString:@"\\\'"]; break;
+      case '\\': [destStr appendString:@"\\\\"]; break;
+      default:
+        if (isprint(*src)) {
+          [destStr appendFormat:@"%c", *src];
+        } else {
+          // NOTE: doing hex means you have to worry about the letter after
+          // the hex being another hex char and forcing that to be escaped, so
+          // use octal to keep it simple.
+          [destStr appendFormat:@"\\%03o", (uint8_t)(*src)];
+        }
+        break;
+    }
+  }
+  [destStr appendString:@"\""];
+}
+
+static void AppendTextFormatForMapMessageField(
+    id map, GPBFieldDescriptor *field, NSMutableString *toStr,
+    NSString *lineIndent, NSString *fieldName, NSString *lineEnding) {
+  GPBDataType keyDataType = field.mapKeyDataType;
+  GPBDataType valueDataType = GPBGetFieldDataType(field);
+  BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType);
+
+  NSString *msgStartFirst =
+      [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding];
+  NSString *msgStart =
+      [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName];
+  NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent];
+
+  NSString *keyLine = [NSString stringWithFormat:@"%@  key: ", lineIndent];
+  NSString *valueLine = [NSString stringWithFormat:@"%@  value%s ", lineIndent,
+                                                   (isMessageValue ? "" : ":")];
+
+  __block BOOL isFirst = YES;
+
+  if ((keyDataType == GPBDataTypeString) &&
+      GPBDataTypeIsObject(valueDataType)) {
+    // map is an NSDictionary.
+    NSDictionary *dict = map;
+    [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
+      #pragma unused(stop)
+      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
+      isFirst = NO;
+
+      [toStr appendString:keyLine];
+      AppendStringEscaped(key, toStr);
+      [toStr appendString:@"\n"];
+
+      [toStr appendString:valueLine];
+      switch (valueDataType) {
+        case GPBDataTypeString:
+          AppendStringEscaped(value, toStr);
+          break;
+
+        case GPBDataTypeBytes:
+          AppendBufferAsString(value, toStr);
+          break;
+
+        case GPBDataTypeMessage:
+          [toStr appendString:@"{\n"];
+          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
+          AppendTextFormatForMessage(value, toStr, subIndent);
+          [toStr appendFormat:@"%@  }", lineIndent];
+          break;
+
+        default:
+          NSCAssert(NO, @"Can't happen");
+          break;
+      }
+      [toStr appendString:@"\n"];
+
+      [toStr appendString:msgEnd];
+    }];
+  } else {
+    // map is one of the GPB*Dictionary classes, type doesn't matter.
+    GPBInt32Int32Dictionary *dict = map;
+    [dict enumerateForTextFormat:^(id keyObj, id valueObj) {
+      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
+      isFirst = NO;
+
+      // Key always is a NSString.
+      if (keyDataType == GPBDataTypeString) {
+        [toStr appendString:keyLine];
+        AppendStringEscaped(keyObj, toStr);
+        [toStr appendString:@"\n"];
+      } else {
+        [toStr appendFormat:@"%@%@\n", keyLine, keyObj];
+      }
+
+      [toStr appendString:valueLine];
+      switch (valueDataType) {
+        case GPBDataTypeString:
+          AppendStringEscaped(valueObj, toStr);
+          break;
+
+        case GPBDataTypeBytes:
+          AppendBufferAsString(valueObj, toStr);
+          break;
+
+        case GPBDataTypeMessage:
+          [toStr appendString:@"{\n"];
+          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
+          AppendTextFormatForMessage(valueObj, toStr, subIndent);
+          [toStr appendFormat:@"%@  }", lineIndent];
+          break;
+
+        case GPBDataTypeEnum: {
+          int32_t enumValue = [valueObj intValue];
+          NSString *valueStr = nil;
+          GPBEnumDescriptor *descriptor = field.enumDescriptor;
+          if (descriptor) {
+            valueStr = [descriptor textFormatNameForValue:enumValue];
+          }
+          if (valueStr) {
+            [toStr appendString:valueStr];
+          } else {
+            [toStr appendFormat:@"%d", enumValue];
+          }
+          break;
+        }
+
+        default:
+          NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen");
+          // Everything else is a NSString.
+          [toStr appendString:valueObj];
+          break;
+      }
+      [toStr appendString:@"\n"];
+
+      [toStr appendString:msgEnd];
+    }];
+  }
+}
+
+static void AppendTextFormatForMessageField(GPBMessage *message,
+                                            GPBFieldDescriptor *field,
+                                            NSMutableString *toStr,
+                                            NSString *lineIndent) {
+  id arrayOrMap;
+  NSUInteger count;
+  GPBFieldType fieldType = field.fieldType;
+  switch (fieldType) {
+    case GPBFieldTypeSingle:
+      arrayOrMap = nil;
+      count = (GPBGetHasIvarField(message, field) ? 1 : 0);
+      break;
+
+    case GPBFieldTypeRepeated:
+      // Will be NSArray or GPB*Array, type doesn't matter, they both
+      // implement count.
+      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
+      count = [(NSArray *)arrayOrMap count];
+      break;
+
+    case GPBFieldTypeMap: {
+      // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
+      // they both implement count.
+      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
+      count = [(NSDictionary *)arrayOrMap count];
+      break;
+    }
+  }
+
+  if (count == 0) {
+    // Nothing to print, out of here.
+    return;
+  }
+
+  NSString *lineEnding = @"";
+
+  // If the name can't be reversed or support for extra info was turned off,
+  // this can return nil.
+  NSString *fieldName = [field textFormatName];
+  if ([fieldName length] == 0) {
+    fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
+    // If there is only one entry, put the objc name as a comment, other wise
+    // add it before the repeated values.
+    if (count > 1) {
+      [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
+    } else {
+      lineEnding = [NSString stringWithFormat:@"  # %@", field.name];
+    }
+  }
+
+  if (fieldType == GPBFieldTypeMap) {
+    AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
+                                       fieldName, lineEnding);
+    return;
+  }
+
+  id array = arrayOrMap;
+  const BOOL isRepeated = (array != nil);
+
+  GPBDataType fieldDataType = GPBGetFieldDataType(field);
+  BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType);
+  for (NSUInteger j = 0; j < count; ++j) {
+    // Start the line.
+    [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
+                        (isMessageField ? "" : ":")];
+
+    // The value.
+    switch (fieldDataType) {
+#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...)                        \
+  case GPBDataType##GPBDATATYPE: {                                            \
+    CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j]   \
+                          : GPBGetMessage##REAL_TYPE##Field(message, field)); \
+    [toStr appendFormat:__VA_ARGS__, v];                                      \
+    break;                                                                    \
+  }
+
+      FIELD_CASE(Int32, int32_t, Int32, @"%d")
+      FIELD_CASE(SInt32, int32_t, Int32, @"%d")
+      FIELD_CASE(SFixed32, int32_t, Int32, @"%d")
+      FIELD_CASE(UInt32, uint32_t, UInt32, @"%u")
+      FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u")
+      FIELD_CASE(Int64, int64_t, Int64, @"%lld")
+      FIELD_CASE(SInt64, int64_t, Int64, @"%lld")
+      FIELD_CASE(SFixed64, int64_t, Int64, @"%lld")
+      FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu")
+      FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu")
+      FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG)
+      FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG)
+
+#undef FIELD_CASE
+
+      case GPBDataTypeEnum: {
+        int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j]
+                                : GPBGetMessageInt32Field(message, field));
+        NSString *valueStr = nil;
+        GPBEnumDescriptor *descriptor = field.enumDescriptor;
+        if (descriptor) {
+          valueStr = [descriptor textFormatNameForValue:v];
+        }
+        if (valueStr) {
+          [toStr appendString:valueStr];
+        } else {
+          [toStr appendFormat:@"%d", v];
+        }
+        break;
+      }
+
+      case GPBDataTypeBool: {
+        BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j]
+                             : GPBGetMessageBoolField(message, field));
+        [toStr appendString:(v ? @"true" : @"false")];
+        break;
+      }
+
+      case GPBDataTypeString: {
+        NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
+                                  : GPBGetMessageStringField(message, field));
+        AppendStringEscaped(v, toStr);
+        break;
+      }
+
+      case GPBDataTypeBytes: {
+        NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
+                                : GPBGetMessageBytesField(message, field));
+        AppendBufferAsString(v, toStr);
+        break;
+      }
+
+      case GPBDataTypeGroup:
+      case GPBDataTypeMessage: {
+        GPBMessage *v =
+            (isRepeated ? [(NSArray *)array objectAtIndex:j]
+                        : GPBGetObjectIvarWithField(message, field));
+        [toStr appendFormat:@"{%@\n", lineEnding];
+        NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
+        AppendTextFormatForMessage(v, toStr, subIndent);
+        [toStr appendFormat:@"%@}", lineIndent];
+        lineEnding = @"";
+        break;
+      }
+
+    }  // switch(fieldDataType)
+
+    // End the line.
+    [toStr appendFormat:@"%@\n", lineEnding];
+
+  }  // for(count)
+}
+
+static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
+                                                     NSArray *activeExtensions,
+                                                     GPBExtensionRange range,
+                                                     NSMutableString *toStr,
+                                                     NSString *lineIndent) {
+  uint32_t start = range.start;
+  uint32_t end = range.end;
+  for (GPBExtensionDescriptor *extension in activeExtensions) {
+    uint32_t fieldNumber = extension.fieldNumber;
+    if (fieldNumber < start) {
+      // Not there yet.
+      continue;
+    }
+    if (fieldNumber > end) {
+      // Done.
+      break;
+    }
+
+    id rawExtValue = [message getExtension:extension];
+    BOOL isRepeated = extension.isRepeated;
+
+    NSUInteger numValues = 1;
+    NSString *lineEnding = @"";
+    if (isRepeated) {
+      numValues = [(NSArray *)rawExtValue count];
+    }
+
+    NSString *singletonName = extension.singletonName;
+    if (numValues == 1) {
+      lineEnding = [NSString stringWithFormat:@"  # [%@]", singletonName];
+    } else {
+      [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName];
+    }
+
+    GPBDataType extDataType = extension.dataType;
+    for (NSUInteger j = 0; j < numValues; ++j) {
+      id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue);
+
+      // Start the line.
+      [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber,
+                          (GPBDataTypeIsMessage(extDataType) ? "" : ":")];
+
+      // The value.
+      switch (extDataType) {
+#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \
+  case GPBDataType##GPBDATATYPE: {                       \
+    CTYPE v = [(NSNumber *)curValue NUMSELECTOR];        \
+    [toStr appendFormat:__VA_ARGS__, v];                 \
+    break;                                               \
+  }
+
+        FIELD_CASE(Int32, int32_t, intValue, @"%d")
+        FIELD_CASE(SInt32, int32_t, intValue, @"%d")
+        FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d")
+        FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u")
+        FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u")
+        FIELD_CASE(Int64, int64_t, longLongValue, @"%lld")
+        FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld")
+        FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld")
+        FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu")
+        FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu")
+        FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG)
+        FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG)
+        // TODO: Add a comment with the enum name from enum descriptors
+        // (might not be real value, so leave it as a comment, ObjC compiler
+        // name mangles differently).  Doesn't look like we actually generate
+        // an enum descriptor reference like we do for normal fields, so this
+        // will take a compiler change.
+        FIELD_CASE(Enum, int32_t, intValue, @"%d")
+
+#undef FIELD_CASE
+
+        case GPBDataTypeBool:
+          [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true"
+                                                                : @"false")];
+          break;
+
+        case GPBDataTypeString:
+          AppendStringEscaped(curValue, toStr);
+          break;
+
+        case GPBDataTypeBytes:
+          AppendBufferAsString((NSData *)curValue, toStr);
+          break;
+
+        case GPBDataTypeGroup:
+        case GPBDataTypeMessage: {
+          [toStr appendFormat:@"{%@\n", lineEnding];
+          NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
+          AppendTextFormatForMessage(curValue, toStr, subIndent);
+          [toStr appendFormat:@"%@}", lineIndent];
+          lineEnding = @"";
+          break;
+        }
+
+      }  // switch(extDataType)
+
+    }  //  for(numValues)
+
+    // End the line.
+    [toStr appendFormat:@"%@\n", lineEnding];
+
+  }  // for..in(activeExtensions)
+}
+
+static void AppendTextFormatForMessage(GPBMessage *message,
+                                       NSMutableString *toStr,
+                                       NSString *lineIndent) {
+  GPBDescriptor *descriptor = [message descriptor];
+  NSArray *fieldsArray = descriptor->fields_;
+  NSUInteger fieldCount = fieldsArray.count;
+  const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
+  NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
+  NSArray *activeExtensions = [message sortedExtensionsInUse];
+  for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
+    if (i == fieldCount) {
+      AppendTextFormatForMessageExtensionRange(
+          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
+    } else if (j == extensionRangesCount ||
+               GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
+      AppendTextFormatForMessageField(message, fieldsArray[i++], toStr,
+                                      lineIndent);
+    } else {
+      AppendTextFormatForMessageExtensionRange(
+          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
+    }
+  }
+
+  NSString *unknownFieldsStr =
+      GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent);
+  if ([unknownFieldsStr length] > 0) {
+    [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent];
+    [toStr appendString:unknownFieldsStr];
+  }
+}
+
+NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) {
+  if (message == nil) return @"";
+  if (lineIndent == nil) lineIndent = @"";
+
+  NSMutableString *buildString = [NSMutableString string];
+  AppendTextFormatForMessage(message, buildString, lineIndent);
+  return buildString;
+}
+
+NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
+                                          NSString *lineIndent) {
+  if (unknownSet == nil) return @"";
+  if (lineIndent == nil) lineIndent = @"";
+
+  NSMutableString *result = [NSMutableString string];
+  for (GPBUnknownField *field in [unknownSet sortedFields]) {
+    int32_t fieldNumber = [field number];
+
+#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT)                                   \
+  [field.PROPNAME                                                             \
+      enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) {  \
+    _Pragma("unused(idx, stop)");                                             \
+    [result                                                                   \
+        appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \
+      }];
+
+    PRINT_LOOP(varintList, uint64_t, %llu);
+    PRINT_LOOP(fixed32List, uint32_t, 0x%X);
+    PRINT_LOOP(fixed64List, uint64_t, 0x%llX);
+
+#undef PRINT_LOOP
+
+    // NOTE: C++ version of TextFormat tries to parse this as a message
+    // and print that if it succeeds.
+    for (NSData *data in field.lengthDelimitedList) {
+      [result appendFormat:@"%@%d: ", lineIndent, fieldNumber];
+      AppendBufferAsString(data, result);
+      [result appendString:@"\n"];
+    }
+
+    for (GPBUnknownFieldSet *subUnknownSet in field.groupList) {
+      [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber];
+      NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
+      NSString *subUnknwonSetStr =
+          GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent);
+      [result appendString:subUnknwonSetStr];
+      [result appendFormat:@"%@}\n", lineIndent];
+    }
+  }
+  return result;
+}
+
+// Helpers to decode a varint. Not using GPBCodedInputStream version because
+// that needs a state object, and we don't want to create an input stream out
+// of the data.
+GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) {
+  int8_t result = *((int8_t *)(*data));
+  ++(*data);
+  return result;
+}
+
+static int32_t ReadRawVarint32FromData(const uint8_t **data) {
+  int8_t tmp = ReadRawByteFromData(data);
+  if (tmp >= 0) {
+    return tmp;
+  }
+  int32_t result = tmp & 0x7f;
+  if ((tmp = ReadRawByteFromData(data)) >= 0) {
+    result |= tmp << 7;
+  } else {
+    result |= (tmp & 0x7f) << 7;
+    if ((tmp = ReadRawByteFromData(data)) >= 0) {
+      result |= tmp << 14;
+    } else {
+      result |= (tmp & 0x7f) << 14;
+      if ((tmp = ReadRawByteFromData(data)) >= 0) {
+        result |= tmp << 21;
+      } else {
+        result |= (tmp & 0x7f) << 21;
+        result |= (tmp = ReadRawByteFromData(data)) << 28;
+        if (tmp < 0) {
+          // Discard upper 32 bits.
+          for (int i = 0; i < 5; i++) {
+            if (ReadRawByteFromData(data) >= 0) {
+              return result;
+            }
+          }
+          [NSException raise:NSParseErrorException
+                      format:@"Unable to read varint32"];
+        }
+      }
+    }
+  }
+  return result;
+}
+
+NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
+                                  NSString *inputStr) {
+  // decodData form:
+  //  varint32: num entries
+  //  for each entry:
+  //    varint32: key
+  //    bytes*: decode data
+  //
+  // decode data one of two forms:
+  //  1: a \0 followed by the string followed by an \0
+  //  2: bytecodes to transform an input into the right thing, ending with \0
+  //
+  // the bytes codes are of the form:
+  //  0xabbccccc
+  //  0x0 (all zeros), end.
+  //  a - if set, add an underscore
+  //  bb - 00 ccccc bytes as is
+  //  bb - 10 ccccc upper first, as is on rest, ccccc byte total
+  //  bb - 01 ccccc lower first, as is on rest, ccccc byte total
+  //  bb - 11 ccccc all upper, ccccc byte total
+
+  if (!decodeData || !inputStr) {
+    return nil;
+  }
+
+  // Find key
+  const uint8_t *scan = decodeData;
+  int32_t numEntries = ReadRawVarint32FromData(&scan);
+  BOOL foundKey = NO;
+  while (!foundKey && (numEntries > 0)) {
+    --numEntries;
+    int32_t dataKey = ReadRawVarint32FromData(&scan);
+    if (dataKey == key) {
+      foundKey = YES;
+    } else {
+      // If it is a inlined string, it will start with \0; if it is bytecode it
+      // will start with a code. So advance one (skipping the inline string
+      // marker), and then loop until reaching the end marker (\0).
+      ++scan;
+      while (*scan != 0) ++scan;
+      // Now move past the end marker.
+      ++scan;
+    }
+  }
+
+  if (!foundKey) {
+    return nil;
+  }
+
+  // Decode
+
+  if (*scan == 0) {
+    // Inline string. Move over the marker, and NSString can take it as
+    // UTF8.
+    ++scan;
+    NSString *result = [NSString stringWithUTF8String:(const char *)scan];
+    return result;
+  }
+
+  NSMutableString *result =
+      [NSMutableString stringWithCapacity:[inputStr length]];
+
+  const uint8_t kAddUnderscore  = 0b10000000;
+  const uint8_t kOpMask         = 0b01100000;
+  // const uint8_t kOpAsIs        = 0b00000000;
+  const uint8_t kOpFirstUpper     = 0b01000000;
+  const uint8_t kOpFirstLower     = 0b00100000;
+  const uint8_t kOpAllUpper       = 0b01100000;
+  const uint8_t kSegmentLenMask = 0b00011111;
+
+  NSInteger i = 0;
+  for (; *scan != 0; ++scan) {
+    if (*scan & kAddUnderscore) {
+      [result appendString:@"_"];
+    }
+    int segmentLen = *scan & kSegmentLenMask;
+    uint8_t decodeOp = *scan & kOpMask;
+
+    // Do op specific handling of the first character.
+    if (decodeOp == kOpFirstUpper) {
+      unichar c = [inputStr characterAtIndex:i];
+      [result appendFormat:@"%c", toupper((char)c)];
+      ++i;
+      --segmentLen;
+    } else if (decodeOp == kOpFirstLower) {
+      unichar c = [inputStr characterAtIndex:i];
+      [result appendFormat:@"%c", tolower((char)c)];
+      ++i;
+      --segmentLen;
+    }
+    // else op == kOpAsIs || op == kOpAllUpper
+
+    // Now pull over the rest of the length for this segment.
+    for (int x = 0; x < segmentLen; ++x) {
+      unichar c = [inputStr characterAtIndex:(i + x)];
+      if (decodeOp == kOpAllUpper) {
+        [result appendFormat:@"%c", toupper((char)c)];
+      } else {
+        [result appendFormat:@"%C", c];
+      }
+    }
+    i += segmentLen;
+  }
+
+  return result;
+}
+
+#pragma mark - GPBMessageSignatureProtocol
+
+// A series of selectors that are used solely to get @encoding values
+// for them by the dynamic protobuf runtime code. An object using the protocol
+// needs to be declared for the protocol to be valid at runtime.
+@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol>
+@end
+@implementation GPBMessageSignatureProtocol
+@end
diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h
new file mode 100644
index 0000000..a6b6c84
--- /dev/null
+++ b/objectivec/GPBUtilities_PackagePrivate.h
@@ -0,0 +1,331 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "GPBUtilities.h"
+
+#import "GPBDescriptor_PackagePrivate.h"
+
+// Macros for stringifying library symbols. These are used in the generated
+// PB descriptor classes wherever a library symbol name is represented as a
+// string. See README.google for more information.
+#define GPBStringify(S) #S
+#define GPBStringifySymbol(S) GPBStringify(S)
+
+#define GPBNSStringify(S) @#S
+#define GPBNSStringifySymbol(S) GPBNSStringify(S)
+
+// Constant to internally mark when there is no has bit.
+#define GPBNoHasBit INT32_MAX
+
+CF_EXTERN_C_BEGIN
+
+// These two are used to inject a runtime check for version mismatch into the
+// generated sources to make sure they are linked with a supporting runtime.
+void GPBCheckRuntimeVersionInternal(int32_t version);
+GPB_INLINE void GPBDebugCheckRuntimeVersion() {
+#if DEBUG
+  GPBCheckRuntimeVersionInternal(GOOGLE_PROTOBUF_OBJC_GEN_VERSION);
+#endif
+}
+
+// Conversion functions for de/serializing floating point types.
+
+GPB_INLINE int64_t GPBConvertDoubleToInt64(double v) {
+  union { double f; int64_t i; } u;
+  u.f = v;
+  return u.i;
+}
+
+GPB_INLINE int32_t GPBConvertFloatToInt32(float v) {
+  union { float f; int32_t i; } u;
+  u.f = v;
+  return u.i;
+}
+
+GPB_INLINE double GPBConvertInt64ToDouble(int64_t v) {
+  union { double f; int64_t i; } u;
+  u.i = v;
+  return u.f;
+}
+
+GPB_INLINE float GPBConvertInt32ToFloat(int32_t v) {
+  union { float f; int32_t i; } u;
+  u.i = v;
+  return u.f;
+}
+
+GPB_INLINE int32_t GPBLogicalRightShift32(int32_t value, int32_t spaces) {
+  return (int32_t)((uint32_t)(value) >> spaces);
+}
+
+GPB_INLINE int64_t GPBLogicalRightShift64(int64_t value, int32_t spaces) {
+  return (int64_t)((uint64_t)(value) >> spaces);
+}
+
+// Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+// into values that can be efficiently encoded with varint.  (Otherwise,
+// negative values must be sign-extended to 64 bits to be varint encoded,
+// thus always taking 10 bytes on the wire.)
+GPB_INLINE int32_t GPBDecodeZigZag32(uint32_t n) {
+  return GPBLogicalRightShift32(n, 1) ^ -(n & 1);
+}
+
+// Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+// into values that can be efficiently encoded with varint.  (Otherwise,
+// negative values must be sign-extended to 64 bits to be varint encoded,
+// thus always taking 10 bytes on the wire.)
+GPB_INLINE int64_t GPBDecodeZigZag64(uint64_t n) {
+  return GPBLogicalRightShift64(n, 1) ^ -(n & 1);
+}
+
+// Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+// into values that can be efficiently encoded with varint.  (Otherwise,
+// negative values must be sign-extended to 64 bits to be varint encoded,
+// thus always taking 10 bytes on the wire.)
+GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) {
+  // Note:  the right-shift must be arithmetic
+  return (n << 1) ^ (n >> 31);
+}
+
+// Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+// into values that can be efficiently encoded with varint.  (Otherwise,
+// negative values must be sign-extended to 64 bits to be varint encoded,
+// thus always taking 10 bytes on the wire.)
+GPB_INLINE uint64_t GPBEncodeZigZag64(int64_t n) {
+  // Note:  the right-shift must be arithmetic
+  return (n << 1) ^ (n >> 63);
+}
+
+GPB_INLINE BOOL GPBDataTypeIsObject(GPBDataType type) {
+  switch (type) {
+    case GPBDataTypeBytes:
+    case GPBDataTypeString:
+    case GPBDataTypeMessage:
+    case GPBDataTypeGroup:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+GPB_INLINE BOOL GPBDataTypeIsMessage(GPBDataType type) {
+  switch (type) {
+    case GPBDataTypeMessage:
+    case GPBDataTypeGroup:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+GPB_INLINE BOOL GPBFieldDataTypeIsMessage(GPBFieldDescriptor *field) {
+  return GPBDataTypeIsMessage(field->description_->dataType);
+}
+
+GPB_INLINE BOOL GPBFieldDataTypeIsObject(GPBFieldDescriptor *field) {
+  return GPBDataTypeIsObject(field->description_->dataType);
+}
+
+GPB_INLINE BOOL GPBExtensionIsMessage(GPBExtensionDescriptor *ext) {
+  return GPBDataTypeIsMessage(ext->description_->dataType);
+}
+
+// The field is an array/map or it has an object value.
+GPB_INLINE BOOL GPBFieldStoresObject(GPBFieldDescriptor *field) {
+  GPBMessageFieldDescription *desc = field->description_;
+  if ((desc->flags & (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0) {
+    return YES;
+  }
+  return GPBDataTypeIsObject(desc->dataType);
+}
+
+BOOL GPBGetHasIvar(GPBMessage *self, int32_t index, uint32_t fieldNumber);
+void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
+                   BOOL value);
+uint32_t GPBGetHasOneof(GPBMessage *self, int32_t index);
+
+GPB_INLINE BOOL
+GPBGetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field) {
+  GPBMessageFieldDescription *fieldDesc = field->description_;
+  return GPBGetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number);
+}
+GPB_INLINE void GPBSetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field,
+                                   BOOL value) {
+  GPBMessageFieldDescription *fieldDesc = field->description_;
+  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, value);
+}
+
+void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
+                        int32_t oneofHasIndex, uint32_t fieldNumberNotToClear);
+
+//%PDDM-DEFINE GPB_IVAR_SET_DECL(NAME, TYPE)
+//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
+//%            NAME$S                     GPBFieldDescriptor *field,
+//%            NAME$S                     TYPE value,
+//%            NAME$S                     GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Bool, BOOL)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
+                                     GPBFieldDescriptor *field,
+                                     BOOL value,
+                                     GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int32, int32_t)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int32_t value,
+                                      GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt32, uint32_t)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint32_t value,
+                                       GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int64, int64_t)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      int64_t value,
+                                      GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt64, uint64_t)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       uint64_t value,
+                                       GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Float, float)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
+                                      GPBFieldDescriptor *field,
+                                      float value,
+                                      GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Double, double)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field,
+                                       double value,
+                                       GPBFileSyntax syntax);
+//%PDDM-EXPAND GPB_IVAR_SET_DECL(Enum, int32_t)
+// This block of code is generated, do not edit it directly.
+
+void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
+                                     GPBFieldDescriptor *field,
+                                     int32_t value,
+                                     GPBFileSyntax syntax);
+//%PDDM-EXPAND-END (8 expansions)
+
+int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
+                                        GPBFieldDescriptor *field,
+                                        GPBFileSyntax syntax);
+
+id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
+
+void GPBSetObjectIvarWithFieldInternal(GPBMessage *self,
+                                       GPBFieldDescriptor *field, id value,
+                                       GPBFileSyntax syntax);
+void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
+                                               GPBFieldDescriptor *field,
+                                               id __attribute__((ns_consumed))
+                                               value,
+                                               GPBFileSyntax syntax);
+
+// GPBGetObjectIvarWithField will automatically create the field (message) if
+// it doesn't exist. GPBGetObjectIvarWithFieldNoAutocreate will return nil.
+id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
+                                         GPBFieldDescriptor *field);
+
+void GPBSetAutocreatedRetainedObjectIvarWithField(
+    GPBMessage *self, GPBFieldDescriptor *field,
+    id __attribute__((ns_consumed)) value);
+
+// Clears and releases the autocreated message ivar, if it's autocreated. If
+// it's not set as autocreated, this method does nothing.
+void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
+                                             GPBFieldDescriptor *field);
+
+// Returns an Objective C encoding for |selector|. |instanceSel| should be
+// YES if it's an instance selector (as opposed to a class selector).
+// |selector| must be a selector from MessageSignatureProtocol.
+const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel);
+
+// Helper for text format name encoding.
+// decodeData is the data describing the sepecial decodes.
+// key and inputString are the input that needs decoding.
+NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
+                                  NSString *inputString);
+
+// A series of selectors that are used solely to get @encoding values
+// for them by the dynamic protobuf runtime code. See
+// GPBMessageEncodingForSelector for details.
+@protocol GPBMessageSignatureProtocol
+@optional
+
+#define GPB_MESSAGE_SIGNATURE_ENTRY(TYPE, NAME) \
+  -(TYPE)get##NAME;                             \
+  -(void)set##NAME : (TYPE)value;               \
+  -(TYPE)get##NAME##AtIndex : (NSUInteger)index;
+
+GPB_MESSAGE_SIGNATURE_ENTRY(BOOL, Bool)
+GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, Fixed32)
+GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SFixed32)
+GPB_MESSAGE_SIGNATURE_ENTRY(float, Float)
+GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, Fixed64)
+GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SFixed64)
+GPB_MESSAGE_SIGNATURE_ENTRY(double, Double)
+GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Int32)
+GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, Int64)
+GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SInt32)
+GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SInt64)
+GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, UInt32)
+GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, UInt64)
+GPB_MESSAGE_SIGNATURE_ENTRY(NSData *, Bytes)
+GPB_MESSAGE_SIGNATURE_ENTRY(NSString *, String)
+GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Message)
+GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Group)
+GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Enum)
+
+#undef GPB_MESSAGE_SIGNATURE_ENTRY
+
+- (id)getArray;
+- (NSUInteger)getArrayCount;
+- (void)setArray:(NSArray *)array;
++ (id)getClassValue;
+@end
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
new file mode 100644
index 0000000..28442fb
--- /dev/null
+++ b/objectivec/GPBWellKnownTypes.h
@@ -0,0 +1,52 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+
+#import "google/protobuf/Duration.pbobjc.h"
+#import "google/protobuf/Timestamp.pbobjc.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Extension to GPBTimestamp to work with standard Foundation time/date types.
+@interface GPBTimestamp (GBPWellKnownTypes)
+@property(nonatomic, readwrite, strong) NSDate *date;
+@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
+- (instancetype)initWithDate:(NSDate *)date;
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
+@end
+
+// Extension to GPBDuration to work with standard Foundation time type.
+@interface GPBDuration (GBPWellKnownTypes)
+@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
new file mode 100644
index 0000000..fe02f5d
--- /dev/null
+++ b/objectivec/GPBWellKnownTypes.m
@@ -0,0 +1,117 @@
+// 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.
+
+// Importing sources here to force the linker to include our category methods in
+// the static library. If these were compiled separately, the category methods
+// below would be stripped by the linker.
+
+#import "google/protobuf/Timestamp.pbobjc.m"
+#import "google/protobuf/Duration.pbobjc.m"
+#import "GPBWellKnownTypes.h"
+
+static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
+                                                               int32_t nanos) {
+  return seconds + (NSTimeInterval)nanos / 1e9;
+}
+
+static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
+                                                        int64_t *outSeconds) {
+  NSTimeInterval seconds;
+  NSTimeInterval nanos = modf(time, &seconds);
+  nanos *= 1e9;
+  *outSeconds = (int64_t)seconds;
+  return (int32_t)nanos;
+}
+
+@implementation GPBTimestamp (GBPWellKnownTypes)
+
+- (instancetype)initWithDate:(NSDate *)date {
+  return [self initWithTimeIntervalSince1970:date.timeIntervalSince1970];
+}
+
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+  if ((self = [super init])) {
+    int64_t seconds;
+    int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970(
+        timeIntervalSince1970, &seconds);
+    self.seconds = seconds;
+    self.nanos = nanos;
+  }
+  return self;
+}
+
+- (NSDate *)date {
+  return [NSDate dateWithTimeIntervalSince1970:self.timeIntervalSince1970];
+}
+
+- (void)setDate:(NSDate *)date {
+  self.timeIntervalSince1970 = date.timeIntervalSince1970;
+}
+
+- (NSTimeInterval)timeIntervalSince1970 {
+  return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos);
+}
+
+- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+  int64_t seconds;
+  int32_t nanos =
+      SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds);
+  self.seconds = seconds;
+  self.nanos = nanos;
+}
+
+@end
+
+@implementation GPBDuration (GBPWellKnownTypes)
+
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+  if ((self = [super init])) {
+    int64_t seconds;
+    int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970(
+        timeIntervalSince1970, &seconds);
+    self.seconds = seconds;
+    self.nanos = nanos;
+  }
+  return self;
+}
+
+- (NSTimeInterval)timeIntervalSince1970 {
+  return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos);
+}
+
+- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+  int64_t seconds;
+  int32_t nanos =
+      SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds);
+  self.seconds = seconds;
+  self.nanos = nanos;
+}
+
+@end
diff --git a/objectivec/GPBWireFormat.h b/objectivec/GPBWireFormat.h
new file mode 100644
index 0000000..29cf2f0
--- /dev/null
+++ b/objectivec/GPBWireFormat.h
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBRuntimeTypes.h"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef enum {
+  GPBWireFormatVarint = 0,
+  GPBWireFormatFixed64 = 1,
+  GPBWireFormatLengthDelimited = 2,
+  GPBWireFormatStartGroup = 3,
+  GPBWireFormatEndGroup = 4,
+  GPBWireFormatFixed32 = 5,
+} GPBWireFormat;
+
+enum {
+  GPBWireFormatMessageSetItem = 1,
+  GPBWireFormatMessageSetTypeId = 2,
+  GPBWireFormatMessageSetMessage = 3
+};
+
+uint32_t GPBWireFormatMakeTag(uint32_t fieldNumber, GPBWireFormat wireType)
+    __attribute__((const));
+GPBWireFormat GPBWireFormatGetTagWireType(uint32_t tag) __attribute__((const));
+uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) __attribute__((const));
+
+GPBWireFormat GPBWireFormatForType(GPBDataType dataType, BOOL isPacked)
+    __attribute__((const));
+
+#define GPBWireFormatMessageSetItemTag \
+  (GPBWireFormatMakeTag(GPBWireFormatMessageSetItem, GPBWireFormatStartGroup))
+#define GPBWireFormatMessageSetItemEndTag \
+  (GPBWireFormatMakeTag(GPBWireFormatMessageSetItem, GPBWireFormatEndGroup))
+#define GPBWireFormatMessageSetTypeIdTag \
+  (GPBWireFormatMakeTag(GPBWireFormatMessageSetTypeId, GPBWireFormatVarint))
+#define GPBWireFormatMessageSetMessageTag               \
+  (GPBWireFormatMakeTag(GPBWireFormatMessageSetMessage, \
+                        GPBWireFormatLengthDelimited))
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
diff --git a/objectivec/GPBWireFormat.m b/objectivec/GPBWireFormat.m
new file mode 100644
index 0000000..193235d
--- /dev/null
+++ b/objectivec/GPBWireFormat.m
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBWireFormat.h"
+
+#import "GPBUtilities_PackagePrivate.h"
+
+enum {
+  GPBWireFormatTagTypeBits = 3,
+  GPBWireFormatTagTypeMask = 7 /* = (1 << GPBWireFormatTagTypeBits) - 1 */,
+};
+
+uint32_t GPBWireFormatMakeTag(uint32_t fieldNumber, GPBWireFormat wireType) {
+  return (fieldNumber << GPBWireFormatTagTypeBits) | wireType;
+}
+
+GPBWireFormat GPBWireFormatGetTagWireType(uint32_t tag) {
+  return (GPBWireFormat)(tag & GPBWireFormatTagTypeMask);
+}
+
+uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) {
+  return GPBLogicalRightShift32(tag, GPBWireFormatTagTypeBits);
+}
+
+GPBWireFormat GPBWireFormatForType(GPBDataType type, BOOL isPacked) {
+  if (isPacked) {
+    return GPBWireFormatLengthDelimited;
+  }
+
+  static const GPBWireFormat format[GPBDataType_Count] = {
+      GPBWireFormatVarint,           // GPBDataTypeBool
+      GPBWireFormatFixed32,          // GPBDataTypeFixed32
+      GPBWireFormatFixed32,          // GPBDataTypeSFixed32
+      GPBWireFormatFixed32,          // GPBDataTypeFloat
+      GPBWireFormatFixed64,          // GPBDataTypeFixed64
+      GPBWireFormatFixed64,          // GPBDataTypeSFixed64
+      GPBWireFormatFixed64,          // GPBDataTypeDouble
+      GPBWireFormatVarint,           // GPBDataTypeInt32
+      GPBWireFormatVarint,           // GPBDataTypeInt64
+      GPBWireFormatVarint,           // GPBDataTypeSInt32
+      GPBWireFormatVarint,           // GPBDataTypeSInt64
+      GPBWireFormatVarint,           // GPBDataTypeUInt32
+      GPBWireFormatVarint,           // GPBDataTypeUInt64
+      GPBWireFormatLengthDelimited,  // GPBDataTypeBytes
+      GPBWireFormatLengthDelimited,  // GPBDataTypeString
+      GPBWireFormatLengthDelimited,  // GPBDataTypeMessage
+      GPBWireFormatStartGroup,       // GPBDataTypeGroup
+      GPBWireFormatVarint            // GPBDataTypeEnum
+  };
+  return format[type];
+}
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..3093425
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -0,0 +1,942 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 47;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; };
+		7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; };
+		7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */; };
+		7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */; };
+		7461B54C0F94FB4E00A0C422 /* GPBUnknownField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */; };
+		7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4BF0F94F99000A0C422 /* GPBMessage.m */; };
+		7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */; };
+		7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E60F94F99000A0C422 /* GPBUtilities.m */; };
+		7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */; };
+		8B210CCE159383D60032D72D /* golden_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCD159383D60032D72D /* golden_message */; };
+		8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCF159386920032D72D /* golden_packed_fields_message */; };
+		8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */; };
+		8B4248D21A927E1500BC1EC6 /* GPBWellKnownTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */; };
+		8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */; };
+		8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; };
+		8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; };
+		8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
+		8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; };
+		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
+		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
+		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
+		8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */; };
+		8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */; };
+		8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */; };
+		8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */; };
+		8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; };
+		8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; };
+		8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		F401DC2D1A8D444600FCC765 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC2B1A8D444600FCC765 /* GPBArray.m */; };
+		F401DC331A8E5C0200FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */; };
+		F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F41C175C1833D3310064ED4D /* GPBPerfTests.m */; };
+		F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */; };
+		F4353D231ABB1537005A6198 /* GPBDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D211ABB1537005A6198 /* GPBDictionary.m */; };
+		F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */; };
+		F4353D351AC06F10005A6198 /* GPBDictionaryTests+Int32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */; };
+		F4353D361AC06F10005A6198 /* GPBDictionaryTests+Int64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */; };
+		F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */; };
+		F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */; };
+		F4353D391AC06F10005A6198 /* GPBDictionaryTests+UInt64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */; };
+		F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; };
+		F4487C4D1A9F8E0200531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		F4487C521A9F8E4D00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; };
+		F4487C751AADF7F500531423 /* GPBMessageTests+Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */; };
+		F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */; };
+		F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */; };
+		F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */; };
+		F45E57C71AE6DC6A000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */; };
+		F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */; };
+		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 */; };
+		F4E6759D1B21D0000054530B /* FieldMask.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758D1B21D0000054530B /* FieldMask.pbobjc.m */; };
+		F4E6759F1B21D0000054530B /* SourceContext.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758F1B21D0000054530B /* SourceContext.pbobjc.m */; };
+		F4E675A11B21D0000054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675911B21D0000054530B /* Struct.pbobjc.m */; };
+		F4E675A31B21D0000054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675931B21D0000054530B /* Type.pbobjc.m */; };
+		F4E675A51B21D0000054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675951B21D0000054530B /* Wrappers.pbobjc.m */; };
+		F4E675AE1B21D0A70054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675871B21D0000054530B /* Any.pbobjc.m */; };
+		F4E675AF1B21D0A70054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675891B21D0000054530B /* Api.pbobjc.m */; };
+		F4E675B01B21D0A70054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758B1B21D0000054530B /* Empty.pbobjc.m */; };
+		F4E675B11B21D0A70054530B /* FieldMask.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758D1B21D0000054530B /* FieldMask.pbobjc.m */; };
+		F4E675B21B21D0A70054530B /* SourceContext.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758F1B21D0000054530B /* SourceContext.pbobjc.m */; };
+		F4E675B31B21D0A70054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675911B21D0000054530B /* Struct.pbobjc.m */; };
+		F4E675B41B21D0A70054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675931B21D0000054530B /* Type.pbobjc.m */; };
+		F4E675B51B21D0A70054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675951B21D0000054530B /* Wrappers.pbobjc.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 7461B52D0F94FAF800A0C422;
+			remoteInfo = ProtocolBuffers;
+		};
+		F45BBC181B0CE3D7002D064D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F45BBC141B0CE3C6002D064D;
+			remoteInfo = "Compile Unittest Protos";
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBConcurrencyTests.m; sourceTree = "<group>"; };
+		51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream_PackagePrivate.h; sourceTree = "<group>"; };
+		515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor_PackagePrivate.h; sourceTree = "<group>"; };
+		5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBMessage_PackagePrivate.h; sourceTree = "<group>"; };
+		7401C1A90F950347006D8281 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = "<group>"; };
+		7461B48D0F94F99000A0C422 /* GPBBootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBBootstrap.h; sourceTree = "<group>"; };
+		7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream.h; sourceTree = "<group>"; };
+		7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPBCodedInputStream.m; sourceTree = "<group>"; };
+		7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream.h; sourceTree = "<group>"; };
+		7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOutputStream.m; sourceTree = "<group>"; };
+		7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry.h; sourceTree = "<group>"; };
+		7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionRegistry.m; sourceTree = "<group>"; };
+		7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField.h; sourceTree = "<group>"; };
+		7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownField.m; sourceTree = "<group>"; };
+		7461B4BE0F94F99000A0C422 /* GPBMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBMessage.h; sourceTree = "<group>"; };
+		7461B4BF0F94F99000A0C422 /* GPBMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessage.m; sourceTree = "<group>"; };
+		7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers.h; sourceTree = "<group>"; };
+		7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet.h; sourceTree = "<group>"; };
+		7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSet.m; sourceTree = "<group>"; };
+		7461B4E50F94F99000A0C422 /* GPBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUtilities.h; sourceTree = "<group>"; };
+		7461B4E60F94F99000A0C422 /* GPBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilities.m; sourceTree = "<group>"; };
+		7461B4E70F94F99000A0C422 /* GPBWireFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWireFormat.h; sourceTree = "<group>"; };
+		7461B4E80F94F99000A0C422 /* GPBWireFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormat.m; sourceTree = "<group>"; };
+		7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libProtocolBuffers.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedInputStreamTests.m; sourceTree = "<group>"; };
+		7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOuputStreamTests.m; sourceTree = "<group>"; };
+		7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessageTests.m; sourceTree = "<group>"; };
+		7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBTestUtilities.h; sourceTree = "<group>"; };
+		7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBTestUtilities.m; sourceTree = "<group>"; };
+		7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSetTest.m; sourceTree = "<group>"; };
+		7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilitiesTests.m; sourceTree = "<group>"; };
+		7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormatTests.m; sourceTree = "<group>"; };
+		8B09AAF614B663A7007B4184 /* unittest_objc.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc.proto; sourceTree = "<group>"; };
+		8B210CCD159383D60032D72D /* golden_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_message; sourceTree = "<group>"; };
+		8B210CCF159386920032D72D /* golden_packed_fields_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_packed_fields_message; sourceTree = "<group>"; };
+		8B4248B81A8C254000BC1EC6 /* protobuf */ = {isa = PBXFileReference; lastKnownFileType = text; name = protobuf; path = ../../Intermediates/ProtocolBuffers_OSX.build/DerivedSources/protos/google/protobuf; sourceTree = BUILT_PRODUCTS_DIR; };
+		8B4248B91A8C256900BC1EC6 /* UnitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnitTests-Bridging-Header.h"; sourceTree = "<group>"; };
+		8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPBSwiftTests.swift; sourceTree = "<group>"; };
+		8B4248CF1A927E1500BC1EC6 /* GPBWellKnownTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWellKnownTypes.h; sourceTree = "<group>"; };
+		8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypes.m; sourceTree = "<group>"; };
+		8B4248D31A92826400BC1EC6 /* Duration.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Duration.pbobjc.h; path = google/protobuf/Duration.pbobjc.h; sourceTree = "<group>"; };
+		8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Duration.pbobjc.m; path = google/protobuf/Duration.pbobjc.m; sourceTree = "<group>"; };
+		8B4248D51A92826400BC1EC6 /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = google/protobuf/Timestamp.pbobjc.h; sourceTree = "<group>"; };
+		8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = google/protobuf/Timestamp.pbobjc.m; sourceTree = "<group>"; };
+		8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = "<group>"; };
+		8B42494C1A92A16600BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = "<group>"; };
+		8B42494D1A92A16600BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = "<group>"; };
+		8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = "<group>"; };
+		8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = "<group>"; };
+		8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_custom_options.proto; path = ../../src/google/protobuf/unittest_custom_options.proto; sourceTree = "<group>"; };
+		8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_embed_optimize_for.proto; path = ../../src/google/protobuf/unittest_embed_optimize_for.proto; sourceTree = "<group>"; };
+		8B7E6A7614893DBA00F8884A /* unittest_empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_empty.proto; path = ../../src/google/protobuf/unittest_empty.proto; sourceTree = "<group>"; };
+		8B7E6A7814893DBB00F8884A /* unittest_import.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_import.proto; path = ../../src/google/protobuf/unittest_import.proto; sourceTree = "<group>"; };
+		8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_mset.proto; path = ../../src/google/protobuf/unittest_mset.proto; sourceTree = "<group>"; };
+		8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_no_generic_services.proto; path = ../../src/google/protobuf/unittest_no_generic_services.proto; sourceTree = "<group>"; };
+		8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_optimize_for.proto; path = ../../src/google/protobuf/unittest_optimize_for.proto; sourceTree = "<group>"; };
+		8B7E6A7E14893DBC00F8884A /* unittest.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest.proto; path = ../../src/google/protobuf/unittest.proto; sourceTree = "<group>"; };
+		8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; };
+		8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; };
+		8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; };
+		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
+		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
+		8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = "<group>"; };
+		8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = "<group>"; };
+		8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = "<group>"; };
+		F401DC2A1A8D444600FCC765 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = "<group>"; };
+		F401DC2B1A8D444600FCC765 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = "<group>"; };
+		F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = "<group>"; };
+		F41C175C1833D3310064ED4D /* GPBPerfTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBPerfTests.m; sourceTree = "<group>"; };
+		F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptorTests.m; sourceTree = "<group>"; };
+		F4353D201ABB1537005A6198 /* GPBDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBDictionary.h; sourceTree = "<group>"; };
+		F4353D211ABB1537005A6198 /* GPBDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionary.m; sourceTree = "<group>"; };
+		F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GPBDictionaryTests.pddm; sourceTree = "<group>"; };
+		F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Bool.m"; sourceTree = "<group>"; };
+		F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int32.m"; sourceTree = "<group>"; };
+		F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int64.m"; sourceTree = "<group>"; };
+		F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+String.m"; sourceTree = "<group>"; };
+		F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt32.m"; sourceTree = "<group>"; };
+		F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt64.m"; sourceTree = "<group>"; };
+		F43725911AC9832D004DCAFB /* GPBDictionary_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDictionary_PackagePrivate.h; sourceTree = "<group>"; };
+		F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = "<group>"; };
+		F4411BE71AF12FD700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = "<group>"; };
+		F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Runtime.m"; sourceTree = "<group>"; };
+		F4487C781AADFB3100531423 /* unittest_runtime_proto2.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto2.proto; sourceTree = "<group>"; };
+		F4487C791AADFB3200531423 /* unittest_runtime_proto3.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto3.proto; sourceTree = "<group>"; };
+		F4487C7C1AAE06AC00531423 /* GPBUtilities_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUtilities_PackagePrivate.h; sourceTree = "<group>"; };
+		F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Serialization.m"; sourceTree = "<group>"; };
+		F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Merge.m"; sourceTree = "<group>"; };
+		F44929001C866B1900C2548A /* GPBCodedOutputStream_PackagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream_PackagePrivate.h; sourceTree = "<group>"; };
+		F451D3F51A8AAE8700B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers_RuntimeSupport.h; sourceTree = "<group>"; };
+		F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionInternals.m; sourceTree = "<group>"; };
+		F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; };
+		F4AC9E1D1A8BEB3500BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; };
+		F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GPBObjectiveCPlusPlusTest.mm; sourceTree = "<group>"; };
+		F4B6B8AF1A9CC98000892426 /* GPBUnknownField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField_PackagePrivate.h; sourceTree = "<group>"; };
+		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>"; };
+		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>"; };
+		F4E675881B21D0000054530B /* Api.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Api.pbobjc.h; path = google/protobuf/Api.pbobjc.h; sourceTree = "<group>"; };
+		F4E675891B21D0000054530B /* Api.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Api.pbobjc.m; path = google/protobuf/Api.pbobjc.m; sourceTree = "<group>"; };
+		F4E6758A1B21D0000054530B /* Empty.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Empty.pbobjc.h; path = google/protobuf/Empty.pbobjc.h; sourceTree = "<group>"; };
+		F4E6758B1B21D0000054530B /* Empty.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Empty.pbobjc.m; path = google/protobuf/Empty.pbobjc.m; sourceTree = "<group>"; };
+		F4E6758C1B21D0000054530B /* FieldMask.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FieldMask.pbobjc.h; path = google/protobuf/FieldMask.pbobjc.h; sourceTree = "<group>"; };
+		F4E6758D1B21D0000054530B /* FieldMask.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FieldMask.pbobjc.m; path = google/protobuf/FieldMask.pbobjc.m; sourceTree = "<group>"; };
+		F4E6758E1B21D0000054530B /* SourceContext.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SourceContext.pbobjc.h; path = google/protobuf/SourceContext.pbobjc.h; sourceTree = "<group>"; };
+		F4E6758F1B21D0000054530B /* SourceContext.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SourceContext.pbobjc.m; path = google/protobuf/SourceContext.pbobjc.m; sourceTree = "<group>"; };
+		F4E675901B21D0000054530B /* Struct.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Struct.pbobjc.h; path = google/protobuf/Struct.pbobjc.h; sourceTree = "<group>"; };
+		F4E675911B21D0000054530B /* Struct.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Struct.pbobjc.m; path = google/protobuf/Struct.pbobjc.m; sourceTree = "<group>"; };
+		F4E675921B21D0000054530B /* Type.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Type.pbobjc.h; path = google/protobuf/Type.pbobjc.h; sourceTree = "<group>"; };
+		F4E675931B21D0000054530B /* Type.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Type.pbobjc.m; path = google/protobuf/Type.pbobjc.m; sourceTree = "<group>"; };
+		F4E675941B21D0000054530B /* Wrappers.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Wrappers.pbobjc.h; path = google/protobuf/Wrappers.pbobjc.h; sourceTree = "<group>"; };
+		F4E675951B21D0000054530B /* Wrappers.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Wrappers.pbobjc.m; path = google/protobuf/Wrappers.pbobjc.m; sourceTree = "<group>"; };
+		F4E675A61B21D05C0054530B /* any.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = any.proto; path = ../src/google/protobuf/any.proto; sourceTree = "<group>"; };
+		F4E675A71B21D05C0054530B /* api.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = api.proto; path = ../src/google/protobuf/api.proto; sourceTree = "<group>"; };
+		F4E675A81B21D05C0054530B /* empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = empty.proto; path = ../src/google/protobuf/empty.proto; sourceTree = "<group>"; };
+		F4E675A91B21D05C0054530B /* field_mask.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = field_mask.proto; path = ../src/google/protobuf/field_mask.proto; sourceTree = "<group>"; };
+		F4E675AA1B21D05C0054530B /* source_context.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = source_context.proto; path = ../src/google/protobuf/source_context.proto; sourceTree = "<group>"; };
+		F4E675AB1B21D05C0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
+		F4E675AC1B21D05C0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
+		F4E675AD1B21D05C0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		7461B52C0F94FAF800A0C422 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8BBEA4A3147C727100C4ADB7 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */,
+				8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C4C1A9F8E0200531423 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F4487C4D1A9F8E0200531423 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		080E96DDFE201D6D7F000001 /* Core Source */ = {
+			isa = PBXGroup;
+			children = (
+				7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */,
+				F451D3F51A8AAE8700B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */,
+				8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */,
+				7461B3C50F94F84100A0C422 /* Extensions */,
+				7461B4850F94F96600A0C422 /* Fields */,
+				7461B4860F94F96B00A0C422 /* IO */,
+				7461B5150F94FA7300A0C422 /* Messages */,
+				8BCF334414ED727300BC5317 /* Support */,
+				29B97315FDCFA39411CA2CEA /* Generated */,
+			);
+			name = "Core Source";
+			sourceTree = "<group>";
+		};
+		19C28FACFE9D520D11CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */,
+				8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */,
+				F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+			isa = PBXGroup;
+			children = (
+				080E96DDFE201D6D7F000001 /* Core Source */,
+				7461B6940F94FDDD00A0C422 /* Tests */,
+				29B97323FDCFA39411CA2CEA /* Frameworks */,
+				19C28FACFE9D520D11CA2CBB /* Products */,
+			);
+			name = CustomTemplate;
+			sourceTree = "<group>";
+		};
+		29B97315FDCFA39411CA2CEA /* Generated */ = {
+			isa = PBXGroup;
+			children = (
+				F4E675861B21D0000054530B /* Any.pbobjc.h */,
+				F4E675871B21D0000054530B /* Any.pbobjc.m */,
+				F4E675A61B21D05C0054530B /* any.proto */,
+				F4E675881B21D0000054530B /* Api.pbobjc.h */,
+				F4E675891B21D0000054530B /* Api.pbobjc.m */,
+				F4E675A71B21D05C0054530B /* api.proto */,
+				8B4248D31A92826400BC1EC6 /* Duration.pbobjc.h */,
+				8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */,
+				8B42494C1A92A16600BC1EC6 /* duration.proto */,
+				F4E6758A1B21D0000054530B /* Empty.pbobjc.h */,
+				F4E6758B1B21D0000054530B /* Empty.pbobjc.m */,
+				F4E675A81B21D05C0054530B /* empty.proto */,
+				F4E675A91B21D05C0054530B /* field_mask.proto */,
+				F4E6758C1B21D0000054530B /* FieldMask.pbobjc.h */,
+				F4E6758D1B21D0000054530B /* FieldMask.pbobjc.m */,
+				F4E675AA1B21D05C0054530B /* source_context.proto */,
+				F4E6758E1B21D0000054530B /* SourceContext.pbobjc.h */,
+				F4E6758F1B21D0000054530B /* SourceContext.pbobjc.m */,
+				F4E675901B21D0000054530B /* Struct.pbobjc.h */,
+				F4E675911B21D0000054530B /* Struct.pbobjc.m */,
+				F4E675AB1B21D05C0054530B /* struct.proto */,
+				8B4248D51A92826400BC1EC6 /* Timestamp.pbobjc.h */,
+				8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */,
+				8B42494D1A92A16600BC1EC6 /* timestamp.proto */,
+				F4E675921B21D0000054530B /* Type.pbobjc.h */,
+				F4E675931B21D0000054530B /* Type.pbobjc.m */,
+				F4E675AC1B21D05C0054530B /* type.proto */,
+				F4E675941B21D0000054530B /* Wrappers.pbobjc.h */,
+				F4E675951B21D0000054530B /* Wrappers.pbobjc.m */,
+				F4E675AD1B21D05C0054530B /* wrappers.proto */,
+			);
+			name = Generated;
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				1D30AB110D05D00D00671497 /* Foundation.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		7461B3C50F94F84100A0C422 /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				F4B6B8B61A9CD1DE00892426 /* GPBExtensionInternals.h */,
+				F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */,
+				7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */,
+				7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */,
+				F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */,
+				8B79657814992E3E002FFBFC /* GPBRootObject.h */,
+				8B79657914992E3E002FFBFC /* GPBRootObject.m */,
+			);
+			name = Extensions;
+			sourceTree = "<group>";
+		};
+		7461B4850F94F96600A0C422 /* Fields */ = {
+			isa = PBXGroup;
+			children = (
+				F4B6B8AF1A9CC98000892426 /* GPBUnknownField_PackagePrivate.h */,
+				7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */,
+				7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */,
+				F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */,
+				7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */,
+				7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */,
+			);
+			name = Fields;
+			sourceTree = "<group>";
+		};
+		7461B4860F94F96B00A0C422 /* IO */ = {
+			isa = PBXGroup;
+			children = (
+				51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */,
+				7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */,
+				7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */,
+				F44929001C866B1900C2548A /* GPBCodedOutputStream_PackagePrivate.h */,
+				7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */,
+				7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */,
+				7461B4E70F94F99000A0C422 /* GPBWireFormat.h */,
+				7461B4E80F94F99000A0C422 /* GPBWireFormat.m */,
+			);
+			name = IO;
+			sourceTree = "<group>";
+		};
+		7461B5150F94FA7300A0C422 /* Messages */ = {
+			isa = PBXGroup;
+			children = (
+				515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */,
+				8B96157214C8B06000A2AC0B /* GPBDescriptor.h */,
+				8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */,
+				7461B4BE0F94F99000A0C422 /* GPBMessage.h */,
+				5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */,
+				7461B4BF0F94F99000A0C422 /* GPBMessage.m */,
+			);
+			name = Messages;
+			sourceTree = "<group>";
+		};
+		7461B6940F94FDDD00A0C422 /* Tests */ = {
+			isa = PBXGroup;
+			children = (
+				8B4248B81A8C254000BC1EC6 /* protobuf */,
+				8B210CCD159383D60032D72D /* golden_message */,
+				8B210CCF159386920032D72D /* golden_packed_fields_message */,
+				8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */,
+				F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */,
+				7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */,
+				7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */,
+				5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */,
+				F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */,
+				F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */,
+				F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */,
+				F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */,
+				F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */,
+				F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */,
+				F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */,
+				F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */,
+				7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */,
+				F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */,
+				F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */,
+				F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */,
+				F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */,
+				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
+				8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */,
+				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
+				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
+				8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+				7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
+				7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
+				8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */,
+				7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */,
+				F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */,
+				F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */,
+				8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */,
+				F4AC9E1D1A8BEB3500BD6E83 /* unittest_cycle.proto */,
+				8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */,
+				8B7E6A7614893DBA00F8884A /* unittest_empty.proto */,
+				8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */,
+				8B7E6A7814893DBB00F8884A /* unittest_import.proto */,
+				8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */,
+				8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */,
+				8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */,
+				8B09AAF614B663A7007B4184 /* unittest_objc.proto */,
+				F4CF31701B162ED800BD9B06 /* unittest_objc_startup.proto */,
+				8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */,
+				F4487C781AADFB3100531423 /* unittest_runtime_proto2.proto */,
+				F4487C791AADFB3200531423 /* unittest_runtime_proto3.proto */,
+				8B7E6A7E14893DBC00F8884A /* unittest.proto */,
+				8B4248B91A8C256900BC1EC6 /* UnitTests-Bridging-Header.h */,
+				7401C1A90F950347006D8281 /* UnitTests-Info.plist */,
+			);
+			path = Tests;
+			sourceTree = "<group>";
+		};
+		8BCF334414ED727300BC5317 /* Support */ = {
+			isa = PBXGroup;
+			children = (
+				F4411BE71AF12FD700324B4A /* GPBArray_PackagePrivate.h */,
+				F401DC2A1A8D444600FCC765 /* GPBArray.h */,
+				F401DC2B1A8D444600FCC765 /* GPBArray.m */,
+				7461B48D0F94F99000A0C422 /* GPBBootstrap.h */,
+				F43725911AC9832D004DCAFB /* GPBDictionary_PackagePrivate.h */,
+				F4353D201ABB1537005A6198 /* GPBDictionary.h */,
+				F4353D211ABB1537005A6198 /* GPBDictionary.m */,
+				8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */,
+				F4487C7C1AAE06AC00531423 /* GPBUtilities_PackagePrivate.h */,
+				7461B4E50F94F99000A0C422 /* GPBUtilities.h */,
+				7461B4E60F94F99000A0C422 /* GPBUtilities.m */,
+				8B4248CF1A927E1500BC1EC6 /* GPBWellKnownTypes.h */,
+				8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */,
+			);
+			name = Support;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		7461B52A0F94FAF800A0C422 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C391A9F8E0200531423 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+		F45BBC141B0CE3C6002D064D /* Compile Unittest Protos */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "$(ACTION)";
+			buildConfigurationList = F45BBC171B0CE3C6002D064D /* Build configuration list for PBXLegacyTarget "Compile Unittest Protos" */;
+			buildPhases = (
+			);
+			buildToolPath = DevTools/compile_testing_protos.sh;
+			dependencies = (
+			);
+			name = "Compile Unittest Protos";
+			passBuildSettingsInEnvironment = 1;
+			productName = "Compile Unittest Protos";
+		};
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+		7461B52D0F94FAF800A0C422 /* ProtocolBuffers */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */;
+			buildPhases = (
+				7461B52A0F94FAF800A0C422 /* Headers */,
+				7461B52B0F94FAF800A0C422 /* Sources */,
+				7461B52C0F94FAF800A0C422 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = ProtocolBuffers;
+			productName = "ProtocolBuffers-iPhoneDevice";
+			productReference = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+		8BBEA4A5147C727100C4ADB7 /* UnitTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */;
+			buildPhases = (
+				F4B62A781AF91F6000AFCEDC /* Script: Check Runtime Stamps */,
+				8BBEA4A1147C727100C4ADB7 /* Resources */,
+				8BBEA4A2147C727100C4ADB7 /* Sources */,
+				8BBEA4A3147C727100C4ADB7 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */,
+				F45BBC191B0CE3D7002D064D /* PBXTargetDependency */,
+			);
+			name = UnitTests;
+			productName = UnitTests;
+			productReference = 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		F4487C381A9F8E0200531423 /* TestSingleSourceBuild */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F4487C4E1A9F8E0200531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */;
+			buildPhases = (
+				F4487C391A9F8E0200531423 /* Headers */,
+				F4487C3D1A9F8E0200531423 /* Sources */,
+				F4487C4C1A9F8E0200531423 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = TestSingleSourceBuild;
+			productName = "ProtocolBuffers-iPhoneDevice";
+			productReference = F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		29B97313FDCFA39411CA2CEA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 0710;
+				LastTestingUpgradeCheck = 0600;
+				LastUpgradeCheck = 0710;
+				TargetAttributes = {
+					8BBEA4A5147C727100C4ADB7 = {
+						TestTargetID = 8B9A5EA41831993600A9D33B;
+					};
+					F45BBC141B0CE3C6002D064D = {
+						CreatedOnToolsVersion = 6.3.2;
+					};
+				};
+			};
+			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_OSX" */;
+			compatibilityVersion = "Xcode 6.3";
+			developmentRegion = English;
+			hasScannedForEncodings = 1;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				7461B52D0F94FAF800A0C422 /* ProtocolBuffers */,
+				8BBEA4A5147C727100C4ADB7 /* UnitTests */,
+				F4487C381A9F8E0200531423 /* TestSingleSourceBuild */,
+				F45BBC141B0CE3C6002D064D /* Compile Unittest Protos */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		8BBEA4A1147C727100C4ADB7 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8B210CCE159383D60032D72D /* golden_message in Resources */,
+				F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */,
+				8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */,
+				F45E57C71AE6DC6A000B7D99 /* text_format_map_unittest_data.txt in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		F4B62A781AF91F6000AFCEDC /* Script: Check Runtime Stamps */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Script: Check Runtime Stamps";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "set -eu\nexec \"${SOURCE_ROOT}/DevTools/check_version_stamps.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		7461B52B0F94FAF800A0C422 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */,
+				F4E6759B1B21D0000054530B /* Empty.pbobjc.m in Sources */,
+				7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */,
+				F401DC2D1A8D444600FCC765 /* GPBArray.m in Sources */,
+				7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */,
+				F4E6759D1B21D0000054530B /* FieldMask.pbobjc.m in Sources */,
+				7461B54C0F94FB4E00A0C422 /* GPBUnknownField.m in Sources */,
+				7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */,
+				7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */,
+				7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */,
+				7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */,
+				F4E675991B21D0000054530B /* Api.pbobjc.m in Sources */,
+				F4E6759F1B21D0000054530B /* SourceContext.pbobjc.m in Sources */,
+				F4353D231ABB1537005A6198 /* GPBDictionary.m in Sources */,
+				8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */,
+				8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */,
+				F4E675971B21D0000054530B /* Any.pbobjc.m in Sources */,
+				F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */,
+				8B4248D21A927E1500BC1EC6 /* GPBWellKnownTypes.m in Sources */,
+				F4E675A31B21D0000054530B /* Type.pbobjc.m in Sources */,
+				F4E675A11B21D0000054530B /* Struct.pbobjc.m in Sources */,
+				F4E675A51B21D0000054530B /* Wrappers.pbobjc.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8BBEA4A2147C727100C4ADB7 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */,
+				F401DC331A8E5C0200FCC765 /* GPBArrayTests.m in Sources */,
+				F4353D361AC06F10005A6198 /* GPBDictionaryTests+Int64.m in Sources */,
+				F4353D391AC06F10005A6198 /* GPBDictionaryTests+UInt64.m in Sources */,
+				8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */,
+				F4E675B21B21D0A70054530B /* SourceContext.pbobjc.m in Sources */,
+				8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */,
+				F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
+				F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */,
+				8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
+				F4E675B01B21D0A70054530B /* Empty.pbobjc.m in Sources */,
+				F4E675B41B21D0A70054530B /* Type.pbobjc.m in Sources */,
+				F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */,
+				F4E675B51B21D0A70054530B /* Wrappers.pbobjc.m in Sources */,
+				F4E675AE1B21D0A70054530B /* Any.pbobjc.m in Sources */,
+				8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */,
+				5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
+				F4E675B31B21D0A70054530B /* Struct.pbobjc.m in Sources */,
+				F4487C751AADF7F500531423 /* GPBMessageTests+Runtime.m in Sources */,
+				F4353D351AC06F10005A6198 /* GPBDictionaryTests+Int32.m in Sources */,
+				8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */,
+				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
+				F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
+				F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */,
+				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
+				F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */,
+				F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
+				8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */,
+				8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */,
+				8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */,
+				8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */,
+				F4E675B11B21D0A70054530B /* FieldMask.pbobjc.m in Sources */,
+				8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */,
+				F4E675AF1B21D0A70054530B /* Api.pbobjc.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C3D1A9F8E0200531423 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F4487C521A9F8E4D00531423 /* GPBProtocolBuffers.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */;
+			targetProxy = 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */;
+		};
+		F45BBC191B0CE3D7002D064D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F45BBC141B0CE3C6002D064D /* Compile Unittest Protos */;
+			targetProxy = F45BBC181B0CE3D7002D064D /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		7461B52F0F94FAFA00A0C422 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = ProtocolBuffers;
+			};
+			name = Debug;
+		};
+		7461B5300F94FAFA00A0C422 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = ProtocolBuffers;
+			};
+			name = Release;
+		};
+		8BBEA4A7147C727100C4ADB7 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = (
+					"${PROJECT_DERIVED_FILE_DIR}/protos",
+					"$(SRCROOT)",
+				);
+				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:identifier}";
+				PRODUCT_NAME = UnitTests;
+				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		8BBEA4A8147C727100C4ADB7 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = (
+					"${PROJECT_DERIVED_FILE_DIR}/protos",
+					"$(SRCROOT)",
+				);
+				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:identifier}";
+				PRODUCT_NAME = UnitTests;
+				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
+			};
+			name = Release;
+		};
+		C01FCF4F08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+				GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+				GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+				GCC_WARN_MISSING_PARENTHESES = YES;
+				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+				GCC_WARN_SHADOW = YES;
+				GCC_WARN_SIGN_COMPARE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNKNOWN_PRAGMAS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_LABEL = YES;
+				GCC_WARN_UNUSED_PARAMETER = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PROFILING_CODE = NO;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
+				ONLY_ACTIVE_ARCH = YES;
+				RUN_CLANG_STATIC_ANALYZER = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		C01FCF5008A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_NS_ASSERTIONS = NO;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+				GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+				GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+				GCC_WARN_MISSING_PARENTHESES = YES;
+				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+				GCC_WARN_SHADOW = YES;
+				GCC_WARN_SIGN_COMPARE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNKNOWN_PRAGMAS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_LABEL = YES;
+				GCC_WARN_UNUSED_PARAMETER = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PROFILING_CODE = NO;
+				MACOSX_DEPLOYMENT_TARGET = 10.9;
+				RUN_CLANG_STATIC_ANALYZER = YES;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		F4487C4F1A9F8E0200531423 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = TestSingleSourceBuild;
+			};
+			name = Debug;
+		};
+		F4487C501A9F8E0200531423 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = TestSingleSourceBuild;
+			};
+			name = Release;
+		};
+		F45BBC151B0CE3C6002D064D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Debug;
+		};
+		F45BBC161B0CE3C6002D064D /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7461B52F0F94FAFA00A0C422 /* Debug */,
+				7461B5300F94FAFA00A0C422 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				8BBEA4A7147C727100C4ADB7 /* Debug */,
+				8BBEA4A8147C727100C4ADB7 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_OSX" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4F08A954540054247B /* Debug */,
+				C01FCF5008A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		F4487C4E1A9F8E0200531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F4487C4F1A9F8E0200531423 /* Debug */,
+				F4487C501A9F8E0200531423 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		F45BBC171B0CE3C6002D064D /* Build configuration list for PBXLegacyTarget "Compile Unittest Protos" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F45BBC151B0CE3C6002D064D /* Debug */,
+				F45BBC161B0CE3C6002D064D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..888be4d
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:ProtocolBuffers_OSX.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..08de0be
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+	<false/>
+</dict>
+</plist>
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
new file mode 100644
index 0000000..25814c5
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
@@ -0,0 +1,335 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0710"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+               BuildableName = "libProtocolBuffers.a"
+               BlueprintName = "ProtocolBuffers"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Release"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "CodedInputStreamTests">
+               </Test>
+               <Test
+                  Identifier = "CodedOutputStreamTests">
+               </Test>
+               <Test
+                  Identifier = "ConcurrencyTests">
+               </Test>
+               <Test
+                  Identifier = "DescriptorTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolBoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolDoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolFloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolUInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolUInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBridgeTests">
+               </Test>
+               <Test
+                  Identifier = "GPBDoubleArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBEnumArrayCustomTests">
+               </Test>
+               <Test
+                  Identifier = "GPBEnumArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBFloatArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBObjectiveCPlusPlusTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringBoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringDoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringEnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringEnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringFloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringUInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringUInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBTestCase">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "MessageMergeTests">
+               </Test>
+               <Test
+                  Identifier = "MessageRuntimeTests">
+               </Test>
+               <Test
+                  Identifier = "MessageSerializationTests">
+               </Test>
+               <Test
+                  Identifier = "MessageTests">
+               </Test>
+               <Test
+                  Identifier = "UnknownFieldSetTest">
+               </Test>
+               <Test
+                  Identifier = "UtilitiesTests">
+               </Test>
+               <Test
+                  Identifier = "WellKnownTypesTest">
+               </Test>
+               <Test
+                  Identifier = "WireFormatTests">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Release"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Release">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
new file mode 100644
index 0000000..8f510f5
--- /dev/null
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0710"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "NO">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+               BuildableName = "libProtocolBuffers.a"
+               BlueprintName = "ProtocolBuffers"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "F4487C381A9F8E0200531423"
+               BuildableName = "libTestSingleSourceBuild.a"
+               BlueprintName = "TestSingleSourceBuild"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "NO"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "PerfTests">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..b622181
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -0,0 +1,1115 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 47;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; };
+		7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; };
+		7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */; };
+		7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */; };
+		7461B54C0F94FB4E00A0C422 /* GPBUnknownField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */; };
+		7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4BF0F94F99000A0C422 /* GPBMessage.m */; };
+		7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */; };
+		7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E60F94F99000A0C422 /* GPBUtilities.m */; };
+		7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */; };
+		8B210CCE159383D60032D72D /* golden_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCD159383D60032D72D /* golden_message */; };
+		8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCF159386920032D72D /* golden_packed_fields_message */; };
+		8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */; };
+		8B4248E41A929C8900BC1EC6 /* GPBWellKnownTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */; };
+		8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */; };
+		8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; };
+		8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; };
+		8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
+		8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; };
+		8B9742331A89D19F00DCE92C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8B9742321A89D19F00DCE92C /* LaunchScreen.xib */; };
+		8B9742431A8AAA7800DCE92C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */; };
+		8B9A5EA61831993600A9D33B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		8B9A5EA81831993600A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; };
+		8B9A5EAE1831993600A9D33B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EAC1831993600A9D33B /* InfoPlist.strings */; };
+		8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB31831993600A9D33B /* AppDelegate.m */; };
+		8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB51831993600A9D33B /* Images.xcassets */; };
+		8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; };
+		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
+		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
+		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
+		8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */; };
+		8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */; };
+		8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */; };
+		8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */; };
+		8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; };
+		8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; };
+		8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */; };
+		F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F41C175C1833D3310064ED4D /* GPBPerfTests.m */; };
+		F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */; };
+		F4353D271ABB156F005A6198 /* GPBDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D251ABB156F005A6198 /* GPBDictionary.m */; };
+		F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */; };
+		F4353D431AC06F31005A6198 /* GPBDictionaryTests+Int32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */; };
+		F4353D441AC06F31005A6198 /* GPBDictionaryTests+Int64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */; };
+		F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */; };
+		F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */; };
+		F4353D471AC06F31005A6198 /* GPBDictionaryTests+UInt64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */; };
+		F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; };
+		F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
+		F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; };
+		F4487C731A9F906200531423 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C711A9F906200531423 /* GPBArray.m */; };
+		F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */; };
+		F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */; };
+		F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */; };
+		F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */; };
+		F45E57C91AE6DC98000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */; };
+		F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */; };
+		F4E675C81B21D1610054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B71B21D1440054530B /* Any.pbobjc.m */; };
+		F4E675C91B21D1610054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B91B21D1440054530B /* Api.pbobjc.m */; };
+		F4E675CA1B21D1610054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BC1B21D1440054530B /* Empty.pbobjc.m */; };
+		F4E675CB1B21D1610054530B /* FieldMask.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BE1B21D1440054530B /* FieldMask.pbobjc.m */; };
+		F4E675CC1B21D1610054530B /* SourceContext.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C01B21D1440054530B /* SourceContext.pbobjc.m */; };
+		F4E675CD1B21D1610054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C21B21D1440054530B /* Struct.pbobjc.m */; };
+		F4E675CE1B21D1610054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C51B21D1440054530B /* Type.pbobjc.m */; };
+		F4E675CF1B21D1610054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C71B21D1440054530B /* Wrappers.pbobjc.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 */; };
+		F4E675D31B21D1620054530B /* FieldMask.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BE1B21D1440054530B /* FieldMask.pbobjc.m */; };
+		F4E675D41B21D1620054530B /* SourceContext.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C01B21D1440054530B /* SourceContext.pbobjc.m */; };
+		F4E675D51B21D1620054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C21B21D1440054530B /* Struct.pbobjc.m */; };
+		F4E675D61B21D1620054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C51B21D1440054530B /* Type.pbobjc.m */; };
+		F4E675D71B21D1620054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		8B9A5ED01831994600A9D33B /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 8B9A5EA41831993600A9D33B;
+			remoteInfo = iOSTestHarness;
+		};
+		8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 7461B52D0F94FAF800A0C422;
+			remoteInfo = ProtocolBuffers;
+		};
+		F45BBC121B0CDBBA002D064D /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F45BBC0E1B0CDB50002D064D;
+			remoteInfo = "Compile Unittest Protos";
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBConcurrencyTests.m; sourceTree = "<group>"; };
+		51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream_PackagePrivate.h; sourceTree = "<group>"; };
+		515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor_PackagePrivate.h; sourceTree = "<group>"; };
+		5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBMessage_PackagePrivate.h; sourceTree = "<group>"; };
+		7401C1A90F950347006D8281 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = "<group>"; };
+		7461B48D0F94F99000A0C422 /* GPBBootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBBootstrap.h; sourceTree = "<group>"; };
+		7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream.h; sourceTree = "<group>"; };
+		7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPBCodedInputStream.m; sourceTree = "<group>"; };
+		7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream.h; sourceTree = "<group>"; };
+		7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOutputStream.m; sourceTree = "<group>"; };
+		7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry.h; sourceTree = "<group>"; };
+		7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionRegistry.m; sourceTree = "<group>"; };
+		7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField.h; sourceTree = "<group>"; };
+		7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownField.m; sourceTree = "<group>"; };
+		7461B4BE0F94F99000A0C422 /* GPBMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBMessage.h; sourceTree = "<group>"; };
+		7461B4BF0F94F99000A0C422 /* GPBMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessage.m; sourceTree = "<group>"; };
+		7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers.h; sourceTree = "<group>"; };
+		7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet.h; sourceTree = "<group>"; };
+		7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSet.m; sourceTree = "<group>"; };
+		7461B4E50F94F99000A0C422 /* GPBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUtilities.h; sourceTree = "<group>"; };
+		7461B4E60F94F99000A0C422 /* GPBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilities.m; sourceTree = "<group>"; };
+		7461B4E70F94F99000A0C422 /* GPBWireFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWireFormat.h; sourceTree = "<group>"; };
+		7461B4E80F94F99000A0C422 /* GPBWireFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormat.m; sourceTree = "<group>"; };
+		7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libProtocolBuffers.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedInputStreamTests.m; sourceTree = "<group>"; };
+		7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOuputStreamTests.m; sourceTree = "<group>"; };
+		7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessageTests.m; sourceTree = "<group>"; };
+		7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBTestUtilities.h; sourceTree = "<group>"; };
+		7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBTestUtilities.m; sourceTree = "<group>"; };
+		7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSetTest.m; sourceTree = "<group>"; };
+		7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilitiesTests.m; sourceTree = "<group>"; };
+		7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormatTests.m; sourceTree = "<group>"; };
+		8B09AAF614B663A7007B4184 /* unittest_objc.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc.proto; sourceTree = "<group>"; };
+		8B210CCD159383D60032D72D /* golden_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_message; sourceTree = "<group>"; };
+		8B210CCF159386920032D72D /* golden_packed_fields_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_packed_fields_message; sourceTree = "<group>"; };
+		8B4248B21A8BD96D00BC1EC6 /* UnitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnitTests-Bridging-Header.h"; sourceTree = "<group>"; };
+		8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPBSwiftTests.swift; sourceTree = "<group>"; };
+		8B4248B71A8BDD9600BC1EC6 /* protobuf */ = {isa = PBXFileReference; lastKnownFileType = text; name = protobuf; path = ../../Intermediates/ProtocolBuffers_iOS.build/DerivedSources/protos/google/protobuf; sourceTree = BUILT_PRODUCTS_DIR; };
+		8B4248DD1A929C7D00BC1EC6 /* Duration.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Duration.pbobjc.h; path = google/protobuf/Duration.pbobjc.h; sourceTree = "<group>"; };
+		8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Duration.pbobjc.m; path = google/protobuf/Duration.pbobjc.m; sourceTree = "<group>"; };
+		8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = google/protobuf/Timestamp.pbobjc.m; sourceTree = "<group>"; };
+		8B4248E11A929C8900BC1EC6 /* GPBWellKnownTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWellKnownTypes.h; sourceTree = "<group>"; };
+		8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypes.m; sourceTree = "<group>"; };
+		8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = "<group>"; };
+		8B4249481A92A02300BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = "<group>"; };
+		8B42494A1A92A0BA00BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = "<group>"; };
+		8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = "<group>"; };
+		8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = "<group>"; };
+		8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_custom_options.proto; path = ../../src/google/protobuf/unittest_custom_options.proto; sourceTree = "<group>"; };
+		8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_embed_optimize_for.proto; path = ../../src/google/protobuf/unittest_embed_optimize_for.proto; sourceTree = "<group>"; };
+		8B7E6A7614893DBA00F8884A /* unittest_empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_empty.proto; path = ../../src/google/protobuf/unittest_empty.proto; sourceTree = "<group>"; };
+		8B7E6A7814893DBB00F8884A /* unittest_import.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_import.proto; path = ../../src/google/protobuf/unittest_import.proto; sourceTree = "<group>"; };
+		8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_mset.proto; path = ../../src/google/protobuf/unittest_mset.proto; sourceTree = "<group>"; };
+		8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_no_generic_services.proto; path = ../../src/google/protobuf/unittest_no_generic_services.proto; sourceTree = "<group>"; };
+		8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_optimize_for.proto; path = ../../src/google/protobuf/unittest_optimize_for.proto; sourceTree = "<group>"; };
+		8B7E6A7E14893DBC00F8884A /* unittest.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest.proto; path = ../../src/google/protobuf/unittest.proto; sourceTree = "<group>"; };
+		8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; };
+		8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; };
+		8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; };
+		8B9742321A89D19F00DCE92C /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; };
+		8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		8B9A5E9F1831913D00A9D33B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		8B9A5EA51831993600A9D33B /* iOSTestHarness.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestHarness.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		8B9A5EAB1831993600A9D33B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		8B9A5EAD1831993600A9D33B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		8B9A5EB31831993600A9D33B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		8B9A5EB51831993600A9D33B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
+		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
+		8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = "<group>"; };
+		8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = "<group>"; };
+		8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = "<group>"; };
+		F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = "<group>"; };
+		F41C175C1833D3310064ED4D /* GPBPerfTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBPerfTests.m; sourceTree = "<group>"; };
+		F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptorTests.m; sourceTree = "<group>"; };
+		F4353D241ABB156F005A6198 /* GPBDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBDictionary.h; sourceTree = "<group>"; };
+		F4353D251ABB156F005A6198 /* GPBDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionary.m; sourceTree = "<group>"; };
+		F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GPBDictionaryTests.pddm; sourceTree = "<group>"; };
+		F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Bool.m"; sourceTree = "<group>"; };
+		F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int32.m"; sourceTree = "<group>"; };
+		F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int64.m"; sourceTree = "<group>"; };
+		F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+String.m"; sourceTree = "<group>"; };
+		F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt32.m"; sourceTree = "<group>"; };
+		F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt64.m"; sourceTree = "<group>"; };
+		F43725921AC9835D004DCAFB /* GPBDictionary_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDictionary_PackagePrivate.h; sourceTree = "<group>"; };
+		F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = "<group>"; };
+		F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = "<group>"; };
+		F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		F4487C701A9F906200531423 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = "<group>"; };
+		F4487C711A9F906200531423 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = "<group>"; };
+		F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Runtime.m"; sourceTree = "<group>"; };
+		F4487C7A1AADFB5500531423 /* unittest_runtime_proto2.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto2.proto; sourceTree = "<group>"; };
+		F4487C7B1AADFB5500531423 /* unittest_runtime_proto3.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto3.proto; sourceTree = "<group>"; };
+		F4487C7D1AAE06C500531423 /* GPBUtilities_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUtilities_PackagePrivate.h; sourceTree = "<group>"; };
+		F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Serialization.m"; sourceTree = "<group>"; };
+		F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Merge.m"; sourceTree = "<group>"; };
+		F44929021C866B3B00C2548A /* GPBCodedOutputStream_PackagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream_PackagePrivate.h; sourceTree = "<group>"; };
+		F451D3F61A8AAEA600B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers_RuntimeSupport.h; sourceTree = "<group>"; };
+		F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionInternals.m; sourceTree = "<group>"; };
+		F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; };
+		F4AC9E1C1A8BEB1000BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; };
+		F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GPBObjectiveCPlusPlusTest.mm; sourceTree = "<group>"; };
+		F4B6B8B01A9CC99500892426 /* GPBUnknownField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField_PackagePrivate.h; sourceTree = "<group>"; };
+		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>"; };
+		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>"; };
+		F4E675B81B21D1440054530B /* Api.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Api.pbobjc.h; path = google/protobuf/Api.pbobjc.h; sourceTree = "<group>"; };
+		F4E675B91B21D1440054530B /* Api.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Api.pbobjc.m; path = google/protobuf/Api.pbobjc.m; sourceTree = "<group>"; };
+		F4E675BB1B21D1440054530B /* Empty.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Empty.pbobjc.h; path = google/protobuf/Empty.pbobjc.h; sourceTree = "<group>"; };
+		F4E675BC1B21D1440054530B /* Empty.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Empty.pbobjc.m; path = google/protobuf/Empty.pbobjc.m; sourceTree = "<group>"; };
+		F4E675BD1B21D1440054530B /* FieldMask.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FieldMask.pbobjc.h; path = google/protobuf/FieldMask.pbobjc.h; sourceTree = "<group>"; };
+		F4E675BE1B21D1440054530B /* FieldMask.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = FieldMask.pbobjc.m; path = google/protobuf/FieldMask.pbobjc.m; sourceTree = "<group>"; };
+		F4E675BF1B21D1440054530B /* SourceContext.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SourceContext.pbobjc.h; path = google/protobuf/SourceContext.pbobjc.h; sourceTree = "<group>"; };
+		F4E675C01B21D1440054530B /* SourceContext.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SourceContext.pbobjc.m; path = google/protobuf/SourceContext.pbobjc.m; sourceTree = "<group>"; };
+		F4E675C11B21D1440054530B /* Struct.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Struct.pbobjc.h; path = google/protobuf/Struct.pbobjc.h; sourceTree = "<group>"; };
+		F4E675C21B21D1440054530B /* Struct.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Struct.pbobjc.m; path = google/protobuf/Struct.pbobjc.m; sourceTree = "<group>"; };
+		F4E675C31B21D1440054530B /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = google/protobuf/Timestamp.pbobjc.h; sourceTree = "<group>"; };
+		F4E675C41B21D1440054530B /* Type.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Type.pbobjc.h; path = google/protobuf/Type.pbobjc.h; sourceTree = "<group>"; };
+		F4E675C51B21D1440054530B /* Type.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Type.pbobjc.m; path = google/protobuf/Type.pbobjc.m; sourceTree = "<group>"; };
+		F4E675C61B21D1440054530B /* Wrappers.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Wrappers.pbobjc.h; path = google/protobuf/Wrappers.pbobjc.h; sourceTree = "<group>"; };
+		F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Wrappers.pbobjc.m; path = google/protobuf/Wrappers.pbobjc.m; sourceTree = "<group>"; };
+		F4E675D81B21D1DE0054530B /* any.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = any.proto; path = ../src/google/protobuf/any.proto; sourceTree = "<group>"; };
+		F4E675D91B21D1DE0054530B /* api.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = api.proto; path = ../src/google/protobuf/api.proto; sourceTree = "<group>"; };
+		F4E675DA1B21D1DE0054530B /* empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = empty.proto; path = ../src/google/protobuf/empty.proto; sourceTree = "<group>"; };
+		F4E675DB1B21D1DE0054530B /* field_mask.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = field_mask.proto; path = ../src/google/protobuf/field_mask.proto; sourceTree = "<group>"; };
+		F4E675DC1B21D1DE0054530B /* source_context.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = source_context.proto; path = ../src/google/protobuf/source_context.proto; sourceTree = "<group>"; };
+		F4E675DD1B21D1DE0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
+		F4E675DE1B21D1DE0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
+		F4E675DF1B21D1DE0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		7461B52C0F94FAF800A0C422 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8B9A5EA21831993600A9D33B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8B9742431A8AAA7800DCE92C /* CoreGraphics.framework in Frameworks */,
+				8B9A5EA81831993600A9D33B /* UIKit.framework in Frameworks */,
+				8B9A5EA61831993600A9D33B /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8BBEA4A3147C727100C4ADB7 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */,
+				8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */,
+				8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C691A9F8F8100531423 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		080E96DDFE201D6D7F000001 /* Core Source */ = {
+			isa = PBXGroup;
+			children = (
+				7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */,
+				F451D3F61A8AAEA600B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */,
+				8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */,
+				7461B3C50F94F84100A0C422 /* Extensions */,
+				7461B4850F94F96600A0C422 /* Fields */,
+				7461B4860F94F96B00A0C422 /* IO */,
+				7461B5150F94FA7300A0C422 /* Messages */,
+				8BCF334414ED727300BC5317 /* Support */,
+				29B97315FDCFA39411CA2CEA /* Generated */,
+			);
+			name = "Core Source";
+			sourceTree = "<group>";
+		};
+		19C28FACFE9D520D11CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */,
+				8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */,
+				8B9A5EA51831993600A9D33B /* iOSTestHarness.app */,
+				F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+			isa = PBXGroup;
+			children = (
+				080E96DDFE201D6D7F000001 /* Core Source */,
+				7461B6940F94FDDD00A0C422 /* Tests */,
+				29B97323FDCFA39411CA2CEA /* Frameworks */,
+				19C28FACFE9D520D11CA2CBB /* Products */,
+			);
+			name = CustomTemplate;
+			sourceTree = "<group>";
+		};
+		29B97315FDCFA39411CA2CEA /* Generated */ = {
+			isa = PBXGroup;
+			children = (
+				F4E675B61B21D1440054530B /* Any.pbobjc.h */,
+				F4E675B71B21D1440054530B /* Any.pbobjc.m */,
+				F4E675D81B21D1DE0054530B /* any.proto */,
+				F4E675B81B21D1440054530B /* Api.pbobjc.h */,
+				F4E675B91B21D1440054530B /* Api.pbobjc.m */,
+				F4E675D91B21D1DE0054530B /* api.proto */,
+				8B4248DD1A929C7D00BC1EC6 /* Duration.pbobjc.h */,
+				8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */,
+				8B42494A1A92A0BA00BC1EC6 /* duration.proto */,
+				F4E675BB1B21D1440054530B /* Empty.pbobjc.h */,
+				F4E675BC1B21D1440054530B /* Empty.pbobjc.m */,
+				F4E675DA1B21D1DE0054530B /* empty.proto */,
+				F4E675DB1B21D1DE0054530B /* field_mask.proto */,
+				F4E675BD1B21D1440054530B /* FieldMask.pbobjc.h */,
+				F4E675BE1B21D1440054530B /* FieldMask.pbobjc.m */,
+				F4E675DC1B21D1DE0054530B /* source_context.proto */,
+				F4E675BF1B21D1440054530B /* SourceContext.pbobjc.h */,
+				F4E675C01B21D1440054530B /* SourceContext.pbobjc.m */,
+				F4E675C11B21D1440054530B /* Struct.pbobjc.h */,
+				F4E675C21B21D1440054530B /* Struct.pbobjc.m */,
+				F4E675DD1B21D1DE0054530B /* struct.proto */,
+				F4E675C31B21D1440054530B /* Timestamp.pbobjc.h */,
+				8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */,
+				8B4249481A92A02300BC1EC6 /* timestamp.proto */,
+				F4E675C41B21D1440054530B /* Type.pbobjc.h */,
+				F4E675C51B21D1440054530B /* Type.pbobjc.m */,
+				F4E675DE1B21D1DE0054530B /* type.proto */,
+				F4E675C61B21D1440054530B /* Wrappers.pbobjc.h */,
+				F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */,
+				F4E675DF1B21D1DE0054530B /* wrappers.proto */,
+			);
+			name = Generated;
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */,
+				8B9A5E9F1831913D00A9D33B /* UIKit.framework */,
+				1D30AB110D05D00D00671497 /* Foundation.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		7461B3C50F94F84100A0C422 /* Extensions */ = {
+			isa = PBXGroup;
+			children = (
+				F4B6B8B31A9CD1C600892426 /* GPBExtensionInternals.h */,
+				F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */,
+				7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */,
+				7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */,
+				F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */,
+				8B79657814992E3E002FFBFC /* GPBRootObject.h */,
+				8B79657914992E3E002FFBFC /* GPBRootObject.m */,
+			);
+			name = Extensions;
+			sourceTree = "<group>";
+		};
+		7461B4850F94F96600A0C422 /* Fields */ = {
+			isa = PBXGroup;
+			children = (
+				F4B6B8B01A9CC99500892426 /* GPBUnknownField_PackagePrivate.h */,
+				7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */,
+				7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */,
+				F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */,
+				7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */,
+				7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */,
+			);
+			name = Fields;
+			sourceTree = "<group>";
+		};
+		7461B4860F94F96B00A0C422 /* IO */ = {
+			isa = PBXGroup;
+			children = (
+				51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */,
+				7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */,
+				7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */,
+				F44929021C866B3B00C2548A /* GPBCodedOutputStream_PackagePrivate.h */,
+				7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */,
+				7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */,
+				7461B4E70F94F99000A0C422 /* GPBWireFormat.h */,
+				7461B4E80F94F99000A0C422 /* GPBWireFormat.m */,
+			);
+			name = IO;
+			sourceTree = "<group>";
+		};
+		7461B5150F94FA7300A0C422 /* Messages */ = {
+			isa = PBXGroup;
+			children = (
+				515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */,
+				8B96157214C8B06000A2AC0B /* GPBDescriptor.h */,
+				8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */,
+				7461B4BE0F94F99000A0C422 /* GPBMessage.h */,
+				5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */,
+				7461B4BF0F94F99000A0C422 /* GPBMessage.m */,
+			);
+			name = Messages;
+			sourceTree = "<group>";
+		};
+		7461B6940F94FDDD00A0C422 /* Tests */ = {
+			isa = PBXGroup;
+			children = (
+				8B9A5EA91831993600A9D33B /* iOSTestHarness */,
+				8B4248B71A8BDD9600BC1EC6 /* protobuf */,
+				8B210CCD159383D60032D72D /* golden_message */,
+				8B210CCF159386920032D72D /* golden_packed_fields_message */,
+				8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */,
+				F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */,
+				7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */,
+				7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */,
+				5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */,
+				F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */,
+				F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */,
+				F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */,
+				F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */,
+				F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */,
+				F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */,
+				F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */,
+				F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */,
+				7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */,
+				F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */,
+				F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */,
+				F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */,
+				F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */,
+				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
+				8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */,
+				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
+				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
+				8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+				7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
+				7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
+				8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */,
+				7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */,
+				F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */,
+				F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */,
+				8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */,
+				F4AC9E1C1A8BEB1000BD6E83 /* unittest_cycle.proto */,
+				8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */,
+				8B7E6A7614893DBA00F8884A /* unittest_empty.proto */,
+				8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */,
+				8B7E6A7814893DBB00F8884A /* unittest_import.proto */,
+				8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */,
+				8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */,
+				8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */,
+				8B09AAF614B663A7007B4184 /* unittest_objc.proto */,
+				F4CF31711B162EF500BD9B06 /* unittest_objc_startup.proto */,
+				8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */,
+				F4487C7A1AADFB5500531423 /* unittest_runtime_proto2.proto */,
+				F4487C7B1AADFB5500531423 /* unittest_runtime_proto3.proto */,
+				8B7E6A7E14893DBC00F8884A /* unittest.proto */,
+				8B4248B21A8BD96D00BC1EC6 /* UnitTests-Bridging-Header.h */,
+				7401C1A90F950347006D8281 /* UnitTests-Info.plist */,
+			);
+			path = Tests;
+			sourceTree = "<group>";
+		};
+		8B9A5EA91831993600A9D33B /* iOSTestHarness */ = {
+			isa = PBXGroup;
+			children = (
+				8B9A5EB31831993600A9D33B /* AppDelegate.m */,
+				8B9A5EB51831993600A9D33B /* Images.xcassets */,
+				8B9A5EAA1831993600A9D33B /* Supporting Files */,
+				8B9742321A89D19F00DCE92C /* LaunchScreen.xib */,
+			);
+			path = iOSTestHarness;
+			sourceTree = "<group>";
+		};
+		8B9A5EAA1831993600A9D33B /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				8B9A5EAB1831993600A9D33B /* Info.plist */,
+				8B9A5EAC1831993600A9D33B /* InfoPlist.strings */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		8BCF334414ED727300BC5317 /* Support */ = {
+			isa = PBXGroup;
+			children = (
+				F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */,
+				F4487C701A9F906200531423 /* GPBArray.h */,
+				F4487C711A9F906200531423 /* GPBArray.m */,
+				7461B48D0F94F99000A0C422 /* GPBBootstrap.h */,
+				F43725921AC9835D004DCAFB /* GPBDictionary_PackagePrivate.h */,
+				F4353D241ABB156F005A6198 /* GPBDictionary.h */,
+				F4353D251ABB156F005A6198 /* GPBDictionary.m */,
+				8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */,
+				F4487C7D1AAE06C500531423 /* GPBUtilities_PackagePrivate.h */,
+				7461B4E50F94F99000A0C422 /* GPBUtilities.h */,
+				7461B4E60F94F99000A0C422 /* GPBUtilities.m */,
+				8B4248E11A929C8900BC1EC6 /* GPBWellKnownTypes.h */,
+				8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */,
+			);
+			name = Support;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		7461B52A0F94FAF800A0C422 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C561A9F8F8100531423 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+		F45BBC0E1B0CDB50002D064D /* Compile Unittest Protos */ = {
+			isa = PBXLegacyTarget;
+			buildArgumentsString = "$(ACTION)";
+			buildConfigurationList = F45BBC111B0CDB50002D064D /* Build configuration list for PBXLegacyTarget "Compile Unittest Protos" */;
+			buildPhases = (
+			);
+			buildToolPath = DevTools/compile_testing_protos.sh;
+			buildWorkingDirectory = "";
+			dependencies = (
+			);
+			name = "Compile Unittest Protos";
+			passBuildSettingsInEnvironment = 1;
+			productName = "Compile Unittest Protos";
+		};
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+		7461B52D0F94FAF800A0C422 /* ProtocolBuffers */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */;
+			buildPhases = (
+				7461B52A0F94FAF800A0C422 /* Headers */,
+				7461B52B0F94FAF800A0C422 /* Sources */,
+				7461B52C0F94FAF800A0C422 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = ProtocolBuffers;
+			productName = "ProtocolBuffers-iPhoneDevice";
+			productReference = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+		8B9A5EA41831993600A9D33B /* iOSTestHarness */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 8B9A5ECA1831993600A9D33B /* Build configuration list for PBXNativeTarget "iOSTestHarness" */;
+			buildPhases = (
+				8B9A5EA11831993600A9D33B /* Sources */,
+				8B9A5EA21831993600A9D33B /* Frameworks */,
+				8B9A5EA31831993600A9D33B /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = iOSTestHarness;
+			productName = iOSTestHarness;
+			productReference = 8B9A5EA51831993600A9D33B /* iOSTestHarness.app */;
+			productType = "com.apple.product-type.application";
+		};
+		8BBEA4A5147C727100C4ADB7 /* UnitTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */;
+			buildPhases = (
+				F4B62A791AF91F7500AFCEDC /* Script: Check Runtime Stamps */,
+				8BBEA4A1147C727100C4ADB7 /* Resources */,
+				8BBEA4A2147C727100C4ADB7 /* Sources */,
+				8BBEA4A3147C727100C4ADB7 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */,
+				F45BBC131B0CDBBA002D064D /* PBXTargetDependency */,
+				8B9A5ED11831994600A9D33B /* PBXTargetDependency */,
+			);
+			name = UnitTests;
+			productName = UnitTests;
+			productReference = 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		F4487C551A9F8F8100531423 /* TestSingleSourceBuild */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = F4487C6B1A9F8F8100531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */;
+			buildPhases = (
+				F4487C561A9F8F8100531423 /* Headers */,
+				F4487C5A1A9F8F8100531423 /* Sources */,
+				F4487C691A9F8F8100531423 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = TestSingleSourceBuild;
+			productName = "ProtocolBuffers-iPhoneDevice";
+			productReference = F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		29B97313FDCFA39411CA2CEA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 0710;
+				LastTestingUpgradeCheck = 0600;
+				LastUpgradeCheck = 0710;
+				TargetAttributes = {
+					8BBEA4A5147C727100C4ADB7 = {
+						TestTargetID = 8B9A5EA41831993600A9D33B;
+					};
+					F45BBC0E1B0CDB50002D064D = {
+						CreatedOnToolsVersion = 6.3.2;
+					};
+				};
+			};
+			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_iOS" */;
+			compatibilityVersion = "Xcode 6.3";
+			developmentRegion = English;
+			hasScannedForEncodings = 1;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				7461B52D0F94FAF800A0C422 /* ProtocolBuffers */,
+				8BBEA4A5147C727100C4ADB7 /* UnitTests */,
+				8B9A5EA41831993600A9D33B /* iOSTestHarness */,
+				F4487C551A9F8F8100531423 /* TestSingleSourceBuild */,
+				F45BBC0E1B0CDB50002D064D /* Compile Unittest Protos */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		8B9A5EA31831993600A9D33B /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8B9A5EAE1831993600A9D33B /* InfoPlist.strings in Resources */,
+				8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */,
+				8B9742331A89D19F00DCE92C /* LaunchScreen.xib in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8BBEA4A1147C727100C4ADB7 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8B210CCE159383D60032D72D /* golden_message in Resources */,
+				F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */,
+				8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */,
+				F45E57C91AE6DC98000B7D99 /* text_format_map_unittest_data.txt in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		F4B62A791AF91F7500AFCEDC /* Script: Check Runtime Stamps */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Script: Check Runtime Stamps";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "set -eu\nexec \"${SOURCE_ROOT}/DevTools/check_version_stamps.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		7461B52B0F94FAF800A0C422 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */,
+				F4E675D21B21D1620054530B /* Empty.pbobjc.m in Sources */,
+				F4487C731A9F906200531423 /* GPBArray.m in Sources */,
+				7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */,
+				7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */,
+				F4E675D31B21D1620054530B /* FieldMask.pbobjc.m in Sources */,
+				7461B54C0F94FB4E00A0C422 /* GPBUnknownField.m in Sources */,
+				7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */,
+				7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */,
+				7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */,
+				7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */,
+				F4E675D11B21D1620054530B /* Api.pbobjc.m in Sources */,
+				F4E675D41B21D1620054530B /* SourceContext.pbobjc.m in Sources */,
+				F4353D271ABB156F005A6198 /* GPBDictionary.m in Sources */,
+				8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */,
+				8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */,
+				F4E675D01B21D1620054530B /* Any.pbobjc.m in Sources */,
+				F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */,
+				8B4248E41A929C8900BC1EC6 /* GPBWellKnownTypes.m in Sources */,
+				F4E675D61B21D1620054530B /* Type.pbobjc.m in Sources */,
+				F4E675D51B21D1620054530B /* Struct.pbobjc.m in Sources */,
+				F4E675D71B21D1620054530B /* Wrappers.pbobjc.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8B9A5EA11831993600A9D33B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		8BBEA4A2147C727100C4ADB7 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */,
+				F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */,
+				F4353D441AC06F31005A6198 /* GPBDictionaryTests+Int64.m in Sources */,
+				F4353D471AC06F31005A6198 /* GPBDictionaryTests+UInt64.m in Sources */,
+				8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */,
+				F4E675CC1B21D1610054530B /* SourceContext.pbobjc.m in Sources */,
+				8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */,
+				F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */,
+				8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
+				F4E675CA1B21D1610054530B /* Empty.pbobjc.m in Sources */,
+				F4E675CE1B21D1610054530B /* Type.pbobjc.m in Sources */,
+				F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */,
+				F4E675CF1B21D1610054530B /* Wrappers.pbobjc.m in Sources */,
+				F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
+				F4E675C81B21D1610054530B /* Any.pbobjc.m in Sources */,
+				8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */,
+				5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
+				F4E675CD1B21D1610054530B /* Struct.pbobjc.m in Sources */,
+				F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */,
+				F4353D431AC06F31005A6198 /* GPBDictionaryTests+Int32.m in Sources */,
+				8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */,
+				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
+				F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
+				F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */,
+				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
+				F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */,
+				F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
+				8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */,
+				8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */,
+				8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */,
+				8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */,
+				F4E675CB1B21D1610054530B /* FieldMask.pbobjc.m in Sources */,
+				8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */,
+				F4E675C91B21D1610054530B /* Api.pbobjc.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		F4487C5A1A9F8F8100531423 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		8B9A5ED11831994600A9D33B /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 8B9A5EA41831993600A9D33B /* iOSTestHarness */;
+			targetProxy = 8B9A5ED01831994600A9D33B /* PBXContainerItemProxy */;
+		};
+		8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */;
+			targetProxy = 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */;
+		};
+		F45BBC131B0CDBBA002D064D /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F45BBC0E1B0CDB50002D064D /* Compile Unittest Protos */;
+			targetProxy = F45BBC121B0CDBBA002D064D /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		8B9A5EAC1831993600A9D33B /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				8B9A5EAD1831993600A9D33B /* en */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		7461B52F0F94FAFA00A0C422 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = ProtocolBuffers;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		7461B5300F94FAFA00A0C422 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = ProtocolBuffers;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		8B9A5ECB1831993600A9D33B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		8B9A5ECC1831993600A9D33B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME:rfc1034identifier}";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+		8BBEA4A7147C727100C4ADB7 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"\"$(SDKROOT)/Developer/Library/Frameworks\"",
+					"\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
+					"$(inherited)",
+				);
+				HEADER_SEARCH_PATHS = (
+					"${PROJECT_DERIVED_FILE_DIR}/protos",
+					"$(SRCROOT)",
+				);
+				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(DEVELOPER_DIR)/usr/lib\"",
+				);
+				PRODUCT_NAME = UnitTests;
+				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestHarness.app/iOSTestHarness";
+			};
+			name = Debug;
+		};
+		8BBEA4A8147C727100C4ADB7 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					"\"$(SDKROOT)/Developer/Library/Frameworks\"",
+					"\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
+					"$(inherited)",
+				);
+				HEADER_SEARCH_PATHS = (
+					"${PROJECT_DERIVED_FILE_DIR}/protos",
+					"$(SRCROOT)",
+				);
+				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(DEVELOPER_DIR)/usr/lib\"",
+				);
+				PRODUCT_NAME = UnitTests;
+				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestHarness.app/iOSTestHarness";
+			};
+			name = Release;
+		};
+		C01FCF4F08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+				GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+				GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+				GCC_WARN_MISSING_PARENTHESES = YES;
+				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+				GCC_WARN_SHADOW = YES;
+				GCC_WARN_SIGN_COMPARE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNKNOWN_PRAGMAS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_LABEL = YES;
+				GCC_WARN_UNUSED_PARAMETER = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PROFILING_CODE = NO;
+				IPHONEOS_DEPLOYMENT_TARGET = 6.1;
+				ONLY_ACTIVE_ARCH = YES;
+				RUN_CLANG_STATIC_ANALYZER = YES;
+				SDKROOT = iphoneos;
+			};
+			name = Debug;
+		};
+		C01FCF5008A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_NS_ASSERTIONS = NO;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+				GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+				GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+				GCC_WARN_MISSING_PARENTHESES = YES;
+				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+				GCC_WARN_SHADOW = YES;
+				GCC_WARN_SIGN_COMPARE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNKNOWN_PRAGMAS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_LABEL = YES;
+				GCC_WARN_UNUSED_PARAMETER = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PROFILING_CODE = NO;
+				IPHONEOS_DEPLOYMENT_TARGET = 6.1;
+				RUN_CLANG_STATIC_ANALYZER = YES;
+				SDKROOT = iphoneos;
+			};
+			name = Release;
+		};
+		F4487C6C1A9F8F8100531423 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = TestSingleSourceBuild;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		F4487C6D1A9F8F8100531423 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				HEADER_SEARCH_PATHS = "$(SRCROOT)";
+				PRODUCT_NAME = TestSingleSourceBuild;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		F45BBC0F1B0CDB50002D064D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Debug;
+		};
+		F45BBC101B0CDB50002D064D /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				7461B52F0F94FAFA00A0C422 /* Debug */,
+				7461B5300F94FAFA00A0C422 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		8B9A5ECA1831993600A9D33B /* Build configuration list for PBXNativeTarget "iOSTestHarness" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				8B9A5ECB1831993600A9D33B /* Debug */,
+				8B9A5ECC1831993600A9D33B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				8BBEA4A7147C727100C4ADB7 /* Debug */,
+				8BBEA4A8147C727100C4ADB7 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_iOS" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4F08A954540054247B /* Debug */,
+				C01FCF5008A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		F4487C6B1A9F8F8100531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F4487C6C1A9F8F8100531423 /* Debug */,
+				F4487C6D1A9F8F8100531423 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		F45BBC111B0CDB50002D064D /* Build configuration list for PBXLegacyTarget "Compile Unittest Protos" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F45BBC0F1B0CDB50002D064D /* Debug */,
+				F45BBC101B0CDB50002D064D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..037a91d
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:ProtocolBuffers_iOS.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..08de0be
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+	<false/>
+</dict>
+</plist>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist
new file mode 100644
index 0000000..0ac0943
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>classNames</key>
+	<dict>
+		<key>PerfTests</key>
+		<dict>
+			<key>testExtensionsPerformance</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.9</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Feb 5, 2015, 9:42:41 AM</string>
+				</dict>
+			</dict>
+			<key>testHas</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.09</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Feb 5, 2015, 9:42:35 AM</string>
+				</dict>
+			</dict>
+			<key>testMessagePerformance</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.57</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Feb 5, 2015, 9:42:47 AM</string>
+				</dict>
+			</dict>
+			<key>testPackedExtensionsPerformance</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.75</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Feb 5, 2015, 9:42:51 AM</string>
+				</dict>
+			</dict>
+			<key>testPackedTypesPerformance</key>
+			<dict>
+				<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
+				<dict>
+					<key>baselineAverage</key>
+					<real>0.26</real>
+					<key>baselineIntegrationDisplayName</key>
+					<string>Feb 5, 2015, 9:42:55 AM</string>
+				</dict>
+			</dict>
+		</dict>
+	</dict>
+</dict>
+</plist>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist
new file mode 100644
index 0000000..45bb9c1
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>runDestinationsByUUID</key>
+	<dict>
+		<key>FFE465CA-0E74-40E8-9F09-500B66B7DCB2</key>
+		<dict>
+			<key>targetArchitecture</key>
+			<string>arm64</string>
+			<key>targetDevice</key>
+			<dict>
+				<key>modelCode</key>
+				<string>iPhone7,1</string>
+				<key>platformIdentifier</key>
+				<string>com.apple.platform.iphoneos</string>
+			</dict>
+		</dict>
+	</dict>
+</dict>
+</plist>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
new file mode 100644
index 0000000..0b96b75
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
@@ -0,0 +1,345 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0710"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+               BuildableName = "libProtocolBuffers.a"
+               BlueprintName = "ProtocolBuffers"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Release"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "CodedInputStreamTests">
+               </Test>
+               <Test
+                  Identifier = "CodedOutputStreamTests">
+               </Test>
+               <Test
+                  Identifier = "ConcurrencyTests">
+               </Test>
+               <Test
+                  Identifier = "DescriptorTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolBoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolDoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolFloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolUInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBoolUInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBBridgeTests">
+               </Test>
+               <Test
+                  Identifier = "GPBDoubleArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBEnumArrayCustomTests">
+               </Test>
+               <Test
+                  Identifier = "GPBEnumArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBFloatArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt32UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBInt64UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBObjectiveCPlusPlusTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringBoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringDoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringEnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringEnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringFloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringUInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBStringUInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBTestCase">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt32UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64ArrayTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64BoolDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64DoubleDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64EnumDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64EnumDictionaryUnknownEnumTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64FloatDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64Int32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64Int64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64ObjectDictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64UInt32DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "GPBUInt64UInt64DictionaryTests">
+               </Test>
+               <Test
+                  Identifier = "MessageMergeTests">
+               </Test>
+               <Test
+                  Identifier = "MessageRuntimeTests">
+               </Test>
+               <Test
+                  Identifier = "MessageSerializationTests">
+               </Test>
+               <Test
+                  Identifier = "MessageTests">
+               </Test>
+               <Test
+                  Identifier = "UnknownFieldSetTest">
+               </Test>
+               <Test
+                  Identifier = "UtilitiesTests">
+               </Test>
+               <Test
+                  Identifier = "WellKnownTypesTest">
+               </Test>
+               <Test
+                  Identifier = "WireFormatTests">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8B9A5EA41831993600A9D33B"
+            BuildableName = "iOSTestHarness.app"
+            BlueprintName = "iOSTestHarness"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Release"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8B9A5EA41831993600A9D33B"
+            BuildableName = "iOSTestHarness.app"
+            BlueprintName = "iOSTestHarness"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Release">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
new file mode 100644
index 0000000..7d219bc
--- /dev/null
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0710"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "NO">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+               BuildableName = "libProtocolBuffers.a"
+               BlueprintName = "ProtocolBuffers"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "F4487C551A9F8F8100531423"
+               BuildableName = "libTestSingleSourceBuild.a"
+               BlueprintName = "TestSingleSourceBuild"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "NO"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "PerfTests">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8B9A5EA41831993600A9D33B"
+            BuildableName = "iOSTestHarness.app"
+            BlueprintName = "iOSTestHarness"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8B9A5EA41831993600A9D33B"
+            BuildableName = "iOSTestHarness.app"
+            BlueprintName = "iOSTestHarness"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "7461B52D0F94FAF800A0C422"
+            BuildableName = "libProtocolBuffers.a"
+            BlueprintName = "ProtocolBuffers"
+            ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/objectivec/README.md b/objectivec/README.md
new file mode 100644
index 0000000..c7313e4
--- /dev/null
+++ b/objectivec/README.md
@@ -0,0 +1,152 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Objective C Protocol Buffers runtime library.
+
+Requirements
+------------
+
+The Objective C implementation requires:
+
+- Objective C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X).
+- Xcode 7.0 (or later).
+- The library code does *not* use ARC (for performance reasons), but it all can
+  be called from ARC code.
+
+Installation
+------------
+
+The full distribution pulled from github includes the sources for both the
+compiler (protoc) and the runtime (this directory). To build the compiler
+and run the runtime tests, you can use:
+
+     $ objectivec/DevTools/full_mac_build.sh
+
+This will generate the `src/protoc` binary.
+
+Building
+--------
+
+There are two ways to include the Runtime sources in your project:
+
+Add `objectivec/\*.h` & `objectivec/GPBProtocolBuffers.m` to your project.
+
+*or*
+
+Add `objectivec/\*.h` & `objectivec/\*.m` except for
+`objectivec/GPBProtocolBuffers.m` to your project.
+
+
+If the target is using ARC, remember to turn off ARC (`-fno-objc-arc`) for the
+`.m` files.
+
+The files generated by `protoc` for the `*.proto` files (`\*.pbobjc.h' and
+`\*.pbobjc.m`) are then also added to the target.
+
+Usage
+-----
+
+The objects generated for messages should work like any other Objective C
+object. They are mutable objects, but if you don't change them, they are safe
+to share between threads (similar to passing an NSMutableDictionary between
+threads/queues; as long as no one mutates it, things are fine).
+
+There are a few behaviors worth calling out:
+
+A property that is type NSString\* will never return nil. If the value is
+unset, it will return an empty string (@""). This is inpart to align things
+with the Protocol Buffers spec which says the default for strings is an empty
+string, but also so you can always safely pass them to isEqual:/compare:, etc.
+and have deterministic results.
+
+A property that is type NSData\* also won't return nil, it will return an empty
+data ([NSData data]). The reasoning is the same as for NSString not returning
+nil.
+
+A property that is another GPBMessage class also will not return nil. If the
+field wasn't already set, you will get a instance of the correct class. This
+instance will be a temporary instance unless you mutate it, at which point it
+will be attached to its parent object. We call this pattern *autocreators*.
+Similar to NSString and NSData properties it makes things a little safer when
+using them with isEqual:/etc.; but more importantly, this allows you to write
+code that uses Objective C's property dot notation to walk into nested objects
+and access and/or assign things without having to check that they are not nil
+and create them each step along the way. You can write this:
+
+```
+- (void)updateRecord:(MyMessage *)msg {
+  ...
+  // Note: You don't have to check subMessage and otherMessage for nil and
+  // alloc/init/assign them back along the way.
+  msg.subMessage.otherMessage.lastName = @"Smith";
+  ...
+}
+```
+
+If you want to check if a GPBMessage property is present, there is always as
+`has\[NAME\]` property to go with the main property to check if it is set.
+
+A property that is of an Array or Dictionary type also provides *autocreator*
+behavior and will never return nil. This provides all the same benefits you
+see for the message properties. Again, you can write:
+
+```
+- (void)updateRecord:(MyMessage *)msg {
+  ...
+  // Note: Just like above, you don't have to check subMessage and otherMessage
+  // for nil and alloc/init/assign them back along the way. You also don't have
+  // to create the siblingsArray, you can safely just append to it.
+  [msg.subMessage.otherMessage.siblingsArray addObject:@"Pat"];
+  ...
+}
+```
+
+If you are inspecting a message you got from some other place (server, disk,
+etc), you may want to check if the Array or Dictionary has entries without
+causing it to be created for you. For this, there is always a `\[NAME\]_Count`
+property also provided that can return zero or the real count, but won't trigger
+the creation.
+
+For primitive type fields (ints, floats, bools, enum) in messages defined in a
+`.proto` file that use *proto2* syntax there are conceptual differences between
+having an *explicit* and *default* value. You can always get the value of the
+property. In the case that it hasn't been set you will get the default. In
+cases where you need to know whether it was set explicitly or you are just
+getting the default, you can use the `has\[NAME\]` property. If the value has
+been set, and you want to clear it, you can set the `has\[NAME\]` to `NO`.
+*proto3* syntax messages do away with this concept, thus the default values are
+never included when the message is encoded.
+
+The Objective C classes/enums can be used from Swift code.
+
+Objective C Generator Options
+-----------------------------
+
+**objc_class_prefix=\<prefix\>** (no default)
+
+Since Objective C uses a global namespace for all of its classes, there can
+be collisions. This option provides a prefix that will be added to the Enums
+and Objects (for messages) generated from the proto. Convention is to base
+the prefix on the package the proto is in.
+
+Contributing
+------------
+
+Please make updates to the tests along with changes. If just changing the
+runtime, the Xcode projects can be used to build and run tests. If your change
+also requires changes to the generated code,
+`objectivec/DevTools/full_mac_build.sh` can be used to easily rebuild and test
+changes. Passing `-h` to the script will show the addition options that could
+be useful.
+
+Documentation
+-------------
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/objectivec/Tests/GPBARCUnittestProtos.m b/objectivec/Tests/GPBARCUnittestProtos.m
new file mode 100644
index 0000000..28d2396
--- /dev/null
+++ b/objectivec/Tests/GPBARCUnittestProtos.m
@@ -0,0 +1,61 @@
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// 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.
+
+// Makes sure all the generated headers compile with ARC on.
+
+// The unittest_custom_options.proto extends the messages in descriptor.proto
+// so we build it in to test extending in general. The library doesn't provide
+// a descriptor as it doesn't use the classes/enums.
+#import "google/protobuf/Descriptor.pbobjc.h"
+
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestCustomOptions.pbobjc.h"
+#import "google/protobuf/UnittestCycle.pbobjc.h"
+#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h"
+#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.h"
+#import "google/protobuf/UnittestEmpty.pbobjc.h"
+#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
+#import "google/protobuf/UnittestImportLite.pbobjc.h"
+#import "google/protobuf/UnittestImportPublic.pbobjc.h"
+#import "google/protobuf/UnittestImportPublicLite.pbobjc.h"
+#import "google/protobuf/UnittestLite.pbobjc.h"
+#import "google/protobuf/UnittestMset.pbobjc.h"
+#import "google/protobuf/UnittestNoGenericServices.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/UnittestObjcStartup.pbobjc.h"
+#import "google/protobuf/UnittestOptimizeFor.pbobjc.h"
+#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m
new file mode 100644
index 0000000..0fb15e4
--- /dev/null
+++ b/objectivec/Tests/GPBArrayTests.m
@@ -0,0 +1,3438 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBArray.h"
+
+#import "GPBTestUtilities.h"
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBEnumArray (TestingTweak)
++ (instancetype)arrayWithValue:(int32_t)value;
+- (instancetype)initWithValues:(const int32_t [])values
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 71:
+    case 72:
+    case 73:
+    case 74:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+static BOOL TestingEnum_IsValidValue2(int32_t value) {
+  switch (value) {
+    case 71:
+    case 72:
+    case 73:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBEnumArray (TestingTweak)
++ (instancetype)arrayWithValue:(int32_t)value {
+  return [[[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                         rawValues:&value
+                                             count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                    count:count];
+}
+@end
+
+#pragma mark - PDDM Macros
+
+//%PDDM-DEFINE ARRAY_TESTS(NAME, TYPE, VAL1, VAL2, VAL3, VAL4)
+//%ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, )
+//%PDDM-DEFINE ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, HELPER)
+//%#pragma mark - NAME
+//%
+//%@interface GPB##NAME##ArrayTests : XCTestCase
+//%@end
+//%
+//%@implementation GPB##NAME##ArrayTests
+//%
+//%- (void)testEmpty {
+//%  GPB##NAME##Array *array = [[GPB##NAME##Array alloc] init];
+//%  XCTAssertNotNil(array);
+//%  XCTAssertEqual(array.count, 0U);
+//%  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+//%  [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    #pragma unused(value, idx, stop)
+//%    XCTFail(@"Shouldn't get here!");
+//%  }];
+//%  [array enumerateValuesWithOptions:NSEnumerationReverse
+//%                         usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    #pragma unused(value, idx, stop)
+//%    XCTFail(@"Shouldn't get here!");
+//%  }];
+//%  [array release];
+//%}
+//%
+//%- (void)testOne {
+//%  GPB##NAME##Array *array = [GPB##NAME##Array arrayWithValue:VAL1];
+//%  XCTAssertNotNil(array);
+//%  XCTAssertEqual(array.count, 1U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+//%  [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, 0U);
+//%    XCTAssertEqual(value, VAL1);
+//%    XCTAssertNotEqual(stop, NULL);
+//%  }];
+//%  [array enumerateValuesWithOptions:NSEnumerationReverse
+//%                         usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, 0U);
+//%    XCTAssertEqual(value, VAL1);
+//%    XCTAssertNotEqual(stop, NULL);
+//%  }];
+//%}
+//%
+//%- (void)testBasics {
+//%  static const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%  XCTAssertEqual(array.count, 4U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL2);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL4);
+//%  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+//%  __block NSUInteger idx2 = 0;
+//%  [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, idx2);
+//%    XCTAssertEqual(value, kValues[idx]);
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx2;
+//%  }];
+//%  idx2 = 0;
+//%  [array enumerateValuesWithOptions:NSEnumerationReverse
+//%                         usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, (3 - idx2));
+//%    XCTAssertEqual(value, kValues[idx]);
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx2;
+//%  }];
+//%  // Stopping the enumeration.
+//%  idx2 = 0;
+//%  [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, idx2);
+//%    XCTAssertEqual(value, kValues[idx]);
+//%    XCTAssertNotEqual(stop, NULL);
+//%    if (idx2 == 1) *stop = YES;
+//%    XCTAssertNotEqual(idx, 2U);
+//%    XCTAssertNotEqual(idx, 3U);
+//%    ++idx2;
+//%  }];
+//%  idx2 = 0;
+//%  [array enumerateValuesWithOptions:NSEnumerationReverse
+//%                         usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) {
+//%    XCTAssertEqual(idx, (3 - idx2));
+//%    XCTAssertEqual(value, kValues[idx]);
+//%    XCTAssertNotEqual(stop, NULL);
+//%    if (idx2 == 1) *stop = YES;
+//%    XCTAssertNotEqual(idx, 1U);
+//%    XCTAssertNotEqual(idx, 0U);
+//%    ++idx2;
+//%  }];
+//%  [array release];
+//%}
+//%
+//%- (void)testEquality {
+//%  const TYPE kValues1[] = { VAL1, VAL2, VAL3 };
+//%  const TYPE kValues2[] = { VAL1, VAL4, VAL3 };
+//%  const TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  GPB##NAME##Array *array1 =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues1
+//%            NAME$S                     count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertNotNil(array1);
+//%  GPB##NAME##Array *array1prime =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues1
+//%            NAME$S                     count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertNotNil(array1prime);
+//%  GPB##NAME##Array *array2 =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues2
+//%            NAME$S                     count:GPBARRAYSIZE(kValues2)];
+//%  XCTAssertNotNil(array2);
+//%  GPB##NAME##Array *array3 =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues3
+//%            NAME$S                     count:GPBARRAYSIZE(kValues3)];
+//%  XCTAssertNotNil(array3);
+//%
+//%  // 1/1Prime should be different objects, but equal.
+//%  XCTAssertNotEqual(array1, array1prime);
+//%  XCTAssertEqualObjects(array1, array1prime);
+//%  // Equal, so they must have same hash.
+//%  XCTAssertEqual([array1 hash], [array1prime hash]);
+//%
+//%  // 1/2/3 shouldn't be equal.
+//%  XCTAssertNotEqualObjects(array1, array2);
+//%  XCTAssertNotEqualObjects(array1, array3);
+//%  XCTAssertNotEqualObjects(array2, array3);
+//%
+//%  [array1 release];
+//%  [array1prime release];
+//%  [array2 release];
+//%  [array3 release];
+//%}
+//%
+//%- (void)testCopy {
+//%  const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%
+//%  GPB##NAME##Array *array2 = [array copy];
+//%  XCTAssertNotNil(array2);
+//%
+//%  // Should be new object but equal.
+//%  XCTAssertNotEqual(array, array2);
+//%  XCTAssertEqualObjects(array, array2);
+//%  [array2 release];
+//%  [array release];
+//%}
+//%
+//%- (void)testArrayFromArray {
+//%  const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%
+//%  GPB##NAME##Array *array2 = [GPB##NAME##Array arrayWithValueArray:array];
+//%  XCTAssertNotNil(array2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(array, array2);
+//%  XCTAssertEqualObjects(array, array2);
+//%  [array release];
+//%}
+//%
+//%- (void)testAdds {
+//%  GPB##NAME##Array *array = [GPB##NAME##Array array];
+//%  XCTAssertNotNil(array);
+//%
+//%  XCTAssertEqual(array.count, 0U);
+//%  [array addValue:VAL1];
+//%  XCTAssertEqual(array.count, 1U);
+//%
+//%  const TYPE kValues1[] = { VAL2, VAL3 };
+//%  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertEqual(array.count, 3U);
+//%
+//%  const TYPE kValues2[] = { VAL4, VAL1 };
+//%  GPB##NAME##Array *array2 =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues2
+//%            NAME$S                     count:GPBARRAYSIZE(kValues2)];
+//%  XCTAssertNotNil(array2);
+//%  [array add##HELPER##ValuesFromArray:array2];
+//%  XCTAssertEqual(array.count, 5U);
+//%
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL2);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL4);
+//%  XCTAssertEqual([array valueAtIndex:4], VAL1);
+//%  [array2 release];
+//%}
+//%
+//%- (void)testInsert {
+//%  const TYPE kValues[] = { VAL1, VAL2, VAL3 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%  XCTAssertEqual(array.count, 3U);
+//%
+//%  // First
+//%  [array insertValue:VAL4 atIndex:0];
+//%  XCTAssertEqual(array.count, 4U);
+//%
+//%  // Middle
+//%  [array insertValue:VAL4 atIndex:2];
+//%  XCTAssertEqual(array.count, 5U);
+//%
+//%  // End
+//%  [array insertValue:VAL4 atIndex:5];
+//%  XCTAssertEqual(array.count, 6U);
+//%
+//%  // Too far.
+//%  XCTAssertThrowsSpecificNamed([array insertValue:VAL4 atIndex:7],
+//%                               NSException, NSRangeException);
+//%
+//%  XCTAssertEqual([array valueAtIndex:0], VAL4);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL4);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL2);
+//%  XCTAssertEqual([array valueAtIndex:4], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:5], VAL4);
+//%  [array release];
+//%}
+//%
+//%- (void)testRemove {
+//%  const TYPE kValues[] = { VAL4, VAL1, VAL2, VAL4, VAL3, VAL4 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%  XCTAssertEqual(array.count, 6U);
+//%
+//%  // First
+//%  [array removeValueAtIndex:0];
+//%  XCTAssertEqual(array.count, 5U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%
+//%  // Middle
+//%  [array removeValueAtIndex:2];
+//%  XCTAssertEqual(array.count, 4U);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%
+//%  // End
+//%  [array removeValueAtIndex:3];
+//%  XCTAssertEqual(array.count, 3U);
+//%
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL2);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%
+//%  // Too far.
+//%  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+//%                               NSException, NSRangeException);
+//%
+//%  [array removeAll];
+//%  XCTAssertEqual(array.count, 0U);
+//%  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+//%                               NSException, NSRangeException);
+//%  [array release];
+//%}
+//%
+//%- (void)testInplaceMutation {
+//%  const TYPE kValues[] = { VAL1, VAL1, VAL3, VAL3 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%
+//%  [array replaceValueAtIndex:1 withValue:VAL2];
+//%  [array replaceValueAtIndex:3 withValue:VAL4];
+//%  XCTAssertEqual(array.count, 4U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL2);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL4);
+//%
+//%  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:VAL4],
+//%                               NSException, NSRangeException);
+//%
+//%  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+//%  XCTAssertEqual(array.count, 4U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL4);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL2);
+//%
+//%  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+//%  XCTAssertEqual(array.count, 4U);
+//%  XCTAssertEqual([array valueAtIndex:0], VAL3);
+//%  XCTAssertEqual([array valueAtIndex:1], VAL4);
+//%  XCTAssertEqual([array valueAtIndex:2], VAL1);
+//%  XCTAssertEqual([array valueAtIndex:3], VAL2);
+//%
+//%  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+//%                               NSException, NSRangeException);
+//%  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+//%                               NSException, NSRangeException);
+//%  [array release];
+//%}
+//%
+//%- (void)testInternalResizing {
+//%  const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  GPB##NAME##Array *array =
+//%      [[GPB##NAME##Array alloc] initWithValues:kValues
+//%            NAME$S                     count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(array);
+//%
+//%  // Add/remove to trigger the intneral buffer to grow/shrink.
+//%  for (int i = 0; i < 100; ++i) {
+//%    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+//%  }
+//%  XCTAssertEqual(array.count, 404U);
+//%  for (int i = 0; i < 100; ++i) {
+//%    [array removeValueAtIndex:(i * 2)];
+//%  }
+//%  XCTAssertEqual(array.count, 304U);
+//%  for (int i = 0; i < 100; ++i) {
+//%    [array insertValue:VAL4 atIndex:(i * 3)];
+//%  }
+//%  XCTAssertEqual(array.count, 404U);
+//%  [array removeAll];
+//%  XCTAssertEqual(array.count, 0U);
+//%  [array release];
+//%}
+//%
+//%@end
+//%
+//%PDDM-EXPAND ARRAY_TESTS(Int32, int32_t, 1, 2, 3, 4)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int32
+
+@interface GPBInt32ArrayTests : XCTestCase
+@end
+
+@implementation GPBInt32ArrayTests
+
+- (void)testEmpty {
+  GPBInt32Array *array = [[GPBInt32Array alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBInt32Array *array = [GPBInt32Array arrayWithValue:1];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 1);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 1);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const int32_t kValues[] = { 1, 2, 3, 4 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertEqual([array valueAtIndex:1], 2);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+  XCTAssertEqual([array valueAtIndex:3], 4);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const int32_t kValues1[] = { 1, 2, 3 };
+  const int32_t kValues2[] = { 1, 4, 3 };
+  const int32_t kValues3[] = { 1, 2, 3, 4 };
+  GPBInt32Array *array1 =
+      [[GPBInt32Array alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBInt32Array *array1prime =
+      [[GPBInt32Array alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBInt32Array *array2 =
+      [[GPBInt32Array alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBInt32Array *array3 =
+      [[GPBInt32Array alloc] initWithValues:kValues3
+                                      count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const int32_t kValues[] = { 1, 2, 3, 4 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBInt32Array *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const int32_t kValues[] = { 1, 2, 3, 4 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBInt32Array *array2 = [GPBInt32Array arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBInt32Array *array = [GPBInt32Array array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:1];
+  XCTAssertEqual(array.count, 1U);
+
+  const int32_t kValues1[] = { 2, 3 };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const int32_t kValues2[] = { 4, 1 };
+  GPBInt32Array *array2 =
+      [[GPBInt32Array alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertEqual([array valueAtIndex:1], 2);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+  XCTAssertEqual([array valueAtIndex:3], 4);
+  XCTAssertEqual([array valueAtIndex:4], 1);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const int32_t kValues[] = { 1, 2, 3 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:4 atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:4 atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:4 atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:4 atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 4);
+  XCTAssertEqual([array valueAtIndex:1], 1);
+  XCTAssertEqual([array valueAtIndex:2], 4);
+  XCTAssertEqual([array valueAtIndex:3], 2);
+  XCTAssertEqual([array valueAtIndex:4], 3);
+  XCTAssertEqual([array valueAtIndex:5], 4);
+  [array release];
+}
+
+- (void)testRemove {
+  const int32_t kValues[] = { 4, 1, 2, 4, 3, 4 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 1);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertEqual([array valueAtIndex:1], 2);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kValues[] = { 1, 1, 3, 3 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:2];
+  [array replaceValueAtIndex:3 withValue:4];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertEqual([array valueAtIndex:1], 2);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+  XCTAssertEqual([array valueAtIndex:3], 4);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:4],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 1);
+  XCTAssertEqual([array valueAtIndex:1], 4);
+  XCTAssertEqual([array valueAtIndex:2], 3);
+  XCTAssertEqual([array valueAtIndex:3], 2);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 3);
+  XCTAssertEqual([array valueAtIndex:1], 4);
+  XCTAssertEqual([array valueAtIndex:2], 1);
+  XCTAssertEqual([array valueAtIndex:3], 2);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const int32_t kValues[] = { 1, 2, 3, 4 };
+  GPBInt32Array *array =
+      [[GPBInt32Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:4 atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(UInt32, uint32_t, 11U, 12U, 13U, 14U)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt32
+
+@interface GPBUInt32ArrayTests : XCTestCase
+@end
+
+@implementation GPBUInt32ArrayTests
+
+- (void)testEmpty {
+  GPBUInt32Array *array = [[GPBUInt32Array alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBUInt32Array *array = [GPBUInt32Array arrayWithValue:11U];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 11U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 11U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const uint32_t kValues[] = { 11U, 12U, 13U, 14U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertEqual([array valueAtIndex:1], 12U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+  XCTAssertEqual([array valueAtIndex:3], 14U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const uint32_t kValues1[] = { 11U, 12U, 13U };
+  const uint32_t kValues2[] = { 11U, 14U, 13U };
+  const uint32_t kValues3[] = { 11U, 12U, 13U, 14U };
+  GPBUInt32Array *array1 =
+      [[GPBUInt32Array alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBUInt32Array *array1prime =
+      [[GPBUInt32Array alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBUInt32Array *array2 =
+      [[GPBUInt32Array alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBUInt32Array *array3 =
+      [[GPBUInt32Array alloc] initWithValues:kValues3
+                                       count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const uint32_t kValues[] = { 11U, 12U, 13U, 14U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBUInt32Array *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const uint32_t kValues[] = { 11U, 12U, 13U, 14U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBUInt32Array *array2 = [GPBUInt32Array arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBUInt32Array *array = [GPBUInt32Array array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:11U];
+  XCTAssertEqual(array.count, 1U);
+
+  const uint32_t kValues1[] = { 12U, 13U };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const uint32_t kValues2[] = { 14U, 11U };
+  GPBUInt32Array *array2 =
+      [[GPBUInt32Array alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertEqual([array valueAtIndex:1], 12U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+  XCTAssertEqual([array valueAtIndex:3], 14U);
+  XCTAssertEqual([array valueAtIndex:4], 11U);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const uint32_t kValues[] = { 11U, 12U, 13U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:14U atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:14U atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:14U atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:14U atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 14U);
+  XCTAssertEqual([array valueAtIndex:1], 11U);
+  XCTAssertEqual([array valueAtIndex:2], 14U);
+  XCTAssertEqual([array valueAtIndex:3], 12U);
+  XCTAssertEqual([array valueAtIndex:4], 13U);
+  XCTAssertEqual([array valueAtIndex:5], 14U);
+  [array release];
+}
+
+- (void)testRemove {
+  const uint32_t kValues[] = { 14U, 11U, 12U, 14U, 13U, 14U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertEqual([array valueAtIndex:1], 12U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kValues[] = { 11U, 11U, 13U, 13U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:12U];
+  [array replaceValueAtIndex:3 withValue:14U];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertEqual([array valueAtIndex:1], 12U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+  XCTAssertEqual([array valueAtIndex:3], 14U);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:14U],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 11U);
+  XCTAssertEqual([array valueAtIndex:1], 14U);
+  XCTAssertEqual([array valueAtIndex:2], 13U);
+  XCTAssertEqual([array valueAtIndex:3], 12U);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 13U);
+  XCTAssertEqual([array valueAtIndex:1], 14U);
+  XCTAssertEqual([array valueAtIndex:2], 11U);
+  XCTAssertEqual([array valueAtIndex:3], 12U);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const uint32_t kValues[] = { 11U, 12U, 13U, 14U };
+  GPBUInt32Array *array =
+      [[GPBUInt32Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:14U atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(Int64, int64_t, 31LL, 32LL, 33LL, 34LL)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Int64
+
+@interface GPBInt64ArrayTests : XCTestCase
+@end
+
+@implementation GPBInt64ArrayTests
+
+- (void)testEmpty {
+  GPBInt64Array *array = [[GPBInt64Array alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBInt64Array *array = [GPBInt64Array arrayWithValue:31LL];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 31LL);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 31LL);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertEqual([array valueAtIndex:1], 32LL);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+  XCTAssertEqual([array valueAtIndex:3], 34LL);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const int64_t kValues1[] = { 31LL, 32LL, 33LL };
+  const int64_t kValues2[] = { 31LL, 34LL, 33LL };
+  const int64_t kValues3[] = { 31LL, 32LL, 33LL, 34LL };
+  GPBInt64Array *array1 =
+      [[GPBInt64Array alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBInt64Array *array1prime =
+      [[GPBInt64Array alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBInt64Array *array2 =
+      [[GPBInt64Array alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBInt64Array *array3 =
+      [[GPBInt64Array alloc] initWithValues:kValues3
+                                      count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBInt64Array *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBInt64Array *array2 = [GPBInt64Array arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBInt64Array *array = [GPBInt64Array array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:31LL];
+  XCTAssertEqual(array.count, 1U);
+
+  const int64_t kValues1[] = { 32LL, 33LL };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const int64_t kValues2[] = { 34LL, 31LL };
+  GPBInt64Array *array2 =
+      [[GPBInt64Array alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertEqual([array valueAtIndex:1], 32LL);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+  XCTAssertEqual([array valueAtIndex:3], 34LL);
+  XCTAssertEqual([array valueAtIndex:4], 31LL);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const int64_t kValues[] = { 31LL, 32LL, 33LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:34LL atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:34LL atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:34LL atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:34LL atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 34LL);
+  XCTAssertEqual([array valueAtIndex:1], 31LL);
+  XCTAssertEqual([array valueAtIndex:2], 34LL);
+  XCTAssertEqual([array valueAtIndex:3], 32LL);
+  XCTAssertEqual([array valueAtIndex:4], 33LL);
+  XCTAssertEqual([array valueAtIndex:5], 34LL);
+  [array release];
+}
+
+- (void)testRemove {
+  const int64_t kValues[] = { 34LL, 31LL, 32LL, 34LL, 33LL, 34LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertEqual([array valueAtIndex:1], 32LL);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kValues[] = { 31LL, 31LL, 33LL, 33LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:32LL];
+  [array replaceValueAtIndex:3 withValue:34LL];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertEqual([array valueAtIndex:1], 32LL);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+  XCTAssertEqual([array valueAtIndex:3], 34LL);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:34LL],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 31LL);
+  XCTAssertEqual([array valueAtIndex:1], 34LL);
+  XCTAssertEqual([array valueAtIndex:2], 33LL);
+  XCTAssertEqual([array valueAtIndex:3], 32LL);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 33LL);
+  XCTAssertEqual([array valueAtIndex:1], 34LL);
+  XCTAssertEqual([array valueAtIndex:2], 31LL);
+  XCTAssertEqual([array valueAtIndex:3], 32LL);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL };
+  GPBInt64Array *array =
+      [[GPBInt64Array alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:34LL atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(UInt64, uint64_t, 41ULL, 42ULL, 43ULL, 44ULL)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - UInt64
+
+@interface GPBUInt64ArrayTests : XCTestCase
+@end
+
+@implementation GPBUInt64ArrayTests
+
+- (void)testEmpty {
+  GPBUInt64Array *array = [[GPBUInt64Array alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBUInt64Array *array = [GPBUInt64Array arrayWithValue:41ULL];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 41ULL);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 41ULL);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertEqual([array valueAtIndex:1], 42ULL);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+  XCTAssertEqual([array valueAtIndex:3], 44ULL);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const uint64_t kValues1[] = { 41ULL, 42ULL, 43ULL };
+  const uint64_t kValues2[] = { 41ULL, 44ULL, 43ULL };
+  const uint64_t kValues3[] = { 41ULL, 42ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array1 =
+      [[GPBUInt64Array alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBUInt64Array *array1prime =
+      [[GPBUInt64Array alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBUInt64Array *array2 =
+      [[GPBUInt64Array alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBUInt64Array *array3 =
+      [[GPBUInt64Array alloc] initWithValues:kValues3
+                                       count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBUInt64Array *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBUInt64Array *array2 = [GPBUInt64Array arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBUInt64Array *array = [GPBUInt64Array array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:41ULL];
+  XCTAssertEqual(array.count, 1U);
+
+  const uint64_t kValues1[] = { 42ULL, 43ULL };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const uint64_t kValues2[] = { 44ULL, 41ULL };
+  GPBUInt64Array *array2 =
+      [[GPBUInt64Array alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertEqual([array valueAtIndex:1], 42ULL);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+  XCTAssertEqual([array valueAtIndex:3], 44ULL);
+  XCTAssertEqual([array valueAtIndex:4], 41ULL);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:44ULL atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:44ULL atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:44ULL atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:44ULL atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 44ULL);
+  XCTAssertEqual([array valueAtIndex:1], 41ULL);
+  XCTAssertEqual([array valueAtIndex:2], 44ULL);
+  XCTAssertEqual([array valueAtIndex:3], 42ULL);
+  XCTAssertEqual([array valueAtIndex:4], 43ULL);
+  XCTAssertEqual([array valueAtIndex:5], 44ULL);
+  [array release];
+}
+
+- (void)testRemove {
+  const uint64_t kValues[] = { 44ULL, 41ULL, 42ULL, 44ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertEqual([array valueAtIndex:1], 42ULL);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kValues[] = { 41ULL, 41ULL, 43ULL, 43ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:42ULL];
+  [array replaceValueAtIndex:3 withValue:44ULL];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertEqual([array valueAtIndex:1], 42ULL);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+  XCTAssertEqual([array valueAtIndex:3], 44ULL);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:44ULL],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 41ULL);
+  XCTAssertEqual([array valueAtIndex:1], 44ULL);
+  XCTAssertEqual([array valueAtIndex:2], 43ULL);
+  XCTAssertEqual([array valueAtIndex:3], 42ULL);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 43ULL);
+  XCTAssertEqual([array valueAtIndex:1], 44ULL);
+  XCTAssertEqual([array valueAtIndex:2], 41ULL);
+  XCTAssertEqual([array valueAtIndex:3], 42ULL);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL };
+  GPBUInt64Array *array =
+      [[GPBUInt64Array alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:44ULL atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(Float, float, 51.f, 52.f, 53.f, 54.f)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Float
+
+@interface GPBFloatArrayTests : XCTestCase
+@end
+
+@implementation GPBFloatArrayTests
+
+- (void)testEmpty {
+  GPBFloatArray *array = [[GPBFloatArray alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBFloatArray *array = [GPBFloatArray arrayWithValue:51.f];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 51.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 51.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const float kValues[] = { 51.f, 52.f, 53.f, 54.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertEqual([array valueAtIndex:1], 52.f);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+  XCTAssertEqual([array valueAtIndex:3], 54.f);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(float value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const float kValues1[] = { 51.f, 52.f, 53.f };
+  const float kValues2[] = { 51.f, 54.f, 53.f };
+  const float kValues3[] = { 51.f, 52.f, 53.f, 54.f };
+  GPBFloatArray *array1 =
+      [[GPBFloatArray alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBFloatArray *array1prime =
+      [[GPBFloatArray alloc] initWithValues:kValues1
+                                      count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBFloatArray *array2 =
+      [[GPBFloatArray alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBFloatArray *array3 =
+      [[GPBFloatArray alloc] initWithValues:kValues3
+                                      count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const float kValues[] = { 51.f, 52.f, 53.f, 54.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBFloatArray *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const float kValues[] = { 51.f, 52.f, 53.f, 54.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBFloatArray *array2 = [GPBFloatArray arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBFloatArray *array = [GPBFloatArray array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:51.f];
+  XCTAssertEqual(array.count, 1U);
+
+  const float kValues1[] = { 52.f, 53.f };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const float kValues2[] = { 54.f, 51.f };
+  GPBFloatArray *array2 =
+      [[GPBFloatArray alloc] initWithValues:kValues2
+                                      count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertEqual([array valueAtIndex:1], 52.f);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+  XCTAssertEqual([array valueAtIndex:3], 54.f);
+  XCTAssertEqual([array valueAtIndex:4], 51.f);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const float kValues[] = { 51.f, 52.f, 53.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:54.f atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:54.f atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:54.f atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:54.f atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 54.f);
+  XCTAssertEqual([array valueAtIndex:1], 51.f);
+  XCTAssertEqual([array valueAtIndex:2], 54.f);
+  XCTAssertEqual([array valueAtIndex:3], 52.f);
+  XCTAssertEqual([array valueAtIndex:4], 53.f);
+  XCTAssertEqual([array valueAtIndex:5], 54.f);
+  [array release];
+}
+
+- (void)testRemove {
+  const float kValues[] = { 54.f, 51.f, 52.f, 54.f, 53.f, 54.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertEqual([array valueAtIndex:1], 52.f);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const float kValues[] = { 51.f, 51.f, 53.f, 53.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:52.f];
+  [array replaceValueAtIndex:3 withValue:54.f];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertEqual([array valueAtIndex:1], 52.f);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+  XCTAssertEqual([array valueAtIndex:3], 54.f);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:54.f],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 51.f);
+  XCTAssertEqual([array valueAtIndex:1], 54.f);
+  XCTAssertEqual([array valueAtIndex:2], 53.f);
+  XCTAssertEqual([array valueAtIndex:3], 52.f);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 53.f);
+  XCTAssertEqual([array valueAtIndex:1], 54.f);
+  XCTAssertEqual([array valueAtIndex:2], 51.f);
+  XCTAssertEqual([array valueAtIndex:3], 52.f);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const float kValues[] = { 51.f, 52.f, 53.f, 54.f };
+  GPBFloatArray *array =
+      [[GPBFloatArray alloc] initWithValues:kValues
+                                      count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:54.f atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(Double, double, 61., 62., 63., 64.)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Double
+
+@interface GPBDoubleArrayTests : XCTestCase
+@end
+
+@implementation GPBDoubleArrayTests
+
+- (void)testEmpty {
+  GPBDoubleArray *array = [[GPBDoubleArray alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBDoubleArray *array = [GPBDoubleArray arrayWithValue:61.];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 61.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 61.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const double kValues[] = { 61., 62., 63., 64. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertEqual([array valueAtIndex:1], 62.);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+  XCTAssertEqual([array valueAtIndex:3], 64.);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(double value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const double kValues1[] = { 61., 62., 63. };
+  const double kValues2[] = { 61., 64., 63. };
+  const double kValues3[] = { 61., 62., 63., 64. };
+  GPBDoubleArray *array1 =
+      [[GPBDoubleArray alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBDoubleArray *array1prime =
+      [[GPBDoubleArray alloc] initWithValues:kValues1
+                                       count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBDoubleArray *array2 =
+      [[GPBDoubleArray alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBDoubleArray *array3 =
+      [[GPBDoubleArray alloc] initWithValues:kValues3
+                                       count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const double kValues[] = { 61., 62., 63., 64. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBDoubleArray *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const double kValues[] = { 61., 62., 63., 64. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBDoubleArray *array2 = [GPBDoubleArray arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBDoubleArray *array = [GPBDoubleArray array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:61.];
+  XCTAssertEqual(array.count, 1U);
+
+  const double kValues1[] = { 62., 63. };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const double kValues2[] = { 64., 61. };
+  GPBDoubleArray *array2 =
+      [[GPBDoubleArray alloc] initWithValues:kValues2
+                                       count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertEqual([array valueAtIndex:1], 62.);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+  XCTAssertEqual([array valueAtIndex:3], 64.);
+  XCTAssertEqual([array valueAtIndex:4], 61.);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const double kValues[] = { 61., 62., 63. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:64. atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:64. atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:64. atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:64. atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 64.);
+  XCTAssertEqual([array valueAtIndex:1], 61.);
+  XCTAssertEqual([array valueAtIndex:2], 64.);
+  XCTAssertEqual([array valueAtIndex:3], 62.);
+  XCTAssertEqual([array valueAtIndex:4], 63.);
+  XCTAssertEqual([array valueAtIndex:5], 64.);
+  [array release];
+}
+
+- (void)testRemove {
+  const double kValues[] = { 64., 61., 62., 64., 63., 64. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertEqual([array valueAtIndex:1], 62.);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const double kValues[] = { 61., 61., 63., 63. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:62.];
+  [array replaceValueAtIndex:3 withValue:64.];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertEqual([array valueAtIndex:1], 62.);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+  XCTAssertEqual([array valueAtIndex:3], 64.);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:64.],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 61.);
+  XCTAssertEqual([array valueAtIndex:1], 64.);
+  XCTAssertEqual([array valueAtIndex:2], 63.);
+  XCTAssertEqual([array valueAtIndex:3], 62.);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 63.);
+  XCTAssertEqual([array valueAtIndex:1], 64.);
+  XCTAssertEqual([array valueAtIndex:2], 61.);
+  XCTAssertEqual([array valueAtIndex:3], 62.);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const double kValues[] = { 61., 62., 63., 64. };
+  GPBDoubleArray *array =
+      [[GPBDoubleArray alloc] initWithValues:kValues
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:64. atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS(Bool, BOOL, TRUE, TRUE, FALSE, FALSE)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool
+
+@interface GPBBoolArrayTests : XCTestCase
+@end
+
+@implementation GPBBoolArrayTests
+
+- (void)testEmpty {
+  GPBBoolArray *array = [[GPBBoolArray alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBBoolArray *array = [GPBBoolArray arrayWithValue:TRUE];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, TRUE);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, TRUE);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertEqual([array valueAtIndex:1], TRUE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+  XCTAssertEqual([array valueAtIndex:3], FALSE);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const BOOL kValues1[] = { TRUE, TRUE, FALSE };
+  const BOOL kValues2[] = { TRUE, FALSE, FALSE };
+  const BOOL kValues3[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array1 =
+      [[GPBBoolArray alloc] initWithValues:kValues1
+                                     count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBBoolArray *array1prime =
+      [[GPBBoolArray alloc] initWithValues:kValues1
+                                     count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBBoolArray *array2 =
+      [[GPBBoolArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBBoolArray *array3 =
+      [[GPBBoolArray alloc] initWithValues:kValues3
+                                     count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBBoolArray *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBBoolArray *array2 = [GPBBoolArray arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBBoolArray *array = [GPBBoolArray array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:TRUE];
+  XCTAssertEqual(array.count, 1U);
+
+  const BOOL kValues1[] = { TRUE, FALSE };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const BOOL kValues2[] = { FALSE, TRUE };
+  GPBBoolArray *array2 =
+      [[GPBBoolArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertEqual([array valueAtIndex:1], TRUE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+  XCTAssertEqual([array valueAtIndex:3], FALSE);
+  XCTAssertEqual([array valueAtIndex:4], TRUE);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const BOOL kValues[] = { TRUE, TRUE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:FALSE atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:FALSE atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:FALSE atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:FALSE atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], FALSE);
+  XCTAssertEqual([array valueAtIndex:1], TRUE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+  XCTAssertEqual([array valueAtIndex:3], TRUE);
+  XCTAssertEqual([array valueAtIndex:4], FALSE);
+  XCTAssertEqual([array valueAtIndex:5], FALSE);
+  [array release];
+}
+
+- (void)testRemove {
+  const BOOL kValues[] = { FALSE, TRUE, TRUE, FALSE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertEqual([array valueAtIndex:1], TRUE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:TRUE];
+  [array replaceValueAtIndex:3 withValue:FALSE];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertEqual([array valueAtIndex:1], TRUE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+  XCTAssertEqual([array valueAtIndex:3], FALSE);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:FALSE],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], TRUE);
+  XCTAssertEqual([array valueAtIndex:1], FALSE);
+  XCTAssertEqual([array valueAtIndex:2], FALSE);
+  XCTAssertEqual([array valueAtIndex:3], TRUE);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], FALSE);
+  XCTAssertEqual([array valueAtIndex:1], FALSE);
+  XCTAssertEqual([array valueAtIndex:2], TRUE);
+  XCTAssertEqual([array valueAtIndex:3], TRUE);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE };
+  GPBBoolArray *array =
+      [[GPBBoolArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:FALSE atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND ARRAY_TESTS2(Enum, int32_t, 71, 72, 73, 74, Raw)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Enum
+
+@interface GPBEnumArrayTests : XCTestCase
+@end
+
+@implementation GPBEnumArrayTests
+
+- (void)testEmpty {
+  GPBEnumArray *array = [[GPBEnumArray alloc] init];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    #pragma unused(value, idx, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [array release];
+}
+
+- (void)testOne {
+  GPBEnumArray *array = [GPBEnumArray arrayWithValue:71];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 1U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException);
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 71);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, 0U);
+    XCTAssertEqual(value, 71);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  static const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 72);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+  XCTAssertEqual([array valueAtIndex:3], 74);
+  XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const int32_t kValues1[] = { 71, 72, 73 };
+  const int32_t kValues2[] = { 71, 74, 73 };
+  const int32_t kValues3[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array1 =
+      [[GPBEnumArray alloc] initWithValues:kValues1
+                                     count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBEnumArray *array1prime =
+      [[GPBEnumArray alloc] initWithValues:kValues1
+                                     count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBEnumArray *array2 =
+      [[GPBEnumArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBEnumArray *array3 =
+      [[GPBEnumArray alloc] initWithValues:kValues3
+                                     count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBEnumArray *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  [array release];
+}
+
+- (void)testAdds {
+  GPBEnumArray *array = [GPBEnumArray array];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addValue:71];
+  XCTAssertEqual(array.count, 1U);
+
+  const int32_t kValues1[] = { 72, 73 };
+  [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const int32_t kValues2[] = { 74, 71 };
+  GPBEnumArray *array2 =
+      [[GPBEnumArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addRawValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 72);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+  XCTAssertEqual([array valueAtIndex:3], 74);
+  XCTAssertEqual([array valueAtIndex:4], 71);
+  [array2 release];
+}
+
+- (void)testInsert {
+  const int32_t kValues[] = { 71, 72, 73 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertValue:74 atIndex:0];
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertValue:74 atIndex:2];
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertValue:74 atIndex:5];
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertValue:74 atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array valueAtIndex:0], 74);
+  XCTAssertEqual([array valueAtIndex:1], 71);
+  XCTAssertEqual([array valueAtIndex:2], 74);
+  XCTAssertEqual([array valueAtIndex:3], 72);
+  XCTAssertEqual([array valueAtIndex:4], 73);
+  XCTAssertEqual([array valueAtIndex:5], 74);
+  [array release];
+}
+
+- (void)testRemove {
+  const int32_t kValues[] = { 74, 71, 72, 74, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 6U);
+
+  // First
+  [array removeValueAtIndex:0];
+  XCTAssertEqual(array.count, 5U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+
+  // Middle
+  [array removeValueAtIndex:2];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+
+  // End
+  [array removeValueAtIndex:3];
+  XCTAssertEqual(array.count, 3U);
+
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 72);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3],
+                               NSException, NSRangeException);
+
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kValues[] = { 71, 71, 73, 73 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withValue:72];
+  [array replaceValueAtIndex:3 withValue:74];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 72);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+  XCTAssertEqual([array valueAtIndex:3], 74);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:74],
+                               NSException, NSRangeException);
+
+  [array exchangeValueAtIndex:1 withValueAtIndex:3];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 74);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+  XCTAssertEqual([array valueAtIndex:3], 72);
+
+  [array exchangeValueAtIndex:2 withValueAtIndex:0];
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 73);
+  XCTAssertEqual([array valueAtIndex:1], 74);
+  XCTAssertEqual([array valueAtIndex:2], 71);
+  XCTAssertEqual([array valueAtIndex:3], 72);
+
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1],
+                               NSException, NSRangeException);
+  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testInternalResizing {
+  const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertValue:74 atIndex:(i * 3)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
+
+//%PDDM-EXPAND-END (8 expansions)
+
+#pragma mark - Non macro-based Enum tests
+
+// These are hand written tests to cover the verification and raw methods.
+
+@interface GPBEnumArrayCustomTests : XCTestCase
+@end
+
+@implementation GPBEnumArrayCustomTests
+
+- (void)testRawBasics {
+  static const int32_t kValues[] = { 71, 272, 73, 374 };
+  static const int32_t kValuesFiltered[] = {
+      71, kGPBUnrecognizedEnumeratorValue, 73, kGPBUnrecognizedEnumeratorValue
+  };
+  XCTAssertEqual(GPBARRAYSIZE(kValues), GPBARRAYSIZE(kValuesFiltered));
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 4U);
+  GPBEnumValidationFunc func = TestingEnum_IsValidValue;
+  XCTAssertEqual(array.validationFunc, func);
+  XCTAssertEqual([array rawValueAtIndex:0], 71);
+  XCTAssertEqual([array rawValueAtIndex:1], 272);
+  XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:2], 73);
+  XCTAssertEqual([array rawValueAtIndex:3], 374);
+  XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertThrowsSpecificNamed([array rawValueAtIndex:4], NSException, NSRangeException);
+  __block NSUInteger idx2 = 0;
+  [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValuesFiltered[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateRawValuesWithOptions:NSEnumerationReverse
+                            usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateValuesWithOptions:NSEnumerationReverse
+                         usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValuesFiltered[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    ++idx2;
+  }];
+  // Stopping the enumeration.
+  idx2 = 0;
+  [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, idx2);
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    XCTAssertNotEqual(idx, 3U);
+    ++idx2;
+  }];
+  idx2 = 0;
+  [array enumerateRawValuesWithOptions:NSEnumerationReverse
+                            usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
+    XCTAssertEqual(idx, (3 - idx2));
+    XCTAssertEqual(value, kValues[idx]);
+    XCTAssertNotEqual(stop, NULL);
+    if (idx2 == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 1U);
+    XCTAssertNotEqual(idx, 0U);
+    ++idx2;
+  }];
+  [array release];
+}
+
+- (void)testEquality {
+  const int32_t kValues1[] = { 71, 72, 173 };  // With unknown value
+  const int32_t kValues2[] = { 71, 74, 173 };  // With unknown value
+  const int32_t kValues3[] = { 71, 72, 173, 74 };  // With unknown value
+  GPBEnumArray *array1 =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1);
+  GPBEnumArray *array1prime =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue2
+                                             rawValues:kValues1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(array1prime);
+  GPBEnumArray *array2 =
+      [[GPBEnumArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  GPBEnumArray *array3 =
+      [[GPBEnumArray alloc] initWithValues:kValues3
+                                     count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(array3);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(array1, array1prime);
+  XCTAssertEqualObjects(array1, array1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([array1 hash], [array1prime hash]);
+  // But different validation functions.
+  XCTAssertNotEqual(array1.validationFunc, array1prime.validationFunc);
+
+  // 1/2/3 shouldn't be equal.
+  XCTAssertNotEqualObjects(array1, array2);
+  XCTAssertNotEqualObjects(array1, array3);
+  XCTAssertNotEqualObjects(array2, array3);
+
+  [array1 release];
+  [array1prime release];
+  [array2 release];
+  [array3 release];
+}
+
+- (void)testCopy {
+  const int32_t kValues[] = { 71, 72 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array addRawValue:1000]; // Unknown
+  XCTAssertEqual(array.count, 3U);
+  XCTAssertEqual([array rawValueAtIndex:0], 71);
+  XCTAssertEqual([array rawValueAtIndex:1], 72);
+  XCTAssertEqual([array rawValueAtIndex:2], 1000);
+  XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
+
+  GPBEnumArray *array2 = [array copy];
+  XCTAssertNotNil(array2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  XCTAssertEqual(array.validationFunc, array2.validationFunc);
+  XCTAssertTrue([array2 isKindOfClass:[GPBEnumArray class]]);
+  XCTAssertEqual(array2.count, 3U);
+  XCTAssertEqual([array2 rawValueAtIndex:0], 71);
+  XCTAssertEqual([array2 rawValueAtIndex:1], 72);
+  XCTAssertEqual([array2 rawValueAtIndex:2], 1000);
+  XCTAssertEqual([array2 valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
+  [array2 release];
+  [array release];
+}
+
+- (void)testArrayFromArray {
+  const int32_t kValues[] = { 71, 172, 173, 74 };  // Unknowns
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array];
+  XCTAssertNotNil(array2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(array, array2);
+  XCTAssertEqualObjects(array, array2);
+  XCTAssertEqual(array.validationFunc, array2.validationFunc);
+  [array release];
+}
+
+- (void)testUnknownAdds {
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(array);
+
+  XCTAssertThrowsSpecificNamed([array addValue:172],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 0U);
+
+  const int32_t kValues1[] = { 172, 173 };  // Unknown
+  XCTAssertThrowsSpecificNamed([array addValues:kValues1 count:GPBARRAYSIZE(kValues1)],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+- (void)testRawAdds {
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(array);
+
+  XCTAssertEqual(array.count, 0U);
+  [array addRawValue:71];  // Valid
+  XCTAssertEqual(array.count, 1U);
+
+  const int32_t kValues1[] = { 172, 173 };  // Unknown
+  [array addRawValues:kValues1 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertEqual(array.count, 3U);
+
+  const int32_t kValues2[] = { 74, 71 };
+  GPBEnumArray *array2 =
+      [[GPBEnumArray alloc] initWithValues:kValues2
+                                     count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(array2);
+  [array addRawValuesFromArray:array2];
+  XCTAssertEqual(array.count, 5U);
+
+  XCTAssertEqual([array rawValueAtIndex:0], 71);
+  XCTAssertEqual([array rawValueAtIndex:1], 172);
+  XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:2], 173);
+  XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:3], 74);
+  XCTAssertEqual([array rawValueAtIndex:4], 71);
+  [array release];
+}
+
+- (void)testUnknownInserts {
+  const int32_t kValues[] = { 71, 72, 73 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  XCTAssertThrowsSpecificNamed([array insertValue:174 atIndex:0],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 3U);
+
+  // Middle
+  XCTAssertThrowsSpecificNamed([array insertValue:274 atIndex:1],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 3U);
+
+  // End
+  XCTAssertThrowsSpecificNamed([array insertValue:374 atIndex:3],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 3U);
+  [array release];
+}
+
+- (void)testRawInsert {
+  const int32_t kValues[] = { 71, 72, 73 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+  XCTAssertEqual(array.count, 3U);
+
+  // First
+  [array insertRawValue:174 atIndex:0];  // Unknown
+  XCTAssertEqual(array.count, 4U);
+
+  // Middle
+  [array insertRawValue:274 atIndex:2];  // Unknown
+  XCTAssertEqual(array.count, 5U);
+
+  // End
+  [array insertRawValue:374 atIndex:5];  // Unknown
+  XCTAssertEqual(array.count, 6U);
+
+  // Too far.
+  XCTAssertThrowsSpecificNamed([array insertRawValue:74 atIndex:7],
+                               NSException, NSRangeException);
+
+  XCTAssertEqual([array rawValueAtIndex:0], 174);
+  XCTAssertEqual([array valueAtIndex:0], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:1], 71);
+  XCTAssertEqual([array rawValueAtIndex:2], 274);
+  XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:3], 72);
+  XCTAssertEqual([array rawValueAtIndex:4], 73);
+  XCTAssertEqual([array rawValueAtIndex:5], 374);
+  XCTAssertEqual([array valueAtIndex:5], kGPBUnrecognizedEnumeratorValue);
+  [array release];
+}
+
+- (void)testUnknownInplaceMutation {
+  const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:1 withValue:172],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:3 withValue:274],
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array valueAtIndex:0], 71);
+  XCTAssertEqual([array valueAtIndex:1], 72);
+  XCTAssertEqual([array valueAtIndex:2], 73);
+  XCTAssertEqual([array valueAtIndex:3], 74);
+  [array release];
+}
+
+
+- (void)testRawInplaceMutation {
+  const int32_t kValues[] = { 71, 72, 73, 74 };
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                             rawValues:kValues
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  [array replaceValueAtIndex:1 withRawValue:172];  // Unknown
+  [array replaceValueAtIndex:3 withRawValue:274];  // Unknown
+  XCTAssertEqual(array.count, 4U);
+  XCTAssertEqual([array rawValueAtIndex:0], 71);
+  XCTAssertEqual([array rawValueAtIndex:1], 172);
+  XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([array rawValueAtIndex:2], 73);
+  XCTAssertEqual([array rawValueAtIndex:3], 274);
+  XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue);
+
+  XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withRawValue:74],
+                               NSException, NSRangeException);
+  [array release];
+}
+
+- (void)testRawInternalResizing {
+  const int32_t kValues[] = { 71, 172, 173, 74 };  // Unknown
+  GPBEnumArray *array =
+      [[GPBEnumArray alloc] initWithValues:kValues
+                                     count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(array);
+
+  // Add/remove to trigger the intneral buffer to grow/shrink.
+  for (int i = 0; i < 100; ++i) {
+    [array addRawValues:kValues count:GPBARRAYSIZE(kValues)];
+  }
+  XCTAssertEqual(array.count, 404U);
+  for (int i = 0; i < 100; ++i) {
+    [array removeValueAtIndex:(i * 2)];
+  }
+  XCTAssertEqual(array.count, 304U);
+  for (int i = 0; i < 100; ++i) {
+    [array insertRawValue:274 atIndex:(i * 3)];  // Unknown
+  }
+  XCTAssertEqual(array.count, 404U);
+  [array removeAll];
+  XCTAssertEqual(array.count, 0U);
+  [array release];
+}
+
+@end
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
new file mode 100644
index 0000000..cc40215
--- /dev/null
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -0,0 +1,335 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import "GPBCodedInputStream.h"
+#import "GPBCodedOutputStream.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "GPBUtilities_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+
+@interface CodedInputStreamTests : GPBTestCase
+@end
+
+@implementation CodedInputStreamTests
+
+- (NSData*)bytes_with_sentinel:(int32_t)unused, ... {
+  va_list list;
+  va_start(list, unused);
+
+  NSMutableData* values = [NSMutableData dataWithCapacity:0];
+  int32_t i;
+
+  while ((i = va_arg(list, int32_t)) != 256) {
+    NSAssert(i >= 0 && i < 256, @"");
+    uint8_t u = (uint8_t)i;
+    [values appendBytes:&u length:1];
+  }
+
+  va_end(list);
+
+  return values;
+}
+
+#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256]
+
+- (void)testDecodeZigZag {
+  XCTAssertEqual(0, GPBDecodeZigZag32(0));
+  XCTAssertEqual(-1, GPBDecodeZigZag32(1));
+  XCTAssertEqual(1, GPBDecodeZigZag32(2));
+  XCTAssertEqual(-2, GPBDecodeZigZag32(3));
+  XCTAssertEqual((int32_t)0x3FFFFFFF, GPBDecodeZigZag32(0x7FFFFFFE));
+  XCTAssertEqual((int32_t)0xC0000000, GPBDecodeZigZag32(0x7FFFFFFF));
+  XCTAssertEqual((int32_t)0x7FFFFFFF, GPBDecodeZigZag32(0xFFFFFFFE));
+  XCTAssertEqual((int32_t)0x80000000, GPBDecodeZigZag32(0xFFFFFFFF));
+
+  XCTAssertEqual((int64_t)0, GPBDecodeZigZag64(0));
+  XCTAssertEqual((int64_t)-1, GPBDecodeZigZag64(1));
+  XCTAssertEqual((int64_t)1, GPBDecodeZigZag64(2));
+  XCTAssertEqual((int64_t)-2, GPBDecodeZigZag64(3));
+  XCTAssertEqual((int64_t)0x000000003FFFFFFFL,
+                 GPBDecodeZigZag64(0x000000007FFFFFFEL));
+  XCTAssertEqual((int64_t)0xFFFFFFFFC0000000L,
+                 GPBDecodeZigZag64(0x000000007FFFFFFFL));
+  XCTAssertEqual((int64_t)0x000000007FFFFFFFL,
+                 GPBDecodeZigZag64(0x00000000FFFFFFFEL));
+  XCTAssertEqual((int64_t)0xFFFFFFFF80000000L,
+                 GPBDecodeZigZag64(0x00000000FFFFFFFFL));
+  XCTAssertEqual((int64_t)0x7FFFFFFFFFFFFFFFL,
+                 GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+  XCTAssertEqual((int64_t)0x8000000000000000L,
+                 GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+}
+
+- (void)assertReadVarint:(NSData*)data value:(int64_t)value {
+  {
+    GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+    XCTAssertEqual((int32_t)value, [input readInt32]);
+  }
+  {
+    GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+    XCTAssertEqual(value, [input readInt64]);
+  }
+}
+
+- (void)assertReadLittleEndian32:(NSData*)data value:(int32_t)value {
+  GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+  XCTAssertEqual(value, [input readSFixed32]);
+}
+
+- (void)assertReadLittleEndian64:(NSData*)data value:(int64_t)value {
+  GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+  XCTAssertEqual(value, [input readSFixed64]);
+}
+
+- (void)assertReadVarintFailure:(NSData*)data {
+  {
+    GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+    XCTAssertThrows([input readInt32]);
+  }
+  {
+    GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+    XCTAssertThrows([input readInt64]);
+  }
+}
+
+- (void)testBytes {
+  NSData* data = bytes(0xa2, 0x74);
+  XCTAssertEqual(data.length, (NSUInteger)2);
+  XCTAssertEqual(((uint8_t*)data.bytes)[0], (uint8_t)0xa2);
+  XCTAssertEqual(((uint8_t*)data.bytes)[1], (uint8_t)0x74);
+}
+
+- (void)testReadVarint {
+  [self assertReadVarint:bytes(0x00) value:0];
+  [self assertReadVarint:bytes(0x01) value:1];
+  [self assertReadVarint:bytes(0x7f) value:127];
+  // 14882
+  [self assertReadVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)];
+  // 2961488830
+  [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b)
+                   value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
+                         (0x04 << 21) | (0x0bLL << 28)];
+
+  // 64-bit
+  // 7256456126
+  [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b)
+                   value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
+                         (0x04 << 21) | (0x1bLL << 28)];
+  // 41256202580718336
+  [self assertReadVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49)
+                   value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) |
+                         (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) |
+                         (0x24LL << 42) | (0x49LL << 49)];
+  // 11964378330978735131
+  [self
+      assertReadVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85,
+                             0xa6, 0x01)
+                 value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+                       (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) |
+                       (0x05LL << 49) | (0x26LL << 56) | (0x01LL << 63)];
+
+  // Failures
+  [self assertReadVarintFailure:bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+                                      0x80, 0x80, 0x80, 0x00)];
+  [self assertReadVarintFailure:bytes(0x80)];
+}
+
+- (void)testReadLittleEndian {
+  [self assertReadLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12)
+                           value:0x12345678];
+  [self assertReadLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a)
+                           value:0x9abcdef0];
+
+  [self assertReadLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
+                                       0x12)
+                           value:0x123456789abcdef0LL];
+  [self assertReadLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
+                                       0x9a)
+                           value:0x9abcdef012345678LL];
+}
+
+- (void)testReadWholeMessage {
+  TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+
+  NSData* rawBytes = message.data;
+  XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
+
+  TestAllTypes* message2 =
+      [TestAllTypes parseFromData:rawBytes extensionRegistry:nil error:NULL];
+  [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testSkipWholeMessage {
+  TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes = message.data;
+
+  // Create two parallel inputs.  Parse one as unknown fields while using
+  // skipField() to skip each field on the other.  Expect the same tags.
+  GPBCodedInputStream* input1 = [GPBCodedInputStream streamWithData:rawBytes];
+  GPBCodedInputStream* input2 = [GPBCodedInputStream streamWithData:rawBytes];
+  GPBUnknownFieldSet* unknownFields =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+
+  while (YES) {
+    int32_t tag = [input1 readTag];
+    XCTAssertEqual(tag, [input2 readTag]);
+    if (tag == 0) {
+      break;
+    }
+    [unknownFields mergeFieldFrom:tag input:input1];
+    [input2 skipField:tag];
+  }
+}
+
+- (void)testReadHugeBlob {
+  // Allocate and initialize a 1MB blob.
+  NSMutableData* blob = [NSMutableData dataWithLength:1 << 20];
+  for (NSUInteger i = 0; i < blob.length; i++) {
+    ((uint8_t*)blob.mutableBytes)[i] = (uint8_t)i;
+  }
+
+  // Make a message containing it.
+  TestAllTypes* message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [message setOptionalBytes:blob];
+
+  // Serialize and parse it.  Make sure to parse from an InputStream, not
+  // directly from a ByteString, so that CodedInputStream uses buffered
+  // reading.
+  NSData *messageData = message.data;
+  XCTAssertNotNil(messageData);
+  GPBCodedInputStream* stream =
+      [GPBCodedInputStream streamWithData:messageData];
+  TestAllTypes* message2 = [TestAllTypes parseFromCodedInputStream:stream
+                                                 extensionRegistry:nil
+                                                             error:NULL];
+
+  XCTAssertEqualObjects(message.optionalBytes, message2.optionalBytes);
+
+  // Make sure all the other fields were parsed correctly.
+  TestAllTypes* message3 = [[message2 copy] autorelease];
+  TestAllTypes* types = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* data = [types optionalBytes];
+  [message3 setOptionalBytes:data];
+
+  [self assertAllFieldsSet:message3 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testReadMaliciouslyLargeBlob {
+  NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+  GPBCodedOutputStream* output =
+      [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+
+  int32_t tag = GPBWireFormatMakeTag(1, GPBWireFormatLengthDelimited);
+  [output writeRawVarint32:tag];
+  [output writeRawVarint32:0x7FFFFFFF];
+  uint8_t bytes[32] = {0};
+  [output writeRawData:[NSData dataWithBytes:bytes length:32]];
+  [output flush];
+
+  NSData* data =
+      [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+  GPBCodedInputStream* input =
+      [GPBCodedInputStream streamWithData:[NSMutableData dataWithData:data]];
+  XCTAssertEqual(tag, [input readTag]);
+
+  XCTAssertThrows([input readBytes]);
+}
+
+// Verifies fix for b/10315336.
+// Note: Now that there isn't a custom string class under the hood, this test
+// isn't as critical, but it does cover bad input and if a custom class is added
+// again, it will help validate that class' handing of bad utf8.
+- (void)testReadMalformedString {
+  NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+  GPBCodedOutputStream* output =
+      [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+
+  int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString,
+                                     GPBWireFormatLengthDelimited);
+  [output writeRawVarint32:tag];
+  [output writeRawVarint32:5];
+  // Create an invalid utf-8 byte array.
+  uint8_t bytes[] = {0xc2, 0xf2, 0x0, 0x0, 0x0};
+  [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]];
+  [output flush];
+
+  NSData *data =
+      [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+  GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+  NSError *error = nil;
+  TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
+                                                extensionRegistry:nil
+                                                            error:&error];
+  XCTAssertNotNil(error);
+  XCTAssertNil(message);
+}
+
+- (void)testBOMWithinStrings {
+  // We've seen servers that end up with BOMs within strings (not always at the
+  // start, and sometimes in multiple places), make sure they always parse
+  // correctly. (Again, this is inpart incase a custom string class is ever
+  // used again.)
+  const char* strs[] = {
+    "\xEF\xBB\xBF String with BOM",
+    "String with \xEF\xBB\xBF in middle",
+    "String with end bom \xEF\xBB\xBF",
+    "\xEF\xBB\xBF\xe2\x99\xa1",  // BOM White Heart
+    "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM",
+  };
+  for (size_t i = 0; i < GPBARRAYSIZE(strs); ++i) {
+    NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+    GPBCodedOutputStream* output =
+        [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+
+    int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString,
+                                       GPBWireFormatLengthDelimited);
+    [output writeRawVarint32:tag];
+    size_t length = strlen(strs[i]);
+    [output writeRawVarint32:(int32_t)length];
+    [output writeRawData:[NSData dataWithBytes:strs[i] length:length]];
+    [output flush];
+
+    NSData* data =
+        [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+    TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
+                                                  extensionRegistry:nil
+                                                              error:NULL];
+    XCTAssertNotNil(message, @"Loop %zd", i);
+    // Ensure the string is there. NSString can consume the BOM in some
+    // cases, so don't actually check the string for exact equality.
+    XCTAssertTrue(message.defaultString.length > 0, @"Loop %zd", i);
+  }
+}
+
+@end
diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m
new file mode 100644
index 0000000..0723b64
--- /dev/null
+++ b/objectivec/Tests/GPBCodedOuputStreamTests.m
@@ -0,0 +1,340 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import "GPBCodedOutputStream_PackagePrivate.h"
+#import "GPBCodedInputStream.h"
+#import "GPBUtilities_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+
+@interface GPBCodedOutputStream (InternalMethods)
+// Declared in the .m file, expose for testing.
+- (instancetype)initWithOutputStream:(NSOutputStream *)output
+                                data:(NSMutableData *)data;
+@end
+
+@interface GPBCodedOutputStream (Helper)
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output
+                            bufferSize:(size_t)bufferSize;
+@end
+
+@implementation GPBCodedOutputStream (Helper)
++ (instancetype)streamWithOutputStream:(NSOutputStream *)output
+                            bufferSize:(size_t)bufferSize {
+  NSMutableData *data = [NSMutableData dataWithLength:bufferSize];
+  return [[[self alloc] initWithOutputStream:output data:data] autorelease];
+}
+@end
+
+@interface CodedOutputStreamTests : GPBTestCase
+@end
+
+@implementation CodedOutputStreamTests
+
+- (NSData*)bytes_with_sentinel:(int32_t)unused, ... {
+  va_list list;
+  va_start(list, unused);
+
+  NSMutableData* values = [NSMutableData dataWithCapacity:0];
+  int32_t i;
+
+  while ((i = va_arg(list, int32_t)) != 256) {
+    NSAssert(i >= 0 && i < 256, @"");
+    uint8_t u = (uint8_t)i;
+    [values appendBytes:&u length:1];
+  }
+
+  va_end(list);
+
+  return values;
+}
+
+#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256]
+
+- (void)assertWriteLittleEndian32:(NSData*)data value:(int32_t)value {
+  NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+  GPBCodedOutputStream* output =
+      [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+  [output writeRawLittleEndian32:(int32_t)value];
+  [output flush];
+
+  NSData* actual =
+      [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+  XCTAssertEqualObjects(data, actual);
+
+  // Try different block sizes.
+  for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+    rawOutput = [NSOutputStream outputStreamToMemory];
+    output = [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                               bufferSize:blockSize];
+    [output writeRawLittleEndian32:(int32_t)value];
+    [output flush];
+
+    actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(data, actual);
+  }
+}
+
+- (void)assertWriteLittleEndian64:(NSData*)data value:(int64_t)value {
+  NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+  GPBCodedOutputStream* output =
+      [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+  [output writeRawLittleEndian64:value];
+  [output flush];
+
+  NSData* actual =
+      [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+  XCTAssertEqualObjects(data, actual);
+
+  // Try different block sizes.
+  for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+    rawOutput = [NSOutputStream outputStreamToMemory];
+    output = [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                               bufferSize:blockSize];
+    [output writeRawLittleEndian64:value];
+    [output flush];
+
+    actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(data, actual);
+  }
+}
+
+- (void)assertWriteVarint:(NSData*)data value:(int64_t)value {
+  // Only do 32-bit write if the value fits in 32 bits.
+  if (GPBLogicalRightShift64(value, 32) == 0) {
+    NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+    GPBCodedOutputStream* output =
+        [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+    [output writeRawVarint32:(int32_t)value];
+    [output flush];
+
+    NSData* actual =
+        [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(data, actual);
+
+    // Also try computing size.
+    XCTAssertEqual(GPBComputeRawVarint32Size((int32_t)value),
+                   (size_t)data.length);
+  }
+
+  {
+    NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+    GPBCodedOutputStream* output =
+        [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+    [output writeRawVarint64:value];
+    [output flush];
+
+    NSData* actual =
+        [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(data, actual);
+
+    // Also try computing size.
+    XCTAssertEqual(GPBComputeRawVarint64Size(value), (size_t)data.length);
+  }
+
+  // Try different block sizes.
+  for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+    // Only do 32-bit write if the value fits in 32 bits.
+    if (GPBLogicalRightShift64(value, 32) == 0) {
+      NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+      GPBCodedOutputStream* output =
+          [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                            bufferSize:blockSize];
+
+      [output writeRawVarint32:(int32_t)value];
+      [output flush];
+
+      NSData* actual =
+          [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+      XCTAssertEqualObjects(data, actual);
+    }
+
+    {
+      NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+      GPBCodedOutputStream* output =
+          [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                            bufferSize:blockSize];
+
+      [output writeRawVarint64:value];
+      [output flush];
+
+      NSData* actual =
+          [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+      XCTAssertEqualObjects(data, actual);
+    }
+  }
+}
+
+- (void)testWriteVarint1 {
+  [self assertWriteVarint:bytes(0x00) value:0];
+}
+
+- (void)testWriteVarint2 {
+  [self assertWriteVarint:bytes(0x01) value:1];
+}
+
+- (void)testWriteVarint3 {
+  [self assertWriteVarint:bytes(0x7f) value:127];
+}
+
+- (void)testWriteVarint4 {
+  // 14882
+  [self assertWriteVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)];
+}
+
+- (void)testWriteVarint5 {
+  // 2961488830
+  [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b)
+                    value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
+                          (0x04 << 21) | (0x0bLL << 28)];
+}
+
+- (void)testWriteVarint6 {
+  // 64-bit
+  // 7256456126
+  [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b)
+                    value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
+                          (0x04 << 21) | (0x1bLL << 28)];
+}
+
+- (void)testWriteVarint7 {
+  // 41256202580718336
+  [self assertWriteVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49)
+                    value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) |
+                          (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) |
+                          (0x24LL << 42) | (0x49LL << 49)];
+}
+
+- (void)testWriteVarint8 {
+  // 11964378330978735131
+  [self assertWriteVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85,
+                                0xa6, 0x01)
+                    value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) |
+                          (0x42 << 21) | (0x3bLL << 28) | (0x56LL << 35) |
+                          (0x00LL << 42) | (0x05LL << 49) | (0x26LL << 56) |
+                          (0x01LL << 63)];
+}
+
+- (void)testWriteLittleEndian {
+  [self assertWriteLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12)
+                            value:0x12345678];
+  [self assertWriteLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a)
+                            value:0x9abcdef0];
+
+  [self assertWriteLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
+                                        0x34, 0x12)
+                            value:0x123456789abcdef0LL];
+  [self assertWriteLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde,
+                                        0xbc, 0x9a)
+                            value:0x9abcdef012345678LL];
+}
+
+- (void)testEncodeZigZag {
+  XCTAssertEqual(0U, GPBEncodeZigZag32(0));
+  XCTAssertEqual(1U, GPBEncodeZigZag32(-1));
+  XCTAssertEqual(2U, GPBEncodeZigZag32(1));
+  XCTAssertEqual(3U, GPBEncodeZigZag32(-2));
+  XCTAssertEqual(0x7FFFFFFEU, GPBEncodeZigZag32(0x3FFFFFFF));
+  XCTAssertEqual(0x7FFFFFFFU, GPBEncodeZigZag32(0xC0000000));
+  XCTAssertEqual(0xFFFFFFFEU, GPBEncodeZigZag32(0x7FFFFFFF));
+  XCTAssertEqual(0xFFFFFFFFU, GPBEncodeZigZag32(0x80000000));
+
+  XCTAssertEqual(0ULL, GPBEncodeZigZag64(0));
+  XCTAssertEqual(1ULL, GPBEncodeZigZag64(-1));
+  XCTAssertEqual(2ULL, GPBEncodeZigZag64(1));
+  XCTAssertEqual(3ULL, GPBEncodeZigZag64(-2));
+  XCTAssertEqual(0x000000007FFFFFFEULL,
+                 GPBEncodeZigZag64(0x000000003FFFFFFFLL));
+  XCTAssertEqual(0x000000007FFFFFFFULL,
+                 GPBEncodeZigZag64(0xFFFFFFFFC0000000LL));
+  XCTAssertEqual(0x00000000FFFFFFFEULL,
+                 GPBEncodeZigZag64(0x000000007FFFFFFFLL));
+  XCTAssertEqual(0x00000000FFFFFFFFULL,
+                 GPBEncodeZigZag64(0xFFFFFFFF80000000LL));
+  XCTAssertEqual(0xFFFFFFFFFFFFFFFEULL,
+                 GPBEncodeZigZag64(0x7FFFFFFFFFFFFFFFLL));
+  XCTAssertEqual(0xFFFFFFFFFFFFFFFFULL,
+                 GPBEncodeZigZag64(0x8000000000000000LL));
+
+  // Some easier-to-verify round-trip tests.  The inputs (other than 0, 1, -1)
+  // were chosen semi-randomly via keyboard bashing.
+  XCTAssertEqual(0U, GPBEncodeZigZag32(GPBDecodeZigZag32(0)));
+  XCTAssertEqual(1U, GPBEncodeZigZag32(GPBDecodeZigZag32(1)));
+  XCTAssertEqual(-1U, GPBEncodeZigZag32(GPBDecodeZigZag32(-1)));
+  XCTAssertEqual(14927U, GPBEncodeZigZag32(GPBDecodeZigZag32(14927)));
+  XCTAssertEqual(-3612U, GPBEncodeZigZag32(GPBDecodeZigZag32(-3612)));
+
+  XCTAssertEqual(0ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(0)));
+  XCTAssertEqual(1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(1)));
+  XCTAssertEqual(-1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-1)));
+  XCTAssertEqual(14927ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(14927)));
+  XCTAssertEqual(-3612ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-3612)));
+
+  XCTAssertEqual(856912304801416ULL,
+                 GPBEncodeZigZag64(GPBDecodeZigZag64(856912304801416LL)));
+  XCTAssertEqual(-75123905439571256ULL,
+                 GPBEncodeZigZag64(GPBDecodeZigZag64(-75123905439571256LL)));
+}
+
+- (void)testWriteWholeMessage {
+  // Not kGPBDefaultRepeatCount because we are comparing to a golden master file
+  // that was generated with 2.
+  TestAllTypes* message = [self allSetRepeatedCount:2];
+
+  NSData* rawBytes = message.data;
+  NSData* goldenData =
+      [self getDataFileNamed:@"golden_message" dataToWrite:rawBytes];
+  XCTAssertEqualObjects(rawBytes, goldenData);
+
+  // Try different block sizes.
+  for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+    NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+    GPBCodedOutputStream* output =
+        [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                          bufferSize:blockSize];
+    [message writeToCodedOutputStream:output];
+    [output flush];
+
+    NSData* actual =
+        [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(rawBytes, actual);
+  }
+
+  // Not kGPBDefaultRepeatCount because we are comparing to a golden master file
+  // that was generated with 2.
+  TestAllExtensions* extensions = [self allExtensionsSetRepeatedCount:2];
+  rawBytes = extensions.data;
+  goldenData = [self getDataFileNamed:@"golden_packed_fields_message"
+                          dataToWrite:rawBytes];
+  XCTAssertEqualObjects(rawBytes, goldenData);
+}
+
+@end
diff --git a/objectivec/Tests/GPBConcurrencyTests.m b/objectivec/Tests/GPBConcurrencyTests.m
new file mode 100644
index 0000000..daf75e7
--- /dev/null
+++ b/objectivec/Tests/GPBConcurrencyTests.m
@@ -0,0 +1,206 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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 "GPBTestUtilities.h"
+
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+
+static const int kNumThreads = 100;
+static const int kNumMessages = 100;
+
+// NOTE: Most of these tests don't "fail" in the sense that the XCTAsserts
+// trip.  Rather, the asserts simply exercise the apis, and if there is
+// a concurancy issue, the NSAsserts in the runtime code fire and/or the
+// code just crashes outright.
+
+@interface ConcurrencyTests : GPBTestCase
+@end
+
+@implementation ConcurrencyTests
+
+- (NSArray *)createThreadsWithSelector:(SEL)selector object:(id)object {
+  NSMutableArray *array = [NSMutableArray array];
+  for (NSUInteger i = 0; i < kNumThreads; i++) {
+    NSThread *thread =
+        [[NSThread alloc] initWithTarget:self selector:selector object:object];
+    [array addObject:thread];
+    [thread release];
+  }
+  return array;
+}
+
+- (NSArray *)createMessagesWithType:(Class)msgType {
+  NSMutableArray *array = [NSMutableArray array];
+  for (NSUInteger i = 0; i < kNumMessages; i++) {
+    [array addObject:[msgType message]];
+  }
+  return array;
+}
+
+- (void)startThreads:(NSArray *)threads {
+  for (NSThread *thread in threads) {
+    [thread start];
+  }
+}
+
+- (void)joinThreads:(NSArray *)threads {
+  for (NSThread *thread in threads) {
+    while (![thread isFinished])
+      ;
+  }
+}
+
+- (void)readForeignMessage:(NSArray *)messages {
+  for (NSUInteger i = 0; i < 10; i++) {
+    for (TestAllTypes *message in messages) {
+      XCTAssertEqual(message.optionalForeignMessage.c, 0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetMessageField {
+  NSArray *messages = [self createMessagesWithType:[TestAllTypes class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readForeignMessage:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestAllTypes *message in messages) {
+    XCTAssertFalse(message.hasOptionalForeignMessage);
+  }
+}
+
+- (void)readRepeatedInt32:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestAllTypes *message in messages) {
+      XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetRepeatedIntField {
+  NSArray *messages = [self createMessagesWithType:[TestAllTypes class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readRepeatedInt32:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestAllTypes *message in messages) {
+    XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0);
+  }
+}
+
+- (void)readRepeatedString:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestAllTypes *message in messages) {
+      XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetRepeatedStringField {
+  NSArray *messages = [self createMessagesWithType:[TestAllTypes class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readRepeatedString:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestAllTypes *message in messages) {
+    XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0);
+  }
+}
+
+- (void)readInt32Int32Map:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestRecursiveMessageWithRepeatedField *message in messages) {
+      XCTAssertEqual([message.iToI count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetInt32Int32MapField {
+  NSArray *messages =
+      [self createMessagesWithType:[TestRecursiveMessageWithRepeatedField class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readInt32Int32Map:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestRecursiveMessageWithRepeatedField *message in messages) {
+    XCTAssertEqual([message.iToI count], (NSUInteger)0);
+  }
+}
+
+- (void)readStringStringMap:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestRecursiveMessageWithRepeatedField *message in messages) {
+      XCTAssertEqual([message.strToStr count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetStringStringMapField {
+  NSArray *messages =
+      [self createMessagesWithType:[TestRecursiveMessageWithRepeatedField class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readStringStringMap:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestRecursiveMessageWithRepeatedField *message in messages) {
+    XCTAssertEqual([message.strToStr count], (NSUInteger)0);
+  }
+}
+
+- (void)readOptionalForeignMessageExtension:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestAllExtensions *message in messages) {
+      ForeignMessage *foreign =
+          [message getExtension:[UnittestRoot optionalForeignMessageExtension]];
+      XCTAssertEqual(foreign.c, 0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetExtensionField {
+  NSArray *messages = [self createMessagesWithType:[TestAllExtensions class]];
+  SEL sel = @selector(readOptionalForeignMessageExtension:);
+  NSArray *threads = [self createThreadsWithSelector:sel object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  GPBExtensionDescriptor *extension =
+      [UnittestRoot optionalForeignMessageExtension];
+  for (TestAllExtensions *message in messages) {
+    XCTAssertFalse([message hasExtension:extension]);
+  }
+}
+
+@end
diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m
new file mode 100644
index 0000000..a1923c9
--- /dev/null
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBDescriptor.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+
+@interface DescriptorTests : GPBTestCase
+@end
+
+@implementation DescriptorTests
+
+- (void)testFieldDescriptor {
+  GPBDescriptor *descriptor = [TestAllTypes descriptor];
+
+  // Nested Enum
+  GPBFieldDescriptor *fieldDescriptorWithName =
+      [descriptor fieldWithName:@"optionalNestedEnum"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  GPBFieldDescriptor *fieldDescriptorWithNumber =
+      [descriptor fieldWithNumber:21];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor);
+  XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name,
+                        @"TestAllTypes_NestedEnum");
+
+  // Foreign Enum
+  fieldDescriptorWithName = [descriptor fieldWithName:@"optionalForeignEnum"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  fieldDescriptorWithNumber = [descriptor fieldWithNumber:22];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor);
+  XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name,
+                        @"ForeignEnum");
+
+  // Import Enum
+  fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportEnum"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  fieldDescriptorWithNumber = [descriptor fieldWithNumber:23];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor);
+  XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name,
+                        @"ImportEnum");
+
+  // Nested Message
+  fieldDescriptorWithName = [descriptor fieldWithName:@"optionalNestedMessage"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  fieldDescriptorWithNumber = [descriptor fieldWithNumber:18];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor);
+
+  // Foreign Message
+  fieldDescriptorWithName =
+      [descriptor fieldWithName:@"optionalForeignMessage"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  fieldDescriptorWithNumber = [descriptor fieldWithNumber:19];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor);
+
+  // Import Message
+  fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportMessage"];
+  XCTAssertNotNil(fieldDescriptorWithName);
+  fieldDescriptorWithNumber = [descriptor fieldWithNumber:20];
+  XCTAssertNotNil(fieldDescriptorWithNumber);
+  XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber);
+  XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor);
+}
+
+- (void)testEnumDescriptor {
+  GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor();
+
+  NSString *enumName = [descriptor enumNameForValue:1];
+  XCTAssertNotNil(enumName);
+  int32_t value;
+  XCTAssertTrue(
+      [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Foo"]);
+  XCTAssertTrue(
+      [descriptor getValue:NULL forEnumName:@"TestAllTypes_NestedEnum_Foo"]);
+  XCTAssertEqual(value, TestAllTypes_NestedEnum_Foo);
+
+  enumName = [descriptor enumNameForValue:2];
+  XCTAssertNotNil(enumName);
+  XCTAssertTrue(
+      [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Bar"]);
+  XCTAssertEqual(value, TestAllTypes_NestedEnum_Bar);
+
+  enumName = [descriptor enumNameForValue:3];
+  XCTAssertNotNil(enumName);
+  XCTAssertTrue(
+      [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Baz"]);
+  XCTAssertEqual(value, TestAllTypes_NestedEnum_Baz);
+
+  // Bad values
+  enumName = [descriptor enumNameForValue:0];
+  XCTAssertNil(enumName);
+  XCTAssertFalse([descriptor getValue:&value forEnumName:@"Unknown"]);
+  XCTAssertFalse([descriptor getValue:NULL forEnumName:@"Unknown"]);
+  XCTAssertFalse([descriptor getValue:&value
+                          forEnumName:@"TestAllTypes_NestedEnum_Unknown"]);
+  XCTAssertFalse([descriptor getValue:NULL
+                          forEnumName:@"TestAllTypes_NestedEnum_Unknown"]);
+}
+
+- (void)testEnumValueValidator {
+  GPBDescriptor *descriptor = [TestAllTypes descriptor];
+  GPBFieldDescriptor *fieldDescriptor =
+      [descriptor fieldWithName:@"optionalNestedEnum"];
+
+  // Valid values
+  XCTAssertTrue([fieldDescriptor isValidEnumValue:1]);
+  XCTAssertTrue([fieldDescriptor isValidEnumValue:2]);
+  XCTAssertTrue([fieldDescriptor isValidEnumValue:3]);
+  XCTAssertTrue([fieldDescriptor isValidEnumValue:-1]);
+
+  // Invalid values
+  XCTAssertFalse([fieldDescriptor isValidEnumValue:4]);
+  XCTAssertFalse([fieldDescriptor isValidEnumValue:0]);
+  XCTAssertFalse([fieldDescriptor isValidEnumValue:-2]);
+}
+
+- (void)testOneofDescriptor {
+  GPBDescriptor *descriptor = [TestOneof2 descriptor];
+
+  // All fields should be listed.
+  XCTAssertEqual(descriptor.fields.count, 17U);
+
+  // There are two oneofs in there.
+  XCTAssertEqual(descriptor.oneofs.count, 2U);
+
+  GPBFieldDescriptor *fooStringField =
+      [descriptor fieldWithNumber:TestOneof2_FieldNumber_FooString];
+  XCTAssertNotNil(fooStringField);
+  GPBFieldDescriptor *barStringField =
+      [descriptor fieldWithNumber:TestOneof2_FieldNumber_BarString];
+  XCTAssertNotNil(barStringField);
+
+  // Check the oneofs to have what is expected.
+
+  GPBOneofDescriptor *oneofFoo = [descriptor oneofWithName:@"foo"];
+  XCTAssertNotNil(oneofFoo);
+  XCTAssertEqual(oneofFoo.fields.count, 9U);
+
+  // Pointer comparisons.
+  XCTAssertEqual([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_FooString],
+                 fooStringField);
+  XCTAssertEqual([oneofFoo fieldWithName:@"fooString"], fooStringField);
+
+  GPBOneofDescriptor *oneofBar = [descriptor oneofWithName:@"bar"];
+  XCTAssertNotNil(oneofBar);
+  XCTAssertEqual(oneofBar.fields.count, 6U);
+
+  // Pointer comparisons.
+  XCTAssertEqual([oneofBar fieldWithNumber:TestOneof2_FieldNumber_BarString],
+                 barStringField);
+  XCTAssertEqual([oneofBar fieldWithName:@"barString"], barStringField);
+
+  // Unknown oneof not found.
+
+  XCTAssertNil([descriptor oneofWithName:@"mumble"]);
+  XCTAssertNil([descriptor oneofWithName:@"Foo"]);
+
+  // Unknown oneof item.
+
+  XCTAssertNil([oneofFoo fieldWithName:@"mumble"]);
+  XCTAssertNil([oneofFoo fieldWithNumber:666]);
+
+  // Field exists, but not in this oneof.
+
+  XCTAssertNil([oneofFoo fieldWithName:@"barString"]);
+  XCTAssertNil([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_BarString]);
+  XCTAssertNil([oneofBar fieldWithName:@"fooString"]);
+  XCTAssertNil([oneofBar fieldWithNumber:TestOneof2_FieldNumber_FooString]);
+
+  // Check pointers back to the enclosing oneofs.
+  // (pointer comparisions)
+  XCTAssertEqual(fooStringField.containingOneof, oneofFoo);
+  XCTAssertEqual(barStringField.containingOneof, oneofBar);
+  GPBFieldDescriptor *bazString =
+      [descriptor fieldWithNumber:TestOneof2_FieldNumber_BazString];
+  XCTAssertNotNil(bazString);
+  XCTAssertNil(bazString.containingOneof);
+}
+
+@end
diff --git a/objectivec/Tests/GPBDictionaryTests+Bool.m b/objectivec/Tests/GPBDictionaryTests+Bool.m
new file mode 100644
index 0000000..afa3d11
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+Bool.m
@@ -0,0 +1,2418 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt32, uint32_t, 100U, 101U)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> UInt32
+
+@interface GPBBoolUInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolUInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBBoolUInt32Dictionary *dict = [[GPBBoolUInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionaryWithValue:100U forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const uint32_t kValues[] = { 100U, 101U };
+  GPBBoolUInt32Dictionary *dict =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  uint32_t *seenValues = malloc(2 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const uint32_t kValues1[] = { 100U, 101U };
+  const uint32_t kValues2[] = { 101U, 100U };
+  const uint32_t kValues3[] = { 101U };
+  GPBBoolUInt32Dictionary *dict1 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolUInt32Dictionary *dict1prime =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolUInt32Dictionary *dict2 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolUInt32Dictionary *dict3 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolUInt32Dictionary *dict4 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const uint32_t kValues[] = { 100U, 101U };
+  GPBBoolUInt32Dictionary *dict =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolUInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const uint32_t kValues[] = { 100U, 101U };
+  GPBBoolUInt32Dictionary *dict =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolUInt32Dictionary *dict2 =
+      [GPBBoolUInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const uint32_t kValues[] = { 101U };
+  GPBBoolUInt32Dictionary *dict2 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 101U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const uint32_t kValues[] = { 100U, 101U };
+  GPBBoolUInt32Dictionary *dict =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const uint32_t kValues[] = { 100U, 101U };
+  GPBBoolUInt32Dictionary *dict =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict setValue:101U forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict setValue:100U forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 100U);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const uint32_t kValues2[] = { 101U, 100U };
+  GPBBoolUInt32Dictionary *dict2 =
+      [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int32, int32_t, 200, 201)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Int32
+
+@interface GPBBoolInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBBoolInt32Dictionary *dict = [[GPBBoolInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionaryWithValue:200 forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const int32_t kValues[] = { 200, 201 };
+  GPBBoolInt32Dictionary *dict =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 201);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  int32_t *seenValues = malloc(2 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const int32_t kValues1[] = { 200, 201 };
+  const int32_t kValues2[] = { 201, 200 };
+  const int32_t kValues3[] = { 201 };
+  GPBBoolInt32Dictionary *dict1 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolInt32Dictionary *dict1prime =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolInt32Dictionary *dict2 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolInt32Dictionary *dict3 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolInt32Dictionary *dict4 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const int32_t kValues[] = { 200, 201 };
+  GPBBoolInt32Dictionary *dict =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const int32_t kValues[] = { 200, 201 };
+  GPBBoolInt32Dictionary *dict =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolInt32Dictionary *dict2 =
+      [GPBBoolInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const int32_t kValues[] = { 201 };
+  GPBBoolInt32Dictionary *dict2 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 201);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const int32_t kValues[] = { 200, 201 };
+  GPBBoolInt32Dictionary *dict =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const int32_t kValues[] = { 200, 201 };
+  GPBBoolInt32Dictionary *dict =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict setValue:201 forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict setValue:200 forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 200);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const int32_t kValues2[] = { 201, 200 };
+  GPBBoolInt32Dictionary *dict2 =
+      [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt64, uint64_t, 300U, 301U)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> UInt64
+
+@interface GPBBoolUInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolUInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBBoolUInt64Dictionary *dict = [[GPBBoolUInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionaryWithValue:300U forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const uint64_t kValues[] = { 300U, 301U };
+  GPBBoolUInt64Dictionary *dict =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  uint64_t *seenValues = malloc(2 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const uint64_t kValues1[] = { 300U, 301U };
+  const uint64_t kValues2[] = { 301U, 300U };
+  const uint64_t kValues3[] = { 301U };
+  GPBBoolUInt64Dictionary *dict1 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolUInt64Dictionary *dict1prime =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolUInt64Dictionary *dict2 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolUInt64Dictionary *dict3 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolUInt64Dictionary *dict4 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const uint64_t kValues[] = { 300U, 301U };
+  GPBBoolUInt64Dictionary *dict =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolUInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const uint64_t kValues[] = { 300U, 301U };
+  GPBBoolUInt64Dictionary *dict =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolUInt64Dictionary *dict2 =
+      [GPBBoolUInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const uint64_t kValues[] = { 301U };
+  GPBBoolUInt64Dictionary *dict2 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 301U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const uint64_t kValues[] = { 300U, 301U };
+  GPBBoolUInt64Dictionary *dict =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const uint64_t kValues[] = { 300U, 301U };
+  GPBBoolUInt64Dictionary *dict =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict setValue:301U forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict setValue:300U forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 300U);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const uint64_t kValues2[] = { 301U, 300U };
+  GPBBoolUInt64Dictionary *dict2 =
+      [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int64, int64_t, 400, 401)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Int64
+
+@interface GPBBoolInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBBoolInt64Dictionary *dict = [[GPBBoolInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionaryWithValue:400 forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const int64_t kValues[] = { 400, 401 };
+  GPBBoolInt64Dictionary *dict =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 401);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  int64_t *seenValues = malloc(2 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const int64_t kValues1[] = { 400, 401 };
+  const int64_t kValues2[] = { 401, 400 };
+  const int64_t kValues3[] = { 401 };
+  GPBBoolInt64Dictionary *dict1 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolInt64Dictionary *dict1prime =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolInt64Dictionary *dict2 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolInt64Dictionary *dict3 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolInt64Dictionary *dict4 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const int64_t kValues[] = { 400, 401 };
+  GPBBoolInt64Dictionary *dict =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const int64_t kValues[] = { 400, 401 };
+  GPBBoolInt64Dictionary *dict =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolInt64Dictionary *dict2 =
+      [GPBBoolInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const int64_t kValues[] = { 401 };
+  GPBBoolInt64Dictionary *dict2 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 401);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const int64_t kValues[] = { 400, 401 };
+  GPBBoolInt64Dictionary *dict =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const int64_t kValues[] = { 400, 401 };
+  GPBBoolInt64Dictionary *dict =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict setValue:401 forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict setValue:400 forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 400);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const int64_t kValues2[] = { 401, 400 };
+  GPBBoolInt64Dictionary *dict2 =
+      [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Bool, BOOL, NO, YES)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Bool
+
+@interface GPBBoolBoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolBoolDictionaryTests
+
+- (void)testEmpty {
+  GPBBoolBoolDictionary *dict = [[GPBBoolBoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionaryWithValue:NO forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, NO);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const BOOL kValues[] = { NO, YES };
+  GPBBoolBoolDictionary *dict =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                            forKeys:kKeys
+                                              count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, YES);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  BOOL *seenValues = malloc(2 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const BOOL kValues1[] = { NO, YES };
+  const BOOL kValues2[] = { YES, NO };
+  const BOOL kValues3[] = { YES };
+  GPBBoolBoolDictionary *dict1 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues1
+                                            forKeys:kKeys1
+                                              count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolBoolDictionary *dict1prime =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues1
+                                            forKeys:kKeys1
+                                              count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolBoolDictionary *dict2 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues2
+                                            forKeys:kKeys1
+                                              count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolBoolDictionary *dict3 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues1
+                                            forKeys:kKeys2
+                                              count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolBoolDictionary *dict4 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues3
+                                            forKeys:kKeys1
+                                              count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const BOOL kValues[] = { NO, YES };
+  GPBBoolBoolDictionary *dict =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                            forKeys:kKeys
+                                              count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolBoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolBoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const BOOL kValues[] = { NO, YES };
+  GPBBoolBoolDictionary *dict =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                            forKeys:kKeys
+                                              count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolBoolDictionary *dict2 =
+      [GPBBoolBoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:NO forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const BOOL kValues[] = { YES };
+  GPBBoolBoolDictionary *dict2 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                            forKeys:kKeys
+                                              count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, YES);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const BOOL kValues[] = { NO, YES };
+  GPBBoolBoolDictionary *dict =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                     forKeys:kKeys
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const BOOL kValues[] = { NO, YES };
+  GPBBoolBoolDictionary *dict =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues
+                                     forKeys:kKeys
+                                       count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict setValue:YES forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict setValue:NO forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, NO);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const BOOL kValues2[] = { YES, NO };
+  GPBBoolBoolDictionary *dict2 =
+      [[GPBBoolBoolDictionary alloc] initWithValues:kValues2
+                                            forKeys:kKeys2
+                                              count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Float, float, 500.f, 501.f)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Float
+
+@interface GPBBoolFloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolFloatDictionaryTests
+
+- (void)testEmpty {
+  GPBBoolFloatDictionary *dict = [[GPBBoolFloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionaryWithValue:500.f forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const float kValues[] = { 500.f, 501.f };
+  GPBBoolFloatDictionary *dict =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  float value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  float *seenValues = malloc(2 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const float kValues1[] = { 500.f, 501.f };
+  const float kValues2[] = { 501.f, 500.f };
+  const float kValues3[] = { 501.f };
+  GPBBoolFloatDictionary *dict1 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolFloatDictionary *dict1prime =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolFloatDictionary *dict2 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolFloatDictionary *dict3 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolFloatDictionary *dict4 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const float kValues[] = { 500.f, 501.f };
+  GPBBoolFloatDictionary *dict =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolFloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolFloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const float kValues[] = { 500.f, 501.f };
+  GPBBoolFloatDictionary *dict =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolFloatDictionary *dict2 =
+      [GPBBoolFloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const float kValues[] = { 501.f };
+  GPBBoolFloatDictionary *dict2 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 501.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const float kValues[] = { 500.f, 501.f };
+  GPBBoolFloatDictionary *dict =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const float kValues[] = { 500.f, 501.f };
+  GPBBoolFloatDictionary *dict =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  float value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict setValue:501.f forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict setValue:500.f forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 500.f);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const float kValues2[] = { 501.f, 500.f };
+  GPBBoolFloatDictionary *dict2 =
+      [[GPBBoolFloatDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Double, double, 600., 601.)
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Double
+
+@interface GPBBoolDoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolDoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBBoolDoubleDictionary *dict = [[GPBBoolDoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionaryWithValue:600. forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const double kValues[] = { 600., 601. };
+  GPBBoolDoubleDictionary *dict =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  double value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  double *seenValues = malloc(2 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const double kValues1[] = { 600., 601. };
+  const double kValues2[] = { 601., 600. };
+  const double kValues3[] = { 601. };
+  GPBBoolDoubleDictionary *dict1 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolDoubleDictionary *dict1prime =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolDoubleDictionary *dict2 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolDoubleDictionary *dict3 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolDoubleDictionary *dict4 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const double kValues[] = { 600., 601. };
+  GPBBoolDoubleDictionary *dict =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolDoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolDoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const double kValues[] = { 600., 601. };
+  GPBBoolDoubleDictionary *dict =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolDoubleDictionary *dict2 =
+      [GPBBoolDoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const double kValues[] = { 601. };
+  GPBBoolDoubleDictionary *dict2 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 601.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const double kValues[] = { 600., 601. };
+  GPBBoolDoubleDictionary *dict =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:YES value:NULL]);
+  XCTAssertFalse([dict valueForKey:NO value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const double kValues[] = { 600., 601. };
+  GPBBoolDoubleDictionary *dict =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  double value;
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict setValue:601. forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict setValue:600. forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 600.);
+
+  const BOOL kKeys2[] = { NO, YES };
+  const double kValues2[] = { 601., 600. };
+  GPBBoolDoubleDictionary *dict2 =
+      [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:YES value:NULL]);
+  XCTAssertTrue([dict valueForKey:YES value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:NO value:NULL]);
+  XCTAssertTrue([dict valueForKey:NO value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND TESTS_FOR_BOOL_KEY_OBJECT_VALUE(Object, NSString*, @"abc", @"def")
+// This block of code is generated, do not edit it directly.
+
+#pragma mark - Bool -> Object
+
+@interface GPBBoolObjectDictionaryTests : XCTestCase
+@end
+
+@implementation GPBBoolObjectDictionaryTests
+
+- (void)testEmpty {
+  GPBBoolObjectDictionary<NSString*> *dict = [[GPBBoolObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:YES]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBBoolObjectDictionary<NSString*> *dict = [GPBBoolObjectDictionary dictionaryWithObject:@"abc" forKey:YES];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, YES);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const BOOL kKeys[] = { YES, NO };
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
+
+  __block NSUInteger idx = 0;
+  BOOL *seenKeys = malloc(2 * sizeof(BOOL));
+  NSString* *seenObjects = malloc(2 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertLessThan(idx, 2U);
+    seenKeys[idx] = aKey;
+    seenObjects[idx] = aObject;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 2; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 2) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenObjects);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
+    if (idx == 0) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const BOOL kKeys1[] = { YES, NO };
+  const BOOL kKeys2[] = { NO, YES };
+  const NSString* kObjects1[] = { @"abc", @"def" };
+  const NSString* kObjects2[] = { @"def", @"abc" };
+  const NSString* kObjects3[] = { @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict1 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBBoolObjectDictionary<NSString*> *dict1prime =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBBoolObjectDictionary<NSString*> *dict3 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBBoolObjectDictionary<NSString*> *dict4 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 Fewer pairs; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const BOOL kKeys[] = { YES, NO };
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolObjectDictionary<NSString*> *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBBoolObjectDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const BOOL kKeys[] = { YES, NO };
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [GPBBoolObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBBoolObjectDictionary<NSString*> *dict = [GPBBoolObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:YES];
+  XCTAssertEqual(dict.count, 1U);
+
+  const BOOL kKeys[] = { NO };
+  const NSString* kObjects[] = { @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const BOOL kKeys[] = { YES, NO};
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+
+  [dict removeObjectForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
+
+  // Remove again does nothing.
+  [dict removeObjectForKey:NO];
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:YES]);
+  XCTAssertNil([dict objectForKey:NO]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const BOOL kKeys[] = { YES, NO };
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
+
+  [dict setObject:@"def" forKey:YES];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"def");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
+
+  [dict setObject:@"abc" forKey:NO];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"def");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"abc");
+
+  const BOOL kKeys2[] = { NO, YES };
+  const NSString* kObjects2[] = { @"def", @"abc" };
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END (8 expansions)
+
+
diff --git a/objectivec/Tests/GPBDictionaryTests+Int32.m b/objectivec/Tests/GPBDictionaryTests+Int32.m
new file mode 100644
index 0000000..54dd2ed
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+Int32.m
@@ -0,0 +1,3647 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14)
+// This block of code is generated, do not edit it directly.
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBInt32EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key;
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 700:
+    case 701:
+    case 702:
+    case 703:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBInt32EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key {
+  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+  // type correct.
+  return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                                  rawValues:&value
+                                                                    forKeys:&key
+                                                                      count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int32_t [])keys
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                  forKeys:keys
+                                    count:count];
+}
+@end
+
+
+#pragma mark - Int32 -> UInt32
+
+@interface GPBInt32UInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32UInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBInt32UInt32Dictionary *dict = [[GPBInt32UInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionaryWithValue:100U forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const uint32_t kValues[] = { 100U, 101U, 102U };
+  GPBInt32UInt32Dictionary *dict =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const uint32_t kValues1[] = { 100U, 101U, 102U };
+  const uint32_t kValues2[] = { 100U, 103U, 102U };
+  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict1 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32UInt32Dictionary *dict1prime =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32UInt32Dictionary *dict2 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32UInt32Dictionary *dict3 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32UInt32Dictionary *dict4 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32UInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32UInt32Dictionary *dict2 =
+      [GPBInt32UInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const uint32_t kValues[] = { 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict2 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 103U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt32UInt32Dictionary *dict =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:103U forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:101U forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const uint32_t kValues2[] = { 102U, 100U };
+  GPBInt32UInt32Dictionary *dict2 =
+      [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Int32
+
+@interface GPBInt32Int32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32Int32DictionaryTests
+
+- (void)testEmpty {
+  GPBInt32Int32Dictionary *dict = [[GPBInt32Int32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionaryWithValue:200 forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const int32_t kValues[] = { 200, 201, 202 };
+  GPBInt32Int32Dictionary *dict =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const int32_t kValues1[] = { 200, 201, 202 };
+  const int32_t kValues2[] = { 200, 203, 202 };
+  const int32_t kValues3[] = { 200, 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict1 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32Int32Dictionary *dict1prime =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32Int32Dictionary *dict2 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32Int32Dictionary *dict3 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32Int32Dictionary *dict4 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32Int32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32Int32Dictionary *dict2 =
+      [GPBInt32Int32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const int32_t kValues[] = { 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict2 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 203);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 203);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt32Int32Dictionary *dict =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:203 forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:201 forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 201);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const int32_t kValues2[] = { 202, 200 };
+  GPBInt32Int32Dictionary *dict2 =
+      [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> UInt64
+
+@interface GPBInt32UInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32UInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBInt32UInt64Dictionary *dict = [[GPBInt32UInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionaryWithValue:300U forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const uint64_t kValues[] = { 300U, 301U, 302U };
+  GPBInt32UInt64Dictionary *dict =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const uint64_t kValues1[] = { 300U, 301U, 302U };
+  const uint64_t kValues2[] = { 300U, 303U, 302U };
+  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict1 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32UInt64Dictionary *dict1prime =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32UInt64Dictionary *dict2 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32UInt64Dictionary *dict3 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32UInt64Dictionary *dict4 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32UInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32UInt64Dictionary *dict2 =
+      [GPBInt32UInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const uint64_t kValues[] = { 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict2 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 303U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt32UInt64Dictionary *dict =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:303U forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:301U forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const uint64_t kValues2[] = { 302U, 300U };
+  GPBInt32UInt64Dictionary *dict2 =
+      [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Int64
+
+@interface GPBInt32Int64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32Int64DictionaryTests
+
+- (void)testEmpty {
+  GPBInt32Int64Dictionary *dict = [[GPBInt32Int64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionaryWithValue:400 forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const int64_t kValues[] = { 400, 401, 402 };
+  GPBInt32Int64Dictionary *dict =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  int64_t *seenValues = malloc(3 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const int64_t kValues1[] = { 400, 401, 402 };
+  const int64_t kValues2[] = { 400, 403, 402 };
+  const int64_t kValues3[] = { 400, 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict1 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32Int64Dictionary *dict1prime =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32Int64Dictionary *dict2 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32Int64Dictionary *dict3 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32Int64Dictionary *dict4 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32Int64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32Int64Dictionary *dict2 =
+      [GPBInt32Int64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const int64_t kValues[] = { 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict2 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 403);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 403);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt32Int64Dictionary *dict =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:403 forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:401 forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 401);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const int64_t kValues2[] = { 402, 400 };
+  GPBInt32Int64Dictionary *dict2 =
+      [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Bool
+
+@interface GPBInt32BoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32BoolDictionaryTests
+
+- (void)testEmpty {
+  GPBInt32BoolDictionary *dict = [[GPBInt32BoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionaryWithValue:YES forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, YES);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const BOOL kValues[] = { YES, YES, NO };
+  GPBInt32BoolDictionary *dict =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  BOOL *seenValues = malloc(3 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const BOOL kValues1[] = { YES, YES, NO };
+  const BOOL kValues2[] = { YES, NO, NO };
+  const BOOL kValues3[] = { YES, YES, NO, NO };
+  GPBInt32BoolDictionary *dict1 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32BoolDictionary *dict1prime =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32BoolDictionary *dict2 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32BoolDictionary *dict3 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32BoolDictionary *dict4 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt32BoolDictionary *dict =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32BoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32BoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt32BoolDictionary *dict =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32BoolDictionary *dict2 =
+      [GPBInt32BoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:YES forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const BOOL kValues[] = { YES, NO, NO };
+  GPBInt32BoolDictionary *dict2 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, NO);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt32BoolDictionary *dict =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, NO);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt32BoolDictionary *dict =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:NO forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:YES forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, YES);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const BOOL kValues2[] = { NO, YES };
+  GPBInt32BoolDictionary *dict2 =
+      [[GPBInt32BoolDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Float
+
+@interface GPBInt32FloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32FloatDictionaryTests
+
+- (void)testEmpty {
+  GPBInt32FloatDictionary *dict = [[GPBInt32FloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionaryWithValue:500.f forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const float kValues[] = { 500.f, 501.f, 502.f };
+  GPBInt32FloatDictionary *dict =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  float *seenValues = malloc(3 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const float kValues1[] = { 500.f, 501.f, 502.f };
+  const float kValues2[] = { 500.f, 503.f, 502.f };
+  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict1 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32FloatDictionary *dict1prime =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32FloatDictionary *dict2 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32FloatDictionary *dict3 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32FloatDictionary *dict4 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32FloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32FloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32FloatDictionary *dict2 =
+      [GPBInt32FloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const float kValues[] = { 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict2 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 503.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt32FloatDictionary *dict =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  float value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:503.f forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:501.f forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const float kValues2[] = { 502.f, 500.f };
+  GPBInt32FloatDictionary *dict2 =
+      [[GPBInt32FloatDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Double
+
+@interface GPBInt32DoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32DoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBInt32DoubleDictionary *dict = [[GPBInt32DoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionaryWithValue:600. forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const double kValues[] = { 600., 601., 602. };
+  GPBInt32DoubleDictionary *dict =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  double *seenValues = malloc(3 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const double kValues1[] = { 600., 601., 602. };
+  const double kValues2[] = { 600., 603., 602. };
+  const double kValues3[] = { 600., 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict1 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32DoubleDictionary *dict1prime =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32DoubleDictionary *dict2 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32DoubleDictionary *dict3 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32DoubleDictionary *dict4 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32DoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32DoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32DoubleDictionary *dict2 =
+      [GPBInt32DoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const double kValues[] = { 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict2 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 603.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt32DoubleDictionary *dict =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  double value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:603. forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:601. forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const double kValues2[] = { 602., 600. };
+  GPBInt32DoubleDictionary *dict2 =
+      [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Enum
+
+@interface GPBInt32EnumDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32EnumDictionaryTests
+
+- (void)testEmpty {
+  GPBInt32EnumDictionary *dict = [[GPBInt32EnumDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionaryWithValue:700 forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqual(aValue, 700);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const int32_t kValues[] = { 700, 701, 702 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const int32_t kValues1[] = { 700, 701, 702 };
+  const int32_t kValues2[] = { 700, 703, 702 };
+  const int32_t kValues3[] = { 700, 701, 702, 703 };
+  GPBInt32EnumDictionary *dict1 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32EnumDictionary *dict1prime =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32EnumDictionary *dict3 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32EnumDictionary *dict4 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32EnumDictionary *dict2 =
+      [GPBInt32EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:700 forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const int32_t kValues[] = { 701, 702, 703 };
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 703);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 703);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:703 forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:701 forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 701);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const int32_t kValues2[] = { 702, 700 };
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 701);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Enum (Unknown Enums)
+
+@interface GPBInt32EnumDictionaryUnknownEnumTests : XCTestCase
+@end
+
+@implementation GPBInt32EnumDictionaryUnknownEnumTests
+
+- (void)testRawBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const int32_t kValues[] = { 700, 801, 702 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:11 rawValue:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:13 rawValue:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:14 rawValue:NULL]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        if (i == 1) {
+          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+        } else {
+          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        }
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEqualityWithUnknowns {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
+  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
+  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt32EnumDictionary *dict1 =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32EnumDictionary *dict1prime =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues2
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32EnumDictionary *dict3 =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys2
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32EnumDictionary *dict4 =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues3
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopyWithUnknowns {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertEqualObjects(dict, dict2);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32EnumDictionary *dict2 =
+      [GPBInt32EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  [dict release];
+}
+
+- (void)testUnknownAdds {
+  GPBInt32EnumDictionary *dict =
+    [GPBInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:12],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 0U);
+  [dict setRawValue:801 forKey:12];  // Unknown
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 11, 13, 14 };
+  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  [dict2 release];
+}
+
+- (void)testUnknownRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict removeValueForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:11 value:NULL]);
+  XCTAssertFalse([dict valueForKey:12 value:NULL]);
+  XCTAssertFalse([dict valueForKey:13 value:NULL]);
+  XCTAssertFalse([dict valueForKey:14 value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutationUnknowns {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:11],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 value:NULL]);
+  XCTAssertTrue([dict valueForKey:11 value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:803 forKey:11];  // Unknown
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:11 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:14 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:700 forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:11 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:12 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:12 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:13 value:NULL]);
+  XCTAssertTrue([dict valueForKey:13 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 700);
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const int32_t kValues2[] = { 702, 801 };  // Unknown
+  GPBInt32EnumDictionary *dict2 =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues2
+                                                         forKeys:kKeys2
+                                                           count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:11 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:11 rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:12 value:NULL]);
+  XCTAssertTrue([dict valueForKey:12 value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:13 rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:13 rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:14 value:NULL]);
+  XCTAssertTrue([dict valueForKey:14 value:&value]);
+  XCTAssertEqual(value, 700);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testCopyUnknowns {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const int32_t kValues[] = { 700, 801, 702, 803 };
+  GPBInt32EnumDictionary *dict =
+      [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int32 -> Object
+
+@interface GPBInt32ObjectDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt32ObjectDictionaryTests
+
+- (void)testEmpty {
+  GPBInt32ObjectDictionary<NSString*> *dict = [[GPBInt32ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:11]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt32ObjectDictionary<NSString*> *dict = [GPBInt32ObjectDictionary dictionaryWithObject:@"abc" forKey:11];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 11);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int32_t kKeys[] = { 11, 12, 13 };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertNil([dict objectForKey:14]);
+
+  __block NSUInteger idx = 0;
+  int32_t *seenKeys = malloc(3 * sizeof(int32_t));
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenObjects[idx] = aObject;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenObjects);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int32_t kKeys1[] = { 11, 12, 13, 14 };
+  const int32_t kKeys2[] = { 12, 11, 14 };
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict1 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBInt32ObjectDictionary<NSString*> *dict1prime =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBInt32ObjectDictionary<NSString*> *dict3 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBInt32ObjectDictionary<NSString*> *dict4 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32ObjectDictionary<NSString*> *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt32ObjectDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [GPBInt32ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt32ObjectDictionary<NSString*> *dict = [GPBInt32ObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:11];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int32_t kKeys[] = { 12, 13, 14 };
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeObjectForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
+
+  // Remove again does nothing.
+  [dict removeObjectForKey:12];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
+
+  [dict removeObjectForKey:14];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertNil([dict objectForKey:14]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:11]);
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertNil([dict objectForKey:13]);
+  XCTAssertNil([dict objectForKey:14]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int32_t kKeys[] = { 11, 12, 13, 14 };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
+
+  [dict setObject:@"jkl" forKey:11];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
+
+  [dict setObject:@"def" forKey:14];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"def");
+
+  const int32_t kKeys2[] = { 12, 13 };
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:13], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:14], @"def");
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14)
+
diff --git a/objectivec/Tests/GPBDictionaryTests+Int64.m b/objectivec/Tests/GPBDictionaryTests+Int64.m
new file mode 100644
index 0000000..66bc648
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+Int64.m
@@ -0,0 +1,3647 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL)
+// This block of code is generated, do not edit it directly.
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBInt64EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key;
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 700:
+    case 701:
+    case 702:
+    case 703:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBInt64EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key {
+  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+  // type correct.
+  return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                                  rawValues:&value
+                                                                    forKeys:&key
+                                                                      count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const int64_t [])keys
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                  forKeys:keys
+                                    count:count];
+}
+@end
+
+
+#pragma mark - Int64 -> UInt32
+
+@interface GPBInt64UInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64UInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBInt64UInt32Dictionary *dict = [[GPBInt64UInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionaryWithValue:100U forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const uint32_t kValues[] = { 100U, 101U, 102U };
+  GPBInt64UInt32Dictionary *dict =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const uint32_t kValues1[] = { 100U, 101U, 102U };
+  const uint32_t kValues2[] = { 100U, 103U, 102U };
+  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict1 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64UInt32Dictionary *dict1prime =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64UInt32Dictionary *dict2 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64UInt32Dictionary *dict3 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64UInt32Dictionary *dict4 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64UInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64UInt32Dictionary *dict2 =
+      [GPBInt64UInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const uint32_t kValues[] = { 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict2 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 103U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBInt64UInt32Dictionary *dict =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:103U forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:101U forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const uint32_t kValues2[] = { 102U, 100U };
+  GPBInt64UInt32Dictionary *dict2 =
+      [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Int32
+
+@interface GPBInt64Int32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64Int32DictionaryTests
+
+- (void)testEmpty {
+  GPBInt64Int32Dictionary *dict = [[GPBInt64Int32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionaryWithValue:200 forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const int32_t kValues[] = { 200, 201, 202 };
+  GPBInt64Int32Dictionary *dict =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const int32_t kValues1[] = { 200, 201, 202 };
+  const int32_t kValues2[] = { 200, 203, 202 };
+  const int32_t kValues3[] = { 200, 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict1 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64Int32Dictionary *dict1prime =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64Int32Dictionary *dict2 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64Int32Dictionary *dict3 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64Int32Dictionary *dict4 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64Int32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64Int32Dictionary *dict2 =
+      [GPBInt64Int32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict2 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 203);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBInt64Int32Dictionary *dict =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:203 forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:201 forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 201);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const int32_t kValues2[] = { 202, 200 };
+  GPBInt64Int32Dictionary *dict2 =
+      [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> UInt64
+
+@interface GPBInt64UInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64UInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBInt64UInt64Dictionary *dict = [[GPBInt64UInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionaryWithValue:300U forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const uint64_t kValues[] = { 300U, 301U, 302U };
+  GPBInt64UInt64Dictionary *dict =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const uint64_t kValues1[] = { 300U, 301U, 302U };
+  const uint64_t kValues2[] = { 300U, 303U, 302U };
+  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict1 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64UInt64Dictionary *dict1prime =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64UInt64Dictionary *dict2 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64UInt64Dictionary *dict3 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64UInt64Dictionary *dict4 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64UInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64UInt64Dictionary *dict2 =
+      [GPBInt64UInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const uint64_t kValues[] = { 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict2 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 303U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBInt64UInt64Dictionary *dict =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:303U forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:301U forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const uint64_t kValues2[] = { 302U, 300U };
+  GPBInt64UInt64Dictionary *dict2 =
+      [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Int64
+
+@interface GPBInt64Int64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64Int64DictionaryTests
+
+- (void)testEmpty {
+  GPBInt64Int64Dictionary *dict = [[GPBInt64Int64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionaryWithValue:400 forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const int64_t kValues[] = { 400, 401, 402 };
+  GPBInt64Int64Dictionary *dict =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  int64_t *seenValues = malloc(3 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const int64_t kValues1[] = { 400, 401, 402 };
+  const int64_t kValues2[] = { 400, 403, 402 };
+  const int64_t kValues3[] = { 400, 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict1 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64Int64Dictionary *dict1prime =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64Int64Dictionary *dict2 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64Int64Dictionary *dict3 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64Int64Dictionary *dict4 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64Int64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64Int64Dictionary *dict2 =
+      [GPBInt64Int64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const int64_t kValues[] = { 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict2 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 403);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBInt64Int64Dictionary *dict =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:403 forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:401 forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 401);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const int64_t kValues2[] = { 402, 400 };
+  GPBInt64Int64Dictionary *dict2 =
+      [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Bool
+
+@interface GPBInt64BoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64BoolDictionaryTests
+
+- (void)testEmpty {
+  GPBInt64BoolDictionary *dict = [[GPBInt64BoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionaryWithValue:YES forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, YES);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const BOOL kValues[] = { YES, YES, NO };
+  GPBInt64BoolDictionary *dict =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  BOOL *seenValues = malloc(3 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const BOOL kValues1[] = { YES, YES, NO };
+  const BOOL kValues2[] = { YES, NO, NO };
+  const BOOL kValues3[] = { YES, YES, NO, NO };
+  GPBInt64BoolDictionary *dict1 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64BoolDictionary *dict1prime =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64BoolDictionary *dict2 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64BoolDictionary *dict3 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64BoolDictionary *dict4 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt64BoolDictionary *dict =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64BoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64BoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt64BoolDictionary *dict =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64BoolDictionary *dict2 =
+      [GPBInt64BoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:YES forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const BOOL kValues[] = { YES, NO, NO };
+  GPBInt64BoolDictionary *dict2 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, NO);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt64BoolDictionary *dict =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBInt64BoolDictionary *dict =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:NO forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:YES forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, YES);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const BOOL kValues2[] = { NO, YES };
+  GPBInt64BoolDictionary *dict2 =
+      [[GPBInt64BoolDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Float
+
+@interface GPBInt64FloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64FloatDictionaryTests
+
+- (void)testEmpty {
+  GPBInt64FloatDictionary *dict = [[GPBInt64FloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionaryWithValue:500.f forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const float kValues[] = { 500.f, 501.f, 502.f };
+  GPBInt64FloatDictionary *dict =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  float *seenValues = malloc(3 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const float kValues1[] = { 500.f, 501.f, 502.f };
+  const float kValues2[] = { 500.f, 503.f, 502.f };
+  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict1 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64FloatDictionary *dict1prime =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64FloatDictionary *dict2 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64FloatDictionary *dict3 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64FloatDictionary *dict4 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64FloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64FloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64FloatDictionary *dict2 =
+      [GPBInt64FloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const float kValues[] = { 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict2 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBInt64FloatDictionary *dict =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  float value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:503.f forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:501.f forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const float kValues2[] = { 502.f, 500.f };
+  GPBInt64FloatDictionary *dict2 =
+      [[GPBInt64FloatDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Double
+
+@interface GPBInt64DoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64DoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBInt64DoubleDictionary *dict = [[GPBInt64DoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionaryWithValue:600. forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const double kValues[] = { 600., 601., 602. };
+  GPBInt64DoubleDictionary *dict =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  double *seenValues = malloc(3 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const double kValues1[] = { 600., 601., 602. };
+  const double kValues2[] = { 600., 603., 602. };
+  const double kValues3[] = { 600., 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict1 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64DoubleDictionary *dict1prime =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64DoubleDictionary *dict2 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64DoubleDictionary *dict3 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64DoubleDictionary *dict4 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64DoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64DoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64DoubleDictionary *dict2 =
+      [GPBInt64DoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const double kValues[] = { 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict2 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 603.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBInt64DoubleDictionary *dict =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  double value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:603. forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:601. forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const double kValues2[] = { 602., 600. };
+  GPBInt64DoubleDictionary *dict2 =
+      [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Enum
+
+@interface GPBInt64EnumDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64EnumDictionaryTests
+
+- (void)testEmpty {
+  GPBInt64EnumDictionary *dict = [[GPBInt64EnumDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionaryWithValue:700 forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqual(aValue, 700);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const int32_t kValues[] = { 700, 701, 702 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const int32_t kValues1[] = { 700, 701, 702 };
+  const int32_t kValues2[] = { 700, 703, 702 };
+  const int32_t kValues3[] = { 700, 701, 702, 703 };
+  GPBInt64EnumDictionary *dict1 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64EnumDictionary *dict1prime =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64EnumDictionary *dict3 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues1
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64EnumDictionary *dict4 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues3
+                                             forKeys:kKeys1
+                                               count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64EnumDictionary *dict2 =
+      [GPBInt64EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:700 forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 701, 702, 703 };
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 703);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                      forKeys:kKeys
+                                        count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:703 forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:701 forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 701);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const int32_t kValues2[] = { 702, 700 };
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues2
+                                             forKeys:kKeys2
+                                               count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 701);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Enum (Unknown Enums)
+
+@interface GPBInt64EnumDictionaryUnknownEnumTests : XCTestCase
+@end
+
+@implementation GPBInt64EnumDictionaryUnknownEnumTests
+
+- (void)testRawBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const int32_t kValues[] = { 700, 801, 702 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL rawValue:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:24LL rawValue:NULL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        if (i == 1) {
+          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+        } else {
+          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        }
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEqualityWithUnknowns {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
+  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
+  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt64EnumDictionary *dict1 =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64EnumDictionary *dict1prime =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues2
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64EnumDictionary *dict3 =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues1
+                                                         forKeys:kKeys2
+                                                           count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64EnumDictionary *dict4 =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues3
+                                                         forKeys:kKeys1
+                                                           count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopyWithUnknowns {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertEqualObjects(dict, dict2);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64EnumDictionary *dict2 =
+      [GPBInt64EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  [dict release];
+}
+
+- (void)testUnknownAdds {
+  GPBInt64EnumDictionary *dict =
+    [GPBInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:22LL],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 0U);
+  [dict setRawValue:801 forKey:22LL];  // Unknown
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 21LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValues:kValues
+                                             forKeys:kKeys
+                                               count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  [dict2 release];
+}
+
+- (void)testUnknownRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict removeValueForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:21LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:22LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:23LL value:NULL]);
+  XCTAssertFalse([dict valueForKey:24LL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutationUnknowns {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:21LL],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:803 forKey:21LL];  // Unknown
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:700 forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:23LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 700);
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const int32_t kValues2[] = { 702, 801 };  // Unknown
+  GPBInt64EnumDictionary *dict2 =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues2
+                                                         forKeys:kKeys2
+                                                           count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:21LL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:22LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:22LL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:23LL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:24LL value:NULL]);
+  XCTAssertTrue([dict valueForKey:24LL value:&value]);
+  XCTAssertEqual(value, 700);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testCopyUnknowns {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };
+  GPBInt64EnumDictionary *dict =
+      [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                       rawValues:kValues
+                                                         forKeys:kKeys
+                                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - Int64 -> Object
+
+@interface GPBInt64ObjectDictionaryTests : XCTestCase
+@end
+
+@implementation GPBInt64ObjectDictionaryTests
+
+- (void)testEmpty {
+  GPBInt64ObjectDictionary<NSString*> *dict = [[GPBInt64ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:21LL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBInt64ObjectDictionary<NSString*> *dict = [GPBInt64ObjectDictionary dictionaryWithObject:@"abc" forKey:21LL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 21LL);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertNil([dict objectForKey:24LL]);
+
+  __block NSUInteger idx = 0;
+  int64_t *seenKeys = malloc(3 * sizeof(int64_t));
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenObjects[idx] = aObject;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenObjects);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
+  const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict1 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBInt64ObjectDictionary<NSString*> *dict1prime =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBInt64ObjectDictionary<NSString*> *dict3 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBInt64ObjectDictionary<NSString*> *dict4 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64ObjectDictionary<NSString*> *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBInt64ObjectDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [GPBInt64ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBInt64ObjectDictionary<NSString*> *dict = [GPBInt64ObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:21LL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const int64_t kKeys[] = { 22LL, 23LL, 24LL };
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeObjectForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
+
+  // Remove again does nothing.
+  [dict removeObjectForKey:22LL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
+
+  [dict removeObjectForKey:24LL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertNil([dict objectForKey:24LL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:21LL]);
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertNil([dict objectForKey:23LL]);
+  XCTAssertNil([dict objectForKey:24LL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
+
+  [dict setObject:@"jkl" forKey:21LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
+
+  [dict setObject:@"def" forKey:24LL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"def");
+
+  const int64_t kKeys2[] = { 22LL, 23LL };
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"def");
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL)
+
diff --git a/objectivec/Tests/GPBDictionaryTests+String.m b/objectivec/Tests/GPBDictionaryTests+String.m
new file mode 100644
index 0000000..bfa10b1
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+String.m
@@ -0,0 +1,3359 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble")
+// This block of code is generated, do not edit it directly.
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBStringEnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key;
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 700:
+    case 701:
+    case 702:
+    case 703:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBStringEnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key {
+  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+  // type correct.
+  return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                                   rawValues:&value
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const NSString * [])keys
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                  forKeys:keys
+                                    count:count];
+}
+@end
+
+
+#pragma mark - String -> UInt32
+
+@interface GPBStringUInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringUInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionaryWithValue:100U forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const uint32_t kValues[] = { 100U, 101U, 102U };
+  GPBStringUInt32Dictionary *dict =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const uint32_t kValues1[] = { 100U, 101U, 102U };
+  const uint32_t kValues2[] = { 100U, 103U, 102U };
+  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict1 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringUInt32Dictionary *dict1prime =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringUInt32Dictionary *dict2 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringUInt32Dictionary *dict3 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringUInt32Dictionary *dict4 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringUInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringUInt32Dictionary *dict2 =
+      [GPBStringUInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const uint32_t kValues[] = { 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict2 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 103U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBStringUInt32Dictionary *dict =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:103U forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:101U forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const uint32_t kValues2[] = { 102U, 100U };
+  GPBStringUInt32Dictionary *dict2 =
+      [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Int32
+
+@interface GPBStringInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionaryWithValue:200 forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const int32_t kValues[] = { 200, 201, 202 };
+  GPBStringInt32Dictionary *dict =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const int32_t kValues1[] = { 200, 201, 202 };
+  const int32_t kValues2[] = { 200, 203, 202 };
+  const int32_t kValues3[] = { 200, 201, 202, 203 };
+  GPBStringInt32Dictionary *dict1 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringInt32Dictionary *dict1prime =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringInt32Dictionary *dict2 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringInt32Dictionary *dict3 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringInt32Dictionary *dict4 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBStringInt32Dictionary *dict =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBStringInt32Dictionary *dict =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringInt32Dictionary *dict2 =
+      [GPBStringInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 201, 202, 203 };
+  GPBStringInt32Dictionary *dict2 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 203);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBStringInt32Dictionary *dict =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 203);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBStringInt32Dictionary *dict =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:203 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:201 forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 201);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const int32_t kValues2[] = { 202, 200 };
+  GPBStringInt32Dictionary *dict2 =
+      [[GPBStringInt32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> UInt64
+
+@interface GPBStringUInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringUInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionaryWithValue:300U forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const uint64_t kValues[] = { 300U, 301U, 302U };
+  GPBStringUInt64Dictionary *dict =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const uint64_t kValues1[] = { 300U, 301U, 302U };
+  const uint64_t kValues2[] = { 300U, 303U, 302U };
+  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict1 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringUInt64Dictionary *dict1prime =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringUInt64Dictionary *dict2 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringUInt64Dictionary *dict3 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringUInt64Dictionary *dict4 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringUInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringUInt64Dictionary *dict2 =
+      [GPBStringUInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const uint64_t kValues[] = { 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict2 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 303U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBStringUInt64Dictionary *dict =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:303U forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:301U forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const uint64_t kValues2[] = { 302U, 300U };
+  GPBStringUInt64Dictionary *dict2 =
+      [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Int64
+
+@interface GPBStringInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionaryWithValue:400 forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const int64_t kValues[] = { 400, 401, 402 };
+  GPBStringInt64Dictionary *dict =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  int64_t *seenValues = malloc(3 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const int64_t kValues1[] = { 400, 401, 402 };
+  const int64_t kValues2[] = { 400, 403, 402 };
+  const int64_t kValues3[] = { 400, 401, 402, 403 };
+  GPBStringInt64Dictionary *dict1 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringInt64Dictionary *dict1prime =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringInt64Dictionary *dict2 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringInt64Dictionary *dict3 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringInt64Dictionary *dict4 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBStringInt64Dictionary *dict =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBStringInt64Dictionary *dict =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringInt64Dictionary *dict2 =
+      [GPBStringInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const int64_t kValues[] = { 401, 402, 403 };
+  GPBStringInt64Dictionary *dict2 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 403);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBStringInt64Dictionary *dict =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 403);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBStringInt64Dictionary *dict =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:403 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:401 forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 401);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const int64_t kValues2[] = { 402, 400 };
+  GPBStringInt64Dictionary *dict2 =
+      [[GPBStringInt64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Bool
+
+@interface GPBStringBoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringBoolDictionaryTests
+
+- (void)testEmpty {
+  GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionaryWithValue:YES forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, YES);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const BOOL kValues[] = { YES, YES, NO };
+  GPBStringBoolDictionary *dict =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  BOOL *seenValues = malloc(3 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const BOOL kValues1[] = { YES, YES, NO };
+  const BOOL kValues2[] = { YES, NO, NO };
+  const BOOL kValues3[] = { YES, YES, NO, NO };
+  GPBStringBoolDictionary *dict1 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringBoolDictionary *dict1prime =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringBoolDictionary *dict2 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringBoolDictionary *dict3 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringBoolDictionary *dict4 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBStringBoolDictionary *dict =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringBoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringBoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBStringBoolDictionary *dict =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringBoolDictionary *dict2 =
+      [GPBStringBoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:YES forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const BOOL kValues[] = { YES, NO, NO };
+  GPBStringBoolDictionary *dict2 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, NO);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBStringBoolDictionary *dict =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, NO);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBStringBoolDictionary *dict =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:NO forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:YES forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, YES);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const BOOL kValues2[] = { NO, YES };
+  GPBStringBoolDictionary *dict2 =
+      [[GPBStringBoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Float
+
+@interface GPBStringFloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringFloatDictionaryTests
+
+- (void)testEmpty {
+  GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionaryWithValue:500.f forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const float kValues[] = { 500.f, 501.f, 502.f };
+  GPBStringFloatDictionary *dict =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  float *seenValues = malloc(3 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const float kValues1[] = { 500.f, 501.f, 502.f };
+  const float kValues2[] = { 500.f, 503.f, 502.f };
+  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict1 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringFloatDictionary *dict1prime =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringFloatDictionary *dict2 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringFloatDictionary *dict3 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringFloatDictionary *dict4 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringFloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringFloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringFloatDictionary *dict2 =
+      [GPBStringFloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const float kValues[] = { 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict2 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 503.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBStringFloatDictionary *dict =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  float value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:503.f forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:501.f forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const float kValues2[] = { 502.f, 500.f };
+  GPBStringFloatDictionary *dict2 =
+      [[GPBStringFloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Double
+
+@interface GPBStringDoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringDoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionaryWithValue:600. forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const double kValues[] = { 600., 601., 602. };
+  GPBStringDoubleDictionary *dict =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  double *seenValues = malloc(3 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const double kValues1[] = { 600., 601., 602. };
+  const double kValues2[] = { 600., 603., 602. };
+  const double kValues3[] = { 600., 601., 602., 603. };
+  GPBStringDoubleDictionary *dict1 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringDoubleDictionary *dict1prime =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringDoubleDictionary *dict2 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringDoubleDictionary *dict3 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringDoubleDictionary *dict4 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBStringDoubleDictionary *dict =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringDoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringDoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBStringDoubleDictionary *dict =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringDoubleDictionary *dict2 =
+      [GPBStringDoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const double kValues[] = { 601., 602., 603. };
+  GPBStringDoubleDictionary *dict2 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 603.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBStringDoubleDictionary *dict =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBStringDoubleDictionary *dict =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  double value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:603. forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:601. forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const double kValues2[] = { 602., 600. };
+  GPBStringDoubleDictionary *dict2 =
+      [[GPBStringDoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Enum
+
+@interface GPBStringEnumDictionaryTests : XCTestCase
+@end
+
+@implementation GPBStringEnumDictionaryTests
+
+- (void)testEmpty {
+  GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionaryWithValue:700 forKey:@"foo"];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqualObjects(aKey, @"foo");
+    XCTAssertEqual(aValue, 700);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const int32_t kValues[] = { 700, 701, 702 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const int32_t kValues1[] = { 700, 701, 702 };
+  const int32_t kValues2[] = { 700, 703, 702 };
+  const int32_t kValues3[] = { 700, 701, 702, 703 };
+  GPBStringEnumDictionary *dict1 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringEnumDictionary *dict1prime =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringEnumDictionary *dict3 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringEnumDictionary *dict4 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringEnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringEnumDictionary *dict2 =
+      [GPBStringEnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:700 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 701, 702, 703 };
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 703);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 703);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:703 forKey:@"foo"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:701 forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 701);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const int32_t kValues2[] = { 702, 700 };
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 701);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - String -> Enum (Unknown Enums)
+
+@interface GPBStringEnumDictionaryUnknownEnumTests : XCTestCase
+@end
+
+@implementation GPBStringEnumDictionaryUnknownEnumTests
+
+- (void)testRawBasics {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
+  const int32_t kValues[] = { 700, 801, 702 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:@"mumble" rawValue:NULL]);
+
+  __block NSUInteger idx = 0;
+  NSString **seenKeys = malloc(3 * sizeof(NSString*));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        if (i == 1) {
+          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+        } else {
+          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        }
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if ([kKeys[i] isEqual:seenKeys[j]]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEqualityWithUnknowns {
+  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
+  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
+  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
+  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBStringEnumDictionary *dict1 =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBStringEnumDictionary *dict1prime =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBStringEnumDictionary *dict3 =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBStringEnumDictionary *dict4 =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues3
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopyWithUnknowns {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringEnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertEqualObjects(dict, dict2);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringEnumDictionary *dict2 =
+      [GPBStringEnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  [dict release];
+}
+
+- (void)testUnknownAdds {
+  GPBStringEnumDictionary *dict =
+    [GPBStringEnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:@"bar"],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 0U);
+  [dict setRawValue:801 forKey:@"bar"];  // Unknown
+  XCTAssertEqual(dict.count, 1U);
+
+  const NSString *kKeys[] = { @"foo", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  [dict2 release];
+}
+
+- (void)testUnknownRemove {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:@"bar"];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict removeValueForKey:@"mumble"];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutationUnknowns {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:@"foo"],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:803 forKey:@"foo"];  // Unknown
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:700 forKey:@"mumble"];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"baz" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 700);
+
+  const NSString *kKeys2[] = { @"bar", @"baz" };
+  const int32_t kValues2[] = { 702, 801 };  // Unknown
+  GPBStringEnumDictionary *dict2 =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:@"bar" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"bar" value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]);
+  XCTAssertTrue([dict valueForKey:@"mumble" value:&value]);
+  XCTAssertEqual(value, 700);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testCopyUnknowns {
+  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
+  const int32_t kValues[] = { 700, 801, 702, 803 };
+  GPBStringEnumDictionary *dict =
+      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBStringEnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble")
+
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt32.m b/objectivec/Tests/GPBDictionaryTests+UInt32.m
new file mode 100644
index 0000000..499f2ad
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+UInt32.m
@@ -0,0 +1,3647 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U)
+// This block of code is generated, do not edit it directly.
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBUInt32EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key;
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 700:
+    case 701:
+    case 702:
+    case 703:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBUInt32EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key {
+  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+  // type correct.
+  return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                                   rawValues:&value
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint32_t [])keys
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                  forKeys:keys
+                                    count:count];
+}
+@end
+
+
+#pragma mark - UInt32 -> UInt32
+
+@interface GPBUInt32UInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32UInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32UInt32Dictionary *dict = [[GPBUInt32UInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionaryWithValue:100U forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const uint32_t kValues[] = { 100U, 101U, 102U };
+  GPBUInt32UInt32Dictionary *dict =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const uint32_t kValues1[] = { 100U, 101U, 102U };
+  const uint32_t kValues2[] = { 100U, 103U, 102U };
+  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict1 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32UInt32Dictionary *dict1prime =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32UInt32Dictionary *dict2 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32UInt32Dictionary *dict3 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32UInt32Dictionary *dict4 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32UInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32UInt32Dictionary *dict2 =
+      [GPBUInt32UInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const uint32_t kValues[] = { 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict2 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 103U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt32UInt32Dictionary *dict =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:103U forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:101U forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const uint32_t kValues2[] = { 102U, 100U };
+  GPBUInt32UInt32Dictionary *dict2 =
+      [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Int32
+
+@interface GPBUInt32Int32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32Int32DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32Int32Dictionary *dict = [[GPBUInt32Int32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionaryWithValue:200 forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const int32_t kValues[] = { 200, 201, 202 };
+  GPBUInt32Int32Dictionary *dict =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const int32_t kValues1[] = { 200, 201, 202 };
+  const int32_t kValues2[] = { 200, 203, 202 };
+  const int32_t kValues3[] = { 200, 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict1 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32Int32Dictionary *dict1prime =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32Int32Dictionary *dict2 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32Int32Dictionary *dict3 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32Int32Dictionary *dict4 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32Int32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32Int32Dictionary *dict2 =
+      [GPBUInt32Int32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const int32_t kValues[] = { 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict2 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 203);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 203);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt32Int32Dictionary *dict =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:203 forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:201 forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 201);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const int32_t kValues2[] = { 202, 200 };
+  GPBUInt32Int32Dictionary *dict2 =
+      [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> UInt64
+
+@interface GPBUInt32UInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32UInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32UInt64Dictionary *dict = [[GPBUInt32UInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionaryWithValue:300U forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const uint64_t kValues[] = { 300U, 301U, 302U };
+  GPBUInt32UInt64Dictionary *dict =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const uint64_t kValues1[] = { 300U, 301U, 302U };
+  const uint64_t kValues2[] = { 300U, 303U, 302U };
+  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict1 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32UInt64Dictionary *dict1prime =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32UInt64Dictionary *dict2 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32UInt64Dictionary *dict3 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32UInt64Dictionary *dict4 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32UInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32UInt64Dictionary *dict2 =
+      [GPBUInt32UInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const uint64_t kValues[] = { 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict2 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 303U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt32UInt64Dictionary *dict =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:303U forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:301U forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const uint64_t kValues2[] = { 302U, 300U };
+  GPBUInt32UInt64Dictionary *dict2 =
+      [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Int64
+
+@interface GPBUInt32Int64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32Int64DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32Int64Dictionary *dict = [[GPBUInt32Int64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionaryWithValue:400 forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const int64_t kValues[] = { 400, 401, 402 };
+  GPBUInt32Int64Dictionary *dict =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  int64_t *seenValues = malloc(3 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const int64_t kValues1[] = { 400, 401, 402 };
+  const int64_t kValues2[] = { 400, 403, 402 };
+  const int64_t kValues3[] = { 400, 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict1 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32Int64Dictionary *dict1prime =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32Int64Dictionary *dict2 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32Int64Dictionary *dict3 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32Int64Dictionary *dict4 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32Int64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32Int64Dictionary *dict2 =
+      [GPBUInt32Int64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const int64_t kValues[] = { 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict2 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 403);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 403);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt32Int64Dictionary *dict =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:403 forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:401 forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 401);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const int64_t kValues2[] = { 402, 400 };
+  GPBUInt32Int64Dictionary *dict2 =
+      [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Bool
+
+@interface GPBUInt32BoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32BoolDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32BoolDictionary *dict = [[GPBUInt32BoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionaryWithValue:YES forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, YES);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const BOOL kValues[] = { YES, YES, NO };
+  GPBUInt32BoolDictionary *dict =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  BOOL *seenValues = malloc(3 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const BOOL kValues1[] = { YES, YES, NO };
+  const BOOL kValues2[] = { YES, NO, NO };
+  const BOOL kValues3[] = { YES, YES, NO, NO };
+  GPBUInt32BoolDictionary *dict1 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32BoolDictionary *dict1prime =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32BoolDictionary *dict2 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32BoolDictionary *dict3 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32BoolDictionary *dict4 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt32BoolDictionary *dict =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32BoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32BoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt32BoolDictionary *dict =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32BoolDictionary *dict2 =
+      [GPBUInt32BoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:YES forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const BOOL kValues[] = { YES, NO, NO };
+  GPBUInt32BoolDictionary *dict2 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, NO);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt32BoolDictionary *dict =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, NO);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt32BoolDictionary *dict =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:NO forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:YES forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, YES);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const BOOL kValues2[] = { NO, YES };
+  GPBUInt32BoolDictionary *dict2 =
+      [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Float
+
+@interface GPBUInt32FloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32FloatDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32FloatDictionary *dict = [[GPBUInt32FloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionaryWithValue:500.f forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const float kValues[] = { 500.f, 501.f, 502.f };
+  GPBUInt32FloatDictionary *dict =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  float *seenValues = malloc(3 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const float kValues1[] = { 500.f, 501.f, 502.f };
+  const float kValues2[] = { 500.f, 503.f, 502.f };
+  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict1 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32FloatDictionary *dict1prime =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32FloatDictionary *dict2 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32FloatDictionary *dict3 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32FloatDictionary *dict4 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32FloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32FloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32FloatDictionary *dict2 =
+      [GPBUInt32FloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const float kValues[] = { 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict2 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 503.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt32FloatDictionary *dict =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  float value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:503.f forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:501.f forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const float kValues2[] = { 502.f, 500.f };
+  GPBUInt32FloatDictionary *dict2 =
+      [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Double
+
+@interface GPBUInt32DoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32DoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32DoubleDictionary *dict = [[GPBUInt32DoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionaryWithValue:600. forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const double kValues[] = { 600., 601., 602. };
+  GPBUInt32DoubleDictionary *dict =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  double *seenValues = malloc(3 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const double kValues1[] = { 600., 601., 602. };
+  const double kValues2[] = { 600., 603., 602. };
+  const double kValues3[] = { 600., 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict1 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32DoubleDictionary *dict1prime =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32DoubleDictionary *dict2 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32DoubleDictionary *dict3 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32DoubleDictionary *dict4 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32DoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32DoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32DoubleDictionary *dict2 =
+      [GPBUInt32DoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const double kValues[] = { 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict2 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 603.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt32DoubleDictionary *dict =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  double value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:603. forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:601. forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const double kValues2[] = { 602., 600. };
+  GPBUInt32DoubleDictionary *dict2 =
+      [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Enum
+
+@interface GPBUInt32EnumDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32EnumDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32EnumDictionary *dict = [[GPBUInt32EnumDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionaryWithValue:700 forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqual(aValue, 700);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const int32_t kValues[] = { 700, 701, 702 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const int32_t kValues1[] = { 700, 701, 702 };
+  const int32_t kValues2[] = { 700, 703, 702 };
+  const int32_t kValues3[] = { 700, 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict1 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32EnumDictionary *dict1prime =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32EnumDictionary *dict3 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32EnumDictionary *dict4 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32EnumDictionary *dict2 =
+      [GPBUInt32EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:700 forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const int32_t kValues[] = { 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 703);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 703);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:703 forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:701 forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 701);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const int32_t kValues2[] = { 702, 700 };
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 701);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Enum (Unknown Enums)
+
+@interface GPBUInt32EnumDictionaryUnknownEnumTests : XCTestCase
+@end
+
+@implementation GPBUInt32EnumDictionaryUnknownEnumTests
+
+- (void)testRawBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const int32_t kValues[] = { 700, 801, 702 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:1U rawValue:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:3U rawValue:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:4U rawValue:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        if (i == 1) {
+          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+        } else {
+          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        }
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEqualityWithUnknowns {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
+  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
+  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt32EnumDictionary *dict1 =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32EnumDictionary *dict1prime =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32EnumDictionary *dict3 =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32EnumDictionary *dict4 =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues3
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopyWithUnknowns {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertEqualObjects(dict, dict2);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32EnumDictionary *dict2 =
+      [GPBUInt32EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  [dict release];
+}
+
+- (void)testUnknownAdds {
+  GPBUInt32EnumDictionary *dict =
+    [GPBUInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:2U],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 0U);
+  [dict setRawValue:801 forKey:2U];  // Unknown
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 1U, 3U, 4U };
+  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  [dict2 release];
+}
+
+- (void)testUnknownRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict removeValueForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:1U value:NULL]);
+  XCTAssertFalse([dict valueForKey:2U value:NULL]);
+  XCTAssertFalse([dict valueForKey:3U value:NULL]);
+  XCTAssertFalse([dict valueForKey:4U value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutationUnknowns {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:1U],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U value:NULL]);
+  XCTAssertTrue([dict valueForKey:1U value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:803 forKey:1U];  // Unknown
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:1U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:4U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:700 forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:1U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:2U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:2U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:3U value:NULL]);
+  XCTAssertTrue([dict valueForKey:3U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 700);
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const int32_t kValues2[] = { 702, 801 };  // Unknown
+  GPBUInt32EnumDictionary *dict2 =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:1U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:1U rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:2U value:NULL]);
+  XCTAssertTrue([dict valueForKey:2U value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:3U rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:3U rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:4U value:NULL]);
+  XCTAssertTrue([dict valueForKey:4U value:&value]);
+  XCTAssertEqual(value, 700);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testCopyUnknowns {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const int32_t kValues[] = { 700, 801, 702, 803 };
+  GPBUInt32EnumDictionary *dict =
+      [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt32 -> Object
+
+@interface GPBUInt32ObjectDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt32ObjectDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt32ObjectDictionary<NSString*> *dict = [[GPBUInt32ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:1U]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt32ObjectDictionary<NSString*> *dict = [GPBUInt32ObjectDictionary dictionaryWithObject:@"abc" forKey:1U];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 1U);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint32_t kKeys[] = { 1U, 2U, 3U };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertNil([dict objectForKey:4U]);
+
+  __block NSUInteger idx = 0;
+  uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenObjects[idx] = aObject;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenObjects);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
+  const uint32_t kKeys2[] = { 2U, 1U, 4U };
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict1 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt32ObjectDictionary<NSString*> *dict1prime =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt32ObjectDictionary<NSString*> *dict3 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt32ObjectDictionary<NSString*> *dict4 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects3
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32ObjectDictionary<NSString*> *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32ObjectDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [GPBUInt32ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt32ObjectDictionary<NSString*> *dict = [GPBUInt32ObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:1U];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint32_t kKeys[] = { 2U, 3U, 4U };
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeObjectForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
+
+  // Remove again does nothing.
+  [dict removeObjectForKey:2U];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
+
+  [dict removeObjectForKey:4U];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertNil([dict objectForKey:4U]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:1U]);
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertNil([dict objectForKey:3U]);
+  XCTAssertNil([dict objectForKey:4U]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
+
+  [dict setObject:@"jkl" forKey:1U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
+
+  [dict setObject:@"def" forKey:4U];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"def");
+
+  const uint32_t kKeys2[] = { 2U, 3U };
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"def");
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U)
+
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt64.m b/objectivec/Tests/GPBDictionaryTests+UInt64.m
new file mode 100644
index 0000000..327e154
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests+UInt64.m
@@ -0,0 +1,3646 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "GPBDictionary.h"
+
+#import "GPBTestUtilities.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+
+// Pull in the macros (using an external file because expanding all tests
+// in a single file makes a file that is failing to work with within Xcode.
+//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
+
+//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL)
+// This block of code is generated, do not edit it directly.
+
+// To let the testing macros work, add some extra methods to simplify things.
+@interface GPBUInt64EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key;
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count;
+@end
+
+static BOOL TestingEnum_IsValidValue(int32_t value) {
+  switch (value) {
+    case 700:
+    case 701:
+    case 702:
+    case 703:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+@implementation GPBUInt64EnumDictionary (TestingTweak)
++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key {
+  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+  // type correct.
+  return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                                   rawValues:&value
+                                                                     forKeys:&key
+                                                                       count:1] autorelease];
+}
+- (instancetype)initWithValues:(const int32_t [])values
+                       forKeys:(const uint64_t [])keys
+                         count:(NSUInteger)count {
+  return [self initWithValidationFunction:TestingEnum_IsValidValue
+                                rawValues:values
+                                  forKeys:keys
+                                    count:count];
+}
+@end
+
+
+#pragma mark - UInt64 -> UInt32
+
+@interface GPBUInt64UInt32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64UInt32DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64UInt32Dictionary *dict = [[GPBUInt64UInt32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionaryWithValue:100U forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 100U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const uint32_t kValues[] = { 100U, 101U, 102U };
+  GPBUInt64UInt32Dictionary *dict =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const uint32_t kValues1[] = { 100U, 101U, 102U };
+  const uint32_t kValues2[] = { 100U, 103U, 102U };
+  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict1 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64UInt32Dictionary *dict1prime =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64UInt32Dictionary *dict2 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64UInt32Dictionary *dict3 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64UInt32Dictionary *dict4 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64UInt32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64UInt32Dictionary *dict2 =
+      [GPBUInt64UInt32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:100U forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const uint32_t kValues[] = { 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict2 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
+  GPBUInt64UInt32Dictionary *dict =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:103U forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+
+  [dict setValue:101U forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const uint32_t kValues2[] = { 102U, 100U };
+  GPBUInt64UInt32Dictionary *dict2 =
+      [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 103U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 102U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 100U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 101U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Int32
+
+@interface GPBUInt64Int32DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64Int32DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64Int32Dictionary *dict = [[GPBUInt64Int32Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionaryWithValue:200 forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 200);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const int32_t kValues[] = { 200, 201, 202 };
+  GPBUInt64Int32Dictionary *dict =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const int32_t kValues1[] = { 200, 201, 202 };
+  const int32_t kValues2[] = { 200, 203, 202 };
+  const int32_t kValues3[] = { 200, 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict1 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64Int32Dictionary *dict1prime =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64Int32Dictionary *dict2 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64Int32Dictionary *dict3 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64Int32Dictionary *dict4 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64Int32Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int32Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64Int32Dictionary *dict2 =
+      [GPBUInt64Int32Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:200 forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict2 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 203);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 200, 201, 202, 203 };
+  GPBUInt64Int32Dictionary *dict =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:203 forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 203);
+
+  [dict setValue:201 forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 201);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 201);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const int32_t kValues2[] = { 202, 200 };
+  GPBUInt64Int32Dictionary *dict2 =
+      [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 203);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 202);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 200);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 201);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> UInt64
+
+@interface GPBUInt64UInt64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64UInt64DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64UInt64Dictionary *dict = [[GPBUInt64UInt64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionaryWithValue:300U forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 300U);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const uint64_t kValues[] = { 300U, 301U, 302U };
+  GPBUInt64UInt64Dictionary *dict =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const uint64_t kValues1[] = { 300U, 301U, 302U };
+  const uint64_t kValues2[] = { 300U, 303U, 302U };
+  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict1 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64UInt64Dictionary *dict1prime =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64UInt64Dictionary *dict2 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64UInt64Dictionary *dict3 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64UInt64Dictionary *dict4 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64UInt64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64UInt64Dictionary *dict2 =
+      [GPBUInt64UInt64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:300U forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const uint64_t kValues[] = { 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict2 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
+  GPBUInt64UInt64Dictionary *dict =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  uint64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:303U forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+
+  [dict setValue:301U forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const uint64_t kValues2[] = { 302U, 300U };
+  GPBUInt64UInt64Dictionary *dict2 =
+      [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 303U);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 302U);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 300U);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 301U);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Int64
+
+@interface GPBUInt64Int64DictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64Int64DictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64Int64Dictionary *dict = [[GPBUInt64Int64Dictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionaryWithValue:400 forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 400);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const int64_t kValues[] = { 400, 401, 402 };
+  GPBUInt64Int64Dictionary *dict =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  int64_t *seenValues = malloc(3 * sizeof(int64_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const int64_t kValues1[] = { 400, 401, 402 };
+  const int64_t kValues2[] = { 400, 403, 402 };
+  const int64_t kValues3[] = { 400, 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict1 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64Int64Dictionary *dict1prime =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64Int64Dictionary *dict2 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64Int64Dictionary *dict3 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64Int64Dictionary *dict4 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64Int64Dictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int64Dictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64Int64Dictionary *dict2 =
+      [GPBUInt64Int64Dictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:400 forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const int64_t kValues[] = { 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict2 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 403);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int64_t kValues[] = { 400, 401, 402, 403 };
+  GPBUInt64Int64Dictionary *dict =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int64_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:403 forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 403);
+
+  [dict setValue:401 forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 401);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 401);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const int64_t kValues2[] = { 402, 400 };
+  GPBUInt64Int64Dictionary *dict2 =
+      [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 403);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 402);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 400);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 401);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Bool
+
+@interface GPBUInt64BoolDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64BoolDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64BoolDictionary *dict = [[GPBUInt64BoolDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionaryWithValue:YES forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, YES);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const BOOL kValues[] = { YES, YES, NO };
+  GPBUInt64BoolDictionary *dict =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  BOOL *seenValues = malloc(3 * sizeof(BOOL));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const BOOL kValues1[] = { YES, YES, NO };
+  const BOOL kValues2[] = { YES, NO, NO };
+  const BOOL kValues3[] = { YES, YES, NO, NO };
+  GPBUInt64BoolDictionary *dict1 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64BoolDictionary *dict1prime =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64BoolDictionary *dict2 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64BoolDictionary *dict3 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64BoolDictionary *dict4 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt64BoolDictionary *dict =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64BoolDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64BoolDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt64BoolDictionary *dict =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64BoolDictionary *dict2 =
+      [GPBUInt64BoolDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:YES forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const BOOL kValues[] = { YES, NO, NO };
+  GPBUInt64BoolDictionary *dict2 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt64BoolDictionary *dict =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const BOOL kValues[] = { YES, YES, NO, NO };
+  GPBUInt64BoolDictionary *dict =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  BOOL value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:NO forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, NO);
+
+  [dict setValue:YES forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, YES);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const BOOL kValues2[] = { NO, YES };
+  GPBUInt64BoolDictionary *dict2 =
+      [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, NO);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, YES);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, YES);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Float
+
+@interface GPBUInt64FloatDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64FloatDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64FloatDictionary *dict = [[GPBUInt64FloatDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionaryWithValue:500.f forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  float value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 500.f);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const float kValues[] = { 500.f, 501.f, 502.f };
+  GPBUInt64FloatDictionary *dict =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  float *seenValues = malloc(3 * sizeof(float));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const float kValues1[] = { 500.f, 501.f, 502.f };
+  const float kValues2[] = { 500.f, 503.f, 502.f };
+  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict1 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64FloatDictionary *dict1prime =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64FloatDictionary *dict2 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64FloatDictionary *dict3 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64FloatDictionary *dict4 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64FloatDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64FloatDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64FloatDictionary *dict2 =
+      [GPBUInt64FloatDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:500.f forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const float kValues[] = { 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict2 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  float value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  float value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
+  GPBUInt64FloatDictionary *dict =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  float value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:503.f forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+
+  [dict setValue:501.f forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const float kValues2[] = { 502.f, 500.f };
+  GPBUInt64FloatDictionary *dict2 =
+      [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 503.f);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 502.f);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 500.f);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 501.f);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Double
+
+@interface GPBUInt64DoubleDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64DoubleDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64DoubleDictionary *dict = [[GPBUInt64DoubleDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionaryWithValue:600. forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  double value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 600.);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const double kValues[] = { 600., 601., 602. };
+  GPBUInt64DoubleDictionary *dict =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  double *seenValues = malloc(3 * sizeof(double));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const double kValues1[] = { 600., 601., 602. };
+  const double kValues2[] = { 600., 603., 602. };
+  const double kValues3[] = { 600., 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict1 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64DoubleDictionary *dict1prime =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64DoubleDictionary *dict2 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64DoubleDictionary *dict3 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64DoubleDictionary *dict4 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64DoubleDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64DoubleDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64DoubleDictionary *dict2 =
+      [GPBUInt64DoubleDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:600. forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const double kValues[] = { 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict2 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  double value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  double value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const double kValues[] = { 600., 601., 602., 603. };
+  GPBUInt64DoubleDictionary *dict =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  double value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:603. forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+
+  [dict setValue:601. forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const double kValues2[] = { 602., 600. };
+  GPBUInt64DoubleDictionary *dict2 =
+      [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 603.);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 602.);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 600.);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 601.);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Enum
+
+@interface GPBUInt64EnumDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64EnumDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64EnumDictionary *dict = [[GPBUInt64EnumDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionaryWithValue:700 forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqual(aValue, 700);
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const int32_t kValues[] = { 700, 701, 702 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const int32_t kValues1[] = { 700, 701, 702 };
+  const int32_t kValues2[] = { 700, 703, 702 };
+  const int32_t kValues3[] = { 700, 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict1 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64EnumDictionary *dict1prime =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64EnumDictionary *dict3 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64EnumDictionary *dict4 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues3
+                                              forKeys:kKeys1
+                                                count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64EnumDictionary *dict2 =
+      [GPBUInt64EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setValue:700 forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 703);
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 701, 702, 703 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                       forKeys:kKeys
+                                         count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:703 forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 703);
+
+  [dict setValue:701 forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 701);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 701);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const int32_t kValues2[] = { 702, 700 };
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2
+                                              forKeys:kKeys2
+                                                count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 703);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 701);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Enum (Unknown Enums)
+
+@interface GPBUInt64EnumDictionaryUnknownEnumTests : XCTestCase
+@end
+
+@implementation GPBUInt64EnumDictionaryUnknownEnumTests
+
+- (void)testRawBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const int32_t kValues[] = { 700, 801, 702 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:34ULL rawValue:NULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  int32_t *seenValues = malloc(3 * sizeof(int32_t));
+  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        if (i == 1) {
+          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+        } else {
+          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        }
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenValues[idx] = aValue;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenValues);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) {
+    #pragma unused(aKey, aValue)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEqualityWithUnknowns {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
+  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
+  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt64EnumDictionary *dict1 =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64EnumDictionary *dict1prime =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64EnumDictionary *dict3 =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues1
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64EnumDictionary *dict4 =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues3
+                                                          forKeys:kKeys1
+                                                            count:GPBARRAYSIZE(kValues3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same values; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopyWithUnknowns {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertEqualObjects(dict, dict2);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64EnumDictionary *dict2 =
+      [GPBUInt64EnumDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  [dict release];
+}
+
+- (void)testUnknownAdds {
+  GPBUInt64EnumDictionary *dict =
+    [GPBUInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:32ULL],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 0U);
+  [dict setRawValue:801 forKey:32ULL];  // Unknown
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 31ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValues:kValues
+                                              forKeys:kKeys
+                                                count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  [dict2 release];
+}
+
+- (void)testUnknownRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  // Remove again does nothing.
+  [dict removeValueForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict removeValueForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertFalse([dict valueForKey:31ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:32ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:33ULL value:NULL]);
+  XCTAssertFalse([dict valueForKey:34ULL value:NULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutationUnknowns {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  int32_t value;
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:31ULL],  // Unknown
+                               NSException, NSInvalidArgumentException);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL value:&value]);
+  XCTAssertEqual(value, 700);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:803 forKey:31ULL];  // Unknown
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+
+  [dict setRawValue:700 forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:33ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 700);
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const int32_t kValues2[] = { 702, 801 };  // Unknown
+  GPBUInt64EnumDictionary *dict2 =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues2
+                                                          forKeys:kKeys2
+                                                            count:GPBARRAYSIZE(kValues2)];
+  XCTAssertNotNil(dict2);
+  [dict addRawEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]);
+  XCTAssertEqual(value, 803);
+  XCTAssertTrue([dict valueForKey:32ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:32ULL value:&value]);
+  XCTAssertEqual(value, 702);
+  XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]);
+  XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]);
+  XCTAssertEqual(value, 801);
+  XCTAssertTrue([dict valueForKey:34ULL value:NULL]);
+  XCTAssertTrue([dict valueForKey:34ULL value:&value]);
+  XCTAssertEqual(value, 700);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testCopyUnknowns {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const int32_t kValues[] = { 700, 801, 702, 803 };
+  GPBUInt64EnumDictionary *dict =
+      [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+                                                        rawValues:kValues
+                                                          forKeys:kKeys
+                                                            count:GPBARRAYSIZE(kValues)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64EnumDictionary *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+#pragma mark - UInt64 -> Object
+
+@interface GPBUInt64ObjectDictionaryTests : XCTestCase
+@end
+
+@implementation GPBUInt64ObjectDictionaryTests
+
+- (void)testEmpty {
+  GPBUInt64ObjectDictionary<NSString*> *dict = [[GPBUInt64ObjectDictionary alloc] init];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:31ULL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
+    XCTFail(@"Shouldn't get here!");
+  }];
+  [dict release];
+}
+
+- (void)testOne {
+  GPBUInt64ObjectDictionary<NSString*> *dict = [GPBUInt64ObjectDictionary dictionaryWithObject:@"abc" forKey:31ULL];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 1U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertEqual(aKey, 31ULL);
+    XCTAssertEqualObjects(aObject, @"abc");
+    XCTAssertNotEqual(stop, NULL);
+  }];
+}
+
+- (void)testBasics {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertNil([dict objectForKey:34ULL]);
+
+  __block NSUInteger idx = 0;
+  uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    XCTAssertLessThan(idx, 3U);
+    seenKeys[idx] = aKey;
+    seenObjects[idx] = aObject;
+    XCTAssertNotEqual(stop, NULL);
+    ++idx;
+  }];
+  for (int i = 0; i < 3; ++i) {
+    BOOL foundKey = NO;
+    for (int j = 0; (j < 3) && !foundKey; ++j) {
+      if (kKeys[i] == seenKeys[j]) {
+        foundKey = YES;
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
+      }
+    }
+    XCTAssertTrue(foundKey, @"i = %d", i);
+  }
+  free(seenKeys);
+  free(seenObjects);
+
+  // Stopping the enumeration.
+  idx = 0;
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
+    if (idx == 1) *stop = YES;
+    XCTAssertNotEqual(idx, 2U);
+    ++idx;
+  }];
+  [dict release];
+}
+
+- (void)testEquality {
+  const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict1 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1);
+  GPBUInt64ObjectDictionary<NSString*> *dict1prime =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict1prime);
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  GPBUInt64ObjectDictionary<NSString*> *dict3 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
+  XCTAssertNotNil(dict3);
+  GPBUInt64ObjectDictionary<NSString*> *dict4 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects3
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects3)];
+  XCTAssertNotNil(dict4);
+
+  // 1/1Prime should be different objects, but equal.
+  XCTAssertNotEqual(dict1, dict1prime);
+  XCTAssertEqualObjects(dict1, dict1prime);
+  // Equal, so they must have same hash.
+  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+
+  // 2 is same keys, different objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict2);
+
+  // 3 is different keys, same objects; not equal.
+  XCTAssertNotEqualObjects(dict1, dict3);
+
+  // 4 extra pair; not equal
+  XCTAssertNotEqualObjects(dict1, dict4);
+
+  [dict1 release];
+  [dict1prime release];
+  [dict2 release];
+  [dict3 release];
+  [dict4 release];
+}
+
+- (void)testCopy {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64ObjectDictionary<NSString*> *dict2 = [dict copy];
+  XCTAssertNotNil(dict2);
+
+  // Should be new object but equal.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64ObjectDictionary class]]);
+
+  [dict2 release];
+  [dict release];
+}
+
+- (void)testDictionaryFromDictionary {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [GPBUInt64ObjectDictionary dictionaryWithDictionary:dict];
+  XCTAssertNotNil(dict2);
+
+  // Should be new pointer, but equal objects.
+  XCTAssertNotEqual(dict, dict2);
+  XCTAssertEqualObjects(dict, dict2);
+  [dict release];
+}
+
+- (void)testAdds {
+  GPBUInt64ObjectDictionary<NSString*> *dict = [GPBUInt64ObjectDictionary dictionary];
+  XCTAssertNotNil(dict);
+
+  XCTAssertEqual(dict.count, 0U);
+  [dict setObject:@"abc" forKey:31ULL];
+  XCTAssertEqual(dict.count, 1U);
+
+  const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
+  [dict2 release];
+}
+
+- (void)testRemove {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+
+  [dict removeObjectForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
+
+  // Remove again does nothing.
+  [dict removeObjectForKey:32ULL];
+  XCTAssertEqual(dict.count, 3U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
+
+  [dict removeObjectForKey:34ULL];
+  XCTAssertEqual(dict.count, 2U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertNil([dict objectForKey:34ULL]);
+
+  [dict removeAll];
+  XCTAssertEqual(dict.count, 0U);
+  XCTAssertNil([dict objectForKey:31ULL]);
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertNil([dict objectForKey:33ULL]);
+  XCTAssertNil([dict objectForKey:34ULL]);
+  [dict release];
+}
+
+- (void)testInplaceMutation {
+  const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
+  XCTAssertNotNil(dict);
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
+
+  [dict setObject:@"jkl" forKey:31ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
+
+  [dict setObject:@"def" forKey:34ULL];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"def");
+
+  const uint64_t kKeys2[] = { 32ULL, 33ULL };
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects2)];
+  XCTAssertNotNil(dict2);
+  [dict addEntriesFromDictionary:dict2];
+  XCTAssertEqual(dict.count, 4U);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"def");
+
+  [dict2 release];
+  [dict release];
+}
+
+@end
+
+//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL)
diff --git a/objectivec/Tests/GPBDictionaryTests.pddm b/objectivec/Tests/GPBDictionaryTests.pddm
new file mode 100644
index 0000000..0951294
--- /dev/null
+++ b/objectivec/Tests/GPBDictionaryTests.pddm
@@ -0,0 +1,1047 @@
+// 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.
+
+//%PDDM-DEFINE TEST_FOR_POD_KEY(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4)
+//%TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4)
+//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, NSString*, @"abc", @"def", @"ghi", @"jkl")
+
+//%PDDM-DEFINE TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4)
+//%TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt32, uint32_t, , 100U, 101U, 102U, 103U)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int32, int32_t, , 200, 201, 202, 203)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt64, uint64_t, , 300U, 301U, 302U, 303U)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int64, int64_t, , 400, 401, 402, 403)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Bool, BOOL, , YES, YES, NO, NO)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Float, float, , 500.f, 501.f, 502.f, 503.f)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Double, double, , 600., 601., 602., 603.)
+//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, Raw, 700, 701, 702, 703)
+//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4)
+
+//%PDDM-DEFINE TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
+//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , value, POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
+
+//%PDDM-DEFINE TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VAL1, VAL2, VAL3, VAL4)
+//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, , VAL1, VAL2, VAL3, VAL4)
+
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLPOD(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLEnum(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLOBJECT(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary<VALUE_TYPE>
+
+//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase
+//%@end
+//%
+//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests
+//%
+//%- (void)testEmpty {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 0U);
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u, stop)
+//%    XCTFail(@"Shouldn't get here!");
+//%  }];
+//%  [dict release];
+//%}
+//%
+//%- (void)testOne {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWith##VNAME$u##:VAL1 forKey:KEY1];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 1U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    XCTAssertEqual##KSUFFIX(aKey, KEY1);
+//%    XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1);
+//%    XCTAssertNotEqual(stop, NULL);
+//%  }];
+//%}
+//%
+//%- (void)testBasics {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 3U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%
+//%  __block NSUInteger idx = 0;
+//%  KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP));
+//%  VALUE_TYPE *seen##VNAME$u##s = malloc(3 * sizeof(VALUE_TYPE));
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    XCTAssertLessThan(idx, 3U);
+//%    seenKeys[idx] = aKey;
+//%    seen##VNAME$u##s[idx] = a##VNAME$u##;
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx;
+//%  }];
+//%  for (int i = 0; i < 3; ++i) {
+//%    BOOL foundKey = NO;
+//%    for (int j = 0; (j < 3) && !foundKey; ++j) {
+//%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
+//%        foundKey = YES;
+//%        XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j);
+//%      }
+//%    }
+//%    XCTAssertTrue(foundKey, @"i = %d", i);
+//%  }
+//%  free(seenKeys);
+//%  free(seen##VNAME$u##s);
+//%
+//%  // Stopping the enumeration.
+//%  idx = 0;
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u)
+//%    if (idx == 1) *stop = YES;
+//%    XCTAssertNotEqual(idx, 2U);
+//%    ++idx;
+//%  }];
+//%  [dict release];
+//%}
+//%
+//%- (void)testEquality {
+//%  const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2, VAL3 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL1, VAL4, VAL3 };
+//%  const VALUE_TYPE k##VNAME$u##s3[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict1);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict1prime);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
+//%  XCTAssertNotNil(dict2);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict3);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s3
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s3)];
+//%  XCTAssertNotNil(dict4);
+//%
+//%  // 1/1Prime should be different objects, but equal.
+//%  XCTAssertNotEqual(dict1, dict1prime);
+//%  XCTAssertEqualObjects(dict1, dict1prime);
+//%  // Equal, so they must have same hash.
+//%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+//%
+//%  // 2 is same keys, different ##VNAME##s; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict2);
+//%
+//%  // 3 is different keys, same ##VNAME##s; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict3);
+//%
+//%  // 4 extra pair; not equal
+//%  XCTAssertNotEqualObjects(dict1, dict4);
+//%
+//%  [dict1 release];
+//%  [dict1prime release];
+//%  [dict2 release];
+//%  [dict3 release];
+//%  [dict4 release];
+//%}
+//%
+//%- (void)testCopy {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new object but equal.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]);
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%- (void)testDictionaryFromDictionary {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  [dict release];
+//%}
+//%
+//%- (void)testAdds {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
+//%  XCTAssertNotNil(dict);
+//%
+//%  XCTAssertEqual(dict.count, 0U);
+//%  [dict set##VNAME$u##:VAL1 forKey:KEY1];
+//%  XCTAssertEqual(dict.count, 1U);
+//%
+//%  const KEY_TYPE KisP##kKeys[] = { KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict add##VACCESSOR##EntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 4U);
+//%
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
+//%  [dict2 release];
+//%}
+//%
+//%- (void)testRemove {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 4U);
+//%
+//%  [dict remove##VNAME$u##ForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 3U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
+//%
+//%  // Remove again does nothing.
+//%  [dict remove##VNAME$u##ForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 3U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
+//%
+//%  [dict remove##VNAME$u##ForKey:KEY4];
+//%  XCTAssertEqual(dict.count, 2U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%
+//%  [dict removeAll];
+//%  XCTAssertEqual(dict.count, 0U);
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY3)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%  [dict release];
+//%}
+//%
+//%- (void)testInplaceMutation {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 4U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
+//%
+//%  [dict set##VNAME$u##:VAL4 forKey:KEY1];
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
+//%
+//%  [dict set##VNAME$u##:VAL2 forKey:KEY4];
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL2)
+//%
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL3, VAL1 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict add##VACCESSOR##EntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL2)
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%@end
+//%
+
+//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4)
+//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, , POD, 700, 801, 702, 803)
+//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2, VAL3, VAL4)
+//%#pragma mark - KEY_NAME -> VALUE_NAME (Unknown Enums)
+//%
+//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests : XCTestCase
+//%@end
+//%
+//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests
+//%
+//%- (void)testRawBasics {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 3U);
+//%  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%RAW_VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%
+//%  __block NSUInteger idx = 0;
+//%  KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP));
+//%  VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE));
+//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%    XCTAssertLessThan(idx, 3U);
+//%    seenKeys[idx] = aKey;
+//%    seenValues[idx] = aValue;
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx;
+//%  }];
+//%  for (int i = 0; i < 3; ++i) {
+//%    BOOL foundKey = NO;
+//%    for (int j = 0; (j < 3) && !foundKey; ++j) {
+//%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
+//%        foundKey = YES;
+//%        if (i == 1) {
+//%          XCTAssertEqual##VSUFFIX(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
+//%        } else {
+//%          XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+//%        }
+//%      }
+//%    }
+//%    XCTAssertTrue(foundKey, @"i = %d", i);
+//%  }
+//%  idx = 0;
+//%  [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%    XCTAssertLessThan(idx, 3U);
+//%    seenKeys[idx] = aKey;
+//%    seenValues[idx] = aValue;
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx;
+//%  }];
+//%  for (int i = 0; i < 3; ++i) {
+//%    BOOL foundKey = NO;
+//%    for (int j = 0; (j < 3) && !foundKey; ++j) {
+//%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
+//%        foundKey = YES;
+//%        XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+//%      }
+//%    }
+//%    XCTAssertTrue(foundKey, @"i = %d", i);
+//%  }
+//%  free(seenKeys);
+//%  free(seenValues);
+//%
+//%  // Stopping the enumeration.
+//%  idx = 0;
+//%  [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%    #pragma unused(aKey, aValue)
+//%    if (idx == 1) *stop = YES;
+//%    XCTAssertNotEqual(idx, 2U);
+//%    ++idx;
+//%  }];
+//%  [dict release];
+//%}
+//%
+//%- (void)testEqualityWithUnknowns {
+//%  const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 };
+//%  const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 };  // Unknown
+//%  const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 };  // Unknown
+//%  const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertNotNil(dict1);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertNotNil(dict1prime);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues2
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues2)];
+//%  XCTAssertNotNil(dict2);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
+//%  XCTAssertNotNil(dict3);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues3
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues3)];
+//%  XCTAssertNotNil(dict4);
+//%
+//%  // 1/1Prime should be different objects, but equal.
+//%  XCTAssertNotEqual(dict1, dict1prime);
+//%  XCTAssertEqualObjects(dict1, dict1prime);
+//%  // Equal, so they must have same hash.
+//%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+//%
+//%  // 2 is same keys, different values; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict2);
+//%
+//%  // 3 is different keys, same values; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict3);
+//%
+//%  // 4 extra pair; not equal
+//%  XCTAssertNotEqualObjects(dict1, dict4);
+//%
+//%  [dict1 release];
+//%  [dict1prime release];
+//%  [dict2 release];
+//%  [dict3 release];
+//%  [dict4 release];
+//%}
+//%
+//%- (void)testCopyWithUnknowns {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknown
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+//%  XCTAssertEqualObjects(dict, dict2);
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%- (void)testDictionaryFromDictionary {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+//%  [dict release];
+//%}
+//%
+//%- (void)testUnknownAdds {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%    [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
+//%  XCTAssertNotNil(dict);
+//%
+//%  XCTAssertEqual(dict.count, 0U);
+//%  XCTAssertThrowsSpecificNamed([dict setValue:VAL2 forKey:KEY2],  // Unknown
+//%                               NSException, NSInvalidArgumentException);
+//%  XCTAssertEqual(dict.count, 0U);
+//%  [dict setRawValue:VAL2 forKey:KEY2];  // Unknown
+//%  XCTAssertEqual(dict.count, 1U);
+//%
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL3, VAL4 };  // Unknown
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict addRawEntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 4U);
+//%
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, value, KEY4, kGPBUnrecognizedEnumeratorValue)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%  [dict2 release];
+//%}
+//%
+//%- (void)testUnknownRemove {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 4U);
+//%
+//%  [dict removeValueForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 3U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%
+//%  // Remove again does nothing.
+//%  [dict removeValueForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 3U);
+//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%
+//%  [dict removeValueForKey:KEY4];
+//%  XCTAssertEqual(dict.count, 2U);
+//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%
+//%  [dict removeAll];
+//%  XCTAssertEqual(dict.count, 0U);
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY3)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
+//%  [dict release];
+//%}
+//%
+//%- (void)testInplaceMutationUnknowns {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 4U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%
+//%  XCTAssertThrowsSpecificNamed([dict setValue:VAL4 forKey:KEY1],  // Unknown
+//%                               NSException, NSInvalidArgumentException);
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%
+//%  [dict setRawValue:VAL4 forKey:KEY1];  // Unknown
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%
+//%  [dict setRawValue:VAL1 forKey:KEY4];
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1)
+//%
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 };
+//%  const VALUE_TYPE kValues2[] = { VAL3, VAL2 };  // Unknown
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues2
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues2)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict addRawEntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 4U);
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3)
+//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL2)
+//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1)
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%- (void)testCopyUnknowns {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
+//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
+//%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
+//%  XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]);
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%@end
+//%
+
+//
+// Helpers for PODs
+//
+
+//%PDDM-DEFINE DECLARE_VALUE_STORAGEPOD(VALUE_TYPE, NAME)
+//%  VALUE_TYPE NAME;
+//%
+//%PDDM-DEFINE VALUE_NOT_FOUNDPOD(DICT, KEY)
+//%  XCTAssertFalse([DICT valueForKey:KEY value:NULL]);
+//%PDDM-DEFINE TEST_VALUEPOD(DICT, STORAGE, KEY, VALUE)
+//%  XCTAssertTrue([DICT valueForKey:KEY value:NULL]);
+//%  XCTAssertTrue([DICT valueForKey:KEY value:&STORAGE]);
+//%  XCTAssertEqual(STORAGE, VALUE);
+//%PDDM-DEFINE COMPARE_KEYS(KEY1, KEY2)
+//%KEY1 == KEY2
+//%PDDM-DEFINE RAW_VALUE_NOT_FOUNDPOD(DICT, KEY)
+//%  XCTAssertFalse([DICT valueForKey:KEY rawValue:NULL]);
+//%PDDM-DEFINE TEST_RAW_VALUEPOD(DICT, STORAGE, KEY, VALUE)
+//%  XCTAssertTrue([DICT valueForKey:KEY rawValue:NULL]);
+//%  XCTAssertTrue([DICT valueForKey:KEY rawValue:&STORAGE]);
+//%  XCTAssertEqual(STORAGE, VALUE);
+
+//
+// Helpers for Objects
+//
+
+//%PDDM-DEFINE DECLARE_VALUE_STORAGEOBJECT(VALUE_TYPE, NAME)
+// Empty
+//%PDDM-DEFINE VALUE_NOT_FOUNDOBJECT(DICT, KEY)
+//%  XCTAssertNil([DICT objectForKey:KEY]);
+//%PDDM-DEFINE TEST_VALUEOBJECT(DICT, STORAGE, KEY, VALUE)
+//%  XCTAssertEqualObjects([DICT objectForKey:KEY], VALUE);
+//%PDDM-DEFINE COMPARE_KEYSObjects(KEY1, KEY2)
+//%[KEY1 isEqual:KEY2]
+
+//
+// Helpers for tests.
+//
+
+//%PDDM-DEFINE TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP)
+//%// To let the testing macros work, add some extra methods to simplify things.
+//%@interface GPB##KEY_NAME##EnumDictionary (TestingTweak)
+//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%- (instancetype)initWithValues:(const int32_t [])values
+//%                       forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                         count:(NSUInteger)count;
+//%@end
+//%
+//%static BOOL TestingEnum_IsValidValue(int32_t value) {
+//%  switch (value) {
+//%    case 700:
+//%    case 701:
+//%    case 702:
+//%    case 703:
+//%      return YES;
+//%    default:
+//%      return NO;
+//%  }
+//%}
+//%
+//%@implementation GPB##KEY_NAME##EnumDictionary (TestingTweak)
+//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%  // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the
+//%  // type correct.
+//%  return [[(GPB##KEY_NAME##EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue
+//%                KEY_NAME$S                                             rawValues:&value
+//%                KEY_NAME$S                                               forKeys:&key
+//%                KEY_NAME$S                                                 count:1] autorelease];
+//%}
+//%- (instancetype)initWithValues:(const int32_t [])values
+//%                       forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                         count:(NSUInteger)count {
+//%  return [self initWithValidationFunction:TestingEnum_IsValidValue
+//%                                rawValues:values
+//%                                  forKeys:keys
+//%                                    count:count];
+//%}
+//%@end
+//%
+//%
+
+
+//
+// BOOL test macros
+//
+//TODO(thomasvl): enum tests
+
+//%PDDM-DEFINE BOOL_TESTS_FOR_POD_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2)
+//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , value, POD, VAL1, VAL2)
+
+//%PDDM-DEFINE TESTS_FOR_BOOL_KEY_OBJECT_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2)
+//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, VAL1, VAL2)
+
+//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VAL1, VAL2)
+//%#pragma mark - KEY_NAME -> VALUE_NAME
+//%
+//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase
+//%@end
+//%
+//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests
+//%
+//%- (void)testEmpty {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 0U);
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u##, stop)
+//%    XCTFail(@"Shouldn't get here!");
+//%  }];
+//%  [dict release];
+//%}
+//%
+//%- (void)testOne {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWith##VNAME$u##:VAL1 forKey:KEY1];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 1U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    XCTAssertEqual##KSUFFIX(aKey, KEY1);
+//%    XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1);
+//%    XCTAssertNotEqual(stop, NULL);
+//%  }];
+//%}
+//%
+//%- (void)testBasics {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 2U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%
+//%  __block NSUInteger idx = 0;
+//%  KEY_TYPE KisP##*seenKeys = malloc(2 * sizeof(KEY_TYPE##KisP));
+//%  VALUE_TYPE *seen##VNAME$u##s = malloc(2 * sizeof(VALUE_TYPE));
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
+//%    XCTAssertLessThan(idx, 2U);
+//%    seenKeys[idx] = aKey;
+//%    seen##VNAME$u##s[idx] = a##VNAME$u;
+//%    XCTAssertNotEqual(stop, NULL);
+//%    ++idx;
+//%  }];
+//%  for (int i = 0; i < 2; ++i) {
+//%    BOOL foundKey = NO;
+//%    for (int j = 0; (j < 2) && !foundKey; ++j) {
+//%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
+//%        foundKey = YES;
+//%        XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j);
+//%      }
+//%    }
+//%    XCTAssertTrue(foundKey, @"i = %d", i);
+//%  }
+//%  free(seenKeys);
+//%  free(seen##VNAME$u##s);
+//%
+//%  // Stopping the enumeration.
+//%  idx = 0;
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u)
+//%    if (idx == 0) *stop = YES;
+//%    XCTAssertNotEqual(idx, 2U);
+//%    ++idx;
+//%  }];
+//%  [dict release];
+//%}
+//%
+//%- (void)testEquality {
+//%  const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2 };
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 };
+//%  const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 };
+//%  const VALUE_TYPE k##VNAME$u##s3[] = { VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict1);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict1prime);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
+//%  XCTAssertNotNil(dict2);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
+//%  XCTAssertNotNil(dict3);
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s3
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s3)];
+//%  XCTAssertNotNil(dict4);
+//%
+//%  // 1/1Prime should be different objects, but equal.
+//%  XCTAssertNotEqual(dict1, dict1prime);
+//%  XCTAssertEqualObjects(dict1, dict1prime);
+//%  // Equal, so they must have same hash.
+//%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
+//%
+//%  // 2 is same keys, different ##VNAME##s; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict2);
+//%
+//%  // 3 is different keys, same ##VNAME##s; not equal.
+//%  XCTAssertNotEqualObjects(dict1, dict3);
+//%
+//%  // 4 Fewer pairs; not equal
+//%  XCTAssertNotEqualObjects(dict1, dict4);
+//%
+//%  [dict1 release];
+//%  [dict1prime release];
+//%  [dict2 release];
+//%  [dict3 release];
+//%  [dict4 release];
+//%}
+//%
+//%- (void)testCopy {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new object but equal.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]);
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%- (void)testDictionaryFromDictionary {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
+//%  XCTAssertNotNil(dict2);
+//%
+//%  // Should be new pointer, but equal objects.
+//%  XCTAssertNotEqual(dict, dict2);
+//%  XCTAssertEqualObjects(dict, dict2);
+//%  [dict release];
+//%}
+//%
+//%- (void)testAdds {
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
+//%  XCTAssertNotNil(dict);
+//%
+//%  XCTAssertEqual(dict.count, 0U);
+//%  [dict set##VNAME$u:VAL1 forKey:KEY1];
+//%  XCTAssertEqual(dict.count, 1U);
+//%
+//%  const KEY_TYPE KisP##kKeys[] = { KEY2 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict addEntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 2U);
+//%
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%  [dict2 release];
+//%}
+//%
+//%- (void)testRemove {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2};
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 2U);
+//%
+//%  [dict remove##VNAME$u##ForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 1U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%
+//%  // Remove again does nothing.
+//%  [dict remove##VNAME$u##ForKey:KEY2];
+//%  XCTAssertEqual(dict.count, 1U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%
+//%  [dict removeAll];
+//%  XCTAssertEqual(dict.count, 0U);
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
+//%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
+//%  [dict release];
+//%}
+//%
+//%- (void)testInplaceMutation {
+//%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
+//%  XCTAssertNotNil(dict);
+//%  XCTAssertEqual(dict.count, 2U);
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%
+//%  [dict set##VNAME$u##:VAL2 forKey:KEY1];
+//%  XCTAssertEqual(dict.count, 2U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%
+//%  [dict set##VNAME$u##:VAL1 forKey:KEY2];
+//%  XCTAssertEqual(dict.count, 2U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL1)
+//%
+//%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
+//%  XCTAssertNotNil(dict2);
+//%  [dict addEntriesFromDictionary:dict2];
+//%  XCTAssertEqual(dict.count, 2U);
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%
+//%  [dict2 release];
+//%  [dict release];
+//%}
+//%
+//%@end
+//%
+
diff --git a/objectivec/Tests/GPBMessageTests+Merge.m b/objectivec/Tests/GPBMessageTests+Merge.m
new file mode 100644
index 0000000..c0bd589
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests+Merge.m
@@ -0,0 +1,700 @@
+// 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.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBMessage.h"
+
+#import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
+
+@interface MessageMergeTests : GPBTestCase
+@end
+
+@implementation MessageMergeTests
+
+// TODO(thomasvl): Pull tests over from GPBMessageTests that are merge specific.
+
+- (void)testProto3MergingAndZeroValues {
+  // Proto2 covered in other tests.
+
+  Message3 *src = [[Message3 alloc] init];
+  Message3 *dst = [[Message3 alloc] init];
+  NSData *testData1 = [@"abc" dataUsingEncoding:NSUTF8StringEncoding];
+  NSData *testData2 = [@"def" dataUsingEncoding:NSUTF8StringEncoding];
+
+  dst.optionalInt32 = 1;
+  dst.optionalInt64 = 1;
+  dst.optionalUint32 = 1;
+  dst.optionalUint64 = 1;
+  dst.optionalSint32 = 1;
+  dst.optionalSint64 = 1;
+  dst.optionalFixed32 = 1;
+  dst.optionalFixed64 = 1;
+  dst.optionalSfixed32 = 1;
+  dst.optionalSfixed64 = 1;
+  dst.optionalFloat = 1.0f;
+  dst.optionalDouble = 1.0;
+  dst.optionalBool = YES;
+  dst.optionalString = @"bar";
+  dst.optionalBytes = testData1;
+  dst.optionalEnum = Message3_Enum_Bar;
+
+  // All zeros, nothing should overright.
+
+  src.optionalInt32 = 0;
+  src.optionalInt64 = 0;
+  src.optionalUint32 = 0;
+  src.optionalUint64 = 0;
+  src.optionalSint32 = 0;
+  src.optionalSint64 = 0;
+  src.optionalFixed32 = 0;
+  src.optionalFixed64 = 0;
+  src.optionalSfixed32 = 0;
+  src.optionalSfixed64 = 0;
+  src.optionalFloat = 0.0f;
+  src.optionalDouble = 0.0;
+  src.optionalBool = NO;
+  src.optionalString = @"";
+  src.optionalBytes = [NSData data];
+  src.optionalEnum = Message3_Enum_Foo;  // first value
+
+  [dst mergeFrom:src];
+
+  XCTAssertEqual(dst.optionalInt32, 1);
+  XCTAssertEqual(dst.optionalInt64, 1);
+  XCTAssertEqual(dst.optionalUint32, 1U);
+  XCTAssertEqual(dst.optionalUint64, 1U);
+  XCTAssertEqual(dst.optionalSint32, 1);
+  XCTAssertEqual(dst.optionalSint64, 1);
+  XCTAssertEqual(dst.optionalFixed32, 1U);
+  XCTAssertEqual(dst.optionalFixed64, 1U);
+  XCTAssertEqual(dst.optionalSfixed32, 1);
+  XCTAssertEqual(dst.optionalSfixed64, 1);
+  XCTAssertEqual(dst.optionalFloat, 1.0f);
+  XCTAssertEqual(dst.optionalDouble, 1.0);
+  XCTAssertEqual(dst.optionalBool, YES);
+  XCTAssertEqualObjects(dst.optionalString, @"bar");
+  XCTAssertEqualObjects(dst.optionalBytes, testData1);
+  XCTAssertEqual(dst.optionalEnum, Message3_Enum_Bar);
+
+  // Half the values that will replace.
+
+  src.optionalInt32 = 0;
+  src.optionalInt64 = 2;
+  src.optionalUint32 = 0;
+  src.optionalUint64 = 2;
+  src.optionalSint32 = 0;
+  src.optionalSint64 = 2;
+  src.optionalFixed32 = 0;
+  src.optionalFixed64 = 2;
+  src.optionalSfixed32 = 0;
+  src.optionalSfixed64 = 2;
+  src.optionalFloat = 0.0f;
+  src.optionalDouble = 2.0;
+  src.optionalBool = YES;  // No other value to use.  :(
+  src.optionalString = @"baz";
+  src.optionalBytes = nil;
+  src.optionalEnum = Message3_Enum_Baz;
+
+  [dst mergeFrom:src];
+
+  XCTAssertEqual(dst.optionalInt32, 1);
+  XCTAssertEqual(dst.optionalInt64, 2);
+  XCTAssertEqual(dst.optionalUint32, 1U);
+  XCTAssertEqual(dst.optionalUint64, 2U);
+  XCTAssertEqual(dst.optionalSint32, 1);
+  XCTAssertEqual(dst.optionalSint64, 2);
+  XCTAssertEqual(dst.optionalFixed32, 1U);
+  XCTAssertEqual(dst.optionalFixed64, 2U);
+  XCTAssertEqual(dst.optionalSfixed32, 1);
+  XCTAssertEqual(dst.optionalSfixed64, 2);
+  XCTAssertEqual(dst.optionalFloat, 1.0f);
+  XCTAssertEqual(dst.optionalDouble, 2.0);
+  XCTAssertEqual(dst.optionalBool, YES);
+  XCTAssertEqualObjects(dst.optionalString, @"baz");
+  XCTAssertEqualObjects(dst.optionalBytes, testData1);
+  XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz);
+
+  // Other half the values that will replace.
+
+  src.optionalInt32 = 3;
+  src.optionalInt64 = 0;
+  src.optionalUint32 = 3;
+  src.optionalUint64 = 0;
+  src.optionalSint32 = 3;
+  src.optionalSint64 = 0;
+  src.optionalFixed32 = 3;
+  src.optionalFixed64 = 0;
+  src.optionalSfixed32 = 3;
+  src.optionalSfixed64 = 0;
+  src.optionalFloat = 3.0f;
+  src.optionalDouble = 0.0;
+  src.optionalBool = YES;  // No other value to use.  :(
+  src.optionalString = nil;
+  src.optionalBytes = testData2;
+  src.optionalEnum = Message3_Enum_Foo;
+
+  [dst mergeFrom:src];
+
+  XCTAssertEqual(dst.optionalInt32, 3);
+  XCTAssertEqual(dst.optionalInt64, 2);
+  XCTAssertEqual(dst.optionalUint32, 3U);
+  XCTAssertEqual(dst.optionalUint64, 2U);
+  XCTAssertEqual(dst.optionalSint32, 3);
+  XCTAssertEqual(dst.optionalSint64, 2);
+  XCTAssertEqual(dst.optionalFixed32, 3U);
+  XCTAssertEqual(dst.optionalFixed64, 2U);
+  XCTAssertEqual(dst.optionalSfixed32, 3);
+  XCTAssertEqual(dst.optionalSfixed64, 2);
+  XCTAssertEqual(dst.optionalFloat, 3.0f);
+  XCTAssertEqual(dst.optionalDouble, 2.0);
+  XCTAssertEqual(dst.optionalBool, YES);
+  XCTAssertEqualObjects(dst.optionalString, @"baz");
+  XCTAssertEqualObjects(dst.optionalBytes, testData2);
+  XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz);
+
+  [src release];
+  [dst release];
+}
+
+- (void)testProto3MergingEnums {
+  UnknownEnumsMyMessage *src = [UnknownEnumsMyMessage message];
+  UnknownEnumsMyMessage *dst = [UnknownEnumsMyMessage message];
+
+  // Known value.
+
+  src.e = UnknownEnumsMyEnum_Bar;
+  src.repeatedEArray =
+      [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue
+                                       rawValue:UnknownEnumsMyEnum_Bar];
+  src.repeatedPackedEArray =
+      [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue
+                                       rawValue:UnknownEnumsMyEnum_Bar];
+  src.oneofE1 = UnknownEnumsMyEnum_Bar;
+
+  [dst mergeFrom:src];
+
+  XCTAssertEqual(dst.e, UnknownEnumsMyEnum_Bar);
+  XCTAssertEqual(dst.repeatedEArray.count, 1U);
+  XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar);
+  XCTAssertEqual(dst.repeatedPackedEArray.count, 1U);
+  XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnum_Bar);
+  XCTAssertEqual(dst.oneofE1, UnknownEnumsMyEnum_Bar);
+
+  // Unknown value.
+
+  const int32_t kUnknownValue = 666;
+
+  SetUnknownEnumsMyMessage_E_RawValue(src, kUnknownValue);
+  src.repeatedEArray =
+      [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue
+                                       rawValue:kUnknownValue];
+  src.repeatedPackedEArray =
+      [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue
+                                       rawValue:kUnknownValue];
+  SetUnknownEnumsMyMessage_OneofE1_RawValue(src, kUnknownValue);
+
+  [dst mergeFrom:src];
+
+  XCTAssertEqual(dst.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(dst), kUnknownValue);
+  XCTAssertEqual(dst.repeatedEArray.count, 2U);
+  XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar);
+  XCTAssertEqual([dst.repeatedEArray valueAtIndex:1],
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([dst.repeatedEArray rawValueAtIndex:1], kUnknownValue);
+  XCTAssertEqual(dst.repeatedPackedEArray.count, 2U);
+  XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnum_Bar);
+  XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:1],
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([dst.repeatedPackedEArray rawValueAtIndex:1], kUnknownValue);
+  XCTAssertEqual(dst.oneofE1,
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(dst), kUnknownValue);
+}
+
+- (void)testProto2MergeOneof {
+  Message2 *src = [Message2 message];
+  Message2 *dst = [Message2 message];
+
+  //
+  // Make sure whatever is in dst gets cleared out be merging in something else.
+  //
+
+  dst.oneofEnum = Message2_Enum_Bar;
+
+//%PDDM-DEFINE MERGE2_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT)
+//%  src.oneof##SET_NAME = SET_VALUE;
+//%  [dst mergeFrom:src];
+//%  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_Oneof##SET_NAME);
+//%  XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE);
+//%  XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT);
+//%
+//%PDDM-EXPAND MERGE2_TEST(Int32, 10, Enum, Message2_Enum_Baz)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofInt32 = 10;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+  XCTAssertEqual(dst.oneofInt32, 10);
+  XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz);
+
+//%PDDM-EXPAND MERGE2_TEST(Int64, 11, Int32, 100)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofInt64 = 11;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
+  XCTAssertEqual(dst.oneofInt64, 11);
+  XCTAssertEqual(dst.oneofInt32, 100);
+
+//%PDDM-EXPAND MERGE2_TEST(Uint32, 12U, Int64, 101)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofUint32 = 12U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
+  XCTAssertEqual(dst.oneofUint32, 12U);
+  XCTAssertEqual(dst.oneofInt64, 101);
+
+//%PDDM-EXPAND MERGE2_TEST(Uint64, 13U, Uint32, 102U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofUint64 = 13U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
+  XCTAssertEqual(dst.oneofUint64, 13U);
+  XCTAssertEqual(dst.oneofUint32, 102U);
+
+//%PDDM-EXPAND MERGE2_TEST(Sint32, 14, Uint64, 103U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSint32 = 14;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
+  XCTAssertEqual(dst.oneofSint32, 14);
+  XCTAssertEqual(dst.oneofUint64, 103U);
+
+//%PDDM-EXPAND MERGE2_TEST(Sint64, 15, Sint32, 104)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSint64 = 15;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
+  XCTAssertEqual(dst.oneofSint64, 15);
+  XCTAssertEqual(dst.oneofSint32, 104);
+
+//%PDDM-EXPAND MERGE2_TEST(Fixed32, 16U, Sint64, 105)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFixed32 = 16U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
+  XCTAssertEqual(dst.oneofFixed32, 16U);
+  XCTAssertEqual(dst.oneofSint64, 105);
+
+//%PDDM-EXPAND MERGE2_TEST(Fixed64, 17U, Fixed32, 106U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFixed64 = 17U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
+  XCTAssertEqual(dst.oneofFixed64, 17U);
+  XCTAssertEqual(dst.oneofFixed32, 106U);
+
+//%PDDM-EXPAND MERGE2_TEST(Sfixed32, 18, Fixed64, 107U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSfixed32 = 18;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
+  XCTAssertEqual(dst.oneofSfixed32, 18);
+  XCTAssertEqual(dst.oneofFixed64, 107U);
+
+//%PDDM-EXPAND MERGE2_TEST(Sfixed64, 19, Sfixed32, 108)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSfixed64 = 19;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
+  XCTAssertEqual(dst.oneofSfixed64, 19);
+  XCTAssertEqual(dst.oneofSfixed32, 108);
+
+//%PDDM-EXPAND MERGE2_TEST(Float, 20.0f, Sfixed64, 109)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFloat = 20.0f;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
+  XCTAssertEqual(dst.oneofFloat, 20.0f);
+  XCTAssertEqual(dst.oneofSfixed64, 109);
+
+//%PDDM-EXPAND MERGE2_TEST(Double, 21.0, Float, 110.0f)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofDouble = 21.0;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
+  XCTAssertEqual(dst.oneofDouble, 21.0);
+  XCTAssertEqual(dst.oneofFloat, 110.0f);
+
+//%PDDM-EXPAND MERGE2_TEST(Bool, NO, Double, 111.0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofBool = NO;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBool);
+  XCTAssertEqual(dst.oneofBool, NO);
+  XCTAssertEqual(dst.oneofDouble, 111.0);
+
+//%PDDM-EXPAND MERGE2_TEST(Enum, Message2_Enum_Bar, Bool, YES)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofEnum = Message2_Enum_Bar;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
+  XCTAssertEqual(dst.oneofEnum, Message2_Enum_Bar);
+  XCTAssertEqual(dst.oneofBool, YES);
+
+//%PDDM-EXPAND-END (14 expansions)
+
+  NSString *oneofStringDefault = @"string";
+  NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding];
+
+  src.oneofString = @"foo";
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofString);
+  XCTAssertEqualObjects(dst.oneofString, @"foo");
+  XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz);
+
+  src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
+  XCTAssertEqualObjects(dst.oneofBytes,
+                        [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+  XCTAssertEqualObjects(dst.oneofString, oneofStringDefault);
+
+  Message2_OneofGroup *group = [Message2_OneofGroup message];
+  group.a = 666;
+  src.oneofGroup = group;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+  Message2_OneofGroup *mergedGroup = [[dst.oneofGroup retain] autorelease];
+  XCTAssertNotNil(mergedGroup);
+  XCTAssertNotEqual(mergedGroup, group);  // Pointer comparision.
+  XCTAssertEqualObjects(mergedGroup, group);
+  XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault);
+
+  Message2 *subMessage = [Message2 message];
+  subMessage.optionalInt32 = 777;
+  src.oneofMessage = subMessage;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+  Message2 *mergedSubMessage = [[dst.oneofMessage retain] autorelease];
+  XCTAssertNotNil(mergedSubMessage);
+  XCTAssertNotEqual(mergedSubMessage, subMessage);  // Pointer comparision.
+  XCTAssertEqualObjects(mergedSubMessage, subMessage);
+  XCTAssertNotNil(dst.oneofGroup);
+  XCTAssertNotEqual(dst.oneofGroup, mergedGroup);  // Pointer comparision.
+
+  // Back to something else to make sure message clears out ok.
+
+  src.oneofInt32 = 10;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+  XCTAssertNotNil(dst.oneofMessage);
+  XCTAssertNotEqual(dst.oneofMessage,
+                    mergedSubMessage);  // Pointer comparision.
+
+  //
+  // Test merging in to message/group when they already had something.
+  //
+
+  src.oneofGroup = group;
+  mergedGroup = [Message2_OneofGroup message];
+  mergedGroup.b = 888;
+  dst.oneofGroup = mergedGroup;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+  // Shouldn't have been a new object.
+  XCTAssertEqual(dst.oneofGroup, mergedGroup);  // Pointer comparision.
+  XCTAssertEqual(dst.oneofGroup.a, 666);        // Pointer comparision.
+  XCTAssertEqual(dst.oneofGroup.b, 888);        // Pointer comparision.
+
+  src.oneofMessage = subMessage;
+  mergedSubMessage = [Message2 message];
+  mergedSubMessage.optionalInt64 = 999;
+  dst.oneofMessage = mergedSubMessage;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+  // Shouldn't have been a new object.
+  XCTAssertEqual(dst.oneofMessage, mergedSubMessage);   // Pointer comparision.
+  XCTAssertEqual(dst.oneofMessage.optionalInt32, 777);  // Pointer comparision.
+  XCTAssertEqual(dst.oneofMessage.optionalInt64, 999);  // Pointer comparision.
+}
+
+- (void)testProto3MergeOneof {
+  Message3 *src = [Message3 message];
+  Message3 *dst = [Message3 message];
+
+  //
+  // Make sure whatever is in dst gets cleared out be merging in something else.
+  //
+
+  dst.oneofEnum = Message3_Enum_Bar;
+
+//%PDDM-DEFINE MERGE3_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT)
+//%  src.oneof##SET_NAME = SET_VALUE;
+//%  [dst mergeFrom:src];
+//%  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_Oneof##SET_NAME);
+//%  XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE);
+//%  XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT);
+//%
+//%PDDM-EXPAND MERGE3_TEST(Int32, 10, Enum, Message3_Enum_Foo)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofInt32 = 10;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+  XCTAssertEqual(dst.oneofInt32, 10);
+  XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo);
+
+//%PDDM-EXPAND MERGE3_TEST(Int64, 11, Int32, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofInt64 = 11;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
+  XCTAssertEqual(dst.oneofInt64, 11);
+  XCTAssertEqual(dst.oneofInt32, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Uint32, 12U, Int64, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofUint32 = 12U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
+  XCTAssertEqual(dst.oneofUint32, 12U);
+  XCTAssertEqual(dst.oneofInt64, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Uint64, 13U, Uint32, 0U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofUint64 = 13U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
+  XCTAssertEqual(dst.oneofUint64, 13U);
+  XCTAssertEqual(dst.oneofUint32, 0U);
+
+//%PDDM-EXPAND MERGE3_TEST(Sint32, 14, Uint64, 0U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSint32 = 14;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
+  XCTAssertEqual(dst.oneofSint32, 14);
+  XCTAssertEqual(dst.oneofUint64, 0U);
+
+//%PDDM-EXPAND MERGE3_TEST(Sint64, 15, Sint32, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSint64 = 15;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
+  XCTAssertEqual(dst.oneofSint64, 15);
+  XCTAssertEqual(dst.oneofSint32, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Fixed32, 16U, Sint64, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFixed32 = 16U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
+  XCTAssertEqual(dst.oneofFixed32, 16U);
+  XCTAssertEqual(dst.oneofSint64, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Fixed64, 17U, Fixed32, 0U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFixed64 = 17U;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
+  XCTAssertEqual(dst.oneofFixed64, 17U);
+  XCTAssertEqual(dst.oneofFixed32, 0U);
+
+//%PDDM-EXPAND MERGE3_TEST(Sfixed32, 18, Fixed64, 0U)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSfixed32 = 18;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
+  XCTAssertEqual(dst.oneofSfixed32, 18);
+  XCTAssertEqual(dst.oneofFixed64, 0U);
+
+//%PDDM-EXPAND MERGE3_TEST(Sfixed64, 19, Sfixed32, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofSfixed64 = 19;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
+  XCTAssertEqual(dst.oneofSfixed64, 19);
+  XCTAssertEqual(dst.oneofSfixed32, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Float, 20.0f, Sfixed64, 0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofFloat = 20.0f;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
+  XCTAssertEqual(dst.oneofFloat, 20.0f);
+  XCTAssertEqual(dst.oneofSfixed64, 0);
+
+//%PDDM-EXPAND MERGE3_TEST(Double, 21.0, Float, 0.0f)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofDouble = 21.0;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
+  XCTAssertEqual(dst.oneofDouble, 21.0);
+  XCTAssertEqual(dst.oneofFloat, 0.0f);
+
+//%PDDM-EXPAND MERGE3_TEST(Bool, YES, Double, 0.0)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofBool = YES;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBool);
+  XCTAssertEqual(dst.oneofBool, YES);
+  XCTAssertEqual(dst.oneofDouble, 0.0);
+
+//%PDDM-EXPAND MERGE3_TEST(Enum, Message3_Enum_Bar, Bool, NO)
+// This block of code is generated, do not edit it directly.
+
+  src.oneofEnum = Message3_Enum_Bar;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
+  XCTAssertEqual(dst.oneofEnum, Message3_Enum_Bar);
+  XCTAssertEqual(dst.oneofBool, NO);
+
+//%PDDM-EXPAND-END (14 expansions)
+
+  NSString *oneofStringDefault = @"";
+  NSData *oneofBytesDefault = [NSData data];
+
+  src.oneofString = @"foo";
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofString);
+  XCTAssertEqualObjects(dst.oneofString, @"foo");
+  XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo);
+
+  src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
+  XCTAssertEqualObjects(dst.oneofBytes,
+                        [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+  XCTAssertEqualObjects(dst.oneofString, oneofStringDefault);
+
+
+  Message3 *subMessage = [Message3 message];
+  subMessage.optionalInt32 = 777;
+  src.oneofMessage = subMessage;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+  Message3 *mergedSubMessage = [[dst.oneofMessage retain] autorelease];
+  XCTAssertNotNil(mergedSubMessage);
+  XCTAssertNotEqual(mergedSubMessage, subMessage);  // Pointer comparision.
+  XCTAssertEqualObjects(mergedSubMessage, subMessage);
+  XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault);
+
+  // Back to something else to make sure message clears out ok.
+
+  src.oneofInt32 = 10;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+  XCTAssertNotNil(dst.oneofMessage);
+  XCTAssertNotEqual(dst.oneofMessage,
+                    mergedSubMessage);  // Pointer comparision.
+
+  //
+  // Test merging in to message when they already had something.
+  //
+
+  src.oneofMessage = subMessage;
+  mergedSubMessage = [Message3 message];
+  mergedSubMessage.optionalInt64 = 999;
+  dst.oneofMessage = mergedSubMessage;
+  [dst mergeFrom:src];
+  XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+  // Shouldn't have been a new object.
+  XCTAssertEqual(dst.oneofMessage, mergedSubMessage);   // Pointer comparision.
+  XCTAssertEqual(dst.oneofMessage.optionalInt32, 777);  // Pointer comparision.
+  XCTAssertEqual(dst.oneofMessage.optionalInt64, 999);  // Pointer comparision.
+}
+
+#pragma mark - Subset from from map_tests.cc
+
+// TEST(GeneratedMapFieldTest, CopyFromMessageMap)
+- (void)testMap_CopyFromMessageMap {
+  TestMessageMap *msg1 = [[TestMessageMap alloc] init];
+  TestMessageMap *msg2 = [[TestMessageMap alloc] init];
+
+  TestAllTypes *subMsg = [TestAllTypes message];
+  subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:100];
+  [msg1.mapInt32Message setObject:subMsg forKey:0];
+  subMsg = nil;
+
+  subMsg = [TestAllTypes message];
+  subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:101];
+
+  [msg2.mapInt32Message setObject:subMsg forKey:0];
+  subMsg = nil;
+
+  [msg1 mergeFrom:msg2];
+
+  // Checks repeated field is overwritten.
+  XCTAssertEqual(msg1.mapInt32Message.count, 1U);
+  subMsg = [msg1.mapInt32Message objectForKey:0];
+  XCTAssertNotNil(subMsg);
+  XCTAssertEqual(subMsg.repeatedInt32Array.count, 1U);
+  XCTAssertEqual([subMsg.repeatedInt32Array valueAtIndex:0], 101);
+
+  [msg2 release];
+  [msg1 release];
+}
+
+@end
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m
new file mode 100644
index 0000000..5e19771
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -0,0 +1,2090 @@
+// 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.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBMessage.h"
+
+#import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjcStartup.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
+
+@interface MessageRuntimeTests : GPBTestCase
+@end
+
+@implementation MessageRuntimeTests
+
+// TODO(thomasvl): Pull tests over from GPBMessageTests that are runtime
+// specific.
+
+- (void)testStartupOrdering {
+  // Just have to create a message.  Nothing else uses the classes from
+  // this file, so the first selector invoked on the class will initialize
+  // it, which also initializes the root.
+  TestObjCStartupMessage *message = [TestObjCStartupMessage message];
+  XCTAssertNotNil(message);
+}
+
+- (void)testProto2HasMethodSupport {
+  NSArray *names = @[
+    @"Int32",
+    @"Int64",
+    @"Uint32",
+    @"Uint64",
+    @"Sint32",
+    @"Sint64",
+    @"Fixed32",
+    @"Fixed64",
+    @"Sfixed32",
+    @"Sfixed64",
+    @"Float",
+    @"Double",
+    @"Bool",
+    @"String",
+    @"Bytes",
+    @"Group",
+    @"Message",
+    @"Enum",
+  ];
+
+  // Proto2 gets:
+
+  // Single fields - has*/setHas* is valid.
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasOptional%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasOptional%@:", name]);
+    XCTAssertTrue([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                  name);
+    XCTAssertTrue([Message2 instancesRespondToSelector:setHasSel], @"field: %@",
+                  name);
+  }
+
+  // Repeated fields
+  //  - no has*/setHas*
+  //  - *Count
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasRepeatedInt32Array/setHasRepeatedInt32Array:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasRepeated%@Array", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasRepeated%@Array:", name]);
+    XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+    // build the selector, i.e. - repeatedInt32Array_Count
+    SEL countSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"repeated%@Array_Count", name]);
+    XCTAssertTrue([Message2 instancesRespondToSelector:countSel], @"field: %@",
+                   name);
+  }
+
+  // OneOf fields - no has*/setHas*
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasOneofInt32/setHasOneofInt32:
+    SEL hasSel =
+        NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasOneof%@:", name]);
+    XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+  }
+
+  // map<> fields
+  //  - no has*/setHas*
+  //  - *Count
+
+  NSArray *mapNames = @[
+    @"Int32Int32",
+    @"Int64Int64",
+    @"Uint32Uint32",
+    @"Uint64Uint64",
+    @"Sint32Sint32",
+    @"Sint64Sint64",
+    @"Fixed32Fixed32",
+    @"Fixed64Fixed64",
+    @"Sfixed32Sfixed32",
+    @"Sfixed64Sfixed64",
+    @"Int32Float",
+    @"Int32Double",
+    @"BoolBool",
+    @"StringString",
+    @"StringBytes",
+    @"StringMessage",
+    @"Int32Bytes",
+    @"Int32Enum",
+    @"Int32Message",
+  ];
+
+  for (NSString *name in mapNames) {
+    // build the selector, i.e. - hasMapInt32Int32/setHasMapInt32Int32:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasMap%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasMap%@:", name]);
+    XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+    // build the selector, i.e. - mapInt32Int32Count
+    SEL countSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"map%@_Count", name]);
+    XCTAssertTrue([Message2 instancesRespondToSelector:countSel], @"field: %@",
+                   name);
+  }
+
+}
+
+- (void)testProto3HasMethodSupport {
+  NSArray *names = @[
+    @"Int32",
+    @"Int64",
+    @"Uint32",
+    @"Uint64",
+    @"Sint32",
+    @"Sint64",
+    @"Fixed32",
+    @"Fixed64",
+    @"Sfixed32",
+    @"Sfixed64",
+    @"Float",
+    @"Double",
+    @"Bool",
+    @"String",
+    @"Bytes",
+    @"Message",
+    @"Enum",
+  ];
+
+  // Proto3 gets:
+
+  // Single fields
+  //  - has*/setHas* invalid for primative types.
+  //  - has*/setHas* valid for Message.
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasOptional%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasOptional%@:", name]);
+    if ([name isEqual:@"Message"]) {
+      // Sub messages/groups are the exception.
+      XCTAssertTrue([Message3 instancesRespondToSelector:hasSel], @"field: %@",
+                    name);
+      XCTAssertTrue([Message3 instancesRespondToSelector:setHasSel],
+                    @"field: %@", name);
+    } else {
+      XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@",
+                     name);
+      XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel],
+                     @"field: %@", name);
+    }
+  }
+
+  // Repeated fields
+  //  - no has*/setHas*
+  //  - *Count
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasRepeatedInt32Array/setHasRepeatedInt32Array:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasRepeated%@Array", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasRepeated%@Array:", name]);
+    XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+    // build the selector, i.e. - repeatedInt32Array_Count
+    SEL countSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"repeated%@Array_Count", name]);
+    XCTAssertTrue([Message2 instancesRespondToSelector:countSel], @"field: %@",
+                  name);
+  }
+
+  // OneOf fields - no has*/setHas*
+
+  for (NSString *name in names) {
+    // build the selector, i.e. - hasOneofInt32/setHasOneofInt32:
+    SEL hasSel =
+        NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasOneof%@:", name]);
+    XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+  }
+
+  // map<> fields
+  //  - no has*/setHas*
+  //  - *Count
+
+  NSArray *mapNames = @[
+    @"Int32Int32",
+    @"Int64Int64",
+    @"Uint32Uint32",
+    @"Uint64Uint64",
+    @"Sint32Sint32",
+    @"Sint64Sint64",
+    @"Fixed32Fixed32",
+    @"Fixed64Fixed64",
+    @"Sfixed32Sfixed32",
+    @"Sfixed64Sfixed64",
+    @"Int32Float",
+    @"Int32Double",
+    @"BoolBool",
+    @"StringString",
+    @"StringBytes",
+    @"StringMessage",
+    @"Int32Bytes",
+    @"Int32Enum",
+    @"Int32Message",
+  ];
+
+  for (NSString *name in mapNames) {
+    // build the selector, i.e. - hasMapInt32Int32/setHasMapInt32Int32:
+    SEL hasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"hasMap%@", name]);
+    SEL setHasSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"setHasMap%@:", name]);
+    XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@",
+                   name);
+    XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel],
+                   @"field: %@", name);
+    // build the selector, i.e. - mapInt32Int32Count
+    SEL countSel = NSSelectorFromString(
+        [NSString stringWithFormat:@"map%@_Count", name]);
+    XCTAssertTrue([Message2 instancesRespondToSelector:countSel], @"field: %@",
+                   name);
+  }
+}
+
+- (void)testProto2SingleFieldHasBehavior {
+  //
+  // Setting to any value including the default value (0) should result has*
+  // being true.
+  //
+
+//%PDDM-DEFINE PROTO2_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE)
+//%  {  // optional##FIELD :: NON_ZERO_VALUE
+//%    Message2 *msg = [[Message2 alloc] init];
+//%    XCTAssertFalse(msg.hasOptional##FIELD);
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = NON_ZERO_VALUE;
+//%    XCTAssertTrue(msg.hasOptional##FIELD);
+//%    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    [msg release];
+//%  }
+//%  {  // optional##FIELD :: ZERO_VALUE
+//%    Message2 *msg = [[Message2 alloc] init];
+//%    XCTAssertFalse(msg.hasOptional##FIELD);
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = ZERO_VALUE;
+//%    XCTAssertTrue(msg.hasOptional##FIELD);
+//%    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    [msg release];
+//%  }
+//%
+//%PDDM-DEFINE PROTO2_TEST_HAS_FIELDS()
+//%PROTO2_TEST_HAS_FIELD(Int32, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Int64, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Uint32, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Uint64, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Sint32, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Sint64, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Fixed32, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Fixed64, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Sfixed32, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Sfixed64, 1, 0)
+//%PROTO2_TEST_HAS_FIELD(Float, 1.0f, 0.0f)
+//%PROTO2_TEST_HAS_FIELD(Double, 1.0, 0.0)
+//%PROTO2_TEST_HAS_FIELD(Bool, YES, NO)
+//%PROTO2_TEST_HAS_FIELD(String, @"foo", @"")
+//%PROTO2_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data])
+//%  //
+//%  // Test doesn't apply to optionalGroup/optionalMessage.
+//%  //
+//%
+//%PROTO2_TEST_HAS_FIELD(Enum, Message2_Enum_Bar, Message2_Enum_Foo)
+//%PDDM-EXPAND PROTO2_TEST_HAS_FIELDS()
+// This block of code is generated, do not edit it directly.
+
+  {  // optionalInt32 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalInt32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32));
+    msg.optionalInt32 = 1;
+    XCTAssertTrue(msg.hasOptionalInt32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32));
+    [msg release];
+  }
+  {  // optionalInt32 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalInt32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32));
+    msg.optionalInt32 = 0;
+    XCTAssertTrue(msg.hasOptionalInt32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32));
+    [msg release];
+  }
+
+  {  // optionalInt64 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalInt64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64));
+    msg.optionalInt64 = 1;
+    XCTAssertTrue(msg.hasOptionalInt64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64));
+    [msg release];
+  }
+  {  // optionalInt64 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalInt64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64));
+    msg.optionalInt64 = 0;
+    XCTAssertTrue(msg.hasOptionalInt64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64));
+    [msg release];
+  }
+
+  {  // optionalUint32 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalUint32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32));
+    msg.optionalUint32 = 1;
+    XCTAssertTrue(msg.hasOptionalUint32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32));
+    [msg release];
+  }
+  {  // optionalUint32 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalUint32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32));
+    msg.optionalUint32 = 0;
+    XCTAssertTrue(msg.hasOptionalUint32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32));
+    [msg release];
+  }
+
+  {  // optionalUint64 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalUint64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64));
+    msg.optionalUint64 = 1;
+    XCTAssertTrue(msg.hasOptionalUint64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64));
+    [msg release];
+  }
+  {  // optionalUint64 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalUint64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64));
+    msg.optionalUint64 = 0;
+    XCTAssertTrue(msg.hasOptionalUint64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64));
+    [msg release];
+  }
+
+  {  // optionalSint32 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSint32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32));
+    msg.optionalSint32 = 1;
+    XCTAssertTrue(msg.hasOptionalSint32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32));
+    [msg release];
+  }
+  {  // optionalSint32 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSint32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32));
+    msg.optionalSint32 = 0;
+    XCTAssertTrue(msg.hasOptionalSint32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32));
+    [msg release];
+  }
+
+  {  // optionalSint64 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSint64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64));
+    msg.optionalSint64 = 1;
+    XCTAssertTrue(msg.hasOptionalSint64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64));
+    [msg release];
+  }
+  {  // optionalSint64 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSint64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64));
+    msg.optionalSint64 = 0;
+    XCTAssertTrue(msg.hasOptionalSint64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64));
+    [msg release];
+  }
+
+  {  // optionalFixed32 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFixed32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32));
+    msg.optionalFixed32 = 1;
+    XCTAssertTrue(msg.hasOptionalFixed32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32));
+    [msg release];
+  }
+  {  // optionalFixed32 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFixed32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32));
+    msg.optionalFixed32 = 0;
+    XCTAssertTrue(msg.hasOptionalFixed32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32));
+    [msg release];
+  }
+
+  {  // optionalFixed64 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFixed64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64));
+    msg.optionalFixed64 = 1;
+    XCTAssertTrue(msg.hasOptionalFixed64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64));
+    [msg release];
+  }
+  {  // optionalFixed64 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFixed64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64));
+    msg.optionalFixed64 = 0;
+    XCTAssertTrue(msg.hasOptionalFixed64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64));
+    [msg release];
+  }
+
+  {  // optionalSfixed32 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSfixed32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32));
+    msg.optionalSfixed32 = 1;
+    XCTAssertTrue(msg.hasOptionalSfixed32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32));
+    [msg release];
+  }
+  {  // optionalSfixed32 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSfixed32);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32));
+    msg.optionalSfixed32 = 0;
+    XCTAssertTrue(msg.hasOptionalSfixed32);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32));
+    [msg release];
+  }
+
+  {  // optionalSfixed64 :: 1
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSfixed64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64));
+    msg.optionalSfixed64 = 1;
+    XCTAssertTrue(msg.hasOptionalSfixed64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64));
+    [msg release];
+  }
+  {  // optionalSfixed64 :: 0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalSfixed64);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64));
+    msg.optionalSfixed64 = 0;
+    XCTAssertTrue(msg.hasOptionalSfixed64);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64));
+    [msg release];
+  }
+
+  {  // optionalFloat :: 1.0f
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFloat);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat));
+    msg.optionalFloat = 1.0f;
+    XCTAssertTrue(msg.hasOptionalFloat);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat));
+    [msg release];
+  }
+  {  // optionalFloat :: 0.0f
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalFloat);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat));
+    msg.optionalFloat = 0.0f;
+    XCTAssertTrue(msg.hasOptionalFloat);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat));
+    [msg release];
+  }
+
+  {  // optionalDouble :: 1.0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalDouble);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble));
+    msg.optionalDouble = 1.0;
+    XCTAssertTrue(msg.hasOptionalDouble);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble));
+    [msg release];
+  }
+  {  // optionalDouble :: 0.0
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalDouble);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble));
+    msg.optionalDouble = 0.0;
+    XCTAssertTrue(msg.hasOptionalDouble);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble));
+    [msg release];
+  }
+
+  {  // optionalBool :: YES
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalBool);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool));
+    msg.optionalBool = YES;
+    XCTAssertTrue(msg.hasOptionalBool);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool));
+    [msg release];
+  }
+  {  // optionalBool :: NO
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalBool);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool));
+    msg.optionalBool = NO;
+    XCTAssertTrue(msg.hasOptionalBool);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool));
+    [msg release];
+  }
+
+  {  // optionalString :: @"foo"
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalString);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    msg.optionalString = @"foo";
+    XCTAssertTrue(msg.hasOptionalString);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    [msg release];
+  }
+  {  // optionalString :: @""
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalString);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    msg.optionalString = @"";
+    XCTAssertTrue(msg.hasOptionalString);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    [msg release];
+  }
+
+  {  // optionalBytes :: [@"foo" dataUsingEncoding:NSUTF8StringEncoding]
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalBytes);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertTrue(msg.hasOptionalBytes);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    [msg release];
+  }
+  {  // optionalBytes :: [NSData data]
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalBytes);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [NSData data];
+    XCTAssertTrue(msg.hasOptionalBytes);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    [msg release];
+  }
+
+  //
+  // Test doesn't apply to optionalGroup/optionalMessage.
+  //
+
+  {  // optionalEnum :: Message2_Enum_Bar
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalEnum);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum));
+    msg.optionalEnum = Message2_Enum_Bar;
+    XCTAssertTrue(msg.hasOptionalEnum);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum));
+    [msg release];
+  }
+  {  // optionalEnum :: Message2_Enum_Foo
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(msg.hasOptionalEnum);
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum));
+    msg.optionalEnum = Message2_Enum_Foo;
+    XCTAssertTrue(msg.hasOptionalEnum);
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum));
+    [msg release];
+  }
+
+//%PDDM-EXPAND-END PROTO2_TEST_HAS_FIELDS()
+}
+
+- (void)testProto3SingleFieldHasBehavior {
+  //
+  // Setting to any value including the default value (0) should result has*
+  // being true.
+  //
+
+//%PDDM-DEFINE PROTO3_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE)
+//%  {  // optional##FIELD
+//%    Message3 *msg = [[Message3 alloc] init];
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = NON_ZERO_VALUE;
+//%    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = ZERO_VALUE;
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    [msg release];
+//%  }
+//%
+//%PDDM-DEFINE PROTO3_TEST_HAS_FIELDS()
+//%PROTO3_TEST_HAS_FIELD(Int32, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Int64, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Uint32, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Uint64, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Sint32, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Sint64, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Fixed32, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Fixed64, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Sfixed32, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Sfixed64, 1, 0)
+//%PROTO3_TEST_HAS_FIELD(Float, 1.0f, 0.0f)
+//%PROTO3_TEST_HAS_FIELD(Double, 1.0, 0.0)
+//%PROTO3_TEST_HAS_FIELD(Bool, YES, NO)
+//%PROTO3_TEST_HAS_FIELD(String, @"foo", @"")
+//%PROTO3_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data])
+//%  //
+//%  // Test doesn't apply to optionalGroup/optionalMessage.
+//%  //
+//%
+//%PROTO3_TEST_HAS_FIELD(Enum, Message3_Enum_Bar, Message3_Enum_Foo)
+//%PDDM-EXPAND PROTO3_TEST_HAS_FIELDS()
+// This block of code is generated, do not edit it directly.
+
+  {  // optionalInt32
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32));
+    msg.optionalInt32 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32));
+    msg.optionalInt32 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32));
+    [msg release];
+  }
+
+  {  // optionalInt64
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64));
+    msg.optionalInt64 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64));
+    msg.optionalInt64 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64));
+    [msg release];
+  }
+
+  {  // optionalUint32
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32));
+    msg.optionalUint32 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32));
+    msg.optionalUint32 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32));
+    [msg release];
+  }
+
+  {  // optionalUint64
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64));
+    msg.optionalUint64 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64));
+    msg.optionalUint64 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64));
+    [msg release];
+  }
+
+  {  // optionalSint32
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32));
+    msg.optionalSint32 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32));
+    msg.optionalSint32 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32));
+    [msg release];
+  }
+
+  {  // optionalSint64
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64));
+    msg.optionalSint64 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64));
+    msg.optionalSint64 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64));
+    [msg release];
+  }
+
+  {  // optionalFixed32
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32));
+    msg.optionalFixed32 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32));
+    msg.optionalFixed32 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32));
+    [msg release];
+  }
+
+  {  // optionalFixed64
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64));
+    msg.optionalFixed64 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64));
+    msg.optionalFixed64 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64));
+    [msg release];
+  }
+
+  {  // optionalSfixed32
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32));
+    msg.optionalSfixed32 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32));
+    msg.optionalSfixed32 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32));
+    [msg release];
+  }
+
+  {  // optionalSfixed64
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64));
+    msg.optionalSfixed64 = 1;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64));
+    msg.optionalSfixed64 = 0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64));
+    [msg release];
+  }
+
+  {  // optionalFloat
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat));
+    msg.optionalFloat = 1.0f;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat));
+    msg.optionalFloat = 0.0f;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat));
+    [msg release];
+  }
+
+  {  // optionalDouble
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble));
+    msg.optionalDouble = 1.0;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble));
+    msg.optionalDouble = 0.0;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble));
+    [msg release];
+  }
+
+  {  // optionalBool
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool));
+    msg.optionalBool = YES;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool));
+    msg.optionalBool = NO;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool));
+    [msg release];
+  }
+
+  {  // optionalString
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    msg.optionalString = @"foo";
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    msg.optionalString = @"";
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    [msg release];
+  }
+
+  {  // optionalBytes
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [NSData data];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    [msg release];
+  }
+
+  //
+  // Test doesn't apply to optionalGroup/optionalMessage.
+  //
+
+  {  // optionalEnum
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum));
+    msg.optionalEnum = Message3_Enum_Bar;
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum));
+    msg.optionalEnum = Message3_Enum_Foo;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum));
+    [msg release];
+  }
+
+//%PDDM-EXPAND-END PROTO3_TEST_HAS_FIELDS()
+}
+
+- (void)testAccessingProto2UnknownEnumValues {
+  Message2 *msg = [[Message2 alloc] init];
+
+  // Set it to something non zero, try and confirm it doesn't change.
+
+  msg.optionalEnum = Message2_Enum_Bar;
+  XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException,
+                               NSInvalidArgumentException);
+  XCTAssertEqual(msg.optionalEnum, Message2_Enum_Bar);
+
+  msg.oneofEnum = Message2_Enum_Bar;
+  XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException,
+                               NSInvalidArgumentException);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
+
+  [msg release];
+}
+
+- (void)testAccessingProto3UnknownEnumValues {
+  Message3 *msg = [[Message3 alloc] init];
+
+  // Set it to something non zero, try and confirm it doesn't change.
+
+  msg.optionalEnum = Message3_Enum_Bar;
+  XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException,
+                               NSInvalidArgumentException);
+  XCTAssertEqual(msg.optionalEnum, Message3_Enum_Bar);
+
+  msg.oneofEnum = Message3_Enum_Bar;
+  XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException,
+                               NSInvalidArgumentException);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar);
+
+  // Set via raw api to confirm it works.
+
+  SetMessage3_OptionalEnum_RawValue(msg, 666);
+  XCTAssertEqual(msg.optionalEnum,
+                 Message3_Enum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(Message3_OptionalEnum_RawValue(msg), 666);
+
+  SetMessage3_OneofEnum_RawValue(msg, 666);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(Message3_OneofEnum_RawValue(msg), 666);
+
+  [msg release];
+}
+
+- (void)testProto2OneofBasicBehaviors {
+  Message2 *msg = [[Message2 alloc] init];
+
+  NSString *oneofStringDefault = @"string";
+  NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding];
+
+  // Nothing set.
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+
+  // Set, check the case, check everyone has default but the one, confirm case
+  // didn't change.
+
+  msg.oneofInt32 = 1;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+  XCTAssertEqual(msg.oneofInt32, 1);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+
+  msg.oneofInt64 = 2;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 2);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
+
+  msg.oneofUint32 = 3;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 3U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
+
+  msg.oneofUint64 = 4;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 4U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
+
+  msg.oneofSint32 = 5;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 5);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
+
+  msg.oneofSint64 = 6;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 6);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
+
+  msg.oneofFixed32 = 7;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 7U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
+
+  msg.oneofFixed64 = 8;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 8U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
+
+  msg.oneofSfixed32 = 9;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 9);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
+
+  msg.oneofSfixed64 = 10;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 10);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
+
+  msg.oneofFloat = 11.0f;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 11.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
+
+  msg.oneofDouble = 12.0;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 12.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
+
+  msg.oneofBool = NO;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool);
+
+  msg.oneofString = @"foo";
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, @"foo");
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString);
+
+  msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes,
+                        [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
+
+  Message2_OneofGroup *group = [Message2_OneofGroup message];
+  msg.oneofGroup = group;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertEqual(msg.oneofGroup, group);  // Pointer compare.
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+
+  Message2 *subMessage = [Message2 message];
+  msg.oneofMessage = subMessage;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotEqual(msg.oneofGroup, group);      // Pointer compare.
+  XCTAssertEqual(msg.oneofMessage, subMessage);  // Pointer compare.
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+
+  msg.oneofEnum = Message2_Enum_Bar;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
+  XCTAssertEqual(msg.oneofInt32, 100);
+  XCTAssertEqual(msg.oneofInt64, 101);
+  XCTAssertEqual(msg.oneofUint32, 102U);
+  XCTAssertEqual(msg.oneofUint64, 103U);
+  XCTAssertEqual(msg.oneofSint32, 104);
+  XCTAssertEqual(msg.oneofSint64, 105);
+  XCTAssertEqual(msg.oneofFixed32, 106U);
+  XCTAssertEqual(msg.oneofFixed64, 107U);
+  XCTAssertEqual(msg.oneofSfixed32, 108);
+  XCTAssertEqual(msg.oneofSfixed64, 109);
+  XCTAssertEqual(msg.oneofFloat, 110.0f);
+  XCTAssertEqual(msg.oneofDouble, 111.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofGroup);
+  XCTAssertNotEqual(msg.oneofGroup, group);  // Pointer compare.
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertNotEqual(msg.oneofMessage, subMessage);  // Pointer compare.
+  XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
+
+  // Test setting/calling clear clearing.
+
+  [msg release];
+  msg = [[Message2 alloc] init];
+
+  uint32_t values[] = {
+    Message2_O_OneOfCase_OneofInt32,
+    Message2_O_OneOfCase_OneofInt64,
+    Message2_O_OneOfCase_OneofUint32,
+    Message2_O_OneOfCase_OneofUint64,
+    Message2_O_OneOfCase_OneofSint32,
+    Message2_O_OneOfCase_OneofSint64,
+    Message2_O_OneOfCase_OneofFixed32,
+    Message2_O_OneOfCase_OneofFixed64,
+    Message2_O_OneOfCase_OneofSfixed32,
+    Message2_O_OneOfCase_OneofSfixed64,
+    Message2_O_OneOfCase_OneofFloat,
+    Message2_O_OneOfCase_OneofDouble,
+    Message2_O_OneOfCase_OneofBool,
+    Message2_O_OneOfCase_OneofString,
+    Message2_O_OneOfCase_OneofBytes,
+    Message2_O_OneOfCase_OneofGroup,
+    Message2_O_OneOfCase_OneofMessage,
+    Message2_O_OneOfCase_OneofEnum,
+  };
+
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+    switch (values[i]) {
+      case Message2_O_OneOfCase_OneofInt32:
+        msg.oneofInt32 = 1;
+        break;
+      case Message2_O_OneOfCase_OneofInt64:
+        msg.oneofInt64 = 2;
+        break;
+      case Message2_O_OneOfCase_OneofUint32:
+        msg.oneofUint32 = 3;
+        break;
+      case Message2_O_OneOfCase_OneofUint64:
+        msg.oneofUint64 = 4;
+        break;
+      case Message2_O_OneOfCase_OneofSint32:
+        msg.oneofSint32 = 5;
+        break;
+      case Message2_O_OneOfCase_OneofSint64:
+        msg.oneofSint64 = 6;
+        break;
+      case Message2_O_OneOfCase_OneofFixed32:
+        msg.oneofFixed32 = 7;
+        break;
+      case Message2_O_OneOfCase_OneofFixed64:
+        msg.oneofFixed64 = 8;
+        break;
+      case Message2_O_OneOfCase_OneofSfixed32:
+        msg.oneofSfixed32 = 9;
+        break;
+      case Message2_O_OneOfCase_OneofSfixed64:
+        msg.oneofSfixed64 = 10;
+        break;
+      case Message2_O_OneOfCase_OneofFloat:
+        msg.oneofFloat = 11.0f;
+        break;
+      case Message2_O_OneOfCase_OneofDouble:
+        msg.oneofDouble = 12.0;
+        break;
+      case Message2_O_OneOfCase_OneofBool:
+        msg.oneofBool = YES;
+        break;
+      case Message2_O_OneOfCase_OneofString:
+        msg.oneofString = @"foo";
+        break;
+      case Message2_O_OneOfCase_OneofBytes:
+        msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+        break;
+      case Message2_O_OneOfCase_OneofGroup:
+        msg.oneofGroup = group;
+        break;
+      case Message2_O_OneOfCase_OneofMessage:
+        msg.oneofMessage = subMessage;
+        break;
+      case Message2_O_OneOfCase_OneofEnum:
+        msg.oneofEnum = Message2_Enum_Bar;
+        break;
+      default:
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
+        break;
+    }
+
+    XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i);
+    // No need to check the value was set, the above tests did that.
+    Message2_ClearOOneOfCase(msg);
+    // Nothing in the case.
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase,
+                   "Loop: %zd", i);
+    // Confirm everything is back to defaults after a clear.
+    XCTAssertEqual(msg.oneofInt32, 100, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofInt64, 101, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint32, 102U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint64, 103U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint32, 104, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint64, 105, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed32, 106U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed64, 107U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed32, 108, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed64, 109, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFloat, 110.0f, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofDouble, 111.0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofBool, YES, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i);
+    XCTAssertNotNil(msg.oneofGroup, "Loop: %zd", i);
+    XCTAssertNotEqual(msg.oneofGroup, group, "Loop: %zd",
+                      i);  // Pointer compare.
+    XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i);
+    XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd",
+                      i);  // Pointer compare.
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz, "Loop: %zd", i);
+  }
+
+  [msg release];
+}
+
+- (void)testProto3OneofBasicBehaviors {
+  Message3 *msg = [[Message3 alloc] init];
+
+  NSString *oneofStringDefault = @"";
+  NSData *oneofBytesDefault = [NSData data];
+
+  // Nothing set.
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+
+  // Set, check the case, check everyone has default but the one, confirm case
+  // didn't change.
+
+  msg.oneofInt32 = 1;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+  XCTAssertEqual(msg.oneofInt32, 1);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+
+  msg.oneofInt64 = 2;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 2);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
+
+  msg.oneofUint32 = 3;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 3U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
+
+  msg.oneofUint64 = 4;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 4U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
+
+  msg.oneofSint32 = 5;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 5);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
+
+  msg.oneofSint64 = 6;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 6);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
+
+  msg.oneofFixed32 = 7;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 7U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
+
+  msg.oneofFixed64 = 8;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 8U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
+
+  msg.oneofSfixed32 = 9;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 9);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
+
+  msg.oneofSfixed64 = 10;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 10);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
+
+  msg.oneofFloat = 11.0f;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 11.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
+
+  msg.oneofDouble = 12.0;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 12.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
+
+  msg.oneofBool = YES;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, YES);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool);
+
+  msg.oneofString = @"foo";
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, @"foo");
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString);
+
+  msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes,
+                        [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
+
+  Message3 *subMessage = [Message3 message];
+  msg.oneofMessage = subMessage;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertEqual(msg.oneofMessage, subMessage);  // Pointer compare.
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+
+  msg.oneofEnum = Message3_Enum_Bar;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
+  XCTAssertEqual(msg.oneofInt32, 0);
+  XCTAssertEqual(msg.oneofInt64, 0);
+  XCTAssertEqual(msg.oneofUint32, 0U);
+  XCTAssertEqual(msg.oneofUint64, 0U);
+  XCTAssertEqual(msg.oneofSint32, 0);
+  XCTAssertEqual(msg.oneofSint64, 0);
+  XCTAssertEqual(msg.oneofFixed32, 0U);
+  XCTAssertEqual(msg.oneofFixed64, 0U);
+  XCTAssertEqual(msg.oneofSfixed32, 0);
+  XCTAssertEqual(msg.oneofSfixed64, 0);
+  XCTAssertEqual(msg.oneofFloat, 0.0f);
+  XCTAssertEqual(msg.oneofDouble, 0.0);
+  XCTAssertEqual(msg.oneofBool, NO);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  XCTAssertNotNil(msg.oneofMessage);
+  XCTAssertNotEqual(msg.oneofMessage, subMessage);  // Pointer compare.
+  XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
+
+  // Test setting/calling clear clearing.
+
+  [msg release];
+  msg = [[Message3 alloc] init];
+
+  uint32_t values[] = {
+    Message3_O_OneOfCase_OneofInt32,
+    Message3_O_OneOfCase_OneofInt64,
+    Message3_O_OneOfCase_OneofUint32,
+    Message3_O_OneOfCase_OneofUint64,
+    Message3_O_OneOfCase_OneofSint32,
+    Message3_O_OneOfCase_OneofSint64,
+    Message3_O_OneOfCase_OneofFixed32,
+    Message3_O_OneOfCase_OneofFixed64,
+    Message3_O_OneOfCase_OneofSfixed32,
+    Message3_O_OneOfCase_OneofSfixed64,
+    Message3_O_OneOfCase_OneofFloat,
+    Message3_O_OneOfCase_OneofDouble,
+    Message3_O_OneOfCase_OneofBool,
+    Message3_O_OneOfCase_OneofString,
+    Message3_O_OneOfCase_OneofBytes,
+    Message3_O_OneOfCase_OneofMessage,
+    Message3_O_OneOfCase_OneofEnum,
+  };
+
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+    switch (values[i]) {
+      case Message3_O_OneOfCase_OneofInt32:
+        msg.oneofInt32 = 1;
+        break;
+      case Message3_O_OneOfCase_OneofInt64:
+        msg.oneofInt64 = 2;
+        break;
+      case Message3_O_OneOfCase_OneofUint32:
+        msg.oneofUint32 = 3;
+        break;
+      case Message3_O_OneOfCase_OneofUint64:
+        msg.oneofUint64 = 4;
+        break;
+      case Message3_O_OneOfCase_OneofSint32:
+        msg.oneofSint32 = 5;
+        break;
+      case Message3_O_OneOfCase_OneofSint64:
+        msg.oneofSint64 = 6;
+        break;
+      case Message3_O_OneOfCase_OneofFixed32:
+        msg.oneofFixed32 = 7;
+        break;
+      case Message3_O_OneOfCase_OneofFixed64:
+        msg.oneofFixed64 = 8;
+        break;
+      case Message3_O_OneOfCase_OneofSfixed32:
+        msg.oneofSfixed32 = 9;
+        break;
+      case Message3_O_OneOfCase_OneofSfixed64:
+        msg.oneofSfixed64 = 10;
+        break;
+      case Message3_O_OneOfCase_OneofFloat:
+        msg.oneofFloat = 11.0f;
+        break;
+      case Message3_O_OneOfCase_OneofDouble:
+        msg.oneofDouble = 12.0;
+        break;
+      case Message3_O_OneOfCase_OneofBool:
+        msg.oneofBool = YES;
+        break;
+      case Message3_O_OneOfCase_OneofString:
+        msg.oneofString = @"foo";
+        break;
+      case Message3_O_OneOfCase_OneofBytes:
+        msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+        break;
+      case Message3_O_OneOfCase_OneofMessage:
+        msg.oneofMessage = subMessage;
+        break;
+      case Message3_O_OneOfCase_OneofEnum:
+        msg.oneofEnum = Message3_Enum_Baz;
+        break;
+      default:
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
+        break;
+    }
+
+    XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i);
+    // No need to check the value was set, the above tests did that.
+    Message3_ClearOOneOfCase(msg);
+    // Nothing in the case.
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase,
+                   "Loop: %zd", i);
+    // Confirm everything is back to defaults after a clear.
+    XCTAssertEqual(msg.oneofInt32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofInt64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint32, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint64, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed32, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed64, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFloat, 0.0f, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofDouble, 0.0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofBool, NO, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i);
+    XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i);
+    XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd",
+                      i);  // Pointer compare.
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo, "Loop: %zd", i);
+  }
+
+  [msg release];
+}
+
+- (void)testCopyingMakesUniqueObjects {
+  const int repeatCount = 5;
+  TestAllTypes *msg1 = [TestAllTypes message];
+  [self setAllFields:msg1 repeatedCount:repeatCount];
+
+  TestAllTypes *msg2 = [[msg1 copy] autorelease];
+
+  XCTAssertNotEqual(msg1, msg2);      // Ptr compare, new object.
+  XCTAssertEqualObjects(msg1, msg2);  // Equal values.
+
+  // Pointer comparisions, different objects.
+
+  XCTAssertNotEqual(msg1.optionalGroup, msg2.optionalGroup);
+  XCTAssertNotEqual(msg1.optionalNestedMessage, msg2.optionalNestedMessage);
+  XCTAssertNotEqual(msg1.optionalForeignMessage, msg2.optionalForeignMessage);
+  XCTAssertNotEqual(msg1.optionalImportMessage, msg2.optionalImportMessage);
+
+  XCTAssertNotEqual(msg1.repeatedInt32Array, msg2.repeatedInt32Array);
+  XCTAssertNotEqual(msg1.repeatedInt64Array, msg2.repeatedInt64Array);
+  XCTAssertNotEqual(msg1.repeatedUint32Array, msg2.repeatedUint32Array);
+  XCTAssertNotEqual(msg1.repeatedUint64Array, msg2.repeatedUint64Array);
+  XCTAssertNotEqual(msg1.repeatedSint32Array, msg2.repeatedSint32Array);
+  XCTAssertNotEqual(msg1.repeatedSint64Array, msg2.repeatedSint64Array);
+  XCTAssertNotEqual(msg1.repeatedFixed32Array, msg2.repeatedFixed32Array);
+  XCTAssertNotEqual(msg1.repeatedFixed64Array, msg2.repeatedFixed64Array);
+  XCTAssertNotEqual(msg1.repeatedSfixed32Array, msg2.repeatedSfixed32Array);
+  XCTAssertNotEqual(msg1.repeatedSfixed64Array, msg2.repeatedSfixed64Array);
+  XCTAssertNotEqual(msg1.repeatedFloatArray, msg2.repeatedFloatArray);
+  XCTAssertNotEqual(msg1.repeatedDoubleArray, msg2.repeatedDoubleArray);
+  XCTAssertNotEqual(msg1.repeatedBoolArray, msg2.repeatedBoolArray);
+  XCTAssertNotEqual(msg1.repeatedStringArray, msg2.repeatedStringArray);
+  XCTAssertNotEqual(msg1.repeatedBytesArray, msg2.repeatedBytesArray);
+  XCTAssertNotEqual(msg1.repeatedGroupArray, msg2.repeatedGroupArray);
+  XCTAssertNotEqual(msg1.repeatedNestedMessageArray,
+                    msg2.repeatedNestedMessageArray);
+  XCTAssertNotEqual(msg1.repeatedForeignMessageArray,
+                    msg2.repeatedForeignMessageArray);
+  XCTAssertNotEqual(msg1.repeatedImportMessageArray,
+                    msg2.repeatedImportMessageArray);
+  XCTAssertNotEqual(msg1.repeatedNestedEnumArray, msg2.repeatedNestedEnumArray);
+  XCTAssertNotEqual(msg1.repeatedForeignEnumArray,
+                    msg2.repeatedForeignEnumArray);
+  XCTAssertNotEqual(msg1.repeatedImportEnumArray, msg2.repeatedImportEnumArray);
+  XCTAssertNotEqual(msg1.repeatedStringPieceArray,
+                    msg2.repeatedStringPieceArray);
+  XCTAssertNotEqual(msg1.repeatedCordArray, msg2.repeatedCordArray);
+
+  for (int i = 0; i < repeatCount; i++) {
+    XCTAssertNotEqual(msg1.repeatedNestedMessageArray[i],
+                      msg2.repeatedNestedMessageArray[i]);
+    XCTAssertNotEqual(msg1.repeatedForeignMessageArray[i],
+                      msg2.repeatedForeignMessageArray[i]);
+    XCTAssertNotEqual(msg1.repeatedImportMessageArray[i],
+                      msg2.repeatedImportMessageArray[i]);
+  }
+}
+
+- (void)testCopyingMapsMakesUniqueObjects {
+  TestMap *msg1 = [TestMap message];
+  [self setAllMapFields:msg1 numEntries:5];
+
+  TestMap *msg2 = [[msg1 copy] autorelease];
+
+  XCTAssertNotEqual(msg1, msg2);      // Ptr compare, new object.
+  XCTAssertEqualObjects(msg1, msg2);  // Equal values.
+
+  // Pointer comparisions, different objects.
+  XCTAssertNotEqual(msg1.mapInt32Int32, msg2.mapInt32Int32);
+  XCTAssertNotEqual(msg1.mapInt64Int64, msg2.mapInt64Int64);
+  XCTAssertNotEqual(msg1.mapUint32Uint32, msg2.mapUint32Uint32);
+  XCTAssertNotEqual(msg1.mapUint64Uint64, msg2.mapUint64Uint64);
+  XCTAssertNotEqual(msg1.mapSint32Sint32, msg2.mapSint32Sint32);
+  XCTAssertNotEqual(msg1.mapSint64Sint64, msg2.mapSint64Sint64);
+  XCTAssertNotEqual(msg1.mapFixed32Fixed32, msg2.mapFixed32Fixed32);
+  XCTAssertNotEqual(msg1.mapFixed64Fixed64, msg2.mapFixed64Fixed64);
+  XCTAssertNotEqual(msg1.mapSfixed32Sfixed32, msg2.mapSfixed32Sfixed32);
+  XCTAssertNotEqual(msg1.mapSfixed64Sfixed64, msg2.mapSfixed64Sfixed64);
+  XCTAssertNotEqual(msg1.mapInt32Float, msg2.mapInt32Float);
+  XCTAssertNotEqual(msg1.mapInt32Double, msg2.mapInt32Double);
+  XCTAssertNotEqual(msg1.mapBoolBool, msg2.mapBoolBool);
+  XCTAssertNotEqual(msg1.mapStringString, msg2.mapStringString);
+  XCTAssertNotEqual(msg1.mapInt32Bytes, msg2.mapInt32Bytes);
+  XCTAssertNotEqual(msg1.mapInt32Enum, msg2.mapInt32Enum);
+  XCTAssertNotEqual(msg1.mapInt32ForeignMessage, msg2.mapInt32ForeignMessage);
+
+  // Ensure the messages are unique per map.
+  [msg1.mapInt32ForeignMessage
+      enumerateKeysAndObjectsUsingBlock:^(int32_t key, id value, BOOL *stop) {
+#pragma unused(stop)
+        ForeignMessage *subMsg2 = [msg2.mapInt32ForeignMessage objectForKey:key];
+        XCTAssertNotEqual(value, subMsg2);  // Ptr compare, new object.
+      }];
+}
+
+#pragma mark - Subset from from map_tests.cc
+
+// TEST(GeneratedMapFieldTest, IsInitialized)
+- (void)testMap_IsInitialized {
+  TestRequiredMessageMap *msg = [[TestRequiredMessageMap alloc] init];
+
+  // Add an uninitialized message.
+  TestRequired *subMsg = [[TestRequired alloc] init];
+  [msg.mapField setObject:subMsg forKey:0];
+  XCTAssertFalse(msg.initialized);
+
+  // Initialize uninitialized message
+  subMsg.a = 0;
+  subMsg.b = 0;
+  subMsg.c = 0;
+  XCTAssertTrue(msg.initialized);
+
+  [subMsg release];
+  [msg release];
+}
+
+@end
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
new file mode 100644
index 0000000..0d811a9
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -0,0 +1,1105 @@
+// 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.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBMessage.h"
+
+#import "google/protobuf/MapProto2Unittest.pbobjc.h"
+#import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h"
+#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
+
+static NSData *DataFromCStr(const char *str) {
+  return [NSData dataWithBytes:str length:strlen(str)];
+}
+
+@interface MessageSerializationTests : GPBTestCase
+@end
+
+@implementation MessageSerializationTests
+
+// TODO(thomasvl): Pull tests over from GPBMessageTests that are serialization
+// specific.
+
+- (void)testProto3SerializationHandlingDefaults {
+  // Proto2 covered in other tests.
+
+  Message3 *msg = [[Message3 alloc] init];
+
+  // Add defaults, no output.
+
+  NSData *data = [msg data];
+  XCTAssertEqual([data length], 0U);
+
+  // All zeros, still nothing.
+
+  msg.optionalInt32 = 0;
+  msg.optionalInt64 = 0;
+  msg.optionalUint32 = 0;
+  msg.optionalUint64 = 0;
+  msg.optionalSint32 = 0;
+  msg.optionalSint64 = 0;
+  msg.optionalFixed32 = 0;
+  msg.optionalFixed64 = 0;
+  msg.optionalSfixed32 = 0;
+  msg.optionalSfixed64 = 0;
+  msg.optionalFloat = 0.0f;
+  msg.optionalDouble = 0.0;
+  msg.optionalBool = NO;
+  msg.optionalString = @"";
+  msg.optionalBytes = [NSData data];
+  msg.optionalEnum = Message3_Enum_Foo;  // first value
+
+  data = [msg data];
+  XCTAssertEqual([data length], 0U);
+
+  // The two that also take nil as nothing.
+
+  msg.optionalString = nil;
+  msg.optionalBytes = nil;
+
+  data = [msg data];
+  XCTAssertEqual([data length], 0U);
+
+  // Set one field...
+
+  msg.optionalInt32 = 1;
+
+  data = [msg data];
+  const uint8_t expectedBytes[] = {0x08, 0x01};
+  NSData *expected = [NSData dataWithBytes:expectedBytes length:2];
+  XCTAssertEqualObjects(data, expected);
+
+  // Back to zero...
+
+  msg.optionalInt32 = 0;
+
+  data = [msg data];
+  XCTAssertEqual([data length], 0U);
+
+  [msg release];
+}
+
+- (void)testProto3DroppingUnknownFields {
+  DropUnknownsFooWithExtraFields *fooWithExtras =
+      [[DropUnknownsFooWithExtraFields alloc] init];
+
+  fooWithExtras.int32Value = 1;
+  fooWithExtras.enumValue = DropUnknownsFooWithExtraFields_NestedEnum_Baz;
+  fooWithExtras.extraInt32Value = 2;
+
+  NSData *data = [fooWithExtras data];
+  XCTAssertNotNil(data);
+  DropUnknownsFoo *foo = [DropUnknownsFoo parseFromData:data error:NULL];
+
+  XCTAssertEqual(foo.int32Value, 1);
+  XCTAssertEqual(foo.enumValue, DropUnknownsFoo_NestedEnum_Baz);
+  // Nothing should end up in the unknowns.
+  XCTAssertEqual([foo.unknownFields countOfFields], 0U);
+
+  [fooWithExtras release];
+  data = [foo data];
+  fooWithExtras =
+      [DropUnknownsFooWithExtraFields parseFromData:data error:NULL];
+  XCTAssertEqual(fooWithExtras.int32Value, 1);
+  XCTAssertEqual(fooWithExtras.enumValue,
+                 DropUnknownsFooWithExtraFields_NestedEnum_Baz);
+  // And the extra value is gone (back to the default).
+  XCTAssertEqual(fooWithExtras.extraInt32Value, 0);
+  XCTAssertEqual([foo.unknownFields countOfFields], 0U);
+}
+
+- (void)testProto2UnknownEnumToUnknownField {
+  Message3 *orig = [[Message3 alloc] init];
+
+  orig.optionalEnum = Message3_Enum_Extra3;
+  orig.repeatedEnumArray =
+      [GPBEnumArray arrayWithValidationFunction:Message3_Enum_IsValidValue
+                                       rawValue:Message3_Enum_Extra3];
+  orig.oneofEnum = Message3_Enum_Extra3;
+
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
+  Message2 *msg = [[Message2 alloc] initWithData:data error:NULL];
+
+  // None of the fields should be set.
+
+  XCTAssertFalse(msg.hasOptionalEnum);
+  XCTAssertEqual(msg.repeatedEnumArray.count, 0U);
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase);
+
+  // All the values should be in unknown fields.
+
+  GPBUnknownFieldSet *unknownFields = msg.unknownFields;
+
+  XCTAssertEqual([unknownFields countOfFields], 3U);
+  XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OptionalEnum]);
+  XCTAssertTrue(
+      [unknownFields hasField:Message2_FieldNumber_RepeatedEnumArray]);
+  XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OneofEnum]);
+
+  GPBUnknownField *field =
+      [unknownFields getField:Message2_FieldNumber_OptionalEnum];
+  XCTAssertEqual(field.varintList.count, 1U);
+  XCTAssertEqual([field.varintList valueAtIndex:0],
+                 (uint64_t)Message3_Enum_Extra3);
+
+  field = [unknownFields getField:Message2_FieldNumber_RepeatedEnumArray];
+  XCTAssertEqual(field.varintList.count, 1U);
+  XCTAssertEqual([field.varintList valueAtIndex:0], (uint64_t)Message3_Enum_Extra3);
+
+  field = [unknownFields getField:Message2_FieldNumber_OneofEnum];
+  XCTAssertEqual(field.varintList.count, 1U);
+  XCTAssertEqual([field.varintList valueAtIndex:0],
+                 (uint64_t)Message3_Enum_Extra3);
+
+  [msg release];
+  [orig release];
+}
+
+- (void)testProto3UnknownEnumPreserving {
+  UnknownEnumsMyMessagePlusExtra *orig =
+      [UnknownEnumsMyMessagePlusExtra message];
+
+  orig.e = UnknownEnumsMyEnumPlusExtra_EExtra;
+  orig.repeatedEArray = [GPBEnumArray
+      arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue
+                         rawValue:UnknownEnumsMyEnumPlusExtra_EExtra];
+  orig.repeatedPackedEArray = [GPBEnumArray
+      arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue
+                         rawValue:UnknownEnumsMyEnumPlusExtra_EExtra];
+  orig.oneofE1 = UnknownEnumsMyEnumPlusExtra_EExtra;
+
+  // Everything should be there via raw values.
+
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
+  UnknownEnumsMyMessage *msg =
+      [UnknownEnumsMyMessage parseFromData:data error:NULL];
+
+  XCTAssertEqual(msg.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(msg),
+                 UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(msg.repeatedEArray.count, 1U);
+  XCTAssertEqual([msg.repeatedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([msg.repeatedEArray rawValueAtIndex:0],
+                 (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(msg.repeatedPackedEArray.count, 1U);
+  XCTAssertEqual([msg.repeatedPackedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual([msg.repeatedPackedEArray rawValueAtIndex:0],
+                 (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(msg.oneofE1,
+                 UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
+  XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(msg),
+                 UnknownEnumsMyEnumPlusExtra_EExtra);
+
+  // Everything should go out and come back.
+
+  data = [msg data];
+  orig = [UnknownEnumsMyMessagePlusExtra parseFromData:data error:NULL];
+
+  XCTAssertEqual(orig.e, UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(orig.repeatedEArray.count, 1U);
+  XCTAssertEqual([orig.repeatedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(orig.repeatedPackedEArray.count, 1U);
+  XCTAssertEqual([orig.repeatedPackedEArray valueAtIndex:0],
+                 UnknownEnumsMyEnumPlusExtra_EExtra);
+  XCTAssertEqual(orig.oneofE1, UnknownEnumsMyEnumPlusExtra_EExtra);
+}
+
+//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF(MESSAGE, FIELD, VALUE)
+//%TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, )
+//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, EQ_SUFFIX)
+//%  {  // oneof##FIELD
+//%    MESSAGE *orig = [[MESSAGE alloc] init];
+//%    orig.oneof##FIELD = VALUE;
+//%    XCTAssertEqual(orig.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
+//%    NSData *data = [orig data];
+//%    XCTAssertNotNil(data);
+//%    MESSAGE *msg = [MESSAGE parseFromData:data error:NULL];
+//%    XCTAssertEqual(msg.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
+//%    XCTAssertEqual##EQ_SUFFIX(msg.oneof##FIELD, VALUE);
+//%    [orig release];
+//%  }
+//%
+//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOFS(SYNTAX, BOOL_NON_DEFAULT)
+//%- (void)testProto##SYNTAX##RoundTripOneof {
+//%
+//%GROUP_INIT##SYNTAX()  Message##SYNTAX *subMessage = [[Message##SYNTAX alloc] init];
+//%  XCTAssertNotNil(subMessage);
+//%  subMessage.optionalInt32 = 666;
+//%
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int32, 1)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int64, 2)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint32, 3U)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint64, 4U)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint32, 5)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint64, 6)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed32, 7U)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed64, 8U)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed32, 9)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed64, 10)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Float, 11.0f)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Double, 12.0)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Bool, BOOL_NON_DEFAULT)
+//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, String, @"foo", Objects)
+//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Bytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding], Objects)
+//%GROUP_TEST##SYNTAX()TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Message, subMessage, Objects)
+//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Enum, Message2_Enum_Bar)
+//%GROUP_CLEANUP##SYNTAX()  [subMessage release];
+//%}
+//%
+//%PDDM-DEFINE GROUP_INIT2()
+//%  Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init];
+//%  XCTAssertNotNil(group);
+//%  group.a = 777;
+//%
+//%PDDM-DEFINE GROUP_CLEANUP2()
+//%  [group release];
+//%
+//%PDDM-DEFINE GROUP_TEST2()
+//%TEST_ROUNDTRIP_ONEOF_ADV(Message2, Group, group, Objects)
+//%
+//%PDDM-DEFINE GROUP_INIT3()
+// Empty
+//%PDDM-DEFINE GROUP_CLEANUP3()
+// Empty
+//%PDDM-DEFINE GROUP_TEST3()
+//%  // Not "group" in proto3.
+//%
+//%
+//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(2, NO)
+// This block of code is generated, do not edit it directly.
+
+- (void)testProto2RoundTripOneof {
+
+  Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init];
+  XCTAssertNotNil(group);
+  group.a = 777;
+  Message2 *subMessage = [[Message2 alloc] init];
+  XCTAssertNotNil(subMessage);
+  subMessage.optionalInt32 = 666;
+
+  {  // oneofInt32
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofInt32 = 1;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
+    XCTAssertEqual(msg.oneofInt32, 1);
+    [orig release];
+  }
+
+  {  // oneofInt64
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofInt64 = 2;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
+    XCTAssertEqual(msg.oneofInt64, 2);
+    [orig release];
+  }
+
+  {  // oneofUint32
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofUint32 = 3U;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
+    XCTAssertEqual(msg.oneofUint32, 3U);
+    [orig release];
+  }
+
+  {  // oneofUint64
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofUint64 = 4U;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
+    XCTAssertEqual(msg.oneofUint64, 4U);
+    [orig release];
+  }
+
+  {  // oneofSint32
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofSint32 = 5;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
+    XCTAssertEqual(msg.oneofSint32, 5);
+    [orig release];
+  }
+
+  {  // oneofSint64
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofSint64 = 6;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
+    XCTAssertEqual(msg.oneofSint64, 6);
+    [orig release];
+  }
+
+  {  // oneofFixed32
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofFixed32 = 7U;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
+    XCTAssertEqual(msg.oneofFixed32, 7U);
+    [orig release];
+  }
+
+  {  // oneofFixed64
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofFixed64 = 8U;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
+    XCTAssertEqual(msg.oneofFixed64, 8U);
+    [orig release];
+  }
+
+  {  // oneofSfixed32
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofSfixed32 = 9;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
+    XCTAssertEqual(msg.oneofSfixed32, 9);
+    [orig release];
+  }
+
+  {  // oneofSfixed64
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofSfixed64 = 10;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
+    XCTAssertEqual(msg.oneofSfixed64, 10);
+    [orig release];
+  }
+
+  {  // oneofFloat
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofFloat = 11.0f;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
+    XCTAssertEqual(msg.oneofFloat, 11.0f);
+    [orig release];
+  }
+
+  {  // oneofDouble
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofDouble = 12.0;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
+    XCTAssertEqual(msg.oneofDouble, 12.0);
+    [orig release];
+  }
+
+  {  // oneofBool
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofBool = NO;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBool);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool);
+    XCTAssertEqual(msg.oneofBool, NO);
+    [orig release];
+  }
+
+  {  // oneofString
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofString = @"foo";
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofString);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString);
+    XCTAssertEqualObjects(msg.oneofString, @"foo");
+    [orig release];
+  }
+
+  {  // oneofBytes
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
+    XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+    [orig release];
+  }
+
+  {  // oneofGroup
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofGroup = group;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
+    XCTAssertEqualObjects(msg.oneofGroup, group);
+    [orig release];
+  }
+
+  {  // oneofMessage
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofMessage = subMessage;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
+    XCTAssertEqualObjects(msg.oneofMessage, subMessage);
+    [orig release];
+  }
+
+  {  // oneofEnum
+    Message2 *orig = [[Message2 alloc] init];
+    orig.oneofEnum = Message2_Enum_Bar;
+    XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
+    [orig release];
+  }
+
+  [group release];
+  [subMessage release];
+}
+
+//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(3, YES)
+// This block of code is generated, do not edit it directly.
+
+- (void)testProto3RoundTripOneof {
+
+  Message3 *subMessage = [[Message3 alloc] init];
+  XCTAssertNotNil(subMessage);
+  subMessage.optionalInt32 = 666;
+
+  {  // oneofInt32
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofInt32 = 1;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
+    XCTAssertEqual(msg.oneofInt32, 1);
+    [orig release];
+  }
+
+  {  // oneofInt64
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofInt64 = 2;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
+    XCTAssertEqual(msg.oneofInt64, 2);
+    [orig release];
+  }
+
+  {  // oneofUint32
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofUint32 = 3U;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
+    XCTAssertEqual(msg.oneofUint32, 3U);
+    [orig release];
+  }
+
+  {  // oneofUint64
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofUint64 = 4U;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
+    XCTAssertEqual(msg.oneofUint64, 4U);
+    [orig release];
+  }
+
+  {  // oneofSint32
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofSint32 = 5;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
+    XCTAssertEqual(msg.oneofSint32, 5);
+    [orig release];
+  }
+
+  {  // oneofSint64
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofSint64 = 6;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
+    XCTAssertEqual(msg.oneofSint64, 6);
+    [orig release];
+  }
+
+  {  // oneofFixed32
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofFixed32 = 7U;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
+    XCTAssertEqual(msg.oneofFixed32, 7U);
+    [orig release];
+  }
+
+  {  // oneofFixed64
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofFixed64 = 8U;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
+    XCTAssertEqual(msg.oneofFixed64, 8U);
+    [orig release];
+  }
+
+  {  // oneofSfixed32
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofSfixed32 = 9;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
+    XCTAssertEqual(msg.oneofSfixed32, 9);
+    [orig release];
+  }
+
+  {  // oneofSfixed64
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofSfixed64 = 10;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
+    XCTAssertEqual(msg.oneofSfixed64, 10);
+    [orig release];
+  }
+
+  {  // oneofFloat
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofFloat = 11.0f;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
+    XCTAssertEqual(msg.oneofFloat, 11.0f);
+    [orig release];
+  }
+
+  {  // oneofDouble
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofDouble = 12.0;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
+    XCTAssertEqual(msg.oneofDouble, 12.0);
+    [orig release];
+  }
+
+  {  // oneofBool
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofBool = YES;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBool);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool);
+    XCTAssertEqual(msg.oneofBool, YES);
+    [orig release];
+  }
+
+  {  // oneofString
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofString = @"foo";
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofString);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString);
+    XCTAssertEqualObjects(msg.oneofString, @"foo");
+    [orig release];
+  }
+
+  {  // oneofBytes
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
+    XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
+    [orig release];
+  }
+
+  // Not "group" in proto3.
+
+  {  // oneofMessage
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofMessage = subMessage;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
+    XCTAssertEqualObjects(msg.oneofMessage, subMessage);
+    [orig release];
+  }
+
+  {  // oneofEnum
+    Message3 *orig = [[Message3 alloc] init];
+    orig.oneofEnum = Message2_Enum_Bar;
+    XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
+    [orig release];
+  }
+
+  [subMessage release];
+}
+
+//%PDDM-EXPAND-END (2 expansions)
+
+- (void)testPackedUnpackedMessageParsing {
+  // packed is optional, a repeated field should parse when packed or unpacked.
+
+  TestPackedTypes *packedOrig = [TestPackedTypes message];
+  TestUnpackedTypes *unpackedOrig = [TestUnpackedTypes message];
+  [self setPackedFields:packedOrig repeatedCount:4];
+  [self setUnpackedFields:unpackedOrig repeatedCount:4];
+
+  NSData *packedData = [packedOrig data];
+  NSData *unpackedData = [unpackedOrig data];
+  XCTAssertNotNil(packedData);
+  XCTAssertNotNil(unpackedData);
+  XCTAssertNotEqualObjects(packedData, unpackedData,
+                           @"Data should differ (packed vs unpacked) use");
+
+  NSError *error = nil;
+  TestPackedTypes *packedParse =
+      [TestPackedTypes parseFromData:unpackedData error:&error];
+  XCTAssertNotNil(packedParse);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(packedParse, packedOrig);
+
+  error = nil;
+  TestUnpackedTypes *unpackedParsed =
+      [TestUnpackedTypes parseFromData:packedData error:&error];
+  XCTAssertNotNil(unpackedParsed);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(unpackedParsed, unpackedOrig);
+}
+
+- (void)testPackedUnpackedExtensionParsing {
+  // packed is optional, a repeated extension should parse when packed or
+  // unpacked.
+
+  TestPackedExtensions *packedOrig = [TestPackedExtensions message];
+  TestUnpackedExtensions *unpackedOrig = [TestUnpackedExtensions message];
+  [self setPackedExtensions:packedOrig repeatedCount:kGPBDefaultRepeatCount];
+  [self setUnpackedExtensions:unpackedOrig repeatedCount:kGPBDefaultRepeatCount];
+
+  NSData *packedData = [packedOrig data];
+  NSData *unpackedData = [unpackedOrig data];
+  XCTAssertNotNil(packedData);
+  XCTAssertNotNil(unpackedData);
+  XCTAssertNotEqualObjects(packedData, unpackedData,
+                           @"Data should differ (packed vs unpacked) use");
+
+  NSError *error = nil;
+  TestPackedExtensions *packedParse =
+      [TestPackedExtensions parseFromData:unpackedData
+                        extensionRegistry:[UnittestRoot extensionRegistry]
+                                    error:&error];
+  XCTAssertNotNil(packedParse);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(packedParse, packedOrig);
+
+  error = nil;
+  TestUnpackedExtensions *unpackedParsed =
+      [TestUnpackedExtensions parseFromData:packedData
+                          extensionRegistry:[UnittestRoot extensionRegistry]
+                                      error:&error];
+  XCTAssertNotNil(unpackedParsed);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(unpackedParsed, unpackedOrig);
+}
+
+- (void)testPackedExtensionVsFieldParsing {
+  // Extensions and fields end up on the wire the same way, so they can parse
+  // each other.
+
+  TestPackedTypes *fieldsOrig = [TestPackedTypes message];
+  TestPackedExtensions *extsOrig = [TestPackedExtensions message];
+  [self setPackedFields:fieldsOrig repeatedCount:kGPBDefaultRepeatCount];
+  [self setPackedExtensions:extsOrig repeatedCount:kGPBDefaultRepeatCount];
+
+  NSData *fieldsData = [fieldsOrig data];
+  NSData *extsData = [extsOrig data];
+  XCTAssertNotNil(fieldsData);
+  XCTAssertNotNil(extsData);
+  XCTAssertEqualObjects(fieldsData, extsData);
+
+  NSError *error = nil;
+  TestPackedTypes *fieldsParse =
+      [TestPackedTypes parseFromData:extsData error:&error];
+  XCTAssertNotNil(fieldsParse);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(fieldsParse, fieldsOrig);
+
+  error = nil;
+  TestPackedExtensions *extsParse =
+      [TestPackedExtensions parseFromData:fieldsData
+                        extensionRegistry:[UnittestRoot extensionRegistry]
+                                    error:&error];
+  XCTAssertNotNil(extsParse);
+  XCTAssertNil(error);
+  XCTAssertEqualObjects(extsParse, extsOrig);
+}
+
+- (void)testUnpackedExtensionVsFieldParsing {
+  // Extensions and fields end up on the wire the same way, so they can parse
+  // each other.
+
+  TestUnpackedTypes *fieldsOrig = [TestUnpackedTypes message];
+  TestUnpackedExtensions *extsOrig = [TestUnpackedExtensions message];
+  [self setUnpackedFields:fieldsOrig repeatedCount:3];
+  [self setUnpackedExtensions:extsOrig repeatedCount:3];
+
+  NSData *fieldsData = [fieldsOrig data];
+  NSData *extsData = [extsOrig data];
+  XCTAssertNotNil(fieldsData);
+  XCTAssertNotNil(extsData);
+  XCTAssertEqualObjects(fieldsData, extsData);
+
+  TestUnpackedTypes *fieldsParse =
+      [TestUnpackedTypes parseFromData:extsData error:NULL];
+  XCTAssertNotNil(fieldsParse);
+  XCTAssertEqualObjects(fieldsParse, fieldsOrig);
+
+  TestUnpackedExtensions *extsParse =
+      [TestUnpackedExtensions parseFromData:fieldsData
+                          extensionRegistry:[UnittestRoot extensionRegistry]
+                                      error:NULL];
+  XCTAssertNotNil(extsParse);
+  XCTAssertEqualObjects(extsParse, extsOrig);
+}
+
+#pragma mark - Subset from from map_tests.cc
+
+// TEST(GeneratedMapFieldTest, StandardWireFormat)
+- (void)testMap_StandardWireFormat {
+  NSData *data = DataFromCStr("\x0A\x04\x08\x01\x10\x01");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
+  XCTAssertEqual(val, 1);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, UnorderedWireFormat)
+- (void)testMap_UnorderedWireFormat {
+  // put value before key in wire format
+  NSData *data = DataFromCStr("\x0A\x04\x10\x01\x08\x02");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
+  XCTAssertEqual(val, 1);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat)
+- (void)testMap_DuplicatedKeyWireFormat {
+  // Two key fields in wire format
+  NSData *data = DataFromCStr("\x0A\x06\x08\x01\x08\x02\x10\x01");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
+  XCTAssertEqual(val, 1);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat)
+- (void)testMap_DuplicatedValueWireFormat {
+  // Two value fields in wire format
+  NSData *data = DataFromCStr("\x0A\x06\x08\x01\x10\x01\x10\x02");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
+  XCTAssertEqual(val, 2);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, MissedKeyWireFormat)
+- (void)testMap_MissedKeyWireFormat {
+  // No key field in wire format
+  NSData *data = DataFromCStr("\x0A\x02\x10\x01");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:0 value:&val]);
+  XCTAssertEqual(val, 1);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, MissedValueWireFormat)
+- (void)testMap_MissedValueWireFormat {
+  // No value field in wire format
+  NSData *data = DataFromCStr("\x0A\x02\x08\x01");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
+  XCTAssertEqual(val, 0);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, UnknownFieldWireFormat)
+- (void)testMap_UnknownFieldWireFormat {
+  // Unknown field in wire format
+  NSData *data = DataFromCStr("\x0A\x06\x08\x02\x10\x03\x18\x01");
+
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
+  XCTAssertEqual(msg.mapInt32Int32.count, 1U);
+  int32_t val = 666;
+  XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
+  XCTAssertEqual(val, 3);
+
+  [msg release];
+}
+
+// TEST(GeneratedMapFieldTest, CorruptedWireFormat)
+- (void)testMap_CorruptedWireFormat {
+  // corrupted data in wire format
+  NSData *data = DataFromCStr("\x0A\x06\x08\x02\x11\x03");
+
+  NSError *error = nil;
+  TestMap *msg = [TestMap parseFromData:data error:&error];
+  XCTAssertNil(msg);
+  XCTAssertNotNil(error);
+  XCTAssertEqualObjects(error.domain, GPBMessageErrorDomain);
+  XCTAssertEqual(error.code, GPBMessageErrorCodeMalformedData);
+}
+
+// TEST(GeneratedMapFieldTest, Proto2UnknownEnum)
+- (void)testMap_Proto2UnknownEnum {
+  TestEnumMapPlusExtra *orig = [[TestEnumMapPlusExtra alloc] init];
+
+  orig.knownMapField = [GPBInt32EnumDictionary
+      dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue];
+  orig.unknownMapField = [GPBInt32EnumDictionary
+      dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue];
+  [orig.knownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumFoo
+                        forKey:0];
+  [orig.unknownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumExtra
+                          forKey:0];
+
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
+  TestEnumMap *msg1 = [TestEnumMap parseFromData:data error:NULL];
+  XCTAssertEqual(msg1.knownMapField.count, 1U);
+  int32_t val = -1;
+  XCTAssertTrue([msg1.knownMapField valueForKey:0 value:&val]);
+  XCTAssertEqual(val, Proto2MapEnum_Proto2MapEnumFoo);
+  XCTAssertEqual(msg1.unknownFields.countOfFields, 1U);
+
+  data = [msg1 data];
+  TestEnumMapPlusExtra *msg2 =
+      [TestEnumMapPlusExtra parseFromData:data error:NULL];
+  val = -1;
+  XCTAssertEqual(msg2.knownMapField.count, 1U);
+  XCTAssertTrue([msg2.knownMapField valueForKey:0 value:&val]);
+  XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumFoo);
+  val = -1;
+  XCTAssertEqual(msg2.unknownMapField.count, 1U);
+  XCTAssertTrue([msg2.unknownMapField valueForKey:0 value:&val]);
+  XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumExtra);
+  XCTAssertEqual(msg2.unknownFields.countOfFields, 0U);
+
+  XCTAssertEqualObjects(orig, msg2);
+
+  [orig release];
+}
+
+#pragma mark - Map Round Tripping
+
+- (void)testProto2MapRoundTripping {
+  Message2 *msg = [[Message2 alloc] init];
+
+  // Key/Value data should result in different byte lengths on wire to ensure
+  // everything is right.
+  [msg.mapInt32Int32 setValue:1000 forKey:200];
+  [msg.mapInt32Int32 setValue:101 forKey:2001];
+  [msg.mapInt64Int64 setValue:1002 forKey:202];
+  [msg.mapInt64Int64 setValue:103 forKey:2003];
+  [msg.mapUint32Uint32 setValue:1004 forKey:204];
+  [msg.mapUint32Uint32 setValue:105 forKey:2005];
+  [msg.mapUint64Uint64 setValue:1006 forKey:206];
+  [msg.mapUint64Uint64 setValue:107 forKey:2007];
+  [msg.mapSint32Sint32 setValue:1008 forKey:208];
+  [msg.mapSint32Sint32 setValue:109 forKey:2009];
+  [msg.mapSint64Sint64 setValue:1010 forKey:210];
+  [msg.mapSint64Sint64 setValue:111 forKey:2011];
+  [msg.mapFixed32Fixed32 setValue:1012 forKey:212];
+  [msg.mapFixed32Fixed32 setValue:113 forKey:2013];
+  [msg.mapFixed64Fixed64 setValue:1014 forKey:214];
+  [msg.mapFixed64Fixed64 setValue:115 forKey:2015];
+  [msg.mapSfixed32Sfixed32 setValue:1016 forKey:216];
+  [msg.mapSfixed32Sfixed32 setValue:117 forKey:2017];
+  [msg.mapSfixed64Sfixed64 setValue:1018 forKey:218];
+  [msg.mapSfixed64Sfixed64 setValue:119 forKey:2019];
+  [msg.mapInt32Float setValue:1020.f forKey:220];
+  [msg.mapInt32Float setValue:121.f forKey:2021];
+  [msg.mapInt32Double setValue:1022. forKey:222];
+  [msg.mapInt32Double setValue:123. forKey:2023];
+  [msg.mapBoolBool setValue:false forKey:true];
+  [msg.mapBoolBool setValue:true forKey:false];
+  msg.mapStringString[@"224"] = @"1024";
+  msg.mapStringString[@"2025"] = @"125";
+  msg.mapStringBytes[@"226"] = DataFromCStr("1026");
+  msg.mapStringBytes[@"2027"] = DataFromCStr("127");
+  Message2 *val1 = [[Message2 alloc] init];
+  val1.optionalInt32 = 1028;
+  Message2 *val2 = [[Message2 alloc] init];
+  val2.optionalInt32 = 129;
+  [msg.mapStringMessage setValue:val1 forKey:@"228"];
+  [msg.mapStringMessage setValue:val2 forKey:@"2029"];
+  [msg.mapInt32Bytes setObject:DataFromCStr("1030 bytes") forKey:230];
+  [msg.mapInt32Bytes setObject:DataFromCStr("131") forKey:2031];
+  [msg.mapInt32Enum setValue:Message2_Enum_Bar forKey:232];
+  [msg.mapInt32Enum setValue:Message2_Enum_Baz forKey:2033];
+  Message2 *val3 = [[Message2 alloc] init];
+  val3.optionalInt32 = 1034;
+  Message2 *val4 = [[Message2 alloc] init];
+  val4.optionalInt32 = 135;
+  [msg.mapInt32Message setObject:val3 forKey:234];
+  [msg.mapInt32Message setObject:val4 forKey:2035];
+
+  NSData *data = [msg data];
+  XCTAssertNotNil(data);
+  Message2 *msg2 = [[Message2 alloc] initWithData:data error:NULL];
+
+  XCTAssertNotEqual(msg2, msg);  // Pointer comparison
+  XCTAssertEqualObjects(msg2, msg);
+
+  [val4 release];
+  [val3 release];
+  [val2 release];
+  [val1 release];
+  [msg2 release];
+  [msg release];
+}
+
+@end
diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m
new file mode 100644
index 0000000..89d1fce
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -0,0 +1,2022 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBArray_PackagePrivate.h"
+#import "GPBDescriptor.h"
+#import "GPBDictionary_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUnknownField_PackagePrivate.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+
+@interface MessageTests : GPBTestCase
+@end
+
+@implementation MessageTests
+
+// TODO(thomasvl): this should get split into a few files of logic junks, it is
+// a jumble of things at the moment (and the testutils have a bunch of the real
+// assertions).
+
+- (TestAllTypes *)mergeSource {
+  TestAllTypes *message = [TestAllTypes message];
+  [message setOptionalInt32:1];
+  [message setOptionalString:@"foo"];
+  [message setOptionalForeignMessage:[ForeignMessage message]];
+  [message.repeatedStringArray addObject:@"bar"];
+  return message;
+}
+
+- (TestAllTypes *)mergeDestination {
+  TestAllTypes *message = [TestAllTypes message];
+  [message setOptionalInt64:2];
+  [message setOptionalString:@"baz"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setC:3];
+  [message setOptionalForeignMessage:foreignMessage];
+  [message.repeatedStringArray addObject:@"qux"];
+  return message;
+}
+
+- (TestAllTypes *)mergeDestinationWithoutForeignMessageIvar {
+  TestAllTypes *message = [TestAllTypes message];
+  [message setOptionalInt64:2];
+  [message setOptionalString:@"baz"];
+  [message.repeatedStringArray addObject:@"qux"];
+  return message;
+}
+
+- (TestAllTypes *)mergeResult {
+  TestAllTypes *message = [TestAllTypes message];
+  [message setOptionalInt32:1];
+  [message setOptionalInt64:2];
+  [message setOptionalString:@"foo"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setC:3];
+  [message setOptionalForeignMessage:foreignMessage];
+  [message.repeatedStringArray addObject:@"qux"];
+  [message.repeatedStringArray addObject:@"bar"];
+  return message;
+}
+
+- (TestAllTypes *)mergeResultForDestinationWithoutForeignMessageIvar {
+  TestAllTypes *message = [TestAllTypes message];
+  [message setOptionalInt32:1];
+  [message setOptionalInt64:2];
+  [message setOptionalString:@"foo"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [message setOptionalForeignMessage:foreignMessage];
+  [message.repeatedStringArray addObject:@"qux"];
+  [message.repeatedStringArray addObject:@"bar"];
+  return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsDestination {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
+  [message setExtension:[UnittestRoot optionalStringExtension] value:@"foo"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  foreignMessage.c = 4;
+  [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+                  value:foreignMessage];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+                  value:nestedMessage];
+  return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsSource {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [message setExtension:[UnittestRoot optionalInt64Extension] value:@6];
+  [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+                  value:foreignMessage];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  nestedMessage.bb = 7;
+  [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+                  value:nestedMessage];
+  return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsResult {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
+  [message setExtension:[UnittestRoot optionalInt64Extension] value:@6];
+  [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  foreignMessage.c = 4;
+  [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+                  value:foreignMessage];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  nestedMessage.bb = 7;
+  [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+                  value:nestedMessage];
+  return message;
+}
+
+- (void)testMergeFrom {
+  TestAllTypes *result = [[self.mergeDestination copy] autorelease];
+  [result mergeFrom:self.mergeSource];
+  NSData *resultData = [result data];
+  NSData *mergeResultData = [self.mergeResult data];
+  XCTAssertEqualObjects(resultData, mergeResultData);
+  XCTAssertEqualObjects(result, self.mergeResult);
+
+  // Test when destination does not have an Ivar (type is an object) but source
+  // has such Ivar.
+  // The result must has the Ivar which is same as the one in source.
+  result = [[self.mergeDestinationWithoutForeignMessageIvar copy] autorelease];
+  [result mergeFrom:self.mergeSource];
+  resultData = [result data];
+  mergeResultData =
+      [self.mergeResultForDestinationWithoutForeignMessageIvar data];
+  XCTAssertEqualObjects(resultData, mergeResultData);
+  XCTAssertEqualObjects(
+      result, self.mergeResultForDestinationWithoutForeignMessageIvar);
+
+  // Test when destination is empty.
+  // The result must is same as the source.
+  result = [TestAllTypes message];
+  [result mergeFrom:self.mergeSource];
+  resultData = [result data];
+  mergeResultData = [self.mergeSource data];
+  XCTAssertEqualObjects(resultData, mergeResultData);
+  XCTAssertEqualObjects(result, self.mergeSource);
+}
+
+- (void)testMergeFromWithExtensions {
+  TestAllExtensions *result = [self mergeExtensionsDestination];
+  [result mergeFrom:[self mergeExtensionsSource]];
+  NSData *resultData = [result data];
+  NSData *mergeResultData = [[self mergeExtensionsResult] data];
+  XCTAssertEqualObjects(resultData, mergeResultData);
+  XCTAssertEqualObjects(result, [self mergeExtensionsResult]);
+
+  // Test merging from data.
+  result = [self mergeExtensionsDestination];
+  NSData *data = [[self mergeExtensionsSource] data];
+  XCTAssertNotNil(data);
+  [result mergeFromData:data
+      extensionRegistry:[UnittestRoot extensionRegistry]];
+  resultData = [result data];
+  XCTAssertEqualObjects(resultData, mergeResultData);
+  XCTAssertEqualObjects(result, [self mergeExtensionsResult]);
+}
+
+- (void)testIsEquals {
+  TestAllTypes *result = [[self.mergeDestination copy] autorelease];
+  [result mergeFrom:self.mergeSource];
+  XCTAssertEqualObjects(result.data, self.mergeResult.data);
+  XCTAssertEqualObjects(result, self.mergeResult);
+  TestAllTypes *result2 = [[self.mergeDestination copy] autorelease];
+  XCTAssertNotEqualObjects(result2.data, self.mergeResult.data);
+  XCTAssertNotEqualObjects(result2, self.mergeResult);
+}
+
+// =================================================================
+// Required-field-related tests.
+
+- (TestRequired *)testRequiredInitialized {
+  TestRequired *message = [TestRequired message];
+  [message setA:1];
+  [message setB:2];
+  [message setC:3];
+  return message;
+}
+
+- (void)testRequired {
+  TestRequired *message = [TestRequired message];
+
+  XCTAssertFalse(message.initialized);
+  [message setA:1];
+  XCTAssertFalse(message.initialized);
+  [message setB:1];
+  XCTAssertFalse(message.initialized);
+  [message setC:1];
+  XCTAssertTrue(message.initialized);
+}
+
+- (void)testRequiredForeign {
+  TestRequiredForeign *message = [TestRequiredForeign message];
+
+  XCTAssertTrue(message.initialized);
+
+  [message setOptionalMessage:[TestRequired message]];
+  XCTAssertFalse(message.initialized);
+
+  [message setOptionalMessage:self.testRequiredInitialized];
+  XCTAssertTrue(message.initialized);
+
+  [message.repeatedMessageArray addObject:[TestRequired message]];
+  XCTAssertFalse(message.initialized);
+
+  [message.repeatedMessageArray removeAllObjects];
+  [message.repeatedMessageArray addObject:self.testRequiredInitialized];
+  XCTAssertTrue(message.initialized);
+}
+
+- (void)testRequiredExtension {
+  TestAllExtensions *message = [TestAllExtensions message];
+
+  XCTAssertTrue(message.initialized);
+
+  [message setExtension:[TestRequired single] value:[TestRequired message]];
+  XCTAssertFalse(message.initialized);
+
+  [message setExtension:[TestRequired single]
+                  value:self.testRequiredInitialized];
+  XCTAssertTrue(message.initialized);
+
+  [message addExtension:[TestRequired multi] value:[TestRequired message]];
+  XCTAssertFalse(message.initialized);
+
+  [message setExtension:[TestRequired multi]
+                  index:0
+                  value:self.testRequiredInitialized];
+  XCTAssertTrue(message.initialized);
+}
+
+- (void)testDataFromUninitialized {
+  TestRequired *message = [TestRequired message];
+  NSData *data = [message data];
+  // In DEBUG, the data generation will fail, but in non DEBUG, it passes
+  // because the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(data);
+#else
+  XCTAssertNotNil(data);
+  XCTAssertFalse(message.initialized);
+#endif  // DEBUG
+}
+
+- (void)testInitialized {
+  // We're mostly testing that no exception is thrown.
+  TestRequired *message = [TestRequired message];
+  XCTAssertFalse(message.initialized);
+}
+
+- (void)testDataFromNestedUninitialized {
+  TestRequiredForeign *message = [TestRequiredForeign message];
+  [message setOptionalMessage:[TestRequired message]];
+  [message.repeatedMessageArray addObject:[TestRequired message]];
+  [message.repeatedMessageArray addObject:[TestRequired message]];
+  NSData *data = [message data];
+  // In DEBUG, the data generation will fail, but in non DEBUG, it passes
+  // because the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(data);
+#else
+  XCTAssertNotNil(data);
+  XCTAssertFalse(message.initialized);
+#endif  // DEBUG
+}
+
+- (void)testNestedInitialized {
+  // We're mostly testing that no exception is thrown.
+
+  TestRequiredForeign *message = [TestRequiredForeign message];
+  [message setOptionalMessage:[TestRequired message]];
+  [message.repeatedMessageArray addObject:[TestRequired message]];
+  [message.repeatedMessageArray addObject:[TestRequired message]];
+
+  XCTAssertFalse(message.initialized);
+}
+
+- (void)testParseUninitialized {
+  NSError *error = nil;
+  TestRequired *msg =
+      [TestRequired parseFromData:GPBEmptyNSData() error:&error];
+  // In DEBUG, the parse will fail, but in non DEBUG, it passes because
+  // the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(msg);
+  XCTAssertNotNil(error);
+  XCTAssertEqualObjects(error.domain, GPBMessageErrorDomain);
+  XCTAssertEqual(error.code, GPBMessageErrorCodeMissingRequiredField);
+#else
+  XCTAssertNotNil(msg);
+  XCTAssertNil(error);
+  XCTAssertFalse(msg.initialized);
+#endif  // DEBUG
+}
+
+- (void)testCoding {
+  NSData *data =
+      [NSKeyedArchiver archivedDataWithRootObject:[self mergeResult]];
+  id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
+
+  XCTAssertEqualObjects(unarchivedObject, [self mergeResult]);
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(unarchivedObject, [self mergeResult]);
+}
+
+- (void)testObjectReset {
+  // Tests a failure where clearing out defaults values caused an over release.
+  TestAllTypes *message = [TestAllTypes message];
+  message.hasOptionalNestedMessage = NO;
+  [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]];
+  message.hasOptionalNestedMessage = NO;
+  [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]];
+  [message setOptionalNestedMessage:nil];
+  message.hasOptionalNestedMessage = NO;
+}
+
+- (void)testSettingHasToYes {
+  TestAllTypes *message = [TestAllTypes message];
+  XCTAssertThrows([message setHasOptionalNestedMessage:YES]);
+}
+
+- (void)testRoot {
+  XCTAssertNotNil([UnittestRoot extensionRegistry]);
+}
+
+- (void)testGPBMessageSize {
+  // See the note in GPBMessage_PackagePrivate.h about why we want to keep the
+  // base instance size pointer size aligned.
+  size_t messageSize = class_getInstanceSize([GPBMessage class]);
+  XCTAssertEqual((messageSize % sizeof(void *)), (size_t)0,
+                 @"Base size isn't pointer size aligned");
+
+  // Since we add storage ourselves (see +allocWithZone: in GPBMessage), confirm
+  // that the size of some generated classes is still the same as the base for
+  // that logic to work as desired.
+  size_t testMessageSize = class_getInstanceSize([TestAllTypes class]);
+  XCTAssertEqual(testMessageSize, messageSize);
+}
+
+- (void)testInit {
+  TestAllTypes *message = [TestAllTypes message];
+  [self assertClear:message];
+}
+
+- (void)testAccessors {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testKVC_ValueForKey {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [self assertAllFieldsKVCMatch:message];
+}
+
+- (void)testKVC_SetValue_ForKey {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFieldsViaKVC:message repeatedCount:kGPBDefaultRepeatCount];
+  [self assertAllFieldsKVCMatch:message];
+  [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount];
+  [self assertAllFieldsKVCMatch:message];
+}
+
+- (void)testDescription {
+  // No real test, just exercise code
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+
+  GPBUnknownFieldSet *unknownFields =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  GPBUnknownField *field =
+      [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
+  [field addVarint:2];
+  [unknownFields addField:field];
+  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
+  [field addVarint:4];
+  [unknownFields addField:field];
+
+  [message setUnknownFields:unknownFields];
+
+  NSString *description = [message description];
+  XCTAssertGreaterThan([description length], 0U);
+
+  GPBMessage *message2 = [TestAllExtensions message];
+  [message2 setExtension:[UnittestRoot optionalInt32Extension] value:@1];
+
+  [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@2];
+
+  description = [message2 description];
+  XCTAssertGreaterThan([description length], 0U);
+}
+
+- (void)testSetter {
+  // Test to make sure that if we set a value that has a default value
+  // with the default, that the has is set, and the value gets put into the
+  // message correctly.
+  TestAllTypes *message = [TestAllTypes message];
+  GPBDescriptor *descriptor = [[message class] descriptor];
+  XCTAssertNotNil(descriptor);
+  GPBFieldDescriptor *fieldDescriptor =
+      [descriptor fieldWithName:@"defaultInt32"];
+  XCTAssertNotNil(fieldDescriptor);
+  GPBGenericValue defaultValue = [fieldDescriptor defaultValue];
+  [message setDefaultInt32:defaultValue.valueInt32];
+  XCTAssertTrue(message.hasDefaultInt32);
+  XCTAssertEqual(message.defaultInt32, defaultValue.valueInt32);
+
+  // Do the same thing with an object type.
+  message = [TestAllTypes message];
+  fieldDescriptor = [descriptor fieldWithName:@"defaultString"];
+  XCTAssertNotNil(fieldDescriptor);
+  defaultValue = [fieldDescriptor defaultValue];
+  [message setDefaultString:defaultValue.valueString];
+  XCTAssertTrue(message.hasDefaultString);
+  XCTAssertEqualObjects(message.defaultString, defaultValue.valueString);
+
+  // Test default string type.
+  message = [TestAllTypes message];
+  XCTAssertEqualObjects(message.defaultString, @"hello");
+  XCTAssertFalse(message.hasDefaultString);
+  fieldDescriptor = [descriptor fieldWithName:@"defaultString"];
+  XCTAssertNotNil(fieldDescriptor);
+  defaultValue = [fieldDescriptor defaultValue];
+  [message setDefaultString:defaultValue.valueString];
+  XCTAssertEqualObjects(message.defaultString, @"hello");
+  XCTAssertTrue(message.hasDefaultString);
+  [message setDefaultString:nil];
+  XCTAssertEqualObjects(message.defaultString, @"hello");
+  XCTAssertFalse(message.hasDefaultString);
+  message.hasDefaultString = NO;
+  XCTAssertFalse(message.hasDefaultString);
+  XCTAssertEqualObjects(message.defaultString, @"hello");
+
+  // Test default bytes type.
+  NSData *defaultBytes = [@"world" dataUsingEncoding:NSUTF8StringEncoding];
+  XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+  XCTAssertFalse(message.hasDefaultString);
+  fieldDescriptor = [descriptor fieldWithName:@"defaultBytes"];
+  XCTAssertNotNil(fieldDescriptor);
+  defaultValue = [fieldDescriptor defaultValue];
+  [message setDefaultBytes:defaultValue.valueData];
+  XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+  XCTAssertTrue(message.hasDefaultBytes);
+  [message setDefaultBytes:nil];
+  XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+  XCTAssertFalse(message.hasDefaultBytes);
+  message.hasDefaultBytes = NO;
+  XCTAssertFalse(message.hasDefaultBytes);
+  XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+
+  // Test optional string.
+  XCTAssertFalse(message.hasOptionalString);
+  XCTAssertEqualObjects(message.optionalString, @"");
+  XCTAssertFalse(message.hasOptionalString);
+  message.optionalString = nil;
+  XCTAssertFalse(message.hasOptionalString);
+  XCTAssertEqualObjects(message.optionalString, @"");
+  NSString *string = @"string";
+  message.optionalString = string;
+  XCTAssertEqualObjects(message.optionalString, string);
+  XCTAssertTrue(message.hasOptionalString);
+  message.optionalString = nil;
+  XCTAssertFalse(message.hasOptionalString);
+  XCTAssertEqualObjects(message.optionalString, @"");
+
+  // Test optional data.
+  XCTAssertFalse(message.hasOptionalBytes);
+  XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+  XCTAssertFalse(message.hasOptionalBytes);
+  message.optionalBytes = nil;
+  XCTAssertFalse(message.hasOptionalBytes);
+  XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+  NSData *data = [@"bytes" dataUsingEncoding:NSUTF8StringEncoding];
+  message.optionalBytes = data;
+  XCTAssertEqualObjects(message.optionalBytes, data);
+  XCTAssertTrue(message.hasOptionalBytes);
+  message.optionalBytes = nil;
+  XCTAssertFalse(message.hasOptionalBytes);
+  XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+
+  // Test lazy message setting
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  XCTAssertNotNil(message.optionalLazyMessage);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  message.hasOptionalLazyMessage = NO;
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  XCTAssertNotNil(message.optionalLazyMessage);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  message.optionalLazyMessage = nil;
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+
+  // Test nested messages
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  message.optionalLazyMessage.bb = 1;
+  XCTAssertTrue(message.hasOptionalLazyMessage);
+  XCTAssertEqual(message.optionalLazyMessage.bb, 1);
+  XCTAssertNotNil(message.optionalLazyMessage);
+  message.optionalLazyMessage = nil;
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  XCTAssertEqual(message.optionalLazyMessage.bb, 0);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+  XCTAssertNotNil(message.optionalLazyMessage);
+
+  // -testDefaultSubMessages tests the "defaulting" handling of fields
+  // containing messages.
+}
+
+- (void)testRepeatedSetters {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [self modifyRepeatedFields:message];
+  [self assertRepeatedFieldsModified:message
+                       repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testClear {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [self clearAllFields:message];
+  [self assertClear:message];
+  TestAllTypes *message2 = [TestAllTypes message];
+  XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testClearKVC {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+  [self clearAllFields:message];
+  [self assertClear:message];
+  [self assertClearKVC:message];
+}
+
+- (void)testClearExtension {
+  // clearExtension() is not actually used in TestUtil, so try it manually.
+  GPBMessage *message1 = [TestAllExtensions message];
+  [message1 setExtension:[UnittestRoot optionalInt32Extension] value:@1];
+
+  XCTAssertTrue([message1 hasExtension:[UnittestRoot optionalInt32Extension]]);
+  [message1 clearExtension:[UnittestRoot optionalInt32Extension]];
+  XCTAssertFalse([message1 hasExtension:[UnittestRoot optionalInt32Extension]]);
+
+  GPBMessage *message2 = [TestAllExtensions message];
+  [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@1];
+
+  XCTAssertEqual(
+      [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count],
+      (NSUInteger)1);
+  [message2 clearExtension:[UnittestRoot repeatedInt32Extension]];
+  XCTAssertEqual(
+      [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count],
+      (NSUInteger)0);
+
+  // Clearing an unset extension field shouldn't make the target message
+  // visible.
+  GPBMessage *message3 = [TestAllExtensions message];
+  GPBMessage *extension_msg =
+      [message3 getExtension:[UnittestObjcRoot recursiveExtension]];
+  XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]);
+  [extension_msg clearExtension:[UnittestRoot optionalInt32Extension]];
+  XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]);
+}
+
+- (void)testDefaultingSubMessages {
+  TestAllTypes *message = [TestAllTypes message];
+
+  // Initially they should all not have values.
+
+  XCTAssertFalse(message.hasOptionalGroup);
+  XCTAssertFalse(message.hasOptionalNestedMessage);
+  XCTAssertFalse(message.hasOptionalForeignMessage);
+  XCTAssertFalse(message.hasOptionalImportMessage);
+  XCTAssertFalse(message.hasOptionalPublicImportMessage);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+
+  // They should auto create something when fetched.
+
+  TestAllTypes_OptionalGroup *optionalGroup = [message.optionalGroup retain];
+  TestAllTypes_NestedMessage *optionalNestedMessage =
+      [message.optionalNestedMessage retain];
+  ForeignMessage *optionalForeignMessage =
+      [message.optionalForeignMessage retain];
+  ImportMessage *optionalImportMessage = [message.optionalImportMessage retain];
+  PublicImportMessage *optionalPublicImportMessage =
+      [message.optionalPublicImportMessage retain];
+  TestAllTypes_NestedMessage *optionalLazyMessage =
+      [message.optionalLazyMessage retain];
+
+  XCTAssertNotNil(optionalGroup);
+  XCTAssertNotNil(optionalNestedMessage);
+  XCTAssertNotNil(optionalForeignMessage);
+  XCTAssertNotNil(optionalImportMessage);
+  XCTAssertNotNil(optionalPublicImportMessage);
+  XCTAssertNotNil(optionalLazyMessage);
+
+  // Although they were created, they should not respond to hasValue until that
+  // submessage is mutated.
+
+  XCTAssertFalse(message.hasOptionalGroup);
+  XCTAssertFalse(message.hasOptionalNestedMessage);
+  XCTAssertFalse(message.hasOptionalForeignMessage);
+  XCTAssertFalse(message.hasOptionalImportMessage);
+  XCTAssertFalse(message.hasOptionalPublicImportMessage);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+
+  // And they set that value back in to the message since the value created was
+  // mutable (so a second fetch should give the same object).
+
+  XCTAssertEqual(message.optionalGroup, optionalGroup);
+  XCTAssertEqual(message.optionalNestedMessage, optionalNestedMessage);
+  XCTAssertEqual(message.optionalForeignMessage, optionalForeignMessage);
+  XCTAssertEqual(message.optionalImportMessage, optionalImportMessage);
+  XCTAssertEqual(message.optionalPublicImportMessage,
+                 optionalPublicImportMessage);
+  XCTAssertEqual(message.optionalLazyMessage, optionalLazyMessage);
+
+  // And the default objects for a second message should be distinct (again,
+  // since they are mutable, each needs their own copy).
+
+  TestAllTypes *message2 = [TestAllTypes message];
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(message2.optionalGroup, optionalGroup);
+  XCTAssertNotEqual(message2.optionalNestedMessage, optionalNestedMessage);
+  XCTAssertNotEqual(message2.optionalForeignMessage, optionalForeignMessage);
+  XCTAssertNotEqual(message2.optionalImportMessage, optionalImportMessage);
+  XCTAssertNotEqual(message2.optionalPublicImportMessage,
+                    optionalPublicImportMessage);
+  XCTAssertNotEqual(message2.optionalLazyMessage, optionalLazyMessage);
+
+  // Setting the values to nil will clear the has flag, and on next access you
+  // get back new submessages.
+
+  message.optionalGroup = nil;
+  message.optionalNestedMessage = nil;
+  message.optionalForeignMessage = nil;
+  message.optionalImportMessage = nil;
+  message.optionalPublicImportMessage = nil;
+  message.optionalLazyMessage = nil;
+
+  XCTAssertFalse(message.hasOptionalGroup);
+  XCTAssertFalse(message.hasOptionalNestedMessage);
+  XCTAssertFalse(message.hasOptionalForeignMessage);
+  XCTAssertFalse(message.hasOptionalImportMessage);
+  XCTAssertFalse(message.hasOptionalPublicImportMessage);
+  XCTAssertFalse(message.hasOptionalLazyMessage);
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(message.optionalGroup, optionalGroup);
+  XCTAssertNotEqual(message.optionalNestedMessage, optionalNestedMessage);
+  XCTAssertNotEqual(message.optionalForeignMessage, optionalForeignMessage);
+  XCTAssertNotEqual(message.optionalImportMessage, optionalImportMessage);
+  XCTAssertNotEqual(message.optionalPublicImportMessage,
+                    optionalPublicImportMessage);
+  XCTAssertNotEqual(message.optionalLazyMessage, optionalLazyMessage);
+
+  [optionalGroup release];
+  [optionalNestedMessage release];
+  [optionalForeignMessage release];
+  [optionalImportMessage release];
+  [optionalPublicImportMessage release];
+  [optionalLazyMessage release];
+}
+
+- (void)testMultiplePointersToAutocreatedMessage {
+  // Multiple objects pointing to the same autocreated message.
+  TestAllTypes *message = [TestAllTypes message];
+  TestAllTypes *message2 = [TestAllTypes message];
+  message2.optionalGroup = message.optionalGroup;
+  XCTAssertTrue([message2 hasOptionalGroup]);
+  XCTAssertFalse([message hasOptionalGroup]);
+  message2.optionalGroup.a = 42;
+  XCTAssertTrue([message hasOptionalGroup]);
+  XCTAssertTrue([message2 hasOptionalGroup]);
+}
+
+- (void)testCopyWithAutocreatedMessage {
+  // Mutable copy should not copy autocreated messages.
+  TestAllTypes *message = [TestAllTypes message];
+  message.optionalGroup.a = 42;
+  XCTAssertNotNil(message.optionalNestedMessage);
+  TestAllTypes *message2 = [[message copy] autorelease];
+  XCTAssertTrue([message2 hasOptionalGroup]);
+  XCTAssertFalse([message2 hasOptionalNestedMessage]);
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(message.optionalNestedMessage,
+                    message2.optionalNestedMessage);
+}
+
+- (void)testClearAutocreatedSubmessage {
+  // Call clear on an intermediate submessage should cause it to get recreated
+  // on the next call.
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  TestRecursiveMessage *message_inner = [message.a.a.a retain];
+  XCTAssertNotNil(message_inner);
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(message_inner, message.a.a));
+  [message.a.a clear];
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a.a));
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(message.a.a.a, message_inner);
+  [message_inner release];
+}
+
+- (void)testRetainAutocreatedSubmessage {
+  // Should be able to retain autocreated submessage while the creator is
+  // dealloced.
+  TestAllTypes *message = [TestAllTypes message];
+
+  ForeignMessage *subMessage;
+  @autoreleasepool {
+    TestAllTypes *message2 = [TestAllTypes message];
+    subMessage = message2.optionalForeignMessage; // Autocreated
+    message.optionalForeignMessage = subMessage;
+    XCTAssertTrue(GPBWasMessageAutocreatedBy(message.optionalForeignMessage,
+                                             message2));
+  }
+
+  // Should be the same object, and should still be live.
+  XCTAssertEqual(message.optionalForeignMessage, subMessage);
+  XCTAssertNotNil([subMessage description]);
+}
+
+- (void)testSetNilAutocreatedSubmessage {
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  TestRecursiveMessage *message_inner = [message.a.a retain];
+  XCTAssertFalse([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+  message.a.a = nil;
+
+  // |message.a| has to be made visible, but |message.a.a| was set to nil so
+  // shouldn't be.
+  XCTAssertTrue([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+
+  // Setting submessage to nil should cause it to lose its creator.
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a));
+
+  // After setting to nil, getting it again should create a new autocreated
+  // message.
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(message.a.a, message_inner);
+
+  [message_inner release];
+}
+
+- (void)testSetDoesntHaveAutocreatedSubmessage {
+  // Clearing submessage (set has == NO) should NOT cause it to lose its
+  // creator.
+  TestAllTypes *message = [TestAllTypes message];
+  TestAllTypes_NestedMessage *nestedMessage = message.optionalNestedMessage;
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+  [message setHasOptionalNestedMessage:NO];
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+  XCTAssertEqual(message.optionalNestedMessage, nestedMessage);
+}
+
+- (void)testSetAutocreatedMessageBecomesVisible {
+  // Setting a value should cause the submessage to appear to its creator.
+  // Test this several levels deep.
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  message.a.a.a.a.i = 42;
+  XCTAssertTrue([message hasA]);
+  XCTAssertTrue([message.a hasA]);
+  XCTAssertTrue([message.a.a hasA]);
+  XCTAssertTrue([message.a.a.a hasA]);
+  XCTAssertFalse([message.a.a.a.a hasA]);
+  XCTAssertEqual(message.a.a.a.a.i, 42);
+}
+
+- (void)testClearUnsetFieldOfAutocreatedMessage {
+  // Clearing an unset field should not cause the submessage to appear to its
+  // creator.
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  message.a.a.a.a.hasI = NO;
+  XCTAssertFalse([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+  XCTAssertFalse([message.a.a hasA]);
+  XCTAssertFalse([message.a.a.a hasA]);
+}
+
+- (void)testAutocreatedSubmessageAssignSkip {
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  TestRecursiveMessage *messageLevel1 = [message.a retain];
+  TestRecursiveMessage *messageLevel2 = [message.a.a retain];
+  TestRecursiveMessage *messageLevel3 = [message.a.a.a retain];
+  TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain];
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3));
+
+  // Test skipping over an autocreated submessage and ensure it gets unset.
+  message.a = message.a.a;
+  XCTAssertEqual(message.a, messageLevel2);
+  XCTAssertTrue([message hasA]);
+  XCTAssertEqual(message.a.a, messageLevel3);
+  XCTAssertFalse([message.a hasA]);
+  XCTAssertEqual(message.a.a.a, messageLevel4);
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1,
+                                            message));  // Because it was orphaned.
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+
+  [messageLevel1 release];
+  [messageLevel2 release];
+  [messageLevel3 release];
+  [messageLevel4 release];
+}
+
+- (void)testAutocreatedSubmessageAssignLoop {
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  TestRecursiveMessage *messageLevel1 = [message.a retain];
+  TestRecursiveMessage *messageLevel2 = [message.a.a retain];
+  TestRecursiveMessage *messageLevel3 = [message.a.a.a retain];
+  TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain];
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+  XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3));
+
+  // Test a property with a loop. You'd never do this but at least ensure the
+  // autocreated submessages behave sanely.
+  message.a.a = message.a;
+  XCTAssertTrue([message hasA]);
+  XCTAssertEqual(message.a, messageLevel1);
+  XCTAssertTrue([message.a hasA]);
+  XCTAssertEqual(message.a.a, messageLevel1);
+  XCTAssertTrue([message.a.a hasA]);
+  XCTAssertEqual(message.a.a.a, messageLevel1);
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1,
+                                            message));  // Because it was assigned.
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel2,
+                                            messageLevel1));  // Because it was orphaned.
+  XCTAssertFalse([messageLevel2 hasA]);
+
+  // Break the retain loop.
+  message.a.a = nil;
+  XCTAssertTrue([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+
+  [messageLevel1 release];
+  [messageLevel2 release];
+  [messageLevel3 release];
+  [messageLevel4 release];
+}
+
+- (void)testSetAutocreatedSubmessage {
+  // Setting autocreated submessage to another value should cause the old one to
+  // lose its creator.
+  TestAllTypes *message = [TestAllTypes message];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [message.optionalNestedMessage retain];
+
+  message.optionalNestedMessage = [TestAllTypes_NestedMessage message];
+  XCTAssertTrue([message hasOptionalNestedMessage]);
+  XCTAssertTrue(message.optionalNestedMessage != nestedMessage);
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(nestedMessage, message));
+
+  [nestedMessage release];
+}
+
+- (void)testAutocreatedUnknownFields {
+  // Doing anything with (except reading) unknown fields should cause the
+  // submessage to become visible.
+  TestAllTypes *message = [TestAllTypes message];
+  XCTAssertNotNil(message.optionalNestedMessage);
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+  XCTAssertNil(message.optionalNestedMessage.unknownFields);
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+
+  GPBUnknownFieldSet *unknownFields =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  message.optionalNestedMessage.unknownFields = unknownFields;
+  XCTAssertTrue([message hasOptionalNestedMessage]);
+
+  message.optionalNestedMessage = nil;
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+  [message.optionalNestedMessage setUnknownFields:unknownFields];
+  XCTAssertTrue([message hasOptionalNestedMessage]);
+}
+
+- (void)testSetAutocreatedSubmessageToSelf {
+  // Setting submessage to itself should cause it to become visible.
+  TestAllTypes *message = [TestAllTypes message];
+  XCTAssertNotNil(message.optionalNestedMessage);
+  XCTAssertFalse([message hasOptionalNestedMessage]);
+  message.optionalNestedMessage = message.optionalNestedMessage;
+  XCTAssertTrue([message hasOptionalNestedMessage]);
+}
+
+- (void)testAutocreatedSubmessageMemoryLeaks {
+  // Test for memory leaks with autocreated submessages.
+  TestRecursiveMessage *message;
+  TestRecursiveMessage *messageLevel1;
+  TestRecursiveMessage *messageLevel2;
+  TestRecursiveMessage *messageLevel3;
+  TestRecursiveMessage *messageLevel4;
+  @autoreleasepool {
+    message = [[TestRecursiveMessage alloc] init];
+    messageLevel1 = [message.a retain];
+    messageLevel2 = [message.a.a retain];
+    messageLevel3 = [message.a.a.a retain];
+    messageLevel4 = [message.a.a.a.a retain];
+    message.a.i = 1;
+  }
+
+  XCTAssertEqual(message.retainCount, (NSUInteger)1);
+  [message release];
+  XCTAssertEqual(messageLevel1.retainCount, (NSUInteger)1);
+  [messageLevel1 release];
+  XCTAssertEqual(messageLevel2.retainCount, (NSUInteger)1);
+  [messageLevel2 release];
+  XCTAssertEqual(messageLevel3.retainCount, (NSUInteger)1);
+  [messageLevel3 release];
+  XCTAssertEqual(messageLevel4.retainCount, (NSUInteger)1);
+  [messageLevel4 release];
+}
+
+- (void)testDefaultingArrays {
+  // Basic tests for default creation of arrays in a message.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2 =
+      [TestRecursiveMessageWithRepeatedField message];
+
+  // Simply accessing the array should not make any fields visible.
+  XCTAssertNotNil(message.a.a.iArray);
+  XCTAssertFalse([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+  XCTAssertNotNil(message2.a.a.strArray);
+  XCTAssertFalse([message2 hasA]);
+  XCTAssertFalse([message2.a hasA]);
+
+  // But adding an element to the array should.
+  [message.a.a.iArray addValue:42];
+  XCTAssertTrue([message hasA]);
+  XCTAssertTrue([message.a hasA]);
+  XCTAssertEqual([message.a.a.iArray count], (NSUInteger)1);
+  [message2.a.a.strArray addObject:@"foo"];
+  XCTAssertTrue([message2 hasA]);
+  XCTAssertTrue([message2.a hasA]);
+  XCTAssertEqual([message2.a.a.strArray count], (NSUInteger)1);
+}
+
+- (void)testAutocreatedArrayShared {
+  // Multiple objects pointing to the same array.
+  TestRecursiveMessageWithRepeatedField *message1a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message1b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message1a.a.iArray = message1b.a.iArray;
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertFalse([message1b hasA]);
+  [message1a.a.iArray addValue:1];
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertTrue([message1b hasA]);
+  XCTAssertEqual(message1a.a.iArray, message1b.a.iArray);
+
+  TestRecursiveMessageWithRepeatedField *message2a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message2a.a.strArray = message2b.a.strArray;
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertFalse([message2b hasA]);
+  [message2a.a.strArray addObject:@"bar"];
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertTrue([message2b hasA]);
+  XCTAssertEqual(message2a.a.strArray, message2b.a.strArray);
+}
+
+- (void)testAutocreatedArrayCopy {
+  // Copy should not copy autocreated arrays.
+  TestAllTypes *message = [TestAllTypes message];
+  XCTAssertNotNil(message.repeatedStringArray);
+  XCTAssertNotNil(message.repeatedInt32Array);
+  TestAllTypes *message2 = [[message copy] autorelease];
+  // Pointer conparisions.
+  XCTAssertNotEqual(message.repeatedStringArray, message2.repeatedStringArray);
+  XCTAssertNotEqual(message.repeatedInt32Array, message2.repeatedInt32Array);
+
+  // Mutable copy should copy empty arrays that were explicitly set (end up
+  // with different objects that are equal).
+  TestAllTypes *message3 = [TestAllTypes message];
+  message3.repeatedInt32Array = [GPBInt32Array arrayWithValue:42];
+  message3.repeatedStringArray = [NSMutableArray arrayWithObject:@"wee"];
+  XCTAssertNotNil(message.repeatedInt32Array);
+  XCTAssertNotNil(message.repeatedStringArray);
+  TestAllTypes *message4 = [[message3 copy] autorelease];
+  XCTAssertNotEqual(message3.repeatedInt32Array, message4.repeatedInt32Array);
+  XCTAssertEqualObjects(message3.repeatedInt32Array,
+                        message4.repeatedInt32Array);
+  XCTAssertNotEqual(message3.repeatedStringArray, message4.repeatedStringArray);
+  XCTAssertEqualObjects(message3.repeatedStringArray,
+                        message4.repeatedStringArray);
+}
+
+- (void)testAutocreatedArrayRetain {
+  // Should be able to retain autocreated array while the creator is dealloced.
+  TestAllTypes *message = [TestAllTypes message];
+
+  @autoreleasepool {
+    TestAllTypes *message2 = [TestAllTypes message];
+    message.repeatedInt32Array = message2.repeatedInt32Array;
+    message.repeatedStringArray = message2.repeatedStringArray;
+    // Pointer conparision
+    XCTAssertEqual(message.repeatedInt32Array->_autocreator, message2);
+    XCTAssertTrue([message.repeatedStringArray
+        isKindOfClass:[GPBAutocreatedArray class]]);
+    XCTAssertEqual(
+        ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator,
+        message2);
+  }
+
+  XCTAssertNil(message.repeatedInt32Array->_autocreator);
+  XCTAssertTrue(
+      [message.repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]);
+  XCTAssertNil(
+      ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator);
+}
+
+- (void)testSetNilAutocreatedArray {
+  // Setting array to nil should cause it to lose its delegate.
+  TestAllTypes *message = [TestAllTypes message];
+  GPBInt32Array *repeatedInt32Array = [message.repeatedInt32Array retain];
+  GPBAutocreatedArray *repeatedStringArray =
+      (GPBAutocreatedArray *)[message.repeatedStringArray retain];
+  XCTAssertTrue([repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]);
+  XCTAssertEqual(repeatedInt32Array->_autocreator, message);
+  XCTAssertEqual(repeatedStringArray->_autocreator, message);
+  message.repeatedInt32Array = nil;
+  message.repeatedStringArray = nil;
+  XCTAssertNil(repeatedInt32Array->_autocreator);
+  XCTAssertNil(repeatedStringArray->_autocreator);
+  [repeatedInt32Array release];
+  [repeatedStringArray release];
+}
+
+- (void)testReplaceAutocreatedArray {
+  // Replacing array should orphan the old one and cause its creator to become
+  // visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iArray);
+    XCTAssertFalse([message hasA]);
+    GPBInt32Array *iArray = [message.a.iArray retain];
+    XCTAssertEqual(iArray->_autocreator, message.a);  // Pointer comparision
+    message.a.iArray = [GPBInt32Array arrayWithValue:1];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.iArray, iArray);  // Pointer comparision
+    XCTAssertNil(iArray->_autocreator);
+    [iArray release];
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strArray);
+    XCTAssertFalse([message hasA]);
+    GPBAutocreatedArray *strArray =
+        (GPBAutocreatedArray *)[message.a.strArray retain];
+    XCTAssertTrue([strArray isKindOfClass:[GPBAutocreatedArray class]]);
+    XCTAssertEqual(strArray->_autocreator, message.a);  // Pointer comparision
+    message.a.strArray = [NSMutableArray arrayWithObject:@"foo"];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.strArray, strArray);  // Pointer comparision
+    XCTAssertNil(strArray->_autocreator);
+    [strArray release];
+  }
+}
+
+- (void)testSetAutocreatedArrayToSelf {
+  // Setting array to itself should cause it to become visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iArray);
+    XCTAssertFalse([message hasA]);
+    message.a.iArray = message.a.iArray;
+    XCTAssertTrue([message hasA]);
+    XCTAssertNil(message.a.iArray->_autocreator);
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strArray);
+    XCTAssertFalse([message hasA]);
+    message.a.strArray = message.a.strArray;
+    XCTAssertTrue([message hasA]);
+    XCTAssertTrue([message.a.strArray isKindOfClass:[GPBAutocreatedArray class]]);
+    XCTAssertNil(((GPBAutocreatedArray *)message.a.strArray)->_autocreator);
+  }
+}
+
+- (void)testAutocreatedArrayRemoveAllValues {
+  // Calling removeAllValues on autocreated array should not cause it to be
+  // visible.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  [message.a.iArray removeAll];
+  XCTAssertFalse([message hasA]);
+  [message.a.strArray removeAllObjects];
+  XCTAssertFalse([message hasA]);
+}
+
+- (void)testDefaultingMaps {
+  // Basic tests for default creation of maps in a message.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2 =
+      [TestRecursiveMessageWithRepeatedField message];
+
+  // Simply accessing the map should not make any fields visible.
+  XCTAssertNotNil(message.a.a.iToI);
+  XCTAssertFalse([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+  XCTAssertNotNil(message2.a.a.strToStr);
+  XCTAssertFalse([message2 hasA]);
+  XCTAssertFalse([message2.a hasA]);
+
+  // But adding an element to the map should.
+  [message.a.a.iToI setValue:100 forKey:200];
+  XCTAssertTrue([message hasA]);
+  XCTAssertTrue([message.a hasA]);
+  XCTAssertEqual([message.a.a.iToI count], (NSUInteger)1);
+  [message2.a.a.strToStr setObject:@"foo" forKey:@"bar"];
+  XCTAssertTrue([message2 hasA]);
+  XCTAssertTrue([message2.a hasA]);
+  XCTAssertEqual([message2.a.a.strToStr count], (NSUInteger)1);
+}
+
+- (void)testAutocreatedMapShared {
+  // Multiple objects pointing to the same map.
+  TestRecursiveMessageWithRepeatedField *message1a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message1b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message1a.a.iToI = message1b.a.iToI;
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertFalse([message1b hasA]);
+  [message1a.a.iToI setValue:1 forKey:2];
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertTrue([message1b hasA]);
+  XCTAssertEqual(message1a.a.iToI, message1b.a.iToI);
+
+  TestRecursiveMessageWithRepeatedField *message2a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message2a.a.strToStr = message2b.a.strToStr;
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertFalse([message2b hasA]);
+  [message2a.a.strToStr setObject:@"bar" forKey:@"foo"];
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertTrue([message2b hasA]);
+  XCTAssertEqual(message2a.a.strToStr, message2b.a.strToStr);
+}
+
+- (void)testAutocreatedMapCopy {
+  // Copy should not copy autocreated maps.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  XCTAssertNotNil(message.strToStr);
+  XCTAssertNotNil(message.iToI);
+  TestRecursiveMessageWithRepeatedField *message2 =
+      [[message copy] autorelease];
+  // Pointer conparisions.
+  XCTAssertNotEqual(message.strToStr, message2.strToStr);
+  XCTAssertNotEqual(message.iToI, message2.iToI);
+
+  // Mutable copy should copy empty arrays that were explicitly set (end up
+  // with different objects that are equal).
+  TestRecursiveMessageWithRepeatedField *message3 =
+      [TestRecursiveMessageWithRepeatedField message];
+  message3.iToI = [GPBInt32Int32Dictionary dictionaryWithValue:10 forKey:20];
+  message3.strToStr =
+      [NSMutableDictionary dictionaryWithObject:@"abc" forKey:@"123"];
+  XCTAssertNotNil(message.iToI);
+  XCTAssertNotNil(message.iToI);
+  TestRecursiveMessageWithRepeatedField *message4 =
+      [[message3 copy] autorelease];
+  XCTAssertNotEqual(message3.iToI, message4.iToI);
+  XCTAssertEqualObjects(message3.iToI, message4.iToI);
+  XCTAssertNotEqual(message3.strToStr, message4.strToStr);
+  XCTAssertEqualObjects(message3.strToStr, message4.strToStr);
+}
+
+- (void)testAutocreatedMapRetain {
+  // Should be able to retain autocreated map while the creator is dealloced.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+
+  @autoreleasepool {
+    TestRecursiveMessageWithRepeatedField *message2 =
+        [TestRecursiveMessageWithRepeatedField message];
+    message.iToI = message2.iToI;
+    message.strToStr = message2.strToStr;
+    // Pointer conparision
+    XCTAssertEqual(message.iToI->_autocreator, message2);
+    XCTAssertTrue([message.strToStr
+        isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertEqual(
+        ((GPBAutocreatedDictionary *)message.strToStr)->_autocreator,
+        message2);
+  }
+
+  XCTAssertNil(message.iToI->_autocreator);
+  XCTAssertTrue(
+      [message.strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+  XCTAssertNil(
+      ((GPBAutocreatedDictionary *)message.strToStr)->_autocreator);
+}
+
+- (void)testSetNilAutocreatedMap {
+  // Setting map to nil should cause it to lose its delegate.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  GPBInt32Int32Dictionary *iToI = [message.iToI retain];
+  GPBAutocreatedDictionary *strToStr =
+      (GPBAutocreatedDictionary *)[message.strToStr retain];
+  XCTAssertTrue([strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+  XCTAssertEqual(iToI->_autocreator, message);
+  XCTAssertEqual(strToStr->_autocreator, message);
+  message.iToI = nil;
+  message.strToStr = nil;
+  XCTAssertNil(iToI->_autocreator);
+  XCTAssertNil(strToStr->_autocreator);
+  [iToI release];
+  [strToStr release];
+}
+
+- (void)testReplaceAutocreatedMap {
+  // Replacing map should orphan the old one and cause its creator to become
+  // visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iToI);
+    XCTAssertFalse([message hasA]);
+    GPBInt32Int32Dictionary *iToI = [message.a.iToI retain];
+    XCTAssertEqual(iToI->_autocreator, message.a);  // Pointer comparision
+    message.a.iToI = [GPBInt32Int32Dictionary dictionaryWithValue:6 forKey:7];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.iToI, iToI);  // Pointer comparision
+    XCTAssertNil(iToI->_autocreator);
+    [iToI release];
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strToStr);
+    XCTAssertFalse([message hasA]);
+    GPBAutocreatedDictionary *strToStr =
+        (GPBAutocreatedDictionary *)[message.a.strToStr retain];
+    XCTAssertTrue([strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertEqual(strToStr->_autocreator, message.a);  // Pointer comparision
+    message.a.strToStr =
+        [NSMutableDictionary dictionaryWithObject:@"abc" forKey:@"def"];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.strToStr, strToStr);  // Pointer comparision
+    XCTAssertNil(strToStr->_autocreator);
+    [strToStr release];
+  }
+}
+
+- (void)testSetAutocreatedMapToSelf {
+  // Setting map to itself should cause it to become visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iToI);
+    XCTAssertFalse([message hasA]);
+    message.a.iToI = message.a.iToI;
+    XCTAssertTrue([message hasA]);
+    XCTAssertNil(message.a.iToI->_autocreator);
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strToStr);
+    XCTAssertFalse([message hasA]);
+    message.a.strToStr = message.a.strToStr;
+    XCTAssertTrue([message hasA]);
+    XCTAssertTrue([message.a.strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertNil(((GPBAutocreatedDictionary *)message.a.strToStr)->_autocreator);
+  }
+}
+
+- (void)testAutocreatedMapRemoveAllValues {
+  // Calling removeAll on autocreated map should not cause it to be visible.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  [message.a.iToI removeAll];
+  XCTAssertFalse([message hasA]);
+  [message.a.strToStr removeAllObjects];
+  XCTAssertFalse([message hasA]);
+}
+
+- (void)testExtensionAccessors {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+  [self assertAllExtensionsSet:message repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testExtensionRepeatedSetters {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+  [self modifyRepeatedExtensions:message];
+  [self assertRepeatedExtensionsModified:message
+                           repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testExtensionDefaults {
+  [self assertExtensionsClear:[TestAllExtensions message]];
+}
+
+- (void)testExtensionIsEquals {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+  [self modifyRepeatedExtensions:message];
+  TestAllExtensions *message2 = [TestAllExtensions message];
+  [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount];
+  XCTAssertFalse([message isEqual:message2]);
+  message2 = [TestAllExtensions message];
+  [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount];
+  [self modifyRepeatedExtensions:message2];
+  XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testExtensionsMergeFrom {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+  [self modifyRepeatedExtensions:message];
+
+  message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+  TestAllExtensions *message2 = [TestAllExtensions message];
+  [self modifyRepeatedExtensions:message2];
+  [message2 mergeFrom:message];
+
+  XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testDefaultingExtensionMessages {
+  TestAllExtensions *message = [TestAllExtensions message];
+
+  // Initially they should all not have values.
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+  XCTAssertFalse([message
+      hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+  // They should auto create something when fetched.
+
+  TestAllTypes_OptionalGroup *optionalGroup =
+      [message getExtension:[UnittestRoot optionalGroupExtension]];
+  TestAllTypes_NestedMessage *optionalNestedMessage =
+      [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
+  ForeignMessage *optionalForeignMessage =
+      [message getExtension:[UnittestRoot optionalForeignMessageExtension]];
+  ImportMessage *optionalImportMessage =
+      [message getExtension:[UnittestRoot optionalImportMessageExtension]];
+  PublicImportMessage *optionalPublicImportMessage = [message
+      getExtension:[UnittestRoot optionalPublicImportMessageExtension]];
+  TestAllTypes_NestedMessage *optionalLazyMessage =
+      [message getExtension:[UnittestRoot optionalLazyMessageExtension]];
+
+  XCTAssertNotNil(optionalGroup);
+  XCTAssertNotNil(optionalNestedMessage);
+  XCTAssertNotNil(optionalForeignMessage);
+  XCTAssertNotNil(optionalImportMessage);
+  XCTAssertNotNil(optionalPublicImportMessage);
+  XCTAssertNotNil(optionalLazyMessage);
+
+  // Although it auto-created empty messages, it should not show that it has
+  // them.
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+  // And they set that value back in to the message since the value created was
+  // mutable (so a second fetch should give the same object).
+
+  XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]],
+                 optionalGroup);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalNestedMessageExtension]],
+      optionalNestedMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalForeignMessageExtension]],
+      optionalForeignMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalImportMessageExtension]],
+      optionalImportMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+      optionalPublicImportMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalLazyMessageExtension]],
+      optionalLazyMessage);
+
+  // And the default objects for a second message should be distinct (again,
+  // since they are mutable, each needs their own copy).
+
+  TestAllExtensions *message2 = [TestAllExtensions message];
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalGroupExtension]],
+      optionalGroup);
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalNestedMessageExtension]],
+      optionalNestedMessage);
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalForeignMessageExtension]],
+      optionalForeignMessage);
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalImportMessageExtension]],
+      optionalImportMessage);
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+      optionalPublicImportMessage);
+  XCTAssertNotEqual(
+      [message2 getExtension:[UnittestRoot optionalLazyMessageExtension]],
+      optionalLazyMessage);
+
+  // Clear values, and on next access you get back new submessages.
+
+  [message setExtension:[UnittestRoot optionalGroupExtension] value:nil];
+  [message setExtension:[UnittestRoot optionalGroupExtension] value:nil];
+  [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+                  value:nil];
+  [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+                  value:nil];
+  [message setExtension:[UnittestRoot optionalImportMessageExtension]
+                  value:nil];
+  [message setExtension:[UnittestRoot optionalPublicImportMessageExtension]
+                  value:nil];
+  [message setExtension:[UnittestRoot optionalLazyMessageExtension] value:nil];
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+  XCTAssertFalse([message
+      hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+  XCTAssertFalse(
+      [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+  XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]],
+                 optionalGroup);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalNestedMessageExtension]],
+      optionalNestedMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalForeignMessageExtension]],
+      optionalForeignMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalImportMessageExtension]],
+      optionalImportMessage);
+  XCTAssertEqual(
+      [message
+          getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+      optionalPublicImportMessage);
+  XCTAssertEqual(
+      [message getExtension:[UnittestRoot optionalLazyMessageExtension]],
+      optionalLazyMessage);
+}
+
+- (void)testMultiplePointersToAutocreatedExtension {
+  // 2 objects point to the same auto-created extension. One should "has" it.
+  // The other should not.
+  TestAllExtensions *message = [TestAllExtensions message];
+  TestAllExtensions *message2 = [TestAllExtensions message];
+  GPBExtensionDescriptor *extension = [UnittestRoot optionalGroupExtension];
+  [message setExtension:extension value:[message2 getExtension:extension]];
+  XCTAssertEqual([message getExtension:extension],
+                 [message2 getExtension:extension]);
+  XCTAssertFalse([message2 hasExtension:extension]);
+  XCTAssertTrue([message hasExtension:extension]);
+
+  TestAllTypes_OptionalGroup *extensionValue =
+      [message2 getExtension:extension];
+  extensionValue.a = 1;
+  XCTAssertTrue([message2 hasExtension:extension]);
+  XCTAssertTrue([message hasExtension:extension]);
+}
+
+- (void)testCopyWithAutocreatedExtension {
+  // Mutable copy shouldn't copy autocreated extensions.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *optionalGroupExtension =
+      [UnittestRoot optionalGroupExtension];
+  GPBExtensionDescriptor *optionalNestedMessageExtesion =
+      [UnittestRoot optionalNestedMessageExtension];
+  TestAllTypes_OptionalGroup *optionalGroup =
+      [message getExtension:optionalGroupExtension];
+  optionalGroup.a = 42;
+  XCTAssertNotNil(optionalGroup);
+  XCTAssertNotNil([message getExtension:optionalNestedMessageExtesion]);
+  XCTAssertTrue([message hasExtension:optionalGroupExtension]);
+  XCTAssertFalse([message hasExtension:optionalNestedMessageExtesion]);
+
+  TestAllExtensions *message2 = [[message copy] autorelease];
+
+  // message2 should end up with its own copy of the optional group.
+  XCTAssertTrue([message2 hasExtension:optionalGroupExtension]);
+  XCTAssertEqualObjects([message getExtension:optionalGroupExtension],
+                        [message2 getExtension:optionalGroupExtension]);
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual([message getExtension:optionalGroupExtension],
+                    [message2 getExtension:optionalGroupExtension]);
+
+  XCTAssertFalse([message2 hasExtension:optionalNestedMessageExtesion]);
+  // Intentionally doing a pointer comparison (auto creation should be
+  // different)
+  XCTAssertNotEqual([message getExtension:optionalNestedMessageExtesion],
+                    [message2 getExtension:optionalNestedMessageExtesion]);
+}
+
+- (void)testClearMessageAutocreatedExtension {
+  // Call clear should cause it to recreate its autocreated extensions.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *optionalGroupExtension =
+      [UnittestRoot optionalGroupExtension];
+  TestAllTypes_OptionalGroup *optionalGroup =
+      [[message getExtension:optionalGroupExtension] retain];
+  [message clear];
+  TestAllTypes_OptionalGroup *optionalGroupNew =
+      [message getExtension:optionalGroupExtension];
+
+  // Intentionally doing a pointer comparison.
+  XCTAssertNotEqual(optionalGroup, optionalGroupNew);
+  [optionalGroup release];
+}
+
+- (void)testRetainAutocreatedExtension {
+  // Should be able to retain autocreated extension while the creator is
+  // dealloced.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *optionalGroupExtension =
+      [UnittestRoot optionalGroupExtension];
+
+  @autoreleasepool {
+    TestAllExtensions *message2 = [TestAllExtensions message];
+    [message setExtension:optionalGroupExtension
+                    value:[message2 getExtension:optionalGroupExtension]];
+    XCTAssertTrue(GPBWasMessageAutocreatedBy(
+        [message getExtension:optionalGroupExtension], message2));
+  }
+
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(
+      [message getExtension:optionalGroupExtension], message));
+}
+
+- (void)testClearAutocreatedExtension {
+  // Clearing autocreated extension should NOT cause it to lose its creator.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *optionalGroupExtension =
+      [UnittestRoot optionalGroupExtension];
+  TestAllTypes_OptionalGroup *optionalGroup =
+      [[message getExtension:optionalGroupExtension] retain];
+  [message clearExtension:optionalGroupExtension];
+  TestAllTypes_OptionalGroup *optionalGroupNew =
+      [message getExtension:optionalGroupExtension];
+  XCTAssertEqual(optionalGroup, optionalGroupNew);
+  XCTAssertFalse([message hasExtension:optionalGroupExtension]);
+  [optionalGroup release];
+
+  // Clearing autocreated extension should not cause its creator to become
+  // visible
+  GPBExtensionDescriptor *recursiveExtension =
+      [UnittestObjcRoot recursiveExtension];
+  TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension];
+  TestAllExtensions *message_lvl3 =
+      [message_lvl2 getExtension:recursiveExtension];
+  [message_lvl3 clearExtension:recursiveExtension];
+  XCTAssertFalse([message hasExtension:recursiveExtension]);
+}
+
+- (void)testSetAutocreatedExtensionBecomesVisible {
+  // Setting an extension should cause the extension to appear to its creator.
+  // Test this several levels deep.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *recursiveExtension =
+      [UnittestObjcRoot recursiveExtension];
+  TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension];
+  TestAllExtensions *message_lvl3 =
+      [message_lvl2 getExtension:recursiveExtension];
+  TestAllExtensions *message_lvl4 =
+      [message_lvl3 getExtension:recursiveExtension];
+  XCTAssertFalse([message hasExtension:recursiveExtension]);
+  XCTAssertFalse([message_lvl2 hasExtension:recursiveExtension]);
+  XCTAssertFalse([message_lvl3 hasExtension:recursiveExtension]);
+  XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]);
+  [message_lvl4 setExtension:[UnittestRoot optionalInt32Extension] value:@(1)];
+  XCTAssertTrue([message hasExtension:recursiveExtension]);
+  XCTAssertTrue([message_lvl2 hasExtension:recursiveExtension]);
+  XCTAssertTrue([message_lvl3 hasExtension:recursiveExtension]);
+  XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]);
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl4, message_lvl3));
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl3, message_lvl2));
+  XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl2, message));
+}
+
+- (void)testSetAutocreatedExtensionToSelf {
+  // Setting extension to itself should cause it to become visible.
+  TestAllExtensions *message = [TestAllExtensions message];
+  GPBExtensionDescriptor *optionalGroupExtension =
+      [UnittestRoot optionalGroupExtension];
+  XCTAssertNotNil([message getExtension:optionalGroupExtension]);
+  XCTAssertFalse([message hasExtension:optionalGroupExtension]);
+  [message setExtension:optionalGroupExtension
+                  value:[message getExtension:optionalGroupExtension]];
+  XCTAssertTrue([message hasExtension:optionalGroupExtension]);
+}
+
+- (void)testAutocreatedExtensionMemoryLeaks {
+  GPBExtensionDescriptor *recursiveExtension =
+      [UnittestObjcRoot recursiveExtension];
+
+  // Test for memory leaks with autocreated extensions.
+  TestAllExtensions *message;
+  TestAllExtensions *message_lvl2;
+  TestAllExtensions *message_lvl3;
+  TestAllExtensions *message_lvl4;
+  @autoreleasepool {
+    message = [[TestAllExtensions alloc] init];
+    message_lvl2 = [[message getExtension:recursiveExtension] retain];
+    message_lvl3 = [[message_lvl2 getExtension:recursiveExtension] retain];
+    message_lvl4 = [[message_lvl3 getExtension:recursiveExtension] retain];
+    [message_lvl2 setExtension:[UnittestRoot optionalInt32Extension]
+                         value:@(1)];
+  }
+
+  XCTAssertEqual(message.retainCount, (NSUInteger)1);
+  @autoreleasepool {
+    [message release];
+  }
+  XCTAssertEqual(message_lvl2.retainCount, (NSUInteger)1);
+  @autoreleasepool {
+    [message_lvl2 release];
+  }
+  XCTAssertEqual(message_lvl3.retainCount, (NSUInteger)1);
+  @autoreleasepool {
+    [message_lvl3 release];
+  }
+  XCTAssertEqual(message_lvl4.retainCount, (NSUInteger)1);
+  [message_lvl4 release];
+}
+
+- (void)testSetExtensionWithAutocreatedValue {
+  GPBExtensionDescriptor *recursiveExtension =
+      [UnittestObjcRoot recursiveExtension];
+
+  TestAllExtensions *message;
+  @autoreleasepool {
+    message = [[TestAllExtensions alloc] init];
+    [message getExtension:recursiveExtension];
+  }
+
+  // This statements checks that the extension value isn't accidentally
+  // dealloced when removing it from the autocreated map.
+  [message setExtension:recursiveExtension
+                  value:[message getExtension:recursiveExtension]];
+  XCTAssertTrue([message hasExtension:recursiveExtension]);
+  [message release];
+}
+
+- (void)testRecursion {
+  TestRecursiveMessage *message = [TestRecursiveMessage message];
+  XCTAssertNotNil(message.a);
+  XCTAssertNotNil(message.a.a);
+  XCTAssertEqual(message.a.a.i, 0);
+}
+
+- (void)testGenerateAndParseUnknownMessage {
+  GPBUnknownFieldSet *unknowns =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  [unknowns mergeVarintField:123 value:456];
+  GPBMessage *message = [GPBMessage message];
+  [message setUnknownFields:unknowns];
+  NSData *data = [message data];
+  GPBMessage *message2 =
+      [GPBMessage parseFromData:data extensionRegistry:nil error:NULL];
+  XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testDelimitedWriteAndParseMultipleMessages {
+  GPBUnknownFieldSet *unknowns1 =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  [unknowns1 mergeVarintField:123 value:456];
+  GPBMessage *message1 = [GPBMessage message];
+  [message1 setUnknownFields:unknowns1];
+
+  GPBUnknownFieldSet *unknowns2 =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  [unknowns2 mergeVarintField:789 value:987];
+  [unknowns2 mergeVarintField:654 value:321];
+  GPBMessage *message2 = [GPBMessage message];
+  [message2 setUnknownFields:unknowns2];
+
+  NSMutableData *delimitedData = [NSMutableData data];
+  [delimitedData appendData:[message1 delimitedData]];
+  [delimitedData appendData:[message2 delimitedData]];
+  GPBCodedInputStream *input =
+      [GPBCodedInputStream streamWithData:delimitedData];
+  GPBMessage *message3 = [GPBMessage parseDelimitedFromCodedInputStream:input
+                                                      extensionRegistry:nil
+                                                                  error:NULL];
+  GPBMessage *message4 = [GPBMessage parseDelimitedFromCodedInputStream:input
+                                                      extensionRegistry:nil
+                                                                  error:NULL];
+  XCTAssertEqualObjects(message1, message3);
+  XCTAssertEqualObjects(message2, message4);
+}
+
+- (void)testDuplicateEnums {
+  XCTAssertEqual(TestEnumWithDupValue_Foo1, TestEnumWithDupValue_Foo2);
+}
+
+- (void)testWeirdDefaults {
+  ObjcWeirdDefaults *message = [ObjcWeirdDefaults message];
+  GPBDescriptor *descriptor = [[message class] descriptor];
+  GPBFieldDescriptor *fieldDesc = [descriptor fieldWithName:@"foo"];
+  XCTAssertNotNil(fieldDesc);
+  XCTAssertTrue(fieldDesc.hasDefaultValue);
+  XCTAssertFalse(message.hasFoo);
+  XCTAssertEqualObjects(message.foo, @"");
+
+  fieldDesc = [descriptor fieldWithName:@"bar"];
+  XCTAssertNotNil(fieldDesc);
+  XCTAssertTrue(fieldDesc.hasDefaultValue);
+  XCTAssertFalse(message.hasBar);
+  XCTAssertEqualObjects(message.bar, GPBEmptyNSData());
+}
+
+- (void)testEnumDescriptorFromExtensionDescriptor {
+  GPBExtensionDescriptor *extDescriptor =
+      [UnittestRoot optionalForeignEnumExtension];
+  XCTAssertEqual(extDescriptor.dataType, GPBDataTypeEnum);
+  GPBEnumDescriptor *enumDescriptor = extDescriptor.enumDescriptor;
+  GPBEnumDescriptor *expectedDescriptor = ForeignEnum_EnumDescriptor();
+  XCTAssertEqualObjects(enumDescriptor, expectedDescriptor);
+}
+
+- (void)testPropertyNaming {
+  // objectivec_helpers.cc has some special handing to get proper all caps
+  // for a few cases to meet objc developer expectations.
+  //
+  // This "test" confirms that the expected names are generated, otherwise the
+  // test itself will fail to compile.
+  ObjCPropertyNaming *msg = [ObjCPropertyNaming message];
+  // On their own, at the end, in the middle.
+  msg.URL = @"good";
+  msg.thumbnailURL = @"good";
+  msg.URLFoo = @"good";
+  msg.someURLBlah = @"good";
+  msg.HTTP = @"good";
+  msg.HTTPS = @"good";
+  // No caps since it was "urls".
+  [msg.urlsArray addObject:@"good"];
+}
+
+- (void)testEnumNaming {
+  // objectivec_helpers.cc has some interesting cases to deal with in
+  // EnumValueName/EnumValueShortName.  Confirm that things generated as
+  // expected.
+
+  // This block just has to compile to confirm we got the expected types/names.
+  // The *_IsValidValue() calls are just there to keep the projects warnings
+  // flags happy by providing use of the variables/values.
+
+  Foo aFoo = Foo_SerializedSize;
+  Foo_IsValidValue(aFoo);
+  aFoo = Foo_Size;
+  Foo_IsValidValue(aFoo);
+
+  Category_Enum aCat = Category_Enum_Red;
+  Category_Enum_IsValidValue(aCat);
+
+  Time aTime = Time_Base;
+  Time_IsValidValue(aTime);
+  aTime = Time_SomethingElse;
+  Time_IsValidValue(aTime);
+
+  // This block confirms the names in the decriptors is what we wanted.
+
+  GPBEnumDescriptor *descriptor;
+  NSString *valueName;
+
+  descriptor = Foo_EnumDescriptor();
+  XCTAssertNotNil(descriptor);
+  XCTAssertEqualObjects(@"Foo", descriptor.name);
+  valueName = [descriptor enumNameForValue:Foo_SerializedSize];
+  XCTAssertEqualObjects(@"Foo_SerializedSize", valueName);
+  valueName = [descriptor enumNameForValue:Foo_Size];
+  XCTAssertEqualObjects(@"Foo_Size", valueName);
+
+  descriptor = Category_Enum_EnumDescriptor();
+  XCTAssertNotNil(descriptor);
+  XCTAssertEqualObjects(@"Category_Enum", descriptor.name);
+  valueName = [descriptor enumNameForValue:Category_Enum_Red];
+  XCTAssertEqualObjects(@"Category_Enum_Red", valueName);
+
+  descriptor = Time_EnumDescriptor();
+  XCTAssertNotNil(descriptor);
+  XCTAssertEqualObjects(@"Time", descriptor.name);
+  valueName = [descriptor enumNameForValue:Time_Base];
+  XCTAssertEqualObjects(@"Time_Base", valueName);
+  valueName = [descriptor enumNameForValue:Time_SomethingElse];
+  XCTAssertEqualObjects(@"Time_SomethingElse", valueName);
+}
+
+- (void)testNegativeEnums {
+  EnumTestMsg *msg = [EnumTestMsg message];
+
+  // Defaults
+  XCTAssertEqual(msg.foo, EnumTestMsg_MyEnum_Zero);
+  XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One);
+  XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne);
+  // Bounce to wire and back.
+  NSData *data = [msg data];
+  XCTAssertNotNil(data);
+  EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:data error:NULL];
+  XCTAssertEqualObjects(msgPrime, msg);
+  XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
+  XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One);
+  XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegOne);
+
+  // Other values
+  msg.bar = EnumTestMsg_MyEnum_Two;
+  msg.baz = EnumTestMsg_MyEnum_NegTwo;
+  XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two);
+  XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo);
+  // Bounce to wire and back.
+  data = [msg data];
+  XCTAssertNotNil(data);
+  msgPrime = [EnumTestMsg parseFromData:data error:NULL];
+  XCTAssertEqualObjects(msgPrime, msg);
+  XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
+  XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two);
+  XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegTwo);
+
+  // Repeated field (shouldn't ever be an issue since developer has to use the
+  // right GPBArray methods themselves).
+  msg.mumbleArray = [GPBEnumArray
+      arrayWithValidationFunction:EnumTestMsg_MyEnum_IsValidValue];
+  [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Zero];
+  [msg.mumbleArray addValue:EnumTestMsg_MyEnum_One];
+  [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Two];
+  [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegOne];
+  [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegTwo];
+  XCTAssertEqual([msg.mumbleArray valueAtIndex:0], EnumTestMsg_MyEnum_Zero);
+  XCTAssertEqual([msg.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One);
+  XCTAssertEqual([msg.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two);
+  XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne);
+  XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo);
+  // Bounce to wire and back.
+  data = [msg data];
+  XCTAssertNotNil(data);
+  msgPrime = [EnumTestMsg parseFromData:data error:NULL];
+  XCTAssertEqualObjects(msgPrime, msg);
+  XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0],
+                 EnumTestMsg_MyEnum_Zero);
+  XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One);
+  XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two);
+  XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:3],
+                 EnumTestMsg_MyEnum_NegOne);
+  XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:4],
+                 EnumTestMsg_MyEnum_NegTwo);
+}
+
+- (void)testOneBasedEnumHolder {
+  // Test case for https://github.com/google/protobuf/issues/1453
+  // Message with no explicit defaults, but a non zero default for an enum.
+  MessageWithOneBasedEnum *enumMsg = [MessageWithOneBasedEnum message];
+  XCTAssertEqual(enumMsg.enumField, MessageWithOneBasedEnum_OneBasedEnum_One);
+}
+
+- (void)testBoolOffsetUsage {
+  // Bools use storage within has_bits; this test ensures that this is honored
+  // in all places where things should crash or fail based on reading out of
+  // field storage instead.
+  BoolOnlyMessage *msg1 = [BoolOnlyMessage message];
+  BoolOnlyMessage *msg2 = [BoolOnlyMessage message];
+
+  msg1.boolField1 = YES;
+  msg2.boolField1 = YES;
+  msg1.boolField3 = YES;
+  msg2.boolField3 = YES;
+  msg1.boolField5 = YES;
+  msg2.boolField5 = YES;
+  msg1.boolField7 = YES;
+  msg2.boolField7 = YES;
+  msg1.boolField9 = YES;
+  msg2.boolField9 = YES;
+  msg1.boolField11 = YES;
+  msg2.boolField11 = YES;
+  msg1.boolField13 = YES;
+  msg2.boolField13 = YES;
+  msg1.boolField15 = YES;
+  msg2.boolField15 = YES;
+  msg1.boolField17 = YES;
+  msg2.boolField17 = YES;
+  msg1.boolField19 = YES;
+  msg2.boolField19 = YES;
+  msg1.boolField21 = YES;
+  msg2.boolField21 = YES;
+  msg1.boolField23 = YES;
+  msg2.boolField23 = YES;
+  msg1.boolField25 = YES;
+  msg2.boolField25 = YES;
+  msg1.boolField27 = YES;
+  msg2.boolField27 = YES;
+  msg1.boolField29 = YES;
+  msg2.boolField29 = YES;
+  msg1.boolField31 = YES;
+  msg2.boolField31 = YES;
+
+  msg1.boolField32 = YES;
+  msg2.boolField32 = YES;
+
+  XCTAssertTrue(msg1 != msg2); // Different pointers.
+  XCTAssertEqual([msg1 hash], [msg2 hash]);
+  XCTAssertEqualObjects(msg1, msg2);
+
+  BoolOnlyMessage *msg1Prime = [[msg1 copy] autorelease];
+  XCTAssertTrue(msg1Prime != msg1); // Different pointers.
+  XCTAssertEqual([msg1 hash], [msg1Prime hash]);
+  XCTAssertEqualObjects(msg1, msg1Prime);
+
+  // Field set in one, but not the other means they don't match (even if
+  // set to default value).
+  msg1Prime.boolField2 = NO;
+  XCTAssertNotEqualObjects(msg1Prime, msg1);
+  // And when set to different values.
+  msg1.boolField2 = YES;
+  XCTAssertNotEqualObjects(msg1Prime, msg1);
+  // And then they match again.
+  msg1.boolField2 = NO;
+  XCTAssertEqualObjects(msg1Prime, msg1);
+  XCTAssertEqual([msg1 hash], [msg1Prime hash]);
+}
+
+@end
diff --git a/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm b/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm
new file mode 100644
index 0000000..9ba8fd0
--- /dev/null
+++ b/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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 "GPBTestUtilities.h"
+
+
+//
+// This is just a compile test (here to make sure things never regress).
+//
+// Objective C++ can run into issues with how the NS_ENUM/CF_ENUM declartion
+// works because of the C++ spec being used for that compilation unit. So
+// the fact that these imports all work without errors/warning means things
+// are still good.
+//
+// The "well know types" should have cross file enums needing imports.
+#import "GPBProtocolBuffers.h"
+// Some of the tests explicitly use cross file enums also.
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
+
+// Sanity check the conditions of the test within the Xcode project.
+#if !__cplusplus
+  #error This isn't compiled as Objective C++?
+#elif __cplusplus >= 201103L
+  // If this trips, it means the Xcode default might have change (or someone
+  // edited the testing project) and it might be time to revisit the GPB_ENUM
+  // define in GPBBootstrap.h.
+  #warning Did the Xcode default for C++ spec change?
+#endif
+
+
+// Dummy XCTest.
+@interface GPBObjectiveCPlusPlusTests : GPBTestCase
+@end
+
+@implementation GPBObjectiveCPlusPlusTests
+- (void)testCPlusPlus {
+  // Nothing, This was a compile test.
+  XCTAssertTrue(YES);
+}
+@end
diff --git a/objectivec/Tests/GPBPerfTests.m b/objectivec/Tests/GPBPerfTests.m
new file mode 100644
index 0000000..1259d14
--- /dev/null
+++ b/objectivec/Tests/GPBPerfTests.m
@@ -0,0 +1,307 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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 "GPBTestUtilities.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+
+//
+// This file really just uses the unittests framework as a testbed to
+// run some simple performance tests. The data can then be used to help
+// evaluate changes to the runtime.
+//
+
+static const uint32_t kRepeatedCount = 100;
+
+@interface PerfTests : GPBTestCase
+@end
+
+@implementation PerfTests
+
+- (void)setUp {
+  // A convenient place to put a break point if you want to connect instruments.
+  [super setUp];
+}
+
+- (void)testMessagePerformance {
+  [self measureBlock:^{
+    for (int i = 0; i < 200; ++i) {
+      TestAllTypes* message = [[TestAllTypes alloc] init];
+      [self setAllFields:message repeatedCount:kRepeatedCount];
+      NSData* rawBytes = [message data];
+      [message release];
+      message = [[TestAllTypes alloc] initWithData:rawBytes error:NULL];
+      [message release];
+    }
+  }];
+}
+
+- (void)testExtensionsPerformance {
+  [self measureBlock:^{
+    for (int i = 0; i < 200; ++i) {
+      TestAllExtensions* message = [[TestAllExtensions alloc] init];
+      [self setAllExtensions:message repeatedCount:kRepeatedCount];
+      NSData* rawBytes = [message data];
+      [message release];
+      TestAllExtensions* message2 =
+          [[TestAllExtensions alloc] initWithData:rawBytes error:NULL];
+      [message2 release];
+    }
+  }];
+}
+
+- (void)testPackedTypesPerformance {
+  [self measureBlock:^{
+    for (int i = 0; i < 1000; ++i) {
+      TestPackedTypes* message = [[TestPackedTypes alloc] init];
+      [self setPackedFields:message repeatedCount:kRepeatedCount];
+      NSData* rawBytes = [message data];
+      [message release];
+      message = [[TestPackedTypes alloc] initWithData:rawBytes error:NULL];
+      [message release];
+    }
+  }];
+}
+
+- (void)testPackedExtensionsPerformance {
+  [self measureBlock:^{
+    for (int i = 0; i < 1000; ++i) {
+      TestPackedExtensions* message = [[TestPackedExtensions alloc] init];
+      [self setPackedExtensions:message repeatedCount:kRepeatedCount];
+      NSData* rawBytes = [message data];
+      [message release];
+      TestPackedExtensions* message2 =
+          [[TestPackedExtensions alloc] initWithData:rawBytes error:NULL];
+      [message2 release];
+    }
+  }];
+}
+
+- (void)testHas {
+  TestAllTypes* message = [self allSetRepeatedCount:1];
+  [self measureBlock:^{
+    for (int i = 0; i < 10000; ++i) {
+      [message hasOptionalInt32];
+      message.hasOptionalInt32 = NO;
+      [message hasOptionalInt32];
+
+      [message hasOptionalInt64];
+      message.hasOptionalInt64 = NO;
+      [message hasOptionalInt64];
+
+      [message hasOptionalUint32];
+      message.hasOptionalUint32 = NO;
+      [message hasOptionalUint32];
+
+      [message hasOptionalUint64];
+      message.hasOptionalUint64 = NO;
+      [message hasOptionalUint64];
+
+      [message hasOptionalSint32];
+      message.hasOptionalSint32 = NO;
+      [message hasOptionalSint32];
+
+      [message hasOptionalSint64];
+      message.hasOptionalSint64 = NO;
+      [message hasOptionalSint64];
+
+      [message hasOptionalFixed32];
+      message.hasOptionalFixed32 = NO;
+      [message hasOptionalFixed32];
+
+      [message hasOptionalFixed64];
+      message.hasOptionalFixed64 = NO;
+      [message hasOptionalFixed64];
+
+      [message hasOptionalSfixed32];
+      message.hasOptionalSfixed32 = NO;
+      [message hasOptionalSfixed32];
+
+      [message hasOptionalSfixed64];
+      message.hasOptionalSfixed64 = NO;
+      [message hasOptionalSfixed64];
+
+      [message hasOptionalFloat];
+      message.hasOptionalFloat = NO;
+      [message hasOptionalFloat];
+
+      [message hasOptionalDouble];
+      message.hasOptionalDouble = NO;
+      [message hasOptionalDouble];
+
+      [message hasOptionalBool];
+      message.hasOptionalBool = NO;
+      [message hasOptionalBool];
+
+      [message hasOptionalString];
+      message.hasOptionalString = NO;
+      [message hasOptionalString];
+
+      [message hasOptionalBytes];
+      message.hasOptionalBytes = NO;
+      [message hasOptionalBytes];
+
+      [message hasOptionalGroup];
+      message.hasOptionalGroup = NO;
+      [message hasOptionalGroup];
+
+      [message hasOptionalNestedMessage];
+      message.hasOptionalNestedMessage = NO;
+      [message hasOptionalNestedMessage];
+
+      [message hasOptionalForeignMessage];
+      message.hasOptionalForeignMessage = NO;
+      [message hasOptionalForeignMessage];
+
+      [message hasOptionalImportMessage];
+      message.hasOptionalImportMessage = NO;
+      [message hasOptionalImportMessage];
+
+      [message.optionalGroup hasA];
+      message.optionalGroup.hasA = NO;
+      [message.optionalGroup hasA];
+
+      [message.optionalNestedMessage hasBb];
+      message.optionalNestedMessage.hasBb = NO;
+      [message.optionalNestedMessage hasBb];
+
+      [message.optionalForeignMessage hasC];
+      message.optionalForeignMessage.hasC = NO;
+      [message.optionalForeignMessage hasC];
+
+      [message.optionalImportMessage hasD];
+      message.optionalImportMessage.hasD = NO;
+      [message.optionalImportMessage hasD];
+
+      [message hasOptionalNestedEnum];
+      message.hasOptionalNestedEnum = NO;
+      [message hasOptionalNestedEnum];
+
+      [message hasOptionalForeignEnum];
+      message.hasOptionalForeignEnum = NO;
+      [message hasOptionalForeignEnum];
+
+      [message hasOptionalImportEnum];
+      message.hasOptionalImportEnum = NO;
+      [message hasOptionalImportEnum];
+
+      [message hasOptionalStringPiece];
+      message.hasOptionalStringPiece = NO;
+      [message hasOptionalStringPiece];
+
+      [message hasOptionalCord];
+      message.hasOptionalCord = NO;
+      [message hasOptionalCord];
+
+      [message hasDefaultInt32];
+      message.hasDefaultInt32 = NO;
+      [message hasDefaultInt32];
+
+      [message hasDefaultInt64];
+      message.hasDefaultInt64 = NO;
+      [message hasDefaultInt64];
+
+      [message hasDefaultUint32];
+      message.hasDefaultUint32 = NO;
+      [message hasDefaultUint32];
+
+      [message hasDefaultUint64];
+      message.hasDefaultUint64 = NO;
+      [message hasDefaultUint64];
+
+      [message hasDefaultSint32];
+      message.hasDefaultSint32 = NO;
+      [message hasDefaultSint32];
+
+      [message hasDefaultSint64];
+      message.hasDefaultSint64 = NO;
+      [message hasDefaultSint64];
+
+      [message hasDefaultFixed32];
+      message.hasDefaultFixed32 = NO;
+      [message hasDefaultFixed32];
+
+      [message hasDefaultFixed64];
+      message.hasDefaultFixed64 = NO;
+      [message hasDefaultFixed64];
+
+      [message hasDefaultSfixed32];
+      message.hasDefaultSfixed32 = NO;
+      [message hasDefaultSfixed32];
+
+      [message hasDefaultSfixed64];
+      message.hasDefaultSfixed64 = NO;
+      [message hasDefaultSfixed64];
+
+      [message hasDefaultFloat];
+      message.hasDefaultFloat = NO;
+      [message hasDefaultFloat];
+
+      [message hasDefaultDouble];
+      message.hasDefaultDouble = NO;
+      [message hasDefaultDouble];
+
+      [message hasDefaultBool];
+      message.hasDefaultBool = NO;
+      [message hasDefaultBool];
+
+      [message hasDefaultString];
+      message.hasDefaultString = NO;
+      [message hasDefaultString];
+
+      [message hasDefaultBytes];
+      message.hasDefaultBytes = NO;
+      [message hasDefaultBytes];
+
+      [message hasDefaultNestedEnum];
+      message.hasDefaultNestedEnum = NO;
+      [message hasDefaultNestedEnum];
+
+      [message hasDefaultForeignEnum];
+      message.hasDefaultForeignEnum = NO;
+      [message hasDefaultForeignEnum];
+
+      [message hasDefaultImportEnum];
+      message.hasDefaultImportEnum = NO;
+      [message hasDefaultImportEnum];
+
+      [message hasDefaultStringPiece];
+      message.hasDefaultStringPiece = NO;
+      [message hasDefaultStringPiece];
+
+      [message hasDefaultCord];
+      message.hasDefaultCord = NO;
+      [message hasDefaultCord];
+    }
+  }];
+}
+
+@end
diff --git a/objectivec/Tests/GPBSwiftTests.swift b/objectivec/Tests/GPBSwiftTests.swift
new file mode 100644
index 0000000..36ed2a6
--- /dev/null
+++ b/objectivec/Tests/GPBSwiftTests.swift
@@ -0,0 +1,460 @@
+// 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.
+
+import Foundation
+import XCTest
+
+// Test some usage of the ObjC library from Swift.
+
+class GPBBridgeTests: XCTestCase {
+
+  func testProto2Basics() {
+    let msg = Message2()
+    let msg2 = Message2()
+    let msg3 = Message2_OptionalGroup()
+
+    msg.optionalInt32 = 100
+    msg.optionalString = "abc"
+    msg.optionalEnum = .Bar
+    msg2.optionalString = "other"
+    msg.optionalMessage = msg2
+    msg3.a = 200
+    msg.optionalGroup = msg3
+    msg.repeatedInt32Array.addValue(300)
+    msg.repeatedInt32Array.addValue(301)
+    msg.repeatedStringArray.addObject("mno")
+    msg.repeatedStringArray.addObject("pqr")
+    msg.repeatedEnumArray.addValue(Message2_Enum.Bar.rawValue)
+    msg.repeatedEnumArray.addValue(Message2_Enum.Baz.rawValue)
+    msg.mapInt32Int32.setValue(400, forKey:500)
+    msg.mapInt32Int32.setValue(401, forKey:501)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
+    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
+    msg.mapInt32Enum.setValue(Message2_Enum.Baz.rawValue, forKey:601)
+
+    // Check has*.
+    XCTAssertTrue(msg.hasOptionalInt32)
+    XCTAssertTrue(msg.hasOptionalString)
+    XCTAssertTrue(msg.hasOptionalEnum)
+    XCTAssertTrue(msg2.hasOptionalString)
+    XCTAssertTrue(msg.hasOptionalMessage)
+    XCTAssertTrue(msg3.hasA)
+    XCTAssertTrue(msg.hasOptionalGroup)
+    XCTAssertFalse(msg.hasOptionalInt64)
+    XCTAssertFalse(msg.hasOptionalFloat)
+
+    // Check values.
+    XCTAssertEqual(msg.optionalInt32, Int32(100))
+    XCTAssertEqual(msg.optionalString, "abc")
+    XCTAssertEqual(msg2.optionalString, "other")
+    XCTAssertTrue(msg.optionalMessage === msg2)
+    XCTAssertEqual(msg.optionalEnum, Message2_Enum.Bar)
+    XCTAssertEqual(msg3.a, Int32(200))
+    XCTAssertTrue(msg.optionalGroup === msg3)
+    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2))
+    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
+    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
+    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
+    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
+    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue)
+    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue)
+    XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    var intValue: Int32 = 0;
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
+    XCTAssertEqual(intValue, Int32(400))
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
+    XCTAssertEqual(intValue, Int32(401))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Baz.rawValue)
+
+    // Clearing a string with nil.
+    msg2.optionalString = nil
+    XCTAssertFalse(msg2.hasOptionalString)
+    XCTAssertEqual(msg2.optionalString, "")
+
+    // Clearing a message with nil.
+    msg.optionalGroup = nil
+    XCTAssertFalse(msg.hasOptionalGroup)
+    XCTAssertTrue(msg.optionalGroup !== msg3)  // New instance
+
+    // Clear.
+    msg.clear()
+    XCTAssertFalse(msg.hasOptionalInt32)
+    XCTAssertFalse(msg.hasOptionalString)
+    XCTAssertFalse(msg.hasOptionalEnum)
+    XCTAssertFalse(msg.hasOptionalMessage)
+    XCTAssertFalse(msg.hasOptionalInt64)
+    XCTAssertFalse(msg.hasOptionalFloat)
+    XCTAssertEqual(msg.optionalInt32, Int32(0))
+    XCTAssertEqual(msg.optionalString, "")
+    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
+    XCTAssertEqual(msg.optionalEnum, Message2_Enum.Foo)  // Default
+    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0))
+    XCTAssertEqual(msg.repeatedStringArray.count, Int(0))
+    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
+    XCTAssertEqual(msg.mapStringString.count, Int(0))
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
+  }
+
+  func testProto3Basics() {
+    let msg = Message3()
+    let msg2 = Message3()
+
+    msg.optionalInt32 = 100
+    msg.optionalString = "abc"
+    msg.optionalEnum = .Bar
+    msg2.optionalString = "other"
+    msg.optionalMessage = msg2
+    msg.repeatedInt32Array.addValue(300)
+    msg.repeatedInt32Array.addValue(301)
+    msg.repeatedStringArray.addObject("mno")
+    msg.repeatedStringArray.addObject("pqr")
+    // "proto3" syntax lets enum get unknown values.
+    msg.repeatedEnumArray.addValue(Message3_Enum.Bar.rawValue)
+    msg.repeatedEnumArray.addRawValue(666)
+    SetMessage3_OptionalEnum_RawValue(msg2, 666)
+    msg.mapInt32Int32.setValue(400, forKey:500)
+    msg.mapInt32Int32.setValue(401, forKey:501)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
+    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
+    // "proto3" syntax lets enum get unknown values.
+    msg.mapInt32Enum.setRawValue(666, forKey:601)
+
+    // Has only exists on for message fields.
+    XCTAssertTrue(msg.hasOptionalMessage)
+    XCTAssertFalse(msg2.hasOptionalMessage)
+
+    // Check values.
+    XCTAssertEqual(msg.optionalInt32, Int32(100))
+    XCTAssertEqual(msg.optionalString, "abc")
+    XCTAssertEqual(msg2.optionalString, "other")
+    XCTAssertTrue(msg.optionalMessage === msg2)
+    XCTAssertEqual(msg.optionalEnum, Message3_Enum.Bar)
+    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2))
+    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
+    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
+    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
+    XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
+    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
+    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message3_Enum.Bar.rawValue)
+    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue)
+    XCTAssertEqual(msg.repeatedEnumArray.rawValueAtIndex(1), 666)
+    XCTAssertEqual(msg2.optionalEnum, Message3_Enum.GPBUnrecognizedEnumeratorValue)
+    XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Int32(666))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    var intValue: Int32 = 0;
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
+    XCTAssertEqual(intValue, Int32(400))
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
+    XCTAssertEqual(intValue, Int32(401))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
+    XCTAssertEqual(intValue, Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, rawValue:&intValue))
+    XCTAssertEqual(intValue, 666)
+
+    // Clearing a string with nil.
+    msg2.optionalString = nil
+    XCTAssertEqual(msg2.optionalString, "")
+
+    // Clearing a message with nil.
+    msg.optionalMessage = nil
+    XCTAssertFalse(msg.hasOptionalMessage)
+    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
+
+    // Clear.
+    msg.clear()
+    XCTAssertFalse(msg.hasOptionalMessage)
+    XCTAssertEqual(msg.optionalInt32, Int32(0))
+    XCTAssertEqual(msg.optionalString, "")
+    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
+    XCTAssertEqual(msg.optionalEnum, Message3_Enum.Foo)  // Default
+    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0))
+    XCTAssertEqual(msg.repeatedStringArray.count, Int(0))
+    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0))
+    msg2.clear()
+    XCTAssertEqual(msg2.optionalEnum, Message3_Enum.Foo)  // Default
+    XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Message3_Enum.Foo.rawValue)
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
+    XCTAssertEqual(msg.mapStringString.count, Int(0))
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
+  }
+
+  func testAutoCreation() {
+    let msg = Message2()
+
+    XCTAssertFalse(msg.hasOptionalGroup)
+    XCTAssertFalse(msg.hasOptionalMessage)
+
+    // Access shouldn't result in has* but should return objects.
+    let msg2 = msg.optionalGroup
+    let msg3 = msg.optionalMessage.optionalMessage
+    let msg4 = msg.optionalMessage
+    XCTAssertNotNil(msg2)
+    XCTAssertNotNil(msg3)
+    XCTAssertFalse(msg.hasOptionalGroup)
+    XCTAssertFalse(msg.optionalMessage.hasOptionalMessage)
+    XCTAssertFalse(msg.hasOptionalMessage)
+
+    // Setting things should trigger has* getting set.
+    msg.optionalGroup.a = 10
+    msg.optionalMessage.optionalMessage.optionalInt32 = 100
+    XCTAssertTrue(msg.hasOptionalGroup)
+    XCTAssertTrue(msg.optionalMessage.hasOptionalMessage)
+    XCTAssertTrue(msg.hasOptionalMessage)
+
+    // And they should be the same pointer as before.
+    XCTAssertTrue(msg2 === msg.optionalGroup)
+    XCTAssertTrue(msg3 === msg.optionalMessage.optionalMessage)
+    XCTAssertTrue(msg4 === msg.optionalMessage)
+
+    // Clear gets us new objects next time around.
+    msg.clear()
+    XCTAssertFalse(msg.hasOptionalGroup)
+    XCTAssertFalse(msg.optionalMessage.hasOptionalMessage)
+    XCTAssertFalse(msg.hasOptionalMessage)
+    msg.optionalGroup.a = 20
+    msg.optionalMessage.optionalMessage.optionalInt32 = 200
+    XCTAssertTrue(msg.hasOptionalGroup)
+    XCTAssertTrue(msg.optionalMessage.hasOptionalMessage)
+    XCTAssertTrue(msg.hasOptionalMessage)
+    XCTAssertTrue(msg2 !== msg.optionalGroup)
+    XCTAssertTrue(msg3 !== msg.optionalMessage.optionalMessage)
+    XCTAssertTrue(msg4 !== msg.optionalMessage)
+
+    // Explicit set of a message, means autocreated object doesn't bind.
+    msg.clear()
+    let autoCreated = msg.optionalMessage
+    XCTAssertFalse(msg.hasOptionalMessage)
+    let msg5 = Message2()
+    msg5.optionalInt32 = 123
+    msg.optionalMessage = msg5
+    XCTAssertTrue(msg.hasOptionalMessage)
+    // Modifing the autocreated doesn't replaced the explicit set one.
+    autoCreated.optionalInt32 = 456
+    XCTAssertTrue(msg.hasOptionalMessage)
+    XCTAssertTrue(msg.optionalMessage === msg5)
+    XCTAssertEqual(msg.optionalMessage.optionalInt32, Int32(123))
+  }
+
+  func testProto2OneOfSupport() {
+    let msg = Message2()
+
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
+    let autoCreated = msg.oneofMessage  // Default create one.
+    XCTAssertNotNil(autoCreated)
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
+
+    msg.oneofInt32 = 10
+    XCTAssertEqual(msg.oneofInt32, Int32(10))
+    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32)
+
+    msg.oneofFloat = 20.0
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(20.0))
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofFloat)
+
+    msg.oneofEnum = .Bar
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Bar)
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofEnum)
+
+    // Sets via the autocreated instance.
+    msg.oneofMessage.optionalInt32 = 200
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200))
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage)
+
+    // Clear the oneof.
+    Message2_ClearOOneOfCase(msg)
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
+    let autoCreated2 = msg.oneofMessage  // Default create one
+    XCTAssertNotNil(autoCreated2)
+    XCTAssertTrue(autoCreated2 !== autoCreated)  // New instance
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
+
+    msg.oneofInt32 = 10
+    XCTAssertEqual(msg.oneofInt32, Int32(10))
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32)
+
+    // Confirm Message.clear() handles the oneof correctly.
+    msg.clear()
+    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
+
+    // Sets via the autocreated instance.
+    msg.oneofMessage.optionalInt32 = 300
+    XCTAssertTrue(msg.oneofMessage !== autoCreated)  // New instance
+    XCTAssertTrue(msg.oneofMessage !== autoCreated2)  // New instance
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300))
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage)
+
+    // Set message to nil clears the oneof.
+    msg.oneofMessage = nil
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
+}
+
+  func testProto3OneOfSupport() {
+    let msg = Message3()
+
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
+    let autoCreated = msg.oneofMessage  // Default create one.
+    XCTAssertNotNil(autoCreated)
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
+
+    msg.oneofInt32 = 10
+    XCTAssertEqual(msg.oneofInt32, Int32(10))
+    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32)
+
+    msg.oneofFloat = 20.0
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(20.0))
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofFloat)
+
+    msg.oneofEnum = .Bar
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Bar)
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofEnum)
+
+    // Sets via the autocreated instance.
+    msg.oneofMessage.optionalInt32 = 200
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
+    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200))
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage)
+
+    // Clear the oneof.
+    Message3_ClearOOneOfCase(msg)
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
+    let autoCreated2 = msg.oneofMessage  // Default create one
+    XCTAssertNotNil(autoCreated2)
+    XCTAssertTrue(autoCreated2 !== autoCreated)  // New instance
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
+
+    msg.oneofInt32 = 10
+    XCTAssertEqual(msg.oneofInt32, Int32(10))
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32)
+
+    // Confirm Message.clear() handles the oneof correctly.
+    msg.clear()
+    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
+
+    // Sets via the autocreated instance.
+    msg.oneofMessage.optionalInt32 = 300
+    XCTAssertTrue(msg.oneofMessage !== autoCreated)  // New instance
+    XCTAssertTrue(msg.oneofMessage !== autoCreated2)  // New instance
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300))
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage)
+
+    // Set message to nil clears the oneof.
+    msg.oneofMessage = nil
+    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
+    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
+  }
+
+  func testSerialization() {
+    let msg = Message2()
+
+    msg.optionalInt32 = 100
+    msg.optionalInt64 = 101
+    msg.optionalGroup.a = 102
+    msg.repeatedStringArray.addObject("abc")
+    msg.repeatedStringArray.addObject("def")
+    msg.mapInt32Int32.setValue(200, forKey:300)
+    msg.mapInt32Int32.setValue(201, forKey:201)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
+
+    let data = msg.data()
+
+    let msg2 = Message2(data: data!, error:nil)
+    XCTAssertTrue(msg2 !== msg)  // New instance
+    XCTAssertEqual(msg.optionalInt32, Int32(100))
+    XCTAssertEqual(msg.optionalInt64, Int64(101))
+    XCTAssertEqual(msg.optionalGroup.a, Int32(102))
+    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
+    XCTAssertEqual(msg2, msg)
+  }
+
+}
diff --git a/objectivec/Tests/GPBTestUtilities.h b/objectivec/Tests/GPBTestUtilities.h
new file mode 100644
index 0000000..44c8084
--- /dev/null
+++ b/objectivec/Tests/GPBTestUtilities.h
@@ -0,0 +1,100 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <XCTest/XCTest.h>
+
+@class TestAllExtensions;
+@class TestAllTypes;
+@class TestMap;
+@class TestPackedTypes;
+@class TestPackedExtensions;
+@class TestUnpackedTypes;
+@class TestUnpackedExtensions;
+@class GPBExtensionRegistry;
+
+
+// Helper for uses of C arrays in tests cases.
+#ifndef GPBARRAYSIZE
+#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
+#endif  // GPBARRAYSIZE
+
+
+// The number of repetitions of any repeated objects inside of test messages.
+extern const uint32_t kGPBDefaultRepeatCount;
+
+@interface GPBTestCase : XCTestCase
+
+- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count;
+- (void)clearAllFields:(TestAllTypes *)message;
+- (void)setAllExtensions:(TestAllExtensions *)message
+           repeatedCount:(uint32_t)count;
+- (void)setPackedFields:(TestPackedTypes *)message
+          repeatedCount:(uint32_t)count;
+- (void)setUnpackedFields:(TestUnpackedTypes *)message
+            repeatedCount:(uint32_t)count;
+- (void)setPackedExtensions:(TestPackedExtensions *)message
+              repeatedCount:(uint32_t)count;
+- (void)setUnpackedExtensions:(TestUnpackedExtensions *)message
+              repeatedCount:(uint32_t)count;
+- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count;
+
+- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count;
+- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count;
+- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count;
+- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count;
+
+- (void)assertAllFieldsSet:(TestAllTypes *)message
+             repeatedCount:(uint32_t)count;
+- (void)assertAllExtensionsSet:(TestAllExtensions *)message
+                 repeatedCount:(uint32_t)count;
+- (void)assertRepeatedFieldsModified:(TestAllTypes *)message
+                       repeatedCount:(uint32_t)count;
+- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message
+                           repeatedCount:(uint32_t)count;
+- (void)assertExtensionsClear:(TestAllExtensions *)message;
+- (void)assertClear:(TestAllTypes *)message;
+- (void)assertPackedFieldsSet:(TestPackedTypes *)message
+                repeatedCount:(uint32_t)count;
+- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message
+                    repeatedCount:(uint32_t)count;
+
+- (void)modifyRepeatedExtensions:(TestAllExtensions *)message;
+- (void)modifyRepeatedFields:(TestAllTypes *)message;
+
+- (GPBExtensionRegistry *)extensionRegistry;
+
+- (NSData *)getDataFileNamed:(NSString *)name dataToWrite:(NSData *)dataToWrite;
+
+- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message;
+- (void)setAllFieldsViaKVC:(TestAllTypes *)message
+             repeatedCount:(uint32_t)count;
+- (void)assertClearKVC:(TestAllTypes *)message;
+
+@end
diff --git a/objectivec/Tests/GPBTestUtilities.m b/objectivec/Tests/GPBTestUtilities.m
new file mode 100644
index 0000000..726761a
--- /dev/null
+++ b/objectivec/Tests/GPBTestUtilities.m
@@ -0,0 +1,2546 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
+
+const uint32_t kGPBDefaultRepeatCount = 2;
+
+// Small category to easily turn a CString into an NSData.
+@interface NSData (GPBTestCase)
++ (NSData *)gpbtu_dataWithCString:(char *)buffer;
++ (instancetype)gpbtu_dataWithEmbeddedNulls;
+@end
+
+@implementation NSData (GPBTestCase)
++ (NSData *)gpbtu_dataWithCString:(char *)buffer {
+  return [NSData dataWithBytes:buffer length:strlen(buffer)];
+}
+
++ (instancetype)gpbtu_dataWithUint32:(uint32_t)value {
+  return [[[self alloc] initWithUint32_gpbtu:value] autorelease];
+}
+
+- (instancetype)initWithUint32_gpbtu:(uint32_t)value {
+  value = CFSwapInt32HostToLittle(value);
+  return [self initWithBytes:&value length:sizeof(value)];
+}
+
++ (instancetype)gpbtu_dataWithEmbeddedNulls {
+  char bytes[6] = "\1\0\2\3\0\5";
+  return [self dataWithBytes:bytes length:sizeof(bytes)];
+}
+@end
+
+@implementation GPBTestCase
+
+// Return data for name. Optionally (based on #if setting) write out dataToWrite
+// to replace that data. Useful for setting golden masters.
+- (NSData *)getDataFileNamed:(NSString *)name
+                 dataToWrite:(NSData *)dataToWrite {
+  NSBundle *bundle = [NSBundle bundleForClass:[self class]];
+  NSString *path = [bundle pathForResource:[name stringByDeletingPathExtension]
+                                    ofType:[name pathExtension]];
+  XCTAssertNotNil(path, @"Unable to find %@", name);
+  NSData *data = [NSData dataWithContentsOfFile:path];
+  XCTAssertNotNil(data, @"Unable to load from %@", path);
+#if 0
+  // Enable to write out golden master files.
+  if (!path) {
+    path = [[bundle resourcePath] stringByAppendingPathComponent:name];
+  }
+  NSError *error = nil;
+  BOOL wrote = [dataToWrite writeToFile:path options:NSDataWritingAtomic error:&error];
+  XCTAssertTrue(wrote, @"Unable to write %@ (%@)", path, error);
+  NSLog(@"Wrote data file to %@", path);
+#else
+  // Kill off the unused variable warning.
+  dataToWrite = dataToWrite;
+#endif
+  return data;
+}
+
+// -------------------------------------------------------------------
+
+- (void)modifyRepeatedExtensions:(TestAllExtensions *)message {
+  [message setExtension:[UnittestRoot repeatedInt32Extension]
+                  index:1
+                  value:@501];
+  [message setExtension:[UnittestRoot repeatedInt64Extension]
+                  index:1
+                  value:@502];
+  [message setExtension:[UnittestRoot repeatedUint32Extension]
+                  index:1
+                  value:@503];
+  [message setExtension:[UnittestRoot repeatedUint64Extension]
+                  index:1
+                  value:@504];
+  [message setExtension:[UnittestRoot repeatedSint32Extension]
+                  index:1
+                  value:@505];
+  [message setExtension:[UnittestRoot repeatedSint64Extension]
+                  index:1
+                  value:@506];
+  [message setExtension:[UnittestRoot repeatedFixed32Extension]
+                  index:1
+                  value:@507];
+  [message setExtension:[UnittestRoot repeatedFixed64Extension]
+                  index:1
+                  value:@508];
+  [message setExtension:[UnittestRoot repeatedSfixed32Extension]
+                  index:1
+                  value:@509];
+  [message setExtension:[UnittestRoot repeatedSfixed64Extension]
+                  index:1
+                  value:@510];
+  [message setExtension:[UnittestRoot repeatedFloatExtension]
+                  index:1
+                  value:@511.0f];
+  [message setExtension:[UnittestRoot repeatedDoubleExtension]
+                  index:1
+                  value:@512.0];
+  [message setExtension:[UnittestRoot repeatedBoolExtension]
+                  index:1
+                  value:@YES];
+  [message setExtension:[UnittestRoot repeatedStringExtension]
+                  index:1
+                  value:@"515"];
+  [message setExtension:[UnittestRoot repeatedBytesExtension]
+                  index:1
+                  value:[NSData gpbtu_dataWithUint32:516]];
+
+  RepeatedGroup_extension *repeatedGroup = [RepeatedGroup_extension message];
+  [repeatedGroup setA:517];
+  [message setExtension:[UnittestRoot repeatedGroupExtension]
+                  index:1
+                  value:repeatedGroup];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  [nestedMessage setBb:518];
+  [message setExtension:[UnittestRoot repeatedNestedMessageExtension]
+                  index:1
+                  value:nestedMessage];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setC:519];
+  [message setExtension:[UnittestRoot repeatedForeignMessageExtension]
+                  index:1
+                  value:foreignMessage];
+  ImportMessage *importMessage = [ImportMessage message];
+  [importMessage setD:520];
+  [message setExtension:[UnittestRoot repeatedImportMessageExtension]
+                  index:1
+                  value:importMessage];
+
+  [message setExtension:[UnittestRoot repeatedNestedEnumExtension]
+                  index:1
+                  value:@(TestAllTypes_NestedEnum_Foo)];
+  [message setExtension:[UnittestRoot repeatedForeignEnumExtension]
+                  index:1
+                  value:@(ForeignEnum_ForeignFoo)];
+  [message setExtension:[UnittestRoot repeatedImportEnumExtension]
+                  index:1
+                  value:@(ImportEnum_ImportFoo)];
+
+  [message setExtension:[UnittestRoot repeatedStringPieceExtension]
+                  index:1
+                  value:@"524"];
+  [message setExtension:[UnittestRoot repeatedCordExtension]
+                  index:1
+                  value:@"525"];
+}
+
+- (void)assertAllExtensionsSet:(TestAllExtensions *)message
+                 repeatedCount:(uint32_t)count {
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalFloatExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalDoubleExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalBoolExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalBytesExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+
+  XCTAssertTrue([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]);
+  XCTAssertTrue([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]);
+  XCTAssertTrue([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]);
+  XCTAssertTrue([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportEnumExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringPieceExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot optionalCordExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]);
+
+  XCTAssertEqual(101, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]);
+  XCTAssertEqual(102LL, [[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]);
+  XCTAssertEqual(103U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]);
+  XCTAssertEqual(104ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(105, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]);
+  XCTAssertEqual(106LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]);
+  XCTAssertEqual(107U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]);
+  XCTAssertEqual(108ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(109, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]);
+  XCTAssertEqual(110LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]);
+  XCTAssertEqualWithAccuracy(111.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy(112.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01);
+  XCTAssertTrue([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]);
+  XCTAssertEqualObjects(@"115", [message getExtension:[UnittestRoot optionalStringExtension]]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls], [message getExtension:[UnittestRoot optionalBytesExtension]]);
+
+  XCTAssertEqual(117, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]);
+  XCTAssertEqual(118, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]);
+  XCTAssertEqual(119, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]);
+  XCTAssertEqual(120, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignBaz, [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]);
+  XCTAssertEqual(ImportEnum_ImportBaz, [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]);
+
+  XCTAssertEqualObjects(@"124", [message getExtension:[UnittestRoot optionalStringPieceExtension]]);
+  XCTAssertEqualObjects(@"125", [message getExtension:[UnittestRoot optionalCordExtension]]);
+
+  // -----------------------------------------------------------------
+
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]);
+
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]);
+
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]);
+
+  for (uint32_t i = 0; i < count; ++i) {
+    id extension = [message getExtension:[UnittestRoot repeatedInt32Extension]];
+    XCTAssertEqual((int)(201 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot repeatedInt64Extension]];
+    XCTAssertEqual(202 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot repeatedUint32Extension]];
+    XCTAssertEqual(203 + i * 100, [extension[i] unsignedIntValue]);
+    extension = [message getExtension:[UnittestRoot repeatedUint64Extension]];
+    XCTAssertEqual(204 + i * 100, [extension[i] unsignedLongLongValue]);
+    extension = [message getExtension:[UnittestRoot repeatedSint32Extension]];
+    XCTAssertEqual((int)(205 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot repeatedSint64Extension]];
+    XCTAssertEqual(206 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot repeatedFixed32Extension]];
+    XCTAssertEqual(207 + i * 100, [extension[i] unsignedIntValue]);
+    extension = [message getExtension:[UnittestRoot repeatedFixed64Extension]];
+    XCTAssertEqual(208 + i * 100, [extension[i] unsignedLongLongValue]);
+    extension = [message getExtension:[UnittestRoot repeatedSfixed32Extension]];
+    XCTAssertEqual((int)(209 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot repeatedSfixed64Extension]];
+    XCTAssertEqual(210 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot repeatedFloatExtension]];
+    XCTAssertEqualWithAccuracy(211 + i * 100, [extension[i] floatValue], 0.01);
+    extension = [message getExtension:[UnittestRoot repeatedDoubleExtension]];
+    XCTAssertEqualWithAccuracy(212 + i * 100, [extension[i] doubleValue], 0.01);
+    extension = [message getExtension:[UnittestRoot repeatedBoolExtension]];
+    XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]);
+
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100];
+    extension = [message getExtension:[UnittestRoot repeatedStringExtension]];
+    XCTAssertEqualObjects(string, extension[i]);
+    [string release];
+
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100];
+    extension = [message getExtension:[UnittestRoot repeatedBytesExtension]];
+    XCTAssertEqualObjects(data, extension[i]);
+    [data release];
+
+    extension = [message getExtension:[UnittestRoot repeatedGroupExtension]];
+    XCTAssertEqual((int)(217 + i * 100), [(TestAllTypes_OptionalGroup*)extension[i] a]);
+    extension = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
+    XCTAssertEqual((int)(218 + i * 100), [(TestAllTypes_NestedMessage*)extension[i] bb]);
+    extension = [message getExtension:[UnittestRoot repeatedForeignMessageExtension]];
+    XCTAssertEqual((int)(219 + i * 100), [extension[i] c]);
+    extension = [message getExtension:[UnittestRoot repeatedImportMessageExtension]];
+    XCTAssertEqual((int)(220 + i * 100), [extension[i] d]);
+
+    extension = [message getExtension:[UnittestRoot repeatedNestedEnumExtension]];
+    XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot repeatedForeignEnumExtension]];
+    XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot repeatedImportEnumExtension]];
+    XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [extension[i] intValue]);
+
+    string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100];
+    extension = [message getExtension:[UnittestRoot repeatedStringPieceExtension]];
+    XCTAssertEqualObjects(string, extension[i]);
+    [string release];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100];
+    extension = [message getExtension:[UnittestRoot repeatedCordExtension]];
+    XCTAssertEqualObjects(string, extension[i]);
+    [string release];
+  }
+
+  // -----------------------------------------------------------------
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]);
+
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]);
+  XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]);
+
+  XCTAssertEqual(401, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]);
+  XCTAssertEqual(402LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]);
+  XCTAssertEqual(403U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]);
+  XCTAssertEqual(404ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(405, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]);
+  XCTAssertEqual(406LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]);
+  XCTAssertEqual(407U, [[message getExtension:[UnittestRoot defaultFixed32Extension]] unsignedIntValue]);
+  XCTAssertEqual(408ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(409, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]);
+  XCTAssertEqual(410LL,[[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]);
+  XCTAssertEqualWithAccuracy(411.0f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy(412.0, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01);
+  XCTAssertFalse([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]);
+  XCTAssertEqualObjects(@"415", [message getExtension:[UnittestRoot defaultStringExtension]]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416], [message getExtension:[UnittestRoot defaultBytesExtension]]);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignFoo, [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]);
+  XCTAssertEqual(ImportEnum_ImportFoo, [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]);
+
+  XCTAssertEqualObjects(@"424", [message getExtension:[UnittestRoot defaultStringPieceExtension]]);
+  XCTAssertEqualObjects(@"425", [message getExtension:[UnittestRoot defaultCordExtension]]);
+}
+
+- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message
+                           repeatedCount:(uint32_t)count {
+  // ModifyRepeatedFields only sets the second repeated element of each
+  // field.  In addition to verifying this, we also verify that the first
+  // element and size were *not* modified.
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]);
+
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]);
+
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]);
+
+  XCTAssertEqual(201,[[message getExtension:[UnittestRoot repeatedInt32Extension]][0] intValue]);
+  XCTAssertEqual(202LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][0] longLongValue]);
+  XCTAssertEqual(203U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][0] unsignedIntValue]);
+  XCTAssertEqual(204ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][0] unsignedLongLongValue]);
+  XCTAssertEqual(205, [[message getExtension:[UnittestRoot repeatedSint32Extension]][0] intValue]);
+  XCTAssertEqual(206LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][0] longLongValue]);
+  XCTAssertEqual(207U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][0] unsignedIntValue]);
+  XCTAssertEqual(208ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][0] unsignedLongLongValue]);
+  XCTAssertEqual(209, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][0] intValue]);
+  XCTAssertEqual(210LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][0] longLongValue]);
+  XCTAssertEqualWithAccuracy(211.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][0] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy(212.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][0] doubleValue], 0.01);
+  XCTAssertFalse([[message getExtension:[UnittestRoot repeatedBoolExtension]][0] boolValue]);
+  XCTAssertEqualObjects(@"215", [message getExtension:[UnittestRoot repeatedStringExtension]][0]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216], [message getExtension:[UnittestRoot repeatedBytesExtension]][0]);
+
+  XCTAssertEqual(217, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][0] a]);
+  XCTAssertEqual(218, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][0] bb]);
+  XCTAssertEqual(219, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][0] c]);
+  XCTAssertEqual(220, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][0] d]);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Baz,
+                 [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][0] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignBaz,
+                 [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][0] intValue]);
+  XCTAssertEqual(ImportEnum_ImportBaz,
+                 [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][0] intValue]);
+
+  XCTAssertEqualObjects(@"224", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][0]);
+  XCTAssertEqualObjects(@"225", [message getExtension:[UnittestRoot repeatedCordExtension]][0]);
+
+  // Actually verify the second (modified) elements now.
+  XCTAssertEqual(501, [[message getExtension:[UnittestRoot repeatedInt32Extension]][1] intValue]);
+  XCTAssertEqual(502LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][1] longLongValue]);
+  XCTAssertEqual(503U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][1] unsignedIntValue]);
+  XCTAssertEqual(504ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][1] unsignedLongLongValue]);
+  XCTAssertEqual(505, [[message getExtension:[UnittestRoot repeatedSint32Extension]][1] intValue]);
+  XCTAssertEqual(506LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][1] longLongValue]);
+  XCTAssertEqual(507U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][1] unsignedIntValue]);
+  XCTAssertEqual(508ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][1] unsignedLongLongValue]);
+  XCTAssertEqual(509, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][1] intValue]);
+  XCTAssertEqual(510LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][1] longLongValue]);
+  XCTAssertEqualWithAccuracy(511.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][1] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy(512.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][1] doubleValue], 0.01);
+  XCTAssertTrue([[message getExtension:[UnittestRoot repeatedBoolExtension]][1] boolValue]);
+  XCTAssertEqualObjects(@"515", [message getExtension:[UnittestRoot repeatedStringExtension]][1]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516], [message getExtension:[UnittestRoot repeatedBytesExtension]][1]);
+
+  XCTAssertEqual(517, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][1] a]);
+  XCTAssertEqual(518, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][1] bb]);
+  XCTAssertEqual(519, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][1] c]);
+  XCTAssertEqual(520, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][1] d]);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo,
+                 [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][1] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignFoo,
+                 [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][1] intValue]);
+  XCTAssertEqual(ImportEnum_ImportFoo,
+                 [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][1] intValue]);
+
+  XCTAssertEqualObjects(@"524", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][1]);
+  XCTAssertEqualObjects(@"525", [message getExtension:[UnittestRoot repeatedCordExtension]][1]);
+}
+
+// -------------------------------------------------------------------
+
+- (void)assertAllFieldsSet:(TestAllTypes *)message
+             repeatedCount:(uint32_t)count {
+  XCTAssertTrue(message.hasOptionalInt32);
+  XCTAssertTrue(message.hasOptionalInt64);
+  XCTAssertTrue(message.hasOptionalUint32);
+  XCTAssertTrue(message.hasOptionalUint64);
+  XCTAssertTrue(message.hasOptionalSint32);
+  XCTAssertTrue(message.hasOptionalSint64);
+  XCTAssertTrue(message.hasOptionalFixed32);
+  XCTAssertTrue(message.hasOptionalFixed64);
+  XCTAssertTrue(message.hasOptionalSfixed32);
+  XCTAssertTrue(message.hasOptionalSfixed64);
+  XCTAssertTrue(message.hasOptionalFloat);
+  XCTAssertTrue(message.hasOptionalDouble);
+  XCTAssertTrue(message.hasOptionalBool);
+  XCTAssertTrue(message.hasOptionalString);
+  XCTAssertTrue(message.hasOptionalBytes);
+
+  XCTAssertTrue(message.hasOptionalGroup);
+  XCTAssertTrue(message.hasOptionalNestedMessage);
+  XCTAssertTrue(message.hasOptionalForeignMessage);
+  XCTAssertTrue(message.hasOptionalImportMessage);
+
+  XCTAssertTrue(message.optionalGroup.hasA);
+  XCTAssertTrue(message.optionalNestedMessage.hasBb);
+  XCTAssertTrue(message.optionalForeignMessage.hasC);
+  XCTAssertTrue(message.optionalImportMessage.hasD);
+
+  XCTAssertTrue(message.hasOptionalNestedEnum);
+  XCTAssertTrue(message.hasOptionalForeignEnum);
+  XCTAssertTrue(message.hasOptionalImportEnum);
+
+  XCTAssertTrue(message.hasOptionalStringPiece);
+  XCTAssertTrue(message.hasOptionalCord);
+
+  XCTAssertEqual(101, message.optionalInt32);
+  XCTAssertEqual(102LL, message.optionalInt64);
+  XCTAssertEqual(103U, message.optionalUint32);
+  XCTAssertEqual(104ULL, message.optionalUint64);
+  XCTAssertEqual(105, message.optionalSint32);
+  XCTAssertEqual(106LL, message.optionalSint64);
+  XCTAssertEqual(107U, message.optionalFixed32);
+  XCTAssertEqual(108ULL, message.optionalFixed64);
+  XCTAssertEqual(109, message.optionalSfixed32);
+  XCTAssertEqual(110LL, message.optionalSfixed64);
+  XCTAssertEqualWithAccuracy(111.0f, message.optionalFloat, 0.1);
+  XCTAssertEqualWithAccuracy(112.0, message.optionalDouble, 0.1);
+  XCTAssertTrue(message.optionalBool);
+  XCTAssertEqualObjects(@"115", message.optionalString);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls],
+                        message.optionalBytes);
+
+  XCTAssertEqual(117, message.optionalGroup.a);
+  XCTAssertEqual(118, message.optionalNestedMessage.bb);
+  XCTAssertEqual(119, message.optionalForeignMessage.c);
+  XCTAssertEqual(120, message.optionalImportMessage.d);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Baz, message.optionalNestedEnum);
+  XCTAssertEqual(ForeignEnum_ForeignBaz, message.optionalForeignEnum);
+  XCTAssertEqual(ImportEnum_ImportBaz, message.optionalImportEnum);
+
+  XCTAssertEqualObjects(@"124", message.optionalStringPiece);
+  XCTAssertEqualObjects(@"125", message.optionalCord);
+
+  // -----------------------------------------------------------------
+
+  XCTAssertEqual(count, message.repeatedInt32Array.count);
+  XCTAssertEqual(count, message.repeatedInt64Array.count);
+  XCTAssertEqual(count, message.repeatedUint32Array.count);
+  XCTAssertEqual(count, message.repeatedUint64Array.count);
+  XCTAssertEqual(count, message.repeatedSint32Array.count);
+  XCTAssertEqual(count, message.repeatedSint64Array.count);
+  XCTAssertEqual(count, message.repeatedFixed32Array.count);
+  XCTAssertEqual(count, message.repeatedFixed64Array.count);
+  XCTAssertEqual(count, message.repeatedSfixed32Array.count);
+  XCTAssertEqual(count, message.repeatedSfixed64Array.count);
+  XCTAssertEqual(count, message.repeatedFloatArray.count);
+  XCTAssertEqual(count, message.repeatedDoubleArray.count);
+  XCTAssertEqual(count, message.repeatedBoolArray.count);
+  XCTAssertEqual(count, message.repeatedStringArray.count);
+  XCTAssertEqual(count, message.repeatedBytesArray.count);
+
+  XCTAssertEqual(count, message.repeatedGroupArray.count);
+  XCTAssertEqual(count, message.repeatedNestedMessageArray.count);
+  XCTAssertEqual(count, message.repeatedForeignMessageArray.count);
+  XCTAssertEqual(count, message.repeatedImportMessageArray.count);
+  XCTAssertEqual(count, message.repeatedNestedEnumArray.count);
+  XCTAssertEqual(count, message.repeatedForeignEnumArray.count);
+  XCTAssertEqual(count, message.repeatedImportEnumArray.count);
+
+  XCTAssertEqual(count, message.repeatedStringPieceArray.count);
+  XCTAssertEqual(count, message.repeatedCordArray.count);
+
+  XCTAssertEqual(count, message.repeatedInt32Array_Count);
+  XCTAssertEqual(count, message.repeatedInt64Array_Count);
+  XCTAssertEqual(count, message.repeatedUint32Array_Count);
+  XCTAssertEqual(count, message.repeatedUint64Array_Count);
+  XCTAssertEqual(count, message.repeatedSint32Array_Count);
+  XCTAssertEqual(count, message.repeatedSint64Array_Count);
+  XCTAssertEqual(count, message.repeatedFixed32Array_Count);
+  XCTAssertEqual(count, message.repeatedFixed64Array_Count);
+  XCTAssertEqual(count, message.repeatedSfixed32Array_Count);
+  XCTAssertEqual(count, message.repeatedSfixed64Array_Count);
+  XCTAssertEqual(count, message.repeatedFloatArray_Count);
+  XCTAssertEqual(count, message.repeatedDoubleArray_Count);
+  XCTAssertEqual(count, message.repeatedBoolArray_Count);
+  XCTAssertEqual(count, message.repeatedStringArray_Count);
+  XCTAssertEqual(count, message.repeatedBytesArray_Count);
+
+  XCTAssertEqual(count, message.repeatedGroupArray_Count);
+  XCTAssertEqual(count, message.repeatedNestedMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedForeignMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedImportMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedNestedEnumArray_Count);
+  XCTAssertEqual(count, message.repeatedForeignEnumArray_Count);
+  XCTAssertEqual(count, message.repeatedImportEnumArray_Count);
+
+  XCTAssertEqual(count, message.repeatedStringPieceArray_Count);
+  XCTAssertEqual(count, message.repeatedCordArray_Count);
+
+  for (uint32_t i = 0; i < count; ++i) {
+    XCTAssertEqual((int)(201 + i * 100),
+                   [message.repeatedInt32Array valueAtIndex:i]);
+    XCTAssertEqual(202 + i * 100, [message.repeatedInt64Array valueAtIndex:i]);
+    XCTAssertEqual(203 + i * 100, [message.repeatedUint32Array valueAtIndex:i]);
+    XCTAssertEqual(204 + i * 100, [message.repeatedUint64Array valueAtIndex:i]);
+    XCTAssertEqual((int)(205 + i * 100),
+                   [message.repeatedSint32Array valueAtIndex:i]);
+    XCTAssertEqual(206 + i * 100, [message.repeatedSint64Array valueAtIndex:i]);
+    XCTAssertEqual(207 + i * 100,
+                   [message.repeatedFixed32Array valueAtIndex:i]);
+    XCTAssertEqual(208 + i * 100,
+                   [message.repeatedFixed64Array valueAtIndex:i]);
+    XCTAssertEqual((int)(209 + i * 100),
+                   [message.repeatedSfixed32Array valueAtIndex:i]);
+    XCTAssertEqual(210 + i * 100,
+                   [message.repeatedSfixed64Array valueAtIndex:i]);
+    XCTAssertEqualWithAccuracy(
+        211 + i * 100, [message.repeatedFloatArray valueAtIndex:i], 0.1);
+    XCTAssertEqualWithAccuracy(
+        212 + i * 100, [message.repeatedDoubleArray valueAtIndex:i], 0.1);
+    XCTAssertEqual((i % 2) ? YES : NO,
+                   [message.repeatedBoolArray valueAtIndex:i]);
+
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100];
+    XCTAssertEqualObjects(string, message.repeatedStringArray[i]);
+    [string release];
+
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100];
+    XCTAssertEqualObjects(data, message.repeatedBytesArray[i]);
+    [data release];
+
+    XCTAssertEqual((int)(217 + i * 100), ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[i]).a);
+    XCTAssertEqual((int)(218 + i * 100), ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[i]).bb);
+    XCTAssertEqual((int)(219 + i * 100), ((ForeignMessage*)message.repeatedForeignMessageArray[i]).c);
+    XCTAssertEqual((int)(220 + i * 100), ((ImportMessage*)message.repeatedImportMessageArray[i]).d);
+
+    XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:i]);
+    XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:i]);
+    XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:i]);
+
+    string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100];
+    XCTAssertEqualObjects(string, message.repeatedStringPieceArray[i]);
+    [string release];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100];
+    XCTAssertEqualObjects(string, message.repeatedCordArray[i]);
+    [string release];
+  }
+
+  // -----------------------------------------------------------------
+
+  XCTAssertTrue(message.hasDefaultInt32);
+  XCTAssertTrue(message.hasDefaultInt64);
+  XCTAssertTrue(message.hasDefaultUint32);
+  XCTAssertTrue(message.hasDefaultUint64);
+  XCTAssertTrue(message.hasDefaultSint32);
+  XCTAssertTrue(message.hasDefaultSint64);
+  XCTAssertTrue(message.hasDefaultFixed32);
+  XCTAssertTrue(message.hasDefaultFixed64);
+  XCTAssertTrue(message.hasDefaultSfixed32);
+  XCTAssertTrue(message.hasDefaultSfixed64);
+  XCTAssertTrue(message.hasDefaultFloat);
+  XCTAssertTrue(message.hasDefaultDouble);
+  XCTAssertTrue(message.hasDefaultBool);
+  XCTAssertTrue(message.hasDefaultString);
+  XCTAssertTrue(message.hasDefaultBytes);
+
+  XCTAssertTrue(message.hasDefaultNestedEnum);
+  XCTAssertTrue(message.hasDefaultForeignEnum);
+  XCTAssertTrue(message.hasDefaultImportEnum);
+
+  XCTAssertTrue(message.hasDefaultStringPiece);
+  XCTAssertTrue(message.hasDefaultCord);
+
+  XCTAssertEqual(401, message.defaultInt32);
+  XCTAssertEqual(402LL, message.defaultInt64);
+  XCTAssertEqual(403U, message.defaultUint32);
+  XCTAssertEqual(404ULL, message.defaultUint64);
+  XCTAssertEqual(405, message.defaultSint32);
+  XCTAssertEqual(406LL, message.defaultSint64);
+  XCTAssertEqual(407U, message.defaultFixed32);
+  XCTAssertEqual(408ULL, message.defaultFixed64);
+  XCTAssertEqual(409, message.defaultSfixed32);
+  XCTAssertEqual(410LL, message.defaultSfixed64);
+  XCTAssertEqualWithAccuracy(411.0f, message.defaultFloat, 0.1);
+  XCTAssertEqualWithAccuracy(412.0, message.defaultDouble, 0.1);
+  XCTAssertFalse(message.defaultBool);
+  XCTAssertEqualObjects(@"415", message.defaultString);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416],
+                        message.defaultBytes);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.defaultNestedEnum);
+  XCTAssertEqual(ForeignEnum_ForeignFoo, message.defaultForeignEnum);
+  XCTAssertEqual(ImportEnum_ImportFoo, message.defaultImportEnum);
+
+  XCTAssertEqualObjects(@"424", message.defaultStringPiece);
+  XCTAssertEqualObjects(@"425", message.defaultCord);
+}
+
+- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count {
+  [message setOptionalInt32:101];
+  [message setOptionalInt64:102];
+  [message setOptionalUint32:103];
+  [message setOptionalUint64:104];
+  [message setOptionalSint32:105];
+  [message setOptionalSint64:106];
+  [message setOptionalFixed32:107];
+  [message setOptionalFixed64:108];
+  [message setOptionalSfixed32:109];
+  [message setOptionalSfixed64:110];
+  [message setOptionalFloat:111];
+  [message setOptionalDouble:112];
+  [message setOptionalBool:YES];
+  [message setOptionalString:@"115"];
+  [message setOptionalBytes:[NSData gpbtu_dataWithEmbeddedNulls]];
+
+  TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message];
+  [allTypes setA:117];
+  [message setOptionalGroup:allTypes];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  [nestedMessage setBb:118];
+  [message setOptionalNestedMessage:nestedMessage];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setC:119];
+  [message setOptionalForeignMessage:foreignMessage];
+  ImportMessage *importMessage = [ImportMessage message];
+  [importMessage setD:120];
+  [message setOptionalImportMessage:importMessage];
+
+  [message setOptionalNestedEnum:TestAllTypes_NestedEnum_Baz];
+  [message setOptionalForeignEnum:ForeignEnum_ForeignBaz];
+  [message setOptionalImportEnum:ImportEnum_ImportBaz];
+
+  [message setOptionalStringPiece:@"124"];
+  [message setOptionalCord:@"125"];
+
+  // -----------------------------------------------------------------
+
+  for (uint32_t i = 0; i < count; i++) {
+    [message.repeatedInt32Array addValue:201 + i * 100];
+    [message.repeatedInt64Array addValue:202 + i * 100];
+    [message.repeatedUint32Array addValue:203 + i * 100];
+    [message.repeatedUint64Array addValue:204 + i * 100];
+    [message.repeatedSint32Array addValue:205 + i * 100];
+    [message.repeatedSint64Array addValue:206 + i * 100];
+    [message.repeatedFixed32Array addValue:207 + i * 100];
+    [message.repeatedFixed64Array addValue:208 + i * 100];
+    [message.repeatedSfixed32Array addValue:209 + i * 100];
+    [message.repeatedSfixed64Array addValue:210 + i * 100];
+    [message.repeatedFloatArray addValue:211 + i * 100];
+    [message.repeatedDoubleArray addValue:212 + i * 100];
+    [message.repeatedBoolArray addValue:(i % 2)];
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100];
+    [message.repeatedStringArray addObject:string];
+    [string release];
+
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100];
+    [message.repeatedBytesArray addObject:data];
+    [data release];
+
+    TestAllTypes_RepeatedGroup *testAll =
+        [[TestAllTypes_RepeatedGroup alloc] init];
+    [testAll setA:217 + i * 100];
+    [message.repeatedGroupArray addObject:testAll];
+    [testAll release];
+
+    nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
+    [nestedMessage setBb:218 + i * 100];
+    [message.repeatedNestedMessageArray addObject:nestedMessage];
+    [nestedMessage release];
+
+    foreignMessage = [[ForeignMessage alloc] init];
+    [foreignMessage setC:219 + i * 100];
+    [message.repeatedForeignMessageArray addObject:foreignMessage];
+    [foreignMessage release];
+
+    importMessage = [[ImportMessage alloc] init];
+    [importMessage setD:220 + i * 100];
+    [message.repeatedImportMessageArray addObject:importMessage];
+    [importMessage release];
+
+    [message.repeatedNestedEnumArray addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz];
+
+    [message.repeatedForeignEnumArray addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz];
+    [message.repeatedImportEnumArray addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100];
+    [message.repeatedStringPieceArray addObject:string];
+    [string release];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100];
+    [message.repeatedCordArray addObject:string];
+    [string release];
+  }
+  // -----------------------------------------------------------------
+
+  message.defaultInt32 = 401;
+  message.defaultInt64 = 402;
+  message.defaultUint32 = 403;
+  message.defaultUint64 = 404;
+  message.defaultSint32 = 405;
+  message.defaultSint64 = 406;
+  message.defaultFixed32 = 407;
+  message.defaultFixed64 = 408;
+  message.defaultSfixed32 = 409;
+  message.defaultSfixed64 = 410;
+  message.defaultFloat = 411;
+  message.defaultDouble = 412;
+  message.defaultBool = NO;
+  message.defaultString = @"415";
+  message.defaultBytes = [NSData gpbtu_dataWithUint32:416];
+
+  message.defaultNestedEnum = TestAllTypes_NestedEnum_Foo;
+  message.defaultForeignEnum = ForeignEnum_ForeignFoo;
+  message.defaultImportEnum = ImportEnum_ImportFoo;
+
+  message.defaultStringPiece = @"424";
+  message.defaultCord = @"425";
+}
+
+- (void)clearAllFields:(TestAllTypes *)message {
+  message.hasOptionalInt32 = NO;
+  message.hasOptionalInt64 = NO;
+  message.hasOptionalUint32 = NO;
+  message.hasOptionalUint64 = NO;
+  message.hasOptionalSint32 = NO;
+  message.hasOptionalSint64 = NO;
+  message.hasOptionalFixed32 = NO;
+  message.hasOptionalFixed64 = NO;
+  message.hasOptionalSfixed32 = NO;
+  message.hasOptionalSfixed64 = NO;
+  message.hasOptionalFloat = NO;
+  message.hasOptionalDouble = NO;
+  message.hasOptionalBool = NO;
+  message.hasOptionalString = NO;
+  message.hasOptionalBytes = NO;
+
+  message.hasOptionalGroup = NO;
+  message.hasOptionalNestedMessage = NO;
+  message.hasOptionalForeignMessage = NO;
+  message.hasOptionalImportMessage = NO;
+
+  message.hasOptionalNestedEnum = NO;
+  message.hasOptionalForeignEnum = NO;
+  message.hasOptionalImportEnum = NO;
+
+  message.hasOptionalStringPiece = NO;
+  message.hasOptionalCord = NO;
+
+  // -----------------------------------------------------------------
+
+  [message.repeatedInt32Array removeAll];
+  [message.repeatedInt64Array removeAll];
+  [message.repeatedUint32Array removeAll];
+  [message.repeatedUint64Array removeAll];
+  [message.repeatedSint32Array removeAll];
+  [message.repeatedSint64Array removeAll];
+  [message.repeatedFixed32Array removeAll];
+  [message.repeatedFixed64Array removeAll];
+  [message.repeatedSfixed32Array removeAll];
+  [message.repeatedSfixed64Array removeAll];
+  [message.repeatedFloatArray removeAll];
+  [message.repeatedDoubleArray removeAll];
+  [message.repeatedBoolArray removeAll];
+  [message.repeatedStringArray removeAllObjects];
+  [message.repeatedBytesArray removeAllObjects];
+
+  [message.repeatedGroupArray removeAllObjects];
+  [message.repeatedNestedMessageArray removeAllObjects];
+  [message.repeatedForeignMessageArray removeAllObjects];
+  [message.repeatedImportMessageArray removeAllObjects];
+
+  [message.repeatedNestedEnumArray removeAll];
+  [message.repeatedForeignEnumArray removeAll];
+  [message.repeatedImportEnumArray removeAll];
+
+  [message.repeatedStringPieceArray removeAllObjects];
+  [message.repeatedCordArray removeAllObjects];
+
+  // -----------------------------------------------------------------
+
+  message.hasDefaultInt32 = NO;
+  message.hasDefaultInt64 = NO;
+  message.hasDefaultUint32 = NO;
+  message.hasDefaultUint64 = NO;
+  message.hasDefaultSint32 = NO;
+  message.hasDefaultSint64 = NO;
+  message.hasDefaultFixed32 = NO;
+  message.hasDefaultFixed64 = NO;
+  message.hasDefaultSfixed32 = NO;
+  message.hasDefaultSfixed64 = NO;
+  message.hasDefaultFloat = NO;
+  message.hasDefaultDouble = NO;
+  message.hasDefaultBool = NO;
+  message.hasDefaultString = NO;
+  message.hasDefaultBytes = NO;
+
+  message.hasDefaultNestedEnum = NO;
+  message.hasDefaultForeignEnum = NO;
+  message.hasDefaultImportEnum = NO;
+
+  message.hasDefaultStringPiece = NO;
+  message.hasDefaultCord = NO;
+}
+
+- (void)setAllExtensions:(TestAllExtensions *)message
+           repeatedCount:(uint32_t)count {
+  [message setExtension:[UnittestRoot optionalInt32Extension] value:@101];
+  [message setExtension:[UnittestRoot optionalInt64Extension] value:@102L];
+  [message setExtension:[UnittestRoot optionalUint32Extension] value:@103];
+  [message setExtension:[UnittestRoot optionalUint64Extension] value:@104L];
+  [message setExtension:[UnittestRoot optionalSint32Extension] value:@105];
+  [message setExtension:[UnittestRoot optionalSint64Extension] value:@106L];
+  [message setExtension:[UnittestRoot optionalFixed32Extension] value:@107];
+  [message setExtension:[UnittestRoot optionalFixed64Extension] value:@108L];
+  [message setExtension:[UnittestRoot optionalSfixed32Extension] value:@109];
+  [message setExtension:[UnittestRoot optionalSfixed64Extension] value:@110L];
+  [message setExtension:[UnittestRoot optionalFloatExtension] value:@111.0f];
+  [message setExtension:[UnittestRoot optionalDoubleExtension] value:@112.0];
+  [message setExtension:[UnittestRoot optionalBoolExtension] value:@YES];
+  [message setExtension:[UnittestRoot optionalStringExtension] value:@"115"];
+  [message setExtension:[UnittestRoot optionalBytesExtension]
+                  value:[NSData gpbtu_dataWithEmbeddedNulls]];
+
+  OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message];
+  [optionalGroup setA:117];
+  [message setExtension:[UnittestRoot optionalGroupExtension]
+                  value:optionalGroup];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  [nestedMessage setBb:118];
+  [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+                  value:nestedMessage];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setC:119];
+  [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+                  value:foreignMessage];
+  ImportMessage *importMessage = [ImportMessage message];
+  [importMessage setD:120];
+  [message setExtension:[UnittestRoot optionalImportMessageExtension]
+                  value:importMessage];
+
+  [message setExtension:[UnittestRoot optionalNestedEnumExtension]
+                  value:@(TestAllTypes_NestedEnum_Baz)];
+  [message setExtension:[UnittestRoot optionalForeignEnumExtension]
+                  value:@(ForeignEnum_ForeignBaz)];
+  [message setExtension:[UnittestRoot optionalImportEnumExtension]
+                  value:@(ImportEnum_ImportBaz)];
+
+  [message setExtension:[UnittestRoot optionalStringPieceExtension]
+                  value:@"124"];
+  [message setExtension:[UnittestRoot optionalCordExtension] value:@"125"];
+
+  for (uint32_t i = 0; i < count; ++i) {
+    [message addExtension:[UnittestRoot repeatedInt32Extension]
+                    value:@(201 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedInt64Extension]
+                    value:@(202 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedUint32Extension]
+                    value:@(203 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedUint64Extension]
+                    value:@(204 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedSint32Extension]
+                    value:@(205 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedSint64Extension]
+                    value:@(206 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedFixed32Extension]
+                    value:@(207 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedFixed64Extension]
+                    value:@(208 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedSfixed32Extension]
+                    value:@(209 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedSfixed64Extension]
+                    value:@(210 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedFloatExtension]
+                    value:@(211 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedDoubleExtension]
+                    value:@(212 + i * 100)];
+    [message addExtension:[UnittestRoot repeatedBoolExtension]
+                    value:@((i % 2) ? YES : NO)];
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100];
+    [message addExtension:[UnittestRoot repeatedStringExtension] value:string];
+    [string release];
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100];
+    [message addExtension:[UnittestRoot repeatedBytesExtension] value:data];
+    [data release];
+
+    RepeatedGroup_extension *repeatedGroup =
+        [[RepeatedGroup_extension alloc] init];
+    [repeatedGroup setA:217 + i * 100];
+    [message addExtension:[UnittestRoot repeatedGroupExtension]
+                    value:repeatedGroup];
+    [repeatedGroup release];
+    nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
+    [nestedMessage setBb:218 + i * 100];
+    [message addExtension:[UnittestRoot repeatedNestedMessageExtension]
+                    value:nestedMessage];
+    [nestedMessage release];
+    foreignMessage = [[ForeignMessage alloc] init];
+    [foreignMessage setC:219 + i * 100];
+    [message addExtension:[UnittestRoot repeatedForeignMessageExtension]
+                    value:foreignMessage];
+    [foreignMessage release];
+    importMessage = [[ImportMessage alloc] init];
+    [importMessage setD:220 + i * 100];
+    [message addExtension:[UnittestRoot repeatedImportMessageExtension]
+                    value:importMessage];
+    [importMessage release];
+    [message addExtension:[UnittestRoot repeatedNestedEnumExtension]
+                    value:@((i % 2) ? TestAllTypes_NestedEnum_Bar
+                                    : TestAllTypes_NestedEnum_Baz)];
+    [message addExtension:[UnittestRoot repeatedForeignEnumExtension]
+                    value:@((i % 2) ? ForeignEnum_ForeignBar
+                                    : ForeignEnum_ForeignBaz)];
+    [message
+        addExtension:[UnittestRoot repeatedImportEnumExtension]
+               value:@((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz)];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100];
+    [message addExtension:[UnittestRoot repeatedStringPieceExtension]
+                    value:string];
+    [string release];
+
+    string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100];
+    [message addExtension:[UnittestRoot repeatedCordExtension] value:string];
+    [string release];
+  }
+
+  // -----------------------------------------------------------------
+
+  [message setExtension:[UnittestRoot defaultInt32Extension] value:@401];
+  [message setExtension:[UnittestRoot defaultInt64Extension] value:@402L];
+  [message setExtension:[UnittestRoot defaultUint32Extension] value:@403];
+  [message setExtension:[UnittestRoot defaultUint64Extension] value:@404L];
+  [message setExtension:[UnittestRoot defaultSint32Extension] value:@405];
+  [message setExtension:[UnittestRoot defaultSint64Extension] value:@406L];
+  [message setExtension:[UnittestRoot defaultFixed32Extension] value:@407];
+  [message setExtension:[UnittestRoot defaultFixed64Extension] value:@408L];
+  [message setExtension:[UnittestRoot defaultSfixed32Extension] value:@409];
+  [message setExtension:[UnittestRoot defaultSfixed64Extension] value:@410L];
+  [message setExtension:[UnittestRoot defaultFloatExtension] value:@411.0f];
+  [message setExtension:[UnittestRoot defaultDoubleExtension] value:@412.0];
+  [message setExtension:[UnittestRoot defaultBoolExtension] value:@NO];
+  [message setExtension:[UnittestRoot defaultStringExtension] value:@"415"];
+  [message setExtension:[UnittestRoot defaultBytesExtension]
+                  value:[NSData gpbtu_dataWithUint32:416]];
+
+  [message setExtension:[UnittestRoot defaultNestedEnumExtension]
+                  value:@(TestAllTypes_NestedEnum_Foo)];
+  [message setExtension:[UnittestRoot defaultForeignEnumExtension]
+                  value:@(ForeignEnum_ForeignFoo)];
+  [message setExtension:[UnittestRoot defaultImportEnumExtension]
+                  value:@(ImportEnum_ImportFoo)];
+
+  [message setExtension:[UnittestRoot defaultStringPieceExtension]
+                  value:@"424"];
+  [message setExtension:[UnittestRoot defaultCordExtension] value:@"425"];
+}
+
+- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count {
+  for (uint32_t i = 0; i < count; i++) {
+    [message.mapInt32Int32 setValue:(i + 1) forKey:100 + i * 100];
+    [message.mapInt64Int64 setValue:(i + 1) forKey:101 + i * 100];
+    [message.mapUint32Uint32 setValue:(i + 1) forKey:102 + i * 100];
+    [message.mapUint64Uint64 setValue:(i + 1) forKey:103 + i * 100];
+    [message.mapSint32Sint32 setValue:(i + 1) forKey:104 + i * 100];
+    [message.mapSint64Sint64 setValue:(i + 1) forKey:105 + i * 100];
+    [message.mapFixed32Fixed32 setValue:(i + 1) forKey:106 + i * 100];
+    [message.mapFixed64Fixed64 setValue:(i + 1) forKey:107 + i * 100];
+    [message.mapSfixed32Sfixed32 setValue:(i + 1) forKey:108 + i * 100];
+    [message.mapSfixed64Sfixed64 setValue:(i + 1) forKey:109 + i * 100];
+    [message.mapInt32Float setValue:(i + 1) forKey:110 + i * 100];
+    [message.mapInt32Double setValue:(i + 1) forKey:111 + i * 100];
+    [message.mapBoolBool setValue:((i % 2) == 1) forKey:((i % 2) == 0)];
+
+    NSString *keyStr = [[NSString alloc] initWithFormat:@"%d", 112 + i * 100];
+    NSString *dataStr = [[NSString alloc] initWithFormat:@"%d", i + 1];
+    [message.mapStringString setObject:dataStr forKey:keyStr];
+    [keyStr release];
+    [dataStr release];
+
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:i + 1];
+    [message.mapInt32Bytes setObject:data forKey:113 + i * 100];
+    [data release];
+
+    [message.mapInt32Enum
+        setValue:(i % 2) ? MapEnum_MapEnumBar : MapEnum_MapEnumBaz
+          forKey:114 + i * 100];
+
+    ForeignMessage *subMsg = [[ForeignMessage alloc] init];
+    subMsg.c = i + 1;
+    [message.mapInt32ForeignMessage setObject:subMsg forKey:115 + i * 100];
+    [subMsg release];
+  }
+}
+
+- (void)setAllTestPackedFields:(TestPackedTypes *)message {
+  // Must match -setAllTestUnpackedFields:
+  [message.packedInt32Array addValue:101];
+  [message.packedInt64Array addValue:102];
+  [message.packedUint32Array addValue:103];
+  [message.packedUint64Array addValue:104];
+  [message.packedSint32Array addValue:105];
+  [message.packedSint64Array addValue:106];
+  [message.packedFixed32Array addValue:107];
+  [message.packedFixed64Array addValue:108];
+  [message.packedSfixed32Array addValue:109];
+  [message.packedSfixed64Array addValue:110];
+  [message.packedFloatArray addValue:111.f];
+  [message.packedDoubleArray addValue:112.];
+  [message.packedBoolArray addValue:YES];
+  [message.packedEnumArray addValue:ForeignEnum_ForeignBar];
+
+  [message.packedInt32Array addValue:201];
+  [message.packedInt64Array addValue:302];
+  [message.packedUint32Array addValue:203];
+  [message.packedUint64Array addValue:204];
+  [message.packedSint32Array addValue:205];
+  [message.packedSint64Array addValue:206];
+  [message.packedFixed32Array addValue:207];
+  [message.packedFixed64Array addValue:208];
+  [message.packedSfixed32Array addValue:209];
+  [message.packedSfixed64Array addValue:210];
+  [message.packedFloatArray addValue:211.f];
+  [message.packedDoubleArray addValue:212.];
+  [message.packedBoolArray addValue:NO];
+  [message.packedEnumArray addValue:ForeignEnum_ForeignBaz];
+}
+
+- (void)setAllTestUnpackedFields:(TestUnpackedTypes *)message {
+  // Must match -setAllTestPackedFields:
+  [message.unpackedInt32Array addValue:101];
+  [message.unpackedInt64Array addValue:102];
+  [message.unpackedUint32Array addValue:103];
+  [message.unpackedUint64Array addValue:104];
+  [message.unpackedSint32Array addValue:105];
+  [message.unpackedSint64Array addValue:106];
+  [message.unpackedFixed32Array addValue:107];
+  [message.unpackedFixed64Array addValue:108];
+  [message.unpackedSfixed32Array addValue:109];
+  [message.unpackedSfixed64Array addValue:110];
+  [message.unpackedFloatArray addValue:111.f];
+  [message.unpackedDoubleArray addValue:112.];
+  [message.unpackedBoolArray addValue:YES];
+  [message.unpackedEnumArray addValue:ForeignEnum_ForeignBar];
+
+  [message.unpackedInt32Array addValue:201];
+  [message.unpackedInt64Array addValue:302];
+  [message.unpackedUint32Array addValue:203];
+  [message.unpackedUint64Array addValue:204];
+  [message.unpackedSint32Array addValue:205];
+  [message.unpackedSint64Array addValue:206];
+  [message.unpackedFixed32Array addValue:207];
+  [message.unpackedFixed64Array addValue:208];
+  [message.unpackedSfixed32Array addValue:209];
+  [message.unpackedSfixed64Array addValue:210];
+  [message.unpackedFloatArray addValue:211.f];
+  [message.unpackedDoubleArray addValue:212.];
+  [message.unpackedBoolArray addValue:NO];
+  [message.unpackedEnumArray addValue:ForeignEnum_ForeignBaz];
+}
+
+- (GPBExtensionRegistry *)extensionRegistry {
+  return [UnittestRoot extensionRegistry];
+}
+
+- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count {
+  TestAllTypes *message = [TestAllTypes message];
+  [self setAllFields:message repeatedCount:count];
+  return message;
+}
+
+- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count {
+  TestAllExtensions *message = [TestAllExtensions message];
+  [self setAllExtensions:message repeatedCount:count];
+  return message;
+}
+
+- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count {
+  TestPackedTypes *message = [TestPackedTypes message];
+  [self setPackedFields:message repeatedCount:count];
+  return message;
+}
+
+- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count {
+  TestPackedExtensions *message = [TestPackedExtensions message];
+  [self setPackedExtensions:message repeatedCount:count];
+  return message;
+}
+
+// -------------------------------------------------------------------
+
+- (void)assertClear:(TestAllTypes *)message {
+  // hasBlah() should initially be NO for all optional fields.
+  XCTAssertFalse(message.hasOptionalInt32);
+  XCTAssertFalse(message.hasOptionalInt64);
+  XCTAssertFalse(message.hasOptionalUint32);
+  XCTAssertFalse(message.hasOptionalUint64);
+  XCTAssertFalse(message.hasOptionalSint32);
+  XCTAssertFalse(message.hasOptionalSint64);
+  XCTAssertFalse(message.hasOptionalFixed32);
+  XCTAssertFalse(message.hasOptionalFixed64);
+  XCTAssertFalse(message.hasOptionalSfixed32);
+  XCTAssertFalse(message.hasOptionalSfixed64);
+  XCTAssertFalse(message.hasOptionalFloat);
+  XCTAssertFalse(message.hasOptionalDouble);
+  XCTAssertFalse(message.hasOptionalBool);
+  XCTAssertFalse(message.hasOptionalString);
+  XCTAssertFalse(message.hasOptionalBytes);
+
+  XCTAssertFalse(message.hasOptionalGroup);
+  XCTAssertFalse(message.hasOptionalNestedMessage);
+  XCTAssertFalse(message.hasOptionalForeignMessage);
+  XCTAssertFalse(message.hasOptionalImportMessage);
+
+  XCTAssertFalse(message.hasOptionalNestedEnum);
+  XCTAssertFalse(message.hasOptionalForeignEnum);
+  XCTAssertFalse(message.hasOptionalImportEnum);
+
+  XCTAssertFalse(message.hasOptionalStringPiece);
+  XCTAssertFalse(message.hasOptionalCord);
+
+  // Optional fields without defaults are set to zero or something like it.
+  XCTAssertEqual(0, message.optionalInt32);
+  XCTAssertEqual(0LL, message.optionalInt64);
+  XCTAssertEqual(0U, message.optionalUint32);
+  XCTAssertEqual(0ULL, message.optionalUint64);
+  XCTAssertEqual(0, message.optionalSint32);
+  XCTAssertEqual(0LL, message.optionalSint64);
+  XCTAssertEqual(0U, message.optionalFixed32);
+  XCTAssertEqual(0ULL, message.optionalFixed64);
+  XCTAssertEqual(0, message.optionalSfixed32);
+  XCTAssertEqual(0LL, message.optionalSfixed64);
+  XCTAssertEqual(0.0f, message.optionalFloat);
+  XCTAssertEqual(0.0, message.optionalDouble);
+  XCTAssertFalse(message.optionalBool);
+  XCTAssertEqualObjects(message.optionalString, @"");
+  XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+
+  // Embedded messages should also be clear.
+  XCTAssertFalse(message.hasOptionalGroup);
+  XCTAssertFalse(message.hasOptionalNestedMessage);
+  XCTAssertFalse(message.hasOptionalForeignMessage);
+  XCTAssertFalse(message.hasOptionalImportMessage);
+
+  // Enums without defaults are set to the first value in the enum.
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.optionalNestedEnum);
+  XCTAssertEqual(ForeignEnum_ForeignFoo, message.optionalForeignEnum);
+  XCTAssertEqual(ImportEnum_ImportFoo, message.optionalImportEnum);
+
+  XCTAssertEqualObjects(message.optionalStringPiece, @"");
+  XCTAssertEqualObjects(message.optionalCord, @"");
+
+  // Repeated fields are empty.
+
+  XCTAssertEqual(0U, message.repeatedInt32Array.count);
+  XCTAssertEqual(0U, message.repeatedInt64Array.count);
+  XCTAssertEqual(0U, message.repeatedUint32Array.count);
+  XCTAssertEqual(0U, message.repeatedUint64Array.count);
+  XCTAssertEqual(0U, message.repeatedSint32Array.count);
+  XCTAssertEqual(0U, message.repeatedSint64Array.count);
+  XCTAssertEqual(0U, message.repeatedFixed32Array.count);
+  XCTAssertEqual(0U, message.repeatedFixed64Array.count);
+  XCTAssertEqual(0U, message.repeatedSfixed32Array.count);
+  XCTAssertEqual(0U, message.repeatedSfixed64Array.count);
+  XCTAssertEqual(0U, message.repeatedFloatArray.count);
+  XCTAssertEqual(0U, message.repeatedDoubleArray.count);
+  XCTAssertEqual(0U, message.repeatedBoolArray.count);
+  XCTAssertEqual(0U, message.repeatedStringArray.count);
+  XCTAssertEqual(0U, message.repeatedBytesArray.count);
+
+  XCTAssertEqual(0U, message.repeatedGroupArray.count);
+  XCTAssertEqual(0U, message.repeatedNestedMessageArray.count);
+  XCTAssertEqual(0U, message.repeatedForeignMessageArray.count);
+  XCTAssertEqual(0U, message.repeatedImportMessageArray.count);
+  XCTAssertEqual(0U, message.repeatedNestedEnumArray.count);
+  XCTAssertEqual(0U, message.repeatedForeignEnumArray.count);
+  XCTAssertEqual(0U, message.repeatedImportEnumArray.count);
+
+  XCTAssertEqual(0U, message.repeatedStringPieceArray.count);
+  XCTAssertEqual(0U, message.repeatedCordArray.count);
+
+  XCTAssertEqual(0U, message.repeatedInt32Array_Count);
+  XCTAssertEqual(0U, message.repeatedInt64Array_Count);
+  XCTAssertEqual(0U, message.repeatedUint32Array_Count);
+  XCTAssertEqual(0U, message.repeatedUint64Array_Count);
+  XCTAssertEqual(0U, message.repeatedSint32Array_Count);
+  XCTAssertEqual(0U, message.repeatedSint64Array_Count);
+  XCTAssertEqual(0U, message.repeatedFixed32Array_Count);
+  XCTAssertEqual(0U, message.repeatedFixed64Array_Count);
+  XCTAssertEqual(0U, message.repeatedSfixed32Array_Count);
+  XCTAssertEqual(0U, message.repeatedSfixed64Array_Count);
+  XCTAssertEqual(0U, message.repeatedFloatArray_Count);
+  XCTAssertEqual(0U, message.repeatedDoubleArray_Count);
+  XCTAssertEqual(0U, message.repeatedBoolArray_Count);
+  XCTAssertEqual(0U, message.repeatedStringArray_Count);
+  XCTAssertEqual(0U, message.repeatedBytesArray_Count);
+
+  XCTAssertEqual(0U, message.repeatedGroupArray_Count);
+  XCTAssertEqual(0U, message.repeatedNestedMessageArray_Count);
+  XCTAssertEqual(0U, message.repeatedForeignMessageArray_Count);
+  XCTAssertEqual(0U, message.repeatedImportMessageArray_Count);
+  XCTAssertEqual(0U, message.repeatedNestedEnumArray_Count);
+  XCTAssertEqual(0U, message.repeatedForeignEnumArray_Count);
+  XCTAssertEqual(0U, message.repeatedImportEnumArray_Count);
+
+  XCTAssertEqual(0U, message.repeatedStringPieceArray_Count);
+  XCTAssertEqual(0U, message.repeatedCordArray_Count);
+
+  // hasBlah() should also be NO for all default fields.
+  XCTAssertFalse(message.hasDefaultInt32);
+  XCTAssertFalse(message.hasDefaultInt64);
+  XCTAssertFalse(message.hasDefaultUint32);
+  XCTAssertFalse(message.hasDefaultUint64);
+  XCTAssertFalse(message.hasDefaultSint32);
+  XCTAssertFalse(message.hasDefaultSint64);
+  XCTAssertFalse(message.hasDefaultFixed32);
+  XCTAssertFalse(message.hasDefaultFixed64);
+  XCTAssertFalse(message.hasDefaultSfixed32);
+  XCTAssertFalse(message.hasDefaultSfixed64);
+  XCTAssertFalse(message.hasDefaultFloat);
+  XCTAssertFalse(message.hasDefaultDouble);
+  XCTAssertFalse(message.hasDefaultBool);
+  XCTAssertFalse(message.hasDefaultString);
+  XCTAssertFalse(message.hasDefaultBytes);
+
+  XCTAssertFalse(message.hasDefaultNestedEnum);
+  XCTAssertFalse(message.hasDefaultForeignEnum);
+  XCTAssertFalse(message.hasDefaultImportEnum);
+
+  XCTAssertFalse(message.hasDefaultStringPiece);
+  XCTAssertFalse(message.hasDefaultCord);
+
+  // Fields with defaults have their default values (duh).
+  XCTAssertEqual(41, message.defaultInt32);
+  XCTAssertEqual(42LL, message.defaultInt64);
+  XCTAssertEqual(43U, message.defaultUint32);
+  XCTAssertEqual(44ULL, message.defaultUint64);
+  XCTAssertEqual(-45, message.defaultSint32);
+  XCTAssertEqual(46LL, message.defaultSint64);
+  XCTAssertEqual(47U, message.defaultFixed32);
+  XCTAssertEqual(48ULL, message.defaultFixed64);
+  XCTAssertEqual(49, message.defaultSfixed32);
+  XCTAssertEqual(-50LL, message.defaultSfixed64);
+  XCTAssertEqualWithAccuracy(51.5f, message.defaultFloat, 0.1);
+  XCTAssertEqualWithAccuracy(52e3, message.defaultDouble, 0.1);
+  XCTAssertTrue(message.defaultBool);
+  XCTAssertEqualObjects(@"hello", message.defaultString);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"],
+                        message.defaultBytes);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Bar, message.defaultNestedEnum);
+  XCTAssertEqual(ForeignEnum_ForeignBar, message.defaultForeignEnum);
+  XCTAssertEqual(ImportEnum_ImportBar, message.defaultImportEnum);
+
+  XCTAssertEqualObjects(@"abc", message.defaultStringPiece);
+  XCTAssertEqualObjects(@"123", message.defaultCord);
+}
+
+- (void)assertExtensionsClear:(TestAllExtensions *)message {
+  // hasBlah() should initially be NO for all optional fields.
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalFloatExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalDoubleExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalBoolExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalBytesExtension]]);
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportEnumExtension]]);
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringPieceExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot optionalCordExtension]]);
+
+  // Optional fields without defaults are set to zero or something like it.
+  XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]);
+  XCTAssertEqual(0LL,[[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]);
+  XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]);
+  XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]);
+  XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]);
+  XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]);
+  XCTAssertEqualWithAccuracy(0.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy(0.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01);
+  XCTAssertFalse([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]);
+  XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringExtension]]);
+  XCTAssertEqualObjects(GPBEmptyNSData(), [message getExtension:[UnittestRoot optionalBytesExtension]]);
+
+  // Embedded messages should also be clear.
+
+  XCTAssertFalse([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]);
+  XCTAssertFalse([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]);
+  XCTAssertFalse([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]);
+  XCTAssertFalse([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]);
+
+  XCTAssertEqual(0, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]);
+  XCTAssertEqual(0, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]);
+  XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]);
+  XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]);
+
+  // Enums without defaults are set to the first value in the enum.
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo,
+               [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignFoo,
+               [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]);
+  XCTAssertEqual(ImportEnum_ImportFoo,
+               [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]);
+
+  XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringPieceExtension]]);
+  XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalCordExtension]]);
+
+  // Repeated fields are empty.
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]);
+
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]);
+
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]);
+  XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]);
+
+  // hasBlah() should also be NO for all default fields.
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed32Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed64Extension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultFloatExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultDoubleExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultBoolExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultBytesExtension]]);
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultImportEnumExtension]]);
+
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringPieceExtension]]);
+  XCTAssertFalse([message hasExtension:[UnittestRoot defaultCordExtension]]);
+
+  // Fields with defaults have their default values (duh).
+  XCTAssertEqual( 41, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]);
+  XCTAssertEqual( 42LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]);
+  XCTAssertEqual( 43U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]);
+  XCTAssertEqual( 44ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual(-45, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]);
+  XCTAssertEqual( 46LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]);
+  XCTAssertEqual( 47, [[message getExtension:[UnittestRoot defaultFixed32Extension]] intValue]);
+  XCTAssertEqual( 48ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]);
+  XCTAssertEqual( 49, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]);
+  XCTAssertEqual(-50LL, [[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]);
+  XCTAssertEqualWithAccuracy( 51.5f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01);
+  XCTAssertEqualWithAccuracy( 52e3, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01);
+  XCTAssertTrue([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]);
+  XCTAssertEqualObjects(@"hello", [message getExtension:[UnittestRoot defaultStringExtension]]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"], [message getExtension:[UnittestRoot defaultBytesExtension]]);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Bar,
+               [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]);
+  XCTAssertEqual(ForeignEnum_ForeignBar,
+               [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]);
+  XCTAssertEqual(ImportEnum_ImportBar,
+               [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]);
+
+  XCTAssertEqualObjects(@"abc", [message getExtension:[UnittestRoot defaultStringPieceExtension]]);
+  XCTAssertEqualObjects(@"123", [message getExtension:[UnittestRoot defaultCordExtension]]);
+}
+
+- (void)modifyRepeatedFields:(TestAllTypes *)message {
+  [message.repeatedInt32Array replaceValueAtIndex:1 withValue:501];
+  [message.repeatedInt64Array replaceValueAtIndex:1 withValue:502];
+  [message.repeatedUint32Array replaceValueAtIndex:1 withValue:503];
+  [message.repeatedUint64Array replaceValueAtIndex:1 withValue:504];
+  [message.repeatedSint32Array replaceValueAtIndex:1 withValue:505];
+  [message.repeatedSint64Array replaceValueAtIndex:1 withValue:506];
+  [message.repeatedFixed32Array replaceValueAtIndex:1 withValue:507];
+  [message.repeatedFixed64Array replaceValueAtIndex:1 withValue:508];
+  [message.repeatedSfixed32Array replaceValueAtIndex:1 withValue:509];
+  [message.repeatedSfixed64Array replaceValueAtIndex:1 withValue:510];
+  [message.repeatedFloatArray replaceValueAtIndex:1 withValue:511];
+  [message.repeatedDoubleArray replaceValueAtIndex:1 withValue:512];
+  [message.repeatedBoolArray replaceValueAtIndex:1 withValue:YES];
+  [message.repeatedStringArray replaceObjectAtIndex:1 withObject:@"515"];
+
+  NSData *data = [[NSData alloc] initWithUint32_gpbtu:516];
+  [message.repeatedBytesArray replaceObjectAtIndex:1 withObject:data];
+  [data release];
+
+  TestAllTypes_RepeatedGroup *testAll =
+      [[TestAllTypes_RepeatedGroup alloc] init];
+  [testAll setA:517];
+  [message.repeatedGroupArray replaceObjectAtIndex:1 withObject:testAll];
+  [testAll release];
+
+  TestAllTypes_NestedMessage *nestedMessage =
+      [[TestAllTypes_NestedMessage alloc] init];
+  [nestedMessage setBb:518];
+  [message.repeatedNestedMessageArray replaceObjectAtIndex:1
+                                                withObject:nestedMessage];
+  [nestedMessage release];
+
+  ForeignMessage *foreignMessage = [[ForeignMessage alloc] init];
+  [foreignMessage setC:519];
+  [message.repeatedForeignMessageArray replaceObjectAtIndex:1
+                                                 withObject:foreignMessage];
+  [foreignMessage release];
+
+  ImportMessage *importMessage = [[ImportMessage alloc] init];
+  [importMessage setD:520];
+  [message.repeatedImportMessageArray replaceObjectAtIndex:1
+                                                withObject:importMessage];
+  [importMessage release];
+
+  [message.repeatedNestedEnumArray replaceValueAtIndex:1 withValue:TestAllTypes_NestedEnum_Foo];
+  [message.repeatedForeignEnumArray replaceValueAtIndex:1 withValue:ForeignEnum_ForeignFoo];
+  [message.repeatedImportEnumArray replaceValueAtIndex:1 withValue:ImportEnum_ImportFoo];
+
+  [message.repeatedStringPieceArray replaceObjectAtIndex:1 withObject:@"524"];
+  [message.repeatedCordArray replaceObjectAtIndex:1 withObject:@"525"];
+}
+
+- (void)assertRepeatedFieldsModified:(TestAllTypes *)message
+                       repeatedCount:(uint32_t)count {
+  // ModifyRepeatedFields only sets the second repeated element of each
+  // field.  In addition to verifying this, we also verify that the first
+  // element and size were *not* modified.
+
+  XCTAssertEqual(count, message.repeatedInt32Array.count);
+  XCTAssertEqual(count, message.repeatedInt64Array.count);
+  XCTAssertEqual(count, message.repeatedUint32Array.count);
+  XCTAssertEqual(count, message.repeatedUint64Array.count);
+  XCTAssertEqual(count, message.repeatedSint32Array.count);
+  XCTAssertEqual(count, message.repeatedSint64Array.count);
+  XCTAssertEqual(count, message.repeatedFixed32Array.count);
+  XCTAssertEqual(count, message.repeatedFixed64Array.count);
+  XCTAssertEqual(count, message.repeatedSfixed32Array.count);
+  XCTAssertEqual(count, message.repeatedSfixed64Array.count);
+  XCTAssertEqual(count, message.repeatedFloatArray.count);
+  XCTAssertEqual(count, message.repeatedDoubleArray.count);
+  XCTAssertEqual(count, message.repeatedBoolArray.count);
+  XCTAssertEqual(count, message.repeatedStringArray.count);
+  XCTAssertEqual(count, message.repeatedBytesArray.count);
+
+  XCTAssertEqual(count, message.repeatedGroupArray.count);
+  XCTAssertEqual(count, message.repeatedNestedMessageArray.count);
+  XCTAssertEqual(count, message.repeatedForeignMessageArray.count);
+  XCTAssertEqual(count, message.repeatedImportMessageArray.count);
+  XCTAssertEqual(count, message.repeatedNestedEnumArray.count);
+  XCTAssertEqual(count, message.repeatedForeignEnumArray.count);
+  XCTAssertEqual(count, message.repeatedImportEnumArray.count);
+
+  XCTAssertEqual(count, message.repeatedStringPieceArray.count);
+  XCTAssertEqual(count, message.repeatedCordArray.count);
+
+  XCTAssertEqual(count, message.repeatedInt32Array_Count);
+  XCTAssertEqual(count, message.repeatedInt64Array_Count);
+  XCTAssertEqual(count, message.repeatedUint32Array_Count);
+  XCTAssertEqual(count, message.repeatedUint64Array_Count);
+  XCTAssertEqual(count, message.repeatedSint32Array_Count);
+  XCTAssertEqual(count, message.repeatedSint64Array_Count);
+  XCTAssertEqual(count, message.repeatedFixed32Array_Count);
+  XCTAssertEqual(count, message.repeatedFixed64Array_Count);
+  XCTAssertEqual(count, message.repeatedSfixed32Array_Count);
+  XCTAssertEqual(count, message.repeatedSfixed64Array_Count);
+  XCTAssertEqual(count, message.repeatedFloatArray_Count);
+  XCTAssertEqual(count, message.repeatedDoubleArray_Count);
+  XCTAssertEqual(count, message.repeatedBoolArray_Count);
+  XCTAssertEqual(count, message.repeatedStringArray_Count);
+  XCTAssertEqual(count, message.repeatedBytesArray_Count);
+
+  XCTAssertEqual(count, message.repeatedGroupArray_Count);
+  XCTAssertEqual(count, message.repeatedNestedMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedForeignMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedImportMessageArray_Count);
+  XCTAssertEqual(count, message.repeatedNestedEnumArray_Count);
+  XCTAssertEqual(count, message.repeatedForeignEnumArray_Count);
+  XCTAssertEqual(count, message.repeatedImportEnumArray_Count);
+
+  XCTAssertEqual(count, message.repeatedStringPieceArray_Count);
+  XCTAssertEqual(count, message.repeatedCordArray_Count);
+
+  XCTAssertEqual(201, [message.repeatedInt32Array valueAtIndex:0]);
+  XCTAssertEqual(202LL, [message.repeatedInt64Array valueAtIndex:0]);
+  XCTAssertEqual(203U, [message.repeatedUint32Array valueAtIndex:0]);
+  XCTAssertEqual(204ULL, [message.repeatedUint64Array valueAtIndex:0]);
+  XCTAssertEqual(205, [message.repeatedSint32Array valueAtIndex:0]);
+  XCTAssertEqual(206LL, [message.repeatedSint64Array valueAtIndex:0]);
+  XCTAssertEqual(207U, [message.repeatedFixed32Array valueAtIndex:0]);
+  XCTAssertEqual(208ULL, [message.repeatedFixed64Array valueAtIndex:0]);
+  XCTAssertEqual(209, [message.repeatedSfixed32Array valueAtIndex:0]);
+  XCTAssertEqual(210LL, [message.repeatedSfixed64Array valueAtIndex:0]);
+  XCTAssertEqualWithAccuracy(211.0f, [message.repeatedFloatArray valueAtIndex:0], 0.01);
+  XCTAssertEqualWithAccuracy(212.0, [message.repeatedDoubleArray valueAtIndex:0], 0.01);
+  XCTAssertFalse([message.repeatedBoolArray valueAtIndex:0]);
+  XCTAssertEqualObjects(@"215", message.repeatedStringArray[0]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216],
+                        message.repeatedBytesArray[0]);
+
+  XCTAssertEqual(217, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[0]).a);
+  XCTAssertEqual(218, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[0]).bb);
+  XCTAssertEqual(219, ((ForeignMessage*)message.repeatedForeignMessageArray[0]).c);
+  XCTAssertEqual(220, ((ImportMessage*)message.repeatedImportMessageArray[0]).d);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:0]);
+  XCTAssertEqual(ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:0]);
+  XCTAssertEqual(ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:0]);
+
+  XCTAssertEqualObjects(@"224", message.repeatedStringPieceArray[0]);
+  XCTAssertEqualObjects(@"225", message.repeatedCordArray[0]);
+
+  // Actually verify the second (modified) elements now.
+  XCTAssertEqual(501, [message.repeatedInt32Array valueAtIndex:1]);
+  XCTAssertEqual(502LL, [message.repeatedInt64Array valueAtIndex:1]);
+  XCTAssertEqual(503U, [message.repeatedUint32Array valueAtIndex:1]);
+  XCTAssertEqual(504ULL, [message.repeatedUint64Array valueAtIndex:1]);
+  XCTAssertEqual(505, [message.repeatedSint32Array valueAtIndex:1]);
+  XCTAssertEqual(506LL, [message.repeatedSint64Array valueAtIndex:1]);
+  XCTAssertEqual(507U, [message.repeatedFixed32Array valueAtIndex:1]);
+  XCTAssertEqual(508ULL, [message.repeatedFixed64Array valueAtIndex:1]);
+  XCTAssertEqual(509, [message.repeatedSfixed32Array valueAtIndex:1]);
+  XCTAssertEqual(510LL, [message.repeatedSfixed64Array valueAtIndex:1]);
+  XCTAssertEqualWithAccuracy(511.0f, [message.repeatedFloatArray valueAtIndex:1], 0.01);
+  XCTAssertEqualWithAccuracy(512.0, [message.repeatedDoubleArray valueAtIndex:1], 0.01);
+  XCTAssertTrue([message.repeatedBoolArray valueAtIndex:1]);
+  XCTAssertEqualObjects(@"515", message.repeatedStringArray[1]);
+  XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516],
+                        message.repeatedBytesArray[1]);
+
+  XCTAssertEqual(517, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[1]).a);
+  XCTAssertEqual(518, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[1]).bb);
+  XCTAssertEqual(519, ((ForeignMessage*)message.repeatedForeignMessageArray[1]).c);
+  XCTAssertEqual(520, ((ImportMessage*)message.repeatedImportMessageArray[1]).d);
+
+  XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [message.repeatedNestedEnumArray valueAtIndex:1]);
+  XCTAssertEqual(ForeignEnum_ForeignFoo, [message.repeatedForeignEnumArray valueAtIndex:1]);
+  XCTAssertEqual(ImportEnum_ImportFoo, [message.repeatedImportEnumArray valueAtIndex:1]);
+
+  XCTAssertEqualObjects(@"524", message.repeatedStringPieceArray[1]);
+  XCTAssertEqualObjects(@"525", message.repeatedCordArray[1]);
+}
+
+- (void)setPackedFields:(TestPackedTypes *)message
+          repeatedCount:(uint32_t)count {
+  // Must match -setUnpackedFields:repeatedCount:
+  // Must match -setPackedExtensions:repeatedCount:
+  // Must match -setUnpackedExtensions:repeatedCount:
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedInt32Array addValue:601 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedInt64Array addValue:602 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedUint32Array addValue:603 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedUint64Array addValue:604 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedSint32Array addValue:605 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedSint64Array addValue:606 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedFixed32Array addValue:607 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedFixed64Array addValue:608 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedSfixed32Array addValue:609 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedSfixed64Array addValue:610 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedFloatArray addValue:611 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedDoubleArray addValue:612 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedBoolArray addValue:(i % 2) ? YES : NO];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.packedEnumArray
+        addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz];
+  }
+}
+
+- (void)setUnpackedFields:(TestUnpackedTypes *)message
+            repeatedCount:(uint32_t)count {
+  // Must match -setPackedFields:repeatedCount:
+  // Must match -setPackedExtensions:repeatedCount:
+  // Must match -setUnpackedExtensions:repeatedCount:
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedInt32Array addValue:601 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedInt64Array addValue:602 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedUint32Array addValue:603 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedUint64Array addValue:604 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedSint32Array addValue:605 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedSint64Array addValue:606 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedFixed32Array addValue:607 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedFixed64Array addValue:608 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedSfixed32Array addValue:609 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedSfixed64Array addValue:610 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedFloatArray addValue:611 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedDoubleArray addValue:612 + i * 100];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedBoolArray addValue:(i % 2) ? YES : NO];
+  }
+  for (uint32_t i = 0; i < count; ++i) {
+    [message.unpackedEnumArray
+        addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz];
+  }
+}
+
+- (void)assertPackedFieldsSet:(TestPackedTypes *)message
+                repeatedCount:(uint32_t)count {
+  XCTAssertEqual(count, message.packedInt32Array.count);
+  XCTAssertEqual(count, message.packedInt64Array.count);
+  XCTAssertEqual(count, message.packedUint32Array.count);
+  XCTAssertEqual(count, message.packedUint64Array.count);
+  XCTAssertEqual(count, message.packedSint32Array.count);
+  XCTAssertEqual(count, message.packedSint64Array.count);
+  XCTAssertEqual(count, message.packedFixed32Array.count);
+  XCTAssertEqual(count, message.packedFixed64Array.count);
+  XCTAssertEqual(count, message.packedSfixed32Array.count);
+  XCTAssertEqual(count, message.packedSfixed64Array.count);
+  XCTAssertEqual(count, message.packedFloatArray.count);
+  XCTAssertEqual(count, message.packedDoubleArray.count);
+  XCTAssertEqual(count, message.packedBoolArray.count);
+  XCTAssertEqual(count, message.packedEnumArray.count);
+  for (uint32_t i = 0; i < count; ++i) {
+    XCTAssertEqual((int)(601 + i * 100),
+                   [message.packedInt32Array valueAtIndex:i]);
+    XCTAssertEqual(602 + i * 100, [message.packedInt64Array valueAtIndex:i]);
+    XCTAssertEqual(603 + i * 100, [message.packedUint32Array valueAtIndex:i]);
+    XCTAssertEqual(604 + i * 100, [message.packedUint64Array valueAtIndex:i]);
+    XCTAssertEqual((int)(605 + i * 100),
+                   [message.packedSint32Array valueAtIndex:i]);
+    XCTAssertEqual(606 + i * 100, [message.packedSint64Array valueAtIndex:i]);
+    XCTAssertEqual(607 + i * 100, [message.packedFixed32Array valueAtIndex:i]);
+    XCTAssertEqual(608 + i * 100, [message.packedFixed64Array valueAtIndex:i]);
+    XCTAssertEqual((int)(609 + i * 100),
+                   [message.packedSfixed32Array valueAtIndex:i]);
+    XCTAssertEqual(610 + i * 100, [message.packedSfixed64Array valueAtIndex:i]);
+    XCTAssertEqualWithAccuracy(611 + i * 100,
+                               [message.packedFloatArray valueAtIndex:i], 0.01);
+    XCTAssertEqualWithAccuracy(
+        612 + i * 100, [message.packedDoubleArray valueAtIndex:i], 0.01);
+    XCTAssertEqual((i % 2) ? YES : NO,
+                   [message.packedBoolArray valueAtIndex:i]);
+    XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz,
+                   [message.packedEnumArray valueAtIndex:i]);
+  }
+}
+
+- (void)setPackedExtensions:(TestPackedExtensions *)message
+              repeatedCount:(uint32_t)count {
+  // Must match -setPackedFields:repeatedCount:
+  // Must match -setUnpackedFields:repeatedCount:
+  // Must match -setUnpackedExtensions:repeatedCount:
+  for (uint32_t i = 0; i < count; i++) {
+    [message addExtension:[UnittestRoot packedInt32Extension]
+                    value:@(601 + i * 100)];
+    [message addExtension:[UnittestRoot packedInt64Extension]
+                    value:@(602 + i * 100)];
+    [message addExtension:[UnittestRoot packedUint32Extension]
+                    value:@(603 + i * 100)];
+    [message addExtension:[UnittestRoot packedUint64Extension]
+                    value:@(604 + i * 100)];
+    [message addExtension:[UnittestRoot packedSint32Extension]
+                    value:@(605 + i * 100)];
+    [message addExtension:[UnittestRoot packedSint64Extension]
+                    value:@(606 + i * 100)];
+    [message addExtension:[UnittestRoot packedFixed32Extension]
+                    value:@(607 + i * 100)];
+    [message addExtension:[UnittestRoot packedFixed64Extension]
+                    value:@(608 + i * 100)];
+    [message addExtension:[UnittestRoot packedSfixed32Extension]
+                    value:@(609 + i * 100)];
+    [message addExtension:[UnittestRoot packedSfixed64Extension]
+                    value:@(610 + i * 100)];
+    [message addExtension:[UnittestRoot packedFloatExtension]
+                    value:@(611 + i * 100)];
+    [message addExtension:[UnittestRoot packedDoubleExtension]
+                    value:@(612 + i * 100)];
+    [message addExtension:[UnittestRoot packedBoolExtension]
+                    value:@((i % 2) ? YES : NO)];
+    [message addExtension:[UnittestRoot packedEnumExtension]
+                    value:@((i % 2) ? ForeignEnum_ForeignBar
+                                    : ForeignEnum_ForeignBaz)];
+  }
+}
+
+- (void)setUnpackedExtensions:(TestUnpackedExtensions *)message
+                repeatedCount:(uint32_t)count {
+  // Must match -setPackedFields:repeatedCount:
+  // Must match -setUnpackedFields:repeatedCount:
+  // Must match -setPackedExtensions:repeatedCount:
+  for (uint32_t i = 0; i < count; i++) {
+    [message addExtension:[UnittestRoot unpackedInt32Extension]
+                    value:@(601 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedInt64Extension]
+                    value:@(602 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedUint32Extension]
+                    value:@(603 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedUint64Extension]
+                    value:@(604 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedSint32Extension]
+                    value:@(605 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedSint64Extension]
+                    value:@(606 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedFixed32Extension]
+                    value:@(607 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedFixed64Extension]
+                    value:@(608 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedSfixed32Extension]
+                    value:@(609 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedSfixed64Extension]
+                    value:@(610 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedFloatExtension]
+                    value:@(611 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedDoubleExtension]
+                    value:@(612 + i * 100)];
+    [message addExtension:[UnittestRoot unpackedBoolExtension]
+                    value:@((i % 2) ? YES : NO)];
+    [message addExtension:[UnittestRoot unpackedEnumExtension]
+                    value:@((i % 2) ? ForeignEnum_ForeignBar
+                         : ForeignEnum_ForeignBaz)];
+  }
+}
+
+- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message
+                    repeatedCount:(uint32_t)count{
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed32Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed64Extension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFloatExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedDoubleExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedBoolExtension]] count]);
+  XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedEnumExtension]] count]);
+
+  for (uint32_t i = 0; i < count; ++i) {
+    id extension = [message getExtension:[UnittestRoot packedInt32Extension]];
+    XCTAssertEqual((int)(601 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot packedInt64Extension]];
+    XCTAssertEqual(602 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot packedUint32Extension]];
+    XCTAssertEqual(603 + i * 100, [extension[i] unsignedIntValue]);
+    extension = [message getExtension:[UnittestRoot packedUint64Extension]];
+    XCTAssertEqual(604 + i * 100, [extension[i] unsignedLongLongValue]);
+    extension = [message getExtension:[UnittestRoot packedSint32Extension]];
+    XCTAssertEqual((int)(605 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot packedSint64Extension]];
+    XCTAssertEqual(606 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot packedFixed32Extension]];
+    XCTAssertEqual(607 + i * 100, [extension[i] unsignedIntValue]);
+    extension = [message getExtension:[UnittestRoot packedFixed64Extension]];
+    XCTAssertEqual(608 + i * 100, [extension[i] unsignedLongLongValue]);
+    extension = [message getExtension:[UnittestRoot packedSfixed32Extension]];
+    XCTAssertEqual((int)(609 + i * 100), [extension[i] intValue]);
+    extension = [message getExtension:[UnittestRoot packedSfixed64Extension]];
+    XCTAssertEqual(610 + i * 100, [extension[i] longLongValue]);
+    extension = [message getExtension:[UnittestRoot packedFloatExtension]];
+    XCTAssertEqualWithAccuracy(611 + i * 100, [extension[i] floatValue], 0.01);
+    extension = [message getExtension:[UnittestRoot packedDoubleExtension]];
+    XCTAssertEqualWithAccuracy(612 + i * 100, [extension[i] doubleValue], 0.01);
+    extension = [message getExtension:[UnittestRoot packedBoolExtension]];
+    XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]);
+    extension = [message getExtension:[UnittestRoot packedEnumExtension]];
+    XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz,
+                   [extension[i] intValue]);
+  }
+}
+
+- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message {
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @YES);
+  XCTAssertEqualObjects(@(message.optionalInt32), [message valueForKey:@"optionalInt32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @YES);
+  XCTAssertEqualObjects(@(message.optionalInt64), [message valueForKey:@"optionalInt64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @YES);
+  XCTAssertEqualObjects(@(message.optionalUint32), [message valueForKey:@"optionalUint32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @YES);
+  XCTAssertEqualObjects(@(message.optionalUint64), [message valueForKey:@"optionalUint64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @YES);
+  XCTAssertEqualObjects(@(message.optionalSint32), [message valueForKey:@"optionalSint32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @YES);
+  XCTAssertEqualObjects(@(message.optionalSint64), [message valueForKey:@"optionalSint64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @YES);
+  XCTAssertEqualObjects(@(message.optionalFixed32), [message valueForKey:@"optionalFixed32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @YES);
+  XCTAssertEqualObjects(@(message.optionalFixed64), [message valueForKey:@"optionalFixed64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @YES);
+  XCTAssertEqualObjects(@(message.optionalSfixed32), [message valueForKey:@"optionalSfixed32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @YES);
+  XCTAssertEqualObjects(@(message.optionalSfixed64), [message valueForKey:@"optionalSfixed64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @YES);
+  XCTAssertEqualObjects(@(message.optionalFloat), [message valueForKey:@"optionalFloat"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @YES);
+  XCTAssertEqualObjects(@(message.optionalDouble), [message valueForKey:@"optionalDouble"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @YES);
+  XCTAssertEqualObjects(@(message.optionalBool), [message valueForKey:@"optionalBool"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @YES);
+  XCTAssertEqualObjects(message.optionalString, [message valueForKey:@"optionalString"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @YES);
+  XCTAssertEqualObjects(message.optionalBytes, [message valueForKey:@"optionalBytes"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @YES);
+  XCTAssertNotNil(message.optionalGroup);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @YES);
+  XCTAssertEqualObjects(@(message.optionalGroup.a), [message valueForKeyPath:@"optionalGroup.a"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @YES);
+  XCTAssertNotNil(message.optionalNestedMessage);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.hasBb"], @YES);
+  XCTAssertEqualObjects(@(message.optionalNestedMessage.bb), [message valueForKeyPath:@"optionalNestedMessage.bb"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"], @YES);
+  XCTAssertNotNil(message.optionalForeignMessage);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.hasC"], @YES);
+  XCTAssertEqualObjects(@(message.optionalForeignMessage.c), [message valueForKeyPath:@"optionalForeignMessage.c"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @YES);
+  XCTAssertNotNil(message.optionalForeignMessage);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"], @YES);
+  XCTAssertEqualObjects(@(message.optionalImportMessage.d), [message valueForKeyPath:@"optionalImportMessage.d"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @YES);
+  XCTAssertEqualObjects(@(message.optionalNestedEnum), [message valueForKey:@"optionalNestedEnum"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @YES);
+  XCTAssertEqualObjects(@(message.optionalForeignEnum), [message valueForKey:@"optionalForeignEnum"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @YES);
+  XCTAssertEqualObjects(@(message.optionalImportEnum), [message valueForKey:@"optionalImportEnum"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @YES);
+  XCTAssertEqualObjects(message.optionalStringPiece, [message valueForKey:@"optionalStringPiece"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @YES);
+  XCTAssertEqualObjects(message.optionalCord, [message valueForKey:@"optionalCord"]);
+
+  // -----------------------------------------------------------------
+
+  // GPBArray interface for repeated
+
+  XCTAssertEqualObjects(message.repeatedInt32Array, [message valueForKey:@"repeatedInt32Array"]);
+  XCTAssertEqualObjects(message.repeatedInt64Array, [message valueForKey:@"repeatedInt64Array"]);
+  XCTAssertEqualObjects(message.repeatedUint32Array, [message valueForKey:@"repeatedUint32Array"]);
+  XCTAssertEqualObjects(message.repeatedUint64Array, [message valueForKey:@"repeatedUint64Array"]);
+  XCTAssertEqualObjects(message.repeatedSint32Array, [message valueForKey:@"repeatedSint32Array"]);
+  XCTAssertEqualObjects(message.repeatedSint64Array, [message valueForKey:@"repeatedSint64Array"]);
+  XCTAssertEqualObjects(message.repeatedFixed32Array, [message valueForKey:@"repeatedFixed32Array"]);
+  XCTAssertEqualObjects(message.repeatedFixed64Array, [message valueForKey:@"repeatedFixed64Array"]);
+  XCTAssertEqualObjects(message.repeatedSfixed32Array, [message valueForKey:@"repeatedSfixed32Array"]);
+  XCTAssertEqualObjects(message.repeatedSfixed64Array, [message valueForKey:@"repeatedSfixed64Array"]);
+  XCTAssertEqualObjects(message.repeatedFloatArray, [message valueForKey:@"repeatedFloatArray"]);
+  XCTAssertEqualObjects(message.repeatedDoubleArray, [message valueForKey:@"repeatedDoubleArray"]);
+  XCTAssertEqualObjects(message.repeatedBoolArray, [message valueForKey:@"repeatedBoolArray"]);
+  XCTAssertEqualObjects(message.repeatedStringArray, [message valueForKey:@"repeatedStringArray"]);
+  XCTAssertEqualObjects(message.repeatedBytesArray, [message valueForKey:@"repeatedBytesArray"]);
+
+  XCTAssertEqualObjects(message.repeatedGroupArray, [message valueForKey:@"repeatedGroupArray"]);
+  XCTAssertEqualObjects(message.repeatedNestedMessageArray, [message valueForKey:@"repeatedNestedMessageArray"]);
+  XCTAssertEqualObjects(message.repeatedForeignMessageArray, [message valueForKey:@"repeatedForeignMessageArray"]);
+  XCTAssertEqualObjects(message.repeatedImportMessageArray, [message valueForKey:@"repeatedImportMessageArray"]);
+
+  XCTAssertEqualObjects(message.repeatedNestedEnumArray, [message valueForKey:@"repeatedNestedEnumArray"]);
+  XCTAssertEqualObjects(message.repeatedForeignEnumArray, [message valueForKey:@"repeatedForeignEnumArray"]);
+  XCTAssertEqualObjects(message.repeatedImportEnumArray, [message valueForKey:@"repeatedImportEnumArray"]);
+
+  XCTAssertEqualObjects(message.repeatedStringPieceArray, [message valueForKey:@"repeatedStringPieceArray"]);
+  XCTAssertEqualObjects(message.repeatedCordArray, [message valueForKey:@"repeatedCordArray"]);
+
+  XCTAssertEqualObjects(@(message.repeatedInt32Array_Count), [message valueForKey:@"repeatedInt32Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedInt64Array_Count), [message valueForKey:@"repeatedInt64Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedUint32Array_Count), [message valueForKey:@"repeatedUint32Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedUint64Array_Count), [message valueForKey:@"repeatedUint64Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedSint32Array_Count), [message valueForKey:@"repeatedSint32Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedSint64Array_Count), [message valueForKey:@"repeatedSint64Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedFixed32Array_Count), [message valueForKey:@"repeatedFixed32Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedFixed64Array_Count), [message valueForKey:@"repeatedFixed64Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedSfixed32Array_Count), [message valueForKey:@"repeatedSfixed32Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedSfixed64Array_Count), [message valueForKey:@"repeatedSfixed64Array_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedFloatArray_Count), [message valueForKey:@"repeatedFloatArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedDoubleArray_Count), [message valueForKey:@"repeatedDoubleArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedBoolArray_Count), [message valueForKey:@"repeatedBoolArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedStringArray_Count), [message valueForKey:@"repeatedStringArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedBytesArray_Count), [message valueForKey:@"repeatedBytesArray_Count"]);
+
+  XCTAssertEqualObjects(@(message.repeatedGroupArray_Count), [message valueForKey:@"repeatedGroupArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedNestedMessageArray_Count), [message valueForKey:@"repeatedNestedMessageArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedForeignMessageArray_Count), [message valueForKey:@"repeatedForeignMessageArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedImportMessageArray_Count), [message valueForKey:@"repeatedImportMessageArray_Count"]);
+
+  XCTAssertEqualObjects(@(message.repeatedNestedEnumArray_Count), [message valueForKey:@"repeatedNestedEnumArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedForeignEnumArray_Count), [message valueForKey:@"repeatedForeignEnumArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedImportEnumArray_Count), [message valueForKey:@"repeatedImportEnumArray_Count"]);
+
+  XCTAssertEqualObjects(@(message.repeatedStringPieceArray_Count), [message valueForKey:@"repeatedStringPieceArray_Count"]);
+  XCTAssertEqualObjects(@(message.repeatedCordArray_Count), [message valueForKey:@"repeatedCordArray_Count"]);
+
+  // -----------------------------------------------------------------
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @YES);
+  XCTAssertEqualObjects(@(message.defaultInt32), [message valueForKey:@"defaultInt32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @YES);
+  XCTAssertEqualObjects(@(message.defaultInt64), [message valueForKey:@"defaultInt64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @YES);
+  XCTAssertEqualObjects(@(message.defaultUint32), [message valueForKey:@"defaultUint32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @YES);
+  XCTAssertEqualObjects(@(message.defaultUint64), [message valueForKey:@"defaultUint64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @YES);
+  XCTAssertEqualObjects(@(message.defaultSint32), [message valueForKey:@"defaultSint32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @YES);
+  XCTAssertEqualObjects(@(message.defaultSint64), [message valueForKey:@"defaultSint64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @YES);
+  XCTAssertEqualObjects(@(message.defaultFixed32), [message valueForKey:@"defaultFixed32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @YES);
+  XCTAssertEqualObjects(@(message.defaultFixed64), [message valueForKey:@"defaultFixed64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @YES);
+  XCTAssertEqualObjects(@(message.defaultSfixed32), [message valueForKey:@"defaultSfixed32"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @YES);
+  XCTAssertEqualObjects(@(message.defaultSfixed64), [message valueForKey:@"defaultSfixed64"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @YES);
+  XCTAssertEqualObjects(@(message.defaultFloat), [message valueForKey:@"defaultFloat"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @YES);
+  XCTAssertEqualObjects(@(message.defaultDouble), [message valueForKey:@"defaultDouble"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @YES);
+  XCTAssertEqualObjects(@(message.defaultBool), [message valueForKey:@"defaultBool"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @YES);
+  XCTAssertEqualObjects(message.defaultString, [message valueForKey:@"defaultString"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @YES);
+  XCTAssertEqualObjects(message.defaultBytes, [message valueForKey:@"defaultBytes"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @YES);
+  XCTAssertEqualObjects(@(message.defaultNestedEnum), [message valueForKey:@"defaultNestedEnum"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @YES);
+  XCTAssertEqualObjects(@(message.defaultForeignEnum), [message valueForKey:@"defaultForeignEnum"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @YES);
+  XCTAssertEqualObjects(@(message.defaultImportEnum), [message valueForKey:@"defaultImportEnum"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @YES);
+  XCTAssertEqualObjects(message.defaultStringPiece, [message valueForKey:@"defaultStringPiece"]);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @YES);
+  XCTAssertEqualObjects(message.defaultCord, [message valueForKey:@"defaultCord"]);
+}
+
+- (void)setAllFieldsViaKVC:(TestAllTypes *)message
+             repeatedCount:(uint32_t)count {
+  [message setValue:@101 forKey:@"optionalInt32"];
+  [message setValue:@102 forKey:@"optionalInt64"];
+  [message setValue:@103 forKey:@"optionalUint32"];
+  [message setValue:@104 forKey:@"optionalUint64"];
+  [message setValue:@105 forKey:@"optionalSint32"];
+  [message setValue:@106 forKey:@"optionalSint64"];
+  [message setValue:@107 forKey:@"optionalFixed32"];
+  [message setValue:@108 forKey:@"optionalFixed64"];
+  [message setValue:@109 forKey:@"optionalSfixed32"];
+  [message setValue:@110 forKey:@"optionalSfixed64"];
+  [message setValue:@111 forKey:@"optionalFloat"];
+  [message setValue:@112 forKey:@"optionalDouble"];
+  [message setValue:@YES forKey:@"optionalBool"];
+  [message setValue:@"115" forKey:@"optionalString"];
+  [message setValue:[NSData gpbtu_dataWithEmbeddedNulls]
+             forKey:@"optionalBytes"];
+
+  TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message];
+  [allTypes setValue:@117 forKey:@"a"];
+  [message setValue:allTypes forKey:@"optionalGroup"];
+  TestAllTypes_NestedMessage *nestedMessage =
+      [TestAllTypes_NestedMessage message];
+  [nestedMessage setValue:@118 forKey:@"bb"];
+  [message setValue:nestedMessage forKey:@"optionalNestedMessage"];
+  ForeignMessage *foreignMessage = [ForeignMessage message];
+  [foreignMessage setValue:@119 forKey:@"c"];
+  [message setValue:foreignMessage forKey:@"optionalForeignMessage"];
+  ImportMessage *importMessage = [ImportMessage message];
+  [importMessage setValue:@120 forKey:@"d"];
+  [message setValue:importMessage forKey:@"optionalImportMessage"];
+
+  [message setValue:@(TestAllTypes_NestedEnum_Baz)
+             forKey:@"optionalNestedEnum"];
+  [message setValue:@(ForeignEnum_ForeignBaz) forKey:@"optionalForeignEnum"];
+  [message setValue:@(ImportEnum_ImportBaz) forKey:@"optionalImportEnum"];
+
+  [message setValue:@"124" forKey:@"optionalStringPiece"];
+  [message setValue:@"125" forKey:@"optionalCord"];
+
+  // -----------------------------------------------------------------
+
+  {
+    GPBInt32Array *scratch = [GPBInt32Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:201 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedInt32Array"];
+  }
+  {
+    GPBInt64Array *scratch = [GPBInt64Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:202 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedInt64Array"];
+  }
+  {
+    GPBUInt32Array *scratch = [GPBUInt32Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:203 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedUint32Array"];
+  }
+  {
+    GPBUInt64Array *scratch = [GPBUInt64Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:204 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedUint64Array"];
+  }
+  {
+    GPBInt32Array *scratch = [GPBInt32Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:205 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedSint32Array"];
+  }
+  {
+    GPBInt64Array *scratch = [GPBInt64Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:206 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedSint64Array"];
+  }
+  {
+    GPBUInt32Array *scratch = [GPBUInt32Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:207 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedFixed32Array"];
+  }
+  {
+    GPBUInt64Array *scratch = [GPBUInt64Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:208 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedFixed64Array"];
+  }
+  {
+    GPBInt32Array *scratch = [GPBInt32Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:209 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedSfixed32Array"];
+  }
+  {
+    GPBInt64Array *scratch = [GPBInt64Array array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:210 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedSfixed64Array"];
+  }
+  {
+    GPBFloatArray *scratch = [GPBFloatArray array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:211 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedFloatArray"];
+  }
+  {
+    GPBDoubleArray *scratch = [GPBDoubleArray array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:212 + i * 100];
+    }
+    [message setValue:scratch forKey:@"repeatedDoubleArray"];
+  }
+  {
+    GPBBoolArray *scratch = [GPBBoolArray array];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:(i % 2) ? YES : NO];
+    }
+    [message setValue:scratch forKey:@"repeatedBoolArray"];
+  }
+
+  NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100];
+    [array addObject:string];
+    [string release];
+  }
+  [message setValue:array forKey:@"repeatedStringArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100];
+    [array addObject:data];
+    [data release];
+  }
+  [message setValue:array forKey:@"repeatedBytesArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    TestAllTypes_RepeatedGroup *testAll =
+        [[TestAllTypes_RepeatedGroup alloc] init];
+    [testAll setA:217 + i * 100];
+    [array addObject:testAll];
+    [testAll release];
+  }
+  [message setValue:array forKey:@"repeatedGroupArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
+    [nestedMessage setBb:218 + i * 100];
+    [array addObject:nestedMessage];
+    [nestedMessage release];
+  }
+  [message setValue:array forKey:@"repeatedNestedMessageArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    foreignMessage = [[ForeignMessage alloc] init];
+    [foreignMessage setC:219 + i * 100];
+    [array addObject:foreignMessage];
+    [foreignMessage release];
+  }
+  [message setValue:array forKey:@"repeatedForeignMessageArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    importMessage = [[ImportMessage alloc] init];
+    [importMessage setD:220 + i * 100];
+    [array addObject:importMessage];
+    [importMessage release];
+  }
+  [message setValue:array forKey:@"repeatedImportMessageArray"];
+  [array release];
+
+  {
+    GPBEnumArray *scratch = [GPBEnumArray
+        arrayWithValidationFunction:TestAllTypes_NestedEnum_IsValidValue];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar
+                                : TestAllTypes_NestedEnum_Baz];
+    }
+    [message setValue:scratch forKey:@"repeatedNestedEnumArray"];
+  }
+  {
+    GPBEnumArray *scratch =
+        [GPBEnumArray arrayWithValidationFunction:ForeignEnum_IsValidValue];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch
+          addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz];
+    }
+    [message setValue:scratch forKey:@"repeatedForeignEnumArray"];
+  }
+  {
+    GPBEnumArray *scratch =
+        [GPBEnumArray arrayWithValidationFunction:ImportEnum_IsValidValue];
+    for (uint32_t i = 0; i < count; ++i) {
+      [scratch addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz];
+    }
+    [message setValue:scratch forKey:@"repeatedImportEnumArray"];
+  }
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100];
+    [array addObject:string];
+    [string release];
+  }
+  [message setValue:array forKey:@"repeatedStringPieceArray"];
+  [array release];
+
+  array = [[NSMutableArray alloc] initWithCapacity:count];
+  for (uint32_t i = 0; i < count; ++i) {
+    NSString *string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100];
+    [array addObject:string];
+    [string release];
+  }
+  [message setValue:array forKey:@"repeatedCordArray"];
+  [array release];
+
+  // -----------------------------------------------------------------
+
+  [message setValue:@401 forKey:@"defaultInt32"];
+  [message setValue:@402 forKey:@"defaultInt64"];
+  [message setValue:@403 forKey:@"defaultUint32"];
+  [message setValue:@404 forKey:@"defaultUint64"];
+  [message setValue:@405 forKey:@"defaultSint32"];
+  [message setValue:@406 forKey:@"defaultSint64"];
+  [message setValue:@407 forKey:@"defaultFixed32"];
+  [message setValue:@408 forKey:@"defaultFixed64"];
+  [message setValue:@409 forKey:@"defaultSfixed32"];
+  [message setValue:@410 forKey:@"defaultSfixed64"];
+  [message setValue:@411 forKey:@"defaultFloat"];
+  [message setValue:@412 forKey:@"defaultDouble"];
+  [message setValue:@NO forKey:@"defaultBool"];
+  [message setValue:@"415" forKey:@"defaultString"];
+  [message setValue:[NSData gpbtu_dataWithUint32:416] forKey:@"defaultBytes"];
+
+  [message setValue:@(TestAllTypes_NestedEnum_Foo) forKey:@"defaultNestedEnum"];
+  [message setValue:@(ForeignEnum_ForeignFoo) forKey:@"defaultForeignEnum"];
+  [message setValue:@(ImportEnum_ImportFoo) forKey:@"defaultImportEnum"];
+
+  [message setValue:@"424" forKey:@"defaultStringPiece"];
+  [message setValue:@"425" forKey:@"defaultCord"];
+}
+
+- (void)assertClearKVC:(TestAllTypes *)message {
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @NO);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"],
+                        @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @NO);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @NO);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @NO);
+
+  // Optional fields without defaults are set to zero or something like it.
+  XCTAssertEqualObjects([message valueForKey:@"optionalInt32"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalInt64"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalUint32"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalUint64"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalSint32"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalSint64"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalFixed32"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalFixed64"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalSfixed32"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalSfixed64"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalFloat"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalDouble"], @0);
+  XCTAssertEqualObjects([message valueForKey:@"optionalBool"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"optionalString"], @"");
+  XCTAssertEqualObjects([message valueForKey:@"optionalBytes"],
+                        GPBEmptyNSData());
+
+  // Embedded messages should also be exist, but be clear.
+  XCTAssertNotNil([message valueForKeyPath:@"optionalGroup"]);
+  XCTAssertNotNil([message valueForKeyPath:@"optionalNestedMessage"]);
+  XCTAssertNotNil([message valueForKeyPath:@"optionalForeignMessage"]);
+  XCTAssertNotNil([message valueForKeyPath:@"optionalImportMessage"]);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @NO);
+  XCTAssertEqualObjects(
+      [message valueForKeyPath:@"optionalNestedMessage.hasBb"], @NO);
+  XCTAssertEqualObjects(
+      [message valueForKeyPath:@"optionalForeignMessage.hasC"], @NO);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"],
+                        @NO);
+
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.a"], @0);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.bb"],
+                        @0);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.c"],
+                        @0);
+  XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.d"],
+                        @0);
+
+  // Enums without defaults are set to the first value in the enum.
+  XCTAssertEqualObjects([message valueForKey:@"optionalNestedEnum"],
+                        @(TestAllTypes_NestedEnum_Foo));
+  XCTAssertEqualObjects([message valueForKey:@"optionalForeignEnum"],
+                        @(ForeignEnum_ForeignFoo));
+  XCTAssertEqualObjects([message valueForKey:@"optionalImportEnum"],
+                        @(ImportEnum_ImportFoo));
+
+  XCTAssertEqualObjects([message valueForKey:@"optionalStringPiece"], @"");
+  XCTAssertEqualObjects([message valueForKey:@"optionalCord"], @"");
+
+  // NSArray interface for repeated doesn't have has*, nil means no value.
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @NO);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @NO);
+
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @NO);
+  XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @NO);
+
+  // Fields with defaults have their default values (duh).
+  XCTAssertEqualObjects([message valueForKey:@"defaultInt32"], @41);
+  XCTAssertEqualObjects([message valueForKey:@"defaultInt64"], @42);
+  XCTAssertEqualObjects([message valueForKey:@"defaultUint32"], @43);
+  XCTAssertEqualObjects([message valueForKey:@"defaultUint64"], @44);
+  XCTAssertEqualObjects([message valueForKey:@"defaultSint32"], @-45);
+  XCTAssertEqualObjects([message valueForKey:@"defaultSint64"], @46);
+  XCTAssertEqualObjects([message valueForKey:@"defaultFixed32"], @47);
+  XCTAssertEqualObjects([message valueForKey:@"defaultFixed64"], @48);
+  XCTAssertEqualObjects([message valueForKey:@"defaultSfixed32"], @49);
+  XCTAssertEqualObjects([message valueForKey:@"defaultSfixed64"], @-50);
+  XCTAssertEqualObjects([message valueForKey:@"defaultFloat"], @51.5);
+  XCTAssertEqualObjects([message valueForKey:@"defaultDouble"], @52e3);
+  XCTAssertEqualObjects([message valueForKey:@"defaultBool"], @YES);
+  XCTAssertEqualObjects([message valueForKey:@"defaultString"], @"hello");
+  XCTAssertEqualObjects([message valueForKey:@"defaultBytes"],
+                        [NSData gpbtu_dataWithCString:"world"]);
+
+  XCTAssertEqualObjects([message valueForKey:@"defaultNestedEnum"],
+                        @(TestAllTypes_NestedEnum_Bar));
+  XCTAssertEqualObjects([message valueForKey:@"defaultForeignEnum"],
+                        @(ForeignEnum_ForeignBar));
+  XCTAssertEqualObjects([message valueForKey:@"defaultImportEnum"],
+                        @(ImportEnum_ImportBar));
+
+  XCTAssertEqualObjects([message valueForKey:@"defaultStringPiece"], @"abc");
+  XCTAssertEqualObjects([message valueForKey:@"defaultCord"], @"123");
+}
+
+@end
diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m
new file mode 100644
index 0000000..d19beee
--- /dev/null
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -0,0 +1,64 @@
+// 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.
+
+// Collects all the compiled protos into one file and compiles them to make sure
+// the compiler is generating valid code.
+
+// The unittest_custom_options.proto extends the messages in descriptor.proto
+// so we build it in to test extending in general. The library doesn't provide
+// a descriptor as it doesn't use the classes/enums.
+#import "google/protobuf/Descriptor.pbobjc.m"
+
+#import "google/protobuf/MapProto2Unittest.pbobjc.m"
+#import "google/protobuf/MapUnittest.pbobjc.m"
+#import "google/protobuf/Unittest.pbobjc.m"
+#import "google/protobuf/UnittestArena.pbobjc.m"
+#import "google/protobuf/UnittestCustomOptions.pbobjc.m"
+#import "google/protobuf/UnittestCycle.pbobjc.m"
+#import "google/protobuf/UnittestDropUnknownFields.pbobjc.m"
+#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.m"
+#import "google/protobuf/UnittestEmpty.pbobjc.m"
+#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.m"
+#import "google/protobuf/UnittestImport.pbobjc.m"
+#import "google/protobuf/UnittestImportLite.pbobjc.m"
+#import "google/protobuf/UnittestImportPublic.pbobjc.m"
+#import "google/protobuf/UnittestImportPublicLite.pbobjc.m"
+#import "google/protobuf/UnittestLite.pbobjc.m"
+#import "google/protobuf/UnittestMset.pbobjc.m"
+#import "google/protobuf/UnittestMsetWireFormat.pbobjc.m"
+#import "google/protobuf/UnittestNoArena.pbobjc.m"
+#import "google/protobuf/UnittestNoArenaImport.pbobjc.m"
+#import "google/protobuf/UnittestNoGenericServices.pbobjc.m"
+#import "google/protobuf/UnittestObjc.pbobjc.m"
+#import "google/protobuf/UnittestObjcStartup.pbobjc.m"
+#import "google/protobuf/UnittestOptimizeFor.pbobjc.m"
+#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m"
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.m"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.m"
diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m
new file mode 100644
index 0000000..01217ca
--- /dev/null
+++ b/objectivec/Tests/GPBUnknownFieldSetTest.m
@@ -0,0 +1,259 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import "GPBUnknownField_PackagePrivate.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+
+@interface GPBUnknownFieldSet (GPBUnknownFieldSetTest)
+- (void)getTags:(int32_t*)tags;
+@end
+
+@interface UnknownFieldSetTest : GPBTestCase {
+ @private
+  TestAllTypes* allFields_;
+  NSData* allFieldsData_;
+
+  // An empty message that has been parsed from allFieldsData.  So, it has
+  // unknown fields of every type.
+  TestEmptyMessage* emptyMessage_;
+  GPBUnknownFieldSet* unknownFields_;
+}
+
+@end
+
+@implementation UnknownFieldSetTest
+
+- (void)setUp {
+  allFields_ = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+  allFieldsData_ = [allFields_ data];
+  emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_ error:NULL];
+  unknownFields_ = emptyMessage_.unknownFields;
+}
+
+- (GPBUnknownField *)getField:(int32_t)number {
+  return [unknownFields_ getField:number];
+}
+
+// Constructs a protocol buffer which contains fields with all the same
+// numbers as allFieldsData except that each field is some other wire
+// type.
+- (NSData*)getBizarroData {
+  GPBUnknownFieldSet* bizarroFields =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  NSUInteger count = [unknownFields_ countOfFields];
+  int32_t tags[count];
+  [unknownFields_ getTags:tags];
+  for (NSUInteger i = 0; i < count; ++i) {
+    int32_t tag = tags[i];
+    GPBUnknownField* field = [unknownFields_ getField:tag];
+    if (field.varintList.count == 0) {
+      // Original field is not a varint, so use a varint.
+      GPBUnknownField* varintField =
+          [[[GPBUnknownField alloc] initWithNumber:tag] autorelease];
+      [varintField addVarint:1];
+      [bizarroFields addField:varintField];
+    } else {
+      // Original field *is* a varint, so use something else.
+      GPBUnknownField* fixed32Field =
+          [[[GPBUnknownField alloc] initWithNumber:tag] autorelease];
+      [fixed32Field addFixed32:1];
+      [bizarroFields addField:fixed32Field];
+    }
+  }
+
+  return [bizarroFields data];
+}
+
+- (void)testSerialize {
+  // Check that serializing the UnknownFieldSet produces the original data
+  // again.
+  NSData* data = [emptyMessage_ data];
+  XCTAssertEqualObjects(allFieldsData_, data);
+}
+
+- (void)testCopyFrom {
+  TestEmptyMessage* message = [TestEmptyMessage message];
+  [message mergeFrom:emptyMessage_];
+
+  XCTAssertEqualObjects(emptyMessage_.data, message.data);
+}
+
+- (void)testMergeFrom {
+  GPBUnknownFieldSet* set1 = [[[GPBUnknownFieldSet alloc] init] autorelease];
+  GPBUnknownField* field = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
+  [field addVarint:2];
+  [set1 addField:field];
+  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
+  [field addVarint:4];
+  [set1 addField:field];
+
+  GPBUnknownFieldSet* set2 = [[[GPBUnknownFieldSet alloc] init] autorelease];
+  field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
+  [field addVarint:1];
+  [set2 addField:field];
+  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
+  [field addVarint:3];
+  [set2 addField:field];
+
+  GPBUnknownFieldSet* set3 = [[[GPBUnknownFieldSet alloc] init] autorelease];
+  field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
+  [field addVarint:1];
+  [set3 addField:field];
+  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
+  [field addVarint:4];
+  [set3 addField:field];
+
+  GPBUnknownFieldSet* set4 = [[[GPBUnknownFieldSet alloc] init] autorelease];
+  field = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
+  [field addVarint:2];
+  [set4 addField:field];
+  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
+  [field addVarint:3];
+  [set4 addField:field];
+
+  TestEmptyMessage* source1 = [TestEmptyMessage message];
+  [source1 setUnknownFields:set1];
+  TestEmptyMessage* source2 = [TestEmptyMessage message];
+  [source2 setUnknownFields:set2];
+  TestEmptyMessage* source3 = [TestEmptyMessage message];
+  [source3 setUnknownFields:set3];
+  TestEmptyMessage* source4 = [TestEmptyMessage message];
+  [source4 setUnknownFields:set4];
+
+  TestEmptyMessage* destination1 = [TestEmptyMessage message];
+  [destination1 mergeFrom:source1];
+  [destination1 mergeFrom:source2];
+
+  TestEmptyMessage* destination2 = [TestEmptyMessage message];
+  [destination2 mergeFrom:source3];
+  [destination2 mergeFrom:source4];
+
+  XCTAssertEqualObjects(destination1.data, destination2.data);
+}
+
+- (void)testClearMessage {
+  TestEmptyMessage *message = [TestEmptyMessage message];
+  [message mergeFrom:emptyMessage_];
+  [message clear];
+  XCTAssertEqual(message.serializedSize, (size_t)0);
+}
+
+- (void)testParseKnownAndUnknown {
+  // Test mixing known and unknown fields when parsing.
+  GPBUnknownFieldSet *fields = [[unknownFields_ copy] autorelease];
+  GPBUnknownField *field =
+    [[[GPBUnknownField alloc] initWithNumber:123456] autorelease];
+  [field addVarint:654321];
+  [fields addField:field];
+
+  NSData* data = fields.data;
+  TestAllTypes* destination = [TestAllTypes parseFromData:data error:NULL];
+
+  [self assertAllFieldsSet:destination repeatedCount:kGPBDefaultRepeatCount];
+  XCTAssertEqual(destination.unknownFields.countOfFields, (NSUInteger)1);
+
+  GPBUnknownField* field2 = [destination.unknownFields getField:123456];
+  XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
+  XCTAssertEqual(654321ULL, [field2.varintList valueAtIndex:0]);
+}
+
+- (void)testWrongTypeTreatedAsUnknown {
+  // Test that fields of the wrong wire type are treated like unknown fields
+  // when parsing.
+
+  NSData* bizarroData = [self getBizarroData];
+  TestAllTypes* allTypesMessage =
+      [TestAllTypes parseFromData:bizarroData error:NULL];
+  TestEmptyMessage* emptyMessage =
+      [TestEmptyMessage parseFromData:bizarroData error:NULL];
+
+  // All fields should have been interpreted as unknown, so the debug strings
+  // should be the same.
+  XCTAssertEqualObjects(emptyMessage.data, allTypesMessage.data);
+}
+
+- (void)testUnknownExtensions {
+  // Make sure fields are properly parsed to the UnknownFieldSet even when
+  // they are declared as extension numbers.
+
+  TestEmptyMessageWithExtensions* message =
+      [TestEmptyMessageWithExtensions parseFromData:allFieldsData_ error:NULL];
+
+  XCTAssertEqual(unknownFields_.countOfFields,
+                 message.unknownFields.countOfFields);
+  XCTAssertEqualObjects(allFieldsData_, message.data);
+}
+
+- (void)testWrongExtensionTypeTreatedAsUnknown {
+  // Test that fields of the wrong wire type are treated like unknown fields
+  // when parsing extensions.
+
+  NSData* bizarroData = [self getBizarroData];
+  TestAllExtensions* allExtensionsMessage =
+      [TestAllExtensions parseFromData:bizarroData error:NULL];
+  TestEmptyMessage* emptyMessage =
+      [TestEmptyMessage parseFromData:bizarroData error:NULL];
+
+  // All fields should have been interpreted as unknown, so the debug strings
+  // should be the same.
+  XCTAssertEqualObjects(emptyMessage.data, allExtensionsMessage.data);
+}
+
+- (void)testLargeVarint {
+  GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease];
+  GPBUnknownField* field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
+  [field addVarint:0x7FFFFFFFFFFFFFFFL];
+  [fields addField:field];
+
+  NSData* data = [fields data];
+
+  GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease];
+  [parsed mergeFromData:data];
+  GPBUnknownField* field2 = [parsed getField:1];
+  XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
+  XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]);
+}
+
+- (void)testMergingFields {
+  GPBUnknownField* field1 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
+  [field1 addVarint:1];
+  [field1 addFixed32:2];
+  [field1 addFixed64:3];
+  [field1 addLengthDelimited:[NSData dataWithBytes:"hello" length:5]];
+  [field1 addGroup:[[unknownFields_ copy] autorelease]];
+  GPBUnknownField* field2 = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
+  [field2 mergeFromField:field1];
+  XCTAssertEqualObjects(field1, field2);
+}
+
+@end
diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m
new file mode 100644
index 0000000..ba1fc27
--- /dev/null
+++ b/objectivec/Tests/GPBUtilitiesTests.m
@@ -0,0 +1,173 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <XCTest/XCTest.h>
+
+#import "GPBUtilities_PackagePrivate.h"
+
+#import <objc/runtime.h>
+
+#import "GPBTestUtilities.h"
+
+#import "GPBDescriptor.h"
+#import "GPBDescriptor_PackagePrivate.h"
+#import "GPBMessage.h"
+
+#import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+
+@interface UtilitiesTests : GPBTestCase
+@end
+
+@implementation UtilitiesTests
+
+- (void)testRightShiftFunctions {
+  XCTAssertEqual((1UL << 31) >> 31, 1UL);
+  XCTAssertEqual((1 << 31) >> 31, -1);
+  XCTAssertEqual((1ULL << 63) >> 63, 1ULL);
+  XCTAssertEqual((1LL << 63) >> 63, -1LL);
+
+  XCTAssertEqual(GPBLogicalRightShift32((1 << 31), 31), 1);
+  XCTAssertEqual(GPBLogicalRightShift64((1LL << 63), 63), 1LL);
+}
+
+- (void)testGPBDecodeTextFormatName {
+  uint8_t decodeData[] = {
+    0x6,
+    // An inlined string (first to make sure the leading null is handled
+    // correctly, and with a key of zero to check that).
+    0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
+    // All as is (00 op)
+    0x1, 0x0A, 0x0,
+    // Underscore, upper + 9 (10 op)
+    0x3, 0xCA, 0x0,
+    //  Upper + 3 (10 op), underscore, upper + 5 (10 op)
+    0x2, 0x44, 0xC6, 0x0,
+    // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op),
+    // underscore, lower + 0 (01 op)
+    0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0,
+    // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op),
+    //   underscore, lower + 3 (01 op), underscore, lower + 1 (01 op),
+    //   underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op),
+    //   underscore, as is + 3 (00 op)
+    0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0,
+  };
+  NSString *inputStr = @"abcdefghIJ";
+
+  // Empty inputs
+
+  XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL));
+  XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL));
+  XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr));
+
+  // Keys not found.
+
+  XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr));
+  XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr));
+
+  // Some name decodes.
+
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ");
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ");
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ");
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j");
+
+  // An inlined string (and key of zero).
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ");
+
+  // Long name so multiple decode ops are needed.
+  inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000";
+  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr),
+                        @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000");
+}
+
+- (void)testTextFormat {
+  TestAllTypes *message = [TestAllTypes message];
+
+  // Not kGPBDefaultRepeatCount because we are comparing to golden master file
+  // which was generated with 2.
+  [self setAllFields:message repeatedCount:2];
+
+  NSString *result = GPBTextFormatForMessage(message, nil);
+
+  NSString *fileName = @"text_format_unittest_data.txt";
+  NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
+  NSData *expectedData =
+      [self getDataFileNamed:fileName dataToWrite:resultData];
+  NSString *expected = [[NSString alloc] initWithData:expectedData
+                                             encoding:NSUTF8StringEncoding];
+  XCTAssertEqualObjects(expected, result);
+  [expected release];
+}
+
+- (void)testTextFormatExtra {
+  // -testTextFormat uses all protos with fields that don't require special
+  // handing for figuring out the names.  The ObjC proto has a bunch of oddball
+  // field and enum names that require the decode info to get right, so this
+  // confirms they generated and decoded correctly.
+
+  self_Class *message = [self_Class message];
+  message.cmd = YES;
+  message.isProxy_p = YES;
+  message.subEnum = self_autorelease_RetainCount;
+  message.new_p.copy_p = @"foo";
+
+  NSString *expected = @"_cmd: true\n"
+                       @"isProxy: true\n"
+                       @"SubEnum: retainCount\n"
+                       @"New {\n"
+                       @"  copy: \"foo\"\n"
+                       @"}\n";
+  NSString *result = GPBTextFormatForMessage(message, nil);
+  XCTAssertEqualObjects(expected, result);
+}
+
+- (void)testTextFormatMaps {
+  TestMap *message = [TestMap message];
+
+  // Map iteration order doesn't have to be stable, so use only one entry.
+  [self setAllMapFields:message numEntries:1];
+
+  NSString *result = GPBTextFormatForMessage(message, nil);
+
+  NSString *fileName = @"text_format_map_unittest_data.txt";
+  NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
+  NSData *expectedData =
+      [self getDataFileNamed:fileName dataToWrite:resultData];
+  NSString *expected = [[NSString alloc] initWithData:expectedData
+                                             encoding:NSUTF8StringEncoding];
+  XCTAssertEqualObjects(expected, result);
+  [expected release];
+}
+
+// TODO(thomasvl): add test with extensions once those format with correct names.
+
+@end
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
new file mode 100644
index 0000000..78f4e63
--- /dev/null
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -0,0 +1,102 @@
+// 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.
+
+#import "GPBWellKnownTypes.h"
+
+#import <XCTest/XCTest.h>
+
+// A basically random interval into the future for testing with.
+static const NSTimeInterval kFutureOffsetInterval = 15000;
+
+// Nanosecond time accuracy
+static const NSTimeInterval kTimeAccuracy = 1e-9;
+
+@interface WellKnownTypesTest : XCTestCase
+@end
+
+@implementation WellKnownTypesTest
+
+- (void)testTimeStamp {
+  // Test Creation.
+  NSDate *date = [NSDate date];
+  GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date];
+  NSDate *timeStampDate = timeStamp.date;
+
+  // Comparing timeIntervals instead of directly comparing dates because date
+  // equality requires the time intervals to be exactly the same, and the
+  // timeintervals go through a bit of floating point error as they are
+  // converted back and forth from the internal representation.
+  XCTAssertEqualWithAccuracy(date.timeIntervalSince1970,
+                             timeStampDate.timeIntervalSince1970,
+                             kTimeAccuracy);
+
+  NSTimeInterval time = [date timeIntervalSince1970];
+  GPBTimestamp *timeStamp2 =
+      [[GPBTimestamp alloc] initWithTimeIntervalSince1970:time];
+  NSTimeInterval durationTime = timeStamp2.timeIntervalSince1970;
+  XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
+  [timeStamp release];
+
+  // Test Mutation.
+  date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval];
+  timeStamp2.date = date;
+  timeStampDate = timeStamp2.date;
+  XCTAssertEqualWithAccuracy(date.timeIntervalSince1970,
+                             timeStampDate.timeIntervalSince1970,
+                             kTimeAccuracy);
+
+  time = date.timeIntervalSince1970;
+  timeStamp2.timeIntervalSince1970 = time;
+  durationTime = timeStamp2.timeIntervalSince1970;
+  XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
+  [timeStamp2 release];
+}
+
+- (void)testDuration {
+  // Test Creation.
+  NSTimeInterval time = [[NSDate date] timeIntervalSince1970];
+  GPBDuration *duration =
+      [[GPBDuration alloc] initWithTimeIntervalSince1970:time];
+  NSTimeInterval durationTime = duration.timeIntervalSince1970;
+  XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
+  [duration release];
+
+  // Test Mutation.
+  GPBDuration *duration2 =
+      [[GPBDuration alloc] initWithTimeIntervalSince1970:time];
+  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval];
+  time = date.timeIntervalSince1970;
+  duration2.timeIntervalSince1970 = time;
+  durationTime = duration2.timeIntervalSince1970;
+  XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
+  [duration2 release];
+}
+
+@end
diff --git a/objectivec/Tests/GPBWireFormatTests.m b/objectivec/Tests/GPBWireFormatTests.m
new file mode 100644
index 0000000..2a406f1
--- /dev/null
+++ b/objectivec/Tests/GPBWireFormatTests.m
@@ -0,0 +1,252 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import "GPBCodedInputStream.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUnknownField_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestMset.pbobjc.h"
+#import "google/protobuf/UnittestMsetWireFormat.pbobjc.h"
+
+@interface WireFormatTests : GPBTestCase
+@end
+
+@implementation WireFormatTests
+
+- (void)testSerialization {
+  TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+
+  NSData* rawBytes = message.data;
+  XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
+
+  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes error:NULL];
+
+  [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testSerializationPacked {
+  TestPackedTypes* message =
+      [self packedSetRepeatedCount:kGPBDefaultRepeatCount];
+
+  NSData* rawBytes = message.data;
+  XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
+
+  TestPackedTypes* message2 =
+      [TestPackedTypes parseFromData:rawBytes error:NULL];
+
+  [self assertPackedFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testSerializeExtensions {
+  // TestAllTypes and TestAllExtensions should have compatible wire formats,
+  // so if we serealize a TestAllExtensions then parse it as TestAllTypes
+  // it should work.
+
+  TestAllExtensions* message =
+      [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes = message.data;
+  XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
+
+  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes error:NULL];
+
+  [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testSerializePackedExtensions {
+  // TestPackedTypes and TestPackedExtensions should have compatible wire
+  // formats; check that they serialize to the same string.
+  TestPackedExtensions* message =
+      [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes = message.data;
+
+  TestPackedTypes* message2 =
+      [self packedSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes2 = message2.data;
+
+  XCTAssertEqualObjects(rawBytes, rawBytes2);
+}
+
+- (void)testParseExtensions {
+  // TestAllTypes and TestAllExtensions should have compatible wire formats,
+  // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+  // it should work.
+
+  TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes = message.data;
+
+  GPBExtensionRegistry* registry = [self extensionRegistry];
+
+  TestAllExtensions* message2 = [TestAllExtensions parseFromData:rawBytes
+                                               extensionRegistry:registry
+                                                           error:NULL];
+
+  [self assertAllExtensionsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
+}
+
+
+- (void) testExtensionsSerializedSize {
+  size_t allSet = [self allSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize;
+  size_t extensionSet = [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize;
+  XCTAssertEqual(allSet, extensionSet);
+}
+
+- (void)testParsePackedExtensions {
+  // Ensure that packed extensions can be properly parsed.
+  TestPackedExtensions* message =
+      [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount];
+  NSData* rawBytes = message.data;
+
+  GPBExtensionRegistry* registry = [self extensionRegistry];
+
+  TestPackedExtensions* message2 = [TestPackedExtensions parseFromData:rawBytes
+                                                     extensionRegistry:registry
+                                                                 error:NULL];
+
+  [self assertPackedExtensionsSet:message2
+                    repeatedCount:kGPBDefaultRepeatCount];
+}
+
+const int kUnknownTypeId = 1550055;
+
+- (void)testSerializeMessageSet {
+  // Set up a TestMessageSet with two known messages and an unknown one.
+  TestMessageSet* message_set = [TestMessageSet message];
+  [[message_set getExtension:[TestMessageSetExtension1 messageSetExtension]]
+      setI:123];
+  [[message_set getExtension:[TestMessageSetExtension2 messageSetExtension]]
+      setStr:@"foo"];
+  GPBUnknownField* unknownField =
+      [[[GPBUnknownField alloc] initWithNumber:kUnknownTypeId] autorelease];
+  [unknownField addLengthDelimited:[NSData dataWithBytes:"bar" length:3]];
+  GPBUnknownFieldSet* unknownFieldSet =
+      [[[GPBUnknownFieldSet alloc] init] autorelease];
+  [unknownFieldSet addField:unknownField];
+  [message_set setUnknownFields:unknownFieldSet];
+
+  NSData* data = [message_set data];
+
+  // Parse back using RawMessageSet and check the contents.
+  RawMessageSet* raw = [RawMessageSet parseFromData:data error:NULL];
+
+  XCTAssertEqual([raw.unknownFields countOfFields], (NSUInteger)0);
+
+  XCTAssertEqual(raw.itemArray.count, (NSUInteger)3);
+  XCTAssertEqual((uint32_t)[raw.itemArray[0] typeId],
+                 [TestMessageSetExtension1 messageSetExtension].fieldNumber);
+  XCTAssertEqual((uint32_t)[raw.itemArray[1] typeId],
+                 [TestMessageSetExtension2 messageSetExtension].fieldNumber);
+  XCTAssertEqual([raw.itemArray[2] typeId], kUnknownTypeId);
+
+  TestMessageSetExtension1* message1 =
+      [TestMessageSetExtension1 parseFromData:[((RawMessageSet_Item*)raw.itemArray[0]) message]
+                                        error:NULL];
+  XCTAssertEqual(message1.i, 123);
+
+  TestMessageSetExtension2* message2 =
+      [TestMessageSetExtension2 parseFromData:[((RawMessageSet_Item*)raw.itemArray[1]) message]
+                                        error:NULL];
+  XCTAssertEqualObjects(message2.str, @"foo");
+
+  XCTAssertEqualObjects([raw.itemArray[2] message],
+                        [NSData dataWithBytes:"bar" length:3]);
+}
+
+- (void)testParseMessageSet {
+  // Set up a RawMessageSet with two known messages and an unknown one.
+  RawMessageSet* raw = [RawMessageSet message];
+
+  {
+    RawMessageSet_Item* item = [RawMessageSet_Item message];
+    item.typeId = [TestMessageSetExtension1 messageSetExtension].fieldNumber;
+    TestMessageSetExtension1* message = [TestMessageSetExtension1 message];
+    message.i = 123;
+    item.message = [message data];
+    [raw.itemArray addObject:item];
+  }
+
+  {
+    RawMessageSet_Item* item = [RawMessageSet_Item message];
+    item.typeId = [TestMessageSetExtension2 messageSetExtension].fieldNumber;
+    TestMessageSetExtension2* message = [TestMessageSetExtension2 message];
+    message.str = @"foo";
+    item.message = [message data];
+    [raw.itemArray addObject:item];
+  }
+
+  {
+    RawMessageSet_Item* item = [RawMessageSet_Item message];
+    item.typeId = kUnknownTypeId;
+    item.message = [NSData dataWithBytes:"bar" length:3];
+    [raw.itemArray addObject:item];
+  }
+
+  NSData* data = [raw data];
+
+  // Parse as a TestMessageSet and check the contents.
+  TestMessageSet* messageSet =
+      [TestMessageSet parseFromData:data
+                  extensionRegistry:[UnittestMsetRoot extensionRegistry]
+                              error:NULL];
+
+  XCTAssertEqual(
+      [[messageSet
+          getExtension:[TestMessageSetExtension1 messageSetExtension]] i],
+      123);
+  XCTAssertEqualObjects(
+      [[messageSet
+          getExtension:[TestMessageSetExtension2 messageSetExtension]] str],
+      @"foo");
+
+  XCTAssertEqual([messageSet.unknownFields countOfFields], (NSUInteger)1);
+  GPBUnknownField* unknownField = [messageSet.unknownFields getField:kUnknownTypeId];
+  XCTAssertNotNil(unknownField);
+  XCTAssertEqual(unknownField.lengthDelimitedList.count, (NSUInteger)1);
+  XCTAssertEqualObjects(unknownField.lengthDelimitedList[0],
+                        [NSData dataWithBytes:"bar" length:3]);
+}
+
+- (void)assertFieldsInOrder:(NSData*)data {
+  GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
+  int32_t previousTag = 0;
+
+  while (YES) {
+    int32_t tag = [input readTag];
+    if (tag == 0) {
+      break;
+    }
+
+    XCTAssertGreaterThan(tag, previousTag);
+    [input skipField:tag];
+  }
+}
+
+@end
diff --git a/objectivec/Tests/UnitTests-Bridging-Header.h b/objectivec/Tests/UnitTests-Bridging-Header.h
new file mode 100644
index 0000000..46292fc
--- /dev/null
+++ b/objectivec/Tests/UnitTests-Bridging-Header.h
@@ -0,0 +1,6 @@
+//
+//  Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
+#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
diff --git a/objectivec/Tests/UnitTests-Info.plist b/objectivec/Tests/UnitTests-Info.plist
new file mode 100644
index 0000000..460a7d9
--- /dev/null
+++ b/objectivec/Tests/UnitTests-Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+</dict>
+</plist>
diff --git a/objectivec/Tests/golden_message b/objectivec/Tests/golden_message
new file mode 100644
index 0000000..7bceab4
--- /dev/null
+++ b/objectivec/Tests/golden_message
Binary files differ
diff --git a/objectivec/Tests/golden_packed_fields_message b/objectivec/Tests/golden_packed_fields_message
new file mode 100644
index 0000000..7bceab4
--- /dev/null
+++ b/objectivec/Tests/golden_packed_fields_message
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/AppDelegate.m b/objectivec/Tests/iOSTestHarness/AppDelegate.m
new file mode 100644
index 0000000..8c4a586
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/AppDelegate.m
@@ -0,0 +1,35 @@
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+@implementation AppDelegate
+
+@synthesize window;
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+  #pragma unused (application, launchOptions)
+
+  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+  self.window.backgroundColor = [UIColor whiteColor];
+  [self.window makeKeyAndVisible];
+  self.window.rootViewController = [[UIViewController alloc] init];
+
+  UILabel *label =
+      [[UILabel alloc] initWithFrame:CGRectMake(0, 200, CGRectGetWidth(self.window.frame), 40)];
+  label.text = @"Protocol Buffer Test Harness";
+  label.textAlignment = NSTextAlignmentCenter;
+  [self.window addSubview:label];
+
+  return YES;
+}
+
+@end
+
+int main(int argc, char * argv[]) {
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+  }
+}
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..0cbf9ac
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,116 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "3x"
+    },
+    {
+      "size" : "57x57",
+      "idiom" : "iphone",
+      "filename" : "iPhone6.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "57x57",
+      "idiom" : "iphone",
+      "filename" : "iPhone6_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "iPhone7_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "iPhone7_3x.png",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "50x50",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "50x50",
+      "scale" : "2x"
+    },
+    {
+      "size" : "72x72",
+      "idiom" : "ipad",
+      "filename" : "iPad6.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "72x72",
+      "idiom" : "ipad",
+      "filename" : "iPad6_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "iPad7.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "iPad7_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "car",
+      "size" : "120x120",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png
new file mode 100644
index 0000000..43da2ee
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6_2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6_2x.png
new file mode 100644
index 0000000..2ec9370
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6_2x.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png
new file mode 100644
index 0000000..aec8bc1
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7_2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7_2x.png
new file mode 100644
index 0000000..e39cc3e
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7_2x.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png
new file mode 100644
index 0000000..5572d79
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6_2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6_2x.png
new file mode 100644
index 0000000..2424997
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6_2x.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_2x.png
new file mode 100644
index 0000000..10bfc3c
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_2x.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_3x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_3x.png
new file mode 100644
index 0000000..8d16f14
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_3x.png
Binary files differ
diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..5a29666
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,49 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "minimum-system-version" : "7.0",
+      "subtype" : "retina4",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "minimum-system-version" : "7.0",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/objectivec/Tests/iOSTestHarness/Info.plist b/objectivec/Tests/iOSTestHarness/Info.plist
new file mode 100644
index 0000000..24bd333
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/Info.plist
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+	</array>
+</dict>
+</plist>
diff --git a/objectivec/Tests/iOSTestHarness/LaunchScreen.xib b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib
new file mode 100644
index 0000000..22204bf
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
+            <rect key="frame" x="0.0" y="0.0" width="630" height="503"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Protocol Buffer Test Harness" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
+                    <rect key="frame" x="20" y="147" width="591" height="43"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
+                    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+            <constraints>
+                <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="Kid-kn-2rF"/>
+                <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
+                <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
+            </constraints>
+            <nil key="simulatedStatusBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="479" y="456.5"/>
+        </view>
+    </objects>
+</document>
diff --git a/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/objectivec/Tests/text_format_map_unittest_data.txt b/objectivec/Tests/text_format_map_unittest_data.txt
new file mode 100644
index 0000000..ad1195e
--- /dev/null
+++ b/objectivec/Tests/text_format_map_unittest_data.txt
@@ -0,0 +1,70 @@
+map_int32_int32 {
+  key: 100
+  value: 1
+}
+map_int64_int64 {
+  key: 101
+  value: 1
+}
+map_uint32_uint32 {
+  key: 102
+  value: 1
+}
+map_uint64_uint64 {
+  key: 103
+  value: 1
+}
+map_sint32_sint32 {
+  key: 104
+  value: 1
+}
+map_sint64_sint64 {
+  key: 105
+  value: 1
+}
+map_fixed32_fixed32 {
+  key: 106
+  value: 1
+}
+map_fixed64_fixed64 {
+  key: 107
+  value: 1
+}
+map_sfixed32_sfixed32 {
+  key: 108
+  value: 1
+}
+map_sfixed64_sfixed64 {
+  key: 109
+  value: 1
+}
+map_int32_float {
+  key: 110
+  value: 1
+}
+map_int32_double {
+  key: 111
+  value: 1
+}
+map_bool_bool {
+  key: true
+  value: false
+}
+map_string_string {
+  key: "112"
+  value: "1"
+}
+map_int32_bytes {
+  key: 113
+  value: "\001\000\000\000"
+}
+map_int32_enum {
+  key: 114
+  value: MAP_ENUM_BAZ
+}
+map_int32_foreign_message {
+  key: 115
+  value {
+    c: 1
+  }
+}
diff --git a/objectivec/Tests/text_format_unittest_data.txt b/objectivec/Tests/text_format_unittest_data.txt
new file mode 100644
index 0000000..d10f100
--- /dev/null
+++ b/objectivec/Tests/text_format_unittest_data.txt
@@ -0,0 +1,116 @@
+optional_int32: 101
+optional_int64: 102
+optional_uint32: 103
+optional_uint64: 104
+optional_sint32: 105
+optional_sint64: 106
+optional_fixed32: 107
+optional_fixed64: 108
+optional_sfixed32: 109
+optional_sfixed64: 110
+optional_float: 111
+optional_double: 112
+optional_bool: true
+optional_string: "115"
+optional_bytes: "\001\000\002\003\000\005"
+OptionalGroup {
+  a: 117
+}
+optional_nested_message {
+  bb: 118
+}
+optional_foreign_message {
+  c: 119
+}
+optional_import_message {
+  d: 120
+}
+optional_nested_enum: BAZ
+optional_foreign_enum: FOREIGN_BAZ
+optional_import_enum: IMPORT_BAZ
+optional_string_piece: "124"
+optional_cord: "125"
+repeated_int32: 201
+repeated_int32: 301
+repeated_int64: 202
+repeated_int64: 302
+repeated_uint32: 203
+repeated_uint32: 303
+repeated_uint64: 204
+repeated_uint64: 304
+repeated_sint32: 205
+repeated_sint32: 305
+repeated_sint64: 206
+repeated_sint64: 306
+repeated_fixed32: 207
+repeated_fixed32: 307
+repeated_fixed64: 208
+repeated_fixed64: 308
+repeated_sfixed32: 209
+repeated_sfixed32: 309
+repeated_sfixed64: 210
+repeated_sfixed64: 310
+repeated_float: 211
+repeated_float: 311
+repeated_double: 212
+repeated_double: 312
+repeated_bool: false
+repeated_bool: true
+repeated_string: "215"
+repeated_string: "315"
+repeated_bytes: "\330\000\000\000"
+repeated_bytes: "<\001\000\000"
+RepeatedGroup {
+  a: 217
+}
+RepeatedGroup {
+  a: 317
+}
+repeated_nested_message {
+  bb: 218
+}
+repeated_nested_message {
+  bb: 318
+}
+repeated_foreign_message {
+  c: 219
+}
+repeated_foreign_message {
+  c: 319
+}
+repeated_import_message {
+  d: 220
+}
+repeated_import_message {
+  d: 320
+}
+repeated_nested_enum: BAZ
+repeated_nested_enum: BAR
+repeated_foreign_enum: FOREIGN_BAZ
+repeated_foreign_enum: FOREIGN_BAR
+repeated_import_enum: IMPORT_BAZ
+repeated_import_enum: IMPORT_BAR
+repeated_string_piece: "224"
+repeated_string_piece: "324"
+repeated_cord: "225"
+repeated_cord: "325"
+default_int32: 401
+default_int64: 402
+default_uint32: 403
+default_uint64: 404
+default_sint32: 405
+default_sint64: 406
+default_fixed32: 407
+default_fixed64: 408
+default_sfixed32: 409
+default_sfixed64: 410
+default_float: 411
+default_double: 412
+default_bool: false
+default_string: "415"
+default_bytes: "\240\001\000\000"
+default_nested_enum: FOO
+default_foreign_enum: FOREIGN_FOO
+default_import_enum: IMPORT_FOO
+default_string_piece: "424"
+default_cord: "425"
diff --git a/objectivec/Tests/unittest_cycle.proto b/objectivec/Tests/unittest_cycle.proto
new file mode 100644
index 0000000..5f6f56a
--- /dev/null
+++ b/objectivec/Tests/unittest_cycle.proto
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+// Cycles in the Message graph can cause problems for the mutable classes
+// since the properties on the mutable class change types. This file just
+// needs to generate source, and that source must compile, to ensure the
+// generated source works for this sort of case.
+
+// You can't make a object graph that spans files, so this can only be done
+// within a single proto file.
+
+message CycleFoo {
+  optional CycleFoo a_foo = 1;
+  optional CycleBar a_bar = 2;
+  optional CycleBaz a_baz = 3;
+}
+
+message CycleBar {
+  optional CycleBar a_bar = 1;
+  optional CycleBaz a_baz = 2;
+  optional CycleFoo a_foo = 3;
+}
+
+message CycleBaz {
+  optional CycleBaz a_baz = 1;
+  optional CycleFoo a_foo = 2;
+  optional CycleBar a_bar = 3;
+}
diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto
new file mode 100644
index 0000000..f6ab6a2
--- /dev/null
+++ b/objectivec/Tests/unittest_objc.proto
@@ -0,0 +1,449 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2011 Google Inc.  All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+// Using the messages in unittest.proto, setup for recursive cases for testing
+// extensions at various depths.
+extend TestAllExtensions {
+  optional TestAllExtensions recursive_extension = 86;
+}
+
+// Recursive message to for testing autocreators at different depths.
+message TestRecursiveMessageWithRepeatedField {
+  optional TestRecursiveMessageWithRepeatedField a = 1;
+  repeated int32 i = 2;
+  repeated string str = 3;
+  map<int32, int32> i_to_i = 4;
+  map<string, string> str_to_str = 5;
+}
+
+// Recursive message and extension to for testing autocreators at different
+// depths.
+message TestRecursiveExtension {
+  optional TestRecursiveExtension recursive_sub_message = 1;
+  repeated int32 repeated_value = 2;
+  extensions 1000 to max;
+}
+
+extend TestRecursiveExtension {
+  optional TestRecursiveExtension recursive_message_extension = 1000;
+}
+
+message self {
+  message super {
+    optional int32 description = 1;
+  }
+
+  enum autorelease {
+    retain      = 1;
+    release     = 2;
+    retainCount = 3;
+  }
+
+  // Singular
+  optional   bool id                =  1;
+  optional   bool _cmd              =  2;
+  optional   bool in                =  3;
+  optional   bool out               =  4;
+  optional   bool inout             =  5;
+  optional   bool bycopy            =  6;
+  optional   bool byref             =  7;
+  optional   bool oneway            =  8;
+  optional   bool dealloc           =  9;
+  optional   bool zone              = 10;
+  optional   bool isProxy           = 11;
+  optional   bool copy              = 12;
+  optional   bool readonly          = 13;
+  optional   bool default           = 14;
+  optional   bool assign            = 15;
+  optional   bool getter            = 16;
+  optional   bool setter            = 17;
+  optional   bool weak              = 18;
+  optional   bool public            = 19;
+  optional   bool case              = 20;
+
+  optional   autorelease SubEnum    = 25;
+
+ optional group New = 50 {
+   optional string copy = 51;
+ }
+  optional group MutableCopy = 60 {
+    optional int32 extensionRegistry = 61;
+  }
+
+  extensions 90 to 94;
+
+}
+
+enum retain {
+  count          = 4;
+  initialized    = 5;
+  serializedSize = 6;
+}
+
+message ObjCPropertyNaming {
+  // Test that the properties properly get things all caps.
+  optional string url           = 1;
+  optional string thumbnail_url = 2;
+  optional string url_foo       = 3;
+  optional string some_url_blah = 4;
+  optional string http          = 5;
+  optional string https         = 6;
+  // This one doesn't.
+  repeated string urls          = 7;
+}
+
+// EnumValueShortName: The short names shouldn't get suffixes/prefixes.
+enum Foo {
+  SERIALIZED_SIZE = 1;
+  SIZE            = 2;
+  OTHER           = 3;
+}
+
+// EnumValueShortName: The enum name gets a prefix.
+enum Category {
+  RED  = 1;
+  BLUE = 2;
+}
+
+// EnumValueShortName: Twist case, full name gets PB, but the short names
+// should still end up correct.
+enum Time {
+  BASE            = 1;
+  RECORD          = 2;
+  SOMETHING_ELSE  = 3;
+}
+
+extend self {
+  repeated    int32 debugDescription    =  90 [packed = true];
+  repeated    int64 finalize            =  91 [packed = true];
+  repeated   uint32 hash                =  92 [packed = true];
+  repeated   uint64 classForCoder       =  93 [packed = true];
+  repeated   sint32 byref               =  94 [packed = true];
+}
+
+// Test handing of fields that start with init* since Xcode 5's ARC support
+// doesn't like messages that look like initializers but aren't.
+message ObjCInitFoo {
+  optional string init_val = 11;
+  optional int32 init_size = 12;
+  optional self init_self = 13;
+
+  repeated string init_vals = 21;
+  repeated int32 init_sizes = 22;
+  repeated self init_selfs = 23;
+}
+
+// Test handling of fields that start with retained names.
+message ObjCRetainedFoo {
+  optional string new_val_lower_complex = 11;
+  optional string new_Val_upper_complex = 12;
+  optional string newvalue_lower_no_underscore_complex = 13;
+  optional string newValue_upper_no_underscore_complex = 14;
+
+  optional int32 new_val_lower_primitive = 15;
+  optional int32 new_Val_upper_primitive = 16;
+  optional int32 newvalue_lower_no_underscore_primitive = 17;
+  optional int32 newValue_upper_no_underscore_primitive = 18;
+
+  optional self new_val_lower_message = 19;
+  optional self new_Val_upper_message = 20;
+  optional self newvalue_lower_no_underscore_message = 21;
+  optional self newValue_upper_no_underscore_message = 22;
+
+  optional Foo new_val_lower_enum = 23;
+  optional Foo new_Val_upper_enum = 24;
+  optional Foo newvalue_lower_no_underscore_enum = 25;
+  optional Foo newValue_upper_no_underscore_enum = 26;
+
+  repeated string new_val_lower_complex_repeated = 111;
+  repeated string new_Val_upper_complex_repeated = 112;
+  repeated string newvalue_lower_no_underscore_complex_repeated = 113;
+  repeated string newValue_upper_no_underscore_complex_repeated = 114;
+
+  repeated int32 new_val_lower_primitive_repeated = 115;
+  repeated int32 new_Val_upper_primitive_repeated = 116;
+  repeated int32 newvalue_lower_no_underscore_primitive_repeated = 117;
+  repeated int32 newValue_upper_no_underscore_primitive_repeated = 118;
+
+  repeated self new_val_lower_message_repeated = 119;
+  repeated self new_Val_upper_message_repeated = 120;
+  repeated self newvalue_lower_no_underscore_message_repeated = 121;
+  repeated self newValue_upper_no_underscore_message_repeated = 122;
+
+  repeated Foo new_val_lower_enum_repeated = 123;
+  repeated Foo new_Val_upper_enum_repeated = 124;
+  repeated Foo newvalue_lower_no_underscore_enum_repeated = 125;
+  repeated Foo newValue_upper_no_underscore_enum_repeated = 126;
+
+  optional string alloc_val_lower_complex = 211;
+  optional string alloc_Val_upper_complex = 212;
+  optional string allocvalue_lower_no_underscore_complex = 213;
+  optional string allocValue_upper_no_underscore_complex = 214;
+
+  optional int32 alloc_val_lower_primitive = 215;
+  optional int32 alloc_Val_upper_primitive = 216;
+  optional int32 allocvalue_lower_no_underscore_primitive = 217;
+  optional int32 allocValue_upper_no_underscore_primitive = 218;
+
+  optional self alloc_val_lower_message = 219;
+  optional self alloc_Val_upper_message = 220;
+  optional self allocvalue_lower_no_underscore_message = 221;
+  optional self allocValue_upper_no_underscore_message = 222;
+
+  optional Foo alloc_val_lower_enum = 223;
+  optional Foo alloc_Val_upper_enum = 224;
+  optional Foo allocvalue_lower_no_underscore_enum = 225;
+  optional Foo allocValue_upper_no_underscore_enum = 226;
+
+  repeated string alloc_val_lower_complex_repeated = 311;
+  repeated string alloc_Val_upper_complex_repeated = 312;
+  repeated string allocvalue_lower_no_underscore_complex_repeated = 313;
+  repeated string allocValue_upper_no_underscore_complex_repeated = 314;
+
+  repeated int32 alloc_val_lower_primitive_repeated = 315;
+  repeated int32 alloc_Val_upper_primitive_repeated = 316;
+  repeated int32 allocvalue_lower_no_underscore_primitive_repeated = 317;
+  repeated int32 allocValue_upper_no_underscore_primitive_repeated = 318;
+
+  repeated self alloc_val_lower_message_repeated = 319;
+  repeated self alloc_Val_upper_message_repeated = 320;
+  repeated self allocvalue_lower_no_underscore_message_repeated = 321;
+  repeated self allocValue_upper_no_underscore_message_repeated = 322;
+
+  repeated Foo alloc_val_lower_enum_repeated = 323;
+  repeated Foo alloc_Val_upper_enum_repeated = 324;
+  repeated Foo allocvalue_lower_no_underscore_enum_repeated = 325;
+  repeated Foo allocValue_upper_no_underscore_enum_repeated = 326;
+
+  optional string copy_val_lower_complex = 411;
+  optional string copy_Val_upper_complex = 412;
+  optional string copyvalue_lower_no_underscore_complex = 413;
+  optional string copyValue_upper_no_underscore_complex = 414;
+
+  optional int32 copy_val_lower_primitive = 415;
+  optional int32 copy_Val_upper_primitive = 416;
+  optional int32 copyvalue_lower_no_underscore_primitive = 417;
+  optional int32 copyValue_upper_no_underscore_primitive = 418;
+
+  optional self copy_val_lower_message = 419;
+  optional self copy_Val_upper_message = 420;
+  optional self copyvalue_lower_no_underscore_message = 421;
+  optional self copyValue_upper_no_underscore_message = 422;
+
+  optional Foo copy_val_lower_enum = 423;
+  optional Foo copy_Val_upper_enum = 424;
+  optional Foo copyvalue_lower_no_underscore_enum = 425;
+  optional Foo copyValue_upper_no_underscore_enum = 426;
+
+  repeated string copy_val_lower_complex_repeated = 511;
+  repeated string copy_Val_upper_complex_repeated = 512;
+  repeated string copyvalue_lower_no_underscore_complex_repeated = 513;
+  repeated string copyValue_upper_no_underscore_complex_repeated = 514;
+
+  repeated int32 copy_val_lower_primitive_repeated = 515;
+  repeated int32 copy_Val_upper_primitive_repeated = 516;
+  repeated int32 copyvalue_lower_no_underscore_primitive_repeated = 517;
+  repeated int32 copyValue_upper_no_underscore_primitive_repeated = 518;
+
+  repeated self copy_val_lower_message_repeated = 519;
+  repeated self copy_Val_upper_message_repeated = 520;
+  repeated self copyvalue_lower_no_underscore_message_repeated = 521;
+  repeated self copyValue_upper_no_underscore_message_repeated = 522;
+
+  repeated Foo copy_val_lower_enum_repeated = 523;
+  repeated Foo copy_Val_upper_enum_repeated = 524;
+  repeated Foo copyvalue_lower_no_underscore_enum_repeated = 525;
+  repeated Foo copyValue_upper_no_underscore_enum_repeated = 526;
+
+  optional string mutableCopy_val_lower_complex = 611;
+  optional string mutableCopy_Val_upper_complex = 612;
+  optional string mutableCopyvalue_lower_no_underscore_complex = 613;
+  optional string mutableCopyValue_upper_no_underscore_complex = 614;
+
+  optional int32 mutableCopy_val_lower_primitive = 615;
+  optional int32 mutableCopy_Val_upper_primitive = 616;
+  optional int32 mutableCopyvalue_lower_no_underscore_primitive = 617;
+  optional int32 mutableCopyValue_upper_no_underscore_primitive = 618;
+
+  optional self mutableCopy_val_lower_message = 619;
+  optional self mutableCopy_Val_upper_message = 620;
+  optional self mutableCopyvalue_lower_no_underscore_message = 621;
+  optional self mutableCopyValue_upper_no_underscore_message = 622;
+
+  optional Foo mutableCopy_val_lower_enum = 623;
+  optional Foo mutableCopy_Val_upper_enum = 624;
+  optional Foo mutableCopyvalue_lower_no_underscore_enum = 625;
+  optional Foo mutableCopyValue_upper_no_underscore_enum = 626;
+
+  repeated string mutableCopy_val_lower_complex_repeated = 711;
+  repeated string mutableCopy_Val_upper_complex_repeated = 712;
+  repeated string mutableCopyvalue_lower_no_underscore_complex_repeated = 713;
+  repeated string mutableCopyValue_upper_no_underscore_complex_repeated = 714;
+
+  repeated int32 mutableCopy_val_lower_primitive_repeated = 715;
+  repeated int32 mutableCopy_Val_upper_primitive_repeated = 716;
+  repeated int32 mutableCopyvalue_lower_no_underscore_primitive_repeated = 717;
+  repeated int32 mutableCopyValue_upper_no_underscore_primitive_repeated = 718;
+
+  repeated self mutableCopy_val_lower_message_repeated = 719;
+  repeated self mutableCopy_Val_upper_message_repeated = 720;
+  repeated self mutableCopyvalue_lower_no_underscore_message_repeated = 721;
+  repeated self mutableCopyValue_upper_no_underscore_message_repeated = 722;
+
+  repeated Foo mutableCopy_val_lower_enum_repeated = 723;
+  repeated Foo mutableCopy_Val_upper_enum_repeated = 724;
+  repeated Foo mutableCopyvalue_lower_no_underscore_enum_repeated = 725;
+  repeated Foo mutableCopyValue_upper_no_underscore_enum_repeated = 726;
+}
+
+// Test handling of fields that are the retained names.
+message ObjCRetainedComplex {
+  optional string new = 1;
+  optional string alloc = 2;
+  optional string copy = 3;
+  optional string mutableCopy = 4;
+}
+
+message ObjCRetainedComplexRepeated {
+  repeated string new = 1;
+  repeated string alloc = 2;
+  repeated string copy = 3;
+  repeated string mutableCopy = 4;
+}
+
+message ObjCRetainedPrimitive {
+  optional int32 new = 1;
+  optional int32 alloc = 2;
+  optional int32 copy = 3;
+  optional int32 mutableCopy = 4;
+}
+
+message ObjCRetainedPrimitiveRepeated {
+  repeated int32 new = 1;
+  repeated int32 alloc = 2;
+  repeated int32 copy = 3;
+  repeated int32 mutableCopy = 4;
+}
+
+message ObjCRetainedMessage {
+  optional self new = 1;
+  optional self alloc = 2;
+  optional self copy = 3;
+  optional self mutableCopy = 4;
+}
+
+message ObjCRetainedMessageRepeated {
+  repeated self new = 1;
+  repeated self alloc = 2;
+  repeated self copy = 3;
+  repeated self mutableCopy = 4;
+}
+
+// Test Handling some MacTypes
+message Point {
+  message Rect {
+    optional int32 TimeValue = 1;
+  }
+}
+
+// Test some weird defaults that we see in protos.
+message ObjcWeirdDefaults {
+  // Set default values that match the protocol buffer defined defaults to
+  // confirm hasDefault and the default values are set correctly.
+  optional string foo = 1 [default = ""];
+  optional bytes bar = 2 [default = ""];
+}
+
+// Used to confirm negative enum values work as expected.
+message EnumTestMsg {
+  enum MyEnum {
+    ZERO    = 0;
+    ONE     = 1;
+    TWO     = 2;
+    NEG_ONE = -1;
+    NEG_TWO = -2;
+  }
+  optional MyEnum foo = 1;
+  optional MyEnum bar = 2 [default = ONE];
+  optional MyEnum baz = 3 [default = NEG_ONE];
+
+  repeated MyEnum mumble = 4;
+}
+
+// Test case for https://github.com/google/protobuf/issues/1453
+// Message with no explicit defaults, but a non zero default for an enum.
+message MessageWithOneBasedEnum {
+  enum OneBasedEnum {
+    ONE = 1;
+    TWO = 2;
+  }
+  optional OneBasedEnum enum_field = 1;
+}
+
+// Message with all bools for testing things related to bool storage.
+message BoolOnlyMessage {
+  optional bool bool_field_1 = 1;
+  optional bool bool_field_2 = 2;
+  optional bool bool_field_3 = 3;
+  optional bool bool_field_4 = 4;
+  optional bool bool_field_5 = 5;
+  optional bool bool_field_6 = 6;
+  optional bool bool_field_7 = 7;
+  optional bool bool_field_8 = 8;
+  optional bool bool_field_9 = 9;
+  optional bool bool_field_10 = 10;
+  optional bool bool_field_11 = 11;
+  optional bool bool_field_12 = 12;
+  optional bool bool_field_13 = 13;
+  optional bool bool_field_14 = 14;
+  optional bool bool_field_15 = 15;
+  optional bool bool_field_16 = 16;
+  optional bool bool_field_17 = 17;
+  optional bool bool_field_18 = 18;
+  optional bool bool_field_19 = 19;
+  optional bool bool_field_20 = 20;
+  optional bool bool_field_21 = 21;
+  optional bool bool_field_22 = 22;
+  optional bool bool_field_23 = 23;
+  optional bool bool_field_24 = 24;
+  optional bool bool_field_25 = 25;
+  optional bool bool_field_26 = 26;
+  optional bool bool_field_27 = 27;
+  optional bool bool_field_28 = 28;
+  optional bool bool_field_29 = 29;
+  optional bool bool_field_30 = 30;
+  optional bool bool_field_31 = 31;
+  optional bool bool_field_32 = 32;
+}
diff --git a/objectivec/Tests/unittest_objc_startup.proto b/objectivec/Tests/unittest_objc_startup.proto
new file mode 100644
index 0000000..aee7bd5
--- /dev/null
+++ b/objectivec/Tests/unittest_objc_startup.proto
@@ -0,0 +1,49 @@
+// 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.
+
+syntax = "proto2";
+
+package protobuf_objc_unittest;
+
+message TestObjCStartupMessage {
+  extensions 1 to max;
+}
+
+extend TestObjCStartupMessage {
+  // Singular
+  optional    int32 optional_int32_extension    = 1;
+  repeated    int32 repeated_int32_extension    = 2;
+}
+
+message TestObjCStartupNested {
+  extend TestObjCStartupMessage {
+    optional string nested_string_extension = 3;
+  }
+}
diff --git a/objectivec/Tests/unittest_runtime_proto2.proto b/objectivec/Tests/unittest_runtime_proto2.proto
new file mode 100644
index 0000000..ed83502
--- /dev/null
+++ b/objectivec/Tests/unittest_runtime_proto2.proto
@@ -0,0 +1,128 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+//
+// 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.
+
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message Message2 {
+  enum Enum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    EXTRA_2 = 20;
+  }
+
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+  optional Message2  optional_message = 18;
+  optional Enum         optional_enum = 19;
+
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+  repeated Message2 repeated_message  = 48;
+  repeated Enum     repeated_enum     = 49;
+
+  oneof o {
+       int32 oneof_int32    = 51 [default = 100];
+       int64 oneof_int64    = 52 [default = 101];
+      uint32 oneof_uint32   = 53 [default = 102];
+      uint64 oneof_uint64   = 54 [default = 103];
+      sint32 oneof_sint32   = 55 [default = 104];
+      sint64 oneof_sint64   = 56 [default = 105];
+     fixed32 oneof_fixed32  = 57 [default = 106];
+     fixed64 oneof_fixed64  = 58 [default = 107];
+    sfixed32 oneof_sfixed32 = 59 [default = 108];
+    sfixed64 oneof_sfixed64 = 60 [default = 109];
+       float oneof_float    = 61 [default = 110];
+      double oneof_double   = 62 [default = 111];
+        bool oneof_bool     = 63 [default = true];
+      string oneof_string   = 64 [default = "string"];
+       bytes oneof_bytes    = 65 [default = "data"];
+       group OneofGroup     = 66 {
+         optional int32 a = 67;
+         optional int32 b = 167;
+       }
+     Message2 oneof_message = 68;
+     Enum        oneof_enum = 69 [default = BAZ];
+  }
+
+  // Some token map cases, too many combinations to list them all.
+  map<int32   , int32   > map_int32_int32       = 70;
+  map<int64   , int64   > map_int64_int64       = 71;
+  map<uint32  , uint32  > map_uint32_uint32     = 72;
+  map<uint64  , uint64  > map_uint64_uint64     = 73;
+  map<sint32  , sint32  > map_sint32_sint32     = 74;
+  map<sint64  , sint64  > map_sint64_sint64     = 75;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 76;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 77;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 78;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 79;
+  map<int32   , float   > map_int32_float       = 80;
+  map<int32   , double  > map_int32_double      = 81;
+  map<bool    , bool    > map_bool_bool         = 82;
+  map<string  , string  > map_string_string     = 83;
+  map<string  , bytes   > map_string_bytes      = 84;
+  map<string  , Message2> map_string_message    = 85;
+  map<int32   , bytes   > map_int32_bytes       = 86;
+  map<int32   , Enum    > map_int32_enum        = 87;
+  map<int32   , Message2> map_int32_message     = 88;
+}
diff --git a/objectivec/Tests/unittest_runtime_proto3.proto b/objectivec/Tests/unittest_runtime_proto3.proto
new file mode 100644
index 0000000..ad2e362
--- /dev/null
+++ b/objectivec/Tests/unittest_runtime_proto3.proto
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+//
+// 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.
+
+syntax = "proto3";
+
+package protobuf_unittest;
+
+message Message3 {
+  enum Enum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    EXTRA_3 = 30;
+  }
+
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+  // No 'group' in proto3.
+  Message3 optional_message  = 18;
+      Enum optional_enum     = 19;
+
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+  // No 'group' in proto3.
+  repeated Message3 repeated_message  = 48;
+  repeated     Enum repeated_enum     = 49;
+
+  oneof o {
+       int32 oneof_int32    = 51;
+       int64 oneof_int64    = 52;
+      uint32 oneof_uint32   = 53;
+      uint64 oneof_uint64   = 54;
+      sint32 oneof_sint32   = 55;
+      sint64 oneof_sint64   = 56;
+     fixed32 oneof_fixed32  = 57;
+     fixed64 oneof_fixed64  = 58;
+    sfixed32 oneof_sfixed32 = 59;
+    sfixed64 oneof_sfixed64 = 60;
+       float oneof_float    = 61;
+      double oneof_double   = 62;
+        bool oneof_bool     = 63;
+      string oneof_string   = 64;
+       bytes oneof_bytes    = 65;
+    // No 'group' in proto3.
+    Message3 oneof_message  = 68;
+        Enum oneof_enum     = 69;
+  }
+
+  // Some token map cases, too many combinations to list them all.
+  map<int32   , int32   > map_int32_int32       = 70;
+  map<int64   , int64   > map_int64_int64       = 71;
+  map<uint32  , uint32  > map_uint32_uint32     = 72;
+  map<uint64  , uint64  > map_uint64_uint64     = 73;
+  map<sint32  , sint32  > map_sint32_sint32     = 74;
+  map<sint64  , sint64  > map_sint64_sint64     = 75;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 76;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 77;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 78;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 79;
+  map<int32   , float   > map_int32_float       = 80;
+  map<int32   , double  > map_int32_double      = 81;
+  map<bool    , bool    > map_bool_bool         = 82;
+  map<string  , string  > map_string_string     = 83;
+  map<string  , bytes   > map_string_bytes      = 84;
+  map<string  , Message3> map_string_message    = 85;
+  map<int32   , bytes   > map_int32_bytes       = 86;
+  map<int32   , Enum    > map_int32_enum        = 87;
+  map<int32   , Message3> map_int32_message     = 88;
+}
diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh
new file mode 100755
index 0000000..36c3460
--- /dev/null
+++ b/objectivec/generate_well_known_types.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+# Run this script to regenerate *.pbobjc.{h,m} for the well known types after
+# the protocol compiler changes.
+
+# HINT:  Flags passed to generate_well_known_types.sh will be passed directly
+#   to make when building protoc.  This is particularly useful for passing
+#   -j4 to run 4 jobs simultaneously.
+
+set -eu
+
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/.."
+
+# Flag for continuous integration to check that everything is current.
+CHECK_ONLY=0
+if [[ $# -ge 1 && ( "$1" == "--check-only" ) ]] ; then
+  CHECK_ONLY=1
+  shift
+fi
+
+pushd "${ProtoRootDir}" > /dev/null
+
+if test ! -e src/google/protobuf/stubs/common.h; then
+  cat >&2 << __EOF__
+Could not find source code.  Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+  exit 1
+fi
+
+if test ! -e src/Makefile; then
+  cat >&2 << __EOF__
+Could not find src/Makefile.  You must run ./configure (and perhaps
+./autogen.sh) first.
+__EOF__
+  exit 1
+fi
+
+# Make sure the compiler is current.
+cd src
+make $@ protoc
+
+declare -a RUNTIME_PROTO_FILES=( \
+  google/protobuf/any.proto \
+  google/protobuf/api.proto \
+  google/protobuf/duration.proto \
+  google/protobuf/empty.proto \
+  google/protobuf/field_mask.proto \
+  google/protobuf/source_context.proto \
+  google/protobuf/struct.proto \
+  google/protobuf/timestamp.proto \
+  google/protobuf/type.proto \
+  google/protobuf/wrappers.proto)
+
+# Generate to a temp directory to see if they match.
+TMP_DIR=$(mktemp -d)
+trap "rm -rf ${TMP_DIR}" EXIT
+./protoc --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
+set +e
+diff -r "${TMP_DIR}/google" "${ProtoRootDir}/objectivec/google" > /dev/null
+if [[ $? -eq 0 ]] ; then
+  echo "Generated source for WellKnownTypes is current."
+  exit 0
+fi
+set -e
+
+# If check only mode, error out.
+if [[ "${CHECK_ONLY}" == 1 ]] ; then
+  echo "ERROR: The WKTs need to be regenerated! Run $0"
+  exit 1
+fi
+
+# Copy them over.
+echo "Copying over updated WellKnownType sources."
+cp -r "${TMP_DIR}/google/." "${ProtoRootDir}/objectivec/google/"
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
new file mode 100644
index 0000000..4002a98
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -0,0 +1,134 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBAnyRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBAnyRoot : GPBRootObject
+@end
+
+#pragma mark - GPBAny
+
+typedef GPB_ENUM(GPBAny_FieldNumber) {
+  GPBAny_FieldNumber_TypeURL = 1,
+  GPBAny_FieldNumber_Value = 2,
+};
+
+/// `Any` contains an arbitrary serialized protocol buffer message along with a
+/// URL that describes the type of the serialized message.
+///
+/// Protobuf library provides support to pack/unpack Any values in the form
+/// of utility functions or additional generated methods of the Any type.
+///
+/// Example 1: Pack and unpack a message in C++.
+///
+///     Foo foo = ...;
+///     Any any;
+///     any.PackFrom(foo);
+///     ...
+///     if (any.UnpackTo(&foo)) {
+///       ...
+///     }
+///
+/// Example 2: Pack and unpack a message in Java.
+///
+///     Foo foo = ...;
+///     Any any = Any.pack(foo);
+///     ...
+///     if (any.is(Foo.class)) {
+///       foo = any.unpack(Foo.class);
+///     }
+///
+/// The pack methods provided by protobuf library will by default use
+/// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+/// methods only use the fully qualified type name after the last '/'
+/// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+/// name "y.z".
+///
+///
+/// JSON
+/// ====
+/// The JSON representation of an `Any` value uses the regular
+/// representation of the deserialized, embedded message, with an
+/// additional field `\@type` which contains the type URL. Example:
+///
+///     package google.profile;
+///     message Person {
+///       string first_name = 1;
+///       string last_name = 2;
+///     }
+///
+///     {
+///       "\@type": "type.googleapis.com/google.profile.Person",
+///       "firstName": <string>,
+///       "lastName": <string>
+///     }
+///
+/// If the embedded message type is well-known and has a custom JSON
+/// representation, that representation will be embedded adding a field
+/// `value` which holds the custom JSON in addition to the `\@type`
+/// field. Example (for message [google.protobuf.Duration][]):
+///
+///     {
+///       "\@type": "type.googleapis.com/google.protobuf.Duration",
+///       "value": "1.212s"
+///     }
+@interface GPBAny : GPBMessage
+
+/// A URL/resource name whose content describes the type of the
+/// serialized protocol buffer message.
+///
+/// For URLs which use the schema `http`, `https`, or no schema, the
+/// following restrictions and interpretations apply:
+///
+/// * If no schema is provided, `https` is assumed.
+/// * The last segment of the URL's path must represent the fully
+///   qualified name of the type (as in `path/google.protobuf.Duration`).
+///   The name should be in a canonical form (e.g., leading "." is
+///   not accepted).
+/// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+///   value in binary format, or produce an error.
+/// * Applications are allowed to cache lookup results based on the
+///   URL, or have them precompiled into a binary to avoid any
+///   lookup. Therefore, binary compatibility needs to be preserved
+///   on changes to types. (Use versioned type names to manage
+///   breaking changes.)
+///
+/// Schemas other than `http`, `https` (or the empty schema) might be
+/// used with implementation specific semantics.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL;
+
+/// Must be a valid serialized protocol buffer of the above specified type.
+@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
new file mode 100644
index 0000000..6a1bf89
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -0,0 +1,93 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Any.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBAnyRoot
+
+@implementation GPBAnyRoot
+
+@end
+
+#pragma mark - GPBAnyRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBAny
+
+@implementation GPBAny
+
+@dynamic typeURL;
+@dynamic value;
+
+typedef struct GPBAny__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *typeURL;
+  NSData *value;
+} GPBAny__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "typeURL",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBAny_FieldNumber_TypeURL,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL),
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBAny_FieldNumber_Value,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBAny__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBytes,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBAny class]
+                                     rootClass:[GPBAnyRoot class]
+                                          file:GPBAnyRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBAny__storage_)
+                                         flags:0];
+#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    static const char *extraTextFormatInfo =
+        "\001\001\004\241!!\000";
+    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];
+#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
new file mode 100644
index 0000000..d66df62
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -0,0 +1,262 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+@class GPBMethod;
+@class GPBMixin;
+@class GPBOption;
+@class GPBSourceContext;
+GPB_ENUM_FWD_DECLARE(GPBSyntax);
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBApiRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBApiRoot : GPBRootObject
+@end
+
+#pragma mark - GPBApi
+
+typedef GPB_ENUM(GPBApi_FieldNumber) {
+  GPBApi_FieldNumber_Name = 1,
+  GPBApi_FieldNumber_MethodsArray = 2,
+  GPBApi_FieldNumber_OptionsArray = 3,
+  GPBApi_FieldNumber_Version = 4,
+  GPBApi_FieldNumber_SourceContext = 5,
+  GPBApi_FieldNumber_MixinsArray = 6,
+  GPBApi_FieldNumber_Syntax = 7,
+};
+
+/// Api is a light-weight descriptor for a protocol buffer service.
+@interface GPBApi : GPBMessage
+
+/// The fully qualified name of this api, including package name
+/// followed by the api's simple name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// The methods of this api, in unspecified order.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethod*> *methodsArray;
+/// The number of items in @c methodsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger methodsArray_Count;
+
+/// Any metadata attached to the API.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+/// A version string for this api. If specified, must have the form
+/// `major-version.minor-version`, as in `1.10`. If the minor version
+/// is omitted, it defaults to zero. If the entire version field is
+/// empty, the major version is derived from the package name, as
+/// outlined below. If the field is not empty, the version in the
+/// package name will be verified to be consistent with what is
+/// provided here.
+///
+/// The versioning schema uses [semantic
+/// versioning](http://semver.org) where the major version number
+/// indicates a breaking change and the minor version an additive,
+/// non-breaking change. Both version numbers are signals to users
+/// what to expect from different versions, and should be carefully
+/// chosen based on the product plan.
+///
+/// The major version is also reflected in the package name of the
+/// API, which must end in `v<major-version>`, as in
+/// `google.feature.v1`. For major versions 0 and 1, the suffix can
+/// be omitted. Zero major versions must only be used for
+/// experimental, none-GA apis.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *version;
+
+/// Source context for the protocol buffer service represented by this
+/// message.
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+/// Test to see if @c sourceContext has been set.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+
+/// Included APIs. See [Mixin][].
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMixin*> *mixinsArray;
+/// The number of items in @c mixinsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger mixinsArray_Count;
+
+/// The source syntax of the service.
+@property(nonatomic, readwrite) enum GPBSyntax syntax;
+
+@end
+
+/// Fetches the raw value of a @c GPBApi's @c syntax property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBApi_Syntax_RawValue(GPBApi *message);
+/// Sets the raw value of an @c GPBApi's @c syntax property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value);
+
+#pragma mark - GPBMethod
+
+typedef GPB_ENUM(GPBMethod_FieldNumber) {
+  GPBMethod_FieldNumber_Name = 1,
+  GPBMethod_FieldNumber_RequestTypeURL = 2,
+  GPBMethod_FieldNumber_RequestStreaming = 3,
+  GPBMethod_FieldNumber_ResponseTypeURL = 4,
+  GPBMethod_FieldNumber_ResponseStreaming = 5,
+  GPBMethod_FieldNumber_OptionsArray = 6,
+  GPBMethod_FieldNumber_Syntax = 7,
+};
+
+/// Method represents a method of an api.
+@interface GPBMethod : GPBMessage
+
+/// The simple name of this method.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// A URL of the input message type.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *requestTypeURL;
+
+/// If true, the request is streamed.
+@property(nonatomic, readwrite) BOOL requestStreaming;
+
+/// The URL of the output message type.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *responseTypeURL;
+
+/// If true, the response is streamed.
+@property(nonatomic, readwrite) BOOL responseStreaming;
+
+/// Any metadata attached to the method.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+/// The source syntax of this method.
+@property(nonatomic, readwrite) enum GPBSyntax syntax;
+
+@end
+
+/// Fetches the raw value of a @c GPBMethod's @c syntax property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBMethod_Syntax_RawValue(GPBMethod *message);
+/// Sets the raw value of an @c GPBMethod's @c syntax property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value);
+
+#pragma mark - GPBMixin
+
+typedef GPB_ENUM(GPBMixin_FieldNumber) {
+  GPBMixin_FieldNumber_Name = 1,
+  GPBMixin_FieldNumber_Root = 2,
+};
+
+/// Declares an API to be included in this API. The including API must
+/// redeclare all the methods from the included API, but documentation
+/// and options are inherited as follows:
+///
+/// - If after comment and whitespace stripping, the documentation
+///   string of the redeclared method is empty, it will be inherited
+///   from the original method.
+///
+/// - Each annotation belonging to the service config (http,
+///   visibility) which is not set in the redeclared method will be
+///   inherited.
+///
+/// - If an http annotation is inherited, the path pattern will be
+///   modified as follows. Any version prefix will be replaced by the
+///   version of the including API plus the [root][] path if specified.
+///
+/// Example of a simple mixin:
+///
+///     package google.acl.v1;
+///     service AccessControl {
+///       // Get the underlying ACL object.
+///       rpc GetAcl(GetAclRequest) returns (Acl) {
+///         option (google.api.http).get = "/v1/{resource=**}:getAcl";
+///       }
+///     }
+///
+///     package google.storage.v2;
+///     service Storage {
+///       rpc GetAcl(GetAclRequest) returns (Acl);
+///
+///       // Get a data record.
+///       rpc GetData(GetDataRequest) returns (Data) {
+///         option (google.api.http).get = "/v2/{resource=**}";
+///       }
+///     }
+///
+/// Example of a mixin configuration:
+///
+///     apis:
+///     - name: google.storage.v2.Storage
+///       mixins:
+///       - name: google.acl.v1.AccessControl
+///
+/// The mixin construct implies that all methods in `AccessControl` are
+/// also declared with same name and request/response types in
+/// `Storage`. A documentation generator or annotation processor will
+/// see the effective `Storage.GetAcl` method after inherting
+/// documentation and annotations as follows:
+///
+///     service Storage {
+///       // Get the underlying ACL object.
+///       rpc GetAcl(GetAclRequest) returns (Acl) {
+///         option (google.api.http).get = "/v2/{resource=**}:getAcl";
+///       }
+///       ...
+///     }
+///
+/// Note how the version in the path pattern changed from `v1` to `v2`.
+///
+/// If the `root` field in the mixin is specified, it should be a
+/// relative path under which inherited HTTP paths are placed. Example:
+///
+///     apis:
+///     - name: google.storage.v2.Storage
+///       mixins:
+///       - name: google.acl.v1.AccessControl
+///         root: acls
+///
+/// This implies the following inherited HTTP annotation:
+///
+///     service Storage {
+///       // Get the underlying ACL object.
+///       rpc GetAcl(GetAclRequest) returns (Acl) {
+///         option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
+///       }
+///       ...
+///     }
+@interface GPBMixin : GPBMessage
+
+/// The fully qualified name of the API which is included.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// If non-empty specifies a path under which inherited HTTP paths
+/// are rooted.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *root;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
new file mode 100644
index 0000000..45a06e6
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -0,0 +1,348 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Api.pbobjc.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+#import "google/protobuf/Type.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBApiRoot
+
+@implementation GPBApiRoot
+
++ (GPBExtensionRegistry*)extensionRegistry {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety and initialization of registry.
+  static GPBExtensionRegistry* registry = nil;
+  if (!registry) {
+    GPBDebugCheckRuntimeVersion();
+    registry = [[GPBExtensionRegistry alloc] init];
+    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
+    [registry addExtensions:[GPBTypeRoot extensionRegistry]];
+  }
+  return registry;
+}
+
+@end
+
+#pragma mark - GPBApiRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBApi
+
+@implementation GPBApi
+
+@dynamic name;
+@dynamic methodsArray, methodsArray_Count;
+@dynamic optionsArray, optionsArray_Count;
+@dynamic version;
+@dynamic hasSourceContext, sourceContext;
+@dynamic mixinsArray, mixinsArray_Count;
+@dynamic syntax;
+
+typedef struct GPBApi__storage_ {
+  uint32_t _has_storage_[1];
+  GPBSyntax syntax;
+  NSString *name;
+  NSMutableArray *methodsArray;
+  NSMutableArray *optionsArray;
+  NSString *version;
+  GPBSourceContext *sourceContext;
+  NSMutableArray *mixinsArray;
+} GPBApi__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBApi_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "methodsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod),
+        .number = GPBApi_FieldNumber_MethodsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, methodsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBApi_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "version",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBApi_FieldNumber_Version,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, version),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "sourceContext",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .number = GPBApi_FieldNumber_SourceContext,
+        .hasIndex = 2,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, sourceContext),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "mixinsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin),
+        .number = GPBApi_FieldNumber_MixinsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, mixinsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "syntax",
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .number = GPBApi_FieldNumber_Syntax,
+        .hasIndex = 3,
+        .offset = (uint32_t)offsetof(GPBApi__storage_, syntax),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBApi class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBApi__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBApi_Syntax_RawValue(GPBApi *message) {
+  GPBDescriptor *descriptor = [GPBApi descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBApi descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - GPBMethod
+
+@implementation GPBMethod
+
+@dynamic name;
+@dynamic requestTypeURL;
+@dynamic requestStreaming;
+@dynamic responseTypeURL;
+@dynamic responseStreaming;
+@dynamic optionsArray, optionsArray_Count;
+@dynamic syntax;
+
+typedef struct GPBMethod__storage_ {
+  uint32_t _has_storage_[1];
+  GPBSyntax syntax;
+  NSString *name;
+  NSString *requestTypeURL;
+  NSString *responseTypeURL;
+  NSMutableArray *optionsArray;
+} GPBMethod__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMethod_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBMethod__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "requestTypeURL",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMethod_FieldNumber_RequestTypeURL,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL),
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "requestStreaming",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMethod_FieldNumber_RequestStreaming,
+        .hasIndex = 2,
+        .offset = 3,  // Stored in _has_storage_ to save space.
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+      },
+      {
+        .name = "responseTypeURL",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMethod_FieldNumber_ResponseTypeURL,
+        .hasIndex = 4,
+        .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL),
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "responseStreaming",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMethod_FieldNumber_ResponseStreaming,
+        .hasIndex = 5,
+        .offset = 6,  // Stored in _has_storage_ to save space.
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBMethod_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBMethod__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "syntax",
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .number = GPBMethod_FieldNumber_Syntax,
+        .hasIndex = 7,
+        .offset = (uint32_t)offsetof(GPBMethod__storage_, syntax),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMethod class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBMethod__storage_)
+                                         flags:0];
+#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    static const char *extraTextFormatInfo =
+        "\002\002\007\244\241!!\000\004\010\244\241!!\000";
+    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];
+#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBMethod_Syntax_RawValue(GPBMethod *message) {
+  GPBDescriptor *descriptor = [GPBMethod descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBMethod descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - GPBMixin
+
+@implementation GPBMixin
+
+@dynamic name;
+@dynamic root;
+
+typedef struct GPBMixin__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSString *root;
+} GPBMixin__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMixin_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBMixin__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "root",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBMixin_FieldNumber_Root,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBMixin__storage_, root),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBMixin class]
+                                     rootClass:[GPBApiRoot class]
+                                          file:GPBApiRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBMixin__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
new file mode 100644
index 0000000..29888d6
--- /dev/null
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -0,0 +1,101 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBDurationRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBDurationRoot : GPBRootObject
+@end
+
+#pragma mark - GPBDuration
+
+typedef GPB_ENUM(GPBDuration_FieldNumber) {
+  GPBDuration_FieldNumber_Seconds = 1,
+  GPBDuration_FieldNumber_Nanos = 2,
+};
+
+/// A Duration represents a signed, fixed-length span of time represented
+/// as a count of seconds and fractions of seconds at nanosecond
+/// resolution. It is independent of any calendar and concepts like "day"
+/// or "month". It is related to Timestamp in that the difference between
+/// two Timestamp values is a Duration and it can be added or subtracted
+/// from a Timestamp. Range is approximately +-10,000 years.
+///
+/// Example 1: Compute Duration from two Timestamps in pseudo code.
+///
+///     Timestamp start = ...;
+///     Timestamp end = ...;
+///     Duration duration = ...;
+///
+///     duration.seconds = end.seconds - start.seconds;
+///     duration.nanos = end.nanos - start.nanos;
+///
+///     if (duration.seconds < 0 && duration.nanos > 0) {
+///       duration.seconds += 1;
+///       duration.nanos -= 1000000000;
+///     } else if (durations.seconds > 0 && duration.nanos < 0) {
+///       duration.seconds -= 1;
+///       duration.nanos += 1000000000;
+///     }
+///
+/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
+///
+///     Timestamp start = ...;
+///     Duration duration = ...;
+///     Timestamp end = ...;
+///
+///     end.seconds = start.seconds + duration.seconds;
+///     end.nanos = start.nanos + duration.nanos;
+///
+///     if (end.nanos < 0) {
+///       end.seconds -= 1;
+///       end.nanos += 1000000000;
+///     } else if (end.nanos >= 1000000000) {
+///       end.seconds += 1;
+///       end.nanos -= 1000000000;
+///     }
+@interface GPBDuration : GPBMessage
+
+/// Signed seconds of the span of time. Must be from -315,576,000,000
+/// to +315,576,000,000 inclusive.
+@property(nonatomic, readwrite) int64_t seconds;
+
+/// Signed fractions of a second at nanosecond resolution of the span
+/// of time. Durations less than one second are represented with a 0
+/// `seconds` field and a positive or negative `nanos` field. For durations
+/// of one second or more, a non-zero value for the `nanos` field must be
+/// of the same sign as the `seconds` field. Must be from -999,999,999
+/// to +999,999,999 inclusive.
+@property(nonatomic, readwrite) int32_t nanos;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
new file mode 100644
index 0000000..7dd6b64
--- /dev/null
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -0,0 +1,88 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Duration.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBDurationRoot
+
+@implementation GPBDurationRoot
+
+@end
+
+#pragma mark - GPBDurationRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBDuration
+
+@implementation GPBDuration
+
+@dynamic seconds;
+@dynamic nanos;
+
+typedef struct GPBDuration__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t nanos;
+  int64_t seconds;
+} GPBDuration__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "seconds",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBDuration_FieldNumber_Seconds,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBDuration__storage_, seconds),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+      },
+      {
+        .name = "nanos",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBDuration_FieldNumber_Nanos,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBDuration__storage_, nanos),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDuration class]
+                                     rootClass:[GPBDurationRoot class]
+                                          file:GPBDurationRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBDuration__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
new file mode 100644
index 0000000..f33db01
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -0,0 +1,53 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBEmptyRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBEmptyRoot : GPBRootObject
+@end
+
+#pragma mark - GPBEmpty
+
+/// A generic empty message that you can re-use to avoid defining duplicated
+/// empty messages in your APIs. A typical example is to use it as the request
+/// or the response type of an API method. For instance:
+///
+///     service Foo {
+///       rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+///     }
+///
+/// The JSON representation for `Empty` is empty JSON object `{}`.
+@interface GPBEmpty : GPBMessage
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
new file mode 100644
index 0000000..88753aa
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -0,0 +1,64 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Empty.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBEmptyRoot
+
+@implementation GPBEmptyRoot
+
+@end
+
+#pragma mark - GPBEmptyRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBEmpty
+
+@implementation GPBEmpty
+
+
+typedef struct GPBEmpty__storage_ {
+  uint32_t _has_storage_[1];
+} GPBEmpty__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEmpty class]
+                                     rootClass:[GPBEmptyRoot class]
+                                          file:GPBEmptyRoot_FileDescriptor()
+                                        fields:NULL
+                                    fieldCount:0
+                                   storageSize:sizeof(GPBEmpty__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
new file mode 100644
index 0000000..73cbd8a
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -0,0 +1,202 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBFieldMaskRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBFieldMaskRoot : GPBRootObject
+@end
+
+#pragma mark - GPBFieldMask
+
+typedef GPB_ENUM(GPBFieldMask_FieldNumber) {
+  GPBFieldMask_FieldNumber_PathsArray = 1,
+};
+
+/// `FieldMask` represents a set of symbolic field paths, for example:
+///
+///     paths: "f.a"
+///     paths: "f.b.d"
+///
+/// Here `f` represents a field in some root message, `a` and `b`
+/// fields in the message found in `f`, and `d` a field found in the
+/// message in `f.b`.
+///
+/// Field masks are used to specify a subset of fields that should be
+/// returned by a get operation or modified by an update operation.
+/// Field masks also have a custom JSON encoding (see below).
+///
+/// # Field Masks in Projections
+///
+/// When used in the context of a projection, a response message or
+/// sub-message is filtered by the API to only contain those fields as
+/// specified in the mask. For example, if the mask in the previous
+/// example is applied to a response message as follows:
+///
+///     f {
+///       a : 22
+///       b {
+///         d : 1
+///         x : 2
+///       }
+///       y : 13
+///     }
+///     z: 8
+///
+/// The result will not contain specific values for fields x,y and z
+/// (their value will be set to the default, and omitted in proto text
+/// output):
+///
+///
+///     f {
+///       a : 22
+///       b {
+///         d : 1
+///       }
+///     }
+///
+/// A repeated field is not allowed except at the last position of a
+/// field mask.
+///
+/// If a FieldMask object is not present in a get operation, the
+/// operation applies to all fields (as if a FieldMask of all fields
+/// had been specified).
+///
+/// Note that a field mask does not necessarily apply to the
+/// top-level response message. In case of a REST get operation, the
+/// field mask applies directly to the response, but in case of a REST
+/// list operation, the mask instead applies to each individual message
+/// in the returned resource list. In case of a REST custom method,
+/// other definitions may be used. Where the mask applies will be
+/// clearly documented together with its declaration in the API.  In
+/// any case, the effect on the returned resource/resources is required
+/// behavior for APIs.
+///
+/// # Field Masks in Update Operations
+///
+/// A field mask in update operations specifies which fields of the
+/// targeted resource are going to be updated. The API is required
+/// to only change the values of the fields as specified in the mask
+/// and leave the others untouched. If a resource is passed in to
+/// describe the updated values, the API ignores the values of all
+/// fields not covered by the mask.
+///
+/// In order to reset a field's value to the default, the field must
+/// be in the mask and set to the default value in the provided resource.
+/// Hence, in order to reset all fields of a resource, provide a default
+/// instance of the resource and set all fields in the mask, or do
+/// not provide a mask as described below.
+///
+/// If a field mask is not present on update, the operation applies to
+/// all fields (as if a field mask of all fields has been specified).
+/// Note that in the presence of schema evolution, this may mean that
+/// fields the client does not know and has therefore not filled into
+/// the request will be reset to their default. If this is unwanted
+/// behavior, a specific service may require a client to always specify
+/// a field mask, producing an error if not.
+///
+/// As with get operations, the location of the resource which
+/// describes the updated values in the request message depends on the
+/// operation kind. In any case, the effect of the field mask is
+/// required to be honored by the API.
+///
+/// ## Considerations for HTTP REST
+///
+/// The HTTP kind of an update operation which uses a field mask must
+/// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+/// (PUT must only be used for full updates).
+///
+/// # JSON Encoding of Field Masks
+///
+/// In JSON, a field mask is encoded as a single string where paths are
+/// separated by a comma. Fields name in each path are converted
+/// to/from lower-camel naming conventions.
+///
+/// As an example, consider the following message declarations:
+///
+///     message Profile {
+///       User user = 1;
+///       Photo photo = 2;
+///     }
+///     message User {
+///       string display_name = 1;
+///       string address = 2;
+///     }
+///
+/// In proto a field mask for `Profile` may look as such:
+///
+///     mask {
+///       paths: "user.display_name"
+///       paths: "photo"
+///     }
+///
+/// In JSON, the same mask is represented as below:
+///
+///     {
+///       mask: "user.displayName,photo"
+///     }
+///
+/// # Field Masks and Oneof Fields
+///
+/// Field masks treat fields in oneofs just as regular fields. Consider the
+/// following message:
+///
+///     message SampleMessage {
+///       oneof test_oneof {
+///         string name = 4;
+///         SubMessage sub_message = 9;
+///       }
+///     }
+///
+/// The field mask can be:
+///
+///     mask {
+///       paths: "name"
+///     }
+///
+/// Or:
+///
+///     mask {
+///       paths: "sub_message"
+///     }
+///
+/// Note that oneof type names ("test_oneof" in this case) cannot be used in
+/// paths.
+@interface GPBFieldMask : GPBMessage
+
+/// The set of field mask paths.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *pathsArray;
+/// The number of items in @c pathsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger pathsArray_Count;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
new file mode 100644
index 0000000..8c241af
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -0,0 +1,77 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/FieldMask.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBFieldMaskRoot
+
+@implementation GPBFieldMaskRoot
+
+@end
+
+#pragma mark - GPBFieldMaskRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBFieldMask
+
+@implementation GPBFieldMask
+
+@dynamic pathsArray, pathsArray_Count;
+
+typedef struct GPBFieldMask__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *pathsArray;
+} GPBFieldMask__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "pathsArray",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBFieldMask_FieldNumber_PathsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBFieldMask__storage_, pathsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFieldMask class]
+                                     rootClass:[GPBFieldMaskRoot class]
+                                          file:GPBFieldMaskRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBFieldMask__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
new file mode 100644
index 0000000..8775348
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -0,0 +1,54 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBSourceContextRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBSourceContextRoot : GPBRootObject
+@end
+
+#pragma mark - GPBSourceContext
+
+typedef GPB_ENUM(GPBSourceContext_FieldNumber) {
+  GPBSourceContext_FieldNumber_FileName = 1,
+};
+
+/// `SourceContext` represents information about the source of a
+/// protobuf element, like the file in which it is defined.
+@interface GPBSourceContext : GPBMessage
+
+/// The path-qualified name of the .proto file that contained the associated
+/// protobuf element.  For example: `"google/protobuf/source.proto"`.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *fileName;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
new file mode 100644
index 0000000..9500712
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -0,0 +1,77 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBSourceContextRoot
+
+@implementation GPBSourceContextRoot
+
+@end
+
+#pragma mark - GPBSourceContextRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBSourceContext
+
+@implementation GPBSourceContext
+
+@dynamic fileName;
+
+typedef struct GPBSourceContext__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *fileName;
+} GPBSourceContext__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "fileName",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBSourceContext_FieldNumber_FileName,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBSourceContext__storage_, fileName),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBSourceContext class]
+                                     rootClass:[GPBSourceContextRoot class]
+                                          file:GPBSourceContextRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBSourceContext__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
new file mode 100644
index 0000000..3924b4b
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -0,0 +1,167 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+@class GPBListValue;
+@class GPBStruct;
+@class GPBValue;
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - Enum GPBNullValue
+
+/// `NullValue` is a singleton enumeration to represent the null value for the
+/// `Value` type union.
+///
+///  The JSON representation for `NullValue` is JSON `null`.
+typedef GPB_ENUM(GPBNullValue) {
+  /// Value used if any message's field encounters a value that is not defined
+  /// by this enum. The message will also have C functions to get/set the rawValue
+  /// of the field.
+  GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  /// Null value.
+  GPBNullValue_NullValue = 0,
+};
+
+GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void);
+
+/// Checks to see if the given value is defined by the enum or was not known at
+/// the time this source was generated.
+BOOL GPBNullValue_IsValidValue(int32_t value);
+
+#pragma mark - GPBStructRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBStructRoot : GPBRootObject
+@end
+
+#pragma mark - GPBStruct
+
+typedef GPB_ENUM(GPBStruct_FieldNumber) {
+  GPBStruct_FieldNumber_Fields = 1,
+};
+
+/// `Struct` represents a structured data value, consisting of fields
+/// which map to dynamically typed values. In some languages, `Struct`
+/// might be supported by a native representation. For example, in
+/// scripting languages like JS a struct is represented as an
+/// object. The details of that representation are described together
+/// with the proto support for the language.
+///
+/// The JSON representation for `Struct` is JSON object.
+@interface GPBStruct : GPBMessage
+
+/// Unordered map of dynamically typed values.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, GPBValue*> *fields;
+/// The number of items in @c fields without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger fields_Count;
+
+@end
+
+#pragma mark - GPBValue
+
+typedef GPB_ENUM(GPBValue_FieldNumber) {
+  GPBValue_FieldNumber_NullValue = 1,
+  GPBValue_FieldNumber_NumberValue = 2,
+  GPBValue_FieldNumber_StringValue = 3,
+  GPBValue_FieldNumber_BoolValue = 4,
+  GPBValue_FieldNumber_StructValue = 5,
+  GPBValue_FieldNumber_ListValue = 6,
+};
+
+typedef GPB_ENUM(GPBValue_Kind_OneOfCase) {
+  GPBValue_Kind_OneOfCase_GPBUnsetOneOfCase = 0,
+  GPBValue_Kind_OneOfCase_NullValue = 1,
+  GPBValue_Kind_OneOfCase_NumberValue = 2,
+  GPBValue_Kind_OneOfCase_StringValue = 3,
+  GPBValue_Kind_OneOfCase_BoolValue = 4,
+  GPBValue_Kind_OneOfCase_StructValue = 5,
+  GPBValue_Kind_OneOfCase_ListValue = 6,
+};
+
+/// `Value` represents a dynamically typed value which can be either
+/// null, a number, a string, a boolean, a recursive struct value, or a
+/// list of values. A producer of value is expected to set one of that
+/// variants, absence of any variant indicates an error.
+///
+/// The JSON representation for `Value` is JSON value.
+@interface GPBValue : GPBMessage
+
+/// The kind of value.
+@property(nonatomic, readonly) GPBValue_Kind_OneOfCase kindOneOfCase;
+
+/// Represents a null value.
+@property(nonatomic, readwrite) GPBNullValue nullValue;
+
+/// Represents a double value.
+@property(nonatomic, readwrite) double numberValue;
+
+/// Represents a string value.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;
+
+/// Represents a boolean value.
+@property(nonatomic, readwrite) BOOL boolValue;
+
+/// Represents a structured value.
+@property(nonatomic, readwrite, strong, null_resettable) GPBStruct *structValue;
+
+/// Represents a repeated `Value`.
+@property(nonatomic, readwrite, strong, null_resettable) GPBListValue *listValue;
+
+@end
+
+/// Fetches the raw value of a @c GPBValue's @c nullValue property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBValue_NullValue_RawValue(GPBValue *message);
+/// Sets the raw value of an @c GPBValue's @c nullValue property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value);
+
+/// Clears whatever value was set for the oneof 'kind'.
+void GPBValue_ClearKindOneOfCase(GPBValue *message);
+
+#pragma mark - GPBListValue
+
+typedef GPB_ENUM(GPBListValue_FieldNumber) {
+  GPBListValue_FieldNumber_ValuesArray = 1,
+};
+
+/// `ListValue` is a wrapper around a repeated field of values.
+///
+/// The JSON representation for `ListValue` is JSON array.
+@interface GPBListValue : GPBMessage
+
+/// Repeated field of dynamically typed values.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBValue*> *valuesArray;
+/// The number of items in @c valuesArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger valuesArray_Count;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
new file mode 100644
index 0000000..6094002
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -0,0 +1,273 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Struct.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBStructRoot
+
+@implementation GPBStructRoot
+
+@end
+
+#pragma mark - GPBStructRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - Enum GPBNullValue
+
+GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static const char *valueNames =
+        "NullValue\000";
+    static const int32_t values[] = {
+        GPBNullValue_NullValue,
+    };
+    GPBEnumDescriptor *worker =
+        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue)
+                                       valueNames:valueNames
+                                           values:values
+                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))
+                                     enumVerifier:GPBNullValue_IsValidValue];
+    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {
+      [worker release];
+    }
+  }
+  return descriptor;
+}
+
+BOOL GPBNullValue_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBNullValue_NullValue:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBStruct
+
+@implementation GPBStruct
+
+@dynamic fields, fields_Count;
+
+typedef struct GPBStruct__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableDictionary *fields;
+} GPBStruct__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "fields",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBValue),
+        .number = GPBStruct_FieldNumber_Fields,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBStruct__storage_, fields),
+        .flags = GPBFieldMapKeyString,
+        .dataType = GPBDataTypeMessage,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBStruct class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBStruct__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBValue
+
+@implementation GPBValue
+
+@dynamic kindOneOfCase;
+@dynamic nullValue;
+@dynamic numberValue;
+@dynamic stringValue;
+@dynamic boolValue;
+@dynamic structValue;
+@dynamic listValue;
+
+typedef struct GPBValue__storage_ {
+  uint32_t _has_storage_[2];
+  GPBNullValue nullValue;
+  NSString *stringValue;
+  GPBStruct *structValue;
+  GPBListValue *listValue;
+  double numberValue;
+} GPBValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "nullValue",
+        .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor,
+        .number = GPBValue_FieldNumber_NullValue,
+        .hasIndex = -1,
+        .offset = (uint32_t)offsetof(GPBValue__storage_, nullValue),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+      {
+        .name = "numberValue",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBValue_FieldNumber_NumberValue,
+        .hasIndex = -1,
+        .offset = (uint32_t)offsetof(GPBValue__storage_, numberValue),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeDouble,
+      },
+      {
+        .name = "stringValue",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBValue_FieldNumber_StringValue,
+        .hasIndex = -1,
+        .offset = (uint32_t)offsetof(GPBValue__storage_, stringValue),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "boolValue",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBValue_FieldNumber_BoolValue,
+        .hasIndex = -1,
+        .offset = 0,  // Stored in _has_storage_ to save space.
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+      },
+      {
+        .name = "structValue",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct),
+        .number = GPBValue_FieldNumber_StructValue,
+        .hasIndex = -1,
+        .offset = (uint32_t)offsetof(GPBValue__storage_, structValue),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "listValue",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue),
+        .number = GPBValue_FieldNumber_ListValue,
+        .hasIndex = -1,
+        .offset = (uint32_t)offsetof(GPBValue__storage_, listValue),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBValue class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBValue__storage_)
+                                         flags:0];
+    static const char *oneofs[] = {
+      "kind",
+    };
+    [localDescriptor setupOneofs:oneofs
+                           count:(uint32_t)(sizeof(oneofs) / sizeof(char*))
+                   firstHasIndex:-1];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBValue_NullValue_RawValue(GPBValue *message) {
+  GPBDescriptor *descriptor = [GPBValue descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBValue descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+void GPBValue_ClearKindOneOfCase(GPBValue *message) {
+  GPBDescriptor *descriptor = [message descriptor];
+  GPBOneofDescriptor *oneof = descriptor->oneofs_[0];
+  GPBMaybeClearOneof(message, oneof, -1, 0);
+}
+#pragma mark - GPBListValue
+
+@implementation GPBListValue
+
+@dynamic valuesArray, valuesArray_Count;
+
+typedef struct GPBListValue__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *valuesArray;
+} GPBListValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "valuesArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBValue),
+        .number = GPBListValue_FieldNumber_ValuesArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBListValue__storage_, valuesArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBListValue class]
+                                     rootClass:[GPBStructRoot class]
+                                          file:GPBStructRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBListValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
new file mode 100644
index 0000000..925dca8
--- /dev/null
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -0,0 +1,113 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBTimestampRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBTimestampRoot : GPBRootObject
+@end
+
+#pragma mark - GPBTimestamp
+
+typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
+  GPBTimestamp_FieldNumber_Seconds = 1,
+  GPBTimestamp_FieldNumber_Nanos = 2,
+};
+
+/// A Timestamp represents a point in time independent of any time zone
+/// or calendar, represented as seconds and fractions of seconds at
+/// nanosecond resolution in UTC Epoch time. It is encoded using the
+/// Proleptic Gregorian Calendar which extends the Gregorian calendar
+/// backwards to year one. It is encoded assuming all minutes are 60
+/// seconds long, i.e. leap seconds are "smeared" so that no leap second
+/// table is needed for interpretation. Range is from
+/// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+/// By restricting to that range, we ensure that we can convert to
+/// and from  RFC 3339 date strings.
+/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+///
+/// Example 1: Compute Timestamp from POSIX `time()`.
+///
+///     Timestamp timestamp;
+///     timestamp.set_seconds(time(NULL));
+///     timestamp.set_nanos(0);
+///
+/// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+///
+///     struct timeval tv;
+///     gettimeofday(&tv, NULL);
+///
+///     Timestamp timestamp;
+///     timestamp.set_seconds(tv.tv_sec);
+///     timestamp.set_nanos(tv.tv_usec * 1000);
+///
+/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+///
+///     FILETIME ft;
+///     GetSystemTimeAsFileTime(&ft);
+///     UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+///
+///     // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+///     // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+///     Timestamp timestamp;
+///     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+///     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+///
+/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+///
+///     long millis = System.currentTimeMillis();
+///
+///     Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+///         .setNanos((int) ((millis % 1000) * 1000000)).build();
+///
+///
+/// Example 5: Compute Timestamp from current time in Python.
+///
+///     now = time.time()
+///     seconds = int(now)
+///     nanos = int((now - seconds) * 10**9)
+///     timestamp = Timestamp(seconds=seconds, nanos=nanos)
+@interface GPBTimestamp : GPBMessage
+
+/// Represents seconds of UTC time since Unix epoch
+/// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+/// 9999-12-31T23:59:59Z inclusive.
+@property(nonatomic, readwrite) int64_t seconds;
+
+/// Non-negative fractions of a second at nanosecond resolution. Negative
+/// second values with fractions must still have non-negative nanos values
+/// that count forward in time. Must be from 0 to 999,999,999
+/// inclusive.
+@property(nonatomic, readwrite) int32_t nanos;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
new file mode 100644
index 0000000..f35e435
--- /dev/null
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -0,0 +1,88 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Timestamp.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBTimestampRoot
+
+@implementation GPBTimestampRoot
+
+@end
+
+#pragma mark - GPBTimestampRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBTimestamp
+
+@implementation GPBTimestamp
+
+@dynamic seconds;
+@dynamic nanos;
+
+typedef struct GPBTimestamp__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t nanos;
+  int64_t seconds;
+} GPBTimestamp__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "seconds",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBTimestamp_FieldNumber_Seconds,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBTimestamp__storage_, seconds),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+      },
+      {
+        .name = "nanos",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBTimestamp_FieldNumber_Nanos,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBTimestamp__storage_, nanos),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBTimestamp class]
+                                     rootClass:[GPBTimestampRoot class]
+                                          file:GPBTimestampRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBTimestamp__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
new file mode 100644
index 0000000..590d970
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -0,0 +1,373 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+@class GPBAny;
+@class GPBEnumValue;
+@class GPBField;
+@class GPBOption;
+@class GPBSourceContext;
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - Enum GPBSyntax
+
+/// The syntax in which a protocol buffer element is defined.
+typedef GPB_ENUM(GPBSyntax) {
+  /// Value used if any message's field encounters a value that is not defined
+  /// by this enum. The message will also have C functions to get/set the rawValue
+  /// of the field.
+  GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  /// Syntax `proto2`.
+  GPBSyntax_SyntaxProto2 = 0,
+
+  /// Syntax `proto3`.
+  GPBSyntax_SyntaxProto3 = 1,
+};
+
+GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void);
+
+/// Checks to see if the given value is defined by the enum or was not known at
+/// the time this source was generated.
+BOOL GPBSyntax_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBField_Kind
+
+/// Basic field types.
+typedef GPB_ENUM(GPBField_Kind) {
+  /// Value used if any message's field encounters a value that is not defined
+  /// by this enum. The message will also have C functions to get/set the rawValue
+  /// of the field.
+  GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  /// Field type unknown.
+  GPBField_Kind_TypeUnknown = 0,
+
+  /// Field type double.
+  GPBField_Kind_TypeDouble = 1,
+
+  /// Field type float.
+  GPBField_Kind_TypeFloat = 2,
+
+  /// Field type int64.
+  GPBField_Kind_TypeInt64 = 3,
+
+  /// Field type uint64.
+  GPBField_Kind_TypeUint64 = 4,
+
+  /// Field type int32.
+  GPBField_Kind_TypeInt32 = 5,
+
+  /// Field type fixed64.
+  GPBField_Kind_TypeFixed64 = 6,
+
+  /// Field type fixed32.
+  GPBField_Kind_TypeFixed32 = 7,
+
+  /// Field type bool.
+  GPBField_Kind_TypeBool = 8,
+
+  /// Field type string.
+  GPBField_Kind_TypeString = 9,
+
+  /// Field type group. Proto2 syntax only, and deprecated.
+  GPBField_Kind_TypeGroup = 10,
+
+  /// Field type message.
+  GPBField_Kind_TypeMessage = 11,
+
+  /// Field type bytes.
+  GPBField_Kind_TypeBytes = 12,
+
+  /// Field type uint32.
+  GPBField_Kind_TypeUint32 = 13,
+
+  /// Field type enum.
+  GPBField_Kind_TypeEnum = 14,
+
+  /// Field type sfixed32.
+  GPBField_Kind_TypeSfixed32 = 15,
+
+  /// Field type sfixed64.
+  GPBField_Kind_TypeSfixed64 = 16,
+
+  /// Field type sint32.
+  GPBField_Kind_TypeSint32 = 17,
+
+  /// Field type sint64.
+  GPBField_Kind_TypeSint64 = 18,
+};
+
+GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void);
+
+/// Checks to see if the given value is defined by the enum or was not known at
+/// the time this source was generated.
+BOOL GPBField_Kind_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBField_Cardinality
+
+/// Whether a field is optional, required, or repeated.
+typedef GPB_ENUM(GPBField_Cardinality) {
+  /// Value used if any message's field encounters a value that is not defined
+  /// by this enum. The message will also have C functions to get/set the rawValue
+  /// of the field.
+  GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  /// For fields with unknown cardinality.
+  GPBField_Cardinality_CardinalityUnknown = 0,
+
+  /// For optional fields.
+  GPBField_Cardinality_CardinalityOptional = 1,
+
+  /// For required fields. Proto2 syntax only.
+  GPBField_Cardinality_CardinalityRequired = 2,
+
+  /// For repeated fields.
+  GPBField_Cardinality_CardinalityRepeated = 3,
+};
+
+GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void);
+
+/// Checks to see if the given value is defined by the enum or was not known at
+/// the time this source was generated.
+BOOL GPBField_Cardinality_IsValidValue(int32_t value);
+
+#pragma mark - GPBTypeRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBTypeRoot : GPBRootObject
+@end
+
+#pragma mark - GPBType
+
+typedef GPB_ENUM(GPBType_FieldNumber) {
+  GPBType_FieldNumber_Name = 1,
+  GPBType_FieldNumber_FieldsArray = 2,
+  GPBType_FieldNumber_OneofsArray = 3,
+  GPBType_FieldNumber_OptionsArray = 4,
+  GPBType_FieldNumber_SourceContext = 5,
+  GPBType_FieldNumber_Syntax = 6,
+};
+
+/// A protocol buffer message type.
+@interface GPBType : GPBMessage
+
+/// The fully qualified message name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// The list of fields.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBField*> *fieldsArray;
+/// The number of items in @c fieldsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger fieldsArray_Count;
+
+/// The list of types appearing in `oneof` definitions in this type.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *oneofsArray;
+/// The number of items in @c oneofsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger oneofsArray_Count;
+
+/// The protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+/// The source context.
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+/// Test to see if @c sourceContext has been set.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+
+/// The source syntax.
+@property(nonatomic, readwrite) GPBSyntax syntax;
+
+@end
+
+/// Fetches the raw value of a @c GPBType's @c syntax property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBType_Syntax_RawValue(GPBType *message);
+/// Sets the raw value of an @c GPBType's @c syntax property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value);
+
+#pragma mark - GPBField
+
+typedef GPB_ENUM(GPBField_FieldNumber) {
+  GPBField_FieldNumber_Kind = 1,
+  GPBField_FieldNumber_Cardinality = 2,
+  GPBField_FieldNumber_Number = 3,
+  GPBField_FieldNumber_Name = 4,
+  GPBField_FieldNumber_TypeURL = 6,
+  GPBField_FieldNumber_OneofIndex = 7,
+  GPBField_FieldNumber_Packed = 8,
+  GPBField_FieldNumber_OptionsArray = 9,
+  GPBField_FieldNumber_JsonName = 10,
+  GPBField_FieldNumber_DefaultValue = 11,
+};
+
+/// A single field of a message type.
+@interface GPBField : GPBMessage
+
+/// The field type.
+@property(nonatomic, readwrite) GPBField_Kind kind;
+
+/// The field cardinality.
+@property(nonatomic, readwrite) GPBField_Cardinality cardinality;
+
+/// The field number.
+@property(nonatomic, readwrite) int32_t number;
+
+/// The field name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// The field type URL, without the scheme, for message or enumeration
+/// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL;
+
+/// The index of the field type in `Type.oneofs`, for message or enumeration
+/// types. The first type has index 1; zero means the type is not in the list.
+@property(nonatomic, readwrite) int32_t oneofIndex;
+
+/// Whether to use alternative packed wire representation.
+@property(nonatomic, readwrite) BOOL packed;
+
+/// The protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+/// The field JSON name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName;
+
+/// The string value of the default value of this field. Proto2 syntax only.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue;
+
+@end
+
+/// Fetches the raw value of a @c GPBField's @c kind property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBField_Kind_RawValue(GPBField *message);
+/// Sets the raw value of an @c GPBField's @c kind property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBField_Kind_RawValue(GPBField *message, int32_t value);
+
+/// Fetches the raw value of a @c GPBField's @c cardinality property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBField_Cardinality_RawValue(GPBField *message);
+/// Sets the raw value of an @c GPBField's @c cardinality property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value);
+
+#pragma mark - GPBEnum
+
+typedef GPB_ENUM(GPBEnum_FieldNumber) {
+  GPBEnum_FieldNumber_Name = 1,
+  GPBEnum_FieldNumber_EnumvalueArray = 2,
+  GPBEnum_FieldNumber_OptionsArray = 3,
+  GPBEnum_FieldNumber_SourceContext = 4,
+  GPBEnum_FieldNumber_Syntax = 5,
+};
+
+/// Enum type definition.
+@interface GPBEnum : GPBMessage
+
+/// Enum type name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// Enum value definitions.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValue*> *enumvalueArray;
+/// The number of items in @c enumvalueArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
+
+/// Protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+/// The source context.
+@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
+/// Test to see if @c sourceContext has been set.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+
+/// The source syntax.
+@property(nonatomic, readwrite) GPBSyntax syntax;
+
+@end
+
+/// Fetches the raw value of a @c GPBEnum's @c syntax property, even
+/// if the value was not defined by the enum at the time the code was generated.
+int32_t GPBEnum_Syntax_RawValue(GPBEnum *message);
+/// Sets the raw value of an @c GPBEnum's @c syntax property, allowing
+/// it to be set to a value that was not defined by the enum at the time the code
+/// was generated.
+void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value);
+
+#pragma mark - GPBEnumValue
+
+typedef GPB_ENUM(GPBEnumValue_FieldNumber) {
+  GPBEnumValue_FieldNumber_Name = 1,
+  GPBEnumValue_FieldNumber_Number = 2,
+  GPBEnumValue_FieldNumber_OptionsArray = 3,
+};
+
+/// Enum value definition.
+@interface GPBEnumValue : GPBMessage
+
+/// Enum value name.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// Enum value number.
+@property(nonatomic, readwrite) int32_t number;
+
+/// Protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
+/// The number of items in @c optionsArray without causing the array to be created.
+@property(nonatomic, readonly) NSUInteger optionsArray_Count;
+
+@end
+
+#pragma mark - GPBOption
+
+typedef GPB_ENUM(GPBOption_FieldNumber) {
+  GPBOption_FieldNumber_Name = 1,
+  GPBOption_FieldNumber_Value = 2,
+};
+
+/// A protocol buffer option, which can be attached to a message, field,
+/// enumeration, etc.
+@interface GPBOption : GPBMessage
+
+/// The option's name. For example, `"java_package"`.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
+
+/// The option's value. For example, `"com.google.protobuf"`.
+@property(nonatomic, readwrite, strong, null_resettable) GPBAny *value;
+/// Test to see if @c value has been set.
+@property(nonatomic, readwrite) BOOL hasValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
new file mode 100644
index 0000000..5554a22
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -0,0 +1,693 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Type.pbobjc.h"
+#import "google/protobuf/Any.pbobjc.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBTypeRoot
+
+@implementation GPBTypeRoot
+
++ (GPBExtensionRegistry*)extensionRegistry {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety and initialization of registry.
+  static GPBExtensionRegistry* registry = nil;
+  if (!registry) {
+    GPBDebugCheckRuntimeVersion();
+    registry = [[GPBExtensionRegistry alloc] init];
+    [registry addExtensions:[GPBAnyRoot extensionRegistry]];
+    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
+  }
+  return registry;
+}
+
+@end
+
+#pragma mark - GPBTypeRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - Enum GPBSyntax
+
+GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static const char *valueNames =
+        "SyntaxProto2\000SyntaxProto3\000";
+    static const int32_t values[] = {
+        GPBSyntax_SyntaxProto2,
+        GPBSyntax_SyntaxProto3,
+    };
+    GPBEnumDescriptor *worker =
+        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax)
+                                       valueNames:valueNames
+                                           values:values
+                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))
+                                     enumVerifier:GPBSyntax_IsValidValue];
+    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {
+      [worker release];
+    }
+  }
+  return descriptor;
+}
+
+BOOL GPBSyntax_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBSyntax_SyntaxProto2:
+    case GPBSyntax_SyntaxProto3:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBType
+
+@implementation GPBType
+
+@dynamic name;
+@dynamic fieldsArray, fieldsArray_Count;
+@dynamic oneofsArray, oneofsArray_Count;
+@dynamic optionsArray, optionsArray_Count;
+@dynamic hasSourceContext, sourceContext;
+@dynamic syntax;
+
+typedef struct GPBType__storage_ {
+  uint32_t _has_storage_[1];
+  GPBSyntax syntax;
+  NSString *name;
+  NSMutableArray *fieldsArray;
+  NSMutableArray *oneofsArray;
+  NSMutableArray *optionsArray;
+  GPBSourceContext *sourceContext;
+} GPBType__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBType_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBType__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "fieldsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBField),
+        .number = GPBType_FieldNumber_FieldsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBType__storage_, fieldsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "oneofsArray",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBType_FieldNumber_OneofsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBType__storage_, oneofsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBType_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBType__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "sourceContext",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .number = GPBType_FieldNumber_SourceContext,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBType__storage_, sourceContext),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "syntax",
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .number = GPBType_FieldNumber_Syntax,
+        .hasIndex = 2,
+        .offset = (uint32_t)offsetof(GPBType__storage_, syntax),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBType class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBType__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBType_Syntax_RawValue(GPBType *message) {
+  GPBDescriptor *descriptor = [GPBType descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBType descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - GPBField
+
+@implementation GPBField
+
+@dynamic kind;
+@dynamic cardinality;
+@dynamic number;
+@dynamic name;
+@dynamic typeURL;
+@dynamic oneofIndex;
+@dynamic packed;
+@dynamic optionsArray, optionsArray_Count;
+@dynamic jsonName;
+@dynamic defaultValue;
+
+typedef struct GPBField__storage_ {
+  uint32_t _has_storage_[1];
+  GPBField_Kind kind;
+  GPBField_Cardinality cardinality;
+  int32_t number;
+  int32_t oneofIndex;
+  NSString *name;
+  NSString *typeURL;
+  NSMutableArray *optionsArray;
+  NSString *jsonName;
+  NSString *defaultValue;
+} GPBField__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "kind",
+        .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor,
+        .number = GPBField_FieldNumber_Kind,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBField__storage_, kind),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+      {
+        .name = "cardinality",
+        .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor,
+        .number = GPBField_FieldNumber_Cardinality,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBField__storage_, cardinality),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+      {
+        .name = "number",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_Number,
+        .hasIndex = 2,
+        .offset = (uint32_t)offsetof(GPBField__storage_, number),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_Name,
+        .hasIndex = 3,
+        .offset = (uint32_t)offsetof(GPBField__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "typeURL",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_TypeURL,
+        .hasIndex = 4,
+        .offset = (uint32_t)offsetof(GPBField__storage_, typeURL),
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "oneofIndex",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_OneofIndex,
+        .hasIndex = 5,
+        .offset = (uint32_t)offsetof(GPBField__storage_, oneofIndex),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+      {
+        .name = "packed",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_Packed,
+        .hasIndex = 6,
+        .offset = 7,  // Stored in _has_storage_ to save space.
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBField_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBField__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "jsonName",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_JsonName,
+        .hasIndex = 8,
+        .offset = (uint32_t)offsetof(GPBField__storage_, jsonName),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "defaultValue",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBField_FieldNumber_DefaultValue,
+        .hasIndex = 9,
+        .offset = (uint32_t)offsetof(GPBField__storage_, defaultValue),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBField class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBField__storage_)
+                                         flags:0];
+#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    static const char *extraTextFormatInfo =
+        "\001\006\004\241!!\000";
+    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];
+#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBField_Kind_RawValue(GPBField *message) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBField_Kind_RawValue(GPBField *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+int32_t GPBField_Cardinality_RawValue(GPBField *message) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - Enum GPBField_Kind
+
+GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static const char *valueNames =
+        "TypeUnknown\000TypeDouble\000TypeFloat\000TypeInt"
+        "64\000TypeUint64\000TypeInt32\000TypeFixed64\000Type"
+        "Fixed32\000TypeBool\000TypeString\000TypeGroup\000Ty"
+        "peMessage\000TypeBytes\000TypeUint32\000TypeEnum\000"
+        "TypeSfixed32\000TypeSfixed64\000TypeSint32\000Typ"
+        "eSint64\000";
+    static const int32_t values[] = {
+        GPBField_Kind_TypeUnknown,
+        GPBField_Kind_TypeDouble,
+        GPBField_Kind_TypeFloat,
+        GPBField_Kind_TypeInt64,
+        GPBField_Kind_TypeUint64,
+        GPBField_Kind_TypeInt32,
+        GPBField_Kind_TypeFixed64,
+        GPBField_Kind_TypeFixed32,
+        GPBField_Kind_TypeBool,
+        GPBField_Kind_TypeString,
+        GPBField_Kind_TypeGroup,
+        GPBField_Kind_TypeMessage,
+        GPBField_Kind_TypeBytes,
+        GPBField_Kind_TypeUint32,
+        GPBField_Kind_TypeEnum,
+        GPBField_Kind_TypeSfixed32,
+        GPBField_Kind_TypeSfixed64,
+        GPBField_Kind_TypeSint32,
+        GPBField_Kind_TypeSint64,
+    };
+    GPBEnumDescriptor *worker =
+        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind)
+                                       valueNames:valueNames
+                                           values:values
+                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))
+                                     enumVerifier:GPBField_Kind_IsValidValue];
+    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {
+      [worker release];
+    }
+  }
+  return descriptor;
+}
+
+BOOL GPBField_Kind_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBField_Kind_TypeUnknown:
+    case GPBField_Kind_TypeDouble:
+    case GPBField_Kind_TypeFloat:
+    case GPBField_Kind_TypeInt64:
+    case GPBField_Kind_TypeUint64:
+    case GPBField_Kind_TypeInt32:
+    case GPBField_Kind_TypeFixed64:
+    case GPBField_Kind_TypeFixed32:
+    case GPBField_Kind_TypeBool:
+    case GPBField_Kind_TypeString:
+    case GPBField_Kind_TypeGroup:
+    case GPBField_Kind_TypeMessage:
+    case GPBField_Kind_TypeBytes:
+    case GPBField_Kind_TypeUint32:
+    case GPBField_Kind_TypeEnum:
+    case GPBField_Kind_TypeSfixed32:
+    case GPBField_Kind_TypeSfixed64:
+    case GPBField_Kind_TypeSint32:
+    case GPBField_Kind_TypeSint64:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - Enum GPBField_Cardinality
+
+GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static const char *valueNames =
+        "CardinalityUnknown\000CardinalityOptional\000C"
+        "ardinalityRequired\000CardinalityRepeated\000";
+    static const int32_t values[] = {
+        GPBField_Cardinality_CardinalityUnknown,
+        GPBField_Cardinality_CardinalityOptional,
+        GPBField_Cardinality_CardinalityRequired,
+        GPBField_Cardinality_CardinalityRepeated,
+    };
+    GPBEnumDescriptor *worker =
+        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality)
+                                       valueNames:valueNames
+                                           values:values
+                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))
+                                     enumVerifier:GPBField_Cardinality_IsValidValue];
+    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {
+      [worker release];
+    }
+  }
+  return descriptor;
+}
+
+BOOL GPBField_Cardinality_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBField_Cardinality_CardinalityUnknown:
+    case GPBField_Cardinality_CardinalityOptional:
+    case GPBField_Cardinality_CardinalityRequired:
+    case GPBField_Cardinality_CardinalityRepeated:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBEnum
+
+@implementation GPBEnum
+
+@dynamic name;
+@dynamic enumvalueArray, enumvalueArray_Count;
+@dynamic optionsArray, optionsArray_Count;
+@dynamic hasSourceContext, sourceContext;
+@dynamic syntax;
+
+typedef struct GPBEnum__storage_ {
+  uint32_t _has_storage_[1];
+  GPBSyntax syntax;
+  NSString *name;
+  NSMutableArray *enumvalueArray;
+  NSMutableArray *optionsArray;
+  GPBSourceContext *sourceContext;
+} GPBEnum__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBEnum_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBEnum__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "enumvalueArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue),
+        .number = GPBEnum_FieldNumber_EnumvalueArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBEnum__storage_, enumvalueArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBEnum_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBEnum__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "sourceContext",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .number = GPBEnum_FieldNumber_SourceContext,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBEnum__storage_, sourceContext),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+      {
+        .name = "syntax",
+        .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor,
+        .number = GPBEnum_FieldNumber_Syntax,
+        .hasIndex = 2,
+        .offset = (uint32_t)offsetof(GPBEnum__storage_, syntax),
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .dataType = GPBDataTypeEnum,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnum class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBEnum__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBEnum_Syntax_RawValue(GPBEnum *message) {
+  GPBDescriptor *descriptor = [GPBEnum descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax];
+  return GPBGetMessageInt32Field(message, field);
+}
+
+void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBEnum descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - GPBEnumValue
+
+@implementation GPBEnumValue
+
+@dynamic name;
+@dynamic number;
+@dynamic optionsArray, optionsArray_Count;
+
+typedef struct GPBEnumValue__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t number;
+  NSString *name;
+  NSMutableArray *optionsArray;
+} GPBEnumValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBEnumValue_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBEnumValue__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "number",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBEnumValue_FieldNumber_Number,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBEnumValue__storage_, number),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+      {
+        .name = "optionsArray",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBOption),
+        .number = GPBEnumValue_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .offset = (uint32_t)offsetof(GPBEnumValue__storage_, optionsArray),
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBEnumValue class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBEnumValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBOption
+
+@implementation GPBOption
+
+@dynamic name;
+@dynamic hasValue, value;
+
+typedef struct GPBOption__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  GPBAny *value;
+} GPBOption__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBOption_FieldNumber_Name,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBOption__storage_, name),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+      {
+        .name = "value",
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBAny),
+        .number = GPBOption_FieldNumber_Value,
+        .hasIndex = 1,
+        .offset = (uint32_t)offsetof(GPBOption__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeMessage,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBOption class]
+                                     rootClass:[GPBTypeRoot class]
+                                          file:GPBTypeRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBOption__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
new file mode 100644
index 0000000..4651050
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -0,0 +1,182 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+CF_EXTERN_C_BEGIN
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - GPBWrappersRoot
+
+/// Exposes the extension registry for this file.
+///
+/// The base class provides:
+/// @code
+///   + (GPBExtensionRegistry *)extensionRegistry;
+/// @endcode
+/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
+/// this file and all files that it depends on.
+@interface GPBWrappersRoot : GPBRootObject
+@end
+
+#pragma mark - GPBDoubleValue
+
+typedef GPB_ENUM(GPBDoubleValue_FieldNumber) {
+  GPBDoubleValue_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `double`.
+///
+/// The JSON representation for `DoubleValue` is JSON number.
+@interface GPBDoubleValue : GPBMessage
+
+/// The double value.
+@property(nonatomic, readwrite) double value;
+
+@end
+
+#pragma mark - GPBFloatValue
+
+typedef GPB_ENUM(GPBFloatValue_FieldNumber) {
+  GPBFloatValue_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `float`.
+///
+/// The JSON representation for `FloatValue` is JSON number.
+@interface GPBFloatValue : GPBMessage
+
+/// The float value.
+@property(nonatomic, readwrite) float value;
+
+@end
+
+#pragma mark - GPBInt64Value
+
+typedef GPB_ENUM(GPBInt64Value_FieldNumber) {
+  GPBInt64Value_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `int64`.
+///
+/// The JSON representation for `Int64Value` is JSON string.
+@interface GPBInt64Value : GPBMessage
+
+/// The int64 value.
+@property(nonatomic, readwrite) int64_t value;
+
+@end
+
+#pragma mark - GPBUInt64Value
+
+typedef GPB_ENUM(GPBUInt64Value_FieldNumber) {
+  GPBUInt64Value_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `uint64`.
+///
+/// The JSON representation for `UInt64Value` is JSON string.
+@interface GPBUInt64Value : GPBMessage
+
+/// The uint64 value.
+@property(nonatomic, readwrite) uint64_t value;
+
+@end
+
+#pragma mark - GPBInt32Value
+
+typedef GPB_ENUM(GPBInt32Value_FieldNumber) {
+  GPBInt32Value_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `int32`.
+///
+/// The JSON representation for `Int32Value` is JSON number.
+@interface GPBInt32Value : GPBMessage
+
+/// The int32 value.
+@property(nonatomic, readwrite) int32_t value;
+
+@end
+
+#pragma mark - GPBUInt32Value
+
+typedef GPB_ENUM(GPBUInt32Value_FieldNumber) {
+  GPBUInt32Value_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `uint32`.
+///
+/// The JSON representation for `UInt32Value` is JSON number.
+@interface GPBUInt32Value : GPBMessage
+
+/// The uint32 value.
+@property(nonatomic, readwrite) uint32_t value;
+
+@end
+
+#pragma mark - GPBBoolValue
+
+typedef GPB_ENUM(GPBBoolValue_FieldNumber) {
+  GPBBoolValue_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `bool`.
+///
+/// The JSON representation for `BoolValue` is JSON `true` and `false`.
+@interface GPBBoolValue : GPBMessage
+
+/// The bool value.
+@property(nonatomic, readwrite) BOOL value;
+
+@end
+
+#pragma mark - GPBStringValue
+
+typedef GPB_ENUM(GPBStringValue_FieldNumber) {
+  GPBStringValue_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `string`.
+///
+/// The JSON representation for `StringValue` is JSON string.
+@interface GPBStringValue : GPBMessage
+
+/// The string value.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *value;
+
+@end
+
+#pragma mark - GPBBytesValue
+
+typedef GPB_ENUM(GPBBytesValue_FieldNumber) {
+  GPBBytesValue_FieldNumber_Value = 1,
+};
+
+/// Wrapper message for `bytes`.
+///
+/// The JSON representation for `BytesValue` is JSON string.
+@interface GPBBytesValue : GPBMessage
+
+/// The bytes value.
+@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+CF_EXTERN_C_END
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
new file mode 100644
index 0000000..5cc6c2e
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -0,0 +1,420 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Wrappers.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#pragma mark - GPBWrappersRoot
+
+@implementation GPBWrappersRoot
+
+@end
+
+#pragma mark - GPBWrappersRoot_FileDescriptor
+
+static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    GPBDebugCheckRuntimeVersion();
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBDoubleValue
+
+@implementation GPBDoubleValue
+
+@dynamic value;
+
+typedef struct GPBDoubleValue__storage_ {
+  uint32_t _has_storage_[1];
+  double value;
+} GPBDoubleValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBDoubleValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBDoubleValue__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeDouble,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBDoubleValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBDoubleValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFloatValue
+
+@implementation GPBFloatValue
+
+@dynamic value;
+
+typedef struct GPBFloatValue__storage_ {
+  uint32_t _has_storage_[1];
+  float value;
+} GPBFloatValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBFloatValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBFloatValue__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeFloat,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBFloatValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBFloatValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBInt64Value
+
+@implementation GPBInt64Value
+
+@dynamic value;
+
+typedef struct GPBInt64Value__storage_ {
+  uint32_t _has_storage_[1];
+  int64_t value;
+} GPBInt64Value__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBInt64Value__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt64,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBInt64Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBInt64Value__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUInt64Value
+
+@implementation GPBUInt64Value
+
+@dynamic value;
+
+typedef struct GPBUInt64Value__storage_ {
+  uint32_t _has_storage_[1];
+  uint64_t value;
+} GPBUInt64Value__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBUInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBUInt64Value__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeUInt64,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUInt64Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBUInt64Value__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBInt32Value
+
+@implementation GPBInt32Value
+
+@dynamic value;
+
+typedef struct GPBInt32Value__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t value;
+} GPBInt32Value__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBInt32Value__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBInt32Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBInt32Value__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUInt32Value
+
+@implementation GPBUInt32Value
+
+@dynamic value;
+
+typedef struct GPBUInt32Value__storage_ {
+  uint32_t _has_storage_[1];
+  uint32_t value;
+} GPBUInt32Value__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBUInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBUInt32Value__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeUInt32,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBUInt32Value class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBUInt32Value__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBBoolValue
+
+@implementation GPBBoolValue
+
+@dynamic value;
+
+typedef struct GPBBoolValue__storage_ {
+  uint32_t _has_storage_[1];
+} GPBBoolValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBBoolValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = 1,  // Stored in _has_storage_ to save space.
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBool,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBBoolValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBBoolValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBStringValue
+
+@implementation GPBStringValue
+
+@dynamic value;
+
+typedef struct GPBStringValue__storage_ {
+  uint32_t _has_storage_[1];
+  NSString *value;
+} GPBStringValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBStringValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBStringValue__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBStringValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBStringValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBBytesValue
+
+@implementation GPBBytesValue
+
+@dynamic value;
+
+typedef struct GPBBytesValue__storage_ {
+  uint32_t _has_storage_[1];
+  NSData *value;
+} GPBBytesValue__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .dataTypeSpecific.className = NULL,
+        .number = GPBBytesValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .offset = (uint32_t)offsetof(GPBBytesValue__storage_, value),
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeBytes,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBBytesValue class]
+                                     rootClass:[GPBWrappersRoot class]
+                                          file:GPBWrappersRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
+                                   storageSize:sizeof(GPBBytesValue__storage_)
+                                         flags:0];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+
+#pragma clang diagnostic pop
+
+// @@protoc_insertion_point(global_scope)
diff --git a/php/ext/google/protobuf/config.m4 b/php/ext/google/protobuf/config.m4
new file mode 100644
index 0000000..b5946f7
--- /dev/null
+++ b/php/ext/google/protobuf/config.m4
@@ -0,0 +1,10 @@
+dnl lines starting with "dnl" are comments
+
+PHP_ARG_ENABLE(protobuf, whether to enable Protobuf extension, [  --enable-protobuf   Enable Protobuf extension])
+
+if test "$PHP_PROTOBUF" != "no"; then
+
+  dnl this defines the extension
+  PHP_NEW_EXTENSION(protobuf, upb.c protobuf.c def.c message.c storage.c, $ext_shared)
+
+fi
diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c
new file mode 100644
index 0000000..fc18806
--- /dev/null
+++ b/php/ext/google/protobuf/def.c
@@ -0,0 +1,381 @@
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Common Utilities
+// -----------------------------------------------------------------------------
+
+void check_upb_status(const upb_status* status, const char* msg) {
+  if (!upb_ok(status)) {
+    zend_error("%s: %s\n", msg, upb_status_errmsg(status));
+  }
+}
+
+
+static upb_def *check_notfrozen(const upb_def *def) {
+  if (upb_def_isfrozen(def)) {
+    zend_error(E_ERROR,
+               "Attempt to modify a frozen descriptor. Once descriptors are "
+               "added to the descriptor pool, they may not be modified.");
+  }
+  return (upb_def *)def;
+}
+
+static upb_msgdef *check_msgdef_notfrozen(const upb_msgdef *def) {
+  return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def *)def));
+}
+
+static upb_fielddef *check_fielddef_notfrozen(const upb_fielddef *def) {
+  return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def *)def));
+}
+
+#define PROTOBUF_WRAP_INTERN(wrapper, intern, intern_dtor)            \
+  Z_TYPE_P(wrapper) = IS_OBJECT;                                      \
+  Z_OBJVAL_P(wrapper)                                                 \
+      .handle = zend_objects_store_put(                               \
+      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \
+      intern_dtor, NULL TSRMLS_CC);                                   \
+  Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers();
+
+#define PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper,    \
+                                    intern)                                   \
+  Z_TYPE_P(wrapper) = IS_OBJECT;                                              \
+  class_name *intern = ALLOC(class_name);                                     \
+  memset(intern, 0, sizeof(class_name));                                      \
+  class_name_lower##_init_c_instance(intern TSRMLS_CC);                       \
+  Z_OBJVAL_P(wrapper)                                                         \
+      .handle = zend_objects_store_put(intern, NULL, class_name_lower##_free, \
+                                       NULL TSRMLS_CC);                       \
+  Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers();
+
+#define PROTOBUF_CREATE_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \
+                                     intern)                                \
+  MAKE_STD_ZVAL(wrapper);                                                   \
+  PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, intern);
+
+#define DEFINE_CLASS(name, name_lower, string_name)                          \
+  zend_class_entry *name_lower##_type;                                       \
+  void name_lower##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods);         \
+    name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
+    name_lower##_type->create_object = name_lower##_create;                  \
+  }                                                                          \
+  name *php_to_##name_lower(zval *val TSRMLS_DC) {                           \
+    return (name *)zend_object_store_get_object(val TSRMLS_CC);              \
+  }                                                                          \
+  void name_lower##_free(void *object TSRMLS_DC) {                           \
+    name *intern = (name *)object;                                           \
+    name_lower##_free_c(intern TSRMLS_CC);                                   \
+    efree(object);                                                           \
+  }                                                                          \
+  zend_object_value name_lower##_create(zend_class_entry *ce TSRMLS_DC) {    \
+    zend_object_value return_value;                                          \
+    name *intern = (name *)emalloc(sizeof(name));                            \
+    memset(intern, 0, sizeof(name));                                         \
+    name_lower##_init_c_instance(intern TSRMLS_CC);                          \
+    return_value.handle = zend_objects_store_put(                            \
+        intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,      \
+        name_lower##_free, NULL TSRMLS_CC);                                  \
+    return_value.handlers = zend_get_std_object_handlers();                  \
+    return return_value;                                                     \
+  }
+
+// -----------------------------------------------------------------------------
+// DescriptorPool
+// -----------------------------------------------------------------------------
+
+static zend_function_entry descriptor_pool_methods[] = {
+  PHP_ME(DescriptorPool, addMessage, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(DescriptorPool, finalize, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(DescriptorPool, descriptor_pool,
+             "Google\\Protobuf\\DescriptorPool");
+
+DescriptorPool *generated_pool;  // The actual generated pool
+
+ZEND_FUNCTION(get_generated_pool) {
+  if (PROTOBUF_G(generated_pool) == NULL) {
+    MAKE_STD_ZVAL(PROTOBUF_G(generated_pool));
+    Z_TYPE_P(PROTOBUF_G(generated_pool)) = IS_OBJECT;
+    generated_pool = ALLOC(DescriptorPool);
+    descriptor_pool_init_c_instance(generated_pool TSRMLS_CC);
+    Z_OBJ_HANDLE_P(PROTOBUF_G(generated_pool)) = zend_objects_store_put(
+        generated_pool, NULL,
+        (zend_objects_free_object_storage_t)descriptor_pool_free, NULL TSRMLS_CC);
+    Z_OBJ_HT_P(PROTOBUF_G(generated_pool)) = zend_get_std_object_handlers();
+  }
+  RETURN_ZVAL(PROTOBUF_G(generated_pool), 1, 0);
+}
+
+void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC) {
+  zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC);
+  pool->symtab = upb_symtab_new(&pool->symtab);
+
+  ALLOC_HASHTABLE(pool->pending_list);
+  zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
+}
+
+void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) {
+  upb_symtab_unref(pool->symtab, &pool->symtab);
+  zend_hash_destroy(pool->pending_list);
+  FREE_HASHTABLE(pool->pending_list);
+}
+
+PHP_METHOD(DescriptorPool, addMessage) {
+  char *name = NULL;
+  int str_len;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &str_len) ==
+      FAILURE) {
+    return;
+  }
+
+  zval* retval = NULL;
+  PROTOBUF_CREATE_ZEND_WRAPPER(MessageBuilderContext, message_builder_context,
+                               retval, context);
+
+  MAKE_STD_ZVAL(context->pool);
+  ZVAL_ZVAL(context->pool, getThis(), 1, 0);
+
+  Descriptor *desc = php_to_descriptor(context->descriptor TSRMLS_CC);
+  Descriptor_name_set(desc, name);
+
+  RETURN_ZVAL(retval, 0, 1);
+}
+
+static void validate_msgdef(const upb_msgdef* msgdef) {
+  // Verify that no required fields exist. proto3 does not support these.
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
+      zend_error(E_ERROR, "Required fields are unsupported in proto3.");
+    }
+  }
+}
+
+PHP_METHOD(DescriptorPool, finalize) {
+  DescriptorPool *self = php_to_descriptor_pool(getThis() TSRMLS_CC);
+  Bucket *temp;
+  int i, num;
+
+  num = zend_hash_num_elements(self->pending_list);
+  upb_def **defs = emalloc(sizeof(upb_def *) * num);
+
+  for (i = 0, temp = self->pending_list->pListHead; temp != NULL;
+       temp = temp->pListNext) {
+    zval *def_php = *(zval **)temp->pData;
+    Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC);
+    defs[i] = (upb_def *)desc->msgdef;
+    validate_msgdef((const upb_msgdef *)defs[i++]);
+  }
+
+  CHECK_UPB(upb_symtab_add(self->symtab, (upb_def **)defs, num, NULL, &status),
+            "Unable to add defs to DescriptorPool");
+
+  for (temp = self->pending_list->pListHead; temp != NULL;
+       temp = temp->pListNext) {
+    // zval *def_php = *(zval **)temp->pData;
+    // Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC);
+    build_class_from_descriptor((zval *)temp->pDataPtr TSRMLS_CC);
+  }
+
+  FREE(defs);
+  zend_hash_destroy(self->pending_list);
+  zend_hash_init(self->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
+}
+
+// -----------------------------------------------------------------------------
+// Descriptor
+// -----------------------------------------------------------------------------
+
+static zend_function_entry descriptor_methods[] = {
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor");
+
+void descriptor_free_c(Descriptor *self TSRMLS_DC) {
+  upb_msg_field_iter iter;
+  upb_msg_field_begin(&iter, self->msgdef);
+  while (!upb_msg_field_done(&iter)) {
+    upb_fielddef *fielddef = upb_msg_iter_field(&iter);
+    upb_fielddef_unref(fielddef, &fielddef);
+    upb_msg_field_next(&iter);
+  }
+  upb_msgdef_unref(self->msgdef, &self->msgdef);
+  if (self->layout) {
+    free_layout(self->layout);
+  }
+}
+
+static void descriptor_add_field(Descriptor *desc,
+                                 const upb_fielddef *fielddef) {
+  upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef);
+  upb_fielddef *mut_field_def = check_fielddef_notfrozen(fielddef);
+  CHECK_UPB(upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status),
+            "Adding field to Descriptor failed");
+  // add_def_obj(fielddef, obj);
+}
+
+void descriptor_init_c_instance(Descriptor* desc TSRMLS_DC) {
+  zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC);
+  desc->msgdef = upb_msgdef_new(&desc->msgdef);
+  desc->layout = NULL;
+  // MAKE_STD_ZVAL(intern->klass);
+  // ZVAL_NULL(intern->klass);
+  desc->pb_serialize_handlers = NULL;
+}
+
+void Descriptor_name_set(Descriptor *desc, const char *name) {
+  upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef);
+  CHECK_UPB(upb_msgdef_setfullname(mut_def, name, &status),
+            "Error setting Descriptor name");
+}
+
+// -----------------------------------------------------------------------------
+// FieldDescriptor
+// -----------------------------------------------------------------------------
+
+static void field_descriptor_name_set(const upb_fielddef* fielddef,
+                                      const char *name) {
+  upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
+  CHECK_UPB(upb_fielddef_setname(mut_def, name, &status),
+            "Error setting FieldDescriptor name");
+}
+
+static void field_descriptor_label_set(const upb_fielddef* fielddef,
+                                       upb_label_t upb_label) {
+  upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
+  upb_fielddef_setlabel(mut_def, upb_label);
+}
+
+upb_fieldtype_t string_to_descriptortype(const char *type) {
+#define CONVERT(upb, str)   \
+  if (!strcmp(type, str)) { \
+    return UPB_DESCRIPTOR_TYPE_##upb;  \
+  }
+
+  CONVERT(FLOAT, "float");
+  CONVERT(DOUBLE, "double");
+  CONVERT(BOOL, "bool");
+  CONVERT(STRING, "string");
+  CONVERT(BYTES, "bytes");
+  CONVERT(MESSAGE, "message");
+  CONVERT(GROUP, "group");
+  CONVERT(ENUM, "enum");
+  CONVERT(INT32, "int32");
+  CONVERT(INT64, "int64");
+  CONVERT(UINT32, "uint32");
+  CONVERT(UINT64, "uint64");
+  CONVERT(SINT32, "sint32");
+  CONVERT(SINT64, "sint64");
+  CONVERT(FIXED32, "fixed32");
+  CONVERT(FIXED64, "fixed64");
+  CONVERT(SFIXED32, "sfixed32");
+  CONVERT(SFIXED64, "sfixed64");
+
+#undef CONVERT
+
+  zend_error(E_ERROR, "Unknown field type.");
+  return 0;
+}
+
+static void field_descriptor_type_set(const upb_fielddef* fielddef,
+                                      const char *type) {
+  upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
+  upb_fielddef_setdescriptortype(mut_def, string_to_descriptortype(type));
+}
+
+static void field_descriptor_number_set(const upb_fielddef* fielddef,
+                                        int number) {
+  upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
+  CHECK_UPB(upb_fielddef_setnumber(mut_def, number, &status),
+            "Error setting field number");
+}
+
+// -----------------------------------------------------------------------------
+// MessageBuilderContext
+// -----------------------------------------------------------------------------
+
+static zend_function_entry message_builder_context_methods[] = {
+    PHP_ME(MessageBuilderContext, finalizeToPool, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(MessageBuilderContext, optional, NULL, ZEND_ACC_PUBLIC)
+    {NULL, NULL, NULL}
+};
+
+DEFINE_CLASS(MessageBuilderContext, message_builder_context,
+             "Google\\Protobuf\\Internal\\MessageBuilderContext");
+
+void message_builder_context_free_c(MessageBuilderContext *context TSRMLS_DC) {
+  zval_ptr_dtor(&context->descriptor);
+  zval_ptr_dtor(&context->pool);
+}
+
+void message_builder_context_init_c_instance(
+    MessageBuilderContext *context TSRMLS_DC) {
+  zend_object_std_init(&context->std, message_builder_context_type TSRMLS_CC);
+  PROTOBUF_CREATE_ZEND_WRAPPER(Descriptor, descriptor, context->descriptor,
+                               desc);
+}
+
+static void msgdef_add_field(Descriptor *desc, upb_label_t upb_label,
+                             const char *name, const char *type, int number,
+                             const char *type_class) {
+  upb_fielddef *fielddef = upb_fielddef_new(&fielddef);
+  upb_fielddef_setpacked(fielddef, false);
+
+  field_descriptor_label_set(fielddef, upb_label);
+  field_descriptor_name_set(fielddef, name);
+  field_descriptor_type_set(fielddef, type);
+  field_descriptor_number_set(fielddef, number);
+
+// //   if (type_class != Qnil) {
+// //     if (TYPE(type_class) != T_STRING) {
+// //       rb_raise(rb_eArgError, "Expected string for type class");
+// //     }
+// //     // Make it an absolute type name by prepending a dot.
+// //     type_class = rb_str_append(rb_str_new2("."), type_class);
+// //     rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class);
+// //   }
+  descriptor_add_field(desc, fielddef);
+}
+
+PHP_METHOD(MessageBuilderContext, optional) {
+  MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_CC);
+  Descriptor *desc = php_to_descriptor(self->descriptor TSRMLS_CC);
+  // VALUE name, type, number, type_class;
+  const char *name, *type, *type_class;
+  int number, name_str_len, type_str_len, type_class_str_len;
+  if (ZEND_NUM_ARGS() == 3) {
+    if (zend_parse_parameters(3 TSRMLS_CC, "ssl", &name,
+                              &name_str_len, &type, &type_str_len, &number) == FAILURE) {
+      return;
+    }
+  } else {
+    if (zend_parse_parameters(4 TSRMLS_CC, "ssls", &name,
+                              &name_str_len, &type, &type_str_len, &number, &type_class,
+                              &type_class_str_len) == FAILURE) {
+      return;
+    }
+  }
+
+  msgdef_add_field(desc, UPB_LABEL_OPTIONAL, name, type, number, type_class);
+
+  zval_copy_ctor(getThis());
+  RETURN_ZVAL(getThis(), 1, 0);
+}
+
+PHP_METHOD(MessageBuilderContext, finalizeToPool) {
+  MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_CC);
+  DescriptorPool *pool = php_to_descriptor_pool(self->pool TSRMLS_CC);
+  Descriptor* desc = php_to_descriptor(self->descriptor TSRMLS_CC);
+
+  Z_ADDREF_P(self->descriptor);
+  zend_hash_next_index_insert(pool->pending_list, &self->descriptor,
+                              sizeof(zval *), NULL);
+  RETURN_ZVAL(self->pool, 1, 0);
+}
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
new file mode 100644
index 0000000..c062d66
--- /dev/null
+++ b/php/ext/google/protobuf/message.c
@@ -0,0 +1,273 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include <php.h>
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Class/module creation from msgdefs and enumdefs, respectively.
+// -----------------------------------------------------------------------------
+
+void* message_data(void* msg) {
+  return ((uint8_t *)msg) + sizeof(MessageHeader);
+}
+
+void message_set_property(zval* object, zval* field_name, zval* value,
+                          const zend_literal* key TSRMLS_DC) {
+  const upb_fielddef* field;
+
+  MessageHeader* self = zend_object_store_get_object(object TSRMLS_CC);
+
+  CHECK_TYPE(field_name, IS_STRING);
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(field_name));
+  if (field == NULL) {
+    zend_error(E_ERROR, "Unknown field: %s", Z_STRVAL_P(field_name));
+  }
+  layout_set(self->descriptor->layout, message_data(self), field, value);
+}
+
+zval* message_get_property(zval* object, zval* member, int type,
+                             const zend_literal* key TSRMLS_DC) {
+  MessageHeader* self =
+      (MessageHeader*)zend_object_store_get_object(object TSRMLS_CC);
+  CHECK_TYPE(member, IS_STRING);
+
+  const upb_fielddef* field;
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
+  if (field == NULL) {
+    return EG(uninitialized_zval_ptr);
+  }
+  zval* retval = layout_get(self->descriptor->layout, message_data(self), field TSRMLS_CC);
+  return retval;
+}
+
+static  zend_function_entry message_methods[] = {
+  PHP_ME(Message, encode, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+/* stringsink *****************************************************************/
+
+// This should probably be factored into a common upb component.
+
+typedef struct {
+  upb_byteshandler handler;
+  upb_bytessink sink;
+  char *ptr;
+  size_t len, size;
+} stringsink;
+
+static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
+  stringsink *sink = _sink;
+  sink->len = 0;
+  return sink;
+}
+
+static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
+                                size_t len, const upb_bufhandle *handle) {
+  stringsink *sink = _sink;
+  size_t new_size = sink->size;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  while (sink->len + len > new_size) {
+    new_size *= 2;
+  }
+
+  if (new_size != sink->size) {
+    sink->ptr = realloc(sink->ptr, new_size);
+    sink->size = new_size;
+  }
+
+  memcpy(sink->ptr + sink->len, ptr, len);
+  sink->len += len;
+
+  return len;
+}
+
+void stringsink_init(stringsink *sink) {
+  upb_byteshandler_init(&sink->handler);
+  upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
+  upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
+
+  upb_bytessink_reset(&sink->sink, &sink->handler, sink);
+
+  sink->size = 32;
+  sink->ptr = malloc(sink->size);
+  sink->len = 0;
+}
+
+void stringsink_uninit(stringsink *sink) { free(sink->ptr); }
+
+// Stack-allocated context during an encode/decode operation. Contains the upb
+// environment and its stack-based allocator, an initial buffer for allocations
+// to avoid malloc() when possible, and a template for PHP exception messages
+// if any error occurs.
+#define STACK_ENV_STACKBYTES 4096
+typedef struct {
+  upb_env env;
+  upb_seededalloc alloc;
+  const char *php_error_template;
+  char allocbuf[STACK_ENV_STACKBYTES];
+} stackenv;
+
+static void stackenv_init(stackenv* se, const char* errmsg);
+static void stackenv_uninit(stackenv* se);
+
+// Callback invoked by upb if any error occurs during parsing or serialization.
+static bool env_error_func(void* ud, const upb_status* status) {
+    stackenv* se = ud;
+    // Free the env -- rb_raise will longjmp up the stack past the encode/decode
+    // function so it would not otherwise have been freed.
+    stackenv_uninit(se);
+
+    // TODO(teboring): have a way to verify that this is actually a parse error,
+    // instead of just throwing "parse error" unconditionally.
+    zend_error(E_ERROR, se->php_error_template);
+    // Never reached.
+    return false;
+}
+
+static void stackenv_init(stackenv* se, const char* errmsg) {
+  se->php_error_template = errmsg;
+  upb_env_init(&se->env);
+  upb_seededalloc_init(&se->alloc, &se->allocbuf, STACK_ENV_STACKBYTES);
+  upb_env_setallocfunc(&se->env, upb_seededalloc_getallocfunc(&se->alloc),
+                       &se->alloc);
+  upb_env_seterrorfunc(&se->env, env_error_func, se);
+}
+
+static void stackenv_uninit(stackenv* se) {
+  upb_env_uninit(&se->env);
+  upb_seededalloc_uninit(&se->alloc);
+}
+
+// -----------------------------------------------------------------------------
+// Message
+// -----------------------------------------------------------------------------
+
+static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
+  if (desc->pb_serialize_handlers == NULL) {
+    desc->pb_serialize_handlers =
+        upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
+  }
+  return desc->pb_serialize_handlers;
+}
+
+PHP_METHOD(Message, encode) {
+  Descriptor* desc = (Descriptor*)zend_object_store_get_object(
+      CE_STATIC_MEMBERS(Z_OBJCE_P(getThis()))[0] TSRMLS_CC);
+
+  stringsink sink;
+  stringsink_init(&sink);
+
+  {
+    const upb_handlers* serialize_handlers = msgdef_pb_serialize_handlers(desc);
+
+    stackenv se;
+    upb_pb_encoder* encoder;
+
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
+
+    putmsg(getThis(), desc, upb_pb_encoder_input(encoder), 0);
+
+    RETVAL_STRINGL(sink.ptr, sink.len, 1);
+
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+  }
+}
+
+void message_free(void * object TSRMLS_DC) {
+  FREE(object);
+}
+
+zend_object_value message_create(zend_class_entry* ce TSRMLS_DC) {
+  zend_object_value return_value;
+
+  zval* php_descriptor = get_def_obj(ce);
+
+  Descriptor* desc = zend_object_store_get_object(php_descriptor TSRMLS_CC);
+  MessageHeader* msg = (MessageHeader*)ALLOC_N(
+      uint8_t, sizeof(MessageHeader) + desc->layout->size);
+  memset(message_data(msg), 0, desc->layout->size);
+
+  // We wrap first so that everything in the message object is GC-rooted in case
+  // a collection happens during object creation in layout_init().
+  msg->descriptor = desc;
+
+  layout_init(desc->layout, message_data(msg));
+  zend_object_std_init(&msg->std, ce TSRMLS_CC);
+
+  return_value.handle = zend_objects_store_put(
+      msg, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+      message_free, NULL TSRMLS_CC);
+
+  return_value.handlers = PROTOBUF_G(message_handlers);
+  return return_value;
+}
+
+const zend_class_entry* build_class_from_descriptor(
+    zval* php_descriptor TSRMLS_DC) {
+  Descriptor* desc = php_to_descriptor(php_descriptor);
+  if (desc->layout == NULL) {
+    MessageLayout* layout = create_layout(desc->msgdef);
+    desc->layout = layout;
+  }
+  // TODO(teboring): Add it back.
+  // if (desc->fill_method == NULL) {
+  //   desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
+  // }
+
+  const char* name = upb_msgdef_fullname(desc->msgdef);
+  if (name == NULL) {
+    zend_error(E_ERROR, "Descriptor does not have assigned name.");
+  }
+
+  zend_class_entry class_entry;
+  INIT_CLASS_ENTRY_EX(class_entry, name, strlen(name), message_methods);
+  zend_class_entry* registered_ce =
+      zend_register_internal_class(&class_entry TSRMLS_CC);
+
+  add_def_obj(registered_ce, php_descriptor);
+
+  if (PROTOBUF_G(message_handlers) == NULL) {
+    PROTOBUF_G(message_handlers) = ALLOC(zend_object_handlers);
+    memcpy(PROTOBUF_G(message_handlers), zend_get_std_object_handlers(),
+           sizeof(zend_object_handlers));
+    PROTOBUF_G(message_handlers)->write_property = message_set_property;
+    PROTOBUF_G(message_handlers)->read_property = message_get_property;
+  }
+
+  registered_ce->create_object = message_create;
+}
diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c
new file mode 100644
index 0000000..b1ace8b
--- /dev/null
+++ b/php/ext/google/protobuf/protobuf.c
@@ -0,0 +1,89 @@
+#include "protobuf.h"
+
+#include <zend_hash.h>
+
+ZEND_DECLARE_MODULE_GLOBALS(protobuf)
+static PHP_GINIT_FUNCTION(protobuf);
+static PHP_GSHUTDOWN_FUNCTION(protobuf);
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+
+void add_def_obj(const void* def, zval* value) {
+  uint nIndex = (ulong)def & PROTOBUF_G(upb_def_to_php_obj_map).nTableMask;
+
+  zval* pDest = NULL;
+  Z_ADDREF_P(value);
+  zend_hash_index_update(&PROTOBUF_G(upb_def_to_php_obj_map), (zend_ulong)def,
+                         &value, sizeof(zval*), &pDest);
+}
+
+zval* get_def_obj(const void* def) {
+  zval** value;
+  if (zend_hash_index_find(&PROTOBUF_G(upb_def_to_php_obj_map), (zend_ulong)def,
+                           &value) == FAILURE) {
+    zend_error(E_ERROR, "PHP object not found for given definition.\n");
+    return NULL;
+  }
+  return *value;
+}
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+// define the function(s) we want to add
+zend_function_entry protobuf_functions[] = {
+  ZEND_FE(get_generated_pool, NULL)
+  ZEND_FE_END
+};
+
+// "protobuf_functions" refers to the struct defined above
+// we'll be filling in more of this later: you can use this to specify
+// globals, php.ini info, startup and teardown functions, etc.
+zend_module_entry protobuf_module_entry = {
+  STANDARD_MODULE_HEADER,
+  PHP_PROTOBUF_EXTNAME, // extension name
+  protobuf_functions,   // function list
+  PHP_MINIT(protobuf),  // process startup
+  NULL,  // process shutdown
+  NULL,  // request startup
+  NULL,  // request shutdown
+  NULL,  // extension info
+  PHP_PROTOBUF_VERSION, // extension version
+  PHP_MODULE_GLOBALS(protobuf),  // globals descriptor
+  PHP_GINIT(protobuf), // globals ctor
+  PHP_GSHUTDOWN(protobuf),  // globals dtor
+  NULL,  // post deactivate
+  STANDARD_MODULE_PROPERTIES_EX
+};
+
+// install module
+ZEND_GET_MODULE(protobuf)
+
+// global variables
+static PHP_GINIT_FUNCTION(protobuf) {
+  protobuf_globals->generated_pool = NULL;
+  generated_pool = NULL;
+  protobuf_globals->message_handlers = NULL;
+  zend_hash_init(&protobuf_globals->upb_def_to_php_obj_map, 16, NULL,
+                 ZVAL_PTR_DTOR, 0);
+}
+
+static PHP_GSHUTDOWN_FUNCTION(protobuf) {
+  if (protobuf_globals->generated_pool != NULL) {
+    FREE_ZVAL(protobuf_globals->generated_pool);
+  }
+  if (protobuf_globals->message_handlers != NULL) {
+    FREE(protobuf_globals->message_handlers);
+  }
+  zend_hash_destroy(&protobuf_globals->upb_def_to_php_obj_map);
+}
+
+PHP_MINIT_FUNCTION(protobuf) {
+  descriptor_pool_init(TSRMLS_C);
+  descriptor_init(TSRMLS_C);
+  message_builder_context_init(TSRMLS_C);
+}
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
new file mode 100644
index 0000000..f903855
--- /dev/null
+++ b/php/ext/google/protobuf/protobuf.h
@@ -0,0 +1,281 @@
+#ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
+#define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
+
+#include <php.h>
+
+#include "upb.h"
+
+#define PHP_PROTOBUF_EXTNAME "protobuf"
+#define PHP_PROTOBUF_VERSION "0.01"
+
+// Forward decls.
+struct DescriptorPool;
+struct Descriptor;
+struct FieldDescriptor;
+struct EnumDescriptor;
+struct MessageLayout;
+struct MessageField;
+struct MessageHeader;
+struct MessageBuilderContext;
+struct EnumBuilderContext;
+
+typedef struct DescriptorPool DescriptorPool;
+typedef struct Descriptor Descriptor;
+typedef struct FieldDescriptor FieldDescriptor;
+typedef struct OneofDescriptor OneofDescriptor;
+typedef struct EnumDescriptor EnumDescriptor;
+typedef struct MessageLayout MessageLayout;
+typedef struct MessageField MessageField;
+typedef struct MessageHeader MessageHeader;
+typedef struct MessageBuilderContext MessageBuilderContext;
+typedef struct OneofBuilderContext OneofBuilderContext;
+typedef struct EnumBuilderContext EnumBuilderContext;
+
+extern zend_class_entry* builder_type;
+extern zend_class_entry* descriptor_type;
+extern zend_class_entry* message_builder_context_type;
+
+extern DescriptorPool* generated_pool;  // The actual generated pool
+
+ZEND_BEGIN_MODULE_GLOBALS(protobuf)
+  zval* generated_pool;
+  zend_object_handlers* message_handlers;
+  HashTable upb_def_to_php_obj_map;
+ZEND_END_MODULE_GLOBALS(protobuf)
+
+ZEND_DECLARE_MODULE_GLOBALS(protobuf)
+
+#ifdef ZTS
+#define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v)
+#else
+#define PROTOBUF_G(v) (protobuf_globals.v)
+#endif
+
+// -----------------------------------------------------------------------------
+// PHP functions and global variables.
+// -----------------------------------------------------------------------------
+
+PHP_MINIT_FUNCTION(protobuf);
+
+// -----------------------------------------------------------------------------
+// PHP class structure.
+// -----------------------------------------------------------------------------
+
+struct DescriptorPool {
+  zend_object std;
+  upb_symtab* symtab;
+  HashTable* pending_list;
+};
+
+struct Descriptor {
+  zend_object std;
+  const upb_msgdef* msgdef;
+  MessageLayout* layout;
+  // zval* klass;  // begins as NULL
+  // const upb_handlers* fill_handlers;
+  // const upb_pbdecodermethod* fill_method;
+  const upb_handlers* pb_serialize_handlers;
+  // const upb_handlers* json_serialize_handlers;
+  // Handlers hold type class references for sub-message fields directly in some
+  // cases. We need to keep these rooted because they might otherwise be
+  // collected.
+  // zval_array typeclass_references;
+};
+
+struct FieldDescriptor {
+  zend_object std;
+  const upb_fielddef* fielddef;
+};
+
+struct OneofDescriptor {
+  zend_object std;
+  const upb_oneofdef* oneofdef;
+};
+
+struct EnumDescriptor {
+  zend_object std;
+  const upb_enumdef* enumdef;
+  // zval* module;  // begins as NULL
+};
+
+// -----------------------------------------------------------------------------
+// Native slot storage abstraction.
+// -----------------------------------------------------------------------------
+
+#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
+
+size_t native_slot_size(upb_fieldtype_t type);
+
+#define MAP_KEY_FIELD 1
+#define MAP_VALUE_FIELD 2
+
+// Oneof case slot value to indicate that no oneof case is set. The value `0` is
+// safe because field numbers are used as case identifiers, and no field can
+// have a number of 0.
+#define ONEOF_CASE_NONE 0
+
+// These operate on a map field (i.e., a repeated field of submessages whose
+// submessage type is a map-entry msgdef).
+bool is_map_field(const upb_fielddef* field);
+const upb_fielddef* map_field_key(const upb_fielddef* field);
+const upb_fielddef* map_field_value(const upb_fielddef* field);
+
+// These operate on a map-entry msgdef.
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
+
+// -----------------------------------------------------------------------------
+// Message layout / storage.
+// -----------------------------------------------------------------------------
+
+#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
+
+struct MessageField {
+  size_t offset;
+  size_t case_offset;  // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
+};
+
+struct MessageLayout {
+  const upb_msgdef* msgdef;
+  MessageField* fields;
+  size_t size;
+};
+
+void layout_init(MessageLayout* layout, void* storage);
+zval* layout_get(MessageLayout* layout, const void* storage,
+                 const upb_fielddef* field TSRMLS_DC);
+MessageLayout* create_layout(const upb_msgdef* msgdef);
+void free_layout(MessageLayout* layout);
+zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/
+                      const void* memory TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// Message class creation.
+// -----------------------------------------------------------------------------
+
+struct MessageHeader {
+  zend_object std;
+  Descriptor* descriptor;  // kept alive by self.class.descriptor reference.
+                           // Data comes after this.
+};
+
+struct MessageBuilderContext {
+  zend_object std;
+  zval* descriptor;
+  zval* pool;
+};
+
+struct OneofBuilderContext {
+  zend_object std;
+  // VALUE descriptor;
+  // VALUE builder;
+};
+
+struct EnumBuilderContext {
+  zend_object std;
+  // VALUE enumdesc;
+};
+
+// Forward-declare all of the PHP method implementations.
+
+DescriptorPool* php_to_descriptor_pool(zval* value TSRMLS_DC);
+zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC);
+void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC);
+void descriptor_pool_free(void* object TSRMLS_DC);
+void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC);
+PHP_METHOD(DescriptorPool, addMessage);
+PHP_METHOD(DescriptorPool, finalize);
+
+Descriptor* php_to_descriptor(zval* value TSRMLS_DC);
+zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC);
+void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC);
+void descriptor_free_c(Descriptor* object TSRMLS_DC);
+void descriptor_free(void* object TSRMLS_DC);
+void descriptor_name_set(Descriptor *desc, const char *name);
+
+MessageBuilderContext* php_to_message_builder_context(zval* value TSRMLS_DC);
+zend_object_value message_builder_context_create(
+    zend_class_entry* ce TSRMLS_DC);
+void message_builder_context_init_c_instance(
+    MessageBuilderContext* intern TSRMLS_DC);
+void message_builder_context_free_c(MessageBuilderContext* object TSRMLS_DC);
+void message_builder_context_free(void* object TSRMLS_DC);
+PHP_METHOD(MessageBuilderContext, optional);
+PHP_METHOD(MessageBuilderContext, finalizeToPool);
+
+PHP_METHOD(Message, encode);
+const zend_class_entry* build_class_from_descriptor(
+    zval* php_descriptor TSRMLS_DC);
+
+PHP_FUNCTION(get_generated_pool);
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// ----------------------------------------------------------------------------
+
+void add_def_obj(const void* def, zval* value);
+zval* get_def_obj(const void* def);
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+// PHP Array utils.
+#define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p))
+#define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead
+#define Z_BUCKET_NEXT_PP(bucket_pp) *bucket_pp = (*bucket_pp)->pListNext
+
+#define DEFINE_PHP_OBJECT(class_name, class_name_lower, name) \
+  do {                                                        \
+    zval* name;                                               \
+    MAKE_STD_ZVAL(name);                                      \
+    object_init_ex(name, class_name_lower##_type);            \
+  } while (0)
+
+#define DEFINE_PHP_WRAPPER(class_name, class_name_lower, name, intern) \
+  zval* name;                                                          \
+  MAKE_STD_ZVAL(name);                                                 \
+  object_init_ex(name, class_name_lower##_type);                       \
+  Z_OBJVAL_P(name)                                                     \
+      .handle = zend_objects_store_put(                                \
+      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,  \
+      class_name_lower##_free, NULL TSRMLS_CC);
+
+#define DEFINE_PHP_ZVAL(name) \
+  do {                        \
+    zval* name;               \
+    MAKE_STD_ZVAL(name);      \
+  } while (0)
+
+#define DEFINE_PHP_STRING(name, value) \
+  do {                                 \
+    zval* name;                        \
+    MAKE_STD_ZVAL(name);               \
+    ZVAL_STRING(name, value, 1);       \
+  } while (0)
+
+// Upb Utilities
+
+void check_upb_status(const upb_status* status, const char* msg);
+
+#define CHECK_UPB(code, msg)             \
+  do {                                   \
+    upb_status status = UPB_STATUS_INIT; \
+    code;                                \
+    check_upb_status(&status, msg);      \
+  } while (0)
+
+// Memory management
+
+#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name))
+#define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n)
+#define FREE(object) efree(object)
+
+// Type Checking
+#define CHECK_TYPE(field, type)             \
+  if (Z_TYPE_P(field) != type) {            \
+    zend_error(E_ERROR, "Unexpected type"); \
+  }
+
+#endif  // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c
new file mode 100644
index 0000000..e5a09c1
--- /dev/null
+++ b/php/ext/google/protobuf/storage.c
@@ -0,0 +1,539 @@
+#include <stdint.h>
+#include <protobuf.h>
+
+// -----------------------------------------------------------------------------
+// PHP <-> native slot management.
+// -----------------------------------------------------------------------------
+
+static zval* int32_to_zval(int32_t value) {
+  zval* tmp;
+  MAKE_STD_ZVAL(tmp);
+  ZVAL_LONG(tmp, value);
+  php_printf("int32 to zval\n");
+  // ZVAL_LONG(tmp, 1);
+  return tmp;
+}
+
+#define DEREF(memory, type) *(type*)(memory)
+
+size_t native_slot_size(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_FLOAT: return 4;
+    case UPB_TYPE_DOUBLE: return 8;
+    case UPB_TYPE_BOOL: return 1;
+    case UPB_TYPE_STRING: return sizeof(zval*);
+    case UPB_TYPE_BYTES: return sizeof(zval*);
+    case UPB_TYPE_MESSAGE: return sizeof(zval*);
+    case UPB_TYPE_ENUM: return 4;
+    case UPB_TYPE_INT32: return 4;
+    case UPB_TYPE_INT64: return 8;
+    case UPB_TYPE_UINT32: return 4;
+    case UPB_TYPE_UINT64: return 8;
+    default: return 0;
+  }
+}
+
+static bool is_php_num(zval* value) {
+  // Is numerial string also valid?
+  return (Z_TYPE_P(value) == IS_LONG ||
+          Z_TYPE_P(value) == IS_DOUBLE);
+}
+
+void native_slot_check_int_range_precision(upb_fieldtype_t type, zval* val) {
+  // TODO(teboring): Add it back.
+  // if (!is_php_num(val)) {
+  //   zend_error(E_ERROR, "Expected number type for integral field.");
+  // }
+
+  // if (Z_TYPE_P(val) == IS_DOUBLE) {
+  //   double dbl_val = NUM2DBL(val);
+  //   if (floor(dbl_val) != dbl_val) {
+  //     zend_error(E_ERROR,
+  //              "Non-integral floating point value assigned to integer field.");
+  //   }
+  // }
+  // if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
+  //   if (NUM2DBL(val) < 0) {
+  //     zend_error(E_ERROR,
+  //              "Assigning negative value to unsigned integer field.");
+  //   }
+  // }
+}
+
+zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/
+                      const void* memory TSRMLS_DC) {
+  zval* retval = NULL;
+  switch (type) {
+    // TODO(teboring): Add it back.
+    // case UPB_TYPE_FLOAT:
+    //   return DBL2NUM(DEREF(memory, float));
+    // case UPB_TYPE_DOUBLE:
+    //   return DBL2NUM(DEREF(memory, double));
+    // case UPB_TYPE_BOOL:
+    //   return DEREF(memory, int8_t) ? Qtrue : Qfalse;
+    // case UPB_TYPE_STRING:
+    // case UPB_TYPE_BYTES:
+    // case UPB_TYPE_MESSAGE:
+    //   return DEREF(memory, VALUE);
+    // case UPB_TYPE_ENUM: {
+    //   int32_t val = DEREF(memory, int32_t);
+    //   VALUE symbol = enum_lookup(type_class, INT2NUM(val));
+    //   if (symbol == Qnil) {
+    //     return INT2NUM(val);
+    //   } else {
+    //     return symbol;
+    //   }
+    // }
+    case UPB_TYPE_INT32:
+      return int32_to_zval(DEREF(memory, int32_t));
+    // TODO(teboring): Add it back.
+    // case UPB_TYPE_INT64:
+    //   return LL2NUM(DEREF(memory, int64_t));
+    // case UPB_TYPE_UINT32:
+    //   return UINT2NUM(DEREF(memory, uint32_t));
+    // case UPB_TYPE_UINT64:
+    //   return ULL2NUM(DEREF(memory, uint64_t));
+    default:
+      return EG(uninitialized_zval_ptr);
+  }
+}
+
+void native_slot_init(upb_fieldtype_t type, void* memory) {
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      DEREF(memory, float) = 0.0;
+      break;
+    case UPB_TYPE_DOUBLE:
+      DEREF(memory, double) = 0.0;
+      break;
+    case UPB_TYPE_BOOL:
+      DEREF(memory, int8_t) = 0;
+      break;
+    // TODO(teboring): Add it back.
+    // case UPB_TYPE_STRING:
+    // case UPB_TYPE_BYTES:
+    //   DEREF(memory, VALUE) = php_str_new2("");
+    //   php_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES)
+    //                                              ? kRubyString8bitEncoding
+    //                                              : kRubyStringUtf8Encoding);
+    //   break;
+    // case UPB_TYPE_MESSAGE:
+    //   DEREF(memory, VALUE) = Qnil;
+    //   break;
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32:
+      DEREF(memory, int32_t) = 0;
+      break;
+    case UPB_TYPE_INT64:
+      DEREF(memory, int64_t) = 0;
+      break;
+    case UPB_TYPE_UINT32:
+      DEREF(memory, uint32_t) = 0;
+      break;
+    case UPB_TYPE_UINT64:
+      DEREF(memory, uint64_t) = 0;
+      break;
+    default:
+      break;
+  }
+}
+
+void native_slot_set(upb_fieldtype_t type, /*VALUE type_class,*/ void* memory,
+                     zval* value) {
+  native_slot_set_value_and_case(type, /*type_class,*/ memory, value, NULL, 0);
+}
+
+void native_slot_set_value_and_case(upb_fieldtype_t type, /*VALUE type_class,*/
+                                    void* memory, zval* value,
+                                    uint32_t* case_memory,
+                                    uint32_t case_number) {
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      if (!Z_TYPE_P(value) == IS_LONG) {
+        zend_error(E_ERROR, "Expected number type for float field.");
+      }
+      DEREF(memory, float) = Z_DVAL_P(value);
+      break;
+    case UPB_TYPE_DOUBLE:
+      // TODO(teboring): Add it back.
+      // if (!is_php_num(value)) {
+      //   zend_error(E_ERROR, "Expected number type for double field.");
+      // }
+      // DEREF(memory, double) = Z_DVAL_P(value);
+      break;
+    case UPB_TYPE_BOOL: {
+      int8_t val = -1;
+      if (zval_is_true(value)) {
+        val = 1;
+      } else {
+        val = 0;
+      }
+      // TODO(teboring): Add it back.
+      // else if (value == Qfalse) {
+      //   val = 0;
+      // }
+      // else {
+      //   php_raise(php_eTypeError, "Invalid argument for boolean field.");
+      // }
+      DEREF(memory, int8_t) = val;
+      break;
+    }
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      // TODO(teboring): Add it back.
+      // if (Z_TYPE_P(value) != IS_STRING) {
+      //   zend_error(E_ERROR, "Invalid argument for string field.");
+      // }
+      // native_slot_validate_string_encoding(type, value);
+      // DEREF(memory, zval*) = value;
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      // TODO(teboring): Add it back.
+      // if (CLASS_OF(value) == CLASS_OF(Qnil)) {
+      //   value = Qnil;
+      // } else if (CLASS_OF(value) != type_class) {
+      //   php_raise(php_eTypeError,
+      //            "Invalid type %s to assign to submessage field.",
+      //            php_class2name(CLASS_OF(value)));
+      // }
+      // DEREF(memory, VALUE) = value;
+      break;
+    }
+    case UPB_TYPE_ENUM: {
+      // TODO(teboring): Add it back.
+      // int32_t int_val = 0;
+      // if (!is_php_num(value) && TYPE(value) != T_SYMBOL) {
+      //   php_raise(php_eTypeError,
+      //            "Expected number or symbol type for enum field.");
+      // }
+      // if (TYPE(value) == T_SYMBOL) {
+      //   // Ensure that the given symbol exists in the enum module.
+      //   VALUE lookup = php_funcall(type_class, php_intern("resolve"), 1, value);
+      //   if (lookup == Qnil) {
+      //     php_raise(php_eRangeError, "Unknown symbol value for enum field.");
+      //   } else {
+      //     int_val = NUM2INT(lookup);
+      //   }
+      // } else {
+      //   native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
+      //   int_val = NUM2INT(value);
+      // }
+      // DEREF(memory, int32_t) = int_val;
+      // break;
+    }
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      native_slot_check_int_range_precision(type, value);
+      switch (type) {
+        case UPB_TYPE_INT32:
+          php_printf("Setting INT32 field\n");
+          DEREF(memory, int32_t) = Z_LVAL_P(value);
+          break;
+        case UPB_TYPE_INT64:
+          // TODO(teboring): Add it back.
+          // DEREF(memory, int64_t) = NUM2LL(value);
+          break;
+        case UPB_TYPE_UINT32:
+          // TODO(teboring): Add it back.
+          // DEREF(memory, uint32_t) = NUM2UINT(value);
+          break;
+        case UPB_TYPE_UINT64:
+          // TODO(teboring): Add it back.
+          // DEREF(memory, uint64_t) = NUM2ULL(value);
+          break;
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (case_memory != NULL) {
+    *case_memory = case_number;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Map field utilities.
+// ----------------------------------------------------------------------------
+
+const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef;
+  if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
+      upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
+    return NULL;
+  }
+  subdef = upb_fielddef_msgsubdef(field);
+  return upb_msgdef_mapentry(subdef) ? subdef : NULL;
+}
+
+const upb_msgdef* map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef = tryget_map_entry_msgdef(field);
+  assert(subdef);
+  return subdef;
+}
+
+bool is_map_field(const upb_fielddef* field) {
+  return tryget_map_entry_msgdef(field) != NULL;
+}
+
+// -----------------------------------------------------------------------------
+// Memory layout management.
+// -----------------------------------------------------------------------------
+
+static size_t align_up_to(size_t offset, size_t granularity) {
+  // Granularity must be a power of two.
+  return (offset + granularity - 1) & ~(granularity - 1);
+}
+
+MessageLayout* create_layout(const upb_msgdef* msgdef) {
+  MessageLayout* layout = ALLOC(MessageLayout);
+  int nfields = upb_msgdef_numfields(msgdef);
+  upb_msg_field_iter it;
+  upb_msg_oneof_iter oit;
+  size_t off = 0;
+
+  layout->fields = ALLOC_N(MessageField, nfields);
+
+  for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    size_t field_size;
+
+    if (upb_fielddef_containingoneof(field)) {
+      // Oneofs are handled separately below.
+      continue;
+    }
+
+    // Allocate |field_size| bytes for this field in the layout.
+    field_size = 0;
+    if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      field_size = sizeof(zval*);
+    } else {
+      field_size = native_slot_size(upb_fielddef_type(field));
+    }
+
+    // Align current offset up to | size | granularity.
+    off = align_up_to(off, field_size);
+    layout->fields[upb_fielddef_index(field)].offset = off;
+    layout->fields[upb_fielddef_index(field)].case_offset =
+        MESSAGE_FIELD_NO_CASE;
+    off += field_size;
+  }
+
+  // Handle oneofs now -- we iterate over oneofs specifically and allocate only
+  // one slot per oneof.
+  //
+  // We assign all value slots first, then pack the 'case' fields at the end,
+  // since in the common case (modern 64-bit platform) these are 8 bytes and 4
+  // bytes respectively and we want to avoid alignment overhead.
+  //
+  // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
+  // space for oneof cases is conceptually as wide as field tag numbers.  In
+  // practice, it's unlikely that a oneof would have more than e.g.  256 or 64K
+  // members (8 or 16 bits respectively), so conceivably we could assign
+  // consecutive case numbers and then pick a smaller oneof case slot size, but
+  // the complexity to implement this indirection is probably not worthwhile.
+  for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
+    // all fields.
+    size_t field_size = NATIVE_SLOT_MAX_SIZE;
+    // Align the offset .
+    off = align_up_to( off, field_size);
+    // Assign all fields in the oneof this same offset.
+    for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].offset = off;
+    }
+    off += field_size;
+  }
+
+  // Now the case fields.
+  for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    size_t field_size = sizeof(uint32_t);
+    // Align the offset .
+    off = (off + field_size - 1) & ~(field_size - 1);
+    // Assign all fields in the oneof this same offset.
+    for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].case_offset = off;
+    }
+    off += field_size;
+  }
+
+  layout->size = off;
+
+  layout->msgdef = msgdef;
+  upb_msgdef_ref(layout->msgdef, &layout->msgdef);
+
+  return layout;
+}
+
+void free_layout(MessageLayout* layout) {
+  FREE(layout->fields);
+  upb_msgdef_unref(layout->msgdef, &layout->msgdef);
+  FREE(layout);
+}
+
+// TODO(teboring): Add it back.
+// VALUE field_type_class(const upb_fielddef* field) {
+//   VALUE type_class = Qnil;
+//   if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
+//     VALUE submsgdesc = get_def_obj(upb_fielddef_subdef(field));
+//     type_class = Descriptor_msgclass(submsgdesc);
+//   } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
+//     VALUE subenumdesc = get_def_obj(upb_fielddef_subdef(field));
+//     type_class = EnumDescriptor_enummodule(subenumdesc);
+//   }
+//   return type_class;
+// }
+
+static void* slot_memory(MessageLayout* layout, const void* storage,
+                         const upb_fielddef* field) {
+  return ((uint8_t*)storage) + layout->fields[upb_fielddef_index(field)].offset;
+}
+
+static uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage,
+                                 const upb_fielddef* field) {
+  return (uint32_t*)(((uint8_t*)storage) +
+                     layout->fields[upb_fielddef_index(field)].case_offset);
+}
+
+void layout_set(MessageLayout* layout, void* storage, const upb_fielddef* field,
+                zval* val) {
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    if (Z_TYPE_P(val) == IS_NULL) {
+      // Assigning nil to a oneof field clears the oneof completely.
+      *oneof_case = ONEOF_CASE_NONE;
+      memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+    } else {
+      // The transition between field types for a single oneof (union) slot is
+      // somewhat complex because we need to ensure that a GC triggered at any
+      // point by a call into the Ruby VM sees a valid state for this field and
+      // does not either go off into the weeds (following what it thinks is a
+      // VALUE but is actually a different field type) or miss an object (seeing
+      // what it thinks is a primitive field but is actually a VALUE for the new
+      // field type).
+      //
+      // In order for the transition to be safe, the oneof case slot must be in
+      // sync with the value slot whenever the Ruby VM has been called. Thus, we
+      // use native_slot_set_value_and_case(), which ensures that both the value
+      // and case number are altered atomically (w.r.t. the Ruby VM).
+      native_slot_set_value_and_case(upb_fielddef_type(field),
+                                     /*field_type_class(field),*/ memory, val,
+                                     oneof_case, upb_fielddef_number(field));
+    }
+  } else if (is_map_field(field)) {
+    // TODO(teboring): Add it back.
+    // check_map_field_type(val, field);
+    // DEREF(memory, zval*) = val;
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+    // TODO(teboring): Add it back.
+    // check_repeated_field_type(val, field);
+    // DEREF(memory, zval*) = val;
+  } else {
+    native_slot_set(upb_fielddef_type(field), /*field_type_class(field),*/ memory,
+                    val);
+  }
+}
+
+void layout_init(MessageLayout* layout, void* storage) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    void* memory = slot_memory(layout, storage, field);
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      // TODO(teboring): Add it back.
+      // memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+      // *oneof_case = ONEOF_CASE_NONE;
+    } else if (is_map_field(field)) {
+      // TODO(teboring): Add it back.
+      // VALUE map = Qnil;
+
+      // const upb_fielddef* key_field = map_field_key(field);
+      // const upb_fielddef* value_field = map_field_value(field);
+      // VALUE type_class = field_type_class(value_field);
+
+      // if (type_class != Qnil) {
+      //   VALUE args[3] = {
+      //       fieldtype_to_php(upb_fielddef_type(key_field)),
+      //       fieldtype_to_php(upb_fielddef_type(value_field)), type_class,
+      //   };
+      //   map = php_class_new_instance(3, args, cMap);
+      // } else {
+      //   VALUE args[2] = {
+      //       fieldtype_to_php(upb_fielddef_type(key_field)),
+      //       fieldtype_to_php(upb_fielddef_type(value_field)),
+      //   };
+      //   map = php_class_new_instance(2, args, cMap);
+      // }
+
+      // DEREF(memory, VALUE) = map;
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      // TODO(teboring): Add it back.
+      // VALUE ary = Qnil;
+
+      // VALUE type_class = field_type_class(field);
+
+      // if (type_class != Qnil) {
+      //   VALUE args[2] = {
+      //       fieldtype_to_php(upb_fielddef_type(field)), type_class,
+      //   };
+      //   ary = php_class_new_instance(2, args, cRepeatedField);
+      // } else {
+      //   VALUE args[1] = {fieldtype_to_php(upb_fielddef_type(field))};
+      //   ary = php_class_new_instance(1, args, cRepeatedField);
+      // }
+
+      // DEREF(memory, VALUE) = ary;
+    } else {
+      native_slot_init(upb_fielddef_type(field), memory);
+    }
+  }
+}
+
+zval* layout_get(MessageLayout* layout, const void* storage,
+                 const upb_fielddef* field TSRMLS_DC) {
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    if (*oneof_case != upb_fielddef_number(field)) {
+      return NULL;
+      // TODO(teboring): Add it back.
+      // return Qnil;
+    }
+      return NULL;
+    // TODO(teboring): Add it back.
+    // return native_slot_get(upb_fielddef_type(field), field_type_class(field),
+    //                        memory);
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      return NULL;
+    // TODO(teboring): Add it back.
+    // return *((VALUE*)memory);
+  } else {
+    return native_slot_get(
+        upb_fielddef_type(field), /*field_type_class(field), */
+        memory TSRMLS_CC);
+  }
+}
diff --git a/php/ext/google/protobuf/test.php b/php/ext/google/protobuf/test.php
new file mode 100644
index 0000000..6bbadd4
--- /dev/null
+++ b/php/ext/google/protobuf/test.php
@@ -0,0 +1,15 @@
+<?php
+
+
+namespace Google\Protobuf;
+
+$pool = get_generated_pool();
+$pool->addMessage("TestMessage")
+    ->optional("optional_int32_a", "int32", 1)
+    ->optional("optional_int32_b", "int32", 2)
+    ->finalizeToPool()
+    ->finalize();
+
+$test_message = new \TestMessage();
+
+?>
diff --git a/php/ext/google/protobuf/upb.c b/php/ext/google/protobuf/upb.c
new file mode 100644
index 0000000..048a163
--- /dev/null
+++ b/php/ext/google/protobuf/upb.c
@@ -0,0 +1,11990 @@
+// Amalgamated source file
+#include "upb.h"
+
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+  size_t len;
+  char str[1];  /* Null-terminated string data follows. */
+} str_t;
+
+static str_t *newstr(const char *data, size_t len) {
+  str_t *ret = malloc(sizeof(*ret) + len);
+  if (!ret) return NULL;
+  ret->len = len;
+  memcpy(ret->str, data, len);
+  ret->str[len] = '\0';
+  return ret;
+}
+
+static void freestr(str_t *s) { free(s); }
+
+/* isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. */
+static bool upb_isbetween(char c, char low, char high) {
+  return c >= low && c <= high;
+}
+
+static bool upb_isletter(char c) {
+  return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+}
+
+static bool upb_isalphanum(char c) {
+  return upb_isletter(c) || upb_isbetween(c, '0', '9');
+}
+
+static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
+  bool start = true;
+  size_t i;
+  for (i = 0; i < len; i++) {
+    char c = str[i];
+    if (c == '.') {
+      if (start || !full) {
+        upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str);
+        return false;
+      }
+      start = true;
+    } else if (start) {
+      if (!upb_isletter(c)) {
+        upb_status_seterrf(
+            s, "invalid name: path components must start with a letter (%s)",
+            str);
+        return false;
+      }
+      start = false;
+    } else {
+      if (!upb_isalphanum(c)) {
+        upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)",
+                           str);
+        return false;
+      }
+    }
+  }
+  return !start;
+}
+
+
+/* upb_def ********************************************************************/
+
+upb_deftype_t upb_def_type(const upb_def *d) { return d->type; }
+
+const char *upb_def_fullname(const upb_def *d) { return d->fullname; }
+
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) {
+  assert(!upb_def_isfrozen(def));
+  if (!upb_isident(fullname, strlen(fullname), true, s)) return false;
+  free((void*)def->fullname);
+  def->fullname = upb_strdup(fullname);
+  return true;
+}
+
+upb_def *upb_def_dup(const upb_def *def, const void *o) {
+  switch (def->type) {
+    case UPB_DEF_MSG:
+      return upb_msgdef_upcast_mutable(
+          upb_msgdef_dup(upb_downcast_msgdef(def), o));
+    case UPB_DEF_FIELD:
+      return upb_fielddef_upcast_mutable(
+          upb_fielddef_dup(upb_downcast_fielddef(def), o));
+    case UPB_DEF_ENUM:
+      return upb_enumdef_upcast_mutable(
+          upb_enumdef_dup(upb_downcast_enumdef(def), o));
+    default: assert(false); return NULL;
+  }
+}
+
+static bool upb_def_init(upb_def *def, upb_deftype_t type,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+  if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false;
+  def->type = type;
+  def->fullname = NULL;
+  def->came_from_user = false;
+  return true;
+}
+
+static void upb_def_uninit(upb_def *def) {
+  free((void*)def->fullname);
+}
+
+static const char *msgdef_name(const upb_msgdef *m) {
+  const char *name = upb_def_fullname(upb_msgdef_upcast(m));
+  return name ? name : "(anonymous)";
+}
+
+static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "fielddef must have name and number set");
+    return false;
+  }
+
+  if (!f->type_is_set_) {
+    upb_status_seterrmsg(s, "fielddef type was not initialized");
+    return false;
+  }
+
+  if (upb_fielddef_lazy(f) &&
+      upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    upb_status_seterrmsg(s,
+                         "only length-delimited submessage fields may be lazy");
+    return false;
+  }
+
+  if (upb_fielddef_hassubdef(f)) {
+    const upb_def *subdef;
+
+    if (f->subdef_is_symbolic) {
+      upb_status_seterrf(s, "field '%s.%s' has not been resolved",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    subdef = upb_fielddef_subdef(f);
+    if (subdef == NULL) {
+      upb_status_seterrf(s, "field %s.%s is missing required subdef",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
+      upb_status_seterrf(s,
+                         "subdef of field %s.%s is not frozen or being frozen",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+  }
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    bool has_default_name = upb_fielddef_enumhasdefaultstr(f);
+    bool has_default_number = upb_fielddef_enumhasdefaultint32(f);
+
+    /* Previously verified by upb_validate_enumdef(). */
+    assert(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0);
+
+    /* We've already validated that we have an associated enumdef and that it
+     * has at least one member, so at least one of these should be true.
+     * Because if the user didn't set anything, we'll pick up the enum's
+     * default, but if the user *did* set something we should at least pick up
+     * the one they set (int32 or string). */
+    assert(has_default_name || has_default_number);
+
+    if (!has_default_name) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%d) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultint32(f));
+      return false;
+    }
+
+    if (!has_default_number) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%s) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultstr(f, NULL));
+      return false;
+    }
+
+    /* Lift the effective numeric default into the field's default slot, in case
+     * we were only getting it "by reference" from the enumdef. */
+    upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f));
+  }
+
+  /* Ensure that MapEntry submessages only appear as repeated fields, not
+   * optional/required (singular) fields. */
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+      upb_fielddef_msgsubdef(f) != NULL) {
+    const upb_msgdef *subdef = upb_fielddef_msgsubdef(f);
+    if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) {
+      upb_status_seterrf(s,
+                         "Field %s refers to mapentry message but is not "
+                         "a repeated field",
+                         upb_fielddef_name(f) ? upb_fielddef_name(f) :
+                         "(unnamed)");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) {
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrf(s, "enum %s has no members (must have at least one)",
+                       upb_enumdef_fullname(e));
+    return false;
+  }
+
+  return true;
+}
+
+/* All submessage fields are lower than all other fields.
+ * Secondly, fields are increasing in order. */
+uint32_t field_rank(const upb_fielddef *f) {
+  uint32_t ret = upb_fielddef_number(f);
+  const uint32_t high_bit = 1 << 30;
+  assert(ret < high_bit);
+  if (!upb_fielddef_issubmsg(f))
+    ret |= high_bit;
+  return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+  const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+  const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+  return field_rank(f1) - field_rank(f2);
+}
+
+static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
+  /* Sort fields.  upb internally relies on UPB_TYPE_MESSAGE fields having the
+   * lowest indexes, but we do not publicly guarantee this. */
+  upb_msg_field_iter j;
+  int i;
+  uint32_t selector;
+  int n = upb_msgdef_numfields(m);
+  upb_fielddef **fields = malloc(n * sizeof(*fields));
+  if (!fields) return false;
+
+  m->submsg_field_count = 0;
+  for(i = 0, upb_msg_field_begin(&j, m);
+      !upb_msg_field_done(&j);
+      upb_msg_field_next(&j), i++) {
+    upb_fielddef *f = upb_msg_iter_field(&j);
+    assert(f->msg.def == m);
+    if (!upb_validate_field(f, s)) {
+      free(fields);
+      return false;
+    }
+    if (upb_fielddef_issubmsg(f)) {
+      m->submsg_field_count++;
+    }
+    fields[i] = f;
+  }
+
+  qsort(fields, n, sizeof(*fields), cmp_fields);
+
+  selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+  for (i = 0; i < n; i++) {
+    upb_fielddef *f = fields[i];
+    f->index_ = i;
+    f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+    selector += upb_handlers_selectorcount(f);
+  }
+  m->selector_count = selector;
+
+#ifndef NDEBUG
+  {
+    /* Verify that all selectors for the message are distinct. */
+#define TRY(type) \
+    if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v);
+
+    upb_inttable t;
+    upb_value v;
+    upb_selector_t sel;
+
+    upb_inttable_init(&t, UPB_CTYPE_BOOL);
+    v = upb_value_bool(true);
+    upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v);
+    upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v);
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      /* These calls will assert-fail in upb_table if the value already
+       * exists. */
+      TRY(UPB_HANDLER_INT32);
+      TRY(UPB_HANDLER_INT64)
+      TRY(UPB_HANDLER_UINT32)
+      TRY(UPB_HANDLER_UINT64)
+      TRY(UPB_HANDLER_FLOAT)
+      TRY(UPB_HANDLER_DOUBLE)
+      TRY(UPB_HANDLER_BOOL)
+      TRY(UPB_HANDLER_STARTSTR)
+      TRY(UPB_HANDLER_STRING)
+      TRY(UPB_HANDLER_ENDSTR)
+      TRY(UPB_HANDLER_STARTSUBMSG)
+      TRY(UPB_HANDLER_ENDSUBMSG)
+      TRY(UPB_HANDLER_STARTSEQ)
+      TRY(UPB_HANDLER_ENDSEQ)
+    }
+    upb_inttable_uninit(&t);
+  }
+#undef TRY
+#endif
+
+  free(fields);
+  return true;
+}
+
+bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
+  int i;
+  int maxdepth;
+  bool ret;
+  upb_status_clear(s);
+
+  /* First perform validation, in two passes so we can check that we have a
+   * transitive closure without needing to search. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    if (upb_def_isfrozen(def)) {
+      /* Could relax this requirement if it's annoying. */
+      upb_status_seterrmsg(s, "def is already frozen");
+      goto err;
+    } else if (def->type == UPB_DEF_FIELD) {
+      upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
+      goto err;
+    } else if (def->type == UPB_DEF_ENUM) {
+      if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) {
+        goto err;
+      }
+    } else {
+      /* Set now to detect transitive closure in the second pass. */
+      def->came_from_user = true;
+    }
+  }
+
+  /* Second pass of validation.  Also assign selector bases and indexes, and
+   * compact tables. */
+  for (i = 0; i < n; i++) {
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]);
+    upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]);
+    if (m) {
+      upb_inttable_compact(&m->itof);
+      if (!assign_msg_indices(m, s)) {
+        goto err;
+      }
+    } else if (e) {
+      upb_inttable_compact(&e->iton);
+    }
+  }
+
+  /* Def graph contains FieldDefs between each MessageDef, so double the
+   * limit. */
+  maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
+
+  /* Validation all passed; freeze the defs. */
+  ret = upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth);
+  assert(!(s && ret != upb_ok(s)));
+  return ret;
+
+err:
+  for (i = 0; i < n; i++) {
+    defs[i]->came_from_user = false;
+  }
+  assert(!(s && upb_ok(s)));
+  return false;
+}
+
+
+/* upb_enumdef ****************************************************************/
+
+static void upb_enumdef_free(upb_refcounted *r) {
+  upb_enumdef *e = (upb_enumdef*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &e->iton);
+  for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    /* To clean up the upb_strdup() from upb_enumdef_addval(). */
+    free(upb_value_getcstr(upb_inttable_iter_value(&i)));
+  }
+  upb_strtable_uninit(&e->ntoi);
+  upb_inttable_uninit(&e->iton);
+  upb_def_uninit(upb_enumdef_upcast_mutable(e));
+  free(e);
+}
+
+upb_enumdef *upb_enumdef_new(const void *owner) {
+  static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_enumdef_free};
+  upb_enumdef *e = malloc(sizeof(*e));
+  if (!e) return NULL;
+  if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM, &vtbl, owner))
+    goto err2;
+  if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2;
+  if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1;
+  return e;
+
+err1:
+  upb_strtable_uninit(&e->ntoi);
+err2:
+  free(e);
+  return NULL;
+}
+
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) {
+  upb_enum_iter i;
+  upb_enumdef *new_e = upb_enumdef_new(owner);
+  if (!new_e) return NULL;
+  for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+    bool success = upb_enumdef_addval(
+        new_e, upb_enum_iter_name(&i),upb_enum_iter_number(&i), NULL);
+    if (!success) {
+      upb_enumdef_unref(new_e, owner);
+      return NULL;
+    }
+  }
+  return new_e;
+}
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) {
+  upb_def *d = upb_enumdef_upcast_mutable(e);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_enumdef_fullname(const upb_enumdef *e) {
+  return upb_def_fullname(upb_enumdef_upcast(e));
+}
+
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s) {
+  return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s);
+}
+
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status) {
+  if (!upb_isident(name, strlen(name), false, status)) {
+    return false;
+  }
+  if (upb_enumdef_ntoiz(e, name, NULL)) {
+    upb_status_seterrf(status, "name '%s' is already defined", name);
+    return false;
+  }
+  if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+  if (!upb_inttable_lookup(&e->iton, num, NULL) &&
+      !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
+    upb_status_seterrmsg(status, "out of memory");
+    upb_strtable_remove(&e->ntoi, name, NULL);
+    return false;
+  }
+  if (upb_enumdef_numvals(e) == 1) {
+    bool ok = upb_enumdef_setdefault(e, num, NULL);
+    UPB_ASSERT_VAR(ok, ok);
+  }
+  return true;
+}
+
+int32_t upb_enumdef_default(const upb_enumdef *e) {
+  assert(upb_enumdef_iton(e, e->defaultval));
+  return e->defaultval;
+}
+
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) {
+  assert(!upb_enumdef_isfrozen(e));
+  if (!upb_enumdef_iton(e, val)) {
+    upb_status_seterrf(s, "number '%d' is not in the enum.", val);
+    return false;
+  }
+  e->defaultval = val;
+  return true;
+}
+
+int upb_enumdef_numvals(const upb_enumdef *e) {
+  return upb_strtable_count(&e->ntoi);
+}
+
+void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
+  /* We iterate over the ntoi table, to account for duplicate numbers. */
+  upb_strtable_begin(i, &e->ntoi);
+}
+
+void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
+bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
+
+bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
+                      size_t len, int32_t *num) {
+  upb_value v;
+  if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
+    return false;
+  }
+  if (num) *num = upb_value_getint32(v);
+  return true;
+}
+
+const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+  upb_value v;
+  return upb_inttable_lookup32(&def->iton, num, &v) ?
+      upb_value_getcstr(v) : NULL;
+}
+
+const char *upb_enum_iter_name(upb_enum_iter *iter) {
+  return upb_strtable_iter_key(iter);
+}
+
+int32_t upb_enum_iter_number(upb_enum_iter *iter) {
+  return upb_value_getint32(upb_strtable_iter_value(iter));
+}
+
+
+/* upb_fielddef ***************************************************************/
+
+static void upb_fielddef_init_default(upb_fielddef *f);
+
+static void upb_fielddef_uninit_default(upb_fielddef *f) {
+  if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes)
+    freestr(f->defaultval.bytes);
+}
+
+static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_fielddef *f = (const upb_fielddef*)r;
+  if (upb_fielddef_containingtype(f)) {
+    visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure);
+  }
+  if (upb_fielddef_containingoneof(f)) {
+    visit(r, upb_oneofdef_upcast2(upb_fielddef_containingoneof(f)), closure);
+  }
+  if (upb_fielddef_subdef(f)) {
+    visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure);
+  }
+}
+
+static void freefield(upb_refcounted *r) {
+  upb_fielddef *f = (upb_fielddef*)r;
+  upb_fielddef_uninit_default(f);
+  if (f->subdef_is_symbolic)
+    free(f->sub.name);
+  upb_def_uninit(upb_fielddef_upcast_mutable(f));
+  free(f);
+}
+
+static const char *enumdefaultstr(const upb_fielddef *f) {
+  const upb_enumdef *e;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (f->default_is_string && f->defaultval.bytes) {
+    /* Default was explicitly set as a string. */
+    str_t *s = f->defaultval.bytes;
+    return s->str;
+  } else if (e) {
+    if (!f->default_is_string) {
+      /* Default was explicitly set as an integer; look it up in enumdef. */
+      const char *name = upb_enumdef_iton(e, f->defaultval.sint);
+      if (name) {
+        return name;
+      }
+    } else {
+      /* Default is completely unset; pull enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        const char *name = upb_enumdef_iton(e, upb_enumdef_default(e));
+        assert(name);
+        return name;
+      }
+    }
+  }
+  return NULL;
+}
+
+static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) {
+  const upb_enumdef *e;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (!f->default_is_string) {
+    /* Default was explicitly set as an integer. */
+    *val = f->defaultval.sint;
+    return true;
+  } else if (e) {
+    if (f->defaultval.bytes) {
+      /* Default was explicitly set as a str; try to lookup corresponding int. */
+      str_t *s = f->defaultval.bytes;
+      if (upb_enumdef_ntoiz(e, s->str, val)) {
+        return true;
+      }
+    } else {
+      /* Default is unset; try to pull in enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        *val = upb_enumdef_default(e);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+upb_fielddef *upb_fielddef_new(const void *o) {
+  static const struct upb_refcounted_vtbl vtbl = {visitfield, freefield};
+  upb_fielddef *f = malloc(sizeof(*f));
+  if (!f) return NULL;
+  if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, &vtbl, o)) {
+    free(f);
+    return NULL;
+  }
+  f->msg.def = NULL;
+  f->sub.def = NULL;
+  f->oneof = NULL;
+  f->subdef_is_symbolic = false;
+  f->msg_is_symbolic = false;
+  f->label_ = UPB_LABEL_OPTIONAL;
+  f->type_ = UPB_TYPE_INT32;
+  f->number_ = 0;
+  f->type_is_set_ = false;
+  f->tagdelim = false;
+  f->is_extension_ = false;
+  f->lazy_ = false;
+  f->packed_ = true;
+
+  /* For the moment we default this to UPB_INTFMT_VARIABLE, since it will work
+   * with all integer types and is in some since more "default" since the most
+   * normal-looking proto2 types int32/int64/uint32/uint64 use variable.
+   *
+   * Other options to consider:
+   * - there is no default; users must set this manually (like type).
+   * - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to
+   *   be an optimal default for signed integers. */
+  f->intfmt = UPB_INTFMT_VARIABLE;
+  return f;
+}
+
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) {
+  const char *srcname;
+  upb_fielddef *newf = upb_fielddef_new(owner);
+  if (!newf) return NULL;
+  upb_fielddef_settype(newf, upb_fielddef_type(f));
+  upb_fielddef_setlabel(newf, upb_fielddef_label(f));
+  upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL);
+  upb_fielddef_setname(newf, upb_fielddef_name(f), NULL);
+  if (f->default_is_string && f->defaultval.bytes) {
+    str_t *s = f->defaultval.bytes;
+    upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL);
+  } else {
+    newf->default_is_string = f->default_is_string;
+    newf->defaultval = f->defaultval;
+  }
+
+  if (f->subdef_is_symbolic) {
+    srcname = f->sub.name;  /* Might be NULL. */
+  } else {
+    srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL;
+  }
+  if (srcname) {
+    char *newname = malloc(strlen(f->sub.def->fullname) + 2);
+    if (!newname) {
+      upb_fielddef_unref(newf, owner);
+      return NULL;
+    }
+    strcpy(newname, ".");
+    strcat(newname, f->sub.def->fullname);
+    upb_fielddef_setsubdefname(newf, newname, NULL);
+    free(newname);
+  }
+
+  return newf;
+}
+
+bool upb_fielddef_typeisset(const upb_fielddef *f) {
+  return f->type_is_set_;
+}
+
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+  assert(f->type_is_set_);
+  return f->type_;
+}
+
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+  return f->index_;
+}
+
+upb_label_t upb_fielddef_label(const upb_fielddef *f) {
+  return f->label_;
+}
+
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) {
+  return f->intfmt;
+}
+
+bool upb_fielddef_istagdelim(const upb_fielddef *f) {
+  return f->tagdelim;
+}
+
+uint32_t upb_fielddef_number(const upb_fielddef *f) {
+  return f->number_;
+}
+
+bool upb_fielddef_isextension(const upb_fielddef *f) {
+  return f->is_extension_;
+}
+
+bool upb_fielddef_lazy(const upb_fielddef *f) {
+  return f->lazy_;
+}
+
+bool upb_fielddef_packed(const upb_fielddef *f) {
+  return f->packed_;
+}
+
+const char *upb_fielddef_name(const upb_fielddef *f) {
+  return upb_def_fullname(upb_fielddef_upcast(f));
+}
+
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+  return f->msg_is_symbolic ? NULL : f->msg.def;
+}
+
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
+  return f->oneof;
+}
+
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) {
+  return (upb_msgdef*)upb_fielddef_containingtype(f);
+}
+
+const char *upb_fielddef_containingtypename(upb_fielddef *f) {
+  return f->msg_is_symbolic ? f->msg.name : NULL;
+}
+
+static void release_containingtype(upb_fielddef *f) {
+  if (f->msg_is_symbolic) free(f->msg.name);
+}
+
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s) {
+  assert(!upb_fielddef_isfrozen(f));
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(s, "field has already been added to a message.");
+    return false;
+  }
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+  release_containingtype(f);
+  f->msg.name = upb_strdup(name);
+  f->msg_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) {
+  if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) {
+    upb_status_seterrmsg(s, "Already added to message or oneof");
+    return false;
+  }
+  return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s);
+}
+
+static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) {
+  UPB_UNUSED(f);
+  UPB_UNUSED(type);
+  assert(f->type_is_set_ && upb_fielddef_type(f) == type);
+}
+
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_INT64);
+  return f->defaultval.sint;
+}
+
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
+  if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    int32_t val;
+    bool ok = enumdefaultint32(f, &val);
+    UPB_ASSERT_VAR(ok, ok);
+    return val;
+  } else {
+    chkdefaulttype(f, UPB_TYPE_INT32);
+    return f->defaultval.sint;
+  }
+}
+
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT64);
+  return f->defaultval.uint;
+}
+
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT32);
+  return f->defaultval.uint;
+}
+
+bool upb_fielddef_defaultbool(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_BOOL);
+  return f->defaultval.uint;
+}
+
+float upb_fielddef_defaultfloat(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_FLOAT);
+  return f->defaultval.flt;
+}
+
+double upb_fielddef_defaultdouble(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_DOUBLE);
+  return f->defaultval.dbl;
+}
+
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
+  assert(f->type_is_set_);
+  assert(upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES ||
+         upb_fielddef_type(f) == UPB_TYPE_ENUM);
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    const char *ret = enumdefaultstr(f);
+    assert(ret);
+    /* Enum defaults can't have embedded NULLs. */
+    if (len) *len = strlen(ret);
+    return ret;
+  }
+
+  if (f->default_is_string) {
+    str_t *str = f->defaultval.bytes;
+    if (len) *len = str->len;
+    return str->str;
+  }
+
+  return NULL;
+}
+
+static void upb_fielddef_init_default(upb_fielddef *f) {
+  f->default_is_string = false;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break;
+    case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break;
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64: f->defaultval.sint = 0; break;
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_BOOL: f->defaultval.uint = 0; break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      f->defaultval.bytes = newstr("", 0);
+      f->default_is_string = true;
+      break;
+    case UPB_TYPE_MESSAGE: break;
+    case UPB_TYPE_ENUM:
+      /* This is our special sentinel that indicates "not set" for an enum. */
+      f->default_is_string = true;
+      f->defaultval.bytes = NULL;
+      break;
+  }
+}
+
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f) {
+  return f->subdef_is_symbolic ? NULL : f->sub.def;
+}
+
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) {
+  return (upb_def*)upb_fielddef_subdef(f);
+}
+
+const char *upb_fielddef_subdefname(const upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    return f->sub.name;
+  } else if (f->sub.def) {
+    return upb_def_fullname(f->sub.def);
+  } else {
+    return NULL;
+  }
+}
+
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(
+        s, "cannot change field number after adding to a message");
+    return false;
+  }
+  if (number == 0 || number > UPB_MAX_FIELDNUMBER) {
+    upb_status_seterrf(s, "invalid field number (%u)", number);
+    return false;
+  }
+  f->number_ = number;
+  return true;
+}
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checktype(type));
+  upb_fielddef_uninit_default(f);
+  f->type_ = type;
+  f->type_is_set_ = true;
+  upb_fielddef_init_default(f);
+}
+
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) {
+  assert(!upb_fielddef_isfrozen(f));
+  switch (type) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+      upb_fielddef_settype(f, UPB_TYPE_DOUBLE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+      upb_fielddef_settype(f, UPB_TYPE_FLOAT);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      upb_fielddef_settype(f, UPB_TYPE_INT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+      upb_fielddef_settype(f, UPB_TYPE_UINT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      upb_fielddef_settype(f, UPB_TYPE_INT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+      upb_fielddef_settype(f, UPB_TYPE_UINT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      upb_fielddef_settype(f, UPB_TYPE_BOOL);
+      break;
+    case UPB_DESCRIPTOR_TYPE_STRING:
+      upb_fielddef_settype(f, UPB_TYPE_STRING);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BYTES:
+      upb_fielddef_settype(f, UPB_TYPE_BYTES);
+      break;
+    case UPB_DESCRIPTOR_TYPE_GROUP:
+    case UPB_DESCRIPTOR_TYPE_MESSAGE:
+      upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      upb_fielddef_settype(f, UPB_TYPE_ENUM);
+      break;
+    default: assert(false);
+  }
+
+  if (type == UPB_DESCRIPTOR_TYPE_FIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_FIXED32 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED);
+  } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 ||
+             type == UPB_DESCRIPTOR_TYPE_SINT32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG);
+  } else {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE);
+  }
+
+  upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP);
+}
+
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_FLOAT:  return UPB_DESCRIPTOR_TYPE_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE;
+    case UPB_TYPE_BOOL:   return UPB_DESCRIPTOR_TYPE_BOOL;
+    case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING;
+    case UPB_TYPE_BYTES:  return UPB_DESCRIPTOR_TYPE_BYTES;
+    case UPB_TYPE_ENUM:   return UPB_DESCRIPTOR_TYPE_ENUM;
+    case UPB_TYPE_INT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED32;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT32;
+      }
+    case UPB_TYPE_INT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED64;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT64;
+      }
+    case UPB_TYPE_UINT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED32;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_UINT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED64;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_MESSAGE:
+      return upb_fielddef_istagdelim(f) ?
+          UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE;
+  }
+  return 0;
+}
+
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->is_extension_ = is_extension;
+}
+
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->lazy_ = lazy;
+}
+
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->packed_ = packed;
+}
+
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checklabel(label));
+  f->label_ = label;
+}
+
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checkintfmt(fmt));
+  f->intfmt = fmt;
+}
+
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->tagdelim = tag_delim;
+  f->tagdelim = tag_delim;
+}
+
+static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) {
+  if (!f->type_is_set_ || upb_fielddef_isfrozen(f) ||
+      upb_fielddef_type(f) != type) {
+    assert(false);
+    return false;
+  }
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    assert(s || type == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  }
+  f->default_is_string = false;
+  return true;
+}
+
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) {
+  if (checksetdefault(f, UPB_TYPE_INT64))
+    f->defaultval.sint = value;
+}
+
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) {
+  if ((upb_fielddef_type(f) == UPB_TYPE_ENUM &&
+       checksetdefault(f, UPB_TYPE_ENUM)) ||
+      checksetdefault(f, UPB_TYPE_INT32)) {
+    f->defaultval.sint = value;
+  }
+}
+
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT64))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT32))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) {
+  if (checksetdefault(f, UPB_TYPE_BOOL))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) {
+  if (checksetdefault(f, UPB_TYPE_FLOAT))
+    f->defaultval.flt = value;
+}
+
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) {
+  if (checksetdefault(f, UPB_TYPE_DOUBLE))
+    f->defaultval.dbl = value;
+}
+
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s) {
+  str_t *str2;
+  assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM);
+  if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s))
+    return false;
+
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    assert(s || f->type_ == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  } else {
+    assert(f->type_ == UPB_TYPE_ENUM);
+  }
+
+  str2 = newstr(str, len);
+  f->defaultval.bytes = str2;
+  f->default_is_string = true;
+  return true;
+}
+
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s) {
+  assert(f->type_is_set_);
+  upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s);
+}
+
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) {
+  int32_t val;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultint32(f, &val);
+}
+
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) {
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultstr(f) != NULL;
+}
+
+static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
+                                 upb_status *s) {
+  if (f->type_ == UPB_TYPE_MESSAGE) {
+    if (upb_dyncast_msgdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
+    return false;
+  } else if (f->type_ == UPB_TYPE_ENUM) {
+    if (upb_dyncast_enumdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this enum field");
+    return false;
+  } else {
+    upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
+    return false;
+  }
+}
+
+static void release_subdef(upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    free(f->sub.name);
+  } else if (f->sub.def) {
+    upb_unref2(f->sub.def, f);
+  }
+}
+
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_hassubdef(f));
+  if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false;
+  release_subdef(f);
+  f->sub.def = subdef;
+  f->subdef_is_symbolic = false;
+  if (f->sub.def) upb_ref2(f->sub.def, f);
+  return true;
+}
+
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_msgdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s) {
+  assert(!upb_fielddef_isfrozen(f));
+  if (!upb_fielddef_hassubdef(f)) {
+    upb_status_seterrmsg(s, "field type does not accept a subdef");
+    return false;
+  }
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+  release_subdef(f);
+  f->sub.name = upb_strdup(name);
+  f->subdef_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_issubmsg(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+}
+
+bool upb_fielddef_isstring(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES;
+}
+
+bool upb_fielddef_isseq(const upb_fielddef *f) {
+  return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+}
+
+bool upb_fielddef_isprimitive(const upb_fielddef *f) {
+  return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+}
+
+bool upb_fielddef_ismap(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
+         upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+}
+
+bool upb_fielddef_hassubdef(const upb_fielddef *f) {
+  return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+}
+
+static bool between(int32_t x, int32_t low, int32_t high) {
+  return x >= low && x <= high;
+}
+
+bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+
+bool upb_fielddef_checkdescriptortype(int32_t type) {
+  return between(type, 1, 18);
+}
+
+/* upb_msgdef *****************************************************************/
+
+static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit,
+                     void *closure) {
+  upb_msg_oneof_iter o;
+  const upb_msgdef *m = (const upb_msgdef*)r;
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  for(upb_msg_oneof_begin(&o, m);
+      !upb_msg_oneof_done(&o);
+      upb_msg_oneof_next(&o)) {
+    upb_oneofdef *f = upb_msg_iter_oneof(&o);
+    visit(r, upb_oneofdef_upcast2(f), closure);
+  }
+}
+
+static void freemsg(upb_refcounted *r) {
+  upb_msgdef *m = (upb_msgdef*)r;
+  upb_strtable_uninit(&m->ntoo);
+  upb_strtable_uninit(&m->ntof);
+  upb_inttable_uninit(&m->itof);
+  upb_def_uninit(upb_msgdef_upcast_mutable(m));
+  free(m);
+}
+
+upb_msgdef *upb_msgdef_new(const void *owner) {
+  static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg};
+  upb_msgdef *m = malloc(sizeof(*m));
+  if (!m) return NULL;
+  if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &vtbl, owner))
+    goto err2;
+  if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err3;
+  if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1;
+  m->map_entry = false;
+  return m;
+
+err1:
+  upb_strtable_uninit(&m->ntof);
+err2:
+  upb_inttable_uninit(&m->itof);
+err3:
+  free(m);
+  return NULL;
+}
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
+  bool ok;
+  upb_msg_field_iter i;
+  upb_msg_oneof_iter o;
+
+  upb_msgdef *newm = upb_msgdef_new(owner);
+  if (!newm) return NULL;
+  ok = upb_def_setfullname(upb_msgdef_upcast_mutable(newm),
+                           upb_def_fullname(upb_msgdef_upcast(m)),
+                           NULL);
+  newm->map_entry = m->map_entry;
+  UPB_ASSERT_VAR(ok, ok);
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
+    /* Fields in oneofs are dup'd below. */
+    if (upb_fielddef_containingoneof(f)) continue;
+    if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) {
+      upb_msgdef_unref(newm, owner);
+      return NULL;
+    }
+  }
+  for(upb_msg_oneof_begin(&o, m);
+      !upb_msg_oneof_done(&o);
+      upb_msg_oneof_next(&o)) {
+    upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f);
+    if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) {
+      upb_msgdef_unref(newm, owner);
+      return NULL;
+    }
+  }
+  return newm;
+}
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) {
+  upb_def *d = upb_msgdef_upcast_mutable(m);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_msgdef_fullname(const upb_msgdef *m) {
+  return upb_def_fullname(upb_msgdef_upcast(m));
+}
+
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname,
+                            upb_status *s) {
+  return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s);
+}
+
+/* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error
+ * on status |s| and return false if not. */
+static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f,
+                            upb_status *s) {
+  if (upb_fielddef_containingtype(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a message");
+    return false;
+  } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_msgdef_ntofz(m, upb_fielddef_name(f)) ||
+             upb_msgdef_itof(m, upb_fielddef_number(f))) {
+    upb_status_seterrmsg(s, "duplicate field name or number for field");
+    return false;
+  }
+  return true;
+}
+
+static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) {
+  release_containingtype(f);
+  f->msg.def = m;
+  f->msg_is_symbolic = false;
+  upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, m);
+  upb_ref2(m, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+}
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s) {
+  /* TODO: extensions need to have a separate namespace, because proto2 allows a
+   * top-level extension (ie. one not in any package) to have the same name as a
+   * field from the message.
+   *
+   * This also implies that there needs to be a separate lookup-by-name method
+   * for extensions.  It seems desirable for iteration to return both extensions
+   * and non-extensions though.
+   *
+   * We also need to validate that the field number is in an extension range iff
+   * it is an extension.
+   *
+   * This method is idempotent. Check if |f| is already part of this msgdef and
+   * return immediately if so. */
+  if (upb_fielddef_containingtype(f) == m) {
+    return true;
+  }
+
+  /* Check constraints for all fields before performing any action. */
+  if (!check_field_add(m, f, s)) {
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    /* Fields in a oneof can only be added by adding the oneof to the msgdef. */
+    upb_status_seterrmsg(s, "fielddef is part of a oneof");
+    return false;
+  }
+
+  /* Constraint checks ok, perform the action. */
+  add_field(m, f, ref_donor);
+  return true;
+}
+
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s) {
+  upb_oneof_iter it;
+
+  /* Check various conditions that would prevent this oneof from being added. */
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneofdef already belongs to a message");
+    return false;
+  } else if (upb_oneofdef_name(o) == NULL) {
+    upb_status_seterrmsg(s, "oneofdef name was not set");
+    return false;
+  } else if (upb_msgdef_ntooz(m, upb_oneofdef_name(o))) {
+    upb_status_seterrmsg(s, "duplicate oneof name");
+    return false;
+  }
+
+  /* Check that all of the oneof's fields do not conflict with names or numbers
+   * of fields already in the message. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&it);
+    if (!check_field_add(m, f, s)) {
+      return false;
+    }
+  }
+
+  /* Everything checks out -- commit now. */
+
+  /* Add oneof itself first. */
+  o->parent = m;
+  upb_strtable_insert(&m->ntoo, upb_oneofdef_name(o), upb_value_ptr(o));
+  upb_ref2(o, m);
+  upb_ref2(m, o);
+
+  /* Add each field of the oneof directly to the msgdef. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    upb_fielddef *f = upb_oneof_iter_field(&it);
+    add_field(m, f, NULL);
+  }
+
+  if (ref_donor) upb_oneofdef_unref(o, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+  upb_value val;
+  return upb_inttable_lookup32(&m->itof, i, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+  return upb_strtable_lookup2(&m->ntof, name, len, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+  return upb_strtable_lookup2(&m->ntoo, name, len, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+int upb_msgdef_numfields(const upb_msgdef *m) {
+  return upb_strtable_count(&m->ntof);
+}
+
+int upb_msgdef_numoneofs(const upb_msgdef *m) {
+  return upb_strtable_count(&m->ntoo);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) {
+  assert(!upb_msgdef_isfrozen(m));
+  m->map_entry = map_entry;
+}
+
+bool upb_msgdef_mapentry(const upb_msgdef *m) {
+  return m->map_entry;
+}
+
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
+  upb_inttable_begin(iter, &m->itof);
+}
+
+void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
+
+bool upb_msg_field_done(const upb_msg_field_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
+  upb_strtable_begin(iter, &m->ntoo);
+}
+
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { upb_strtable_next(iter); }
+
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
+  return upb_strtable_done(iter);
+}
+
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
+  return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter));
+}
+
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
+  upb_strtable_iter_setdone(iter);
+}
+
+/* upb_oneofdef ***************************************************************/
+
+static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_oneofdef *o = (const upb_oneofdef*)r;
+  upb_oneof_iter i;
+  for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  if (o->parent) {
+    visit(r, upb_msgdef_upcast2(o->parent), closure);
+  }
+}
+
+static void freeoneof(upb_refcounted *r) {
+  upb_oneofdef *o = (upb_oneofdef*)r;
+  upb_strtable_uninit(&o->ntof);
+  upb_inttable_uninit(&o->itof);
+  upb_def_uninit(upb_oneofdef_upcast_mutable(o));
+  free(o);
+}
+
+upb_oneofdef *upb_oneofdef_new(const void *owner) {
+  static const struct upb_refcounted_vtbl vtbl = {visitoneof, freeoneof};
+  upb_oneofdef *o = malloc(sizeof(*o));
+  o->parent = NULL;
+  if (!o) return NULL;
+  if (!upb_def_init(upb_oneofdef_upcast_mutable(o), UPB_DEF_ONEOF, &vtbl,
+                    owner))
+    goto err2;
+  if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1;
+  return o;
+
+err1:
+  upb_inttable_uninit(&o->itof);
+err2:
+  free(o);
+  return NULL;
+}
+
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) {
+  bool ok;
+  upb_oneof_iter i;
+  upb_oneofdef *newo = upb_oneofdef_new(owner);
+  if (!newo) return NULL;
+  ok = upb_def_setfullname(upb_oneofdef_upcast_mutable(newo),
+                           upb_def_fullname(upb_oneofdef_upcast(o)), NULL);
+  UPB_ASSERT_VAR(ok, ok);
+  for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f);
+    if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) {
+      upb_oneofdef_unref(newo, owner);
+      return NULL;
+    }
+  }
+  return newo;
+}
+
+const char *upb_oneofdef_name(const upb_oneofdef *o) {
+  return upb_def_fullname(upb_oneofdef_upcast(o));
+}
+
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname,
+                             upb_status *s) {
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneof already added to a message");
+    return false;
+  }
+  return upb_def_setfullname(upb_oneofdef_upcast_mutable(o), fullname, s);
+}
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+  return o->parent;
+}
+
+int upb_oneofdef_numfields(const upb_oneofdef *o) {
+  return upb_strtable_count(&o->ntof);
+}
+
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s) {
+  assert(!upb_oneofdef_isfrozen(o));
+  assert(!o->parent || !upb_msgdef_isfrozen(o->parent));
+
+  /* This method is idempotent. Check if |f| is already part of this oneofdef
+   * and return immediately if so. */
+  if (upb_fielddef_containingoneof(f) == o) {
+    return true;
+  }
+
+  /* The field must have an OPTIONAL label. */
+  if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+    upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label");
+    return false;
+  }
+
+  /* Check that no field with this name or number exists already in the oneof.
+   * Also check that the field is not already part of a oneof. */
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) ||
+             upb_oneofdef_ntofz(o, upb_fielddef_name(f))) {
+    upb_status_seterrmsg(s, "duplicate field name or number");
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a oneof");
+    return false;
+  }
+
+  /* We allow adding a field to the oneof either if the field is not part of a
+   * msgdef, or if it is and we are also part of the same msgdef. */
+  if (o->parent == NULL) {
+    /* If we're not in a msgdef, the field cannot be either. Otherwise we would
+     * need to magically add this oneof to a msgdef to remain consistent, which
+     * is surprising behavior. */
+    if (upb_fielddef_containingtype(f) != NULL) {
+      upb_status_seterrmsg(s, "fielddef already belongs to a message, but "
+                              "oneof does not");
+      return false;
+    }
+  } else {
+    /* If we're in a msgdef, the user can add fields that either aren't in any
+     * msgdef (in which case they're added to our msgdef) or already a part of
+     * our msgdef. */
+    if (upb_fielddef_containingtype(f) != NULL &&
+        upb_fielddef_containingtype(f) != o->parent) {
+      upb_status_seterrmsg(s, "fielddef belongs to a different message "
+                              "than oneof");
+      return false;
+    }
+  }
+
+  /* Commit phase. First add the field to our parent msgdef, if any, because
+   * that may fail; then add the field to our own tables. */
+
+  if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) {
+    if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) {
+      return false;
+    }
+  }
+
+  release_containingtype(f);
+  f->oneof = o;
+  upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, o);
+  upb_ref2(o, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length) {
+  upb_value val;
+  return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+  upb_value val;
+  return upb_inttable_lookup32(&o->itof, num, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
+  upb_inttable_begin(iter, &o->itof);
+}
+
+void upb_oneof_next(upb_oneof_iter *iter) {
+  upb_inttable_next(iter);
+}
+
+bool upb_oneof_done(upb_oneof_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct cleanup_ent {
+  upb_cleanup_func *cleanup;
+  void *ud;
+  struct cleanup_ent *next;
+} cleanup_ent;
+
+static void *seeded_alloc(void *ud, void *ptr, size_t oldsize, size_t size);
+
+/* Default allocator **********************************************************/
+
+/* Just use realloc, keeping all allocated blocks in a linked list to destroy at
+ * the end. */
+
+typedef struct mem_block {
+  /* List is doubly-linked, because in cases where realloc() moves an existing
+   * block, we need to be able to remove the old pointer from the list
+   * efficiently. */
+  struct mem_block *prev, *next;
+#ifndef NDEBUG
+  size_t size;  /* Doesn't include mem_block structure. */
+#endif
+} mem_block;
+
+typedef struct {
+  mem_block *head;
+} default_alloc_ud;
+
+static void *default_alloc(void *_ud, void *ptr, size_t oldsize, size_t size) {
+  default_alloc_ud *ud = _ud;
+  mem_block *from, *block;
+  void *ret;
+  UPB_UNUSED(oldsize);
+
+  from = ptr ? (void*)((char*)ptr - sizeof(mem_block)) : NULL;
+
+#ifndef NDEBUG
+  if (from) {
+    assert(oldsize <= from->size);
+  }
+#endif
+
+  /* TODO(haberman): we probably need to provide even better alignment here,
+   * like 16-byte alignment of the returned data pointer. */
+  block = realloc(from, size + sizeof(mem_block));
+  if (!block) return NULL;
+  ret = (char*)block + sizeof(*block);
+
+#ifndef NDEBUG
+  block->size = size;
+#endif
+
+  if (from) {
+    if (block != from) {
+      /* The block was moved, so pointers in next and prev blocks must be
+       * updated to its new location. */
+      if (block->next) block->next->prev = block;
+      if (block->prev) block->prev->next = block;
+      if (ud->head == from) ud->head = block;
+    }
+  } else {
+    /* Insert at head of linked list. */
+    block->prev = NULL;
+    block->next = ud->head;
+    if (block->next) block->next->prev = block;
+    ud->head = block;
+  }
+
+  return ret;
+}
+
+static void default_alloc_cleanup(void *_ud) {
+  default_alloc_ud *ud = _ud;
+  mem_block *block = ud->head;
+
+  while (block) {
+    void *to_free = block;
+    block = block->next;
+    free(to_free);
+  }
+}
+
+
+/* Standard error functions ***************************************************/
+
+static bool default_err(void *ud, const upb_status *status) {
+  UPB_UNUSED(ud);
+  UPB_UNUSED(status);
+  return false;
+}
+
+static bool write_err_to(void *ud, const upb_status *status) {
+  upb_status *copy_to = ud;
+  upb_status_copy(copy_to, status);
+  return false;
+}
+
+
+/* upb_env ********************************************************************/
+
+void upb_env_init(upb_env *e) {
+  default_alloc_ud *ud = (default_alloc_ud*)&e->default_alloc_ud;
+  e->ok_ = true;
+  e->bytes_allocated = 0;
+  e->cleanup_head = NULL;
+
+  ud->head = NULL;
+
+  /* Set default functions. */
+  upb_env_setallocfunc(e, default_alloc, ud);
+  upb_env_seterrorfunc(e, default_err, NULL);
+}
+
+void upb_env_uninit(upb_env *e) {
+  cleanup_ent *ent = e->cleanup_head;
+
+  while (ent) {
+    ent->cleanup(ent->ud);
+    ent = ent->next;
+  }
+
+  /* Must do this after running cleanup functions, because this will delete
+     the memory we store our cleanup entries in! */
+  if (e->alloc == default_alloc) {
+    default_alloc_cleanup(e->alloc_ud);
+  }
+}
+
+UPB_FORCEINLINE void upb_env_setallocfunc(upb_env *e, upb_alloc_func *alloc,
+                                          void *ud) {
+  e->alloc = alloc;
+  e->alloc_ud = ud;
+}
+
+UPB_FORCEINLINE void upb_env_seterrorfunc(upb_env *e, upb_error_func *func,
+                                          void *ud) {
+  e->err = func;
+  e->err_ud = ud;
+}
+
+void upb_env_reporterrorsto(upb_env *e, upb_status *status) {
+  e->err = write_err_to;
+  e->err_ud = status;
+}
+
+bool upb_env_ok(const upb_env *e) {
+  return e->ok_;
+}
+
+bool upb_env_reporterror(upb_env *e, const upb_status *status) {
+  e->ok_ = false;
+  return e->err(e->err_ud, status);
+}
+
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) {
+  cleanup_ent *ent = upb_env_malloc(e, sizeof(cleanup_ent));
+  if (!ent) return false;
+
+  ent->cleanup = func;
+  ent->ud = ud;
+  ent->next = e->cleanup_head;
+  e->cleanup_head = ent;
+
+  return true;
+}
+
+void *upb_env_malloc(upb_env *e, size_t size) {
+  e->bytes_allocated += size;
+  if (e->alloc == seeded_alloc) {
+    /* This is equivalent to the next branch, but allows inlining for a
+     * measurable perf benefit. */
+    return seeded_alloc(e->alloc_ud, NULL, 0, size);
+  } else {
+    return e->alloc(e->alloc_ud, NULL, 0, size);
+  }
+}
+
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) {
+  char *ret;
+  assert(oldsize <= size);
+  ret = e->alloc(e->alloc_ud, ptr, oldsize, size);
+
+#ifndef NDEBUG
+  /* Overwrite non-preserved memory to ensure callers are passing the oldsize
+   * that they truly require. */
+  memset(ret + oldsize, 0xff, size - oldsize);
+#endif
+
+  return ret;
+}
+
+size_t upb_env_bytesallocated(const upb_env *e) {
+  return e->bytes_allocated;
+}
+
+
+/* upb_seededalloc ************************************************************/
+
+/* Be conservative and choose 16 in case anyone is using SSE. */
+static const size_t maxalign = 16;
+
+static size_t align_up(size_t size) {
+  return ((size + maxalign - 1) / maxalign) * maxalign;
+}
+
+UPB_FORCEINLINE static void *seeded_alloc(void *ud, void *ptr, size_t oldsize,
+                                          size_t size) {
+  upb_seededalloc *a = ud;
+
+  size = align_up(size);
+
+  assert(a->mem_limit >= a->mem_ptr);
+
+  if (oldsize == 0 && size <= (size_t)(a->mem_limit - a->mem_ptr)) {
+    /* Fast path: we can satisfy from the initial allocation. */
+    void *ret = a->mem_ptr;
+    a->mem_ptr += size;
+    return ret;
+  } else {
+    char *chptr = ptr;
+    /* Slow path: fallback to other allocator. */
+    a->need_cleanup = true;
+    /* Is `ptr` part of the user-provided initial block? Don't pass it to the
+     * default allocator if so; otherwise, it may try to realloc() the block. */
+    if (chptr >= a->mem_base && chptr < a->mem_limit) {
+      void *ret;
+      assert(chptr + oldsize <= a->mem_limit);
+      ret = a->alloc(a->alloc_ud, NULL, 0, size);
+      if (ret) memcpy(ret, ptr, oldsize);
+      return ret;
+    } else {
+      return a->alloc(a->alloc_ud, ptr, oldsize, size);
+    }
+  }
+}
+
+void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len) {
+  default_alloc_ud *ud = (default_alloc_ud*)&a->default_alloc_ud;
+  a->mem_base = mem;
+  a->mem_ptr = mem;
+  a->mem_limit = (char*)mem + len;
+  a->need_cleanup = false;
+  a->returned_allocfunc = false;
+
+  ud->head = NULL;
+
+  upb_seededalloc_setfallbackalloc(a, default_alloc, ud);
+}
+
+void upb_seededalloc_uninit(upb_seededalloc *a) {
+  if (a->alloc == default_alloc && a->need_cleanup) {
+    default_alloc_cleanup(a->alloc_ud);
+  }
+}
+
+UPB_FORCEINLINE void upb_seededalloc_setfallbackalloc(upb_seededalloc *a,
+                                                      upb_alloc_func *alloc,
+                                                      void *ud) {
+  assert(!a->returned_allocfunc);
+  a->alloc = alloc;
+  a->alloc_ud = ud;
+}
+
+upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a) {
+  a->returned_allocfunc = true;
+  return seeded_alloc;
+}
+/*
+** TODO(haberman): it's unclear whether a lot of the consistency checks should
+** assert() or return false.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/* Defined for the sole purpose of having a unique pointer value for
+ * UPB_NO_CLOSURE. */
+char _upb_noclosure;
+
+static void freehandlers(upb_refcounted *r) {
+  upb_handlers *h = (upb_handlers*)r;
+
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &h->cleanup_);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    void *val = (void*)upb_inttable_iter_key(&i);
+    upb_value func_val = upb_inttable_iter_value(&i);
+    upb_handlerfree *func = upb_value_getfptr(func_val);
+    func(val);
+  }
+
+  upb_inttable_uninit(&h->cleanup_);
+  upb_msgdef_unref(h->msg, h);
+  free(h->sub);
+  free(h);
+}
+
+static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
+                          void *closure) {
+  const upb_handlers *h = (const upb_handlers*)r;
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, h->msg);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub;
+    if (!upb_fielddef_issubmsg(f)) continue;
+    sub = upb_handlers_getsubhandlers(h, f);
+    if (sub) visit(r, upb_handlers_upcast(sub), closure);
+  }
+}
+
+static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
+
+typedef struct {
+  upb_inttable tab;  /* maps upb_msgdef* -> upb_handlers*. */
+  upb_handlers_callback *callback;
+  const void *closure;
+} dfs_state;
+
+/* TODO(haberman): discard upb_handlers* objects that do not actually have any
+ * handlers set and cannot reach any upb_handlers* object that does.  This is
+ * slightly tricky to do correctly. */
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
+                               dfs_state *s) {
+  upb_msg_field_iter i;
+  upb_handlers *h = upb_handlers_new(m, owner);
+  if (!h) return NULL;
+  if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+
+  s->callback(s->closure, h);
+
+  /* For each submessage field, get or create a handlers object and set it as
+   * the subhandlers. */
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_msgdef *subdef;
+    upb_value subm_ent;
+
+    if (!upb_fielddef_issubmsg(f)) continue;
+
+    subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+    if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
+      upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
+    } else {
+      upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
+      if (!sub_mh) goto oom;
+      upb_handlers_setsubhandlers(h, f, sub_mh);
+      upb_handlers_unref(sub_mh, &sub_mh);
+    }
+  }
+  return h;
+
+oom:
+  upb_handlers_unref(h, owner);
+  return NULL;
+}
+
+/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
+ * subhandlers for this submessage field. */
+#define SUBH(h, selector) (h->sub[selector])
+
+/* The selector for a submessage field is the field index. */
+#define SUBH_F(h, f) SUBH(h, f->index_)
+
+static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
+                         upb_handlertype_t type) {
+  upb_selector_t sel;
+  assert(!upb_handlers_isfrozen(h));
+  if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
+    upb_status_seterrf(
+        &h->status_, "type mismatch: field %s does not belong to message %s",
+        upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
+    return -1;
+  }
+  if (!upb_handlers_getselector(f, type, &sel)) {
+    upb_status_seterrf(
+        &h->status_,
+        "type mismatch: cannot register handler type %d for field %s",
+        type, upb_fielddef_name(f));
+    return -1;
+  }
+  return sel;
+}
+
+static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f,
+                             upb_handlertype_t type) {
+  int32_t sel = trygetsel(h, f, type);
+  assert(sel >= 0);
+  return sel;
+}
+
+static const void **returntype(upb_handlers *h, const upb_fielddef *f,
+                               upb_handlertype_t type) {
+  return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_;
+}
+
+static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f,
+                  upb_handlertype_t type, upb_func *func,
+                  upb_handlerattr *attr) {
+  upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
+  const void *closure_type;
+  const void **context_closure_type;
+
+  assert(!upb_handlers_isfrozen(h));
+
+  if (sel < 0) {
+    upb_status_seterrmsg(&h->status_,
+                         "incorrect handler type for this field.");
+    return false;
+  }
+
+  if (h->table[sel].func) {
+    upb_status_seterrmsg(&h->status_,
+                         "cannot change handler once it has been set.");
+    return false;
+  }
+
+  if (attr) {
+    set_attr = *attr;
+  }
+
+  /* Check that the given closure type matches the closure type that has been
+   * established for this context (if any). */
+  closure_type = upb_handlerattr_closuretype(&set_attr);
+
+  if (type == UPB_HANDLER_STRING) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR);
+  } else if (f && upb_fielddef_isseq(f) &&
+             type != UPB_HANDLER_STARTSEQ &&
+             type != UPB_HANDLER_ENDSEQ) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ);
+  } else {
+    context_closure_type = &h->top_closure_type;
+  }
+
+  if (closure_type && *context_closure_type &&
+      closure_type != *context_closure_type) {
+    /* TODO(haberman): better message for debugging. */
+    if (f) {
+      upb_status_seterrf(&h->status_,
+                         "closure type does not match for field %s",
+                         upb_fielddef_name(f));
+    } else {
+      upb_status_seterrmsg(
+          &h->status_, "closure type does not match for message-level handler");
+    }
+    return false;
+  }
+
+  if (closure_type)
+    *context_closure_type = closure_type;
+
+  /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer
+   * matches any pre-existing expectations about what type is expected. */
+  if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) {
+    const void *return_type = upb_handlerattr_returnclosuretype(&set_attr);
+    const void *table_return_type =
+        upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+    if (return_type && table_return_type && return_type != table_return_type) {
+      upb_status_seterrmsg(&h->status_, "closure return type does not match");
+      return false;
+    }
+
+    if (table_return_type && !return_type)
+      upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type);
+  }
+
+  h->table[sel].func = (upb_func*)func;
+  h->table[sel].attr = set_attr;
+  return true;
+}
+
+/* Returns the effective closure type for this handler (which will propagate
+ * from outer frames if this frame has no START* handler).  Not implemented for
+ * UPB_HANDLER_STRING at the moment since this is not needed.  Returns NULL is
+ * the effective closure type is unspecified (either no handler was registered
+ * to specify it or the handler that was registered did not specify the closure
+ * type). */
+const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f,
+                                   upb_handlertype_t type) {
+  const void *ret;
+  upb_selector_t sel;
+
+  assert(type != UPB_HANDLER_STRING);
+  ret = h->top_closure_type;
+
+  if (upb_fielddef_isseq(f) &&
+      type != UPB_HANDLER_STARTSEQ &&
+      type != UPB_HANDLER_ENDSEQ &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  if (type == UPB_HANDLER_STRING &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  /* The effective type of the submessage; not used yet.
+   * if (type == SUBMESSAGE &&
+   *     h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) {
+   *   ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+   * } */
+
+  return ret;
+}
+
+/* Checks whether the START* handler specified by f & type is missing even
+ * though it is required to convert the established type of an outer frame
+ * ("closure_type") into the established type of an inner frame (represented in
+ * the return closure type of this handler's attr. */
+bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type,
+                upb_status *status) {
+  const void *closure_type;
+  const upb_handlerattr *attr;
+  const void *return_closure_type;
+
+  upb_selector_t sel = handlers_getsel(h, f, type);
+  if (h->table[sel].func) return true;
+  closure_type = effective_closure_type(h, f, type);
+  attr = &h->table[sel].attr;
+  return_closure_type = upb_handlerattr_returnclosuretype(attr);
+  if (closure_type && return_closure_type &&
+      closure_type != return_closure_type) {
+    upb_status_seterrf(status,
+                       "expected start handler to return sub type for field %f",
+                       upb_fielddef_name(f));
+    return false;
+  }
+  return true;
+}
+
+/* Public interface ***********************************************************/
+
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+  int extra;
+  upb_handlers *h;
+
+  assert(upb_msgdef_isfrozen(md));
+
+  extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+  h = calloc(sizeof(*h) + extra, 1);
+  if (!h) return NULL;
+
+  h->msg = md;
+  upb_msgdef_ref(h->msg, h);
+  upb_status_clear(&h->status_);
+  h->sub = calloc(md->submsg_field_count, sizeof(*h->sub));
+  if (!h->sub) goto oom;
+  if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner))
+    goto oom;
+  if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom;
+
+  /* calloc() above initialized all handlers to NULL. */
+  return h;
+
+oom:
+  freehandlers(upb_handlers_upcast_mutable(h));
+  return NULL;
+}
+
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure) {
+  dfs_state state;
+  upb_handlers *ret;
+  bool ok;
+  upb_refcounted *r;
+
+  state.callback = callback;
+  state.closure = closure;
+  if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
+
+  ret = newformsg(m, owner, &state);
+
+  upb_inttable_uninit(&state.tab);
+  if (!ret) return NULL;
+
+  r = upb_handlers_upcast_mutable(ret);
+  ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
+  UPB_ASSERT_VAR(ok, ok);
+
+  return ret;
+}
+
+const upb_status *upb_handlers_status(upb_handlers *h) {
+  assert(!upb_handlers_isfrozen(h));
+  return &h->status_;
+}
+
+void upb_handlers_clearerr(upb_handlers *h) {
+  assert(!upb_handlers_isfrozen(h));
+  upb_status_clear(&h->status_);
+}
+
+#define SETTER(name, handlerctype, handlertype) \
+  bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
+                                handlerctype func, upb_handlerattr *attr) { \
+    int32_t sel = trygetsel(h, f, handlertype); \
+    return doset(h, sel, f, handlertype, (upb_func*)func, attr); \
+  }
+
+SETTER(int32,       upb_int32_handlerfunc*,       UPB_HANDLER_INT32)
+SETTER(int64,       upb_int64_handlerfunc*,       UPB_HANDLER_INT64)
+SETTER(uint32,      upb_uint32_handlerfunc*,      UPB_HANDLER_UINT32)
+SETTER(uint64,      upb_uint64_handlerfunc*,      UPB_HANDLER_UINT64)
+SETTER(float,       upb_float_handlerfunc*,       UPB_HANDLER_FLOAT)
+SETTER(double,      upb_double_handlerfunc*,      UPB_HANDLER_DOUBLE)
+SETTER(bool,        upb_bool_handlerfunc*,        UPB_HANDLER_BOOL)
+SETTER(startstr,    upb_startstr_handlerfunc*,    UPB_HANDLER_STARTSTR)
+SETTER(string,      upb_string_handlerfunc*,      UPB_HANDLER_STRING)
+SETTER(endstr,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSTR)
+SETTER(startseq,    upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSEQ)
+SETTER(startsubmsg, upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSUBMSG)
+SETTER(endsubmsg,   upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSUBMSG)
+SETTER(endseq,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSEQ)
+
+#undef SETTER
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr) {
+  return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr) {
+  assert(!upb_handlers_isfrozen(h));
+  return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub) {
+  assert(sub);
+  assert(!upb_handlers_isfrozen(h));
+  assert(upb_fielddef_issubmsg(f));
+  if (SUBH_F(h, f)) return false;  /* Can't reset. */
+  if (upb_msgdef_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+    return false;
+  }
+  SUBH_F(h, f) = sub;
+  upb_ref2(sub, h);
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f) {
+  assert(upb_fielddef_issubmsg(f));
+  return SUBH_F(h, f);
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel,
+                          upb_handlerattr *attr) {
+  if (!upb_handlers_gethandler(h, sel))
+    return false;
+  *attr = h->table[sel].attr;
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel) {
+  /* STARTSUBMSG selector in sel is the field's selector base. */
+  return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
+}
+
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
+
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) {
+  bool ok;
+  if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) {
+    return false;
+  }
+  ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
+  UPB_ASSERT_VAR(ok, ok);
+  return true;
+}
+
+
+/* "Static" methods ***********************************************************/
+
+bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
+  /* TODO: verify we have a transitive closure. */
+  int i;
+  for (i = 0; i < n; i++) {
+    upb_msg_field_iter j;
+    upb_handlers *h = handlers[i];
+
+    if (!upb_ok(&h->status_)) {
+      upb_status_seterrf(s, "handlers for message %s had error status: %s",
+                         upb_msgdef_fullname(upb_handlers_msgdef(h)),
+                         upb_status_errmsg(&h->status_));
+      return false;
+    }
+
+    /* Check that there are no closure mismatches due to missing Start* handlers
+     * or subhandlers with different type-level types. */
+    for(upb_msg_field_begin(&j, h->msg);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+
+      const upb_fielddef *f = upb_msg_iter_field(&j);
+      if (upb_fielddef_isseq(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s))
+          return false;
+      }
+
+      if (upb_fielddef_isstring(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s))
+          return false;
+      }
+
+      if (upb_fielddef_issubmsg(f)) {
+        bool hashandler = false;
+        if (upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) ||
+            upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) {
+          hashandler = true;
+        }
+
+        if (upb_fielddef_isseq(f) &&
+            (upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) ||
+             upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) {
+          hashandler = true;
+        }
+
+        if (hashandler && !upb_handlers_getsubhandlers(h, f)) {
+          /* For now we add an empty subhandlers in this case.  It makes the
+           * decoder code generator simpler, because it only has to handle two
+           * cases (submessage has handlers or not) as opposed to three
+           * (submessage has handlers in enclosing message but no subhandlers).
+           *
+           * This makes parsing less efficient in the case that we want to
+           * notice a submessage but skip its contents (like if we're testing
+           * for submessage presence or counting the number of repeated
+           * submessages).  In this case we will end up parsing the submessage
+           * field by field and throwing away the results for each, instead of
+           * skipping the whole delimited thing at once.  If this is an issue we
+           * can revisit it, but do remember that this only arises when you have
+           * handlers (startseq/startsubmsg/endsubmsg/endseq) set for the
+           * submessage but no subhandlers.  The uses cases for this are
+           * limited. */
+          upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub);
+          upb_handlers_setsubhandlers(h, f, sub);
+          upb_handlers_unref(sub, &sub);
+        }
+
+        /* TODO(haberman): check type of submessage.
+         * This is slightly tricky; also consider whether we should check that
+         * they match at setsubhandlers time. */
+      }
+    }
+  }
+
+  if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s,
+                             UPB_MAX_HANDLER_DEPTH)) {
+    return false;
+  }
+
+  return true;
+}
+
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
+    case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
+    case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
+    case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64;
+    case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE;
+    case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL;
+    default: assert(false); return -1;  /* Invalid input. */
+  }
+}
+
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s) {
+  switch (type) {
+    case UPB_HANDLER_INT32:
+    case UPB_HANDLER_INT64:
+    case UPB_HANDLER_UINT32:
+    case UPB_HANDLER_UINT64:
+    case UPB_HANDLER_FLOAT:
+    case UPB_HANDLER_DOUBLE:
+    case UPB_HANDLER_BOOL:
+      if (!upb_fielddef_isprimitive(f) ||
+          upb_handlers_getprimitivehandlertype(f) != type)
+        return false;
+      *s = f->selector_base;
+      break;
+    case UPB_HANDLER_STRING:
+      if (upb_fielddef_isstring(f)) {
+        *s = f->selector_base;
+      } else if (upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 3;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 1;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_ENDSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 2;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 2;
+      break;
+    case UPB_HANDLER_ENDSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 1;
+      break;
+    case UPB_HANDLER_STARTSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      /* Selectors for STARTSUBMSG are at the beginning of the table so that the
+       * selector can also be used as an index into the "sub" array of
+       * subhandlers.  The indexes for the two into these two tables are the
+       * same, except that in the handler table the static selectors come first. */
+      *s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
+      break;
+    case UPB_HANDLER_ENDSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      *s = f->selector_base;
+      break;
+  }
+  assert((size_t)*s < upb_fielddef_containingtype(f)->selector_count);
+  return true;
+}
+
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+  uint32_t ret = 1;
+  if (upb_fielddef_isseq(f)) ret += 2;    /* STARTSEQ/ENDSEQ */
+  if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */
+  if (upb_fielddef_issubmsg(f)) {
+    /* ENDSUBMSG (STARTSUBMSG is at table beginning) */
+    ret += 0;
+    if (upb_fielddef_lazy(f)) {
+      /* STARTSTR/ENDSTR/STRING (for lazy) */
+      ret += 3;
+    }
+  }
+  return ret;
+}
+
+
+/* upb_handlerattr ************************************************************/
+
+void upb_handlerattr_init(upb_handlerattr *attr) {
+  upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
+  memcpy(attr, &from, sizeof(*attr));
+}
+
+void upb_handlerattr_uninit(upb_handlerattr *attr) {
+  UPB_UNUSED(attr);
+}
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) {
+  attr->handler_data_ = hd;
+  return true;
+}
+
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) {
+  attr->closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) {
+  return attr->closure_type_;
+}
+
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type) {
+  attr->return_closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) {
+  return attr->return_closure_type_;
+}
+
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) {
+  attr->alwaysok_ = alwaysok;
+  return true;
+}
+
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) {
+  return attr->alwaysok_;
+}
+
+/* upb_bufhandle **************************************************************/
+
+size_t upb_bufhandle_objofs(const upb_bufhandle *h) {
+  return h->objofs_;
+}
+
+/* upb_byteshandler ***********************************************************/
+
+void upb_byteshandler_init(upb_byteshandler* h) {
+  memset(h, 0, sizeof(*h));
+}
+
+/* For when we support handlerfree callbacks. */
+void upb_byteshandler_uninit(upb_byteshandler* h) {
+  UPB_UNUSED(h);
+}
+
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d) {
+  h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d) {
+  h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d) {
+  h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+/*
+** upb::RefCounted Implementation
+**
+** Our key invariants are:
+** 1. reference cycles never span groups
+** 2. for ref2(to, from), we increment to's count iff group(from) != group(to)
+**
+** The previous two are how we avoid leaking cycles.  Other important
+** invariants are:
+** 3. for mutable objects "from" and "to", if there exists a ref2(to, from)
+**    this implies group(from) == group(to).  (In practice, what we implement
+**    is even stronger; "from" and "to" will share a group if there has *ever*
+**    been a ref2(to, from), but all that is necessary for correctness is the
+**    weaker one).
+** 4. mutable and immutable objects are never in the same group.
+*/
+
+
+#include <setjmp.h>
+#include <stdlib.h>
+
+static void freeobj(upb_refcounted *o);
+
+const char untracked_val;
+const void *UPB_UNTRACKED_REF = &untracked_val;
+
+/* arch-specific atomic primitives  *******************************************/
+
+#ifdef UPB_THREAD_UNSAFE /*---------------------------------------------------*/
+
+static void atomic_inc(uint32_t *a) { (*a)++; }
+static bool atomic_dec(uint32_t *a) { return --(*a) == 0; }
+
+#elif defined(__GNUC__) || defined(__clang__) /*------------------------------*/
+
+static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); }
+static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; }
+
+#elif defined(WIN32) /*-------------------------------------------------------*/
+
+#include <Windows.h>
+
+static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); }
+static bool atomic_dec(upb_atomic_t *a) {
+  return InterlockedDecrement(&a->val) == 0;
+}
+
+#else
+#error Atomic primitives not defined for your platform/CPU.  \
+       Implement them or compile with UPB_THREAD_UNSAFE.
+#endif
+
+/* All static objects point to this refcount.
+ * It is special-cased in ref/unref below.  */
+uint32_t static_refcount = -1;
+
+/* We can avoid atomic ops for statically-declared objects.
+ * This is a minor optimization but nice since we can avoid degrading under
+ * contention in this case. */
+
+static void refgroup(uint32_t *group) {
+  if (group != &static_refcount)
+    atomic_inc(group);
+}
+
+static bool unrefgroup(uint32_t *group) {
+  if (group == &static_refcount) {
+    return false;
+  } else {
+    return atomic_dec(group);
+  }
+}
+
+
+/* Reference tracking (debug only) ********************************************/
+
+#ifdef UPB_DEBUG_REFS
+
+#ifdef UPB_THREAD_UNSAFE
+
+static void upb_lock() {}
+static void upb_unlock() {}
+
+#else
+
+/* User must define functions that lock/unlock a global mutex and link this
+ * file against them. */
+void upb_lock();
+void upb_unlock();
+
+#endif
+
+/* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some
+ * code-paths that can normally never fail, like upb_refcounted_ref().  Since
+ * we have no way to propagage out-of-memory errors back to the user, and since
+ * these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail. */
+#define CHECK_OOM(predicate) if (!(predicate)) { assert(predicate); exit(1); }
+
+typedef struct {
+  int count;  /* How many refs there are (duplicates only allowed for ref2). */
+  bool is_ref2;
+} trackedref;
+
+static trackedref *trackedref_new(bool is_ref2) {
+  trackedref *ret = malloc(sizeof(*ret));
+  CHECK_OOM(ret);
+  ret->count = 1;
+  ret->is_ref2 = is_ref2;
+  return ret;
+}
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+
+  assert(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  if (upb_inttable_lookupptr(r->refs, owner, &v)) {
+    trackedref *ref = upb_value_getptr(v);
+    /* Since we allow multiple ref2's for the same to/from pair without
+     * allocating separate memory for each one, we lose the fine-grained
+     * tracking behavior we get with regular refs.  Since ref2s only happen
+     * inside upb, we'll accept this limitation until/unless there is a really
+     * difficult upb-internal bug that can't be figured out without it. */
+    assert(ref2);
+    assert(ref->is_ref2);
+    ref->count++;
+  } else {
+    trackedref *ref = trackedref_new(ref2);
+    bool ok = upb_inttable_insertptr(r->refs, owner, upb_value_ptr(ref));
+    CHECK_OOM(ok);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      assert(!upb_inttable_lookupptr(from->ref2s, r, NULL));
+      ok = upb_inttable_insertptr(from->ref2s, r, upb_value_ptr(NULL));
+      CHECK_OOM(ok);
+    }
+  }
+  upb_unlock();
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  assert(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  /* This assert will fail if an owner attempts to release a ref it didn't have. */
+  UPB_ASSERT_VAR(found, found);
+  ref = upb_value_getptr(v);
+  assert(ref->is_ref2 == ref2);
+  if (--ref->count == 0) {
+    free(ref);
+    upb_inttable_removeptr(r->refs, owner, NULL);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      bool removed = upb_inttable_removeptr(from->ref2s, r, NULL);
+      assert(removed);
+    }
+  }
+  upb_unlock();
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  UPB_ASSERT_VAR(found, found);
+  ref = upb_value_getptr(v);
+  assert(ref->is_ref2 == ref2);
+  upb_unlock();
+}
+
+/* Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that
+ * originate from the given owner. */
+static void getref2s(const upb_refcounted *owner, upb_inttable *tab) {
+  upb_inttable_iter i;
+
+  upb_lock();
+  upb_inttable_begin(&i, owner->ref2s);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_value v;
+    upb_value count;
+    trackedref *ref;
+    bool ok;
+    bool found;
+
+    upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i);
+
+    /* To get the count we need to look in the target's table. */
+    found = upb_inttable_lookupptr(to->refs, owner, &v);
+    assert(found);
+    ref = upb_value_getptr(v);
+    count = upb_value_int32(ref->count);
+
+    ok = upb_inttable_insertptr(tab, to, count);
+    CHECK_OOM(ok);
+  }
+  upb_unlock();
+}
+
+typedef struct {
+  upb_inttable ref2;
+  const upb_refcounted *obj;
+} check_state;
+
+static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj,
+                        void *closure) {
+  check_state *s = closure;
+  upb_inttable *ref2 = &s->ref2;
+  upb_value v;
+  bool removed;
+  int32_t newcount;
+
+  assert(obj == s->obj);
+  assert(subobj);
+  removed = upb_inttable_removeptr(ref2, subobj, &v);
+  /* The following assertion will fail if the visit() function visits a subobj
+   * that it did not have a ref2 on, or visits the same subobj too many times. */
+  assert(removed);
+  newcount = upb_value_getint32(v) - 1;
+  if (newcount > 0) {
+    upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount));
+  }
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  bool ok;
+
+  /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know
+   * exactly the set of nodes that visit() should visit.  So we verify visit()'s
+   * correctness here. */
+  check_state state;
+  state.obj = r;
+  ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32);
+  CHECK_OOM(ok);
+  getref2s(r, &state.ref2);
+
+  /* This should visit any children in the ref2 table. */
+  if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state);
+
+  /* This assertion will fail if the visit() function missed any children. */
+  assert(upb_inttable_count(&state.ref2) == 0);
+  upb_inttable_uninit(&state.ref2);
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+static bool trackinit(upb_refcounted *r) {
+  r->refs = malloc(sizeof(*r->refs));
+  r->ref2s = malloc(sizeof(*r->ref2s));
+  if (!r->refs || !r->ref2s) goto err1;
+
+  if (!upb_inttable_init(r->refs, UPB_CTYPE_PTR)) goto err1;
+  if (!upb_inttable_init(r->ref2s, UPB_CTYPE_PTR)) goto err2;
+  return true;
+
+err2:
+  upb_inttable_uninit(r->refs);
+err1:
+  free(r->refs);
+  free(r->ref2s);
+  return false;
+}
+
+static void trackfree(const upb_refcounted *r) {
+  upb_inttable_uninit(r->refs);
+  upb_inttable_uninit(r->ref2s);
+  free(r->refs);
+  free(r->ref2s);
+}
+
+#else
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static bool trackinit(upb_refcounted *r) {
+  UPB_UNUSED(r);
+  return true;
+}
+
+static void trackfree(const upb_refcounted *r) {
+  UPB_UNUSED(r);
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+#endif  /* UPB_DEBUG_REFS */
+
+
+/* freeze() *******************************************************************/
+
+/* The freeze() operation is by far the most complicated part of this scheme.
+ * We compute strongly-connected components and then mutate the graph such that
+ * we preserve the invariants documented at the top of this file.  And we must
+ * handle out-of-memory errors gracefully (without leaving the graph
+ * inconsistent), which adds to the fun. */
+
+/* The state used by the freeze operation (shared across many functions). */
+typedef struct {
+  int depth;
+  int maxdepth;
+  uint64_t index;
+  /* Maps upb_refcounted* -> attributes (color, etc).  attr layout varies by
+   * color. */
+  upb_inttable objattr;
+  upb_inttable stack;   /* stack of upb_refcounted* for Tarjan's algorithm. */
+  upb_inttable groups;  /* array of uint32_t*, malloc'd refcounts for new groups */
+  upb_status *status;
+  jmp_buf err;
+} tarjan;
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure);
+
+/* Node attributes -----------------------------------------------------------*/
+
+/* After our analysis phase all nodes will be either GRAY or WHITE. */
+
+typedef enum {
+  BLACK = 0,  /* Object has not been seen. */
+  GRAY,   /* Object has been found via a refgroup but may not be reachable. */
+  GREEN,  /* Object is reachable and is currently on the Tarjan stack. */
+  WHITE   /* Object is reachable and has been assigned a group (SCC). */
+} color_t;
+
+UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
+UPB_NORETURN static void oom(tarjan *t) {
+  upb_status_seterrmsg(t->status, "out of memory");
+  err(t);
+}
+
+static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  return upb_inttable_lookupptr(&t->objattr, r, &v) ?
+      upb_value_getuint64(v) : 0;
+}
+
+static uint64_t getattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  bool found = upb_inttable_lookupptr(&t->objattr, r, &v);
+  UPB_ASSERT_VAR(found, found);
+  return upb_value_getuint64(v);
+}
+
+static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) {
+  upb_inttable_removeptr(&t->objattr, r, NULL);
+  upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr));
+}
+
+static color_t color(tarjan *t, const upb_refcounted *r) {
+  return trygetattr(t, r) & 0x3;  /* Color is always stored in the low 2 bits. */
+}
+
+static void set_gray(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == BLACK);
+  setattr(t, r, GRAY);
+}
+
+/* Pushes an obj onto the Tarjan stack and sets it to GREEN. */
+static void push(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == BLACK || color(t, r) == GRAY);
+  /* This defines the attr layout for the GREEN state.  "index" and "lowlink"
+   * get 31 bits, which is plenty (limit of 2B objects frozen at a time). */
+  setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
+  if (++t->index == 0x80000000) {
+    upb_status_seterrmsg(t->status, "too many objects to freeze");
+    err(t);
+  }
+  upb_inttable_push(&t->stack, upb_value_ptr((void*)r));
+}
+
+/* Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its
+ * SCC group. */
+static upb_refcounted *pop(tarjan *t) {
+  upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack));
+  assert(color(t, r) == GREEN);
+  /* This defines the attr layout for nodes in the WHITE state.
+   * Top of group stack is [group, NULL]; we point at group. */
+  setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8);
+  return r;
+}
+
+static void tarjan_newgroup(tarjan *t) {
+  uint32_t *group = malloc(sizeof(*group));
+  if (!group) oom(t);
+  /* Push group and empty group leader (we'll fill in leader later). */
+  if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) ||
+      !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) {
+    free(group);
+    oom(t);
+  }
+  *group = 0;
+}
+
+static uint32_t idx(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == GREEN);
+  return (getattr(t, r) >> 2) & 0x7FFFFFFF;
+}
+
+static uint32_t lowlink(tarjan *t, const upb_refcounted *r) {
+  if (color(t, r) == GREEN) {
+    return getattr(t, r) >> 33;
+  } else {
+    return UINT32_MAX;
+  }
+}
+
+static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) {
+  assert(color(t, r) == GREEN);
+  setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF));
+}
+
+static uint32_t *group(tarjan *t, upb_refcounted *r) {
+  uint64_t groupnum;
+  upb_value v;
+  bool found;
+
+  assert(color(t, r) == WHITE);
+  groupnum = getattr(t, r) >> 8;
+  found = upb_inttable_lookup(&t->groups, groupnum, &v);
+  UPB_ASSERT_VAR(found, found);
+  return upb_value_getptr(v);
+}
+
+/* If the group leader for this object's group has not previously been set,
+ * the given object is assigned to be its leader. */
+static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) {
+  uint64_t leader_slot;
+  upb_value v;
+  bool found;
+
+  assert(color(t, r) == WHITE);
+  leader_slot = (getattr(t, r) >> 8) + 1;
+  found = upb_inttable_lookup(&t->groups, leader_slot, &v);
+  UPB_ASSERT_VAR(found, found);
+  if (upb_value_getptr(v)) {
+    return upb_value_getptr(v);
+  } else {
+    upb_inttable_remove(&t->groups, leader_slot, NULL);
+    upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r));
+    return r;
+  }
+}
+
+
+/* Tarjan's algorithm --------------------------------------------------------*/
+
+/* See:
+ *   http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */
+static void do_tarjan(const upb_refcounted *obj, tarjan *t);
+
+static void tarjan_visit(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  tarjan *t = closure;
+  if (++t->depth > t->maxdepth) {
+    upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth);
+    err(t);
+  } else if (subobj->is_frozen || color(t, subobj) == WHITE) {
+    /* Do nothing: we don't want to visit or color already-frozen nodes,
+     * and WHITE nodes have already been assigned a SCC. */
+  } else if (color(t, subobj) < GREEN) {
+    /* Subdef has not yet been visited; recurse on it. */
+    do_tarjan(subobj, t);
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj)));
+  } else if (color(t, subobj) == GREEN) {
+    /* Subdef is in the stack and hence in the current SCC. */
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj)));
+  }
+  --t->depth;
+}
+
+static void do_tarjan(const upb_refcounted *obj, tarjan *t) {
+  if (color(t, obj) == BLACK) {
+    /* We haven't seen this object's group; mark the whole group GRAY. */
+    const upb_refcounted *o = obj;
+    do { set_gray(t, o); } while ((o = o->next) != obj);
+  }
+
+  push(t, obj);
+  visit(obj, tarjan_visit, t);
+  if (lowlink(t, obj) == idx(t, obj)) {
+    tarjan_newgroup(t);
+    while (pop(t) != obj)
+      ;
+  }
+}
+
+
+/* freeze() ------------------------------------------------------------------*/
+
+static void crossref(const upb_refcounted *r, const upb_refcounted *subobj,
+                     void *_t) {
+  tarjan *t = _t;
+  assert(color(t, r) > BLACK);
+  if (color(t, subobj) > BLACK && r->group != subobj->group) {
+    /* Previously this ref was not reflected in subobj->group because they
+     * were in the same group; now that they are split a ref must be taken. */
+    refgroup(subobj->group);
+  }
+}
+
+static bool freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                   int maxdepth) {
+  volatile bool ret = false;
+  int i;
+  upb_inttable_iter iter;
+
+  /* We run in two passes so that we can allocate all memory before performing
+   * any mutation of the input -- this allows us to leave the input unchanged
+   * in the case of memory allocation failure. */
+  tarjan t;
+  t.index = 0;
+  t.depth = 0;
+  t.maxdepth = maxdepth;
+  t.status = s;
+  if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1;
+  if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3;
+  if (setjmp(t.err) != 0) goto err4;
+
+
+  for (i = 0; i < n; i++) {
+    if (color(&t, roots[i]) < GREEN) {
+      do_tarjan(roots[i], &t);
+    }
+  }
+
+  /* If we've made it this far, no further errors are possible so it's safe to
+   * mutate the objects without risk of leaving them in an inconsistent state. */
+  ret = true;
+
+  /* The transformation that follows requires care.  The preconditions are:
+   * - all objects in attr map are WHITE or GRAY, and are in mutable groups
+   *   (groups of all mutable objs)
+   * - no ref2(to, from) refs have incremented count(to) if both "to" and
+   *   "from" are in our attr map (this follows from invariants (2) and (3)) */
+
+  /* Pass 1: we remove WHITE objects from their mutable groups, and add them to
+   * new groups  according to the SCC's we computed.  These new groups will
+   * consist of only frozen objects.  None will be immediately collectible,
+   * because WHITE objects are by definition reachable from one of "roots",
+   * which the caller must own refs on. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    /* Since removal from a singly-linked list requires access to the object's
+     * predecessor, we consider obj->next instead of obj for moving.  With the
+     * while() loop we guarantee that we will visit every node's predecessor.
+     * Proof:
+     *  1. every node's predecessor is in our attr map.
+     *  2. though the loop body may change a node's predecessor, it will only
+     *     change it to be the node we are currently operating on, so with a
+     *     while() loop we guarantee ourselves the chance to remove each node. */
+    while (color(&t, obj->next) == WHITE &&
+           group(&t, obj->next) != obj->next->group) {
+      upb_refcounted *leader;
+
+      /* Remove from old group. */
+      upb_refcounted *move = obj->next;
+      if (obj == move) {
+        /* Removing the last object from a group. */
+        assert(*obj->group == obj->individual_count);
+        free(obj->group);
+      } else {
+        obj->next = move->next;
+        /* This may decrease to zero; we'll collect GRAY objects (if any) that
+         * remain in the group in the third pass. */
+        assert(*move->group >= move->individual_count);
+        *move->group -= move->individual_count;
+      }
+
+      /* Add to new group. */
+      leader = groupleader(&t, move);
+      if (move == leader) {
+        /* First object added to new group is its leader. */
+        move->group = group(&t, move);
+        move->next = move;
+        *move->group = move->individual_count;
+      } else {
+        /* Group already has at least one object in it. */
+        assert(leader->group == group(&t, move));
+        move->group = group(&t, move);
+        move->next = leader->next;
+        leader->next = move;
+        *move->group += move->individual_count;
+      }
+
+      move->is_frozen = true;
+    }
+  }
+
+  /* Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must
+   * increment count(to) if group(obj) != group(to) (which could now be the
+   * case if "to" was just frozen). */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    visit(obj, crossref, &t);
+  }
+
+  /* Pass 3: GRAY objects are collected if their group's refcount dropped to
+   * zero when we removed its white nodes.  This can happen if they had only
+   * been kept alive by virtue of sharing a group with an object that was just
+   * frozen.
+   *
+   * It is important that we do this last, since the GRAY object's free()
+   * function could call unref2() on just-frozen objects, which will decrement
+   * refs that were added in pass 2. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    if (obj->group == NULL || *obj->group == 0) {
+      if (obj->group) {
+        upb_refcounted *o;
+
+        /* We eagerly free() the group's count (since we can't easily determine
+         * the group's remaining size it's the easiest way to ensure it gets
+         * done). */
+        free(obj->group);
+
+        /* Visit to release ref2's (done in a separate pass since release_ref2
+         * depends on o->group being unmodified so it can test merged()). */
+        o = obj;
+        do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj);
+
+        /* Mark "group" fields as NULL so we know to free the objects later in
+         * this loop, but also don't try to delete the group twice. */
+        o = obj;
+        do { o->group = NULL; } while ((o = o->next) != obj);
+      }
+      freeobj(obj);
+    }
+  }
+
+err4:
+  if (!ret) {
+    upb_inttable_begin(&iter, &t.groups);
+    for(; !upb_inttable_done(&iter); upb_inttable_next(&iter))
+      free(upb_value_getptr(upb_inttable_iter_value(&iter)));
+  }
+  upb_inttable_uninit(&t.groups);
+err3:
+  upb_inttable_uninit(&t.stack);
+err2:
+  upb_inttable_uninit(&t.objattr);
+err1:
+  return ret;
+}
+
+
+/* Misc internal functions  ***************************************************/
+
+static bool merged(const upb_refcounted *r, const upb_refcounted *r2) {
+  return r->group == r2->group;
+}
+
+static void merge(upb_refcounted *r, upb_refcounted *from) {
+  upb_refcounted *base;
+  upb_refcounted *tmp;
+
+  if (merged(r, from)) return;
+  *r->group += *from->group;
+  free(from->group);
+  base = from;
+
+  /* Set all refcount pointers in the "from" chain to the merged refcount.
+   *
+   * TODO(haberman): this linear algorithm can result in an overall O(n^2) bound
+   * if the user continuously extends a group by one object.  Prevent this by
+   * using one of the techniques in this paper:
+   *     ftp://www.ncedc.org/outgoing/geomorph/dino/orals/p245-tarjan.pdf */
+  do { from->group = r->group; } while ((from = from->next) != base);
+
+  /* Merge the two circularly linked lists by swapping their next pointers. */
+  tmp = r->next;
+  r->next = base->next;
+  base->next = tmp;
+}
+
+static void unref(const upb_refcounted *r);
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  UPB_UNUSED(closure);
+  untrack(subobj, obj, true);
+  if (!merged(obj, subobj)) {
+    assert(subobj->is_frozen);
+    unref(subobj);
+  }
+}
+
+static void unref(const upb_refcounted *r) {
+  if (unrefgroup(r->group)) {
+    const upb_refcounted *o;
+
+    free(r->group);
+
+    /* In two passes, since release_ref2 needs a guarantee that any subobjs
+     * are alive. */
+    o = r;
+    do { visit(o, release_ref2, NULL); } while((o = o->next) != r);
+
+    o = r;
+    do {
+      const upb_refcounted *next = o->next;
+      assert(o->is_frozen || o->individual_count == 0);
+      freeobj((upb_refcounted*)o);
+      o = next;
+    } while(o != r);
+  }
+}
+
+static void freeobj(upb_refcounted *o) {
+  trackfree(o);
+  o->vtbl->free((upb_refcounted*)o);
+}
+
+
+/* Public interface ***********************************************************/
+
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+#ifndef NDEBUG
+  /* Endianness check.  This is unrelated to upb_refcounted, it's just a
+   * convenient place to put the check that we can be assured will run for
+   * basically every program using upb. */
+  const int x = 1;
+#ifdef UPB_BIG_ENDIAN
+  assert(*(char*)&x != 1);
+#else
+  assert(*(char*)&x == 1);
+#endif
+#endif
+
+  r->next = r;
+  r->vtbl = vtbl;
+  r->individual_count = 0;
+  r->is_frozen = false;
+  r->group = malloc(sizeof(*r->group));
+  if (!r->group) return false;
+  *r->group = 0;
+  if (!trackinit(r)) {
+    free(r->group);
+    return false;
+  }
+  upb_refcounted_ref(r, owner);
+  return true;
+}
+
+bool upb_refcounted_isfrozen(const upb_refcounted *r) {
+  return r->is_frozen;
+}
+
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner) {
+  track(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count++;
+  refgroup(r->group);
+}
+
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner) {
+  untrack(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count--;
+  unref(r);
+}
+
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) {
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
+  track(r, from, true);
+  if (r->is_frozen) {
+    refgroup(r->group);
+  } else {
+    merge((upb_refcounted*)r, from);
+  }
+}
+
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) {
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
+  untrack(r, from, true);
+  if (r->is_frozen) {
+    unref(r);
+  } else {
+    assert(merged(r, from));
+  }
+}
+
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to) {
+  assert(from != to);
+  if (to != NULL)
+    upb_refcounted_ref(r, to);
+  if (from != NULL)
+    upb_refcounted_unref(r, from);
+}
+
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) {
+  checkref(r, owner, false);
+}
+
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth) {
+  int i;
+  for (i = 0; i < n; i++) {
+    assert(!roots[i]->is_frozen);
+  }
+  return freeze(roots, n, s, maxdepth);
+}
+
+
+#include <stdlib.h>
+
+/* Fallback implementation if the shim is not specialized by the JIT. */
+#define SHIM_WRITER(type, ctype)                                              \
+  bool upb_shim_set ## type (void *c, const void *hd, ctype val) {            \
+    uint8_t *m = c;                                                           \
+    const upb_shim_data *d = hd;                                              \
+    if (d->hasbit > 0)                                                        \
+      *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8);                   \
+    *(ctype*)&m[d->offset] = val;                                             \
+    return true;                                                              \
+  }                                                                           \
+
+SHIM_WRITER(double, double)
+SHIM_WRITER(float,  float)
+SHIM_WRITER(int32,  int32_t)
+SHIM_WRITER(int64,  int64_t)
+SHIM_WRITER(uint32, uint32_t)
+SHIM_WRITER(uint64, uint64_t)
+SHIM_WRITER(bool,   bool)
+#undef SHIM_WRITER
+
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+                  int32_t hasbit) {
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  bool ok;
+
+  upb_shim_data *d = malloc(sizeof(*d));
+  if (!d) return false;
+  d->offset = offset;
+  d->hasbit = hasbit;
+
+  upb_handlerattr_sethandlerdata(&attr, d);
+  upb_handlerattr_setalwaysok(&attr, true);
+  upb_handlers_addcleanup(h, d, free);
+
+#define TYPE(u, l) \
+  case UPB_TYPE_##u: \
+    ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
+
+  ok = false;
+
+  switch (upb_fielddef_type(f)) {
+    TYPE(INT64,  int64);
+    TYPE(INT32,  int32);
+    TYPE(ENUM,   int32);
+    TYPE(UINT64, uint64);
+    TYPE(UINT32, uint32);
+    TYPE(DOUBLE, double);
+    TYPE(FLOAT,  float);
+    TYPE(BOOL,   bool);
+    default: assert(false); break;
+  }
+#undef TYPE
+
+  upb_handlerattr_uninit(&attr);
+  return ok;
+}
+
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+                                      upb_fieldtype_t *type) {
+  upb_func *f = upb_handlers_gethandler(h, s);
+
+  if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
+    *type = UPB_TYPE_INT64;
+  } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
+    *type = UPB_TYPE_INT32;
+  } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
+    *type = UPB_TYPE_UINT64;
+  } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
+    *type = UPB_TYPE_UINT32;
+  } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
+    *type = UPB_TYPE_DOUBLE;
+  } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
+    *type = UPB_TYPE_FLOAT;
+  } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
+    *type = UPB_TYPE_BOOL;
+  } else {
+    return NULL;
+  }
+
+  return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s);
+}
+
+
+#include <stdlib.h>
+#include <string.h>
+
+static void upb_symtab_free(upb_refcounted *r) {
+  upb_symtab *s = (upb_symtab*)r;
+  upb_strtable_iter i;
+  upb_strtable_begin(&i, &s->symtab);
+  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+    upb_def_unref(def, s);
+  }
+  upb_strtable_uninit(&s->symtab);
+  free(s);
+}
+
+
+upb_symtab *upb_symtab_new(const void *owner) {
+  static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free};
+  upb_symtab *s = malloc(sizeof(*s));
+  upb_refcounted_init(upb_symtab_upcast_mutable(s), &vtbl, owner);
+  upb_strtable_init(&s->symtab, UPB_CTYPE_PTR);
+  return s;
+}
+
+void upb_symtab_freeze(upb_symtab *s) {
+  upb_refcounted *r;
+  bool ok;
+
+  assert(!upb_symtab_isfrozen(s));
+  r = upb_symtab_upcast_mutable(s);
+  /* The symtab does not take ref2's (see refcounted.h) on the defs, because
+   * defs cannot refer back to the table and therefore cannot create cycles.  So
+   * 0 will suffice for maxdepth here. */
+  ok = upb_refcounted_freeze(&r, 1, NULL, 0);
+  UPB_ASSERT_VAR(ok, ok);
+}
+
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return ret;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+/* Given a symbol and the base symbol inside which it is defined, find the
+ * symbol's definition in t. */
+static upb_def *upb_resolvename(const upb_strtable *t,
+                                const char *base, const char *sym) {
+  if(strlen(sym) == 0) return NULL;
+  if(sym[0] == '.') {
+    /* Symbols starting with '.' are absolute, so we do a single lookup.
+     * Slice to omit the leading '.' */
+    upb_value v;
+    return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL;
+  } else {
+    /* Remove components from base until we find an entry or run out.
+     * TODO: This branch is totally broken, but currently not used. */
+    (void)base;
+    assert(false);
+    return NULL;
+  }
+}
+
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym) {
+  upb_def *ret = upb_resolvename(&s->symtab, base, sym);
+  return ret;
+}
+
+/* Starts a depth-first traversal at "def", recursing into any subdefs
+ * (ie. submessage types).  Adds duplicates of existing defs to addtab
+ * wherever necessary, so that the resulting symtab will be consistent once
+ * addtab is added.
+ *
+ * More specifically, if any def D is found in the DFS that:
+ *
+ *   1. can reach a def that is being replaced by something in addtab, AND
+ *
+ *   2. is not itself being replaced already (ie. this name doesn't already
+ *      exist in addtab)
+ *
+ * ...then a duplicate (new copy) of D will be added to addtab.
+ *
+ * Returns true if this happened for any def reachable from "def."
+ *
+ * It is slightly tricky to do this correctly in the presence of cycles.  If we
+ * detect that our DFS has hit a cycle, we might not yet know if any SCCs on
+ * our stack can reach a def in addtab or not.  Once we figure this out, that
+ * answer needs to apply to *all* defs in these SCCs, even if we visited them
+ * already.  So a straight up one-pass cycle-detecting DFS won't work.
+ *
+ * To work around this problem, we traverse each SCC (which we already
+ * computed, since these defs are frozen) as a single node.  We first compute
+ * whether the SCC as a whole can reach any def in addtab, then we dup (or not)
+ * the entire SCC.  This requires breaking the encapsulation of upb_refcounted,
+ * since that is where we get the data about what SCC we are in. */
+static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
+                            const void *new_owner, upb_inttable *seen,
+                            upb_status *s) {
+  upb_value v;
+  bool need_dup;
+  const upb_def *base;
+  const void* memoize_key;
+
+  /* Memoize results of this function for efficiency (since we're traversing a
+   * DAG this is not needed to limit the depth of the search).
+   *
+   * We memoize by SCC instead of by individual def. */
+  memoize_key = def->base.group;
+
+  if (upb_inttable_lookupptr(seen, memoize_key, &v))
+    return upb_value_getbool(v);
+
+  /* Visit submessages for all messages in the SCC. */
+  need_dup = false;
+  base = def;
+  do {
+    upb_value v;
+    const upb_msgdef *m;
+
+    assert(upb_def_isfrozen(def));
+    if (def->type == UPB_DEF_FIELD) continue;
+    if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
+      need_dup = true;
+    }
+
+    /* For messages, continue the recursion by visiting all subdefs, but only
+     * ones in different SCCs. */
+    m = upb_dyncast_msgdef(def);
+    if (m) {
+      upb_msg_field_iter i;
+      for(upb_msg_field_begin(&i, m);
+          !upb_msg_field_done(&i);
+          upb_msg_field_next(&i)) {
+        upb_fielddef *f = upb_msg_iter_field(&i);
+        const upb_def *subdef;
+
+        if (!upb_fielddef_hassubdef(f)) continue;
+        subdef = upb_fielddef_subdef(f);
+
+        /* Skip subdefs in this SCC. */
+        if (def->base.group == subdef->base.group) continue;
+
+        /* |= to avoid short-circuit; we need its side-effects. */
+        need_dup |= upb_resolve_dfs(subdef, addtab, new_owner, seen, s);
+        if (!upb_ok(s)) return false;
+      }
+    }
+  } while ((def = (upb_def*)def->base.next) != base);
+
+  if (need_dup) {
+    /* Dup all defs in this SCC that don't already have entries in addtab. */
+    def = base;
+    do {
+      const char *name;
+
+      if (def->type == UPB_DEF_FIELD) continue;
+      name = upb_def_fullname(def);
+      if (!upb_strtable_lookup(addtab, name, NULL)) {
+        upb_def *newdef = upb_def_dup(def, new_owner);
+        if (!newdef) goto oom;
+        newdef->came_from_user = false;
+        if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef)))
+          goto oom;
+      }
+    } while ((def = (upb_def*)def->base.next) != base);
+  }
+
+  upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup));
+  return need_dup;
+
+oom:
+  upb_status_seterrmsg(s, "out of memory");
+  return false;
+}
+
+/* TODO(haberman): we need a lot more testing of error conditions.
+ * The came_from_user stuff in particular is not tested. */
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
+                    upb_status *status) {
+  int i;
+  upb_strtable_iter iter;
+  upb_def **add_defs = NULL;
+  upb_strtable addtab;
+  upb_inttable seen;
+
+  assert(!upb_symtab_isfrozen(s));
+  if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+
+  /* Add new defs to our "add" set. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    const char *fullname;
+    upb_fielddef *f;
+
+    if (upb_def_isfrozen(def)) {
+      upb_status_seterrmsg(status, "added defs must be mutable");
+      goto err;
+    }
+    assert(!upb_def_isfrozen(def));
+    fullname = upb_def_fullname(def);
+    if (!fullname) {
+      upb_status_seterrmsg(
+          status, "Anonymous defs cannot be added to a symtab");
+      goto err;
+    }
+
+    f = upb_dyncast_fielddef_mutable(def);
+
+    if (f) {
+      if (!upb_fielddef_containingtypename(f)) {
+        upb_status_seterrmsg(status,
+                             "Standalone fielddefs must have a containing type "
+                             "(extendee) name set");
+        goto err;
+      }
+    } else {
+      if (upb_strtable_lookup(&addtab, fullname, NULL)) {
+        upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
+        goto err;
+      }
+      /* We need this to back out properly, because if there is a failure we
+       * need to donate the ref back to the caller. */
+      def->came_from_user = true;
+      upb_def_donateref(def, ref_donor, s);
+      if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def)))
+        goto oom_err;
+    }
+  }
+
+  /* Add standalone fielddefs (ie. extensions) to the appropriate messages.
+   * If the appropriate message only exists in the existing symtab, duplicate
+   * it so we have a mutable copy we can add the fields to. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
+    const char *msgname;
+    upb_value v;
+    upb_msgdef *m;
+
+    if (!f) continue;
+    msgname = upb_fielddef_containingtypename(f);
+    /* We validated this earlier in this function. */
+    assert(msgname);
+
+    /* If the extendee name is absolutely qualified, move past the initial ".".
+     * TODO(haberman): it is not obvious what it would mean if this was not
+     * absolutely qualified. */
+    if (msgname[0] == '.') {
+      msgname++;
+    }
+
+    if (upb_strtable_lookup(&addtab, msgname, &v)) {
+      /* Extendee is in the set of defs the user asked us to add. */
+      m = upb_value_getptr(v);
+    } else {
+      /* Need to find and dup the extendee from the existing symtab. */
+      const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname);
+      if (!frozen_m) {
+        upb_status_seterrf(status,
+                           "Tried to extend message %s that does not exist "
+                           "in this SymbolTable.",
+                           msgname);
+        goto err;
+      }
+      m = upb_msgdef_dup(frozen_m, s);
+      if (!m) goto oom_err;
+      if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) {
+        upb_msgdef_unref(m, s);
+        goto oom_err;
+      }
+    }
+
+    if (!upb_msgdef_addfield(m, f, ref_donor, status)) {
+      goto err;
+    }
+  }
+
+  /* Add dups of any existing def that can reach a def with the same name as
+   * anything in our "add" set. */
+  if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err;
+  upb_strtable_begin(&iter, &s->symtab);
+  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+    upb_resolve_dfs(def, &addtab, s, &seen, status);
+    if (!upb_ok(status)) goto err;
+  }
+  upb_inttable_uninit(&seen);
+
+  /* Now using the table, resolve symbolic references for subdefs. */
+  upb_strtable_begin(&iter, &addtab);
+  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    const char *base;
+    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+    upb_msg_field_iter j;
+
+    if (!m) continue;
+    /* Type names are resolved relative to the message in which they appear. */
+    base = upb_msgdef_fullname(m);
+
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      const char *name = upb_fielddef_subdefname(f);
+      if (name && !upb_fielddef_subdef(f)) {
+        /* Try the lookup in the current set of to-be-added defs first. If not
+         * there, try existing defs. */
+        upb_def *subdef = upb_resolvename(&addtab, base, name);
+        if (subdef == NULL) {
+          subdef = upb_resolvename(&s->symtab, base, name);
+        }
+        if (subdef == NULL) {
+          upb_status_seterrf(
+              status, "couldn't resolve name '%s' in message '%s'", name, base);
+          goto err;
+        } else if (!upb_fielddef_setsubdef(f, subdef, status)) {
+          goto err;
+        }
+      }
+    }
+  }
+
+  /* We need an array of the defs in addtab, for passing to upb_def_freeze. */
+  add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab));
+  if (add_defs == NULL) goto oom_err;
+  upb_strtable_begin(&iter, &addtab);
+  for (n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&iter));
+  }
+
+  if (!upb_def_freeze(add_defs, n, status)) goto err;
+
+  /* This must be delayed until all errors have been detected, since error
+   * recovery code uses this table to cleanup defs. */
+  upb_strtable_uninit(&addtab);
+
+  /* TODO(haberman) we don't properly handle errors after this point (like
+   * OOM in upb_strtable_insert() below). */
+  for (i = 0; i < n; i++) {
+    upb_def *def = add_defs[i];
+    const char *name = upb_def_fullname(def);
+    upb_value v;
+    bool success;
+
+    if (upb_strtable_remove(&s->symtab, name, &v)) {
+      const upb_def *def = upb_value_getptr(v);
+      upb_def_unref(def, s);
+    }
+    success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
+    UPB_ASSERT_VAR(success, success == true);
+  }
+  free(add_defs);
+  return true;
+
+oom_err:
+  upb_status_seterrmsg(status, "out of memory");
+err: {
+    /* For defs the user passed in, we need to donate the refs back.  For defs
+     * we dup'd, we need to just unref them. */
+    upb_strtable_begin(&iter, &addtab);
+    for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+      upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+      bool came_from_user = def->came_from_user;
+      def->came_from_user = false;
+      if (came_from_user) {
+        upb_def_donateref(def, s, ref_donor);
+      } else {
+        upb_def_unref(def, s);
+      }
+    }
+  }
+  upb_strtable_uninit(&addtab);
+  free(add_defs);
+  assert(!upb_ok(status));
+  return false;
+}
+
+/* Iteration. */
+
+static void advance_to_matching(upb_symtab_iter *iter) {
+  if (iter->type == UPB_DEF_ANY)
+    return;
+
+  while (!upb_strtable_done(&iter->iter) &&
+         iter->type != upb_symtab_iter_def(iter)->type) {
+    upb_strtable_next(&iter->iter);
+  }
+}
+
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type) {
+  upb_strtable_begin(&iter->iter, &s->symtab);
+  iter->type = type;
+  advance_to_matching(iter);
+}
+
+void upb_symtab_next(upb_symtab_iter *iter) {
+  upb_strtable_next(&iter->iter);
+  advance_to_matching(iter);
+}
+
+bool upb_symtab_done(const upb_symtab_iter *iter) {
+  return upb_strtable_done(&iter->iter);
+}
+
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) {
+  return upb_value_getptr(upb_strtable_iter_value(&iter->iter));
+}
+/*
+** upb_table Implementation
+**
+** Implementation is heavily inspired by Lua's ltable.c.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#define UPB_MAXARRSIZE 16  /* 64k. */
+
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+    ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
+static const double MAX_LOAD = 0.85;
+
+/* The minimum utilization of the array part of a mixed hash/array table.  This
+ * is a speed/memory-usage tradeoff (though it's not straightforward because of
+ * cache effects).  The lower this is, the more memory we'll use. */
+static const double MIN_DENSITY = 0.1;
+
+bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
+
+int log2ceil(uint64_t v) {
+  int ret = 0;
+  bool pow2 = is_pow2(v);
+  while (v >>= 1) ret++;
+  ret = pow2 ? ret : ret + 1;  /* Ceiling. */
+  return UPB_MIN(UPB_MAXARRSIZE, ret);
+}
+
+char *upb_strdup(const char *s) {
+  return upb_strdup2(s, strlen(s));
+}
+
+char *upb_strdup2(const char *s, size_t len) {
+  size_t n;
+  char *p;
+
+  /* Prevent overflow errors. */
+  if (len == SIZE_MAX) return NULL;
+  /* Always null-terminate, even if binary data; but don't rely on the input to
+   * have a null-terminating byte since it may be a raw binary buffer. */
+  n = len + 1;
+  p = malloc(n);
+  if (p) {
+    memcpy(p, s, len);
+    p[len] = 0;
+  }
+  return p;
+}
+
+/* A type to represent the lookup key of either a strtable or an inttable. */
+typedef union {
+  uintptr_t num;
+  struct {
+    const char *str;
+    size_t len;
+  } str;
+} lookupkey_t;
+
+static lookupkey_t strkey2(const char *str, size_t len) {
+  lookupkey_t k;
+  k.str.str = str;
+  k.str.len = len;
+  return k;
+}
+
+static lookupkey_t intkey(uintptr_t key) {
+  lookupkey_t k;
+  k.num = key;
+  return k;
+}
+
+typedef uint32_t hashfunc_t(upb_tabkey key);
+typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
+
+/* Base table (shared code) ***************************************************/
+
+/* For when we need to cast away const. */
+static upb_tabent *mutable_entries(upb_table *t) {
+  return (upb_tabent*)t->entries;
+}
+
+static bool isfull(upb_table *t) {
+  return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD;
+}
+
+static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) {
+  size_t bytes;
+
+  t->count = 0;
+  t->ctype = ctype;
+  t->size_lg2 = size_lg2;
+  t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
+  bytes = upb_table_size(t) * sizeof(upb_tabent);
+  if (bytes > 0) {
+    t->entries = malloc(bytes);
+    if (!t->entries) return false;
+    memset(mutable_entries(t), 0, bytes);
+  } else {
+    t->entries = NULL;
+  }
+  return true;
+}
+
+static void uninit(upb_table *t) { free(mutable_entries(t)); }
+
+static upb_tabent *emptyent(upb_table *t) {
+  upb_tabent *e = mutable_entries(t) + upb_table_size(t);
+  while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); }
+}
+
+static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+  return (upb_tabent*)upb_getentry(t, hash);
+}
+
+static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
+                                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e;
+
+  if (t->size_lg2 == 0) return NULL;
+  e = upb_getentry(t, hash);
+  if (upb_tabent_isempty(e)) return NULL;
+  while (1) {
+    if (eql(e->key, key)) return e;
+    if ((e = e->next) == NULL) return NULL;
+  }
+}
+
+static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
+                                     uint32_t hash, eqlfunc_t *eql) {
+  return (upb_tabent*)findentry(t, key, hash, eql);
+}
+
+static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
+                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e = findentry(t, key, hash, eql);
+  if (e) {
+    if (v) {
+      _upb_value_setval(v, e->val.val, t->ctype);
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* The given key must not already exist in the table. */
+static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
+                   upb_value val, uint32_t hash,
+                   hashfunc_t *hashfunc, eqlfunc_t *eql) {
+  upb_tabent *mainpos_e;
+  upb_tabent *our_e;
+
+  UPB_UNUSED(eql);
+  UPB_UNUSED(key);
+  assert(findentry(t, key, hash, eql) == NULL);
+  assert(val.ctype == t->ctype);
+
+  t->count++;
+  mainpos_e = getentry_mutable(t, hash);
+  our_e = mainpos_e;
+
+  if (upb_tabent_isempty(mainpos_e)) {
+    /* Our main position is empty; use it. */
+    our_e->next = NULL;
+  } else {
+    /* Collision. */
+    upb_tabent *new_e = emptyent(t);
+    /* Head of collider's chain. */
+    upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+    if (chain == mainpos_e) {
+      /* Existing ent is in its main posisiton (it has the same hash as us, and
+       * is the head of our chain).  Insert to new ent and append to this chain. */
+      new_e->next = mainpos_e->next;
+      mainpos_e->next = new_e;
+      our_e = new_e;
+    } else {
+      /* Existing ent is not in its main position (it is a node in some other
+       * chain).  This implies that no existing ent in the table has our hash.
+       * Evict it (updating its chain) and use its ent for head of our chain. */
+      *new_e = *mainpos_e;  /* copies next. */
+      while (chain->next != mainpos_e) {
+        chain = (upb_tabent*)chain->next;
+        assert(chain);
+      }
+      chain->next = new_e;
+      our_e = mainpos_e;
+      our_e->next = NULL;
+    }
+  }
+  our_e->key = tabkey;
+  our_e->val.val = val.val;
+  assert(findentry(t, key, hash, eql) == our_e);
+}
+
+static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
+               upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
+  upb_tabent *chain = getentry_mutable(t, hash);
+  if (upb_tabent_isempty(chain)) return false;
+  if (eql(chain->key, key)) {
+    /* Element to remove is at the head of its chain. */
+    t->count--;
+    if (val) {
+      _upb_value_setval(val, chain->val.val, t->ctype);
+    }
+    if (chain->next) {
+      upb_tabent *move = (upb_tabent*)chain->next;
+      *chain = *move;
+      if (removed) *removed = move->key;
+      move->key = 0;  /* Make the slot empty. */
+    } else {
+      if (removed) *removed = chain->key;
+      chain->key = 0;  /* Make the slot empty. */
+    }
+    return true;
+  } else {
+    /* Element to remove is either in a non-head position or not in the
+     * table. */
+    while (chain->next && !eql(chain->next->key, key))
+      chain = (upb_tabent*)chain->next;
+    if (chain->next) {
+      /* Found element to remove. */
+      upb_tabent *rm;
+
+      if (val) {
+        _upb_value_setval(val, chain->next->val.val, t->ctype);
+      }
+      rm = (upb_tabent*)chain->next;
+      if (removed) *removed = rm->key;
+      rm->key = 0;
+      chain->next = rm->next;
+      t->count--;
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
+
+static size_t next(const upb_table *t, size_t i) {
+  do {
+    if (++i >= upb_table_size(t))
+      return SIZE_MAX;
+  } while(upb_tabent_isempty(&t->entries[i]));
+
+  return i;
+}
+
+static size_t begin(const upb_table *t) {
+  return next(t, -1);
+}
+
+
+/* upb_strtable ***************************************************************/
+
+/* A simple "subclass" of upb_table that only adds a hash function for strings. */
+
+static upb_tabkey strcopy(lookupkey_t k2) {
+  char *str = malloc(k2.str.len + sizeof(uint32_t) + 1);
+  if (str == NULL) return 0;
+  memcpy(str, &k2.str.len, sizeof(uint32_t));
+  memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1);
+  return (uintptr_t)str;
+}
+
+static uint32_t strhash(upb_tabkey key) {
+  uint32_t len;
+  char *str = upb_tabstr(key, &len);
+  return MurmurHash2(str, len, 0);
+}
+
+static bool streql(upb_tabkey k1, lookupkey_t k2) {
+  uint32_t len;
+  char *str = upb_tabstr(k1, &len);
+  return len == k2.str.len && memcmp(str, k2.str.str, len) == 0;
+}
+
+bool upb_strtable_init(upb_strtable *t, upb_ctype_t ctype) {
+  return init(&t->t, ctype, 2);
+}
+
+void upb_strtable_uninit(upb_strtable *t) {
+  size_t i;
+  for (i = 0; i < upb_table_size(&t->t); i++)
+    free((void*)t->t.entries[i].key);
+  uninit(&t->t);
+}
+
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2) {
+  upb_strtable new_table;
+  upb_strtable_iter i;
+
+  if (!init(&new_table.t, t->t.ctype, size_lg2))
+    return false;
+  upb_strtable_begin(&i, t);
+  for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    upb_strtable_insert2(
+        &new_table,
+        upb_strtable_iter_key(&i),
+        upb_strtable_iter_keylength(&i),
+        upb_strtable_iter_value(&i));
+  }
+  upb_strtable_uninit(t);
+  *t = new_table;
+  return true;
+}
+
+bool upb_strtable_insert2(upb_strtable *t, const char *k, size_t len,
+                          upb_value v) {
+  lookupkey_t key;
+  upb_tabkey tabkey;
+  uint32_t hash;
+
+  if (isfull(&t->t)) {
+    /* Need to resize.  New table of double the size, add old elements to it. */
+    if (!upb_strtable_resize(t, t->t.size_lg2 + 1)) {
+      return false;
+    }
+  }
+
+  key = strkey2(k, len);
+  tabkey = strcopy(key);
+  if (tabkey == 0) return false;
+
+  hash = MurmurHash2(key.str.str, key.str.len, 0);
+  insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
+  return true;
+}
+
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v) {
+  uint32_t hash = MurmurHash2(key, len, 0);
+  return lookup(&t->t, strkey2(key, len), v, hash, &streql);
+}
+
+bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len,
+                         upb_value *val) {
+  uint32_t hash = MurmurHash2(key, strlen(key), 0);
+  upb_tabkey tabkey;
+  if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
+    free((void*)tabkey);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* Iteration */
+
+static const upb_tabent *str_tabent(const upb_strtable_iter *i) {
+  return &i->t->t.entries[i->index];
+}
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+  i->t = t;
+  i->index = begin(&t->t);
+}
+
+void upb_strtable_next(upb_strtable_iter *i) {
+  i->index = next(&i->t->t, i->index);
+}
+
+bool upb_strtable_done(const upb_strtable_iter *i) {
+  return i->index >= upb_table_size(&i->t->t) ||
+         upb_tabent_isempty(str_tabent(i));
+}
+
+const char *upb_strtable_iter_key(upb_strtable_iter *i) {
+  assert(!upb_strtable_done(i));
+  return upb_tabstr(str_tabent(i)->key, NULL);
+}
+
+size_t upb_strtable_iter_keylength(upb_strtable_iter *i) {
+  uint32_t len;
+  assert(!upb_strtable_done(i));
+  upb_tabstr(str_tabent(i)->key, &len);
+  return len;
+}
+
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+  assert(!upb_strtable_done(i));
+  return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype);
+}
+
+void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+  i->index = SIZE_MAX;
+}
+
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2) {
+  if (upb_strtable_done(i1) && upb_strtable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index;
+}
+
+
+/* upb_inttable ***************************************************************/
+
+/* For inttables we use a hybrid structure where small keys are kept in an
+ * array and large keys are put in the hash table. */
+
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
+
+static bool inteql(upb_tabkey k1, lookupkey_t k2) {
+  return k1 == k2.num;
+}
+
+static upb_tabval *mutable_array(upb_inttable *t) {
+  return (upb_tabval*)t->array;
+}
+
+static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) {
+  if (key < t->array_size) {
+    return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
+  } else {
+    upb_tabent *e =
+        findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
+    return e ? &e->val : NULL;
+  }
+}
+
+static const upb_tabval *inttable_val_const(const upb_inttable *t,
+                                            uintptr_t key) {
+  return inttable_val((upb_inttable*)t, key);
+}
+
+size_t upb_inttable_count(const upb_inttable *t) {
+  return t->t.count + t->array_count;
+}
+
+static void check(upb_inttable *t) {
+  UPB_UNUSED(t);
+#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
+  {
+    /* This check is very expensive (makes inserts/deletes O(N)). */
+    size_t count = 0;
+    upb_inttable_iter i;
+    upb_inttable_begin(&i, t);
+    for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+      assert(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
+    }
+    assert(count == upb_inttable_count(t));
+  }
+#endif
+}
+
+bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype,
+                            size_t asize, int hsize_lg2) {
+  size_t array_bytes;
+
+  if (!init(&t->t, ctype, hsize_lg2)) return false;
+  /* Always make the array part at least 1 long, so that we know key 0
+   * won't be in the hash part, which simplifies things. */
+  t->array_size = UPB_MAX(1, asize);
+  t->array_count = 0;
+  array_bytes = t->array_size * sizeof(upb_value);
+  t->array = malloc(array_bytes);
+  if (!t->array) {
+    uninit(&t->t);
+    return false;
+  }
+  memset(mutable_array(t), 0xff, array_bytes);
+  check(t);
+  return true;
+}
+
+bool upb_inttable_init(upb_inttable *t, upb_ctype_t ctype) {
+  return upb_inttable_sizedinit(t, ctype, 0, 4);
+}
+
+void upb_inttable_uninit(upb_inttable *t) {
+  uninit(&t->t);
+  free(mutable_array(t));
+}
+
+bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) {
+  /* XXX: Table can't store value (uint64_t)-1.  Need to somehow statically
+   * guarantee that this is not necessary, or fix the limitation. */
+  upb_tabval tabval;
+  tabval.val = val.val;
+  UPB_UNUSED(tabval);
+  assert(upb_arrhas(tabval));
+
+  if (key < t->array_size) {
+    assert(!upb_arrhas(t->array[key]));
+    t->array_count++;
+    mutable_array(t)[key].val = val.val;
+  } else {
+    if (isfull(&t->t)) {
+      /* Need to resize the hash part, but we re-use the array part. */
+      size_t i;
+      upb_table new_table;
+      if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1))
+        return false;
+      for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
+        const upb_tabent *e = &t->t.entries[i];
+        uint32_t hash;
+        upb_value v;
+
+        _upb_value_setval(&v, e->val.val, t->t.ctype);
+        hash = upb_inthash(e->key);
+        insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
+      }
+
+      assert(t->t.count == new_table.count);
+
+      uninit(&t->t);
+      t->t = new_table;
+    }
+    insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
+  }
+  check(t);
+  return true;
+}
+
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
+  const upb_tabval *table_v = inttable_val_const(t, key);
+  if (!table_v) return false;
+  if (v) _upb_value_setval(v, table_v->val, t->t.ctype);
+  return true;
+}
+
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
+  upb_tabval *table_v = inttable_val(t, key);
+  if (!table_v) return false;
+  table_v->val = val.val;
+  return true;
+}
+
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+  bool success;
+  if (key < t->array_size) {
+    if (upb_arrhas(t->array[key])) {
+      upb_tabval empty = UPB_TABVALUE_EMPTY_INIT;
+      t->array_count--;
+      if (val) {
+        _upb_value_setval(val, t->array[key].val, t->t.ctype);
+      }
+      mutable_array(t)[key] = empty;
+      success = true;
+    } else {
+      success = false;
+    }
+  } else {
+    upb_tabkey removed;
+    uint32_t hash = upb_inthash(key);
+    success = rm(&t->t, intkey(key), val, &removed, hash, &inteql);
+  }
+  check(t);
+  return success;
+}
+
+bool upb_inttable_push(upb_inttable *t, upb_value val) {
+  return upb_inttable_insert(t, upb_inttable_count(t), val);
+}
+
+upb_value upb_inttable_pop(upb_inttable *t) {
+  upb_value val;
+  bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val);
+  UPB_ASSERT_VAR(ok, ok);
+  return val;
+}
+
+bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) {
+  return upb_inttable_insert(t, (uintptr_t)key, val);
+}
+
+bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
+                            upb_value *v) {
+  return upb_inttable_lookup(t, (uintptr_t)key, v);
+}
+
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
+  return upb_inttable_remove(t, (uintptr_t)key, val);
+}
+
+void upb_inttable_compact(upb_inttable *t) {
+  /* Create a power-of-two histogram of the table keys. */
+  int counts[UPB_MAXARRSIZE + 1] = {0};
+  uintptr_t max_key = 0;
+  upb_inttable_iter i;
+  size_t arr_size;
+  int arr_count;
+  upb_inttable new_t;
+
+  upb_inttable_begin(&i, t);
+  for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    uintptr_t key = upb_inttable_iter_key(&i);
+    if (key > max_key) {
+      max_key = key;
+    }
+    counts[log2ceil(key)]++;
+  }
+
+  arr_size = 1;
+  arr_count = upb_inttable_count(t);
+
+  if (upb_inttable_count(t) >= max_key * MIN_DENSITY) {
+    /* We can put 100% of the entries in the array part. */
+    arr_size = max_key + 1;
+  } else {
+    /* Find the largest power of two that satisfies the MIN_DENSITY
+     * definition. */
+    int size_lg2;
+    for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 1; size_lg2--) {
+      arr_size = 1 << size_lg2;
+      arr_count -= counts[size_lg2];
+      if (arr_count >= arr_size * MIN_DENSITY) {
+        break;
+      }
+    }
+  }
+
+  /* Array part must always be at least 1 entry large to catch lookups of key
+   * 0.  Key 0 must always be in the array part because "0" in the hash part
+   * denotes an empty entry. */
+  arr_size = UPB_MAX(arr_size, 1);
+
+  {
+    /* Insert all elements into new, perfectly-sized table. */
+    int hash_count = upb_inttable_count(t) - arr_count;
+    int hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
+    int hashsize_lg2 = log2ceil(hash_size);
+
+    assert(hash_count >= 0);
+    upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2);
+    upb_inttable_begin(&i, t);
+    for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+      uintptr_t k = upb_inttable_iter_key(&i);
+      upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i));
+    }
+    assert(new_t.array_size == arr_size);
+    assert(new_t.t.size_lg2 == hashsize_lg2);
+  }
+  upb_inttable_uninit(t);
+  *t = new_t;
+}
+
+/* Iteration. */
+
+static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+  assert(!i->array_part);
+  return &i->t->t.entries[i->index];
+}
+
+static upb_tabval int_arrent(const upb_inttable_iter *i) {
+  assert(i->array_part);
+  return i->t->array[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+  i->t = t;
+  i->index = -1;
+  i->array_part = true;
+  upb_inttable_next(i);
+}
+
+void upb_inttable_next(upb_inttable_iter *iter) {
+  const upb_inttable *t = iter->t;
+  if (iter->array_part) {
+    while (++iter->index < t->array_size) {
+      if (upb_arrhas(int_arrent(iter))) {
+        return;
+      }
+    }
+    iter->array_part = false;
+    iter->index = begin(&t->t);
+  } else {
+    iter->index = next(&t->t, iter->index);
+  }
+}
+
+bool upb_inttable_done(const upb_inttable_iter *i) {
+  if (i->array_part) {
+    return i->index >= i->t->array_size ||
+           !upb_arrhas(int_arrent(i));
+  } else {
+    return i->index >= upb_table_size(&i->t->t) ||
+           upb_tabent_isempty(int_tabent(i));
+  }
+}
+
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+  assert(!upb_inttable_done(i));
+  return i->array_part ? i->index : int_tabent(i)->key;
+}
+
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+  assert(!upb_inttable_done(i));
+  return _upb_value_val(
+      i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val,
+      i->t->t.ctype);
+}
+
+void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+  i->index = SIZE_MAX;
+  i->array_part = false;
+}
+
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                                          const upb_inttable_iter *i2) {
+  if (upb_inttable_done(i1) && upb_inttable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index &&
+         i1->array_part == i2->array_part;
+}
+
+#ifdef UPB_UNALIGNED_READS_OK
+/* -----------------------------------------------------------------------------
+ * MurmurHash2, by Austin Appleby (released as public domain).
+ * Reformatted and C99-ified by Joshua Haberman.
+ * Note - This code makes a few assumptions about how your machine behaves -
+ *   1. We can read a 4-byte value from any address without crashing
+ *   2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t
+ * And it has a few limitations -
+ *   1. It will not work incrementally.
+ *   2. It will not produce the same results on little-endian and big-endian
+ *      machines. */
+uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) {
+  /* 'm' and 'r' are mixing constants generated offline.
+   * They're not really 'magic', they just happen to work well. */
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+
+  /* Initialize the hash to a 'random' value */
+  uint32_t h = seed ^ len;
+
+  /* Mix 4 bytes at a time into the hash */
+  const uint8_t * data = (const uint8_t *)key;
+  while(len >= 4) {
+    uint32_t k = *(uint32_t *)data;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h *= m;
+    h ^= k;
+
+    data += 4;
+    len -= 4;
+  }
+
+  /* Handle the last few bytes of the input array */
+  switch(len) {
+    case 3: h ^= data[2] << 16;
+    case 2: h ^= data[1] << 8;
+    case 1: h ^= data[0]; h *= m;
+  };
+
+  /* Do a few final mixes of the hash to ensure the last few
+   * bytes are well-incorporated. */
+  h ^= h >> 13;
+  h *= m;
+  h ^= h >> 15;
+
+  return h;
+}
+
+#else /* !UPB_UNALIGNED_READS_OK */
+
+/* -----------------------------------------------------------------------------
+ * MurmurHashAligned2, by Austin Appleby
+ * Same algorithm as MurmurHash2, but only does aligned reads - should be safer
+ * on certain platforms.
+ * Performance will be lower than MurmurHash2 */
+
+#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) {
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+  const uint8_t * data = (const uint8_t *)key;
+  uint32_t h = seed ^ len;
+  uint8_t align = (uintptr_t)data & 3;
+
+  if(align && (len >= 4)) {
+    /* Pre-load the temp registers */
+    uint32_t t = 0, d = 0;
+    int32_t sl;
+    int32_t sr;
+
+    switch(align) {
+      case 1: t |= data[2] << 16;
+      case 2: t |= data[1] << 8;
+      case 3: t |= data[0];
+    }
+
+    t <<= (8 * align);
+
+    data += 4-align;
+    len -= 4-align;
+
+    sl = 8 * (4-align);
+    sr = 8 * align;
+
+    /* Mix */
+
+    while(len >= 4) {
+      uint32_t k;
+
+      d = *(uint32_t *)data;
+      t = (t >> sr) | (d << sl);
+
+      k = t;
+
+      MIX(h,k,m);
+
+      t = d;
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* Handle leftover data in temp registers */
+
+    d = 0;
+
+    if(len >= align) {
+      uint32_t k;
+
+      switch(align) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+      }
+
+      k = (t >> sr) | (d << sl);
+      MIX(h,k,m);
+
+      data += align;
+      len -= align;
+
+      /* ----------
+       * Handle tail bytes */
+
+      switch(len) {
+        case 3: h ^= data[2] << 16;
+        case 2: h ^= data[1] << 8;
+        case 1: h ^= data[0]; h *= m;
+      };
+    } else {
+      switch(len) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+        case 0: h ^= (t >> sr) | (d << sl); h *= m;
+      }
+    }
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  } else {
+    while(len >= 4) {
+      uint32_t k = *(uint32_t *)data;
+
+      MIX(h,k,m);
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* ----------
+     * Handle tail bytes */
+
+    switch(len) {
+      case 3: h ^= data[2] << 16;
+      case 2: h ^= data[1] << 8;
+      case 1: h ^= data[0]; h *= m;
+    };
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  }
+}
+#undef MIX
+
+#endif /* UPB_UNALIGNED_READS_OK */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool upb_dumptostderr(void *closure, const upb_status* status) {
+  UPB_UNUSED(closure);
+  fprintf(stderr, "%s\n", upb_status_errmsg(status));
+  return false;
+}
+
+/* Guarantee null-termination and provide ellipsis truncation.
+ * It may be tempting to "optimize" this by initializing these final
+ * four bytes up-front and then being careful never to overwrite them,
+ * this is safer and simpler. */
+static void nullz(upb_status *status) {
+  const char *ellipsis = "...";
+  size_t len = strlen(ellipsis);
+  assert(sizeof(status->msg) > len);
+  memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
+}
+
+void upb_status_clear(upb_status *status) {
+  if (!status) return;
+  status->ok_ = true;
+  status->code_ = 0;
+  status->msg[0] = '\0';
+}
+
+bool upb_ok(const upb_status *status) { return status->ok_; }
+
+upb_errorspace *upb_status_errspace(const upb_status *status) {
+  return status->error_space_;
+}
+
+int upb_status_errcode(const upb_status *status) { return status->code_; }
+
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+  if (!status) return;
+  status->ok_ = false;
+  strncpy(status->msg, msg, sizeof(status->msg));
+  nullz(status);
+}
+
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  upb_status_vseterrf(status, fmt, args);
+  va_end(args);
+}
+
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+  if (!status) return;
+  status->ok_ = false;
+  _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+  nullz(status);
+}
+
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space,
+                           int code) {
+  if (!status) return;
+  status->ok_ = false;
+  status->error_space_ = space;
+  status->code_ = code;
+  space->set_message(status, code);
+}
+
+void upb_status_copy(upb_status *to, const upb_status *from) {
+  if (!to) return;
+  *to = *from;
+}
+/* This file was generated by upbc (the upb compiler).
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+
+static const upb_msgdef msgs[20];
+static const upb_fielddef fields[81];
+static const upb_enumdef enums[4];
+static const upb_tabent strentries[236];
+static const upb_tabent intentries[14];
+static const upb_tabval arrays[232];
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[212];
+#endif
+
+static const upb_msgdef msgs[20] = {
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[0]),&reftables[0], &reftables[1]),
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]),&reftables[2], &reftables[3]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[20]),&reftables[4], &reftables[5]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[15], 8, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[24]),&reftables[6], &reftables[7]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[23], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]),&reftables[8], &reftables[9]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[27], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[32]),&reftables[10], &reftables[11]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &strentries[36]),&reftables[12], &reftables[13]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 14, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[40], 32, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[52]),&reftables[14], &reftables[15]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 39, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[72], 12, 11), UPB_STRTABLE_INIT(11, 15, UPB_CTYPE_PTR, 4, &strentries[68]),&reftables[16], &reftables[17]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[84], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[84]),&reftables[18], &reftables[19]),
+  UPB_MSGDEF_INIT("google.protobuf.FileOptions", 21, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[86], 64, 9), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[88]),&reftables[20], &reftables[21]),
+  UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[150], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[104]),&reftables[22], &reftables[23]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[166], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[108]),&reftables[24], &reftables[25]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[10], &arrays[171], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[116]),&reftables[26], &reftables[27]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[175], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[120]),&reftables[28], &reftables[29]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[12], &arrays[179], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[124]),&reftables[30], &reftables[31]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[183], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[128]),&reftables[32], &reftables[33]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 14, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[185], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[132]),&reftables[34], &reftables[35]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[190], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[140]),&reftables[36], &reftables[37]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[199], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[156]),&reftables[38], &reftables[39]),
+};
+
+static const upb_fielddef fields[81] = {
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[3], NULL, 6, 1, {0},&reftables[42], &reftables[43]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[10], NULL, 17, 6, {0},&reftables[44], &reftables[45]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[7], (const upb_def*)(&enums[2]), 6, 1, {0},&reftables[46], &reftables[47]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[6], NULL, 16, 7, {0},&reftables[48], &reftables[49]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[8], NULL, 30, 8, {0},&reftables[50], &reftables[51]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[7], NULL, 8, 3, {0},&reftables[52], &reftables[53]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[18], NULL, 11, 4, {0},&reftables[54], &reftables[55]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[56], &reftables[57]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[2]), 16, 2, {0},&reftables[58], &reftables[59]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[8], (const upb_def*)(&msgs[2]), 13, 1, {0},&reftables[60], &reftables[61]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "experimental_map_key", 9, &msgs[7], NULL, 10, 5, {0},&reftables[62], &reftables[63]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[6], NULL, 7, 2, {0},&reftables[64], &reftables[65]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[8], (const upb_def*)(&msgs[6]), 19, 3, {0},&reftables[66], &reftables[67]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[6]), 22, 4, {0},&reftables[68], &reftables[69]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], (const upb_def*)(&msgs[1]), 19, 3, {0},&reftables[70], &reftables[71]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], (const upb_def*)(&msgs[6]), 10, 0, {0},&reftables[72], &reftables[73]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[9], (const upb_def*)(&msgs[8]), 5, 0, {0},&reftables[74], &reftables[75]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[10], NULL, 14, 5, {0},&reftables[76], &reftables[77]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[18], NULL, 6, 1, {0},&reftables[78], &reftables[79]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[12], NULL, 7, 2, {0},&reftables[80], &reftables[81]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[19], NULL, 5, 1, {0},&reftables[82], &reftables[83]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[10], NULL, 20, 9, {0},&reftables[84], &reftables[85]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[10], NULL, 18, 7, {0},&reftables[86], &reftables[87]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[10], NULL, 13, 4, {0},&reftables[88], &reftables[89]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[10], NULL, 9, 2, {0},&reftables[90], &reftables[91]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[10], NULL, 6, 1, {0},&reftables[92], &reftables[93]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[6], (const upb_def*)(&enums[0]), 11, 4, {0},&reftables[94], &reftables[95]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[7], NULL, 9, 4, {0},&reftables[96], &reftables[97]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[17], NULL, 8, 2, {0},&reftables[98], &reftables[99]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[16], (const upb_def*)(&msgs[17]), 5, 0, {0},&reftables[100], &reftables[101]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[11], NULL, 6, 1, {0},&reftables[102], &reftables[103]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[8], (const upb_def*)(&msgs[0]), 10, 0, {0},&reftables[104], &reftables[105]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[14], (const upb_def*)(&msgs[12]), 6, 0, {0},&reftables[106], &reftables[107]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[8], NULL, 22, 6, {0},&reftables[108], &reftables[109]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[14], NULL, 8, 2, {0},&reftables[110], &reftables[111]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[18], (const upb_def*)(&msgs[19]), 5, 0, {0},&reftables[112], &reftables[113]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[4], NULL, 4, 1, {0},&reftables[114], &reftables[115]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 24, 6, {0},&reftables[116], &reftables[117]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[12], NULL, 4, 1, {0},&reftables[118], &reftables[119]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[2], NULL, 8, 2, {0},&reftables[120], &reftables[121]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[6], NULL, 4, 1, {0},&reftables[122], &reftables[123]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[19], NULL, 2, 0, {0},&reftables[124], &reftables[125]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[18], NULL, 10, 3, {0},&reftables[126], &reftables[127]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 13, 1, {0},&reftables[128], &reftables[129]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[11], NULL, 7, 2, {0},&reftables[130], &reftables[131]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[6], NULL, 10, 3, {0},&reftables[132], &reftables[133]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[4], NULL, 7, 2, {0},&reftables[134], &reftables[135]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[10], (const upb_def*)(&enums[3]), 12, 3, {0},&reftables[136], &reftables[137]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[11]), 23, 5, {0},&reftables[138], &reftables[139]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[2], (const upb_def*)(&msgs[3]), 7, 1, {0},&reftables[140], &reftables[141]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[6], (const upb_def*)(&msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[4], (const upb_def*)(&msgs[5]), 3, 0, {0},&reftables[144], &reftables[145]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[8], (const upb_def*)(&msgs[10]), 20, 4, {0},&reftables[146], &reftables[147]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[14], (const upb_def*)(&msgs[15]), 7, 1, {0},&reftables[148], &reftables[149]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[12], (const upb_def*)(&msgs[13]), 3, 0, {0},&reftables[150], &reftables[151]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[12], NULL, 10, 3, {0},&reftables[152], &reftables[153]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[8], NULL, 25, 7, {0},&reftables[154], &reftables[155]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[7], NULL, 7, 2, {0},&reftables[156], &reftables[157]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[17], NULL, 4, 0, {0},&reftables[158], &reftables[159]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[18], NULL, 9, 2, {0},&reftables[160], &reftables[161]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[8], NULL, 35, 9, {0},&reftables[162], &reftables[163]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[10], NULL, 19, 8, {0},&reftables[164], &reftables[165]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[8], (const upb_def*)(&msgs[14]), 16, 2, {0},&reftables[166], &reftables[167]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[8], (const upb_def*)(&msgs[16]), 21, 5, {0},&reftables[168], &reftables[169]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[17], NULL, 7, 1, {0},&reftables[170], &reftables[171]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[172], &reftables[173]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[18], NULL, 12, 5, {0},&reftables[174], &reftables[175]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[17], NULL, 11, 3, {0},&reftables[176], &reftables[177]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[6], (const upb_def*)(&enums[1]), 12, 5, {0},&reftables[178], &reftables[179]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[6], NULL, 13, 6, {0},&reftables[180], &reftables[181]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[5], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[15], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[184], &reftables[185]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[3], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[186], &reftables[187]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[13], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[188], &reftables[189]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[10], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[190], &reftables[191]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[192], &reftables[193]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[7], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[194], &reftables[195]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[2], (const upb_def*)(&msgs[4]), 6, 0, {0},&reftables[196], &reftables[197]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[7], NULL, 13, 6, {0},&reftables[198], &reftables[199]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[8], NULL, 38, 10, {0},&reftables[200], &reftables[201]),
+};
+
+static const upb_enumdef enums[4] = {
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[160]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[202], 4, 3), 0, &reftables[202], &reftables[203]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[164]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[206], 19, 18), 0, &reftables[204], &reftables[205]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[196]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[225], 3, 3), 0, &reftables[206], &reftables[207]),
+  UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[200]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[228], 4, 3), 0, &reftables[208], &reftables[209]),
+};
+
+static const upb_tabent strentries[236] = {
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "field"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "extension_range"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[49]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[9]), &strentries[14]},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL},
+  {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[78]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[50]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[40]), &strentries[22]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[52]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[37]), &strentries[30]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[27]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[41]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[49]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[12]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[48]},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "experimental_map_key"), UPB_TABVALUE_PTR_INIT(&fields[11]), &strentries[67]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[79]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "packed"), UPB_TABVALUE_PTR_INIT(&fields[58]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "lazy"), UPB_TABVALUE_PTR_INIT(&fields[28]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[3]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[80]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[63]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[5]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[32]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[57]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[82]},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[61]), &strentries[81]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "cc_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "java_multiple_files"), UPB_TABVALUE_PTR_INIT(&fields[24]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\025", "\000", "\000", "\000", "java_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[23]), &strentries[102]},
+  {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "java_generate_equals_and_hash"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "go_package"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "java_package"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[62]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[25]), NULL},
+  {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[31]), &strentries[106]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[54]), &strentries[122]},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[33]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[35]), &strentries[121]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[72]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[30]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "span"), UPB_TABVALUE_PTR_INIT(&fields[65]), &strentries[139]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "trailing_comments"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "leading_comments"), UPB_TABVALUE_PTR_INIT(&fields[29]), &strentries[137]},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "path"), UPB_TABVALUE_PTR_INIT(&fields[59]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "negative_int_value"), UPB_TABVALUE_PTR_INIT(&fields[43]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "aggregate_value"), UPB_TABVALUE_PTR_INIT(&fields[0]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "positive_int_value"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "identifier_value"), UPB_TABVALUE_PTR_INIT(&fields[19]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "string_value"), UPB_TABVALUE_PTR_INIT(&fields[67]), &strentries[154]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "is_extension"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "name_part"), UPB_TABVALUE_PTR_INIT(&fields[42]), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REQUIRED"), UPB_TABVALUE_INT_INIT(2), &strentries[162]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REPEATED"), UPB_TABVALUE_INT_INIT(3), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_OPTIONAL"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED64"), UPB_TABVALUE_INT_INIT(6), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_STRING"), UPB_TABVALUE_INT_INIT(9), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_FLOAT"), UPB_TABVALUE_INT_INIT(2), &strentries[193]},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_DOUBLE"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT32"), UPB_TABVALUE_INT_INIT(5), NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED32"), UPB_TABVALUE_INT_INIT(15), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED32"), UPB_TABVALUE_INT_INIT(7), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_MESSAGE"), UPB_TABVALUE_INT_INIT(11), &strentries[194]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT64"), UPB_TABVALUE_INT_INIT(3), &strentries[191]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_ENUM"), UPB_TABVALUE_INT_INIT(14), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT32"), UPB_TABVALUE_INT_INIT(13), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT64"), UPB_TABVALUE_INT_INIT(4), &strentries[190]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED64"), UPB_TABVALUE_INT_INIT(16), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_BYTES"), UPB_TABVALUE_INT_INIT(12), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT64"), UPB_TABVALUE_INT_INIT(18), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_BOOL"), UPB_TABVALUE_INT_INIT(8), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_GROUP"), UPB_TABVALUE_INT_INIT(10), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT32"), UPB_TABVALUE_INT_INIT(17), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "CORD"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "STRING"), UPB_TABVALUE_INT_INIT(0), &strentries[197]},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "STRING_PIECE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "CODE_SIZE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[203]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\047", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo.Location"), UPB_TABVALUE_PTR_INIT(&msgs[17]), NULL},
+  {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.UninterpretedOption"), UPB_TABVALUE_PTR_INIT(&msgs[18]), NULL},
+  {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.FileDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[8]), NULL},
+  {UPB_TABKEY_STR("\045", "\000", "\000", "\000", "google.protobuf.MethodDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[12]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\040", "\000", "\000", "\000", "google.protobuf.EnumValueOptions"), UPB_TABVALUE_PTR_INIT(&msgs[5]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "google.protobuf.DescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[0]), &strentries[228]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo"), UPB_TABVALUE_PTR_INIT(&msgs[16]), NULL},
+  {UPB_TABKEY_STR("\051", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Type"), UPB_TABVALUE_PTR_INIT(&enums[1]), NULL},
+  {UPB_TABKEY_STR("\056", "\000", "\000", "\000", "google.protobuf.DescriptorProto.ExtensionRange"), UPB_TABVALUE_PTR_INIT(&msgs[1]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.EnumValueDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[4]), NULL},
+  {UPB_TABKEY_STR("\034", "\000", "\000", "\000", "google.protobuf.FieldOptions"), UPB_TABVALUE_PTR_INIT(&msgs[7]), NULL},
+  {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.FileOptions"), UPB_TABVALUE_PTR_INIT(&msgs[10]), NULL},
+  {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.EnumDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[2]), &strentries[233]},
+  {UPB_TABKEY_STR("\052", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Label"), UPB_TABVALUE_PTR_INIT(&enums[0]), NULL},
+  {UPB_TABKEY_STR("\046", "\000", "\000", "\000", "google.protobuf.ServiceDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[14]), NULL},
+  {UPB_TABKEY_STR("\042", "\000", "\000", "\000", "google.protobuf.FieldOptions.CType"), UPB_TABVALUE_PTR_INIT(&enums[2]), &strentries[229]},
+  {UPB_TABKEY_STR("\041", "\000", "\000", "\000", "google.protobuf.FileDescriptorSet"), UPB_TABVALUE_PTR_INIT(&msgs[9]), &strentries[235]},
+  {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.EnumOptions"), UPB_TABVALUE_PTR_INIT(&msgs[3]), NULL},
+  {UPB_TABKEY_STR("\044", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[6]), NULL},
+  {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.FileOptions.OptimizeMode"), UPB_TABVALUE_PTR_INIT(&enums[3]), &strentries[221]},
+  {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.ServiceOptions"), UPB_TABVALUE_PTR_INIT(&msgs[15]), NULL},
+  {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.MessageOptions"), UPB_TABVALUE_PTR_INIT(&msgs[11]), NULL},
+  {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "google.protobuf.MethodOptions"), UPB_TABVALUE_PTR_INIT(&msgs[13]), &strentries[226]},
+  {UPB_TABKEY_STR("\054", "\000", "\000", "\000", "google.protobuf.UninterpretedOption.NamePart"), UPB_TABVALUE_PTR_INIT(&msgs[19]), NULL},
+};
+
+static const upb_tabent intentries[14] = {
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[72]), NULL},
+};
+
+static const upb_tabval arrays[232] = {
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[38]),
+  UPB_TABVALUE_PTR_INIT(&fields[16]),
+  UPB_TABVALUE_PTR_INIT(&fields[44]),
+  UPB_TABVALUE_PTR_INIT(&fields[9]),
+  UPB_TABVALUE_PTR_INIT(&fields[15]),
+  UPB_TABVALUE_PTR_INIT(&fields[14]),
+  UPB_TABVALUE_PTR_INIT(&fields[49]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[66]),
+  UPB_TABVALUE_PTR_INIT(&fields[8]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[40]),
+  UPB_TABVALUE_PTR_INIT(&fields[78]),
+  UPB_TABVALUE_PTR_INIT(&fields[50]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[1]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[37]),
+  UPB_TABVALUE_PTR_INIT(&fields[47]),
+  UPB_TABVALUE_PTR_INIT(&fields[52]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[41]),
+  UPB_TABVALUE_PTR_INIT(&fields[12]),
+  UPB_TABVALUE_PTR_INIT(&fields[46]),
+  UPB_TABVALUE_PTR_INIT(&fields[27]),
+  UPB_TABVALUE_PTR_INIT(&fields[69]),
+  UPB_TABVALUE_PTR_INIT(&fields[70]),
+  UPB_TABVALUE_PTR_INIT(&fields[4]),
+  UPB_TABVALUE_PTR_INIT(&fields[51]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[3]),
+  UPB_TABVALUE_PTR_INIT(&fields[58]),
+  UPB_TABVALUE_PTR_INIT(&fields[6]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[28]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[11]),
+  UPB_TABVALUE_PTR_INIT(&fields[79]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[34]),
+  UPB_TABVALUE_PTR_INIT(&fields[57]),
+  UPB_TABVALUE_PTR_INIT(&fields[5]),
+  UPB_TABVALUE_PTR_INIT(&fields[32]),
+  UPB_TABVALUE_PTR_INIT(&fields[10]),
+  UPB_TABVALUE_PTR_INIT(&fields[63]),
+  UPB_TABVALUE_PTR_INIT(&fields[13]),
+  UPB_TABVALUE_PTR_INIT(&fields[53]),
+  UPB_TABVALUE_PTR_INIT(&fields[64]),
+  UPB_TABVALUE_PTR_INIT(&fields[61]),
+  UPB_TABVALUE_PTR_INIT(&fields[80]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[17]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[26]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[25]),
+  UPB_TABVALUE_PTR_INIT(&fields[48]),
+  UPB_TABVALUE_PTR_INIT(&fields[24]),
+  UPB_TABVALUE_PTR_INIT(&fields[18]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[2]),
+  UPB_TABVALUE_PTR_INIT(&fields[23]),
+  UPB_TABVALUE_PTR_INIT(&fields[62]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[22]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[31]),
+  UPB_TABVALUE_PTR_INIT(&fields[45]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[39]),
+  UPB_TABVALUE_PTR_INIT(&fields[20]),
+  UPB_TABVALUE_PTR_INIT(&fields[56]),
+  UPB_TABVALUE_PTR_INIT(&fields[55]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[35]),
+  UPB_TABVALUE_PTR_INIT(&fields[33]),
+  UPB_TABVALUE_PTR_INIT(&fields[54]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[30]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[59]),
+  UPB_TABVALUE_PTR_INIT(&fields[65]),
+  UPB_TABVALUE_PTR_INIT(&fields[29]),
+  UPB_TABVALUE_PTR_INIT(&fields[68]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[36]),
+  UPB_TABVALUE_PTR_INIT(&fields[19]),
+  UPB_TABVALUE_PTR_INIT(&fields[60]),
+  UPB_TABVALUE_PTR_INIT(&fields[43]),
+  UPB_TABVALUE_PTR_INIT(&fields[7]),
+  UPB_TABVALUE_PTR_INIT(&fields[67]),
+  UPB_TABVALUE_PTR_INIT(&fields[0]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[42]),
+  UPB_TABVALUE_PTR_INIT(&fields[21]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("LABEL_OPTIONAL"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REQUIRED"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REPEATED"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("TYPE_DOUBLE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FLOAT"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BOOL"),
+  UPB_TABVALUE_PTR_INIT("TYPE_STRING"),
+  UPB_TABVALUE_PTR_INIT("TYPE_GROUP"),
+  UPB_TABVALUE_PTR_INIT("TYPE_MESSAGE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BYTES"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_ENUM"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT64"),
+  UPB_TABVALUE_PTR_INIT("STRING"),
+  UPB_TABVALUE_PTR_INIT("CORD"),
+  UPB_TABVALUE_PTR_INIT("STRING_PIECE"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("SPEED"),
+  UPB_TABVALUE_PTR_INIT("CODE_SIZE"),
+  UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"),
+};
+
+static const upb_symtab symtab = UPB_SYMTAB_INIT(UPB_STRTABLE_INIT(24, 31, UPB_CTYPE_PTR, 5, &strentries[204]), &reftables[210], &reftables[211]);
+
+const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner) {
+  upb_symtab_ref(&symtab, owner);
+  return &symtab;
+}
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[212] = {
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+};
+#endif
+
+/*
+** XXX: The routines in this file that consume a string do not currently
+** support having the string span buffers.  In the future, as upb_sink and
+** its buffering/sharing functionality evolve there should be an easy and
+** idiomatic way of correctly handling this case.  For now, we accept this
+** limitation since we currently only parse descriptors from single strings.
+*/
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* upb_deflist is an internal-only dynamic array for storing a growing list of
+ * upb_defs. */
+typedef struct {
+  upb_def **defs;
+  size_t len;
+  size_t size;
+  bool owned;
+} upb_deflist;
+
+/* We keep a stack of all the messages scopes we are currently in, as well as
+ * the top-level file scope.  This is necessary to correctly qualify the
+ * definitions that are contained inside.  "name" tracks the name of the
+ * message or package (a bare name -- not qualified by any enclosing scopes). */
+typedef struct {
+  char *name;
+  /* Index of the first def that is under this scope.  For msgdefs, the
+   * msgdef itself is at start-1. */
+  int start;
+} upb_descreader_frame;
+
+/* The maximum number of nested declarations that are allowed, ie.
+ * message Foo {
+ *   message Bar {
+ *     message Baz {
+ *     }
+ *   }
+ * }
+ *
+ * This is a resource limit that affects how big our runtime stack can grow.
+ * TODO: make this a runtime-settable property of the Reader instance. */
+#define UPB_MAX_MESSAGE_NESTING 64
+
+struct upb_descreader {
+  upb_sink sink;
+  upb_deflist defs;
+  upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
+  int stack_len;
+
+  uint32_t number;
+  char *name;
+  bool saw_number;
+  bool saw_name;
+
+  char *default_string;
+
+  upb_fielddef *f;
+};
+
+static char *upb_strndup(const char *buf, size_t n) {
+  char *ret = malloc(n + 1);
+  if (!ret) return NULL;
+  memcpy(ret, buf, n);
+  ret[n] = '\0';
+  return ret;
+}
+
+/* Returns a newly allocated string that joins input strings together, for
+ * example:
+ *   join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
+ *   join("", "Baz") -> "Baz"
+ * Caller owns a ref on the returned string. */
+static char *upb_join(const char *base, const char *name) {
+  if (!base || strlen(base) == 0) {
+    return upb_strdup(name);
+  } else {
+    char *ret = malloc(strlen(base) + strlen(name) + 2);
+    ret[0] = '\0';
+    strcat(ret, base);
+    strcat(ret, ".");
+    strcat(ret, name);
+    return ret;
+  }
+}
+
+
+/* upb_deflist ****************************************************************/
+
+void upb_deflist_init(upb_deflist *l) {
+  l->size = 0;
+  l->defs = NULL;
+  l->len = 0;
+  l->owned = true;
+}
+
+void upb_deflist_uninit(upb_deflist *l) {
+  size_t i;
+  if (l->owned)
+    for(i = 0; i < l->len; i++)
+      upb_def_unref(l->defs[i], l);
+  free(l->defs);
+}
+
+bool upb_deflist_push(upb_deflist *l, upb_def *d) {
+  if(++l->len >= l->size) {
+    size_t new_size = UPB_MAX(l->size, 4);
+    new_size *= 2;
+    l->defs = realloc(l->defs, new_size * sizeof(void *));
+    if (!l->defs) return false;
+    l->size = new_size;
+  }
+  l->defs[l->len - 1] = d;
+  return true;
+}
+
+void upb_deflist_donaterefs(upb_deflist *l, void *owner) {
+  size_t i;
+  assert(l->owned);
+  for (i = 0; i < l->len; i++)
+    upb_def_donateref(l->defs[i], l, owner);
+  l->owned = false;
+}
+
+static upb_def *upb_deflist_last(upb_deflist *l) {
+  return l->defs[l->len-1];
+}
+
+/* Qualify the defname for all defs starting with offset "start" with "str". */
+static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) {
+  uint32_t i;
+  for (i = start; i < l->len; i++) {
+    upb_def *def = l->defs[i];
+    char *name = upb_join(str, upb_def_fullname(def));
+    upb_def_setfullname(def, name, NULL);
+    free(name);
+  }
+}
+
+
+/* upb_descreader  ************************************************************/
+
+static upb_msgdef *upb_descreader_top(upb_descreader *r) {
+  int index;
+  assert(r->stack_len > 1);
+  index = r->stack[r->stack_len-1].start - 1;
+  assert(index >= 0);
+  return upb_downcast_msgdef_mutable(r->defs.defs[index]);
+}
+
+static upb_def *upb_descreader_last(upb_descreader *r) {
+  return upb_deflist_last(&r->defs);
+}
+
+/* Start/end handlers for FileDescriptorProto and DescriptorProto (the two
+ * entities that have names and can contain sub-definitions. */
+void upb_descreader_startcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[r->stack_len++];
+  f->start = r->defs.len;
+  f->name = NULL;
+}
+
+void upb_descreader_endcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[--r->stack_len];
+  upb_deflist_qualify(&r->defs, f->name, f->start);
+  free(f->name);
+  f->name = NULL;
+}
+
+void upb_descreader_setscopename(upb_descreader *r, char *str) {
+  upb_descreader_frame *f = &r->stack[r->stack_len-1];
+  free(f->name);
+  f->name = str;
+}
+
+/* Handlers for google.protobuf.FileDescriptorProto. */
+static bool file_startmsg(void *r, const void *hd) {
+  UPB_UNUSED(hd);
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool file_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  upb_descreader_endcontainer(r);
+  return true;
+}
+
+static size_t file_onpackage(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_descreader_setscopename(r, upb_strndup(buf, n));
+  return n;
+}
+
+/* Handlers for google.protobuf.EnumValueDescriptorProto. */
+static bool enumval_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->saw_number = false;
+  r->saw_name = false;
+  return true;
+}
+
+static size_t enumval_onname(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  free(r->name);
+  r->name = upb_strndup(buf, n);
+  r->saw_name = true;
+  return n;
+}
+
+static bool enumval_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->number = val;
+  r->saw_number = true;
+  return true;
+}
+
+static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  if(!r->saw_number || !r->saw_name) {
+    upb_status_seterrmsg(status, "Enum value missing name or number.");
+    return false;
+  }
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  upb_enumdef_addval(e, r->name, r->number, status);
+  free(r->name);
+  r->name = NULL;
+  return true;
+}
+
+
+/* Handlers for google.protobuf.EnumDescriptorProto. */
+static bool enum_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  upb_deflist_push(&r->defs,
+                   upb_enumdef_upcast_mutable(upb_enumdef_new(&r->defs)));
+  return true;
+}
+
+static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
+    upb_status_seterrmsg(status, "Enum had no name.");
+    return false;
+  }
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrmsg(status, "Enum had no values.");
+    return false;
+  }
+  return true;
+}
+
+static size_t enum_onname(void *closure, const void *hd, const char *buf,
+                          size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *fullname = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_def_setfullname(upb_descreader_last(r), fullname, NULL);
+  free(fullname);
+  return n;
+}
+
+/* Handlers for google.protobuf.FieldDescriptorProto */
+static bool field_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->f = upb_fielddef_new(&r->defs);
+  free(r->default_string);
+  r->default_string = NULL;
+
+  /* fielddefs default to packed, but descriptors default to non-packed. */
+  upb_fielddef_setpacked(r->f, false);
+  return true;
+}
+
+/* Converts the default value in string "str" into "d".  Passes a ref on str.
+ * Returns true on success. */
+static bool parse_default(char *str, upb_fielddef *f) {
+  bool success = true;
+  char *end;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32: {
+      long val = strtol(str, &end, 0);
+      if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint32(f, val);
+      break;
+    }
+    case UPB_TYPE_INT64: {
+      /* XXX: Need to write our own strtoll, since it's not available in c89. */
+      long long val = strtol(str, &end, 0);
+      if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint64(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(str, &end, 0);
+      if (val > UINT32_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint32(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT64: {
+      /* XXX: Need to write our own strtoull, since it's not available in c89. */
+      unsigned long long val = strtoul(str, &end, 0);
+      if (val > UINT64_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint64(f, val);
+      break;
+    }
+    case UPB_TYPE_DOUBLE: {
+      double val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultdouble(f, val);
+      break;
+    }
+    case UPB_TYPE_FLOAT: {
+      /* XXX: Need to write our own strtof, since it's not available in c89. */
+      float val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultfloat(f, val);
+      break;
+    }
+    case UPB_TYPE_BOOL: {
+      if (strcmp(str, "false") == 0)
+        upb_fielddef_setdefaultbool(f, false);
+      else if (strcmp(str, "true") == 0)
+        upb_fielddef_setdefaultbool(f, true);
+      else
+        success = false;
+      break;
+    }
+    default: abort();
+  }
+  return success;
+}
+
+static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_fielddef *f = r->f;
+  UPB_UNUSED(hd);
+
+  /* TODO: verify that all required fields were present. */
+  assert(upb_fielddef_number(f) != 0);
+  assert(upb_fielddef_name(f) != NULL);
+  assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f));
+
+  if (r->default_string) {
+    if (upb_fielddef_issubmsg(f)) {
+      upb_status_seterrmsg(status, "Submessages cannot have defaults.");
+      return false;
+    }
+    if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+      upb_fielddef_setdefaultcstr(f, r->default_string, NULL);
+    } else {
+      if (r->default_string && !parse_default(r->default_string, f)) {
+        /* We don't worry too much about giving a great error message since the
+         * compiler should have ensured this was correct. */
+        upb_status_seterrmsg(status, "Error converting default value.");
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+static bool field_onlazy(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlazy(r->f, val);
+  return true;
+}
+
+static bool field_onpacked(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setpacked(r->f, val);
+  return true;
+}
+
+static bool field_ontype(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setdescriptortype(r->f, val);
+  return true;
+}
+
+static bool field_onlabel(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlabel(r->f, val);
+  return true;
+}
+
+static bool field_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  bool ok = upb_fielddef_setnumber(r->f, val, NULL);
+  UPB_UNUSED(hd);
+
+  UPB_ASSERT_VAR(ok, ok);
+  return true;
+}
+
+static size_t field_onname(void *closure, const void *hd, const char *buf,
+                           size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setname(r->f, name, NULL);
+  free(name);
+  return n;
+}
+
+static size_t field_ontypename(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setsubdefname(r->f, name, NULL);
+  free(name);
+  return n;
+}
+
+static size_t field_onextendee(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setcontainingtypename(r->f, name, NULL);
+  free(name);
+  return n;
+}
+
+static size_t field_ondefaultval(void *closure, const void *hd, const char *buf,
+                                 size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* Have to convert from string to the correct type, but we might not know the
+   * type yet, so we save it as a string until the end of the field.
+   * XXX: see comment at the top of the file. */
+  free(r->default_string);
+  r->default_string = upb_strndup(buf, n);
+  return n;
+}
+
+/* Handlers for google.protobuf.DescriptorProto (representing a message). */
+static bool msg_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_deflist_push(&r->defs,
+                   upb_msgdef_upcast_mutable(upb_msgdef_new(&r->defs)));
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool msg_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) {
+    upb_status_seterrmsg(status, "Encountered message with no name.");
+    return false;
+  }
+  upb_descreader_endcontainer(r);
+  return true;
+}
+
+static size_t msg_onname(void *closure, const void *hd, const char *buf,
+                         size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  /* XXX: see comment at the top of the file. */
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL);
+  upb_descreader_setscopename(r, name);  /* Passes ownership of name. */
+  return n;
+}
+
+static bool msg_onendfield(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  upb_msgdef_addfield(m, r->f, &r->defs, NULL);
+  r->f = NULL;
+  return true;
+}
+
+static bool pushextension(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  assert(upb_fielddef_containingtypename(r->f));
+  upb_fielddef_setisextension(r->f, true);
+  upb_deflist_push(&r->defs, upb_fielddef_upcast_mutable(r->f));
+  r->f = NULL;
+  return true;
+}
+
+#define D(name) upbdefs_google_protobuf_ ## name(s)
+
+static void reghandlers(const void *closure, upb_handlers *h) {
+  const upb_symtab *s = closure;
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+
+  if (m == D(DescriptorProto)) {
+    upb_handlers_setstartmsg(h, &msg_startmsg, NULL);
+    upb_handlers_setendmsg(h, &msg_endmsg, NULL);
+    upb_handlers_setstring(h, D(DescriptorProto_name), &msg_onname, NULL);
+    upb_handlers_setendsubmsg(h, D(DescriptorProto_field), &msg_onendfield,
+                              NULL);
+    upb_handlers_setendsubmsg(h, D(DescriptorProto_extension), &pushextension,
+                              NULL);
+  } else if (m == D(FileDescriptorProto)) {
+    upb_handlers_setstartmsg(h, &file_startmsg, NULL);
+    upb_handlers_setendmsg(h, &file_endmsg, NULL);
+    upb_handlers_setstring(h, D(FileDescriptorProto_package), &file_onpackage,
+                           NULL);
+    upb_handlers_setendsubmsg(h, D(FileDescriptorProto_extension), &pushextension,
+                              NULL);
+  } else if (m == D(EnumValueDescriptorProto)) {
+    upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
+    upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
+    upb_handlers_setstring(h, D(EnumValueDescriptorProto_name), &enumval_onname, NULL);
+    upb_handlers_setint32(h, D(EnumValueDescriptorProto_number), &enumval_onnumber,
+                          NULL);
+  } else if (m == D(EnumDescriptorProto)) {
+    upb_handlers_setstartmsg(h, &enum_startmsg, NULL);
+    upb_handlers_setendmsg(h, &enum_endmsg, NULL);
+    upb_handlers_setstring(h, D(EnumDescriptorProto_name), &enum_onname, NULL);
+  } else if (m == D(FieldDescriptorProto)) {
+    upb_handlers_setstartmsg(h, &field_startmsg, NULL);
+    upb_handlers_setendmsg(h, &field_endmsg, NULL);
+    upb_handlers_setint32(h, D(FieldDescriptorProto_type), &field_ontype,
+                          NULL);
+    upb_handlers_setint32(h, D(FieldDescriptorProto_label), &field_onlabel,
+                          NULL);
+    upb_handlers_setint32(h, D(FieldDescriptorProto_number), &field_onnumber,
+                          NULL);
+    upb_handlers_setstring(h, D(FieldDescriptorProto_name), &field_onname,
+                           NULL);
+    upb_handlers_setstring(h, D(FieldDescriptorProto_type_name),
+                           &field_ontypename, NULL);
+    upb_handlers_setstring(h, D(FieldDescriptorProto_extendee),
+                           &field_onextendee, NULL);
+    upb_handlers_setstring(h, D(FieldDescriptorProto_default_value),
+                           &field_ondefaultval, NULL);
+  } else if (m == D(FieldOptions)) {
+    upb_handlers_setbool(h, D(FieldOptions_lazy), &field_onlazy, NULL);
+    upb_handlers_setbool(h, D(FieldOptions_packed), &field_onpacked, NULL);
+  }
+}
+
+#undef D
+
+void descreader_cleanup(void *_r) {
+  upb_descreader *r = _r;
+  free(r->name);
+  upb_deflist_uninit(&r->defs);
+  free(r->default_string);
+  while (r->stack_len > 0) {
+    upb_descreader_frame *f = &r->stack[--r->stack_len];
+    free(f->name);
+  }
+}
+
+
+/* Public API  ****************************************************************/
+
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) {
+  upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader));
+  if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) {
+    return NULL;
+  }
+
+  upb_deflist_init(&r->defs);
+  upb_sink_reset(upb_descreader_input(r), h, r);
+  r->stack_len = 0;
+  r->name = NULL;
+  r->default_string = NULL;
+
+  return r;
+}
+
+upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) {
+  *n = r->defs.len;
+  upb_deflist_donaterefs(&r->defs, owner);
+  return r->defs.defs;
+}
+
+upb_sink *upb_descreader_input(upb_descreader *r) {
+  return &r->sink;
+}
+
+const upb_handlers *upb_descreader_newhandlers(const void *owner) {
+  const upb_symtab *s = upbdefs_google_protobuf_descriptor(&s);
+  const upb_handlers *h = upb_handlers_newfrozen(
+      upbdefs_google_protobuf_FileDescriptorSet(s), owner, reghandlers, s);
+  upb_symtab_unref(s, &s);
+  return h;
+}
+/*
+** protobuf decoder bytecode compiler
+**
+** Code to compile a upb::Handlers into bytecode for decoding a protobuf
+** according to that specific schema and destination handlers.
+**
+** Compiling to bytecode is always the first step.  If we are using the
+** interpreted decoder we leave it as bytecode and interpret that.  If we are
+** using a JIT decoder we use a code generator to turn the bytecode into native
+** code, LLVM IR, etc.
+**
+** Bytecode definition is in decoder.int.h.
+*/
+
+#include <stdarg.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define MAXLABEL 5
+#define EMPTYLABEL -1
+
+/* mgroup *********************************************************************/
+
+static void freegroup(upb_refcounted *r) {
+  mgroup *g = (mgroup*)r;
+  upb_inttable_uninit(&g->methods);
+#ifdef UPB_USE_JIT_X64
+  upb_pbdecoder_freejit(g);
+#endif
+  free(g->bytecode);
+  free(g);
+}
+
+static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const mgroup *g = (const mgroup*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    visit(r, upb_pbdecodermethod_upcast(method), closure);
+  }
+}
+
+mgroup *newgroup(const void *owner) {
+  mgroup *g = malloc(sizeof(*g));
+  static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
+  upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner);
+  upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
+  g->bytecode = NULL;
+  g->bytecode_end = NULL;
+  return g;
+}
+
+
+/* upb_pbdecodermethod ********************************************************/
+
+static void freemethod(upb_refcounted *r) {
+  upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
+
+  if (method->dest_handlers_) {
+    upb_handlers_unref(method->dest_handlers_, method);
+  }
+
+  upb_inttable_uninit(&method->dispatch);
+  free(method);
+}
+
+static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
+                        void *closure) {
+  const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
+  visit(r, m->group, closure);
+}
+
+static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers,
+                                      mgroup *group) {
+  static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
+  upb_pbdecodermethod *ret = malloc(sizeof(*ret));
+  upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret);
+  upb_byteshandler_init(&ret->input_handler_);
+
+  /* The method references the group and vice-versa, in a circular reference. */
+  upb_ref2(ret, group);
+  upb_ref2(group, ret);
+  upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret));
+  upb_pbdecodermethod_unref(ret, &ret);
+
+  ret->group = mgroup_upcast_mutable(group);
+  ret->dest_handlers_ = dest_handlers;
+  ret->is_native_ = false;  /* If we JIT, it will update this later. */
+  upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
+
+  if (ret->dest_handlers_) {
+    upb_handlers_ref(ret->dest_handlers_, ret);
+  }
+  return ret;
+}
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m) {
+  return m->dest_handlers_;
+}
+
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m) {
+  return &m->input_handler_;
+}
+
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
+  return m->is_native_;
+}
+
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner) {
+  const upb_pbdecodermethod *ret;
+  upb_pbcodecache cache;
+
+  upb_pbcodecache_init(&cache);
+  ret = upb_pbcodecache_getdecodermethod(&cache, opts);
+  upb_pbdecodermethod_ref(ret, owner);
+  upb_pbcodecache_uninit(&cache);
+  return ret;
+}
+
+
+/* bytecode compiler **********************************************************/
+
+/* Data used only at compilation time. */
+typedef struct {
+  mgroup *group;
+
+  uint32_t *pc;
+  int fwd_labels[MAXLABEL];
+  int back_labels[MAXLABEL];
+
+  /* For fields marked "lazy", parse them lazily or eagerly? */
+  bool lazy;
+} compiler;
+
+static compiler *newcompiler(mgroup *group, bool lazy) {
+  compiler *ret = malloc(sizeof(*ret));
+  int i;
+
+  ret->group = group;
+  ret->lazy = lazy;
+  for (i = 0; i < MAXLABEL; i++) {
+    ret->fwd_labels[i] = EMPTYLABEL;
+    ret->back_labels[i] = EMPTYLABEL;
+  }
+  return ret;
+}
+
+static void freecompiler(compiler *c) {
+  free(c);
+}
+
+const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
+
+/* How many words an instruction is. */
+static int instruction_len(uint32_t instr) {
+  switch (getop(instr)) {
+    case OP_SETDISPATCH: return 1 + ptr_words;
+    case OP_TAGN: return 3;
+    case OP_SETBIGGROUPNUM: return 2;
+    default: return 1;
+  }
+}
+
+bool op_has_longofs(int32_t instruction) {
+  switch (getop(instruction)) {
+    case OP_CALL:
+    case OP_BRANCH:
+    case OP_CHECKDELIM:
+      return true;
+    /* The "tag" instructions only have 8 bytes available for the jump target,
+     * but that is ok because these opcodes only require short jumps. */
+    case OP_TAG1:
+    case OP_TAG2:
+    case OP_TAGN:
+      return false;
+    default:
+      assert(false);
+      return false;
+  }
+}
+
+static int32_t getofs(uint32_t instruction) {
+  if (op_has_longofs(instruction)) {
+    return (int32_t)instruction >> 8;
+  } else {
+    return (int8_t)(instruction >> 8);
+  }
+}
+
+static void setofs(uint32_t *instruction, int32_t ofs) {
+  if (op_has_longofs(*instruction)) {
+    *instruction = getop(*instruction) | ofs << 8;
+  } else {
+    *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
+  }
+  assert(getofs(*instruction) == ofs);  /* Would fail in cases of overflow. */
+}
+
+static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
+
+/* Defines a local label at the current PC location.  All previous forward
+ * references are updated to point to this location.  The location is noted
+ * for any future backward references. */
+static void label(compiler *c, unsigned int label) {
+  int val;
+  uint32_t *codep;
+
+  assert(label < MAXLABEL);
+  val = c->fwd_labels[label];
+  codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
+  while (codep) {
+    int ofs = getofs(*codep);
+    setofs(codep, c->pc - codep - instruction_len(*codep));
+    codep = ofs ? codep + ofs : NULL;
+  }
+  c->fwd_labels[label] = EMPTYLABEL;
+  c->back_labels[label] = pcofs(c);
+}
+
+/* Creates a reference to a numbered label; either a forward reference
+ * (positive arg) or backward reference (negative arg).  For forward references
+ * the value returned now is actually a "next" pointer into a linked list of all
+ * instructions that use this label and will be patched later when the label is
+ * defined with label().
+ *
+ * The returned value is the offset that should be written into the instruction.
+ */
+static int32_t labelref(compiler *c, int label) {
+  assert(label < MAXLABEL);
+  if (label == LABEL_DISPATCH) {
+    /* No resolving required. */
+    return 0;
+  } else if (label < 0) {
+    /* Backward local label.  Relative to the next instruction. */
+    uint32_t from = (c->pc + 1) - c->group->bytecode;
+    return c->back_labels[-label] - from;
+  } else {
+    /* Forward local label: prepend to (possibly-empty) linked list. */
+    int *lptr = &c->fwd_labels[label];
+    int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c);
+    *lptr = pcofs(c);
+    return ret;
+  }
+}
+
+static void put32(compiler *c, uint32_t v) {
+  mgroup *g = c->group;
+  if (c->pc == g->bytecode_end) {
+    int ofs = pcofs(c);
+    size_t oldsize = g->bytecode_end - g->bytecode;
+    size_t newsize = UPB_MAX(oldsize * 2, 64);
+    /* TODO(haberman): handle OOM. */
+    g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t));
+    g->bytecode_end = g->bytecode + newsize;
+    c->pc = g->bytecode + ofs;
+  }
+  *c->pc++ = v;
+}
+
+static void putop(compiler *c, opcode op, ...) {
+  va_list ap;
+  va_start(ap, op);
+
+  switch (op) {
+    case OP_SETDISPATCH: {
+      uintptr_t ptr = (uintptr_t)va_arg(ap, void*);
+      put32(c, OP_SETDISPATCH);
+      put32(c, ptr);
+      if (sizeof(uintptr_t) > sizeof(uint32_t))
+        put32(c, (uint64_t)ptr >> 32);
+      break;
+    }
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_PUSHLENDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_HALT:
+    case OP_RET:
+    case OP_DISPATCH:
+      put32(c, op);
+      break;
+    case OP_PARSE_DOUBLE:
+    case OP_PARSE_FLOAT:
+    case OP_PARSE_INT64:
+    case OP_PARSE_UINT64:
+    case OP_PARSE_INT32:
+    case OP_PARSE_FIXED64:
+    case OP_PARSE_FIXED32:
+    case OP_PARSE_BOOL:
+    case OP_PARSE_UINT32:
+    case OP_PARSE_SFIXED32:
+    case OP_PARSE_SFIXED64:
+    case OP_PARSE_SINT32:
+    case OP_PARSE_SINT64:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_STRING:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+      put32(c, op | va_arg(ap, upb_selector_t) << 8);
+      break;
+    case OP_SETBIGGROUPNUM:
+      put32(c, op);
+      put32(c, va_arg(ap, int));
+      break;
+    case OP_CALL: {
+      const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
+      put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
+      break;
+    }
+    case OP_CHECKDELIM:
+    case OP_BRANCH: {
+      uint32_t instruction = op;
+      int label = va_arg(ap, int);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAG1:
+    case OP_TAG2: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (tag << 16);
+      assert(tag <= 0xffff);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAGN: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (upb_value_size(tag) << 16);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      put32(c, tag);
+      put32(c, tag >> 32);
+      break;
+    }
+  }
+
+  va_end(ap);
+}
+
+#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE)
+
+const char *upb_pbdecoder_getopname(unsigned int op) {
+#define QUOTE(x) #x
+#define EXPAND_AND_QUOTE(x) QUOTE(x)
+#define OPNAME(x) OP_##x
+#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x));
+#define T(x) OP(PARSE_##x)
+  /* Keep in sync with list in decoder.int.h. */
+  switch ((opcode)op) {
+    T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32)
+    T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64)
+    OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG)
+    OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET)
+    OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM)
+    OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP)
+    OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT)
+  }
+  return "<unknown op>";
+#undef OP
+#undef T
+}
+
+#endif
+
+#ifdef UPB_DUMP_BYTECODE
+
+static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
+
+  uint32_t *begin = p;
+
+  while (p < end) {
+    fprintf(f, "%p  %8tx", p, p - begin);
+    uint32_t instr = *p++;
+    uint8_t op = getop(instr);
+    fprintf(f, " %s", upb_pbdecoder_getopname(op));
+    switch ((opcode)op) {
+      case OP_SETDISPATCH: {
+        const upb_inttable *dispatch;
+        memcpy(&dispatch, p, sizeof(void*));
+        p += ptr_words;
+        const upb_pbdecodermethod *method =
+            (void *)((char *)dispatch -
+                     offsetof(upb_pbdecodermethod, dispatch));
+        fprintf(f, " %s", upb_msgdef_fullname(
+                              upb_handlers_msgdef(method->dest_handlers_)));
+        break;
+      }
+      case OP_DISPATCH:
+      case OP_STARTMSG:
+      case OP_ENDMSG:
+      case OP_PUSHLENDELIM:
+      case OP_POP:
+      case OP_SETDELIM:
+      case OP_HALT:
+      case OP_RET:
+        break;
+      case OP_PARSE_DOUBLE:
+      case OP_PARSE_FLOAT:
+      case OP_PARSE_INT64:
+      case OP_PARSE_UINT64:
+      case OP_PARSE_INT32:
+      case OP_PARSE_FIXED64:
+      case OP_PARSE_FIXED32:
+      case OP_PARSE_BOOL:
+      case OP_PARSE_UINT32:
+      case OP_PARSE_SFIXED32:
+      case OP_PARSE_SFIXED64:
+      case OP_PARSE_SINT32:
+      case OP_PARSE_SINT64:
+      case OP_STARTSEQ:
+      case OP_ENDSEQ:
+      case OP_STARTSUBMSG:
+      case OP_ENDSUBMSG:
+      case OP_STARTSTR:
+      case OP_STRING:
+      case OP_ENDSTR:
+      case OP_PUSHTAGDELIM:
+        fprintf(f, " %d", instr >> 8);
+        break;
+      case OP_SETBIGGROUPNUM:
+        fprintf(f, " %d", *p++);
+        break;
+      case OP_CHECKDELIM:
+      case OP_CALL:
+      case OP_BRANCH:
+        fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        break;
+      case OP_TAG1:
+      case OP_TAG2: {
+        fprintf(f, " tag:0x%x", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+      case OP_TAGN: {
+        uint64_t tag = *p++;
+        tag |= (uint64_t)*p++ << 32;
+        fprintf(f, " tag:0x%llx", (long long)tag);
+        fprintf(f, " n:%d", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+    }
+    fputs("\n", f);
+  }
+}
+
+#endif
+
+static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) {
+  uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type;
+  uint64_t encoded_tag = upb_vencode32(tag);
+  /* No tag should be greater than 5 bytes. */
+  assert(encoded_tag <= 0xffffffffff);
+  return encoded_tag;
+}
+
+static void putchecktag(compiler *c, const upb_fielddef *f,
+                        int wire_type, int dest) {
+  uint64_t tag = get_encoded_tag(f, wire_type);
+  switch (upb_value_size(tag)) {
+    case 1:
+      putop(c, OP_TAG1, dest, tag);
+      break;
+    case 2:
+      putop(c, OP_TAG2, dest, tag);
+      break;
+    default:
+      putop(c, OP_TAGN, dest, tag);
+      break;
+  }
+}
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+  upb_selector_t selector;
+  bool ok = upb_handlers_getselector(f, type, &selector);
+  UPB_ASSERT_VAR(ok, ok);
+  return selector;
+}
+
+/* Takes an existing, primary dispatch table entry and repacks it with a
+ * different alternate wire type.  Called when we are inserting a secondary
+ * dispatch table entry for an alternate wire type. */
+static uint64_t repack(uint64_t dispatch, int new_wt2) {
+  uint64_t ofs;
+  uint8_t wt1;
+  uint8_t old_wt2;
+  upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2);
+  assert(old_wt2 == NO_WIRE_TYPE);  /* wt2 should not be set yet. */
+  return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2);
+}
+
+/* Marks the current bytecode position as the dispatch target for this message,
+ * field, and wire type. */
+static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
+                           const upb_fielddef *f, int wire_type) {
+  /* Offset is relative to msg base. */
+  uint64_t ofs = pcofs(c) - method->code_base.ofs;
+  uint32_t fn = upb_fielddef_number(f);
+  upb_inttable *d = &method->dispatch;
+  upb_value v;
+  if (upb_inttable_remove(d, fn, &v)) {
+    /* TODO: prioritize based on packed setting in .proto file. */
+    uint64_t repacked = repack(upb_value_getuint64(v), wire_type);
+    upb_inttable_insert(d, fn, upb_value_uint64(repacked));
+    upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs));
+  } else {
+    uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE);
+    upb_inttable_insert(d, fn, upb_value_uint64(val));
+  }
+}
+
+static void putpush(compiler *c, const upb_fielddef *f) {
+  if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    putop(c, OP_PUSHLENDELIM);
+  } else {
+    uint32_t fn = upb_fielddef_number(f);
+    if (fn >= 1 << 24) {
+      putop(c, OP_PUSHTAGDELIM, 0);
+      putop(c, OP_SETBIGGROUPNUM, fn);
+    } else {
+      putop(c, OP_PUSHTAGDELIM, fn);
+    }
+  }
+}
+
+static upb_pbdecodermethod *find_submethod(const compiler *c,
+                                           const upb_pbdecodermethod *method,
+                                           const upb_fielddef *f) {
+  const upb_handlers *sub =
+      upb_handlers_getsubhandlers(method->dest_handlers_, f);
+  upb_value v;
+  return upb_inttable_lookupptr(&c->group->methods, sub, &v)
+             ? upb_value_getptr(v)
+             : NULL;
+}
+
+static void putsel(compiler *c, opcode op, upb_selector_t sel,
+                   const upb_handlers *h) {
+  if (upb_handlers_gethandler(h, sel)) {
+    putop(c, op, sel);
+  }
+}
+
+/* Puts an opcode to call a callback, but only if a callback actually exists for
+ * this field and handler type. */
+static void maybeput(compiler *c, opcode op, const upb_handlers *h,
+                     const upb_fielddef *f, upb_handlertype_t type) {
+  putsel(c, op, getsel(f, type), h);
+}
+
+static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) {
+  if (!upb_fielddef_lazy(f))
+    return false;
+
+  return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+
+/* bytecode compiler code generation ******************************************/
+
+/* Symbolic names for our local labels. */
+#define LABEL_LOOPSTART 1  /* Top of a repeated field loop. */
+#define LABEL_LOOPBREAK 2  /* To jump out of a repeated loop */
+#define LABEL_FIELD     3  /* Jump backward to find the most recent field. */
+#define LABEL_ENDMSG    4  /* To reach the OP_ENDMSG instr for this msg. */
+
+/* Generates bytecode to parse a single non-lazy message field. */
+static void generate_msgfield(compiler *c, const upb_fielddef *f,
+                              upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  const upb_pbdecodermethod *sub_m = find_submethod(c, method, f);
+  int wire_type;
+
+  if (!sub_m) {
+    /* Don't emit any code for this field at all; it will be parsed as an
+     * unknown field. */
+    return;
+  }
+
+  label(c, LABEL_FIELD);
+
+  wire_type =
+      (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
+          ? UPB_WIRE_TYPE_DELIMITED
+          : UPB_WIRE_TYPE_START_GROUP;
+
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+  }
+}
+
+/* Generates bytecode to parse a single string or lazy submessage field. */
+static void generate_delimfield(compiler *c, const upb_fielddef *f,
+                                upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+
+  label(c, LABEL_FIELD);
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    /* Need to emit even if no handler to skip past the string. */
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+  }
+}
+
+/* Generates bytecode to parse a single primitive field. */
+static void generate_primitivefield(compiler *c, const upb_fielddef *f,
+                                    upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f);
+  opcode parse_type;
+  upb_selector_t sel;
+  int wire_type;
+
+  label(c, LABEL_FIELD);
+
+  /* From a decoding perspective, ENUM is the same as INT32. */
+  if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM)
+    descriptor_type = UPB_DESCRIPTOR_TYPE_INT32;
+
+  parse_type = (opcode)descriptor_type;
+
+  /* TODO(haberman): generate packed or non-packed first depending on "packed"
+   * setting in the fielddef.  This will favor (in speed) whichever was
+   * specified. */
+
+  assert((int)parse_type >= 0 && parse_type <= OP_MAX);
+  sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Non-packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);  /* Packed and non-packed join. */
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+    putop(c, OP_SETDELIM);  /* Could remove for non-packed by dup ENDSEQ. */
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, parse_type, sel);
+  }
+}
+
+/* Adds bytecode for parsing the given message to the given decoderplan,
+ * while adding all dispatch targets to this message's dispatch table. */
+static void compile_method(compiler *c, upb_pbdecodermethod *method) {
+  const upb_handlers *h;
+  const upb_msgdef *md;
+  uint32_t* start_pc;
+  upb_msg_field_iter i;
+  upb_value val;
+
+  assert(method);
+
+  /* Clear all entries in the dispatch table. */
+  upb_inttable_uninit(&method->dispatch);
+  upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
+
+  h = upb_pbdecodermethod_desthandlers(method);
+  md = upb_handlers_msgdef(h);
+
+ method->code_base.ofs = pcofs(c);
+  putop(c, OP_SETDISPATCH, &method->dispatch);
+  putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
+ label(c, LABEL_FIELD);
+  start_pc = c->pc;
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_fieldtype_t type = upb_fielddef_type(f);
+
+    if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) {
+      generate_msgfield(c, f, method);
+    } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
+               type == UPB_TYPE_MESSAGE) {
+      generate_delimfield(c, f, method);
+    } else {
+      generate_primitivefield(c, f, method);
+    }
+  }
+
+  /* If there were no fields, or if no handlers were defined, we need to
+   * generate a non-empty loop body so that we can at least dispatch for unknown
+   * fields and check for the end of the message. */
+  if (c->pc == start_pc) {
+    /* Check for end-of-message. */
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    /* Unconditionally dispatch. */
+    putop(c, OP_DISPATCH, 0);
+  }
+
+  /* For now we just loop back to the last field of the message (or if none,
+   * the DISPATCH opcode for the message). */
+  putop(c, OP_BRANCH, -LABEL_FIELD);
+
+  /* Insert both a label and a dispatch table entry for this end-of-msg. */
+ label(c, LABEL_ENDMSG);
+  val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
+  upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val);
+
+  putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h);
+  putop(c, OP_RET);
+
+  upb_inttable_compact(&method->dispatch);
+}
+
+/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h".
+ * Returns the method for these handlers.
+ *
+ * Generates a new method for every destination handlers reachable from "h". */
+static void find_methods(compiler *c, const upb_handlers *h) {
+  upb_value v;
+  upb_msg_field_iter i;
+  const upb_msgdef *md;
+
+  if (upb_inttable_lookupptr(&c->group->methods, h, &v))
+    return;
+  newmethod(h, c->group);
+
+  /* Find submethods. */
+  md = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub_h;
+    if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+        (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) {
+      /* We only generate a decoder method for submessages with handlers.
+       * Others will be parsed as unknown fields. */
+      find_methods(c, sub_h);
+    }
+  }
+}
+
+/* (Re-)compile bytecode for all messages in "msgs."
+ * Overwrites any existing bytecode in "c". */
+static void compile_methods(compiler *c) {
+  upb_inttable_iter i;
+
+  /* Start over at the beginning of the bytecode. */
+  c->pc = c->group->bytecode;
+
+  upb_inttable_begin(&i, &c->group->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    compile_method(c, method);
+  }
+}
+
+static void set_bytecode_handlers(mgroup *g) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
+    upb_byteshandler *h = &m->input_handler_;
+
+    m->code_base.ptr = g->bytecode + m->code_base.ofs;
+
+    upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
+    upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
+    upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
+  }
+}
+
+
+/* JIT setup. *****************************************************************/
+
+#ifdef UPB_USE_JIT_X64
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  g->jit_code = NULL;
+  if (allowjit) {
+    /* Compile byte-code into machine code, create handlers. */
+    upb_pbdecoder_jit(g);
+  } else {
+    set_bytecode_handlers(g);
+  }
+}
+
+#else  /* UPB_USE_JIT_X64 */
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  /* No JIT compiled in; use bytecode handlers unconditionally. */
+  UPB_UNUSED(allowjit);
+  set_bytecode_handlers(g);
+}
+
+#endif  /* UPB_USE_JIT_X64 */
+
+
+/* TODO(haberman): allow this to be constructed for an arbitrary set of dest
+ * handlers and other mgroups (but verify we have a transitive closure). */
+const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy,
+                         const void *owner) {
+  mgroup *g;
+  compiler *c;
+
+  UPB_UNUSED(allowjit);
+  assert(upb_handlers_isfrozen(dest));
+
+  g = newgroup(owner);
+  c = newcompiler(g, lazy);
+  find_methods(c, dest);
+
+  /* We compile in two passes:
+   * 1. all messages are assigned relative offsets from the beginning of the
+   *    bytecode (saved in method->code_base).
+   * 2. forwards OP_CALL instructions can be correctly linked since message
+   *    offsets have been previously assigned.
+   *
+   * Could avoid the second pass by linking OP_CALL instructions somehow. */
+  compile_methods(c);
+  compile_methods(c);
+  g->bytecode_end = c->pc;
+  freecompiler(c);
+
+#ifdef UPB_DUMP_BYTECODE
+  {
+    FILE *f = fopen("/tmp/upb-bytecode", "wb");
+    assert(f);
+    dumpbc(g->bytecode, g->bytecode_end, stderr);
+    dumpbc(g->bytecode, g->bytecode_end, f);
+    fclose(f);
+  }
+#endif
+
+  sethandlers(g, allowjit);
+  return g;
+}
+
+
+/* upb_pbcodecache ************************************************************/
+
+void upb_pbcodecache_init(upb_pbcodecache *c) {
+  upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
+  c->allow_jit_ = true;
+}
+
+void upb_pbcodecache_uninit(upb_pbcodecache *c) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &c->groups);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
+    mgroup_unref(group, c);
+  }
+  upb_inttable_uninit(&c->groups);
+}
+
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
+  return c->allow_jit_;
+}
+
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
+  if (upb_inttable_count(&c->groups) > 0)
+    return false;
+  c->allow_jit_ = allow;
+  return true;
+}
+
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) {
+  upb_value v;
+  bool ok;
+
+  /* Right now we build a new DecoderMethod every time.
+   * TODO(haberman): properly cache methods by their true key. */
+  const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c);
+  upb_inttable_push(&c->groups, upb_value_constptr(g));
+
+  ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
+  UPB_ASSERT_VAR(ok, ok);
+  return upb_value_getptr(v);
+}
+
+
+/* upb_pbdecodermethodopts ****************************************************/
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h) {
+  opts->handlers = h;
+  opts->lazy = false;
+}
+
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) {
+  opts->lazy = lazy;
+}
+/*
+** upb::Decoder (Bytecode Decoder VM)
+**
+** Bytecode must previously have been generated using the bytecode compiler in
+** compile_decoder.c.  This decoder then walks through the bytecode op-by-op to
+** parse the input.
+**
+** Decoding is fully resumable; we just keep a pointer to the current bytecode
+** instruction and resume from there.  A fair amount of the logic here is to
+** handle the fact that values can span buffer seams and we have to be able to
+** be capable of suspending/resuming from any byte in the stream.  This
+** sometimes requires keeping a few trailing bytes from the last buffer around
+** in the "residual" buffer.
+*/
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+const char *kPbDecoderStackOverflow = "Nesting too deep.";
+const char *kPbDecoderSubmessageTooLong =
+    "Submessage end extends past enclosing submessage.";
+
+/* Error messages shared within this file. */
+static const char *kUnterminatedVarint = "Unterminated varint.";
+
+/* upb_pbdecoder **************************************************************/
+
+static opcode halt = OP_HALT;
+
+/* Whether an op consumes any of the input buffer. */
+static bool consumes_input(opcode op) {
+  switch (op) {
+    case OP_SETDISPATCH:
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_SETBIGGROUPNUM:
+    case OP_CHECKDELIM:
+    case OP_CALL:
+    case OP_RET:
+    case OP_BRANCH:
+      return false;
+    default:
+      return true;
+  }
+}
+
+static size_t stacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+  return entries * sizeof(upb_pbdecoder_frame);
+}
+
+static size_t callstacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+
+#ifdef UPB_USE_JIT_X64
+  if (d->method_->is_native_) {
+    /* Each native stack frame needs two pointers, plus we need a few frames for
+     * the enter/exit trampolines. */
+    size_t ret = entries * sizeof(void*) * 2;
+    ret += sizeof(void*) * 10;
+    return ret;
+  }
+#endif
+
+  return entries * sizeof(uint32_t*);
+}
+
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p);
+
+/* It's unfortunate that we have to micro-manage the compiler with
+ * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily
+ * specific to one hardware configuration.  But empirically on a Core i7,
+ * performance increases 30-50% with these annotations.  Every instance where
+ * these appear, gcc 4.2.1 made the wrong decision and degraded performance in
+ * benchmarks. */
+
+static void seterr(upb_pbdecoder *d, const char *msg) {
+  upb_status status = UPB_STATUS_INIT;
+  upb_status_seterrmsg(&status, msg);
+  upb_env_reporterror(d->env, &status);
+}
+
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
+  seterr(d, msg);
+}
+
+
+/* Buffering ******************************************************************/
+
+/* We operate on one buffer at a time, which is either the user's buffer passed
+ * to our "decode" callback or some residual bytes from the previous buffer. */
+
+/* How many bytes can be safely read from d->ptr without reading past end-of-buf
+ * or past the current delimited end. */
+static size_t curbufleft(const upb_pbdecoder *d) {
+  assert(d->data_end >= d->ptr);
+  return d->data_end - d->ptr;
+}
+
+/* How many bytes are available before end-of-buffer. */
+static size_t bufleft(const upb_pbdecoder *d) {
+  return d->end - d->ptr;
+}
+
+/* Overall stream offset of d->ptr. */
+uint64_t offset(const upb_pbdecoder *d) {
+  return d->bufstart_ofs + (d->ptr - d->buf);
+}
+
+/* How many bytes are available before the end of this delimited region. */
+size_t delim_remaining(const upb_pbdecoder *d) {
+  return d->top->end_ofs - offset(d);
+}
+
+/* Advances d->ptr. */
+static void advance(upb_pbdecoder *d, size_t len) {
+  assert(curbufleft(d) >= len);
+  d->ptr += len;
+}
+
+static bool in_buf(const char *p, const char *buf, const char *end) {
+  return p >= buf && p <= end;
+}
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p) {
+  return in_buf(p, d->residual, d->residual_end);
+}
+
+/* Calculates the delim_end value, which is affected by both the current buffer
+ * and the parsing stack, so must be called whenever either is updated. */
+static void set_delim_end(upb_pbdecoder *d) {
+  size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs;
+  if (delim_ofs <= (size_t)(d->end - d->buf)) {
+    d->delim_end = d->buf + delim_ofs;
+    d->data_end = d->delim_end;
+  } else {
+    d->data_end = d->end;
+    d->delim_end = NULL;
+  }
+}
+
+static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) {
+  d->ptr = buf;
+  d->buf = buf;
+  d->end = end;
+  set_delim_end(d);
+}
+
+static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) {
+  assert(curbufleft(d) == 0);
+  d->bufstart_ofs += (d->end - d->buf);
+  switchtobuf(d, buf, buf + len);
+}
+
+static void checkpoint(upb_pbdecoder *d) {
+  /* The assertion here is in the interests of efficiency, not correctness.
+   * We are trying to ensure that we don't checkpoint() more often than
+   * necessary. */
+  assert(d->checkpoint != d->ptr);
+  d->checkpoint = d->ptr;
+}
+
+/* Skips "bytes" bytes in the stream, which may be more than available.  If we
+ * skip more bytes than are available, we return a long read count to the caller
+ * indicating how many bytes can be skipped over before passing actual data
+ * again.  Skipped bytes can pass a NULL buffer and the decoder guarantees they
+ * won't actually be read.
+ */
+static int32_t skip(upb_pbdecoder *d, size_t bytes) {
+  assert(!in_residual_buf(d, d->ptr) || d->size_param == 0);
+  assert(d->skip == 0);
+  if (bytes > delim_remaining(d)) {
+    seterr(d, "Skipped value extended beyond enclosing submessage.");
+    return upb_pbdecoder_suspend(d);
+  } else if (bufleft(d) > bytes) {
+    /* Skipped data is all in current buffer, and more is still available. */
+    advance(d, bytes);
+    d->skip = 0;
+    return DECODE_OK;
+  } else {
+    /* Skipped data extends beyond currently available buffers. */
+    d->pc = d->last;
+    d->skip = bytes - curbufleft(d);
+    d->bufstart_ofs += (d->end - d->buf);
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return d->size_param + d->skip;
+  }
+}
+
+
+/* Resumes the decoder from an initial state or from a previous suspend. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle) {
+  UPB_UNUSED(p);  /* Useless; just for the benefit of the JIT. */
+
+  d->buf_param = buf;
+  d->size_param = size;
+  d->handle = handle;
+
+  if (d->residual_end > d->residual) {
+    /* We have residual bytes from the last buffer. */
+    assert(d->ptr == d->residual);
+  } else {
+    switchtobuf(d, buf, buf + size);
+  }
+
+  d->checkpoint = d->ptr;
+
+  if (d->skip) {
+    size_t skip_bytes = d->skip;
+    d->skip = 0;
+    CHECK_RETURN(skip(d, skip_bytes));
+    d->checkpoint = d->ptr;
+  }
+
+  if (!buf) {
+    /* NULL buf is ok if its entire span is covered by the "skip" above, but
+     * by this point we know that "skip" doesn't cover the buffer. */
+    seterr(d, "Passed NULL buffer over non-skippable region.");
+    return upb_pbdecoder_suspend(d);
+  }
+
+  if (d->top->groupnum < 0) {
+    CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0));
+    d->checkpoint = d->ptr;
+  }
+
+  return DECODE_OK;
+}
+
+/* Suspends the decoder at the last checkpoint, without saving any residual
+ * bytes.  If there are any unconsumed bytes, returns a short byte count. */
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d) {
+  d->pc = d->last;
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; no user bytes were consumed. */
+    d->ptr = d->residual;
+    return 0;
+  } else {
+    size_t consumed;
+    assert(!in_residual_buf(d, d->checkpoint));
+    assert(d->buf == d->buf_param);
+
+    consumed = d->checkpoint - d->buf;
+    d->bufstart_ofs += consumed;
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return consumed;
+  }
+}
+
+/* Suspends the decoder at the last checkpoint, and saves any unconsumed
+ * bytes in our residual buffer.  This is necessary if we need more user
+ * bytes to form a complete value, which might not be contiguous in the
+ * user's buffers.  Always consumes all user bytes. */
+static size_t suspend_save(upb_pbdecoder *d) {
+  /* We hit end-of-buffer before we could parse a full value.
+   * Save any unconsumed bytes (if any) to the residual buffer. */
+  d->pc = d->last;
+
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; append user byte(s) to residual buf. */
+    assert((d->residual_end - d->residual) + d->size_param <=
+           sizeof(d->residual));
+    if (!in_residual_buf(d, d->ptr)) {
+      d->bufstart_ofs -= (d->residual_end - d->residual);
+    }
+    memcpy(d->residual_end, d->buf_param, d->size_param);
+    d->residual_end += d->size_param;
+  } else {
+    /* Checkpoint was in user buf; old residual bytes not needed. */
+    size_t save;
+    assert(!in_residual_buf(d, d->checkpoint));
+
+    d->ptr = d->checkpoint;
+    save = curbufleft(d);
+    assert(save <= sizeof(d->residual));
+    memcpy(d->residual, d->ptr, save);
+    d->residual_end = d->residual + save;
+    d->bufstart_ofs = offset(d);
+  }
+
+  switchtobuf(d, d->residual, d->residual_end);
+  return d->size_param;
+}
+
+/* Copies the next "bytes" bytes into "buf" and advances the stream.
+ * Requires that this many bytes are available in the current buffer. */
+UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf,
+                                         size_t bytes) {
+  assert(bytes <= curbufleft(d));
+  memcpy(buf, d->ptr, bytes);
+  advance(d, bytes);
+}
+
+/* Slow path for getting the next "bytes" bytes, regardless of whether they are
+ * available in the current buffer or not.  Returns a status code as described
+ * in decoder.int.h. */
+UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  const size_t avail = curbufleft(d);
+  consumebytes(d, buf, avail);
+  bytes -= avail;
+  assert(bytes > 0);
+  if (in_residual_buf(d, d->ptr)) {
+    advancetobuf(d, d->buf_param, d->size_param);
+  }
+  if (curbufleft(d) >= bytes) {
+    consumebytes(d, (char *)buf + avail, bytes);
+    return DECODE_OK;
+  } else if (d->data_end == d->delim_end) {
+    seterr(d, "Submessage ended in the middle of a value or group");
+    return upb_pbdecoder_suspend(d);
+  } else {
+    return suspend_save(d);
+  }
+}
+
+/* Gets the next "bytes" bytes, regardless of whether they are available in the
+ * current buffer or not.  Returns a status code as described in decoder.int.h.
+ */
+UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    /* Buffer has enough data to satisfy. */
+    consumebytes(d, buf, bytes);
+    return DECODE_OK;
+  } else {
+    return getbytes_slow(d, buf, bytes);
+  }
+}
+
+UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  size_t ret = curbufleft(d);
+  memcpy(buf, d->ptr, ret);
+  if (in_residual_buf(d, d->ptr)) {
+    size_t copy = UPB_MIN(bytes - ret, d->size_param);
+    memcpy((char *)buf + ret, d->buf_param, copy);
+    ret += copy;
+  }
+  return ret;
+}
+
+UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    memcpy(buf, d->ptr, bytes);
+    return bytes;
+  } else {
+    return peekbytes_slow(d, buf, bytes);
+  }
+}
+
+
+/* Decoding of wire types *****************************************************/
+
+/* Slow path for decoding a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d,
+                                                      uint64_t *u64) {
+  uint8_t byte = 0x80;
+  int bitpos;
+  *u64 = 0;
+  for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+    int32_t ret = getbytes(d, &byte, 1);
+    if (ret >= 0) return ret;
+    *u64 |= (uint64_t)(byte & 0x7F) << bitpos;
+  }
+  if(bitpos == 70 && (byte & 0x80)) {
+    seterr(d, kUnterminatedVarint);
+    return upb_pbdecoder_suspend(d);
+  }
+  return DECODE_OK;
+}
+
+/* Decodes a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) {
+  if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) {
+    *u64 = *d->ptr;
+    advance(d, 1);
+    return DECODE_OK;
+  } else if (curbufleft(d) >= 10) {
+    /* Fast case. */
+    upb_decoderet r = upb_vdecode_fast(d->ptr);
+    if (r.p == NULL) {
+      seterr(d, kUnterminatedVarint);
+      return upb_pbdecoder_suspend(d);
+    }
+    advance(d, r.p - d->ptr);
+    *u64 = r.val;
+    return DECODE_OK;
+  } else {
+    /* Slow case -- varint spans buffer seam. */
+    return upb_pbdecoder_decode_varint_slow(d, u64);
+  }
+}
+
+/* Decodes a 32-bit varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) {
+  uint64_t u64;
+  int32_t ret = decode_varint(d, &u64);
+  if (ret >= 0) return ret;
+  if (u64 > UINT32_MAX) {
+    seterr(d, "Unterminated 32-bit varint");
+    /* TODO(haberman) guarantee that this function return is >= 0 somehow,
+     * so we know this path will always be treated as error by our caller.
+     * Right now the size_t -> int32_t can overflow and produce negative values.
+     */
+    *u32 = 0;
+    return upb_pbdecoder_suspend(d);
+  }
+  *u32 = u64;
+  return DECODE_OK;
+}
+
+/* Decodes a fixed32 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) {
+  return getbytes(d, u32, 4);
+}
+
+/* Decodes a fixed64 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) {
+  return getbytes(d, u64, 8);
+}
+
+/* Non-static versions of the above functions.
+ * These are called by the JIT for fallback paths. */
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) {
+  return decode_fixed32(d, u32);
+}
+
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) {
+  return decode_fixed64(d, u64);
+}
+
+static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; }
+static float  as_float(uint32_t n)  { float  f; memcpy(&f, &n, 4); return f; }
+
+/* Pushes a frame onto the decoder stack. */
+static bool decoder_push(upb_pbdecoder *d, uint64_t end) {
+  upb_pbdecoder_frame *fr = d->top;
+
+  if (end > fr->end_ofs) {
+    seterr(d, kPbDecoderSubmessageTooLong);
+    return false;
+  } else if (fr == d->limit) {
+    seterr(d, kPbDecoderStackOverflow);
+    return false;
+  }
+
+  fr++;
+  fr->end_ofs = end;
+  fr->dispatch = NULL;
+  fr->groupnum = 0;
+  d->top = fr;
+  return true;
+}
+
+static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) {
+  /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence
+   * field number) prior to hitting any enclosing submessage end, pushing our
+   * existing delim end prevents us from continuing to parse values from a
+   * corrupt proto that doesn't give us an END tag in time. */
+  if (!decoder_push(d, d->top->end_ofs))
+    return false;
+  d->top->groupnum = arg;
+  return true;
+}
+
+/* Pops a frame from the decoder stack. */
+static void decoder_pop(upb_pbdecoder *d) { d->top--; }
+
+UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d,
+                                                 uint64_t expected) {
+  uint64_t data = 0;
+  size_t bytes = upb_value_size(expected);
+  size_t read = peekbytes(d, &data, bytes);
+  if (read == bytes && data == expected) {
+    /* Advance past matched bytes. */
+    int32_t ok = getbytes(d, &data, read);
+    UPB_ASSERT_VAR(ok, ok < 0);
+    return DECODE_OK;
+  } else if (read < bytes && memcmp(&data, &expected, read) == 0) {
+    return suspend_save(d);
+  } else {
+    return DECODE_MISMATCH;
+  }
+}
+
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type) {
+  if (fieldnum >= 0)
+    goto have_tag;
+
+  while (true) {
+    uint32_t tag;
+    CHECK_RETURN(decode_v32(d, &tag));
+    wire_type = tag & 0x7;
+    fieldnum = tag >> 3;
+
+have_tag:
+    if (fieldnum == 0) {
+      seterr(d, "Saw invalid field number (0)");
+      return upb_pbdecoder_suspend(d);
+    }
+
+    /* TODO: deliver to unknown field callback. */
+    switch (wire_type) {
+      case UPB_WIRE_TYPE_32BIT:
+        CHECK_RETURN(skip(d, 4));
+        break;
+      case UPB_WIRE_TYPE_64BIT:
+        CHECK_RETURN(skip(d, 8));
+        break;
+      case UPB_WIRE_TYPE_VARINT: {
+        uint64_t u64;
+        CHECK_RETURN(decode_varint(d, &u64));
+        break;
+      }
+      case UPB_WIRE_TYPE_DELIMITED: {
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_RETURN(skip(d, len));
+        break;
+      }
+      case UPB_WIRE_TYPE_START_GROUP:
+        CHECK_SUSPEND(pushtagdelim(d, -fieldnum));
+        break;
+      case UPB_WIRE_TYPE_END_GROUP:
+        if (fieldnum == -d->top->groupnum) {
+          decoder_pop(d);
+        } else if (fieldnum == d->top->groupnum) {
+          return DECODE_ENDGROUP;
+        } else {
+          seterr(d, "Unmatched ENDGROUP tag.");
+          return upb_pbdecoder_suspend(d);
+        }
+        break;
+      default:
+        seterr(d, "Invalid wire type");
+        return upb_pbdecoder_suspend(d);
+    }
+
+    if (d->top->groupnum >= 0) {
+      return DECODE_OK;
+    }
+
+    /* Unknown group -- continue looping over unknown fields. */
+    checkpoint(d);
+  }
+}
+
+static void goto_endmsg(upb_pbdecoder *d) {
+  upb_value v;
+  bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v);
+  UPB_ASSERT_VAR(found, found);
+  d->pc = d->top->base + upb_value_getuint64(v);
+}
+
+/* Parses a tag and jumps to the corresponding bytecode instruction for this
+ * field.
+ *
+ * If the tag is unknown (or the wire type doesn't match), parses the field as
+ * unknown.  If the tag is a valid ENDGROUP tag, jumps to the bytecode
+ * instruction for the end of message. */
+static int32_t dispatch(upb_pbdecoder *d) {
+  upb_inttable *dispatch = d->top->dispatch;
+  uint32_t tag;
+  uint8_t wire_type;
+  uint32_t fieldnum;
+  upb_value val;
+  int32_t retval;
+
+  /* Decode tag. */
+  CHECK_RETURN(decode_v32(d, &tag));
+  wire_type = tag & 0x7;
+  fieldnum = tag >> 3;
+
+  /* Lookup tag.  Because of packed/non-packed compatibility, we have to
+   * check the wire type against two possibilities. */
+  if (fieldnum != DISPATCH_ENDMSG &&
+      upb_inttable_lookup32(dispatch, fieldnum, &val)) {
+    uint64_t v = upb_value_getuint64(val);
+    if (wire_type == (v & 0xff)) {
+      d->pc = d->top->base + (v >> 16);
+      return DECODE_OK;
+    } else if (wire_type == ((v >> 8) & 0xff)) {
+      bool found =
+          upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val);
+      UPB_ASSERT_VAR(found, found);
+      d->pc = d->top->base + upb_value_getuint64(val);
+      return DECODE_OK;
+    }
+  }
+
+  /* We have some unknown fields (or ENDGROUP) to parse.  The DISPATCH or TAG
+   * bytecode that triggered this is preceded by a CHECKDELIM bytecode which
+   * we need to back up to, so that when we're done skipping unknown data we
+   * can re-check the delimited end. */
+  d->last--;  /* Necessary if we get suspended */
+  d->pc = d->last;
+  assert(getop(*d->last) == OP_CHECKDELIM);
+
+  /* Unknown field or ENDGROUP. */
+  retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type);
+
+  CHECK_RETURN(retval);
+
+  if (retval == DECODE_ENDGROUP) {
+    goto_endmsg(d);
+    return DECODE_OK;
+  }
+
+  return DECODE_OK;
+}
+
+/* Callers know that the stack is more than one deep because the opcodes that
+ * call this only occur after PUSH operations. */
+upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
+  assert(d->top != d->stack);
+  return d->top - 1;
+}
+
+
+/* The main decoding loop *****************************************************/
+
+/* The main decoder VM function.  Uses traditional bytecode dispatch loop with a
+ * switch() statement. */
+size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group,
+                      const upb_bufhandle* handle) {
+
+#define VMCASE(op, code) \
+  case op: { code; if (consumes_input(op)) checkpoint(d); break; }
+#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \
+  VMCASE(OP_PARSE_ ## type, { \
+    ctype val; \
+    CHECK_RETURN(decode_ ## wt(d, &val)); \
+    upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
+  })
+
+  while(1) {
+    int32_t instruction;
+    opcode op;
+    uint32_t arg;
+    int32_t longofs;
+
+    d->last = d->pc;
+    instruction = *d->pc++;
+    op = getop(instruction);
+    arg = instruction >> 8;
+    longofs = arg;
+    assert(d->ptr != d->residual_end);
+    UPB_UNUSED(group);
+#ifdef UPB_DUMP_BYTECODE
+    fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d "
+                    "%x %s (%d)\n",
+            (int)offset(d),
+            (int)(d->ptr - d->buf),
+            (int)(d->data_end - d->ptr),
+            (int)(d->end - d->ptr),
+            (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)),
+            (int)(d->pc - 1 - group->bytecode),
+            upb_pbdecoder_getopname(op),
+            arg);
+#endif
+    switch (op) {
+      /* Technically, we are losing data if we see a 32-bit varint that is not
+       * properly sign-extended.  We could detect this and error about the data
+       * loss, but proto2 does not do this, so we pass. */
+      PRIMITIVE_OP(INT32,    varint,  int32,  int32_t,      uint64_t)
+      PRIMITIVE_OP(INT64,    varint,  int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(UINT32,   varint,  uint32, uint32_t,     uint64_t)
+      PRIMITIVE_OP(UINT64,   varint,  uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(FIXED32,  fixed32, uint32, uint32_t,     uint32_t)
+      PRIMITIVE_OP(FIXED64,  fixed64, uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(SFIXED32, fixed32, int32,  int32_t,      uint32_t)
+      PRIMITIVE_OP(SFIXED64, fixed64, int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(BOOL,     varint,  bool,   bool,         uint64_t)
+      PRIMITIVE_OP(DOUBLE,   fixed64, double, as_double,    uint64_t)
+      PRIMITIVE_OP(FLOAT,    fixed32, float,  as_float,     uint32_t)
+      PRIMITIVE_OP(SINT32,   varint,  int32,  upb_zzdec_32, uint64_t)
+      PRIMITIVE_OP(SINT64,   varint,  int64,  upb_zzdec_64, uint64_t)
+
+      VMCASE(OP_SETDISPATCH,
+        d->top->base = d->pc - 1;
+        memcpy(&d->top->dispatch, d->pc, sizeof(void*));
+        d->pc += sizeof(void*) / sizeof(uint32_t);
+      )
+      VMCASE(OP_STARTMSG,
+        CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
+      )
+      VMCASE(OP_ENDMSG,
+        CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
+      )
+      VMCASE(OP_STARTSEQ,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSEQ,
+        CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSUBMSG,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSUBMSG,
+        CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSTR,
+        uint32_t len = delim_remaining(d);
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
+        if (len == 0) {
+          d->pc++;  /* Skip OP_STRING. */
+        }
+      )
+      VMCASE(OP_STRING,
+        uint32_t len = curbufleft(d);
+        size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle);
+        if (n > len) {
+          if (n > delim_remaining(d)) {
+            seterr(d, "Tried to skip past end of string.");
+            return upb_pbdecoder_suspend(d);
+          } else {
+            int32_t ret = skip(d, n);
+            /* This shouldn't return DECODE_OK, because n > len. */
+            assert(ret >= 0);
+            return ret;
+          }
+        }
+        advance(d, n);
+        if (n < len || d->delim_end == NULL) {
+          /* We aren't finished with this string yet. */
+          d->pc--;  /* Repeat OP_STRING. */
+          if (n > 0) checkpoint(d);
+          return upb_pbdecoder_suspend(d);
+        }
+      )
+      VMCASE(OP_ENDSTR,
+        CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
+      )
+      VMCASE(OP_PUSHTAGDELIM,
+        CHECK_SUSPEND(pushtagdelim(d, arg));
+      )
+      VMCASE(OP_SETBIGGROUPNUM,
+        d->top->groupnum = *d->pc++;
+      )
+      VMCASE(OP_POP,
+        assert(d->top > d->stack);
+        decoder_pop(d);
+      )
+      VMCASE(OP_PUSHLENDELIM,
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_SUSPEND(decoder_push(d, offset(d) + len));
+        set_delim_end(d);
+      )
+      VMCASE(OP_SETDELIM,
+        set_delim_end(d);
+      )
+      VMCASE(OP_CHECKDELIM,
+        /* We are guaranteed of this assert because we never allow ourselves to
+         * consume bytes beyond data_end, which covers delim_end when non-NULL.
+         */
+        assert(!(d->delim_end && d->ptr > d->delim_end));
+        if (d->ptr == d->delim_end)
+          d->pc += longofs;
+      )
+      VMCASE(OP_CALL,
+        d->callstack[d->call_len++] = d->pc;
+        d->pc += longofs;
+      )
+      VMCASE(OP_RET,
+        assert(d->call_len > 0);
+        d->pc = d->callstack[--d->call_len];
+      )
+      VMCASE(OP_BRANCH,
+        d->pc += longofs;
+      )
+      VMCASE(OP_TAG1,
+        uint8_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xff;
+        if (*d->ptr == expected) {
+          advance(d, 1);
+        } else {
+          int8_t shortofs;
+         badtag:
+          shortofs = arg;
+          if (shortofs == LABEL_DISPATCH) {
+            CHECK_RETURN(dispatch(d));
+          } else {
+            d->pc += shortofs;
+            break; /* Avoid checkpoint(). */
+          }
+        }
+      )
+      VMCASE(OP_TAG2,
+        uint16_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xffff;
+        if (curbufleft(d) >= 2) {
+          uint16_t actual;
+          memcpy(&actual, d->ptr, 2);
+          if (expected == actual) {
+            advance(d, 2);
+          } else {
+            goto badtag;
+          }
+        } else {
+          int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+          if (result == DECODE_MISMATCH) goto badtag;
+          if (result >= 0) return result;
+        }
+      )
+      VMCASE(OP_TAGN, {
+        uint64_t expected;
+        int32_t result;
+        memcpy(&expected, d->pc, 8);
+        d->pc += 2;
+        result = upb_pbdecoder_checktag_slow(d, expected);
+        if (result == DECODE_MISMATCH) goto badtag;
+        if (result >= 0) return result;
+      })
+      VMCASE(OP_DISPATCH, {
+        CHECK_RETURN(dispatch(d));
+      })
+      VMCASE(OP_HALT, {
+        return d->size_param;
+      })
+    }
+  }
+}
+
+
+/* BytesHandler handlers ******************************************************/
+
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 1;
+  d->callstack[0] = &halt;
+  d->pc = pc;
+  d->skip = 0;
+  return d;
+}
+
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 0;
+  d->skip = 0;
+  return d;
+}
+
+bool upb_pbdecoder_end(void *closure, const void *handler_data) {
+  upb_pbdecoder *d = closure;
+  const upb_pbdecodermethod *method = handler_data;
+  uint64_t end;
+  char dummy;
+
+  if (d->residual_end > d->residual) {
+    seterr(d, "Unexpected EOF: decoder still has buffered unparsed data");
+    return false;
+  }
+
+  if (d->skip) {
+    seterr(d, "Unexpected EOF inside skipped data");
+    return false;
+  }
+
+  if (d->top->end_ofs != UINT64_MAX) {
+    seterr(d, "Unexpected EOF inside delimited string");
+    return false;
+  }
+
+  /* The user's end() call indicates that the message ends here. */
+  end = offset(d);
+  d->top->end_ofs = end;
+
+#ifdef UPB_USE_JIT_X64
+  if (method->is_native_) {
+    const mgroup *group = (const mgroup*)method->group;
+    if (d->top != d->stack)
+      d->stack->end_ofs = 0;
+    group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL);
+  } else
+#endif
+  {
+    const uint32_t *p = d->pc;
+    d->stack->end_ofs = end;
+    /* Check the previous bytecode, but guard against beginning. */
+    if (p != method->code_base.ptr) p--;
+    if (getop(*p) == OP_CHECKDELIM) {
+      /* Rewind from OP_TAG* to OP_CHECKDELIM. */
+      assert(getop(*d->pc) == OP_TAG1 ||
+             getop(*d->pc) == OP_TAG2 ||
+             getop(*d->pc) == OP_TAGN ||
+             getop(*d->pc) == OP_DISPATCH);
+      d->pc = p;
+    }
+    upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
+  }
+
+  if (d->call_len != 0) {
+    seterr(d, "Unexpected EOF inside submessage or group");
+    return false;
+  }
+
+  return true;
+}
+
+size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf,
+                            size_t size, const upb_bufhandle *handle) {
+  int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle);
+
+  if (result == DECODE_ENDGROUP) goto_endmsg(decoder);
+  CHECK_RETURN(result);
+
+  return run_decoder_vm(decoder, group, handle);
+}
+
+
+/* Public API *****************************************************************/
+
+void upb_pbdecoder_reset(upb_pbdecoder *d) {
+  d->top = d->stack;
+  d->top->groupnum = 0;
+  d->ptr = d->residual;
+  d->buf = d->residual;
+  d->end = d->residual;
+  d->residual_end = d->residual;
+}
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m,
+                                    upb_sink *sink) {
+  const size_t default_max_nesting = 64;
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_pbdecoder *d = upb_env_malloc(e, sizeof(upb_pbdecoder));
+  if (!d) return NULL;
+
+  d->method_ = m;
+  d->callstack = upb_env_malloc(e, callstacksize(d, default_max_nesting));
+  d->stack = upb_env_malloc(e, stacksize(d, default_max_nesting));
+  if (!d->stack || !d->callstack) {
+    return NULL;
+  }
+
+  d->env = e;
+  d->limit = d->stack + default_max_nesting - 1;
+  d->stack_size = default_max_nesting;
+
+  upb_pbdecoder_reset(d);
+  upb_bytessink_reset(&d->input_, &m->input_handler_, d);
+
+  assert(sink);
+  if (d->method_->dest_handlers_) {
+    if (sink->handlers != d->method_->dest_handlers_)
+      return NULL;
+  }
+  upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
+
+  /* If this fails, increase the value in decoder.h. */
+  assert(upb_env_bytesallocated(e) - size_before <= UPB_PB_DECODER_SIZE);
+  return d;
+}
+
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) {
+  return offset(d);
+}
+
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
+  return d->method_;
+}
+
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
+  return &d->input_;
+}
+
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) {
+  return d->stack_size;
+}
+
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) {
+  assert(d->top >= d->stack);
+
+  if (max < (size_t)(d->top - d->stack)) {
+    /* Can't set a limit smaller than what we are currently at. */
+    return false;
+  }
+
+  if (max > d->stack_size) {
+    /* Need to reallocate stack and callstack to accommodate. */
+    size_t old_size = stacksize(d, d->stack_size);
+    size_t new_size = stacksize(d, max);
+    void *p = upb_env_realloc(d->env, d->stack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->stack = p;
+
+    old_size = callstacksize(d, d->stack_size);
+    new_size = callstacksize(d, max);
+    p = upb_env_realloc(d->env, d->callstack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->callstack = p;
+
+    d->stack_size = max;
+  }
+
+  d->limit = d->stack + max - 1;
+  return true;
+}
+/*
+** upb::Encoder
+**
+** Since we are implementing pure handlers (ie. without any out-of-band access
+** to pre-computed lengths), we have to buffer all submessages before we can
+** emit even their first byte.
+**
+** Not knowing the size of submessages also means we can't write a perfect
+** zero-copy implementation, even with buffering.  Lengths are stored as
+** varints, which means that we don't know how many bytes to reserve for the
+** length until we know what the length is.
+**
+** This leaves us with three main choices:
+**
+** 1. buffer all submessage data in a temporary buffer, then copy it exactly
+**    once into the output buffer.
+**
+** 2. attempt to buffer data directly into the output buffer, estimating how
+**    many bytes each length will take.  When our guesses are wrong, use
+**    memmove() to grow or shrink the allotted space.
+**
+** 3. buffer directly into the output buffer, allocating a max length
+**    ahead-of-time for each submessage length.  If we overallocated, we waste
+**    space, but no memcpy() or memmove() is required.  This approach requires
+**    defining a maximum size for submessages and rejecting submessages that
+**    exceed that size.
+**
+** (2) and (3) have the potential to have better performance, but they are more
+** complicated and subtle to implement:
+**
+**   (3) requires making an arbitrary choice of the maximum message size; it
+**       wastes space when submessages are shorter than this and fails
+**       completely when they are longer.  This makes it more finicky and
+**       requires configuration based on the input.  It also makes it impossible
+**       to perfectly match the output of reference encoders that always use the
+**       optimal amount of space for each length.
+**
+**   (2) requires guessing the the size upfront, and if multiple lengths are
+**       guessed wrong the minimum required number of memmove() operations may
+**       be complicated to compute correctly.  Implemented properly, it may have
+**       a useful amortized or average cost, but more investigation is required
+**       to determine this and what the optimal algorithm is to achieve it.
+**
+**   (1) makes you always pay for exactly one copy, but its implementation is
+**       the simplest and its performance is predictable.
+**
+** So for now, we implement (1) only.  If we wish to optimize later, we should
+** be able to do it without affecting users.
+**
+** The strategy is to buffer the segments of data that do *not* depend on
+** unknown lengths in one buffer, and keep a separate buffer of segment pointers
+** and lengths.  When the top-level submessage ends, we can go beginning to end,
+** alternating the writing of lengths with memcpy() of the rest of the data.
+** At the top level though, no buffering is required.
+*/
+
+
+#include <stdlib.h>
+
+/* The output buffer is divided into segments; a segment is a string of data
+ * that is "ready to go" -- it does not need any varint lengths inserted into
+ * the middle.  The seams between segments are where varints will be inserted
+ * once they are known.
+ *
+ * We also use the concept of a "run", which is a range of encoded bytes that
+ * occur at a single submessage level.  Every segment contains one or more runs.
+ *
+ * A segment can span messages.  Consider:
+ *
+ *                  .--Submessage lengths---------.
+ *                  |       |                     |
+ *                  |       V                     V
+ *                  V      | |---------------    | |-----------------
+ * Submessages:    | |-----------------------------------------------
+ * Top-level msg: ------------------------------------------------------------
+ *
+ * Segments:          -----   -------------------   -----------------
+ * Runs:              *----   *--------------*---   *----------------
+ * (* marks the start)
+ *
+ * Note that the top-level menssage is not in any segment because it does not
+ * have any length preceding it.
+ *
+ * A segment is only interrupted when another length needs to be inserted.  So
+ * observe how the second segment spans both the inner submessage and part of
+ * the next enclosing message. */
+typedef struct {
+  uint32_t msglen;  /* The length to varint-encode before this segment. */
+  uint32_t seglen;  /* Length of the segment. */
+} upb_pb_encoder_segment;
+
+struct upb_pb_encoder {
+  upb_env *env;
+
+  /* Our input and output. */
+  upb_sink input_;
+  upb_bytessink *output_;
+
+  /* The "subclosure" -- used as the inner closure as part of the bytessink
+   * protocol. */
+  void *subc;
+
+  /* The output buffer and limit, and our current write position.  "buf"
+   * initially points to "initbuf", but is dynamically allocated if we need to
+   * grow beyond the initial size. */
+  char *buf, *ptr, *limit;
+
+  /* The beginning of the current run, or undefined if we are at the top
+   * level. */
+  char *runbegin;
+
+  /* The list of segments we are accumulating. */
+  upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
+
+  /* The stack of enclosing submessages.  Each entry in the stack points to the
+   * segment where this submessage's length is being accumulated. */
+  int *stack, *top, *stacklimit;
+
+  /* Depth of startmsg/endmsg calls. */
+  int depth;
+};
+
+/* low-level buffering ********************************************************/
+
+/* Low-level functions for interacting with the output buffer. */
+
+/* TODO(haberman): handle pushback */
+static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
+  size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
+  UPB_ASSERT_VAR(n, n == len);
+}
+
+static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
+  return &e->segbuf[*e->top];
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr.  Returns false if the bytes could not be allocated. */
+static bool reserve(upb_pb_encoder *e, size_t bytes) {
+  if ((size_t)(e->limit - e->ptr) < bytes) {
+    /* Grow buffer. */
+    char *new_buf;
+    size_t needed = bytes + (e->ptr - e->buf);
+    size_t old_size = e->limit - e->buf;
+
+    size_t new_size = old_size;
+
+    while (new_size < needed) {
+      new_size *= 2;
+    }
+
+    new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
+
+    if (new_buf == NULL) {
+      return false;
+    }
+
+    e->ptr = new_buf + (e->ptr - e->buf);
+    e->runbegin = new_buf + (e->runbegin - e->buf);
+    e->limit = new_buf + new_size;
+    e->buf = new_buf;
+  }
+
+  return true;
+}
+
+/* Call when "bytes" bytes have been writte at e->ptr.  The caller *must* have
+ * previously called reserve() with at least this many bytes. */
+static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
+  assert((size_t)(e->limit - e->ptr) >= bytes);
+  e->ptr += bytes;
+}
+
+/* Call when all of the bytes for a handler have been written.  Flushes the
+ * bytes if possible and necessary, returning false if this failed. */
+static bool commit(upb_pb_encoder *e) {
+  if (!e->top) {
+    /* We aren't inside a delimited region.  Flush our accumulated bytes to
+     * the output.
+     *
+     * TODO(haberman): in the future we may want to delay flushing for
+     * efficiency reasons. */
+    putbuf(e, e->buf, e->ptr - e->buf);
+    e->ptr = e->buf;
+  }
+
+  return true;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) {
+  if (!reserve(e, len)) {
+    return false;
+  }
+
+  memcpy(e->ptr, data, len);
+  encoder_advance(e, len);
+  return true;
+}
+
+/* Finish the current run by adding the run totals to the segment and message
+ * length. */
+static void accumulate(upb_pb_encoder *e) {
+  size_t run_len;
+  assert(e->ptr >= e->runbegin);
+  run_len = e->ptr - e->runbegin;
+  e->segptr->seglen += run_len;
+  top(e)->msglen += run_len;
+  e->runbegin = e->ptr;
+}
+
+/* Call to indicate the start of delimited region for which the full length is
+ * not yet known.  All data will be buffered until the length is known.
+ * Delimited regions may be nested; their lengths will all be tracked properly. */
+static bool start_delim(upb_pb_encoder *e) {
+  if (e->top) {
+    /* We are already buffering, advance to the next segment and push it on the
+     * stack. */
+    accumulate(e);
+
+    if (++e->top == e->stacklimit) {
+      /* TODO(haberman): grow stack? */
+      return false;
+    }
+
+    if (++e->segptr == e->seglimit) {
+      /* Grow segment buffer. */
+      size_t old_size =
+          (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
+      size_t new_size = old_size * 2;
+      upb_pb_encoder_segment *new_buf =
+          upb_env_realloc(e->env, e->segbuf, old_size, new_size);
+
+      if (new_buf == NULL) {
+        return false;
+      }
+
+      e->segptr = new_buf + (e->segptr - e->segbuf);
+      e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
+      e->segbuf = new_buf;
+    }
+  } else {
+    /* We were previously at the top level, start buffering. */
+    e->segptr = e->segbuf;
+    e->top = e->stack;
+    e->runbegin = e->ptr;
+  }
+
+  *e->top = e->segptr - e->segbuf;
+  e->segptr->seglen = 0;
+  e->segptr->msglen = 0;
+
+  return true;
+}
+
+/* Call to indicate the end of a delimited region.  We now know the length of
+ * the delimited region.  If we are not nested inside any other delimited
+ * regions, we can now emit all of the buffered data we accumulated. */
+static bool end_delim(upb_pb_encoder *e) {
+  size_t msglen;
+  accumulate(e);
+  msglen = top(e)->msglen;
+
+  if (e->top == e->stack) {
+    /* All lengths are now available, emit all buffered data. */
+    char buf[UPB_PB_VARINT_MAX_LEN];
+    upb_pb_encoder_segment *s;
+    const char *ptr = e->buf;
+    for (s = e->segbuf; s <= e->segptr; s++) {
+      size_t lenbytes = upb_vencode64(s->msglen, buf);
+      putbuf(e, buf, lenbytes);
+      putbuf(e, ptr, s->seglen);
+      ptr += s->seglen;
+    }
+
+    e->ptr = e->buf;
+    e->top = NULL;
+  } else {
+    /* Need to keep buffering; propagate length info into enclosing
+     * submessages. */
+    --e->top;
+    top(e)->msglen += msglen + upb_varint_size(msglen);
+  }
+
+  return true;
+}
+
+
+/* tag_t **********************************************************************/
+
+/* A precomputed (pre-encoded) tag and length. */
+
+typedef struct {
+  uint8_t bytes;
+  char tag[7];
+} tag_t;
+
+/* Allocates a new tag for this field, and sets it in these handlerattr. */
+static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
+                    upb_handlerattr *attr) {
+  uint32_t n = upb_fielddef_number(f);
+
+  tag_t *tag = malloc(sizeof(tag_t));
+  tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
+
+  upb_handlerattr_init(attr);
+  upb_handlerattr_sethandlerdata(attr, tag);
+  upb_handlers_addcleanup(h, tag, free);
+}
+
+static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) {
+  return encode_bytes(e, tag->tag, tag->bytes);
+}
+
+
+/* encoding of wire types *****************************************************/
+
+static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+static bool encode_varint(upb_pb_encoder *e, uint64_t val) {
+  if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
+    return false;
+  }
+
+  encoder_advance(e, upb_vencode64(val, e->ptr));
+  return true;
+}
+
+static uint64_t dbl2uint64(double d) {
+  uint64_t ret;
+  memcpy(&ret, &d, sizeof(uint64_t));
+  return ret;
+}
+
+static uint32_t flt2uint32(float d) {
+  uint32_t ret;
+  memcpy(&ret, &d, sizeof(uint32_t));
+  return ret;
+}
+
+
+/* encoding of proto types ****************************************************/
+
+static bool startmsg(void *c, const void *hd) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  if (e->depth++ == 0) {
+    upb_bytessink_start(e->output_, 0, &e->subc);
+  }
+  return true;
+}
+
+static bool endmsg(void *c, const void *hd, upb_status *status) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  if (--e->depth == 0) {
+    upb_bytessink_end(e->output_);
+  }
+  return true;
+}
+
+static void *encode_startdelimfield(void *c, const void *hd) {
+  bool ok = encode_tag(c, hd) && commit(c) && start_delim(c);
+  return ok ? c : UPB_BREAK;
+}
+
+static bool encode_enddelimfield(void *c, const void *hd) {
+  UPB_UNUSED(hd);
+  return end_delim(c);
+}
+
+static void *encode_startgroup(void *c, const void *hd) {
+  return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK;
+}
+
+static bool encode_endgroup(void *c, const void *hd) {
+  return encode_tag(c, hd) && commit(c);
+}
+
+static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
+  UPB_UNUSED(size_hint);
+  return encode_startdelimfield(c, hd);
+}
+
+static size_t encode_strbuf(void *c, const void *hd, const char *buf,
+                            size_t len, const upb_bufhandle *h) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(h);
+  return encode_bytes(c, buf, len) ? len : 0;
+}
+
+#define T(type, ctype, convert, encode)                                  \
+  static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
+    return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e);  \
+  }                                                                      \
+  static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
+    UPB_UNUSED(hd);                                                      \
+    return encode(e, (convert)(val));                                    \
+  }
+
+T(double,   double,   dbl2uint64,   encode_fixed64)
+T(float,    float,    flt2uint32,   encode_fixed32)
+T(int64,    int64_t,  uint64_t,     encode_varint)
+T(int32,    int32_t,  uint32_t,     encode_varint)
+T(fixed64,  uint64_t, uint64_t,     encode_fixed64)
+T(fixed32,  uint32_t, uint32_t,     encode_fixed32)
+T(bool,     bool,     bool,         encode_varint)
+T(uint32,   uint32_t, uint32_t,     encode_varint)
+T(uint64,   uint64_t, uint64_t,     encode_varint)
+T(enum,     int32_t,  uint32_t,     encode_varint)
+T(sfixed32, int32_t,  uint32_t,     encode_fixed32)
+T(sfixed64, int64_t,  uint64_t,     encode_fixed64)
+T(sint32,   int32_t,  upb_zzenc_32, encode_varint)
+T(sint64,   int64_t,  upb_zzenc_64, encode_varint)
+
+#undef T
+
+
+/* code to build the handlers *************************************************/
+
+static void newhandlers_callback(const void *closure, upb_handlers *h) {
+  const upb_msgdef *m;
+  upb_msg_field_iter i;
+
+  UPB_UNUSED(closure);
+
+  upb_handlers_setstartmsg(h, startmsg, NULL);
+  upb_handlers_setendmsg(h, endmsg, NULL);
+
+  m = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
+                  upb_fielddef_packed(f);
+    upb_handlerattr attr;
+    upb_wiretype_t wt =
+        packed ? UPB_WIRE_TYPE_DELIMITED
+               : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+
+    /* Pre-encode the tag for this field. */
+    new_tag(h, f, wt, &attr);
+
+    if (packed) {
+      upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
+      upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
+    }
+
+#define T(upper, lower, upbtype)                                     \
+  case UPB_DESCRIPTOR_TYPE_##upper:                                  \
+    if (packed) {                                                    \
+      upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
+    } else {                                                         \
+      upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
+    }                                                                \
+    break;
+
+    switch (upb_fielddef_descriptortype(f)) {
+      T(DOUBLE,   double,   double);
+      T(FLOAT,    float,    float);
+      T(INT64,    int64,    int64);
+      T(INT32,    int32,    int32);
+      T(FIXED64,  fixed64,  uint64);
+      T(FIXED32,  fixed32,  uint32);
+      T(BOOL,     bool,     bool);
+      T(UINT32,   uint32,   uint32);
+      T(UINT64,   uint64,   uint64);
+      T(ENUM,     enum,     int32);
+      T(SFIXED32, sfixed32, int32);
+      T(SFIXED64, sfixed64, int64);
+      T(SINT32,   sint32,   int32);
+      T(SINT64,   sint64,   int64);
+      case UPB_DESCRIPTOR_TYPE_STRING:
+      case UPB_DESCRIPTOR_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, encode_startstr, &attr);
+        upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
+        upb_handlers_setstring(h, f, encode_strbuf, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_MESSAGE:
+        upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_GROUP: {
+        /* Endgroup takes a different tag (wire_type = END_GROUP). */
+        upb_handlerattr attr2;
+        new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
+
+        upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
+
+        upb_handlerattr_uninit(&attr2);
+        break;
+      }
+    }
+
+#undef T
+
+    upb_handlerattr_uninit(&attr);
+  }
+}
+
+void upb_pb_encoder_reset(upb_pb_encoder *e) {
+  e->segptr = NULL;
+  e->top = NULL;
+  e->depth = 0;
+}
+
+
+/* public API *****************************************************************/
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner) {
+  return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL);
+}
+
+upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h,
+                                      upb_bytessink *output) {
+  const size_t initial_bufsize = 256;
+  const size_t initial_segbufsize = 16;
+  /* TODO(haberman): make this configurable. */
+  const size_t stack_size = 64;
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+
+  upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder));
+  if (!e) return NULL;
+
+  e->buf = upb_env_malloc(env, initial_bufsize);
+  e->segbuf = upb_env_malloc(env, initial_segbufsize * sizeof(*e->segbuf));
+  e->stack = upb_env_malloc(env, stack_size * sizeof(*e->stack));
+
+  if (!e->buf || !e->segbuf || !e->stack) {
+    return NULL;
+  }
+
+  e->limit = e->buf + initial_bufsize;
+  e->seglimit = e->segbuf + initial_segbufsize;
+  e->stacklimit = e->stack + stack_size;
+
+  upb_pb_encoder_reset(e);
+  upb_sink_reset(&e->input_, h, e);
+
+  e->env = env;
+  e->output_ = output;
+  e->subc = output->closure;
+  e->ptr = e->buf;
+
+  /* If this fails, increase the value in encoder.h. */
+  assert(upb_env_bytesallocated(env) - size_before <= UPB_PB_ENCODER_SIZE);
+  return e;
+}
+
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; }
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
+                                        void *owner, upb_status *status) {
+  /* Create handlers. */
+  const upb_pbdecodermethod *decoder_m;
+  const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+  upb_env env;
+  upb_pbdecodermethodopts opts;
+  upb_pbdecoder *decoder;
+  upb_descreader *reader;
+  bool ok;
+  upb_def **ret = NULL;
+  upb_def **defs;
+
+  upb_pbdecodermethodopts_init(&opts, reader_h);
+  decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m);
+
+  upb_env_init(&env);
+  upb_env_reporterrorsto(&env, status);
+
+  reader = upb_descreader_create(&env, reader_h);
+  decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader));
+
+  /* Push input data. */
+  ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(decoder));
+
+  if (!ok) goto cleanup;
+  defs = upb_descreader_getdefs(reader, owner, n);
+  ret = malloc(sizeof(upb_def*) * (*n));
+  memcpy(ret, defs, sizeof(upb_def*) * (*n));
+
+cleanup:
+  upb_env_uninit(&env);
+  upb_handlers_unref(reader_h, &reader_h);
+  upb_pbdecodermethod_unref(decoder_m, &decoder_m);
+  return ret;
+}
+
+bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len,
+                                     upb_status *status) {
+  int n;
+  bool success;
+  upb_def **defs = upb_load_defs_from_descriptor(str, len, &n, &defs, status);
+  if (!defs) return false;
+  success = upb_symtab_add(s, defs, n, &defs, status);
+  free(defs);
+  return success;
+}
+
+char *upb_readfile(const char *filename, size_t *len) {
+  long size;
+  char *buf;
+  FILE *f = fopen(filename, "rb");
+  if(!f) return NULL;
+  if(fseek(f, 0, SEEK_END) != 0) goto error;
+  size = ftell(f);
+  if(size < 0) goto error;
+  if(fseek(f, 0, SEEK_SET) != 0) goto error;
+  buf = malloc(size + 1);
+  if(size && fread(buf, size, 1, f) != 1) goto error;
+  fclose(f);
+  if (len) *len = size;
+  return buf;
+
+error:
+  fclose(f);
+  return NULL;
+}
+
+bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname,
+                                          upb_status *status) {
+  size_t len;
+  bool success;
+  char *data = upb_readfile(fname, &len);
+  if (!data) {
+    if (status) upb_status_seterrf(status, "Couldn't read file: %s", fname);
+    return false;
+  }
+  success = upb_load_descriptor_into_symtab(symtab, data, len, status);
+  free(data);
+  return success;
+}
+/*
+ * upb::pb::TextPrinter
+ *
+ * OPT: This is not optimized at all.  It uses printf() which parses the format
+ * string every time, and it allocates memory for every put.
+ */
+
+
+#include <ctype.h>
+#include <float.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct upb_textprinter {
+  upb_sink input_;
+  upb_bytessink *output_;
+  int indent_depth_;
+  bool single_line_;
+  void *subc;
+};
+
+#define CHECK(x) if ((x) < 0) goto err;
+
+static const char *shortname(const char *longname) {
+  const char *last = strrchr(longname, '.');
+  return last ? last + 1 : longname;
+}
+
+static int indent(upb_textprinter *p) {
+  int i;
+  if (!p->single_line_)
+    for (i = 0; i < p->indent_depth_; i++)
+      upb_bytessink_putbuf(p->output_, p->subc, "  ", 2, NULL);
+  return 0;
+}
+
+static int endfield(upb_textprinter *p) {
+  const char ch = (p->single_line_ ? ' ' : '\n');
+  upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
+  return 0;
+}
+
+static int putescaped(upb_textprinter *p, const char *buf, size_t len,
+                      bool preserve_utf8) {
+  /* Based on CEscapeInternal() from Google's protobuf release. */
+  char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
+  const char *end = buf + len;
+
+  /* I think hex is prettier and more useful, but proto2 uses octal; should
+   * investigate whether it can parse hex also. */
+  const bool use_hex = false;
+  bool last_hex_escape = false; /* true if last output char was \xNN */
+
+  for (; buf < end; buf++) {
+    bool is_hex_escape;
+
+    if (dstend - dst < 4) {
+      upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+      dst = dstbuf;
+    }
+
+    is_hex_escape = false;
+    switch (*buf) {
+      case '\n': *(dst++) = '\\'; *(dst++) = 'n';  break;
+      case '\r': *(dst++) = '\\'; *(dst++) = 'r';  break;
+      case '\t': *(dst++) = '\\'; *(dst++) = 't';  break;
+      case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
+      case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
+      case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
+      default:
+        /* Note that if we emit \xNN and the buf character after that is a hex
+         * digit then that digit must be escaped too to prevent it being
+         * interpreted as part of the character code by C. */
+        if ((!preserve_utf8 || (uint8_t)*buf < 0x80) &&
+            (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) {
+          sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf);
+          is_hex_escape = use_hex;
+          dst += 4;
+        } else {
+          *(dst++) = *buf; break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+  /* Flush remaining data. */
+  upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+  return 0;
+}
+
+bool putf(upb_textprinter *p, const char *fmt, ...) {
+  va_list args;
+  va_list args_copy;
+  char *str;
+  int written;
+  int len;
+  bool ok;
+
+  va_start(args, fmt);
+
+  /* Run once to get the length of the string. */
+  _upb_va_copy(args_copy, args);
+  len = _upb_vsnprintf(NULL, 0, fmt, args_copy);
+  va_end(args_copy);
+
+  /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */
+  str = malloc(len + 1);
+  if (!str) return false;
+  written = vsprintf(str, fmt, args);
+  va_end(args);
+  UPB_ASSERT_VAR(written, written == len);
+
+  ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+  free(str);
+  return ok;
+}
+
+
+/* handlers *******************************************************************/
+
+static bool textprinter_startmsg(void *c, const void *hd) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc);
+  }
+  return true;
+}
+
+static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(s);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+#define TYPE(name, ctype, fmt) \
+  static bool textprinter_put ## name(void *closure, const void *handler_data, \
+                                      ctype val) {                             \
+    upb_textprinter *p = closure;                                              \
+    const upb_fielddef *f = handler_data;                                      \
+    CHECK(indent(p));                                                          \
+    putf(p, "%s: " fmt, upb_fielddef_name(f), val);                            \
+    CHECK(endfield(p));                                                        \
+    return true;                                                               \
+  err:                                                                         \
+    return false;                                                              \
+}
+
+static bool textprinter_putbool(void *closure, const void *handler_data,
+                                bool val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+#define STRINGIFY_HELPER(x) #x
+#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x)
+
+TYPE(int32,  int32_t,  "%" PRId32)
+TYPE(int64,  int64_t,  "%" PRId64)
+TYPE(uint32, uint32_t, "%" PRIu32)
+TYPE(uint64, uint64_t, "%" PRIu64)
+TYPE(float,  float,    "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
+TYPE(double, double,   "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
+
+#undef TYPE
+
+/* Output a symbolic value from the enum if found, else just print as int32. */
+static bool textprinter_putenum(void *closure, const void *handler_data,
+                                int32_t val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
+  const char *label = upb_enumdef_iton(enum_def, val);
+  if (label) {
+    indent(p);
+    putf(p, "%s: %s", upb_fielddef_name(f), label);
+    endfield(p);
+  } else {
+    if (!textprinter_putint32(closure, handler_data, val))
+      return false;
+  }
+  return true;
+}
+
+static void *textprinter_startstr(void *closure, const void *handler_data,
+                      size_t size_hint) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  UPB_UNUSED(size_hint);
+  indent(p);
+  putf(p, "%s: \"", upb_fielddef_name(f));
+  return p;
+}
+
+static bool textprinter_endstr(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  putf(p, "\"");
+  endfield(p);
+  return true;
+}
+
+static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
+                                 size_t len, const upb_bufhandle *handle) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = hd;
+  UPB_UNUSED(handle);
+  CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
+  return len;
+err:
+  return 0;
+}
+
+static void *textprinter_startsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  const char *name = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
+  p->indent_depth_++;
+  return p;
+err:
+  return UPB_BREAK;
+}
+
+static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  p->indent_depth_--;
+  CHECK(indent(p));
+  upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+static void onmreg(const void *c, upb_handlers *h) {
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+  upb_msg_field_iter i;
+  UPB_UNUSED(c);
+
+  upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
+  upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
+
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&attr, f);
+    switch (upb_fielddef_type(f)) {
+      case UPB_TYPE_INT32:
+        upb_handlers_setint32(h, f, textprinter_putint32, &attr);
+        break;
+      case UPB_TYPE_INT64:
+        upb_handlers_setint64(h, f, textprinter_putint64, &attr);
+        break;
+      case UPB_TYPE_UINT32:
+        upb_handlers_setuint32(h, f, textprinter_putuint32, &attr);
+        break;
+      case UPB_TYPE_UINT64:
+        upb_handlers_setuint64(h, f, textprinter_putuint64, &attr);
+        break;
+      case UPB_TYPE_FLOAT:
+        upb_handlers_setfloat(h, f, textprinter_putfloat, &attr);
+        break;
+      case UPB_TYPE_DOUBLE:
+        upb_handlers_setdouble(h, f, textprinter_putdouble, &attr);
+        break;
+      case UPB_TYPE_BOOL:
+        upb_handlers_setbool(h, f, textprinter_putbool, &attr);
+        break;
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, textprinter_startstr, &attr);
+        upb_handlers_setstring(h, f, textprinter_putstr, &attr);
+        upb_handlers_setendstr(h, f, textprinter_endstr, &attr);
+        break;
+      case UPB_TYPE_MESSAGE: {
+        const char *name =
+            upb_fielddef_istagdelim(f)
+                ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
+                : upb_fielddef_name(f);
+        upb_handlerattr_sethandlerdata(&attr, name);
+        upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr);
+        upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr);
+        break;
+      }
+      case UPB_TYPE_ENUM:
+        upb_handlers_setint32(h, f, textprinter_putenum, &attr);
+        break;
+    }
+  }
+}
+
+static void textprinter_reset(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+  p->indent_depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output) {
+  upb_textprinter *p = upb_env_malloc(env, sizeof(upb_textprinter));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  upb_sink_reset(&p->input_, h, p);
+  textprinter_reset(p, false);
+
+  return p;
+}
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner) {
+  return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
+}
+
+upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
+
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+}
+
+
+/* Index is descriptor type. */
+const uint8_t upb_pb_native_wire_types[] = {
+  UPB_WIRE_TYPE_END_GROUP,     /* ENDGROUP */
+  UPB_WIRE_TYPE_64BIT,         /* DOUBLE */
+  UPB_WIRE_TYPE_32BIT,         /* FLOAT */
+  UPB_WIRE_TYPE_VARINT,        /* INT64 */
+  UPB_WIRE_TYPE_VARINT,        /* UINT64 */
+  UPB_WIRE_TYPE_VARINT,        /* INT32 */
+  UPB_WIRE_TYPE_64BIT,         /* FIXED64 */
+  UPB_WIRE_TYPE_32BIT,         /* FIXED32 */
+  UPB_WIRE_TYPE_VARINT,        /* BOOL */
+  UPB_WIRE_TYPE_DELIMITED,     /* STRING */
+  UPB_WIRE_TYPE_START_GROUP,   /* GROUP */
+  UPB_WIRE_TYPE_DELIMITED,     /* MESSAGE */
+  UPB_WIRE_TYPE_DELIMITED,     /* BYTES */
+  UPB_WIRE_TYPE_VARINT,        /* UINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* ENUM */
+  UPB_WIRE_TYPE_32BIT,         /* SFIXED32 */
+  UPB_WIRE_TYPE_64BIT,         /* SFIXED64 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT64 */
+};
+
+/* A basic branch-based decoder, uses 32-bit values to get good performance
+ * on 32-bit architectures (but performs well on 64-bits also).
+ * This scheme comes from the original Google Protobuf implementation
+ * (proto2). */
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) {
+  upb_decoderet err = {NULL, 0};
+  const char *p = r.p;
+  uint32_t low = (uint32_t)r.val;
+  uint32_t high = 0;
+  uint32_t b;
+  b = *(p++); low  |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 28;
+              high  = (b & 0x7fU) >>  4; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) <<  3; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = ((uint64_t)high << 32) | low;
+  r.p = p;
+  return r;
+}
+
+/* Like the previous, but uses 64-bit values. */
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) {
+  const char *p = r.p;
+  uint64_t val = r.val;
+  uint64_t b;
+  upb_decoderet err = {NULL, 0};
+  b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = val;
+  r.p = p;
+  return r;
+}
+
+/* Given an encoded varint v, returns an integer with a single bit set that
+ * indicates the end of the varint.  Subtracting one from this value will
+ * yield a mask that leaves only bits that are part of the varint.  Returns
+ * 0 if the varint is unterminated. */
+static uint64_t upb_get_vstopbit(uint64_t v) {
+  uint64_t cbits = v | 0x7f7f7f7f7f7f7f7fULL;
+  return ~cbits & (cbits+1);
+}
+
+/* A branchless decoder.  Credit to Pascal Massimino for the bit-twiddling. */
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r) {
+  uint64_t b;
+  uint64_t stop_bit;
+  upb_decoderet my_r;
+  memcpy(&b, r.p, sizeof(b));
+  stop_bit = upb_get_vstopbit(b);
+  b =  (b & 0x7f7f7f7f7f7f7f7fULL) & (stop_bit - 1);
+  b +=       b & 0x007f007f007f007fULL;
+  b +=  3 * (b & 0x0000ffff0000ffffULL);
+  b += 15 * (b & 0x00000000ffffffffULL);
+  if (stop_bit == 0) {
+    /* Error: unterminated varint. */
+    upb_decoderet err_r = {(void*)0, 0};
+    return err_r;
+  }
+  my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+                            r.val | (b << 7));
+  return my_r;
+}
+
+/* A branchless decoder.  Credit to Daniel Wright for the bit-twiddling. */
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) {
+  uint64_t b;
+  uint64_t stop_bit;
+  upb_decoderet my_r;
+  memcpy(&b, r.p, sizeof(b));
+  stop_bit = upb_get_vstopbit(b);
+  b &= (stop_bit - 1);
+  b = ((b & 0x7f007f007f007f00ULL) >> 1) | (b & 0x007f007f007f007fULL);
+  b = ((b & 0xffff0000ffff0000ULL) >> 2) | (b & 0x0000ffff0000ffffULL);
+  b = ((b & 0xffffffff00000000ULL) >> 4) | (b & 0x00000000ffffffffULL);
+  if (stop_bit == 0) {
+    /* Error: unterminated varint. */
+    upb_decoderet err_r = {(void*)0, 0};
+    return err_r;
+  }
+  my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+                            r.val | (b << 14));
+  return my_r;
+}
+
+#line 1 "upb/json/parser.rl"
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** A parser that uses the Ragel State Machine Compiler to generate
+** the finite automata.
+**
+** Ragel only natively handles regular languages, but we can manually
+** program it a bit to handle context-free languages like JSON, by using
+** the "fcall" and "fret" constructs.
+**
+** This parser can handle the basics, but needs several things to be fleshed
+** out:
+**
+** - handling of unicode escape sequences (including high surrogate pairs).
+** - properly check and report errors for unknown fields, stack overflow,
+**   improper array nesting (or lack of nesting).
+** - handling of base64 sequences with padding characters.
+** - handling of push-back (non-success returns from sink functions).
+** - handling of keys/escape-sequences/etc that span input buffers.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+#define UPB_JSON_MAX_DEPTH 64
+
+typedef struct {
+  upb_sink sink;
+
+  /* The current message in which we're parsing, and the field whose value we're
+   * expecting next. */
+  const upb_msgdef *m;
+  const upb_fielddef *f;
+
+  /* We are in a repeated-field context, ready to emit mapentries as
+   * submessages. This flag alters the start-of-object (open-brace) behavior to
+   * begin a sequence of mapentry messages rather than a single submessage. */
+  bool is_map;
+
+  /* We are in a map-entry message context. This flag is set when parsing the
+   * value field of a single map entry and indicates to all value-field parsers
+   * (subobjects, strings, numbers, and bools) that the map-entry submessage
+   * should end as soon as the value is parsed. */
+  bool is_mapentry;
+
+  /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent
+   * message's map field that we're currently parsing. This differs from |f|
+   * because |f| is the field in the *current* message (i.e., the map-entry
+   * message itself), not the parent's field that leads to this map. */
+  const upb_fielddef *mapfield;
+} upb_jsonparser_frame;
+
+struct upb_json_parser {
+  upb_env *env;
+  upb_byteshandler input_handler_;
+  upb_bytessink input_;
+
+  /* Stack to track the JSON scopes we are in. */
+  upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH];
+  upb_jsonparser_frame *top;
+  upb_jsonparser_frame *limit;
+
+  upb_status status;
+
+  /* Ragel's internal parsing stack for the parsing state machine. */
+  int current_state;
+  int parser_stack[UPB_JSON_MAX_DEPTH];
+  int parser_top;
+
+  /* The handle for the current buffer. */
+  const upb_bufhandle *handle;
+
+  /* Accumulate buffer.  See details in parser.rl. */
+  const char *accumulated;
+  size_t accumulated_len;
+  char *accumulate_buf;
+  size_t accumulate_buf_size;
+
+  /* Multi-part text data.  See details in parser.rl. */
+  int multipart_state;
+  upb_selector_t string_selector;
+
+  /* Input capture.  See details in parser.rl. */
+  const char *capture;
+
+  /* Intermediate result of parsing a unicode escape sequence. */
+  uint32_t digit;
+};
+
+#define PARSER_CHECK_RETURN(x) if (!(x)) return false
+
+/* Used to signal that a capture has been suspended. */
+static char suspend_capture;
+
+static upb_selector_t getsel_for_handlertype(upb_json_parser *p,
+                                             upb_handlertype_t type) {
+  upb_selector_t sel;
+  bool ok = upb_handlers_getselector(p->top->f, type, &sel);
+  UPB_ASSERT_VAR(ok, ok);
+  return sel;
+}
+
+static upb_selector_t parser_getsel(upb_json_parser *p) {
+  return getsel_for_handlertype(
+      p, upb_handlers_getprimitivehandlertype(p->top->f));
+}
+
+static bool check_stack(upb_json_parser *p) {
+  if ((p->top + 1) == p->limit) {
+    upb_status_seterrmsg(&p->status, "Nesting too deep");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+/* There are GCC/Clang built-ins for overflow checking which we could start
+ * using if there was any performance benefit to it. */
+
+static bool checked_add(size_t a, size_t b, size_t *c) {
+  if (SIZE_MAX - a < b) return false;
+  *c = a + b;
+  return true;
+}
+
+static size_t saturating_multiply(size_t a, size_t b) {
+  /* size_t is unsigned, so this is defined behavior even on overflow. */
+  size_t ret = a * b;
+  if (b != 0 && ret / b != a) {
+    ret = SIZE_MAX;
+  }
+  return ret;
+}
+
+
+/* Base64 decoding ************************************************************/
+
+/* TODO(haberman): make this streaming. */
+
+static const signed char b64table[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+  07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+/* Returns the table value sign-extended to 32 bits.  Knowing that the upper
+ * bits will be 1 for unrecognized characters makes it easier to check for
+ * this error condition later (see below). */
+int32_t b64lookup(unsigned char ch) { return b64table[ch]; }
+
+/* Returns true if the given character is not a valid base64 character or
+ * padding. */
+bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; }
+
+static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr,
+                        size_t len) {
+  const char *limit = ptr + len;
+  for (; ptr < limit; ptr += 4) {
+    uint32_t val;
+    char output[3];
+
+    if (limit - ptr < 4) {
+      upb_status_seterrf(&p->status,
+                         "Base64 input for bytes field not a multiple of 4: %s",
+                         upb_fielddef_name(p->top->f));
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6  |
+          b64lookup(ptr[3]);
+
+    /* Test the upper bit; returns true if any of the characters returned -1. */
+    if (val & 0x80000000) {
+      goto otherchar;
+    }
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    output[2] = val & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 3, NULL);
+  }
+  return true;
+
+otherchar:
+  if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) ||
+      nonbase64(ptr[3]) ) {
+    upb_status_seterrf(&p->status,
+                       "Non-base64 characters in bytes field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  } if (ptr[2] == '=') {
+    uint32_t val;
+    char output;
+
+    /* Last group contains only two input bytes, one output byte. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12;
+
+    assert(!(val & 0x80000000));
+    output = val >> 16;
+    upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL);
+    return true;
+  } else {
+    uint32_t val;
+    char output[2];
+
+    /* Last group contains only three input bytes, two output bytes. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6;
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 2, NULL);
+    return true;
+  }
+
+badpadding:
+  upb_status_seterrf(&p->status,
+                     "Incorrect base64 padding for field: %s (%.*s)",
+                     upb_fielddef_name(p->top->f),
+                     4, ptr);
+  upb_env_reporterror(p->env, &p->status);
+  return false;
+}
+
+
+/* Accumulate buffer **********************************************************/
+
+/* Functionality for accumulating a buffer.
+ *
+ * Some parts of the parser need an entire value as a contiguous string.  For
+ * example, to look up a member name in a hash table, or to turn a string into
+ * a number, the relevant library routines need the input string to be in
+ * contiguous memory, even if the value spanned two or more buffers in the
+ * input.  These routines handle that.
+ *
+ * In the common case we can just point to the input buffer to get this
+ * contiguous string and avoid any actual copy.  So we optimistically begin
+ * this way.  But there are a few cases where we must instead copy into a
+ * separate buffer:
+ *
+ *   1. The string was not contiguous in the input (it spanned buffers).
+ *
+ *   2. The string included escape sequences that need to be interpreted to get
+ *      the true value in a contiguous buffer. */
+
+static void assert_accumulate_empty(upb_json_parser *p) {
+  UPB_UNUSED(p);
+  assert(p->accumulated == NULL);
+  assert(p->accumulated_len == 0);
+}
+
+static void accumulate_clear(upb_json_parser *p) {
+  p->accumulated = NULL;
+  p->accumulated_len = 0;
+}
+
+/* Used internally by accumulate_append(). */
+static bool accumulate_realloc(upb_json_parser *p, size_t need) {
+  void *mem;
+  size_t old_size = p->accumulate_buf_size;
+  size_t new_size = UPB_MAX(old_size, 128);
+  while (new_size < need) {
+    new_size = saturating_multiply(new_size, 2);
+  }
+
+  mem = upb_env_realloc(p->env, p->accumulate_buf, old_size, new_size);
+  if (!mem) {
+    upb_status_seterrmsg(&p->status, "Out of memory allocating buffer.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  p->accumulate_buf = mem;
+  p->accumulate_buf_size = new_size;
+  return true;
+}
+
+/* Logically appends the given data to the append buffer.
+ * If "can_alias" is true, we will try to avoid actually copying, but the buffer
+ * must be valid until the next accumulate_append() call (if any). */
+static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len,
+                              bool can_alias) {
+  size_t need;
+
+  if (!p->accumulated && can_alias) {
+    p->accumulated = buf;
+    p->accumulated_len = len;
+    return true;
+  }
+
+  if (!checked_add(p->accumulated_len, len, &need)) {
+    upb_status_seterrmsg(&p->status, "Integer overflow.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) {
+    return false;
+  }
+
+  if (p->accumulated != p->accumulate_buf) {
+    memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len);
+    p->accumulated = p->accumulate_buf;
+  }
+
+  memcpy(p->accumulate_buf + p->accumulated_len, buf, len);
+  p->accumulated_len += len;
+  return true;
+}
+
+/* Returns a pointer to the data accumulated since the last accumulate_clear()
+ * call, and writes the length to *len.  This with point either to the input
+ * buffer or a temporary accumulate buffer. */
+static const char *accumulate_getptr(upb_json_parser *p, size_t *len) {
+  assert(p->accumulated);
+  *len = p->accumulated_len;
+  return p->accumulated;
+}
+
+
+/* Mult-part text data ********************************************************/
+
+/* When we have text data in the input, it can often come in multiple segments.
+ * For example, there may be some raw string data followed by an escape
+ * sequence.  The two segments are processed with different logic.  Also buffer
+ * seams in the input can cause multiple segments.
+ *
+ * As we see segments, there are two main cases for how we want to process them:
+ *
+ *  1. we want to push the captured input directly to string handlers.
+ *
+ *  2. we need to accumulate all the parts into a contiguous buffer for further
+ *     processing (field name lookup, string->number conversion, etc). */
+
+/* This is the set of states for p->multipart_state. */
+enum {
+  /* We are not currently processing multipart data. */
+  MULTIPART_INACTIVE = 0,
+
+  /* We are processing multipart data by accumulating it into a contiguous
+   * buffer. */
+  MULTIPART_ACCUMULATE = 1,
+
+  /* We are processing multipart data by pushing each part directly to the
+   * current string handlers. */
+  MULTIPART_PUSHEAGERLY = 2
+};
+
+/* Start a multi-part text value where we accumulate the data for processing at
+ * the end. */
+static void multipart_startaccum(upb_json_parser *p) {
+  assert_accumulate_empty(p);
+  assert(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_ACCUMULATE;
+}
+
+/* Start a multi-part text value where we immediately push text data to a string
+ * value with the given selector. */
+static void multipart_start(upb_json_parser *p, upb_selector_t sel) {
+  assert_accumulate_empty(p);
+  assert(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_PUSHEAGERLY;
+  p->string_selector = sel;
+}
+
+static bool multipart_text(upb_json_parser *p, const char *buf, size_t len,
+                           bool can_alias) {
+  switch (p->multipart_state) {
+    case MULTIPART_INACTIVE:
+      upb_status_seterrmsg(
+          &p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+
+    case MULTIPART_ACCUMULATE:
+      if (!accumulate_append(p, buf, len, can_alias)) {
+        return false;
+      }
+      break;
+
+    case MULTIPART_PUSHEAGERLY: {
+      const upb_bufhandle *handle = can_alias ? p->handle : NULL;
+      upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle);
+      break;
+    }
+  }
+
+  return true;
+}
+
+/* Note: this invalidates the accumulate buffer!  Call only after reading its
+ * contents. */
+static void multipart_end(upb_json_parser *p) {
+  assert(p->multipart_state != MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_INACTIVE;
+  accumulate_clear(p);
+}
+
+
+/* Input capture **************************************************************/
+
+/* Functionality for capturing a region of the input as text.  Gracefully
+ * handles the case where a buffer seam occurs in the middle of the captured
+ * region. */
+
+static void capture_begin(upb_json_parser *p, const char *ptr) {
+  assert(p->multipart_state != MULTIPART_INACTIVE);
+  assert(p->capture == NULL);
+  p->capture = ptr;
+}
+
+static bool capture_end(upb_json_parser *p, const char *ptr) {
+  assert(p->capture);
+  if (multipart_text(p, p->capture, ptr - p->capture, true)) {
+    p->capture = NULL;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* This is called at the end of each input buffer (ie. when we have hit a
+ * buffer seam).  If we are in the middle of capturing the input, this
+ * processes the unprocessed capture region. */
+static void capture_suspend(upb_json_parser *p, const char **ptr) {
+  if (!p->capture) return;
+
+  if (multipart_text(p, p->capture, *ptr - p->capture, false)) {
+    /* We use this as a signal that we were in the middle of capturing, and
+     * that capturing should resume at the beginning of the next buffer.
+     * 
+     * We can't use *ptr here, because we have no guarantee that this pointer
+     * will be valid when we resume (if the underlying memory is freed, then
+     * using the pointer at all, even to compare to NULL, is likely undefined
+     * behavior). */
+    p->capture = &suspend_capture;
+  } else {
+    /* Need to back up the pointer to the beginning of the capture, since
+     * we were not able to actually preserve it. */
+    *ptr = p->capture;
+  }
+}
+
+static void capture_resume(upb_json_parser *p, const char *ptr) {
+  if (p->capture) {
+    assert(p->capture == &suspend_capture);
+    p->capture = ptr;
+  }
+}
+
+
+/* Callbacks from the parser **************************************************/
+
+/* These are the functions called directly from the parser itself.
+ * We define these in the same order as their declarations in the parser. */
+
+static char escape_char(char in) {
+  switch (in) {
+    case 'r': return '\r';
+    case 't': return '\t';
+    case 'n': return '\n';
+    case 'f': return '\f';
+    case 'b': return '\b';
+    case '/': return '/';
+    case '"': return '"';
+    case '\\': return '\\';
+    default:
+      assert(0);
+      return 'x';
+  }
+}
+
+static bool escape(upb_json_parser *p, const char *ptr) {
+  char ch = escape_char(*ptr);
+  return multipart_text(p, &ch, 1, false);
+}
+
+static void start_hex(upb_json_parser *p) {
+  p->digit = 0;
+}
+
+static void hexdigit(upb_json_parser *p, const char *ptr) {
+  char ch = *ptr;
+
+  p->digit <<= 4;
+
+  if (ch >= '0' && ch <= '9') {
+    p->digit += (ch - '0');
+  } else if (ch >= 'a' && ch <= 'f') {
+    p->digit += ((ch - 'a') + 10);
+  } else {
+    assert(ch >= 'A' && ch <= 'F');
+    p->digit += ((ch - 'A') + 10);
+  }
+}
+
+static bool end_hex(upb_json_parser *p) {
+  uint32_t codepoint = p->digit;
+
+  /* emit the codepoint as UTF-8. */
+  char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */
+  int length = 0;
+  if (codepoint <= 0x7F) {
+    utf8[0] = codepoint;
+    length = 1;
+  } else if (codepoint <= 0x07FF) {
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x1F) | 0xC0;
+    length = 2;
+  } else /* codepoint <= 0xFFFF */ {
+    utf8[2] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x0F) | 0xE0;
+    length = 3;
+  }
+  /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate
+   * we have to wait for the next escape to get the full code point). */
+
+  return multipart_text(p, utf8, length, false);
+}
+
+static void start_text(upb_json_parser *p, const char *ptr) {
+  capture_begin(p, ptr);
+}
+
+static bool end_text(upb_json_parser *p, const char *ptr) {
+  return capture_end(p, ptr);
+}
+
+static void start_number(upb_json_parser *p, const char *ptr) {
+  multipart_startaccum(p);
+  capture_begin(p, ptr);
+}
+
+static bool parse_number(upb_json_parser *p);
+
+static bool end_number(upb_json_parser *p, const char *ptr) {
+  if (!capture_end(p, ptr)) {
+    return false;
+  }
+
+  return parse_number(p);
+}
+
+static bool parse_number(upb_json_parser *p) {
+  size_t len;
+  const char *buf;
+  const char *myend;
+  char *end;
+
+  /* strtol() and friends unfortunately do not support specifying the length of
+   * the input string, so we need to force a copy into a NULL-terminated buffer. */
+  if (!multipart_text(p, "\0", 1, false)) {
+    return false;
+  }
+
+  buf = accumulate_getptr(p, &len);
+  myend = buf + len - 1;  /* One for NULL. */
+
+  /* XXX: We are using strtol to parse integers, but this is wrong as even
+   * integers can be represented as 1e6 (for example), which strtol can't
+   * handle correctly.
+   *
+   * XXX: Also, we can't handle large integers properly because strto[u]ll
+   * isn't in C89.
+   *
+   * XXX: Also, we don't properly check floats for overflow, since strtof
+   * isn't in C89. */
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32: {
+      long val = strtol(p->accumulated, &end, 0);
+      if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_INT64: {
+      long long val = strtol(p->accumulated, &end, 0);
+      if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(p->accumulated, &end, 0);
+      if (val > UINT32_MAX || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_UINT64: {
+      unsigned long long val = strtoul(p->accumulated, &end, 0);
+      if (val > UINT64_MAX || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_DOUBLE: {
+      double val = strtod(p->accumulated, &end);
+      if (errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_FLOAT: {
+      float val = strtod(p->accumulated, &end);
+      if (errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    default:
+      assert(false);
+  }
+
+  multipart_end(p);
+
+  return true;
+
+err:
+  upb_status_seterrf(&p->status, "error parsing number: %s", buf);
+  upb_env_reporterror(p->env, &p->status);
+  multipart_end(p);
+  return false;
+}
+
+static bool parser_putbool(upb_json_parser *p, bool val) {
+  bool ok;
+
+  if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
+    upb_status_seterrf(&p->status,
+                       "Boolean value specified for non-bool field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
+  UPB_ASSERT_VAR(ok, ok);
+
+  return true;
+}
+
+static bool start_stringval(upb_json_parser *p) {
+  assert(p->top->f);
+
+  if (upb_fielddef_isstring(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    if (!check_stack(p)) return false;
+
+    /* Start a new parser frame: parser frames correspond one-to-one with
+     * handler frames, and string events occur in a sub-frame. */
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+    upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink);
+    inner->m = p->top->m;
+    inner->f = p->top->f;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) {
+      /* For STRING fields we push data directly to the handlers as it is
+       * parsed.  We don't do this yet for BYTES fields, because our base64
+       * decoder is not streaming.
+       *
+       * TODO(haberman): make base64 decoding streaming also. */
+      multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING));
+      return true;
+    } else {
+      multipart_startaccum(p);
+      return true;
+    }
+  } else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) {
+    /* No need to push a frame -- symbolic enum names in quotes remain in the
+     * current parser frame.
+     *
+     * Enum string values must accumulate so we can look up the value in a table
+     * once it is complete. */
+    multipart_startaccum(p);
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "String specified for non-string/non-enum field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static bool end_stringval(upb_json_parser *p) {
+  bool ok = true;
+
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_BYTES:
+      if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
+                       p->accumulated, p->accumulated_len)) {
+        return false;
+      }
+      /* Fall through. */
+
+    case UPB_TYPE_STRING: {
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      upb_sink_endstr(&p->top->sink, sel);
+      p->top--;
+      break;
+    }
+
+    case UPB_TYPE_ENUM: {
+      /* Resolve enum symbolic name to integer value. */
+      const upb_enumdef *enumdef =
+          (const upb_enumdef*)upb_fielddef_subdef(p->top->f);
+
+      size_t len;
+      const char *buf = accumulate_getptr(p, &len);
+
+      int32_t int_val = 0;
+      ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val);
+
+      if (ok) {
+        upb_selector_t sel = parser_getsel(p);
+        upb_sink_putint32(&p->top->sink, sel, int_val);
+      } else {
+        upb_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf);
+        upb_env_reporterror(p->env, &p->status);
+      }
+
+      break;
+    }
+
+    default:
+      assert(false);
+      upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
+      upb_env_reporterror(p->env, &p->status);
+      ok = false;
+      break;
+  }
+
+  multipart_end(p);
+
+  return ok;
+}
+
+static void start_member(upb_json_parser *p) {
+  assert(!p->top->f);
+  multipart_startaccum(p);
+}
+
+/* Helper: invoked during parse_mapentry() to emit the mapentry message's key
+ * field based on the current contents of the accumulate buffer. */
+static bool parse_mapentry_key(upb_json_parser *p) {
+
+  size_t len;
+  const char *buf = accumulate_getptr(p, &len);
+
+  /* Emit the key field. We do a bit of ad-hoc parsing here because the
+   * parser state machine has already decided that this is a string field
+   * name, and we are reinterpreting it as some arbitrary key type. In
+   * particular, integer and bool keys are quoted, so we need to parse the
+   * quoted string contents here. */
+
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY);
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no key");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      /* Invoke end_number. The accum buffer has the number's text already. */
+      if (!parse_number(p)) {
+        return false;
+      }
+      break;
+    case UPB_TYPE_BOOL:
+      if (len == 4 && !strncmp(buf, "true", 4)) {
+        if (!parser_putbool(p, true)) {
+          return false;
+        }
+      } else if (len == 5 && !strncmp(buf, "false", 5)) {
+        if (!parser_putbool(p, false)) {
+          return false;
+        }
+      } else {
+        upb_status_seterrmsg(&p->status,
+                             "Map bool key not 'true' or 'false'");
+        upb_env_reporterror(p->env, &p->status);
+        return false;
+      }
+      multipart_end(p);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      upb_sink subsink;
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+      upb_sink_startstr(&p->top->sink, sel, len, &subsink);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_STRING);
+      upb_sink_putstring(&subsink, sel, buf, len, NULL);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      upb_sink_endstr(&subsink, sel);
+      multipart_end(p);
+      break;
+    }
+    default:
+      upb_status_seterrmsg(&p->status, "Invalid field type for map key");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+  }
+
+  return true;
+}
+
+/* Helper: emit one map entry (as a submessage in the map field sequence). This
+ * is invoked from end_membername(), at the end of the map entry's key string,
+ * with the map key in the accumulate buffer. It parses the key from that
+ * buffer, emits the handler calls to start the mapentry submessage (setting up
+ * its subframe in the process), and sets up state in the subframe so that the
+ * value parser (invoked next) will emit the mapentry's value field and then
+ * end the mapentry message. */
+
+static bool handle_mapentry(upb_json_parser *p) {
+  const upb_fielddef *mapfield;
+  const upb_msgdef *mapentrymsg;
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  /* Map entry: p->top->sink is the seq frame, so we need to start a frame
+   * for the mapentry itself, and then set |f| in that frame so that the map
+   * value field is parsed, and also set a flag to end the frame after the
+   * map-entry value is parsed. */
+  if (!check_stack(p)) return false;
+
+  mapfield = p->top->mapfield;
+  mapentrymsg = upb_fielddef_msgsubdef(mapfield);
+
+  inner = p->top + 1;
+  p->top->f = mapfield;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+  upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+  inner->m = mapentrymsg;
+  inner->mapfield = mapfield;
+  inner->is_map = false;
+
+  /* Don't set this to true *yet* -- we reuse parsing handlers below to push
+   * the key field value to the sink, and these handlers will pop the frame
+   * if they see is_mapentry (when invoked by the parser state machine, they
+   * would have just seen the map-entry value, not key). */
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  /* send STARTMSG in submsg frame. */
+  upb_sink_startmsg(&p->top->sink);
+
+  parse_mapentry_key(p);
+
+  /* Set up the value field to receive the map-entry value. */
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE);
+  p->top->is_mapentry = true;  /* set up to pop frame after value is parsed. */
+  p->top->mapfield = mapfield;
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no value");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+static bool end_membername(upb_json_parser *p) {
+  assert(!p->top->f);
+
+  if (p->top->is_map) {
+    return handle_mapentry(p);
+  } else {
+    size_t len;
+    const char *buf = accumulate_getptr(p, &len);
+    const upb_fielddef *f = upb_msgdef_ntof(p->top->m, buf, len);
+
+    if (!f) {
+      /* TODO(haberman): Ignore unknown fields if requested/configured to do
+       * so. */
+      upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+
+    p->top->f = f;
+    multipart_end(p);
+
+    return true;
+  }
+}
+
+static void end_member(upb_json_parser *p) {
+  /* If we just parsed a map-entry value, end that frame too. */
+  if (p->top->is_mapentry) {
+    upb_status s = UPB_STATUS_INIT;
+    upb_selector_t sel;
+    bool ok;
+    const upb_fielddef *mapfield;
+
+    assert(p->top > p->stack);
+    /* send ENDMSG on submsg. */
+    upb_sink_endmsg(&p->top->sink, &s);
+    mapfield = p->top->mapfield;
+
+    /* send ENDSUBMSG in repeated-field-of-mapentries frame. */
+    p->top--;
+    ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel);
+    UPB_ASSERT_VAR(ok, ok);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+
+  p->top->f = NULL;
+}
+
+static bool start_subobject(upb_json_parser *p) {
+  assert(p->top->f);
+
+  if (upb_fielddef_ismap(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a map. Start a new parser frame in a repeated-field
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+    upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    inner->mapfield = p->top->f;
+    inner->f = NULL;
+    inner->is_map = true;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else if (upb_fielddef_issubmsg(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a subobject. Start a new parser frame in the submsg
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+    upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    inner->f = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "Object specified for non-message/group field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static void end_subobject(upb_json_parser *p) {
+  if (p->top->is_map) {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+    upb_sink_endseq(&p->top->sink, sel);
+  } else {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+}
+
+static bool start_array(upb_json_parser *p) {
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  assert(p->top->f);
+
+  if (!upb_fielddef_isseq(p->top->f)) {
+    upb_status_seterrf(&p->status,
+                       "Array specified for non-repeated field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (!check_stack(p)) return false;
+
+  inner = p->top + 1;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+  upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+  inner->m = p->top->m;
+  inner->f = p->top->f;
+  inner->is_map = false;
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  return true;
+}
+
+static void end_array(upb_json_parser *p) {
+  upb_selector_t sel;
+
+  assert(p->top > p->stack);
+
+  p->top--;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+  upb_sink_endseq(&p->top->sink, sel);
+}
+
+static void start_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_sink_startmsg(&p->top->sink);
+  }
+}
+
+static void end_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_status status;
+    upb_status_clear(&status);
+    upb_sink_endmsg(&p->top->sink, &status);
+    if (!upb_ok(&status)) {
+      upb_env_reporterror(p->env, &status);
+    }
+  }
+}
+
+
+#define CHECK_RETURN_TOP(x) if (!(x)) goto error
+
+
+/* The actual parser **********************************************************/
+
+/* What follows is the Ragel parser itself.  The language is specified in Ragel
+ * and the actions call our C functions above.
+ *
+ * Ragel has an extensive set of functionality, and we use only a small part of
+ * it.  There are many action types but we only use a few:
+ *
+ *   ">" -- transition into a machine
+ *   "%" -- transition out of a machine
+ *   "@" -- transition into a final state of a machine.
+ *
+ * "@" transitions are tricky because a machine can transition into a final
+ * state repeatedly.  But in some cases we know this can't happen, for example
+ * a string which is delimited by a final '"' can only transition into its
+ * final state once, when the closing '"' is seen. */
+
+
+#line 1218 "upb/json/parser.rl"
+
+
+
+#line 1130 "upb/json/parser.c"
+static const char _json_actions[] = {
+	0, 1, 0, 1, 2, 1, 3, 1, 
+	5, 1, 6, 1, 7, 1, 8, 1, 
+	10, 1, 12, 1, 13, 1, 14, 1, 
+	15, 1, 16, 1, 17, 1, 21, 1, 
+	25, 1, 27, 2, 3, 8, 2, 4, 
+	5, 2, 6, 2, 2, 6, 8, 2, 
+	11, 9, 2, 13, 15, 2, 14, 15, 
+	2, 18, 1, 2, 19, 27, 2, 20, 
+	9, 2, 22, 27, 2, 23, 27, 2, 
+	24, 27, 2, 26, 27, 3, 14, 11, 
+	9
+};
+
+static const unsigned char _json_key_offsets[] = {
+	0, 0, 4, 9, 14, 15, 19, 24, 
+	29, 34, 38, 42, 45, 48, 50, 54, 
+	58, 60, 62, 67, 69, 71, 80, 86, 
+	92, 98, 104, 106, 115, 116, 116, 116, 
+	121, 126, 131, 132, 133, 134, 135, 135, 
+	136, 137, 138, 138, 139, 140, 141, 141, 
+	146, 151, 152, 156, 161, 166, 171, 175, 
+	175, 178, 178, 178
+};
+
+static const char _json_trans_keys[] = {
+	32, 123, 9, 13, 32, 34, 125, 9, 
+	13, 32, 34, 125, 9, 13, 34, 32, 
+	58, 9, 13, 32, 93, 125, 9, 13, 
+	32, 44, 125, 9, 13, 32, 44, 125, 
+	9, 13, 32, 34, 9, 13, 45, 48, 
+	49, 57, 48, 49, 57, 46, 69, 101, 
+	48, 57, 69, 101, 48, 57, 43, 45, 
+	48, 57, 48, 57, 48, 57, 46, 69, 
+	101, 48, 57, 34, 92, 34, 92, 34, 
+	47, 92, 98, 102, 110, 114, 116, 117, 
+	48, 57, 65, 70, 97, 102, 48, 57, 
+	65, 70, 97, 102, 48, 57, 65, 70, 
+	97, 102, 48, 57, 65, 70, 97, 102, 
+	34, 92, 34, 45, 91, 102, 110, 116, 
+	123, 48, 57, 34, 32, 93, 125, 9, 
+	13, 32, 44, 93, 9, 13, 32, 93, 
+	125, 9, 13, 97, 108, 115, 101, 117, 
+	108, 108, 114, 117, 101, 32, 34, 125, 
+	9, 13, 32, 34, 125, 9, 13, 34, 
+	32, 58, 9, 13, 32, 93, 125, 9, 
+	13, 32, 44, 125, 9, 13, 32, 44, 
+	125, 9, 13, 32, 34, 9, 13, 32, 
+	9, 13, 0
+};
+
+static const char _json_single_lengths[] = {
+	0, 2, 3, 3, 1, 2, 3, 3, 
+	3, 2, 2, 1, 3, 0, 2, 2, 
+	0, 0, 3, 2, 2, 9, 0, 0, 
+	0, 0, 2, 7, 1, 0, 0, 3, 
+	3, 3, 1, 1, 1, 1, 0, 1, 
+	1, 1, 0, 1, 1, 1, 0, 3, 
+	3, 1, 2, 3, 3, 3, 2, 0, 
+	1, 0, 0, 0
+};
+
+static const char _json_range_lengths[] = {
+	0, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 0, 0, 0, 3, 3, 
+	3, 3, 0, 1, 0, 0, 0, 1, 
+	1, 1, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 1, 
+	1, 0, 1, 1, 1, 1, 1, 0, 
+	1, 0, 0, 0
+};
+
+static const short _json_index_offsets[] = {
+	0, 0, 4, 9, 14, 16, 20, 25, 
+	30, 35, 39, 43, 46, 50, 52, 56, 
+	60, 62, 64, 69, 72, 75, 85, 89, 
+	93, 97, 101, 104, 113, 115, 116, 117, 
+	122, 127, 132, 134, 136, 138, 140, 141, 
+	143, 145, 147, 148, 150, 152, 154, 155, 
+	160, 165, 167, 171, 176, 181, 186, 190, 
+	191, 194, 195, 196
+};
+
+static const char _json_indicies[] = {
+	0, 2, 0, 1, 3, 4, 5, 3, 
+	1, 6, 7, 8, 6, 1, 9, 1, 
+	10, 11, 10, 1, 11, 1, 1, 11, 
+	12, 13, 14, 15, 13, 1, 16, 17, 
+	8, 16, 1, 17, 7, 17, 1, 18, 
+	19, 20, 1, 19, 20, 1, 22, 23, 
+	23, 21, 24, 1, 23, 23, 24, 21, 
+	25, 25, 26, 1, 26, 1, 26, 21, 
+	22, 23, 23, 20, 21, 28, 29, 27, 
+	31, 32, 30, 33, 33, 33, 33, 33, 
+	33, 33, 33, 34, 1, 35, 35, 35, 
+	1, 36, 36, 36, 1, 37, 37, 37, 
+	1, 38, 38, 38, 1, 40, 41, 39, 
+	42, 43, 44, 45, 46, 47, 48, 43, 
+	1, 49, 1, 50, 51, 53, 54, 1, 
+	53, 52, 55, 56, 54, 55, 1, 56, 
+	1, 1, 56, 52, 57, 1, 58, 1, 
+	59, 1, 60, 1, 61, 62, 1, 63, 
+	1, 64, 1, 65, 66, 1, 67, 1, 
+	68, 1, 69, 70, 71, 72, 70, 1, 
+	73, 74, 75, 73, 1, 76, 1, 77, 
+	78, 77, 1, 78, 1, 1, 78, 79, 
+	80, 81, 82, 80, 1, 83, 84, 75, 
+	83, 1, 84, 74, 84, 1, 85, 86, 
+	86, 1, 1, 1, 1, 0
+};
+
+static const char _json_trans_targs[] = {
+	1, 0, 2, 3, 4, 56, 3, 4, 
+	56, 5, 5, 6, 7, 8, 9, 56, 
+	8, 9, 11, 12, 18, 57, 13, 15, 
+	14, 16, 17, 20, 58, 21, 20, 58, 
+	21, 19, 22, 23, 24, 25, 26, 20, 
+	58, 21, 28, 30, 31, 34, 39, 43, 
+	47, 29, 59, 59, 32, 31, 29, 32, 
+	33, 35, 36, 37, 38, 59, 40, 41, 
+	42, 59, 44, 45, 46, 59, 48, 49, 
+	55, 48, 49, 55, 50, 50, 51, 52, 
+	53, 54, 55, 53, 54, 59, 56
+};
+
+static const char _json_trans_actions[] = {
+	0, 0, 0, 21, 77, 53, 0, 47, 
+	23, 17, 0, 0, 15, 19, 19, 50, 
+	0, 0, 0, 0, 0, 1, 0, 0, 
+	0, 0, 0, 3, 13, 0, 0, 35, 
+	5, 11, 0, 38, 7, 7, 7, 41, 
+	44, 9, 62, 56, 25, 0, 0, 0, 
+	31, 29, 33, 59, 15, 0, 27, 0, 
+	0, 0, 0, 0, 0, 68, 0, 0, 
+	0, 71, 0, 0, 0, 65, 21, 77, 
+	53, 0, 47, 23, 17, 0, 0, 15, 
+	19, 19, 50, 0, 0, 74, 0
+};
+
+static const int json_start = 1;
+
+static const int json_en_number_machine = 10;
+static const int json_en_string_machine = 19;
+static const int json_en_value_machine = 27;
+static const int json_en_main = 1;
+
+
+#line 1221 "upb/json/parser.rl"
+
+size_t parse(void *closure, const void *hd, const char *buf, size_t size,
+             const upb_bufhandle *handle) {
+  upb_json_parser *parser = closure;
+
+  /* Variables used by Ragel's generated code. */
+  int cs = parser->current_state;
+  int *stack = parser->parser_stack;
+  int top = parser->parser_top;
+
+  const char *p = buf;
+  const char *pe = buf + size;
+
+  parser->handle = handle;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  capture_resume(parser, buf);
+
+  
+#line 1301 "upb/json/parser.c"
+	{
+	int _klen;
+	unsigned int _trans;
+	const char *_acts;
+	unsigned int _nacts;
+	const char *_keys;
+
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _json_trans_keys + _json_key_offsets[cs];
+	_trans = _json_index_offsets[cs];
+
+	_klen = _json_single_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + _klen - 1;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + ((_upper-_lower) >> 1);
+			if ( (*p) < *_mid )
+				_upper = _mid - 1;
+			else if ( (*p) > *_mid )
+				_lower = _mid + 1;
+			else {
+				_trans += (unsigned int)(_mid - _keys);
+				goto _match;
+			}
+		}
+		_keys += _klen;
+		_trans += _klen;
+	}
+
+	_klen = _json_range_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + (_klen<<1) - 2;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + (((_upper-_lower) >> 1) & ~1);
+			if ( (*p) < _mid[0] )
+				_upper = _mid - 2;
+			else if ( (*p) > _mid[1] )
+				_lower = _mid + 2;
+			else {
+				_trans += (unsigned int)((_mid - _keys)>>1);
+				goto _match;
+			}
+		}
+		_trans += _klen;
+	}
+
+_match:
+	_trans = _json_indicies[_trans];
+	cs = _json_trans_targs[_trans];
+
+	if ( _json_trans_actions[_trans] == 0 )
+		goto _again;
+
+	_acts = _json_actions + _json_trans_actions[_trans];
+	_nacts = (unsigned int) *_acts++;
+	while ( _nacts-- > 0 )
+	{
+		switch ( *_acts++ )
+		{
+	case 0:
+#line 1133 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 1:
+#line 1134 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
+	break;
+	case 2:
+#line 1138 "upb/json/parser.rl"
+	{ start_text(parser, p); }
+	break;
+	case 3:
+#line 1139 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_text(parser, p)); }
+	break;
+	case 4:
+#line 1145 "upb/json/parser.rl"
+	{ start_hex(parser); }
+	break;
+	case 5:
+#line 1146 "upb/json/parser.rl"
+	{ hexdigit(parser, p); }
+	break;
+	case 6:
+#line 1147 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_hex(parser)); }
+	break;
+	case 7:
+#line 1153 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(escape(parser, p)); }
+	break;
+	case 8:
+#line 1159 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 9:
+#line 1162 "upb/json/parser.rl"
+	{ {stack[top++] = cs; cs = 19; goto _again;} }
+	break;
+	case 10:
+#line 1164 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
+	break;
+	case 11:
+#line 1169 "upb/json/parser.rl"
+	{ start_member(parser); }
+	break;
+	case 12:
+#line 1170 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_membername(parser)); }
+	break;
+	case 13:
+#line 1173 "upb/json/parser.rl"
+	{ end_member(parser); }
+	break;
+	case 14:
+#line 1179 "upb/json/parser.rl"
+	{ start_object(parser); }
+	break;
+	case 15:
+#line 1182 "upb/json/parser.rl"
+	{ end_object(parser); }
+	break;
+	case 16:
+#line 1188 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_array(parser)); }
+	break;
+	case 17:
+#line 1192 "upb/json/parser.rl"
+	{ end_array(parser); }
+	break;
+	case 18:
+#line 1197 "upb/json/parser.rl"
+	{ start_number(parser, p); }
+	break;
+	case 19:
+#line 1198 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_number(parser, p)); }
+	break;
+	case 20:
+#line 1200 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_stringval(parser)); }
+	break;
+	case 21:
+#line 1201 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_stringval(parser)); }
+	break;
+	case 22:
+#line 1203 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
+	break;
+	case 23:
+#line 1205 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
+	break;
+	case 24:
+#line 1207 "upb/json/parser.rl"
+	{ /* null value */ }
+	break;
+	case 25:
+#line 1209 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_subobject(parser)); }
+	break;
+	case 26:
+#line 1210 "upb/json/parser.rl"
+	{ end_subobject(parser); }
+	break;
+	case 27:
+#line 1215 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+#line 1487 "upb/json/parser.c"
+		}
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	_out: {}
+	}
+
+#line 1242 "upb/json/parser.rl"
+
+  if (p != pe) {
+    upb_status_seterrf(&parser->status, "Parse error at %s\n", p);
+    upb_env_reporterror(parser->env, &parser->status);
+  } else {
+    capture_suspend(parser, &p);
+  }
+
+error:
+  /* Save parsing state back to parser. */
+  parser->current_state = cs;
+  parser->parser_top = top;
+
+  return p - buf;
+}
+
+bool end(void *closure, const void *hd) {
+  UPB_UNUSED(closure);
+  UPB_UNUSED(hd);
+
+  /* Prevent compile warning on unused static constants. */
+  UPB_UNUSED(json_start);
+  UPB_UNUSED(json_en_number_machine);
+  UPB_UNUSED(json_en_string_machine);
+  UPB_UNUSED(json_en_value_machine);
+  UPB_UNUSED(json_en_main);
+  return true;
+}
+
+static void json_parser_reset(upb_json_parser *p) {
+  int cs;
+  int top;
+
+  p->top = p->stack;
+  p->top->f = NULL;
+  p->top->is_map = false;
+  p->top->is_mapentry = false;
+
+  /* Emit Ragel initialization of the parser. */
+  
+#line 1541 "upb/json/parser.c"
+	{
+	cs = json_start;
+	top = 0;
+	}
+
+#line 1282 "upb/json/parser.rl"
+  p->current_state = cs;
+  p->parser_top = top;
+  accumulate_clear(p);
+  p->multipart_state = MULTIPART_INACTIVE;
+  p->capture = NULL;
+  p->accumulated = NULL;
+  upb_status_clear(&p->status);
+}
+
+
+/* Public API *****************************************************************/
+
+upb_json_parser *upb_json_parser_create(upb_env *env, upb_sink *output) {
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+  upb_json_parser *p = upb_env_malloc(env, sizeof(upb_json_parser));
+  if (!p) return false;
+
+  p->env = env;
+  p->limit = p->stack + UPB_JSON_MAX_DEPTH;
+  p->accumulate_buf = NULL;
+  p->accumulate_buf_size = 0;
+  upb_byteshandler_init(&p->input_handler_);
+  upb_byteshandler_setstring(&p->input_handler_, parse, NULL);
+  upb_byteshandler_setendstr(&p->input_handler_, end, NULL);
+  upb_bytessink_reset(&p->input_, &p->input_handler_, p);
+
+  json_parser_reset(p);
+  upb_sink_reset(&p->top->sink, output->handlers, output->closure);
+  p->top->m = upb_handlers_msgdef(output->handlers);
+
+  /* If this fails, uncomment and increase the value in parser.h. */
+  /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
+  assert(upb_env_bytesallocated(env) - size_before <= UPB_JSON_PARSER_SIZE);
+  return p;
+}
+
+upb_bytessink *upb_json_parser_input(upb_json_parser *p) {
+  return &p->input_;
+}
+/*
+** This currently uses snprintf() to format primitives, and could be optimized
+** further.
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+struct upb_json_printer {
+  upb_sink input_;
+  /* BytesSink closure. */
+  void *subc_;
+  upb_bytessink *output_;
+
+  /* We track the depth so that we know when to emit startstr/endstr on the
+   * output. */
+  int depth_;
+
+  /* Have we emitted the first element? This state is necessary to emit commas
+   * without leaving a trailing comma in arrays/maps. We keep this state per
+   * frame depth.
+   *
+   * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages.
+   * We count frames (contexts in which we separate elements by commas) as both
+   * repeated fields and messages (maps), and the worst case is a
+   * message->repeated field->submessage->repeated field->... nesting. */
+  bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2];
+};
+
+/* StringPiece; a pointer plus a length. */
+typedef struct {
+  const char *ptr;
+  size_t len;
+} strpc;
+
+strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) {
+  strpc *ret = malloc(sizeof(*ret));
+  ret->ptr = upb_fielddef_name(f);
+  ret->len = strlen(ret->ptr);
+  upb_handlers_addcleanup(h, ret, free);
+  return ret;
+}
+
+/* ------------ JSON string printing: values, maps, arrays ------------------ */
+
+static void print_data(
+    upb_json_printer *p, const char *buf, unsigned int len) {
+  /* TODO: Will need to change if we support pushback from the sink. */
+  size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL);
+  UPB_ASSERT_VAR(n, n == len);
+}
+
+static void print_comma(upb_json_printer *p) {
+  if (!p->first_elem_[p->depth_]) {
+    print_data(p, ",", 1);
+  }
+  p->first_elem_[p->depth_] = false;
+}
+
+/* Helpers that print properly formatted elements to the JSON output stream. */
+
+/* Used for escaping control chars in strings. */
+static const char kControlCharLimit = 0x20;
+
+UPB_INLINE bool is_json_escaped(char c) {
+  /* See RFC 4627. */
+  unsigned char uc = (unsigned char)c;
+  return uc < kControlCharLimit || uc == '"' || uc == '\\';
+}
+
+UPB_INLINE char* json_nice_escape(char c) {
+  switch (c) {
+    case '"':  return "\\\"";
+    case '\\': return "\\\\";
+    case '\b': return "\\b";
+    case '\f': return "\\f";
+    case '\n': return "\\n";
+    case '\r': return "\\r";
+    case '\t': return "\\t";
+    default:   return NULL;
+  }
+}
+
+/* Write a properly escaped string chunk. The surrounding quotes are *not*
+ * printed; this is so that the caller has the option of emitting the string
+ * content in chunks. */
+static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
+  const char* unescaped_run = NULL;
+  unsigned int i;
+  for (i = 0; i < len; i++) {
+    char c = buf[i];
+    /* Handle escaping. */
+    if (is_json_escaped(c)) {
+      /* Use a "nice" escape, like \n, if one exists for this character. */
+      const char* escape = json_nice_escape(c);
+      /* If we don't have a specific 'nice' escape code, use a \uXXXX-style
+       * escape. */
+      char escape_buf[8];
+      if (!escape) {
+        unsigned char byte = (unsigned char)c;
+        _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte);
+        escape = escape_buf;
+      }
+
+      /* N.B. that we assume that the input encoding is equal to the output
+       * encoding (both UTF-8 for  now), so for chars >= 0x20 and != \, ", we
+       * can simply pass the bytes through. */
+
+      /* If there's a current run of unescaped chars, print that run first. */
+      if (unescaped_run) {
+        print_data(p, unescaped_run, &buf[i] - unescaped_run);
+        unescaped_run = NULL;
+      }
+      /* Then print the escape code. */
+      print_data(p, escape, strlen(escape));
+    } else {
+      /* Add to the current unescaped run of characters. */
+      if (unescaped_run == NULL) {
+        unescaped_run = &buf[i];
+      }
+    }
+  }
+
+  /* If the string ended in a run of unescaped characters, print that last run. */
+  if (unescaped_run) {
+    print_data(p, unescaped_run, &buf[len] - unescaped_run);
+  }
+}
+
+#define CHKLENGTH(x) if (!(x)) return -1;
+
+/* Helpers that format floating point values according to our custom formats.
+ * Right now we use %.8g and %.17g for float/double, respectively, to match
+ * proto2::util::JsonFormat's defaults.  May want to change this later. */
+
+static size_t fmt_double(double val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%.17g", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_float(float val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%.8g", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_bool(bool val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false"));
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_int64(long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%ld", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%llu", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+/* Print a map key given a field name. Called by scalar field handlers and by
+ * startseq for repeated fields. */
+static bool putkey(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  const strpc *key = handler_data;
+  print_comma(p);
+  print_data(p, "\"", 1);
+  putstring(p, key->ptr, key->len);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+#define CHKFMT(val) if ((val) == (size_t)-1) return false;
+#define CHK(val)    if (!(val)) return false;
+
+#define TYPE_HANDLERS(type, fmt_func)                                        \
+  static bool put##type(void *closure, const void *handler_data, type val) { \
+    upb_json_printer *p = closure;                                           \
+    char data[64];                                                           \
+    size_t length = fmt_func(val, data, sizeof(data));                       \
+    UPB_UNUSED(handler_data);                                                \
+    CHKFMT(length);                                                          \
+    print_data(p, data, length);                                             \
+    return true;                                                             \
+  }                                                                          \
+  static bool scalar_##type(void *closure, const void *handler_data,         \
+                            type val) {                                      \
+    CHK(putkey(closure, handler_data));                                      \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }                                                                          \
+  static bool repeated_##type(void *closure, const void *handler_data,       \
+                              type val) {                                    \
+    upb_json_printer *p = closure;                                           \
+    print_comma(p);                                                          \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }
+
+#define TYPE_HANDLERS_MAPKEY(type, fmt_func)                                 \
+  static bool putmapkey_##type(void *closure, const void *handler_data,      \
+                            type val) {                                      \
+    upb_json_printer *p = closure;                                           \
+    print_data(p, "\"", 1);                                                  \
+    CHK(put##type(closure, handler_data, val));                              \
+    print_data(p, "\":", 2);                                                 \
+    return true;                                                             \
+  }
+
+TYPE_HANDLERS(double,   fmt_double)
+TYPE_HANDLERS(float,    fmt_float)
+TYPE_HANDLERS(bool,     fmt_bool)
+TYPE_HANDLERS(int32_t,  fmt_int64)
+TYPE_HANDLERS(uint32_t, fmt_int64)
+TYPE_HANDLERS(int64_t,  fmt_int64)
+TYPE_HANDLERS(uint64_t, fmt_uint64)
+
+/* double and float are not allowed to be map keys. */
+TYPE_HANDLERS_MAPKEY(bool,     fmt_bool)
+TYPE_HANDLERS_MAPKEY(int32_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64)
+TYPE_HANDLERS_MAPKEY(int64_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64)
+
+#undef TYPE_HANDLERS
+#undef TYPE_HANDLERS_MAPKEY
+
+typedef struct {
+  void *keyname;
+  const upb_enumdef *enumdef;
+} EnumHandlerData;
+
+static bool scalar_enum(void *closure, const void *handler_data,
+                        int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  const char *symbolic_name;
+
+  CHK(putkey(closure, hd->keyname));
+
+  symbolic_name = upb_enumdef_iton(hd->enumdef, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(closure, NULL, val);
+  }
+
+  return true;
+}
+
+static void print_enum_symbolic_name(upb_json_printer *p,
+                                     const upb_enumdef *def,
+                                     int32_t val) {
+  const char *symbolic_name = upb_enumdef_iton(def, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(p, NULL, val);
+  }
+}
+
+static bool repeated_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  print_comma(p);
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static bool mapvalue_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static void *scalar_startsubmsg(void *closure, const void *handler_data) {
+  return putkey(closure, handler_data) ? closure : UPB_BREAK;
+}
+
+static void *repeated_startsubmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_comma(p);
+  return closure;
+}
+
+static void start_frame(upb_json_printer *p) {
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+}
+
+static void end_frame(upb_json_printer *p) {
+  print_data(p, "}", 1);
+  p->depth_--;
+}
+
+static bool printer_startmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  if (p->depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc_);
+  }
+  start_frame(p);
+  return true;
+}
+
+static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(s);
+  end_frame(p);
+  if (p->depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+static void *startseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "[", 1);
+  return closure;
+}
+
+static bool endseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "]", 1);
+  p->depth_--;
+  return true;
+}
+
+static void *startmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+  return closure;
+}
+
+static bool endmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "}", 1);
+  p->depth_--;
+  return true;
+}
+
+static size_t putstr(void *closure, const void *handler_data, const char *str,
+                     size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+  putstring(p, str, len);
+  return len;
+}
+
+/* This has to Base64 encode the bytes, because JSON has no "bytes" type. */
+static size_t putbytes(void *closure, const void *handler_data, const char *str,
+                       size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+
+  /* This is the regular base64, not the "web-safe" version. */
+  static const char base64[] =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /* Base64-encode. */
+  char data[16000];
+  const char *limit = data + sizeof(data);
+  const unsigned char *from = (const unsigned char*)str;
+  char *to = data;
+  size_t remaining = len;
+  size_t bytes;
+
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+
+  while (remaining > 2) {
+    /* TODO(haberman): handle encoded lengths > sizeof(data) */
+    UPB_ASSERT_VAR(limit, (limit - to) >= 4);
+
+    to[0] = base64[from[0] >> 2];
+    to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+    to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)];
+    to[3] = base64[from[2] & 0x3f];
+
+    remaining -= 3;
+    to += 4;
+    from += 3;
+  }
+
+  switch (remaining) {
+    case 2:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+      to[2] = base64[(from[1] & 0xf) << 2];
+      to[3] = '=';
+      to += 4;
+      from += 2;
+      break;
+    case 1:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4)];
+      to[2] = '=';
+      to[3] = '=';
+      to += 4;
+      from += 1;
+      break;
+  }
+
+  bytes = to - data;
+  print_data(p, "\"", 1);
+  putstring(p, data, bytes);
+  print_data(p, "\"", 1);
+  return len;
+}
+
+static void *scalar_startstr(void *closure, const void *handler_data,
+                             size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  CHK(putkey(closure, handler_data));
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t scalar_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool scalar_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *repeated_startstr(void *closure, const void *handler_data,
+                               size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_comma(p);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t repeated_str(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool repeated_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *mapkeyval_startstr(void *closure, const void *handler_data,
+                                size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t mapkey_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool mapkey_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+static bool mapvalue_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static size_t scalar_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putkey(closure, handler_data));
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t repeated_bytes(void *closure, const void *handler_data,
+                             const char *str, size_t len,
+                             const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  print_comma(p);
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t mapkey_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  print_data(p, ":", 1);
+  return len;
+}
+
+static void set_enum_hd(upb_handlers *h,
+                        const upb_fielddef *f,
+                        upb_handlerattr *attr) {
+  EnumHandlerData *hd = malloc(sizeof(EnumHandlerData));
+  hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f);
+  hd->keyname = newstrpc(h, f);
+  upb_handlers_addcleanup(h, hd, free);
+  upb_handlerattr_sethandlerdata(attr, hd);
+}
+
+/* Set up handlers for a mapentry submessage (i.e., an individual key/value pair
+ * in a map).
+ *
+ * TODO: Handle missing key, missing value, out-of-order key/value, or repeated
+ * key or value cases properly. The right way to do this is to allocate a
+ * temporary structure at the start of a mapentry submessage, store key and
+ * value data in it as key and value handlers are called, and then print the
+ * key/value pair once at the end of the submessage. If we don't do this, we
+ * should at least detect the case and throw an error. However, so far all of
+ * our sources that emit mapentry messages do so canonically (with one key
+ * field, and then one value field), so this is not a pressing concern at the
+ * moment. */
+void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+
+  /* A mapentry message is printed simply as '"key": value'. Rather than
+   * special-case key and value for every type below, we just handle both
+   * fields explicitly here. */
+  const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY);
+  const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE);
+
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+
+  UPB_UNUSED(closure);
+
+  switch (upb_fielddef_type(key_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr);
+      upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr);
+      break;
+    default:
+      assert(false);
+      break;
+  }
+
+  switch (upb_fielddef_type(value_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, value_field, putint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, value_field, putint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, value_field, putbool, &empty_attr);
+      break;
+    case UPB_TYPE_FLOAT:
+      upb_handlers_setfloat(h, value_field, putfloat, &empty_attr);
+      break;
+    case UPB_TYPE_DOUBLE:
+      upb_handlers_setdouble(h, value_field, putdouble, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, value_field, putstr, &empty_attr);
+      upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, value_field, putbytes, &empty_attr);
+      break;
+    case UPB_TYPE_ENUM: {
+      upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+      set_enum_hd(h, value_field, &enum_attr);
+      upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr);
+      upb_handlerattr_uninit(&enum_attr);
+      break;
+    }
+    case UPB_TYPE_MESSAGE:
+      /* No handler necessary -- the submsg handlers will print the message
+       * as appropriate. */
+      break;
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+}
+
+void printer_sethandlers(const void *closure, upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+  bool is_mapentry = upb_msgdef_mapentry(md);
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_msg_field_iter i;
+
+  UPB_UNUSED(closure);
+
+  if (is_mapentry) {
+    /* mapentry messages are sufficiently different that we handle them
+     * separately. */
+    printer_sethandlers_mapentry(closure, h);
+    return;
+  }
+
+  upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr);
+  upb_handlers_setendmsg(h, printer_endmsg, &empty_attr);
+
+#define TYPE(type, name, ctype)                                               \
+  case type:                                                                  \
+    if (upb_fielddef_isseq(f)) {                                              \
+      upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr);            \
+    } else {                                                                  \
+      upb_handlers_set##name(h, f, scalar_##ctype, &name_attr);               \
+    }                                                                         \
+    break;
+
+  upb_msg_field_begin(&i, md);
+  for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+
+    upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f));
+
+    if (upb_fielddef_ismap(f)) {
+      upb_handlers_setstartseq(h, f, startmap, &name_attr);
+      upb_handlers_setendseq(h, f, endmap, &name_attr);
+    } else if (upb_fielddef_isseq(f)) {
+      upb_handlers_setstartseq(h, f, startseq, &name_attr);
+      upb_handlers_setendseq(h, f, endseq, &empty_attr);
+    }
+
+    switch (upb_fielddef_type(f)) {
+      TYPE(UPB_TYPE_FLOAT,  float,  float);
+      TYPE(UPB_TYPE_DOUBLE, double, double);
+      TYPE(UPB_TYPE_BOOL,   bool,   bool);
+      TYPE(UPB_TYPE_INT32,  int32,  int32_t);
+      TYPE(UPB_TYPE_UINT32, uint32, uint32_t);
+      TYPE(UPB_TYPE_INT64,  int64,  int64_t);
+      TYPE(UPB_TYPE_UINT64, uint64, uint64_t);
+      case UPB_TYPE_ENUM: {
+        /* For now, we always emit symbolic names for enums. We may want an
+         * option later to control this behavior, but we will wait for a real
+         * need first. */
+        upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+        set_enum_hd(h, f, &enum_attr);
+
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setint32(h, f, repeated_enum, &enum_attr);
+        } else {
+          upb_handlers_setint32(h, f, scalar_enum, &enum_attr);
+        }
+
+        upb_handlerattr_uninit(&enum_attr);
+        break;
+      }
+      case UPB_TYPE_STRING:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr);
+          upb_handlers_setstring(h, f, repeated_str, &empty_attr);
+          upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr);
+        } else {
+          upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr);
+          upb_handlers_setstring(h, f, scalar_str, &empty_attr);
+          upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr);
+        }
+        break;
+      case UPB_TYPE_BYTES:
+        /* XXX: this doesn't support strings that span buffers yet. The base64
+         * encoder will need to be made resumable for this to work properly. */
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstring(h, f, repeated_bytes, &empty_attr);
+        } else {
+          upb_handlers_setstring(h, f, scalar_bytes, &name_attr);
+        }
+        break;
+      case UPB_TYPE_MESSAGE:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr);
+        } else {
+          upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr);
+        }
+        break;
+    }
+
+    upb_handlerattr_uninit(&name_attr);
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+#undef TYPE
+}
+
+static void json_printer_reset(upb_json_printer *p) {
+  p->depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output) {
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  json_printer_reset(p);
+  upb_sink_reset(&p->input_, h, p);
+
+  /* If this fails, increase the value in printer.h. */
+  assert(upb_env_bytesallocated(e) - size_before <= UPB_JSON_PRINTER_SIZE);
+  return p;
+}
+
+upb_sink *upb_json_printer_input(upb_json_printer *p) {
+  return &p->input_;
+}
+
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 const void *owner) {
+  return upb_handlers_newfrozen(md, owner, printer_sethandlers, NULL);
+}
diff --git a/php/ext/google/protobuf/upb.h b/php/ext/google/protobuf/upb.h
new file mode 100644
index 0000000..078e2a2
--- /dev/null
+++ b/php/ext/google/protobuf/upb.h
@@ -0,0 +1,8217 @@
+// Amalgamated source file
+/*
+** Defs are upb's internal representation of the constructs that can appear
+** in a .proto file:
+**
+** - upb::MessageDef (upb_msgdef): describes a "message" construct.
+** - upb::FieldDef (upb_fielddef): describes a message field.
+** - upb::EnumDef (upb_enumdef): describes an enum.
+** - upb::OneofDef (upb_oneofdef): describes a oneof.
+** - upb::Def (upb_def): base class of all the others.
+**
+** TODO: definitions of services.
+**
+** Like upb_refcounted objects, defs are mutable only until frozen, and are
+** only thread-safe once frozen.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_DEF_H_
+#define UPB_DEF_H_
+
+/*
+** upb::RefCounted (upb_refcounted)
+**
+** A refcounting scheme that supports circular refs.  It accomplishes this by
+** partitioning the set of objects into groups such that no cycle spans groups;
+** we can then reference-count the group as a whole and ignore refs within the
+** group.  When objects are mutable, these groups are computed very
+** conservatively; we group any objects that have ever had a link between them.
+** When objects are frozen, we compute strongly-connected components which
+** allows us to be precise and only group objects that are actually cyclic.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_REFCOUNTED_H_
+#define UPB_REFCOUNTED_H_
+
+/*
+** upb_table
+**
+** This header is INTERNAL-ONLY!  Its interfaces are not public or stable!
+** This file defines very fast int->upb_value (inttable) and string->upb_value
+** (strtable) hash tables.
+**
+** The table uses chained scatter with Brent's variation (inspired by the Lua
+** implementation of hash tables).  The hash function for strings is Austin
+** Appleby's "MurmurHash."
+**
+** The inttable uses uintptr_t as its key, which guarantees it can be used to
+** store pointers or integers of at least 32 bits (upb isn't really useful on
+** systems where sizeof(void*) < 4).
+**
+** The table must be homogenous (all values of the same type).  In debug
+** mode, we check this on insert and lookup.
+*/
+
+#ifndef UPB_TABLE_H_
+#define UPB_TABLE_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+/*
+** This file contains shared definitions that are widely used across upb.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_H_
+#define UPB_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/* UPB_INLINE: inline if possible, emit standalone code if required. */
+#ifdef __cplusplus
+#define UPB_INLINE inline
+#elif defined (__GNUC__)
+#define UPB_INLINE static __inline__
+#else
+#define UPB_INLINE static
+#endif
+
+/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler
+ * doesn't provide these preprocessor symbols. */
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define UPB_BIG_ENDIAN
+#endif
+
+/* Macros for function attributes on compilers that support them. */
+#ifdef __GNUC__
+#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
+#define UPB_NOINLINE __attribute__((noinline))
+#define UPB_NORETURN __attribute__((__noreturn__))
+#else  /* !defined(__GNUC__) */
+#define UPB_FORCEINLINE
+#define UPB_NOINLINE
+#define UPB_NORETURN
+#endif
+
+/* A few hacky workarounds for functions not in C89.
+ * For internal use only!
+ * TODO(haberman): fix these by including our own implementations, or finding
+ * another workaround.
+ */
+#ifdef __GNUC__
+#define _upb_snprintf __builtin_snprintf
+#define _upb_vsnprintf __builtin_vsnprintf
+#define _upb_va_copy(a, b) __va_copy(a, b)
+#elif __STDC_VERSION__ >= 199901L
+/* C99 versions. */
+#define _upb_snprintf snprintf
+#define _upb_vsnprintf vsnprintf
+#define _upb_va_copy(a, b) va_copy(a, b)
+#else
+#error Need implementations of [v]snprintf and va_copy
+#endif
+
+
+#if ((defined(__cplusplus) && __cplusplus >= 201103L) || \
+      defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11)
+#define UPB_CXX11
+#endif
+
+/* UPB_DISALLOW_COPY_AND_ASSIGN()
+ * UPB_DISALLOW_POD_OPS()
+ *
+ * Declare these in the "private" section of a C++ class to forbid copy/assign
+ * or all POD ops (construct, destruct, copy, assign) on that class. */
+#ifdef UPB_CXX11
+#include <type_traits>
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&) = delete; \
+  void operator=(const class_name&) = delete;
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name() = delete; \
+  ~class_name() = delete; \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type) \
+  static_assert(std::is_standard_layout<type>::value, \
+                #type " must be standard layout");
+#else  /* !defined(UPB_CXX11) */
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&); \
+  void operator=(const class_name&);
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name(); \
+  ~class_name(); \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type)
+#endif
+
+/* UPB_DECLARE_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE2()
+ *
+ * Macros for declaring C and C++ types both, including inheritance.
+ * The inheritance doesn't use real C++ inheritance, to stay compatible with C.
+ *
+ * These macros also provide upcasts:
+ *  - in C: types-specific functions (ie. upb_foo_upcast(foo))
+ *  - in C++: upb::upcast(foo) along with implicit conversions
+ *
+ * Downcasts are not provided, but upb/def.h defines downcasts for upb::Def. */
+
+#define UPB_C_UPCASTS(ty, base)                                      \
+  UPB_INLINE base *ty ## _upcast_mutable(ty *p) { return (base*)p; } \
+  UPB_INLINE const base *ty ## _upcast(const ty *p) { return (const base*)p; }
+
+#define UPB_C_UPCASTS2(ty, base, base2)                                 \
+  UPB_C_UPCASTS(ty, base)                                               \
+  UPB_INLINE base2 *ty ## _upcast2_mutable(ty *p) { return (base2*)p; } \
+  UPB_INLINE const base2 *ty ## _upcast2(const ty *p) { return (const base2*)p; }
+
+#ifdef __cplusplus
+
+#define UPB_BEGIN_EXTERN_C extern "C" {
+#define UPB_END_EXTERN_C }
+#define UPB_PRIVATE_FOR_CPP private:
+#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname;
+
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase)  \
+  UPB_DECLARE_TYPE(cppname, cname)                                \
+  UPB_C_UPCASTS(cname, cbase)                                     \
+  namespace upb {                                                 \
+  template <>                                                     \
+  class Pointer<cppname> : public PointerBase<cppname, cppbase> { \
+   public:                                                        \
+    explicit Pointer(cppname* ptr) : PointerBase(ptr) {}          \
+  };                                                              \
+  template <>                                                     \
+  class Pointer<const cppname>                                    \
+      : public PointerBase<const cppname, const cppbase> {        \
+   public:                                                        \
+    explicit Pointer(const cppname* ptr) : PointerBase(ptr) {}    \
+  };                                                              \
+  }
+
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, cname, cbase,  \
+                                  cbase2)                                    \
+  UPB_DECLARE_TYPE(cppname, cname)                                           \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)                                       \
+  namespace upb {                                                            \
+  template <>                                                                \
+  class Pointer<cppname> : public PointerBase2<cppname, cppbase, cppbase2> { \
+   public:                                                                   \
+    explicit Pointer(cppname* ptr) : PointerBase2(ptr) {}                    \
+  };                                                                         \
+  template <>                                                                \
+  class Pointer<const cppname>                                               \
+      : public PointerBase2<const cppname, const cppbase, const cppbase2> {  \
+   public:                                                                   \
+    explicit Pointer(const cppname* ptr) : PointerBase2(ptr) {}              \
+  };                                                                         \
+  }
+
+#else  /* !defined(__cplusplus) */
+
+#define UPB_BEGIN_EXTERN_C
+#define UPB_END_EXTERN_C
+#define UPB_PRIVATE_FOR_CPP
+#define UPB_DECLARE_TYPE(cppname, cname) \
+  struct cname;                          \
+  typedef struct cname cname;
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS(cname, cbase)
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2,    \
+                                  cname, cbase, cbase2)          \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)
+
+#endif  /* defined(__cplusplus) */
+
+#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define UPB_UNUSED(var) (void)var
+
+/* For asserting something about a variable when the variable is not used for
+ * anything else.  This prevents "unused variable" warnings when compiling in
+ * debug mode. */
+#define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate)
+
+/* Generic function type. */
+typedef void upb_func();
+
+/* C++ Casts ******************************************************************/
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> class Pointer;
+
+/* Casts to a subclass.  The caller must know that cast is correct; an
+ * incorrect cast will throw an assertion failure in debug mode.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // Assert-fails if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that downcasts are only defined for some types (at the moment you can
+ * only downcast from a upb::Def to a specific Def type). */
+template<class To, class From> To down_cast(From* f);
+
+/* Casts to a subclass.  If the class does not actually match the given To type,
+ * returns NULL.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // md will be NULL if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that dynamic casts are only defined for some types (at the moment you
+ * can only downcast from a upb::Def to a specific Def type).. */
+template<class To, class From> To dyn_cast(From* f);
+
+/* Casts to any base class, or the type itself (ie. can be a no-op).
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   // This will fail to compile if this wasn't actually a base class.
+ *   upb::Def* def = upb::upcast(md);
+ */
+template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
+
+/* Attempt upcast to specific base class.
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   upb::upcast_to<upb::Def>(md)->MethodOnDef();
+ */
+template <class T, class F> inline T* upcast_to(F *f) {
+  return static_cast<T*>(upcast(f));
+}
+
+/* PointerBase<T>: implementation detail of upb::upcast().
+ * It is implicitly convertable to pointers to the Base class(es).
+ */
+template <class T, class Base>
+class PointerBase {
+ public:
+  explicit PointerBase(T* ptr) : ptr_(ptr) {}
+  operator T*() { return ptr_; }
+  operator Base*() { return (Base*)ptr_; }
+
+ private:
+  T* ptr_;
+};
+
+template <class T, class Base, class Base2>
+class PointerBase2 : public PointerBase<T, Base> {
+ public:
+  explicit PointerBase2(T* ptr) : PointerBase<T, Base>(ptr) {}
+  operator Base2*() { return Pointer<Base>(*this); }
+};
+
+}
+
+#endif
+
+
+/* upb::reffed_ptr ************************************************************/
+
+#ifdef __cplusplus
+
+#include <algorithm>  /* For std::swap(). */
+
+namespace upb {
+
+/* Provides RAII semantics for upb refcounted objects.  Each reffed_ptr owns a
+ * ref on whatever object it points to (if any). */
+template <class T> class reffed_ptr {
+ public:
+  reffed_ptr() : ptr_(NULL) {}
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  reffed_ptr(U* val, const void* ref_donor = NULL)
+      : ptr_(upb::upcast(val)) {
+    if (ref_donor) {
+      assert(ptr_);
+      ptr_->DonateRef(ref_donor, this);
+    } else if (ptr_) {
+      ptr_->Ref(this);
+    }
+  }
+
+  template <class U>
+  reffed_ptr(const reffed_ptr<U>& other)
+      : ptr_(upb::upcast(other.get())) {
+    if (ptr_) ptr_->Ref(this);
+  }
+
+  ~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
+
+  template <class U>
+  reffed_ptr& operator=(const reffed_ptr<U>& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  reffed_ptr& operator=(const reffed_ptr& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  /* TODO(haberman): add C++11 move construction/assignment for greater
+   * efficiency. */
+
+  void swap(reffed_ptr& other) {
+    if (ptr_ == other.ptr_) {
+      return;
+    }
+
+    if (ptr_) ptr_->DonateRef(this, &other);
+    if (other.ptr_) other.ptr_->DonateRef(&other, this);
+    std::swap(ptr_, other.ptr_);
+  }
+
+  T& operator*() const {
+    assert(ptr_);
+    return *ptr_;
+  }
+
+  T* operator->() const {
+    assert(ptr_);
+    return ptr_;
+  }
+
+  T* get() const { return ptr_; }
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  void reset(U* ptr = NULL, const void* ref_donor = NULL) {
+    reffed_ptr(ptr, ref_donor).swap(*this);
+  }
+
+  template <class U>
+  reffed_ptr<U> down_cast() {
+    return reffed_ptr<U>(upb::down_cast<U*>(get()));
+  }
+
+  template <class U>
+  reffed_ptr<U> dyn_cast() {
+    return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
+  }
+
+  /* Plain release() is unsafe; if we were the only owner, it would leak the
+   * object.  Instead we provide this: */
+  T* ReleaseTo(const void* new_owner) {
+    T* ret = NULL;
+    ptr_->DonateRef(this, new_owner);
+    std::swap(ret, ptr_);
+    return ret;
+  }
+
+ private:
+  T* ptr_;
+};
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+
+/* upb::Status ****************************************************************/
+
+#ifdef __cplusplus
+namespace upb {
+class ErrorSpace;
+class Status;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace)
+UPB_DECLARE_TYPE(upb::Status, upb_status)
+
+/* The maximum length of an error message before it will get truncated. */
+#define UPB_STATUS_MAX_MESSAGE 128
+
+/* An error callback function is used to report errors from some component.
+ * The function can return "true" to indicate that the component should try
+ * to recover and proceed, but this is not always possible. */
+typedef bool upb_errcb_t(void *closure, const upb_status* status);
+
+#ifdef __cplusplus
+class upb::ErrorSpace {
+#else
+struct upb_errorspace {
+#endif
+  const char *name;
+  /* Should the error message in the status object according to this code. */
+  void (*set_message)(upb_status* status, int code);
+};
+
+#ifdef __cplusplus
+
+/* Object representing a success or failure status.
+ * It owns no resources and allocates no memory, so it should work
+ * even in OOM situations. */
+
+class upb::Status {
+ public:
+  Status();
+
+  /* Returns true if there is no error. */
+  bool ok() const;
+
+  /* Optional error space and code, useful if the caller wants to
+   * programmatically check the specific kind of error. */
+  ErrorSpace* error_space();
+  int code() const;
+
+  const char *error_message() const;
+
+  /* The error message will be truncated if it is longer than
+   * UPB_STATUS_MAX_MESSAGE-4. */
+  void SetErrorMessage(const char* msg);
+  void SetFormattedErrorMessage(const char* fmt, ...);
+
+  /* If there is no error message already, this will use the ErrorSpace to
+   * populate the error message for this code.  The caller can still call
+   * SetErrorMessage() to give a more specific message. */
+  void SetErrorCode(ErrorSpace* space, int code);
+
+  /* Resets the status to a successful state with no message. */
+  void Clear();
+
+  void CopyFrom(const Status& other);
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Status)
+#else
+struct upb_status {
+#endif
+  bool ok_;
+
+  /* Specific status code defined by some error space (optional). */
+  int code_;
+  upb_errorspace *error_space_;
+
+  /* Error message; NULL-terminated. */
+  char msg[UPB_STATUS_MAX_MESSAGE];
+};
+
+#define UPB_STATUS_INIT {true, 0, NULL, {0}}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The returned string is invalidated by any other call into the status. */
+const char *upb_status_errmsg(const upb_status *status);
+bool upb_ok(const upb_status *status);
+upb_errorspace *upb_status_errspace(const upb_status *status);
+int upb_status_errcode(const upb_status *status);
+
+/* Any of the functions that write to a status object allow status to be NULL,
+ * to support use cases where the function's caller does not care about the
+ * status message. */
+void upb_status_clear(upb_status *status);
+void upb_status_seterrmsg(upb_status *status, const char *msg);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code);
+void upb_status_copy(upb_status *to, const upb_status *from);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+
+namespace upb {
+
+/* C++ Wrappers */
+inline Status::Status() { Clear(); }
+inline bool Status::ok() const { return upb_ok(this); }
+inline const char* Status::error_message() const {
+  return upb_status_errmsg(this);
+}
+inline void Status::SetErrorMessage(const char* msg) {
+  upb_status_seterrmsg(this, msg);
+}
+inline void Status::SetFormattedErrorMessage(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  upb_status_vseterrf(this, fmt, args);
+  va_end(args);
+}
+inline void Status::SetErrorCode(ErrorSpace* space, int code) {
+  upb_status_seterrcode(this, space, code);
+}
+inline void Status::Clear() { upb_status_clear(this); }
+inline void Status::CopyFrom(const Status& other) {
+  upb_status_copy(this, &other);
+}
+
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_H_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* upb_value ******************************************************************/
+
+/* A tagged union (stored untagged inside the table) so that we can check that
+ * clients calling table accessors are correctly typed without having to have
+ * an explosion of accessors. */
+typedef enum {
+  UPB_CTYPE_INT32    = 1,
+  UPB_CTYPE_INT64    = 2,
+  UPB_CTYPE_UINT32   = 3,
+  UPB_CTYPE_UINT64   = 4,
+  UPB_CTYPE_BOOL     = 5,
+  UPB_CTYPE_CSTR     = 6,
+  UPB_CTYPE_PTR      = 7,
+  UPB_CTYPE_CONSTPTR = 8,
+  UPB_CTYPE_FPTR     = 9
+} upb_ctype_t;
+
+typedef struct {
+  uint64_t val;
+#ifndef NDEBUG
+  /* In debug mode we carry the value type around also so we can check accesses
+   * to be sure the right member is being read. */
+  upb_ctype_t ctype;
+#endif
+} upb_value;
+
+#ifdef NDEBUG
+#define SET_TYPE(dest, val)      UPB_UNUSED(val)
+#else
+#define SET_TYPE(dest, val) dest = val
+#endif
+
+/* Like strdup(), which isn't always available since it's not ANSI C. */
+char *upb_strdup(const char *s);
+/* Variant that works with a length-delimited rather than NULL-delimited string,
+ * as supported by strtable. */
+char *upb_strdup2(const char *s, size_t len);
+
+UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val,
+                                  upb_ctype_t ctype) {
+  v->val = val;
+  SET_TYPE(v->ctype, ctype);
+}
+
+UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) {
+  upb_value ret;
+  _upb_value_setval(&ret, val, ctype);
+  return ret;
+}
+
+/* For each value ctype, define the following set of functions:
+ *
+ * // Get/set an int32 from a upb_value.
+ * int32_t upb_value_getint32(upb_value val);
+ * void upb_value_setint32(upb_value *val, int32_t cval);
+ *
+ * // Construct a new upb_value from an int32.
+ * upb_value upb_value_int32(int32_t val); */
+#define FUNCS(name, membername, type_t, converter, proto_type) \
+  UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \
+    val->val = (converter)cval; \
+    SET_TYPE(val->ctype, proto_type); \
+  } \
+  UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
+    upb_value ret; \
+    upb_value_set ## name(&ret, val); \
+    return ret; \
+  } \
+  UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
+    assert(val.ctype == proto_type); \
+    return (type_t)(converter)val.val; \
+  }
+
+FUNCS(int32,    int32,        int32_t,      int32_t,    UPB_CTYPE_INT32)
+FUNCS(int64,    int64,        int64_t,      int64_t,    UPB_CTYPE_INT64)
+FUNCS(uint32,   uint32,       uint32_t,     uint32_t,   UPB_CTYPE_UINT32)
+FUNCS(uint64,   uint64,       uint64_t,     uint64_t,   UPB_CTYPE_UINT64)
+FUNCS(bool,     _bool,        bool,         bool,       UPB_CTYPE_BOOL)
+FUNCS(cstr,     cstr,         char*,        uintptr_t,  UPB_CTYPE_CSTR)
+FUNCS(ptr,      ptr,          void*,        uintptr_t,  UPB_CTYPE_PTR)
+FUNCS(constptr, constptr,     const void*,  uintptr_t,  UPB_CTYPE_CONSTPTR)
+FUNCS(fptr,     fptr,         upb_func*,    uintptr_t,  UPB_CTYPE_FPTR)
+
+#undef FUNCS
+#undef SET_TYPE
+
+
+/* upb_tabkey *****************************************************************/
+
+/* Either:
+ *   1. an actual integer key, or
+ *   2. a pointer to a string prefixed by its uint32_t length, owned by us.
+ *
+ * ...depending on whether this is a string table or an int table.  We would
+ * make this a union of those two types, but C89 doesn't support statically
+ * initializing a non-first union member. */
+typedef uintptr_t upb_tabkey;
+
+#define UPB_TABKEY_NUM(n) n
+#define UPB_TABKEY_NONE 0
+/* The preprocessor isn't quite powerful enough to turn the compile-time string
+ * length into a byte-wise string representation, so code generation needs to
+ * help it along.
+ *
+ * "len1" is the low byte and len4 is the high byte. */
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len4 len3 len2 len1 strval)
+#else
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len1 len2 len3 len4 strval)
+#endif
+
+UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
+  char* mem = (char*)key;
+  if (len) memcpy(len, mem, sizeof(*len));
+  return mem + sizeof(*len);
+}
+
+
+/* upb_tabval *****************************************************************/
+
+#ifdef __cplusplus
+
+/* Status initialization not supported.
+ *
+ * This separate definition is necessary because in C++, UINTPTR_MAX isn't
+ * reliably available. */
+typedef struct {
+  uint64_t val;
+} upb_tabval;
+
+#else
+
+/* C -- supports static initialization, but to support static initialization of
+ * both integers and points for both 32 and 64 bit targets, it takes a little
+ * bit of doing. */
+
+#if UINTPTR_MAX == 0xffffffffffffffffULL
+#define UPB_PTR_IS_64BITS
+#elif UINTPTR_MAX != 0xffffffff
+#error Could not determine how many bits pointers are.
+#endif
+
+typedef union {
+  /* For static initialization.
+   *
+   * Unfortunately this ugliness is necessary -- it is the only way that we can,
+   * with -std=c89 -pedantic, statically initialize this to either a pointer or
+   * an integer on 32-bit platforms. */
+  struct {
+#ifdef UPB_PTR_IS_64BITS
+    uintptr_t val;
+#else
+    uintptr_t val1;
+    uintptr_t val2;
+#endif
+  } staticinit;
+
+  /* The normal accessor that we use for everything at runtime. */
+  uint64_t val;
+} upb_tabval;
+
+#ifdef UPB_PTR_IS_64BITS
+#define UPB_TABVALUE_INT_INIT(v) {{v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1}}
+#else
+
+/* 32-bit pointers */
+
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABVALUE_INT_INIT(v) {{0, v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#else
+#define UPB_TABVALUE_INT_INIT(v) {{v, 0}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#endif
+
+#endif
+
+#define UPB_TABVALUE_PTR_INIT(v) UPB_TABVALUE_INT_INIT((uintptr_t)v)
+
+#undef UPB_PTR_IS_64BITS
+
+#endif  /* __cplusplus */
+
+
+/* upb_table ******************************************************************/
+
+typedef struct _upb_tabent {
+  upb_tabkey key;
+  upb_tabval val;
+
+  /* Internal chaining.  This is const so we can create static initializers for
+   * tables.  We cast away const sometimes, but *only* when the containing
+   * upb_table is known to be non-const.  This requires a bit of care, but
+   * the subtlety is confined to table.c. */
+  const struct _upb_tabent *next;
+} upb_tabent;
+
+typedef struct {
+  size_t count;          /* Number of entries in the hash part. */
+  size_t mask;           /* Mask to turn hash value -> bucket. */
+  upb_ctype_t ctype;     /* Type of all values. */
+  uint8_t size_lg2;      /* Size of the hashtable part is 2^size_lg2 entries. */
+
+  /* Hash table entries.
+   * Making this const isn't entirely accurate; what we really want is for it to
+   * have the same const-ness as the table it's inside.  But there's no way to
+   * declare that in C.  So we have to make it const so that we can statically
+   * initialize const hash tables.  Then we cast away const when we have to.
+   */
+  const upb_tabent *entries;
+} upb_table;
+
+typedef struct {
+  upb_table t;
+} upb_strtable;
+
+#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \
+  {{count, mask, ctype, size_lg2, entries}}
+
+#define UPB_EMPTY_STRTABLE_INIT(ctype)                           \
+  UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL)
+
+typedef struct {
+  upb_table t;              /* For entries that don't fit in the array part. */
+  const upb_tabval *array;  /* Array part of the table. See const note above. */
+  size_t array_size;        /* Array part size. */
+  size_t array_count;       /* Array part number of elements. */
+} upb_inttable;
+
+#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \
+  {{count, mask, ctype, size_lg2, ent}, a, asize, acount}
+
+#define UPB_EMPTY_INTTABLE_INIT(ctype) \
+  UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0)
+
+#define UPB_ARRAY_EMPTYENT -1
+
+UPB_INLINE size_t upb_table_size(const upb_table *t) {
+  if (t->size_lg2 == 0)
+    return 0;
+  else
+    return 1 << t->size_lg2;
+}
+
+/* Internal-only functions, in .h file only out of necessity. */
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
+  return e->key == 0;
+}
+
+/* Used by some of the unit tests for generic hashing functionality. */
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed);
+
+UPB_INLINE uintptr_t upb_intkey(uintptr_t key) {
+  return key;
+}
+
+UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
+  return (uint32_t)key;
+}
+
+static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
+  return t->entries + (hash & t->mask);
+}
+
+UPB_INLINE bool upb_arrhas(upb_tabval key) {
+  return key.val != (uint64_t)-1;
+}
+
+/* Initialize and uninitialize a table, respectively.  If memory allocation
+ * failed, false is returned that the table is uninitialized. */
+bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype);
+bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype);
+void upb_inttable_uninit(upb_inttable *table);
+void upb_strtable_uninit(upb_strtable *table);
+
+/* Returns the number of values in the table. */
+size_t upb_inttable_count(const upb_inttable *t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
+  return t->t.count;
+}
+
+/* Inserts the given key into the hashtable with the given value.  The key must
+ * not already exist in the hash table.  For string tables, the key must be
+ * NULL-terminated, and the table will make an internal copy of the key.
+ * Inttables must not insert a value of UINTPTR_MAX.
+ *
+ * If a table resize was required but memory allocation failed, false is
+ * returned and the table is unchanged. */
+bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val);
+bool upb_strtable_insert2(upb_strtable *t, const char *key, size_t len,
+                          upb_value val);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key,
+                                    upb_value val) {
+  return upb_strtable_insert2(t, key, strlen(key), val);
+}
+
+/* Looks up key in this table, returning "true" if the key was found.
+ * If v is non-NULL, copies the value for this key into *v. */
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_lookup2(t, key, strlen(key), v);
+}
+
+/* Removes an item from the table.  Returns true if the remove was successful,
+ * and stores the removed item in *val if non-NULL. */
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
+bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len,
+                          upb_value *val);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_remove2(t, key, strlen(key), v);
+}
+
+/* Updates an existing entry in an inttable.  If the entry does not exist,
+ * returns false and does nothing.  Unlike insert/remove, this does not
+ * invalidate iterators. */
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
+
+/* Handy routines for treating an inttable like a stack.  May not be mixed with
+ * other insert/remove calls. */
+bool upb_inttable_push(upb_inttable *t, upb_value val);
+upb_value upb_inttable_pop(upb_inttable *t);
+
+/* Convenience routines for inttables with pointer keys. */
+bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val);
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
+bool upb_inttable_lookupptr(
+    const upb_inttable *t, const void *key, upb_value *val);
+
+/* Optimizes the table for the current set of entries, for both memory use and
+ * lookup time.  Client should call this after all entries have been inserted;
+ * inserting more entries is legal, but will likely require a table resize. */
+void upb_inttable_compact(upb_inttable *t);
+
+/* A special-case inlinable version of the lookup routine for 32-bit
+ * integers. */
+UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
+                                      upb_value *v) {
+  *v = upb_value_int32(0);  /* Silence compiler warnings. */
+  if (key < t->array_size) {
+    upb_tabval arrval = t->array[key];
+    if (upb_arrhas(arrval)) {
+      _upb_value_setval(v, arrval.val, t->t.ctype);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    const upb_tabent *e;
+    if (t->t.entries == NULL) return false;
+    for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) {
+      if ((uint32_t)e->key == key) {
+        _upb_value_setval(v, e->val.val, t->t.ctype);
+        return true;
+      }
+      if (e->next == NULL) return false;
+    }
+  }
+}
+
+/* Exposed for testing only. */
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2);
+
+/* Iterators ******************************************************************/
+
+/* Iterators for int and string tables.  We are subject to some kind of unusual
+ * design constraints:
+ *
+ * For high-level languages:
+ *  - we must be able to guarantee that we don't crash or corrupt memory even if
+ *    the program accesses an invalidated iterator.
+ *
+ * For C++11 range-based for:
+ *  - iterators must be copyable
+ *  - iterators must be comparable
+ *  - it must be possible to construct an "end" value.
+ *
+ * Iteration order is undefined.
+ *
+ * Modifying the table invalidates iterators.  upb_{str,int}table_done() is
+ * guaranteed to work even on an invalidated iterator, as long as the table it
+ * is iterating over has not been freed.  Calling next() or accessing data from
+ * an invalidated iterator yields unspecified elements from the table, but it is
+ * guaranteed not to crash and to return real table elements (except when done()
+ * is true). */
+
+
+/* upb_strtable_iter **********************************************************/
+
+/*   upb_strtable_iter i;
+ *   upb_strtable_begin(&i, t);
+ *   for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ *     const char *key = upb_strtable_iter_key(&i);
+ *     const upb_value val = upb_strtable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_strtable *t;
+  size_t index;
+} upb_strtable_iter;
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
+void upb_strtable_next(upb_strtable_iter *i);
+bool upb_strtable_done(const upb_strtable_iter *i);
+const char *upb_strtable_iter_key(upb_strtable_iter *i);
+size_t upb_strtable_iter_keylength(upb_strtable_iter *i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i);
+void upb_strtable_iter_setdone(upb_strtable_iter *i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2);
+
+
+/* upb_inttable_iter **********************************************************/
+
+/*   upb_inttable_iter i;
+ *   upb_inttable_begin(&i, t);
+ *   for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ *     uintptr_t key = upb_inttable_iter_key(&i);
+ *     upb_value val = upb_inttable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_inttable *t;
+  size_t index;
+  bool array_part;
+} upb_inttable_iter;
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
+void upb_inttable_next(upb_inttable_iter *i);
+bool upb_inttable_done(const upb_inttable_iter *i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i);
+void upb_inttable_iter_setdone(upb_inttable_iter *i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                               const upb_inttable_iter *i2);
+
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_TABLE_H_ */
+
+/* Reference tracking will check ref()/unref() operations to make sure the
+ * ref ownership is correct.  Where possible it will also make tools like
+ * Valgrind attribute ref leaks to the code that took the leaked ref, not
+ * the code that originally created the object.
+ *
+ * Enabling this requires the application to define upb_lock()/upb_unlock()
+ * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
+ * For this reason we don't enable it by default, even in debug builds.
+ */
+
+/* #define UPB_DEBUG_REFS */
+
+#ifdef __cplusplus
+namespace upb { class RefCounted; }
+#endif
+
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted)
+
+struct upb_refcounted_vtbl;
+
+#ifdef __cplusplus
+
+class upb::RefCounted {
+ public:
+  /* Returns true if the given object is frozen. */
+  bool IsFrozen() const;
+
+  /* Increases the ref count, the new ref is owned by "owner" which must not
+   * already own a ref (and should not itself be a refcounted object if the ref
+   * could possibly be circular; see below).
+   * Thread-safe iff "this" is frozen. */
+  void Ref(const void *owner) const;
+
+  /* Release a ref that was acquired from upb_refcounted_ref() and collects any
+   * objects it can. */
+  void Unref(const void *owner) const;
+
+  /* Moves an existing ref from "from" to "to", without changing the overall
+   * ref count.  DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
+   * but "to" may not be NULL. */
+  void DonateRef(const void *from, const void *to) const;
+
+  /* Verifies that a ref to the given object is currently held by the given
+   * owner.  Only effective in UPB_DEBUG_REFS builds. */
+  void CheckRef(const void *owner) const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted)
+#else
+struct upb_refcounted {
+#endif
+  /* TODO(haberman): move the actual structure definition to structdefs.int.h.
+   * The only reason they are here is because inline functions need to see the
+   * definition of upb_handlers, which needs to see this definition.  But we
+   * can change the upb_handlers inline functions to deal in raw offsets
+   * instead.
+   */
+
+  /* A single reference count shared by all objects in the group. */
+  uint32_t *group;
+
+  /* A singly-linked list of all objects in the group. */
+  upb_refcounted *next;
+
+  /* Table of function pointers for this type. */
+  const struct upb_refcounted_vtbl *vtbl;
+
+  /* Maintained only when mutable, this tracks the number of refs (but not
+   * ref2's) to this object.  *group should be the sum of all individual_count
+   * in the group. */
+  uint32_t individual_count;
+
+  bool is_frozen;
+
+#ifdef UPB_DEBUG_REFS
+  upb_inttable *refs;  /* Maps owner -> trackedref for incoming refs. */
+  upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */
+#endif
+};
+
+#ifdef UPB_DEBUG_REFS
+#define UPB_REFCOUNT_INIT(refs, ref2s) \
+    {&static_refcount, NULL, NULL, 0, true, refs, ref2s}
+#else
+#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true}
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* It is better to use tracked refs when possible, for the extra debugging
+ * capability.  But if this is not possible (because you don't have easy access
+ * to a stable pointer value that is associated with the ref), you can pass
+ * UPB_UNTRACKED_REF instead.  */
+extern const void *UPB_UNTRACKED_REF;
+
+/* Native C API. */
+bool upb_refcounted_isfrozen(const upb_refcounted *r);
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to);
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner);
+
+#define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \
+  UPB_INLINE bool type ## _isfrozen(const type *v) { \
+    return upb_refcounted_isfrozen(upcastfunc(v)); \
+  } \
+  UPB_INLINE void type ## _ref(const type *v, const void *owner) { \
+    upb_refcounted_ref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _unref(const type *v, const void *owner) { \
+    upb_refcounted_unref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \
+    upb_refcounted_donateref(upcastfunc(v), from, to); \
+  } \
+  UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \
+    upb_refcounted_checkref(upcastfunc(v), owner); \
+  }
+
+#define UPB_REFCOUNTED_CPPMETHODS \
+  bool IsFrozen() const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->IsFrozen(); \
+  } \
+  void Ref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Ref(owner); \
+  } \
+  void Unref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Unref(owner); \
+  } \
+  void DonateRef(const void *from, const void *to) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->DonateRef(from, to); \
+  } \
+  void CheckRef(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->CheckRef(owner); \
+  }
+
+/* Internal-to-upb Interface **************************************************/
+
+typedef void upb_refcounted_visit(const upb_refcounted *r,
+                                  const upb_refcounted *subobj,
+                                  void *closure);
+
+struct upb_refcounted_vtbl {
+  /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
+   * Must be longjmp()-safe. */
+  void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c);
+
+  /* Must free the object and release all references to other objects. */
+  void (*free)(upb_refcounted *r);
+};
+
+/* Initializes the refcounted with a single ref for the given owner.  Returns
+ * false if memory could not be allocated. */
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner);
+
+/* Adds a ref from one refcounted object to another ("from" must not already
+ * own a ref).  These refs may be circular; cycles will be collected correctly
+ * (if conservatively).  These refs do not need to be freed in from's free()
+ * function. */
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from);
+
+/* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
+ * object it can.  This is only necessary when "from" no longer points to "r",
+ * and not from from's "free" function. */
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
+
+#define upb_ref2(r, from) \
+    upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from)
+#define upb_unref2(r, from) \
+    upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from)
+
+/* Freezes all mutable object reachable by ref2() refs from the given roots.
+ * This will split refcounting groups into precise SCC groups, so that
+ * refcounting of frozen objects can be more aggressive.  If memory allocation
+ * fails, or if more than 2**31 mutable objects are reachable from "roots", or
+ * if the maximum depth of the graph exceeds "maxdepth", false is returned and
+ * the objects are unchanged.
+ *
+ * After this operation succeeds, the objects are frozen/const, and may not be
+ * used through non-const pointers.  In particular, they may not be passed as
+ * the second parameter of upb_refcounted_{ref,unref}2().  On the upside, all
+ * operations on frozen refcounteds are threadsafe, and objects will be freed
+ * at the precise moment that they become unreachable.
+ *
+ * Caller must own refs on each object in the "roots" list. */
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth);
+
+/* Shared by all compiled-in refcounted objects. */
+extern uint32_t static_refcount;
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ Wrappers. */
+namespace upb {
+inline bool RefCounted::IsFrozen() const {
+  return upb_refcounted_isfrozen(this);
+}
+inline void RefCounted::Ref(const void *owner) const {
+  upb_refcounted_ref(this, owner);
+}
+inline void RefCounted::Unref(const void *owner) const {
+  upb_refcounted_unref(this, owner);
+}
+inline void RefCounted::DonateRef(const void *from, const void *to) const {
+  upb_refcounted_donateref(this, from, to);
+}
+inline void RefCounted::CheckRef(const void *owner) const {
+  upb_refcounted_checkref(this, owner);
+}
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_REFCOUNT_H_ */
+
+#ifdef __cplusplus
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class MessageDef;
+class OneofDef;
+}
+#endif
+
+UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted)
+
+/* The maximum message depth that the type graph can have.  This is a resource
+ * limit for the C stack since we sometimes need to recursively traverse the
+ * graph.  Cycles are ok; the traversal will stop when it detects a cycle, but
+ * we must hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Def::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_MESSAGE_DEPTH 64
+
+
+/* upb::Def: base class for defs  *********************************************/
+
+/* All the different kind of defs we support.  These correspond 1:1 with
+ * declarations in a .proto file. */
+typedef enum {
+  UPB_DEF_MSG,
+  UPB_DEF_FIELD,
+  UPB_DEF_ENUM,
+  UPB_DEF_ONEOF,
+  UPB_DEF_SERVICE,   /* Not yet implemented. */
+  UPB_DEF_ANY = -1   /* Wildcard for upb_symtab_get*() */
+} upb_deftype_t;
+
+#ifdef __cplusplus
+
+/* The base class of all defs.  Its base is upb::RefCounted (use upb::upcast()
+ * to convert). */
+class upb::Def {
+ public:
+  typedef upb_deftype_t Type;
+
+  Def* Dup(const void *owner) const;
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  Type def_type() const;
+
+  /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */
+  const char *full_name() const;
+
+  /* The def must be mutable.  Caller retains ownership of fullname.  Defs are
+   * not required to have a name; if a def has no name when it is frozen, it
+   * will remain an anonymous def.  On failure, returns false and details in "s"
+   * if non-NULL. */
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string &fullname, upb::Status* s);
+
+  /* Freezes the given defs; this validates all constraints and marks the defs
+   * as frozen (read-only).  "defs" may not contain any fielddefs, but fields
+   * of any msgdefs will be frozen.
+   *
+   * Symbolic references to sub-types and enum defaults must have already been
+   * resolved.  Any mutable defs reachable from any of "defs" must also be in
+   * the list; more formally, "defs" must be a transitive closure of mutable
+   * defs.
+   *
+   * After this operation succeeds, the finalized defs must only be accessed
+   * through a const pointer! */
+  static bool Freeze(Def* const* defs, int n, Status* status);
+  static bool Freeze(const std::vector<Def*>& defs, Status* status);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Def, upb::Def)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_def *upb_def_dup(const upb_def *def, const void *owner);
+
+/* Include upb_refcounted methods like upb_def_ref()/upb_def_unref(). */
+UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast)
+
+upb_deftype_t upb_def_type(const upb_def *d);
+const char *upb_def_fullname(const upb_def *d);
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s);
+bool upb_def_freeze(upb_def *const *defs, int n, upb_status *s);
+
+UPB_END_EXTERN_C
+
+
+/* upb::Def casts *************************************************************/
+
+#ifdef __cplusplus
+#define UPB_CPP_CASTS(cname, cpptype)                                          \
+  namespace upb {                                                              \
+  template <>                                                                  \
+  inline cpptype *down_cast<cpptype *, Def>(Def * def) {                       \
+    return upb_downcast_##cname##_mutable(def);                                \
+  }                                                                            \
+  template <>                                                                  \
+  inline cpptype *dyn_cast<cpptype *, Def>(Def * def) {                        \
+    return upb_dyncast_##cname##_mutable(def);                                 \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, const Def>(                 \
+      const Def *def) {                                                        \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, const Def>(const Def *def) { \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, Def>(Def * def) {           \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, Def>(Def * def) {            \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  }  /* namespace upb */
+#else
+#define UPB_CPP_CASTS(cname, cpptype)
+#endif  /* __cplusplus */
+
+/* Dynamic casts, for determining if a def is of a particular type at runtime.
+ * Downcasts, for when some wants to assert that a def is of a particular type.
+ * These are only checked if we are building debug. */
+#define UPB_DEF_CASTS(lower, upper, cpptype)                               \
+  UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) {  \
+    if (upb_def_type(def) != UPB_DEF_##upper) return NULL;                 \
+    return (upb_##lower *)def;                                             \
+  }                                                                        \
+  UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \
+    assert(upb_def_type(def) == UPB_DEF_##upper);                          \
+    return (const upb_##lower *)def;                                       \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) {    \
+    return (upb_##lower *)upb_dyncast_##lower(def);                        \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) {   \
+    return (upb_##lower *)upb_downcast_##lower(def);                       \
+  }                                                                        \
+  UPB_CPP_CASTS(lower, cpptype)
+
+#define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members)             \
+  UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, cppmethods,            \
+                   members)                                                    \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+#define UPB_DECLARE_DEF_TYPE(cppname, lower, upper) \
+  UPB_DECLARE_DERIVED_TYPE2(cppname, upb::Def, upb::RefCounted, \
+                            upb_ ## lower, upb_def, upb_refcounted) \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD)
+UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG)
+UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM)
+UPB_DECLARE_DEF_TYPE(upb::OneofDef, oneofdef, ONEOF)
+
+#undef UPB_DECLARE_DEF_TYPE
+#undef UPB_DEF_CASTS
+#undef UPB_CPP_CASTS
+
+
+/* upb::FieldDef **************************************************************/
+
+/* The types a field can have.  Note that this list is not identical to the
+ * types defined in descriptor.proto, which gives INT32 and SINT32 separate
+ * types (we distinguish the two with the "integer encoding" enum below). */
+typedef enum {
+  UPB_TYPE_FLOAT    = 1,
+  UPB_TYPE_DOUBLE   = 2,
+  UPB_TYPE_BOOL     = 3,
+  UPB_TYPE_STRING   = 4,
+  UPB_TYPE_BYTES    = 5,
+  UPB_TYPE_MESSAGE  = 6,
+  UPB_TYPE_ENUM     = 7,  /* Enum values are int32. */
+  UPB_TYPE_INT32    = 8,
+  UPB_TYPE_UINT32   = 9,
+  UPB_TYPE_INT64    = 10,
+  UPB_TYPE_UINT64   = 11
+} upb_fieldtype_t;
+
+/* The repeated-ness of each field; this matches descriptor.proto. */
+typedef enum {
+  UPB_LABEL_OPTIONAL = 1,
+  UPB_LABEL_REQUIRED = 2,
+  UPB_LABEL_REPEATED = 3
+} upb_label_t;
+
+/* How integers should be encoded in serializations that offer multiple
+ * integer encoding methods. */
+typedef enum {
+  UPB_INTFMT_VARIABLE = 1,
+  UPB_INTFMT_FIXED = 2,
+  UPB_INTFMT_ZIGZAG = 3   /* Only for signed types (INT32/INT64). */
+} upb_intfmt_t;
+
+/* Descriptor types, as defined in descriptor.proto. */
+typedef enum {
+  UPB_DESCRIPTOR_TYPE_DOUBLE   = 1,
+  UPB_DESCRIPTOR_TYPE_FLOAT    = 2,
+  UPB_DESCRIPTOR_TYPE_INT64    = 3,
+  UPB_DESCRIPTOR_TYPE_UINT64   = 4,
+  UPB_DESCRIPTOR_TYPE_INT32    = 5,
+  UPB_DESCRIPTOR_TYPE_FIXED64  = 6,
+  UPB_DESCRIPTOR_TYPE_FIXED32  = 7,
+  UPB_DESCRIPTOR_TYPE_BOOL     = 8,
+  UPB_DESCRIPTOR_TYPE_STRING   = 9,
+  UPB_DESCRIPTOR_TYPE_GROUP    = 10,
+  UPB_DESCRIPTOR_TYPE_MESSAGE  = 11,
+  UPB_DESCRIPTOR_TYPE_BYTES    = 12,
+  UPB_DESCRIPTOR_TYPE_UINT32   = 13,
+  UPB_DESCRIPTOR_TYPE_ENUM     = 14,
+  UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
+  UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
+  UPB_DESCRIPTOR_TYPE_SINT32   = 17,
+  UPB_DESCRIPTOR_TYPE_SINT64   = 18
+} upb_descriptortype_t;
+
+/* Maximum field number allowed for FieldDefs.  This is an inherent limit of the
+ * protobuf wire format. */
+#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
+
+#ifdef __cplusplus
+
+/* A upb_fielddef describes a single field in a message.  It is most often
+ * found as a part of a upb_msgdef, but can also stand alone to represent
+ * an extension.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::FieldDef {
+ public:
+  typedef upb_fieldtype_t Type;
+  typedef upb_label_t Label;
+  typedef upb_intfmt_t IntegerFormat;
+  typedef upb_descriptortype_t DescriptorType;
+
+  /* These return true if the given value is a valid member of the enumeration. */
+  static bool CheckType(int32_t val);
+  static bool CheckLabel(int32_t val);
+  static bool CheckDescriptorType(int32_t val);
+  static bool CheckIntegerFormat(int32_t val);
+
+  /* These convert to the given enumeration; they require that the value is
+   * valid. */
+  static Type ConvertType(int32_t val);
+  static Label ConvertLabel(int32_t val);
+  static DescriptorType ConvertDescriptorType(int32_t val);
+  static IntegerFormat ConvertIntegerFormat(int32_t val);
+
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<FieldDef> New();
+
+  /* Duplicates the given field, returning NULL if memory allocation failed.
+   * When a fielddef is duplicated, the subdef (if any) is made symbolic if it
+   * wasn't already.  If the subdef is set but has no name (which is possible
+   * since msgdefs are not required to have a name) the new fielddef's subdef
+   * will be unset. */
+  FieldDef* Dup(const void* owner) const;
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+
+  bool type_is_set() const;  /* set_[descriptor_]type() has been called? */
+  Type type() const;         /* Requires that type_is_set() == true. */
+  Label label() const;       /* Defaults to UPB_LABEL_OPTIONAL. */
+  const char* name() const;  /* NULL if uninitialized. */
+  uint32_t number() const;   /* Returns 0 if uninitialized. */
+  bool is_extension() const;
+
+  /* For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false,
+   * indicates whether this field should have lazy parsing handlers that yield
+   * the unparsed string for the submessage.
+   *
+   * TODO(haberman): I think we want to move this into a FieldOptions container
+   * when we add support for custom options (the FieldOptions struct will
+   * contain both regular FieldOptions like "lazy" *and* custom options). */
+  bool lazy() const;
+
+  /* For non-string, non-submessage fields, this indicates whether binary
+   * protobufs are encoded in packed or non-packed format.
+   *
+   * TODO(haberman): see note above about putting options like this into a
+   * FieldOptions container. */
+  bool packed() const;
+
+  /* An integer that can be used as an index into an array of fields for
+   * whatever message this field belongs to.  Guaranteed to be less than
+   * f->containing_type()->field_count().  May only be accessed once the def has
+   * been finalized. */
+  int index() const;
+
+  /* The MessageDef to which this field belongs.
+   *
+   * If this field has been added to a MessageDef, that message can be retrieved
+   * directly (this is always the case for frozen FieldDefs).
+   *
+   * If the field has not yet been added to a MessageDef, you can set the name
+   * of the containing type symbolically instead.  This is mostly useful for
+   * extensions, where the extension is declared separately from the message. */
+  const MessageDef* containing_type() const;
+  const char* containing_type_name();
+
+  /* The OneofDef to which this field belongs, or NULL if this field is not part
+   * of a oneof. */
+  const OneofDef* containing_oneof() const;
+
+  /* The field's type according to the enum in descriptor.proto.  This is not
+   * the same as UPB_TYPE_*, because it distinguishes between (for example)
+   * INT32 and SINT32, whereas our "type" enum does not.  This return of
+   * descriptor_type() is a function of type(), integer_format(), and
+   * is_tag_delimited().  Likewise set_descriptor_type() sets all three
+   * appropriately. */
+  DescriptorType descriptor_type() const;
+
+  /* Convenient field type tests. */
+  bool IsSubMessage() const;
+  bool IsString() const;
+  bool IsSequence() const;
+  bool IsPrimitive() const;
+  bool IsMap() const;
+
+  /* How integers are encoded.  Only meaningful for integer types.
+   * Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes. */
+  IntegerFormat integer_format() const;
+
+  /* Whether a submessage field is tag-delimited or not (if false, then
+   * length-delimited).  May only be set when type() == UPB_TYPE_MESSAGE. */
+  bool is_tag_delimited() const;
+
+  /* Returns the non-string default value for this fielddef, which may either
+   * be something the client set explicitly or the "default default" (0 for
+   * numbers, empty for strings).  The field's type indicates the type of the
+   * returned value, except for enum fields that are still mutable.
+   *
+   * Requires that the given function matches the field's current type. */
+  int64_t default_int64() const;
+  int32_t default_int32() const;
+  uint64_t default_uint64() const;
+  uint32_t default_uint32() const;
+  bool default_bool() const;
+  float default_float() const;
+  double default_double() const;
+
+  /* The resulting string is always NULL-terminated.  If non-NULL, the length
+   * will be stored in *len. */
+  const char *default_string(size_t* len) const;
+
+  /* For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either
+   * string or int32, and both of these methods will always return true.
+   *
+   * For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated.
+   * Enum defaults are unusual. They can be specified either as string or int32,
+   * but to be valid the enum must have that value as a member.  And if no
+   * default is specified, the "default default" comes from the EnumDef.
+   *
+   * We allow reading the default as either an int32 or a string, but only if
+   * we have a meaningful value to report.  We have a meaningful value if it was
+   * set explicitly, or if we could get the "default default" from the EnumDef.
+   * Also if you explicitly set the name and we find the number in the EnumDef */
+  bool EnumHasStringDefault() const;
+  bool EnumHasInt32Default() const;
+
+  /* Submessage and enum fields must reference a "subdef", which is the
+   * upb::MessageDef or upb::EnumDef that defines their type.  Note that when
+   * the FieldDef is mutable it may not have a subdef *yet*, but this function
+   * still returns true to indicate that the field's type requires a subdef. */
+  bool HasSubDef() const;
+
+  /* Returns the enum or submessage def for this field, if any.  The field's
+   * type must match (ie. you may only call enum_subdef() for fields where
+   * type() == UPB_TYPE_ENUM).  Returns NULL if the subdef has not been set or
+   * is currently set symbolically. */
+  const EnumDef* enum_subdef() const;
+  const MessageDef* message_subdef() const;
+
+  /* Returns the generic subdef for this field.  Requires that HasSubDef() (ie.
+   * only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields). */
+  const Def* subdef() const;
+
+  /* Returns the symbolic name of the subdef.  If the subdef is currently set
+   * unresolved (ie. set symbolically) returns the symbolic name.  If it has
+   * been resolved to a specific subdef, returns the name from that subdef. */
+  const char* subdef_name() const;
+
+  /* Setters (non-const methods), only valid for mutable FieldDefs! ***********/
+
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string& fullname, upb::Status* s);
+
+  /* This may only be called if containing_type() == NULL (ie. the field has not
+   * been added to a message yet). */
+  bool set_containing_type_name(const char *name, Status* status);
+  bool set_containing_type_name(const std::string& name, Status* status);
+
+  /* Defaults to false.  When we freeze, we ensure that this can only be true
+   * for length-delimited message fields.  Prior to freezing this can be true or
+   * false with no restrictions. */
+  void set_lazy(bool lazy);
+
+  /* Defaults to true.  Sets whether this field is encoded in packed format. */
+  void set_packed(bool packed);
+
+  /* "type" or "descriptor_type" MUST be set explicitly before the fielddef is
+   * finalized.  These setters require that the enum value is valid; if the
+   * value did not come directly from an enum constant, the caller should
+   * validate it first with the functions above (CheckFieldType(), etc). */
+  void set_type(Type type);
+  void set_label(Label label);
+  void set_descriptor_type(DescriptorType type);
+  void set_is_extension(bool is_extension);
+
+  /* "number" and "name" must be set before the FieldDef is added to a
+   * MessageDef, and may not be set after that.
+   *
+   * "name" is the same as full_name()/set_full_name(), but since fielddefs
+   * most often use simple, non-qualified names, we provide this accessor
+   * also.  Generally only extensions will want to think of this name as
+   * fully-qualified. */
+  bool set_number(uint32_t number, upb::Status* s);
+  bool set_name(const char* name, upb::Status* s);
+  bool set_name(const std::string& name, upb::Status* s);
+
+  void set_integer_format(IntegerFormat format);
+  bool set_tag_delimited(bool tag_delimited, upb::Status* s);
+
+  /* Sets default value for the field.  The call must exactly match the type
+   * of the field.  Enum fields may use either setint32 or setstring to set
+   * the default numerically or symbolically, respectively, but symbolic
+   * defaults must be resolved before finalizing (see ResolveEnumDefault()).
+   *
+   * Changing the type of a field will reset its default. */
+  void set_default_int64(int64_t val);
+  void set_default_int32(int32_t val);
+  void set_default_uint64(uint64_t val);
+  void set_default_uint32(uint32_t val);
+  void set_default_bool(bool val);
+  void set_default_float(float val);
+  void set_default_double(double val);
+  bool set_default_string(const void *str, size_t len, Status *s);
+  bool set_default_string(const std::string &str, Status *s);
+  void set_default_cstr(const char *str, Status *s);
+
+  /* Before a fielddef is frozen, its subdef may be set either directly (with a
+   * upb::Def*) or symbolically.  Symbolic refs must be resolved before the
+   * containing msgdef can be frozen (see upb_resolve() above).  upb always
+   * guarantees that any def reachable from a live def will also be kept alive.
+   *
+   * Both methods require that upb_hassubdef(f) (so the type must be set prior
+   * to calling these methods).  Returns false if this is not the case, or if
+   * the given subdef is not of the correct type.  The subdef is reset if the
+   * field's type is changed.  The subdef can be set to NULL to clear it. */
+  bool set_subdef(const Def* subdef, Status* s);
+  bool set_enum_subdef(const EnumDef* subdef, Status* s);
+  bool set_message_subdef(const MessageDef* subdef, Status* s);
+  bool set_subdef_name(const char* name, Status* s);
+  bool set_subdef_name(const std::string &name, Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef)
+};
+
+# endif  /* defined(__cplusplus) */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_fielddef *upb_fielddef_new(const void *owner);
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner);
+
+/* Include upb_refcounted methods like upb_fielddef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2)
+
+/* Methods from upb_def. */
+const char *upb_fielddef_fullname(const upb_fielddef *f);
+bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname,
+                              upb_status *s);
+
+bool upb_fielddef_typeisset(const upb_fielddef *f);
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
+upb_label_t upb_fielddef_label(const upb_fielddef *f);
+uint32_t upb_fielddef_number(const upb_fielddef *f);
+const char *upb_fielddef_name(const upb_fielddef *f);
+bool upb_fielddef_isextension(const upb_fielddef *f);
+bool upb_fielddef_lazy(const upb_fielddef *f);
+bool upb_fielddef_packed(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
+const char *upb_fielddef_containingtypename(upb_fielddef *f);
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
+uint32_t upb_fielddef_index(const upb_fielddef *f);
+bool upb_fielddef_istagdelim(const upb_fielddef *f);
+bool upb_fielddef_issubmsg(const upb_fielddef *f);
+bool upb_fielddef_isstring(const upb_fielddef *f);
+bool upb_fielddef_isseq(const upb_fielddef *f);
+bool upb_fielddef_isprimitive(const upb_fielddef *f);
+bool upb_fielddef_ismap(const upb_fielddef *f);
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f);
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f);
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f);
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f);
+bool upb_fielddef_defaultbool(const upb_fielddef *f);
+float upb_fielddef_defaultfloat(const upb_fielddef *f);
+double upb_fielddef_defaultdouble(const upb_fielddef *f);
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f);
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f);
+bool upb_fielddef_hassubdef(const upb_fielddef *f);
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
+const char *upb_fielddef_subdefname(const upb_fielddef *f);
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type);
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type);
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label);
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s);
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s);
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension);
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy);
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed);
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt);
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim);
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val);
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val);
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val);
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val);
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val);
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val);
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val);
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s);
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s);
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s);
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s);
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s);
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s);
+
+bool upb_fielddef_checklabel(int32_t label);
+bool upb_fielddef_checktype(int32_t type);
+bool upb_fielddef_checkdescriptortype(int32_t type);
+bool upb_fielddef_checkintfmt(int32_t fmt);
+
+UPB_END_EXTERN_C
+
+
+/* upb::MessageDef ************************************************************/
+
+typedef upb_inttable_iter upb_msg_field_iter;
+typedef upb_strtable_iter upb_msg_oneof_iter;
+
+#ifdef __cplusplus
+
+/* Structure that describes a single .proto message type.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::MessageDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<MessageDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this MessageDef.
+   * WARNING: this will fail if this message has any unfrozen submessages!
+   * Messages with cycles must be frozen as a batch using upb::Def::Freeze(). */
+  bool Freeze(Status* s);
+
+  /* The number of fields that belong to the MessageDef. */
+  int field_count() const;
+
+  /* The number of oneofs that belong to the MessageDef. */
+  int oneof_count() const;
+
+  /* Adds a field (upb_fielddef object) to a msgdef.  Requires that the msgdef
+   * and the fielddefs are mutable.  The fielddef's name and number must be
+   * set, and the message may not already contain any field with this name or
+   * number, and this fielddef may not be part of another message.  In error
+   * cases false is returned and the msgdef is unchanged.
+   *
+   * If the given field is part of a oneof, this call succeeds if and only if
+   * that oneof is already part of this msgdef. (Note that adding a oneof to a
+   * msgdef automatically adds all of its fields to the msgdef at the time that
+   * the oneof is added, so it is usually more idiomatic to add the oneof's
+   * fields first then add the oneof to the msgdef. This case is supported for
+   * convenience.)
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* f, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
+
+  /* Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef,
+   * oneof, and any fielddefs are mutable, that the fielddefs contained in the
+   * oneof do not have any name or number conflicts with existing fields in the
+   * msgdef, and that the oneof's name is unique among all oneofs in the msgdef.
+   * If the oneof is added successfully, all of its fields will be added
+   * directly to the msgdef as well. In error cases, false is returned and the
+   * msgdef is unchanged. */
+  bool AddOneof(OneofDef* o, Status* s);
+  bool AddOneof(const reffed_ptr<OneofDef>& o, Status* s);
+
+  /* These return NULL if the field is not found. */
+  FieldDef* FindFieldByNumber(uint32_t number);
+  FieldDef* FindFieldByName(const char *name, size_t len);
+  const FieldDef* FindFieldByNumber(uint32_t number) const;
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+
+
+  FieldDef* FindFieldByName(const char *name) {
+    return FindFieldByName(name, strlen(name));
+  }
+  const FieldDef* FindFieldByName(const char *name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  OneofDef* FindOneofByName(const char* name, size_t len);
+  const OneofDef* FindOneofByName(const char* name, size_t len) const;
+
+  OneofDef* FindOneofByName(const char* name) {
+    return FindOneofByName(name, strlen(name));
+  }
+  const OneofDef* FindOneofByName(const char* name) const {
+    return FindOneofByName(name, strlen(name));
+  }
+
+  template<class T>
+  OneofDef* FindOneofByName(const T& str) {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+  template<class T>
+  const OneofDef* FindOneofByName(const T& str) const {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+
+  /* Returns a new msgdef that is a copy of the given msgdef (and a copy of all
+   * the fields) but with any references to submessages broken and replaced
+   * with just the name of the submessage.  Returns NULL if memory allocation
+   * failed.
+   *
+   * TODO(haberman): which is more useful, keeping fields resolved or
+   * unresolving them?  If there's no obvious answer, Should this functionality
+   * just be moved into symtab.c? */
+  MessageDef* Dup(const void* owner) const;
+
+  /* Is this message a map entry? */
+  void setmapentry(bool map_entry);
+  bool mapentry() const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class field_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit field_iterator(MessageDef* md);
+    static field_iterator end(MessageDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const field_iterator& other) const;
+    bool operator==(const field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  class const_field_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_field_iterator(const MessageDef* md);
+    static const_field_iterator end(const MessageDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_field_iterator& other) const;
+    bool operator==(const const_field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  /* Iteration over oneofs. The order is undefined. */
+  class oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit oneof_iterator(MessageDef* md);
+    static oneof_iterator end(MessageDef* md);
+
+    void operator++();
+    OneofDef* operator*() const;
+    bool operator!=(const oneof_iterator& other) const;
+    bool operator==(const oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class const_oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_oneof_iterator(const MessageDef* md);
+    static const_oneof_iterator end(const MessageDef* md);
+
+    void operator++();
+    const OneofDef* operator*() const;
+    bool operator!=(const const_oneof_iterator& other) const;
+    bool operator==(const const_oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class FieldAccessor {
+   public:
+    explicit FieldAccessor(MessageDef* msg) : msg_(msg) {}
+    field_iterator begin() { return msg_->field_begin(); }
+    field_iterator end() { return msg_->field_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstFieldAccessor {
+   public:
+    explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_field_iterator begin() { return msg_->field_begin(); }
+    const_field_iterator end() { return msg_->field_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  class OneofAccessor {
+   public:
+    explicit OneofAccessor(MessageDef* msg) : msg_(msg) {}
+    oneof_iterator begin() { return msg_->oneof_begin(); }
+    oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstOneofAccessor {
+   public:
+    explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_oneof_iterator begin() { return msg_->oneof_begin(); }
+    const_oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  field_iterator field_begin();
+  field_iterator field_end();
+  const_field_iterator field_begin() const;
+  const_field_iterator field_end() const;
+
+  oneof_iterator oneof_begin();
+  oneof_iterator oneof_end();
+  const_oneof_iterator oneof_begin() const;
+  const_oneof_iterator oneof_end() const;
+
+  FieldAccessor fields() { return FieldAccessor(this); }
+  ConstFieldAccessor fields() const { return ConstFieldAccessor(this); }
+  OneofAccessor oneofs() { return OneofAccessor(this); }
+  ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
+
+ private:
+  UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Returns NULL if memory allocation failed. */
+upb_msgdef *upb_msgdef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_msgdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2)
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status);
+
+const char *upb_msgdef_fullname(const upb_msgdef *m);
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner);
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s);
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s);
+
+/* Field lookup in a couple of different variations:
+ *   - itof = int to field
+ *   - ntof = name to field
+ *   - ntofz = name to field, null-terminated string. */
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numfields(const upb_msgdef *m);
+
+UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
+                                                const char *name) {
+  return upb_msgdef_ntof(m, name, strlen(name));
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) {
+  return (upb_fielddef*)upb_msgdef_itof(m, i);
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
+}
+
+/* Oneof lookup:
+ *   - ntoo = name to oneof
+ *   - ntooz = name to oneof, null-terminated string. */
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
+                                               const char *name) {
+  return upb_msgdef_ntoo(m, name, strlen(name));
+}
+
+UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry);
+bool upb_msgdef_mapentry(const upb_msgdef *m);
+
+/* Well-known field tag numbers for map-entry messages. */
+#define UPB_MAPENTRY_KEY   1
+#define UPB_MAPENTRY_VALUE 2
+
+const upb_oneofdef *upb_msgdef_findoneof(const upb_msgdef *m,
+                                          const char *name);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+/* upb_msg_field_iter i;
+ * for(upb_msg_field_begin(&i, m);
+ *     !upb_msg_field_done(&i);
+ *     upb_msg_field_next(&i)) {
+ *   upb_fielddef *f = upb_msg_iter_field(&i);
+ *   // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
+void upb_msg_field_next(upb_msg_field_iter *iter);
+bool upb_msg_field_done(const upb_msg_field_iter *iter);
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
+
+/* Similar to above, we also support iterating through the oneofs in a
+ * msgdef. */
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m);
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter);
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::EnumDef ***************************************************************/
+
+typedef upb_strtable_iter upb_enum_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents an enum.  Its base class is upb::Def (convert with
+ * upb::upcast()). */
+class upb::EnumDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<EnumDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this EnumDef. */
+  bool Freeze(Status* s);
+
+  /* The value that is used as the default when no field default is specified.
+   * If not set explicitly, the first value that was added will be used.
+   * The default value must be a member of the enum.
+   * Requires that value_count() > 0. */
+  int32_t default_value() const;
+
+  /* Sets the default value.  If this value is not valid, returns false and an
+   * error message in status. */
+  bool set_default_value(int32_t val, Status* status);
+
+  /* Returns the number of values currently defined in the enum.  Note that
+   * multiple names can refer to the same number, so this may be greater than
+   * the total number of unique numbers. */
+  int value_count() const;
+
+  /* Adds a single name/number pair to the enum.  Fails if this name has
+   * already been used by another value. */
+  bool AddValue(const char* name, int32_t num, Status* status);
+  bool AddValue(const std::string& name, int32_t num, Status* status);
+
+  /* Lookups from name to integer, returning true if found. */
+  bool FindValueByName(const char* name, int32_t* num) const;
+
+  /* Finds the name corresponding to the given number, or NULL if none was
+   * found.  If more than one name corresponds to this number, returns the
+   * first one that was added. */
+  const char* FindValueByNumber(int32_t num) const;
+
+  /* Returns a new EnumDef with all the same values.  The new EnumDef will be
+   * owned by the given owner. */
+  EnumDef* Dup(const void* owner) const;
+
+  /* Iteration over name/value pairs.  The order is undefined.
+   * Adding an enum val invalidates any iterators.
+   *
+   * TODO: make compatible with range-for, with elements as pairs? */
+  class Iterator {
+   public:
+    explicit Iterator(const EnumDef*);
+
+    int32_t number();
+    const char *name();
+    bool Done();
+    void Next();
+
+   private:
+    upb_enum_iter iter_;
+  };
+
+ private:
+  UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_enumdef *upb_enumdef_new(const void *owner);
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner);
+
+/* Include upb_refcounted methods like upb_enumdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_enumdef, upb_enumdef_upcast2)
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status);
+
+/* From upb_def. */
+const char *upb_enumdef_fullname(const upb_enumdef *e);
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s);
+
+int32_t upb_enumdef_default(const upb_enumdef *e);
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s);
+int upb_enumdef_numvals(const upb_enumdef *e);
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status);
+
+/* Enum lookups:
+ * - ntoi:  look up a name with specified length.
+ * - ntoiz: look up a name provided as a null-terminated string.
+ * - iton:  look up an integer, returning the name as a null-terminated
+ *          string. */
+bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
+                      int32_t *num);
+UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
+                                  const char *name, int32_t *num) {
+  return upb_enumdef_ntoi(e, name, strlen(name), num);
+}
+const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
+
+/*  upb_enum_iter i;
+ *  for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
+void upb_enum_next(upb_enum_iter *iter);
+bool upb_enum_done(upb_enum_iter *iter);
+const char *upb_enum_iter_name(upb_enum_iter *iter);
+int32_t upb_enum_iter_number(upb_enum_iter *iter);
+
+UPB_END_EXTERN_C
+
+/* upb::OneofDef **************************************************************/
+
+typedef upb_inttable_iter upb_oneof_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents a oneof.  Its base class is upb::Def (convert with
+ * upb::upcast()). */
+class upb::OneofDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<OneofDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+
+  /* Returns the MessageDef that owns this OneofDef. */
+  const MessageDef* containing_type() const;
+
+  /* Returns the name of this oneof. This is the name used to look up the oneof
+   * by name once added to a message def. */
+  const char* name() const;
+  bool set_name(const char* name, Status* s);
+
+  /* Returns the number of fields currently defined in the oneof. */
+  int field_count() const;
+
+  /* Adds a field to the oneof. The field must not have been added to any other
+   * oneof or msgdef. If the oneof is not yet part of a msgdef, then when the
+   * oneof is eventually added to a msgdef, all fields added to the oneof will
+   * also be added to the msgdef at that time. If the oneof is already part of a
+   * msgdef, the field must either be a part of that msgdef already, or must not
+   * be a part of any msgdef; in the latter case, the field is added to the
+   * msgdef as a part of this operation.
+   *
+   * The field may only have an OPTIONAL label, never REQUIRED or REPEATED.
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* field, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& field, Status* s);
+
+  /* Looks up by name. */
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+  FieldDef* FindFieldByName(const char* name, size_t len);
+  const FieldDef* FindFieldByName(const char* name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+  FieldDef* FindFieldByName(const char* name) {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  /* Looks up by tag number. */
+  const FieldDef* FindFieldByNumber(uint32_t num) const;
+
+  /* Returns a new OneofDef with all the same fields. The OneofDef will be owned
+   * by the given owner. */
+  OneofDef* Dup(const void* owner) const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit iterator(OneofDef* md);
+    static iterator end(OneofDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const iterator& other) const;
+    bool operator==(const iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  class const_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_iterator(const OneofDef* md);
+    static const_iterator end(const OneofDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_iterator& other) const;
+    bool operator==(const const_iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_oneofdef *upb_oneofdef_new(const void *owner);
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
+
+/* Include upb_refcounted methods like upb_oneofdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast2)
+
+const char *upb_oneofdef_name(const upb_oneofdef *o);
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
+int upb_oneofdef_numfields(const upb_oneofdef *o);
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s);
+
+/* Oneof lookups:
+ * - ntof:  look up a field by name.
+ * - ntofz: look up a field by name (as a null-terminated string).
+ * - itof:  look up a field by number. */
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length);
+UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
+                                                  const char *name) {
+  return upb_oneofdef_ntof(o, name, strlen(name));
+}
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
+
+/*  upb_oneof_iter i;
+ *  for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
+void upb_oneof_next(upb_oneof_iter *iter);
+bool upb_oneof_done(upb_oneof_iter *iter);
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
+void upb_oneof_iter_setdone(upb_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+UPB_INLINE const char* upb_safecstr(const std::string& str) {
+  assert(str.size() == std::strlen(str.c_str()));
+  return str.c_str();
+}
+
+/* Inline C++ wrappers. */
+namespace upb {
+
+inline Def* Def::Dup(const void* owner) const {
+  return upb_def_dup(this, owner);
+}
+inline Def::Type Def::def_type() const { return upb_def_type(this); }
+inline const char* Def::full_name() const { return upb_def_fullname(this); }
+inline bool Def::set_full_name(const char* fullname, Status* s) {
+  return upb_def_setfullname(this, fullname, s);
+}
+inline bool Def::set_full_name(const std::string& fullname, Status* s) {
+  return upb_def_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool Def::Freeze(Def* const* defs, int n, Status* status) {
+  return upb_def_freeze(defs, n, status);
+}
+inline bool Def::Freeze(const std::vector<Def*>& defs, Status* status) {
+  return upb_def_freeze((Def* const*)&defs[0], defs.size(), status);
+}
+
+inline bool FieldDef::CheckType(int32_t val) {
+  return upb_fielddef_checktype(val);
+}
+inline bool FieldDef::CheckLabel(int32_t val) {
+  return upb_fielddef_checklabel(val);
+}
+inline bool FieldDef::CheckDescriptorType(int32_t val) {
+  return upb_fielddef_checkdescriptortype(val);
+}
+inline bool FieldDef::CheckIntegerFormat(int32_t val) {
+  return upb_fielddef_checkintfmt(val);
+}
+inline FieldDef::Type FieldDef::ConvertType(int32_t val) {
+  assert(CheckType(val));
+  return static_cast<FieldDef::Type>(val);
+}
+inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) {
+  assert(CheckLabel(val));
+  return static_cast<FieldDef::Label>(val);
+}
+inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) {
+  assert(CheckDescriptorType(val));
+  return static_cast<FieldDef::DescriptorType>(val);
+}
+inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
+  assert(CheckIntegerFormat(val));
+  return static_cast<FieldDef::IntegerFormat>(val);
+}
+
+inline reffed_ptr<FieldDef> FieldDef::New() {
+  upb_fielddef *f = upb_fielddef_new(&f);
+  return reffed_ptr<FieldDef>(f, &f);
+}
+inline FieldDef* FieldDef::Dup(const void* owner) const {
+  return upb_fielddef_dup(this, owner);
+}
+inline const char* FieldDef::full_name() const {
+  return upb_fielddef_fullname(this);
+}
+inline bool FieldDef::set_full_name(const char* fullname, Status* s) {
+  return upb_fielddef_setfullname(this, fullname, s);
+}
+inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_fielddef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool FieldDef::type_is_set() const {
+  return upb_fielddef_typeisset(this);
+}
+inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); }
+inline FieldDef::DescriptorType FieldDef::descriptor_type() const {
+  return upb_fielddef_descriptortype(this);
+}
+inline FieldDef::Label FieldDef::label() const {
+  return upb_fielddef_label(this);
+}
+inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); }
+inline const char* FieldDef::name() const { return upb_fielddef_name(this); }
+inline bool FieldDef::is_extension() const {
+  return upb_fielddef_isextension(this);
+}
+inline bool FieldDef::lazy() const {
+  return upb_fielddef_lazy(this);
+}
+inline void FieldDef::set_lazy(bool lazy) {
+  upb_fielddef_setlazy(this, lazy);
+}
+inline bool FieldDef::packed() const {
+  return upb_fielddef_packed(this);
+}
+inline void FieldDef::set_packed(bool packed) {
+  upb_fielddef_setpacked(this, packed);
+}
+inline const MessageDef* FieldDef::containing_type() const {
+  return upb_fielddef_containingtype(this);
+}
+inline const OneofDef* FieldDef::containing_oneof() const {
+  return upb_fielddef_containingoneof(this);
+}
+inline const char* FieldDef::containing_type_name() {
+  return upb_fielddef_containingtypename(this);
+}
+inline bool FieldDef::set_number(uint32_t number, Status* s) {
+  return upb_fielddef_setnumber(this, number, s);
+}
+inline bool FieldDef::set_name(const char *name, Status* s) {
+  return upb_fielddef_setname(this, name, s);
+}
+inline bool FieldDef::set_name(const std::string& name, Status* s) {
+  return upb_fielddef_setname(this, upb_safecstr(name), s);
+}
+inline bool FieldDef::set_containing_type_name(const char *name, Status* s) {
+  return upb_fielddef_setcontainingtypename(this, name, s);
+}
+inline bool FieldDef::set_containing_type_name(const std::string &name,
+                                               Status *s) {
+  return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s);
+}
+inline void FieldDef::set_type(upb_fieldtype_t type) {
+  upb_fielddef_settype(this, type);
+}
+inline void FieldDef::set_is_extension(bool is_extension) {
+  upb_fielddef_setisextension(this, is_extension);
+}
+inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) {
+  upb_fielddef_setdescriptortype(this, type);
+}
+inline void FieldDef::set_label(upb_label_t label) {
+  upb_fielddef_setlabel(this, label);
+}
+inline bool FieldDef::IsSubMessage() const {
+  return upb_fielddef_issubmsg(this);
+}
+inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); }
+inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); }
+inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); }
+inline int64_t FieldDef::default_int64() const {
+  return upb_fielddef_defaultint64(this);
+}
+inline int32_t FieldDef::default_int32() const {
+  return upb_fielddef_defaultint32(this);
+}
+inline uint64_t FieldDef::default_uint64() const {
+  return upb_fielddef_defaultuint64(this);
+}
+inline uint32_t FieldDef::default_uint32() const {
+  return upb_fielddef_defaultuint32(this);
+}
+inline bool FieldDef::default_bool() const {
+  return upb_fielddef_defaultbool(this);
+}
+inline float FieldDef::default_float() const {
+  return upb_fielddef_defaultfloat(this);
+}
+inline double FieldDef::default_double() const {
+  return upb_fielddef_defaultdouble(this);
+}
+inline const char* FieldDef::default_string(size_t* len) const {
+  return upb_fielddef_defaultstr(this, len);
+}
+inline void FieldDef::set_default_int64(int64_t value) {
+  upb_fielddef_setdefaultint64(this, value);
+}
+inline void FieldDef::set_default_int32(int32_t value) {
+  upb_fielddef_setdefaultint32(this, value);
+}
+inline void FieldDef::set_default_uint64(uint64_t value) {
+  upb_fielddef_setdefaultuint64(this, value);
+}
+inline void FieldDef::set_default_uint32(uint32_t value) {
+  upb_fielddef_setdefaultuint32(this, value);
+}
+inline void FieldDef::set_default_bool(bool value) {
+  upb_fielddef_setdefaultbool(this, value);
+}
+inline void FieldDef::set_default_float(float value) {
+  upb_fielddef_setdefaultfloat(this, value);
+}
+inline void FieldDef::set_default_double(double value) {
+  upb_fielddef_setdefaultdouble(this, value);
+}
+inline bool FieldDef::set_default_string(const void *str, size_t len,
+                                         Status *s) {
+  return upb_fielddef_setdefaultstr(this, str, len, s);
+}
+inline bool FieldDef::set_default_string(const std::string& str, Status* s) {
+  return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s);
+}
+inline void FieldDef::set_default_cstr(const char* str, Status* s) {
+  return upb_fielddef_setdefaultcstr(this, str, s);
+}
+inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); }
+inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); }
+inline const MessageDef *FieldDef::message_subdef() const {
+  return upb_fielddef_msgsubdef(this);
+}
+inline const EnumDef *FieldDef::enum_subdef() const {
+  return upb_fielddef_enumsubdef(this);
+}
+inline const char* FieldDef::subdef_name() const {
+  return upb_fielddef_subdefname(this);
+}
+inline bool FieldDef::set_subdef(const Def* subdef, Status* s) {
+  return upb_fielddef_setsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) {
+  return upb_fielddef_setenumsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) {
+  return upb_fielddef_setmsgsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_subdef_name(const char* name, Status* s) {
+  return upb_fielddef_setsubdefname(this, name, s);
+}
+inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
+  return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
+}
+
+inline reffed_ptr<MessageDef> MessageDef::New() {
+  upb_msgdef *m = upb_msgdef_new(&m);
+  return reffed_ptr<MessageDef>(m, &m);
+}
+inline const char *MessageDef::full_name() const {
+  return upb_msgdef_fullname(this);
+}
+inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
+  return upb_msgdef_setfullname(this, fullname, s);
+}
+inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool MessageDef::Freeze(Status* status) {
+  return upb_msgdef_freeze(this, status);
+}
+inline int MessageDef::field_count() const {
+  return upb_msgdef_numfields(this);
+}
+inline int MessageDef::oneof_count() const {
+  return upb_msgdef_numoneofs(this);
+}
+inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
+  return upb_msgdef_addfield(this, f, NULL, s);
+}
+inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
+  return upb_msgdef_addfield(this, f.get(), NULL, s);
+}
+inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) {
+  return upb_msgdef_addoneof(this, o, NULL, s);
+}
+inline bool MessageDef::AddOneof(const reffed_ptr<OneofDef>& o, Status* s) {
+  return upb_msgdef_addoneof(this, o.get(), NULL, s);
+}
+inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
+  return upb_msgdef_itof_mutable(this, number);
+}
+inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) {
+  return upb_msgdef_ntof_mutable(this, name, len);
+}
+inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const {
+  return upb_msgdef_itof(this, number);
+}
+inline const FieldDef *MessageDef::FindFieldByName(const char *name,
+                                                   size_t len) const {
+  return upb_msgdef_ntof(this, name, len);
+}
+inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) {
+  return upb_msgdef_ntoo_mutable(this, name, len);
+}
+inline const OneofDef* MessageDef::FindOneofByName(const char* name,
+                                                   size_t len) const {
+  return upb_msgdef_ntoo(this, name, len);
+}
+inline MessageDef* MessageDef::Dup(const void *owner) const {
+  return upb_msgdef_dup(this, owner);
+}
+inline void MessageDef::setmapentry(bool map_entry) {
+  upb_msgdef_setmapentry(this, map_entry);
+}
+inline bool MessageDef::mapentry() const {
+  return upb_msgdef_mapentry(this);
+}
+inline MessageDef::field_iterator MessageDef::field_begin() {
+  return field_iterator(this);
+}
+inline MessageDef::field_iterator MessageDef::field_end() {
+  return field_iterator::end(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_begin() const {
+  return const_field_iterator(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_end() const {
+  return const_field_iterator::end(this);
+}
+
+inline MessageDef::oneof_iterator MessageDef::oneof_begin() {
+  return oneof_iterator(this);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_end() {
+  return oneof_iterator::end(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const {
+  return const_oneof_iterator(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const {
+  return const_oneof_iterator::end(this);
+}
+
+inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::field_iterator MessageDef::field_iterator::end(
+    MessageDef* md) {
+  MessageDef::field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* MessageDef::field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::field_iterator::operator==(
+    const field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::field_iterator::operator!=(
+    const field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_field_iterator::const_field_iterator(
+    const MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* MessageDef::const_field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::const_field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::const_field_iterator::operator==(
+    const const_field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_field_iterator::operator!=(
+    const const_field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end(
+    MessageDef* md) {
+  MessageDef::oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline OneofDef* MessageDef::oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::oneof_iterator::operator==(
+    const oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::oneof_iterator::operator!=(
+    const oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_oneof_iterator::const_oneof_iterator(
+    const MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::const_oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator==(
+    const const_oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator!=(
+    const const_oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline reffed_ptr<EnumDef> EnumDef::New() {
+  upb_enumdef *e = upb_enumdef_new(&e);
+  return reffed_ptr<EnumDef>(e, &e);
+}
+inline const char* EnumDef::full_name() const {
+  return upb_enumdef_fullname(this);
+}
+inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
+  return upb_enumdef_setfullname(this, fullname, s);
+}
+inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool EnumDef::Freeze(Status* status) {
+  return upb_enumdef_freeze(this, status);
+}
+inline int32_t EnumDef::default_value() const {
+  return upb_enumdef_default(this);
+}
+inline bool EnumDef::set_default_value(int32_t val, Status* status) {
+  return upb_enumdef_setdefault(this, val, status);
+}
+inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); }
+inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) {
+  return upb_enumdef_addval(this, name, num, status);
+}
+inline bool EnumDef::AddValue(const std::string& name, int32_t num,
+                              Status* status) {
+  return upb_enumdef_addval(this, upb_safecstr(name), num, status);
+}
+inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const {
+  return upb_enumdef_ntoiz(this, name, num);
+}
+inline const char* EnumDef::FindValueByNumber(int32_t num) const {
+  return upb_enumdef_iton(this, num);
+}
+inline EnumDef* EnumDef::Dup(const void* owner) const {
+  return upb_enumdef_dup(this, owner);
+}
+
+inline EnumDef::Iterator::Iterator(const EnumDef* e) {
+  upb_enum_begin(&iter_, e);
+}
+inline int32_t EnumDef::Iterator::number() {
+  return upb_enum_iter_number(&iter_);
+}
+inline const char* EnumDef::Iterator::name() {
+  return upb_enum_iter_name(&iter_);
+}
+inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); }
+inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); }
+
+inline reffed_ptr<OneofDef> OneofDef::New() {
+  upb_oneofdef *o = upb_oneofdef_new(&o);
+  return reffed_ptr<OneofDef>(o, &o);
+}
+inline const char* OneofDef::full_name() const {
+  return upb_oneofdef_name(this);
+}
+
+inline const MessageDef* OneofDef::containing_type() const {
+  return upb_oneofdef_containingtype(this);
+}
+inline const char* OneofDef::name() const {
+  return upb_oneofdef_name(this);
+}
+inline bool OneofDef::set_name(const char* name, Status* s) {
+  return upb_oneofdef_setname(this, name, s);
+}
+inline int OneofDef::field_count() const {
+  return upb_oneofdef_numfields(this);
+}
+inline bool OneofDef::AddField(FieldDef* field, Status* s) {
+  return upb_oneofdef_addfield(this, field, NULL, s);
+}
+inline bool OneofDef::AddField(const reffed_ptr<FieldDef>& field, Status* s) {
+  return upb_oneofdef_addfield(this, field.get(), NULL, s);
+}
+inline const FieldDef* OneofDef::FindFieldByName(const char* name,
+                                                 size_t len) const {
+  return upb_oneofdef_ntof(this, name, len);
+}
+inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const {
+  return upb_oneofdef_itof(this, num);
+}
+inline OneofDef::iterator OneofDef::begin() { return iterator(this); }
+inline OneofDef::iterator OneofDef::end() { return iterator::end(this); }
+inline OneofDef::const_iterator OneofDef::begin() const {
+  return const_iterator(this);
+}
+inline OneofDef::const_iterator OneofDef::end() const {
+  return const_iterator::end(this);
+}
+
+inline OneofDef::iterator::iterator(OneofDef* o) {
+  upb_oneof_begin(&iter_, o);
+}
+inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) {
+  OneofDef::iterator iter(o);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* OneofDef::iterator::operator*() const {
+  return upb_oneof_iter_field(&iter_);
+}
+inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); }
+inline bool OneofDef::iterator::operator==(const iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::iterator::operator!=(const iterator &other) const {
+  return !(*this == other);
+}
+
+inline OneofDef::const_iterator::const_iterator(const OneofDef* md) {
+  upb_oneof_begin(&iter_, md);
+}
+inline OneofDef::const_iterator OneofDef::const_iterator::end(
+    const OneofDef *md) {
+  OneofDef::const_iterator iter(md);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* OneofDef::const_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void OneofDef::const_iterator::operator++() {
+  return upb_oneof_next(&iter_);
+}
+inline bool OneofDef::const_iterator::operator==(
+    const const_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::const_iterator::operator!=(
+    const const_iterator &other) const {
+  return !(*this == other);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif /* UPB_DEF_H_ */
+/*
+** This file contains definitions of structs that should be considered private
+** and NOT stable across versions of upb.
+**
+** The only reason they are declared here and not in .c files is to allow upb
+** and the application (if desired) to embed statically-initialized instances
+** of structures like defs.
+**
+** If you include this file, all guarantees of ABI compatibility go out the
+** window!  Any code that includes this file needs to recompile against the
+** exact same version of upb that they are linking against.
+**
+** You also need to recompile if you change the value of the UPB_DEBUG_REFS
+** flag.
+*/
+
+
+#ifndef UPB_STATICINIT_H_
+#define UPB_STATICINIT_H_
+
+#ifdef __cplusplus
+/* Because of how we do our typedefs, this header can't be included from C++. */
+#error This file cannot be included from C++
+#endif
+
+/* upb_refcounted *************************************************************/
+
+
+/* upb_def ********************************************************************/
+
+struct upb_def {
+  upb_refcounted base;
+
+  const char *fullname;
+  char type;  /* A upb_deftype_t (char to save space) */
+
+  /* Used as a flag during the def's mutable stage.  Must be false unless
+   * it is currently being used by a function on the stack.  This allows
+   * us to easily determine which defs were passed into the function's
+   * current invocation. */
+  bool came_from_user;
+};
+
+#define UPB_DEF_INIT(name, type, refs, ref2s) \
+    { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false }
+
+
+/* upb_fielddef ***************************************************************/
+
+struct upb_fielddef {
+  upb_def base;
+
+  union {
+    int64_t sint;
+    uint64_t uint;
+    double dbl;
+    float flt;
+    void *bytes;
+  } defaultval;
+  union {
+    const upb_msgdef *def;  /* If !msg_is_symbolic. */
+    char *name;             /* If msg_is_symbolic. */
+  } msg;
+  union {
+    const upb_def *def;  /* If !subdef_is_symbolic. */
+    char *name;          /* If subdef_is_symbolic. */
+  } sub;  /* The msgdef or enumdef for this field, if upb_hassubdef(f). */
+  bool subdef_is_symbolic;
+  bool msg_is_symbolic;
+  const upb_oneofdef *oneof;
+  bool default_is_string;
+  bool type_is_set_;     /* False until type is explicitly set. */
+  bool is_extension_;
+  bool lazy_;
+  bool packed_;
+  upb_intfmt_t intfmt;
+  bool tagdelim;
+  upb_fieldtype_t type_;
+  upb_label_t label_;
+  uint32_t number_;
+  uint32_t selector_base;  /* Used to index into a upb::Handlers table. */
+  uint32_t index_;
+};
+
+#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy,   \
+                          packed, name, num, msgdef, subdef, selector_base,    \
+                          index, defaultval, refs, ref2s)                      \
+  {                                                                            \
+    UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef},      \
+        {subdef}, NULL, false, false,                                          \
+        type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \
+        lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \
+  }
+
+
+/* upb_msgdef *****************************************************************/
+
+struct upb_msgdef {
+  upb_def base;
+
+  size_t selector_count;
+  uint32_t submsg_field_count;
+
+  /* Tables for looking up fields by number and name. */
+  upb_inttable itof;  /* int to field */
+  upb_strtable ntof;  /* name to field */
+
+  /* Tables for looking up oneofs by name. */
+  upb_strtable ntoo;  /* name to oneof */
+
+  /* Is this a map-entry message?
+   * TODO: set this flag properly for static descriptors; regenerate
+   * descriptor.upb.c. */
+  bool map_entry;
+
+  /* TODO(haberman): proper extension ranges (there can be multiple). */
+};
+
+/* TODO: also support static initialization of the oneofs table. This will be
+ * needed if we compile in descriptors that contain oneofs. */
+#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
+                        refs, ref2s)                                          \
+  {                                                                           \
+    UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count,             \
+        submsg_field_count, itof, ntof,                                       \
+        UPB_EMPTY_STRTABLE_INIT(UPB_CTYPE_PTR), false                         \
+  }
+
+
+/* upb_enumdef ****************************************************************/
+
+struct upb_enumdef {
+  upb_def base;
+
+  upb_strtable ntoi;
+  upb_inttable iton;
+  int32_t defaultval;
+};
+
+#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \
+  { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval }
+
+
+/* upb_oneofdef ***************************************************************/
+
+struct upb_oneofdef {
+  upb_def base;
+
+  upb_strtable ntof;
+  upb_inttable itof;
+  const upb_msgdef *parent;
+};
+
+#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
+  { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof }
+
+
+/* upb_symtab *****************************************************************/
+
+struct upb_symtab {
+  upb_refcounted base;
+
+  upb_strtable symtab;
+};
+
+#define UPB_SYMTAB_INIT(symtab, refs, ref2s) \
+  { UPB_REFCOUNT_INIT(refs, ref2s), symtab }
+
+
+#endif  /* UPB_STATICINIT_H_ */
+/*
+** upb::Handlers (upb_handlers)
+**
+** A upb_handlers is like a virtual table for a upb_msgdef.  Each field of the
+** message can have associated functions that will be called when we are
+** parsing or visiting a stream of data.  This is similar to how handlers work
+** in SAX (the Simple API for XML).
+**
+** The handlers have no idea where the data is coming from, so a single set of
+** handlers could be used with two completely different data sources (for
+** example, a parser and a visitor over in-memory objects).  This decoupling is
+** the most important feature of upb, because it allows parsers and serializers
+** to be highly reusable.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_HANDLERS_H
+#define UPB_HANDLERS_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferHandle;
+class BytesHandler;
+class HandlerAttributes;
+class Handlers;
+template <class T> class Handler;
+template <class T> struct CanonicalType;
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle)
+UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler)
+UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr)
+UPB_DECLARE_DERIVED_TYPE(upb::Handlers, upb::RefCounted,
+                         upb_handlers, upb_refcounted)
+
+/* The maximum depth that the handler graph can have.  This is a resource limit
+ * for the C stack since we sometimes need to recursively traverse the graph.
+ * Cycles are ok; the traversal will stop when it detects a cycle, but we must
+ * hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Handlers::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_HANDLER_DEPTH 64
+
+/* All the different types of handlers that can be registered.
+ * Only needed for the advanced functions in upb::Handlers. */
+typedef enum {
+  UPB_HANDLER_INT32,
+  UPB_HANDLER_INT64,
+  UPB_HANDLER_UINT32,
+  UPB_HANDLER_UINT64,
+  UPB_HANDLER_FLOAT,
+  UPB_HANDLER_DOUBLE,
+  UPB_HANDLER_BOOL,
+  UPB_HANDLER_STARTSTR,
+  UPB_HANDLER_STRING,
+  UPB_HANDLER_ENDSTR,
+  UPB_HANDLER_STARTSUBMSG,
+  UPB_HANDLER_ENDSUBMSG,
+  UPB_HANDLER_STARTSEQ,
+  UPB_HANDLER_ENDSEQ
+} upb_handlertype_t;
+
+#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
+
+#define UPB_BREAK NULL
+
+/* A convenient definition for when no closure is needed. */
+extern char _upb_noclosure;
+#define UPB_NO_CLOSURE &_upb_noclosure
+
+/* A selector refers to a specific field handler in the Handlers object
+ * (for example: the STARTSUBMSG handler for field "field15"). */
+typedef int32_t upb_selector_t;
+
+UPB_BEGIN_EXTERN_C
+
+/* Forward-declares for C inline accessors.  We need to declare these here
+ * so we can "friend" them in the class declarations in C++. */
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s);
+UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s);
+
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h);
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type);
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs);
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h);
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h);
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h);
+
+UPB_END_EXTERN_C
+
+
+/* Static selectors for upb::Handlers. */
+#define UPB_STARTMSG_SELECTOR 0
+#define UPB_ENDMSG_SELECTOR 1
+#define UPB_STATIC_SELECTOR_COUNT 2
+
+/* Static selectors for upb::BytesHandler. */
+#define UPB_STARTSTR_SELECTOR 0
+#define UPB_STRING_SELECTOR 1
+#define UPB_ENDSTR_SELECTOR 2
+
+typedef void upb_handlerfree(void *d);
+
+#ifdef __cplusplus
+
+/* A set of attributes that accompanies a handler's function pointer. */
+class upb::HandlerAttributes {
+ public:
+  HandlerAttributes();
+  ~HandlerAttributes();
+
+  /* Sets the handler data that will be passed as the second parameter of the
+   * handler.  To free this pointer when the handlers are freed, call
+   * Handlers::AddCleanup(). */
+  bool SetHandlerData(const void *handler_data);
+  const void* handler_data() const;
+
+  /* Use this to specify the type of the closure.  This will be checked against
+   * all other closure types for handler that use the same closure.
+   * Registration will fail if this does not match all other non-NULL closure
+   * types. */
+  bool SetClosureType(const void *closure_type);
+  const void* closure_type() const;
+
+  /* Use this to specify the type of the returned closure.  Only used for
+   * Start*{String,SubMessage,Sequence} handlers.  This must match the closure
+   * type of any handlers that use it (for example, the StringBuf handler must
+   * match the closure returned from StartString). */
+  bool SetReturnClosureType(const void *return_closure_type);
+  const void* return_closure_type() const;
+
+  /* Set to indicate that the handler always returns "ok" (either "true" or a
+   * non-NULL closure).  This is a hint that can allow code generators to
+   * generate more efficient code. */
+  bool SetAlwaysOk(bool always_ok);
+  bool always_ok() const;
+
+ private:
+  friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
+      const upb_handlerattr *attr);
+#else
+struct upb_handlerattr {
+#endif
+  const void *handler_data_;
+  const void *closure_type_;
+  const void *return_closure_type_;
+  bool alwaysok_;
+};
+
+#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false}
+
+typedef struct {
+  upb_func *func;
+
+  /* It is wasteful to include the entire attributes here:
+   *
+   * * Some of the information is redundant (like storing the closure type
+   *   separately for each handler that must match).
+   * * Some of the info is only needed prior to freeze() (like closure types).
+   * * alignment padding wastes a lot of space for alwaysok_.
+   *
+   * If/when the size and locality of handlers is an issue, we can optimize this
+   * not to store the entire attr like this.  We do not expose the table's
+   * layout to allow this optimization in the future. */
+  upb_handlerattr attr;
+} upb_handlers_tabent;
+
+#ifdef __cplusplus
+
+/* Extra information about a buffer that is passed to a StringBuf handler.
+ * TODO(haberman): allow the handle to be pinned so that it will outlive
+ * the handler invocation. */
+class upb::BufferHandle {
+ public:
+  BufferHandle();
+  ~BufferHandle();
+
+  /* The beginning of the buffer.  This may be different than the pointer
+   * passed to a StringBuf handler because the handler may receive data
+   * that is from the middle or end of a larger buffer. */
+  const char* buffer() const;
+
+  /* The offset within the attached object where this buffer begins.  Only
+   * meaningful if there is an attached object. */
+  size_t object_offset() const;
+
+  /* Note that object_offset is the offset of "buf" within the attached
+   * object. */
+  void SetBuffer(const char* buf, size_t object_offset);
+
+  /* The BufferHandle can have an "attached object", which can be used to
+   * tunnel through a pointer to the buffer's underlying representation. */
+  template <class T>
+  void SetAttachedObject(const T* obj);
+
+  /* Returns NULL if the attached object is not of this type. */
+  template <class T>
+  const T* GetAttachedObject() const;
+
+ private:
+  friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h);
+  friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h,
+                                                const void *obj,
+                                                const void *type);
+  friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h,
+                                                const char *buf, size_t ofs);
+  friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h);
+  friend UPB_INLINE const void* ::upb_bufhandle_objtype(
+      const upb_bufhandle *h);
+  friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h);
+#else
+struct upb_bufhandle {
+#endif
+  const char *buf_;
+  const void *obj_;
+  const void *objtype_;
+  size_t objofs_;
+};
+
+#ifdef __cplusplus
+
+/* A upb::Handlers object represents the set of handlers associated with a
+ * message in the graph of messages.  You can think of it as a big virtual
+ * table with functions corresponding to all the events that can fire while
+ * parsing or visiting a message of a specific type.
+ *
+ * Any handlers that are not set behave as if they had successfully consumed
+ * the value.  Any unset Start* handlers will propagate their closure to the
+ * inner frame.
+ *
+ * The easiest way to create the *Handler objects needed by the Set* methods is
+ * with the UpbBind() and UpbMakeHandler() macros; see below. */
+class upb::Handlers {
+ public:
+  typedef upb_selector_t Selector;
+  typedef upb_handlertype_t Type;
+
+  typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
+  typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler;
+  typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
+  typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
+                             const BufferHandle *)> StringHandler;
+
+  template <class T> struct ValueHandler {
+    typedef Handler<bool(*)(void *, const void *, T)> H;
+  };
+
+  typedef ValueHandler<int32_t>::H     Int32Handler;
+  typedef ValueHandler<int64_t>::H     Int64Handler;
+  typedef ValueHandler<uint32_t>::H    UInt32Handler;
+  typedef ValueHandler<uint64_t>::H    UInt64Handler;
+  typedef ValueHandler<float>::H       FloatHandler;
+  typedef ValueHandler<double>::H      DoubleHandler;
+  typedef ValueHandler<bool>::H        BoolHandler;
+
+  /* Any function pointer can be converted to this and converted back to its
+   * correct type. */
+  typedef void GenericFunction();
+
+  typedef void HandlersCallback(const void *closure, upb_handlers *h);
+
+  /* Returns a new handlers object for the given frozen msgdef.
+   * Returns NULL if memory allocation failed. */
+  static reffed_ptr<Handlers> New(const MessageDef *m);
+
+  /* Convenience function for registering a graph of handlers that mirrors the
+   * graph of msgdefs for some message.  For "m" and all its children a new set
+   * of handlers will be created and the given callback will be invoked,
+   * allowing the client to register handlers for this message.  Note that any
+   * subhandlers set by the callback will be overwritten. */
+  static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
+                                              HandlersCallback *callback,
+                                              const void *closure);
+
+  /* Functionality from upb::RefCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* All handler registration functions return bool to indicate success or
+   * failure; details about failures are stored in this status object.  If a
+   * failure does occur, it must be cleared before the Handlers are frozen,
+   * otherwise the freeze() operation will fail.  The functions may *only* be
+   * used while the Handlers are mutable. */
+  const Status* status();
+  void ClearError();
+
+  /* Call to freeze these Handlers.  Requires that any SubHandlers are already
+   * frozen.  For cycles, you must use the static version below and freeze the
+   * whole graph at once. */
+  bool Freeze(Status* s);
+
+  /* Freezes the given set of handlers.  You may not freeze a handler without
+   * also freezing any handlers they point to. */
+  static bool Freeze(Handlers*const* handlers, int n, Status* s);
+  static bool Freeze(const std::vector<Handlers*>& handlers, Status* s);
+
+  /* Returns the msgdef associated with this handlers object. */
+  const MessageDef* message_def() const;
+
+  /* Adds the given pointer and function to the list of cleanup functions that
+   * will be run when these handlers are freed.  If this pointer has previously
+   * been registered, the function returns false and does nothing. */
+  bool AddCleanup(void *ptr, upb_handlerfree *cleanup);
+
+  /* Sets the startmsg handler for the message, which is defined as follows:
+   *
+   *   bool startmsg(MyType* closure) {
+   *     // Called when the message begins.  Returns true if processing should
+   *     // continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartMessageHandler(const StartMessageHandler& handler);
+
+  /* Sets the endmsg handler for the message, which is defined as follows:
+   *
+   *   bool endmsg(MyType* closure, upb_status *status) {
+   *     // Called when processing of this message ends, whether in success or
+   *     // failure.  "status" indicates the final status of processing, and
+   *     // can also be modified in-place to update the final status.
+   *   }
+   */
+  bool SetEndMessageHandler(const EndMessageHandler& handler);
+
+  /* Sets the value handler for the given field, which is defined as follows
+   * (this is for an int32 field; other field types will pass their native
+   * C/C++ type for "val"):
+   *
+   *   bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
+   *     // Called when the field's value is encountered.  "d" contains
+   *     // whatever data was bound to this field when it was registered.
+   *     // Returns true if processing should continue.
+   *     return true;
+   *   }
+   *
+   *   handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
+   *
+   * The value type must exactly match f->type().
+   * For example, a handler that takes an int32_t parameter may only be used for
+   * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
+   *
+   * Returns false if the handler failed to register; in this case the cleanup
+   * handler (if any) will be called immediately.
+   */
+  bool SetInt32Handler (const FieldDef* f,  const Int32Handler& h);
+  bool SetInt64Handler (const FieldDef* f,  const Int64Handler& h);
+  bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h);
+  bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h);
+  bool SetFloatHandler (const FieldDef* f,  const FloatHandler& h);
+  bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h);
+  bool SetBoolHandler  (const FieldDef* f,   const BoolHandler& h);
+
+  /* Like the previous, but templated on the type on the value (ie. int32).
+   * This is mostly useful to call from other templates.  To call this you must
+   * specify the template parameter explicitly, ie:
+   *   h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData)); */
+  template <class T>
+  bool SetValueHandler(
+      const FieldDef *f,
+      const typename ValueHandler<typename CanonicalType<T>::Type>::H& handler);
+
+  /* Sets handlers for a string field, which are defined as follows:
+   *
+   *   MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
+   *                          size_t size_hint) {
+   *     // Called when a string value begins.  The return value indicates the
+   *     // closure for the string.  "size_hint" indicates the size of the
+   *     // string if it is known, however if the string is length-delimited
+   *     // and the end-of-string is not available size_hint will be zero.
+   *     // This case is indistinguishable from the case where the size is
+   *     // known to be zero.
+   *     //
+   *     // TODO(haberman): is it important to distinguish these cases?
+   *     // If we had ssize_t as a type we could make -1 "unknown", but
+   *     // ssize_t is POSIX (not ANSI) and therefore less portable.
+   *     // In practice I suspect it won't be important to distinguish.
+   *     return closure;
+   *   }
+   *
+   *   size_t str(MyClosure* closure, const MyHandlerData* d,
+   *              const char *str, size_t len) {
+   *     // Called for each buffer of string data; the multiple physical buffers
+   *     // are all part of the same logical string.  The return value indicates
+   *     // how many bytes were consumed.  If this number is less than "len",
+   *     // this will also indicate that processing should be halted for now,
+   *     // like returning false or UPB_BREAK from any other callback.  If
+   *     // number is greater than "len", the excess bytes will be skipped over
+   *     // and not passed to the callback.
+   *     return len;
+   *   }
+   *
+   *   bool endstr(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a string value ends.  Return value indicates whether
+   *     // processing should continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h);
+  bool SetStringHandler(const FieldDef* f, const StringHandler& h);
+  bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets the startseq handler, which is defined as follows:
+   *
+   *   MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence (repeated field) begins.  The returned
+   *     // pointer indicates the closure for the sequence (or UPB_BREAK
+   *     // to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the startsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage begins.  The returned pointer indicates the
+   *     // closure for the sequence (or UPB_BREAK to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
+   *                                           new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the endsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage ends.  Returns true to continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h);
+
+  /* Starts the endsubseq handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence ends.  Returns true continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets or gets the object that specifies handlers for the given field, which
+   * must be a submessage or group.  Returns NULL if no handlers are set. */
+  bool SetSubHandlers(const FieldDef* f, const Handlers* sub);
+  const Handlers* GetSubHandlers(const FieldDef* f) const;
+
+  /* Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the
+   * field. */
+  const Handlers* GetSubHandlers(Selector startsubmsg) const;
+
+  /* A selector refers to a specific field handler in the Handlers object
+   * (for example: the STARTSUBMSG handler for field "field15").
+   * On success, returns true and stores the selector in "s".
+   * If the FieldDef or Type are invalid, returns false.
+   * The returned selector is ONLY valid for Handlers whose MessageDef
+   * contains this FieldDef. */
+  static bool GetSelector(const FieldDef* f, Type type, Selector* s);
+
+  /* Given a START selector of any kind, returns the corresponding END selector. */
+  static Selector GetEndSelector(Selector start_selector);
+
+  /* Returns the function pointer for this handler.  It is the client's
+   * responsibility to cast to the correct function type before calling it. */
+  GenericFunction* GetHandler(Selector selector);
+
+  /* Sets the given attributes to the attributes for this selector. */
+  bool GetAttributes(Selector selector, HandlerAttributes* attr);
+
+  /* Returns the handler data that was registered with this handler. */
+  const void* GetHandlerData(Selector selector);
+
+  /* Could add any of the following functions as-needed, with some minor
+   * implementation changes:
+   *
+   * const FieldDef* GetFieldDef(Selector selector);
+   * static bool IsSequence(Selector selector); */
+
+ private:
+  UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers)
+
+  friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
+      const upb_handlers *h, upb_selector_t s);
+  friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
+      const upb_handlers *h, upb_selector_t s);
+#else
+struct upb_handlers {
+#endif
+  upb_refcounted base;
+
+  const upb_msgdef *msg;
+  const upb_handlers **sub;
+  const void *top_closure_type;
+  upb_inttable cleanup_;
+  upb_status status_;  /* Used only when mutable. */
+  upb_handlers_tabent table[1];  /* Dynamically-sized field handler array. */
+};
+
+#ifdef __cplusplus
+
+namespace upb {
+
+/* Convenience macros for creating a Handler object that is wrapped with a
+ * type-safe wrapper function that converts the "void*" parameters/returns
+ * of the underlying C API into nice C++ function.
+ *
+ * Sample usage:
+ *   void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that doesn't need any data bound to it.
+ *   void OnValue2(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that returns bool so it can return failure if necessary.
+ *   bool OnValue3(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *     return ok;
+ *   }
+ *
+ *   // Member function handler.
+ *   class MyClosure {
+ *    public:
+ *     void OnValue(int32_t val) {
+ *       // do stuff ...
+ *     }
+ *   };
+ *
+ *   // Takes ownership of the MyHandlerData.
+ *   handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
+ *   handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
+ */
+
+#ifdef UPB_CXX11
+
+/* In C++11, the "template" disambiguator can appear even outside templates,
+ * so all calls can safely use this pair of macros. */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+#else
+
+/* Prior to C++11, the "template" disambiguator may only appear inside a
+ * template, so the regular macro must not use "template" */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
+
+#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
+
+#endif  /* UPB_CXX11 */
+
+/* This macro must be used in C++98 for calls from inside a template.  But we
+ * define this variant in all cases; code that wants to be compatible with both
+ * C++98 and C++11 should always use this macro when calling from a template. */
+#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+/* Handler: a struct that contains the (handler, data, deleter) tuple that is
+ * used to register all handlers.  Users can Make() these directly but it's
+ * more convenient to use the UpbMakeHandler/UpbBind macros above. */
+template <class T> class Handler {
+ public:
+  /* The underlying, handler function signature that upb uses internally. */
+  typedef T FuncPtr;
+
+  /* Intentionally implicit. */
+  template <class F> Handler(F func);
+  ~Handler();
+
+ private:
+  void AddCleanup(Handlers* h) const {
+    if (cleanup_func_) {
+      bool ok = h->AddCleanup(cleanup_data_, cleanup_func_);
+      UPB_ASSERT_VAR(ok, ok);
+    }
+  }
+
+  UPB_DISALLOW_COPY_AND_ASSIGN(Handler)
+  friend class Handlers;
+  FuncPtr handler_;
+  mutable HandlerAttributes attr_;
+  mutable bool registered_;
+  void *cleanup_data_;
+  upb_handlerfree *cleanup_func_;
+};
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+/* Handler function typedefs. */
+typedef bool upb_startmsg_handlerfunc(void *c, const void*);
+typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
+typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
+typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
+typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
+typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
+typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
+typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
+typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
+typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
+                                       size_t size_hint);
+typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
+                                      size_t n, const upb_bufhandle* handle);
+
+/* upb_bufhandle */
+size_t upb_bufhandle_objofs(const upb_bufhandle *h);
+
+/* upb_handlerattr */
+void upb_handlerattr_init(upb_handlerattr *attr);
+void upb_handlerattr_uninit(upb_handlerattr *attr);
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd);
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type);
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type);
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok);
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlerattr_handlerdata(
+    const upb_handlerattr *attr) {
+  return attr->handler_data_;
+}
+
+/* upb_handlers */
+typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
+upb_handlers *upb_handlers_new(const upb_msgdef *m,
+                               const void *owner);
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure);
+
+/* Include refcounted methods like upb_handlers_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_handlers, upb_handlers_upcast)
+
+const upb_status *upb_handlers_status(upb_handlers *h);
+void upb_handlers_clearerr(upb_handlers *h);
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
+                           upb_int32_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
+                           upb_int64_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint32_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint64_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
+                           upb_float_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
+                            upb_double_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
+                          upb_bool_handlerfunc *func,
+                          upb_handlerattr *attr);
+bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
+                              upb_startstr_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
+                            upb_string_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
+                              upb_startfield_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
+                                 upb_startfield_handlerfunc *func,
+                                 upb_handlerattr *attr);
+bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
+                               upb_endfield_handlerfunc *func,
+                               upb_handlerattr *attr);
+bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub);
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f);
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel);
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s) {
+  return (upb_func *)h->table[s].func;
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
+                          upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s) {
+  return upb_handlerattr_handlerdata(&h->table[s].attr);
+}
+
+#ifdef __cplusplus
+
+/* Handler types for single fields.
+ * Right now we only have one for TYPE_BYTES but ones for other types
+ * should follow.
+ *
+ * These follow the same handlers protocol for fields of a message. */
+class upb::BytesHandler {
+ public:
+  BytesHandler();
+  ~BytesHandler();
+#else
+struct upb_byteshandler {
+#endif
+  upb_handlers_tabent table[3];
+};
+
+void upb_byteshandler_init(upb_byteshandler *h);
+
+/* Caller must ensure that "d" outlives the handlers.
+ * TODO(haberman): should this have a "freeze" operation?  It's not necessary
+ * for memory management, but could be useful to force immutability and provide
+ * a convenient moment to verify that all registration succeeded. */
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d);
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d);
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d);
+
+/* "Static" methods */
+bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s);
+UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
+  return start + 1;
+}
+
+/* Internal-only. */
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
+
+UPB_END_EXTERN_C
+
+/*
+** Inline definitions for handlers.h, which are particularly long and a bit
+** tricky.
+*/
+
+#ifndef UPB_HANDLERS_INL_H_
+#define UPB_HANDLERS_INL_H_
+
+#include <limits.h>
+
+/* C inline methods. */
+
+/* upb_bufhandle */
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) {
+  h->obj_ = NULL;
+  h->objtype_ = NULL;
+  h->buf_ = NULL;
+  h->objofs_ = 0;
+}
+UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) {
+  UPB_UNUSED(h);
+}
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type) {
+  h->obj_ = obj;
+  h->objtype_ = type;
+}
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs) {
+  h->buf_ = buf;
+  h->objofs_ = ofs;
+}
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) {
+  return h->obj_;
+}
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) {
+  return h->objtype_;
+}
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) {
+  return h->buf_;
+}
+
+
+#ifdef __cplusplus
+
+/* Type detection and typedefs for integer types.
+ * For platforms where there are multiple 32-bit or 64-bit types, we need to be
+ * able to enumerate them so we can properly create overloads for all variants.
+ *
+ * If any platform existed where there were three integer types with the same
+ * size, this would have to become more complicated.  For example, short, int,
+ * and long could all be 32-bits.  Even more diabolically, short, int, long,
+ * and long long could all be 64 bits and still be standard-compliant.
+ * However, few platforms are this strange, and it's unlikely that upb will be
+ * used on the strangest ones. */
+
+/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are
+ * only defined when __STDC_LIMIT_MACROS are defined before the *first* include
+ * of stdint.h.  We can't guarantee that someone else didn't include these first
+ * without defining __STDC_LIMIT_MACROS. */
+#define UPB_INT32_MAX 0x7fffffffLL
+#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
+#define UPB_INT64_MAX 0x7fffffffffffffffLL
+#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
+
+#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
+#define UPB_INT_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
+#define UPB_LONG_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
+#define UPB_LONG_IS_64BITS 1
+#endif
+
+#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
+#define UPB_LLONG_IS_64BITS 1
+#endif
+
+/* We use macros instead of typedefs so we can undefine them later and avoid
+ * leaking them outside this header file. */
+#if UPB_INT_IS_32BITS
+#define UPB_INT32_T int
+#define UPB_UINT32_T unsigned int
+
+#if UPB_LONG_IS_32BITS
+#define UPB_TWO_32BIT_TYPES 1
+#define UPB_INT32ALT_T long
+#define UPB_UINT32ALT_T unsigned long
+#endif  /* UPB_LONG_IS_32BITS */
+
+#elif UPB_LONG_IS_32BITS  /* && !UPB_INT_IS_32BITS */
+#define UPB_INT32_T long
+#define UPB_UINT32_T unsigned long
+#endif  /* UPB_INT_IS_32BITS */
+
+
+#if UPB_LONG_IS_64BITS
+#define UPB_INT64_T long
+#define UPB_UINT64_T unsigned long
+
+#if UPB_LLONG_IS_64BITS
+#define UPB_TWO_64BIT_TYPES 1
+#define UPB_INT64ALT_T long long
+#define UPB_UINT64ALT_T unsigned long long
+#endif  /* UPB_LLONG_IS_64BITS */
+
+#elif UPB_LLONG_IS_64BITS  /* && !UPB_LONG_IS_64BITS */
+#define UPB_INT64_T long long
+#define UPB_UINT64_T unsigned long long
+#endif  /* UPB_LONG_IS_64BITS */
+
+#undef UPB_INT32_MAX
+#undef UPB_INT32_MIN
+#undef UPB_INT64_MAX
+#undef UPB_INT64_MIN
+#undef UPB_INT_IS_32BITS
+#undef UPB_LONG_IS_32BITS
+#undef UPB_LONG_IS_64BITS
+#undef UPB_LLONG_IS_64BITS
+
+
+namespace upb {
+
+typedef void CleanupFunc(void *ptr);
+
+/* Template to remove "const" from "const T*" and just return "T*".
+ *
+ * We define a nonsense default because otherwise it will fail to instantiate as
+ * a function parameter type even in cases where we don't expect any caller to
+ * actually match the overload. */
+class CouldntRemoveConst {};
+template <class T> struct remove_constptr { typedef CouldntRemoveConst type; };
+template <class T> struct remove_constptr<const T *> { typedef T *type; };
+
+/* Template that we use below to remove a template specialization from
+ * consideration if it matches a specific type. */
+template <class T, class U> struct disable_if_same { typedef void Type; };
+template <class T> struct disable_if_same<T, T> {};
+
+template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); }
+
+template <class T1, class T2>
+struct FirstUnlessVoidOrBool {
+  typedef T1 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<void, T2> {
+  typedef T2 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<bool, T2> {
+  typedef T2 value;
+};
+
+template<class T, class U>
+struct is_same {
+  static bool value;
+};
+
+template<class T>
+struct is_same<T, T> {
+  static bool value;
+};
+
+template<class T, class U>
+bool is_same<T, U>::value = false;
+
+template<class T>
+bool is_same<T, T>::value = true;
+
+/* FuncInfo *******************************************************************/
+
+/* Info about the user's original, pre-wrapped function. */
+template <class C, class R = void>
+struct FuncInfo {
+  /* The type of the closure that the function takes (its first param). */
+  typedef C Closure;
+
+  /* The return type. */
+  typedef R Return;
+};
+
+/* Func ***********************************************************************/
+
+/* Func1, Func2, Func3: Template classes representing a function and its
+ * signature.
+ *
+ * Since the function is a template parameter, calling the function can be
+ * inlined at compile-time and does not require a function pointer at runtime.
+ * These functions are not bound to a handler data so have no data or cleanup
+ * handler. */
+struct UnboundFunc {
+  CleanupFunc *GetCleanup() { return NULL; }
+  void *GetData() { return NULL; }
+};
+
+template <class R, class P1, R F(P1), class I>
+struct Func1 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1) { return F(p1); }
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct Func2 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2) { return F(p1, p2); }
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct Func3 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct Func4 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct Func5 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+    return F(p1, p2, p3, p4, p5);
+  }
+};
+
+/* BoundFunc ******************************************************************/
+
+/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
+ * shall be bound to the function's second parameter.
+ * 
+ * Note that the second parameter is a const pointer, but our stored bound value
+ * is non-const so we can free it when the handlers are destroyed. */
+template <class T>
+struct BoundFunc {
+  typedef typename remove_constptr<T>::type MutableP2;
+  explicit BoundFunc(MutableP2 data_) : data(data_) {}
+  CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
+  MutableP2 GetData() { return data; }
+  MutableP2 data;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct BoundFunc2 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct BoundFunc3 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct BoundFunc4 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct BoundFunc5 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+/* FuncSig ********************************************************************/
+
+/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
+ * *signature*, but without a specific function attached.
+ *
+ * These classes contain member functions that can be invoked with a
+ * specific function to return a Func/BoundFunc class. */
+template <class R, class P1>
+struct FuncSig1 {
+  template <R F(P1)>
+  Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() {
+    return Func1<R, P1, F, FuncInfo<P1, R> >();
+  }
+};
+
+template <class R, class P1, class P2>
+struct FuncSig2 {
+  template <R F(P1, P2)>
+  Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() {
+    return Func2<R, P1, P2, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2)>
+  BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3>
+struct FuncSig3 {
+  template <R F(P1, P2, P3)>
+  Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() {
+    return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3)>
+  BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct FuncSig4 {
+  template <R F(P1, P2, P3, P4)>
+  Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() {
+    return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4)>
+  BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct FuncSig5 {
+  template <R F(P1, P2, P3, P4, P5)>
+  Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() {
+    return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4, P5)>
+  BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+/* Overloaded template function that can construct the appropriate FuncSig*
+ * class given a function pointer by deducing the template parameters. */
+template <class R, class P1>
+inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig1<R, P1>();
+}
+
+template <class R, class P1, class P2>
+inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig2<R, P1, P2>();
+}
+
+template <class R, class P1, class P2, class P3>
+inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig3<R, P1, P2, P3>();
+}
+
+template <class R, class P1, class P2, class P3, class P4>
+inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig4<R, P1, P2, P3, P4>();
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig5<R, P1, P2, P3, P4, P5>();
+}
+
+/* MethodSig ******************************************************************/
+
+/* CallMethod*: a function template that calls a given method. */
+template <class R, class C, R (C::*F)()>
+R CallMethod0(C *obj) {
+  return ((*obj).*F)();
+}
+
+template <class R, class C, class P1, R (C::*F)(P1)>
+R CallMethod1(C *obj, P1 arg1) {
+  return ((*obj).*F)(arg1);
+}
+
+template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
+R CallMethod2(C *obj, P1 arg1, P2 arg2) {
+  return ((*obj).*F)(arg1, arg2);
+}
+
+template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
+R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
+  return ((*obj).*F)(arg1, arg2, arg3);
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4,
+          R (C::*F)(P1, P2, P3, P4)>
+R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) {
+  return ((*obj).*F)(arg1, arg2, arg3, arg4);
+}
+
+/* MethodSig: like FuncSig, but for member functions.
+ *
+ * GetFunc() returns a normal FuncN object, so after calling GetFunc() no
+ * more logic is required to special-case methods. */
+template <class R, class C>
+struct MethodSig0 {
+  template <R (C::*F)()>
+  Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >();
+  }
+};
+
+template <class R, class C, class P1>
+struct MethodSig1 {
+  template <R (C::*F)(P1)>
+  Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1)>
+  BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc(
+      typename remove_constptr<P1>::type param1) {
+    return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C, class P1, class P2>
+struct MethodSig2 {
+  template <R (C::*F)(P1, P2)>
+  Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2)>
+  BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3>
+struct MethodSig3 {
+  template <R (C::*F)(P1, P2, P3)>
+  Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3)>
+  BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+struct MethodSig4 {
+  template <R (C::*F)(P1, P2, P3, P4)>
+  Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+        FuncInfo<C *, R> >
+  GetFunc() {
+    return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3, P4)>
+  BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc5<R, C *, P1, P2, P3, P4,
+                      CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C>
+inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig0<R, C>();
+}
+
+template <class R, class C, class P1>
+inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig1<R, C, P1>();
+}
+
+template <class R, class C, class P1, class P2>
+inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig2<R, C, P1, P2>();
+}
+
+template <class R, class C, class P1, class P2, class P3>
+inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig3<R, C, P1, P2, P3>();
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig4<R, C, P1, P2, P3, P4>();
+}
+
+/* MaybeWrapReturn ************************************************************/
+
+/* Template class that attempts to wrap the return value of the function so it
+ * matches the expected type.  There are two main adjustments it may make:
+ *
+ *   1. If the function returns void, make it return the expected type and with
+ *      a value that always indicates success.
+ *   2. If the function returns bool, make it return the expected type with a
+ *      value that indicates success or failure.
+ *
+ * The "expected type" for return is:
+ *   1. void* for start handlers.  If the closure parameter has a different type
+ *      we will cast it to void* for the return in the success case.
+ *   2. size_t for string buffer handlers.
+ *   3. bool for everything else. */
+
+/* Template parameters are FuncN type and desired return type. */
+template <class F, class R, class Enable = void>
+struct MaybeWrapReturn;
+
+/* If the return type matches, return the given function unwrapped. */
+template <class F>
+struct MaybeWrapReturn<F, typename F::Return> {
+  typedef F Func;
+};
+
+/* Function wrapper that munges the return value from void to (bool)true. */
+template <class P1, class P2, void F(P1, P2)>
+bool ReturnTrue2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return true;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return true;
+}
+
+/* Function wrapper that munges the return value from void to (void*)arg1  */
+template <class P1, class P2, void F(P1, P2)>
+void *ReturnClosure2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return p1;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return p1;
+}
+
+/* Function wrapper that munges the return value from R to void*. */
+template <class R, class P1, class P2, R F(P1, P2)>
+void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
+  return F(p1, p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3);
+}
+
+/* Function wrapper that munges the return value from bool to void*. */
+template <class P1, class P2, bool F(P1, P2)>
+void *ReturnClosureOrBreak2(P1 p1, P2 p2) {
+  return F(p1, p2) ? p1 : UPB_BREAK;
+}
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3)>
+void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3) ? p1 : UPB_BREAK;
+}
+
+/* For the string callback, which takes five params, returns the size param. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4,
+                       const BufferHandle *p5) {
+  F(p1, p2, p3, p4, p5);
+  return p4;
+}
+
+/* For the string callback, which takes five params, returns the size param or
+ * zero. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4,
+                  const BufferHandle *p5) {
+  return F(p1, p2, p3, p4, p5) ? p4 : 0;
+}
+
+/* If we have a function returning void but want a function returning bool, wrap
+ * it in a function that returns true. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> {
+  typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> {
+  typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns void but we want one returning void*, wrap it in a
+ * function that returns the first argument. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns R* but we want one returning void*, wrap it in a
+ * function that casts to void*. */
+template <class R, class P1, class P2, R *F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func;
+};
+
+template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns bool but we want one returning void*, wrap it in a
+ * function that returns either the first param or UPB_BREAK. */
+template <class P1, class P2, bool F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns void but we want one returning size_t, wrap it in a
+ * function that returns the size argument. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+          size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnStringLen<P1, P2, F>, I> Func;
+};
+
+/* If our function returns bool but we want one returning size_t, wrap it in a
+ * function that returns either 0 or the buf size. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<bool, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+    size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnNOr0<P1, P2, F>, I> Func;
+};
+
+/* ConvertParams **************************************************************/
+
+/* Template class that converts the function parameters if necessary, and
+ * ignores the HandlerData parameter if appropriate.
+ *
+ * Template parameter is the are FuncN function type. */
+template <class F, class T>
+struct ConvertParams;
+
+/* Function that discards the handler data parameter. */
+template <class R, class P1, R F(P1)>
+R IgnoreHandlerData2(void *p1, const void *hd) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1));
+}
+
+template <class R, class P1, class P2Wrapper, class P2Wrapped,
+          R F(P1, P2Wrapped)>
+R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3, p4);
+}
+
+template <class R, class P1, R F(P1, const char*, size_t)>
+R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2,
+                                size_t p3, const BufferHandle *handle) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+/* Function that casts the handler data parameter. */
+template <class R, class P1, class P2, R F(P1, P2)>
+R CastHandlerData2(void *c, const void *hd) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd));
+}
+
+template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
+          R F(P1, P2, P3Wrapped)>
+R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5)>
+R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5);
+}
+
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)>
+R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3,
+                              size_t p4, const BufferHandle *handle) {
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
+}
+
+/* For unbound functions, ignore the handler data. */
+template <class R, class P1, R F(P1), class I, class T>
+struct ConvertParams<Func1<R, P1, F, I>, T> {
+  typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<Func2<R, P1, P2, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores both the handler data and the
+ * BufferHandle. */
+template <class R, class P1, R F(P1, const char *, size_t), class I, class T>
+struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I, class T>
+struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> {
+  typedef Func5<R, void *, const void *, P2, P3, P4,
+                IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
+};
+
+/* For bound functions, cast the handler data. */
+template <class R, class P1, class P2, R F(P1, P2), class I, class T>
+struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> {
+  typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I>
+      Func;
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores the BufferHandle. */
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t),
+          class I, class T>
+struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I, class T>
+struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> {
+  typedef Func5<R, void *, const void *, P3, P4, P5,
+                CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func;
+};
+
+/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
+ * variant C type. */
+#define TYPE_METHODS(utype, ltype, ctype, vtype)                               \
+  template <> struct CanonicalType<vtype> {                                    \
+    typedef ctype Type;                                                        \
+  };                                                                           \
+  template <>                                                                  \
+  inline bool Handlers::SetValueHandler<vtype>(                                \
+      const FieldDef *f,                                                       \
+      const Handlers::utype ## Handler& handler) {                             \
+    assert(!handler.registered_);                                              \
+    handler.AddCleanup(this);                                                  \
+    handler.registered_ = true;                                                \
+    return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
+  }                                                                            \
+
+TYPE_METHODS(Double, double, double,   double)
+TYPE_METHODS(Float,  float,  float,    float)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T)
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64_T)
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32_T)
+TYPE_METHODS(Bool,   bool,   bool,     bool)
+
+#ifdef UPB_TWO_32BIT_TYPES
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32ALT_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T)
+#endif
+
+#ifdef UPB_TWO_64BIT_TYPES
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64ALT_T)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T)
+#endif
+#undef TYPE_METHODS
+
+template <> struct CanonicalType<Status*> {
+  typedef Status* Type;
+};
+
+/* Type methods that are only one-per-canonical-type and not
+ * one-per-cvariant. */
+
+#define TYPE_METHODS(utype, ctype) \
+    inline bool Handlers::Set##utype##Handler(const FieldDef *f, \
+                                              const utype##Handler &h) { \
+      return SetValueHandler<ctype>(f, h); \
+    } \
+
+TYPE_METHODS(Double, double)
+TYPE_METHODS(Float,  float)
+TYPE_METHODS(UInt64, uint64_t)
+TYPE_METHODS(UInt32, uint32_t)
+TYPE_METHODS(Int64,  int64_t)
+TYPE_METHODS(Int32,  int32_t)
+TYPE_METHODS(Bool,   bool)
+#undef TYPE_METHODS
+
+template <class F> struct ReturnOf;
+
+template <class R, class P1, class P2>
+struct ReturnOf<R (*)(P1, P2)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3>
+struct ReturnOf<R (*)(P1, P2, P3)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct ReturnOf<R (*)(P1, P2, P3, P4)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> {
+  typedef R Return;
+};
+
+template<class T> const void *UniquePtrForType() {
+  static const char ch = 0;
+  return &ch;
+}
+
+template <class T>
+template <class F>
+inline Handler<T>::Handler(F func)
+    : registered_(false),
+      cleanup_data_(func.GetData()),
+      cleanup_func_(func.GetCleanup()) {
+  upb_handlerattr_sethandlerdata(&attr_, func.GetData());
+  typedef typename ReturnOf<T>::Return Return;
+  typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc;
+  typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
+      ReturnWrappedFunc;
+  handler_ = ReturnWrappedFunc().Call;
+
+  /* Set attributes based on what templates can statically tell us about the
+   * user's function. */
+
+  /* If the original function returns void, then we know that we wrapped it to
+   * always return ok. */
+  bool always_ok = is_same<typename F::FuncInfo::Return, void>::value;
+  attr_.SetAlwaysOk(always_ok);
+
+  /* Closure parameter and return type. */
+  attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>());
+
+  /* We use the closure type (from the first parameter) if the return type is
+   * void or bool, since these are the two cases we wrap to return the closure's
+   * type anyway.
+   *
+   * This is all nonsense for non START* handlers, but it doesn't matter because
+   * in that case the value will be ignored. */
+  typedef typename FirstUnlessVoidOrBool<typename F::FuncInfo::Return,
+                                         typename F::FuncInfo::Closure>::value
+      EffectiveReturn;
+  attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>());
+}
+
+template <class T>
+inline Handler<T>::~Handler() {
+  assert(registered_);
+}
+
+inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
+inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
+inline bool HandlerAttributes::SetHandlerData(const void *hd) {
+  return upb_handlerattr_sethandlerdata(this, hd);
+}
+inline const void* HandlerAttributes::handler_data() const {
+  return upb_handlerattr_handlerdata(this);
+}
+inline bool HandlerAttributes::SetClosureType(const void *type) {
+  return upb_handlerattr_setclosuretype(this, type);
+}
+inline const void* HandlerAttributes::closure_type() const {
+  return upb_handlerattr_closuretype(this);
+}
+inline bool HandlerAttributes::SetReturnClosureType(const void *type) {
+  return upb_handlerattr_setreturnclosuretype(this, type);
+}
+inline const void* HandlerAttributes::return_closure_type() const {
+  return upb_handlerattr_returnclosuretype(this);
+}
+inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) {
+  return upb_handlerattr_setalwaysok(this, always_ok);
+}
+inline bool HandlerAttributes::always_ok() const {
+  return upb_handlerattr_alwaysok(this);
+}
+
+inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); }
+inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); }
+inline const char* BufferHandle::buffer() const {
+  return upb_bufhandle_buf(this);
+}
+inline size_t BufferHandle::object_offset() const {
+  return upb_bufhandle_objofs(this);
+}
+inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) {
+  upb_bufhandle_setbuf(this, buf, ofs);
+}
+template <class T>
+void BufferHandle::SetAttachedObject(const T* obj) {
+  upb_bufhandle_setobj(this, obj, UniquePtrForType<T>());
+}
+template <class T>
+const T* BufferHandle::GetAttachedObject() const {
+  return upb_bufhandle_objtype(this) == UniquePtrForType<T>()
+      ? static_cast<const T *>(upb_bufhandle_obj(this))
+                               : NULL;
+}
+
+inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
+  upb_handlers *h = upb_handlers_new(m, &h);
+  return reffed_ptr<Handlers>(h, &h);
+}
+inline reffed_ptr<const Handlers> Handlers::NewFrozen(
+    const MessageDef *m, upb_handlers_callback *callback,
+    const void *closure) {
+  const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+inline const Status* Handlers::status() {
+  return upb_handlers_status(this);
+}
+inline void Handlers::ClearError() {
+  return upb_handlers_clearerr(this);
+}
+inline bool Handlers::Freeze(Status *s) {
+  upb::Handlers* h = this;
+  return upb_handlers_freeze(&h, 1, s);
+}
+inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
+  return upb_handlers_freeze(handlers, n, s);
+}
+inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
+  return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
+}
+inline const MessageDef *Handlers::message_def() const {
+  return upb_handlers_msgdef(this);
+}
+inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) {
+  return upb_handlers_addcleanup(this, p, func);
+}
+inline bool Handlers::SetStartMessageHandler(
+    const Handlers::StartMessageHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndMessageHandler(
+    const Handlers::EndMessageHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartStringHandler(const FieldDef *f,
+                                            const StartStringHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndStringHandler(const FieldDef *f,
+                                          const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStringHandler(const FieldDef *f,
+                                       const StringHandler& handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSequenceHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSubMessageHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
+                                              const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
+                                            const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
+  return upb_handlers_setsubhandlers(this, f, sub);
+}
+inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const {
+  return upb_handlers_getsubhandlers(this, f);
+}
+inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const {
+  return upb_handlers_getsubhandlers_sel(this, sel);
+}
+inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type,
+                                  Handlers::Selector *s) {
+  return upb_handlers_getselector(f, type, s);
+}
+inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) {
+  return upb_handlers_getendselector(start);
+}
+inline Handlers::GenericFunction *Handlers::GetHandler(
+    Handlers::Selector selector) {
+  return upb_handlers_gethandler(this, selector);
+}
+inline const void *Handlers::GetHandlerData(Handlers::Selector selector) {
+  return upb_handlers_gethandlerdata(this, selector);
+}
+
+inline BytesHandler::BytesHandler() {
+  upb_byteshandler_init(this);
+}
+
+inline BytesHandler::~BytesHandler() {}
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+
+#undef UPB_TWO_32BIT_TYPES
+#undef UPB_TWO_64BIT_TYPES
+#undef UPB_INT32_T
+#undef UPB_UINT32_T
+#undef UPB_INT32ALT_T
+#undef UPB_UINT32ALT_T
+#undef UPB_INT64_T
+#undef UPB_UINT64_T
+#undef UPB_INT64ALT_T
+#undef UPB_UINT64ALT_T
+
+#endif  /* UPB_HANDLERS_INL_H_ */
+
+#endif  /* UPB_HANDLERS_H */
+/*
+** upb::Environment (upb_env)
+**
+** A upb::Environment provides a means for injecting malloc and an
+** error-reporting callback into encoders/decoders.  This allows them to be
+** independent of nearly all assumptions about their actual environment.
+**
+** It is also a container for allocating the encoders/decoders themselves that
+** insulates clients from knowing their actual size.  This provides ABI
+** compatibility even if the size of the objects change.  And this allows the
+** structure definitions to be in the .c files instead of the .h files, making
+** the .h files smaller and more readable.
+*/
+
+
+#ifndef UPB_ENV_H_
+#define UPB_ENV_H_
+
+#ifdef __cplusplus
+namespace upb {
+class Environment;
+class SeededAllocator;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::Environment, upb_env)
+UPB_DECLARE_TYPE(upb::SeededAllocator, upb_seededalloc)
+
+typedef void *upb_alloc_func(void *ud, void *ptr, size_t oldsize, size_t size);
+typedef void upb_cleanup_func(void *ud);
+typedef bool upb_error_func(void *ud, const upb_status *status);
+
+#ifdef __cplusplus
+
+/* An environment is *not* thread-safe. */
+class upb::Environment {
+ public:
+  Environment();
+  ~Environment();
+
+  /* Set a custom memory allocation function for the environment.  May ONLY
+   * be called before any calls to Malloc()/Realloc()/AddCleanup() below.
+   * If this is not called, the system realloc() function will be used.
+   * The given user pointer "ud" will be passed to the allocation function.
+   *
+   * The allocation function will not receive corresponding "free" calls.  it
+   * must ensure that the memory is valid for the lifetime of the Environment,
+   * but it may be reclaimed any time thereafter.  The likely usage is that
+   * "ud" points to a stateful allocator, and that the allocator frees all
+   * memory, arena-style, when it is destroyed.  In this case the allocator must
+   * outlive the Environment.  Another possibility is that the allocation
+   * function returns GC-able memory that is guaranteed to be GC-rooted for the
+   * life of the Environment. */
+  void SetAllocationFunction(upb_alloc_func* alloc, void* ud);
+
+  template<class T>
+  void SetAllocator(T* allocator) {
+    SetAllocationFunction(allocator->GetAllocationFunction(), allocator);
+  }
+
+  /* Set a custom error reporting function. */
+  void SetErrorFunction(upb_error_func* func, void* ud);
+
+  /* Set the error reporting function to simply copy the status to the given
+   * status and abort. */
+  void ReportErrorsTo(Status* status);
+
+  /* Returns true if all allocations and AddCleanup() calls have succeeded,
+   * and no errors were reported with ReportError() (except ones that recovered
+   * successfully). */
+  bool ok() const;
+
+  /* Functions for use by encoders/decoders. **********************************/
+
+  /* Reports an error to this environment's callback, returning true if
+   * the caller should try to recover. */
+  bool ReportError(const Status* status);
+
+  /* Allocate memory.  Uses the environment's allocation function.
+   *
+   * There is no need to free(). All memory will be freed automatically, but is
+   * guaranteed to outlive the Environment. */
+  void* Malloc(size_t size);
+
+  /* Reallocate memory.  Preserves "oldsize" bytes from the existing buffer
+   * Requires: oldsize <= existing_size.
+   *
+   * TODO(haberman): should we also enforce that oldsize <= size? */
+  void* Realloc(void* ptr, size_t oldsize, size_t size);
+
+  /* Add a cleanup function to run when the environment is destroyed.
+   * Returns false on out-of-memory.
+   *
+   * The first call to AddCleanup() after SetAllocationFunction() is guaranteed
+   * to return true -- this makes it possible to robustly set a cleanup handler
+   * for a custom allocation function. */
+  bool AddCleanup(upb_cleanup_func* func, void* ud);
+
+  /* Total number of bytes that have been allocated.  It is undefined what
+   * Realloc() does to this counter. */
+  size_t BytesAllocated() const;
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Environment)
+
+#else
+struct upb_env {
+#endif  /* __cplusplus */
+
+  bool ok_;
+  size_t bytes_allocated;
+
+  /* Alloc function. */
+  upb_alloc_func *alloc;
+  void *alloc_ud;
+
+  /* Error-reporting function. */
+  upb_error_func *err;
+  void *err_ud;
+
+  /* Userdata for default alloc func. */
+  void *default_alloc_ud;
+
+  /* Cleanup entries.  Pointer to a cleanup_ent, defined in env.c */
+  void *cleanup_head;
+
+  /* For future expansion, since the size of this struct is exposed to users. */
+  void *future1;
+  void *future2;
+};
+
+UPB_BEGIN_EXTERN_C
+
+void upb_env_init(upb_env *e);
+void upb_env_uninit(upb_env *e);
+void upb_env_setallocfunc(upb_env *e, upb_alloc_func *func, void *ud);
+void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud);
+void upb_env_reporterrorsto(upb_env *e, upb_status *status);
+bool upb_env_ok(const upb_env *e);
+bool upb_env_reporterror(upb_env *e, const upb_status *status);
+void *upb_env_malloc(upb_env *e, size_t size);
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size);
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud);
+size_t upb_env_bytesallocated(const upb_env *e);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+/* An allocator that allocates from an initial memory region (likely the stack)
+ * before falling back to another allocator. */
+class upb::SeededAllocator {
+ public:
+  SeededAllocator(void *mem, size_t len);
+  ~SeededAllocator();
+
+  /* Set a custom fallback memory allocation function for the allocator, to use
+   * once the initial region runs out.
+   *
+   * May ONLY be called before GetAllocationFunction().  If this is not
+   * called, the system realloc() will be the fallback allocator. */
+  void SetFallbackAllocator(upb_alloc_func *alloc, void *ud);
+
+  /* Gets the allocation function for this allocator. */
+  upb_alloc_func* GetAllocationFunction();
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(SeededAllocator)
+
+#else
+struct upb_seededalloc {
+#endif  /* __cplusplus */
+
+  /* Fallback alloc function.  */
+  upb_alloc_func *alloc;
+  upb_cleanup_func *alloc_cleanup;
+  void *alloc_ud;
+  bool need_cleanup;
+  bool returned_allocfunc;
+
+  /* Userdata for default alloc func. */
+  void *default_alloc_ud;
+
+  /* Pointers for the initial memory region. */
+  char *mem_base;
+  char *mem_ptr;
+  char *mem_limit;
+
+  /* For future expansion, since the size of this struct is exposed to users. */
+  void *future1;
+  void *future2;
+};
+
+UPB_BEGIN_EXTERN_C
+
+void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len);
+void upb_seededalloc_uninit(upb_seededalloc *a);
+void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, upb_alloc_func *func,
+                                      void *ud);
+upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+inline Environment::Environment() {
+  upb_env_init(this);
+}
+inline Environment::~Environment() {
+  upb_env_uninit(this);
+}
+inline void Environment::SetAllocationFunction(upb_alloc_func *alloc,
+                                               void *ud) {
+  upb_env_setallocfunc(this, alloc, ud);
+}
+inline void Environment::SetErrorFunction(upb_error_func *func, void *ud) {
+  upb_env_seterrorfunc(this, func, ud);
+}
+inline void Environment::ReportErrorsTo(Status* status) {
+  upb_env_reporterrorsto(this, status);
+}
+inline bool Environment::ok() const {
+  return upb_env_ok(this);
+}
+inline bool Environment::ReportError(const Status* status) {
+  return upb_env_reporterror(this, status);
+}
+inline void *Environment::Malloc(size_t size) {
+  return upb_env_malloc(this, size);
+}
+inline void *Environment::Realloc(void *ptr, size_t oldsize, size_t size) {
+  return upb_env_realloc(this, ptr, oldsize, size);
+}
+inline bool Environment::AddCleanup(upb_cleanup_func *func, void *ud) {
+  return upb_env_addcleanup(this, func, ud);
+}
+inline size_t Environment::BytesAllocated() const {
+  return upb_env_bytesallocated(this);
+}
+
+inline SeededAllocator::SeededAllocator(void *mem, size_t len) {
+  upb_seededalloc_init(this, mem, len);
+}
+inline SeededAllocator::~SeededAllocator() {
+  upb_seededalloc_uninit(this);
+}
+inline void SeededAllocator::SetFallbackAllocator(upb_alloc_func *alloc,
+                                                  void *ud) {
+  upb_seededalloc_setfallbackalloc(this, alloc, ud);
+}
+inline upb_alloc_func *SeededAllocator::GetAllocationFunction() {
+  return upb_seededalloc_getallocfunc(this);
+}
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_ENV_H_ */
+/*
+** upb::Sink (upb_sink)
+** upb::BytesSink (upb_bytessink)
+**
+** A upb_sink is an object that binds a upb_handlers object to some runtime
+** state.  It is the object that can actually receive data via the upb_handlers
+** interface.
+**
+** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
+** thread-safe.  You can create as many of them as you want, but each one may
+** only be used in a single thread at a time.
+**
+** If we compare with class-based OOP, a you can think of a upb_def as an
+** abstract base class, a upb_handlers as a concrete derived class, and a
+** upb_sink as an object (class instance).
+*/
+
+#ifndef UPB_SINK_H
+#define UPB_SINK_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferSource;
+class BytesSink;
+class Sink;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc)
+UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink)
+UPB_DECLARE_TYPE(upb::Sink, upb_sink)
+
+#ifdef __cplusplus
+
+/* A upb::Sink is an object that binds a upb::Handlers object to some runtime
+ * state.  It represents an endpoint to which data can be sent.
+ *
+ * TODO(haberman): right now all of these functions take selectors.  Should they
+ * take selectorbase instead?
+ *
+ * ie. instead of calling:
+ *   sink->StartString(FOO_FIELD_START_STRING, ...)
+ * a selector base would let you say:
+ *   sink->StartString(FOO_FIELD, ...)
+ *
+ * This would make call sites a little nicer and require emitting fewer selector
+ * definitions in .h files.
+ *
+ * But the current scheme has the benefit that you can retrieve a function
+ * pointer for any handler with handlers->GetHandler(selector), without having
+ * to have a separate GetHandler() function for each handler type.  The JIT
+ * compiler uses this.  To accommodate we'd have to expose a separate
+ * GetHandler() for every handler type.
+ *
+ * Also to ponder: selectors right now are independent of a specific Handlers
+ * instance.  In other words, they allocate a number to every possible handler
+ * that *could* be registered, without knowing anything about what handlers
+ * *are* registered.  That means that using selectors as table offsets prohibits
+ * us from compacting the handler table at Freeze() time.  If the table is very
+ * sparse, this could be wasteful.
+ *
+ * Having another selector-like thing that is specific to a Handlers instance
+ * would allow this compacting, but then it would be impossible to write code
+ * ahead-of-time that can be bound to any Handlers instance at runtime.  For
+ * example, a .proto file parser written as straight C will not know what
+ * Handlers it will be bound to, so when it calls sink->StartString() what
+ * selector will it pass?  It needs a selector like we have today, that is
+ * independent of any particular upb::Handlers.
+ *
+ * Is there a way then to allow Handlers table compaction? */
+class upb::Sink {
+ public:
+  /* Constructor with no initialization; must be Reset() before use. */
+  Sink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> Sink(const Handlers* handlers, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const Handlers* handlers, T* closure);
+
+  /* Returns the top-level object that is bound to this sink.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> T* GetObject() const;
+
+  /* Functions for pushing data into the sink.
+   *
+   * These return false if processing should stop (either due to error or just
+   * to suspend).
+   *
+   * These may not be called from within one of the same sink's handlers (in
+   * other words, handlers are not re-entrant). */
+
+  /* Should be called at the start and end of every message; both the top-level
+   * message and submessages.  This means that submessages should use the
+   * following sequence:
+   *   sink->StartSubMessage(startsubmsg_selector);
+   *   sink->StartMessage();
+   *   // ...
+   *   sink->EndMessage(&status);
+   *   sink->EndSubMessage(endsubmsg_selector); */
+  bool StartMessage();
+  bool EndMessage(Status* status);
+
+  /* Putting of individual values.  These work for both repeated and
+   * non-repeated fields, but for repeated fields you must wrap them in
+   * calls to StartSequence()/EndSequence(). */
+  bool PutInt32(Handlers::Selector s, int32_t val);
+  bool PutInt64(Handlers::Selector s, int64_t val);
+  bool PutUInt32(Handlers::Selector s, uint32_t val);
+  bool PutUInt64(Handlers::Selector s, uint64_t val);
+  bool PutFloat(Handlers::Selector s, float val);
+  bool PutDouble(Handlers::Selector s, double val);
+  bool PutBool(Handlers::Selector s, bool val);
+
+  /* Putting of string/bytes values.  Each string can consist of zero or more
+   * non-contiguous buffers of data.
+   *
+   * For StartString(), the function will write a sink for the string to "sub."
+   * The sub-sink must be used for any/all PutStringBuffer() calls. */
+  bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
+  size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len,
+                         const BufferHandle *handle);
+  bool EndString(Handlers::Selector s);
+
+  /* For submessage fields.
+   *
+   * For StartSubMessage(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * submessage. */
+  bool StartSubMessage(Handlers::Selector s, Sink* sub);
+  bool EndSubMessage(Handlers::Selector s);
+
+  /* For repeated fields of any type, the sequence of values must be wrapped in
+   * these calls.
+   *
+   * For StartSequence(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * sequence. */
+  bool StartSequence(Handlers::Selector s, Sink* sub);
+  bool EndSequence(Handlers::Selector s);
+
+  /* Copy and assign specifically allowed.
+   * We don't even bother making these members private because so many
+   * functions need them and this is mainly just a dumb data container anyway.
+   */
+#else
+struct upb_sink {
+#endif
+  const upb_handlers *handlers;
+  void *closure;
+};
+
+#ifdef __cplusplus
+class upb::BytesSink {
+ public:
+  BytesSink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO(haberman): once the Handlers know the expected closure type, verify
+   * that T matches it. */
+  template <class T> BytesSink(const BytesHandler* handler, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const BytesHandler* handler, T* closure);
+
+  bool Start(size_t size_hint, void **subc);
+  size_t PutBuffer(void *subc, const char *buf, size_t len,
+                   const BufferHandle *handle);
+  bool End();
+#else
+struct upb_bytessink {
+#endif
+  const upb_byteshandler *handler;
+  void *closure;
+};
+
+#ifdef __cplusplus
+
+/* A class for pushing a flat buffer of data to a BytesSink.
+ * You can construct an instance of this to get a resumable source,
+ * or just call the static PutBuffer() to do a non-resumable push all in one
+ * go. */
+class upb::BufferSource {
+ public:
+  BufferSource();
+  BufferSource(const char* buf, size_t len, BytesSink* sink);
+
+  /* Returns true if the entire buffer was pushed successfully.  Otherwise the
+   * next call to PutNext() will resume where the previous one left off.
+   * TODO(haberman): implement this. */
+  bool PutNext();
+
+  /* A static version; with this version is it not possible to resume in the
+   * case of failure or a partially-consumed buffer. */
+  static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
+
+  template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
+    return PutBuffer(str.c_str(), str.size(), sink);
+  }
+#else
+struct upb_bufsrc {
+  char dummy;
+#endif
+};
+
+UPB_BEGIN_EXTERN_C
+
+/* Inline definitions. */
+
+UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
+                                    void *closure) {
+  s->handler = h;
+  s->closure = closure;
+}
+
+UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
+                                    void **subc) {
+  typedef upb_startstr_handlerfunc func;
+  func *start;
+  *subc = s->closure;
+  if (!s->handler) return true;
+  start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+
+  if (!start) return true;
+  *subc = start(s->closure, upb_handlerattr_handlerdata(
+                                &s->handler->table[UPB_STARTSTR_SELECTOR].attr),
+                size_hint);
+  return *subc != NULL;
+}
+
+UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
+                                       const char *buf, size_t size,
+                                       const upb_bufhandle* handle) {
+  typedef upb_string_handlerfunc func;
+  func *putbuf;
+  if (!s->handler) return true;
+  putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func;
+
+  if (!putbuf) return true;
+  return putbuf(subc, upb_handlerattr_handlerdata(
+                          &s->handler->table[UPB_STRING_SELECTOR].attr),
+                buf, size, handle);
+}
+
+UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+  typedef upb_endfield_handlerfunc func;
+  func *end;
+  if (!s->handler) return true;
+  end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+
+  if (!end) return true;
+  return end(s->closure,
+             upb_handlerattr_handlerdata(
+                 &s->handler->table[UPB_ENDSTR_SELECTOR].attr));
+}
+
+UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
+                                  upb_bytessink *sink) {
+  void *subc;
+  bool ret;
+  upb_bufhandle handle;
+  upb_bufhandle_init(&handle);
+  upb_bufhandle_setbuf(&handle, buf, 0);
+  ret = upb_bytessink_start(sink, len, &subc);
+  if (ret && len != 0) {
+    ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
+  }
+  if (ret) {
+    ret = upb_bytessink_end(sink);
+  }
+  upb_bufhandle_uninit(&handle);
+  return ret;
+}
+
+#define PUTVAL(type, ctype)                                                    \
+  UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel,          \
+                                     ctype val) {                              \
+    typedef upb_##type##_handlerfunc functype;                                 \
+    functype *func;                                                            \
+    const void *hd;                                                            \
+    if (!s->handlers) return true;                                             \
+    func = (functype *)upb_handlers_gethandler(s->handlers, sel);              \
+    if (!func) return true;                                                    \
+    hd = upb_handlers_gethandlerdata(s->handlers, sel);                        \
+    return func(s->closure, hd, val);                                          \
+  }
+
+PUTVAL(int32,  int32_t)
+PUTVAL(int64,  int64_t)
+PUTVAL(uint32, uint32_t)
+PUTVAL(uint64, uint64_t)
+PUTVAL(float,  float)
+PUTVAL(double, double)
+PUTVAL(bool,   bool)
+#undef PUTVAL
+
+UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
+  s->handlers = h;
+  s->closure = c;
+}
+
+UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
+                                     const char *buf, size_t n,
+                                     const upb_bufhandle *handle) {
+  typedef upb_string_handlerfunc func;
+  func *handler;
+  const void *hd;
+  if (!s->handlers) return n;
+  handler = (func *)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!handler) return n;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return handler(s->closure, hd, buf, n, handle);
+}
+
+UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
+  typedef upb_startmsg_handlerfunc func;
+  func *startmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR);
+
+  if (!startmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+  return startmsg(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
+  typedef upb_endmsg_handlerfunc func;
+  func *endmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR);
+
+  if (!endmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+  return endmsg(s->closure, hd, status);
+}
+
+UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
+                                  upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startseq;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startseq(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endseq;
+  const void *hd;
+  if (!s->handlers) return true;
+  endseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endseq(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
+                                  size_t size_hint, upb_sink *sub) {
+  typedef upb_startstr_handlerfunc func;
+  func *startstr;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startstr(s->closure, hd, size_hint);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endstr;
+  const void *hd;
+  if (!s->handlers) return true;
+  endstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endstr(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
+                                     upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startsubmsg;
+  const void *hd;
+  sub->closure = s->closure;
+  if (!s->handlers) {
+    sub->handlers = NULL;
+    return true;
+  }
+  sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
+  startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startsubmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startsubmsg(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endsubmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endsubmsg) return s->closure;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endsubmsg(s->closure, hd);
+}
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+template <class T>
+inline void Sink::Reset(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+inline bool Sink::StartMessage() {
+  return upb_sink_startmsg(this);
+}
+inline bool Sink::EndMessage(Status* status) {
+  return upb_sink_endmsg(this, status);
+}
+inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
+  return upb_sink_putint32(this, sel, val);
+}
+inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
+  return upb_sink_putint64(this, sel, val);
+}
+inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
+  return upb_sink_putuint32(this, sel, val);
+}
+inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
+  return upb_sink_putuint64(this, sel, val);
+}
+inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
+  return upb_sink_putfloat(this, sel, val);
+}
+inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
+  return upb_sink_putdouble(this, sel, val);
+}
+inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
+  return upb_sink_putbool(this, sel, val);
+}
+inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
+                              Sink *sub) {
+  return upb_sink_startstr(this, sel, size_hint, sub);
+}
+inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
+                                    size_t len, const BufferHandle* handle) {
+  return upb_sink_putstring(this, sel, buf, len, handle);
+}
+inline bool Sink::EndString(Handlers::Selector sel) {
+  return upb_sink_endstr(this, sel);
+}
+inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startsubmsg(this, sel, sub);
+}
+inline bool Sink::EndSubMessage(Handlers::Selector sel) {
+  return upb_sink_endsubmsg(this, sel);
+}
+inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startseq(this, sel, sub);
+}
+inline bool Sink::EndSequence(Handlers::Selector sel) {
+  return upb_sink_endseq(this, sel);
+}
+
+template <class T>
+BytesSink::BytesSink(const BytesHandler* handler, T* closure) {
+  Reset(handler, closure);
+}
+
+template <class T>
+void BytesSink::Reset(const BytesHandler *handler, T *closure) {
+  upb_bytessink_reset(this, handler, closure);
+}
+inline bool BytesSink::Start(size_t size_hint, void **subc) {
+  return upb_bytessink_start(this, size_hint, subc);
+}
+inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len,
+                                   const BufferHandle *handle) {
+  return upb_bytessink_putbuf(this, subc, buf, len, handle);
+}
+inline bool BytesSink::End() {
+  return upb_bytessink_end(this);
+}
+
+inline bool BufferSource::PutBuffer(const char *buf, size_t len,
+                                    BytesSink *sink) {
+  return upb_bufsrc_putbuf(buf, len, sink);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif
+/*
+** For handlers that do very tiny, very simple operations, the function call
+** overhead of calling a handler can be significant.  This file allows the
+** user to define handlers that do something very simple like store the value
+** to memory and/or set a hasbit.  JIT compilers can then special-case these
+** handlers and emit specialized code for them instead of actually calling the
+** handler.
+**
+** The functionality is very simple/limited right now but may expand to be able
+** to call another function.
+*/
+
+#ifndef UPB_SHIM_H
+#define UPB_SHIM_H
+
+
+typedef struct {
+  size_t offset;
+  int32_t hasbit;
+} upb_shim_data;
+
+#ifdef __cplusplus
+
+namespace upb {
+
+struct Shim {
+  typedef upb_shim_data Data;
+
+  /* Sets a handler for the given field that writes the value to the given
+   * offset and, if hasbit >= 0, sets a bit at the given bit offset.  Returns
+   * true if the handler was set successfully. */
+  static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit);
+
+  /* If this handler is a shim, returns the corresponding upb::Shim::Data and
+   * stores the type in "type".  Otherwise returns NULL. */
+  static const Data* GetData(const Handlers* h, Handlers::Selector s,
+                             FieldDef::Type* type);
+};
+
+}  /* namespace upb */
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+                  int32_t hasbit);
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+                                      upb_fieldtype_t *type);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ Wrappers. */
+namespace upb {
+inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs,
+                      int32_t hasbit) {
+  return upb_shim_set(h, f, ofs, hasbit);
+}
+inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s,
+                                       FieldDef::Type* type) {
+  return upb_shim_getdata(h, s, type);
+}
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_SHIM_H */
+/*
+** upb::SymbolTable (upb_symtab)
+**
+** A symtab (symbol table) stores a name->def map of upb_defs.  Clients could
+** always create such tables themselves, but upb_symtab has logic for resolving
+** symbolic references, and in particular, for keeping a whole set of consistent
+** defs when replacing some subset of those defs.  This logic is nontrivial.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_SYMTAB_H_
+#define UPB_SYMTAB_H_
+
+
+#ifdef __cplusplus
+#include <vector>
+namespace upb { class SymbolTable; }
+#endif
+
+UPB_DECLARE_DERIVED_TYPE(upb::SymbolTable, upb::RefCounted,
+                         upb_symtab, upb_refcounted)
+
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+  upb_strtable_iter iter;
+  upb_deftype_t type;
+} upb_symtab_iter;
+
+#ifdef __cplusplus
+
+/* Non-const methods in upb::SymbolTable are NOT thread-safe. */
+class upb::SymbolTable {
+ public:
+  /* Returns a new symbol table with a single ref owned by "owner."
+   * Returns NULL if memory allocation failed. */
+  static reffed_ptr<SymbolTable> New();
+
+  /* Include RefCounted base methods. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* For all lookup functions, the returned pointer is not owned by the
+   * caller; it may be invalidated by any non-const call or unref of the
+   * SymbolTable!  To protect against this, take a ref if desired. */
+
+  /* Freezes the symbol table: prevents further modification of it.
+   * After the Freeze() operation is successful, the SymbolTable must only be
+   * accessed via a const pointer.
+   *
+   * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not
+   * a necessary step in using a SymbolTable.  If you have no need for it to be
+   * immutable, there is no need to freeze it ever.  However sometimes it is
+   * useful, and SymbolTables that are statically compiled into the binary are
+   * always frozen by nature. */
+  void Freeze();
+
+  /* Resolves the given symbol using the rules described in descriptor.proto,
+   * namely:
+   *
+   *    If the name starts with a '.', it is fully-qualified.  Otherwise,
+   *    C++-like scoping rules are used to find the type (i.e. first the nested
+   *    types within this message are searched, then within the parent, on up
+   *    to the root namespace).
+   *
+   * If not found, returns NULL. */
+  const Def* Resolve(const char* base, const char* sym) const;
+
+  /* Finds an entry in the symbol table with this exact name.  If not found,
+   * returns NULL. */
+  const Def* Lookup(const char *sym) const;
+  const MessageDef* LookupMessage(const char *sym) const;
+  const EnumDef* LookupEnum(const char *sym) const;
+
+  /* TODO: introduce a C++ iterator, but make it nice and templated so that if
+   * you ask for an iterator of MessageDef the iterated elements are strongly
+   * typed as MessageDef*. */
+
+  /* Adds the given mutable defs to the symtab, resolving all symbols
+   * (including enum default values) and finalizing the defs.  Only one def per
+   * name may be in the list, but defs can replace existing defs in the symtab.
+   * All defs must have a name -- anonymous defs are not allowed.  Anonymous
+   * defs can still be frozen by calling upb_def_freeze() directly.
+   *
+   * Any existing defs that can reach defs that are being replaced will
+   * themselves be replaced also, so that the resulting set of defs is fully
+   * consistent.
+   *
+   * This logic implemented in this method is a convenience; ultimately it
+   * calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and
+   * upb_freeze(), any of which the client could call themself.  However, since
+   * the logic for doing so is nontrivial, we provide it here.
+   *
+   * The entire operation either succeeds or fails.  If the operation fails,
+   * the symtab is unchanged, false is returned, and status indicates the
+   * error.  The caller passes a ref on all defs to the symtab (even if the
+   * operation fails).
+   *
+   * TODO(haberman): currently failure will leave the symtab unchanged, but may
+   * leave the defs themselves partially resolved.  Does this matter?  If so we
+   * could do a prepass that ensures that all symbols are resolvable and bail
+   * if not, so we don't mutate anything until we know the operation will
+   * succeed.
+   *
+   * TODO(haberman): since the defs must be mutable, refining a frozen def
+   * requires making mutable copies of the entire tree.  This is wasteful if
+   * only a few messages are changing.  We may want to add a way of adding a
+   * tree of frozen defs to the symtab (perhaps an alternate constructor where
+   * you pass the root of the tree?) */
+  bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status);
+
+  bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
+    return Add((Def*const*)&defs[0], defs.size(), owner, status);
+  }
+
+ private:
+  UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+/* Include refcounted methods like upb_symtab_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_symtab, upb_symtab_upcast)
+
+upb_symtab *upb_symtab_new(const void *owner);
+void upb_symtab_freeze(upb_symtab *s);
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym);
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym);
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
+                    upb_status *status);
+
+/* upb_symtab_iter i;
+ * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i);
+ *     upb_symtab_next(&i)) {
+ *   const upb_def *def = upb_symtab_iter_def(&i);
+ *    // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type);
+void upb_symtab_next(upb_symtab_iter *iter);
+bool upb_symtab_done(const upb_symtab_iter *iter);
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ inline wrappers. */
+namespace upb {
+inline reffed_ptr<SymbolTable> SymbolTable::New() {
+  upb_symtab *s = upb_symtab_new(&s);
+  return reffed_ptr<SymbolTable>(s, &s);
+}
+
+inline void SymbolTable::Freeze() {
+  return upb_symtab_freeze(this);
+}
+inline const Def *SymbolTable::Resolve(const char *base,
+                                       const char *sym) const {
+  return upb_symtab_resolve(this, base, sym);
+}
+inline const Def* SymbolTable::Lookup(const char *sym) const {
+  return upb_symtab_lookup(this, sym);
+}
+inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const {
+  return upb_symtab_lookupmsg(this, sym);
+}
+inline bool SymbolTable::Add(
+    Def*const* defs, int n, void* ref_donor, upb_status* status) {
+  return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status);
+}
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_SYMTAB_H_ */
+/*
+** upb::descriptor::Reader (upb_descreader)
+**
+** Provides a way of building upb::Defs from data in descriptor.proto format.
+*/
+
+#ifndef UPB_DESCRIPTOR_H
+#define UPB_DESCRIPTOR_H
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace descriptor {
+class Reader;
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader)
+
+#ifdef __cplusplus
+
+/* Class that receives descriptor data according to the descriptor.proto schema
+ * and use it to build upb::Defs corresponding to that schema. */
+class upb::descriptor::Reader {
+ public:
+  /* These handlers must have come from NewHandlers() and must outlive the
+   * Reader.
+   *
+   * TODO: generate the handlers statically (like we do with the
+   * descriptor.proto defs) so that there is no need to pass this parameter (or
+   * to build/memory-manage the handlers at runtime at all).  Unfortunately this
+   * is a bit tricky to implement for Handlers, but necessary to simplify this
+   * interface. */
+  static Reader* Create(Environment* env, const Handlers* handlers);
+
+  /* The reader's input; this is where descriptor.proto data should be sent. */
+  Sink* input();
+
+  /* Returns an array of all defs that have been parsed, and transfers ownership
+   * of them to "owner".  The number of defs is stored in *n.  Ownership of the
+   * returned array is retained and is invalidated by any other call into
+   * Reader.
+   *
+   * These defs are not frozen or resolved; they are ready to be added to a
+   * symtab. */
+  upb::Def** GetDefs(void* owner, int* n);
+
+  /* Builds and returns handlers for the reader, owned by "owner." */
+  static Handlers* NewHandlers(const void* owner);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h);
+upb_sink *upb_descreader_input(upb_descreader *r);
+upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n);
+const upb_handlers *upb_descreader_newhandlers(const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ implementation details. ************************************************/
+namespace upb {
+namespace descriptor {
+inline Reader* Reader::Create(Environment* e, const Handlers *h) {
+  return upb_descreader_create(e, h);
+}
+inline Sink* Reader::input() { return upb_descreader_input(this); }
+inline upb::Def** Reader::GetDefs(void* owner, int* n) {
+  return upb_descreader_getdefs(this, owner, n);
+}
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_DESCRIPTOR_H */
+/* This file contains accessors for a set of compiled-in defs.
+ * Note that unlike Google's protobuf, it does *not* define
+ * generated classes or any other kind of data structure for
+ * actually storing protobufs.  It only contains *defs* which
+ * let you reflect over a protobuf *schema*.
+ */
+/* This file was generated by upbc (the upb compiler).
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_
+#define GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_
+
+
+#ifdef __cplusplus
+UPB_BEGIN_EXTERN_C
+#endif
+
+/* Enums */
+
+typedef enum {
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_OPTIONAL = 1,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED = 2,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED = 3
+} google_protobuf_FieldDescriptorProto_Label;
+
+typedef enum {
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_DOUBLE = 1,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FLOAT = 2,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT64 = 3,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT64 = 4,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 = 5,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED64 = 6,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED32 = 7,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BOOL = 8,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING = 9,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_GROUP = 10,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_MESSAGE = 11,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES = 12,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32 = 13,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ENUM = 14,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED32 = 15,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED64 = 16,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT32 = 17,
+  GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT64 = 18
+} google_protobuf_FieldDescriptorProto_Type;
+
+typedef enum {
+  GOOGLE_PROTOBUF_FIELDOPTIONS_STRING = 0,
+  GOOGLE_PROTOBUF_FIELDOPTIONS_CORD = 1,
+  GOOGLE_PROTOBUF_FIELDOPTIONS_STRING_PIECE = 2
+} google_protobuf_FieldOptions_CType;
+
+typedef enum {
+  GOOGLE_PROTOBUF_FILEOPTIONS_SPEED = 1,
+  GOOGLE_PROTOBUF_FILEOPTIONS_CODE_SIZE = 2,
+  GOOGLE_PROTOBUF_FILEOPTIONS_LITE_RUNTIME = 3
+} google_protobuf_FileOptions_OptimizeMode;
+
+/* Selectors */
+
+/* google.protobuf.DescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 8
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 9
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 10
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 11
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 12
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 14
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 15
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 16
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 17
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 18
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 19
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 20
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 21
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 23
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 24
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 25
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 26
+
+/* google.protobuf.DescriptorProto.ExtensionRange */
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2
+#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3
+
+/* google.protobuf.EnumDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10
+
+/* google.protobuf.EnumOptions */
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_ALLOW_ALIAS_BOOL 6
+
+/* google.protobuf.EnumValueDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7
+
+/* google.protobuf.EnumValueOptions */
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+/* google.protobuf.FieldDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17
+#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18
+
+/* google.protobuf.FieldOptions */
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_LAZY_BOOL 9
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 10
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 11
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 12
+#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_WEAK_BOOL 13
+
+/* google.protobuf.FileDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_STARTSEQ 33
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_ENDSEQ 34
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_INT32 35
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_STARTSEQ 36
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_ENDSEQ 37
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_INT32 38
+
+/* google.protobuf.FileDescriptorSet */
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5
+
+/* google.protobuf.FileOptions */
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STRING 14
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STARTSTR 15
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_ENDSTR 16
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 17
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 18
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 19
+#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 20
+
+/* google.protobuf.MessageOptions */
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6
+#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7
+
+/* google.protobuf.MethodDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11
+#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12
+
+/* google.protobuf.MethodOptions */
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+/* google.protobuf.ServiceDescriptorProto */
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10
+
+/* google.protobuf.ServiceOptions */
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+
+/* google.protobuf.SourceCodeInfo */
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5
+
+/* google.protobuf.SourceCodeInfo.Location */
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 2
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STRING 8
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STARTSTR 9
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_ENDSTR 10
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STRING 11
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STARTSTR 12
+#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_ENDSTR 13
+
+/* google.protobuf.UninterpretedOption */
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17
+
+/* google.protobuf.UninterpretedOption.NamePart */
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4
+#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5
+
+const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner);
+
+/* MessageDefs */
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MessageOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceOptions(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption");
+  assert(m);
+  return m;
+}
+UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart(const upb_symtab *s) {
+  const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart");
+  assert(m);
+  return m;
+}
+
+
+/* EnumDefs */
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label(const upb_symtab *s) {
+  const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Label");
+  assert(e);
+  return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type(const upb_symtab *s) {
+  const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Type");
+  assert(e);
+  return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType(const upb_symtab *s) {
+  const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldOptions.CType");
+  assert(e);
+  return e;
+}
+UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode(const upb_symtab *s) {
+  const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FileOptions.OptimizeMode");
+  assert(e);
+  return e;
+}
+
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension_range(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_field(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_nested_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_allow_alias(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_default_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_extendee(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_label(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_ctype(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_experimental_map_key(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_lazy(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_packed(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_weak(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_message_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_public_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_service(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_source_code_info(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_weak_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_file(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorSet(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_cc_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 16); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_go_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 20); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 17); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_multiple_files(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_outer_classname(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_optimize_for(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_py_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 18); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_message_set_wire_format(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_input_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_output_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_method(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceOptions(s), 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_path(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_span(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_location(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_aggregate_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_double_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_identifier_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_negative_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_positive_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_string_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 7); }
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upbdefs {
+namespace google {
+namespace protobuf {
+namespace descriptor {
+inline upb::reffed_ptr<const upb::SymbolTable> SymbolTable() {
+  const upb::SymbolTable* s = upbdefs_google_protobuf_descriptor(&s);
+  return upb::reffed_ptr<const upb::SymbolTable>(s, &s);
+}
+}  /* namespace descriptor */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+#define RETURN_REFFED(type, func) \
+    const type* obj = func(upbdefs::google::protobuf::descriptor::SymbolTable().get()); \
+    return upb::reffed_ptr<const type>(obj);
+
+namespace google {
+namespace protobuf {
+namespace DescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_enum_type) }
+inline upb::reffed_ptr<const upb::FieldDef> extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> extension_range() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension_range) }
+inline upb::reffed_ptr<const upb::FieldDef> field() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_field) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> nested_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_nested_type) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_options) }
+}  /* namespace DescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace DescriptorProto {
+namespace ExtensionRange {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange) }
+inline upb::reffed_ptr<const upb::FieldDef> end() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end) }
+inline upb::reffed_ptr<const upb::FieldDef> start() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start) }
+}  /* namespace ExtensionRange */
+}  /* namespace DescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace EnumDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_value) }
+}  /* namespace EnumDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace EnumOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> allow_alias() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_allow_alias) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_uninterpreted_option) }
+}  /* namespace EnumOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace EnumValueDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_number) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_options) }
+}  /* namespace EnumValueDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace EnumValueOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option) }
+}  /* namespace EnumValueOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace FieldDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> default_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_default_value) }
+inline upb::reffed_ptr<const upb::FieldDef> extendee() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_extendee) }
+inline upb::reffed_ptr<const upb::FieldDef> label() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_label) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_number) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type) }
+inline upb::reffed_ptr<const upb::FieldDef> type_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type_name) }
+inline upb::reffed_ptr<const upb::EnumDef> Label() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Label) }
+inline upb::reffed_ptr<const upb::EnumDef> Type() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Type) }
+}  /* namespace FieldDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace FieldOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> ctype() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_ctype) }
+inline upb::reffed_ptr<const upb::FieldDef> deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_deprecated) }
+inline upb::reffed_ptr<const upb::FieldDef> experimental_map_key() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_experimental_map_key) }
+inline upb::reffed_ptr<const upb::FieldDef> lazy() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_lazy) }
+inline upb::reffed_ptr<const upb::FieldDef> packed() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_packed) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_uninterpreted_option) }
+inline upb::reffed_ptr<const upb::FieldDef> weak() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_weak) }
+inline upb::reffed_ptr<const upb::EnumDef> CType() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldOptions_CType) }
+}  /* namespace FieldOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace FileDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_dependency) }
+inline upb::reffed_ptr<const upb::FieldDef> enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_enum_type) }
+inline upb::reffed_ptr<const upb::FieldDef> extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> message_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_message_type) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_package) }
+inline upb::reffed_ptr<const upb::FieldDef> public_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_public_dependency) }
+inline upb::reffed_ptr<const upb::FieldDef> service() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_service) }
+inline upb::reffed_ptr<const upb::FieldDef> source_code_info() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_source_code_info) }
+inline upb::reffed_ptr<const upb::FieldDef> weak_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_weak_dependency) }
+}  /* namespace FileDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace FileDescriptorSet {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorSet) }
+inline upb::reffed_ptr<const upb::FieldDef> file() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorSet_file) }
+}  /* namespace FileDescriptorSet */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace FileOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> cc_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_cc_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> go_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_go_package) }
+inline upb::reffed_ptr<const upb::FieldDef> java_generate_equals_and_hash() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash) }
+inline upb::reffed_ptr<const upb::FieldDef> java_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> java_multiple_files() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_multiple_files) }
+inline upb::reffed_ptr<const upb::FieldDef> java_outer_classname() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_outer_classname) }
+inline upb::reffed_ptr<const upb::FieldDef> java_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_package) }
+inline upb::reffed_ptr<const upb::FieldDef> optimize_for() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_optimize_for) }
+inline upb::reffed_ptr<const upb::FieldDef> py_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_py_generic_services) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_uninterpreted_option) }
+inline upb::reffed_ptr<const upb::EnumDef> OptimizeMode() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FileOptions_OptimizeMode) }
+}  /* namespace FileOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace MessageOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MessageOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> message_set_wire_format() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_message_set_wire_format) }
+inline upb::reffed_ptr<const upb::FieldDef> no_standard_descriptor_accessor() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_uninterpreted_option) }
+}  /* namespace MessageOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace MethodDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> input_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_input_type) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_options) }
+inline upb::reffed_ptr<const upb::FieldDef> output_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_output_type) }
+}  /* namespace MethodDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace MethodOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodOptions_uninterpreted_option) }
+}  /* namespace MethodOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace ServiceDescriptorProto {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceDescriptorProto) }
+inline upb::reffed_ptr<const upb::FieldDef> method() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_method) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_name) }
+inline upb::reffed_ptr<const upb::FieldDef> options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_options) }
+}  /* namespace ServiceDescriptorProto */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace ServiceOptions {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceOptions) }
+inline upb::reffed_ptr<const upb::FieldDef> uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceOptions_uninterpreted_option) }
+}  /* namespace ServiceOptions */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace SourceCodeInfo {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo) }
+inline upb::reffed_ptr<const upb::FieldDef> location() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_location) }
+}  /* namespace SourceCodeInfo */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace SourceCodeInfo {
+namespace Location {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo_Location) }
+inline upb::reffed_ptr<const upb::FieldDef> leading_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments) }
+inline upb::reffed_ptr<const upb::FieldDef> path() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_path) }
+inline upb::reffed_ptr<const upb::FieldDef> span() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_span) }
+inline upb::reffed_ptr<const upb::FieldDef> trailing_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments) }
+}  /* namespace Location */
+}  /* namespace SourceCodeInfo */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace UninterpretedOption {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption) }
+inline upb::reffed_ptr<const upb::FieldDef> aggregate_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_aggregate_value) }
+inline upb::reffed_ptr<const upb::FieldDef> double_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_double_value) }
+inline upb::reffed_ptr<const upb::FieldDef> identifier_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_identifier_value) }
+inline upb::reffed_ptr<const upb::FieldDef> name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_name) }
+inline upb::reffed_ptr<const upb::FieldDef> negative_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_negative_int_value) }
+inline upb::reffed_ptr<const upb::FieldDef> positive_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_positive_int_value) }
+inline upb::reffed_ptr<const upb::FieldDef> string_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_string_value) }
+}  /* namespace UninterpretedOption */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+namespace google {
+namespace protobuf {
+namespace UninterpretedOption {
+namespace NamePart {
+inline upb::reffed_ptr<const upb::MessageDef> MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption_NamePart) }
+inline upb::reffed_ptr<const upb::FieldDef> is_extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension) }
+inline upb::reffed_ptr<const upb::FieldDef> name_part() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part) }
+}  /* namespace NamePart */
+}  /* namespace UninterpretedOption */
+}  /* namespace protobuf */
+}  /* namespace google */
+
+}  /* namespace upbdefs */
+
+
+#undef RETURN_REFFED
+#endif /* __cplusplus */
+
+#endif  /* GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ */
+/*
+** Internal-only definitions for the decoder.
+*/
+
+#ifndef UPB_DECODER_INT_H_
+#define UPB_DECODER_INT_H_
+
+#include <stdlib.h>
+/*
+** upb::pb::Decoder
+**
+** A high performance, streaming, resumable decoder for the binary protobuf
+** format.
+**
+** This interface works the same regardless of what decoder backend is being
+** used.  A client of this class does not need to know whether decoding is using
+** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder.  By default,
+** it will always use the fastest available decoder.  However, you can call
+** set_allow_jit(false) to disable any JIT decoder that might be available.
+** This is primarily useful for testing purposes.
+*/
+
+#ifndef UPB_DECODER_H_
+#define UPB_DECODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class CodeCache;
+class Decoder;
+class DecoderMethod;
+class DecoderMethodOptions;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache)
+UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder)
+UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts)
+
+UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted,
+                         upb_pbdecodermethod, upb_refcounted)
+
+#ifdef __cplusplus
+
+/* The parameters one uses to construct a DecoderMethod.
+ * TODO(haberman): move allowjit here?  Seems more convenient for users.
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::DecoderMethodOptions {
+ public:
+  /* Parameter represents the destination handlers that this method will push
+   * to. */
+  explicit DecoderMethodOptions(const Handlers* dest_handlers);
+
+  /* Should the decoder push submessages to lazy handlers for fields that have
+   * them?  The caller should set this iff the lazy handlers expect data that is
+   * in protobuf binary format and the caller wishes to lazy parse it. */
+  void set_lazy(bool lazy);
+#else
+struct upb_pbdecodermethodopts {
+#endif
+  const upb_handlers *handlers;
+  bool lazy;
+};
+
+#ifdef __cplusplus
+
+/* Represents the code to parse a protobuf according to a destination
+ * Handlers. */
+class upb::pb::DecoderMethod {
+ public:
+  /* Include base methods from upb::ReferenceCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* The destination handlers that are statically bound to this method.
+   * This method is only capable of outputting to a sink that uses these
+   * handlers. */
+  const Handlers* dest_handlers() const;
+
+  /* The input handlers for this decoder method. */
+  const BytesHandler* input_handler() const;
+
+  /* Whether this method is native. */
+  bool is_native() const;
+
+  /* Convenience method for generating a DecoderMethod without explicitly
+   * creating a CodeCache. */
+  static reffed_ptr<const DecoderMethod> New(const DecoderMethodOptions& opts);
+
+ private:
+  UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod)
+};
+
+#endif
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_DECODER_SIZE 4408
+
+#ifdef __cplusplus
+
+/* A Decoder receives binary protobuf data on its input sink and pushes the
+ * decoded data to its output sink. */
+class upb::pb::Decoder {
+ public:
+  /* Constructs a decoder instance for the given method, which must outlive this
+   * decoder.  Any errors during parsing will be set on the given status, which
+   * must also outlive this decoder.
+   *
+   * The sink must match the given method. */
+  static Decoder* Create(Environment* env, const DecoderMethod* method,
+                         Sink* output);
+
+  /* Returns the DecoderMethod this decoder is parsing from. */
+  const DecoderMethod* method() const;
+
+  /* The sink on which this decoder receives input. */
+  BytesSink* input();
+
+  /* Returns number of bytes successfully parsed.
+   *
+   * This can be useful for determining the stream position where an error
+   * occurred.
+   *
+   * This value may not be up-to-date when called from inside a parsing
+   * callback. */
+  uint64_t BytesParsed() const;
+
+  /* Gets/sets the parsing nexting limit.  If the total number of nested
+   * submessages and repeated fields hits this limit, parsing will fail.  This
+   * is a resource limit that controls the amount of memory used by the parsing
+   * stack.
+   *
+   * Setting the limit will fail if the parser is currently suspended at a depth
+   * greater than this, or if memory allocation of the stack fails. */
+  size_t max_nesting() const;
+  bool set_max_nesting(size_t max);
+
+  void Reset();
+
+  static const size_t kSize = UPB_PB_DECODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder)
+};
+
+#endif  /* __cplusplus */
+
+#ifdef __cplusplus
+
+/* A class for caching protobuf processing code, whether bytecode for the
+ * interpreted decoder or machine code for the JIT.
+ *
+ * This class is not thread-safe.
+ *
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::CodeCache {
+ public:
+  CodeCache();
+  ~CodeCache();
+
+  /* Whether the cache is allowed to generate machine code.  Defaults to true.
+   * There is no real reason to turn it off except for testing or if you are
+   * having a specific problem with the JIT.
+   *
+   * Note that allow_jit = true does not *guarantee* that the code will be JIT
+   * compiled.  If this platform is not supported or the JIT was not compiled
+   * in, the code may still be interpreted. */
+  bool allow_jit() const;
+
+  /* This may only be called when the object is first constructed, and prior to
+   * any code generation, otherwise returns false and does nothing. */
+  bool set_allow_jit(bool allow);
+
+  /* Returns a DecoderMethod that can push data to the given handlers.
+   * If a suitable method already exists, it will be returned from the cache.
+   *
+   * Specifying the destination handlers here allows the DecoderMethod to be
+   * statically bound to the destination handlers if possible, which can allow
+   * more efficient decoding.  However the returned method may or may not
+   * actually be statically bound.  But in all cases, the returned method can
+   * push data to the given handlers. */
+  const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts);
+
+  /* If/when someone needs to explicitly create a dynamically-bound
+   * DecoderMethod*, we can add a method to get it here. */
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache)
+#else
+struct upb_pbcodecache {
+#endif
+  bool allow_jit_;
+
+  /* Array of mgroups. */
+  upb_inttable groups;
+};
+
+UPB_BEGIN_EXTERN_C
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e,
+                                    const upb_pbdecodermethod *method,
+                                    upb_sink *output);
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d);
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max);
+void upb_pbdecoder_reset(upb_pbdecoder *d);
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h);
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy);
+
+
+/* Include refcounted methods like upb_pbdecodermethod_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_pbdecodermethod, upb_pbdecodermethod_upcast)
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner);
+
+void upb_pbcodecache_init(upb_pbcodecache *c);
+void upb_pbcodecache_uninit(upb_pbcodecache *c);
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+namespace pb {
+
+/* static */
+inline Decoder* Decoder::Create(Environment* env, const DecoderMethod* m,
+                                Sink* sink) {
+  return upb_pbdecoder_create(env, m, sink);
+}
+inline const DecoderMethod* Decoder::method() const {
+  return upb_pbdecoder_method(this);
+}
+inline BytesSink* Decoder::input() {
+  return upb_pbdecoder_input(this);
+}
+inline uint64_t Decoder::BytesParsed() const {
+  return upb_pbdecoder_bytesparsed(this);
+}
+inline size_t Decoder::max_nesting() const {
+  return upb_pbdecoder_maxnesting(this);
+}
+inline bool Decoder::set_max_nesting(size_t max) {
+  return upb_pbdecoder_setmaxnesting(this, max);
+}
+inline void Decoder::Reset() { upb_pbdecoder_reset(this); }
+
+inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) {
+  upb_pbdecodermethodopts_init(this, h);
+}
+inline void DecoderMethodOptions::set_lazy(bool lazy) {
+  upb_pbdecodermethodopts_setlazy(this, lazy);
+}
+
+inline const Handlers* DecoderMethod::dest_handlers() const {
+  return upb_pbdecodermethod_desthandlers(this);
+}
+inline const BytesHandler* DecoderMethod::input_handler() const {
+  return upb_pbdecodermethod_inputhandler(this);
+}
+inline bool DecoderMethod::is_native() const {
+  return upb_pbdecodermethod_isnative(this);
+}
+/* static */
+inline reffed_ptr<const DecoderMethod> DecoderMethod::New(
+    const DecoderMethodOptions &opts) {
+  const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
+  return reffed_ptr<const DecoderMethod>(m, &m);
+}
+
+inline CodeCache::CodeCache() {
+  upb_pbcodecache_init(this);
+}
+inline CodeCache::~CodeCache() {
+  upb_pbcodecache_uninit(this);
+}
+inline bool CodeCache::allow_jit() const {
+  return upb_pbcodecache_allowjit(this);
+}
+inline bool CodeCache::set_allow_jit(bool allow) {
+  return upb_pbcodecache_setallowjit(this, allow);
+}
+inline const DecoderMethod *CodeCache::GetDecoderMethod(
+    const DecoderMethodOptions& opts) {
+  return upb_pbcodecache_getdecodermethod(this, &opts);
+}
+
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_DECODER_H_ */
+
+/* C++ names are not actually used since this type isn't exposed to users. */
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class MessageGroup;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+UPB_DECLARE_DERIVED_TYPE(upb::pb::MessageGroup, upb::RefCounted,
+                         mgroup, upb_refcounted)
+
+/* Opcode definitions.  The canonical meaning of each opcode is its
+ * implementation in the interpreter (the JIT is written to match this).
+ *
+ * All instructions have the opcode in the low byte.
+ * Instruction format for most instructions is:
+ *
+ * +-------------------+--------+
+ * |     arg (24)      | op (8) |
+ * +-------------------+--------+
+ *
+ * Exceptions are indicated below.  A few opcodes are multi-word. */
+typedef enum {
+  /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types.
+   * Arg for all of these is the upb selector for this field. */
+#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type
+  T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
+  T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
+#undef T
+  OP_STARTMSG       = 9,   /* No arg. */
+  OP_ENDMSG         = 10,  /* No arg. */
+  OP_STARTSEQ       = 11,
+  OP_ENDSEQ         = 12,
+  OP_STARTSUBMSG    = 14,
+  OP_ENDSUBMSG      = 19,
+  OP_STARTSTR       = 20,
+  OP_STRING         = 21,
+  OP_ENDSTR         = 22,
+
+  OP_PUSHTAGDELIM   = 23,  /* No arg. */
+  OP_PUSHLENDELIM   = 24,  /* No arg. */
+  OP_POP            = 25,  /* No arg. */
+  OP_SETDELIM       = 26,  /* No arg. */
+  OP_SETBIGGROUPNUM = 27,  /* two words:
+                            *   | unused (24)     | opc (8) |
+                            *   |        groupnum (32)      | */
+  OP_CHECKDELIM     = 28,
+  OP_CALL           = 29,
+  OP_RET            = 30,
+  OP_BRANCH         = 31,
+
+  /* Different opcodes depending on how many bytes expected. */
+  OP_TAG1           = 32,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAG2           = 33,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAGN           = 34,  /* three words: */
+                           /*   | unused (16) | jump target(8) | opc (8) | */
+                           /*   |           match tag 1 (32)             | */
+                           /*   |           match tag 2 (32)             | */
+
+  OP_SETDISPATCH    = 35,  /* N words: */
+                           /*   | unused (24)         | opc | */
+                           /*   | upb_inttable* (32 or 64)  | */
+
+  OP_DISPATCH       = 36,  /* No arg. */
+
+  OP_HALT           = 37   /* No arg. */
+} opcode;
+
+#define OP_MAX OP_HALT
+
+UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
+
+/* Method group; represents a set of decoder methods that had their code
+ * emitted together, and must therefore be freed together.  Immutable once
+ * created.  It is possible we may want to expose this to users at some point.
+ *
+ * Overall ownership of Decoder objects looks like this:
+ *
+ *                +----------+
+ *                |          | <---> DecoderMethod
+ *                | method   |
+ * CodeCache ---> |  group   | <---> DecoderMethod
+ *                |          |
+ *                | (mgroup) | <---> DecoderMethod
+ *                +----------+
+ */
+struct mgroup {
+  upb_refcounted base;
+
+  /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod.  We own refs on the
+   * methods. */
+  upb_inttable methods;
+
+  /* When we add the ability to link to previously existing mgroups, we'll
+   * need an array of mgroups we reference here, and own refs on them. */
+
+  /* The bytecode for our methods, if any exists.  Owned by us. */
+  uint32_t *bytecode;
+  uint32_t *bytecode_end;
+
+#ifdef UPB_USE_JIT_X64
+  /* JIT-generated machine code, if any. */
+  upb_string_handlerfunc *jit_code;
+  /* The size of the jit_code (required to munmap()). */
+  size_t jit_size;
+  char *debug_info;
+  void *dl;
+#endif
+};
+
+/* The maximum that any submessages can be nested.  Matches proto2's limit.
+ * This specifies the size of the decoder's statically-sized array and therefore
+ * setting it high will cause the upb::pb::Decoder object to be larger.
+ *
+ * If necessary we can add a runtime-settable property to Decoder that allow
+ * this to be larger than the compile-time setting, but this would add
+ * complexity, particularly since we would have to decide how/if to give users
+ * the ability to set a custom memory allocation function. */
+#define UPB_DECODER_MAX_NESTING 64
+
+/* Internal-only struct used by the decoder. */
+typedef struct {
+  /* Space optimization note: we store two pointers here that the JIT
+   * doesn't need at all; the upb_handlers* inside the sink and
+   * the dispatch table pointer.  We can optimze so that the JIT uses
+   * smaller stack frames than the interpreter.  The only thing we need
+   * to guarantee is that the fallback routines can find end_ofs. */
+  upb_sink sink;
+
+  /* The absolute stream offset of the end-of-frame delimiter.
+   * Non-delimited frames (groups and non-packed repeated fields) reuse the
+   * delimiter of their parent, even though the frame may not end there.
+   *
+   * NOTE: the JIT stores a slightly different value here for non-top frames.
+   * It stores the value relative to the end of the enclosed message.  But the
+   * top frame is still stored the same way, which is important for ensuring
+   * that calls from the JIT into C work correctly. */
+  uint64_t end_ofs;
+  const uint32_t *base;
+
+  /* 0 indicates a length-delimited field.
+   * A positive number indicates a known group.
+   * A negative number indicates an unknown group. */
+  int32_t groupnum;
+  upb_inttable *dispatch;  /* Not used by the JIT. */
+} upb_pbdecoder_frame;
+
+struct upb_pbdecodermethod {
+  upb_refcounted base;
+
+  /* While compiling, the base is relative in "ofs", after compiling it is
+   * absolute in "ptr". */
+  union {
+    uint32_t ofs;     /* PC offset of method. */
+    void *ptr;        /* Pointer to bytecode or machine code for this method. */
+  } code_base;
+
+  /* The decoder method group to which this method belongs.  We own a ref.
+   * Owning a ref on the entire group is more coarse-grained than is strictly
+   * necessary; all we truly require is that methods we directly reference
+   * outlive us, while the group could contain many other messages we don't
+   * require.  But the group represents the messages that were
+   * allocated+compiled together, so it makes the most sense to free them
+   * together also. */
+  const upb_refcounted *group;
+
+  /* Whether this method is native code or bytecode. */
+  bool is_native_;
+
+  /* The handler one calls to invoke this method. */
+  upb_byteshandler input_handler_;
+
+  /* The destination handlers this method is bound to.  We own a ref. */
+  const upb_handlers *dest_handlers_;
+
+  /* Dispatch table -- used by both bytecode decoder and JIT when encountering a
+   * field number that wasn't the one we were expecting to see.  See
+   * decoder.int.h for the layout of this table. */
+  upb_inttable dispatch;
+};
+
+struct upb_pbdecoder {
+  upb_env *env;
+
+  /* Our input sink. */
+  upb_bytessink input_;
+
+  /* The decoder method we are parsing with (owned). */
+  const upb_pbdecodermethod *method_;
+
+  size_t call_len;
+  const uint32_t *pc, *last;
+
+  /* Current input buffer and its stream offset. */
+  const char *buf, *ptr, *end, *checkpoint;
+
+  /* End of the delimited region, relative to ptr, NULL if not in this buf. */
+  const char *delim_end;
+
+  /* End of the delimited region, relative to ptr, end if not in this buf. */
+  const char *data_end;
+
+  /* Overall stream offset of "buf." */
+  uint64_t bufstart_ofs;
+
+  /* Buffer for residual bytes not parsed from the previous buffer.
+   * The maximum number of residual bytes we require is 12; a five-byte
+   * unknown tag plus an eight-byte value, less one because the value
+   * is only a partial value. */
+  char residual[12];
+  char *residual_end;
+
+  /* Bytes of data that should be discarded from the input beore we start
+   * parsing again.  We set this when we internally determine that we can
+   * safely skip the next N bytes, but this region extends past the current
+   * user buffer. */
+  size_t skip;
+
+  /* Stores the user buffer passed to our decode function. */
+  const char *buf_param;
+  size_t size_param;
+  const upb_bufhandle *handle;
+
+  /* Our internal stack. */
+  upb_pbdecoder_frame *stack, *top, *limit;
+  const uint32_t **callstack;
+  size_t stack_size;
+
+  upb_status *status;
+
+#ifdef UPB_USE_JIT_X64
+  /* Used momentarily by the generated code to store a value while a user
+   * function is called. */
+  uint32_t tmp_len;
+
+  const void *saved_rsp;
+#endif
+};
+
+/* Decoder entry points; used as handlers. */
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
+size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
+                            size_t size, const upb_bufhandle *handle);
+bool upb_pbdecoder_end(void *closure, const void *handler_data);
+
+/* Decoder-internal functions that the JIT calls to handle fallback paths. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle);
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type);
+int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected);
+int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64);
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32);
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64);
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+extern const char *kPbDecoderStackOverflow;
+extern const char *kPbDecoderSubmessageTooLong;
+
+/* Access to decoderplan members needed by the decoder. */
+const char *upb_pbdecoder_getopname(unsigned int op);
+
+/* JIT codegen entry point. */
+void upb_pbdecoder_jit(mgroup *group);
+void upb_pbdecoder_freejit(mgroup *group);
+UPB_REFCOUNTED_CMETHODS(mgroup, mgroup_upcast)
+
+/* A special label that means "do field dispatch for this message and branch to
+ * wherever that takes you." */
+#define LABEL_DISPATCH 0
+
+/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or
+ * RET) for branching to when we find an appropriate ENDGROUP tag. */
+#define DISPATCH_ENDMSG 0
+
+/* It's important to use this invalid wire type instead of 0 (which is a valid
+ * wire type). */
+#define NO_WIRE_TYPE 0xff
+
+/* The dispatch table layout is:
+ *   [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
+ *
+ * If wt1 matches, jump to the 48-bit offset.  If wt2 matches, lookup
+ * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
+ *
+ * We need two wire types because of packed/non-packed compatibility.  A
+ * primitive repeated field can use either wire type and be valid.  While we
+ * could key the table on fieldnum+wiretype, the table would be 8x sparser.
+ *
+ * Storing two wire types in the primary value allows us to quickly rule out
+ * the second wire type without needing to do a separate lookup (this case is
+ * less common than an unknown field). */
+UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1,
+                                               uint8_t wt2) {
+  return (ofs << 16) | (wt2 << 8) | wt1;
+}
+
+UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs,
+                                             uint8_t *wt1, uint8_t *wt2) {
+  *wt1 = (uint8_t)dispatch;
+  *wt2 = (uint8_t)(dispatch >> 8);
+  *ofs = dispatch >> 16;
+}
+
+/* All of the functions in decoder.c that return int32_t return values according
+ * to the following scheme:
+ *   1. negative values indicate a return code from the following list.
+ *   2. positive values indicate that error or end of buffer was hit, and
+ *      that the decode function should immediately return the given value
+ *      (the decoder state has already been suspended and is ready to be
+ *      resumed). */
+#define DECODE_OK -1
+#define DECODE_MISMATCH -2  /* Used only from checktag_slow(). */
+#define DECODE_ENDGROUP -3  /* Used only from checkunknown(). */
+
+#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; }
+
+#endif  /* UPB_DECODER_INT_H_ */
+/*
+** A number of routines for varint manipulation (we keep them all around to
+** have multiple approaches available for benchmarking).
+*/
+
+#ifndef UPB_VARINT_DECODER_H_
+#define UPB_VARINT_DECODER_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A list of types as they are encoded on-the-wire. */
+typedef enum {
+  UPB_WIRE_TYPE_VARINT      = 0,
+  UPB_WIRE_TYPE_64BIT       = 1,
+  UPB_WIRE_TYPE_DELIMITED   = 2,
+  UPB_WIRE_TYPE_START_GROUP = 3,
+  UPB_WIRE_TYPE_END_GROUP   = 4,
+  UPB_WIRE_TYPE_32BIT       = 5
+} upb_wiretype_t;
+
+#define UPB_MAX_WIRE_TYPE 5
+
+/* The maximum number of bytes that it takes to encode a 64-bit varint.
+ * Note that with a better encoding this could be 9 (TODO: write up a
+ * wiki document about this). */
+#define UPB_PB_VARINT_MAX_LEN 10
+
+/* Array of the "native" (ie. non-packed-repeated) wire type for the given a
+ * descriptor type (upb_descriptortype_t). */
+extern const uint8_t upb_pb_native_wire_types[];
+
+/* Zig-zag encoding/decoding **************************************************/
+
+UPB_INLINE int32_t upb_zzdec_32(uint32_t n) {
+  return (n >> 1) ^ -(int32_t)(n & 1);
+}
+UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
+  return (n >> 1) ^ -(int64_t)(n & 1);
+}
+UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+/* Decoding *******************************************************************/
+
+/* All decoding functions return this struct by value. */
+typedef struct {
+  const char *p;  /* NULL if the varint was unterminated. */
+  uint64_t val;
+} upb_decoderet;
+
+UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) {
+  upb_decoderet ret;
+  ret.p = p;
+  ret.val = val;
+  return ret;
+}
+
+/* Four functions for decoding a varint of at most eight bytes.  They are all
+ * functionally identical, but are implemented in different ways and likely have
+ * different performance profiles.  We keep them around for performance testing.
+ *
+ * Note that these functions may not read byte-by-byte, so they must not be used
+ * unless there are at least eight bytes left in the buffer! */
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r);
+
+/* Template for a function that checks the first two bytes with branching
+ * and dispatches 2-10 bytes with a separate function.  Note that this may read
+ * up to 10 bytes, so it must not be used unless there are at least ten bytes
+ * left in the buffer! */
+#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function)                  \
+UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) {         \
+  uint8_t *p = (uint8_t*)_p;                                                   \
+  upb_decoderet r;                                                             \
+  if ((*p & 0x80) == 0) {                                                      \
+  /* Common case: one-byte varint. */                                          \
+    return upb_decoderet_make(_p + 1, *p & 0x7fU);                             \
+  }                                                                            \
+  r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7));    \
+  if ((*(p + 1) & 0x80) == 0) {                                                \
+    /* Two-byte varint. */                                                     \
+    return r;                                                                  \
+  }                                                                            \
+  /* Longer varint, fallback to out-of-line function. */                       \
+  return decode_max8_function(r);                                              \
+}
+
+UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32)
+UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64)
+UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright)
+UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino)
+#undef UPB_VARINT_DECODER_CHECK2
+
+/* Our canonical functions for decoding varints, based on the currently
+ * favored best-performing implementations. */
+UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
+  if (sizeof(long) == 8)
+    return upb_vdecode_check2_branch64(p);
+  else
+    return upb_vdecode_check2_branch32(p);
+}
+
+UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) {
+  return upb_vdecode_max8_massimino(r);
+}
+
+
+/* Encoding *******************************************************************/
+
+UPB_INLINE int upb_value_size(uint64_t val) {
+#ifdef __GNUC__
+  int high_bit = 63 - __builtin_clzll(val);  /* 0-based, undef if val == 0. */
+#else
+  int high_bit = 0;
+  uint64_t tmp = val;
+  while(tmp >>= 1) high_bit++;
+#endif
+  return val == 0 ? 1 : high_bit / 8 + 1;
+}
+
+/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN
+ * bytes long), returning how many bytes were used.
+ *
+ * TODO: benchmark and optimize if necessary. */
+UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
+  size_t i;
+  if (val == 0) { buf[0] = 0; return 1; }
+  i = 0;
+  while (val) {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val) byte |= 0x80U;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+UPB_INLINE size_t upb_varint_size(uint64_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  return upb_vencode64(val, buf);
+}
+
+/* Encodes a 32-bit varint, *not* sign-extended. */
+UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  size_t bytes = upb_vencode64(val, buf);
+  uint64_t ret = 0;
+  assert(bytes <= 5);
+  memcpy(&ret, buf, bytes);
+  assert(ret <= 0xffffffffffU);
+  return ret;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_VARINT_DECODER_H_ */
+/*
+** upb::pb::Encoder (upb_pb_encoder)
+**
+** Implements a set of upb_handlers that write protobuf data to the binary wire
+** format.
+**
+** This encoder implementation does not have any access to any out-of-band or
+** precomputed lengths for submessages, so it must buffer submessages internally
+** before it can emit the first byte.
+*/
+
+#ifndef UPB_ENCODER_H_
+#define UPB_ENCODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class Encoder;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder)
+
+#define UPB_PBENCODER_MAX_NESTING 100
+
+/* upb::pb::Encoder ***********************************************************/
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_ENCODER_SIZE 768
+
+#ifdef __cplusplus
+
+class upb::pb::Encoder {
+ public:
+  /* Creates a new encoder in the given environment.  The Handlers must have
+   * come from NewHandlers() below. */
+  static Encoder* Create(Environment* env, const Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the encoder. */
+  Sink* input();
+
+  /* Creates a new set of handlers for this MessageDef. */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* msg);
+
+  static const size_t kSize = UPB_PB_ENCODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner);
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
+upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h,
+                                      upb_bytessink* output);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline Encoder* Encoder::Create(Environment* env, const Handlers* handlers,
+                                BytesSink* output) {
+  return upb_pb_encoder_create(env, handlers, output);
+}
+inline Sink* Encoder::input() {
+  return upb_pb_encoder_input(this);
+}
+inline reffed_ptr<const Handlers> Encoder::NewHandlers(
+    const upb::MessageDef *md) {
+  const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_ENCODER_H_ */
+/*
+** upb's core components like upb_decoder and upb_msg are carefully designed to
+** avoid depending on each other for maximum orthogonality.  In other words,
+** you can use a upb_decoder to decode into *any* kind of structure; upb_msg is
+** just one such structure.  A upb_msg can be serialized/deserialized into any
+** format, protobuf binary format is just one such format.
+**
+** However, for convenience we provide functions here for doing common
+** operations like deserializing protobuf binary format into a upb_msg.  The
+** compromise is that this file drags in almost all of upb as a dependency,
+** which could be undesirable if you're trying to use a trimmed-down build of
+** upb.
+**
+** While these routines are convenient, they do not reuse any encoding/decoding
+** state.  For example, if a decoder is JIT-based, it will be re-JITted every
+** time these functions are called.  For this reason, if you are parsing lots
+** of data and efficiency is an issue, these may not be the best functions to
+** use (though they are useful for prototyping, before optimizing).
+*/
+
+#ifndef UPB_GLUE_H
+#define UPB_GLUE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Loads all defs from the given protobuf binary descriptor, setting default
+ * accessors and a default layout on all messages.  The caller owns the
+ * returned array of defs, which will be of length *n.  On error NULL is
+ * returned and status is set (if non-NULL). */
+upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
+                                        void *owner, upb_status *status);
+
+/* Like the previous but also adds the loaded defs to the given symtab. */
+bool upb_load_descriptor_into_symtab(upb_symtab *symtab, const char *str,
+                                     size_t len, upb_status *status);
+
+/* Like the previous but also reads the descriptor from the given filename. */
+bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname,
+                                          upb_status *status);
+
+/* Reads the given filename into a character string, returning NULL if there
+ * was an error. */
+char *upb_readfile(const char *filename, size_t *len);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+
+namespace upb {
+
+/* All routines that load descriptors expect the descriptor to be a
+ * FileDescriptorSet. */
+inline bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname,
+                                         Status* status) {
+  return upb_load_descriptor_file_into_symtab(s, fname, status);
+}
+
+inline bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str,
+                                     size_t len, Status* status) {
+  return upb_load_descriptor_into_symtab(s, str, len, status);
+}
+
+/* Templated so it can accept both string and std::string. */
+template <typename T>
+bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) {
+  return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status);
+}
+
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_GLUE_H */
+/*
+** upb::pb::TextPrinter (upb_textprinter)
+**
+** Handlers for writing to protobuf text format.
+*/
+
+#ifndef UPB_TEXT_H_
+#define UPB_TEXT_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class TextPrinter;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter)
+
+#ifdef __cplusplus
+
+class upb::pb::TextPrinter {
+ public:
+  /* The given handlers must have come from NewHandlers().  It must outlive the
+   * TextPrinter. */
+  static TextPrinter *Create(Environment *env, const upb::Handlers *handlers,
+                             BytesSink *output);
+
+  void SetSingleLineMode(bool single_line);
+
+  Sink* input();
+
+  /* If handler caching becomes a requirement we can add a code cache as in
+   * decoder.h */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md);
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output);
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
+upb_sink *upb_textprinter_input(upb_textprinter *p);
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline TextPrinter *TextPrinter::Create(Environment *env,
+                                        const upb::Handlers *handlers,
+                                        BytesSink *output) {
+  return upb_textprinter_create(env, handlers, output);
+}
+inline void TextPrinter::SetSingleLineMode(bool single_line) {
+  upb_textprinter_setsingleline(this, single_line);
+}
+inline Sink* TextPrinter::input() {
+  return upb_textprinter_input(this);
+}
+inline reffed_ptr<const Handlers> TextPrinter::NewHandlers(
+    const MessageDef *md) {
+  const Handlers* h = upb_textprinter_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_TEXT_H_ */
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** Parses JSON according to a specific schema.
+** Support for parsing arbitrary JSON (schema-less) will be added later.
+*/
+
+#ifndef UPB_JSON_PARSER_H_
+#define UPB_JSON_PARSER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Parser;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser)
+
+/* upb::json::Parser **********************************************************/
+
+/* Preallocation hint: parser won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the parser library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_JSON_PARSER_SIZE 3704
+
+#ifdef __cplusplus
+
+/* Parses an incoming BytesStream, pushing the results to the destination
+ * sink. */
+class upb::json::Parser {
+ public:
+  static Parser* Create(Environment* env, Sink* output);
+
+  BytesSink* input();
+
+ private:
+  UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+upb_json_parser *upb_json_parser_create(upb_env *e, upb_sink *output);
+upb_bytessink *upb_json_parser_input(upb_json_parser *p);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Parser* Parser::Create(Environment* env, Sink* output) {
+  return upb_json_parser_create(env, output);
+}
+inline BytesSink* Parser::input() {
+  return upb_json_parser_input(this);
+}
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+
+#endif  /* UPB_JSON_PARSER_H_ */
+/*
+** upb::json::Printer
+**
+** Handlers that emit JSON according to a specific protobuf schema.
+*/
+
+#ifndef UPB_JSON_TYPED_PRINTER_H_
+#define UPB_JSON_TYPED_PRINTER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Printer;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer)
+
+
+/* upb::json::Printer *********************************************************/
+
+#define UPB_JSON_PRINTER_SIZE 168
+
+#ifdef __cplusplus
+
+/* Prints an incoming stream of data to a BytesSink in JSON format. */
+class upb::json::Printer {
+ public:
+  static Printer* Create(Environment* env, const upb::Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the printer. */
+  Sink* input();
+
+  /* Returns handlers for printing according to the specified schema. */
+  static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md);
+
+  static const size_t kSize = UPB_JSON_PRINTER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output);
+upb_sink *upb_json_printer_input(upb_json_printer *p);
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers,
+                                BytesSink* output) {
+  return upb_json_printer_create(env, handlers, output);
+}
+inline Sink* Printer::input() { return upb_json_printer_input(this); }
+inline reffed_ptr<const Handlers> Printer::NewHandlers(
+    const upb::MessageDef *md) {
+  const Handlers* h = upb_json_printer_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_JSON_TYPED_PRINTER_H_ */
diff --git a/php/tests/autoload.php b/php/tests/autoload.php
new file mode 100644
index 0000000..af88ba0
--- /dev/null
+++ b/php/tests/autoload.php
@@ -0,0 +1,4 @@
+<?php
+
+require_once('test.pb.php');
+require_once('test_util.php');
diff --git a/post_process_dist.sh b/post_process_dist.sh
index 7b2e599..82736bd 100755
--- a/post_process_dist.sh
+++ b/post_process_dist.sh
@@ -16,7 +16,7 @@
 # 5) Cleans up after itself.
 
 if [ "$1" == "" ]; then
-  echo "USAGE:  $1 DISTFILE" >&2
+  echo "USAGE:  $0 DISTFILE" >&2
   exit 1
 fi
 
@@ -27,7 +27,9 @@
 
 set -ex
 
+LANGUAGES="cpp csharp java javanano js objectivec python ruby"
 BASENAME=`basename $1 .tar.gz`
+VERSION=${BASENAME:9}
 
 # Create a directory called "dist", copy the tarball there and unpack it.
 mkdir dist
@@ -38,23 +40,25 @@
 
 # Set the entire contents to be user-writable.
 chmod -R u+w $BASENAME
+cd $BASENAME
 
-# Convert the MSVC projects to MSVC 2005 format.
-cd $BASENAME/vsprojects
-./convert2008to2005.sh
-cd ..
-
-# Build the dist again in .tar.gz and .tar.bz2 formats.
-./configure
-make dist-gzip
-make dist-bzip2
+for LANG in $LANGUAGES; do
+  # Build the dist again in .tar.gz
+  ./configure DIST_LANG=$LANG
+  make dist-gzip
+  mv $BASENAME.tar.gz ../protobuf-$LANG-$VERSION.tar.gz
+done
 
 # Convert all text files to use DOS-style line endings, then build a .zip
 # distribution.
 todos *.txt */*.txt
-make dist-zip
 
-# Clean up.
-mv $BASENAME.tar.gz $BASENAME.tar.bz2 $BASENAME.zip ..
+for LANG in $LANGUAGES; do
+  # Build the dist again in .zip
+  ./configure DIST_LANG=$LANG
+  make dist-zip
+  mv $BASENAME.zip ../protobuf-$LANG-$VERSION.zip
+done
+
 cd ..
 rm -rf $BASENAME
diff --git a/protobuf-lite.pc.in b/protobuf-lite.pc.in
index 29c218e..80f1f46 100644
--- a/protobuf-lite.pc.in
+++ b/protobuf-lite.pc.in
@@ -8,6 +8,4 @@
 Version: @VERSION@
 Libs: -L${libdir} -lprotobuf-lite @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
 Cflags: -I${includedir} @PTHREAD_CFLAGS@
-# Commented out because it crashes pkg-config *sigh*:
-#   http://bugs.freedesktop.org/show_bug.cgi?id=13265
-# Conflicts: protobuf
+Conflicts: protobuf
diff --git a/protobuf.bzl b/protobuf.bzl
new file mode 100644
index 0000000..fbcae0b
--- /dev/null
+++ b/protobuf.bzl
@@ -0,0 +1,304 @@
+# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
+
+def _GetPath(ctx, path):
+  if ctx.label.workspace_root:
+    return ctx.label.workspace_root + '/' + path
+  else:
+    return path
+
+def _GenDir(ctx):
+  if not ctx.attr.includes:
+    return ctx.label.workspace_root
+  if not ctx.attr.includes[0]:
+    return _GetPath(ctx, ctx.label.package)
+  if not ctx.label.package:
+    return _GetPath(ctx, ctx.attr.includes[0])
+  return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
+
+def _CcOuts(srcs, use_grpc_plugin=False):
+  ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
+        [s[:-len(".proto")] + ".pb.cc" for s in srcs]
+  if use_grpc_plugin:
+    ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] + \
+           [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
+  return ret
+
+def _PyOuts(srcs):
+  return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
+
+def _RelativeOutputPath(path, include):
+  if include == None:
+    return path
+
+  if not path.startswith(include):
+    fail("Include path %s isn't part of the path %s." % (include, path))
+
+  if include and include[-1] != '/':
+    include = include + '/'
+
+  path = path[len(include):]
+
+  if not path.startswith(PACKAGE_NAME):
+    fail("The package %s is not within the path %s" % (PACKAGE_NAME, path))
+
+  if not PACKAGE_NAME:
+    return path
+
+  return path[len(PACKAGE_NAME)+1:]
+
+def _proto_gen_impl(ctx):
+  """General implementation for generating protos"""
+  srcs = ctx.files.srcs
+  deps = []
+  deps += ctx.files.srcs
+  gen_dir = _GenDir(ctx)
+  if gen_dir:
+    import_flags = ["-I" + gen_dir]
+  else:
+    import_flags = ["-I."]
+
+  for dep in ctx.attr.deps:
+    import_flags += dep.proto.import_flags
+    deps += dep.proto.deps
+
+  args = []
+  if ctx.attr.gen_cc:
+    args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+  if ctx.attr.gen_py:
+    args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+
+  if ctx.executable.grpc_cpp_plugin:
+    args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path]
+    args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+
+  if args:
+    ctx.action(
+        inputs=srcs + deps,
+        outputs=ctx.outputs.outs,
+        arguments=args + import_flags + [s.path for s in srcs],
+        executable=ctx.executable.protoc,
+    )
+
+  return struct(
+      proto=struct(
+          srcs=srcs,
+          import_flags=import_flags,
+          deps=deps,
+      ),
+  )
+
+_proto_gen = rule(
+    attrs = {
+        "srcs": attr.label_list(allow_files = True),
+        "deps": attr.label_list(providers = ["proto"]),
+        "includes": attr.string_list(),
+        "protoc": attr.label(
+            cfg = HOST_CFG,
+            executable = True,
+            single_file = True,
+            mandatory = True,
+        ),
+        "grpc_cpp_plugin": attr.label(
+            cfg = HOST_CFG,
+            executable = True,
+            single_file = True,
+        ),
+        "gen_cc": attr.bool(),
+        "gen_py": attr.bool(),
+        "outs": attr.output_list(),
+    },
+    output_to_genfiles = True,
+    implementation = _proto_gen_impl,
+)
+
+def cc_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        cc_libs=[],
+        include=None,
+        protoc="//:protoc",
+        internal_bootstrap_hack=False,
+        use_grpc_plugin=False,
+        default_runtime="//:protobuf",
+        **kargs):
+  """Bazel rule to create a C++ protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the cc_proto_library.
+    srcs: the .proto files of the cc_proto_library.
+    deps: a list of dependency labels; must be cc_proto_library.
+    cc_libs: a list of other cc_library targets depended by the generated
+        cc_library.
+    include: a string indicating the include path of the .proto files.
+    protoc: the label of the protocol compiler to generate the sources.
+    internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
+        for bootstraping. When it is set to True, no files will be generated.
+        The rule will simply be a provider for .proto files, so that other
+        cc_proto_library can depend on it.
+    use_grpc_plugin: a flag to indicate whether to call the grpc C++ plugin
+        when processing the proto files.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated cc_library target.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  if internal_bootstrap_hack:
+    # For pre-checked-in generated files, we add the internal_bootstrap_hack
+    # which will skip the codegen action.
+    _proto_gen(
+        name=name + "_genproto",
+        srcs=srcs,
+        deps=[s + "_genproto" for s in deps],
+        includes=includes,
+        protoc=protoc,
+        visibility=["//visibility:public"],
+    )
+    # An empty cc_library to make rule dependency consistent.
+    native.cc_library(
+        name=name,
+        **kargs)
+    return
+
+  grpc_cpp_plugin = None
+  if use_grpc_plugin:
+    grpc_cpp_plugin = "//external:grpc_cpp_plugin"
+
+  outs = _CcOuts(srcs, use_grpc_plugin)
+
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      grpc_cpp_plugin=grpc_cpp_plugin,
+      gen_cc=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in cc_libs:
+    cc_libs += [default_runtime]
+  if use_grpc_plugin:
+    cc_libs += ["//external:grpc_lib"]
+
+  native.cc_library(
+      name=name,
+      srcs=outs,
+      deps=cc_libs + deps,
+      includes=includes,
+      **kargs)
+
+
+def internal_gen_well_known_protos_java(srcs):
+  """Bazel rule to generate the gen_well_known_protos_java genrule
+
+  Args:
+    srcs: the well known protos
+  """
+  root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root
+  if root == "":
+    include = " -Isrc "
+  else:
+    include = " -I%s/src " % root
+  native.genrule(
+    name = "gen_well_known_protos_java",
+    srcs = srcs,
+    outs = [
+        "wellknown.srcjar",
+    ],
+    cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
+          " %s $(SRCS) " % include +
+          " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
+    tools = [":protoc"],
+  )
+
+
+def py_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        py_libs=[],
+        py_extra_srcs=[],
+        include=None,
+        default_runtime="//:protobuf_python",
+        protoc="//:protoc",
+        **kargs):
+  """Bazel rule to create a Python protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the py_proto_library.
+    srcs: the .proto files of the py_proto_library.
+    deps: a list of dependency labels; must be py_proto_library.
+    py_libs: a list of other py_library targets depended by the generated
+        py_library.
+    py_extra_srcs: extra source files that will be added to the output
+        py_library. This attribute is used for internal bootstrapping.
+    include: a string indicating the include path of the .proto files.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated py_library target.
+    protoc: the label of the protocol compiler to generate the sources.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+  outs = _PyOuts(srcs)
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      gen_py=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in py_libs + deps:
+    py_libs += [default_runtime]
+
+  native.py_library(
+      name=name,
+      srcs=outs+py_extra_srcs,
+      deps=py_libs+deps,
+      imports=includes,
+      **kargs)
+
+def internal_protobuf_py_tests(
+    name,
+    modules=[],
+    **kargs):
+  """Bazel rules to create batch tests for protobuf internal.
+
+  Args:
+    name: the name of the rule.
+    modules: a list of modules for tests. The macro will create a py_test for
+        each of the parameter with the source "google/protobuf/%s.py"
+    kargs: extra parameters that will be passed into the py_test.
+
+  """
+  for m in modules:
+    s = "python/google/protobuf/internal/%s.py" % m
+    native.py_test(
+        name="py_%s" % m,
+        srcs=[s],
+        main=s,
+        **kargs)
diff --git a/protobuf.pc.in b/protobuf.pc.in
index 29f2487..4901490 100644
--- a/protobuf.pc.in
+++ b/protobuf.pc.in
@@ -9,6 +9,4 @@
 Libs: -L${libdir} -lprotobuf @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
 Libs.private: @LIBS@
 Cflags: -I${includedir} @PTHREAD_CFLAGS@
-# Commented out because it crashes pkg-config *sigh*:
-#   http://bugs.freedesktop.org/show_bug.cgi?id=13265
-# Conflicts: protobuf-lite
+Conflicts: protobuf-lite
diff --git a/protoc-artifacts/Dockerfile b/protoc-artifacts/Dockerfile
new file mode 100644
index 0000000..fd35b89
--- /dev/null
+++ b/protoc-artifacts/Dockerfile
@@ -0,0 +1,40 @@
+FROM centos:6.6
+
+RUN yum install -y git \
+                   tar \
+                   wget \
+                   make \
+                   autoconf \
+                   curl-devel \
+                   unzip \
+                   automake \
+                   libtool \
+                   glibc-static.i686 \
+                   glibc-devel \
+                   glibc-devel.i686
+
+# Install Java 8
+RUN wget -q --no-cookies --no-check-certificate \
+    --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.tar.gz" \
+    -O - | tar xz -C /var/local
+ENV JAVA_HOME /var/local/jdk1.8.0_45
+ENV PATH $JAVA_HOME/bin:$PATH
+
+# Install Maven
+RUN wget -q http://apache.cs.utah.edu/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz -O - | \
+    tar xz -C /var/local
+ENV PATH /var/local/apache-maven-3.3.3/bin:$PATH
+
+# Install GCC 4.7 to support -static-libstdc++
+RUN wget http://people.centos.org/tru/devtools-1.1/devtools-1.1.repo -P /etc/yum.repos.d
+RUN bash -c 'echo "enabled=1" >> /etc/yum.repos.d/devtools-1.1.repo'
+RUN bash -c "sed -e 's/\$basearch/i386/g' /etc/yum.repos.d/devtools-1.1.repo > /etc/yum.repos.d/devtools-i386-1.1.repo"
+RUN sed -e 's/testing-/testing-i386-/g' -i /etc/yum.repos.d/devtools-i386-1.1.repo
+RUN yum install -y devtoolset-1.1 \
+                   devtoolset-1.1-libstdc++-devel \
+                   devtoolset-1.1-libstdc++-devel.i686
+
+RUN git clone --depth 1 https://github.com/google/protobuf.git
+
+# Start in devtoolset environment that uses GCC 4.7
+CMD ["scl", "enable", "devtoolset-1.1", "bash"]
diff --git a/protoc-artifacts/README.md b/protoc-artifacts/README.md
new file mode 100644
index 0000000..4320f65
--- /dev/null
+++ b/protoc-artifacts/README.md
@@ -0,0 +1,143 @@
+# Build scripts that publish pre-compiled protoc artifacts
+``protoc`` is the compiler for ``.proto`` files. It generates language bindings
+for the messages and/or RPC services from ``.proto`` files.
+
+Because ``protoc`` is a native executable, the scripts under this directory
+build and publish a ``protoc`` executable (a.k.a. artifact) to Maven
+repositories. The artifact can be used by build automation tools so that users
+would not need to compile and install ``protoc`` for their systems.
+
+## Versioning
+The version of the ``protoc`` artifact must be the same as the version of the
+Protobuf project.
+
+## Artifact name
+The name of a published ``protoc`` artifact is in the following format:
+``protoc-<version>-<os>-<arch>.exe``, e.g., ``protoc-3.0.0-alpha-3-windows-x86_64.exe``.
+
+## System requirement
+Install [Apache Maven](http://maven.apache.org/) if you don't have it.
+
+The scripts only work under Unix-like environments, e.g., Linux, MacOSX, and
+Cygwin or MinGW for Windows. Please see ``README.md`` of the Protobuf project
+for how to set up the build environment.
+
+## To install artifacts locally
+The following command will install the ``protoc`` artifact to your local Maven repository.
+```
+$ mvn install
+```
+
+## Cross-compilation
+The Maven script will try to detect the OS and the architecture from Java
+system properties. It's possible to build a protoc binary for an architecture
+that is different from what Java has detected, as long as you have the proper
+compilers installed.
+
+You can override the Maven properties ``os.detected.name`` and
+``os.detected.arch`` to force the script to generate binaries for a specific OS
+and/or architecture. Valid values are defined as the return values of
+``normalizeOs()`` and ``normalizeArch()`` of ``Detector`` from
+[os-maven-plugin](https://github.com/trustin/os-maven-plugin/blob/master/src/main/java/kr/motd/maven/os/Detector.java).
+Frequently used values are:
+- ``os.detected.name``: ``linux``, ``osx``, ``windows``.
+- ``os.detected.arch``: ``x86_32``, ``x86_64``
+
+For example, MingGW32 only ships with 32-bit compilers, but you can still build
+32-bit protoc under 64-bit Windows, with the following command:
+```
+$ mvn install -Dos.detected.arch=x86_32
+```
+
+## To push artifacts to Maven Central
+Before you can upload artifacts to Maven Central repository, make sure you have
+read [this page](http://central.sonatype.org/pages/apache-maven.html) on how to
+configure GPG and Sonatype account.
+
+You need to perform the deployment for every platform that you want to
+support. DO NOT close the staging repository until you have done the
+deployment for all platforms. Currently the following platforms are supported:
+- Linux (x86_32 and x86_64)
+- Windows (x86_32 and x86_64) with
+ - Cygwin with MinGW compilers (both x86_32 and x86_64)
+ - MSYS with MinGW32 (x86_32 only)
+- MacOSX (x86_32 and x86_64)
+
+Use the following command to deploy artifacts for the host platform to a
+staging repository.
+```
+$ mvn clean deploy -P release
+```
+It creates a new staging repository. Go to
+https://oss.sonatype.org/#stagingRepositories and find the repository, usually
+in the name like ``comgoogle-123``.
+
+You will want to run this command on a different platform. Remember, in
+subsequent deployments you will need to provide the repository name that you
+have found in the first deployment so that all artifacts go to the same
+repository:
+```
+$ mvn clean deploy -P release -Dstaging.repository=comgoogle-123
+```
+
+A 32-bit artifact can be deployed from a 64-bit host with
+``-Dos.detected.arch=x86_32``
+
+When you have done deployment for all platforms, go to
+https://oss.sonatype.org/#stagingRepositories, verify that the staging
+repository has all the binaries, close and release this repository.
+
+### Tips for deploying on Linux
+We build on Centos 6.6 to provide a good compatibility for not very new
+systems. We have provided a ``Dockerfile`` under this directory to build the
+environment. It has been tested with Docker 1.6.1.
+
+To build a image:
+```
+$ docker build -t protoc-artifacts .
+```
+
+To run the image:
+```
+$ docker run -it --rm=true protoc-artifacts
+```
+
+The Protobuf repository has been cloned into ``/protobuf``.
+
+### Tips for deploying on Windows
+Under Windows the following error may occur: ``gpg: cannot open tty `no tty':
+No such file or directory``. This can be fixed by configuring gpg through an
+active profile in ``.m2\settings.xml`` where also the Sonatype password is
+stored:
+```xml
+<settings>
+  <servers>
+    <server>
+      <id>ossrh</id>
+      <username>[username]</username>
+      <password>[password]</password>
+    </server>
+  </servers>
+  <profiles>
+    <profile>
+      <id>gpg</id>
+      <properties>
+        <gpg.executable>gpg</gpg.executable>
+        <gpg.passphrase>[password]</gpg.passphrase>
+      </properties>
+    </profile>
+  </profiles>
+  <activeProfiles>
+    <activeProfile>gpg</activeProfile>
+  </activeProfiles>
+</settings>
+```
+
+### Tested build environments
+We have successfully built artifacts on the following environments:
+- Linux x86_32 and x86_64:
+ - Centos 6.6 (within Docker 1.6.1)
+ - Ubuntu 14.04.2 64-bit
+- Windows x86_32: MSYS with ``mingw32-gcc-g++ 4.8.1-4`` on Windows 7 64-bit
+- Windows x86_64: Cygwin64 with ``mingw64-x86_64-gcc-g++ 4.8.3-1`` on Windows 7 64-bit
+- Mac OS X x86_32 and x86_64: Mac OS X 10.9.5
diff --git a/protoc-artifacts/build-protoc.sh b/protoc-artifacts/build-protoc.sh
new file mode 100755
index 0000000..88e6ae5
--- /dev/null
+++ b/protoc-artifacts/build-protoc.sh
@@ -0,0 +1,225 @@
+#!/bin/bash
+
+# Builds protoc executable into target/protoc.exe
+# To be run from Maven.
+# Usage: build-protoc.sh <OS> <ARCH>
+# <OS> and <ARCH> are ${os.detected.name} and ${os.detected.arch} from os-maven-plugin
+OS=$1
+ARCH=$2
+
+if [[ $# < 2 ]]; then
+  echo "No arguments provided. This script is intended to be run from Maven."
+  exit 1
+fi
+
+# Under Cygwin, bash doesn't have these in PATH when called from Maven which
+# runs in Windows version of Java.
+export PATH="/bin:/usr/bin:$PATH"
+
+############################################################################
+# Helper functions
+############################################################################
+E_PARAM_ERR=98
+E_ASSERT_FAILED=99
+
+# Usage:
+fail()
+{
+  echo "ERROR: $1"
+  echo
+  exit $E_ASSERT_FAILED
+}
+
+# Usage: assertEq VAL1 VAL2 $LINENO
+assertEq ()
+{
+  lineno=$3
+  if [ -z "$lineno" ]; then
+    echo "lineno not given"
+    exit $E_PARAM_ERR
+  fi
+
+  if [[ "$1" != "$2" ]]; then
+    echo "Assertion failed:  \"$1\" == \"$2\""
+    echo "File \"$0\", line $lineno"    # Give name of file and line number.
+    exit $E_ASSERT_FAILED
+  fi
+}
+
+# Checks the artifact is for the expected architecture
+# Usage: checkArch <path-to-protoc>
+checkArch ()
+{
+  echo
+  echo "Checking file format ..."
+  if [[ "$OS" == windows || "$OS" == linux ]]; then
+    format="$(objdump -f "$1" | grep -o "file format .*$" | grep -o "[^ ]*$")"
+    echo Format=$format
+    if [[ "$OS" == linux ]]; then
+      if [[ "$ARCH" == x86_32 ]]; then
+        assertEq $format "elf32-i386" $LINENO
+      elif [[ "$ARCH" == x86_64 ]]; then
+        assertEq $format "elf64-x86-64" $LINENO
+      else
+        fail "Unsupported arch: $ARCH"
+      fi
+    else
+      # $OS == windows
+      if [[ "$ARCH" == x86_32 ]]; then
+        assertEq $format "pei-i386" $LINENO
+      elif [[ "$ARCH" == x86_64 ]]; then
+        assertEq $format "pei-x86-64" $LINENO
+      else
+        fail "Unsupported arch: $ARCH"
+      fi
+    fi
+  elif [[ "$OS" == osx ]]; then
+    format="$(file -b "$1" | grep -o "[^ ]*$")"
+    echo Format=$format
+    if [[ "$ARCH" == x86_32 ]]; then
+      assertEq $format "i386" $LINENO
+    elif [[ "$ARCH" == x86_64 ]]; then
+      assertEq $format "x86_64" $LINENO
+    else
+      fail "Unsupported arch: $ARCH"
+    fi
+  else
+    fail "Unsupported system: $OS"
+  fi
+  echo
+}
+
+# Checks the dependencies of the artifact. Artifacts should only depend on
+# system libraries.
+# Usage: checkDependencies <path-to-protoc>
+checkDependencies ()
+{
+  if [[ "$OS" == windows ]]; then
+    dump_cmd='objdump -x '"$1"' | fgrep "DLL Name"'
+    white_list="KERNEL32\.dll\|msvcrt\.dll"
+  elif [[ "$OS" == linux ]]; then
+    dump_cmd='ldd '"$1"
+    if [[ "$ARCH" == x86_32 ]]; then
+      white_list="linux-gate\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux\.so\.2"
+    elif [[ "$ARCH" == x86_64 ]]; then
+      white_list="linux-vdso\.so\.1\|libpthread\.so\.0\|libm\.so\.6\|libc\.so\.6\|ld-linux-x86-64\.so\.2"
+    fi
+  elif [[ "$OS" == osx ]]; then
+    dump_cmd='otool -L '"$1"' | fgrep dylib'
+    white_list="libz\.1\.dylib\|libstdc++\.6\.dylib\|libSystem\.B\.dylib"
+  fi
+  if [[ -z "$white_list" || -z "$dump_cmd" ]]; then
+    fail "Unsupported platform $OS-$ARCH."
+  fi
+  echo "Checking for expected dependencies ..."
+  eval $dump_cmd | grep -i "$white_list" || fail "doesn't show any expected dependencies"
+  echo "Checking for unexpected dependencies ..."
+  eval $dump_cmd | grep -i -v "$white_list"
+  ret=$?
+  if [[ $ret == 0 ]]; then
+    fail "found unexpected dependencies (listed above)."
+  elif [[ $ret != 1 ]]; then
+    fail "Error when checking dependencies."
+  fi  # grep returns 1 when "not found", which is what we expect
+  echo "Dependencies look good."
+  echo
+}
+############################################################################
+
+echo "Building protoc, OS=$OS ARCH=$ARCH"
+
+# Nested double quotes are unintuitive, but it works.
+cd "$(dirname "$0")"
+
+WORKING_DIR=$(pwd)
+CONFIGURE_ARGS="--disable-shared"
+
+MAKE_TARGET="protoc"
+if [[ "$OS" == windows ]]; then
+  MAKE_TARGET="${MAKE_TARGET}.exe"
+fi
+
+# Override the default value set in configure.ac that has '-g' which produces
+# huge binary.
+CXXFLAGS="-DNDEBUG"
+LDFLAGS=""
+
+if [[ "$(uname)" == CYGWIN* ]]; then
+  assertEq "$OS" windows $LINENO
+  # Use mingw32 compilers because executables produced by Cygwin compiler
+  # always have dependency on Cygwin DLL.
+  if [[ "$ARCH" == x86_64 ]]; then
+    CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
+  elif [[ "$ARCH" == x86_32 ]]; then
+    CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-pc-mingw32"
+  else
+    fail "Unsupported arch by CYGWIN: $ARCH"
+  fi
+elif [[ "$(uname)" == MINGW32* ]]; then
+  assertEq "$OS" windows $LINENO
+  assertEq "$ARCH" x86_32 $LINENO
+elif [[ "$(uname)" == MINGW64* ]]; then
+  assertEq "$OS" windows $LINENO
+  assertEq "$ARCH" x86_64 $LINENO
+elif [[ "$(uname)" == Linux* ]]; then
+  if [[ "$OS" == linux ]]; then
+    if [[ "$ARCH" == x86_64 ]]; then
+      CXXFLAGS="$CXXFLAGS -m64"
+    elif [[ "$ARCH" == x86_32 ]]; then
+      CXXFLAGS="$CXXFLAGS -m32"
+    else
+      fail "Unsupported arch: $ARCH"
+    fi
+  elif [[ "$OS" == windows ]]; then
+    # Cross-compilation for Windows
+    # TODO(zhangkun83) MinGW 64 always adds dependency on libwinpthread-1.dll,
+    # which is undesirable for repository deployment.
+    CONFIGURE_ARGS="$CONFIGURE_ARGS"
+    if [[ "$ARCH" == x86_64 ]]; then
+      CONFIGURE_ARGS="$CONFIGURE_ARGS --host=x86_64-w64-mingw32"
+    elif [[ "$ARCH" == x86_32 ]]; then
+      CONFIGURE_ARGS="$CONFIGURE_ARGS --host=i686-w64-mingw32"
+    else
+      fail "Unsupported arch: $ARCH"
+    fi
+  else
+    fail "Cannot build $OS on $(uname)"
+  fi
+elif [[ "$(uname)" == Darwin* ]]; then
+  assertEq "$OS" osx $LINENO
+  # Make the binary compatible with OSX 10.7 and later
+  CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.7"
+  if [[ "$ARCH" == x86_64 ]]; then
+    CXXFLAGS="$CXXFLAGS -m64"
+  elif [[ "$ARCH" == x86_32 ]]; then
+    CXXFLAGS="$CXXFLAGS -m32"
+  else
+    fail "Unsupported arch: $ARCH"
+  fi
+else
+  fail "Unsupported system: $(uname)"
+fi
+
+# Statically link libgcc and libstdc++.
+# -s to produce stripped binary.
+# And they don't work under Mac.
+if [[ "$OS" != osx ]]; then
+  LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++ -s"
+fi
+
+export CXXFLAGS LDFLAGS
+
+TARGET_FILE=target/protoc.exe
+
+cd "$WORKING_DIR"/.. && ./configure $CONFIGURE_ARGS &&
+  cd src && make clean && make $MAKE_TARGET &&
+  cd "$WORKING_DIR" && mkdir -p target &&
+  (cp ../src/protoc $TARGET_FILE || cp ../src/protoc.exe $TARGET_FILE) ||
+  exit 1
+
+if [[ "$OS" == osx ]]; then
+  # Since Mac linker doesn't accept "-s", we need to run strip
+  strip $TARGET_FILE || exit 1
+fi
+
+checkArch $TARGET_FILE && checkDependencies $TARGET_FILE
diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml
new file mode 100644
index 0000000..e9728a0
--- /dev/null
+++ b/protoc-artifacts/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google</groupId>
+    <artifactId>google</artifactId>
+    <version>1</version>
+  </parent>
+  <groupId>com.google.protobuf</groupId>
+  <artifactId>protoc</artifactId>
+  <version>3.0.0-beta-2</version>
+  <packaging>pom</packaging>
+  <name>Protobuf Compiler</name>
+  <description>
+    Protobuf Compiler (protoc) is a compiler for .proto files. It generates
+    language-specific code for Protobuf messages and RPC interfaces.
+  </description>
+  <inceptionYear>2008</inceptionYear>
+  <url>https://developers.google.com/protocol-buffers/</url>
+  <licenses>
+    <license>
+      <name>New BSD license</name>
+      <url>http://www.opensource.org/licenses/bsd-license.php</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <url>https://github.com/google/protobuf</url>
+    <connection>
+      scm:git:https://github.com/google/protobuf.git
+    </connection>
+  </scm>
+  <build>
+    <extensions>
+      <extension>
+        <groupId>kr.motd.maven</groupId>
+        <artifactId>os-maven-plugin</artifactId>
+        <version>1.2.3.Final</version>
+      </extension>
+    </extensions>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.1.1</version>
+        <executions>
+          <execution>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <executable>bash</executable>
+          <arguments>
+            <argument>build-protoc.sh</argument>
+            <argument>${os.detected.name}</argument>
+            <argument>${os.detected.arch}</argument>
+          </arguments>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.8</version>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <phase>package</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${basedir}/target/protoc.exe</file>
+                  <classifier>${os.detected.name}-${os.detected.arch}</classifier>
+                  <type>exe</type>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>release</id>
+      <properties>
+        <!-- Specify the staging repository to deploy to. This can be left
+             empty for the first deployment, and Sonatype will create one. For
+             subsequent deployments it should be set to what Sonatype has
+             created, so that all deployments will go to the same repository.
+             -->
+        <staging.repository></staging.repository>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.5</version>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.sonatype.plugins</groupId>
+            <artifactId>nexus-staging-maven-plugin</artifactId>
+            <version>1.6.3</version>
+            <extensions>true</extensions>
+            <configuration>
+               <serverId>sonatype-nexus-staging</serverId>
+               <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+               <skipStagingRepositoryClose>true</skipStagingRepositoryClose>
+               <autoReleaseAfterClose>false</autoReleaseAfterClose>
+               <stagingRepositoryId>${staging.repository}</stagingRepositoryId>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/python/MANIFEST.in b/python/MANIFEST.in
new file mode 100644
index 0000000..2608882
--- /dev/null
+++ b/python/MANIFEST.in
@@ -0,0 +1,14 @@
+prune google/protobuf/internal/import_test_package
+exclude google/protobuf/internal/*_pb2.py
+exclude google/protobuf/internal/*_test.py
+exclude google/protobuf/internal/*.proto
+exclude google/protobuf/internal/test_util.py
+
+recursive-exclude google *_test.py
+recursive-exclude google *_test.proto
+recursive-exclude google unittest*_pb2.py
+
+global-exclude *.dll
+global-exclude *.pyc
+global-exclude *.pyo
+global-exclude *.so
diff --git a/python/README.md b/python/README.md
new file mode 100644
index 0000000..57acfd9
--- /dev/null
+++ b/python/README.md
@@ -0,0 +1,127 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Python Protocol Buffers runtime library.
+
+Normally, this directory comes as part of the protobuf package, available
+from:
+
+  https://developers.google.com/protocol-buffers/
+
+The complete package includes the C++ source code, which includes the
+Protocol Compiler (protoc).  If you downloaded this package from PyPI
+or some other Python-specific source, you may have received only the
+Python part of the code.  In this case, you will need to obtain the
+Protocol Compiler from some other source before you can use this
+package.
+
+Development Warning
+===================
+
+The Python implementation of Protocol Buffers is not as mature as the C++
+and Java implementations.  It may be more buggy, and it is known to be
+pretty slow at this time.  If you would like to help fix these issues,
+join the Protocol Buffers discussion list and let us know!
+
+Installation
+============
+
+1) Make sure you have Python 2.6 or newer.  If in doubt, run:
+
+     $ python -V
+
+2) If you do not have setuptools installed, note that it will be
+   downloaded and installed automatically as soon as you run setup.py.
+   If you would rather install it manually, you may do so by following
+   the instructions on this page:
+
+     https://packaging.python.org/en/latest/installing.html#setup-for-installing-packages
+
+3) Build the C++ code, or install a binary distribution of protoc.  If
+   you install a binary distribution, make sure that it is the same
+   version as this package.  If in doubt, run:
+
+     $ protoc --version
+
+4) Build and run the tests:
+
+     $ python setup.py build
+     $ python setup.py test
+
+     To build, test, and use the C++ implementation, you must first compile
+     libprotobuf.so:
+
+     $ (cd .. && make)
+
+     On OS X:
+
+      If you are running a homebrew-provided python, you must make sure another
+      version of protobuf is not already installed, as homebrew's python will
+      search /usr/local/lib for libprotobuf.so before it searches ../src/.libs
+      You can either unlink homebrew's protobuf or install the libprotobuf you
+      built earlier:
+
+      $ brew unlink protobuf
+      or
+      $ (cd .. && make install)
+
+     On other *nix:
+
+      You must make libprotobuf.so dynamically available. You can either
+      install libprotobuf you built earlier, or set LD_LIBRARY_PATH:
+
+      $ export LD_LIBRARY_PATH=../src/.libs
+      or
+      $ (cd .. && make install)
+
+     To build the C++ implementation run:
+     $ python setup.py build --cpp_implementation
+
+     Then run the tests like so:
+     $ python setup.py test --cpp_implementation
+
+   If some tests fail, this library may not work correctly on your
+   system.  Continue at your own risk.
+
+   Please note that there is a known problem with some versions of
+   Python on Cygwin which causes the tests to fail after printing the
+   error:  "sem_init: Resource temporarily unavailable".  This appears
+   to be a bug either in Cygwin or in Python:
+     http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html
+   We do not know if or when it might me fixed.  We also do not know
+   how likely it is that this bug will affect users in practice.
+
+5) Install:
+
+    $ python setup.py install
+
+  or:
+
+    $ (cd .. && make install)
+    $ python setup.py install --cpp_implementation
+
+   This step may require superuser privileges.
+   NOTE: To use C++ implementation, you need to export an environment
+   variable before running your program.  See the "C++ Implementation"
+   section below for more details.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+  https://developers.google.com/protocol-buffers/
+
+C++ Implementation
+==================
+
+The C++ implementation for Python messages is built as a Python extension to
+improve the overall protobuf Python performance.
+
+To use the C++ implementation, you need to install the C++ protobuf runtime
+library, please see instructions in the parent directory.
diff --git a/python/README.txt b/python/README.txt
deleted file mode 100644
index da044af..0000000
--- a/python/README.txt
+++ /dev/null
@@ -1,105 +0,0 @@
-Protocol Buffers - Google's data interchange format
-Copyright 2008 Google Inc.
-
-This directory contains the Python Protocol Buffers runtime library.
-
-Normally, this directory comes as part of the protobuf package, available
-from:
-
-  https://developers.google.com/protocol-buffers/
-
-The complete package includes the C++ source code, which includes the
-Protocol Compiler (protoc).  If you downloaded this package from PyPI
-or some other Python-specific source, you may have received only the
-Python part of the code.  In this case, you will need to obtain the
-Protocol Compiler from some other source before you can use this
-package.
-
-Development Warning
-===================
-
-The Python implementation of Protocol Buffers is not as mature as the C++
-and Java implementations.  It may be more buggy, and it is known to be
-pretty slow at this time.  If you would like to help fix these issues,
-join the Protocol Buffers discussion list and let us know!
-
-Installation
-============
-
-1) Make sure you have Python 2.4 or newer.  If in doubt, run:
-
-     $ python -V
-
-2) If you do not have setuptools installed, note that it will be
-   downloaded and installed automatically as soon as you run setup.py.
-   If you would rather install it manually, you may do so by following
-   the instructions on this page:
-
-     http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions
-
-3) Build the C++ code, or install a binary distribution of protoc.  If
-   you install a binary distribution, make sure that it is the same
-   version as this package.  If in doubt, run:
-
-     $ protoc --version
-
-4) Build and run the tests:
-
-     $ python setup.py build
-     $ python setup.py google_test
-
-     If you want to test c++ implementation, run:
-     $ python setup.py test --cpp_implementation
-
-   If some tests fail, this library may not work correctly on your
-   system.  Continue at your own risk.
-
-   Please note that there is a known problem with some versions of
-   Python on Cygwin which causes the tests to fail after printing the
-   error:  "sem_init: Resource temporarily unavailable".  This appears
-   to be a bug either in Cygwin or in Python:
-     http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html
-   We do not know if or when it might me fixed.  We also do not know
-   how likely it is that this bug will affect users in practice.
-
-5) Install:
-
-     $ python setup.py install
-     or:
-     $ python setup.py install --cpp_implementation
-
-   This step may require superuser privileges.
-   NOTE: To use C++ implementation, you need to install C++ protobuf runtime
-   library of the same version and export the environment variable before this
-   step. See the "C++ Implementation" section below for more details.
-
-Usage
-=====
-
-The complete documentation for Protocol Buffers is available via the
-web at:
-
-  https://developers.google.com/protocol-buffers/
-
-C++ Implementation
-==================
-
-The C++ implementation for Python messages is built as a Python extension to
-improve the overall protobuf Python performance.
-
-To use the C++ implementation, you need to:
-1) Install the C++ protobuf runtime library, please see instructions in the
-   parent directory.
-2) Export an environment variable:
-
-  $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
-  $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
-
-You need to export this variable before running setup.py script to build and
-install the extension.  You must also set the variable at runtime, otherwise
-the pure-Python implementation will be used. In a future release, we will
-change the default so that C++ implementation is used whenever it is available.
-It is strongly recommended to run `python setup.py test` after setting the
-variable to "cpp", so the tests will be against C++ implemented Python
-messages.
-
diff --git a/python/ez_setup.py b/python/ez_setup.py
deleted file mode 100755
index 3aec98e..0000000
--- a/python/ez_setup.py
+++ /dev/null
@@ -1,284 +0,0 @@
-#!python
-
-# This file was obtained from:
-#   http://peak.telecommunity.com/dist/ez_setup.py
-# on 2011/1/21.
-
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
-    from ez_setup import use_setuptools
-    use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import sys
-DEFAULT_VERSION = "0.6c11"
-DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
-
-md5_data = {
-    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
-    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
-    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
-    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
-    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
-    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
-    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
-    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
-    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
-    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
-    'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
-    'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
-    'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
-    'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
-    'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
-    'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
-    'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
-    'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
-    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
-    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
-    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
-    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
-    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
-    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
-    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
-    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
-    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
-    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
-    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
-    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
-    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
-    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
-    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
-    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
-    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
-    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
-    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
-    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
-    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
-    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
-    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
-    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
-}
-
-import sys, os
-try: from hashlib import md5
-except ImportError: from md5 import md5
-
-def _validate_md5(egg_name, data):
-    if egg_name in md5_data:
-        digest = md5(data).hexdigest()
-        if digest != md5_data[egg_name]:
-            print >>sys.stderr, (
-                "md5 validation of %s failed!  (Possible download problem?)"
-                % egg_name
-            )
-            sys.exit(2)
-    return data
-
-def use_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
-    download_delay=15
-):
-    """Automatically find/download setuptools and make it available on sys.path
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end with
-    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
-    it is not already available.  If `download_delay` is specified, it should
-    be the number of seconds that will be paused before initiating a download,
-    should one be required.  If an older version of setuptools is installed,
-    this routine will print a message to ``sys.stderr`` and raise SystemExit in
-    an attempt to abort the calling script.
-    """
-    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
-    def do_download():
-        egg = download_setuptools(version, download_base, to_dir, download_delay)
-        sys.path.insert(0, egg)
-        import setuptools; setuptools.bootstrap_install_from = egg
-    try:
-        import pkg_resources
-    except ImportError:
-        return do_download()       
-    try:
-        return do_download()
-        pkg_resources.require("setuptools>="+version); return
-    except pkg_resources.VersionConflict, e:
-        if was_imported:
-            print >>sys.stderr, (
-            "The required version of setuptools (>=%s) is not available, and\n"
-            "can't be installed while this script is running. Please install\n"
-            " a more recent version first, using 'easy_install -U setuptools'."
-            "\n\n(Currently using %r)"
-            ) % (version, e.args[0])
-            sys.exit(2)
-    except pkg_resources.DistributionNotFound:
-        pass
-
-    del pkg_resources, sys.modules['pkg_resources']    # reload ok
-    return do_download()
-
-def download_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
-    delay = 15
-):
-    """Download setuptools from a specified location and return its filename
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end
-    with a '/'). `to_dir` is the directory where the egg will be downloaded.
-    `delay` is the number of seconds to pause before an actual download attempt.
-    """
-    import urllib2, shutil
-    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
-    url = download_base + egg_name
-    saveto = os.path.join(to_dir, egg_name)
-    src = dst = None
-    if not os.path.exists(saveto):  # Avoid repeated downloads
-        try:
-            from distutils import log
-            if delay:
-                log.warn("""
----------------------------------------------------------------------------
-This script requires setuptools version %s to run (even to display
-help).  I will attempt to download it for you (from
-%s), but
-you may need to enable firewall access for this script first.
-I will start the download in %d seconds.
-
-(Note: if this machine does not have network access, please obtain the file
-
-   %s
-
-and place it in this directory before rerunning this script.)
----------------------------------------------------------------------------""",
-                    version, download_base, delay, url
-                ); from time import sleep; sleep(delay)
-            log.warn("Downloading %s", url)
-            src = urllib2.urlopen(url)
-            # Read/write all in one block, so we don't create a corrupt file
-            # if the download is interrupted.
-            data = _validate_md5(egg_name, src.read())
-            dst = open(saveto,"wb"); dst.write(data)
-        finally:
-            if src: src.close()
-            if dst: dst.close()
-    return os.path.realpath(saveto)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-def main(argv, version=DEFAULT_VERSION):
-    """Install or upgrade setuptools and EasyInstall"""
-    try:
-        import setuptools
-    except ImportError:
-        egg = None
-        try:
-            egg = download_setuptools(version, delay=0)
-            sys.path.insert(0,egg)
-            from setuptools.command.easy_install import main
-            return main(list(argv)+[egg])   # we're done here
-        finally:
-            if egg and os.path.exists(egg):
-                os.unlink(egg)
-    else:
-        if setuptools.__version__ == '0.0.1':
-            print >>sys.stderr, (
-            "You have an obsolete version of setuptools installed.  Please\n"
-            "remove it from your system entirely before rerunning this script."
-            )
-            sys.exit(2)
-
-    req = "setuptools>="+version
-    import pkg_resources
-    try:
-        pkg_resources.require(req)
-    except pkg_resources.VersionConflict:
-        try:
-            from setuptools.command.easy_install import main
-        except ImportError:
-            from easy_install import main
-        main(list(argv)+[download_setuptools(delay=0)])
-        sys.exit(0) # try to force an exit
-    else:
-        if argv:
-            from setuptools.command.easy_install import main
-            main(argv)
-        else:
-            print "Setuptools version",version,"or greater has been installed."
-            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
-def update_md5(filenames):
-    """Update our built-in md5 registry"""
-
-    import re
-
-    for name in filenames:
-        base = os.path.basename(name)
-        f = open(name,'rb')
-        md5_data[base] = md5(f.read()).hexdigest()
-        f.close()
-
-    data = ["    %r: %r,\n" % it for it in md5_data.items()]
-    data.sort()
-    repl = "".join(data)
-
-    import inspect
-    srcfile = inspect.getsourcefile(sys.modules[__name__])
-    f = open(srcfile, 'rb'); src = f.read(); f.close()
-
-    match = re.search("\nmd5_data = {\n([^}]+)}", src)
-    if not match:
-        print >>sys.stderr, "Internal error!"
-        sys.exit(2)
-
-    src = src[:match.start(1)] + repl + src[match.end(1):]
-    f = open(srcfile,'w')
-    f.write(src)
-    f.close()
-
-
-if __name__=='__main__':
-    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
-        update_md5(sys.argv[2:])
-    else:
-        main(sys.argv[1:])
diff --git a/python/google/__init__.py b/python/google/__init__.py
index de40ea7..5585614 100755
--- a/python/google/__init__.py
+++ b/python/google/__init__.py
@@ -1 +1,4 @@
-__import__('pkg_resources').declare_namespace(__name__)
+try:
+  __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+  __path__ = __import__('pkgutil').extend_path(__path__, __name__)
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index e69de29..2a3c677 100755
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -0,0 +1,39 @@
+# 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.
+
+# Copyright 2007 Google Inc. All Rights Reserved.
+
+__version__ = '3.0.0b3'
+
+if __name__ != '__main__':
+  try:
+    __import__('pkg_resources').declare_namespace(__name__)
+  except ImportError:
+    __path__ = __import__('pkgutil').extend_path(__path__, __name__)
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 6da8bb0..3209b34 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -28,28 +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.
 
-# Needs to stay compatible with Python 2.5 due to GAE.
-#
-# Copyright 2007 Google Inc. All Rights Reserved.
-
 """Descriptors essentially contain exactly the information found in a .proto
 file, in types that make this information accessible in Python.
 """
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
+import six
+
 from google.protobuf.internal import api_implementation
 
-
+_USE_C_DESCRIPTORS = False
 if api_implementation.Type() == 'cpp':
   # Used by MakeDescriptor in cpp mode
   import os
   import uuid
-
-  if api_implementation.Version() == 2:
-    from google.protobuf.pyext import _message
-  else:
-    from google.protobuf.internal import cpp_message
+  from google.protobuf.pyext import _message
+  _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False)
 
 
 class Error(Exception):
@@ -60,12 +55,29 @@
   """Error transforming between python proto type and corresponding C++ type."""
 
 
-class DescriptorBase(object):
+if _USE_C_DESCRIPTORS:
+  # This metaclass allows to override the behavior of code like
+  #     isinstance(my_descriptor, FieldDescriptor)
+  # and make it return True when the descriptor is an instance of the extension
+  # type written in C++.
+  class DescriptorMetaclass(type):
+    def __instancecheck__(cls, obj):
+      if super(DescriptorMetaclass, cls).__instancecheck__(obj):
+        return True
+      if isinstance(obj, cls._C_DESCRIPTOR_CLASS):
+        return True
+      return False
+else:
+  # The standard metaclass; nothing changes.
+  DescriptorMetaclass = type
+
+
+class DescriptorBase(six.with_metaclass(DescriptorMetaclass)):
 
   """Descriptors base class.
 
   This class is the base of all descriptor classes. It provides common options
-  related functionaility.
+  related functionality.
 
   Attributes:
     has_options:  True if the descriptor has non-default options.  Usually it
@@ -75,6 +87,11 @@
         avoid some bootstrapping issues.
   """
 
+  if _USE_C_DESCRIPTORS:
+    # The class, or tuple of classes, that are considered as "virtual
+    # subclasses" of this descriptor class.
+    _C_DESCRIPTOR_CLASS = ()
+
   def __init__(self, options, options_class_name):
     """Initialize the descriptor given its options message and the name of the
     class of the options message. The name of the class is required in case
@@ -201,6 +218,9 @@
     fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
       objects as in |fields|, but indexed by "name" attribute in each
       FieldDescriptor.
+    fields_by_camelcase_name: (dict str -> FieldDescriptor) Same
+      FieldDescriptor objects as in |fields|, but indexed by
+      "camelcase_name" attribute in each FieldDescriptor.
 
     nested_types: (list of Descriptors) Descriptor references
       for all protocol message types nested within this one.
@@ -224,9 +244,6 @@
 
     is_extendable:  Does this type define any extension ranges?
 
-    options: (descriptor_pb2.MessageOptions) Protocol message options or None
-      to use default message options.
-
     oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields
       in this message.
     oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|,
@@ -235,13 +252,25 @@
     file: (FileDescriptor) Reference to file descriptor.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.Descriptor
+
+    def __new__(cls, name, full_name, filename, containing_type, fields,
+                nested_types, enum_types, extensions, options=None,
+                is_extendable=True, extension_ranges=None, oneofs=None,
+                file=None, serialized_start=None, serialized_end=None,
+                syntax=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindMessageTypeByName(full_name)
+
   # NOTE(tmarek): The file argument redefining a builtin is nothing we can
   # fix right now since we don't know how many clients already rely on the
   # name of the argument.
   def __init__(self, name, full_name, filename, containing_type, fields,
                nested_types, enum_types, extensions, options=None,
                is_extendable=True, extension_ranges=None, oneofs=None,
-               file=None, serialized_start=None, serialized_end=None):  # pylint:disable=redefined-builtin
+               file=None, serialized_start=None, serialized_end=None,
+               syntax=None):  # pylint:disable=redefined-builtin
     """Arguments to __init__() are as described in the description
     of Descriptor fields above.
 
@@ -263,6 +292,7 @@
       field.containing_type = self
     self.fields_by_number = dict((f.number, f) for f in fields)
     self.fields_by_name = dict((f.name, f) for f in fields)
+    self._fields_by_camelcase_name = None
 
     self.nested_types = nested_types
     for nested_type in nested_types:
@@ -286,6 +316,14 @@
     self.oneofs_by_name = dict((o.name, o) for o in self.oneofs)
     for oneof in self.oneofs:
       oneof.containing_type = self
+    self.syntax = syntax or "proto2"
+
+  @property
+  def fields_by_camelcase_name(self):
+    if self._fields_by_camelcase_name is None:
+      self._fields_by_camelcase_name = dict(
+          (f.camelcase_name, f) for f in self.fields)
+    return self._fields_by_camelcase_name
 
   def EnumValueName(self, enum, value):
     """Returns the string name of an enum value.
@@ -335,6 +373,7 @@
     name: (str) Name of this field, exactly as it appears in .proto.
     full_name: (str) Name of this field, including containing scope.  This is
       particularly relevant for extensions.
+    camelcase_name: (str) Camelcase name of this field.
     index: (int) Dense, 0-indexed index giving the order that this
       field textually appears within its message in the .proto file.
     number: (int) Tag number declared for this field in the .proto file.
@@ -452,6 +491,19 @@
   FIRST_RESERVED_FIELD_NUMBER = 19000
   LAST_RESERVED_FIELD_NUMBER = 19999
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.FieldDescriptor
+
+    def __new__(cls, name, full_name, index, number, type, cpp_type, label,
+                default_value, message_type, enum_type, containing_type,
+                is_extension, extension_scope, options=None,
+                has_default_value=True, containing_oneof=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      if is_extension:
+        return _message.default_pool.FindExtensionByName(full_name)
+      else:
+        return _message.default_pool.FindFieldByName(full_name)
+
   def __init__(self, name, full_name, index, number, type, cpp_type, label,
                default_value, message_type, enum_type, containing_type,
                is_extension, extension_scope, options=None,
@@ -466,6 +518,7 @@
     super(FieldDescriptor, self).__init__(options, 'FieldOptions')
     self.name = name
     self.full_name = full_name
+    self._camelcase_name = None
     self.index = index
     self.number = number
     self.type = type
@@ -481,23 +534,18 @@
     self.containing_oneof = containing_oneof
     if api_implementation.Type() == 'cpp':
       if is_extension:
-        if api_implementation.Version() == 2:
-          # pylint: disable=protected-access
-          self._cdescriptor = (
-              _message.Message._GetExtensionDescriptor(full_name))
-          # pylint: enable=protected-access
-        else:
-          self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name)
+        self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
       else:
-        if api_implementation.Version() == 2:
-          # pylint: disable=protected-access
-          self._cdescriptor = _message.Message._GetFieldDescriptor(full_name)
-          # pylint: enable=protected-access
-        else:
-          self._cdescriptor = cpp_message.GetFieldDescriptor(full_name)
+        self._cdescriptor = _message.default_pool.FindFieldByName(full_name)
     else:
       self._cdescriptor = None
 
+  @property
+  def camelcase_name(self):
+    if self._camelcase_name is None:
+      self._camelcase_name = _ToCamelCase(self.name)
+    return self._camelcase_name
+
   @staticmethod
   def ProtoTypeToCppProtoType(proto_type):
     """Converts from a Python proto type to a C++ Proto Type.
@@ -544,6 +592,15 @@
       None to use default enum options.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.EnumDescriptor
+
+    def __new__(cls, name, full_name, filename, values,
+                containing_type=None, options=None, file=None,
+                serialized_start=None, serialized_end=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindEnumTypeByName(full_name)
+
   def __init__(self, name, full_name, filename, values,
                containing_type=None, options=None, file=None,
                serialized_start=None, serialized_end=None):
@@ -588,6 +645,17 @@
       None to use default enum value options options.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor
+
+    def __new__(cls, name, index, number, type=None, options=None):
+      _message.Message._CheckCalledFromGeneratedFile()
+      # There is no way we can build a complete EnumValueDescriptor with the
+      # given parameters (the name of the Enum is not known, for example).
+      # Fortunately generated files just pass it to the EnumDescriptor()
+      # constructor, which will ignore it, so returning None is good enough.
+      return None
+
   def __init__(self, name, index, number, type=None, options=None):
     """Arguments are as described in the attribute description above."""
     super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions')
@@ -611,6 +679,13 @@
       oneof can contain.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
+
+    def __new__(cls, name, full_name, index, containing_type, fields):
+      _message.Message._CheckCalledFromGeneratedFile()
+      return _message.default_pool.FindOneofByName(full_name)
+
   def __init__(self, name, full_name, index, containing_type, fields):
     """Arguments are as described in the attribute description above."""
     self.name = name
@@ -704,36 +779,58 @@
 
   name: name of file, relative to root of source tree.
   package: name of the package
+  syntax: string indicating syntax of the file (can be "proto2" or "proto3")
   serialized_pb: (str) Byte string of serialized
     descriptor_pb2.FileDescriptorProto.
   dependencies: List of other FileDescriptors this FileDescriptor depends on.
+  public_dependencies: A list of FileDescriptors, subset of the dependencies
+    above, which were declared as "public".
   message_types_by_name: Dict of message names of their descriptors.
   enum_types_by_name: Dict of enum names and their descriptors.
   extensions_by_name: Dict of extension names and their descriptors.
+  pool: the DescriptorPool this descriptor belongs to.  When not passed to the
+    constructor, the global default pool is used.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.FileDescriptor
+
+    def __new__(cls, name, package, options=None, serialized_pb=None,
+                dependencies=None, public_dependencies=None,
+                syntax=None, pool=None):
+      # FileDescriptor() is called from various places, not only from generated
+      # files, to register dynamic proto files and messages.
+      if serialized_pb:
+        # TODO(amauryfa): use the pool passed as argument. This will work only
+        # for C++-implemented DescriptorPools.
+        return _message.default_pool.AddSerializedFile(serialized_pb)
+      else:
+        return super(FileDescriptor, cls).__new__(cls)
+
   def __init__(self, name, package, options=None, serialized_pb=None,
-               dependencies=None):
+               dependencies=None, public_dependencies=None,
+               syntax=None, pool=None):
     """Constructor."""
     super(FileDescriptor, self).__init__(options, 'FileOptions')
 
+    if pool is None:
+      from google.protobuf import descriptor_pool
+      pool = descriptor_pool.Default()
+    self.pool = pool
     self.message_types_by_name = {}
     self.name = name
     self.package = package
+    self.syntax = syntax or "proto2"
     self.serialized_pb = serialized_pb
 
     self.enum_types_by_name = {}
     self.extensions_by_name = {}
     self.dependencies = (dependencies or [])
+    self.public_dependencies = (public_dependencies or [])
 
     if (api_implementation.Type() == 'cpp' and
         self.serialized_pb is not None):
-      if api_implementation.Version() == 2:
-        # pylint: disable=protected-access
-        _message.Message._BuildFile(self.serialized_pb)
-        # pylint: enable=protected-access
-      else:
-        cpp_message.BuildFile(self.serialized_pb)
+      _message.default_pool.AddSerializedFile(self.serialized_pb)
 
   def CopyToProto(self, proto):
     """Copies this to a descriptor_pb2.FileDescriptorProto.
@@ -754,7 +851,29 @@
   return message
 
 
-def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True):
+def _ToCamelCase(name):
+  """Converts name to camel-case and returns it."""
+  capitalize_next = False
+  result = []
+
+  for c in name:
+    if c == '_':
+      if result:
+        capitalize_next = True
+    elif capitalize_next:
+      result.append(c.upper())
+      capitalize_next = False
+    else:
+      result += c
+
+  # Lower-case the first letter.
+  if result and result[0].isupper():
+    result[0] = result[0].lower()
+  return ''.join(result)
+
+
+def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
+                   syntax=None):
   """Make a protobuf Descriptor given a DescriptorProto protobuf.
 
   Handles nested descriptors. Note that this is limited to the scope of defining
@@ -766,6 +885,8 @@
     package: Optional package name for the new message Descriptor (string).
     build_file_if_cpp: Update the C++ descriptor pool if api matches.
                        Set to False on recursion, so no duplicates are created.
+    syntax: The syntax/semantics that should be used.  Set to "proto3" to get
+            proto3 field presence semantics.
   Returns:
     A Descriptor for protobuf messages.
   """
@@ -778,10 +899,10 @@
     file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
     file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
 
-    # Generate a random name for this proto file to prevent conflicts with
-    # any imported ones. We need to specify a file name so BuildFile accepts
-    # our FileDescriptorProto, but it is not important what that file name
-    # is actually set to.
+    # Generate a random name for this proto file to prevent conflicts with any
+    # imported ones. We need to specify a file name so the descriptor pool
+    # accepts our FileDescriptorProto, but it is not important what that file
+    # name is actually set to.
     proto_name = str(uuid.uuid4())
 
     if package:
@@ -791,12 +912,11 @@
     else:
       file_descriptor_proto.name = proto_name + '.proto'
 
-    if api_implementation.Version() == 2:
-      # pylint: disable=protected-access
-      _message.Message._BuildFile(file_descriptor_proto.SerializeToString())
-      # pylint: enable=protected-access
-    else:
-      cpp_message.BuildFile(file_descriptor_proto.SerializeToString())
+    _message.default_pool.Add(file_descriptor_proto)
+    result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
+
+    if _USE_C_DESCRIPTORS:
+      return result.message_types_by_name[desc_proto.name]
 
   full_message_name = [desc_proto.name]
   if package: full_message_name.insert(0, package)
@@ -819,7 +939,8 @@
     # used by fields in the message, so no loops are possible here.
     nested_desc = MakeDescriptor(nested_proto,
                                  package='.'.join(full_message_name),
-                                 build_file_if_cpp=False)
+                                 build_file_if_cpp=False,
+                                 syntax=syntax)
     nested_types[full_name] = nested_desc
 
   fields = []
@@ -841,9 +962,10 @@
         field_proto.number, field_proto.type,
         FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
         field_proto.label, None, nested_desc, enum_desc, None, False, None,
-        has_default_value=False)
+        options=field_proto.options, has_default_value=False)
     fields.append(field)
 
   desc_name = '.'.join(full_message_name)
   return Descriptor(desc_proto.name, desc_name, None, None, fields,
-                    nested_types.values(), enum_types.values(), [])
+                    list(nested_types.values()), list(enum_types.values()), [],
+                    options=desc_proto.options)
diff --git a/python/google/protobuf/descriptor_database.py b/python/google/protobuf/descriptor_database.py
index 55fb8c7..1333f99 100644
--- a/python/google/protobuf/descriptor_database.py
+++ b/python/google/protobuf/descriptor_database.py
@@ -65,6 +65,7 @@
       raise DescriptorDatabaseConflictingDefinitionError(
           '%s already added, but with different descriptor.' % proto_name)
 
+    # Add the top-level Message, Enum and Extension descriptors to the index.
     package = file_desc_proto.package
     for message in file_desc_proto.message_type:
       self._file_desc_protos_by_symbol.update(
@@ -72,6 +73,9 @@
     for enum in file_desc_proto.enum_type:
       self._file_desc_protos_by_symbol[
           '.'.join((package, enum.name))] = file_desc_proto
+    for extension in file_desc_proto.extension:
+      self._file_desc_protos_by_symbol[
+          '.'.join((package, extension.name))] = file_desc_proto
 
   def FindFileByName(self, name):
     """Finds the file descriptor proto by file name.
@@ -133,5 +137,5 @@
   for nested_type in desc_proto.nested_type:
     for symbol in _ExtractSymbols(nested_type, message_name):
       yield symbol
-    for enum_type in desc_proto.enum_type:
-      yield '.'.join((message_name, enum_type.name))
+  for enum_type in desc_proto.enum_type:
+    yield '.'.join((message_name, enum_type.name))
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index cf234cfa..20a3370 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -57,13 +57,14 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-import sys
-
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import text_encoding
 
 
+_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS
+
+
 def _NormalizeFullyQualifiedName(name):
   """Remove leading period from fully-qualified type name.
 
@@ -82,6 +83,12 @@
 class DescriptorPool(object):
   """A collection of protobufs dynamically constructed by descriptor protos."""
 
+  if _USE_C_DESCRIPTORS:
+
+    def __new__(cls, descriptor_db=None):
+      # pylint: disable=protected-access
+      return descriptor._message.DescriptorPool(descriptor_db)
+
   def __init__(self, descriptor_db=None):
     """Initializes a Pool of proto buffs.
 
@@ -110,6 +117,20 @@
 
     self._internal_db.Add(file_desc_proto)
 
+  def AddSerializedFile(self, serialized_file_desc_proto):
+    """Adds the FileDescriptorProto and its types to this pool.
+
+    Args:
+      serialized_file_desc_proto: A bytes string, serialization of the
+        FileDescriptorProto to add.
+    """
+
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf import descriptor_pb2
+    file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        serialized_file_desc_proto)
+    self.Add(file_desc_proto)
+
   def AddDescriptor(self, desc):
     """Adds a Descriptor to the pool, non-recursively.
 
@@ -175,8 +196,7 @@
 
     try:
       file_proto = self._internal_db.FindFileByName(file_name)
-    except KeyError:
-      _, error, _ = sys.exc_info()  #PY25 compatible for GAE.
+    except KeyError as error:
       if self._descriptor_db:
         file_proto = self._descriptor_db.FindFileByName(file_name)
       else:
@@ -211,8 +231,7 @@
 
     try:
       file_proto = self._internal_db.FindFileContainingSymbol(symbol)
-    except KeyError:
-      _, error, _ = sys.exc_info()  #PY25 compatible for GAE.
+    except KeyError as error:
       if self._descriptor_db:
         file_proto = self._descriptor_db.FindFileContainingSymbol(symbol)
       else:
@@ -251,6 +270,39 @@
       self.FindFileContainingSymbol(full_name)
     return self._enum_descriptors[full_name]
 
+  def FindFieldByName(self, full_name):
+    """Loads the named field descriptor from the pool.
+
+    Args:
+      full_name: The full name of the field descriptor to load.
+
+    Returns:
+      The field descriptor for the named field.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    message_name, _, field_name = full_name.rpartition('.')
+    message_descriptor = self.FindMessageTypeByName(message_name)
+    return message_descriptor.fields_by_name[field_name]
+
+  def FindExtensionByName(self, full_name):
+    """Loads the named extension descriptor from the pool.
+
+    Args:
+      full_name: The full name of the extension descriptor to load.
+
+    Returns:
+      A FieldDescriptor, describing the named extension.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    message_name, _, extension_name = full_name.rpartition('.')
+    try:
+      # Most extensions are nested inside a message.
+      scope = self.FindMessageTypeByName(message_name)
+    except KeyError:
+      # Some extensions are defined at file scope.
+      scope = self.FindFileContainingSymbol(full_name)
+    return scope.extensions_by_name[extension_name]
+
   def _ConvertFileProtoToFileDescriptor(self, file_proto):
     """Creates a FileDescriptor from a proto or returns a cached copy.
 
@@ -267,62 +319,88 @@
     if file_proto.name not in self._file_descriptors:
       built_deps = list(self._GetDeps(file_proto.dependency))
       direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
+      public_deps = [direct_deps[i] for i in file_proto.public_dependency]
 
       file_descriptor = descriptor.FileDescriptor(
+          pool=self,
           name=file_proto.name,
           package=file_proto.package,
+          syntax=file_proto.syntax,
           options=file_proto.options,
           serialized_pb=file_proto.SerializeToString(),
-          dependencies=direct_deps)
-      scope = {}
-
-      # This loop extracts all the message and enum types from all the
-      # dependencoes of the file_proto. This is necessary to create the
-      # scope of available message types when defining the passed in
-      # file proto.
-      for dependency in built_deps:
-        scope.update(self._ExtractSymbols(
-            dependency.message_types_by_name.values()))
-        scope.update((_PrefixWithDot(enum.full_name), enum)
-                     for enum in dependency.enum_types_by_name.values())
-
-      for message_type in file_proto.message_type:
-        message_desc = self._ConvertMessageDescriptor(
-            message_type, file_proto.package, file_descriptor, scope)
-        file_descriptor.message_types_by_name[message_desc.name] = message_desc
-
-      for enum_type in file_proto.enum_type:
-        file_descriptor.enum_types_by_name[enum_type.name] = (
-            self._ConvertEnumDescriptor(enum_type, file_proto.package,
-                                        file_descriptor, None, scope))
-
-      for index, extension_proto in enumerate(file_proto.extension):
-        extension_desc = self.MakeFieldDescriptor(
-            extension_proto, file_proto.package, index, is_extension=True)
-        extension_desc.containing_type = self._GetTypeFromScope(
-            file_descriptor.package, extension_proto.extendee, scope)
-        self.SetFieldType(extension_proto, extension_desc,
-                          file_descriptor.package, scope)
-        file_descriptor.extensions_by_name[extension_desc.name] = extension_desc
-
-      for desc_proto in file_proto.message_type:
-        self.SetAllFieldTypes(file_proto.package, desc_proto, scope)
-
-      if file_proto.package:
-        desc_proto_prefix = _PrefixWithDot(file_proto.package)
+          dependencies=direct_deps,
+          public_dependencies=public_deps)
+      if _USE_C_DESCRIPTORS:
+        # When using C++ descriptors, all objects defined in the file were added
+        # to the C++ database when the FileDescriptor was built above.
+        # Just add them to this descriptor pool.
+        def _AddMessageDescriptor(message_desc):
+          self._descriptors[message_desc.full_name] = message_desc
+          for nested in message_desc.nested_types:
+            _AddMessageDescriptor(nested)
+          for enum_type in message_desc.enum_types:
+            _AddEnumDescriptor(enum_type)
+        def _AddEnumDescriptor(enum_desc):
+          self._enum_descriptors[enum_desc.full_name] = enum_desc
+        for message_type in file_descriptor.message_types_by_name.values():
+          _AddMessageDescriptor(message_type)
+        for enum_type in file_descriptor.enum_types_by_name.values():
+          _AddEnumDescriptor(enum_type)
       else:
-        desc_proto_prefix = ''
+        scope = {}
 
-      for desc_proto in file_proto.message_type:
-        desc = self._GetTypeFromScope(desc_proto_prefix, desc_proto.name, scope)
-        file_descriptor.message_types_by_name[desc_proto.name] = desc
+        # This loop extracts all the message and enum types from all the
+        # dependencies of the file_proto. This is necessary to create the
+        # scope of available message types when defining the passed in
+        # file proto.
+        for dependency in built_deps:
+          scope.update(self._ExtractSymbols(
+              dependency.message_types_by_name.values()))
+          scope.update((_PrefixWithDot(enum.full_name), enum)
+                       for enum in dependency.enum_types_by_name.values())
+
+        for message_type in file_proto.message_type:
+          message_desc = self._ConvertMessageDescriptor(
+              message_type, file_proto.package, file_descriptor, scope,
+              file_proto.syntax)
+          file_descriptor.message_types_by_name[message_desc.name] = (
+              message_desc)
+
+        for enum_type in file_proto.enum_type:
+          file_descriptor.enum_types_by_name[enum_type.name] = (
+              self._ConvertEnumDescriptor(enum_type, file_proto.package,
+                                          file_descriptor, None, scope))
+
+        for index, extension_proto in enumerate(file_proto.extension):
+          extension_desc = self._MakeFieldDescriptor(
+              extension_proto, file_proto.package, index, is_extension=True)
+          extension_desc.containing_type = self._GetTypeFromScope(
+              file_descriptor.package, extension_proto.extendee, scope)
+          self._SetFieldType(extension_proto, extension_desc,
+                            file_descriptor.package, scope)
+          file_descriptor.extensions_by_name[extension_desc.name] = (
+              extension_desc)
+
+        for desc_proto in file_proto.message_type:
+          self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
+
+        if file_proto.package:
+          desc_proto_prefix = _PrefixWithDot(file_proto.package)
+        else:
+          desc_proto_prefix = ''
+
+        for desc_proto in file_proto.message_type:
+          desc = self._GetTypeFromScope(
+              desc_proto_prefix, desc_proto.name, scope)
+          file_descriptor.message_types_by_name[desc_proto.name] = desc
+
       self.Add(file_proto)
       self._file_descriptors[file_proto.name] = file_descriptor
 
     return self._file_descriptors[file_proto.name]
 
   def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
-                                scope=None):
+                                scope=None, syntax=None):
     """Adds the proto to the pool in the specified package.
 
     Args:
@@ -349,15 +427,17 @@
       scope = {}
 
     nested = [
-        self._ConvertMessageDescriptor(nested, desc_name, file_desc, scope)
+        self._ConvertMessageDescriptor(
+            nested, desc_name, file_desc, scope, syntax)
         for nested in desc_proto.nested_type]
     enums = [
         self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
         for enum in desc_proto.enum_type]
-    fields = [self.MakeFieldDescriptor(field, desc_name, index)
+    fields = [self._MakeFieldDescriptor(field, desc_name, index)
               for index, field in enumerate(desc_proto.field)]
     extensions = [
-        self.MakeFieldDescriptor(extension, desc_name, index, is_extension=True)
+        self._MakeFieldDescriptor(extension, desc_name, index,
+                                  is_extension=True)
         for index, extension in enumerate(desc_proto.extension)]
     oneofs = [
         descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
@@ -383,7 +463,8 @@
         extension_ranges=extension_ranges,
         file=file_desc,
         serialized_start=None,
-        serialized_end=None)
+        serialized_end=None,
+        syntax=syntax)
     for nested in desc.nested_types:
       nested.containing_type = desc
     for enum in desc.enum_types:
@@ -436,8 +517,8 @@
     self._enum_descriptors[enum_name] = desc
     return desc
 
-  def MakeFieldDescriptor(self, field_proto, message_name, index,
-                          is_extension=False):
+  def _MakeFieldDescriptor(self, field_proto, message_name, index,
+                           is_extension=False):
     """Creates a field descriptor from a FieldDescriptorProto.
 
     For message and enum type fields, this method will do a look up
@@ -478,7 +559,7 @@
         extension_scope=None,
         options=field_proto.options)
 
-  def SetAllFieldTypes(self, package, desc_proto, scope):
+  def _SetAllFieldTypes(self, package, desc_proto, scope):
     """Sets all the descriptor's fields's types.
 
     This method also sets the containing types on any extensions.
@@ -499,18 +580,18 @@
       nested_package = '.'.join([package, desc_proto.name])
 
     for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
-      self.SetFieldType(field_proto, field_desc, nested_package, scope)
+      self._SetFieldType(field_proto, field_desc, nested_package, scope)
 
     for extension_proto, extension_desc in (
         zip(desc_proto.extension, main_desc.extensions)):
       extension_desc.containing_type = self._GetTypeFromScope(
           nested_package, extension_proto.extendee, scope)
-      self.SetFieldType(extension_proto, extension_desc, nested_package, scope)
+      self._SetFieldType(extension_proto, extension_desc, nested_package, scope)
 
     for nested_type in desc_proto.nested_type:
-      self.SetAllFieldTypes(nested_package, nested_type, scope)
+      self._SetAllFieldTypes(nested_package, nested_type, scope)
 
-  def SetFieldType(self, field_proto, field_desc, package, scope):
+  def _SetFieldType(self, field_proto, field_desc, package, scope):
     """Sets the field's type, cpp_type, message_type and enum_type.
 
     Args:
@@ -554,15 +635,29 @@
         field_desc.default_value = field_proto.default_value.lower() == 'true'
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
         field_desc.default_value = field_desc.enum_type.values_by_name[
-            field_proto.default_value].index
+            field_proto.default_value].number
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
         field_desc.default_value = text_encoding.CUnescape(
             field_proto.default_value)
       else:
+        # All other types are of the "int" type.
         field_desc.default_value = int(field_proto.default_value)
     else:
       field_desc.has_default_value = False
-      field_desc.default_value = None
+      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
+          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
+        field_desc.default_value = 0.0
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
+        field_desc.default_value = u''
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
+        field_desc.default_value = False
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
+        field_desc.default_value = field_desc.enum_type.values[0].number
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        field_desc.default_value = b''
+      else:
+        # All other types are of the "int" type.
+        field_desc.default_value = 0
 
     field_desc.type = field_proto.type
 
@@ -641,3 +736,16 @@
 
 def _PrefixWithDot(name):
   return name if name.startswith('.') else '.%s' % name
+
+
+if _USE_C_DESCRIPTORS:
+  # TODO(amauryfa): This pool could be constructed from Python code, when we
+  # support a flag like 'use_cpp_generated_pool=True'.
+  # pylint: disable=protected-access
+  _DEFAULT = descriptor._message.default_pool
+else:
+  _DEFAULT = DescriptorPool()
+
+
+def Default():
+  return _DEFAULT
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py
new file mode 100755
index 0000000..dea3f19
--- /dev/null
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -0,0 +1,443 @@
+#! /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.
+
+"""Adds support for parameterized tests to Python's unittest TestCase class.
+
+A parameterized test is a method in a test case that is invoked with different
+argument tuples.
+
+A simple example:
+
+  class AdditionExample(parameterized.ParameterizedTestCase):
+    @parameterized.Parameters(
+       (1, 2, 3),
+       (4, 5, 9),
+       (1, 1, 3))
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+
+Each invocation is a separate test case and properly isolated just
+like a normal test method, with its own setUp/tearDown cycle. In the
+example above, there are three separate testcases, one of which will
+fail due to an assertion error (1 + 1 != 3).
+
+Parameters for invididual test cases can be tuples (with positional parameters)
+or dictionaries (with named parameters):
+
+  class AdditionExample(parameterized.ParameterizedTestCase):
+    @parameterized.Parameters(
+       {'op1': 1, 'op2': 2, 'result': 3},
+       {'op1': 4, 'op2': 5, 'result': 9},
+    )
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+If a parameterized test fails, the error message will show the
+original test name (which is modified internally) and the arguments
+for the specific invocation, which are part of the string returned by
+the shortDescription() method on test cases.
+
+The id method of the test, used internally by the unittest framework,
+is also modified to show the arguments. To make sure that test names
+stay the same across several invocations, object representations like
+
+  >>> class Foo(object):
+  ...  pass
+  >>> repr(Foo())
+  '<__main__.Foo object at 0x23d8610>'
+
+are turned into '<__main__.Foo>'. For even more descriptive names,
+especially in test logs, you can use the NamedParameters decorator. In
+this case, only tuples are supported, and the first parameters has to
+be a string (or an object that returns an apt name when converted via
+str()):
+
+  class NamedExample(parameterized.ParameterizedTestCase):
+    @parameterized.NamedParameters(
+       ('Normal', 'aa', 'aaa', True),
+       ('EmptyPrefix', '', 'abc', True),
+       ('BothEmpty', '', '', True))
+    def testStartsWith(self, prefix, string, result):
+      self.assertEqual(result, strings.startswith(prefix))
+
+Named tests also have the benefit that they can be run individually
+from the command line:
+
+  $ testmodule.py NamedExample.testStartsWithNormal
+  .
+  --------------------------------------------------------------------
+  Ran 1 test in 0.000s
+
+  OK
+
+Parameterized Classes
+=====================
+If invocation arguments are shared across test methods in a single
+ParameterizedTestCase class, instead of decorating all test methods
+individually, the class itself can be decorated:
+
+  @parameterized.Parameters(
+    (1, 2, 3)
+    (4, 5, 9))
+  class ArithmeticTest(parameterized.ParameterizedTestCase):
+    def testAdd(self, arg1, arg2, result):
+      self.assertEqual(arg1 + arg2, result)
+
+    def testSubtract(self, arg2, arg2, result):
+      self.assertEqual(result - arg1, arg2)
+
+Inputs from Iterables
+=====================
+If parameters should be shared across several test cases, or are dynamically
+created from other sources, a single non-tuple iterable can be passed into
+the decorator. This iterable will be used to obtain the test cases:
+
+  class AdditionExample(parameterized.ParameterizedTestCase):
+    @parameterized.Parameters(
+      c.op1, c.op2, c.result for c in testcases
+    )
+    def testAddition(self, op1, op2, result):
+      self.assertEqual(result, op1 + op2)
+
+
+Single-Argument Test Methods
+============================
+If a test method takes only one argument, the single argument does not need to
+be wrapped into a tuple:
+
+  class NegativeNumberExample(parameterized.ParameterizedTestCase):
+    @parameterized.Parameters(
+       -1, -3, -4, -5
+    )
+    def testIsNegative(self, arg):
+      self.assertTrue(IsNegative(arg))
+"""
+
+__author__ = 'tmarek@google.com (Torsten Marek)'
+
+import collections
+import functools
+import re
+import types
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
+import uuid
+
+import six
+
+ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
+_SEPARATOR = uuid.uuid1().hex
+_FIRST_ARG = object()
+_ARGUMENT_REPR = object()
+
+
+def _CleanRepr(obj):
+  return ADDR_RE.sub(r'<\1>', repr(obj))
+
+
+# Helper function formerly from the unittest module, removed from it in
+# Python 2.7.
+def _StrClass(cls):
+  return '%s.%s' % (cls.__module__, cls.__name__)
+
+
+def _NonStringIterable(obj):
+  return (isinstance(obj, collections.Iterable) and not
+          isinstance(obj, six.string_types))
+
+
+def _FormatParameterList(testcase_params):
+  if isinstance(testcase_params, collections.Mapping):
+    return ', '.join('%s=%s' % (argname, _CleanRepr(value))
+                     for argname, value in testcase_params.items())
+  elif _NonStringIterable(testcase_params):
+    return ', '.join(map(_CleanRepr, testcase_params))
+  else:
+    return _FormatParameterList((testcase_params,))
+
+
+class _ParameterizedTestIter(object):
+  """Callable and iterable class for producing new test cases."""
+
+  def __init__(self, test_method, testcases, naming_type):
+    """Returns concrete test functions for a test and a list of parameters.
+
+    The naming_type is used to determine the name of the concrete
+    functions as reported by the unittest framework. If naming_type is
+    _FIRST_ARG, the testcases must be tuples, and the first element must
+    have a string representation that is a valid Python identifier.
+
+    Args:
+      test_method: The decorated test method.
+      testcases: (list of tuple/dict) A list of parameter
+                 tuples/dicts for individual test invocations.
+      naming_type: The test naming type, either _NAMED or _ARGUMENT_REPR.
+    """
+    self._test_method = test_method
+    self.testcases = testcases
+    self._naming_type = naming_type
+
+  def __call__(self, *args, **kwargs):
+    raise RuntimeError('You appear to be running a parameterized test case '
+                       'without having inherited from parameterized.'
+                       'ParameterizedTestCase. This is bad because none of '
+                       'your test cases are actually being run.')
+
+  def __iter__(self):
+    test_method = self._test_method
+    naming_type = self._naming_type
+
+    def MakeBoundParamTest(testcase_params):
+      @functools.wraps(test_method)
+      def BoundParamTest(self):
+        if isinstance(testcase_params, collections.Mapping):
+          test_method(self, **testcase_params)
+        elif _NonStringIterable(testcase_params):
+          test_method(self, *testcase_params)
+        else:
+          test_method(self, testcase_params)
+
+      if naming_type is _FIRST_ARG:
+        # Signal the metaclass that the name of the test function is unique
+        # and descriptive.
+        BoundParamTest.__x_use_name__ = True
+        BoundParamTest.__name__ += str(testcase_params[0])
+        testcase_params = testcase_params[1:]
+      elif naming_type is _ARGUMENT_REPR:
+        # __x_extra_id__ is used to pass naming information to the __new__
+        # method of TestGeneratorMetaclass.
+        # The metaclass will make sure to create a unique, but nondescriptive
+        # name for this test.
+        BoundParamTest.__x_extra_id__ = '(%s)' % (
+            _FormatParameterList(testcase_params),)
+      else:
+        raise RuntimeError('%s is not a valid naming type.' % (naming_type,))
+
+      BoundParamTest.__doc__ = '%s(%s)' % (
+          BoundParamTest.__name__, _FormatParameterList(testcase_params))
+      if test_method.__doc__:
+        BoundParamTest.__doc__ += '\n%s' % (test_method.__doc__,)
+      return BoundParamTest
+    return (MakeBoundParamTest(c) for c in self.testcases)
+
+
+def _IsSingletonList(testcases):
+  """True iff testcases contains only a single non-tuple element."""
+  return len(testcases) == 1 and not isinstance(testcases[0], tuple)
+
+
+def _ModifyClass(class_object, testcases, naming_type):
+  assert not getattr(class_object, '_id_suffix', None), (
+      'Cannot add parameters to %s,'
+      ' which already has parameterized methods.' % (class_object,))
+  class_object._id_suffix = id_suffix = {}
+  # We change the size of __dict__ while we iterate over it, 
+  # which Python 3.x will complain about, so use copy().
+  for name, obj in class_object.__dict__.copy().items():
+    if (name.startswith(unittest.TestLoader.testMethodPrefix)
+        and isinstance(obj, types.FunctionType)):
+      delattr(class_object, name)
+      methods = {}
+      _UpdateClassDictForParamTestCase(
+          methods, id_suffix, name,
+          _ParameterizedTestIter(obj, testcases, naming_type))
+      for name, meth in methods.items():
+        setattr(class_object, name, meth)
+
+
+def _ParameterDecorator(naming_type, testcases):
+  """Implementation of the parameterization decorators.
+
+  Args:
+    naming_type: The naming type.
+    testcases: Testcase parameters.
+
+  Returns:
+    A function for modifying the decorated object.
+  """
+  def _Apply(obj):
+    if isinstance(obj, type):
+      _ModifyClass(
+          obj,
+          list(testcases) if not isinstance(testcases, collections.Sequence)
+          else testcases,
+          naming_type)
+      return obj
+    else:
+      return _ParameterizedTestIter(obj, testcases, naming_type)
+
+  if _IsSingletonList(testcases):
+    assert _NonStringIterable(testcases[0]), (
+        'Single parameter argument must be a non-string iterable')
+    testcases = testcases[0]
+
+  return _Apply
+
+
+def Parameters(*testcases):
+  """A decorator for creating parameterized tests.
+
+  See the module docstring for a usage example.
+  Args:
+    *testcases: Parameters for the decorated method, either a single
+                iterable, or a list of tuples/dicts/objects (for tests
+                with only one argument).
+
+  Returns:
+     A test generator to be handled by TestGeneratorMetaclass.
+  """
+  return _ParameterDecorator(_ARGUMENT_REPR, testcases)
+
+
+def NamedParameters(*testcases):
+  """A decorator for creating parameterized tests.
+
+  See the module docstring for a usage example. The first element of
+  each parameter tuple should be a string and will be appended to the
+  name of the test method.
+
+  Args:
+    *testcases: Parameters for the decorated method, either a single
+                iterable, or a list of tuples.
+
+  Returns:
+     A test generator to be handled by TestGeneratorMetaclass.
+  """
+  return _ParameterDecorator(_FIRST_ARG, testcases)
+
+
+class TestGeneratorMetaclass(type):
+  """Metaclass for test cases with test generators.
+
+  A test generator is an iterable in a testcase that produces callables. These
+  callables must be single-argument methods. These methods are injected into
+  the class namespace and the original iterable is removed. If the name of the
+  iterable conforms to the test pattern, the injected methods will be picked
+  up as tests by the unittest framework.
+
+  In general, it is supposed to be used in conjuction with the
+  Parameters decorator.
+  """
+
+  def __new__(mcs, class_name, bases, dct):
+    dct['_id_suffix'] = id_suffix = {}
+    for name, obj in dct.items():
+      if (name.startswith(unittest.TestLoader.testMethodPrefix) and
+          _NonStringIterable(obj)):
+        iterator = iter(obj)
+        dct.pop(name)
+        _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator)
+
+    return type.__new__(mcs, class_name, bases, dct)
+
+
+def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator):
+  """Adds individual test cases to a dictionary.
+
+  Args:
+    dct: The target dictionary.
+    id_suffix: The dictionary for mapping names to test IDs.
+    name: The original name of the test case.
+    iterator: The iterator generating the individual test cases.
+  """
+  for idx, func in enumerate(iterator):
+    assert callable(func), 'Test generators must yield callables, got %r' % (
+        func,)
+    if getattr(func, '__x_use_name__', False):
+      new_name = func.__name__
+    else:
+      new_name = '%s%s%d' % (name, _SEPARATOR, idx)
+    assert new_name not in dct, (
+        'Name of parameterized test case "%s" not unique' % (new_name,))
+    dct[new_name] = func
+    id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
+
+
+class ParameterizedTestCase(unittest.TestCase):
+  """Base class for test cases using the Parameters decorator."""
+  __metaclass__ = TestGeneratorMetaclass
+
+  def _OriginalName(self):
+    return self._testMethodName.split(_SEPARATOR)[0]
+
+  def __str__(self):
+    return '%s (%s)' % (self._OriginalName(), _StrClass(self.__class__))
+
+  def id(self):  # pylint: disable=invalid-name
+    """Returns the descriptive ID of the test.
+
+    This is used internally by the unittesting framework to get a name
+    for the test to be used in reports.
+
+    Returns:
+      The test id.
+    """
+    return '%s.%s%s' % (_StrClass(self.__class__),
+                        self._OriginalName(),
+                        self._id_suffix.get(self._testMethodName, ''))
+
+
+def CoopParameterizedTestCase(other_base_class):
+  """Returns a new base class with a cooperative metaclass base.
+
+  This enables the ParameterizedTestCase to be used in combination
+  with other base classes that have custom metaclasses, such as
+  mox.MoxTestBase.
+
+  Only works with metaclasses that do not override type.__new__.
+
+  Example:
+
+    import google3
+    import mox
+
+    from google3.testing.pybase import parameterized
+
+    class ExampleTest(parameterized.CoopParameterizedTestCase(mox.MoxTestBase)):
+      ...
+
+  Args:
+    other_base_class: (class) A test case base class.
+
+  Returns:
+    A new class object.
+  """
+  metaclass = type(
+      'CoopMetaclass',
+      (other_base_class.__metaclass__,
+       TestGeneratorMetaclass), {})
+  return metaclass(
+      'CoopParameterizedTestCase',
+      (other_base_class, ParameterizedTestCase), {})
diff --git a/python/google/protobuf/internal/any_test.proto b/python/google/protobuf/internal/any_test.proto
new file mode 100644
index 0000000..cd641ca
--- /dev/null
+++ b/python/google/protobuf/internal/any_test.proto
@@ -0,0 +1,42 @@
+// 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.
+
+// Author: jieluo@google.com (Jie Luo)
+
+syntax = "proto3";
+
+package google.protobuf.internal;
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  google.protobuf.Any value = 1;
+  int32 int_value = 2;
+}
diff --git a/python/google/protobuf/internal/api_implementation.cc b/python/google/protobuf/internal/api_implementation.cc
index 83db40b..6db12e8 100644
--- a/python/google/protobuf/internal/api_implementation.cc
+++ b/python/google/protobuf/internal/api_implementation.cc
@@ -50,10 +50,7 @@
 // and
 //   PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2
 #ifdef PYTHON_PROTO2_CPP_IMPL_V1
-#if PY_MAJOR_VERSION >= 3
-#error "PYTHON_PROTO2_CPP_IMPL_V1 is not supported under Python 3."
-#endif
-static int kImplVersion = 1;
+#error "PYTHON_PROTO2_CPP_IMPL_V1 is no longer supported."
 #else
 #ifdef PYTHON_PROTO2_CPP_IMPL_V2
 static int kImplVersion = 2;
@@ -62,14 +59,7 @@
 static int kImplVersion = 0;
 #else
 
-// The defaults are set here.  Python 3 uses the fast C++ APIv2 by default.
-// Python 2 still uses the Python version by default until some compatibility
-// issues can be worked around.
-#if PY_MAJOR_VERSION >= 3
-static int kImplVersion = 2;
-#else
-static int kImplVersion = 0;
-#endif
+static int kImplVersion = -1;  // -1 means "Unspecified by compiler flags".
 
 #endif  // PYTHON_PROTO2_PYTHON_IMPL
 #endif  // PYTHON_PROTO2_CPP_IMPL_V2
diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py
index f7926c1..460a4a6 100755
--- a/python/google/protobuf/internal/api_implementation.py
+++ b/python/google/protobuf/internal/api_implementation.py
@@ -32,6 +32,7 @@
 """
 
 import os
+import warnings
 import sys
 
 try:
@@ -40,14 +41,33 @@
   # The compile-time constants in the _api_implementation module can be used to
   # switch to a certain implementation of the Python API at build time.
   _api_version = _api_implementation.api_version
-  del _api_implementation
+  _proto_extension_modules_exist_in_build = True
 except ImportError:
-  _api_version = 0
+  _api_version = -1  # Unspecified by compiler flags.
+  _proto_extension_modules_exist_in_build = False
+
+if _api_version == 1:
+  raise ValueError('api_version=1 is no longer supported.')
+if _api_version < 0:  # Still unspecified?
+  try:
+    # The presence of this module in a build allows the proto implementation to
+    # be upgraded merely via build deps rather than a compiler flag or the
+    # runtime environment variable.
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf import _use_fast_cpp_protos
+    # Work around a known issue in the classic bootstrap .par import hook.
+    if not _use_fast_cpp_protos:
+      raise ImportError('_use_fast_cpp_protos import succeeded but was None')
+    del _use_fast_cpp_protos
+    _api_version = 2
+  except ImportError:
+    if _proto_extension_modules_exist_in_build:
+      if sys.version_info[0] >= 3:  # Python 3 defaults to C++ impl v2.
+        _api_version = 2
+      # TODO(b/17427486): Make Python 2 default to C++ impl v2.
 
 _default_implementation_type = (
-    'python' if _api_version == 0 else 'cpp')
-_default_version_str = (
-    '1' if _api_version <= 1 else '2')
+    'python' if _api_version <= 0 else 'cpp')
 
 # This environment variable can be used to switch to a certain implementation
 # of the Python API, overriding the compile-time constants in the
@@ -59,18 +79,22 @@
 if _implementation_type != 'python':
   _implementation_type = 'cpp'
 
+if 'PyPy' in sys.version and _implementation_type == 'cpp':
+  warnings.warn('PyPy does not work yet with cpp protocol buffers. '
+                'Falling back to the python implementation.')
+  _implementation_type = 'python'
+
 # This environment variable can be used to switch between the two
 # 'cpp' implementations, overriding the compile-time constants in the
-# _api_implementation module. Right now only 1 and 2 are valid values. Any other
-# value will be ignored.
+# _api_implementation module. Right now only '2' is supported. Any other
+# value will cause an error to be raised.
 _implementation_version_str = os.getenv(
-    'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION',
-    _default_version_str)
+    'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', '2')
 
-if _implementation_version_str not in ('1', '2'):
+if _implementation_version_str != '2':
   raise ValueError(
-      "unsupported PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION: '" +
-      _implementation_version_str + "' (supported versions: 1, 2)"
+      'unsupported PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION: "' +
+      _implementation_version_str + '" (supported versions: 2)'
       )
 
 _implementation_version = int(_implementation_version_str)
diff --git a/python/google/protobuf/internal/api_implementation_default_test.py b/python/google/protobuf/internal/api_implementation_default_test.py
deleted file mode 100644
index 78d5cf2..0000000
--- a/python/google/protobuf/internal/api_implementation_default_test.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#! /usr/bin/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.
-
-"""Test that the api_implementation defaults are what we expect."""
-
-import os
-import sys
-# Clear environment implementation settings before the google3 imports.
-os.environ.pop('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION', None)
-os.environ.pop('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', None)
-
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-
-
-class ApiImplementationDefaultTest(basetest.TestCase):
-
-  if sys.version_info.major <= 2:
-
-    def testThatPythonIsTheDefault(self):
-      """If -DPYTHON_PROTO_*IMPL* was given at build time, this may fail."""
-      self.assertEqual('python', api_implementation.Type())
-
-  else:
-
-    def testThatCppApiV2IsTheDefault(self):
-      """If -DPYTHON_PROTO_*IMPL* was given at build time, this may fail."""
-      self.assertEqual('cpp', api_implementation.Type())
-      self.assertEqual(2, api_implementation.Version())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index 20bfa85..97cdd84 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -41,6 +41,146 @@
 
 __author__ = 'petar@google.com (Petar Petrov)'
 
+import collections
+import sys
+
+if sys.version_info[0] < 3:
+  # We would use collections.MutableMapping all the time, but in Python 2 it
+  # doesn't define __slots__.  This causes two significant problems:
+  #
+  # 1. we can't disallow arbitrary attribute assignment, even if our derived
+  #    classes *do* define __slots__.
+  #
+  # 2. we can't safely derive a C type from it without __slots__ defined (the
+  #    interpreter expects to find a dict at tp_dictoffset, which we can't
+  #    robustly provide.  And we don't want an instance dict anyway.
+  #
+  # So this is the Python 2.7 definition of Mapping/MutableMapping functions
+  # verbatim, except that:
+  # 1. We declare __slots__.
+  # 2. We don't declare this as a virtual base class.  The classes defined
+  #    in collections are the interesting base classes, not us.
+  #
+  # Note: deriving from object is critical.  It is the only thing that makes
+  # this a true type, allowing us to derive from it in C++ cleanly and making
+  # __slots__ properly disallow arbitrary element assignment.
+
+  class Mapping(object):
+    __slots__ = ()
+
+    def get(self, key, default=None):
+      try:
+        return self[key]
+      except KeyError:
+        return default
+
+    def __contains__(self, key):
+      try:
+        self[key]
+      except KeyError:
+        return False
+      else:
+        return True
+
+    def iterkeys(self):
+      return iter(self)
+
+    def itervalues(self):
+      for key in self:
+        yield self[key]
+
+    def iteritems(self):
+      for key in self:
+        yield (key, self[key])
+
+    def keys(self):
+      return list(self)
+
+    def items(self):
+      return [(key, self[key]) for key in self]
+
+    def values(self):
+      return [self[key] for key in self]
+
+    # Mappings are not hashable by default, but subclasses can change this
+    __hash__ = None
+
+    def __eq__(self, other):
+      if not isinstance(other, collections.Mapping):
+        return NotImplemented
+      return dict(self.items()) == dict(other.items())
+
+    def __ne__(self, other):
+      return not (self == other)
+
+  class MutableMapping(Mapping):
+    __slots__ = ()
+
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+      try:
+        value = self[key]
+      except KeyError:
+        if default is self.__marker:
+          raise
+        return default
+      else:
+        del self[key]
+        return value
+
+    def popitem(self):
+      try:
+        key = next(iter(self))
+      except StopIteration:
+        raise KeyError
+      value = self[key]
+      del self[key]
+      return key, value
+
+    def clear(self):
+      try:
+        while True:
+          self.popitem()
+      except KeyError:
+        pass
+
+    def update(*args, **kwds):
+      if len(args) > 2:
+        raise TypeError("update() takes at most 2 positional "
+                        "arguments ({} given)".format(len(args)))
+      elif not args:
+        raise TypeError("update() takes at least 1 argument (0 given)")
+      self = args[0]
+      other = args[1] if len(args) >= 2 else ()
+
+      if isinstance(other, Mapping):
+        for key in other:
+          self[key] = other[key]
+      elif hasattr(other, "keys"):
+        for key in other.keys():
+          self[key] = other[key]
+      else:
+        for key, value in other:
+          self[key] = value
+      for key, value in kwds.items():
+        self[key] = value
+
+    def setdefault(self, key, default=None):
+      try:
+        return self[key]
+      except KeyError:
+        self[key] = default
+      return default
+
+  collections.Mapping.register(Mapping)
+  collections.MutableMapping.register(MutableMapping)
+
+else:
+  # In Python 3 we can just use MutableMapping directly, because it defines
+  # __slots__.
+  MutableMapping = collections.MutableMapping
+
 
 class BaseContainer(object):
 
@@ -119,15 +259,23 @@
       self._message_listener.Modified()
 
   def extend(self, elem_seq):
-    """Extends by appending the given sequence. Similar to list.extend()."""
-    if not elem_seq:
-      return
+    """Extends by appending the given iterable. Similar to list.extend()."""
 
-    new_values = []
-    for elem in elem_seq:
-      new_values.append(self._type_checker.CheckValue(elem))
-    self._values.extend(new_values)
-    self._message_listener.Modified()
+    if elem_seq is None:
+      return
+    try:
+      elem_seq_iter = iter(elem_seq)
+    except TypeError:
+      if not elem_seq:
+        # silently ignore falsy inputs :-/.
+        # TODO(ptucker): Deprecate this behavior. b/18413862
+        return
+      raise
+
+    new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter]
+    if new_values:
+      self._values.extend(new_values)
+      self._message_listener.Modified()
 
   def MergeFrom(self, other):
     """Appends the contents of another repeated field of the same type to this
@@ -141,6 +289,12 @@
     self._values.remove(elem)
     self._message_listener.Modified()
 
+  def pop(self, key=-1):
+    """Removes and returns an item at a given index. Similar to list.pop()."""
+    value = self._values[key]
+    self.__delitem__(key)
+    return value
+
   def __setitem__(self, key, value):
     """Sets the item on the specified position."""
     if isinstance(key, slice):  # PY3
@@ -183,6 +337,8 @@
     # We are presumably comparing against some other sequence type.
     return other == self._values
 
+collections.MutableSequence.register(BaseContainer)
+
 
 class RepeatedCompositeFieldContainer(BaseContainer):
 
@@ -245,6 +401,12 @@
     self._values.remove(elem)
     self._message_listener.Modified()
 
+  def pop(self, key=-1):
+    """Removes and returns an item at a given index. Similar to list.pop()."""
+    value = self._values[key]
+    self.__delitem__(key)
+    return value
+
   def __getslice__(self, start, stop):
     """Retrieves the subset of items from between the specified indices."""
     return self._values[start:stop]
@@ -267,3 +429,183 @@
       raise TypeError('Can only compare repeated composite fields against '
                       'other repeated composite fields.')
     return self._values == other._values
+
+
+class ScalarMap(MutableMapping):
+
+  """Simple, type-checked, dict-like container for holding repeated scalars."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener']
+
+  def __init__(self, message_listener, key_checker, value_checker):
+    """
+    Args:
+      message_listener: A MessageListener implementation.
+        The ScalarMap will call this object's Modified() method when it
+        is modified.
+      key_checker: A type_checkers.ValueChecker instance to run on keys
+        inserted into this container.
+      value_checker: A type_checkers.ValueChecker instance to run on values
+        inserted into this container.
+    """
+    self._message_listener = message_listener
+    self._key_checker = key_checker
+    self._value_checker = value_checker
+    self._values = {}
+
+  def __getitem__(self, key):
+    try:
+      return self._values[key]
+    except KeyError:
+      key = self._key_checker.CheckValue(key)
+      val = self._value_checker.DefaultValue()
+      self._values[key] = val
+      return val
+
+  def __contains__(self, item):
+    # We check the key's type to match the strong-typing flavor of the API.
+    # Also this makes it easier to match the behavior of the C++ implementation.
+    self._key_checker.CheckValue(item)
+    return item in self._values
+
+  # We need to override this explicitly, because our defaultdict-like behavior
+  # will make the default implementation (from our base class) always insert
+  # the key.
+  def get(self, key, default=None):
+    if key in self:
+      return self[key]
+    else:
+      return default
+
+  def __setitem__(self, key, value):
+    checked_key = self._key_checker.CheckValue(key)
+    checked_value = self._value_checker.CheckValue(value)
+    self._values[checked_key] = checked_value
+    self._message_listener.Modified()
+
+  def __delitem__(self, key):
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self):
+    return len(self._values)
+
+  def __iter__(self):
+    return iter(self._values)
+
+  def __repr__(self):
+    return repr(self._values)
+
+  def MergeFrom(self, other):
+    self._values.update(other._values)
+    self._message_listener.Modified()
+
+  def InvalidateIterators(self):
+    # It appears that the only way to reliably invalidate iterators to
+    # self._values is to ensure that its size changes.
+    original = self._values
+    self._values = original.copy()
+    original[None] = None
+
+  # This is defined in the abstract base, but we can do it much more cheaply.
+  def clear(self):
+    self._values.clear()
+    self._message_listener.Modified()
+
+
+class MessageMap(MutableMapping):
+
+  """Simple, type-checked, dict-like container for with submessage values."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_values', '_message_listener',
+               '_message_descriptor']
+
+  def __init__(self, message_listener, message_descriptor, key_checker):
+    """
+    Args:
+      message_listener: A MessageListener implementation.
+        The ScalarMap will call this object's Modified() method when it
+        is modified.
+      key_checker: A type_checkers.ValueChecker instance to run on keys
+        inserted into this container.
+      value_checker: A type_checkers.ValueChecker instance to run on values
+        inserted into this container.
+    """
+    self._message_listener = message_listener
+    self._message_descriptor = message_descriptor
+    self._key_checker = key_checker
+    self._values = {}
+
+  def __getitem__(self, key):
+    try:
+      return self._values[key]
+    except KeyError:
+      key = self._key_checker.CheckValue(key)
+      new_element = self._message_descriptor._concrete_class()
+      new_element._SetListener(self._message_listener)
+      self._values[key] = new_element
+      self._message_listener.Modified()
+
+      return new_element
+
+  def get_or_create(self, key):
+    """get_or_create() is an alias for getitem (ie. map[key]).
+
+    Args:
+      key: The key to get or create in the map.
+
+    This is useful in cases where you want to be explicit that the call is
+    mutating the map.  This can avoid lint errors for statements like this
+    that otherwise would appear to be pointless statements:
+
+      msg.my_map[key]
+    """
+    return self[key]
+
+  # We need to override this explicitly, because our defaultdict-like behavior
+  # will make the default implementation (from our base class) always insert
+  # the key.
+  def get(self, key, default=None):
+    if key in self:
+      return self[key]
+    else:
+      return default
+
+  def __contains__(self, item):
+    return item in self._values
+
+  def __setitem__(self, key, value):
+    raise ValueError('May not set values directly, call my_map[key].foo = 5')
+
+  def __delitem__(self, key):
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self):
+    return len(self._values)
+
+  def __iter__(self):
+    return iter(self._values)
+
+  def __repr__(self):
+    return repr(self._values)
+
+  def MergeFrom(self, other):
+    for key in other:
+      self[key].MergeFrom(other[key])
+    # self._message_listener.Modified() not required here, because
+    # mutations to submessages already propagate.
+
+  def InvalidateIterators(self):
+    # It appears that the only way to reliably invalidate iterators to
+    # self._values is to ensure that its size changes.
+    original = self._values
+    self._values = original.copy()
+    original[None] = None
+
+  # This is defined in the abstract base, but we can do it much more cheaply.
+  def clear(self):
+    self._values.clear()
+    self._message_listener.Modified()
diff --git a/python/google/protobuf/internal/cpp_message.py b/python/google/protobuf/internal/cpp_message.py
deleted file mode 100755
index 0313cb0..0000000
--- a/python/google/protobuf/internal/cpp_message.py
+++ /dev/null
@@ -1,663 +0,0 @@
-# Protocol Buffers - Google's data interchange format
-# Copyright 2008 Google Inc.  All rights reserved.
-# https://developers.google.com/protocol-buffers/
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Contains helper functions used to create protocol message classes from
-Descriptor objects at runtime backed by the protocol buffer C++ API.
-"""
-
-__author__ = 'petar@google.com (Petar Petrov)'
-
-import copy_reg
-import operator
-from google.protobuf.internal import _net_proto2___python
-from google.protobuf.internal import enum_type_wrapper
-from google.protobuf import message
-
-
-_LABEL_REPEATED = _net_proto2___python.LABEL_REPEATED
-_LABEL_OPTIONAL = _net_proto2___python.LABEL_OPTIONAL
-_CPPTYPE_MESSAGE = _net_proto2___python.CPPTYPE_MESSAGE
-_TYPE_MESSAGE = _net_proto2___python.TYPE_MESSAGE
-
-
-def GetDescriptorPool():
-  """Creates a new DescriptorPool C++ object."""
-  return _net_proto2___python.NewCDescriptorPool()
-
-
-_pool = GetDescriptorPool()
-
-
-def GetFieldDescriptor(full_field_name):
-  """Searches for a field descriptor given a full field name."""
-  return _pool.FindFieldByName(full_field_name)
-
-
-def BuildFile(content):
-  """Registers a new proto file in the underlying C++ descriptor pool."""
-  _net_proto2___python.BuildFile(content)
-
-
-def GetExtensionDescriptor(full_extension_name):
-  """Searches for extension descriptor given a full field name."""
-  return _pool.FindExtensionByName(full_extension_name)
-
-
-def NewCMessage(full_message_name):
-  """Creates a new C++ protocol message by its name."""
-  return _net_proto2___python.NewCMessage(full_message_name)
-
-
-def ScalarProperty(cdescriptor):
-  """Returns a scalar property for the given descriptor."""
-
-  def Getter(self):
-    return self._cmsg.GetScalar(cdescriptor)
-
-  def Setter(self, value):
-    self._cmsg.SetScalar(cdescriptor, value)
-
-  return property(Getter, Setter)
-
-
-def CompositeProperty(cdescriptor, message_type):
-  """Returns a Python property the given composite field."""
-
-  def Getter(self):
-    sub_message = self._composite_fields.get(cdescriptor.name, None)
-    if sub_message is None:
-      cmessage = self._cmsg.NewSubMessage(cdescriptor)
-      sub_message = message_type._concrete_class(__cmessage=cmessage)
-      self._composite_fields[cdescriptor.name] = sub_message
-    return sub_message
-
-  return property(Getter)
-
-
-class RepeatedScalarContainer(object):
-  """Container for repeated scalar fields."""
-
-  __slots__ = ['_message', '_cfield_descriptor', '_cmsg']
-
-  def __init__(self, msg, cfield_descriptor):
-    self._message = msg
-    self._cmsg = msg._cmsg
-    self._cfield_descriptor = cfield_descriptor
-
-  def append(self, value):
-    self._cmsg.AddRepeatedScalar(
-        self._cfield_descriptor, value)
-
-  def extend(self, sequence):
-    for element in sequence:
-      self.append(element)
-
-  def insert(self, key, value):
-    values = self[slice(None, None, None)]
-    values.insert(key, value)
-    self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values)
-
-  def remove(self, value):
-    values = self[slice(None, None, None)]
-    values.remove(value)
-    self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values)
-
-  def __setitem__(self, key, value):
-    values = self[slice(None, None, None)]
-    values[key] = value
-    self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values)
-
-  def __getitem__(self, key):
-    return self._cmsg.GetRepeatedScalar(self._cfield_descriptor, key)
-
-  def __delitem__(self, key):
-    self._cmsg.DeleteRepeatedField(self._cfield_descriptor, key)
-
-  def __len__(self):
-    return len(self[slice(None, None, None)])
-
-  def __eq__(self, other):
-    if self is other:
-      return True
-    if not operator.isSequenceType(other):
-      raise TypeError(
-          'Can only compare repeated scalar fields against sequences.')
-    # We are presumably comparing against some other sequence type.
-    return other == self[slice(None, None, None)]
-
-  def __ne__(self, other):
-    return not self == other
-
-  def __hash__(self):
-    raise TypeError('unhashable object')
-
-  def sort(self, *args, **kwargs):
-    # Maintain compatibility with the previous interface.
-    if 'sort_function' in kwargs:
-      kwargs['cmp'] = kwargs.pop('sort_function')
-    self._cmsg.AssignRepeatedScalar(self._cfield_descriptor,
-                                    sorted(self, *args, **kwargs))
-
-
-def RepeatedScalarProperty(cdescriptor):
-  """Returns a Python property the given repeated scalar field."""
-
-  def Getter(self):
-    container = self._composite_fields.get(cdescriptor.name, None)
-    if container is None:
-      container = RepeatedScalarContainer(self, cdescriptor)
-      self._composite_fields[cdescriptor.name] = container
-    return container
-
-  def Setter(self, new_value):
-    raise AttributeError('Assignment not allowed to repeated field '
-                         '"%s" in protocol message object.' % cdescriptor.name)
-
-  doc = 'Magic attribute generated for "%s" proto field.' % cdescriptor.name
-  return property(Getter, Setter, doc=doc)
-
-
-class RepeatedCompositeContainer(object):
-  """Container for repeated composite fields."""
-
-  __slots__ = ['_message', '_subclass', '_cfield_descriptor', '_cmsg']
-
-  def __init__(self, msg, cfield_descriptor, subclass):
-    self._message = msg
-    self._cmsg = msg._cmsg
-    self._subclass = subclass
-    self._cfield_descriptor = cfield_descriptor
-
-  def add(self, **kwargs):
-    cmessage = self._cmsg.AddMessage(self._cfield_descriptor)
-    return self._subclass(__cmessage=cmessage, __owner=self._message, **kwargs)
-
-  def extend(self, elem_seq):
-    """Extends by appending the given sequence of elements of the same type
-    as this one, copying each individual message.
-    """
-    for message in elem_seq:
-      self.add().MergeFrom(message)
-
-  def remove(self, value):
-    # TODO(protocol-devel): This is inefficient as it needs to generate a
-    # message pointer for each message only to do index().  Move this to a C++
-    # extension function.
-    self.__delitem__(self[slice(None, None, None)].index(value))
-
-  def MergeFrom(self, other):
-    for message in other[:]:
-      self.add().MergeFrom(message)
-
-  def __getitem__(self, key):
-    cmessages = self._cmsg.GetRepeatedMessage(
-        self._cfield_descriptor, key)
-    subclass = self._subclass
-    if not isinstance(cmessages, list):
-      return subclass(__cmessage=cmessages, __owner=self._message)
-
-    return [subclass(__cmessage=m, __owner=self._message) for m in cmessages]
-
-  def __delitem__(self, key):
-    self._cmsg.DeleteRepeatedField(
-        self._cfield_descriptor, key)
-
-  def __len__(self):
-    return self._cmsg.FieldLength(self._cfield_descriptor)
-
-  def __eq__(self, other):
-    """Compares the current instance with another one."""
-    if self is other:
-      return True
-    if not isinstance(other, self.__class__):
-      raise TypeError('Can only compare repeated composite fields against '
-                      'other repeated composite fields.')
-    messages = self[slice(None, None, None)]
-    other_messages = other[slice(None, None, None)]
-    return messages == other_messages
-
-  def __hash__(self):
-    raise TypeError('unhashable object')
-
-  def sort(self, cmp=None, key=None, reverse=False, **kwargs):
-    # Maintain compatibility with the old interface.
-    if cmp is None and 'sort_function' in kwargs:
-      cmp = kwargs.pop('sort_function')
-
-    # The cmp function, if provided, is passed the results of the key function,
-    # so we only need to wrap one of them.
-    if key is None:
-      index_key = self.__getitem__
-    else:
-      index_key = lambda i: key(self[i])
-
-    # Sort the list of current indexes by the underlying object.
-    indexes = range(len(self))
-    indexes.sort(cmp=cmp, key=index_key, reverse=reverse)
-
-    # Apply the transposition.
-    for dest, src in enumerate(indexes):
-      if dest == src:
-        continue
-      self._cmsg.SwapRepeatedFieldElements(self._cfield_descriptor, dest, src)
-      # Don't swap the same value twice.
-      indexes[src] = src
-
-
-def RepeatedCompositeProperty(cdescriptor, message_type):
-  """Returns a Python property for the given repeated composite field."""
-
-  def Getter(self):
-    container = self._composite_fields.get(cdescriptor.name, None)
-    if container is None:
-      container = RepeatedCompositeContainer(
-          self, cdescriptor, message_type._concrete_class)
-      self._composite_fields[cdescriptor.name] = container
-    return container
-
-  def Setter(self, new_value):
-    raise AttributeError('Assignment not allowed to repeated field '
-                         '"%s" in protocol message object.' % cdescriptor.name)
-
-  doc = 'Magic attribute generated for "%s" proto field.' % cdescriptor.name
-  return property(Getter, Setter, doc=doc)
-
-
-class ExtensionDict(object):
-  """Extension dictionary added to each protocol message."""
-
-  def __init__(self, msg):
-    self._message = msg
-    self._cmsg = msg._cmsg
-    self._values = {}
-
-  def __setitem__(self, extension, value):
-    from google.protobuf import descriptor
-    if not isinstance(extension, descriptor.FieldDescriptor):
-      raise KeyError('Bad extension %r.' % (extension,))
-    cdescriptor = extension._cdescriptor
-    if (cdescriptor.label != _LABEL_OPTIONAL or
-        cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
-      raise TypeError('Extension %r is repeated and/or a composite type.' % (
-          extension.full_name,))
-    self._cmsg.SetScalar(cdescriptor, value)
-    self._values[extension] = value
-
-  def __getitem__(self, extension):
-    from google.protobuf import descriptor
-    if not isinstance(extension, descriptor.FieldDescriptor):
-      raise KeyError('Bad extension %r.' % (extension,))
-
-    cdescriptor = extension._cdescriptor
-    if (cdescriptor.label != _LABEL_REPEATED and
-        cdescriptor.cpp_type != _CPPTYPE_MESSAGE):
-      return self._cmsg.GetScalar(cdescriptor)
-
-    ext = self._values.get(extension, None)
-    if ext is not None:
-      return ext
-
-    ext = self._CreateNewHandle(extension)
-    self._values[extension] = ext
-    return ext
-
-  def ClearExtension(self, extension):
-    from google.protobuf import descriptor
-    if not isinstance(extension, descriptor.FieldDescriptor):
-      raise KeyError('Bad extension %r.' % (extension,))
-    self._cmsg.ClearFieldByDescriptor(extension._cdescriptor)
-    if extension in self._values:
-      del self._values[extension]
-
-  def HasExtension(self, extension):
-    from google.protobuf import descriptor
-    if not isinstance(extension, descriptor.FieldDescriptor):
-      raise KeyError('Bad extension %r.' % (extension,))
-    return self._cmsg.HasFieldByDescriptor(extension._cdescriptor)
-
-  def _FindExtensionByName(self, name):
-    """Tries to find a known extension with the specified name.
-
-    Args:
-      name: Extension full name.
-
-    Returns:
-      Extension field descriptor.
-    """
-    return self._message._extensions_by_name.get(name, None)
-
-  def _CreateNewHandle(self, extension):
-    cdescriptor = extension._cdescriptor
-    if (cdescriptor.label != _LABEL_REPEATED and
-        cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
-      cmessage = self._cmsg.NewSubMessage(cdescriptor)
-      return extension.message_type._concrete_class(__cmessage=cmessage)
-
-    if cdescriptor.label == _LABEL_REPEATED:
-      if cdescriptor.cpp_type == _CPPTYPE_MESSAGE:
-        return RepeatedCompositeContainer(
-            self._message, cdescriptor, extension.message_type._concrete_class)
-      else:
-        return RepeatedScalarContainer(self._message, cdescriptor)
-    # This shouldn't happen!
-    assert False
-    return None
-
-
-def NewMessage(bases, message_descriptor, dictionary):
-  """Creates a new protocol message *class*."""
-  _AddClassAttributesForNestedExtensions(message_descriptor, dictionary)
-  _AddEnumValues(message_descriptor, dictionary)
-  _AddDescriptors(message_descriptor, dictionary)
-  return bases
-
-
-def InitMessage(message_descriptor, cls):
-  """Constructs a new message instance (called before instance's __init__)."""
-  cls._extensions_by_name = {}
-  _AddInitMethod(message_descriptor, cls)
-  _AddMessageMethods(message_descriptor, cls)
-  _AddPropertiesForExtensions(message_descriptor, cls)
-  copy_reg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
-
-
-def _AddDescriptors(message_descriptor, dictionary):
-  """Sets up a new protocol message class dictionary.
-
-  Args:
-    message_descriptor: A Descriptor instance describing this message type.
-    dictionary: Class dictionary to which we'll add a '__slots__' entry.
-  """
-  dictionary['__descriptors'] = {}
-  for field in message_descriptor.fields:
-    dictionary['__descriptors'][field.name] = GetFieldDescriptor(
-        field.full_name)
-
-  dictionary['__slots__'] = list(dictionary['__descriptors'].iterkeys()) + [
-      '_cmsg', '_owner', '_composite_fields', 'Extensions', '_HACK_REFCOUNTS']
-
-
-def _AddEnumValues(message_descriptor, dictionary):
-  """Sets class-level attributes for all enum fields defined in this message.
-
-  Args:
-    message_descriptor: Descriptor object for this message type.
-    dictionary: Class dictionary that should be populated.
-  """
-  for enum_type in message_descriptor.enum_types:
-    dictionary[enum_type.name] = enum_type_wrapper.EnumTypeWrapper(enum_type)
-    for enum_value in enum_type.values:
-      dictionary[enum_value.name] = enum_value.number
-
-
-def _AddClassAttributesForNestedExtensions(message_descriptor, dictionary):
-  """Adds class attributes for the nested extensions."""
-  extension_dict = message_descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.iteritems():
-    assert extension_name not in dictionary
-    dictionary[extension_name] = extension_field
-
-
-def _AddInitMethod(message_descriptor, cls):
-  """Adds an __init__ method to cls."""
-
-  # Create and attach message field properties to the message class.
-  # This can be done just once per message class, since property setters and
-  # getters are passed the message instance.
-  # This makes message instantiation extremely fast, and at the same time it
-  # doesn't require the creation of property objects for each message instance,
-  # which saves a lot of memory.
-  for field in message_descriptor.fields:
-    field_cdescriptor = cls.__descriptors[field.name]
-    if field.label == _LABEL_REPEATED:
-      if field.cpp_type == _CPPTYPE_MESSAGE:
-        value = RepeatedCompositeProperty(field_cdescriptor, field.message_type)
-      else:
-        value = RepeatedScalarProperty(field_cdescriptor)
-    elif field.cpp_type == _CPPTYPE_MESSAGE:
-      value = CompositeProperty(field_cdescriptor, field.message_type)
-    else:
-      value = ScalarProperty(field_cdescriptor)
-    setattr(cls, field.name, value)
-
-    # Attach a constant with the field number.
-    constant_name = field.name.upper() + '_FIELD_NUMBER'
-    setattr(cls, constant_name, field.number)
-
-  def Init(self, **kwargs):
-    """Message constructor."""
-    cmessage = kwargs.pop('__cmessage', None)
-    if cmessage:
-      self._cmsg = cmessage
-    else:
-      self._cmsg = NewCMessage(message_descriptor.full_name)
-
-    # Keep a reference to the owner, as the owner keeps a reference to the
-    # underlying protocol buffer message.
-    owner = kwargs.pop('__owner', None)
-    if owner:
-      self._owner = owner
-
-    if message_descriptor.is_extendable:
-      self.Extensions = ExtensionDict(self)
-    else:
-      # Reference counting in the C++ code is broken and depends on
-      # the Extensions reference to keep this object alive during unit
-      # tests (see b/4856052).  Remove this once b/4945904 is fixed.
-      self._HACK_REFCOUNTS = self
-    self._composite_fields = {}
-
-    for field_name, field_value in kwargs.iteritems():
-      field_cdescriptor = self.__descriptors.get(field_name, None)
-      if not field_cdescriptor:
-        raise ValueError('Protocol message has no "%s" field.' % field_name)
-      if field_cdescriptor.label == _LABEL_REPEATED:
-        if field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE:
-          field_name = getattr(self, field_name)
-          for val in field_value:
-            field_name.add().MergeFrom(val)
-        else:
-          getattr(self, field_name).extend(field_value)
-      elif field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE:
-        getattr(self, field_name).MergeFrom(field_value)
-      else:
-        setattr(self, field_name, field_value)
-
-  Init.__module__ = None
-  Init.__doc__ = None
-  cls.__init__ = Init
-
-
-def _IsMessageSetExtension(field):
-  """Checks if a field is a message set extension."""
-  return (field.is_extension and
-          field.containing_type.has_options and
-          field.containing_type.GetOptions().message_set_wire_format and
-          field.type == _TYPE_MESSAGE and
-          field.message_type == field.extension_scope and
-          field.label == _LABEL_OPTIONAL)
-
-
-def _AddMessageMethods(message_descriptor, cls):
-  """Adds the methods to a protocol message class."""
-  if message_descriptor.is_extendable:
-
-    def ClearExtension(self, extension):
-      self.Extensions.ClearExtension(extension)
-
-    def HasExtension(self, extension):
-      return self.Extensions.HasExtension(extension)
-
-  def HasField(self, field_name):
-    return self._cmsg.HasField(field_name)
-
-  def ClearField(self, field_name):
-    child_cmessage = None
-    if field_name in self._composite_fields:
-      child_field = self._composite_fields[field_name]
-      del self._composite_fields[field_name]
-
-      child_cdescriptor = self.__descriptors[field_name]
-      # TODO(anuraag): Support clearing repeated message fields as well.
-      if (child_cdescriptor.label != _LABEL_REPEATED and
-          child_cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
-        child_field._owner = None
-        child_cmessage = child_field._cmsg
-
-    if child_cmessage is not None:
-      self._cmsg.ClearField(field_name, child_cmessage)
-    else:
-      self._cmsg.ClearField(field_name)
-
-  def Clear(self):
-    cmessages_to_release = []
-    for field_name, child_field in self._composite_fields.iteritems():
-      child_cdescriptor = self.__descriptors[field_name]
-      # TODO(anuraag): Support clearing repeated message fields as well.
-      if (child_cdescriptor.label != _LABEL_REPEATED and
-          child_cdescriptor.cpp_type == _CPPTYPE_MESSAGE):
-        child_field._owner = None
-        cmessages_to_release.append((child_cdescriptor, child_field._cmsg))
-    self._composite_fields.clear()
-    self._cmsg.Clear(cmessages_to_release)
-
-  def IsInitialized(self, errors=None):
-    if self._cmsg.IsInitialized():
-      return True
-    if errors is not None:
-      errors.extend(self.FindInitializationErrors());
-    return False
-
-  def SerializeToString(self):
-    if not self.IsInitialized():
-      raise message.EncodeError(
-          'Message %s is missing required fields: %s' % (
-          self._cmsg.full_name, ','.join(self.FindInitializationErrors())))
-    return self._cmsg.SerializeToString()
-
-  def SerializePartialToString(self):
-    return self._cmsg.SerializePartialToString()
-
-  def ParseFromString(self, serialized):
-    self.Clear()
-    self.MergeFromString(serialized)
-
-  def MergeFromString(self, serialized):
-    byte_size = self._cmsg.MergeFromString(serialized)
-    if byte_size < 0:
-      raise message.DecodeError('Unable to merge from string.')
-    return byte_size
-
-  def MergeFrom(self, msg):
-    if not isinstance(msg, cls):
-      raise TypeError(
-          "Parameter to MergeFrom() must be instance of same class: "
-          "expected %s got %s." % (cls.__name__, type(msg).__name__))
-    self._cmsg.MergeFrom(msg._cmsg)
-
-  def CopyFrom(self, msg):
-    self._cmsg.CopyFrom(msg._cmsg)
-
-  def ByteSize(self):
-    return self._cmsg.ByteSize()
-
-  def SetInParent(self):
-    return self._cmsg.SetInParent()
-
-  def ListFields(self):
-    all_fields = []
-    field_list = self._cmsg.ListFields()
-    fields_by_name = cls.DESCRIPTOR.fields_by_name
-    for is_extension, field_name in field_list:
-      if is_extension:
-        extension = cls._extensions_by_name[field_name]
-        all_fields.append((extension, self.Extensions[extension]))
-      else:
-        field_descriptor = fields_by_name[field_name]
-        all_fields.append(
-            (field_descriptor, getattr(self, field_name)))
-    all_fields.sort(key=lambda item: item[0].number)
-    return all_fields
-
-  def FindInitializationErrors(self):
-    return self._cmsg.FindInitializationErrors()
-
-  def __str__(self):
-    return str(self._cmsg)
-
-  def __eq__(self, other):
-    if self is other:
-      return True
-    if not isinstance(other, self.__class__):
-      return False
-    return self.ListFields() == other.ListFields()
-
-  def __ne__(self, other):
-    return not self == other
-
-  def __hash__(self):
-    raise TypeError('unhashable object')
-
-  def __unicode__(self):
-    # Lazy import to prevent circular import when text_format imports this file.
-    from google.protobuf import text_format
-    return text_format.MessageToString(self, as_utf8=True).decode('utf-8')
-
-  # Attach the local methods to the message class.
-  for key, value in locals().copy().iteritems():
-    if key not in ('key', 'value', '__builtins__', '__name__', '__doc__'):
-      setattr(cls, key, value)
-
-  # Static methods:
-
-  def RegisterExtension(extension_handle):
-    extension_handle.containing_type = cls.DESCRIPTOR
-    cls._extensions_by_name[extension_handle.full_name] = extension_handle
-
-    if _IsMessageSetExtension(extension_handle):
-      # MessageSet extension.  Also register under type name.
-      cls._extensions_by_name[
-          extension_handle.message_type.full_name] = extension_handle
-  cls.RegisterExtension = staticmethod(RegisterExtension)
-
-  def FromString(string):
-    msg = cls()
-    msg.MergeFromString(string)
-    return msg
-  cls.FromString = staticmethod(FromString)
-
-
-
-def _AddPropertiesForExtensions(message_descriptor, cls):
-  """Adds properties for all fields in this protocol message type."""
-  extension_dict = message_descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.iteritems():
-    constant_name = extension_name.upper() + '_FIELD_NUMBER'
-    setattr(cls, constant_name, extension_field.number)
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index a4b9060..31869e4 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -28,10 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
-# Copyright 2009 Google Inc. All Rights Reserved.
-
 """Code for decoding protocol buffer primitives.
 
 This code is very similar to encoder.py -- read the docs for that module first.
@@ -85,8 +81,12 @@
 __author__ = 'kenton@google.com (Kenton Varda)'
 
 import struct
-import sys  ##PY25
-_PY2 = sys.version_info[0] < 3  ##PY25
+
+import six
+
+if six.PY3:
+  long = int
+
 from google.protobuf.internal import encoder
 from google.protobuf.internal import wire_format
 from google.protobuf import message
@@ -114,14 +114,11 @@
   decoder returns a (value, new_pos) pair.
   """
 
-  local_ord = ord
-  py2 = _PY2  ##PY25
-##!PY25  py2 = str is bytes
   def DecodeVarint(buffer, pos):
     result = 0
     shift = 0
     while 1:
-      b = local_ord(buffer[pos]) if py2 else buffer[pos]
+      b = six.indexbytes(buffer, pos)
       result |= ((b & 0x7f) << shift)
       pos += 1
       if not (b & 0x80):
@@ -137,14 +134,11 @@
 def _SignedVarintDecoder(mask, result_type):
   """Like _VarintDecoder() but decodes signed values."""
 
-  local_ord = ord
-  py2 = _PY2  ##PY25
-##!PY25  py2 = str is bytes
   def DecodeVarint(buffer, pos):
     result = 0
     shift = 0
     while 1:
-      b = local_ord(buffer[pos]) if py2 else buffer[pos]
+      b = six.indexbytes(buffer, pos)
       result |= ((b & 0x7f) << shift)
       pos += 1
       if not (b & 0x80):
@@ -183,10 +177,8 @@
   use that, but not in Python.
   """
 
-  py2 = _PY2  ##PY25
-##!PY25  py2 = str is bytes
   start = pos
-  while (ord(buffer[pos]) if py2 else buffer[pos]) & 0x80:
+  while six.indexbytes(buffer, pos) & 0x80:
     pos += 1
   pos += 1
   return (buffer[start:pos], pos)
@@ -301,7 +293,6 @@
   """
 
   local_unpack = struct.unpack
-  b = (lambda x:x) if _PY2 else lambda x:x.encode('latin1')  ##PY25
 
   def InnerDecode(buffer, pos):
     # We expect a 32-bit value in little-endian byte order.  Bit 1 is the sign
@@ -312,17 +303,12 @@
     # If this value has all its exponent bits set, then it's non-finite.
     # In Python 2.4, struct.unpack will convert it to a finite 64-bit value.
     # To avoid that, we parse it specially.
-    if ((float_bytes[3:4] in b('\x7F\xFF'))  ##PY25
-##!PY25    if ((float_bytes[3:4] in b'\x7F\xFF')
-        and (float_bytes[2:3] >= b('\x80'))):  ##PY25
-##!PY25        and (float_bytes[2:3] >= b'\x80')):
+    if (float_bytes[3:4] in b'\x7F\xFF' and float_bytes[2:3] >= b'\x80'):
       # If at least one significand bit is set...
-      if float_bytes[0:3] != b('\x00\x00\x80'):  ##PY25
-##!PY25      if float_bytes[0:3] != b'\x00\x00\x80':
+      if float_bytes[0:3] != b'\x00\x00\x80':
         return (_NAN, new_pos)
       # If sign bit is set...
-      if float_bytes[3:4] == b('\xFF'):  ##PY25
-##!PY25      if float_bytes[3:4] == b'\xFF':
+      if float_bytes[3:4] == b'\xFF':
         return (_NEG_INF, new_pos)
       return (_POS_INF, new_pos)
 
@@ -341,7 +327,6 @@
   """
 
   local_unpack = struct.unpack
-  b = (lambda x:x) if _PY2 else lambda x:x.encode('latin1')  ##PY25
 
   def InnerDecode(buffer, pos):
     # We expect a 64-bit value in little-endian byte order.  Bit 1 is the sign
@@ -352,12 +337,9 @@
     # If this value has all its exponent bits set and at least one significand
     # bit set, it's not a number.  In Python 2.4, struct.unpack will treat it
     # as inf or -inf.  To avoid that, we treat it specially.
-##!PY25    if ((double_bytes[7:8] in b'\x7F\xFF')
-##!PY25        and (double_bytes[6:7] >= b'\xF0')
-##!PY25        and (double_bytes[0:7] != b'\x00\x00\x00\x00\x00\x00\xF0')):
-    if ((double_bytes[7:8] in b('\x7F\xFF'))  ##PY25
-        and (double_bytes[6:7] >= b('\xF0'))  ##PY25
-        and (double_bytes[0:7] != b('\x00\x00\x00\x00\x00\x00\xF0'))):  ##PY25
+    if ((double_bytes[7:8] in b'\x7F\xFF')
+        and (double_bytes[6:7] >= b'\xF0')
+        and (double_bytes[0:7] != b'\x00\x00\x00\x00\x00\x00\xF0')):
       return (_NAN, new_pos)
 
     # Note that we expect someone up-stack to catch struct.error and convert
@@ -480,12 +462,12 @@
   """Returns a decoder for a string field."""
 
   local_DecodeVarint = _DecodeVarint
-  local_unicode = unicode
+  local_unicode = six.text_type
 
   def _ConvertToUnicode(byte_str):
     try:
       return local_unicode(byte_str, 'utf-8')
-    except UnicodeDecodeError, e:
+    except UnicodeDecodeError as e:
       # add more information to the error message and re-raise it.
       e.reason = '%s in field: %s' % (e, key.full_name)
       raise
@@ -621,9 +603,6 @@
       if value is None:
         value = field_dict.setdefault(key, new_default(message))
       while 1:
-        value = field_dict.get(key)
-        if value is None:
-          value = field_dict.setdefault(key, new_default(message))
         # Read length.
         (size, pos) = local_DecodeVarint(buffer, pos)
         new_pos = pos + size
@@ -736,6 +715,50 @@
   return DecodeItem
 
 # --------------------------------------------------------------------
+
+def MapDecoder(field_descriptor, new_default, is_message_map):
+  """Returns a decoder for a map field."""
+
+  key = field_descriptor
+  tag_bytes = encoder.TagBytes(field_descriptor.number,
+                               wire_format.WIRETYPE_LENGTH_DELIMITED)
+  tag_len = len(tag_bytes)
+  local_DecodeVarint = _DecodeVarint
+  # Can't read _concrete_class yet; might not be initialized.
+  message_type = field_descriptor.message_type
+
+  def DecodeMap(buffer, pos, end, message, field_dict):
+    submsg = message_type._concrete_class()
+    value = field_dict.get(key)
+    if value is None:
+      value = field_dict.setdefault(key, new_default(message))
+    while 1:
+      # Read length.
+      (size, pos) = local_DecodeVarint(buffer, pos)
+      new_pos = pos + size
+      if new_pos > end:
+        raise _DecodeError('Truncated message.')
+      # Read sub-message.
+      submsg.Clear()
+      if submsg._InternalParse(buffer, pos, new_pos) != new_pos:
+        # The only reason _InternalParse would return early is if it
+        # encountered an end-group tag.
+        raise _DecodeError('Unexpected end-group tag.')
+
+      if is_message_map:
+        value[submsg.key].MergeFrom(submsg.value)
+      else:
+        value[submsg.key] = submsg.value
+
+      # Predict that the next tag is another copy of the same repeated field.
+      pos = new_pos + tag_len
+      if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+        # Prediction failed.  Return.
+        return new_pos
+
+  return DecodeMap
+
+# --------------------------------------------------------------------
 # Optimization is not as heavy here because calls to SkipField() are rare,
 # except for handling end-group tags.
 
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
index fc65b69..5225a45 100644
--- a/python/google/protobuf/internal/descriptor_database_test.py
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,13 +34,17 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf import descriptor_database
 
 
-class DescriptorDatabaseTest(basetest.TestCase):
+class DescriptorDatabaseTest(unittest.TestCase):
 
   def testAdd(self):
     db = descriptor_database.DescriptorDatabase()
@@ -48,16 +52,18 @@
         factory_test2_pb2.DESCRIPTOR.serialized_pb)
     db.Add(file_desc_proto)
 
-    self.assertEquals(file_desc_proto, db.FindFileByName(
+    self.assertEqual(file_desc_proto, db.FindFileByName(
         'google/protobuf/internal/factory_test2.proto'))
-    self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Message'))
-    self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Message.NestedFactory2Message'))
-    self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Enum'))
-    self.assertEquals(file_desc_proto, db.FindFileContainingSymbol(
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum'))
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.MessageWithNestedEnumOnly.NestedEnum'))
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index d2f8557..6a13e0b 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -35,9 +35,15 @@
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 import os
-import unittest
+import sys
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_import_public_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import api_implementation
@@ -45,12 +51,15 @@
 from google.protobuf.internal import descriptor_pool_test2_pb2
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import more_messages_pb2
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
+from google.protobuf import symbol_database
 
 
-class DescriptorPoolTest(basetest.TestCase):
+class DescriptorPoolTest(unittest.TestCase):
 
   def setUp(self):
     self.pool = descriptor_pool.DescriptorPool()
@@ -65,15 +74,15 @@
     name1 = 'google/protobuf/internal/factory_test1.proto'
     file_desc1 = self.pool.FindFileByName(name1)
     self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
-    self.assertEquals(name1, file_desc1.name)
-    self.assertEquals('google.protobuf.python.internal', file_desc1.package)
+    self.assertEqual(name1, file_desc1.name)
+    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
     self.assertIn('Factory1Message', file_desc1.message_types_by_name)
 
     name2 = 'google/protobuf/internal/factory_test2.proto'
     file_desc2 = self.pool.FindFileByName(name2)
     self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
-    self.assertEquals(name2, file_desc2.name)
-    self.assertEquals('google.protobuf.python.internal', file_desc2.package)
+    self.assertEqual(name2, file_desc2.name)
+    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
     self.assertIn('Factory2Message', file_desc2.message_types_by_name)
 
   def testFindFileByNameFailure(self):
@@ -84,17 +93,17 @@
     file_desc1 = self.pool.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory1Message')
     self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
-    self.assertEquals('google/protobuf/internal/factory_test1.proto',
-                      file_desc1.name)
-    self.assertEquals('google.protobuf.python.internal', file_desc1.package)
+    self.assertEqual('google/protobuf/internal/factory_test1.proto',
+                     file_desc1.name)
+    self.assertEqual('google.protobuf.python.internal', file_desc1.package)
     self.assertIn('Factory1Message', file_desc1.message_types_by_name)
 
     file_desc2 = self.pool.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Message')
     self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
-    self.assertEquals('google/protobuf/internal/factory_test2.proto',
-                      file_desc2.name)
-    self.assertEquals('google.protobuf.python.internal', file_desc2.package)
+    self.assertEqual('google/protobuf/internal/factory_test2.proto',
+                     file_desc2.name)
+    self.assertEqual('google.protobuf.python.internal', file_desc2.package)
     self.assertIn('Factory2Message', file_desc2.message_types_by_name)
 
   def testFindFileContainingSymbolFailure(self):
@@ -105,72 +114,72 @@
     msg1 = self.pool.FindMessageTypeByName(
         'google.protobuf.python.internal.Factory1Message')
     self.assertIsInstance(msg1, descriptor.Descriptor)
-    self.assertEquals('Factory1Message', msg1.name)
-    self.assertEquals('google.protobuf.python.internal.Factory1Message',
-                      msg1.full_name)
-    self.assertEquals(None, msg1.containing_type)
+    self.assertEqual('Factory1Message', msg1.name)
+    self.assertEqual('google.protobuf.python.internal.Factory1Message',
+                     msg1.full_name)
+    self.assertEqual(None, msg1.containing_type)
 
     nested_msg1 = msg1.nested_types[0]
-    self.assertEquals('NestedFactory1Message', nested_msg1.name)
-    self.assertEquals(msg1, nested_msg1.containing_type)
+    self.assertEqual('NestedFactory1Message', nested_msg1.name)
+    self.assertEqual(msg1, nested_msg1.containing_type)
 
     nested_enum1 = msg1.enum_types[0]
-    self.assertEquals('NestedFactory1Enum', nested_enum1.name)
-    self.assertEquals(msg1, nested_enum1.containing_type)
+    self.assertEqual('NestedFactory1Enum', nested_enum1.name)
+    self.assertEqual(msg1, nested_enum1.containing_type)
 
-    self.assertEquals(nested_msg1, msg1.fields_by_name[
+    self.assertEqual(nested_msg1, msg1.fields_by_name[
         'nested_factory_1_message'].message_type)
-    self.assertEquals(nested_enum1, msg1.fields_by_name[
+    self.assertEqual(nested_enum1, msg1.fields_by_name[
         'nested_factory_1_enum'].enum_type)
 
     msg2 = self.pool.FindMessageTypeByName(
         'google.protobuf.python.internal.Factory2Message')
     self.assertIsInstance(msg2, descriptor.Descriptor)
-    self.assertEquals('Factory2Message', msg2.name)
-    self.assertEquals('google.protobuf.python.internal.Factory2Message',
-                      msg2.full_name)
+    self.assertEqual('Factory2Message', msg2.name)
+    self.assertEqual('google.protobuf.python.internal.Factory2Message',
+                     msg2.full_name)
     self.assertIsNone(msg2.containing_type)
 
     nested_msg2 = msg2.nested_types[0]
-    self.assertEquals('NestedFactory2Message', nested_msg2.name)
-    self.assertEquals(msg2, nested_msg2.containing_type)
+    self.assertEqual('NestedFactory2Message', nested_msg2.name)
+    self.assertEqual(msg2, nested_msg2.containing_type)
 
     nested_enum2 = msg2.enum_types[0]
-    self.assertEquals('NestedFactory2Enum', nested_enum2.name)
-    self.assertEquals(msg2, nested_enum2.containing_type)
+    self.assertEqual('NestedFactory2Enum', nested_enum2.name)
+    self.assertEqual(msg2, nested_enum2.containing_type)
 
-    self.assertEquals(nested_msg2, msg2.fields_by_name[
+    self.assertEqual(nested_msg2, msg2.fields_by_name[
         'nested_factory_2_message'].message_type)
-    self.assertEquals(nested_enum2, msg2.fields_by_name[
+    self.assertEqual(nested_enum2, msg2.fields_by_name[
         'nested_factory_2_enum'].enum_type)
 
     self.assertTrue(msg2.fields_by_name['int_with_default'].has_default_value)
-    self.assertEquals(
+    self.assertEqual(
         1776, msg2.fields_by_name['int_with_default'].default_value)
 
     self.assertTrue(
         msg2.fields_by_name['double_with_default'].has_default_value)
-    self.assertEquals(
+    self.assertEqual(
         9.99, msg2.fields_by_name['double_with_default'].default_value)
 
     self.assertTrue(
         msg2.fields_by_name['string_with_default'].has_default_value)
-    self.assertEquals(
+    self.assertEqual(
         'hello world', msg2.fields_by_name['string_with_default'].default_value)
 
     self.assertTrue(msg2.fields_by_name['bool_with_default'].has_default_value)
     self.assertFalse(msg2.fields_by_name['bool_with_default'].default_value)
 
     self.assertTrue(msg2.fields_by_name['enum_with_default'].has_default_value)
-    self.assertEquals(
+    self.assertEqual(
         1, msg2.fields_by_name['enum_with_default'].default_value)
 
     msg3 = self.pool.FindMessageTypeByName(
         'google.protobuf.python.internal.Factory2Message.NestedFactory2Message')
-    self.assertEquals(nested_msg2, msg3)
+    self.assertEqual(nested_msg2, msg3)
 
     self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value)
-    self.assertEquals(
+    self.assertEqual(
         b'a\xfb\x00c',
         msg2.fields_by_name['bytes_with_default'].default_value)
 
@@ -190,35 +199,66 @@
     enum1 = self.pool.FindEnumTypeByName(
         'google.protobuf.python.internal.Factory1Enum')
     self.assertIsInstance(enum1, descriptor.EnumDescriptor)
-    self.assertEquals(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
-    self.assertEquals(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
+    self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number)
+    self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number)
 
     nested_enum1 = self.pool.FindEnumTypeByName(
         'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum')
     self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor)
-    self.assertEquals(
+    self.assertEqual(
         0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number)
-    self.assertEquals(
+    self.assertEqual(
         1, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_1'].number)
 
     enum2 = self.pool.FindEnumTypeByName(
         'google.protobuf.python.internal.Factory2Enum')
     self.assertIsInstance(enum2, descriptor.EnumDescriptor)
-    self.assertEquals(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number)
-    self.assertEquals(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number)
+    self.assertEqual(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number)
+    self.assertEqual(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number)
 
     nested_enum2 = self.pool.FindEnumTypeByName(
         'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum')
     self.assertIsInstance(nested_enum2, descriptor.EnumDescriptor)
-    self.assertEquals(
+    self.assertEqual(
         0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number)
-    self.assertEquals(
+    self.assertEqual(
         1, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_1'].number)
 
   def testFindEnumTypeByNameFailure(self):
     with self.assertRaises(KeyError):
       self.pool.FindEnumTypeByName('Does not exist')
 
+  def testFindFieldByName(self):
+    field = self.pool.FindFieldByName(
+        'google.protobuf.python.internal.Factory1Message.list_value')
+    self.assertEqual(field.name, 'list_value')
+    self.assertEqual(field.label, field.LABEL_REPEATED)
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('Does not exist')
+
+  def testFindExtensionByName(self):
+    # An extension defined in a message.
+    extension = self.pool.FindExtensionByName(
+        'google.protobuf.python.internal.Factory2Message.one_more_field')
+    self.assertEqual(extension.name, 'one_more_field')
+    # An extension defined at file scope.
+    extension = self.pool.FindExtensionByName(
+        'google.protobuf.python.internal.another_field')
+    self.assertEqual(extension.name, 'another_field')
+    self.assertEqual(extension.number, 1002)
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('Does not exist')
+
+  def testExtensionsAreNotFields(self):
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('google.protobuf.python.internal.another_field')
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName(
+          'google.protobuf.python.internal.Factory2Message.one_more_field')
+    with self.assertRaises(KeyError):
+      self.pool.FindExtensionByName(
+          'google.protobuf.python.internal.Factory1Message.list_value')
+
   def testUserDefinedDB(self):
     db = descriptor_database.DescriptorDatabase()
     self.pool = descriptor_pool.DescriptorPool(db)
@@ -226,32 +266,109 @@
     db.Add(self.factory_test2_fd)
     self.testFindMessageTypeByName()
 
+  def testAddSerializedFile(self):
+    self.pool = descriptor_pool.DescriptorPool()
+    self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString())
+    self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString())
+    self.testFindMessageTypeByName()
+
   def testComplexNesting(self):
+    more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString(
+        more_messages_pb2.DESCRIPTOR.serialized_pb)
     test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
         descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
     test2_desc = descriptor_pb2.FileDescriptorProto.FromString(
         descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb)
+    self.pool.Add(more_messages_desc)
     self.pool.Add(test1_desc)
     self.pool.Add(test2_desc)
     TEST1_FILE.CheckFile(self, self.pool)
     TEST2_FILE.CheckFile(self, self.pool)
 
 
+  def testEnumDefaultValue(self):
+    """Test the default value of enums which don't start at zero."""
+    def _CheckDefaultValue(file_descriptor):
+      default_value = (file_descriptor
+                       .message_types_by_name['DescriptorPoolTest1']
+                       .fields_by_name['nested_enum']
+                       .default_value)
+      self.assertEqual(default_value,
+                       descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA)
+    # First check what the generated descriptor contains.
+    _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR)
+    # Then check the generated pool. Normally this is the same descriptor.
+    file_descriptor = symbol_database.Default().pool.FindFileByName(
+        'google/protobuf/internal/descriptor_pool_test1.proto')
+    self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR)
+    _CheckDefaultValue(file_descriptor)
+
+    # Then check the dynamic pool and its internal DescriptorDatabase.
+    descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
+    self.pool.Add(descriptor_proto)
+    # And do the same check as above
+    file_descriptor = self.pool.FindFileByName(
+        'google/protobuf/internal/descriptor_pool_test1.proto')
+    _CheckDefaultValue(file_descriptor)
+
+  def testDefaultValueForCustomMessages(self):
+    """Check the value returned by non-existent fields."""
+    def _CheckValueAndType(value, expected_value, expected_type):
+      self.assertEqual(value, expected_value)
+      self.assertIsInstance(value, expected_type)
+
+    def _CheckDefaultValues(msg):
+      try:
+        int64 = long
+      except NameError:  # Python3
+        int64 = int
+      try:
+        unicode_type = unicode
+      except NameError:  # Python3
+        unicode_type = str
+      _CheckValueAndType(msg.optional_int32, 0, int)
+      _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
+      _CheckValueAndType(msg.optional_float, 0, (float, int))
+      _CheckValueAndType(msg.optional_double, 0, (float, int))
+      _CheckValueAndType(msg.optional_bool, False, bool)
+      _CheckValueAndType(msg.optional_string, u'', unicode_type)
+      _CheckValueAndType(msg.optional_bytes, b'', bytes)
+      _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
+    # First for the generated message
+    _CheckDefaultValues(unittest_pb2.TestAllTypes())
+    # Then for a message built with from the DescriptorPool.
+    pool = descriptor_pool.DescriptorPool()
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb))
+    message_class = message_factory.MessageFactory(pool).GetPrototype(
+        pool.FindMessageTypeByName(
+            unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
+    _CheckDefaultValues(message_class())
+
 
 class ProtoFile(object):
 
-  def __init__(self, name, package, messages, dependencies=None):
+  def __init__(self, name, package, messages, dependencies=None,
+               public_dependencies=None):
     self.name = name
     self.package = package
     self.messages = messages
     self.dependencies = dependencies or []
+    self.public_dependencies = public_dependencies or []
 
   def CheckFile(self, test, pool):
     file_desc = pool.FindFileByName(self.name)
-    test.assertEquals(self.name, file_desc.name)
-    test.assertEquals(self.package, file_desc.package)
+    test.assertEqual(self.name, file_desc.name)
+    test.assertEqual(self.package, file_desc.package)
     dependencies_names = [f.name for f in file_desc.dependencies]
     test.assertEqual(self.dependencies, dependencies_names)
+    public_dependencies_names = [f.name for f in file_desc.public_dependencies]
+    test.assertEqual(self.public_dependencies, public_dependencies_names)
     for name, msg_type in self.messages.items():
       msg_type.CheckType(test, None, name, file_desc)
 
@@ -328,7 +445,7 @@
     test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM,
                      field_desc.cpp_type)
     test.assertTrue(field_desc.has_default_value)
-    test.assertEqual(enum_desc.values_by_name[self.default_value].index,
+    test.assertEqual(enum_desc.values_by_name[self.default_value].number,
                      field_desc.default_value)
     test.assertEqual(msg_desc, field_desc.containing_type)
     test.assertEqual(enum_desc, field_desc.enum_type)
@@ -399,12 +516,12 @@
     test.assertEqual(self.extended_type, field_desc.containing_type.name)
 
 
-class AddDescriptorTest(basetest.TestCase):
+class AddDescriptorTest(unittest.TestCase):
 
   def _TestMessage(self, prefix):
     pool = descriptor_pool.DescriptorPool()
     pool.AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes',
         pool.FindMessageTypeByName(
             prefix + 'protobuf_unittest.TestAllTypes').full_name)
@@ -415,22 +532,24 @@
           prefix + 'protobuf_unittest.TestAllTypes.NestedMessage')
 
     pool.AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes.NestedMessage',
         pool.FindMessageTypeByName(
             prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
 
     # Files are implicitly also indexed when messages are added.
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         pool.FindFileByName(
             'google/protobuf/unittest.proto').name)
 
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         pool.FindFileContainingSymbol(
             prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                   'With the cpp implementation, Add() must be called first')
   def testMessage(self):
     self._TestMessage('')
     self._TestMessage('.')
@@ -438,7 +557,7 @@
   def _TestEnum(self, prefix):
     pool = descriptor_pool.DescriptorPool()
     pool.AddEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.ForeignEnum',
         pool.FindEnumTypeByName(
             prefix + 'protobuf_unittest.ForeignEnum').full_name)
@@ -449,30 +568,34 @@
           prefix + 'protobuf_unittest.ForeignEnum.NestedEnum')
 
     pool.AddEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes.NestedEnum',
         pool.FindEnumTypeByName(
             prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
 
     # Files are implicitly also indexed when enums are added.
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         pool.FindFileByName(
             'google/protobuf/unittest.proto').name)
 
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         pool.FindFileContainingSymbol(
             prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                   'With the cpp implementation, Add() must be called first')
   def testEnum(self):
     self._TestEnum('')
     self._TestEnum('.')
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                   'With the cpp implementation, Add() must be called first')
   def testFile(self):
     pool = descriptor_pool.DescriptorPool()
     pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR)
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         pool.FindFileByName(
             'google/protobuf/unittest.proto').name)
@@ -483,6 +606,67 @@
       pool.FindFileContainingSymbol(
           'protobuf_unittest.TestAllTypes')
 
+  def testEmptyDescriptorPool(self):
+    # Check that an empty DescriptorPool() contains no messages.
+    pool = descriptor_pool.DescriptorPool()
+    proto_file_name = descriptor_pb2.DESCRIPTOR.name
+    self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
+    # Add the above file to the pool
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
+    pool.Add(file_descriptor)
+    # Now it exists.
+    self.assertTrue(pool.FindFileByName(proto_file_name))
+
+  def testCustomDescriptorPool(self):
+    # Create a new pool, and add a file descriptor.
+    pool = descriptor_pool.DescriptorPool()
+    file_desc = descriptor_pb2.FileDescriptorProto(
+        name='some/file.proto', package='package')
+    file_desc.message_type.add(name='Message')
+    pool.Add(file_desc)
+    self.assertEqual(pool.FindFileByName('some/file.proto').name,
+                     'some/file.proto')
+    self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
+                     'Message')
+
+
+@unittest.skipIf(
+    api_implementation.Type() != 'cpp',
+    'default_pool is only supported by the C++ implementation')
+class DefaultPoolTest(unittest.TestCase):
+
+  def testFindMethods(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    self.assertIs(
+        pool.FindFileByName('google/protobuf/unittest.proto'),
+        unittest_pb2.DESCRIPTOR)
+    self.assertIs(
+        pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertIs(
+        pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertIs(
+        pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
+        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
+    self.assertIs(
+        pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
+        unittest_pb2.ForeignEnum.DESCRIPTOR)
+    self.assertIs(
+        pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
+
+  def testAddFileDescriptor(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
+    pool.Add(file_desc)
+    pool.AddSerializedFile(file_desc.SerializeToString())
+
 
 TEST1_FILE = ProtoFile(
     'google/protobuf/internal/descriptor_pool_test1.proto',
@@ -557,8 +741,10 @@
              ExtensionField(1001, 'DescriptorPoolTest1')),
         ]),
     },
-    dependencies=['google/protobuf/internal/descriptor_pool_test1.proto'])
+    dependencies=['google/protobuf/internal/descriptor_pool_test1.proto',
+                  'google/protobuf/internal/more_messages.proto'],
+    public_dependencies=['google/protobuf/internal/more_messages.proto'])
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test1.proto b/python/google/protobuf/internal/descriptor_pool_test1.proto
index 6dfe4ef..00816b7 100644
--- a/python/google/protobuf/internal/descriptor_pool_test1.proto
+++ b/python/google/protobuf/internal/descriptor_pool_test1.proto
@@ -28,6 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+syntax = "proto2";
+
 package google.protobuf.python.internal;
 
 
diff --git a/python/google/protobuf/internal/descriptor_pool_test2.proto b/python/google/protobuf/internal/descriptor_pool_test2.proto
index fbc8438..a218ecc 100644
--- a/python/google/protobuf/internal/descriptor_pool_test2.proto
+++ b/python/google/protobuf/internal/descriptor_pool_test2.proto
@@ -28,9 +28,12 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+syntax = "proto2";
+
 package google.protobuf.python.internal;
 
 import "google/protobuf/internal/descriptor_pool_test1.proto";
+import public "google/protobuf/internal/more_messages.proto";
 
 
 message DescriptorPoolTest3 {
diff --git a/python/google/protobuf/internal/descriptor_python_test.py b/python/google/protobuf/internal/descriptor_python_test.py
deleted file mode 100644
index 5471ae0..0000000
--- a/python/google/protobuf/internal/descriptor_python_test.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#! /usr/bin/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.
-
-"""Unittest for descriptor.py for the pure Python implementation."""
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
-
-# We must set the implementation version above before the google3 imports.
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-# Run all tests from the original module by putting them in our namespace.
-# pylint: disable=wildcard-import
-from google.protobuf.internal.descriptor_test import *
-
-
-class ConfirmPurePythonTest(basetest.TestCase):
-
-  def testImplementationSetting(self):
-    self.assertEqual('python', api_implementation.Type())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index b3777e3..b8e7555 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,12 +34,22 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.apputils import basetest
+import sys
+
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
+from google.protobuf.internal import api_implementation
+from google.protobuf.internal import test_util
 from google.protobuf import descriptor
+from google.protobuf import descriptor_pool
+from google.protobuf import symbol_database
 from google.protobuf import text_format
 
 
@@ -48,44 +58,31 @@
 """
 
 
-class DescriptorTest(basetest.TestCase):
+class DescriptorTest(unittest.TestCase):
 
   def setUp(self):
-    self.my_file = descriptor.FileDescriptor(
+    file_proto = descriptor_pb2.FileDescriptorProto(
         name='some/filename/some.proto',
-        package='protobuf_unittest'
-        )
-    self.my_enum = descriptor.EnumDescriptor(
-        name='ForeignEnum',
-        full_name='protobuf_unittest.ForeignEnum',
-        filename=None,
-        file=self.my_file,
-        values=[
-          descriptor.EnumValueDescriptor(name='FOREIGN_FOO', index=0, number=4),
-          descriptor.EnumValueDescriptor(name='FOREIGN_BAR', index=1, number=5),
-          descriptor.EnumValueDescriptor(name='FOREIGN_BAZ', index=2, number=6),
-        ])
-    self.my_message = descriptor.Descriptor(
-        name='NestedMessage',
-        full_name='protobuf_unittest.TestAllTypes.NestedMessage',
-        filename=None,
-        file=self.my_file,
-        containing_type=None,
-        fields=[
-          descriptor.FieldDescriptor(
-            name='bb',
-            full_name='protobuf_unittest.TestAllTypes.NestedMessage.bb',
-            index=0, number=1,
-            type=5, cpp_type=1, label=1,
-            has_default_value=False, default_value=0,
-            message_type=None, enum_type=None, containing_type=None,
-            is_extension=False, extension_scope=None),
-        ],
-        nested_types=[],
-        enum_types=[
-          self.my_enum,
-        ],
-        extensions=[])
+        package='protobuf_unittest')
+    message_proto = file_proto.message_type.add(
+        name='NestedMessage')
+    message_proto.field.add(
+        name='bb',
+        number=1,
+        type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32,
+        label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL)
+    enum_proto = message_proto.enum_type.add(
+        name='ForeignEnum')
+    enum_proto.value.add(name='FOREIGN_FOO', number=4)
+    enum_proto.value.add(name='FOREIGN_BAR', number=5)
+    enum_proto.value.add(name='FOREIGN_BAZ', number=6)
+
+    self.pool = self.GetDescriptorPool()
+    self.pool.Add(file_proto)
+    self.my_file = self.pool.FindFileByName(file_proto.name)
+    self.my_message = self.my_file.message_types_by_name[message_proto.name]
+    self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
+
     self.my_method = descriptor.MethodDescriptor(
         name='Bar',
         full_name='protobuf_unittest.TestService.Bar',
@@ -102,6 +99,9 @@
             self.my_method
         ])
 
+  def GetDescriptorPool(self):
+    return symbol_database.Default().pool
+
   def testEnumValueName(self):
     self.assertEqual(self.my_message.EnumValueName('ForeignEnum', 4),
                      'FOREIGN_FOO')
@@ -173,6 +173,11 @@
     self.assertEqual(unittest_custom_options_pb2.METHODOPT1_VAL2,
                      method_options.Extensions[method_opt1])
 
+    message_descriptor = (
+        unittest_custom_options_pb2.DummyMessageContainingEnum.DESCRIPTOR)
+    self.assertTrue(file_descriptor.has_options)
+    self.assertFalse(message_descriptor.has_options)
+
   def testDifferentCustomOptionTypes(self):
     kint32min = -2**31
     kint64min = -2**63
@@ -393,9 +398,130 @@
   def testFileDescriptor(self):
     self.assertEqual(self.my_file.name, 'some/filename/some.proto')
     self.assertEqual(self.my_file.package, 'protobuf_unittest')
+    self.assertEqual(self.my_file.pool, self.pool)
+    # Generated modules also belong to the default pool.
+    self.assertEqual(unittest_pb2.DESCRIPTOR.pool, descriptor_pool.Default())
+
+  @unittest.skipIf(
+      api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
+      'Immutability of descriptors is only enforced in v2 implementation')
+  def testImmutableCppDescriptor(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    with self.assertRaises(AttributeError):
+      message_descriptor.fields_by_name = None
+    with self.assertRaises(TypeError):
+      message_descriptor.fields_by_name['Another'] = None
+    with self.assertRaises(TypeError):
+      message_descriptor.fields.append(None)
 
 
-class DescriptorCopyToProtoTest(basetest.TestCase):
+class NewDescriptorTest(DescriptorTest):
+  """Redo the same tests as above, but with a separate DescriptorPool."""
+
+  def GetDescriptorPool(self):
+    return descriptor_pool.DescriptorPool()
+
+
+class GeneratedDescriptorTest(unittest.TestCase):
+  """Tests for the properties of descriptors in generated code."""
+
+  def CheckMessageDescriptor(self, message_descriptor):
+    # Basic properties
+    self.assertEqual(message_descriptor.name, 'TestAllTypes')
+    self.assertEqual(message_descriptor.full_name,
+                     'protobuf_unittest.TestAllTypes')
+    # Test equality and hashability
+    self.assertEqual(message_descriptor, message_descriptor)
+    self.assertEqual(message_descriptor.fields[0].containing_type,
+                     message_descriptor)
+    self.assertIn(message_descriptor, [message_descriptor])
+    self.assertIn(message_descriptor, {message_descriptor: None})
+    # Test field containers
+    self.CheckDescriptorSequence(message_descriptor.fields)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_name)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_number)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_camelcase_name)
+
+  def CheckFieldDescriptor(self, field_descriptor):
+    # Basic properties
+    self.assertEqual(field_descriptor.name, 'optional_int32')
+    self.assertEqual(field_descriptor.camelcase_name, 'optionalInt32')
+    self.assertEqual(field_descriptor.full_name,
+                     'protobuf_unittest.TestAllTypes.optional_int32')
+    self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes')
+    # Test equality and hashability
+    self.assertEqual(field_descriptor, field_descriptor)
+    self.assertEqual(
+        field_descriptor.containing_type.fields_by_name['optional_int32'],
+        field_descriptor)
+    self.assertEqual(
+        field_descriptor.containing_type.fields_by_camelcase_name[
+            'optionalInt32'],
+        field_descriptor)
+    self.assertIn(field_descriptor, [field_descriptor])
+    self.assertIn(field_descriptor, {field_descriptor: None})
+
+  def CheckDescriptorSequence(self, sequence):
+    # Verifies that a property like 'messageDescriptor.fields' has all the
+    # properties of an immutable abc.Sequence.
+    self.assertGreater(len(sequence), 0)  # Sized
+    self.assertEqual(len(sequence), len(list(sequence)))  # Iterable
+    item = sequence[0]
+    self.assertEqual(item, sequence[0])
+    self.assertIn(item, sequence)  # Container
+    self.assertEqual(sequence.index(item), 0)
+    self.assertEqual(sequence.count(item), 1)
+    reversed_iterator = reversed(sequence)
+    self.assertEqual(list(reversed_iterator), list(sequence)[::-1])
+    self.assertRaises(StopIteration, next, reversed_iterator)
+
+  def CheckDescriptorMapping(self, mapping):
+    # Verifies that a property like 'messageDescriptor.fields' has all the
+    # properties of an immutable abc.Mapping.
+    self.assertGreater(len(mapping), 0)  # Sized
+    self.assertEqual(len(mapping), len(list(mapping)))  # Iterable
+    if sys.version_info >= (3,):
+      key, item = next(iter(mapping.items()))
+    else:
+      key, item = mapping.items()[0]
+    self.assertIn(key, mapping)  # Container
+    self.assertEqual(mapping.get(key), item)
+    # keys(), iterkeys() &co
+    item = (next(iter(mapping.keys())), next(iter(mapping.values())))
+    self.assertEqual(item, next(iter(mapping.items())))
+    if sys.version_info < (3,):
+      def CheckItems(seq, iterator):
+        self.assertEqual(next(iterator), seq[0])
+        self.assertEqual(list(iterator), seq[1:])
+      CheckItems(mapping.keys(), mapping.iterkeys())
+      CheckItems(mapping.values(), mapping.itervalues())
+      CheckItems(mapping.items(), mapping.iteritems())
+
+  def testDescriptor(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.CheckMessageDescriptor(message_descriptor)
+    field_descriptor = message_descriptor.fields_by_name['optional_int32']
+    self.CheckFieldDescriptor(field_descriptor)
+    field_descriptor = message_descriptor.fields_by_camelcase_name[
+        'optionalInt32']
+    self.CheckFieldDescriptor(field_descriptor)
+
+  def testCppDescriptorContainer(self):
+    # Check that the collection is still valid even if the parent disappeared.
+    enum = unittest_pb2.TestAllTypes.DESCRIPTOR.enum_types_by_name['NestedEnum']
+    values = enum.values
+    del enum
+    self.assertEqual('FOO', values[0].name)
+
+  def testCppDescriptorContainer_Iterator(self):
+    # Same test with the iterator
+    enum = unittest_pb2.TestAllTypes.DESCRIPTOR.enum_types_by_name['NestedEnum']
+    values_iter = iter(enum.values)
+    del enum
+    self.assertEqual('FOO', next(values_iter).name)
+
+
+class DescriptorCopyToProtoTest(unittest.TestCase):
   """Tests for CopyTo functions of Descriptor."""
 
   def _AssertProtoEqual(self, actual_proto, expected_class, expected_ascii):
@@ -471,7 +597,7 @@
       """
 
     self._InternalTestCopyToProto(
-        unittest_pb2._FOREIGNENUM,
+        unittest_pb2.ForeignEnum.DESCRIPTOR,
         descriptor_pb2.EnumDescriptorProto,
         TEST_FOREIGN_ENUM_ASCII)
 
@@ -588,13 +714,15 @@
         output_type: '.protobuf_unittest.BarResponse'
       >
       """
-    self._InternalTestCopyToProto(
-        unittest_pb2.TestService.DESCRIPTOR,
-        descriptor_pb2.ServiceDescriptorProto,
-        TEST_SERVICE_ASCII)
+    # TODO(rocking): enable this test after the proto descriptor change is
+    # checked in.
+    #self._InternalTestCopyToProto(
+    #    unittest_pb2.TestService.DESCRIPTOR,
+    #    descriptor_pb2.ServiceDescriptorProto,
+    #    TEST_SERVICE_ASCII)
 
 
-class MakeDescriptorTest(basetest.TestCase):
+class MakeDescriptorTest(unittest.TestCase):
 
   def testMakeDescriptorWithNestedFields(self):
     file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
@@ -665,5 +793,30 @@
                      descriptor.FieldDescriptor.CPPTYPE_UINT64)
 
 
+  def testMakeDescriptorWithOptions(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    aggregate_message = unittest_custom_options_pb2.AggregateMessage
+    aggregate_message.DESCRIPTOR.CopyToProto(descriptor_proto)
+    reformed_descriptor = descriptor.MakeDescriptor(descriptor_proto)
+
+    options = reformed_descriptor.GetOptions()
+    self.assertEqual(101,
+                      options.Extensions[unittest_custom_options_pb2.msgopt].i)
+
+  def testCamelcaseName(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    descriptor_proto.name = 'Bar'
+    names = ['foo_foo', 'FooBar', 'fooBaz', 'fooFoo', 'foobar']
+    camelcase_names = ['fooFoo', 'fooBar', 'fooBaz', 'fooFoo', 'foobar']
+    for index in range(len(names)):
+      field = descriptor_proto.field.add()
+      field.number = index + 1
+      field.name = names[index]
+    result = descriptor.MakeDescriptor(descriptor_proto)
+    for index in range(len(camelcase_names)):
+      self.assertEqual(result.fields[index].camelcase_name,
+                       camelcase_names[index])
+
+
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index 38a5138..48ef2df 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -28,10 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
-# Copyright 2009 Google Inc. All Rights Reserved.
-
 """Code for encoding protocol message primitives.
 
 Contains the logic for encoding every logical protocol field type
@@ -45,7 +41,7 @@
 sizer takes a value of this field's type and computes its byte size.  The
 encoder takes a writer function and a value.  It encodes the value into byte
 strings and invokes the writer function to write those strings.  Typically the
-writer function is the write() method of a cStringIO.
+writer function is the write() method of a BytesIO.
 
 We try to do as much work as possible when constructing the writer and the
 sizer rather than when calling them.  In particular:
@@ -71,8 +67,9 @@
 __author__ = 'kenton@google.com (Kenton Varda)'
 
 import struct
-import sys  ##PY25
-_PY2 = sys.version_info[0] < 3  ##PY25
+
+import six
+
 from google.protobuf.internal import wire_format
 
 
@@ -314,7 +311,7 @@
 
 
 # --------------------------------------------------------------------
-# MessageSet is special.
+# MessageSet is special: it needs custom logic to compute its size properly.
 
 
 def MessageSetItemSizer(field_number):
@@ -339,6 +336,32 @@
   return FieldSize
 
 
+# --------------------------------------------------------------------
+# Map is special: it needs custom logic to compute its size properly.
+
+
+def MapSizer(field_descriptor):
+  """Returns a sizer for a map field."""
+
+  # Can't look at field_descriptor.message_type._concrete_class because it may
+  # not have been initialized yet.
+  message_type = field_descriptor.message_type
+  message_sizer = MessageSizer(field_descriptor.number, False, False)
+
+  def FieldSize(map_value):
+    total = 0
+    for key in map_value:
+      value = map_value[key]
+      # It's wasteful to create the messages and throw them away one second
+      # later since we'll do the same for the actual encode.  But there's not an
+      # obvious way to avoid this within the current design without tons of code
+      # duplication.
+      entry_msg = message_type._concrete_class(key=key, value=value)
+      total += message_sizer(entry_msg)
+    return total
+
+  return FieldSize
+
 # ====================================================================
 # Encoders!
 
@@ -346,16 +369,14 @@
 def _VarintEncoder():
   """Return an encoder for a basic varint value (does not include tag)."""
 
-  local_chr = _PY2 and chr or (lambda x: bytes((x,)))  ##PY25
-##!PY25  local_chr = chr if bytes is str else lambda x: bytes((x,))
   def EncodeVarint(write, value):
     bits = value & 0x7f
     value >>= 7
     while value:
-      write(local_chr(0x80|bits))
+      write(six.int2byte(0x80|bits))
       bits = value & 0x7f
       value >>= 7
-    return write(local_chr(bits))
+    return write(six.int2byte(bits))
 
   return EncodeVarint
 
@@ -364,18 +385,16 @@
   """Return an encoder for a basic signed varint value (does not include
   tag)."""
 
-  local_chr = _PY2 and chr or (lambda x: bytes((x,)))  ##PY25
-##!PY25  local_chr = chr if bytes is str else lambda x: bytes((x,))
   def EncodeSignedVarint(write, value):
     if value < 0:
       value += (1 << 64)
     bits = value & 0x7f
     value >>= 7
     while value:
-      write(local_chr(0x80|bits))
+      write(six.int2byte(0x80|bits))
       bits = value & 0x7f
       value >>= 7
-    return write(local_chr(bits))
+    return write(six.int2byte(bits))
 
   return EncodeSignedVarint
 
@@ -390,8 +409,7 @@
 
   pieces = []
   _EncodeVarint(pieces.append, value)
-  return "".encode("latin1").join(pieces)  ##PY25
-##!PY25  return b"".join(pieces)
+  return b"".join(pieces)
 
 
 def TagBytes(field_number, wire_type):
@@ -529,33 +547,26 @@
       format:  The format string to pass to struct.pack().
   """
 
-  b = _PY2 and (lambda x:x) or (lambda x:x.encode('latin1'))  ##PY25
   value_size = struct.calcsize(format)
   if value_size == 4:
     def EncodeNonFiniteOrRaise(write, value):
       # Remember that the serialized form uses little-endian byte order.
       if value == _POS_INF:
-        write(b('\x00\x00\x80\x7F'))  ##PY25
-##!PY25        write(b'\x00\x00\x80\x7F')
+        write(b'\x00\x00\x80\x7F')
       elif value == _NEG_INF:
-        write(b('\x00\x00\x80\xFF'))  ##PY25
-##!PY25        write(b'\x00\x00\x80\xFF')
+        write(b'\x00\x00\x80\xFF')
       elif value != value:           # NaN
-        write(b('\x00\x00\xC0\x7F'))  ##PY25
-##!PY25        write(b'\x00\x00\xC0\x7F')
+        write(b'\x00\x00\xC0\x7F')
       else:
         raise
   elif value_size == 8:
     def EncodeNonFiniteOrRaise(write, value):
       if value == _POS_INF:
-        write(b('\x00\x00\x00\x00\x00\x00\xF0\x7F'))  ##PY25
-##!PY25        write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F')
+        write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F')
       elif value == _NEG_INF:
-        write(b('\x00\x00\x00\x00\x00\x00\xF0\xFF'))  ##PY25
-##!PY25        write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF')
+        write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF')
       elif value != value:                         # NaN
-        write(b('\x00\x00\x00\x00\x00\x00\xF8\x7F'))  ##PY25
-##!PY25        write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F')
+        write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F')
       else:
         raise
   else:
@@ -631,10 +642,8 @@
 def BoolEncoder(field_number, is_repeated, is_packed):
   """Returns an encoder for a boolean field."""
 
-##!PY25  false_byte = b'\x00'
-##!PY25  true_byte = b'\x01'
-  false_byte = '\x00'.encode('latin1')  ##PY25
-  true_byte = '\x01'.encode('latin1')  ##PY25
+  false_byte = b'\x00'
+  true_byte = b'\x01'
   if is_packed:
     tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
     local_EncodeVarint = _EncodeVarint
@@ -770,8 +779,7 @@
       }
     }
   """
-  start_bytes = "".encode("latin1").join([  ##PY25
-##!PY25  start_bytes = b"".join([
+  start_bytes = b"".join([
       TagBytes(1, wire_format.WIRETYPE_START_GROUP),
       TagBytes(2, wire_format.WIRETYPE_VARINT),
       _VarintBytes(field_number),
@@ -786,3 +794,30 @@
     return write(end_bytes)
 
   return EncodeField
+
+
+# --------------------------------------------------------------------
+# As before, Map is special.
+
+
+def MapEncoder(field_descriptor):
+  """Encoder for extensions of MessageSet.
+
+  Maps always have a wire format like this:
+    message MapEntry {
+      key_type key = 1;
+      value_type value = 2;
+    }
+    repeated MapEntry map = N;
+  """
+  # Can't look at field_descriptor.message_type._concrete_class because it may
+  # not have been initialized yet.
+  message_type = field_descriptor.message_type
+  encode_message = MessageEncoder(field_descriptor.number, False, False)
+
+  def EncodeField(write, value):
+    for key in value:
+      entry_msg = message_type._concrete_class(key=key, value=value[key])
+      encode_message(write, entry_msg)
+
+  return EncodeField
diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto
index 9f5a391..d2fbbee 100644
--- a/python/google/protobuf/internal/factory_test1.proto
+++ b/python/google/protobuf/internal/factory_test1.proto
@@ -30,6 +30,7 @@
 
 // Author: matthewtoia@google.com (Matt Toia)
 
+syntax = "proto2";
 
 package google.protobuf.python.internal;
 
diff --git a/python/google/protobuf/internal/factory_test2.proto b/python/google/protobuf/internal/factory_test2.proto
index 27feb6c..bb1b54a 100644
--- a/python/google/protobuf/internal/factory_test2.proto
+++ b/python/google/protobuf/internal/factory_test2.proto
@@ -30,6 +30,7 @@
 
 // Author: matthewtoia@google.com (Matt Toia)
 
+syntax = "proto2";
 
 package google.protobuf.python.internal;
 
@@ -87,6 +88,12 @@
   optional Factory2Message loop = 1;
 }
 
+message MessageWithNestedEnumOnly {
+  enum NestedEnum {
+    NESTED_MESSAGE_ENUM_0 = 0;
+  }
+}
+
 extend Factory1Message {
   optional string another_field = 1002;
 }
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
index 422fa9a..83ea5f5 100755
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -35,18 +35,23 @@
 # indirect testing of the protocol compiler output.
 
 """Unittest that directly tests the output of the pure-Python protocol
-compiler.  See //google/protobuf/reflection_test.py for a test which
+compiler.  See //google/protobuf/internal/reflection_test.py for a test which
 further ensures that we can use Python protocol message objects as we expect.
 """
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf.internal import test_bad_identifiers_pb2
 from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_import_public_pb2
 from google.protobuf import unittest_mset_pb2
+from google.protobuf import unittest_mset_wire_format_pb2
 from google.protobuf import unittest_no_generic_services_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import service
@@ -55,7 +60,7 @@
 MAX_EXTENSION = 536870912
 
 
-class GeneratorTest(basetest.TestCase):
+class GeneratorTest(unittest.TestCase):
 
   def testNestedMessageDescriptor(self):
     field_name = 'optional_nested_message'
@@ -142,18 +147,18 @@
     self.assertTrue(not non_extension_descriptor.is_extension)
 
   def testOptions(self):
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = unittest_mset_wire_format_pb2.TestMessageSet()
     self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
 
   def testMessageWithCustomOptions(self):
     proto = unittest_custom_options_pb2.TestMessageWithCustomOptions()
     enum_options = proto.DESCRIPTOR.enum_types_by_name['AnEnum'].GetOptions()
     self.assertTrue(enum_options is not None)
-    # TODO(gps): We really should test for the presense of the enum_opt1
+    # TODO(gps): We really should test for the presence of the enum_opt1
     # extension and for its value to be set to -789.
 
   def testNestedTypes(self):
-    self.assertEquals(
+    self.assertEqual(
         set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types),
         set([
             unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR,
@@ -291,53 +296,53 @@
     self.assertIs(desc.oneofs[0], desc.oneofs_by_name['oneof_field'])
     nested_names = set(['oneof_uint32', 'oneof_nested_message',
                         'oneof_string', 'oneof_bytes'])
-    self.assertSameElements(
+    self.assertEqual(
         nested_names,
-        [field.name for field in desc.oneofs[0].fields])
-    for field_name, field_desc in desc.fields_by_name.iteritems():
+        set([field.name for field in desc.oneofs[0].fields]))
+    for field_name, field_desc in desc.fields_by_name.items():
       if field_name in nested_names:
         self.assertIs(desc.oneofs[0], field_desc.containing_oneof)
       else:
         self.assertIsNone(field_desc.containing_oneof)
 
 
-class SymbolDatabaseRegistrationTest(basetest.TestCase):
+class SymbolDatabaseRegistrationTest(unittest.TestCase):
   """Checks that messages, enums and files are correctly registered."""
 
   def testGetSymbol(self):
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes, symbol_database.Default().GetSymbol(
             'protobuf_unittest.TestAllTypes'))
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.NestedMessage,
         symbol_database.Default().GetSymbol(
             'protobuf_unittest.TestAllTypes.NestedMessage'))
     with self.assertRaises(KeyError):
       symbol_database.Default().GetSymbol('protobuf_unittest.NestedMessage')
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.OptionalGroup,
         symbol_database.Default().GetSymbol(
             'protobuf_unittest.TestAllTypes.OptionalGroup'))
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.RepeatedGroup,
         symbol_database.Default().GetSymbol(
             'protobuf_unittest.TestAllTypes.RepeatedGroup'))
 
   def testEnums(self):
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.ForeignEnum',
         symbol_database.Default().pool.FindEnumTypeByName(
             'protobuf_unittest.ForeignEnum').full_name)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes.NestedEnum',
         symbol_database.Default().pool.FindEnumTypeByName(
             'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
 
   def testFindFileByName(self):
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         symbol_database.Default().pool.FindFileByName(
             'google/protobuf/unittest.proto').name)
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/import_test_package/__init__.py b/python/google/protobuf/internal/import_test_package/__init__.py
new file mode 100644
index 0000000..5121dd0
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/__init__.py
@@ -0,0 +1,33 @@
+# 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.
+
+"""Sample module importing a nested proto from itself."""
+
+from google.protobuf.internal.import_test_package import outer_pb2 as myproto
diff --git a/python/google/protobuf/internal/import_test_package/inner.proto b/python/google/protobuf/internal/import_test_package/inner.proto
new file mode 100644
index 0000000..2887c12
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/inner.proto
@@ -0,0 +1,37 @@
+// 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.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+message Inner {
+  optional int32 value = 1 [default = 57];
+}
diff --git a/python/google/protobuf/internal/import_test_package/outer.proto b/python/google/protobuf/internal/import_test_package/outer.proto
new file mode 100644
index 0000000..a27fb5c
--- /dev/null
+++ b/python/google/protobuf/internal/import_test_package/outer.proto
@@ -0,0 +1,39 @@
+// 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.
+
+syntax = "proto2";
+
+package google.protobuf.python.internal.import_test_package;
+
+import "google/protobuf/internal/import_test_package/inner.proto";
+
+message Outer {
+  optional Inner inner = 1;
+}
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
new file mode 100644
index 0000000..bdc9f49
--- /dev/null
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -0,0 +1,769 @@
+#! /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.
+
+"""Test for google.protobuf.json_format."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import json
+import math
+import sys
+
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
+from google.protobuf import any_pb2
+from google.protobuf import duration_pb2
+from google.protobuf import field_mask_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import timestamp_pb2
+from google.protobuf import wrappers_pb2
+from google.protobuf.internal import well_known_types
+from google.protobuf import json_format
+from google.protobuf.util import json_format_proto3_pb2
+
+
+class JsonFormatBase(unittest.TestCase):
+
+  def FillAllFields(self, message):
+    message.int32_value = 20
+    message.int64_value = -20
+    message.uint32_value = 3120987654
+    message.uint64_value = 12345678900
+    message.float_value = float('-inf')
+    message.double_value = 3.1415
+    message.bool_value = True
+    message.string_value = 'foo'
+    message.bytes_value = b'bar'
+    message.message_value.value = 10
+    message.enum_value = json_format_proto3_pb2.BAR
+    # Repeated
+    message.repeated_int32_value.append(0x7FFFFFFF)
+    message.repeated_int32_value.append(-2147483648)
+    message.repeated_int64_value.append(9007199254740992)
+    message.repeated_int64_value.append(-9007199254740992)
+    message.repeated_uint32_value.append(0xFFFFFFF)
+    message.repeated_uint32_value.append(0x7FFFFFF)
+    message.repeated_uint64_value.append(9007199254740992)
+    message.repeated_uint64_value.append(9007199254740991)
+    message.repeated_float_value.append(0)
+
+    message.repeated_double_value.append(1E-15)
+    message.repeated_double_value.append(float('inf'))
+    message.repeated_bool_value.append(True)
+    message.repeated_bool_value.append(False)
+    message.repeated_string_value.append('Few symbols!#$,;')
+    message.repeated_string_value.append('bar')
+    message.repeated_bytes_value.append(b'foo')
+    message.repeated_bytes_value.append(b'bar')
+    message.repeated_message_value.add().value = 10
+    message.repeated_message_value.add().value = 11
+    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
+    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
+    self.message = message
+
+  def CheckParseBack(self, message, parsed_message):
+    json_format.Parse(json_format.MessageToJson(message),
+                      parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def CheckError(self, text, error_message):
+    message = json_format_proto3_pb2.TestMessage()
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        error_message,
+        json_format.Parse, text, message)
+
+
+class JsonFormatTest(JsonFormatBase):
+
+  def testEmptyMessageToJson(self):
+    message = json_format_proto3_pb2.TestMessage()
+    self.assertEqual(json_format.MessageToJson(message),
+                     '{}')
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testPartialMessageToJson(self):
+    message = json_format_proto3_pb2.TestMessage(
+        string_value='test',
+        repeated_int32_value=[89, 4])
+    self.assertEqual(json.loads(json_format.MessageToJson(message)),
+                     json.loads('{"stringValue": "test", '
+                                '"repeatedInt32Value": [89, 4]}'))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testAllFieldsToJson(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = ('{"int32Value": 20, '
+            '"int64Value": "-20", '
+            '"uint32Value": 3120987654,'
+            '"uint64Value": "12345678900",'
+            '"floatValue": "-Infinity",'
+            '"doubleValue": 3.1415,'
+            '"boolValue": true,'
+            '"stringValue": "foo",'
+            '"bytesValue": "YmFy",'
+            '"messageValue": {"value": 10},'
+            '"enumValue": "BAR",'
+            '"repeatedInt32Value": [2147483647, -2147483648],'
+            '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
+            '"repeatedUint32Value": [268435455, 134217727],'
+            '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
+            '"repeatedFloatValue": [0],'
+            '"repeatedDoubleValue": [1e-15, "Infinity"],'
+            '"repeatedBoolValue": [true, false],'
+            '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
+            '"repeatedBytesValue": ["Zm9v", "YmFy"],'
+            '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
+            '"repeatedEnumValue": ["FOO", "BAR"]'
+            '}')
+    self.FillAllFields(message)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message)),
+        json.loads(text))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testJsonEscapeString(self):
+    message = json_format_proto3_pb2.TestMessage()
+    if sys.version_info[0] < 3:
+      message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
+    else:
+      message.string_value = '&\n<\"\r>\b\t\f\\\001/'
+      message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
+    self.assertEqual(
+        json_format.MessageToJson(message),
+        '{\n  "stringValue": '
+        '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+    text = u'{"int32Value": "\u0031"}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.int32_value, 1)
+
+  def testAlwaysSeriliaze(self):
+    message = json_format_proto3_pb2.TestMessage(
+        string_value='foo')
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"repeatedStringValue": [],'
+                   '"stringValue": "foo",'
+                   '"repeatedBoolValue": [],'
+                   '"repeatedUint32Value": [],'
+                   '"repeatedInt32Value": [],'
+                   '"enumValue": "FOO",'
+                   '"int32Value": 0,'
+                   '"floatValue": 0,'
+                   '"int64Value": "0",'
+                   '"uint32Value": 0,'
+                   '"repeatedBytesValue": [],'
+                   '"repeatedUint64Value": [],'
+                   '"repeatedDoubleValue": [],'
+                   '"bytesValue": "",'
+                   '"boolValue": false,'
+                   '"repeatedEnumValue": [],'
+                   '"uint64Value": "0",'
+                   '"doubleValue": 0,'
+                   '"repeatedFloatValue": [],'
+                   '"repeatedInt64Value": [],'
+                   '"repeatedMessageValue": []}'))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testMapFields(self):
+    message = json_format_proto3_pb2.TestMap()
+    message.bool_map[True] = 1
+    message.bool_map[False] = 2
+    message.int32_map[1] = 2
+    message.int32_map[2] = 3
+    message.int64_map[1] = 2
+    message.int64_map[2] = 3
+    message.uint32_map[1] = 2
+    message.uint32_map[2] = 3
+    message.uint64_map[1] = 2
+    message.uint64_map[2] = 3
+    message.string_map['1'] = 2
+    message.string_map['null'] = 3
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"boolMap": {"false": 2, "true": 1},'
+                   '"int32Map": {"1": 2, "2": 3},'
+                   '"int64Map": {"1": 2, "2": 3},'
+                   '"uint32Map": {"1": 2, "2": 3},'
+                   '"uint64Map": {"1": 2, "2": 3},'
+                   '"stringMap": {"1": 2, "null": 3}'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestMap()
+    self.CheckParseBack(message, parsed_message)
+
+  def testOneofFields(self):
+    message = json_format_proto3_pb2.TestOneof()
+    # Always print does not affect oneof fields.
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{}')
+    message.oneof_int32_value = 0
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "oneofInt32Value": 0\n'
+        '}')
+    parsed_message = json_format_proto3_pb2.TestOneof()
+    self.CheckParseBack(message, parsed_message)
+
+  def testTimestampMessage(self):
+    message = json_format_proto3_pb2.TestTimestamp()
+    message.value.seconds = 0
+    message.value.nanos = 0
+    message.repeated_value.add().seconds = 20
+    message.repeated_value[0].nanos = 1
+    message.repeated_value.add().seconds = 0
+    message.repeated_value[1].nanos = 10000
+    message.repeated_value.add().seconds = 100000000
+    message.repeated_value[2].nanos = 0
+    # Maximum time
+    message.repeated_value.add().seconds = 253402300799
+    message.repeated_value[3].nanos = 999999999
+    # Minimum time
+    message.repeated_value.add().seconds = -62135596800
+    message.repeated_value[4].nanos = 0
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"value": "1970-01-01T00:00:00Z",'
+                   '"repeatedValue": ['
+                   '  "1970-01-01T00:00:20.000000001Z",'
+                   '  "1970-01-01T00:00:00.000010Z",'
+                   '  "1973-03-03T09:46:40Z",'
+                   '  "9999-12-31T23:59:59.999999999Z",'
+                   '  "0001-01-01T00:00:00Z"'
+                   ']'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestTimestamp()
+    self.CheckParseBack(message, parsed_message)
+    text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
+            r'"repeatedValue":['
+            r'  "1970-01-01T00:00:00.01+08:30",'
+            r'  "1970-01-01T00:00:00.01-01:23"]}')
+    json_format.Parse(text, parsed_message)
+    self.assertEqual(parsed_message.value.seconds, -8 * 3600)
+    self.assertEqual(parsed_message.value.nanos, 10000000)
+    self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
+    self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
+
+  def testDurationMessage(self):
+    message = json_format_proto3_pb2.TestDuration()
+    message.value.seconds = 1
+    message.repeated_value.add().seconds = 0
+    message.repeated_value[0].nanos = 10
+    message.repeated_value.add().seconds = -1
+    message.repeated_value[1].nanos = -1000
+    message.repeated_value.add().seconds = 10
+    message.repeated_value[2].nanos = 11000000
+    message.repeated_value.add().seconds = -315576000000
+    message.repeated_value.add().seconds = 315576000000
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"value": "1s",'
+                   '"repeatedValue": ['
+                   '  "0.000000010s",'
+                   '  "-1.000001s",'
+                   '  "10.011s",'
+                   '  "-315576000000s",'
+                   '  "315576000000s"'
+                   ']'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestDuration()
+    self.CheckParseBack(message, parsed_message)
+
+  def testFieldMaskMessage(self):
+    message = json_format_proto3_pb2.TestFieldMask()
+    message.value.paths.append('foo.bar')
+    message.value.paths.append('bar')
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "value": "foo.bar,bar"\n'
+        '}')
+    parsed_message = json_format_proto3_pb2.TestFieldMask()
+    self.CheckParseBack(message, parsed_message)
+
+  def testWrapperMessage(self):
+    message = json_format_proto3_pb2.TestWrapper()
+    message.bool_value.value = False
+    message.int32_value.value = 0
+    message.string_value.value = ''
+    message.bytes_value.value = b''
+    message.repeated_bool_value.add().value = True
+    message.repeated_bool_value.add().value = False
+    message.repeated_int32_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{\n'
+                   '  "int32Value": 0,'
+                   '  "boolValue": false,'
+                   '  "stringValue": "",'
+                   '  "bytesValue": "",'
+                   '  "repeatedBoolValue": [true, false],'
+                   '  "repeatedInt32Value": [0],'
+                   '  "repeatedUint32Value": [],'
+                   '  "repeatedFloatValue": [],'
+                   '  "repeatedDoubleValue": [],'
+                   '  "repeatedBytesValue": [],'
+                   '  "repeatedInt64Value": [],'
+                   '  "repeatedUint64Value": [],'
+                   '  "repeatedStringValue": []'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestWrapper()
+    self.CheckParseBack(message, parsed_message)
+
+  def testStructMessage(self):
+    message = json_format_proto3_pb2.TestStruct()
+    message.value['name'] = 'Jim'
+    message.value['age'] = 10
+    message.value['attend'] = True
+    message.value['email'] = None
+    message.value.get_or_create_struct('address')['city'] = 'SFO'
+    message.value['address']['house_number'] = 1024
+    struct_list = message.value.get_or_create_list('list')
+    struct_list.extend([6, 'seven', True, False, None])
+    struct_list.add_struct()['subkey2'] = 9
+    message.repeated_value.add()['age'] = 11
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": {'
+            '    "address": {'
+            '      "city": "SFO", '
+            '      "house_number": 1024'
+            '    }, '
+            '    "age": 10, '
+            '    "name": "Jim", '
+            '    "attend": true, '
+            '    "email": null, '
+            '    "list": [6, "seven", true, false, null, {"subkey2": 9}]'
+            '  },'
+            '  "repeatedValue": [{"age": 11}, {}]'
+            '}'))
+    parsed_message = json_format_proto3_pb2.TestStruct()
+    self.CheckParseBack(message, parsed_message)
+
+  def testValueMessage(self):
+    message = json_format_proto3_pb2.TestValue()
+    message.value.string_value = 'hello'
+    message.repeated_value.add().number_value = 11.1
+    message.repeated_value.add().bool_value = False
+    message.repeated_value.add().null_value = 0
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": "hello",'
+            '  "repeatedValue": [11.1, false, null]'
+            '}'))
+    parsed_message = json_format_proto3_pb2.TestValue()
+    self.CheckParseBack(message, parsed_message)
+    # Can't parse back if the Value message is not set.
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": "hello",'
+            '  "repeatedValue": [11.1, false, null, null]'
+            '}'))
+
+  def testListValueMessage(self):
+    message = json_format_proto3_pb2.TestListValue()
+    message.value.values.add().number_value = 11.1
+    message.value.values.add().null_value = 0
+    message.value.values.add().bool_value = True
+    message.value.values.add().string_value = 'hello'
+    message.value.values.add().struct_value['name'] = 'Jim'
+    message.repeated_value.add().values.add().number_value = 1
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
+            '"repeatedValue": [[1], []]}'))
+    parsed_message = json_format_proto3_pb2.TestListValue()
+    self.CheckParseBack(message, parsed_message)
+
+  def testAnyMessage(self):
+    message = json_format_proto3_pb2.TestAny()
+    value1 = json_format_proto3_pb2.MessageType()
+    value2 = json_format_proto3_pb2.MessageType()
+    value1.value = 1234
+    value2.value = 5678
+    message.value.Pack(value1)
+    message.repeated_value.add().Pack(value1)
+    message.repeated_value.add().Pack(value2)
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "repeatedValue": [ {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 1234\n'
+            '  }, {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 5678\n'
+            '  },\n'
+            '  {}],\n'
+            '  "value": {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 1234\n'
+            '  }\n'
+            '}\n'))
+    parsed_message = json_format_proto3_pb2.TestAny()
+    self.CheckParseBack(message, parsed_message)
+
+  def testWellKnownInAnyMessage(self):
+    message = any_pb2.Any()
+    int32_value = wrappers_pb2.Int32Value()
+    int32_value.value = 1234
+    message.Pack(int32_value)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
+            '  "value": 1234\n'
+            '}\n'))
+    parsed_message = any_pb2.Any()
+    self.CheckParseBack(message, parsed_message)
+
+    timestamp = timestamp_pb2.Timestamp()
+    message.Pack(timestamp)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
+            '  "value": "1970-01-01T00:00:00Z"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    duration = duration_pb2.Duration()
+    duration.seconds = 1
+    message.Pack(duration)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Duration",\n'
+            '  "value": "1s"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    field_mask = field_mask_pb2.FieldMask()
+    field_mask.paths.append('foo.bar')
+    field_mask.paths.append('bar')
+    message.Pack(field_mask)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
+            '  "value": "foo.bar,bar"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    struct_message = struct_pb2.Struct()
+    struct_message['name'] = 'Jim'
+    message.Pack(struct_message)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Struct",\n'
+            '  "value": {"name": "Jim"}\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    nested_any = any_pb2.Any()
+    int32_value.value = 5678
+    nested_any.Pack(int32_value)
+    message.Pack(nested_any)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Any",\n'
+            '  "value": {\n'
+            '    "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
+            '    "value": 5678\n'
+            '  }\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+  def testParseNull(self):
+    message = json_format_proto3_pb2.TestMessage()
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.FillAllFields(parsed_message)
+    json_format.Parse('{"int32Value": null, '
+                      '"int64Value": null, '
+                      '"uint32Value": null,'
+                      '"uint64Value": null,'
+                      '"floatValue": null,'
+                      '"doubleValue": null,'
+                      '"boolValue": null,'
+                      '"stringValue": null,'
+                      '"bytesValue": null,'
+                      '"messageValue": null,'
+                      '"enumValue": null,'
+                      '"repeatedInt32Value": null,'
+                      '"repeatedInt64Value": null,'
+                      '"repeatedUint32Value": null,'
+                      '"repeatedUint64Value": null,'
+                      '"repeatedFloatValue": null,'
+                      '"repeatedDoubleValue": null,'
+                      '"repeatedBoolValue": null,'
+                      '"repeatedStringValue": null,'
+                      '"repeatedBytesValue": null,'
+                      '"repeatedMessageValue": null,'
+                      '"repeatedEnumValue": null'
+                      '}',
+                      parsed_message)
+    self.assertEqual(message, parsed_message)
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse repeatedInt32Value field: '
+        'null is not allowed to be used as an element in a repeated field.',
+        json_format.Parse,
+        '{"repeatedInt32Value":[1, null]}',
+        parsed_message)
+
+  def testNanFloat(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.float_value = float('nan')
+    text = '{\n  "floatValue": "NaN"\n}'
+    self.assertEqual(json_format.MessageToJson(message), text)
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message)
+    self.assertTrue(math.isnan(parsed_message.float_value))
+
+  def testParseEmptyText(self):
+    self.CheckError('',
+                    r'Failed to load JSON: (Expecting value)|(No JSON).')
+
+  def testParseBadEnumValue(self):
+    self.CheckError(
+        '{"enumValue": 1}',
+        'Enum value must be a string literal with double quotes. '
+        'Type "proto3.EnumType" has no value named 1.')
+    self.CheckError(
+        '{"enumValue": "baz"}',
+        'Enum value must be a string literal with double quotes. '
+        'Type "proto3.EnumType" has no value named baz.')
+
+  def testParseBadIdentifer(self):
+    self.CheckError('{int32Value: 1}',
+                    (r'Failed to load JSON: Expecting property name'
+                     r'( enclosed in double quotes)?: line 1'))
+    self.CheckError('{"unknownName": 1}',
+                    'Message type "proto3.TestMessage" has no field named '
+                    '"unknownName".')
+
+  def testDuplicateField(self):
+    # Duplicate key check is not supported for python2.6
+    if sys.version_info < (2, 7):
+      return
+    self.CheckError('{"int32Value": 1,\n"int32Value":2}',
+                    'Failed to load JSON: duplicate key int32Value.')
+
+  def testInvalidBoolValue(self):
+    self.CheckError('{"boolValue": 1}',
+                    'Failed to parse boolValue field: '
+                    'Expected true or false without quotes.')
+    self.CheckError('{"boolValue": "true"}',
+                    'Failed to parse boolValue field: '
+                    'Expected true or false without quotes.')
+
+  def testInvalidIntegerValue(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = '{"int32Value": 0x12345}'
+    self.assertRaises(json_format.ParseError,
+                      json_format.Parse, text, message)
+    self.CheckError('{"int32Value": 012345}',
+                    (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
+                     r'line 1.'))
+    self.CheckError('{"int32Value": 1.0}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: 1.0.')
+    self.CheckError('{"int32Value": " 1 "}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: " 1 ".')
+    self.CheckError('{"int32Value": "1 "}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: "1 ".')
+    self.CheckError('{"int32Value": 12345678901234567890}',
+                    'Failed to parse int32Value field: Value out of range: '
+                    '12345678901234567890.')
+    self.CheckError('{"int32Value": 1e5}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: 100000.0.')
+    self.CheckError('{"uint32Value": -1}',
+                    'Failed to parse uint32Value field: '
+                    'Value out of range: -1.')
+
+  def testInvalidFloatValue(self):
+    self.CheckError('{"floatValue": "nan"}',
+                    'Failed to parse floatValue field: Couldn\'t '
+                    'parse float "nan", use "NaN" instead.')
+
+  def testInvalidBytesValue(self):
+    self.CheckError('{"bytesValue": "AQI"}',
+                    'Failed to parse bytesValue field: Incorrect padding.')
+    self.CheckError('{"bytesValue": "AQI*"}',
+                    'Failed to parse bytesValue field: Incorrect padding.')
+
+  def testInvalidMap(self):
+    message = json_format_proto3_pb2.TestMap()
+    text = '{"int32Map": {"null": 2, "2": 3}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse int32Map field: invalid literal',
+        json_format.Parse, text, message)
+    text = '{"int32Map": {1: 2, "2": 3}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        (r'Failed to load JSON: Expecting property name'
+         r'( enclosed in double quotes)?: line 1'),
+        json_format.Parse, text, message)
+    text = '{"boolMap": {"null": 1}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse boolMap field: Expected "true" or "false", not null.',
+        json_format.Parse, text, message)
+    if sys.version_info < (2, 7):
+      return
+    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to load JSON: duplicate key a',
+        json_format.Parse, text, message)
+
+  def testInvalidTimestamp(self):
+    message = json_format_proto3_pb2.TestTimestamp()
+    text = '{"value": "10000-01-01T00:00:00.00Z"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'time data \'10000-01-01T00:00:00\' does not match'
+        ' format \'%Y-%m-%dT%H:%M:%S\'.',
+        json_format.Parse, text, message)
+    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'nanos 0123456789012 more than 9 fractional digits.',
+        json_format.Parse, text, message)
+    text = '{"value": "1972-01-01T01:00:00.01+08"}'
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        (r'Invalid timezone offset value: \+08.'),
+        json_format.Parse, text, message)
+    # Time smaller than minimum time.
+    text = '{"value": "0000-01-01T00:00:00Z"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse value field: year is out of range.',
+        json_format.Parse, text, message)
+    # Time bigger than maxinum time.
+    message.value.seconds = 253402300800
+    self.assertRaisesRegexp(
+        OverflowError,
+        'date value out of range',
+        json_format.MessageToJson, message)
+
+  def testInvalidOneof(self):
+    message = json_format_proto3_pb2.TestOneof()
+    text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Message type "proto3.TestOneof"'
+        ' should not have multiple "oneof_value" oneof fields.',
+        json_format.Parse, text, message)
+
+  def testInvalidListValue(self):
+    message = json_format_proto3_pb2.TestListValue()
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        r'Failed to parse value field: ListValue must be in \[\] which is 1234',
+        json_format.Parse, text, message)
+
+  def testInvalidStruct(self):
+    message = json_format_proto3_pb2.TestStruct()
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse value field: Struct must be in a dict which is 1234',
+        json_format.Parse, text, message)
+
+  def testInvalidAny(self):
+    message = any_pb2.Any()
+    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
+    self.assertRaisesRegexp(
+        KeyError,
+        'value',
+        json_format.Parse, text, message)
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        '@type is missing when parsing any message.',
+        json_format.Parse, text, message)
+    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
+    self.assertRaisesRegexp(
+        TypeError,
+        'Can not find message descriptor by type_url: '
+        'type.googleapis.com/MessageNotExist.',
+        json_format.Parse, text, message)
+    # Only last part is to be used: b/25630112
+    text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
+            r'"value": 1234}')
+    json_format.Parse(text, message)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/message_factory_python_test.py b/python/google/protobuf/internal/message_factory_python_test.py
deleted file mode 100644
index 85e02b2..0000000
--- a/python/google/protobuf/internal/message_factory_python_test.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#! /usr/bin/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.
-
-"""Tests for ..public.message_factory for the pure Python implementation."""
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
-
-# We must set the implementation version above before the google3 imports.
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-# Run all tests from the original module by putting them in our namespace.
-# pylint: disable=wildcard-import
-from google.protobuf.internal.message_factory_test import *
-
-
-class ConfirmPurePythonTest(basetest.TestCase):
-
-  def testImplementationSetting(self):
-    self.assertEqual('python', api_implementation.Type())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index fcf1341..7bb7d1a 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,7 +34,11 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
@@ -43,7 +47,7 @@
 from google.protobuf import message_factory
 
 
-class MessageFactoryTest(basetest.TestCase):
+class MessageFactoryTest(unittest.TestCase):
 
   def setUp(self):
     self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
@@ -81,9 +85,9 @@
     serialized = msg.SerializeToString()
     converted = factory_test2_pb2.Factory2Message.FromString(serialized)
     reserialized = converted.SerializeToString()
-    self.assertEquals(serialized, reserialized)
+    self.assertEqual(serialized, reserialized)
     result = cls.FromString(reserialized)
-    self.assertEquals(msg, result)
+    self.assertEqual(msg, result)
 
   def testGetPrototype(self):
     db = descriptor_database.DescriptorDatabase()
@@ -93,28 +97,29 @@
     factory = message_factory.MessageFactory()
     cls = factory.GetPrototype(pool.FindMessageTypeByName(
         'google.protobuf.python.internal.Factory2Message'))
-    self.assertIsNot(cls, factory_test2_pb2.Factory2Message)
+    self.assertFalse(cls is factory_test2_pb2.Factory2Message)
     self._ExerciseDynamicClass(cls)
     cls2 = factory.GetPrototype(pool.FindMessageTypeByName(
         'google.protobuf.python.internal.Factory2Message'))
-    self.assertIs(cls, cls2)
+    self.assertTrue(cls is cls2)
 
   def testGetMessages(self):
     # performed twice because multiple calls with the same input must be allowed
     for _ in range(2):
-      messages = message_factory.GetMessages([self.factory_test2_fd,
-                                              self.factory_test1_fd])
-      self.assertContainsSubset(
-          ['google.protobuf.python.internal.Factory2Message',
-           'google.protobuf.python.internal.Factory1Message'],
-          messages.keys())
+      messages = message_factory.GetMessages([self.factory_test1_fd,
+                                              self.factory_test2_fd])
+      self.assertTrue(
+          set(['google.protobuf.python.internal.Factory2Message',
+               'google.protobuf.python.internal.Factory1Message'],
+             ).issubset(set(messages.keys())))
       self._ExerciseDynamicClass(
           messages['google.protobuf.python.internal.Factory2Message'])
-      self.assertContainsSubset(
-          ['google.protobuf.python.internal.Factory2Message.one_more_field',
-           'google.protobuf.python.internal.another_field'],
-          (messages['google.protobuf.python.internal.Factory1Message']
-           ._extensions_by_name.keys()))
+      self.assertTrue(
+          set(['google.protobuf.python.internal.Factory2Message.one_more_field',
+               'google.protobuf.python.internal.another_field'],
+             ).issubset(
+                 set(messages['google.protobuf.python.internal.Factory1Message']
+                     ._extensions_by_name.keys())))
       factory_msg1 = messages['google.protobuf.python.internal.Factory1Message']
       msg1 = messages['google.protobuf.python.internal.Factory1Message']()
       ext1 = factory_msg1._extensions_by_name[
@@ -123,9 +128,63 @@
           'google.protobuf.python.internal.another_field']
       msg1.Extensions[ext1] = 'test1'
       msg1.Extensions[ext2] = 'test2'
-      self.assertEquals('test1', msg1.Extensions[ext1])
-      self.assertEquals('test2', msg1.Extensions[ext2])
+      self.assertEqual('test1', msg1.Extensions[ext1])
+      self.assertEqual('test2', msg1.Extensions[ext2])
+
+  def testDuplicateExtensionNumber(self):
+    pool = descriptor_pool.DescriptorPool()
+    factory = message_factory.MessageFactory(pool=pool)
+
+    # Add Container message.
+    f = descriptor_pb2.FileDescriptorProto()
+    f.name = 'google/protobuf/internal/container.proto'
+    f.package = 'google.protobuf.python.internal'
+    msg = f.message_type.add()
+    msg.name = 'Container'
+    rng = msg.extension_range.add()
+    rng.start = 1
+    rng.end = 10
+    pool.Add(f)
+    msgs = factory.GetMessages([f.name])
+    self.assertIn('google.protobuf.python.internal.Container', msgs)
+
+    # Extend container.
+    f = descriptor_pb2.FileDescriptorProto()
+    f.name = 'google/protobuf/internal/extension.proto'
+    f.package = 'google.protobuf.python.internal'
+    f.dependency.append('google/protobuf/internal/container.proto')
+    msg = f.message_type.add()
+    msg.name = 'Extension'
+    ext = msg.extension.add()
+    ext.name = 'extension_field'
+    ext.number = 2
+    ext.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+    ext.type_name = 'Extension'
+    ext.extendee = 'Container'
+    pool.Add(f)
+    msgs = factory.GetMessages([f.name])
+    self.assertIn('google.protobuf.python.internal.Extension', msgs)
+
+    # Add Duplicate extending the same field number.
+    f = descriptor_pb2.FileDescriptorProto()
+    f.name = 'google/protobuf/internal/duplicate.proto'
+    f.package = 'google.protobuf.python.internal'
+    f.dependency.append('google/protobuf/internal/container.proto')
+    msg = f.message_type.add()
+    msg.name = 'Duplicate'
+    ext = msg.extension.add()
+    ext.name = 'extension_field'
+    ext.number = 2
+    ext.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+    ext.type_name = 'Duplicate'
+    ext.extendee = 'Container'
+    pool.Add(f)
+
+    with self.assertRaises(Exception) as cm:
+      factory.GetMessages([f.name])
+
+    self.assertIsInstance(cm.exception, (AssertionError, ValueError))
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/message_python_test.py b/python/google/protobuf/internal/message_python_test.py
deleted file mode 100644
index c40623a..0000000
--- a/python/google/protobuf/internal/message_python_test.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#! /usr/bin/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.
-
-"""Tests for ..public.message for the pure Python implementation."""
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'
-
-# We must set the implementation version above before the google3 imports.
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-# Run all tests from the original module by putting them in our namespace.
-# pylint: disable=wildcard-import
-from google.protobuf.internal.message_test import *
-
-
-class ConfirmPurePythonTest(basetest.TestCase):
-
-  def testImplementationSetting(self):
-    self.assertEqual('python', api_implementation.Type())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/internal/message_set_extensions.proto b/python/google/protobuf/internal/message_set_extensions.proto
new file mode 100644
index 0000000..14e5f19
--- /dev/null
+++ b/python/google/protobuf/internal/message_set_extensions.proto
@@ -0,0 +1,74 @@
+// 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.
+
+// This file contains messages that extend MessageSet.
+
+syntax = "proto2";
+package google.protobuf.internal;
+
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message TestMessageSetExtension1 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension1 message_set_extension = 98418603;
+  }
+  optional int32 i = 15;
+}
+
+message TestMessageSetExtension2 {
+  extend TestMessageSet {
+    optional TestMessageSetExtension2 message_set_extension = 98418634;
+  }
+  optional string str = 25;
+}
+
+message TestMessageSetExtension3 {
+  optional string text = 35;
+}
+
+extend TestMessageSet {
+  optional TestMessageSetExtension3 message_set_extension3 = 98418655;
+}
+
+// This message was used to generate
+// //net/proto2/python/internal/testdata/message_set_message, but is commented
+// out since it must not actually exist in code, to simulate an "unknown"
+// extension.
+// message TestMessageSetUnknownExtension {
+//   extend TestMessageSet {
+//     optional TestMessageSetUnknownExtension message_set_extension = 56141421;
+//   }
+//   optional int64 a = 1;
+// }
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 48b7ffd..4ee31d8 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -43,17 +43,36 @@
 
 __author__ = 'gps@google.com (Gregory P. Smith)'
 
+
+import collections
 import copy
 import math
 import operator
 import pickle
+import six
 import sys
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
+from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
+from google.protobuf import text_format
 from google.protobuf.internal import api_implementation
+from google.protobuf.internal import packed_field_test_pb2
 from google.protobuf.internal import test_util
 from google.protobuf import message
+from google.protobuf.internal import _parameterized
+
+if six.PY3:
+  long = int
+
 
 # Python pre-2.6 does not have isinf() or isnan() functions, so we have
 # to provide our own.
@@ -69,88 +88,72 @@
   return isinf(val) and (val < 0)
 
 
-class MessageTest(basetest.TestCase):
+@_parameterized.Parameters(
+    (unittest_pb2),
+    (unittest_proto3_arena_pb2))
+class MessageTest(unittest.TestCase):
 
-  def testBadUtf8String(self):
+  def testBadUtf8String(self, message_module):
     if api_implementation.Type() != 'python':
       self.skipTest("Skipping testBadUtf8String, currently only the python "
                     "api implementation raises UnicodeDecodeError when a "
                     "string field contains bad utf-8.")
     bad_utf8_data = test_util.GoldenFileData('bad_utf8_string')
     with self.assertRaises(UnicodeDecodeError) as context:
-      unittest_pb2.TestAllTypes.FromString(bad_utf8_data)
-    self.assertIn('field: protobuf_unittest.TestAllTypes.optional_string',
-                  str(context.exception))
+      message_module.TestAllTypes.FromString(bad_utf8_data)
+    self.assertIn('TestAllTypes.optional_string', str(context.exception))
 
-  def testGoldenMessage(self):
-    golden_data = test_util.GoldenFileData(
-        'golden_message_oneof_implemented')
-    golden_message = unittest_pb2.TestAllTypes()
+  def testGoldenMessage(self, message_module):
+    # Proto3 doesn't have the "default_foo" members or foreign enums,
+    # and doesn't preserve unknown fields, so for proto3 we use a golden
+    # message that doesn't have these fields set.
+    if message_module is unittest_pb2:
+      golden_data = test_util.GoldenFileData(
+          'golden_message_oneof_implemented')
+    else:
+      golden_data = test_util.GoldenFileData('golden_message_proto3')
+
+    golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
-    test_util.ExpectAllFieldsSet(self, golden_message)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, golden_message)
     self.assertEqual(golden_data, golden_message.SerializeToString())
     golden_copy = copy.deepcopy(golden_message)
     self.assertEqual(golden_data, golden_copy.SerializeToString())
 
-  def testGoldenExtensions(self):
-    golden_data = test_util.GoldenFileData('golden_message')
-    golden_message = unittest_pb2.TestAllExtensions()
-    golden_message.ParseFromString(golden_data)
-    all_set = unittest_pb2.TestAllExtensions()
-    test_util.SetAllExtensions(all_set)
-    self.assertEquals(all_set, golden_message)
-    self.assertEqual(golden_data, golden_message.SerializeToString())
-    golden_copy = copy.deepcopy(golden_message)
-    self.assertEqual(golden_data, golden_copy.SerializeToString())
-
-  def testGoldenPackedMessage(self):
+  def testGoldenPackedMessage(self, message_module):
     golden_data = test_util.GoldenFileData('golden_packed_fields_message')
-    golden_message = unittest_pb2.TestPackedTypes()
+    golden_message = message_module.TestPackedTypes()
     golden_message.ParseFromString(golden_data)
-    all_set = unittest_pb2.TestPackedTypes()
+    all_set = message_module.TestPackedTypes()
     test_util.SetAllPackedFields(all_set)
-    self.assertEquals(all_set, golden_message)
+    self.assertEqual(all_set, golden_message)
     self.assertEqual(golden_data, all_set.SerializeToString())
     golden_copy = copy.deepcopy(golden_message)
     self.assertEqual(golden_data, golden_copy.SerializeToString())
 
-  def testGoldenPackedExtensions(self):
-    golden_data = test_util.GoldenFileData('golden_packed_fields_message')
-    golden_message = unittest_pb2.TestPackedExtensions()
-    golden_message.ParseFromString(golden_data)
-    all_set = unittest_pb2.TestPackedExtensions()
-    test_util.SetAllPackedExtensions(all_set)
-    self.assertEquals(all_set, golden_message)
-    self.assertEqual(golden_data, all_set.SerializeToString())
-    golden_copy = copy.deepcopy(golden_message)
-    self.assertEqual(golden_data, golden_copy.SerializeToString())
-
-  def testPickleSupport(self):
+  def testPickleSupport(self, message_module):
     golden_data = test_util.GoldenFileData('golden_message')
-    golden_message = unittest_pb2.TestAllTypes()
+    golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     pickled_message = pickle.dumps(golden_message)
 
     unpickled_message = pickle.loads(pickled_message)
-    self.assertEquals(unpickled_message, golden_message)
+    self.assertEqual(unpickled_message, golden_message)
 
+  def testPositiveInfinity(self, message_module):
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCD\x02\x00\x00\x80\x7F'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCA\x02\x04\x00\x00\x80\x7F'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
 
-  def testPickleIncompleteProto(self):
-    golden_message = unittest_pb2.TestRequired(a=1)
-    pickled_message = pickle.dumps(golden_message)
-
-    unpickled_message = pickle.loads(pickled_message)
-    self.assertEquals(unpickled_message, golden_message)
-    self.assertEquals(unpickled_message.a, 1)
-    # This is still an incomplete proto - so serializing should fail
-    self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
-
-  def testPositiveInfinity(self):
-    golden_data = (b'\x5D\x00\x00\x80\x7F'
-                   b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
-                   b'\xCD\x02\x00\x00\x80\x7F'
-                   b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
-    golden_message = unittest_pb2.TestAllTypes()
+    golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsPosInf(golden_message.optional_float))
     self.assertTrue(IsPosInf(golden_message.optional_double))
@@ -158,12 +161,19 @@
     self.assertTrue(IsPosInf(golden_message.repeated_double[0]))
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
-  def testNegativeInfinity(self):
-    golden_data = (b'\x5D\x00\x00\x80\xFF'
-                   b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
-                   b'\xCD\x02\x00\x00\x80\xFF'
-                   b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
-    golden_message = unittest_pb2.TestAllTypes()
+  def testNegativeInfinity(self, message_module):
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCD\x02\x00\x00\x80\xFF'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCA\x02\x04\x00\x00\x80\xFF'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
+
+    golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsNegInf(golden_message.optional_float))
     self.assertTrue(IsNegInf(golden_message.optional_double))
@@ -171,12 +181,12 @@
     self.assertTrue(IsNegInf(golden_message.repeated_double[0]))
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
-  def testNotANumber(self):
+  def testNotANumber(self, message_module):
     golden_data = (b'\x5D\x00\x00\xC0\x7F'
                    b'\x61\x00\x00\x00\x00\x00\x00\xF8\x7F'
                    b'\xCD\x02\x00\x00\xC0\x7F'
                    b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF8\x7F')
-    golden_message = unittest_pb2.TestAllTypes()
+    golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(isnan(golden_message.optional_float))
     self.assertTrue(isnan(golden_message.optional_double))
@@ -188,47 +198,47 @@
     # verify the serialized string can be converted into a correctly
     # behaving protocol buffer.
     serialized = golden_message.SerializeToString()
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
     message.ParseFromString(serialized)
     self.assertTrue(isnan(message.optional_float))
     self.assertTrue(isnan(message.optional_double))
     self.assertTrue(isnan(message.repeated_float[0]))
     self.assertTrue(isnan(message.repeated_double[0]))
 
-  def testPositiveInfinityPacked(self):
+  def testPositiveInfinityPacked(self, message_module):
     golden_data = (b'\xA2\x06\x04\x00\x00\x80\x7F'
                    b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
-    golden_message = unittest_pb2.TestPackedTypes()
+    golden_message = message_module.TestPackedTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsPosInf(golden_message.packed_float[0]))
     self.assertTrue(IsPosInf(golden_message.packed_double[0]))
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
-  def testNegativeInfinityPacked(self):
+  def testNegativeInfinityPacked(self, message_module):
     golden_data = (b'\xA2\x06\x04\x00\x00\x80\xFF'
                    b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
-    golden_message = unittest_pb2.TestPackedTypes()
+    golden_message = message_module.TestPackedTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsNegInf(golden_message.packed_float[0]))
     self.assertTrue(IsNegInf(golden_message.packed_double[0]))
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
-  def testNotANumberPacked(self):
+  def testNotANumberPacked(self, message_module):
     golden_data = (b'\xA2\x06\x04\x00\x00\xC0\x7F'
                    b'\xAA\x06\x08\x00\x00\x00\x00\x00\x00\xF8\x7F')
-    golden_message = unittest_pb2.TestPackedTypes()
+    golden_message = message_module.TestPackedTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(isnan(golden_message.packed_float[0]))
     self.assertTrue(isnan(golden_message.packed_double[0]))
 
     serialized = golden_message.SerializeToString()
-    message = unittest_pb2.TestPackedTypes()
+    message = message_module.TestPackedTypes()
     message.ParseFromString(serialized)
     self.assertTrue(isnan(message.packed_float[0]))
     self.assertTrue(isnan(message.packed_double[0]))
 
-  def testExtremeFloatValues(self):
-    message = unittest_pb2.TestAllTypes()
+  def testExtremeFloatValues(self, message_module):
+    message = message_module.TestAllTypes()
 
     # Most positive exponent, no significand bits set.
     kMostPosExponentNoSigBits = math.pow(2, 127)
@@ -272,8 +282,8 @@
     message.ParseFromString(message.SerializeToString())
     self.assertTrue(message.optional_float == -kMostNegExponentOneSigBit)
 
-  def testExtremeDoubleValues(self):
-    message = unittest_pb2.TestAllTypes()
+  def testExtremeDoubleValues(self, message_module):
+    message = message_module.TestAllTypes()
 
     # Most positive exponent, no significand bits set.
     kMostPosExponentNoSigBits = math.pow(2, 1023)
@@ -317,29 +327,43 @@
     message.ParseFromString(message.SerializeToString())
     self.assertTrue(message.optional_double == -kMostNegExponentOneSigBit)
 
-  def testFloatPrinting(self):
-    message = unittest_pb2.TestAllTypes()
+  def testFloatPrinting(self, message_module):
+    message = message_module.TestAllTypes()
     message.optional_float = 2.0
     self.assertEqual(str(message), 'optional_float: 2.0\n')
 
-  def testHighPrecisionFloatPrinting(self):
-    message = unittest_pb2.TestAllTypes()
+  def testHighPrecisionFloatPrinting(self, message_module):
+    message = message_module.TestAllTypes()
     message.optional_double = 0.12345678912345678
-    if sys.version_info.major >= 3:
+    if sys.version_info >= (3,):
       self.assertEqual(str(message), 'optional_double: 0.12345678912345678\n')
     else:
       self.assertEqual(str(message), 'optional_double: 0.123456789123\n')
 
-  def testUnknownFieldPrinting(self):
-    populated = unittest_pb2.TestAllTypes()
+  def testUnknownFieldPrinting(self, message_module):
+    populated = message_module.TestAllTypes()
     test_util.SetAllNonLazyFields(populated)
-    empty = unittest_pb2.TestEmptyMessage()
+    empty = message_module.TestEmptyMessage()
     empty.ParseFromString(populated.SerializeToString())
     self.assertEqual(str(empty), '')
 
-  def testSortingRepeatedScalarFieldsDefaultComparator(self):
+  def testRepeatedNestedFieldIteration(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.add(bb=1)
+    msg.repeated_nested_message.add(bb=2)
+    msg.repeated_nested_message.add(bb=3)
+    msg.repeated_nested_message.add(bb=4)
+
+    self.assertEqual([1, 2, 3, 4],
+                     [m.bb for m in msg.repeated_nested_message])
+    self.assertEqual([4, 3, 2, 1],
+                     [m.bb for m in reversed(msg.repeated_nested_message)])
+    self.assertEqual([4, 3, 2, 1],
+                     [m.bb for m in msg.repeated_nested_message[::-1]])
+
+  def testSortingRepeatedScalarFieldsDefaultComparator(self, message_module):
     """Check some different types with the default comparator."""
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
 
     # TODO(mattp): would testing more scalar types strengthen test?
     message.repeated_int32.append(1)
@@ -374,9 +398,9 @@
     self.assertEqual(message.repeated_bytes[1], b'b')
     self.assertEqual(message.repeated_bytes[2], b'c')
 
-  def testSortingRepeatedScalarFieldsCustomComparator(self):
+  def testSortingRepeatedScalarFieldsCustomComparator(self, message_module):
     """Check some different types with custom comparator."""
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
 
     message.repeated_int32.append(-3)
     message.repeated_int32.append(-2)
@@ -394,9 +418,9 @@
     self.assertEqual(message.repeated_string[1], 'bb')
     self.assertEqual(message.repeated_string[2], 'aaa')
 
-  def testSortingRepeatedCompositeFieldsCustomComparator(self):
+  def testSortingRepeatedCompositeFieldsCustomComparator(self, message_module):
     """Check passing a custom comparator to sort a repeated composite field."""
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
 
     message.repeated_nested_message.add().bb = 1
     message.repeated_nested_message.add().bb = 3
@@ -412,9 +436,34 @@
     self.assertEqual(message.repeated_nested_message[4].bb, 5)
     self.assertEqual(message.repeated_nested_message[5].bb, 6)
 
-  def testRepeatedCompositeFieldSortArguments(self):
+  def testSortingRepeatedCompositeFieldsStable(self, message_module):
+    """Check passing a custom comparator to sort a repeated composite field."""
+    message = message_module.TestAllTypes()
+
+    message.repeated_nested_message.add().bb = 21
+    message.repeated_nested_message.add().bb = 20
+    message.repeated_nested_message.add().bb = 13
+    message.repeated_nested_message.add().bb = 33
+    message.repeated_nested_message.add().bb = 11
+    message.repeated_nested_message.add().bb = 24
+    message.repeated_nested_message.add().bb = 10
+    message.repeated_nested_message.sort(key=lambda z: z.bb // 10)
+    self.assertEqual(
+        [13, 11, 10, 21, 20, 24, 33],
+        [n.bb for n in message.repeated_nested_message])
+
+    # Make sure that for the C++ implementation, the underlying fields
+    # are actually reordered.
+    pb = message.SerializeToString()
+    message.Clear()
+    message.MergeFromString(pb)
+    self.assertEqual(
+        [13, 11, 10, 21, 20, 24, 33],
+        [n.bb for n in message.repeated_nested_message])
+
+  def testRepeatedCompositeFieldSortArguments(self, message_module):
     """Check sorting a repeated composite field using list.sort() arguments."""
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
 
     get_bb = operator.attrgetter('bb')
     cmp_bb = lambda a, b: cmp(a.bb, b.bb)
@@ -430,7 +479,7 @@
     message.repeated_nested_message.sort(key=get_bb, reverse=True)
     self.assertEqual([k.bb for k in message.repeated_nested_message],
                      [6, 5, 4, 3, 2, 1])
-    if sys.version_info.major >= 3: return  # No cmp sorting in PY3.
+    if sys.version_info >= (3,): return  # No cmp sorting in PY3.
     message.repeated_nested_message.sort(sort_function=cmp_bb)
     self.assertEqual([k.bb for k in message.repeated_nested_message],
                      [1, 2, 3, 4, 5, 6])
@@ -438,9 +487,9 @@
     self.assertEqual([k.bb for k in message.repeated_nested_message],
                      [6, 5, 4, 3, 2, 1])
 
-  def testRepeatedScalarFieldSortArguments(self):
+  def testRepeatedScalarFieldSortArguments(self, message_module):
     """Check sorting a scalar field using list.sort() arguments."""
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
 
     message.repeated_int32.append(-3)
     message.repeated_int32.append(-2)
@@ -449,7 +498,7 @@
     self.assertEqual(list(message.repeated_int32), [-1, -2, -3])
     message.repeated_int32.sort(key=abs, reverse=True)
     self.assertEqual(list(message.repeated_int32), [-3, -2, -1])
-    if sys.version_info.major < 3:  # No cmp sorting in PY3.
+    if sys.version_info < (3,):  # No cmp sorting in PY3.
       abs_cmp = lambda a, b: cmp(abs(a), abs(b))
       message.repeated_int32.sort(sort_function=abs_cmp)
       self.assertEqual(list(message.repeated_int32), [-1, -2, -3])
@@ -463,16 +512,16 @@
     self.assertEqual(list(message.repeated_string), ['c', 'bb', 'aaa'])
     message.repeated_string.sort(key=len, reverse=True)
     self.assertEqual(list(message.repeated_string), ['aaa', 'bb', 'c'])
-    if sys.version_info.major < 3:  # No cmp sorting in PY3.
+    if sys.version_info < (3,):  # No cmp sorting in PY3.
       len_cmp = lambda a, b: cmp(len(a), len(b))
       message.repeated_string.sort(sort_function=len_cmp)
       self.assertEqual(list(message.repeated_string), ['c', 'bb', 'aaa'])
       message.repeated_string.sort(cmp=len_cmp, reverse=True)
       self.assertEqual(list(message.repeated_string), ['aaa', 'bb', 'c'])
 
-  def testRepeatedFieldsComparable(self):
-    m1 = unittest_pb2.TestAllTypes()
-    m2 = unittest_pb2.TestAllTypes()
+  def testRepeatedFieldsComparable(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
     m1.repeated_int32.append(0)
     m1.repeated_int32.append(1)
     m1.repeated_int32.append(2)
@@ -486,7 +535,7 @@
     m2.repeated_nested_message.add().bb = 2
     m2.repeated_nested_message.add().bb = 3
 
-    if sys.version_info.major >= 3: return  # No cmp() in PY3.
+    if sys.version_info >= (3,): return  # No cmp() in PY3.
 
     # These comparisons should not raise errors.
     _ = m1 < m2
@@ -505,6 +554,508 @@
 
     # TODO(anuraag): Implement extensiondict comparison in C++ and then add test
 
+  def testRepeatedFieldsAreSequences(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIsInstance(m.repeated_int32, collections.MutableSequence)
+    self.assertIsInstance(m.repeated_nested_message,
+                          collections.MutableSequence)
+
+  def ensureNestedMessageExists(self, msg, attribute):
+    """Make sure that a nested message object exists.
+
+    As soon as a nested message attribute is accessed, it will be present in the
+    _fields dict, without being marked as actually being set.
+    """
+    getattr(msg, attribute)
+    self.assertFalse(msg.HasField(attribute))
+
+  def testOneofGetCaseNonexistingField(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertRaises(ValueError, m.WhichOneof, 'no_such_oneof_field')
+
+  def testOneofDefaultValues(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+
+    # Oneof is set even when setting it to a default value.
+    m.oneof_uint32 = 0
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+    self.assertFalse(m.HasField('oneof_string'))
+
+    m.oneof_string = ""
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+
+  def testOneofSemantics(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+    m.oneof_uint32 = 11
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+
+    m.oneof_string = u'foo'
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertTrue(m.HasField('oneof_string'))
+
+    # Read nested message accessor without accessing submessage.
+    m.oneof_nested_message
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+
+    # Read accessor of nested message without accessing submessage.
+    m.oneof_nested_message.bb
+    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
+    self.assertTrue(m.HasField('oneof_string'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+
+    m.oneof_nested_message.bb = 11
+    self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_string'))
+    self.assertTrue(m.HasField('oneof_nested_message'))
+
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+    self.assertFalse(m.HasField('oneof_nested_message'))
+    self.assertTrue(m.HasField('oneof_bytes'))
+
+  def testOneofCompositeFieldReadAccess(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+
+    self.ensureNestedMessageExists(m, 'oneof_nested_message')
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    self.assertEqual(11, m.oneof_uint32)
+
+  def testOneofWhichOneof(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+
+    m.oneof_uint32 = 11
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertTrue(m.HasField('oneof_field'))
+
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+    m.ClearField('oneof_bytes')
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+
+  def testOneofClearField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.ClearField('oneof_field')
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+  def testOneofClearSetField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.ClearField('oneof_uint32')
+    if message_module is unittest_pb2:
+      self.assertFalse(m.HasField('oneof_field'))
+    self.assertFalse(m.HasField('oneof_uint32'))
+    self.assertIs(None, m.WhichOneof('oneof_field'))
+
+  def testOneofClearUnsetField(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    self.ensureNestedMessageExists(m, 'oneof_nested_message')
+    m.ClearField('oneof_nested_message')
+    self.assertEqual(11, m.oneof_uint32)
+    if message_module is unittest_pb2:
+      self.assertTrue(m.HasField('oneof_field'))
+    self.assertTrue(m.HasField('oneof_uint32'))
+    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
+
+  def testOneofDeserialize(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    m2.ParseFromString(m.SerializeToString())
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testOneofCopyFrom(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    m2.CopyFrom(m)
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testOneofNestedMergeFrom(self, message_module):
+    m = message_module.NestedTestAllTypes()
+    m.payload.oneof_uint32 = 11
+    m2 = message_module.NestedTestAllTypes()
+    m2.payload.oneof_bytes = b'bb'
+    m2.child.payload.oneof_bytes = b'bb'
+    m2.MergeFrom(m)
+    self.assertEqual('oneof_uint32', m2.payload.WhichOneof('oneof_field'))
+    self.assertEqual('oneof_bytes', m2.child.payload.WhichOneof('oneof_field'))
+
+  def testOneofMessageMergeFrom(self, message_module):
+    m = message_module.NestedTestAllTypes()
+    m.payload.oneof_nested_message.bb = 11
+    m.child.payload.oneof_nested_message.bb = 12
+    m2 = message_module.NestedTestAllTypes()
+    m2.payload.oneof_uint32 = 13
+    m2.MergeFrom(m)
+    self.assertEqual('oneof_nested_message',
+                     m2.payload.WhichOneof('oneof_field'))
+    self.assertEqual('oneof_nested_message',
+                     m2.child.payload.WhichOneof('oneof_field'))
+
+  def testOneofNestedMessageInit(self, message_module):
+    m = message_module.TestAllTypes(
+        oneof_nested_message=message_module.TestAllTypes.NestedMessage())
+    self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
+
+  def testOneofClear(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m.Clear()
+    self.assertIsNone(m.WhichOneof('oneof_field'))
+    m.oneof_bytes = b'bb'
+    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
+
+  def testAssignByteStringToUnicodeField(self, message_module):
+    """Assigning a byte string to a string field should result
+    in the value being converted to a Unicode string."""
+    m = message_module.TestAllTypes()
+    m.optional_string = str('')
+    self.assertIsInstance(m.optional_string, six.text_type)
+
+  def testLongValuedSlice(self, message_module):
+    """It should be possible to use long-valued indicies in slices
+
+    This didn't used to work in the v2 C++ implementation.
+    """
+    m = message_module.TestAllTypes()
+
+    # Repeated scalar
+    m.repeated_int32.append(1)
+    sl = m.repeated_int32[long(0):long(len(m.repeated_int32))]
+    self.assertEqual(len(m.repeated_int32), len(sl))
+
+    # Repeated composite
+    m.repeated_nested_message.add().bb = 3
+    sl = m.repeated_nested_message[long(0):long(len(m.repeated_nested_message))]
+    self.assertEqual(len(m.repeated_nested_message), len(sl))
+
+  def testExtendShouldNotSwallowExceptions(self, message_module):
+    """This didn't use to work in the v2 C++ implementation."""
+    m = message_module.TestAllTypes()
+    with self.assertRaises(NameError) as _:
+      m.repeated_int32.extend(a for i in range(10))  # pylint: disable=undefined-variable
+    with self.assertRaises(NameError) as _:
+      m.repeated_nested_enum.extend(
+          a for i in range(10))  # pylint: disable=undefined-variable
+
+  FALSY_VALUES = [None, False, 0, 0.0, b'', u'', bytearray(), [], {}, set()]
+
+  def testExtendInt32WithNothing(self, message_module):
+    """Test no-ops extending repeated int32 fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_int32.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_int32)
+
+    m.repeated_int32.extend([])
+    self.assertSequenceEqual([], m.repeated_int32)
+
+  def testExtendFloatWithNothing(self, message_module):
+    """Test no-ops extending repeated float fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_float.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_float)
+
+    m.repeated_float.extend([])
+    self.assertSequenceEqual([], m.repeated_float)
+
+  def testExtendStringWithNothing(self, message_module):
+    """Test no-ops extending repeated string fields."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+
+    # TODO(ptucker): Deprecate this behavior. b/18413862
+    for falsy_value in MessageTest.FALSY_VALUES:
+      m.repeated_string.extend(falsy_value)
+      self.assertSequenceEqual([], m.repeated_string)
+
+    m.repeated_string.extend([])
+    self.assertSequenceEqual([], m.repeated_string)
+
+  def testExtendInt32WithPythonList(self, message_module):
+    """Test extending repeated int32 fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend([0])
+    self.assertSequenceEqual([0], m.repeated_int32)
+    m.repeated_int32.extend([1, 2])
+    self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+    m.repeated_int32.extend([3, 4])
+    self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+  def testExtendFloatWithPythonList(self, message_module):
+    """Test extending repeated float fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend([0.0])
+    self.assertSequenceEqual([0.0], m.repeated_float)
+    m.repeated_float.extend([1.0, 2.0])
+    self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+    m.repeated_float.extend([3.0, 4.0])
+    self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+  def testExtendStringWithPythonList(self, message_module):
+    """Test extending repeated string fields with python lists."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend([''])
+    self.assertSequenceEqual([''], m.repeated_string)
+    m.repeated_string.extend(['11', '22'])
+    self.assertSequenceEqual(['', '11', '22'], m.repeated_string)
+    m.repeated_string.extend(['33', '44'])
+    self.assertSequenceEqual(['', '11', '22', '33', '44'], m.repeated_string)
+
+  def testExtendStringWithString(self, message_module):
+    """Test extending repeated string fields with characters from a string."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend('abc')
+    self.assertSequenceEqual(['a', 'b', 'c'], m.repeated_string)
+
+  class TestIterable(object):
+    """This iterable object mimics the behavior of numpy.array.
+
+    __nonzero__ fails for length > 1, and returns bool(item[0]) for length == 1.
+
+    """
+
+    def __init__(self, values=None):
+      self._list = values or []
+
+    def __nonzero__(self):
+      size = len(self._list)
+      if size == 0:
+        return False
+      if size == 1:
+        return bool(self._list[0])
+      raise ValueError('Truth value is ambiguous.')
+
+    def __len__(self):
+      return len(self._list)
+
+    def __iter__(self):
+      return self._list.__iter__()
+
+  def testExtendInt32WithIterable(self, message_module):
+    """Test extending repeated int32 fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([0]))
+    self.assertSequenceEqual([0], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([1, 2]))
+    self.assertSequenceEqual([0, 1, 2], m.repeated_int32)
+    m.repeated_int32.extend(MessageTest.TestIterable([3, 4]))
+    self.assertSequenceEqual([0, 1, 2, 3, 4], m.repeated_int32)
+
+  def testExtendFloatWithIterable(self, message_module):
+    """Test extending repeated float fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([0.0]))
+    self.assertSequenceEqual([0.0], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([1.0, 2.0]))
+    self.assertSequenceEqual([0.0, 1.0, 2.0], m.repeated_float)
+    m.repeated_float.extend(MessageTest.TestIterable([3.0, 4.0]))
+    self.assertSequenceEqual([0.0, 1.0, 2.0, 3.0, 4.0], m.repeated_float)
+
+  def testExtendStringWithIterable(self, message_module):
+    """Test extending repeated string fields with iterable."""
+    m = message_module.TestAllTypes()
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable([]))
+    self.assertSequenceEqual([], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['']))
+    self.assertSequenceEqual([''], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['1', '2']))
+    self.assertSequenceEqual(['', '1', '2'], m.repeated_string)
+    m.repeated_string.extend(MessageTest.TestIterable(['3', '4']))
+    self.assertSequenceEqual(['', '1', '2', '3', '4'], m.repeated_string)
+
+  def testPickleRepeatedScalarContainer(self, message_module):
+    # TODO(tibell): The pure-Python implementation support pickling of
+    #   scalar containers in *some* cases. For now the cpp2 version
+    #   throws an exception to avoid a segfault. Investigate if we
+    #   want to support pickling of these fields.
+    #
+    # For more information see: https://b2.corp.google.com/u/0/issues/18677897
+    if (api_implementation.Type() != 'cpp' or
+        api_implementation.Version() == 2):
+      return
+    m = message_module.TestAllTypes()
+    with self.assertRaises(pickle.PickleError) as _:
+      pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
+
+  def testSortEmptyRepeatedCompositeContainer(self, message_module):
+    """Exercise a scenario that has led to segfaults in the past.
+    """
+    m = message_module.TestAllTypes()
+    m.repeated_nested_message.sort()
+
+  def testHasFieldOnRepeatedField(self, message_module):
+    """Using HasField on a repeated field should raise an exception.
+    """
+    m = message_module.TestAllTypes()
+    with self.assertRaises(ValueError) as _:
+      m.HasField('repeated_int32')
+
+  def testRepeatedScalarFieldPop(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(IndexError) as _:
+      m.repeated_int32.pop()
+    m.repeated_int32.extend(range(5))
+    self.assertEqual(4, m.repeated_int32.pop())
+    self.assertEqual(0, m.repeated_int32.pop(0))
+    self.assertEqual(2, m.repeated_int32.pop(1))
+    self.assertEqual([1, 3], m.repeated_int32)
+
+  def testRepeatedCompositeFieldPop(self, message_module):
+    m = message_module.TestAllTypes()
+    with self.assertRaises(IndexError) as _:
+      m.repeated_nested_message.pop()
+    for i in range(5):
+      n = m.repeated_nested_message.add()
+      n.bb = i
+    self.assertEqual(4, m.repeated_nested_message.pop().bb)
+    self.assertEqual(0, m.repeated_nested_message.pop(0).bb)
+    self.assertEqual(2, m.repeated_nested_message.pop(1).bb)
+    self.assertEqual([1, 3], [n.bb for n in m.repeated_nested_message])
+
+
+# Class to test proto2-only features (required, extensions, etc.)
+class Proto2Test(unittest.TestCase):
+
+  def testFieldPresence(self):
+    message = unittest_pb2.TestAllTypes()
+
+    self.assertFalse(message.HasField("optional_int32"))
+    self.assertFalse(message.HasField("optional_bool"))
+    self.assertFalse(message.HasField("optional_nested_message"))
+
+    with self.assertRaises(ValueError):
+      message.HasField("field_doesnt_exist")
+
+    with self.assertRaises(ValueError):
+      message.HasField("repeated_int32")
+    with self.assertRaises(ValueError):
+      message.HasField("repeated_nested_message")
+
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+    # Fields are set even when setting the values to default values.
+    message.optional_int32 = 0
+    message.optional_bool = False
+    message.optional_nested_message.bb = 0
+    self.assertTrue(message.HasField("optional_int32"))
+    self.assertTrue(message.HasField("optional_bool"))
+    self.assertTrue(message.HasField("optional_nested_message"))
+
+    # Set the fields to non-default values.
+    message.optional_int32 = 5
+    message.optional_bool = True
+    message.optional_nested_message.bb = 15
+
+    self.assertTrue(message.HasField("optional_int32"))
+    self.assertTrue(message.HasField("optional_bool"))
+    self.assertTrue(message.HasField("optional_nested_message"))
+
+    # Clearing the fields unsets them and resets their value to default.
+    message.ClearField("optional_int32")
+    message.ClearField("optional_bool")
+    message.ClearField("optional_nested_message")
+
+    self.assertFalse(message.HasField("optional_int32"))
+    self.assertFalse(message.HasField("optional_bool"))
+    self.assertFalse(message.HasField("optional_nested_message"))
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+  # TODO(tibell): The C++ implementations actually allows assignment
+  # of unknown enum values to *scalar* fields (but not repeated
+  # fields). Once checked enum fields becomes the default in the
+  # Python implementation, the C++ implementation should follow suit.
+  def testAssignInvalidEnum(self):
+    """It should not be possible to assign an invalid enum number to an
+    enum field."""
+    m = unittest_pb2.TestAllTypes()
+
+    with self.assertRaises(ValueError) as _:
+      m.optional_nested_enum = 1234567
+    self.assertRaises(ValueError, m.repeated_nested_enum.append, 1234567)
+
+  def testGoldenExtensions(self):
+    golden_data = test_util.GoldenFileData('golden_message')
+    golden_message = unittest_pb2.TestAllExtensions()
+    golden_message.ParseFromString(golden_data)
+    all_set = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(all_set)
+    self.assertEqual(all_set, golden_message)
+    self.assertEqual(golden_data, golden_message.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testGoldenPackedExtensions(self):
+    golden_data = test_util.GoldenFileData('golden_packed_fields_message')
+    golden_message = unittest_pb2.TestPackedExtensions()
+    golden_message.ParseFromString(golden_data)
+    all_set = unittest_pb2.TestPackedExtensions()
+    test_util.SetAllPackedExtensions(all_set)
+    self.assertEqual(all_set, golden_message)
+    self.assertEqual(golden_data, all_set.SerializeToString())
+    golden_copy = copy.deepcopy(golden_message)
+    self.assertEqual(golden_data, golden_copy.SerializeToString())
+
+  def testPickleIncompleteProto(self):
+    golden_message = unittest_pb2.TestRequired(a=1)
+    pickled_message = pickle.dumps(golden_message)
+
+    unpickled_message = pickle.loads(pickled_message)
+    self.assertEqual(unpickled_message, golden_message)
+    self.assertEqual(unpickled_message.a, 1)
+    # This is still an incomplete proto - so serializing should fail
+    self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
+
+
+  # TODO(haberman): this isn't really a proto2-specific test except that this
+  # message has a required field in it.  Should probably be factored out so
+  # that we can test the other parts with proto3.
   def testParsingMerge(self):
     """Check the merge behavior when a required or optional field appears
     multiple times in the input."""
@@ -554,108 +1105,618 @@
     self.assertEqual(len(parsing_merge.Extensions[
         unittest_pb2.TestParsingMerge.repeated_ext]), 3)
 
-  def ensureNestedMessageExists(self, msg, attribute):
-    """Make sure that a nested message object exists.
+  def testPythonicInit(self):
+    message = unittest_pb2.TestAllTypes(
+        optional_int32=100,
+        optional_fixed32=200,
+        optional_float=300.5,
+        optional_bytes=b'x',
+        optionalgroup={'a': 400},
+        optional_nested_message={'bb': 500},
+        optional_nested_enum='BAZ',
+        repeatedgroup=[{'a': 600},
+                       {'a': 700}],
+        repeated_nested_enum=['FOO', unittest_pb2.TestAllTypes.BAR],
+        default_int32=800,
+        oneof_string='y')
+    self.assertIsInstance(message, unittest_pb2.TestAllTypes)
+    self.assertEqual(100, message.optional_int32)
+    self.assertEqual(200, message.optional_fixed32)
+    self.assertEqual(300.5, message.optional_float)
+    self.assertEqual(b'x', message.optional_bytes)
+    self.assertEqual(400, message.optionalgroup.a)
+    self.assertIsInstance(message.optional_nested_message, unittest_pb2.TestAllTypes.NestedMessage)
+    self.assertEqual(500, message.optional_nested_message.bb)
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
+    self.assertEqual(2, len(message.repeatedgroup))
+    self.assertEqual(600, message.repeatedgroup[0].a)
+    self.assertEqual(700, message.repeatedgroup[1].a)
+    self.assertEqual(2, len(message.repeated_nested_enum))
+    self.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                     message.repeated_nested_enum[0])
+    self.assertEqual(unittest_pb2.TestAllTypes.BAR,
+                     message.repeated_nested_enum[1])
+    self.assertEqual(800, message.default_int32)
+    self.assertEqual('y', message.oneof_string)
+    self.assertFalse(message.HasField('optional_int64'))
+    self.assertEqual(0, len(message.repeated_float))
+    self.assertEqual(42, message.default_int64)
 
-    As soon as a nested message attribute is accessed, it will be present in the
-    _fields dict, without being marked as actually being set.
-    """
-    getattr(msg, attribute)
-    self.assertFalse(msg.HasField(attribute))
+    message = unittest_pb2.TestAllTypes(optional_nested_enum=u'BAZ')
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
 
-  def testOneofGetCaseNonexistingField(self):
-    m = unittest_pb2.TestAllTypes()
-    self.assertRaises(ValueError, m.WhichOneof, 'no_such_oneof_field')
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'INVALID_NESTED_FIELD': 17})
 
-  def testOneofSemantics(self):
-    m = unittest_pb2.TestAllTypes()
-    self.assertIs(None, m.WhichOneof('oneof_field'))
+    with self.assertRaises(TypeError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'bb': 'INVALID_VALUE_TYPE'})
 
-    m.oneof_uint32 = 11
-    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
-    self.assertTrue(m.HasField('oneof_uint32'))
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(optional_nested_enum='INVALID_LABEL')
 
-    m.oneof_string = u'foo'
-    self.assertEqual('oneof_string', m.WhichOneof('oneof_field'))
-    self.assertFalse(m.HasField('oneof_uint32'))
-    self.assertTrue(m.HasField('oneof_string'))
-
-    m.oneof_nested_message.bb = 11
-    self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
-    self.assertFalse(m.HasField('oneof_string'))
-    self.assertTrue(m.HasField('oneof_nested_message'))
-
-    m.oneof_bytes = b'bb'
-    self.assertEqual('oneof_bytes', m.WhichOneof('oneof_field'))
-    self.assertFalse(m.HasField('oneof_nested_message'))
-    self.assertTrue(m.HasField('oneof_bytes'))
-
-  def testOneofCompositeFieldReadAccess(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-
-    self.ensureNestedMessageExists(m, 'oneof_nested_message')
-    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
-    self.assertEqual(11, m.oneof_uint32)
-
-  def testOneofHasField(self):
-    m = unittest_pb2.TestAllTypes()
-    self.assertFalse(m.HasField('oneof_field'))
-    m.oneof_uint32 = 11
-    self.assertTrue(m.HasField('oneof_field'))
-    m.oneof_bytes = b'bb'
-    self.assertTrue(m.HasField('oneof_field'))
-    m.ClearField('oneof_bytes')
-    self.assertFalse(m.HasField('oneof_field'))
-
-  def testOneofClearField(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-    m.ClearField('oneof_field')
-    self.assertFalse(m.HasField('oneof_field'))
-    self.assertFalse(m.HasField('oneof_uint32'))
-    self.assertIs(None, m.WhichOneof('oneof_field'))
-
-  def testOneofClearSetField(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-    m.ClearField('oneof_uint32')
-    self.assertFalse(m.HasField('oneof_field'))
-    self.assertFalse(m.HasField('oneof_uint32'))
-    self.assertIs(None, m.WhichOneof('oneof_field'))
-
-  def testOneofClearUnsetField(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-    self.ensureNestedMessageExists(m, 'oneof_nested_message')
-    m.ClearField('oneof_nested_message')
-    self.assertEqual(11, m.oneof_uint32)
-    self.assertTrue(m.HasField('oneof_field'))
-    self.assertTrue(m.HasField('oneof_uint32'))
-    self.assertEqual('oneof_uint32', m.WhichOneof('oneof_field'))
-
-  def testOneofDeserialize(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-    m2 = unittest_pb2.TestAllTypes()
-    m2.ParseFromString(m.SerializeToString())
-    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
-
-  def testSortEmptyRepeatedCompositeContainer(self):
-    """Exercise a scenario that has led to segfaults in the past.
-    """
-    m = unittest_pb2.TestAllTypes()
-    m.repeated_nested_message.sort()
-
-  def testHasFieldOnRepeatedField(self):
-    """Using HasField on a repeated field should raise an exception.
-    """
-    m = unittest_pb2.TestAllTypes()
-    with self.assertRaises(ValueError) as _:
-      m.HasField('repeated_int32')
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(repeated_nested_enum='FOO')
 
 
-class ValidTypeNamesTest(basetest.TestCase):
+
+# Class to test proto3-only features/behavior (updated field presence & enums)
+class Proto3Test(unittest.TestCase):
+
+  # Utility method for comparing equality with a map.
+  def assertMapIterEquals(self, map_iter, dict_value):
+    # Avoid mutating caller's copy.
+    dict_value = dict(dict_value)
+
+    for k, v in map_iter:
+      self.assertEqual(v, dict_value[k])
+      del dict_value[k]
+
+    self.assertEqual({}, dict_value)
+
+  def testFieldPresence(self):
+    message = unittest_proto3_arena_pb2.TestAllTypes()
+
+    # We can't test presence of non-repeated, non-submessage fields.
+    with self.assertRaises(ValueError):
+      message.HasField('optional_int32')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_float')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_string')
+    with self.assertRaises(ValueError):
+      message.HasField('optional_bool')
+
+    # But we can still test presence of submessage fields.
+    self.assertFalse(message.HasField('optional_nested_message'))
+
+    # As with proto2, we can't test presence of fields that don't exist, or
+    # repeated fields.
+    with self.assertRaises(ValueError):
+      message.HasField('field_doesnt_exist')
+
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_int32')
+    with self.assertRaises(ValueError):
+      message.HasField('repeated_nested_message')
+
+    # Fields should default to their type-specific default.
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(0, message.optional_float)
+    self.assertEqual('', message.optional_string)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+    # Setting a submessage should still return proper presence information.
+    message.optional_nested_message.bb = 0
+    self.assertTrue(message.HasField('optional_nested_message'))
+
+    # Set the fields to non-default values.
+    message.optional_int32 = 5
+    message.optional_float = 1.1
+    message.optional_string = 'abc'
+    message.optional_bool = True
+    message.optional_nested_message.bb = 15
+
+    # Clearing the fields unsets them and resets their value to default.
+    message.ClearField('optional_int32')
+    message.ClearField('optional_float')
+    message.ClearField('optional_string')
+    message.ClearField('optional_bool')
+    message.ClearField('optional_nested_message')
+
+    self.assertEqual(0, message.optional_int32)
+    self.assertEqual(0, message.optional_float)
+    self.assertEqual('', message.optional_string)
+    self.assertEqual(False, message.optional_bool)
+    self.assertEqual(0, message.optional_nested_message.bb)
+
+  def testAssignUnknownEnum(self):
+    """Assigning an unknown enum value is allowed and preserves the value."""
+    m = unittest_proto3_arena_pb2.TestAllTypes()
+
+    m.optional_nested_enum = 1234567
+    self.assertEqual(1234567, m.optional_nested_enum)
+    m.repeated_nested_enum.append(22334455)
+    self.assertEqual(22334455, m.repeated_nested_enum[0])
+    # Assignment is a different code path than append for the C++ impl.
+    m.repeated_nested_enum[0] = 7654321
+    self.assertEqual(7654321, m.repeated_nested_enum[0])
+    serialized = m.SerializeToString()
+
+    m2 = unittest_proto3_arena_pb2.TestAllTypes()
+    m2.ParseFromString(serialized)
+    self.assertEqual(1234567, m2.optional_nested_enum)
+    self.assertEqual(7654321, m2.repeated_nested_enum[0])
+
+  # Map isn't really a proto3-only feature. But there is no proto2 equivalent
+  # of google/protobuf/map_unittest.proto right now, so it's not easy to
+  # test both with the same test like we do for the other proto2/proto3 tests.
+  # (google/protobuf/map_protobuf_unittest.proto is very different in the set
+  # of messages and fields it contains).
+  def testScalarMapDefaults(self):
+    msg = map_unittest_pb2.TestMap()
+
+    # Scalars start out unset.
+    self.assertFalse(-123 in msg.map_int32_int32)
+    self.assertFalse(-2**33 in msg.map_int64_int64)
+    self.assertFalse(123 in msg.map_uint32_uint32)
+    self.assertFalse(2**33 in msg.map_uint64_uint64)
+    self.assertFalse(123 in msg.map_int32_double)
+    self.assertFalse(False in msg.map_bool_bool)
+    self.assertFalse('abc' in msg.map_string_string)
+    self.assertFalse(111 in msg.map_int32_bytes)
+    self.assertFalse(888 in msg.map_int32_enum)
+
+    # Accessing an unset key returns the default.
+    self.assertEqual(0, msg.map_int32_int32[-123])
+    self.assertEqual(0, msg.map_int64_int64[-2**33])
+    self.assertEqual(0, msg.map_uint32_uint32[123])
+    self.assertEqual(0, msg.map_uint64_uint64[2**33])
+    self.assertEqual(0.0, msg.map_int32_double[123])
+    self.assertTrue(isinstance(msg.map_int32_double[123], float))
+    self.assertEqual(False, msg.map_bool_bool[False])
+    self.assertTrue(isinstance(msg.map_bool_bool[False], bool))
+    self.assertEqual('', msg.map_string_string['abc'])
+    self.assertEqual(b'', msg.map_int32_bytes[111])
+    self.assertEqual(0, msg.map_int32_enum[888])
+
+    # It also sets the value in the map
+    self.assertTrue(-123 in msg.map_int32_int32)
+    self.assertTrue(-2**33 in msg.map_int64_int64)
+    self.assertTrue(123 in msg.map_uint32_uint32)
+    self.assertTrue(2**33 in msg.map_uint64_uint64)
+    self.assertTrue(123 in msg.map_int32_double)
+    self.assertTrue(False in msg.map_bool_bool)
+    self.assertTrue('abc' in msg.map_string_string)
+    self.assertTrue(111 in msg.map_int32_bytes)
+    self.assertTrue(888 in msg.map_int32_enum)
+
+    self.assertIsInstance(msg.map_string_string['abc'], six.text_type)
+
+    # Accessing an unset key still throws TypeError if the type of the key
+    # is incorrect.
+    with self.assertRaises(TypeError):
+      msg.map_string_string[123]
+
+    with self.assertRaises(TypeError):
+      123 in msg.map_string_string
+
+  def testMapGet(self):
+    # Need to test that get() properly returns the default, even though the dict
+    # has defaultdict-like semantics.
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertIsNone(msg.map_int32_int32.get(5))
+    self.assertEqual(10, msg.map_int32_int32.get(5, 10))
+    self.assertIsNone(msg.map_int32_int32.get(5))
+
+    msg.map_int32_int32[5] = 15
+    self.assertEqual(15, msg.map_int32_int32.get(5))
+
+    self.assertIsNone(msg.map_int32_foreign_message.get(5))
+    self.assertEqual(10, msg.map_int32_foreign_message.get(5, 10))
+
+    submsg = msg.map_int32_foreign_message[5]
+    self.assertIs(submsg, msg.map_int32_foreign_message.get(5))
+
+  def testScalarMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_int32))
+    self.assertFalse(5 in msg.map_int32_int32)
+
+    msg.map_int32_int32[-123] = -456
+    msg.map_int64_int64[-2**33] = -2**34
+    msg.map_uint32_uint32[123] = 456
+    msg.map_uint64_uint64[2**33] = 2**34
+    msg.map_string_string['abc'] = '123'
+    msg.map_int32_enum[888] = 2
+
+    self.assertEqual([], msg.FindInitializationErrors())
+
+    self.assertEqual(1, len(msg.map_string_string))
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg.map_string_string[123] = '123'
+
+    # Verify that trying to assign a bad key doesn't actually add a member to
+    # the map.
+    self.assertEqual(1, len(msg.map_string_string))
+
+    # Bad value.
+    with self.assertRaises(TypeError):
+      msg.map_string_string['123'] = 123
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg2.map_string_string[123] = '123'
+
+    # Bad value.
+    with self.assertRaises(TypeError):
+      msg2.map_string_string['123'] = 123
+
+    self.assertEqual(-456, msg2.map_int32_int32[-123])
+    self.assertEqual(-2**34, msg2.map_int64_int64[-2**33])
+    self.assertEqual(456, msg2.map_uint32_uint32[123])
+    self.assertEqual(2**34, msg2.map_uint64_uint64[2**33])
+    self.assertEqual('123', msg2.map_string_string['abc'])
+    self.assertEqual(2, msg2.map_int32_enum[888])
+
+  def testStringUnicodeConversionInMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    unicode_obj = u'\u1234'
+    bytes_obj = unicode_obj.encode('utf8')
+
+    msg.map_string_string[bytes_obj] = bytes_obj
+
+    (key, value) = list(msg.map_string_string.items())[0]
+
+    self.assertEqual(key, unicode_obj)
+    self.assertEqual(value, unicode_obj)
+
+    self.assertIsInstance(key, six.text_type)
+    self.assertIsInstance(value, six.text_type)
+
+  def testMessageMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_foreign_message))
+    self.assertFalse(5 in msg.map_int32_foreign_message)
+
+    msg.map_int32_foreign_message[123]
+    # get_or_create() is an alias for getitem.
+    msg.map_int32_foreign_message.get_or_create(-456)
+
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+    self.assertIn(123, msg.map_int32_foreign_message)
+    self.assertIn(-456, msg.map_int32_foreign_message)
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg.map_int32_foreign_message['123']
+
+    # Can't assign directly to submessage.
+    with self.assertRaises(ValueError):
+      msg.map_int32_foreign_message[999] = msg.map_int32_foreign_message[123]
+
+    # Verify that trying to assign a bad key doesn't actually add a member to
+    # the map.
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(2, len(msg2.map_int32_foreign_message))
+    self.assertIn(123, msg2.map_int32_foreign_message)
+    self.assertIn(-456, msg2.map_int32_foreign_message)
+    self.assertEqual(2, len(msg2.map_int32_foreign_message))
+
+  def testMergeFrom(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[12] = 34
+    msg.map_int32_int32[56] = 78
+    msg.map_int64_int64[22] = 33
+    msg.map_int32_foreign_message[111].c = 5
+    msg.map_int32_foreign_message[222].c = 10
+
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.map_int32_int32[12] = 55
+    msg2.map_int64_int64[88] = 99
+    msg2.map_int32_foreign_message[222].c = 15
+
+    msg2.MergeFrom(msg)
+
+    self.assertEqual(34, msg2.map_int32_int32[12])
+    self.assertEqual(78, msg2.map_int32_int32[56])
+    self.assertEqual(33, msg2.map_int64_int64[22])
+    self.assertEqual(99, msg2.map_int64_int64[88])
+    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
+    self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
+
+    # Verify that there is only one entry per key, even though the MergeFrom
+    # may have internally created multiple entries for a single key in the
+    # list representation.
+    as_dict = {}
+    for key in msg2.map_int32_foreign_message:
+      self.assertFalse(key in as_dict)
+      as_dict[key] = msg2.map_int32_foreign_message[key].c
+
+    self.assertEqual({111: 5, 222: 10}, as_dict)
+
+    # Special case: test that delete of item really removes the item, even if
+    # there might have physically been duplicate keys due to the previous merge.
+    # This is only a special case for the C++ implementation which stores the
+    # map as an array.
+    del msg2.map_int32_int32[12]
+    self.assertFalse(12 in msg2.map_int32_int32)
+
+    del msg2.map_int32_foreign_message[222]
+    self.assertFalse(222 in msg2.map_int32_foreign_message)
+
+  def testMergeFromBadType(self):
+    msg = map_unittest_pb2.TestMap()
+    with self.assertRaisesRegexp(
+        TypeError,
+        r'Parameter to MergeFrom\(\) must be instance of same class: expected '
+        r'.*TestMap got int\.'):
+      msg.MergeFrom(1)
+
+  def testCopyFromBadType(self):
+    msg = map_unittest_pb2.TestMap()
+    with self.assertRaisesRegexp(
+        TypeError,
+        r'Parameter to [A-Za-z]*From\(\) must be instance of same class: '
+        r'expected .*TestMap got int\.'):
+      msg.CopyFrom(1)
+
+  def testIntegerMapWithLongs(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[long(-123)] = long(-456)
+    msg.map_int64_int64[long(-2**33)] = long(-2**34)
+    msg.map_uint32_uint32[long(123)] = long(456)
+    msg.map_uint64_uint64[long(2**33)] = long(2**34)
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(-456, msg2.map_int32_int32[-123])
+    self.assertEqual(-2**34, msg2.map_int64_int64[-2**33])
+    self.assertEqual(456, msg2.map_uint32_uint32[123])
+    self.assertEqual(2**34, msg2.map_uint64_uint64[2**33])
+
+  def testMapAssignmentCausesPresence(self):
+    msg = map_unittest_pb2.TestMapSubmessage()
+    msg.test_map.map_int32_int32[123] = 456
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMapSubmessage()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(msg, msg2)
+
+    # Now test that various mutations of the map properly invalidate the
+    # cached size of the submessage.
+    msg.test_map.map_int32_int32[888] = 999
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_int32.clear()
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+  def testMapAssignmentCausesPresenceForSubmessages(self):
+    msg = map_unittest_pb2.TestMapSubmessage()
+    msg.test_map.map_int32_foreign_message[123].c = 5
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMapSubmessage()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(msg, msg2)
+
+    # Now test that various mutations of the map properly invalidate the
+    # cached size of the submessage.
+    msg.test_map.map_int32_foreign_message[888].c = 7
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_foreign_message[888].MergeFrom(
+        msg.test_map.map_int32_foreign_message[123])
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_foreign_message.clear()
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+  def testModifyMapWhileIterating(self):
+    msg = map_unittest_pb2.TestMap()
+
+    string_string_iter = iter(msg.map_string_string)
+    int32_foreign_iter = iter(msg.map_int32_foreign_message)
+
+    msg.map_string_string['abc'] = '123'
+    msg.map_int32_foreign_message[5].c = 5
+
+    with self.assertRaises(RuntimeError):
+      for key in string_string_iter:
+        pass
+
+    with self.assertRaises(RuntimeError):
+      for key in int32_foreign_iter:
+        pass
+
+  def testSubmessageMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    submsg = msg.map_int32_foreign_message[111]
+    self.assertIs(submsg, msg.map_int32_foreign_message[111])
+    self.assertIsInstance(submsg, unittest_pb2.ForeignMessage)
+
+    submsg.c = 5
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
+
+    # Doesn't allow direct submessage assignment.
+    with self.assertRaises(ValueError):
+      msg.map_int32_foreign_message[88] = unittest_pb2.ForeignMessage()
+
+  def testMapIteration(self):
+    msg = map_unittest_pb2.TestMap()
+
+    for k, v in msg.map_int32_int32.items():
+      # Should not be reached.
+      self.assertTrue(False)
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+    self.assertEqual(3, len(msg.map_int32_int32))
+
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(msg.map_int32_int32.items(), matching_dict)
+
+  def testMapItems(self):
+    # Map items used to have strange behaviors when use c extension. Because
+    # [] may reorder the map and invalidate any exsting iterators.
+    # TODO(jieluo): Check if [] reordering the map is a bug or intended
+    # behavior.
+    msg = map_unittest_pb2.TestMap()
+    msg.map_string_string['local_init_op'] = ''
+    msg.map_string_string['trainable_variables'] = ''
+    msg.map_string_string['variables'] = ''
+    msg.map_string_string['init_op'] = ''
+    msg.map_string_string['summaries'] = ''
+    items1 = msg.map_string_string.items()
+    items2 = msg.map_string_string.items()
+    self.assertEqual(items1, items2)
+
+  def testMapIterationClearMessage(self):
+    # Iterator needs to work even if message and map are deleted.
+    msg = map_unittest_pb2.TestMap()
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+
+    it = msg.map_int32_int32.items()
+    del msg
+
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(it, matching_dict)
+
+  def testMapConstruction(self):
+    msg = map_unittest_pb2.TestMap(map_int32_int32={1: 2, 3: 4})
+    self.assertEqual(2, msg.map_int32_int32[1])
+    self.assertEqual(4, msg.map_int32_int32[3])
+
+    msg = map_unittest_pb2.TestMap(
+        map_int32_foreign_message={3: unittest_pb2.ForeignMessage(c=5)})
+    self.assertEqual(5, msg.map_int32_foreign_message[3].c)
+
+  def testMapValidAfterFieldCleared(self):
+    # Map needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    int32_map = msg.map_int32_int32
+
+    int32_map[2] = 4
+    int32_map[3] = 6
+    int32_map[4] = 8
+
+    msg.ClearField('map_int32_int32')
+    self.assertEqual(b'', msg.SerializeToString())
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(int32_map.items(), matching_dict)
+
+  def testMessageMapValidAfterFieldCleared(self):
+    # Map needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    int32_foreign_message = msg.map_int32_foreign_message
+
+    int32_foreign_message[2].c = 5
+
+    msg.ClearField('map_int32_foreign_message')
+    self.assertEqual(b'', msg.SerializeToString())
+    self.assertTrue(2 in int32_foreign_message.keys())
+
+  def testMapIterInvalidatedByClearField(self):
+    # Map iterator is invalidated when field is cleared.
+    # But this case does need to not crash the interpreter.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+
+    it = iter(msg.map_int32_int32)
+
+    msg.ClearField('map_int32_int32')
+    with self.assertRaises(RuntimeError):
+      for _ in it:
+        pass
+
+    it = iter(msg.map_int32_foreign_message)
+    msg.ClearField('map_int32_foreign_message')
+    with self.assertRaises(RuntimeError):
+      for _ in it:
+        pass
+
+  def testMapDelete(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_int32))
+
+    msg.map_int32_int32[4] = 6
+    self.assertEqual(1, len(msg.map_int32_int32))
+
+    with self.assertRaises(KeyError):
+      del msg.map_int32_int32[88]
+
+    del msg.map_int32_int32[4]
+    self.assertEqual(0, len(msg.map_int32_int32))
+
+  def testMapsAreMapping(self):
+    msg = map_unittest_pb2.TestMap()
+    self.assertIsInstance(msg.map_int32_int32, collections.Mapping)
+    self.assertIsInstance(msg.map_int32_int32, collections.MutableMapping)
+    self.assertIsInstance(msg.map_int32_foreign_message, collections.Mapping)
+    self.assertIsInstance(msg.map_int32_foreign_message,
+                          collections.MutableMapping)
+
+  def testMapFindInitializationErrorsSmokeTest(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_string_string['abc'] = '123'
+    msg.map_int32_int32[35] = 64
+    msg.map_string_foreign_message['foo'].c = 5
+    self.assertEqual(0, len(msg.FindInitializationErrors()))
+
+
+
+class ValidTypeNamesTest(unittest.TestCase):
 
   def assertImportFromName(self, msg, base_name):
     # Parse <type 'module.class_name'> to extra 'some.name' as a string.
@@ -676,6 +1737,116 @@
     self.assertImportFromName(pb.repeated_int32, 'Scalar')
     self.assertImportFromName(pb.repeated_nested_message, 'Composite')
 
+class PackedFieldTest(unittest.TestCase):
+
+  def setMessage(self, message):
+    message.repeated_int32.append(1)
+    message.repeated_int64.append(1)
+    message.repeated_uint32.append(1)
+    message.repeated_uint64.append(1)
+    message.repeated_sint32.append(1)
+    message.repeated_sint64.append(1)
+    message.repeated_fixed32.append(1)
+    message.repeated_fixed64.append(1)
+    message.repeated_sfixed32.append(1)
+    message.repeated_sfixed64.append(1)
+    message.repeated_float.append(1.0)
+    message.repeated_double.append(1.0)
+    message.repeated_bool.append(True)
+    message.repeated_nested_enum.append(1)
+
+  def testPackedFields(self):
+    message = packed_field_test_pb2.TestPackedTypes()
+    self.setMessage(message)
+    golden_data = (b'\x0A\x01\x01'
+                   b'\x12\x01\x01'
+                   b'\x1A\x01\x01'
+                   b'\x22\x01\x01'
+                   b'\x2A\x01\x02'
+                   b'\x32\x01\x02'
+                   b'\x3A\x04\x01\x00\x00\x00'
+                   b'\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x4A\x04\x01\x00\x00\x00'
+                   b'\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x5A\x04\x00\x00\x80\x3f'
+                   b'\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f'
+                   b'\x6A\x01\x01'
+                   b'\x72\x01\x01')
+    self.assertEqual(golden_data, message.SerializeToString())
+
+  def testUnpackedFields(self):
+    message = packed_field_test_pb2.TestUnpackedTypes()
+    self.setMessage(message)
+    golden_data = (b'\x08\x01'
+                   b'\x10\x01'
+                   b'\x18\x01'
+                   b'\x20\x01'
+                   b'\x28\x02'
+                   b'\x30\x02'
+                   b'\x3D\x01\x00\x00\x00'
+                   b'\x41\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x4D\x01\x00\x00\x00'
+                   b'\x51\x01\x00\x00\x00\x00\x00\x00\x00'
+                   b'\x5D\x00\x00\x80\x3f'
+                   b'\x61\x00\x00\x00\x00\x00\x00\xf0\x3f'
+                   b'\x68\x01'
+                   b'\x70\x01')
+    self.assertEqual(golden_data, message.SerializeToString())
+
+
+@unittest.skipIf(api_implementation.Type() != 'cpp',
+                 'explicit tests of the C++ implementation')
+class OversizeProtosTest(unittest.TestCase):
+
+  def setUp(self):
+    self.file_desc = """
+      name: "f/f.msg2"
+      package: "f"
+      message_type {
+        name: "msg1"
+        field {
+          name: "payload"
+          number: 1
+          label: LABEL_OPTIONAL
+          type: TYPE_STRING
+        }
+      }
+      message_type {
+        name: "msg2"
+        field {
+          name: "field"
+          number: 1
+          label: LABEL_OPTIONAL
+          type: TYPE_MESSAGE
+          type_name: "msg1"
+        }
+      }
+    """
+    pool = descriptor_pool.DescriptorPool()
+    desc = descriptor_pb2.FileDescriptorProto()
+    text_format.Parse(self.file_desc, desc)
+    pool.Add(desc)
+    self.proto_cls = message_factory.MessageFactory(pool).GetPrototype(
+        pool.FindMessageTypeByName('f.msg2'))
+    self.p = self.proto_cls()
+    self.p.field.payload = 'c' * (1024 * 1024 * 64 + 1)
+    self.p_serialized = self.p.SerializeToString()
+
+  def testAssertOversizeProto(self):
+    from google.protobuf.pyext._message import SetAllowOversizeProtos
+    SetAllowOversizeProtos(False)
+    q = self.proto_cls()
+    try:
+      q.ParseFromString(self.p_serialized)
+    except message.DecodeError as e:
+      self.assertEqual(str(e), 'Error parsing message')
+
+  def testSucceedOversizeProto(self):
+    from google.protobuf.pyext._message import SetAllowOversizeProtos
+    SetAllowOversizeProtos(True)
+    q = self.proto_cls()
+    q.ParseFromString(self.p_serialized)
+    self.assertEqual(self.p.field.payload, q.field.payload)
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
index e90f0cd..1850be5 100644
--- a/python/google/protobuf/internal/missing_enum_values.proto
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -28,6 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+syntax = "proto2";
+
 package google.protobuf.python.internal;
 
 message TestEnumValues {
@@ -48,3 +50,7 @@
   repeated NestedEnum repeated_nested_enum = 2;
   repeated NestedEnum packed_nested_enum = 3 [packed = true];
 }
+
+message JustString {
+  required string dummy = 1;
+}
diff --git a/python/google/protobuf/internal/more_extensions.proto b/python/google/protobuf/internal/more_extensions.proto
index c04e597..78f1467 100644
--- a/python/google/protobuf/internal/more_extensions.proto
+++ b/python/google/protobuf/internal/more_extensions.proto
@@ -30,6 +30,7 @@
 
 // Author: robinson@google.com (Will Robinson)
 
+syntax = "proto2";
 
 package google.protobuf.internal;
 
diff --git a/python/google/protobuf/internal/more_extensions_dynamic.proto b/python/google/protobuf/internal/more_extensions_dynamic.proto
index 88bd9c1..11f85ef 100644
--- a/python/google/protobuf/internal/more_extensions_dynamic.proto
+++ b/python/google/protobuf/internal/more_extensions_dynamic.proto
@@ -34,6 +34,7 @@
 // generated C++ type is available for the extendee, but the extension is
 // defined in a file whose C++ type is not in the binary.
 
+syntax = "proto2";
 
 import "google/protobuf/internal/more_extensions.proto";
 
diff --git a/python/google/protobuf/internal/more_messages.proto b/python/google/protobuf/internal/more_messages.proto
index 61db66c..2c6ab9e 100644
--- a/python/google/protobuf/internal/more_messages.proto
+++ b/python/google/protobuf/internal/more_messages.proto
@@ -30,6 +30,7 @@
 
 // Author: robinson@google.com (Will Robinson)
 
+syntax = "proto2";
 
 package google.protobuf.internal;
 
diff --git a/python/google/protobuf/internal/packed_field_test.proto b/python/google/protobuf/internal/packed_field_test.proto
new file mode 100644
index 0000000..0dfdc10
--- /dev/null
+++ b/python/google/protobuf/internal/packed_field_test.proto
@@ -0,0 +1,73 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf.python.internal;
+
+message TestPackedTypes {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+
+  repeated    int32 repeated_int32    =  1;
+  repeated    int64 repeated_int64    =  2;
+  repeated   uint32 repeated_uint32   =  3;
+  repeated   uint64 repeated_uint64   =  4;
+  repeated   sint32 repeated_sint32   =  5;
+  repeated   sint64 repeated_sint64   =  6;
+  repeated  fixed32 repeated_fixed32  =  7;
+  repeated  fixed64 repeated_fixed64  =  8;
+  repeated sfixed32 repeated_sfixed32 =  9;
+  repeated sfixed64 repeated_sfixed64 = 10;
+  repeated    float repeated_float    = 11;
+  repeated   double repeated_double   = 12;
+  repeated     bool repeated_bool     = 13;
+  repeated NestedEnum repeated_nested_enum = 14;
+}
+
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestPackedTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
new file mode 100644
index 0000000..36dfbfd
--- /dev/null
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -0,0 +1,96 @@
+#! /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.
+
+"""Tests for google.protobuf.proto_builder."""
+
+try:
+    from collections import OrderedDict
+except ImportError:
+    from ordereddict import OrderedDict  #PY26
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
+
+from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor_pool
+from google.protobuf import proto_builder
+from google.protobuf import text_format
+
+
+class ProtoBuilderTest(unittest.TestCase):
+
+  def setUp(self):
+    self.ordered_fields = OrderedDict([
+        ('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64),
+        ('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING),
+        ])
+    self._fields = dict(self.ordered_fields)
+
+  def testMakeSimpleProtoClass(self):
+    """Test that we can create a proto class."""
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test')
+    proto = proto_cls()
+    proto.foo = 12345
+    proto.bar = 'asdf'
+    self.assertMultiLineEqual(
+        'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto))
+
+  def testOrderedFields(self):
+    """Test that the field order is maintained when given an OrderedDict."""
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        self.ordered_fields,
+        full_name='net.proto2.python.public.proto_builder_test.OrderedTest')
+    proto = proto_cls()
+    proto.foo = 12345
+    proto.bar = 'asdf'
+    self.assertMultiLineEqual(
+        'foo: 12345\nbar: "asdf"\n', text_format.MessageToString(proto))
+
+  def testMakeSameProtoClassTwice(self):
+    """Test that the DescriptorPool is used."""
+    pool = descriptor_pool.DescriptorPool()
+    proto_cls1 = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test',
+        pool=pool)
+    proto_cls2 = proto_builder.MakeSimpleProtoClass(
+        self._fields,
+        full_name='net.proto2.python.public.proto_builder_test.Test',
+        pool=pool)
+    self.assertIs(proto_cls1.DESCRIPTOR, proto_cls2.DESCRIPTOR)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index a5c26f4..f8f73dd 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -28,10 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Keep it Python2.5 compatible for GAE.
-#
-# Copyright 2007 Google Inc. All Rights Reserved.
-#
 # This code is meant to work on Python 2.4 and above only.
 #
 # TODO(robinson): Helpers for verbose, common checks like seeing if a
@@ -54,19 +50,21 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
+from io import BytesIO
 import sys
-if sys.version_info[0] < 3:
-  try:
-    from cStringIO import StringIO as BytesIO
-  except ImportError:
-    from StringIO import StringIO as BytesIO
-  import copy_reg as copyreg
-else:
-  from io import BytesIO
-  import copyreg
 import struct
 import weakref
 
+import six
+try:
+  import six.moves.copyreg as copyreg
+except ImportError:
+  # On some platforms, for example gMac, we run native Python because there is
+  # nothing like hermetic Python. This means lesser control on the system and
+  # the six.moves package may be missing (is missing on 20150321 on gMac). Be
+  # extra conservative and try to load the old replacement if it fails.
+  import copy_reg as copyreg
+
 # We use "as" to avoid name collisions with variables.
 from google.protobuf.internal import containers
 from google.protobuf.internal import decoder
@@ -74,41 +72,121 @@
 from google.protobuf.internal import enum_type_wrapper
 from google.protobuf.internal import message_listener as message_listener_mod
 from google.protobuf.internal import type_checkers
+from google.protobuf.internal import well_known_types
 from google.protobuf.internal import wire_format
 from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message as message_mod
+from google.protobuf import symbol_database
 from google.protobuf import text_format
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
+_AnyFullTypeName = 'google.protobuf.Any'
 
 
-def NewMessage(bases, descriptor, dictionary):
-  _AddClassAttributesForNestedExtensions(descriptor, dictionary)
-  _AddSlots(descriptor, dictionary)
-  return bases
+class GeneratedProtocolMessageType(type):
 
+  """Metaclass for protocol message classes created at runtime from Descriptors.
 
-def InitMessage(descriptor, cls):
-  cls._decoders_by_tag = {}
-  cls._extensions_by_name = {}
-  cls._extensions_by_number = {}
-  if (descriptor.has_options and
-      descriptor.GetOptions().message_set_wire_format):
-    cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
-        decoder.MessageSetItemDecoder(cls._extensions_by_number), None)
+  We add implementations for all methods described in the Message class.  We
+  also create properties to allow getting/setting all fields in the protocol
+  message.  Finally, we create slots to prevent users from accidentally
+  "setting" nonexistent fields in the protocol message, which then wouldn't get
+  serialized / deserialized properly.
 
-  # Attach stuff to each FieldDescriptor for quick lookup later on.
-  for field in descriptor.fields:
-    _AttachFieldHelpers(cls, field)
+  The protocol compiler currently uses this metaclass to create protocol
+  message classes at runtime.  Clients can also manually create their own
+  classes at runtime, as in this example:
 
-  _AddEnumValues(descriptor, cls)
-  _AddInitMethod(descriptor, cls)
-  _AddPropertiesForFields(descriptor, cls)
-  _AddPropertiesForExtensions(descriptor, cls)
-  _AddStaticMethods(cls)
-  _AddMessageMethods(descriptor, cls)
-  _AddPrivateHelperMethods(descriptor, cls)
-  copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
+  mydescriptor = Descriptor(.....)
+  class MyProtoClass(Message):
+    __metaclass__ = GeneratedProtocolMessageType
+    DESCRIPTOR = mydescriptor
+  myproto_instance = MyProtoClass()
+  myproto.foo_field = 23
+  ...
+
+  The above example will not work for nested types. If you wish to include them,
+  use reflection.MakeClass() instead of manually instantiating the class in
+  order to create the appropriate class structure.
+  """
+
+  # Must be consistent with the protocol-compiler code in
+  # proto2/compiler/internal/generator.*.
+  _DESCRIPTOR_KEY = 'DESCRIPTOR'
+
+  def __new__(cls, name, bases, dictionary):
+    """Custom allocation for runtime-generated class types.
+
+    We override __new__ because this is apparently the only place
+    where we can meaningfully set __slots__ on the class we're creating(?).
+    (The interplay between metaclasses and slots is not very well-documented).
+
+    Args:
+      name: Name of the class (ignored, but required by the
+        metaclass protocol).
+      bases: Base classes of the class we're constructing.
+        (Should be message.Message).  We ignore this field, but
+        it's required by the metaclass protocol
+      dictionary: The class dictionary of the class we're
+        constructing.  dictionary[_DESCRIPTOR_KEY] must contain
+        a Descriptor object describing this protocol message
+        type.
+
+    Returns:
+      Newly-allocated class.
+    """
+    descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+    if descriptor.full_name in well_known_types.WKTBASES:
+      bases += (well_known_types.WKTBASES[descriptor.full_name],)
+    _AddClassAttributesForNestedExtensions(descriptor, dictionary)
+    _AddSlots(descriptor, dictionary)
+
+    superclass = super(GeneratedProtocolMessageType, cls)
+    new_class = superclass.__new__(cls, name, bases, dictionary)
+    return new_class
+
+  def __init__(cls, name, bases, dictionary):
+    """Here we perform the majority of our work on the class.
+    We add enum getters, an __init__ method, implementations
+    of all Message methods, and properties for all fields
+    in the protocol type.
+
+    Args:
+      name: Name of the class (ignored, but required by the
+        metaclass protocol).
+      bases: Base classes of the class we're constructing.
+        (Should be message.Message).  We ignore this field, but
+        it's required by the metaclass protocol
+      dictionary: The class dictionary of the class we're
+        constructing.  dictionary[_DESCRIPTOR_KEY] must contain
+        a Descriptor object describing this protocol message
+        type.
+    """
+    descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+    cls._decoders_by_tag = {}
+    cls._extensions_by_name = {}
+    cls._extensions_by_number = {}
+    if (descriptor.has_options and
+        descriptor.GetOptions().message_set_wire_format):
+      cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
+          decoder.MessageSetItemDecoder(cls._extensions_by_number), None)
+
+    # Attach stuff to each FieldDescriptor for quick lookup later on.
+    for field in descriptor.fields:
+      _AttachFieldHelpers(cls, field)
+
+    descriptor._concrete_class = cls  # pylint: disable=protected-access
+    _AddEnumValues(descriptor, cls)
+    _AddInitMethod(descriptor, cls)
+    _AddPropertiesForFields(descriptor, cls)
+    _AddPropertiesForExtensions(descriptor, cls)
+    _AddStaticMethods(cls)
+    _AddMessageMethods(descriptor, cls)
+    _AddPrivateHelperMethods(descriptor, cls)
+    copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
+
+    superclass = super(GeneratedProtocolMessageType, cls)
+    superclass.__init__(name, bases, dictionary)
 
 
 # Stateless helpers for GeneratedProtocolMessageType below.
@@ -194,16 +272,40 @@
           field.containing_type.has_options and
           field.containing_type.GetOptions().message_set_wire_format and
           field.type == _FieldDescriptor.TYPE_MESSAGE and
-          field.message_type == field.extension_scope and
           field.label == _FieldDescriptor.LABEL_OPTIONAL)
 
 
+def _IsMapField(field):
+  return (field.type == _FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
+def _IsMessageMapField(field):
+  value_type = field.message_type.fields_by_name["value"]
+  return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
+
+
 def _AttachFieldHelpers(cls, field_descriptor):
   is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED)
-  is_packed = (field_descriptor.has_options and
-               field_descriptor.GetOptions().packed)
+  is_packable = (is_repeated and
+                 wire_format.IsTypePackable(field_descriptor.type))
+  if not is_packable:
+    is_packed = False
+  elif field_descriptor.containing_type.syntax == "proto2":
+    is_packed = (field_descriptor.has_options and
+                field_descriptor.GetOptions().packed)
+  else:
+    has_packed_false = (field_descriptor.has_options and
+                        field_descriptor.GetOptions().HasField("packed") and
+                        field_descriptor.GetOptions().packed == False)
+    is_packed = not has_packed_false
+  is_map_entry = _IsMapField(field_descriptor)
 
-  if _IsMessageSetExtension(field_descriptor):
+  if is_map_entry:
+    field_encoder = encoder.MapEncoder(field_descriptor)
+    sizer = encoder.MapSizer(field_descriptor)
+  elif _IsMessageSetExtension(field_descriptor):
     field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number)
     sizer = encoder.MessageSetItemSizer(field_descriptor.number)
   else:
@@ -219,12 +321,27 @@
 
   def AddDecoder(wiretype, is_packed):
     tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype)
-    cls._decoders_by_tag[tag_bytes] = (
-        type_checkers.TYPE_TO_DECODER[field_descriptor.type](
-            field_descriptor.number, is_repeated, is_packed,
-            field_descriptor, field_descriptor._default_constructor),
-        field_descriptor if field_descriptor.containing_oneof is not None
-        else None)
+    decode_type = field_descriptor.type
+    if (decode_type == _FieldDescriptor.TYPE_ENUM and
+        type_checkers.SupportsOpenEnums(field_descriptor)):
+      decode_type = _FieldDescriptor.TYPE_INT32
+
+    oneof_descriptor = None
+    if field_descriptor.containing_oneof is not None:
+      oneof_descriptor = field_descriptor
+
+    if is_map_entry:
+      is_message_map = _IsMessageMapField(field_descriptor)
+
+      field_decoder = decoder.MapDecoder(
+          field_descriptor, _GetInitializeDefaultForMap(field_descriptor),
+          is_message_map)
+    else:
+      field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
+              field_descriptor.number, is_repeated, is_packed,
+              field_descriptor, field_descriptor._default_constructor)
+
+    cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
 
   AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type],
              False)
@@ -237,7 +354,7 @@
 
 def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
   extension_dict = descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.iteritems():
+  for extension_name, extension_field in extension_dict.items():
     assert extension_name not in dictionary
     dictionary[extension_name] = extension_field
 
@@ -257,6 +374,26 @@
       setattr(cls, enum_value.name, enum_value.number)
 
 
+def _GetInitializeDefaultForMap(field):
+  if field.label != _FieldDescriptor.LABEL_REPEATED:
+    raise ValueError('map_entry set on non-repeated field %s' % (
+        field.name))
+  fields_by_name = field.message_type.fields_by_name
+  key_checker = type_checkers.GetTypeChecker(fields_by_name['key'])
+
+  value_field = fields_by_name['value']
+  if _IsMessageMapField(field):
+    def MakeMessageMapDefault(message):
+      return containers.MessageMap(
+          message._listener_for_children, value_field.message_type, key_checker)
+    return MakeMessageMapDefault
+  else:
+    value_checker = type_checkers.GetTypeChecker(value_field)
+    def MakePrimitiveMapDefault(message):
+      return containers.ScalarMap(
+          message._listener_for_children, key_checker, value_checker)
+    return MakePrimitiveMapDefault
+
 def _DefaultValueConstructorForField(field):
   """Returns a function which returns a default value for a field.
 
@@ -271,6 +408,9 @@
     value may refer back to |message| via a weak reference.
   """
 
+  if _IsMapField(field):
+    return _GetInitializeDefaultForMap(field)
+
   if field.label == _FieldDescriptor.LABEL_REPEATED:
     if field.has_default_value and field.default_value != []:
       raise ValueError('Repeated field default value not empty list: %s' % (
@@ -295,7 +435,10 @@
     message_type = field.message_type
     def MakeSubMessageDefault(message):
       result = message_type._concrete_class()
-      result._SetListener(message._listener_for_children)
+      result._SetListener(
+          _OneofListener(message, field)
+          if field.containing_oneof is not None
+          else message._listener_for_children)
       return result
     return MakeSubMessageDefault
 
@@ -306,9 +449,35 @@
   return MakeScalarDefault
 
 
+def _ReraiseTypeErrorWithFieldName(message_name, field_name):
+  """Re-raise the currently-handled TypeError with the field name added."""
+  exc = sys.exc_info()[1]
+  if len(exc.args) == 1 and type(exc) is TypeError:
+    # simple TypeError; add field name to exception message
+    exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name))
+
+  # re-raise possibly-amended exception with original traceback:
+  six.reraise(type(exc), exc, sys.exc_info()[2])
+
+
 def _AddInitMethod(message_descriptor, cls):
   """Adds an __init__ method to cls."""
-  fields = message_descriptor.fields
+
+  def _GetIntegerEnumValue(enum_type, value):
+    """Convert a string or integer enum value to an integer.
+
+    If the value is a string, it is converted to the enum value in
+    enum_type with the same name.  If the value is not a string, it's
+    returned as-is.  (No conversion or bounds-checking is done.)
+    """
+    if isinstance(value, six.string_types):
+      try:
+        return enum_type.values_by_name[value].number
+      except KeyError:
+        raise ValueError('Enum type %s: unknown label "%s"' % (
+            enum_type.full_name, value))
+    return value
+
   def init(self, **kwargs):
     self._cached_byte_size = 0
     self._cached_byte_size_dirty = len(kwargs) > 0
@@ -323,25 +492,52 @@
     self._is_present_in_parent = False
     self._listener = message_listener_mod.NullMessageListener()
     self._listener_for_children = _Listener(self)
-    for field_name, field_value in kwargs.iteritems():
+    for field_name, field_value in kwargs.items():
       field = _GetFieldByName(message_descriptor, field_name)
       if field is None:
         raise TypeError("%s() got an unexpected keyword argument '%s'" %
                         (message_descriptor.name, field_name))
+      if field_value is None:
+        # field=None is the same as no field at all.
+        continue
       if field.label == _FieldDescriptor.LABEL_REPEATED:
         copy = field._default_constructor(self)
         if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:  # Composite
-          for val in field_value:
-            copy.add().MergeFrom(val)
+          if _IsMapField(field):
+            if _IsMessageMapField(field):
+              for key in field_value:
+                copy[key].MergeFrom(field_value[key])
+            else:
+              copy.update(field_value)
+          else:
+            for val in field_value:
+              if isinstance(val, dict):
+                copy.add(**val)
+              else:
+                copy.add().MergeFrom(val)
         else:  # Scalar
+          if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+            field_value = [_GetIntegerEnumValue(field.enum_type, val)
+                           for val in field_value]
           copy.extend(field_value)
         self._fields[field] = copy
       elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
         copy = field._default_constructor(self)
-        copy.MergeFrom(field_value)
+        new_val = field_value
+        if isinstance(field_value, dict):
+          new_val = field.message_type._concrete_class(**field_value)
+        try:
+          copy.MergeFrom(new_val)
+        except TypeError:
+          _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
         self._fields[field] = copy
       else:
-        setattr(self, field_name, field_value)
+        if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+          field_value = _GetIntegerEnumValue(field.enum_type, field_value)
+        try:
+          setattr(self, field_name, field_value)
+        except TypeError:
+          _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
 
   init.__module__ = None
   init.__doc__ = None
@@ -360,7 +556,8 @@
   try:
     return message_descriptor.fields_by_name[field_name]
   except KeyError:
-    raise ValueError('Protocol message has no "%s" field.' % field_name)
+    raise ValueError('Protocol message %s has no "%s" field.' %
+                     (message_descriptor.name, field_name))
 
 
 def _AddPropertiesForFields(descriptor, cls):
@@ -459,6 +656,7 @@
   type_checker = type_checkers.GetTypeChecker(field)
   default_value = field.default_value
   valid_values = set()
+  is_proto3 = field.containing_type.syntax == "proto3"
 
   def getter(self):
     # TODO(protobuf-team): This may be broken since there may not be
@@ -466,15 +664,24 @@
     return self._fields.get(field, default_value)
   getter.__module__ = None
   getter.__doc__ = 'Getter for %s.' % proto_field_name
+
+  clear_when_set_to_default = is_proto3 and not field.containing_oneof
+
   def field_setter(self, new_value):
     # pylint: disable=protected-access
-    self._fields[field] = type_checker.CheckValue(new_value)
+    # Testing the value for truthiness captures all of the proto3 defaults
+    # (0, 0.0, enum 0, and False).
+    new_value = type_checker.CheckValue(new_value)
+    if clear_when_set_to_default and not new_value:
+      self._fields.pop(field, None)
+    else:
+      self._fields[field] = new_value
     # Check _cached_byte_size_dirty inline to improve performance, since scalar
     # setters are called frequently.
     if not self._cached_byte_size_dirty:
       self._Modified()
 
-  if field.containing_oneof is not None:
+  if field.containing_oneof:
     def setter(self, new_value):
       field_setter(self, new_value)
       self._UpdateOneofState(field)
@@ -505,21 +712,11 @@
   proto_field_name = field.name
   property_name = _PropertyName(proto_field_name)
 
-  # TODO(komarek): Can anyone explain to me why we cache the message_type this
-  # way, instead of referring to field.message_type inside of getter(self)?
-  # What if someone sets message_type later on (which makes for simpler
-  # dyanmic proto descriptor and class creation code).
-  message_type = field.message_type
-
   def getter(self):
     field_value = self._fields.get(field)
     if field_value is None:
       # Construct a new object to represent this field.
-      field_value = message_type._concrete_class()  # use field.message_type?
-      field_value._SetListener(
-          _OneofListener(self, field)
-          if field.containing_oneof is not None
-          else self._listener_for_children)
+      field_value = field._default_constructor(self)
 
       # Atomically check if another thread has preempted us and, if not, swap
       # in the new object we just created.  If someone has preempted us, we
@@ -546,7 +743,7 @@
 def _AddPropertiesForExtensions(descriptor, cls):
   """Adds properties for all fields in this protocol message type."""
   extension_dict = descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.iteritems():
+  for extension_name, extension_field in extension_dict.items():
     constant_name = extension_name.upper() + "_FIELD_NUMBER"
     setattr(cls, constant_name, extension_field.number)
 
@@ -601,30 +798,41 @@
   """Helper for _AddMessageMethods()."""
 
   def ListFields(self):
-    all_fields = [item for item in self._fields.iteritems() if _IsPresent(item)]
+    all_fields = [item for item in self._fields.items() if _IsPresent(item)]
     all_fields.sort(key = lambda item: item[0].number)
     return all_fields
 
   cls.ListFields = ListFields
 
+_Proto3HasError = 'Protocol message has no non-repeated submessage field "%s"'
+_Proto2HasError = 'Protocol message has no non-repeated field "%s"'
 
 def _AddHasFieldMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
 
-  singular_fields = {}
+  is_proto3 = (message_descriptor.syntax == "proto3")
+  error_msg = _Proto3HasError if is_proto3 else _Proto2HasError
+
+  hassable_fields = {}
   for field in message_descriptor.fields:
-    if field.label != _FieldDescriptor.LABEL_REPEATED:
-      singular_fields[field.name] = field
-  # Fields inside oneofs are never repeated (enforced by the compiler).
-  for field in message_descriptor.oneofs:
-    singular_fields[field.name] = field
+    if field.label == _FieldDescriptor.LABEL_REPEATED:
+      continue
+    # For proto3, only submessages and fields inside a oneof have presence.
+    if (is_proto3 and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE and
+        not field.containing_oneof):
+      continue
+    hassable_fields[field.name] = field
+
+  if not is_proto3:
+    # Fields inside oneofs are never repeated (enforced by the compiler).
+    for oneof in message_descriptor.oneofs:
+      hassable_fields[oneof.name] = oneof
 
   def HasField(self, field_name):
     try:
-      field = singular_fields[field_name]
+      field = hassable_fields[field_name]
     except KeyError:
-      raise ValueError(
-          'Protocol message has no singular "%s" field.' % field_name)
+      raise ValueError(error_msg % field_name)
 
     if isinstance(field, descriptor_mod.OneofDescriptor):
       try:
@@ -654,9 +862,15 @@
         else:
           return
       except KeyError:
-        raise ValueError('Protocol message has no "%s" field.' % field_name)
+        raise ValueError('Protocol message %s() has no "%s" field.' %
+                         (message_descriptor.name, field_name))
 
     if field in self._fields:
+      # To match the C++ implementation, we need to invalidate iterators
+      # for map fields when ClearField() happens.
+      if hasattr(self._fields[field], 'InvalidateIterators'):
+        self._fields[field].InvalidateIterators()
+
       # Note:  If the field is a sub-message, its listener will still point
       #   at us.  That's fine, because the worst than can happen is that it
       #   will call _Modified() and invalidate our byte size.  Big deal.
@@ -685,16 +899,6 @@
   cls.ClearExtension = ClearExtension
 
 
-def _AddClearMethod(message_descriptor, cls):
-  """Helper for _AddMessageMethods()."""
-  def Clear(self):
-    # Clear fields.
-    self._fields = {}
-    self._unknown_fields = ()
-    self._Modified()
-  cls.Clear = Clear
-
-
 def _AddHasExtensionMethod(cls):
   """Helper for _AddMessageMethods()."""
   def HasExtension(self, extension_handle):
@@ -709,6 +913,38 @@
       return extension_handle in self._fields
   cls.HasExtension = HasExtension
 
+def _InternalUnpackAny(msg):
+  """Unpacks Any message and returns the unpacked message.
+
+  This internal method is differnt from public Any Unpack method which takes
+  the target message as argument. _InternalUnpackAny method does not have
+  target message type and need to find the message type in descriptor pool.
+
+  Args:
+    msg: An Any message to be unpacked.
+
+  Returns:
+    The unpacked message.
+  """
+  type_url = msg.type_url
+  db = symbol_database.Default()
+
+  if not type_url:
+    return None
+
+  # TODO(haberman): For now we just strip the hostname.  Better logic will be
+  # required.
+  type_name = type_url.split("/")[-1]
+  descriptor = db.pool.FindMessageTypeByName(type_name)
+
+  if descriptor is None:
+    return None
+
+  message_class = db.GetPrototype(descriptor)
+  message = message_class()
+
+  message.ParseFromString(msg.value)
+  return message
 
 def _AddEqualsMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
@@ -720,6 +956,12 @@
     if self is other:
       return True
 
+    if self.DESCRIPTOR.full_name == _AnyFullTypeName:
+      any_a = _InternalUnpackAny(self)
+      any_b = _InternalUnpackAny(other)
+      if any_a and any_b:
+        return any_a == any_b
+
     if not self.ListFields() == other.ListFields():
       return False
 
@@ -741,6 +983,13 @@
   cls.__str__ = __str__
 
 
+def _AddReprMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def __repr__(self):
+    return text_format.MessageToString(self)
+  cls.__repr__ = __repr__
+
+
 def _AddUnicodeMethod(unused_message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
 
@@ -749,16 +998,6 @@
   cls.__unicode__ = __unicode__
 
 
-def _AddSetListenerMethod(cls):
-  """Helper for _AddMessageMethods()."""
-  def SetListener(self, listener):
-    if listener is None:
-      self._listener = message_listener_mod.NullMessageListener()
-    else:
-      self._listener = listener
-  cls._SetListener = SetListener
-
-
 def _BytesForNonRepeatedElement(value, field_number, field_type):
   """Returns the number of bytes needed to serialize a non-repeated element.
   The returned byte count includes space for tag information and any
@@ -845,7 +1084,7 @@
     except (IndexError, TypeError):
       # Now ord(buf[p:p+1]) == ord('') gets TypeError.
       raise message_mod.DecodeError('Truncated message.')
-    except struct.error, e:
+    except struct.error as e:
       raise message_mod.DecodeError(e)
     return length   # Return this for legacy reasons.
   cls.MergeFromString = MergeFromString
@@ -853,6 +1092,7 @@
   local_ReadTag = decoder.ReadTag
   local_SkipField = decoder.SkipField
   decoders_by_tag = cls._decoders_by_tag
+  is_proto3 = message_descriptor.syntax == "proto3"
 
   def InternalParse(self, buffer, pos, end):
     self._Modified()
@@ -866,9 +1106,11 @@
         new_pos = local_SkipField(buffer, new_pos, end, tag_bytes)
         if new_pos == -1:
           return pos
-        if not unknown_field_list:
-          unknown_field_list = self._unknown_fields = []
-        unknown_field_list.append((tag_bytes, buffer[value_start_pos:new_pos]))
+        if not is_proto3:
+          if not unknown_field_list:
+            unknown_field_list = self._unknown_fields = []
+          unknown_field_list.append(
+              (tag_bytes, buffer[value_start_pos:new_pos]))
         pos = new_pos
       else:
         pos = field_decoder(buffer, new_pos, end, self, field_dict)
@@ -909,6 +1151,9 @@
     for field, value in list(self._fields.items()):  # dict can change size!
       if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
         if field.label == _FieldDescriptor.LABEL_REPEATED:
+          if (field.message_type.has_options and
+              field.message_type.GetOptions().map_entry):
+            continue
           for element in value:
             if not element.IsInitialized():
               if errors is not None:
@@ -944,16 +1189,26 @@
         else:
           name = field.name
 
-        if field.label == _FieldDescriptor.LABEL_REPEATED:
-          for i in xrange(len(value)):
+        if _IsMapField(field):
+          if _IsMessageMapField(field):
+            for key in value:
+              element = value[key]
+              prefix = "%s[%s]." % (name, key)
+              sub_errors = element.FindInitializationErrors()
+              errors += [prefix + error for error in sub_errors]
+          else:
+            # ScalarMaps can't have any initialization errors.
+            pass
+        elif field.label == _FieldDescriptor.LABEL_REPEATED:
+          for i in range(len(value)):
             element = value[i]
             prefix = "%s[%d]." % (name, i)
             sub_errors = element.FindInitializationErrors()
-            errors += [ prefix + error for error in sub_errors ]
+            errors += [prefix + error for error in sub_errors]
         else:
           prefix = name + "."
           sub_errors = value.FindInitializationErrors()
-          errors += [ prefix + error for error in sub_errors ]
+          errors += [prefix + error for error in sub_errors]
 
     return errors
 
@@ -975,7 +1230,7 @@
 
     fields = self._fields
 
-    for field, value in msg._fields.iteritems():
+    for field, value in msg._fields.items():
       if field.label == LABEL_REPEATED:
         field_value = fields.get(field)
         if field_value is None:
@@ -993,6 +1248,8 @@
           field_value.MergeFrom(value)
       else:
         self._fields[field] = value
+        if field.containing_oneof:
+          self._UpdateOneofState(field)
 
     if msg._unknown_fields:
       if not self._unknown_fields:
@@ -1020,6 +1277,32 @@
   cls.WhichOneof = WhichOneof
 
 
+def _Clear(self):
+  # Clear fields.
+  self._fields = {}
+  self._unknown_fields = ()
+  self._oneofs = {}
+  self._Modified()
+
+
+def _DiscardUnknownFields(self):
+  self._unknown_fields = []
+  for field, value in self.ListFields():
+    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      if field.label == _FieldDescriptor.LABEL_REPEATED:
+        for sub_message in value:
+          sub_message.DiscardUnknownFields()
+      else:
+        value.DiscardUnknownFields()
+
+
+def _SetListener(self, listener):
+  if listener is None:
+    self._listener = message_listener_mod.NullMessageListener()
+  else:
+    self._listener = listener
+
+
 def _AddMessageMethods(message_descriptor, cls):
   """Adds implementations of all Message methods to cls."""
   _AddListFieldsMethod(message_descriptor, cls)
@@ -1028,11 +1311,10 @@
   if message_descriptor.is_extendable:
     _AddClearExtensionMethod(cls)
     _AddHasExtensionMethod(cls)
-  _AddClearMethod(message_descriptor, cls)
   _AddEqualsMethod(message_descriptor, cls)
   _AddStrMethod(message_descriptor, cls)
+  _AddReprMethod(message_descriptor, cls)
   _AddUnicodeMethod(message_descriptor, cls)
-  _AddSetListenerMethod(cls)
   _AddByteSizeMethod(message_descriptor, cls)
   _AddSerializeToStringMethod(message_descriptor, cls)
   _AddSerializePartialToStringMethod(message_descriptor, cls)
@@ -1040,6 +1322,11 @@
   _AddIsInitializedMethod(message_descriptor, cls)
   _AddMergeFromMethod(cls)
   _AddWhichOneofMethod(message_descriptor, cls)
+  # Adds methods which do not depend on cls.
+  cls.Clear = _Clear
+  cls.DiscardUnknownFields = _DiscardUnknownFields
+  cls._SetListener = _SetListener
+
 
 def _AddPrivateHelperMethods(message_descriptor, cls):
   """Adds implementation of private helper methods to cls."""
@@ -1232,11 +1519,10 @@
 
     # It's slightly wasteful to lookup the type checker each time,
     # but we expect this to be a vanishingly uncommon case anyway.
-    type_checker = type_checkers.GetTypeChecker(
-        extension_handle)
+    type_checker = type_checkers.GetTypeChecker(extension_handle)
     # pylint: disable=protected-access
     self._extended_message._fields[extension_handle] = (
-      type_checker.CheckValue(value))
+        type_checker.CheckValue(value))
     self._extended_message._Modified()
 
   def _FindExtensionByName(self, name):
@@ -1249,3 +1535,14 @@
       Extension field descriptor.
     """
     return self._extended_message._extensions_by_name.get(name, None)
+
+  def _FindExtensionByNumber(self, number):
+    """Tries to find a known extension with the field number.
+
+    Args:
+      number: Extension field number.
+
+    Returns:
+      Extension field descriptor.
+    """
+    return self._extended_message._extensions_by_number.get(number, None)
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index d59815d..6dc2fff 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 # -*- coding: utf-8 -*-
 #
 # Protocol Buffers - Google's data interchange format
@@ -35,14 +35,17 @@
 pure-Python protocol compiler.
 """
 
-__author__ = 'robinson@google.com (Will Robinson)'
-
 import copy
 import gc
 import operator
+import six
 import struct
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
@@ -54,6 +57,7 @@
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import more_extensions_pb2
 from google.protobuf.internal import more_messages_pb2
+from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf.internal import wire_format
 from google.protobuf.internal import test_util
 from google.protobuf.internal import decoder
@@ -104,7 +108,7 @@
     return self._pos == len(self._bytes)
 
 
-class ReflectionTest(basetest.TestCase):
+class ReflectionTest(unittest.TestCase):
 
   def assertListsEqual(self, values, others):
     self.assertEqual(len(values), len(others))
@@ -116,11 +120,13 @@
     proto = unittest_pb2.TestAllTypes(
         optional_int32=24,
         optional_double=54.321,
-        optional_string='optional_string')
+        optional_string='optional_string',
+        optional_float=None)
 
     self.assertEqual(24, proto.optional_int32)
     self.assertEqual(54.321, proto.optional_double)
     self.assertEqual('optional_string', proto.optional_string)
+    self.assertFalse(proto.HasField("optional_float"))
 
   def testRepeatedScalarConstructor(self):
     # Constructor with only repeated scalar types should succeed.
@@ -128,12 +134,14 @@
         repeated_int32=[1, 2, 3, 4],
         repeated_double=[1.23, 54.321],
         repeated_bool=[True, False, False],
-        repeated_string=["optional_string"])
+        repeated_string=["optional_string"],
+        repeated_float=None)
 
-    self.assertEquals([1, 2, 3, 4], list(proto.repeated_int32))
-    self.assertEquals([1.23, 54.321], list(proto.repeated_double))
-    self.assertEquals([True, False, False], list(proto.repeated_bool))
-    self.assertEquals(["optional_string"], list(proto.repeated_string))
+    self.assertEqual([1, 2, 3, 4], list(proto.repeated_int32))
+    self.assertEqual([1.23, 54.321], list(proto.repeated_double))
+    self.assertEqual([True, False, False], list(proto.repeated_bool))
+    self.assertEqual(["optional_string"], list(proto.repeated_string))
+    self.assertEqual([], list(proto.repeated_float))
 
   def testRepeatedCompositeConstructor(self):
     # Constructor with only repeated composite types should succeed.
@@ -152,18 +160,18 @@
             unittest_pb2.TestAllTypes.RepeatedGroup(a=1),
             unittest_pb2.TestAllTypes.RepeatedGroup(a=2)])
 
-    self.assertEquals(
+    self.assertEqual(
         [unittest_pb2.TestAllTypes.NestedMessage(
             bb=unittest_pb2.TestAllTypes.FOO),
          unittest_pb2.TestAllTypes.NestedMessage(
              bb=unittest_pb2.TestAllTypes.BAR)],
         list(proto.repeated_nested_message))
-    self.assertEquals(
+    self.assertEqual(
         [unittest_pb2.ForeignMessage(c=-43),
          unittest_pb2.ForeignMessage(c=45324),
          unittest_pb2.ForeignMessage(c=12)],
         list(proto.repeated_foreign_message))
-    self.assertEquals(
+    self.assertEqual(
         [unittest_pb2.TestAllTypes.RepeatedGroup(),
          unittest_pb2.TestAllTypes.RepeatedGroup(a=1),
          unittest_pb2.TestAllTypes.RepeatedGroup(a=2)],
@@ -184,23 +192,25 @@
         repeated_foreign_message=[
             unittest_pb2.ForeignMessage(c=-43),
             unittest_pb2.ForeignMessage(c=45324),
-            unittest_pb2.ForeignMessage(c=12)])
+            unittest_pb2.ForeignMessage(c=12)],
+        optional_nested_message=None)
 
     self.assertEqual(24, proto.optional_int32)
     self.assertEqual('optional_string', proto.optional_string)
-    self.assertEquals([1.23, 54.321], list(proto.repeated_double))
-    self.assertEquals([True, False, False], list(proto.repeated_bool))
-    self.assertEquals(
+    self.assertEqual([1.23, 54.321], list(proto.repeated_double))
+    self.assertEqual([True, False, False], list(proto.repeated_bool))
+    self.assertEqual(
         [unittest_pb2.TestAllTypes.NestedMessage(
             bb=unittest_pb2.TestAllTypes.FOO),
          unittest_pb2.TestAllTypes.NestedMessage(
              bb=unittest_pb2.TestAllTypes.BAR)],
         list(proto.repeated_nested_message))
-    self.assertEquals(
+    self.assertEqual(
         [unittest_pb2.ForeignMessage(c=-43),
          unittest_pb2.ForeignMessage(c=45324),
          unittest_pb2.ForeignMessage(c=12)],
         list(proto.repeated_foreign_message))
+    self.assertFalse(proto.HasField("optional_nested_message"))
 
   def testConstructorTypeError(self):
     self.assertRaises(
@@ -224,18 +234,18 @@
 
   def testConstructorInvalidatesCachedByteSize(self):
     message = unittest_pb2.TestAllTypes(optional_int32 = 12)
-    self.assertEquals(2, message.ByteSize())
+    self.assertEqual(2, message.ByteSize())
 
     message = unittest_pb2.TestAllTypes(
         optional_nested_message = unittest_pb2.TestAllTypes.NestedMessage())
-    self.assertEquals(3, message.ByteSize())
+    self.assertEqual(3, message.ByteSize())
 
     message = unittest_pb2.TestAllTypes(repeated_int32 = [12])
-    self.assertEquals(3, message.ByteSize())
+    self.assertEqual(3, message.ByteSize())
 
     message = unittest_pb2.TestAllTypes(
         repeated_nested_message = [unittest_pb2.TestAllTypes.NestedMessage()])
-    self.assertEquals(3, message.ByteSize())
+    self.assertEqual(3, message.ByteSize())
 
   def testSimpleHasBits(self):
     # Test a scalar.
@@ -469,7 +479,7 @@
     proto.repeated_string.extend(['foo', 'bar'])
     proto.repeated_string.extend([])
     proto.repeated_string.append('baz')
-    proto.repeated_string.extend(str(x) for x in xrange(2))
+    proto.repeated_string.extend(str(x) for x in range(2))
     proto.optional_int32 = 21
     proto.repeated_bool  # Access but don't set anything; should not be listed.
     self.assertEqual(
@@ -611,14 +621,18 @@
     def TestGetAndDeserialize(field_name, value, expected_type):
       proto = unittest_pb2.TestAllTypes()
       setattr(proto, field_name, value)
-      self.assertTrue(isinstance(getattr(proto, field_name), expected_type))
+      self.assertIsInstance(getattr(proto, field_name), expected_type)
       proto2 = unittest_pb2.TestAllTypes()
       proto2.ParseFromString(proto.SerializeToString())
-      self.assertTrue(isinstance(getattr(proto2, field_name), expected_type))
+      self.assertIsInstance(getattr(proto2, field_name), expected_type)
 
     TestGetAndDeserialize('optional_int32', 1, int)
     TestGetAndDeserialize('optional_int32', 1 << 30, int)
     TestGetAndDeserialize('optional_uint32', 1 << 30, int)
+    try:
+      integer_64 = long
+    except NameError: # Python3
+      integer_64 = int
     if struct.calcsize('L') == 4:
       # Python only has signed ints, so 32-bit python can't fit an uint32
       # in an int.
@@ -626,10 +640,10 @@
     else:
       # 64-bit python can fit uint32 inside an int
       TestGetAndDeserialize('optional_uint32', 1 << 31, int)
-    TestGetAndDeserialize('optional_int64', 1 << 30, long)
-    TestGetAndDeserialize('optional_int64', 1 << 60, long)
-    TestGetAndDeserialize('optional_uint64', 1 << 30, long)
-    TestGetAndDeserialize('optional_uint64', 1 << 60, long)
+    TestGetAndDeserialize('optional_int64', 1 << 30, integer_64)
+    TestGetAndDeserialize('optional_int64', 1 << 60, integer_64)
+    TestGetAndDeserialize('optional_uint64', 1 << 30, integer_64)
+    TestGetAndDeserialize('optional_uint64', 1 << 60, integer_64)
 
   def testSingleScalarBoundsChecking(self):
     def TestMinAndMaxIntegers(field_name, expected_min, expected_max):
@@ -755,18 +769,18 @@
 
   def testEnum_KeysAndValues(self):
     self.assertEqual(['FOREIGN_FOO', 'FOREIGN_BAR', 'FOREIGN_BAZ'],
-                     unittest_pb2.ForeignEnum.keys())
+                     list(unittest_pb2.ForeignEnum.keys()))
     self.assertEqual([4, 5, 6],
-                     unittest_pb2.ForeignEnum.values())
+                     list(unittest_pb2.ForeignEnum.values()))
     self.assertEqual([('FOREIGN_FOO', 4), ('FOREIGN_BAR', 5),
                       ('FOREIGN_BAZ', 6)],
-                     unittest_pb2.ForeignEnum.items())
+                     list(unittest_pb2.ForeignEnum.items()))
 
     proto = unittest_pb2.TestAllTypes()
-    self.assertEqual(['FOO', 'BAR', 'BAZ', 'NEG'], proto.NestedEnum.keys())
-    self.assertEqual([1, 2, 3, -1], proto.NestedEnum.values())
+    self.assertEqual(['FOO', 'BAR', 'BAZ', 'NEG'], list(proto.NestedEnum.keys()))
+    self.assertEqual([1, 2, 3, -1], list(proto.NestedEnum.values()))
     self.assertEqual([('FOO', 1), ('BAR', 2), ('BAZ', 3), ('NEG', -1)],
-                     proto.NestedEnum.items())
+                     list(proto.NestedEnum.items()))
 
   def testRepeatedScalars(self):
     proto = unittest_pb2.TestAllTypes()
@@ -805,7 +819,7 @@
     self.assertEqual([5, 25, 20, 15, 30], proto.repeated_int32[:])
 
     # Test slice assignment with an iterator
-    proto.repeated_int32[1:4] = (i for i in xrange(3))
+    proto.repeated_int32[1:4] = (i for i in range(3))
     self.assertEqual([5, 0, 1, 2, 30], proto.repeated_int32)
 
     # Test slice assignment.
@@ -896,7 +910,7 @@
     self.assertTrue(proto.repeated_nested_message)
     self.assertEqual(2, len(proto.repeated_nested_message))
     self.assertListsEqual([m0, m1], proto.repeated_nested_message)
-    self.assertTrue(isinstance(m0, unittest_pb2.TestAllTypes.NestedMessage))
+    self.assertIsInstance(m0, unittest_pb2.TestAllTypes.NestedMessage)
 
     # Test out-of-bounds indices.
     self.assertRaises(IndexError, proto.repeated_nested_message.__getitem__,
@@ -1008,9 +1022,8 @@
         containing_type=None, nested_types=[], enum_types=[],
         fields=[foo_field_descriptor], extensions=[],
         options=descriptor_pb2.MessageOptions())
-    class MyProtoClass(message.Message):
+    class MyProtoClass(six.with_metaclass(reflection.GeneratedProtocolMessageType, message.Message)):
       DESCRIPTOR = mydescriptor
-      __metaclass__ = reflection.GeneratedProtocolMessageType
     myproto_instance = MyProtoClass()
     self.assertEqual(0, myproto_instance.foo_field)
     self.assertTrue(not myproto_instance.HasField('foo_field'))
@@ -1050,14 +1063,13 @@
     new_field.label = descriptor_pb2.FieldDescriptorProto.LABEL_REPEATED
 
     desc = descriptor.MakeDescriptor(desc_proto)
-    self.assertTrue(desc.fields_by_name.has_key('name'))
-    self.assertTrue(desc.fields_by_name.has_key('year'))
-    self.assertTrue(desc.fields_by_name.has_key('automatic'))
-    self.assertTrue(desc.fields_by_name.has_key('price'))
-    self.assertTrue(desc.fields_by_name.has_key('owners'))
+    self.assertTrue('name' in desc.fields_by_name)
+    self.assertTrue('year' in desc.fields_by_name)
+    self.assertTrue('automatic' in desc.fields_by_name)
+    self.assertTrue('price' in desc.fields_by_name)
+    self.assertTrue('owners' in desc.fields_by_name)
 
-    class CarMessage(message.Message):
-      __metaclass__ = reflection.GeneratedProtocolMessageType
+    class CarMessage(six.with_metaclass(reflection.GeneratedProtocolMessageType, message.Message)):
       DESCRIPTOR = desc
 
     prius = CarMessage()
@@ -1175,7 +1187,7 @@
     self.assertTrue(1 in unittest_pb2.TestAllExtensions._extensions_by_number)
     # Make sure extensions haven't been registered into types that shouldn't
     # have any.
-    self.assertEquals(0, len(unittest_pb2.TestAllTypes._extensions_by_name))
+    self.assertEqual(0, len(unittest_pb2.TestAllTypes._extensions_by_name))
 
   # If message A directly contains message B, and
   # a.HasField('b') is currently False, then mutating any
@@ -1252,15 +1264,18 @@
 
     # Try something that *is* an extension handle, just not for
     # this message...
-    unknown_handle = more_extensions_pb2.optional_int_extension
-    self.assertRaises(KeyError, extendee_proto.HasExtension,
-                      unknown_handle)
-    self.assertRaises(KeyError, extendee_proto.ClearExtension,
-                      unknown_handle)
-    self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__,
-                      unknown_handle)
-    self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__,
-                      unknown_handle, 5)
+    for unknown_handle in (more_extensions_pb2.optional_int_extension,
+                           more_extensions_pb2.optional_message_extension,
+                           more_extensions_pb2.repeated_int_extension,
+                           more_extensions_pb2.repeated_message_extension):
+      self.assertRaises(KeyError, extendee_proto.HasExtension,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.ClearExtension,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.Extensions.__getitem__,
+                        unknown_handle)
+      self.assertRaises(KeyError, extendee_proto.Extensions.__setitem__,
+                        unknown_handle, 5)
 
     # Try call HasExtension() with a valid handle, but for a
     # *repeated* field.  (Just as with non-extension repeated
@@ -1496,18 +1511,18 @@
       test_util.SetAllNonLazyFields(proto)
     # Clear the message.
     proto.Clear()
-    self.assertEquals(proto.ByteSize(), 0)
+    self.assertEqual(proto.ByteSize(), 0)
     empty_proto = unittest_pb2.TestAllTypes()
-    self.assertEquals(proto, empty_proto)
+    self.assertEqual(proto, empty_proto)
 
     # Test if extensions which were set are cleared.
     proto = unittest_pb2.TestAllExtensions()
     test_util.SetAllExtensions(proto)
     # Clear the message.
     proto.Clear()
-    self.assertEquals(proto.ByteSize(), 0)
+    self.assertEqual(proto.ByteSize(), 0)
     empty_proto = unittest_pb2.TestAllExtensions()
-    self.assertEquals(proto, empty_proto)
+    self.assertEqual(proto, empty_proto)
 
   def testDisconnectingBeforeClear(self):
     proto = unittest_pb2.TestAllTypes()
@@ -1618,7 +1633,7 @@
     self.assertFalse(proto.IsInitialized(errors))
     self.assertEqual(errors, ['a', 'b', 'c'])
 
-  @basetest.unittest.skipIf(
+  @unittest.skipIf(
       api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
       'Errors are only available from the most recent C++ implementation.')
   def testFileDescriptorErrors(self):
@@ -1660,30 +1675,29 @@
                       setattr, proto, 'optional_bytes', u'unicode object')
 
     # Check that the default value is of python's 'unicode' type.
-    self.assertEqual(type(proto.optional_string), unicode)
+    self.assertEqual(type(proto.optional_string), six.text_type)
 
-    proto.optional_string = unicode('Testing')
+    proto.optional_string = six.text_type('Testing')
     self.assertEqual(proto.optional_string, str('Testing'))
 
     # Assign a value of type 'str' which can be encoded in UTF-8.
     proto.optional_string = str('Testing')
-    self.assertEqual(proto.optional_string, unicode('Testing'))
+    self.assertEqual(proto.optional_string, six.text_type('Testing'))
 
-    # Try to assign a 'str' value which contains bytes that aren't 7-bit ASCII.
+    # Try to assign a 'bytes' object which contains non-UTF-8.
     self.assertRaises(ValueError,
                       setattr, proto, 'optional_string', b'a\x80a')
-    if str is bytes:  # PY2
-      # Assign a 'str' object which contains a UTF-8 encoded string.
-      self.assertRaises(ValueError,
-                        setattr, proto, 'optional_string', 'Тест')
-    else:
-      proto.optional_string = 'Тест'
-    # No exception thrown.
+    # No exception: Assign already encoded UTF-8 bytes to a string field.
+    utf8_bytes = u'Тест'.encode('utf-8')
+    proto.optional_string = utf8_bytes
+    # No exception: Assign the a non-ascii unicode object.
+    proto.optional_string = u'Тест'
+    # No exception thrown (normal str assignment containing ASCII).
     proto.optional_string = 'abc'
 
   def testStringUTF8Serialization(self):
-    proto = unittest_mset_pb2.TestMessageSet()
-    extension_message = unittest_mset_pb2.TestMessageSetExtension2
+    proto = message_set_extensions_pb2.TestMessageSet()
+    extension_message = message_set_extensions_pb2.TestMessageSetExtension2
     extension = extension_message.message_set_extension
 
     test_utf8 = u'Тест'
@@ -1703,19 +1717,18 @@
     bytes_read = raw.MergeFromString(serialized)
     self.assertEqual(len(serialized), bytes_read)
 
-    message2 = unittest_mset_pb2.TestMessageSetExtension2()
+    message2 = message_set_extensions_pb2.TestMessageSetExtension2()
 
     self.assertEqual(1, len(raw.item))
     # Check that the type_id is the same as the tag ID in the .proto file.
-    self.assertEqual(raw.item[0].type_id, 1547769)
+    self.assertEqual(raw.item[0].type_id, 98418634)
 
     # Check the actual bytes on the wire.
-    self.assertTrue(
-        raw.item[0].message.endswith(test_utf8_bytes))
+    self.assertTrue(raw.item[0].message.endswith(test_utf8_bytes))
     bytes_read = message2.MergeFromString(raw.item[0].message)
     self.assertEqual(len(raw.item[0].message), bytes_read)
 
-    self.assertEqual(type(message2.str), unicode)
+    self.assertEqual(type(message2.str), six.text_type)
     self.assertEqual(message2.str, test_utf8)
 
     # The pure Python API throws an exception on MergeFromString(),
@@ -1739,7 +1752,7 @@
   def testBytesInTextFormat(self):
     proto = unittest_pb2.TestAllTypes(optional_bytes=b'\x00\x7f\x80\xff')
     self.assertEqual(u'optional_bytes: "\\000\\177\\200\\377"\n',
-                     unicode(proto))
+                     six.text_type(proto))
 
   def testEmptyNestedMessage(self):
     proto = unittest_pb2.TestAllTypes()
@@ -1774,12 +1787,29 @@
     proto.optionalgroup.SetInParent()
     self.assertTrue(proto.HasField('optionalgroup'))
 
+  def testPackageInitializationImport(self):
+    """Test that we can import nested messages from their __init__.py.
+
+    Such setup is not trivial since at the time of processing of __init__.py one
+    can't refer to its submodules by name in code, so expressions like
+    google.protobuf.internal.import_test_package.inner_pb2
+    don't work. They do work in imports, so we have assign an alias at import
+    and then use that alias in generated code.
+    """
+    # We import here since it's the import that used to fail, and we want
+    # the failure to have the right context.
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.internal import import_test_package
+    # pylint: enable=g-import-not-at-top
+    msg = import_test_package.myproto.Outer()
+    # Just check the default value.
+    self.assertEqual(57, msg.inner.value)
 
 #  Since we had so many tests for protocol buffer equality, we broke these out
 #  into separate TestCase classes.
 
 
-class TestAllTypesEqualityTest(basetest.TestCase):
+class TestAllTypesEqualityTest(unittest.TestCase):
 
   def setUp(self):
     self.first_proto = unittest_pb2.TestAllTypes()
@@ -1795,7 +1825,7 @@
     self.assertEqual(self.first_proto, self.second_proto)
 
 
-class FullProtosEqualityTest(basetest.TestCase):
+class FullProtosEqualityTest(unittest.TestCase):
 
   """Equality tests using completely-full protos as a starting point."""
 
@@ -1881,7 +1911,7 @@
     self.assertEqual(self.first_proto, self.second_proto)
 
 
-class ExtensionEqualityTest(basetest.TestCase):
+class ExtensionEqualityTest(unittest.TestCase):
 
   def testExtensionEquality(self):
     first_proto = unittest_pb2.TestAllExtensions()
@@ -1914,7 +1944,7 @@
     self.assertEqual(first_proto, second_proto)
 
 
-class MutualRecursionEqualityTest(basetest.TestCase):
+class MutualRecursionEqualityTest(unittest.TestCase):
 
   def testEqualityWithMutualRecursion(self):
     first_proto = unittest_pb2.TestMutualRecursionA()
@@ -1926,7 +1956,7 @@
     self.assertEqual(first_proto, second_proto)
 
 
-class ByteSizeTest(basetest.TestCase):
+class ByteSizeTest(unittest.TestCase):
 
   def setUp(self):
     self.proto = unittest_pb2.TestAllTypes()
@@ -2222,7 +2252,7 @@
 #   * Handling of empty submessages (with and without "has"
 #     bits set).
 
-class SerializationTest(basetest.TestCase):
+class SerializationTest(unittest.TestCase):
 
   def testSerializeEmtpyMessage(self):
     first_proto = unittest_pb2.TestAllTypes()
@@ -2289,7 +2319,7 @@
     test_util.SetAllFields(first_proto)
     serialized = first_proto.SerializeToString()
 
-    for truncation_point in xrange(len(serialized) + 1):
+    for truncation_point in range(len(serialized) + 1):
       try:
         second_proto = unittest_pb2.TestAllTypes()
         unknown_fields = unittest_pb2.TestEmptyMessage()
@@ -2366,13 +2396,15 @@
     self.assertEqual(42, second_proto.optional_nested_message.bb)
 
   def testMessageSetWireFormat(self):
-    proto = unittest_mset_pb2.TestMessageSet()
-    extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
-    extension_message2 = unittest_mset_pb2.TestMessageSetExtension2
+    proto = message_set_extensions_pb2.TestMessageSet()
+    extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1
+    extension_message2 = message_set_extensions_pb2.TestMessageSetExtension2
     extension1 = extension_message1.message_set_extension
     extension2 = extension_message2.message_set_extension
+    extension3 = message_set_extensions_pb2.message_set_extension3
     proto.Extensions[extension1].i = 123
     proto.Extensions[extension2].str = 'foo'
+    proto.Extensions[extension3].text = 'bar'
 
     # Serialize using the MessageSet wire format (this is specified in the
     # .proto file).
@@ -2384,27 +2416,34 @@
     self.assertEqual(
         len(serialized),
         raw.MergeFromString(serialized))
-    self.assertEqual(2, len(raw.item))
+    self.assertEqual(3, len(raw.item))
 
-    message1 = unittest_mset_pb2.TestMessageSetExtension1()
+    message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     self.assertEqual(
         len(raw.item[0].message),
         message1.MergeFromString(raw.item[0].message))
     self.assertEqual(123, message1.i)
 
-    message2 = unittest_mset_pb2.TestMessageSetExtension2()
+    message2 = message_set_extensions_pb2.TestMessageSetExtension2()
     self.assertEqual(
         len(raw.item[1].message),
         message2.MergeFromString(raw.item[1].message))
     self.assertEqual('foo', message2.str)
 
+    message3 = message_set_extensions_pb2.TestMessageSetExtension3()
+    self.assertEqual(
+        len(raw.item[2].message),
+        message3.MergeFromString(raw.item[2].message))
+    self.assertEqual('bar', message3.text)
+
     # Deserialize using the MessageSet wire format.
-    proto2 = unittest_mset_pb2.TestMessageSet()
+    proto2 = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(
         len(serialized),
         proto2.MergeFromString(serialized))
     self.assertEqual(123, proto2.Extensions[extension1].i)
     self.assertEqual('foo', proto2.Extensions[extension2].str)
+    self.assertEqual('bar', proto2.Extensions[extension3].text)
 
     # Check byte size.
     self.assertEqual(proto2.ByteSize(), len(serialized))
@@ -2417,39 +2456,39 @@
 
     # Add an item.
     item = raw.item.add()
-    item.type_id = 1545008
-    extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
-    message1 = unittest_mset_pb2.TestMessageSetExtension1()
+    item.type_id = 98418603
+    extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1
+    message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     message1.i = 12345
     item.message = message1.SerializeToString()
 
     # Add a second, unknown extension.
     item = raw.item.add()
-    item.type_id = 1545009
-    extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
-    message1 = unittest_mset_pb2.TestMessageSetExtension1()
+    item.type_id = 98418604
+    extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1
+    message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     message1.i = 12346
     item.message = message1.SerializeToString()
 
     # Add another unknown extension.
     item = raw.item.add()
-    item.type_id = 1545010
-    message1 = unittest_mset_pb2.TestMessageSetExtension2()
+    item.type_id = 98418605
+    message1 = message_set_extensions_pb2.TestMessageSetExtension2()
     message1.str = 'foo'
     item.message = message1.SerializeToString()
 
     serialized = raw.SerializeToString()
 
     # Parse message using the message set wire format.
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(
         len(serialized),
         proto.MergeFromString(serialized))
 
     # Check that the message parsed well.
-    extension_message1 = unittest_mset_pb2.TestMessageSetExtension1
+    extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1
     extension1 = extension_message1.message_set_extension
-    self.assertEquals(12345, proto.Extensions[extension1].i)
+    self.assertEqual(12345, proto.Extensions[extension1].i)
 
   def testUnknownFields(self):
     proto = unittest_pb2.TestAllTypes()
@@ -2734,9 +2773,10 @@
   def testInitArgsUnknownFieldName(self):
     def InitalizeEmptyMessageWithExtraKeywordArg():
       unused_proto = unittest_pb2.TestEmptyMessage(unknown='unknown')
-    self._CheckRaises(ValueError,
-                      InitalizeEmptyMessageWithExtraKeywordArg,
-                      'Protocol message has no "unknown" field.')
+    self._CheckRaises(
+        ValueError,
+        InitalizeEmptyMessageWithExtraKeywordArg,
+        'Protocol message TestEmptyMessage has no "unknown" field.')
 
   def testInitRequiredKwargs(self):
     proto = unittest_pb2.TestRequired(a=1, b=1, c=1)
@@ -2773,10 +2813,10 @@
     self.assertEqual(3, proto.repeated_int32[2])
 
 
-class OptionsTest(basetest.TestCase):
+class OptionsTest(unittest.TestCase):
 
   def testMessageOptions(self):
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(True,
                      proto.DESCRIPTOR.GetOptions().message_set_wire_format)
     proto = unittest_pb2.TestAllTypes()
@@ -2795,13 +2835,16 @@
     proto.packed_double.append(3.0)
     for field_descriptor, _ in proto.ListFields():
       self.assertEqual(True, field_descriptor.GetOptions().packed)
-      self.assertEqual(reflection._FieldDescriptor.LABEL_REPEATED,
+      self.assertEqual(descriptor.FieldDescriptor.LABEL_REPEATED,
                        field_descriptor.label)
 
 
 
-class ClassAPITest(basetest.TestCase):
+class ClassAPITest(unittest.TestCase):
 
+  @unittest.skipIf(
+      api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
+      'C++ implementation requires a call to MakeDescriptor()')
   def testMakeClassWithNestedDescriptor(self):
     leaf_desc = descriptor.Descriptor('leaf', 'package.parent.child.leaf', '',
                                       containing_type=None, fields=[],
@@ -2882,13 +2925,19 @@
 
   def testParsingFlatClassWithExplicitClassDeclaration(self):
     """Test that the generated class can parse a flat message."""
+    # TODO(xiaofeng): This test fails with cpp implemetnation in the call
+    # of six.with_metaclass(). The other two callsites of with_metaclass
+    # in this file are both excluded from cpp test, so it might be expected
+    # to fail. Need someone more familiar with the python code to take a
+    # look at this.
+    if api_implementation.Type() != 'python':
+      return
     file_descriptor = descriptor_pb2.FileDescriptorProto()
     file_descriptor.ParseFromString(self._GetSerializedFileDescriptor('A'))
     msg_descriptor = descriptor.MakeDescriptor(
         file_descriptor.message_type[0])
 
-    class MessageClass(message.Message):
-      __metaclass__ = reflection.GeneratedProtocolMessageType
+    class MessageClass(six.with_metaclass(reflection.GeneratedProtocolMessageType, message.Message)):
       DESCRIPTOR = msg_descriptor
     msg = MessageClass()
     msg_str = (
@@ -2931,4 +2980,4 @@
     self.assertEqual(msg.bar.baz.deep, 4)
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py
index 07dcf44..62900b1 100755
--- a/python/google/protobuf/internal/service_reflection_test.py
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,13 +34,18 @@
 
 __author__ = 'petar@google.com (Petar Petrov)'
 
-from google.apputils import basetest
+
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import unittest_pb2
 from google.protobuf import service_reflection
 from google.protobuf import service
 
 
-class FooUnitTest(basetest.TestCase):
+class FooUnitTest(unittest.TestCase):
 
   def testService(self):
     class MockRpcChannel(service.RpcChannel):
@@ -80,7 +85,7 @@
     self.assertEqual('Method Bar not implemented.',
                      rpc_controller.failure_message)
     self.assertEqual(None, self.callback_response)
-    
+
     class MyServiceImpl(unittest_pb2.TestService):
       def Foo(self, rpc_controller, request, done):
         self.foo_called = True
@@ -118,19 +123,18 @@
     rpc_controller = 'controller'
     request = 'request'
 
-    # GetDescriptor now static, still works as instance method for compatability
+    # GetDescriptor now static, still works as instance method for compatibility
     self.assertEqual(unittest_pb2.TestService_Stub.GetDescriptor(),
                      stub.GetDescriptor())
 
     # Invoke method.
     stub.Foo(rpc_controller, request, MyCallback)
 
-    self.assertTrue(isinstance(self.callback_response,
-                               unittest_pb2.FooResponse))
+    self.assertIsInstance(self.callback_response, unittest_pb2.FooResponse)
     self.assertEqual(request, channel.request)
     self.assertEqual(rpc_controller, channel.controller)
     self.assertEqual(stub.GetDescriptor().methods[0], channel.method)
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
index 47572d5..c99b426 100644
--- a/python/google/protobuf/internal/symbol_database_test.py
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -32,24 +32,33 @@
 
 """Tests for google.protobuf.symbol_database."""
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import unittest_pb2
+from google.protobuf import descriptor
 from google.protobuf import symbol_database
 
-
-class SymbolDatabaseTest(basetest.TestCase):
+class SymbolDatabaseTest(unittest.TestCase):
 
   def _Database(self):
-    db = symbol_database.SymbolDatabase()
-    # Register representative types from unittest_pb2.
-    db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
-    db.RegisterMessage(unittest_pb2.TestAllTypes)
-    db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
-    db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
-    db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
-    db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
-    db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
-    return db
+    # TODO(b/17734095): Remove this difference when the C++ implementation
+    # supports multiple databases.
+    if descriptor._USE_C_DESCRIPTORS:
+      return symbol_database.Default()
+    else:
+      db = symbol_database.SymbolDatabase()
+      # Register representative types from unittest_pb2.
+      db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
+      db.RegisterMessage(unittest_pb2.TestAllTypes)
+      db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
+      db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
+      db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
+      db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+      db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+      return db
 
   def testGetPrototype(self):
     instance = self._Database().GetPrototype(
@@ -64,57 +73,57 @@
         messages['protobuf_unittest.TestAllTypes'])
 
   def testGetSymbol(self):
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes, self._Database().GetSymbol(
             'protobuf_unittest.TestAllTypes'))
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.NestedMessage, self._Database().GetSymbol(
             'protobuf_unittest.TestAllTypes.NestedMessage'))
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.OptionalGroup, self._Database().GetSymbol(
             'protobuf_unittest.TestAllTypes.OptionalGroup'))
-    self.assertEquals(
+    self.assertEqual(
         unittest_pb2.TestAllTypes.RepeatedGroup, self._Database().GetSymbol(
             'protobuf_unittest.TestAllTypes.RepeatedGroup'))
 
   def testEnums(self):
     # Check registration of types in the pool.
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.ForeignEnum',
         self._Database().pool.FindEnumTypeByName(
             'protobuf_unittest.ForeignEnum').full_name)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes.NestedEnum',
         self._Database().pool.FindEnumTypeByName(
             'protobuf_unittest.TestAllTypes.NestedEnum').full_name)
 
   def testFindMessageTypeByName(self):
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes',
         self._Database().pool.FindMessageTypeByName(
             'protobuf_unittest.TestAllTypes').full_name)
-    self.assertEquals(
+    self.assertEqual(
         'protobuf_unittest.TestAllTypes.NestedMessage',
         self._Database().pool.FindMessageTypeByName(
             'protobuf_unittest.TestAllTypes.NestedMessage').full_name)
 
   def testFindFindContainingSymbol(self):
     # Lookup based on either enum or message.
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         self._Database().pool.FindFileContainingSymbol(
             'protobuf_unittest.TestAllTypes.NestedEnum').name)
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         self._Database().pool.FindFileContainingSymbol(
             'protobuf_unittest.TestAllTypes').name)
 
   def testFindFileByName(self):
-    self.assertEquals(
+    self.assertEqual(
         'google/protobuf/unittest.proto',
         self._Database().pool.FindFileByName(
             'google/protobuf/unittest.proto').name)
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/test_bad_identifiers.proto b/python/google/protobuf/internal/test_bad_identifiers.proto
index 9eb18cb..c4860ea 100644
--- a/python/google/protobuf/internal/test_bad_identifiers.proto
+++ b/python/google/protobuf/internal/test_bad_identifiers.proto
@@ -30,6 +30,7 @@
 
 // Author: kenton@google.com (Kenton Varda)
 
+syntax = "proto2";
 
 package protobuf_unittest;
 
diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py
index 787f465..2c80559 100755
--- a/python/google/protobuf/internal/test_util.py
+++ b/python/google/protobuf/internal/test_util.py
@@ -38,15 +38,23 @@
 
 import os.path
 
+import sys
+
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_pb2
+from google.protobuf import descriptor_pb2
 
+# Tests whether the given TestAllTypes message is proto2 or not.
+# This is used to gate several fields/features that only exist
+# for the proto2 version of the message.
+def IsProto2(message):
+  return message.DESCRIPTOR.syntax == "proto2"
 
 def SetAllNonLazyFields(message):
   """Sets every non-lazy field in the message to a unique value.
 
   Args:
-    message: A unittest_pb2.TestAllTypes instance.
+    message: A TestAllTypes instance.
   """
 
   #
@@ -69,7 +77,8 @@
   message.optional_string   = u'115'
   message.optional_bytes    = b'116'
 
-  message.optionalgroup.a = 117
+  if IsProto2(message):
+    message.optionalgroup.a = 117
   message.optional_nested_message.bb = 118
   message.optional_foreign_message.c = 119
   message.optional_import_message.d = 120
@@ -77,7 +86,8 @@
 
   message.optional_nested_enum = unittest_pb2.TestAllTypes.BAZ
   message.optional_foreign_enum = unittest_pb2.FOREIGN_BAZ
-  message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
+  if IsProto2(message):
+    message.optional_import_enum = unittest_import_pb2.IMPORT_BAZ
 
   message.optional_string_piece = u'124'
   message.optional_cord = u'125'
@@ -102,7 +112,8 @@
   message.repeated_string.append(u'215')
   message.repeated_bytes.append(b'216')
 
-  message.repeatedgroup.add().a = 217
+  if IsProto2(message):
+    message.repeatedgroup.add().a = 217
   message.repeated_nested_message.add().bb = 218
   message.repeated_foreign_message.add().c = 219
   message.repeated_import_message.add().d = 220
@@ -110,7 +121,8 @@
 
   message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAR)
   message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
-  message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
+  if IsProto2(message):
+    message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAR)
 
   message.repeated_string_piece.append(u'224')
   message.repeated_cord.append(u'225')
@@ -132,7 +144,8 @@
   message.repeated_string.append(u'315')
   message.repeated_bytes.append(b'316')
 
-  message.repeatedgroup.add().a = 317
+  if IsProto2(message):
+    message.repeatedgroup.add().a = 317
   message.repeated_nested_message.add().bb = 318
   message.repeated_foreign_message.add().c = 319
   message.repeated_import_message.add().d = 320
@@ -140,7 +153,8 @@
 
   message.repeated_nested_enum.append(unittest_pb2.TestAllTypes.BAZ)
   message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
-  message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
+  if IsProto2(message):
+    message.repeated_import_enum.append(unittest_import_pb2.IMPORT_BAZ)
 
   message.repeated_string_piece.append(u'324')
   message.repeated_cord.append(u'325')
@@ -149,28 +163,29 @@
   # Fields that have defaults.
   #
 
-  message.default_int32 = 401
-  message.default_int64 = 402
-  message.default_uint32 = 403
-  message.default_uint64 = 404
-  message.default_sint32 = 405
-  message.default_sint64 = 406
-  message.default_fixed32 = 407
-  message.default_fixed64 = 408
-  message.default_sfixed32 = 409
-  message.default_sfixed64 = 410
-  message.default_float = 411
-  message.default_double = 412
-  message.default_bool = False
-  message.default_string = '415'
-  message.default_bytes = b'416'
+  if IsProto2(message):
+    message.default_int32 = 401
+    message.default_int64 = 402
+    message.default_uint32 = 403
+    message.default_uint64 = 404
+    message.default_sint32 = 405
+    message.default_sint64 = 406
+    message.default_fixed32 = 407
+    message.default_fixed64 = 408
+    message.default_sfixed32 = 409
+    message.default_sfixed64 = 410
+    message.default_float = 411
+    message.default_double = 412
+    message.default_bool = False
+    message.default_string = '415'
+    message.default_bytes = b'416'
 
-  message.default_nested_enum = unittest_pb2.TestAllTypes.FOO
-  message.default_foreign_enum = unittest_pb2.FOREIGN_FOO
-  message.default_import_enum = unittest_import_pb2.IMPORT_FOO
+    message.default_nested_enum = unittest_pb2.TestAllTypes.FOO
+    message.default_foreign_enum = unittest_pb2.FOREIGN_FOO
+    message.default_import_enum = unittest_import_pb2.IMPORT_FOO
 
-  message.default_string_piece = '424'
-  message.default_cord = '425'
+    message.default_string_piece = '424'
+    message.default_cord = '425'
 
   message.oneof_uint32 = 601
   message.oneof_nested_message.bb = 602
@@ -386,7 +401,8 @@
   test_case.assertTrue(message.HasField('optional_string'))
   test_case.assertTrue(message.HasField('optional_bytes'))
 
-  test_case.assertTrue(message.HasField('optionalgroup'))
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('optionalgroup'))
   test_case.assertTrue(message.HasField('optional_nested_message'))
   test_case.assertTrue(message.HasField('optional_foreign_message'))
   test_case.assertTrue(message.HasField('optional_import_message'))
@@ -398,7 +414,8 @@
 
   test_case.assertTrue(message.HasField('optional_nested_enum'))
   test_case.assertTrue(message.HasField('optional_foreign_enum'))
-  test_case.assertTrue(message.HasField('optional_import_enum'))
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('optional_import_enum'))
 
   test_case.assertTrue(message.HasField('optional_string_piece'))
   test_case.assertTrue(message.HasField('optional_cord'))
@@ -419,7 +436,8 @@
   test_case.assertEqual('115', message.optional_string)
   test_case.assertEqual(b'116', message.optional_bytes)
 
-  test_case.assertEqual(117, message.optionalgroup.a)
+  if IsProto2(message):
+    test_case.assertEqual(117, message.optionalgroup.a)
   test_case.assertEqual(118, message.optional_nested_message.bb)
   test_case.assertEqual(119, message.optional_foreign_message.c)
   test_case.assertEqual(120, message.optional_import_message.d)
@@ -430,8 +448,9 @@
                         message.optional_nested_enum)
   test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
                         message.optional_foreign_enum)
-  test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
-                        message.optional_import_enum)
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                          message.optional_import_enum)
 
   # -----------------------------------------------------------------
 
@@ -451,13 +470,15 @@
   test_case.assertEqual(2, len(message.repeated_string))
   test_case.assertEqual(2, len(message.repeated_bytes))
 
-  test_case.assertEqual(2, len(message.repeatedgroup))
+  if IsProto2(message):
+    test_case.assertEqual(2, len(message.repeatedgroup))
   test_case.assertEqual(2, len(message.repeated_nested_message))
   test_case.assertEqual(2, len(message.repeated_foreign_message))
   test_case.assertEqual(2, len(message.repeated_import_message))
   test_case.assertEqual(2, len(message.repeated_nested_enum))
   test_case.assertEqual(2, len(message.repeated_foreign_enum))
-  test_case.assertEqual(2, len(message.repeated_import_enum))
+  if IsProto2(message):
+    test_case.assertEqual(2, len(message.repeated_import_enum))
 
   test_case.assertEqual(2, len(message.repeated_string_piece))
   test_case.assertEqual(2, len(message.repeated_cord))
@@ -478,7 +499,8 @@
   test_case.assertEqual('215', message.repeated_string[0])
   test_case.assertEqual(b'216', message.repeated_bytes[0])
 
-  test_case.assertEqual(217, message.repeatedgroup[0].a)
+  if IsProto2(message):
+    test_case.assertEqual(217, message.repeatedgroup[0].a)
   test_case.assertEqual(218, message.repeated_nested_message[0].bb)
   test_case.assertEqual(219, message.repeated_foreign_message[0].c)
   test_case.assertEqual(220, message.repeated_import_message[0].d)
@@ -488,8 +510,9 @@
                         message.repeated_nested_enum[0])
   test_case.assertEqual(unittest_pb2.FOREIGN_BAR,
                         message.repeated_foreign_enum[0])
-  test_case.assertEqual(unittest_import_pb2.IMPORT_BAR,
-                        message.repeated_import_enum[0])
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAR,
+                          message.repeated_import_enum[0])
 
   test_case.assertEqual(301, message.repeated_int32[1])
   test_case.assertEqual(302, message.repeated_int64[1])
@@ -507,7 +530,8 @@
   test_case.assertEqual('315', message.repeated_string[1])
   test_case.assertEqual(b'316', message.repeated_bytes[1])
 
-  test_case.assertEqual(317, message.repeatedgroup[1].a)
+  if IsProto2(message):
+    test_case.assertEqual(317, message.repeatedgroup[1].a)
   test_case.assertEqual(318, message.repeated_nested_message[1].bb)
   test_case.assertEqual(319, message.repeated_foreign_message[1].c)
   test_case.assertEqual(320, message.repeated_import_message[1].d)
@@ -517,53 +541,55 @@
                         message.repeated_nested_enum[1])
   test_case.assertEqual(unittest_pb2.FOREIGN_BAZ,
                         message.repeated_foreign_enum[1])
-  test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
-                        message.repeated_import_enum[1])
+  if IsProto2(message):
+    test_case.assertEqual(unittest_import_pb2.IMPORT_BAZ,
+                          message.repeated_import_enum[1])
 
   # -----------------------------------------------------------------
 
-  test_case.assertTrue(message.HasField('default_int32'))
-  test_case.assertTrue(message.HasField('default_int64'))
-  test_case.assertTrue(message.HasField('default_uint32'))
-  test_case.assertTrue(message.HasField('default_uint64'))
-  test_case.assertTrue(message.HasField('default_sint32'))
-  test_case.assertTrue(message.HasField('default_sint64'))
-  test_case.assertTrue(message.HasField('default_fixed32'))
-  test_case.assertTrue(message.HasField('default_fixed64'))
-  test_case.assertTrue(message.HasField('default_sfixed32'))
-  test_case.assertTrue(message.HasField('default_sfixed64'))
-  test_case.assertTrue(message.HasField('default_float'))
-  test_case.assertTrue(message.HasField('default_double'))
-  test_case.assertTrue(message.HasField('default_bool'))
-  test_case.assertTrue(message.HasField('default_string'))
-  test_case.assertTrue(message.HasField('default_bytes'))
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('default_int32'))
+    test_case.assertTrue(message.HasField('default_int64'))
+    test_case.assertTrue(message.HasField('default_uint32'))
+    test_case.assertTrue(message.HasField('default_uint64'))
+    test_case.assertTrue(message.HasField('default_sint32'))
+    test_case.assertTrue(message.HasField('default_sint64'))
+    test_case.assertTrue(message.HasField('default_fixed32'))
+    test_case.assertTrue(message.HasField('default_fixed64'))
+    test_case.assertTrue(message.HasField('default_sfixed32'))
+    test_case.assertTrue(message.HasField('default_sfixed64'))
+    test_case.assertTrue(message.HasField('default_float'))
+    test_case.assertTrue(message.HasField('default_double'))
+    test_case.assertTrue(message.HasField('default_bool'))
+    test_case.assertTrue(message.HasField('default_string'))
+    test_case.assertTrue(message.HasField('default_bytes'))
 
-  test_case.assertTrue(message.HasField('default_nested_enum'))
-  test_case.assertTrue(message.HasField('default_foreign_enum'))
-  test_case.assertTrue(message.HasField('default_import_enum'))
+    test_case.assertTrue(message.HasField('default_nested_enum'))
+    test_case.assertTrue(message.HasField('default_foreign_enum'))
+    test_case.assertTrue(message.HasField('default_import_enum'))
 
-  test_case.assertEqual(401, message.default_int32)
-  test_case.assertEqual(402, message.default_int64)
-  test_case.assertEqual(403, message.default_uint32)
-  test_case.assertEqual(404, message.default_uint64)
-  test_case.assertEqual(405, message.default_sint32)
-  test_case.assertEqual(406, message.default_sint64)
-  test_case.assertEqual(407, message.default_fixed32)
-  test_case.assertEqual(408, message.default_fixed64)
-  test_case.assertEqual(409, message.default_sfixed32)
-  test_case.assertEqual(410, message.default_sfixed64)
-  test_case.assertEqual(411, message.default_float)
-  test_case.assertEqual(412, message.default_double)
-  test_case.assertEqual(False, message.default_bool)
-  test_case.assertEqual('415', message.default_string)
-  test_case.assertEqual(b'416', message.default_bytes)
+    test_case.assertEqual(401, message.default_int32)
+    test_case.assertEqual(402, message.default_int64)
+    test_case.assertEqual(403, message.default_uint32)
+    test_case.assertEqual(404, message.default_uint64)
+    test_case.assertEqual(405, message.default_sint32)
+    test_case.assertEqual(406, message.default_sint64)
+    test_case.assertEqual(407, message.default_fixed32)
+    test_case.assertEqual(408, message.default_fixed64)
+    test_case.assertEqual(409, message.default_sfixed32)
+    test_case.assertEqual(410, message.default_sfixed64)
+    test_case.assertEqual(411, message.default_float)
+    test_case.assertEqual(412, message.default_double)
+    test_case.assertEqual(False, message.default_bool)
+    test_case.assertEqual('415', message.default_string)
+    test_case.assertEqual(b'416', message.default_bytes)
 
-  test_case.assertEqual(unittest_pb2.TestAllTypes.FOO,
-                        message.default_nested_enum)
-  test_case.assertEqual(unittest_pb2.FOREIGN_FOO,
-                        message.default_foreign_enum)
-  test_case.assertEqual(unittest_import_pb2.IMPORT_FOO,
-                        message.default_import_enum)
+    test_case.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                          message.default_nested_enum)
+    test_case.assertEqual(unittest_pb2.FOREIGN_FOO,
+                          message.default_foreign_enum)
+    test_case.assertEqual(unittest_import_pb2.IMPORT_FOO,
+                          message.default_import_enum)
 
 
 def GoldenFile(filename):
@@ -578,6 +604,14 @@
       return open(full_path, 'rb')
     path = os.path.join(path, '..')
 
+  # Search internally.
+  path = '.'
+  full_path = os.path.join(path, 'third_party/py/google/protobuf/testdata',
+                           filename)
+  if os.path.exists(full_path):
+    # Found it.  Load the golden file from the testdata directory.
+    return open(full_path, 'rb')
+
   raise RuntimeError(
       'Could not find golden files.  This test must be run from within the '
       'protobuf source package so that it can read test data files from the '
@@ -594,7 +628,7 @@
   """Sets every field in the message to a unique value.
 
   Args:
-    message: A unittest_pb2.TestPackedTypes instance.
+    message: A TestPackedTypes instance.
   """
   message.packed_int32.extend([601, 701])
   message.packed_int64.extend([602, 702])
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
index db0222b..c7d182c 100755
--- a/python/google/protobuf/internal/text_encoding_test.py
+++ b/python/google/protobuf/internal/text_encoding_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -32,7 +32,11 @@
 
 """Tests for google.protobuf.text_encoding."""
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import text_encoding
 
 TEST_VALUES = [
@@ -50,19 +54,19 @@
      b"\010\011\012\013\014\015")]
 
 
-class TextEncodingTestCase(basetest.TestCase):
+class TextEncodingTestCase(unittest.TestCase):
   def testCEscape(self):
     for escaped, escaped_utf8, unescaped in TEST_VALUES:
-      self.assertEquals(escaped,
+      self.assertEqual(escaped,
                         text_encoding.CEscape(unescaped, as_utf8=False))
-      self.assertEquals(escaped_utf8,
+      self.assertEqual(escaped_utf8,
                         text_encoding.CEscape(unescaped, as_utf8=True))
 
   def testCUnescape(self):
     for escaped, escaped_utf8, unescaped in TEST_VALUES:
-      self.assertEquals(unescaped, text_encoding.CUnescape(escaped))
-      self.assertEquals(unescaped, text_encoding.CUnescape(escaped_utf8))
+      self.assertEqual(unescaped, text_encoding.CUnescape(escaped))
+      self.assertEqual(unescaped, text_encoding.CUnescape(escaped_utf8))
 
 
 if __name__ == "__main__":
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index b0a3a5f..ab2bf05 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,16 +34,42 @@
 
 __author__ = 'kenton@google.com (Kenton Varda)'
 
-import re
 
-from google.apputils import basetest
-from google.protobuf import text_format
+import re
+import six
+import string
+
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
+from google.protobuf.internal import _parameterized
+
+from google.protobuf import map_unittest_pb2
+from google.protobuf import unittest_mset_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import test_util
-from google.protobuf import unittest_pb2
-from google.protobuf import unittest_mset_pb2
+from google.protobuf.internal import message_set_extensions_pb2
+from google.protobuf import text_format
 
-class TextFormatTest(basetest.TestCase):
+
+# Low-level nuts-n-bolts tests.
+class SimpleTextFormatTests(unittest.TestCase):
+
+  # The members of _QUOTES are formatted into a regexp template that
+  # expects single characters.  Therefore it's an error (in addition to being
+  # non-sensical in the first place) to try to specify a "quote mark" that is
+  # more than one character.
+  def testQuoteMarksAreSingleChars(self):
+    for quote in text_format._QUOTES:
+      self.assertEqual(1, len(quote))
+
+
+# Base class with some common functionality.
+class TextFormatBase(unittest.TestCase):
 
   def ReadGolden(self, golden_filename):
     with test_util.GoldenFile(golden_filename) as f:
@@ -55,70 +81,26 @@
     self.assertMultiLineEqual(text, ''.join(golden_lines))
 
   def CompareToGoldenText(self, text, golden_text):
-    self.assertMultiLineEqual(text, golden_text)
+    self.assertEqual(text, golden_text)
 
-  def testPrintAllFields(self):
-    message = unittest_pb2.TestAllTypes()
-    test_util.SetAllFields(message)
-    self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(text_format.MessageToString(message)),
-        'text_format_unittest_data_oneof_implemented.txt')
+  def RemoveRedundantZeros(self, text):
+    # Some platforms print 1e+5 as 1e+005.  This is fine, but we need to remove
+    # these zeros in order to match the golden file.
+    text = text.replace('e+0','e+').replace('e+0','e+') \
+               .replace('e-0','e-').replace('e-0','e-')
+    # Floating point fields are printed with .0 suffix even if they are
+    # actualy integer numbers.
+    text = re.compile('\.0$', re.MULTILINE).sub('', text)
+    return text
 
-  def testPrintInIndexOrder(self):
-    message = unittest_pb2.TestFieldOrderings()
-    message.my_string = '115'
-    message.my_int = 101
-    message.my_float = 111
-    self.CompareToGoldenText(
-        self.RemoveRedundantZeros(text_format.MessageToString(
-            message, use_index_order=True)),
-        'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n')
-    self.CompareToGoldenText(
-        self.RemoveRedundantZeros(text_format.MessageToString(
-            message)), 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n')
 
-  def testPrintAllExtensions(self):
-    message = unittest_pb2.TestAllExtensions()
-    test_util.SetAllExtensions(message)
-    self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(text_format.MessageToString(message)),
-        'text_format_unittest_extensions_data.txt')
+@_parameterized.Parameters(
+    (unittest_pb2),
+    (unittest_proto3_arena_pb2))
+class TextFormatTest(TextFormatBase):
 
-  def testPrintAllFieldsPointy(self):
-    message = unittest_pb2.TestAllTypes()
-    test_util.SetAllFields(message)
-    self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(
-            text_format.MessageToString(message, pointy_brackets=True)),
-        'text_format_unittest_data_pointy_oneof.txt')
-
-  def testPrintAllExtensionsPointy(self):
-    message = unittest_pb2.TestAllExtensions()
-    test_util.SetAllExtensions(message)
-    self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(text_format.MessageToString(
-            message, pointy_brackets=True)),
-        'text_format_unittest_extensions_data_pointy.txt')
-
-  def testPrintMessageSet(self):
-    message = unittest_mset_pb2.TestMessageSetContainer()
-    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
-    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
-    message.message_set.Extensions[ext1].i = 23
-    message.message_set.Extensions[ext2].str = 'foo'
-    self.CompareToGoldenText(
-        text_format.MessageToString(message),
-        'message_set {\n'
-        '  [protobuf_unittest.TestMessageSetExtension1] {\n'
-        '    i: 23\n'
-        '  }\n'
-        '  [protobuf_unittest.TestMessageSetExtension2] {\n'
-        '    str: \"foo\"\n'
-        '  }\n'
-        '}\n')
-
-  def testPrintExotic(self):
-    message = unittest_pb2.TestAllTypes()
+  def testPrintExotic(self, message_module):
+    message = message_module.TestAllTypes()
     message.repeated_int64.append(-9223372036854775808)
     message.repeated_uint64.append(18446744073709551615)
     message.repeated_double.append(123.456)
@@ -137,61 +119,44 @@
         ' "\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""\n'
         'repeated_string: "\\303\\274\\352\\234\\237"\n')
 
-  def testPrintExoticUnicodeSubclass(self):
-    class UnicodeSub(unicode):
+  def testPrintExoticUnicodeSubclass(self, message_module):
+    class UnicodeSub(six.text_type):
       pass
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
     message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
     self.CompareToGoldenText(
         text_format.MessageToString(message),
         'repeated_string: "\\303\\274\\352\\234\\237"\n')
 
-  def testPrintNestedMessageAsOneLine(self):
-    message = unittest_pb2.TestAllTypes()
+  def testPrintNestedMessageAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
     msg = message.repeated_nested_message.add()
     msg.bb = 42
     self.CompareToGoldenText(
         text_format.MessageToString(message, as_one_line=True),
         'repeated_nested_message { bb: 42 }')
 
-  def testPrintRepeatedFieldsAsOneLine(self):
-    message = unittest_pb2.TestAllTypes()
+  def testPrintRepeatedFieldsAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
     message.repeated_int32.append(1)
     message.repeated_int32.append(1)
     message.repeated_int32.append(3)
-    message.repeated_string.append("Google")
-    message.repeated_string.append("Zurich")
+    message.repeated_string.append('Google')
+    message.repeated_string.append('Zurich')
     self.CompareToGoldenText(
         text_format.MessageToString(message, as_one_line=True),
         'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
         'repeated_string: "Google" repeated_string: "Zurich"')
 
-  def testPrintNestedNewLineInStringAsOneLine(self):
-    message = unittest_pb2.TestAllTypes()
-    message.optional_string = "a\nnew\nline"
+  def testPrintNestedNewLineInStringAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
+    message.optional_string = 'a\nnew\nline'
     self.CompareToGoldenText(
         text_format.MessageToString(message, as_one_line=True),
         'optional_string: "a\\nnew\\nline"')
 
-  def testPrintMessageSetAsOneLine(self):
-    message = unittest_mset_pb2.TestMessageSetContainer()
-    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
-    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
-    message.message_set.Extensions[ext1].i = 23
-    message.message_set.Extensions[ext2].str = 'foo'
-    self.CompareToGoldenText(
-        text_format.MessageToString(message, as_one_line=True),
-        'message_set {'
-        ' [protobuf_unittest.TestMessageSetExtension1] {'
-        ' i: 23'
-        ' }'
-        ' [protobuf_unittest.TestMessageSetExtension2] {'
-        ' str: \"foo\"'
-        ' }'
-        ' }')
-
-  def testPrintExoticAsOneLine(self):
-    message = unittest_pb2.TestAllTypes()
+  def testPrintExoticAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
     message.repeated_int64.append(-9223372036854775808)
     message.repeated_uint64.append(18446744073709551615)
     message.repeated_double.append(123.456)
@@ -211,8 +176,8 @@
         '"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\""'
         ' repeated_string: "\\303\\274\\352\\234\\237"')
 
-  def testRoundTripExoticAsOneLine(self):
-    message = unittest_pb2.TestAllTypes()
+  def testRoundTripExoticAsOneLine(self, message_module):
+    message = message_module.TestAllTypes()
     message.repeated_int64.append(-9223372036854775808)
     message.repeated_uint64.append(18446744073709551615)
     message.repeated_double.append(123.456)
@@ -224,33 +189,33 @@
     # Test as_utf8 = False.
     wire_text = text_format.MessageToString(
         message, as_one_line=True, as_utf8=False)
-    parsed_message = unittest_pb2.TestAllTypes()
+    parsed_message = message_module.TestAllTypes()
     r = text_format.Parse(wire_text, parsed_message)
     self.assertIs(r, parsed_message)
-    self.assertEquals(message, parsed_message)
+    self.assertEqual(message, parsed_message)
 
     # Test as_utf8 = True.
     wire_text = text_format.MessageToString(
         message, as_one_line=True, as_utf8=True)
-    parsed_message = unittest_pb2.TestAllTypes()
+    parsed_message = message_module.TestAllTypes()
     r = text_format.Parse(wire_text, parsed_message)
     self.assertIs(r, parsed_message)
-    self.assertEquals(message, parsed_message,
+    self.assertEqual(message, parsed_message,
                       '\n%s != %s' % (message, parsed_message))
 
-  def testPrintRawUtf8String(self):
-    message = unittest_pb2.TestAllTypes()
+  def testPrintRawUtf8String(self, message_module):
+    message = message_module.TestAllTypes()
     message.repeated_string.append(u'\u00fc\ua71f')
     text = text_format.MessageToString(message, as_utf8=True)
     self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n')
-    parsed_message = unittest_pb2.TestAllTypes()
+    parsed_message = message_module.TestAllTypes()
     text_format.Parse(text, parsed_message)
-    self.assertEquals(message, parsed_message,
+    self.assertEqual(message, parsed_message,
                       '\n%s != %s' % (message, parsed_message))
 
-  def testPrintFloatFormat(self):
+  def testPrintFloatFormat(self, message_module):
     # Check that float_format argument is passed to sub-message formatting.
-    message = unittest_pb2.NestedTestAllTypes()
+    message = message_module.NestedTestAllTypes()
     # We use 1.25 as it is a round number in binary.  The proto 32-bit float
     # will not gain additional imprecise digits as a 64-bit Python float and
     # show up in its str.  32-bit 1.2 is noisy when extended to 64-bit:
@@ -272,93 +237,62 @@
     text_message = text_format.MessageToString(message, float_format='.15g')
     self.CompareToGoldenText(
         self.RemoveRedundantZeros(text_message),
-        'payload {{\n  {}\n  {}\n  {}\n  {}\n}}\n'.format(*formatted_fields))
+        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(*formatted_fields))
     # as_one_line=True is a separate code branch where float_format is passed.
     text_message = text_format.MessageToString(message, as_one_line=True,
                                                float_format='.15g')
     self.CompareToGoldenText(
         self.RemoveRedundantZeros(text_message),
-        'payload {{ {} {} {} {} }}'.format(*formatted_fields))
+        'payload {{ {0} {1} {2} {3} }}'.format(*formatted_fields))
 
-  def testMessageToString(self):
-    message = unittest_pb2.ForeignMessage()
+  def testMessageToString(self, message_module):
+    message = message_module.ForeignMessage()
     message.c = 123
     self.assertEqual('c: 123\n', str(message))
 
-  def RemoveRedundantZeros(self, text):
-    # Some platforms print 1e+5 as 1e+005.  This is fine, but we need to remove
-    # these zeros in order to match the golden file.
-    text = text.replace('e+0','e+').replace('e+0','e+') \
-               .replace('e-0','e-').replace('e-0','e-')
-    # Floating point fields are printed with .0 suffix even if they are
-    # actualy integer numbers.
-    text = re.compile('\.0$', re.MULTILINE).sub('', text)
-    return text
+  def testPrintField(self, message_module):
+    message = message_module.TestAllTypes()
+    field = message.DESCRIPTOR.fields_by_name['optional_float']
+    value = message.optional_float
+    out = text_format.TextWriter(False)
+    text_format.PrintField(field, value, out)
+    self.assertEqual('optional_float: 0.0\n', out.getvalue())
+    out.close()
+    # Test Printer
+    out = text_format.TextWriter(False)
+    printer = text_format._Printer(out)
+    printer.PrintField(field, value)
+    self.assertEqual('optional_float: 0.0\n', out.getvalue())
+    out.close()
 
-  def testParseGolden(self):
-    golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
-    parsed_message = unittest_pb2.TestAllTypes()
-    r = text_format.Parse(golden_text, parsed_message)
-    self.assertIs(r, parsed_message)
+  def testPrintFieldValue(self, message_module):
+    message = message_module.TestAllTypes()
+    field = message.DESCRIPTOR.fields_by_name['optional_float']
+    value = message.optional_float
+    out = text_format.TextWriter(False)
+    text_format.PrintFieldValue(field, value, out)
+    self.assertEqual('0.0', out.getvalue())
+    out.close()
+    # Test Printer
+    out = text_format.TextWriter(False)
+    printer = text_format._Printer(out)
+    printer.PrintFieldValue(field, value)
+    self.assertEqual('0.0', out.getvalue())
+    out.close()
 
-    message = unittest_pb2.TestAllTypes()
-    test_util.SetAllFields(message)
-    self.assertEquals(message, parsed_message)
-
-  def testParseGoldenExtensions(self):
-    golden_text = '\n'.join(self.ReadGolden(
-        'text_format_unittest_extensions_data.txt'))
-    parsed_message = unittest_pb2.TestAllExtensions()
-    text_format.Parse(golden_text, parsed_message)
-
-    message = unittest_pb2.TestAllExtensions()
-    test_util.SetAllExtensions(message)
-    self.assertEquals(message, parsed_message)
-
-  def testParseAllFields(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseAllFields(self, message_module):
+    message = message_module.TestAllTypes()
     test_util.SetAllFields(message)
     ascii_text = text_format.MessageToString(message)
 
-    parsed_message = unittest_pb2.TestAllTypes()
+    parsed_message = message_module.TestAllTypes()
     text_format.Parse(ascii_text, parsed_message)
     self.assertEqual(message, parsed_message)
-    test_util.ExpectAllFieldsSet(self, message)
+    if message_module is unittest_pb2:
+      test_util.ExpectAllFieldsSet(self, message)
 
-  def testParseAllExtensions(self):
-    message = unittest_pb2.TestAllExtensions()
-    test_util.SetAllExtensions(message)
-    ascii_text = text_format.MessageToString(message)
-
-    parsed_message = unittest_pb2.TestAllExtensions()
-    text_format.Parse(ascii_text, parsed_message)
-    self.assertEqual(message, parsed_message)
-
-  def testParseMessageSet(self):
-    message = unittest_pb2.TestAllTypes()
-    text = ('repeated_uint64: 1\n'
-            'repeated_uint64: 2\n')
-    text_format.Parse(text, message)
-    self.assertEqual(1, message.repeated_uint64[0])
-    self.assertEqual(2, message.repeated_uint64[1])
-
-    message = unittest_mset_pb2.TestMessageSetContainer()
-    text = ('message_set {\n'
-            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
-            '    i: 23\n'
-            '  }\n'
-            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
-            '    str: \"foo\"\n'
-            '  }\n'
-            '}\n')
-    text_format.Parse(text, message)
-    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
-    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
-    self.assertEquals(23, message.message_set.Extensions[ext1].i)
-    self.assertEquals('foo', message.message_set.Extensions[ext2].str)
-
-  def testParseExotic(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseExotic(self, message_module):
+    message = message_module.TestAllTypes()
     text = ('repeated_int64: -9223372036854775808\n'
             'repeated_uint64: 18446744073709551615\n'
             'repeated_double: 123.456\n'
@@ -383,8 +317,8 @@
     self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
     self.assertEqual(u'\u00fc', message.repeated_string[3])
 
-  def testParseTrailingCommas(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseTrailingCommas(self, message_module):
+    message = message_module.TestAllTypes()
     text = ('repeated_int64: 100;\n'
             'repeated_int64: 200;\n'
             'repeated_int64: 300,\n'
@@ -398,101 +332,87 @@
     self.assertEqual(u'one', message.repeated_string[0])
     self.assertEqual(u'two', message.repeated_string[1])
 
-  def testParseEmptyText(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseRepeatedScalarShortFormat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_int64: [100, 200];\n'
+            'repeated_int64: 300,\n'
+            'repeated_string: ["one", "two"];\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(100, message.repeated_int64[0])
+    self.assertEqual(200, message.repeated_int64[1])
+    self.assertEqual(300, message.repeated_int64[2])
+    self.assertEqual(u'one', message.repeated_string[0])
+    self.assertEqual(u'two', message.repeated_string[1])
+
+  def testParseRepeatedMessageShortFormat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n'
+            'repeated_nested_message: {bb: 300}\n'
+            'repeated_nested_message [{bb: 400}];\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(100, message.repeated_nested_message[0].bb)
+    self.assertEqual(200, message.repeated_nested_message[1].bb)
+    self.assertEqual(300, message.repeated_nested_message[2].bb)
+    self.assertEqual(400, message.repeated_nested_message[3].bb)
+
+  def testParseEmptyText(self, message_module):
+    message = message_module.TestAllTypes()
     text = ''
     text_format.Parse(text, message)
-    self.assertEquals(unittest_pb2.TestAllTypes(), message)
+    self.assertEqual(message_module.TestAllTypes(), message)
 
-  def testParseInvalidUtf8(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseInvalidUtf8(self, message_module):
+    message = message_module.TestAllTypes()
     text = 'repeated_string: "\\xc3\\xc3"'
     self.assertRaises(text_format.ParseError, text_format.Parse, text, message)
 
-  def testParseSingleWord(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseSingleWord(self, message_module):
+    message = message_module.TestAllTypes()
     text = 'foo'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
-        ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
-         '"foo".'),
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"foo".'),
         text_format.Parse, text, message)
 
-  def testParseUnknownField(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseUnknownField(self, message_module):
+    message = message_module.TestAllTypes()
     text = 'unknown_field: 8\n'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
-        ('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
-         '"unknown_field".'),
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"unknown_field".'),
         text_format.Parse, text, message)
 
-  def testParseBadExtension(self):
-    message = unittest_pb2.TestAllExtensions()
-    text = '[unknown_extension]: 8\n'
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError,
-        '1:2 : Extension "unknown_extension" not registered.',
-        text_format.Parse, text, message)
-    message = unittest_pb2.TestAllTypes()
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError,
-        ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
-         'extensions.'),
-        text_format.Parse, text, message)
-
-  def testParseGroupNotClosed(self):
-    message = unittest_pb2.TestAllTypes()
-    text = 'RepeatedGroup: <'
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError, '1:16 : Expected ">".',
-        text_format.Parse, text, message)
-
-    text = 'RepeatedGroup: {'
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError, '1:16 : Expected "}".',
-        text_format.Parse, text, message)
-
-  def testParseEmptyGroup(self):
-    message = unittest_pb2.TestAllTypes()
-    text = 'OptionalGroup: {}'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
-    message.Clear()
-
-    message = unittest_pb2.TestAllTypes()
-    text = 'OptionalGroup: <>'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
-  def testParseBadEnumValue(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseBadEnumValue(self, message_module):
+    message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
-        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
-         'has no value named BARR.'),
+        (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+         r'has no value named BARR.'),
         text_format.Parse, text, message)
 
-    message = unittest_pb2.TestAllTypes()
+    message = message_module.TestAllTypes()
     text = 'optional_nested_enum: 100'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
-        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
-         'has no value with number 100.'),
+        (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+         r'has no value with number 100.'),
         text_format.Parse, text, message)
 
-  def testParseBadIntValue(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseBadIntValue(self, message_module):
+    message = message_module.TestAllTypes()
     text = 'optional_int32: bork'
-    self.assertRaisesWithLiteralMatch(
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:17 : Couldn\'t parse integer: bork'),
         text_format.Parse, text, message)
 
-  def testParseStringFieldUnescape(self):
-    message = unittest_pb2.TestAllTypes()
+  def testParseStringFieldUnescape(self, message_module):
+    message = message_module.TestAllTypes()
     text = r'''repeated_string: "\xf\x62"
                repeated_string: "\\xf\\x62"
                repeated_string: "\\\xf\\\x62"
@@ -511,74 +431,102 @@
                      message.repeated_string[4])
     self.assertEqual(SLASH + 'x20', message.repeated_string[5])
 
-  def testMergeRepeatedScalars(self):
-    message = unittest_pb2.TestAllTypes()
+  def testMergeDuplicateScalars(self, message_module):
+    message = message_module.TestAllTypes()
     text = ('optional_int32: 42 '
             'optional_int32: 67')
     r = text_format.Merge(text, message)
     self.assertIs(r, message)
     self.assertEqual(67, message.optional_int32)
 
-  def testParseRepeatedScalars(self):
-    message = unittest_pb2.TestAllTypes()
-    text = ('optional_int32: 42 '
-            'optional_int32: 67')
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError,
-        ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
-         'have multiple "optional_int32" fields.'),
-        text_format.Parse, text, message)
-
-  def testMergeRepeatedNestedMessageScalars(self):
-    message = unittest_pb2.TestAllTypes()
+  def testMergeDuplicateNestedMessageScalars(self, message_module):
+    message = message_module.TestAllTypes()
     text = ('optional_nested_message { bb: 1 } '
             'optional_nested_message { bb: 2 }')
     r = text_format.Merge(text, message)
     self.assertTrue(r is message)
     self.assertEqual(2, message.optional_nested_message.bb)
 
-  def testParseRepeatedNestedMessageScalars(self):
+  def testParseOneof(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    text_format.Parse(text_format.MessageToString(m), m2)
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testParseMultipleOneof(self, message_module):
+    m_string = '\n'.join([
+        'oneof_uint32: 11',
+        'oneof_string: "foo"'])
+    m2 = message_module.TestAllTypes()
+    if message_module is unittest_pb2:
+      with self.assertRaisesRegexp(
+          text_format.ParseError, ' is specified along with field '):
+        text_format.Parse(m_string, m2)
+    else:
+      text_format.Parse(m_string, m2)
+      self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
+
+
+# These are tests that aren't fundamentally specific to proto2, but are at
+# the moment because of differences between the proto2 and proto3 test schemas.
+# Ideally the schemas would be made more similar so these tests could pass.
+class OnlyWorksWithProto2RightNowTests(TextFormatBase):
+
+  def testPrintAllFieldsPointy(self):
     message = unittest_pb2.TestAllTypes()
-    text = ('optional_nested_message { bb: 1 } '
-            'optional_nested_message { bb: 2 }')
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError,
-        ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
-         'should not have multiple "bb" fields.'),
-        text_format.Parse, text, message)
+    test_util.SetAllFields(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(
+            text_format.MessageToString(message, pointy_brackets=True)),
+        'text_format_unittest_data_pointy_oneof.txt')
 
-  def testMergeRepeatedExtensionScalars(self):
-    message = unittest_pb2.TestAllExtensions()
-    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
-            '[protobuf_unittest.optional_int32_extension]: 67')
-    text_format.Merge(text, message)
-    self.assertEqual(
-        67,
-        message.Extensions[unittest_pb2.optional_int32_extension])
-
-  def testParseRepeatedExtensionScalars(self):
-    message = unittest_pb2.TestAllExtensions()
-    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
-            '[protobuf_unittest.optional_int32_extension]: 67')
-    self.assertRaisesWithLiteralMatch(
-        text_format.ParseError,
-        ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
-         'should not have multiple '
-         '"protobuf_unittest.optional_int32_extension" extensions.'),
-        text_format.Parse, text, message)
-
-  def testParseLinesGolden(self):
-    opened = self.ReadGolden('text_format_unittest_data.txt')
+  def testParseGolden(self):
+    golden_text = '\n'.join(self.ReadGolden(
+        'text_format_unittest_data_oneof_implemented.txt'))
     parsed_message = unittest_pb2.TestAllTypes()
-    r = text_format.ParseLines(opened, parsed_message)
+    r = text_format.Parse(golden_text, parsed_message)
     self.assertIs(r, parsed_message)
 
     message = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(message)
-    self.assertEquals(message, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testPrintAllFields(self):
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'text_format_unittest_data_oneof_implemented.txt')
+
+  def testPrintAllFieldsPointy(self):
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(
+            text_format.MessageToString(message, pointy_brackets=True)),
+        'text_format_unittest_data_pointy_oneof.txt')
+
+  def testPrintInIndexOrder(self):
+    message = unittest_pb2.TestFieldOrderings()
+    message.my_string = '115'
+    message.my_int = 101
+    message.my_float = 111
+    message.optional_nested_message.oo = 0
+    message.optional_nested_message.bb = 1
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, use_index_order=True)),
+        'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n'
+        'optional_nested_message {\n  oo: 0\n  bb: 1\n}\n')
+    self.CompareToGoldenText(
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message)),
+        'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n'
+        'optional_nested_message {\n  bb: 1\n  oo: 0\n}\n')
 
   def testMergeLinesGolden(self):
-    opened = self.ReadGolden('text_format_unittest_data.txt')
+    opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
     parsed_message = unittest_pb2.TestAllTypes()
     r = text_format.MergeLines(opened, parsed_message)
     self.assertIs(r, parsed_message)
@@ -587,15 +535,483 @@
     test_util.SetAllFields(message)
     self.assertEqual(message, parsed_message)
 
-  def testParseOneof(self):
-    m = unittest_pb2.TestAllTypes()
-    m.oneof_uint32 = 11
-    m2 = unittest_pb2.TestAllTypes()
-    text_format.Parse(text_format.MessageToString(m), m2)
-    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+  def testParseLinesGolden(self):
+    opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
+    parsed_message = unittest_pb2.TestAllTypes()
+    r = text_format.ParseLines(opened, parsed_message)
+    self.assertIs(r, parsed_message)
+
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.assertEqual(message, parsed_message)
+
+  def testPrintMap(self):
+    message = map_unittest_pb2.TestMap()
+
+    message.map_int32_int32[-123] = -456
+    message.map_int64_int64[-2**33] = -2**34
+    message.map_uint32_uint32[123] = 456
+    message.map_uint64_uint64[2**33] = 2**34
+    message.map_string_string["abc"] = "123"
+    message.map_int32_foreign_message[111].c = 5
+
+    # Maps are serialized to text format using their underlying repeated
+    # representation.
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        'map_int32_int32 {\n'
+        '  key: -123\n'
+        '  value: -456\n'
+        '}\n'
+        'map_int64_int64 {\n'
+        '  key: -8589934592\n'
+        '  value: -17179869184\n'
+        '}\n'
+        'map_uint32_uint32 {\n'
+        '  key: 123\n'
+        '  value: 456\n'
+        '}\n'
+        'map_uint64_uint64 {\n'
+        '  key: 8589934592\n'
+        '  value: 17179869184\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "123"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 5\n'
+        '  }\n'
+        '}\n')
+
+  def testMapOrderEnforcement(self):
+    message = map_unittest_pb2.TestMap()
+    for letter in string.ascii_uppercase[13:26]:
+      message.map_string_string[letter] = 'dummy'
+    for letter in reversed(string.ascii_uppercase[0:13]):
+      message.map_string_string[letter] = 'dummy'
+    golden = ''.join((
+        'map_string_string {\n  key: "%c"\n  value: "dummy"\n}\n' % (letter,)
+        for letter in string.ascii_uppercase))
+    self.CompareToGoldenText(text_format.MessageToString(message), golden)
+
+  def testMapOrderSemantics(self):
+    golden_lines = self.ReadGolden('map_test_data.txt')
+    # The C++ implementation emits defaulted-value fields, while the Python
+    # implementation does not.  Adjusting for this is awkward, but it is
+    # valuable to test against a common golden file.
+    line_blacklist = ('  key: 0\n',
+                      '  value: 0\n',
+                      '  key: false\n',
+                      '  value: false\n')
+    golden_lines = [line for line in golden_lines if line not in line_blacklist]
+
+    message = map_unittest_pb2.TestMap()
+    text_format.ParseLines(golden_lines, message)
+    candidate = text_format.MessageToString(message)
+    # The Python implementation emits "1.0" for the double value that the C++
+    # implementation emits as "1".
+    candidate = candidate.replace('1.0', '1', 2)
+    self.assertMultiLineEqual(candidate, ''.join(golden_lines))
 
 
-class TokenizerTest(basetest.TestCase):
+# Tests of proto2-only features (MessageSet, extensions, etc.).
+class Proto2Tests(TextFormatBase):
+
+  def testPrintMessageSet(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        'message_set {\n'
+        '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+        '    i: 23\n'
+        '  }\n'
+        '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+        '    str: \"foo\"\n'
+        '  }\n'
+        '}\n')
+
+    message = message_set_extensions_pb2.TestMessageSet()
+    ext = message_set_extensions_pb2.message_set_extension3
+    message.Extensions[ext].text = 'bar'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        '[google.protobuf.internal.TestMessageSetExtension3] {\n'
+        '  text: \"bar\"\n'
+        '}\n')
+
+  def testPrintMessageSetByFieldNumber(self):
+    out = text_format.TextWriter(False)
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    text_format.PrintMessage(message, out, use_field_number=True)
+    self.CompareToGoldenText(
+        out.getvalue(),
+        '1 {\n'
+        '  1545008 {\n'
+        '    15: 23\n'
+        '  }\n'
+        '  1547769 {\n'
+        '    25: \"foo\"\n'
+        '  }\n'
+        '}\n')
+    out.close()
+
+  def testPrintMessageSetAsOneLine(self):
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    message.message_set.Extensions[ext1].i = 23
+    message.message_set.Extensions[ext2].str = 'foo'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message, as_one_line=True),
+        'message_set {'
+        ' [protobuf_unittest.TestMessageSetExtension1] {'
+        ' i: 23'
+        ' }'
+        ' [protobuf_unittest.TestMessageSetExtension2] {'
+        ' str: \"foo\"'
+        ' }'
+        ' }')
+
+  def testParseMessageSet(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('repeated_uint64: 1\n'
+            'repeated_uint64: 2\n')
+    text_format.Parse(text, message)
+    self.assertEqual(1, message.repeated_uint64[0])
+    self.assertEqual(2, message.repeated_uint64[1])
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+            '    i: 23\n'
+            '  }\n'
+            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+            '    str: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
+  def testParseMessageByFieldNumber(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('34: 1\n'
+            'repeated_uint64: 2\n')
+    text_format.Parse(text, message, allow_field_number=True)
+    self.assertEqual(1, message.repeated_uint64[0])
+    self.assertEqual(2, message.repeated_uint64[1])
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('1 {\n'
+            '  1545008 {\n'
+            '    15: 23\n'
+            '  }\n'
+            '  1547769 {\n'
+            '    25: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message, allow_field_number=True)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
+    # Can't parse field number without set allow_field_number=True.
+    message = unittest_pb2.TestAllTypes()
+    text = '34:1\n'
+    six.assertRaisesRegex(
+        self,
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"34".'),
+        text_format.Parse, text, message)
+
+    # Can't parse if field number is not found.
+    text = '1234:1\n'
+    six.assertRaisesRegex(
+        self,
+        text_format.ParseError,
+        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+         r'"1234".'),
+        text_format.Parse, text, message, allow_field_number=True)
+
+  def testPrintAllExtensions(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
+        'text_format_unittest_extensions_data.txt')
+
+  def testPrintAllExtensionsPointy(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, pointy_brackets=True)),
+        'text_format_unittest_extensions_data_pointy.txt')
+
+  def testParseGoldenExtensions(self):
+    golden_text = '\n'.join(self.ReadGolden(
+        'text_format_unittest_extensions_data.txt'))
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Parse(golden_text, parsed_message)
+
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    self.assertEqual(message, parsed_message)
+
+  def testParseAllExtensions(self):
+    message = unittest_pb2.TestAllExtensions()
+    test_util.SetAllExtensions(message)
+    ascii_text = text_format.MessageToString(message)
+
+    parsed_message = unittest_pb2.TestAllExtensions()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testParseAllowedUnknownExtension(self):
+    # Skip over unknown extension correctly.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [unknown_extension] {\n'
+            '    i: 23\n'
+            '    bin: "\xe0"'
+            '    [nested_unknown_ext]: {\n'
+            '      i: 23\n'
+            '      test: "test_string"\n'
+            '      floaty_float: -0.315\n'
+            '      num: -inf\n'
+            '      multiline_str: "abc"\n'
+            '          "def"\n'
+            '          "xyz."\n'
+            '      [nested_unknown_ext]: <\n'
+            '        i: 23\n'
+            '        i: 24\n'
+            '        pointfloat: .3\n'
+            '        test: "test_string"\n'
+            '        floaty_float: -0.315\n'
+            '        num: -inf\n'
+            '        long_string: "test" "test2" \n'
+            '      >\n'
+            '    }\n'
+            '  }\n'
+            '  [unknown_extension]: 5\n'
+            '}\n')
+    text_format.Parse(text, message, allow_unknown_extension=True)
+    golden = 'message_set {\n}\n'
+    self.CompareToGoldenText(text_format.MessageToString(message), golden)
+
+    # Catch parse errors in unknown extension.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    i:\n'  # Missing value.
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: }',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    str: "malformed string\n'  # Missing closing quote.
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: "',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    str: "malformed\n multiline\n string\n'
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: "',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [malformed_extension] <\n'
+                 '    i: -5\n'
+                 '  \n'  # Missing '>' here.
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          '5:1 : Expected ">".',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    # Don't allow unknown fields with allow_unknown_extension=True.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  unknown_field: true\n'
+                 '  \n'  # Missing '>' here.
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          ('2:3 : Message type '
+                           '"proto2_wireformat_unittest.TestMessageSet" has no'
+                           ' field named "unknown_field".'),
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    # Parse known extension correcty.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+            '    i: 23\n'
+            '  }\n'
+            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+            '    str: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message, allow_unknown_extension=True)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
+  def testParseBadExtension(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = '[unknown_extension]: 8\n'
+    six.assertRaisesRegex(self,
+        text_format.ParseError,
+        '1:2 : Extension "unknown_extension" not registered.',
+        text_format.Parse, text, message)
+    message = unittest_pb2.TestAllTypes()
+    six.assertRaisesRegex(self,
+        text_format.ParseError,
+        ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
+         'extensions.'),
+        text_format.Parse, text, message)
+
+  def testMergeDuplicateExtensionScalars(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+            '[protobuf_unittest.optional_int32_extension]: 67')
+    text_format.Merge(text, message)
+    self.assertEqual(
+        67,
+        message.Extensions[unittest_pb2.optional_int32_extension])
+
+  def testParseDuplicateExtensionScalars(self):
+    message = unittest_pb2.TestAllExtensions()
+    text = ('[protobuf_unittest.optional_int32_extension]: 42 '
+            '[protobuf_unittest.optional_int32_extension]: 67')
+    six.assertRaisesRegex(self,
+        text_format.ParseError,
+        ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
+         'should not have multiple '
+         '"protobuf_unittest.optional_int32_extension" extensions.'),
+        text_format.Parse, text, message)
+
+  def testParseDuplicateNestedMessageScalars(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('optional_nested_message { bb: 1 } '
+            'optional_nested_message { bb: 2 }')
+    six.assertRaisesRegex(self,
+        text_format.ParseError,
+        ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
+         'should not have multiple "bb" fields.'),
+        text_format.Parse, text, message)
+
+  def testParseDuplicateScalars(self):
+    message = unittest_pb2.TestAllTypes()
+    text = ('optional_int32: 42 '
+            'optional_int32: 67')
+    six.assertRaisesRegex(self,
+        text_format.ParseError,
+        ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
+         'have multiple "optional_int32" fields.'),
+        text_format.Parse, text, message)
+
+  def testParseGroupNotClosed(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'RepeatedGroup: <'
+    six.assertRaisesRegex(self,
+        text_format.ParseError, '1:16 : Expected ">".',
+        text_format.Parse, text, message)
+    text = 'RepeatedGroup: {'
+    six.assertRaisesRegex(self,
+        text_format.ParseError, '1:16 : Expected "}".',
+        text_format.Parse, text, message)
+
+  def testParseEmptyGroup(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: {}'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+    message.Clear()
+
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: <>'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+  # Maps aren't really proto2-only, but our test schema only has maps for
+  # proto2.
+  def testParseMap(self):
+    text = ('map_int32_int32 {\n'
+            '  key: -123\n'
+            '  value: -456\n'
+            '}\n'
+            'map_int64_int64 {\n'
+            '  key: -8589934592\n'
+            '  value: -17179869184\n'
+            '}\n'
+            'map_uint32_uint32 {\n'
+            '  key: 123\n'
+            '  value: 456\n'
+            '}\n'
+            'map_uint64_uint64 {\n'
+            '  key: 8589934592\n'
+            '  value: 17179869184\n'
+            '}\n'
+            'map_string_string {\n'
+            '  key: "abc"\n'
+            '  value: "123"\n'
+            '}\n'
+            'map_int32_foreign_message {\n'
+            '  key: 111\n'
+            '  value {\n'
+            '    c: 5\n'
+            '  }\n'
+            '}\n')
+    message = map_unittest_pb2.TestMap()
+    text_format.Parse(text, message)
+
+    self.assertEqual(-456, message.map_int32_int32[-123])
+    self.assertEqual(-2**34, message.map_int64_int64[-2**33])
+    self.assertEqual(456, message.map_uint32_uint32[123])
+    self.assertEqual(2**34, message.map_uint64_uint64[2**33])
+    self.assertEqual("123", message.map_string_string["abc"])
+    self.assertEqual(5, message.map_int32_foreign_message[111].c)
+
+
+class TokenizerTest(unittest.TestCase):
 
   def testSimpleTokenCases(self):
     text = ('identifier1:"string1"\n     \n\n'
@@ -740,4 +1156,4 @@
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 56d2646..1be3ad9 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -28,10 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
-# Copyright 2008 Google Inc. All Rights Reserved.
-
 """Provides type checking routines.
 
 This module defines type checking utilities in the forms of dictionaries:
@@ -49,8 +45,11 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-import sys  ##PY25
-if sys.version < '2.6': bytes = str  ##PY25
+import six
+
+if six.PY3:
+  long = int
+
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import decoder
 from google.protobuf.internal import encoder
@@ -59,6 +58,8 @@
 
 _FieldDescriptor = descriptor.FieldDescriptor
 
+def SupportsOpenEnums(field_descriptor):
+  return field_descriptor.containing_type.syntax == "proto3"
 
 def GetTypeChecker(field):
   """Returns a type checker for a message field of the specified types.
@@ -74,7 +75,11 @@
       field.type == _FieldDescriptor.TYPE_STRING):
     return UnicodeValueChecker()
   if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
-    return EnumValueChecker(field.enum_type)
+    if SupportsOpenEnums(field):
+      # When open enums are supported, any int32 can be assigned.
+      return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32]
+    else:
+      return EnumValueChecker(field.enum_type)
   return _VALUE_CHECKERS[field.cpp_type]
 
 
@@ -104,6 +109,16 @@
     return proposed_value
 
 
+class TypeCheckerWithDefault(TypeChecker):
+
+  def __init__(self, default_value, *acceptable_types):
+    TypeChecker.__init__(self, acceptable_types)
+    self._default_value = default_value
+
+  def DefaultValue(self):
+    return self._default_value
+
+
 # IntValueChecker and its subclasses perform integer type-checks
 # and bounds-checks.
 class IntValueChecker(object):
@@ -111,9 +126,9 @@
   """Checker used for integer fields.  Performs type-check and range check."""
 
   def CheckValue(self, proposed_value):
-    if not isinstance(proposed_value, (int, long)):
+    if not isinstance(proposed_value, six.integer_types):
       message = ('%.1024r has type %s, but expected one of: %s' %
-                 (proposed_value, type(proposed_value), (int, long)))
+                 (proposed_value, type(proposed_value), six.integer_types))
       raise TypeError(message)
     if not self._MIN <= proposed_value <= self._MAX:
       raise ValueError('Value out of range: %d' % proposed_value)
@@ -123,6 +138,9 @@
     proposed_value = self._TYPE(proposed_value)
     return proposed_value
 
+  def DefaultValue(self):
+    return 0
+
 
 class EnumValueChecker(object):
 
@@ -132,14 +150,17 @@
     self._enum_type = enum_type
 
   def CheckValue(self, proposed_value):
-    if not isinstance(proposed_value, (int, long)):
+    if not isinstance(proposed_value, six.integer_types):
       message = ('%.1024r has type %s, but expected one of: %s' %
-                 (proposed_value, type(proposed_value), (int, long)))
+                 (proposed_value, type(proposed_value), six.integer_types))
       raise TypeError(message)
     if proposed_value not in self._enum_type.values_by_number:
       raise ValueError('Unknown enum value: %d' % proposed_value)
     return proposed_value
 
+  def DefaultValue(self):
+    return self._enum_type.values[0].number
+
 
 class UnicodeValueChecker(object):
 
@@ -149,23 +170,25 @@
   """
 
   def CheckValue(self, proposed_value):
-    if not isinstance(proposed_value, (bytes, unicode)):
+    if not isinstance(proposed_value, (bytes, six.text_type)):
       message = ('%.1024r has type %s, but expected one of: %s' %
-                 (proposed_value, type(proposed_value), (bytes, unicode)))
+                 (proposed_value, type(proposed_value), (bytes, six.text_type)))
       raise TypeError(message)
 
-    # If the value is of type 'bytes' make sure that it is in 7-bit ASCII
-    # encoding.
+    # If the value is of type 'bytes' make sure that it is valid UTF-8 data.
     if isinstance(proposed_value, bytes):
       try:
-        proposed_value = proposed_value.decode('ascii')
+        proposed_value = proposed_value.decode('utf-8')
       except UnicodeDecodeError:
-        raise ValueError('%.1024r has type bytes, but isn\'t in 7-bit ASCII '
-                         'encoding. Non-ASCII strings must be converted to '
+        raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 '
+                         'encoding. Non-UTF-8 strings must be converted to '
                          'unicode objects before being added.' %
                          (proposed_value))
     return proposed_value
 
+  def DefaultValue(self):
+    return u""
+
 
 class Int32ValueChecker(IntValueChecker):
   # We're sure to use ints instead of longs here since comparison may be more
@@ -199,12 +222,13 @@
     _FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(),
     _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
     _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
-    _FieldDescriptor.CPPTYPE_DOUBLE: TypeChecker(
-        float, int, long),
-    _FieldDescriptor.CPPTYPE_FLOAT: TypeChecker(
-        float, int, long),
-    _FieldDescriptor.CPPTYPE_BOOL: TypeChecker(bool, int),
-    _FieldDescriptor.CPPTYPE_STRING: TypeChecker(bytes),
+    _FieldDescriptor.CPPTYPE_DOUBLE: TypeCheckerWithDefault(
+        0.0, float, int, long),
+    _FieldDescriptor.CPPTYPE_FLOAT: TypeCheckerWithDefault(
+        0.0, float, int, long),
+    _FieldDescriptor.CPPTYPE_BOOL: TypeCheckerWithDefault(
+        False, bool, int),
+    _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
     }
 
 
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 7177560..84073f1 100755
--- a/python/google/protobuf/internal/unknown_fields_test.py
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 # -*- coding: utf-8 -*-
 #
 # Protocol Buffers - Google's data interchange format
@@ -35,16 +35,28 @@
 
 __author__ = 'bohdank@google.com (Bohdan Koval)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
+from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf.internal import api_implementation
 from google.protobuf.internal import encoder
+from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf.internal import missing_enum_values_pb2
 from google.protobuf.internal import test_util
 from google.protobuf.internal import type_checkers
 
 
-class UnknownFieldsTest(basetest.TestCase):
+def SkipIfCppImplementation(func):
+  return unittest.skipIf(
+      api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
+      'C++ implementation does not expose unknown fields to Python')(func)
+
+
+class UnknownFieldsTest(unittest.TestCase):
 
   def setUp(self):
     self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
@@ -53,46 +65,6 @@
     self.all_fields_data = self.all_fields.SerializeToString()
     self.empty_message = unittest_pb2.TestEmptyMessage()
     self.empty_message.ParseFromString(self.all_fields_data)
-    self.unknown_fields = self.empty_message._unknown_fields
-
-  def GetField(self, name):
-    field_descriptor = self.descriptor.fields_by_name[name]
-    wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
-    field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
-    result_dict = {}
-    for tag_bytes, value in self.unknown_fields:
-      if tag_bytes == field_tag:
-        decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
-        decoder(value, 0, len(value), self.all_fields, result_dict)
-    return result_dict[field_descriptor]
-
-  def testEnum(self):
-    value = self.GetField('optional_nested_enum')
-    self.assertEqual(self.all_fields.optional_nested_enum, value)
-
-  def testRepeatedEnum(self):
-    value = self.GetField('repeated_nested_enum')
-    self.assertEqual(self.all_fields.repeated_nested_enum, value)
-
-  def testVarint(self):
-    value = self.GetField('optional_int32')
-    self.assertEqual(self.all_fields.optional_int32, value)
-
-  def testFixed32(self):
-    value = self.GetField('optional_fixed32')
-    self.assertEqual(self.all_fields.optional_fixed32, value)
-
-  def testFixed64(self):
-    value = self.GetField('optional_fixed64')
-    self.assertEqual(self.all_fields.optional_fixed64, value)
-
-  def testLengthDelimited(self):
-    value = self.GetField('optional_string')
-    self.assertEqual(self.all_fields.optional_string, value)
-
-  def testGroup(self):
-    value = self.GetField('optionalgroup')
-    self.assertEqual(self.all_fields.optionalgroup, value)
 
   def testSerialize(self):
     data = self.empty_message.SerializeToString()
@@ -101,42 +73,15 @@
     # stdout.
     self.assertTrue(data == self.all_fields_data)
 
-  def testCopyFrom(self):
-    message = unittest_pb2.TestEmptyMessage()
-    message.CopyFrom(self.empty_message)
-    self.assertEqual(self.unknown_fields, message._unknown_fields)
-
-  def testMergeFrom(self):
-    message = unittest_pb2.TestAllTypes()
-    message.optional_int32 = 1
-    message.optional_uint32 = 2
-    source = unittest_pb2.TestEmptyMessage()
-    source.ParseFromString(message.SerializeToString())
-
-    message.ClearField('optional_int32')
-    message.optional_int64 = 3
-    message.optional_uint32 = 4
-    destination = unittest_pb2.TestEmptyMessage()
-    destination.ParseFromString(message.SerializeToString())
-    unknown_fields = destination._unknown_fields[:]
-
-    destination.MergeFrom(source)
-    self.assertEqual(unknown_fields + source._unknown_fields,
-                     destination._unknown_fields)
-
-  def testClear(self):
-    self.empty_message.Clear()
-    self.assertEqual(0, len(self.empty_message._unknown_fields))
+  def testSerializeProto3(self):
+    # Verify that proto3 doesn't preserve unknown fields.
+    message = unittest_proto3_arena_pb2.TestEmptyMessage()
+    message.ParseFromString(self.all_fields_data)
+    self.assertEqual(0, len(message.SerializeToString()))
 
   def testByteSize(self):
     self.assertEqual(self.all_fields.ByteSize(), self.empty_message.ByteSize())
 
-  def testUnknownExtensions(self):
-    message = unittest_pb2.TestEmptyMessageWithExtensions()
-    message.ParseFromString(self.all_fields_data)
-    self.assertEqual(self.empty_message._unknown_fields,
-                     message._unknown_fields)
-
   def testListFields(self):
     # Make sure ListFields doesn't return unknown fields.
     self.assertEqual(0, len(self.empty_message.ListFields()))
@@ -148,15 +93,15 @@
 
     # Add an unknown extension.
     item = raw.item.add()
-    item.type_id = 1545009
-    message1 = unittest_mset_pb2.TestMessageSetExtension1()
+    item.type_id = 98418603
+    message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     message1.i = 12345
     item.message = message1.SerializeToString()
 
     serialized = raw.SerializeToString()
 
     # Parse message using the message set wire format.
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     proto.MergeFromString(serialized)
 
     # Verify that the unknown extension is serialized unchanged
@@ -174,8 +119,129 @@
     message.ParseFromString(self.all_fields.SerializeToString())
     self.assertNotEqual(self.empty_message, message)
 
+  def testDiscardUnknownFields(self):
+    self.empty_message.DiscardUnknownFields()
+    self.assertEqual(b'', self.empty_message.SerializeToString())
+    # Test message field and repeated message field.
+    message = unittest_pb2.TestAllTypes()
+    other_message = unittest_pb2.TestAllTypes()
+    other_message.optional_string = 'discard'
+    message.optional_nested_message.ParseFromString(
+        other_message.SerializeToString())
+    message.repeated_nested_message.add().ParseFromString(
+        other_message.SerializeToString())
+    self.assertNotEqual(
+        b'', message.optional_nested_message.SerializeToString())
+    self.assertNotEqual(
+        b'', message.repeated_nested_message[0].SerializeToString())
+    message.DiscardUnknownFields()
+    self.assertEqual(b'', message.optional_nested_message.SerializeToString())
+    self.assertEqual(
+        b'', message.repeated_nested_message[0].SerializeToString())
 
-class UnknownFieldsTest(basetest.TestCase):
+
+class UnknownFieldsAccessorsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    self.all_fields = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(self.all_fields)
+    self.all_fields_data = self.all_fields.SerializeToString()
+    self.empty_message = unittest_pb2.TestEmptyMessage()
+    self.empty_message.ParseFromString(self.all_fields_data)
+    if api_implementation.Type() != 'cpp':
+      # _unknown_fields is an implementation detail.
+      self.unknown_fields = self.empty_message._unknown_fields
+
+  # All the tests that use GetField() check an implementation detail of the
+  # Python implementation, which stores unknown fields as serialized strings.
+  # These tests are skipped by the C++ implementation: it's enough to check that
+  # the message is correctly serialized.
+
+  def GetField(self, name):
+    field_descriptor = self.descriptor.fields_by_name[name]
+    wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
+    field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
+    result_dict = {}
+    for tag_bytes, value in self.unknown_fields:
+      if tag_bytes == field_tag:
+        decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
+        decoder(value, 0, len(value), self.all_fields, result_dict)
+    return result_dict[field_descriptor]
+
+  @SkipIfCppImplementation
+  def testEnum(self):
+    value = self.GetField('optional_nested_enum')
+    self.assertEqual(self.all_fields.optional_nested_enum, value)
+
+  @SkipIfCppImplementation
+  def testRepeatedEnum(self):
+    value = self.GetField('repeated_nested_enum')
+    self.assertEqual(self.all_fields.repeated_nested_enum, value)
+
+  @SkipIfCppImplementation
+  def testVarint(self):
+    value = self.GetField('optional_int32')
+    self.assertEqual(self.all_fields.optional_int32, value)
+
+  @SkipIfCppImplementation
+  def testFixed32(self):
+    value = self.GetField('optional_fixed32')
+    self.assertEqual(self.all_fields.optional_fixed32, value)
+
+  @SkipIfCppImplementation
+  def testFixed64(self):
+    value = self.GetField('optional_fixed64')
+    self.assertEqual(self.all_fields.optional_fixed64, value)
+
+  @SkipIfCppImplementation
+  def testLengthDelimited(self):
+    value = self.GetField('optional_string')
+    self.assertEqual(self.all_fields.optional_string, value)
+
+  @SkipIfCppImplementation
+  def testGroup(self):
+    value = self.GetField('optionalgroup')
+    self.assertEqual(self.all_fields.optionalgroup, value)
+
+  def testCopyFrom(self):
+    message = unittest_pb2.TestEmptyMessage()
+    message.CopyFrom(self.empty_message)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
+
+  def testMergeFrom(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 1
+    message.optional_uint32 = 2
+    source = unittest_pb2.TestEmptyMessage()
+    source.ParseFromString(message.SerializeToString())
+
+    message.ClearField('optional_int32')
+    message.optional_int64 = 3
+    message.optional_uint32 = 4
+    destination = unittest_pb2.TestEmptyMessage()
+    destination.ParseFromString(message.SerializeToString())
+
+    destination.MergeFrom(source)
+    # Check that the fields where correctly merged, even stored in the unknown
+    # fields set.
+    message.ParseFromString(destination.SerializeToString())
+    self.assertEqual(message.optional_int32, 1)
+    self.assertEqual(message.optional_uint32, 2)
+    self.assertEqual(message.optional_int64, 3)
+
+  def testClear(self):
+    self.empty_message.Clear()
+    # All cleared, even unknown fields.
+    self.assertEqual(self.empty_message.SerializeToString(), b'')
+
+  def testUnknownExtensions(self):
+    message = unittest_pb2.TestEmptyMessageWithExtensions()
+    message.ParseFromString(self.all_fields_data)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
+
+
+class UnknownEnumValuesTest(unittest.TestCase):
 
   def setUp(self):
     self.descriptor = missing_enum_values_pb2.TestEnumValues.DESCRIPTOR
@@ -194,7 +260,14 @@
     self.message_data = self.message.SerializeToString()
     self.missing_message = missing_enum_values_pb2.TestMissingEnumValues()
     self.missing_message.ParseFromString(self.message_data)
-    self.unknown_fields = self.missing_message._unknown_fields
+    if api_implementation.Type() != 'cpp':
+      # _unknown_fields is an implementation detail.
+      self.unknown_fields = self.missing_message._unknown_fields
+
+  # All the tests that use GetField() check an implementation detail of the
+  # Python implementation, which stores unknown fields as serialized strings.
+  # These tests are skipped by the C++ implementation: it's enough to check that
+  # the message is correctly serialized.
 
   def GetField(self, name):
     field_descriptor = self.descriptor.fields_by_name[name]
@@ -208,15 +281,31 @@
         decoder(value, 0, len(value), self.message, result_dict)
     return result_dict[field_descriptor]
 
+  def testUnknownParseMismatchEnumValue(self):
+    just_string = missing_enum_values_pb2.JustString()
+    just_string.dummy = 'blah'
+
+    missing = missing_enum_values_pb2.TestEnumValues()
+    # The parse is invalid, storing the string proto into the set of
+    # unknown fields.
+    missing.ParseFromString(just_string.SerializeToString())
+
+    # Fetching the enum field shouldn't crash, instead returning the
+    # default value.
+    self.assertEqual(missing.optional_nested_enum, 0)
+
+  @SkipIfCppImplementation
   def testUnknownEnumValue(self):
     self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
     value = self.GetField('optional_nested_enum')
     self.assertEqual(self.message.optional_nested_enum, value)
 
+  @SkipIfCppImplementation
   def testUnknownRepeatedEnumValue(self):
     value = self.GetField('repeated_nested_enum')
     self.assertEqual(self.message.repeated_nested_enum, value)
 
+  @SkipIfCppImplementation
   def testUnknownPackedEnumValue(self):
     value = self.GetField('packed_nested_enum')
     self.assertEqual(self.message.packed_nested_enum, value)
@@ -228,4 +317,4 @@
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
new file mode 100644
index 0000000..7c5dffd
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -0,0 +1,724 @@
+# 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.
+
+"""Contains well known classes.
+
+This files defines well known classes which need extra maintenance including:
+  - Any
+  - Duration
+  - FieldMask
+  - Struct
+  - Timestamp
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from datetime import datetime
+from datetime import timedelta
+import six
+
+from google.protobuf.descriptor import FieldDescriptor
+
+_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
+_NANOS_PER_SECOND = 1000000000
+_NANOS_PER_MILLISECOND = 1000000
+_NANOS_PER_MICROSECOND = 1000
+_MILLIS_PER_SECOND = 1000
+_MICROS_PER_SECOND = 1000000
+_SECONDS_PER_DAY = 24 * 3600
+
+
+class Error(Exception):
+  """Top-level module error."""
+
+
+class ParseError(Error):
+  """Thrown in case of parsing error."""
+
+
+class Any(object):
+  """Class for Any Message type."""
+
+  def Pack(self, msg, type_url_prefix='type.googleapis.com/'):
+    """Packs the specified message into current Any message."""
+    if len(type_url_prefix) < 1 or type_url_prefix[-1] != '/':
+      self.type_url = '%s/%s' % (type_url_prefix, msg.DESCRIPTOR.full_name)
+    else:
+      self.type_url = '%s%s' % (type_url_prefix, msg.DESCRIPTOR.full_name)
+    self.value = msg.SerializeToString()
+
+  def Unpack(self, msg):
+    """Unpacks the current Any message into specified message."""
+    descriptor = msg.DESCRIPTOR
+    if not self.Is(descriptor):
+      return False
+    msg.ParseFromString(self.value)
+    return True
+
+  def TypeName(self):
+    """Returns the protobuf type name of the inner message."""
+    # Only last part is to be used: b/25630112
+    return self.type_url.split('/')[-1]
+
+  def Is(self, descriptor):
+    """Checks if this Any represents the given protobuf type."""
+    return self.TypeName() == descriptor.full_name
+
+
+class Timestamp(object):
+  """Class for Timestamp message type."""
+
+  def ToJsonString(self):
+    """Converts Timestamp to RFC 3339 date string format.
+
+    Returns:
+      A string converted from timestamp. The string is always Z-normalized
+      and uses 3, 6 or 9 fractional digits as required to represent the
+      exact time. Example of the return format: '1972-01-01T10:00:20.021Z'
+    """
+    nanos = self.nanos % _NANOS_PER_SECOND
+    total_sec = self.seconds + (self.nanos - nanos) // _NANOS_PER_SECOND
+    seconds = total_sec % _SECONDS_PER_DAY
+    days = (total_sec - seconds) // _SECONDS_PER_DAY
+    dt = datetime(1970, 1, 1) + timedelta(days, seconds)
+
+    result = dt.isoformat()
+    if (nanos % 1e9) == 0:
+      # If there are 0 fractional digits, the fractional
+      # point '.' should be omitted when serializing.
+      return result + 'Z'
+    if (nanos % 1e6) == 0:
+      # Serialize 3 fractional digits.
+      return result + '.%03dZ' % (nanos / 1e6)
+    if (nanos % 1e3) == 0:
+      # Serialize 6 fractional digits.
+      return result + '.%06dZ' % (nanos / 1e3)
+    # Serialize 9 fractional digits.
+    return result + '.%09dZ' % nanos
+
+  def FromJsonString(self, value):
+    """Parse a RFC 3339 date string format to Timestamp.
+
+    Args:
+      value: A date string. Any fractional digits (or none) and any offset are
+          accepted as long as they fit into nano-seconds precision.
+          Example of accepted format: '1972-01-01T10:00:20.021-05:00'
+
+    Raises:
+      ParseError: On parsing problems.
+    """
+    timezone_offset = value.find('Z')
+    if timezone_offset == -1:
+      timezone_offset = value.find('+')
+    if timezone_offset == -1:
+      timezone_offset = value.rfind('-')
+    if timezone_offset == -1:
+      raise ParseError(
+          'Failed to parse timestamp: missing valid timezone offset.')
+    time_value = value[0:timezone_offset]
+    # Parse datetime and nanos.
+    point_position = time_value.find('.')
+    if point_position == -1:
+      second_value = time_value
+      nano_value = ''
+    else:
+      second_value = time_value[:point_position]
+      nano_value = time_value[point_position + 1:]
+    date_object = datetime.strptime(second_value, _TIMESTAMPFOMAT)
+    td = date_object - datetime(1970, 1, 1)
+    seconds = td.seconds + td.days * _SECONDS_PER_DAY
+    if len(nano_value) > 9:
+      raise ParseError(
+          'Failed to parse Timestamp: nanos {0} more than '
+          '9 fractional digits.'.format(nano_value))
+    if nano_value:
+      nanos = round(float('0.' + nano_value) * 1e9)
+    else:
+      nanos = 0
+    # Parse timezone offsets.
+    if value[timezone_offset] == 'Z':
+      if len(value) != timezone_offset + 1:
+        raise ParseError('Failed to parse timestamp: invalid trailing'
+                         ' data {0}.'.format(value))
+    else:
+      timezone = value[timezone_offset:]
+      pos = timezone.find(':')
+      if pos == -1:
+        raise ParseError(
+            'Invalid timezone offset value: {0}.'.format(timezone))
+      if timezone[0] == '+':
+        seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+      else:
+        seconds += (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+    # Set seconds and nanos
+    self.seconds = int(seconds)
+    self.nanos = int(nanos)
+
+  def GetCurrentTime(self):
+    """Get the current UTC into Timestamp."""
+    self.FromDatetime(datetime.utcnow())
+
+  def ToNanoseconds(self):
+    """Converts Timestamp to nanoseconds since epoch."""
+    return self.seconds * _NANOS_PER_SECOND + self.nanos
+
+  def ToMicroseconds(self):
+    """Converts Timestamp to microseconds since epoch."""
+    return (self.seconds * _MICROS_PER_SECOND +
+            self.nanos // _NANOS_PER_MICROSECOND)
+
+  def ToMilliseconds(self):
+    """Converts Timestamp to milliseconds since epoch."""
+    return (self.seconds * _MILLIS_PER_SECOND +
+            self.nanos // _NANOS_PER_MILLISECOND)
+
+  def ToSeconds(self):
+    """Converts Timestamp to seconds since epoch."""
+    return self.seconds
+
+  def FromNanoseconds(self, nanos):
+    """Converts nanoseconds since epoch to Timestamp."""
+    self.seconds = nanos // _NANOS_PER_SECOND
+    self.nanos = nanos % _NANOS_PER_SECOND
+
+  def FromMicroseconds(self, micros):
+    """Converts microseconds since epoch to Timestamp."""
+    self.seconds = micros // _MICROS_PER_SECOND
+    self.nanos = (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND
+
+  def FromMilliseconds(self, millis):
+    """Converts milliseconds since epoch to Timestamp."""
+    self.seconds = millis // _MILLIS_PER_SECOND
+    self.nanos = (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND
+
+  def FromSeconds(self, seconds):
+    """Converts seconds since epoch to Timestamp."""
+    self.seconds = seconds
+    self.nanos = 0
+
+  def ToDatetime(self):
+    """Converts Timestamp to datetime."""
+    return datetime.utcfromtimestamp(
+        self.seconds + self.nanos / float(_NANOS_PER_SECOND))
+
+  def FromDatetime(self, dt):
+    """Converts datetime to Timestamp."""
+    td = dt - datetime(1970, 1, 1)
+    self.seconds = td.seconds + td.days * _SECONDS_PER_DAY
+    self.nanos = td.microseconds * _NANOS_PER_MICROSECOND
+
+
+class Duration(object):
+  """Class for Duration message type."""
+
+  def ToJsonString(self):
+    """Converts Duration to string format.
+
+    Returns:
+      A string converted from self. The string format will contains
+      3, 6, or 9 fractional digits depending on the precision required to
+      represent the exact Duration value. For example: "1s", "1.010s",
+      "1.000000100s", "-3.100s"
+    """
+    if self.seconds < 0 or self.nanos < 0:
+      result = '-'
+      seconds = - self.seconds + int((0 - self.nanos) // 1e9)
+      nanos = (0 - self.nanos) % 1e9
+    else:
+      result = ''
+      seconds = self.seconds + int(self.nanos // 1e9)
+      nanos = self.nanos % 1e9
+    result += '%d' % seconds
+    if (nanos % 1e9) == 0:
+      # If there are 0 fractional digits, the fractional
+      # point '.' should be omitted when serializing.
+      return result + 's'
+    if (nanos % 1e6) == 0:
+      # Serialize 3 fractional digits.
+      return result + '.%03ds' % (nanos / 1e6)
+    if (nanos % 1e3) == 0:
+      # Serialize 6 fractional digits.
+      return result + '.%06ds' % (nanos / 1e3)
+    # Serialize 9 fractional digits.
+    return result + '.%09ds' % nanos
+
+  def FromJsonString(self, value):
+    """Converts a string to Duration.
+
+    Args:
+      value: A string to be converted. The string must end with 's'. Any
+          fractional digits (or none) are accepted as long as they fit into
+          precision. For example: "1s", "1.01s", "1.0000001s", "-3.100s
+
+    Raises:
+      ParseError: On parsing problems.
+    """
+    if len(value) < 1 or value[-1] != 's':
+      raise ParseError(
+          'Duration must end with letter "s": {0}.'.format(value))
+    try:
+      pos = value.find('.')
+      if pos == -1:
+        self.seconds = int(value[:-1])
+        self.nanos = 0
+      else:
+        self.seconds = int(value[:pos])
+        if value[0] == '-':
+          self.nanos = int(round(float('-0{0}'.format(value[pos: -1])) *1e9))
+        else:
+          self.nanos = int(round(float('0{0}'.format(value[pos: -1])) *1e9))
+    except ValueError:
+      raise ParseError(
+          'Couldn\'t parse duration: {0}.'.format(value))
+
+  def ToNanoseconds(self):
+    """Converts a Duration to nanoseconds."""
+    return self.seconds * _NANOS_PER_SECOND + self.nanos
+
+  def ToMicroseconds(self):
+    """Converts a Duration to microseconds."""
+    micros = _RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND)
+    return self.seconds * _MICROS_PER_SECOND + micros
+
+  def ToMilliseconds(self):
+    """Converts a Duration to milliseconds."""
+    millis = _RoundTowardZero(self.nanos, _NANOS_PER_MILLISECOND)
+    return self.seconds * _MILLIS_PER_SECOND + millis
+
+  def ToSeconds(self):
+    """Converts a Duration to seconds."""
+    return self.seconds
+
+  def FromNanoseconds(self, nanos):
+    """Converts nanoseconds to Duration."""
+    self._NormalizeDuration(nanos // _NANOS_PER_SECOND,
+                            nanos % _NANOS_PER_SECOND)
+
+  def FromMicroseconds(self, micros):
+    """Converts microseconds to Duration."""
+    self._NormalizeDuration(
+        micros // _MICROS_PER_SECOND,
+        (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND)
+
+  def FromMilliseconds(self, millis):
+    """Converts milliseconds to Duration."""
+    self._NormalizeDuration(
+        millis // _MILLIS_PER_SECOND,
+        (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND)
+
+  def FromSeconds(self, seconds):
+    """Converts seconds to Duration."""
+    self.seconds = seconds
+    self.nanos = 0
+
+  def ToTimedelta(self):
+    """Converts Duration to timedelta."""
+    return timedelta(
+        seconds=self.seconds, microseconds=_RoundTowardZero(
+            self.nanos, _NANOS_PER_MICROSECOND))
+
+  def FromTimedelta(self, td):
+    """Convertd timedelta to Duration."""
+    self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY,
+                            td.microseconds * _NANOS_PER_MICROSECOND)
+
+  def _NormalizeDuration(self, seconds, nanos):
+    """Set Duration by seconds and nonas."""
+    # Force nanos to be negative if the duration is negative.
+    if seconds < 0 and nanos > 0:
+      seconds += 1
+      nanos -= _NANOS_PER_SECOND
+    self.seconds = seconds
+    self.nanos = nanos
+
+
+def _RoundTowardZero(value, divider):
+  """Truncates the remainder part after division."""
+  # For some languanges, the sign of the remainder is implementation
+  # dependent if any of the operands is negative. Here we enforce
+  # "rounded toward zero" semantics. For example, for (-5) / 2 an
+  # implementation may give -3 as the result with the remainder being
+  # 1. This function ensures we always return -2 (closer to zero).
+  result = value // divider
+  remainder = value % divider
+  if result < 0 and remainder > 0:
+    return result + 1
+  else:
+    return result
+
+
+class FieldMask(object):
+  """Class for FieldMask message type."""
+
+  def ToJsonString(self):
+    """Converts FieldMask to string according to proto3 JSON spec."""
+    return ','.join(self.paths)
+
+  def FromJsonString(self, value):
+    """Converts string to FieldMask according to proto3 JSON spec."""
+    self.Clear()
+    for path in value.split(','):
+      self.paths.append(path)
+
+  def IsValidForDescriptor(self, message_descriptor):
+    """Checks whether the FieldMask is valid for Message Descriptor."""
+    for path in self.paths:
+      if not _IsValidPath(message_descriptor, path):
+        return False
+    return True
+
+  def AllFieldsFromDescriptor(self, message_descriptor):
+    """Gets all direct fields of Message Descriptor to FieldMask."""
+    self.Clear()
+    for field in message_descriptor.fields:
+      self.paths.append(field.name)
+
+  def CanonicalFormFromMask(self, mask):
+    """Converts a FieldMask to the canonical form.
+
+    Removes paths that are covered by another path. For example,
+    "foo.bar" is covered by "foo" and will be removed if "foo"
+    is also in the FieldMask. Then sorts all paths in alphabetical order.
+
+    Args:
+      mask: The original FieldMask to be converted.
+    """
+    tree = _FieldMaskTree(mask)
+    tree.ToFieldMask(self)
+
+  def Union(self, mask1, mask2):
+    """Merges mask1 and mask2 into this FieldMask."""
+    _CheckFieldMaskMessage(mask1)
+    _CheckFieldMaskMessage(mask2)
+    tree = _FieldMaskTree(mask1)
+    tree.MergeFromFieldMask(mask2)
+    tree.ToFieldMask(self)
+
+  def Intersect(self, mask1, mask2):
+    """Intersects mask1 and mask2 into this FieldMask."""
+    _CheckFieldMaskMessage(mask1)
+    _CheckFieldMaskMessage(mask2)
+    tree = _FieldMaskTree(mask1)
+    intersection = _FieldMaskTree()
+    for path in mask2.paths:
+      tree.IntersectPath(path, intersection)
+    intersection.ToFieldMask(self)
+
+  def MergeMessage(
+      self, source, destination,
+      replace_message_field=False, replace_repeated_field=False):
+    """Merges fields specified in FieldMask from source to destination.
+
+    Args:
+      source: Source message.
+      destination: The destination message to be merged into.
+      replace_message_field: Replace message field if True. Merge message
+          field if False.
+      replace_repeated_field: Replace repeated field if True. Append
+          elements of repeated field if False.
+    """
+    tree = _FieldMaskTree(self)
+    tree.MergeMessage(
+        source, destination, replace_message_field, replace_repeated_field)
+
+
+def _IsValidPath(message_descriptor, path):
+  """Checks whether the path is valid for Message Descriptor."""
+  parts = path.split('.')
+  last = parts.pop()
+  for name in parts:
+    field = message_descriptor.fields_by_name[name]
+    if (field is None or
+        field.label == FieldDescriptor.LABEL_REPEATED or
+        field.type != FieldDescriptor.TYPE_MESSAGE):
+      return False
+    message_descriptor = field.message_type
+  return last in message_descriptor.fields_by_name
+
+
+def _CheckFieldMaskMessage(message):
+  """Raises ValueError if message is not a FieldMask."""
+  message_descriptor = message.DESCRIPTOR
+  if (message_descriptor.name != 'FieldMask' or
+      message_descriptor.file.name != 'google/protobuf/field_mask.proto'):
+    raise ValueError('Message {0} is not a FieldMask.'.format(
+        message_descriptor.full_name))
+
+
+class _FieldMaskTree(object):
+  """Represents a FieldMask in a tree structure.
+
+  For example, given a FieldMask "foo.bar,foo.baz,bar.baz",
+  the FieldMaskTree will be:
+      [_root] -+- foo -+- bar
+            |       |
+            |       +- baz
+            |
+            +- bar --- baz
+  In the tree, each leaf node represents a field path.
+  """
+
+  def __init__(self, field_mask=None):
+    """Initializes the tree by FieldMask."""
+    self._root = {}
+    if field_mask:
+      self.MergeFromFieldMask(field_mask)
+
+  def MergeFromFieldMask(self, field_mask):
+    """Merges a FieldMask to the tree."""
+    for path in field_mask.paths:
+      self.AddPath(path)
+
+  def AddPath(self, path):
+    """Adds a field path into the tree.
+
+    If the field path to add is a sub-path of an existing field path
+    in the tree (i.e., a leaf node), it means the tree already matches
+    the given path so nothing will be added to the tree. If the path
+    matches an existing non-leaf node in the tree, that non-leaf node
+    will be turned into a leaf node with all its children removed because
+    the path matches all the node's children. Otherwise, a new path will
+    be added.
+
+    Args:
+      path: The field path to add.
+    """
+    node = self._root
+    for name in path.split('.'):
+      if name not in node:
+        node[name] = {}
+      elif not node[name]:
+        # Pre-existing empty node implies we already have this entire tree.
+        return
+      node = node[name]
+    # Remove any sub-trees we might have had.
+    node.clear()
+
+  def ToFieldMask(self, field_mask):
+    """Converts the tree to a FieldMask."""
+    field_mask.Clear()
+    _AddFieldPaths(self._root, '', field_mask)
+
+  def IntersectPath(self, path, intersection):
+    """Calculates the intersection part of a field path with this tree.
+
+    Args:
+      path: The field path to calculates.
+      intersection: The out tree to record the intersection part.
+    """
+    node = self._root
+    for name in path.split('.'):
+      if name not in node:
+        return
+      elif not node[name]:
+        intersection.AddPath(path)
+        return
+      node = node[name]
+    intersection.AddLeafNodes(path, node)
+
+  def AddLeafNodes(self, prefix, node):
+    """Adds leaf nodes begin with prefix to this tree."""
+    if not node:
+      self.AddPath(prefix)
+    for name in node:
+      child_path = prefix + '.' + name
+      self.AddLeafNodes(child_path, node[name])
+
+  def MergeMessage(
+      self, source, destination,
+      replace_message, replace_repeated):
+    """Merge all fields specified by this tree from source to destination."""
+    _MergeMessage(
+        self._root, source, destination, replace_message, replace_repeated)
+
+
+def _StrConvert(value):
+  """Converts value to str if it is not."""
+  # This file is imported by c extension and some methods like ClearField
+  # requires string for the field name. py2/py3 has different text
+  # type and may use unicode.
+  if not isinstance(value, str):
+    return value.encode('utf-8')
+  return value
+
+
+def _MergeMessage(
+    node, source, destination, replace_message, replace_repeated):
+  """Merge all fields specified by a sub-tree from source to destination."""
+  source_descriptor = source.DESCRIPTOR
+  for name in node:
+    child = node[name]
+    field = source_descriptor.fields_by_name[name]
+    if field is None:
+      raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(
+          name, source_descriptor.full_name))
+    if child:
+      # Sub-paths are only allowed for singular message fields.
+      if (field.label == FieldDescriptor.LABEL_REPEATED or
+          field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):
+        raise ValueError('Error: Field {0} in message {1} is not a singular '
+                         'message field and cannot have sub-fields.'.format(
+                             name, source_descriptor.full_name))
+      _MergeMessage(
+          child, getattr(source, name), getattr(destination, name),
+          replace_message, replace_repeated)
+      continue
+    if field.label == FieldDescriptor.LABEL_REPEATED:
+      if replace_repeated:
+        destination.ClearField(_StrConvert(name))
+      repeated_source = getattr(source, name)
+      repeated_destination = getattr(destination, name)
+      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+        for item in repeated_source:
+          repeated_destination.add().MergeFrom(item)
+      else:
+        repeated_destination.extend(repeated_source)
+    else:
+      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+        if replace_message:
+          destination.ClearField(_StrConvert(name))
+        if source.HasField(name):
+          getattr(destination, name).MergeFrom(getattr(source, name))
+      else:
+        setattr(destination, name, getattr(source, name))
+
+
+def _AddFieldPaths(node, prefix, field_mask):
+  """Adds the field paths descended from node to field_mask."""
+  if not node:
+    field_mask.paths.append(prefix)
+    return
+  for name in sorted(node):
+    if prefix:
+      child_path = prefix + '.' + name
+    else:
+      child_path = name
+    _AddFieldPaths(node[name], child_path, field_mask)
+
+
+_INT_OR_FLOAT = six.integer_types + (float,)
+
+
+def _SetStructValue(struct_value, value):
+  if value is None:
+    struct_value.null_value = 0
+  elif isinstance(value, bool):
+    # Note: this check must come before the number check because in Python
+    # True and False are also considered numbers.
+    struct_value.bool_value = value
+  elif isinstance(value, six.string_types):
+    struct_value.string_value = value
+  elif isinstance(value, _INT_OR_FLOAT):
+    struct_value.number_value = value
+  else:
+    raise ValueError('Unexpected type')
+
+
+def _GetStructValue(struct_value):
+  which = struct_value.WhichOneof('kind')
+  if which == 'struct_value':
+    return struct_value.struct_value
+  elif which == 'null_value':
+    return None
+  elif which == 'number_value':
+    return struct_value.number_value
+  elif which == 'string_value':
+    return struct_value.string_value
+  elif which == 'bool_value':
+    return struct_value.bool_value
+  elif which == 'list_value':
+    return struct_value.list_value
+  elif which is None:
+    raise ValueError('Value not set')
+
+
+class Struct(object):
+  """Class for Struct message type."""
+
+  __slots__ = []
+
+  def __getitem__(self, key):
+    return _GetStructValue(self.fields[key])
+
+  def __setitem__(self, key, value):
+    _SetStructValue(self.fields[key], value)
+
+  def get_or_create_list(self, key):
+    """Returns a list for this key, creating if it didn't exist already."""
+    return self.fields[key].list_value
+
+  def get_or_create_struct(self, key):
+    """Returns a struct for this key, creating if it didn't exist already."""
+    return self.fields[key].struct_value
+
+  # TODO(haberman): allow constructing/merging from dict.
+
+
+class ListValue(object):
+  """Class for ListValue message type."""
+
+  def __len__(self):
+    return len(self.values)
+
+  def append(self, value):
+    _SetStructValue(self.values.add(), value)
+
+  def extend(self, elem_seq):
+    for value in elem_seq:
+      self.append(value)
+
+  def __getitem__(self, index):
+    """Retrieves item by the specified index."""
+    return _GetStructValue(self.values.__getitem__(index))
+
+  def __setitem__(self, index, value):
+    _SetStructValue(self.values.__getitem__(index), value)
+
+  def items(self):
+    for i in range(len(self)):
+      yield self[i]
+
+  def add_struct(self):
+    """Appends and returns a struct value as the next value in the list."""
+    return self.values.add().struct_value
+
+  def add_list(self):
+    """Appends and returns a list value as the next value in the list."""
+    return self.values.add().list_value
+
+
+WKTBASES = {
+    'google.protobuf.Any': Any,
+    'google.protobuf.Duration': Duration,
+    'google.protobuf.FieldMask': FieldMask,
+    'google.protobuf.ListValue': ListValue,
+    'google.protobuf.Struct': Struct,
+    'google.protobuf.Timestamp': Timestamp,
+}
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
new file mode 100644
index 0000000..2f32ac9
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -0,0 +1,644 @@
+#! /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.
+
+"""Test for google.protobuf.internal.well_known_types."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from datetime import datetime
+
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
+from google.protobuf import any_pb2
+from google.protobuf import duration_pb2
+from google.protobuf import field_mask_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import timestamp_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf.internal import any_test_pb2
+from google.protobuf.internal import test_util
+from google.protobuf.internal import well_known_types
+from google.protobuf import descriptor
+from google.protobuf import text_format
+
+
+class TimeUtilTestBase(unittest.TestCase):
+
+  def CheckTimestampConversion(self, message, text):
+    self.assertEqual(text, message.ToJsonString())
+    parsed_message = timestamp_pb2.Timestamp()
+    parsed_message.FromJsonString(text)
+    self.assertEqual(message, parsed_message)
+
+  def CheckDurationConversion(self, message, text):
+    self.assertEqual(text, message.ToJsonString())
+    parsed_message = duration_pb2.Duration()
+    parsed_message.FromJsonString(text)
+    self.assertEqual(message, parsed_message)
+
+
+class TimeUtilTest(TimeUtilTestBase):
+
+  def testTimestampSerializeAndParse(self):
+    message = timestamp_pb2.Timestamp()
+    # Generated output should contain 3, 6, or 9 fractional digits.
+    message.seconds = 0
+    message.nanos = 0
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00Z')
+    message.nanos = 10000000
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.010Z')
+    message.nanos = 10000
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000010Z')
+    message.nanos = 10
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000000010Z')
+    # Test min timestamps.
+    message.seconds = -62135596800
+    message.nanos = 0
+    self.CheckTimestampConversion(message, '0001-01-01T00:00:00Z')
+    # Test max timestamps.
+    message.seconds = 253402300799
+    message.nanos = 999999999
+    self.CheckTimestampConversion(message, '9999-12-31T23:59:59.999999999Z')
+    # Test negative timestamps.
+    message.seconds = -1
+    self.CheckTimestampConversion(message, '1969-12-31T23:59:59.999999999Z')
+
+    # Parsing accepts an fractional digits as long as they fit into nano
+    # precision.
+    message.FromJsonString('1970-01-01T00:00:00.1Z')
+    self.assertEqual(0, message.seconds)
+    self.assertEqual(100000000, message.nanos)
+    # Parsing accpets offsets.
+    message.FromJsonString('1970-01-01T00:00:00-08:00')
+    self.assertEqual(8 * 3600, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+  def testDurationSerializeAndParse(self):
+    message = duration_pb2.Duration()
+    # Generated output should contain 3, 6, or 9 fractional digits.
+    message.seconds = 0
+    message.nanos = 0
+    self.CheckDurationConversion(message, '0s')
+    message.nanos = 10000000
+    self.CheckDurationConversion(message, '0.010s')
+    message.nanos = 10000
+    self.CheckDurationConversion(message, '0.000010s')
+    message.nanos = 10
+    self.CheckDurationConversion(message, '0.000000010s')
+
+    # Test min and max
+    message.seconds = 315576000000
+    message.nanos = 999999999
+    self.CheckDurationConversion(message, '315576000000.999999999s')
+    message.seconds = -315576000000
+    message.nanos = -999999999
+    self.CheckDurationConversion(message, '-315576000000.999999999s')
+
+    # Parsing accepts an fractional digits as long as they fit into nano
+    # precision.
+    message.FromJsonString('0.1s')
+    self.assertEqual(100000000, message.nanos)
+    message.FromJsonString('0.0000001s')
+    self.assertEqual(100, message.nanos)
+
+  def testTimestampIntegerConversion(self):
+    message = timestamp_pb2.Timestamp()
+    message.FromNanoseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.000000001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToNanoseconds())
+
+    message.FromNanoseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999999999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToNanoseconds())
+
+    message.FromMicroseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.000001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMicroseconds())
+
+    message.FromMicroseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMicroseconds())
+
+    message.FromMilliseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMilliseconds())
+
+    message.FromMilliseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMilliseconds())
+
+    message.FromSeconds(1)
+    self.assertEqual('1970-01-01T00:00:01Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToSeconds())
+
+    message.FromSeconds(-1)
+    self.assertEqual('1969-12-31T23:59:59Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToSeconds())
+
+    message.FromNanoseconds(1999)
+    self.assertEqual(1, message.ToMicroseconds())
+    # For negative values, Timestamp will be rounded down.
+    # For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds
+    # will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than
+    # "1970-01-01T00:00:00Z" (i.e., 0s).
+    message.FromNanoseconds(-1999)
+    self.assertEqual(-2, message.ToMicroseconds())
+
+  def testDurationIntegerConversion(self):
+    message = duration_pb2.Duration()
+    message.FromNanoseconds(1)
+    self.assertEqual('0.000000001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToNanoseconds())
+
+    message.FromNanoseconds(-1)
+    self.assertEqual('-0.000000001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToNanoseconds())
+
+    message.FromMicroseconds(1)
+    self.assertEqual('0.000001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMicroseconds())
+
+    message.FromMicroseconds(-1)
+    self.assertEqual('-0.000001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMicroseconds())
+
+    message.FromMilliseconds(1)
+    self.assertEqual('0.001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMilliseconds())
+
+    message.FromMilliseconds(-1)
+    self.assertEqual('-0.001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMilliseconds())
+
+    message.FromSeconds(1)
+    self.assertEqual('1s', message.ToJsonString())
+    self.assertEqual(1, message.ToSeconds())
+
+    message.FromSeconds(-1)
+    self.assertEqual('-1s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToSeconds())
+
+    # Test truncation behavior.
+    message.FromNanoseconds(1999)
+    self.assertEqual(1, message.ToMicroseconds())
+
+    # For negative values, Duration will be rounded towards 0.
+    message.FromNanoseconds(-1999)
+    self.assertEqual(-1, message.ToMicroseconds())
+
+  def testDatetimeConverison(self):
+    message = timestamp_pb2.Timestamp()
+    dt = datetime(1970, 1, 1)
+    message.FromDatetime(dt)
+    self.assertEqual(dt, message.ToDatetime())
+
+    message.FromMilliseconds(1999)
+    self.assertEqual(datetime(1970, 1, 1, 0, 0, 1, 999000),
+                     message.ToDatetime())
+
+  def testTimedeltaConversion(self):
+    message = duration_pb2.Duration()
+    message.FromNanoseconds(1999999999)
+    td = message.ToTimedelta()
+    self.assertEqual(1, td.seconds)
+    self.assertEqual(999999, td.microseconds)
+
+    message.FromNanoseconds(-1999999999)
+    td = message.ToTimedelta()
+    self.assertEqual(-1, td.days)
+    self.assertEqual(86398, td.seconds)
+    self.assertEqual(1, td.microseconds)
+
+    message.FromMicroseconds(-1)
+    td = message.ToTimedelta()
+    self.assertEqual(-1, td.days)
+    self.assertEqual(86399, td.seconds)
+    self.assertEqual(999999, td.microseconds)
+    converted_message = duration_pb2.Duration()
+    converted_message.FromTimedelta(td)
+    self.assertEqual(message, converted_message)
+
+  def testInvalidTimestamp(self):
+    message = timestamp_pb2.Timestamp()
+    self.assertRaisesRegexp(
+        ValueError,
+        'time data \'10000-01-01T00:00:00\' does not match'
+        ' format \'%Y-%m-%dT%H:%M:%S\'',
+        message.FromJsonString, '10000-01-01T00:00:00.00Z')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'nanos 0123456789012 more than 9 fractional digits.',
+        message.FromJsonString,
+        '1970-01-01T00:00:00.0123456789012Z')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        (r'Invalid timezone offset value: \+08.'),
+        message.FromJsonString,
+        '1972-01-01T01:00:00.01+08',)
+    self.assertRaisesRegexp(
+        ValueError,
+        'year is out of range',
+        message.FromJsonString,
+        '0000-01-01T00:00:00Z')
+    message.seconds = 253402300800
+    self.assertRaisesRegexp(
+        OverflowError,
+        'date value out of range',
+        message.ToJsonString)
+
+  def testInvalidDuration(self):
+    message = duration_pb2.Duration()
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'Duration must end with letter "s": 1.',
+        message.FromJsonString, '1')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'Couldn\'t parse duration: 1...2s.',
+        message.FromJsonString, '1...2s')
+
+
+class FieldMaskTest(unittest.TestCase):
+
+  def testStringFormat(self):
+    mask = field_mask_pb2.FieldMask()
+    self.assertEqual('', mask.ToJsonString())
+    mask.paths.append('foo')
+    self.assertEqual('foo', mask.ToJsonString())
+    mask.paths.append('bar')
+    self.assertEqual('foo,bar', mask.ToJsonString())
+
+    mask.FromJsonString('')
+    self.assertEqual('', mask.ToJsonString())
+    mask.FromJsonString('foo')
+    self.assertEqual(['foo'], mask.paths)
+    mask.FromJsonString('foo,bar')
+    self.assertEqual(['foo', 'bar'], mask.paths)
+
+  def testDescriptorToFieldMask(self):
+    mask = field_mask_pb2.FieldMask()
+    msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    mask.AllFieldsFromDescriptor(msg_descriptor)
+    self.assertEqual(75, len(mask.paths))
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    for field in msg_descriptor.fields:
+      self.assertTrue(field.name in mask.paths)
+    mask.paths.append('optional_nested_message.bb')
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    mask.paths.append('repeated_nested_message.bb')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+
+  def testCanonicalFrom(self):
+    mask = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    # Paths will be sorted.
+    mask.FromJsonString('baz.quz,bar,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString())
+    # Duplicated paths will be removed.
+    mask.FromJsonString('foo,bar,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,foo', out_mask.ToJsonString())
+    # Sub-paths of other paths will be removed.
+    mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString())
+
+    # Test more deeply nested cases.
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar.baz1,foo.bar.baz2',
+                     out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar.baz1,foo.bar.baz2',
+                     out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar', out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo', out_mask.ToJsonString())
+
+  def testUnion(self):
+    mask1 = field_mask_pb2.FieldMask()
+    mask2 = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    mask1.FromJsonString('foo,baz')
+    mask2.FromJsonString('bar,quz')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString())
+    # Overlap with duplicated paths.
+    mask1.FromJsonString('foo,baz.bb')
+    mask2.FromJsonString('baz.bb,quz')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString())
+    # Overlap with paths covering some other paths.
+    mask1.FromJsonString('foo.bar.baz,quz')
+    mask2.FromJsonString('foo.bar,bar')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString())
+
+  def testIntersect(self):
+    mask1 = field_mask_pb2.FieldMask()
+    mask2 = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    # Test cases without overlapping.
+    mask1.FromJsonString('foo,baz')
+    mask2.FromJsonString('bar,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('', out_mask.ToJsonString())
+    # Overlap with duplicated paths.
+    mask1.FromJsonString('foo,baz.bb')
+    mask2.FromJsonString('baz.bb,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('baz.bb', out_mask.ToJsonString())
+    # Overlap with paths covering some other paths.
+    mask1.FromJsonString('foo.bar.baz,quz')
+    mask2.FromJsonString('foo.bar,bar')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
+    mask1.FromJsonString('foo.bar,bar')
+    mask2.FromJsonString('foo.bar.baz,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
+
+  def testMergeMessage(self):
+    # Test merge one field.
+    src = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(src)
+    for field in src.DESCRIPTOR.fields:
+      if field.containing_oneof:
+        continue
+      field_name = field.name
+      dst = unittest_pb2.TestAllTypes()
+      # Only set one path to mask.
+      mask = field_mask_pb2.FieldMask()
+      mask.paths.append(field_name)
+      mask.MergeMessage(src, dst)
+      # The expected result message.
+      msg = unittest_pb2.TestAllTypes()
+      if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        repeated_src = getattr(src, field_name)
+        repeated_msg = getattr(msg, field_name)
+        if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          for item in repeated_src:
+            repeated_msg.add().CopyFrom(item)
+        else:
+          repeated_msg.extend(repeated_src)
+      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        getattr(msg, field_name).CopyFrom(getattr(src, field_name))
+      else:
+        setattr(msg, field_name, getattr(src, field_name))
+      # Only field specified in mask is merged.
+      self.assertEqual(msg, dst)
+
+    # Test merge nested fields.
+    nested_src = unittest_pb2.NestedTestAllTypes()
+    nested_dst = unittest_pb2.NestedTestAllTypes()
+    nested_src.child.payload.optional_int32 = 1234
+    nested_src.child.child.payload.optional_int32 = 5678
+    mask = field_mask_pb2.FieldMask()
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(0, nested_dst.child.child.payload.optional_int32)
+
+    mask.FromJsonString('child.child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    nested_dst.Clear()
+    mask.FromJsonString('child.child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(0, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    nested_dst.Clear()
+    mask.FromJsonString('child')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    # Test MergeOptions.
+    nested_dst.Clear()
+    nested_dst.child.payload.optional_int64 = 4321
+    # Message fields will be merged by default.
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(4321, nested_dst.child.payload.optional_int64)
+    # Change the behavior to replace message fields.
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst, True, False)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(0, nested_dst.child.payload.optional_int64)
+
+    # By default, fields missing in source are not cleared in destination.
+    nested_dst.payload.optional_int32 = 1234
+    self.assertTrue(nested_dst.HasField('payload'))
+    mask.FromJsonString('payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertTrue(nested_dst.HasField('payload'))
+    # But they are cleared when replacing message fields.
+    nested_dst.Clear()
+    nested_dst.payload.optional_int32 = 1234
+    mask.FromJsonString('payload')
+    mask.MergeMessage(nested_src, nested_dst, True, False)
+    self.assertFalse(nested_dst.HasField('payload'))
+
+    nested_src.payload.repeated_int32.append(1234)
+    nested_dst.payload.repeated_int32.append(5678)
+    # Repeated fields will be appended by default.
+    mask.FromJsonString('payload.repeated_int32')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(2, len(nested_dst.payload.repeated_int32))
+    self.assertEqual(5678, nested_dst.payload.repeated_int32[0])
+    self.assertEqual(1234, nested_dst.payload.repeated_int32[1])
+    # Change the behavior to replace repeated fields.
+    mask.FromJsonString('payload.repeated_int32')
+    mask.MergeMessage(nested_src, nested_dst, False, True)
+    self.assertEqual(1, len(nested_dst.payload.repeated_int32))
+    self.assertEqual(1234, nested_dst.payload.repeated_int32[0])
+
+
+class StructTest(unittest.TestCase):
+
+  def testStruct(self):
+    struct = struct_pb2.Struct()
+    struct_class = struct.__class__
+
+    struct['key1'] = 5
+    struct['key2'] = 'abc'
+    struct['key3'] = True
+    struct.get_or_create_struct('key4')['subkey'] = 11.0
+    struct_list = struct.get_or_create_list('key5')
+    struct_list.extend([6, 'seven', True, False, None])
+    struct_list.add_struct()['subkey2'] = 9
+
+    self.assertTrue(isinstance(struct, well_known_types.Struct))
+    self.assertEquals(5, struct['key1'])
+    self.assertEquals('abc', struct['key2'])
+    self.assertIs(True, struct['key3'])
+    self.assertEquals(11, struct['key4']['subkey'])
+    inner_struct = struct_class()
+    inner_struct['subkey2'] = 9
+    self.assertEquals([6, 'seven', True, False, None, inner_struct],
+                      list(struct['key5'].items()))
+
+    serialized = struct.SerializeToString()
+
+    struct2 = struct_pb2.Struct()
+    struct2.ParseFromString(serialized)
+
+    self.assertEquals(struct, struct2)
+
+    self.assertTrue(isinstance(struct2, well_known_types.Struct))
+    self.assertEquals(5, struct2['key1'])
+    self.assertEquals('abc', struct2['key2'])
+    self.assertIs(True, struct2['key3'])
+    self.assertEquals(11, struct2['key4']['subkey'])
+    self.assertEquals([6, 'seven', True, False, None, inner_struct],
+                      list(struct2['key5'].items()))
+
+    struct_list = struct2['key5']
+    self.assertEquals(6, struct_list[0])
+    self.assertEquals('seven', struct_list[1])
+    self.assertEquals(True, struct_list[2])
+    self.assertEquals(False, struct_list[3])
+    self.assertEquals(None, struct_list[4])
+    self.assertEquals(inner_struct, struct_list[5])
+
+    struct_list[1] = 7
+    self.assertEquals(7, struct_list[1])
+
+    struct_list.add_list().extend([1, 'two', True, False, None])
+    self.assertEquals([1, 'two', True, False, None],
+                      list(struct_list[6].items()))
+
+    text_serialized = str(struct)
+    struct3 = struct_pb2.Struct()
+    text_format.Merge(text_serialized, struct3)
+    self.assertEquals(struct, struct3)
+
+    struct.get_or_create_struct('key3')['replace'] = 12
+    self.assertEquals(12, struct['key3']['replace'])
+
+
+class AnyTest(unittest.TestCase):
+
+  def testAnyMessage(self):
+    # Creates and sets message.
+    msg = any_test_pb2.TestAny()
+    msg_descriptor = msg.DESCRIPTOR
+    all_types = unittest_pb2.TestAllTypes()
+    all_descriptor = all_types.DESCRIPTOR
+    all_types.repeated_string.append(u'\u00fc\ua71f')
+    # Packs to Any.
+    msg.value.Pack(all_types)
+    self.assertEqual(msg.value.type_url,
+                     'type.googleapis.com/%s' % all_descriptor.full_name)
+    self.assertEqual(msg.value.value,
+                     all_types.SerializeToString())
+    # Tests Is() method.
+    self.assertTrue(msg.value.Is(all_descriptor))
+    self.assertFalse(msg.value.Is(msg_descriptor))
+    # Unpacks Any.
+    unpacked_message = unittest_pb2.TestAllTypes()
+    self.assertTrue(msg.value.Unpack(unpacked_message))
+    self.assertEqual(all_types, unpacked_message)
+    # Unpacks to different type.
+    self.assertFalse(msg.value.Unpack(msg))
+    # Only Any messages have Pack method.
+    try:
+      msg.Pack(all_types)
+    except AttributeError:
+      pass
+    else:
+      raise AttributeError('%s should not have Pack method.' %
+                           msg_descriptor.full_name)
+
+  def testMessageName(self):
+    # Creates and sets message.
+    submessage = any_test_pb2.TestAny()
+    submessage.int_value = 12345
+    msg = any_pb2.Any()
+    msg.Pack(submessage)
+    self.assertEqual(msg.TypeName(), 'google.protobuf.internal.TestAny')
+
+  def testPackWithCustomTypeUrl(self):
+    submessage = any_test_pb2.TestAny()
+    submessage.int_value = 12345
+    msg = any_pb2.Any()
+    # Pack with a custom type URL prefix.
+    msg.Pack(submessage, 'type.myservice.com')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with a custom type URL prefix ending with '/'.
+    msg.Pack(submessage, 'type.myservice.com/')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with an empty type URL prefix.
+    msg.Pack(submessage, '')
+    self.assertEqual(msg.type_url,
+                     '/%s' % submessage.DESCRIPTOR.full_name)
+    # Test unpacking the type.
+    unpacked_message = any_test_pb2.TestAny()
+    self.assertTrue(msg.Unpack(unpacked_message))
+    self.assertEqual(submessage, unpacked_message)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
index f39035c..da120f3 100755
--- a/python/google/protobuf/internal/wire_format_test.py
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -34,12 +34,16 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-from google.apputils import basetest
+try:
+  import unittest2 as unittest  #PY26
+except ImportError:
+  import unittest
+
 from google.protobuf import message
 from google.protobuf.internal import wire_format
 
 
-class WireFormatTest(basetest.TestCase):
+class WireFormatTest(unittest.TestCase):
 
   def testPackTag(self):
     field_number = 0xabc
@@ -250,4 +254,4 @@
 
 
 if __name__ == '__main__':
-  basetest.main()
+  unittest.main()
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
new file mode 100644
index 0000000..7921556
--- /dev/null
+++ b/python/google/protobuf/json_format.py
@@ -0,0 +1,645 @@
+# 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.
+
+"""Contains routines for printing protocol messages in JSON format.
+
+Simple usage example:
+
+  # Create a proto object and serialize it to a json format string.
+  message = my_proto_pb2.MyMessage(foo='bar')
+  json_string = json_format.MessageToJson(message)
+
+  # Parse a json format string to proto object.
+  message = json_format.Parse(json_string, my_proto_pb2.MyMessage())
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import base64
+import json
+import math
+import six
+import sys
+
+from google.protobuf import descriptor
+from google.protobuf import symbol_database
+
+_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
+_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
+                        descriptor.FieldDescriptor.CPPTYPE_UINT32,
+                        descriptor.FieldDescriptor.CPPTYPE_INT64,
+                        descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64,
+                          descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
+                          descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
+_INFINITY = 'Infinity'
+_NEG_INFINITY = '-Infinity'
+_NAN = 'NaN'
+
+
+class Error(Exception):
+  """Top-level module error for json_format."""
+
+
+class SerializeToJsonError(Error):
+  """Thrown if serialization to JSON fails."""
+
+
+class ParseError(Error):
+  """Thrown in case of parsing error."""
+
+
+def MessageToJson(message, including_default_value_fields=False):
+  """Converts protobuf message to JSON format.
+
+  Args:
+    message: The protocol buffers message instance to serialize.
+    including_default_value_fields: If True, singular primitive fields,
+        repeated fields, and map fields will always be serialized.  If
+        False, only serialize non-empty fields.  Singular message fields
+        and oneof fields are not affected by this option.
+
+  Returns:
+    A string containing the JSON formatted protocol buffer message.
+  """
+  js = _MessageToJsonObject(message, including_default_value_fields)
+  return json.dumps(js, indent=2)
+
+
+def _MessageToJsonObject(message, including_default_value_fields):
+  """Converts message to an object according to Proto3 JSON Specification."""
+  message_descriptor = message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    return _WrapperMessageToJsonObject(message)
+  if full_name in _WKTJSONMETHODS:
+    return _WKTJSONMETHODS[full_name][0](
+        message, including_default_value_fields)
+  js = {}
+  return _RegularMessageToJsonObject(
+      message, js, including_default_value_fields)
+
+
+def _IsMapEntry(field):
+  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
+def _RegularMessageToJsonObject(message, js, including_default_value_fields):
+  """Converts normal message according to Proto3 JSON Specification."""
+  fields = message.ListFields()
+  include_default = including_default_value_fields
+
+  try:
+    for field, value in fields:
+      name = field.camelcase_name
+      if _IsMapEntry(field):
+        # Convert a map field.
+        v_field = field.message_type.fields_by_name['value']
+        js_map = {}
+        for key in value:
+          if isinstance(key, bool):
+            if key:
+              recorded_key = 'true'
+            else:
+              recorded_key = 'false'
+          else:
+            recorded_key = key
+          js_map[recorded_key] = _FieldToJsonObject(
+              v_field, value[key], including_default_value_fields)
+        js[name] = js_map
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        # Convert a repeated field.
+        js[name] = [_FieldToJsonObject(field, k, include_default)
+                    for k in value]
+      else:
+        js[name] = _FieldToJsonObject(field, value, include_default)
+
+    # Serialize default value if including_default_value_fields is True.
+    if including_default_value_fields:
+      message_descriptor = message.DESCRIPTOR
+      for field in message_descriptor.fields:
+        # Singular message fields and oneof fields will not be affected.
+        if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
+             field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
+            field.containing_oneof):
+          continue
+        name = field.camelcase_name
+        if name in js:
+          # Skip the field which has been serailized already.
+          continue
+        if _IsMapEntry(field):
+          js[name] = {}
+        elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          js[name] = []
+        else:
+          js[name] = _FieldToJsonObject(field, field.default_value)
+
+  except ValueError as e:
+    raise SerializeToJsonError(
+        'Failed to serialize {0} field: {1}.'.format(field.name, e))
+
+  return js
+
+
+def _FieldToJsonObject(
+    field, value, including_default_value_fields=False):
+  """Converts field value according to Proto3 JSON Specification."""
+  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+    return _MessageToJsonObject(value, including_default_value_fields)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+    enum_value = field.enum_type.values_by_number.get(value, None)
+    if enum_value is not None:
+      return enum_value.name
+    else:
+      raise SerializeToJsonError('Enum field contains an integer value '
+                                 'which can not mapped to an enum value.')
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      # Use base64 Data encoding for bytes
+      return base64.b64encode(value).decode('utf-8')
+    else:
+      return value
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+    return bool(value)
+  elif field.cpp_type in _INT64_TYPES:
+    return str(value)
+  elif field.cpp_type in _FLOAT_TYPES:
+    if math.isinf(value):
+      if value < 0.0:
+        return _NEG_INFINITY
+      else:
+        return _INFINITY
+    if math.isnan(value):
+      return _NAN
+  return value
+
+
+def _AnyMessageToJsonObject(message, including_default):
+  """Converts Any message according to Proto3 JSON Specification."""
+  if not message.ListFields():
+    return {}
+  js = {}
+  type_url = message.type_url
+  js['@type'] = type_url
+  sub_message = _CreateMessageFromTypeUrl(type_url)
+  sub_message.ParseFromString(message.value)
+  message_descriptor = sub_message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    js['value'] = _WrapperMessageToJsonObject(sub_message)
+    return js
+  if full_name in _WKTJSONMETHODS:
+    js['value'] = _WKTJSONMETHODS[full_name][0](sub_message, including_default)
+    return js
+  return _RegularMessageToJsonObject(sub_message, js, including_default)
+
+
+def _CreateMessageFromTypeUrl(type_url):
+  # TODO(jieluo): Should add a way that users can register the type resolver
+  # instead of the default one.
+  db = symbol_database.Default()
+  type_name = type_url.split('/')[-1]
+  try:
+    message_descriptor = db.pool.FindMessageTypeByName(type_name)
+  except KeyError:
+    raise TypeError(
+        'Can not find message descriptor by type_url: {0}.'.format(type_url))
+  message_class = db.GetPrototype(message_descriptor)
+  return message_class()
+
+
+def _GenericMessageToJsonObject(message, unused_including_default):
+  """Converts message by ToJsonString according to Proto3 JSON Specification."""
+  # Duration, Timestamp and FieldMask have ToJsonString method to do the
+  # convert. Users can also call the method directly.
+  return message.ToJsonString()
+
+
+def _ValueMessageToJsonObject(message, unused_including_default=False):
+  """Converts Value message according to Proto3 JSON Specification."""
+  which = message.WhichOneof('kind')
+  # If the Value message is not set treat as null_value when serialize
+  # to JSON. The parse back result will be different from original message.
+  if which is None or which == 'null_value':
+    return None
+  if which == 'list_value':
+    return _ListValueMessageToJsonObject(message.list_value)
+  if which == 'struct_value':
+    value = message.struct_value
+  else:
+    value = getattr(message, which)
+  oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
+  return _FieldToJsonObject(oneof_descriptor, value)
+
+
+def _ListValueMessageToJsonObject(message, unused_including_default=False):
+  """Converts ListValue message according to Proto3 JSON Specification."""
+  return [_ValueMessageToJsonObject(value)
+          for value in message.values]
+
+
+def _StructMessageToJsonObject(message, unused_including_default=False):
+  """Converts Struct message according to Proto3 JSON Specification."""
+  fields = message.fields
+  ret = {}
+  for key in fields:
+    ret[key] = _ValueMessageToJsonObject(fields[key])
+  return ret
+
+
+def _IsWrapperMessage(message_descriptor):
+  return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
+
+
+def _WrapperMessageToJsonObject(message):
+  return _FieldToJsonObject(
+      message.DESCRIPTOR.fields_by_name['value'], message.value)
+
+
+def _DuplicateChecker(js):
+  result = {}
+  for name, value in js:
+    if name in result:
+      raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name))
+    result[name] = value
+  return result
+
+
+def Parse(text, message):
+  """Parses a JSON representation of a protocol message into a message.
+
+  Args:
+    text: Message JSON representation.
+    message: A protocol beffer message to merge into.
+
+  Returns:
+    The same message passed as argument.
+
+  Raises::
+    ParseError: On JSON parsing problems.
+  """
+  if not isinstance(text, six.text_type): text = text.decode('utf-8')
+  try:
+    if sys.version_info < (2, 7):
+      # object_pair_hook is not supported before python2.7
+      js = json.loads(text)
+    else:
+      js = json.loads(text, object_pairs_hook=_DuplicateChecker)
+  except ValueError as e:
+    raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
+  _ConvertMessage(js, message)
+  return message
+
+
+def _ConvertFieldValuePair(js, message):
+  """Convert field value pairs into regular message.
+
+  Args:
+    js: A JSON object to convert the field value pairs.
+    message: A regular protocol message to record the data.
+
+  Raises:
+    ParseError: In case of problems converting.
+  """
+  names = []
+  message_descriptor = message.DESCRIPTOR
+  for name in js:
+    try:
+      field = message_descriptor.fields_by_camelcase_name.get(name, None)
+      if not field:
+        raise ParseError(
+            'Message type "{0}" has no field named "{1}".'.format(
+                message_descriptor.full_name, name))
+      if name in names:
+        raise ParseError(
+            'Message type "{0}" should not have multiple "{1}" fields.'.format(
+                message.DESCRIPTOR.full_name, name))
+      names.append(name)
+      # Check no other oneof field is parsed.
+      if field.containing_oneof is not None:
+        oneof_name = field.containing_oneof.name
+        if oneof_name in names:
+          raise ParseError('Message type "{0}" should not have multiple "{1}" '
+                           'oneof fields.'.format(
+                               message.DESCRIPTOR.full_name, oneof_name))
+        names.append(oneof_name)
+
+      value = js[name]
+      if value is None:
+        message.ClearField(field.name)
+        continue
+
+      # Parse field value.
+      if _IsMapEntry(field):
+        message.ClearField(field.name)
+        _ConvertMapFieldValue(value, message, field)
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        message.ClearField(field.name)
+        if not isinstance(value, list):
+          raise ParseError('repeated field {0} must be in [] which is '
+                           '{1}.'.format(name, value))
+        if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          # Repeated message field.
+          for item in value:
+            sub_message = getattr(message, field.name).add()
+            # None is a null_value in Value.
+            if (item is None and
+                sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
+              raise ParseError('null is not allowed to be used as an element'
+                               ' in a repeated field.')
+            _ConvertMessage(item, sub_message)
+        else:
+          # Repeated scalar field.
+          for item in value:
+            if item is None:
+              raise ParseError('null is not allowed to be used as an element'
+                               ' in a repeated field.')
+            getattr(message, field.name).append(
+                _ConvertScalarFieldValue(item, field))
+      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        sub_message = getattr(message, field.name)
+        _ConvertMessage(value, sub_message)
+      else:
+        setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+    except ParseError as e:
+      if field and field.containing_oneof is None:
+        raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+      else:
+        raise ParseError(str(e))
+    except ValueError as e:
+      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+    except TypeError as e:
+      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+
+
+def _ConvertMessage(value, message):
+  """Convert a JSON object into a message.
+
+  Args:
+    value: A JSON object.
+    message: A WKT or regular protocol message to record the data.
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  message_descriptor = message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    _ConvertWrapperMessage(value, message)
+  elif full_name in _WKTJSONMETHODS:
+    _WKTJSONMETHODS[full_name][1](value, message)
+  else:
+    _ConvertFieldValuePair(value, message)
+
+
+def _ConvertAnyMessage(value, message):
+  """Convert a JSON representation into Any message."""
+  if isinstance(value, dict) and not value:
+    return
+  try:
+    type_url = value['@type']
+  except KeyError:
+    raise ParseError('@type is missing when parsing any message.')
+
+  sub_message = _CreateMessageFromTypeUrl(type_url)
+  message_descriptor = sub_message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    _ConvertWrapperMessage(value['value'], sub_message)
+  elif full_name in _WKTJSONMETHODS:
+    _WKTJSONMETHODS[full_name][1](value['value'], sub_message)
+  else:
+    del value['@type']
+    _ConvertFieldValuePair(value, sub_message)
+  # Sets Any message
+  message.value = sub_message.SerializeToString()
+  message.type_url = type_url
+
+
+def _ConvertGenericMessage(value, message):
+  """Convert a JSON representation into message with FromJsonString."""
+  # Durantion, Timestamp, FieldMask have FromJsonString method to do the
+  # convert. Users can also call the method directly.
+  message.FromJsonString(value)
+
+
+_INT_OR_FLOAT = six.integer_types + (float,)
+
+
+def _ConvertValueMessage(value, message):
+  """Convert a JSON representation into Value message."""
+  if isinstance(value, dict):
+    _ConvertStructMessage(value, message.struct_value)
+  elif isinstance(value, list):
+    _ConvertListValueMessage(value, message.list_value)
+  elif value is None:
+    message.null_value = 0
+  elif isinstance(value, bool):
+    message.bool_value = value
+  elif isinstance(value, six.string_types):
+    message.string_value = value
+  elif isinstance(value, _INT_OR_FLOAT):
+    message.number_value = value
+  else:
+    raise ParseError('Unexpected type for Value message.')
+
+
+def _ConvertListValueMessage(value, message):
+  """Convert a JSON representation into ListValue message."""
+  if not isinstance(value, list):
+    raise ParseError(
+        'ListValue must be in [] which is {0}.'.format(value))
+  message.ClearField('values')
+  for item in value:
+    _ConvertValueMessage(item, message.values.add())
+
+
+def _ConvertStructMessage(value, message):
+  """Convert a JSON representation into Struct message."""
+  if not isinstance(value, dict):
+    raise ParseError(
+        'Struct must be in a dict which is {0}.'.format(value))
+  for key in value:
+    _ConvertValueMessage(value[key], message.fields[key])
+  return
+
+
+def _ConvertWrapperMessage(value, message):
+  """Convert a JSON representation into Wrapper message."""
+  field = message.DESCRIPTOR.fields_by_name['value']
+  setattr(message, 'value', _ConvertScalarFieldValue(value, field))
+
+
+def _ConvertMapFieldValue(value, message, field):
+  """Convert map field value for a message map field.
+
+  Args:
+    value: A JSON object to convert the map field value.
+    message: A protocol message to record the converted data.
+    field: The descriptor of the map field to be converted.
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  if not isinstance(value, dict):
+    raise ParseError(
+        'Map field {0} must be in a dict which is {1}.'.format(
+            field.name, value))
+  key_field = field.message_type.fields_by_name['key']
+  value_field = field.message_type.fields_by_name['value']
+  for key in value:
+    key_value = _ConvertScalarFieldValue(key, key_field, True)
+    if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      _ConvertMessage(value[key], getattr(message, field.name)[key_value])
+    else:
+      getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+          value[key], value_field)
+
+
+def _ConvertScalarFieldValue(value, field, require_str=False):
+  """Convert a single scalar field value.
+
+  Args:
+    value: A scalar value to convert the scalar field value.
+    field: The descriptor of the field to convert.
+    require_str: If True, the field value must be a str.
+
+  Returns:
+    The converted scalar field value
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  if field.cpp_type in _INT_TYPES:
+    return _ConvertInteger(value)
+  elif field.cpp_type in _FLOAT_TYPES:
+    return _ConvertFloat(value)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+    return _ConvertBool(value, require_str)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      return base64.b64decode(value)
+    else:
+      return value
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+    # Convert an enum value.
+    enum_value = field.enum_type.values_by_name.get(value, None)
+    if enum_value is None:
+      raise ParseError(
+          'Enum value must be a string literal with double quotes. '
+          'Type "{0}" has no value named {1}.'.format(
+              field.enum_type.full_name, value))
+    return enum_value.number
+
+
+def _ConvertInteger(value):
+  """Convert an integer.
+
+  Args:
+    value: A scalar value to convert.
+
+  Returns:
+    The integer value.
+
+  Raises:
+    ParseError: If an integer couldn't be consumed.
+  """
+  if isinstance(value, float):
+    raise ParseError('Couldn\'t parse integer: {0}.'.format(value))
+
+  if isinstance(value, six.text_type) and value.find(' ') != -1:
+    raise ParseError('Couldn\'t parse integer: "{0}".'.format(value))
+
+  return int(value)
+
+
+def _ConvertFloat(value):
+  """Convert an floating point number."""
+  if value == 'nan':
+    raise ParseError('Couldn\'t parse float "nan", use "NaN" instead.')
+  try:
+    # Assume Python compatible syntax.
+    return float(value)
+  except ValueError:
+    # Check alternative spellings.
+    if value == _NEG_INFINITY:
+      return float('-inf')
+    elif value == _INFINITY:
+      return float('inf')
+    elif value == _NAN:
+      return float('nan')
+    else:
+      raise ParseError('Couldn\'t parse float: {0}.'.format(value))
+
+
+def _ConvertBool(value, require_str):
+  """Convert a boolean value.
+
+  Args:
+    value: A scalar value to convert.
+    require_str: If True, value must be a str.
+
+  Returns:
+    The bool parsed.
+
+  Raises:
+    ParseError: If a boolean value couldn't be consumed.
+  """
+  if require_str:
+    if value == 'true':
+      return True
+    elif value == 'false':
+      return False
+    else:
+      raise ParseError('Expected "true" or "false", not {0}.'.format(value))
+
+  if not isinstance(value, bool):
+    raise ParseError('Expected true or false without quotes.')
+  return value
+
+_WKTJSONMETHODS = {
+    'google.protobuf.Any': [_AnyMessageToJsonObject,
+                            _ConvertAnyMessage],
+    'google.protobuf.Duration': [_GenericMessageToJsonObject,
+                                 _ConvertGenericMessage],
+    'google.protobuf.FieldMask': [_GenericMessageToJsonObject,
+                                  _ConvertGenericMessage],
+    'google.protobuf.ListValue': [_ListValueMessageToJsonObject,
+                                  _ConvertListValueMessage],
+    'google.protobuf.Struct': [_StructMessageToJsonObject,
+                               _ConvertStructMessage],
+    'google.protobuf.Timestamp': [_GenericMessageToJsonObject,
+                                  _ConvertGenericMessage],
+    'google.protobuf.Value': [_ValueMessageToJsonObject,
+                              _ConvertValueMessage]
+}
diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py
index c186452..606f735 100755
--- a/python/google/protobuf/message.py
+++ b/python/google/protobuf/message.py
@@ -36,7 +36,6 @@
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
-
 class Error(Exception): pass
 class DecodeError(Error): pass
 class EncodeError(Error): pass
@@ -233,12 +232,21 @@
     raise NotImplementedError
 
   def HasField(self, field_name):
-    """Checks if a certain field is set for the message. Note if the
-    field_name is not defined in the message descriptor, ValueError will be
-    raised."""
+    """Checks if a certain field is set for the message, or if any field inside
+    a oneof group is set.  Note that if the field_name is not defined in the
+    message descriptor, ValueError will be raised."""
     raise NotImplementedError
 
   def ClearField(self, field_name):
+    """Clears the contents of a given field, or the field set inside a oneof
+    group.  If the name neither refers to a defined field or oneof group,
+    ValueError is raised."""
+    raise NotImplementedError
+
+  def WhichOneof(self, oneof_group):
+    """Returns the name of the field that is set inside a oneof group, or
+    None if no field is set.  If no group with the given name exists, ValueError
+    will be raised."""
     raise NotImplementedError
 
   def HasExtension(self, extension_handle):
@@ -247,6 +255,9 @@
   def ClearExtension(self, extension_handle):
     raise NotImplementedError
 
+  def DiscardUnknownFields(self):
+    raise NotImplementedError
+
   def ByteSize(self):
     """Returns the serialized size of this message.
     Recursively calls ByteSize() on all contained messages.
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
index 7fd7bec..1b059d1 100644
--- a/python/google/protobuf/message_factory.py
+++ b/python/google/protobuf/message_factory.py
@@ -28,10 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
-# Copyright 2012 Google Inc. All Rights Reserved.
-
 """Provides a factory class for generating dynamic messages.
 
 The easiest way to use this class is if you have access to the FileDescriptor
@@ -43,8 +39,6 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-import sys  ##PY25
-from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
 from google.protobuf import message
 from google.protobuf import reflection
@@ -55,8 +49,7 @@
 
   def __init__(self, pool=None):
     """Initializes a new factory."""
-    self.pool = (pool or descriptor_pool.DescriptorPool(
-        descriptor_database.DescriptorDatabase()))
+    self.pool = pool or descriptor_pool.DescriptorPool()
 
     # local cache of all classes built from protobuf descriptors
     self._classes = {}
@@ -75,8 +68,7 @@
     """
     if descriptor.full_name not in self._classes:
       descriptor_name = descriptor.name
-      if sys.version_info[0] < 3:  ##PY25
-##!PY25      if str is bytes:  # PY2
+      if str is bytes:  # PY2
         descriptor_name = descriptor.name.encode('ascii', 'ignore')
       result_class = reflection.GeneratedProtocolMessageType(
           descriptor_name,
@@ -111,7 +103,7 @@
     result = {}
     for file_name in files:
       file_desc = self.pool.FindFileByName(file_name)
-      for name, msg in file_desc.message_types_by_name.iteritems():
+      for name, msg in file_desc.message_types_by_name.items():
         if file_desc.package:
           full_name = '.'.join([file_desc.package, name])
         else:
@@ -128,7 +120,7 @@
       # ignore the registration if the original was the same, or raise
       # an error if they were different.
 
-      for name, extension in file_desc.extensions_by_name.iteritems():
+      for name, extension in file_desc.extensions_by_name.items():
         if extension.containing_type.full_name not in self._classes:
           self.GetPrototype(extension.containing_type)
         extended_class = self._classes[extension.containing_type.full_name]
diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py
new file mode 100644
index 0000000..736caed
--- /dev/null
+++ b/python/google/protobuf/proto_builder.py
@@ -0,0 +1,130 @@
+# 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.
+
+"""Dynamic Protobuf class creator."""
+
+try:
+    from collections import OrderedDict
+except ImportError:
+    from ordereddict import OrderedDict  #PY26
+import hashlib
+import os
+
+from google.protobuf import descriptor_pb2
+from google.protobuf import message_factory
+
+
+def _GetMessageFromFactory(factory, full_name):
+  """Get a proto class from the MessageFactory by name.
+
+  Args:
+    factory: a MessageFactory instance.
+    full_name: str, the fully qualified name of the proto type.
+  Returns:
+    A class, for the type identified by full_name.
+  Raises:
+    KeyError, if the proto is not found in the factory's descriptor pool.
+  """
+  proto_descriptor = factory.pool.FindMessageTypeByName(full_name)
+  proto_cls = factory.GetPrototype(proto_descriptor)
+  return proto_cls
+
+
+def MakeSimpleProtoClass(fields, full_name=None, pool=None):
+  """Create a Protobuf class whose fields are basic types.
+
+  Note: this doesn't validate field names!
+
+  Args:
+    fields: dict of {name: field_type} mappings for each field in the proto. If
+        this is an OrderedDict the order will be maintained, otherwise the
+        fields will be sorted by name.
+    full_name: optional str, the fully-qualified name of the proto type.
+    pool: optional DescriptorPool instance.
+  Returns:
+    a class, the new protobuf class with a FileDescriptor.
+  """
+  factory = message_factory.MessageFactory(pool=pool)
+
+  if full_name is not None:
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
+
+  # Get a list of (name, field_type) tuples from the fields dict. If fields was
+  # an OrderedDict we keep the order, but otherwise we sort the field to ensure
+  # consistent ordering.
+  field_items = fields.items()
+  if not isinstance(fields, OrderedDict):
+    field_items = sorted(field_items)
+
+  # Use a consistent file name that is unlikely to conflict with any imported
+  # proto files.
+  fields_hash = hashlib.sha1()
+  for f_name, f_type in field_items:
+    fields_hash.update(f_name.encode('utf-8'))
+    fields_hash.update(str(f_type).encode('utf-8'))
+  proto_file_name = fields_hash.hexdigest() + '.proto'
+
+  # If the proto is anonymous, use the same hash to name it.
+  if full_name is None:
+    full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' +
+                 fields_hash.hexdigest())
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
+
+  # This is the first time we see this proto: add a new descriptor to the pool.
+  factory.pool.Add(
+      _MakeFileDescriptorProto(proto_file_name, full_name, field_items))
+  return _GetMessageFromFactory(factory, full_name)
+
+
+def _MakeFileDescriptorProto(proto_file_name, full_name, field_items):
+  """Populate FileDescriptorProto for MessageFactory's DescriptorPool."""
+  package, name = full_name.rsplit('.', 1)
+  file_proto = descriptor_pb2.FileDescriptorProto()
+  file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name)
+  file_proto.package = package
+  desc_proto = file_proto.message_type.add()
+  desc_proto.name = name
+  for f_number, (f_name, f_type) in enumerate(field_items, 1):
+    field_proto = desc_proto.field.add()
+    field_proto.name = f_name
+    field_proto.number = f_number
+    field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
+    field_proto.type = f_type
+  return file_proto
diff --git a/python/google/protobuf/pyext/__init__.py b/python/google/protobuf/pyext/__init__.py
index e69de29..5585614 100644
--- a/python/google/protobuf/pyext/__init__.py
+++ b/python/google/protobuf/pyext/__init__.py
@@ -0,0 +1,4 @@
+try:
+  __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+  __path__ = __import__('pkgutil').extend_path(__path__, __name__)
diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py
index dcf34a0..b215211 100644
--- a/python/google/protobuf/pyext/cpp_message.py
+++ b/python/google/protobuf/pyext/cpp_message.py
@@ -37,25 +37,29 @@
 __author__ = 'tibell@google.com (Johan Tibell)'
 
 from google.protobuf.pyext import _message
-from google.protobuf import message
 
 
-def NewMessage(bases, message_descriptor, dictionary):
-  """Creates a new protocol message *class*."""
-  new_bases = []
-  for base in bases:
-    if base is message.Message:
-      # _message.Message must come before message.Message as it
-      # overrides methods in that class.
-      new_bases.append(_message.Message)
-    new_bases.append(base)
-  return tuple(new_bases)
+class GeneratedProtocolMessageType(_message.MessageMeta):
 
+  """Metaclass for protocol message classes created at runtime from Descriptors.
 
-def InitMessage(message_descriptor, cls):
-  """Constructs a new message instance (called before instance's __init__)."""
+  The protocol compiler currently uses this metaclass to create protocol
+  message classes at runtime.  Clients can also manually create their own
+  classes at runtime, as in this example:
 
-  def SubInit(self, **kwargs):
-    super(cls, self).__init__(message_descriptor, **kwargs)
-  cls.__init__ = SubInit
-  cls.AddDescriptors(message_descriptor)
+  mydescriptor = Descriptor(.....)
+  class MyProtoClass(Message):
+    __metaclass__ = GeneratedProtocolMessageType
+    DESCRIPTOR = mydescriptor
+  myproto_instance = MyProtoClass()
+  myproto.foo_field = 23
+  ...
+
+  The above example will not work for nested types. If you wish to include them,
+  use reflection.MakeClass() instead of manually instantiating the class in
+  order to create the appropriate class structure.
+  """
+
+  # Must be consistent with the protocol-compiler code in
+  # proto2/compiler/internal/generator.*.
+  _DESCRIPTOR_KEY = 'DESCRIPTOR'
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 3f7be73..2355753 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -31,29 +31,119 @@
 // Author: petar@google.com (Petar Petrov)
 
 #include <Python.h>
+#include <frameobject.h>
 #include <string>
 
+#include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define C(str) const_cast<char*>(str)
-
 #if PY_MAJOR_VERSION >= 3
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+  #define PyString_Check PyUnicode_Check
+  #define PyString_InternFromString PyUnicode_InternFromString
   #define PyInt_FromLong PyLong_FromLong
+  #define PyInt_FromSize_t PyLong_FromSize_t
   #if PY_VERSION_HEX < 0x03030000
     #error "Python 3.0 - 3.2 are not supported."
-  #else
-  #define PyString_AsString(ob) \
-    (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob))
   #endif
+  #define PyString_AsStringAndSize(ob, charpp, sizep) \
+    (PyUnicode_Check(ob)? \
+       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 #endif
 
 namespace google {
 namespace protobuf {
 namespace python {
 
+// Store interned descriptors, so that the same C++ descriptor yields the same
+// Python object. Objects are not immortal: this map does not own the
+// references, and items are deleted when the last reference to the object is
+// released.
+// This is enough to support the "is" operator on live objects.
+// All descriptors are stored here.
+hash_map<const void*, PyObject*> interned_descriptors;
+
+PyObject* PyString_FromCppString(const string& str) {
+  return PyString_FromStringAndSize(str.c_str(), str.size());
+}
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which creates descriptors, then update some properties.
+// For example:
+//   message_descriptor = Descriptor(
+//       name='Message',
+//       fields = [FieldDescriptor(name='field')]
+//   message_descriptor.fields[0].containing_type = message_descriptor
+//
+// This code is still executed, but the descriptors now have no other storage
+// than the (const) C++ pointer, and are immutable.
+// So we let this code pass, by simply ignoring the new value.
+//
+// From user code, descriptors still look immutable.
+//
+// TODO(amauryfa): Change the proto2 compiler to remove the assignments, and
+// remove this hack.
+bool _CalledFromGeneratedFile(int stacklevel) {
+#ifndef PYPY_VERSION
+  // This check is not critical and is somewhat difficult to implement correctly
+  // in PyPy.
+  PyFrameObject* frame = PyEval_GetFrame();
+  if (frame == NULL) {
+    return false;
+  }
+  while (stacklevel-- > 0) {
+    frame = frame->f_back;
+    if (frame == NULL) {
+      return false;
+    }
+  }
+  if (frame->f_globals != frame->f_locals) {
+    // Not at global module scope
+    return false;
+  }
+
+  if (frame->f_code->co_filename == NULL) {
+    return false;
+  }
+  char* filename;
+  Py_ssize_t filename_size;
+  if (PyString_AsStringAndSize(frame->f_code->co_filename,
+                               &filename, &filename_size) < 0) {
+    // filename is not a string.
+    PyErr_Clear();
+    return false;
+  }
+  if (filename_size < 7) {
+    // filename is too short.
+    return false;
+  }
+  if (strcmp(&filename[filename_size - 7], "_pb2.py") != 0) {
+    // Filename is not ending with _pb2.
+    return false;
+  }
+#endif
+  return true;
+}
+
+// If the calling code is not a _pb2.py file, raise AttributeError.
+// To be used in attribute setters.
+static int CheckCalledFromGeneratedFile(const char* attr_name) {
+  if (_CalledFromGeneratedFile(0)) {
+    return 0;
+  }
+  PyErr_Format(PyExc_AttributeError,
+               "attribute is not writable: %s", attr_name);
+  return -1;
+}
+
 
 #ifndef PyVarObject_HEAD_INIT
 #define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -63,58 +153,225 @@
 #endif
 
 
-static google::protobuf::DescriptorPool* g_descriptor_pool = NULL;
+// Helper functions for descriptor objects.
 
-namespace cfield_descriptor {
+// A set of templates to retrieve the C++ FileDescriptor of any descriptor.
+template<class DescriptorClass>
+const FileDescriptor* GetFileDescriptor(const DescriptorClass* descriptor) {
+  return descriptor->file();
+}
+template<>
+const FileDescriptor* GetFileDescriptor(const FileDescriptor* descriptor) {
+  return descriptor;
+}
+template<>
+const FileDescriptor* GetFileDescriptor(const EnumValueDescriptor* descriptor) {
+  return descriptor->type()->file();
+}
+template<>
+const FileDescriptor* GetFileDescriptor(const OneofDescriptor* descriptor) {
+  return descriptor->containing_type()->file();
+}
 
-static void Dealloc(CFieldDescriptor* self) {
-  Py_CLEAR(self->descriptor_field);
+// Converts options into a Python protobuf, and cache the result.
+//
+// This is a bit tricky because options can contain extension fields defined in
+// the same proto file. In this case the options parsed from the serialized_pb
+// have unkown fields, and we need to parse them again.
+//
+// Always returns a new reference.
+template<class DescriptorClass>
+static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
+  // Options (and their extensions) are completely resolved in the proto file
+  // containing the descriptor.
+  PyDescriptorPool* pool = GetDescriptorPool_FromPool(
+      GetFileDescriptor(descriptor)->pool());
+
+  hash_map<const void*, PyObject*>* descriptor_options =
+      pool->descriptor_options;
+  // First search in the cache.
+  if (descriptor_options->find(descriptor) != descriptor_options->end()) {
+    PyObject *value = (*descriptor_options)[descriptor];
+    Py_INCREF(value);
+    return value;
+  }
+
+  // Build the Options object: get its Python class, and make a copy of the C++
+  // read-only instance.
+  const Message& options(descriptor->options());
+  const Descriptor *message_type = options.GetDescriptor();
+  CMessageClass* message_class(
+      cdescriptor_pool::GetMessageClass(pool, message_type));
+  if (message_class == NULL) {
+    // The Options message was not found in the current DescriptorPool.
+    // In this case, there cannot be extensions to these options, and we can
+    // try to use the basic pool instead.
+    PyErr_Clear();
+    message_class = cdescriptor_pool::GetMessageClass(
+      GetDefaultDescriptorPool(), message_type);
+  }
+  if (message_class == NULL) {
+    PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
+                 message_type->full_name().c_str());
+    return NULL;
+  }
+  ScopedPyObjectPtr value(
+      PyEval_CallObject(message_class->AsPyObject(), NULL));
+  if (value == NULL) {
+    return NULL;
+  }
+  if (!PyObject_TypeCheck(value.get(), &CMessage_Type)) {
+      PyErr_Format(PyExc_TypeError, "Invalid class for %s: %s",
+                   message_type->full_name().c_str(),
+                   Py_TYPE(value.get())->tp_name);
+      return NULL;
+  }
+  CMessage* cmsg = reinterpret_cast<CMessage*>(value.get());
+
+  const Reflection* reflection = options.GetReflection();
+  const UnknownFieldSet& unknown_fields(reflection->GetUnknownFields(options));
+  if (unknown_fields.empty()) {
+    cmsg->message->CopyFrom(options);
+  } else {
+    // Reparse options string!  XXX call cmessage::MergeFromString
+    string serialized;
+    options.SerializeToString(&serialized);
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
+    input.SetExtensionRegistry(pool->pool, pool->message_factory);
+    bool success = cmsg->message->MergePartialFromCodedStream(&input);
+    if (!success) {
+      PyErr_Format(PyExc_ValueError, "Error parsing Options message");
+      return NULL;
+    }
+  }
+
+  // Cache the result.
+  Py_INCREF(value.get());
+  (*pool->descriptor_options)[descriptor] = value.get();
+
+  return value.release();
+}
+
+// Copy the C++ descriptor to a Python message.
+// The Python message is an instance of descriptor_pb2.DescriptorProto
+// or similar.
+template<class DescriptorProtoClass, class DescriptorClass>
+static PyObject* CopyToPythonProto(const DescriptorClass *descriptor,
+                                   PyObject *target) {
+  const Descriptor* self_descriptor =
+      DescriptorProtoClass::default_instance().GetDescriptor();
+  CMessage* message = reinterpret_cast<CMessage*>(target);
+  if (!PyObject_TypeCheck(target, &CMessage_Type) ||
+      message->message->GetDescriptor() != self_descriptor) {
+    PyErr_Format(PyExc_TypeError, "Not a %s message",
+                 self_descriptor->full_name().c_str());
+    return NULL;
+  }
+  cmessage::AssureWritable(message);
+  DescriptorProtoClass* descriptor_message =
+      static_cast<DescriptorProtoClass*>(message->message);
+  descriptor->CopyTo(descriptor_message);
+  Py_RETURN_NONE;
+}
+
+// All Descriptors classes share the same memory layout.
+typedef struct PyBaseDescriptor {
+  PyObject_HEAD
+
+  // Pointer to the C++ proto2 descriptor.
+  // Like all descriptors, it is owned by the global DescriptorPool.
+  const void* descriptor;
+
+  // Owned reference to the DescriptorPool, to ensure it is kept alive.
+  PyDescriptorPool* pool;
+} PyBaseDescriptor;
+
+
+// FileDescriptor structure "inherits" from the base descriptor.
+typedef struct PyFileDescriptor {
+  PyBaseDescriptor base;
+
+  // The cached version of serialized pb. Either NULL, or a Bytes string.
+  // We own the reference.
+  PyObject *serialized_pb;
+} PyFileDescriptor;
+
+
+namespace descriptor {
+
+// Creates or retrieve a Python descriptor of the specified type.
+// Objects are interned: the same descriptor will return the same object if it
+// was kept alive.
+// 'was_created' is an optional pointer to a bool, and is set to true if a new
+// object was allocated.
+// Always return a new reference.
+template<class DescriptorClass>
+PyObject* NewInternedDescriptor(PyTypeObject* type,
+                                const DescriptorClass* descriptor,
+                                bool* was_created) {
+  if (was_created) {
+    *was_created = false;
+  }
+  if (descriptor == NULL) {
+    PyErr_BadInternalCall();
+    return NULL;
+  }
+
+  // See if the object is in the map of interned descriptors
+  hash_map<const void*, PyObject*>::iterator it =
+      interned_descriptors.find(descriptor);
+  if (it != interned_descriptors.end()) {
+    GOOGLE_DCHECK(Py_TYPE(it->second) == type);
+    Py_INCREF(it->second);
+    return it->second;
+  }
+  // Create a new descriptor object
+  PyBaseDescriptor* py_descriptor = PyObject_New(
+      PyBaseDescriptor, type);
+  if (py_descriptor == NULL) {
+    return NULL;
+  }
+  py_descriptor->descriptor = descriptor;
+
+  // and cache it.
+  interned_descriptors.insert(
+      std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
+
+  // Ensures that the DescriptorPool stays alive.
+  PyDescriptorPool* pool = GetDescriptorPool_FromPool(
+      GetFileDescriptor(descriptor)->pool());
+  if (pool == NULL) {
+    // Don't DECREF, the object is not fully initialized.
+    PyObject_Del(py_descriptor);
+    return NULL;
+  }
+  Py_INCREF(pool);
+  py_descriptor->pool = pool;
+
+  if (was_created) {
+    *was_created = true;
+  }
+  return reinterpret_cast<PyObject*>(py_descriptor);
+}
+
+static void Dealloc(PyBaseDescriptor* self) {
+  // Remove from interned dictionary
+  interned_descriptors.erase(self->descriptor);
+  Py_CLEAR(self->pool);
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
-static PyObject* GetFullName(CFieldDescriptor* self, void *closure) {
-  return PyString_FromStringAndSize(
-      self->descriptor->full_name().c_str(),
-      self->descriptor->full_name().size());
-}
-
-static PyObject* GetName(CFieldDescriptor *self, void *closure) {
-  return PyString_FromStringAndSize(
-      self->descriptor->name().c_str(),
-      self->descriptor->name().size());
-}
-
-static PyObject* GetCppType(CFieldDescriptor *self, void *closure) {
-  return PyInt_FromLong(self->descriptor->cpp_type());
-}
-
-static PyObject* GetLabel(CFieldDescriptor *self, void *closure) {
-  return PyInt_FromLong(self->descriptor->label());
-}
-
-static PyObject* GetID(CFieldDescriptor *self, void *closure) {
-  return PyLong_FromVoidPtr(self);
-}
-
 static PyGetSetDef Getters[] = {
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("name"), (getter)GetName, NULL, "last name", NULL},
-  { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL},
-  { C("label"), (getter)GetLabel, NULL, "Label", NULL},
-  { C("id"), (getter)GetID, NULL, "ID", NULL},
   {NULL}
 };
 
-}  // namespace cfield_descriptor
-
-PyTypeObject CFieldDescriptor_Type = {
+PyTypeObject PyBaseDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_net_proto2___python."
-    "CFieldDescriptor"),                // tp_name
-  sizeof(CFieldDescriptor),             // tp_basicsize
+  FULL_MODULE_NAME ".DescriptorBase",   // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
-  (destructor)cfield_descriptor::Dealloc,  // tp_dealloc
+  (destructor)Dealloc,                  // tp_dealloc
   0,                                    // tp_print
   0,                                    // tp_getattr
   0,                                    // tp_setattr
@@ -130,7 +387,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Field Descriptor"),              // tp_doc
+  "Descriptors base class",             // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -139,214 +396,1184 @@
   0,                                    // tp_iternext
   0,                                    // tp_methods
   0,                                    // tp_members
-  cfield_descriptor::Getters,           // tp_getset
-  0,                                    // tp_base
+  Getters,                              // tp_getset
+};
+
+}  // namespace descriptor
+
+const void* PyDescriptor_AsVoidPtr(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &descriptor::PyBaseDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a BaseDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor;
+}
+
+namespace message_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const Descriptor* _GetDescriptor(PyBaseDescriptor* self) {
+  return reinterpret_cast<const Descriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
+  // Retuns the canonical class for the given descriptor.
+  // This is the class that was registered with the primary descriptor pool
+  // which contains this descriptor.
+  // This might not be the one you expect! For example the returned object does
+  // not know about extensions defined in a custom pool.
+  CMessageClass* concrete_class(cdescriptor_pool::GetMessageClass(
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()),
+      _GetDescriptor(self)));
+  Py_XINCREF(concrete_class);
+  return concrete_class->AsPyObject();
+}
+
+static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self,
+                                          void *closure) {
+  return NewMessageFieldsByCamelcaseName(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetFieldsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageNestedTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetNestedTypesSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageNestedTypesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensions(PyBaseDescriptor* self, void *closure) {
+  return NewMessageExtensionsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumValuesByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsByName(PyBaseDescriptor* self, void *closure) {
+  return NewMessageOneofsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetOneofsSeq(PyBaseDescriptor* self, void *closure) {
+  return NewMessageOneofsSeq(_GetDescriptor(self));
+}
+
+static PyObject* IsExtendable(PyBaseDescriptor *self, void *closure) {
+  if (_GetDescriptor(self)->extension_range_count() > 0) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PyObject* GetExtensionRanges(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* descriptor = _GetDescriptor(self);
+  PyObject* range_list = PyList_New(descriptor->extension_range_count());
+
+  for (int i = 0; i < descriptor->extension_range_count(); i++) {
+    const Descriptor::ExtensionRange* range = descriptor->extension_range(i);
+    PyObject* start = PyInt_FromLong(range->start);
+    PyObject* end = PyInt_FromLong(range->end);
+    PyList_SetItem(range_list, i, PyTuple_Pack(2, start, end));
+  }
+
+  return range_list;
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const MessageOptions& options(_GetDescriptor(self)->options());
+  if (&options != &MessageOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<DescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) {
+  const char *enum_name;
+  int number;
+  if (!PyArg_ParseTuple(args, "si", &enum_name, &number))
+    return NULL;
+  const EnumDescriptor *enum_type =
+      _GetDescriptor(self)->FindEnumTypeByName(enum_name);
+  if (enum_type == NULL) {
+    PyErr_SetString(PyExc_KeyError, enum_name);
+    return NULL;
+  }
+  const EnumValueDescriptor *enum_value =
+      enum_type->FindValueByNumber(number);
+  if (enum_value == NULL) {
+    PyErr_Format(PyExc_KeyError, "%d", number);
+    return NULL;
+  }
+  return PyString_FromCppString(enum_value->name());
+}
+
+static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) {
+  return PyString_InternFromString(
+      FileDescriptor::SyntaxName(_GetDescriptor(self)->file()->syntax()));
+}
+
+static PyGetSetDef Getters[] = {
+  { "name", (getter)GetName, NULL, "Last name"},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "_concrete_class", (getter)GetConcreteClass, NULL, "concrete class"},
+  { "file", (getter)GetFile, NULL, "File descriptor"},
+
+  { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"},
+  { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"},
+  { "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL,
+    "Fields by camelCase name"},
+  { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"},
+  { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"},
+  { "nested_types_by_name", (getter)GetNestedTypesByName, NULL,
+    "Nested types by name"},
+  { "extensions", (getter)GetExtensions, NULL, "Extensions Sequence"},
+  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
+    "Extensions by name"},
+  { "extension_ranges", (getter)GetExtensionRanges, NULL, "Extension ranges"},
+  { "enum_types", (getter)GetEnumsSeq, NULL, "Enum sequence"},
+  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL,
+    "Enum types by name"},
+  { "enum_values_by_name", (getter)GetEnumValuesByName, NULL,
+    "Enum values by name"},
+  { "oneofs_by_name", (getter)GetOneofsByName, NULL, "Oneofs by name"},
+  { "oneofs", (getter)GetOneofsSeq, NULL, "Oneofs by name"},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "is_extendable", (getter)IsExtendable, (setter)NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+  { "EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS, },
+  {NULL}
+};
+
+}  // namespace message_descriptor
+
+PyTypeObject PyMessageDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MessageDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A Message Descriptor",               // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  message_descriptor::Methods,          // tp_methods
+  0,                                    // tp_members
+  message_descriptor::Getters,          // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyMessageDescriptor_FromDescriptor(
+    const Descriptor* message_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyMessageDescriptor_Type, message_descriptor, NULL);
+}
+
+const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyMessageDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a MessageDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const Descriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace field_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FieldDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const FieldDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->camelcase_name());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetCppType(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->cpp_type());
+}
+
+static PyObject* GetLabel(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->label());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetID(PyBaseDescriptor *self, void *closure) {
+  return PyLong_FromVoidPtr(self);
+}
+
+static PyObject* IsExtension(PyBaseDescriptor *self, void *closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->is_extension());
+}
+
+static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->has_default_value());
+}
+
+static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
+  PyObject *result;
+
+  switch (_GetDescriptor(self)->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      int32 value = _GetDescriptor(self)->default_value_int32();
+      result = PyInt_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      int64 value = _GetDescriptor(self)->default_value_int64();
+      result = PyLong_FromLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      uint32 value = _GetDescriptor(self)->default_value_uint32();
+      result = PyInt_FromSize_t(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      uint64 value = _GetDescriptor(self)->default_value_uint64();
+      result = PyLong_FromUnsignedLongLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      float value = _GetDescriptor(self)->default_value_float();
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      double value = _GetDescriptor(self)->default_value_double();
+      result = PyFloat_FromDouble(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      bool value = _GetDescriptor(self)->default_value_bool();
+      result = PyBool_FromLong(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      string value = _GetDescriptor(self)->default_value_string();
+      result = ToStringObject(_GetDescriptor(self), value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      const EnumValueDescriptor* value =
+          _GetDescriptor(self)->default_value_enum();
+      result = PyInt_FromLong(value->number());
+      break;
+    }
+    default:
+      PyErr_Format(PyExc_NotImplementedError, "default value for %s",
+                   _GetDescriptor(self)->full_name().c_str());
+      return NULL;
+  }
+  return result;
+}
+
+static PyObject* GetCDescriptor(PyObject *self, void *closure) {
+  Py_INCREF(self);
+  return self;
+}
+
+static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) {
+  const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type();
+  if (enum_type) {
+    return PyEnumDescriptor_FromDescriptor(enum_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetEnumType(PyBaseDescriptor *self, PyObject *value, void *closure) {
+  return CheckCalledFromGeneratedFile("enum_type");
+}
+
+static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* message_type = _GetDescriptor(self)->message_type();
+  if (message_type) {
+    return PyMessageDescriptor_FromDescriptor(message_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetMessageType(PyBaseDescriptor *self, PyObject *value,
+                          void *closure) {
+  return CheckCalledFromGeneratedFile("message_type");
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+static PyObject* GetExtensionScope(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* extension_scope =
+      _GetDescriptor(self)->extension_scope();
+  if (extension_scope) {
+    return PyMessageDescriptor_FromDescriptor(extension_scope);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static PyObject* GetContainingOneof(PyBaseDescriptor *self, void *closure) {
+  const OneofDescriptor* containing_oneof =
+      _GetDescriptor(self)->containing_oneof();
+  if (containing_oneof) {
+    return PyOneofDescriptor_FromDescriptor(containing_oneof);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingOneof(PyBaseDescriptor *self, PyObject *value,
+                              void *closure) {
+  return CheckCalledFromGeneratedFile("containing_oneof");
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const FieldOptions& options(_GetDescriptor(self)->options());
+  if (&options != &FieldOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+
+static PyGetSetDef Getters[] = {
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "name", (getter)GetName, NULL, "Unqualified name"},
+  { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
+  { "type", (getter)GetType, NULL, "C++ Type"},
+  { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
+  { "label", (getter)GetLabel, NULL, "Label"},
+  { "number", (getter)GetNumber, NULL, "Number"},
+  { "index", (getter)GetIndex, NULL, "Index"},
+  { "default_value", (getter)GetDefaultValue, NULL, "Default Value"},
+  { "has_default_value", (getter)HasDefaultValue},
+  { "is_extension", (getter)IsExtension, NULL, "ID"},
+  { "id", (getter)GetID, NULL, "ID"},
+  { "_cdescriptor", (getter)GetCDescriptor, NULL, "HAACK REMOVE ME"},
+
+  { "message_type", (getter)GetMessageType, (setter)SetMessageType,
+    "Message type"},
+  { "enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "extension_scope", (getter)GetExtensionScope, (setter)NULL,
+    "Extension scope"},
+  { "containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof,
+    "Containing oneof"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  {NULL}
+};
+
+}  // namespace field_descriptor
+
+PyTypeObject PyFieldDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".FieldDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A Field Descriptor",                 // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  field_descriptor::Methods,            // tp_methods
+  0,                                    // tp_members
+  field_descriptor::Getters,            // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyFieldDescriptor_FromDescriptor(
+    const FieldDescriptor* field_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyFieldDescriptor_Type, field_descriptor, NULL);
+}
+
+const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyFieldDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a FieldDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const FieldDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace enum_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const EnumDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
+}
+
+static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesByNumber(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesByNumber(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumvaluesSeq(PyBaseDescriptor* self, void *closure) {
+  return NewEnumValuesSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static int SetContainingType(PyBaseDescriptor *self, PyObject *value,
+                             void *closure) {
+  return CheckCalledFromGeneratedFile("containing_type");
+}
+
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const EnumOptions& options(_GetDescriptor(self)->options());
+  if (&options != &EnumOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<EnumDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+  {NULL}
+};
+
+static PyGetSetDef Getters[] = {
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "name", (getter)GetName, NULL, "last name"},
+  { "file", (getter)GetFile, NULL, "File descriptor"},
+  { "values", (getter)GetEnumvaluesSeq, NULL, "values"},
+  { "values_by_name", (getter)GetEnumvaluesByName, NULL,
+    "Enum values by name"},
+  { "values_by_number", (getter)GetEnumvaluesByNumber, NULL,
+    "Enum values by number"},
+
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  {NULL}
+};
+
+}  // namespace enum_descriptor
+
+PyTypeObject PyEnumDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".EnumDescriptor",   // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A Enum Descriptor",                  // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  enum_descriptor::Methods,             // tp_getset
+  0,                                    // tp_members
+  enum_descriptor::Getters,             // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyEnumDescriptor_FromDescriptor(
+    const EnumDescriptor* enum_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyEnumDescriptor_Type, enum_descriptor, NULL);
+}
+
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const EnumDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
+namespace enumvalue_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const EnumValueDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const EnumValueDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetNumber(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->number());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
+  return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type());
+}
+
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const EnumValueOptions& options(_GetDescriptor(self)->options());
+  if (&options != &EnumValueOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+
+static PyGetSetDef Getters[] = {
+  { "name", (getter)GetName, NULL, "name"},
+  { "number", (getter)GetNumber, NULL, "number"},
+  { "index", (getter)GetIndex, NULL, "index"},
+  { "type", (getter)GetType, NULL, "index"},
+
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  {NULL}
+};
+
+}  // namespace enumvalue_descriptor
+
+PyTypeObject PyEnumValueDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".EnumValueDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A EnumValue Descriptor",             // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  enumvalue_descriptor::Methods,        // tp_methods
+  0,                                    // tp_members
+  enumvalue_descriptor::Getters,        // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyEnumValueDescriptor_FromDescriptor(
+    const EnumValueDescriptor* enumvalue_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL);
+}
+
+namespace file_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const FileDescriptor* _GetDescriptor(PyFileDescriptor *self) {
+  return reinterpret_cast<const FileDescriptor*>(self->base.descriptor);
+}
+
+static void Dealloc(PyFileDescriptor* self) {
+  Py_XDECREF(self->serialized_pb);
+  descriptor::Dealloc(&self->base);
+}
+
+static PyObject* GetPool(PyFileDescriptor *self, void *closure) {
+  PyObject* pool = reinterpret_cast<PyObject*>(
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->pool()));
+  Py_XINCREF(pool);
+  return pool;
+}
+
+static PyObject* GetName(PyFileDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetPackage(PyFileDescriptor *self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->package());
+}
+
+static PyObject* GetSerializedPb(PyFileDescriptor *self, void *closure) {
+  PyObject *serialized_pb = self->serialized_pb;
+  if (serialized_pb != NULL) {
+    Py_INCREF(serialized_pb);
+    return serialized_pb;
+  }
+  FileDescriptorProto file_proto;
+  _GetDescriptor(self)->CopyTo(&file_proto);
+  string contents;
+  file_proto.SerializePartialToString(&contents);
+  self->serialized_pb = PyBytes_FromStringAndSize(
+      contents.c_str(), contents.size());
+  if (self->serialized_pb == NULL) {
+    return NULL;
+  }
+  Py_INCREF(self->serialized_pb);
+  return self->serialized_pb;
+}
+
+static PyObject* GetMessageTypesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileMessageTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetEnumTypesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileEnumTypesByName(_GetDescriptor(self));
+}
+
+static PyObject* GetExtensionsByName(PyFileDescriptor* self, void *closure) {
+  return NewFileExtensionsByName(_GetDescriptor(self));
+}
+
+static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) {
+  return NewFileDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetPublicDependencies(PyFileDescriptor* self, void *closure) {
+  return NewFilePublicDependencies(_GetDescriptor(self));
+}
+
+static PyObject* GetHasOptions(PyFileDescriptor *self, void *closure) {
+  const FileOptions& options(_GetDescriptor(self)->options());
+  if (&options != &FileOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyFileDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyFileDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyFileDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
+static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) {
+  return PyString_InternFromString(
+      FileDescriptor::SyntaxName(_GetDescriptor(self)->syntax()));
+}
+
+static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<FileDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+  { "pool", (getter)GetPool, NULL, "pool"},
+  { "name", (getter)GetName, NULL, "name"},
+  { "package", (getter)GetPackage, NULL, "package"},
+  { "serialized_pb", (getter)GetSerializedPb},
+  { "message_types_by_name", (getter)GetMessageTypesByName, NULL,
+    "Messages by name"},
+  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"},
+  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
+    "Extensions by name"},
+  { "dependencies", (getter)GetDependencies, NULL, "Dependencies"},
+  { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"},
+
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+  {NULL}
+};
+
+}  // namespace file_descriptor
+
+PyTypeObject PyFileDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".FileDescriptor",   // tp_name
+  sizeof(PyFileDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  (destructor)file_descriptor::Dealloc,  // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A File Descriptor",                  // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  file_descriptor::Methods,             // tp_methods
+  0,                                    // tp_members
+  file_descriptor::Getters,             // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
   0,                                    // tp_dict
   0,                                    // tp_descr_get
   0,                                    // tp_descr_set
   0,                                    // tp_dictoffset
   0,                                    // tp_init
-  PyType_GenericAlloc,                  // tp_alloc
-  PyType_GenericNew,                    // tp_new
+  0,                                    // tp_alloc
+  0,                                    // tp_new
   PyObject_Del,                         // tp_free
 };
 
-namespace cdescriptor_pool {
-
-static void Dealloc(CDescriptorPool* self) {
-  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor) {
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor,
+                                                         NULL);
 }
 
-static PyObject* NewCDescriptor(
-    const google::protobuf::FieldDescriptor* field_descriptor) {
-  CFieldDescriptor* cfield_descriptor = PyObject_New(
-      CFieldDescriptor, &CFieldDescriptor_Type);
-  if (cfield_descriptor == NULL) {
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
+    const FileDescriptor* file_descriptor, PyObject *serialized_pb) {
+  bool was_created;
+  PyObject* py_descriptor = descriptor::NewInternedDescriptor(
+      &PyFileDescriptor_Type, file_descriptor, &was_created);
+  if (py_descriptor == NULL) {
     return NULL;
   }
-  cfield_descriptor->descriptor = field_descriptor;
-  cfield_descriptor->descriptor_field = NULL;
+  if (was_created) {
+    PyFileDescriptor* cfile_descriptor =
+        reinterpret_cast<PyFileDescriptor*>(py_descriptor);
+    Py_XINCREF(serialized_pb);
+    cfile_descriptor->serialized_pb = serialized_pb;
+  }
+  // TODO(amauryfa): In the case of a cached object, check that serialized_pb
+  // is the same as before.
 
-  return reinterpret_cast<PyObject*>(cfield_descriptor);
+  return py_descriptor;
 }
 
-PyObject* FindFieldByName(CDescriptorPool* self, PyObject* name) {
-  const char* full_field_name = PyString_AsString(name);
-  if (full_field_name == NULL) {
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
     return NULL;
   }
-
-  const google::protobuf::FieldDescriptor* field_descriptor = NULL;
-
-  field_descriptor = self->pool->FindFieldByName(full_field_name);
-
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
-                 full_field_name);
-    return NULL;
-  }
-
-  return NewCDescriptor(field_descriptor);
+  return reinterpret_cast<const FileDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
 }
 
-PyObject* FindExtensionByName(CDescriptorPool* self, PyObject* arg) {
-  const char* full_field_name = PyString_AsString(arg);
-  if (full_field_name == NULL) {
-    return NULL;
-  }
+namespace oneof_descriptor {
 
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->pool->FindExtensionByName(full_field_name);
-  if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
-                 full_field_name);
-    return NULL;
-  }
-
-  return NewCDescriptor(field_descriptor);
+// Unchecked accessor to the C++ pointer.
+static const OneofDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const OneofDescriptor*>(self->descriptor);
 }
 
-static PyMethodDef Methods[] = {
-  { C("FindFieldByName"),
-    (PyCFunction)FindFieldByName,
-    METH_O,
-    C("Searches for a field descriptor by full name.") },
-  { C("FindExtensionByName"),
-    (PyCFunction)FindExtensionByName,
-    METH_O,
-    C("Searches for extension descriptor by full name.") },
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetFields(PyBaseDescriptor* self, void *closure) {
+  return NewOneofFieldsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* containing_type =
+      _GetDescriptor(self)->containing_type();
+  if (containing_type) {
+    return PyMessageDescriptor_FromDescriptor(containing_type);
+  } else {
+    Py_RETURN_NONE;
+  }
+}
+
+static PyGetSetDef Getters[] = {
+  { "name", (getter)GetName, NULL, "Name"},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "index", (getter)GetIndex, NULL, "Index"},
+
+  { "containing_type", (getter)GetContainingType, NULL, "Containing type"},
+  { "fields", (getter)GetFields, NULL, "Fields"},
   {NULL}
 };
 
-}  // namespace cdescriptor_pool
+}  // namespace oneof_descriptor
 
-PyTypeObject CDescriptorPool_Type = {
+PyTypeObject PyOneofDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_net_proto2___python."
-    "CFieldDescriptor"),               // tp_name
-  sizeof(CDescriptorPool),             // tp_basicsize
-  0,                                   // tp_itemsize
-  (destructor)cdescriptor_pool::Dealloc,  // tp_dealloc
-  0,                                   // tp_print
-  0,                                   // tp_getattr
-  0,                                   // tp_setattr
-  0,                                   // tp_compare
-  0,                                   // tp_repr
-  0,                                   // tp_as_number
-  0,                                   // tp_as_sequence
-  0,                                   // tp_as_mapping
-  0,                                   // tp_hash
-  0,                                   // tp_call
-  0,                                   // tp_str
-  0,                                   // tp_getattro
-  0,                                   // tp_setattro
-  0,                                   // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  // tp_flags
-  C("A Descriptor Pool"),              // tp_doc
-  0,                                   // tp_traverse
-  0,                                   // tp_clear
-  0,                                   // tp_richcompare
-  0,                                   // tp_weaklistoffset
-  0,                                   // tp_iter
-  0,                                   // tp_iternext
-  cdescriptor_pool::Methods,           // tp_methods
-  0,                                   // tp_members
-  0,                                   // tp_getset
-  0,                                   // tp_base
-  0,                                   // tp_dict
-  0,                                   // tp_descr_get
-  0,                                   // tp_descr_set
-  0,                                   // tp_dictoffset
-  0,                                   // tp_init
-  PyType_GenericAlloc,                 // tp_alloc
-  PyType_GenericNew,                   // tp_new
-  PyObject_Del,                        // tp_free
+  FULL_MODULE_NAME ".OneofDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  "A Oneof Descriptor",                 // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  0,                                    // tp_methods
+  0,                                    // tp_members
+  oneof_descriptor::Getters,            // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-google::protobuf::DescriptorPool* GetDescriptorPool() {
-  if (g_descriptor_pool == NULL) {
-    g_descriptor_pool = new google::protobuf::DescriptorPool(
-        google::protobuf::DescriptorPool::generated_pool());
-  }
-  return g_descriptor_pool;
+PyObject* PyOneofDescriptor_FromDescriptor(
+    const OneofDescriptor* oneof_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyOneofDescriptor_Type, oneof_descriptor, NULL);
 }
 
-PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) {
-  CDescriptorPool* cdescriptor_pool = PyObject_New(
-      CDescriptorPool, &CDescriptorPool_Type);
-  if (cdescriptor_pool == NULL) {
-    return NULL;
-  }
-  cdescriptor_pool->pool = GetDescriptorPool();
-  return reinterpret_cast<PyObject*>(cdescriptor_pool);
-}
-
-
-// Collects errors that occur during proto file building to allow them to be
-// propagated in the python exception instead of only living in ERROR logs.
-class BuildFileErrorCollector : public google::protobuf::DescriptorPool::ErrorCollector {
- public:
-  BuildFileErrorCollector() : error_message(""), had_errors(false) {}
-
-  void AddError(const string& filename, const string& element_name,
-                const Message* descriptor, ErrorLocation location,
-                const string& message) {
-    // Replicates the logging behavior that happens in the C++ implementation
-    // when an error collector is not passed in.
-    if (!had_errors) {
-      error_message +=
-          ("Invalid proto descriptor for file \"" + filename + "\":\n");
+// Add a enum values to a type dictionary.
+static bool AddEnumValues(PyTypeObject *type,
+                          const EnumDescriptor* enum_descriptor) {
+  for (int i = 0; i < enum_descriptor->value_count(); ++i) {
+    const EnumValueDescriptor* value = enum_descriptor->value(i);
+    ScopedPyObjectPtr obj(PyInt_FromLong(value->number()));
+    if (obj == NULL) {
+      return false;
     }
-    // As this only happens on failure and will result in the program not
-    // running at all, no effort is made to optimize this string manipulation.
-    error_message += ("  " + element_name + ": " + message + "\n");
+    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) <
+        0) {
+      return false;
+    }
   }
-
-  string error_message;
-  bool had_errors;
-};
-
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) {
-  char* message_type;
-  Py_ssize_t message_len;
-
-  if (PyBytes_AsStringAndSize(arg, &message_type, &message_len) < 0) {
-    return NULL;
-  }
-
-  google::protobuf::FileDescriptorProto file_proto;
-  if (!file_proto.ParseFromArray(message_type, message_len)) {
-    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
-    return NULL;
-  }
-
-  if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
-          file_proto.name()) != NULL) {
-    Py_RETURN_NONE;
-  }
-
-  BuildFileErrorCollector error_collector;
-  const google::protobuf::FileDescriptor* descriptor =
-      GetDescriptorPool()->BuildFileCollectingErrors(file_proto,
-                                                     &error_collector);
-  if (descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError,
-                 "Couldn't build proto file into descriptor pool!\n%s",
-                 error_collector.error_message.c_str());
-    return NULL;
-  }
-
-  Py_RETURN_NONE;
+  return true;
 }
 
+static bool AddIntConstant(PyTypeObject *type, const char* name, int value) {
+  ScopedPyObjectPtr obj(PyInt_FromLong(value));
+  if (PyDict_SetItemString(type->tp_dict, name, obj.get()) < 0) {
+    return false;
+  }
+  return true;
+}
+
+
 bool InitDescriptor() {
-  CFieldDescriptor_Type.tp_new = PyType_GenericNew;
-  if (PyType_Ready(&CFieldDescriptor_Type) < 0)
+  if (PyType_Ready(&PyMessageDescriptor_Type) < 0)
     return false;
 
-  CDescriptorPool_Type.tp_new = PyType_GenericNew;
-  if (PyType_Ready(&CDescriptorPool_Type) < 0)
+  if (PyType_Ready(&PyFieldDescriptor_Type) < 0)
+    return false;
+
+  if (!AddEnumValues(&PyFieldDescriptor_Type,
+                     FieldDescriptorProto::Label_descriptor())) {
+    return false;
+  }
+  if (!AddEnumValues(&PyFieldDescriptor_Type,
+                     FieldDescriptorProto::Type_descriptor())) {
+    return false;
+  }
+#define ADD_FIELDDESC_CONSTANT(NAME) AddIntConstant( \
+    &PyFieldDescriptor_Type, #NAME, FieldDescriptor::NAME)
+  if (!ADD_FIELDDESC_CONSTANT(CPPTYPE_INT32) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_INT64) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT32) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_UINT64) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_DOUBLE) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_FLOAT) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_BOOL) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_ENUM) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_STRING) ||
+      !ADD_FIELDDESC_CONSTANT(CPPTYPE_MESSAGE)) {
+    return false;
+  }
+#undef ADD_FIELDDESC_CONSTANT
+
+  if (PyType_Ready(&PyEnumDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyEnumValueDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyFileDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyOneofDescriptor_Type) < 0)
+    return false;
+
+  if (!InitDescriptorMappingTypes())
     return false;
 
   return true;
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index ae7a1b9..eb99df1 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -34,60 +34,61 @@
 #define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
 
 #include <Python.h>
-#include <structmember.h>
 
 #include <google/protobuf/descriptor.h>
 
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#endif
-
 namespace google {
 namespace protobuf {
 namespace python {
 
-typedef struct CFieldDescriptor {
-  PyObject_HEAD
+extern PyTypeObject PyMessageDescriptor_Type;
+extern PyTypeObject PyFieldDescriptor_Type;
+extern PyTypeObject PyEnumDescriptor_Type;
+extern PyTypeObject PyEnumValueDescriptor_Type;
+extern PyTypeObject PyFileDescriptor_Type;
+extern PyTypeObject PyOneofDescriptor_Type;
 
-  // The proto2 descriptor that this object represents.
-  const google::protobuf::FieldDescriptor* descriptor;
-
-  // Reference to the original field object in the Python DESCRIPTOR.
-  PyObject* descriptor_field;
-} CFieldDescriptor;
-
-typedef struct {
-  PyObject_HEAD
-
-  const google::protobuf::DescriptorPool* pool;
-} CDescriptorPool;
-
-extern PyTypeObject CFieldDescriptor_Type;
-
-extern PyTypeObject CDescriptorPool_Type;
-
-namespace cdescriptor_pool {
-
-// Looks up a field by name. Returns a CDescriptor corresponding to
-// the field on success, or NULL on failure.
-//
+// Wraps a Descriptor in a Python object.
+// The C++ pointer is usually borrowed from the global DescriptorPool.
+// In any case, it must stay alive as long as the Python object.
 // Returns a new reference.
-PyObject* FindFieldByName(CDescriptorPool* self, PyObject* name);
+PyObject* PyMessageDescriptor_FromDescriptor(const Descriptor* descriptor);
+PyObject* PyFieldDescriptor_FromDescriptor(const FieldDescriptor* descriptor);
+PyObject* PyEnumDescriptor_FromDescriptor(const EnumDescriptor* descriptor);
+PyObject* PyEnumValueDescriptor_FromDescriptor(
+    const EnumValueDescriptor* descriptor);
+PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor);
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor);
 
-// Looks up an extension by name. Returns a CDescriptor corresponding
-// to the field on success, or NULL on failure.
-//
+// Alternate constructor of PyFileDescriptor, used when we already have a
+// serialized FileDescriptorProto that can be cached.
 // Returns a new reference.
-PyObject* FindExtensionByName(CDescriptorPool* self, PyObject* arg);
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
+    const FileDescriptor* file_descriptor, PyObject* serialized_pb);
 
-}  // namespace cdescriptor_pool
+// Return the C++ descriptor pointer.
+// This function checks the parameter type; on error, return NULL with a Python
+// exception set.
+const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj);
+const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj);
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj);
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj);
 
-PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args);
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
+// Returns the raw C++ pointer.
+const void* PyDescriptor_AsVoidPtr(PyObject* obj);
+
+// Check that the calling Python code is the global scope of a _pb2.py module.
+// This function is used to support the current code generated by the proto
+// compiler, which insists on modifying descriptors after they have been
+// created.
+//
+// stacklevel indicates which Python frame should be the _pb2.py module.
+//
+// Don't use this function outside descriptor classes.
+bool _CalledFromGeneratedFile(int stacklevel);
+
 bool InitDescriptor();
-google::protobuf::DescriptorPool* GetDescriptorPool();
 
 }  // namespace python
 }  // namespace protobuf
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
new file mode 100644
index 0000000..e505d81
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -0,0 +1,1652 @@
+// 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.
+
+// Mappings and Sequences of descriptors.
+// Used by Descriptor.fields_by_name, EnumDescriptor.values...
+//
+// They avoid the allocation of a full dictionary or a full list: they simply
+// store a pointer to the parent descriptor, use the C++ Descriptor methods (see
+// google/protobuf/descriptor.h) to retrieve other descriptors, and create
+// Python objects on the fly.
+//
+// The containers fully conform to abc.Mapping and abc.Sequence, and behave just
+// like read-only dictionaries and lists.
+//
+// Because the interface of C++ Descriptors is quite regular, this file actually
+// defines only three types, the exact behavior of a container is controlled by
+// a DescriptorContainerDef structure, which contains functions that uses the
+// public Descriptor API.
+//
+// Note: This DescriptorContainerDef is similar to the "virtual methods table"
+// that a C++ compiler generates for a class. We have to make it explicit
+// because the Python API is based on C, and does not play well with C++
+// inheritance.
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/pyext/descriptor_containers.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+  #define PyString_FromFormat PyUnicode_FromFormat
+  #define PyInt_FromLong PyLong_FromLong
+  #if PY_VERSION_HEX < 0x03030000
+    #error "Python 3.0 - 3.2 are not supported."
+  #endif
+  #define PyString_AsStringAndSize(ob, charpp, sizep) \
+    (PyUnicode_Check(ob)? \
+       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct PyContainer;
+
+typedef int (*CountMethod)(PyContainer* self);
+typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
+typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
+typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
+                                                const string& name);
+typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
+typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
+typedef const string& (*GetItemNameMethod)(const void* descriptor);
+typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor);
+typedef int (*GetItemNumberMethod)(const void* descriptor);
+typedef int (*GetItemIndexMethod)(const void* descriptor);
+
+struct DescriptorContainerDef {
+  const char* mapping_name;
+  // Returns the number of items in the container.
+  CountMethod count_fn;
+  // Retrieve item by index (usually the order of declaration in the proto file)
+  // Used by sequences, but also iterators. 0 <= index < Count().
+  GetByIndexMethod get_by_index_fn;
+  // Retrieve item by name (usually a call to some 'FindByName' method).
+  // Used by "by_name" mappings.
+  GetByNameMethod get_by_name_fn;
+  // Retrieve item by camelcase name (usually a call to some
+  // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
+  GetByCamelcaseNameMethod get_by_camelcase_name_fn;
+  // Retrieve item by declared number (field tag, or enum value).
+  // Used by "by_number" mappings.
+  GetByNumberMethod get_by_number_fn;
+  // Converts a item C++ descriptor to a Python object. Returns a new reference.
+  NewObjectFromItemMethod new_object_from_item_fn;
+  // Retrieve the name of an item. Used by iterators on "by_name" mappings.
+  GetItemNameMethod get_item_name_fn;
+  // Retrieve the camelcase name of an item. Used by iterators on
+  // "by_camelcase_name" mappings.
+  GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
+  // Retrieve the number of an item. Used by iterators on "by_number" mappings.
+  GetItemNumberMethod get_item_number_fn;
+  // Retrieve the index of an item for the container type.
+  // Used by "__contains__".
+  // If not set, "x in sequence" will do a linear search.
+  GetItemIndexMethod get_item_index_fn;
+};
+
+struct PyContainer {
+  PyObject_HEAD
+
+  // The proto2 descriptor this container belongs to the global DescriptorPool.
+  const void* descriptor;
+
+  // A pointer to a static structure with function pointers that control the
+  // behavior of the container. Very similar to the table of virtual functions
+  // of a C++ class.
+  const DescriptorContainerDef* container_def;
+
+  // The kind of container: list, or dict by name or value.
+  enum ContainerKind {
+    KIND_SEQUENCE,
+    KIND_BYNAME,
+    KIND_BYCAMELCASENAME,
+    KIND_BYNUMBER,
+  } kind;
+};
+
+struct PyContainerIterator {
+  PyObject_HEAD
+
+  // The container we are iterating over. Own a reference.
+  PyContainer* container;
+
+  // The current index in the iterator.
+  int index;
+
+  // The kind of container: list, or dict by name or value.
+  enum IterKind {
+    KIND_ITERKEY,
+    KIND_ITERVALUE,
+    KIND_ITERITEM,
+    KIND_ITERVALUE_REVERSED,  // For sequences
+  } kind;
+};
+
+namespace descriptor {
+
+// Returns the C++ item descriptor for a given Python key.
+// When the descriptor is found, return true and set *item.
+// When the descriptor is not found, return true, but set *item to NULL.
+// On error, returns false with an exception set.
+static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
+  switch (self->kind) {
+    case PyContainer::KIND_BYNAME:
+      {
+        char* name;
+        Py_ssize_t name_size;
+        if (PyString_AsStringAndSize(key, &name, &name_size) < 0) {
+          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+            // Not a string, cannot be in the container.
+            PyErr_Clear();
+            *item = NULL;
+            return true;
+          }
+          return false;
+        }
+        *item = self->container_def->get_by_name_fn(
+            self, string(name, name_size));
+        return true;
+      }
+    case PyContainer::KIND_BYCAMELCASENAME:
+      {
+        char* camelcase_name;
+        Py_ssize_t name_size;
+        if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) {
+          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+            // Not a string, cannot be in the container.
+            PyErr_Clear();
+            *item = NULL;
+            return true;
+          }
+          return false;
+        }
+        *item = self->container_def->get_by_camelcase_name_fn(
+            self, string(camelcase_name, name_size));
+        return true;
+      }
+    case PyContainer::KIND_BYNUMBER:
+      {
+        Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
+        if (number == -1 && PyErr_Occurred()) {
+          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+            // Not a number, cannot be in the container.
+            PyErr_Clear();
+            *item = NULL;
+            return true;
+          }
+          return false;
+        }
+        *item = self->container_def->get_by_number_fn(self, number);
+        return true;
+      }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return false;
+  }
+}
+
+// Returns the key of the object at the given index.
+// Used when iterating over mappings.
+static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
+  const void* item = self->container_def->get_by_index_fn(self, index);
+  switch (self->kind) {
+    case PyContainer::KIND_BYNAME:
+      {
+        const string& name(self->container_def->get_item_name_fn(item));
+        return PyString_FromStringAndSize(name.c_str(), name.size());
+      }
+    case PyContainer::KIND_BYCAMELCASENAME:
+      {
+        const string& name(
+            self->container_def->get_item_camelcase_name_fn(item));
+        return PyString_FromStringAndSize(name.c_str(), name.size());
+      }
+    case PyContainer::KIND_BYNUMBER:
+      {
+        int value = self->container_def->get_item_number_fn(item);
+        return PyInt_FromLong(value);
+      }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return NULL;
+  }
+}
+
+// Returns the object at the given index.
+// Also used when iterating over mappings.
+static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) {
+  return self->container_def->new_object_from_item_fn(
+      self->container_def->get_by_index_fn(self, index));
+}
+
+static Py_ssize_t Length(PyContainer* self) {
+  return self->container_def->count_fn(self);
+}
+
+// The DescriptorMapping type.
+
+static PyObject* Subscript(PyContainer* self, PyObject* key) {
+  const void* item = NULL;
+  if (!_GetItemByKey(self, key, &item)) {
+    return NULL;
+  }
+  if (!item) {
+    PyErr_SetObject(PyExc_KeyError, key);
+    return NULL;
+  }
+  return self->container_def->new_object_from_item_fn(item);
+}
+
+static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) {
+  if (_CalledFromGeneratedFile(0)) {
+    return 0;
+  }
+  PyErr_Format(PyExc_TypeError,
+               "'%.200s' object does not support item assignment",
+               Py_TYPE(self)->tp_name);
+  return -1;
+}
+
+static PyMappingMethods MappingMappingMethods = {
+  (lenfunc)Length,               // mp_length
+  (binaryfunc)Subscript,         // mp_subscript
+  (objobjargproc)AssSubscript,   // mp_ass_subscript
+};
+
+static int Contains(PyContainer* self, PyObject* key) {
+  const void* item = NULL;
+  if (!_GetItemByKey(self, key, &item)) {
+    return -1;
+  }
+  if (item) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+static PyObject* ContainerRepr(PyContainer* self) {
+  const char* kind = "";
+  switch (self->kind) {
+    case PyContainer::KIND_SEQUENCE:
+      kind = "sequence";
+      break;
+    case PyContainer::KIND_BYNAME:
+      kind = "mapping by name";
+      break;
+    case PyContainer::KIND_BYCAMELCASENAME:
+      kind = "mapping by camelCase name";
+      break;
+    case PyContainer::KIND_BYNUMBER:
+      kind = "mapping by number";
+      break;
+  }
+  return PyString_FromFormat(
+      "<%s %s>", self->container_def->mapping_name, kind);
+}
+
+extern PyTypeObject DescriptorMapping_Type;
+extern PyTypeObject DescriptorSequence_Type;
+
+// A sequence container can only be equal to another sequence container, or (for
+// backward compatibility) to a list containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) {
+  // Check the identity of C++ pointers.
+  if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) {
+    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+    if (self->descriptor == other_container->descriptor &&
+        self->container_def == other_container->container_def &&
+        self->kind == other_container->kind) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
+  // If other is a list
+  if (PyList_Check(other)) {
+    // return list(self) == other
+    int size = Length(self);
+    if (size != PyList_Size(other)) {
+      return false;
+    }
+    for (int index = 0; index < size; index++) {
+      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+      if (value1 == NULL) {
+        return -1;
+      }
+      PyObject* value2 = PyList_GetItem(other, index);
+      if (value2 == NULL) {
+        return -1;
+      }
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
+      if (cmp != 1)  // error or not equal
+          return cmp;
+    }
+    // All items were found and equal
+    return 1;
+  }
+
+  // Any other object is different.
+  return 0;
+}
+
+// A mapping container can only be equal to another mapping container, or (for
+// backward compatibility) to a dict containing the same items.
+// Returns 1 if equal, 0 if unequal, -1 on error.
+static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) {
+  // Check the identity of C++ pointers.
+  if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) {
+    PyContainer* other_container = reinterpret_cast<PyContainer*>(other);
+    if (self->descriptor == other_container->descriptor &&
+        self->container_def == other_container->container_def &&
+        self->kind == other_container->kind) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
+  // If other is a dict
+  if (PyDict_Check(other)) {
+    // equivalent to dict(self.items()) == other
+    int size = Length(self);
+    if (size != PyDict_Size(other)) {
+      return false;
+    }
+    for (int index = 0; index < size; index++) {
+      ScopedPyObjectPtr key(_NewKey_ByIndex(self, index));
+      if (key == NULL) {
+        return -1;
+      }
+      ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
+      if (value1 == NULL) {
+        return -1;
+      }
+      PyObject* value2 = PyDict_GetItem(other, key.get());
+      if (value2 == NULL) {
+        // Not found in the other dictionary
+        return 0;
+      }
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
+      if (cmp != 1)  // error or not equal
+          return cmp;
+    }
+    // All items were found and equal
+    return 1;
+  }
+
+  // Any other object is different.
+  return 0;
+}
+
+static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) {
+  if (opid != Py_EQ && opid != Py_NE) {
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+  }
+
+  int result;
+
+  if (self->kind == PyContainer::KIND_SEQUENCE) {
+    result = DescriptorSequence_Equal(self, other);
+  } else {
+    result = DescriptorMapping_Equal(self, other);
+  }
+  if (result < 0) {
+    return NULL;
+  }
+  if (result ^ (opid == Py_NE)) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+static PySequenceMethods MappingSequenceMethods = {
+    0,                      // sq_length
+    0,                      // sq_concat
+    0,                      // sq_repeat
+    0,                      // sq_item
+    0,                      // sq_slice
+    0,                      // sq_ass_item
+    0,                      // sq_ass_slice
+    (objobjproc)Contains,   // sq_contains
+};
+
+static PyObject* Get(PyContainer* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = Py_None;
+  if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
+    return NULL;
+  }
+
+  const void* item;
+  if (!_GetItemByKey(self, key, &item)) {
+    return NULL;
+  }
+  if (item == NULL) {
+    Py_INCREF(default_value);
+    return default_value;
+  }
+  return self->container_def->new_object_from_item_fn(item);
+}
+
+static PyObject* Keys(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == NULL) {
+    return NULL;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    PyObject* key = _NewKey_ByIndex(self, index);
+    if (key == NULL) {
+      return NULL;
+    }
+    PyList_SET_ITEM(list.get(), index, key);
+  }
+  return list.release();
+}
+
+static PyObject* Values(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == NULL) {
+    return NULL;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    PyObject* value = _NewObj_ByIndex(self, index);
+    if (value == NULL) {
+      return NULL;
+    }
+    PyList_SET_ITEM(list.get(), index, value);
+  }
+  return list.release();
+}
+
+static PyObject* Items(PyContainer* self, PyObject* args) {
+  Py_ssize_t count = Length(self);
+  ScopedPyObjectPtr list(PyList_New(count));
+  if (list == NULL) {
+    return NULL;
+  }
+  for (Py_ssize_t index = 0; index < count; ++index) {
+    ScopedPyObjectPtr obj(PyTuple_New(2));
+    if (obj == NULL) {
+      return NULL;
+    }
+    PyObject* key = _NewKey_ByIndex(self, index);
+    if (key == NULL) {
+      return NULL;
+    }
+    PyTuple_SET_ITEM(obj.get(), 0, key);
+    PyObject* value = _NewObj_ByIndex(self, index);
+    if (value == NULL) {
+      return NULL;
+    }
+    PyTuple_SET_ITEM(obj.get(), 1, value);
+    PyList_SET_ITEM(list.get(), index, obj.release());
+  }
+  return list.release();
+}
+
+static PyObject* NewContainerIterator(PyContainer* mapping,
+                                      PyContainerIterator::IterKind kind);
+
+static PyObject* Iter(PyContainer* self) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterKeys(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY);
+}
+static PyObject* IterValues(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE);
+}
+static PyObject* IterItems(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM);
+}
+
+static PyMethodDef MappingMethods[] = {
+  { "get", (PyCFunction)Get, METH_VARARGS, },
+  { "keys", (PyCFunction)Keys, METH_NOARGS, },
+  { "values", (PyCFunction)Values, METH_NOARGS, },
+  { "items", (PyCFunction)Items, METH_NOARGS, },
+  { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, },
+  { "itervalues", (PyCFunction)IterValues, METH_NOARGS, },
+  { "iteritems", (PyCFunction)IterItems, METH_NOARGS, },
+  {NULL}
+};
+
+PyTypeObject DescriptorMapping_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  "DescriptorMapping",                  // tp_name
+  sizeof(PyContainer),                  // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  (reprfunc)ContainerRepr,              // tp_repr
+  0,                                    // tp_as_number
+  &MappingSequenceMethods,              // tp_as_sequence
+  &MappingMappingMethods,               // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  0,                                    // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  (richcmpfunc)RichCompare,             // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  (getiterfunc)Iter,                    // tp_iter
+  0,                                    // tp_iternext
+  MappingMethods,                       // tp_methods
+  0,                                    // tp_members
+  0,                                    // tp_getset
+  0,                                    // tp_base
+  0,                                    // tp_dict
+  0,                                    // tp_descr_get
+  0,                                    // tp_descr_set
+  0,                                    // tp_dictoffset
+  0,                                    // tp_init
+  0,                                    // tp_alloc
+  0,                                    // tp_new
+  0,                                    // tp_free
+};
+
+// The DescriptorSequence type.
+
+static PyObject* GetItem(PyContainer* self, Py_ssize_t index) {
+  if (index < 0) {
+    index += Length(self);
+  }
+  if (index < 0 || index >= Length(self)) {
+    PyErr_SetString(PyExc_IndexError, "index out of range");
+    return NULL;
+  }
+  return _NewObj_ByIndex(self, index);
+}
+
+// Returns the position of the item in the sequence, of -1 if not found.
+// This function never fails.
+int Find(PyContainer* self, PyObject* item) {
+  // The item can only be in one position: item.index.
+  // Check that self[item.index] == item, it's faster than a linear search.
+  //
+  // This assumes that sequences are only defined by syntax of the .proto file:
+  // a specific item belongs to only one sequence, depending on its position in
+  // the .proto file definition.
+  const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item);
+  if (descriptor_ptr == NULL) {
+    // Not a descriptor, it cannot be in the list.
+    return -1;
+  }
+  if (self->container_def->get_item_index_fn) {
+    int index = self->container_def->get_item_index_fn(descriptor_ptr);
+    if (index < 0 || index >= Length(self)) {
+      // This index is not from this collection.
+      return -1;
+    }
+    if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) {
+      // The descriptor at this index is not the same.
+      return -1;
+    }
+    // self[item.index] == item, so return the index.
+    return index;
+  } else {
+    // Fall back to linear search.
+    int length = Length(self);
+    for (int index=0; index < length; index++) {
+      if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) {
+        return index;
+      }
+    }
+    // Not found
+    return -1;
+  }
+}
+
+// Implements list.index(): the position of the item is in the sequence.
+static PyObject* Index(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    // Not found
+    PyErr_SetNone(PyExc_ValueError);
+    return NULL;
+  } else {
+    return PyInt_FromLong(position);
+  }
+}
+// Implements "list.__contains__()": is the object in the sequence.
+static int SeqContains(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+// Implements list.count(): number of occurrences of the item in the sequence.
+// An item can only appear once in a sequence. If it exists, return 1.
+static PyObject* Count(PyContainer* self, PyObject* item) {
+  int position = Find(self, item);
+  if (position < 0) {
+    return PyInt_FromLong(0);
+  } else {
+    return PyInt_FromLong(1);
+  }
+}
+
+static PyObject* Append(PyContainer* self, PyObject* args) {
+  if (_CalledFromGeneratedFile(0)) {
+    Py_RETURN_NONE;
+  }
+  PyErr_Format(PyExc_TypeError,
+               "'%.200s' object is not a mutable sequence",
+               Py_TYPE(self)->tp_name);
+  return NULL;
+}
+
+static PyObject* Reversed(PyContainer* self, PyObject* args) {
+  return NewContainerIterator(self,
+                              PyContainerIterator::KIND_ITERVALUE_REVERSED);
+}
+
+static PyMethodDef SeqMethods[] = {
+  { "index", (PyCFunction)Index, METH_O, },
+  { "count", (PyCFunction)Count, METH_O, },
+  { "append", (PyCFunction)Append, METH_O, },
+  { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, },
+  {NULL}
+};
+
+static PySequenceMethods SeqSequenceMethods = {
+    (lenfunc)Length,          // sq_length
+    0,                        // sq_concat
+    0,                        // sq_repeat
+    (ssizeargfunc)GetItem,    // sq_item
+    0,                        // sq_slice
+    0,                        // sq_ass_item
+    0,                        // sq_ass_slice
+    (objobjproc)SeqContains,  // sq_contains
+};
+
+PyTypeObject DescriptorSequence_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  "DescriptorSequence",                 // tp_name
+  sizeof(PyContainer),                  // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  (reprfunc)ContainerRepr,              // tp_repr
+  0,                                    // tp_as_number
+  &SeqSequenceMethods,                  // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  0,                                    // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  (richcmpfunc)RichCompare,             // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  SeqMethods,                           // tp_methods
+  0,                                    // tp_members
+  0,                                    // tp_getset
+  0,                                    // tp_base
+  0,                                    // tp_dict
+  0,                                    // tp_descr_get
+  0,                                    // tp_descr_set
+  0,                                    // tp_dictoffset
+  0,                                    // tp_init
+  0,                                    // tp_alloc
+  0,                                    // tp_new
+  0,                                    // tp_free
+};
+
+static PyObject* NewMappingByName(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYNAME;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewMappingByCamelcaseName(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYCAMELCASENAME;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewMappingByNumber(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  if (container_def->get_by_number_fn == NULL ||
+      container_def->get_item_number_fn == NULL) {
+    PyErr_SetNone(PyExc_NotImplementedError);
+    return NULL;
+  }
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYNUMBER;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static PyObject* NewSequence(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_SEQUENCE;
+  return reinterpret_cast<PyObject*>(self);
+}
+
+// Implement iterators over PyContainers.
+
+static void Iterator_Dealloc(PyContainerIterator* self) {
+  Py_CLEAR(self->container);
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+static PyObject* Iterator_Next(PyContainerIterator* self) {
+  int count = self->container->container_def->count_fn(self->container);
+  if (self->index >= count) {
+    // Return NULL with no exception to indicate the end.
+    return NULL;
+  }
+  int index = self->index;
+  self->index += 1;
+  switch (self->kind) {
+    case PyContainerIterator::KIND_ITERKEY:
+      return _NewKey_ByIndex(self->container, index);
+    case PyContainerIterator::KIND_ITERVALUE:
+      return _NewObj_ByIndex(self->container, index);
+    case PyContainerIterator::KIND_ITERVALUE_REVERSED:
+      return _NewObj_ByIndex(self->container, count - index - 1);
+    case PyContainerIterator::KIND_ITERITEM:
+      {
+        PyObject* obj = PyTuple_New(2);
+        if (obj == NULL) {
+          return NULL;
+        }
+        PyObject* key = _NewKey_ByIndex(self->container, index);
+        if (key == NULL) {
+          Py_DECREF(obj);
+          return NULL;
+        }
+        PyTuple_SET_ITEM(obj, 0, key);
+        PyObject* value = _NewObj_ByIndex(self->container, index);
+        if (value == NULL) {
+          Py_DECREF(obj);
+          return NULL;
+        }
+        PyTuple_SET_ITEM(obj, 1, value);
+        return obj;
+      }
+    default:
+      PyErr_SetNone(PyExc_NotImplementedError);
+      return NULL;
+  }
+}
+
+static PyTypeObject ContainerIterator_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  "DescriptorContainerIterator",        // tp_name
+  sizeof(PyContainerIterator),          // tp_basicsize
+  0,                                    // tp_itemsize
+  (destructor)Iterator_Dealloc,         // tp_dealloc
+  0,                                    // tp_print
+  0,                                    // tp_getattr
+  0,                                    // tp_setattr
+  0,                                    // tp_compare
+  0,                                    // tp_repr
+  0,                                    // tp_as_number
+  0,                                    // tp_as_sequence
+  0,                                    // tp_as_mapping
+  0,                                    // tp_hash
+  0,                                    // tp_call
+  0,                                    // tp_str
+  0,                                    // tp_getattro
+  0,                                    // tp_setattro
+  0,                                    // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                   // tp_flags
+  0,                                    // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  PyObject_SelfIter,                    // tp_iter
+  (iternextfunc)Iterator_Next,          // tp_iternext
+  0,                                    // tp_methods
+  0,                                    // tp_members
+  0,                                    // tp_getset
+  0,                                    // tp_base
+  0,                                    // tp_dict
+  0,                                    // tp_descr_get
+  0,                                    // tp_descr_set
+  0,                                    // tp_dictoffset
+  0,                                    // tp_init
+  0,                                    // tp_alloc
+  0,                                    // tp_new
+  0,                                    // tp_free
+};
+
+static PyObject* NewContainerIterator(PyContainer* container,
+                                      PyContainerIterator::IterKind kind) {
+  PyContainerIterator* self = PyObject_New(PyContainerIterator,
+                                           &ContainerIterator_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  Py_INCREF(container);
+  self->container = container;
+  self->kind = kind;
+  self->index = 0;
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+}  // namespace descriptor
+
+// Now define the real collections!
+
+namespace message_descriptor {
+
+typedef const Descriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->field_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindFieldByName(name);
+}
+
+static ItemDescriptor GetByCamelcaseName(PyContainer* self,
+                                         const string& name) {
+  return GetDescriptor(self)->FindFieldByCamelcaseName(name);
+}
+
+static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+  return GetDescriptor(self)->FindFieldByNumber(number);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFieldDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static const string& GetItemCamelcaseName(ItemDescriptor item) {
+  return item->camelcase_name();
+}
+
+static int GetItemNumber(ItemDescriptor item) {
+  return item->number();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageFields",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)GetByCamelcaseName,
+  (GetByNumberMethod)GetByNumber,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
+  (GetItemNumberMethod)GetItemNumber,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace fields
+
+PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
+                                               descriptor);
+}
+
+PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+namespace nested_types {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->nested_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindNestedTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->nested_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyMessageDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageNestedTypes",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace nested_types
+
+PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&nested_types::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->enum_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyEnumDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageNestedEnums",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace enums
+
+PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&enums::ContainerDef, descriptor);
+}
+
+namespace enumvalues {
+
+// This is the "enum_values_by_name" mapping, which collects values from all
+// enum types in a message.
+//
+// Note that the behavior of the C++ descriptor is different: it will search and
+// return the first value that matches the name, whereas the Python
+// implementation retrieves the last one.
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  int count = 0;
+  for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) {
+    count += GetDescriptor(self)->enum_type(i)->value_count();
+  }
+  return count;
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindEnumValueByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  // This is not optimal, but the number of enums *types* in a given message
+  // is small.  This function is only used when iterating over the mapping.
+  const EnumDescriptor* enum_type = NULL;
+  int enum_type_count = GetDescriptor(self)->enum_type_count();
+  for (int i = 0; i < enum_type_count; ++i) {
+    enum_type = GetDescriptor(self)->enum_type(i);
+    int enum_value_count = enum_type->value_count();
+    if (index < enum_value_count) {
+      // Found it!
+      break;
+    }
+    index -= enum_value_count;
+  }
+  // The next statement cannot overflow, because this function is only called by
+  // internal iterators which ensure that 0 <= index < Count().
+  return enum_type->value(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyEnumValueDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageEnumValues",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)NULL,
+};
+
+}  // namespace enumvalues
+
+PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->extension_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFieldDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageExtensions",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace extensions
+
+PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&extensions::ContainerDef, descriptor);
+}
+
+namespace oneofs {
+
+typedef const OneofDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->oneof_decl_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindOneofByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->oneof_decl(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyOneofDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "MessageOneofs",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace oneofs
+
+PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor);
+}
+
+PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&oneofs::ContainerDef, descriptor);
+}
+
+}  // namespace message_descriptor
+
+namespace enum_descriptor {
+
+typedef const EnumDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace enumvalues {
+
+typedef const EnumValueDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->value_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->value(index);
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindValueByName(name);
+}
+
+static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+  return GetDescriptor(self)->FindValueByNumber(number);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyEnumValueDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemNumber(ItemDescriptor item) {
+  return item->number();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "EnumValues",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)GetByNumber,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)GetItemNumber,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace enumvalues
+
+PyObject* NewEnumValuesByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor);
+}
+
+PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor);
+}
+
+}  // namespace enum_descriptor
+
+namespace oneof_descriptor {
+
+typedef const OneofDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace fields {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->field_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->field(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFieldDescriptor_FromDescriptor(item);
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index_in_oneof();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "OneofFields",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace fields
+
+PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&fields::ContainerDef, descriptor);
+}
+
+}  // namespace oneof_descriptor
+
+namespace file_descriptor {
+
+typedef const FileDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace messages {
+
+typedef const Descriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->message_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindMessageTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->message_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyMessageDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FileMessages",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace messages
+
+PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) {
+  return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
+}
+
+namespace enums {
+
+typedef const EnumDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->enum_type_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindEnumTypeByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->enum_type(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyEnumDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FileEnums",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace enums
+
+PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) {
+  return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
+}
+
+namespace extensions {
+
+typedef const FieldDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->extension_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindExtensionByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->extension(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFieldDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FileExtensions",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace extensions
+
+PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) {
+  return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
+}
+
+namespace dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->dependency_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->dependency(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFileDescriptor_FromDescriptor(item);
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FileDependencies",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)NULL,
+};
+
+}  // namespace dependencies
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor) {
+  return descriptor::NewSequence(&dependencies::ContainerDef, descriptor);
+}
+
+namespace public_dependencies {
+
+typedef const FileDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->public_dependency_count();
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->public_dependency(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyFileDescriptor_FromDescriptor(item);
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FilePublicDependencies",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)NULL,
+};
+
+}  // namespace public_dependencies
+
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) {
+  return descriptor::NewSequence(&public_dependencies::ContainerDef,
+                                 descriptor);
+}
+
+}  // namespace file_descriptor
+
+
+// Register all implementations
+
+bool InitDescriptorMappingTypes() {
+  if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0)
+    return false;
+  if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0)
+    return false;
+  if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0)
+    return false;
+  return true;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
new file mode 100644
index 0000000..ce40747
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -0,0 +1,101 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
+
+// Mappings and Sequences of descriptors.
+// They implement containers like fields_by_name, EnumDescriptor.values...
+// See descriptor_containers.cc for more description.
+#include <Python.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class FileDescriptor;
+class EnumDescriptor;
+class OneofDescriptor;
+
+namespace python {
+
+// Initialize the various types and objects.
+bool InitDescriptorMappingTypes();
+
+// Each function below returns a Mapping, or a Sequence of descriptors.
+// They all return a new reference.
+
+namespace message_descriptor {
+PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
+PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageNestedTypesSeq(const Descriptor* descriptor);
+PyObject* NewMessageNestedTypesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageEnumsByName(const Descriptor* descriptor);
+PyObject* NewMessageEnumsSeq(const Descriptor* descriptor);
+PyObject* NewMessageEnumValuesByName(const Descriptor* descriptor);
+
+PyObject* NewMessageExtensionsByName(const Descriptor* descriptor);
+PyObject* NewMessageExtensionsSeq(const Descriptor* descriptor);
+
+PyObject* NewMessageOneofsByName(const Descriptor* descriptor);
+PyObject* NewMessageOneofsSeq(const Descriptor* descriptor);
+}  // namespace message_descriptor
+
+namespace enum_descriptor {
+PyObject* NewEnumValuesByName(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesByNumber(const EnumDescriptor* descriptor);
+PyObject* NewEnumValuesSeq(const EnumDescriptor* descriptor);
+}  // namespace enum_descriptor
+
+namespace oneof_descriptor {
+PyObject* NewOneofFieldsSeq(const OneofDescriptor* descriptor);
+}  // namespace oneof_descriptor
+
+namespace file_descriptor {
+PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor);
+
+PyObject* NewFileDependencies(const FileDescriptor* descriptor);
+PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor);
+}  // namespace file_descriptor
+
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
diff --git a/python/google/protobuf/pyext/descriptor_cpp2_test.py b/python/google/protobuf/pyext/descriptor_cpp2_test.py
deleted file mode 100644
index 3cf45a2..0000000
--- a/python/google/protobuf/pyext/descriptor_cpp2_test.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#! /usr/bin/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.
-
-"""Tests for google.protobuf.pyext behavior."""
-
-__author__ = 'anuraag@google.com (Anuraag Agrawal)'
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION'] = '2'
-
-# We must set the implementation version above before the google3 imports.
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-# Run all tests from the original module by putting them in our namespace.
-# pylint: disable=wildcard-import
-from google.protobuf.internal.descriptor_test import *
-
-
-class ConfirmCppApi2Test(basetest.TestCase):
-
-  def testImplementationSetting(self):
-    self.assertEqual('cpp', api_implementation.Type())
-    self.assertEqual(2, api_implementation.Version())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc
new file mode 100644
index 0000000..daa40cc
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.cc
@@ -0,0 +1,148 @@
+// 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.
+
+// This file defines a C++ DescriptorDatabase, which wraps a Python Database
+// and delegate all its operations to Python methods.
+
+#include <google/protobuf/pyext/descriptor_database.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+PyDescriptorDatabase::PyDescriptorDatabase(PyObject* py_database)
+    : py_database_(py_database) {
+  Py_INCREF(py_database_);
+}
+
+PyDescriptorDatabase::~PyDescriptorDatabase() { Py_DECREF(py_database_); }
+
+// Convert a Python object to a FileDescriptorProto pointer.
+// Handles all kinds of Python errors, which are simply logged.
+static bool GetFileDescriptorProto(PyObject* py_descriptor,
+                                   FileDescriptorProto* output) {
+  if (py_descriptor == NULL) {
+    if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+      // Expected error: item was simply not found.
+      PyErr_Clear();
+    } else {
+      GOOGLE_LOG(ERROR) << "DescriptorDatabase method raised an error";
+      PyErr_Print();
+    }
+    return false;
+  }
+  if (py_descriptor == Py_None) {
+    return false;
+  }
+  const Descriptor* filedescriptor_descriptor =
+      FileDescriptorProto::default_instance().GetDescriptor();
+  CMessage* message = reinterpret_cast<CMessage*>(py_descriptor);
+  if (PyObject_TypeCheck(py_descriptor, &CMessage_Type) &&
+      message->message->GetDescriptor() == filedescriptor_descriptor) {
+    // Fast path: Just use the pointer.
+    FileDescriptorProto* file_proto =
+        static_cast<FileDescriptorProto*>(message->message);
+    *output = *file_proto;
+    return true;
+  } else {
+    // Slow path: serialize the message. This allows to use databases which
+    // use a different implementation of FileDescriptorProto.
+    ScopedPyObjectPtr serialized_pb(
+        PyObject_CallMethod(py_descriptor, "SerializeToString", NULL));
+    if (serialized_pb == NULL) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      PyErr_Print();
+      return false;
+    }
+    char* str;
+    Py_ssize_t len;
+    if (PyBytes_AsStringAndSize(serialized_pb.get(), &str, &len) < 0) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      PyErr_Print();
+      return false;
+    }
+    FileDescriptorProto file_proto;
+    if (!file_proto.ParseFromArray(str, len)) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      return false;
+    }
+    *output = file_proto;
+    return true;
+  }
+}
+
+// Find a file by file name.
+bool PyDescriptorDatabase::FindFileByName(const string& filename,
+                                          FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_descriptor(PyObject_CallMethod(
+      py_database_, "FindFileByName", "s#", filename.c_str(), filename.size()));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+// Find the file that declares the given fully-qualified symbol name.
+bool PyDescriptorDatabase::FindFileContainingSymbol(
+    const string& symbol_name, FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_descriptor(
+      PyObject_CallMethod(py_database_, "FindFileContainingSymbol", "s#",
+                          symbol_name.c_str(), symbol_name.size()));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+// Find the file which defines an extension extending the given message type
+// with the given field number.
+// Python DescriptorDatabases are not required to implement this method.
+bool PyDescriptorDatabase::FindFileContainingExtension(
+    const string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_method(
+      PyObject_GetAttrString(py_database_, "FindFileContainingExtension"));
+  if (py_method == NULL) {
+    // This method is not implemented, returns without error.
+    PyErr_Clear();
+    return false;
+  }
+  ScopedPyObjectPtr py_descriptor(
+      PyObject_CallFunction(py_method.get(), "s#i", containing_type.c_str(),
+                            containing_type.size(), field_number));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_database.h b/python/google/protobuf/pyext/descriptor_database.h
new file mode 100644
index 0000000..fc71c4b
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor_database.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+class PyDescriptorDatabase : public DescriptorDatabase {
+ public:
+  explicit PyDescriptorDatabase(PyObject* py_database);
+  ~PyDescriptorDatabase();
+
+  // Implement the abstract interface. All these functions fill the output
+  // with a copy of FileDescriptorProto.
+
+  // Find a file by file name.
+  bool FindFileByName(const string& filename,
+                      FileDescriptorProto* output);
+
+  // Find the file that declares the given fully-qualified symbol name.
+  bool FindFileContainingSymbol(const string& symbol_name,
+                                FileDescriptorProto* output);
+
+  // Find the file which defines an extension extending the given message type
+  // with the given field number.
+  // Containing_type must be a fully-qualified type name.
+  // Python objects are not required to implement this method.
+  bool FindFileContainingExtension(const string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output);
+
+ private:
+  // The python object that implements the database. The reference is owned.
+  PyObject* py_database_;
+};
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
new file mode 100644
index 0000000..1faff96
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -0,0 +1,593 @@
+// 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.
+
+// Implements the DescriptorPool, which collects all descriptors.
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_database.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
+  #if PY_VERSION_HEX < 0x03030000
+    #error "Python 3.0 - 3.2 are not supported."
+  #endif
+  #define PyString_AsStringAndSize(ob, charpp, sizep) \
+    (PyUnicode_Check(ob)? \
+       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// A map to cache Python Pools per C++ pointer.
+// Pointers are not owned here, and belong to the PyDescriptorPool.
+static hash_map<const DescriptorPool*, PyDescriptorPool*> descriptor_pool_map;
+
+namespace cdescriptor_pool {
+
+// Create a Python DescriptorPool object, but does not fill the "pool"
+// attribute.
+static PyDescriptorPool* _CreateDescriptorPool() {
+  PyDescriptorPool* cpool = PyObject_New(
+      PyDescriptorPool, &PyDescriptorPool_Type);
+  if (cpool == NULL) {
+    return NULL;
+  }
+
+  cpool->underlay = NULL;
+  cpool->database = NULL;
+
+  DynamicMessageFactory* message_factory = new DynamicMessageFactory();
+  // This option might be the default some day.
+  message_factory->SetDelegateToGeneratedFactory(true);
+  cpool->message_factory = message_factory;
+
+  // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same
+  // storage.
+  cpool->classes_by_descriptor =
+      new PyDescriptorPool::ClassesByMessageMap();
+  cpool->descriptor_options =
+      new hash_map<const void*, PyObject *>();
+
+  return cpool;
+}
+
+// Create a Python DescriptorPool, using the given pool as an underlay:
+// new messages will be added to a custom pool, not to the underlay.
+//
+// Ownership of the underlay is not transferred, its pointer should
+// stay alive.
+static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay(
+    const DescriptorPool* underlay) {
+  PyDescriptorPool* cpool = _CreateDescriptorPool();
+  if (cpool == NULL) {
+    return NULL;
+  }
+  cpool->pool = new DescriptorPool(underlay);
+  cpool->underlay = underlay;
+
+  if (!descriptor_pool_map.insert(
+      std::make_pair(cpool->pool, cpool)).second) {
+    // Should never happen -- would indicate an internal error / bug.
+    PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
+    return NULL;
+  }
+
+  return cpool;
+}
+
+static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
+    DescriptorDatabase* database) {
+  PyDescriptorPool* cpool = _CreateDescriptorPool();
+  if (cpool == NULL) {
+    return NULL;
+  }
+  if (database != NULL) {
+    cpool->pool = new DescriptorPool(database);
+    cpool->database = database;
+  } else {
+    cpool->pool = new DescriptorPool();
+  }
+
+  if (!descriptor_pool_map.insert(std::make_pair(cpool->pool, cpool)).second) {
+    // Should never happen -- would indicate an internal error / bug.
+    PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
+    return NULL;
+  }
+
+  return cpool;
+}
+
+// The public DescriptorPool constructor.
+static PyObject* New(PyTypeObject* type,
+                     PyObject* args, PyObject* kwargs) {
+  static char* kwlist[] = {"descriptor_db", 0};
+  PyObject* py_database = NULL;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &py_database)) {
+    return NULL;
+  }
+  DescriptorDatabase* database = NULL;
+  if (py_database && py_database != Py_None) {
+    database = new PyDescriptorDatabase(py_database);
+  }
+  return reinterpret_cast<PyObject*>(
+      PyDescriptorPool_NewWithDatabase(database));
+}
+
+static void Dealloc(PyDescriptorPool* self) {
+  typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+  descriptor_pool_map.erase(self->pool);
+  for (iterator it = self->classes_by_descriptor->begin();
+       it != self->classes_by_descriptor->end(); ++it) {
+    Py_DECREF(it->second);
+  }
+  delete self->classes_by_descriptor;
+  for (hash_map<const void*, PyObject*>::iterator it =
+           self->descriptor_options->begin();
+       it != self->descriptor_options->end(); ++it) {
+    Py_DECREF(it->second);
+  }
+  delete self->descriptor_options;
+  delete self->message_factory;
+  delete self->database;
+  delete self->pool;
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const Descriptor* message_descriptor =
+      self->pool->FindMessageTypeByName(string(name, name_size));
+
+  if (message_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
+    return NULL;
+  }
+
+  return PyMessageDescriptor_FromDescriptor(message_descriptor);
+}
+
+// Add a message class to our database.
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor* message_descriptor,
+                         CMessageClass* message_class) {
+  Py_INCREF(message_class);
+  typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+  std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
+      std::make_pair(message_descriptor, message_class));
+  if (!ret.second) {
+    // Update case: DECREF the previous value.
+    Py_DECREF(ret.first->second);
+    ret.first->second = message_class;
+  }
+  return 0;
+}
+
+// Retrieve the message class added to our database.
+CMessageClass* GetMessageClass(PyDescriptorPool* self,
+                               const Descriptor* message_descriptor) {
+  typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
+  iterator ret = self->classes_by_descriptor->find(message_descriptor);
+  if (ret == self->classes_by_descriptor->end()) {
+    PyErr_Format(PyExc_TypeError, "No message class registered for '%s'",
+                 message_descriptor->full_name().c_str());
+    return NULL;
+  } else {
+    return ret->second;
+  }
+}
+
+PyObject* FindFileByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FileDescriptor* file_descriptor =
+      self->pool->FindFileByName(string(name, name_size));
+  if (file_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s",
+                 name);
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FieldDescriptor* field_descriptor =
+      self->pool->FindFieldByName(string(name, name_size));
+  if (field_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s",
+                 name);
+    return NULL;
+  }
+
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
+}
+
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FieldDescriptor* field_descriptor =
+      self->pool->FindExtensionByName(string(name, name_size));
+  if (field_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name);
+    return NULL;
+  }
+
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
+}
+
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const EnumDescriptor* enum_descriptor =
+      self->pool->FindEnumTypeByName(string(name, name_size));
+  if (enum_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
+    return NULL;
+  }
+
+  return PyEnumDescriptor_FromDescriptor(enum_descriptor);
+}
+
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const OneofDescriptor* oneof_descriptor =
+      self->pool->FindOneofByName(string(name, name_size));
+  if (oneof_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
+    return NULL;
+  }
+
+  return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
+}
+
+PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FileDescriptor* file_descriptor =
+      self->pool->FindFileContainingSymbol(string(name, name_size));
+  if (file_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+// These functions should not exist -- the only valid way to create
+// descriptors is to call Add() or AddSerializedFile().
+// But these AddDescriptor() functions were created in Python and some people
+// call them, so we support them for now for compatibility.
+// However we do check that the existing descriptor already exists in the pool,
+// which appears to always be true for existing calls -- but then why do people
+// call a function that will just be a no-op?
+// TODO(amauryfa): Need to investigate further.
+
+PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const FileDescriptor* file_descriptor =
+      PyFileDescriptor_AsDescriptor(descriptor);
+  if (!file_descriptor) {
+    return NULL;
+  }
+  if (file_descriptor !=
+      self->pool->FindFileByName(file_descriptor->name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The file descriptor %s does not belong to this pool",
+                 file_descriptor->name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(descriptor);
+  if (!message_descriptor) {
+    return NULL;
+  }
+  if (message_descriptor !=
+      self->pool->FindMessageTypeByName(message_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The message descriptor %s does not belong to this pool",
+                 message_descriptor->full_name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const EnumDescriptor* enum_descriptor =
+      PyEnumDescriptor_AsDescriptor(descriptor);
+  if (!enum_descriptor) {
+    return NULL;
+  }
+  if (enum_descriptor !=
+      self->pool->FindEnumTypeByName(enum_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The enum descriptor %s does not belong to this pool",
+                 enum_descriptor->full_name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+// The code below loads new Descriptors from a serialized FileDescriptorProto.
+
+
+// Collects errors that occur during proto file building to allow them to be
+// propagated in the python exception instead of only living in ERROR logs.
+class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  BuildFileErrorCollector() : error_message(""), had_errors(false) {}
+
+  void AddError(const string& filename, const string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const string& message) {
+    // Replicates the logging behavior that happens in the C++ implementation
+    // when an error collector is not passed in.
+    if (!had_errors) {
+      error_message +=
+          ("Invalid proto descriptor for file \"" + filename + "\":\n");
+      had_errors = true;
+    }
+    // As this only happens on failure and will result in the program not
+    // running at all, no effort is made to optimize this string manipulation.
+    error_message += ("  " + element_name + ": " + message + "\n");
+  }
+
+  string error_message;
+  bool had_errors;
+};
+
+PyObject* AddSerializedFile(PyDescriptorPool* self, PyObject* serialized_pb) {
+  char* message_type;
+  Py_ssize_t message_len;
+
+  if (self->database != NULL) {
+    PyErr_SetString(
+        PyExc_ValueError,
+        "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
+        "Add your file to the underlying database.");
+    return NULL;
+  }
+
+  if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
+    return NULL;
+  }
+
+  FileDescriptorProto file_proto;
+  if (!file_proto.ParseFromArray(message_type, message_len)) {
+    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
+    return NULL;
+  }
+
+  // If the file was already part of a C++ library, all its descriptors are in
+  // the underlying pool.  No need to do anything else.
+  const FileDescriptor* generated_file = NULL;
+  if (self->underlay) {
+    generated_file = self->underlay->FindFileByName(file_proto.name());
+  }
+  if (generated_file != NULL) {
+    return PyFileDescriptor_FromDescriptorWithSerializedPb(
+        generated_file, serialized_pb);
+  }
+
+  BuildFileErrorCollector error_collector;
+  const FileDescriptor* descriptor =
+      self->pool->BuildFileCollectingErrors(file_proto,
+                                            &error_collector);
+  if (descriptor == NULL) {
+    PyErr_Format(PyExc_TypeError,
+                 "Couldn't build proto file into descriptor pool!\n%s",
+                 error_collector.error_message.c_str());
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(
+      descriptor, serialized_pb);
+}
+
+PyObject* Add(PyDescriptorPool* self, PyObject* file_descriptor_proto) {
+  ScopedPyObjectPtr serialized_pb(
+      PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL));
+  if (serialized_pb == NULL) {
+    return NULL;
+  }
+  return AddSerializedFile(self, serialized_pb.get());
+}
+
+static PyMethodDef Methods[] = {
+  { "Add", (PyCFunction)Add, METH_O,
+    "Adds the FileDescriptorProto and its types to this pool." },
+  { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O,
+    "Adds a serialized FileDescriptorProto to this pool." },
+
+  // TODO(amauryfa): Understand why the Python implementation differs from
+  // this one, ask users to use another API and deprecate these functions.
+  { "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+  { "AddDescriptor", (PyCFunction)AddDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+  { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+
+  { "FindFileByName", (PyCFunction)FindFileByName, METH_O,
+    "Searches for a file descriptor by its .proto name." },
+  { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O,
+    "Searches for a message descriptor by full name." },
+  { "FindFieldByName", (PyCFunction)FindFieldByName, METH_O,
+    "Searches for a field descriptor by full name." },
+  { "FindExtensionByName", (PyCFunction)FindExtensionByName, METH_O,
+    "Searches for extension descriptor by full name." },
+  { "FindEnumTypeByName", (PyCFunction)FindEnumTypeByName, METH_O,
+    "Searches for enum type descriptor by full name." },
+  { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
+    "Searches for oneof descriptor by full name." },
+
+  { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
+    "Gets the FileDescriptor containing the specified symbol." },
+  {NULL}
+};
+
+}  // namespace cdescriptor_pool
+
+PyTypeObject PyDescriptorPool_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".DescriptorPool",  // tp_name
+  sizeof(PyDescriptorPool),            // tp_basicsize
+  0,                                   // tp_itemsize
+  (destructor)cdescriptor_pool::Dealloc,  // tp_dealloc
+  0,                                   // tp_print
+  0,                                   // tp_getattr
+  0,                                   // tp_setattr
+  0,                                   // tp_compare
+  0,                                   // tp_repr
+  0,                                   // tp_as_number
+  0,                                   // tp_as_sequence
+  0,                                   // tp_as_mapping
+  0,                                   // tp_hash
+  0,                                   // tp_call
+  0,                                   // tp_str
+  0,                                   // tp_getattro
+  0,                                   // tp_setattro
+  0,                                   // tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  // tp_flags
+  "A Descriptor Pool",                 // tp_doc
+  0,                                   // tp_traverse
+  0,                                   // tp_clear
+  0,                                   // tp_richcompare
+  0,                                   // tp_weaklistoffset
+  0,                                   // tp_iter
+  0,                                   // tp_iternext
+  cdescriptor_pool::Methods,           // tp_methods
+  0,                                   // tp_members
+  0,                                   // tp_getset
+  0,                                   // tp_base
+  0,                                   // tp_dict
+  0,                                   // tp_descr_get
+  0,                                   // tp_descr_set
+  0,                                   // tp_dictoffset
+  0,                                   // tp_init
+  0,                                   // tp_alloc
+  cdescriptor_pool::New,               // tp_new
+  PyObject_Del,                        // tp_free
+};
+
+// This is the DescriptorPool which contains all the definitions from the
+// generated _pb2.py modules.
+static PyDescriptorPool* python_generated_pool = NULL;
+
+bool InitDescriptorPool() {
+  if (PyType_Ready(&PyDescriptorPool_Type) < 0)
+    return false;
+
+  // The Pool of messages declared in Python libraries.
+  // generated_pool() contains all messages already linked in C++ libraries, and
+  // is used as underlay.
+  python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
+      DescriptorPool::generated_pool());
+  if (python_generated_pool == NULL) {
+    return false;
+  }
+  // Register this pool to be found for C++-generated descriptors.
+  descriptor_pool_map.insert(
+      std::make_pair(DescriptorPool::generated_pool(),
+                     python_generated_pool));
+
+  return true;
+}
+
+// The default DescriptorPool used everywhere in this module.
+// Today it's the python_generated_pool.
+// TODO(amauryfa): Remove all usages of this function: the pool should be
+// derived from the context.
+PyDescriptorPool* GetDefaultDescriptorPool() {
+  return python_generated_pool;
+}
+
+PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
+  // Fast path for standard descriptors.
+  if (pool == python_generated_pool->pool ||
+      pool == DescriptorPool::generated_pool()) {
+    return python_generated_pool;
+  }
+  hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it =
+      descriptor_pool_map.find(pool);
+  if (it == descriptor_pool_map.end()) {
+    PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
+    return NULL;
+  }
+  return it->second;
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
new file mode 100644
index 0000000..2a42c11
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -0,0 +1,167 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
+
+#include <Python.h>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+class MessageFactory;
+
+namespace python {
+
+// The (meta) type of all Messages classes.
+struct CMessageClass;
+
+// Wraps operations to the global DescriptorPool which contains information
+// about all messages and fields.
+//
+// There is normally one pool per process. We make it a Python object only
+// because it contains many Python references.
+// TODO(amauryfa): See whether such objects can appear in reference cycles, and
+// consider adding support for the cyclic GC.
+//
+// "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool
+// namespace.
+typedef struct PyDescriptorPool {
+  PyObject_HEAD
+
+  // The C++ pool containing Descriptors.
+  DescriptorPool* pool;
+
+  // The C++ pool acting as an underlay. Can be NULL.
+  // This pointer is not owned and must stay alive.
+  const DescriptorPool* underlay;
+
+  // The C++ descriptor database used to fetch unknown protos. Can be NULL.
+  // This pointer is owned.
+  const DescriptorDatabase* database;
+
+  // DynamicMessageFactory used to create C++ instances of messages.
+  // This object cache the descriptors that were used, so the DescriptorPool
+  // needs to get rid of it before it can delete itself.
+  //
+  // Note: A C++ MessageFactory is different from the Python MessageFactory.
+  // The C++ one creates messages, when the Python one creates classes.
+  MessageFactory* message_factory;
+
+  // Make our own mapping to retrieve Python classes from C++ descriptors.
+  //
+  // Descriptor pointers stored here are owned by the DescriptorPool above.
+  // Python references to classes are owned by this PyDescriptorPool.
+  typedef hash_map<const Descriptor*, CMessageClass*> ClassesByMessageMap;
+  ClassesByMessageMap* classes_by_descriptor;
+
+  // Cache the options for any kind of descriptor.
+  // Descriptor pointers are owned by the DescriptorPool above.
+  // Python objects are owned by the map.
+  hash_map<const void*, PyObject*>* descriptor_options;
+} PyDescriptorPool;
+
+
+extern PyTypeObject PyDescriptorPool_Type;
+
+namespace cdescriptor_pool {
+
+// Looks up a message by name.
+// Returns a message Descriptor, or NULL if not found.
+const Descriptor* FindMessageTypeByName(PyDescriptorPool* self,
+                                        const string& name);
+
+// Registers a new Python class for the given message descriptor.
+// On error, returns -1 with a Python exception set.
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor* message_descriptor,
+                         CMessageClass* message_class);
+
+// Retrieves the Python class registered with the given message descriptor.
+//
+// Returns a *borrowed* reference if found, otherwise returns NULL with an
+// exception set.
+CMessageClass* GetMessageClass(PyDescriptorPool* self,
+                               const Descriptor* message_descriptor);
+
+// The functions below are also exposed as methods of the DescriptorPool type.
+
+// Looks up a message by name. Returns a PyMessageDescriptor corresponding to
+// the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* name);
+
+// Looks up a field by name. Returns a PyFieldDescriptor corresponding to
+// the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* name);
+
+// Looks up an extension by name. Returns a PyFieldDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up an enum type by name. Returns a PyEnumDescriptor corresponding
+// to the field on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg);
+
+// Looks up a oneof by name. Returns a COneofDescriptor corresponding
+// to the oneof on success, or NULL on failure.
+//
+// Returns a new reference.
+PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg);
+
+}  // namespace cdescriptor_pool
+
+// Retrieve the global descriptor pool owned by the _message module.
+// This is the one used by pb2.py generated modules.
+// Returns a *borrowed* reference.
+// "Default" pool used to register messages from _pb2.py modules.
+PyDescriptorPool* GetDefaultDescriptorPool();
+
+// Retrieve the python descriptor pool owning a C++ descriptor pool.
+// Returns a *borrowed* reference.
+PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool);
+
+// Initialize objects used by this module.
+bool InitDescriptorPool();
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index 3861c79..21bbb8c 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -33,11 +33,13 @@
 
 #include <google/protobuf/pyext/extension_dict.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/repeated_composite_container.h>
 #include <google/protobuf/pyext/repeated_scalar_container.h>
@@ -48,36 +50,8 @@
 namespace protobuf {
 namespace python {
 
-extern google::protobuf::DynamicMessageFactory* global_message_factory;
-
 namespace extension_dict {
 
-// TODO(tibell): Always use self->message for clarity, just like in
-// RepeatedCompositeContainer.
-static google::protobuf::Message* GetMessage(ExtensionDict* self) {
-  if (self->parent != NULL) {
-    return self->parent->message;
-  } else {
-    return self->message;
-  }
-}
-
-CFieldDescriptor* InternalGetCDescriptorFromExtension(PyObject* extension) {
-  PyObject* cdescriptor = PyObject_GetAttrString(extension, "_cdescriptor");
-  if (cdescriptor == NULL) {
-    PyErr_SetString(PyExc_KeyError, "Unregistered extension.");
-    return NULL;
-  }
-  if (!PyObject_TypeCheck(cdescriptor, &CFieldDescriptor_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Not a CFieldDescriptor");
-    Py_DECREF(cdescriptor);
-    return NULL;
-  }
-  CFieldDescriptor* descriptor =
-      reinterpret_cast<CFieldDescriptor*>(cdescriptor);
-  return descriptor;
-}
-
 PyObject* len(ExtensionDict* self) {
 #if PY_MAJOR_VERSION >= 3
   return PyLong_FromLong(PyDict_Size(self->values));
@@ -89,10 +63,9 @@
 // TODO(tibell): Use VisitCompositeField.
 int ReleaseExtension(ExtensionDict* self,
                      PyObject* extension,
-                     const google::protobuf::FieldDescriptor* descriptor) {
-  if (descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
-    if (descriptor->cpp_type() ==
-        google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+                     const FieldDescriptor* descriptor) {
+  if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       if (repeated_composite_container::Release(
               reinterpret_cast<RepeatedCompositeContainer*>(
                   extension)) < 0) {
@@ -105,10 +78,9 @@
         return -1;
       }
     }
-  } else if (descriptor->cpp_type() ==
-             google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+  } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     if (cmessage::ReleaseSubMessage(
-            GetMessage(self), descriptor,
+            self->parent, descriptor,
             reinterpret_cast<CMessage*>(extension)) < 0) {
       return -1;
     }
@@ -118,19 +90,17 @@
 }
 
 PyObject* subscript(ExtensionDict* self, PyObject* key) {
-  CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension(
-      key);
-  if (cdescriptor == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor));
-  const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor;
+  const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
   if (descriptor == NULL) {
     return NULL;
   }
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
+    return NULL;
+  }
+
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
-    return cmessage::InternalGetScalar(self->parent, descriptor);
+    return cmessage::InternalGetScalar(self->message, descriptor);
   }
 
   PyObject* value = PyDict_GetItem(self->values, key);
@@ -139,10 +109,18 @@
     return value;
   }
 
+  if (self->parent == NULL) {
+    // We are in "detached" state. Don't allow further modifications.
+    // TODO(amauryfa): Support adding non-scalars to a detached extension dict.
+    // This probably requires to store the type of the main message.
+    PyErr_SetObject(PyExc_KeyError, key);
+    return NULL;
+  }
+
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     PyObject* sub_message = cmessage::InternalGetSubMessage(
-        self->parent, cdescriptor);
+        self->parent, descriptor);
     if (sub_message == NULL) {
       return NULL;
     }
@@ -152,33 +130,22 @@
 
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      // COPIED
-      PyObject* py_container = PyObject_CallObject(
-          reinterpret_cast<PyObject*>(&RepeatedCompositeContainer_Type),
-          NULL);
+      CMessageClass* message_class = cdescriptor_pool::GetMessageClass(
+          cmessage::GetDescriptorPoolForMessage(self->parent),
+          descriptor->message_type());
+      if (message_class == NULL) {
+        return NULL;
+      }
+      PyObject* py_container = repeated_composite_container::NewContainer(
+          self->parent, descriptor, message_class);
       if (py_container == NULL) {
         return NULL;
       }
-      RepeatedCompositeContainer* container =
-          reinterpret_cast<RepeatedCompositeContainer*>(py_container);
-      PyObject* field = cdescriptor->descriptor_field;
-      PyObject* message_type = PyObject_GetAttrString(field, "message_type");
-      PyObject* concrete_class = PyObject_GetAttrString(message_type,
-                                                        "_concrete_class");
-      container->owner = self->owner;
-      container->parent = self->parent;
-      container->message = self->parent->message;
-      container->parent_field = cdescriptor;
-      container->subclass_init = concrete_class;
-      Py_DECREF(message_type);
       PyDict_SetItem(self->values, key, py_container);
       return py_container;
     } else {
-      // COPIED
-      ScopedPyObjectPtr init_args(PyTuple_Pack(2, self->parent, cdescriptor));
-      PyObject* py_container = PyObject_CallObject(
-          reinterpret_cast<PyObject*>(&RepeatedScalarContainer_Type),
-          init_args);
+      PyObject* py_container = repeated_scalar_container::NewContainer(
+          self->parent, descriptor);
       if (py_container == NULL) {
         return NULL;
       }
@@ -191,22 +158,25 @@
 }
 
 int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
-  CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension(
-      key);
-  if (cdescriptor == NULL) {
+  const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+  if (descriptor == NULL) {
     return -1;
   }
-  ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor));
-  const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor;
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
+    return -1;
+  }
+
   if (descriptor->label() != FieldDescriptor::LABEL_OPTIONAL ||
       descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     PyErr_SetString(PyExc_TypeError, "Extension is repeated and/or composite "
                     "type");
     return -1;
   }
-  cmessage::AssureWritable(self->parent);
-  if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
-    return -1;
+  if (self->parent) {
+    cmessage::AssureWritable(self->parent);
+    if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
+      return -1;
+    }
   }
   // TODO(tibell): We shouldn't write scalars to the cache.
   PyDict_SetItem(self->values, key, value);
@@ -214,22 +184,23 @@
 }
 
 PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) {
-  CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension(
-      extension);
-  if (cdescriptor == NULL) {
+  const FieldDescriptor* descriptor =
+      cmessage::GetExtensionDescriptor(extension);
+  if (descriptor == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor));
   PyObject* value = PyDict_GetItem(self->values, extension);
-  if (value != NULL) {
-    if (ReleaseExtension(self, value, cdescriptor->descriptor) < 0) {
+  if (self->parent) {
+    if (value != NULL) {
+      if (ReleaseExtension(self, value, descriptor) < 0) {
+        return NULL;
+      }
+    }
+    if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor(
+            self->parent, descriptor)) == NULL) {
       return NULL;
     }
   }
-  if (cmessage::ClearFieldByDescriptor(self->parent,
-                                       cdescriptor->descriptor) == NULL) {
-    return NULL;
-  }
   if (PyDict_DelItem(self->values, extension) < 0) {
     PyErr_Clear();
   }
@@ -237,15 +208,20 @@
 }
 
 PyObject* HasExtension(ExtensionDict* self, PyObject* extension) {
-  CFieldDescriptor* cdescriptor = InternalGetCDescriptorFromExtension(
-      extension);
-  if (cdescriptor == NULL) {
+  const FieldDescriptor* descriptor =
+      cmessage::GetExtensionDescriptor(extension);
+  if (descriptor == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor));
-  PyObject* result = cmessage::HasFieldByDescriptor(
-      self->parent, cdescriptor->descriptor);
-  return result;
+  if (self->parent) {
+    return cmessage::HasFieldByDescriptor(self->parent, descriptor);
+  } else {
+    int exists = PyDict_Contains(self->values, extension);
+    if (exists < 0) {
+      return NULL;
+    }
+    return PyBool_FromLong(exists);
+  }
 }
 
 PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) {
@@ -254,7 +230,7 @@
   if (extensions_by_name == NULL) {
     return NULL;
   }
-  PyObject* result = PyDict_GetItem(extensions_by_name, name);
+  PyObject* result = PyDict_GetItem(extensions_by_name.get(), name);
   if (result == NULL) {
     Py_RETURN_NONE;
   } else {
@@ -263,11 +239,33 @@
   }
 }
 
-int init(ExtensionDict* self, PyObject* args, PyObject* kwargs) {
-  self->parent = NULL;
-  self->message = NULL;
+PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number) {
+  ScopedPyObjectPtr extensions_by_number(PyObject_GetAttrString(
+      reinterpret_cast<PyObject*>(self->parent), "_extensions_by_number"));
+  if (extensions_by_number == NULL) {
+    return NULL;
+  }
+  PyObject* result = PyDict_GetItem(extensions_by_number.get(), number);
+  if (result == NULL) {
+    Py_RETURN_NONE;
+  } else {
+    Py_INCREF(result);
+    return result;
+  }
+}
+
+ExtensionDict* NewExtensionDict(CMessage *parent) {
+  ExtensionDict* self = reinterpret_cast<ExtensionDict*>(
+      PyType_GenericAlloc(&ExtensionDict_Type, 0));
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->parent = parent;  // Store a borrowed reference.
+  self->message = parent->message;
+  self->owner = parent->owner;
   self->values = PyDict_New();
-  return 0;
+  return self;
 }
 
 void dealloc(ExtensionDict* self) {
@@ -288,6 +286,8 @@
   EDMETHOD(HasExtension, METH_O, "Checks if the object has an extension."),
   EDMETHOD(_FindExtensionByName, METH_O,
            "Finds an extension by name."),
+  EDMETHOD(_FindExtensionByNumber, METH_O,
+           "Finds an extension by field number."),
   { NULL, NULL }
 };
 
@@ -295,8 +295,7 @@
 
 PyTypeObject ExtensionDict_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-  "cpp._message.ExtensionDict",        // tp_name
+  FULL_MODULE_NAME ".ExtensionDict",   // tp_name
   sizeof(ExtensionDict),               // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)extension_dict::dealloc,  //  tp_dealloc
@@ -308,7 +307,7 @@
   0,                                   //  tp_as_number
   0,                                   //  tp_as_sequence
   &extension_dict::MpMethods,          //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_getattro
@@ -330,7 +329,7 @@
   0,                                   //  tp_descr_get
   0,                                   //  tp_descr_set
   0,                                   //  tp_dictoffset
-  (initproc)extension_dict::init,      //  tp_init
+  0,                                   //  tp_init
 };
 
 }  // namespace python
diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h
index 13c874a..2456eda 100644
--- a/python/google/protobuf/pyext/extension_dict.h
+++ b/python/google/protobuf/pyext/extension_dict.h
@@ -41,25 +41,41 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 
-
 namespace google {
 namespace protobuf {
 
 class Message;
 class FieldDescriptor;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
 struct CMessage;
-struct CFieldDescriptor;
 
 typedef struct ExtensionDict {
   PyObject_HEAD;
+
+  // This is the top-level C++ Message object that owns the whole
+  // proto tree.  Every Python container class holds a
+  // reference to it in order to keep it alive as long as there's a
+  // Python object that references any part of the tree.
   shared_ptr<Message> owner;
+
+  // Weak reference to parent message. Used to make sure
+  // the parent is writable when an extension field is modified.
   CMessage* parent;
+
+  // Pointer to the C++ Message that this ExtensionDict extends.
+  // Not owned by us.
   Message* message;
+
+  // A dict of child messages, indexed by Extension descriptors.
+  // Similar to CMessage::composite_fields.
   PyObject* values;
 } ExtensionDict;
 
@@ -67,11 +83,8 @@
 
 namespace extension_dict {
 
-// Gets the _cdescriptor reference to a CFieldDescriptor object given a
-// python descriptor object.
-//
-// Returns a new reference.
-CFieldDescriptor* InternalGetCDescriptorFromExtension(PyObject* extension);
+// Builds an Extensions dict for a specific message.
+ExtensionDict* NewExtensionDict(CMessage *parent);
 
 // Gets the number of extension values in this ExtensionDict as a python object.
 //
@@ -84,7 +97,7 @@
 // Returns 0 on success, -1 on failure.
 int ReleaseExtension(ExtensionDict* self,
                      PyObject* extension,
-                     const google::protobuf::FieldDescriptor* descriptor);
+                     const FieldDescriptor* descriptor);
 
 // Gets an extension from the dict for the given extension descriptor.
 //
@@ -104,17 +117,18 @@
 PyObject* ClearExtension(ExtensionDict* self,
                                        PyObject* extension);
 
-// Checks if the dict has an extension.
-//
-// Returns a new python boolean reference.
-PyObject* HasExtension(ExtensionDict* self, PyObject* extension);
-
 // Gets an extension from the dict given the extension name as opposed to
 // descriptor.
 //
 // Returns a new reference.
 PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name);
 
+// Gets an extension from the dict given the extension field number as
+// opposed to descriptor.
+//
+// Returns a new reference.
+PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number);
+
 }  // namespace extension_dict
 }  // namespace python
 }  // namespace protobuf
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
new file mode 100644
index 0000000..e022406
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -0,0 +1,970 @@
+// 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.
+
+// Author: haberman@google.com (Josh Haberman)
+
+#include <google/protobuf/pyext/map_container.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyInt_FromLong PyLong_FromLong
+  #define PyInt_FromSize_t PyLong_FromSize_t
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Functions that need access to map reflection functionality.
+// They need to be contained in this class because it is friended.
+class MapReflectionFriend {
+ public:
+  // Methods that are in common between the map types.
+  static PyObject* Contains(PyObject* _self, PyObject* key);
+  static Py_ssize_t Length(PyObject* _self);
+  static PyObject* GetIterator(PyObject *_self);
+  static PyObject* IterNext(PyObject* _self);
+
+  // Methods that differ between the map types.
+  static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
+  static PyObject* MessageMapGetItem(PyObject* _self, PyObject* key);
+  static int ScalarMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
+  static int MessageMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
+};
+
+struct MapIterator {
+  PyObject_HEAD;
+
+  google::protobuf::scoped_ptr< ::google::protobuf::MapIterator> iter;
+
+  // A pointer back to the container, so we can notice changes to the version.
+  // We own a ref on this.
+  MapContainer* container;
+
+  // We need to keep a ref on the Message* too, because
+  // MapIterator::~MapIterator() accesses it.  Normally this would be ok because
+  // the ref on container (above) would guarantee outlive semantics.  However in
+  // the case of ClearField(), InitializeAndCopyToParentContainer() resets the
+  // message pointer (and the owner) to a different message, a copy of the
+  // original.  But our iterator still points to the original, which could now
+  // get deleted before us.
+  //
+  // To prevent this, we ensure that the Message will always stay alive as long
+  // as this iterator does.  This is solely for the benefit of the MapIterator
+  // destructor -- we should never actually access the iterator in this state
+  // except to delete it.
+  shared_ptr<Message> owner;
+
+  // The version of the map when we took the iterator to it.
+  //
+  // We store this so that if the map is modified during iteration we can throw
+  // an error.
+  uint64 version;
+
+  // True if the container is empty.  We signal this separately to avoid calling
+  // any of the iteration methods, which are non-const.
+  bool empty;
+};
+
+Message* MapContainer::GetMutableMessage() {
+  cmessage::AssureWritable(parent);
+  return const_cast<Message*>(message);
+}
+
+// Consumes a reference on the Python string object.
+static bool PyStringToSTL(PyObject* py_string, string* stl_string) {
+  char *value;
+  Py_ssize_t value_len;
+
+  if (!py_string) {
+    return false;
+  }
+  if (PyBytes_AsStringAndSize(py_string, &value, &value_len) < 0) {
+    Py_DECREF(py_string);
+    return false;
+  } else {
+    stl_string->assign(value, value_len);
+    Py_DECREF(py_string);
+    return true;
+  }
+}
+
+static bool PythonToMapKey(PyObject* obj,
+                           const FieldDescriptor* field_descriptor,
+                           MapKey* key) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      key->SetInt32Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(obj, value, false);
+      key->SetInt64Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(obj, value, false);
+      key->SetUInt32Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(obj, value, false);
+      key->SetUInt64Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(obj, value, false);
+      key->SetBoolValue(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      string str;
+      if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
+        return false;
+      }
+      key->SetStringValue(str);
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Type %d cannot be a map key",
+          field_descriptor->cpp_type());
+      return false;
+  }
+  return true;
+}
+
+static PyObject* MapKeyToPython(const FieldDescriptor* field_descriptor,
+                                const MapKey& key) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyInt_FromLong(key.GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(key.GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyInt_FromSize_t(key.GetUInt32Value());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return PyLong_FromUnsignedLongLong(key.GetUInt64Value());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return PyBool_FromLong(key.GetBoolValue());
+    case FieldDescriptor::CPPTYPE_STRING:
+      return ToStringObject(field_descriptor, key.GetStringValue());
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Couldn't convert type %d to value",
+          field_descriptor->cpp_type());
+      return NULL;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+PyObject* MapValueRefToPython(const FieldDescriptor* field_descriptor,
+                              MapValueRef* value) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyInt_FromLong(value->GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(value->GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyInt_FromSize_t(value->GetUInt32Value());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return PyLong_FromUnsignedLongLong(value->GetUInt64Value());
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return PyFloat_FromDouble(value->GetFloatValue());
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return PyFloat_FromDouble(value->GetDoubleValue());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return PyBool_FromLong(value->GetBoolValue());
+    case FieldDescriptor::CPPTYPE_STRING:
+      return ToStringObject(field_descriptor, value->GetStringValue());
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return PyInt_FromLong(value->GetEnumValue());
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Couldn't convert type %d to value",
+          field_descriptor->cpp_type());
+      return NULL;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+static bool PythonToMapValueRef(PyObject* obj,
+                                const FieldDescriptor* field_descriptor,
+                                bool allow_unknown_enum_values,
+                                MapValueRef* value_ref) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      value_ref->SetInt32Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(obj, value, false);
+      value_ref->SetInt64Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(obj, value, false);
+      value_ref->SetUInt32Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(obj, value, false);
+      value_ref->SetUInt64Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      GOOGLE_CHECK_GET_FLOAT(obj, value, false);
+      value_ref->SetFloatValue(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      GOOGLE_CHECK_GET_DOUBLE(obj, value, false);
+      value_ref->SetDoubleValue(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(obj, value, false);
+      value_ref->SetBoolValue(value);
+      return true;;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      string str;
+      if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
+        return false;
+      }
+      value_ref->SetStringValue(str);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      if (allow_unknown_enum_values) {
+        value_ref->SetEnumValue(value);
+        return true;
+      } else {
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != NULL) {
+          value_ref->SetEnumValue(value);
+          return true;
+        } else {
+          PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
+          return false;
+        }
+      }
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Setting value to a field of unknown type %d",
+          field_descriptor->cpp_type());
+      return false;
+  }
+}
+
+// Map methods common to ScalarMap and MessageMap //////////////////////////////
+
+static MapContainer* GetMap(PyObject* obj) {
+  return reinterpret_cast<MapContainer*>(obj);
+}
+
+Py_ssize_t MapReflectionFriend::Length(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  const google::protobuf::Message* message = self->message;
+  return message->GetReflection()->MapSize(*message,
+                                           self->parent_field_descriptor);
+}
+
+PyObject* Clear(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, self->parent_field_descriptor);
+
+  Py_RETURN_NONE;
+}
+
+PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) {
+  MapContainer* self = GetMap(_self);
+
+  const Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
+                                 map_key)) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+// Initializes the underlying Message object of "to" so it becomes a new parent
+// repeated scalar, and copies all the values from "from" to it. A child scalar
+// container can be released by passing it as both from and to (e.g. making it
+// the recipient of the new parent message and copying the values from itself).
+static int InitializeAndCopyToParentContainer(MapContainer* from,
+                                              MapContainer* to) {
+  // For now we require from == to, re-evaluate if we want to support deep copy
+  // as in repeated_scalar_container.cc.
+  GOOGLE_DCHECK(from == to);
+  Message* new_message = from->message->New();
+
+  if (MapReflectionFriend::Length(reinterpret_cast<PyObject*>(from)) > 0) {
+    // A somewhat roundabout way of copying just one field from old_message to
+    // new_message.  This is the best we can do with what Reflection gives us.
+    Message* mutable_old = from->GetMutableMessage();
+    vector<const FieldDescriptor*> fields;
+    fields.push_back(from->parent_field_descriptor);
+
+    // Move the map field into the new message.
+    mutable_old->GetReflection()->SwapFields(mutable_old, new_message, fields);
+
+    // If/when we support from != to, this will be required also to copy the
+    // map field back into the existing message:
+    // mutable_old->MergeFrom(*new_message);
+  }
+
+  // If from == to this could delete old_message.
+  to->owner.reset(new_message);
+
+  to->parent = NULL;
+  to->parent_field_descriptor = from->parent_field_descriptor;
+  to->message = new_message;
+
+  // Invalidate iterators, since they point to the old copy of the field.
+  to->version++;
+
+  return 0;
+}
+
+int MapContainer::Release() {
+  return InitializeAndCopyToParentContainer(this, this);
+}
+
+
+// ScalarMap ///////////////////////////////////////////////////////////////////
+
+PyObject *NewScalarMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+#if PY_MAJOR_VERSION >= 3
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(
+        reinterpret_cast<PyTypeObject *>(ScalarMapContainer_Type), 0));
+#else
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0));
+#endif
+  if (obj.get() == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  MapContainer* self = GetMap(obj.get());
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj.release();
+}
+
+PyObject* MapReflectionFriend::ScalarMapGetItem(PyObject* _self,
+                                                PyObject* key) {
+  MapContainer* self = GetMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return MapValueRefToPython(self->value_field_descriptor, &value);
+}
+
+int MapReflectionFriend::ScalarMapSetItem(PyObject* _self, PyObject* key,
+                                          PyObject* v) {
+  MapContainer* self = GetMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return -1;
+  }
+
+  self->version++;
+
+  if (v) {
+    // Set item to v.
+    reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                       map_key, &value);
+
+    return PythonToMapValueRef(v, self->value_field_descriptor,
+                               reflection->SupportsUnknownEnumValues(), &value)
+               ? 0
+               : -1;
+  } else {
+    // Delete key from map.
+    if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
+                                   map_key)) {
+      return 0;
+    } else {
+      PyErr_Format(PyExc_KeyError, "Key not present in map");
+      return -1;
+    }
+  }
+}
+
+static PyObject* ScalarMapGet(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::ScalarMapGetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static void ScalarMapDealloc(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  self->owner.reset();
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef ScalarMapMethods[] = {
+  { "__contains__", MapReflectionFriend::Contains, METH_O,
+    "Tests whether a key is a member of the map." },
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map." },
+  { "get", ScalarMapGet, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+#if PY_MAJOR_VERSION >= 3
+  static PyType_Slot ScalarMapContainer_Type_slots[] = {
+      {Py_tp_dealloc, (void *)ScalarMapDealloc},
+      {Py_mp_length, (void *)MapReflectionFriend::Length},
+      {Py_mp_subscript, (void *)MapReflectionFriend::ScalarMapGetItem},
+      {Py_mp_ass_subscript, (void *)MapReflectionFriend::ScalarMapSetItem},
+      {Py_tp_methods, (void *)ScalarMapMethods},
+      {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
+      {0, 0},
+  };
+
+  PyType_Spec ScalarMapContainer_Type_spec = {
+      FULL_MODULE_NAME ".ScalarMapContainer",
+      sizeof(MapContainer),
+      0,
+      Py_TPFLAGS_DEFAULT,
+      ScalarMapContainer_Type_slots
+  };
+  PyObject *ScalarMapContainer_Type;
+#else
+  static PyMappingMethods ScalarMapMappingMethods = {
+    MapReflectionFriend::Length,             // mp_length
+    MapReflectionFriend::ScalarMapGetItem,   // mp_subscript
+    MapReflectionFriend::ScalarMapSetItem,   // mp_ass_subscript
+  };
+
+  PyTypeObject ScalarMapContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    FULL_MODULE_NAME ".ScalarMapContainer",  //  tp_name
+    sizeof(MapContainer),                //  tp_basicsize
+    0,                                   //  tp_itemsize
+    ScalarMapDealloc,                    //  tp_dealloc
+    0,                                   //  tp_print
+    0,                                   //  tp_getattr
+    0,                                   //  tp_setattr
+    0,                                   //  tp_compare
+    0,                                   //  tp_repr
+    0,                                   //  tp_as_number
+    0,                                   //  tp_as_sequence
+    &ScalarMapMappingMethods,            //  tp_as_mapping
+    0,                                   //  tp_hash
+    0,                                   //  tp_call
+    0,                                   //  tp_str
+    0,                                   //  tp_getattro
+    0,                                   //  tp_setattro
+    0,                                   //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  //  tp_flags
+    "A scalar map container",            //  tp_doc
+    0,                                   //  tp_traverse
+    0,                                   //  tp_clear
+    0,                                   //  tp_richcompare
+    0,                                   //  tp_weaklistoffset
+    MapReflectionFriend::GetIterator,    //  tp_iter
+    0,                                   //  tp_iternext
+    ScalarMapMethods,                    //  tp_methods
+    0,                                   //  tp_members
+    0,                                   //  tp_getset
+    0,                                   //  tp_base
+    0,                                   //  tp_dict
+    0,                                   //  tp_descr_get
+    0,                                   //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    0,                                   //  tp_init
+  };
+#endif
+
+
+// MessageMap //////////////////////////////////////////////////////////////////
+
+static MessageMapContainer* GetMessageMap(PyObject* obj) {
+  return reinterpret_cast<MessageMapContainer*>(obj);
+}
+
+static PyObject* GetCMessage(MessageMapContainer* self, Message* message) {
+  // Get or create the CMessage object corresponding to this message.
+  ScopedPyObjectPtr key(PyLong_FromVoidPtr(message));
+  PyObject* ret = PyDict_GetItem(self->message_dict, key.get());
+
+  if (ret == NULL) {
+    CMessage* cmsg = cmessage::NewEmptyMessage(self->message_class);
+    ret = reinterpret_cast<PyObject*>(cmsg);
+
+    if (cmsg == NULL) {
+      return NULL;
+    }
+    cmsg->owner = self->owner;
+    cmsg->message = message;
+    cmsg->parent = self->parent;
+
+    if (PyDict_SetItem(self->message_dict, key.get(), ret) < 0) {
+      Py_DECREF(ret);
+      return NULL;
+    }
+  } else {
+    Py_INCREF(ret);
+  }
+
+  return ret;
+}
+
+PyObject* NewMessageMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor,
+    CMessageClass* message_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+#if PY_MAJOR_VERSION >= 3
+  PyObject* obj = PyType_GenericAlloc(
+        reinterpret_cast<PyTypeObject *>(MessageMapContainer_Type), 0);
+#else
+  PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0);
+#endif
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  MessageMapContainer* self = GetMessageMap(obj);
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  self->message_dict = PyDict_New();
+  if (self->message_dict == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate message dict.");
+  }
+
+  Py_INCREF(message_class);
+  self->message_class = message_class;
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    Py_DECREF(obj);
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj;
+}
+
+int MapReflectionFriend::MessageMapSetItem(PyObject* _self, PyObject* key,
+                                           PyObject* v) {
+  if (v) {
+    PyErr_Format(PyExc_ValueError,
+                 "Direct assignment of submessage not allowed");
+    return -1;
+  }
+
+  // Now we know that this is a delete, not a set.
+
+  MessageMapContainer* self = GetMessageMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  self->version++;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return -1;
+  }
+
+  // Delete key from map.
+  if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
+                                 map_key)) {
+    return 0;
+  } else {
+    PyErr_Format(PyExc_KeyError, "Key not present in map");
+    return -1;
+  }
+}
+
+PyObject* MapReflectionFriend::MessageMapGetItem(PyObject* _self,
+                                                 PyObject* key) {
+  MessageMapContainer* self = GetMessageMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return GetCMessage(self, value.MutableMessageValue());
+}
+
+PyObject* MessageMapGet(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::MessageMapGetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static void MessageMapDealloc(PyObject* _self) {
+  MessageMapContainer* self = GetMessageMap(_self);
+  self->owner.reset();
+  Py_DECREF(self->message_dict);
+  Py_DECREF(self->message_class);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef MessageMapMethods[] = {
+  { "__contains__", (PyCFunction)MapReflectionFriend::Contains, METH_O,
+    "Tests whether the map contains this element."},
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map."},
+  { "get", MessageMapGet, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  { "get_or_create", MapReflectionFriend::MessageMapGetItem, METH_O,
+    "Alias for getitem, useful to make explicit that the map is mutated." },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+#if PY_MAJOR_VERSION >= 3
+  static PyType_Slot MessageMapContainer_Type_slots[] = {
+      {Py_tp_dealloc, (void *)MessageMapDealloc},
+      {Py_mp_length, (void *)MapReflectionFriend::Length},
+      {Py_mp_subscript, (void *)MapReflectionFriend::MessageMapGetItem},
+      {Py_mp_ass_subscript, (void *)MapReflectionFriend::MessageMapSetItem},
+      {Py_tp_methods, (void *)MessageMapMethods},
+      {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
+      {0, 0}
+  };
+
+  PyType_Spec MessageMapContainer_Type_spec = {
+      FULL_MODULE_NAME ".MessageMapContainer",
+      sizeof(MessageMapContainer),
+      0,
+      Py_TPFLAGS_DEFAULT,
+      MessageMapContainer_Type_slots
+  };
+
+  PyObject *MessageMapContainer_Type;
+#else
+  static PyMappingMethods MessageMapMappingMethods = {
+    MapReflectionFriend::Length,              // mp_length
+    MapReflectionFriend::MessageMapGetItem,   // mp_subscript
+    MapReflectionFriend::MessageMapSetItem,   // mp_ass_subscript
+  };
+
+  PyTypeObject MessageMapContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    FULL_MODULE_NAME ".MessageMapContainer",  //  tp_name
+    sizeof(MessageMapContainer),         //  tp_basicsize
+    0,                                   //  tp_itemsize
+    MessageMapDealloc,                   //  tp_dealloc
+    0,                                   //  tp_print
+    0,                                   //  tp_getattr
+    0,                                   //  tp_setattr
+    0,                                   //  tp_compare
+    0,                                   //  tp_repr
+    0,                                   //  tp_as_number
+    0,                                   //  tp_as_sequence
+    &MessageMapMappingMethods,           //  tp_as_mapping
+    0,                                   //  tp_hash
+    0,                                   //  tp_call
+    0,                                   //  tp_str
+    0,                                   //  tp_getattro
+    0,                                   //  tp_setattro
+    0,                                   //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  //  tp_flags
+    "A map container for message",       //  tp_doc
+    0,                                   //  tp_traverse
+    0,                                   //  tp_clear
+    0,                                   //  tp_richcompare
+    0,                                   //  tp_weaklistoffset
+    MapReflectionFriend::GetIterator,    //  tp_iter
+    0,                                   //  tp_iternext
+    MessageMapMethods,                   //  tp_methods
+    0,                                   //  tp_members
+    0,                                   //  tp_getset
+    0,                                   //  tp_base
+    0,                                   //  tp_dict
+    0,                                   //  tp_descr_get
+    0,                                   //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    0,                                   //  tp_init
+  };
+#endif
+
+// MapIterator /////////////////////////////////////////////////////////////////
+
+static MapIterator* GetIter(PyObject* obj) {
+  return reinterpret_cast<MapIterator*>(obj);
+}
+
+PyObject* MapReflectionFriend::GetIterator(PyObject *_self) {
+  MapContainer* self = GetMap(_self);
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&MapIterator_Type, 0));
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
+  }
+
+  MapIterator* iter = GetIter(obj.get());
+
+  Py_INCREF(self);
+  iter->container = self;
+  iter->version = self->version;
+  iter->owner = self->owner;
+
+  if (MapReflectionFriend::Length(_self) > 0) {
+    Message* message = self->GetMutableMessage();
+    const Reflection* reflection = message->GetReflection();
+
+    iter->iter.reset(new ::google::protobuf::MapIterator(
+        reflection->MapBegin(message, self->parent_field_descriptor)));
+  }
+
+  return obj.release();
+}
+
+PyObject* MapReflectionFriend::IterNext(PyObject* _self) {
+  MapIterator* self = GetIter(_self);
+
+  // This won't catch mutations to the map performed by MergeFrom(); no easy way
+  // to address that.
+  if (self->version != self->container->version) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Map modified during iteration.");
+  }
+
+  if (self->iter.get() == NULL) {
+    return NULL;
+  }
+
+  Message* message = self->container->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+
+  if (*self->iter ==
+      reflection->MapEnd(message, self->container->parent_field_descriptor)) {
+    return NULL;
+  }
+
+  PyObject* ret = MapKeyToPython(self->container->key_field_descriptor,
+                                 self->iter->GetKey());
+
+  ++(*self->iter);
+
+  return ret;
+}
+
+static void DeallocMapIterator(PyObject* _self) {
+  MapIterator* self = GetIter(_self);
+  self->iter.reset();
+  self->owner.reset();
+  Py_XDECREF(self->container);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+PyTypeObject MapIterator_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MapIterator",     //  tp_name
+  sizeof(MapIterator),                 //  tp_basicsize
+  0,                                   //  tp_itemsize
+  DeallocMapIterator,                  //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  0,                                   //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A scalar map iterator",             //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  PyObject_SelfIter,                   //  tp_iter
+  MapReflectionFriend::IterNext,       //  tp_iternext
+  0,                                   //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h
new file mode 100644
index 0000000..fbd6713
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.h
@@ -0,0 +1,142 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
+using internal::shared_ptr;
+#endif
+
+namespace python {
+
+struct CMessage;
+struct CMessageClass;
+
+// This struct is used directly for ScalarMap, and is the base class of
+// MessageMapContainer, which is used for MessageMap.
+struct MapContainer {
+  PyObject_HEAD;
+
+  // This is the top-level C++ Message object that owns the whole
+  // proto tree.  Every Python MapContainer holds a
+  // reference to it in order to keep it alive as long as there's a
+  // Python object that references any part of the tree.
+  shared_ptr<Message> owner;
+
+  // Pointer to the C++ Message that contains this container.  The
+  // MapContainer does not own this pointer.
+  const Message* message;
+
+  // Use to get a mutable message when necessary.
+  Message* GetMutableMessage();
+
+  // Weak reference to a parent CMessage object (i.e. may be NULL.)
+  //
+  // Used to make sure all ancestors are also mutable when first
+  // modifying the container.
+  CMessage* parent;
+
+  // Pointer to the parent's descriptor that describes this
+  // field.  Used together with the parent's message when making a
+  // default message instance mutable.
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
+  const FieldDescriptor* key_field_descriptor;
+  const FieldDescriptor* value_field_descriptor;
+
+  // We bump this whenever we perform a mutation, to invalidate existing
+  // iterators.
+  uint64 version;
+
+  // Releases the messages in the container to a new message.
+  //
+  // Returns 0 on success, -1 on failure.
+  int Release();
+
+  // Set the owner field of self and any children of self.
+  void SetOwner(const shared_ptr<Message>& new_owner) {
+    owner = new_owner;
+  }
+};
+
+struct MessageMapContainer : public MapContainer {
+  // The type used to create new child messages.
+  CMessageClass* message_class;
+
+  // A dict mapping Message* -> CMessage.
+  PyObject* message_dict;
+};
+
+#if PY_MAJOR_VERSION >= 3
+  extern PyObject *MessageMapContainer_Type;
+  extern PyType_Spec MessageMapContainer_Type_spec;
+  extern PyObject *ScalarMapContainer_Type;
+  extern PyType_Spec ScalarMapContainer_Type_spec;
+#else
+  extern PyTypeObject MessageMapContainer_Type;
+  extern PyTypeObject ScalarMapContainer_Type;
+#endif
+
+extern PyTypeObject MapIterator_Type;  // Both map types use the same iterator.
+
+// Builds a MapContainer object, from a parent message and a
+// field descriptor.
+extern PyObject* NewScalarMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
+
+// Builds a MessageMap object, from a parent message and a
+// field descriptor.
+extern PyObject* NewMessageMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor,
+    CMessageClass* message_class);
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 9fb7083..83c151f 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -33,12 +33,14 @@
 
 #include <google/protobuf/pyext/message.h>
 
+#include <map>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #include <string>
 #include <vector>
+#include <structmember.h>  // A Python header file.
 
 #ifndef PyVarObject_HEAD_INIT
 #define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -48,16 +50,21 @@
 #endif
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
+#include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/extension_dict.h>
 #include <google/protobuf/pyext/repeated_composite_container.h>
 #include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/map_container.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/stubs/strutil.h>
 
 #if PY_MAJOR_VERSION >= 3
   #define PyInt_Check PyLong_Check
@@ -71,7 +78,11 @@
     #error "Python 3.0 - 3.2 are not supported."
   #else
   #define PyString_AsString(ob) \
-    (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob))
+    (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob))
+  #define PyString_AsStringAndSize(ob, charpp, sizep) \
+    (PyUnicode_Check(ob)? \
+       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
   #endif
 #endif
 
@@ -79,14 +90,328 @@
 namespace protobuf {
 namespace python {
 
+static PyObject* kDESCRIPTOR;
+static PyObject* k_extensions_by_name;
+static PyObject* k_extensions_by_number;
+PyObject* EnumTypeWrapper_class;
+static PyObject* PythonMessage_class;
+static PyObject* kEmptyWeakref;
+static PyObject* WKT_classes = NULL;
+
+namespace message_meta {
+
+static int InsertEmptyWeakref(PyTypeObject* base);
+
+// Add the number of a field descriptor to the containing message class.
+// Equivalent to:
+//   _cls.<field>_FIELD_NUMBER = <number>
+static bool AddFieldNumberToClass(
+    PyObject* cls, const FieldDescriptor* field_descriptor) {
+  string constant_name = field_descriptor->name() + "_FIELD_NUMBER";
+  UpperString(&constant_name);
+  ScopedPyObjectPtr attr_name(PyString_FromStringAndSize(
+      constant_name.c_str(), constant_name.size()));
+  if (attr_name == NULL) {
+    return false;
+  }
+  ScopedPyObjectPtr number(PyInt_FromLong(field_descriptor->number()));
+  if (number == NULL) {
+    return false;
+  }
+  if (PyObject_SetAttr(cls, attr_name.get(), number.get()) == -1) {
+    return false;
+  }
+  return true;
+}
+
+
+// Finalize the creation of the Message class.
+static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
+  // If there are extension_ranges, the message is "extendable", and extension
+  // classes will register themselves in this class.
+  if (descriptor->extension_range_count() > 0) {
+    ScopedPyObjectPtr by_name(PyDict_New());
+    if (PyObject_SetAttr(cls, k_extensions_by_name, by_name.get()) < 0) {
+      return -1;
+    }
+    ScopedPyObjectPtr by_number(PyDict_New());
+    if (PyObject_SetAttr(cls, k_extensions_by_number, by_number.get()) < 0) {
+      return -1;
+    }
+  }
+
+  // For each field set: cls.<field>_FIELD_NUMBER = <number>
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (!AddFieldNumberToClass(cls, descriptor->field(i))) {
+      return -1;
+    }
+  }
+
+  // For each enum set cls.<enum name> = EnumTypeWrapper(<enum descriptor>).
+  for (int i = 0; i < descriptor->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
+    ScopedPyObjectPtr enum_type(
+        PyEnumDescriptor_FromDescriptor(enum_descriptor));
+    if (enum_type == NULL) {
+      return -1;
+     }
+    // Add wrapped enum type to message class.
+    ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
+        EnumTypeWrapper_class, enum_type.get(), NULL));
+    if (wrapped == NULL) {
+      return -1;
+    }
+    if (PyObject_SetAttrString(
+            cls, enum_descriptor->name().c_str(), wrapped.get()) == -1) {
+      return -1;
+    }
+
+    // For each enum value add cls.<name> = <number>
+    for (int j = 0; j < enum_descriptor->value_count(); ++j) {
+      const EnumValueDescriptor* enum_value_descriptor =
+          enum_descriptor->value(j);
+      ScopedPyObjectPtr value_number(PyInt_FromLong(
+          enum_value_descriptor->number()));
+      if (value_number == NULL) {
+        return -1;
+      }
+      if (PyObject_SetAttrString(cls, enum_value_descriptor->name().c_str(),
+                                 value_number.get()) == -1) {
+        return -1;
+      }
+    }
+  }
+
+  // For each extension set cls.<extension name> = <extension descriptor>.
+  //
+  // Extension descriptors come from
+  // <message descriptor>.extensions_by_name[name]
+  // which was defined previously.
+  for (int i = 0; i < descriptor->extension_count(); ++i) {
+    const google::protobuf::FieldDescriptor* field = descriptor->extension(i);
+    ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field));
+    if (extension_field == NULL) {
+      return -1;
+    }
+
+    // Add the extension field to the message class.
+    if (PyObject_SetAttrString(
+            cls, field->name().c_str(), extension_field.get()) == -1) {
+      return -1;
+    }
+
+    // For each extension set cls.<extension name>_FIELD_NUMBER = <number>.
+    if (!AddFieldNumberToClass(cls, field)) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static PyObject* New(PyTypeObject* type,
+                     PyObject* args, PyObject* kwargs) {
+  static char *kwlist[] = {"name", "bases", "dict", 0};
+  PyObject *bases, *dict;
+  const char* name;
+
+  // Check arguments: (name, bases, dict)
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", kwlist,
+                                   &name,
+                                   &PyTuple_Type, &bases,
+                                   &PyDict_Type, &dict)) {
+    return NULL;
+  }
+
+  // Check bases: only (), or (message.Message,) are allowed
+  if (!(PyTuple_GET_SIZE(bases) == 0 ||
+        (PyTuple_GET_SIZE(bases) == 1 &&
+         PyTuple_GET_ITEM(bases, 0) == PythonMessage_class))) {
+    PyErr_SetString(PyExc_TypeError,
+                    "A Message class can only inherit from Message");
+    return NULL;
+  }
+
+  // Check dict['DESCRIPTOR']
+  PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
+  if (py_descriptor == NULL) {
+    PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
+    return NULL;
+  }
+  if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
+    PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
+                 py_descriptor->ob_type->tp_name);
+    return NULL;
+  }
+
+  // Build the arguments to the base metaclass.
+  // We change the __bases__ classes.
+  ScopedPyObjectPtr new_args;
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (message_descriptor == NULL) {
+    return NULL;
+  }
+
+  if (WKT_classes == NULL) {
+    ScopedPyObjectPtr well_known_types(PyImport_ImportModule(
+        "google.protobuf.internal.well_known_types"));
+    GOOGLE_DCHECK(well_known_types != NULL);
+
+    WKT_classes = PyObject_GetAttrString(well_known_types.get(), "WKTBASES");
+    GOOGLE_DCHECK(WKT_classes != NULL);
+  }
+
+  PyObject* well_known_class = PyDict_GetItemString(
+      WKT_classes, message_descriptor->full_name().c_str());
+  if (well_known_class == NULL) {
+    new_args.reset(Py_BuildValue("s(OO)O", name, &CMessage_Type,
+                                 PythonMessage_class, dict));
+  } else {
+    new_args.reset(Py_BuildValue("s(OOO)O", name, &CMessage_Type,
+                                 PythonMessage_class, well_known_class, dict));
+  }
+
+  if (new_args == NULL) {
+    return NULL;
+  }
+  // Call the base metaclass.
+  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), NULL));
+  if (result == NULL) {
+    return NULL;
+  }
+  CMessageClass* newtype = reinterpret_cast<CMessageClass*>(result.get());
+
+  // Insert the empty weakref into the base classes.
+  if (InsertEmptyWeakref(
+          reinterpret_cast<PyTypeObject*>(PythonMessage_class)) < 0 ||
+      InsertEmptyWeakref(&CMessage_Type) < 0) {
+    return NULL;
+  }
+
+  // Cache the descriptor, both as Python object and as C++ pointer.
+  const Descriptor* descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (descriptor == NULL) {
+    return NULL;
+  }
+  Py_INCREF(py_descriptor);
+  newtype->py_message_descriptor = py_descriptor;
+  newtype->message_descriptor = descriptor;
+  // TODO(amauryfa): Don't always use the canonical pool of the descriptor,
+  // use the MessageFactory optionally passed in the class dict.
+  newtype->py_descriptor_pool = GetDescriptorPool_FromPool(
+      descriptor->file()->pool());
+  if (newtype->py_descriptor_pool == NULL) {
+    return NULL;
+  }
+  Py_INCREF(newtype->py_descriptor_pool);
+
+  // Add the message to the DescriptorPool.
+  if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool,
+                                             descriptor, newtype) < 0) {
+    return NULL;
+  }
+
+  // Continue with type initialization: add other descriptors, enum values...
+  if (AddDescriptors(result.get(), descriptor) < 0) {
+    return NULL;
+  }
+  return result.release();
+}
+
+static void Dealloc(CMessageClass *self) {
+  Py_DECREF(self->py_message_descriptor);
+  Py_DECREF(self->py_descriptor_pool);
+  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+
+// This function inserts and empty weakref at the end of the list of
+// subclasses for the main protocol buffer Message class.
+//
+// This eliminates a O(n^2) behaviour in the internal add_subclass
+// routine.
+static int InsertEmptyWeakref(PyTypeObject *base_type) {
+#if PY_MAJOR_VERSION >= 3
+  // Python 3.4 has already included the fix for the issue that this
+  // hack addresses. For further background and the fix please see
+  // https://bugs.python.org/issue17936.
+  return 0;
+#else
+  PyObject *subclasses = base_type->tp_subclasses;
+  if (subclasses && PyList_CheckExact(subclasses)) {
+    return PyList_Append(subclasses, kEmptyWeakref);
+  }
+  return 0;
+#endif  // PY_MAJOR_VERSION >= 3
+}
+
+}  // namespace message_meta
+
+PyTypeObject CMessageClass_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MessageMeta",     // tp_name
+  sizeof(CMessageClass),               // tp_basicsize
+  0,                                   // tp_itemsize
+  (destructor)message_meta::Dealloc,   // tp_dealloc
+  0,                                   // tp_print
+  0,                                   // tp_getattr
+  0,                                   // tp_setattr
+  0,                                   // tp_compare
+  0,                                   // tp_repr
+  0,                                   // tp_as_number
+  0,                                   // tp_as_sequence
+  0,                                   // tp_as_mapping
+  0,                                   // tp_hash
+  0,                                   // tp_call
+  0,                                   // tp_str
+  0,                                   // tp_getattro
+  0,                                   // tp_setattro
+  0,                                   // tp_as_buffer
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
+  "The metaclass of ProtocolMessages",  // tp_doc
+  0,                                   // tp_traverse
+  0,                                   // tp_clear
+  0,                                   // tp_richcompare
+  0,                                   // tp_weaklistoffset
+  0,                                   // tp_iter
+  0,                                   // tp_iternext
+  0,                                   // tp_methods
+  0,                                   // tp_members
+  0,                                   // tp_getset
+  0,                                   // tp_base
+  0,                                   // tp_dict
+  0,                                   // tp_descr_get
+  0,                                   // tp_descr_set
+  0,                                   // tp_dictoffset
+  0,                                   // tp_init
+  0,                                   // tp_alloc
+  message_meta::New,                   // tp_new
+};
+
+static CMessageClass* CheckMessageClass(PyTypeObject* cls) {
+  if (!PyObject_TypeCheck(cls, &CMessageClass_Type)) {
+    PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
+    return NULL;
+  }
+  return reinterpret_cast<CMessageClass*>(cls);
+}
+
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+  CMessageClass* type = CheckMessageClass(cls);
+  if (type == NULL) {
+    return NULL;
+  }
+  return type->message_descriptor;
+}
+
 // Forward declarations
 namespace cmessage {
-static PyObject* GetDescriptor(CMessage* self, PyObject* name);
-static string GetMessageName(CMessage* self);
 int InternalReleaseFieldByDescriptor(
-    const google::protobuf::FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    google::protobuf::Message* parent_message);
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
+    PyObject* composite_field);
 }  // namespace cmessage
 
 // ---------------------------------------------------------------------
@@ -105,7 +430,7 @@
 
   // Returns 0 on success, -1 on failure.
   int VisitCMessage(CMessage* cmessage,
-                    const google::protobuf::FieldDescriptor* field_descriptor) {
+                    const FieldDescriptor* field_descriptor) {
     return 0;
   }
 };
@@ -116,20 +441,26 @@
 static int VisitCompositeField(const FieldDescriptor* descriptor,
                                PyObject* child,
                                Visitor visitor) {
-  if (descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
-    if (descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
-      RepeatedCompositeContainer* container =
-        reinterpret_cast<RepeatedCompositeContainer*>(child);
-      if (visitor.VisitRepeatedCompositeContainer(container) == -1)
-        return -1;
+  if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      if (descriptor->is_map()) {
+        MapContainer* container = reinterpret_cast<MapContainer*>(child);
+        if (visitor.VisitMapContainer(container) == -1) {
+          return -1;
+        }
+      } else {
+        RepeatedCompositeContainer* container =
+          reinterpret_cast<RepeatedCompositeContainer*>(child);
+        if (visitor.VisitRepeatedCompositeContainer(container) == -1)
+          return -1;
+      }
     } else {
       RepeatedScalarContainer* container =
         reinterpret_cast<RepeatedScalarContainer*>(child);
       if (visitor.VisitRepeatedScalarContainer(container) == -1)
         return -1;
     }
-  } else if (descriptor->cpp_type() ==
-             google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+  } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     CMessage* cmsg = reinterpret_cast<CMessage*>(child);
     if (visitor.VisitCMessage(cmsg, descriptor) == -1)
       return -1;
@@ -148,24 +479,33 @@
   PyObject* field;
 
   // Visit normal fields.
-  while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
-    PyObject* cdescriptor = cmessage::GetDescriptor(self, key);
-    if (cdescriptor != NULL) {
-      const google::protobuf::FieldDescriptor* descriptor =
-          reinterpret_cast<CFieldDescriptor*>(cdescriptor)->descriptor;
-      if (VisitCompositeField(descriptor, field, visitor) == -1)
+  if (self->composite_fields) {
+    // Never use self->message in this function, it may be already freed.
+    const Descriptor* message_descriptor =
+        GetMessageDescriptor(Py_TYPE(self));
+    while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
+      Py_ssize_t key_str_size;
+      char *key_str_data;
+      if (PyString_AsStringAndSize(key, &key_str_data, &key_str_size) != 0)
         return -1;
+      const string key_str(key_str_data, key_str_size);
+      const FieldDescriptor* descriptor =
+        message_descriptor->FindFieldByName(key_str);
+      if (descriptor != NULL) {
+        if (VisitCompositeField(descriptor, field, visitor) == -1)
+          return -1;
+      }
     }
   }
 
   // Visit extension fields.
   if (self->extensions != NULL) {
+    pos = 0;
     while (PyDict_Next(self->extensions->values, &pos, &key, &field)) {
-      CFieldDescriptor* cdescriptor =
-          extension_dict::InternalGetCDescriptorFromExtension(key);
-      if (cdescriptor == NULL)
+      const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
+      if (descriptor == NULL)
         return -1;
-      if (VisitCompositeField(cdescriptor->descriptor, field, visitor) == -1)
+      if (VisitCompositeField(descriptor, field, visitor) == -1)
         return -1;
     }
   }
@@ -184,25 +524,13 @@
 PyObject* kint64max_py;
 PyObject* kuint64max_py;
 
-PyObject* EnumTypeWrapper_class;
 PyObject* EncodeError_class;
 PyObject* DecodeError_class;
 PyObject* PickleError_class;
 
 // Constant PyString values used for GetAttr/GetItem.
-static PyObject* kDESCRIPTOR;
-static PyObject* k__descriptors;
+static PyObject* k_cdescriptor;
 static PyObject* kfull_name;
-static PyObject* kname;
-static PyObject* kmessage_type;
-static PyObject* kis_extendable;
-static PyObject* kextensions_by_name;
-static PyObject* k_extensions_by_name;
-static PyObject* k_extensions_by_number;
-static PyObject* k_concrete_class;
-static PyObject* kfields_by_name;
-
-static CDescriptorPool* descriptor_pool;
 
 /* Is 64bit */
 void FormatTypeError(PyObject* arg, char* expected_types) {
@@ -235,12 +563,14 @@
   if (PyObject_RichCompareBool(min, arg, Py_LE) != 1 ||
       PyObject_RichCompareBool(max, arg, Py_GE) != 1) {
 #endif
-    PyObject *s = PyObject_Str(arg);
-    if (s) {
-      PyErr_Format(PyExc_ValueError,
-                   "Value out of range: %s",
-                   PyString_AsString(s));
-      Py_DECREF(s);
+    if (!PyErr_Occurred()) {
+      PyObject *s = PyObject_Str(arg);
+      if (s) {
+        PyErr_Format(PyExc_ValueError,
+                     "Value out of range: %s",
+                     PyString_AsString(s));
+        Py_DECREF(s);
+      }
     }
     return false;
   }
@@ -298,49 +628,59 @@
   return true;
 }
 
-bool CheckAndSetString(
-    PyObject* arg, google::protobuf::Message* message,
-    const google::protobuf::FieldDescriptor* descriptor,
-    const google::protobuf::Reflection* reflection,
-    bool append,
-    int index) {
-  GOOGLE_DCHECK(descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
-         descriptor->type() == google::protobuf::FieldDescriptor::TYPE_BYTES);
-  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
-    if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) {
-      FormatTypeError(arg, "bytes, unicode");
+// Checks whether the given object (which must be "bytes" or "unicode") contains
+// valid UTF-8.
+bool IsValidUTF8(PyObject* obj) {
+  if (PyBytes_Check(obj)) {
+    PyObject* unicode = PyUnicode_FromEncodedObject(obj, "utf-8", NULL);
+
+    // Clear the error indicator; we report our own error when desired.
+    PyErr_Clear();
+
+    if (unicode) {
+      Py_DECREF(unicode);
+      return true;
+    } else {
       return false;
     }
+  } else {
+    // Unicode object, known to be valid UTF-8.
+    return true;
+  }
+}
 
-    if (PyBytes_Check(arg)) {
-      PyObject* unicode = PyUnicode_FromEncodedObject(arg, "ascii", NULL);
-      if (unicode == NULL) {
-        PyObject* repr = PyObject_Repr(arg);
-        PyErr_Format(PyExc_ValueError,
-                     "%s has type str, but isn't in 7-bit ASCII "
-                     "encoding. Non-ASCII strings must be converted to "
-                     "unicode objects before being added.",
-                     PyString_AsString(repr));
-        Py_DECREF(repr);
-        return false;
-      } else {
-        Py_DECREF(unicode);
-      }
+bool AllowInvalidUTF8(const FieldDescriptor* field) { return false; }
+
+PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor) {
+  GOOGLE_DCHECK(descriptor->type() == FieldDescriptor::TYPE_STRING ||
+         descriptor->type() == FieldDescriptor::TYPE_BYTES);
+  if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
+    if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) {
+      FormatTypeError(arg, "bytes, unicode");
+      return NULL;
+    }
+
+    if (!IsValidUTF8(arg) && !AllowInvalidUTF8(descriptor)) {
+      PyObject* repr = PyObject_Repr(arg);
+      PyErr_Format(PyExc_ValueError,
+                   "%s has type str, but isn't valid UTF-8 "
+                   "encoding. Non-UTF-8 strings must be converted to "
+                   "unicode objects before being added.",
+                   PyString_AsString(repr));
+      Py_DECREF(repr);
+      return NULL;
     }
   } else if (!PyBytes_Check(arg)) {
     FormatTypeError(arg, "bytes");
-    return false;
+    return NULL;
   }
 
   PyObject* encoded_string = NULL;
-  if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
+  if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
     if (PyBytes_Check(arg)) {
-#if PY_MAJOR_VERSION < 3
-      encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL);
-#else
+      // The bytes were already validated as correctly encoded UTF-8 above.
       encoded_string = arg;  // Already encoded.
       Py_INCREF(encoded_string);
-#endif
     } else {
       encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
     }
@@ -350,14 +690,24 @@
     Py_INCREF(encoded_string);
   }
 
-  if (encoded_string == NULL) {
+  return encoded_string;
+}
+
+bool CheckAndSetString(
+    PyObject* arg, Message* message,
+    const FieldDescriptor* descriptor,
+    const Reflection* reflection,
+    bool append,
+    int index) {
+  ScopedPyObjectPtr encoded_string(CheckString(arg, descriptor));
+
+  if (encoded_string.get() == NULL) {
     return false;
   }
 
   char* value;
   Py_ssize_t value_len;
-  if (PyBytes_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
-    Py_DECREF(encoded_string);
+  if (PyBytes_AsStringAndSize(encoded_string.get(), &value, &value_len) < 0) {
     return false;
   }
 
@@ -369,13 +719,11 @@
   } else {
     reflection->SetRepeatedString(message, descriptor, index, value_string);
   }
-  Py_DECREF(encoded_string);
   return true;
 }
 
-PyObject* ToStringObject(
-    const google::protobuf::FieldDescriptor* descriptor, string value) {
-  if (descriptor->type() != google::protobuf::FieldDescriptor::TYPE_STRING) {
+PyObject* ToStringObject(const FieldDescriptor* descriptor, string value) {
+  if (descriptor->type() != FieldDescriptor::TYPE_STRING) {
     return PyBytes_FromStringAndSize(value.c_str(), value.length());
   }
 
@@ -391,16 +739,36 @@
   return result;
 }
 
-google::protobuf::DynamicMessageFactory* global_message_factory;
+bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
+                                const Message* message) {
+  if (message->GetDescriptor() == field_descriptor->containing_type()) {
+    return true;
+  }
+  PyErr_Format(PyExc_KeyError, "Field '%s' does not belong to message '%s'",
+               field_descriptor->full_name().c_str(),
+               message->GetDescriptor()->full_name().c_str());
+  return false;
+}
 
 namespace cmessage {
 
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) {
+  // No need to check the type: the type of instances of CMessage is always
+  // an instance of CMessageClass. Let's prove it with a debug-only check.
+  GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type));
+  return reinterpret_cast<CMessageClass*>(Py_TYPE(message))->py_descriptor_pool;
+}
+
+MessageFactory* GetFactoryForMessage(CMessage* message) {
+  return GetDescriptorPoolForMessage(message)->message_factory;
+}
+
 static int MaybeReleaseOverlappingOneofField(
     CMessage* cmessage,
-    const google::protobuf::FieldDescriptor* field) {
+    const FieldDescriptor* field) {
 #ifdef GOOGLE_PROTOBUF_HAS_ONEOF
-  google::protobuf::Message* message = cmessage->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  Message* message = cmessage->message;
+  const Reflection* reflection = message->GetReflection();
   if (!field->containing_oneof() ||
       !reflection->HasOneof(*message, field->containing_oneof()) ||
       reflection->HasField(*message, field)) {
@@ -411,20 +779,20 @@
   const OneofDescriptor* oneof = field->containing_oneof();
   const FieldDescriptor* existing_field =
       reflection->GetOneofFieldDescriptor(*message, oneof);
-  if (existing_field->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+  if (existing_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
     // Non-message fields don't need to be released.
     return 0;
   }
   const char* field_name = existing_field->name().c_str();
-  PyObject* child_message = PyDict_GetItemString(
-      cmessage->composite_fields, field_name);
+  PyObject* child_message = cmessage->composite_fields ?
+      PyDict_GetItemString(cmessage->composite_fields, field_name) : NULL;
   if (child_message == NULL) {
     // No python reference to this field so no need to release.
     return 0;
   }
 
   if (InternalReleaseFieldByDescriptor(
-          existing_field, child_message, message) < 0) {
+          cmessage, existing_field, child_message) < 0) {
     return -1;
   }
   return PyDict_DelItemString(cmessage->composite_fields, field_name);
@@ -436,21 +804,21 @@
 // ---------------------------------------------------------------------
 // Making a message writable
 
-static google::protobuf::Message* GetMutableMessage(
+static Message* GetMutableMessage(
     CMessage* parent,
-    const google::protobuf::FieldDescriptor* parent_field) {
-  google::protobuf::Message* parent_message = parent->message;
-  const google::protobuf::Reflection* reflection = parent_message->GetReflection();
+    const FieldDescriptor* parent_field) {
+  Message* parent_message = parent->message;
+  const Reflection* reflection = parent_message->GetReflection();
   if (MaybeReleaseOverlappingOneofField(parent, parent_field) < 0) {
     return NULL;
   }
   return reflection->MutableMessage(
-      parent_message, parent_field, global_message_factory);
+      parent_message, parent_field, GetFactoryForMessage(parent));
 }
 
 struct FixupMessageReference : public ChildVisitor {
   // message must outlive this object.
-  explicit FixupMessageReference(google::protobuf::Message* message) :
+  explicit FixupMessageReference(Message* message) :
       message_(message) {}
 
   int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
@@ -463,8 +831,13 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->message = message_;
+    return 0;
+  }
+
  private:
-  google::protobuf::Message* message_;
+  Message* message_;
 };
 
 int AssureWritable(CMessage* self) {
@@ -476,20 +849,20 @@
     // If parent is NULL but we are trying to modify a read-only message, this
     // is a reference to a constant default instance that needs to be replaced
     // with a mutable top-level message.
-    const Message* prototype = global_message_factory->GetPrototype(
-        self->message->GetDescriptor());
-    self->message = prototype->New();
+    self->message = self->message->New();
     self->owner.reset(self->message);
+    // Cascade the new owner to eventual children: even if this message is
+    // empty, some submessages or repeated containers might exist already.
+    SetOwner(self, self->owner);
   } else {
     // Otherwise, we need a mutable child message.
     if (AssureWritable(self->parent) == -1)
       return -1;
 
     // Make self->message writable.
-    google::protobuf::Message* parent_message = self->parent->message;
-    google::protobuf::Message* mutable_message = GetMutableMessage(
+    Message* mutable_message = GetMutableMessage(
         self->parent,
-        self->parent_field->descriptor);
+        self->parent_field_descriptor);
     if (mutable_message == NULL) {
       return -1;
     }
@@ -500,8 +873,8 @@
   // When a CMessage is made writable its Message pointer is updated
   // to point to a new mutable Message.  When that happens we need to
   // update any references to the old, read-only CMessage.  There are
-  // three places such references occur: RepeatedScalarContainer,
-  // RepeatedCompositeContainer, and ExtensionDict.
+  // four places such references occur: RepeatedScalarContainer,
+  // RepeatedCompositeContainer, MapContainer, and ExtensionDict.
   if (self->extensions != NULL)
     self->extensions->message = self->message;
   if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1)
@@ -512,26 +885,65 @@
 
 // --- Globals:
 
-static PyObject* GetDescriptor(CMessage* self, PyObject* name) {
-  PyObject* descriptors =
-      PyDict_GetItem(Py_TYPE(self)->tp_dict, k__descriptors);
-  if (descriptors == NULL) {
-    PyErr_SetString(PyExc_TypeError, "No __descriptors");
+// Retrieve a C++ FieldDescriptor for a message attribute.
+// The C++ message must be valid.
+// TODO(amauryfa): This function should stay internal, because exception
+// handling is not consistent.
+static const FieldDescriptor* GetFieldDescriptor(
+    CMessage* self, PyObject* name) {
+  const Descriptor *message_descriptor = self->message->GetDescriptor();
+  char* field_name;
+  Py_ssize_t size;
+  if (PyString_AsStringAndSize(name, &field_name, &size) < 0) {
     return NULL;
   }
-
-  return PyDict_GetItem(descriptors, name);
+  const FieldDescriptor *field_descriptor =
+      message_descriptor->FindFieldByName(string(field_name, size));
+  if (field_descriptor == NULL) {
+    // Note: No exception is set!
+    return NULL;
+  }
+  return field_descriptor;
 }
 
-static const google::protobuf::Message* CreateMessage(const char* message_type) {
-  string message_name(message_type);
-  const google::protobuf::Descriptor* descriptor =
-      GetDescriptorPool()->FindMessageTypeByName(message_name);
-  if (descriptor == NULL) {
-    PyErr_SetString(PyExc_TypeError, message_type);
+// Retrieve a C++ FieldDescriptor for an extension handle.
+const FieldDescriptor* GetExtensionDescriptor(PyObject* extension) {
+  ScopedPyObjectPtr cdescriptor;
+  if (!PyObject_TypeCheck(extension, &PyFieldDescriptor_Type)) {
+    // Most callers consider extensions as a plain dictionary.  We should
+    // allow input which is not a field descriptor, and simply pretend it does
+    // not exist.
+    PyErr_SetObject(PyExc_KeyError, extension);
     return NULL;
   }
-  return global_message_factory->GetPrototype(descriptor);
+  return PyFieldDescriptor_AsDescriptor(extension);
+}
+
+// If value is a string, convert it into an enum value based on the labels in
+// descriptor, otherwise simply return value.  Always returns a new reference.
+static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor,
+                                     PyObject* value) {
+  if (PyString_Check(value) || PyUnicode_Check(value)) {
+    const EnumDescriptor* enum_descriptor = descriptor.enum_type();
+    if (enum_descriptor == NULL) {
+      PyErr_SetString(PyExc_TypeError, "not an enum field");
+      return NULL;
+    }
+    char* enum_label;
+    Py_ssize_t size;
+    if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) {
+      return NULL;
+    }
+    const EnumValueDescriptor* enum_value_descriptor =
+        enum_descriptor->FindValueByName(string(enum_label, size));
+    if (enum_value_descriptor == NULL) {
+      PyErr_SetString(PyExc_ValueError, "unknown enum label");
+      return NULL;
+    }
+    return PyInt_FromLong(enum_value_descriptor->number());
+  }
+  Py_INCREF(value);
+  return value;
 }
 
 // If cmessage_list is not NULL, this function releases values into the
@@ -539,12 +951,13 @@
 // needs to do this to make sure CMessages stay alive if they're still
 // referenced after deletion. Repeated scalar container doesn't need to worry.
 int InternalDeleteRepeatedField(
-    google::protobuf::Message* message,
-    const google::protobuf::FieldDescriptor* field_descriptor,
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
     PyObject* slice,
     PyObject* cmessage_list) {
+  Message* message = self->message;
   Py_ssize_t length, from, to, step, slice_length;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  const Reflection* reflection = message->GetReflection();
   int min, max;
   length = reflection->FieldSize(*message, field_descriptor);
 
@@ -616,7 +1029,7 @@
       CMessage* last_cmessage = reinterpret_cast<CMessage*>(
           PyList_GET_ITEM(cmessage_list, PyList_GET_SIZE(cmessage_list) - 1));
       repeated_composite_container::ReleaseLastTo(
-          field_descriptor, message, last_cmessage);
+          self, field_descriptor, last_cmessage);
       if (PySequence_DelItem(cmessage_list, -1) < 0) {
         return -1;
       }
@@ -627,39 +1040,8 @@
   return 0;
 }
 
-int InitAttributes(CMessage* self, PyObject* arg, PyObject* kwargs) {
-  ScopedPyObjectPtr descriptor;
-  if (arg == NULL) {
-    descriptor.reset(
-        PyObject_GetAttr(reinterpret_cast<PyObject*>(self), kDESCRIPTOR));
-    if (descriptor == NULL) {
-      return NULL;
-    }
-  } else {
-    descriptor.reset(arg);
-    descriptor.inc();
-  }
-  ScopedPyObjectPtr is_extendable(PyObject_GetAttr(descriptor, kis_extendable));
-  if (is_extendable == NULL) {
-    return NULL;
-  }
-  int retcode = PyObject_IsTrue(is_extendable);
-  if (retcode == -1) {
-    return NULL;
-  }
-  if (retcode) {
-    PyObject* py_extension_dict = PyObject_CallObject(
-        reinterpret_cast<PyObject*>(&ExtensionDict_Type), NULL);
-    if (py_extension_dict == NULL) {
-      return NULL;
-    }
-    ExtensionDict* extension_dict = reinterpret_cast<ExtensionDict*>(
-        py_extension_dict);
-    extension_dict->parent = self;
-    extension_dict->message = self->message;
-    self->extensions = extension_dict;
-  }
-
+// Initializes fields of a message. Used in constructors.
+int InitAttributes(CMessage* self, PyObject* kwargs) {
   if (kwargs == NULL) {
     return 0;
   }
@@ -672,46 +1054,138 @@
       PyErr_SetString(PyExc_ValueError, "Field name must be a string");
       return -1;
     }
-    PyObject* py_cdescriptor = GetDescriptor(self, name);
-    if (py_cdescriptor == NULL) {
-      PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.",
+    const FieldDescriptor* descriptor = GetFieldDescriptor(self, name);
+    if (descriptor == NULL) {
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.",
+                   self->message->GetDescriptor()->name().c_str(),
                    PyString_AsString(name));
       return -1;
     }
-    const google::protobuf::FieldDescriptor* descriptor =
-        reinterpret_cast<CFieldDescriptor*>(py_cdescriptor)->descriptor;
-    if (descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
+    if (value == Py_None) {
+      // field=None is the same as no field at all.
+      continue;
+    }
+    if (descriptor->is_map()) {
+      ScopedPyObjectPtr map(GetAttr(self, name));
+      const FieldDescriptor* value_descriptor =
+          descriptor->message_type()->FindFieldByName("value");
+      if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        Py_ssize_t map_pos = 0;
+        PyObject* map_key;
+        PyObject* map_value;
+        while (PyDict_Next(value, &map_pos, &map_key, &map_value)) {
+          ScopedPyObjectPtr function_return;
+          function_return.reset(PyObject_GetItem(map.get(), map_key));
+          if (function_return.get() == NULL) {
+            return -1;
+          }
+          ScopedPyObjectPtr ok(PyObject_CallMethod(
+              function_return.get(), "MergeFrom", "O", map_value));
+          if (ok.get() == NULL) {
+            return -1;
+          }
+        }
+      } else {
+        ScopedPyObjectPtr function_return;
+        function_return.reset(
+            PyObject_CallMethod(map.get(), "update", "O", value));
+        if (function_return.get() == NULL) {
+          return -1;
+        }
+      }
+    } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
       ScopedPyObjectPtr container(GetAttr(self, name));
       if (container == NULL) {
         return -1;
       }
-      if (descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
-        if (repeated_composite_container::Extend(
-                reinterpret_cast<RepeatedCompositeContainer*>(container.get()),
-                value)
-            == NULL) {
+      if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        RepeatedCompositeContainer* rc_container =
+            reinterpret_cast<RepeatedCompositeContainer*>(container.get());
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == NULL) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+          PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : NULL);
+          ScopedPyObjectPtr new_msg(
+              repeated_composite_container::Add(rc_container, NULL, kwargs));
+          if (new_msg == NULL) {
+            return -1;
+          }
+          if (kwargs == NULL) {
+            // next was not a dict, it's a message we need to merge
+            ScopedPyObjectPtr merged(MergeFrom(
+                reinterpret_cast<CMessage*>(new_msg.get()), next.get()));
+            if (merged.get() == NULL) {
+              return -1;
+            }
+          }
+        }
+        if (PyErr_Occurred()) {
+          // Check to see how PyIter_Next() exited.
+          return -1;
+        }
+      } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        RepeatedScalarContainer* rs_container =
+            reinterpret_cast<RepeatedScalarContainer*>(container.get());
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == NULL) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+          ScopedPyObjectPtr enum_value(
+              GetIntegerEnumValue(*descriptor, next.get()));
+          if (enum_value == NULL) {
+            return -1;
+          }
+          ScopedPyObjectPtr new_msg(repeated_scalar_container::Append(
+              rs_container, enum_value.get()));
+          if (new_msg == NULL) {
+            return -1;
+          }
+        }
+        if (PyErr_Occurred()) {
+          // Check to see how PyIter_Next() exited.
           return -1;
         }
       } else {
-        if (repeated_scalar_container::Extend(
+        if (ScopedPyObjectPtr(repeated_scalar_container::Extend(
                 reinterpret_cast<RepeatedScalarContainer*>(container.get()),
-                value) ==
+                value)) ==
             NULL) {
           return -1;
         }
       }
-    } else if (descriptor->cpp_type() ==
-               google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+    } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       ScopedPyObjectPtr message(GetAttr(self, name));
       if (message == NULL) {
         return -1;
       }
-      if (MergeFrom(reinterpret_cast<CMessage*>(message.get()),
-                             value) == NULL) {
-        return -1;
+      CMessage* cmessage = reinterpret_cast<CMessage*>(message.get());
+      if (PyDict_Check(value)) {
+        if (InitAttributes(cmessage, value) < 0) {
+          return -1;
+        }
+      } else {
+        ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
+        if (merged == NULL) {
+          return -1;
+        }
       }
     } else {
-      if (SetAttr(self, name, value) < 0) {
+      ScopedPyObjectPtr new_val;
+      if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        new_val.reset(GetIntegerEnumValue(*descriptor, value));
+        if (new_val == NULL) {
+          return -1;
+        }
+      }
+      if (SetAttr(self, name, (new_val.get() == NULL) ? value : new_val.get()) <
+          0) {
         return -1;
       }
     }
@@ -719,59 +1193,64 @@
   return 0;
 }
 
-static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
-  CMessage* self = reinterpret_cast<CMessage*>(type->tp_alloc(type, 0));
+// Allocates an incomplete Python Message: the caller must fill self->message,
+// self->owner and eventually self->parent.
+CMessage* NewEmptyMessage(CMessageClass* type) {
+  CMessage* self = reinterpret_cast<CMessage*>(
+      PyType_GenericAlloc(&type->super.ht_type, 0));
   if (self == NULL) {
     return NULL;
   }
 
   self->message = NULL;
   self->parent = NULL;
-  self->parent_field = NULL;
+  self->parent_field_descriptor = NULL;
   self->read_only = false;
   self->extensions = NULL;
 
-  self->composite_fields = PyDict_New();
-  if (self->composite_fields == NULL) {
+  self->composite_fields = NULL;
+
+  return self;
+}
+
+// The __new__ method of Message classes.
+// Creates a new C++ message and takes ownership.
+static PyObject* New(PyTypeObject* cls,
+                     PyObject* unused_args, PyObject* unused_kwargs) {
+  CMessageClass* type = CheckMessageClass(cls);
+  if (type == NULL) {
     return NULL;
   }
+  // Retrieve the message descriptor and the default instance (=prototype).
+  const Descriptor* message_descriptor = type->message_descriptor;
+  if (message_descriptor == NULL) {
+    return NULL;
+  }
+  const Message* default_message = type->py_descriptor_pool->message_factory
+                                   ->GetPrototype(message_descriptor);
+  if (default_message == NULL) {
+    PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
+    return NULL;
+  }
+
+  CMessage* self = NewEmptyMessage(type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->message = default_message->New();
+  self->owner.reset(self->message);
   return reinterpret_cast<PyObject*>(self);
 }
 
-PyObject* NewEmpty(PyObject* type) {
-  return New(reinterpret_cast<PyTypeObject*>(type), NULL, NULL);
-}
-
+// The __init__ method of Message classes.
+// It initializes fields from keywords passed to the constructor.
 static int Init(CMessage* self, PyObject* args, PyObject* kwargs) {
-  if (kwargs == NULL) {
-    // TODO(anuraag): Set error
+  if (PyTuple_Size(args) != 0) {
+    PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
     return -1;
   }
 
-  PyObject* descriptor = PyTuple_GetItem(args, 0);
-  if (descriptor == NULL || PyTuple_Size(args) != 1) {
-    PyErr_SetString(PyExc_ValueError, "args must contain one arg: descriptor");
-    return -1;
-  }
-
-  ScopedPyObjectPtr py_message_type(PyObject_GetAttr(descriptor, kfull_name));
-  if (py_message_type == NULL) {
-    return -1;
-  }
-
-  const char* message_type = PyString_AsString(py_message_type.get());
-  const google::protobuf::Message* message = CreateMessage(message_type);
-  if (message == NULL) {
-    return -1;
-  }
-
-  self->message = message->New();
-  self->owner.reset(self->message);
-
-  if (InitAttributes(self, descriptor, kwargs) < 0) {
-    return -1;
-  }
-  return 0;
+  return InitAttributes(self, kwargs);
 }
 
 // ---------------------------------------------------------------------
@@ -800,8 +1279,13 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->parent = NULL;
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
-                    const google::protobuf::FieldDescriptor* field_descriptor) {
+                    const FieldDescriptor* field_descriptor) {
     cmessage->parent = NULL;
     return 0;
   }
@@ -810,6 +1294,9 @@
 static void Dealloc(CMessage* self) {
   // Null out all weak references from children to this message.
   GOOGLE_CHECK_EQ(0, ForEachCompositeField(self, ClearWeakReferences()));
+  if (self->extensions) {
+    self->extensions->parent = NULL;
+  }
 
   Py_CLEAR(self->extensions);
   Py_CLEAR(self->composite_fields);
@@ -851,14 +1338,12 @@
 }
 
 PyObject* HasFieldByDescriptor(
-    CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor) {
-  google::protobuf::Message* message = self->message;
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(PyExc_KeyError,
-                    "Field does not belong to message!");
+    CMessage* self, const FieldDescriptor* field_descriptor) {
+  Message* message = self->message;
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
     return NULL;
   }
-  if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
+  if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     PyErr_SetString(PyExc_KeyError,
                     "Field is repeated. A singular method is required.");
     return NULL;
@@ -868,42 +1353,78 @@
   return PyBool_FromLong(has_field ? 1 : 0);
 }
 
-const google::protobuf::FieldDescriptor* FindFieldWithOneofs(
-    const google::protobuf::Message* message, const char* field_name, bool* in_oneof) {
-  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
-  const google::protobuf::FieldDescriptor* field_descriptor =
+const FieldDescriptor* FindFieldWithOneofs(
+    const Message* message, const string& field_name, bool* in_oneof) {
+  *in_oneof = false;
+  const Descriptor* descriptor = message->GetDescriptor();
+  const FieldDescriptor* field_descriptor =
       descriptor->FindFieldByName(field_name);
-  if (field_descriptor == NULL) {
-    const google::protobuf::OneofDescriptor* oneof_desc =
-      message->GetDescriptor()->FindOneofByName(field_name);
-    if (oneof_desc == NULL) {
-      *in_oneof = false;
-      return NULL;
-    } else {
-      *in_oneof = true;
-      return message->GetReflection()->GetOneofFieldDescriptor(
-          *message, oneof_desc);
+  if (field_descriptor != NULL) {
+    return field_descriptor;
+  }
+  const OneofDescriptor* oneof_desc =
+      descriptor->FindOneofByName(field_name);
+  if (oneof_desc != NULL) {
+    *in_oneof = true;
+    return message->GetReflection()->GetOneofFieldDescriptor(*message,
+                                                             oneof_desc);
+  }
+  return NULL;
+}
+
+bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
+  if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    PyErr_Format(PyExc_ValueError,
+                 "Protocol message has no singular \"%s\" field.",
+                 field_descriptor->name().c_str());
+    return false;
+  }
+
+  if (field_descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    // HasField() for a oneof *itself* isn't supported.
+    if (in_oneof) {
+      PyErr_Format(PyExc_ValueError,
+                   "Can't test oneof field \"%s\" for presence in proto3, use "
+                   "WhichOneof instead.",
+                   field_descriptor->containing_oneof()->name().c_str());
+      return false;
+    }
+
+    // ...but HasField() for fields *in* a oneof is supported.
+    if (field_descriptor->containing_oneof() != NULL) {
+      return true;
+    }
+
+    if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+      PyErr_Format(
+          PyExc_ValueError,
+          "Can't test non-submessage field \"%s\" for presence in proto3.",
+          field_descriptor->name().c_str());
+      return false;
     }
   }
-  return field_descriptor;
+
+  return true;
 }
 
 PyObject* HasField(CMessage* self, PyObject* arg) {
-#if PY_MAJOR_VERSION < 3
   char* field_name;
-  if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
-#else
-  char* field_name = PyUnicode_AsUTF8(arg);
-  if (!field_name) {
-#endif
+  Py_ssize_t size;
+#if PY_MAJOR_VERSION < 3
+  if (PyString_AsStringAndSize(arg, &field_name, &size) < 0) {
     return NULL;
   }
+#else
+  field_name = PyUnicode_AsUTF8AndSize(arg, &size);
+  if (!field_name) {
+    return NULL;
+  }
+#endif
 
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
+  Message* message = self->message;
   bool is_in_oneof;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      FindFieldWithOneofs(message, field_name, &is_in_oneof);
+  const FieldDescriptor* field_descriptor =
+      FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
   if (field_descriptor == NULL) {
     if (!is_in_oneof) {
       PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
@@ -913,44 +1434,51 @@
     }
   }
 
-  if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
-    PyErr_Format(PyExc_ValueError,
-                 "Protocol message has no singular \"%s\" field.", field_name);
+  if (!CheckHasPresence(field_descriptor, is_in_oneof)) {
     return NULL;
   }
 
-  bool has_field =
-      message->GetReflection()->HasField(*message, field_descriptor);
-  if (!has_field && field_descriptor->cpp_type() ==
-      google::protobuf::FieldDescriptor::CPPTYPE_ENUM) {
-    // We may have an invalid enum value stored in the UnknownFieldSet and need
-    // to check presence in there as well.
-    const google::protobuf::UnknownFieldSet& unknown_field_set =
+  if (message->GetReflection()->HasField(*message, field_descriptor)) {
+    Py_RETURN_TRUE;
+  }
+  if (!message->GetReflection()->SupportsUnknownEnumValues() &&
+      field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+    // Special case: Python HasField() differs in semantics from C++
+    // slightly: we return HasField('enum_field') == true if there is
+    // an unknown enum value present. To implement this we have to
+    // look in the UnknownFieldSet.
+    const UnknownFieldSet& unknown_field_set =
         message->GetReflection()->GetUnknownFields(*message);
     for (int i = 0; i < unknown_field_set.field_count(); ++i) {
       if (unknown_field_set.field(i).number() == field_descriptor->number()) {
         Py_RETURN_TRUE;
       }
     }
-    Py_RETURN_FALSE;
   }
-  return PyBool_FromLong(has_field ? 1 : 0);
+  Py_RETURN_FALSE;
 }
 
-PyObject* ClearExtension(CMessage* self, PyObject* arg) {
+PyObject* ClearExtension(CMessage* self, PyObject* extension) {
   if (self->extensions != NULL) {
-    return extension_dict::ClearExtension(self->extensions, arg);
+    return extension_dict::ClearExtension(self->extensions, extension);
+  } else {
+    const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+    if (descriptor == NULL) {
+      return NULL;
+    }
+    if (ScopedPyObjectPtr(ClearFieldByDescriptor(self, descriptor)) == NULL) {
+      return NULL;
+    }
   }
-  PyErr_SetString(PyExc_TypeError, "Message is not extendable");
-  return NULL;
+  Py_RETURN_NONE;
 }
 
-PyObject* HasExtension(CMessage* self, PyObject* arg) {
-  if (self->extensions != NULL) {
-    return extension_dict::HasExtension(self->extensions, arg);
+PyObject* HasExtension(CMessage* self, PyObject* extension) {
+  const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+  if (descriptor == NULL) {
+    return NULL;
   }
-  PyErr_SetString(PyExc_TypeError, "Message is not extendable");
-  return NULL;
+  return HasFieldByDescriptor(self, descriptor);
 }
 
 // ---------------------------------------------------------------------
@@ -1000,8 +1528,13 @@
     return 0;
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    container->SetOwner(new_owner_);
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
-                    const google::protobuf::FieldDescriptor* field_descriptor) {
+                    const FieldDescriptor* field_descriptor) {
     return SetOwner(cmessage, new_owner_);
   }
 
@@ -1020,18 +1553,18 @@
 // Releases the message specified by 'field' and returns the
 // pointer. If the field does not exist a new message is created using
 // 'descriptor'. The caller takes ownership of the returned pointer.
-Message* ReleaseMessage(google::protobuf::Message* message,
-                        const google::protobuf::Descriptor* descriptor,
-                        const google::protobuf::FieldDescriptor* field_descriptor) {
-  Message* released_message = message->GetReflection()->ReleaseMessage(
-      message, field_descriptor, global_message_factory);
+Message* ReleaseMessage(CMessage* self,
+                        const Descriptor* descriptor,
+                        const FieldDescriptor* field_descriptor) {
+  MessageFactory* message_factory = GetFactoryForMessage(self);
+  Message* released_message = self->message->GetReflection()->ReleaseMessage(
+      self->message, field_descriptor, message_factory);
   // ReleaseMessage will return NULL which differs from
   // child_cmessage->message, if the field does not exist.  In this case,
   // the latter points to the default instance via a const_cast<>, so we
   // have to reset it to a new mutable object since we are taking ownership.
   if (released_message == NULL) {
-    const Message* prototype = global_message_factory->GetPrototype(
-        descriptor);
+    const Message* prototype = message_factory->GetPrototype(descriptor);
     GOOGLE_DCHECK(prototype != NULL);
     released_message = prototype->New();
   }
@@ -1039,16 +1572,16 @@
   return released_message;
 }
 
-int ReleaseSubMessage(google::protobuf::Message* message,
-                      const google::protobuf::FieldDescriptor* field_descriptor,
+int ReleaseSubMessage(CMessage* self,
+                      const FieldDescriptor* field_descriptor,
                       CMessage* child_cmessage) {
   // Release the Message
   shared_ptr<Message> released_message(ReleaseMessage(
-      message, child_cmessage->message->GetDescriptor(), field_descriptor));
+      self, child_cmessage->message->GetDescriptor(), field_descriptor));
   child_cmessage->message = released_message.get();
   child_cmessage->owner.swap(released_message);
   child_cmessage->parent = NULL;
-  child_cmessage->parent_field = NULL;
+  child_cmessage->parent_field_descriptor = NULL;
   child_cmessage->read_only = false;
   return ForEachCompositeField(child_cmessage,
                                SetOwnerVisitor(child_cmessage->owner));
@@ -1056,8 +1589,8 @@
 
 struct ReleaseChild : public ChildVisitor {
   // message must outlive this object.
-  explicit ReleaseChild(google::protobuf::Message* parent_message) :
-      parent_message_(parent_message) {}
+  explicit ReleaseChild(CMessage* parent) :
+      parent_(parent) {}
 
   int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
     return repeated_composite_container::Release(
@@ -1069,44 +1602,33 @@
         reinterpret_cast<RepeatedScalarContainer*>(container));
   }
 
+  int VisitMapContainer(MapContainer* container) {
+    return reinterpret_cast<MapContainer*>(container)->Release();
+  }
+
   int VisitCMessage(CMessage* cmessage,
-                    const google::protobuf::FieldDescriptor* field_descriptor) {
-    return ReleaseSubMessage(parent_message_, field_descriptor,
+                    const FieldDescriptor* field_descriptor) {
+    return ReleaseSubMessage(parent_, field_descriptor,
         reinterpret_cast<CMessage*>(cmessage));
   }
 
-  google::protobuf::Message* parent_message_;
+  CMessage* parent_;
 };
 
 int InternalReleaseFieldByDescriptor(
-    const google::protobuf::FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    google::protobuf::Message* parent_message) {
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
+    PyObject* composite_field) {
   return VisitCompositeField(
       field_descriptor,
       composite_field,
-      ReleaseChild(parent_message));
-}
-
-int InternalReleaseField(CMessage* self, PyObject* composite_field,
-                         PyObject* name) {
-  PyObject* cdescriptor = GetDescriptor(self, name);
-  if (cdescriptor != NULL) {
-    const google::protobuf::FieldDescriptor* descriptor =
-        reinterpret_cast<CFieldDescriptor*>(cdescriptor)->descriptor;
-    return InternalReleaseFieldByDescriptor(
-        descriptor, composite_field, self->message);
-  }
-
-  return 0;
+      ReleaseChild(self));
 }
 
 PyObject* ClearFieldByDescriptor(
     CMessage* self,
-    const google::protobuf::FieldDescriptor* descriptor) {
-  if (!FIELD_BELONGS_TO_MESSAGE(descriptor, self->message)) {
-    PyErr_SetString(PyExc_KeyError,
-                    "Field does not belong to message!");
+    const FieldDescriptor* descriptor) {
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
     return NULL;
   }
   AssureWritable(self);
@@ -1115,25 +1637,23 @@
 }
 
 PyObject* ClearField(CMessage* self, PyObject* arg) {
-  char* field_name;
   if (!PyString_Check(arg)) {
     PyErr_SetString(PyExc_TypeError, "field name must be a string");
     return NULL;
   }
 #if PY_MAJOR_VERSION < 3
-  if (PyString_AsStringAndSize(arg, &field_name, NULL) < 0) {
-    return NULL;
-  }
+  const char* field_name = PyString_AS_STRING(arg);
+  Py_ssize_t size = PyString_GET_SIZE(arg);
 #else
-  field_name = PyUnicode_AsUTF8(arg);
+  Py_ssize_t size;
+  const char* field_name = PyUnicode_AsUTF8AndSize(arg, &size);
 #endif
   AssureWritable(self);
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Descriptor* descriptor = message->GetDescriptor();
+  Message* message = self->message;
   ScopedPyObjectPtr arg_in_oneof;
   bool is_in_oneof;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      FindFieldWithOneofs(message, field_name, &is_in_oneof);
+  const FieldDescriptor* field_descriptor =
+      FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
   if (field_descriptor == NULL) {
     if (!is_in_oneof) {
       PyErr_Format(PyExc_ValueError,
@@ -1143,24 +1663,27 @@
       Py_RETURN_NONE;
     }
   } else if (is_in_oneof) {
-    arg_in_oneof.reset(PyString_FromString(field_descriptor->name().c_str()));
+    const string& name = field_descriptor->name();
+    arg_in_oneof.reset(PyString_FromStringAndSize(name.c_str(), name.size()));
     arg = arg_in_oneof.get();
   }
 
-  PyObject* composite_field = PyDict_GetItem(self->composite_fields,
-                                             arg);
+  PyObject* composite_field = self->composite_fields ?
+      PyDict_GetItem(self->composite_fields, arg) : NULL;
 
   // Only release the field if there's a possibility that there are
   // references to it.
   if (composite_field != NULL) {
-    if (InternalReleaseField(self, composite_field, arg) < 0) {
+    if (InternalReleaseFieldByDescriptor(self, field_descriptor,
+                                         composite_field) < 0) {
       return NULL;
     }
     PyDict_DelItem(self->composite_fields, arg);
   }
   message->GetReflection()->ClearField(message, field_descriptor);
-  if (field_descriptor->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_ENUM) {
-    google::protobuf::UnknownFieldSet* unknown_field_set =
+  if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+      !message->GetReflection()->SupportsUnknownEnumValues()) {
+    UnknownFieldSet* unknown_field_set =
         message->GetReflection()->MutableUnknownFields(message);
     unknown_field_set->DeleteByNumber(field_descriptor->number());
   }
@@ -1170,25 +1693,12 @@
 
 PyObject* Clear(CMessage* self) {
   AssureWritable(self);
-  if (ForEachCompositeField(self, ReleaseChild(self->message)) == -1)
+  if (ForEachCompositeField(self, ReleaseChild(self)) == -1)
     return NULL;
-
-  // The old ExtensionDict still aliases this CMessage, but all its
-  // fields have been released.
-  if (self->extensions != NULL) {
-    Py_CLEAR(self->extensions);
-    PyObject* py_extension_dict = PyObject_CallObject(
-        reinterpret_cast<PyObject*>(&ExtensionDict_Type), NULL);
-    if (py_extension_dict == NULL) {
-      return NULL;
-    }
-    ExtensionDict* extension_dict = reinterpret_cast<ExtensionDict*>(
-        py_extension_dict);
-    extension_dict->parent = self;
-    extension_dict->message = self->message;
-    self->extensions = extension_dict;
+  Py_CLEAR(self->extensions);
+  if (self->composite_fields) {
+    PyDict_Clear(self->composite_fields);
   }
-  PyDict_Clear(self->composite_fields);
   self->message->Clear();
   Py_RETURN_NONE;
 }
@@ -1196,8 +1706,8 @@
 // ---------------------------------------------------------------------
 
 static string GetMessageName(CMessage* self) {
-  if (self->parent_field != NULL) {
-    return self->parent_field->descriptor->full_name();
+  if (self->parent_field_descriptor != NULL) {
+    return self->parent_field_descriptor->full_name();
   } else {
     return self->message->GetDescriptor()->full_name();
   }
@@ -1218,7 +1728,27 @@
     if (joined == NULL) {
       return NULL;
     }
-    PyErr_Format(EncodeError_class, "Message %s is missing required fields: %s",
+
+    // TODO(haberman): this is a (hopefully temporary) hack.  The unit testing
+    // infrastructure reloads all pure-Python modules for every test, but not
+    // C++ modules (because that's generally impossible:
+    // http://bugs.python.org/issue1144263).  But if we cache EncodeError, we'll
+    // return the EncodeError from a previous load of the module, which won't
+    // match a user's attempt to catch EncodeError.  So we have to look it up
+    // again every time.
+    ScopedPyObjectPtr message_module(PyImport_ImportModule(
+        "google.protobuf.message"));
+    if (message_module.get() == NULL) {
+      return NULL;
+    }
+
+    ScopedPyObjectPtr encode_error(
+        PyObject_GetAttrString(message_module.get(), "EncodeError"));
+    if (encode_error.get() == NULL) {
+      return NULL;
+    }
+    PyErr_Format(encode_error.get(),
+                 "Message %s is missing required fields: %s",
                  GetMessageName(self).c_str(), PyString_AsString(joined.get()));
     return NULL;
   }
@@ -1244,40 +1774,44 @@
 
 // Formats proto fields for ascii dumps using python formatting functions where
 // appropriate.
-class PythonFieldValuePrinter : public google::protobuf::TextFormat::FieldValuePrinter {
+class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
-  PythonFieldValuePrinter() : float_holder_(PyFloat_FromDouble(0)) {}
-
   // Python has some differences from C++ when printing floating point numbers.
   //
   // 1) Trailing .0 is always printed.
-  // 2) Outputted is rounded to 12 digits.
+  // 2) (Python2) Output is rounded to 12 digits.
+  // 3) (Python3) The full precision of the double is preserved (and Python uses
+  //    David M. Gay's dtoa(), when the C++ code uses SimpleDtoa. There are some
+  //    differences, but they rarely happen)
   //
   // We override floating point printing with the C-API function for printing
   // Python floats to ensure consistency.
   string PrintFloat(float value) const { return PrintDouble(value); }
   string PrintDouble(double value) const {
-    reinterpret_cast<PyFloatObject*>(float_holder_.get())->ob_fval = value;
-    ScopedPyObjectPtr s(PyObject_Str(float_holder_.get()));
-    if (s == NULL) return string();
-#if PY_MAJOR_VERSION < 3
-    char *cstr = PyBytes_AS_STRING(static_cast<PyObject*>(s));
-#else
-    char *cstr = PyUnicode_AsUTF8(s);
-#endif
-    return string(cstr);
-  }
+    // This implementation is not highly optimized (it allocates two temporary
+    // Python objects) but it is simple and portable.  If this is shown to be a
+    // performance bottleneck, we can optimize it, but the results will likely
+    // be more complicated to accommodate the differing behavior of double
+    // formatting between Python 2 and Python 3.
+    //
+    // (Though a valid question is: do we really want to make out output
+    // dependent on the Python version?)
+    ScopedPyObjectPtr py_value(PyFloat_FromDouble(value));
+    if (!py_value.get()) {
+      return string();
+    }
 
- private:
-  // Holder for a python float object which we use to allow us to use
-  // the Python API for printing doubles. We initialize once and then
-  // directly modify it for every float printed to save on allocations
-  // and refcounting.
-  ScopedPyObjectPtr float_holder_;
+    ScopedPyObjectPtr py_str(PyObject_Str(py_value.get()));
+    if (!py_str.get()) {
+      return string();
+    }
+
+    return string(PyString_AsString(py_str.get()));
+  }
 };
 
 static PyObject* ToStr(CMessage* self) {
-  google::protobuf::TextFormat::Printer printer;
+  TextFormat::Printer printer;
   // Passes ownership
   printer.SetDefaultFieldValuePrinter(new PythonFieldValuePrinter());
   printer.SetHideUnknownFields(true);
@@ -1291,8 +1825,12 @@
 
 PyObject* MergeFrom(CMessage* self, PyObject* arg) {
   CMessage* other_message;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a message");
+  if (!PyObject_TypeCheck(arg, &CMessage_Type)) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to MergeFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 Py_TYPE(arg)->tp_name);
     return NULL;
   }
 
@@ -1300,8 +1838,8 @@
   if (other_message->message->GetDescriptor() !=
       self->message->GetDescriptor()) {
     PyErr_Format(PyExc_TypeError,
-                 "Tried to merge from a message with a different type. "
-                 "to: %s, from: %s",
+                 "Parameter to MergeFrom() must be instance of same class: "
+                 "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  other_message->message->GetDescriptor()->full_name().c_str());
     return NULL;
@@ -1319,8 +1857,12 @@
 
 static PyObject* CopyFrom(CMessage* self, PyObject* arg) {
   CMessage* other_message;
-  if (!PyObject_TypeCheck(reinterpret_cast<PyObject *>(arg), &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Must be a message");
+  if (!PyObject_TypeCheck(arg, &CMessage_Type)) {
+    PyErr_Format(PyExc_TypeError,
+                 "Parameter to CopyFrom() must be instance of same class: "
+                 "expected %s got %s.",
+                 self->message->GetDescriptor()->full_name().c_str(),
+                 Py_TYPE(arg)->tp_name);
     return NULL;
   }
 
@@ -1333,8 +1875,8 @@
   if (other_message->message->GetDescriptor() !=
       self->message->GetDescriptor()) {
     PyErr_Format(PyExc_TypeError,
-                 "Tried to copy from a message with a different type. "
-                 "to: %s, from: %s",
+                 "Parameter to CopyFrom() must be instance of same class: "
+                 "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  other_message->message->GetDescriptor()->full_name().c_str());
     return NULL;
@@ -1344,13 +1886,37 @@
 
   // CopyFrom on the message will not clean up self->composite_fields,
   // which can leave us in an inconsistent state, so clear it out here.
-  Clear(self);
+  (void)ScopedPyObjectPtr(Clear(self));
 
   self->message->CopyFrom(*other_message->message);
 
   Py_RETURN_NONE;
 }
 
+// Protobuf has a 64MB limit built in, this variable will override this. Please
+// do not enable this unless you fully understand the implications: protobufs
+// must all be kept in memory at the same time, so if they grow too big you may
+// get OOM errors. The protobuf APIs do not provide any tools for processing
+// protobufs in chunks.  If you have protos this big you should break them up if
+// it is at all convenient to do so.
+static bool allow_oversize_protos = false;
+
+// Provide a method in the module to set allow_oversize_protos to a boolean
+// value. This method returns the newly value of allow_oversize_protos.
+static PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
+  if (!arg || !PyBool_Check(arg)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Argument to SetAllowOversizeProtos must be boolean");
+    return NULL;
+  }
+  allow_oversize_protos = PyObject_IsTrue(arg);
+  if (allow_oversize_protos) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
 static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
   const void* data;
   Py_ssize_t data_length;
@@ -1359,9 +1925,13 @@
   }
 
   AssureWritable(self);
-  google::protobuf::io::CodedInputStream input(
+  io::CodedInputStream input(
       reinterpret_cast<const uint8*>(data), data_length);
-  input.SetExtensionRegistry(GetDescriptorPool(), global_message_factory);
+  if (allow_oversize_protos) {
+    input.SetTotalBytesLimit(INT_MAX, INT_MAX);
+  }
+  PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
+  input.SetExtensionRegistry(pool->pool, pool->message_factory);
   bool success = self->message->MergePartialFromCodedStream(&input);
   if (success) {
     return PyInt_FromLong(input.CurrentPosition());
@@ -1372,7 +1942,7 @@
 }
 
 static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
-  if (Clear(self) == NULL) {
+  if (ScopedPyObjectPtr(Clear(self)) == NULL) {
     return NULL;
   }
   return MergeFromString(self, arg);
@@ -1384,14 +1954,12 @@
 
 static PyObject* RegisterExtension(PyObject* cls,
                                    PyObject* extension_handle) {
-  ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
-  if (message_descriptor == NULL) {
+  const FieldDescriptor* descriptor =
+      GetExtensionDescriptor(extension_handle);
+  if (descriptor == NULL) {
     return NULL;
   }
-  if (PyObject_SetAttrString(extension_handle, "containing_type",
-                             message_descriptor) < 0) {
-    return NULL;
-  }
+
   ScopedPyObjectPtr extensions_by_name(
       PyObject_GetAttr(cls, k_extensions_by_name));
   if (extensions_by_name == NULL) {
@@ -1402,7 +1970,23 @@
   if (full_name == NULL) {
     return NULL;
   }
-  if (PyDict_SetItem(extensions_by_name, full_name, extension_handle) < 0) {
+
+  // If the extension was already registered, check that it is the same.
+  PyObject* existing_extension =
+      PyDict_GetItem(extensions_by_name.get(), full_name.get());
+  if (existing_extension != NULL) {
+    const FieldDescriptor* existing_extension_descriptor =
+        GetExtensionDescriptor(existing_extension);
+    if (existing_extension_descriptor != descriptor) {
+      PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
+      return NULL;
+    }
+    // Nothing else to do.
+    Py_RETURN_NONE;
+  }
+
+  if (PyDict_SetItem(extensions_by_name.get(), full_name.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
@@ -1413,36 +1997,52 @@
     PyErr_SetString(PyExc_TypeError, "no extensions_by_number on class");
     return NULL;
   }
+
   ScopedPyObjectPtr number(PyObject_GetAttrString(extension_handle, "number"));
   if (number == NULL) {
     return NULL;
   }
-  if (PyDict_SetItem(extensions_by_number, number, extension_handle) < 0) {
+
+  // If the extension was already registered by number, check that it is the
+  // same.
+  existing_extension = PyDict_GetItem(extensions_by_number.get(), number.get());
+  if (existing_extension != NULL) {
+    const FieldDescriptor* existing_extension_descriptor =
+        GetExtensionDescriptor(existing_extension);
+    if (existing_extension_descriptor != descriptor) {
+      const Descriptor* msg_desc = GetMessageDescriptor(
+          reinterpret_cast<PyTypeObject*>(cls));
+      PyErr_Format(
+          PyExc_ValueError,
+          "Extensions \"%s\" and \"%s\" both try to extend message type "
+          "\"%s\" with field number %ld.",
+          existing_extension_descriptor->full_name().c_str(),
+          descriptor->full_name().c_str(),
+          msg_desc->full_name().c_str(),
+          PyInt_AsLong(number.get()));
+      return NULL;
+    }
+    // Nothing else to do.
+    Py_RETURN_NONE;
+  }
+  if (PyDict_SetItem(extensions_by_number.get(), number.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
-  CFieldDescriptor* cdescriptor =
-      extension_dict::InternalGetCDescriptorFromExtension(extension_handle);
-  ScopedPyObjectPtr py_cdescriptor(reinterpret_cast<PyObject*>(cdescriptor));
-  if (cdescriptor == NULL) {
-    return NULL;
-  }
-  Py_INCREF(extension_handle);
-  cdescriptor->descriptor_field = extension_handle;
-  const google::protobuf::FieldDescriptor* descriptor = cdescriptor->descriptor;
   // Check if it's a message set
   if (descriptor->is_extension() &&
       descriptor->containing_type()->options().message_set_wire_format() &&
-      descriptor->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE &&
-      descriptor->message_type() == descriptor->extension_scope() &&
-      descriptor->label() == google::protobuf::FieldDescriptor::LABEL_OPTIONAL) {
+      descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+      descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) {
     ScopedPyObjectPtr message_name(PyString_FromStringAndSize(
         descriptor->message_type()->full_name().c_str(),
         descriptor->message_type()->full_name().size()));
     if (message_name == NULL) {
       return NULL;
     }
-    PyDict_SetItem(extensions_by_name, message_name, extension_handle);
+    PyDict_SetItem(extensions_by_name.get(), message_name.get(),
+                   extension_handle);
   }
 
   Py_RETURN_NONE;
@@ -1454,53 +2054,38 @@
 }
 
 static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
-  char* oneof_name;
-  if (!PyString_Check(arg)) {
-    PyErr_SetString(PyExc_TypeError, "field name must be a string");
+  Py_ssize_t name_size;
+  char *name_data;
+  if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0)
     return NULL;
-  }
-  oneof_name = PyString_AsString(arg);
-  if (oneof_name == NULL) {
-    return NULL;
-  }
-  const google::protobuf::OneofDescriptor* oneof_desc =
+  string oneof_name = string(name_data, name_size);
+  const OneofDescriptor* oneof_desc =
       self->message->GetDescriptor()->FindOneofByName(oneof_name);
   if (oneof_desc == NULL) {
     PyErr_Format(PyExc_ValueError,
-                 "Protocol message has no oneof \"%s\" field.", oneof_name);
+                 "Protocol message has no oneof \"%s\" field.",
+                 oneof_name.c_str());
     return NULL;
   }
-  const google::protobuf::FieldDescriptor* field_in_oneof =
+  const FieldDescriptor* field_in_oneof =
       self->message->GetReflection()->GetOneofFieldDescriptor(
           *self->message, oneof_desc);
   if (field_in_oneof == NULL) {
     Py_RETURN_NONE;
   } else {
-    return PyString_FromString(field_in_oneof->name().c_str());
+    const string& name = field_in_oneof->name();
+    return PyString_FromStringAndSize(name.c_str(), name.size());
   }
 }
 
+static PyObject* GetExtensionDict(CMessage* self, void *closure);
+
 static PyObject* ListFields(CMessage* self) {
-  vector<const google::protobuf::FieldDescriptor*> fields;
+  vector<const FieldDescriptor*> fields;
   self->message->GetReflection()->ListFields(*self->message, &fields);
 
-  PyObject* descriptor = PyDict_GetItem(Py_TYPE(self)->tp_dict, kDESCRIPTOR);
-  if (descriptor == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr fields_by_name(
-      PyObject_GetAttr(descriptor, kfields_by_name));
-  if (fields_by_name == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr extensions_by_name(PyObject_GetAttr(
-      reinterpret_cast<PyObject*>(Py_TYPE(self)), k_extensions_by_name));
-  if (extensions_by_name == NULL) {
-    PyErr_SetString(PyExc_ValueError, "no extensionsbyname");
-    return NULL;
-  }
   // Normally, the list will be exactly the size of the fields.
-  PyObject* all_fields = PyList_New(fields.size());
+  ScopedPyObjectPtr all_fields(PyList_New(fields.size()));
   if (all_fields == NULL) {
     return NULL;
   }
@@ -1509,75 +2094,84 @@
   // the field information.  Thus the actual size of the py list will be
   // smaller than the size of fields.  Set the actual size at the end.
   Py_ssize_t actual_size = 0;
-  for (Py_ssize_t i = 0; i < fields.size(); ++i) {
+  for (size_t i = 0; i < fields.size(); ++i) {
     ScopedPyObjectPtr t(PyTuple_New(2));
     if (t == NULL) {
-      Py_DECREF(all_fields);
       return NULL;
     }
 
     if (fields[i]->is_extension()) {
-      const string& field_name = fields[i]->full_name();
-      PyObject* extension_field = PyDict_GetItemString(extensions_by_name,
-                                                       field_name.c_str());
+      ScopedPyObjectPtr extension_field(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (extension_field == NULL) {
-        // If we couldn't fetch extension_field, it means the module that
-        // defines this extension has not been explicitly imported in Python
-        // code, and the extension hasn't been registered. There's nothing much
-        // we can do about this, so just skip it in the output to match the
-        // behavior of the python implementation.
+        return NULL;
+      }
+      // With C++ descriptors, the field can always be retrieved, but for
+      // unknown extensions which have not been imported in Python code, there
+      // is no message class and we cannot retrieve the value.
+      // TODO(amauryfa): consider building the class on the fly!
+      if (fields[i]->message_type() != NULL &&
+          cdescriptor_pool::GetMessageClass(
+              GetDescriptorPoolForMessage(self),
+              fields[i]->message_type()) == NULL) {
+        PyErr_Clear();
         continue;
       }
-      PyObject* extensions = reinterpret_cast<PyObject*>(self->extensions);
+      ScopedPyObjectPtr extensions(GetExtensionDict(self, NULL));
       if (extensions == NULL) {
-        Py_DECREF(all_fields);
         return NULL;
       }
       // 'extension' reference later stolen by PyTuple_SET_ITEM.
-      PyObject* extension = PyObject_GetItem(extensions, extension_field);
+      PyObject* extension = PyObject_GetItem(
+          extensions.get(), extension_field.get());
       if (extension == NULL) {
-        Py_DECREF(all_fields);
         return NULL;
       }
-      Py_INCREF(extension_field);
-      PyTuple_SET_ITEM(t.get(), 0, extension_field);
+      PyTuple_SET_ITEM(t.get(), 0, extension_field.release());
       // Steals reference to 'extension'
       PyTuple_SET_ITEM(t.get(), 1, extension);
     } else {
+      // Normal field
       const string& field_name = fields[i]->name();
       ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize(
           field_name.c_str(), field_name.length()));
       if (py_field_name == NULL) {
         PyErr_SetString(PyExc_ValueError, "bad string");
-        Py_DECREF(all_fields);
         return NULL;
       }
-      PyObject* field_descriptor =
-          PyDict_GetItem(fields_by_name, py_field_name);
+      ScopedPyObjectPtr field_descriptor(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (field_descriptor == NULL) {
-        Py_DECREF(all_fields);
         return NULL;
       }
 
-      PyObject* field_value = GetAttr(self, py_field_name);
+      PyObject* field_value = GetAttr(self, py_field_name.get());
       if (field_value == NULL) {
-        PyErr_SetObject(PyExc_ValueError, py_field_name);
-        Py_DECREF(all_fields);
+        PyErr_SetObject(PyExc_ValueError, py_field_name.get());
         return NULL;
       }
-      Py_INCREF(field_descriptor);
-      PyTuple_SET_ITEM(t.get(), 0, field_descriptor);
+      PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
       PyTuple_SET_ITEM(t.get(), 1, field_value);
     }
-    PyList_SET_ITEM(all_fields, actual_size, t.release());
+    PyList_SET_ITEM(all_fields.get(), actual_size, t.release());
     ++actual_size;
   }
-  Py_SIZE(all_fields) = actual_size;
-  return all_fields;
+  if (static_cast<size_t>(actual_size) != fields.size() &&
+      (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) <
+       0)) {
+    return NULL;
+  }
+  return all_fields.release();
+}
+
+static PyObject* DiscardUnknownFields(CMessage* self) {
+  AssureWritable(self);
+  self->message->DiscardUnknownFields();
+  Py_RETURN_NONE;
 }
 
 PyObject* FindInitializationErrors(CMessage* self) {
-  google::protobuf::Message* message = self->message;
+  Message* message = self->message;
   vector<string> errors;
   message->FindInitializationErrors(&errors);
 
@@ -1585,7 +2179,7 @@
   if (error_list == NULL) {
     return NULL;
   }
-  for (Py_ssize_t i = 0; i < errors.size(); ++i) {
+  for (size_t i = 0; i < errors.size(); ++i) {
     const string& error = errors[i];
     PyObject* error_string = PyString_FromStringAndSize(
         error.c_str(), error.length());
@@ -1599,94 +2193,105 @@
 }
 
 static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) {
-  if (!PyObject_TypeCheck(other, &CMessage_Type)) {
-    if (opid == Py_EQ) {
-      Py_RETURN_FALSE;
-    } else if (opid == Py_NE) {
-      Py_RETURN_TRUE;
-    }
-  }
-  if (opid == Py_EQ || opid == Py_NE) {
-    ScopedPyObjectPtr self_fields(ListFields(self));
-    ScopedPyObjectPtr other_fields(ListFields(
-        reinterpret_cast<CMessage*>(other)));
-    return PyObject_RichCompare(self_fields, other_fields, opid);
-  } else {
+  // Only equality comparisons are implemented.
+  if (opid != Py_EQ && opid != Py_NE) {
     Py_INCREF(Py_NotImplemented);
     return Py_NotImplemented;
   }
+  bool equals = true;
+  // If other is not a message, it cannot be equal.
+  if (!PyObject_TypeCheck(other, &CMessage_Type)) {
+    equals = false;
+  }
+  const google::protobuf::Message* other_message =
+      reinterpret_cast<CMessage*>(other)->message;
+  // If messages don't have the same descriptors, they are not equal.
+  if (equals &&
+      self->message->GetDescriptor() != other_message->GetDescriptor()) {
+    equals = false;
+  }
+  // Check the message contents.
+  if (equals && !google::protobuf::util::MessageDifferencer::Equals(
+          *self->message,
+          *reinterpret_cast<CMessage*>(other)->message)) {
+    equals = false;
+  }
+  if (equals ^ (opid == Py_EQ)) {
+    Py_RETURN_FALSE;
+  } else {
+    Py_RETURN_TRUE;
+  }
 }
 
-PyObject* InternalGetScalar(
-    CMessage* self,
-    const google::protobuf::FieldDescriptor* field_descriptor) {
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+PyObject* InternalGetScalar(const Message* message,
+                            const FieldDescriptor* field_descriptor) {
+  const Reflection* reflection = message->GetReflection();
 
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
     return NULL;
   }
 
   PyObject* result = NULL;
   switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
+    case FieldDescriptor::CPPTYPE_INT32: {
       int32 value = reflection->GetInt32(*message, field_descriptor);
       result = PyInt_FromLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
+    case FieldDescriptor::CPPTYPE_INT64: {
       int64 value = reflection->GetInt64(*message, field_descriptor);
       result = PyLong_FromLongLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
+    case FieldDescriptor::CPPTYPE_UINT32: {
       uint32 value = reflection->GetUInt32(*message, field_descriptor);
       result = PyInt_FromSize_t(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
+    case FieldDescriptor::CPPTYPE_UINT64: {
       uint64 value = reflection->GetUInt64(*message, field_descriptor);
       result = PyLong_FromUnsignedLongLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
+    case FieldDescriptor::CPPTYPE_FLOAT: {
       float value = reflection->GetFloat(*message, field_descriptor);
       result = PyFloat_FromDouble(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
       double value = reflection->GetDouble(*message, field_descriptor);
       result = PyFloat_FromDouble(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
+    case FieldDescriptor::CPPTYPE_BOOL: {
       bool value = reflection->GetBool(*message, field_descriptor);
       result = PyBool_FromLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
+    case FieldDescriptor::CPPTYPE_STRING: {
       string value = reflection->GetString(*message, field_descriptor);
       result = ToStringObject(field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      if (!message->GetReflection()->HasField(*message, field_descriptor)) {
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      if (!message->GetReflection()->SupportsUnknownEnumValues() &&
+          !message->GetReflection()->HasField(*message, field_descriptor)) {
         // Look for the value in the unknown fields.
-        google::protobuf::UnknownFieldSet* unknown_field_set =
-            message->GetReflection()->MutableUnknownFields(message);
-        for (int i = 0; i < unknown_field_set->field_count(); ++i) {
-          if (unknown_field_set->field(i).number() ==
-              field_descriptor->number()) {
-            result = PyInt_FromLong(unknown_field_set->field(i).varint());
+        const UnknownFieldSet& unknown_field_set =
+            message->GetReflection()->GetUnknownFields(*message);
+        for (int i = 0; i < unknown_field_set.field_count(); ++i) {
+          if (unknown_field_set.field(i).number() ==
+              field_descriptor->number() &&
+              unknown_field_set.field(i).type() ==
+              google::protobuf::UnknownField::TYPE_VARINT) {
+            result = PyInt_FromLong(unknown_field_set.field(i).varint());
             break;
           }
         }
       }
 
       if (result == NULL) {
-        const google::protobuf::EnumValueDescriptor* enum_value =
+        const EnumValueDescriptor* enum_value =
             message->GetReflection()->GetEnum(*message, field_descriptor);
         result = PyInt_FromLong(enum_value->number());
       }
@@ -1701,116 +2306,100 @@
   return result;
 }
 
-PyObject* InternalGetSubMessage(CMessage* self,
-                                CFieldDescriptor* cfield_descriptor) {
-  PyObject* field = cfield_descriptor->descriptor_field;
-  ScopedPyObjectPtr message_type(PyObject_GetAttr(field, kmessage_type));
-  if (message_type == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr concrete_class(
-      PyObject_GetAttr(message_type, k_concrete_class));
-  if (concrete_class == NULL) {
-    return NULL;
-  }
-  PyObject* py_cmsg = cmessage::NewEmpty(concrete_class);
-  if (py_cmsg == NULL) {
-    return NULL;
-  }
-  if (!PyObject_TypeCheck(py_cmsg, &CMessage_Type)) {
-    PyErr_SetString(PyExc_TypeError, "Not a CMessage!");
-  }
-  CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+PyObject* InternalGetSubMessage(
+    CMessage* self, const FieldDescriptor* field_descriptor) {
+  const Reflection* reflection = self->message->GetReflection();
+  PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
+  const Message& sub_message = reflection->GetMessage(
+      *self->message, field_descriptor, pool->message_factory);
 
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      cfield_descriptor->descriptor;
-  const google::protobuf::Reflection* reflection = self->message->GetReflection();
-  const google::protobuf::Message& sub_message = reflection->GetMessage(
-      *self->message, field_descriptor, global_message_factory);
+  CMessageClass* message_class = cdescriptor_pool::GetMessageClass(
+      pool, field_descriptor->message_type());
+  if (message_class == NULL) {
+    return NULL;
+  }
+
+  CMessage* cmsg = cmessage::NewEmptyMessage(message_class);
+  if (cmsg == NULL) {
+    return NULL;
+  }
+
   cmsg->owner = self->owner;
   cmsg->parent = self;
-  cmsg->parent_field = cfield_descriptor;
+  cmsg->parent_field_descriptor = field_descriptor;
   cmsg->read_only = !reflection->HasField(*self->message, field_descriptor);
-  cmsg->message = const_cast<google::protobuf::Message*>(&sub_message);
+  cmsg->message = const_cast<Message*>(&sub_message);
 
-  if (InitAttributes(cmsg, NULL, NULL) < 0) {
-    Py_DECREF(py_cmsg);
-    return NULL;
-  }
-  return py_cmsg;
+  return reinterpret_cast<PyObject*>(cmsg);
 }
 
-int InternalSetScalar(
-    CMessage* self,
-    const google::protobuf::FieldDescriptor* field_descriptor,
+int InternalSetNonOneofScalar(
+    Message* message,
+    const FieldDescriptor* field_descriptor,
     PyObject* arg) {
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  const Reflection* reflection = message->GetReflection();
 
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return -1;
-  }
-
-  if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
+  if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
     return -1;
   }
 
   switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
+    case FieldDescriptor::CPPTYPE_INT32: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
       reflection->SetInt32(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
+    case FieldDescriptor::CPPTYPE_INT64: {
       GOOGLE_CHECK_GET_INT64(arg, value, -1);
       reflection->SetInt64(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
+    case FieldDescriptor::CPPTYPE_UINT32: {
       GOOGLE_CHECK_GET_UINT32(arg, value, -1);
       reflection->SetUInt32(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
+    case FieldDescriptor::CPPTYPE_UINT64: {
       GOOGLE_CHECK_GET_UINT64(arg, value, -1);
       reflection->SetUInt64(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
+    case FieldDescriptor::CPPTYPE_FLOAT: {
       GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
       reflection->SetFloat(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
       GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
       reflection->SetDouble(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
+    case FieldDescriptor::CPPTYPE_BOOL: {
       GOOGLE_CHECK_GET_BOOL(arg, value, -1);
       reflection->SetBool(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
+    case FieldDescriptor::CPPTYPE_STRING: {
       if (!CheckAndSetString(
           arg, message, field_descriptor, reflection, false, -1)) {
         return -1;
       }
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
+    case FieldDescriptor::CPPTYPE_ENUM: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
-      const google::protobuf::EnumDescriptor* enum_descriptor =
-          field_descriptor->enum_type();
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          enum_descriptor->FindValueByNumber(value);
-      if (enum_value != NULL) {
-        reflection->SetEnum(message, field_descriptor, enum_value);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->SetEnumValue(message, field_descriptor, value);
       } else {
-        PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
-        return -1;
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != NULL) {
+          reflection->SetEnum(message, field_descriptor, enum_value);
+        } else {
+          PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
+          return -1;
+        }
       }
       break;
     }
@@ -1824,6 +2413,21 @@
   return 0;
 }
 
+int InternalSetScalar(
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
+    PyObject* arg) {
+  if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) {
+    return -1;
+  }
+
+  if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
+    return -1;
+  }
+
+  return InternalSetNonOneofScalar(self->message, field_descriptor, arg);
+}
+
 PyObject* FromString(PyTypeObject* cls, PyObject* serialized) {
   PyObject* py_cmsg = PyObject_CallObject(
       reinterpret_cast<PyObject*>(cls), NULL);
@@ -1838,197 +2442,9 @@
     return NULL;
   }
 
-  if (InitAttributes(cmsg, NULL, NULL) < 0) {
-    Py_DECREF(py_cmsg);
-    return NULL;
-  }
   return py_cmsg;
 }
 
-static PyObject* AddDescriptors(PyTypeObject* cls,
-                                PyObject* descriptor) {
-  if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                       k_extensions_by_name, PyDict_New()) < 0) {
-    return NULL;
-  }
-  if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                       k_extensions_by_number, PyDict_New()) < 0) {
-    return NULL;
-  }
-
-  ScopedPyObjectPtr field_descriptors(PyDict_New());
-
-  ScopedPyObjectPtr fields(PyObject_GetAttrString(descriptor, "fields"));
-  if (fields == NULL) {
-    return NULL;
-  }
-
-  ScopedPyObjectPtr _NUMBER_string(PyString_FromString("_FIELD_NUMBER"));
-  if (_NUMBER_string == NULL) {
-    return NULL;
-  }
-
-  const Py_ssize_t fields_size = PyList_GET_SIZE(fields.get());
-  for (int i = 0; i < fields_size; ++i) {
-    PyObject* field = PyList_GET_ITEM(fields.get(), i);
-    ScopedPyObjectPtr field_name(PyObject_GetAttr(field, kname));
-    ScopedPyObjectPtr full_field_name(PyObject_GetAttr(field, kfull_name));
-    if (field_name == NULL || full_field_name == NULL) {
-      PyErr_SetString(PyExc_TypeError, "Name is null");
-      return NULL;
-    }
-
-    PyObject* field_descriptor =
-        cdescriptor_pool::FindFieldByName(descriptor_pool, full_field_name);
-    if (field_descriptor == NULL) {
-      PyErr_SetString(PyExc_TypeError, "Couldn't find field");
-      return NULL;
-    }
-    Py_INCREF(field);
-    CFieldDescriptor* cfield_descriptor = reinterpret_cast<CFieldDescriptor*>(
-        field_descriptor);
-    cfield_descriptor->descriptor_field = field;
-    if (PyDict_SetItem(field_descriptors, field_name, field_descriptor) < 0) {
-      return NULL;
-    }
-
-    // The FieldDescriptor's name field might either be of type bytes or
-    // of type unicode, depending on whether the FieldDescriptor was
-    // parsed from a serialized message or read from the
-    // <message>_pb2.py module.
-    ScopedPyObjectPtr field_name_upcased(
-         PyObject_CallMethod(field_name, "upper", NULL));
-    if (field_name_upcased == NULL) {
-      return NULL;
-    }
-
-    ScopedPyObjectPtr field_number_name(PyObject_CallMethod(
-         field_name_upcased, "__add__", "(O)", _NUMBER_string.get()));
-    if (field_number_name == NULL) {
-      return NULL;
-    }
-
-    ScopedPyObjectPtr number(PyInt_FromLong(
-        cfield_descriptor->descriptor->number()));
-    if (number == NULL) {
-      return NULL;
-    }
-    if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                         field_number_name, number) == -1) {
-      return NULL;
-    }
-  }
-
-  PyDict_SetItem(cls->tp_dict, k__descriptors, field_descriptors);
-
-  // Enum Values
-  ScopedPyObjectPtr enum_types(PyObject_GetAttrString(descriptor,
-                                                      "enum_types"));
-  if (enum_types == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr type_iter(PyObject_GetIter(enum_types));
-  if (type_iter == NULL) {
-    return NULL;
-  }
-  ScopedPyObjectPtr enum_type;
-  while ((enum_type.reset(PyIter_Next(type_iter))) != NULL) {
-    ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
-        EnumTypeWrapper_class, enum_type.get(), NULL));
-    if (wrapped == NULL) {
-      return NULL;
-    }
-    ScopedPyObjectPtr enum_name(PyObject_GetAttr(enum_type, kname));
-    if (enum_name == NULL) {
-      return NULL;
-    }
-    if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                         enum_name, wrapped) == -1) {
-      return NULL;
-    }
-
-    ScopedPyObjectPtr enum_values(PyObject_GetAttrString(enum_type, "values"));
-    if (enum_values == NULL) {
-      return NULL;
-    }
-    ScopedPyObjectPtr values_iter(PyObject_GetIter(enum_values));
-    if (values_iter == NULL) {
-      return NULL;
-    }
-    ScopedPyObjectPtr enum_value;
-    while ((enum_value.reset(PyIter_Next(values_iter))) != NULL) {
-      ScopedPyObjectPtr value_name(PyObject_GetAttr(enum_value, kname));
-      if (value_name == NULL) {
-        return NULL;
-      }
-      ScopedPyObjectPtr value_number(PyObject_GetAttrString(enum_value,
-                                                            "number"));
-      if (value_number == NULL) {
-        return NULL;
-      }
-      if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                           value_name, value_number) == -1) {
-        return NULL;
-      }
-    }
-    if (PyErr_Occurred()) {  // If PyIter_Next failed
-      return NULL;
-    }
-  }
-  if (PyErr_Occurred()) {  // If PyIter_Next failed
-    return NULL;
-  }
-
-  ScopedPyObjectPtr extension_dict(
-      PyObject_GetAttr(descriptor, kextensions_by_name));
-  if (extension_dict == NULL || !PyDict_Check(extension_dict)) {
-    PyErr_SetString(PyExc_TypeError, "extensions_by_name not a dict");
-    return NULL;
-  }
-  Py_ssize_t pos = 0;
-  PyObject* extension_name;
-  PyObject* extension_field;
-
-  while (PyDict_Next(extension_dict, &pos, &extension_name, &extension_field)) {
-    if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                         extension_name, extension_field) == -1) {
-      return NULL;
-    }
-    ScopedPyObjectPtr py_cfield_descriptor(
-        PyObject_GetAttrString(extension_field, "_cdescriptor"));
-    if (py_cfield_descriptor == NULL) {
-      return NULL;
-    }
-    CFieldDescriptor* cfield_descriptor =
-        reinterpret_cast<CFieldDescriptor*>(py_cfield_descriptor.get());
-    Py_INCREF(extension_field);
-    cfield_descriptor->descriptor_field = extension_field;
-
-    ScopedPyObjectPtr field_name_upcased(
-        PyObject_CallMethod(extension_name, "upper", NULL));
-    if (field_name_upcased == NULL) {
-      return NULL;
-    }
-    ScopedPyObjectPtr field_number_name(PyObject_CallMethod(
-         field_name_upcased, "__add__", "(O)", _NUMBER_string.get()));
-    if (field_number_name == NULL) {
-      return NULL;
-    }
-    ScopedPyObjectPtr number(PyInt_FromLong(
-        cfield_descriptor->descriptor->number()));
-    if (number == NULL) {
-      return NULL;
-    }
-    if (PyObject_SetAttr(reinterpret_cast<PyObject*>(cls),
-                         field_number_name, PyInt_FromLong(
-            cfield_descriptor->descriptor->number())) == -1) {
-      return NULL;
-    }
-  }
-
-  Py_RETURN_NONE;
-}
-
 PyObject* DeepCopy(CMessage* self, PyObject* arg) {
   PyObject* clone = PyObject_CallObject(
       reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
@@ -2039,12 +2455,9 @@
     Py_DECREF(clone);
     return NULL;
   }
-  if (InitAttributes(reinterpret_cast<CMessage*>(clone), NULL, NULL) < 0) {
-    Py_DECREF(clone);
-    return NULL;
-  }
-  if (MergeFrom(reinterpret_cast<CMessage*>(clone),
-                reinterpret_cast<PyObject*>(self)) == NULL) {
+  if (ScopedPyObjectPtr(MergeFrom(
+          reinterpret_cast<CMessage*>(clone),
+          reinterpret_cast<PyObject*>(self))) == NULL) {
     Py_DECREF(clone);
     return NULL;
   }
@@ -2063,16 +2476,16 @@
     return NULL;
   }
   Py_INCREF(Py_True);
-  ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(text_format, method_name,
-                                                       self, Py_True, NULL));
+  ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(
+      text_format.get(), method_name.get(), self, Py_True, NULL));
   Py_DECREF(Py_True);
   if (encoded == NULL) {
     return NULL;
   }
 #if PY_MAJOR_VERSION < 3
-  PyObject* decoded = PyString_AsDecodedObject(encoded, "utf-8", NULL);
+  PyObject* decoded = PyString_AsDecodedObject(encoded.get(), "utf-8", NULL);
 #else
-  PyObject* decoded = PyUnicode_FromEncodedObject(encoded, "utf-8", NULL);
+  PyObject* decoded = PyUnicode_FromEncodedObject(encoded.get(), "utf-8", NULL);
 #endif
   if (decoded == NULL) {
     return NULL;
@@ -2095,7 +2508,7 @@
   if (serialized == NULL) {
     return NULL;
   }
-  if (PyDict_SetItemString(state, "serialized", serialized) < 0) {
+  if (PyDict_SetItemString(state.get(), "serialized", serialized.get()) < 0) {
     return NULL;
   }
   return Py_BuildValue("OOO", constructor.get(), args.get(), state.get());
@@ -2110,24 +2523,49 @@
   if (serialized == NULL) {
     return NULL;
   }
-  if (ParseFromString(self, serialized) == NULL) {
+  if (ScopedPyObjectPtr(ParseFromString(self, serialized)) == NULL) {
     return NULL;
   }
   Py_RETURN_NONE;
 }
 
 // CMessage static methods:
-PyObject* _GetFieldDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindFieldByName(descriptor_pool, arg);
+PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
+                                        PyObject* unused_arg) {
+  if (!_CalledFromGeneratedFile(1)) {
+    PyErr_SetString(PyExc_TypeError,
+                    "Descriptors should not be created directly, "
+                    "but only retrieved from their parent.");
+    return NULL;
+  }
+  Py_RETURN_NONE;
 }
 
-PyObject* _GetExtensionDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindExtensionByName(descriptor_pool, arg);
+static PyObject* GetExtensionDict(CMessage* self, void *closure) {
+  if (self->extensions)  {
+    Py_INCREF(self->extensions);
+    return reinterpret_cast<PyObject*>(self->extensions);
+  }
+
+  // If there are extension_ranges, the message is "extendable". Allocate a
+  // dictionary to store the extension fields.
+  const Descriptor* descriptor = GetMessageDescriptor(Py_TYPE(self));
+  if (descriptor->extension_range_count() > 0) {
+    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
+    if (extension_dict == NULL) {
+      return NULL;
+    }
+    self->extensions = extension_dict;
+    Py_INCREF(self->extensions);
+    return reinterpret_cast<PyObject*>(self->extensions);
+  }
+
+  PyErr_SetNone(PyExc_AttributeError);
+  return NULL;
 }
 
-static PyMemberDef Members[] = {
-  {"Extensions", T_OBJECT_EX, offsetof(CMessage, extensions), 0,
-   "Extension dict"},
+static PyGetSetDef Getters[] = {
+  {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"},
   {NULL}
 };
 
@@ -2140,8 +2578,6 @@
     "Inputs picklable representation of the message." },
   { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
     "Outputs a unicode representation of the message." },
-  { "AddDescriptors", (PyCFunction)AddDescriptors, METH_O | METH_CLASS,
-    "Adds field descriptors to the class" },
   { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
     "Returns the size of the message in bytes." },
   { "Clear", (PyCFunction)Clear, METH_NOARGS,
@@ -2152,6 +2588,8 @@
     "Clears a message field." },
   { "CopyFrom", (PyCFunction)CopyFrom, METH_O,
     "Copies a protocol message into the current message." },
+  { "DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS,
+    "Discards the unknown fields." },
   { "FindInitializationErrors", (PyCFunction)FindInitializationErrors,
     METH_NOARGS,
     "Finds unset required fields." },
@@ -2185,113 +2623,117 @@
     "or None if no field is set." },
 
   // Static Methods.
-  { "_BuildFile", (PyCFunction)Python_BuildFile, METH_O | METH_STATIC,
-    "Registers a new protocol buffer file in the global C++ descriptor pool." },
-  { "_GetFieldDescriptor", (PyCFunction)_GetFieldDescriptor,
-    METH_O | METH_STATIC, "Finds a field descriptor in the message pool." },
-  { "_GetExtensionDescriptor", (PyCFunction)_GetExtensionDescriptor,
-    METH_O | METH_STATIC,
-    "Finds a extension descriptor in the message pool." },
+  { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile,
+    METH_NOARGS | METH_STATIC,
+    "Raises TypeError if the caller is not in a _pb2.py file."},
   { NULL, NULL}
 };
 
+static bool SetCompositeField(
+    CMessage* self, PyObject* name, PyObject* value) {
+  if (self->composite_fields == NULL) {
+    self->composite_fields = PyDict_New();
+    if (self->composite_fields == NULL) {
+      return false;
+    }
+  }
+  return PyDict_SetItem(self->composite_fields, name, value) == 0;
+}
+
 PyObject* GetAttr(CMessage* self, PyObject* name) {
-  PyObject* value = PyDict_GetItem(self->composite_fields, name);
+  PyObject* value = self->composite_fields ?
+      PyDict_GetItem(self->composite_fields, name) : NULL;
   if (value != NULL) {
     Py_INCREF(value);
     return value;
   }
 
-  PyObject* descriptor = GetDescriptor(self, name);
-  if (descriptor != NULL) {
-    CFieldDescriptor* cdescriptor =
-        reinterpret_cast<CFieldDescriptor*>(descriptor);
-    const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor;
-    if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
-      if (field_descriptor->cpp_type() ==
-          google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
-        PyObject* py_container = PyObject_CallObject(
-            reinterpret_cast<PyObject*>(&RepeatedCompositeContainer_Type),
-            NULL);
-        if (py_container == NULL) {
-          return NULL;
-        }
-        RepeatedCompositeContainer* container =
-            reinterpret_cast<RepeatedCompositeContainer*>(py_container);
-        PyObject* field = cdescriptor->descriptor_field;
-        PyObject* message_type = PyObject_GetAttr(field, kmessage_type);
-        if (message_type == NULL) {
-          return NULL;
-        }
-        PyObject* concrete_class =
-            PyObject_GetAttr(message_type, k_concrete_class);
-        if (concrete_class == NULL) {
-          return NULL;
-        }
-        container->parent = self;
-        container->parent_field = cdescriptor;
-        container->message = self->message;
-        container->owner = self->owner;
-        container->subclass_init = concrete_class;
-        Py_DECREF(message_type);
-        if (PyDict_SetItem(self->composite_fields, name, py_container) < 0) {
-          Py_DECREF(py_container);
-          return NULL;
-        }
-        return py_container;
-      } else {
-        ScopedPyObjectPtr init_args(PyTuple_Pack(2, self, cdescriptor));
-        PyObject* py_container = PyObject_CallObject(
-            reinterpret_cast<PyObject*>(&RepeatedScalarContainer_Type),
-            init_args);
-        if (py_container == NULL) {
-          return NULL;
-        }
-        if (PyDict_SetItem(self->composite_fields, name, py_container) < 0) {
-          Py_DECREF(py_container);
-          return NULL;
-        }
-        return py_container;
-      }
-    } else {
-      if (field_descriptor->cpp_type() ==
-          google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
-        PyObject* sub_message = InternalGetSubMessage(self, cdescriptor);
-        if (PyDict_SetItem(self->composite_fields, name, sub_message) < 0) {
-          Py_DECREF(sub_message);
-          return NULL;
-        }
-        return sub_message;
-      } else {
-        return InternalGetScalar(self, field_descriptor);
-      }
-    }
+  const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name);
+  if (field_descriptor == NULL) {
+    return CMessage_Type.tp_base->tp_getattro(
+        reinterpret_cast<PyObject*>(self), name);
   }
 
-  return CMessage_Type.tp_base->tp_getattro(reinterpret_cast<PyObject*>(self),
-                                            name);
+  if (field_descriptor->is_map()) {
+    PyObject* py_container = NULL;
+    const Descriptor* entry_type = field_descriptor->message_type();
+    const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
+    if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      CMessageClass* value_class = cdescriptor_pool::GetMessageClass(
+          GetDescriptorPoolForMessage(self), value_type->message_type());
+      if (value_class == NULL) {
+        return NULL;
+      }
+      py_container =
+          NewMessageMapContainer(self, field_descriptor, value_class);
+    } else {
+      py_container = NewScalarMapContainer(self, field_descriptor);
+    }
+    if (py_container == NULL) {
+      return NULL;
+    }
+    if (!SetCompositeField(self, name, py_container)) {
+      Py_DECREF(py_container);
+      return NULL;
+    }
+    return py_container;
+  }
+
+  if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    PyObject* py_container = NULL;
+    if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      CMessageClass* message_class = cdescriptor_pool::GetMessageClass(
+          GetDescriptorPoolForMessage(self), field_descriptor->message_type());
+      if (message_class == NULL) {
+        return NULL;
+      }
+      py_container = repeated_composite_container::NewContainer(
+          self, field_descriptor, message_class);
+    } else {
+      py_container = repeated_scalar_container::NewContainer(
+          self, field_descriptor);
+    }
+    if (py_container == NULL) {
+      return NULL;
+    }
+    if (!SetCompositeField(self, name, py_container)) {
+      Py_DECREF(py_container);
+      return NULL;
+    }
+    return py_container;
+  }
+
+  if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    PyObject* sub_message = InternalGetSubMessage(self, field_descriptor);
+    if (sub_message == NULL) {
+      return NULL;
+    }
+    if (!SetCompositeField(self, name, sub_message)) {
+      Py_DECREF(sub_message);
+      return NULL;
+    }
+    return sub_message;
+  }
+
+  return InternalGetScalar(self->message, field_descriptor);
 }
 
 int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
-  if (PyDict_Contains(self->composite_fields, name)) {
+  if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) {
     PyErr_SetString(PyExc_TypeError, "Can't set composite field");
     return -1;
   }
 
-  PyObject* descriptor = GetDescriptor(self, name);
-  if (descriptor != NULL) {
+  const FieldDescriptor* field_descriptor = GetFieldDescriptor(self, name);
+  if (field_descriptor != NULL) {
     AssureWritable(self);
-    CFieldDescriptor* cdescriptor =
-        reinterpret_cast<CFieldDescriptor*>(descriptor);
-    const google::protobuf::FieldDescriptor* field_descriptor = cdescriptor->descriptor;
-    if (field_descriptor->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
+    if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
       PyErr_Format(PyExc_AttributeError, "Assignment not allowed to repeated "
                    "field \"%s\" in protocol message object.",
                    field_descriptor->name().c_str());
       return -1;
     } else {
-      if (field_descriptor->cpp_type() ==
-          google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
+      if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
         PyErr_Format(PyExc_AttributeError, "Assignment not allowed to "
                      "field \"%s\" in protocol message object.",
                      field_descriptor->name().c_str());
@@ -2302,16 +2744,18 @@
     }
   }
 
-  PyErr_Format(PyExc_AttributeError, "Assignment not allowed");
+  PyErr_Format(PyExc_AttributeError,
+               "Assignment not allowed "
+               "(no field \"%s\" in protocol message object).",
+               PyString_AsString(name));
   return -1;
 }
 
 }  // namespace cmessage
 
 PyTypeObject CMessage_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-  "cpp._message.CMessage",             // tp_name
+  PyVarObject_HEAD_INIT(&CMessageClass_Type, 0)
+  FULL_MODULE_NAME ".CMessage",        // tp_name
   sizeof(CMessage),                    // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)cmessage::Dealloc,       //  tp_dealloc
@@ -2319,11 +2763,11 @@
   0,                                   //  tp_getattr
   0,                                   //  tp_setattr
   0,                                   //  tp_compare
-  0,                                   //  tp_repr
+  (reprfunc)cmessage::ToStr,           //  tp_repr
   0,                                   //  tp_as_number
   0,                                   //  tp_as_sequence
   0,                                   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   (reprfunc)cmessage::ToStr,           //  tp_str
   (getattrofunc)cmessage::GetAttr,     //  tp_getattro
@@ -2338,8 +2782,8 @@
   0,                                   //  tp_iter
   0,                                   //  tp_iternext
   cmessage::Methods,                   //  tp_methods
-  cmessage::Members,                   //  tp_members
-  0,                                   //  tp_getset
+  0,                                   //  tp_members
+  cmessage::Getters,                   //  tp_getset
   0,                                   //  tp_base
   0,                                   //  tp_dict
   0,                                   //  tp_descr_get
@@ -2355,7 +2799,7 @@
 const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
 Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
 
-static const google::protobuf::Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
+static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
   if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
     return NULL;
   }
@@ -2363,12 +2807,12 @@
   return cmsg->message;
 }
 
-static google::protobuf::Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
+static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
   if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
     return NULL;
   }
   CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
-  if (PyDict_Size(cmsg->composite_fields) != 0 ||
+  if ((cmsg->composite_fields && PyDict_Size(cmsg->composite_fields) != 0) ||
       (cmsg->extensions != NULL &&
        PyDict_Size(cmsg->extensions->values) != 0)) {
     // There is currently no way of accurately syncing arbitrary changes to
@@ -2401,87 +2845,212 @@
   kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max);
 
   kDESCRIPTOR = PyString_FromString("DESCRIPTOR");
-  k__descriptors = PyString_FromString("__descriptors");
+  k_cdescriptor = PyString_FromString("_cdescriptor");
   kfull_name = PyString_FromString("full_name");
-  kis_extendable = PyString_FromString("is_extendable");
-  kextensions_by_name = PyString_FromString("extensions_by_name");
   k_extensions_by_name = PyString_FromString("_extensions_by_name");
   k_extensions_by_number = PyString_FromString("_extensions_by_number");
-  k_concrete_class = PyString_FromString("_concrete_class");
-  kmessage_type = PyString_FromString("message_type");
-  kname = PyString_FromString("name");
-  kfields_by_name = PyString_FromString("fields_by_name");
 
-  global_message_factory = new DynamicMessageFactory(GetDescriptorPool());
-  global_message_factory->SetDelegateToGeneratedFactory(true);
-
-  descriptor_pool = reinterpret_cast<google::protobuf::python::CDescriptorPool*>(
-      Python_NewCDescriptorPool(NULL, NULL));
+  PyObject *dummy_obj = PySet_New(NULL);
+  kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL);
+  Py_DECREF(dummy_obj);
 }
 
 bool InitProto2MessageModule(PyObject *m) {
+  // Initialize types and globals in descriptor.cc
+  if (!InitDescriptor()) {
+    return false;
+  }
+
+  // Initialize types and globals in descriptor_pool.cc
+  if (!InitDescriptorPool()) {
+    return false;
+  }
+
+  // Initialize constants defined in this file.
   InitGlobals();
 
-  google::protobuf::python::CMessage_Type.tp_hash = PyObject_HashNotImplemented;
-  if (PyType_Ready(&google::protobuf::python::CMessage_Type) < 0) {
+  CMessageClass_Type.tp_base = &PyType_Type;
+  if (PyType_Ready(&CMessageClass_Type) < 0) {
+    return false;
+  }
+  PyModule_AddObject(m, "MessageMeta",
+                     reinterpret_cast<PyObject*>(&CMessageClass_Type));
+
+  if (PyType_Ready(&CMessage_Type) < 0) {
     return false;
   }
 
-  // All three of these are actually set elsewhere, directly onto the child
-  // protocol buffer message class, but set them here as well to document that
-  // subclasses need to set these.
-  PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict, kDESCRIPTOR, Py_None);
-  PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict,
-                 k_extensions_by_name, Py_None);
-  PyDict_SetItem(google::protobuf::python::CMessage_Type.tp_dict,
-                 k_extensions_by_number, Py_None);
-
-  PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(
-      &google::protobuf::python::CMessage_Type));
-
-  google::protobuf::python::RepeatedScalarContainer_Type.tp_new = PyType_GenericNew;
-  google::protobuf::python::RepeatedScalarContainer_Type.tp_hash =
-      PyObject_HashNotImplemented;
-  if (PyType_Ready(&google::protobuf::python::RepeatedScalarContainer_Type) < 0) {
+  // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set
+  // it here as well to document that subclasses need to set it.
+  PyDict_SetItem(CMessage_Type.tp_dict, kDESCRIPTOR, Py_None);
+  // Subclasses with message extensions will override _extensions_by_name and
+  // _extensions_by_number with fresh mutable dictionaries in AddDescriptors.
+  // All other classes can share this same immutable mapping.
+  ScopedPyObjectPtr empty_dict(PyDict_New());
+  if (empty_dict == NULL) {
+    return false;
+  }
+  ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict.get()));
+  if (immutable_dict == NULL) {
+    return false;
+  }
+  if (PyDict_SetItem(CMessage_Type.tp_dict,
+                     k_extensions_by_name, immutable_dict.get()) < 0) {
+    return false;
+  }
+  if (PyDict_SetItem(CMessage_Type.tp_dict,
+                     k_extensions_by_number, immutable_dict.get()) < 0) {
     return false;
   }
 
-  PyModule_AddObject(m, "RepeatedScalarContainer",
-                     reinterpret_cast<PyObject*>(
-                         &google::protobuf::python::RepeatedScalarContainer_Type));
+  PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type));
 
-  google::protobuf::python::RepeatedCompositeContainer_Type.tp_new = PyType_GenericNew;
-  google::protobuf::python::RepeatedCompositeContainer_Type.tp_hash =
-      PyObject_HashNotImplemented;
-  if (PyType_Ready(&google::protobuf::python::RepeatedCompositeContainer_Type) < 0) {
-    return false;
+  // Initialize Repeated container types.
+  {
+    if (PyType_Ready(&RepeatedScalarContainer_Type) < 0) {
+      return false;
+    }
+
+    PyModule_AddObject(m, "RepeatedScalarContainer",
+                       reinterpret_cast<PyObject*>(
+                           &RepeatedScalarContainer_Type));
+
+    if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) {
+      return false;
+    }
+
+    PyModule_AddObject(
+        m, "RepeatedCompositeContainer",
+        reinterpret_cast<PyObject*>(
+            &RepeatedCompositeContainer_Type));
+
+    // Register them as collections.Sequence
+    ScopedPyObjectPtr collections(PyImport_ImportModule("collections"));
+    if (collections == NULL) {
+      return false;
+    }
+    ScopedPyObjectPtr mutable_sequence(
+        PyObject_GetAttrString(collections.get(), "MutableSequence"));
+    if (mutable_sequence == NULL) {
+      return false;
+    }
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedScalarContainer_Type)) == NULL) {
+      return false;
+    }
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedCompositeContainer_Type)) == NULL) {
+      return false;
+    }
   }
 
-  PyModule_AddObject(
-      m, "RepeatedCompositeContainer",
-      reinterpret_cast<PyObject*>(
-          &google::protobuf::python::RepeatedCompositeContainer_Type));
+  // Initialize Map container types.
+  {
+    // ScalarMapContainer_Type derives from our MutableMapping type.
+    ScopedPyObjectPtr containers(PyImport_ImportModule(
+        "google.protobuf.internal.containers"));
+    if (containers == NULL) {
+      return false;
+    }
 
-  google::protobuf::python::ExtensionDict_Type.tp_new = PyType_GenericNew;
-  google::protobuf::python::ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented;
-  if (PyType_Ready(&google::protobuf::python::ExtensionDict_Type) < 0) {
-    return false;
+    ScopedPyObjectPtr mutable_mapping(
+        PyObject_GetAttrString(containers.get(), "MutableMapping"));
+    if (mutable_mapping == NULL) {
+      return false;
+    }
+
+    if (!PyObject_TypeCheck(mutable_mapping.get(), &PyType_Type)) {
+      return false;
+    }
+
+    Py_INCREF(mutable_mapping.get());
+#if PY_MAJOR_VERSION >= 3
+    PyObject* bases = PyTuple_New(1);
+    PyTuple_SET_ITEM(bases, 0, mutable_mapping.get());
+
+    ScalarMapContainer_Type = 
+        PyType_FromSpecWithBases(&ScalarMapContainer_Type_spec, bases);
+    PyModule_AddObject(m, "ScalarMapContainer", ScalarMapContainer_Type);
+#else
+    ScalarMapContainer_Type.tp_base =
+        reinterpret_cast<PyTypeObject*>(mutable_mapping.get());
+
+    if (PyType_Ready(&ScalarMapContainer_Type) < 0) {
+      return false;
+    }
+
+    PyModule_AddObject(m, "ScalarMapContainer",
+                       reinterpret_cast<PyObject*>(&ScalarMapContainer_Type));
+#endif
+
+    if (PyType_Ready(&MapIterator_Type) < 0) {
+      return false;
+    }
+
+    PyModule_AddObject(m, "MapIterator",
+                       reinterpret_cast<PyObject*>(&MapIterator_Type));
+
+
+#if PY_MAJOR_VERSION >= 3
+    MessageMapContainer_Type = 
+        PyType_FromSpecWithBases(&MessageMapContainer_Type_spec, bases);
+    PyModule_AddObject(m, "MessageMapContainer", MessageMapContainer_Type);
+#else
+    Py_INCREF(mutable_mapping.get());
+    MessageMapContainer_Type.tp_base =
+        reinterpret_cast<PyTypeObject*>(mutable_mapping.get());
+
+    if (PyType_Ready(&MessageMapContainer_Type) < 0) {
+      return false;
+    }
+
+    PyModule_AddObject(m, "MessageMapContainer",
+                       reinterpret_cast<PyObject*>(&MessageMapContainer_Type));
+#endif
   }
 
+  if (PyType_Ready(&ExtensionDict_Type) < 0) {
+    return false;
+  }
   PyModule_AddObject(
       m, "ExtensionDict",
-      reinterpret_cast<PyObject*>(&google::protobuf::python::ExtensionDict_Type));
+      reinterpret_cast<PyObject*>(&ExtensionDict_Type));
 
-  if (!google::protobuf::python::InitDescriptor()) {
-    return false;
-  }
+  // Expose the DescriptorPool used to hold all descriptors added from generated
+  // pb2.py files.
+  // PyModule_AddObject steals a reference.
+  Py_INCREF(GetDefaultDescriptorPool());
+  PyModule_AddObject(m, "default_pool",
+                     reinterpret_cast<PyObject*>(GetDefaultDescriptorPool()));
+
+  PyModule_AddObject(m, "DescriptorPool", reinterpret_cast<PyObject*>(
+      &PyDescriptorPool_Type));
+
+  // This implementation provides full Descriptor types, we advertise it so that
+  // descriptor.py can use them in replacement of the Python classes.
+  PyModule_AddIntConstant(m, "_USE_C_DESCRIPTORS", 1);
+
+  PyModule_AddObject(m, "Descriptor", reinterpret_cast<PyObject*>(
+      &PyMessageDescriptor_Type));
+  PyModule_AddObject(m, "FieldDescriptor", reinterpret_cast<PyObject*>(
+      &PyFieldDescriptor_Type));
+  PyModule_AddObject(m, "EnumDescriptor", reinterpret_cast<PyObject*>(
+      &PyEnumDescriptor_Type));
+  PyModule_AddObject(m, "EnumValueDescriptor", reinterpret_cast<PyObject*>(
+      &PyEnumValueDescriptor_Type));
+  PyModule_AddObject(m, "FileDescriptor", reinterpret_cast<PyObject*>(
+      &PyFileDescriptor_Type));
+  PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast<PyObject*>(
+      &PyOneofDescriptor_Type));
 
   PyObject* enum_type_wrapper = PyImport_ImportModule(
       "google.protobuf.internal.enum_type_wrapper");
   if (enum_type_wrapper == NULL) {
     return false;
   }
-  google::protobuf::python::EnumTypeWrapper_class =
+  EnumTypeWrapper_class =
       PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper");
   Py_DECREF(enum_type_wrapper);
 
@@ -2490,25 +3059,21 @@
   if (message_module == NULL) {
     return false;
   }
-  google::protobuf::python::EncodeError_class = PyObject_GetAttrString(message_module,
-                                                             "EncodeError");
-  google::protobuf::python::DecodeError_class = PyObject_GetAttrString(message_module,
-                                                             "DecodeError");
+  EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
+  DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError");
+  PythonMessage_class = PyObject_GetAttrString(message_module, "Message");
   Py_DECREF(message_module);
 
   PyObject* pickle_module = PyImport_ImportModule("pickle");
   if (pickle_module == NULL) {
     return false;
   }
-  google::protobuf::python::PickleError_class = PyObject_GetAttrString(pickle_module,
-                                                             "PickleError");
+  PickleError_class = PyObject_GetAttrString(pickle_module, "PickleError");
   Py_DECREF(pickle_module);
 
   // Override {Get,Mutable}CProtoInsidePyProto.
-  google::protobuf::python::GetCProtoInsidePyProtoPtr =
-      google::protobuf::python::GetCProtoInsidePyProtoImpl;
-  google::protobuf::python::MutableCProtoInsidePyProtoPtr =
-      google::protobuf::python::MutableCProtoInsidePyProtoImpl;
+  GetCProtoInsidePyProtoPtr = GetCProtoInsidePyProtoImpl;
+  MutableCProtoInsidePyProtoPtr = MutableCProtoInsidePyProtoImpl;
 
   return true;
 }
@@ -2516,6 +3081,12 @@
 }  // namespace python
 }  // namespace protobuf
 
+static PyMethodDef ModuleMethods[] = {
+  {"SetAllowOversizeProtos",
+    (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
+    METH_O, "Enable/disable oversize proto parsing."},
+  { NULL, NULL}
+};
 
 #if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef _module = {
@@ -2523,7 +3094,7 @@
   "_message",
   google::protobuf::python::module_docstring,
   -1,
-  NULL,
+  ModuleMethods,  /* m_methods */
   NULL,
   NULL,
   NULL,
@@ -2542,7 +3113,8 @@
 #if PY_MAJOR_VERSION >= 3
     m = PyModule_Create(&_module);
 #else
-    m = Py_InitModule3("_message", NULL, google::protobuf::python::module_docstring);
+    m = Py_InitModule3("_message", ModuleMethods,
+                       google::protobuf::python::module_docstring);
 #endif
     if (m == NULL) {
       return INITFUNC_ERRORVAL;
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 9f4978f..3a4bec8 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -42,20 +42,27 @@
 #endif
 #include <string>
 
-
 namespace google {
 namespace protobuf {
 
 class Message;
 class Reflection;
 class FieldDescriptor;
+class Descriptor;
+class DescriptorPool;
+class MessageFactory;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+using ::std::string;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
-struct CFieldDescriptor;
 struct ExtensionDict;
+struct PyDescriptorPool;
 
 typedef struct CMessage {
   PyObject_HEAD;
@@ -79,13 +86,11 @@
   // to use this pointer will result in a crash.
   struct CMessage* parent;
 
-  // Weak reference to the parent's descriptor that describes this submessage.
+  // Pointer to the parent's descriptor that describes this submessage.
   // Used together with the parent's message when making a default message
   // instance mutable.
-  // TODO(anuraag): With a bit of work on the Python/C++ layer, it should be
-  // possible to make this a direct pointer to a C++ FieldDescriptor, this would
-  // be easier if this implementation replaces upstream.
-  CFieldDescriptor* parent_field;
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
 
   // Pointer to the C++ Message object for this CMessage.  The
   // CMessage does not own this pointer.
@@ -111,49 +116,91 @@
 
 extern PyTypeObject CMessage_Type;
 
+
+// The (meta) type of all Messages classes.
+// It allows us to cache some C++ pointers in the class object itself, they are
+// faster to extract than from the type's dictionary.
+
+struct CMessageClass {
+  // This is how CPython subclasses C structures: the base structure must be
+  // the first member of the object.
+  PyHeapTypeObject super;
+
+  // C++ descriptor of this message.
+  const Descriptor* message_descriptor;
+
+  // Owned reference, used to keep the pointer above alive.
+  PyObject* py_message_descriptor;
+
+  // The Python DescriptorPool used to create the class. It is needed to resolve
+  // fields descriptors, including extensions fields; its C++ MessageFactory is
+  // used to instantiate submessages.
+  // This can be different from DESCRIPTOR.file.pool, in the case of a custom
+  // DescriptorPool which defines new extensions.
+  // We own the reference, because it's important to keep the descriptors and
+  // factory alive.
+  PyDescriptorPool* py_descriptor_pool;
+
+  PyObject* AsPyObject() {
+    return reinterpret_cast<PyObject*>(this);
+  }
+};
+
+
 namespace cmessage {
 
-// Create a new empty message that can be populated by the parent.
-PyObject* NewEmpty(PyObject* type);
+// Internal function to create a new empty Message Python object, but with empty
+// pointers to the C++ objects.
+// The caller must fill self->message, self->owner and eventually self->parent.
+CMessage* NewEmptyMessage(CMessageClass* type);
 
 // Release a submessage from its proto tree, making it a new top-level messgae.
 // A new message will be created if this is a read-only default instance.
 //
 // Corresponds to reflection api method ReleaseMessage.
-int ReleaseSubMessage(google::protobuf::Message* message,
-                      const google::protobuf::FieldDescriptor* field_descriptor,
+int ReleaseSubMessage(CMessage* self,
+                      const FieldDescriptor* field_descriptor,
                       CMessage* child_cmessage);
 
+// Retrieves the C++ descriptor of a Python Extension descriptor.
+// On error, return NULL with an exception set.
+const FieldDescriptor* GetExtensionDescriptor(PyObject* extension);
+
 // Initializes a new CMessage instance for a submessage. Only called once per
 // submessage as the result is cached in composite_fields.
 //
 // Corresponds to reflection api method GetMessage.
-PyObject* InternalGetSubMessage(CMessage* self,
-                                CFieldDescriptor* cfield_descriptor);
+PyObject* InternalGetSubMessage(
+    CMessage* self, const FieldDescriptor* field_descriptor);
 
 // Deletes a range of C++ submessages in a repeated field (following a
 // removal in a RepeatedCompositeContainer).
 //
 // Releases messages to the provided cmessage_list if it is not NULL rather
 // than just removing them from the underlying proto. This cmessage_list must
-// have a CMessage for each underlying submessage. The CMessages refered to
+// have a CMessage for each underlying submessage. The CMessages referred to
 // by slice will be removed from cmessage_list by this function.
 //
 // Corresponds to reflection api method RemoveLast.
-int InternalDeleteRepeatedField(google::protobuf::Message* message,
-                                const google::protobuf::FieldDescriptor* field_descriptor,
+int InternalDeleteRepeatedField(CMessage* self,
+                                const FieldDescriptor* field_descriptor,
                                 PyObject* slice, PyObject* cmessage_list);
 
 // Sets the specified scalar value to the message.
 int InternalSetScalar(CMessage* self,
-                      const google::protobuf::FieldDescriptor* field_descriptor,
+                      const FieldDescriptor* field_descriptor,
                       PyObject* value);
 
+// Sets the specified scalar value to the message.  Requires it is not a Oneof.
+int InternalSetNonOneofScalar(Message* message,
+                              const FieldDescriptor* field_descriptor,
+                              PyObject* arg);
+
 // Retrieves the specified scalar value from the message.
 //
 // Returns a new python reference.
-PyObject* InternalGetScalar(CMessage* self,
-                            const google::protobuf::FieldDescriptor* field_descriptor);
+PyObject* InternalGetScalar(const Message* message,
+                            const FieldDescriptor* field_descriptor);
 
 // Clears the message, removing all contained data. Extension dictionary and
 // submessages are released first if there are remaining external references.
@@ -169,8 +216,7 @@
 //
 // Corresponds to reflection api method ClearField.
 PyObject* ClearFieldByDescriptor(
-    CMessage* self,
-    const google::protobuf::FieldDescriptor* descriptor);
+    CMessage* self, const FieldDescriptor* descriptor);
 
 // Clears the data for the given field name. The message is released if there
 // are any external references.
@@ -183,17 +229,15 @@
 //
 // Corresponds to reflection api method HasField
 PyObject* HasFieldByDescriptor(
-    CMessage* self, const google::protobuf::FieldDescriptor* field_descriptor);
+    CMessage* self, const FieldDescriptor* field_descriptor);
 
 // Checks if the message has the named field.
 //
 // Corresponds to reflection api method HasField.
 PyObject* HasField(CMessage* self, PyObject* arg);
 
-// Initializes constants/enum values on a message. This is called by
-// RepeatedCompositeContainer and ExtensionDict after calling the constructor.
-// TODO(anuraag): Make it always called from within the constructor since it can
-int InitAttributes(CMessage* self, PyObject* descriptor, PyObject* kwargs);
+// Initializes values of fields on a newly constructed message.
+int InitAttributes(CMessage* self, PyObject* kwargs);
 
 PyObject* MergeFrom(CMessage* self, PyObject* arg);
 
@@ -216,16 +260,23 @@
 
 int AssureWritable(CMessage* self);
 
+// Returns the "best" DescriptorPool for the given message.
+// This is often equivalent to message.DESCRIPTOR.pool, but not always, when
+// the message class was created from a MessageFactory using a custom pool which
+// uses the generated pool as an underlay.
+//
+// The returned pool is suitable for finding fields and building submessages,
+// even in the case of extensions.
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
+
 }  // namespace cmessage
 
+
 /* Is 64bit */
 #define IS_64BIT (SIZEOF_LONG == 8)
 
-#define FIELD_BELONGS_TO_MESSAGE(field_descriptor, message) \
-    ((message)->GetDescriptor() == (field_descriptor)->containing_type())
-
 #define FIELD_IS_REPEATED(field_descriptor)                 \
-    ((field_descriptor)->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED)
+    ((field_descriptor)->label() == FieldDescriptor::LABEL_REPEATED)
 
 #define GOOGLE_CHECK_GET_INT32(arg, value, err)                        \
     int32 value;                                            \
@@ -278,7 +329,7 @@
 extern PyObject* kint64max_py;
 extern PyObject* kuint64max_py;
 
-#define C(str) const_cast<char*>(str)
+#define FULL_MODULE_NAME "google.protobuf.pyext._message"
 
 void FormatTypeError(PyObject* arg, char* expected_types);
 template<class T>
@@ -287,14 +338,19 @@
 bool CheckAndGetDouble(PyObject* arg, double* value);
 bool CheckAndGetFloat(PyObject* arg, float* value);
 bool CheckAndGetBool(PyObject* arg, bool* value);
+PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor);
 bool CheckAndSetString(
-    PyObject* arg, google::protobuf::Message* message,
-    const google::protobuf::FieldDescriptor* descriptor,
-    const google::protobuf::Reflection* reflection,
+    PyObject* arg, Message* message,
+    const FieldDescriptor* descriptor,
+    const Reflection* reflection,
     bool append,
     int index);
-PyObject* ToStringObject(
-    const google::protobuf::FieldDescriptor* descriptor, string value);
+PyObject* ToStringObject(const FieldDescriptor* descriptor, string value);
+
+// Check if the passed field descriptor belongs to the given message.
+// If not, return false and set a Python exception (a KeyError)
+bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
+                                const Message* message);
 
 extern PyObject* PickleError_class;
 
diff --git a/python/google/protobuf/pyext/message_factory_cpp2_test.py b/python/google/protobuf/pyext/message_factory_cpp2_test.py
deleted file mode 100644
index 32ab4f8..0000000
--- a/python/google/protobuf/pyext/message_factory_cpp2_test.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#! /usr/bin/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.
-
-"""Tests for google.protobuf.message_factory."""
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION'] = '2'
-
-# We must set the implementation version above before the google3 imports.
-# pylint: disable=g-import-not-at-top
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-# Run all tests from the original module by putting them in our namespace.
-# pylint: disable=wildcard-import
-from google.protobuf.internal.message_factory_test import *
-
-
-class ConfirmCppApi2Test(basetest.TestCase):
-
-  def testImplementationSetting(self):
-    self.assertEqual('cpp', api_implementation.Type())
-    self.assertEqual(2, api_implementation.Version())
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/pyext/proto2_api_test.proto b/python/google/protobuf/pyext/proto2_api_test.proto
index 72c31b1..18aecfb 100644
--- a/python/google/protobuf/pyext/proto2_api_test.proto
+++ b/python/google/protobuf/pyext/proto2_api_test.proto
@@ -28,6 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+syntax = "proto2";
+
 import "google/protobuf/internal/cpp/proto1_api_test.proto";
 
 package google.protobuf.python.internal;
diff --git a/python/google/protobuf/pyext/python.proto b/python/google/protobuf/pyext/python.proto
index d47d402..cce645d 100644
--- a/python/google/protobuf/pyext/python.proto
+++ b/python/google/protobuf/pyext/python.proto
@@ -33,6 +33,7 @@
 // These message definitions are used to exercises known corner cases
 // in the C++ implementation of the Python API.
 
+syntax = "proto2";
 
 package google.protobuf.python.internal;
 
@@ -63,4 +64,5 @@
 
 extend TestAllExtensions {
   optional TestAllTypes.NestedMessage optional_nested_message_extension = 1;
+  repeated TestAllTypes.NestedMessage repeated_nested_message_extension = 2;
 }
diff --git a/python/google/protobuf/pyext/reflection_cpp2_generated_test.py b/python/google/protobuf/pyext/reflection_cpp2_generated_test.py
deleted file mode 100755
index 552efd4..0000000
--- a/python/google/protobuf/pyext/reflection_cpp2_generated_test.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#! /usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# 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.
-
-"""Unittest for reflection.py, which tests the generated C++ implementation."""
-
-__author__ = 'jasonh@google.com (Jason Hsueh)'
-
-import os
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
-os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION'] = '2'
-
-from google.apputils import basetest
-from google.protobuf.internal import api_implementation
-from google.protobuf.internal import more_extensions_dynamic_pb2
-from google.protobuf.internal import more_extensions_pb2
-from google.protobuf.internal.reflection_test import *
-
-
-class ReflectionCppTest(basetest.TestCase):
-  def testImplementationSetting(self):
-    self.assertEqual('cpp', api_implementation.Type())
-    self.assertEqual(2, api_implementation.Version())
-
-  def testExtensionOfGeneratedTypeInDynamicFile(self):
-    """Tests that a file built dynamically can extend a generated C++ type.
-
-    The C++ implementation uses a DescriptorPool that has the generated
-    DescriptorPool as an underlay. Typically, a type can only find
-    extensions in its own pool. With the python C-extension, the generated C++
-    extendee may be available, but not the extension. This tests that the
-    C-extension implements the correct special handling to make such extensions
-    available.
-    """
-    pb1 = more_extensions_pb2.ExtendedMessage()
-    # Test that basic accessors work.
-    self.assertFalse(
-        pb1.HasExtension(more_extensions_dynamic_pb2.dynamic_int32_extension))
-    self.assertFalse(
-        pb1.HasExtension(more_extensions_dynamic_pb2.dynamic_message_extension))
-    pb1.Extensions[more_extensions_dynamic_pb2.dynamic_int32_extension] = 17
-    pb1.Extensions[more_extensions_dynamic_pb2.dynamic_message_extension].a = 24
-    self.assertTrue(
-        pb1.HasExtension(more_extensions_dynamic_pb2.dynamic_int32_extension))
-    self.assertTrue(
-        pb1.HasExtension(more_extensions_dynamic_pb2.dynamic_message_extension))
-
-    # Now serialize the data and parse to a new message.
-    pb2 = more_extensions_pb2.ExtendedMessage()
-    pb2.MergeFromString(pb1.SerializeToString())
-
-    self.assertTrue(
-        pb2.HasExtension(more_extensions_dynamic_pb2.dynamic_int32_extension))
-    self.assertTrue(
-        pb2.HasExtension(more_extensions_dynamic_pb2.dynamic_message_extension))
-    self.assertEqual(
-        17, pb2.Extensions[more_extensions_dynamic_pb2.dynamic_int32_extension])
-    self.assertEqual(
-        24,
-        pb2.Extensions[more_extensions_dynamic_pb2.dynamic_message_extension].a)
-
-
-
-if __name__ == '__main__':
-  basetest.main()
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index 5c05b3d..4f339e7 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -38,11 +38,13 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
@@ -56,8 +58,6 @@
 namespace protobuf {
 namespace python {
 
-extern google::protobuf::DynamicMessageFactory* global_message_factory;
-
 namespace repeated_composite_container {
 
 // TODO(tibell): We might also want to check:
@@ -65,144 +65,25 @@
 #define GOOGLE_CHECK_ATTACHED(self)             \
   do {                                   \
     GOOGLE_CHECK_NOTNULL((self)->message);      \
-    GOOGLE_CHECK_NOTNULL((self)->parent_field); \
+    GOOGLE_CHECK_NOTNULL((self)->parent_field_descriptor); \
   } while (0);
 
 #define GOOGLE_CHECK_RELEASED(self)             \
   do {                                   \
     GOOGLE_CHECK((self)->owner.get() == NULL);  \
     GOOGLE_CHECK((self)->message == NULL);      \
-    GOOGLE_CHECK((self)->parent_field == NULL); \
+    GOOGLE_CHECK((self)->parent_field_descriptor == NULL); \
     GOOGLE_CHECK((self)->parent == NULL);       \
   } while (0);
 
-// Returns a new reference.
-static PyObject* GetKey(PyObject* x) {
-  // Just the identity function.
-  Py_INCREF(x);
-  return x;
-}
-
-#define GET_KEY(keyfunc, value)                                         \
-  ((keyfunc) == NULL ?                                                  \
-  GetKey((value)) :                                                     \
-  PyObject_CallFunctionObjArgs((keyfunc), (value), NULL))
-
-// Converts a comparison function that returns -1, 0, or 1 into a
-// less-than predicate.
-//
-// Returns -1 on error, 1 if x < y, 0 if x >= y.
-static int islt(PyObject *x, PyObject *y, PyObject *compare) {
-  if (compare == NULL)
-    return PyObject_RichCompareBool(x, y, Py_LT);
-
-  ScopedPyObjectPtr res(PyObject_CallFunctionObjArgs(compare, x, y, NULL));
-  if (res == NULL)
-    return -1;
-  if (!PyInt_Check(res)) {
-    PyErr_Format(PyExc_TypeError,
-                 "comparison function must return int, not %.200s",
-                 Py_TYPE(res)->tp_name);
-    return -1;
-  }
-  return PyInt_AsLong(res) < 0;
-}
-
-// Copied from uarrsort.c but swaps memcpy swaps with protobuf/python swaps
-// TODO(anuraag): Is there a better way to do this then reinventing the wheel?
-static int InternalQuickSort(RepeatedCompositeContainer* self,
-                             Py_ssize_t start,
-                             Py_ssize_t limit,
-                             PyObject* cmp,
-                             PyObject* keyfunc) {
-  if (limit - start <= 1)
-    return 0;  // Nothing to sort.
-
-  GOOGLE_CHECK_ATTACHED(self);
-
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
-  const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor;
-  Py_ssize_t left;
-  Py_ssize_t right;
-
-  PyObject* children = self->child_messages;
-
-  do {
-    left = start;
-    right = limit;
-    ScopedPyObjectPtr mid(
-        GET_KEY(keyfunc, PyList_GET_ITEM(children, (start + limit) / 2)));
-    do {
-      ScopedPyObjectPtr key(GET_KEY(keyfunc, PyList_GET_ITEM(children, left)));
-      int is_lt = islt(key, mid, cmp);
-      if (is_lt == -1)
-        return -1;
-      /* array[left]<x */
-      while (is_lt) {
-        ++left;
-        ScopedPyObjectPtr key(GET_KEY(keyfunc,
-                                      PyList_GET_ITEM(children, left)));
-        is_lt = islt(key, mid, cmp);
-        if (is_lt == -1)
-          return -1;
-      }
-      key.reset(GET_KEY(keyfunc, PyList_GET_ITEM(children, right - 1)));
-      is_lt = islt(mid, key, cmp);
-      if (is_lt == -1)
-        return -1;
-      while (is_lt) {
-        --right;
-        ScopedPyObjectPtr key(GET_KEY(keyfunc,
-                                      PyList_GET_ITEM(children, right - 1)));
-        is_lt = islt(mid, key, cmp);
-        if (is_lt == -1)
-          return -1;
-      }
-      if (left < right) {
-        --right;
-        if (left < right) {
-          reflection->SwapElements(message, descriptor, left, right);
-          PyObject* tmp = PyList_GET_ITEM(children, left);
-          PyList_SET_ITEM(children, left, PyList_GET_ITEM(children, right));
-          PyList_SET_ITEM(children, right, tmp);
-        }
-        ++left;
-      }
-    } while (left < right);
-
-    if ((right - start) < (limit - left)) {
-      /* sort [start..right[ */
-      if (start < (right - 1)) {
-        InternalQuickSort(self, start, right, cmp, keyfunc);
-      }
-
-      /* sort [left..limit[ */
-      start = left;
-    } else {
-      /* sort [left..limit[ */
-      if (left < (limit - 1)) {
-        InternalQuickSort(self, left, limit, cmp, keyfunc);
-      }
-
-      /* sort [start..right[ */
-      limit = right;
-    }
-  } while (start < (limit - 1));
-
-  return 0;
-}
-
-#undef GET_KEY
-
 // ---------------------------------------------------------------------
 // len()
 
 static Py_ssize_t Length(RepeatedCompositeContainer* self) {
-  google::protobuf::Message* message = self->message;
+  Message* message = self->message;
   if (message != NULL) {
     return message->GetReflection()->FieldSize(*message,
-                                               self->parent_field->descriptor);
+                                               self->parent_field_descriptor);
   } else {
     // The container has been released (i.e. by a call to Clear() or
     // ClearField() on the parent) and thus there's no message.
@@ -221,23 +102,22 @@
   // be removed in such a way so there's no need to worry about that.
   Py_ssize_t message_length = Length(self);
   Py_ssize_t child_length = PyList_GET_SIZE(self->child_messages);
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
   for (Py_ssize_t i = child_length; i < message_length; ++i) {
     const Message& sub_message = reflection->GetRepeatedMessage(
-        *(self->message), self->parent_field->descriptor, i);
-    ScopedPyObjectPtr py_cmsg(cmessage::NewEmpty(self->subclass_init));
-    if (py_cmsg == NULL) {
+        *(self->message), self->parent_field_descriptor, i);
+    CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class);
+    ScopedPyObjectPtr py_cmsg(reinterpret_cast<PyObject*>(cmsg));
+    if (cmsg == NULL) {
       return -1;
     }
-    CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg.get());
     cmsg->owner = self->owner;
-    cmsg->message = const_cast<google::protobuf::Message*>(&sub_message);
+    cmsg->message = const_cast<Message*>(&sub_message);
     cmsg->parent = self->parent;
-    if (cmessage::InitAttributes(cmsg, NULL, NULL) < 0) {
+    if (PyList_Append(self->child_messages, py_cmsg.get()) < 0) {
       return -1;
     }
-    PyList_Append(self->child_messages, py_cmsg);
   }
   return 0;
 }
@@ -255,26 +135,27 @@
   }
   if (cmessage::AssureWritable(self->parent) == -1)
     return NULL;
-  google::protobuf::Message* message = self->message;
-  google::protobuf::Message* sub_message =
+  Message* message = self->message;
+  Message* sub_message =
       message->GetReflection()->AddMessage(message,
-                                           self->parent_field->descriptor);
-  PyObject* py_cmsg = cmessage::NewEmpty(self->subclass_init);
-  if (py_cmsg == NULL) {
+                                           self->parent_field_descriptor);
+  CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class);
+  if (cmsg == NULL)
     return NULL;
-  }
-  CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
 
   cmsg->owner = self->owner;
   cmsg->message = sub_message;
   cmsg->parent = self->parent;
-  // cmessage::InitAttributes must be called after cmsg->message has
-  // been set.
-  if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) {
+  if (cmessage::InitAttributes(cmsg, kwargs) < 0) {
+    Py_DECREF(cmsg);
+    return NULL;
+  }
+
+  PyObject* py_cmsg = reinterpret_cast<PyObject*>(cmsg);
+  if (PyList_Append(self->child_messages, py_cmsg) < 0) {
     Py_DECREF(py_cmsg);
     return NULL;
   }
-  PyList_Append(self->child_messages, py_cmsg);
   return py_cmsg;
 }
 
@@ -283,20 +164,16 @@
                                PyObject* kwargs) {
   GOOGLE_CHECK_RELEASED(self);
 
-  // Create the CMessage
-  PyObject* py_cmsg = PyObject_CallObject(self->subclass_init, NULL);
+  // Create a new Message detached from the rest.
+  PyObject* py_cmsg = PyEval_CallObjectWithKeywords(
+      self->child_message_class->AsPyObject(), NULL, kwargs);
   if (py_cmsg == NULL)
     return NULL;
-  CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
-  if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) {
+
+  if (PyList_Append(self->child_messages, py_cmsg) < 0) {
     Py_DECREF(py_cmsg);
     return NULL;
   }
-
-  // The Message got created by the call to subclass_init above and
-  // it set self->owner to the newly allocated message.
-
-  PyList_Append(self->child_messages, py_cmsg);
   return py_cmsg;
 }
 
@@ -323,8 +200,8 @@
     return NULL;
   }
   ScopedPyObjectPtr next;
-  while ((next.reset(PyIter_Next(iter))) != NULL) {
-    if (!PyObject_TypeCheck(next, &CMessage_Type)) {
+  while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+    if (!PyObject_TypeCheck(next.get(), &CMessage_Type)) {
       PyErr_SetString(PyExc_TypeError, "Not a cmessage");
       return NULL;
     }
@@ -333,7 +210,8 @@
       return NULL;
     }
     CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
-    if (cmessage::MergeFrom(new_cmessage, next) == NULL) {
+    if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next.get())) ==
+        NULL) {
       return NULL;
     }
   }
@@ -354,35 +232,9 @@
   if (UpdateChildMessages(self) < 0) {
     return NULL;
   }
-  Py_ssize_t from;
-  Py_ssize_t to;
-  Py_ssize_t step;
-  Py_ssize_t length = Length(self);
-  Py_ssize_t slicelength;
-  if (PySlice_Check(slice)) {
-#if PY_MAJOR_VERSION >= 3
-    if (PySlice_GetIndicesEx(slice,
-#else
-    if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
-#endif
-                             length, &from, &to, &step, &slicelength) == -1) {
-      return NULL;
-    }
-    return PyList_GetSlice(self->child_messages, from, to);
-  } else if (PyInt_Check(slice) || PyLong_Check(slice)) {
-    from = to = PyLong_AsLong(slice);
-    if (from < 0) {
-      from = to = length + from;
-    }
-    PyObject* result = PyList_GetItem(self->child_messages, from);
-    if (result == NULL) {
-      return NULL;
-    }
-    Py_INCREF(result);
-    return result;
-  }
-  PyErr_SetString(PyExc_TypeError, "index must be an integer or slice");
-  return NULL;
+  // Just forward the call to the subscript-handling function of the
+  // list containing the child messages.
+  return PyObject_GetItem(self->child_messages, slice);
 }
 
 int AssignSubscript(RepeatedCompositeContainer* self,
@@ -397,9 +249,9 @@
   }
 
   // Delete from the underlying Message, if any.
-  if (self->message != NULL) {
-    if (cmessage::InternalDeleteRepeatedField(self->message,
-                                              self->parent_field->descriptor,
+  if (self->parent != NULL) {
+    if (cmessage::InternalDeleteRepeatedField(self->parent,
+                                              self->parent_field_descriptor,
                                               slice,
                                               self->child_messages) < 0) {
       return -1;
@@ -441,7 +293,7 @@
     return NULL;
   }
   ScopedPyObjectPtr py_index(PyLong_FromLong(index));
-  if (AssignSubscript(self, py_index, NULL) < 0) {
+  if (AssignSubscript(self, py_index.get(), NULL) < 0) {
     return NULL;
   }
   Py_RETURN_NONE;
@@ -465,17 +317,17 @@
     if (full_slice == NULL) {
       return NULL;
     }
-    ScopedPyObjectPtr list(Subscript(self, full_slice));
+    ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
     if (list == NULL) {
       return NULL;
     }
     ScopedPyObjectPtr other_list(
-        Subscript(
-            reinterpret_cast<RepeatedCompositeContainer*>(other), full_slice));
+        Subscript(reinterpret_cast<RepeatedCompositeContainer*>(other),
+                  full_slice.get()));
     if (other_list == NULL) {
       return NULL;
     }
-    return PyObject_RichCompare(list, other_list, opid);
+    return PyObject_RichCompare(list.get(), other_list.get(), opid);
   } else {
     Py_INCREF(Py_NotImplemented);
     return Py_NotImplemented;
@@ -485,58 +337,39 @@
 // ---------------------------------------------------------------------
 // sort()
 
-static PyObject* SortAttached(RepeatedCompositeContainer* self,
-                              PyObject* args,
-                              PyObject* kwds) {
-  // Sort the underlying Message array.
-  PyObject *compare = NULL;
-  int reverse = 0;
-  PyObject *keyfunc = NULL;
-  static char *kwlist[] = {"cmp", "key", "reverse", 0};
-
-  if (args != NULL) {
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort",
-                                     kwlist, &compare, &keyfunc, &reverse))
-      return NULL;
-  }
-  if (compare == Py_None)
-    compare = NULL;
-  if (keyfunc == Py_None)
-    keyfunc = NULL;
-
+static void ReorderAttached(RepeatedCompositeContainer* self) {
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  const FieldDescriptor* descriptor = self->parent_field_descriptor;
   const Py_ssize_t length = Length(self);
-  if (InternalQuickSort(self, 0, length, compare, keyfunc) < 0)
-    return NULL;
 
-  // Finally reverse the result if requested.
-  if (reverse) {
-    google::protobuf::Message* message = self->message;
-    const google::protobuf::Reflection* reflection = message->GetReflection();
-    const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor;
+  // Since Python protobuf objects are never arena-allocated, adding and
+  // removing message pointers to the underlying array is just updating
+  // pointers.
+  for (Py_ssize_t i = 0; i < length; ++i)
+    reflection->ReleaseLast(message, descriptor);
 
-    // Reverse the Message array.
-    for (int i = 0; i < length / 2; ++i)
-      reflection->SwapElements(message, descriptor, i, length - i - 1);
-
-    // Reverse the Python list.
-    ScopedPyObjectPtr res(PyObject_CallMethod(self->child_messages,
-                                              "reverse", NULL));
-    if (res == NULL)
-      return NULL;
+  for (Py_ssize_t i = 0; i < length; ++i) {
+    CMessage* py_cmsg = reinterpret_cast<CMessage*>(
+        PyList_GET_ITEM(self->child_messages, i));
+    reflection->AddAllocatedMessage(message, descriptor, py_cmsg->message);
   }
-
-  Py_RETURN_NONE;
 }
 
-static PyObject* SortReleased(RepeatedCompositeContainer* self,
-                              PyObject* args,
-                              PyObject* kwds) {
+// Returns 0 if successful; returns -1 and sets an exception if
+// unsuccessful.
+static int SortPythonMessages(RepeatedCompositeContainer* self,
+                               PyObject* args,
+                               PyObject* kwds) {
   ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort"));
   if (m == NULL)
-    return NULL;
-  if (PyObject_Call(m, args, kwds) == NULL)
-    return NULL;
-  Py_RETURN_NONE;
+    return -1;
+  if (PyObject_Call(m.get(), args, kwds) == NULL)
+    return -1;
+  if (self->message != NULL) {
+    ReorderAttached(self);
+  }
+  return 0;
 }
 
 static PyObject* Sort(RepeatedCompositeContainer* self,
@@ -554,13 +387,13 @@
     }
   }
 
-  if (UpdateChildMessages(self) < 0)
+  if (UpdateChildMessages(self) < 0) {
     return NULL;
-  if (self->message == NULL) {
-    return SortReleased(self, args, kwds);
-  } else {
-    return SortAttached(self, args, kwds);
   }
+  if (SortPythonMessages(self, args, kwds) < 0) {
+    return NULL;
+  }
+  Py_RETURN_NONE;
 }
 
 // ---------------------------------------------------------------------
@@ -581,46 +414,43 @@
   return item;
 }
 
-// The caller takes ownership of the returned Message.
-Message* ReleaseLast(const FieldDescriptor* field,
-                     const Descriptor* type,
-                     Message* message) {
-  GOOGLE_CHECK_NOTNULL(field);
-  GOOGLE_CHECK_NOTNULL(type);
-  GOOGLE_CHECK_NOTNULL(message);
-
-  Message* released_message = message->GetReflection()->ReleaseLast(
-      message, field);
-  // TODO(tibell): Deal with proto1.
-
-  // ReleaseMessage will return NULL which differs from
-  // child_cmessage->message, if the field does not exist.  In this case,
-  // the latter points to the default instance via a const_cast<>, so we
-  // have to reset it to a new mutable object since we are taking ownership.
-  if (released_message == NULL) {
-    const Message* prototype = global_message_factory->GetPrototype(type);
-    GOOGLE_CHECK_NOTNULL(prototype);
-    return prototype->New();
-  } else {
-    return released_message;
+static PyObject* Pop(RepeatedCompositeContainer* self,
+                     PyObject* args) {
+  Py_ssize_t index = -1;
+  if (!PyArg_ParseTuple(args, "|n", &index)) {
+    return NULL;
   }
+  PyObject* item = Item(self, index);
+  if (item == NULL) {
+    PyErr_Format(PyExc_IndexError,
+                 "list index (%zd) out of range",
+                 index);
+    return NULL;
+  }
+  ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
+  if (AssignSubscript(self, py_index.get(), NULL) < 0) {
+    return NULL;
+  }
+  return item;
 }
 
-// Release field of message and transfer the ownership to cmessage.
-void ReleaseLastTo(const FieldDescriptor* field,
-                   Message* message,
-                   CMessage* cmessage) {
+// Release field of parent message and transfer the ownership to target.
+void ReleaseLastTo(CMessage* parent,
+                   const FieldDescriptor* field,
+                   CMessage* target) {
+  GOOGLE_CHECK_NOTNULL(parent);
   GOOGLE_CHECK_NOTNULL(field);
-  GOOGLE_CHECK_NOTNULL(message);
-  GOOGLE_CHECK_NOTNULL(cmessage);
+  GOOGLE_CHECK_NOTNULL(target);
 
   shared_ptr<Message> released_message(
-      ReleaseLast(field, cmessage->message->GetDescriptor(), message));
-  cmessage->parent = NULL;
-  cmessage->parent_field = NULL;
-  cmessage->message = released_message.get();
-  cmessage->read_only = false;
-  cmessage::SetOwner(cmessage, released_message);
+      parent->message->GetReflection()->ReleaseLast(parent->message, field));
+  // TODO(tibell): Deal with proto1.
+
+  target->parent = NULL;
+  target->parent_field_descriptor = NULL;
+  target->message = released_message.get();
+  target->read_only = false;
+  cmessage::SetOwner(target, released_message);
 }
 
 // Called to release a container using
@@ -633,7 +463,7 @@
   }
 
   Message* message = self->message;
-  const FieldDescriptor* field = self->parent_field->descriptor;
+  const FieldDescriptor* field = self->parent_field_descriptor;
 
   // The reflection API only lets us release the last message in a
   // repeated field.  Therefore we iterate through the children
@@ -643,12 +473,12 @@
   for (Py_ssize_t i = size - 1; i >= 0; --i) {
     CMessage* child_cmessage = reinterpret_cast<CMessage*>(
         PyList_GET_ITEM(self->child_messages, i));
-    ReleaseLastTo(field, message, child_cmessage);
+    ReleaseLastTo(self->parent, field, child_cmessage);
   }
 
   // Detach from containing message.
   self->parent = NULL;
-  self->parent_field = NULL;
+  self->parent_field_descriptor = NULL;
   self->message = NULL;
   self->owner.reset();
 
@@ -670,22 +500,40 @@
   return 0;
 }
 
-static int Init(RepeatedCompositeContainer* self,
-                PyObject* args,
-                PyObject* kwargs) {
-  self->message = NULL;
-  self->parent = NULL;
-  self->parent_field = NULL;
-  self->subclass_init = NULL;
+// The private constructor of RepeatedCompositeContainer objects.
+PyObject *NewContainer(
+    CMessage* parent,
+    const FieldDescriptor* parent_field_descriptor,
+    CMessageClass* concrete_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(
+          PyType_GenericAlloc(&RepeatedCompositeContainer_Type, 0));
+  if (self == NULL) {
+    return NULL;
+  }
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  Py_INCREF(concrete_class);
+  self->child_message_class = concrete_class;
   self->child_messages = PyList_New(0);
-  return 0;
+
+  return reinterpret_cast<PyObject*>(self);
 }
 
 static void Dealloc(RepeatedCompositeContainer* self) {
   Py_CLEAR(self->child_messages);
+  Py_CLEAR(self->child_message_class);
   // TODO(tibell): Do we need to call delete on these objects to make
   // sure their destructors are called?
   self->owner.reset();
+
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
@@ -707,6 +555,8 @@
     "Adds an object to the repeated container." },
   { "extend", (PyCFunction) Extend, METH_O,
     "Adds objects to the repeated container." },
+  { "pop", (PyCFunction)Pop, METH_VARARGS,
+    "Removes an object from the repeated container and returns it." },
   { "remove", (PyCFunction) Remove, METH_O,
     "Removes an object from the repeated container." },
   { "sort", (PyCFunction) Sort, METH_VARARGS | METH_KEYWORDS,
@@ -720,9 +570,8 @@
 
 PyTypeObject RepeatedCompositeContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-  "cpp._message.RepeatedCompositeContainer",  // tp_name
-  sizeof(RepeatedCompositeContainer),     // tp_basicsize
+  FULL_MODULE_NAME ".RepeatedCompositeContainer",  // tp_name
+  sizeof(RepeatedCompositeContainer),  // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_composite_container::Dealloc,  //  tp_dealloc
   0,                                   //  tp_print
@@ -733,7 +582,7 @@
   0,                                   //  tp_as_number
   &repeated_composite_container::SqMethods,   //  tp_as_sequence
   &repeated_composite_container::MpMethods,   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_getattro
@@ -755,7 +604,7 @@
   0,                                   //  tp_descr_get
   0,                                   //  tp_descr_set
   0,                                   //  tp_dictoffset
-  (initproc)repeated_composite_container::Init,  //  tp_init
+  0,                                   //  tp_init
 };
 
 }  // namespace python
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
index 898ef5a..a7b56b6 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.h
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -43,30 +43,33 @@
 #include <string>
 #include <vector>
 
-
 namespace google {
 namespace protobuf {
 
 class FieldDescriptor;
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
 struct CMessage;
-struct CFieldDescriptor;
+struct CMessageClass;
 
 // A RepeatedCompositeContainer can be in one of two states: attached
 // or released.
 //
 // When in the attached state all modifications to the container are
 // done both on the 'message' and on the 'child_messages'
-// list.  In this state all Messages refered to by the children in
+// list.  In this state all Messages referred to by the children in
 // 'child_messages' are owner by the 'owner'.
 //
 // When in the released state 'message', 'owner', 'parent', and
-// 'parent_field' are NULL.
+// 'parent_field_descriptor' are NULL.
 typedef struct RepeatedCompositeContainer {
   PyObject_HEAD;
 
@@ -82,7 +85,8 @@
   CMessage* parent;
 
   // A descriptor used to modify the underlying 'message'.
-  CFieldDescriptor* parent_field;
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
 
   // Pointer to the C++ Message that contains this container.  The
   // RepeatedCompositeContainer does not own this pointer.
@@ -91,8 +95,8 @@
   // calling Clear() or ClearField() on the parent.
   Message* message;
 
-  // A callable that is used to create new child messages.
-  PyObject* subclass_init;
+  // The type used to create new child messages.
+  CMessageClass* child_message_class;
 
   // A list of child messages.
   PyObject* child_messages;
@@ -102,8 +106,12 @@
 
 namespace repeated_composite_container {
 
-// Returns the number of items in this repeated composite container.
-static Py_ssize_t Length(RepeatedCompositeContainer* self);
+// Builds a RepeatedCompositeContainer object, from a parent message and a
+// field descriptor.
+PyObject *NewContainer(
+    CMessage* parent,
+    const FieldDescriptor* parent_field_descriptor,
+    CMessageClass *child_message_class);
 
 // Appends a new CMessage to the container and returns it.  The
 // CMessage is initialized using the content of kwargs.
@@ -143,8 +151,7 @@
 // Releases the messages in the container to the given message.
 //
 // Returns 0 on success, -1 on failure.
-int ReleaseToMessage(RepeatedCompositeContainer* self,
-                     google::protobuf::Message* new_message);
+int ReleaseToMessage(RepeatedCompositeContainer* self, Message* new_message);
 
 // Releases the messages in the container to a new message.
 //
@@ -156,13 +163,13 @@
              const shared_ptr<Message>& new_owner);
 
 // Removes the last element of the repeated message field 'field' on
-// the Message 'message', and transfers the ownership of the released
-// Message to 'cmessage'.
+// the Message 'parent', and transfers the ownership of the released
+// Message to 'target'.
 //
 // Corresponds to reflection api method ReleaseMessage.
-void ReleaseLastTo(const FieldDescriptor* field,
-                   Message* message,
-                   CMessage* cmessage);
+void ReleaseLastTo(CMessage* parent,
+                   const FieldDescriptor* field,
+                   CMessage* target);
 
 }  // namespace repeated_composite_container
 }  // namespace python
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index e627d37..95da85f 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -39,10 +39,12 @@
 #endif
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
@@ -52,7 +54,7 @@
     #error "Python 3.0 - 3.2 are not supported."
   #else
   #define PyString_AsString(ob) \
-    (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob))
+    (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AsString(ob))
   #endif
 #endif
 
@@ -60,17 +62,15 @@
 namespace protobuf {
 namespace python {
 
-extern google::protobuf::DynamicMessageFactory* global_message_factory;
-
 namespace repeated_scalar_container {
 
 static int InternalAssignRepeatedField(
     RepeatedScalarContainer* self, PyObject* list) {
   self->message->GetReflection()->ClearField(self->message,
-                                             self->parent_field->descriptor);
+                                             self->parent_field_descriptor);
   for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
     PyObject* value = PyList_GET_ITEM(list, i);
-    if (Append(self, value) == NULL) {
+    if (ScopedPyObjectPtr(Append(self, value)) == NULL) {
       return -1;
     }
   }
@@ -78,25 +78,19 @@
 }
 
 static Py_ssize_t Len(RepeatedScalarContainer* self) {
-  google::protobuf::Message* message = self->message;
+  Message* message = self->message;
   return message->GetReflection()->FieldSize(*message,
-                                             self->parent_field->descriptor);
+                                             self->parent_field_descriptor);
 }
 
 static int AssignItem(RepeatedScalarContainer* self,
                       Py_ssize_t index,
                       PyObject* arg) {
   cmessage::AssureWritable(self->parent);
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->parent_field->descriptor;
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return -1;
-  }
+  Message* message = self->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
 
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  const Reflection* reflection = message->GetReflection();
   int field_size = reflection->FieldSize(*message, field_descriptor);
   if (index < 0) {
     index = field_size + index;
@@ -110,8 +104,8 @@
 
   if (arg == NULL) {
     ScopedPyObjectPtr py_index(PyLong_FromLong(index));
-    return cmessage::InternalDeleteRepeatedField(message, field_descriptor,
-                                                 py_index, NULL);
+    return cmessage::InternalDeleteRepeatedField(self->parent, field_descriptor,
+                                                 py_index.get(), NULL);
   }
 
   if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
@@ -120,64 +114,68 @@
   }
 
   switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
+    case FieldDescriptor::CPPTYPE_INT32: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
       reflection->SetRepeatedInt32(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
+    case FieldDescriptor::CPPTYPE_INT64: {
       GOOGLE_CHECK_GET_INT64(arg, value, -1);
       reflection->SetRepeatedInt64(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
+    case FieldDescriptor::CPPTYPE_UINT32: {
       GOOGLE_CHECK_GET_UINT32(arg, value, -1);
       reflection->SetRepeatedUInt32(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
+    case FieldDescriptor::CPPTYPE_UINT64: {
       GOOGLE_CHECK_GET_UINT64(arg, value, -1);
       reflection->SetRepeatedUInt64(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
+    case FieldDescriptor::CPPTYPE_FLOAT: {
       GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
       reflection->SetRepeatedFloat(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
       GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
       reflection->SetRepeatedDouble(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
+    case FieldDescriptor::CPPTYPE_BOOL: {
       GOOGLE_CHECK_GET_BOOL(arg, value, -1);
       reflection->SetRepeatedBool(message, field_descriptor, index, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
+    case FieldDescriptor::CPPTYPE_STRING: {
       if (!CheckAndSetString(
           arg, message, field_descriptor, reflection, false, index)) {
         return -1;
       }
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
+    case FieldDescriptor::CPPTYPE_ENUM: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
-      const google::protobuf::EnumDescriptor* enum_descriptor =
-          field_descriptor->enum_type();
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          enum_descriptor->FindValueByNumber(value);
-      if (enum_value != NULL) {
-        reflection->SetRepeatedEnum(message, field_descriptor, index,
-                                    enum_value);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->SetRepeatedEnumValue(message, field_descriptor, index,
+                                         value);
       } else {
-        ScopedPyObjectPtr s(PyObject_Str(arg));
-        if (s != NULL) {
-          PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                       PyString_AsString(s.get()));
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != NULL) {
+          reflection->SetRepeatedEnum(message, field_descriptor, index,
+                                      enum_value);
+        } else {
+          ScopedPyObjectPtr s(PyObject_Str(arg));
+          if (s != NULL) {
+            PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+                         PyString_AsString(s.get()));
+          }
+          return -1;
         }
-        return -1;
       }
       break;
     }
@@ -191,10 +189,9 @@
 }
 
 static PyObject* Item(RepeatedScalarContainer* self, Py_ssize_t index) {
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->parent_field->descriptor;
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  Message* message = self->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+  const Reflection* reflection = message->GetReflection();
 
   int field_size = reflection->FieldSize(*message, field_descriptor);
   if (index < 0) {
@@ -202,80 +199,80 @@
   }
   if (index < 0 || index >= field_size) {
     PyErr_Format(PyExc_IndexError,
-                 "list assignment index (%d) out of range",
-                 static_cast<int>(index));
+                 "list index (%zd) out of range",
+                 index);
     return NULL;
   }
 
   PyObject* result = NULL;
   switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
+    case FieldDescriptor::CPPTYPE_INT32: {
       int32 value = reflection->GetRepeatedInt32(
           *message, field_descriptor, index);
       result = PyInt_FromLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
+    case FieldDescriptor::CPPTYPE_INT64: {
       int64 value = reflection->GetRepeatedInt64(
           *message, field_descriptor, index);
       result = PyLong_FromLongLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
+    case FieldDescriptor::CPPTYPE_UINT32: {
       uint32 value = reflection->GetRepeatedUInt32(
           *message, field_descriptor, index);
       result = PyLong_FromLongLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
+    case FieldDescriptor::CPPTYPE_UINT64: {
       uint64 value = reflection->GetRepeatedUInt64(
           *message, field_descriptor, index);
       result = PyLong_FromUnsignedLongLong(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
+    case FieldDescriptor::CPPTYPE_FLOAT: {
       float value = reflection->GetRepeatedFloat(
           *message, field_descriptor, index);
       result = PyFloat_FromDouble(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
       double value = reflection->GetRepeatedDouble(
           *message, field_descriptor, index);
       result = PyFloat_FromDouble(value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
+    case FieldDescriptor::CPPTYPE_BOOL: {
       bool value = reflection->GetRepeatedBool(
           *message, field_descriptor, index);
       result = PyBool_FromLong(value ? 1 : 0);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
-      const google::protobuf::EnumValueDescriptor* enum_value =
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      const EnumValueDescriptor* enum_value =
           message->GetReflection()->GetRepeatedEnum(
               *message, field_descriptor, index);
       result = PyInt_FromLong(enum_value->number());
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
+    case FieldDescriptor::CPPTYPE_STRING: {
       string value = reflection->GetRepeatedString(
           *message, field_descriptor, index);
       result = ToStringObject(field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
       PyObject* py_cmsg = PyObject_CallObject(reinterpret_cast<PyObject*>(
           &CMessage_Type), NULL);
       if (py_cmsg == NULL) {
         return NULL;
       }
       CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
-      const google::protobuf::Message& msg = reflection->GetRepeatedMessage(
+      const Message& msg = reflection->GetRepeatedMessage(
           *message, field_descriptor, index);
       cmsg->owner = self->owner;
       cmsg->parent = self->parent;
-      cmsg->message = const_cast<google::protobuf::Message*>(&msg);
+      cmsg->message = const_cast<Message*>(&msg);
       cmsg->read_only = false;
       result = reinterpret_cast<PyObject*>(py_cmsg);
       break;
@@ -337,7 +334,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   } else {
     if (step > 0) {
@@ -348,7 +345,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   }
   return list;
@@ -356,75 +353,71 @@
 
 PyObject* Append(RepeatedScalarContainer* self, PyObject* item) {
   cmessage::AssureWritable(self->parent);
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->parent_field->descriptor;
+  Message* message = self->message;
+  const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
 
-  if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return NULL;
-  }
-
-  const google::protobuf::Reflection* reflection = message->GetReflection();
+  const Reflection* reflection = message->GetReflection();
   switch (field_descriptor->cpp_type()) {
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
+    case FieldDescriptor::CPPTYPE_INT32: {
       GOOGLE_CHECK_GET_INT32(item, value, NULL);
       reflection->AddInt32(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
+    case FieldDescriptor::CPPTYPE_INT64: {
       GOOGLE_CHECK_GET_INT64(item, value, NULL);
       reflection->AddInt64(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
+    case FieldDescriptor::CPPTYPE_UINT32: {
       GOOGLE_CHECK_GET_UINT32(item, value, NULL);
       reflection->AddUInt32(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
+    case FieldDescriptor::CPPTYPE_UINT64: {
       GOOGLE_CHECK_GET_UINT64(item, value, NULL);
       reflection->AddUInt64(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
+    case FieldDescriptor::CPPTYPE_FLOAT: {
       GOOGLE_CHECK_GET_FLOAT(item, value, NULL);
       reflection->AddFloat(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
       GOOGLE_CHECK_GET_DOUBLE(item, value, NULL);
       reflection->AddDouble(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
+    case FieldDescriptor::CPPTYPE_BOOL: {
       GOOGLE_CHECK_GET_BOOL(item, value, NULL);
       reflection->AddBool(message, field_descriptor, value);
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
+    case FieldDescriptor::CPPTYPE_STRING: {
       if (!CheckAndSetString(
           item, message, field_descriptor, reflection, true, -1)) {
         return NULL;
       }
       break;
     }
-    case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
+    case FieldDescriptor::CPPTYPE_ENUM: {
       GOOGLE_CHECK_GET_INT32(item, value, NULL);
-      const google::protobuf::EnumDescriptor* enum_descriptor =
-          field_descriptor->enum_type();
-      const google::protobuf::EnumValueDescriptor* enum_value =
-          enum_descriptor->FindValueByNumber(value);
-      if (enum_value != NULL) {
-        reflection->AddEnum(message, field_descriptor, enum_value);
+      if (reflection->SupportsUnknownEnumValues()) {
+        reflection->AddEnumValue(message, field_descriptor, value);
       } else {
-        ScopedPyObjectPtr s(PyObject_Str(item));
-        if (s != NULL) {
-          PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                       PyString_AsString(s.get()));
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != NULL) {
+          reflection->AddEnum(message, field_descriptor, enum_value);
+        } else {
+          ScopedPyObjectPtr s(PyObject_Str(item));
+          if (s != NULL) {
+            PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
+                         PyString_AsString(s.get()));
+          }
+          return NULL;
         }
-        return NULL;
       }
       break;
     }
@@ -449,9 +442,9 @@
   bool create_list = false;
 
   cmessage::AssureWritable(self->parent);
-  google::protobuf::Message* message = self->message;
-  const google::protobuf::FieldDescriptor* field_descriptor =
-      self->parent_field->descriptor;
+  Message* message = self->message;
+  const FieldDescriptor* field_descriptor =
+      self->parent_field_descriptor;
 
 #if PY_MAJOR_VERSION < 3
   if (PyInt_Check(slice)) {
@@ -461,7 +454,7 @@
   if (PyLong_Check(slice)) {
     from = to = PyLong_AsLong(slice);
   } else if (PySlice_Check(slice)) {
-    const google::protobuf::Reflection* reflection = message->GetReflection();
+    const Reflection* reflection = message->GetReflection();
     length = reflection->FieldSize(*message, field_descriptor);
 #if PY_MAJOR_VERSION >= 3
     if (PySlice_GetIndicesEx(slice,
@@ -479,7 +472,7 @@
 
   if (value == NULL) {
     return cmessage::InternalDeleteRepeatedField(
-        message, field_descriptor, slice, NULL);
+        self->parent, field_descriptor, slice, NULL);
   }
 
   if (!create_list) {
@@ -490,30 +483,36 @@
   if (full_slice == NULL) {
     return -1;
   }
-  ScopedPyObjectPtr new_list(Subscript(self, full_slice));
+  ScopedPyObjectPtr new_list(Subscript(self, full_slice.get()));
   if (new_list == NULL) {
     return -1;
   }
-  if (PySequence_SetSlice(new_list, from, to, value) < 0) {
+  if (PySequence_SetSlice(new_list.get(), from, to, value) < 0) {
     return -1;
   }
 
-  return InternalAssignRepeatedField(self, new_list);
+  return InternalAssignRepeatedField(self, new_list.get());
 }
 
 PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
   cmessage::AssureWritable(self->parent);
-  if (PyObject_Not(value)) {
+
+  // TODO(ptucker): Deprecate this behavior. b/18413862
+  if (value == Py_None) {
     Py_RETURN_NONE;
   }
+  if ((Py_TYPE(value)->tp_as_sequence == NULL) && PyObject_Not(value)) {
+    Py_RETURN_NONE;
+  }
+
   ScopedPyObjectPtr iter(PyObject_GetIter(value));
   if (iter == NULL) {
     PyErr_SetString(PyExc_TypeError, "Value must be iterable");
     return NULL;
   }
   ScopedPyObjectPtr next;
-  while ((next.reset(PyIter_Next(iter))) != NULL) {
-    if (Append(self, next) == NULL) {
+  while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+    if (ScopedPyObjectPtr(Append(self, next.get())) == NULL) {
       return NULL;
     }
   }
@@ -530,11 +529,11 @@
     return NULL;
   }
   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
-  ScopedPyObjectPtr new_list(Subscript(self, full_slice));
-  if (PyList_Insert(new_list, index, value) < 0) {
+  ScopedPyObjectPtr new_list(Subscript(self, full_slice.get()));
+  if (PyList_Insert(new_list.get(), index, value) < 0) {
     return NULL;
   }
-  int ret = InternalAssignRepeatedField(self, new_list);
+  int ret = InternalAssignRepeatedField(self, new_list.get());
   if (ret < 0) {
     return NULL;
   }
@@ -545,7 +544,7 @@
   Py_ssize_t match_index = -1;
   for (Py_ssize_t i = 0; i < Len(self); ++i) {
     ScopedPyObjectPtr elem(Item(self, i));
-    if (PyObject_RichCompareBool(elem, value, Py_EQ)) {
+    if (PyObject_RichCompareBool(elem.get(), value, Py_EQ)) {
       match_index = i;
       break;
     }
@@ -580,15 +579,15 @@
   ScopedPyObjectPtr other_list_deleter;
   if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
     other_list_deleter.reset(Subscript(
-        reinterpret_cast<RepeatedScalarContainer*>(other), full_slice));
+        reinterpret_cast<RepeatedScalarContainer*>(other), full_slice.get()));
     other = other_list_deleter.get();
   }
 
-  ScopedPyObjectPtr list(Subscript(self, full_slice));
+  ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
   if (list == NULL) {
     return NULL;
   }
-  return PyObject_RichCompare(list, other, opid);
+  return PyObject_RichCompare(list.get(), other, opid);
 }
 
 PyObject* Reduce(RepeatedScalarContainer* unused_self) {
@@ -619,66 +618,63 @@
   if (full_slice == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr list(Subscript(self, full_slice));
+  ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
   if (list == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr m(PyObject_GetAttrString(list, "sort"));
+  ScopedPyObjectPtr m(PyObject_GetAttrString(list.get(), "sort"));
   if (m == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr res(PyObject_Call(m, args, kwds));
+  ScopedPyObjectPtr res(PyObject_Call(m.get(), args, kwds));
   if (res == NULL) {
     return NULL;
   }
-  int ret = InternalAssignRepeatedField(self, list);
+  int ret = InternalAssignRepeatedField(self, list.get());
   if (ret < 0) {
     return NULL;
   }
   Py_RETURN_NONE;
 }
 
-static int Init(RepeatedScalarContainer* self,
-                PyObject* args,
-                PyObject* kwargs) {
-  PyObject* py_parent;
-  PyObject* py_parent_field;
-  if (!PyArg_UnpackTuple(args, "__init__()", 2, 2, &py_parent,
-                         &py_parent_field)) {
-    return -1;
+static PyObject* Pop(RepeatedScalarContainer* self,
+                     PyObject* args) {
+  Py_ssize_t index = -1;
+  if (!PyArg_ParseTuple(args, "|n", &index)) {
+    return NULL;
+  }
+  PyObject* item = Item(self, index);
+  if (item == NULL) {
+    PyErr_Format(PyExc_IndexError,
+                 "list index (%zd) out of range",
+                 index);
+    return NULL;
+  }
+  if (AssignItem(self, index, NULL) < 0) {
+    return NULL;
+  }
+  return item;
+}
+
+// The private constructor of RepeatedScalarContainer objects.
+PyObject *NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
   }
 
-  if (!PyObject_TypeCheck(py_parent, &CMessage_Type)) {
-    PyErr_Format(PyExc_TypeError,
-                 "expect %s, but got %s",
-                 CMessage_Type.tp_name,
-                 Py_TYPE(py_parent)->tp_name);
-    return -1;
+  RepeatedScalarContainer* self = reinterpret_cast<RepeatedScalarContainer*>(
+      PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0));
+  if (self == NULL) {
+    return NULL;
   }
 
-  if (!PyObject_TypeCheck(py_parent_field, &CFieldDescriptor_Type)) {
-    PyErr_Format(PyExc_TypeError,
-                 "expect %s, but got %s",
-                 CFieldDescriptor_Type.tp_name,
-                 Py_TYPE(py_parent_field)->tp_name);
-    return -1;
-  }
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
 
-  CMessage* cmessage = reinterpret_cast<CMessage*>(py_parent);
-  CFieldDescriptor* cdescriptor = reinterpret_cast<CFieldDescriptor*>(
-      py_parent_field);
-
-  if (!FIELD_BELONGS_TO_MESSAGE(cdescriptor->descriptor, cmessage->message)) {
-    PyErr_SetString(
-        PyExc_KeyError, "Field does not belong to message!");
-    return -1;
-  }
-
-  self->message = cmessage->message;
-  self->parent = cmessage;
-  self->parent_field = cdescriptor;
-  self->owner = cmessage->owner;
-  return 0;
+  return reinterpret_cast<PyObject*>(self);
 }
 
 // Initializes the underlying Message object of "to" so it becomes a new parent
@@ -692,20 +688,16 @@
   if (full_slice == NULL) {
     return -1;
   }
-  ScopedPyObjectPtr values(Subscript(from, full_slice));
+  ScopedPyObjectPtr values(Subscript(from, full_slice.get()));
   if (values == NULL) {
     return -1;
   }
-  google::protobuf::Message* new_message = global_message_factory->GetPrototype(
-      from->message->GetDescriptor())->New();
+  Message* new_message = from->message->New();
   to->parent = NULL;
-  // TODO(anuraag): Document why it's OK to hang on to parent_field,
-  //     even though it's a weak reference. It ought to be enough to
-  //     hold on to the FieldDescriptor only.
-  to->parent_field = from->parent_field;
+  to->parent_field_descriptor = from->parent_field_descriptor;
   to->message = new_message;
   to->owner.reset(new_message);
-  if (InternalAssignRepeatedField(to, values) < 0) {
+  if (InternalAssignRepeatedField(to, values.get()) < 0) {
     return -1;
   }
   return 0;
@@ -716,23 +708,17 @@
 }
 
 PyObject* DeepCopy(RepeatedScalarContainer* self, PyObject* arg) {
-  ScopedPyObjectPtr init_args(
-      PyTuple_Pack(2, self->parent, self->parent_field));
-  PyObject* clone = PyObject_CallObject(
-      reinterpret_cast<PyObject*>(&RepeatedScalarContainer_Type), init_args);
+  RepeatedScalarContainer* clone = reinterpret_cast<RepeatedScalarContainer*>(
+      PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0));
   if (clone == NULL) {
     return NULL;
   }
-  if (!PyObject_TypeCheck(clone, &RepeatedScalarContainer_Type)) {
+
+  if (InitializeAndCopyToParentContainer(self, clone) < 0) {
     Py_DECREF(clone);
     return NULL;
   }
-  if (InitializeAndCopyToParentContainer(
-          self, reinterpret_cast<RepeatedScalarContainer*>(clone)) < 0) {
-    Py_DECREF(clone);
-    return NULL;
-  }
-  return clone;
+  return reinterpret_cast<PyObject*>(clone);
 }
 
 static void Dealloc(RepeatedScalarContainer* self) {
@@ -771,6 +757,8 @@
     "Appends objects to the repeated container." },
   { "insert", (PyCFunction)Insert, METH_VARARGS,
     "Appends objects to the repeated container." },
+  { "pop", (PyCFunction)Pop, METH_VARARGS,
+    "Removes an object from the repeated container and returns it." },
   { "remove", (PyCFunction)Remove, METH_O,
     "Removes an object from the repeated container." },
   { "sort", (PyCFunction)Sort, METH_VARARGS | METH_KEYWORDS,
@@ -782,8 +770,7 @@
 
 PyTypeObject RepeatedScalarContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-  "cpp._message.RepeatedScalarContainer",  // tp_name
+  FULL_MODULE_NAME ".RepeatedScalarContainer",  // tp_name
   sizeof(RepeatedScalarContainer),     // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc
@@ -795,7 +782,7 @@
   0,                                   //  tp_as_number
   &repeated_scalar_container::SqMethods,   //  tp_as_sequence
   &repeated_scalar_container::MpMethods,   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_getattro
@@ -817,7 +804,7 @@
   0,                                   //  tp_descr_get
   0,                                   //  tp_descr_set
   0,                                   //  tp_dictoffset
-  (initproc)repeated_scalar_container::Init,  //  tp_init
+  0,                                   //  tp_init
 };
 
 }  // namespace python
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h
index 69d15d5..555e621 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.h
+++ b/python/google/protobuf/pyext/repeated_scalar_container.h
@@ -41,17 +41,21 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 
+#include <google/protobuf/descriptor.h>
 
 namespace google {
 namespace protobuf {
 
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
-struct CFieldDescriptor;
 struct CMessage;
 
 typedef struct RepeatedScalarContainer {
@@ -73,16 +77,22 @@
   // modifying the container.
   CMessage* parent;
 
-  // Weak reference to the parent's descriptor that describes this
+  // Pointer to the parent's descriptor that describes this
   // field.  Used together with the parent's message when making a
   // default message instance mutable.
-  CFieldDescriptor* parent_field;
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
 } RepeatedScalarContainer;
 
 extern PyTypeObject RepeatedScalarContainer_Type;
 
 namespace repeated_scalar_container {
 
+// Builds a RepeatedScalarContainer object, from a parent message and a
+// field descriptor.
+extern PyObject *NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
+
 // Appends the scalar 'item' to the end of the container 'self'.
 //
 // Returns None if successful; returns NULL and sets an exception if
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
index 9f337c3..a128cd4 100644
--- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -33,12 +33,14 @@
 #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
 #define GOOGLE_PROTOBUF_PYTHON_CPP_SCOPED_PYOBJECT_PTR_H__
 
+#include <google/protobuf/stubs/common.h>
+
 #include <Python.h>
 
 namespace google {
 class ScopedPyObjectPtr {
  public:
-  // Constructor.  Defaults to intializing with NULL.
+  // Constructor.  Defaults to initializing with NULL.
   // There is no way to create an uninitialized ScopedPyObjectPtr.
   explicit ScopedPyObjectPtr(PyObject* p = NULL) : ptr_(p) { }
 
@@ -49,24 +51,23 @@
 
   // Reset.  Deletes the current owned object, if any.
   // Then takes ownership of a new object, if given.
-  // this->reset(this->get()) works.
+  // This function must be called with a reference that you own.
+  //   this->reset(this->get()) is wrong!
+  //   this->reset(this->release()) is OK.
   PyObject* reset(PyObject* p = NULL) {
-    if (p != ptr_) {
-      Py_XDECREF(ptr_);
-      ptr_ = p;
-    }
+    Py_XDECREF(ptr_);
+    ptr_ = p;
     return ptr_;
   }
 
   // Releases ownership of the object.
+  // The caller now owns the returned reference.
   PyObject* release() {
     PyObject* p = ptr_;
     ptr_ = NULL;
     return p;
   }
 
-  operator PyObject*() { return ptr_; }
-
   PyObject* operator->() const  {
     assert(ptr_ != NULL);
     return ptr_;
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
index 1fc704a..0c75726 100755
--- a/python/google/protobuf/reflection.py
+++ b/python/google/protobuf/reflection.py
@@ -49,108 +49,23 @@
 
 
 from google.protobuf.internal import api_implementation
-from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message
 
-_FieldDescriptor = descriptor_mod.FieldDescriptor
-
 
 if api_implementation.Type() == 'cpp':
-  if api_implementation.Version() == 2:
-    from google.protobuf.pyext import cpp_message
-    _NewMessage = cpp_message.NewMessage
-    _InitMessage = cpp_message.InitMessage
-  else:
-    from google.protobuf.internal import cpp_message
-    _NewMessage = cpp_message.NewMessage
-    _InitMessage = cpp_message.InitMessage
+  from google.protobuf.pyext import cpp_message as message_impl
 else:
-  from google.protobuf.internal import python_message
-  _NewMessage = python_message.NewMessage
-  _InitMessage = python_message.InitMessage
+  from google.protobuf.internal import python_message as message_impl
 
-
-class GeneratedProtocolMessageType(type):
-
-  """Metaclass for protocol message classes created at runtime from Descriptors.
-
-  We add implementations for all methods described in the Message class.  We
-  also create properties to allow getting/setting all fields in the protocol
-  message.  Finally, we create slots to prevent users from accidentally
-  "setting" nonexistent fields in the protocol message, which then wouldn't get
-  serialized / deserialized properly.
-
-  The protocol compiler currently uses this metaclass to create protocol
-  message classes at runtime.  Clients can also manually create their own
-  classes at runtime, as in this example:
-
-  mydescriptor = Descriptor(.....)
-  class MyProtoClass(Message):
-    __metaclass__ = GeneratedProtocolMessageType
-    DESCRIPTOR = mydescriptor
-  myproto_instance = MyProtoClass()
-  myproto.foo_field = 23
-  ...
-
-  The above example will not work for nested types. If you wish to include them,
-  use reflection.MakeClass() instead of manually instantiating the class in
-  order to create the appropriate class structure.
-  """
-
-  # Must be consistent with the protocol-compiler code in
-  # proto2/compiler/internal/generator.*.
-  _DESCRIPTOR_KEY = 'DESCRIPTOR'
-
-  def __new__(cls, name, bases, dictionary):
-    """Custom allocation for runtime-generated class types.
-
-    We override __new__ because this is apparently the only place
-    where we can meaningfully set __slots__ on the class we're creating(?).
-    (The interplay between metaclasses and slots is not very well-documented).
-
-    Args:
-      name: Name of the class (ignored, but required by the
-        metaclass protocol).
-      bases: Base classes of the class we're constructing.
-        (Should be message.Message).  We ignore this field, but
-        it's required by the metaclass protocol
-      dictionary: The class dictionary of the class we're
-        constructing.  dictionary[_DESCRIPTOR_KEY] must contain
-        a Descriptor object describing this protocol message
-        type.
-
-    Returns:
-      Newly-allocated class.
-    """
-    descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
-    bases = _NewMessage(bases, descriptor, dictionary)
-    superclass = super(GeneratedProtocolMessageType, cls)
-
-    new_class = superclass.__new__(cls, name, bases, dictionary)
-    setattr(descriptor, '_concrete_class', new_class)
-    return new_class
-
-  def __init__(cls, name, bases, dictionary):
-    """Here we perform the majority of our work on the class.
-    We add enum getters, an __init__ method, implementations
-    of all Message methods, and properties for all fields
-    in the protocol type.
-
-    Args:
-      name: Name of the class (ignored, but required by the
-        metaclass protocol).
-      bases: Base classes of the class we're constructing.
-        (Should be message.Message).  We ignore this field, but
-        it's required by the metaclass protocol
-      dictionary: The class dictionary of the class we're
-        constructing.  dictionary[_DESCRIPTOR_KEY] must contain
-        a Descriptor object describing this protocol message
-        type.
-    """
-    descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
-    _InitMessage(descriptor, cls)
-    superclass = super(GeneratedProtocolMessageType, cls)
-    superclass.__init__(name, bases, dictionary)
+# The type of all Message classes.
+# Part of the public interface.
+#
+# Used by generated files, but clients can also use it at runtime:
+#   mydescriptor = pool.FindDescriptor(.....)
+#   class MyProtoClass(Message):
+#     __metaclass__ = GeneratedProtocolMessageType
+#     DESCRIPTOR = mydescriptor
+GeneratedProtocolMessageType = message_impl.GeneratedProtocolMessageType
 
 
 def ParseMessage(descriptor, byte_str):
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
index 4c70b39..87760f2 100644
--- a/python/google/protobuf/symbol_database.py
+++ b/python/google/protobuf/symbol_database.py
@@ -72,12 +72,12 @@
   buffer types used within a program.
   """
 
-  def __init__(self):
+  def __init__(self, pool=None):
     """Constructor."""
 
     self._symbols = {}
     self._symbols_by_file = {}
-    self.pool = descriptor_pool.DescriptorPool()
+    self.pool = pool or descriptor_pool.Default()
 
   def RegisterMessage(self, message):
     """Registers the given message type in the local database.
@@ -177,7 +177,7 @@
       result.update(self._symbols_by_file[f])
     return result
 
-_DEFAULT = SymbolDatabase()
+_DEFAULT = SymbolDatabase(pool=descriptor_pool.Default())
 
 
 def Default():
diff --git a/python/google/protobuf/text_encoding.py b/python/google/protobuf/text_encoding.py
index 2d86a67..9899563 100644
--- a/python/google/protobuf/text_encoding.py
+++ b/python/google/protobuf/text_encoding.py
@@ -28,15 +28,13 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
 """Encoding related utilities."""
-
 import re
-import sys  ##PY25
+
+import six
 
 # Lookup table for utf8
-_cescape_utf8_to_str = [chr(i) for i in xrange(0, 256)]
+_cescape_utf8_to_str = [chr(i) for i in range(0, 256)]
 _cescape_utf8_to_str[9] = r'\t'  # optional escape
 _cescape_utf8_to_str[10] = r'\n'  # optional escape
 _cescape_utf8_to_str[13] = r'\r'  # optional escape
@@ -46,9 +44,9 @@
 _cescape_utf8_to_str[92] = r'\\'  # necessary escape
 
 # Lookup table for non-utf8, with necessary escapes at (o >= 127 or o < 32)
-_cescape_byte_to_str = ([r'\%03o' % i for i in xrange(0, 32)] +
-                        [chr(i) for i in xrange(32, 127)] +
-                        [r'\%03o' % i for i in xrange(127, 256)])
+_cescape_byte_to_str = ([r'\%03o' % i for i in range(0, 32)] +
+                        [chr(i) for i in range(32, 127)] +
+                        [r'\%03o' % i for i in range(127, 256)])
 _cescape_byte_to_str[9] = r'\t'  # optional escape
 _cescape_byte_to_str[10] = r'\n'  # optional escape
 _cescape_byte_to_str[13] = r'\r'  # optional escape
@@ -75,7 +73,7 @@
   """
   # PY3 hack: make Ord work for str and bytes:
   # //platforms/networking/data uses unicode here, hence basestring.
-  Ord = ord if isinstance(text, basestring) else lambda x: x
+  Ord = ord if isinstance(text, six.string_types) else lambda x: x
   if as_utf8:
     return ''.join(_cescape_utf8_to_str[Ord(c)] for c in text)
   return ''.join(_cescape_byte_to_str[Ord(c)] for c in text)
@@ -100,8 +98,7 @@
   # allow single-digit hex escapes (like '\xf').
   result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
 
-  if sys.version_info[0] < 3:  ##PY25
-##!PY25  if str is bytes:  # PY2
+  if str is bytes:  # PY2
     return result.decode('string_escape')
   result = ''.join(_cescape_highbit_to_str[ord(c)] for c in result)
   return (result.encode('ascii')  # Make it bytes to allow decode.
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 2429fa5..6f1e3c8 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -28,17 +28,28 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#PY25 compatible for GAE.
-#
-# Copyright 2007 Google Inc. All Rights Reserved.
+"""Contains routines for printing protocol messages in text format.
 
-"""Contains routines for printing protocol messages in text format."""
+Simple usage example:
+
+  # Create a proto object and serialize it to a text proto string.
+  message = my_proto_pb2.MyMessage(foo='bar')
+  text_proto = text_format.MessageToString(message)
+
+  # Parse a text proto string.
+  message = text_format.Parse(text_proto, my_proto_pb2.MyMessage())
+"""
 
 __author__ = 'kenton@google.com (Kenton Varda)'
 
-import cStringIO
+import io
 import re
 
+import six
+
+if six.PY3:
+  long = int
+
 from google.protobuf.internal import type_checkers
 from google.protobuf import descriptor
 from google.protobuf import text_encoding
@@ -55,6 +66,7 @@
 _FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
 _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
                           descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
+_QUOTES = frozenset(("'", '"'))
 
 
 class Error(Exception):
@@ -62,17 +74,38 @@
 
 
 class ParseError(Error):
-  """Thrown in case of ASCII parsing error."""
+  """Thrown in case of text parsing error."""
+
+
+class TextWriter(object):
+  def __init__(self, as_utf8):
+    if six.PY2:
+      self._writer = io.BytesIO()
+    else:
+      self._writer = io.StringIO()
+
+  def write(self, val):
+    if six.PY2:
+      if isinstance(val, six.text_type):
+        val = val.encode('utf-8')
+    return self._writer.write(val)
+
+  def close(self):
+    return self._writer.close()
+
+  def getvalue(self):
+    return self._writer.getvalue()
 
 
 def MessageToString(message, as_utf8=False, as_one_line=False,
                     pointy_brackets=False, use_index_order=False,
-                    float_format=None):
+                    float_format=None, use_field_number=False):
   """Convert protobuf message to text format.
 
   Floating point values can be formatted compactly with 15 digits of
   precision (which is the most that IEEE 754 "double" can guarantee)
-  using float_format='.15g'.
+  using float_format='.15g'. To ensure that converting to text and back to a
+  proto will result in an identical value, float_format='.17g' should be used.
 
   Args:
     message: The protocol buffers message.
@@ -85,15 +118,16 @@
       field number order.
     float_format: If set, use this to specify floating point number formatting
       (per the "Format Specification Mini-Language"); otherwise, str() is used.
+    use_field_number: If True, print field numbers instead of names.
 
   Returns:
     A string of the text formatted protocol buffer message.
   """
-  out = cStringIO.StringIO()
-  PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line,
-               pointy_brackets=pointy_brackets,
-               use_index_order=use_index_order,
-               float_format=float_format)
+  out = TextWriter(as_utf8)
+  printer = _Printer(out, 0, as_utf8, as_one_line,
+                     pointy_brackets, use_index_order, float_format,
+                     use_field_number)
+  printer.PrintMessage(message)
   result = out.getvalue()
   out.close()
   if as_one_line:
@@ -101,262 +135,446 @@
   return result
 
 
+def _IsMapEntry(field):
+  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
 def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
                  pointy_brackets=False, use_index_order=False,
-                 float_format=None):
-  fields = message.ListFields()
-  if use_index_order:
-    fields.sort(key=lambda x: x[0].index)
-  for field, value in fields:
-    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
-      for element in value:
-        PrintField(field, element, out, indent, as_utf8, as_one_line,
-                   pointy_brackets=pointy_brackets,
-                   float_format=float_format)
-    else:
-      PrintField(field, value, out, indent, as_utf8, as_one_line,
-                 pointy_brackets=pointy_brackets,
-                 float_format=float_format)
+                 float_format=None, use_field_number=False):
+  printer = _Printer(out, indent, as_utf8, as_one_line,
+                     pointy_brackets, use_index_order, float_format,
+                     use_field_number)
+  printer.PrintMessage(message)
 
 
 def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,
-               pointy_brackets=False, float_format=None):
-  """Print a single field name/value pair.  For repeated fields, the value
-  should be a single element."""
-
-  out.write(' ' * indent)
-  if field.is_extension:
-    out.write('[')
-    if (field.containing_type.GetOptions().message_set_wire_format and
-        field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
-        field.message_type == field.extension_scope and
-        field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
-      out.write(field.message_type.full_name)
-    else:
-      out.write(field.full_name)
-    out.write(']')
-  elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
-    # For groups, use the capitalized name.
-    out.write(field.message_type.name)
-  else:
-    out.write(field.name)
-
-  if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-    # The colon is optional in this case, but our cross-language golden files
-    # don't include it.
-    out.write(': ')
-
-  PrintFieldValue(field, value, out, indent, as_utf8, as_one_line,
-                  pointy_brackets=pointy_brackets,
-                  float_format=float_format)
-  if as_one_line:
-    out.write(' ')
-  else:
-    out.write('\n')
+               pointy_brackets=False, use_index_order=False, float_format=None):
+  """Print a single field name/value pair."""
+  printer = _Printer(out, indent, as_utf8, as_one_line,
+                     pointy_brackets, use_index_order, float_format)
+  printer.PrintField(field, value)
 
 
 def PrintFieldValue(field, value, out, indent=0, as_utf8=False,
                     as_one_line=False, pointy_brackets=False,
+                    use_index_order=False,
                     float_format=None):
-  """Print a single field value (not including name).  For repeated fields,
-  the value should be a single element."""
+  """Print a single field value (not including name)."""
+  printer = _Printer(out, indent, as_utf8, as_one_line,
+                     pointy_brackets, use_index_order, float_format)
+  printer.PrintFieldValue(field, value)
 
-  if pointy_brackets:
-    openb = '<'
-    closeb = '>'
-  else:
-    openb = '{'
-    closeb = '}'
 
-  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-    if as_one_line:
-      out.write(' %s ' % openb)
-      PrintMessage(value, out, indent, as_utf8, as_one_line,
-                   pointy_brackets=pointy_brackets,
-                   float_format=float_format)
-      out.write(closeb)
+class _Printer(object):
+  """Text format printer for protocol message."""
+
+  def __init__(self, out, indent=0, as_utf8=False, as_one_line=False,
+               pointy_brackets=False, use_index_order=False, float_format=None,
+               use_field_number=False):
+    """Initialize the Printer.
+
+    Floating point values can be formatted compactly with 15 digits of
+    precision (which is the most that IEEE 754 "double" can guarantee)
+    using float_format='.15g'. To ensure that converting to text and back to a
+    proto will result in an identical value, float_format='.17g' should be used.
+
+    Args:
+      out: To record the text format result.
+      indent: The indent level for pretty print.
+      as_utf8: Produce text output in UTF8 format.
+      as_one_line: Don't introduce newlines between fields.
+      pointy_brackets: If True, use angle brackets instead of curly braces for
+        nesting.
+      use_index_order: If True, print fields of a proto message using the order
+        defined in source code instead of the field number. By default, use the
+        field number order.
+      float_format: If set, use this to specify floating point number formatting
+        (per the "Format Specification Mini-Language"); otherwise, str() is
+        used.
+      use_field_number: If True, print field numbers instead of names.
+    """
+    self.out = out
+    self.indent = indent
+    self.as_utf8 = as_utf8
+    self.as_one_line = as_one_line
+    self.pointy_brackets = pointy_brackets
+    self.use_index_order = use_index_order
+    self.float_format = float_format
+    self.use_field_number = use_field_number
+
+  def PrintMessage(self, message):
+    """Convert protobuf message to text format.
+
+    Args:
+      message: The protocol buffers message.
+    """
+    fields = message.ListFields()
+    if self.use_index_order:
+      fields.sort(key=lambda x: x[0].index)
+    for field, value in fields:
+      if _IsMapEntry(field):
+        for key in sorted(value):
+          # This is slow for maps with submessage entires because it copies the
+          # entire tree.  Unfortunately this would take significant refactoring
+          # of this file to work around.
+          #
+          # TODO(haberman): refactor and optimize if this becomes an issue.
+          entry_submsg = field.message_type._concrete_class(
+              key=key, value=value[key])
+          self.PrintField(field, entry_submsg)
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        for element in value:
+          self.PrintField(field, element)
+      else:
+        self.PrintField(field, value)
+
+  def PrintField(self, field, value):
+    """Print a single field name/value pair."""
+    out = self.out
+    out.write(' ' * self.indent)
+    if self.use_field_number:
+      out.write(str(field.number))
     else:
-      out.write(' %s\n' % openb)
-      PrintMessage(value, out, indent + 2, as_utf8, as_one_line,
-                   pointy_brackets=pointy_brackets,
-                   float_format=float_format)
-      out.write(' ' * indent + closeb)
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
-    enum_value = field.enum_type.values_by_number.get(value, None)
-    if enum_value is not None:
-      out.write(enum_value.name)
+      if field.is_extension:
+        out.write('[')
+        if (field.containing_type.GetOptions().message_set_wire_format and
+            field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+            field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
+          out.write(field.message_type.full_name)
+        else:
+          out.write(field.full_name)
+        out.write(']')
+      elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
+        # For groups, use the capitalized name.
+        out.write(field.message_type.name)
+      else:
+        out.write(field.name)
+
+    if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      # The colon is optional in this case, but our cross-language golden files
+      # don't include it.
+      out.write(': ')
+
+    self.PrintFieldValue(field, value)
+    if self.as_one_line:
+      out.write(' ')
+    else:
+      out.write('\n')
+
+  def PrintFieldValue(self, field, value):
+    """Print a single field value (not including name).
+
+    For repeated fields, the value should be a single element.
+
+    Args:
+      field: The descriptor of the field to be printed.
+      value: The value of the field.
+    """
+    out = self.out
+    if self.pointy_brackets:
+      openb = '<'
+      closeb = '>'
+    else:
+      openb = '{'
+      closeb = '}'
+
+    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      if self.as_one_line:
+        out.write(' %s ' % openb)
+        self.PrintMessage(value)
+        out.write(closeb)
+      else:
+        out.write(' %s\n' % openb)
+        self.indent += 2
+        self.PrintMessage(value)
+        self.indent -= 2
+        out.write(' ' * self.indent + closeb)
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+      enum_value = field.enum_type.values_by_number.get(value, None)
+      if enum_value is not None:
+        out.write(enum_value.name)
+      else:
+        out.write(str(value))
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+      out.write('\"')
+      if isinstance(value, six.text_type):
+        out_value = value.encode('utf-8')
+      else:
+        out_value = value
+      if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        # We need to escape non-UTF8 chars in TYPE_BYTES field.
+        out_as_utf8 = False
+      else:
+        out_as_utf8 = self.as_utf8
+      out.write(text_encoding.CEscape(out_value, out_as_utf8))
+      out.write('\"')
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+      if value:
+        out.write('true')
+      else:
+        out.write('false')
+    elif field.cpp_type in _FLOAT_TYPES and self.float_format is not None:
+      out.write('{1:{0}}'.format(self.float_format, value))
     else:
       out.write(str(value))
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
-    out.write('\"')
-    if isinstance(value, unicode):
-      out_value = value.encode('utf-8')
-    else:
-      out_value = value
-    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
-      # We need to escape non-UTF8 chars in TYPE_BYTES field.
-      out_as_utf8 = False
-    else:
-      out_as_utf8 = as_utf8
-    out.write(text_encoding.CEscape(out_value, out_as_utf8))
-    out.write('\"')
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
-    if value:
-      out.write('true')
-    else:
-      out.write('false')
-  elif field.cpp_type in _FLOAT_TYPES and float_format is not None:
-    out.write('{1:{0}}'.format(float_format, value))
-  else:
-    out.write(str(value))
 
 
-def _ParseOrMerge(lines, message, allow_multiple_scalars):
-  """Converts an ASCII representation of a protocol message into a message.
+def Parse(text, message,
+          allow_unknown_extension=False, allow_field_number=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    lines: Lines of a message's ASCII representation.
+    text: Message text representation.
     message: A protocol buffer message to merge into.
-    allow_multiple_scalars: Determines if repeated values for a non-repeated
-      field are permitted, e.g., the string "foo: 1 foo: 2" for a
-      required/optional field named "foo".
-
-  Raises:
-    ParseError: On ASCII parsing problems.
-  """
-  tokenizer = _Tokenizer(lines)
-  while not tokenizer.AtEnd():
-    _MergeField(tokenizer, message, allow_multiple_scalars)
-
-
-def Parse(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
-
-  Args:
-    text: Message ASCII representation.
-    message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  if not isinstance(text, str): text = text.decode('utf-8')
-  return ParseLines(text.split('\n'), message)
+  if not isinstance(text, str):
+    text = text.decode('utf-8')
+  return ParseLines(text.split('\n'), message, allow_unknown_extension,
+                    allow_field_number)
 
 
-def Merge(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def Merge(text, message, allow_unknown_extension=False,
+          allow_field_number=False):
+  """Parses an text representation of a protocol message into a message.
 
   Like Parse(), but allows repeated values for a non-repeated field, and uses
   the last one.
 
   Args:
-    text: Message ASCII representation.
+    text: Message text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  return MergeLines(text.split('\n'), message)
+  return MergeLines(text.split('\n'), message, allow_unknown_extension,
+                    allow_field_number)
 
 
-def ParseLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def ParseLines(lines, message, allow_unknown_extension=False,
+               allow_field_number=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    lines: An iterable of lines of a message's ASCII representation.
+    lines: An iterable of lines of a message's text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, False)
-  return message
+  parser = _Parser(allow_unknown_extension, allow_field_number)
+  return parser.ParseLines(lines, message)
 
 
-def MergeLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def MergeLines(lines, message, allow_unknown_extension=False,
+               allow_field_number=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    lines: An iterable of lines of a message's ASCII representation.
+    lines: An iterable of lines of a message's text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
+    allow_field_number: if True, both field number and field name are allowed.
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, True)
-  return message
+  parser = _Parser(allow_unknown_extension, allow_field_number)
+  return parser.MergeLines(lines, message)
 
 
-def _MergeField(tokenizer, message, allow_multiple_scalars):
-  """Merges a single protocol message field into a message.
+class _Parser(object):
+  """Text format parser for protocol message."""
 
-  Args:
-    tokenizer: A tokenizer to parse the field name and values.
-    message: A protocol message to record the data.
-    allow_multiple_scalars: Determines if repeated values for a non-repeated
-      field are permitted, e.g., the string "foo: 1 foo: 2" for a
-      required/optional field named "foo".
+  def __init__(self, allow_unknown_extension=False, allow_field_number=False):
+    self.allow_unknown_extension = allow_unknown_extension
+    self.allow_field_number = allow_field_number
 
-  Raises:
-    ParseError: In case of ASCII parsing problems.
-  """
-  message_descriptor = message.DESCRIPTOR
-  if tokenizer.TryConsume('['):
-    name = [tokenizer.ConsumeIdentifier()]
-    while tokenizer.TryConsume('.'):
-      name.append(tokenizer.ConsumeIdentifier())
-    name = '.'.join(name)
+  def ParseFromString(self, text, message):
+    """Parses an text representation of a protocol message into a message."""
+    if not isinstance(text, str):
+      text = text.decode('utf-8')
+    return self.ParseLines(text.split('\n'), message)
 
-    if not message_descriptor.is_extendable:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Message type "%s" does not have extensions.' %
-          message_descriptor.full_name)
-    # pylint: disable=protected-access
-    field = message.Extensions._FindExtensionByName(name)
-    # pylint: enable=protected-access
-    if not field:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Extension "%s" not registered.' % name)
-    elif message_descriptor != field.containing_type:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Extension "%s" does not extend message type "%s".' % (
-              name, message_descriptor.full_name))
-    tokenizer.Consume(']')
-  else:
-    name = tokenizer.ConsumeIdentifier()
-    field = message_descriptor.fields_by_name.get(name, None)
+  def ParseLines(self, lines, message):
+    """Parses an text representation of a protocol message into a message."""
+    self._allow_multiple_scalars = False
+    self._ParseOrMerge(lines, message)
+    return message
 
-    # Group names are expected to be capitalized as they appear in the
-    # .proto file, which actually matches their type names, not their field
-    # names.
-    if not field:
-      field = message_descriptor.fields_by_name.get(name.lower(), None)
-      if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
-        field = None
+  def MergeFromString(self, text, message):
+    """Merges an text representation of a protocol message into a message."""
+    return self._MergeLines(text.split('\n'), message)
 
-    if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
-        field.message_type.name != name):
-      field = None
+  def MergeLines(self, lines, message):
+    """Merges an text representation of a protocol message into a message."""
+    self._allow_multiple_scalars = True
+    self._ParseOrMerge(lines, message)
+    return message
 
-    if not field:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Message type "%s" has no field named "%s".' % (
-              message_descriptor.full_name, name))
+  def _ParseOrMerge(self, lines, message):
+    """Converts an text representation of a protocol message into a message.
 
-  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-    tokenizer.TryConsume(':')
+    Args:
+      lines: Lines of a message's text representation.
+      message: A protocol buffer message to merge into.
+
+    Raises:
+      ParseError: On text parsing problems.
+    """
+    tokenizer = _Tokenizer(lines)
+    while not tokenizer.AtEnd():
+      self._MergeField(tokenizer, message)
+
+  def _MergeField(self, tokenizer, message):
+    """Merges a single protocol message field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field name and values.
+      message: A protocol message to record the data.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+    """
+    message_descriptor = message.DESCRIPTOR
+    if (hasattr(message_descriptor, 'syntax') and
+        message_descriptor.syntax == 'proto3'):
+      # Proto3 doesn't represent presence so we can't test if multiple
+      # scalars have occurred.  We have to allow them.
+      self._allow_multiple_scalars = True
+    if tokenizer.TryConsume('['):
+      name = [tokenizer.ConsumeIdentifier()]
+      while tokenizer.TryConsume('.'):
+        name.append(tokenizer.ConsumeIdentifier())
+      name = '.'.join(name)
+
+      if not message_descriptor.is_extendable:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Message type "%s" does not have extensions.' %
+            message_descriptor.full_name)
+      # pylint: disable=protected-access
+      field = message.Extensions._FindExtensionByName(name)
+      # pylint: enable=protected-access
+      if not field:
+        if self.allow_unknown_extension:
+          field = None
+        else:
+          raise tokenizer.ParseErrorPreviousToken(
+              'Extension "%s" not registered.' % name)
+      elif message_descriptor != field.containing_type:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Extension "%s" does not extend message type "%s".' % (
+                name, message_descriptor.full_name))
+
+      tokenizer.Consume(']')
+
+    else:
+      name = tokenizer.ConsumeIdentifier()
+      if self.allow_field_number and name.isdigit():
+        number = ParseInteger(name, True, True)
+        field = message_descriptor.fields_by_number.get(number, None)
+        if not field and message_descriptor.is_extendable:
+          field = message.Extensions._FindExtensionByNumber(number)
+      else:
+        field = message_descriptor.fields_by_name.get(name, None)
+
+        # Group names are expected to be capitalized as they appear in the
+        # .proto file, which actually matches their type names, not their field
+        # names.
+        if not field:
+          field = message_descriptor.fields_by_name.get(name.lower(), None)
+          if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
+            field = None
+
+        if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
+            field.message_type.name != name):
+          field = None
+
+      if not field:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Message type "%s" has no field named "%s".' % (
+                message_descriptor.full_name, name))
+
+    if field:
+      if not self._allow_multiple_scalars and field.containing_oneof:
+        # Check if there's a different field set in this oneof.
+        # Note that we ignore the case if the same field was set before, and we
+        # apply _allow_multiple_scalars to non-scalar fields as well.
+        which_oneof = message.WhichOneof(field.containing_oneof.name)
+        if which_oneof is not None and which_oneof != field.name:
+          raise tokenizer.ParseErrorPreviousToken(
+              'Field "%s" is specified along with field "%s", another member '
+              'of oneof "%s" for message type "%s".' % (
+                  field.name, which_oneof, field.containing_oneof.name,
+                  message_descriptor.full_name))
+
+      if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        tokenizer.TryConsume(':')
+        merger = self._MergeMessageField
+      else:
+        tokenizer.Consume(':')
+        merger = self._MergeScalarField
+
+      if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED
+          and tokenizer.TryConsume('[')):
+        # Short repeated format, e.g. "foo: [1, 2, 3]"
+        while True:
+          merger(tokenizer, message, field)
+          if tokenizer.TryConsume(']'): break
+          tokenizer.Consume(',')
+
+      else:
+        merger(tokenizer, message, field)
+
+    else:  # Proto field is unknown.
+      assert self.allow_unknown_extension
+      _SkipFieldContents(tokenizer)
+
+    # For historical reasons, fields may optionally be separated by commas or
+    # semicolons.
+    if not tokenizer.TryConsume(','):
+      tokenizer.TryConsume(';')
+
+  def _MergeMessageField(self, tokenizer, message, field):
+    """Merges a single scalar field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field value.
+      message: The message of which field is a member.
+      field: The descriptor of the field to be merged.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+    """
+    is_map_entry = _IsMapEntry(field)
 
     if tokenizer.TryConsume('<'):
       end_token = '>'
@@ -367,6 +585,9 @@
     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       if field.is_extension:
         sub_message = message.Extensions[field].add()
+      elif is_map_entry:
+        # pylint: disable=protected-access
+        sub_message = field.message_type._concrete_class()
       else:
         sub_message = getattr(message, field.name).add()
     else:
@@ -378,10 +599,117 @@
 
     while not tokenizer.TryConsume(end_token):
       if tokenizer.AtEnd():
-        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
-      _MergeField(tokenizer, sub_message, allow_multiple_scalars)
+        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,))
+      self._MergeField(tokenizer, sub_message)
+
+    if is_map_entry:
+      value_cpptype = field.message_type.fields_by_name['value'].cpp_type
+      if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        value = getattr(message, field.name)[sub_message.key]
+        value.MergeFrom(sub_message.value)
+      else:
+        getattr(message, field.name)[sub_message.key] = sub_message.value
+
+  def _MergeScalarField(self, tokenizer, message, field):
+    """Merges a single scalar field into a message.
+
+    Args:
+      tokenizer: A tokenizer to parse the field value.
+      message: A protocol message to record the data.
+      field: The descriptor of the field to be merged.
+
+    Raises:
+      ParseError: In case of text parsing problems.
+      RuntimeError: On runtime errors.
+    """
+    _ = self.allow_unknown_extension
+    value = None
+
+    if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
+                      descriptor.FieldDescriptor.TYPE_SINT32,
+                      descriptor.FieldDescriptor.TYPE_SFIXED32):
+      value = tokenizer.ConsumeInt32()
+    elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
+                        descriptor.FieldDescriptor.TYPE_SINT64,
+                        descriptor.FieldDescriptor.TYPE_SFIXED64):
+      value = tokenizer.ConsumeInt64()
+    elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
+                        descriptor.FieldDescriptor.TYPE_FIXED32):
+      value = tokenizer.ConsumeUint32()
+    elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
+                        descriptor.FieldDescriptor.TYPE_FIXED64):
+      value = tokenizer.ConsumeUint64()
+    elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
+                        descriptor.FieldDescriptor.TYPE_DOUBLE):
+      value = tokenizer.ConsumeFloat()
+    elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
+      value = tokenizer.ConsumeBool()
+    elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
+      value = tokenizer.ConsumeString()
+    elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      value = tokenizer.ConsumeByteString()
+    elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
+      value = tokenizer.ConsumeEnum(field)
+    else:
+      raise RuntimeError('Unknown field type %d' % field.type)
+
+    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+      if field.is_extension:
+        message.Extensions[field].append(value)
+      else:
+        getattr(message, field.name).append(value)
+    else:
+      if field.is_extension:
+        if not self._allow_multiple_scalars and message.HasExtension(field):
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" extensions.' %
+              (message.DESCRIPTOR.full_name, field.full_name))
+        else:
+          message.Extensions[field] = value
+      else:
+        if not self._allow_multiple_scalars and message.HasField(field.name):
+          raise tokenizer.ParseErrorPreviousToken(
+              'Message type "%s" should not have multiple "%s" fields.' %
+              (message.DESCRIPTOR.full_name, field.name))
+        else:
+          setattr(message, field.name, value)
+
+
+def _SkipFieldContents(tokenizer):
+  """Skips over contents (value or message) of a field.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+  # Try to guess the type of this field.
+  # If this field is not a message, there should be a ":" between the
+  # field name and the field value and also the field value should not
+  # start with "{" or "<" which indicates the beginning of a message body.
+  # If there is no ":" or there is a "{" or "<" after ":", this field has
+  # to be a message or the input is ill-formed.
+  if tokenizer.TryConsume(':') and not tokenizer.LookingAt(
+      '{') and not tokenizer.LookingAt('<'):
+    _SkipFieldValue(tokenizer)
   else:
-    _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+    _SkipFieldMessage(tokenizer)
+
+
+def _SkipField(tokenizer):
+  """Skips over a complete field (name and value/message).
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+  if tokenizer.TryConsume('['):
+    # Consume extension name.
+    tokenizer.ConsumeIdentifier()
+    while tokenizer.TryConsume('.'):
+      tokenizer.ConsumeIdentifier()
+    tokenizer.Consume(']')
+  else:
+    tokenizer.ConsumeIdentifier()
+
+  _SkipFieldContents(tokenizer)
 
   # For historical reasons, fields may optionally be separated by commas or
   # semicolons.
@@ -389,76 +717,50 @@
     tokenizer.TryConsume(';')
 
 
-def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):
-  """Merges a single protocol message scalar field into a message.
+def _SkipFieldMessage(tokenizer):
+  """Skips over a field message.
 
   Args:
-    tokenizer: A tokenizer to parse the field value.
-    message: A protocol message to record the data.
-    field: The descriptor of the field to be merged.
-    allow_multiple_scalars: Determines if repeated values for a non-repeated
-      field are permitted, e.g., the string "foo: 1 foo: 2" for a
-      required/optional field named "foo".
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+
+  if tokenizer.TryConsume('<'):
+    delimiter = '>'
+  else:
+    tokenizer.Consume('{')
+    delimiter = '}'
+
+  while not tokenizer.LookingAt('>') and not tokenizer.LookingAt('}'):
+    _SkipField(tokenizer)
+
+  tokenizer.Consume(delimiter)
+
+
+def _SkipFieldValue(tokenizer):
+  """Skips over a field value.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
 
   Raises:
-    ParseError: In case of ASCII parsing problems.
-    RuntimeError: On runtime errors.
+    ParseError: In case an invalid field value is found.
   """
-  tokenizer.Consume(':')
-  value = None
+  # String/bytes tokens can come in multiple adjacent string literals.
+  # If we can consume one, consume as many as we can.
+  if tokenizer.TryConsumeByteString():
+    while tokenizer.TryConsumeByteString():
+      pass
+    return
 
-  if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
-                    descriptor.FieldDescriptor.TYPE_SINT32,
-                    descriptor.FieldDescriptor.TYPE_SFIXED32):
-    value = tokenizer.ConsumeInt32()
-  elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
-                      descriptor.FieldDescriptor.TYPE_SINT64,
-                      descriptor.FieldDescriptor.TYPE_SFIXED64):
-    value = tokenizer.ConsumeInt64()
-  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
-                      descriptor.FieldDescriptor.TYPE_FIXED32):
-    value = tokenizer.ConsumeUint32()
-  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
-                      descriptor.FieldDescriptor.TYPE_FIXED64):
-    value = tokenizer.ConsumeUint64()
-  elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
-                      descriptor.FieldDescriptor.TYPE_DOUBLE):
-    value = tokenizer.ConsumeFloat()
-  elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
-    value = tokenizer.ConsumeBool()
-  elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
-    value = tokenizer.ConsumeString()
-  elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
-    value = tokenizer.ConsumeByteString()
-  elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
-    value = tokenizer.ConsumeEnum(field)
-  else:
-    raise RuntimeError('Unknown field type %d' % field.type)
-
-  if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
-    if field.is_extension:
-      message.Extensions[field].append(value)
-    else:
-      getattr(message, field.name).append(value)
-  else:
-    if field.is_extension:
-      if not allow_multiple_scalars and message.HasExtension(field):
-        raise tokenizer.ParseErrorPreviousToken(
-            'Message type "%s" should not have multiple "%s" extensions.' %
-            (message.DESCRIPTOR.full_name, field.full_name))
-      else:
-        message.Extensions[field] = value
-    else:
-      if not allow_multiple_scalars and message.HasField(field.name):
-        raise tokenizer.ParseErrorPreviousToken(
-            'Message type "%s" should not have multiple "%s" fields.' %
-            (message.DESCRIPTOR.full_name, field.name))
-      else:
-        setattr(message, field.name, value)
+  if (not tokenizer.TryConsumeIdentifier() and
+      not tokenizer.TryConsumeInt64() and
+      not tokenizer.TryConsumeUint64() and
+      not tokenizer.TryConsumeFloat()):
+    raise ParseError('Invalid field value: ' + tokenizer.token)
 
 
 class _Tokenizer(object):
-  """Protocol buffer ASCII representation tokenizer.
+  """Protocol buffer text representation tokenizer.
 
   This class handles the lower level string parsing by splitting it into
   meaningful tokens.
@@ -467,11 +769,13 @@
   """
 
   _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
-  _TOKEN = re.compile(
-      '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier
-      '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number
-      '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string
-      '\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string
+  _TOKEN = re.compile('|'.join([
+      r'[a-zA-Z_][0-9a-zA-Z_+-]*',             # an identifier
+      r'([0-9+-]|(\.[0-9]))[0-9a-zA-Z_.+-]*',  # a number
+  ] + [                                        # quoted str for each quote mark
+      r'{qt}([^{qt}\n\\]|\\.)*({qt}|\\?$)'.format(qt=mark) for mark in _QUOTES
+  ]))
+
   _IDENTIFIER = re.compile(r'\w+')
 
   def __init__(self, lines):
@@ -488,6 +792,9 @@
     self._SkipWhitespace()
     self.NextToken()
 
+  def LookingAt(self, token):
+    return self.token == token
+
   def AtEnd(self):
     """Checks the end of the text was reached.
 
@@ -499,7 +806,7 @@
   def _PopLine(self):
     while len(self._current_line) <= self._column:
       try:
-        self._current_line = self._lines.next()
+        self._current_line = next(self._lines)
       except StopIteration:
         self._current_line = ''
         self._more_lines = False
@@ -543,6 +850,13 @@
     if not self.TryConsume(token):
       raise self._ParseError('Expected "%s".' % token)
 
+  def TryConsumeIdentifier(self):
+    try:
+      self.ConsumeIdentifier()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeIdentifier(self):
     """Consumes protocol message field identifier.
 
@@ -569,7 +883,7 @@
     """
     try:
       result = ParseInteger(self.token, is_signed=True, is_long=False)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
@@ -585,11 +899,18 @@
     """
     try:
       result = ParseInteger(self.token, is_signed=False, is_long=False)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
 
+  def TryConsumeInt64(self):
+    try:
+      self.ConsumeInt64()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeInt64(self):
     """Consumes a signed 64bit integer number.
 
@@ -601,11 +922,18 @@
     """
     try:
       result = ParseInteger(self.token, is_signed=True, is_long=True)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
 
+  def TryConsumeUint64(self):
+    try:
+      self.ConsumeUint64()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeUint64(self):
     """Consumes an unsigned 64bit integer number.
 
@@ -617,11 +945,18 @@
     """
     try:
       result = ParseInteger(self.token, is_signed=False, is_long=True)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
 
+  def TryConsumeFloat(self):
+    try:
+      self.ConsumeFloat()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeFloat(self):
     """Consumes an floating point number.
 
@@ -633,7 +968,7 @@
     """
     try:
       result = ParseFloat(self.token)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
@@ -649,11 +984,18 @@
     """
     try:
       result = ParseBool(self.token)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
 
+  def TryConsumeByteString(self):
+    try:
+      self.ConsumeByteString()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeString(self):
     """Consumes a string value.
 
@@ -665,8 +1007,8 @@
     """
     the_bytes = self.ConsumeByteString()
     try:
-      return unicode(the_bytes, 'utf-8')
-    except UnicodeDecodeError, e:
+      return six.text_type(the_bytes, 'utf-8')
+    except UnicodeDecodeError as e:
       raise self._StringParseError(e)
 
   def ConsumeByteString(self):
@@ -679,10 +1021,9 @@
       ParseError: If a byte array value couldn't be consumed.
     """
     the_list = [self._ConsumeSingleByteString()]
-    while self.token and self.token[0] in ('\'', '"'):
+    while self.token and self.token[0] in _QUOTES:
       the_list.append(self._ConsumeSingleByteString())
-    return ''.encode('latin1').join(the_list)  ##PY25
-##!PY25    return b''.join(the_list)
+    return b''.join(the_list)
 
   def _ConsumeSingleByteString(self):
     """Consume one token of a string literal.
@@ -690,17 +1031,22 @@
     String literals (whether bytes or text) can come in multiple adjacent
     tokens which are automatically concatenated, like in C or Python.  This
     method only consumes one token.
+
+    Returns:
+      The token parsed.
+    Raises:
+      ParseError: When the wrong format data is found.
     """
     text = self.token
-    if len(text) < 1 or text[0] not in ('\'', '"'):
-      raise self._ParseError('Expected string.')
+    if len(text) < 1 or text[0] not in _QUOTES:
+      raise self._ParseError('Expected string but found: %r' % (text,))
 
     if len(text) < 2 or text[-1] != text[0]:
-      raise self._ParseError('String missing ending quote.')
+      raise self._ParseError('String missing ending quote: %r' % (text,))
 
     try:
       result = text_encoding.CUnescape(text[1:-1])
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
@@ -708,7 +1054,7 @@
   def ConsumeEnum(self, field):
     try:
       result = ParseEnum(field, self.token)
-    except ValueError, e:
+    except ValueError as e:
       raise self._ParseError(str(e))
     self.NextToken()
     return result
diff --git a/python/mox.py b/python/mox.py
index ce80ba5..257468e 100755
--- a/python/mox.py
+++ b/python/mox.py
@@ -31,7 +31,7 @@
 parameters) is called, then an exception will be raised.
 
 Once you are done interacting with the mock, you need to verify that
-all the expected interactions occured.  (Maybe your code exited
+all the expected interactions occurred.  (Maybe your code exited
 prematurely without calling some cleanup method!)  The verify phase
 ensures that every expected method was called; otherwise, an exception
 will be raised.
diff --git a/python/setup.py b/python/setup.py
index 2450a77..0f4b53c 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -1,29 +1,24 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # See README for usage instructions.
-import sys
+import glob
 import os
 import subprocess
+import sys
 
 # We must use setuptools, not distutils, because we need to use the
 # namespace_packages option for the "google" package.
-try:
-  from setuptools import setup, Extension
-except ImportError:
-  try:
-    from ez_setup import use_setuptools
-    use_setuptools()
-    from setuptools import setup, Extension
-  except ImportError:
-    sys.stderr.write(
-        "Could not import setuptools; make sure you have setuptools or "
-        "ez_setup installed.\n")
-    raise
-from distutils.command.clean import clean as _clean
-from distutils.command.build_py import build_py as _build_py
-from distutils.spawn import find_executable
+from setuptools import setup, Extension, find_packages
 
-maintainer_email = "protobuf@googlegroups.com"
+from distutils.command.clean import clean as _clean
+
+if sys.version_info[0] == 3:
+  # Python 3
+  from distutils.command.build_py import build_py_2to3 as _build_py
+else:
+  # Python 2
+  from distutils.command.build_py import build_py as _build_py
+from distutils.spawn import find_executable
 
 # Find the Protocol Compiler.
 if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
@@ -39,23 +34,38 @@
 else:
   protoc = find_executable("protoc")
 
-def generate_proto(source):
+
+def GetVersion():
+  """Gets the version from google/protobuf/__init__.py
+
+  Do not import google.protobuf.__init__ directly, because an installed
+  protobuf library may be loaded instead."""
+
+  with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file:
+    exec(version_file.read(), globals())
+    return __version__
+
+
+def generate_proto(source, require = True):
   """Invokes the Protocol Compiler to generate a _pb2.py from the given
   .proto file.  Does nothing if the output already exists and is newer than
   the input."""
 
+  if not require and not os.path.exists(source):
+    return
+
   output = source.replace(".proto", "_pb2.py").replace("../src/", "")
 
   if (not os.path.exists(output) or
       (os.path.exists(source) and
        os.path.getmtime(source) > os.path.getmtime(output))):
-    print ("Generating %s..." % output)
+    print("Generating %s..." % output)
 
     if not os.path.exists(source):
       sys.stderr.write("Can't find required file: %s\n" % source)
       sys.exit(-1)
 
-    if protoc == None:
+    if protoc is None:
       sys.stderr.write(
           "protoc is not installed nor found in ../src.  Please compile it "
           "or install the binary package.\n")
@@ -66,39 +76,35 @@
       sys.exit(-1)
 
 def GenerateUnittestProtos():
-  generate_proto("../src/google/protobuf/unittest.proto")
-  generate_proto("../src/google/protobuf/unittest_custom_options.proto")
-  generate_proto("../src/google/protobuf/unittest_import.proto")
-  generate_proto("../src/google/protobuf/unittest_import_public.proto")
-  generate_proto("../src/google/protobuf/unittest_mset.proto")
-  generate_proto("../src/google/protobuf/unittest_no_generic_services.proto")
-  generate_proto("google/protobuf/internal/descriptor_pool_test1.proto")
-  generate_proto("google/protobuf/internal/descriptor_pool_test2.proto")
-  generate_proto("google/protobuf/internal/test_bad_identifiers.proto")
-  generate_proto("google/protobuf/internal/missing_enum_values.proto")
-  generate_proto("google/protobuf/internal/more_extensions.proto")
-  generate_proto("google/protobuf/internal/more_extensions_dynamic.proto")
-  generate_proto("google/protobuf/internal/more_messages.proto")
-  generate_proto("google/protobuf/internal/factory_test1.proto")
-  generate_proto("google/protobuf/internal/factory_test2.proto")
-  generate_proto("google/protobuf/pyext/python.proto")
+  generate_proto("../src/google/protobuf/map_unittest.proto", False)
+  generate_proto("../src/google/protobuf/unittest_arena.proto", False)
+  generate_proto("../src/google/protobuf/unittest_no_arena.proto", False)
+  generate_proto("../src/google/protobuf/unittest_no_arena_import.proto", False)
+  generate_proto("../src/google/protobuf/unittest.proto", False)
+  generate_proto("../src/google/protobuf/unittest_custom_options.proto", False)
+  generate_proto("../src/google/protobuf/unittest_import.proto", False)
+  generate_proto("../src/google/protobuf/unittest_import_public.proto", False)
+  generate_proto("../src/google/protobuf/unittest_mset.proto", False)
+  generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False)
+  generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False)
+  generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False)
+  generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False)
+  generate_proto("google/protobuf/internal/any_test.proto", False)
+  generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False)
+  generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
+  generate_proto("google/protobuf/internal/factory_test1.proto", False)
+  generate_proto("google/protobuf/internal/factory_test2.proto", False)
+  generate_proto("google/protobuf/internal/import_test_package/inner.proto", False)
+  generate_proto("google/protobuf/internal/import_test_package/outer.proto", False)
+  generate_proto("google/protobuf/internal/missing_enum_values.proto", False)
+  generate_proto("google/protobuf/internal/message_set_extensions.proto", False)
+  generate_proto("google/protobuf/internal/more_extensions.proto", False)
+  generate_proto("google/protobuf/internal/more_extensions_dynamic.proto", False)
+  generate_proto("google/protobuf/internal/more_messages.proto", False)
+  generate_proto("google/protobuf/internal/packed_field_test.proto", False)
+  generate_proto("google/protobuf/internal/test_bad_identifiers.proto", False)
+  generate_proto("google/protobuf/pyext/python.proto", False)
 
-def MakeTestSuite():
-  # Test C++ implementation
-  import unittest
-  import google.protobuf.pyext.descriptor_cpp2_test as descriptor_cpp2_test
-  import google.protobuf.pyext.message_factory_cpp2_test \
-      as message_factory_cpp2_test
-  import google.protobuf.pyext.reflection_cpp2_generated_test \
-      as reflection_cpp2_generated_test
-
-  loader = unittest.defaultTestLoader
-  suite = unittest.TestSuite()
-  for test in [  descriptor_cpp2_test,
-                 message_factory_cpp2_test,
-                 reflection_cpp2_generated_test]:
-    suite.addTest(loader.loadTestsFromModule(test))
-  return suite
 
 class clean(_clean):
   def run(self):
@@ -108,7 +114,8 @@
         filepath = os.path.join(dirpath, filename)
         if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \
           filepath.endswith(".so") or filepath.endswith(".o") or \
-          filepath.endswith('google/protobuf/compiler/__init__.py'):
+          filepath.endswith('google/protobuf/compiler/__init__.py') or \
+          filepath.endswith('google/protobuf/util/__init__.py'):
           os.remove(filepath)
     # _clean is an old-style class, so super() doesn't work.
     _clean.run(self)
@@ -118,84 +125,126 @@
     # Generate necessary .proto file if it doesn't exist.
     generate_proto("../src/google/protobuf/descriptor.proto")
     generate_proto("../src/google/protobuf/compiler/plugin.proto")
+    generate_proto("../src/google/protobuf/any.proto")
+    generate_proto("../src/google/protobuf/api.proto")
+    generate_proto("../src/google/protobuf/duration.proto")
+    generate_proto("../src/google/protobuf/empty.proto")
+    generate_proto("../src/google/protobuf/field_mask.proto")
+    generate_proto("../src/google/protobuf/source_context.proto")
+    generate_proto("../src/google/protobuf/struct.proto")
+    generate_proto("../src/google/protobuf/timestamp.proto")
+    generate_proto("../src/google/protobuf/type.proto")
+    generate_proto("../src/google/protobuf/wrappers.proto")
     GenerateUnittestProtos()
 
     # Make sure google.protobuf/** are valid packages.
-    for path in ['', 'internal/', 'compiler/', 'pyext/']:
+    for path in ['', 'internal/', 'compiler/', 'pyext/', 'util/']:
       try:
         open('google/protobuf/%s__init__.py' % path, 'a').close()
       except EnvironmentError:
         pass
     # _build_py is an old-style class, so super() doesn't work.
     _build_py.run(self)
-  # TODO(mrovner): Subclass to run 2to3 on some files only.
-  # Tracing what https://wiki.python.org/moin/PortingPythonToPy3k's "Approach 2"
-  # section on how to get 2to3 to run on source files during install under
-  # Python 3.  This class seems like a good place to put logic that calls
-  # python3's distutils.util.run_2to3 on the subset of the files we have in our
-  # release that are subject to conversion.
-  # See code reference in previous code review.
+
+class test_conformance(_build_py):
+  target = 'test_python'
+  def run(self):
+    if sys.version_info >= (2, 7):
+      # Python 2.6 dodges these extra failures.
+      os.environ["CONFORMANCE_PYTHON_EXTRA_FAILURES"] = (
+          "--failure_list failure_list_python-post26.txt")
+    cmd = 'cd ../conformance && make %s' % (test_conformance.target)
+    status = subprocess.check_call(cmd, shell=True)
+
+
+def get_option_from_sys_argv(option_str):
+  if option_str in sys.argv:
+    sys.argv.remove(option_str)
+    return True
+  return False
+
 
 if __name__ == '__main__':
   ext_module_list = []
-  cpp_impl = '--cpp_implementation'
-  if cpp_impl in sys.argv:
-    sys.argv.remove(cpp_impl)
-    # C++ implementation extension
-    ext_module_list.append(Extension(
-        "google.protobuf.pyext._message",
-        [ "google/protobuf/pyext/descriptor.cc",
-          "google/protobuf/pyext/message.cc",
-          "google/protobuf/pyext/extension_dict.cc",
-          "google/protobuf/pyext/repeated_scalar_container.cc",
-          "google/protobuf/pyext/repeated_composite_container.cc" ],
-        define_macros=[('GOOGLE_PROTOBUF_HAS_ONEOF', '1')],
-        include_dirs = [ ".", "../src"],
-        libraries = [ "protobuf" ],
-        library_dirs = [ '../src/.libs' ],
-        ))
+  warnings_as_errors = '--warnings_as_errors'
+  if get_option_from_sys_argv('--cpp_implementation'):
+    # Link libprotobuf.a and libprotobuf-lite.a statically with the
+    # extension. Note that those libraries have to be compiled with
+    # -fPIC for this to work.
+    compile_static_ext = get_option_from_sys_argv('--compile_static_extension')
+    extra_compile_args = ['-Wno-write-strings',
+                          '-Wno-invalid-offsetof',
+                          '-Wno-sign-compare']
+    libraries = ['protobuf']
+    extra_objects = None
+    if compile_static_ext:
+      libraries = None
+      extra_objects = ['../src/.libs/libprotobuf.a',
+                       '../src/.libs/libprotobuf-lite.a']
+    test_conformance.target = 'test_python_cpp'
 
-  setup(name = 'protobuf',
-        version = '2.6.1',
-        packages = [ 'google' ],
-        namespace_packages = [ 'google' ],
-        test_suite = 'setup.MakeTestSuite',
-        google_test_dir = "google/protobuf/internal",
-        # Must list modules explicitly so that we don't install tests.
-        py_modules = [
-          'google.protobuf.internal.api_implementation',
-          'google.protobuf.internal.containers',
-          'google.protobuf.internal.cpp_message',
-          'google.protobuf.internal.decoder',
-          'google.protobuf.internal.encoder',
-          'google.protobuf.internal.enum_type_wrapper',
-          'google.protobuf.internal.message_listener',
-          'google.protobuf.internal.python_message',
-          'google.protobuf.internal.type_checkers',
-          'google.protobuf.internal.wire_format',
-          'google.protobuf.descriptor',
-          'google.protobuf.descriptor_pb2',
-          'google.protobuf.compiler.plugin_pb2',
-          'google.protobuf.message',
-          'google.protobuf.descriptor_database',
-          'google.protobuf.descriptor_pool',
-          'google.protobuf.message_factory',
-          'google.protobuf.pyext.cpp_message',
-          'google.protobuf.reflection',
-          'google.protobuf.service',
-          'google.protobuf.service_reflection',
-          'google.protobuf.symbol_database',
-          'google.protobuf.text_encoding',
-          'google.protobuf.text_format'],
-        cmdclass = { 'clean': clean, 'build_py': build_py },
-        install_requires = ['setuptools'],
-        setup_requires = ['google-apputils'],
-        ext_modules = ext_module_list,
-        url = 'https://developers.google.com/protocol-buffers/',
-        maintainer = maintainer_email,
-        maintainer_email = 'protobuf@googlegroups.com',
-        license = 'New BSD License',
-        description = 'Protocol Buffers',
-        long_description =
-          "Protocol Buffers are Google's data interchange format.",
-        )
+    if "clang" in os.popen('$CC --version 2> /dev/null').read():
+      extra_compile_args.append('-Wno-shorten-64-to-32')
+
+    if warnings_as_errors in sys.argv:
+      extra_compile_args.append('-Werror')
+      sys.argv.remove(warnings_as_errors)
+
+    # C++ implementation extension
+    ext_module_list.extend([
+        Extension(
+            "google.protobuf.pyext._message",
+            glob.glob('google/protobuf/pyext/*.cc'),
+            include_dirs=[".", "../src"],
+            libraries=libraries,
+            extra_objects=extra_objects,
+            library_dirs=['../src/.libs'],
+            extra_compile_args=extra_compile_args,
+        ),
+        Extension(
+            "google.protobuf.internal._api_implementation",
+            glob.glob('google/protobuf/internal/api_implementation.cc'),
+            extra_compile_args=['-DPYTHON_PROTO2_CPP_IMPL_V2'],
+        ),
+    ])
+    os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
+
+  # Keep this list of dependencies in sync with tox.ini.
+  install_requires = ['six>=1.9', 'setuptools']
+  if sys.version_info <= (2,7):
+    install_requires.append('ordereddict')
+    install_requires.append('unittest2')
+
+  setup(
+      name='protobuf',
+      version=GetVersion(),
+      description='Protocol Buffers',
+      long_description="Protocol Buffers are Google's data interchange format",
+      url='https://developers.google.com/protocol-buffers/',
+      maintainer='protobuf@googlegroups.com',
+      maintainer_email='protobuf@googlegroups.com',
+      license='New BSD License',
+      classifiers=[
+        "Programming Language :: Python",
+        "Programming Language :: Python :: 2",
+        "Programming Language :: Python :: 2.6",
+        "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.3",
+        "Programming Language :: Python :: 3.4",
+        ],
+      namespace_packages=['google'],
+      packages=find_packages(
+          exclude=[
+              'import_test_package',
+          ],
+      ),
+      test_suite='google.protobuf.internal',
+      cmdclass={
+          'clean': clean,
+          'build_py': build_py,
+          'test_conformance': test_conformance,
+      },
+      install_requires=install_requires,
+      ext_modules=ext_module_list,
+  )
diff --git a/python/tox.ini b/python/tox.ini
new file mode 100644
index 0000000..cf8d540
--- /dev/null
+++ b/python/tox.ini
@@ -0,0 +1,24 @@
+[tox]
+envlist =
+    py{26,27,33,34}-{cpp,python}
+
+[testenv]
+usedevelop=true
+passenv = CC
+setenv =
+    cpp: LD_LIBRARY_PATH={toxinidir}/../src/.libs
+    cpp: DYLD_LIBRARY_PATH={toxinidir}/../src/.libs
+    cpp: PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
+commands =
+    python setup.py -q build_py
+    python: python setup.py -q build
+    cpp: python setup.py -q build --cpp_implementation --warnings_as_errors
+    python: python setup.py -q test -q
+    cpp: python setup.py -q test -q --cpp_implementation
+    python: python setup.py -q test_conformance
+    cpp: python setup.py -q test_conformance --cpp_implementation
+deps =
+    # Keep this list of dependencies in sync with setup.py.
+    six>=1.9
+    py26: ordereddict
+    py26: unittest2
diff --git a/ruby/.gitignore b/ruby/.gitignore
new file mode 100644
index 0000000..bd8745d
--- /dev/null
+++ b/ruby/.gitignore
@@ -0,0 +1,8 @@
+*.bundle
+tags
+.idea/
+lib/google/protobuf_java.jar
+protobuf-jruby.iml
+target/
+pkg/
+tmp/
diff --git a/ruby/Gemfile b/ruby/Gemfile
new file mode 100644
index 0000000..fa75df1
--- /dev/null
+++ b/ruby/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gemspec
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
new file mode 100644
index 0000000..d0eb9cc
--- /dev/null
+++ b/ruby/Gemfile.lock
@@ -0,0 +1,30 @@
+PATH
+  remote: .
+  specs:
+    google-protobuf (3.0.0.alpha.5.0.5)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    power_assert (0.2.2)
+    rake (10.4.2)
+    rake-compiler (0.9.5)
+      rake
+    rake-compiler-dock (0.5.1)
+    rubygems-tasks (0.2.4)
+    test-unit (3.0.9)
+      power_assert
+
+PLATFORMS
+  java
+  ruby
+
+DEPENDENCIES
+  google-protobuf!
+  rake-compiler
+  rake-compiler-dock
+  rubygems-tasks
+  test-unit
+
+BUNDLED WITH
+   1.11.2
diff --git a/ruby/README.md b/ruby/README.md
new file mode 100644
index 0000000..f28e05a
--- /dev/null
+++ b/ruby/README.md
@@ -0,0 +1,114 @@
+This directory contains the Ruby extension that implements Protocol Buffers
+functionality in Ruby.
+
+The Ruby extension makes use of generated Ruby code that defines message and
+enum types in a Ruby DSL. You may write definitions in this DSL directly, but
+we recommend using protoc's Ruby generation support with .proto files. The
+build process in this directory only installs the extension; you need to
+install protoc as well to have Ruby code generation functionality.
+
+Installation from Gem
+---------------------
+
+When we release a version of Protocol Buffers, we will upload a Gem to
+[RubyGems](https://www.rubygems.org/). To use this pre-packaged gem, simply
+install it as you would any other gem:
+
+    $ gem install [--prerelease] google-protobuf
+
+The `--pre` flag is necessary if we have not yet made a non-alpha/beta release
+of the Ruby extension; it allows `gem` to consider these "pre-release"
+alpha/beta versions.
+
+Once the gem is installed, you may or may not need `protoc`. If you write your
+message type descriptions directly in the Ruby DSL, you do not need it.
+However, if you wish to generate the Ruby DSL from a `.proto` file, you will
+also want to install Protocol Buffers itself, as described in this repository's
+main `README` file. The version of `protoc` included in the latest release
+supports the `--ruby_out` option to generate Ruby code.
+
+A simple example of using the Ruby extension follows. More extensive
+documentation may be found in the RubyDoc comments (`call-seq` tags) in the
+source, and we plan to release separate, more detailed, documentation at a
+later date.
+
+```ruby
+require 'google/protobuf'
+
+# generated from my_proto_types.proto with protoc:
+#  $ protoc --ruby_out=. my_proto_types.proto
+require 'my_proto_types'
+
+mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"])
+mymessage.field1 = 43
+mymessage.field2.push("d")
+mymessage.field3 = SubMessage.new(:foo => 100)
+
+encoded_data = MyTestMessage.encode(mymessage)
+decoded = MyTestMessage.decode(encoded_data)
+assert decoded == mymessage
+
+puts "JSON:"
+puts MyTestMessage.encode_json(mymessage)
+```
+
+Installation from Source (Building Gem)
+---------------------------------------
+
+To build this Ruby extension, you will need:
+
+* Rake
+* Bundler
+* Ruby development headers
+* a C compiler
+
+To Build the JRuby extension, you will need:
+
+* Maven
+* The latest version of the protobuf java library (see ../java/README.md)
+* Install JRuby via rbenv or RVM
+
+First switch to the desired platform with rbenv or RVM.
+
+Then install the required Ruby gems:
+
+    $ gem install bundler
+    $ bundle
+
+Then build the Gem:
+
+    $ rake
+    $ rake clobber_package gem
+    $ gem install `ls pkg/google-protobuf-*.gem`
+
+To run the specs:
+
+    $ rake test
+
+This gem includes the upb parsing and serialization library as a single-file
+amalgamation. It is up-to-date with upb git commit
+`535bc2fe2f2b467f59347ffc9449e11e47791257`.
+
+Version Number Scheme
+---------------------
+
+We are using a version number scheme that is a hybrid of Protocol Buffers'
+overall version number and some Ruby-specific rules. Gem does not allow
+re-uploads of a gem with the same version number, so we add a sequence number
+("upload version") to the version. We also format alphabetical tags (alpha,
+pre, ...) slightly differently, and we avoid hyphens. In more detail:
+
+* First, we determine the prefix: a Protocol Buffers version "3.0.0-alpha-2"
+  becomes "3.0.0.alpha.2". When we release 3.0.0, this prefix will be simply
+  "3.0.0".
+* We then append the upload version: "3.0.0.alpha.2.0" or "3.0.0.0". If we need
+  to upload a new version of the gem to fix an issue, the version becomes
+  "3.0.0.alpha.2.1" or "3.0.0.1".
+* If we are working on a prerelease version, we append a prerelease tag:
+  "3.0.0.alpha.3.0.pre". The prerelease tag comes at the end so that when
+  version numbers are sorted, any prerelease builds are ordered between the
+  prior version and current version.
+
+These rules are designed to work with the sorting rules for
+[Gem::Version](http://ruby-doc.org/stdlib-2.0/libdoc/rubygems/rdoc/Gem/Version.html):
+release numbers should sort in actual release order.
diff --git a/ruby/Rakefile b/ruby/Rakefile
new file mode 100644
index 0000000..fa29c31
--- /dev/null
+++ b/ruby/Rakefile
@@ -0,0 +1,103 @@
+require "rubygems"
+require "rubygems/package_task"
+require "rake/extensiontask" unless RUBY_PLATFORM == "java"
+require "rake/testtask"
+
+spec = Gem::Specification.load("google-protobuf.gemspec")
+
+well_known_protos = %w[
+  google/protobuf/any.proto
+  google/protobuf/api.proto
+  google/protobuf/duration.proto
+  google/protobuf/empty.proto
+  google/protobuf/field_mask.proto
+  google/protobuf/source_context.proto
+  google/protobuf/struct.proto
+  google/protobuf/timestamp.proto
+  google/protobuf/type.proto
+  google/protobuf/wrappers.proto
+]
+
+# These are omitted for now because we don't support proto2.
+proto2_protos = %w[
+  google/protobuf/descriptor.proto
+  google/protobuf/compiler/plugin.proto
+]
+
+genproto_output = []
+
+# We won't have access to .. from within docker, but the proto files
+# will be there, thanks to the :genproto rule dependency for gem:native.
+unless ENV['IN_DOCKER'] == 'true'
+  well_known_protos.each do |proto_file|
+    input_file = "../src/" + proto_file
+    output_file = "lib/" + proto_file.sub(/\.proto$/, ".rb")
+    genproto_output << output_file
+    file output_file => input_file do |file_task|
+      sh "../src/protoc -I../src --ruby_out=lib #{input_file}"
+    end
+  end
+end
+
+if RUBY_PLATFORM == "java"
+  if `which mvn` == ''
+    raise ArgumentError, "maven needs to be installed"
+  end
+  task :clean do
+    system("mvn clean")
+  end
+
+  task :compile do
+    system("mvn package")
+  end
+else
+  Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
+    ext.ext_dir = "ext/google/protobuf_c"
+    ext.lib_dir = "lib/google"
+    ext.cross_compile = true
+    ext.cross_platform = [
+      'x86-mingw32', 'x64-mingw32',
+      'x86_64-linux', 'x86-linux',
+      'universal-darwin'
+    ]
+  end
+
+  task 'gem:windows' do
+    require 'rake_compiler_dock'
+    RakeCompilerDock.sh "bundle && IN_DOCKER=true rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0"
+  end
+
+  if RUBY_PLATFORM =~ /darwin/
+    task 'gem:native' do
+      system "rake genproto"
+      system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0"
+    end
+  else
+    task 'gem:native' => [:genproto, 'gem:windows']
+  end
+end
+
+
+# Proto for tests.
+genproto_output << "tests/generated_code.rb"
+file "tests/generated_code.rb" => "tests/generated_code.proto" do |file_task|
+  sh "../src/protoc --ruby_out=. tests/generated_code.proto"
+end
+
+task :genproto => genproto_output
+
+task :clean do
+  sh "rm -f #{genproto_output.join(' ')}"
+end
+
+Gem::PackageTask.new(spec) do |pkg|
+end
+
+Rake::TestTask.new(:test => :build) do |t|
+  t.test_files = FileList["tests/*.rb"]
+end
+
+task :build => [:clean, :compile, :genproto]
+task :default => [:build]
+
+# vim:sw=2:et
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
new file mode 100644
index 0000000..7e93baf
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -0,0 +1,1763 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Common utilities.
+// -----------------------------------------------------------------------------
+
+static const char* get_str(VALUE str) {
+  Check_Type(str, T_STRING);
+  return RSTRING_PTR(str);
+}
+
+static VALUE rb_str_maybe_null(const char* s) {
+  if (s == NULL) {
+    s = "";
+  }
+  return rb_str_new2(s);
+}
+
+static upb_def* check_notfrozen(const upb_def* def) {
+  if (upb_def_isfrozen(def)) {
+    rb_raise(rb_eRuntimeError,
+             "Attempt to modify a frozen descriptor. Once descriptors are "
+             "added to the descriptor pool, they may not be modified.");
+  }
+  return (upb_def*)def;
+}
+
+static upb_msgdef* check_msg_notfrozen(const upb_msgdef* def) {
+  return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def*)def));
+}
+
+static upb_fielddef* check_field_notfrozen(const upb_fielddef* def) {
+  return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def*)def));
+}
+
+static upb_oneofdef* check_oneof_notfrozen(const upb_oneofdef* def) {
+  return (upb_oneofdef*)check_notfrozen((const upb_def*)def);
+}
+
+static upb_enumdef* check_enum_notfrozen(const upb_enumdef* def) {
+  return (upb_enumdef*)check_notfrozen((const upb_def*)def);
+}
+
+// -----------------------------------------------------------------------------
+// DescriptorPool.
+// -----------------------------------------------------------------------------
+
+#define DEFINE_CLASS(name, string_name)                             \
+    VALUE c ## name;                                                \
+    const rb_data_type_t _ ## name ## _type = {                     \
+      string_name,                                                  \
+      { name ## _mark, name ## _free, NULL },                       \
+    };                                                              \
+    name* ruby_to_ ## name(VALUE val) {                             \
+      name* ret;                                                    \
+      TypedData_Get_Struct(val, name, &_ ## name ## _type, ret);    \
+      return ret;                                                   \
+    }                                                               \
+
+#define DEFINE_SELF(type, var, rb_var)                              \
+    type* var = ruby_to_ ## type(rb_var)
+
+// Global singleton DescriptorPool. The user is free to create others, but this
+// is used by generated code.
+VALUE generated_pool;
+
+DEFINE_CLASS(DescriptorPool, "Google::Protobuf::DescriptorPool");
+
+void DescriptorPool_mark(void* _self) {
+}
+
+void DescriptorPool_free(void* _self) {
+  DescriptorPool* self = _self;
+  upb_symtab_unref(self->symtab, &self->symtab);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     DescriptorPool.new => pool
+ *
+ * Creates a new, empty, descriptor pool.
+ */
+VALUE DescriptorPool_alloc(VALUE klass) {
+  DescriptorPool* self = ALLOC(DescriptorPool);
+  self->symtab = upb_symtab_new(&self->symtab);
+  return TypedData_Wrap_Struct(klass, &_DescriptorPool_type, self);
+}
+
+void DescriptorPool_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "DescriptorPool", rb_cObject);
+  rb_define_alloc_func(klass, DescriptorPool_alloc);
+  rb_define_method(klass, "add", DescriptorPool_add, 1);
+  rb_define_method(klass, "build", DescriptorPool_build, 0);
+  rb_define_method(klass, "lookup", DescriptorPool_lookup, 1);
+  rb_define_singleton_method(klass, "generated_pool",
+                             DescriptorPool_generated_pool, 0);
+  cDescriptorPool = klass;
+  rb_gc_register_address(&cDescriptorPool);
+
+  generated_pool = rb_class_new_instance(0, NULL, klass);
+  rb_gc_register_address(&generated_pool);
+}
+
+static void add_descriptor_to_pool(DescriptorPool* self,
+                                   Descriptor* descriptor) {
+  CHECK_UPB(
+      upb_symtab_add(self->symtab, (upb_def**)&descriptor->msgdef, 1,
+                     NULL, &status),
+      "Adding Descriptor to DescriptorPool failed");
+}
+
+static void add_enumdesc_to_pool(DescriptorPool* self,
+                                 EnumDescriptor* enumdesc) {
+  CHECK_UPB(
+      upb_symtab_add(self->symtab, (upb_def**)&enumdesc->enumdef, 1,
+                     NULL, &status),
+      "Adding EnumDescriptor to DescriptorPool failed");
+}
+
+/*
+ * call-seq:
+ *     DescriptorPool.add(descriptor)
+ *
+ * Adds the given Descriptor or EnumDescriptor to this pool. All references to
+ * other types in a Descriptor's fields must be resolvable within this pool or
+ * an exception will be raised.
+ */
+VALUE DescriptorPool_add(VALUE _self, VALUE def) {
+  DEFINE_SELF(DescriptorPool, self, _self);
+  VALUE def_klass = rb_obj_class(def);
+  if (def_klass == cDescriptor) {
+    add_descriptor_to_pool(self, ruby_to_Descriptor(def));
+  } else if (def_klass == cEnumDescriptor) {
+    add_enumdesc_to_pool(self, ruby_to_EnumDescriptor(def));
+  } else {
+    rb_raise(rb_eArgError,
+             "Second argument must be a Descriptor or EnumDescriptor.");
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     DescriptorPool.build(&block)
+ *
+ * Invokes the block with a Builder instance as self. All message and enum types
+ * added within the block are committed to the pool atomically, and may refer
+ * (co)recursively to each other. The user should call Builder#add_message and
+ * Builder#add_enum within the block as appropriate.  This is the recommended,
+ * idiomatic way to define new message and enum types.
+ */
+VALUE DescriptorPool_build(VALUE _self) {
+  VALUE ctx = rb_class_new_instance(0, NULL, cBuilder);
+  VALUE block = rb_block_proc();
+  rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+  rb_funcall(ctx, rb_intern("finalize_to_pool"), 1, _self);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     DescriptorPool.lookup(name) => descriptor
+ *
+ * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none
+ * exists with the given name.
+ */
+VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
+  DEFINE_SELF(DescriptorPool, self, _self);
+  const char* name_str = get_str(name);
+  const upb_def* def = upb_symtab_lookup(self->symtab, name_str);
+  if (!def) {
+    return Qnil;
+  }
+  return get_def_obj(def);
+}
+
+/*
+ * call-seq:
+ *     DescriptorPool.generated_pool => descriptor_pool
+ *
+ * Class method that returns the global DescriptorPool. This is a singleton into
+ * which generated-code message and enum types are registered. The user may also
+ * register types in this pool for convenience so that they do not have to hold
+ * a reference to a private pool instance.
+ */
+VALUE DescriptorPool_generated_pool(VALUE _self) {
+  return generated_pool;
+}
+
+// -----------------------------------------------------------------------------
+// Descriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(Descriptor, "Google::Protobuf::Descriptor");
+
+void Descriptor_mark(void* _self) {
+  Descriptor* self = _self;
+  rb_gc_mark(self->klass);
+  rb_gc_mark(self->typeclass_references);
+}
+
+void Descriptor_free(void* _self) {
+  Descriptor* self = _self;
+  upb_msgdef_unref(self->msgdef, &self->msgdef);
+  if (self->layout) {
+    free_layout(self->layout);
+  }
+  if (self->fill_handlers) {
+    upb_handlers_unref(self->fill_handlers, &self->fill_handlers);
+  }
+  if (self->fill_method) {
+    upb_pbdecodermethod_unref(self->fill_method, &self->fill_method);
+  }
+  if (self->json_fill_method) {
+    upb_json_parsermethod_unref(self->json_fill_method,
+                                &self->json_fill_method);
+  }
+  if (self->pb_serialize_handlers) {
+    upb_handlers_unref(self->pb_serialize_handlers,
+                       &self->pb_serialize_handlers);
+  }
+  if (self->json_serialize_handlers) {
+    upb_handlers_unref(self->json_serialize_handlers,
+                       &self->json_serialize_handlers);
+  }
+  if (self->json_serialize_handlers_preserve) {
+    upb_handlers_unref(self->json_serialize_handlers_preserve,
+                       &self->json_serialize_handlers_preserve);
+  }
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     Descriptor.new => descriptor
+ *
+ * Creates a new, empty, message type descriptor. At a minimum, its name must be
+ * set before it is added to a pool. It cannot be used to create messages until
+ * it is added to a pool, after which it becomes immutable (as part of a
+ * finalization process).
+ */
+VALUE Descriptor_alloc(VALUE klass) {
+  Descriptor* self = ALLOC(Descriptor);
+  VALUE ret = TypedData_Wrap_Struct(klass, &_Descriptor_type, self);
+  self->msgdef = upb_msgdef_new(&self->msgdef);
+  self->klass = Qnil;
+  self->layout = NULL;
+  self->fill_handlers = NULL;
+  self->fill_method = NULL;
+  self->json_fill_method = NULL;
+  self->pb_serialize_handlers = NULL;
+  self->json_serialize_handlers = NULL;
+  self->json_serialize_handlers_preserve = NULL;
+  self->typeclass_references = rb_ary_new();
+  return ret;
+}
+
+void Descriptor_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "Descriptor", rb_cObject);
+  rb_define_alloc_func(klass, Descriptor_alloc);
+  rb_define_method(klass, "each", Descriptor_each, 0);
+  rb_define_method(klass, "lookup", Descriptor_lookup, 1);
+  rb_define_method(klass, "add_field", Descriptor_add_field, 1);
+  rb_define_method(klass, "add_oneof", Descriptor_add_oneof, 1);
+  rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0);
+  rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1);
+  rb_define_method(klass, "msgclass", Descriptor_msgclass, 0);
+  rb_define_method(klass, "name", Descriptor_name, 0);
+  rb_define_method(klass, "name=", Descriptor_name_set, 1);
+  rb_include_module(klass, rb_mEnumerable);
+  cDescriptor = klass;
+  rb_gc_register_address(&cDescriptor);
+}
+
+/*
+ * call-seq:
+ *     Descriptor.name => name
+ *
+ * Returns the name of this message type as a fully-qualfied string (e.g.,
+ * My.Package.MessageType).
+ */
+VALUE Descriptor_name(VALUE _self) {
+  DEFINE_SELF(Descriptor, self, _self);
+  return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
+}
+
+/*
+ * call-seq:
+ *    Descriptor.name = name
+ *
+ * Assigns a name to this message type. The descriptor must not have been added
+ * to a pool yet.
+ */
+VALUE Descriptor_name_set(VALUE _self, VALUE str) {
+  DEFINE_SELF(Descriptor, self, _self);
+  upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+  const char* name = get_str(str);
+  CHECK_UPB(
+      upb_msgdef_setfullname(mut_def, name, &status),
+      "Error setting Descriptor name");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Descriptor.each(&block)
+ *
+ * Iterates over fields in this message type, yielding to the block on each one.
+ */
+VALUE Descriptor_each(VALUE _self) {
+  DEFINE_SELF(Descriptor, self, _self);
+
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, self->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    VALUE obj = get_def_obj(field);
+    rb_yield(obj);
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Descriptor.lookup(name) => FieldDescriptor
+ *
+ * Returns the field descriptor for the field with the given name, if present,
+ * or nil if none.
+ */
+VALUE Descriptor_lookup(VALUE _self, VALUE name) {
+  DEFINE_SELF(Descriptor, self, _self);
+  const char* s = get_str(name);
+  const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
+  if (field == NULL) {
+    return Qnil;
+  }
+  return get_def_obj(field);
+}
+
+/*
+ * call-seq:
+ *     Descriptor.add_field(field) => nil
+ *
+ * Adds the given FieldDescriptor to this message type. This descriptor must not
+ * have been added to a pool yet. Raises an exception if a field with the same
+ * name or number already exists. Sub-type references (e.g. for fields of type
+ * message) are not resolved at this point.
+ */
+VALUE Descriptor_add_field(VALUE _self, VALUE obj) {
+  DEFINE_SELF(Descriptor, self, _self);
+  upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+  FieldDescriptor* def = ruby_to_FieldDescriptor(obj);
+  upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef);
+  CHECK_UPB(
+      upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status),
+      "Adding field to Descriptor failed");
+  add_def_obj(def->fielddef, obj);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Descriptor.add_oneof(oneof) => nil
+ *
+ * Adds the given OneofDescriptor to this message type. This descriptor must not
+ * have been added to a pool yet. Raises an exception if a oneof with the same
+ * name already exists, or if any of the oneof's fields' names or numbers
+ * conflict with an existing field in this message type. All fields in the oneof
+ * are added to the message descriptor. Sub-type references (e.g. for fields of
+ * type message) are not resolved at this point.
+ */
+VALUE Descriptor_add_oneof(VALUE _self, VALUE obj) {
+  DEFINE_SELF(Descriptor, self, _self);
+  upb_msgdef* mut_def = check_msg_notfrozen(self->msgdef);
+  OneofDescriptor* def = ruby_to_OneofDescriptor(obj);
+  upb_oneofdef* mut_oneof_def = check_oneof_notfrozen(def->oneofdef);
+  CHECK_UPB(
+      upb_msgdef_addoneof(mut_def, mut_oneof_def, NULL, &status),
+      "Adding oneof to Descriptor failed");
+  add_def_obj(def->oneofdef, obj);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Descriptor.each_oneof(&block) => nil
+ *
+ * Invokes the given block for each oneof in this message type, passing the
+ * corresponding OneofDescriptor.
+ */
+VALUE Descriptor_each_oneof(VALUE _self) {
+  DEFINE_SELF(Descriptor, self, _self);
+
+  upb_msg_oneof_iter it;
+  for (upb_msg_oneof_begin(&it, self->msgdef);
+       !upb_msg_oneof_done(&it);
+       upb_msg_oneof_next(&it)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
+    VALUE obj = get_def_obj(oneof);
+    rb_yield(obj);
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Descriptor.lookup_oneof(name) => OneofDescriptor
+ *
+ * Returns the oneof descriptor for the oneof with the given name, if present,
+ * or nil if none.
+ */
+VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
+  DEFINE_SELF(Descriptor, self, _self);
+  const char* s = get_str(name);
+  const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
+  if (oneof == NULL) {
+    return Qnil;
+  }
+  return get_def_obj(oneof);
+}
+
+/*
+ * call-seq:
+ *     Descriptor.msgclass => message_klass
+ *
+ * Returns the Ruby class created for this message type. Valid only once the
+ * message type has been added to a pool.
+ */
+VALUE Descriptor_msgclass(VALUE _self) {
+  DEFINE_SELF(Descriptor, self, _self);
+  if (!upb_def_isfrozen((const upb_def*)self->msgdef)) {
+    rb_raise(rb_eRuntimeError,
+             "Cannot fetch message class from a Descriptor not yet in a pool.");
+  }
+  if (self->klass == Qnil) {
+    self->klass = build_class_from_descriptor(self);
+  }
+  return self->klass;
+}
+
+// -----------------------------------------------------------------------------
+// FieldDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(FieldDescriptor, "Google::Protobuf::FieldDescriptor");
+
+void FieldDescriptor_mark(void* _self) {
+}
+
+void FieldDescriptor_free(void* _self) {
+  FieldDescriptor* self = _self;
+  upb_fielddef_unref(self->fielddef, &self->fielddef);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.new => field
+ *
+ * Returns a new field descriptor. Its name, type, etc. must be set before it is
+ * added to a message type.
+ */
+VALUE FieldDescriptor_alloc(VALUE klass) {
+  FieldDescriptor* self = ALLOC(FieldDescriptor);
+  VALUE ret = TypedData_Wrap_Struct(klass, &_FieldDescriptor_type, self);
+  upb_fielddef* fielddef = upb_fielddef_new(&self->fielddef);
+  upb_fielddef_setpacked(fielddef, false);
+  self->fielddef = fielddef;
+  return ret;
+}
+
+void FieldDescriptor_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "FieldDescriptor", rb_cObject);
+  rb_define_alloc_func(klass, FieldDescriptor_alloc);
+  rb_define_method(klass, "name", FieldDescriptor_name, 0);
+  rb_define_method(klass, "name=", FieldDescriptor_name_set, 1);
+  rb_define_method(klass, "type", FieldDescriptor_type, 0);
+  rb_define_method(klass, "type=", FieldDescriptor_type_set, 1);
+  rb_define_method(klass, "label", FieldDescriptor_label, 0);
+  rb_define_method(klass, "label=", FieldDescriptor_label_set, 1);
+  rb_define_method(klass, "number", FieldDescriptor_number, 0);
+  rb_define_method(klass, "number=", FieldDescriptor_number_set, 1);
+  rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
+  rb_define_method(klass, "submsg_name=", FieldDescriptor_submsg_name_set, 1);
+  rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0);
+  rb_define_method(klass, "get", FieldDescriptor_get, 1);
+  rb_define_method(klass, "set", FieldDescriptor_set, 2);
+  cFieldDescriptor = klass;
+  rb_gc_register_address(&cFieldDescriptor);
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.name => name
+ *
+ * Returns the name of this field.
+ */
+VALUE FieldDescriptor_name(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.name = name
+ *
+ * Sets the name of this field. Cannot be called once the containing message
+ * type, if any, is added to a pool.
+ */
+VALUE FieldDescriptor_name_set(VALUE _self, VALUE str) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+  const char* name = get_str(str);
+  CHECK_UPB(upb_fielddef_setname(mut_def, name, &status),
+            "Error setting FieldDescriptor name");
+  return Qnil;
+}
+
+upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
+  if (TYPE(type) != T_SYMBOL) {
+    rb_raise(rb_eArgError, "Expected symbol for field type.");
+  }
+
+#define CONVERT(upb, ruby)                                           \
+  if (SYM2ID(type) == rb_intern( # ruby )) {                         \
+    return UPB_TYPE_ ## upb;                                         \
+  }
+
+  CONVERT(FLOAT, float);
+  CONVERT(DOUBLE, double);
+  CONVERT(BOOL, bool);
+  CONVERT(STRING, string);
+  CONVERT(BYTES, bytes);
+  CONVERT(MESSAGE, message);
+  CONVERT(ENUM, enum);
+  CONVERT(INT32, int32);
+  CONVERT(INT64, int64);
+  CONVERT(UINT32, uint32);
+  CONVERT(UINT64, uint64);
+
+#undef CONVERT
+
+  rb_raise(rb_eArgError, "Unknown field type.");
+  return 0;
+}
+
+VALUE fieldtype_to_ruby(upb_fieldtype_t type) {
+  switch (type) {
+#define CONVERT(upb, ruby)                                           \
+    case UPB_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
+    CONVERT(FLOAT, float);
+    CONVERT(DOUBLE, double);
+    CONVERT(BOOL, bool);
+    CONVERT(STRING, string);
+    CONVERT(BYTES, bytes);
+    CONVERT(MESSAGE, message);
+    CONVERT(ENUM, enum);
+    CONVERT(INT32, int32);
+    CONVERT(INT64, int64);
+    CONVERT(UINT32, uint32);
+    CONVERT(UINT64, uint64);
+#undef CONVERT
+  }
+  return Qnil;
+}
+
+upb_descriptortype_t ruby_to_descriptortype(VALUE type) {
+  if (TYPE(type) != T_SYMBOL) {
+    rb_raise(rb_eArgError, "Expected symbol for field type.");
+  }
+
+#define CONVERT(upb, ruby)                                           \
+  if (SYM2ID(type) == rb_intern( # ruby )) {                         \
+    return UPB_DESCRIPTOR_TYPE_ ## upb;                              \
+  }
+
+  CONVERT(FLOAT, float);
+  CONVERT(DOUBLE, double);
+  CONVERT(BOOL, bool);
+  CONVERT(STRING, string);
+  CONVERT(BYTES, bytes);
+  CONVERT(MESSAGE, message);
+  CONVERT(GROUP, group);
+  CONVERT(ENUM, enum);
+  CONVERT(INT32, int32);
+  CONVERT(INT64, int64);
+  CONVERT(UINT32, uint32);
+  CONVERT(UINT64, uint64);
+  CONVERT(SINT32, sint32);
+  CONVERT(SINT64, sint64);
+  CONVERT(FIXED32, fixed32);
+  CONVERT(FIXED64, fixed64);
+  CONVERT(SFIXED32, sfixed32);
+  CONVERT(SFIXED64, sfixed64);
+
+#undef CONVERT
+
+  rb_raise(rb_eArgError, "Unknown field type.");
+  return 0;
+}
+
+VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
+  switch (type) {
+#define CONVERT(upb, ruby)                                           \
+    case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
+    CONVERT(FLOAT, float);
+    CONVERT(DOUBLE, double);
+    CONVERT(BOOL, bool);
+    CONVERT(STRING, string);
+    CONVERT(BYTES, bytes);
+    CONVERT(MESSAGE, message);
+    CONVERT(GROUP, group);
+    CONVERT(ENUM, enum);
+    CONVERT(INT32, int32);
+    CONVERT(INT64, int64);
+    CONVERT(UINT32, uint32);
+    CONVERT(UINT64, uint64);
+    CONVERT(SINT32, sint32);
+    CONVERT(SINT64, sint64);
+    CONVERT(FIXED32, fixed32);
+    CONVERT(FIXED64, fixed64);
+    CONVERT(SFIXED32, sfixed32);
+    CONVERT(SFIXED64, sfixed64);
+#undef CONVERT
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.type => type
+ *
+ * Returns this field's type, as a Ruby symbol, or nil if not yet set.
+ *
+ * Valid field types are:
+ *     :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
+ *     :bytes, :message.
+ */
+VALUE FieldDescriptor_type(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  if (!upb_fielddef_typeisset(self->fielddef)) {
+    return Qnil;
+  }
+  return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.type = type
+ *
+ * Sets this field's type. Cannot be called if field is part of a message type
+ * already in a pool.
+ */
+VALUE FieldDescriptor_type_set(VALUE _self, VALUE type) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+  upb_fielddef_setdescriptortype(mut_def, ruby_to_descriptortype(type));
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.label => label
+ *
+ * Returns this field's label (i.e., plurality), as a Ruby symbol.
+ *
+ * Valid field labels are:
+ *     :optional, :repeated
+ */
+VALUE FieldDescriptor_label(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  switch (upb_fielddef_label(self->fielddef)) {
+#define CONVERT(upb, ruby)                                           \
+    case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
+
+    CONVERT(OPTIONAL, optional);
+    CONVERT(REQUIRED, required);
+    CONVERT(REPEATED, repeated);
+
+#undef CONVERT
+  }
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.label = label
+ *
+ * Sets the label on this field. Cannot be called if field is part of a message
+ * type already in a pool.
+ */
+VALUE FieldDescriptor_label_set(VALUE _self, VALUE label) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+  upb_label_t upb_label = -1;
+  bool converted = false;
+
+  if (TYPE(label) != T_SYMBOL) {
+    rb_raise(rb_eArgError, "Expected symbol for field label.");
+  }
+
+#define CONVERT(upb, ruby)                                           \
+  if (SYM2ID(label) == rb_intern( # ruby )) {                        \
+    upb_label = UPB_LABEL_ ## upb;                                   \
+    converted = true;                                                \
+  }
+
+  CONVERT(OPTIONAL, optional);
+  CONVERT(REQUIRED, required);
+  CONVERT(REPEATED, repeated);
+
+#undef CONVERT
+
+  if (!converted) {
+    rb_raise(rb_eArgError, "Unknown field label.");
+  }
+
+  upb_fielddef_setlabel(mut_def, upb_label);
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.number => number
+ *
+ * Returns the tag number for this field.
+ */
+VALUE FieldDescriptor_number(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  return INT2NUM(upb_fielddef_number(self->fielddef));
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.number = number
+ *
+ * Sets the tag number for this field. Cannot be called if field is part of a
+ * message type already in a pool.
+ */
+VALUE FieldDescriptor_number_set(VALUE _self, VALUE number) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+  CHECK_UPB(upb_fielddef_setnumber(mut_def, NUM2INT(number), &status),
+            "Error setting field number");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.submsg_name => submsg_name
+ *
+ * Returns the name of the message or enum type corresponding to this field, if
+ * it is a message or enum field (respectively), or nil otherwise. This type
+ * name will be resolved within the context of the pool to which the containing
+ * message type is added.
+ */
+VALUE FieldDescriptor_submsg_name(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  if (!upb_fielddef_hassubdef(self->fielddef)) {
+    return Qnil;
+  }
+  return rb_str_maybe_null(upb_fielddef_subdefname(self->fielddef));
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.submsg_name = submsg_name
+ *
+ * Sets the name of the message or enum type corresponding to this field, if it
+ * is a message or enum field (respectively). This type name will be resolved
+ * within the context of the pool to which the containing message type is added.
+ * Cannot be called on field that are not of message or enum type, or on fields
+ * that are part of a message type already added to a pool.
+ */
+VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  upb_fielddef* mut_def = check_field_notfrozen(self->fielddef);
+  const char* str = get_str(value);
+  if (!upb_fielddef_hassubdef(self->fielddef)) {
+    rb_raise(rb_eTypeError, "FieldDescriptor does not have subdef.");
+  }
+  CHECK_UPB(upb_fielddef_setsubdefname(mut_def, str, &status),
+            "Error setting submessage name");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.subtype => message_or_enum_descriptor
+ *
+ * Returns the message or enum descriptor corresponding to this field's type if
+ * it is a message or enum field, respectively, or nil otherwise. Cannot be
+ * called *until* the containing message type is added to a pool (and thus
+ * resolved).
+ */
+VALUE FieldDescriptor_subtype(VALUE _self) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  const upb_def* def;
+
+  if (!upb_fielddef_hassubdef(self->fielddef)) {
+    return Qnil;
+  }
+  def = upb_fielddef_subdef(self->fielddef);
+  if (def == NULL) {
+    return Qnil;
+  }
+  return get_def_obj(def);
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.get(message) => value
+ *
+ * Returns the value set for this field on the given message. Raises an
+ * exception if message is of the wrong type.
+ */
+VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  MessageHeader* msg;
+  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+  if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+    rb_raise(rb_eTypeError, "get method called on wrong message type");
+  }
+  return layout_get(msg->descriptor->layout, Message_data(msg), self->fielddef);
+}
+
+/*
+ * call-seq:
+ *     FieldDescriptor.set(message, value)
+ *
+ * Sets the value corresponding to this field to the given value on the given
+ * message. Raises an exception if message is of the wrong type. Performs the
+ * ordinary type-checks for field setting.
+ */
+VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
+  DEFINE_SELF(FieldDescriptor, self, _self);
+  MessageHeader* msg;
+  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+  if (msg->descriptor->msgdef != upb_fielddef_containingtype(self->fielddef)) {
+    rb_raise(rb_eTypeError, "set method called on wrong message type");
+  }
+  layout_set(msg->descriptor->layout, Message_data(msg), self->fielddef, value);
+  return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// OneofDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(OneofDescriptor, "Google::Protobuf::OneofDescriptor");
+
+void OneofDescriptor_mark(void* _self) {
+}
+
+void OneofDescriptor_free(void* _self) {
+  OneofDescriptor* self = _self;
+  upb_oneofdef_unref(self->oneofdef, &self->oneofdef);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     OneofDescriptor.new => oneof_descriptor
+ *
+ * Creates a new, empty, oneof descriptor. The oneof may only be modified prior
+ * to being added to a message descriptor which is subsequently added to a pool.
+ */
+VALUE OneofDescriptor_alloc(VALUE klass) {
+  OneofDescriptor* self = ALLOC(OneofDescriptor);
+  VALUE ret = TypedData_Wrap_Struct(klass, &_OneofDescriptor_type, self);
+  self->oneofdef = upb_oneofdef_new(&self->oneofdef);
+  return ret;
+}
+
+void OneofDescriptor_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "OneofDescriptor", rb_cObject);
+  rb_define_alloc_func(klass, OneofDescriptor_alloc);
+  rb_define_method(klass, "name", OneofDescriptor_name, 0);
+  rb_define_method(klass, "name=", OneofDescriptor_name_set, 1);
+  rb_define_method(klass, "add_field", OneofDescriptor_add_field, 1);
+  rb_define_method(klass, "each", OneofDescriptor_each, 0);
+  rb_include_module(klass, rb_mEnumerable);
+  cOneofDescriptor = klass;
+  rb_gc_register_address(&cOneofDescriptor);
+}
+
+/*
+ * call-seq:
+ *     OneofDescriptor.name => name
+ *
+ * Returns the name of this oneof.
+ */
+VALUE OneofDescriptor_name(VALUE _self) {
+  DEFINE_SELF(OneofDescriptor, self, _self);
+  return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
+}
+
+/*
+ * call-seq:
+ *     OneofDescriptor.name = name
+ *
+ * Sets a new name for this oneof. The oneof must not have been added to a
+ * message descriptor yet.
+ */
+VALUE OneofDescriptor_name_set(VALUE _self, VALUE value) {
+  DEFINE_SELF(OneofDescriptor, self, _self);
+  upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
+  const char* str = get_str(value);
+  CHECK_UPB(upb_oneofdef_setname(mut_def, str, &status),
+            "Error setting oneof name");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     OneofDescriptor.add_field(field) => nil
+ *
+ * Adds a field to this oneof. The field may have been added to this oneof in
+ * the past, or the message to which this oneof belongs (if any), but may not
+ * have already been added to any other oneof or message. Otherwise, an
+ * exception is raised.
+ *
+ * All fields added to the oneof via this method will be automatically added to
+ * the message to which this oneof belongs, if it belongs to one currently, or
+ * else will be added to any message to which the oneof is later added at the
+ * time that it is added.
+ */
+VALUE OneofDescriptor_add_field(VALUE _self, VALUE obj) {
+  DEFINE_SELF(OneofDescriptor, self, _self);
+  upb_oneofdef* mut_def = check_oneof_notfrozen(self->oneofdef);
+  FieldDescriptor* def = ruby_to_FieldDescriptor(obj);
+  upb_fielddef* mut_field_def = check_field_notfrozen(def->fielddef);
+  CHECK_UPB(
+      upb_oneofdef_addfield(mut_def, mut_field_def, NULL, &status),
+      "Adding field to OneofDescriptor failed");
+  add_def_obj(def->fielddef, obj);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     OneofDescriptor.each(&block) => nil
+ *
+ * Iterates through fields in this oneof, yielding to the block on each one.
+ */
+VALUE OneofDescriptor_each(VALUE _self, VALUE field) {
+  DEFINE_SELF(OneofDescriptor, self, _self);
+  upb_oneof_iter it;
+  for (upb_oneof_begin(&it, self->oneofdef);
+       !upb_oneof_done(&it);
+       upb_oneof_next(&it)) {
+    const upb_fielddef* f = upb_oneof_iter_field(&it);
+    VALUE obj = get_def_obj(f);
+    rb_yield(obj);
+  }
+  return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// EnumDescriptor.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(EnumDescriptor, "Google::Protobuf::EnumDescriptor");
+
+void EnumDescriptor_mark(void* _self) {
+  EnumDescriptor* self = _self;
+  rb_gc_mark(self->module);
+}
+
+void EnumDescriptor_free(void* _self) {
+  EnumDescriptor* self = _self;
+  upb_enumdef_unref(self->enumdef, &self->enumdef);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.new => enum_descriptor
+ *
+ * Creates a new, empty, enum descriptor. Must be added to a pool before the
+ * enum type can be used. The enum type may only be modified prior to adding to
+ * a pool.
+ */
+VALUE EnumDescriptor_alloc(VALUE klass) {
+  EnumDescriptor* self = ALLOC(EnumDescriptor);
+  VALUE ret = TypedData_Wrap_Struct(klass, &_EnumDescriptor_type, self);
+  self->enumdef = upb_enumdef_new(&self->enumdef);
+  self->module = Qnil;
+  return ret;
+}
+
+void EnumDescriptor_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "EnumDescriptor", rb_cObject);
+  rb_define_alloc_func(klass, EnumDescriptor_alloc);
+  rb_define_method(klass, "name", EnumDescriptor_name, 0);
+  rb_define_method(klass, "name=", EnumDescriptor_name_set, 1);
+  rb_define_method(klass, "add_value", EnumDescriptor_add_value, 2);
+  rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1);
+  rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1);
+  rb_define_method(klass, "each", EnumDescriptor_each, 0);
+  rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0);
+  rb_include_module(klass, rb_mEnumerable);
+  cEnumDescriptor = klass;
+  rb_gc_register_address(&cEnumDescriptor);
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.name => name
+ *
+ * Returns the name of this enum type.
+ */
+VALUE EnumDescriptor_name(VALUE _self) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.name = name
+ *
+ * Sets the name of this enum type. Cannot be called if the enum type has
+ * already been added to a pool.
+ */
+VALUE EnumDescriptor_name_set(VALUE _self, VALUE str) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef);
+  const char* name = get_str(str);
+  CHECK_UPB(upb_enumdef_setfullname(mut_def, name, &status),
+            "Error setting EnumDescriptor name");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.add_value(key, value)
+ *
+ * Adds a new key => value mapping to this enum type. Key must be given as a
+ * Ruby symbol. Cannot be called if the enum type has already been added to a
+ * pool. Will raise an exception if the key or value is already in use.
+ */
+VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  upb_enumdef* mut_def = check_enum_notfrozen(self->enumdef);
+  const char* name_str = rb_id2name(SYM2ID(name));
+  int32_t val = NUM2INT(number);
+  CHECK_UPB(upb_enumdef_addval(mut_def, name_str, val, &status),
+            "Error adding value to enum");
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.lookup_name(name) => value
+ *
+ * Returns the numeric value corresponding to the given key name (as a Ruby
+ * symbol), or nil if none.
+ */
+VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  const char* name_str= rb_id2name(SYM2ID(name));
+  int32_t val = 0;
+  if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
+    return INT2NUM(val);
+  } else {
+    return Qnil;
+  }
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.lookup_value(name) => value
+ *
+ * Returns the key name (as a Ruby symbol) corresponding to the integer value,
+ * or nil if none.
+ */
+VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  int32_t val = NUM2INT(number);
+  const char* name = upb_enumdef_iton(self->enumdef, val);
+  if (name != NULL) {
+    return ID2SYM(rb_intern(name));
+  } else {
+    return Qnil;
+  }
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.each(&block)
+ *
+ * Iterates over key => value mappings in this enum's definition, yielding to
+ * the block with (key, value) arguments for each one.
+ */
+VALUE EnumDescriptor_each(VALUE _self) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+
+  upb_enum_iter it;
+  for (upb_enum_begin(&it, self->enumdef);
+       !upb_enum_done(&it);
+       upb_enum_next(&it)) {
+    VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it)));
+    VALUE number = INT2NUM(upb_enum_iter_number(&it));
+    rb_yield_values(2, key, number);
+  }
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     EnumDescriptor.enummodule => module
+ *
+ * Returns the Ruby module corresponding to this enum type. Cannot be called
+ * until the enum descriptor has been added to a pool.
+ */
+VALUE EnumDescriptor_enummodule(VALUE _self) {
+  DEFINE_SELF(EnumDescriptor, self, _self);
+  if (!upb_def_isfrozen((const upb_def*)self->enumdef)) {
+    rb_raise(rb_eRuntimeError,
+             "Cannot fetch enum module from an EnumDescriptor not yet "
+             "in a pool.");
+  }
+  if (self->module == Qnil) {
+    self->module = build_module_from_enumdesc(self);
+  }
+  return self->module;
+}
+
+// -----------------------------------------------------------------------------
+// MessageBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(MessageBuilderContext,
+    "Google::Protobuf::Internal::MessageBuilderContext");
+
+void MessageBuilderContext_mark(void* _self) {
+  MessageBuilderContext* self = _self;
+  rb_gc_mark(self->descriptor);
+  rb_gc_mark(self->builder);
+}
+
+void MessageBuilderContext_free(void* _self) {
+  MessageBuilderContext* self = _self;
+  xfree(self);
+}
+
+VALUE MessageBuilderContext_alloc(VALUE klass) {
+  MessageBuilderContext* self = ALLOC(MessageBuilderContext);
+  VALUE ret = TypedData_Wrap_Struct(
+      klass, &_MessageBuilderContext_type, self);
+  self->descriptor = Qnil;
+  self->builder = Qnil;
+  return ret;
+}
+
+void MessageBuilderContext_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "MessageBuilderContext", rb_cObject);
+  rb_define_alloc_func(klass, MessageBuilderContext_alloc);
+  rb_define_method(klass, "initialize",
+                   MessageBuilderContext_initialize, 2);
+  rb_define_method(klass, "optional", MessageBuilderContext_optional, -1);
+  rb_define_method(klass, "required", MessageBuilderContext_required, -1);
+  rb_define_method(klass, "repeated", MessageBuilderContext_repeated, -1);
+  rb_define_method(klass, "map", MessageBuilderContext_map, -1);
+  rb_define_method(klass, "oneof", MessageBuilderContext_oneof, 1);
+  cMessageBuilderContext = klass;
+  rb_gc_register_address(&cMessageBuilderContext);
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.new(desc, builder) => context
+ *
+ * Create a new message builder context around the given message descriptor and
+ * builder context. This class is intended to serve as a DSL context to be used
+ * with #instance_eval.
+ */
+VALUE MessageBuilderContext_initialize(VALUE _self,
+                                       VALUE msgdef,
+                                       VALUE builder) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  self->descriptor = msgdef;
+  self->builder = builder;
+  return Qnil;
+}
+
+static VALUE msgdef_add_field(VALUE msgdef,
+                              const char* label, VALUE name,
+                              VALUE type, VALUE number,
+                              VALUE type_class) {
+  VALUE fielddef = rb_class_new_instance(0, NULL, cFieldDescriptor);
+  VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+
+  rb_funcall(fielddef, rb_intern("label="), 1, ID2SYM(rb_intern(label)));
+  rb_funcall(fielddef, rb_intern("name="), 1, name_str);
+  rb_funcall(fielddef, rb_intern("type="), 1, type);
+  rb_funcall(fielddef, rb_intern("number="), 1, number);
+
+  if (type_class != Qnil) {
+    if (TYPE(type_class) != T_STRING) {
+      rb_raise(rb_eArgError, "Expected string for type class");
+    }
+    // Make it an absolute type name by prepending a dot.
+    type_class = rb_str_append(rb_str_new2("."), type_class);
+    rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class);
+  }
+
+  rb_funcall(msgdef, rb_intern("add_field"), 1, fielddef);
+  return fielddef;
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.optional(name, type, number, type_class = nil)
+ *
+ * Defines a new optional field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  VALUE name, type, number, type_class;
+
+  if (argc < 3) {
+    rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+  }
+  name = argv[0];
+  type = argv[1];
+  number = argv[2];
+  type_class = (argc > 3) ? argv[3] : Qnil;
+
+  return msgdef_add_field(self->descriptor, "optional",
+                          name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.required(name, type, number, type_class = nil)
+ *
+ * Defines a new required field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ *
+ * Proto3 does not have required fields, but this method exists for
+ * completeness. Any attempt to add a message type with required fields to a
+ * pool will currently result in an error.
+ */
+VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  VALUE name, type, number, type_class;
+
+  if (argc < 3) {
+    rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+  }
+  name = argv[0];
+  type = argv[1];
+  number = argv[2];
+  type_class = (argc > 3) ? argv[3] : Qnil;
+
+  return msgdef_add_field(self->descriptor, "required",
+                          name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.repeated(name, type, number, type_class = nil)
+ *
+ * Defines a new repeated field on this message type with the given type, tag
+ * number, and type class (for message and enum fields). The type must be a Ruby
+ * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+ * string, if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  VALUE name, type, number, type_class;
+
+  if (argc < 3) {
+    rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+  }
+  name = argv[0];
+  type = argv[1];
+  number = argv[2];
+  type_class = (argc > 3) ? argv[3] : Qnil;
+
+  return msgdef_add_field(self->descriptor, "repeated",
+                          name, type, number, type_class);
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.map(name, key_type, value_type, number,
+ *                               value_type_class = nil)
+ *
+ * Defines a new map field on this message type with the given key and value
+ * types, tag number, and type class (for message and enum value types). The key
+ * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
+ * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
+ * type_class must be a string, if present (as accepted by
+ * FieldDescriptor#submsg_name=).
+ */
+VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  VALUE name, key_type, value_type, number, type_class;
+  VALUE mapentry_desc, mapentry_desc_name;
+
+  if (argc < 4) {
+    rb_raise(rb_eArgError, "Expected at least 4 arguments.");
+  }
+  name = argv[0];
+  key_type = argv[1];
+  value_type = argv[2];
+  number = argv[3];
+  type_class = (argc > 4) ? argv[4] : Qnil;
+
+  // Validate the key type. We can't accept enums, messages, or floats/doubles
+  // as map keys. (We exclude these explicitly, and the field-descriptor setter
+  // below then ensures that the type is one of the remaining valid options.)
+  if (SYM2ID(key_type) == rb_intern("float") ||
+      SYM2ID(key_type) == rb_intern("double") ||
+      SYM2ID(key_type) == rb_intern("enum") ||
+      SYM2ID(key_type) == rb_intern("message")) {
+    rb_raise(rb_eArgError,
+             "Cannot add a map field with a float, double, enum, or message "
+             "type.");
+  }
+
+  // Create a new message descriptor for the map entry message, and create a
+  // repeated submessage field here with that type.
+  mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
+  mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0);
+  mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_");
+  mapentry_desc_name = rb_str_cat2(mapentry_desc_name,
+                                   rb_id2name(SYM2ID(name)));
+  Descriptor_name_set(mapentry_desc, mapentry_desc_name);
+
+  {
+    // The 'mapentry' attribute has no Ruby setter because we do not want the
+    // user attempting to DIY the setup below; we want to ensure that the fields
+    // are correct. So we reach into the msgdef here to set the bit manually.
+    Descriptor* mapentry_desc_self = ruby_to_Descriptor(mapentry_desc);
+    upb_msgdef_setmapentry((upb_msgdef*)mapentry_desc_self->msgdef, true);
+  }
+
+  {
+    // optional <type> key = 1;
+    VALUE key_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+    FieldDescriptor_name_set(key_field, rb_str_new2("key"));
+    FieldDescriptor_label_set(key_field, ID2SYM(rb_intern("optional")));
+    FieldDescriptor_number_set(key_field, INT2NUM(1));
+    FieldDescriptor_type_set(key_field, key_type);
+    Descriptor_add_field(mapentry_desc, key_field);
+  }
+
+  {
+    // optional <type> value = 2;
+    VALUE value_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+    FieldDescriptor_name_set(value_field, rb_str_new2("value"));
+    FieldDescriptor_label_set(value_field, ID2SYM(rb_intern("optional")));
+    FieldDescriptor_number_set(value_field, INT2NUM(2));
+    FieldDescriptor_type_set(value_field, value_type);
+    if (type_class != Qnil) {
+      VALUE submsg_name = rb_str_new2("."); // prepend '.' to make absolute.
+      submsg_name = rb_str_append(submsg_name, type_class);
+      FieldDescriptor_submsg_name_set(value_field, submsg_name);
+    }
+    Descriptor_add_field(mapentry_desc, value_field);
+  }
+
+  {
+    // Add the map-entry message type to the current builder, and use the type
+    // to create the map field itself.
+    Builder* builder_self = ruby_to_Builder(self->builder);
+    rb_ary_push(builder_self->pending_list, mapentry_desc);
+  }
+
+  {
+    VALUE map_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
+    VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+    VALUE submsg_name;
+
+    FieldDescriptor_name_set(map_field, name_str);
+    FieldDescriptor_number_set(map_field, number);
+    FieldDescriptor_label_set(map_field, ID2SYM(rb_intern("repeated")));
+    FieldDescriptor_type_set(map_field, ID2SYM(rb_intern("message")));
+    submsg_name = rb_str_new2("."); // prepend '.' to make name absolute.
+    submsg_name = rb_str_append(submsg_name, mapentry_desc_name);
+    FieldDescriptor_submsg_name_set(map_field, submsg_name);
+    Descriptor_add_field(self->descriptor, map_field);
+  }
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     MessageBuilderContext.oneof(name, &block) => nil
+ *
+ * Creates a new OneofDescriptor with the given name, creates a
+ * OneofBuilderContext attached to that OneofDescriptor, evaluates the given
+ * block in the context of that OneofBuilderContext with #instance_eval, and
+ * then adds the oneof to the message.
+ *
+ * This is the recommended, idiomatic way to build oneof definitions.
+ */
+VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name) {
+  DEFINE_SELF(MessageBuilderContext, self, _self);
+  VALUE oneofdef = rb_class_new_instance(0, NULL, cOneofDescriptor);
+  VALUE args[2] = { oneofdef, self->builder };
+  VALUE ctx = rb_class_new_instance(2, args, cOneofBuilderContext);
+  VALUE block = rb_block_proc();
+  VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
+  rb_funcall(oneofdef, rb_intern("name="), 1, name_str);
+  rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+  Descriptor_add_oneof(self->descriptor, oneofdef);
+
+  return Qnil;
+}
+
+// -----------------------------------------------------------------------------
+// OneofBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(OneofBuilderContext,
+    "Google::Protobuf::Internal::OneofBuilderContext");
+
+void OneofBuilderContext_mark(void* _self) {
+  OneofBuilderContext* self = _self;
+  rb_gc_mark(self->descriptor);
+  rb_gc_mark(self->builder);
+}
+
+void OneofBuilderContext_free(void* _self) {
+  OneofBuilderContext* self = _self;
+  xfree(self);
+}
+
+VALUE OneofBuilderContext_alloc(VALUE klass) {
+  OneofBuilderContext* self = ALLOC(OneofBuilderContext);
+  VALUE ret = TypedData_Wrap_Struct(
+      klass, &_OneofBuilderContext_type, self);
+  self->descriptor = Qnil;
+  self->builder = Qnil;
+  return ret;
+}
+
+void OneofBuilderContext_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "OneofBuilderContext", rb_cObject);
+  rb_define_alloc_func(klass, OneofBuilderContext_alloc);
+  rb_define_method(klass, "initialize",
+                   OneofBuilderContext_initialize, 2);
+  rb_define_method(klass, "optional", OneofBuilderContext_optional, -1);
+  cOneofBuilderContext = klass;
+  rb_gc_register_address(&cOneofBuilderContext);
+}
+
+/*
+ * call-seq:
+ *     OneofBuilderContext.new(desc, builder) => context
+ *
+ * Create a new oneof builder context around the given oneof descriptor and
+ * builder context. This class is intended to serve as a DSL context to be used
+ * with #instance_eval.
+ */
+VALUE OneofBuilderContext_initialize(VALUE _self,
+                                     VALUE oneofdef,
+                                     VALUE builder) {
+  DEFINE_SELF(OneofBuilderContext, self, _self);
+  self->descriptor = oneofdef;
+  self->builder = builder;
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     OneofBuilderContext.optional(name, type, number, type_class = nil)
+ *
+ * Defines a new optional field in this oneof with the given type, tag number,
+ * and type class (for message and enum fields). The type must be a Ruby symbol
+ * (as accepted by FieldDescriptor#type=) and the type_class must be a string,
+ * if present (as accepted by FieldDescriptor#submsg_name=).
+ */
+VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self) {
+  DEFINE_SELF(OneofBuilderContext, self, _self);
+  VALUE name, type, number, type_class;
+
+  if (argc < 3) {
+    rb_raise(rb_eArgError, "Expected at least 3 arguments.");
+  }
+  name = argv[0];
+  type = argv[1];
+  number = argv[2];
+  type_class = (argc > 3) ? argv[3] : Qnil;
+
+  return msgdef_add_field(self->descriptor, "optional",
+                          name, type, number, type_class);
+}
+
+// -----------------------------------------------------------------------------
+// EnumBuilderContext.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(EnumBuilderContext,
+    "Google::Protobuf::Internal::EnumBuilderContext");
+
+void EnumBuilderContext_mark(void* _self) {
+  EnumBuilderContext* self = _self;
+  rb_gc_mark(self->enumdesc);
+}
+
+void EnumBuilderContext_free(void* _self) {
+  EnumBuilderContext* self = _self;
+  xfree(self);
+}
+
+VALUE EnumBuilderContext_alloc(VALUE klass) {
+  EnumBuilderContext* self = ALLOC(EnumBuilderContext);
+  VALUE ret = TypedData_Wrap_Struct(
+      klass, &_EnumBuilderContext_type, self);
+  self->enumdesc = Qnil;
+  return ret;
+}
+
+void EnumBuilderContext_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "EnumBuilderContext", rb_cObject);
+  rb_define_alloc_func(klass, EnumBuilderContext_alloc);
+  rb_define_method(klass, "initialize",
+                   EnumBuilderContext_initialize, 1);
+  rb_define_method(klass, "value", EnumBuilderContext_value, 2);
+  cEnumBuilderContext = klass;
+  rb_gc_register_address(&cEnumBuilderContext);
+}
+
+/*
+ * call-seq:
+ *     EnumBuilderContext.new(enumdesc) => context
+ *
+ * Create a new builder context around the given enum descriptor. This class is
+ * intended to serve as a DSL context to be used with #instance_eval.
+ */
+VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdef) {
+  DEFINE_SELF(EnumBuilderContext, self, _self);
+  self->enumdesc = enumdef;
+  return Qnil;
+}
+
+static VALUE enumdef_add_value(VALUE enumdef,
+                               VALUE name, VALUE number) {
+  rb_funcall(enumdef, rb_intern("add_value"), 2, name, number);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     EnumBuilder.add_value(name, number)
+ *
+ * Adds the given name => number mapping to the enum type. Name must be a Ruby
+ * symbol.
+ */
+VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number) {
+  DEFINE_SELF(EnumBuilderContext, self, _self);
+  return enumdef_add_value(self->enumdesc, name, number);
+}
+
+// -----------------------------------------------------------------------------
+// Builder.
+// -----------------------------------------------------------------------------
+
+DEFINE_CLASS(Builder, "Google::Protobuf::Internal::Builder");
+
+void Builder_mark(void* _self) {
+  Builder* self = _self;
+  rb_gc_mark(self->pending_list);
+}
+
+void Builder_free(void* _self) {
+  Builder* self = _self;
+  xfree(self->defs);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     Builder.new => builder
+ *
+ * Creates a new Builder. A Builder can accumulate a set of new message and enum
+ * descriptors and atomically register them into a pool in a way that allows for
+ * (co)recursive type references.
+ */
+VALUE Builder_alloc(VALUE klass) {
+  Builder* self = ALLOC(Builder);
+  VALUE ret = TypedData_Wrap_Struct(
+      klass, &_Builder_type, self);
+  self->pending_list = rb_ary_new();
+  self->defs = NULL;
+  return ret;
+}
+
+void Builder_register(VALUE module) {
+  VALUE klass = rb_define_class_under(module, "Builder", rb_cObject);
+  rb_define_alloc_func(klass, Builder_alloc);
+  rb_define_method(klass, "add_message", Builder_add_message, 1);
+  rb_define_method(klass, "add_enum", Builder_add_enum, 1);
+  rb_define_method(klass, "finalize_to_pool", Builder_finalize_to_pool, 1);
+  cBuilder = klass;
+  rb_gc_register_address(&cBuilder);
+}
+
+/*
+ * call-seq:
+ *     Builder.add_message(name, &block)
+ *
+ * Creates a new, empty descriptor with the given name, and invokes the block in
+ * the context of a MessageBuilderContext on that descriptor. The block can then
+ * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
+ * methods to define the message fields.
+ *
+ * This is the recommended, idiomatic way to build message definitions.
+ */
+VALUE Builder_add_message(VALUE _self, VALUE name) {
+  DEFINE_SELF(Builder, self, _self);
+  VALUE msgdef = rb_class_new_instance(0, NULL, cDescriptor);
+  VALUE args[2] = { msgdef, _self };
+  VALUE ctx = rb_class_new_instance(2, args, cMessageBuilderContext);
+  VALUE block = rb_block_proc();
+  rb_funcall(msgdef, rb_intern("name="), 1, name);
+  rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+  rb_ary_push(self->pending_list, msgdef);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Builder.add_enum(name, &block)
+ *
+ * Creates a new, empty enum descriptor with the given name, and invokes the
+ * block in the context of an EnumBuilderContext on that descriptor. The block
+ * can then call EnumBuilderContext#add_value to define the enum values.
+ *
+ * This is the recommended, idiomatic way to build enum definitions.
+ */
+VALUE Builder_add_enum(VALUE _self, VALUE name) {
+  DEFINE_SELF(Builder, self, _self);
+  VALUE enumdef = rb_class_new_instance(0, NULL, cEnumDescriptor);
+  VALUE ctx = rb_class_new_instance(1, &enumdef, cEnumBuilderContext);
+  VALUE block = rb_block_proc();
+  rb_funcall(enumdef, rb_intern("name="), 1, name);
+  rb_funcall_with_block(ctx, rb_intern("instance_eval"), 0, NULL, block);
+  rb_ary_push(self->pending_list, enumdef);
+  return Qnil;
+}
+
+static void validate_msgdef(const upb_msgdef* msgdef) {
+  // Verify that no required fields exist. proto3 does not support these.
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
+      rb_raise(rb_eTypeError, "Required fields are unsupported in proto3.");
+    }
+  }
+}
+
+static void validate_enumdef(const upb_enumdef* enumdef) {
+  // Verify that an entry exists with integer value 0. (This is the default
+  // value.)
+  const char* lookup = upb_enumdef_iton(enumdef, 0);
+  if (lookup == NULL) {
+    rb_raise(rb_eTypeError,
+             "Enum definition does not contain a value for '0'.");
+  }
+}
+
+/*
+ * call-seq:
+ *     Builder.finalize_to_pool(pool)
+ *
+ * Adds all accumulated message and enum descriptors created in this builder
+ * context to the given pool. The operation occurs atomically, and all
+ * descriptors can refer to each other (including in cycles). This is the only
+ * way to build (co)recursive message definitions.
+ *
+ * This method is usually called automatically by DescriptorPool#build after it
+ * invokes the given user block in the context of the builder. The user should
+ * not normally need to call this manually because a Builder is not normally
+ * created manually.
+ */
+VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
+  DEFINE_SELF(Builder, self, _self);
+
+  DescriptorPool* pool = ruby_to_DescriptorPool(pool_rb);
+
+  REALLOC_N(self->defs, upb_def*, RARRAY_LEN(self->pending_list));
+
+  for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
+    VALUE def_rb = rb_ary_entry(self->pending_list, i);
+    if (CLASS_OF(def_rb) == cDescriptor) {
+      self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
+      validate_msgdef((const upb_msgdef*)self->defs[i]);
+    } else if (CLASS_OF(def_rb) == cEnumDescriptor) {
+      self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef;
+      validate_enumdef((const upb_enumdef*)self->defs[i]);
+    }
+  }
+
+  CHECK_UPB(upb_symtab_add(pool->symtab, (upb_def**)self->defs,
+                           RARRAY_LEN(self->pending_list), NULL, &status),
+            "Unable to add defs to DescriptorPool");
+
+  for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
+    VALUE def_rb = rb_ary_entry(self->pending_list, i);
+    add_def_obj(self->defs[i], def_rb);
+  }
+
+  self->pending_list = rb_ary_new();
+  return Qnil;
+}
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
new file mode 100644
index 0000000..f6bea50
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -0,0 +1,1233 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// This function is equivalent to rb_str_cat(), but unlike the real
+// rb_str_cat(), it doesn't leak memory in some versions of Ruby.
+// For more information, see:
+//   https://bugs.ruby-lang.org/issues/11328
+VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) {
+  char *p;
+  size_t oldlen = RSTRING_LEN(rb_str);
+  rb_str_modify_expand(rb_str, len);
+  p = RSTRING_PTR(rb_str);
+  memcpy(p + oldlen, str, len);
+  rb_str_set_len(rb_str, oldlen + len);
+  return rb_str;
+}
+
+// -----------------------------------------------------------------------------
+// Parsing.
+// -----------------------------------------------------------------------------
+
+#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
+
+// Creates a handlerdata that simply contains the offset for this field.
+static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) {
+  size_t* hd_ofs = ALLOC(size_t);
+  *hd_ofs = ofs;
+  upb_handlers_addcleanup(h, hd_ofs, free);
+  return hd_ofs;
+}
+
+typedef struct {
+  size_t ofs;
+  const upb_msgdef *md;
+} submsg_handlerdata_t;
+
+// Creates a handlerdata that contains offset and submessage type information.
+static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
+                                        const upb_fielddef* f) {
+  submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
+  hd->ofs = ofs;
+  hd->md = upb_fielddef_msgsubdef(f);
+  upb_handlers_addcleanup(h, hd, free);
+  return hd;
+}
+
+typedef struct {
+  size_t ofs;              // union data slot
+  size_t case_ofs;         // oneof_case field
+  uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
+  const upb_msgdef *md;    // msgdef, for oneof submessage handler
+} oneof_handlerdata_t;
+
+static const void *newoneofhandlerdata(upb_handlers *h,
+                                       uint32_t ofs,
+                                       uint32_t case_ofs,
+                                       const upb_fielddef *f) {
+  oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
+  hd->ofs = ofs;
+  hd->case_ofs = case_ofs;
+  // We reuse the field tag number as a oneof union discriminant tag. Note that
+  // we don't expose these numbers to the user, so the only requirement is that
+  // we have some unique ID for each union case/possibility. The field tag
+  // numbers are already present and are easy to use so there's no reason to
+  // create a separate ID space. In addition, using the field tag number here
+  // lets us easily look up the field in the oneof accessor.
+  hd->oneof_case_num = upb_fielddef_number(f);
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
+    hd->md = upb_fielddef_msgsubdef(f);
+  } else {
+    hd->md = NULL;
+  }
+  upb_handlers_addcleanup(h, hd, free);
+  return hd;
+}
+
+// A handler that starts a repeated field.  Gets the Repeated*Field instance for
+// this field (such an instance always exists even in an empty message).
+static void *startseq_handler(void* closure, const void* hd) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  return (void*)DEREF(msg, *ofs, VALUE);
+}
+
+// Handlers that append primitive values to a repeated field.
+#define DEFINE_APPEND_HANDLER(type, ctype)                 \
+  static bool append##type##_handler(void *closure, const void *hd, \
+                                     ctype val) {                   \
+    VALUE ary = (VALUE)closure;                                     \
+    RepeatedField_push_native(ary, &val);                           \
+    return true;                                                    \
+  }
+
+DEFINE_APPEND_HANDLER(bool,   bool)
+DEFINE_APPEND_HANDLER(int32,  int32_t)
+DEFINE_APPEND_HANDLER(uint32, uint32_t)
+DEFINE_APPEND_HANDLER(float,  float)
+DEFINE_APPEND_HANDLER(int64,  int64_t)
+DEFINE_APPEND_HANDLER(uint64, uint64_t)
+DEFINE_APPEND_HANDLER(double, double)
+
+// Appends a string to a repeated field.
+static void* appendstr_handler(void *closure,
+                               const void *hd,
+                               size_t size_hint) {
+  VALUE ary = (VALUE)closure;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyStringUtf8Encoding);
+  RepeatedField_push(ary, str);
+  return (void*)str;
+}
+
+// Appends a 'bytes' string to a repeated field.
+static void* appendbytes_handler(void *closure,
+                                 const void *hd,
+                                 size_t size_hint) {
+  VALUE ary = (VALUE)closure;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyString8bitEncoding);
+  RepeatedField_push(ary, str);
+  return (void*)str;
+}
+
+// Sets a non-repeated string field in a message.
+static void* str_handler(void *closure,
+                         const void *hd,
+                         size_t size_hint) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyStringUtf8Encoding);
+  DEREF(msg, *ofs, VALUE) = str;
+  return (void*)str;
+}
+
+// Sets a non-repeated 'bytes' field in a message.
+static void* bytes_handler(void *closure,
+                           const void *hd,
+                           size_t size_hint) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyString8bitEncoding);
+  DEREF(msg, *ofs, VALUE) = str;
+  return (void*)str;
+}
+
+static size_t stringdata_handler(void* closure, const void* hd,
+                                 const char* str, size_t len,
+                                 const upb_bufhandle* handle) {
+  VALUE rb_str = (VALUE)closure;
+  noleak_rb_str_cat(rb_str, str, len);
+  return len;
+}
+
+// Appends a submessage to a repeated field (a regular Ruby array for now).
+static void *appendsubmsg_handler(void *closure, const void *hd) {
+  VALUE ary = (VALUE)closure;
+  const submsg_handlerdata_t *submsgdata = hd;
+  VALUE subdesc =
+      get_def_obj((void*)submsgdata->md);
+  VALUE subklass = Descriptor_msgclass(subdesc);
+  MessageHeader* submsg;
+
+  VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
+  RepeatedField_push(ary, submsg_rb);
+
+  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+  return submsg;
+}
+
+// Sets a non-repeated submessage field in a message.
+static void *submsg_handler(void *closure, const void *hd) {
+  MessageHeader* msg = closure;
+  const submsg_handlerdata_t* submsgdata = hd;
+  VALUE subdesc =
+      get_def_obj((void*)submsgdata->md);
+  VALUE subklass = Descriptor_msgclass(subdesc);
+  VALUE submsg_rb;
+  MessageHeader* submsg;
+
+  if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
+    DEREF(msg, submsgdata->ofs, VALUE) =
+        rb_class_new_instance(0, NULL, subklass);
+  }
+
+  submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
+  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+  return submsg;
+}
+
+// Handler data for startmap/endmap handlers.
+typedef struct {
+  size_t ofs;
+  upb_fieldtype_t key_field_type;
+  upb_fieldtype_t value_field_type;
+
+  // We know that we can hold this reference because the handlerdata has the
+  // same lifetime as the upb_handlers struct, and the upb_handlers struct holds
+  // a reference to the upb_msgdef, which in turn has references to its subdefs.
+  const upb_def* value_field_subdef;
+} map_handlerdata_t;
+
+// Temporary frame for map parsing: at the beginning of a map entry message, a
+// submsg handler allocates a frame to hold (i) a reference to the Map object
+// into which this message will be inserted and (ii) storage slots to
+// temporarily hold the key and value for this map entry until the end of the
+// submessage. When the submessage ends, another handler is called to insert the
+// value into the map.
+typedef struct {
+  VALUE map;
+  char key_storage[NATIVE_SLOT_MAX_SIZE];
+  char value_storage[NATIVE_SLOT_MAX_SIZE];
+} map_parse_frame_t;
+
+// Handler to begin a map entry: allocates a temporary frame. This is the
+// 'startsubmsg' handler on the msgdef that contains the map field.
+static void *startmapentry_handler(void *closure, const void *hd) {
+  MessageHeader* msg = closure;
+  const map_handlerdata_t* mapdata = hd;
+  VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE);
+
+  map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
+  frame->map = map_rb;
+
+  native_slot_init(mapdata->key_field_type, &frame->key_storage);
+  native_slot_init(mapdata->value_field_type, &frame->value_storage);
+
+  return frame;
+}
+
+// Handler to end a map entry: inserts the value defined during the message into
+// the map. This is the 'endmsg' handler on the map entry msgdef.
+static bool endmap_handler(void *closure, const void *hd, upb_status* s) {
+  map_parse_frame_t* frame = closure;
+  const map_handlerdata_t* mapdata = hd;
+
+  VALUE key = native_slot_get(
+      mapdata->key_field_type, Qnil,
+      &frame->key_storage);
+
+  VALUE value_field_typeclass = Qnil;
+  VALUE value;
+
+  if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
+      mapdata->value_field_type == UPB_TYPE_ENUM) {
+    value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
+  }
+
+  value = native_slot_get(
+      mapdata->value_field_type, value_field_typeclass,
+      &frame->value_storage);
+
+  Map_index_set(frame->map, key, value);
+  free(frame);
+
+  return true;
+}
+
+// Allocates a new map_handlerdata_t given the map entry message definition. If
+// the offset of the field within the parent message is also given, that is
+// added to the handler data as well. Note that this is called *twice* per map
+// field: once in the parent message handler setup when setting the startsubmsg
+// handler and once in the map entry message handler setup when setting the
+// key/value and endmsg handlers. The reason is that there is no easy way to
+// pass the handlerdata down to the sub-message handler setup.
+static map_handlerdata_t* new_map_handlerdata(
+    size_t ofs,
+    const upb_msgdef* mapentry_def,
+    Descriptor* desc) {
+  const upb_fielddef* key_field;
+  const upb_fielddef* value_field;
+  map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
+  hd->ofs = ofs;
+  key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
+  assert(key_field != NULL);
+  hd->key_field_type = upb_fielddef_type(key_field);
+  value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
+  assert(value_field != NULL);
+  hd->value_field_type = upb_fielddef_type(value_field);
+  hd->value_field_subdef = upb_fielddef_subdef(value_field);
+
+  return hd;
+}
+
+// Handlers that set primitive values in oneofs.
+#define DEFINE_ONEOF_HANDLER(type, ctype)                           \
+  static bool oneof##type##_handler(void *closure, const void *hd,  \
+                                     ctype val) {                   \
+    const oneof_handlerdata_t *oneofdata = hd;                      \
+    DEREF(closure, oneofdata->case_ofs, uint32_t) =                 \
+        oneofdata->oneof_case_num;                                  \
+    DEREF(closure, oneofdata->ofs, ctype) = val;                    \
+    return true;                                                    \
+  }
+
+DEFINE_ONEOF_HANDLER(bool,   bool)
+DEFINE_ONEOF_HANDLER(int32,  int32_t)
+DEFINE_ONEOF_HANDLER(uint32, uint32_t)
+DEFINE_ONEOF_HANDLER(float,  float)
+DEFINE_ONEOF_HANDLER(int64,  int64_t)
+DEFINE_ONEOF_HANDLER(uint64, uint64_t)
+DEFINE_ONEOF_HANDLER(double, double)
+
+#undef DEFINE_ONEOF_HANDLER
+
+// Handlers for strings in a oneof.
+static void *oneofstr_handler(void *closure,
+                              const void *hd,
+                              size_t size_hint) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyStringUtf8Encoding);
+  DEREF(msg, oneofdata->case_ofs, uint32_t) =
+      oneofdata->oneof_case_num;
+  DEREF(msg, oneofdata->ofs, VALUE) = str;
+  return (void*)str;
+}
+
+static void *oneofbytes_handler(void *closure,
+                                const void *hd,
+                                size_t size_hint) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+  VALUE str = rb_str_new2("");
+  rb_enc_associate(str, kRubyString8bitEncoding);
+  DEREF(msg, oneofdata->case_ofs, uint32_t) =
+      oneofdata->oneof_case_num;
+  DEREF(msg, oneofdata->ofs, VALUE) = str;
+  return (void*)str;
+}
+
+// Handler for a submessage field in a oneof.
+static void *oneofsubmsg_handler(void *closure,
+                                 const void *hd) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+  uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
+
+  VALUE subdesc =
+      get_def_obj((void*)oneofdata->md);
+  VALUE subklass = Descriptor_msgclass(subdesc);
+  VALUE submsg_rb;
+  MessageHeader* submsg;
+
+  if (oldcase != oneofdata->oneof_case_num ||
+      DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
+    DEREF(msg, oneofdata->ofs, VALUE) =
+        rb_class_new_instance(0, NULL, subklass);
+  }
+  // Set the oneof case *after* allocating the new class instance -- otherwise,
+  // if the Ruby GC is invoked as part of a call into the VM, it might invoke
+  // our mark routines, and our mark routines might see the case value
+  // indicating a VALUE is present and expect a valid VALUE. See comment in
+  // layout_set() for more detail: basically, the change to the value and the
+  // case must be atomic w.r.t. the Ruby VM.
+  DEREF(msg, oneofdata->case_ofs, uint32_t) =
+      oneofdata->oneof_case_num;
+
+  submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
+  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
+  return submsg;
+}
+
+// Set up handlers for a repeated field.
+static void add_handlers_for_repeated_field(upb_handlers *h,
+                                            const upb_fielddef *f,
+                                            size_t offset) {
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+  upb_handlers_setstartseq(h, f, startseq_handler, &attr);
+  upb_handlerattr_uninit(&attr);
+
+  switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype)                                 \
+  case utype:                                                     \
+    upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \
+    break;
+
+    SET_HANDLER(UPB_TYPE_BOOL,   bool);
+    SET_HANDLER(UPB_TYPE_INT32,  int32);
+    SET_HANDLER(UPB_TYPE_UINT32, uint32);
+    SET_HANDLER(UPB_TYPE_ENUM,   int32);
+    SET_HANDLER(UPB_TYPE_FLOAT,  float);
+    SET_HANDLER(UPB_TYPE_INT64,  int64);
+    SET_HANDLER(UPB_TYPE_UINT64, uint64);
+    SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlers_setstartstr(h, f, is_bytes ?
+                               appendbytes_handler : appendstr_handler,
+                               NULL);
+      upb_handlers_setstring(h, f, stringdata_handler, NULL);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f));
+      upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+  }
+}
+
+// Set up handlers for a singular field.
+static void add_handlers_for_singular_field(upb_handlers *h,
+                                            const upb_fielddef *f,
+                                            size_t offset) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_FLOAT:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_DOUBLE:
+      upb_shim_set(h, f, offset, -1);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+      upb_handlers_setstartstr(h, f,
+                               is_bytes ? bytes_handler : str_handler,
+                               &attr);
+      upb_handlers_setstring(h, f, stringdata_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f));
+      upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+  }
+}
+
+// Adds handlers to a map field.
+static void add_handlers_for_mapfield(upb_handlers* h,
+                                      const upb_fielddef* fielddef,
+                                      size_t offset,
+                                      Descriptor* desc) {
+  const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
+  map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+
+  upb_handlers_addcleanup(h, hd, free);
+  upb_handlerattr_sethandlerdata(&attr, hd);
+  upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
+  upb_handlerattr_uninit(&attr);
+}
+
+// Adds handlers to a map-entry msgdef.
+static void add_handlers_for_mapentry(const upb_msgdef* msgdef,
+                                      upb_handlers* h,
+                                      Descriptor* desc) {
+  const upb_fielddef* key_field = map_entry_key(msgdef);
+  const upb_fielddef* value_field = map_entry_value(msgdef);
+  map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+
+  upb_handlers_addcleanup(h, hd, free);
+  upb_handlerattr_sethandlerdata(&attr, hd);
+  upb_handlers_setendmsg(h, endmap_handler, &attr);
+
+  add_handlers_for_singular_field(
+      h, key_field,
+      offsetof(map_parse_frame_t, key_storage));
+  add_handlers_for_singular_field(
+      h, value_field,
+      offsetof(map_parse_frame_t, value_storage));
+}
+
+// Set up handlers for a oneof field.
+static void add_handlers_for_oneof_field(upb_handlers *h,
+                                         const upb_fielddef *f,
+                                         size_t offset,
+                                         size_t oneof_case_offset) {
+
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(
+      &attr, newoneofhandlerdata(h, offset, oneof_case_offset, f));
+
+  switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype)                                 \
+  case utype:                                                     \
+    upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
+    break;
+
+    SET_HANDLER(UPB_TYPE_BOOL,   bool);
+    SET_HANDLER(UPB_TYPE_INT32,  int32);
+    SET_HANDLER(UPB_TYPE_UINT32, uint32);
+    SET_HANDLER(UPB_TYPE_ENUM,   int32);
+    SET_HANDLER(UPB_TYPE_FLOAT,  float);
+    SET_HANDLER(UPB_TYPE_INT64,  int64);
+    SET_HANDLER(UPB_TYPE_UINT64, uint64);
+    SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlers_setstartstr(h, f, is_bytes ?
+                               oneofbytes_handler : oneofstr_handler,
+                               &attr);
+      upb_handlers_setstring(h, f, stringdata_handler, NULL);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
+      break;
+    }
+  }
+
+  upb_handlerattr_uninit(&attr);
+}
+
+
+static void add_handlers_for_message(const void *closure, upb_handlers *h) {
+  const upb_msgdef* msgdef = upb_handlers_msgdef(h);
+  Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
+  upb_msg_field_iter i;
+
+  // If this is a mapentry message type, set up a special set of handlers and
+  // bail out of the normal (user-defined) message type handling.
+  if (upb_msgdef_mapentry(msgdef)) {
+    add_handlers_for_mapentry(msgdef, h, desc);
+    return;
+  }
+
+  // Ensure layout exists. We may be invoked to create handlers for a given
+  // message if we are included as a submsg of another message type before our
+  // class is actually built, so to work around this, we just create the layout
+  // (and handlers, in the class-building function) on-demand.
+  if (desc->layout == NULL) {
+    desc->layout = create_layout(desc->msgdef);
+  }
+
+  for (upb_msg_field_begin(&i, desc->msgdef);
+       !upb_msg_field_done(&i);
+       upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
+        sizeof(MessageHeader);
+
+    if (upb_fielddef_containingoneof(f)) {
+      size_t oneof_case_offset =
+          desc->layout->fields[upb_fielddef_index(f)].case_offset +
+          sizeof(MessageHeader);
+      add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
+    } else if (is_map_field(f)) {
+      add_handlers_for_mapfield(h, f, offset, desc);
+    } else if (upb_fielddef_isseq(f)) {
+      add_handlers_for_repeated_field(h, f, offset);
+    } else {
+      add_handlers_for_singular_field(h, f, offset);
+    }
+  }
+}
+
+// Creates upb handlers for populating a message.
+static const upb_handlers *new_fill_handlers(Descriptor* desc,
+                                             const void* owner) {
+  // TODO(cfallin, haberman): once upb gets a caching/memoization layer for
+  // handlers, reuse subdef handlers so that e.g. if we already parse
+  // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to
+  // parse A-with-field-of-type-B-with-field-of-type-C.
+  return upb_handlers_newfrozen(desc->msgdef, owner,
+                                add_handlers_for_message, NULL);
+}
+
+// Constructs the handlers for filling a message's data into an in-memory
+// object.
+const upb_handlers* get_fill_handlers(Descriptor* desc) {
+  if (!desc->fill_handlers) {
+    desc->fill_handlers =
+        new_fill_handlers(desc, &desc->fill_handlers);
+  }
+  return desc->fill_handlers;
+}
+
+// Constructs the upb decoder method for parsing messages of this type.
+// This is called from the message class creation code.
+const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc,
+                                                     const void* owner) {
+  const upb_handlers* handlers = get_fill_handlers(desc);
+  upb_pbdecodermethodopts opts;
+  upb_pbdecodermethodopts_init(&opts, handlers);
+
+  return upb_pbdecodermethod_new(&opts, owner);
+}
+
+static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
+  if (desc->fill_method == NULL) {
+    desc->fill_method = new_fillmsg_decodermethod(
+        desc, &desc->fill_method);
+  }
+  return desc->fill_method;
+}
+
+static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
+  if (desc->json_fill_method == NULL) {
+    desc->json_fill_method =
+        upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
+  }
+  return desc->json_fill_method;
+}
+
+
+// Stack-allocated context during an encode/decode operation. Contains the upb
+// environment and its stack-based allocator, an initial buffer for allocations
+// to avoid malloc() when possible, and a template for Ruby exception messages
+// if any error occurs.
+#define STACK_ENV_STACKBYTES 4096
+typedef struct {
+  upb_env env;
+  const char* ruby_error_template;
+  char allocbuf[STACK_ENV_STACKBYTES];
+} stackenv;
+
+static void stackenv_init(stackenv* se, const char* errmsg);
+static void stackenv_uninit(stackenv* se);
+
+// Callback invoked by upb if any error occurs during parsing or serialization.
+static bool env_error_func(void* ud, const upb_status* status) {
+  stackenv* se = ud;
+  // Free the env -- rb_raise will longjmp up the stack past the encode/decode
+  // function so it would not otherwise have been freed.
+  stackenv_uninit(se);
+
+  // TODO(haberman): have a way to verify that this is actually a parse error,
+  // instead of just throwing "parse error" unconditionally.
+  rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status));
+  // Never reached: rb_raise() always longjmp()s up the stack, past all of our
+  // code, back to Ruby.
+  return false;
+}
+
+static void stackenv_init(stackenv* se, const char* errmsg) {
+  se->ruby_error_template = errmsg;
+  upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL);
+  upb_env_seterrorfunc(&se->env, env_error_func, se);
+}
+
+static void stackenv_uninit(stackenv* se) {
+  upb_env_uninit(&se->env);
+}
+
+/*
+ * call-seq:
+ *     MessageClass.decode(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+VALUE Message_decode(VALUE klass, VALUE data) {
+  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+  Descriptor* desc = ruby_to_Descriptor(descriptor);
+  VALUE msgklass = Descriptor_msgclass(descriptor);
+  VALUE msg_rb;
+  MessageHeader* msg;
+
+  if (TYPE(data) != T_STRING) {
+    rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
+  }
+
+  msg_rb = rb_class_new_instance(0, NULL, msgklass);
+  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+  {
+    const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
+    const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
+    stackenv se;
+    upb_sink sink;
+    upb_pbdecoder* decoder;
+    stackenv_init(&se, "Error occurred during parsing: %s");
+
+    upb_sink_reset(&sink, h, msg);
+    decoder = upb_pbdecoder_create(&se.env, method, &sink);
+    upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
+                      upb_pbdecoder_input(decoder));
+
+    stackenv_uninit(&se);
+  }
+
+  return msg_rb;
+}
+
+/*
+ * call-seq:
+ *     MessageClass.decode_json(data) => message
+ *
+ * Decodes the given data (as a string containing bytes in protocol buffers wire
+ * format) under the interpretration given by this message class's definition
+ * and returns a message object with the corresponding field values.
+ */
+VALUE Message_decode_json(VALUE klass, VALUE data) {
+  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+  Descriptor* desc = ruby_to_Descriptor(descriptor);
+  VALUE msgklass = Descriptor_msgclass(descriptor);
+  VALUE msg_rb;
+  MessageHeader* msg;
+
+  if (TYPE(data) != T_STRING) {
+    rb_raise(rb_eArgError, "Expected string for JSON data.");
+  }
+  // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
+  // convert, because string handlers pass data directly to message string
+  // fields.
+
+  msg_rb = rb_class_new_instance(0, NULL, msgklass);
+  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+  {
+    const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
+    stackenv se;
+    upb_sink sink;
+    upb_json_parser* parser;
+    stackenv_init(&se, "Error occurred during parsing: %s");
+
+    upb_sink_reset(&sink, get_fill_handlers(desc), msg);
+    parser = upb_json_parser_create(&se.env, method, &sink);
+    upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
+                      upb_json_parser_input(parser));
+
+    stackenv_uninit(&se);
+  }
+
+  return msg_rb;
+}
+
+// -----------------------------------------------------------------------------
+// Serializing.
+// -----------------------------------------------------------------------------
+//
+// The code below also comes from upb's prototype Ruby binding, developed by
+// haberman@.
+
+/* stringsink *****************************************************************/
+
+// This should probably be factored into a common upb component.
+
+typedef struct {
+  upb_byteshandler handler;
+  upb_bytessink sink;
+  char *ptr;
+  size_t len, size;
+} stringsink;
+
+static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
+  stringsink *sink = _sink;
+  sink->len = 0;
+  return sink;
+}
+
+static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
+                                size_t len, const upb_bufhandle *handle) {
+  stringsink *sink = _sink;
+  size_t new_size = sink->size;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  while (sink->len + len > new_size) {
+    new_size *= 2;
+  }
+
+  if (new_size != sink->size) {
+    sink->ptr = realloc(sink->ptr, new_size);
+    sink->size = new_size;
+  }
+
+  memcpy(sink->ptr + sink->len, ptr, len);
+  sink->len += len;
+
+  return len;
+}
+
+void stringsink_init(stringsink *sink) {
+  upb_byteshandler_init(&sink->handler);
+  upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
+  upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
+
+  upb_bytessink_reset(&sink->sink, &sink->handler, sink);
+
+  sink->size = 32;
+  sink->ptr = malloc(sink->size);
+  sink->len = 0;
+}
+
+void stringsink_uninit(stringsink *sink) {
+  free(sink->ptr);
+}
+
+/* msgvisitor *****************************************************************/
+
+// TODO: If/when we support proto2 semantics in addition to the current proto3
+// semantics, which means that we have true field presence, we will want to
+// modify msgvisitor so that it emits all present fields rather than all
+// non-default-value fields.
+//
+// Likewise, when implementing JSON serialization, we may need to have a
+// 'verbose' mode that outputs all fields and a 'concise' mode that outputs only
+// those with non-default values.
+
+static void putmsg(VALUE msg, const Descriptor* desc,
+                   upb_sink *sink, int depth);
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+  upb_selector_t ret;
+  bool ok = upb_handlers_getselector(f, type, &ret);
+  UPB_ASSERT_VAR(ok, ok);
+  return ret;
+}
+
+static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
+  upb_sink subsink;
+
+  if (str == Qnil) return;
+
+  assert(BUILTIN_TYPE(str) == RUBY_T_STRING);
+
+  // Ensure that the string has the correct encoding. We also check at field-set
+  // time, but the user may have mutated the string object since then.
+  native_slot_validate_string_encoding(upb_fielddef_type(f), str);
+
+  upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
+                    &subsink);
+  upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
+                     RSTRING_LEN(str), NULL);
+  upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
+                      int depth) {
+  upb_sink subsink;
+  VALUE descriptor;
+  Descriptor* subdesc;
+
+  if (submsg == Qnil) return;
+
+  descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
+  subdesc = ruby_to_Descriptor(descriptor);
+
+  upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
+  putmsg(submsg, subdesc, &subsink, depth + 1);
+  upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+}
+
+static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
+                   int depth) {
+  upb_sink subsink;
+  upb_fieldtype_t type = upb_fielddef_type(f);
+  upb_selector_t sel = 0;
+  int size;
+
+  if (ary == Qnil) return;
+
+  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+  if (upb_fielddef_isprimitive(f)) {
+    sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  }
+
+  size = NUM2INT(RepeatedField_length(ary));
+  for (int i = 0; i < size; i++) {
+    void* memory = RepeatedField_index_native(ary, i);
+    switch (type) {
+#define T(upbtypeconst, upbtype, ctype)                         \
+  case upbtypeconst:                                            \
+    upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory));   \
+    break;
+
+      T(UPB_TYPE_FLOAT,  float,  float)
+      T(UPB_TYPE_DOUBLE, double, double)
+      T(UPB_TYPE_BOOL,   bool,   int8_t)
+      case UPB_TYPE_ENUM:
+      T(UPB_TYPE_INT32,  int32,  int32_t)
+      T(UPB_TYPE_UINT32, uint32, uint32_t)
+      T(UPB_TYPE_INT64,  int64,  int64_t)
+      T(UPB_TYPE_UINT64, uint64, uint64_t)
+
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        putstr(*((VALUE *)memory), f, &subsink);
+        break;
+      case UPB_TYPE_MESSAGE:
+        putsubmsg(*((VALUE *)memory), f, &subsink, depth);
+        break;
+
+#undef T
+
+    }
+  }
+  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static void put_ruby_value(VALUE value,
+                           const upb_fielddef *f,
+                           VALUE type_class,
+                           int depth,
+                           upb_sink *sink) {
+  upb_selector_t sel = 0;
+  if (upb_fielddef_isprimitive(f)) {
+    sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  }
+
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32:
+      upb_sink_putint32(sink, sel, NUM2INT(value));
+      break;
+    case UPB_TYPE_INT64:
+      upb_sink_putint64(sink, sel, NUM2LL(value));
+      break;
+    case UPB_TYPE_UINT32:
+      upb_sink_putuint32(sink, sel, NUM2UINT(value));
+      break;
+    case UPB_TYPE_UINT64:
+      upb_sink_putuint64(sink, sel, NUM2ULL(value));
+      break;
+    case UPB_TYPE_FLOAT:
+      upb_sink_putfloat(sink, sel, NUM2DBL(value));
+      break;
+    case UPB_TYPE_DOUBLE:
+      upb_sink_putdouble(sink, sel, NUM2DBL(value));
+      break;
+    case UPB_TYPE_ENUM: {
+      if (TYPE(value) == T_SYMBOL) {
+        value = rb_funcall(type_class, rb_intern("resolve"), 1, value);
+      }
+      upb_sink_putint32(sink, sel, NUM2INT(value));
+      break;
+    }
+    case UPB_TYPE_BOOL:
+      upb_sink_putbool(sink, sel, value == Qtrue);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      putstr(value, f, sink);
+      break;
+    case UPB_TYPE_MESSAGE:
+      putsubmsg(value, f, sink, depth);
+  }
+}
+
+static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
+                   int depth) {
+  Map* self;
+  upb_sink subsink;
+  const upb_fielddef* key_field;
+  const upb_fielddef* value_field;
+  Map_iter it;
+
+  if (map == Qnil) return;
+  self = ruby_to_Map(map);
+
+  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+  assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE);
+  key_field = map_field_key(f);
+  value_field = map_field_value(f);
+
+  for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) {
+    VALUE key = Map_iter_key(&it);
+    VALUE value = Map_iter_value(&it);
+    upb_status status;
+
+    upb_sink entry_sink;
+    upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
+                         &entry_sink);
+    upb_sink_startmsg(&entry_sink);
+
+    put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink);
+    put_ruby_value(value, value_field, self->value_type_class, depth + 1,
+                   &entry_sink);
+
+    upb_sink_endmsg(&entry_sink, &status);
+    upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+  }
+
+  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static void putmsg(VALUE msg_rb, const Descriptor* desc,
+                   upb_sink *sink, int depth) {
+  MessageHeader* msg;
+  upb_msg_field_iter i;
+  upb_status status;
+
+  upb_sink_startmsg(sink);
+
+  // Protect against cycles (possible because users may freely reassign message
+  // and repeated fields) by imposing a maximum recursion depth.
+  if (depth > ENCODE_MAX_NESTING) {
+    rb_raise(rb_eRuntimeError,
+             "Maximum recursion depth exceeded during encoding.");
+  }
+
+  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
+
+  for (upb_msg_field_begin(&i, desc->msgdef);
+       !upb_msg_field_done(&i);
+       upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    bool is_matching_oneof = false;
+    uint32_t offset =
+        desc->layout->fields[upb_fielddef_index(f)].offset +
+        sizeof(MessageHeader);
+
+    if (upb_fielddef_containingoneof(f)) {
+      uint32_t oneof_case_offset =
+          desc->layout->fields[upb_fielddef_index(f)].case_offset +
+          sizeof(MessageHeader);
+      // For a oneof, check that this field is actually present -- skip all the
+      // below if not.
+      if (DEREF(msg, oneof_case_offset, uint32_t) !=
+          upb_fielddef_number(f)) {
+        continue;
+      }
+      // Otherwise, fall through to the appropriate singular-field handler
+      // below.
+      is_matching_oneof = true;
+    }
+
+    if (is_map_field(f)) {
+      VALUE map = DEREF(msg, offset, VALUE);
+      if (map != Qnil) {
+        putmap(map, f, sink, depth);
+      }
+    } else if (upb_fielddef_isseq(f)) {
+      VALUE ary = DEREF(msg, offset, VALUE);
+      if (ary != Qnil) {
+        putary(ary, f, sink, depth);
+      }
+    } else if (upb_fielddef_isstring(f)) {
+      VALUE str = DEREF(msg, offset, VALUE);
+      if (is_matching_oneof || RSTRING_LEN(str) > 0) {
+        putstr(str, f, sink);
+      }
+    } else if (upb_fielddef_issubmsg(f)) {
+      putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth);
+    } else {
+      upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+
+#define T(upbtypeconst, upbtype, ctype, default_value)                \
+  case upbtypeconst: {                                                \
+      ctype value = DEREF(msg, offset, ctype);                        \
+      if (is_matching_oneof || value != default_value) {              \
+        upb_sink_put##upbtype(sink, sel, value);                      \
+      }                                                               \
+    }                                                                 \
+    break;
+
+      switch (upb_fielddef_type(f)) {
+        T(UPB_TYPE_FLOAT,  float,  float, 0.0)
+        T(UPB_TYPE_DOUBLE, double, double, 0.0)
+        T(UPB_TYPE_BOOL,   bool,   uint8_t, 0)
+        case UPB_TYPE_ENUM:
+        T(UPB_TYPE_INT32,  int32,  int32_t, 0)
+        T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
+        T(UPB_TYPE_INT64,  int64,  int64_t, 0)
+        T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
+
+        case UPB_TYPE_STRING:
+        case UPB_TYPE_BYTES:
+        case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error.");
+      }
+
+#undef T
+
+    }
+  }
+
+  upb_sink_endmsg(sink, &status);
+}
+
+static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
+  if (desc->pb_serialize_handlers == NULL) {
+    desc->pb_serialize_handlers =
+        upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
+  }
+  return desc->pb_serialize_handlers;
+}
+
+static const upb_handlers* msgdef_json_serialize_handlers(
+    Descriptor* desc, bool preserve_proto_fieldnames) {
+  if (preserve_proto_fieldnames) {
+    if (desc->json_serialize_handlers == NULL) {
+      desc->json_serialize_handlers =
+          upb_json_printer_newhandlers(
+              desc->msgdef, true, &desc->json_serialize_handlers);
+    }
+    return desc->json_serialize_handlers;
+  } else {
+    if (desc->json_serialize_handlers_preserve == NULL) {
+      desc->json_serialize_handlers_preserve =
+          upb_json_printer_newhandlers(
+              desc->msgdef, false, &desc->json_serialize_handlers_preserve);
+    }
+    return desc->json_serialize_handlers_preserve;
+  }
+}
+
+/*
+ * call-seq:
+ *     MessageClass.encode(msg) => bytes
+ *
+ * Encodes the given message object to its serialized form in protocol buffers
+ * wire format.
+ */
+VALUE Message_encode(VALUE klass, VALUE msg_rb) {
+  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+  Descriptor* desc = ruby_to_Descriptor(descriptor);
+
+  stringsink sink;
+  stringsink_init(&sink);
+
+  {
+    const upb_handlers* serialize_handlers =
+        msgdef_pb_serialize_handlers(desc);
+
+    stackenv se;
+    upb_pb_encoder* encoder;
+    VALUE ret;
+
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
+
+    putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0);
+
+    ret = rb_str_new(sink.ptr, sink.len);
+
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+
+    return ret;
+  }
+}
+
+/*
+ * call-seq:
+ *     MessageClass.encode_json(msg) => json_string
+ *
+ * Encodes the given message object into its serialized JSON representation.
+ */
+VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
+  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+  Descriptor* desc = ruby_to_Descriptor(descriptor);
+  VALUE msg_rb;
+  VALUE preserve_proto_fieldnames = Qfalse;
+  stringsink sink;
+
+  if (argc < 1 || argc > 2) {
+    rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
+  }
+
+  msg_rb = argv[0];
+
+  if (argc == 2) {
+    VALUE hash_args = argv[1];
+    if (TYPE(hash_args) != T_HASH) {
+      rb_raise(rb_eArgError, "Expected hash arguments.");
+    }
+    preserve_proto_fieldnames = rb_hash_lookup2(
+        hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse);
+  }
+
+  stringsink_init(&sink);
+
+  {
+    const upb_handlers* serialize_handlers =
+        msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames));
+    upb_json_printer* printer;
+    stackenv se;
+    VALUE ret;
+
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
+
+    putmsg(msg_rb, desc, upb_json_printer_input(printer), 0);
+
+    ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding());
+
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+
+    return ret;
+  }
+}
+
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
new file mode 100644
index 0000000..b368dcc
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -0,0 +1,10 @@
+#!/usr/bin/ruby
+
+require 'mkmf'
+
+$CFLAGS += " -std=c99 -O3 -DNDEBUG"
+
+$objs = ["protobuf.o", "defs.o", "storage.o", "message.o",
+         "repeated_field.o", "map.o", "encode_decode.o", "upb.o"]
+
+create_makefile("google/protobuf_c")
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
new file mode 100644
index 0000000..92fc728
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -0,0 +1,808 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Basic map operations on top of upb's strtable.
+//
+// Note that we roll our own `Map` container here because, as for
+// `RepeatedField`, we want a strongly-typed container. This is so that any user
+// errors due to incorrect map key or value types are raised as close as
+// possible to the error site, rather than at some deferred point (e.g.,
+// serialization).
+//
+// We build our `Map` on top of upb_strtable so that we're able to take
+// advantage of the native_slot storage abstraction, as RepeatedField does.
+// (This is not quite a perfect mapping -- see the key conversions below -- but
+// gives us full support and error-checking for all value types for free.)
+// -----------------------------------------------------------------------------
+
+// Map values are stored using the native_slot abstraction (as with repeated
+// field values), but keys are a bit special. Since we use a strtable, we need
+// to store keys as sequences of bytes such that equality of those bytes maps
+// one-to-one to equality of keys. We store strings directly (i.e., they map to
+// their own bytes) and integers as native integers (using the native_slot
+// abstraction).
+
+// Note that there is another tradeoff here in keeping string keys as native
+// strings rather than Ruby strings: traversing the Map requires conversion to
+// Ruby string values on every traversal, potentially creating more garbage. We
+// should consider ways to cache a Ruby version of the key if this becomes an
+// issue later.
+
+// Forms a key to use with the underlying strtable from a Ruby key value. |buf|
+// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
+// construct a key byte sequence if needed. |out_key| and |out_length| provide
+// the resulting key data/length.
+#define TABLE_KEY_BUF_LENGTH 8  // sizeof(uint64_t)
+static void table_key(Map* self, VALUE key,
+                      char* buf,
+                      const char** out_key,
+                      size_t* out_length) {
+  switch (self->key_type) {
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_STRING:
+      // Strings: use string content directly.
+      Check_Type(key, T_STRING);
+      native_slot_validate_string_encoding(self->key_type, key);
+      *out_key = RSTRING_PTR(key);
+      *out_length = RSTRING_LEN(key);
+      break;
+
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      native_slot_set(self->key_type, Qnil, buf, key);
+      *out_key = buf;
+      *out_length = native_slot_size(self->key_type);
+      break;
+
+    default:
+      // Map constructor should not allow a Map with another key type to be
+      // constructed.
+      assert(false);
+      break;
+  }
+}
+
+static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
+  switch (self->key_type) {
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_STRING: {
+      VALUE ret = rb_str_new(buf, length);
+      rb_enc_associate(ret,
+                       (self->key_type == UPB_TYPE_BYTES) ?
+                       kRubyString8bitEncoding : kRubyStringUtf8Encoding);
+      return ret;
+    }
+
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      return native_slot_get(self->key_type, Qnil, buf);
+
+    default:
+      assert(false);
+      return Qnil;
+  }
+}
+
+static void* value_memory(upb_value* v) {
+  return (void*)(&v->val);
+}
+
+// -----------------------------------------------------------------------------
+// Map container type.
+// -----------------------------------------------------------------------------
+
+const rb_data_type_t Map_type = {
+  "Google::Protobuf::Map",
+  { Map_mark, Map_free, NULL },
+};
+
+VALUE cMap;
+
+Map* ruby_to_Map(VALUE _self) {
+  Map* self;
+  TypedData_Get_Struct(_self, Map, &Map_type, self);
+  return self;
+}
+
+void Map_mark(void* _self) {
+  Map* self = _self;
+
+  rb_gc_mark(self->value_type_class);
+
+  if (self->value_type == UPB_TYPE_STRING ||
+      self->value_type == UPB_TYPE_BYTES ||
+      self->value_type == UPB_TYPE_MESSAGE) {
+    upb_strtable_iter it;
+    for (upb_strtable_begin(&it, &self->table);
+         !upb_strtable_done(&it);
+         upb_strtable_next(&it)) {
+      upb_value v = upb_strtable_iter_value(&it);
+      void* mem = value_memory(&v);
+      native_slot_mark(self->value_type, mem);
+    }
+  }
+}
+
+void Map_free(void* _self) {
+  Map* self = _self;
+  upb_strtable_uninit(&self->table);
+  xfree(self);
+}
+
+VALUE Map_alloc(VALUE klass) {
+  Map* self = ALLOC(Map);
+  memset(self, 0, sizeof(Map));
+  self->value_type_class = Qnil;
+  return TypedData_Wrap_Struct(klass, &Map_type, self);
+}
+
+static bool needs_typeclass(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_MESSAGE:
+    case UPB_TYPE_ENUM:
+      return true;
+    default:
+      return false;
+  }
+}
+
+/*
+ * call-seq:
+ *     Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
+ *     => new map
+ *
+ * Allocates a new Map container. This constructor may be called with 2, 3, or 4
+ * arguments. The first two arguments are always present and are symbols (taking
+ * on the same values as field-type symbols in message descriptors) that
+ * indicate the type of the map key and value fields.
+ *
+ * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes.
+ *
+ * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
+ * :string, :bytes, :enum, :message.
+ *
+ * The third argument, value_typeclass, must be present if value_type is :enum
+ * or :message. As in RepeatedField#new, this argument must be a message class
+ * (for :message) or enum module (for :enum).
+ *
+ * The last argument, if present, provides initial content for map. Note that
+ * this may be an ordinary Ruby hashmap or another Map instance with identical
+ * key and value types. Also note that this argument may be present whether or
+ * not value_typeclass is present (and it is unambiguously separate from
+ * value_typeclass because value_typeclass's presence is strictly determined by
+ * value_type). The contents of this initial hashmap or Map instance are
+ * shallow-copied into the new Map: the original map is unmodified, but
+ * references to underlying objects will be shared if the value type is a
+ * message type.
+ */
+VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+  int init_value_arg;
+
+  // We take either two args (:key_type, :value_type), three args (:key_type,
+  // :value_type, "ValueMessageType"), or four args (the above plus an initial
+  // hashmap).
+  if (argc < 2 || argc > 4) {
+    rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments.");
+  }
+
+  self->key_type = ruby_to_fieldtype(argv[0]);
+  self->value_type = ruby_to_fieldtype(argv[1]);
+
+  // Check that the key type is an allowed type.
+  switch (self->key_type) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      // These are OK.
+      break;
+    default:
+      rb_raise(rb_eArgError, "Invalid key type for map.");
+  }
+
+  init_value_arg = 2;
+  if (needs_typeclass(self->value_type) && argc > 2) {
+    self->value_type_class = argv[2];
+    validate_type_class(self->value_type, self->value_type_class);
+    init_value_arg = 3;
+  }
+
+  // Table value type is always UINT64: this ensures enough space to store the
+  // native_slot value.
+  if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
+    rb_raise(rb_eRuntimeError, "Could not allocate table.");
+  }
+
+  if (argc > init_value_arg) {
+    Map_merge_into_self(_self, argv[init_value_arg]);
+  }
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Map.each(&block)
+ *
+ * Invokes &block on each |key, value| pair in the map, in unspecified order.
+ * Note that Map also includes Enumerable; map thus acts like a normal Ruby
+ * sequence.
+ */
+VALUE Map_each(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    VALUE key = table_key_to_ruby(
+        self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    VALUE value = native_slot_get(self->value_type,
+                                  self->value_type_class,
+                                  mem);
+
+    rb_yield_values(2, key, value);
+  }
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Map.keys => [list_of_keys]
+ *
+ * Returns the list of keys contained in the map, in unspecified order.
+ */
+VALUE Map_keys(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  VALUE ret = rb_ary_new();
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    VALUE key = table_key_to_ruby(
+        self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+    rb_ary_push(ret, key);
+  }
+
+  return ret;
+}
+
+/*
+ * call-seq:
+ *     Map.values => [list_of_values]
+ *
+ * Returns the list of values contained in the map, in unspecified order.
+ */
+VALUE Map_values(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  VALUE ret = rb_ary_new();
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    VALUE value = native_slot_get(self->value_type,
+                                  self->value_type_class,
+                                  mem);
+
+    rb_ary_push(ret, value);
+  }
+
+  return ret;
+}
+
+/*
+ * call-seq:
+ *     Map.[](key) => value
+ *
+ * Accesses the element at the given key. Throws an exception if the key type is
+ * incorrect. Returns nil when the key is not present in the map.
+ */
+VALUE Map_index(VALUE _self, VALUE key) {
+  Map* self = ruby_to_Map(_self);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+  table_key(self, key, keybuf, &keyval, &length);
+
+  if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
+    void* mem = value_memory(&v);
+    return native_slot_get(self->value_type, self->value_type_class, mem);
+  } else {
+    return Qnil;
+  }
+}
+
+/*
+ * call-seq:
+ *     Map.[]=(key, value) => value
+ *
+ * Inserts or overwrites the value at the given key with the given new value.
+ * Throws an exception if the key type is incorrect. Returns the new value that
+ * was just inserted.
+ */
+VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
+  Map* self = ruby_to_Map(_self);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+  void* mem;
+  table_key(self, key, keybuf, &keyval, &length);
+
+  mem = value_memory(&v);
+  native_slot_set(self->value_type, self->value_type_class, mem, value);
+
+  // Replace any existing value by issuing a 'remove' operation first.
+  upb_strtable_remove2(&self->table, keyval, length, NULL);
+  if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
+    rb_raise(rb_eRuntimeError, "Could not insert into table");
+  }
+
+  // Ruby hashmap's :[]= method also returns the inserted value.
+  return value;
+}
+
+/*
+ * call-seq:
+ *     Map.has_key?(key) => bool
+ *
+ * Returns true if the given key is present in the map. Throws an exception if
+ * the key has the wrong type.
+ */
+VALUE Map_has_key(VALUE _self, VALUE key) {
+  Map* self = ruby_to_Map(_self);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  table_key(self, key, keybuf, &keyval, &length);
+
+  if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
+    return Qtrue;
+  } else {
+    return Qfalse;
+  }
+}
+
+/*
+ * call-seq:
+ *     Map.delete(key) => old_value
+ *
+ * Deletes the value at the given key, if any, returning either the old value or
+ * nil if none was present. Throws an exception if the key is of the wrong type.
+ */
+VALUE Map_delete(VALUE _self, VALUE key) {
+  Map* self = ruby_to_Map(_self);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+  table_key(self, key, keybuf, &keyval, &length);
+
+  if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
+    void* mem = value_memory(&v);
+    return native_slot_get(self->value_type, self->value_type_class, mem);
+  } else {
+    return Qnil;
+  }
+}
+
+/*
+ * call-seq:
+ *     Map.clear
+ *
+ * Removes all entries from the map.
+ */
+VALUE Map_clear(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  // Uninit and reinit the table -- this is faster than iterating and doing a
+  // delete-lookup on each key.
+  upb_strtable_uninit(&self->table);
+  if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
+    rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Map.length
+ *
+ * Returns the number of entries (key-value pairs) in the map.
+ */
+VALUE Map_length(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+  return ULL2NUM(upb_strtable_count(&self->table));
+}
+
+static VALUE Map_new_this_type(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+  VALUE new_map = Qnil;
+  VALUE key_type = fieldtype_to_ruby(self->key_type);
+  VALUE value_type = fieldtype_to_ruby(self->value_type);
+  if (self->value_type_class != Qnil) {
+    new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
+                         key_type, value_type, self->value_type_class);
+  } else {
+    new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
+                         key_type, value_type);
+  }
+  return new_map;
+}
+
+/*
+ * call-seq:
+ *     Map.dup => new_map
+ *
+ * Duplicates this map with a shallow copy. References to all non-primitive
+ * element objects (e.g., submessages) are shared.
+ */
+VALUE Map_dup(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+  VALUE new_map = Map_new_this_type(_self);
+  Map* new_self = ruby_to_Map(new_map);
+
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    upb_value dup;
+    void* dup_mem = value_memory(&dup);
+    native_slot_dup(self->value_type, dup_mem, mem);
+
+    if (!upb_strtable_insert2(&new_self->table,
+                              upb_strtable_iter_key(&it),
+                              upb_strtable_iter_keylength(&it),
+                              dup)) {
+      rb_raise(rb_eRuntimeError, "Error inserting value into new table");
+    }
+  }
+
+  return new_map;
+}
+
+// Used by Google::Protobuf.deep_copy but not exposed directly.
+VALUE Map_deep_copy(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+  VALUE new_map = Map_new_this_type(_self);
+  Map* new_self = ruby_to_Map(new_map);
+
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    upb_value dup;
+    void* dup_mem = value_memory(&dup);
+    native_slot_deep_copy(self->value_type, dup_mem, mem);
+
+    if (!upb_strtable_insert2(&new_self->table,
+                              upb_strtable_iter_key(&it),
+                              upb_strtable_iter_keylength(&it),
+                              dup)) {
+      rb_raise(rb_eRuntimeError, "Error inserting value into new table");
+    }
+  }
+
+  return new_map;
+}
+
+/*
+ * call-seq:
+ *     Map.==(other) => boolean
+ *
+ * Compares this map to another. Maps are equal if they have identical key sets,
+ * and for each key, the values in both maps compare equal. Elements are
+ * compared as per normal Ruby semantics, by calling their :== methods (or
+ * performing a more efficient comparison for primitive types).
+ *
+ * Maps with dissimilar key types or value types/typeclasses are never equal,
+ * even if value comparison (for example, between integers and floats) would
+ * have otherwise indicated that every element has equal value.
+ */
+VALUE Map_eq(VALUE _self, VALUE _other) {
+  Map* self = ruby_to_Map(_self);
+  Map* other;
+  upb_strtable_iter it;
+
+  // Allow comparisons to Ruby hashmaps by converting to a temporary Map
+  // instance. Slow, but workable.
+  if (TYPE(_other) == T_HASH) {
+    VALUE other_map = Map_new_this_type(_self);
+    Map_merge_into_self(other_map, _other);
+    _other = other_map;
+  }
+
+  other = ruby_to_Map(_other);
+
+  if (self == other) {
+    return Qtrue;
+  }
+  if (self->key_type != other->key_type ||
+      self->value_type != other->value_type ||
+      self->value_type_class != other->value_type_class) {
+    return Qfalse;
+  }
+  if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
+    return Qfalse;
+  }
+
+  // For each member of self, check that an equal member exists at the same key
+  // in other.
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    upb_value other_v;
+    void* other_mem = value_memory(&other_v);
+
+    if (!upb_strtable_lookup2(&other->table,
+                              upb_strtable_iter_key(&it),
+                              upb_strtable_iter_keylength(&it),
+                              &other_v)) {
+      // Not present in other map.
+      return Qfalse;
+    }
+
+    if (!native_slot_eq(self->value_type, mem, other_mem)) {
+      // Present, but value not equal.
+      return Qfalse;
+    }
+  }
+
+  return Qtrue;
+}
+
+/*
+ * call-seq:
+ *     Map.hash => hash_value
+ *
+ * Returns a hash value based on this map's contents.
+ */
+VALUE Map_hash(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  st_index_t h = rb_hash_start(0);
+  VALUE hash_sym = rb_intern("hash");
+
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+    VALUE key = table_key_to_ruby(
+        self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    VALUE value = native_slot_get(self->value_type,
+                                  self->value_type_class,
+                                  mem);
+
+    h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
+    h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
+  }
+
+  return INT2FIX(h);
+}
+
+/*
+ * call-seq:
+ *     Map.inspect => string
+ *
+ * Returns a string representing this map's elements. It will be formatted as
+ * "{key => value, key => value, ...}", with each key and value string
+ * representation computed by its own #inspect method.
+ */
+VALUE Map_inspect(VALUE _self) {
+  Map* self = ruby_to_Map(_self);
+
+  VALUE str = rb_str_new2("{");
+
+  bool first = true;
+  VALUE inspect_sym = rb_intern("inspect");
+
+  upb_strtable_iter it;
+  for (upb_strtable_begin(&it, &self->table);
+       !upb_strtable_done(&it);
+       upb_strtable_next(&it)) {
+    VALUE key = table_key_to_ruby(
+        self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
+
+    upb_value v = upb_strtable_iter_value(&it);
+    void* mem = value_memory(&v);
+    VALUE value = native_slot_get(self->value_type,
+                                  self->value_type_class,
+                                  mem);
+
+    if (!first) {
+      str = rb_str_cat2(str, ", ");
+    } else {
+      first = false;
+    }
+    str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
+    str = rb_str_cat2(str, "=>");
+    str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
+  }
+
+  str = rb_str_cat2(str, "}");
+  return str;
+}
+
+/*
+ * call-seq:
+ *     Map.merge(other_map) => map
+ *
+ * Copies key/value pairs from other_map into a copy of this map. If a key is
+ * set in other_map and this map, the value from other_map overwrites the value
+ * in the new copy of this map. Returns the new copy of this map with merged
+ * contents.
+ */
+VALUE Map_merge(VALUE _self, VALUE hashmap) {
+  VALUE dupped = Map_dup(_self);
+  return Map_merge_into_self(dupped, hashmap);
+}
+
+static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
+  Map_index_set(self, key, value);
+  return ST_CONTINUE;
+}
+
+// Used only internally -- shared by #merge and #initialize.
+VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
+  if (TYPE(hashmap) == T_HASH) {
+    rb_hash_foreach(hashmap, merge_into_self_callback, _self);
+  } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
+             RTYPEDDATA_TYPE(hashmap) == &Map_type) {
+
+    Map* self = ruby_to_Map(_self);
+    Map* other = ruby_to_Map(hashmap);
+    upb_strtable_iter it;
+
+    if (self->key_type != other->key_type ||
+        self->value_type != other->value_type ||
+        self->value_type_class != other->value_type_class) {
+      rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
+    }
+
+    for (upb_strtable_begin(&it, &other->table);
+         !upb_strtable_done(&it);
+         upb_strtable_next(&it)) {
+
+      // Replace any existing value by issuing a 'remove' operation first.
+      upb_value v;
+      upb_value oldv;
+      upb_strtable_remove2(&self->table,
+                           upb_strtable_iter_key(&it),
+                           upb_strtable_iter_keylength(&it),
+                           &oldv);
+
+      v = upb_strtable_iter_value(&it);
+      upb_strtable_insert2(&self->table,
+                           upb_strtable_iter_key(&it),
+                           upb_strtable_iter_keylength(&it),
+                           v);
+    }
+  } else {
+    rb_raise(rb_eArgError, "Unknown type merging into Map");
+  }
+  return _self;
+}
+
+// Internal method: map iterator initialization (used for serialization).
+void Map_begin(VALUE _self, Map_iter* iter) {
+  Map* self = ruby_to_Map(_self);
+  iter->self = self;
+  upb_strtable_begin(&iter->it, &self->table);
+}
+
+void Map_next(Map_iter* iter) {
+  upb_strtable_next(&iter->it);
+}
+
+bool Map_done(Map_iter* iter) {
+  return upb_strtable_done(&iter->it);
+}
+
+VALUE Map_iter_key(Map_iter* iter) {
+  return table_key_to_ruby(
+      iter->self,
+      upb_strtable_iter_key(&iter->it),
+      upb_strtable_iter_keylength(&iter->it));
+}
+
+VALUE Map_iter_value(Map_iter* iter) {
+  upb_value v = upb_strtable_iter_value(&iter->it);
+  void* mem = value_memory(&v);
+  return native_slot_get(iter->self->value_type,
+                         iter->self->value_type_class,
+                         mem);
+}
+
+void Map_register(VALUE module) {
+  VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
+  rb_define_alloc_func(klass, Map_alloc);
+  cMap = klass;
+  rb_gc_register_address(&cMap);
+
+  rb_define_method(klass, "initialize", Map_init, -1);
+  rb_define_method(klass, "each", Map_each, 0);
+  rb_define_method(klass, "keys", Map_keys, 0);
+  rb_define_method(klass, "values", Map_values, 0);
+  rb_define_method(klass, "[]", Map_index, 1);
+  rb_define_method(klass, "[]=", Map_index_set, 2);
+  rb_define_method(klass, "has_key?", Map_has_key, 1);
+  rb_define_method(klass, "delete", Map_delete, 1);
+  rb_define_method(klass, "clear", Map_clear, 0);
+  rb_define_method(klass, "length", Map_length, 0);
+  rb_define_method(klass, "dup", Map_dup, 0);
+  rb_define_method(klass, "==", Map_eq, 1);
+  rb_define_method(klass, "hash", Map_hash, 0);
+  rb_define_method(klass, "inspect", Map_inspect, 0);
+  rb_define_method(klass, "merge", Map_merge, 1);
+  rb_include_module(klass, rb_mEnumerable);
+}
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
new file mode 100644
index 0000000..e16250f
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -0,0 +1,578 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Class/module creation from msgdefs and enumdefs, respectively.
+// -----------------------------------------------------------------------------
+
+void* Message_data(void* msg) {
+  return ((uint8_t *)msg) + sizeof(MessageHeader);
+}
+
+void Message_mark(void* _self) {
+  MessageHeader* self = (MessageHeader *)_self;
+  layout_mark(self->descriptor->layout, Message_data(self));
+}
+
+void Message_free(void* self) {
+  xfree(self);
+}
+
+rb_data_type_t Message_type = {
+  "Message",
+  { Message_mark, Message_free, NULL },
+};
+
+VALUE Message_alloc(VALUE klass) {
+  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
+  Descriptor* desc = ruby_to_Descriptor(descriptor);
+  MessageHeader* msg = (MessageHeader*)ALLOC_N(
+      uint8_t, sizeof(MessageHeader) + desc->layout->size);
+  VALUE ret;
+
+  memset(Message_data(msg), 0, desc->layout->size);
+
+  // We wrap first so that everything in the message object is GC-rooted in case
+  // a collection happens during object creation in layout_init().
+  ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
+  msg->descriptor = desc;
+  rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
+
+  layout_init(desc->layout, Message_data(msg));
+
+  return ret;
+}
+
+static VALUE which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
+  upb_oneof_iter it;
+  size_t case_ofs;
+  uint32_t oneof_case;
+  const upb_fielddef* first_field;
+  const upb_fielddef* f;
+
+  // If no fields in the oneof, always nil.
+  if (upb_oneofdef_numfields(o) == 0) {
+    return Qnil;
+  }
+  // Grab the first field in the oneof so we can get its layout info to find the
+  // oneof_case field.
+  upb_oneof_begin(&it, o);
+  assert(!upb_oneof_done(&it));
+  first_field = upb_oneof_iter_field(&it);
+  assert(upb_fielddef_containingoneof(first_field) != NULL);
+
+  case_ofs =
+      self->descriptor->layout->
+      fields[upb_fielddef_index(first_field)].case_offset;
+  oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
+
+  if (oneof_case == ONEOF_CASE_NONE) {
+    return Qnil;
+  }
+
+  // oneof_case is a field index, so find that field.
+  f = upb_oneofdef_itof(o, oneof_case);
+  assert(f != NULL);
+
+  return ID2SYM(rb_intern(upb_fielddef_name(f)));
+}
+
+/*
+ * call-seq:
+ *     Message.method_missing(*args)
+ *
+ * Provides accessors and setters for message fields according to their field
+ * names. For any field whose name does not conflict with a built-in method, an
+ * accessor is provided with the same name as the field, and a setter is
+ * provided with the name of the field plus the '=' suffix. Thus, given a
+ * message instance 'msg' with field 'foo', the following code is valid:
+ *
+ *     msg.foo = 42
+ *     puts msg.foo
+ *
+ * This method also provides read-only accessors for oneofs. If a oneof exists
+ * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to
+ * the name of the field in that oneof that is currently set, or nil if none.
+ */
+VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
+  MessageHeader* self;
+  VALUE method_name, method_str;
+  char* name;
+  size_t name_len;
+  bool setter;
+  const upb_oneofdef* o;
+  const upb_fielddef* f;
+
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+  if (argc < 1) {
+    rb_raise(rb_eArgError, "Expected method name as first argument.");
+  }
+  method_name = argv[0];
+  if (!SYMBOL_P(method_name)) {
+    rb_raise(rb_eArgError, "Expected symbol as method name.");
+  }
+  method_str = rb_id2str(SYM2ID(method_name));
+  name = RSTRING_PTR(method_str);
+  name_len = RSTRING_LEN(method_str);
+  setter = false;
+
+  // Setters have names that end in '='.
+  if (name[name_len - 1] == '=') {
+    setter = true;
+    name_len--;
+  }
+
+  // See if this name corresponds to either a oneof or field in this message.
+  if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
+                             &o)) {
+    return rb_call_super(argc, argv);
+  }
+
+  if (o != NULL) {
+    // This is a oneof -- return which field inside the oneof is set.
+    if (setter) {
+      rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
+    }
+    return which_oneof_field(self, o);
+  } else {
+    // This is a field -- get or set the field's value.
+    assert(f);
+    if (setter) {
+      if (argc < 2) {
+        rb_raise(rb_eArgError, "No value provided to setter.");
+      }
+      layout_set(self->descriptor->layout, Message_data(self), f, argv[1]);
+      return Qnil;
+    } else {
+      return layout_get(self->descriptor->layout, Message_data(self), f);
+    }
+  }
+}
+
+int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
+  MessageHeader* self;
+  VALUE method_str;
+  char* name;
+  const upb_fielddef* f;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  if (!SYMBOL_P(key)) {
+    rb_raise(rb_eArgError,
+             "Expected symbols as hash keys in initialization map.");
+  }
+
+  method_str = rb_id2str(SYM2ID(key));
+  name = RSTRING_PTR(method_str);
+  f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
+  if (f == NULL) {
+    rb_raise(rb_eArgError,
+             "Unknown field name '%s' in initialization map entry.", name);
+  }
+
+  if (is_map_field(f)) {
+    VALUE map;
+
+    if (TYPE(val) != T_HASH) {
+      rb_raise(rb_eArgError,
+               "Expected Hash object as initializer value for map field '%s'.", name);
+    }
+    map = layout_get(self->descriptor->layout, Message_data(self), f);
+    Map_merge_into_self(map, val);
+  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
+    VALUE ary;
+
+    if (TYPE(val) != T_ARRAY) {
+      rb_raise(rb_eArgError,
+               "Expected array as initializer value for repeated field '%s'.", name);
+    }
+    ary = layout_get(self->descriptor->layout, Message_data(self), f);
+    for (int i = 0; i < RARRAY_LEN(val); i++) {
+      RepeatedField_push(ary, rb_ary_entry(val, i));
+    }
+  } else {
+    layout_set(self->descriptor->layout, Message_data(self), f, val);
+  }
+  return 0;
+}
+
+/*
+ * call-seq:
+ *     Message.new(kwargs) => new_message
+ *
+ * Creates a new instance of the given message class. Keyword arguments may be
+ * provided with keywords corresponding to field names.
+ *
+ * Note that no literal Message class exists. Only concrete classes per message
+ * type exist, as provided by the #msgclass method on Descriptors after they
+ * have been added to a pool. The method definitions described here on the
+ * Message class are provided on each concrete message class.
+ */
+VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
+  VALUE hash_args;
+
+  if (argc == 0) {
+    return Qnil;
+  }
+  if (argc != 1) {
+    rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
+  }
+  hash_args = argv[0];
+  if (TYPE(hash_args) != T_HASH) {
+    rb_raise(rb_eArgError, "Expected hash arguments.");
+  }
+
+  rb_hash_foreach(hash_args, Message_initialize_kwarg, _self);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Message.dup => new_message
+ *
+ * Performs a shallow copy of this message and returns the new copy.
+ */
+VALUE Message_dup(VALUE _self) {
+  MessageHeader* self;
+  VALUE new_msg;
+  MessageHeader* new_msg_self;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
+  TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
+
+  layout_dup(self->descriptor->layout,
+             Message_data(new_msg_self),
+             Message_data(self));
+
+  return new_msg;
+}
+
+// Internal only; used by Google::Protobuf.deep_copy.
+VALUE Message_deep_copy(VALUE _self) {
+  MessageHeader* self;
+  MessageHeader* new_msg_self;
+  VALUE new_msg;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
+  TypedData_Get_Struct(new_msg, MessageHeader, &Message_type, new_msg_self);
+
+  layout_deep_copy(self->descriptor->layout,
+                   Message_data(new_msg_self),
+                   Message_data(self));
+
+  return new_msg;
+}
+
+/*
+ * call-seq:
+ *     Message.==(other) => boolean
+ *
+ * Performs a deep comparison of this message with another. Messages are equal
+ * if they have the same type and if each field is equal according to the :==
+ * method's semantics (a more efficient comparison may actually be done if the
+ * field is of a primitive type).
+ */
+VALUE Message_eq(VALUE _self, VALUE _other) {
+  MessageHeader* self;
+  MessageHeader* other;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+  TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
+
+  if (self->descriptor != other->descriptor) {
+    return Qfalse;
+  }
+
+  return layout_eq(self->descriptor->layout,
+                   Message_data(self),
+                   Message_data(other));
+}
+
+/*
+ * call-seq:
+ *     Message.hash => hash_value
+ *
+ * Returns a hash value that represents this message's field values.
+ */
+VALUE Message_hash(VALUE _self) {
+  MessageHeader* self;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  return layout_hash(self->descriptor->layout, Message_data(self));
+}
+
+/*
+ * call-seq:
+ *     Message.inspect => string
+ *
+ * Returns a human-readable string representing this message. It will be
+ * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
+ * field's value is represented according to its own #inspect method.
+ */
+VALUE Message_inspect(VALUE _self) {
+  MessageHeader* self;
+  VALUE str;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  str = rb_str_new2("<");
+  str = rb_str_append(str, rb_str_new2(rb_class2name(CLASS_OF(_self))));
+  str = rb_str_cat2(str, ": ");
+  str = rb_str_append(str, layout_inspect(
+      self->descriptor->layout, Message_data(self)));
+  str = rb_str_cat2(str, ">");
+  return str;
+}
+
+
+VALUE Message_to_h(VALUE _self) {
+  MessageHeader* self;
+  VALUE hash;
+  upb_msg_field_iter it;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+
+  hash = rb_hash_new();
+
+  for (upb_msg_field_begin(&it, self->descriptor->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
+                                 field);
+    VALUE msg_key   = ID2SYM(rb_intern(upb_fielddef_name(field)));
+    if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      msg_value = RepeatedField_to_ary(msg_value);
+    }
+    rb_hash_aset(hash, msg_key, msg_value);
+  }
+  return hash;
+}
+
+
+
+/*
+ * call-seq:
+ *     Message.[](index) => value
+ *
+ * Accesses a field's value by field name. The provided field name should be a
+ * string.
+ */
+VALUE Message_index(VALUE _self, VALUE field_name) {
+  MessageHeader* self;
+  const upb_fielddef* field;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+  Check_Type(field_name, T_STRING);
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+  if (field == NULL) {
+    return Qnil;
+  }
+  return layout_get(self->descriptor->layout, Message_data(self), field);
+}
+
+/*
+ * call-seq:
+ *     Message.[]=(index, value)
+ *
+ * Sets a field's value by field name. The provided field name should be a
+ * string.
+ */
+VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
+  MessageHeader* self;
+  const upb_fielddef* field;
+  TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+  Check_Type(field_name, T_STRING);
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, RSTRING_PTR(field_name));
+  if (field == NULL) {
+    rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
+  }
+  layout_set(self->descriptor->layout, Message_data(self), field, value);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *     Message.descriptor => descriptor
+ *
+ * Class method that returns the Descriptor instance corresponding to this
+ * message class's type.
+ */
+VALUE Message_descriptor(VALUE klass) {
+  return rb_ivar_get(klass, descriptor_instancevar_interned);
+}
+
+VALUE build_class_from_descriptor(Descriptor* desc) {
+  const char *name;
+  VALUE klass;
+
+  if (desc->layout == NULL) {
+    desc->layout = create_layout(desc->msgdef);
+  }
+  if (desc->fill_method == NULL) {
+    desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method);
+  }
+
+  name = upb_msgdef_fullname(desc->msgdef);
+  if (name == NULL) {
+    rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
+  }
+
+  klass = rb_define_class_id(
+      // Docs say this parameter is ignored. User will assign return value to
+      // their own toplevel constant class name.
+      rb_intern("Message"),
+      rb_cObject);
+  rb_ivar_set(klass, descriptor_instancevar_interned,
+              get_def_obj(desc->msgdef));
+  rb_define_alloc_func(klass, Message_alloc);
+  rb_require("google/protobuf/message_exts");
+  rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
+  rb_extend_object(
+      klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
+
+  rb_define_method(klass, "method_missing",
+                   Message_method_missing, -1);
+  rb_define_method(klass, "initialize", Message_initialize, -1);
+  rb_define_method(klass, "dup", Message_dup, 0);
+  // Also define #clone so that we don't inherit Object#clone.
+  rb_define_method(klass, "clone", Message_dup, 0);
+  rb_define_method(klass, "==", Message_eq, 1);
+  rb_define_method(klass, "hash", Message_hash, 0);
+  rb_define_method(klass, "to_h", Message_to_h, 0);
+  rb_define_method(klass, "to_hash", Message_to_h, 0);
+  rb_define_method(klass, "inspect", Message_inspect, 0);
+  rb_define_method(klass, "[]", Message_index, 1);
+  rb_define_method(klass, "[]=", Message_index_set, 2);
+  rb_define_singleton_method(klass, "decode", Message_decode, 1);
+  rb_define_singleton_method(klass, "encode", Message_encode, 1);
+  rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1);
+  rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1);
+  rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0);
+
+  return klass;
+}
+
+/*
+ * call-seq:
+ *     Enum.lookup(number) => name
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by number and returns its name as a Ruby symbol, or nil if not found.
+ */
+VALUE enum_lookup(VALUE self, VALUE number) {
+  int32_t num = NUM2INT(number);
+  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
+  EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+
+  const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
+  if (name == NULL) {
+    return Qnil;
+  } else {
+    return ID2SYM(rb_intern(name));
+  }
+}
+
+/*
+ * call-seq:
+ *     Enum.resolve(name) => number
+ *
+ * This module method, provided on each generated enum module, looks up an enum
+ * value by name (as a Ruby symbol) and returns its name, or nil if not found.
+ */
+VALUE enum_resolve(VALUE self, VALUE sym) {
+  const char* name = rb_id2name(SYM2ID(sym));
+  VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
+  EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
+
+  int32_t num = 0;
+  bool found = upb_enumdef_ntoiz(enumdesc->enumdef, name, &num);
+  if (!found) {
+    return Qnil;
+  } else {
+    return INT2NUM(num);
+  }
+}
+
+/*
+ * call-seq:
+ *     Enum.descriptor
+ *
+ * This module method, provided on each generated enum module, returns the
+ * EnumDescriptor corresponding to this enum type.
+ */
+VALUE enum_descriptor(VALUE self) {
+  return rb_ivar_get(self, descriptor_instancevar_interned);
+}
+
+VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
+  VALUE mod = rb_define_module_id(
+      rb_intern(upb_enumdef_fullname(enumdesc->enumdef)));
+
+  upb_enum_iter it;
+  for (upb_enum_begin(&it, enumdesc->enumdef);
+       !upb_enum_done(&it);
+       upb_enum_next(&it)) {
+    const char* name = upb_enum_iter_name(&it);
+    int32_t value = upb_enum_iter_number(&it);
+    if (name[0] < 'A' || name[0] > 'Z') {
+      rb_raise(rb_eTypeError,
+               "Enum value '%s' does not start with an uppercase letter "
+               "as is required for Ruby constants.",
+               name);
+    }
+    rb_define_const(mod, name, INT2NUM(value));
+  }
+
+  rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
+  rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
+  rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
+  rb_ivar_set(mod, descriptor_instancevar_interned,
+              get_def_obj(enumdesc->enumdef));
+
+  return mod;
+}
+
+/*
+ * call-seq:
+ *     Google::Protobuf.deep_copy(obj) => copy_of_obj
+ *
+ * Performs a deep copy of a RepeatedField instance, a Map instance, or a
+ * message object, recursively copying its members.
+ */
+VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
+  VALUE klass = CLASS_OF(obj);
+  if (klass == cRepeatedField) {
+    return RepeatedField_deep_copy(obj);
+  } else if (klass == cMap) {
+    return Map_deep_copy(obj);
+  } else {
+    return Message_deep_copy(obj);
+  }
+}
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
new file mode 100644
index 0000000..7cde4ae
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -0,0 +1,115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+
+// This is a hash table from def objects (encoded by converting pointers to
+// Ruby integers) to MessageDef/EnumDef instances (as Ruby values).
+VALUE upb_def_to_ruby_obj_map;
+
+VALUE cError;
+VALUE cParseError;
+
+void add_def_obj(const void* def, VALUE value) {
+  rb_hash_aset(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def), value);
+}
+
+VALUE get_def_obj(const void* def) {
+  return rb_hash_aref(upb_def_to_ruby_obj_map, ULL2NUM((intptr_t)def));
+}
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+// Raises a Ruby error if |status| is not OK, using its error message.
+void check_upb_status(const upb_status* status, const char* msg) {
+  if (!upb_ok(status)) {
+    rb_raise(rb_eRuntimeError, "%s: %s\n", msg, upb_status_errmsg(status));
+  }
+}
+
+// String encodings: we look these up once, at load time, and then cache them
+// here.
+rb_encoding* kRubyStringUtf8Encoding;
+rb_encoding* kRubyStringASCIIEncoding;
+rb_encoding* kRubyString8bitEncoding;
+
+// Ruby-interned string: "descriptor". We use this identifier to store an
+// instance variable on message classes we create in order to link them back to
+// their descriptors.
+//
+// We intern this once at module load time then use the interned identifier at
+// runtime in order to avoid the cost of repeatedly interning in hot paths.
+const char* kDescriptorInstanceVar = "descriptor";
+ID descriptor_instancevar_interned;
+
+// -----------------------------------------------------------------------------
+// Initialization/entry point.
+// -----------------------------------------------------------------------------
+
+// This must be named "Init_protobuf_c" because the Ruby module is named
+// "protobuf_c" -- the VM looks for this symbol in our .so.
+void Init_protobuf_c() {
+  VALUE google = rb_define_module("Google");
+  VALUE protobuf = rb_define_module_under(google, "Protobuf");
+  VALUE internal = rb_define_module_under(protobuf, "Internal");
+
+  descriptor_instancevar_interned = rb_intern(kDescriptorInstanceVar);
+  DescriptorPool_register(protobuf);
+  Descriptor_register(protobuf);
+  FieldDescriptor_register(protobuf);
+  OneofDescriptor_register(protobuf);
+  EnumDescriptor_register(protobuf);
+  MessageBuilderContext_register(internal);
+  OneofBuilderContext_register(internal);
+  EnumBuilderContext_register(internal);
+  Builder_register(internal);
+  RepeatedField_register(protobuf);
+  Map_register(protobuf);
+
+  cError = rb_const_get(protobuf, rb_intern("Error"));
+  cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
+
+  rb_define_singleton_method(protobuf, "deep_copy",
+                             Google_Protobuf_deep_copy, 1);
+
+  kRubyStringUtf8Encoding = rb_utf8_encoding();
+  kRubyStringASCIIEncoding = rb_usascii_encoding();
+  kRubyString8bitEncoding = rb_ascii8bit_encoding();
+
+  upb_def_to_ruby_obj_map = rb_hash_new();
+  rb_gc_register_address(&upb_def_to_ruby_obj_map);
+}
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
new file mode 100644
index 0000000..2834c89
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -0,0 +1,538 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
+#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
+
+#include <ruby/ruby.h>
+#include <ruby/vm.h>
+#include <ruby/encoding.h>
+
+#include "upb.h"
+
+// Forward decls.
+struct DescriptorPool;
+struct Descriptor;
+struct FieldDescriptor;
+struct EnumDescriptor;
+struct MessageLayout;
+struct MessageField;
+struct MessageHeader;
+struct MessageBuilderContext;
+struct EnumBuilderContext;
+struct Builder;
+
+typedef struct DescriptorPool DescriptorPool;
+typedef struct Descriptor Descriptor;
+typedef struct FieldDescriptor FieldDescriptor;
+typedef struct OneofDescriptor OneofDescriptor;
+typedef struct EnumDescriptor EnumDescriptor;
+typedef struct MessageLayout MessageLayout;
+typedef struct MessageField MessageField;
+typedef struct MessageHeader MessageHeader;
+typedef struct MessageBuilderContext MessageBuilderContext;
+typedef struct OneofBuilderContext OneofBuilderContext;
+typedef struct EnumBuilderContext EnumBuilderContext;
+typedef struct Builder Builder;
+
+/*
+ It can be a bit confusing how the C structs defined below and the Ruby
+ objects interact and hold references to each other. First, a few principles:
+
+ - Ruby's "TypedData" abstraction lets a Ruby VALUE hold a pointer to a C
+   struct (or arbitrary memory chunk), own it, and free it when collected.
+   Thus, each struct below will have a corresponding Ruby object
+   wrapping/owning it.
+
+ - To get back from an underlying upb {msg,enum}def to the Ruby object, we
+   keep a global hashmap, accessed by get_def_obj/add_def_obj below.
+
+ The in-memory structure is then something like:
+
+   Ruby                        |      upb
+                               |
+   DescriptorPool  ------------|-----------> upb_symtab____________________
+                               |                | (message types)          \
+                               |                v                           \
+   Descriptor   ---------------|-----------> upb_msgdef         (enum types)|
+    |--> msgclass              |                |   ^                       |
+    |    (dynamically built)   |                |   | (submsg fields)       |
+    |--> MessageLayout         |                |   |                       /
+    |--------------------------|> decoder method|   |                      /
+    \--------------------------|> serialize     |   |                     /
+                               |  handlers      v   |                    /
+   FieldDescriptor  -----------|-----------> upb_fielddef               /
+                               |                    |                  /
+                               |                    v (enum fields)   /
+   EnumDescriptor  ------------|-----------> upb_enumdef  <----------'
+                               |
+                               |
+               ^               |               \___/
+               `---------------|-----------------'    (get_def_obj map)
+ */
+
+// -----------------------------------------------------------------------------
+// Ruby class structure definitions.
+// -----------------------------------------------------------------------------
+
+struct DescriptorPool {
+  upb_symtab* symtab;
+};
+
+struct Descriptor {
+  const upb_msgdef* msgdef;
+  MessageLayout* layout;
+  VALUE klass;  // begins as nil
+  const upb_handlers* fill_handlers;
+  const upb_pbdecodermethod* fill_method;
+  const upb_json_parsermethod* json_fill_method;
+  const upb_handlers* pb_serialize_handlers;
+  const upb_handlers* json_serialize_handlers;
+  const upb_handlers* json_serialize_handlers_preserve;
+  // Handlers hold type class references for sub-message fields directly in some
+  // cases. We need to keep these rooted because they might otherwise be
+  // collected.
+  VALUE typeclass_references;
+};
+
+struct FieldDescriptor {
+  const upb_fielddef* fielddef;
+};
+
+struct OneofDescriptor {
+  const upb_oneofdef* oneofdef;
+};
+
+struct EnumDescriptor {
+  const upb_enumdef* enumdef;
+  VALUE module;  // begins as nil
+};
+
+struct MessageBuilderContext {
+  VALUE descriptor;
+  VALUE builder;
+};
+
+struct OneofBuilderContext {
+  VALUE descriptor;
+  VALUE builder;
+};
+
+struct EnumBuilderContext {
+  VALUE enumdesc;
+};
+
+struct Builder {
+  VALUE pending_list;
+  upb_def** defs;  // used only while finalizing
+};
+
+extern VALUE cDescriptorPool;
+extern VALUE cDescriptor;
+extern VALUE cFieldDescriptor;
+extern VALUE cEnumDescriptor;
+extern VALUE cMessageBuilderContext;
+extern VALUE cOneofBuilderContext;
+extern VALUE cEnumBuilderContext;
+extern VALUE cBuilder;
+
+extern VALUE cError;
+extern VALUE cParseError;
+
+// We forward-declare all of the Ruby method implementations here because we
+// sometimes call the methods directly across .c files, rather than going
+// through Ruby's method dispatching (e.g. during message parse). It's cleaner
+// to keep the list of object methods together than to split them between
+// static-in-file definitions and header declarations.
+
+void DescriptorPool_mark(void* _self);
+void DescriptorPool_free(void* _self);
+VALUE DescriptorPool_alloc(VALUE klass);
+void DescriptorPool_register(VALUE module);
+DescriptorPool* ruby_to_DescriptorPool(VALUE value);
+VALUE DescriptorPool_add(VALUE _self, VALUE def);
+VALUE DescriptorPool_build(VALUE _self);
+VALUE DescriptorPool_lookup(VALUE _self, VALUE name);
+VALUE DescriptorPool_generated_pool(VALUE _self);
+
+void Descriptor_mark(void* _self);
+void Descriptor_free(void* _self);
+VALUE Descriptor_alloc(VALUE klass);
+void Descriptor_register(VALUE module);
+Descriptor* ruby_to_Descriptor(VALUE value);
+VALUE Descriptor_name(VALUE _self);
+VALUE Descriptor_name_set(VALUE _self, VALUE str);
+VALUE Descriptor_each(VALUE _self);
+VALUE Descriptor_lookup(VALUE _self, VALUE name);
+VALUE Descriptor_add_field(VALUE _self, VALUE obj);
+VALUE Descriptor_add_oneof(VALUE _self, VALUE obj);
+VALUE Descriptor_each_oneof(VALUE _self);
+VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name);
+VALUE Descriptor_msgclass(VALUE _self);
+extern const rb_data_type_t _Descriptor_type;
+
+void FieldDescriptor_mark(void* _self);
+void FieldDescriptor_free(void* _self);
+VALUE FieldDescriptor_alloc(VALUE klass);
+void FieldDescriptor_register(VALUE module);
+FieldDescriptor* ruby_to_FieldDescriptor(VALUE value);
+VALUE FieldDescriptor_name(VALUE _self);
+VALUE FieldDescriptor_name_set(VALUE _self, VALUE str);
+VALUE FieldDescriptor_type(VALUE _self);
+VALUE FieldDescriptor_type_set(VALUE _self, VALUE type);
+VALUE FieldDescriptor_label(VALUE _self);
+VALUE FieldDescriptor_label_set(VALUE _self, VALUE label);
+VALUE FieldDescriptor_number(VALUE _self);
+VALUE FieldDescriptor_number_set(VALUE _self, VALUE number);
+VALUE FieldDescriptor_submsg_name(VALUE _self);
+VALUE FieldDescriptor_submsg_name_set(VALUE _self, VALUE value);
+VALUE FieldDescriptor_subtype(VALUE _self);
+VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb);
+VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value);
+upb_fieldtype_t ruby_to_fieldtype(VALUE type);
+VALUE fieldtype_to_ruby(upb_fieldtype_t type);
+
+void OneofDescriptor_mark(void* _self);
+void OneofDescriptor_free(void* _self);
+VALUE OneofDescriptor_alloc(VALUE klass);
+void OneofDescriptor_register(VALUE module);
+OneofDescriptor* ruby_to_OneofDescriptor(VALUE value);
+VALUE OneofDescriptor_name(VALUE _self);
+VALUE OneofDescriptor_name_set(VALUE _self, VALUE value);
+VALUE OneofDescriptor_add_field(VALUE _self, VALUE field);
+VALUE OneofDescriptor_each(VALUE _self, VALUE field);
+
+void EnumDescriptor_mark(void* _self);
+void EnumDescriptor_free(void* _self);
+VALUE EnumDescriptor_alloc(VALUE klass);
+void EnumDescriptor_register(VALUE module);
+EnumDescriptor* ruby_to_EnumDescriptor(VALUE value);
+VALUE EnumDescriptor_name(VALUE _self);
+VALUE EnumDescriptor_name_set(VALUE _self, VALUE str);
+VALUE EnumDescriptor_add_value(VALUE _self, VALUE name, VALUE number);
+VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name);
+VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number);
+VALUE EnumDescriptor_each(VALUE _self);
+VALUE EnumDescriptor_enummodule(VALUE _self);
+extern const rb_data_type_t _EnumDescriptor_type;
+
+void MessageBuilderContext_mark(void* _self);
+void MessageBuilderContext_free(void* _self);
+VALUE MessageBuilderContext_alloc(VALUE klass);
+void MessageBuilderContext_register(VALUE module);
+MessageBuilderContext* ruby_to_MessageBuilderContext(VALUE value);
+VALUE MessageBuilderContext_initialize(VALUE _self,
+                                       VALUE descriptor,
+                                       VALUE builder);
+VALUE MessageBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_required(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_repeated(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self);
+VALUE MessageBuilderContext_oneof(VALUE _self, VALUE name);
+
+void OneofBuilderContext_mark(void* _self);
+void OneofBuilderContext_free(void* _self);
+VALUE OneofBuilderContext_alloc(VALUE klass);
+void OneofBuilderContext_register(VALUE module);
+OneofBuilderContext* ruby_to_OneofBuilderContext(VALUE value);
+VALUE OneofBuilderContext_initialize(VALUE _self,
+                                     VALUE descriptor,
+                                     VALUE builder);
+VALUE OneofBuilderContext_optional(int argc, VALUE* argv, VALUE _self);
+
+void EnumBuilderContext_mark(void* _self);
+void EnumBuilderContext_free(void* _self);
+VALUE EnumBuilderContext_alloc(VALUE klass);
+void EnumBuilderContext_register(VALUE module);
+EnumBuilderContext* ruby_to_EnumBuilderContext(VALUE value);
+VALUE EnumBuilderContext_initialize(VALUE _self, VALUE enumdesc);
+VALUE EnumBuilderContext_value(VALUE _self, VALUE name, VALUE number);
+
+void Builder_mark(void* _self);
+void Builder_free(void* _self);
+VALUE Builder_alloc(VALUE klass);
+void Builder_register(VALUE module);
+Builder* ruby_to_Builder(VALUE value);
+VALUE Builder_add_message(VALUE _self, VALUE name);
+VALUE Builder_add_enum(VALUE _self, VALUE name);
+VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb);
+
+// -----------------------------------------------------------------------------
+// Native slot storage abstraction.
+// -----------------------------------------------------------------------------
+
+#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
+
+size_t native_slot_size(upb_fieldtype_t type);
+void native_slot_set(upb_fieldtype_t type,
+                     VALUE type_class,
+                     void* memory,
+                     VALUE value);
+// Atomically (with respect to Ruby VM calls) either update the value and set a
+// oneof case, or do neither. If |case_memory| is null, then no case value is
+// set.
+void native_slot_set_value_and_case(upb_fieldtype_t type,
+                                    VALUE type_class,
+                                    void* memory,
+                                    VALUE value,
+                                    uint32_t* case_memory,
+                                    uint32_t case_number);
+VALUE native_slot_get(upb_fieldtype_t type,
+                      VALUE type_class,
+                      const void* memory);
+void native_slot_init(upb_fieldtype_t type, void* memory);
+void native_slot_mark(upb_fieldtype_t type, void* memory);
+void native_slot_dup(upb_fieldtype_t type, void* to, void* from);
+void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from);
+bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
+
+void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value);
+void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value);
+
+extern rb_encoding* kRubyStringUtf8Encoding;
+extern rb_encoding* kRubyStringASCIIEncoding;
+extern rb_encoding* kRubyString8bitEncoding;
+
+VALUE field_type_class(const upb_fielddef* field);
+
+#define MAP_KEY_FIELD 1
+#define MAP_VALUE_FIELD 2
+
+// Oneof case slot value to indicate that no oneof case is set. The value `0` is
+// safe because field numbers are used as case identifiers, and no field can
+// have a number of 0.
+#define ONEOF_CASE_NONE 0
+
+// These operate on a map field (i.e., a repeated field of submessages whose
+// submessage type is a map-entry msgdef).
+bool is_map_field(const upb_fielddef* field);
+const upb_fielddef* map_field_key(const upb_fielddef* field);
+const upb_fielddef* map_field_value(const upb_fielddef* field);
+
+// These operate on a map-entry msgdef.
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
+
+// -----------------------------------------------------------------------------
+// Repeated field container type.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+  upb_fieldtype_t field_type;
+  VALUE field_type_class;
+  void* elements;
+  int size;
+  int capacity;
+} RepeatedField;
+
+void RepeatedField_mark(void* self);
+void RepeatedField_free(void* self);
+VALUE RepeatedField_alloc(VALUE klass);
+VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self);
+void RepeatedField_register(VALUE module);
+
+extern const rb_data_type_t RepeatedField_type;
+extern VALUE cRepeatedField;
+
+RepeatedField* ruby_to_RepeatedField(VALUE value);
+
+VALUE RepeatedField_each(VALUE _self);
+VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self);
+void* RepeatedField_index_native(VALUE _self, int index);
+VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val);
+void RepeatedField_reserve(RepeatedField* self, int new_size);
+VALUE RepeatedField_push(VALUE _self, VALUE val);
+void RepeatedField_push_native(VALUE _self, void* data);
+VALUE RepeatedField_pop_one(VALUE _self);
+VALUE RepeatedField_insert(int argc, VALUE* argv, VALUE _self);
+VALUE RepeatedField_replace(VALUE _self, VALUE list);
+VALUE RepeatedField_clear(VALUE _self);
+VALUE RepeatedField_length(VALUE _self);
+VALUE RepeatedField_dup(VALUE _self);
+VALUE RepeatedField_deep_copy(VALUE _self);
+VALUE RepeatedField_to_ary(VALUE _self);
+VALUE RepeatedField_eq(VALUE _self, VALUE _other);
+VALUE RepeatedField_hash(VALUE _self);
+VALUE RepeatedField_inspect(VALUE _self);
+VALUE RepeatedField_plus(VALUE _self, VALUE list);
+
+// Defined in repeated_field.c; also used by Map.
+void validate_type_class(upb_fieldtype_t type, VALUE klass);
+
+// -----------------------------------------------------------------------------
+// Map container type.
+// -----------------------------------------------------------------------------
+
+typedef struct {
+  upb_fieldtype_t key_type;
+  upb_fieldtype_t value_type;
+  VALUE value_type_class;
+  upb_strtable table;
+} Map;
+
+void Map_mark(void* self);
+void Map_free(void* self);
+VALUE Map_alloc(VALUE klass);
+VALUE Map_init(int argc, VALUE* argv, VALUE self);
+void Map_register(VALUE module);
+
+extern const rb_data_type_t Map_type;
+extern VALUE cMap;
+
+Map* ruby_to_Map(VALUE value);
+
+VALUE Map_each(VALUE _self);
+VALUE Map_keys(VALUE _self);
+VALUE Map_values(VALUE _self);
+VALUE Map_index(VALUE _self, VALUE key);
+VALUE Map_index_set(VALUE _self, VALUE key, VALUE value);
+VALUE Map_has_key(VALUE _self, VALUE key);
+VALUE Map_delete(VALUE _self, VALUE key);
+VALUE Map_clear(VALUE _self);
+VALUE Map_length(VALUE _self);
+VALUE Map_dup(VALUE _self);
+VALUE Map_deep_copy(VALUE _self);
+VALUE Map_eq(VALUE _self, VALUE _other);
+VALUE Map_hash(VALUE _self);
+VALUE Map_inspect(VALUE _self);
+VALUE Map_merge(VALUE _self, VALUE hashmap);
+VALUE Map_merge_into_self(VALUE _self, VALUE hashmap);
+
+typedef struct {
+  Map* self;
+  upb_strtable_iter it;
+} Map_iter;
+
+void Map_begin(VALUE _self, Map_iter* iter);
+void Map_next(Map_iter* iter);
+bool Map_done(Map_iter* iter);
+VALUE Map_iter_key(Map_iter* iter);
+VALUE Map_iter_value(Map_iter* iter);
+
+// -----------------------------------------------------------------------------
+// Message layout / storage.
+// -----------------------------------------------------------------------------
+
+#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
+
+struct MessageField {
+  size_t offset;
+  size_t case_offset;  // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
+};
+
+struct MessageLayout {
+  const upb_msgdef* msgdef;
+  MessageField* fields;
+  size_t size;
+};
+
+MessageLayout* create_layout(const upb_msgdef* msgdef);
+void free_layout(MessageLayout* layout);
+VALUE layout_get(MessageLayout* layout,
+                 const void* storage,
+                 const upb_fielddef* field);
+void layout_set(MessageLayout* layout,
+                void* storage,
+                const upb_fielddef* field,
+                VALUE val);
+void layout_init(MessageLayout* layout, void* storage);
+void layout_mark(MessageLayout* layout, void* storage);
+void layout_dup(MessageLayout* layout, void* to, void* from);
+void layout_deep_copy(MessageLayout* layout, void* to, void* from);
+VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2);
+VALUE layout_hash(MessageLayout* layout, void* storage);
+VALUE layout_inspect(MessageLayout* layout, void* storage);
+
+// -----------------------------------------------------------------------------
+// Message class creation.
+// -----------------------------------------------------------------------------
+
+struct MessageHeader {
+  Descriptor* descriptor;  // kept alive by self.class.descriptor reference.
+  // Data comes after this.
+};
+
+extern rb_data_type_t Message_type;
+
+VALUE build_class_from_descriptor(Descriptor* descriptor);
+void* Message_data(void* msg);
+void Message_mark(void* self);
+void Message_free(void* self);
+VALUE Message_alloc(VALUE klass);
+VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self);
+VALUE Message_initialize(int argc, VALUE* argv, VALUE _self);
+VALUE Message_dup(VALUE _self);
+VALUE Message_deep_copy(VALUE _self);
+VALUE Message_eq(VALUE _self, VALUE _other);
+VALUE Message_hash(VALUE _self);
+VALUE Message_inspect(VALUE _self);
+VALUE Message_index(VALUE _self, VALUE field_name);
+VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value);
+VALUE Message_descriptor(VALUE klass);
+VALUE Message_decode(VALUE klass, VALUE data);
+VALUE Message_encode(VALUE klass, VALUE msg_rb);
+VALUE Message_decode_json(VALUE klass, VALUE data);
+VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass);
+
+VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj);
+
+VALUE build_module_from_enumdesc(EnumDescriptor* enumdef);
+VALUE enum_lookup(VALUE self, VALUE number);
+VALUE enum_resolve(VALUE self, VALUE sym);
+
+const upb_pbdecodermethod *new_fillmsg_decodermethod(
+    Descriptor* descriptor, const void *owner);
+
+// Maximum depth allowed during encoding, to avoid stack overflows due to
+// cycles.
+#define ENCODE_MAX_NESTING 63
+
+// -----------------------------------------------------------------------------
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+// -----------------------------------------------------------------------------
+void add_def_obj(const void* def, VALUE value);
+VALUE get_def_obj(const void* def);
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+void check_upb_status(const upb_status* status, const char* msg);
+
+#define CHECK_UPB(code, msg) do {                                             \
+    upb_status status = UPB_STATUS_INIT;                                      \
+    code;                                                                     \
+    check_upb_status(&status, msg);                                           \
+} while (0)
+
+extern ID descriptor_instancevar_interned;
+
+#endif  // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
new file mode 100644
index 0000000..83afbc9
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -0,0 +1,651 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+// -----------------------------------------------------------------------------
+// Repeated field container type.
+// -----------------------------------------------------------------------------
+
+const rb_data_type_t RepeatedField_type = {
+  "Google::Protobuf::RepeatedField",
+  { RepeatedField_mark, RepeatedField_free, NULL },
+};
+
+VALUE cRepeatedField;
+
+RepeatedField* ruby_to_RepeatedField(VALUE _self) {
+  RepeatedField* self;
+  TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
+  return self;
+}
+
+void* RepeatedField_memoryat(RepeatedField* self, int index, int element_size) {
+  return ((uint8_t *)self->elements) + index * element_size;
+}
+
+static int index_position(VALUE _index, RepeatedField* repeated_field) {
+  int index = NUM2INT(_index);
+  if (index < 0 && repeated_field->size > 0) {
+    index = repeated_field->size + index;
+  }
+  return index;
+}
+
+VALUE RepeatedField_subarray(VALUE _self, long beg, long len) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  int element_size = native_slot_size(self->field_type);
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+
+  size_t off = beg * element_size;
+  VALUE ary = rb_ary_new2(len);
+  for (int i = beg; i < beg + len; i++, off += element_size) {
+    void* mem = ((uint8_t *)self->elements) + off;
+    VALUE elem = native_slot_get(field_type, field_type_class, mem);
+    rb_ary_push(ary, elem);
+  }
+  return ary;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.each(&block)
+ *
+ * Invokes the block once for each element of the repeated field. RepeatedField
+ * also includes Enumerable; combined with this method, the repeated field thus
+ * acts like an ordinary Ruby sequence.
+ */
+VALUE RepeatedField_each(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+  int element_size = native_slot_size(field_type);
+
+  size_t off = 0;
+  for (int i = 0; i < self->size; i++, off += element_size) {
+    void* memory = (void *) (((uint8_t *)self->elements) + off);
+    VALUE val = native_slot_get(field_type, field_type_class, memory);
+    rb_yield(val);
+  }
+  return _self;
+}
+
+
+/*
+ * call-seq:
+ *     RepeatedField.[](index) => value
+ *
+ * Accesses the element at the given index. Returns nil on out-of-bounds
+ */
+VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  int element_size = native_slot_size(self->field_type);
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+
+  VALUE arg = argv[0];
+  long beg, len;
+
+  if (argc == 1){
+    if (FIXNUM_P(arg)) {
+      /* standard case */
+      void* memory;
+      int index = index_position(argv[0], self);
+      if (index < 0 || index >= self->size) {
+        return Qnil;
+      }
+      memory = RepeatedField_memoryat(self, index, element_size);
+      return native_slot_get(field_type, field_type_class, memory);
+    }else{
+      /* check if idx is Range */
+      switch (rb_range_beg_len(arg, &beg, &len, self->size, 0)) {
+        case Qfalse:
+          break;
+        case Qnil:
+          return Qnil;
+        default:
+          return RepeatedField_subarray(_self, beg, len);
+      }
+    }
+  }
+  /* assume 2 arguments */
+  beg = NUM2LONG(argv[0]);
+  len = NUM2LONG(argv[1]);
+  if (beg < 0) {
+    beg += self->size;
+  }
+  if (beg >= self->size) {
+    return Qnil;
+  }
+  return RepeatedField_subarray(_self, beg, len);
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.[]=(index, value)
+ *
+ * Sets the element at the given index. On out-of-bounds assignments, extends
+ * the array and fills the hole (if any) with default values.
+ */
+VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+  int element_size = native_slot_size(field_type);
+  void* memory;
+
+  int index = index_position(_index, self);
+  if (index < 0 || index >= (INT_MAX - 1)) {
+    return Qnil;
+  }
+  if (index >= self->size) {
+    upb_fieldtype_t field_type = self->field_type;
+    int element_size = native_slot_size(field_type);
+    RepeatedField_reserve(self, index + 1);
+    for (int i = self->size; i <= index; i++) {
+      void* elem = RepeatedField_memoryat(self, i, element_size);
+      native_slot_init(field_type, elem);
+    }
+    self->size = index + 1;
+  }
+
+  memory = RepeatedField_memoryat(self, index, element_size);
+  native_slot_set(field_type, field_type_class, memory, val);
+  return Qnil;
+}
+
+static int kInitialSize = 8;
+
+void RepeatedField_reserve(RepeatedField* self, int new_size) {
+  void* old_elems = self->elements;
+  int elem_size = native_slot_size(self->field_type);
+  if (new_size <= self->capacity) {
+    return;
+  }
+  if (self->capacity == 0) {
+    self->capacity = kInitialSize;
+  }
+  while (self->capacity < new_size) {
+    self->capacity *= 2;
+  }
+  self->elements = ALLOC_N(uint8_t, elem_size * self->capacity);
+  if (old_elems != NULL) {
+    memcpy(self->elements, old_elems, self->size * elem_size);
+    xfree(old_elems);
+  }
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.push(value)
+ *
+ * Adds a new element to the repeated field.
+ */
+VALUE RepeatedField_push(VALUE _self, VALUE val) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  int element_size = native_slot_size(field_type);
+  void* memory;
+
+  RepeatedField_reserve(self, self->size + 1);
+  memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
+  native_slot_set(field_type, self->field_type_class, memory, val);
+  // native_slot_set may raise an error; bump size only after set.
+  self->size++;
+  return _self;
+}
+
+
+// Used by parsing handlers.
+void RepeatedField_push_native(VALUE _self, void* data) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  int element_size = native_slot_size(field_type);
+  void* memory;
+
+  RepeatedField_reserve(self, self->size + 1);
+  memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
+  memcpy(memory, data, element_size);
+  self->size++;
+}
+
+void* RepeatedField_index_native(VALUE _self, int index) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  int element_size = native_slot_size(field_type);
+  return RepeatedField_memoryat(self, index, element_size);
+}
+
+/*
+ * Private ruby method, used by RepeatedField.pop
+ */
+VALUE RepeatedField_pop_one(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+  int element_size = native_slot_size(field_type);
+  int index;
+  void* memory;
+  VALUE ret;
+
+  if (self->size == 0) {
+    return Qnil;
+  }
+  index = self->size - 1;
+  memory = RepeatedField_memoryat(self, index, element_size);
+  ret = native_slot_get(field_type, field_type_class, memory);
+  self->size--;
+  return ret;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.replace(list)
+ *
+ * Replaces the contents of the repeated field with the given list of elements.
+ */
+VALUE RepeatedField_replace(VALUE _self, VALUE list) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  Check_Type(list, T_ARRAY);
+  self->size = 0;
+  for (int i = 0; i < RARRAY_LEN(list); i++) {
+    RepeatedField_push(_self, rb_ary_entry(list, i));
+  }
+  return list;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.clear
+ *
+ * Clears (removes all elements from) this repeated field.
+ */
+VALUE RepeatedField_clear(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  self->size = 0;
+  return _self;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.length
+ *
+ * Returns the length of this repeated field.
+ */
+VALUE RepeatedField_length(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  return INT2NUM(self->size);
+}
+
+static VALUE RepeatedField_new_this_type(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  VALUE new_rptfield = Qnil;
+  VALUE element_type = fieldtype_to_ruby(self->field_type);
+  if (self->field_type_class != Qnil) {
+    new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
+                              element_type, self->field_type_class);
+  } else {
+    new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1,
+                              element_type);
+  }
+  return new_rptfield;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.dup => repeated_field
+ *
+ * Duplicates this repeated field with a shallow copy. References to all
+ * non-primitive element objects (e.g., submessages) are shared.
+ */
+VALUE RepeatedField_dup(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  VALUE new_rptfield = RepeatedField_new_this_type(_self);
+  RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
+  upb_fieldtype_t field_type = self->field_type;
+  size_t elem_size = native_slot_size(field_type);
+  size_t off = 0;
+  RepeatedField_reserve(new_rptfield_self, self->size);
+  for (int i = 0; i < self->size; i++, off += elem_size) {
+    void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
+    void* from_mem = (uint8_t *)self->elements + off;
+    native_slot_dup(field_type, to_mem, from_mem);
+    new_rptfield_self->size++;
+  }
+
+  return new_rptfield;
+}
+
+// Internal only: used by Google::Protobuf.deep_copy.
+VALUE RepeatedField_deep_copy(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  VALUE new_rptfield = RepeatedField_new_this_type(_self);
+  RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
+  upb_fieldtype_t field_type = self->field_type;
+  size_t elem_size = native_slot_size(field_type);
+  size_t off = 0;
+  RepeatedField_reserve(new_rptfield_self, self->size);
+  for (int i = 0; i < self->size; i++, off += elem_size) {
+    void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
+    void* from_mem = (uint8_t *)self->elements + off;
+    native_slot_deep_copy(field_type, to_mem, from_mem);
+    new_rptfield_self->size++;
+  }
+
+  return new_rptfield;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.to_ary => array
+ *
+ * Used when converted implicitly into array, e.g. compared to an Array.
+ * Also called as a fallback of Object#to_a
+ */
+VALUE RepeatedField_to_ary(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  upb_fieldtype_t field_type = self->field_type;
+
+  size_t elem_size = native_slot_size(field_type);
+  size_t off = 0;
+  VALUE ary = rb_ary_new2(self->size);
+  for (int i = 0; i < self->size; i++, off += elem_size) {
+    void* mem = ((uint8_t *)self->elements) + off;
+    VALUE elem = native_slot_get(field_type, self->field_type_class, mem);
+    rb_ary_push(ary, elem);
+  }
+  return ary;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.==(other) => boolean
+ *
+ * Compares this repeated field to another. Repeated fields are equal if their
+ * element types are equal, their lengths are equal, and each element is equal.
+ * Elements are compared as per normal Ruby semantics, by calling their :==
+ * methods (or performing a more efficient comparison for primitive types).
+ *
+ * Repeated fields with dissimilar element types are never equal, even if value
+ * comparison (for example, between integers and floats) would have otherwise
+ * indicated that every element has equal value.
+ */
+VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
+  RepeatedField* self;
+  RepeatedField* other;
+
+  if (_self == _other) {
+    return Qtrue;
+  }
+
+  if (TYPE(_other) == T_ARRAY) {
+    VALUE self_ary = RepeatedField_to_ary(_self);
+    return rb_equal(self_ary, _other);
+  }
+
+  self = ruby_to_RepeatedField(_self);
+  other = ruby_to_RepeatedField(_other);
+  if (self->field_type != other->field_type ||
+      self->field_type_class != other->field_type_class ||
+      self->size != other->size) {
+    return Qfalse;
+  }
+
+  {
+    upb_fieldtype_t field_type = self->field_type;
+    size_t elem_size = native_slot_size(field_type);
+    size_t off = 0;
+    for (int i = 0; i < self->size; i++, off += elem_size) {
+      void* self_mem = ((uint8_t *)self->elements) + off;
+      void* other_mem = ((uint8_t *)other->elements) + off;
+      if (!native_slot_eq(field_type, self_mem, other_mem)) {
+        return Qfalse;
+      }
+    }
+    return Qtrue;
+  }
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.hash => hash_value
+ *
+ * Returns a hash value computed from this repeated field's elements.
+ */
+VALUE RepeatedField_hash(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+
+  VALUE hash = LL2NUM(0);
+
+  upb_fieldtype_t field_type = self->field_type;
+  VALUE field_type_class = self->field_type_class;
+  size_t elem_size = native_slot_size(field_type);
+  size_t off = 0;
+  for (int i = 0; i < self->size; i++, off += elem_size) {
+    void* mem = ((uint8_t *)self->elements) + off;
+    VALUE elem = native_slot_get(field_type, field_type_class, mem);
+    hash = rb_funcall(hash, rb_intern("<<"), 1, INT2NUM(2));
+    hash = rb_funcall(hash, rb_intern("^"), 1,
+                      rb_funcall(elem, rb_intern("hash"), 0));
+  }
+
+  return hash;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.+(other) => repeated field
+ *
+ * Returns a new repeated field that contains the concatenated list of this
+ * repeated field's elements and other's elements. The other (second) list may
+ * be either another repeated field or a Ruby array.
+ */
+VALUE RepeatedField_plus(VALUE _self, VALUE list) {
+  VALUE dupped = RepeatedField_dup(_self);
+
+  if (TYPE(list) == T_ARRAY) {
+    for (int i = 0; i < RARRAY_LEN(list); i++) {
+      VALUE elem = rb_ary_entry(list, i);
+      RepeatedField_push(dupped, elem);
+    }
+  } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) &&
+             RTYPEDDATA_TYPE(list) == &RepeatedField_type) {
+    RepeatedField* self = ruby_to_RepeatedField(_self);
+    RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
+    if (self->field_type != list_rptfield->field_type ||
+        self->field_type_class != list_rptfield->field_type_class) {
+      rb_raise(rb_eArgError,
+               "Attempt to append RepeatedField with different element type.");
+    }
+    for (int i = 0; i < list_rptfield->size; i++) {
+      void* mem = RepeatedField_index_native(list, i);
+      RepeatedField_push_native(dupped, mem);
+    }
+  } else {
+    rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
+  }
+
+  return dupped;
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.concat(other) => self
+ *
+ * concats the passed in array to self.  Returns a Ruby array.
+ */
+VALUE RepeatedField_concat(VALUE _self, VALUE list) {
+  Check_Type(list, T_ARRAY);
+  for (int i = 0; i < RARRAY_LEN(list); i++) {
+    RepeatedField_push(_self, rb_ary_entry(list, i));
+  }
+  return _self;
+}
+
+
+void validate_type_class(upb_fieldtype_t type, VALUE klass) {
+  if (rb_ivar_get(klass, descriptor_instancevar_interned) == Qnil) {
+    rb_raise(rb_eArgError,
+             "Type class has no descriptor. Please pass a "
+             "class or enum as returned by the DescriptorPool.");
+  }
+  if (type == UPB_TYPE_MESSAGE) {
+    VALUE desc = rb_ivar_get(klass, descriptor_instancevar_interned);
+    if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) ||
+        RTYPEDDATA_TYPE(desc) != &_Descriptor_type) {
+      rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
+    }
+    if (rb_get_alloc_func(klass) != &Message_alloc) {
+      rb_raise(rb_eArgError,
+               "Message class was not returned by the DescriptorPool.");
+    }
+  } else if (type == UPB_TYPE_ENUM) {
+    VALUE enumdesc = rb_ivar_get(klass, descriptor_instancevar_interned);
+    if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) ||
+        RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) {
+      rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
+    }
+  }
+}
+
+void RepeatedField_init_args(int argc, VALUE* argv,
+                             VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  VALUE ary = Qnil;
+  if (argc < 1) {
+    rb_raise(rb_eArgError, "Expected at least 1 argument.");
+  }
+  self->field_type = ruby_to_fieldtype(argv[0]);
+
+  if (self->field_type == UPB_TYPE_MESSAGE ||
+      self->field_type == UPB_TYPE_ENUM) {
+    if (argc < 2) {
+      rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum.");
+    }
+    self->field_type_class = argv[1];
+    if (argc > 2) {
+      ary = argv[2];
+    }
+    validate_type_class(self->field_type, self->field_type_class);
+  } else {
+    if (argc > 2) {
+      rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2.");
+    }
+    if (argc > 1) {
+      ary = argv[1];
+    }
+  }
+
+  if (ary != Qnil) {
+    if (!RB_TYPE_P(ary, T_ARRAY)) {
+      rb_raise(rb_eArgError, "Expected array as initialize argument");
+    }
+    for (int i = 0; i < RARRAY_LEN(ary); i++) {
+      RepeatedField_push(_self, rb_ary_entry(ary, i));
+    }
+  }
+}
+
+// Mark, free, alloc, init and class setup functions.
+
+void RepeatedField_mark(void* _self) {
+  RepeatedField* self = (RepeatedField*)_self;
+  upb_fieldtype_t field_type = self->field_type;
+  int element_size = native_slot_size(field_type);
+  rb_gc_mark(self->field_type_class);
+  for (int i = 0; i < self->size; i++) {
+    void* memory = (((uint8_t *)self->elements) + i * element_size);
+    native_slot_mark(self->field_type, memory);
+  }
+}
+
+void RepeatedField_free(void* _self) {
+  RepeatedField* self = (RepeatedField*)_self;
+  xfree(self->elements);
+  xfree(self);
+}
+
+/*
+ * call-seq:
+ *     RepeatedField.new(type, type_class = nil, initial_elems = [])
+ *
+ * Creates a new repeated field. The provided type must be a Ruby symbol, and
+ * can take on the same values as those accepted by FieldDescriptor#type=. If
+ * the type is :message or :enum, type_class must be non-nil, and must be the
+ * Ruby class or module returned by Descriptor#msgclass or
+ * EnumDescriptor#enummodule, respectively. An initial list of elements may also
+ * be provided.
+ */
+VALUE RepeatedField_alloc(VALUE klass) {
+  RepeatedField* self = ALLOC(RepeatedField);
+  self->elements = NULL;
+  self->size = 0;
+  self->capacity = 0;
+  self->field_type = -1;
+  self->field_type_class = Qnil;
+  return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
+}
+
+VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) {
+  RepeatedField_init_args(argc, argv, self);
+  return Qnil;
+}
+
+void RepeatedField_register(VALUE module) {
+  VALUE klass = rb_define_class_under(
+      module, "RepeatedField", rb_cObject);
+  rb_define_alloc_func(klass, RepeatedField_alloc);
+  cRepeatedField = klass;
+  rb_gc_register_address(&cRepeatedField);
+
+  rb_define_method(klass, "initialize",
+                   RepeatedField_init, -1);
+  rb_define_method(klass, "each", RepeatedField_each, 0);
+  rb_define_method(klass, "[]", RepeatedField_index, -1);
+  rb_define_method(klass, "at", RepeatedField_index, -1);
+  rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
+  rb_define_method(klass, "push", RepeatedField_push, 1);
+  rb_define_method(klass, "<<", RepeatedField_push, 1);
+  rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
+  rb_define_method(klass, "replace", RepeatedField_replace, 1);
+  rb_define_method(klass, "clear", RepeatedField_clear, 0);
+  rb_define_method(klass, "length", RepeatedField_length, 0);
+  rb_define_method(klass, "size", RepeatedField_length, 0);
+  rb_define_method(klass, "dup", RepeatedField_dup, 0);
+  // Also define #clone so that we don't inherit Object#clone.
+  rb_define_method(klass, "clone", RepeatedField_dup, 0);
+  rb_define_method(klass, "==", RepeatedField_eq, 1);
+  rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
+  rb_define_method(klass, "hash", RepeatedField_hash, 0);
+  rb_define_method(klass, "+", RepeatedField_plus, 1);
+  rb_define_method(klass, "concat", RepeatedField_concat, 1);
+  rb_include_module(klass, rb_mEnumerable);
+}
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
new file mode 100644
index 0000000..b1f65f4
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -0,0 +1,863 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include "protobuf.h"
+
+#include <math.h>
+
+#include <ruby/encoding.h>
+
+// -----------------------------------------------------------------------------
+// Ruby <-> native slot management.
+// -----------------------------------------------------------------------------
+
+#define DEREF(memory, type) *(type*)(memory)
+
+size_t native_slot_size(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_FLOAT:   return 4;
+    case UPB_TYPE_DOUBLE:  return 8;
+    case UPB_TYPE_BOOL:    return 1;
+    case UPB_TYPE_STRING:  return sizeof(VALUE);
+    case UPB_TYPE_BYTES:   return sizeof(VALUE);
+    case UPB_TYPE_MESSAGE: return sizeof(VALUE);
+    case UPB_TYPE_ENUM:    return 4;
+    case UPB_TYPE_INT32:   return 4;
+    case UPB_TYPE_INT64:   return 8;
+    case UPB_TYPE_UINT32:  return 4;
+    case UPB_TYPE_UINT64:  return 8;
+    default: return 0;
+  }
+}
+
+static bool is_ruby_num(VALUE value) {
+  return (TYPE(value) == T_FLOAT ||
+          TYPE(value) == T_FIXNUM ||
+          TYPE(value) == T_BIGNUM);
+}
+
+void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
+  if (!is_ruby_num(val)) {
+    rb_raise(rb_eTypeError, "Expected number type for integral field.");
+  }
+
+  // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
+  // bound; we just need to do precision checks (i.e., disallow rounding) and
+  // check for < 0 on unsigned types.
+  if (TYPE(val) == T_FLOAT) {
+    double dbl_val = NUM2DBL(val);
+    if (floor(dbl_val) != dbl_val) {
+      rb_raise(rb_eRangeError,
+               "Non-integral floating point value assigned to integer field.");
+    }
+  }
+  if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
+    if (NUM2DBL(val) < 0) {
+      rb_raise(rb_eRangeError,
+               "Assigning negative value to unsigned integer field.");
+    }
+  }
+}
+
+void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
+  bool bad_encoding = false;
+  rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
+  if (type == UPB_TYPE_STRING) {
+    bad_encoding =
+        string_encoding != kRubyStringUtf8Encoding &&
+        string_encoding != kRubyStringASCIIEncoding;
+  } else {
+    bad_encoding =
+        string_encoding != kRubyString8bitEncoding;
+  }
+  // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
+  // (for bytes fields).
+  if (bad_encoding) {
+    rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
+             (type == UPB_TYPE_STRING) ? "string" : "bytes",
+             (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
+             rb_enc_name(string_encoding));
+  }
+}
+
+void native_slot_set(upb_fieldtype_t type, VALUE type_class,
+                     void* memory, VALUE value) {
+  native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
+}
+
+void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
+                                    void* memory, VALUE value,
+                                    uint32_t* case_memory,
+                                    uint32_t case_number) {
+  // Note that in order to atomically change the value in memory and the case
+  // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after
+  // all Ruby VM calls are complete. The case is then set at the bottom of this
+  // function.
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      if (!is_ruby_num(value)) {
+        rb_raise(rb_eTypeError, "Expected number type for float field.");
+      }
+      DEREF(memory, float) = NUM2DBL(value);
+      break;
+    case UPB_TYPE_DOUBLE:
+      if (!is_ruby_num(value)) {
+        rb_raise(rb_eTypeError, "Expected number type for double field.");
+      }
+      DEREF(memory, double) = NUM2DBL(value);
+      break;
+    case UPB_TYPE_BOOL: {
+      int8_t val = -1;
+      if (value == Qtrue) {
+        val = 1;
+      } else if (value == Qfalse) {
+        val = 0;
+      } else {
+        rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
+      }
+      DEREF(memory, int8_t) = val;
+      break;
+    }
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      if (CLASS_OF(value) != rb_cString) {
+        rb_raise(rb_eTypeError, "Invalid argument for string field.");
+      }
+      native_slot_validate_string_encoding(type, value);
+      DEREF(memory, VALUE) = value;
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      if (CLASS_OF(value) == CLASS_OF(Qnil)) {
+        value = Qnil;
+      } else if (CLASS_OF(value) != type_class) {
+        rb_raise(rb_eTypeError,
+                 "Invalid type %s to assign to submessage field.",
+                 rb_class2name(CLASS_OF(value)));
+      }
+      DEREF(memory, VALUE) = value;
+      break;
+    }
+    case UPB_TYPE_ENUM: {
+      int32_t int_val = 0;
+      if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
+        rb_raise(rb_eTypeError,
+                 "Expected number or symbol type for enum field.");
+      }
+      if (TYPE(value) == T_SYMBOL) {
+        // Ensure that the given symbol exists in the enum module.
+        VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
+        if (lookup == Qnil) {
+          rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
+        } else {
+          int_val = NUM2INT(lookup);
+        }
+      } else {
+        native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
+        int_val = NUM2INT(value);
+      }
+      DEREF(memory, int32_t) = int_val;
+      break;
+    }
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      native_slot_check_int_range_precision(type, value);
+      switch (type) {
+      case UPB_TYPE_INT32:
+        DEREF(memory, int32_t) = NUM2INT(value);
+        break;
+      case UPB_TYPE_INT64:
+        DEREF(memory, int64_t) = NUM2LL(value);
+        break;
+      case UPB_TYPE_UINT32:
+        DEREF(memory, uint32_t) = NUM2UINT(value);
+        break;
+      case UPB_TYPE_UINT64:
+        DEREF(memory, uint64_t) = NUM2ULL(value);
+        break;
+      default:
+        break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (case_memory != NULL) {
+    *case_memory = case_number;
+  }
+}
+
+VALUE native_slot_get(upb_fieldtype_t type,
+                      VALUE type_class,
+                      const void* memory) {
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      return DBL2NUM(DEREF(memory, float));
+    case UPB_TYPE_DOUBLE:
+      return DBL2NUM(DEREF(memory, double));
+    case UPB_TYPE_BOOL:
+      return DEREF(memory, int8_t) ? Qtrue : Qfalse;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE:
+      return DEREF(memory, VALUE);
+    case UPB_TYPE_ENUM: {
+      int32_t val = DEREF(memory, int32_t);
+      VALUE symbol = enum_lookup(type_class, INT2NUM(val));
+      if (symbol == Qnil) {
+        return INT2NUM(val);
+      } else {
+        return symbol;
+      }
+    }
+    case UPB_TYPE_INT32:
+      return INT2NUM(DEREF(memory, int32_t));
+    case UPB_TYPE_INT64:
+      return LL2NUM(DEREF(memory, int64_t));
+    case UPB_TYPE_UINT32:
+      return UINT2NUM(DEREF(memory, uint32_t));
+    case UPB_TYPE_UINT64:
+      return ULL2NUM(DEREF(memory, uint64_t));
+    default:
+      return Qnil;
+  }
+}
+
+void native_slot_init(upb_fieldtype_t type, void* memory) {
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      DEREF(memory, float) = 0.0;
+      break;
+    case UPB_TYPE_DOUBLE:
+      DEREF(memory, double) = 0.0;
+      break;
+    case UPB_TYPE_BOOL:
+      DEREF(memory, int8_t) = 0;
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      DEREF(memory, VALUE) = rb_str_new2("");
+      rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ?
+                       kRubyString8bitEncoding : kRubyStringUtf8Encoding);
+      break;
+    case UPB_TYPE_MESSAGE:
+      DEREF(memory, VALUE) = Qnil;
+      break;
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32:
+      DEREF(memory, int32_t) = 0;
+      break;
+    case UPB_TYPE_INT64:
+      DEREF(memory, int64_t) = 0;
+      break;
+    case UPB_TYPE_UINT32:
+      DEREF(memory, uint32_t) = 0;
+      break;
+    case UPB_TYPE_UINT64:
+      DEREF(memory, uint64_t) = 0;
+      break;
+    default:
+      break;
+  }
+}
+
+void native_slot_mark(upb_fieldtype_t type, void* memory) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE:
+      rb_gc_mark(DEREF(memory, VALUE));
+      break;
+    default:
+      break;
+  }
+}
+
+void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
+  memcpy(to, from, native_slot_size(type));
+}
+
+void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      VALUE from_val = DEREF(from, VALUE);
+      DEREF(to, VALUE) = (from_val != Qnil) ?
+          rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      VALUE from_val = DEREF(from, VALUE);
+      DEREF(to, VALUE) = (from_val != Qnil) ?
+          Message_deep_copy(from_val) : Qnil;
+      break;
+    }
+    default:
+      memcpy(to, from, native_slot_size(type));
+  }
+}
+
+bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE: {
+      VALUE val1 = DEREF(mem1, VALUE);
+      VALUE val2 = DEREF(mem2, VALUE);
+      VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
+      return ret == Qtrue;
+    }
+    default:
+      return !memcmp(mem1, mem2, native_slot_size(type));
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Map field utilities.
+// -----------------------------------------------------------------------------
+
+const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef;
+  if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
+      upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
+    return NULL;
+  }
+  subdef = upb_fielddef_msgsubdef(field);
+  return upb_msgdef_mapentry(subdef) ? subdef : NULL;
+}
+
+const upb_msgdef *map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef = tryget_map_entry_msgdef(field);
+  assert(subdef);
+  return subdef;
+}
+
+bool is_map_field(const upb_fielddef *field) {
+  return tryget_map_entry_msgdef(field) != NULL;
+}
+
+const upb_fielddef* map_field_key(const upb_fielddef* field) {
+  const upb_msgdef* subdef = map_entry_msgdef(field);
+  return map_entry_key(subdef);
+}
+
+const upb_fielddef* map_field_value(const upb_fielddef* field) {
+  const upb_msgdef* subdef = map_entry_msgdef(field);
+  return map_entry_value(subdef);
+}
+
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
+  const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
+  assert(key_field != NULL);
+  return key_field;
+}
+
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
+  const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
+  assert(value_field != NULL);
+  return value_field;
+}
+
+// -----------------------------------------------------------------------------
+// Memory layout management.
+// -----------------------------------------------------------------------------
+
+static size_t align_up_to(size_t offset, size_t granularity) {
+  // Granularity must be a power of two.
+  return (offset + granularity - 1) & ~(granularity - 1);
+}
+
+MessageLayout* create_layout(const upb_msgdef* msgdef) {
+  MessageLayout* layout = ALLOC(MessageLayout);
+  int nfields = upb_msgdef_numfields(msgdef);
+  upb_msg_field_iter it;
+  upb_msg_oneof_iter oit;
+  size_t off = 0;
+
+  layout->fields = ALLOC_N(MessageField, nfields);
+
+  for (upb_msg_field_begin(&it, msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    size_t field_size;
+
+    if (upb_fielddef_containingoneof(field)) {
+      // Oneofs are handled separately below.
+      continue;
+    }
+
+    // Allocate |field_size| bytes for this field in the layout.
+    field_size = 0;
+    if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      field_size = sizeof(VALUE);
+    } else {
+      field_size = native_slot_size(upb_fielddef_type(field));
+    }
+    // Align current offset up to |size| granularity.
+    off = align_up_to(off, field_size);
+    layout->fields[upb_fielddef_index(field)].offset = off;
+    layout->fields[upb_fielddef_index(field)].case_offset =
+        MESSAGE_FIELD_NO_CASE;
+    off += field_size;
+  }
+
+  // Handle oneofs now -- we iterate over oneofs specifically and allocate only
+  // one slot per oneof.
+  //
+  // We assign all value slots first, then pack the 'case' fields at the end,
+  // since in the common case (modern 64-bit platform) these are 8 bytes and 4
+  // bytes respectively and we want to avoid alignment overhead.
+  //
+  // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
+  // space for oneof cases is conceptually as wide as field tag numbers. In
+  // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K
+  // members (8 or 16 bits respectively), so conceivably we could assign
+  // consecutive case numbers and then pick a smaller oneof case slot size, but
+  // the complexity to implement this indirection is probably not worthwhile.
+  for (upb_msg_oneof_begin(&oit, msgdef);
+       !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
+    // all fields.
+    size_t field_size = NATIVE_SLOT_MAX_SIZE;
+    // Align the offset.
+    off = align_up_to(off, field_size);
+    // Assign all fields in the oneof this same offset.
+    for (upb_oneof_begin(&fit, oneof);
+         !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].offset = off;
+    }
+    off += field_size;
+  }
+
+  // Now the case fields.
+  for (upb_msg_oneof_begin(&oit, msgdef);
+       !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    size_t field_size = sizeof(uint32_t);
+    // Align the offset.
+    off = (off + field_size - 1) & ~(field_size - 1);
+    // Assign all fields in the oneof this same offset.
+    for (upb_oneof_begin(&fit, oneof);
+         !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].case_offset = off;
+    }
+    off += field_size;
+  }
+
+  layout->size = off;
+
+  layout->msgdef = msgdef;
+  upb_msgdef_ref(layout->msgdef, &layout->msgdef);
+
+  return layout;
+}
+
+void free_layout(MessageLayout* layout) {
+  xfree(layout->fields);
+  upb_msgdef_unref(layout->msgdef, &layout->msgdef);
+  xfree(layout);
+}
+
+VALUE field_type_class(const upb_fielddef* field) {
+  VALUE type_class = Qnil;
+  if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
+    VALUE submsgdesc =
+        get_def_obj(upb_fielddef_subdef(field));
+    type_class = Descriptor_msgclass(submsgdesc);
+  } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
+    VALUE subenumdesc =
+        get_def_obj(upb_fielddef_subdef(field));
+    type_class = EnumDescriptor_enummodule(subenumdesc);
+  }
+  return type_class;
+}
+
+static void* slot_memory(MessageLayout* layout,
+                         const void* storage,
+                         const upb_fielddef* field) {
+  return ((uint8_t *)storage) +
+      layout->fields[upb_fielddef_index(field)].offset;
+}
+
+static uint32_t* slot_oneof_case(MessageLayout* layout,
+                                 const void* storage,
+                                 const upb_fielddef* field) {
+  return (uint32_t *)(((uint8_t *)storage) +
+      layout->fields[upb_fielddef_index(field)].case_offset);
+}
+
+
+VALUE layout_get(MessageLayout* layout,
+                 const void* storage,
+                 const upb_fielddef* field) {
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    if (*oneof_case != upb_fielddef_number(field)) {
+      return Qnil;
+    }
+    return native_slot_get(upb_fielddef_type(field),
+                           field_type_class(field),
+                           memory);
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+    return *((VALUE *)memory);
+  } else {
+    return native_slot_get(upb_fielddef_type(field),
+                           field_type_class(field),
+                           memory);
+  }
+}
+
+static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
+  RepeatedField* self;
+  assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
+
+  if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+      RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
+    rb_raise(rb_eTypeError, "Expected repeated field array");
+  }
+
+  self = ruby_to_RepeatedField(val);
+  if (self->field_type != upb_fielddef_type(field)) {
+    rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
+  }
+
+  if (self->field_type == UPB_TYPE_MESSAGE ||
+      self->field_type == UPB_TYPE_ENUM) {
+    if (self->field_type_class !=
+        get_def_obj(upb_fielddef_subdef(field))) {
+      rb_raise(rb_eTypeError,
+               "Repeated field array has wrong message/enum class");
+    }
+  }
+}
+
+static void check_map_field_type(VALUE val, const upb_fielddef* field) {
+  const upb_fielddef* key_field = map_field_key(field);
+  const upb_fielddef* value_field = map_field_value(field);
+  Map* self;
+
+  if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
+      RTYPEDDATA_TYPE(val) != &Map_type) {
+    rb_raise(rb_eTypeError, "Expected Map instance");
+  }
+
+  self = ruby_to_Map(val);
+  if (self->key_type != upb_fielddef_type(key_field)) {
+    rb_raise(rb_eTypeError, "Map key type does not match field's key type");
+  }
+  if (self->value_type != upb_fielddef_type(value_field)) {
+    rb_raise(rb_eTypeError, "Map value type does not match field's value type");
+  }
+  if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
+      upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
+    if (self->value_type_class !=
+        get_def_obj(upb_fielddef_subdef(value_field))) {
+      rb_raise(rb_eTypeError,
+               "Map value type has wrong message/enum class");
+    }
+  }
+}
+
+
+void layout_set(MessageLayout* layout,
+                void* storage,
+                const upb_fielddef* field,
+                VALUE val) {
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    if (val == Qnil) {
+      // Assigning nil to a oneof field clears the oneof completely.
+      *oneof_case = ONEOF_CASE_NONE;
+      memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+    } else {
+      // The transition between field types for a single oneof (union) slot is
+      // somewhat complex because we need to ensure that a GC triggered at any
+      // point by a call into the Ruby VM sees a valid state for this field and
+      // does not either go off into the weeds (following what it thinks is a
+      // VALUE but is actually a different field type) or miss an object (seeing
+      // what it thinks is a primitive field but is actually a VALUE for the new
+      // field type).
+      //
+      // In order for the transition to be safe, the oneof case slot must be in
+      // sync with the value slot whenever the Ruby VM has been called. Thus, we
+      // use native_slot_set_value_and_case(), which ensures that both the value
+      // and case number are altered atomically (w.r.t. the Ruby VM).
+      native_slot_set_value_and_case(
+          upb_fielddef_type(field), field_type_class(field),
+          memory, val,
+          oneof_case, upb_fielddef_number(field));
+    }
+  } else if (is_map_field(field)) {
+    check_map_field_type(val, field);
+    DEREF(memory, VALUE) = val;
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+    check_repeated_field_type(val, field);
+    DEREF(memory, VALUE) = val;
+  } else {
+    native_slot_set(upb_fielddef_type(field), field_type_class(field),
+                    memory, val);
+  }
+}
+
+void layout_init(MessageLayout* layout,
+                 void* storage) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    void* memory = slot_memory(layout, storage, field);
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+      *oneof_case = ONEOF_CASE_NONE;
+    } else if (is_map_field(field)) {
+      VALUE map = Qnil;
+
+      const upb_fielddef* key_field = map_field_key(field);
+      const upb_fielddef* value_field = map_field_value(field);
+      VALUE type_class = field_type_class(value_field);
+
+      if (type_class != Qnil) {
+        VALUE args[3] = {
+          fieldtype_to_ruby(upb_fielddef_type(key_field)),
+          fieldtype_to_ruby(upb_fielddef_type(value_field)),
+          type_class,
+        };
+        map = rb_class_new_instance(3, args, cMap);
+      } else {
+        VALUE args[2] = {
+          fieldtype_to_ruby(upb_fielddef_type(key_field)),
+          fieldtype_to_ruby(upb_fielddef_type(value_field)),
+        };
+        map = rb_class_new_instance(2, args, cMap);
+      }
+
+      DEREF(memory, VALUE) = map;
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      VALUE ary = Qnil;
+
+      VALUE type_class = field_type_class(field);
+
+      if (type_class != Qnil) {
+        VALUE args[2] = {
+          fieldtype_to_ruby(upb_fielddef_type(field)),
+          type_class,
+        };
+        ary = rb_class_new_instance(2, args, cRepeatedField);
+      } else {
+        VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
+        ary = rb_class_new_instance(1, args, cRepeatedField);
+      }
+
+      DEREF(memory, VALUE) = ary;
+    } else {
+      native_slot_init(upb_fielddef_type(field), memory);
+    }
+  }
+}
+
+void layout_mark(MessageLayout* layout, void* storage) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    void* memory = slot_memory(layout, storage, field);
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      if (*oneof_case == upb_fielddef_number(field)) {
+        native_slot_mark(upb_fielddef_type(field), memory);
+      }
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      rb_gc_mark(DEREF(memory, VALUE));
+    } else {
+      native_slot_mark(upb_fielddef_type(field), memory);
+    }
+  }
+}
+
+void layout_dup(MessageLayout* layout, void* to, void* from) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+
+    void* to_memory = slot_memory(layout, to, field);
+    uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
+    void* from_memory = slot_memory(layout, from, field);
+    uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      if (*from_oneof_case == upb_fielddef_number(field)) {
+        *to_oneof_case = *from_oneof_case;
+        native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
+      }
+    } else if (is_map_field(field)) {
+      DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
+    } else {
+      native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
+    }
+  }
+}
+
+void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+
+    void* to_memory = slot_memory(layout, to, field);
+    uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
+    void* from_memory = slot_memory(layout, from, field);
+    uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      if (*from_oneof_case == upb_fielddef_number(field)) {
+        *to_oneof_case = *from_oneof_case;
+        native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
+      }
+    } else if (is_map_field(field)) {
+      DEREF(to_memory, VALUE) =
+          Map_deep_copy(DEREF(from_memory, VALUE));
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      DEREF(to_memory, VALUE) =
+          RepeatedField_deep_copy(DEREF(from_memory, VALUE));
+    } else {
+      native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
+    }
+  }
+}
+
+VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+
+    void* msg1_memory = slot_memory(layout, msg1, field);
+    uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
+    void* msg2_memory = slot_memory(layout, msg2, field);
+    uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      if (*msg1_oneof_case != *msg2_oneof_case ||
+          (*msg1_oneof_case == upb_fielddef_number(field) &&
+           !native_slot_eq(upb_fielddef_type(field),
+                           msg1_memory,
+                           msg2_memory))) {
+        return Qfalse;
+      }
+    } else if (is_map_field(field)) {
+      if (!Map_eq(DEREF(msg1_memory, VALUE),
+                  DEREF(msg2_memory, VALUE))) {
+        return Qfalse;
+      }
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
+                            DEREF(msg2_memory, VALUE))) {
+        return Qfalse;
+      }
+    } else {
+      if (!native_slot_eq(upb_fielddef_type(field),
+                          msg1_memory, msg2_memory)) {
+        return Qfalse;
+      }
+    }
+  }
+  return Qtrue;
+}
+
+VALUE layout_hash(MessageLayout* layout, void* storage) {
+  upb_msg_field_iter it;
+  st_index_t h = rb_hash_start(0);
+  VALUE hash_sym = rb_intern("hash");
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    VALUE field_val = layout_get(layout, storage, field);
+    h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
+  }
+  h = rb_hash_end(h);
+
+  return INT2FIX(h);
+}
+
+VALUE layout_inspect(MessageLayout* layout, void* storage) {
+  VALUE str = rb_str_new2("");
+
+  upb_msg_field_iter it;
+  bool first = true;
+  for (upb_msg_field_begin(&it, layout->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    VALUE field_val = layout_get(layout, storage, field);
+
+    if (!first) {
+      str = rb_str_cat2(str, ", ");
+    } else {
+      first = false;
+    }
+    str = rb_str_cat2(str, upb_fielddef_name(field));
+    str = rb_str_cat2(str, ": ");
+
+    str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
+  }
+
+  return str;
+}
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
new file mode 100644
index 0000000..74a2a1d
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -0,0 +1,12812 @@
+// Amalgamated source file
+#include "upb.h"
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+  size_t len;
+  char str[1];  /* Null-terminated string data follows. */
+} str_t;
+
+static str_t *newstr(const char *data, size_t len) {
+  str_t *ret = upb_gmalloc(sizeof(*ret) + len);
+  if (!ret) return NULL;
+  ret->len = len;
+  memcpy(ret->str, data, len);
+  ret->str[len] = '\0';
+  return ret;
+}
+
+static void freestr(str_t *s) { upb_gfree(s); }
+
+/* isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. */
+static bool upb_isbetween(char c, char low, char high) {
+  return c >= low && c <= high;
+}
+
+static bool upb_isletter(char c) {
+  return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+}
+
+static bool upb_isalphanum(char c) {
+  return upb_isletter(c) || upb_isbetween(c, '0', '9');
+}
+
+static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
+  bool start = true;
+  size_t i;
+  for (i = 0; i < len; i++) {
+    char c = str[i];
+    if (c == '.') {
+      if (start || !full) {
+        upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str);
+        return false;
+      }
+      start = true;
+    } else if (start) {
+      if (!upb_isletter(c)) {
+        upb_status_seterrf(
+            s, "invalid name: path components must start with a letter (%s)",
+            str);
+        return false;
+      }
+      start = false;
+    } else {
+      if (!upb_isalphanum(c)) {
+        upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)",
+                           str);
+        return false;
+      }
+    }
+  }
+  return !start;
+}
+
+static bool upb_isoneof(const upb_refcounted *def) {
+  return def->vtbl == &upb_oneofdef_vtbl;
+}
+
+static bool upb_isfield(const upb_refcounted *def) {
+  return def->vtbl == &upb_fielddef_vtbl;
+}
+
+static const upb_oneofdef *upb_trygetoneof(const upb_refcounted *def) {
+  return upb_isoneof(def) ? (const upb_oneofdef*)def : NULL;
+}
+
+static const upb_fielddef *upb_trygetfield(const upb_refcounted *def) {
+  return upb_isfield(def) ? (const upb_fielddef*)def : NULL;
+}
+
+
+/* upb_def ********************************************************************/
+
+upb_deftype_t upb_def_type(const upb_def *d) { return d->type; }
+
+const char *upb_def_fullname(const upb_def *d) { return d->fullname; }
+
+const char *upb_def_name(const upb_def *d) {
+  const char *p;
+
+  if (d->fullname == NULL) {
+    return NULL;
+  } else if ((p = strrchr(d->fullname, '.')) == NULL) {
+    /* No '.' in the name, return the full string. */
+    return d->fullname;
+  } else {
+    /* Return one past the last '.'. */
+    return p + 1;
+  }
+}
+
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) {
+  assert(!upb_def_isfrozen(def));
+  if (!upb_isident(fullname, strlen(fullname), true, s)) {
+    return false;
+  }
+
+  fullname = upb_gstrdup(fullname);
+  if (!fullname) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  upb_gfree((void*)def->fullname);
+  def->fullname = fullname;
+  return true;
+}
+
+const upb_filedef *upb_def_file(const upb_def *d) { return d->file; }
+
+upb_def *upb_def_dup(const upb_def *def, const void *o) {
+  switch (def->type) {
+    case UPB_DEF_MSG:
+      return upb_msgdef_upcast_mutable(
+          upb_msgdef_dup(upb_downcast_msgdef(def), o));
+    case UPB_DEF_FIELD:
+      return upb_fielddef_upcast_mutable(
+          upb_fielddef_dup(upb_downcast_fielddef(def), o));
+    case UPB_DEF_ENUM:
+      return upb_enumdef_upcast_mutable(
+          upb_enumdef_dup(upb_downcast_enumdef(def), o));
+    default: assert(false); return NULL;
+  }
+}
+
+static bool upb_def_init(upb_def *def, upb_deftype_t type,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+  if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false;
+  def->type = type;
+  def->fullname = NULL;
+  def->came_from_user = false;
+  def->file = NULL;
+  return true;
+}
+
+static void upb_def_uninit(upb_def *def) {
+  upb_gfree((void*)def->fullname);
+}
+
+static const char *msgdef_name(const upb_msgdef *m) {
+  const char *name = upb_def_fullname(upb_msgdef_upcast(m));
+  return name ? name : "(anonymous)";
+}
+
+static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "fielddef must have name and number set");
+    return false;
+  }
+
+  if (!f->type_is_set_) {
+    upb_status_seterrmsg(s, "fielddef type was not initialized");
+    return false;
+  }
+
+  if (upb_fielddef_lazy(f) &&
+      upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    upb_status_seterrmsg(s,
+                         "only length-delimited submessage fields may be lazy");
+    return false;
+  }
+
+  if (upb_fielddef_hassubdef(f)) {
+    const upb_def *subdef;
+
+    if (f->subdef_is_symbolic) {
+      upb_status_seterrf(s, "field '%s.%s' has not been resolved",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    subdef = upb_fielddef_subdef(f);
+    if (subdef == NULL) {
+      upb_status_seterrf(s, "field %s.%s is missing required subdef",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
+      upb_status_seterrf(s,
+                         "subdef of field %s.%s is not frozen or being frozen",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+  }
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    bool has_default_name = upb_fielddef_enumhasdefaultstr(f);
+    bool has_default_number = upb_fielddef_enumhasdefaultint32(f);
+
+    /* Previously verified by upb_validate_enumdef(). */
+    assert(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0);
+
+    /* We've already validated that we have an associated enumdef and that it
+     * has at least one member, so at least one of these should be true.
+     * Because if the user didn't set anything, we'll pick up the enum's
+     * default, but if the user *did* set something we should at least pick up
+     * the one they set (int32 or string). */
+    assert(has_default_name || has_default_number);
+
+    if (!has_default_name) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%d) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultint32(f));
+      return false;
+    }
+
+    if (!has_default_number) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%s) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultstr(f, NULL));
+      return false;
+    }
+
+    /* Lift the effective numeric default into the field's default slot, in case
+     * we were only getting it "by reference" from the enumdef. */
+    upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f));
+  }
+
+  /* Ensure that MapEntry submessages only appear as repeated fields, not
+   * optional/required (singular) fields. */
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+      upb_fielddef_msgsubdef(f) != NULL) {
+    const upb_msgdef *subdef = upb_fielddef_msgsubdef(f);
+    if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) {
+      upb_status_seterrf(s,
+                         "Field %s refers to mapentry message but is not "
+                         "a repeated field",
+                         upb_fielddef_name(f) ? upb_fielddef_name(f) :
+                         "(unnamed)");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) {
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrf(s, "enum %s has no members (must have at least one)",
+                       upb_enumdef_fullname(e));
+    return false;
+  }
+
+  return true;
+}
+
+/* All submessage fields are lower than all other fields.
+ * Secondly, fields are increasing in order. */
+uint32_t field_rank(const upb_fielddef *f) {
+  uint32_t ret = upb_fielddef_number(f);
+  const uint32_t high_bit = 1 << 30;
+  assert(ret < high_bit);
+  if (!upb_fielddef_issubmsg(f))
+    ret |= high_bit;
+  return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+  const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+  const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+  return field_rank(f1) - field_rank(f2);
+}
+
+static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
+  /* Sort fields.  upb internally relies on UPB_TYPE_MESSAGE fields having the
+   * lowest indexes, but we do not publicly guarantee this. */
+  upb_msg_field_iter j;
+  int i;
+  uint32_t selector;
+  int n = upb_msgdef_numfields(m);
+  upb_fielddef **fields;
+
+  if (n == 0) {
+    m->selector_count = UPB_STATIC_SELECTOR_COUNT;
+    m->submsg_field_count = 0;
+    return true;
+  }
+
+  fields = upb_gmalloc(n * sizeof(*fields));
+  if (!fields) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  m->submsg_field_count = 0;
+  for(i = 0, upb_msg_field_begin(&j, m);
+      !upb_msg_field_done(&j);
+      upb_msg_field_next(&j), i++) {
+    upb_fielddef *f = upb_msg_iter_field(&j);
+    assert(f->msg.def == m);
+    if (!upb_validate_field(f, s)) {
+      upb_gfree(fields);
+      return false;
+    }
+    if (upb_fielddef_issubmsg(f)) {
+      m->submsg_field_count++;
+    }
+    fields[i] = f;
+  }
+
+  qsort(fields, n, sizeof(*fields), cmp_fields);
+
+  selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+  for (i = 0; i < n; i++) {
+    upb_fielddef *f = fields[i];
+    f->index_ = i;
+    f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+    selector += upb_handlers_selectorcount(f);
+  }
+  m->selector_count = selector;
+
+#ifndef NDEBUG
+  {
+    /* Verify that all selectors for the message are distinct. */
+#define TRY(type) \
+    if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v);
+
+    upb_inttable t;
+    upb_value v;
+    upb_selector_t sel;
+
+    upb_inttable_init(&t, UPB_CTYPE_BOOL);
+    v = upb_value_bool(true);
+    upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v);
+    upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v);
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      /* These calls will assert-fail in upb_table if the value already
+       * exists. */
+      TRY(UPB_HANDLER_INT32);
+      TRY(UPB_HANDLER_INT64)
+      TRY(UPB_HANDLER_UINT32)
+      TRY(UPB_HANDLER_UINT64)
+      TRY(UPB_HANDLER_FLOAT)
+      TRY(UPB_HANDLER_DOUBLE)
+      TRY(UPB_HANDLER_BOOL)
+      TRY(UPB_HANDLER_STARTSTR)
+      TRY(UPB_HANDLER_STRING)
+      TRY(UPB_HANDLER_ENDSTR)
+      TRY(UPB_HANDLER_STARTSUBMSG)
+      TRY(UPB_HANDLER_ENDSUBMSG)
+      TRY(UPB_HANDLER_STARTSEQ)
+      TRY(UPB_HANDLER_ENDSEQ)
+    }
+    upb_inttable_uninit(&t);
+  }
+#undef TRY
+#endif
+
+  upb_gfree(fields);
+  return true;
+}
+
+bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s) {
+  size_t i;
+
+  /* First perform validation, in two passes so we can check that we have a
+   * transitive closure without needing to search. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    if (upb_def_isfrozen(def)) {
+      /* Could relax this requirement if it's annoying. */
+      upb_status_seterrmsg(s, "def is already frozen");
+      goto err;
+    } else if (def->type == UPB_DEF_FIELD) {
+      upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
+      goto err;
+    } else if (def->type == UPB_DEF_ENUM) {
+      if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) {
+        goto err;
+      }
+    } else {
+      /* Set now to detect transitive closure in the second pass. */
+      def->came_from_user = true;
+    }
+  }
+
+  /* Second pass of validation.  Also assign selector bases and indexes, and
+   * compact tables. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+    upb_enumdef *e = upb_dyncast_enumdef_mutable(def);
+    if (m) {
+      upb_inttable_compact(&m->itof);
+      if (!assign_msg_indices(m, s)) {
+        goto err;
+      }
+    } else if (e) {
+      upb_inttable_compact(&e->iton);
+    }
+  }
+
+  return true;
+
+err:
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    def->came_from_user = false;
+  }
+  assert(!(s && upb_ok(s)));
+  return false;
+}
+
+bool upb_def_freeze(upb_def *const* defs, size_t n, upb_status *s) {
+  /* Def graph contains FieldDefs between each MessageDef, so double the
+   * limit. */
+  const size_t maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
+
+  if (!_upb_def_validate(defs, n, s)) {
+    return false;
+  }
+
+
+  /* Validation all passed; freeze the objects. */
+  return upb_refcounted_freeze((upb_refcounted *const*)defs, n, s, maxdepth);
+}
+
+
+/* upb_enumdef ****************************************************************/
+
+static void upb_enumdef_free(upb_refcounted *r) {
+  upb_enumdef *e = (upb_enumdef*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &e->iton);
+  for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    /* To clean up the upb_gstrdup() from upb_enumdef_addval(). */
+    upb_gfree(upb_value_getcstr(upb_inttable_iter_value(&i)));
+  }
+  upb_strtable_uninit(&e->ntoi);
+  upb_inttable_uninit(&e->iton);
+  upb_def_uninit(upb_enumdef_upcast_mutable(e));
+  upb_gfree(e);
+}
+
+const struct upb_refcounted_vtbl upb_enumdef_vtbl = {NULL, &upb_enumdef_free};
+
+upb_enumdef *upb_enumdef_new(const void *owner) {
+  upb_enumdef *e = upb_gmalloc(sizeof(*e));
+  if (!e) return NULL;
+
+  if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM,
+                    &upb_enumdef_vtbl, owner)) {
+    goto err2;
+  }
+
+  if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2;
+  if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1;
+  return e;
+
+err1:
+  upb_strtable_uninit(&e->ntoi);
+err2:
+  upb_gfree(e);
+  return NULL;
+}
+
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) {
+  upb_enum_iter i;
+  upb_enumdef *new_e = upb_enumdef_new(owner);
+  if (!new_e) return NULL;
+  for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+    bool success = upb_enumdef_addval(
+        new_e, upb_enum_iter_name(&i),upb_enum_iter_number(&i), NULL);
+    if (!success) {
+      upb_enumdef_unref(new_e, owner);
+      return NULL;
+    }
+  }
+  return new_e;
+}
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) {
+  upb_def *d = upb_enumdef_upcast_mutable(e);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_enumdef_fullname(const upb_enumdef *e) {
+  return upb_def_fullname(upb_enumdef_upcast(e));
+}
+
+const char *upb_enumdef_name(const upb_enumdef *e) {
+  return upb_def_name(upb_enumdef_upcast(e));
+}
+
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s) {
+  return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s);
+}
+
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status) {
+  char *name2;
+
+  if (!upb_isident(name, strlen(name), false, status)) {
+    return false;
+  }
+
+  if (upb_enumdef_ntoiz(e, name, NULL)) {
+    upb_status_seterrf(status, "name '%s' is already defined", name);
+    return false;
+  }
+
+  if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+
+  if (!upb_inttable_lookup(&e->iton, num, NULL)) {
+    name2 = upb_gstrdup(name);
+    if (!name2 || !upb_inttable_insert(&e->iton, num, upb_value_cstr(name2))) {
+      upb_status_seterrmsg(status, "out of memory");
+      upb_strtable_remove(&e->ntoi, name, NULL);
+      return false;
+    }
+  }
+
+  if (upb_enumdef_numvals(e) == 1) {
+    bool ok = upb_enumdef_setdefault(e, num, NULL);
+    UPB_ASSERT_VAR(ok, ok);
+  }
+
+  return true;
+}
+
+int32_t upb_enumdef_default(const upb_enumdef *e) {
+  assert(upb_enumdef_iton(e, e->defaultval));
+  return e->defaultval;
+}
+
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) {
+  assert(!upb_enumdef_isfrozen(e));
+  if (!upb_enumdef_iton(e, val)) {
+    upb_status_seterrf(s, "number '%d' is not in the enum.", val);
+    return false;
+  }
+  e->defaultval = val;
+  return true;
+}
+
+int upb_enumdef_numvals(const upb_enumdef *e) {
+  return upb_strtable_count(&e->ntoi);
+}
+
+void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
+  /* We iterate over the ntoi table, to account for duplicate numbers. */
+  upb_strtable_begin(i, &e->ntoi);
+}
+
+void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
+bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
+
+bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
+                      size_t len, int32_t *num) {
+  upb_value v;
+  if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
+    return false;
+  }
+  if (num) *num = upb_value_getint32(v);
+  return true;
+}
+
+const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+  upb_value v;
+  return upb_inttable_lookup32(&def->iton, num, &v) ?
+      upb_value_getcstr(v) : NULL;
+}
+
+const char *upb_enum_iter_name(upb_enum_iter *iter) {
+  return upb_strtable_iter_key(iter);
+}
+
+int32_t upb_enum_iter_number(upb_enum_iter *iter) {
+  return upb_value_getint32(upb_strtable_iter_value(iter));
+}
+
+
+/* upb_fielddef ***************************************************************/
+
+static void upb_fielddef_init_default(upb_fielddef *f);
+
+static void upb_fielddef_uninit_default(upb_fielddef *f) {
+  if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes)
+    freestr(f->defaultval.bytes);
+}
+
+const char *upb_fielddef_fullname(const upb_fielddef *e) {
+  return upb_def_fullname(upb_fielddef_upcast(e));
+}
+
+static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_fielddef *f = (const upb_fielddef*)r;
+  if (upb_fielddef_containingtype(f)) {
+    visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure);
+  }
+  if (upb_fielddef_containingoneof(f)) {
+    visit(r, upb_oneofdef_upcast(upb_fielddef_containingoneof(f)), closure);
+  }
+  if (upb_fielddef_subdef(f)) {
+    visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure);
+  }
+}
+
+static void freefield(upb_refcounted *r) {
+  upb_fielddef *f = (upb_fielddef*)r;
+  upb_fielddef_uninit_default(f);
+  if (f->subdef_is_symbolic)
+    upb_gfree(f->sub.name);
+  upb_def_uninit(upb_fielddef_upcast_mutable(f));
+  upb_gfree(f);
+}
+
+static const char *enumdefaultstr(const upb_fielddef *f) {
+  const upb_enumdef *e;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (f->default_is_string && f->defaultval.bytes) {
+    /* Default was explicitly set as a string. */
+    str_t *s = f->defaultval.bytes;
+    return s->str;
+  } else if (e) {
+    if (!f->default_is_string) {
+      /* Default was explicitly set as an integer; look it up in enumdef. */
+      const char *name = upb_enumdef_iton(e, f->defaultval.sint);
+      if (name) {
+        return name;
+      }
+    } else {
+      /* Default is completely unset; pull enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        const char *name = upb_enumdef_iton(e, upb_enumdef_default(e));
+        assert(name);
+        return name;
+      }
+    }
+  }
+  return NULL;
+}
+
+static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) {
+  const upb_enumdef *e;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (!f->default_is_string) {
+    /* Default was explicitly set as an integer. */
+    *val = f->defaultval.sint;
+    return true;
+  } else if (e) {
+    if (f->defaultval.bytes) {
+      /* Default was explicitly set as a str; try to lookup corresponding int. */
+      str_t *s = f->defaultval.bytes;
+      if (upb_enumdef_ntoiz(e, s->str, val)) {
+        return true;
+      }
+    } else {
+      /* Default is unset; try to pull in enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        *val = upb_enumdef_default(e);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+const struct upb_refcounted_vtbl upb_fielddef_vtbl = {visitfield, freefield};
+
+upb_fielddef *upb_fielddef_new(const void *o) {
+  upb_fielddef *f = upb_gmalloc(sizeof(*f));
+  if (!f) return NULL;
+  if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD,
+                    &upb_fielddef_vtbl, o)) {
+    upb_gfree(f);
+    return NULL;
+  }
+  f->msg.def = NULL;
+  f->sub.def = NULL;
+  f->oneof = NULL;
+  f->subdef_is_symbolic = false;
+  f->msg_is_symbolic = false;
+  f->label_ = UPB_LABEL_OPTIONAL;
+  f->type_ = UPB_TYPE_INT32;
+  f->number_ = 0;
+  f->type_is_set_ = false;
+  f->tagdelim = false;
+  f->is_extension_ = false;
+  f->lazy_ = false;
+  f->packed_ = true;
+
+  /* For the moment we default this to UPB_INTFMT_VARIABLE, since it will work
+   * with all integer types and is in some since more "default" since the most
+   * normal-looking proto2 types int32/int64/uint32/uint64 use variable.
+   *
+   * Other options to consider:
+   * - there is no default; users must set this manually (like type).
+   * - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to
+   *   be an optimal default for signed integers. */
+  f->intfmt = UPB_INTFMT_VARIABLE;
+  return f;
+}
+
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) {
+  const char *srcname;
+  upb_fielddef *newf = upb_fielddef_new(owner);
+  if (!newf) return NULL;
+  upb_fielddef_settype(newf, upb_fielddef_type(f));
+  upb_fielddef_setlabel(newf, upb_fielddef_label(f));
+  upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL);
+  upb_fielddef_setname(newf, upb_fielddef_name(f), NULL);
+  if (f->default_is_string && f->defaultval.bytes) {
+    str_t *s = f->defaultval.bytes;
+    upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL);
+  } else {
+    newf->default_is_string = f->default_is_string;
+    newf->defaultval = f->defaultval;
+  }
+
+  if (f->subdef_is_symbolic) {
+    srcname = f->sub.name;  /* Might be NULL. */
+  } else {
+    srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL;
+  }
+  if (srcname) {
+    char *newname = upb_gmalloc(strlen(f->sub.def->fullname) + 2);
+    if (!newname) {
+      upb_fielddef_unref(newf, owner);
+      return NULL;
+    }
+    strcpy(newname, ".");
+    strcat(newname, f->sub.def->fullname);
+    upb_fielddef_setsubdefname(newf, newname, NULL);
+    upb_gfree(newname);
+  }
+
+  return newf;
+}
+
+bool upb_fielddef_typeisset(const upb_fielddef *f) {
+  return f->type_is_set_;
+}
+
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+  assert(f->type_is_set_);
+  return f->type_;
+}
+
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+  return f->index_;
+}
+
+upb_label_t upb_fielddef_label(const upb_fielddef *f) {
+  return f->label_;
+}
+
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) {
+  return f->intfmt;
+}
+
+bool upb_fielddef_istagdelim(const upb_fielddef *f) {
+  return f->tagdelim;
+}
+
+uint32_t upb_fielddef_number(const upb_fielddef *f) {
+  return f->number_;
+}
+
+bool upb_fielddef_isextension(const upb_fielddef *f) {
+  return f->is_extension_;
+}
+
+bool upb_fielddef_lazy(const upb_fielddef *f) {
+  return f->lazy_;
+}
+
+bool upb_fielddef_packed(const upb_fielddef *f) {
+  return f->packed_;
+}
+
+const char *upb_fielddef_name(const upb_fielddef *f) {
+  return upb_def_fullname(upb_fielddef_upcast(f));
+}
+
+size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len) {
+  const char *name = upb_fielddef_name(f);
+  size_t src, dst = 0;
+  bool ucase_next = false;
+
+#define WRITE(byte) \
+  ++dst; \
+  if (dst < len) buf[dst - 1] = byte; \
+  else if (dst == len) buf[dst - 1] = '\0'
+
+  if (!name) {
+    WRITE('\0');
+    return 0;
+  }
+
+  /* Implement the transformation as described in the spec:
+   *   1. upper case all letters after an underscore.
+   *   2. remove all underscores.
+   */
+  for (src = 0; name[src]; src++) {
+    if (name[src] == '_') {
+      ucase_next = true;
+      continue;
+    }
+
+    if (ucase_next) {
+      WRITE(toupper(name[src]));
+      ucase_next = false;
+    } else {
+      WRITE(name[src]);
+    }
+  }
+
+  WRITE('\0');
+  return dst;
+
+#undef WRITE
+}
+
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+  return f->msg_is_symbolic ? NULL : f->msg.def;
+}
+
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
+  return f->oneof;
+}
+
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) {
+  return (upb_msgdef*)upb_fielddef_containingtype(f);
+}
+
+const char *upb_fielddef_containingtypename(upb_fielddef *f) {
+  return f->msg_is_symbolic ? f->msg.name : NULL;
+}
+
+static void release_containingtype(upb_fielddef *f) {
+  if (f->msg_is_symbolic) upb_gfree(f->msg.name);
+}
+
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s) {
+  char *name_copy;
+  assert(!upb_fielddef_isfrozen(f));
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(s, "field has already been added to a message.");
+    return false;
+  }
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+
+  name_copy = upb_gstrdup(name);
+  if (!name_copy) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  release_containingtype(f);
+  f->msg.name = name_copy;
+  f->msg_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) {
+  if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) {
+    upb_status_seterrmsg(s, "Already added to message or oneof");
+    return false;
+  }
+  return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s);
+}
+
+static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) {
+  UPB_UNUSED(f);
+  UPB_UNUSED(type);
+  assert(f->type_is_set_ && upb_fielddef_type(f) == type);
+}
+
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_INT64);
+  return f->defaultval.sint;
+}
+
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
+  if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    int32_t val;
+    bool ok = enumdefaultint32(f, &val);
+    UPB_ASSERT_VAR(ok, ok);
+    return val;
+  } else {
+    chkdefaulttype(f, UPB_TYPE_INT32);
+    return f->defaultval.sint;
+  }
+}
+
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT64);
+  return f->defaultval.uint;
+}
+
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT32);
+  return f->defaultval.uint;
+}
+
+bool upb_fielddef_defaultbool(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_BOOL);
+  return f->defaultval.uint;
+}
+
+float upb_fielddef_defaultfloat(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_FLOAT);
+  return f->defaultval.flt;
+}
+
+double upb_fielddef_defaultdouble(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_DOUBLE);
+  return f->defaultval.dbl;
+}
+
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
+  assert(f->type_is_set_);
+  assert(upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES ||
+         upb_fielddef_type(f) == UPB_TYPE_ENUM);
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    const char *ret = enumdefaultstr(f);
+    assert(ret);
+    /* Enum defaults can't have embedded NULLs. */
+    if (len) *len = strlen(ret);
+    return ret;
+  }
+
+  if (f->default_is_string) {
+    str_t *str = f->defaultval.bytes;
+    if (len) *len = str->len;
+    return str->str;
+  }
+
+  return NULL;
+}
+
+static void upb_fielddef_init_default(upb_fielddef *f) {
+  f->default_is_string = false;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break;
+    case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break;
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64: f->defaultval.sint = 0; break;
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_BOOL: f->defaultval.uint = 0; break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      f->defaultval.bytes = newstr("", 0);
+      f->default_is_string = true;
+      break;
+    case UPB_TYPE_MESSAGE: break;
+    case UPB_TYPE_ENUM:
+      /* This is our special sentinel that indicates "not set" for an enum. */
+      f->default_is_string = true;
+      f->defaultval.bytes = NULL;
+      break;
+  }
+}
+
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f) {
+  return f->subdef_is_symbolic ? NULL : f->sub.def;
+}
+
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) {
+  return (upb_def*)upb_fielddef_subdef(f);
+}
+
+const char *upb_fielddef_subdefname(const upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    return f->sub.name;
+  } else if (f->sub.def) {
+    return upb_def_fullname(f->sub.def);
+  } else {
+    return NULL;
+  }
+}
+
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(
+        s, "cannot change field number after adding to a message");
+    return false;
+  }
+  if (number == 0 || number > UPB_MAX_FIELDNUMBER) {
+    upb_status_seterrf(s, "invalid field number (%u)", number);
+    return false;
+  }
+  f->number_ = number;
+  return true;
+}
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checktype(type));
+  upb_fielddef_uninit_default(f);
+  f->type_ = type;
+  f->type_is_set_ = true;
+  upb_fielddef_init_default(f);
+}
+
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) {
+  assert(!upb_fielddef_isfrozen(f));
+  switch (type) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+      upb_fielddef_settype(f, UPB_TYPE_DOUBLE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+      upb_fielddef_settype(f, UPB_TYPE_FLOAT);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      upb_fielddef_settype(f, UPB_TYPE_INT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+      upb_fielddef_settype(f, UPB_TYPE_UINT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      upb_fielddef_settype(f, UPB_TYPE_INT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+      upb_fielddef_settype(f, UPB_TYPE_UINT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      upb_fielddef_settype(f, UPB_TYPE_BOOL);
+      break;
+    case UPB_DESCRIPTOR_TYPE_STRING:
+      upb_fielddef_settype(f, UPB_TYPE_STRING);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BYTES:
+      upb_fielddef_settype(f, UPB_TYPE_BYTES);
+      break;
+    case UPB_DESCRIPTOR_TYPE_GROUP:
+    case UPB_DESCRIPTOR_TYPE_MESSAGE:
+      upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      upb_fielddef_settype(f, UPB_TYPE_ENUM);
+      break;
+    default: assert(false);
+  }
+
+  if (type == UPB_DESCRIPTOR_TYPE_FIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_FIXED32 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED);
+  } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 ||
+             type == UPB_DESCRIPTOR_TYPE_SINT32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG);
+  } else {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE);
+  }
+
+  upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP);
+}
+
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_FLOAT:  return UPB_DESCRIPTOR_TYPE_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE;
+    case UPB_TYPE_BOOL:   return UPB_DESCRIPTOR_TYPE_BOOL;
+    case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING;
+    case UPB_TYPE_BYTES:  return UPB_DESCRIPTOR_TYPE_BYTES;
+    case UPB_TYPE_ENUM:   return UPB_DESCRIPTOR_TYPE_ENUM;
+    case UPB_TYPE_INT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED32;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT32;
+      }
+    case UPB_TYPE_INT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED64;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT64;
+      }
+    case UPB_TYPE_UINT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED32;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_UINT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED64;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_MESSAGE:
+      return upb_fielddef_istagdelim(f) ?
+          UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE;
+  }
+  return 0;
+}
+
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->is_extension_ = is_extension;
+}
+
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->lazy_ = lazy;
+}
+
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->packed_ = packed;
+}
+
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checklabel(label));
+  f->label_ = label;
+}
+
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_checkintfmt(fmt));
+  f->intfmt = fmt;
+}
+
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) {
+  assert(!upb_fielddef_isfrozen(f));
+  f->tagdelim = tag_delim;
+  f->tagdelim = tag_delim;
+}
+
+static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) {
+  if (!f->type_is_set_ || upb_fielddef_isfrozen(f) ||
+      upb_fielddef_type(f) != type) {
+    assert(false);
+    return false;
+  }
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    assert(s || type == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  }
+  f->default_is_string = false;
+  return true;
+}
+
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) {
+  if (checksetdefault(f, UPB_TYPE_INT64))
+    f->defaultval.sint = value;
+}
+
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) {
+  if ((upb_fielddef_type(f) == UPB_TYPE_ENUM &&
+       checksetdefault(f, UPB_TYPE_ENUM)) ||
+      checksetdefault(f, UPB_TYPE_INT32)) {
+    f->defaultval.sint = value;
+  }
+}
+
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT64))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT32))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) {
+  if (checksetdefault(f, UPB_TYPE_BOOL))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) {
+  if (checksetdefault(f, UPB_TYPE_FLOAT))
+    f->defaultval.flt = value;
+}
+
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) {
+  if (checksetdefault(f, UPB_TYPE_DOUBLE))
+    f->defaultval.dbl = value;
+}
+
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s) {
+  str_t *str2;
+  assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM);
+  if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s))
+    return false;
+
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    assert(s || f->type_ == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  } else {
+    assert(f->type_ == UPB_TYPE_ENUM);
+  }
+
+  str2 = newstr(str, len);
+  f->defaultval.bytes = str2;
+  f->default_is_string = true;
+  return true;
+}
+
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s) {
+  assert(f->type_is_set_);
+  upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s);
+}
+
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) {
+  int32_t val;
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultint32(f, &val);
+}
+
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) {
+  assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultstr(f) != NULL;
+}
+
+static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
+                                 upb_status *s) {
+  if (f->type_ == UPB_TYPE_MESSAGE) {
+    if (upb_dyncast_msgdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
+    return false;
+  } else if (f->type_ == UPB_TYPE_ENUM) {
+    if (upb_dyncast_enumdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this enum field");
+    return false;
+  } else {
+    upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
+    return false;
+  }
+}
+
+static void release_subdef(upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    upb_gfree(f->sub.name);
+  } else if (f->sub.def) {
+    upb_unref2(f->sub.def, f);
+  }
+}
+
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s) {
+  assert(!upb_fielddef_isfrozen(f));
+  assert(upb_fielddef_hassubdef(f));
+  if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false;
+  release_subdef(f);
+  f->sub.def = subdef;
+  f->subdef_is_symbolic = false;
+  if (f->sub.def) upb_ref2(f->sub.def, f);
+  return true;
+}
+
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_msgdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s) {
+  char *name_copy;
+  assert(!upb_fielddef_isfrozen(f));
+  if (!upb_fielddef_hassubdef(f)) {
+    upb_status_seterrmsg(s, "field type does not accept a subdef");
+    return false;
+  }
+
+  name_copy = upb_gstrdup(name);
+  if (!name_copy) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+  release_subdef(f);
+  f->sub.name = name_copy;
+  f->subdef_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_issubmsg(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+}
+
+bool upb_fielddef_isstring(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES;
+}
+
+bool upb_fielddef_isseq(const upb_fielddef *f) {
+  return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+}
+
+bool upb_fielddef_isprimitive(const upb_fielddef *f) {
+  return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+}
+
+bool upb_fielddef_ismap(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
+         upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+}
+
+bool upb_fielddef_haspresence(const upb_fielddef *f) {
+  if (upb_fielddef_isseq(f)) return false;
+  if (upb_fielddef_issubmsg(f)) return true;
+
+  /* Primitive field: return true unless there is a message that specifies
+   * presence should not exist. */
+  if (f->msg_is_symbolic || !f->msg.def) return true;
+  return f->msg.def->syntax == UPB_SYNTAX_PROTO2;
+}
+
+bool upb_fielddef_hassubdef(const upb_fielddef *f) {
+  return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+}
+
+static bool between(int32_t x, int32_t low, int32_t high) {
+  return x >= low && x <= high;
+}
+
+bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+
+bool upb_fielddef_checkdescriptortype(int32_t type) {
+  return between(type, 1, 18);
+}
+
+/* upb_msgdef *****************************************************************/
+
+static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit,
+                     void *closure) {
+  upb_msg_oneof_iter o;
+  const upb_msgdef *m = (const upb_msgdef*)r;
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  for(upb_msg_oneof_begin(&o, m);
+      !upb_msg_oneof_done(&o);
+      upb_msg_oneof_next(&o)) {
+    upb_oneofdef *f = upb_msg_iter_oneof(&o);
+    visit(r, upb_oneofdef_upcast(f), closure);
+  }
+}
+
+static void freemsg(upb_refcounted *r) {
+  upb_msgdef *m = (upb_msgdef*)r;
+  upb_strtable_uninit(&m->ntof);
+  upb_inttable_uninit(&m->itof);
+  upb_def_uninit(upb_msgdef_upcast_mutable(m));
+  upb_gfree(m);
+}
+
+const struct upb_refcounted_vtbl upb_msgdef_vtbl = {visitmsg, freemsg};
+
+upb_msgdef *upb_msgdef_new(const void *owner) {
+  upb_msgdef *m = upb_gmalloc(sizeof(*m));
+  if (!m) return NULL;
+
+  if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &upb_msgdef_vtbl,
+                    owner)) {
+    goto err2;
+  }
+
+  if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1;
+  m->map_entry = false;
+  m->syntax = UPB_SYNTAX_PROTO2;
+  return m;
+
+err1:
+  upb_inttable_uninit(&m->itof);
+err2:
+  upb_gfree(m);
+  return NULL;
+}
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
+  bool ok;
+  upb_msg_field_iter i;
+  upb_msg_oneof_iter o;
+
+  upb_msgdef *newm = upb_msgdef_new(owner);
+  if (!newm) return NULL;
+  ok = upb_def_setfullname(upb_msgdef_upcast_mutable(newm),
+                           upb_def_fullname(upb_msgdef_upcast(m)),
+                           NULL);
+  newm->map_entry = m->map_entry;
+  newm->syntax = m->syntax;
+  UPB_ASSERT_VAR(ok, ok);
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
+    /* Fields in oneofs are dup'd below. */
+    if (upb_fielddef_containingoneof(f)) continue;
+    if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) {
+      upb_msgdef_unref(newm, owner);
+      return NULL;
+    }
+  }
+  for(upb_msg_oneof_begin(&o, m);
+      !upb_msg_oneof_done(&o);
+      upb_msg_oneof_next(&o)) {
+    upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f);
+    if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) {
+      upb_msgdef_unref(newm, owner);
+      return NULL;
+    }
+  }
+  return newm;
+}
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) {
+  upb_def *d = upb_msgdef_upcast_mutable(m);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_msgdef_fullname(const upb_msgdef *m) {
+  return upb_def_fullname(upb_msgdef_upcast(m));
+}
+
+const char *upb_msgdef_name(const upb_msgdef *m) {
+  return upb_def_name(upb_msgdef_upcast(m));
+}
+
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname,
+                            upb_status *s) {
+  return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s);
+}
+
+bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax) {
+  if (syntax != UPB_SYNTAX_PROTO2 && syntax != UPB_SYNTAX_PROTO3) {
+    return false;
+  }
+
+  m->syntax = syntax;
+  return true;
+}
+
+upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) {
+  return m->syntax;
+}
+
+/* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error
+ * on status |s| and return false if not. */
+static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f,
+                            upb_status *s) {
+  if (upb_fielddef_containingtype(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a message");
+    return false;
+  } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_msgdef_itof(m, upb_fielddef_number(f))) {
+    upb_status_seterrmsg(s, "duplicate field number");
+    return false;
+  } else if (upb_strtable_lookup(&m->ntof, upb_fielddef_name(f), NULL)) {
+    upb_status_seterrmsg(s, "name conflicts with existing field or oneof");
+    return false;
+  }
+  return true;
+}
+
+static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) {
+  release_containingtype(f);
+  f->msg.def = m;
+  f->msg_is_symbolic = false;
+  upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, m);
+  upb_ref2(m, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+}
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s) {
+  /* TODO: extensions need to have a separate namespace, because proto2 allows a
+   * top-level extension (ie. one not in any package) to have the same name as a
+   * field from the message.
+   *
+   * This also implies that there needs to be a separate lookup-by-name method
+   * for extensions.  It seems desirable for iteration to return both extensions
+   * and non-extensions though.
+   *
+   * We also need to validate that the field number is in an extension range iff
+   * it is an extension.
+   *
+   * This method is idempotent. Check if |f| is already part of this msgdef and
+   * return immediately if so. */
+  if (upb_fielddef_containingtype(f) == m) {
+    return true;
+  }
+
+  /* Check constraints for all fields before performing any action. */
+  if (!check_field_add(m, f, s)) {
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    /* Fields in a oneof can only be added by adding the oneof to the msgdef. */
+    upb_status_seterrmsg(s, "fielddef is part of a oneof");
+    return false;
+  }
+
+  /* Constraint checks ok, perform the action. */
+  add_field(m, f, ref_donor);
+  return true;
+}
+
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s) {
+  upb_oneof_iter it;
+
+  /* Check various conditions that would prevent this oneof from being added. */
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneofdef already belongs to a message");
+    return false;
+  } else if (upb_oneofdef_name(o) == NULL) {
+    upb_status_seterrmsg(s, "oneofdef name was not set");
+    return false;
+  } else if (upb_strtable_lookup(&m->ntof, upb_oneofdef_name(o), NULL)) {
+    upb_status_seterrmsg(s, "name conflicts with existing field or oneof");
+    return false;
+  }
+
+  /* Check that all of the oneof's fields do not conflict with names or numbers
+   * of fields already in the message. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&it);
+    if (!check_field_add(m, f, s)) {
+      return false;
+    }
+  }
+
+  /* Everything checks out -- commit now. */
+
+  /* Add oneof itself first. */
+  o->parent = m;
+  upb_strtable_insert(&m->ntof, upb_oneofdef_name(o), upb_value_ptr(o));
+  upb_ref2(o, m);
+  upb_ref2(m, o);
+
+  /* Add each field of the oneof directly to the msgdef. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    upb_fielddef *f = upb_oneof_iter_field(&it);
+    add_field(m, f, NULL);
+  }
+
+  if (ref_donor) upb_oneofdef_unref(o, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+  upb_value val;
+  return upb_inttable_lookup32(&m->itof, i, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return NULL;
+  }
+
+  return upb_trygetfield(upb_value_getptr(val));
+}
+
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return NULL;
+  }
+
+  return upb_trygetoneof(upb_value_getptr(val));
+}
+
+bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
+                           const upb_fielddef **f, const upb_oneofdef **o) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return false;
+  }
+
+  *o = upb_trygetoneof(upb_value_getptr(val));
+  *f = upb_trygetfield(upb_value_getptr(val));
+  assert((*o != NULL) ^ (*f != NULL));  /* Exactly one of the two should be set. */
+  return true;
+}
+
+int upb_msgdef_numfields(const upb_msgdef *m) {
+  /* The number table contains only fields. */
+  return upb_inttable_count(&m->itof);
+}
+
+int upb_msgdef_numoneofs(const upb_msgdef *m) {
+  /* The name table includes oneofs, and the number table does not. */
+  return upb_strtable_count(&m->ntof) - upb_inttable_count(&m->itof);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) {
+  assert(!upb_msgdef_isfrozen(m));
+  m->map_entry = map_entry;
+}
+
+bool upb_msgdef_mapentry(const upb_msgdef *m) {
+  return m->map_entry;
+}
+
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
+  upb_inttable_begin(iter, &m->itof);
+}
+
+void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
+
+bool upb_msg_field_done(const upb_msg_field_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
+  upb_strtable_begin(iter, &m->ntof);
+  /* We need to skip past any initial fields. */
+  while (!upb_strtable_done(iter) &&
+         !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))) {
+    upb_strtable_next(iter);
+  }
+}
+
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter) {
+  /* We need to skip past fields to return only oneofs. */
+  do {
+    upb_strtable_next(iter);
+  } while (!upb_strtable_done(iter) &&
+           !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter))));
+}
+
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
+  return upb_strtable_done(iter);
+}
+
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
+  return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter));
+}
+
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
+  upb_strtable_iter_setdone(iter);
+}
+
+/* upb_oneofdef ***************************************************************/
+
+static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_oneofdef *o = (const upb_oneofdef*)r;
+  upb_oneof_iter i;
+  for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  if (o->parent) {
+    visit(r, upb_msgdef_upcast2(o->parent), closure);
+  }
+}
+
+static void freeoneof(upb_refcounted *r) {
+  upb_oneofdef *o = (upb_oneofdef*)r;
+  upb_strtable_uninit(&o->ntof);
+  upb_inttable_uninit(&o->itof);
+  upb_gfree((void*)o->name);
+  upb_gfree(o);
+}
+
+const struct upb_refcounted_vtbl upb_oneofdef_vtbl = {visitoneof, freeoneof};
+
+upb_oneofdef *upb_oneofdef_new(const void *owner) {
+  upb_oneofdef *o = upb_gmalloc(sizeof(*o));
+
+  if (!o) {
+    return NULL;
+  }
+
+  o->parent = NULL;
+  o->name = NULL;
+
+  if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &upb_oneofdef_vtbl,
+                           owner)) {
+    goto err2;
+  }
+
+  if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1;
+
+  return o;
+
+err1:
+  upb_inttable_uninit(&o->itof);
+err2:
+  upb_gfree(o);
+  return NULL;
+}
+
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) {
+  bool ok;
+  upb_oneof_iter i;
+  upb_oneofdef *newo = upb_oneofdef_new(owner);
+  if (!newo) return NULL;
+  ok = upb_oneofdef_setname(newo, upb_oneofdef_name(o), NULL);
+  UPB_ASSERT_VAR(ok, ok);
+  for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f);
+    if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) {
+      upb_oneofdef_unref(newo, owner);
+      return NULL;
+    }
+  }
+  return newo;
+}
+
+const char *upb_oneofdef_name(const upb_oneofdef *o) { return o->name; }
+
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) {
+  assert(!upb_oneofdef_isfrozen(o));
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneof already added to a message");
+    return false;
+  }
+
+  if (!upb_isident(name, strlen(name), true, s)) {
+    return false;
+  }
+
+  name = upb_gstrdup(name);
+  if (!name) {
+    upb_status_seterrmsg(s, "One of memory");
+    return false;
+  }
+
+  upb_gfree((void*)o->name);
+  o->name = name;
+  return true;
+}
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+  return o->parent;
+}
+
+int upb_oneofdef_numfields(const upb_oneofdef *o) {
+  return upb_strtable_count(&o->ntof);
+}
+
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s) {
+  assert(!upb_oneofdef_isfrozen(o));
+  assert(!o->parent || !upb_msgdef_isfrozen(o->parent));
+
+  /* This method is idempotent. Check if |f| is already part of this oneofdef
+   * and return immediately if so. */
+  if (upb_fielddef_containingoneof(f) == o) {
+    return true;
+  }
+
+  /* The field must have an OPTIONAL label. */
+  if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+    upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label");
+    return false;
+  }
+
+  /* Check that no field with this name or number exists already in the oneof.
+   * Also check that the field is not already part of a oneof. */
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) ||
+             upb_oneofdef_ntofz(o, upb_fielddef_name(f))) {
+    upb_status_seterrmsg(s, "duplicate field name or number");
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a oneof");
+    return false;
+  }
+
+  /* We allow adding a field to the oneof either if the field is not part of a
+   * msgdef, or if it is and we are also part of the same msgdef. */
+  if (o->parent == NULL) {
+    /* If we're not in a msgdef, the field cannot be either. Otherwise we would
+     * need to magically add this oneof to a msgdef to remain consistent, which
+     * is surprising behavior. */
+    if (upb_fielddef_containingtype(f) != NULL) {
+      upb_status_seterrmsg(s, "fielddef already belongs to a message, but "
+                              "oneof does not");
+      return false;
+    }
+  } else {
+    /* If we're in a msgdef, the user can add fields that either aren't in any
+     * msgdef (in which case they're added to our msgdef) or already a part of
+     * our msgdef. */
+    if (upb_fielddef_containingtype(f) != NULL &&
+        upb_fielddef_containingtype(f) != o->parent) {
+      upb_status_seterrmsg(s, "fielddef belongs to a different message "
+                              "than oneof");
+      return false;
+    }
+  }
+
+  /* Commit phase. First add the field to our parent msgdef, if any, because
+   * that may fail; then add the field to our own tables. */
+
+  if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) {
+    if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) {
+      return false;
+    }
+  }
+
+  release_containingtype(f);
+  f->oneof = o;
+  upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, o);
+  upb_ref2(o, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length) {
+  upb_value val;
+  return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+  upb_value val;
+  return upb_inttable_lookup32(&o->itof, num, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
+  upb_inttable_begin(iter, &o->itof);
+}
+
+void upb_oneof_next(upb_oneof_iter *iter) {
+  upb_inttable_next(iter);
+}
+
+bool upb_oneof_done(upb_oneof_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+/* upb_filedef ****************************************************************/
+
+static void visitfiledef(const upb_refcounted *r, upb_refcounted_visit *visit,
+                         void *closure) {
+  const upb_filedef *f = (const upb_filedef*)r;
+  size_t i;
+
+  for(i = 0; i < upb_filedef_defcount(f); i++) {
+    visit(r, upb_def_upcast(upb_filedef_def(f, i)), closure);
+  }
+}
+
+static void freefiledef(upb_refcounted *r) {
+  upb_filedef *f = (upb_filedef*)r;
+  size_t i;
+
+  for(i = 0; i < upb_filedef_depcount(f); i++) {
+    upb_filedef_unref(upb_filedef_dep(f, i), f);
+  }
+
+  upb_inttable_uninit(&f->defs);
+  upb_inttable_uninit(&f->deps);
+  upb_gfree((void*)f->name);
+  upb_gfree((void*)f->package);
+  upb_gfree(f);
+}
+
+const struct upb_refcounted_vtbl upb_filedef_vtbl = {visitfiledef, freefiledef};
+
+upb_filedef *upb_filedef_new(const void *owner) {
+  upb_filedef *f = upb_gmalloc(sizeof(*f));
+
+  if (!f) {
+    return NULL;
+  }
+
+  f->package = NULL;
+  f->name = NULL;
+  f->syntax = UPB_SYNTAX_PROTO2;
+
+  if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &upb_filedef_vtbl,
+                           owner)) {
+    goto err;
+  }
+
+  if (!upb_inttable_init(&f->defs, UPB_CTYPE_CONSTPTR)) {
+    goto err;
+  }
+
+  if (!upb_inttable_init(&f->deps, UPB_CTYPE_CONSTPTR)) {
+    goto err2;
+  }
+
+  return f;
+
+
+err2:
+  upb_inttable_uninit(&f->defs);
+
+err:
+  upb_gfree(f);
+  return NULL;
+}
+
+const char *upb_filedef_name(const upb_filedef *f) {
+  return f->name;
+}
+
+const char *upb_filedef_package(const upb_filedef *f) {
+  return f->package;
+}
+
+upb_syntax_t upb_filedef_syntax(const upb_filedef *f) {
+  return f->syntax;
+}
+
+size_t upb_filedef_defcount(const upb_filedef *f) {
+  return upb_inttable_count(&f->defs);
+}
+
+size_t upb_filedef_depcount(const upb_filedef *f) {
+  return upb_inttable_count(&f->deps);
+}
+
+const upb_def *upb_filedef_def(const upb_filedef *f, size_t i) {
+  upb_value v;
+
+  if (upb_inttable_lookup32(&f->defs, i, &v)) {
+    return upb_value_getconstptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i) {
+  upb_value v;
+
+  if (upb_inttable_lookup32(&f->deps, i, &v)) {
+    return upb_value_getconstptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) {
+  name = upb_gstrdup(name);
+  if (!name) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->name);
+  f->name = name;
+  return true;
+}
+
+bool upb_filedef_setpackage(upb_filedef *f, const char *package,
+                            upb_status *s) {
+  if (!upb_isident(package, strlen(package), true, s)) return false;
+  package = upb_gstrdup(package);
+  if (!package) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->package);
+  f->package = package;
+  return true;
+}
+
+bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax,
+                           upb_status *s) {
+  UPB_UNUSED(s);
+  if (syntax != UPB_SYNTAX_PROTO2 &&
+      syntax != UPB_SYNTAX_PROTO3) {
+    upb_status_seterrmsg(s, "Unknown syntax value.");
+    return false;
+  }
+  f->syntax = syntax;
+
+  {
+    /* Set all messages in this file to match. */
+    size_t i;
+    for (i = 0; i < upb_filedef_defcount(f); i++) {
+      /* Casting const away is safe since all defs in mutable filedef must
+       * also be mutable. */
+      upb_def *def = (upb_def*)upb_filedef_def(f, i);
+
+      upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+      if (m) {
+        m->syntax = syntax;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor,
+                        upb_status *s) {
+  if (def->file) {
+    upb_status_seterrmsg(s, "Def is already part of another filedef.");
+    return false;
+  }
+
+  if (upb_inttable_push(&f->defs, upb_value_constptr(def))) {
+    def->file = f;
+    upb_ref2(def, f);
+    if (ref_donor) upb_def_unref(def, ref_donor);
+    if (def->type == UPB_DEF_MSG) {
+      upb_downcast_msgdef_mutable(def)->syntax = f->syntax;
+    }
+    return true;
+  } else {
+    upb_upberr_setoom(s);
+    return false;
+  }
+}
+
+bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) {
+  if (upb_inttable_push(&f->deps, upb_value_constptr(dep))) {
+    /* Regular ref instead of ref2 because files can't form cycles. */
+    upb_filedef_ref(dep, f);
+    return true;
+  } else {
+    return false;
+  }
+}
+/*
+** TODO(haberman): it's unclear whether a lot of the consistency checks should
+** assert() or return false.
+*/
+
+
+#include <string.h>
+
+
+static void *upb_calloc(size_t size) {
+  void *mem = upb_gmalloc(size);
+  if (mem) {
+    memset(mem, 0, size);
+  }
+  return mem;
+}
+
+/* Defined for the sole purpose of having a unique pointer value for
+ * UPB_NO_CLOSURE. */
+char _upb_noclosure;
+
+static void freehandlers(upb_refcounted *r) {
+  upb_handlers *h = (upb_handlers*)r;
+
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &h->cleanup_);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    void *val = (void*)upb_inttable_iter_key(&i);
+    upb_value func_val = upb_inttable_iter_value(&i);
+    upb_handlerfree *func = upb_value_getfptr(func_val);
+    func(val);
+  }
+
+  upb_inttable_uninit(&h->cleanup_);
+  upb_msgdef_unref(h->msg, h);
+  upb_gfree(h->sub);
+  upb_gfree(h);
+}
+
+static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
+                          void *closure) {
+  const upb_handlers *h = (const upb_handlers*)r;
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, h->msg);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub;
+    if (!upb_fielddef_issubmsg(f)) continue;
+    sub = upb_handlers_getsubhandlers(h, f);
+    if (sub) visit(r, upb_handlers_upcast(sub), closure);
+  }
+}
+
+static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
+
+typedef struct {
+  upb_inttable tab;  /* maps upb_msgdef* -> upb_handlers*. */
+  upb_handlers_callback *callback;
+  const void *closure;
+} dfs_state;
+
+/* TODO(haberman): discard upb_handlers* objects that do not actually have any
+ * handlers set and cannot reach any upb_handlers* object that does.  This is
+ * slightly tricky to do correctly. */
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
+                               dfs_state *s) {
+  upb_msg_field_iter i;
+  upb_handlers *h = upb_handlers_new(m, owner);
+  if (!h) return NULL;
+  if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+
+  s->callback(s->closure, h);
+
+  /* For each submessage field, get or create a handlers object and set it as
+   * the subhandlers. */
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_msgdef *subdef;
+    upb_value subm_ent;
+
+    if (!upb_fielddef_issubmsg(f)) continue;
+
+    subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+    if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
+      upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
+    } else {
+      upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
+      if (!sub_mh) goto oom;
+      upb_handlers_setsubhandlers(h, f, sub_mh);
+      upb_handlers_unref(sub_mh, &sub_mh);
+    }
+  }
+  return h;
+
+oom:
+  upb_handlers_unref(h, owner);
+  return NULL;
+}
+
+/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
+ * subhandlers for this submessage field. */
+#define SUBH(h, selector) (h->sub[selector])
+
+/* The selector for a submessage field is the field index. */
+#define SUBH_F(h, f) SUBH(h, f->index_)
+
+static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
+                         upb_handlertype_t type) {
+  upb_selector_t sel;
+  assert(!upb_handlers_isfrozen(h));
+  if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
+    upb_status_seterrf(
+        &h->status_, "type mismatch: field %s does not belong to message %s",
+        upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
+    return -1;
+  }
+  if (!upb_handlers_getselector(f, type, &sel)) {
+    upb_status_seterrf(
+        &h->status_,
+        "type mismatch: cannot register handler type %d for field %s",
+        type, upb_fielddef_name(f));
+    return -1;
+  }
+  return sel;
+}
+
+static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f,
+                             upb_handlertype_t type) {
+  int32_t sel = trygetsel(h, f, type);
+  assert(sel >= 0);
+  return sel;
+}
+
+static const void **returntype(upb_handlers *h, const upb_fielddef *f,
+                               upb_handlertype_t type) {
+  return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_;
+}
+
+static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f,
+                  upb_handlertype_t type, upb_func *func,
+                  upb_handlerattr *attr) {
+  upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
+  const void *closure_type;
+  const void **context_closure_type;
+
+  assert(!upb_handlers_isfrozen(h));
+
+  if (sel < 0) {
+    upb_status_seterrmsg(&h->status_,
+                         "incorrect handler type for this field.");
+    return false;
+  }
+
+  if (h->table[sel].func) {
+    upb_status_seterrmsg(&h->status_,
+                         "cannot change handler once it has been set.");
+    return false;
+  }
+
+  if (attr) {
+    set_attr = *attr;
+  }
+
+  /* Check that the given closure type matches the closure type that has been
+   * established for this context (if any). */
+  closure_type = upb_handlerattr_closuretype(&set_attr);
+
+  if (type == UPB_HANDLER_STRING) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR);
+  } else if (f && upb_fielddef_isseq(f) &&
+             type != UPB_HANDLER_STARTSEQ &&
+             type != UPB_HANDLER_ENDSEQ) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ);
+  } else {
+    context_closure_type = &h->top_closure_type;
+  }
+
+  if (closure_type && *context_closure_type &&
+      closure_type != *context_closure_type) {
+    /* TODO(haberman): better message for debugging. */
+    if (f) {
+      upb_status_seterrf(&h->status_,
+                         "closure type does not match for field %s",
+                         upb_fielddef_name(f));
+    } else {
+      upb_status_seterrmsg(
+          &h->status_, "closure type does not match for message-level handler");
+    }
+    return false;
+  }
+
+  if (closure_type)
+    *context_closure_type = closure_type;
+
+  /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer
+   * matches any pre-existing expectations about what type is expected. */
+  if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) {
+    const void *return_type = upb_handlerattr_returnclosuretype(&set_attr);
+    const void *table_return_type =
+        upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+    if (return_type && table_return_type && return_type != table_return_type) {
+      upb_status_seterrmsg(&h->status_, "closure return type does not match");
+      return false;
+    }
+
+    if (table_return_type && !return_type)
+      upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type);
+  }
+
+  h->table[sel].func = (upb_func*)func;
+  h->table[sel].attr = set_attr;
+  return true;
+}
+
+/* Returns the effective closure type for this handler (which will propagate
+ * from outer frames if this frame has no START* handler).  Not implemented for
+ * UPB_HANDLER_STRING at the moment since this is not needed.  Returns NULL is
+ * the effective closure type is unspecified (either no handler was registered
+ * to specify it or the handler that was registered did not specify the closure
+ * type). */
+const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f,
+                                   upb_handlertype_t type) {
+  const void *ret;
+  upb_selector_t sel;
+
+  assert(type != UPB_HANDLER_STRING);
+  ret = h->top_closure_type;
+
+  if (upb_fielddef_isseq(f) &&
+      type != UPB_HANDLER_STARTSEQ &&
+      type != UPB_HANDLER_ENDSEQ &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  if (type == UPB_HANDLER_STRING &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  /* The effective type of the submessage; not used yet.
+   * if (type == SUBMESSAGE &&
+   *     h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) {
+   *   ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+   * } */
+
+  return ret;
+}
+
+/* Checks whether the START* handler specified by f & type is missing even
+ * though it is required to convert the established type of an outer frame
+ * ("closure_type") into the established type of an inner frame (represented in
+ * the return closure type of this handler's attr. */
+bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type,
+                upb_status *status) {
+  const void *closure_type;
+  const upb_handlerattr *attr;
+  const void *return_closure_type;
+
+  upb_selector_t sel = handlers_getsel(h, f, type);
+  if (h->table[sel].func) return true;
+  closure_type = effective_closure_type(h, f, type);
+  attr = &h->table[sel].attr;
+  return_closure_type = upb_handlerattr_returnclosuretype(attr);
+  if (closure_type && return_closure_type &&
+      closure_type != return_closure_type) {
+    upb_status_seterrf(status,
+                       "expected start handler to return sub type for field %f",
+                       upb_fielddef_name(f));
+    return false;
+  }
+  return true;
+}
+
+/* Public interface ***********************************************************/
+
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+  int extra;
+  upb_handlers *h;
+
+  assert(upb_msgdef_isfrozen(md));
+
+  extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+  h = upb_calloc(sizeof(*h) + extra);
+  if (!h) return NULL;
+
+  h->msg = md;
+  upb_msgdef_ref(h->msg, h);
+  upb_status_clear(&h->status_);
+
+  if (md->submsg_field_count > 0) {
+    h->sub = upb_calloc(md->submsg_field_count * sizeof(*h->sub));
+    if (!h->sub) goto oom;
+  } else {
+    h->sub = 0;
+  }
+
+  if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner))
+    goto oom;
+  if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom;
+
+  /* calloc() above initialized all handlers to NULL. */
+  return h;
+
+oom:
+  freehandlers(upb_handlers_upcast_mutable(h));
+  return NULL;
+}
+
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure) {
+  dfs_state state;
+  upb_handlers *ret;
+  bool ok;
+  upb_refcounted *r;
+
+  state.callback = callback;
+  state.closure = closure;
+  if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
+
+  ret = newformsg(m, owner, &state);
+
+  upb_inttable_uninit(&state.tab);
+  if (!ret) return NULL;
+
+  r = upb_handlers_upcast_mutable(ret);
+  ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
+  UPB_ASSERT_VAR(ok, ok);
+
+  return ret;
+}
+
+const upb_status *upb_handlers_status(upb_handlers *h) {
+  assert(!upb_handlers_isfrozen(h));
+  return &h->status_;
+}
+
+void upb_handlers_clearerr(upb_handlers *h) {
+  assert(!upb_handlers_isfrozen(h));
+  upb_status_clear(&h->status_);
+}
+
+#define SETTER(name, handlerctype, handlertype) \
+  bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
+                                handlerctype func, upb_handlerattr *attr) { \
+    int32_t sel = trygetsel(h, f, handlertype); \
+    return doset(h, sel, f, handlertype, (upb_func*)func, attr); \
+  }
+
+SETTER(int32,       upb_int32_handlerfunc*,       UPB_HANDLER_INT32)
+SETTER(int64,       upb_int64_handlerfunc*,       UPB_HANDLER_INT64)
+SETTER(uint32,      upb_uint32_handlerfunc*,      UPB_HANDLER_UINT32)
+SETTER(uint64,      upb_uint64_handlerfunc*,      UPB_HANDLER_UINT64)
+SETTER(float,       upb_float_handlerfunc*,       UPB_HANDLER_FLOAT)
+SETTER(double,      upb_double_handlerfunc*,      UPB_HANDLER_DOUBLE)
+SETTER(bool,        upb_bool_handlerfunc*,        UPB_HANDLER_BOOL)
+SETTER(startstr,    upb_startstr_handlerfunc*,    UPB_HANDLER_STARTSTR)
+SETTER(string,      upb_string_handlerfunc*,      UPB_HANDLER_STRING)
+SETTER(endstr,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSTR)
+SETTER(startseq,    upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSEQ)
+SETTER(startsubmsg, upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSUBMSG)
+SETTER(endsubmsg,   upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSUBMSG)
+SETTER(endseq,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSEQ)
+
+#undef SETTER
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr) {
+  return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr) {
+  assert(!upb_handlers_isfrozen(h));
+  return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub) {
+  assert(sub);
+  assert(!upb_handlers_isfrozen(h));
+  assert(upb_fielddef_issubmsg(f));
+  if (SUBH_F(h, f)) return false;  /* Can't reset. */
+  if (upb_msgdef_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+    return false;
+  }
+  SUBH_F(h, f) = sub;
+  upb_ref2(sub, h);
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f) {
+  assert(upb_fielddef_issubmsg(f));
+  return SUBH_F(h, f);
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel,
+                          upb_handlerattr *attr) {
+  if (!upb_handlers_gethandler(h, sel))
+    return false;
+  *attr = h->table[sel].attr;
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel) {
+  /* STARTSUBMSG selector in sel is the field's selector base. */
+  return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
+}
+
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
+
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) {
+  bool ok;
+  if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) {
+    return false;
+  }
+  ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
+  UPB_ASSERT_VAR(ok, ok);
+  return true;
+}
+
+
+/* "Static" methods ***********************************************************/
+
+bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
+  /* TODO: verify we have a transitive closure. */
+  int i;
+  for (i = 0; i < n; i++) {
+    upb_msg_field_iter j;
+    upb_handlers *h = handlers[i];
+
+    if (!upb_ok(&h->status_)) {
+      upb_status_seterrf(s, "handlers for message %s had error status: %s",
+                         upb_msgdef_fullname(upb_handlers_msgdef(h)),
+                         upb_status_errmsg(&h->status_));
+      return false;
+    }
+
+    /* Check that there are no closure mismatches due to missing Start* handlers
+     * or subhandlers with different type-level types. */
+    for(upb_msg_field_begin(&j, h->msg);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+
+      const upb_fielddef *f = upb_msg_iter_field(&j);
+      if (upb_fielddef_isseq(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s))
+          return false;
+      }
+
+      if (upb_fielddef_isstring(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s))
+          return false;
+      }
+
+      if (upb_fielddef_issubmsg(f)) {
+        bool hashandler = false;
+        if (upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) ||
+            upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) {
+          hashandler = true;
+        }
+
+        if (upb_fielddef_isseq(f) &&
+            (upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) ||
+             upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) {
+          hashandler = true;
+        }
+
+        if (hashandler && !upb_handlers_getsubhandlers(h, f)) {
+          /* For now we add an empty subhandlers in this case.  It makes the
+           * decoder code generator simpler, because it only has to handle two
+           * cases (submessage has handlers or not) as opposed to three
+           * (submessage has handlers in enclosing message but no subhandlers).
+           *
+           * This makes parsing less efficient in the case that we want to
+           * notice a submessage but skip its contents (like if we're testing
+           * for submessage presence or counting the number of repeated
+           * submessages).  In this case we will end up parsing the submessage
+           * field by field and throwing away the results for each, instead of
+           * skipping the whole delimited thing at once.  If this is an issue we
+           * can revisit it, but do remember that this only arises when you have
+           * handlers (startseq/startsubmsg/endsubmsg/endseq) set for the
+           * submessage but no subhandlers.  The uses cases for this are
+           * limited. */
+          upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub);
+          upb_handlers_setsubhandlers(h, f, sub);
+          upb_handlers_unref(sub, &sub);
+        }
+
+        /* TODO(haberman): check type of submessage.
+         * This is slightly tricky; also consider whether we should check that
+         * they match at setsubhandlers time. */
+      }
+    }
+  }
+
+  if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s,
+                             UPB_MAX_HANDLER_DEPTH)) {
+    return false;
+  }
+
+  return true;
+}
+
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
+    case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
+    case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
+    case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64;
+    case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE;
+    case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL;
+    default: assert(false); return -1;  /* Invalid input. */
+  }
+}
+
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s) {
+  switch (type) {
+    case UPB_HANDLER_INT32:
+    case UPB_HANDLER_INT64:
+    case UPB_HANDLER_UINT32:
+    case UPB_HANDLER_UINT64:
+    case UPB_HANDLER_FLOAT:
+    case UPB_HANDLER_DOUBLE:
+    case UPB_HANDLER_BOOL:
+      if (!upb_fielddef_isprimitive(f) ||
+          upb_handlers_getprimitivehandlertype(f) != type)
+        return false;
+      *s = f->selector_base;
+      break;
+    case UPB_HANDLER_STRING:
+      if (upb_fielddef_isstring(f)) {
+        *s = f->selector_base;
+      } else if (upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 3;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 1;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_ENDSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 2;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 2;
+      break;
+    case UPB_HANDLER_ENDSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 1;
+      break;
+    case UPB_HANDLER_STARTSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      /* Selectors for STARTSUBMSG are at the beginning of the table so that the
+       * selector can also be used as an index into the "sub" array of
+       * subhandlers.  The indexes for the two into these two tables are the
+       * same, except that in the handler table the static selectors come first. */
+      *s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
+      break;
+    case UPB_HANDLER_ENDSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      *s = f->selector_base;
+      break;
+  }
+  assert((size_t)*s < upb_fielddef_containingtype(f)->selector_count);
+  return true;
+}
+
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+  uint32_t ret = 1;
+  if (upb_fielddef_isseq(f)) ret += 2;    /* STARTSEQ/ENDSEQ */
+  if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */
+  if (upb_fielddef_issubmsg(f)) {
+    /* ENDSUBMSG (STARTSUBMSG is at table beginning) */
+    ret += 0;
+    if (upb_fielddef_lazy(f)) {
+      /* STARTSTR/ENDSTR/STRING (for lazy) */
+      ret += 3;
+    }
+  }
+  return ret;
+}
+
+
+/* upb_handlerattr ************************************************************/
+
+void upb_handlerattr_init(upb_handlerattr *attr) {
+  upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
+  memcpy(attr, &from, sizeof(*attr));
+}
+
+void upb_handlerattr_uninit(upb_handlerattr *attr) {
+  UPB_UNUSED(attr);
+}
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) {
+  attr->handler_data_ = hd;
+  return true;
+}
+
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) {
+  attr->closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) {
+  return attr->closure_type_;
+}
+
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type) {
+  attr->return_closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) {
+  return attr->return_closure_type_;
+}
+
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) {
+  attr->alwaysok_ = alwaysok;
+  return true;
+}
+
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) {
+  return attr->alwaysok_;
+}
+
+/* upb_bufhandle **************************************************************/
+
+size_t upb_bufhandle_objofs(const upb_bufhandle *h) {
+  return h->objofs_;
+}
+
+/* upb_byteshandler ***********************************************************/
+
+void upb_byteshandler_init(upb_byteshandler* h) {
+  memset(h, 0, sizeof(*h));
+}
+
+/* For when we support handlerfree callbacks. */
+void upb_byteshandler_uninit(upb_byteshandler* h) {
+  UPB_UNUSED(h);
+}
+
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d) {
+  h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d) {
+  h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d) {
+  h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+/*
+** upb::RefCounted Implementation
+**
+** Our key invariants are:
+** 1. reference cycles never span groups
+** 2. for ref2(to, from), we increment to's count iff group(from) != group(to)
+**
+** The previous two are how we avoid leaking cycles.  Other important
+** invariants are:
+** 3. for mutable objects "from" and "to", if there exists a ref2(to, from)
+**    this implies group(from) == group(to).  (In practice, what we implement
+**    is even stronger; "from" and "to" will share a group if there has *ever*
+**    been a ref2(to, from), but all that is necessary for correctness is the
+**    weaker one).
+** 4. mutable and immutable objects are never in the same group.
+*/
+
+
+#include <setjmp.h>
+
+static void freeobj(upb_refcounted *o);
+
+const char untracked_val;
+const void *UPB_UNTRACKED_REF = &untracked_val;
+
+/* arch-specific atomic primitives  *******************************************/
+
+#ifdef UPB_THREAD_UNSAFE /*---------------------------------------------------*/
+
+static void atomic_inc(uint32_t *a) { (*a)++; }
+static bool atomic_dec(uint32_t *a) { return --(*a) == 0; }
+
+#elif defined(__GNUC__) || defined(__clang__) /*------------------------------*/
+
+static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); }
+static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; }
+
+#elif defined(WIN32) /*-------------------------------------------------------*/
+
+#include <Windows.h>
+
+static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); }
+static bool atomic_dec(upb_atomic_t *a) {
+  return InterlockedDecrement(&a->val) == 0;
+}
+
+#else
+#error Atomic primitives not defined for your platform/CPU.  \
+       Implement them or compile with UPB_THREAD_UNSAFE.
+#endif
+
+/* All static objects point to this refcount.
+ * It is special-cased in ref/unref below.  */
+uint32_t static_refcount = -1;
+
+/* We can avoid atomic ops for statically-declared objects.
+ * This is a minor optimization but nice since we can avoid degrading under
+ * contention in this case. */
+
+static void refgroup(uint32_t *group) {
+  if (group != &static_refcount)
+    atomic_inc(group);
+}
+
+static bool unrefgroup(uint32_t *group) {
+  if (group == &static_refcount) {
+    return false;
+  } else {
+    return atomic_dec(group);
+  }
+}
+
+
+/* Reference tracking (debug only) ********************************************/
+
+#ifdef UPB_DEBUG_REFS
+
+#ifdef UPB_THREAD_UNSAFE
+
+static void upb_lock() {}
+static void upb_unlock() {}
+
+#else
+
+/* User must define functions that lock/unlock a global mutex and link this
+ * file against them. */
+void upb_lock();
+void upb_unlock();
+
+#endif
+
+/* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some
+ * code-paths that can normally never fail, like upb_refcounted_ref().  Since
+ * we have no way to propagage out-of-memory errors back to the user, and since
+ * these errors can only occur in UPB_DEBUG_REFS mode, we use an allocator that
+ * immediately aborts on failure (avoiding the global allocator, which might
+ * inject failures). */
+
+#include <stdlib.h>
+
+static void *upb_debugrefs_allocfunc(upb_alloc *alloc, void *ptr,
+                                     size_t oldsize, size_t size) {
+  UPB_UNUSED(alloc);
+  UPB_UNUSED(oldsize);
+  if (size == 0) {
+    free(ptr);
+    return NULL;
+  } else {
+    void *ret = realloc(ptr, size);
+
+    if (!ret) {
+      abort();
+    }
+
+    return ret;
+  }
+}
+
+upb_alloc upb_alloc_debugrefs = {&upb_debugrefs_allocfunc};
+
+typedef struct {
+  int count;  /* How many refs there are (duplicates only allowed for ref2). */
+  bool is_ref2;
+} trackedref;
+
+static trackedref *trackedref_new(bool is_ref2) {
+  trackedref *ret = upb_malloc(&upb_alloc_debugrefs, sizeof(*ret));
+  ret->count = 1;
+  ret->is_ref2 = is_ref2;
+  return ret;
+}
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+
+  assert(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  if (upb_inttable_lookupptr(r->refs, owner, &v)) {
+    trackedref *ref = upb_value_getptr(v);
+    /* Since we allow multiple ref2's for the same to/from pair without
+     * allocating separate memory for each one, we lose the fine-grained
+     * tracking behavior we get with regular refs.  Since ref2s only happen
+     * inside upb, we'll accept this limitation until/unless there is a really
+     * difficult upb-internal bug that can't be figured out without it. */
+    assert(ref2);
+    assert(ref->is_ref2);
+    ref->count++;
+  } else {
+    trackedref *ref = trackedref_new(ref2);
+    upb_inttable_insertptr2(r->refs, owner, upb_value_ptr(ref),
+                            &upb_alloc_debugrefs);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      assert(!upb_inttable_lookupptr(from->ref2s, r, NULL));
+      upb_inttable_insertptr2(from->ref2s, r, upb_value_ptr(NULL),
+                              &upb_alloc_debugrefs);
+    }
+  }
+  upb_unlock();
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  assert(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  /* This assert will fail if an owner attempts to release a ref it didn't have. */
+  UPB_ASSERT_VAR(found, found);
+  ref = upb_value_getptr(v);
+  assert(ref->is_ref2 == ref2);
+  if (--ref->count == 0) {
+    free(ref);
+    upb_inttable_removeptr(r->refs, owner, NULL);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      bool removed = upb_inttable_removeptr(from->ref2s, r, NULL);
+      assert(removed);
+    }
+  }
+  upb_unlock();
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  UPB_ASSERT_VAR(found, found);
+  ref = upb_value_getptr(v);
+  assert(ref->is_ref2 == ref2);
+  upb_unlock();
+}
+
+/* Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that
+ * originate from the given owner. */
+static void getref2s(const upb_refcounted *owner, upb_inttable *tab) {
+  upb_inttable_iter i;
+
+  upb_lock();
+  upb_inttable_begin(&i, owner->ref2s);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_value v;
+    upb_value count;
+    trackedref *ref;
+    bool found;
+
+    upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i);
+
+    /* To get the count we need to look in the target's table. */
+    found = upb_inttable_lookupptr(to->refs, owner, &v);
+    assert(found);
+    ref = upb_value_getptr(v);
+    count = upb_value_int32(ref->count);
+
+    upb_inttable_insertptr2(tab, to, count, &upb_alloc_debugrefs);
+  }
+  upb_unlock();
+}
+
+typedef struct {
+  upb_inttable ref2;
+  const upb_refcounted *obj;
+} check_state;
+
+static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj,
+                        void *closure) {
+  check_state *s = closure;
+  upb_inttable *ref2 = &s->ref2;
+  upb_value v;
+  bool removed;
+  int32_t newcount;
+
+  assert(obj == s->obj);
+  assert(subobj);
+  removed = upb_inttable_removeptr(ref2, subobj, &v);
+  /* The following assertion will fail if the visit() function visits a subobj
+   * that it did not have a ref2 on, or visits the same subobj too many times. */
+  assert(removed);
+  newcount = upb_value_getint32(v) - 1;
+  if (newcount > 0) {
+    upb_inttable_insert2(ref2, (uintptr_t)subobj, upb_value_int32(newcount),
+                         &upb_alloc_debugrefs);
+  }
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know
+   * exactly the set of nodes that visit() should visit.  So we verify visit()'s
+   * correctness here. */
+  check_state state;
+  state.obj = r;
+  upb_inttable_init2(&state.ref2, UPB_CTYPE_INT32, &upb_alloc_debugrefs);
+  getref2s(r, &state.ref2);
+
+  /* This should visit any children in the ref2 table. */
+  if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state);
+
+  /* This assertion will fail if the visit() function missed any children. */
+  assert(upb_inttable_count(&state.ref2) == 0);
+  upb_inttable_uninit2(&state.ref2, &upb_alloc_debugrefs);
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+static void trackinit(upb_refcounted *r) {
+  r->refs = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->refs));
+  r->ref2s = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->ref2s));
+  upb_inttable_init2(r->refs, UPB_CTYPE_PTR, &upb_alloc_debugrefs);
+  upb_inttable_init2(r->ref2s, UPB_CTYPE_PTR, &upb_alloc_debugrefs);
+}
+
+static void trackfree(const upb_refcounted *r) {
+  upb_inttable_uninit2(r->refs, &upb_alloc_debugrefs);
+  upb_inttable_uninit2(r->ref2s, &upb_alloc_debugrefs);
+  upb_free(&upb_alloc_debugrefs, r->refs);
+  upb_free(&upb_alloc_debugrefs, r->ref2s);
+}
+
+#else
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void trackinit(upb_refcounted *r) {
+  UPB_UNUSED(r);
+}
+
+static void trackfree(const upb_refcounted *r) {
+  UPB_UNUSED(r);
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+#endif  /* UPB_DEBUG_REFS */
+
+
+/* freeze() *******************************************************************/
+
+/* The freeze() operation is by far the most complicated part of this scheme.
+ * We compute strongly-connected components and then mutate the graph such that
+ * we preserve the invariants documented at the top of this file.  And we must
+ * handle out-of-memory errors gracefully (without leaving the graph
+ * inconsistent), which adds to the fun. */
+
+/* The state used by the freeze operation (shared across many functions). */
+typedef struct {
+  int depth;
+  int maxdepth;
+  uint64_t index;
+  /* Maps upb_refcounted* -> attributes (color, etc).  attr layout varies by
+   * color. */
+  upb_inttable objattr;
+  upb_inttable stack;   /* stack of upb_refcounted* for Tarjan's algorithm. */
+  upb_inttable groups;  /* array of uint32_t*, malloc'd refcounts for new groups */
+  upb_status *status;
+  jmp_buf err;
+} tarjan;
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure);
+
+/* Node attributes -----------------------------------------------------------*/
+
+/* After our analysis phase all nodes will be either GRAY or WHITE. */
+
+typedef enum {
+  BLACK = 0,  /* Object has not been seen. */
+  GRAY,   /* Object has been found via a refgroup but may not be reachable. */
+  GREEN,  /* Object is reachable and is currently on the Tarjan stack. */
+  WHITE   /* Object is reachable and has been assigned a group (SCC). */
+} color_t;
+
+UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
+UPB_NORETURN static void oom(tarjan *t) {
+  upb_status_seterrmsg(t->status, "out of memory");
+  err(t);
+}
+
+static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  return upb_inttable_lookupptr(&t->objattr, r, &v) ?
+      upb_value_getuint64(v) : 0;
+}
+
+static uint64_t getattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  bool found = upb_inttable_lookupptr(&t->objattr, r, &v);
+  UPB_ASSERT_VAR(found, found);
+  return upb_value_getuint64(v);
+}
+
+static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) {
+  upb_inttable_removeptr(&t->objattr, r, NULL);
+  upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr));
+}
+
+static color_t color(tarjan *t, const upb_refcounted *r) {
+  return trygetattr(t, r) & 0x3;  /* Color is always stored in the low 2 bits. */
+}
+
+static void set_gray(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == BLACK);
+  setattr(t, r, GRAY);
+}
+
+/* Pushes an obj onto the Tarjan stack and sets it to GREEN. */
+static void push(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == BLACK || color(t, r) == GRAY);
+  /* This defines the attr layout for the GREEN state.  "index" and "lowlink"
+   * get 31 bits, which is plenty (limit of 2B objects frozen at a time). */
+  setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
+  if (++t->index == 0x80000000) {
+    upb_status_seterrmsg(t->status, "too many objects to freeze");
+    err(t);
+  }
+  upb_inttable_push(&t->stack, upb_value_ptr((void*)r));
+}
+
+/* Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its
+ * SCC group. */
+static upb_refcounted *pop(tarjan *t) {
+  upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack));
+  assert(color(t, r) == GREEN);
+  /* This defines the attr layout for nodes in the WHITE state.
+   * Top of group stack is [group, NULL]; we point at group. */
+  setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8);
+  return r;
+}
+
+static void tarjan_newgroup(tarjan *t) {
+  uint32_t *group = upb_gmalloc(sizeof(*group));
+  if (!group) oom(t);
+  /* Push group and empty group leader (we'll fill in leader later). */
+  if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) ||
+      !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) {
+    upb_gfree(group);
+    oom(t);
+  }
+  *group = 0;
+}
+
+static uint32_t idx(tarjan *t, const upb_refcounted *r) {
+  assert(color(t, r) == GREEN);
+  return (getattr(t, r) >> 2) & 0x7FFFFFFF;
+}
+
+static uint32_t lowlink(tarjan *t, const upb_refcounted *r) {
+  if (color(t, r) == GREEN) {
+    return getattr(t, r) >> 33;
+  } else {
+    return UINT32_MAX;
+  }
+}
+
+static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) {
+  assert(color(t, r) == GREEN);
+  setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF));
+}
+
+static uint32_t *group(tarjan *t, upb_refcounted *r) {
+  uint64_t groupnum;
+  upb_value v;
+  bool found;
+
+  assert(color(t, r) == WHITE);
+  groupnum = getattr(t, r) >> 8;
+  found = upb_inttable_lookup(&t->groups, groupnum, &v);
+  UPB_ASSERT_VAR(found, found);
+  return upb_value_getptr(v);
+}
+
+/* If the group leader for this object's group has not previously been set,
+ * the given object is assigned to be its leader. */
+static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) {
+  uint64_t leader_slot;
+  upb_value v;
+  bool found;
+
+  assert(color(t, r) == WHITE);
+  leader_slot = (getattr(t, r) >> 8) + 1;
+  found = upb_inttable_lookup(&t->groups, leader_slot, &v);
+  UPB_ASSERT_VAR(found, found);
+  if (upb_value_getptr(v)) {
+    return upb_value_getptr(v);
+  } else {
+    upb_inttable_remove(&t->groups, leader_slot, NULL);
+    upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r));
+    return r;
+  }
+}
+
+
+/* Tarjan's algorithm --------------------------------------------------------*/
+
+/* See:
+ *   http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */
+static void do_tarjan(const upb_refcounted *obj, tarjan *t);
+
+static void tarjan_visit(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  tarjan *t = closure;
+  if (++t->depth > t->maxdepth) {
+    upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth);
+    err(t);
+  } else if (subobj->is_frozen || color(t, subobj) == WHITE) {
+    /* Do nothing: we don't want to visit or color already-frozen nodes,
+     * and WHITE nodes have already been assigned a SCC. */
+  } else if (color(t, subobj) < GREEN) {
+    /* Subdef has not yet been visited; recurse on it. */
+    do_tarjan(subobj, t);
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj)));
+  } else if (color(t, subobj) == GREEN) {
+    /* Subdef is in the stack and hence in the current SCC. */
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj)));
+  }
+  --t->depth;
+}
+
+static void do_tarjan(const upb_refcounted *obj, tarjan *t) {
+  if (color(t, obj) == BLACK) {
+    /* We haven't seen this object's group; mark the whole group GRAY. */
+    const upb_refcounted *o = obj;
+    do { set_gray(t, o); } while ((o = o->next) != obj);
+  }
+
+  push(t, obj);
+  visit(obj, tarjan_visit, t);
+  if (lowlink(t, obj) == idx(t, obj)) {
+    tarjan_newgroup(t);
+    while (pop(t) != obj)
+      ;
+  }
+}
+
+
+/* freeze() ------------------------------------------------------------------*/
+
+static void crossref(const upb_refcounted *r, const upb_refcounted *subobj,
+                     void *_t) {
+  tarjan *t = _t;
+  assert(color(t, r) > BLACK);
+  if (color(t, subobj) > BLACK && r->group != subobj->group) {
+    /* Previously this ref was not reflected in subobj->group because they
+     * were in the same group; now that they are split a ref must be taken. */
+    refgroup(subobj->group);
+  }
+}
+
+static bool freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                   int maxdepth) {
+  volatile bool ret = false;
+  int i;
+  upb_inttable_iter iter;
+
+  /* We run in two passes so that we can allocate all memory before performing
+   * any mutation of the input -- this allows us to leave the input unchanged
+   * in the case of memory allocation failure. */
+  tarjan t;
+  t.index = 0;
+  t.depth = 0;
+  t.maxdepth = maxdepth;
+  t.status = s;
+  if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1;
+  if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3;
+  if (setjmp(t.err) != 0) goto err4;
+
+
+  for (i = 0; i < n; i++) {
+    if (color(&t, roots[i]) < GREEN) {
+      do_tarjan(roots[i], &t);
+    }
+  }
+
+  /* If we've made it this far, no further errors are possible so it's safe to
+   * mutate the objects without risk of leaving them in an inconsistent state. */
+  ret = true;
+
+  /* The transformation that follows requires care.  The preconditions are:
+   * - all objects in attr map are WHITE or GRAY, and are in mutable groups
+   *   (groups of all mutable objs)
+   * - no ref2(to, from) refs have incremented count(to) if both "to" and
+   *   "from" are in our attr map (this follows from invariants (2) and (3)) */
+
+  /* Pass 1: we remove WHITE objects from their mutable groups, and add them to
+   * new groups  according to the SCC's we computed.  These new groups will
+   * consist of only frozen objects.  None will be immediately collectible,
+   * because WHITE objects are by definition reachable from one of "roots",
+   * which the caller must own refs on. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    /* Since removal from a singly-linked list requires access to the object's
+     * predecessor, we consider obj->next instead of obj for moving.  With the
+     * while() loop we guarantee that we will visit every node's predecessor.
+     * Proof:
+     *  1. every node's predecessor is in our attr map.
+     *  2. though the loop body may change a node's predecessor, it will only
+     *     change it to be the node we are currently operating on, so with a
+     *     while() loop we guarantee ourselves the chance to remove each node. */
+    while (color(&t, obj->next) == WHITE &&
+           group(&t, obj->next) != obj->next->group) {
+      upb_refcounted *leader;
+
+      /* Remove from old group. */
+      upb_refcounted *move = obj->next;
+      if (obj == move) {
+        /* Removing the last object from a group. */
+        assert(*obj->group == obj->individual_count);
+        upb_gfree(obj->group);
+      } else {
+        obj->next = move->next;
+        /* This may decrease to zero; we'll collect GRAY objects (if any) that
+         * remain in the group in the third pass. */
+        assert(*move->group >= move->individual_count);
+        *move->group -= move->individual_count;
+      }
+
+      /* Add to new group. */
+      leader = groupleader(&t, move);
+      if (move == leader) {
+        /* First object added to new group is its leader. */
+        move->group = group(&t, move);
+        move->next = move;
+        *move->group = move->individual_count;
+      } else {
+        /* Group already has at least one object in it. */
+        assert(leader->group == group(&t, move));
+        move->group = group(&t, move);
+        move->next = leader->next;
+        leader->next = move;
+        *move->group += move->individual_count;
+      }
+
+      move->is_frozen = true;
+    }
+  }
+
+  /* Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must
+   * increment count(to) if group(obj) != group(to) (which could now be the
+   * case if "to" was just frozen). */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    visit(obj, crossref, &t);
+  }
+
+  /* Pass 3: GRAY objects are collected if their group's refcount dropped to
+   * zero when we removed its white nodes.  This can happen if they had only
+   * been kept alive by virtue of sharing a group with an object that was just
+   * frozen.
+   *
+   * It is important that we do this last, since the GRAY object's free()
+   * function could call unref2() on just-frozen objects, which will decrement
+   * refs that were added in pass 2. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    if (obj->group == NULL || *obj->group == 0) {
+      if (obj->group) {
+        upb_refcounted *o;
+
+        /* We eagerly free() the group's count (since we can't easily determine
+         * the group's remaining size it's the easiest way to ensure it gets
+         * done). */
+        upb_gfree(obj->group);
+
+        /* Visit to release ref2's (done in a separate pass since release_ref2
+         * depends on o->group being unmodified so it can test merged()). */
+        o = obj;
+        do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj);
+
+        /* Mark "group" fields as NULL so we know to free the objects later in
+         * this loop, but also don't try to delete the group twice. */
+        o = obj;
+        do { o->group = NULL; } while ((o = o->next) != obj);
+      }
+      freeobj(obj);
+    }
+  }
+
+err4:
+  if (!ret) {
+    upb_inttable_begin(&iter, &t.groups);
+    for(; !upb_inttable_done(&iter); upb_inttable_next(&iter))
+      upb_gfree(upb_value_getptr(upb_inttable_iter_value(&iter)));
+  }
+  upb_inttable_uninit(&t.groups);
+err3:
+  upb_inttable_uninit(&t.stack);
+err2:
+  upb_inttable_uninit(&t.objattr);
+err1:
+  return ret;
+}
+
+
+/* Misc internal functions  ***************************************************/
+
+static bool merged(const upb_refcounted *r, const upb_refcounted *r2) {
+  return r->group == r2->group;
+}
+
+static void merge(upb_refcounted *r, upb_refcounted *from) {
+  upb_refcounted *base;
+  upb_refcounted *tmp;
+
+  if (merged(r, from)) return;
+  *r->group += *from->group;
+  upb_gfree(from->group);
+  base = from;
+
+  /* Set all refcount pointers in the "from" chain to the merged refcount.
+   *
+   * TODO(haberman): this linear algorithm can result in an overall O(n^2) bound
+   * if the user continuously extends a group by one object.  Prevent this by
+   * using one of the techniques in this paper:
+   *     ftp://www.ncedc.org/outgoing/geomorph/dino/orals/p245-tarjan.pdf */
+  do { from->group = r->group; } while ((from = from->next) != base);
+
+  /* Merge the two circularly linked lists by swapping their next pointers. */
+  tmp = r->next;
+  r->next = base->next;
+  base->next = tmp;
+}
+
+static void unref(const upb_refcounted *r);
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  UPB_UNUSED(closure);
+  untrack(subobj, obj, true);
+  if (!merged(obj, subobj)) {
+    assert(subobj->is_frozen);
+    unref(subobj);
+  }
+}
+
+static void unref(const upb_refcounted *r) {
+  if (unrefgroup(r->group)) {
+    const upb_refcounted *o;
+
+    upb_gfree(r->group);
+
+    /* In two passes, since release_ref2 needs a guarantee that any subobjs
+     * are alive. */
+    o = r;
+    do { visit(o, release_ref2, NULL); } while((o = o->next) != r);
+
+    o = r;
+    do {
+      const upb_refcounted *next = o->next;
+      assert(o->is_frozen || o->individual_count == 0);
+      freeobj((upb_refcounted*)o);
+      o = next;
+    } while(o != r);
+  }
+}
+
+static void freeobj(upb_refcounted *o) {
+  trackfree(o);
+  o->vtbl->free((upb_refcounted*)o);
+}
+
+
+/* Public interface ***********************************************************/
+
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+#ifndef NDEBUG
+  /* Endianness check.  This is unrelated to upb_refcounted, it's just a
+   * convenient place to put the check that we can be assured will run for
+   * basically every program using upb. */
+  const int x = 1;
+#ifdef UPB_BIG_ENDIAN
+  assert(*(char*)&x != 1);
+#else
+  assert(*(char*)&x == 1);
+#endif
+#endif
+
+  r->next = r;
+  r->vtbl = vtbl;
+  r->individual_count = 0;
+  r->is_frozen = false;
+  r->group = upb_gmalloc(sizeof(*r->group));
+  if (!r->group) return false;
+  *r->group = 0;
+  trackinit(r);
+  upb_refcounted_ref(r, owner);
+  return true;
+}
+
+bool upb_refcounted_isfrozen(const upb_refcounted *r) {
+  return r->is_frozen;
+}
+
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner) {
+  track(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count++;
+  refgroup(r->group);
+}
+
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner) {
+  untrack(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count--;
+  unref(r);
+}
+
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) {
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
+  track(r, from, true);
+  if (r->is_frozen) {
+    refgroup(r->group);
+  } else {
+    merge((upb_refcounted*)r, from);
+  }
+}
+
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) {
+  assert(!from->is_frozen);  /* Non-const pointer implies this. */
+  untrack(r, from, true);
+  if (r->is_frozen) {
+    unref(r);
+  } else {
+    assert(merged(r, from));
+  }
+}
+
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to) {
+  assert(from != to);
+  if (to != NULL)
+    upb_refcounted_ref(r, to);
+  if (from != NULL)
+    upb_refcounted_unref(r, from);
+}
+
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) {
+  checkref(r, owner, false);
+}
+
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth) {
+  int i;
+  bool ret;
+  for (i = 0; i < n; i++) {
+    assert(!roots[i]->is_frozen);
+  }
+  ret = freeze(roots, n, s, maxdepth);
+  assert(!s || ret == upb_ok(s));
+  return ret;
+}
+
+
+/* Fallback implementation if the shim is not specialized by the JIT. */
+#define SHIM_WRITER(type, ctype)                                              \
+  bool upb_shim_set ## type (void *c, const void *hd, ctype val) {            \
+    uint8_t *m = c;                                                           \
+    const upb_shim_data *d = hd;                                              \
+    if (d->hasbit > 0)                                                        \
+      *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8);                   \
+    *(ctype*)&m[d->offset] = val;                                             \
+    return true;                                                              \
+  }                                                                           \
+
+SHIM_WRITER(double, double)
+SHIM_WRITER(float,  float)
+SHIM_WRITER(int32,  int32_t)
+SHIM_WRITER(int64,  int64_t)
+SHIM_WRITER(uint32, uint32_t)
+SHIM_WRITER(uint64, uint64_t)
+SHIM_WRITER(bool,   bool)
+#undef SHIM_WRITER
+
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+                  int32_t hasbit) {
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  bool ok;
+
+  upb_shim_data *d = upb_gmalloc(sizeof(*d));
+  if (!d) return false;
+  d->offset = offset;
+  d->hasbit = hasbit;
+
+  upb_handlerattr_sethandlerdata(&attr, d);
+  upb_handlerattr_setalwaysok(&attr, true);
+  upb_handlers_addcleanup(h, d, upb_gfree);
+
+#define TYPE(u, l) \
+  case UPB_TYPE_##u: \
+    ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
+
+  ok = false;
+
+  switch (upb_fielddef_type(f)) {
+    TYPE(INT64,  int64);
+    TYPE(INT32,  int32);
+    TYPE(ENUM,   int32);
+    TYPE(UINT64, uint64);
+    TYPE(UINT32, uint32);
+    TYPE(DOUBLE, double);
+    TYPE(FLOAT,  float);
+    TYPE(BOOL,   bool);
+    default: assert(false); break;
+  }
+#undef TYPE
+
+  upb_handlerattr_uninit(&attr);
+  return ok;
+}
+
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+                                      upb_fieldtype_t *type) {
+  upb_func *f = upb_handlers_gethandler(h, s);
+
+  if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
+    *type = UPB_TYPE_INT64;
+  } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
+    *type = UPB_TYPE_INT32;
+  } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
+    *type = UPB_TYPE_UINT64;
+  } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
+    *type = UPB_TYPE_UINT32;
+  } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
+    *type = UPB_TYPE_DOUBLE;
+  } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
+    *type = UPB_TYPE_FLOAT;
+  } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
+    *type = UPB_TYPE_BOOL;
+  } else {
+    return NULL;
+  }
+
+  return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s);
+}
+
+
+#include <string.h>
+
+static void upb_symtab_free(upb_refcounted *r) {
+  upb_symtab *s = (upb_symtab*)r;
+  upb_strtable_iter i;
+  upb_strtable_begin(&i, &s->symtab);
+  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+    upb_def_unref(def, s);
+  }
+  upb_strtable_uninit(&s->symtab);
+  upb_gfree(s);
+}
+
+upb_symtab *upb_symtab_new(const void *owner) {
+  static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free};
+
+  upb_symtab *s = upb_gmalloc(sizeof(*s));
+  if (!s) {
+    return NULL;
+  }
+
+  upb_refcounted_init(upb_symtab_upcast_mutable(s), &vtbl, owner);
+  upb_strtable_init(&s->symtab, UPB_CTYPE_PTR);
+  return s;
+}
+
+void upb_symtab_freeze(upb_symtab *s) {
+  upb_refcounted *r;
+  bool ok;
+
+  assert(!upb_symtab_isfrozen(s));
+  r = upb_symtab_upcast_mutable(s);
+  /* The symtab does not take ref2's (see refcounted.h) on the defs, because
+   * defs cannot refer back to the table and therefore cannot create cycles.  So
+   * 0 will suffice for maxdepth here. */
+  ok = upb_refcounted_freeze(&r, 1, NULL, 0);
+  UPB_ASSERT_VAR(ok, ok);
+}
+
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return ret;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+/* Given a symbol and the base symbol inside which it is defined, find the
+ * symbol's definition in t. */
+static upb_def *upb_resolvename(const upb_strtable *t,
+                                const char *base, const char *sym) {
+  if(strlen(sym) == 0) return NULL;
+  if(sym[0] == '.') {
+    /* Symbols starting with '.' are absolute, so we do a single lookup.
+     * Slice to omit the leading '.' */
+    upb_value v;
+    return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL;
+  } else {
+    /* Remove components from base until we find an entry or run out.
+     * TODO: This branch is totally broken, but currently not used. */
+    (void)base;
+    assert(false);
+    return NULL;
+  }
+}
+
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym) {
+  upb_def *ret = upb_resolvename(&s->symtab, base, sym);
+  return ret;
+}
+
+/* Starts a depth-first traversal at "def", recursing into any subdefs
+ * (ie. submessage types).  Adds duplicates of existing defs to addtab
+ * wherever necessary, so that the resulting symtab will be consistent once
+ * addtab is added.
+ *
+ * More specifically, if any def D is found in the DFS that:
+ *
+ *   1. can reach a def that is being replaced by something in addtab, AND
+ *
+ *   2. is not itself being replaced already (ie. this name doesn't already
+ *      exist in addtab)
+ *
+ * ...then a duplicate (new copy) of D will be added to addtab.
+ *
+ * Returns true if this happened for any def reachable from "def."
+ *
+ * It is slightly tricky to do this correctly in the presence of cycles.  If we
+ * detect that our DFS has hit a cycle, we might not yet know if any SCCs on
+ * our stack can reach a def in addtab or not.  Once we figure this out, that
+ * answer needs to apply to *all* defs in these SCCs, even if we visited them
+ * already.  So a straight up one-pass cycle-detecting DFS won't work.
+ *
+ * To work around this problem, we traverse each SCC (which we already
+ * computed, since these defs are frozen) as a single node.  We first compute
+ * whether the SCC as a whole can reach any def in addtab, then we dup (or not)
+ * the entire SCC.  This requires breaking the encapsulation of upb_refcounted,
+ * since that is where we get the data about what SCC we are in. */
+static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
+                            const void *new_owner, upb_inttable *seen,
+                            upb_status *s) {
+  upb_value v;
+  bool need_dup;
+  const upb_def *base;
+  const void* memoize_key;
+
+  /* Memoize results of this function for efficiency (since we're traversing a
+   * DAG this is not needed to limit the depth of the search).
+   *
+   * We memoize by SCC instead of by individual def. */
+  memoize_key = def->base.group;
+
+  if (upb_inttable_lookupptr(seen, memoize_key, &v))
+    return upb_value_getbool(v);
+
+  /* Visit submessages for all messages in the SCC. */
+  need_dup = false;
+  base = def;
+  do {
+    upb_value v;
+    const upb_msgdef *m;
+
+    assert(upb_def_isfrozen(def));
+    if (def->type == UPB_DEF_FIELD) continue;
+    if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
+      need_dup = true;
+    }
+
+    /* For messages, continue the recursion by visiting all subdefs, but only
+     * ones in different SCCs. */
+    m = upb_dyncast_msgdef(def);
+    if (m) {
+      upb_msg_field_iter i;
+      for(upb_msg_field_begin(&i, m);
+          !upb_msg_field_done(&i);
+          upb_msg_field_next(&i)) {
+        upb_fielddef *f = upb_msg_iter_field(&i);
+        const upb_def *subdef;
+
+        if (!upb_fielddef_hassubdef(f)) continue;
+        subdef = upb_fielddef_subdef(f);
+
+        /* Skip subdefs in this SCC. */
+        if (def->base.group == subdef->base.group) continue;
+
+        /* |= to avoid short-circuit; we need its side-effects. */
+        need_dup |= upb_resolve_dfs(subdef, addtab, new_owner, seen, s);
+        if (!upb_ok(s)) return false;
+      }
+    }
+  } while ((def = (upb_def*)def->base.next) != base);
+
+  if (need_dup) {
+    /* Dup all defs in this SCC that don't already have entries in addtab. */
+    def = base;
+    do {
+      const char *name;
+
+      if (def->type == UPB_DEF_FIELD) continue;
+      name = upb_def_fullname(def);
+      if (!upb_strtable_lookup(addtab, name, NULL)) {
+        upb_def *newdef = upb_def_dup(def, new_owner);
+        if (!newdef) goto oom;
+        newdef->came_from_user = false;
+        if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef)))
+          goto oom;
+      }
+    } while ((def = (upb_def*)def->base.next) != base);
+  }
+
+  upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup));
+  return need_dup;
+
+oom:
+  upb_status_seterrmsg(s, "out of memory");
+  return false;
+}
+
+/* TODO(haberman): we need a lot more testing of error conditions.
+ * The came_from_user stuff in particular is not tested. */
+static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                       void *ref_donor, upb_refcounted *freeze_also,
+                       upb_status *status) {
+  size_t i;
+  size_t add_n;
+  size_t freeze_n;
+  upb_strtable_iter iter;
+  upb_refcounted **add_objs = NULL;
+  upb_def **add_defs = NULL;
+  size_t add_objs_size;
+  upb_strtable addtab;
+  upb_inttable seen;
+
+  if (n == 0 && !freeze_also) {
+    return true;
+  }
+
+  assert(!upb_symtab_isfrozen(s));
+  if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+
+  /* Add new defs to our "add" set. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    const char *fullname;
+    upb_fielddef *f;
+
+    if (upb_def_isfrozen(def)) {
+      upb_status_seterrmsg(status, "added defs must be mutable");
+      goto err;
+    }
+    assert(!upb_def_isfrozen(def));
+    fullname = upb_def_fullname(def);
+    if (!fullname) {
+      upb_status_seterrmsg(
+          status, "Anonymous defs cannot be added to a symtab");
+      goto err;
+    }
+
+    f = upb_dyncast_fielddef_mutable(def);
+
+    if (f) {
+      if (!upb_fielddef_containingtypename(f)) {
+        upb_status_seterrmsg(status,
+                             "Standalone fielddefs must have a containing type "
+                             "(extendee) name set");
+        goto err;
+      }
+    } else {
+      if (upb_strtable_lookup(&addtab, fullname, NULL)) {
+        upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
+        goto err;
+      }
+      /* We need this to back out properly, because if there is a failure we
+       * need to donate the ref back to the caller. */
+      def->came_from_user = true;
+      upb_def_donateref(def, ref_donor, s);
+      if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def)))
+        goto oom_err;
+    }
+  }
+
+  /* Add standalone fielddefs (ie. extensions) to the appropriate messages.
+   * If the appropriate message only exists in the existing symtab, duplicate
+   * it so we have a mutable copy we can add the fields to. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
+    const char *msgname;
+    upb_value v;
+    upb_msgdef *m;
+
+    if (!f) continue;
+    msgname = upb_fielddef_containingtypename(f);
+    /* We validated this earlier in this function. */
+    assert(msgname);
+
+    /* If the extendee name is absolutely qualified, move past the initial ".".
+     * TODO(haberman): it is not obvious what it would mean if this was not
+     * absolutely qualified. */
+    if (msgname[0] == '.') {
+      msgname++;
+    }
+
+    if (upb_strtable_lookup(&addtab, msgname, &v)) {
+      /* Extendee is in the set of defs the user asked us to add. */
+      m = upb_value_getptr(v);
+    } else {
+      /* Need to find and dup the extendee from the existing symtab. */
+      const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname);
+      if (!frozen_m) {
+        upb_status_seterrf(status,
+                           "Tried to extend message %s that does not exist "
+                           "in this SymbolTable.",
+                           msgname);
+        goto err;
+      }
+      m = upb_msgdef_dup(frozen_m, s);
+      if (!m) goto oom_err;
+      if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) {
+        upb_msgdef_unref(m, s);
+        goto oom_err;
+      }
+    }
+
+    if (!upb_msgdef_addfield(m, f, ref_donor, status)) {
+      goto err;
+    }
+  }
+
+  /* Add dups of any existing def that can reach a def with the same name as
+   * anything in our "add" set. */
+  if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err;
+  upb_strtable_begin(&iter, &s->symtab);
+  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+    upb_resolve_dfs(def, &addtab, s, &seen, status);
+    if (!upb_ok(status)) goto err;
+  }
+  upb_inttable_uninit(&seen);
+
+  /* Now using the table, resolve symbolic references for subdefs. */
+  upb_strtable_begin(&iter, &addtab);
+  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    const char *base;
+    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+    upb_msg_field_iter j;
+
+    if (!m) continue;
+    /* Type names are resolved relative to the message in which they appear. */
+    base = upb_msgdef_fullname(m);
+
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      const char *name = upb_fielddef_subdefname(f);
+      if (name && !upb_fielddef_subdef(f)) {
+        /* Try the lookup in the current set of to-be-added defs first. If not
+         * there, try existing defs. */
+        upb_def *subdef = upb_resolvename(&addtab, base, name);
+        if (subdef == NULL) {
+          subdef = upb_resolvename(&s->symtab, base, name);
+        }
+        if (subdef == NULL) {
+          upb_status_seterrf(
+              status, "couldn't resolve name '%s' in message '%s'", name, base);
+          goto err;
+        } else if (!upb_fielddef_setsubdef(f, subdef, status)) {
+          goto err;
+        }
+      }
+    }
+  }
+
+  /* We need an array of the defs in addtab, for passing to
+   * upb_refcounted_freeze(). */
+  add_objs_size = upb_strtable_count(&addtab);
+  if (freeze_also) {
+    add_objs_size++;
+  }
+
+  add_defs = upb_gmalloc(sizeof(void*) * add_objs_size);
+  if (add_defs == NULL) goto oom_err;
+  upb_strtable_begin(&iter, &addtab);
+  for (add_n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    add_defs[add_n++] = upb_value_getptr(upb_strtable_iter_value(&iter));
+  }
+
+  /* Validate defs. */
+  if (!_upb_def_validate(add_defs, add_n, status)) {
+    goto err;
+  }
+
+  /* Cheat a little and give the array a new type.
+   * This is probably undefined behavior, but this code will be deleted soon. */
+  add_objs = (upb_refcounted**)add_defs;
+
+  freeze_n = add_n;
+  if (freeze_also) {
+    add_objs[freeze_n++] = freeze_also;
+  }
+
+  if (!upb_refcounted_freeze(add_objs, freeze_n, status,
+                             UPB_MAX_MESSAGE_DEPTH * 2)) {
+    goto err;
+  }
+
+  /* This must be delayed until all errors have been detected, since error
+   * recovery code uses this table to cleanup defs. */
+  upb_strtable_uninit(&addtab);
+
+  /* TODO(haberman) we don't properly handle errors after this point (like
+   * OOM in upb_strtable_insert() below). */
+  for (i = 0; i < add_n; i++) {
+    upb_def *def = (upb_def*)add_objs[i];
+    const char *name = upb_def_fullname(def);
+    upb_value v;
+    bool success;
+
+    if (upb_strtable_remove(&s->symtab, name, &v)) {
+      const upb_def *def = upb_value_getptr(v);
+      upb_def_unref(def, s);
+    }
+    success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
+    UPB_ASSERT_VAR(success, success == true);
+  }
+  upb_gfree(add_defs);
+  return true;
+
+oom_err:
+  upb_status_seterrmsg(status, "out of memory");
+err: {
+    /* For defs the user passed in, we need to donate the refs back.  For defs
+     * we dup'd, we need to just unref them. */
+    upb_strtable_begin(&iter, &addtab);
+    for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+      upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+      bool came_from_user = def->came_from_user;
+      def->came_from_user = false;
+      if (came_from_user) {
+        upb_def_donateref(def, s, ref_donor);
+      } else {
+        upb_def_unref(def, s);
+      }
+    }
+  }
+  upb_strtable_uninit(&addtab);
+  upb_gfree(add_defs);
+  assert(!upb_ok(status));
+  return false;
+}
+
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                    void *ref_donor, upb_status *status) {
+  return symtab_add(s, defs, n, ref_donor, NULL, status);
+}
+
+bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) {
+  size_t n;
+  size_t i;
+  upb_def **defs;
+  bool ret;
+
+  n = upb_filedef_defcount(file);
+  defs = upb_gmalloc(sizeof(*defs) * n);
+
+  if (defs == NULL) {
+    upb_status_seterrmsg(status, "Out of memory");
+    return false;
+  }
+
+  for (i = 0; i < n; i++) {
+    defs[i] = upb_filedef_mutabledef(file, i);
+  }
+
+  ret = symtab_add(s, defs, n, NULL, upb_filedef_upcast_mutable(file), status);
+
+  upb_gfree(defs);
+  return ret;
+}
+
+/* Iteration. */
+
+static void advance_to_matching(upb_symtab_iter *iter) {
+  if (iter->type == UPB_DEF_ANY)
+    return;
+
+  while (!upb_strtable_done(&iter->iter) &&
+         iter->type != upb_symtab_iter_def(iter)->type) {
+    upb_strtable_next(&iter->iter);
+  }
+}
+
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type) {
+  upb_strtable_begin(&iter->iter, &s->symtab);
+  iter->type = type;
+  advance_to_matching(iter);
+}
+
+void upb_symtab_next(upb_symtab_iter *iter) {
+  upb_strtable_next(&iter->iter);
+  advance_to_matching(iter);
+}
+
+bool upb_symtab_done(const upb_symtab_iter *iter) {
+  return upb_strtable_done(&iter->iter);
+}
+
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) {
+  return upb_value_getptr(upb_strtable_iter_value(&iter->iter));
+}
+/*
+** upb_table Implementation
+**
+** Implementation is heavily inspired by Lua's ltable.c.
+*/
+
+
+#include <string.h>
+
+#define UPB_MAXARRSIZE 16  /* 64k. */
+
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+    ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
+#ifdef NDEBUG
+static void upb_check_alloc(upb_table *t, upb_alloc *a) {
+  UPB_UNUSED(t);
+  UPB_UNUSED(a);
+}
+#else
+static void upb_check_alloc(upb_table *t, upb_alloc *a) {
+  assert(t->alloc == a);
+}
+#endif
+
+static const double MAX_LOAD = 0.85;
+
+/* The minimum utilization of the array part of a mixed hash/array table.  This
+ * is a speed/memory-usage tradeoff (though it's not straightforward because of
+ * cache effects).  The lower this is, the more memory we'll use. */
+static const double MIN_DENSITY = 0.1;
+
+bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
+
+int log2ceil(uint64_t v) {
+  int ret = 0;
+  bool pow2 = is_pow2(v);
+  while (v >>= 1) ret++;
+  ret = pow2 ? ret : ret + 1;  /* Ceiling. */
+  return UPB_MIN(UPB_MAXARRSIZE, ret);
+}
+
+char *upb_strdup(const char *s, upb_alloc *a) {
+  return upb_strdup2(s, strlen(s), a);
+}
+
+char *upb_strdup2(const char *s, size_t len, upb_alloc *a) {
+  size_t n;
+  char *p;
+
+  /* Prevent overflow errors. */
+  if (len == SIZE_MAX) return NULL;
+  /* Always null-terminate, even if binary data; but don't rely on the input to
+   * have a null-terminating byte since it may be a raw binary buffer. */
+  n = len + 1;
+  p = upb_malloc(a, n);
+  if (p) {
+    memcpy(p, s, len);
+    p[len] = 0;
+  }
+  return p;
+}
+
+/* A type to represent the lookup key of either a strtable or an inttable. */
+typedef union {
+  uintptr_t num;
+  struct {
+    const char *str;
+    size_t len;
+  } str;
+} lookupkey_t;
+
+static lookupkey_t strkey2(const char *str, size_t len) {
+  lookupkey_t k;
+  k.str.str = str;
+  k.str.len = len;
+  return k;
+}
+
+static lookupkey_t intkey(uintptr_t key) {
+  lookupkey_t k;
+  k.num = key;
+  return k;
+}
+
+typedef uint32_t hashfunc_t(upb_tabkey key);
+typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
+
+/* Base table (shared code) ***************************************************/
+
+/* For when we need to cast away const. */
+static upb_tabent *mutable_entries(upb_table *t) {
+  return (upb_tabent*)t->entries;
+}
+
+static bool isfull(upb_table *t) {
+  if (upb_table_size(t) == 0) {
+    return true;
+  } else {
+    return ((double)(t->count + 1) / upb_table_size(t)) > MAX_LOAD;
+  }
+}
+
+static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2,
+                 upb_alloc *a) {
+  size_t bytes;
+
+  t->count = 0;
+  t->ctype = ctype;
+  t->size_lg2 = size_lg2;
+  t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
+#ifndef NDEBUG
+  t->alloc = a;
+#endif
+  bytes = upb_table_size(t) * sizeof(upb_tabent);
+  if (bytes > 0) {
+    t->entries = upb_malloc(a, bytes);
+    if (!t->entries) return false;
+    memset(mutable_entries(t), 0, bytes);
+  } else {
+    t->entries = NULL;
+  }
+  return true;
+}
+
+static void uninit(upb_table *t, upb_alloc *a) {
+  upb_check_alloc(t, a);
+  upb_free(a, mutable_entries(t));
+}
+
+static upb_tabent *emptyent(upb_table *t) {
+  upb_tabent *e = mutable_entries(t) + upb_table_size(t);
+  while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); }
+}
+
+static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+  return (upb_tabent*)upb_getentry(t, hash);
+}
+
+static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
+                                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e;
+
+  if (t->size_lg2 == 0) return NULL;
+  e = upb_getentry(t, hash);
+  if (upb_tabent_isempty(e)) return NULL;
+  while (1) {
+    if (eql(e->key, key)) return e;
+    if ((e = e->next) == NULL) return NULL;
+  }
+}
+
+static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
+                                     uint32_t hash, eqlfunc_t *eql) {
+  return (upb_tabent*)findentry(t, key, hash, eql);
+}
+
+static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
+                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e = findentry(t, key, hash, eql);
+  if (e) {
+    if (v) {
+      _upb_value_setval(v, e->val.val, t->ctype);
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* The given key must not already exist in the table. */
+static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
+                   upb_value val, uint32_t hash,
+                   hashfunc_t *hashfunc, eqlfunc_t *eql) {
+  upb_tabent *mainpos_e;
+  upb_tabent *our_e;
+
+  UPB_UNUSED(eql);
+  UPB_UNUSED(key);
+  assert(findentry(t, key, hash, eql) == NULL);
+  assert(val.ctype == t->ctype);
+
+  t->count++;
+  mainpos_e = getentry_mutable(t, hash);
+  our_e = mainpos_e;
+
+  if (upb_tabent_isempty(mainpos_e)) {
+    /* Our main position is empty; use it. */
+    our_e->next = NULL;
+  } else {
+    /* Collision. */
+    upb_tabent *new_e = emptyent(t);
+    /* Head of collider's chain. */
+    upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+    if (chain == mainpos_e) {
+      /* Existing ent is in its main posisiton (it has the same hash as us, and
+       * is the head of our chain).  Insert to new ent and append to this chain. */
+      new_e->next = mainpos_e->next;
+      mainpos_e->next = new_e;
+      our_e = new_e;
+    } else {
+      /* Existing ent is not in its main position (it is a node in some other
+       * chain).  This implies that no existing ent in the table has our hash.
+       * Evict it (updating its chain) and use its ent for head of our chain. */
+      *new_e = *mainpos_e;  /* copies next. */
+      while (chain->next != mainpos_e) {
+        chain = (upb_tabent*)chain->next;
+        assert(chain);
+      }
+      chain->next = new_e;
+      our_e = mainpos_e;
+      our_e->next = NULL;
+    }
+  }
+  our_e->key = tabkey;
+  our_e->val.val = val.val;
+  assert(findentry(t, key, hash, eql) == our_e);
+}
+
+static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
+               upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
+  upb_tabent *chain = getentry_mutable(t, hash);
+  if (upb_tabent_isempty(chain)) return false;
+  if (eql(chain->key, key)) {
+    /* Element to remove is at the head of its chain. */
+    t->count--;
+    if (val) {
+      _upb_value_setval(val, chain->val.val, t->ctype);
+    }
+    if (chain->next) {
+      upb_tabent *move = (upb_tabent*)chain->next;
+      *chain = *move;
+      if (removed) *removed = move->key;
+      move->key = 0;  /* Make the slot empty. */
+    } else {
+      if (removed) *removed = chain->key;
+      chain->key = 0;  /* Make the slot empty. */
+    }
+    return true;
+  } else {
+    /* Element to remove is either in a non-head position or not in the
+     * table. */
+    while (chain->next && !eql(chain->next->key, key))
+      chain = (upb_tabent*)chain->next;
+    if (chain->next) {
+      /* Found element to remove. */
+      upb_tabent *rm;
+
+      if (val) {
+        _upb_value_setval(val, chain->next->val.val, t->ctype);
+      }
+      rm = (upb_tabent*)chain->next;
+      if (removed) *removed = rm->key;
+      rm->key = 0;
+      chain->next = rm->next;
+      t->count--;
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
+
+static size_t next(const upb_table *t, size_t i) {
+  do {
+    if (++i >= upb_table_size(t))
+      return SIZE_MAX;
+  } while(upb_tabent_isempty(&t->entries[i]));
+
+  return i;
+}
+
+static size_t begin(const upb_table *t) {
+  return next(t, -1);
+}
+
+
+/* upb_strtable ***************************************************************/
+
+/* A simple "subclass" of upb_table that only adds a hash function for strings. */
+
+static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) {
+  char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
+  if (str == NULL) return 0;
+  memcpy(str, &k2.str.len, sizeof(uint32_t));
+  memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1);
+  return (uintptr_t)str;
+}
+
+static uint32_t strhash(upb_tabkey key) {
+  uint32_t len;
+  char *str = upb_tabstr(key, &len);
+  return MurmurHash2(str, len, 0);
+}
+
+static bool streql(upb_tabkey k1, lookupkey_t k2) {
+  uint32_t len;
+  char *str = upb_tabstr(k1, &len);
+  return len == k2.str.len && memcmp(str, k2.str.str, len) == 0;
+}
+
+bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) {
+  return init(&t->t, ctype, 2, a);
+}
+
+void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) {
+  size_t i;
+  for (i = 0; i < upb_table_size(&t->t); i++)
+    upb_free(a, (void*)t->t.entries[i].key);
+  uninit(&t->t, a);
+}
+
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) {
+  upb_strtable new_table;
+  upb_strtable_iter i;
+
+  upb_check_alloc(&t->t, a);
+
+  if (!init(&new_table.t, t->t.ctype, size_lg2, a))
+    return false;
+  upb_strtable_begin(&i, t);
+  for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    upb_strtable_insert3(
+        &new_table,
+        upb_strtable_iter_key(&i),
+        upb_strtable_iter_keylength(&i),
+        upb_strtable_iter_value(&i),
+        a);
+  }
+  upb_strtable_uninit2(t, a);
+  *t = new_table;
+  return true;
+}
+
+bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len,
+                          upb_value v, upb_alloc *a) {
+  lookupkey_t key;
+  upb_tabkey tabkey;
+  uint32_t hash;
+
+  upb_check_alloc(&t->t, a);
+
+  if (isfull(&t->t)) {
+    /* Need to resize.  New table of double the size, add old elements to it. */
+    if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) {
+      return false;
+    }
+  }
+
+  key = strkey2(k, len);
+  tabkey = strcopy(key, a);
+  if (tabkey == 0) return false;
+
+  hash = MurmurHash2(key.str.str, key.str.len, 0);
+  insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
+  return true;
+}
+
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v) {
+  uint32_t hash = MurmurHash2(key, len, 0);
+  return lookup(&t->t, strkey2(key, len), v, hash, &streql);
+}
+
+bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
+                         upb_value *val, upb_alloc *alloc) {
+  uint32_t hash = MurmurHash2(key, strlen(key), 0);
+  upb_tabkey tabkey;
+  if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
+    upb_free(alloc, (void*)tabkey);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* Iteration */
+
+static const upb_tabent *str_tabent(const upb_strtable_iter *i) {
+  return &i->t->t.entries[i->index];
+}
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+  i->t = t;
+  i->index = begin(&t->t);
+}
+
+void upb_strtable_next(upb_strtable_iter *i) {
+  i->index = next(&i->t->t, i->index);
+}
+
+bool upb_strtable_done(const upb_strtable_iter *i) {
+  return i->index >= upb_table_size(&i->t->t) ||
+         upb_tabent_isempty(str_tabent(i));
+}
+
+const char *upb_strtable_iter_key(const upb_strtable_iter *i) {
+  assert(!upb_strtable_done(i));
+  return upb_tabstr(str_tabent(i)->key, NULL);
+}
+
+size_t upb_strtable_iter_keylength(const upb_strtable_iter *i) {
+  uint32_t len;
+  assert(!upb_strtable_done(i));
+  upb_tabstr(str_tabent(i)->key, &len);
+  return len;
+}
+
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+  assert(!upb_strtable_done(i));
+  return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype);
+}
+
+void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+  i->index = SIZE_MAX;
+}
+
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2) {
+  if (upb_strtable_done(i1) && upb_strtable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index;
+}
+
+
+/* upb_inttable ***************************************************************/
+
+/* For inttables we use a hybrid structure where small keys are kept in an
+ * array and large keys are put in the hash table. */
+
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
+
+static bool inteql(upb_tabkey k1, lookupkey_t k2) {
+  return k1 == k2.num;
+}
+
+static upb_tabval *mutable_array(upb_inttable *t) {
+  return (upb_tabval*)t->array;
+}
+
+static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) {
+  if (key < t->array_size) {
+    return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
+  } else {
+    upb_tabent *e =
+        findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
+    return e ? &e->val : NULL;
+  }
+}
+
+static const upb_tabval *inttable_val_const(const upb_inttable *t,
+                                            uintptr_t key) {
+  return inttable_val((upb_inttable*)t, key);
+}
+
+size_t upb_inttable_count(const upb_inttable *t) {
+  return t->t.count + t->array_count;
+}
+
+static void check(upb_inttable *t) {
+  UPB_UNUSED(t);
+#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
+  {
+    /* This check is very expensive (makes inserts/deletes O(N)). */
+    size_t count = 0;
+    upb_inttable_iter i;
+    upb_inttable_begin(&i, t);
+    for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+      assert(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
+    }
+    assert(count == upb_inttable_count(t));
+  }
+#endif
+}
+
+bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype,
+                            size_t asize, int hsize_lg2, upb_alloc *a) {
+  size_t array_bytes;
+
+  if (!init(&t->t, ctype, hsize_lg2, a)) return false;
+  /* Always make the array part at least 1 long, so that we know key 0
+   * won't be in the hash part, which simplifies things. */
+  t->array_size = UPB_MAX(1, asize);
+  t->array_count = 0;
+  array_bytes = t->array_size * sizeof(upb_value);
+  t->array = upb_malloc(a, array_bytes);
+  if (!t->array) {
+    uninit(&t->t, a);
+    return false;
+  }
+  memset(mutable_array(t), 0xff, array_bytes);
+  check(t);
+  return true;
+}
+
+bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) {
+  return upb_inttable_sizedinit(t, ctype, 0, 4, a);
+}
+
+void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) {
+  uninit(&t->t, a);
+  upb_free(a, mutable_array(t));
+}
+
+bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
+                          upb_alloc *a) {
+  upb_tabval tabval;
+  tabval.val = val.val;
+  UPB_UNUSED(tabval);
+  assert(upb_arrhas(tabval));  /* This will reject (uint64_t)-1.  Fix this. */
+
+  upb_check_alloc(&t->t, a);
+
+  if (key < t->array_size) {
+    assert(!upb_arrhas(t->array[key]));
+    t->array_count++;
+    mutable_array(t)[key].val = val.val;
+  } else {
+    if (isfull(&t->t)) {
+      /* Need to resize the hash part, but we re-use the array part. */
+      size_t i;
+      upb_table new_table;
+
+      if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1, a)) {
+        return false;
+      }
+
+      for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
+        const upb_tabent *e = &t->t.entries[i];
+        uint32_t hash;
+        upb_value v;
+
+        _upb_value_setval(&v, e->val.val, t->t.ctype);
+        hash = upb_inthash(e->key);
+        insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
+      }
+
+      assert(t->t.count == new_table.count);
+
+      uninit(&t->t, a);
+      t->t = new_table;
+    }
+    insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
+  }
+  check(t);
+  return true;
+}
+
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
+  const upb_tabval *table_v = inttable_val_const(t, key);
+  if (!table_v) return false;
+  if (v) _upb_value_setval(v, table_v->val, t->t.ctype);
+  return true;
+}
+
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
+  upb_tabval *table_v = inttable_val(t, key);
+  if (!table_v) return false;
+  table_v->val = val.val;
+  return true;
+}
+
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+  bool success;
+  if (key < t->array_size) {
+    if (upb_arrhas(t->array[key])) {
+      upb_tabval empty = UPB_TABVALUE_EMPTY_INIT;
+      t->array_count--;
+      if (val) {
+        _upb_value_setval(val, t->array[key].val, t->t.ctype);
+      }
+      mutable_array(t)[key] = empty;
+      success = true;
+    } else {
+      success = false;
+    }
+  } else {
+    upb_tabkey removed;
+    uint32_t hash = upb_inthash(key);
+    success = rm(&t->t, intkey(key), val, &removed, hash, &inteql);
+  }
+  check(t);
+  return success;
+}
+
+bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) {
+  upb_check_alloc(&t->t, a);
+  return upb_inttable_insert2(t, upb_inttable_count(t), val, a);
+}
+
+upb_value upb_inttable_pop(upb_inttable *t) {
+  upb_value val;
+  bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val);
+  UPB_ASSERT_VAR(ok, ok);
+  return val;
+}
+
+bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
+                             upb_alloc *a) {
+  upb_check_alloc(&t->t, a);
+  return upb_inttable_insert2(t, (uintptr_t)key, val, a);
+}
+
+bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
+                            upb_value *v) {
+  return upb_inttable_lookup(t, (uintptr_t)key, v);
+}
+
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
+  return upb_inttable_remove(t, (uintptr_t)key, val);
+}
+
+void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) {
+  /* A power-of-two histogram of the table keys. */
+  size_t counts[UPB_MAXARRSIZE + 1] = {0};
+
+  /* The max key in each bucket. */
+  uintptr_t max[UPB_MAXARRSIZE + 1] = {0};
+
+  upb_inttable_iter i;
+  size_t arr_count;
+  int size_lg2;
+  upb_inttable new_t;
+
+  upb_check_alloc(&t->t, a);
+
+  upb_inttable_begin(&i, t);
+  for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    uintptr_t key = upb_inttable_iter_key(&i);
+    int bucket = log2ceil(key);
+    max[bucket] = UPB_MAX(max[bucket], key);
+    counts[bucket]++;
+  }
+
+  /* Find the largest power of two that satisfies the MIN_DENSITY
+   * definition (while actually having some keys). */
+  arr_count = upb_inttable_count(t);
+
+  for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) {
+    if (counts[size_lg2] == 0) {
+      /* We can halve again without losing any entries. */
+      continue;
+    } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) {
+      break;
+    }
+
+    arr_count -= counts[size_lg2];
+  }
+
+  assert(arr_count <= upb_inttable_count(t));
+
+  {
+    /* Insert all elements into new, perfectly-sized table. */
+    size_t arr_size = max[size_lg2] + 1;  /* +1 so arr[max] will fit. */
+    size_t hash_count = upb_inttable_count(t) - arr_count;
+    size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
+    size_t hashsize_lg2 = log2ceil(hash_size);
+
+    upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2, a);
+    upb_inttable_begin(&i, t);
+    for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+      uintptr_t k = upb_inttable_iter_key(&i);
+      upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a);
+    }
+    assert(new_t.array_size == arr_size);
+    assert(new_t.t.size_lg2 == hashsize_lg2);
+  }
+  upb_inttable_uninit2(t, a);
+  *t = new_t;
+}
+
+/* Iteration. */
+
+static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+  assert(!i->array_part);
+  return &i->t->t.entries[i->index];
+}
+
+static upb_tabval int_arrent(const upb_inttable_iter *i) {
+  assert(i->array_part);
+  return i->t->array[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+  i->t = t;
+  i->index = -1;
+  i->array_part = true;
+  upb_inttable_next(i);
+}
+
+void upb_inttable_next(upb_inttable_iter *iter) {
+  const upb_inttable *t = iter->t;
+  if (iter->array_part) {
+    while (++iter->index < t->array_size) {
+      if (upb_arrhas(int_arrent(iter))) {
+        return;
+      }
+    }
+    iter->array_part = false;
+    iter->index = begin(&t->t);
+  } else {
+    iter->index = next(&t->t, iter->index);
+  }
+}
+
+bool upb_inttable_done(const upb_inttable_iter *i) {
+  if (i->array_part) {
+    return i->index >= i->t->array_size ||
+           !upb_arrhas(int_arrent(i));
+  } else {
+    return i->index >= upb_table_size(&i->t->t) ||
+           upb_tabent_isempty(int_tabent(i));
+  }
+}
+
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+  assert(!upb_inttable_done(i));
+  return i->array_part ? i->index : int_tabent(i)->key;
+}
+
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+  assert(!upb_inttable_done(i));
+  return _upb_value_val(
+      i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val,
+      i->t->t.ctype);
+}
+
+void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+  i->index = SIZE_MAX;
+  i->array_part = false;
+}
+
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                                          const upb_inttable_iter *i2) {
+  if (upb_inttable_done(i1) && upb_inttable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index &&
+         i1->array_part == i2->array_part;
+}
+
+#ifdef UPB_UNALIGNED_READS_OK
+/* -----------------------------------------------------------------------------
+ * MurmurHash2, by Austin Appleby (released as public domain).
+ * Reformatted and C99-ified by Joshua Haberman.
+ * Note - This code makes a few assumptions about how your machine behaves -
+ *   1. We can read a 4-byte value from any address without crashing
+ *   2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t
+ * And it has a few limitations -
+ *   1. It will not work incrementally.
+ *   2. It will not produce the same results on little-endian and big-endian
+ *      machines. */
+uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) {
+  /* 'm' and 'r' are mixing constants generated offline.
+   * They're not really 'magic', they just happen to work well. */
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+
+  /* Initialize the hash to a 'random' value */
+  uint32_t h = seed ^ len;
+
+  /* Mix 4 bytes at a time into the hash */
+  const uint8_t * data = (const uint8_t *)key;
+  while(len >= 4) {
+    uint32_t k = *(uint32_t *)data;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h *= m;
+    h ^= k;
+
+    data += 4;
+    len -= 4;
+  }
+
+  /* Handle the last few bytes of the input array */
+  switch(len) {
+    case 3: h ^= data[2] << 16;
+    case 2: h ^= data[1] << 8;
+    case 1: h ^= data[0]; h *= m;
+  };
+
+  /* Do a few final mixes of the hash to ensure the last few
+   * bytes are well-incorporated. */
+  h ^= h >> 13;
+  h *= m;
+  h ^= h >> 15;
+
+  return h;
+}
+
+#else /* !UPB_UNALIGNED_READS_OK */
+
+/* -----------------------------------------------------------------------------
+ * MurmurHashAligned2, by Austin Appleby
+ * Same algorithm as MurmurHash2, but only does aligned reads - should be safer
+ * on certain platforms.
+ * Performance will be lower than MurmurHash2 */
+
+#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) {
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+  const uint8_t * data = (const uint8_t *)key;
+  uint32_t h = seed ^ len;
+  uint8_t align = (uintptr_t)data & 3;
+
+  if(align && (len >= 4)) {
+    /* Pre-load the temp registers */
+    uint32_t t = 0, d = 0;
+    int32_t sl;
+    int32_t sr;
+
+    switch(align) {
+      case 1: t |= data[2] << 16;
+      case 2: t |= data[1] << 8;
+      case 3: t |= data[0];
+    }
+
+    t <<= (8 * align);
+
+    data += 4-align;
+    len -= 4-align;
+
+    sl = 8 * (4-align);
+    sr = 8 * align;
+
+    /* Mix */
+
+    while(len >= 4) {
+      uint32_t k;
+
+      d = *(uint32_t *)data;
+      t = (t >> sr) | (d << sl);
+
+      k = t;
+
+      MIX(h,k,m);
+
+      t = d;
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* Handle leftover data in temp registers */
+
+    d = 0;
+
+    if(len >= align) {
+      uint32_t k;
+
+      switch(align) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+      }
+
+      k = (t >> sr) | (d << sl);
+      MIX(h,k,m);
+
+      data += align;
+      len -= align;
+
+      /* ----------
+       * Handle tail bytes */
+
+      switch(len) {
+        case 3: h ^= data[2] << 16;
+        case 2: h ^= data[1] << 8;
+        case 1: h ^= data[0]; h *= m;
+      };
+    } else {
+      switch(len) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+        case 0: h ^= (t >> sr) | (d << sl); h *= m;
+      }
+    }
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  } else {
+    while(len >= 4) {
+      uint32_t k = *(uint32_t *)data;
+
+      MIX(h,k,m);
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* ----------
+     * Handle tail bytes */
+
+    switch(len) {
+      case 3: h ^= data[2] << 16;
+      case 2: h ^= data[1] << 8;
+      case 1: h ^= data[0]; h *= m;
+    };
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  }
+}
+#undef MIX
+
+#endif /* UPB_UNALIGNED_READS_OK */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool upb_dumptostderr(void *closure, const upb_status* status) {
+  UPB_UNUSED(closure);
+  fprintf(stderr, "%s\n", upb_status_errmsg(status));
+  return false;
+}
+
+/* Guarantee null-termination and provide ellipsis truncation.
+ * It may be tempting to "optimize" this by initializing these final
+ * four bytes up-front and then being careful never to overwrite them,
+ * this is safer and simpler. */
+static void nullz(upb_status *status) {
+  const char *ellipsis = "...";
+  size_t len = strlen(ellipsis);
+  assert(sizeof(status->msg) > len);
+  memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
+}
+
+
+/* upb_upberr *****************************************************************/
+
+upb_errorspace upb_upberr = {"upb error"};
+
+void upb_upberr_setoom(upb_status *status) {
+  status->error_space_ = &upb_upberr;
+  upb_status_seterrmsg(status, "Out of memory");
+}
+
+
+/* upb_status *****************************************************************/
+
+void upb_status_clear(upb_status *status) {
+  if (!status) return;
+  status->ok_ = true;
+  status->code_ = 0;
+  status->msg[0] = '\0';
+}
+
+bool upb_ok(const upb_status *status) { return status->ok_; }
+
+upb_errorspace *upb_status_errspace(const upb_status *status) {
+  return status->error_space_;
+}
+
+int upb_status_errcode(const upb_status *status) { return status->code_; }
+
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+  if (!status) return;
+  status->ok_ = false;
+  strncpy(status->msg, msg, sizeof(status->msg));
+  nullz(status);
+}
+
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  upb_status_vseterrf(status, fmt, args);
+  va_end(args);
+}
+
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+  if (!status) return;
+  status->ok_ = false;
+  _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+  nullz(status);
+}
+
+void upb_status_copy(upb_status *to, const upb_status *from) {
+  if (!to) return;
+  *to = *from;
+}
+
+
+/* upb_alloc ******************************************************************/
+
+static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                                  size_t size) {
+  UPB_UNUSED(alloc);
+  UPB_UNUSED(oldsize);
+  if (size == 0) {
+    free(ptr);
+    return NULL;
+  } else {
+    return realloc(ptr, size);
+  }
+}
+
+upb_alloc upb_alloc_global = {&upb_global_allocfunc};
+
+
+/* upb_arena ******************************************************************/
+
+/* Be conservative and choose 16 in case anyone is using SSE. */
+static const size_t maxalign = 16;
+
+static size_t align_up(size_t size) {
+  return ((size + maxalign - 1) / maxalign) * maxalign;
+}
+
+typedef struct mem_block {
+  struct mem_block *next;
+  size_t size;
+  size_t used;
+  bool owned;
+  /* Data follows. */
+} mem_block;
+
+typedef struct cleanup_ent {
+  struct cleanup_ent *next;
+  upb_cleanup_func *cleanup;
+  void *ud;
+} cleanup_ent;
+
+static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size,
+                               bool owned) {
+  mem_block *block = ptr;
+
+  block->next = a->block_head;
+  block->size = size;
+  block->used = align_up(sizeof(mem_block));
+  block->owned = owned;
+
+  a->block_head = block;
+
+  /* TODO(haberman): ASAN poison. */
+}
+
+
+static mem_block *upb_arena_allocblock(upb_arena *a, size_t size) {
+  size_t block_size = UPB_MAX(size, a->next_block_size) + sizeof(mem_block);
+  mem_block *block = upb_malloc(a->block_alloc, block_size);
+
+  if (!block) {
+    return NULL;
+  }
+
+  upb_arena_addblock(a, block, block_size, true);
+  a->next_block_size = UPB_MIN(block_size * 2, a->max_block_size);
+
+  return block;
+}
+
+static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                               size_t size) {
+  upb_arena *a = (upb_arena*)alloc;  /* upb_alloc is initial member. */
+  mem_block *block = a->block_head;
+  void *ret;
+
+  if (size == 0) {
+    return NULL;  /* We are an arena, don't need individual frees. */
+  }
+
+  size = align_up(size);
+
+  /* TODO(haberman): special-case if this is a realloc of the last alloc? */
+
+  if (!block || block->size - block->used < size) {
+    /* Slow path: have to allocate a new block. */
+    block = upb_arena_allocblock(a, size);
+
+    if (!block) {
+      return NULL;  /* Out of memory. */
+    }
+  }
+
+  ret = (char*)block + block->used;
+  block->used += size;
+
+  if (oldsize > 0) {
+    memcpy(ret, ptr, oldsize);  /* Preserve existing data. */
+  }
+
+  /* TODO(haberman): ASAN unpoison. */
+
+  a->bytes_allocated += size;
+  return ret;
+}
+
+/* Public Arena API ***********************************************************/
+
+void upb_arena_init(upb_arena *a) {
+  a->alloc.func = &upb_arena_doalloc;
+  a->block_alloc = &upb_alloc_global;
+  a->bytes_allocated = 0;
+  a->next_block_size = 256;
+  a->max_block_size = 16384;
+  a->cleanup_head = NULL;
+  a->block_head = NULL;
+}
+
+void upb_arena_init2(upb_arena *a, void *mem, size_t size, upb_alloc *alloc) {
+  upb_arena_init(a);
+
+  if (size > sizeof(mem_block)) {
+    upb_arena_addblock(a, mem, size, false);
+  }
+
+  if (alloc) {
+    a->block_alloc = alloc;
+  }
+}
+
+void upb_arena_uninit(upb_arena *a) {
+  cleanup_ent *ent = a->cleanup_head;
+  mem_block *block = a->block_head;
+
+  while (ent) {
+    ent->cleanup(ent->ud);
+    ent = ent->next;
+  }
+
+  /* Must do this after running cleanup functions, because this will delete
+   * the memory we store our cleanup entries in! */
+  while (block) {
+    mem_block *next = block->next;
+
+    if (block->owned) {
+      upb_free(a->block_alloc, block);
+    }
+
+    block = next;
+  }
+}
+
+bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud) {
+  cleanup_ent *ent = upb_malloc(&a->alloc, sizeof(cleanup_ent));
+  if (!ent) {
+    return false;  /* Out of memory. */
+  }
+
+  ent->cleanup = func;
+  ent->ud = ud;
+  ent->next = a->cleanup_head;
+  a->cleanup_head = ent;
+
+  return true;
+}
+
+size_t upb_arena_bytesallocated(const upb_arena *a) {
+  return a->bytes_allocated;
+}
+
+
+/* Standard error functions ***************************************************/
+
+static bool default_err(void *ud, const upb_status *status) {
+  UPB_UNUSED(ud);
+  UPB_UNUSED(status);
+  return false;
+}
+
+static bool write_err_to(void *ud, const upb_status *status) {
+  upb_status *copy_to = ud;
+  upb_status_copy(copy_to, status);
+  return false;
+}
+
+
+/* upb_env ********************************************************************/
+
+void upb_env_initonly(upb_env *e) {
+  e->ok_ = true;
+  e->error_func_ = &default_err;
+  e->error_ud_ = NULL;
+}
+
+void upb_env_init(upb_env *e) {
+  upb_arena_init(&e->arena_);
+  upb_env_initonly(e);
+}
+
+void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc) {
+  upb_arena_init2(&e->arena_, mem, n, alloc);
+  upb_env_initonly(e);
+}
+
+void upb_env_uninit(upb_env *e) {
+  upb_arena_uninit(&e->arena_);
+}
+
+void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud) {
+  e->error_func_ = func;
+  e->error_ud_ = ud;
+}
+
+void upb_env_reporterrorsto(upb_env *e, upb_status *s) {
+  e->error_func_ = &write_err_to;
+  e->error_ud_ = s;
+}
+
+bool upb_env_reporterror(upb_env *e, const upb_status *status) {
+  e->ok_ = false;
+  return e->error_func_(e->error_ud_, status);
+}
+
+void *upb_env_malloc(upb_env *e, size_t size) {
+  return upb_malloc(&e->arena_.alloc, size);
+}
+
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) {
+  return upb_realloc(&e->arena_.alloc, ptr, oldsize, size);
+}
+
+void upb_env_free(upb_env *e, void *ptr) {
+  upb_free(&e->arena_.alloc, ptr);
+}
+
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) {
+  return upb_arena_addcleanup(&e->arena_, func, ud);
+}
+
+size_t upb_env_bytesallocated(const upb_env *e) {
+  return upb_arena_bytesallocated(&e->arena_);
+}
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     upb/descriptor/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <assert.h>
+
+
+static const upb_msgdef msgs[22];
+static const upb_fielddef fields[105];
+static const upb_enumdef enums[5];
+static const upb_tabent strentries[236];
+static const upb_tabent intentries[18];
+static const upb_tabval arrays[184];
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[264];
+#endif
+
+static const upb_msgdef msgs[22] = {
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 40, 8, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[0]), false, UPB_SYNTAX_PROTO2, &reftables[0], &reftables[1]),
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]), false, UPB_SYNTAX_PROTO2, &reftables[2], &reftables[3]),
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ReservedRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[14], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[20]), false, UPB_SYNTAX_PROTO2, &reftables[4], &reftables[5]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[17], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[24]), false, UPB_SYNTAX_PROTO2, &reftables[6], &reftables[7]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[21], 4, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]), false, UPB_SYNTAX_PROTO2, &reftables[8], &reftables[9]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[25], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[32]), false, UPB_SYNTAX_PROTO2, &reftables[10], &reftables[11]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[29], 2, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[36]), false, UPB_SYNTAX_PROTO2, &reftables[12], &reftables[13]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 23, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[40]), false, UPB_SYNTAX_PROTO2, &reftables[14], &reftables[15]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[42], 11, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[56]), false, UPB_SYNTAX_PROTO2, &reftables[16], &reftables[17]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 42, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[53], 13, 12), UPB_STRTABLE_INIT(12, 15, UPB_CTYPE_PTR, 4, &strentries[72]), false, UPB_SYNTAX_PROTO2, &reftables[18], &reftables[19]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[66], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[88]), false, UPB_SYNTAX_PROTO2, &reftables[20], &reftables[21]),
+  UPB_MSGDEF_INIT("google.protobuf.FileOptions", 31, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[68], 39, 15), UPB_STRTABLE_INIT(16, 31, UPB_CTYPE_PTR, 5, &strentries[92]), false, UPB_SYNTAX_PROTO2, &reftables[22], &reftables[23]),
+  UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 10, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[107], 8, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[124]), false, UPB_SYNTAX_PROTO2, &reftables[24], &reftables[25]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 15, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[115], 7, 6), UPB_STRTABLE_INIT(6, 7, UPB_CTYPE_PTR, 3, &strentries[132]), false, UPB_SYNTAX_PROTO2, &reftables[26], &reftables[27]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[10], &arrays[122], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[140]), false, UPB_SYNTAX_PROTO2, &reftables[28], &reftables[29]),
+  UPB_MSGDEF_INIT("google.protobuf.OneofDescriptorProto", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[123], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[144]), false, UPB_SYNTAX_PROTO2, &reftables[30], &reftables[31]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[125], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[148]), false, UPB_SYNTAX_PROTO2, &reftables[32], &reftables[33]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[14], &arrays[129], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[152]), false, UPB_SYNTAX_PROTO2, &reftables[34], &reftables[35]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[130], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[156]), false, UPB_SYNTAX_PROTO2, &reftables[36], &reftables[37]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 19, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[132], 7, 5), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[160]), false, UPB_SYNTAX_PROTO2, &reftables[38], &reftables[39]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[139], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[168]), false, UPB_SYNTAX_PROTO2, &reftables[40], &reftables[41]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[148], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[184]), false, UPB_SYNTAX_PROTO2, &reftables[42], &reftables[43]),
+};
+
+static const upb_fielddef fields[105] = {
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[20], NULL, 15, 6, {0},&reftables[44], &reftables[45]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[4], NULL, 6, 1, {0},&reftables[46], &reftables[47]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_enable_arenas", 31, &msgs[11], NULL, 23, 12, {0},&reftables[48], &reftables[49]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[11], NULL, 17, 6, {0},&reftables[50], &reftables[51]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "client_streaming", 5, &msgs[13], NULL, 13, 4, {0},&reftables[52], &reftables[53]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "csharp_namespace", 37, &msgs[11], NULL, 27, 14, {0},&reftables[54], &reftables[55]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[8], (const upb_def*)(&enums[2]), 6, 1, {0},&reftables[56], &reftables[57]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[7], NULL, 16, 7, {0},&reftables[58], &reftables[59]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[9], NULL, 30, 8, {0},&reftables[60], &reftables[61]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[12], NULL, 8, 3, {0},&reftables[62], &reftables[63]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[8], NULL, 8, 3, {0},&reftables[64], &reftables[65]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[14], NULL, 6, 1, {0},&reftables[66], &reftables[67]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 23, &msgs[11], NULL, 21, 10, {0},&reftables[68], &reftables[69]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[4], NULL, 7, 2, {0},&reftables[70], &reftables[71]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[17], NULL, 6, 1, {0},&reftables[72], &reftables[73]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 1, &msgs[6], NULL, 6, 1, {0},&reftables[74], &reftables[75]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[20], NULL, 11, 4, {0},&reftables[76], &reftables[77]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[2], NULL, 3, 1, {0},&reftables[78], &reftables[79]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[80], &reftables[81]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[3]), 18, 2, {0},&reftables[82], &reftables[83]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[9], (const upb_def*)(&msgs[3]), 13, 1, {0},&reftables[84], &reftables[85]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[7], NULL, 7, 2, {0},&reftables[86], &reftables[87]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[7]), 24, 4, {0},&reftables[88], &reftables[89]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[9], (const upb_def*)(&msgs[7]), 19, 3, {0},&reftables[90], &reftables[91]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], (const upb_def*)(&msgs[1]), 21, 3, {0},&reftables[92], &reftables[93]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], (const upb_def*)(&msgs[7]), 12, 0, {0},&reftables[94], &reftables[95]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[10], (const upb_def*)(&msgs[9]), 5, 0, {0},&reftables[96], &reftables[97]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[11], NULL, 14, 5, {0},&reftables[98], &reftables[99]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[20], NULL, 6, 1, {0},&reftables[100], &reftables[101]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[13], NULL, 7, 2, {0},&reftables[102], &reftables[103]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[21], NULL, 5, 1, {0},&reftables[104], &reftables[105]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[11], NULL, 20, 9, {0},&reftables[106], &reftables[107]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[11], NULL, 18, 7, {0},&reftables[108], &reftables[109]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[11], NULL, 13, 4, {0},&reftables[110], &reftables[111]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[11], NULL, 9, 2, {0},&reftables[112], &reftables[113]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[11], NULL, 6, 1, {0},&reftables[114], &reftables[115]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_string_check_utf8", 27, &msgs[11], NULL, 22, 11, {0},&reftables[116], &reftables[117]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "javanano_use_deprecated_package", 38, &msgs[11], NULL, 30, 15, {0},&reftables[118], &reftables[119]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "json_name", 10, &msgs[7], NULL, 20, 9, {0},&reftables[120], &reftables[121]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "jstype", 6, &msgs[8], (const upb_def*)(&enums[3]), 10, 5, {0},&reftables[122], &reftables[123]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[7], (const upb_def*)(&enums[0]), 11, 4, {0},&reftables[124], &reftables[125]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[8], NULL, 9, 4, {0},&reftables[126], &reftables[127]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[19], NULL, 8, 2, {0},&reftables[128], &reftables[129]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "leading_detached_comments", 6, &msgs[19], NULL, 16, 4, {0},&reftables[130], &reftables[131]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[18], (const upb_def*)(&msgs[19]), 5, 0, {0},&reftables[132], &reftables[133]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "map_entry", 7, &msgs[12], NULL, 9, 4, {0},&reftables[134], &reftables[135]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[12], NULL, 6, 1, {0},&reftables[136], &reftables[137]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[9], (const upb_def*)(&msgs[0]), 10, 0, {0},&reftables[138], &reftables[139]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[16], (const upb_def*)(&msgs[13]), 6, 0, {0},&reftables[140], &reftables[141]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[3], NULL, 8, 2, {0},&reftables[142], &reftables[143]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[15], NULL, 2, 0, {0},&reftables[144], &reftables[145]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[20], (const upb_def*)(&msgs[21]), 5, 0, {0},&reftables[146], &reftables[147]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 32, 8, {0},&reftables[148], &reftables[149]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[5], NULL, 4, 1, {0},&reftables[150], &reftables[151]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[9], NULL, 22, 6, {0},&reftables[152], &reftables[153]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[7], NULL, 4, 1, {0},&reftables[154], &reftables[155]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[13], NULL, 4, 1, {0},&reftables[156], &reftables[157]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[16], NULL, 8, 2, {0},&reftables[158], &reftables[159]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[21], NULL, 2, 0, {0},&reftables[160], &reftables[161]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[20], NULL, 10, 3, {0},&reftables[162], &reftables[163]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 15, 1, {0},&reftables[164], &reftables[165]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[12], NULL, 7, 2, {0},&reftables[166], &reftables[167]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[5], NULL, 7, 2, {0},&reftables[168], &reftables[169]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[7], NULL, 10, 3, {0},&reftables[170], &reftables[171]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "objc_class_prefix", 36, &msgs[11], NULL, 24, 13, {0},&reftables[172], &reftables[173]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "oneof_decl", 8, &msgs[0], (const upb_def*)(&msgs[15]), 28, 6, {0},&reftables[174], &reftables[175]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "oneof_index", 9, &msgs[7], NULL, 19, 8, {0},&reftables[176], &reftables[177]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[11], (const upb_def*)(&enums[4]), 12, 3, {0},&reftables[178], &reftables[179]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[12]), 25, 5, {0},&reftables[180], &reftables[181]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[9], (const upb_def*)(&msgs[11]), 20, 4, {0},&reftables[182], &reftables[183]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[13], (const upb_def*)(&msgs[14]), 3, 0, {0},&reftables[184], &reftables[185]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[7], (const upb_def*)(&msgs[8]), 3, 0, {0},&reftables[186], &reftables[187]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[16], (const upb_def*)(&msgs[17]), 7, 1, {0},&reftables[188], &reftables[189]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[5], (const upb_def*)(&msgs[6]), 3, 0, {0},&reftables[190], &reftables[191]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[3], (const upb_def*)(&msgs[4]), 7, 1, {0},&reftables[192], &reftables[193]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[13], NULL, 10, 3, {0},&reftables[194], &reftables[195]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[9], NULL, 25, 7, {0},&reftables[196], &reftables[197]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[8], NULL, 7, 2, {0},&reftables[198], &reftables[199]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[19], NULL, 4, 0, {0},&reftables[200], &reftables[201]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[20], NULL, 9, 2, {0},&reftables[202], &reftables[203]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[9], NULL, 35, 9, {0},&reftables[204], &reftables[205]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[11], NULL, 19, 8, {0},&reftables[206], &reftables[207]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "reserved_name", 10, &msgs[0], NULL, 37, 9, {0},&reftables[208], &reftables[209]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "reserved_range", 9, &msgs[0], (const upb_def*)(&msgs[2]), 31, 7, {0},&reftables[210], &reftables[211]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "server_streaming", 6, &msgs[13], NULL, 14, 5, {0},&reftables[212], &reftables[213]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[9], (const upb_def*)(&msgs[16]), 16, 2, {0},&reftables[214], &reftables[215]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[9], (const upb_def*)(&msgs[18]), 21, 5, {0},&reftables[216], &reftables[217]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[19], NULL, 7, 1, {0},&reftables[218], &reftables[219]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[2], NULL, 2, 0, {0},&reftables[220], &reftables[221]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[222], &reftables[223]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[20], NULL, 12, 5, {0},&reftables[224], &reftables[225]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "syntax", 12, &msgs[9], NULL, 39, 11, {0},&reftables[226], &reftables[227]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[19], NULL, 11, 3, {0},&reftables[228], &reftables[229]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[7], (const upb_def*)(&enums[1]), 12, 5, {0},&reftables[230], &reftables[231]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[7], NULL, 13, 6, {0},&reftables[232], &reftables[233]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[234], &reftables[235]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[12], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[236], &reftables[237]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[6], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[238], &reftables[239]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[4], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[240], &reftables[241]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[8], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[242], &reftables[243]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[14], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[244], &reftables[245]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[17], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[246], &reftables[247]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[3], (const upb_def*)(&msgs[5]), 6, 0, {0},&reftables[248], &reftables[249]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[8], NULL, 11, 6, {0},&reftables[250], &reftables[251]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[9], NULL, 38, 10, {0},&reftables[252], &reftables[253]),
+};
+
+static const upb_enumdef enums[5] = {
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[188]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[151], 4, 3), 0, &reftables[254], &reftables[255]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[192]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[155], 19, 18), 0, &reftables[256], &reftables[257]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[224]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[174], 3, 3), 0, &reftables[258], &reftables[259]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.JSType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[228]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[177], 3, 3), 0, &reftables[260], &reftables[261]),
+  UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[232]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[180], 4, 3), 0, &reftables[262], &reftables[263]),
+};
+
+static const upb_tabent strentries[236] = {
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "reserved_name"), UPB_TABVALUE_PTR_INIT(&fields[82]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[52]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "field"), UPB_TABVALUE_PTR_INIT(&fields[25]), &strentries[12]},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "extension_range"), UPB_TABVALUE_PTR_INIT(&fields[24]), &strentries[14]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "reserved_range"), UPB_TABVALUE_PTR_INIT(&fields[83]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "oneof_decl"), UPB_TABVALUE_PTR_INIT(&fields[65]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[19]), &strentries[13]},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[89]), NULL},
+  {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[88]), NULL},
+  {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[102]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[49]), &strentries[26]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[62]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[34]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "oneof_index"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[40]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[63]), &strentries[53]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[94]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "json_name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[93]), &strentries[50]},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[103]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "packed"), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "lazy"), UPB_TABVALUE_PTR_INIT(&fields[41]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "jstype"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[23]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[104]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[54]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[85]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[86]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "syntax"), UPB_TABVALUE_PTR_INIT(&fields[91]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[86]},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), NULL},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[80]), &strentries[85]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "cc_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[3]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "csharp_namespace"), UPB_TABVALUE_PTR_INIT(&fields[5]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "go_package"), UPB_TABVALUE_PTR_INIT(&fields[27]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "java_package"), UPB_TABVALUE_PTR_INIT(&fields[35]), &strentries[120]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "java_multiple_files"), UPB_TABVALUE_PTR_INIT(&fields[33]), &strentries[117]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\025", "\000", "\000", "\000", "java_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[32]), &strentries[118]},
+  {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "java_generate_equals_and_hash"), UPB_TABVALUE_PTR_INIT(&fields[31]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "javanano_use_deprecated_package"), UPB_TABVALUE_PTR_INIT(&fields[37]), &strentries[123]},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[81]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[67]), NULL},
+  {UPB_TABKEY_STR("\026", "\000", "\000", "\000", "java_string_check_utf8"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[12]), &strentries[119]},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "objc_class_prefix"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "cc_enable_arenas"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL},
+  {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[128]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[9]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "map_entry"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[61]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "client_streaming"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "server_streaming"), UPB_TABVALUE_PTR_INIT(&fields[84]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[29]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[50]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[72]), &strentries[150]},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[57]), &strentries[149]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "span"), UPB_TABVALUE_PTR_INIT(&fields[87]), &strentries[167]},
+  {UPB_TABKEY_STR("\031", "\000", "\000", "\000", "leading_detached_comments"), UPB_TABVALUE_PTR_INIT(&fields[43]), &strentries[165]},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "trailing_comments"), UPB_TABVALUE_PTR_INIT(&fields[92]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "leading_comments"), UPB_TABVALUE_PTR_INIT(&fields[42]), &strentries[164]},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "path"), UPB_TABVALUE_PTR_INIT(&fields[78]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "negative_int_value"), UPB_TABVALUE_PTR_INIT(&fields[59]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "aggregate_value"), UPB_TABVALUE_PTR_INIT(&fields[0]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "positive_int_value"), UPB_TABVALUE_PTR_INIT(&fields[79]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "identifier_value"), UPB_TABVALUE_PTR_INIT(&fields[28]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "string_value"), UPB_TABVALUE_PTR_INIT(&fields[90]), &strentries[182]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "is_extension"), UPB_TABVALUE_PTR_INIT(&fields[30]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "name_part"), UPB_TABVALUE_PTR_INIT(&fields[58]), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REQUIRED"), UPB_TABVALUE_INT_INIT(2), &strentries[190]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REPEATED"), UPB_TABVALUE_INT_INIT(3), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_OPTIONAL"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED64"), UPB_TABVALUE_INT_INIT(6), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_STRING"), UPB_TABVALUE_INT_INIT(9), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_FLOAT"), UPB_TABVALUE_INT_INIT(2), &strentries[221]},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_DOUBLE"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT32"), UPB_TABVALUE_INT_INIT(5), NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED32"), UPB_TABVALUE_INT_INIT(15), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED32"), UPB_TABVALUE_INT_INIT(7), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_MESSAGE"), UPB_TABVALUE_INT_INIT(11), &strentries[222]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT64"), UPB_TABVALUE_INT_INIT(3), &strentries[219]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_ENUM"), UPB_TABVALUE_INT_INIT(14), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT32"), UPB_TABVALUE_INT_INIT(13), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT64"), UPB_TABVALUE_INT_INIT(4), &strentries[218]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED64"), UPB_TABVALUE_INT_INIT(16), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_BYTES"), UPB_TABVALUE_INT_INIT(12), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT64"), UPB_TABVALUE_INT_INIT(18), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_BOOL"), UPB_TABVALUE_INT_INIT(8), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_GROUP"), UPB_TABVALUE_INT_INIT(10), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT32"), UPB_TABVALUE_INT_INIT(17), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "CORD"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "STRING"), UPB_TABVALUE_INT_INIT(0), &strentries[225]},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "STRING_PIECE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NORMAL"), UPB_TABVALUE_INT_INIT(0), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NUMBER"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_STRING"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "CODE_SIZE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[235]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL},
+};
+
+static const upb_tabent intentries[18] = {
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL},
+};
+
+static const upb_tabval arrays[184] = {
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[52]),
+  UPB_TABVALUE_PTR_INIT(&fields[25]),
+  UPB_TABVALUE_PTR_INIT(&fields[60]),
+  UPB_TABVALUE_PTR_INIT(&fields[19]),
+  UPB_TABVALUE_PTR_INIT(&fields[24]),
+  UPB_TABVALUE_PTR_INIT(&fields[22]),
+  UPB_TABVALUE_PTR_INIT(&fields[68]),
+  UPB_TABVALUE_PTR_INIT(&fields[65]),
+  UPB_TABVALUE_PTR_INIT(&fields[83]),
+  UPB_TABVALUE_PTR_INIT(&fields[82]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[89]),
+  UPB_TABVALUE_PTR_INIT(&fields[18]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[88]),
+  UPB_TABVALUE_PTR_INIT(&fields[17]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[49]),
+  UPB_TABVALUE_PTR_INIT(&fields[102]),
+  UPB_TABVALUE_PTR_INIT(&fields[74]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[1]),
+  UPB_TABVALUE_PTR_INIT(&fields[13]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[53]),
+  UPB_TABVALUE_PTR_INIT(&fields[62]),
+  UPB_TABVALUE_PTR_INIT(&fields[73]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[15]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[55]),
+  UPB_TABVALUE_PTR_INIT(&fields[21]),
+  UPB_TABVALUE_PTR_INIT(&fields[63]),
+  UPB_TABVALUE_PTR_INIT(&fields[40]),
+  UPB_TABVALUE_PTR_INIT(&fields[93]),
+  UPB_TABVALUE_PTR_INIT(&fields[94]),
+  UPB_TABVALUE_PTR_INIT(&fields[7]),
+  UPB_TABVALUE_PTR_INIT(&fields[71]),
+  UPB_TABVALUE_PTR_INIT(&fields[66]),
+  UPB_TABVALUE_PTR_INIT(&fields[38]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[6]),
+  UPB_TABVALUE_PTR_INIT(&fields[77]),
+  UPB_TABVALUE_PTR_INIT(&fields[10]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[41]),
+  UPB_TABVALUE_PTR_INIT(&fields[39]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[103]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[54]),
+  UPB_TABVALUE_PTR_INIT(&fields[76]),
+  UPB_TABVALUE_PTR_INIT(&fields[8]),
+  UPB_TABVALUE_PTR_INIT(&fields[47]),
+  UPB_TABVALUE_PTR_INIT(&fields[20]),
+  UPB_TABVALUE_PTR_INIT(&fields[85]),
+  UPB_TABVALUE_PTR_INIT(&fields[23]),
+  UPB_TABVALUE_PTR_INIT(&fields[69]),
+  UPB_TABVALUE_PTR_INIT(&fields[86]),
+  UPB_TABVALUE_PTR_INIT(&fields[80]),
+  UPB_TABVALUE_PTR_INIT(&fields[104]),
+  UPB_TABVALUE_PTR_INIT(&fields[91]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[26]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[35]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[34]),
+  UPB_TABVALUE_PTR_INIT(&fields[67]),
+  UPB_TABVALUE_PTR_INIT(&fields[33]),
+  UPB_TABVALUE_PTR_INIT(&fields[27]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[3]),
+  UPB_TABVALUE_PTR_INIT(&fields[32]),
+  UPB_TABVALUE_PTR_INIT(&fields[81]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[31]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[12]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[36]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[2]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[64]),
+  UPB_TABVALUE_PTR_INIT(&fields[5]),
+  UPB_TABVALUE_PTR_INIT(&fields[37]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[46]),
+  UPB_TABVALUE_PTR_INIT(&fields[61]),
+  UPB_TABVALUE_PTR_INIT(&fields[9]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[45]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[56]),
+  UPB_TABVALUE_PTR_INIT(&fields[29]),
+  UPB_TABVALUE_PTR_INIT(&fields[75]),
+  UPB_TABVALUE_PTR_INIT(&fields[70]),
+  UPB_TABVALUE_PTR_INIT(&fields[4]),
+  UPB_TABVALUE_PTR_INIT(&fields[84]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[50]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[57]),
+  UPB_TABVALUE_PTR_INIT(&fields[48]),
+  UPB_TABVALUE_PTR_INIT(&fields[72]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[44]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[78]),
+  UPB_TABVALUE_PTR_INIT(&fields[87]),
+  UPB_TABVALUE_PTR_INIT(&fields[42]),
+  UPB_TABVALUE_PTR_INIT(&fields[92]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[43]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[51]),
+  UPB_TABVALUE_PTR_INIT(&fields[28]),
+  UPB_TABVALUE_PTR_INIT(&fields[79]),
+  UPB_TABVALUE_PTR_INIT(&fields[59]),
+  UPB_TABVALUE_PTR_INIT(&fields[16]),
+  UPB_TABVALUE_PTR_INIT(&fields[90]),
+  UPB_TABVALUE_PTR_INIT(&fields[0]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[58]),
+  UPB_TABVALUE_PTR_INIT(&fields[30]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("LABEL_OPTIONAL"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REQUIRED"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REPEATED"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("TYPE_DOUBLE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FLOAT"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BOOL"),
+  UPB_TABVALUE_PTR_INIT("TYPE_STRING"),
+  UPB_TABVALUE_PTR_INIT("TYPE_GROUP"),
+  UPB_TABVALUE_PTR_INIT("TYPE_MESSAGE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BYTES"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_ENUM"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT64"),
+  UPB_TABVALUE_PTR_INIT("STRING"),
+  UPB_TABVALUE_PTR_INIT("CORD"),
+  UPB_TABVALUE_PTR_INIT("STRING_PIECE"),
+  UPB_TABVALUE_PTR_INIT("JS_NORMAL"),
+  UPB_TABVALUE_PTR_INIT("JS_STRING"),
+  UPB_TABVALUE_PTR_INIT("JS_NUMBER"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("SPEED"),
+  UPB_TABVALUE_PTR_INIT("CODE_SIZE"),
+  UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"),
+};
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[264] = {
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+};
+#endif
+
+static const upb_msgdef *refm(const upb_msgdef *m, const void *owner) {
+  upb_msgdef_ref(m, owner);
+  return m;
+}
+
+static const upb_enumdef *refe(const upb_enumdef *e, const void *owner) {
+  upb_enumdef_ref(e, owner);
+  return e;
+}
+
+/* Public API. */
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner) { return refm(&msgs[0], owner); }
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner) { return refm(&msgs[1], owner); }
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner) { return refm(&msgs[2], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner) { return refm(&msgs[3], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner) { return refm(&msgs[4], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner) { return refm(&msgs[5], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner) { return refm(&msgs[6], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner) { return refm(&msgs[7], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner) { return refm(&msgs[8], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner) { return refm(&msgs[9], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner) { return refm(&msgs[10], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner) { return refm(&msgs[11], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner) { return refm(&msgs[12], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner) { return refm(&msgs[13], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner) { return refm(&msgs[14], owner); }
+const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner) { return refm(&msgs[15], owner); }
+const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner) { return refm(&msgs[16], owner); }
+const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner) { return refm(&msgs[17], owner); }
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner) { return refm(&msgs[18], owner); }
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner) { return refm(&msgs[19], owner); }
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner) { return refm(&msgs[20], owner); }
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner) { return refm(&msgs[21], owner); }
+
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner) { return refe(&enums[0], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner) { return refe(&enums[1], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner) { return refe(&enums[2], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner) { return refe(&enums[3], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner) { return refe(&enums[4], owner); }
+/*
+** XXX: The routines in this file that consume a string do not currently
+** support having the string span buffers.  In the future, as upb_sink and
+** its buffering/sharing functionality evolve there should be an easy and
+** idiomatic way of correctly handling this case.  For now, we accept this
+** limitation since we currently only parse descriptors from single strings.
+*/
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Compares a NULL-terminated string with a non-NULL-terminated string. */
+static bool upb_streq(const char *str, const char *buf, size_t n) {
+  return strlen(str) == n && memcmp(str, buf, n) == 0;
+}
+
+/* We keep a stack of all the messages scopes we are currently in, as well as
+ * the top-level file scope.  This is necessary to correctly qualify the
+ * definitions that are contained inside.  "name" tracks the name of the
+ * message or package (a bare name -- not qualified by any enclosing scopes). */
+typedef struct {
+  char *name;
+  /* Index of the first def that is under this scope.  For msgdefs, the
+   * msgdef itself is at start-1. */
+  int start;
+} upb_descreader_frame;
+
+/* The maximum number of nested declarations that are allowed, ie.
+ * message Foo {
+ *   message Bar {
+ *     message Baz {
+ *     }
+ *   }
+ * }
+ *
+ * This is a resource limit that affects how big our runtime stack can grow.
+ * TODO: make this a runtime-settable property of the Reader instance. */
+#define UPB_MAX_MESSAGE_NESTING 64
+
+struct upb_descreader {
+  upb_sink sink;
+  upb_inttable files;
+  upb_filedef *file;  /* The last file in files. */
+  upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
+  int stack_len;
+
+  uint32_t number;
+  char *name;
+  bool saw_number;
+  bool saw_name;
+
+  char *default_string;
+
+  upb_fielddef *f;
+};
+
+static char *upb_strndup(const char *buf, size_t n) {
+  char *ret = upb_gmalloc(n + 1);
+  if (!ret) return NULL;
+  memcpy(ret, buf, n);
+  ret[n] = '\0';
+  return ret;
+}
+
+/* Returns a newly allocated string that joins input strings together, for
+ * example:
+ *   join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
+ *   join("", "Baz") -> "Baz"
+ * Caller owns a ref on the returned string. */
+static char *upb_join(const char *base, const char *name) {
+  if (!base || strlen(base) == 0) {
+    return upb_gstrdup(name);
+  } else {
+    char *ret = upb_gmalloc(strlen(base) + strlen(name) + 2);
+    if (!ret) {
+      return NULL;
+    }
+    ret[0] = '\0';
+    strcat(ret, base);
+    strcat(ret, ".");
+    strcat(ret, name);
+    return ret;
+  }
+}
+
+/* Qualify the defname for all defs starting with offset "start" with "str". */
+static bool upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) {
+  size_t i;
+  for (i = start; i < upb_filedef_defcount(f); i++) {
+    upb_def *def = upb_filedef_mutabledef(f, i);
+    char *name = upb_join(str, upb_def_fullname(def));
+    if (!name) {
+      /* Need better logic here; at this point we've qualified some names but
+       * not others. */
+      return false;
+    }
+    upb_def_setfullname(def, name, NULL);
+    upb_gfree(name);
+  }
+  return true;
+}
+
+
+/* upb_descreader  ************************************************************/
+
+static upb_msgdef *upb_descreader_top(upb_descreader *r) {
+  int index;
+  assert(r->stack_len > 1);
+  index = r->stack[r->stack_len-1].start - 1;
+  assert(index >= 0);
+  return upb_downcast_msgdef_mutable(upb_filedef_mutabledef(r->file, index));
+}
+
+static upb_def *upb_descreader_last(upb_descreader *r) {
+  return upb_filedef_mutabledef(r->file, upb_filedef_defcount(r->file) - 1);
+}
+
+/* Start/end handlers for FileDescriptorProto and DescriptorProto (the two
+ * entities that have names and can contain sub-definitions. */
+void upb_descreader_startcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[r->stack_len++];
+  f->start = upb_filedef_defcount(r->file);
+  f->name = NULL;
+}
+
+bool upb_descreader_endcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[--r->stack_len];
+  if (!upb_descreader_qualify(r->file, f->name, f->start)) {
+    return false;
+  }
+  upb_gfree(f->name);
+  f->name = NULL;
+  return true;
+}
+
+void upb_descreader_setscopename(upb_descreader *r, char *str) {
+  upb_descreader_frame *f = &r->stack[r->stack_len-1];
+  upb_gfree(f->name);
+  f->name = str;
+}
+
+/** Handlers for google.protobuf.FileDescriptorSet. ***************************/
+
+static void *fileset_startfile(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->file = upb_filedef_new(&r->files);
+  upb_inttable_push(&r->files, upb_value_ptr(r->file));
+  return r;
+}
+
+/** Handlers for google.protobuf.FileDescriptorProto. *************************/
+
+static bool file_start(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool file_end(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  return upb_descreader_endcontainer(r);
+}
+
+static size_t file_onname(void *closure, const void *hd, const char *buf,
+                          size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  name = upb_strndup(buf, n);
+  /* XXX: see comment at the top of the file. */
+  ok = upb_filedef_setname(r->file, name, NULL);
+  upb_gfree(name);
+  UPB_ASSERT_VAR(ok, ok);
+  return n;
+}
+
+static size_t file_onpackage(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *package;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  package = upb_strndup(buf, n);
+  /* XXX: see comment at the top of the file. */
+  upb_descreader_setscopename(r, package);
+  ok = upb_filedef_setpackage(r->file, package, NULL);
+  UPB_ASSERT_VAR(ok, ok);
+  return n;
+}
+
+static size_t file_onsyntax(void *closure, const void *hd, const char *buf,
+                            size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  if (upb_streq("proto2", buf, n)) {
+    ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO2, NULL);
+  } else if (upb_streq("proto3", buf, n)) {
+    ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO3, NULL);
+  } else {
+    ok = false;
+  }
+
+  UPB_ASSERT_VAR(ok, ok);
+  return n;
+}
+
+static void *file_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_msgdef_new(&m);
+  bool ok = upb_filedef_addmsg(r->file, m, &m, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT_VAR(ok, ok);
+  return r;
+}
+
+static void *file_startenum(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_enumdef *e = upb_enumdef_new(&e);
+  bool ok = upb_filedef_addenum(r->file, e, &e, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT_VAR(ok, ok);
+  return r;
+}
+
+static void *file_startext(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  bool ok;
+  r->f = upb_fielddef_new(r);
+  ok = upb_filedef_addext(r->file, r->f, r, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT_VAR(ok, ok);
+  return r;
+}
+
+/** Handlers for google.protobuf.EnumValueDescriptorProto. *********************/
+
+static bool enumval_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->saw_number = false;
+  r->saw_name = false;
+  return true;
+}
+
+static size_t enumval_onname(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_gfree(r->name);
+  r->name = upb_strndup(buf, n);
+  r->saw_name = true;
+  return n;
+}
+
+static bool enumval_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->number = val;
+  r->saw_number = true;
+  return true;
+}
+
+static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  if(!r->saw_number || !r->saw_name) {
+    upb_status_seterrmsg(status, "Enum value missing name or number.");
+    return false;
+  }
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  upb_enumdef_addval(e, r->name, r->number, status);
+  upb_gfree(r->name);
+  r->name = NULL;
+  return true;
+}
+
+/** Handlers for google.protobuf.EnumDescriptorProto. *************************/
+
+static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
+    upb_status_seterrmsg(status, "Enum had no name.");
+    return false;
+  }
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrmsg(status, "Enum had no values.");
+    return false;
+  }
+  return true;
+}
+
+static size_t enum_onname(void *closure, const void *hd, const char *buf,
+                          size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *fullname = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_def_setfullname(upb_descreader_last(r), fullname, NULL);
+  upb_gfree(fullname);
+  return n;
+}
+
+/** Handlers for google.protobuf.FieldDescriptorProto *************************/
+
+static bool field_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  assert(r->f);
+  upb_gfree(r->default_string);
+  r->default_string = NULL;
+
+  /* fielddefs default to packed, but descriptors default to non-packed. */
+  upb_fielddef_setpacked(r->f, false);
+  return true;
+}
+
+/* Converts the default value in string "str" into "d".  Passes a ref on str.
+ * Returns true on success. */
+static bool parse_default(char *str, upb_fielddef *f) {
+  bool success = true;
+  char *end;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32: {
+      long val = strtol(str, &end, 0);
+      if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint32(f, val);
+      break;
+    }
+    case UPB_TYPE_INT64: {
+      /* XXX: Need to write our own strtoll, since it's not available in c89. */
+      long long val = strtol(str, &end, 0);
+      if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint64(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(str, &end, 0);
+      if (val > UINT32_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint32(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT64: {
+      /* XXX: Need to write our own strtoull, since it's not available in c89. */
+      unsigned long long val = strtoul(str, &end, 0);
+      if (val > UINT64_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint64(f, val);
+      break;
+    }
+    case UPB_TYPE_DOUBLE: {
+      double val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultdouble(f, val);
+      break;
+    }
+    case UPB_TYPE_FLOAT: {
+      /* XXX: Need to write our own strtof, since it's not available in c89. */
+      float val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultfloat(f, val);
+      break;
+    }
+    case UPB_TYPE_BOOL: {
+      if (strcmp(str, "false") == 0)
+        upb_fielddef_setdefaultbool(f, false);
+      else if (strcmp(str, "true") == 0)
+        upb_fielddef_setdefaultbool(f, true);
+      else
+        success = false;
+      break;
+    }
+    default: abort();
+  }
+  return success;
+}
+
+static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_fielddef *f = r->f;
+  UPB_UNUSED(hd);
+
+  /* TODO: verify that all required fields were present. */
+  assert(upb_fielddef_number(f) != 0);
+  assert(upb_fielddef_name(f) != NULL);
+  assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f));
+
+  if (r->default_string) {
+    if (upb_fielddef_issubmsg(f)) {
+      upb_status_seterrmsg(status, "Submessages cannot have defaults.");
+      return false;
+    }
+    if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+      upb_fielddef_setdefaultcstr(f, r->default_string, NULL);
+    } else {
+      if (r->default_string && !parse_default(r->default_string, f)) {
+        /* We don't worry too much about giving a great error message since the
+         * compiler should have ensured this was correct. */
+        upb_status_seterrmsg(status, "Error converting default value.");
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+static bool field_onlazy(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlazy(r->f, val);
+  return true;
+}
+
+static bool field_onpacked(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setpacked(r->f, val);
+  return true;
+}
+
+static bool field_ontype(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setdescriptortype(r->f, val);
+  return true;
+}
+
+static bool field_onlabel(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlabel(r->f, val);
+  return true;
+}
+
+static bool field_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  bool ok;
+  UPB_UNUSED(hd);
+
+  ok = upb_fielddef_setnumber(r->f, val, NULL);
+  UPB_ASSERT_VAR(ok, ok);
+  return true;
+}
+
+static size_t field_onname(void *closure, const void *hd, const char *buf,
+                           size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setname(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_ontypename(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setsubdefname(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_onextendee(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setcontainingtypename(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_ondefaultval(void *closure, const void *hd, const char *buf,
+                                 size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* Have to convert from string to the correct type, but we might not know the
+   * type yet, so we save it as a string until the end of the field.
+   * XXX: see comment at the top of the file. */
+  upb_gfree(r->default_string);
+  r->default_string = upb_strndup(buf, n);
+  return n;
+}
+
+/** Handlers for google.protobuf.DescriptorProto ******************************/
+
+static bool msg_start(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool msg_end(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) {
+    upb_status_seterrmsg(status, "Encountered message with no name.");
+    return false;
+  }
+  return upb_descreader_endcontainer(r);
+}
+
+static size_t msg_name(void *closure, const void *hd, const char *buf,
+                       size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  /* XXX: see comment at the top of the file. */
+  char *name = upb_strndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL);
+  upb_descreader_setscopename(r, name);  /* Passes ownership of name. */
+  return n;
+}
+
+static void *msg_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_msgdef_new(&m);
+  bool ok = upb_filedef_addmsg(r->file, m, &m, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT_VAR(ok, ok);
+  return r;
+}
+
+static void *msg_startext(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_fielddef *f = upb_fielddef_new(&f);
+  bool ok = upb_filedef_addext(r->file, f, &f, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT_VAR(ok, ok);
+  return r;
+}
+
+static void *msg_startfield(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  r->f = upb_fielddef_new(&r->f);
+  /* We can't add the new field to the message until its name/number are
+   * filled in. */
+  UPB_UNUSED(hd);
+  return r;
+}
+
+static bool msg_endfield(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  upb_msgdef_addfield(m, r->f, &r->f, NULL);
+  r->f = NULL;
+  return true;
+}
+
+static bool msg_onmapentry(void *closure, const void *hd, bool mapentry) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  upb_msgdef_setmapentry(m, mapentry);
+  r->f = NULL;
+  return true;
+}
+
+
+
+/** Code to register handlers *************************************************/
+
+#define F(msg, field) upbdefs_google_protobuf_ ## msg ## _f_ ## field(m)
+
+static void reghandlers(const void *closure, upb_handlers *h) {
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+  UPB_UNUSED(closure);
+
+  if (upbdefs_google_protobuf_FileDescriptorSet_is(m)) {
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorSet, file),
+                                &fileset_startfile, NULL);
+  } else if (upbdefs_google_protobuf_DescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &msg_start, NULL);
+    upb_handlers_setendmsg(h, &msg_end, NULL);
+    upb_handlers_setstring(h, F(DescriptorProto, name), &msg_name, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, extension), &msg_startext,
+                                NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, nested_type),
+                                &msg_startmsg, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, field),
+                                &msg_startfield, NULL);
+    upb_handlers_setendsubmsg(h, F(DescriptorProto, field),
+                              &msg_endfield, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, enum_type),
+                                &file_startenum, NULL);
+  } else if (upbdefs_google_protobuf_FileDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &file_start, NULL);
+    upb_handlers_setendmsg(h, &file_end, NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, name), &file_onname,
+                           NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, package), &file_onpackage,
+                           NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, syntax), &file_onsyntax,
+                           NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, message_type),
+                                &file_startmsg, NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, enum_type),
+                                &file_startenum, NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, extension),
+                                &file_startext, NULL);
+  } else if (upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
+    upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
+    upb_handlers_setstring(h, F(EnumValueDescriptorProto, name), &enumval_onname, NULL);
+    upb_handlers_setint32(h, F(EnumValueDescriptorProto, number), &enumval_onnumber,
+                          NULL);
+  } else if (upbdefs_google_protobuf_EnumDescriptorProto_is(m)) {
+    upb_handlers_setendmsg(h, &enum_endmsg, NULL);
+    upb_handlers_setstring(h, F(EnumDescriptorProto, name), &enum_onname, NULL);
+  } else if (upbdefs_google_protobuf_FieldDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &field_startmsg, NULL);
+    upb_handlers_setendmsg(h, &field_endmsg, NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, type), &field_ontype,
+                          NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, label), &field_onlabel,
+                          NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, number), &field_onnumber,
+                          NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, name), &field_onname,
+                           NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, type_name),
+                           &field_ontypename, NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, extendee),
+                           &field_onextendee, NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, default_value),
+                           &field_ondefaultval, NULL);
+  } else if (upbdefs_google_protobuf_FieldOptions_is(m)) {
+    upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL);
+    upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL);
+  } else if (upbdefs_google_protobuf_MessageOptions_is(m)) {
+    upb_handlers_setbool(h, F(MessageOptions, map_entry), &msg_onmapentry, NULL);
+  }
+
+  assert(upb_ok(upb_handlers_status(h)));
+}
+
+#undef F
+
+void descreader_cleanup(void *_r) {
+  upb_descreader *r = _r;
+  size_t i;
+
+  for (i = 0; i < upb_descreader_filecount(r); i++) {
+    upb_filedef_unref(upb_descreader_file(r, i), &r->files);
+  }
+
+  upb_gfree(r->name);
+  upb_inttable_uninit(&r->files);
+  upb_gfree(r->default_string);
+  while (r->stack_len > 0) {
+    upb_descreader_frame *f = &r->stack[--r->stack_len];
+    upb_gfree(f->name);
+  }
+}
+
+
+/* Public API  ****************************************************************/
+
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) {
+  upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader));
+  if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) {
+    return NULL;
+  }
+
+  upb_inttable_init(&r->files, UPB_CTYPE_PTR);
+  upb_sink_reset(upb_descreader_input(r), h, r);
+  r->stack_len = 0;
+  r->name = NULL;
+  r->default_string = NULL;
+
+  return r;
+}
+
+size_t upb_descreader_filecount(const upb_descreader *r) {
+  return upb_inttable_count(&r->files);
+}
+
+upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i) {
+  upb_value v;
+  if (upb_inttable_lookup(&r->files, i, &v)) {
+    return upb_value_getptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+upb_sink *upb_descreader_input(upb_descreader *r) {
+  return &r->sink;
+}
+
+const upb_handlers *upb_descreader_newhandlers(const void *owner) {
+  const upb_msgdef *m = upbdefs_google_protobuf_FileDescriptorSet_get(&m);
+  const upb_handlers *h = upb_handlers_newfrozen(m, owner, reghandlers, NULL);
+  upb_msgdef_unref(m, &m);
+  return h;
+}
+/*
+** protobuf decoder bytecode compiler
+**
+** Code to compile a upb::Handlers into bytecode for decoding a protobuf
+** according to that specific schema and destination handlers.
+**
+** Compiling to bytecode is always the first step.  If we are using the
+** interpreted decoder we leave it as bytecode and interpret that.  If we are
+** using a JIT decoder we use a code generator to turn the bytecode into native
+** code, LLVM IR, etc.
+**
+** Bytecode definition is in decoder.int.h.
+*/
+
+#include <stdarg.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define MAXLABEL 5
+#define EMPTYLABEL -1
+
+/* mgroup *********************************************************************/
+
+static void freegroup(upb_refcounted *r) {
+  mgroup *g = (mgroup*)r;
+  upb_inttable_uninit(&g->methods);
+#ifdef UPB_USE_JIT_X64
+  upb_pbdecoder_freejit(g);
+#endif
+  upb_gfree(g->bytecode);
+  upb_gfree(g);
+}
+
+static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const mgroup *g = (const mgroup*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    visit(r, upb_pbdecodermethod_upcast(method), closure);
+  }
+}
+
+mgroup *newgroup(const void *owner) {
+  mgroup *g = upb_gmalloc(sizeof(*g));
+  static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
+  upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner);
+  upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
+  g->bytecode = NULL;
+  g->bytecode_end = NULL;
+  return g;
+}
+
+
+/* upb_pbdecodermethod ********************************************************/
+
+static void freemethod(upb_refcounted *r) {
+  upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
+
+  if (method->dest_handlers_) {
+    upb_handlers_unref(method->dest_handlers_, method);
+  }
+
+  upb_inttable_uninit(&method->dispatch);
+  upb_gfree(method);
+}
+
+static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
+                        void *closure) {
+  const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
+  visit(r, m->group, closure);
+}
+
+static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers,
+                                      mgroup *group) {
+  static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
+  upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret));
+  upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret);
+  upb_byteshandler_init(&ret->input_handler_);
+
+  /* The method references the group and vice-versa, in a circular reference. */
+  upb_ref2(ret, group);
+  upb_ref2(group, ret);
+  upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret));
+  upb_pbdecodermethod_unref(ret, &ret);
+
+  ret->group = mgroup_upcast_mutable(group);
+  ret->dest_handlers_ = dest_handlers;
+  ret->is_native_ = false;  /* If we JIT, it will update this later. */
+  upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
+
+  if (ret->dest_handlers_) {
+    upb_handlers_ref(ret->dest_handlers_, ret);
+  }
+  return ret;
+}
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m) {
+  return m->dest_handlers_;
+}
+
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m) {
+  return &m->input_handler_;
+}
+
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
+  return m->is_native_;
+}
+
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner) {
+  const upb_pbdecodermethod *ret;
+  upb_pbcodecache cache;
+
+  upb_pbcodecache_init(&cache);
+  ret = upb_pbcodecache_getdecodermethod(&cache, opts);
+  upb_pbdecodermethod_ref(ret, owner);
+  upb_pbcodecache_uninit(&cache);
+  return ret;
+}
+
+
+/* bytecode compiler **********************************************************/
+
+/* Data used only at compilation time. */
+typedef struct {
+  mgroup *group;
+
+  uint32_t *pc;
+  int fwd_labels[MAXLABEL];
+  int back_labels[MAXLABEL];
+
+  /* For fields marked "lazy", parse them lazily or eagerly? */
+  bool lazy;
+} compiler;
+
+static compiler *newcompiler(mgroup *group, bool lazy) {
+  compiler *ret = upb_gmalloc(sizeof(*ret));
+  int i;
+
+  ret->group = group;
+  ret->lazy = lazy;
+  for (i = 0; i < MAXLABEL; i++) {
+    ret->fwd_labels[i] = EMPTYLABEL;
+    ret->back_labels[i] = EMPTYLABEL;
+  }
+  return ret;
+}
+
+static void freecompiler(compiler *c) {
+  upb_gfree(c);
+}
+
+const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
+
+/* How many words an instruction is. */
+static int instruction_len(uint32_t instr) {
+  switch (getop(instr)) {
+    case OP_SETDISPATCH: return 1 + ptr_words;
+    case OP_TAGN: return 3;
+    case OP_SETBIGGROUPNUM: return 2;
+    default: return 1;
+  }
+}
+
+bool op_has_longofs(int32_t instruction) {
+  switch (getop(instruction)) {
+    case OP_CALL:
+    case OP_BRANCH:
+    case OP_CHECKDELIM:
+      return true;
+    /* The "tag" instructions only have 8 bytes available for the jump target,
+     * but that is ok because these opcodes only require short jumps. */
+    case OP_TAG1:
+    case OP_TAG2:
+    case OP_TAGN:
+      return false;
+    default:
+      assert(false);
+      return false;
+  }
+}
+
+static int32_t getofs(uint32_t instruction) {
+  if (op_has_longofs(instruction)) {
+    return (int32_t)instruction >> 8;
+  } else {
+    return (int8_t)(instruction >> 8);
+  }
+}
+
+static void setofs(uint32_t *instruction, int32_t ofs) {
+  if (op_has_longofs(*instruction)) {
+    *instruction = getop(*instruction) | ofs << 8;
+  } else {
+    *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
+  }
+  assert(getofs(*instruction) == ofs);  /* Would fail in cases of overflow. */
+}
+
+static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
+
+/* Defines a local label at the current PC location.  All previous forward
+ * references are updated to point to this location.  The location is noted
+ * for any future backward references. */
+static void label(compiler *c, unsigned int label) {
+  int val;
+  uint32_t *codep;
+
+  assert(label < MAXLABEL);
+  val = c->fwd_labels[label];
+  codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
+  while (codep) {
+    int ofs = getofs(*codep);
+    setofs(codep, c->pc - codep - instruction_len(*codep));
+    codep = ofs ? codep + ofs : NULL;
+  }
+  c->fwd_labels[label] = EMPTYLABEL;
+  c->back_labels[label] = pcofs(c);
+}
+
+/* Creates a reference to a numbered label; either a forward reference
+ * (positive arg) or backward reference (negative arg).  For forward references
+ * the value returned now is actually a "next" pointer into a linked list of all
+ * instructions that use this label and will be patched later when the label is
+ * defined with label().
+ *
+ * The returned value is the offset that should be written into the instruction.
+ */
+static int32_t labelref(compiler *c, int label) {
+  assert(label < MAXLABEL);
+  if (label == LABEL_DISPATCH) {
+    /* No resolving required. */
+    return 0;
+  } else if (label < 0) {
+    /* Backward local label.  Relative to the next instruction. */
+    uint32_t from = (c->pc + 1) - c->group->bytecode;
+    return c->back_labels[-label] - from;
+  } else {
+    /* Forward local label: prepend to (possibly-empty) linked list. */
+    int *lptr = &c->fwd_labels[label];
+    int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c);
+    *lptr = pcofs(c);
+    return ret;
+  }
+}
+
+static void put32(compiler *c, uint32_t v) {
+  mgroup *g = c->group;
+  if (c->pc == g->bytecode_end) {
+    int ofs = pcofs(c);
+    size_t oldsize = g->bytecode_end - g->bytecode;
+    size_t newsize = UPB_MAX(oldsize * 2, 64);
+    /* TODO(haberman): handle OOM. */
+    g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t),
+                                            newsize * sizeof(uint32_t));
+    g->bytecode_end = g->bytecode + newsize;
+    c->pc = g->bytecode + ofs;
+  }
+  *c->pc++ = v;
+}
+
+static void putop(compiler *c, opcode op, ...) {
+  va_list ap;
+  va_start(ap, op);
+
+  switch (op) {
+    case OP_SETDISPATCH: {
+      uintptr_t ptr = (uintptr_t)va_arg(ap, void*);
+      put32(c, OP_SETDISPATCH);
+      put32(c, ptr);
+      if (sizeof(uintptr_t) > sizeof(uint32_t))
+        put32(c, (uint64_t)ptr >> 32);
+      break;
+    }
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_PUSHLENDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_HALT:
+    case OP_RET:
+    case OP_DISPATCH:
+      put32(c, op);
+      break;
+    case OP_PARSE_DOUBLE:
+    case OP_PARSE_FLOAT:
+    case OP_PARSE_INT64:
+    case OP_PARSE_UINT64:
+    case OP_PARSE_INT32:
+    case OP_PARSE_FIXED64:
+    case OP_PARSE_FIXED32:
+    case OP_PARSE_BOOL:
+    case OP_PARSE_UINT32:
+    case OP_PARSE_SFIXED32:
+    case OP_PARSE_SFIXED64:
+    case OP_PARSE_SINT32:
+    case OP_PARSE_SINT64:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_STRING:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+      put32(c, op | va_arg(ap, upb_selector_t) << 8);
+      break;
+    case OP_SETBIGGROUPNUM:
+      put32(c, op);
+      put32(c, va_arg(ap, int));
+      break;
+    case OP_CALL: {
+      const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
+      put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
+      break;
+    }
+    case OP_CHECKDELIM:
+    case OP_BRANCH: {
+      uint32_t instruction = op;
+      int label = va_arg(ap, int);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAG1:
+    case OP_TAG2: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (tag << 16);
+      assert(tag <= 0xffff);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAGN: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (upb_value_size(tag) << 16);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      put32(c, tag);
+      put32(c, tag >> 32);
+      break;
+    }
+  }
+
+  va_end(ap);
+}
+
+#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE)
+
+const char *upb_pbdecoder_getopname(unsigned int op) {
+#define QUOTE(x) #x
+#define EXPAND_AND_QUOTE(x) QUOTE(x)
+#define OPNAME(x) OP_##x
+#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x));
+#define T(x) OP(PARSE_##x)
+  /* Keep in sync with list in decoder.int.h. */
+  switch ((opcode)op) {
+    T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32)
+    T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64)
+    OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG)
+    OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET)
+    OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM)
+    OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP)
+    OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT)
+  }
+  return "<unknown op>";
+#undef OP
+#undef T
+}
+
+#endif
+
+#ifdef UPB_DUMP_BYTECODE
+
+static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
+
+  uint32_t *begin = p;
+
+  while (p < end) {
+    fprintf(f, "%p  %8tx", p, p - begin);
+    uint32_t instr = *p++;
+    uint8_t op = getop(instr);
+    fprintf(f, " %s", upb_pbdecoder_getopname(op));
+    switch ((opcode)op) {
+      case OP_SETDISPATCH: {
+        const upb_inttable *dispatch;
+        memcpy(&dispatch, p, sizeof(void*));
+        p += ptr_words;
+        const upb_pbdecodermethod *method =
+            (void *)((char *)dispatch -
+                     offsetof(upb_pbdecodermethod, dispatch));
+        fprintf(f, " %s", upb_msgdef_fullname(
+                              upb_handlers_msgdef(method->dest_handlers_)));
+        break;
+      }
+      case OP_DISPATCH:
+      case OP_STARTMSG:
+      case OP_ENDMSG:
+      case OP_PUSHLENDELIM:
+      case OP_POP:
+      case OP_SETDELIM:
+      case OP_HALT:
+      case OP_RET:
+        break;
+      case OP_PARSE_DOUBLE:
+      case OP_PARSE_FLOAT:
+      case OP_PARSE_INT64:
+      case OP_PARSE_UINT64:
+      case OP_PARSE_INT32:
+      case OP_PARSE_FIXED64:
+      case OP_PARSE_FIXED32:
+      case OP_PARSE_BOOL:
+      case OP_PARSE_UINT32:
+      case OP_PARSE_SFIXED32:
+      case OP_PARSE_SFIXED64:
+      case OP_PARSE_SINT32:
+      case OP_PARSE_SINT64:
+      case OP_STARTSEQ:
+      case OP_ENDSEQ:
+      case OP_STARTSUBMSG:
+      case OP_ENDSUBMSG:
+      case OP_STARTSTR:
+      case OP_STRING:
+      case OP_ENDSTR:
+      case OP_PUSHTAGDELIM:
+        fprintf(f, " %d", instr >> 8);
+        break;
+      case OP_SETBIGGROUPNUM:
+        fprintf(f, " %d", *p++);
+        break;
+      case OP_CHECKDELIM:
+      case OP_CALL:
+      case OP_BRANCH:
+        fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        break;
+      case OP_TAG1:
+      case OP_TAG2: {
+        fprintf(f, " tag:0x%x", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+      case OP_TAGN: {
+        uint64_t tag = *p++;
+        tag |= (uint64_t)*p++ << 32;
+        fprintf(f, " tag:0x%llx", (long long)tag);
+        fprintf(f, " n:%d", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+    }
+    fputs("\n", f);
+  }
+}
+
+#endif
+
+static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) {
+  uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type;
+  uint64_t encoded_tag = upb_vencode32(tag);
+  /* No tag should be greater than 5 bytes. */
+  assert(encoded_tag <= 0xffffffffff);
+  return encoded_tag;
+}
+
+static void putchecktag(compiler *c, const upb_fielddef *f,
+                        int wire_type, int dest) {
+  uint64_t tag = get_encoded_tag(f, wire_type);
+  switch (upb_value_size(tag)) {
+    case 1:
+      putop(c, OP_TAG1, dest, tag);
+      break;
+    case 2:
+      putop(c, OP_TAG2, dest, tag);
+      break;
+    default:
+      putop(c, OP_TAGN, dest, tag);
+      break;
+  }
+}
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+  upb_selector_t selector;
+  bool ok = upb_handlers_getselector(f, type, &selector);
+  UPB_ASSERT_VAR(ok, ok);
+  return selector;
+}
+
+/* Takes an existing, primary dispatch table entry and repacks it with a
+ * different alternate wire type.  Called when we are inserting a secondary
+ * dispatch table entry for an alternate wire type. */
+static uint64_t repack(uint64_t dispatch, int new_wt2) {
+  uint64_t ofs;
+  uint8_t wt1;
+  uint8_t old_wt2;
+  upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2);
+  assert(old_wt2 == NO_WIRE_TYPE);  /* wt2 should not be set yet. */
+  return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2);
+}
+
+/* Marks the current bytecode position as the dispatch target for this message,
+ * field, and wire type. */
+static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
+                           const upb_fielddef *f, int wire_type) {
+  /* Offset is relative to msg base. */
+  uint64_t ofs = pcofs(c) - method->code_base.ofs;
+  uint32_t fn = upb_fielddef_number(f);
+  upb_inttable *d = &method->dispatch;
+  upb_value v;
+  if (upb_inttable_remove(d, fn, &v)) {
+    /* TODO: prioritize based on packed setting in .proto file. */
+    uint64_t repacked = repack(upb_value_getuint64(v), wire_type);
+    upb_inttable_insert(d, fn, upb_value_uint64(repacked));
+    upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs));
+  } else {
+    uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE);
+    upb_inttable_insert(d, fn, upb_value_uint64(val));
+  }
+}
+
+static void putpush(compiler *c, const upb_fielddef *f) {
+  if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    putop(c, OP_PUSHLENDELIM);
+  } else {
+    uint32_t fn = upb_fielddef_number(f);
+    if (fn >= 1 << 24) {
+      putop(c, OP_PUSHTAGDELIM, 0);
+      putop(c, OP_SETBIGGROUPNUM, fn);
+    } else {
+      putop(c, OP_PUSHTAGDELIM, fn);
+    }
+  }
+}
+
+static upb_pbdecodermethod *find_submethod(const compiler *c,
+                                           const upb_pbdecodermethod *method,
+                                           const upb_fielddef *f) {
+  const upb_handlers *sub =
+      upb_handlers_getsubhandlers(method->dest_handlers_, f);
+  upb_value v;
+  return upb_inttable_lookupptr(&c->group->methods, sub, &v)
+             ? upb_value_getptr(v)
+             : NULL;
+}
+
+static void putsel(compiler *c, opcode op, upb_selector_t sel,
+                   const upb_handlers *h) {
+  if (upb_handlers_gethandler(h, sel)) {
+    putop(c, op, sel);
+  }
+}
+
+/* Puts an opcode to call a callback, but only if a callback actually exists for
+ * this field and handler type. */
+static void maybeput(compiler *c, opcode op, const upb_handlers *h,
+                     const upb_fielddef *f, upb_handlertype_t type) {
+  putsel(c, op, getsel(f, type), h);
+}
+
+static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) {
+  if (!upb_fielddef_lazy(f))
+    return false;
+
+  return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+
+/* bytecode compiler code generation ******************************************/
+
+/* Symbolic names for our local labels. */
+#define LABEL_LOOPSTART 1  /* Top of a repeated field loop. */
+#define LABEL_LOOPBREAK 2  /* To jump out of a repeated loop */
+#define LABEL_FIELD     3  /* Jump backward to find the most recent field. */
+#define LABEL_ENDMSG    4  /* To reach the OP_ENDMSG instr for this msg. */
+
+/* Generates bytecode to parse a single non-lazy message field. */
+static void generate_msgfield(compiler *c, const upb_fielddef *f,
+                              upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  const upb_pbdecodermethod *sub_m = find_submethod(c, method, f);
+  int wire_type;
+
+  if (!sub_m) {
+    /* Don't emit any code for this field at all; it will be parsed as an
+     * unknown field.
+     *
+     * TODO(haberman): we should change this to parse it as a string field
+     * instead.  It will probably be faster, but more importantly, once we
+     * start vending unknown fields, a field shouldn't be treated as unknown
+     * just because it doesn't have subhandlers registered. */
+    return;
+  }
+
+  label(c, LABEL_FIELD);
+
+  wire_type =
+      (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
+          ? UPB_WIRE_TYPE_DELIMITED
+          : UPB_WIRE_TYPE_START_GROUP;
+
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+  }
+}
+
+/* Generates bytecode to parse a single string or lazy submessage field. */
+static void generate_delimfield(compiler *c, const upb_fielddef *f,
+                                upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+
+  label(c, LABEL_FIELD);
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    /* Need to emit even if no handler to skip past the string. */
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+  }
+}
+
+/* Generates bytecode to parse a single primitive field. */
+static void generate_primitivefield(compiler *c, const upb_fielddef *f,
+                                    upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f);
+  opcode parse_type;
+  upb_selector_t sel;
+  int wire_type;
+
+  label(c, LABEL_FIELD);
+
+  /* From a decoding perspective, ENUM is the same as INT32. */
+  if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM)
+    descriptor_type = UPB_DESCRIPTOR_TYPE_INT32;
+
+  parse_type = (opcode)descriptor_type;
+
+  /* TODO(haberman): generate packed or non-packed first depending on "packed"
+   * setting in the fielddef.  This will favor (in speed) whichever was
+   * specified. */
+
+  assert((int)parse_type >= 0 && parse_type <= OP_MAX);
+  sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Non-packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);  /* Packed and non-packed join. */
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+    putop(c, OP_SETDELIM);  /* Could remove for non-packed by dup ENDSEQ. */
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, parse_type, sel);
+  }
+}
+
+/* Adds bytecode for parsing the given message to the given decoderplan,
+ * while adding all dispatch targets to this message's dispatch table. */
+static void compile_method(compiler *c, upb_pbdecodermethod *method) {
+  const upb_handlers *h;
+  const upb_msgdef *md;
+  uint32_t* start_pc;
+  upb_msg_field_iter i;
+  upb_value val;
+
+  assert(method);
+
+  /* Clear all entries in the dispatch table. */
+  upb_inttable_uninit(&method->dispatch);
+  upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
+
+  h = upb_pbdecodermethod_desthandlers(method);
+  md = upb_handlers_msgdef(h);
+
+ method->code_base.ofs = pcofs(c);
+  putop(c, OP_SETDISPATCH, &method->dispatch);
+  putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
+ label(c, LABEL_FIELD);
+  start_pc = c->pc;
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_fieldtype_t type = upb_fielddef_type(f);
+
+    if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) {
+      generate_msgfield(c, f, method);
+    } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
+               type == UPB_TYPE_MESSAGE) {
+      generate_delimfield(c, f, method);
+    } else {
+      generate_primitivefield(c, f, method);
+    }
+  }
+
+  /* If there were no fields, or if no handlers were defined, we need to
+   * generate a non-empty loop body so that we can at least dispatch for unknown
+   * fields and check for the end of the message. */
+  if (c->pc == start_pc) {
+    /* Check for end-of-message. */
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    /* Unconditionally dispatch. */
+    putop(c, OP_DISPATCH, 0);
+  }
+
+  /* For now we just loop back to the last field of the message (or if none,
+   * the DISPATCH opcode for the message). */
+  putop(c, OP_BRANCH, -LABEL_FIELD);
+
+  /* Insert both a label and a dispatch table entry for this end-of-msg. */
+ label(c, LABEL_ENDMSG);
+  val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
+  upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val);
+
+  putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h);
+  putop(c, OP_RET);
+
+  upb_inttable_compact(&method->dispatch);
+}
+
+/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h".
+ * Returns the method for these handlers.
+ *
+ * Generates a new method for every destination handlers reachable from "h". */
+static void find_methods(compiler *c, const upb_handlers *h) {
+  upb_value v;
+  upb_msg_field_iter i;
+  const upb_msgdef *md;
+
+  if (upb_inttable_lookupptr(&c->group->methods, h, &v))
+    return;
+  newmethod(h, c->group);
+
+  /* Find submethods. */
+  md = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub_h;
+    if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+        (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) {
+      /* We only generate a decoder method for submessages with handlers.
+       * Others will be parsed as unknown fields. */
+      find_methods(c, sub_h);
+    }
+  }
+}
+
+/* (Re-)compile bytecode for all messages in "msgs."
+ * Overwrites any existing bytecode in "c". */
+static void compile_methods(compiler *c) {
+  upb_inttable_iter i;
+
+  /* Start over at the beginning of the bytecode. */
+  c->pc = c->group->bytecode;
+
+  upb_inttable_begin(&i, &c->group->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    compile_method(c, method);
+  }
+}
+
+static void set_bytecode_handlers(mgroup *g) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
+    upb_byteshandler *h = &m->input_handler_;
+
+    m->code_base.ptr = g->bytecode + m->code_base.ofs;
+
+    upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
+    upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
+    upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
+  }
+}
+
+
+/* JIT setup. *****************************************************************/
+
+#ifdef UPB_USE_JIT_X64
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  g->jit_code = NULL;
+  if (allowjit) {
+    /* Compile byte-code into machine code, create handlers. */
+    upb_pbdecoder_jit(g);
+  } else {
+    set_bytecode_handlers(g);
+  }
+}
+
+#else  /* UPB_USE_JIT_X64 */
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  /* No JIT compiled in; use bytecode handlers unconditionally. */
+  UPB_UNUSED(allowjit);
+  set_bytecode_handlers(g);
+}
+
+#endif  /* UPB_USE_JIT_X64 */
+
+
+/* TODO(haberman): allow this to be constructed for an arbitrary set of dest
+ * handlers and other mgroups (but verify we have a transitive closure). */
+const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy,
+                         const void *owner) {
+  mgroup *g;
+  compiler *c;
+
+  UPB_UNUSED(allowjit);
+  assert(upb_handlers_isfrozen(dest));
+
+  g = newgroup(owner);
+  c = newcompiler(g, lazy);
+  find_methods(c, dest);
+
+  /* We compile in two passes:
+   * 1. all messages are assigned relative offsets from the beginning of the
+   *    bytecode (saved in method->code_base).
+   * 2. forwards OP_CALL instructions can be correctly linked since message
+   *    offsets have been previously assigned.
+   *
+   * Could avoid the second pass by linking OP_CALL instructions somehow. */
+  compile_methods(c);
+  compile_methods(c);
+  g->bytecode_end = c->pc;
+  freecompiler(c);
+
+#ifdef UPB_DUMP_BYTECODE
+  {
+    FILE *f = fopen("/tmp/upb-bytecode", "w");
+    assert(f);
+    dumpbc(g->bytecode, g->bytecode_end, stderr);
+    dumpbc(g->bytecode, g->bytecode_end, f);
+    fclose(f);
+
+    f = fopen("/tmp/upb-bytecode.bin", "wb");
+    assert(f);
+    fwrite(g->bytecode, 1, g->bytecode_end - g->bytecode, f);
+    fclose(f);
+  }
+#endif
+
+  sethandlers(g, allowjit);
+  return g;
+}
+
+
+/* upb_pbcodecache ************************************************************/
+
+void upb_pbcodecache_init(upb_pbcodecache *c) {
+  upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
+  c->allow_jit_ = true;
+}
+
+void upb_pbcodecache_uninit(upb_pbcodecache *c) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &c->groups);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
+    mgroup_unref(group, c);
+  }
+  upb_inttable_uninit(&c->groups);
+}
+
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
+  return c->allow_jit_;
+}
+
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
+  if (upb_inttable_count(&c->groups) > 0)
+    return false;
+  c->allow_jit_ = allow;
+  return true;
+}
+
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) {
+  upb_value v;
+  bool ok;
+
+  /* Right now we build a new DecoderMethod every time.
+   * TODO(haberman): properly cache methods by their true key. */
+  const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c);
+  upb_inttable_push(&c->groups, upb_value_constptr(g));
+
+  ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
+  UPB_ASSERT_VAR(ok, ok);
+  return upb_value_getptr(v);
+}
+
+
+/* upb_pbdecodermethodopts ****************************************************/
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h) {
+  opts->handlers = h;
+  opts->lazy = false;
+}
+
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) {
+  opts->lazy = lazy;
+}
+/*
+** upb::Decoder (Bytecode Decoder VM)
+**
+** Bytecode must previously have been generated using the bytecode compiler in
+** compile_decoder.c.  This decoder then walks through the bytecode op-by-op to
+** parse the input.
+**
+** Decoding is fully resumable; we just keep a pointer to the current bytecode
+** instruction and resume from there.  A fair amount of the logic here is to
+** handle the fact that values can span buffer seams and we have to be able to
+** be capable of suspending/resuming from any byte in the stream.  This
+** sometimes requires keeping a few trailing bytes from the last buffer around
+** in the "residual" buffer.
+*/
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+const char *kPbDecoderStackOverflow = "Nesting too deep.";
+const char *kPbDecoderSubmessageTooLong =
+    "Submessage end extends past enclosing submessage.";
+
+/* Error messages shared within this file. */
+static const char *kUnterminatedVarint = "Unterminated varint.";
+
+/* upb_pbdecoder **************************************************************/
+
+static opcode halt = OP_HALT;
+
+/* A dummy character we can point to when the user passes us a NULL buffer.
+ * We need this because in C (NULL + 0) and (NULL - NULL) are undefined
+ * behavior, which would invalidate functions like curbufleft(). */
+static const char dummy_char;
+
+/* Whether an op consumes any of the input buffer. */
+static bool consumes_input(opcode op) {
+  switch (op) {
+    case OP_SETDISPATCH:
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_SETBIGGROUPNUM:
+    case OP_CHECKDELIM:
+    case OP_CALL:
+    case OP_RET:
+    case OP_BRANCH:
+      return false;
+    default:
+      return true;
+  }
+}
+
+static size_t stacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+  return entries * sizeof(upb_pbdecoder_frame);
+}
+
+static size_t callstacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+
+#ifdef UPB_USE_JIT_X64
+  if (d->method_->is_native_) {
+    /* Each native stack frame needs two pointers, plus we need a few frames for
+     * the enter/exit trampolines. */
+    size_t ret = entries * sizeof(void*) * 2;
+    ret += sizeof(void*) * 10;
+    return ret;
+  }
+#endif
+
+  return entries * sizeof(uint32_t*);
+}
+
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p);
+
+/* It's unfortunate that we have to micro-manage the compiler with
+ * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily
+ * specific to one hardware configuration.  But empirically on a Core i7,
+ * performance increases 30-50% with these annotations.  Every instance where
+ * these appear, gcc 4.2.1 made the wrong decision and degraded performance in
+ * benchmarks. */
+
+static void seterr(upb_pbdecoder *d, const char *msg) {
+  upb_status status = UPB_STATUS_INIT;
+  upb_status_seterrmsg(&status, msg);
+  upb_env_reporterror(d->env, &status);
+}
+
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
+  seterr(d, msg);
+}
+
+
+/* Buffering ******************************************************************/
+
+/* We operate on one buffer at a time, which is either the user's buffer passed
+ * to our "decode" callback or some residual bytes from the previous buffer. */
+
+/* How many bytes can be safely read from d->ptr without reading past end-of-buf
+ * or past the current delimited end. */
+static size_t curbufleft(const upb_pbdecoder *d) {
+  assert(d->data_end >= d->ptr);
+  return d->data_end - d->ptr;
+}
+
+/* How many bytes are available before end-of-buffer. */
+static size_t bufleft(const upb_pbdecoder *d) {
+  return d->end - d->ptr;
+}
+
+/* Overall stream offset of d->ptr. */
+uint64_t offset(const upb_pbdecoder *d) {
+  return d->bufstart_ofs + (d->ptr - d->buf);
+}
+
+/* How many bytes are available before the end of this delimited region. */
+size_t delim_remaining(const upb_pbdecoder *d) {
+  return d->top->end_ofs - offset(d);
+}
+
+/* Advances d->ptr. */
+static void advance(upb_pbdecoder *d, size_t len) {
+  assert(curbufleft(d) >= len);
+  d->ptr += len;
+}
+
+static bool in_buf(const char *p, const char *buf, const char *end) {
+  return p >= buf && p <= end;
+}
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p) {
+  return in_buf(p, d->residual, d->residual_end);
+}
+
+/* Calculates the delim_end value, which is affected by both the current buffer
+ * and the parsing stack, so must be called whenever either is updated. */
+static void set_delim_end(upb_pbdecoder *d) {
+  size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs;
+  if (delim_ofs <= (size_t)(d->end - d->buf)) {
+    d->delim_end = d->buf + delim_ofs;
+    d->data_end = d->delim_end;
+  } else {
+    d->data_end = d->end;
+    d->delim_end = NULL;
+  }
+}
+
+static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) {
+  d->ptr = buf;
+  d->buf = buf;
+  d->end = end;
+  set_delim_end(d);
+}
+
+static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) {
+  assert(curbufleft(d) == 0);
+  d->bufstart_ofs += (d->end - d->buf);
+  switchtobuf(d, buf, buf + len);
+}
+
+static void checkpoint(upb_pbdecoder *d) {
+  /* The assertion here is in the interests of efficiency, not correctness.
+   * We are trying to ensure that we don't checkpoint() more often than
+   * necessary. */
+  assert(d->checkpoint != d->ptr);
+  d->checkpoint = d->ptr;
+}
+
+/* Skips "bytes" bytes in the stream, which may be more than available.  If we
+ * skip more bytes than are available, we return a long read count to the caller
+ * indicating how many bytes can be skipped over before passing actual data
+ * again.  Skipped bytes can pass a NULL buffer and the decoder guarantees they
+ * won't actually be read.
+ */
+static int32_t skip(upb_pbdecoder *d, size_t bytes) {
+  assert(!in_residual_buf(d, d->ptr) || d->size_param == 0);
+  assert(d->skip == 0);
+  if (bytes > delim_remaining(d)) {
+    seterr(d, "Skipped value extended beyond enclosing submessage.");
+    return upb_pbdecoder_suspend(d);
+  } else if (bufleft(d) >= bytes) {
+    /* Skipped data is all in current buffer, and more is still available. */
+    advance(d, bytes);
+    d->skip = 0;
+    return DECODE_OK;
+  } else {
+    /* Skipped data extends beyond currently available buffers. */
+    d->pc = d->last;
+    d->skip = bytes - curbufleft(d);
+    d->bufstart_ofs += (d->end - d->buf);
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return d->size_param + d->skip;
+  }
+}
+
+
+/* Resumes the decoder from an initial state or from a previous suspend. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle) {
+  UPB_UNUSED(p);  /* Useless; just for the benefit of the JIT. */
+
+  /* d->skip and d->residual_end could probably elegantly be represented
+   * as a single variable, to more easily represent this invariant. */
+  assert(!(d->skip && d->residual_end > d->residual));
+
+  /* We need to remember the original size_param, so that the value we return
+   * is relative to it, even if we do some skipping first. */
+  d->size_param = size;
+  d->handle = handle;
+
+  /* Have to handle this case specially (ie. not with skip()) because the user
+   * is allowed to pass a NULL buffer here, which won't allow us to safely
+   * calculate a d->end or use our normal functions like curbufleft(). */
+  if (d->skip && d->skip >= size) {
+    d->skip -= size;
+    d->bufstart_ofs += size;
+    buf = &dummy_char;
+    size = 0;
+
+    /* We can't just return now, because we might need to execute some ops
+     * like CHECKDELIM, which could call some callbacks and pop the stack. */
+  }
+
+  /* We need to pretend that this was the actual buffer param, since some of the
+   * calculations assume that d->ptr/d->buf is relative to this. */
+  d->buf_param = buf;
+
+  if (!buf) {
+    /* NULL buf is ok if its entire span is covered by the "skip" above, but
+     * by this point we know that "skip" doesn't cover the buffer. */
+    seterr(d, "Passed NULL buffer over non-skippable region.");
+    return upb_pbdecoder_suspend(d);
+  }
+
+  if (d->residual_end > d->residual) {
+    /* We have residual bytes from the last buffer. */
+    assert(d->ptr == d->residual);
+  } else {
+    switchtobuf(d, buf, buf + size);
+  }
+
+  d->checkpoint = d->ptr;
+
+  /* Handle skips that don't cover the whole buffer (as above). */
+  if (d->skip) {
+    size_t skip_bytes = d->skip;
+    d->skip = 0;
+    CHECK_RETURN(skip(d, skip_bytes));
+    checkpoint(d);
+  }
+
+  /* If we're inside an unknown group, continue to parse unknown values. */
+  if (d->top->groupnum < 0) {
+    CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0));
+    checkpoint(d);
+  }
+
+  return DECODE_OK;
+}
+
+/* Suspends the decoder at the last checkpoint, without saving any residual
+ * bytes.  If there are any unconsumed bytes, returns a short byte count. */
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d) {
+  d->pc = d->last;
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; no user bytes were consumed. */
+    d->ptr = d->residual;
+    return 0;
+  } else {
+    size_t ret = d->size_param - (d->end - d->checkpoint);
+    assert(!in_residual_buf(d, d->checkpoint));
+    assert(d->buf == d->buf_param || d->buf == &dummy_char);
+
+    d->bufstart_ofs += (d->checkpoint - d->buf);
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return ret;
+  }
+}
+
+/* Suspends the decoder at the last checkpoint, and saves any unconsumed
+ * bytes in our residual buffer.  This is necessary if we need more user
+ * bytes to form a complete value, which might not be contiguous in the
+ * user's buffers.  Always consumes all user bytes. */
+static size_t suspend_save(upb_pbdecoder *d) {
+  /* We hit end-of-buffer before we could parse a full value.
+   * Save any unconsumed bytes (if any) to the residual buffer. */
+  d->pc = d->last;
+
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; append user byte(s) to residual buf. */
+    assert((d->residual_end - d->residual) + d->size_param <=
+           sizeof(d->residual));
+    if (!in_residual_buf(d, d->ptr)) {
+      d->bufstart_ofs -= (d->residual_end - d->residual);
+    }
+    memcpy(d->residual_end, d->buf_param, d->size_param);
+    d->residual_end += d->size_param;
+  } else {
+    /* Checkpoint was in user buf; old residual bytes not needed. */
+    size_t save;
+    assert(!in_residual_buf(d, d->checkpoint));
+
+    d->ptr = d->checkpoint;
+    save = curbufleft(d);
+    assert(save <= sizeof(d->residual));
+    memcpy(d->residual, d->ptr, save);
+    d->residual_end = d->residual + save;
+    d->bufstart_ofs = offset(d);
+  }
+
+  switchtobuf(d, d->residual, d->residual_end);
+  return d->size_param;
+}
+
+/* Copies the next "bytes" bytes into "buf" and advances the stream.
+ * Requires that this many bytes are available in the current buffer. */
+UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf,
+                                         size_t bytes) {
+  assert(bytes <= curbufleft(d));
+  memcpy(buf, d->ptr, bytes);
+  advance(d, bytes);
+}
+
+/* Slow path for getting the next "bytes" bytes, regardless of whether they are
+ * available in the current buffer or not.  Returns a status code as described
+ * in decoder.int.h. */
+UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  const size_t avail = curbufleft(d);
+  consumebytes(d, buf, avail);
+  bytes -= avail;
+  assert(bytes > 0);
+  if (in_residual_buf(d, d->ptr)) {
+    advancetobuf(d, d->buf_param, d->size_param);
+  }
+  if (curbufleft(d) >= bytes) {
+    consumebytes(d, (char *)buf + avail, bytes);
+    return DECODE_OK;
+  } else if (d->data_end == d->delim_end) {
+    seterr(d, "Submessage ended in the middle of a value or group");
+    return upb_pbdecoder_suspend(d);
+  } else {
+    return suspend_save(d);
+  }
+}
+
+/* Gets the next "bytes" bytes, regardless of whether they are available in the
+ * current buffer or not.  Returns a status code as described in decoder.int.h.
+ */
+UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    /* Buffer has enough data to satisfy. */
+    consumebytes(d, buf, bytes);
+    return DECODE_OK;
+  } else {
+    return getbytes_slow(d, buf, bytes);
+  }
+}
+
+UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  size_t ret = curbufleft(d);
+  memcpy(buf, d->ptr, ret);
+  if (in_residual_buf(d, d->ptr)) {
+    size_t copy = UPB_MIN(bytes - ret, d->size_param);
+    memcpy((char *)buf + ret, d->buf_param, copy);
+    ret += copy;
+  }
+  return ret;
+}
+
+UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    memcpy(buf, d->ptr, bytes);
+    return bytes;
+  } else {
+    return peekbytes_slow(d, buf, bytes);
+  }
+}
+
+
+/* Decoding of wire types *****************************************************/
+
+/* Slow path for decoding a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d,
+                                                      uint64_t *u64) {
+  uint8_t byte = 0x80;
+  int bitpos;
+  *u64 = 0;
+  for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+    CHECK_RETURN(getbytes(d, &byte, 1));
+    *u64 |= (uint64_t)(byte & 0x7F) << bitpos;
+  }
+  if(bitpos == 70 && (byte & 0x80)) {
+    seterr(d, kUnterminatedVarint);
+    return upb_pbdecoder_suspend(d);
+  }
+  return DECODE_OK;
+}
+
+/* Decodes a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) {
+  if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) {
+    *u64 = *d->ptr;
+    advance(d, 1);
+    return DECODE_OK;
+  } else if (curbufleft(d) >= 10) {
+    /* Fast case. */
+    upb_decoderet r = upb_vdecode_fast(d->ptr);
+    if (r.p == NULL) {
+      seterr(d, kUnterminatedVarint);
+      return upb_pbdecoder_suspend(d);
+    }
+    advance(d, r.p - d->ptr);
+    *u64 = r.val;
+    return DECODE_OK;
+  } else {
+    /* Slow case -- varint spans buffer seam. */
+    return upb_pbdecoder_decode_varint_slow(d, u64);
+  }
+}
+
+/* Decodes a 32-bit varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) {
+  uint64_t u64;
+  int32_t ret = decode_varint(d, &u64);
+  if (ret >= 0) return ret;
+  if (u64 > UINT32_MAX) {
+    seterr(d, "Unterminated 32-bit varint");
+    /* TODO(haberman) guarantee that this function return is >= 0 somehow,
+     * so we know this path will always be treated as error by our caller.
+     * Right now the size_t -> int32_t can overflow and produce negative values.
+     */
+    *u32 = 0;
+    return upb_pbdecoder_suspend(d);
+  }
+  *u32 = u64;
+  return DECODE_OK;
+}
+
+/* Decodes a fixed32 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) {
+  return getbytes(d, u32, 4);
+}
+
+/* Decodes a fixed64 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) {
+  return getbytes(d, u64, 8);
+}
+
+/* Non-static versions of the above functions.
+ * These are called by the JIT for fallback paths. */
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) {
+  return decode_fixed32(d, u32);
+}
+
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) {
+  return decode_fixed64(d, u64);
+}
+
+static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; }
+static float  as_float(uint32_t n)  { float  f; memcpy(&f, &n, 4); return f; }
+
+/* Pushes a frame onto the decoder stack. */
+static bool decoder_push(upb_pbdecoder *d, uint64_t end) {
+  upb_pbdecoder_frame *fr = d->top;
+
+  if (end > fr->end_ofs) {
+    seterr(d, kPbDecoderSubmessageTooLong);
+    return false;
+  } else if (fr == d->limit) {
+    seterr(d, kPbDecoderStackOverflow);
+    return false;
+  }
+
+  fr++;
+  fr->end_ofs = end;
+  fr->dispatch = NULL;
+  fr->groupnum = 0;
+  d->top = fr;
+  return true;
+}
+
+static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) {
+  /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence
+   * field number) prior to hitting any enclosing submessage end, pushing our
+   * existing delim end prevents us from continuing to parse values from a
+   * corrupt proto that doesn't give us an END tag in time. */
+  if (!decoder_push(d, d->top->end_ofs))
+    return false;
+  d->top->groupnum = arg;
+  return true;
+}
+
+/* Pops a frame from the decoder stack. */
+static void decoder_pop(upb_pbdecoder *d) { d->top--; }
+
+UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d,
+                                                 uint64_t expected) {
+  uint64_t data = 0;
+  size_t bytes = upb_value_size(expected);
+  size_t read = peekbytes(d, &data, bytes);
+  if (read == bytes && data == expected) {
+    /* Advance past matched bytes. */
+    int32_t ok = getbytes(d, &data, read);
+    UPB_ASSERT_VAR(ok, ok < 0);
+    return DECODE_OK;
+  } else if (read < bytes && memcmp(&data, &expected, read) == 0) {
+    return suspend_save(d);
+  } else {
+    return DECODE_MISMATCH;
+  }
+}
+
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type) {
+  if (fieldnum >= 0)
+    goto have_tag;
+
+  while (true) {
+    uint32_t tag;
+    CHECK_RETURN(decode_v32(d, &tag));
+    wire_type = tag & 0x7;
+    fieldnum = tag >> 3;
+
+have_tag:
+    if (fieldnum == 0) {
+      seterr(d, "Saw invalid field number (0)");
+      return upb_pbdecoder_suspend(d);
+    }
+
+    /* TODO: deliver to unknown field callback. */
+    switch (wire_type) {
+      case UPB_WIRE_TYPE_32BIT:
+        CHECK_RETURN(skip(d, 4));
+        break;
+      case UPB_WIRE_TYPE_64BIT:
+        CHECK_RETURN(skip(d, 8));
+        break;
+      case UPB_WIRE_TYPE_VARINT: {
+        uint64_t u64;
+        CHECK_RETURN(decode_varint(d, &u64));
+        break;
+      }
+      case UPB_WIRE_TYPE_DELIMITED: {
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_RETURN(skip(d, len));
+        break;
+      }
+      case UPB_WIRE_TYPE_START_GROUP:
+        CHECK_SUSPEND(pushtagdelim(d, -fieldnum));
+        break;
+      case UPB_WIRE_TYPE_END_GROUP:
+        if (fieldnum == -d->top->groupnum) {
+          decoder_pop(d);
+        } else if (fieldnum == d->top->groupnum) {
+          return DECODE_ENDGROUP;
+        } else {
+          seterr(d, "Unmatched ENDGROUP tag.");
+          return upb_pbdecoder_suspend(d);
+        }
+        break;
+      default:
+        seterr(d, "Invalid wire type");
+        return upb_pbdecoder_suspend(d);
+    }
+
+    if (d->top->groupnum >= 0) {
+      return DECODE_OK;
+    }
+
+    /* Unknown group -- continue looping over unknown fields. */
+    checkpoint(d);
+  }
+}
+
+static void goto_endmsg(upb_pbdecoder *d) {
+  upb_value v;
+  bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v);
+  UPB_ASSERT_VAR(found, found);
+  d->pc = d->top->base + upb_value_getuint64(v);
+}
+
+/* Parses a tag and jumps to the corresponding bytecode instruction for this
+ * field.
+ *
+ * If the tag is unknown (or the wire type doesn't match), parses the field as
+ * unknown.  If the tag is a valid ENDGROUP tag, jumps to the bytecode
+ * instruction for the end of message. */
+static int32_t dispatch(upb_pbdecoder *d) {
+  upb_inttable *dispatch = d->top->dispatch;
+  uint32_t tag;
+  uint8_t wire_type;
+  uint32_t fieldnum;
+  upb_value val;
+  int32_t retval;
+
+  /* Decode tag. */
+  CHECK_RETURN(decode_v32(d, &tag));
+  wire_type = tag & 0x7;
+  fieldnum = tag >> 3;
+
+  /* Lookup tag.  Because of packed/non-packed compatibility, we have to
+   * check the wire type against two possibilities. */
+  if (fieldnum != DISPATCH_ENDMSG &&
+      upb_inttable_lookup32(dispatch, fieldnum, &val)) {
+    uint64_t v = upb_value_getuint64(val);
+    if (wire_type == (v & 0xff)) {
+      d->pc = d->top->base + (v >> 16);
+      return DECODE_OK;
+    } else if (wire_type == ((v >> 8) & 0xff)) {
+      bool found =
+          upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val);
+      UPB_ASSERT_VAR(found, found);
+      d->pc = d->top->base + upb_value_getuint64(val);
+      return DECODE_OK;
+    }
+  }
+
+  /* We have some unknown fields (or ENDGROUP) to parse.  The DISPATCH or TAG
+   * bytecode that triggered this is preceded by a CHECKDELIM bytecode which
+   * we need to back up to, so that when we're done skipping unknown data we
+   * can re-check the delimited end. */
+  d->last--;  /* Necessary if we get suspended */
+  d->pc = d->last;
+  assert(getop(*d->last) == OP_CHECKDELIM);
+
+  /* Unknown field or ENDGROUP. */
+  retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type);
+
+  CHECK_RETURN(retval);
+
+  if (retval == DECODE_ENDGROUP) {
+    goto_endmsg(d);
+    return DECODE_OK;
+  }
+
+  return DECODE_OK;
+}
+
+/* Callers know that the stack is more than one deep because the opcodes that
+ * call this only occur after PUSH operations. */
+upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
+  assert(d->top != d->stack);
+  return d->top - 1;
+}
+
+
+/* The main decoding loop *****************************************************/
+
+/* The main decoder VM function.  Uses traditional bytecode dispatch loop with a
+ * switch() statement. */
+size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group,
+                      const upb_bufhandle* handle) {
+
+#define VMCASE(op, code) \
+  case op: { code; if (consumes_input(op)) checkpoint(d); break; }
+#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \
+  VMCASE(OP_PARSE_ ## type, { \
+    ctype val; \
+    CHECK_RETURN(decode_ ## wt(d, &val)); \
+    upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
+  })
+
+  while(1) {
+    int32_t instruction;
+    opcode op;
+    uint32_t arg;
+    int32_t longofs;
+
+    d->last = d->pc;
+    instruction = *d->pc++;
+    op = getop(instruction);
+    arg = instruction >> 8;
+    longofs = arg;
+    assert(d->ptr != d->residual_end);
+    UPB_UNUSED(group);
+#ifdef UPB_DUMP_BYTECODE
+    fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d "
+                    "%x %s (%d)\n",
+            (int)offset(d),
+            (int)(d->ptr - d->buf),
+            (int)(d->data_end - d->ptr),
+            (int)(d->end - d->ptr),
+            (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)),
+            (int)(d->pc - 1 - group->bytecode),
+            upb_pbdecoder_getopname(op),
+            arg);
+#endif
+    switch (op) {
+      /* Technically, we are losing data if we see a 32-bit varint that is not
+       * properly sign-extended.  We could detect this and error about the data
+       * loss, but proto2 does not do this, so we pass. */
+      PRIMITIVE_OP(INT32,    varint,  int32,  int32_t,      uint64_t)
+      PRIMITIVE_OP(INT64,    varint,  int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(UINT32,   varint,  uint32, uint32_t,     uint64_t)
+      PRIMITIVE_OP(UINT64,   varint,  uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(FIXED32,  fixed32, uint32, uint32_t,     uint32_t)
+      PRIMITIVE_OP(FIXED64,  fixed64, uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(SFIXED32, fixed32, int32,  int32_t,      uint32_t)
+      PRIMITIVE_OP(SFIXED64, fixed64, int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(BOOL,     varint,  bool,   bool,         uint64_t)
+      PRIMITIVE_OP(DOUBLE,   fixed64, double, as_double,    uint64_t)
+      PRIMITIVE_OP(FLOAT,    fixed32, float,  as_float,     uint32_t)
+      PRIMITIVE_OP(SINT32,   varint,  int32,  upb_zzdec_32, uint64_t)
+      PRIMITIVE_OP(SINT64,   varint,  int64,  upb_zzdec_64, uint64_t)
+
+      VMCASE(OP_SETDISPATCH,
+        d->top->base = d->pc - 1;
+        memcpy(&d->top->dispatch, d->pc, sizeof(void*));
+        d->pc += sizeof(void*) / sizeof(uint32_t);
+      )
+      VMCASE(OP_STARTMSG,
+        CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
+      )
+      VMCASE(OP_ENDMSG,
+        CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
+      )
+      VMCASE(OP_STARTSEQ,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSEQ,
+        CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSUBMSG,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSUBMSG,
+        CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSTR,
+        uint32_t len = delim_remaining(d);
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
+        if (len == 0) {
+          d->pc++;  /* Skip OP_STRING. */
+        }
+      )
+      VMCASE(OP_STRING,
+        uint32_t len = curbufleft(d);
+        size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle);
+        if (n > len) {
+          if (n > delim_remaining(d)) {
+            seterr(d, "Tried to skip past end of string.");
+            return upb_pbdecoder_suspend(d);
+          } else {
+            int32_t ret = skip(d, n);
+            /* This shouldn't return DECODE_OK, because n > len. */
+            assert(ret >= 0);
+            return ret;
+          }
+        }
+        advance(d, n);
+        if (n < len || d->delim_end == NULL) {
+          /* We aren't finished with this string yet. */
+          d->pc--;  /* Repeat OP_STRING. */
+          if (n > 0) checkpoint(d);
+          return upb_pbdecoder_suspend(d);
+        }
+      )
+      VMCASE(OP_ENDSTR,
+        CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
+      )
+      VMCASE(OP_PUSHTAGDELIM,
+        CHECK_SUSPEND(pushtagdelim(d, arg));
+      )
+      VMCASE(OP_SETBIGGROUPNUM,
+        d->top->groupnum = *d->pc++;
+      )
+      VMCASE(OP_POP,
+        assert(d->top > d->stack);
+        decoder_pop(d);
+      )
+      VMCASE(OP_PUSHLENDELIM,
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_SUSPEND(decoder_push(d, offset(d) + len));
+        set_delim_end(d);
+      )
+      VMCASE(OP_SETDELIM,
+        set_delim_end(d);
+      )
+      VMCASE(OP_CHECKDELIM,
+        /* We are guaranteed of this assert because we never allow ourselves to
+         * consume bytes beyond data_end, which covers delim_end when non-NULL.
+         */
+        assert(!(d->delim_end && d->ptr > d->delim_end));
+        if (d->ptr == d->delim_end)
+          d->pc += longofs;
+      )
+      VMCASE(OP_CALL,
+        d->callstack[d->call_len++] = d->pc;
+        d->pc += longofs;
+      )
+      VMCASE(OP_RET,
+        assert(d->call_len > 0);
+        d->pc = d->callstack[--d->call_len];
+      )
+      VMCASE(OP_BRANCH,
+        d->pc += longofs;
+      )
+      VMCASE(OP_TAG1,
+        uint8_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xff;
+        if (*d->ptr == expected) {
+          advance(d, 1);
+        } else {
+          int8_t shortofs;
+         badtag:
+          shortofs = arg;
+          if (shortofs == LABEL_DISPATCH) {
+            CHECK_RETURN(dispatch(d));
+          } else {
+            d->pc += shortofs;
+            break; /* Avoid checkpoint(). */
+          }
+        }
+      )
+      VMCASE(OP_TAG2,
+        uint16_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xffff;
+        if (curbufleft(d) >= 2) {
+          uint16_t actual;
+          memcpy(&actual, d->ptr, 2);
+          if (expected == actual) {
+            advance(d, 2);
+          } else {
+            goto badtag;
+          }
+        } else {
+          int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+          if (result == DECODE_MISMATCH) goto badtag;
+          if (result >= 0) return result;
+        }
+      )
+      VMCASE(OP_TAGN, {
+        uint64_t expected;
+        int32_t result;
+        memcpy(&expected, d->pc, 8);
+        d->pc += 2;
+        result = upb_pbdecoder_checktag_slow(d, expected);
+        if (result == DECODE_MISMATCH) goto badtag;
+        if (result >= 0) return result;
+      })
+      VMCASE(OP_DISPATCH, {
+        CHECK_RETURN(dispatch(d));
+      })
+      VMCASE(OP_HALT, {
+        return d->size_param;
+      })
+    }
+  }
+}
+
+
+/* BytesHandler handlers ******************************************************/
+
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 1;
+  d->callstack[0] = &halt;
+  d->pc = pc;
+  d->skip = 0;
+  return d;
+}
+
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 0;
+  d->skip = 0;
+  return d;
+}
+
+bool upb_pbdecoder_end(void *closure, const void *handler_data) {
+  upb_pbdecoder *d = closure;
+  const upb_pbdecodermethod *method = handler_data;
+  uint64_t end;
+  char dummy;
+
+  if (d->residual_end > d->residual) {
+    seterr(d, "Unexpected EOF: decoder still has buffered unparsed data");
+    return false;
+  }
+
+  if (d->skip) {
+    seterr(d, "Unexpected EOF inside skipped data");
+    return false;
+  }
+
+  if (d->top->end_ofs != UINT64_MAX) {
+    seterr(d, "Unexpected EOF inside delimited string");
+    return false;
+  }
+
+  /* The user's end() call indicates that the message ends here. */
+  end = offset(d);
+  d->top->end_ofs = end;
+
+#ifdef UPB_USE_JIT_X64
+  if (method->is_native_) {
+    const mgroup *group = (const mgroup*)method->group;
+    if (d->top != d->stack)
+      d->stack->end_ofs = 0;
+    group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL);
+  } else
+#endif
+  {
+    const uint32_t *p = d->pc;
+    d->stack->end_ofs = end;
+    /* Check the previous bytecode, but guard against beginning. */
+    if (p != method->code_base.ptr) p--;
+    if (getop(*p) == OP_CHECKDELIM) {
+      /* Rewind from OP_TAG* to OP_CHECKDELIM. */
+      assert(getop(*d->pc) == OP_TAG1 ||
+             getop(*d->pc) == OP_TAG2 ||
+             getop(*d->pc) == OP_TAGN ||
+             getop(*d->pc) == OP_DISPATCH);
+      d->pc = p;
+    }
+    upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
+  }
+
+  if (d->call_len != 0) {
+    seterr(d, "Unexpected EOF inside submessage or group");
+    return false;
+  }
+
+  return true;
+}
+
+size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf,
+                            size_t size, const upb_bufhandle *handle) {
+  int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle);
+
+  if (result == DECODE_ENDGROUP) goto_endmsg(decoder);
+  CHECK_RETURN(result);
+
+  return run_decoder_vm(decoder, group, handle);
+}
+
+
+/* Public API *****************************************************************/
+
+void upb_pbdecoder_reset(upb_pbdecoder *d) {
+  d->top = d->stack;
+  d->top->groupnum = 0;
+  d->ptr = d->residual;
+  d->buf = d->residual;
+  d->end = d->residual;
+  d->residual_end = d->residual;
+}
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m,
+                                    upb_sink *sink) {
+  const size_t default_max_nesting = 64;
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_pbdecoder *d = upb_env_malloc(e, sizeof(upb_pbdecoder));
+  if (!d) return NULL;
+
+  d->method_ = m;
+  d->callstack = upb_env_malloc(e, callstacksize(d, default_max_nesting));
+  d->stack = upb_env_malloc(e, stacksize(d, default_max_nesting));
+  if (!d->stack || !d->callstack) {
+    return NULL;
+  }
+
+  d->env = e;
+  d->limit = d->stack + default_max_nesting - 1;
+  d->stack_size = default_max_nesting;
+  d->status = NULL;
+
+  upb_pbdecoder_reset(d);
+  upb_bytessink_reset(&d->input_, &m->input_handler_, d);
+
+  assert(sink);
+  if (d->method_->dest_handlers_) {
+    if (sink->handlers != d->method_->dest_handlers_)
+      return NULL;
+  }
+  upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
+
+  /* If this fails, increase the value in decoder.h. */
+  assert(upb_env_bytesallocated(e) - size_before <= UPB_PB_DECODER_SIZE);
+  return d;
+}
+
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) {
+  return offset(d);
+}
+
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
+  return d->method_;
+}
+
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
+  return &d->input_;
+}
+
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) {
+  return d->stack_size;
+}
+
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) {
+  assert(d->top >= d->stack);
+
+  if (max < (size_t)(d->top - d->stack)) {
+    /* Can't set a limit smaller than what we are currently at. */
+    return false;
+  }
+
+  if (max > d->stack_size) {
+    /* Need to reallocate stack and callstack to accommodate. */
+    size_t old_size = stacksize(d, d->stack_size);
+    size_t new_size = stacksize(d, max);
+    void *p = upb_env_realloc(d->env, d->stack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->stack = p;
+
+    old_size = callstacksize(d, d->stack_size);
+    new_size = callstacksize(d, max);
+    p = upb_env_realloc(d->env, d->callstack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->callstack = p;
+
+    d->stack_size = max;
+  }
+
+  d->limit = d->stack + max - 1;
+  return true;
+}
+/*
+** upb::Encoder
+**
+** Since we are implementing pure handlers (ie. without any out-of-band access
+** to pre-computed lengths), we have to buffer all submessages before we can
+** emit even their first byte.
+**
+** Not knowing the size of submessages also means we can't write a perfect
+** zero-copy implementation, even with buffering.  Lengths are stored as
+** varints, which means that we don't know how many bytes to reserve for the
+** length until we know what the length is.
+**
+** This leaves us with three main choices:
+**
+** 1. buffer all submessage data in a temporary buffer, then copy it exactly
+**    once into the output buffer.
+**
+** 2. attempt to buffer data directly into the output buffer, estimating how
+**    many bytes each length will take.  When our guesses are wrong, use
+**    memmove() to grow or shrink the allotted space.
+**
+** 3. buffer directly into the output buffer, allocating a max length
+**    ahead-of-time for each submessage length.  If we overallocated, we waste
+**    space, but no memcpy() or memmove() is required.  This approach requires
+**    defining a maximum size for submessages and rejecting submessages that
+**    exceed that size.
+**
+** (2) and (3) have the potential to have better performance, but they are more
+** complicated and subtle to implement:
+**
+**   (3) requires making an arbitrary choice of the maximum message size; it
+**       wastes space when submessages are shorter than this and fails
+**       completely when they are longer.  This makes it more finicky and
+**       requires configuration based on the input.  It also makes it impossible
+**       to perfectly match the output of reference encoders that always use the
+**       optimal amount of space for each length.
+**
+**   (2) requires guessing the the size upfront, and if multiple lengths are
+**       guessed wrong the minimum required number of memmove() operations may
+**       be complicated to compute correctly.  Implemented properly, it may have
+**       a useful amortized or average cost, but more investigation is required
+**       to determine this and what the optimal algorithm is to achieve it.
+**
+**   (1) makes you always pay for exactly one copy, but its implementation is
+**       the simplest and its performance is predictable.
+**
+** So for now, we implement (1) only.  If we wish to optimize later, we should
+** be able to do it without affecting users.
+**
+** The strategy is to buffer the segments of data that do *not* depend on
+** unknown lengths in one buffer, and keep a separate buffer of segment pointers
+** and lengths.  When the top-level submessage ends, we can go beginning to end,
+** alternating the writing of lengths with memcpy() of the rest of the data.
+** At the top level though, no buffering is required.
+*/
+
+
+
+/* The output buffer is divided into segments; a segment is a string of data
+ * that is "ready to go" -- it does not need any varint lengths inserted into
+ * the middle.  The seams between segments are where varints will be inserted
+ * once they are known.
+ *
+ * We also use the concept of a "run", which is a range of encoded bytes that
+ * occur at a single submessage level.  Every segment contains one or more runs.
+ *
+ * A segment can span messages.  Consider:
+ *
+ *                  .--Submessage lengths---------.
+ *                  |       |                     |
+ *                  |       V                     V
+ *                  V      | |---------------    | |-----------------
+ * Submessages:    | |-----------------------------------------------
+ * Top-level msg: ------------------------------------------------------------
+ *
+ * Segments:          -----   -------------------   -----------------
+ * Runs:              *----   *--------------*---   *----------------
+ * (* marks the start)
+ *
+ * Note that the top-level menssage is not in any segment because it does not
+ * have any length preceding it.
+ *
+ * A segment is only interrupted when another length needs to be inserted.  So
+ * observe how the second segment spans both the inner submessage and part of
+ * the next enclosing message. */
+typedef struct {
+  uint32_t msglen;  /* The length to varint-encode before this segment. */
+  uint32_t seglen;  /* Length of the segment. */
+} upb_pb_encoder_segment;
+
+struct upb_pb_encoder {
+  upb_env *env;
+
+  /* Our input and output. */
+  upb_sink input_;
+  upb_bytessink *output_;
+
+  /* The "subclosure" -- used as the inner closure as part of the bytessink
+   * protocol. */
+  void *subc;
+
+  /* The output buffer and limit, and our current write position.  "buf"
+   * initially points to "initbuf", but is dynamically allocated if we need to
+   * grow beyond the initial size. */
+  char *buf, *ptr, *limit;
+
+  /* The beginning of the current run, or undefined if we are at the top
+   * level. */
+  char *runbegin;
+
+  /* The list of segments we are accumulating. */
+  upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
+
+  /* The stack of enclosing submessages.  Each entry in the stack points to the
+   * segment where this submessage's length is being accumulated. */
+  int *stack, *top, *stacklimit;
+
+  /* Depth of startmsg/endmsg calls. */
+  int depth;
+};
+
+/* low-level buffering ********************************************************/
+
+/* Low-level functions for interacting with the output buffer. */
+
+/* TODO(haberman): handle pushback */
+static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
+  size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
+  UPB_ASSERT_VAR(n, n == len);
+}
+
+static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
+  return &e->segbuf[*e->top];
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr.  Returns false if the bytes could not be allocated. */
+static bool reserve(upb_pb_encoder *e, size_t bytes) {
+  if ((size_t)(e->limit - e->ptr) < bytes) {
+    /* Grow buffer. */
+    char *new_buf;
+    size_t needed = bytes + (e->ptr - e->buf);
+    size_t old_size = e->limit - e->buf;
+
+    size_t new_size = old_size;
+
+    while (new_size < needed) {
+      new_size *= 2;
+    }
+
+    new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
+
+    if (new_buf == NULL) {
+      return false;
+    }
+
+    e->ptr = new_buf + (e->ptr - e->buf);
+    e->runbegin = new_buf + (e->runbegin - e->buf);
+    e->limit = new_buf + new_size;
+    e->buf = new_buf;
+  }
+
+  return true;
+}
+
+/* Call when "bytes" bytes have been writte at e->ptr.  The caller *must* have
+ * previously called reserve() with at least this many bytes. */
+static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
+  assert((size_t)(e->limit - e->ptr) >= bytes);
+  e->ptr += bytes;
+}
+
+/* Call when all of the bytes for a handler have been written.  Flushes the
+ * bytes if possible and necessary, returning false if this failed. */
+static bool commit(upb_pb_encoder *e) {
+  if (!e->top) {
+    /* We aren't inside a delimited region.  Flush our accumulated bytes to
+     * the output.
+     *
+     * TODO(haberman): in the future we may want to delay flushing for
+     * efficiency reasons. */
+    putbuf(e, e->buf, e->ptr - e->buf);
+    e->ptr = e->buf;
+  }
+
+  return true;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) {
+  if (!reserve(e, len)) {
+    return false;
+  }
+
+  memcpy(e->ptr, data, len);
+  encoder_advance(e, len);
+  return true;
+}
+
+/* Finish the current run by adding the run totals to the segment and message
+ * length. */
+static void accumulate(upb_pb_encoder *e) {
+  size_t run_len;
+  assert(e->ptr >= e->runbegin);
+  run_len = e->ptr - e->runbegin;
+  e->segptr->seglen += run_len;
+  top(e)->msglen += run_len;
+  e->runbegin = e->ptr;
+}
+
+/* Call to indicate the start of delimited region for which the full length is
+ * not yet known.  All data will be buffered until the length is known.
+ * Delimited regions may be nested; their lengths will all be tracked properly. */
+static bool start_delim(upb_pb_encoder *e) {
+  if (e->top) {
+    /* We are already buffering, advance to the next segment and push it on the
+     * stack. */
+    accumulate(e);
+
+    if (++e->top == e->stacklimit) {
+      /* TODO(haberman): grow stack? */
+      return false;
+    }
+
+    if (++e->segptr == e->seglimit) {
+      /* Grow segment buffer. */
+      size_t old_size =
+          (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
+      size_t new_size = old_size * 2;
+      upb_pb_encoder_segment *new_buf =
+          upb_env_realloc(e->env, e->segbuf, old_size, new_size);
+
+      if (new_buf == NULL) {
+        return false;
+      }
+
+      e->segptr = new_buf + (e->segptr - e->segbuf);
+      e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
+      e->segbuf = new_buf;
+    }
+  } else {
+    /* We were previously at the top level, start buffering. */
+    e->segptr = e->segbuf;
+    e->top = e->stack;
+    e->runbegin = e->ptr;
+  }
+
+  *e->top = e->segptr - e->segbuf;
+  e->segptr->seglen = 0;
+  e->segptr->msglen = 0;
+
+  return true;
+}
+
+/* Call to indicate the end of a delimited region.  We now know the length of
+ * the delimited region.  If we are not nested inside any other delimited
+ * regions, we can now emit all of the buffered data we accumulated. */
+static bool end_delim(upb_pb_encoder *e) {
+  size_t msglen;
+  accumulate(e);
+  msglen = top(e)->msglen;
+
+  if (e->top == e->stack) {
+    /* All lengths are now available, emit all buffered data. */
+    char buf[UPB_PB_VARINT_MAX_LEN];
+    upb_pb_encoder_segment *s;
+    const char *ptr = e->buf;
+    for (s = e->segbuf; s <= e->segptr; s++) {
+      size_t lenbytes = upb_vencode64(s->msglen, buf);
+      putbuf(e, buf, lenbytes);
+      putbuf(e, ptr, s->seglen);
+      ptr += s->seglen;
+    }
+
+    e->ptr = e->buf;
+    e->top = NULL;
+  } else {
+    /* Need to keep buffering; propagate length info into enclosing
+     * submessages. */
+    --e->top;
+    top(e)->msglen += msglen + upb_varint_size(msglen);
+  }
+
+  return true;
+}
+
+
+/* tag_t **********************************************************************/
+
+/* A precomputed (pre-encoded) tag and length. */
+
+typedef struct {
+  uint8_t bytes;
+  char tag[7];
+} tag_t;
+
+/* Allocates a new tag for this field, and sets it in these handlerattr. */
+static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
+                    upb_handlerattr *attr) {
+  uint32_t n = upb_fielddef_number(f);
+
+  tag_t *tag = upb_gmalloc(sizeof(tag_t));
+  tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
+
+  upb_handlerattr_init(attr);
+  upb_handlerattr_sethandlerdata(attr, tag);
+  upb_handlers_addcleanup(h, tag, upb_gfree);
+}
+
+static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) {
+  return encode_bytes(e, tag->tag, tag->bytes);
+}
+
+
+/* encoding of wire types *****************************************************/
+
+static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+static bool encode_varint(upb_pb_encoder *e, uint64_t val) {
+  if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
+    return false;
+  }
+
+  encoder_advance(e, upb_vencode64(val, e->ptr));
+  return true;
+}
+
+static uint64_t dbl2uint64(double d) {
+  uint64_t ret;
+  memcpy(&ret, &d, sizeof(uint64_t));
+  return ret;
+}
+
+static uint32_t flt2uint32(float d) {
+  uint32_t ret;
+  memcpy(&ret, &d, sizeof(uint32_t));
+  return ret;
+}
+
+
+/* encoding of proto types ****************************************************/
+
+static bool startmsg(void *c, const void *hd) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  if (e->depth++ == 0) {
+    upb_bytessink_start(e->output_, 0, &e->subc);
+  }
+  return true;
+}
+
+static bool endmsg(void *c, const void *hd, upb_status *status) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  if (--e->depth == 0) {
+    upb_bytessink_end(e->output_);
+  }
+  return true;
+}
+
+static void *encode_startdelimfield(void *c, const void *hd) {
+  bool ok = encode_tag(c, hd) && commit(c) && start_delim(c);
+  return ok ? c : UPB_BREAK;
+}
+
+static bool encode_enddelimfield(void *c, const void *hd) {
+  UPB_UNUSED(hd);
+  return end_delim(c);
+}
+
+static void *encode_startgroup(void *c, const void *hd) {
+  return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK;
+}
+
+static bool encode_endgroup(void *c, const void *hd) {
+  return encode_tag(c, hd) && commit(c);
+}
+
+static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
+  UPB_UNUSED(size_hint);
+  return encode_startdelimfield(c, hd);
+}
+
+static size_t encode_strbuf(void *c, const void *hd, const char *buf,
+                            size_t len, const upb_bufhandle *h) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(h);
+  return encode_bytes(c, buf, len) ? len : 0;
+}
+
+#define T(type, ctype, convert, encode)                                  \
+  static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
+    return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e);  \
+  }                                                                      \
+  static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
+    UPB_UNUSED(hd);                                                      \
+    return encode(e, (convert)(val));                                    \
+  }
+
+T(double,   double,   dbl2uint64,   encode_fixed64)
+T(float,    float,    flt2uint32,   encode_fixed32)
+T(int64,    int64_t,  uint64_t,     encode_varint)
+T(int32,    int32_t,  uint32_t,     encode_varint)
+T(fixed64,  uint64_t, uint64_t,     encode_fixed64)
+T(fixed32,  uint32_t, uint32_t,     encode_fixed32)
+T(bool,     bool,     bool,         encode_varint)
+T(uint32,   uint32_t, uint32_t,     encode_varint)
+T(uint64,   uint64_t, uint64_t,     encode_varint)
+T(enum,     int32_t,  uint32_t,     encode_varint)
+T(sfixed32, int32_t,  uint32_t,     encode_fixed32)
+T(sfixed64, int64_t,  uint64_t,     encode_fixed64)
+T(sint32,   int32_t,  upb_zzenc_32, encode_varint)
+T(sint64,   int64_t,  upb_zzenc_64, encode_varint)
+
+#undef T
+
+
+/* code to build the handlers *************************************************/
+
+static void newhandlers_callback(const void *closure, upb_handlers *h) {
+  const upb_msgdef *m;
+  upb_msg_field_iter i;
+
+  UPB_UNUSED(closure);
+
+  upb_handlers_setstartmsg(h, startmsg, NULL);
+  upb_handlers_setendmsg(h, endmsg, NULL);
+
+  m = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
+                  upb_fielddef_packed(f);
+    upb_handlerattr attr;
+    upb_wiretype_t wt =
+        packed ? UPB_WIRE_TYPE_DELIMITED
+               : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+
+    /* Pre-encode the tag for this field. */
+    new_tag(h, f, wt, &attr);
+
+    if (packed) {
+      upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
+      upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
+    }
+
+#define T(upper, lower, upbtype)                                     \
+  case UPB_DESCRIPTOR_TYPE_##upper:                                  \
+    if (packed) {                                                    \
+      upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
+    } else {                                                         \
+      upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
+    }                                                                \
+    break;
+
+    switch (upb_fielddef_descriptortype(f)) {
+      T(DOUBLE,   double,   double);
+      T(FLOAT,    float,    float);
+      T(INT64,    int64,    int64);
+      T(INT32,    int32,    int32);
+      T(FIXED64,  fixed64,  uint64);
+      T(FIXED32,  fixed32,  uint32);
+      T(BOOL,     bool,     bool);
+      T(UINT32,   uint32,   uint32);
+      T(UINT64,   uint64,   uint64);
+      T(ENUM,     enum,     int32);
+      T(SFIXED32, sfixed32, int32);
+      T(SFIXED64, sfixed64, int64);
+      T(SINT32,   sint32,   int32);
+      T(SINT64,   sint64,   int64);
+      case UPB_DESCRIPTOR_TYPE_STRING:
+      case UPB_DESCRIPTOR_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, encode_startstr, &attr);
+        upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
+        upb_handlers_setstring(h, f, encode_strbuf, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_MESSAGE:
+        upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_GROUP: {
+        /* Endgroup takes a different tag (wire_type = END_GROUP). */
+        upb_handlerattr attr2;
+        new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
+
+        upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
+
+        upb_handlerattr_uninit(&attr2);
+        break;
+      }
+    }
+
+#undef T
+
+    upb_handlerattr_uninit(&attr);
+  }
+}
+
+void upb_pb_encoder_reset(upb_pb_encoder *e) {
+  e->segptr = NULL;
+  e->top = NULL;
+  e->depth = 0;
+}
+
+
+/* public API *****************************************************************/
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner) {
+  return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL);
+}
+
+upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h,
+                                      upb_bytessink *output) {
+  const size_t initial_bufsize = 256;
+  const size_t initial_segbufsize = 16;
+  /* TODO(haberman): make this configurable. */
+  const size_t stack_size = 64;
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+
+  upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder));
+  if (!e) return NULL;
+
+  e->buf = upb_env_malloc(env, initial_bufsize);
+  e->segbuf = upb_env_malloc(env, initial_segbufsize * sizeof(*e->segbuf));
+  e->stack = upb_env_malloc(env, stack_size * sizeof(*e->stack));
+
+  if (!e->buf || !e->segbuf || !e->stack) {
+    return NULL;
+  }
+
+  e->limit = e->buf + initial_bufsize;
+  e->seglimit = e->segbuf + initial_segbufsize;
+  e->stacklimit = e->stack + stack_size;
+
+  upb_pb_encoder_reset(e);
+  upb_sink_reset(&e->input_, h, e);
+
+  e->env = env;
+  e->output_ = output;
+  e->subc = output->closure;
+  e->ptr = e->buf;
+
+  /* If this fails, increase the value in encoder.h. */
+  assert(upb_env_bytesallocated(env) - size_before <= UPB_PB_ENCODER_SIZE);
+  return e;
+}
+
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; }
+
+
+
+upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner,
+                                 upb_status *status) {
+  /* Create handlers. */
+  const upb_pbdecodermethod *decoder_m;
+  const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+  upb_env env;
+  upb_pbdecodermethodopts opts;
+  upb_pbdecoder *decoder;
+  upb_descreader *reader;
+  bool ok;
+  size_t i;
+  upb_filedef **ret = NULL;
+
+  upb_pbdecodermethodopts_init(&opts, reader_h);
+  decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m);
+
+  upb_env_init(&env);
+  upb_env_reporterrorsto(&env, status);
+
+  reader = upb_descreader_create(&env, reader_h);
+  decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader));
+
+  /* Push input data. */
+  ok = upb_bufsrc_putbuf(buf, n, upb_pbdecoder_input(decoder));
+
+  if (!ok) {
+    goto cleanup;
+  }
+
+  ret = upb_gmalloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1));
+
+  if (!ret) {
+    goto cleanup;
+  }
+
+  for (i = 0; i < upb_descreader_filecount(reader); i++) {
+    ret[i] = upb_descreader_file(reader, i);
+    upb_filedef_ref(ret[i], owner);
+  }
+
+  ret[i] = NULL;
+
+cleanup:
+  upb_env_uninit(&env);
+  upb_handlers_unref(reader_h, &reader_h);
+  upb_pbdecodermethod_unref(decoder_m, &decoder_m);
+  return ret;
+}
+/*
+ * upb::pb::TextPrinter
+ *
+ * OPT: This is not optimized at all.  It uses printf() which parses the format
+ * string every time, and it allocates memory for every put.
+ */
+
+
+#include <ctype.h>
+#include <float.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+struct upb_textprinter {
+  upb_sink input_;
+  upb_bytessink *output_;
+  int indent_depth_;
+  bool single_line_;
+  void *subc;
+};
+
+#define CHECK(x) if ((x) < 0) goto err;
+
+static const char *shortname(const char *longname) {
+  const char *last = strrchr(longname, '.');
+  return last ? last + 1 : longname;
+}
+
+static int indent(upb_textprinter *p) {
+  int i;
+  if (!p->single_line_)
+    for (i = 0; i < p->indent_depth_; i++)
+      upb_bytessink_putbuf(p->output_, p->subc, "  ", 2, NULL);
+  return 0;
+}
+
+static int endfield(upb_textprinter *p) {
+  const char ch = (p->single_line_ ? ' ' : '\n');
+  upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
+  return 0;
+}
+
+static int putescaped(upb_textprinter *p, const char *buf, size_t len,
+                      bool preserve_utf8) {
+  /* Based on CEscapeInternal() from Google's protobuf release. */
+  char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
+  const char *end = buf + len;
+
+  /* I think hex is prettier and more useful, but proto2 uses octal; should
+   * investigate whether it can parse hex also. */
+  const bool use_hex = false;
+  bool last_hex_escape = false; /* true if last output char was \xNN */
+
+  for (; buf < end; buf++) {
+    bool is_hex_escape;
+
+    if (dstend - dst < 4) {
+      upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+      dst = dstbuf;
+    }
+
+    is_hex_escape = false;
+    switch (*buf) {
+      case '\n': *(dst++) = '\\'; *(dst++) = 'n';  break;
+      case '\r': *(dst++) = '\\'; *(dst++) = 'r';  break;
+      case '\t': *(dst++) = '\\'; *(dst++) = 't';  break;
+      case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
+      case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
+      case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
+      default:
+        /* Note that if we emit \xNN and the buf character after that is a hex
+         * digit then that digit must be escaped too to prevent it being
+         * interpreted as part of the character code by C. */
+        if ((!preserve_utf8 || (uint8_t)*buf < 0x80) &&
+            (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) {
+          sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf);
+          is_hex_escape = use_hex;
+          dst += 4;
+        } else {
+          *(dst++) = *buf; break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+  /* Flush remaining data. */
+  upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+  return 0;
+}
+
+bool putf(upb_textprinter *p, const char *fmt, ...) {
+  va_list args;
+  va_list args_copy;
+  char *str;
+  int written;
+  int len;
+  bool ok;
+
+  va_start(args, fmt);
+
+  /* Run once to get the length of the string. */
+  _upb_va_copy(args_copy, args);
+  len = _upb_vsnprintf(NULL, 0, fmt, args_copy);
+  va_end(args_copy);
+
+  /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */
+  str = upb_gmalloc(len + 1);
+  if (!str) return false;
+  written = vsprintf(str, fmt, args);
+  va_end(args);
+  UPB_ASSERT_VAR(written, written == len);
+
+  ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+  upb_gfree(str);
+  return ok;
+}
+
+
+/* handlers *******************************************************************/
+
+static bool textprinter_startmsg(void *c, const void *hd) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc);
+  }
+  return true;
+}
+
+static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(s);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+#define TYPE(name, ctype, fmt) \
+  static bool textprinter_put ## name(void *closure, const void *handler_data, \
+                                      ctype val) {                             \
+    upb_textprinter *p = closure;                                              \
+    const upb_fielddef *f = handler_data;                                      \
+    CHECK(indent(p));                                                          \
+    putf(p, "%s: " fmt, upb_fielddef_name(f), val);                            \
+    CHECK(endfield(p));                                                        \
+    return true;                                                               \
+  err:                                                                         \
+    return false;                                                              \
+}
+
+static bool textprinter_putbool(void *closure, const void *handler_data,
+                                bool val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+#define STRINGIFY_HELPER(x) #x
+#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x)
+
+TYPE(int32,  int32_t,  "%" PRId32)
+TYPE(int64,  int64_t,  "%" PRId64)
+TYPE(uint32, uint32_t, "%" PRIu32)
+TYPE(uint64, uint64_t, "%" PRIu64)
+TYPE(float,  float,    "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
+TYPE(double, double,   "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
+
+#undef TYPE
+
+/* Output a symbolic value from the enum if found, else just print as int32. */
+static bool textprinter_putenum(void *closure, const void *handler_data,
+                                int32_t val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
+  const char *label = upb_enumdef_iton(enum_def, val);
+  if (label) {
+    indent(p);
+    putf(p, "%s: %s", upb_fielddef_name(f), label);
+    endfield(p);
+  } else {
+    if (!textprinter_putint32(closure, handler_data, val))
+      return false;
+  }
+  return true;
+}
+
+static void *textprinter_startstr(void *closure, const void *handler_data,
+                      size_t size_hint) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  UPB_UNUSED(size_hint);
+  indent(p);
+  putf(p, "%s: \"", upb_fielddef_name(f));
+  return p;
+}
+
+static bool textprinter_endstr(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  putf(p, "\"");
+  endfield(p);
+  return true;
+}
+
+static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
+                                 size_t len, const upb_bufhandle *handle) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = hd;
+  UPB_UNUSED(handle);
+  CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
+  return len;
+err:
+  return 0;
+}
+
+static void *textprinter_startsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  const char *name = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
+  p->indent_depth_++;
+  return p;
+err:
+  return UPB_BREAK;
+}
+
+static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  p->indent_depth_--;
+  CHECK(indent(p));
+  upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+static void onmreg(const void *c, upb_handlers *h) {
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+  upb_msg_field_iter i;
+  UPB_UNUSED(c);
+
+  upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
+  upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
+
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&attr, f);
+    switch (upb_fielddef_type(f)) {
+      case UPB_TYPE_INT32:
+        upb_handlers_setint32(h, f, textprinter_putint32, &attr);
+        break;
+      case UPB_TYPE_INT64:
+        upb_handlers_setint64(h, f, textprinter_putint64, &attr);
+        break;
+      case UPB_TYPE_UINT32:
+        upb_handlers_setuint32(h, f, textprinter_putuint32, &attr);
+        break;
+      case UPB_TYPE_UINT64:
+        upb_handlers_setuint64(h, f, textprinter_putuint64, &attr);
+        break;
+      case UPB_TYPE_FLOAT:
+        upb_handlers_setfloat(h, f, textprinter_putfloat, &attr);
+        break;
+      case UPB_TYPE_DOUBLE:
+        upb_handlers_setdouble(h, f, textprinter_putdouble, &attr);
+        break;
+      case UPB_TYPE_BOOL:
+        upb_handlers_setbool(h, f, textprinter_putbool, &attr);
+        break;
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, textprinter_startstr, &attr);
+        upb_handlers_setstring(h, f, textprinter_putstr, &attr);
+        upb_handlers_setendstr(h, f, textprinter_endstr, &attr);
+        break;
+      case UPB_TYPE_MESSAGE: {
+        const char *name =
+            upb_fielddef_istagdelim(f)
+                ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
+                : upb_fielddef_name(f);
+        upb_handlerattr_sethandlerdata(&attr, name);
+        upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr);
+        upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr);
+        break;
+      }
+      case UPB_TYPE_ENUM:
+        upb_handlers_setint32(h, f, textprinter_putenum, &attr);
+        break;
+    }
+  }
+}
+
+static void textprinter_reset(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+  p->indent_depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output) {
+  upb_textprinter *p = upb_env_malloc(env, sizeof(upb_textprinter));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  upb_sink_reset(&p->input_, h, p);
+  textprinter_reset(p, false);
+
+  return p;
+}
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner) {
+  return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
+}
+
+upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
+
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+}
+
+
+/* Index is descriptor type. */
+const uint8_t upb_pb_native_wire_types[] = {
+  UPB_WIRE_TYPE_END_GROUP,     /* ENDGROUP */
+  UPB_WIRE_TYPE_64BIT,         /* DOUBLE */
+  UPB_WIRE_TYPE_32BIT,         /* FLOAT */
+  UPB_WIRE_TYPE_VARINT,        /* INT64 */
+  UPB_WIRE_TYPE_VARINT,        /* UINT64 */
+  UPB_WIRE_TYPE_VARINT,        /* INT32 */
+  UPB_WIRE_TYPE_64BIT,         /* FIXED64 */
+  UPB_WIRE_TYPE_32BIT,         /* FIXED32 */
+  UPB_WIRE_TYPE_VARINT,        /* BOOL */
+  UPB_WIRE_TYPE_DELIMITED,     /* STRING */
+  UPB_WIRE_TYPE_START_GROUP,   /* GROUP */
+  UPB_WIRE_TYPE_DELIMITED,     /* MESSAGE */
+  UPB_WIRE_TYPE_DELIMITED,     /* BYTES */
+  UPB_WIRE_TYPE_VARINT,        /* UINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* ENUM */
+  UPB_WIRE_TYPE_32BIT,         /* SFIXED32 */
+  UPB_WIRE_TYPE_64BIT,         /* SFIXED64 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT64 */
+};
+
+/* A basic branch-based decoder, uses 32-bit values to get good performance
+ * on 32-bit architectures (but performs well on 64-bits also).
+ * This scheme comes from the original Google Protobuf implementation
+ * (proto2). */
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) {
+  upb_decoderet err = {NULL, 0};
+  const char *p = r.p;
+  uint32_t low = (uint32_t)r.val;
+  uint32_t high = 0;
+  uint32_t b;
+  b = *(p++); low  |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 28;
+              high  = (b & 0x7fU) >>  4; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) <<  3; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = ((uint64_t)high << 32) | low;
+  r.p = p;
+  return r;
+}
+
+/* Like the previous, but uses 64-bit values. */
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) {
+  const char *p = r.p;
+  uint64_t val = r.val;
+  uint64_t b;
+  upb_decoderet err = {NULL, 0};
+  b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = val;
+  r.p = p;
+  return r;
+}
+
+/* Given an encoded varint v, returns an integer with a single bit set that
+ * indicates the end of the varint.  Subtracting one from this value will
+ * yield a mask that leaves only bits that are part of the varint.  Returns
+ * 0 if the varint is unterminated. */
+static uint64_t upb_get_vstopbit(uint64_t v) {
+  uint64_t cbits = v | 0x7f7f7f7f7f7f7f7fULL;
+  return ~cbits & (cbits+1);
+}
+
+/* A branchless decoder.  Credit to Pascal Massimino for the bit-twiddling. */
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r) {
+  uint64_t b;
+  uint64_t stop_bit;
+  upb_decoderet my_r;
+  memcpy(&b, r.p, sizeof(b));
+  stop_bit = upb_get_vstopbit(b);
+  b =  (b & 0x7f7f7f7f7f7f7f7fULL) & (stop_bit - 1);
+  b +=       b & 0x007f007f007f007fULL;
+  b +=  3 * (b & 0x0000ffff0000ffffULL);
+  b += 15 * (b & 0x00000000ffffffffULL);
+  if (stop_bit == 0) {
+    /* Error: unterminated varint. */
+    upb_decoderet err_r = {(void*)0, 0};
+    return err_r;
+  }
+  my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+                            r.val | (b << 7));
+  return my_r;
+}
+
+/* A branchless decoder.  Credit to Daniel Wright for the bit-twiddling. */
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) {
+  uint64_t b;
+  uint64_t stop_bit;
+  upb_decoderet my_r;
+  memcpy(&b, r.p, sizeof(b));
+  stop_bit = upb_get_vstopbit(b);
+  b &= (stop_bit - 1);
+  b = ((b & 0x7f007f007f007f00ULL) >> 1) | (b & 0x007f007f007f007fULL);
+  b = ((b & 0xffff0000ffff0000ULL) >> 2) | (b & 0x0000ffff0000ffffULL);
+  b = ((b & 0xffffffff00000000ULL) >> 4) | (b & 0x00000000ffffffffULL);
+  if (stop_bit == 0) {
+    /* Error: unterminated varint. */
+    upb_decoderet err_r = {(void*)0, 0};
+    return err_r;
+  }
+  my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8),
+                            r.val | (b << 14));
+  return my_r;
+}
+
+#line 1 "upb/json/parser.rl"
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** A parser that uses the Ragel State Machine Compiler to generate
+** the finite automata.
+**
+** Ragel only natively handles regular languages, but we can manually
+** program it a bit to handle context-free languages like JSON, by using
+** the "fcall" and "fret" constructs.
+**
+** This parser can handle the basics, but needs several things to be fleshed
+** out:
+**
+** - handling of unicode escape sequences (including high surrogate pairs).
+** - properly check and report errors for unknown fields, stack overflow,
+**   improper array nesting (or lack of nesting).
+** - handling of base64 sequences with padding characters.
+** - handling of push-back (non-success returns from sink functions).
+** - handling of keys/escape-sequences/etc that span input buffers.
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define UPB_JSON_MAX_DEPTH 64
+
+typedef struct {
+  upb_sink sink;
+
+  /* The current message in which we're parsing, and the field whose value we're
+   * expecting next. */
+  const upb_msgdef *m;
+  const upb_fielddef *f;
+
+  /* The table mapping json name to fielddef for this message. */
+  upb_strtable *name_table;
+
+  /* We are in a repeated-field context, ready to emit mapentries as
+   * submessages. This flag alters the start-of-object (open-brace) behavior to
+   * begin a sequence of mapentry messages rather than a single submessage. */
+  bool is_map;
+
+  /* We are in a map-entry message context. This flag is set when parsing the
+   * value field of a single map entry and indicates to all value-field parsers
+   * (subobjects, strings, numbers, and bools) that the map-entry submessage
+   * should end as soon as the value is parsed. */
+  bool is_mapentry;
+
+  /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent
+   * message's map field that we're currently parsing. This differs from |f|
+   * because |f| is the field in the *current* message (i.e., the map-entry
+   * message itself), not the parent's field that leads to this map. */
+  const upb_fielddef *mapfield;
+} upb_jsonparser_frame;
+
+struct upb_json_parser {
+  upb_env *env;
+  const upb_json_parsermethod *method;
+  upb_bytessink input_;
+
+  /* Stack to track the JSON scopes we are in. */
+  upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH];
+  upb_jsonparser_frame *top;
+  upb_jsonparser_frame *limit;
+
+  upb_status status;
+
+  /* Ragel's internal parsing stack for the parsing state machine. */
+  int current_state;
+  int parser_stack[UPB_JSON_MAX_DEPTH];
+  int parser_top;
+
+  /* The handle for the current buffer. */
+  const upb_bufhandle *handle;
+
+  /* Accumulate buffer.  See details in parser.rl. */
+  const char *accumulated;
+  size_t accumulated_len;
+  char *accumulate_buf;
+  size_t accumulate_buf_size;
+
+  /* Multi-part text data.  See details in parser.rl. */
+  int multipart_state;
+  upb_selector_t string_selector;
+
+  /* Input capture.  See details in parser.rl. */
+  const char *capture;
+
+  /* Intermediate result of parsing a unicode escape sequence. */
+  uint32_t digit;
+};
+
+struct upb_json_parsermethod {
+  upb_refcounted base;
+
+  upb_byteshandler input_handler_;
+
+  /* Mainly for the purposes of refcounting, so all the fielddefs we point
+   * to stay alive. */
+  const upb_msgdef *msg;
+
+  /* Keys are upb_msgdef*, values are upb_strtable (json_name -> fielddef) */
+  upb_inttable name_tables;
+};
+
+#define PARSER_CHECK_RETURN(x) if (!(x)) return false
+
+/* Used to signal that a capture has been suspended. */
+static char suspend_capture;
+
+static upb_selector_t getsel_for_handlertype(upb_json_parser *p,
+                                             upb_handlertype_t type) {
+  upb_selector_t sel;
+  bool ok = upb_handlers_getselector(p->top->f, type, &sel);
+  UPB_ASSERT_VAR(ok, ok);
+  return sel;
+}
+
+static upb_selector_t parser_getsel(upb_json_parser *p) {
+  return getsel_for_handlertype(
+      p, upb_handlers_getprimitivehandlertype(p->top->f));
+}
+
+static bool check_stack(upb_json_parser *p) {
+  if ((p->top + 1) == p->limit) {
+    upb_status_seterrmsg(&p->status, "Nesting too deep");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+static void set_name_table(upb_json_parser *p, upb_jsonparser_frame *frame) {
+  upb_value v;
+  bool ok = upb_inttable_lookupptr(&p->method->name_tables, frame->m, &v);
+  UPB_ASSERT_VAR(ok, ok);
+  frame->name_table = upb_value_getptr(v);
+}
+
+/* There are GCC/Clang built-ins for overflow checking which we could start
+ * using if there was any performance benefit to it. */
+
+static bool checked_add(size_t a, size_t b, size_t *c) {
+  if (SIZE_MAX - a < b) return false;
+  *c = a + b;
+  return true;
+}
+
+static size_t saturating_multiply(size_t a, size_t b) {
+  /* size_t is unsigned, so this is defined behavior even on overflow. */
+  size_t ret = a * b;
+  if (b != 0 && ret / b != a) {
+    ret = SIZE_MAX;
+  }
+  return ret;
+}
+
+
+/* Base64 decoding ************************************************************/
+
+/* TODO(haberman): make this streaming. */
+
+static const signed char b64table[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+  07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+/* Returns the table value sign-extended to 32 bits.  Knowing that the upper
+ * bits will be 1 for unrecognized characters makes it easier to check for
+ * this error condition later (see below). */
+int32_t b64lookup(unsigned char ch) { return b64table[ch]; }
+
+/* Returns true if the given character is not a valid base64 character or
+ * padding. */
+bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; }
+
+static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr,
+                        size_t len) {
+  const char *limit = ptr + len;
+  for (; ptr < limit; ptr += 4) {
+    uint32_t val;
+    char output[3];
+
+    if (limit - ptr < 4) {
+      upb_status_seterrf(&p->status,
+                         "Base64 input for bytes field not a multiple of 4: %s",
+                         upb_fielddef_name(p->top->f));
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6  |
+          b64lookup(ptr[3]);
+
+    /* Test the upper bit; returns true if any of the characters returned -1. */
+    if (val & 0x80000000) {
+      goto otherchar;
+    }
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    output[2] = val & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 3, NULL);
+  }
+  return true;
+
+otherchar:
+  if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) ||
+      nonbase64(ptr[3]) ) {
+    upb_status_seterrf(&p->status,
+                       "Non-base64 characters in bytes field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  } if (ptr[2] == '=') {
+    uint32_t val;
+    char output;
+
+    /* Last group contains only two input bytes, one output byte. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12;
+
+    assert(!(val & 0x80000000));
+    output = val >> 16;
+    upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL);
+    return true;
+  } else {
+    uint32_t val;
+    char output[2];
+
+    /* Last group contains only three input bytes, two output bytes. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6;
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 2, NULL);
+    return true;
+  }
+
+badpadding:
+  upb_status_seterrf(&p->status,
+                     "Incorrect base64 padding for field: %s (%.*s)",
+                     upb_fielddef_name(p->top->f),
+                     4, ptr);
+  upb_env_reporterror(p->env, &p->status);
+  return false;
+}
+
+
+/* Accumulate buffer **********************************************************/
+
+/* Functionality for accumulating a buffer.
+ *
+ * Some parts of the parser need an entire value as a contiguous string.  For
+ * example, to look up a member name in a hash table, or to turn a string into
+ * a number, the relevant library routines need the input string to be in
+ * contiguous memory, even if the value spanned two or more buffers in the
+ * input.  These routines handle that.
+ *
+ * In the common case we can just point to the input buffer to get this
+ * contiguous string and avoid any actual copy.  So we optimistically begin
+ * this way.  But there are a few cases where we must instead copy into a
+ * separate buffer:
+ *
+ *   1. The string was not contiguous in the input (it spanned buffers).
+ *
+ *   2. The string included escape sequences that need to be interpreted to get
+ *      the true value in a contiguous buffer. */
+
+static void assert_accumulate_empty(upb_json_parser *p) {
+  UPB_UNUSED(p);
+  assert(p->accumulated == NULL);
+  assert(p->accumulated_len == 0);
+}
+
+static void accumulate_clear(upb_json_parser *p) {
+  p->accumulated = NULL;
+  p->accumulated_len = 0;
+}
+
+/* Used internally by accumulate_append(). */
+static bool accumulate_realloc(upb_json_parser *p, size_t need) {
+  void *mem;
+  size_t old_size = p->accumulate_buf_size;
+  size_t new_size = UPB_MAX(old_size, 128);
+  while (new_size < need) {
+    new_size = saturating_multiply(new_size, 2);
+  }
+
+  mem = upb_env_realloc(p->env, p->accumulate_buf, old_size, new_size);
+  if (!mem) {
+    upb_status_seterrmsg(&p->status, "Out of memory allocating buffer.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  p->accumulate_buf = mem;
+  p->accumulate_buf_size = new_size;
+  return true;
+}
+
+/* Logically appends the given data to the append buffer.
+ * If "can_alias" is true, we will try to avoid actually copying, but the buffer
+ * must be valid until the next accumulate_append() call (if any). */
+static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len,
+                              bool can_alias) {
+  size_t need;
+
+  if (!p->accumulated && can_alias) {
+    p->accumulated = buf;
+    p->accumulated_len = len;
+    return true;
+  }
+
+  if (!checked_add(p->accumulated_len, len, &need)) {
+    upb_status_seterrmsg(&p->status, "Integer overflow.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) {
+    return false;
+  }
+
+  if (p->accumulated != p->accumulate_buf) {
+    memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len);
+    p->accumulated = p->accumulate_buf;
+  }
+
+  memcpy(p->accumulate_buf + p->accumulated_len, buf, len);
+  p->accumulated_len += len;
+  return true;
+}
+
+/* Returns a pointer to the data accumulated since the last accumulate_clear()
+ * call, and writes the length to *len.  This with point either to the input
+ * buffer or a temporary accumulate buffer. */
+static const char *accumulate_getptr(upb_json_parser *p, size_t *len) {
+  assert(p->accumulated);
+  *len = p->accumulated_len;
+  return p->accumulated;
+}
+
+
+/* Mult-part text data ********************************************************/
+
+/* When we have text data in the input, it can often come in multiple segments.
+ * For example, there may be some raw string data followed by an escape
+ * sequence.  The two segments are processed with different logic.  Also buffer
+ * seams in the input can cause multiple segments.
+ *
+ * As we see segments, there are two main cases for how we want to process them:
+ *
+ *  1. we want to push the captured input directly to string handlers.
+ *
+ *  2. we need to accumulate all the parts into a contiguous buffer for further
+ *     processing (field name lookup, string->number conversion, etc). */
+
+/* This is the set of states for p->multipart_state. */
+enum {
+  /* We are not currently processing multipart data. */
+  MULTIPART_INACTIVE = 0,
+
+  /* We are processing multipart data by accumulating it into a contiguous
+   * buffer. */
+  MULTIPART_ACCUMULATE = 1,
+
+  /* We are processing multipart data by pushing each part directly to the
+   * current string handlers. */
+  MULTIPART_PUSHEAGERLY = 2
+};
+
+/* Start a multi-part text value where we accumulate the data for processing at
+ * the end. */
+static void multipart_startaccum(upb_json_parser *p) {
+  assert_accumulate_empty(p);
+  assert(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_ACCUMULATE;
+}
+
+/* Start a multi-part text value where we immediately push text data to a string
+ * value with the given selector. */
+static void multipart_start(upb_json_parser *p, upb_selector_t sel) {
+  assert_accumulate_empty(p);
+  assert(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_PUSHEAGERLY;
+  p->string_selector = sel;
+}
+
+static bool multipart_text(upb_json_parser *p, const char *buf, size_t len,
+                           bool can_alias) {
+  switch (p->multipart_state) {
+    case MULTIPART_INACTIVE:
+      upb_status_seterrmsg(
+          &p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+
+    case MULTIPART_ACCUMULATE:
+      if (!accumulate_append(p, buf, len, can_alias)) {
+        return false;
+      }
+      break;
+
+    case MULTIPART_PUSHEAGERLY: {
+      const upb_bufhandle *handle = can_alias ? p->handle : NULL;
+      upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle);
+      break;
+    }
+  }
+
+  return true;
+}
+
+/* Note: this invalidates the accumulate buffer!  Call only after reading its
+ * contents. */
+static void multipart_end(upb_json_parser *p) {
+  assert(p->multipart_state != MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_INACTIVE;
+  accumulate_clear(p);
+}
+
+
+/* Input capture **************************************************************/
+
+/* Functionality for capturing a region of the input as text.  Gracefully
+ * handles the case where a buffer seam occurs in the middle of the captured
+ * region. */
+
+static void capture_begin(upb_json_parser *p, const char *ptr) {
+  assert(p->multipart_state != MULTIPART_INACTIVE);
+  assert(p->capture == NULL);
+  p->capture = ptr;
+}
+
+static bool capture_end(upb_json_parser *p, const char *ptr) {
+  assert(p->capture);
+  if (multipart_text(p, p->capture, ptr - p->capture, true)) {
+    p->capture = NULL;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* This is called at the end of each input buffer (ie. when we have hit a
+ * buffer seam).  If we are in the middle of capturing the input, this
+ * processes the unprocessed capture region. */
+static void capture_suspend(upb_json_parser *p, const char **ptr) {
+  if (!p->capture) return;
+
+  if (multipart_text(p, p->capture, *ptr - p->capture, false)) {
+    /* We use this as a signal that we were in the middle of capturing, and
+     * that capturing should resume at the beginning of the next buffer.
+     * 
+     * We can't use *ptr here, because we have no guarantee that this pointer
+     * will be valid when we resume (if the underlying memory is freed, then
+     * using the pointer at all, even to compare to NULL, is likely undefined
+     * behavior). */
+    p->capture = &suspend_capture;
+  } else {
+    /* Need to back up the pointer to the beginning of the capture, since
+     * we were not able to actually preserve it. */
+    *ptr = p->capture;
+  }
+}
+
+static void capture_resume(upb_json_parser *p, const char *ptr) {
+  if (p->capture) {
+    assert(p->capture == &suspend_capture);
+    p->capture = ptr;
+  }
+}
+
+
+/* Callbacks from the parser **************************************************/
+
+/* These are the functions called directly from the parser itself.
+ * We define these in the same order as their declarations in the parser. */
+
+static char escape_char(char in) {
+  switch (in) {
+    case 'r': return '\r';
+    case 't': return '\t';
+    case 'n': return '\n';
+    case 'f': return '\f';
+    case 'b': return '\b';
+    case '/': return '/';
+    case '"': return '"';
+    case '\\': return '\\';
+    default:
+      assert(0);
+      return 'x';
+  }
+}
+
+static bool escape(upb_json_parser *p, const char *ptr) {
+  char ch = escape_char(*ptr);
+  return multipart_text(p, &ch, 1, false);
+}
+
+static void start_hex(upb_json_parser *p) {
+  p->digit = 0;
+}
+
+static void hexdigit(upb_json_parser *p, const char *ptr) {
+  char ch = *ptr;
+
+  p->digit <<= 4;
+
+  if (ch >= '0' && ch <= '9') {
+    p->digit += (ch - '0');
+  } else if (ch >= 'a' && ch <= 'f') {
+    p->digit += ((ch - 'a') + 10);
+  } else {
+    assert(ch >= 'A' && ch <= 'F');
+    p->digit += ((ch - 'A') + 10);
+  }
+}
+
+static bool end_hex(upb_json_parser *p) {
+  uint32_t codepoint = p->digit;
+
+  /* emit the codepoint as UTF-8. */
+  char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */
+  int length = 0;
+  if (codepoint <= 0x7F) {
+    utf8[0] = codepoint;
+    length = 1;
+  } else if (codepoint <= 0x07FF) {
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x1F) | 0xC0;
+    length = 2;
+  } else /* codepoint <= 0xFFFF */ {
+    utf8[2] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x0F) | 0xE0;
+    length = 3;
+  }
+  /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate
+   * we have to wait for the next escape to get the full code point). */
+
+  return multipart_text(p, utf8, length, false);
+}
+
+static void start_text(upb_json_parser *p, const char *ptr) {
+  capture_begin(p, ptr);
+}
+
+static bool end_text(upb_json_parser *p, const char *ptr) {
+  return capture_end(p, ptr);
+}
+
+static void start_number(upb_json_parser *p, const char *ptr) {
+  multipart_startaccum(p);
+  capture_begin(p, ptr);
+}
+
+static bool parse_number(upb_json_parser *p);
+
+static bool end_number(upb_json_parser *p, const char *ptr) {
+  if (!capture_end(p, ptr)) {
+    return false;
+  }
+
+  return parse_number(p);
+}
+
+static bool parse_number(upb_json_parser *p) {
+  size_t len;
+  const char *buf;
+  const char *myend;
+  char *end;
+
+  /* strtol() and friends unfortunately do not support specifying the length of
+   * the input string, so we need to force a copy into a NULL-terminated buffer. */
+  if (!multipart_text(p, "\0", 1, false)) {
+    return false;
+  }
+
+  buf = accumulate_getptr(p, &len);
+  myend = buf + len - 1;  /* One for NULL. */
+
+  /* XXX: We are using strtol to parse integers, but this is wrong as even
+   * integers can be represented as 1e6 (for example), which strtol can't
+   * handle correctly.
+   *
+   * XXX: Also, we can't handle large integers properly because strto[u]ll
+   * isn't in C89.
+   *
+   * XXX: Also, we don't properly check floats for overflow, since strtof
+   * isn't in C89. */
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32: {
+      long val = strtol(p->accumulated, &end, 0);
+      if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_INT64: {
+      long long val = strtol(p->accumulated, &end, 0);
+      if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(p->accumulated, &end, 0);
+      if (val > UINT32_MAX || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_UINT64: {
+      unsigned long long val = strtoul(p->accumulated, &end, 0);
+      if (val > UINT64_MAX || errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_DOUBLE: {
+      double val = strtod(p->accumulated, &end);
+      if (errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    case UPB_TYPE_FLOAT: {
+      float val = strtod(p->accumulated, &end);
+      if (errno == ERANGE || end != myend)
+        goto err;
+      else
+        upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
+      break;
+    }
+    default:
+      assert(false);
+  }
+
+  multipart_end(p);
+
+  return true;
+
+err:
+  upb_status_seterrf(&p->status, "error parsing number: %s", buf);
+  upb_env_reporterror(p->env, &p->status);
+  multipart_end(p);
+  return false;
+}
+
+static bool parser_putbool(upb_json_parser *p, bool val) {
+  bool ok;
+
+  if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
+    upb_status_seterrf(&p->status,
+                       "Boolean value specified for non-bool field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
+  UPB_ASSERT_VAR(ok, ok);
+
+  return true;
+}
+
+static bool start_stringval(upb_json_parser *p) {
+  assert(p->top->f);
+
+  if (upb_fielddef_isstring(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    if (!check_stack(p)) return false;
+
+    /* Start a new parser frame: parser frames correspond one-to-one with
+     * handler frames, and string events occur in a sub-frame. */
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+    upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink);
+    inner->m = p->top->m;
+    inner->f = p->top->f;
+    inner->name_table = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) {
+      /* For STRING fields we push data directly to the handlers as it is
+       * parsed.  We don't do this yet for BYTES fields, because our base64
+       * decoder is not streaming.
+       *
+       * TODO(haberman): make base64 decoding streaming also. */
+      multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING));
+      return true;
+    } else {
+      multipart_startaccum(p);
+      return true;
+    }
+  } else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) {
+    /* No need to push a frame -- symbolic enum names in quotes remain in the
+     * current parser frame.
+     *
+     * Enum string values must accumulate so we can look up the value in a table
+     * once it is complete. */
+    multipart_startaccum(p);
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "String specified for non-string/non-enum field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static bool end_stringval(upb_json_parser *p) {
+  bool ok = true;
+
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_BYTES:
+      if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
+                       p->accumulated, p->accumulated_len)) {
+        return false;
+      }
+      /* Fall through. */
+
+    case UPB_TYPE_STRING: {
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      upb_sink_endstr(&p->top->sink, sel);
+      p->top--;
+      break;
+    }
+
+    case UPB_TYPE_ENUM: {
+      /* Resolve enum symbolic name to integer value. */
+      const upb_enumdef *enumdef =
+          (const upb_enumdef*)upb_fielddef_subdef(p->top->f);
+
+      size_t len;
+      const char *buf = accumulate_getptr(p, &len);
+
+      int32_t int_val = 0;
+      ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val);
+
+      if (ok) {
+        upb_selector_t sel = parser_getsel(p);
+        upb_sink_putint32(&p->top->sink, sel, int_val);
+      } else {
+        upb_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf);
+        upb_env_reporterror(p->env, &p->status);
+      }
+
+      break;
+    }
+
+    default:
+      assert(false);
+      upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
+      upb_env_reporterror(p->env, &p->status);
+      ok = false;
+      break;
+  }
+
+  multipart_end(p);
+
+  return ok;
+}
+
+static void start_member(upb_json_parser *p) {
+  assert(!p->top->f);
+  multipart_startaccum(p);
+}
+
+/* Helper: invoked during parse_mapentry() to emit the mapentry message's key
+ * field based on the current contents of the accumulate buffer. */
+static bool parse_mapentry_key(upb_json_parser *p) {
+
+  size_t len;
+  const char *buf = accumulate_getptr(p, &len);
+
+  /* Emit the key field. We do a bit of ad-hoc parsing here because the
+   * parser state machine has already decided that this is a string field
+   * name, and we are reinterpreting it as some arbitrary key type. In
+   * particular, integer and bool keys are quoted, so we need to parse the
+   * quoted string contents here. */
+
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY);
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no key");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      /* Invoke end_number. The accum buffer has the number's text already. */
+      if (!parse_number(p)) {
+        return false;
+      }
+      break;
+    case UPB_TYPE_BOOL:
+      if (len == 4 && !strncmp(buf, "true", 4)) {
+        if (!parser_putbool(p, true)) {
+          return false;
+        }
+      } else if (len == 5 && !strncmp(buf, "false", 5)) {
+        if (!parser_putbool(p, false)) {
+          return false;
+        }
+      } else {
+        upb_status_seterrmsg(&p->status,
+                             "Map bool key not 'true' or 'false'");
+        upb_env_reporterror(p->env, &p->status);
+        return false;
+      }
+      multipart_end(p);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      upb_sink subsink;
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+      upb_sink_startstr(&p->top->sink, sel, len, &subsink);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_STRING);
+      upb_sink_putstring(&subsink, sel, buf, len, NULL);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      upb_sink_endstr(&subsink, sel);
+      multipart_end(p);
+      break;
+    }
+    default:
+      upb_status_seterrmsg(&p->status, "Invalid field type for map key");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+  }
+
+  return true;
+}
+
+/* Helper: emit one map entry (as a submessage in the map field sequence). This
+ * is invoked from end_membername(), at the end of the map entry's key string,
+ * with the map key in the accumulate buffer. It parses the key from that
+ * buffer, emits the handler calls to start the mapentry submessage (setting up
+ * its subframe in the process), and sets up state in the subframe so that the
+ * value parser (invoked next) will emit the mapentry's value field and then
+ * end the mapentry message. */
+
+static bool handle_mapentry(upb_json_parser *p) {
+  const upb_fielddef *mapfield;
+  const upb_msgdef *mapentrymsg;
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  /* Map entry: p->top->sink is the seq frame, so we need to start a frame
+   * for the mapentry itself, and then set |f| in that frame so that the map
+   * value field is parsed, and also set a flag to end the frame after the
+   * map-entry value is parsed. */
+  if (!check_stack(p)) return false;
+
+  mapfield = p->top->mapfield;
+  mapentrymsg = upb_fielddef_msgsubdef(mapfield);
+
+  inner = p->top + 1;
+  p->top->f = mapfield;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+  upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+  inner->m = mapentrymsg;
+  inner->name_table = NULL;
+  inner->mapfield = mapfield;
+  inner->is_map = false;
+
+  /* Don't set this to true *yet* -- we reuse parsing handlers below to push
+   * the key field value to the sink, and these handlers will pop the frame
+   * if they see is_mapentry (when invoked by the parser state machine, they
+   * would have just seen the map-entry value, not key). */
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  /* send STARTMSG in submsg frame. */
+  upb_sink_startmsg(&p->top->sink);
+
+  parse_mapentry_key(p);
+
+  /* Set up the value field to receive the map-entry value. */
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE);
+  p->top->is_mapentry = true;  /* set up to pop frame after value is parsed. */
+  p->top->mapfield = mapfield;
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no value");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+static bool end_membername(upb_json_parser *p) {
+  assert(!p->top->f);
+
+  if (p->top->is_map) {
+    return handle_mapentry(p);
+  } else {
+    size_t len;
+    const char *buf = accumulate_getptr(p, &len);
+    upb_value v;
+
+    if (upb_strtable_lookup2(p->top->name_table, buf, len, &v)) {
+      p->top->f = upb_value_getconstptr(v);
+      multipart_end(p);
+
+      return true;
+    } else {
+      /* TODO(haberman): Ignore unknown fields if requested/configured to do
+       * so. */
+      upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+  }
+}
+
+static void end_member(upb_json_parser *p) {
+  /* If we just parsed a map-entry value, end that frame too. */
+  if (p->top->is_mapentry) {
+    upb_status s = UPB_STATUS_INIT;
+    upb_selector_t sel;
+    bool ok;
+    const upb_fielddef *mapfield;
+
+    assert(p->top > p->stack);
+    /* send ENDMSG on submsg. */
+    upb_sink_endmsg(&p->top->sink, &s);
+    mapfield = p->top->mapfield;
+
+    /* send ENDSUBMSG in repeated-field-of-mapentries frame. */
+    p->top--;
+    ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel);
+    UPB_ASSERT_VAR(ok, ok);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+
+  p->top->f = NULL;
+}
+
+static bool start_subobject(upb_json_parser *p) {
+  assert(p->top->f);
+
+  if (upb_fielddef_ismap(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a map. Start a new parser frame in a repeated-field
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+    upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    inner->name_table = NULL;
+    inner->mapfield = p->top->f;
+    inner->f = NULL;
+    inner->is_map = true;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else if (upb_fielddef_issubmsg(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a subobject. Start a new parser frame in the submsg
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+    upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    set_name_table(p, inner);
+    inner->f = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "Object specified for non-message/group field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static void end_subobject(upb_json_parser *p) {
+  if (p->top->is_map) {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+    upb_sink_endseq(&p->top->sink, sel);
+  } else {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+}
+
+static bool start_array(upb_json_parser *p) {
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  assert(p->top->f);
+
+  if (!upb_fielddef_isseq(p->top->f)) {
+    upb_status_seterrf(&p->status,
+                       "Array specified for non-repeated field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (!check_stack(p)) return false;
+
+  inner = p->top + 1;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+  upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+  inner->m = p->top->m;
+  inner->name_table = NULL;
+  inner->f = p->top->f;
+  inner->is_map = false;
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  return true;
+}
+
+static void end_array(upb_json_parser *p) {
+  upb_selector_t sel;
+
+  assert(p->top > p->stack);
+
+  p->top--;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+  upb_sink_endseq(&p->top->sink, sel);
+}
+
+static void start_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_sink_startmsg(&p->top->sink);
+  }
+}
+
+static void end_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_status status;
+    upb_status_clear(&status);
+    upb_sink_endmsg(&p->top->sink, &status);
+    if (!upb_ok(&status)) {
+      upb_env_reporterror(p->env, &status);
+    }
+  }
+}
+
+
+#define CHECK_RETURN_TOP(x) if (!(x)) goto error
+
+
+/* The actual parser **********************************************************/
+
+/* What follows is the Ragel parser itself.  The language is specified in Ragel
+ * and the actions call our C functions above.
+ *
+ * Ragel has an extensive set of functionality, and we use only a small part of
+ * it.  There are many action types but we only use a few:
+ *
+ *   ">" -- transition into a machine
+ *   "%" -- transition out of a machine
+ *   "@" -- transition into a final state of a machine.
+ *
+ * "@" transitions are tricky because a machine can transition into a final
+ * state repeatedly.  But in some cases we know this can't happen, for example
+ * a string which is delimited by a final '"' can only transition into its
+ * final state once, when the closing '"' is seen. */
+
+
+#line 1245 "upb/json/parser.rl"
+
+
+
+#line 1157 "upb/json/parser.c"
+static const char _json_actions[] = {
+	0, 1, 0, 1, 2, 1, 3, 1, 
+	5, 1, 6, 1, 7, 1, 8, 1, 
+	10, 1, 12, 1, 13, 1, 14, 1, 
+	15, 1, 16, 1, 17, 1, 21, 1, 
+	25, 1, 27, 2, 3, 8, 2, 4, 
+	5, 2, 6, 2, 2, 6, 8, 2, 
+	11, 9, 2, 13, 15, 2, 14, 15, 
+	2, 18, 1, 2, 19, 27, 2, 20, 
+	9, 2, 22, 27, 2, 23, 27, 2, 
+	24, 27, 2, 26, 27, 3, 14, 11, 
+	9
+};
+
+static const unsigned char _json_key_offsets[] = {
+	0, 0, 4, 9, 14, 15, 19, 24, 
+	29, 34, 38, 42, 45, 48, 50, 54, 
+	58, 60, 62, 67, 69, 71, 80, 86, 
+	92, 98, 104, 106, 115, 116, 116, 116, 
+	121, 126, 131, 132, 133, 134, 135, 135, 
+	136, 137, 138, 138, 139, 140, 141, 141, 
+	146, 151, 152, 156, 161, 166, 171, 175, 
+	175, 178, 178, 178
+};
+
+static const char _json_trans_keys[] = {
+	32, 123, 9, 13, 32, 34, 125, 9, 
+	13, 32, 34, 125, 9, 13, 34, 32, 
+	58, 9, 13, 32, 93, 125, 9, 13, 
+	32, 44, 125, 9, 13, 32, 44, 125, 
+	9, 13, 32, 34, 9, 13, 45, 48, 
+	49, 57, 48, 49, 57, 46, 69, 101, 
+	48, 57, 69, 101, 48, 57, 43, 45, 
+	48, 57, 48, 57, 48, 57, 46, 69, 
+	101, 48, 57, 34, 92, 34, 92, 34, 
+	47, 92, 98, 102, 110, 114, 116, 117, 
+	48, 57, 65, 70, 97, 102, 48, 57, 
+	65, 70, 97, 102, 48, 57, 65, 70, 
+	97, 102, 48, 57, 65, 70, 97, 102, 
+	34, 92, 34, 45, 91, 102, 110, 116, 
+	123, 48, 57, 34, 32, 93, 125, 9, 
+	13, 32, 44, 93, 9, 13, 32, 93, 
+	125, 9, 13, 97, 108, 115, 101, 117, 
+	108, 108, 114, 117, 101, 32, 34, 125, 
+	9, 13, 32, 34, 125, 9, 13, 34, 
+	32, 58, 9, 13, 32, 93, 125, 9, 
+	13, 32, 44, 125, 9, 13, 32, 44, 
+	125, 9, 13, 32, 34, 9, 13, 32, 
+	9, 13, 0
+};
+
+static const char _json_single_lengths[] = {
+	0, 2, 3, 3, 1, 2, 3, 3, 
+	3, 2, 2, 1, 3, 0, 2, 2, 
+	0, 0, 3, 2, 2, 9, 0, 0, 
+	0, 0, 2, 7, 1, 0, 0, 3, 
+	3, 3, 1, 1, 1, 1, 0, 1, 
+	1, 1, 0, 1, 1, 1, 0, 3, 
+	3, 1, 2, 3, 3, 3, 2, 0, 
+	1, 0, 0, 0
+};
+
+static const char _json_range_lengths[] = {
+	0, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 0, 0, 0, 3, 3, 
+	3, 3, 0, 1, 0, 0, 0, 1, 
+	1, 1, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 1, 
+	1, 0, 1, 1, 1, 1, 1, 0, 
+	1, 0, 0, 0
+};
+
+static const short _json_index_offsets[] = {
+	0, 0, 4, 9, 14, 16, 20, 25, 
+	30, 35, 39, 43, 46, 50, 52, 56, 
+	60, 62, 64, 69, 72, 75, 85, 89, 
+	93, 97, 101, 104, 113, 115, 116, 117, 
+	122, 127, 132, 134, 136, 138, 140, 141, 
+	143, 145, 147, 148, 150, 152, 154, 155, 
+	160, 165, 167, 171, 176, 181, 186, 190, 
+	191, 194, 195, 196
+};
+
+static const char _json_indicies[] = {
+	0, 2, 0, 1, 3, 4, 5, 3, 
+	1, 6, 7, 8, 6, 1, 9, 1, 
+	10, 11, 10, 1, 11, 1, 1, 11, 
+	12, 13, 14, 15, 13, 1, 16, 17, 
+	8, 16, 1, 17, 7, 17, 1, 18, 
+	19, 20, 1, 19, 20, 1, 22, 23, 
+	23, 21, 24, 1, 23, 23, 24, 21, 
+	25, 25, 26, 1, 26, 1, 26, 21, 
+	22, 23, 23, 20, 21, 28, 29, 27, 
+	31, 32, 30, 33, 33, 33, 33, 33, 
+	33, 33, 33, 34, 1, 35, 35, 35, 
+	1, 36, 36, 36, 1, 37, 37, 37, 
+	1, 38, 38, 38, 1, 40, 41, 39, 
+	42, 43, 44, 45, 46, 47, 48, 43, 
+	1, 49, 1, 50, 51, 53, 54, 1, 
+	53, 52, 55, 56, 54, 55, 1, 56, 
+	1, 1, 56, 52, 57, 1, 58, 1, 
+	59, 1, 60, 1, 61, 62, 1, 63, 
+	1, 64, 1, 65, 66, 1, 67, 1, 
+	68, 1, 69, 70, 71, 72, 70, 1, 
+	73, 74, 75, 73, 1, 76, 1, 77, 
+	78, 77, 1, 78, 1, 1, 78, 79, 
+	80, 81, 82, 80, 1, 83, 84, 75, 
+	83, 1, 84, 74, 84, 1, 85, 86, 
+	86, 1, 1, 1, 1, 0
+};
+
+static const char _json_trans_targs[] = {
+	1, 0, 2, 3, 4, 56, 3, 4, 
+	56, 5, 5, 6, 7, 8, 9, 56, 
+	8, 9, 11, 12, 18, 57, 13, 15, 
+	14, 16, 17, 20, 58, 21, 20, 58, 
+	21, 19, 22, 23, 24, 25, 26, 20, 
+	58, 21, 28, 30, 31, 34, 39, 43, 
+	47, 29, 59, 59, 32, 31, 29, 32, 
+	33, 35, 36, 37, 38, 59, 40, 41, 
+	42, 59, 44, 45, 46, 59, 48, 49, 
+	55, 48, 49, 55, 50, 50, 51, 52, 
+	53, 54, 55, 53, 54, 59, 56
+};
+
+static const char _json_trans_actions[] = {
+	0, 0, 0, 21, 77, 53, 0, 47, 
+	23, 17, 0, 0, 15, 19, 19, 50, 
+	0, 0, 0, 0, 0, 1, 0, 0, 
+	0, 0, 0, 3, 13, 0, 0, 35, 
+	5, 11, 0, 38, 7, 7, 7, 41, 
+	44, 9, 62, 56, 25, 0, 0, 0, 
+	31, 29, 33, 59, 15, 0, 27, 0, 
+	0, 0, 0, 0, 0, 68, 0, 0, 
+	0, 71, 0, 0, 0, 65, 21, 77, 
+	53, 0, 47, 23, 17, 0, 0, 15, 
+	19, 19, 50, 0, 0, 74, 0
+};
+
+static const int json_start = 1;
+
+static const int json_en_number_machine = 10;
+static const int json_en_string_machine = 19;
+static const int json_en_value_machine = 27;
+static const int json_en_main = 1;
+
+
+#line 1248 "upb/json/parser.rl"
+
+size_t parse(void *closure, const void *hd, const char *buf, size_t size,
+             const upb_bufhandle *handle) {
+  upb_json_parser *parser = closure;
+
+  /* Variables used by Ragel's generated code. */
+  int cs = parser->current_state;
+  int *stack = parser->parser_stack;
+  int top = parser->parser_top;
+
+  const char *p = buf;
+  const char *pe = buf + size;
+
+  parser->handle = handle;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  capture_resume(parser, buf);
+
+  
+#line 1328 "upb/json/parser.c"
+	{
+	int _klen;
+	unsigned int _trans;
+	const char *_acts;
+	unsigned int _nacts;
+	const char *_keys;
+
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _json_trans_keys + _json_key_offsets[cs];
+	_trans = _json_index_offsets[cs];
+
+	_klen = _json_single_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + _klen - 1;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + ((_upper-_lower) >> 1);
+			if ( (*p) < *_mid )
+				_upper = _mid - 1;
+			else if ( (*p) > *_mid )
+				_lower = _mid + 1;
+			else {
+				_trans += (unsigned int)(_mid - _keys);
+				goto _match;
+			}
+		}
+		_keys += _klen;
+		_trans += _klen;
+	}
+
+	_klen = _json_range_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + (_klen<<1) - 2;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + (((_upper-_lower) >> 1) & ~1);
+			if ( (*p) < _mid[0] )
+				_upper = _mid - 2;
+			else if ( (*p) > _mid[1] )
+				_lower = _mid + 2;
+			else {
+				_trans += (unsigned int)((_mid - _keys)>>1);
+				goto _match;
+			}
+		}
+		_trans += _klen;
+	}
+
+_match:
+	_trans = _json_indicies[_trans];
+	cs = _json_trans_targs[_trans];
+
+	if ( _json_trans_actions[_trans] == 0 )
+		goto _again;
+
+	_acts = _json_actions + _json_trans_actions[_trans];
+	_nacts = (unsigned int) *_acts++;
+	while ( _nacts-- > 0 )
+	{
+		switch ( *_acts++ )
+		{
+	case 0:
+#line 1160 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 1:
+#line 1161 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
+	break;
+	case 2:
+#line 1165 "upb/json/parser.rl"
+	{ start_text(parser, p); }
+	break;
+	case 3:
+#line 1166 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_text(parser, p)); }
+	break;
+	case 4:
+#line 1172 "upb/json/parser.rl"
+	{ start_hex(parser); }
+	break;
+	case 5:
+#line 1173 "upb/json/parser.rl"
+	{ hexdigit(parser, p); }
+	break;
+	case 6:
+#line 1174 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_hex(parser)); }
+	break;
+	case 7:
+#line 1180 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(escape(parser, p)); }
+	break;
+	case 8:
+#line 1186 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 9:
+#line 1189 "upb/json/parser.rl"
+	{ {stack[top++] = cs; cs = 19; goto _again;} }
+	break;
+	case 10:
+#line 1191 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
+	break;
+	case 11:
+#line 1196 "upb/json/parser.rl"
+	{ start_member(parser); }
+	break;
+	case 12:
+#line 1197 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_membername(parser)); }
+	break;
+	case 13:
+#line 1200 "upb/json/parser.rl"
+	{ end_member(parser); }
+	break;
+	case 14:
+#line 1206 "upb/json/parser.rl"
+	{ start_object(parser); }
+	break;
+	case 15:
+#line 1209 "upb/json/parser.rl"
+	{ end_object(parser); }
+	break;
+	case 16:
+#line 1215 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_array(parser)); }
+	break;
+	case 17:
+#line 1219 "upb/json/parser.rl"
+	{ end_array(parser); }
+	break;
+	case 18:
+#line 1224 "upb/json/parser.rl"
+	{ start_number(parser, p); }
+	break;
+	case 19:
+#line 1225 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_number(parser, p)); }
+	break;
+	case 20:
+#line 1227 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_stringval(parser)); }
+	break;
+	case 21:
+#line 1228 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_stringval(parser)); }
+	break;
+	case 22:
+#line 1230 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
+	break;
+	case 23:
+#line 1232 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
+	break;
+	case 24:
+#line 1234 "upb/json/parser.rl"
+	{ /* null value */ }
+	break;
+	case 25:
+#line 1236 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_subobject(parser)); }
+	break;
+	case 26:
+#line 1237 "upb/json/parser.rl"
+	{ end_subobject(parser); }
+	break;
+	case 27:
+#line 1242 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+#line 1514 "upb/json/parser.c"
+		}
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	_out: {}
+	}
+
+#line 1269 "upb/json/parser.rl"
+
+  if (p != pe) {
+    upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
+    upb_env_reporterror(parser->env, &parser->status);
+  } else {
+    capture_suspend(parser, &p);
+  }
+
+error:
+  /* Save parsing state back to parser. */
+  parser->current_state = cs;
+  parser->parser_top = top;
+
+  return p - buf;
+}
+
+bool end(void *closure, const void *hd) {
+  UPB_UNUSED(closure);
+  UPB_UNUSED(hd);
+
+  /* Prevent compile warning on unused static constants. */
+  UPB_UNUSED(json_start);
+  UPB_UNUSED(json_en_number_machine);
+  UPB_UNUSED(json_en_string_machine);
+  UPB_UNUSED(json_en_value_machine);
+  UPB_UNUSED(json_en_main);
+  return true;
+}
+
+static void json_parser_reset(upb_json_parser *p) {
+  int cs;
+  int top;
+
+  p->top = p->stack;
+  p->top->f = NULL;
+  p->top->is_map = false;
+  p->top->is_mapentry = false;
+
+  /* Emit Ragel initialization of the parser. */
+  
+#line 1568 "upb/json/parser.c"
+	{
+	cs = json_start;
+	top = 0;
+	}
+
+#line 1309 "upb/json/parser.rl"
+  p->current_state = cs;
+  p->parser_top = top;
+  accumulate_clear(p);
+  p->multipart_state = MULTIPART_INACTIVE;
+  p->capture = NULL;
+  p->accumulated = NULL;
+  upb_status_clear(&p->status);
+}
+
+static void visit_json_parsermethod(const upb_refcounted *r,
+                                    upb_refcounted_visit *visit,
+                                    void *closure) {
+  const upb_json_parsermethod *method = (upb_json_parsermethod*)r;
+  visit(r, upb_msgdef_upcast2(method->msg), closure);
+}
+
+static void free_json_parsermethod(upb_refcounted *r) {
+  upb_json_parsermethod *method = (upb_json_parsermethod*)r;
+
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &method->name_tables);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_value val = upb_inttable_iter_value(&i);
+    upb_strtable *t = upb_value_getptr(val);
+    upb_strtable_uninit(t);
+    upb_gfree(t);
+  }
+
+  upb_inttable_uninit(&method->name_tables);
+
+  upb_gfree(r);
+}
+
+static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
+  upb_msg_field_iter i;
+  upb_strtable *t;
+
+  /* It would be nice to stack-allocate this, but protobufs do not limit the
+   * length of fields to any reasonable limit. */
+  char *buf = NULL;
+  size_t len = 0;
+
+  if (upb_inttable_lookupptr(&m->name_tables, md, NULL)) {
+    return;
+  }
+
+  /* TODO(haberman): handle malloc failure. */
+  t = upb_gmalloc(sizeof(*t));
+  upb_strtable_init(t, UPB_CTYPE_CONSTPTR);
+  upb_inttable_insertptr(&m->name_tables, md, upb_value_ptr(t));
+
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+
+    /* Add an entry for the JSON name. */
+    size_t field_len = upb_fielddef_getjsonname(f, buf, len);
+    if (field_len > len) {
+      size_t len2;
+      buf = upb_grealloc(buf, 0, field_len);
+      len = field_len;
+      len2 = upb_fielddef_getjsonname(f, buf, len);
+      UPB_ASSERT_VAR(len2, len == len2);
+    }
+    upb_strtable_insert(t, buf, upb_value_constptr(f));
+
+    if (strcmp(buf, upb_fielddef_name(f)) != 0) {
+      /* Since the JSON name is different from the regular field name, add an
+       * entry for the raw name (compliant proto3 JSON parsers must accept
+       * both). */
+      upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f));
+    }
+
+    if (upb_fielddef_issubmsg(f)) {
+      add_jsonname_table(m, upb_fielddef_msgsubdef(f));
+    }
+  }
+
+  upb_gfree(buf);
+}
+
+/* Public API *****************************************************************/
+
+upb_json_parser *upb_json_parser_create(upb_env *env,
+                                        const upb_json_parsermethod *method,
+                                        upb_sink *output) {
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+  upb_json_parser *p = upb_env_malloc(env, sizeof(upb_json_parser));
+  if (!p) return false;
+
+  p->env = env;
+  p->method = method;
+  p->limit = p->stack + UPB_JSON_MAX_DEPTH;
+  p->accumulate_buf = NULL;
+  p->accumulate_buf_size = 0;
+  upb_bytessink_reset(&p->input_, &method->input_handler_, p);
+
+  json_parser_reset(p);
+  upb_sink_reset(&p->top->sink, output->handlers, output->closure);
+  p->top->m = upb_handlers_msgdef(output->handlers);
+  set_name_table(p, p->top);
+
+  /* If this fails, uncomment and increase the value in parser.h. */
+  /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
+  assert(upb_env_bytesallocated(env) - size_before <= UPB_JSON_PARSER_SIZE);
+  return p;
+}
+
+upb_bytessink *upb_json_parser_input(upb_json_parser *p) {
+  return &p->input_;
+}
+
+upb_json_parsermethod *upb_json_parsermethod_new(const upb_msgdef* md,
+                                                 const void* owner) {
+  static const struct upb_refcounted_vtbl vtbl = {visit_json_parsermethod,
+                                                  free_json_parsermethod};
+  upb_json_parsermethod *ret = upb_gmalloc(sizeof(*ret));
+  upb_refcounted_init(upb_json_parsermethod_upcast_mutable(ret), &vtbl, owner);
+
+  ret->msg = md;
+  upb_ref2(md, ret);
+
+  upb_byteshandler_init(&ret->input_handler_);
+  upb_byteshandler_setstring(&ret->input_handler_, parse, ret);
+  upb_byteshandler_setendstr(&ret->input_handler_, end, ret);
+
+  upb_inttable_init(&ret->name_tables, UPB_CTYPE_PTR);
+
+  add_jsonname_table(ret, md);
+
+  return ret;
+}
+
+const upb_byteshandler *upb_json_parsermethod_inputhandler(
+    const upb_json_parsermethod *m) {
+  return &m->input_handler_;
+}
+/*
+** This currently uses snprintf() to format primitives, and could be optimized
+** further.
+*/
+
+
+#include <string.h>
+#include <stdint.h>
+
+struct upb_json_printer {
+  upb_sink input_;
+  /* BytesSink closure. */
+  void *subc_;
+  upb_bytessink *output_;
+
+  /* We track the depth so that we know when to emit startstr/endstr on the
+   * output. */
+  int depth_;
+
+  /* Have we emitted the first element? This state is necessary to emit commas
+   * without leaving a trailing comma in arrays/maps. We keep this state per
+   * frame depth.
+   *
+   * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages.
+   * We count frames (contexts in which we separate elements by commas) as both
+   * repeated fields and messages (maps), and the worst case is a
+   * message->repeated field->submessage->repeated field->... nesting. */
+  bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2];
+};
+
+/* StringPiece; a pointer plus a length. */
+typedef struct {
+  char *ptr;
+  size_t len;
+} strpc;
+
+void freestrpc(void *ptr) {
+  strpc *pc = ptr;
+  upb_gfree(pc->ptr);
+  upb_gfree(pc);
+}
+
+/* Convert fielddef name to JSON name and return as a string piece. */
+strpc *newstrpc(upb_handlers *h, const upb_fielddef *f,
+                bool preserve_fieldnames) {
+  /* TODO(haberman): handle malloc failure. */
+  strpc *ret = upb_gmalloc(sizeof(*ret));
+  if (preserve_fieldnames) {
+    ret->ptr = upb_gstrdup(upb_fielddef_name(f));
+    ret->len = strlen(ret->ptr);
+  } else {
+    size_t len;
+    ret->len = upb_fielddef_getjsonname(f, NULL, 0);
+    ret->ptr = upb_gmalloc(ret->len);
+    len = upb_fielddef_getjsonname(f, ret->ptr, ret->len);
+    UPB_ASSERT_VAR(len, len == ret->len);
+    ret->len--;  /* NULL */
+  }
+
+  upb_handlers_addcleanup(h, ret, freestrpc);
+  return ret;
+}
+
+/* ------------ JSON string printing: values, maps, arrays ------------------ */
+
+static void print_data(
+    upb_json_printer *p, const char *buf, unsigned int len) {
+  /* TODO: Will need to change if we support pushback from the sink. */
+  size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL);
+  UPB_ASSERT_VAR(n, n == len);
+}
+
+static void print_comma(upb_json_printer *p) {
+  if (!p->first_elem_[p->depth_]) {
+    print_data(p, ",", 1);
+  }
+  p->first_elem_[p->depth_] = false;
+}
+
+/* Helpers that print properly formatted elements to the JSON output stream. */
+
+/* Used for escaping control chars in strings. */
+static const char kControlCharLimit = 0x20;
+
+UPB_INLINE bool is_json_escaped(char c) {
+  /* See RFC 4627. */
+  unsigned char uc = (unsigned char)c;
+  return uc < kControlCharLimit || uc == '"' || uc == '\\';
+}
+
+UPB_INLINE const char* json_nice_escape(char c) {
+  switch (c) {
+    case '"':  return "\\\"";
+    case '\\': return "\\\\";
+    case '\b': return "\\b";
+    case '\f': return "\\f";
+    case '\n': return "\\n";
+    case '\r': return "\\r";
+    case '\t': return "\\t";
+    default:   return NULL;
+  }
+}
+
+/* Write a properly escaped string chunk. The surrounding quotes are *not*
+ * printed; this is so that the caller has the option of emitting the string
+ * content in chunks. */
+static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
+  const char* unescaped_run = NULL;
+  unsigned int i;
+  for (i = 0; i < len; i++) {
+    char c = buf[i];
+    /* Handle escaping. */
+    if (is_json_escaped(c)) {
+      /* Use a "nice" escape, like \n, if one exists for this character. */
+      const char* escape = json_nice_escape(c);
+      /* If we don't have a specific 'nice' escape code, use a \uXXXX-style
+       * escape. */
+      char escape_buf[8];
+      if (!escape) {
+        unsigned char byte = (unsigned char)c;
+        _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte);
+        escape = escape_buf;
+      }
+
+      /* N.B. that we assume that the input encoding is equal to the output
+       * encoding (both UTF-8 for  now), so for chars >= 0x20 and != \, ", we
+       * can simply pass the bytes through. */
+
+      /* If there's a current run of unescaped chars, print that run first. */
+      if (unescaped_run) {
+        print_data(p, unescaped_run, &buf[i] - unescaped_run);
+        unescaped_run = NULL;
+      }
+      /* Then print the escape code. */
+      print_data(p, escape, strlen(escape));
+    } else {
+      /* Add to the current unescaped run of characters. */
+      if (unescaped_run == NULL) {
+        unescaped_run = &buf[i];
+      }
+    }
+  }
+
+  /* If the string ended in a run of unescaped characters, print that last run. */
+  if (unescaped_run) {
+    print_data(p, unescaped_run, &buf[len] - unescaped_run);
+  }
+}
+
+#define CHKLENGTH(x) if (!(x)) return -1;
+
+/* Helpers that format floating point values according to our custom formats.
+ * Right now we use %.8g and %.17g for float/double, respectively, to match
+ * proto2::util::JsonFormat's defaults.  May want to change this later. */
+
+static size_t fmt_double(double val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%.17g", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_float(float val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%.8g", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_bool(bool val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false"));
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_int64(long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%ld", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%llu", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+/* Print a map key given a field name. Called by scalar field handlers and by
+ * startseq for repeated fields. */
+static bool putkey(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  const strpc *key = handler_data;
+  print_comma(p);
+  print_data(p, "\"", 1);
+  putstring(p, key->ptr, key->len);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+#define CHKFMT(val) if ((val) == (size_t)-1) return false;
+#define CHK(val)    if (!(val)) return false;
+
+#define TYPE_HANDLERS(type, fmt_func)                                        \
+  static bool put##type(void *closure, const void *handler_data, type val) { \
+    upb_json_printer *p = closure;                                           \
+    char data[64];                                                           \
+    size_t length = fmt_func(val, data, sizeof(data));                       \
+    UPB_UNUSED(handler_data);                                                \
+    CHKFMT(length);                                                          \
+    print_data(p, data, length);                                             \
+    return true;                                                             \
+  }                                                                          \
+  static bool scalar_##type(void *closure, const void *handler_data,         \
+                            type val) {                                      \
+    CHK(putkey(closure, handler_data));                                      \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }                                                                          \
+  static bool repeated_##type(void *closure, const void *handler_data,       \
+                              type val) {                                    \
+    upb_json_printer *p = closure;                                           \
+    print_comma(p);                                                          \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }
+
+#define TYPE_HANDLERS_MAPKEY(type, fmt_func)                                 \
+  static bool putmapkey_##type(void *closure, const void *handler_data,      \
+                            type val) {                                      \
+    upb_json_printer *p = closure;                                           \
+    print_data(p, "\"", 1);                                                  \
+    CHK(put##type(closure, handler_data, val));                              \
+    print_data(p, "\":", 2);                                                 \
+    return true;                                                             \
+  }
+
+TYPE_HANDLERS(double,   fmt_double)
+TYPE_HANDLERS(float,    fmt_float)
+TYPE_HANDLERS(bool,     fmt_bool)
+TYPE_HANDLERS(int32_t,  fmt_int64)
+TYPE_HANDLERS(uint32_t, fmt_int64)
+TYPE_HANDLERS(int64_t,  fmt_int64)
+TYPE_HANDLERS(uint64_t, fmt_uint64)
+
+/* double and float are not allowed to be map keys. */
+TYPE_HANDLERS_MAPKEY(bool,     fmt_bool)
+TYPE_HANDLERS_MAPKEY(int32_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64)
+TYPE_HANDLERS_MAPKEY(int64_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64)
+
+#undef TYPE_HANDLERS
+#undef TYPE_HANDLERS_MAPKEY
+
+typedef struct {
+  void *keyname;
+  const upb_enumdef *enumdef;
+} EnumHandlerData;
+
+static bool scalar_enum(void *closure, const void *handler_data,
+                        int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  const char *symbolic_name;
+
+  CHK(putkey(closure, hd->keyname));
+
+  symbolic_name = upb_enumdef_iton(hd->enumdef, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(closure, NULL, val);
+  }
+
+  return true;
+}
+
+static void print_enum_symbolic_name(upb_json_printer *p,
+                                     const upb_enumdef *def,
+                                     int32_t val) {
+  const char *symbolic_name = upb_enumdef_iton(def, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(p, NULL, val);
+  }
+}
+
+static bool repeated_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  print_comma(p);
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static bool mapvalue_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static void *scalar_startsubmsg(void *closure, const void *handler_data) {
+  return putkey(closure, handler_data) ? closure : UPB_BREAK;
+}
+
+static void *repeated_startsubmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_comma(p);
+  return closure;
+}
+
+static void start_frame(upb_json_printer *p) {
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+}
+
+static void end_frame(upb_json_printer *p) {
+  print_data(p, "}", 1);
+  p->depth_--;
+}
+
+static bool printer_startmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  if (p->depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc_);
+  }
+  start_frame(p);
+  return true;
+}
+
+static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(s);
+  end_frame(p);
+  if (p->depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+static void *startseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "[", 1);
+  return closure;
+}
+
+static bool endseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "]", 1);
+  p->depth_--;
+  return true;
+}
+
+static void *startmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+  return closure;
+}
+
+static bool endmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "}", 1);
+  p->depth_--;
+  return true;
+}
+
+static size_t putstr(void *closure, const void *handler_data, const char *str,
+                     size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+  putstring(p, str, len);
+  return len;
+}
+
+/* This has to Base64 encode the bytes, because JSON has no "bytes" type. */
+static size_t putbytes(void *closure, const void *handler_data, const char *str,
+                       size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+
+  /* This is the regular base64, not the "web-safe" version. */
+  static const char base64[] =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /* Base64-encode. */
+  char data[16000];
+  const char *limit = data + sizeof(data);
+  const unsigned char *from = (const unsigned char*)str;
+  char *to = data;
+  size_t remaining = len;
+  size_t bytes;
+
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+
+  while (remaining > 2) {
+    /* TODO(haberman): handle encoded lengths > sizeof(data) */
+    UPB_ASSERT_VAR(limit, (limit - to) >= 4);
+
+    to[0] = base64[from[0] >> 2];
+    to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+    to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)];
+    to[3] = base64[from[2] & 0x3f];
+
+    remaining -= 3;
+    to += 4;
+    from += 3;
+  }
+
+  switch (remaining) {
+    case 2:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+      to[2] = base64[(from[1] & 0xf) << 2];
+      to[3] = '=';
+      to += 4;
+      from += 2;
+      break;
+    case 1:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4)];
+      to[2] = '=';
+      to[3] = '=';
+      to += 4;
+      from += 1;
+      break;
+  }
+
+  bytes = to - data;
+  print_data(p, "\"", 1);
+  putstring(p, data, bytes);
+  print_data(p, "\"", 1);
+  return len;
+}
+
+static void *scalar_startstr(void *closure, const void *handler_data,
+                             size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  CHK(putkey(closure, handler_data));
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t scalar_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool scalar_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *repeated_startstr(void *closure, const void *handler_data,
+                               size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_comma(p);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t repeated_str(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool repeated_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *mapkeyval_startstr(void *closure, const void *handler_data,
+                                size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t mapkey_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool mapkey_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+static bool mapvalue_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static size_t scalar_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putkey(closure, handler_data));
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t repeated_bytes(void *closure, const void *handler_data,
+                             const char *str, size_t len,
+                             const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  print_comma(p);
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t mapkey_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  print_data(p, ":", 1);
+  return len;
+}
+
+static void set_enum_hd(upb_handlers *h,
+                        const upb_fielddef *f,
+                        bool preserve_fieldnames,
+                        upb_handlerattr *attr) {
+  EnumHandlerData *hd = upb_gmalloc(sizeof(EnumHandlerData));
+  hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f);
+  hd->keyname = newstrpc(h, f, preserve_fieldnames);
+  upb_handlers_addcleanup(h, hd, upb_gfree);
+  upb_handlerattr_sethandlerdata(attr, hd);
+}
+
+/* Set up handlers for a mapentry submessage (i.e., an individual key/value pair
+ * in a map).
+ *
+ * TODO: Handle missing key, missing value, out-of-order key/value, or repeated
+ * key or value cases properly. The right way to do this is to allocate a
+ * temporary structure at the start of a mapentry submessage, store key and
+ * value data in it as key and value handlers are called, and then print the
+ * key/value pair once at the end of the submessage. If we don't do this, we
+ * should at least detect the case and throw an error. However, so far all of
+ * our sources that emit mapentry messages do so canonically (with one key
+ * field, and then one value field), so this is not a pressing concern at the
+ * moment. */
+void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames,
+                                  upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+
+  /* A mapentry message is printed simply as '"key": value'. Rather than
+   * special-case key and value for every type below, we just handle both
+   * fields explicitly here. */
+  const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY);
+  const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE);
+
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+
+  UPB_UNUSED(closure);
+
+  switch (upb_fielddef_type(key_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr);
+      upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr);
+      break;
+    default:
+      assert(false);
+      break;
+  }
+
+  switch (upb_fielddef_type(value_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, value_field, putint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, value_field, putint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, value_field, putbool, &empty_attr);
+      break;
+    case UPB_TYPE_FLOAT:
+      upb_handlers_setfloat(h, value_field, putfloat, &empty_attr);
+      break;
+    case UPB_TYPE_DOUBLE:
+      upb_handlers_setdouble(h, value_field, putdouble, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, value_field, putstr, &empty_attr);
+      upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, value_field, putbytes, &empty_attr);
+      break;
+    case UPB_TYPE_ENUM: {
+      upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+      set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr);
+      upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr);
+      upb_handlerattr_uninit(&enum_attr);
+      break;
+    }
+    case UPB_TYPE_MESSAGE:
+      /* No handler necessary -- the submsg handlers will print the message
+       * as appropriate. */
+      break;
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+}
+
+void printer_sethandlers(const void *closure, upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+  bool is_mapentry = upb_msgdef_mapentry(md);
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_msg_field_iter i;
+  const bool *preserve_fieldnames_ptr = closure;
+  const bool preserve_fieldnames = *preserve_fieldnames_ptr;
+
+  if (is_mapentry) {
+    /* mapentry messages are sufficiently different that we handle them
+     * separately. */
+    printer_sethandlers_mapentry(closure, preserve_fieldnames, h);
+    return;
+  }
+
+  upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr);
+  upb_handlers_setendmsg(h, printer_endmsg, &empty_attr);
+
+#define TYPE(type, name, ctype)                                               \
+  case type:                                                                  \
+    if (upb_fielddef_isseq(f)) {                                              \
+      upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr);            \
+    } else {                                                                  \
+      upb_handlers_set##name(h, f, scalar_##ctype, &name_attr);               \
+    }                                                                         \
+    break;
+
+  upb_msg_field_begin(&i, md);
+  for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+
+    upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&name_attr,
+                                   newstrpc(h, f, preserve_fieldnames));
+
+    if (upb_fielddef_ismap(f)) {
+      upb_handlers_setstartseq(h, f, startmap, &name_attr);
+      upb_handlers_setendseq(h, f, endmap, &name_attr);
+    } else if (upb_fielddef_isseq(f)) {
+      upb_handlers_setstartseq(h, f, startseq, &name_attr);
+      upb_handlers_setendseq(h, f, endseq, &empty_attr);
+    }
+
+    switch (upb_fielddef_type(f)) {
+      TYPE(UPB_TYPE_FLOAT,  float,  float);
+      TYPE(UPB_TYPE_DOUBLE, double, double);
+      TYPE(UPB_TYPE_BOOL,   bool,   bool);
+      TYPE(UPB_TYPE_INT32,  int32,  int32_t);
+      TYPE(UPB_TYPE_UINT32, uint32, uint32_t);
+      TYPE(UPB_TYPE_INT64,  int64,  int64_t);
+      TYPE(UPB_TYPE_UINT64, uint64, uint64_t);
+      case UPB_TYPE_ENUM: {
+        /* For now, we always emit symbolic names for enums. We may want an
+         * option later to control this behavior, but we will wait for a real
+         * need first. */
+        upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+        set_enum_hd(h, f, preserve_fieldnames, &enum_attr);
+
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setint32(h, f, repeated_enum, &enum_attr);
+        } else {
+          upb_handlers_setint32(h, f, scalar_enum, &enum_attr);
+        }
+
+        upb_handlerattr_uninit(&enum_attr);
+        break;
+      }
+      case UPB_TYPE_STRING:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr);
+          upb_handlers_setstring(h, f, repeated_str, &empty_attr);
+          upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr);
+        } else {
+          upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr);
+          upb_handlers_setstring(h, f, scalar_str, &empty_attr);
+          upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr);
+        }
+        break;
+      case UPB_TYPE_BYTES:
+        /* XXX: this doesn't support strings that span buffers yet. The base64
+         * encoder will need to be made resumable for this to work properly. */
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstring(h, f, repeated_bytes, &empty_attr);
+        } else {
+          upb_handlers_setstring(h, f, scalar_bytes, &name_attr);
+        }
+        break;
+      case UPB_TYPE_MESSAGE:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr);
+        } else {
+          upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr);
+        }
+        break;
+    }
+
+    upb_handlerattr_uninit(&name_attr);
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+#undef TYPE
+}
+
+static void json_printer_reset(upb_json_printer *p) {
+  p->depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output) {
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  json_printer_reset(p);
+  upb_sink_reset(&p->input_, h, p);
+
+  /* If this fails, increase the value in printer.h. */
+  assert(upb_env_bytesallocated(e) - size_before <= UPB_JSON_PRINTER_SIZE);
+  return p;
+}
+
+upb_sink *upb_json_printer_input(upb_json_printer *p) {
+  return &p->input_;
+}
+
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 bool preserve_fieldnames,
+                                                 const void *owner) {
+  return upb_handlers_newfrozen(
+      md, owner, printer_sethandlers, &preserve_fieldnames);
+}
diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h
new file mode 100644
index 0000000..2faf74e
--- /dev/null
+++ b/ruby/ext/google/protobuf_c/upb.h
@@ -0,0 +1,8569 @@
+// Amalgamated source file
+/*
+** Defs are upb's internal representation of the constructs that can appear
+** in a .proto file:
+**
+** - upb::MessageDef (upb_msgdef): describes a "message" construct.
+** - upb::FieldDef (upb_fielddef): describes a message field.
+** - upb::FileDef (upb_filedef): describes a .proto file and its defs.
+** - upb::EnumDef (upb_enumdef): describes an enum.
+** - upb::OneofDef (upb_oneofdef): describes a oneof.
+** - upb::Def (upb_def): base class of all the others.
+**
+** TODO: definitions of services.
+**
+** Like upb_refcounted objects, defs are mutable only until frozen, and are
+** only thread-safe once frozen.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_DEF_H_
+#define UPB_DEF_H_
+
+/*
+** upb::RefCounted (upb_refcounted)
+**
+** A refcounting scheme that supports circular refs.  It accomplishes this by
+** partitioning the set of objects into groups such that no cycle spans groups;
+** we can then reference-count the group as a whole and ignore refs within the
+** group.  When objects are mutable, these groups are computed very
+** conservatively; we group any objects that have ever had a link between them.
+** When objects are frozen, we compute strongly-connected components which
+** allows us to be precise and only group objects that are actually cyclic.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_REFCOUNTED_H_
+#define UPB_REFCOUNTED_H_
+
+/*
+** upb_table
+**
+** This header is INTERNAL-ONLY!  Its interfaces are not public or stable!
+** This file defines very fast int->upb_value (inttable) and string->upb_value
+** (strtable) hash tables.
+**
+** The table uses chained scatter with Brent's variation (inspired by the Lua
+** implementation of hash tables).  The hash function for strings is Austin
+** Appleby's "MurmurHash."
+**
+** The inttable uses uintptr_t as its key, which guarantees it can be used to
+** store pointers or integers of at least 32 bits (upb isn't really useful on
+** systems where sizeof(void*) < 4).
+**
+** The table must be homogenous (all values of the same type).  In debug
+** mode, we check this on insert and lookup.
+*/
+
+#ifndef UPB_TABLE_H_
+#define UPB_TABLE_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+/*
+** This file contains shared definitions that are widely used across upb.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_H_
+#define UPB_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+namespace upb {
+class Allocator;
+class Arena;
+class Environment;
+class ErrorSpace;
+class Status;
+template <int N> class InlinedArena;
+template <int N> class InlinedEnvironment;
+}
+#endif
+
+/* UPB_INLINE: inline if possible, emit standalone code if required. */
+#ifdef __cplusplus
+#define UPB_INLINE inline
+#elif defined (__GNUC__)
+#define UPB_INLINE static __inline__
+#else
+#define UPB_INLINE static
+#endif
+
+/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler
+ * doesn't provide these preprocessor symbols. */
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define UPB_BIG_ENDIAN
+#endif
+
+/* Macros for function attributes on compilers that support them. */
+#ifdef __GNUC__
+#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
+#define UPB_NOINLINE __attribute__((noinline))
+#define UPB_NORETURN __attribute__((__noreturn__))
+#else  /* !defined(__GNUC__) */
+#define UPB_FORCEINLINE
+#define UPB_NOINLINE
+#define UPB_NORETURN
+#endif
+
+/* A few hacky workarounds for functions not in C89.
+ * For internal use only!
+ * TODO(haberman): fix these by including our own implementations, or finding
+ * another workaround.
+ */
+#ifdef __GNUC__
+#define _upb_snprintf __builtin_snprintf
+#define _upb_vsnprintf __builtin_vsnprintf
+#define _upb_va_copy(a, b) __va_copy(a, b)
+#elif __STDC_VERSION__ >= 199901L
+/* C99 versions. */
+#define _upb_snprintf snprintf
+#define _upb_vsnprintf vsnprintf
+#define _upb_va_copy(a, b) va_copy(a, b)
+#else
+#error Need implementations of [v]snprintf and va_copy
+#endif
+
+
+#if ((defined(__cplusplus) && __cplusplus >= 201103L) || \
+      defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11)
+#define UPB_CXX11
+#endif
+
+/* UPB_DISALLOW_COPY_AND_ASSIGN()
+ * UPB_DISALLOW_POD_OPS()
+ *
+ * Declare these in the "private" section of a C++ class to forbid copy/assign
+ * or all POD ops (construct, destruct, copy, assign) on that class. */
+#ifdef UPB_CXX11
+#include <type_traits>
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&) = delete; \
+  void operator=(const class_name&) = delete;
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name() = delete; \
+  ~class_name() = delete; \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type) \
+  static_assert(std::is_standard_layout<type>::value, \
+                #type " must be standard layout");
+#define UPB_FINAL final
+#else  /* !defined(UPB_CXX11) */
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&); \
+  void operator=(const class_name&);
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name(); \
+  ~class_name(); \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type)
+#define UPB_FINAL
+#endif
+
+/* UPB_DECLARE_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE2()
+ *
+ * Macros for declaring C and C++ types both, including inheritance.
+ * The inheritance doesn't use real C++ inheritance, to stay compatible with C.
+ *
+ * These macros also provide upcasts:
+ *  - in C: types-specific functions (ie. upb_foo_upcast(foo))
+ *  - in C++: upb::upcast(foo) along with implicit conversions
+ *
+ * Downcasts are not provided, but upb/def.h defines downcasts for upb::Def. */
+
+#define UPB_C_UPCASTS(ty, base)                                      \
+  UPB_INLINE base *ty ## _upcast_mutable(ty *p) { return (base*)p; } \
+  UPB_INLINE const base *ty ## _upcast(const ty *p) { return (const base*)p; }
+
+#define UPB_C_UPCASTS2(ty, base, base2)                                 \
+  UPB_C_UPCASTS(ty, base)                                               \
+  UPB_INLINE base2 *ty ## _upcast2_mutable(ty *p) { return (base2*)p; } \
+  UPB_INLINE const base2 *ty ## _upcast2(const ty *p) { return (const base2*)p; }
+
+#ifdef __cplusplus
+
+#define UPB_BEGIN_EXTERN_C extern "C" {
+#define UPB_END_EXTERN_C }
+#define UPB_PRIVATE_FOR_CPP private:
+#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname;
+
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase)  \
+  UPB_DECLARE_TYPE(cppname, cname)                                \
+  UPB_C_UPCASTS(cname, cbase)                                     \
+  namespace upb {                                                 \
+  template <>                                                     \
+  class Pointer<cppname> : public PointerBase<cppname, cppbase> { \
+   public:                                                        \
+    explicit Pointer(cppname* ptr)                                \
+        : PointerBase<cppname, cppbase>(ptr) {}                   \
+  };                                                              \
+  template <>                                                     \
+  class Pointer<const cppname>                                    \
+      : public PointerBase<const cppname, const cppbase> {        \
+   public:                                                        \
+    explicit Pointer(const cppname* ptr)                          \
+        : PointerBase<const cppname, const cppbase>(ptr) {}       \
+  };                                                              \
+  }
+
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, cname, cbase,  \
+                                  cbase2)                                    \
+  UPB_DECLARE_TYPE(cppname, cname)                                           \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)                                       \
+  namespace upb {                                                            \
+  template <>                                                                \
+  class Pointer<cppname> : public PointerBase2<cppname, cppbase, cppbase2> { \
+   public:                                                                   \
+    explicit Pointer(cppname* ptr)                                           \
+        : PointerBase2<cppname, cppbase, cppbase2>(ptr) {}                   \
+  };                                                                         \
+  template <>                                                                \
+  class Pointer<const cppname>                                               \
+      : public PointerBase2<const cppname, const cppbase, const cppbase2> {  \
+   public:                                                                   \
+    explicit Pointer(const cppname* ptr)                                     \
+        : PointerBase2<const cppname, const cppbase, const cppbase2>(ptr) {} \
+  };                                                                         \
+  }
+
+#else  /* !defined(__cplusplus) */
+
+#define UPB_BEGIN_EXTERN_C
+#define UPB_END_EXTERN_C
+#define UPB_PRIVATE_FOR_CPP
+#define UPB_DECLARE_TYPE(cppname, cname) \
+  struct cname;                          \
+  typedef struct cname cname;
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS(cname, cbase)
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2,    \
+                                  cname, cbase, cbase2)          \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)
+
+#endif  /* defined(__cplusplus) */
+
+#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define UPB_UNUSED(var) (void)var
+
+/* For asserting something about a variable when the variable is not used for
+ * anything else.  This prevents "unused variable" warnings when compiling in
+ * debug mode. */
+#define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate)
+
+/* Generic function type. */
+typedef void upb_func();
+
+
+/* C++ Casts ******************************************************************/
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> class Pointer;
+
+/* Casts to a subclass.  The caller must know that cast is correct; an
+ * incorrect cast will throw an assertion failure in debug mode.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // Assert-fails if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that downcasts are only defined for some types (at the moment you can
+ * only downcast from a upb::Def to a specific Def type). */
+template<class To, class From> To down_cast(From* f);
+
+/* Casts to a subclass.  If the class does not actually match the given To type,
+ * returns NULL.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // md will be NULL if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that dynamic casts are only defined for some types (at the moment you
+ * can only downcast from a upb::Def to a specific Def type).. */
+template<class To, class From> To dyn_cast(From* f);
+
+/* Casts to any base class, or the type itself (ie. can be a no-op).
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   // This will fail to compile if this wasn't actually a base class.
+ *   upb::Def* def = upb::upcast(md);
+ */
+template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
+
+/* Attempt upcast to specific base class.
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   upb::upcast_to<upb::Def>(md)->MethodOnDef();
+ */
+template <class T, class F> inline T* upcast_to(F *f) {
+  return static_cast<T*>(upcast(f));
+}
+
+/* PointerBase<T>: implementation detail of upb::upcast().
+ * It is implicitly convertable to pointers to the Base class(es).
+ */
+template <class T, class Base>
+class PointerBase {
+ public:
+  explicit PointerBase(T* ptr) : ptr_(ptr) {}
+  operator T*() { return ptr_; }
+  operator Base*() { return (Base*)ptr_; }
+
+ private:
+  T* ptr_;
+};
+
+template <class T, class Base, class Base2>
+class PointerBase2 : public PointerBase<T, Base> {
+ public:
+  explicit PointerBase2(T* ptr) : PointerBase<T, Base>(ptr) {}
+  operator Base2*() { return Pointer<Base>(*this); }
+};
+
+}
+
+#endif
+
+
+/* upb::ErrorSpace ************************************************************/
+
+/* A upb::ErrorSpace represents some domain of possible error values.  This lets
+ * upb::Status attach specific error codes to operations, like POSIX/C errno,
+ * Win32 error codes, etc.  Clients who want to know the very specific error
+ * code can check the error space and then know the type of the integer code.
+ *
+ * NOTE: upb::ErrorSpace is currently not used and should be considered
+ * experimental.  It is important primarily in cases where upb is performing
+ * I/O, but upb doesn't currently have any components that do this. */
+
+UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace)
+
+#ifdef __cplusplus
+class upb::ErrorSpace {
+#else
+struct upb_errorspace {
+#endif
+  const char *name;
+};
+
+
+/* upb::Status ****************************************************************/
+
+/* upb::Status represents a success or failure status and error message.
+ * It owns no resources and allocates no memory, so it should work
+ * even in OOM situations. */
+UPB_DECLARE_TYPE(upb::Status, upb_status)
+
+/* The maximum length of an error message before it will get truncated. */
+#define UPB_STATUS_MAX_MESSAGE 128
+
+UPB_BEGIN_EXTERN_C
+
+const char *upb_status_errmsg(const upb_status *status);
+bool upb_ok(const upb_status *status);
+upb_errorspace *upb_status_errspace(const upb_status *status);
+int upb_status_errcode(const upb_status *status);
+
+/* Any of the functions that write to a status object allow status to be NULL,
+ * to support use cases where the function's caller does not care about the
+ * status message. */
+void upb_status_clear(upb_status *status);
+void upb_status_seterrmsg(upb_status *status, const char *msg);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_copy(upb_status *to, const upb_status *from);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Status {
+ public:
+  Status() { upb_status_clear(this); }
+
+  /* Returns true if there is no error. */
+  bool ok() const { return upb_ok(this); }
+
+  /* Optional error space and code, useful if the caller wants to
+   * programmatically check the specific kind of error. */
+  ErrorSpace* error_space() { return upb_status_errspace(this); }
+  int error_code() const { return upb_status_errcode(this); }
+
+  /* The returned string is invalidated by any other call into the status. */
+  const char *error_message() const { return upb_status_errmsg(this); }
+
+  /* The error message will be truncated if it is longer than
+   * UPB_STATUS_MAX_MESSAGE-4. */
+  void SetErrorMessage(const char* msg) { upb_status_seterrmsg(this, msg); }
+  void SetFormattedErrorMessage(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    upb_status_vseterrf(this, fmt, args);
+    va_end(args);
+  }
+
+  /* Resets the status to a successful state with no message. */
+  void Clear() { upb_status_clear(this); }
+
+  void CopyFrom(const Status& other) { upb_status_copy(this, &other); }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Status)
+#else
+struct upb_status {
+#endif
+  bool ok_;
+
+  /* Specific status code defined by some error space (optional). */
+  int code_;
+  upb_errorspace *error_space_;
+
+  /* TODO(haberman): add file/line of error? */
+
+  /* Error message; NULL-terminated. */
+  char msg[UPB_STATUS_MAX_MESSAGE];
+};
+
+#define UPB_STATUS_INIT {true, 0, NULL, {0}}
+
+
+/** Built-in error spaces. ****************************************************/
+
+/* Errors raised by upb that we want to be able to detect programmatically. */
+typedef enum {
+  UPB_NOMEM   /* Can't reuse ENOMEM because it is POSIX, not ISO C. */
+} upb_errcode_t;
+
+extern upb_errorspace upb_upberr;
+
+void upb_upberr_setoom(upb_status *s);
+
+/* Since errno is defined by standard C, we define an error space for it in
+ * core upb.  Other error spaces should be defined in other, platform-specific
+ * modules. */
+
+extern upb_errorspace upb_errnoerr;
+
+
+/** upb::Allocator ************************************************************/
+
+/* A upb::Allocator is a possibly-stateful allocator object.
+ *
+ * It could either be an arena allocator (which doesn't require individual
+ * free() calls) or a regular malloc() (which does).  The client must therefore
+ * free memory unless it knows that the allocator is an arena allocator. */
+UPB_DECLARE_TYPE(upb::Allocator, upb_alloc)
+
+/* A malloc()/free() function.
+ * If "size" is 0 then the function acts like free(), otherwise it acts like
+ * realloc().  Only "oldsize" bytes from a previous allocation are preserved. */
+typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize,
+                             size_t size);
+
+#ifdef __cplusplus
+
+class upb::Allocator UPB_FINAL {
+ public:
+  Allocator() {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Allocator)
+
+ public:
+#else
+struct upb_alloc {
+#endif  /* __cplusplus */
+  upb_alloc_func *func;
+};
+
+UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) {
+  assert(size > 0);
+  return alloc->func(alloc, NULL, 0, size);
+}
+
+UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                             size_t size) {
+  assert(size > 0);
+  return alloc->func(alloc, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) {
+  alloc->func(alloc, ptr, 0, 0);
+}
+
+/* The global allocator used by upb.  Uses the standard malloc()/free(). */
+
+extern upb_alloc upb_alloc_global;
+
+/* Functions that hard-code the global malloc.
+ *
+ * We still get benefit because we can put custom logic into our global
+ * allocator, like injecting out-of-memory faults in debug/testing builds. */
+
+UPB_INLINE void *upb_gmalloc(size_t size) {
+  return upb_malloc(&upb_alloc_global, size);
+}
+
+UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) {
+  return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_gfree(void *ptr) {
+  upb_free(&upb_alloc_global, ptr);
+}
+
+/* upb::Arena *****************************************************************/
+
+/* upb::Arena is a specific allocator implementation that uses arena allocation.
+ * The user provides an allocator that will be used to allocate the underlying
+ * arena blocks.  Arenas by nature do not require the individual allocations
+ * to be freed.  However the Arena does allow users to register cleanup
+ * functions that will run when the arena is destroyed.
+ *
+ * A upb::Arena is *not* thread-safe.
+ *
+ * You could write a thread-safe arena allocator that satisfies the
+ * upb::Allocator interface, but it would not be as efficient for the
+ * single-threaded case. */
+UPB_DECLARE_TYPE(upb::Arena, upb_arena)
+
+typedef void upb_cleanup_func(void *ud);
+
+#define UPB_ARENA_BLOCK_OVERHEAD (sizeof(size_t)*4)
+
+UPB_BEGIN_EXTERN_C
+
+void upb_arena_init(upb_arena *a);
+void upb_arena_init2(upb_arena *a, void *mem, size_t n, upb_alloc *alloc);
+void upb_arena_uninit(upb_arena *a);
+upb_alloc *upb_arena_alloc(upb_arena *a);
+bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud);
+size_t upb_arena_bytesallocated(const upb_arena *a);
+void upb_arena_setnextblocksize(upb_arena *a, size_t size);
+void upb_arena_setmaxblocksize(upb_arena *a, size_t size);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Arena {
+ public:
+  /* A simple arena with no initial memory block and the default allocator. */
+  Arena() { upb_arena_init(this); }
+
+  /* Constructs an arena with the given initial block which allocates blocks
+   * with the given allocator.  The given allocator must outlive the Arena.
+   *
+   * If you pass NULL for the allocator it will default to the global allocator
+   * upb_alloc_global, and NULL/0 for the initial block will cause there to be
+   * no initial block. */
+  Arena(void *mem, size_t len, Allocator* a) {
+    upb_arena_init2(this, mem, len, a);
+  }
+
+  ~Arena() { upb_arena_uninit(this); }
+
+  /* Sets the size of the next block the Arena will request (unless the
+   * requested allocation is larger).  Each block will double in size until the
+   * max limit is reached. */
+  void SetNextBlockSize(size_t size) { upb_arena_setnextblocksize(this, size); }
+
+  /* Sets the maximum block size.  No blocks larger than this will be requested
+   * from the underlying allocator unless individual arena allocations are
+   * larger. */
+  void SetMaxBlockSize(size_t size) { upb_arena_setmaxblocksize(this, size); }
+
+  /* Allows this arena to be used as a generic allocator.
+   *
+   * The arena does not need free() calls so when using Arena as an allocator
+   * it is safe to skip them.  However they are no-ops so there is no harm in
+   * calling free() either. */
+  Allocator* allocator() { return upb_arena_alloc(this); }
+
+  /* Add a cleanup function to run when the arena is destroyed.
+   * Returns false on out-of-memory. */
+  bool AddCleanup(upb_cleanup_func* func, void* ud) {
+    return upb_arena_addcleanup(this, func, ud);
+  }
+
+  /* Total number of bytes that have been allocated.  It is undefined what
+   * Realloc() does to this counter. */
+  size_t BytesAllocated() const {
+    return upb_arena_bytesallocated(this);
+  }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Arena)
+
+#else
+struct upb_arena {
+#endif  /* __cplusplus */
+  /* We implement the allocator interface.
+   * This must be the first member of upb_arena! */
+  upb_alloc alloc;
+
+  /* Allocator to allocate arena blocks.  We are responsible for freeing these
+   * when we are destroyed. */
+  upb_alloc *block_alloc;
+
+  size_t bytes_allocated;
+  size_t next_block_size;
+  size_t max_block_size;
+
+  /* Linked list of blocks.  Points to an arena_block, defined in env.c */
+  void *block_head;
+
+  /* Cleanup entries.  Pointer to a cleanup_ent, defined in env.c */
+  void *cleanup_head;
+
+  /* For future expansion, since the size of this struct is exposed to users. */
+  void *future1;
+  void *future2;
+};
+
+
+/* upb::Environment ***********************************************************/
+
+/* A upb::Environment provides a means for injecting malloc and an
+ * error-reporting callback into encoders/decoders.  This allows them to be
+ * independent of nearly all assumptions about their actual environment.
+ *
+ * It is also a container for allocating the encoders/decoders themselves that
+ * insulates clients from knowing their actual size.  This provides ABI
+ * compatibility even if the size of the objects change.  And this allows the
+ * structure definitions to be in the .c files instead of the .h files, making
+ * the .h files smaller and more readable.
+ *
+ * We might want to consider renaming this to "Pipeline" if/when the concept of
+ * a pipeline element becomes more formalized. */
+UPB_DECLARE_TYPE(upb::Environment, upb_env)
+
+/* A function that receives an error report from an encoder or decoder.  The
+ * callback can return true to request that the error should be recovered, but
+ * if the error is not recoverable this has no effect. */
+typedef bool upb_error_func(void *ud, const upb_status *status);
+
+UPB_BEGIN_EXTERN_C
+
+void upb_env_init(upb_env *e);
+void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc);
+void upb_env_uninit(upb_env *e);
+
+void upb_env_initonly(upb_env *e);
+
+upb_arena *upb_env_arena(upb_env *e);
+bool upb_env_ok(const upb_env *e);
+void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud);
+
+/* Convenience wrappers around the methods of the contained arena. */
+void upb_env_reporterrorsto(upb_env *e, upb_status *s);
+bool upb_env_reporterror(upb_env *e, const upb_status *s);
+void *upb_env_malloc(upb_env *e, size_t size);
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size);
+void upb_env_free(upb_env *e, void *ptr);
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud);
+size_t upb_env_bytesallocated(const upb_env *e);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Environment {
+ public:
+  /* The given Arena must outlive this environment. */
+  Environment() { upb_env_initonly(this); }
+
+  Environment(void *mem, size_t len, Allocator *a) : arena_(mem, len, a) {
+    upb_env_initonly(this);
+  }
+
+  Arena* arena() { return upb_env_arena(this); }
+
+  /* Set a custom error reporting function. */
+  void SetErrorFunction(upb_error_func* func, void* ud) {
+    upb_env_seterrorfunc(this, func, ud);
+  }
+
+  /* Set the error reporting function to simply copy the status to the given
+   * status and abort. */
+  void ReportErrorsTo(Status* status) { upb_env_reporterrorsto(this, status); }
+
+  /* Returns true if all allocations and AddCleanup() calls have succeeded,
+   * and no errors were reported with ReportError() (except ones that recovered
+   * successfully). */
+  bool ok() const { return upb_env_ok(this); }
+
+  /* Reports an error to this environment's callback, returning true if
+   * the caller should try to recover. */
+  bool ReportError(const Status* status) {
+    return upb_env_reporterror(this, status);
+  }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Environment)
+
+#else
+struct upb_env {
+#endif  /* __cplusplus */
+  upb_arena arena_;
+  upb_error_func *error_func_;
+  void *error_ud_;
+  bool ok_;
+};
+
+
+/* upb::InlinedArena **********************************************************/
+/* upb::InlinedEnvironment ****************************************************/
+
+/* upb::InlinedArena and upb::InlinedEnvironment seed their arenas with a
+ * predefined amount of memory.  No heap memory will be allocated until the
+ * initial block is exceeded.
+ *
+ * These types only exist in C++ */
+
+#ifdef __cplusplus
+
+template <int N> class upb::InlinedArena : public upb::Arena {
+ public:
+  InlinedArena() : Arena(initial_block_, N, NULL) {}
+  explicit InlinedArena(Allocator* a) : Arena(initial_block_, N, a) {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(InlinedArena)
+
+  char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD];
+};
+
+template <int N> class upb::InlinedEnvironment : public upb::Environment {
+ public:
+  InlinedEnvironment() : Environment(initial_block_, N, NULL) {}
+  explicit InlinedEnvironment(Allocator *a)
+      : Environment(initial_block_, N, a) {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(InlinedEnvironment)
+
+  char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD];
+};
+
+#endif  /* __cplusplus */
+
+
+
+#endif  /* UPB_H_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* upb_value ******************************************************************/
+
+/* A tagged union (stored untagged inside the table) so that we can check that
+ * clients calling table accessors are correctly typed without having to have
+ * an explosion of accessors. */
+typedef enum {
+  UPB_CTYPE_INT32    = 1,
+  UPB_CTYPE_INT64    = 2,
+  UPB_CTYPE_UINT32   = 3,
+  UPB_CTYPE_UINT64   = 4,
+  UPB_CTYPE_BOOL     = 5,
+  UPB_CTYPE_CSTR     = 6,
+  UPB_CTYPE_PTR      = 7,
+  UPB_CTYPE_CONSTPTR = 8,
+  UPB_CTYPE_FPTR     = 9
+} upb_ctype_t;
+
+typedef struct {
+  uint64_t val;
+#ifndef NDEBUG
+  /* In debug mode we carry the value type around also so we can check accesses
+   * to be sure the right member is being read. */
+  upb_ctype_t ctype;
+#endif
+} upb_value;
+
+#ifdef NDEBUG
+#define SET_TYPE(dest, val)      UPB_UNUSED(val)
+#else
+#define SET_TYPE(dest, val) dest = val
+#endif
+
+/* Like strdup(), which isn't always available since it's not ANSI C. */
+char *upb_strdup(const char *s, upb_alloc *a);
+/* Variant that works with a length-delimited rather than NULL-delimited string,
+ * as supported by strtable. */
+char *upb_strdup2(const char *s, size_t len, upb_alloc *a);
+
+UPB_INLINE char *upb_gstrdup(const char *s) {
+  return upb_strdup(s, &upb_alloc_global);
+}
+
+UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val,
+                                  upb_ctype_t ctype) {
+  v->val = val;
+  SET_TYPE(v->ctype, ctype);
+}
+
+UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) {
+  upb_value ret;
+  _upb_value_setval(&ret, val, ctype);
+  return ret;
+}
+
+/* For each value ctype, define the following set of functions:
+ *
+ * // Get/set an int32 from a upb_value.
+ * int32_t upb_value_getint32(upb_value val);
+ * void upb_value_setint32(upb_value *val, int32_t cval);
+ *
+ * // Construct a new upb_value from an int32.
+ * upb_value upb_value_int32(int32_t val); */
+#define FUNCS(name, membername, type_t, converter, proto_type) \
+  UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \
+    val->val = (converter)cval; \
+    SET_TYPE(val->ctype, proto_type); \
+  } \
+  UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
+    upb_value ret; \
+    upb_value_set ## name(&ret, val); \
+    return ret; \
+  } \
+  UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
+    assert(val.ctype == proto_type); \
+    return (type_t)(converter)val.val; \
+  }
+
+FUNCS(int32,    int32,        int32_t,      int32_t,    UPB_CTYPE_INT32)
+FUNCS(int64,    int64,        int64_t,      int64_t,    UPB_CTYPE_INT64)
+FUNCS(uint32,   uint32,       uint32_t,     uint32_t,   UPB_CTYPE_UINT32)
+FUNCS(uint64,   uint64,       uint64_t,     uint64_t,   UPB_CTYPE_UINT64)
+FUNCS(bool,     _bool,        bool,         bool,       UPB_CTYPE_BOOL)
+FUNCS(cstr,     cstr,         char*,        uintptr_t,  UPB_CTYPE_CSTR)
+FUNCS(ptr,      ptr,          void*,        uintptr_t,  UPB_CTYPE_PTR)
+FUNCS(constptr, constptr,     const void*,  uintptr_t,  UPB_CTYPE_CONSTPTR)
+FUNCS(fptr,     fptr,         upb_func*,    uintptr_t,  UPB_CTYPE_FPTR)
+
+#undef FUNCS
+#undef SET_TYPE
+
+
+/* upb_tabkey *****************************************************************/
+
+/* Either:
+ *   1. an actual integer key, or
+ *   2. a pointer to a string prefixed by its uint32_t length, owned by us.
+ *
+ * ...depending on whether this is a string table or an int table.  We would
+ * make this a union of those two types, but C89 doesn't support statically
+ * initializing a non-first union member. */
+typedef uintptr_t upb_tabkey;
+
+#define UPB_TABKEY_NUM(n) n
+#define UPB_TABKEY_NONE 0
+/* The preprocessor isn't quite powerful enough to turn the compile-time string
+ * length into a byte-wise string representation, so code generation needs to
+ * help it along.
+ *
+ * "len1" is the low byte and len4 is the high byte. */
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len4 len3 len2 len1 strval)
+#else
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len1 len2 len3 len4 strval)
+#endif
+
+UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
+  char* mem = (char*)key;
+  if (len) memcpy(len, mem, sizeof(*len));
+  return mem + sizeof(*len);
+}
+
+
+/* upb_tabval *****************************************************************/
+
+#ifdef __cplusplus
+
+/* Status initialization not supported.
+ *
+ * This separate definition is necessary because in C++, UINTPTR_MAX isn't
+ * reliably available. */
+typedef struct {
+  uint64_t val;
+} upb_tabval;
+
+#else
+
+/* C -- supports static initialization, but to support static initialization of
+ * both integers and points for both 32 and 64 bit targets, it takes a little
+ * bit of doing. */
+
+#if UINTPTR_MAX == 0xffffffffffffffffULL
+#define UPB_PTR_IS_64BITS
+#elif UINTPTR_MAX != 0xffffffff
+#error Could not determine how many bits pointers are.
+#endif
+
+typedef union {
+  /* For static initialization.
+   *
+   * Unfortunately this ugliness is necessary -- it is the only way that we can,
+   * with -std=c89 -pedantic, statically initialize this to either a pointer or
+   * an integer on 32-bit platforms. */
+  struct {
+#ifdef UPB_PTR_IS_64BITS
+    uintptr_t val;
+#else
+    uintptr_t val1;
+    uintptr_t val2;
+#endif
+  } staticinit;
+
+  /* The normal accessor that we use for everything at runtime. */
+  uint64_t val;
+} upb_tabval;
+
+#ifdef UPB_PTR_IS_64BITS
+#define UPB_TABVALUE_INT_INIT(v) {{v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1}}
+#else
+
+/* 32-bit pointers */
+
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABVALUE_INT_INIT(v) {{0, v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#else
+#define UPB_TABVALUE_INT_INIT(v) {{v, 0}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#endif
+
+#endif
+
+#define UPB_TABVALUE_PTR_INIT(v) UPB_TABVALUE_INT_INIT((uintptr_t)v)
+
+#undef UPB_PTR_IS_64BITS
+
+#endif  /* __cplusplus */
+
+
+/* upb_table ******************************************************************/
+
+typedef struct _upb_tabent {
+  upb_tabkey key;
+  upb_tabval val;
+
+  /* Internal chaining.  This is const so we can create static initializers for
+   * tables.  We cast away const sometimes, but *only* when the containing
+   * upb_table is known to be non-const.  This requires a bit of care, but
+   * the subtlety is confined to table.c. */
+  const struct _upb_tabent *next;
+} upb_tabent;
+
+typedef struct {
+  size_t count;          /* Number of entries in the hash part. */
+  size_t mask;           /* Mask to turn hash value -> bucket. */
+  upb_ctype_t ctype;     /* Type of all values. */
+  uint8_t size_lg2;      /* Size of the hashtable part is 2^size_lg2 entries. */
+
+  /* Hash table entries.
+   * Making this const isn't entirely accurate; what we really want is for it to
+   * have the same const-ness as the table it's inside.  But there's no way to
+   * declare that in C.  So we have to make it const so that we can statically
+   * initialize const hash tables.  Then we cast away const when we have to.
+   */
+  const upb_tabent *entries;
+
+#ifndef NDEBUG
+  /* This table's allocator.  We make the user pass it in to every relevant
+   * function and only use this to check it in debug mode.  We do this solely
+   * to keep upb_table as small as possible.  This might seem slightly paranoid
+   * but the plan is to use upb_table for all map fields and extension sets in
+   * a forthcoming message representation, so there could be a lot of these.
+   * If this turns out to be too annoying later, we can change it (since this
+   * is an internal-only header file). */
+  upb_alloc *alloc;
+#endif
+} upb_table;
+
+#ifdef NDEBUG
+#  define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+     {count, mask, ctype, size_lg2, entries}
+#else
+#  ifdef UPB_DEBUG_REFS
+/* At the moment the only mutable tables we statically initialize are debug
+ * ref tables. */
+#    define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+       {count, mask, ctype, size_lg2, entries, &upb_alloc_debugrefs}
+#  else
+#    define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+       {count, mask, ctype, size_lg2, entries, NULL}
+#  endif
+#endif
+
+typedef struct {
+  upb_table t;
+} upb_strtable;
+
+#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \
+  {UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries)}
+
+#define UPB_EMPTY_STRTABLE_INIT(ctype)                           \
+  UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL)
+
+typedef struct {
+  upb_table t;              /* For entries that don't fit in the array part. */
+  const upb_tabval *array;  /* Array part of the table. See const note above. */
+  size_t array_size;        /* Array part size. */
+  size_t array_count;       /* Array part number of elements. */
+} upb_inttable;
+
+#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \
+  {UPB_TABLE_INIT(count, mask, ctype, size_lg2, ent), a, asize, acount}
+
+#define UPB_EMPTY_INTTABLE_INIT(ctype) \
+  UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0)
+
+#define UPB_ARRAY_EMPTYENT -1
+
+UPB_INLINE size_t upb_table_size(const upb_table *t) {
+  if (t->size_lg2 == 0)
+    return 0;
+  else
+    return 1 << t->size_lg2;
+}
+
+/* Internal-only functions, in .h file only out of necessity. */
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
+  return e->key == 0;
+}
+
+/* Used by some of the unit tests for generic hashing functionality. */
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed);
+
+UPB_INLINE uintptr_t upb_intkey(uintptr_t key) {
+  return key;
+}
+
+UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
+  return (uint32_t)key;
+}
+
+static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
+  return t->entries + (hash & t->mask);
+}
+
+UPB_INLINE bool upb_arrhas(upb_tabval key) {
+  return key.val != (uint64_t)-1;
+}
+
+/* Initialize and uninitialize a table, respectively.  If memory allocation
+ * failed, false is returned that the table is uninitialized. */
+bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a);
+bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a);
+void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a);
+void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a);
+
+UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) {
+  return upb_inttable_init2(table, ctype, &upb_alloc_global);
+}
+
+UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) {
+  return upb_strtable_init2(table, ctype, &upb_alloc_global);
+}
+
+UPB_INLINE void upb_inttable_uninit(upb_inttable *table) {
+  upb_inttable_uninit2(table, &upb_alloc_global);
+}
+
+UPB_INLINE void upb_strtable_uninit(upb_strtable *table) {
+  upb_strtable_uninit2(table, &upb_alloc_global);
+}
+
+/* Returns the number of values in the table. */
+size_t upb_inttable_count(const upb_inttable *t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
+  return t->t.count;
+}
+
+/* Inserts the given key into the hashtable with the given value.  The key must
+ * not already exist in the hash table.  For string tables, the key must be
+ * NULL-terminated, and the table will make an internal copy of the key.
+ * Inttables must not insert a value of UINTPTR_MAX.
+ *
+ * If a table resize was required but memory allocation failed, false is
+ * returned and the table is unchanged. */
+bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
+                          upb_alloc *a);
+bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len,
+                          upb_value val, upb_alloc *a);
+
+UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key,
+                                    upb_value val) {
+  return upb_inttable_insert2(t, key, val, &upb_alloc_global);
+}
+
+UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key,
+                                     size_t len, upb_value val) {
+  return upb_strtable_insert3(t, key, len, val, &upb_alloc_global);
+}
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key,
+                                    upb_value val) {
+  return upb_strtable_insert2(t, key, strlen(key), val);
+}
+
+/* Looks up key in this table, returning "true" if the key was found.
+ * If v is non-NULL, copies the value for this key into *v. */
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_lookup2(t, key, strlen(key), v);
+}
+
+/* Removes an item from the table.  Returns true if the remove was successful,
+ * and stores the removed item in *val if non-NULL. */
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
+bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
+                          upb_value *val, upb_alloc *alloc);
+
+UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key,
+                                     size_t len, upb_value *val) {
+  return upb_strtable_remove3(t, key, len, val, &upb_alloc_global);
+}
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_remove2(t, key, strlen(key), v);
+}
+
+/* Updates an existing entry in an inttable.  If the entry does not exist,
+ * returns false and does nothing.  Unlike insert/remove, this does not
+ * invalidate iterators. */
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
+
+/* Handy routines for treating an inttable like a stack.  May not be mixed with
+ * other insert/remove calls. */
+bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a);
+upb_value upb_inttable_pop(upb_inttable *t);
+
+UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) {
+  return upb_inttable_push2(t, val, &upb_alloc_global);
+}
+
+/* Convenience routines for inttables with pointer keys. */
+bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
+                             upb_alloc *a);
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
+bool upb_inttable_lookupptr(
+    const upb_inttable *t, const void *key, upb_value *val);
+
+UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key,
+                                       upb_value val) {
+  return upb_inttable_insertptr2(t, key, val, &upb_alloc_global);
+}
+
+/* Optimizes the table for the current set of entries, for both memory use and
+ * lookup time.  Client should call this after all entries have been inserted;
+ * inserting more entries is legal, but will likely require a table resize. */
+void upb_inttable_compact2(upb_inttable *t, upb_alloc *a);
+
+UPB_INLINE void upb_inttable_compact(upb_inttable *t) {
+  upb_inttable_compact2(t, &upb_alloc_global);
+}
+
+/* A special-case inlinable version of the lookup routine for 32-bit
+ * integers. */
+UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
+                                      upb_value *v) {
+  *v = upb_value_int32(0);  /* Silence compiler warnings. */
+  if (key < t->array_size) {
+    upb_tabval arrval = t->array[key];
+    if (upb_arrhas(arrval)) {
+      _upb_value_setval(v, arrval.val, t->t.ctype);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    const upb_tabent *e;
+    if (t->t.entries == NULL) return false;
+    for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) {
+      if ((uint32_t)e->key == key) {
+        _upb_value_setval(v, e->val.val, t->t.ctype);
+        return true;
+      }
+      if (e->next == NULL) return false;
+    }
+  }
+}
+
+/* Exposed for testing only. */
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a);
+
+/* Iterators ******************************************************************/
+
+/* Iterators for int and string tables.  We are subject to some kind of unusual
+ * design constraints:
+ *
+ * For high-level languages:
+ *  - we must be able to guarantee that we don't crash or corrupt memory even if
+ *    the program accesses an invalidated iterator.
+ *
+ * For C++11 range-based for:
+ *  - iterators must be copyable
+ *  - iterators must be comparable
+ *  - it must be possible to construct an "end" value.
+ *
+ * Iteration order is undefined.
+ *
+ * Modifying the table invalidates iterators.  upb_{str,int}table_done() is
+ * guaranteed to work even on an invalidated iterator, as long as the table it
+ * is iterating over has not been freed.  Calling next() or accessing data from
+ * an invalidated iterator yields unspecified elements from the table, but it is
+ * guaranteed not to crash and to return real table elements (except when done()
+ * is true). */
+
+
+/* upb_strtable_iter **********************************************************/
+
+/*   upb_strtable_iter i;
+ *   upb_strtable_begin(&i, t);
+ *   for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ *     const char *key = upb_strtable_iter_key(&i);
+ *     const upb_value val = upb_strtable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_strtable *t;
+  size_t index;
+} upb_strtable_iter;
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
+void upb_strtable_next(upb_strtable_iter *i);
+bool upb_strtable_done(const upb_strtable_iter *i);
+const char *upb_strtable_iter_key(const upb_strtable_iter *i);
+size_t upb_strtable_iter_keylength(const upb_strtable_iter *i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i);
+void upb_strtable_iter_setdone(upb_strtable_iter *i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2);
+
+
+/* upb_inttable_iter **********************************************************/
+
+/*   upb_inttable_iter i;
+ *   upb_inttable_begin(&i, t);
+ *   for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ *     uintptr_t key = upb_inttable_iter_key(&i);
+ *     upb_value val = upb_inttable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_inttable *t;
+  size_t index;
+  bool array_part;
+} upb_inttable_iter;
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
+void upb_inttable_next(upb_inttable_iter *i);
+bool upb_inttable_done(const upb_inttable_iter *i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i);
+void upb_inttable_iter_setdone(upb_inttable_iter *i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                               const upb_inttable_iter *i2);
+
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_TABLE_H_ */
+
+/* Reference tracking will check ref()/unref() operations to make sure the
+ * ref ownership is correct.  Where possible it will also make tools like
+ * Valgrind attribute ref leaks to the code that took the leaked ref, not
+ * the code that originally created the object.
+ *
+ * Enabling this requires the application to define upb_lock()/upb_unlock()
+ * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
+ * For this reason we don't enable it by default, even in debug builds.
+ */
+
+/* #define UPB_DEBUG_REFS */
+
+#ifdef __cplusplus
+namespace upb {
+class RefCounted;
+template <class T> class reffed_ptr;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted)
+
+struct upb_refcounted_vtbl;
+
+#ifdef __cplusplus
+
+class upb::RefCounted {
+ public:
+  /* Returns true if the given object is frozen. */
+  bool IsFrozen() const;
+
+  /* Increases the ref count, the new ref is owned by "owner" which must not
+   * already own a ref (and should not itself be a refcounted object if the ref
+   * could possibly be circular; see below).
+   * Thread-safe iff "this" is frozen. */
+  void Ref(const void *owner) const;
+
+  /* Release a ref that was acquired from upb_refcounted_ref() and collects any
+   * objects it can. */
+  void Unref(const void *owner) const;
+
+  /* Moves an existing ref from "from" to "to", without changing the overall
+   * ref count.  DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
+   * but "to" may not be NULL. */
+  void DonateRef(const void *from, const void *to) const;
+
+  /* Verifies that a ref to the given object is currently held by the given
+   * owner.  Only effective in UPB_DEBUG_REFS builds. */
+  void CheckRef(const void *owner) const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted)
+#else
+struct upb_refcounted {
+#endif
+  /* TODO(haberman): move the actual structure definition to structdefs.int.h.
+   * The only reason they are here is because inline functions need to see the
+   * definition of upb_handlers, which needs to see this definition.  But we
+   * can change the upb_handlers inline functions to deal in raw offsets
+   * instead.
+   */
+
+  /* A single reference count shared by all objects in the group. */
+  uint32_t *group;
+
+  /* A singly-linked list of all objects in the group. */
+  upb_refcounted *next;
+
+  /* Table of function pointers for this type. */
+  const struct upb_refcounted_vtbl *vtbl;
+
+  /* Maintained only when mutable, this tracks the number of refs (but not
+   * ref2's) to this object.  *group should be the sum of all individual_count
+   * in the group. */
+  uint32_t individual_count;
+
+  bool is_frozen;
+
+#ifdef UPB_DEBUG_REFS
+  upb_inttable *refs;  /* Maps owner -> trackedref for incoming refs. */
+  upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */
+#endif
+};
+
+#ifdef UPB_DEBUG_REFS
+extern upb_alloc upb_alloc_debugrefs;
+#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \
+    {&static_refcount, NULL, vtbl, 0, true, refs, ref2s}
+#else
+#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \
+    {&static_refcount, NULL, vtbl, 0, true}
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* It is better to use tracked refs when possible, for the extra debugging
+ * capability.  But if this is not possible (because you don't have easy access
+ * to a stable pointer value that is associated with the ref), you can pass
+ * UPB_UNTRACKED_REF instead.  */
+extern const void *UPB_UNTRACKED_REF;
+
+/* Native C API. */
+bool upb_refcounted_isfrozen(const upb_refcounted *r);
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to);
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner);
+
+#define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \
+  UPB_INLINE bool type ## _isfrozen(const type *v) { \
+    return upb_refcounted_isfrozen(upcastfunc(v)); \
+  } \
+  UPB_INLINE void type ## _ref(const type *v, const void *owner) { \
+    upb_refcounted_ref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _unref(const type *v, const void *owner) { \
+    upb_refcounted_unref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \
+    upb_refcounted_donateref(upcastfunc(v), from, to); \
+  } \
+  UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \
+    upb_refcounted_checkref(upcastfunc(v), owner); \
+  }
+
+#define UPB_REFCOUNTED_CPPMETHODS \
+  bool IsFrozen() const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->IsFrozen(); \
+  } \
+  void Ref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Ref(owner); \
+  } \
+  void Unref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Unref(owner); \
+  } \
+  void DonateRef(const void *from, const void *to) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->DonateRef(from, to); \
+  } \
+  void CheckRef(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->CheckRef(owner); \
+  }
+
+/* Internal-to-upb Interface **************************************************/
+
+typedef void upb_refcounted_visit(const upb_refcounted *r,
+                                  const upb_refcounted *subobj,
+                                  void *closure);
+
+struct upb_refcounted_vtbl {
+  /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
+   * Must be longjmp()-safe. */
+  void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c);
+
+  /* Must free the object and release all references to other objects. */
+  void (*free)(upb_refcounted *r);
+};
+
+/* Initializes the refcounted with a single ref for the given owner.  Returns
+ * false if memory could not be allocated. */
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner);
+
+/* Adds a ref from one refcounted object to another ("from" must not already
+ * own a ref).  These refs may be circular; cycles will be collected correctly
+ * (if conservatively).  These refs do not need to be freed in from's free()
+ * function. */
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from);
+
+/* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
+ * object it can.  This is only necessary when "from" no longer points to "r",
+ * and not from from's "free" function. */
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
+
+#define upb_ref2(r, from) \
+    upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from)
+#define upb_unref2(r, from) \
+    upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from)
+
+/* Freezes all mutable object reachable by ref2() refs from the given roots.
+ * This will split refcounting groups into precise SCC groups, so that
+ * refcounting of frozen objects can be more aggressive.  If memory allocation
+ * fails, or if more than 2**31 mutable objects are reachable from "roots", or
+ * if the maximum depth of the graph exceeds "maxdepth", false is returned and
+ * the objects are unchanged.
+ *
+ * After this operation succeeds, the objects are frozen/const, and may not be
+ * used through non-const pointers.  In particular, they may not be passed as
+ * the second parameter of upb_refcounted_{ref,unref}2().  On the upside, all
+ * operations on frozen refcounteds are threadsafe, and objects will be freed
+ * at the precise moment that they become unreachable.
+ *
+ * Caller must own refs on each object in the "roots" list. */
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth);
+
+/* Shared by all compiled-in refcounted objects. */
+extern uint32_t static_refcount;
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ Wrappers. */
+namespace upb {
+inline bool RefCounted::IsFrozen() const {
+  return upb_refcounted_isfrozen(this);
+}
+inline void RefCounted::Ref(const void *owner) const {
+  upb_refcounted_ref(this, owner);
+}
+inline void RefCounted::Unref(const void *owner) const {
+  upb_refcounted_unref(this, owner);
+}
+inline void RefCounted::DonateRef(const void *from, const void *to) const {
+  upb_refcounted_donateref(this, from, to);
+}
+inline void RefCounted::CheckRef(const void *owner) const {
+  upb_refcounted_checkref(this, owner);
+}
+}  /* namespace upb */
+#endif
+
+
+/* upb::reffed_ptr ************************************************************/
+
+#ifdef __cplusplus
+
+#include <algorithm>  /* For std::swap(). */
+
+/* Provides RAII semantics for upb refcounted objects.  Each reffed_ptr owns a
+ * ref on whatever object it points to (if any). */
+template <class T> class upb::reffed_ptr {
+ public:
+  reffed_ptr() : ptr_(NULL) {}
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  reffed_ptr(U* val, const void* ref_donor = NULL)
+      : ptr_(upb::upcast(val)) {
+    if (ref_donor) {
+      assert(ptr_);
+      ptr_->DonateRef(ref_donor, this);
+    } else if (ptr_) {
+      ptr_->Ref(this);
+    }
+  }
+
+  template <class U>
+  reffed_ptr(const reffed_ptr<U>& other)
+      : ptr_(upb::upcast(other.get())) {
+    if (ptr_) ptr_->Ref(this);
+  }
+
+  reffed_ptr(const reffed_ptr& other)
+      : ptr_(upb::upcast(other.get())) {
+    if (ptr_) ptr_->Ref(this);
+  }
+
+  ~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
+
+  template <class U>
+  reffed_ptr& operator=(const reffed_ptr<U>& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  reffed_ptr& operator=(const reffed_ptr& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  /* TODO(haberman): add C++11 move construction/assignment for greater
+   * efficiency. */
+
+  void swap(reffed_ptr& other) {
+    if (ptr_ == other.ptr_) {
+      return;
+    }
+
+    if (ptr_) ptr_->DonateRef(this, &other);
+    if (other.ptr_) other.ptr_->DonateRef(&other, this);
+    std::swap(ptr_, other.ptr_);
+  }
+
+  T& operator*() const {
+    assert(ptr_);
+    return *ptr_;
+  }
+
+  T* operator->() const {
+    assert(ptr_);
+    return ptr_;
+  }
+
+  T* get() const { return ptr_; }
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  void reset(U* ptr = NULL, const void* ref_donor = NULL) {
+    reffed_ptr(ptr, ref_donor).swap(*this);
+  }
+
+  template <class U>
+  reffed_ptr<U> down_cast() {
+    return reffed_ptr<U>(upb::down_cast<U*>(get()));
+  }
+
+  template <class U>
+  reffed_ptr<U> dyn_cast() {
+    return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
+  }
+
+  /* Plain release() is unsafe; if we were the only owner, it would leak the
+   * object.  Instead we provide this: */
+  T* ReleaseTo(const void* new_owner) {
+    T* ret = NULL;
+    ptr_->DonateRef(this, new_owner);
+    std::swap(ret, ptr_);
+    return ret;
+  }
+
+ private:
+  T* ptr_;
+};
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_REFCOUNT_H_ */
+
+#ifdef __cplusplus
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class FileDef;
+class MessageDef;
+class OneofDef;
+}
+#endif
+
+UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted)
+UPB_DECLARE_DERIVED_TYPE(upb::OneofDef, upb::RefCounted, upb_oneofdef,
+                         upb_refcounted)
+UPB_DECLARE_DERIVED_TYPE(upb::FileDef, upb::RefCounted, upb_filedef,
+                         upb_refcounted)
+
+/* The maximum message depth that the type graph can have.  This is a resource
+ * limit for the C stack since we sometimes need to recursively traverse the
+ * graph.  Cycles are ok; the traversal will stop when it detects a cycle, but
+ * we must hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Def::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_MESSAGE_DEPTH 64
+
+
+/* upb::Def: base class for top-level defs  ***********************************/
+
+/* All the different kind of defs that can be defined at the top-level and put
+ * in a SymbolTable or appear in a FileDef::defs() list.  This excludes some
+ * defs (like oneofs and files).  It only includes fields because they can be
+ * defined as extensions. */
+typedef enum {
+  UPB_DEF_MSG,
+  UPB_DEF_FIELD,
+  UPB_DEF_ENUM,
+  UPB_DEF_SERVICE,   /* Not yet implemented. */
+  UPB_DEF_ANY = -1   /* Wildcard for upb_symtab_get*() */
+} upb_deftype_t;
+
+#ifdef __cplusplus
+
+/* The base class of all defs.  Its base is upb::RefCounted (use upb::upcast()
+ * to convert). */
+class upb::Def {
+ public:
+  typedef upb_deftype_t Type;
+
+  Def* Dup(const void *owner) const;
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  Type def_type() const;
+
+  /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */
+  const char *full_name() const;
+
+  /* The final part of a def's name (eg. Message). */
+  const char *name() const;
+
+  /* The def must be mutable.  Caller retains ownership of fullname.  Defs are
+   * not required to have a name; if a def has no name when it is frozen, it
+   * will remain an anonymous def.  On failure, returns false and details in "s"
+   * if non-NULL. */
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string &fullname, upb::Status* s);
+
+  /* The file in which this def appears.  It is not necessary to add a def to a
+   * file (and consequently the accessor may return NULL).  Set this by calling
+   * file->Add(def). */
+  FileDef* file() const;
+
+  /* Freezes the given defs; this validates all constraints and marks the defs
+   * as frozen (read-only).  "defs" may not contain any fielddefs, but fields
+   * of any msgdefs will be frozen.
+   *
+   * Symbolic references to sub-types and enum defaults must have already been
+   * resolved.  Any mutable defs reachable from any of "defs" must also be in
+   * the list; more formally, "defs" must be a transitive closure of mutable
+   * defs.
+   *
+   * After this operation succeeds, the finalized defs must only be accessed
+   * through a const pointer! */
+  static bool Freeze(Def* const* defs, size_t n, Status* status);
+  static bool Freeze(const std::vector<Def*>& defs, Status* status);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Def, upb::Def)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_def *upb_def_dup(const upb_def *def, const void *owner);
+
+/* Include upb_refcounted methods like upb_def_ref()/upb_def_unref(). */
+UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast)
+
+upb_deftype_t upb_def_type(const upb_def *d);
+const char *upb_def_fullname(const upb_def *d);
+const char *upb_def_name(const upb_def *d);
+const upb_filedef *upb_def_file(const upb_def *d);
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s);
+bool upb_def_freeze(upb_def *const *defs, size_t n, upb_status *s);
+
+/* Temporary API: for internal use only. */
+bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s);
+
+UPB_END_EXTERN_C
+
+
+/* upb::Def casts *************************************************************/
+
+#ifdef __cplusplus
+#define UPB_CPP_CASTS(cname, cpptype)                                          \
+  namespace upb {                                                              \
+  template <>                                                                  \
+  inline cpptype *down_cast<cpptype *, Def>(Def * def) {                       \
+    return upb_downcast_##cname##_mutable(def);                                \
+  }                                                                            \
+  template <>                                                                  \
+  inline cpptype *dyn_cast<cpptype *, Def>(Def * def) {                        \
+    return upb_dyncast_##cname##_mutable(def);                                 \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, const Def>(                 \
+      const Def *def) {                                                        \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, const Def>(const Def *def) { \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, Def>(Def * def) {           \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, Def>(Def * def) {            \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  }  /* namespace upb */
+#else
+#define UPB_CPP_CASTS(cname, cpptype)
+#endif  /* __cplusplus */
+
+/* Dynamic casts, for determining if a def is of a particular type at runtime.
+ * Downcasts, for when some wants to assert that a def is of a particular type.
+ * These are only checked if we are building debug. */
+#define UPB_DEF_CASTS(lower, upper, cpptype)                               \
+  UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) {  \
+    if (upb_def_type(def) != UPB_DEF_##upper) return NULL;                 \
+    return (upb_##lower *)def;                                             \
+  }                                                                        \
+  UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \
+    assert(upb_def_type(def) == UPB_DEF_##upper);                          \
+    return (const upb_##lower *)def;                                       \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) {    \
+    return (upb_##lower *)upb_dyncast_##lower(def);                        \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) {   \
+    return (upb_##lower *)upb_downcast_##lower(def);                       \
+  }                                                                        \
+  UPB_CPP_CASTS(lower, cpptype)
+
+#define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members)             \
+  UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, cppmethods,            \
+                   members)                                                    \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+#define UPB_DECLARE_DEF_TYPE(cppname, lower, upper) \
+  UPB_DECLARE_DERIVED_TYPE2(cppname, upb::Def, upb::RefCounted, \
+                            upb_ ## lower, upb_def, upb_refcounted) \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD)
+UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG)
+UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM)
+
+#undef UPB_DECLARE_DEF_TYPE
+#undef UPB_DEF_CASTS
+#undef UPB_CPP_CASTS
+
+
+/* upb::FieldDef **************************************************************/
+
+/* The types a field can have.  Note that this list is not identical to the
+ * types defined in descriptor.proto, which gives INT32 and SINT32 separate
+ * types (we distinguish the two with the "integer encoding" enum below). */
+typedef enum {
+  UPB_TYPE_FLOAT    = 1,
+  UPB_TYPE_DOUBLE   = 2,
+  UPB_TYPE_BOOL     = 3,
+  UPB_TYPE_STRING   = 4,
+  UPB_TYPE_BYTES    = 5,
+  UPB_TYPE_MESSAGE  = 6,
+  UPB_TYPE_ENUM     = 7,  /* Enum values are int32. */
+  UPB_TYPE_INT32    = 8,
+  UPB_TYPE_UINT32   = 9,
+  UPB_TYPE_INT64    = 10,
+  UPB_TYPE_UINT64   = 11
+} upb_fieldtype_t;
+
+/* The repeated-ness of each field; this matches descriptor.proto. */
+typedef enum {
+  UPB_LABEL_OPTIONAL = 1,
+  UPB_LABEL_REQUIRED = 2,
+  UPB_LABEL_REPEATED = 3
+} upb_label_t;
+
+/* How integers should be encoded in serializations that offer multiple
+ * integer encoding methods. */
+typedef enum {
+  UPB_INTFMT_VARIABLE = 1,
+  UPB_INTFMT_FIXED = 2,
+  UPB_INTFMT_ZIGZAG = 3   /* Only for signed types (INT32/INT64). */
+} upb_intfmt_t;
+
+/* Descriptor types, as defined in descriptor.proto. */
+typedef enum {
+  UPB_DESCRIPTOR_TYPE_DOUBLE   = 1,
+  UPB_DESCRIPTOR_TYPE_FLOAT    = 2,
+  UPB_DESCRIPTOR_TYPE_INT64    = 3,
+  UPB_DESCRIPTOR_TYPE_UINT64   = 4,
+  UPB_DESCRIPTOR_TYPE_INT32    = 5,
+  UPB_DESCRIPTOR_TYPE_FIXED64  = 6,
+  UPB_DESCRIPTOR_TYPE_FIXED32  = 7,
+  UPB_DESCRIPTOR_TYPE_BOOL     = 8,
+  UPB_DESCRIPTOR_TYPE_STRING   = 9,
+  UPB_DESCRIPTOR_TYPE_GROUP    = 10,
+  UPB_DESCRIPTOR_TYPE_MESSAGE  = 11,
+  UPB_DESCRIPTOR_TYPE_BYTES    = 12,
+  UPB_DESCRIPTOR_TYPE_UINT32   = 13,
+  UPB_DESCRIPTOR_TYPE_ENUM     = 14,
+  UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
+  UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
+  UPB_DESCRIPTOR_TYPE_SINT32   = 17,
+  UPB_DESCRIPTOR_TYPE_SINT64   = 18
+} upb_descriptortype_t;
+
+typedef enum {
+  UPB_SYNTAX_PROTO2 = 2,
+  UPB_SYNTAX_PROTO3 = 3
+} upb_syntax_t;
+
+/* Maximum field number allowed for FieldDefs.  This is an inherent limit of the
+ * protobuf wire format. */
+#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
+
+#ifdef __cplusplus
+
+/* A upb_fielddef describes a single field in a message.  It is most often
+ * found as a part of a upb_msgdef, but can also stand alone to represent
+ * an extension.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::FieldDef {
+ public:
+  typedef upb_fieldtype_t Type;
+  typedef upb_label_t Label;
+  typedef upb_intfmt_t IntegerFormat;
+  typedef upb_descriptortype_t DescriptorType;
+
+  /* These return true if the given value is a valid member of the enumeration. */
+  static bool CheckType(int32_t val);
+  static bool CheckLabel(int32_t val);
+  static bool CheckDescriptorType(int32_t val);
+  static bool CheckIntegerFormat(int32_t val);
+
+  /* These convert to the given enumeration; they require that the value is
+   * valid. */
+  static Type ConvertType(int32_t val);
+  static Label ConvertLabel(int32_t val);
+  static DescriptorType ConvertDescriptorType(int32_t val);
+  static IntegerFormat ConvertIntegerFormat(int32_t val);
+
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<FieldDef> New();
+
+  /* Duplicates the given field, returning NULL if memory allocation failed.
+   * When a fielddef is duplicated, the subdef (if any) is made symbolic if it
+   * wasn't already.  If the subdef is set but has no name (which is possible
+   * since msgdefs are not required to have a name) the new fielddef's subdef
+   * will be unset. */
+  FieldDef* Dup(const void* owner) const;
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+
+  bool type_is_set() const;  /* set_[descriptor_]type() has been called? */
+  Type type() const;         /* Requires that type_is_set() == true. */
+  Label label() const;       /* Defaults to UPB_LABEL_OPTIONAL. */
+  const char* name() const;  /* NULL if uninitialized. */
+  uint32_t number() const;   /* Returns 0 if uninitialized. */
+  bool is_extension() const;
+
+  /* Copies the JSON name for this field into the given buffer.  Returns the
+   * actual size of the JSON name, including the NULL terminator.  If the
+   * return value is 0, the JSON name is unset.  If the return value is
+   * greater than len, the JSON name was truncated.  The buffer is always
+   * NULL-terminated if len > 0.
+   *
+   * The JSON name always defaults to a camelCased version of the regular
+   * name.  However if the regular name is unset, the JSON name will be unset
+   * also.
+   */
+  size_t GetJsonName(char* buf, size_t len) const;
+
+  /* Convenience version of the above function which copies the JSON name
+   * into the given string, returning false if the name is not set. */
+  template <class T>
+  bool GetJsonName(T* str) {
+    str->resize(GetJsonName(NULL, 0));
+    GetJsonName(&(*str)[0], str->size());
+    return str->size() > 0;
+  }
+
+  /* For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false,
+   * indicates whether this field should have lazy parsing handlers that yield
+   * the unparsed string for the submessage.
+   *
+   * TODO(haberman): I think we want to move this into a FieldOptions container
+   * when we add support for custom options (the FieldOptions struct will
+   * contain both regular FieldOptions like "lazy" *and* custom options). */
+  bool lazy() const;
+
+  /* For non-string, non-submessage fields, this indicates whether binary
+   * protobufs are encoded in packed or non-packed format.
+   *
+   * TODO(haberman): see note above about putting options like this into a
+   * FieldOptions container. */
+  bool packed() const;
+
+  /* An integer that can be used as an index into an array of fields for
+   * whatever message this field belongs to.  Guaranteed to be less than
+   * f->containing_type()->field_count().  May only be accessed once the def has
+   * been finalized. */
+  uint32_t index() const;
+
+  /* The MessageDef to which this field belongs.
+   *
+   * If this field has been added to a MessageDef, that message can be retrieved
+   * directly (this is always the case for frozen FieldDefs).
+   *
+   * If the field has not yet been added to a MessageDef, you can set the name
+   * of the containing type symbolically instead.  This is mostly useful for
+   * extensions, where the extension is declared separately from the message. */
+  const MessageDef* containing_type() const;
+  const char* containing_type_name();
+
+  /* The OneofDef to which this field belongs, or NULL if this field is not part
+   * of a oneof. */
+  const OneofDef* containing_oneof() const;
+
+  /* The field's type according to the enum in descriptor.proto.  This is not
+   * the same as UPB_TYPE_*, because it distinguishes between (for example)
+   * INT32 and SINT32, whereas our "type" enum does not.  This return of
+   * descriptor_type() is a function of type(), integer_format(), and
+   * is_tag_delimited().  Likewise set_descriptor_type() sets all three
+   * appropriately. */
+  DescriptorType descriptor_type() const;
+
+  /* Convenient field type tests. */
+  bool IsSubMessage() const;
+  bool IsString() const;
+  bool IsSequence() const;
+  bool IsPrimitive() const;
+  bool IsMap() const;
+
+  /* Whether this field must be able to explicitly represent presence:
+   *
+   * * This is always false for repeated fields (an empty repeated field is
+   *   equivalent to a repeated field with zero entries).
+   *
+   * * This is always true for submessages.
+   *
+   * * For other fields, it depends on the message (see
+   *   MessageDef::SetPrimitivesHavePresence())
+   */
+  bool HasPresence() const;
+
+  /* How integers are encoded.  Only meaningful for integer types.
+   * Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes. */
+  IntegerFormat integer_format() const;
+
+  /* Whether a submessage field is tag-delimited or not (if false, then
+   * length-delimited).  May only be set when type() == UPB_TYPE_MESSAGE. */
+  bool is_tag_delimited() const;
+
+  /* Returns the non-string default value for this fielddef, which may either
+   * be something the client set explicitly or the "default default" (0 for
+   * numbers, empty for strings).  The field's type indicates the type of the
+   * returned value, except for enum fields that are still mutable.
+   *
+   * Requires that the given function matches the field's current type. */
+  int64_t default_int64() const;
+  int32_t default_int32() const;
+  uint64_t default_uint64() const;
+  uint32_t default_uint32() const;
+  bool default_bool() const;
+  float default_float() const;
+  double default_double() const;
+
+  /* The resulting string is always NULL-terminated.  If non-NULL, the length
+   * will be stored in *len. */
+  const char *default_string(size_t* len) const;
+
+  /* For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either
+   * string or int32, and both of these methods will always return true.
+   *
+   * For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated.
+   * Enum defaults are unusual. They can be specified either as string or int32,
+   * but to be valid the enum must have that value as a member.  And if no
+   * default is specified, the "default default" comes from the EnumDef.
+   *
+   * We allow reading the default as either an int32 or a string, but only if
+   * we have a meaningful value to report.  We have a meaningful value if it was
+   * set explicitly, or if we could get the "default default" from the EnumDef.
+   * Also if you explicitly set the name and we find the number in the EnumDef */
+  bool EnumHasStringDefault() const;
+  bool EnumHasInt32Default() const;
+
+  /* Submessage and enum fields must reference a "subdef", which is the
+   * upb::MessageDef or upb::EnumDef that defines their type.  Note that when
+   * the FieldDef is mutable it may not have a subdef *yet*, but this function
+   * still returns true to indicate that the field's type requires a subdef. */
+  bool HasSubDef() const;
+
+  /* Returns the enum or submessage def for this field, if any.  The field's
+   * type must match (ie. you may only call enum_subdef() for fields where
+   * type() == UPB_TYPE_ENUM).  Returns NULL if the subdef has not been set or
+   * is currently set symbolically. */
+  const EnumDef* enum_subdef() const;
+  const MessageDef* message_subdef() const;
+
+  /* Returns the generic subdef for this field.  Requires that HasSubDef() (ie.
+   * only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields). */
+  const Def* subdef() const;
+
+  /* Returns the symbolic name of the subdef.  If the subdef is currently set
+   * unresolved (ie. set symbolically) returns the symbolic name.  If it has
+   * been resolved to a specific subdef, returns the name from that subdef. */
+  const char* subdef_name() const;
+
+  /* Setters (non-const methods), only valid for mutable FieldDefs! ***********/
+
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string& fullname, upb::Status* s);
+
+  /* This may only be called if containing_type() == NULL (ie. the field has not
+   * been added to a message yet). */
+  bool set_containing_type_name(const char *name, Status* status);
+  bool set_containing_type_name(const std::string& name, Status* status);
+
+  /* Defaults to false.  When we freeze, we ensure that this can only be true
+   * for length-delimited message fields.  Prior to freezing this can be true or
+   * false with no restrictions. */
+  void set_lazy(bool lazy);
+
+  /* Defaults to true.  Sets whether this field is encoded in packed format. */
+  void set_packed(bool packed);
+
+  /* "type" or "descriptor_type" MUST be set explicitly before the fielddef is
+   * finalized.  These setters require that the enum value is valid; if the
+   * value did not come directly from an enum constant, the caller should
+   * validate it first with the functions above (CheckFieldType(), etc). */
+  void set_type(Type type);
+  void set_label(Label label);
+  void set_descriptor_type(DescriptorType type);
+  void set_is_extension(bool is_extension);
+
+  /* "number" and "name" must be set before the FieldDef is added to a
+   * MessageDef, and may not be set after that.
+   *
+   * "name" is the same as full_name()/set_full_name(), but since fielddefs
+   * most often use simple, non-qualified names, we provide this accessor
+   * also.  Generally only extensions will want to think of this name as
+   * fully-qualified. */
+  bool set_number(uint32_t number, upb::Status* s);
+  bool set_name(const char* name, upb::Status* s);
+  bool set_name(const std::string& name, upb::Status* s);
+
+  /* Sets the JSON name to the given string. */
+  /* TODO(haberman): implement.  Right now only default json_name (camelCase)
+   * is supported. */
+  bool set_json_name(const char* json_name, upb::Status* s);
+  bool set_json_name(const std::string& name, upb::Status* s);
+
+  /* Clears the JSON name. This will make it revert to its default, which is
+   * a camelCased version of the regular field name. */
+  void clear_json_name();
+
+  void set_integer_format(IntegerFormat format);
+  bool set_tag_delimited(bool tag_delimited, upb::Status* s);
+
+  /* Sets default value for the field.  The call must exactly match the type
+   * of the field.  Enum fields may use either setint32 or setstring to set
+   * the default numerically or symbolically, respectively, but symbolic
+   * defaults must be resolved before finalizing (see ResolveEnumDefault()).
+   *
+   * Changing the type of a field will reset its default. */
+  void set_default_int64(int64_t val);
+  void set_default_int32(int32_t val);
+  void set_default_uint64(uint64_t val);
+  void set_default_uint32(uint32_t val);
+  void set_default_bool(bool val);
+  void set_default_float(float val);
+  void set_default_double(double val);
+  bool set_default_string(const void *str, size_t len, Status *s);
+  bool set_default_string(const std::string &str, Status *s);
+  void set_default_cstr(const char *str, Status *s);
+
+  /* Before a fielddef is frozen, its subdef may be set either directly (with a
+   * upb::Def*) or symbolically.  Symbolic refs must be resolved before the
+   * containing msgdef can be frozen (see upb_resolve() above).  upb always
+   * guarantees that any def reachable from a live def will also be kept alive.
+   *
+   * Both methods require that upb_hassubdef(f) (so the type must be set prior
+   * to calling these methods).  Returns false if this is not the case, or if
+   * the given subdef is not of the correct type.  The subdef is reset if the
+   * field's type is changed.  The subdef can be set to NULL to clear it. */
+  bool set_subdef(const Def* subdef, Status* s);
+  bool set_enum_subdef(const EnumDef* subdef, Status* s);
+  bool set_message_subdef(const MessageDef* subdef, Status* s);
+  bool set_subdef_name(const char* name, Status* s);
+  bool set_subdef_name(const std::string &name, Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef)
+};
+
+# endif  /* defined(__cplusplus) */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_fielddef *upb_fielddef_new(const void *owner);
+upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner);
+
+/* Include upb_refcounted methods like upb_fielddef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2)
+
+/* Methods from upb_def. */
+const char *upb_fielddef_fullname(const upb_fielddef *f);
+bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname,
+                              upb_status *s);
+
+bool upb_fielddef_typeisset(const upb_fielddef *f);
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
+upb_label_t upb_fielddef_label(const upb_fielddef *f);
+uint32_t upb_fielddef_number(const upb_fielddef *f);
+const char *upb_fielddef_name(const upb_fielddef *f);
+bool upb_fielddef_isextension(const upb_fielddef *f);
+bool upb_fielddef_lazy(const upb_fielddef *f);
+bool upb_fielddef_packed(const upb_fielddef *f);
+size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len);
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
+const char *upb_fielddef_containingtypename(upb_fielddef *f);
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
+uint32_t upb_fielddef_index(const upb_fielddef *f);
+bool upb_fielddef_istagdelim(const upb_fielddef *f);
+bool upb_fielddef_issubmsg(const upb_fielddef *f);
+bool upb_fielddef_isstring(const upb_fielddef *f);
+bool upb_fielddef_isseq(const upb_fielddef *f);
+bool upb_fielddef_isprimitive(const upb_fielddef *f);
+bool upb_fielddef_ismap(const upb_fielddef *f);
+bool upb_fielddef_haspresence(const upb_fielddef *f);
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f);
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f);
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f);
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f);
+bool upb_fielddef_defaultbool(const upb_fielddef *f);
+float upb_fielddef_defaultfloat(const upb_fielddef *f);
+double upb_fielddef_defaultdouble(const upb_fielddef *f);
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f);
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f);
+bool upb_fielddef_hassubdef(const upb_fielddef *f);
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
+const char *upb_fielddef_subdefname(const upb_fielddef *f);
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type);
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type);
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label);
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s);
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_setjsonname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_clearjsonname(upb_fielddef *f);
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s);
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension);
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy);
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed);
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt);
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim);
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val);
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val);
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val);
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val);
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val);
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val);
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val);
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s);
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s);
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s);
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s);
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s);
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s);
+
+bool upb_fielddef_checklabel(int32_t label);
+bool upb_fielddef_checktype(int32_t type);
+bool upb_fielddef_checkdescriptortype(int32_t type);
+bool upb_fielddef_checkintfmt(int32_t fmt);
+
+UPB_END_EXTERN_C
+
+
+/* upb::MessageDef ************************************************************/
+
+typedef upb_inttable_iter upb_msg_field_iter;
+typedef upb_strtable_iter upb_msg_oneof_iter;
+
+/* Well-known field tag numbers for map-entry messages. */
+#define UPB_MAPENTRY_KEY   1
+#define UPB_MAPENTRY_VALUE 2
+
+#ifdef __cplusplus
+
+/* Structure that describes a single .proto message type.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::MessageDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<MessageDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  const char* name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this MessageDef.
+   * WARNING: this will fail if this message has any unfrozen submessages!
+   * Messages with cycles must be frozen as a batch using upb::Def::Freeze(). */
+  bool Freeze(Status* s);
+
+  /* The number of fields that belong to the MessageDef. */
+  int field_count() const;
+
+  /* The number of oneofs that belong to the MessageDef. */
+  int oneof_count() const;
+
+  /* Adds a field (upb_fielddef object) to a msgdef.  Requires that the msgdef
+   * and the fielddefs are mutable.  The fielddef's name and number must be
+   * set, and the message may not already contain any field with this name or
+   * number, and this fielddef may not be part of another message.  In error
+   * cases false is returned and the msgdef is unchanged.
+   *
+   * If the given field is part of a oneof, this call succeeds if and only if
+   * that oneof is already part of this msgdef. (Note that adding a oneof to a
+   * msgdef automatically adds all of its fields to the msgdef at the time that
+   * the oneof is added, so it is usually more idiomatic to add the oneof's
+   * fields first then add the oneof to the msgdef. This case is supported for
+   * convenience.)
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* f, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
+
+  /* Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef,
+   * oneof, and any fielddefs are mutable, that the fielddefs contained in the
+   * oneof do not have any name or number conflicts with existing fields in the
+   * msgdef, and that the oneof's name is unique among all oneofs in the msgdef.
+   * If the oneof is added successfully, all of its fields will be added
+   * directly to the msgdef as well. In error cases, false is returned and the
+   * msgdef is unchanged. */
+  bool AddOneof(OneofDef* o, Status* s);
+  bool AddOneof(const reffed_ptr<OneofDef>& o, Status* s);
+
+  upb_syntax_t syntax() const;
+
+  /* Returns false if we don't support this syntax value. */
+  bool set_syntax(upb_syntax_t syntax);
+
+  /* Set this to false to indicate that primitive fields should not have
+   * explicit presence information associated with them.  This will affect all
+   * fields added to this message.  Defaults to true. */
+  void SetPrimitivesHavePresence(bool have_presence);
+
+  /* These return NULL if the field is not found. */
+  FieldDef* FindFieldByNumber(uint32_t number);
+  FieldDef* FindFieldByName(const char *name, size_t len);
+  const FieldDef* FindFieldByNumber(uint32_t number) const;
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+
+
+  FieldDef* FindFieldByName(const char *name) {
+    return FindFieldByName(name, strlen(name));
+  }
+  const FieldDef* FindFieldByName(const char *name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  OneofDef* FindOneofByName(const char* name, size_t len);
+  const OneofDef* FindOneofByName(const char* name, size_t len) const;
+
+  OneofDef* FindOneofByName(const char* name) {
+    return FindOneofByName(name, strlen(name));
+  }
+  const OneofDef* FindOneofByName(const char* name) const {
+    return FindOneofByName(name, strlen(name));
+  }
+
+  template<class T>
+  OneofDef* FindOneofByName(const T& str) {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+  template<class T>
+  const OneofDef* FindOneofByName(const T& str) const {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+
+  /* Returns a new msgdef that is a copy of the given msgdef (and a copy of all
+   * the fields) but with any references to submessages broken and replaced
+   * with just the name of the submessage.  Returns NULL if memory allocation
+   * failed.
+   *
+   * TODO(haberman): which is more useful, keeping fields resolved or
+   * unresolving them?  If there's no obvious answer, Should this functionality
+   * just be moved into symtab.c? */
+  MessageDef* Dup(const void* owner) const;
+
+  /* Is this message a map entry? */
+  void setmapentry(bool map_entry);
+  bool mapentry() const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class field_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit field_iterator(MessageDef* md);
+    static field_iterator end(MessageDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const field_iterator& other) const;
+    bool operator==(const field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  class const_field_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_field_iterator(const MessageDef* md);
+    static const_field_iterator end(const MessageDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_field_iterator& other) const;
+    bool operator==(const const_field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  /* Iteration over oneofs. The order is undefined. */
+  class oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit oneof_iterator(MessageDef* md);
+    static oneof_iterator end(MessageDef* md);
+
+    void operator++();
+    OneofDef* operator*() const;
+    bool operator!=(const oneof_iterator& other) const;
+    bool operator==(const oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class const_oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_oneof_iterator(const MessageDef* md);
+    static const_oneof_iterator end(const MessageDef* md);
+
+    void operator++();
+    const OneofDef* operator*() const;
+    bool operator!=(const const_oneof_iterator& other) const;
+    bool operator==(const const_oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class FieldAccessor {
+   public:
+    explicit FieldAccessor(MessageDef* msg) : msg_(msg) {}
+    field_iterator begin() { return msg_->field_begin(); }
+    field_iterator end() { return msg_->field_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstFieldAccessor {
+   public:
+    explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_field_iterator begin() { return msg_->field_begin(); }
+    const_field_iterator end() { return msg_->field_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  class OneofAccessor {
+   public:
+    explicit OneofAccessor(MessageDef* msg) : msg_(msg) {}
+    oneof_iterator begin() { return msg_->oneof_begin(); }
+    oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstOneofAccessor {
+   public:
+    explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_oneof_iterator begin() { return msg_->oneof_begin(); }
+    const_oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  field_iterator field_begin();
+  field_iterator field_end();
+  const_field_iterator field_begin() const;
+  const_field_iterator field_end() const;
+
+  oneof_iterator oneof_begin();
+  oneof_iterator oneof_end();
+  const_oneof_iterator oneof_begin() const;
+  const_oneof_iterator oneof_end() const;
+
+  FieldAccessor fields() { return FieldAccessor(this); }
+  ConstFieldAccessor fields() const { return ConstFieldAccessor(this); }
+  OneofAccessor oneofs() { return OneofAccessor(this); }
+  ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
+
+ private:
+  UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Returns NULL if memory allocation failed. */
+upb_msgdef *upb_msgdef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_msgdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2)
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status);
+
+upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner);
+const char *upb_msgdef_fullname(const upb_msgdef *m);
+const char *upb_msgdef_name(const upb_msgdef *m);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m);
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s);
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s);
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry);
+bool upb_msgdef_mapentry(const upb_msgdef *m);
+bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax);
+
+/* Field lookup in a couple of different variations:
+ *   - itof = int to field
+ *   - ntof = name to field
+ *   - ntofz = name to field, null-terminated string. */
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numfields(const upb_msgdef *m);
+
+UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
+                                                const char *name) {
+  return upb_msgdef_ntof(m, name, strlen(name));
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) {
+  return (upb_fielddef*)upb_msgdef_itof(m, i);
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
+}
+
+/* Oneof lookup:
+ *   - ntoo = name to oneof
+ *   - ntooz = name to oneof, null-terminated string. */
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
+                                               const char *name) {
+  return upb_msgdef_ntoo(m, name, strlen(name));
+}
+
+UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len);
+}
+
+/* Lookup of either field or oneof by name.  Returns whether either was found.
+ * If the return is true, then the found def will be set, and the non-found
+ * one set to NULL. */
+bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
+                           const upb_fielddef **f, const upb_oneofdef **o);
+
+UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name,
+                                       const upb_fielddef **f,
+                                       const upb_oneofdef **o) {
+  return upb_msgdef_lookupname(m, name, strlen(name), f, o);
+}
+
+/* Iteration over fields and oneofs.  For example:
+ *
+ * upb_msg_field_iter i;
+ * for(upb_msg_field_begin(&i, m);
+ *     !upb_msg_field_done(&i);
+ *     upb_msg_field_next(&i)) {
+ *   upb_fielddef *f = upb_msg_iter_field(&i);
+ *   // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
+void upb_msg_field_next(upb_msg_field_iter *iter);
+bool upb_msg_field_done(const upb_msg_field_iter *iter);
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
+
+/* Similar to above, we also support iterating through the oneofs in a
+ * msgdef. */
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m);
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter);
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::EnumDef ***************************************************************/
+
+typedef upb_strtable_iter upb_enum_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents an enum.  Its base class is upb::Def (convert with
+ * upb::upcast()). */
+class upb::EnumDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<EnumDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  const char* name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this EnumDef. */
+  bool Freeze(Status* s);
+
+  /* The value that is used as the default when no field default is specified.
+   * If not set explicitly, the first value that was added will be used.
+   * The default value must be a member of the enum.
+   * Requires that value_count() > 0. */
+  int32_t default_value() const;
+
+  /* Sets the default value.  If this value is not valid, returns false and an
+   * error message in status. */
+  bool set_default_value(int32_t val, Status* status);
+
+  /* Returns the number of values currently defined in the enum.  Note that
+   * multiple names can refer to the same number, so this may be greater than
+   * the total number of unique numbers. */
+  int value_count() const;
+
+  /* Adds a single name/number pair to the enum.  Fails if this name has
+   * already been used by another value. */
+  bool AddValue(const char* name, int32_t num, Status* status);
+  bool AddValue(const std::string& name, int32_t num, Status* status);
+
+  /* Lookups from name to integer, returning true if found. */
+  bool FindValueByName(const char* name, int32_t* num) const;
+
+  /* Finds the name corresponding to the given number, or NULL if none was
+   * found.  If more than one name corresponds to this number, returns the
+   * first one that was added. */
+  const char* FindValueByNumber(int32_t num) const;
+
+  /* Returns a new EnumDef with all the same values.  The new EnumDef will be
+   * owned by the given owner. */
+  EnumDef* Dup(const void* owner) const;
+
+  /* Iteration over name/value pairs.  The order is undefined.
+   * Adding an enum val invalidates any iterators.
+   *
+   * TODO: make compatible with range-for, with elements as pairs? */
+  class Iterator {
+   public:
+    explicit Iterator(const EnumDef*);
+
+    int32_t number();
+    const char *name();
+    bool Done();
+    void Next();
+
+   private:
+    upb_enum_iter iter_;
+  };
+
+ private:
+  UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_enumdef *upb_enumdef_new(const void *owner);
+upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner);
+
+/* Include upb_refcounted methods like upb_enumdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_enumdef, upb_enumdef_upcast2)
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status);
+
+/* From upb_def. */
+const char *upb_enumdef_fullname(const upb_enumdef *e);
+const char *upb_enumdef_name(const upb_enumdef *e);
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s);
+
+int32_t upb_enumdef_default(const upb_enumdef *e);
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s);
+int upb_enumdef_numvals(const upb_enumdef *e);
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status);
+
+/* Enum lookups:
+ * - ntoi:  look up a name with specified length.
+ * - ntoiz: look up a name provided as a null-terminated string.
+ * - iton:  look up an integer, returning the name as a null-terminated
+ *          string. */
+bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
+                      int32_t *num);
+UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
+                                  const char *name, int32_t *num) {
+  return upb_enumdef_ntoi(e, name, strlen(name), num);
+}
+const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
+
+/*  upb_enum_iter i;
+ *  for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
+void upb_enum_next(upb_enum_iter *iter);
+bool upb_enum_done(upb_enum_iter *iter);
+const char *upb_enum_iter_name(upb_enum_iter *iter);
+int32_t upb_enum_iter_number(upb_enum_iter *iter);
+
+UPB_END_EXTERN_C
+
+/* upb::OneofDef **************************************************************/
+
+typedef upb_inttable_iter upb_oneof_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents a oneof. */
+class upb::OneofDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<OneofDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Returns the MessageDef that owns this OneofDef. */
+  const MessageDef* containing_type() const;
+
+  /* Returns the name of this oneof. This is the name used to look up the oneof
+   * by name once added to a message def. */
+  const char* name() const;
+  bool set_name(const char* name, Status* s);
+  bool set_name(const std::string& name, Status* s);
+
+  /* Returns the number of fields currently defined in the oneof. */
+  int field_count() const;
+
+  /* Adds a field to the oneof. The field must not have been added to any other
+   * oneof or msgdef. If the oneof is not yet part of a msgdef, then when the
+   * oneof is eventually added to a msgdef, all fields added to the oneof will
+   * also be added to the msgdef at that time. If the oneof is already part of a
+   * msgdef, the field must either be a part of that msgdef already, or must not
+   * be a part of any msgdef; in the latter case, the field is added to the
+   * msgdef as a part of this operation.
+   *
+   * The field may only have an OPTIONAL label, never REQUIRED or REPEATED.
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* field, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& field, Status* s);
+
+  /* Looks up by name. */
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+  FieldDef* FindFieldByName(const char* name, size_t len);
+  const FieldDef* FindFieldByName(const char* name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+  FieldDef* FindFieldByName(const char* name) {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  /* Looks up by tag number. */
+  const FieldDef* FindFieldByNumber(uint32_t num) const;
+
+  /* Returns a new OneofDef with all the same fields. The OneofDef will be owned
+   * by the given owner. */
+  OneofDef* Dup(const void* owner) const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit iterator(OneofDef* md);
+    static iterator end(OneofDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const iterator& other) const;
+    bool operator==(const iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  class const_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_iterator(const OneofDef* md);
+    static const_iterator end(const OneofDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_iterator& other) const;
+    bool operator==(const const_iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_oneofdef *upb_oneofdef_new(const void *owner);
+upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
+
+/* Include upb_refcounted methods like upb_oneofdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast)
+
+const char *upb_oneofdef_name(const upb_oneofdef *o);
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
+int upb_oneofdef_numfields(const upb_oneofdef *o);
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s);
+
+/* Oneof lookups:
+ * - ntof:  look up a field by name.
+ * - ntofz: look up a field by name (as a null-terminated string).
+ * - itof:  look up a field by number. */
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length);
+UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
+                                                  const char *name) {
+  return upb_oneofdef_ntof(o, name, strlen(name));
+}
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
+
+/*  upb_oneof_iter i;
+ *  for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
+void upb_oneof_next(upb_oneof_iter *iter);
+bool upb_oneof_done(upb_oneof_iter *iter);
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
+void upb_oneof_iter_setdone(upb_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::FileDef ***************************************************************/
+
+#ifdef __cplusplus
+
+/* Class that represents a .proto file with some things defined in it.
+ *
+ * Many users won't care about FileDefs, but they are necessary if you want to
+ * read the values of file-level options. */
+class upb::FileDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<FileDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Get/set name of the file (eg. "foo/bar.proto"). */
+  const char* name() const;
+  bool set_name(const char* name, Status* s);
+  bool set_name(const std::string& name, Status* s);
+
+  /* Package name for definitions inside the file (eg. "foo.bar"). */
+  const char* package() const;
+  bool set_package(const char* package, Status* s);
+
+  /* Syntax for the file.  Defaults to proto2. */
+  upb_syntax_t syntax() const;
+  void set_syntax(upb_syntax_t syntax);
+
+  /* Get the list of defs from the file.  These are returned in the order that
+   * they were added to the FileDef. */
+  int def_count() const;
+  const Def* def(int index) const;
+  Def* def(int index);
+
+  /* Get the list of dependencies from the file.  These are returned in the
+   * order that they were added to the FileDef. */
+  int dependency_count() const;
+  const FileDef* dependency(int index) const;
+
+  /* Adds defs to this file.  The def must not already belong to another
+   * file.
+   *
+   * Note: this does *not* ensure that this def's name is unique in this file!
+   * Use a SymbolTable if you want to check this property.  Especially since
+   * properly checking uniqueness would require a check across *all* files
+   * (including dependencies). */
+  bool AddDef(Def* def, Status* s);
+  bool AddMessage(MessageDef* m, Status* s);
+  bool AddEnum(EnumDef* e, Status* s);
+  bool AddExtension(FieldDef* f, Status* s);
+
+  /* Adds a dependency of this file. */
+  bool AddDependency(const FileDef* file);
+
+  /* Freezes this FileDef and all messages/enums under it.  All subdefs must be
+   * resolved and all messages/enums must validate.  Returns true if this
+   * succeeded.
+   *
+   * TODO(haberman): should we care whether the file's dependencies are frozen
+   * already? */
+  bool Freeze(Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(FileDef, upb::FileDef)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+upb_filedef *upb_filedef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_msgdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_filedef, upb_filedef_upcast)
+
+const char *upb_filedef_name(const upb_filedef *f);
+const char *upb_filedef_package(const upb_filedef *f);
+upb_syntax_t upb_filedef_syntax(const upb_filedef *f);
+size_t upb_filedef_defcount(const upb_filedef *f);
+size_t upb_filedef_depcount(const upb_filedef *f);
+const upb_def *upb_filedef_def(const upb_filedef *f, size_t i);
+const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i);
+
+bool upb_filedef_freeze(upb_filedef *f, upb_status *s);
+bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s);
+bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s);
+bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, upb_status *s);
+
+bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor,
+                        upb_status *s);
+bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep);
+
+UPB_INLINE bool upb_filedef_addmsg(upb_filedef *f, upb_msgdef *m,
+                                   const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(f, upb_msgdef_upcast_mutable(m), ref_donor, s);
+}
+
+UPB_INLINE bool upb_filedef_addenum(upb_filedef *f, upb_enumdef *e,
+                                    const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(f, upb_enumdef_upcast_mutable(e), ref_donor, s);
+}
+
+UPB_INLINE bool upb_filedef_addext(upb_filedef *file, upb_fielddef *f,
+                                   const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(file, upb_fielddef_upcast_mutable(f), ref_donor, s);
+}
+UPB_INLINE upb_def *upb_filedef_mutabledef(upb_filedef *f, int i) {
+  return (upb_def*)upb_filedef_def(f, i);
+}
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+UPB_INLINE const char* upb_safecstr(const std::string& str) {
+  assert(str.size() == std::strlen(str.c_str()));
+  return str.c_str();
+}
+
+/* Inline C++ wrappers. */
+namespace upb {
+
+inline Def* Def::Dup(const void* owner) const {
+  return upb_def_dup(this, owner);
+}
+inline Def::Type Def::def_type() const { return upb_def_type(this); }
+inline const char* Def::full_name() const { return upb_def_fullname(this); }
+inline const char* Def::name() const { return upb_def_name(this); }
+inline bool Def::set_full_name(const char* fullname, Status* s) {
+  return upb_def_setfullname(this, fullname, s);
+}
+inline bool Def::set_full_name(const std::string& fullname, Status* s) {
+  return upb_def_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool Def::Freeze(Def* const* defs, size_t n, Status* status) {
+  return upb_def_freeze(defs, n, status);
+}
+inline bool Def::Freeze(const std::vector<Def*>& defs, Status* status) {
+  return upb_def_freeze((Def* const*)&defs[0], defs.size(), status);
+}
+
+inline bool FieldDef::CheckType(int32_t val) {
+  return upb_fielddef_checktype(val);
+}
+inline bool FieldDef::CheckLabel(int32_t val) {
+  return upb_fielddef_checklabel(val);
+}
+inline bool FieldDef::CheckDescriptorType(int32_t val) {
+  return upb_fielddef_checkdescriptortype(val);
+}
+inline bool FieldDef::CheckIntegerFormat(int32_t val) {
+  return upb_fielddef_checkintfmt(val);
+}
+inline FieldDef::Type FieldDef::ConvertType(int32_t val) {
+  assert(CheckType(val));
+  return static_cast<FieldDef::Type>(val);
+}
+inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) {
+  assert(CheckLabel(val));
+  return static_cast<FieldDef::Label>(val);
+}
+inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) {
+  assert(CheckDescriptorType(val));
+  return static_cast<FieldDef::DescriptorType>(val);
+}
+inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
+  assert(CheckIntegerFormat(val));
+  return static_cast<FieldDef::IntegerFormat>(val);
+}
+
+inline reffed_ptr<FieldDef> FieldDef::New() {
+  upb_fielddef *f = upb_fielddef_new(&f);
+  return reffed_ptr<FieldDef>(f, &f);
+}
+inline FieldDef* FieldDef::Dup(const void* owner) const {
+  return upb_fielddef_dup(this, owner);
+}
+inline const char* FieldDef::full_name() const {
+  return upb_fielddef_fullname(this);
+}
+inline bool FieldDef::set_full_name(const char* fullname, Status* s) {
+  return upb_fielddef_setfullname(this, fullname, s);
+}
+inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_fielddef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool FieldDef::type_is_set() const {
+  return upb_fielddef_typeisset(this);
+}
+inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); }
+inline FieldDef::DescriptorType FieldDef::descriptor_type() const {
+  return upb_fielddef_descriptortype(this);
+}
+inline FieldDef::Label FieldDef::label() const {
+  return upb_fielddef_label(this);
+}
+inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); }
+inline const char* FieldDef::name() const { return upb_fielddef_name(this); }
+inline bool FieldDef::is_extension() const {
+  return upb_fielddef_isextension(this);
+}
+inline size_t FieldDef::GetJsonName(char* buf, size_t len) const {
+  return upb_fielddef_getjsonname(this, buf, len);
+}
+inline bool FieldDef::lazy() const {
+  return upb_fielddef_lazy(this);
+}
+inline void FieldDef::set_lazy(bool lazy) {
+  upb_fielddef_setlazy(this, lazy);
+}
+inline bool FieldDef::packed() const {
+  return upb_fielddef_packed(this);
+}
+inline uint32_t FieldDef::index() const {
+  return upb_fielddef_index(this);
+}
+inline void FieldDef::set_packed(bool packed) {
+  upb_fielddef_setpacked(this, packed);
+}
+inline const MessageDef* FieldDef::containing_type() const {
+  return upb_fielddef_containingtype(this);
+}
+inline const OneofDef* FieldDef::containing_oneof() const {
+  return upb_fielddef_containingoneof(this);
+}
+inline const char* FieldDef::containing_type_name() {
+  return upb_fielddef_containingtypename(this);
+}
+inline bool FieldDef::set_number(uint32_t number, Status* s) {
+  return upb_fielddef_setnumber(this, number, s);
+}
+inline bool FieldDef::set_name(const char *name, Status* s) {
+  return upb_fielddef_setname(this, name, s);
+}
+inline bool FieldDef::set_name(const std::string& name, Status* s) {
+  return upb_fielddef_setname(this, upb_safecstr(name), s);
+}
+inline bool FieldDef::set_json_name(const char *name, Status* s) {
+  return upb_fielddef_setjsonname(this, name, s);
+}
+inline bool FieldDef::set_json_name(const std::string& name, Status* s) {
+  return upb_fielddef_setjsonname(this, upb_safecstr(name), s);
+}
+inline void FieldDef::clear_json_name() {
+  upb_fielddef_clearjsonname(this);
+}
+inline bool FieldDef::set_containing_type_name(const char *name, Status* s) {
+  return upb_fielddef_setcontainingtypename(this, name, s);
+}
+inline bool FieldDef::set_containing_type_name(const std::string &name,
+                                               Status *s) {
+  return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s);
+}
+inline void FieldDef::set_type(upb_fieldtype_t type) {
+  upb_fielddef_settype(this, type);
+}
+inline void FieldDef::set_is_extension(bool is_extension) {
+  upb_fielddef_setisextension(this, is_extension);
+}
+inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) {
+  upb_fielddef_setdescriptortype(this, type);
+}
+inline void FieldDef::set_label(upb_label_t label) {
+  upb_fielddef_setlabel(this, label);
+}
+inline bool FieldDef::IsSubMessage() const {
+  return upb_fielddef_issubmsg(this);
+}
+inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); }
+inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); }
+inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); }
+inline int64_t FieldDef::default_int64() const {
+  return upb_fielddef_defaultint64(this);
+}
+inline int32_t FieldDef::default_int32() const {
+  return upb_fielddef_defaultint32(this);
+}
+inline uint64_t FieldDef::default_uint64() const {
+  return upb_fielddef_defaultuint64(this);
+}
+inline uint32_t FieldDef::default_uint32() const {
+  return upb_fielddef_defaultuint32(this);
+}
+inline bool FieldDef::default_bool() const {
+  return upb_fielddef_defaultbool(this);
+}
+inline float FieldDef::default_float() const {
+  return upb_fielddef_defaultfloat(this);
+}
+inline double FieldDef::default_double() const {
+  return upb_fielddef_defaultdouble(this);
+}
+inline const char* FieldDef::default_string(size_t* len) const {
+  return upb_fielddef_defaultstr(this, len);
+}
+inline void FieldDef::set_default_int64(int64_t value) {
+  upb_fielddef_setdefaultint64(this, value);
+}
+inline void FieldDef::set_default_int32(int32_t value) {
+  upb_fielddef_setdefaultint32(this, value);
+}
+inline void FieldDef::set_default_uint64(uint64_t value) {
+  upb_fielddef_setdefaultuint64(this, value);
+}
+inline void FieldDef::set_default_uint32(uint32_t value) {
+  upb_fielddef_setdefaultuint32(this, value);
+}
+inline void FieldDef::set_default_bool(bool value) {
+  upb_fielddef_setdefaultbool(this, value);
+}
+inline void FieldDef::set_default_float(float value) {
+  upb_fielddef_setdefaultfloat(this, value);
+}
+inline void FieldDef::set_default_double(double value) {
+  upb_fielddef_setdefaultdouble(this, value);
+}
+inline bool FieldDef::set_default_string(const void *str, size_t len,
+                                         Status *s) {
+  return upb_fielddef_setdefaultstr(this, str, len, s);
+}
+inline bool FieldDef::set_default_string(const std::string& str, Status* s) {
+  return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s);
+}
+inline void FieldDef::set_default_cstr(const char* str, Status* s) {
+  return upb_fielddef_setdefaultcstr(this, str, s);
+}
+inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); }
+inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); }
+inline const MessageDef *FieldDef::message_subdef() const {
+  return upb_fielddef_msgsubdef(this);
+}
+inline const EnumDef *FieldDef::enum_subdef() const {
+  return upb_fielddef_enumsubdef(this);
+}
+inline const char* FieldDef::subdef_name() const {
+  return upb_fielddef_subdefname(this);
+}
+inline bool FieldDef::set_subdef(const Def* subdef, Status* s) {
+  return upb_fielddef_setsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) {
+  return upb_fielddef_setenumsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) {
+  return upb_fielddef_setmsgsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_subdef_name(const char* name, Status* s) {
+  return upb_fielddef_setsubdefname(this, name, s);
+}
+inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
+  return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
+}
+
+inline reffed_ptr<MessageDef> MessageDef::New() {
+  upb_msgdef *m = upb_msgdef_new(&m);
+  return reffed_ptr<MessageDef>(m, &m);
+}
+inline const char *MessageDef::full_name() const {
+  return upb_msgdef_fullname(this);
+}
+inline const char *MessageDef::name() const {
+  return upb_msgdef_name(this);
+}
+inline upb_syntax_t MessageDef::syntax() const {
+  return upb_msgdef_syntax(this);
+}
+inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
+  return upb_msgdef_setfullname(this, fullname, s);
+}
+inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool MessageDef::set_syntax(upb_syntax_t syntax) {
+  return upb_msgdef_setsyntax(this, syntax);
+}
+inline bool MessageDef::Freeze(Status* status) {
+  return upb_msgdef_freeze(this, status);
+}
+inline int MessageDef::field_count() const {
+  return upb_msgdef_numfields(this);
+}
+inline int MessageDef::oneof_count() const {
+  return upb_msgdef_numoneofs(this);
+}
+inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
+  return upb_msgdef_addfield(this, f, NULL, s);
+}
+inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
+  return upb_msgdef_addfield(this, f.get(), NULL, s);
+}
+inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) {
+  return upb_msgdef_addoneof(this, o, NULL, s);
+}
+inline bool MessageDef::AddOneof(const reffed_ptr<OneofDef>& o, Status* s) {
+  return upb_msgdef_addoneof(this, o.get(), NULL, s);
+}
+inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
+  return upb_msgdef_itof_mutable(this, number);
+}
+inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) {
+  return upb_msgdef_ntof_mutable(this, name, len);
+}
+inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const {
+  return upb_msgdef_itof(this, number);
+}
+inline const FieldDef *MessageDef::FindFieldByName(const char *name,
+                                                   size_t len) const {
+  return upb_msgdef_ntof(this, name, len);
+}
+inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) {
+  return upb_msgdef_ntoo_mutable(this, name, len);
+}
+inline const OneofDef* MessageDef::FindOneofByName(const char* name,
+                                                   size_t len) const {
+  return upb_msgdef_ntoo(this, name, len);
+}
+inline MessageDef* MessageDef::Dup(const void *owner) const {
+  return upb_msgdef_dup(this, owner);
+}
+inline void MessageDef::setmapentry(bool map_entry) {
+  upb_msgdef_setmapentry(this, map_entry);
+}
+inline bool MessageDef::mapentry() const {
+  return upb_msgdef_mapentry(this);
+}
+inline MessageDef::field_iterator MessageDef::field_begin() {
+  return field_iterator(this);
+}
+inline MessageDef::field_iterator MessageDef::field_end() {
+  return field_iterator::end(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_begin() const {
+  return const_field_iterator(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_end() const {
+  return const_field_iterator::end(this);
+}
+
+inline MessageDef::oneof_iterator MessageDef::oneof_begin() {
+  return oneof_iterator(this);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_end() {
+  return oneof_iterator::end(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const {
+  return const_oneof_iterator(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const {
+  return const_oneof_iterator::end(this);
+}
+
+inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::field_iterator MessageDef::field_iterator::end(
+    MessageDef* md) {
+  MessageDef::field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* MessageDef::field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::field_iterator::operator==(
+    const field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::field_iterator::operator!=(
+    const field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_field_iterator::const_field_iterator(
+    const MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* MessageDef::const_field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::const_field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::const_field_iterator::operator==(
+    const const_field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_field_iterator::operator!=(
+    const const_field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end(
+    MessageDef* md) {
+  MessageDef::oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline OneofDef* MessageDef::oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::oneof_iterator::operator==(
+    const oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::oneof_iterator::operator!=(
+    const oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_oneof_iterator::const_oneof_iterator(
+    const MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::const_oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator==(
+    const const_oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator!=(
+    const const_oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline reffed_ptr<EnumDef> EnumDef::New() {
+  upb_enumdef *e = upb_enumdef_new(&e);
+  return reffed_ptr<EnumDef>(e, &e);
+}
+inline const char* EnumDef::full_name() const {
+  return upb_enumdef_fullname(this);
+}
+inline const char* EnumDef::name() const {
+  return upb_enumdef_name(this);
+}
+inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
+  return upb_enumdef_setfullname(this, fullname, s);
+}
+inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool EnumDef::Freeze(Status* status) {
+  return upb_enumdef_freeze(this, status);
+}
+inline int32_t EnumDef::default_value() const {
+  return upb_enumdef_default(this);
+}
+inline bool EnumDef::set_default_value(int32_t val, Status* status) {
+  return upb_enumdef_setdefault(this, val, status);
+}
+inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); }
+inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) {
+  return upb_enumdef_addval(this, name, num, status);
+}
+inline bool EnumDef::AddValue(const std::string& name, int32_t num,
+                              Status* status) {
+  return upb_enumdef_addval(this, upb_safecstr(name), num, status);
+}
+inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const {
+  return upb_enumdef_ntoiz(this, name, num);
+}
+inline const char* EnumDef::FindValueByNumber(int32_t num) const {
+  return upb_enumdef_iton(this, num);
+}
+inline EnumDef* EnumDef::Dup(const void* owner) const {
+  return upb_enumdef_dup(this, owner);
+}
+
+inline EnumDef::Iterator::Iterator(const EnumDef* e) {
+  upb_enum_begin(&iter_, e);
+}
+inline int32_t EnumDef::Iterator::number() {
+  return upb_enum_iter_number(&iter_);
+}
+inline const char* EnumDef::Iterator::name() {
+  return upb_enum_iter_name(&iter_);
+}
+inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); }
+inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); }
+
+inline reffed_ptr<OneofDef> OneofDef::New() {
+  upb_oneofdef *o = upb_oneofdef_new(&o);
+  return reffed_ptr<OneofDef>(o, &o);
+}
+
+inline const MessageDef* OneofDef::containing_type() const {
+  return upb_oneofdef_containingtype(this);
+}
+inline const char* OneofDef::name() const {
+  return upb_oneofdef_name(this);
+}
+inline bool OneofDef::set_name(const char* name, Status* s) {
+  return upb_oneofdef_setname(this, name, s);
+}
+inline bool OneofDef::set_name(const std::string& name, Status* s) {
+  return upb_oneofdef_setname(this, upb_safecstr(name), s);
+}
+inline int OneofDef::field_count() const {
+  return upb_oneofdef_numfields(this);
+}
+inline bool OneofDef::AddField(FieldDef* field, Status* s) {
+  return upb_oneofdef_addfield(this, field, NULL, s);
+}
+inline bool OneofDef::AddField(const reffed_ptr<FieldDef>& field, Status* s) {
+  return upb_oneofdef_addfield(this, field.get(), NULL, s);
+}
+inline const FieldDef* OneofDef::FindFieldByName(const char* name,
+                                                 size_t len) const {
+  return upb_oneofdef_ntof(this, name, len);
+}
+inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const {
+  return upb_oneofdef_itof(this, num);
+}
+inline OneofDef::iterator OneofDef::begin() { return iterator(this); }
+inline OneofDef::iterator OneofDef::end() { return iterator::end(this); }
+inline OneofDef::const_iterator OneofDef::begin() const {
+  return const_iterator(this);
+}
+inline OneofDef::const_iterator OneofDef::end() const {
+  return const_iterator::end(this);
+}
+
+inline OneofDef::iterator::iterator(OneofDef* o) {
+  upb_oneof_begin(&iter_, o);
+}
+inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) {
+  OneofDef::iterator iter(o);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* OneofDef::iterator::operator*() const {
+  return upb_oneof_iter_field(&iter_);
+}
+inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); }
+inline bool OneofDef::iterator::operator==(const iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::iterator::operator!=(const iterator &other) const {
+  return !(*this == other);
+}
+
+inline OneofDef::const_iterator::const_iterator(const OneofDef* md) {
+  upb_oneof_begin(&iter_, md);
+}
+inline OneofDef::const_iterator OneofDef::const_iterator::end(
+    const OneofDef *md) {
+  OneofDef::const_iterator iter(md);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* OneofDef::const_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void OneofDef::const_iterator::operator++() {
+  return upb_oneof_next(&iter_);
+}
+inline bool OneofDef::const_iterator::operator==(
+    const const_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::const_iterator::operator!=(
+    const const_iterator &other) const {
+  return !(*this == other);
+}
+
+inline reffed_ptr<FileDef> FileDef::New() {
+  upb_filedef *f = upb_filedef_new(&f);
+  return reffed_ptr<FileDef>(f, &f);
+}
+
+inline const char* FileDef::name() const {
+  return upb_filedef_name(this);
+}
+inline bool FileDef::set_name(const char* name, Status* s) {
+  return upb_filedef_setname(this, name, s);
+}
+inline bool FileDef::set_name(const std::string& name, Status* s) {
+  return upb_filedef_setname(this, upb_safecstr(name), s);
+}
+inline const char* FileDef::package() const {
+  return upb_filedef_package(this);
+}
+inline bool FileDef::set_package(const char* package, Status* s) {
+  return upb_filedef_setpackage(this, package, s);
+}
+inline int FileDef::def_count() const {
+  return upb_filedef_defcount(this);
+}
+inline const Def* FileDef::def(int index) const {
+  return upb_filedef_def(this, index);
+}
+inline Def* FileDef::def(int index) {
+  return const_cast<Def*>(upb_filedef_def(this, index));
+}
+inline int FileDef::dependency_count() const {
+  return upb_filedef_depcount(this);
+}
+inline const FileDef* FileDef::dependency(int index) const {
+  return upb_filedef_dep(this, index);
+}
+inline bool FileDef::AddDef(Def* def, Status* s) {
+  return upb_filedef_adddef(this, def, NULL, s);
+}
+inline bool FileDef::AddMessage(MessageDef* m, Status* s) {
+  return upb_filedef_addmsg(this, m, NULL, s);
+}
+inline bool FileDef::AddEnum(EnumDef* e, Status* s) {
+  return upb_filedef_addenum(this, e, NULL, s);
+}
+inline bool FileDef::AddExtension(FieldDef* f, Status* s) {
+  return upb_filedef_addext(this, f, NULL, s);
+}
+inline bool FileDef::AddDependency(const FileDef* file) {
+  return upb_filedef_adddep(this, file);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif /* UPB_DEF_H_ */
+/*
+** This file contains definitions of structs that should be considered private
+** and NOT stable across versions of upb.
+**
+** The only reason they are declared here and not in .c files is to allow upb
+** and the application (if desired) to embed statically-initialized instances
+** of structures like defs.
+**
+** If you include this file, all guarantees of ABI compatibility go out the
+** window!  Any code that includes this file needs to recompile against the
+** exact same version of upb that they are linking against.
+**
+** You also need to recompile if you change the value of the UPB_DEBUG_REFS
+** flag.
+*/
+
+
+#ifndef UPB_STATICINIT_H_
+#define UPB_STATICINIT_H_
+
+#ifdef __cplusplus
+/* Because of how we do our typedefs, this header can't be included from C++. */
+#error This file cannot be included from C++
+#endif
+
+/* upb_refcounted *************************************************************/
+
+
+/* upb_def ********************************************************************/
+
+struct upb_def {
+  upb_refcounted base;
+
+  const char *fullname;
+  const upb_filedef* file;
+  char type;  /* A upb_deftype_t (char to save space) */
+
+  /* Used as a flag during the def's mutable stage.  Must be false unless
+   * it is currently being used by a function on the stack.  This allows
+   * us to easily determine which defs were passed into the function's
+   * current invocation. */
+  bool came_from_user;
+};
+
+#define UPB_DEF_INIT(name, type, vtbl, refs, ref2s) \
+    { UPB_REFCOUNT_INIT(vtbl, refs, ref2s), name, NULL, type, false }
+
+
+/* upb_fielddef ***************************************************************/
+
+struct upb_fielddef {
+  upb_def base;
+
+  union {
+    int64_t sint;
+    uint64_t uint;
+    double dbl;
+    float flt;
+    void *bytes;
+  } defaultval;
+  union {
+    const upb_msgdef *def;  /* If !msg_is_symbolic. */
+    char *name;             /* If msg_is_symbolic. */
+  } msg;
+  union {
+    const upb_def *def;  /* If !subdef_is_symbolic. */
+    char *name;          /* If subdef_is_symbolic. */
+  } sub;  /* The msgdef or enumdef for this field, if upb_hassubdef(f). */
+  bool subdef_is_symbolic;
+  bool msg_is_symbolic;
+  const upb_oneofdef *oneof;
+  bool default_is_string;
+  bool type_is_set_;     /* False until type is explicitly set. */
+  bool is_extension_;
+  bool lazy_;
+  bool packed_;
+  upb_intfmt_t intfmt;
+  bool tagdelim;
+  upb_fieldtype_t type_;
+  upb_label_t label_;
+  uint32_t number_;
+  uint32_t selector_base;  /* Used to index into a upb::Handlers table. */
+  uint32_t index_;
+};
+
+extern const struct upb_refcounted_vtbl upb_fielddef_vtbl;
+
+#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy,   \
+                          packed, name, num, msgdef, subdef, selector_base,    \
+                          index, defaultval, refs, ref2s)                      \
+  {                                                                            \
+    UPB_DEF_INIT(name, UPB_DEF_FIELD, &upb_fielddef_vtbl, refs, ref2s),        \
+        defaultval, {msgdef}, {subdef}, NULL, false, false,                    \
+        type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \
+        lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \
+  }
+
+
+/* upb_msgdef *****************************************************************/
+
+struct upb_msgdef {
+  upb_def base;
+
+  size_t selector_count;
+  uint32_t submsg_field_count;
+
+  /* Tables for looking up fields by number and name. */
+  upb_inttable itof;  /* int to field */
+  upb_strtable ntof;  /* name to field/oneof */
+
+  /* Is this a map-entry message? */
+  bool map_entry;
+
+  /* Whether this message has proto2 or proto3 semantics. */
+  upb_syntax_t syntax;
+
+  /* TODO(haberman): proper extension ranges (there can be multiple). */
+};
+
+extern const struct upb_refcounted_vtbl upb_msgdef_vtbl;
+
+/* TODO: also support static initialization of the oneofs table. This will be
+ * needed if we compile in descriptors that contain oneofs. */
+#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
+                        map_entry, syntax, refs, ref2s)                       \
+  {                                                                           \
+    UPB_DEF_INIT(name, UPB_DEF_MSG, &upb_fielddef_vtbl, refs, ref2s),         \
+        selector_count, submsg_field_count, itof, ntof, map_entry, syntax     \
+  }
+
+
+/* upb_enumdef ****************************************************************/
+
+struct upb_enumdef {
+  upb_def base;
+
+  upb_strtable ntoi;
+  upb_inttable iton;
+  int32_t defaultval;
+};
+
+extern const struct upb_refcounted_vtbl upb_enumdef_vtbl;
+
+#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \
+  { UPB_DEF_INIT(name, UPB_DEF_ENUM, &upb_enumdef_vtbl, refs, ref2s), ntoi,    \
+    iton, defaultval }
+
+
+/* upb_oneofdef ***************************************************************/
+
+struct upb_oneofdef {
+  upb_refcounted base;
+
+  const char *name;
+  upb_strtable ntof;
+  upb_inttable itof;
+  const upb_msgdef *parent;
+};
+
+extern const struct upb_refcounted_vtbl upb_oneofdef_vtbl;
+
+#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
+  { UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), name, ntof, itof }
+
+
+/* upb_symtab *****************************************************************/
+
+struct upb_symtab {
+  upb_refcounted base;
+
+  upb_strtable symtab;
+};
+
+struct upb_filedef {
+  upb_refcounted base;
+
+  const char *name;
+  const char *package;
+  upb_syntax_t syntax;
+
+  upb_inttable defs;
+  upb_inttable deps;
+};
+
+extern const struct upb_refcounted_vtbl upb_filedef_vtbl;
+
+#endif  /* UPB_STATICINIT_H_ */
+/*
+** upb::Handlers (upb_handlers)
+**
+** A upb_handlers is like a virtual table for a upb_msgdef.  Each field of the
+** message can have associated functions that will be called when we are
+** parsing or visiting a stream of data.  This is similar to how handlers work
+** in SAX (the Simple API for XML).
+**
+** The handlers have no idea where the data is coming from, so a single set of
+** handlers could be used with two completely different data sources (for
+** example, a parser and a visitor over in-memory objects).  This decoupling is
+** the most important feature of upb, because it allows parsers and serializers
+** to be highly reusable.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_HANDLERS_H
+#define UPB_HANDLERS_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferHandle;
+class BytesHandler;
+class HandlerAttributes;
+class Handlers;
+template <class T> class Handler;
+template <class T> struct CanonicalType;
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle)
+UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler)
+UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr)
+UPB_DECLARE_DERIVED_TYPE(upb::Handlers, upb::RefCounted,
+                         upb_handlers, upb_refcounted)
+
+/* The maximum depth that the handler graph can have.  This is a resource limit
+ * for the C stack since we sometimes need to recursively traverse the graph.
+ * Cycles are ok; the traversal will stop when it detects a cycle, but we must
+ * hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Handlers::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_HANDLER_DEPTH 64
+
+/* All the different types of handlers that can be registered.
+ * Only needed for the advanced functions in upb::Handlers. */
+typedef enum {
+  UPB_HANDLER_INT32,
+  UPB_HANDLER_INT64,
+  UPB_HANDLER_UINT32,
+  UPB_HANDLER_UINT64,
+  UPB_HANDLER_FLOAT,
+  UPB_HANDLER_DOUBLE,
+  UPB_HANDLER_BOOL,
+  UPB_HANDLER_STARTSTR,
+  UPB_HANDLER_STRING,
+  UPB_HANDLER_ENDSTR,
+  UPB_HANDLER_STARTSUBMSG,
+  UPB_HANDLER_ENDSUBMSG,
+  UPB_HANDLER_STARTSEQ,
+  UPB_HANDLER_ENDSEQ
+} upb_handlertype_t;
+
+#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
+
+#define UPB_BREAK NULL
+
+/* A convenient definition for when no closure is needed. */
+extern char _upb_noclosure;
+#define UPB_NO_CLOSURE &_upb_noclosure
+
+/* A selector refers to a specific field handler in the Handlers object
+ * (for example: the STARTSUBMSG handler for field "field15"). */
+typedef int32_t upb_selector_t;
+
+UPB_BEGIN_EXTERN_C
+
+/* Forward-declares for C inline accessors.  We need to declare these here
+ * so we can "friend" them in the class declarations in C++. */
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s);
+UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s);
+
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h);
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type);
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs);
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h);
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h);
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h);
+
+UPB_END_EXTERN_C
+
+
+/* Static selectors for upb::Handlers. */
+#define UPB_STARTMSG_SELECTOR 0
+#define UPB_ENDMSG_SELECTOR 1
+#define UPB_STATIC_SELECTOR_COUNT 2
+
+/* Static selectors for upb::BytesHandler. */
+#define UPB_STARTSTR_SELECTOR 0
+#define UPB_STRING_SELECTOR 1
+#define UPB_ENDSTR_SELECTOR 2
+
+typedef void upb_handlerfree(void *d);
+
+#ifdef __cplusplus
+
+/* A set of attributes that accompanies a handler's function pointer. */
+class upb::HandlerAttributes {
+ public:
+  HandlerAttributes();
+  ~HandlerAttributes();
+
+  /* Sets the handler data that will be passed as the second parameter of the
+   * handler.  To free this pointer when the handlers are freed, call
+   * Handlers::AddCleanup(). */
+  bool SetHandlerData(const void *handler_data);
+  const void* handler_data() const;
+
+  /* Use this to specify the type of the closure.  This will be checked against
+   * all other closure types for handler that use the same closure.
+   * Registration will fail if this does not match all other non-NULL closure
+   * types. */
+  bool SetClosureType(const void *closure_type);
+  const void* closure_type() const;
+
+  /* Use this to specify the type of the returned closure.  Only used for
+   * Start*{String,SubMessage,Sequence} handlers.  This must match the closure
+   * type of any handlers that use it (for example, the StringBuf handler must
+   * match the closure returned from StartString). */
+  bool SetReturnClosureType(const void *return_closure_type);
+  const void* return_closure_type() const;
+
+  /* Set to indicate that the handler always returns "ok" (either "true" or a
+   * non-NULL closure).  This is a hint that can allow code generators to
+   * generate more efficient code. */
+  bool SetAlwaysOk(bool always_ok);
+  bool always_ok() const;
+
+ private:
+  friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
+      const upb_handlerattr *attr);
+#else
+struct upb_handlerattr {
+#endif
+  const void *handler_data_;
+  const void *closure_type_;
+  const void *return_closure_type_;
+  bool alwaysok_;
+};
+
+#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false}
+
+typedef struct {
+  upb_func *func;
+
+  /* It is wasteful to include the entire attributes here:
+   *
+   * * Some of the information is redundant (like storing the closure type
+   *   separately for each handler that must match).
+   * * Some of the info is only needed prior to freeze() (like closure types).
+   * * alignment padding wastes a lot of space for alwaysok_.
+   *
+   * If/when the size and locality of handlers is an issue, we can optimize this
+   * not to store the entire attr like this.  We do not expose the table's
+   * layout to allow this optimization in the future. */
+  upb_handlerattr attr;
+} upb_handlers_tabent;
+
+#ifdef __cplusplus
+
+/* Extra information about a buffer that is passed to a StringBuf handler.
+ * TODO(haberman): allow the handle to be pinned so that it will outlive
+ * the handler invocation. */
+class upb::BufferHandle {
+ public:
+  BufferHandle();
+  ~BufferHandle();
+
+  /* The beginning of the buffer.  This may be different than the pointer
+   * passed to a StringBuf handler because the handler may receive data
+   * that is from the middle or end of a larger buffer. */
+  const char* buffer() const;
+
+  /* The offset within the attached object where this buffer begins.  Only
+   * meaningful if there is an attached object. */
+  size_t object_offset() const;
+
+  /* Note that object_offset is the offset of "buf" within the attached
+   * object. */
+  void SetBuffer(const char* buf, size_t object_offset);
+
+  /* The BufferHandle can have an "attached object", which can be used to
+   * tunnel through a pointer to the buffer's underlying representation. */
+  template <class T>
+  void SetAttachedObject(const T* obj);
+
+  /* Returns NULL if the attached object is not of this type. */
+  template <class T>
+  const T* GetAttachedObject() const;
+
+ private:
+  friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h);
+  friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h,
+                                                const void *obj,
+                                                const void *type);
+  friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h,
+                                                const char *buf, size_t ofs);
+  friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h);
+  friend UPB_INLINE const void* ::upb_bufhandle_objtype(
+      const upb_bufhandle *h);
+  friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h);
+#else
+struct upb_bufhandle {
+#endif
+  const char *buf_;
+  const void *obj_;
+  const void *objtype_;
+  size_t objofs_;
+};
+
+#ifdef __cplusplus
+
+/* A upb::Handlers object represents the set of handlers associated with a
+ * message in the graph of messages.  You can think of it as a big virtual
+ * table with functions corresponding to all the events that can fire while
+ * parsing or visiting a message of a specific type.
+ *
+ * Any handlers that are not set behave as if they had successfully consumed
+ * the value.  Any unset Start* handlers will propagate their closure to the
+ * inner frame.
+ *
+ * The easiest way to create the *Handler objects needed by the Set* methods is
+ * with the UpbBind() and UpbMakeHandler() macros; see below. */
+class upb::Handlers {
+ public:
+  typedef upb_selector_t Selector;
+  typedef upb_handlertype_t Type;
+
+  typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
+  typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler;
+  typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
+  typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
+                             const BufferHandle *)> StringHandler;
+
+  template <class T> struct ValueHandler {
+    typedef Handler<bool(*)(void *, const void *, T)> H;
+  };
+
+  typedef ValueHandler<int32_t>::H     Int32Handler;
+  typedef ValueHandler<int64_t>::H     Int64Handler;
+  typedef ValueHandler<uint32_t>::H    UInt32Handler;
+  typedef ValueHandler<uint64_t>::H    UInt64Handler;
+  typedef ValueHandler<float>::H       FloatHandler;
+  typedef ValueHandler<double>::H      DoubleHandler;
+  typedef ValueHandler<bool>::H        BoolHandler;
+
+  /* Any function pointer can be converted to this and converted back to its
+   * correct type. */
+  typedef void GenericFunction();
+
+  typedef void HandlersCallback(const void *closure, upb_handlers *h);
+
+  /* Returns a new handlers object for the given frozen msgdef.
+   * Returns NULL if memory allocation failed. */
+  static reffed_ptr<Handlers> New(const MessageDef *m);
+
+  /* Convenience function for registering a graph of handlers that mirrors the
+   * graph of msgdefs for some message.  For "m" and all its children a new set
+   * of handlers will be created and the given callback will be invoked,
+   * allowing the client to register handlers for this message.  Note that any
+   * subhandlers set by the callback will be overwritten. */
+  static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
+                                              HandlersCallback *callback,
+                                              const void *closure);
+
+  /* Functionality from upb::RefCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* All handler registration functions return bool to indicate success or
+   * failure; details about failures are stored in this status object.  If a
+   * failure does occur, it must be cleared before the Handlers are frozen,
+   * otherwise the freeze() operation will fail.  The functions may *only* be
+   * used while the Handlers are mutable. */
+  const Status* status();
+  void ClearError();
+
+  /* Call to freeze these Handlers.  Requires that any SubHandlers are already
+   * frozen.  For cycles, you must use the static version below and freeze the
+   * whole graph at once. */
+  bool Freeze(Status* s);
+
+  /* Freezes the given set of handlers.  You may not freeze a handler without
+   * also freezing any handlers they point to. */
+  static bool Freeze(Handlers*const* handlers, int n, Status* s);
+  static bool Freeze(const std::vector<Handlers*>& handlers, Status* s);
+
+  /* Returns the msgdef associated with this handlers object. */
+  const MessageDef* message_def() const;
+
+  /* Adds the given pointer and function to the list of cleanup functions that
+   * will be run when these handlers are freed.  If this pointer has previously
+   * been registered, the function returns false and does nothing. */
+  bool AddCleanup(void *ptr, upb_handlerfree *cleanup);
+
+  /* Sets the startmsg handler for the message, which is defined as follows:
+   *
+   *   bool startmsg(MyType* closure) {
+   *     // Called when the message begins.  Returns true if processing should
+   *     // continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartMessageHandler(const StartMessageHandler& handler);
+
+  /* Sets the endmsg handler for the message, which is defined as follows:
+   *
+   *   bool endmsg(MyType* closure, upb_status *status) {
+   *     // Called when processing of this message ends, whether in success or
+   *     // failure.  "status" indicates the final status of processing, and
+   *     // can also be modified in-place to update the final status.
+   *   }
+   */
+  bool SetEndMessageHandler(const EndMessageHandler& handler);
+
+  /* Sets the value handler for the given field, which is defined as follows
+   * (this is for an int32 field; other field types will pass their native
+   * C/C++ type for "val"):
+   *
+   *   bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
+   *     // Called when the field's value is encountered.  "d" contains
+   *     // whatever data was bound to this field when it was registered.
+   *     // Returns true if processing should continue.
+   *     return true;
+   *   }
+   *
+   *   handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
+   *
+   * The value type must exactly match f->type().
+   * For example, a handler that takes an int32_t parameter may only be used for
+   * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
+   *
+   * Returns false if the handler failed to register; in this case the cleanup
+   * handler (if any) will be called immediately.
+   */
+  bool SetInt32Handler (const FieldDef* f,  const Int32Handler& h);
+  bool SetInt64Handler (const FieldDef* f,  const Int64Handler& h);
+  bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h);
+  bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h);
+  bool SetFloatHandler (const FieldDef* f,  const FloatHandler& h);
+  bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h);
+  bool SetBoolHandler  (const FieldDef* f,   const BoolHandler& h);
+
+  /* Like the previous, but templated on the type on the value (ie. int32).
+   * This is mostly useful to call from other templates.  To call this you must
+   * specify the template parameter explicitly, ie:
+   *   h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData)); */
+  template <class T>
+  bool SetValueHandler(
+      const FieldDef *f,
+      const typename ValueHandler<typename CanonicalType<T>::Type>::H& handler);
+
+  /* Sets handlers for a string field, which are defined as follows:
+   *
+   *   MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
+   *                          size_t size_hint) {
+   *     // Called when a string value begins.  The return value indicates the
+   *     // closure for the string.  "size_hint" indicates the size of the
+   *     // string if it is known, however if the string is length-delimited
+   *     // and the end-of-string is not available size_hint will be zero.
+   *     // This case is indistinguishable from the case where the size is
+   *     // known to be zero.
+   *     //
+   *     // TODO(haberman): is it important to distinguish these cases?
+   *     // If we had ssize_t as a type we could make -1 "unknown", but
+   *     // ssize_t is POSIX (not ANSI) and therefore less portable.
+   *     // In practice I suspect it won't be important to distinguish.
+   *     return closure;
+   *   }
+   *
+   *   size_t str(MyClosure* closure, const MyHandlerData* d,
+   *              const char *str, size_t len) {
+   *     // Called for each buffer of string data; the multiple physical buffers
+   *     // are all part of the same logical string.  The return value indicates
+   *     // how many bytes were consumed.  If this number is less than "len",
+   *     // this will also indicate that processing should be halted for now,
+   *     // like returning false or UPB_BREAK from any other callback.  If
+   *     // number is greater than "len", the excess bytes will be skipped over
+   *     // and not passed to the callback.
+   *     return len;
+   *   }
+   *
+   *   bool endstr(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a string value ends.  Return value indicates whether
+   *     // processing should continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h);
+  bool SetStringHandler(const FieldDef* f, const StringHandler& h);
+  bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets the startseq handler, which is defined as follows:
+   *
+   *   MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence (repeated field) begins.  The returned
+   *     // pointer indicates the closure for the sequence (or UPB_BREAK
+   *     // to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the startsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage begins.  The returned pointer indicates the
+   *     // closure for the sequence (or UPB_BREAK to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
+   *                                           new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the endsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage ends.  Returns true to continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h);
+
+  /* Starts the endsubseq handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence ends.  Returns true continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets or gets the object that specifies handlers for the given field, which
+   * must be a submessage or group.  Returns NULL if no handlers are set. */
+  bool SetSubHandlers(const FieldDef* f, const Handlers* sub);
+  const Handlers* GetSubHandlers(const FieldDef* f) const;
+
+  /* Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the
+   * field. */
+  const Handlers* GetSubHandlers(Selector startsubmsg) const;
+
+  /* A selector refers to a specific field handler in the Handlers object
+   * (for example: the STARTSUBMSG handler for field "field15").
+   * On success, returns true and stores the selector in "s".
+   * If the FieldDef or Type are invalid, returns false.
+   * The returned selector is ONLY valid for Handlers whose MessageDef
+   * contains this FieldDef. */
+  static bool GetSelector(const FieldDef* f, Type type, Selector* s);
+
+  /* Given a START selector of any kind, returns the corresponding END selector. */
+  static Selector GetEndSelector(Selector start_selector);
+
+  /* Returns the function pointer for this handler.  It is the client's
+   * responsibility to cast to the correct function type before calling it. */
+  GenericFunction* GetHandler(Selector selector);
+
+  /* Sets the given attributes to the attributes for this selector. */
+  bool GetAttributes(Selector selector, HandlerAttributes* attr);
+
+  /* Returns the handler data that was registered with this handler. */
+  const void* GetHandlerData(Selector selector);
+
+  /* Could add any of the following functions as-needed, with some minor
+   * implementation changes:
+   *
+   * const FieldDef* GetFieldDef(Selector selector);
+   * static bool IsSequence(Selector selector); */
+
+ private:
+  UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers)
+
+  friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
+      const upb_handlers *h, upb_selector_t s);
+  friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
+      const upb_handlers *h, upb_selector_t s);
+#else
+struct upb_handlers {
+#endif
+  upb_refcounted base;
+
+  const upb_msgdef *msg;
+  const upb_handlers **sub;
+  const void *top_closure_type;
+  upb_inttable cleanup_;
+  upb_status status_;  /* Used only when mutable. */
+  upb_handlers_tabent table[1];  /* Dynamically-sized field handler array. */
+};
+
+#ifdef __cplusplus
+
+namespace upb {
+
+/* Convenience macros for creating a Handler object that is wrapped with a
+ * type-safe wrapper function that converts the "void*" parameters/returns
+ * of the underlying C API into nice C++ function.
+ *
+ * Sample usage:
+ *   void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that doesn't need any data bound to it.
+ *   void OnValue2(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that returns bool so it can return failure if necessary.
+ *   bool OnValue3(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *     return ok;
+ *   }
+ *
+ *   // Member function handler.
+ *   class MyClosure {
+ *    public:
+ *     void OnValue(int32_t val) {
+ *       // do stuff ...
+ *     }
+ *   };
+ *
+ *   // Takes ownership of the MyHandlerData.
+ *   handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
+ *   handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
+ */
+
+#ifdef UPB_CXX11
+
+/* In C++11, the "template" disambiguator can appear even outside templates,
+ * so all calls can safely use this pair of macros. */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+#else
+
+/* Prior to C++11, the "template" disambiguator may only appear inside a
+ * template, so the regular macro must not use "template" */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
+
+#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
+
+#endif  /* UPB_CXX11 */
+
+/* This macro must be used in C++98 for calls from inside a template.  But we
+ * define this variant in all cases; code that wants to be compatible with both
+ * C++98 and C++11 should always use this macro when calling from a template. */
+#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+/* Handler: a struct that contains the (handler, data, deleter) tuple that is
+ * used to register all handlers.  Users can Make() these directly but it's
+ * more convenient to use the UpbMakeHandler/UpbBind macros above. */
+template <class T> class Handler {
+ public:
+  /* The underlying, handler function signature that upb uses internally. */
+  typedef T FuncPtr;
+
+  /* Intentionally implicit. */
+  template <class F> Handler(F func);
+  ~Handler();
+
+ private:
+  void AddCleanup(Handlers* h) const {
+    if (cleanup_func_) {
+      bool ok = h->AddCleanup(cleanup_data_, cleanup_func_);
+      UPB_ASSERT_VAR(ok, ok);
+    }
+  }
+
+  UPB_DISALLOW_COPY_AND_ASSIGN(Handler)
+  friend class Handlers;
+  FuncPtr handler_;
+  mutable HandlerAttributes attr_;
+  mutable bool registered_;
+  void *cleanup_data_;
+  upb_handlerfree *cleanup_func_;
+};
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+/* Handler function typedefs. */
+typedef bool upb_startmsg_handlerfunc(void *c, const void*);
+typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
+typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
+typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
+typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
+typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
+typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
+typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
+typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
+typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
+                                       size_t size_hint);
+typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
+                                      size_t n, const upb_bufhandle* handle);
+
+/* upb_bufhandle */
+size_t upb_bufhandle_objofs(const upb_bufhandle *h);
+
+/* upb_handlerattr */
+void upb_handlerattr_init(upb_handlerattr *attr);
+void upb_handlerattr_uninit(upb_handlerattr *attr);
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd);
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type);
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type);
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok);
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlerattr_handlerdata(
+    const upb_handlerattr *attr) {
+  return attr->handler_data_;
+}
+
+/* upb_handlers */
+typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
+upb_handlers *upb_handlers_new(const upb_msgdef *m,
+                               const void *owner);
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure);
+
+/* Include refcounted methods like upb_handlers_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_handlers, upb_handlers_upcast)
+
+const upb_status *upb_handlers_status(upb_handlers *h);
+void upb_handlers_clearerr(upb_handlers *h);
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
+                           upb_int32_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
+                           upb_int64_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint32_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint64_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
+                           upb_float_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
+                            upb_double_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
+                          upb_bool_handlerfunc *func,
+                          upb_handlerattr *attr);
+bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
+                              upb_startstr_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
+                            upb_string_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
+                              upb_startfield_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
+                                 upb_startfield_handlerfunc *func,
+                                 upb_handlerattr *attr);
+bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
+                               upb_endfield_handlerfunc *func,
+                               upb_handlerattr *attr);
+bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub);
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f);
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel);
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s) {
+  return (upb_func *)h->table[s].func;
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
+                          upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s) {
+  return upb_handlerattr_handlerdata(&h->table[s].attr);
+}
+
+#ifdef __cplusplus
+
+/* Handler types for single fields.
+ * Right now we only have one for TYPE_BYTES but ones for other types
+ * should follow.
+ *
+ * These follow the same handlers protocol for fields of a message. */
+class upb::BytesHandler {
+ public:
+  BytesHandler();
+  ~BytesHandler();
+#else
+struct upb_byteshandler {
+#endif
+  upb_handlers_tabent table[3];
+};
+
+void upb_byteshandler_init(upb_byteshandler *h);
+
+/* Caller must ensure that "d" outlives the handlers.
+ * TODO(haberman): should this have a "freeze" operation?  It's not necessary
+ * for memory management, but could be useful to force immutability and provide
+ * a convenient moment to verify that all registration succeeded. */
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d);
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d);
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d);
+
+/* "Static" methods */
+bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s);
+UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
+  return start + 1;
+}
+
+/* Internal-only. */
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
+
+UPB_END_EXTERN_C
+
+/*
+** Inline definitions for handlers.h, which are particularly long and a bit
+** tricky.
+*/
+
+#ifndef UPB_HANDLERS_INL_H_
+#define UPB_HANDLERS_INL_H_
+
+#include <limits.h>
+
+/* C inline methods. */
+
+/* upb_bufhandle */
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) {
+  h->obj_ = NULL;
+  h->objtype_ = NULL;
+  h->buf_ = NULL;
+  h->objofs_ = 0;
+}
+UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) {
+  UPB_UNUSED(h);
+}
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type) {
+  h->obj_ = obj;
+  h->objtype_ = type;
+}
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs) {
+  h->buf_ = buf;
+  h->objofs_ = ofs;
+}
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) {
+  return h->obj_;
+}
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) {
+  return h->objtype_;
+}
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) {
+  return h->buf_;
+}
+
+
+#ifdef __cplusplus
+
+/* Type detection and typedefs for integer types.
+ * For platforms where there are multiple 32-bit or 64-bit types, we need to be
+ * able to enumerate them so we can properly create overloads for all variants.
+ *
+ * If any platform existed where there were three integer types with the same
+ * size, this would have to become more complicated.  For example, short, int,
+ * and long could all be 32-bits.  Even more diabolically, short, int, long,
+ * and long long could all be 64 bits and still be standard-compliant.
+ * However, few platforms are this strange, and it's unlikely that upb will be
+ * used on the strangest ones. */
+
+/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are
+ * only defined when __STDC_LIMIT_MACROS are defined before the *first* include
+ * of stdint.h.  We can't guarantee that someone else didn't include these first
+ * without defining __STDC_LIMIT_MACROS. */
+#define UPB_INT32_MAX 0x7fffffffLL
+#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
+#define UPB_INT64_MAX 0x7fffffffffffffffLL
+#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
+
+#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
+#define UPB_INT_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
+#define UPB_LONG_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
+#define UPB_LONG_IS_64BITS 1
+#endif
+
+#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
+#define UPB_LLONG_IS_64BITS 1
+#endif
+
+/* We use macros instead of typedefs so we can undefine them later and avoid
+ * leaking them outside this header file. */
+#if UPB_INT_IS_32BITS
+#define UPB_INT32_T int
+#define UPB_UINT32_T unsigned int
+
+#if UPB_LONG_IS_32BITS
+#define UPB_TWO_32BIT_TYPES 1
+#define UPB_INT32ALT_T long
+#define UPB_UINT32ALT_T unsigned long
+#endif  /* UPB_LONG_IS_32BITS */
+
+#elif UPB_LONG_IS_32BITS  /* && !UPB_INT_IS_32BITS */
+#define UPB_INT32_T long
+#define UPB_UINT32_T unsigned long
+#endif  /* UPB_INT_IS_32BITS */
+
+
+#if UPB_LONG_IS_64BITS
+#define UPB_INT64_T long
+#define UPB_UINT64_T unsigned long
+
+#if UPB_LLONG_IS_64BITS
+#define UPB_TWO_64BIT_TYPES 1
+#define UPB_INT64ALT_T long long
+#define UPB_UINT64ALT_T unsigned long long
+#endif  /* UPB_LLONG_IS_64BITS */
+
+#elif UPB_LLONG_IS_64BITS  /* && !UPB_LONG_IS_64BITS */
+#define UPB_INT64_T long long
+#define UPB_UINT64_T unsigned long long
+#endif  /* UPB_LONG_IS_64BITS */
+
+#undef UPB_INT32_MAX
+#undef UPB_INT32_MIN
+#undef UPB_INT64_MAX
+#undef UPB_INT64_MIN
+#undef UPB_INT_IS_32BITS
+#undef UPB_LONG_IS_32BITS
+#undef UPB_LONG_IS_64BITS
+#undef UPB_LLONG_IS_64BITS
+
+
+namespace upb {
+
+typedef void CleanupFunc(void *ptr);
+
+/* Template to remove "const" from "const T*" and just return "T*".
+ *
+ * We define a nonsense default because otherwise it will fail to instantiate as
+ * a function parameter type even in cases where we don't expect any caller to
+ * actually match the overload. */
+class CouldntRemoveConst {};
+template <class T> struct remove_constptr { typedef CouldntRemoveConst type; };
+template <class T> struct remove_constptr<const T *> { typedef T *type; };
+
+/* Template that we use below to remove a template specialization from
+ * consideration if it matches a specific type. */
+template <class T, class U> struct disable_if_same { typedef void Type; };
+template <class T> struct disable_if_same<T, T> {};
+
+template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); }
+
+template <class T1, class T2>
+struct FirstUnlessVoidOrBool {
+  typedef T1 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<void, T2> {
+  typedef T2 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<bool, T2> {
+  typedef T2 value;
+};
+
+template<class T, class U>
+struct is_same {
+  static bool value;
+};
+
+template<class T>
+struct is_same<T, T> {
+  static bool value;
+};
+
+template<class T, class U>
+bool is_same<T, U>::value = false;
+
+template<class T>
+bool is_same<T, T>::value = true;
+
+/* FuncInfo *******************************************************************/
+
+/* Info about the user's original, pre-wrapped function. */
+template <class C, class R = void>
+struct FuncInfo {
+  /* The type of the closure that the function takes (its first param). */
+  typedef C Closure;
+
+  /* The return type. */
+  typedef R Return;
+};
+
+/* Func ***********************************************************************/
+
+/* Func1, Func2, Func3: Template classes representing a function and its
+ * signature.
+ *
+ * Since the function is a template parameter, calling the function can be
+ * inlined at compile-time and does not require a function pointer at runtime.
+ * These functions are not bound to a handler data so have no data or cleanup
+ * handler. */
+struct UnboundFunc {
+  CleanupFunc *GetCleanup() { return NULL; }
+  void *GetData() { return NULL; }
+};
+
+template <class R, class P1, R F(P1), class I>
+struct Func1 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1) { return F(p1); }
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct Func2 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2) { return F(p1, p2); }
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct Func3 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct Func4 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct Func5 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+    return F(p1, p2, p3, p4, p5);
+  }
+};
+
+/* BoundFunc ******************************************************************/
+
+/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
+ * shall be bound to the function's second parameter.
+ * 
+ * Note that the second parameter is a const pointer, but our stored bound value
+ * is non-const so we can free it when the handlers are destroyed. */
+template <class T>
+struct BoundFunc {
+  typedef typename remove_constptr<T>::type MutableP2;
+  explicit BoundFunc(MutableP2 data_) : data(data_) {}
+  CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
+  MutableP2 GetData() { return data; }
+  MutableP2 data;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct BoundFunc2 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct BoundFunc3 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct BoundFunc4 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct BoundFunc5 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+/* FuncSig ********************************************************************/
+
+/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
+ * *signature*, but without a specific function attached.
+ *
+ * These classes contain member functions that can be invoked with a
+ * specific function to return a Func/BoundFunc class. */
+template <class R, class P1>
+struct FuncSig1 {
+  template <R F(P1)>
+  Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() {
+    return Func1<R, P1, F, FuncInfo<P1, R> >();
+  }
+};
+
+template <class R, class P1, class P2>
+struct FuncSig2 {
+  template <R F(P1, P2)>
+  Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() {
+    return Func2<R, P1, P2, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2)>
+  BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3>
+struct FuncSig3 {
+  template <R F(P1, P2, P3)>
+  Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() {
+    return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3)>
+  BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct FuncSig4 {
+  template <R F(P1, P2, P3, P4)>
+  Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() {
+    return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4)>
+  BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct FuncSig5 {
+  template <R F(P1, P2, P3, P4, P5)>
+  Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() {
+    return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4, P5)>
+  BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+/* Overloaded template function that can construct the appropriate FuncSig*
+ * class given a function pointer by deducing the template parameters. */
+template <class R, class P1>
+inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig1<R, P1>();
+}
+
+template <class R, class P1, class P2>
+inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig2<R, P1, P2>();
+}
+
+template <class R, class P1, class P2, class P3>
+inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig3<R, P1, P2, P3>();
+}
+
+template <class R, class P1, class P2, class P3, class P4>
+inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig4<R, P1, P2, P3, P4>();
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig5<R, P1, P2, P3, P4, P5>();
+}
+
+/* MethodSig ******************************************************************/
+
+/* CallMethod*: a function template that calls a given method. */
+template <class R, class C, R (C::*F)()>
+R CallMethod0(C *obj) {
+  return ((*obj).*F)();
+}
+
+template <class R, class C, class P1, R (C::*F)(P1)>
+R CallMethod1(C *obj, P1 arg1) {
+  return ((*obj).*F)(arg1);
+}
+
+template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
+R CallMethod2(C *obj, P1 arg1, P2 arg2) {
+  return ((*obj).*F)(arg1, arg2);
+}
+
+template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
+R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
+  return ((*obj).*F)(arg1, arg2, arg3);
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4,
+          R (C::*F)(P1, P2, P3, P4)>
+R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) {
+  return ((*obj).*F)(arg1, arg2, arg3, arg4);
+}
+
+/* MethodSig: like FuncSig, but for member functions.
+ *
+ * GetFunc() returns a normal FuncN object, so after calling GetFunc() no
+ * more logic is required to special-case methods. */
+template <class R, class C>
+struct MethodSig0 {
+  template <R (C::*F)()>
+  Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >();
+  }
+};
+
+template <class R, class C, class P1>
+struct MethodSig1 {
+  template <R (C::*F)(P1)>
+  Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1)>
+  BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc(
+      typename remove_constptr<P1>::type param1) {
+    return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C, class P1, class P2>
+struct MethodSig2 {
+  template <R (C::*F)(P1, P2)>
+  Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2)>
+  BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3>
+struct MethodSig3 {
+  template <R (C::*F)(P1, P2, P3)>
+  Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3)>
+  BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+struct MethodSig4 {
+  template <R (C::*F)(P1, P2, P3, P4)>
+  Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+        FuncInfo<C *, R> >
+  GetFunc() {
+    return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3, P4)>
+  BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc5<R, C *, P1, P2, P3, P4,
+                      CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C>
+inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig0<R, C>();
+}
+
+template <class R, class C, class P1>
+inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig1<R, C, P1>();
+}
+
+template <class R, class C, class P1, class P2>
+inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig2<R, C, P1, P2>();
+}
+
+template <class R, class C, class P1, class P2, class P3>
+inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig3<R, C, P1, P2, P3>();
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig4<R, C, P1, P2, P3, P4>();
+}
+
+/* MaybeWrapReturn ************************************************************/
+
+/* Template class that attempts to wrap the return value of the function so it
+ * matches the expected type.  There are two main adjustments it may make:
+ *
+ *   1. If the function returns void, make it return the expected type and with
+ *      a value that always indicates success.
+ *   2. If the function returns bool, make it return the expected type with a
+ *      value that indicates success or failure.
+ *
+ * The "expected type" for return is:
+ *   1. void* for start handlers.  If the closure parameter has a different type
+ *      we will cast it to void* for the return in the success case.
+ *   2. size_t for string buffer handlers.
+ *   3. bool for everything else. */
+
+/* Template parameters are FuncN type and desired return type. */
+template <class F, class R, class Enable = void>
+struct MaybeWrapReturn;
+
+/* If the return type matches, return the given function unwrapped. */
+template <class F>
+struct MaybeWrapReturn<F, typename F::Return> {
+  typedef F Func;
+};
+
+/* Function wrapper that munges the return value from void to (bool)true. */
+template <class P1, class P2, void F(P1, P2)>
+bool ReturnTrue2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return true;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return true;
+}
+
+/* Function wrapper that munges the return value from void to (void*)arg1  */
+template <class P1, class P2, void F(P1, P2)>
+void *ReturnClosure2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return p1;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return p1;
+}
+
+/* Function wrapper that munges the return value from R to void*. */
+template <class R, class P1, class P2, R F(P1, P2)>
+void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
+  return F(p1, p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3);
+}
+
+/* Function wrapper that munges the return value from bool to void*. */
+template <class P1, class P2, bool F(P1, P2)>
+void *ReturnClosureOrBreak2(P1 p1, P2 p2) {
+  return F(p1, p2) ? p1 : UPB_BREAK;
+}
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3)>
+void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3) ? p1 : UPB_BREAK;
+}
+
+/* For the string callback, which takes five params, returns the size param. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4,
+                       const BufferHandle *p5) {
+  F(p1, p2, p3, p4, p5);
+  return p4;
+}
+
+/* For the string callback, which takes five params, returns the size param or
+ * zero. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4,
+                  const BufferHandle *p5) {
+  return F(p1, p2, p3, p4, p5) ? p4 : 0;
+}
+
+/* If we have a function returning void but want a function returning bool, wrap
+ * it in a function that returns true. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> {
+  typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> {
+  typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns void but we want one returning void*, wrap it in a
+ * function that returns the first argument. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns R* but we want one returning void*, wrap it in a
+ * function that casts to void*. */
+template <class R, class P1, class P2, R *F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func;
+};
+
+template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns bool but we want one returning void*, wrap it in a
+ * function that returns either the first param or UPB_BREAK. */
+template <class P1, class P2, bool F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns void but we want one returning size_t, wrap it in a
+ * function that returns the size argument. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+          size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnStringLen<P1, P2, F>, I> Func;
+};
+
+/* If our function returns bool but we want one returning size_t, wrap it in a
+ * function that returns either 0 or the buf size. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<bool, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+    size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnNOr0<P1, P2, F>, I> Func;
+};
+
+/* ConvertParams **************************************************************/
+
+/* Template class that converts the function parameters if necessary, and
+ * ignores the HandlerData parameter if appropriate.
+ *
+ * Template parameter is the are FuncN function type. */
+template <class F, class T>
+struct ConvertParams;
+
+/* Function that discards the handler data parameter. */
+template <class R, class P1, R F(P1)>
+R IgnoreHandlerData2(void *p1, const void *hd) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1));
+}
+
+template <class R, class P1, class P2Wrapper, class P2Wrapped,
+          R F(P1, P2Wrapped)>
+R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3, p4);
+}
+
+template <class R, class P1, R F(P1, const char*, size_t)>
+R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2,
+                                size_t p3, const BufferHandle *handle) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+/* Function that casts the handler data parameter. */
+template <class R, class P1, class P2, R F(P1, P2)>
+R CastHandlerData2(void *c, const void *hd) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd));
+}
+
+template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
+          R F(P1, P2, P3Wrapped)>
+R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5)>
+R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5);
+}
+
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)>
+R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3,
+                              size_t p4, const BufferHandle *handle) {
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
+}
+
+/* For unbound functions, ignore the handler data. */
+template <class R, class P1, R F(P1), class I, class T>
+struct ConvertParams<Func1<R, P1, F, I>, T> {
+  typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<Func2<R, P1, P2, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores both the handler data and the
+ * BufferHandle. */
+template <class R, class P1, R F(P1, const char *, size_t), class I, class T>
+struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I, class T>
+struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> {
+  typedef Func5<R, void *, const void *, P2, P3, P4,
+                IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
+};
+
+/* For bound functions, cast the handler data. */
+template <class R, class P1, class P2, R F(P1, P2), class I, class T>
+struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> {
+  typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I>
+      Func;
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores the BufferHandle. */
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t),
+          class I, class T>
+struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I, class T>
+struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> {
+  typedef Func5<R, void *, const void *, P3, P4, P5,
+                CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func;
+};
+
+/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
+ * variant C type. */
+#define TYPE_METHODS(utype, ltype, ctype, vtype)                               \
+  template <> struct CanonicalType<vtype> {                                    \
+    typedef ctype Type;                                                        \
+  };                                                                           \
+  template <>                                                                  \
+  inline bool Handlers::SetValueHandler<vtype>(                                \
+      const FieldDef *f,                                                       \
+      const Handlers::utype ## Handler& handler) {                             \
+    assert(!handler.registered_);                                              \
+    handler.AddCleanup(this);                                                  \
+    handler.registered_ = true;                                                \
+    return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
+  }                                                                            \
+
+TYPE_METHODS(Double, double, double,   double)
+TYPE_METHODS(Float,  float,  float,    float)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T)
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64_T)
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32_T)
+TYPE_METHODS(Bool,   bool,   bool,     bool)
+
+#ifdef UPB_TWO_32BIT_TYPES
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32ALT_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T)
+#endif
+
+#ifdef UPB_TWO_64BIT_TYPES
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64ALT_T)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T)
+#endif
+#undef TYPE_METHODS
+
+template <> struct CanonicalType<Status*> {
+  typedef Status* Type;
+};
+
+/* Type methods that are only one-per-canonical-type and not
+ * one-per-cvariant. */
+
+#define TYPE_METHODS(utype, ctype) \
+    inline bool Handlers::Set##utype##Handler(const FieldDef *f, \
+                                              const utype##Handler &h) { \
+      return SetValueHandler<ctype>(f, h); \
+    } \
+
+TYPE_METHODS(Double, double)
+TYPE_METHODS(Float,  float)
+TYPE_METHODS(UInt64, uint64_t)
+TYPE_METHODS(UInt32, uint32_t)
+TYPE_METHODS(Int64,  int64_t)
+TYPE_METHODS(Int32,  int32_t)
+TYPE_METHODS(Bool,   bool)
+#undef TYPE_METHODS
+
+template <class F> struct ReturnOf;
+
+template <class R, class P1, class P2>
+struct ReturnOf<R (*)(P1, P2)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3>
+struct ReturnOf<R (*)(P1, P2, P3)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct ReturnOf<R (*)(P1, P2, P3, P4)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> {
+  typedef R Return;
+};
+
+template<class T> const void *UniquePtrForType() {
+  static const char ch = 0;
+  return &ch;
+}
+
+template <class T>
+template <class F>
+inline Handler<T>::Handler(F func)
+    : registered_(false),
+      cleanup_data_(func.GetData()),
+      cleanup_func_(func.GetCleanup()) {
+  upb_handlerattr_sethandlerdata(&attr_, func.GetData());
+  typedef typename ReturnOf<T>::Return Return;
+  typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc;
+  typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
+      ReturnWrappedFunc;
+  handler_ = ReturnWrappedFunc().Call;
+
+  /* Set attributes based on what templates can statically tell us about the
+   * user's function. */
+
+  /* If the original function returns void, then we know that we wrapped it to
+   * always return ok. */
+  bool always_ok = is_same<typename F::FuncInfo::Return, void>::value;
+  attr_.SetAlwaysOk(always_ok);
+
+  /* Closure parameter and return type. */
+  attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>());
+
+  /* We use the closure type (from the first parameter) if the return type is
+   * void or bool, since these are the two cases we wrap to return the closure's
+   * type anyway.
+   *
+   * This is all nonsense for non START* handlers, but it doesn't matter because
+   * in that case the value will be ignored. */
+  typedef typename FirstUnlessVoidOrBool<typename F::FuncInfo::Return,
+                                         typename F::FuncInfo::Closure>::value
+      EffectiveReturn;
+  attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>());
+}
+
+template <class T>
+inline Handler<T>::~Handler() {
+  assert(registered_);
+}
+
+inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
+inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
+inline bool HandlerAttributes::SetHandlerData(const void *hd) {
+  return upb_handlerattr_sethandlerdata(this, hd);
+}
+inline const void* HandlerAttributes::handler_data() const {
+  return upb_handlerattr_handlerdata(this);
+}
+inline bool HandlerAttributes::SetClosureType(const void *type) {
+  return upb_handlerattr_setclosuretype(this, type);
+}
+inline const void* HandlerAttributes::closure_type() const {
+  return upb_handlerattr_closuretype(this);
+}
+inline bool HandlerAttributes::SetReturnClosureType(const void *type) {
+  return upb_handlerattr_setreturnclosuretype(this, type);
+}
+inline const void* HandlerAttributes::return_closure_type() const {
+  return upb_handlerattr_returnclosuretype(this);
+}
+inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) {
+  return upb_handlerattr_setalwaysok(this, always_ok);
+}
+inline bool HandlerAttributes::always_ok() const {
+  return upb_handlerattr_alwaysok(this);
+}
+
+inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); }
+inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); }
+inline const char* BufferHandle::buffer() const {
+  return upb_bufhandle_buf(this);
+}
+inline size_t BufferHandle::object_offset() const {
+  return upb_bufhandle_objofs(this);
+}
+inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) {
+  upb_bufhandle_setbuf(this, buf, ofs);
+}
+template <class T>
+void BufferHandle::SetAttachedObject(const T* obj) {
+  upb_bufhandle_setobj(this, obj, UniquePtrForType<T>());
+}
+template <class T>
+const T* BufferHandle::GetAttachedObject() const {
+  return upb_bufhandle_objtype(this) == UniquePtrForType<T>()
+      ? static_cast<const T *>(upb_bufhandle_obj(this))
+                               : NULL;
+}
+
+inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
+  upb_handlers *h = upb_handlers_new(m, &h);
+  return reffed_ptr<Handlers>(h, &h);
+}
+inline reffed_ptr<const Handlers> Handlers::NewFrozen(
+    const MessageDef *m, upb_handlers_callback *callback,
+    const void *closure) {
+  const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+inline const Status* Handlers::status() {
+  return upb_handlers_status(this);
+}
+inline void Handlers::ClearError() {
+  return upb_handlers_clearerr(this);
+}
+inline bool Handlers::Freeze(Status *s) {
+  upb::Handlers* h = this;
+  return upb_handlers_freeze(&h, 1, s);
+}
+inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
+  return upb_handlers_freeze(handlers, n, s);
+}
+inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
+  return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
+}
+inline const MessageDef *Handlers::message_def() const {
+  return upb_handlers_msgdef(this);
+}
+inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) {
+  return upb_handlers_addcleanup(this, p, func);
+}
+inline bool Handlers::SetStartMessageHandler(
+    const Handlers::StartMessageHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndMessageHandler(
+    const Handlers::EndMessageHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartStringHandler(const FieldDef *f,
+                                            const StartStringHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndStringHandler(const FieldDef *f,
+                                          const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStringHandler(const FieldDef *f,
+                                       const StringHandler& handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSequenceHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSubMessageHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
+                                              const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
+                                            const EndFieldHandler &handler) {
+  assert(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
+  return upb_handlers_setsubhandlers(this, f, sub);
+}
+inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const {
+  return upb_handlers_getsubhandlers(this, f);
+}
+inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const {
+  return upb_handlers_getsubhandlers_sel(this, sel);
+}
+inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type,
+                                  Handlers::Selector *s) {
+  return upb_handlers_getselector(f, type, s);
+}
+inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) {
+  return upb_handlers_getendselector(start);
+}
+inline Handlers::GenericFunction *Handlers::GetHandler(
+    Handlers::Selector selector) {
+  return upb_handlers_gethandler(this, selector);
+}
+inline const void *Handlers::GetHandlerData(Handlers::Selector selector) {
+  return upb_handlers_gethandlerdata(this, selector);
+}
+
+inline BytesHandler::BytesHandler() {
+  upb_byteshandler_init(this);
+}
+
+inline BytesHandler::~BytesHandler() {}
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+
+#undef UPB_TWO_32BIT_TYPES
+#undef UPB_TWO_64BIT_TYPES
+#undef UPB_INT32_T
+#undef UPB_UINT32_T
+#undef UPB_INT32ALT_T
+#undef UPB_UINT32ALT_T
+#undef UPB_INT64_T
+#undef UPB_UINT64_T
+#undef UPB_INT64ALT_T
+#undef UPB_UINT64ALT_T
+
+#endif  /* UPB_HANDLERS_INL_H_ */
+
+#endif  /* UPB_HANDLERS_H */
+/*
+** upb::Sink (upb_sink)
+** upb::BytesSink (upb_bytessink)
+**
+** A upb_sink is an object that binds a upb_handlers object to some runtime
+** state.  It is the object that can actually receive data via the upb_handlers
+** interface.
+**
+** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
+** thread-safe.  You can create as many of them as you want, but each one may
+** only be used in a single thread at a time.
+**
+** If we compare with class-based OOP, a you can think of a upb_def as an
+** abstract base class, a upb_handlers as a concrete derived class, and a
+** upb_sink as an object (class instance).
+*/
+
+#ifndef UPB_SINK_H
+#define UPB_SINK_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferSource;
+class BytesSink;
+class Sink;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc)
+UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink)
+UPB_DECLARE_TYPE(upb::Sink, upb_sink)
+
+#ifdef __cplusplus
+
+/* A upb::Sink is an object that binds a upb::Handlers object to some runtime
+ * state.  It represents an endpoint to which data can be sent.
+ *
+ * TODO(haberman): right now all of these functions take selectors.  Should they
+ * take selectorbase instead?
+ *
+ * ie. instead of calling:
+ *   sink->StartString(FOO_FIELD_START_STRING, ...)
+ * a selector base would let you say:
+ *   sink->StartString(FOO_FIELD, ...)
+ *
+ * This would make call sites a little nicer and require emitting fewer selector
+ * definitions in .h files.
+ *
+ * But the current scheme has the benefit that you can retrieve a function
+ * pointer for any handler with handlers->GetHandler(selector), without having
+ * to have a separate GetHandler() function for each handler type.  The JIT
+ * compiler uses this.  To accommodate we'd have to expose a separate
+ * GetHandler() for every handler type.
+ *
+ * Also to ponder: selectors right now are independent of a specific Handlers
+ * instance.  In other words, they allocate a number to every possible handler
+ * that *could* be registered, without knowing anything about what handlers
+ * *are* registered.  That means that using selectors as table offsets prohibits
+ * us from compacting the handler table at Freeze() time.  If the table is very
+ * sparse, this could be wasteful.
+ *
+ * Having another selector-like thing that is specific to a Handlers instance
+ * would allow this compacting, but then it would be impossible to write code
+ * ahead-of-time that can be bound to any Handlers instance at runtime.  For
+ * example, a .proto file parser written as straight C will not know what
+ * Handlers it will be bound to, so when it calls sink->StartString() what
+ * selector will it pass?  It needs a selector like we have today, that is
+ * independent of any particular upb::Handlers.
+ *
+ * Is there a way then to allow Handlers table compaction? */
+class upb::Sink {
+ public:
+  /* Constructor with no initialization; must be Reset() before use. */
+  Sink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> Sink(const Handlers* handlers, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const Handlers* handlers, T* closure);
+
+  /* Returns the top-level object that is bound to this sink.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> T* GetObject() const;
+
+  /* Functions for pushing data into the sink.
+   *
+   * These return false if processing should stop (either due to error or just
+   * to suspend).
+   *
+   * These may not be called from within one of the same sink's handlers (in
+   * other words, handlers are not re-entrant). */
+
+  /* Should be called at the start and end of every message; both the top-level
+   * message and submessages.  This means that submessages should use the
+   * following sequence:
+   *   sink->StartSubMessage(startsubmsg_selector);
+   *   sink->StartMessage();
+   *   // ...
+   *   sink->EndMessage(&status);
+   *   sink->EndSubMessage(endsubmsg_selector); */
+  bool StartMessage();
+  bool EndMessage(Status* status);
+
+  /* Putting of individual values.  These work for both repeated and
+   * non-repeated fields, but for repeated fields you must wrap them in
+   * calls to StartSequence()/EndSequence(). */
+  bool PutInt32(Handlers::Selector s, int32_t val);
+  bool PutInt64(Handlers::Selector s, int64_t val);
+  bool PutUInt32(Handlers::Selector s, uint32_t val);
+  bool PutUInt64(Handlers::Selector s, uint64_t val);
+  bool PutFloat(Handlers::Selector s, float val);
+  bool PutDouble(Handlers::Selector s, double val);
+  bool PutBool(Handlers::Selector s, bool val);
+
+  /* Putting of string/bytes values.  Each string can consist of zero or more
+   * non-contiguous buffers of data.
+   *
+   * For StartString(), the function will write a sink for the string to "sub."
+   * The sub-sink must be used for any/all PutStringBuffer() calls. */
+  bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
+  size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len,
+                         const BufferHandle *handle);
+  bool EndString(Handlers::Selector s);
+
+  /* For submessage fields.
+   *
+   * For StartSubMessage(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * submessage. */
+  bool StartSubMessage(Handlers::Selector s, Sink* sub);
+  bool EndSubMessage(Handlers::Selector s);
+
+  /* For repeated fields of any type, the sequence of values must be wrapped in
+   * these calls.
+   *
+   * For StartSequence(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * sequence. */
+  bool StartSequence(Handlers::Selector s, Sink* sub);
+  bool EndSequence(Handlers::Selector s);
+
+  /* Copy and assign specifically allowed.
+   * We don't even bother making these members private because so many
+   * functions need them and this is mainly just a dumb data container anyway.
+   */
+#else
+struct upb_sink {
+#endif
+  const upb_handlers *handlers;
+  void *closure;
+};
+
+#ifdef __cplusplus
+class upb::BytesSink {
+ public:
+  BytesSink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO(haberman): once the Handlers know the expected closure type, verify
+   * that T matches it. */
+  template <class T> BytesSink(const BytesHandler* handler, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const BytesHandler* handler, T* closure);
+
+  bool Start(size_t size_hint, void **subc);
+  size_t PutBuffer(void *subc, const char *buf, size_t len,
+                   const BufferHandle *handle);
+  bool End();
+#else
+struct upb_bytessink {
+#endif
+  const upb_byteshandler *handler;
+  void *closure;
+};
+
+#ifdef __cplusplus
+
+/* A class for pushing a flat buffer of data to a BytesSink.
+ * You can construct an instance of this to get a resumable source,
+ * or just call the static PutBuffer() to do a non-resumable push all in one
+ * go. */
+class upb::BufferSource {
+ public:
+  BufferSource();
+  BufferSource(const char* buf, size_t len, BytesSink* sink);
+
+  /* Returns true if the entire buffer was pushed successfully.  Otherwise the
+   * next call to PutNext() will resume where the previous one left off.
+   * TODO(haberman): implement this. */
+  bool PutNext();
+
+  /* A static version; with this version is it not possible to resume in the
+   * case of failure or a partially-consumed buffer. */
+  static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
+
+  template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
+    return PutBuffer(str.c_str(), str.size(), sink);
+  }
+#else
+struct upb_bufsrc {
+  char dummy;
+#endif
+};
+
+UPB_BEGIN_EXTERN_C
+
+/* Inline definitions. */
+
+UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
+                                    void *closure) {
+  s->handler = h;
+  s->closure = closure;
+}
+
+UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
+                                    void **subc) {
+  typedef upb_startstr_handlerfunc func;
+  func *start;
+  *subc = s->closure;
+  if (!s->handler) return true;
+  start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+
+  if (!start) return true;
+  *subc = start(s->closure, upb_handlerattr_handlerdata(
+                                &s->handler->table[UPB_STARTSTR_SELECTOR].attr),
+                size_hint);
+  return *subc != NULL;
+}
+
+UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
+                                       const char *buf, size_t size,
+                                       const upb_bufhandle* handle) {
+  typedef upb_string_handlerfunc func;
+  func *putbuf;
+  if (!s->handler) return true;
+  putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func;
+
+  if (!putbuf) return true;
+  return putbuf(subc, upb_handlerattr_handlerdata(
+                          &s->handler->table[UPB_STRING_SELECTOR].attr),
+                buf, size, handle);
+}
+
+UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+  typedef upb_endfield_handlerfunc func;
+  func *end;
+  if (!s->handler) return true;
+  end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+
+  if (!end) return true;
+  return end(s->closure,
+             upb_handlerattr_handlerdata(
+                 &s->handler->table[UPB_ENDSTR_SELECTOR].attr));
+}
+
+UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
+                                  upb_bytessink *sink) {
+  void *subc;
+  bool ret;
+  upb_bufhandle handle;
+  upb_bufhandle_init(&handle);
+  upb_bufhandle_setbuf(&handle, buf, 0);
+  ret = upb_bytessink_start(sink, len, &subc);
+  if (ret && len != 0) {
+    ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
+  }
+  if (ret) {
+    ret = upb_bytessink_end(sink);
+  }
+  upb_bufhandle_uninit(&handle);
+  return ret;
+}
+
+#define PUTVAL(type, ctype)                                                    \
+  UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel,          \
+                                     ctype val) {                              \
+    typedef upb_##type##_handlerfunc functype;                                 \
+    functype *func;                                                            \
+    const void *hd;                                                            \
+    if (!s->handlers) return true;                                             \
+    func = (functype *)upb_handlers_gethandler(s->handlers, sel);              \
+    if (!func) return true;                                                    \
+    hd = upb_handlers_gethandlerdata(s->handlers, sel);                        \
+    return func(s->closure, hd, val);                                          \
+  }
+
+PUTVAL(int32,  int32_t)
+PUTVAL(int64,  int64_t)
+PUTVAL(uint32, uint32_t)
+PUTVAL(uint64, uint64_t)
+PUTVAL(float,  float)
+PUTVAL(double, double)
+PUTVAL(bool,   bool)
+#undef PUTVAL
+
+UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
+  s->handlers = h;
+  s->closure = c;
+}
+
+UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
+                                     const char *buf, size_t n,
+                                     const upb_bufhandle *handle) {
+  typedef upb_string_handlerfunc func;
+  func *handler;
+  const void *hd;
+  if (!s->handlers) return n;
+  handler = (func *)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!handler) return n;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return handler(s->closure, hd, buf, n, handle);
+}
+
+UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
+  typedef upb_startmsg_handlerfunc func;
+  func *startmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR);
+
+  if (!startmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+  return startmsg(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
+  typedef upb_endmsg_handlerfunc func;
+  func *endmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR);
+
+  if (!endmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+  return endmsg(s->closure, hd, status);
+}
+
+UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
+                                  upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startseq;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startseq(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endseq;
+  const void *hd;
+  if (!s->handlers) return true;
+  endseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endseq(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
+                                  size_t size_hint, upb_sink *sub) {
+  typedef upb_startstr_handlerfunc func;
+  func *startstr;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startstr(s->closure, hd, size_hint);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endstr;
+  const void *hd;
+  if (!s->handlers) return true;
+  endstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endstr(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
+                                     upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startsubmsg;
+  const void *hd;
+  sub->closure = s->closure;
+  if (!s->handlers) {
+    sub->handlers = NULL;
+    return true;
+  }
+  sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
+  startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startsubmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startsubmsg(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endsubmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endsubmsg) return s->closure;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endsubmsg(s->closure, hd);
+}
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+template <class T>
+inline void Sink::Reset(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+inline bool Sink::StartMessage() {
+  return upb_sink_startmsg(this);
+}
+inline bool Sink::EndMessage(Status* status) {
+  return upb_sink_endmsg(this, status);
+}
+inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
+  return upb_sink_putint32(this, sel, val);
+}
+inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
+  return upb_sink_putint64(this, sel, val);
+}
+inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
+  return upb_sink_putuint32(this, sel, val);
+}
+inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
+  return upb_sink_putuint64(this, sel, val);
+}
+inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
+  return upb_sink_putfloat(this, sel, val);
+}
+inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
+  return upb_sink_putdouble(this, sel, val);
+}
+inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
+  return upb_sink_putbool(this, sel, val);
+}
+inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
+                              Sink *sub) {
+  return upb_sink_startstr(this, sel, size_hint, sub);
+}
+inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
+                                    size_t len, const BufferHandle* handle) {
+  return upb_sink_putstring(this, sel, buf, len, handle);
+}
+inline bool Sink::EndString(Handlers::Selector sel) {
+  return upb_sink_endstr(this, sel);
+}
+inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startsubmsg(this, sel, sub);
+}
+inline bool Sink::EndSubMessage(Handlers::Selector sel) {
+  return upb_sink_endsubmsg(this, sel);
+}
+inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startseq(this, sel, sub);
+}
+inline bool Sink::EndSequence(Handlers::Selector sel) {
+  return upb_sink_endseq(this, sel);
+}
+
+template <class T>
+BytesSink::BytesSink(const BytesHandler* handler, T* closure) {
+  Reset(handler, closure);
+}
+
+template <class T>
+void BytesSink::Reset(const BytesHandler *handler, T *closure) {
+  upb_bytessink_reset(this, handler, closure);
+}
+inline bool BytesSink::Start(size_t size_hint, void **subc) {
+  return upb_bytessink_start(this, size_hint, subc);
+}
+inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len,
+                                   const BufferHandle *handle) {
+  return upb_bytessink_putbuf(this, subc, buf, len, handle);
+}
+inline bool BytesSink::End() {
+  return upb_bytessink_end(this);
+}
+
+inline bool BufferSource::PutBuffer(const char *buf, size_t len,
+                                    BytesSink *sink) {
+  return upb_bufsrc_putbuf(buf, len, sink);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif
+/*
+** For handlers that do very tiny, very simple operations, the function call
+** overhead of calling a handler can be significant.  This file allows the
+** user to define handlers that do something very simple like store the value
+** to memory and/or set a hasbit.  JIT compilers can then special-case these
+** handlers and emit specialized code for them instead of actually calling the
+** handler.
+**
+** The functionality is very simple/limited right now but may expand to be able
+** to call another function.
+*/
+
+#ifndef UPB_SHIM_H
+#define UPB_SHIM_H
+
+
+typedef struct {
+  size_t offset;
+  int32_t hasbit;
+} upb_shim_data;
+
+#ifdef __cplusplus
+
+namespace upb {
+
+struct Shim {
+  typedef upb_shim_data Data;
+
+  /* Sets a handler for the given field that writes the value to the given
+   * offset and, if hasbit >= 0, sets a bit at the given bit offset.  Returns
+   * true if the handler was set successfully. */
+  static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit);
+
+  /* If this handler is a shim, returns the corresponding upb::Shim::Data and
+   * stores the type in "type".  Otherwise returns NULL. */
+  static const Data* GetData(const Handlers* h, Handlers::Selector s,
+                             FieldDef::Type* type);
+};
+
+}  /* namespace upb */
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
+                  int32_t hasbit);
+const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
+                                      upb_fieldtype_t *type);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ Wrappers. */
+namespace upb {
+inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs,
+                      int32_t hasbit) {
+  return upb_shim_set(h, f, ofs, hasbit);
+}
+inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s,
+                                       FieldDef::Type* type) {
+  return upb_shim_getdata(h, s, type);
+}
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_SHIM_H */
+/*
+** upb::SymbolTable (upb_symtab)
+**
+** A symtab (symbol table) stores a name->def map of upb_defs.  Clients could
+** always create such tables themselves, but upb_symtab has logic for resolving
+** symbolic references, and in particular, for keeping a whole set of consistent
+** defs when replacing some subset of those defs.  This logic is nontrivial.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_SYMTAB_H_
+#define UPB_SYMTAB_H_
+
+
+#ifdef __cplusplus
+#include <vector>
+namespace upb { class SymbolTable; }
+#endif
+
+UPB_DECLARE_DERIVED_TYPE(upb::SymbolTable, upb::RefCounted,
+                         upb_symtab, upb_refcounted)
+
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+  upb_strtable_iter iter;
+  upb_deftype_t type;
+} upb_symtab_iter;
+
+#ifdef __cplusplus
+
+/* Non-const methods in upb::SymbolTable are NOT thread-safe. */
+class upb::SymbolTable {
+ public:
+  /* Returns a new symbol table with a single ref owned by "owner."
+   * Returns NULL if memory allocation failed. */
+  static reffed_ptr<SymbolTable> New();
+
+  /* Include RefCounted base methods. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* For all lookup functions, the returned pointer is not owned by the
+   * caller; it may be invalidated by any non-const call or unref of the
+   * SymbolTable!  To protect against this, take a ref if desired. */
+
+  /* Freezes the symbol table: prevents further modification of it.
+   * After the Freeze() operation is successful, the SymbolTable must only be
+   * accessed via a const pointer.
+   *
+   * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not
+   * a necessary step in using a SymbolTable.  If you have no need for it to be
+   * immutable, there is no need to freeze it ever.  However sometimes it is
+   * useful, and SymbolTables that are statically compiled into the binary are
+   * always frozen by nature. */
+  void Freeze();
+
+  /* Resolves the given symbol using the rules described in descriptor.proto,
+   * namely:
+   *
+   *    If the name starts with a '.', it is fully-qualified.  Otherwise,
+   *    C++-like scoping rules are used to find the type (i.e. first the nested
+   *    types within this message are searched, then within the parent, on up
+   *    to the root namespace).
+   *
+   * If not found, returns NULL. */
+  const Def* Resolve(const char* base, const char* sym) const;
+
+  /* Finds an entry in the symbol table with this exact name.  If not found,
+   * returns NULL. */
+  const Def* Lookup(const char *sym) const;
+  const MessageDef* LookupMessage(const char *sym) const;
+  const EnumDef* LookupEnum(const char *sym) const;
+
+  /* TODO: introduce a C++ iterator, but make it nice and templated so that if
+   * you ask for an iterator of MessageDef the iterated elements are strongly
+   * typed as MessageDef*. */
+
+  /* Adds the given mutable defs to the symtab, resolving all symbols
+   * (including enum default values) and finalizing the defs.  Only one def per
+   * name may be in the list, but defs can replace existing defs in the symtab.
+   * All defs must have a name -- anonymous defs are not allowed.  Anonymous
+   * defs can still be frozen by calling upb_def_freeze() directly.
+   *
+   * Any existing defs that can reach defs that are being replaced will
+   * themselves be replaced also, so that the resulting set of defs is fully
+   * consistent.
+   *
+   * This logic implemented in this method is a convenience; ultimately it
+   * calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and
+   * upb_freeze(), any of which the client could call themself.  However, since
+   * the logic for doing so is nontrivial, we provide it here.
+   *
+   * The entire operation either succeeds or fails.  If the operation fails,
+   * the symtab is unchanged, false is returned, and status indicates the
+   * error.  The caller passes a ref on all defs to the symtab (even if the
+   * operation fails).
+   *
+   * TODO(haberman): currently failure will leave the symtab unchanged, but may
+   * leave the defs themselves partially resolved.  Does this matter?  If so we
+   * could do a prepass that ensures that all symbols are resolvable and bail
+   * if not, so we don't mutate anything until we know the operation will
+   * succeed.
+   *
+   * TODO(haberman): since the defs must be mutable, refining a frozen def
+   * requires making mutable copies of the entire tree.  This is wasteful if
+   * only a few messages are changing.  We may want to add a way of adding a
+   * tree of frozen defs to the symtab (perhaps an alternate constructor where
+   * you pass the root of the tree?) */
+  bool Add(Def*const* defs, size_t n, void* ref_donor, Status* status);
+
+  bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
+    return Add((Def*const*)&defs[0], defs.size(), owner, status);
+  }
+
+  /* Resolves all subdefs for messages in this file and attempts to freeze the
+   * file.  If this succeeds, adds all the symbols to this SymbolTable
+   * (replacing any existing ones with the same names). */
+  bool AddFile(FileDef* file, Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+/* Include refcounted methods like upb_symtab_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_symtab, upb_symtab_upcast)
+
+upb_symtab *upb_symtab_new(const void *owner);
+void upb_symtab_freeze(upb_symtab *s);
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym);
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym);
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                    void *ref_donor, upb_status *status);
+bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status* status);
+
+/* upb_symtab_iter i;
+ * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i);
+ *     upb_symtab_next(&i)) {
+ *   const upb_def *def = upb_symtab_iter_def(&i);
+ *    // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type);
+void upb_symtab_next(upb_symtab_iter *iter);
+bool upb_symtab_done(const upb_symtab_iter *iter);
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ inline wrappers. */
+namespace upb {
+inline reffed_ptr<SymbolTable> SymbolTable::New() {
+  upb_symtab *s = upb_symtab_new(&s);
+  return reffed_ptr<SymbolTable>(s, &s);
+}
+
+inline void SymbolTable::Freeze() {
+  return upb_symtab_freeze(this);
+}
+inline const Def *SymbolTable::Resolve(const char *base,
+                                       const char *sym) const {
+  return upb_symtab_resolve(this, base, sym);
+}
+inline const Def* SymbolTable::Lookup(const char *sym) const {
+  return upb_symtab_lookup(this, sym);
+}
+inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const {
+  return upb_symtab_lookupmsg(this, sym);
+}
+inline bool SymbolTable::Add(
+    Def*const* defs, size_t n, void* ref_donor, Status* status) {
+  return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status);
+}
+inline bool SymbolTable::AddFile(FileDef* file, Status* s) {
+  return upb_symtab_addfile(this, file, s);
+}
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_SYMTAB_H_ */
+/*
+** upb::descriptor::Reader (upb_descreader)
+**
+** Provides a way of building upb::Defs from data in descriptor.proto format.
+*/
+
+#ifndef UPB_DESCRIPTOR_H
+#define UPB_DESCRIPTOR_H
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace descriptor {
+class Reader;
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader)
+
+#ifdef __cplusplus
+
+/* Class that receives descriptor data according to the descriptor.proto schema
+ * and use it to build upb::Defs corresponding to that schema. */
+class upb::descriptor::Reader {
+ public:
+  /* These handlers must have come from NewHandlers() and must outlive the
+   * Reader.
+   *
+   * TODO: generate the handlers statically (like we do with the
+   * descriptor.proto defs) so that there is no need to pass this parameter (or
+   * to build/memory-manage the handlers at runtime at all).  Unfortunately this
+   * is a bit tricky to implement for Handlers, but necessary to simplify this
+   * interface. */
+  static Reader* Create(Environment* env, const Handlers* handlers);
+
+  /* The reader's input; this is where descriptor.proto data should be sent. */
+  Sink* input();
+
+  /* Use to get the FileDefs that have been parsed. */
+  size_t file_count() const;
+  FileDef* file(size_t i) const;
+
+  /* Builds and returns handlers for the reader, owned by "owner." */
+  static Handlers* NewHandlers(const void* owner);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h);
+upb_sink *upb_descreader_input(upb_descreader *r);
+size_t upb_descreader_filecount(const upb_descreader *r);
+upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i);
+const upb_handlers *upb_descreader_newhandlers(const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ implementation details. ************************************************/
+namespace upb {
+namespace descriptor {
+inline Reader* Reader::Create(Environment* e, const Handlers *h) {
+  return upb_descreader_create(e, h);
+}
+inline Sink* Reader::input() { return upb_descreader_input(this); }
+inline size_t Reader::file_count() const {
+  return upb_descreader_filecount(this);
+}
+inline FileDef* Reader::file(size_t i) const {
+  return upb_descreader_file(this, i);
+}
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_DESCRIPTOR_H */
+/* This file contains accessors for a set of compiled-in defs.
+ * Note that unlike Google's protobuf, it does *not* define
+ * generated classes or any other kind of data structure for
+ * actually storing protobufs.  It only contains *defs* which
+ * let you reflect over a protobuf *schema*.
+ */
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     upb/descriptor/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_
+#define UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_
+
+
+UPB_BEGIN_EXTERN_C
+
+/* Enums */
+
+typedef enum {
+  google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1,
+  google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2,
+  google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3
+} google_protobuf_FieldDescriptorProto_Label;
+
+typedef enum {
+  google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1,
+  google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2,
+  google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3,
+  google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4,
+  google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5,
+  google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6,
+  google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7,
+  google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8,
+  google_protobuf_FieldDescriptorProto_TYPE_STRING = 9,
+  google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10,
+  google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11,
+  google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12,
+  google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13,
+  google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14,
+  google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15,
+  google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16,
+  google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17,
+  google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18
+} google_protobuf_FieldDescriptorProto_Type;
+
+typedef enum {
+  google_protobuf_FieldOptions_STRING = 0,
+  google_protobuf_FieldOptions_CORD = 1,
+  google_protobuf_FieldOptions_STRING_PIECE = 2
+} google_protobuf_FieldOptions_CType;
+
+typedef enum {
+  google_protobuf_FieldOptions_JS_NORMAL = 0,
+  google_protobuf_FieldOptions_JS_STRING = 1,
+  google_protobuf_FieldOptions_JS_NUMBER = 2
+} google_protobuf_FieldOptions_JSType;
+
+typedef enum {
+  google_protobuf_FileOptions_SPEED = 1,
+  google_protobuf_FileOptions_CODE_SIZE = 2,
+  google_protobuf_FileOptions_LITE_RUNTIME = 3
+} google_protobuf_FileOptions_OptimizeMode;
+
+/* MessageDefs: call these functions to get a ref to a msgdef. */
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner);
+
+/* EnumDefs: call these functions to get a ref to an enumdef. */
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner);
+
+/* Functions to test whether this message is of a certain type. */
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ExtensionRange") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ReservedRange") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumValueDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumValueOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorSet_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorSet") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MessageOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MessageOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MethodDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MethodOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_OneofDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.OneofDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_ServiceDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_ServiceOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_Location_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo.Location") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_NamePart_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption.NamePart") == 0;
+}
+
+/* Functions to test whether this enum is of a certain type. */
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Label_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Label") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Type_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Type") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_CType_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.CType") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_JSType_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.JSType") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileOptions_OptimizeMode_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FileOptions.OptimizeMode") == 0;
+}
+
+
+/* Functions to get a fielddef from a msgdef reference. */
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_end(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_start(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_end(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_start(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_enum_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension_range(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_field(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_nested_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_oneof_decl(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_range(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_allow_alias(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_number(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_default_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_extendee(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_json_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_label(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_number(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_oneof_index(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_ctype(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_jstype(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_lazy(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_packed(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_weak(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_enum_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_message_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_public_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_service(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_source_code_info(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_syntax(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 12); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_weak_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_f_file(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorSet_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_enable_arenas(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 31); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 16); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_csharp_namespace(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 37); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 23); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_go_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generate_equals_and_hash(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 20); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 17); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_multiple_files(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_outer_classname(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_string_check_utf8(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 27); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_javanano_use_deprecated_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 38); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_objc_class_prefix(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 36); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_optimize_for(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_py_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 18); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_map_entry(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_message_set_wire_format(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_no_standard_descriptor_accessor(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_client_streaming(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_input_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_output_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_server_streaming(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 33); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_OneofDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_method(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 33); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_detached_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_path(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_span(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_trailing_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_f_location(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_is_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_name_part(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_aggregate_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_double_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_identifier_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_negative_int_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_positive_int_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_string_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 7); }
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upbdefs {
+namespace google {
+namespace protobuf {
+
+class DescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  DescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_DescriptorProto_is(m));
+  }
+
+  static DescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m);
+    return DescriptorProto(m, &m);
+  }
+
+  class ExtensionRange : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    ExtensionRange(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m));
+    }
+
+    static ExtensionRange get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m);
+      return ExtensionRange(m, &m);
+    }
+  };
+
+  class ReservedRange : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    ReservedRange(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m));
+    }
+
+    static ReservedRange get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m);
+      return ReservedRange(m, &m);
+    }
+  };
+};
+
+class EnumDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m));
+  }
+
+  static EnumDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m);
+    return EnumDescriptorProto(m, &m);
+  }
+};
+
+class EnumOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_EnumOptions_is(m));
+  }
+
+  static EnumOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m);
+    return EnumOptions(m, &m);
+  }
+};
+
+class EnumValueDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumValueDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m));
+  }
+
+  static EnumValueDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m);
+    return EnumValueDescriptorProto(m, &m);
+  }
+};
+
+class EnumValueOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumValueOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_EnumValueOptions_is(m));
+  }
+
+  static EnumValueOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m);
+    return EnumValueOptions(m, &m);
+  }
+};
+
+class FieldDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FieldDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m));
+  }
+
+  static FieldDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m);
+    return FieldDescriptorProto(m, &m);
+  }
+
+  class Label : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    Label(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      assert(upbdefs_google_protobuf_FieldDescriptorProto_Label_is(e));
+    }
+    static Label get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e);
+      return Label(e, &e);
+    }
+  };
+
+  class Type : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    Type(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      assert(upbdefs_google_protobuf_FieldDescriptorProto_Type_is(e));
+    }
+    static Type get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e);
+      return Type(e, &e);
+    }
+  };
+};
+
+class FieldOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FieldOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_FieldOptions_is(m));
+  }
+
+  static FieldOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m);
+    return FieldOptions(m, &m);
+  }
+
+  class CType : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    CType(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      assert(upbdefs_google_protobuf_FieldOptions_CType_is(e));
+    }
+    static CType get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e);
+      return CType(e, &e);
+    }
+  };
+
+  class JSType : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    JSType(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      assert(upbdefs_google_protobuf_FieldOptions_JSType_is(e));
+    }
+    static JSType get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e);
+      return JSType(e, &e);
+    }
+  };
+};
+
+class FileDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_FileDescriptorProto_is(m));
+  }
+
+  static FileDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m);
+    return FileDescriptorProto(m, &m);
+  }
+};
+
+class FileDescriptorSet : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileDescriptorSet(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_FileDescriptorSet_is(m));
+  }
+
+  static FileDescriptorSet get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m);
+    return FileDescriptorSet(m, &m);
+  }
+};
+
+class FileOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_FileOptions_is(m));
+  }
+
+  static FileOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m);
+    return FileOptions(m, &m);
+  }
+
+  class OptimizeMode : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    OptimizeMode(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      assert(upbdefs_google_protobuf_FileOptions_OptimizeMode_is(e));
+    }
+    static OptimizeMode get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e);
+      return OptimizeMode(e, &e);
+    }
+  };
+};
+
+class MessageOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MessageOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_MessageOptions_is(m));
+  }
+
+  static MessageOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m);
+    return MessageOptions(m, &m);
+  }
+};
+
+class MethodDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MethodDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m));
+  }
+
+  static MethodDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m);
+    return MethodDescriptorProto(m, &m);
+  }
+};
+
+class MethodOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MethodOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_MethodOptions_is(m));
+  }
+
+  static MethodOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m);
+    return MethodOptions(m, &m);
+  }
+};
+
+class OneofDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  OneofDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_OneofDescriptorProto_is(m));
+  }
+
+  static OneofDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m);
+    return OneofDescriptorProto(m, &m);
+  }
+};
+
+class ServiceDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  ServiceDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m));
+  }
+
+  static ServiceDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m);
+    return ServiceDescriptorProto(m, &m);
+  }
+};
+
+class ServiceOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  ServiceOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_ServiceOptions_is(m));
+  }
+
+  static ServiceOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m);
+    return ServiceOptions(m, &m);
+  }
+};
+
+class SourceCodeInfo : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  SourceCodeInfo(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_SourceCodeInfo_is(m));
+  }
+
+  static SourceCodeInfo get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m);
+    return SourceCodeInfo(m, &m);
+  }
+
+  class Location : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    Location(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m));
+    }
+
+    static Location get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m);
+      return Location(m, &m);
+    }
+  };
+};
+
+class UninterpretedOption : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  UninterpretedOption(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    assert(upbdefs_google_protobuf_UninterpretedOption_is(m));
+  }
+
+  static UninterpretedOption get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m);
+    return UninterpretedOption(m, &m);
+  }
+
+  class NamePart : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    NamePart(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m));
+    }
+
+    static NamePart get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m);
+      return NamePart(m, &m);
+    }
+  };
+};
+
+}  /* namespace protobuf */
+}  /* namespace google */
+}  /* namespace upbdefs */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ */
+/*
+** Internal-only definitions for the decoder.
+*/
+
+#ifndef UPB_DECODER_INT_H_
+#define UPB_DECODER_INT_H_
+
+/*
+** upb::pb::Decoder
+**
+** A high performance, streaming, resumable decoder for the binary protobuf
+** format.
+**
+** This interface works the same regardless of what decoder backend is being
+** used.  A client of this class does not need to know whether decoding is using
+** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder.  By default,
+** it will always use the fastest available decoder.  However, you can call
+** set_allow_jit(false) to disable any JIT decoder that might be available.
+** This is primarily useful for testing purposes.
+*/
+
+#ifndef UPB_DECODER_H_
+#define UPB_DECODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class CodeCache;
+class Decoder;
+class DecoderMethod;
+class DecoderMethodOptions;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache)
+UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder)
+UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts)
+
+UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted,
+                         upb_pbdecodermethod, upb_refcounted)
+
+/* The maximum number of bytes we are required to buffer internally between
+ * calls to the decoder.  The value is 14: a 5 byte unknown tag plus ten-byte
+ * varint, less one because we are buffering an incomplete value.
+ *
+ * Should only be used by unit tests. */
+#define UPB_DECODER_MAX_RESIDUAL_BYTES 14
+
+#ifdef __cplusplus
+
+/* The parameters one uses to construct a DecoderMethod.
+ * TODO(haberman): move allowjit here?  Seems more convenient for users.
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::DecoderMethodOptions {
+ public:
+  /* Parameter represents the destination handlers that this method will push
+   * to. */
+  explicit DecoderMethodOptions(const Handlers* dest_handlers);
+
+  /* Should the decoder push submessages to lazy handlers for fields that have
+   * them?  The caller should set this iff the lazy handlers expect data that is
+   * in protobuf binary format and the caller wishes to lazy parse it. */
+  void set_lazy(bool lazy);
+#else
+struct upb_pbdecodermethodopts {
+#endif
+  const upb_handlers *handlers;
+  bool lazy;
+};
+
+#ifdef __cplusplus
+
+/* Represents the code to parse a protobuf according to a destination
+ * Handlers. */
+class upb::pb::DecoderMethod {
+ public:
+  /* Include base methods from upb::ReferenceCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* The destination handlers that are statically bound to this method.
+   * This method is only capable of outputting to a sink that uses these
+   * handlers. */
+  const Handlers* dest_handlers() const;
+
+  /* The input handlers for this decoder method. */
+  const BytesHandler* input_handler() const;
+
+  /* Whether this method is native. */
+  bool is_native() const;
+
+  /* Convenience method for generating a DecoderMethod without explicitly
+   * creating a CodeCache. */
+  static reffed_ptr<const DecoderMethod> New(const DecoderMethodOptions& opts);
+
+ private:
+  UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod)
+};
+
+#endif
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_DECODER_SIZE 4416
+
+#ifdef __cplusplus
+
+/* A Decoder receives binary protobuf data on its input sink and pushes the
+ * decoded data to its output sink. */
+class upb::pb::Decoder {
+ public:
+  /* Constructs a decoder instance for the given method, which must outlive this
+   * decoder.  Any errors during parsing will be set on the given status, which
+   * must also outlive this decoder.
+   *
+   * The sink must match the given method. */
+  static Decoder* Create(Environment* env, const DecoderMethod* method,
+                         Sink* output);
+
+  /* Returns the DecoderMethod this decoder is parsing from. */
+  const DecoderMethod* method() const;
+
+  /* The sink on which this decoder receives input. */
+  BytesSink* input();
+
+  /* Returns number of bytes successfully parsed.
+   *
+   * This can be useful for determining the stream position where an error
+   * occurred.
+   *
+   * This value may not be up-to-date when called from inside a parsing
+   * callback. */
+  uint64_t BytesParsed() const;
+
+  /* Gets/sets the parsing nexting limit.  If the total number of nested
+   * submessages and repeated fields hits this limit, parsing will fail.  This
+   * is a resource limit that controls the amount of memory used by the parsing
+   * stack.
+   *
+   * Setting the limit will fail if the parser is currently suspended at a depth
+   * greater than this, or if memory allocation of the stack fails. */
+  size_t max_nesting() const;
+  bool set_max_nesting(size_t max);
+
+  void Reset();
+
+  static const size_t kSize = UPB_PB_DECODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder)
+};
+
+#endif  /* __cplusplus */
+
+#ifdef __cplusplus
+
+/* A class for caching protobuf processing code, whether bytecode for the
+ * interpreted decoder or machine code for the JIT.
+ *
+ * This class is not thread-safe.
+ *
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::CodeCache {
+ public:
+  CodeCache();
+  ~CodeCache();
+
+  /* Whether the cache is allowed to generate machine code.  Defaults to true.
+   * There is no real reason to turn it off except for testing or if you are
+   * having a specific problem with the JIT.
+   *
+   * Note that allow_jit = true does not *guarantee* that the code will be JIT
+   * compiled.  If this platform is not supported or the JIT was not compiled
+   * in, the code may still be interpreted. */
+  bool allow_jit() const;
+
+  /* This may only be called when the object is first constructed, and prior to
+   * any code generation, otherwise returns false and does nothing. */
+  bool set_allow_jit(bool allow);
+
+  /* Returns a DecoderMethod that can push data to the given handlers.
+   * If a suitable method already exists, it will be returned from the cache.
+   *
+   * Specifying the destination handlers here allows the DecoderMethod to be
+   * statically bound to the destination handlers if possible, which can allow
+   * more efficient decoding.  However the returned method may or may not
+   * actually be statically bound.  But in all cases, the returned method can
+   * push data to the given handlers. */
+  const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts);
+
+  /* If/when someone needs to explicitly create a dynamically-bound
+   * DecoderMethod*, we can add a method to get it here. */
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache)
+#else
+struct upb_pbcodecache {
+#endif
+  bool allow_jit_;
+
+  /* Array of mgroups. */
+  upb_inttable groups;
+};
+
+UPB_BEGIN_EXTERN_C
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e,
+                                    const upb_pbdecodermethod *method,
+                                    upb_sink *output);
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d);
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max);
+void upb_pbdecoder_reset(upb_pbdecoder *d);
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h);
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy);
+
+
+/* Include refcounted methods like upb_pbdecodermethod_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_pbdecodermethod, upb_pbdecodermethod_upcast)
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner);
+
+void upb_pbcodecache_init(upb_pbcodecache *c);
+void upb_pbcodecache_uninit(upb_pbcodecache *c);
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+namespace pb {
+
+/* static */
+inline Decoder* Decoder::Create(Environment* env, const DecoderMethod* m,
+                                Sink* sink) {
+  return upb_pbdecoder_create(env, m, sink);
+}
+inline const DecoderMethod* Decoder::method() const {
+  return upb_pbdecoder_method(this);
+}
+inline BytesSink* Decoder::input() {
+  return upb_pbdecoder_input(this);
+}
+inline uint64_t Decoder::BytesParsed() const {
+  return upb_pbdecoder_bytesparsed(this);
+}
+inline size_t Decoder::max_nesting() const {
+  return upb_pbdecoder_maxnesting(this);
+}
+inline bool Decoder::set_max_nesting(size_t max) {
+  return upb_pbdecoder_setmaxnesting(this, max);
+}
+inline void Decoder::Reset() { upb_pbdecoder_reset(this); }
+
+inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) {
+  upb_pbdecodermethodopts_init(this, h);
+}
+inline void DecoderMethodOptions::set_lazy(bool lazy) {
+  upb_pbdecodermethodopts_setlazy(this, lazy);
+}
+
+inline const Handlers* DecoderMethod::dest_handlers() const {
+  return upb_pbdecodermethod_desthandlers(this);
+}
+inline const BytesHandler* DecoderMethod::input_handler() const {
+  return upb_pbdecodermethod_inputhandler(this);
+}
+inline bool DecoderMethod::is_native() const {
+  return upb_pbdecodermethod_isnative(this);
+}
+/* static */
+inline reffed_ptr<const DecoderMethod> DecoderMethod::New(
+    const DecoderMethodOptions &opts) {
+  const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
+  return reffed_ptr<const DecoderMethod>(m, &m);
+}
+
+inline CodeCache::CodeCache() {
+  upb_pbcodecache_init(this);
+}
+inline CodeCache::~CodeCache() {
+  upb_pbcodecache_uninit(this);
+}
+inline bool CodeCache::allow_jit() const {
+  return upb_pbcodecache_allowjit(this);
+}
+inline bool CodeCache::set_allow_jit(bool allow) {
+  return upb_pbcodecache_setallowjit(this, allow);
+}
+inline const DecoderMethod *CodeCache::GetDecoderMethod(
+    const DecoderMethodOptions& opts) {
+  return upb_pbcodecache_getdecodermethod(this, &opts);
+}
+
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_DECODER_H_ */
+
+/* C++ names are not actually used since this type isn't exposed to users. */
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class MessageGroup;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+UPB_DECLARE_DERIVED_TYPE(upb::pb::MessageGroup, upb::RefCounted,
+                         mgroup, upb_refcounted)
+
+/* Opcode definitions.  The canonical meaning of each opcode is its
+ * implementation in the interpreter (the JIT is written to match this).
+ *
+ * All instructions have the opcode in the low byte.
+ * Instruction format for most instructions is:
+ *
+ * +-------------------+--------+
+ * |     arg (24)      | op (8) |
+ * +-------------------+--------+
+ *
+ * Exceptions are indicated below.  A few opcodes are multi-word. */
+typedef enum {
+  /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types.
+   * Arg for all of these is the upb selector for this field. */
+#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type
+  T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
+  T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
+#undef T
+  OP_STARTMSG       = 9,   /* No arg. */
+  OP_ENDMSG         = 10,  /* No arg. */
+  OP_STARTSEQ       = 11,
+  OP_ENDSEQ         = 12,
+  OP_STARTSUBMSG    = 14,
+  OP_ENDSUBMSG      = 19,
+  OP_STARTSTR       = 20,
+  OP_STRING         = 21,
+  OP_ENDSTR         = 22,
+
+  OP_PUSHTAGDELIM   = 23,  /* No arg. */
+  OP_PUSHLENDELIM   = 24,  /* No arg. */
+  OP_POP            = 25,  /* No arg. */
+  OP_SETDELIM       = 26,  /* No arg. */
+  OP_SETBIGGROUPNUM = 27,  /* two words:
+                            *   | unused (24)     | opc (8) |
+                            *   |        groupnum (32)      | */
+  OP_CHECKDELIM     = 28,
+  OP_CALL           = 29,
+  OP_RET            = 30,
+  OP_BRANCH         = 31,
+
+  /* Different opcodes depending on how many bytes expected. */
+  OP_TAG1           = 32,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAG2           = 33,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAGN           = 34,  /* three words: */
+                           /*   | unused (16) | jump target(8) | opc (8) | */
+                           /*   |           match tag 1 (32)             | */
+                           /*   |           match tag 2 (32)             | */
+
+  OP_SETDISPATCH    = 35,  /* N words: */
+                           /*   | unused (24)         | opc | */
+                           /*   | upb_inttable* (32 or 64)  | */
+
+  OP_DISPATCH       = 36,  /* No arg. */
+
+  OP_HALT           = 37   /* No arg. */
+} opcode;
+
+#define OP_MAX OP_HALT
+
+UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
+
+/* Method group; represents a set of decoder methods that had their code
+ * emitted together, and must therefore be freed together.  Immutable once
+ * created.  It is possible we may want to expose this to users at some point.
+ *
+ * Overall ownership of Decoder objects looks like this:
+ *
+ *                +----------+
+ *                |          | <---> DecoderMethod
+ *                | method   |
+ * CodeCache ---> |  group   | <---> DecoderMethod
+ *                |          |
+ *                | (mgroup) | <---> DecoderMethod
+ *                +----------+
+ */
+struct mgroup {
+  upb_refcounted base;
+
+  /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod.  We own refs on the
+   * methods. */
+  upb_inttable methods;
+
+  /* When we add the ability to link to previously existing mgroups, we'll
+   * need an array of mgroups we reference here, and own refs on them. */
+
+  /* The bytecode for our methods, if any exists.  Owned by us. */
+  uint32_t *bytecode;
+  uint32_t *bytecode_end;
+
+#ifdef UPB_USE_JIT_X64
+  /* JIT-generated machine code, if any. */
+  upb_string_handlerfunc *jit_code;
+  /* The size of the jit_code (required to munmap()). */
+  size_t jit_size;
+  char *debug_info;
+  void *dl;
+#endif
+};
+
+/* The maximum that any submessages can be nested.  Matches proto2's limit.
+ * This specifies the size of the decoder's statically-sized array and therefore
+ * setting it high will cause the upb::pb::Decoder object to be larger.
+ *
+ * If necessary we can add a runtime-settable property to Decoder that allow
+ * this to be larger than the compile-time setting, but this would add
+ * complexity, particularly since we would have to decide how/if to give users
+ * the ability to set a custom memory allocation function. */
+#define UPB_DECODER_MAX_NESTING 64
+
+/* Internal-only struct used by the decoder. */
+typedef struct {
+  /* Space optimization note: we store two pointers here that the JIT
+   * doesn't need at all; the upb_handlers* inside the sink and
+   * the dispatch table pointer.  We can optimze so that the JIT uses
+   * smaller stack frames than the interpreter.  The only thing we need
+   * to guarantee is that the fallback routines can find end_ofs. */
+  upb_sink sink;
+
+  /* The absolute stream offset of the end-of-frame delimiter.
+   * Non-delimited frames (groups and non-packed repeated fields) reuse the
+   * delimiter of their parent, even though the frame may not end there.
+   *
+   * NOTE: the JIT stores a slightly different value here for non-top frames.
+   * It stores the value relative to the end of the enclosed message.  But the
+   * top frame is still stored the same way, which is important for ensuring
+   * that calls from the JIT into C work correctly. */
+  uint64_t end_ofs;
+  const uint32_t *base;
+
+  /* 0 indicates a length-delimited field.
+   * A positive number indicates a known group.
+   * A negative number indicates an unknown group. */
+  int32_t groupnum;
+  upb_inttable *dispatch;  /* Not used by the JIT. */
+} upb_pbdecoder_frame;
+
+struct upb_pbdecodermethod {
+  upb_refcounted base;
+
+  /* While compiling, the base is relative in "ofs", after compiling it is
+   * absolute in "ptr". */
+  union {
+    uint32_t ofs;     /* PC offset of method. */
+    void *ptr;        /* Pointer to bytecode or machine code for this method. */
+  } code_base;
+
+  /* The decoder method group to which this method belongs.  We own a ref.
+   * Owning a ref on the entire group is more coarse-grained than is strictly
+   * necessary; all we truly require is that methods we directly reference
+   * outlive us, while the group could contain many other messages we don't
+   * require.  But the group represents the messages that were
+   * allocated+compiled together, so it makes the most sense to free them
+   * together also. */
+  const upb_refcounted *group;
+
+  /* Whether this method is native code or bytecode. */
+  bool is_native_;
+
+  /* The handler one calls to invoke this method. */
+  upb_byteshandler input_handler_;
+
+  /* The destination handlers this method is bound to.  We own a ref. */
+  const upb_handlers *dest_handlers_;
+
+  /* Dispatch table -- used by both bytecode decoder and JIT when encountering a
+   * field number that wasn't the one we were expecting to see.  See
+   * decoder.int.h for the layout of this table. */
+  upb_inttable dispatch;
+};
+
+struct upb_pbdecoder {
+  upb_env *env;
+
+  /* Our input sink. */
+  upb_bytessink input_;
+
+  /* The decoder method we are parsing with (owned). */
+  const upb_pbdecodermethod *method_;
+
+  size_t call_len;
+  const uint32_t *pc, *last;
+
+  /* Current input buffer and its stream offset. */
+  const char *buf, *ptr, *end, *checkpoint;
+
+  /* End of the delimited region, relative to ptr, NULL if not in this buf. */
+  const char *delim_end;
+
+  /* End of the delimited region, relative to ptr, end if not in this buf. */
+  const char *data_end;
+
+  /* Overall stream offset of "buf." */
+  uint64_t bufstart_ofs;
+
+  /* Buffer for residual bytes not parsed from the previous buffer. */
+  char residual[UPB_DECODER_MAX_RESIDUAL_BYTES];
+  char *residual_end;
+
+  /* Bytes of data that should be discarded from the input beore we start
+   * parsing again.  We set this when we internally determine that we can
+   * safely skip the next N bytes, but this region extends past the current
+   * user buffer. */
+  size_t skip;
+
+  /* Stores the user buffer passed to our decode function. */
+  const char *buf_param;
+  size_t size_param;
+  const upb_bufhandle *handle;
+
+  /* Our internal stack. */
+  upb_pbdecoder_frame *stack, *top, *limit;
+  const uint32_t **callstack;
+  size_t stack_size;
+
+  upb_status *status;
+
+#ifdef UPB_USE_JIT_X64
+  /* Used momentarily by the generated code to store a value while a user
+   * function is called. */
+  uint32_t tmp_len;
+
+  const void *saved_rsp;
+#endif
+};
+
+/* Decoder entry points; used as handlers. */
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
+size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
+                            size_t size, const upb_bufhandle *handle);
+bool upb_pbdecoder_end(void *closure, const void *handler_data);
+
+/* Decoder-internal functions that the JIT calls to handle fallback paths. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle);
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type);
+int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected);
+int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64);
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32);
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64);
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+extern const char *kPbDecoderStackOverflow;
+extern const char *kPbDecoderSubmessageTooLong;
+
+/* Access to decoderplan members needed by the decoder. */
+const char *upb_pbdecoder_getopname(unsigned int op);
+
+/* JIT codegen entry point. */
+void upb_pbdecoder_jit(mgroup *group);
+void upb_pbdecoder_freejit(mgroup *group);
+UPB_REFCOUNTED_CMETHODS(mgroup, mgroup_upcast)
+
+/* A special label that means "do field dispatch for this message and branch to
+ * wherever that takes you." */
+#define LABEL_DISPATCH 0
+
+/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or
+ * RET) for branching to when we find an appropriate ENDGROUP tag. */
+#define DISPATCH_ENDMSG 0
+
+/* It's important to use this invalid wire type instead of 0 (which is a valid
+ * wire type). */
+#define NO_WIRE_TYPE 0xff
+
+/* The dispatch table layout is:
+ *   [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
+ *
+ * If wt1 matches, jump to the 48-bit offset.  If wt2 matches, lookup
+ * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
+ *
+ * We need two wire types because of packed/non-packed compatibility.  A
+ * primitive repeated field can use either wire type and be valid.  While we
+ * could key the table on fieldnum+wiretype, the table would be 8x sparser.
+ *
+ * Storing two wire types in the primary value allows us to quickly rule out
+ * the second wire type without needing to do a separate lookup (this case is
+ * less common than an unknown field). */
+UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1,
+                                               uint8_t wt2) {
+  return (ofs << 16) | (wt2 << 8) | wt1;
+}
+
+UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs,
+                                             uint8_t *wt1, uint8_t *wt2) {
+  *wt1 = (uint8_t)dispatch;
+  *wt2 = (uint8_t)(dispatch >> 8);
+  *ofs = dispatch >> 16;
+}
+
+/* All of the functions in decoder.c that return int32_t return values according
+ * to the following scheme:
+ *   1. negative values indicate a return code from the following list.
+ *   2. positive values indicate that error or end of buffer was hit, and
+ *      that the decode function should immediately return the given value
+ *      (the decoder state has already been suspended and is ready to be
+ *      resumed). */
+#define DECODE_OK -1
+#define DECODE_MISMATCH -2  /* Used only from checktag_slow(). */
+#define DECODE_ENDGROUP -3  /* Used only from checkunknown(). */
+
+#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; }
+
+#endif  /* UPB_DECODER_INT_H_ */
+/*
+** A number of routines for varint manipulation (we keep them all around to
+** have multiple approaches available for benchmarking).
+*/
+
+#ifndef UPB_VARINT_DECODER_H_
+#define UPB_VARINT_DECODER_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A list of types as they are encoded on-the-wire. */
+typedef enum {
+  UPB_WIRE_TYPE_VARINT      = 0,
+  UPB_WIRE_TYPE_64BIT       = 1,
+  UPB_WIRE_TYPE_DELIMITED   = 2,
+  UPB_WIRE_TYPE_START_GROUP = 3,
+  UPB_WIRE_TYPE_END_GROUP   = 4,
+  UPB_WIRE_TYPE_32BIT       = 5
+} upb_wiretype_t;
+
+#define UPB_MAX_WIRE_TYPE 5
+
+/* The maximum number of bytes that it takes to encode a 64-bit varint.
+ * Note that with a better encoding this could be 9 (TODO: write up a
+ * wiki document about this). */
+#define UPB_PB_VARINT_MAX_LEN 10
+
+/* Array of the "native" (ie. non-packed-repeated) wire type for the given a
+ * descriptor type (upb_descriptortype_t). */
+extern const uint8_t upb_pb_native_wire_types[];
+
+/* Zig-zag encoding/decoding **************************************************/
+
+UPB_INLINE int32_t upb_zzdec_32(uint32_t n) {
+  return (n >> 1) ^ -(int32_t)(n & 1);
+}
+UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
+  return (n >> 1) ^ -(int64_t)(n & 1);
+}
+UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+/* Decoding *******************************************************************/
+
+/* All decoding functions return this struct by value. */
+typedef struct {
+  const char *p;  /* NULL if the varint was unterminated. */
+  uint64_t val;
+} upb_decoderet;
+
+UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) {
+  upb_decoderet ret;
+  ret.p = p;
+  ret.val = val;
+  return ret;
+}
+
+/* Four functions for decoding a varint of at most eight bytes.  They are all
+ * functionally identical, but are implemented in different ways and likely have
+ * different performance profiles.  We keep them around for performance testing.
+ *
+ * Note that these functions may not read byte-by-byte, so they must not be used
+ * unless there are at least eight bytes left in the buffer! */
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_wright(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r);
+
+/* Template for a function that checks the first two bytes with branching
+ * and dispatches 2-10 bytes with a separate function.  Note that this may read
+ * up to 10 bytes, so it must not be used unless there are at least ten bytes
+ * left in the buffer! */
+#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function)                  \
+UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) {         \
+  uint8_t *p = (uint8_t*)_p;                                                   \
+  upb_decoderet r;                                                             \
+  if ((*p & 0x80) == 0) {                                                      \
+  /* Common case: one-byte varint. */                                          \
+    return upb_decoderet_make(_p + 1, *p & 0x7fU);                             \
+  }                                                                            \
+  r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7));    \
+  if ((*(p + 1) & 0x80) == 0) {                                                \
+    /* Two-byte varint. */                                                     \
+    return r;                                                                  \
+  }                                                                            \
+  /* Longer varint, fallback to out-of-line function. */                       \
+  return decode_max8_function(r);                                              \
+}
+
+UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32)
+UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64)
+UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright)
+UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino)
+#undef UPB_VARINT_DECODER_CHECK2
+
+/* Our canonical functions for decoding varints, based on the currently
+ * favored best-performing implementations. */
+UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
+  if (sizeof(long) == 8)
+    return upb_vdecode_check2_branch64(p);
+  else
+    return upb_vdecode_check2_branch32(p);
+}
+
+UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) {
+  return upb_vdecode_max8_massimino(r);
+}
+
+
+/* Encoding *******************************************************************/
+
+UPB_INLINE int upb_value_size(uint64_t val) {
+#ifdef __GNUC__
+  int high_bit = 63 - __builtin_clzll(val);  /* 0-based, undef if val == 0. */
+#else
+  int high_bit = 0;
+  uint64_t tmp = val;
+  while(tmp >>= 1) high_bit++;
+#endif
+  return val == 0 ? 1 : high_bit / 8 + 1;
+}
+
+/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN
+ * bytes long), returning how many bytes were used.
+ *
+ * TODO: benchmark and optimize if necessary. */
+UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
+  size_t i;
+  if (val == 0) { buf[0] = 0; return 1; }
+  i = 0;
+  while (val) {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val) byte |= 0x80U;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+UPB_INLINE size_t upb_varint_size(uint64_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  return upb_vencode64(val, buf);
+}
+
+/* Encodes a 32-bit varint, *not* sign-extended. */
+UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  size_t bytes = upb_vencode64(val, buf);
+  uint64_t ret = 0;
+  assert(bytes <= 5);
+  memcpy(&ret, buf, bytes);
+  assert(ret <= 0xffffffffffU);
+  return ret;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_VARINT_DECODER_H_ */
+/*
+** upb::pb::Encoder (upb_pb_encoder)
+**
+** Implements a set of upb_handlers that write protobuf data to the binary wire
+** format.
+**
+** This encoder implementation does not have any access to any out-of-band or
+** precomputed lengths for submessages, so it must buffer submessages internally
+** before it can emit the first byte.
+*/
+
+#ifndef UPB_ENCODER_H_
+#define UPB_ENCODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class Encoder;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder)
+
+#define UPB_PBENCODER_MAX_NESTING 100
+
+/* upb::pb::Encoder ***********************************************************/
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_ENCODER_SIZE 768
+
+#ifdef __cplusplus
+
+class upb::pb::Encoder {
+ public:
+  /* Creates a new encoder in the given environment.  The Handlers must have
+   * come from NewHandlers() below. */
+  static Encoder* Create(Environment* env, const Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the encoder. */
+  Sink* input();
+
+  /* Creates a new set of handlers for this MessageDef. */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* msg);
+
+  static const size_t kSize = UPB_PB_ENCODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner);
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
+upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h,
+                                      upb_bytessink* output);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline Encoder* Encoder::Create(Environment* env, const Handlers* handlers,
+                                BytesSink* output) {
+  return upb_pb_encoder_create(env, handlers, output);
+}
+inline Sink* Encoder::input() {
+  return upb_pb_encoder_input(this);
+}
+inline reffed_ptr<const Handlers> Encoder::NewHandlers(
+    const upb::MessageDef *md) {
+  const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_ENCODER_H_ */
+/*
+** upb's core components like upb_decoder and upb_msg are carefully designed to
+** avoid depending on each other for maximum orthogonality.  In other words,
+** you can use a upb_decoder to decode into *any* kind of structure; upb_msg is
+** just one such structure.  A upb_msg can be serialized/deserialized into any
+** format, protobuf binary format is just one such format.
+**
+** However, for convenience we provide functions here for doing common
+** operations like deserializing protobuf binary format into a upb_msg.  The
+** compromise is that this file drags in almost all of upb as a dependency,
+** which could be undesirable if you're trying to use a trimmed-down build of
+** upb.
+**
+** While these routines are convenient, they do not reuse any encoding/decoding
+** state.  For example, if a decoder is JIT-based, it will be re-JITted every
+** time these functions are called.  For this reason, if you are parsing lots
+** of data and efficiency is an issue, these may not be the best functions to
+** use (though they are useful for prototyping, before optimizing).
+*/
+
+#ifndef UPB_GLUE_H
+#define UPB_GLUE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+#include <vector>
+
+extern "C" {
+#endif
+
+/* Loads a binary descriptor and returns a NULL-terminated array of unfrozen
+ * filedefs.  The caller owns the returned array, which must be freed with
+ * upb_gfree(). */
+upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner,
+                                 upb_status *status);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+
+namespace upb {
+
+inline bool LoadDescriptor(const char* buf, size_t n, Status* status,
+                           std::vector<reffed_ptr<FileDef> >* files) {
+  FileDef** parsed_files = upb_loaddescriptor(buf, n, &parsed_files, status);
+
+  if (parsed_files) {
+    FileDef** p = parsed_files;
+    while (*p) {
+      files->push_back(reffed_ptr<FileDef>(*p, &parsed_files));
+      ++p;
+    }
+    free(parsed_files);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* Templated so it can accept both string and std::string. */
+template <typename T>
+bool LoadDescriptor(const T& desc, Status* status,
+                    std::vector<reffed_ptr<FileDef> >* files) {
+  return LoadDescriptor(desc.c_str(), desc.size(), status, files);
+}
+
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_GLUE_H */
+/*
+** upb::pb::TextPrinter (upb_textprinter)
+**
+** Handlers for writing to protobuf text format.
+*/
+
+#ifndef UPB_TEXT_H_
+#define UPB_TEXT_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class TextPrinter;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter)
+
+#ifdef __cplusplus
+
+class upb::pb::TextPrinter {
+ public:
+  /* The given handlers must have come from NewHandlers().  It must outlive the
+   * TextPrinter. */
+  static TextPrinter *Create(Environment *env, const upb::Handlers *handlers,
+                             BytesSink *output);
+
+  void SetSingleLineMode(bool single_line);
+
+  Sink* input();
+
+  /* If handler caching becomes a requirement we can add a code cache as in
+   * decoder.h */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md);
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output);
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
+upb_sink *upb_textprinter_input(upb_textprinter *p);
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline TextPrinter *TextPrinter::Create(Environment *env,
+                                        const upb::Handlers *handlers,
+                                        BytesSink *output) {
+  return upb_textprinter_create(env, handlers, output);
+}
+inline void TextPrinter::SetSingleLineMode(bool single_line) {
+  upb_textprinter_setsingleline(this, single_line);
+}
+inline Sink* TextPrinter::input() {
+  return upb_textprinter_input(this);
+}
+inline reffed_ptr<const Handlers> TextPrinter::NewHandlers(
+    const MessageDef *md) {
+  const Handlers* h = upb_textprinter_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_TEXT_H_ */
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** Parses JSON according to a specific schema.
+** Support for parsing arbitrary JSON (schema-less) will be added later.
+*/
+
+#ifndef UPB_JSON_PARSER_H_
+#define UPB_JSON_PARSER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Parser;
+class ParserMethod;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser)
+UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted,
+                         upb_json_parsermethod, upb_refcounted)
+
+/* upb::json::Parser **********************************************************/
+
+/* Preallocation hint: parser won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the parser library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_JSON_PARSER_SIZE 4112
+
+#ifdef __cplusplus
+
+/* Parses an incoming BytesStream, pushing the results to the destination
+ * sink. */
+class upb::json::Parser {
+ public:
+  static Parser* Create(Environment* env, const ParserMethod* method,
+                        Sink* output);
+
+  BytesSink* input();
+
+ private:
+  UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser)
+};
+
+class upb::json::ParserMethod {
+ public:
+  /* Include base methods from upb::ReferenceCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Returns handlers for parsing according to the specified schema. */
+  static reffed_ptr<const ParserMethod> New(const upb::MessageDef* md);
+
+  /* The destination handlers that are statically bound to this method.
+   * This method is only capable of outputting to a sink that uses these
+   * handlers. */
+  const Handlers* dest_handlers() const;
+
+  /* The input handlers for this decoder method. */
+  const BytesHandler* input_handler() const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(ParserMethod, upb::json::ParserMethod)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+upb_json_parser* upb_json_parser_create(upb_env* e,
+                                        const upb_json_parsermethod* m,
+                                        upb_sink* output);
+upb_bytessink *upb_json_parser_input(upb_json_parser *p);
+
+upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md,
+                                                 const void* owner);
+const upb_handlers *upb_json_parsermethod_desthandlers(
+    const upb_json_parsermethod *m);
+const upb_byteshandler *upb_json_parsermethod_inputhandler(
+    const upb_json_parsermethod *m);
+
+/* Include refcounted methods like upb_json_parsermethod_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_json_parsermethod, upb_json_parsermethod_upcast)
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Parser* Parser::Create(Environment* env, const ParserMethod* method,
+                              Sink* output) {
+  return upb_json_parser_create(env, method, output);
+}
+inline BytesSink* Parser::input() {
+  return upb_json_parser_input(this);
+}
+
+inline const Handlers* ParserMethod::dest_handlers() const {
+  return upb_json_parsermethod_desthandlers(this);
+}
+inline const BytesHandler* ParserMethod::input_handler() const {
+  return upb_json_parsermethod_inputhandler(this);
+}
+/* static */
+inline reffed_ptr<const ParserMethod> ParserMethod::New(
+    const MessageDef* md) {
+  const upb_json_parsermethod *m = upb_json_parsermethod_new(md, &m);
+  return reffed_ptr<const ParserMethod>(m, &m);
+}
+
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+
+#endif  /* UPB_JSON_PARSER_H_ */
+/*
+** upb::json::Printer
+**
+** Handlers that emit JSON according to a specific protobuf schema.
+*/
+
+#ifndef UPB_JSON_TYPED_PRINTER_H_
+#define UPB_JSON_TYPED_PRINTER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Printer;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer)
+
+
+/* upb::json::Printer *********************************************************/
+
+#define UPB_JSON_PRINTER_SIZE 176
+
+#ifdef __cplusplus
+
+/* Prints an incoming stream of data to a BytesSink in JSON format. */
+class upb::json::Printer {
+ public:
+  static Printer* Create(Environment* env, const upb::Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the printer. */
+  Sink* input();
+
+  /* Returns handlers for printing according to the specified schema.
+   * If preserve_proto_fieldnames is true, the output JSON will use the
+   * original .proto field names (ie. {"my_field":3}) instead of using
+   * camelCased names, which is the default: (eg. {"myField":3}). */
+  static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md,
+                                                bool preserve_proto_fieldnames);
+
+  static const size_t kSize = UPB_JSON_PRINTER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output);
+upb_sink *upb_json_printer_input(upb_json_printer *p);
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 bool preserve_fieldnames,
+                                                 const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers,
+                                BytesSink* output) {
+  return upb_json_printer_create(env, handlers, output);
+}
+inline Sink* Printer::input() { return upb_json_printer_input(this); }
+inline reffed_ptr<const Handlers> Printer::NewHandlers(
+    const upb::MessageDef *md, bool preserve_proto_fieldnames) {
+  const Handlers* h = upb_json_printer_newhandlers(
+      md, preserve_proto_fieldnames, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_JSON_TYPED_PRINTER_H_ */
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
new file mode 100644
index 0000000..c542abf
--- /dev/null
+++ b/ruby/google-protobuf.gemspec
@@ -0,0 +1,25 @@
+Gem::Specification.new do |s|
+  s.name        = "google-protobuf"
+  s.version     = "3.0.0.alpha.6.0.0"
+  s.licenses    = ["BSD"]
+  s.summary     = "Protocol Buffers"
+  s.description = "Protocol Buffers are Google's data interchange format."
+  s.homepage    = "https://developers.google.com/protocol-buffers"
+  s.authors     = ["Protobuf Authors"]
+  s.email       = "protobuf@googlegroups.com"
+  s.require_paths = ["lib"]
+  s.files       = Dir.glob('lib/**/*.rb')
+  if RUBY_PLATFORM == "java"
+    s.files     += ["lib/google/protobuf_java.jar"]
+  else
+    s.files     += Dir.glob('ext/**/*')
+    s.extensions= ["ext/google/protobuf_c/extconf.rb"]
+    s.add_development_dependency "rake-compiler-dock"
+  end
+  s.test_files  = ["tests/basic.rb",
+                  "tests/stress.rb",
+                  "tests/generated_code_test.rb"]
+  s.add_development_dependency "rake-compiler"
+  s.add_development_dependency "test-unit"
+  s.add_development_dependency "rubygems-tasks"
+end
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
new file mode 100644
index 0000000..62bdd1b
--- /dev/null
+++ b/ruby/lib/google/protobuf.rb
@@ -0,0 +1,76 @@
+# 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.
+
+# require mixins before we hook them into the java & c code
+require 'google/protobuf/message_exts'
+
+# We define these before requiring the platform-specific modules.
+# That way the module init can grab references to these.
+module Google
+  module Protobuf
+    class Error < StandardError; end
+    class ParseError < Error; end
+  end
+end
+
+if RUBY_PLATFORM == "java"
+  require 'json'
+  require 'google/protobuf_java'
+else
+  begin
+    require "google/#{RUBY_VERSION.sub(/\.\d$/, '')}/protobuf_c"
+  rescue LoadError
+    require 'google/protobuf_c'
+  end
+end
+
+require 'google/protobuf/repeated_field'
+
+module Google
+  module Protobuf
+
+    def self.encode(msg)
+      msg.to_proto
+    end
+
+    def self.encode_json(msg)
+      msg.to_json
+    end
+
+    def self.decode(klass, proto)
+      klass.decode(proto)
+    end
+
+    def self.decode_json(klass, json)
+      klass.decode_json(json)
+    end
+
+  end
+end
diff --git a/ruby/lib/google/protobuf/message_exts.rb b/ruby/lib/google/protobuf/message_exts.rb
new file mode 100644
index 0000000..e10266b
--- /dev/null
+++ b/ruby/lib/google/protobuf/message_exts.rb
@@ -0,0 +1,53 @@
+# 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.
+
+module Google
+  module Protobuf
+    module MessageExts
+
+      #this is only called in jruby; mri loades the ClassMethods differently
+      def self.included(klass)
+        klass.extend(ClassMethods)
+      end
+
+      module ClassMethods
+      end
+
+      def to_json
+        self.class.encode_json(self)
+      end
+
+      def to_proto
+        self.class.encode(self)
+      end
+
+    end
+  end
+end
diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb
new file mode 100644
index 0000000..0ad2060
--- /dev/null
+++ b/ruby/lib/google/protobuf/repeated_field.rb
@@ -0,0 +1,188 @@
+# 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.
+
+require 'forwardable'
+
+#
+# This class makes RepeatedField act (almost-) like a Ruby Array.
+# It has convenience methods that extend the core C or Java based
+# methods.
+#
+# This is a best-effort to mirror Array behavior.  Two comments:
+#  1) patches always welcome :)
+#  2) if performance is an issue, feel free to rewrite the method
+#     in jruby and C.  The source code has plenty of examples
+#
+# KNOWN ISSUES
+#   - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'`
+#   - #concat should return the orig array
+#   - #push should accept multiple arguments and push them all at the same time
+#
+module Google
+  module Protobuf
+    class RepeatedField
+      extend Forwardable
+
+      # methods defined in C or Java:
+      #   +
+      #   [], at
+      #   []=
+      #   concat
+      #   clear
+      #   dup, clone
+      #   each
+      #   push, <<
+      #   replace
+      #   length, size
+      #   ==
+      #   to_ary, to_a
+      #   also all enumerable
+      #
+      # NOTE:  using delegators rather than method_missing to make the
+      #        relationship explicit instead of implicit
+      def_delegators :to_ary,
+        :&, :*, :-, :'<=>',
+        :assoc, :bsearch, :bsearch_index, :combination, :compact, :count,
+        :cycle, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten,
+        :include?, :index, :inspect, :join,
+        :pack, :permutation, :product, :pretty_print, :pretty_print_cycle,
+        :rassoc, :repeated_combination, :repeated_permutation, :reverse,
+        :rindex, :rotate, :sample, :shuffle, :shelljoin, :slice,
+        :to_s, :transpose, :uniq, :|
+
+
+      def first(n=nil)
+        n ? self[0..n] : self[0]
+      end
+
+
+      def last(n=nil)
+        n ? self[(self.size-n-1)..-1] : self[-1]
+      end
+
+
+      def pop(n=nil)
+        if n
+          results = []
+          n.times{ results << pop_one }
+          return results
+        else
+          return pop_one
+        end
+      end
+
+
+      def empty?
+        self.size == 0
+      end
+
+      # array aliases into enumerable
+      alias_method :each_index, :each_with_index
+      alias_method :slice, :[]
+      alias_method :values_at, :select
+      alias_method :map, :collect
+
+
+      class << self
+        def define_array_wrapper_method(method_name)
+          define_method(method_name) do |*args, &block|
+            arr = self.to_a
+            result = arr.send(method_name, *args)
+            self.replace(arr)
+            return result if result
+            return block ? block.call : result
+          end
+        end
+        private :define_array_wrapper_method
+
+
+        def define_array_wrapper_with_result_method(method_name)
+          define_method(method_name) do |*args, &block|
+            # result can be an Enumerator, Array, or nil
+            # Enumerator can sometimes be returned if a block is an optional argument and it is not passed in
+            # nil usually specifies that no change was made
+            result = self.to_a.send(method_name, *args, &block)
+            if result
+              new_arr = result.to_a
+              self.replace(new_arr)
+              if result.is_a?(Enumerator)
+                # generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will
+                # reset the enum with the same length, but all the #next calls will
+                # return nil
+                result = new_arr.to_enum
+                # generate a wrapper enum so any changes which occur by a chained
+                # enum can be captured
+                ie = ProxyingEnumerator.new(self, result)
+                result = ie.to_enum
+              end
+            end
+            result
+          end
+        end
+        private :define_array_wrapper_with_result_method
+      end
+
+
+      %w(delete delete_at delete_if shift slice! unshift).each do |method_name|
+        define_array_wrapper_method(method_name)
+      end
+
+
+      %w(collect! compact! fill flatten! insert reverse!
+        rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name|
+        define_array_wrapper_with_result_method(method_name)
+      end
+      alias_method :keep_if, :select!
+      alias_method :map!, :collect!
+      alias_method :reject!, :delete_if
+
+
+      # propagates changes made by user of enumerator back to the original repeated field.
+      # This only applies in cases where the calling function which created the enumerator,
+      # such as #sort!, modifies itself rather than a new array, such as #sort
+      class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator)
+        def each(*args, &block)
+          results = []
+          external_enumerator.each_with_index do |val, i|
+            result = yield(val)
+            results << result
+            #nil means no change occured from yield; usually occurs when #to_a is called
+            if result
+              repeated_field[i] = result if result != val
+            end
+          end
+          results
+        end
+      end
+
+
+    end
+  end
+end
diff --git a/ruby/pom.xml b/ruby/pom.xml
new file mode 100644
index 0000000..4cbd6d3
--- /dev/null
+++ b/ruby/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+      <groupId>com.google</groupId>
+      <artifactId>google</artifactId>
+      <version>1</version>
+    </parent>
+
+    <groupId>com.google.protobuf.jruby</groupId>
+    <artifactId>protobuf-jruby</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>Protocol Buffer JRuby native extension</name>
+    <description>
+      Protocol Buffers are a way of encoding structured data in an efficient yet
+      extensible format.
+    </description>
+    <inceptionYear>2014</inceptionYear>
+    <url>https://developers.google.com/protocol-buffers/</url>
+    <licenses>
+      <license>
+        <name>New BSD license</name>
+        <url>http://www.opensource.org/licenses/bsd-license.php</url>
+        <distribution>repo</distribution>
+      </license>
+    </licenses>
+    <scm>
+      <url>https://github.com/google/protobuf</url>
+      <connection>
+        scm:git:https://github.com/google/protobuf.git
+      </connection>
+    </scm>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <ruby.sources>lib/google</ruby.sources>
+        <jar.finalName>protobuf_java</jar.finalName>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <finalName>${jar.finalName}</finalName>
+                    <outputDirectory>${ruby.sources}</outputDirectory>
+                    <appendAssemblyId>false</appendAssemblyId>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-compiler-plugin</artifactId>
+              <configuration>
+                <source>1.6</source>
+                <target>1.6</target>
+              </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.4.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jruby</groupId>
+            <artifactId>jruby-complete</artifactId>
+            <version>1.7.13</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>3.0.0-alpha-3</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java
new file mode 100644
index 0000000..5addae5
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java
@@ -0,0 +1,167 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.*;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "Builder")
+public class RubyBuilder extends RubyObject {
+    public static void createRubyBuilder(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cBuilder = protobuf.defineClassUnder("Builder", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyBuilder(runtime, klazz);
+            }
+        });
+        cBuilder.defineAnnotatedMethods(RubyBuilder.class);
+    }
+
+    public RubyBuilder(Ruby runtime, RubyClass metaClass) {
+        super(runtime, metaClass);
+        this.cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor");
+        this.cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor");
+        this.cMessageBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MessageBuilderContext");
+        this.cEnumBuilderContext = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumBuilderContext");
+    }
+
+    /*
+     * call-seq:
+     *     Builder.new => builder
+     *
+     * Creates a new Builder. A Builder can accumulate a set of new message and enum
+     * descriptors and atomically register them into a pool in a way that allows for
+     * (co)recursive type references.
+     */
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        Ruby runtime = context.runtime;
+        this.pendingList = runtime.newArray();
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     Builder.add_message(name, &block)
+     *
+     * Creates a new, empty descriptor with the given name, and invokes the block in
+     * the context of a MessageBuilderContext on that descriptor. The block can then
+     * call, e.g., MessageBuilderContext#optional and MessageBuilderContext#repeated
+     * methods to define the message fields.
+     *
+     * This is the recommended, idiomatic way to build message definitions.
+     */
+    @JRubyMethod(name = "add_message")
+    public IRubyObject addMessage(ThreadContext context, IRubyObject name, Block block) {
+        RubyDescriptor msgdef = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
+        IRubyObject ctx = cMessageBuilderContext.newInstance(context, msgdef, this, Block.NULL_BLOCK);
+        msgdef.setName(context, name);
+        if (block.isGiven()) {
+            if (block.arity() == Arity.ONE_ARGUMENT) {
+                block.yield(context, ctx);
+            } else {
+                Binding binding = block.getBinding();
+                binding.setSelf(ctx);
+                block.yieldSpecific(context);
+            }
+        }
+        this.pendingList.add(msgdef);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Builder.add_enum(name, &block)
+     *
+     * Creates a new, empty enum descriptor with the given name, and invokes the block in
+     * the context of an EnumBuilderContext on that descriptor. The block can then
+     * call EnumBuilderContext#add_value to define the enum values.
+     *
+     * This is the recommended, idiomatic way to build enum definitions.
+     */
+    @JRubyMethod(name = "add_enum")
+    public IRubyObject addEnum(ThreadContext context, IRubyObject name, Block block) {
+        RubyEnumDescriptor enumDef = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK);
+        IRubyObject ctx = cEnumBuilderContext.newInstance(context, enumDef, Block.NULL_BLOCK);
+        enumDef.setName(context, name);
+
+        if (block.isGiven()) {
+            if (block.arity() == Arity.ONE_ARGUMENT) {
+                block.yield(context, ctx);
+            } else {
+                Binding binding = block.getBinding();
+                binding.setSelf(ctx);
+                block.yieldSpecific(context);
+            }
+        }
+
+        this.pendingList.add(enumDef);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Builder.finalize_to_pool(pool)
+     *
+     * Adds all accumulated message and enum descriptors created in this builder
+     * context to the given pool. The operation occurs atomically, and all
+     * descriptors can refer to each other (including in cycles). This is the only
+     * way to build (co)recursive message definitions.
+     *
+     * This method is usually called automatically by DescriptorPool#build after it
+     * invokes the given user block in the context of the builder. The user should
+     * not normally need to call this manually because a Builder is not normally
+     * created manually.
+     */
+    @JRubyMethod(name = "finalize_to_pool")
+    public IRubyObject finalizeToPool(ThreadContext context, IRubyObject rbPool) {
+        RubyDescriptorPool pool = (RubyDescriptorPool) rbPool;
+        for (int i = 0; i < this.pendingList.size(); i++) {
+            IRubyObject defRb = this.pendingList.entry(i);
+            if (defRb instanceof RubyDescriptor) {
+                pool.addToSymtab(context, (RubyDescriptor) defRb);
+            } else {
+                pool.addToSymtab(context, (RubyEnumDescriptor) defRb);
+            }
+        }
+        this.pendingList = context.runtime.newArray();
+        return context.runtime.getNil();
+    }
+
+    protected RubyArray pendingList;
+    private RubyClass cDescriptor, cEnumDescriptor, cMessageBuilderContext, cEnumBuilderContext;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
new file mode 100644
index 0000000..dd9179b
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java
@@ -0,0 +1,269 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+@JRubyClass(name = "Descriptor", include = "Enumerable")
+public class RubyDescriptor extends RubyObject {
+    public static void createRubyDescriptor(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cDescriptor = protobuf.defineClassUnder("Descriptor", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyDescriptor(runtime, klazz);
+            }
+        });
+        cDescriptor.includeModule(runtime.getEnumerable());
+        cDescriptor.defineAnnotatedMethods(RubyDescriptor.class);
+    }
+
+    public RubyDescriptor(Ruby runtime, RubyClass klazz) {
+        super(runtime, klazz);
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.new => descriptor
+     *
+     * Creates a new, empty, message type descriptor. At a minimum, its name must be
+     * set before it is added to a pool. It cannot be used to create messages until
+     * it is added to a pool, after which it becomes immutable (as part of a
+     * finalization process).
+     */
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        this.builder = DescriptorProtos.DescriptorProto.newBuilder();
+        this.fieldDefMap = new HashMap<String, RubyFieldDescriptor>();
+        this.oneofDefs = new HashMap<IRubyObject, RubyOneofDescriptor>();
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.name => name
+     *
+     * Returns the name of this message type as a fully-qualfied string (e.g.,
+     * My.Package.MessageType).
+     */
+    @JRubyMethod(name = "name")
+    public IRubyObject getName(ThreadContext context) {
+        return this.name;
+    }
+
+    /*
+     * call-seq:
+     *    Descriptor.name = name
+     *
+     * Assigns a name to this message type. The descriptor must not have been added
+     * to a pool yet.
+     */
+    @JRubyMethod(name = "name=")
+    public IRubyObject setName(ThreadContext context, IRubyObject name) {
+        this.name = name;
+        this.builder.setName(Utils.escapeIdentifier(this.name.asJavaString()));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.add_field(field) => nil
+     *
+     * Adds the given FieldDescriptor to this message type. The descriptor must not
+     * have been added to a pool yet. Raises an exception if a field with the same
+     * name or number already exists. Sub-type references (e.g. for fields of type
+     * message) are not resolved at this point.
+     */
+    @JRubyMethod(name = "add_field")
+    public IRubyObject addField(ThreadContext context, IRubyObject obj) {
+        RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) obj;
+        this.fieldDefMap.put(fieldDef.getName(context).asJavaString(), fieldDef);
+        this.builder.addField(fieldDef.build());
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.lookup(name) => FieldDescriptor
+     *
+     * Returns the field descriptor for the field with the given name, if present,
+     * or nil if none.
+     */
+    @JRubyMethod
+    public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) {
+        return this.fieldDefMap.get(fieldName.asJavaString());
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.msgclass => message_klass
+     *
+     * Returns the Ruby class created for this message type. Valid only once the
+     * message type has been added to a pool.
+     */
+    @JRubyMethod
+    public IRubyObject msgclass(ThreadContext context) {
+        if (this.klazz == null) {
+            this.klazz = buildClassFromDescriptor(context);
+        }
+        return this.klazz;
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.each(&block)
+     *
+     * Iterates over fields in this message type, yielding to the block on each one.
+     */
+    @JRubyMethod
+    public IRubyObject each(ThreadContext context, Block block) {
+        for (Map.Entry<String, RubyFieldDescriptor> entry : fieldDefMap.entrySet()) {
+            block.yield(context, entry.getValue());
+        }
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.add_oneof(oneof) => nil
+     *
+     * Adds the given OneofDescriptor to this message type. This descriptor must not
+     * have been added to a pool yet. Raises an exception if a oneof with the same
+     * name already exists, or if any of the oneof's fields' names or numbers
+     * conflict with an existing field in this message type. All fields in the oneof
+     * are added to the message descriptor. Sub-type references (e.g. for fields of
+     * type message) are not resolved at this point.
+     */
+    @JRubyMethod(name = "add_oneof")
+    public IRubyObject addOneof(ThreadContext context, IRubyObject obj) {
+        RubyOneofDescriptor def = (RubyOneofDescriptor) obj;
+        builder.addOneofDecl(def.build(builder.getOneofDeclCount()));
+        for (RubyFieldDescriptor fieldDescriptor : def.getFields()) {
+            addField(context, fieldDescriptor);
+        }
+        oneofDefs.put(def.getName(context), def);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.each_oneof(&block) => nil
+     *
+     * Invokes the given block for each oneof in this message type, passing the
+     * corresponding OneofDescriptor.
+     */
+    @JRubyMethod(name = "each_oneof")
+    public IRubyObject eachOneof(ThreadContext context, Block block) {
+        for (RubyOneofDescriptor oneofDescriptor : oneofDefs.values()) {
+            block.yieldSpecific(context, oneofDescriptor);
+        }
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Descriptor.lookup_oneof(name) => OneofDescriptor
+     *
+     * Returns the oneof descriptor for the oneof with the given name, if present,
+     * or nil if none.
+     */
+    @JRubyMethod(name = "lookup_oneof")
+    public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) {
+        if (name instanceof RubySymbol) {
+            name = ((RubySymbol) name).id2name();
+        }
+        return oneofDefs.containsKey(name) ? oneofDefs.get(name) : context.runtime.getNil();
+    }
+
+    public void setDescriptor(Descriptors.Descriptor descriptor) {
+        this.descriptor = descriptor;
+    }
+
+    public Descriptors.Descriptor getDescriptor() {
+        return this.descriptor;
+    }
+
+    public DescriptorProtos.DescriptorProto.Builder getBuilder() {
+        return builder;
+    }
+
+    public void setMapEntry(boolean isMapEntry) {
+        this.builder.setOptions(DescriptorProtos.MessageOptions.newBuilder().setMapEntry(isMapEntry));
+    }
+
+    private RubyModule buildClassFromDescriptor(ThreadContext context) {
+        Ruby runtime = context.runtime;
+
+        ObjectAllocator allocator = new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyMessage(runtime, klazz, descriptor);
+            }
+        };
+
+        // rb_define_class_id
+        RubyClass klass = RubyClass.newClass(runtime, runtime.getObject());
+        klass.setAllocator(allocator);
+        klass.makeMetaClass(runtime.getObject().getMetaClass());
+        klass.inherit(runtime.getObject());
+        RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts");
+        klass.include(new IRubyObject[] {messageExts});
+        klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
+        klass.defineAnnotatedMethods(RubyMessage.class);
+        return klass;
+    }
+
+    protected RubyFieldDescriptor lookup(String fieldName) {
+        return fieldDefMap.get(Utils.unescapeIdentifier(fieldName));
+    }
+
+    private IRubyObject name;
+    private RubyModule klazz;
+
+    private DescriptorProtos.DescriptorProto.Builder builder;
+    private Descriptors.Descriptor descriptor;
+    private Map<String, RubyFieldDescriptor> fieldDefMap;
+    private Map<IRubyObject, RubyOneofDescriptor> oneofDefs;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
new file mode 100644
index 0000000..0345cb9
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java
@@ -0,0 +1,169 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.*;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@JRubyClass(name = "DescriptorPool")
+public class RubyDescriptorPool extends RubyObject {
+    public static void createRubyDescriptorPool(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyDescriptorPool(runtime, klazz);
+            }
+        });
+
+        cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class);
+        descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK);
+    }
+
+    public RubyDescriptorPool(Ruby ruby, RubyClass klazz) {
+        super(ruby, klazz);
+    }
+
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        this.symtab = new HashMap<IRubyObject, IRubyObject>();
+        this.cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Builder");
+        this.builder = DescriptorProtos.FileDescriptorProto.newBuilder();
+        return this;
+    }
+
+    @JRubyMethod
+    public IRubyObject build(ThreadContext context, Block block) {
+        RubyBuilder ctx = (RubyBuilder) cBuilder.newInstance(context, Block.NULL_BLOCK);
+        if (block.arity() == Arity.ONE_ARGUMENT) {
+            block.yield(context, ctx);
+        } else {
+            Binding binding = block.getBinding();
+            binding.setSelf(ctx);
+            block.yieldSpecific(context);
+        }
+        ctx.finalizeToPool(context, this);
+        buildFileDescriptor(context);
+        return context.runtime.getNil();
+    }
+
+    @JRubyMethod
+    public IRubyObject lookup(ThreadContext context, IRubyObject name) {
+        IRubyObject descriptor = this.symtab.get(name);
+        if (descriptor == null) {
+            return context.runtime.getNil();
+        }
+        return descriptor;
+    }
+
+    /*
+     * call-seq:
+     *     DescriptorPool.generated_pool => descriptor_pool
+     *
+     * Class method that returns the global DescriptorPool. This is a singleton into
+     * which generated-code message and enum types are registered. The user may also
+     * register types in this pool for convenience so that they do not have to hold
+     * a reference to a private pool instance.
+     */
+    @JRubyMethod(meta = true, name = "generated_pool")
+    public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) {
+        return descriptorPool;
+    }
+
+    protected void addToSymtab(ThreadContext context, RubyDescriptor def) {
+        symtab.put(def.getName(context), def);
+        this.builder.addMessageType(def.getBuilder());
+    }
+
+    protected void addToSymtab(ThreadContext context, RubyEnumDescriptor def) {
+        symtab.put(def.getName(context), def);
+        this.builder.addEnumType(def.getBuilder());
+    }
+
+    private void buildFileDescriptor(ThreadContext context) {
+        Ruby runtime = context.runtime;
+        try {
+            this.builder.setSyntax("proto3");
+            final Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom(
+                    this.builder.build(), new Descriptors.FileDescriptor[]{});
+
+            for (Descriptors.EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) {
+                String enumName = Utils.unescapeIdentifier(enumDescriptor.getName());
+                if (enumDescriptor.findValueByNumber(0) == null) {
+                    throw runtime.newTypeError("Enum definition " + enumName
+                            + " does not contain a value for '0'");
+                }
+                ((RubyEnumDescriptor) symtab.get(runtime.newString(enumName)))
+                        .setDescriptor(enumDescriptor);
+            }
+            for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) {
+                RubyDescriptor rubyDescriptor = ((RubyDescriptor)
+                        symtab.get(runtime.newString(Utils.unescapeIdentifier(descriptor.getName()))));
+                for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) {
+                    if (fieldDescriptor.isRequired()) {
+                        throw runtime.newTypeError("Required fields are unsupported in proto3");
+                    }
+                    RubyFieldDescriptor rubyFieldDescriptor = rubyDescriptor.lookup(fieldDescriptor.getName());
+                    rubyFieldDescriptor.setFieldDef(fieldDescriptor);
+                    if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
+                        RubyDescriptor subType = (RubyDescriptor) lookup(context,
+                                runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getMessageType().getName())));
+                        rubyFieldDescriptor.setSubType(subType);
+                    }
+                    if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.ENUM) {
+                        RubyEnumDescriptor subType = (RubyEnumDescriptor) lookup(context,
+                                runtime.newString(Utils.unescapeIdentifier(fieldDescriptor.getEnumType().getName())));
+                        rubyFieldDescriptor.setSubType(subType);
+                    }
+                }
+                rubyDescriptor.setDescriptor(descriptor);
+            }
+        } catch (Descriptors.DescriptorValidationException e) {
+            throw runtime.newRuntimeError(e.getMessage());
+        }
+    }
+
+    private static RubyDescriptorPool descriptorPool;
+
+    private RubyClass cBuilder;
+    private Map<IRubyObject, IRubyObject> symtab;
+    private DescriptorProtos.FileDescriptorProto.Builder builder;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
new file mode 100644
index 0000000..929d869
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java
@@ -0,0 +1,86 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.RubyModule;
+import org.jruby.RubyNumeric;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+public class RubyEnum {
+    /*
+     * call-seq:
+     *     Enum.lookup(number) => name
+     *
+     * This module method, provided on each generated enum module, looks up an enum
+     * value by number and returns its name as a Ruby symbol, or nil if not found.
+     */
+    @JRubyMethod(meta = true)
+    public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) {
+        RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
+        Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
+        Descriptors.EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number));
+        if (value == null) return context.runtime.getNil();
+        return context.runtime.newSymbol(value.getName());
+    }
+
+    /*
+     * call-seq:
+     *     Enum.resolve(name) => number
+     *
+     * This module method, provided on each generated enum module, looks up an enum
+     * value by name (as a Ruby symbol) and returns its name, or nil if not found.
+     */
+    @JRubyMethod(meta = true)
+    public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) {
+        RubyEnumDescriptor rubyEnumDescriptorescriptor = (RubyEnumDescriptor) getDescriptor(context, recv);
+        Descriptors.EnumDescriptor descriptor = rubyEnumDescriptorescriptor.getDescriptor();
+        Descriptors.EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString());
+        if (value == null) return context.runtime.getNil();
+        return context.runtime.newFixnum(value.getNumber());
+    }
+
+    /*
+     * call-seq:
+     *     Enum.descriptor
+     *
+     * This module method, provided on each generated enum module, returns the
+     * EnumDescriptor corresponding to this enum type.
+     */
+    @JRubyMethod(meta = true, name = "descriptor")
+    public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
+        return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
+    }
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java
new file mode 100644
index 0000000..e4cac34
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java
@@ -0,0 +1,82 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "EnumBuilderContext")
+public class RubyEnumBuilderContext extends RubyObject {
+    public static void createRubyEnumBuilderContext(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cMessageBuilderContext = protobuf.defineClassUnder("EnumBuilderContext", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyEnumBuilderContext(runtime, klazz);
+            }
+        });
+        cMessageBuilderContext.defineAnnotatedMethods(RubyEnumBuilderContext.class);
+    }
+
+    public RubyEnumBuilderContext(Ruby ruby, RubyClass klazz) {
+        super(ruby, klazz);
+    }
+
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context, IRubyObject enumDescriptor) {
+        this.enumDescriptor = (RubyEnumDescriptor) enumDescriptor;
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     EnumBuilder.add_value(name, number)
+     *
+     * Adds the given name => number mapping to the enum type. Name must be a Ruby
+     * symbol.
+     */
+    @JRubyMethod
+    public IRubyObject value(ThreadContext context, IRubyObject name, IRubyObject number) {
+        this.enumDescriptor.addValue(context, name, number);
+        return context.runtime.getNil();
+    }
+
+    private RubyEnumDescriptor enumDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
new file mode 100644
index 0000000..4df832d
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
@@ -0,0 +1,185 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.RubyNumeric;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "EnumDescriptor", include = "Enumerable")
+public class RubyEnumDescriptor extends RubyObject {
+    public static void createRubyEnumDescriptor(Ruby runtime) {
+        RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyEnumDescriptor(runtime, klazz);
+            }
+        });
+        cEnumDescriptor.includeModule(runtime.getEnumerable());
+        cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class);
+    }
+
+    public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) {
+        super(runtime, klazz);
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.new => enum_descriptor
+     *
+     * Creates a new, empty, enum descriptor. Must be added to a pool before the
+     * enum type can be used. The enum type may only be modified prior to adding to
+     * a pool.
+     */
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        this.builder = DescriptorProtos.EnumDescriptorProto.newBuilder();
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.name => name
+     *
+     * Returns the name of this enum type.
+     */
+    @JRubyMethod(name = "name")
+    public IRubyObject getName(ThreadContext context) {
+        return this.name;
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.name = name
+     *
+     * Sets the name of this enum type. Cannot be called if the enum type has
+     * already been added to a pool.
+     */
+    @JRubyMethod(name = "name=")
+    public IRubyObject setName(ThreadContext context, IRubyObject name) {
+        this.name = name;
+        this.builder.setName(Utils.escapeIdentifier(name.asJavaString()));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.add_value(key, value)
+     *
+     * Adds a new key => value mapping to this enum type. Key must be given as a
+     * Ruby symbol. Cannot be called if the enum type has already been added to a
+     * pool. Will raise an exception if the key or value is already in use.
+     */
+    @JRubyMethod(name = "add_value")
+    public IRubyObject addValue(ThreadContext context, IRubyObject name, IRubyObject number) {
+        DescriptorProtos.EnumValueDescriptorProto.Builder valueBuilder = DescriptorProtos.EnumValueDescriptorProto.newBuilder();
+        valueBuilder.setName(name.asJavaString());
+        valueBuilder.setNumber(RubyNumeric.num2int(number));
+        this.builder.addValue(valueBuilder);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.each(&block)
+     *
+     * Iterates over key => value mappings in this enum's definition, yielding to
+     * the block with (key, value) arguments for each one.
+     */
+    @JRubyMethod
+    public IRubyObject each(ThreadContext context, Block block) {
+        Ruby runtime = context.runtime;
+        for (Descriptors.EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) {
+            block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()),
+                    runtime.newFixnum(enumValueDescriptor.getNumber())));
+        }
+        return runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     EnumDescriptor.enummodule => module
+     *
+     * Returns the Ruby module corresponding to this enum type. Cannot be called
+     * until the enum descriptor has been added to a pool.
+     */
+    @JRubyMethod
+    public IRubyObject enummodule(ThreadContext context) {
+        if (this.klazz == null) {
+            this.klazz = buildModuleFromDescriptor(context);
+        }
+        return this.klazz;
+    }
+
+    public void setDescriptor(Descriptors.EnumDescriptor descriptor) {
+        this.descriptor = descriptor;
+    }
+
+    public Descriptors.EnumDescriptor getDescriptor() {
+        return this.descriptor;
+    }
+
+    public DescriptorProtos.EnumDescriptorProto.Builder getBuilder() {
+        return this.builder;
+    }
+
+    private RubyModule buildModuleFromDescriptor(ThreadContext context) {
+        Ruby runtime = context.runtime;
+        Utils.checkNameAvailability(context, name.asJavaString());
+
+        RubyModule enumModule = RubyModule.newModule(runtime);
+        for (Descriptors.EnumValueDescriptor value : descriptor.getValues()) {
+            enumModule.defineConstant(value.getName(), runtime.newFixnum(value.getNumber()));
+        }
+
+        enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this);
+        enumModule.defineAnnotatedMethods(RubyEnum.class);
+        return enumModule;
+    }
+
+    private IRubyObject name;
+    private RubyModule klazz;
+    private Descriptors.EnumDescriptor descriptor;
+    private DescriptorProtos.EnumDescriptorProto.Builder builder;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
new file mode 100644
index 0000000..f3c488b
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java
@@ -0,0 +1,277 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "FieldDescriptor")
+public class RubyFieldDescriptor extends RubyObject {
+    public static void createRubyFileDescriptor(Ruby runtime) {
+        RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyFieldDescriptor(runtime, klazz);
+            }
+        });
+        cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class);
+    }
+
+    public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) {
+        super(runtime, klazz);
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.new => field
+     *
+     * Returns a new field descriptor. Its name, type, etc. must be set before it is
+     * added to a message type.
+     */
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        builder = DescriptorProtos.FieldDescriptorProto.newBuilder();
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.label
+     *
+     * Return the label of this field.
+     */
+    @JRubyMethod(name = "label")
+    public IRubyObject getLabel(ThreadContext context) {
+        return this.label;
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.label = label
+     *
+     * Sets the label on this field. Cannot be called if field is part of a message
+     * type already in a pool.
+     */
+    @JRubyMethod(name = "label=")
+    public IRubyObject setLabel(ThreadContext context, IRubyObject value) {
+        String labelName = value.asJavaString();
+        this.label = context.runtime.newSymbol(labelName.toLowerCase());
+        this.builder.setLabel(
+                DescriptorProtos.FieldDescriptorProto.Label.valueOf("LABEL_" + labelName.toUpperCase()));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.name => name
+     *
+     * Returns the name of this field as a Ruby String, or nil if it is not set.
+     */
+    @JRubyMethod(name = "name")
+    public IRubyObject getName(ThreadContext context) {
+        return this.name;
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.name = name
+     *
+     * Sets the name of this field. Cannot be called once the containing message
+     * type, if any, is added to a pool.
+     */
+    @JRubyMethod(name = "name=")
+    public IRubyObject setName(ThreadContext context, IRubyObject value) {
+        String nameStr = value.asJavaString();
+        this.name = context.runtime.newString(nameStr);
+        this.builder.setName(Utils.escapeIdentifier(nameStr));
+        return context.runtime.getNil();
+    }
+
+
+    @JRubyMethod(name = "subtype")
+    public IRubyObject getSubType(ThreadContext context) {
+        return subType;
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.type => type
+     *
+     * Returns this field's type, as a Ruby symbol, or nil if not yet set.
+     *
+     * Valid field types are:
+     *     :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string,
+     *     :bytes, :message.
+     */
+    @JRubyMethod(name = "type")
+    public IRubyObject getType(ThreadContext context) {
+        return Utils.fieldTypeToRuby(context, this.builder.getType());
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.type = type
+     *
+     * Sets this field's type. Cannot be called if field is part of a message type
+     * already in a pool.
+     */
+    @JRubyMethod(name = "type=")
+    public IRubyObject setType(ThreadContext context, IRubyObject value) {
+        this.builder.setType(DescriptorProtos.FieldDescriptorProto.Type.valueOf("TYPE_" + value.asJavaString().toUpperCase()));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.number => number
+     *
+     * Returns this field's number, as a Ruby Integer, or nil if not yet set.
+     *
+     */
+    @JRubyMethod(name = "number")
+    public IRubyObject getnumber(ThreadContext context) {
+        return this.number;
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.number = number
+     *
+     * Sets the tag number for this field. Cannot be called if field is part of a
+     * message type already in a pool.
+     */
+    @JRubyMethod(name = "number=")
+    public IRubyObject setNumber(ThreadContext context, IRubyObject value) {
+        this.number = value;
+        this.builder.setNumber(RubyNumeric.num2int(value));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.submsg_name = submsg_name
+     *
+     * Sets the name of the message or enum type corresponding to this field, if it
+     * is a message or enum field (respectively). This type name will be resolved
+     * within the context of the pool to which the containing message type is added.
+     * Cannot be called on field that are not of message or enum type, or on fields
+     * that are part of a message type already added to a pool.
+     */
+    @JRubyMethod(name = "submsg_name=")
+    public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) {
+        this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString()));
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.get(message) => value
+     *
+     * Returns the value set for this field on the given message. Raises an
+     * exception if message is of the wrong type.
+     */
+    @JRubyMethod(name = "get")
+    public IRubyObject getValue(ThreadContext context, IRubyObject msgRb) {
+        RubyMessage message = (RubyMessage) msgRb;
+        if (message.getDescriptor() != fieldDef.getContainingType()) {
+            throw context.runtime.newTypeError("set method called on wrong message type");
+        }
+        return message.getField(context, fieldDef);
+    }
+
+    /*
+     * call-seq:
+     *     FieldDescriptor.set(message, value)
+     *
+     * Sets the value corresponding to this field to the given value on the given
+     * message. Raises an exception if message is of the wrong type. Performs the
+     * ordinary type-checks for field setting.
+     */
+    @JRubyMethod(name = "set")
+    public IRubyObject setValue(ThreadContext context, IRubyObject msgRb, IRubyObject value) {
+        RubyMessage message = (RubyMessage) msgRb;
+        if (message.getDescriptor() != fieldDef.getContainingType()) {
+            throw context.runtime.newTypeError("set method called on wrong message type");
+        }
+        message.setField(context, fieldDef, value);
+        return context.runtime.getNil();
+    }
+
+    protected void setSubType(IRubyObject rubyDescriptor) {
+        this.subType = rubyDescriptor;
+    }
+
+    protected void setFieldDef(Descriptors.FieldDescriptor fieldDescriptor) {
+        this.fieldDef = fieldDescriptor;
+    }
+
+    protected void setOneofName(IRubyObject name) {
+        oneofName = name;
+    }
+
+    protected void setOneofIndex(int index) {
+        hasOneofIndex = true;
+        oneofIndex = index;
+    }
+
+    protected IRubyObject getOneofName() {
+        return oneofName;
+    }
+
+    protected Descriptors.FieldDescriptor getFieldDef() {
+        return fieldDef;
+    }
+
+    protected DescriptorProtos.FieldDescriptorProto build() {
+        if (hasOneofIndex)
+            builder.setOneofIndex(oneofIndex);
+        return this.builder.build();
+    }
+
+    private DescriptorProtos.FieldDescriptorProto.Builder builder;
+    private IRubyObject name;
+    private IRubyObject label;
+    private IRubyObject number;
+    private IRubyObject subType;
+    private IRubyObject oneofName;
+    private Descriptors.FieldDescriptor fieldDef;
+    private int oneofIndex;
+    private boolean hasOneofIndex = false;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
new file mode 100644
index 0000000..2d4c03b
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
@@ -0,0 +1,434 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.MapEntry;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.internal.runtime.methods.DynamicMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.util.ByteList;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@JRubyClass(name = "Map", include = "Enumerable")
+public class RubyMap extends RubyObject {
+    public static void createRubyMap(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cMap = protobuf.defineClassUnder("Map", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+                return new RubyMap(ruby, rubyClass);
+            }
+        });
+        cMap.includeModule(runtime.getEnumerable());
+        cMap.defineAnnotatedMethods(RubyMap.class);
+    }
+
+    public RubyMap(Ruby ruby, RubyClass rubyClass) {
+        super(ruby, rubyClass);
+    }
+
+    /*
+     * call-seq:
+     *     Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
+     *     => new map
+     *
+     * Allocates a new Map container. This constructor may be called with 2, 3, or 4
+     * arguments. The first two arguments are always present and are symbols (taking
+     * on the same values as field-type symbols in message descriptors) that
+     * indicate the type of the map key and value fields.
+     *
+     * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
+     * :string, :bytes.
+     *
+     * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
+     * :string, :bytes, :enum, :message.
+     *
+     * The third argument, value_typeclass, must be present if value_type is :enum
+     * or :message. As in RepeatedField#new, this argument must be a message class
+     * (for :message) or enum module (for :enum).
+     *
+     * The last argument, if present, provides initial content for map. Note that
+     * this may be an ordinary Ruby hashmap or another Map instance with identical
+     * key and value types. Also note that this argument may be present whether or
+     * not value_typeclass is present (and it is unambiguously separate from
+     * value_typeclass because value_typeclass's presence is strictly determined by
+     * value_type). The contents of this initial hashmap or Map instance are
+     * shallow-copied into the new Map: the original map is unmodified, but
+     * references to underlying objects will be shared if the value type is a
+     * message type.
+     */
+
+    @JRubyMethod(required = 2, optional = 2)
+    public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+        this.table = new HashMap<IRubyObject, IRubyObject>();
+        this.keyType = Utils.rubyToFieldType(args[0]);
+        this.valueType = Utils.rubyToFieldType(args[1]);
+
+        switch(keyType) {
+            case INT32:
+            case INT64:
+            case UINT32:
+            case UINT64:
+            case BOOL:
+            case STRING:
+            case BYTES:
+                // These are OK.
+                break;
+            default:
+                throw context.runtime.newArgumentError("Invalid key type for map.");
+        }
+
+        int initValueArg = 2;
+        if (needTypeclass(this.valueType) && args.length > 2) {
+            this.valueTypeClass = args[2];
+            Utils.validateTypeClass(context, this.valueType, this.valueTypeClass);
+            initValueArg = 3;
+        } else {
+            this.valueTypeClass = context.runtime.getNilClass();
+        }
+
+        // Table value type is always UINT64: this ensures enough space to store the
+        // native_slot value.
+        if (args.length > initValueArg) {
+            mergeIntoSelf(context, args[initValueArg]);
+        }
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     Map.[]=(key, value) => value
+     *
+     * Inserts or overwrites the value at the given key with the given new value.
+     * Throws an exception if the key type is incorrect. Returns the new value that
+     * was just inserted.
+     */
+    @JRubyMethod(name = "[]=")
+    public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
+        Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass);
+        Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass);
+        IRubyObject symbol;
+        if (valueType == Descriptors.FieldDescriptor.Type.ENUM &&
+                Utils.isRubyNum(value) &&
+                ! (symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) {
+            value = symbol;
+        }
+        this.table.put(key, value);
+        return value;
+    }
+
+    /*
+     * call-seq:
+     *     Map.[](key) => value
+     *
+     * Accesses the element at the given key. Throws an exception if the key type is
+     * incorrect. Returns nil when the key is not present in the map.
+     */
+    @JRubyMethod(name = "[]")
+    public IRubyObject index(ThreadContext context, IRubyObject key) {
+        if (table.containsKey(key))
+            return this.table.get(key);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Map.==(other) => boolean
+     *
+     * Compares this map to another. Maps are equal if they have identical key sets,
+     * and for each key, the values in both maps compare equal. Elements are
+     * compared as per normal Ruby semantics, by calling their :== methods (or
+     * performing a more efficient comparison for primitive types).
+     *
+     * Maps with dissimilar key types or value types/typeclasses are never equal,
+     * even if value comparison (for example, between integers and floats) would
+     * have otherwise indicated that every element has equal value.
+     */
+    @JRubyMethod(name = "==")
+    public IRubyObject eq(ThreadContext context, IRubyObject _other) {
+        if (_other instanceof RubyHash)
+            return toHash(context).op_equal(context, _other);
+        RubyMap other = (RubyMap) _other;
+        if (this == other) return context.runtime.getTrue();
+        if (!typeCompatible(other) || this.table.size() != other.table.size())
+            return context.runtime.getFalse();
+        for (IRubyObject key : table.keySet()) {
+            if (! other.table.containsKey(key))
+                return context.runtime.getFalse();
+            if (! other.table.get(key).equals(table.get(key)))
+                return context.runtime.getFalse();
+        }
+        return context.runtime.getTrue();
+    }
+
+    /*
+     * call-seq:
+     *     Map.inspect => string
+     *
+     * Returns a string representing this map's elements. It will be formatted as
+     * "{key => value, key => value, ...}", with each key and value string
+     * representation computed by its own #inspect method.
+     */
+    @JRubyMethod
+    public IRubyObject inspect() {
+        return toHash(getRuntime().getCurrentContext()).inspect();
+    }
+
+    /*
+     * call-seq:
+     *     Map.hash => hash_value
+     *
+     * Returns a hash value based on this map's contents.
+     */
+    @JRubyMethod
+    public IRubyObject hash(ThreadContext context) {
+        try {
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+            for (IRubyObject key : table.keySet()) {
+                digest.update((byte) key.hashCode());
+                digest.update((byte) table.get(key).hashCode());
+            }
+            return context.runtime.newString(new ByteList(digest.digest()));
+        } catch (NoSuchAlgorithmException ignore) {
+            return context.runtime.newFixnum(System.identityHashCode(table));
+        }
+    }
+
+    /*
+     * call-seq:
+     *     Map.keys => [list_of_keys]
+     *
+     * Returns the list of keys contained in the map, in unspecified order.
+     */
+    @JRubyMethod
+    public IRubyObject keys(ThreadContext context) {
+        return RubyArray.newArray(context.runtime, table.keySet());
+    }
+
+    /*
+     * call-seq:
+     *     Map.values => [list_of_values]
+     *
+     * Returns the list of values contained in the map, in unspecified order.
+     */
+    @JRubyMethod
+    public IRubyObject values(ThreadContext context) {
+        return RubyArray.newArray(context.runtime, table.values());
+    }
+
+    /*
+     * call-seq:
+     *     Map.clear
+     *
+     * Removes all entries from the map.
+     */
+    @JRubyMethod
+    public IRubyObject clear(ThreadContext context) {
+        table.clear();
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Map.each(&block)
+     *
+     * Invokes &block on each |key, value| pair in the map, in unspecified order.
+     * Note that Map also includes Enumerable; map thus acts like a normal Ruby
+     * sequence.
+     */
+    @JRubyMethod
+    public IRubyObject each(ThreadContext context, Block block) {
+        for (IRubyObject key : table.keySet()) {
+            block.yieldSpecific(context, key, table.get(key));
+        }
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     Map.delete(key) => old_value
+     *
+     * Deletes the value at the given key, if any, returning either the old value or
+     * nil if none was present. Throws an exception if the key is of the wrong type.
+     */
+    @JRubyMethod
+    public IRubyObject delete(ThreadContext context, IRubyObject key) {
+        return table.remove(key);
+    }
+
+    /*
+     * call-seq:
+     *     Map.has_key?(key) => bool
+     *
+     * Returns true if the given key is present in the map. Throws an exception if
+     * the key has the wrong type.
+     */
+    @JRubyMethod(name = "has_key?")
+    public IRubyObject hasKey(ThreadContext context, IRubyObject key) {
+        return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse();
+    }
+
+    /*
+     * call-seq:
+     *     Map.length
+     *
+     * Returns the number of entries (key-value pairs) in the map.
+     */
+    @JRubyMethod
+    public IRubyObject length(ThreadContext context) {
+        return context.runtime.newFixnum(this.table.size());
+    }
+
+    /*
+     * call-seq:
+     *     Map.dup => new_map
+     *
+     * Duplicates this map with a shallow copy. References to all non-primitive
+     * element objects (e.g., submessages) are shared.
+     */
+    @JRubyMethod
+    public IRubyObject dup(ThreadContext context) {
+        RubyMap newMap = newThisType(context);
+        for (Map.Entry<IRubyObject, IRubyObject> entry : table.entrySet()) {
+            newMap.table.put(entry.getKey(), entry.getValue());
+        }
+        return newMap;
+    }
+
+    @JRubyMethod(name = {"to_h", "to_hash"})
+    public RubyHash toHash(ThreadContext context) {
+        return RubyHash.newHash(context.runtime, table, context.runtime.getNil());
+    }
+
+    // Used by Google::Protobuf.deep_copy but not exposed directly.
+    protected IRubyObject deepCopy(ThreadContext context) {
+        RubyMap newMap = newThisType(context);
+        switch (valueType) {
+            case MESSAGE:
+                for (IRubyObject key : table.keySet()) {
+                    RubyMessage message = (RubyMessage) table.get(key);
+                    newMap.table.put(key.dup(), message.deepCopy(context));
+                }
+                break;
+            default:
+                for (IRubyObject key : table.keySet()) {
+                    newMap.table.put(key.dup(), table.get(key).dup());
+                }
+        }
+        return newMap;
+    }
+
+    protected List<DynamicMessage> build(ThreadContext context, RubyDescriptor descriptor) {
+        List<DynamicMessage> list = new ArrayList<DynamicMessage>();
+        RubyClass rubyClass = (RubyClass) descriptor.msgclass(context);
+        Descriptors.FieldDescriptor keyField = descriptor.lookup("key").getFieldDef();
+        Descriptors.FieldDescriptor valueField = descriptor.lookup("value").getFieldDef();
+        for (IRubyObject key : table.keySet()) {
+            RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK);
+            mapMessage.setField(context, keyField, key);
+            mapMessage.setField(context, valueField, table.get(key));
+            list.add(mapMessage.build(context));
+        }
+        return list;
+    }
+
+    protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) {
+        if (hashmap instanceof RubyHash) {
+            ((RubyHash) hashmap).visitAll(new RubyHash.Visitor() {
+                @Override
+                public void visit(IRubyObject key, IRubyObject val) {
+                    indexSet(context, key, val);
+                }
+            });
+        } else if (hashmap instanceof RubyMap) {
+            RubyMap other = (RubyMap) hashmap;
+            if (!typeCompatible(other)) {
+                throw context.runtime.newTypeError("Attempt to merge Map with mismatching types");
+            }
+        } else {
+            throw context.runtime.newTypeError("Unknown type merging into Map");
+        }
+        return this;
+    }
+
+    protected boolean typeCompatible(RubyMap other) {
+        return this.keyType == other.keyType &&
+                this.valueType == other.valueType &&
+                this.valueTypeClass == other.valueTypeClass;
+    }
+
+    private RubyMap newThisType(ThreadContext context) {
+        RubyMap newMap;
+        if (needTypeclass(valueType)) {
+            newMap = (RubyMap) metaClass.newInstance(context,
+                    Utils.fieldTypeToRuby(context, keyType),
+                    Utils.fieldTypeToRuby(context, valueType),
+                    valueTypeClass, Block.NULL_BLOCK);
+        } else {
+            newMap = (RubyMap) metaClass.newInstance(context,
+                    Utils.fieldTypeToRuby(context, keyType),
+                    Utils.fieldTypeToRuby(context, valueType),
+                    Block.NULL_BLOCK);
+        }
+        newMap.table = new HashMap<IRubyObject, IRubyObject>();
+        return newMap;
+    }
+
+    private boolean needTypeclass(Descriptors.FieldDescriptor.Type type) {
+        switch(type) {
+            case MESSAGE:
+            case ENUM:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private Descriptors.FieldDescriptor.Type keyType;
+    private Descriptors.FieldDescriptor.Type valueType;
+    private IRubyObject valueTypeClass;
+    private Map<IRubyObject, IRubyObject> table;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
new file mode 100644
index 0000000..39213c4
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -0,0 +1,765 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.*;
+import org.jruby.*;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.Helpers;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.util.ByteList;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class RubyMessage extends RubyObject {
+    public RubyMessage(Ruby ruby, RubyClass klazz, Descriptors.Descriptor descriptor) {
+        super(ruby, klazz);
+        this.descriptor = descriptor;
+    }
+
+    /*
+     * call-seq:
+     *     Message.new(kwargs) => new_message
+     *
+     * Creates a new instance of the given message class. Keyword arguments may be
+     * provided with keywords corresponding to field names.
+     *
+     * Note that no literal Message class exists. Only concrete classes per message
+     * type exist, as provided by the #msgclass method on Descriptors after they
+     * have been added to a pool. The method definitions described here on the
+     * Message class are provided on each concrete message class.
+     */
+    @JRubyMethod(optional = 1)
+    public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) {
+        final Ruby runtime = context.runtime;
+        this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField");
+        this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map");
+        this.builder = DynamicMessage.newBuilder(this.descriptor);
+        this.repeatedFields = new HashMap<Descriptors.FieldDescriptor, RubyRepeatedField>();
+        this.maps = new HashMap<Descriptors.FieldDescriptor, RubyMap>();
+        this.fields = new HashMap<Descriptors.FieldDescriptor, IRubyObject>();
+        this.oneofCases = new HashMap<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor>();
+        if (args.length == 1) {
+            if (!(args[0] instanceof RubyHash)) {
+                throw runtime.newArgumentError("expected Hash arguments.");
+            }
+            RubyHash hash = args[0].convertToHash();
+            hash.visitAll(new RubyHash.Visitor() {
+                @Override
+                public void visit(IRubyObject key, IRubyObject value) {
+                    if (!(key instanceof RubySymbol))
+                        throw runtime.newTypeError("Expected symbols as hash keys in initialization map.");
+                    final Descriptors.FieldDescriptor fieldDescriptor = findField(context, key);
+
+                    if (Utils.isMapEntry(fieldDescriptor)) {
+                        if (!(value instanceof RubyHash))
+                            throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" +  key.asJavaString() + "'.");
+
+                        final RubyMap map = newMapForField(context, fieldDescriptor);
+                        map.mergeIntoSelf(context, value);
+                        maps.put(fieldDescriptor, map);
+                    } else if (fieldDescriptor.isRepeated()) {
+                        if (!(value instanceof RubyArray))
+                            throw runtime.newArgumentError("Expected array as initializer value for repeated field '" +  key.asJavaString() + "'.");
+                        RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value);
+                        addRepeatedField(fieldDescriptor, repeatedField);
+                    } else {
+                        Descriptors.OneofDescriptor oneof = fieldDescriptor.getContainingOneof();
+                        if (oneof != null) {
+                            oneofCases.put(oneof, fieldDescriptor);
+                        }
+                        fields.put(fieldDescriptor, value);
+                    }
+
+                }
+            });
+        }
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     Message.[]=(index, value)
+     *
+     * Sets a field's value by field name. The provided field name should be a
+     * string.
+     */
+    @JRubyMethod(name = "[]=")
+    public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) {
+        Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
+        return setField(context, fieldDescriptor, value);
+    }
+
+    /*
+     * call-seq:
+     *     Message.[](index) => value
+     *
+     * Accesses a field's value by field name. The provided field name should be a
+     * string.
+     */
+    @JRubyMethod(name = "[]")
+    public IRubyObject index(ThreadContext context, IRubyObject fieldName) {
+        Descriptors.FieldDescriptor fieldDescriptor = findField(context, fieldName);
+        return getField(context, fieldDescriptor);
+    }
+
+    /*
+     * call-seq:
+     *     Message.inspect => string
+     *
+     * Returns a human-readable string representing this message. It will be
+     * formatted as "<MessageType: field1: value1, field2: value2, ...>". Each
+     * field's value is represented according to its own #inspect method.
+     */
+    @JRubyMethod
+    public IRubyObject inspect() {
+        String cname = metaClass.getName();
+        StringBuilder sb = new StringBuilder("<");
+        sb.append(cname);
+        sb.append(": ");
+        sb.append(this.layoutInspect());
+        sb.append(">");
+
+        return getRuntime().newString(sb.toString());
+    }
+
+    /*
+     * call-seq:
+     *     Message.hash => hash_value
+     *
+     * Returns a hash value that represents this message's field values.
+     */
+    @JRubyMethod
+    public IRubyObject hash(ThreadContext context) {
+        int hashCode = System.identityHashCode(this);
+        return context.runtime.newFixnum(hashCode);
+    }
+
+    /*
+     * call-seq:
+     *     Message.==(other) => boolean
+     *
+     * Performs a deep comparison of this message with another. Messages are equal
+     * if they have the same type and if each field is equal according to the :==
+     * method's semantics (a more efficient comparison may actually be done if the
+     * field is of a primitive type).
+     */
+    @JRubyMethod(name = "==")
+    public IRubyObject eq(ThreadContext context, IRubyObject other) {
+        Ruby runtime = context.runtime;
+        if (!(other instanceof RubyMessage))
+            return runtime.getFalse();
+        RubyMessage message = (RubyMessage) other;
+        if (descriptor != message.descriptor) {
+            return runtime.getFalse();
+        }
+
+        for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
+            IRubyObject thisVal = getField(context, fdef);
+            IRubyObject thatVal = message.getField(context, fdef);
+            IRubyObject ret = thisVal.callMethod(context, "==", thatVal);
+            if (!ret.isTrue()) {
+                return runtime.getFalse();
+            }
+        }
+        return runtime.getTrue();
+    }
+
+    /*
+     * call-seq:
+     *     Message.method_missing(*args)
+     *
+     * Provides accessors and setters for message fields according to their field
+     * names. For any field whose name does not conflict with a built-in method, an
+     * accessor is provided with the same name as the field, and a setter is
+     * provided with the name of the field plus the '=' suffix. Thus, given a
+     * message instance 'msg' with field 'foo', the following code is valid:
+     *
+     *     msg.foo = 42
+     *     puts msg.foo
+     */
+    @JRubyMethod(name = "method_missing", rest = true)
+    public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) {
+        if (args.length == 1) {
+            RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
+            IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]);
+            if (oneofDescriptor.isNil()) {
+                if (!hasField(args[0])) {
+                    return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
+                }
+                return index(context, args[0]);
+            }
+            RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor;
+            Descriptors.FieldDescriptor fieldDescriptor =
+                    oneofCases.get(rubyOneofDescriptor.getOneofDescriptor());
+            if (fieldDescriptor == null)
+                return context.runtime.getNil();
+
+            return context.runtime.newSymbol(fieldDescriptor.getName());
+        } else {
+            // fieldName is RubySymbol
+            RubyString field = args[0].asString();
+            RubyString equalSign = context.runtime.newString(Utils.EQUAL_SIGN);
+            if (field.end_with_p(context, equalSign).isTrue()) {
+                field.chomp_bang(context, equalSign);
+            }
+
+            if (!hasField(field)) {
+                return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
+            }
+            return indexSet(context, field, args[1]);
+        }
+    }
+
+    /**
+     * call-seq:
+     * Message.dup => new_message
+     * Performs a shallow copy of this message and returns the new copy.
+     */
+    @JRubyMethod
+    public IRubyObject dup(ThreadContext context) {
+        RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
+        IRubyObject value;
+        for (Descriptors.FieldDescriptor fieldDescriptor : this.descriptor.getFields()) {
+            if (fieldDescriptor.isRepeated()) {
+                dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor));
+            } else if (fields.containsKey(fieldDescriptor)) {
+                dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor));
+            } else if (this.builder.hasField(fieldDescriptor)) {
+                dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor)));
+            }
+        }
+        for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
+            dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor));
+        }
+        return dup;
+    }
+
+    /*
+     * call-seq:
+     *     Message.descriptor => descriptor
+     *
+     * Class method that returns the Descriptor instance corresponding to this
+     * message class's type.
+     */
+    @JRubyMethod(name = "descriptor", meta = true)
+    public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) {
+        return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR);
+    }
+
+    /*
+     * call-seq:
+     *     MessageClass.encode(msg) => bytes
+     *
+     * Encodes the given message object to its serialized form in protocol buffers
+     * wire format.
+     */
+    @JRubyMethod(meta = true)
+    public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject value) {
+        RubyMessage message = (RubyMessage) value;
+        return context.runtime.newString(new ByteList(message.build(context).toByteArray()));
+    }
+
+    /*
+     * call-seq:
+     *     MessageClass.decode(data) => message
+     *
+     * Decodes the given data (as a string containing bytes in protocol buffers wire
+     * format) under the interpretration given by this message class's definition
+     * and returns a message object with the corresponding field values.
+     */
+    @JRubyMethod(meta = true)
+    public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject data) {
+        byte[] bin = data.convertToString().getBytes();
+        RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
+        try {
+            ret.builder.mergeFrom(bin);
+        } catch (InvalidProtocolBufferException e) {
+            throw context.runtime.newRuntimeError(e.getMessage());
+        }
+        return ret;
+    }
+
+    /*
+     * call-seq:
+     *     MessageClass.encode_json(msg) => json_string
+     *
+     * Encodes the given message object into its serialized JSON representation.
+     */
+    @JRubyMethod(name = "encode_json", meta = true)
+    public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject msgRb) {
+        RubyMessage message = (RubyMessage) msgRb;
+        return Helpers.invoke(context, message.toHash(context), "to_json");
+    }
+
+    /*
+     * call-seq:
+     *     MessageClass.decode_json(data) => message
+     *
+     * Decodes the given data (as a string containing bytes in protocol buffers wire
+     * format) under the interpretration given by this message class's definition
+     * and returns a message object with the corresponding field values.
+     */
+    @JRubyMethod(name = "decode_json", meta = true)
+    public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject json) {
+        Ruby runtime = context.runtime;
+        RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK);
+        RubyModule jsonModule = runtime.getClassFromPath("JSON");
+        RubyHash opts = RubyHash.newHash(runtime);
+        opts.fastASet(runtime.newSymbol("symbolize_names"), runtime.getTrue());
+        IRubyObject[] args = new IRubyObject[] { Helpers.invoke(context, jsonModule, "parse", json, opts) };
+        ret.initialize(context, args);
+        return ret;
+    }
+
+    @JRubyMethod(name = {"to_h", "to_hash"})
+    public IRubyObject toHash(ThreadContext context) {
+        Ruby runtime = context.runtime;
+        RubyHash ret = RubyHash.newHash(runtime);
+        for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
+            IRubyObject value = getField(context, fdef);
+            if (!value.isNil()) {
+                if (value.respondsTo("to_h")) {
+                    value = Helpers.invoke(context, value, "to_h");
+                } else if (value.respondsTo("to_a")) {
+                    value = Helpers.invoke(context, value, "to_a");
+                }
+            }
+            ret.fastASet(runtime.newSymbol(fdef.getName()), value);
+        }
+        return ret;
+    }
+
+    protected DynamicMessage build(ThreadContext context) {
+        return build(context, 0);
+    }
+
+    protected DynamicMessage build(ThreadContext context, int depth) {
+        if (depth > SINK_MAXIMUM_NESTING) {
+            throw context.runtime.newRuntimeError("Maximum recursion depth exceeded during encoding.");
+        }
+        for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) {
+            this.builder.clearField(fieldDescriptor);
+            RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+            for (DynamicMessage kv : maps.get(fieldDescriptor).build(context, mapDescriptor)) {
+                this.builder.addRepeatedField(fieldDescriptor, kv);
+            }
+        }
+        for (Descriptors.FieldDescriptor fieldDescriptor : repeatedFields.keySet()) {
+            RubyRepeatedField repeatedField = repeatedFields.get(fieldDescriptor);
+            this.builder.clearField(fieldDescriptor);
+            for (int i = 0; i < repeatedField.size(); i++) {
+                Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth);
+                this.builder.addRepeatedField(fieldDescriptor, item);
+            }
+        }
+        for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) {
+            IRubyObject value = fields.get(fieldDescriptor);
+            this.builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth));
+        }
+        return this.builder.build();
+    }
+
+    protected Descriptors.Descriptor getDescriptor() {
+        return this.descriptor;
+    }
+
+    // Internal use only, called by Google::Protobuf.deep_copy
+    protected IRubyObject deepCopy(ThreadContext context) {
+        RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK);
+        for (Descriptors.FieldDescriptor fdef : this.descriptor.getFields()) {
+            if (fdef.isRepeated()) {
+                copy.addRepeatedField(fdef, this.getRepeatedField(context, fdef).deepCopy(context));
+            } else if (fields.containsKey(fdef)) {
+                copy.fields.put(fdef, fields.get(fdef));
+            } else if (this.builder.hasField(fdef)) {
+                copy.fields.put(fdef, wrapField(context, fdef, this.builder.getField(fdef)));
+            }
+        }
+        return copy;
+    }
+
+    private RubyRepeatedField getRepeatedField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+        if (this.repeatedFields.containsKey(fieldDescriptor)) {
+            return this.repeatedFields.get(fieldDescriptor);
+        }
+        int count = this.builder.getRepeatedFieldCount(fieldDescriptor);
+        RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
+        for (int i = 0; i < count; i++) {
+            ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i)));
+        }
+        addRepeatedField(fieldDescriptor, ret);
+        return ret;
+    }
+
+    private void addRepeatedField(Descriptors.FieldDescriptor fieldDescriptor, RubyRepeatedField repeatedField) {
+        this.repeatedFields.put(fieldDescriptor, repeatedField);
+    }
+
+    private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) {
+        this.builder.mergeFrom(dynamicMessage);
+        return this;
+    }
+
+    private Descriptors.FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) {
+        String nameStr = fieldName.asJavaString();
+        Descriptors.FieldDescriptor ret = this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr));
+        if (ret == null)
+            throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found");
+        return ret;
+    }
+
+    private boolean hasField(IRubyObject fieldName) {
+        String nameStr = fieldName.asJavaString();
+        return this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)) != null;
+    }
+
+    private void checkRepeatedFieldType(ThreadContext context, IRubyObject value,
+                                        Descriptors.FieldDescriptor fieldDescriptor) {
+        Ruby runtime = context.runtime;
+        if (!(value instanceof RubyRepeatedField)) {
+            throw runtime.newTypeError("Expected repeated field array");
+        }
+    }
+
+    // convert a ruby object to protobuf type, with type check
+    private Object convert(ThreadContext context,
+                           Descriptors.FieldDescriptor fieldDescriptor,
+                           IRubyObject value, int depth) {
+        Ruby runtime = context.runtime;
+        Object val = null;
+        switch (fieldDescriptor.getType()) {
+            case INT32:
+            case INT64:
+            case UINT32:
+            case UINT64:
+                if (!Utils.isRubyNum(value)) {
+                    throw runtime.newTypeError("Expected number type for integral field.");
+                }
+                Utils.checkIntTypePrecision(context, fieldDescriptor.getType(), value);
+                switch (fieldDescriptor.getType()) {
+                    case INT32:
+                        val = RubyNumeric.num2int(value);
+                        break;
+                    case INT64:
+                        val = RubyNumeric.num2long(value);
+                        break;
+                    case UINT32:
+                        val = Utils.num2uint(value);
+                        break;
+                    case UINT64:
+                        val = Utils.num2ulong(context.runtime, value);
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            case FLOAT:
+                if (!Utils.isRubyNum(value))
+                    throw runtime.newTypeError("Expected number type for float field.");
+                val = (float) RubyNumeric.num2dbl(value);
+                break;
+            case DOUBLE:
+                if (!Utils.isRubyNum(value))
+                    throw runtime.newTypeError("Expected number type for double field.");
+                val = RubyNumeric.num2dbl(value);
+                break;
+            case BOOL:
+                if (!(value instanceof RubyBoolean))
+                    throw runtime.newTypeError("Invalid argument for boolean field.");
+                val = value.isTrue();
+                break;
+            case BYTES:
+            case STRING:
+                Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value);
+                RubyString str = (RubyString) value;
+                switch (fieldDescriptor.getType()) {
+                    case BYTES:
+                        val = ByteString.copyFrom(str.getBytes());
+                        break;
+                    case STRING:
+                        val = str.asJavaString();
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            case MESSAGE:
+                RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+                if (!value.getMetaClass().equals(typeClass))
+                    throw runtime.newTypeError(value, "Invalid type to assign to submessage field.");
+                val = ((RubyMessage) value).build(context, depth + 1);
+                break;
+            case ENUM:
+                Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
+
+                if (Utils.isRubyNum(value)) {
+                    val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
+                } else if (value instanceof RubySymbol) {
+                    val = enumDescriptor.findValueByName(value.asJavaString());
+                } else {
+                    throw runtime.newTypeError("Expected number or symbol type for enum field.");
+                }
+                if (val == null) {
+                    throw runtime.newRangeError("Enum value " + value + " is not found.");
+                }
+                break;
+            default:
+                break;
+        }
+        return val;
+    }
+
+    private IRubyObject wrapField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, Object value) {
+        if (value == null) {
+            return context.runtime.getNil();
+        }
+        Ruby runtime = context.runtime;
+        switch (fieldDescriptor.getType()) {
+            case INT32:
+            case INT64:
+            case UINT32:
+            case UINT64:
+            case FLOAT:
+            case DOUBLE:
+            case BOOL:
+            case BYTES:
+            case STRING:
+                return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value);
+            case MESSAGE:
+                RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+                RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK);
+                return msg.buildFrom(context, (DynamicMessage) value);
+            case ENUM:
+                Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor) value;
+                if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE
+                    return runtime.newFixnum(enumValueDescriptor.getNumber());
+                }
+                return runtime.newSymbol(enumValueDescriptor.getName());
+            default:
+                return runtime.newString(value.toString());
+        }
+    }
+
+    private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context,
+                                                              Descriptors.FieldDescriptor fieldDescriptor) {
+        IRubyObject typeClass = context.runtime.getNilClass();
+
+        IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor);
+        Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType();
+        if (type == Descriptors.FieldDescriptor.Type.MESSAGE) {
+            typeClass = ((RubyDescriptor) descriptor).msgclass(context);
+
+        } else if (type == Descriptors.FieldDescriptor.Type.ENUM) {
+            typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context);
+        }
+        return new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass);
+    }
+
+    protected IRubyObject getField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+        Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
+        if (oneofDescriptor != null) {
+            if (oneofCases.containsKey(oneofDescriptor)) {
+                if (oneofCases.get(oneofDescriptor) != fieldDescriptor)
+                    return context.runtime.getNil();
+                return fields.get(fieldDescriptor);
+            } else {
+                Descriptors.FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor);
+                if (oneofCase != fieldDescriptor) return context.runtime.getNil();
+                IRubyObject value = wrapField(context, oneofCase, builder.getField(oneofCase));
+                fields.put(fieldDescriptor, value);
+                return value;
+            }
+        }
+
+        if (Utils.isMapEntry(fieldDescriptor)) {
+            RubyMap map = maps.get(fieldDescriptor);
+            if (map == null) {
+                map = newMapForField(context, fieldDescriptor);
+                int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor);
+                Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
+                Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
+                RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+                RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context);
+                for (int i = 0; i < mapSize; i++) {
+                    RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK);
+                    DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i);
+                    kvMessage.buildFrom(context, message);
+                    map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField));
+                }
+                maps.put(fieldDescriptor, map);
+            }
+            return map;
+        }
+        if (fieldDescriptor.isRepeated()) {
+            return getRepeatedField(context, fieldDescriptor);
+        }
+        if (fieldDescriptor.getType() != Descriptors.FieldDescriptor.Type.MESSAGE ||
+                this.builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) {
+            if (fields.containsKey(fieldDescriptor)) {
+                return fields.get(fieldDescriptor);
+            } else {
+                IRubyObject value = wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor));
+                if (this.builder.hasField(fieldDescriptor)) {
+                    fields.put(fieldDescriptor, value);
+                }
+                return value;
+            }
+        }
+        return context.runtime.getNil();
+    }
+
+    protected IRubyObject setField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
+        if (Utils.isMapEntry(fieldDescriptor)) {
+            if (!(value instanceof RubyMap)) {
+                throw context.runtime.newTypeError("Expected Map instance");
+            }
+            RubyMap thisMap = (RubyMap) getField(context, fieldDescriptor);
+            thisMap.mergeIntoSelf(context, value);
+        } else if (fieldDescriptor.isRepeated()) {
+            checkRepeatedFieldType(context, value, fieldDescriptor);
+            if (value instanceof RubyRepeatedField) {
+                addRepeatedField(fieldDescriptor, (RubyRepeatedField) value);
+            } else {
+                RubyArray ary = value.convertToArray();
+                RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, ary);
+                addRepeatedField(fieldDescriptor, repeatedField);
+            }
+        } else {
+            Descriptors.OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof();
+            if (oneofDescriptor != null) {
+                Descriptors.FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor);
+                if (oneofCase != null && oneofCase != fieldDescriptor) {
+                    fields.remove(oneofCase);
+                }
+                if (value.isNil()) {
+                    oneofCases.remove(oneofDescriptor);
+                    fields.remove(fieldDescriptor);
+                } else {
+                    oneofCases.put(oneofDescriptor, fieldDescriptor);
+                    fields.put(fieldDescriptor, value);
+                }
+            } else {
+                Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType();
+                IRubyObject typeClass = context.runtime.getObject();
+                boolean addValue = true;
+                if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
+                    typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context);
+                    if (value.isNil()){
+                        addValue = false;
+                    }
+                } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
+                    typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context);
+                    Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType();
+                    if (Utils.isRubyNum(value)) {
+                        Descriptors.EnumValueDescriptor val =
+                                enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value));
+                        if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName());
+                    }
+                }
+                if (addValue) {
+                    Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+                    this.fields.put(fieldDescriptor, value);
+                } else {
+                    this.fields.remove(fieldDescriptor);
+                }
+            }
+        }
+        return context.runtime.getNil();
+    }
+
+    private String layoutInspect() {
+        ThreadContext context = getRuntime().getCurrentContext();
+        StringBuilder sb = new StringBuilder();
+        for (Descriptors.FieldDescriptor fdef : descriptor.getFields()) {
+            sb.append(Utils.unescapeIdentifier(fdef.getName()));
+            sb.append(": ");
+            sb.append(getField(context, fdef).inspect());
+            sb.append(", ");
+        }
+        return sb.substring(0, sb.length() - 2);
+    }
+
+    private IRubyObject getDescriptorForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+        RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
+        return thisRbDescriptor.lookup(fieldDescriptor.getName()).getSubType(context);
+    }
+
+    private RubyRepeatedField rubyToRepeatedField(ThreadContext context,
+                                                  Descriptors.FieldDescriptor fieldDescriptor, IRubyObject value) {
+        RubyArray arr = value.convertToArray();
+        RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor);
+        for (int i = 0; i < arr.size(); i++) {
+            repeatedField.push(context, arr.eltInternal(i));
+        }
+        return repeatedField;
+    }
+
+    private RubyMap newMapForField(ThreadContext context, Descriptors.FieldDescriptor fieldDescriptor) {
+        RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor);
+        Descriptors.FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1);
+        Descriptors.FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2);
+        IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name());
+        IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name());
+        if (valueField.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
+            RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context,
+                    context.runtime.newString("value"));
+            RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubType(context);
+            return (RubyMap) cMap.newInstance(context, keyType, valueType,
+                    rubyDescriptor.msgclass(context), Block.NULL_BLOCK);
+        } else {
+            return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK);
+        }
+    }
+
+    private Descriptors.FieldDescriptor getOneofCase(Descriptors.OneofDescriptor oneof) {
+        if (oneofCases.containsKey(oneof)) {
+            return oneofCases.get(oneof);
+        }
+        return builder.getOneofFieldDescriptor(oneof);
+    }
+
+    private Descriptors.Descriptor descriptor;
+    private DynamicMessage.Builder builder;
+    private RubyClass cRepeatedField;
+    private RubyClass cMap;
+    private Map<Descriptors.FieldDescriptor, RubyRepeatedField> repeatedFields;
+    private Map<Descriptors.FieldDescriptor, RubyMap> maps;
+    private Map<Descriptors.FieldDescriptor, IRubyObject> fields;
+    private Map<Descriptors.OneofDescriptor, Descriptors.FieldDescriptor> oneofCases;
+
+    private static final int SINK_MAXIMUM_NESTING = 64;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java
new file mode 100644
index 0000000..a619b80
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java
@@ -0,0 +1,217 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Binding;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "MessageBuilderContext")
+public class RubyMessageBuilderContext extends RubyObject {
+    public static void createRubyMessageBuilderContext(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cMessageBuilderContext = protobuf.defineClassUnder("MessageBuilderContext", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                return new RubyMessageBuilderContext(runtime, klazz);
+            }
+        });
+        cMessageBuilderContext.defineAnnotatedMethods(RubyMessageBuilderContext.class);
+    }
+
+    public RubyMessageBuilderContext(Ruby ruby, RubyClass klazz) {
+        super(ruby, klazz);
+    }
+
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context, IRubyObject descriptor, IRubyObject rubyBuilder) {
+        this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
+        this.cDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Descriptor");
+        this.cOneofDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::OneofDescriptor");
+        this.cOneofBuilderContext = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::OneofBuilderContext");
+        this.descriptor = (RubyDescriptor) descriptor;
+        this.builder = (RubyBuilder) rubyBuilder;
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     MessageBuilderContext.optional(name, type, number, type_class = nil)
+     *
+     * Defines a new optional field on this message type with the given type, tag
+     * number, and type class (for message and enum fields). The type must be a Ruby
+     * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+     * string, if present (as accepted by FieldDescriptor#submsg_name=).
+     */
+    @JRubyMethod(required = 3, optional = 1)
+    public IRubyObject optional(ThreadContext context, IRubyObject[] args) {
+        Ruby runtime = context.runtime;
+        IRubyObject typeClass = runtime.getNil();
+        if (args.length > 3) typeClass = args[3];
+        msgdefAddField(context, "optional", args[0], args[1], args[2], typeClass);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     MessageBuilderContext.required(name, type, number, type_class = nil)
+     *
+     * Defines a new required field on this message type with the given type, tag
+     * number, and type class (for message and enum fields). The type must be a Ruby
+     * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+     * string, if present (as accepted by FieldDescriptor#submsg_name=).
+     *
+     * Proto3 does not have required fields, but this method exists for
+     * completeness. Any attempt to add a message type with required fields to a
+     * pool will currently result in an error.
+     */
+    @JRubyMethod(required = 3, optional = 1)
+    public IRubyObject required(ThreadContext context, IRubyObject[] args) {
+        IRubyObject typeClass = context.runtime.getNil();
+        if (args.length > 3) typeClass = args[3];
+        msgdefAddField(context, "required", args[0], args[1], args[2], typeClass);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     MessageBuilderContext.repeated(name, type, number, type_class = nil)
+     *
+     * Defines a new repeated field on this message type with the given type, tag
+     * number, and type class (for message and enum fields). The type must be a Ruby
+     * symbol (as accepted by FieldDescriptor#type=) and the type_class must be a
+     * string, if present (as accepted by FieldDescriptor#submsg_name=).
+     */
+    @JRubyMethod(required = 3, optional = 1)
+    public IRubyObject repeated(ThreadContext context, IRubyObject[] args) {
+        IRubyObject typeClass = context.runtime.getNil();
+        if (args.length > 3) typeClass = args[3];
+        msgdefAddField(context, "repeated", args[0], args[1], args[2], typeClass);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     MessageBuilderContext.map(name, key_type, value_type, number,
+     *                               value_type_class = nil)
+     *
+     * Defines a new map field on this message type with the given key and value
+     * types, tag number, and type class (for message and enum value types). The key
+     * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
+     * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
+     * type_class must be a string, if present (as accepted by
+     * FieldDescriptor#submsg_name=).
+     */
+    @JRubyMethod(required = 4, optional = 1)
+    public IRubyObject map(ThreadContext context, IRubyObject[] args) {
+        Ruby runtime = context.runtime;
+        IRubyObject name = args[0];
+        IRubyObject keyType = args[1];
+        IRubyObject valueType = args[2];
+        IRubyObject number = args[3];
+        IRubyObject typeClass = args.length > 4 ? args[4] : context.runtime.getNil();
+
+        // Validate the key type. We can't accept enums, messages, or floats/doubles
+        // as map keys. (We exclude these explicitly, and the field-descriptor setter
+        // below then ensures that the type is one of the remaining valid options.)
+        if (keyType.equals(RubySymbol.newSymbol(runtime, "float")) ||
+                keyType.equals(RubySymbol.newSymbol(runtime, "double")) ||
+                keyType.equals(RubySymbol.newSymbol(runtime, "enum")) ||
+                keyType.equals(RubySymbol.newSymbol(runtime, "message")))
+            throw runtime.newArgumentError("Cannot add a map field with a float, double, enum, or message type.");
+
+        // Create a new message descriptor for the map entry message, and create a
+        // repeated submessage field here with that type.
+        RubyDescriptor mapentryDesc = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK);
+        IRubyObject mapentryDescName = RubySymbol.newSymbol(runtime, name).id2name(context);
+        mapentryDesc.setName(context, mapentryDescName);
+        mapentryDesc.setMapEntry(true);
+
+        //optional <type> key = 1;
+        RubyFieldDescriptor keyField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+        keyField.setName(context, runtime.newString("key"));
+        keyField.setLabel(context, RubySymbol.newSymbol(runtime, "optional"));
+        keyField.setNumber(context, runtime.newFixnum(1));
+        keyField.setType(context, keyType);
+        mapentryDesc.addField(context, keyField);
+
+        //optional <type> value = 2;
+        RubyFieldDescriptor valueField = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+        valueField.setName(context, runtime.newString("value"));
+        valueField.setLabel(context, RubySymbol.newSymbol(runtime, "optional"));
+        valueField.setNumber(context, runtime.newFixnum(2));
+        valueField.setType(context, valueType);
+        if (! typeClass.isNil()) valueField.setSubmsgName(context, typeClass);
+        mapentryDesc.addField(context, valueField);
+
+        // Add the map-entry message type to the current builder, and use the type to
+        // create the map field itself.
+        this.builder.pendingList.add(mapentryDesc);
+
+        msgdefAddField(context, "repeated", name, runtime.newSymbol("message"), number, mapentryDescName);
+        return runtime.getNil();
+    }
+
+    @JRubyMethod
+    public IRubyObject oneof(ThreadContext context, IRubyObject name, Block block) {
+        RubyOneofDescriptor oneofdef = (RubyOneofDescriptor)
+                cOneofDescriptor.newInstance(context, Block.NULL_BLOCK);
+        RubyOneofBuilderContext ctx = (RubyOneofBuilderContext)
+                cOneofBuilderContext.newInstance(context, oneofdef, Block.NULL_BLOCK);
+        oneofdef.setName(context, name);
+        Binding binding = block.getBinding();
+        binding.setSelf(ctx);
+        block.yieldSpecific(context);
+        descriptor.addOneof(context, oneofdef);
+        return context.runtime.getNil();
+    }
+
+    private void msgdefAddField(ThreadContext context, String label, IRubyObject name,
+                                IRubyObject type, IRubyObject number, IRubyObject typeClass) {
+        descriptor.addField(context,
+                Utils.msgdefCreateField(context, label, name, type, number, typeClass, cFieldDescriptor));
+    }
+
+    private RubyDescriptor descriptor;
+    private RubyBuilder builder;
+    private RubyClass cFieldDescriptor;
+    private RubyClass cOneofDescriptor;
+    private RubyClass cOneofBuilderContext;
+    private RubyClass cDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java
new file mode 100644
index 0000000..c9b99e0
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java
@@ -0,0 +1,84 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyClass(name = "OneofBuilderContext")
+public class RubyOneofBuilderContext extends RubyObject {
+    public static void createRubyOneofBuilderContext(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyModule internal = protobuf.defineModuleUnder("Internal");
+        RubyClass cRubyOneofBuidlerContext = internal.defineClassUnder("OneofBuilderContext", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+                return new RubyOneofBuilderContext(ruby, rubyClass);
+            }
+        });
+        cRubyOneofBuidlerContext.defineAnnotatedMethods(RubyOneofBuilderContext.class);
+    }
+
+    public RubyOneofBuilderContext(Ruby ruby, RubyClass rubyClass) {
+        super(ruby, rubyClass);
+    }
+
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context, IRubyObject oneofdef) {
+        this.descriptor = (RubyOneofDescriptor) oneofdef;
+        this.cFieldDescriptor = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::FieldDescriptor");
+        return this;
+    }
+
+    @JRubyMethod(required = 3, optional = 1)
+    public IRubyObject optional(ThreadContext context, IRubyObject[] args) {
+        IRubyObject name = args[0];
+        IRubyObject type = args[1];
+        IRubyObject number = args[2];
+        IRubyObject typeClass = args.length > 3 ? args[3] : context.runtime.getNil();
+        RubyFieldDescriptor fieldDescriptor = Utils.msgdefCreateField(context, "optional",
+                name, type, number, typeClass, cFieldDescriptor);
+        descriptor.addField(context, fieldDescriptor);
+        return this;
+    }
+
+    private RubyOneofDescriptor descriptor;
+    private RubyClass cFieldDescriptor;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
new file mode 100644
index 0000000..cc4ab66
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java
@@ -0,0 +1,124 @@
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.util.*;
+
+@JRubyClass(name = "OneofDescriptor", include = "Enumerable")
+public class RubyOneofDescriptor extends RubyObject {
+
+    public static void createRubyOneofDescriptor(Ruby runtime) {
+        RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() {
+            @Override
+            public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) {
+                return new RubyOneofDescriptor(ruby, rubyClass);
+            }
+        });
+        cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class);
+        cRubyOneofDescriptor.includeModule(runtime.getEnumerable());
+    }
+
+    public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) {
+        super(ruby, rubyClass);
+    }
+
+    @JRubyMethod
+    public IRubyObject initialize(ThreadContext context) {
+        builder = DescriptorProtos.OneofDescriptorProto.newBuilder();
+        fields = new ArrayList<RubyFieldDescriptor>();
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     OneofDescriptor.name => name
+     *
+     * Returns the name of this oneof.
+     */
+    @JRubyMethod(name = "name")
+    public IRubyObject getName(ThreadContext context) {
+        return name;
+    }
+
+    /*
+     * call-seq:
+     *     OneofDescriptor.name = name
+     *
+     * Sets a new name for this oneof. The oneof must not have been added to a
+     * message descriptor yet.
+     */
+    @JRubyMethod(name = "name=")
+    public IRubyObject setName(ThreadContext context, IRubyObject name) {
+        this.name = context.runtime.newString(name.asJavaString());
+        this.builder.setName(name.asJavaString());
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     OneofDescriptor.add_field(field) => nil
+     *
+     * Adds a field to this oneof. The field may have been added to this oneof in
+     * the past, or the message to which this oneof belongs (if any), but may not
+     * have already been added to any other oneof or message. Otherwise, an
+     * exception is raised.
+     *
+     * All fields added to the oneof via this method will be automatically added to
+     * the message to which this oneof belongs, if it belongs to one currently, or
+     * else will be added to any message to which the oneof is later added at the
+     * time that it is added.
+     */
+    @JRubyMethod(name = "add_field")
+    public IRubyObject addField(ThreadContext context, IRubyObject obj) {
+        RubyFieldDescriptor fieldDescriptor = (RubyFieldDescriptor) obj;
+        fieldDescriptor.setOneofName(this.name);
+        fields.add(fieldDescriptor);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     OneofDescriptor.each(&block) => nil
+     *
+     * Iterates through fields in this oneof, yielding to the block on each one.
+     */
+    @JRubyMethod
+    public IRubyObject each(ThreadContext context, Block block) {
+        for (RubyFieldDescriptor field : fields) {
+            block.yieldSpecific(context, field);
+        }
+        return context.runtime.getNil();
+    }
+
+    public DescriptorProtos.OneofDescriptorProto build(int index) {
+        for (RubyFieldDescriptor field: fields) {
+            field.setOneofIndex(index);
+        }
+        return this.builder.build();
+    }
+
+    protected Collection<RubyFieldDescriptor> getFields() {
+        return fields;
+    }
+
+    protected Descriptors.OneofDescriptor getOneofDescriptor() {
+        RubyFieldDescriptor fieldDescriptor = fields.get(0);
+        return fieldDescriptor.getFieldDef().getContainingOneof();
+    }
+
+    private IRubyObject name;
+    private DescriptorProtos.OneofDescriptorProto.Builder builder;
+    private List<RubyFieldDescriptor> fields;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
new file mode 100644
index 0000000..2cf210d
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java
@@ -0,0 +1,68 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import org.jruby.Ruby;
+import org.jruby.RubyModule;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.anno.JRubyModule;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+@JRubyModule(name = "Protobuf")
+public class RubyProtobuf {
+
+    public static void createProtobuf(Ruby runtime) {
+        RubyModule mGoogle = runtime.getModule("Google");
+        RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf");
+        mProtobuf.defineAnnotatedMethods(RubyProtobuf.class);
+    }
+
+    /*
+     * call-seq:
+     *     Google::Protobuf.deep_copy(obj) => copy_of_obj
+     *
+     * Performs a deep copy of either a RepeatedField instance or a message object,
+     * recursively copying its members.
+     */
+    @JRubyMethod(name = "deep_copy", meta = true)
+    public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) {
+        if (message instanceof RubyMessage) {
+            return ((RubyMessage) message).deepCopy(context);
+        } else if (message instanceof RubyRepeatedField) {
+            return ((RubyRepeatedField) message).deepCopy(context);
+        } else {
+            return ((RubyMap) message).deepCopy(context);
+        }
+    }
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
new file mode 100644
index 0000000..946f9e7
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
@@ -0,0 +1,409 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.Descriptors;
+import org.jruby.*;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import java.util.Arrays;
+
+@JRubyClass(name = "RepeatedClass", include = "Enumerable")
+public class RubyRepeatedField extends RubyObject {
+    public static void createRubyRepeatedField(Ruby runtime) {
+        RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf");
+        RubyClass cRepeatedField = mProtobuf.defineClassUnder("RepeatedField", runtime.getObject(),
+                new ObjectAllocator() {
+                    @Override
+                    public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+                        return new RubyRepeatedField(runtime, klazz);
+                    }
+                });
+        cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class);
+        cRepeatedField.includeModule(runtime.getEnumerable());
+    }
+
+    public RubyRepeatedField(Ruby runtime, RubyClass klazz) {
+        super(runtime, klazz);
+    }
+
+    public RubyRepeatedField(Ruby runtime, RubyClass klazz, Descriptors.FieldDescriptor.Type fieldType, IRubyObject typeClass) {
+        this(runtime, klazz);
+        this.fieldType = fieldType;
+        this.storage = runtime.newArray();
+        this.typeClass = typeClass;
+    }
+
+    @JRubyMethod(required = 1, optional = 2)
+    public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+        Ruby runtime = context.runtime;
+        this.storage = runtime.newArray();
+        IRubyObject ary = null;
+        if (!(args[0] instanceof RubySymbol)) {
+            throw runtime.newArgumentError("Expected Symbol for type name");
+        }
+        this.fieldType = Utils.rubyToFieldType(args[0]);
+        if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE
+                || fieldType == Descriptors.FieldDescriptor.Type.ENUM) {
+            if (args.length < 2)
+                throw runtime.newArgumentError("Expected at least 2 arguments for message/enum");
+            typeClass = args[1];
+            if (args.length > 2)
+                ary = args[2];
+            Utils.validateTypeClass(context, fieldType, typeClass);
+        } else {
+            if (args.length > 2)
+                throw runtime.newArgumentError("Too many arguments: expected 1 or 2");
+            if (args.length > 1)
+                ary = args[1];
+        }
+        if (ary != null) {
+            RubyArray arr = ary.convertToArray();
+            for (int i = 0; i < arr.size(); i++) {
+                this.storage.add(arr.eltInternal(i));
+            }
+        }
+        return this;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.[]=(index, value)
+     *
+     * Sets the element at the given index. On out-of-bounds assignments, extends
+     * the array and fills the hole (if any) with default values.
+     */
+    @JRubyMethod(name = "[]=")
+    public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
+        int arrIndex = normalizeArrayIndex(index);
+        Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+        IRubyObject defaultValue = defaultValue(context);
+        for (int i = this.storage.size(); i < arrIndex; i++) {
+            this.storage.set(i, defaultValue);
+        }
+        this.storage.set(arrIndex, value);
+        return context.runtime.getNil();
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.[](index) => value
+     *
+     * Accesses the element at the given index. Returns nil on out-of-bounds
+     */
+    @JRubyMethod(required=1, optional=1, name = {"at", "[]"})
+    public IRubyObject index(ThreadContext context, IRubyObject[] args) {
+        if (args.length == 1){
+            IRubyObject arg = args[0];
+            if (Utils.isRubyNum(arg)) {
+                /* standard case */
+                int arrIndex = normalizeArrayIndex(arg);
+                if (arrIndex < 0 || arrIndex >= this.storage.size()) {
+                    return context.runtime.getNil();
+                }
+                return this.storage.eltInternal(arrIndex);
+            } else if (arg instanceof RubyRange) {
+                RubyRange range = ((RubyRange) arg);
+                int beg = RubyNumeric.num2int(range.first(context));
+                int to = RubyNumeric.num2int(range.last(context));
+                int len = to - beg + 1;
+                return this.storage.subseq(beg, len);
+            }
+        }
+        /* assume 2 arguments */
+        int beg = RubyNumeric.num2int(args[0]);
+        int len = RubyNumeric.num2int(args[1]);
+        if (beg < 0) {
+            beg += this.storage.size();
+        }
+        if (beg >= this.storage.size()) {
+            return context.runtime.getNil();
+        }
+        return this.storage.subseq(beg, len);
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.push(value)
+     *
+     * Adds a new element to the repeated field.
+     */
+    @JRubyMethod(name = {"push", "<<"})
+    public IRubyObject push(ThreadContext context, IRubyObject value) {
+        if (!(fieldType == Descriptors.FieldDescriptor.Type.MESSAGE &&
+            value == context.runtime.getNil())) {
+            Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+        }
+        this.storage.add(value);
+        return this.storage;
+    }
+
+    /*
+     * private Ruby method used by RepeatedField.pop
+     */
+    @JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE)
+    public IRubyObject pop_one(ThreadContext context) {
+        IRubyObject ret = this.storage.last();
+        this.storage.remove(ret);
+        return ret;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.replace(list)
+     *
+     * Replaces the contents of the repeated field with the given list of elements.
+     */
+    @JRubyMethod
+    public IRubyObject replace(ThreadContext context, IRubyObject list) {
+        RubyArray arr = (RubyArray) list;
+        checkArrayElementType(context, arr);
+        this.storage = arr;
+        return this.storage;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.clear
+     *
+     * Clears (removes all elements from) this repeated field.
+     */
+    @JRubyMethod
+    public IRubyObject clear(ThreadContext context) {
+        this.storage.clear();
+        return this.storage;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.length
+     *
+     * Returns the length of this repeated field.
+     */
+    @JRubyMethod(name = {"length", "size"})
+    public IRubyObject length(ThreadContext context) {
+        return context.runtime.newFixnum(this.storage.size());
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.+(other) => repeated field
+     *
+     * Returns a new repeated field that contains the concatenated list of this
+     * repeated field's elements and other's elements. The other (second) list may
+     * be either another repeated field or a Ruby array.
+     */
+    @JRubyMethod(name = {"+"})
+    public IRubyObject plus(ThreadContext context, IRubyObject list) {
+        RubyRepeatedField dup = (RubyRepeatedField) dup(context);
+        if (list instanceof RubyArray) {
+            checkArrayElementType(context, (RubyArray) list);
+            dup.storage.addAll((RubyArray) list);
+        } else {
+            RubyRepeatedField repeatedField = (RubyRepeatedField) list;
+            if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
+                    typeClass.equals(repeatedField.typeClass)))
+                throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
+            dup.storage.addAll((RubyArray) repeatedField.toArray(context));
+        }
+        return dup;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.concat(other) => self
+     *
+     * concats the passed in array to self.  Returns a Ruby array.
+     */
+    @JRubyMethod
+    public IRubyObject concat(ThreadContext context, IRubyObject list) {
+        if (list instanceof RubyArray) {
+            checkArrayElementType(context, (RubyArray) list);
+            this.storage.addAll((RubyArray) list);
+        } else {
+            RubyRepeatedField repeatedField = (RubyRepeatedField) list;
+            if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && !
+                    typeClass.equals(repeatedField.typeClass)))
+                throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type.");
+            this.storage.addAll((RubyArray) repeatedField.toArray(context));
+        }
+        return this.storage;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.hash => hash_value
+     *
+     * Returns a hash value computed from this repeated field's elements.
+     */
+    @JRubyMethod
+    public IRubyObject hash(ThreadContext context) {
+        int hashCode = this.storage.hashCode();
+        return context.runtime.newFixnum(hashCode);
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.==(other) => boolean
+     *
+     * Compares this repeated field to another. Repeated fields are equal if their
+     * element types are equal, their lengths are equal, and each element is equal.
+     * Elements are compared as per normal Ruby semantics, by calling their :==
+     * methods (or performing a more efficient comparison for primitive types).
+     */
+    @JRubyMethod(name = "==")
+    public IRubyObject eq(ThreadContext context, IRubyObject other) {
+        return this.toArray(context).op_equal(context, other);
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.each(&block)
+     *
+     * Invokes the block once for each element of the repeated field. RepeatedField
+     * also includes Enumerable; combined with this method, the repeated field thus
+     * acts like an ordinary Ruby sequence.
+     */
+    @JRubyMethod
+    public IRubyObject each(ThreadContext context, Block block) {
+        this.storage.each(context, block);
+        return this.storage;
+    }
+
+
+    @JRubyMethod(name = {"to_ary", "to_a"})
+    public IRubyObject toArray(ThreadContext context) {
+        return this.storage;
+    }
+
+    /*
+     * call-seq:
+     *     RepeatedField.dup => repeated_field
+     *
+     * Duplicates this repeated field with a shallow copy. References to all
+     * non-primitive element objects (e.g., submessages) are shared.
+     */
+    @JRubyMethod
+    public IRubyObject dup(ThreadContext context) {
+        RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
+        for (int i = 0; i < this.storage.size(); i++) {
+            dup.push(context, this.storage.eltInternal(i));
+        }
+        return dup;
+    }
+
+    // Java API
+    protected IRubyObject get(int index) {
+        return this.storage.eltInternal(index);
+    }
+
+    protected RubyRepeatedField deepCopy(ThreadContext context) {
+        RubyRepeatedField copy = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass);
+        for (int i = 0; i < size(); i++) {
+            IRubyObject value = storage.eltInternal(i);
+            if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) {
+                copy.storage.add(((RubyMessage) value).deepCopy(context));
+            } else {
+                copy.storage.add(value);
+            }
+        }
+        return copy;
+    }
+
+    protected int size() {
+        return this.storage.size();
+    }
+
+    private IRubyObject defaultValue(ThreadContext context) {
+        SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance();
+        Object value;
+        switch (fieldType) {
+            case INT32:
+                value = sentinel.getDefaultInt32();
+                break;
+            case INT64:
+                value = sentinel.getDefaultInt64();
+                break;
+            case UINT32:
+                value = sentinel.getDefaultUnit32();
+                break;
+            case UINT64:
+                value = sentinel.getDefaultUint64();
+                break;
+            case FLOAT:
+                value = sentinel.getDefaultFloat();
+                break;
+            case DOUBLE:
+                value = sentinel.getDefaultDouble();
+                break;
+            case BOOL:
+                value = sentinel.getDefaultBool();
+                break;
+            case BYTES:
+                value = sentinel.getDefaultBytes();
+                break;
+            case STRING:
+                value = sentinel.getDefaultString();
+                break;
+            case ENUM:
+                IRubyObject defaultEnumLoc = context.runtime.newFixnum(0);
+                return RubyEnum.lookup(context, typeClass, defaultEnumLoc);
+            default:
+                return context.runtime.getNil();
+        }
+        return Utils.wrapPrimaryValue(context, fieldType, value);
+    }
+
+    private void checkArrayElementType(ThreadContext context, RubyArray arr) {
+        for (int i = 0; i < arr.getLength(); i++) {
+            Utils.checkType(context, fieldType, arr.eltInternal(i), (RubyModule) typeClass);
+        }
+    }
+
+    private int normalizeArrayIndex(IRubyObject index) {
+        int arrIndex = RubyNumeric.num2int(index);
+        int arrSize = this.storage.size();
+        if (arrIndex < 0 && arrSize > 0) {
+            arrIndex = arrSize + arrIndex;
+        }
+        return arrIndex;
+    }
+
+    private RubyArray storage;
+    private Descriptors.FieldDescriptor.Type fieldType;
+    private IRubyObject typeClass;
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
new file mode 100644
index 0000000..54f2c72
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java
@@ -0,0 +1,776 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: sentinel.proto
+
+package com.google.protobuf.jruby;
+
+public final class SentinelOuterClass {
+  private SentinelOuterClass() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+  }
+  public interface SentinelOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:com.google.protobuf.jruby.Sentinel)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional int32 default_int32 = 1;</code>
+     */
+    int getDefaultInt32();
+
+    /**
+     * <code>optional int64 default_int64 = 2;</code>
+     */
+    long getDefaultInt64();
+
+    /**
+     * <code>optional uint32 default_unit32 = 3;</code>
+     */
+    int getDefaultUnit32();
+
+    /**
+     * <code>optional uint64 default_uint64 = 4;</code>
+     */
+    long getDefaultUint64();
+
+    /**
+     * <code>optional string default_string = 5;</code>
+     */
+    java.lang.String getDefaultString();
+    /**
+     * <code>optional string default_string = 5;</code>
+     */
+    com.google.protobuf.ByteString
+        getDefaultStringBytes();
+
+    /**
+     * <code>optional bool default_bool = 6;</code>
+     */
+    boolean getDefaultBool();
+
+    /**
+     * <code>optional float default_float = 7;</code>
+     */
+    float getDefaultFloat();
+
+    /**
+     * <code>optional double default_double = 8;</code>
+     */
+    double getDefaultDouble();
+
+    /**
+     * <code>optional bytes default_bytes = 9;</code>
+     */
+    com.google.protobuf.ByteString getDefaultBytes();
+  }
+  /**
+   * Protobuf type {@code com.google.protobuf.jruby.Sentinel}
+   */
+  public  static final class Sentinel extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:com.google.protobuf.jruby.Sentinel)
+      SentinelOrBuilder {
+    // Use Sentinel.newBuilder() to construct.
+    private Sentinel(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private Sentinel() {
+      defaultInt32_ = 0;
+      defaultInt64_ = 0L;
+      defaultUnit32_ = 0;
+      defaultUint64_ = 0L;
+      defaultString_ = "";
+      defaultBool_ = false;
+      defaultFloat_ = 0F;
+      defaultDouble_ = 0D;
+      defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
+    }
+
+    public static final com.google.protobuf.Parser<Sentinel> PARSER =
+        new com.google.protobuf.AbstractParser<Sentinel>() {
+      public Sentinel parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        Builder builder = newBuilder();
+        try {
+          builder.mergeFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          throw e.setUnfinishedMessage(builder.buildPartial());
+        } catch (java.io.IOException e) {
+          throw new com.google.protobuf.InvalidProtocolBufferException(
+              e.getMessage()).setUnfinishedMessage(builder.buildPartial());
+        }
+        return builder.buildPartial();
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Sentinel> getParserForType() {
+      return PARSER;
+    }
+
+    public static final int DEFAULT_INT32_FIELD_NUMBER = 1;
+    private int defaultInt32_;
+    /**
+     * <code>optional int32 default_int32 = 1;</code>
+     */
+    public int getDefaultInt32() {
+      return defaultInt32_;
+    }
+
+    public static final int DEFAULT_INT64_FIELD_NUMBER = 2;
+    private long defaultInt64_;
+    /**
+     * <code>optional int64 default_int64 = 2;</code>
+     */
+    public long getDefaultInt64() {
+      return defaultInt64_;
+    }
+
+    public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3;
+    private int defaultUnit32_;
+    /**
+     * <code>optional uint32 default_unit32 = 3;</code>
+     */
+    public int getDefaultUnit32() {
+      return defaultUnit32_;
+    }
+
+    public static final int DEFAULT_UINT64_FIELD_NUMBER = 4;
+    private long defaultUint64_;
+    /**
+     * <code>optional uint64 default_uint64 = 4;</code>
+     */
+    public long getDefaultUint64() {
+      return defaultUint64_;
+    }
+
+    public static final int DEFAULT_STRING_FIELD_NUMBER = 5;
+    private java.lang.Object defaultString_;
+    /**
+     * <code>optional string default_string = 5;</code>
+     */
+    public java.lang.String getDefaultString() {
+      java.lang.Object ref = defaultString_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          defaultString_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string default_string = 5;</code>
+     */
+    public com.google.protobuf.ByteString
+        getDefaultStringBytes() {
+      java.lang.Object ref = defaultString_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        defaultString_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int DEFAULT_BOOL_FIELD_NUMBER = 6;
+    private boolean defaultBool_;
+    /**
+     * <code>optional bool default_bool = 6;</code>
+     */
+    public boolean getDefaultBool() {
+      return defaultBool_;
+    }
+
+    public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7;
+    private float defaultFloat_;
+    /**
+     * <code>optional float default_float = 7;</code>
+     */
+    public float getDefaultFloat() {
+      return defaultFloat_;
+    }
+
+    public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8;
+    private double defaultDouble_;
+    /**
+     * <code>optional double default_double = 8;</code>
+     */
+    public double getDefaultDouble() {
+      return defaultDouble_;
+    }
+
+    public static final int DEFAULT_BYTES_FIELD_NUMBER = 9;
+    private com.google.protobuf.ByteString defaultBytes_;
+    /**
+     * <code>optional bytes default_bytes = 9;</code>
+     */
+    public com.google.protobuf.ByteString getDefaultBytes() {
+      return defaultBytes_;
+    }
+
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return new Builder(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code com.google.protobuf.jruby.Sentinel}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:com.google.protobuf.jruby.Sentinel)
+        com.google.protobuf.jruby.SentinelOuterClass.SentinelOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class);
+      }
+
+      // Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        defaultInt32_ = 0;
+
+        defaultInt64_ = 0L;
+
+        defaultUnit32_ = 0;
+
+        defaultUint64_ = 0L;
+
+        defaultString_ = "";
+
+        defaultBool_ = false;
+
+        defaultFloat_ = 0F;
+
+        defaultDouble_ = 0D;
+
+        defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+      }
+
+      public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
+        return com.google.protobuf.jruby.SentinelOuterClass.Sentinel.getDefaultInstance();
+      }
+
+      public com.google.protobuf.jruby.SentinelOuterClass.Sentinel build() {
+        com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() {
+        com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this);
+        result.defaultInt32_ = defaultInt32_;
+        result.defaultInt64_ = defaultInt64_;
+        result.defaultUnit32_ = defaultUnit32_;
+        result.defaultUint64_ = defaultUint64_;
+        result.defaultString_ = defaultString_;
+        result.defaultBool_ = defaultBool_;
+        result.defaultFloat_ = defaultFloat_;
+        result.defaultDouble_ = defaultDouble_;
+        result.defaultBytes_ = defaultBytes_;
+        onBuilt();
+        return result;
+      }
+
+
+      private int defaultInt32_ ;
+      /**
+       * <code>optional int32 default_int32 = 1;</code>
+       */
+      public int getDefaultInt32() {
+        return defaultInt32_;
+      }
+      /**
+       * <code>optional int32 default_int32 = 1;</code>
+       */
+      public Builder setDefaultInt32(int value) {
+        
+        defaultInt32_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int32 default_int32 = 1;</code>
+       */
+      public Builder clearDefaultInt32() {
+        
+        defaultInt32_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private long defaultInt64_ ;
+      /**
+       * <code>optional int64 default_int64 = 2;</code>
+       */
+      public long getDefaultInt64() {
+        return defaultInt64_;
+      }
+      /**
+       * <code>optional int64 default_int64 = 2;</code>
+       */
+      public Builder setDefaultInt64(long value) {
+        
+        defaultInt64_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int64 default_int64 = 2;</code>
+       */
+      public Builder clearDefaultInt64() {
+        
+        defaultInt64_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      private int defaultUnit32_ ;
+      /**
+       * <code>optional uint32 default_unit32 = 3;</code>
+       */
+      public int getDefaultUnit32() {
+        return defaultUnit32_;
+      }
+      /**
+       * <code>optional uint32 default_unit32 = 3;</code>
+       */
+      public Builder setDefaultUnit32(int value) {
+        
+        defaultUnit32_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional uint32 default_unit32 = 3;</code>
+       */
+      public Builder clearDefaultUnit32() {
+        
+        defaultUnit32_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private long defaultUint64_ ;
+      /**
+       * <code>optional uint64 default_uint64 = 4;</code>
+       */
+      public long getDefaultUint64() {
+        return defaultUint64_;
+      }
+      /**
+       * <code>optional uint64 default_uint64 = 4;</code>
+       */
+      public Builder setDefaultUint64(long value) {
+        
+        defaultUint64_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional uint64 default_uint64 = 4;</code>
+       */
+      public Builder clearDefaultUint64() {
+        
+        defaultUint64_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object defaultString_ = "";
+      /**
+       * <code>optional string default_string = 5;</code>
+       */
+      public java.lang.String getDefaultString() {
+        java.lang.Object ref = defaultString_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            defaultString_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string default_string = 5;</code>
+       */
+      public com.google.protobuf.ByteString
+          getDefaultStringBytes() {
+        java.lang.Object ref = defaultString_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          defaultString_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string default_string = 5;</code>
+       */
+      public Builder setDefaultString(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        defaultString_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string default_string = 5;</code>
+       */
+      public Builder clearDefaultString() {
+        
+        defaultString_ = getDefaultInstance().getDefaultString();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string default_string = 5;</code>
+       */
+      public Builder setDefaultStringBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        defaultString_ = value;
+        onChanged();
+        return this;
+      }
+
+      private boolean defaultBool_ ;
+      /**
+       * <code>optional bool default_bool = 6;</code>
+       */
+      public boolean getDefaultBool() {
+        return defaultBool_;
+      }
+      /**
+       * <code>optional bool default_bool = 6;</code>
+       */
+      public Builder setDefaultBool(boolean value) {
+        
+        defaultBool_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool default_bool = 6;</code>
+       */
+      public Builder clearDefaultBool() {
+        
+        defaultBool_ = false;
+        onChanged();
+        return this;
+      }
+
+      private float defaultFloat_ ;
+      /**
+       * <code>optional float default_float = 7;</code>
+       */
+      public float getDefaultFloat() {
+        return defaultFloat_;
+      }
+      /**
+       * <code>optional float default_float = 7;</code>
+       */
+      public Builder setDefaultFloat(float value) {
+        
+        defaultFloat_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional float default_float = 7;</code>
+       */
+      public Builder clearDefaultFloat() {
+        
+        defaultFloat_ = 0F;
+        onChanged();
+        return this;
+      }
+
+      private double defaultDouble_ ;
+      /**
+       * <code>optional double default_double = 8;</code>
+       */
+      public double getDefaultDouble() {
+        return defaultDouble_;
+      }
+      /**
+       * <code>optional double default_double = 8;</code>
+       */
+      public Builder setDefaultDouble(double value) {
+        
+        defaultDouble_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional double default_double = 8;</code>
+       */
+      public Builder clearDefaultDouble() {
+        
+        defaultDouble_ = 0D;
+        onChanged();
+        return this;
+      }
+
+      private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY;
+      /**
+       * <code>optional bytes default_bytes = 9;</code>
+       */
+      public com.google.protobuf.ByteString getDefaultBytes() {
+        return defaultBytes_;
+      }
+      /**
+       * <code>optional bytes default_bytes = 9;</code>
+       */
+      public Builder setDefaultBytes(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        defaultBytes_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bytes default_bytes = 9;</code>
+       */
+      public Builder clearDefaultBytes() {
+        
+        defaultBytes_ = getDefaultInstance().getDefaultBytes();
+        onChanged();
+        return this;
+      }
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:com.google.protobuf.jruby.Sentinel)
+    }
+
+    // @@protoc_insertion_point(class_scope:com.google.protobuf.jruby.Sentinel)
+    private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;static {
+      defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel();
+    }
+
+    public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+  }
+
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_com_google_protobuf_jruby_Sentinel_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n\016sentinel.proto\022\031com.google.protobuf.jr" +
+      "uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" +
+      "\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" +
+      "\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" +
+      "t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" +
+      "default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " +
+      "\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3"
+    };
+    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
+          public com.google.protobuf.ExtensionRegistry assignDescriptors(
+              com.google.protobuf.Descriptors.FileDescriptor root) {
+            descriptor = root;
+            return null;
+          }
+        };
+    com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+        }, assigner);
+    internal_static_com_google_protobuf_jruby_Sentinel_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_com_google_protobuf_jruby_Sentinel_descriptor,
+        new java.lang.String[] { "DefaultInt32", "DefaultInt64", "DefaultUnit32", "DefaultUint64", "DefaultString", "DefaultBool", "DefaultFloat", "DefaultDouble", "DefaultBytes", });
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
new file mode 100644
index 0000000..596a097
--- /dev/null
+++ b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
@@ -0,0 +1,300 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package com.google.protobuf.jruby;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.Descriptors;
+import org.jcodings.Encoding;
+import org.jcodings.specific.ASCIIEncoding;
+import org.jcodings.specific.USASCIIEncoding;
+import org.jcodings.specific.UTF8Encoding;
+import org.jruby.*;
+import org.jruby.runtime.Block;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import java.math.BigInteger;
+
+public class Utils {
+    public static Descriptors.FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) {
+        return Descriptors.FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase());
+    }
+
+    public static IRubyObject fieldTypeToRuby(ThreadContext context, Descriptors.FieldDescriptor.Type type) {
+        return fieldTypeToRuby(context, type.name());
+    }
+
+    public static IRubyObject fieldTypeToRuby(ThreadContext context, DescriptorProtos.FieldDescriptorProto.Type type) {
+        return fieldTypeToRuby(context, type.name());
+    }
+
+    private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) {
+
+        return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
+    }
+
+    public static void checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType,
+                            IRubyObject value, RubyModule typeClass) {
+        Ruby runtime = context.runtime;
+        Object val;
+        switch(fieldType) {
+            case INT32:
+            case INT64:
+            case UINT32:
+            case UINT64:
+                if (!isRubyNum(value)) {
+                    throw runtime.newTypeError("Expected number type for integral field.");
+                }
+                switch(fieldType) {
+                    case INT32:
+                        RubyNumeric.num2int(value);
+                        break;
+                    case INT64:
+                        RubyNumeric.num2long(value);
+                        break;
+                    case UINT32:
+                        num2uint(value);
+                        break;
+                    default:
+                        num2ulong(context.runtime, value);
+                        break;
+                }
+                checkIntTypePrecision(context, fieldType, value);
+                break;
+            case FLOAT:
+                if (!isRubyNum(value))
+                    throw runtime.newTypeError("Expected number type for float field.");
+                break;
+            case DOUBLE:
+                if (!isRubyNum(value))
+                    throw runtime.newTypeError("Expected number type for double field.");
+                break;
+            case BOOL:
+                if (!(value instanceof RubyBoolean))
+                    throw runtime.newTypeError("Invalid argument for boolean field.");
+                break;
+            case BYTES:
+            case STRING:
+                validateStringEncoding(context.runtime, fieldType, value);
+                break;
+            case MESSAGE:
+                if (value.getMetaClass() != typeClass) {
+                    throw runtime.newTypeError(value, typeClass);
+                }
+                break;
+            case ENUM:
+                if (value instanceof RubySymbol) {
+                    Descriptors.EnumDescriptor enumDescriptor =
+                            ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).getDescriptor();
+                    val = enumDescriptor.findValueByName(value.asJavaString());
+                    if (val == null)
+                        throw runtime.newRangeError("Enum value " + value + " is not found.");
+                } else if(!isRubyNum(value)) {
+                    throw runtime.newTypeError("Expected number or symbol type for enum field.");
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) {
+        Ruby runtime = context.runtime;
+        switch (fieldType) {
+            case INT32:
+                return runtime.newFixnum((Integer) value);
+            case INT64:
+                return runtime.newFixnum((Long) value);
+            case UINT32:
+                return runtime.newFixnum(((Integer) value) & (-1l >>> 32));
+            case UINT64:
+                long ret = (Long) value;
+                return ret >= 0 ? runtime.newFixnum(ret) :
+                        RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + "")));
+            case FLOAT:
+                return runtime.newFloat((Float) value);
+            case DOUBLE:
+                return runtime.newFloat((Double) value);
+            case BOOL:
+                return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
+            case BYTES:
+                return runtime.newString(((ByteString) value).toStringUtf8());
+            case STRING:
+                return runtime.newString(value.toString());
+            default:
+                return runtime.getNil();
+        }
+    }
+
+    public static int num2uint(IRubyObject value) {
+        long longVal = RubyNumeric.num2long(value);
+        if (longVal > UINT_MAX)
+            throw value.getRuntime().newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'");
+        long num = longVal;
+        if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE)
+            // encode to UINT32
+            num = (-longVal ^ (-1l >>> 32) ) + 1;
+        RubyNumeric.checkInt(value, num);
+        return (int) num;
+    }
+
+    public static long num2ulong(Ruby runtime, IRubyObject value) {
+        if (value instanceof RubyFloat) {
+            RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue());
+            return RubyBignum.big2ulong(bignum);
+        } else if (value instanceof RubyBignum) {
+            return RubyBignum.big2ulong((RubyBignum) value);
+        } else {
+            return RubyNumeric.num2long(value);
+        }
+    }
+
+    public static void validateStringEncoding(Ruby runtime, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+        if (!(value instanceof RubyString))
+            throw runtime.newTypeError("Invalid argument for string field.");
+        Encoding encoding = ((RubyString) value).getEncoding();
+        switch(type) {
+            case BYTES:
+                if (encoding != ASCIIEncoding.INSTANCE)
+                    throw runtime.newTypeError("Encoding for bytes fields" +
+                            " must be \"ASCII-8BIT\", but was " + encoding);
+                break;
+            case STRING:
+                if (encoding != UTF8Encoding.INSTANCE
+                        && encoding != USASCIIEncoding.INSTANCE)
+                    throw runtime.newTypeError("Encoding for string fields" +
+                            " must be \"UTF-8\" or \"ASCII\", but was " + encoding);
+                break;
+            default:
+                break;
+        }
+    }
+
+    public static void checkNameAvailability(ThreadContext context, String name) {
+        if (context.runtime.getObject().getConstantAt(name) != null)
+            throw context.runtime.newNameError(name + " is already defined", name);
+    }
+
+    /**
+     * Replace invalid "." in descriptor with __DOT__
+     * @param name
+     * @return
+     */
+    public static String escapeIdentifier(String name) {
+        return name.replace(".", BADNAME_REPLACEMENT);
+    }
+
+    /**
+     * Replace __DOT__ in descriptor name with "."
+     * @param name
+     * @return
+     */
+    public static String unescapeIdentifier(String name) {
+        return name.replace(BADNAME_REPLACEMENT, ".");
+    }
+
+    public static boolean isMapEntry(Descriptors.FieldDescriptor fieldDescriptor) {
+        return fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE &&
+                fieldDescriptor.isRepeated() &&
+                fieldDescriptor.getMessageType().getOptions().getMapEntry();
+    }
+
+    public static RubyFieldDescriptor msgdefCreateField(ThreadContext context, String label, IRubyObject name,
+                                      IRubyObject type, IRubyObject number, IRubyObject typeClass, RubyClass cFieldDescriptor) {
+        Ruby runtime = context.runtime;
+        RubyFieldDescriptor fieldDef = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK);
+        fieldDef.setLabel(context, runtime.newString(label));
+        fieldDef.setName(context, name);
+        fieldDef.setType(context, type);
+        fieldDef.setNumber(context, number);
+
+        if (!typeClass.isNil()) {
+            if (!(typeClass instanceof RubyString)) {
+                throw runtime.newArgumentError("expected string for type class");
+            }
+            fieldDef.setSubmsgName(context, typeClass);
+        }
+        return fieldDef;
+    }
+
+    protected static void checkIntTypePrecision(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+        if (value instanceof RubyFloat) {
+            double doubleVal = RubyNumeric.num2dbl(value);
+            if (Math.floor(doubleVal) != doubleVal) {
+                throw context.runtime.newRangeError("Non-integral floating point value assigned to integer field.");
+            }
+        }
+        if (type == Descriptors.FieldDescriptor.Type.UINT32 || type == Descriptors.FieldDescriptor.Type.UINT64) {
+            if (RubyNumeric.num2dbl(value) < 0) {
+                throw context.runtime.newRangeError("Assigning negative value to unsigned integer field.");
+            }
+        }
+    }
+
+    protected static boolean isRubyNum(Object value) {
+        return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum;
+    }
+
+    protected static void validateTypeClass(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+        Ruby runtime = context.runtime;
+        if (!(value instanceof RubyModule)) {
+            throw runtime.newArgumentError("TypeClass has incorrect type");
+        }
+        RubyModule klass = (RubyModule) value;
+        IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR);
+        if (descriptor.isNil()) {
+            throw runtime.newArgumentError("Type class has no descriptor. Please pass a " +
+                    "class or enum as returned by the DescriptorPool.");
+        }
+        if (type == Descriptors.FieldDescriptor.Type.MESSAGE) {
+            if (! (descriptor instanceof RubyDescriptor)) {
+                throw runtime.newArgumentError("Descriptor has an incorrect type");
+            }
+        } else if (type == Descriptors.FieldDescriptor.Type.ENUM) {
+            if (! (descriptor instanceof RubyEnumDescriptor)) {
+                throw runtime.newArgumentError("Descriptor has an incorrect type");
+            }
+        }
+    }
+
+    public static String BADNAME_REPLACEMENT = "__DOT__";
+
+    public static String DESCRIPTOR_INSTANCE_VAR = "@descriptor";
+
+    public static String EQUAL_SIGN = "=";
+
+    private static BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64)
+
+    private static long UINT_MAX = 0xffffffffl;
+}
diff --git a/ruby/src/main/java/google/ProtobufJavaService.java b/ruby/src/main/java/google/ProtobufJavaService.java
new file mode 100644
index 0000000..bffb492
--- /dev/null
+++ b/ruby/src/main/java/google/ProtobufJavaService.java
@@ -0,0 +1,60 @@
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2014 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.
+ */
+
+package google;
+
+import com.google.protobuf.jruby.*;
+import org.jruby.Ruby;
+import org.jruby.runtime.load.BasicLibraryService;
+
+import java.io.IOException;
+
+public class ProtobufJavaService implements BasicLibraryService {
+    @Override
+    public boolean basicLoad(Ruby ruby) throws IOException {
+        ruby.defineModule("Google");
+        RubyProtobuf.createProtobuf(ruby);
+        RubyDescriptor.createRubyDescriptor(ruby);
+        RubyBuilder.createRubyBuilder(ruby);
+        RubyFieldDescriptor.createRubyFileDescriptor(ruby);
+        RubyMessageBuilderContext.createRubyMessageBuilderContext(ruby);
+        RubyEnumDescriptor.createRubyEnumDescriptor(ruby);
+        RubyEnumBuilderContext.createRubyEnumBuilderContext(ruby);
+        RubyDescriptorPool.createRubyDescriptorPool(ruby);
+        RubyRepeatedField.createRubyRepeatedField(ruby);
+        RubyFieldDescriptor.createRubyFileDescriptor(ruby);
+        RubyMap.createRubyMap(ruby);
+        RubyOneofDescriptor.createRubyOneofDescriptor(ruby);
+        RubyOneofBuilderContext.createRubyOneofBuilderContext(ruby);
+        return true;
+    }
+}
diff --git a/ruby/src/main/sentinel.proto b/ruby/src/main/sentinel.proto
new file mode 100644
index 0000000..722041b
--- /dev/null
+++ b/ruby/src/main/sentinel.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+package com.google.protobuf.jruby;
+option optimize_for = CODE_SIZE;
+
+message Sentinel {
+  int32 default_int32 = 1;
+  int64 default_int64 = 2;
+  uint32 default_unit32 = 3;
+  uint64 default_uint64 = 4;
+  string default_string = 5;
+  bool default_bool = 6;
+  float default_float = 7;
+  double default_double = 8;
+  bytes default_bytes = 9;
+}
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
new file mode 100644
index 0000000..77c186e
--- /dev/null
+++ b/ruby/tests/basic.rb
@@ -0,0 +1,1174 @@
+#!/usr/bin/ruby
+
+require 'google/protobuf'
+require 'test/unit'
+
+# ------------- generated code --------------
+
+module BasicTest
+  pool = Google::Protobuf::DescriptorPool.new
+  pool.build do
+    add_message "Foo" do
+      optional :bar, :message, 1, "Bar"
+      repeated :baz, :message, 2, "Baz"
+    end
+
+    add_message "Bar" do
+      optional :msg, :string, 1
+    end
+
+    add_message "Baz" do
+      optional :msg, :string, 1
+    end
+
+    add_message "TestMessage" do
+      optional :optional_int32,  :int32,        1
+      optional :optional_int64,  :int64,        2
+      optional :optional_uint32, :uint32,       3
+      optional :optional_uint64, :uint64,       4
+      optional :optional_bool,   :bool,         5
+      optional :optional_float,  :float,        6
+      optional :optional_double, :double,       7
+      optional :optional_string, :string,       8
+      optional :optional_bytes,  :bytes,        9
+      optional :optional_msg,    :message,      10, "TestMessage2"
+      optional :optional_enum,   :enum,         11, "TestEnum"
+
+      repeated :repeated_int32,  :int32,        12
+      repeated :repeated_int64,  :int64,        13
+      repeated :repeated_uint32, :uint32,       14
+      repeated :repeated_uint64, :uint64,       15
+      repeated :repeated_bool,   :bool,         16
+      repeated :repeated_float,  :float,        17
+      repeated :repeated_double, :double,       18
+      repeated :repeated_string, :string,       19
+      repeated :repeated_bytes,  :bytes,        20
+      repeated :repeated_msg,    :message,      21, "TestMessage2"
+      repeated :repeated_enum,   :enum,         22, "TestEnum"
+    end
+    add_message "TestMessage2" do
+      optional :foo, :int32, 1
+    end
+
+    add_message "Recursive1" do
+      optional :foo, :message, 1, "Recursive2"
+    end
+    add_message "Recursive2" do
+      optional :foo, :message, 1, "Recursive1"
+    end
+
+    add_enum "TestEnum" do
+      value :Default, 0
+      value :A, 1
+      value :B, 2
+      value :C, 3
+    end
+
+    add_message "BadFieldNames" do
+      optional :dup, :int32, 1
+      optional :class, :int32, 2
+      optional :"a.b", :int32, 3
+    end
+
+    add_message "MapMessage" do
+      map :map_string_int32, :string, :int32, 1
+      map :map_string_msg, :string, :message, 2, "TestMessage2"
+    end
+    add_message "MapMessageWireEquiv" do
+      repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1"
+      repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2"
+    end
+    add_message "MapMessageWireEquiv_entry1" do
+      optional :key, :string, 1
+      optional :value, :int32, 2
+    end
+    add_message "MapMessageWireEquiv_entry2" do
+      optional :key, :string, 1
+      optional :value, :message, 2, "TestMessage2"
+    end
+
+    add_message "OneofMessage" do
+      oneof :my_oneof do
+        optional :a, :string, 1
+        optional :b, :int32, 2
+        optional :c, :message, 3, "TestMessage2"
+        optional :d, :enum, 4, "TestEnum"
+      end
+    end
+  end
+
+  Foo = pool.lookup("Foo").msgclass
+  Bar = pool.lookup("Bar").msgclass
+  Baz = pool.lookup("Baz").msgclass
+  TestMessage = pool.lookup("TestMessage").msgclass
+  TestMessage2 = pool.lookup("TestMessage2").msgclass
+  Recursive1 = pool.lookup("Recursive1").msgclass
+  Recursive2 = pool.lookup("Recursive2").msgclass
+  TestEnum = pool.lookup("TestEnum").enummodule
+  BadFieldNames = pool.lookup("BadFieldNames").msgclass
+  MapMessage = pool.lookup("MapMessage").msgclass
+  MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass
+  MapMessageWireEquiv_entry1 =
+    pool.lookup("MapMessageWireEquiv_entry1").msgclass
+  MapMessageWireEquiv_entry2 =
+    pool.lookup("MapMessageWireEquiv_entry2").msgclass
+  OneofMessage = pool.lookup("OneofMessage").msgclass
+
+# ------------ test cases ---------------
+
+  class MessageContainerTest < Test::Unit::TestCase
+
+    def test_defaults
+      m = TestMessage.new
+      assert m.optional_int32 == 0
+      assert m.optional_int64 == 0
+      assert m.optional_uint32 == 0
+      assert m.optional_uint64 == 0
+      assert m.optional_bool == false
+      assert m.optional_float == 0.0
+      assert m.optional_double == 0.0
+      assert m.optional_string == ""
+      assert m.optional_bytes == ""
+      assert m.optional_msg == nil
+      assert m.optional_enum == :Default
+    end
+
+    def test_setters
+      m = TestMessage.new
+      m.optional_int32 = -42
+      assert m.optional_int32 == -42
+      m.optional_int64 = -0x1_0000_0000
+      assert m.optional_int64 == -0x1_0000_0000
+      m.optional_uint32 = 0x9000_0000
+      assert m.optional_uint32 == 0x9000_0000
+      m.optional_uint64 = 0x9000_0000_0000_0000
+      assert m.optional_uint64 == 0x9000_0000_0000_0000
+      m.optional_bool = true
+      assert m.optional_bool == true
+      m.optional_float = 0.5
+      assert m.optional_float == 0.5
+      m.optional_double = 0.5
+      m.optional_string = "hello"
+      assert m.optional_string == "hello"
+      m.optional_bytes = "world".encode!('ASCII-8BIT')
+      assert m.optional_bytes == "world"
+      m.optional_msg = TestMessage2.new(:foo => 42)
+      assert m.optional_msg == TestMessage2.new(:foo => 42)
+      m.optional_msg = nil
+      assert m.optional_msg == nil
+    end
+
+    def test_ctor_args
+      m = TestMessage.new(:optional_int32 => -42,
+                          :optional_msg => TestMessage2.new,
+                          :optional_enum => :C,
+                          :repeated_string => ["hello", "there", "world"])
+      assert m.optional_int32 == -42
+      assert m.optional_msg.class == TestMessage2
+      assert m.repeated_string.length == 3
+      assert m.optional_enum == :C
+      assert m.repeated_string[0] == "hello"
+      assert m.repeated_string[1] == "there"
+      assert m.repeated_string[2] == "world"
+    end
+
+    def test_inspect
+      m = TestMessage.new(:optional_int32 => -42,
+                          :optional_enum => :A,
+                          :optional_msg => TestMessage2.new,
+                          :repeated_string => ["hello", "there", "world"])
+      expected = '<BasicTest::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: "", optional_bytes: "", optional_msg: <BasicTest::TestMessage2: foo: 0>, optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: ["hello", "there", "world"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>'
+      assert_equal expected, m.inspect
+    end
+
+    def test_hash
+      m1 = TestMessage.new(:optional_int32 => 42)
+      m2 = TestMessage.new(:optional_int32 => 102)
+      assert m1.hash != 0
+      assert m2.hash != 0
+      # relying on the randomness here -- if hash function changes and we are
+      # unlucky enough to get a collision, then change the values above.
+      assert m1.hash != m2.hash
+    end
+
+    def test_unknown_field_errors
+      e = assert_raise NoMethodError do
+        TestMessage.new.hello
+      end
+      assert_match(/hello/, e.message)
+
+      e = assert_raise NoMethodError do
+        TestMessage.new.hello = "world"
+      end
+      assert_match(/hello/, e.message)
+    end
+
+    def test_initialization_map_errors
+      e = assert_raise ArgumentError do
+        TestMessage.new(:hello => "world")
+      end
+      assert_match(/hello/, e.message)
+
+      e = assert_raise ArgumentError do
+        MapMessage.new(:map_string_int32 => "hello")
+      end
+      assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
+
+      e = assert_raise ArgumentError do
+        TestMessage.new(:repeated_uint32 => "hello")
+      end
+      assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
+    end
+
+    def test_type_errors
+      m = TestMessage.new
+      assert_raise TypeError do
+        m.optional_int32 = "hello"
+      end
+      assert_raise TypeError do
+        m.optional_string = 42
+      end
+      assert_raise TypeError do
+        m.optional_string = nil
+      end
+      assert_raise TypeError do
+        m.optional_bool = 42
+      end
+      assert_raise TypeError do
+        m.optional_msg = TestMessage.new  # expects TestMessage2
+      end
+
+      assert_raise TypeError do
+        m.repeated_int32 = []  # needs RepeatedField
+      end
+
+      assert_raise TypeError do
+        m.repeated_int32.push "hello"
+      end
+
+      assert_raise TypeError do
+        m.repeated_msg.push TestMessage.new
+      end
+    end
+
+    def test_string_encoding
+      m = TestMessage.new
+
+      # Assigning a normal (ASCII or UTF8) string to a bytes field, or
+      # ASCII-8BIT to a string field, raises an error.
+      assert_raise TypeError do
+        m.optional_bytes = "Test string ASCII".encode!('ASCII')
+      end
+      assert_raise TypeError do
+        m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
+      end
+      assert_raise TypeError do
+        m.optional_string = ["FFFF"].pack('H*')
+      end
+
+      # "Ordinary" use case.
+      m.optional_bytes = ["FFFF"].pack('H*')
+      m.optional_string = "\u0100"
+
+      # strings are mutable so we can do this, but serialize should catch it.
+      m.optional_string = "asdf".encode!('UTF-8')
+      m.optional_string.encode!('ASCII-8BIT')
+      assert_raise TypeError do
+        data = TestMessage.encode(m)
+      end
+    end
+
+    def test_rptfield_int32
+      l = Google::Protobuf::RepeatedField.new(:int32)
+      assert l.count == 0
+      l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
+      assert l.count == 3
+      assert_equal [1, 2, 3], l
+      assert_equal l, [1, 2, 3]
+      l.push 4
+      assert l == [1, 2, 3, 4]
+      dst_list = []
+      l.each { |val| dst_list.push val }
+      assert dst_list == [1, 2, 3, 4]
+      assert l.to_a == [1, 2, 3, 4]
+      assert l[0] == 1
+      assert l[3] == 4
+      l[0] = 5
+      assert l == [5, 2, 3, 4]
+
+      l2 = l.dup
+      assert l == l2
+      assert l.object_id != l2.object_id
+      l2.push 6
+      assert l.count == 4
+      assert l2.count == 5
+
+      assert l.inspect == '[5, 2, 3, 4]'
+
+      l.concat([7, 8, 9])
+      assert l == [5, 2, 3, 4, 7, 8, 9]
+      assert l.pop == 9
+      assert l == [5, 2, 3, 4, 7, 8]
+
+      assert_raise TypeError do
+        m = TestMessage.new
+        l.push m
+      end
+
+      m = TestMessage.new
+      m.repeated_int32 = l
+      assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
+      assert m.repeated_int32.object_id == l.object_id
+      l.push 42
+      assert m.repeated_int32.pop == 42
+
+      l3 = l + l.dup
+      assert l3.count == l.count * 2
+      l.count.times do |i|
+        assert l3[i] == l[i]
+        assert l3[l.count + i] == l[i]
+      end
+
+      l.clear
+      assert l.count == 0
+      l += [1, 2, 3, 4]
+      l.replace([5, 6, 7, 8])
+      assert l == [5, 6, 7, 8]
+
+      l4 = Google::Protobuf::RepeatedField.new(:int32)
+      l4[5] = 42
+      assert l4 == [0, 0, 0, 0, 0, 42]
+
+      l4 << 100
+      assert l4 == [0, 0, 0, 0, 0, 42, 100]
+      l4 << 101 << 102
+      assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
+    end
+
+    def test_parent_rptfield
+      #make sure we set the RepeatedField and can add to it
+      m = TestMessage.new
+      assert m.repeated_string == []
+      m.repeated_string << 'ok'
+      m.repeated_string.push('ok2')
+      assert m.repeated_string == ['ok', 'ok2']
+      m.repeated_string += ['ok3']
+      assert m.repeated_string == ['ok', 'ok2', 'ok3']
+    end
+
+    def test_rptfield_msg
+      l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
+      l.push TestMessage.new
+      assert l.count == 1
+      assert_raise TypeError do
+        l.push TestMessage2.new
+      end
+      assert_raise TypeError do
+        l.push 42
+      end
+
+      l2 = l.dup
+      assert l2[0] == l[0]
+      assert l2[0].object_id == l[0].object_id
+
+      l2 = Google::Protobuf.deep_copy(l)
+      assert l2[0] == l[0]
+      assert l2[0].object_id != l[0].object_id
+
+      l3 = l + l2
+      assert l3.count == 2
+      assert l3[0] == l[0]
+      assert l3[1] == l2[0]
+      l3[0].optional_int32 = 1000
+      assert l[0].optional_int32 == 1000
+
+      new_msg = TestMessage.new(:optional_int32 => 200)
+      l4 = l + [new_msg]
+      assert l4.count == 2
+      new_msg.optional_int32 = 1000
+      assert l4[1].optional_int32 == 1000
+    end
+
+    def test_rptfield_enum
+      l = Google::Protobuf::RepeatedField.new(:enum, TestEnum)
+      l.push :A
+      l.push :B
+      l.push :C
+      assert l.count == 3
+      assert_raise RangeError do
+        l.push :D
+      end
+      assert l[0] == :A
+
+      l.push 4
+      assert l[3] == 4
+    end
+
+    def test_rptfield_initialize
+      assert_raise ArgumentError do
+        l = Google::Protobuf::RepeatedField.new
+      end
+      assert_raise ArgumentError do
+        l = Google::Protobuf::RepeatedField.new(:message)
+      end
+      assert_raise ArgumentError do
+        l = Google::Protobuf::RepeatedField.new([1, 2, 3])
+      end
+      assert_raise ArgumentError do
+        l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new])
+      end
+    end
+
+    def test_rptfield_array_ducktyping
+      l = Google::Protobuf::RepeatedField.new(:int32)
+      length_methods = %w(count length size)
+      length_methods.each do |lm|
+        assert l.send(lm)  == 0
+      end
+      # out of bounds returns a nil
+      assert l[0] == nil
+      assert l[1] == nil
+      assert l[-1] == nil
+      l.push 4
+      length_methods.each do |lm|
+        assert l.send(lm) == 1
+      end
+      assert l[0] == 4
+      assert l[1] == nil
+      assert l[-1] == 4
+      assert l[-2] == nil
+
+      l.push 2
+      length_methods.each do |lm|
+        assert l.send(lm) == 2
+      end
+      assert l[0] == 4
+      assert l[1] == 2
+      assert l[2] == nil
+      assert l[-1] == 2
+      assert l[-2] == 4
+      assert l[-3] == nil
+
+      #adding out of scope will backfill with empty objects
+    end
+
+    def test_map_basic
+      # allowed key types:
+      # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
+
+      m = Google::Protobuf::Map.new(:string, :int32)
+      m["asdf"] = 1
+      assert m["asdf"] == 1
+      m["jkl;"] = 42
+      assert m == { "jkl;" => 42, "asdf" => 1 }
+      assert m.has_key?("asdf")
+      assert !m.has_key?("qwerty")
+      assert m.length == 2
+
+      m2 = m.dup
+      assert m == m2
+      assert m.hash != 0
+      assert m.hash == m2.hash
+
+      collected = {}
+      m.each { |k,v| collected[v] = k }
+      assert collected == { 42 => "jkl;", 1 => "asdf" }
+
+      assert m.delete("asdf") == 1
+      assert !m.has_key?("asdf")
+      assert m["asdf"] == nil
+      assert !m.has_key?("asdf")
+
+      # We only assert on inspect value when there is one map entry because the
+      # order in which elements appear is unspecified (depends on the internal
+      # hash function). We don't want a brittle test.
+      assert m.inspect == "{\"jkl;\"=>42}"
+
+      assert m.keys == ["jkl;"]
+      assert m.values == [42]
+
+      m.clear
+      assert m.length == 0
+      assert m == {}
+
+      assert_raise TypeError do
+        m[1] = 1
+      end
+      assert_raise RangeError do
+        m["asdf"] = 0x1_0000_0000
+      end
+    end
+
+    def test_map_ctor
+      m = Google::Protobuf::Map.new(:string, :int32,
+                                    {"a" => 1, "b" => 2, "c" => 3})
+      assert m == {"a" => 1, "c" => 3, "b" => 2}
+    end
+
+    def test_map_keytypes
+      m = Google::Protobuf::Map.new(:int32, :int32)
+      m[1] = 42
+      m[-1] = 42
+      assert_raise RangeError do
+        m[0x8000_0000] = 1
+      end
+      assert_raise TypeError do
+        m["asdf"] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:int64, :int32)
+      m[0x1000_0000_0000_0000] = 1
+      assert_raise RangeError do
+        m[0x1_0000_0000_0000_0000] = 1
+      end
+      assert_raise TypeError do
+        m["asdf"] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:uint32, :int32)
+      m[0x8000_0000] = 1
+      assert_raise RangeError do
+        m[0x1_0000_0000] = 1
+      end
+      assert_raise RangeError do
+        m[-1] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:uint64, :int32)
+      m[0x8000_0000_0000_0000] = 1
+      assert_raise RangeError do
+        m[0x1_0000_0000_0000_0000] = 1
+      end
+      assert_raise RangeError do
+        m[-1] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:bool, :int32)
+      m[true] = 1
+      m[false] = 2
+      assert_raise TypeError do
+        m[1] = 1
+      end
+      assert_raise TypeError do
+        m["asdf"] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:string, :int32)
+      m["asdf"] = 1
+      assert_raise TypeError do
+        m[1] = 1
+      end
+      assert_raise TypeError do
+        bytestring = ["FFFF"].pack("H*")
+        m[bytestring] = 1
+      end
+
+      m = Google::Protobuf::Map.new(:bytes, :int32)
+      bytestring = ["FFFF"].pack("H*")
+      m[bytestring] = 1
+      assert_raise TypeError do
+        m["asdf"] = 1
+      end
+      assert_raise TypeError do
+        m[1] = 1
+      end
+    end
+
+    def test_map_msg_enum_valuetypes
+      m = Google::Protobuf::Map.new(:string, :message, TestMessage)
+      m["asdf"] = TestMessage.new
+      assert_raise TypeError do
+        m["jkl;"] = TestMessage2.new
+      end
+
+      m = Google::Protobuf::Map.new(
+        :string, :message, TestMessage,
+        { "a" => TestMessage.new(:optional_int32 => 42),
+          "b" => TestMessage.new(:optional_int32 => 84) })
+      assert m.length == 2
+      assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
+
+      m = Google::Protobuf::Map.new(:string, :enum, TestEnum,
+                                    { "x" => :A, "y" => :B, "z" => :C })
+      assert m.length == 3
+      assert m["z"] == :C
+      m["z"] = 2
+      assert m["z"] == :B
+      m["z"] = 4
+      assert m["z"] == 4
+      assert_raise RangeError do
+        m["z"] = :Z
+      end
+      assert_raise TypeError do
+        m["z"] = "z"
+      end
+    end
+
+    def test_map_dup_deep_copy
+      m = Google::Protobuf::Map.new(
+        :string, :message, TestMessage,
+        { "a" => TestMessage.new(:optional_int32 => 42),
+          "b" => TestMessage.new(:optional_int32 => 84) })
+
+      m2 = m.dup
+      assert m == m2
+      assert m.object_id != m2.object_id
+      assert m["a"].object_id == m2["a"].object_id
+      assert m["b"].object_id == m2["b"].object_id
+
+      m2 = Google::Protobuf.deep_copy(m)
+      assert m == m2
+      assert m.object_id != m2.object_id
+      assert m["a"].object_id != m2["a"].object_id
+      assert m["b"].object_id != m2["b"].object_id
+    end
+
+    def test_map_field
+      m = MapMessage.new
+      assert m.map_string_int32 == {}
+      assert m.map_string_msg == {}
+
+      m = MapMessage.new(
+        :map_string_int32 => {"a" => 1, "b" => 2},
+        :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
+                            "b" => TestMessage2.new(:foo => 2)})
+      assert m.map_string_int32.keys.sort == ["a", "b"]
+      assert m.map_string_int32["a"] == 1
+      assert m.map_string_msg["b"].foo == 2
+
+      m.map_string_int32["c"] = 3
+      assert m.map_string_int32["c"] == 3
+      m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
+      assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
+      m.map_string_msg.delete("b")
+      m.map_string_msg.delete("c")
+      assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
+
+      assert_raise TypeError do
+        m.map_string_msg["e"] = TestMessage.new # wrong value type
+      end
+      # ensure nothing was added by the above
+      assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
+
+      m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
+      assert_raise TypeError do
+        m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
+      end
+      assert_raise TypeError do
+        m.map_string_int32 = {}
+      end
+
+      assert_raise TypeError do
+        m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
+      end
+    end
+
+    def test_map_encode_decode
+      m = MapMessage.new(
+        :map_string_int32 => {"a" => 1, "b" => 2},
+        :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
+                            "b" => TestMessage2.new(:foo => 2)})
+      m2 = MapMessage.decode(MapMessage.encode(m))
+      assert m == m2
+
+      m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
+      assert m3.map_string_int32.length == 2
+
+      kv = {}
+      m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
+      assert kv == {"a" => 1, "b" => 2}
+
+      kv = {}
+      m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
+      assert kv == {"a" => TestMessage2.new(:foo => 1),
+                    "b" => TestMessage2.new(:foo => 2)}
+    end
+
+    def test_oneof_descriptors
+      d = OneofMessage.descriptor
+      o = d.lookup_oneof("my_oneof")
+      assert o != nil
+      assert o.class == Google::Protobuf::OneofDescriptor
+      assert o.name == "my_oneof"
+      oneof_count = 0
+      d.each_oneof{ |oneof|
+        oneof_count += 1
+        assert oneof == o
+      }
+      assert oneof_count == 1
+      assert o.count == 4
+      field_names = o.map{|f| f.name}.sort
+      assert field_names == ["a", "b", "c", "d"]
+    end
+
+    def test_oneof
+      d = OneofMessage.new
+      assert d.a == nil
+      assert d.b == nil
+      assert d.c == nil
+      assert d.d == nil
+      assert d.my_oneof == nil
+
+      d.a = "hi"
+      assert d.a == "hi"
+      assert d.b == nil
+      assert d.c == nil
+      assert d.d == nil
+      assert d.my_oneof == :a
+
+      d.b = 42
+      assert d.a == nil
+      assert d.b == 42
+      assert d.c == nil
+      assert d.d == nil
+      assert d.my_oneof == :b
+
+      d.c = TestMessage2.new(:foo => 100)
+      assert d.a == nil
+      assert d.b == nil
+      assert d.c.foo == 100
+      assert d.d == nil
+      assert d.my_oneof == :c
+
+      d.d = :C
+      assert d.a == nil
+      assert d.b == nil
+      assert d.c == nil
+      assert d.d == :C
+      assert d.my_oneof == :d
+
+      d2 = OneofMessage.decode(OneofMessage.encode(d))
+      assert d2 == d
+
+      encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
+      encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
+      encoded_field_c = OneofMessage.encode(
+        OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
+      encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
+
+      d3 = OneofMessage.decode(
+        encoded_field_c + encoded_field_a + encoded_field_d)
+      assert d3.a == nil
+      assert d3.b == nil
+      assert d3.c == nil
+      assert d3.d == :B
+
+      d4 = OneofMessage.decode(
+        encoded_field_c + encoded_field_a + encoded_field_d +
+        encoded_field_c)
+      assert d4.a == nil
+      assert d4.b == nil
+      assert d4.c.foo == 1
+      assert d4.d == nil
+
+      d5 = OneofMessage.new(:a => "hello")
+      assert d5.a != nil
+      d5.a = nil
+      assert d5.a == nil
+      assert OneofMessage.encode(d5) == ''
+      assert d5.my_oneof == nil
+    end
+
+    def test_enum_field
+      m = TestMessage.new
+      assert m.optional_enum == :Default
+      m.optional_enum = :A
+      assert m.optional_enum == :A
+      assert_raise RangeError do
+        m.optional_enum = :ASDF
+      end
+      m.optional_enum = 1
+      assert m.optional_enum == :A
+      m.optional_enum = 100
+      assert m.optional_enum == 100
+    end
+
+    def test_dup
+      m = TestMessage.new
+      m.optional_string = "hello"
+      m.optional_int32 = 42
+      tm1 = TestMessage2.new(:foo => 100)
+      tm2 = TestMessage2.new(:foo => 200)
+      m.repeated_msg.push tm1
+      assert m.repeated_msg[-1] == tm1
+      m.repeated_msg.push tm2
+      assert m.repeated_msg[-1] == tm2
+      m2 = m.dup
+      assert m == m2
+      m.optional_int32 += 1
+      assert m != m2
+      assert m.repeated_msg[0] == m2.repeated_msg[0]
+      assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
+    end
+
+    def test_deep_copy
+      m = TestMessage.new(:optional_int32 => 42,
+                          :repeated_msg => [TestMessage2.new(:foo => 100)])
+      m2 = Google::Protobuf.deep_copy(m)
+      assert m == m2
+      assert m.repeated_msg == m2.repeated_msg
+      assert m.repeated_msg.object_id != m2.repeated_msg.object_id
+      assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
+    end
+
+    def test_eq
+      m = TestMessage.new(:optional_int32 => 42,
+                          :repeated_int32 => [1, 2, 3])
+      m2 = TestMessage.new(:optional_int32 => 43,
+                           :repeated_int32 => [1, 2, 3])
+      assert m != m2
+    end
+
+    def test_enum_lookup
+      assert TestEnum::A == 1
+      assert TestEnum::B == 2
+      assert TestEnum::C == 3
+
+      assert TestEnum::lookup(1) == :A
+      assert TestEnum::lookup(2) == :B
+      assert TestEnum::lookup(3) == :C
+
+      assert TestEnum::resolve(:A) == 1
+      assert TestEnum::resolve(:B) == 2
+      assert TestEnum::resolve(:C) == 3
+    end
+
+    def test_parse_serialize
+      m = TestMessage.new(:optional_int32 => 42,
+                          :optional_string => "hello world",
+                          :optional_enum => :B,
+                          :repeated_string => ["a", "b", "c"],
+                          :repeated_int32 => [42, 43, 44],
+                          :repeated_enum => [:A, :B, :C, 100],
+                          :repeated_msg => [TestMessage2.new(:foo => 1),
+                                            TestMessage2.new(:foo => 2)])
+      data = TestMessage.encode m
+      m2 = TestMessage.decode data
+      assert m == m2
+
+      data = Google::Protobuf.encode m
+      m2 = Google::Protobuf.decode(TestMessage, data)
+      assert m == m2
+    end
+
+    def test_encode_decode_helpers
+      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+      json = m.to_json
+      m2 = TestMessage.decode_json(json)
+      assert m2.optional_string == 'foo'
+      assert m2.repeated_string == ['bar1', 'bar2']
+
+      proto = m.to_proto
+      m2 = TestMessage.decode(proto)
+      assert m2.optional_string == 'foo'
+      assert m2.repeated_string == ['bar1', 'bar2']
+    end
+
+    def test_protobuf_encode_decode_helpers
+      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+      encoded_msg = Google::Protobuf.encode(m)
+      assert_equal m.to_proto, encoded_msg
+
+      decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg)
+      assert_equal TestMessage.decode(m.to_proto), decoded_msg
+    end
+
+    def test_protobuf_encode_decode_json_helpers
+      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+      encoded_msg = Google::Protobuf.encode_json(m)
+      assert_equal m.to_json, encoded_msg
+
+      decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg)
+      assert_equal TestMessage.decode_json(m.to_json), decoded_msg
+    end
+
+    def test_to_h
+      m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+      expected_result = {
+        :optional_bool=>true,
+        :optional_bytes=>"",
+        :optional_double=>-10.100001,
+        :optional_enum=>:Default,
+        :optional_float=>0.0,
+        :optional_int32=>0,
+        :optional_int64=>0,
+        :optional_msg=>nil,
+        :optional_string=>"foo",
+        :optional_uint32=>0,
+        :optional_uint64=>0,
+        :repeated_bool=>[],
+        :repeated_bytes=>[],
+        :repeated_double=>[],
+        :repeated_enum=>[],
+        :repeated_float=>[],
+        :repeated_int32=>[],
+        :repeated_int64=>[],
+        :repeated_msg=>[],
+        :repeated_string=>["bar1", "bar2"],
+        :repeated_uint32=>[],
+        :repeated_uint64=>[]
+      }
+      assert_equal expected_result, m.to_h
+    end
+
+
+    def test_def_errors
+      s = Google::Protobuf::DescriptorPool.new
+      assert_raise TypeError do
+        s.build do
+          # enum with no default (integer value 0)
+          add_enum "MyEnum" do
+            value :A, 1
+          end
+        end
+      end
+      assert_raise TypeError do
+        s.build do
+          # message with required field (unsupported in proto3)
+          add_message "MyMessage" do
+            required :foo, :int32, 1
+          end
+        end
+      end
+    end
+
+    def test_corecursive
+      # just be sure that we can instantiate types with corecursive field-type
+      # references.
+      m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new))
+      assert Recursive1.descriptor.lookup("foo").subtype ==
+        Recursive2.descriptor
+      assert Recursive2.descriptor.lookup("foo").subtype ==
+        Recursive1.descriptor
+
+      serialized = Recursive1.encode(m)
+      m2 = Recursive1.decode(serialized)
+      assert m == m2
+    end
+
+    def test_serialize_cycle
+      m = Recursive1.new(:foo => Recursive2.new)
+      m.foo.foo = m
+      assert_raise RuntimeError do
+        serialized = Recursive1.encode(m)
+      end
+    end
+
+    def test_bad_field_names
+      m = BadFieldNames.new(:dup => 1, :class => 2)
+      m2 = m.dup
+      assert m == m2
+      assert m['dup'] == 1
+      assert m['class'] == 2
+      m['dup'] = 3
+      assert m['dup'] == 3
+      m['a.b'] = 4
+      assert m['a.b'] == 4
+    end
+
+    def test_int_ranges
+      m = TestMessage.new
+
+      m.optional_int32 = 0
+      m.optional_int32 = -0x8000_0000
+      m.optional_int32 = +0x7fff_ffff
+      m.optional_int32 = 1.0
+      m.optional_int32 = -1.0
+      m.optional_int32 = 2e9
+      assert_raise RangeError do
+        m.optional_int32 = -0x8000_0001
+      end
+      assert_raise RangeError do
+        m.optional_int32 = +0x8000_0000
+      end
+      assert_raise RangeError do
+        m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+      end
+      assert_raise RangeError do
+        m.optional_int32 = 1e12
+      end
+      assert_raise RangeError do
+        m.optional_int32 = 1.5
+      end
+
+      m.optional_uint32 = 0
+      m.optional_uint32 = +0xffff_ffff
+      m.optional_uint32 = 1.0
+      m.optional_uint32 = 4e9
+      assert_raise RangeError do
+        m.optional_uint32 = -1
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = -1.5
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = -1.5e12
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = -0x1000_0000_0000_0000
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = +0x1_0000_0000
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = 1e12
+      end
+      assert_raise RangeError do
+        m.optional_uint32 = 1.5
+      end
+
+      m.optional_int64 = 0
+      m.optional_int64 = -0x8000_0000_0000_0000
+      m.optional_int64 = +0x7fff_ffff_ffff_ffff
+      m.optional_int64 = 1.0
+      m.optional_int64 = -1.0
+      m.optional_int64 = 8e18
+      m.optional_int64 = -8e18
+      assert_raise RangeError do
+        m.optional_int64 = -0x8000_0000_0000_0001
+      end
+      assert_raise RangeError do
+        m.optional_int64 = +0x8000_0000_0000_0000
+      end
+      assert_raise RangeError do
+        m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+      end
+      assert_raise RangeError do
+        m.optional_int64 = 1e50
+      end
+      assert_raise RangeError do
+        m.optional_int64 = 1.5
+      end
+
+      m.optional_uint64 = 0
+      m.optional_uint64 = +0xffff_ffff_ffff_ffff
+      m.optional_uint64 = 1.0
+      m.optional_uint64 = 16e18
+      assert_raise RangeError do
+        m.optional_uint64 = -1
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = -1.5
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = -1.5e12
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = -0x1_0000_0000_0000_0000
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = +0x1_0000_0000_0000_0000
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = 1e50
+      end
+      assert_raise RangeError do
+        m.optional_uint64 = 1.5
+      end
+    end
+
+    def test_stress_test
+      m = TestMessage.new
+      m.optional_int32 = 42
+      m.optional_int64 = 0x100000000
+      m.optional_string = "hello world"
+      10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end
+      10.times do m.repeated_string.push "hello world" end
+
+      data = TestMessage.encode(m)
+
+      l = 0
+      10_000.times do
+        m = TestMessage.decode(data)
+        data_new = TestMessage.encode(m)
+        assert data_new == data
+        data = data_new
+      end
+    end
+
+    def test_reflection
+      m = TestMessage.new(:optional_int32 => 1234)
+      msgdef = m.class.descriptor
+      assert msgdef.class == Google::Protobuf::Descriptor
+      assert msgdef.any? {|field| field.name == "optional_int32"}
+      optional_int32 = msgdef.lookup "optional_int32"
+      assert optional_int32.class == Google::Protobuf::FieldDescriptor
+      assert optional_int32 != nil
+      assert optional_int32.name == "optional_int32"
+      assert optional_int32.type == :int32
+      optional_int32.set(m, 5678)
+      assert m.optional_int32 == 5678
+      m.optional_int32 = 1000
+      assert optional_int32.get(m) == 1000
+
+      optional_msg = msgdef.lookup "optional_msg"
+      assert optional_msg.subtype == TestMessage2.descriptor
+
+      optional_msg.set(m, optional_msg.subtype.msgclass.new)
+
+      assert msgdef.msgclass == TestMessage
+
+      optional_enum = msgdef.lookup "optional_enum"
+      assert optional_enum.subtype == TestEnum.descriptor
+      assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
+      optional_enum.subtype.each do |k, v|
+        # set with integer, check resolution to symbolic name
+        optional_enum.set(m, v)
+        assert optional_enum.get(m) == k
+      end
+    end
+
+    def test_json
+      # TODO: Fix JSON in JRuby version.
+      return if RUBY_PLATFORM == "java"
+      m = TestMessage.new(:optional_int32 => 1234,
+                          :optional_int64 => -0x1_0000_0000,
+                          :optional_uint32 => 0x8000_0000,
+                          :optional_uint64 => 0xffff_ffff_ffff_ffff,
+                          :optional_bool => true,
+                          :optional_float => 1.0,
+                          :optional_double => -1e100,
+                          :optional_string => "Test string",
+                          :optional_bytes => ["FFFFFFFF"].pack('H*'),
+                          :optional_msg => TestMessage2.new(:foo => 42),
+                          :repeated_int32 => [1, 2, 3, 4],
+                          :repeated_string => ["a", "b", "c"],
+                          :repeated_bool => [true, false, true, false],
+                          :repeated_msg => [TestMessage2.new(:foo => 1),
+                                            TestMessage2.new(:foo => 2)])
+
+      json_text = TestMessage.encode_json(m)
+      m2 = TestMessage.decode_json(json_text)
+      assert m == m2
+
+      # Crash case from GitHub issue 283.
+      bar = Bar.new(msg: "bar")
+      baz1 = Baz.new(msg: "baz")
+      baz2 = Baz.new(msg: "quux")
+      Foo.encode_json(Foo.new)
+      Foo.encode_json(Foo.new(bar: bar))
+      Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
+    end
+
+    def test_json_maps
+      # TODO: Fix JSON in JRuby version.
+      return if RUBY_PLATFORM == "java"
+      m = MapMessage.new(:map_string_int32 => {"a" => 1})
+      expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}'
+      expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
+      assert MapMessage.encode_json(m) == expected
+
+      json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
+      assert json == expected_preserve
+
+      m2 = MapMessage.decode_json(MapMessage.encode_json(m))
+      assert m == m2
+    end
+  end
+end
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
new file mode 100644
index 0000000..42d82a6
--- /dev/null
+++ b/ruby/tests/generated_code.proto
@@ -0,0 +1,67 @@
+syntax = "proto3";
+
+package A.B.C;
+
+message TestMessage {
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  bool optional_bool = 5;
+  double optional_double = 6;
+  float optional_float = 7;
+  string optional_string = 8;
+  bytes optional_bytes = 9;
+  TestEnum optional_enum = 10;
+  TestMessage optional_msg = 11;
+
+  repeated int32 repeated_int32 = 21;
+  repeated int64 repeated_int64 = 22;
+  repeated uint32 repeated_uint32 = 23;
+  repeated uint64 repeated_uint64 = 24;
+  repeated bool repeated_bool = 25;
+  repeated double repeated_double = 26;
+  repeated float repeated_float = 27;
+  repeated string repeated_string = 28;
+  repeated bytes repeated_bytes = 29;
+  repeated TestEnum repeated_enum = 30;
+  repeated TestMessage repeated_msg = 31;
+
+  oneof my_oneof {
+    int32 oneof_int32 = 41;
+    int64 oneof_int64 = 42;
+    uint32 oneof_uint32 = 43;
+    uint64 oneof_uint64 = 44;
+    bool oneof_bool = 45;
+    double oneof_double = 46;
+    float oneof_float = 47;
+    string oneof_string = 48;
+    bytes oneof_bytes = 49;
+    TestEnum oneof_enum = 50;
+    TestMessage oneof_msg = 51;
+  }
+
+  map<int32, string> map_int32_string = 61;
+  map<int64, string> map_int64_string = 62;
+  map<uint32, string> map_uint32_string = 63;
+  map<uint64, string> map_uint64_string = 64;
+  map<bool, string> map_bool_string = 65;
+  map<string, string> map_string_string = 66;
+  map<string, TestMessage> map_string_msg = 67;
+  map<string, TestEnum> map_string_enum = 68;
+  map<string, int32> map_string_int32 = 69;
+  map<string, bool> map_string_bool = 70;
+
+  message NestedMessage {
+    int32 foo = 1;
+  }
+
+  NestedMessage nested_message = 80;
+}
+
+enum TestEnum {
+  Default = 0;
+  A = 1;
+  B = 2;
+  C = 3;
+}
diff --git a/ruby/tests/generated_code_test.rb b/ruby/tests/generated_code_test.rb
new file mode 100644
index 0000000..daef357
--- /dev/null
+++ b/ruby/tests/generated_code_test.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/ruby
+
+# generated_code.rb is in the same directory as this test.
+$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
+
+require 'generated_code'
+require 'test/unit'
+
+class GeneratedCodeTest < Test::Unit::TestCase
+  def test_generated_msg
+    # just test that we can instantiate the message. The purpose of this test
+    # is to ensure that the output of the code generator is valid Ruby and
+    # successfully creates message definitions and classes, not to test every
+    # aspect of the extension (basic.rb is for that).
+    m = A::B::C::TestMessage.new()
+  end
+end
diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb
new file mode 100644
index 0000000..25727b7
--- /dev/null
+++ b/ruby/tests/repeated_field_test.rb
@@ -0,0 +1,640 @@
+#!/usr/bin/ruby
+
+require 'google/protobuf'
+require 'test/unit'
+
+class RepeatedFieldTest < Test::Unit::TestCase
+
+  def test_acts_like_enumerator
+    m = TestMessage.new
+    (Enumerable.instance_methods - TestMessage.new.repeated_string.methods).each do |method_name|
+      assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
+    end
+  end
+
+  def test_acts_like_an_array
+    m = TestMessage.new
+    arr_methods = ([].methods - TestMessage.new.repeated_string.methods)
+    # jRuby additions to the Array class that we can ignore
+    arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
+      :iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
+      :nitems, :iter_for_reverse_each, :indexes]
+    arr_methods.each do |method_name|
+      assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
+    end
+  end
+
+  def test_first
+    m = TestMessage.new
+    repeated_field_names(TestMessage).each do |field_name|
+      assert_nil m.send(field_name).first
+    end
+    fill_test_msg(m)
+    assert_equal -10, m.repeated_int32.first
+    assert_equal -1_000_000, m.repeated_int64.first
+    assert_equal 10, m.repeated_uint32.first
+    assert_equal 1_000_000, m.repeated_uint64.first
+    assert_equal true, m.repeated_bool.first
+    assert_equal -1.01,  m.repeated_float.first.round(2)
+    assert_equal -1.0000000000001, m.repeated_double.first
+    assert_equal 'foo', m.repeated_string.first
+    assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.first
+    assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first
+    assert_equal :A, m.repeated_enum.first
+  end
+
+
+  def test_last
+    m = TestMessage.new
+    repeated_field_names(TestMessage).each do |field_name|
+      assert_nil m.send(field_name).first
+    end
+    fill_test_msg(m)
+    assert_equal -11, m.repeated_int32.last
+    assert_equal -1_000_001, m.repeated_int64.last
+    assert_equal 11, m.repeated_uint32.last
+    assert_equal 1_000_001, m.repeated_uint64.last
+    assert_equal false, m.repeated_bool.last
+    assert_equal -1.02, m.repeated_float.last.round(2)
+    assert_equal -1.0000000000002, m.repeated_double.last
+    assert_equal 'bar', m.repeated_string.last
+    assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last
+    assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last
+    assert_equal :B, m.repeated_enum.last
+  end
+
+
+  def test_pop
+    m = TestMessage.new
+    repeated_field_names(TestMessage).each do |field_name|
+      assert_nil m.send(field_name).pop
+    end
+    fill_test_msg(m)
+
+    assert_equal -11, m.repeated_int32.pop
+    assert_equal -10, m.repeated_int32.pop
+    assert_equal -1_000_001, m.repeated_int64.pop
+    assert_equal -1_000_000, m.repeated_int64.pop
+    assert_equal 11, m.repeated_uint32.pop
+    assert_equal 10, m.repeated_uint32.pop
+    assert_equal 1_000_001, m.repeated_uint64.pop
+    assert_equal 1_000_000, m.repeated_uint64.pop
+    assert_equal false, m.repeated_bool.pop
+    assert_equal true, m.repeated_bool.pop
+    assert_equal -1.02,  m.repeated_float.pop.round(2)
+    assert_equal -1.01,  m.repeated_float.pop.round(2)
+    assert_equal -1.0000000000002, m.repeated_double.pop
+    assert_equal -1.0000000000001, m.repeated_double.pop
+    assert_equal 'bar', m.repeated_string.pop
+    assert_equal 'foo', m.repeated_string.pop
+    assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.pop
+    assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.pop
+    assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.pop
+    assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.pop
+    assert_equal :B, m.repeated_enum.pop
+    assert_equal :A, m.repeated_enum.pop
+    repeated_field_names(TestMessage).each do |field_name|
+      assert_nil m.send(field_name).pop
+    end
+
+    fill_test_msg(m)
+    assert_equal ['bar', 'foo'], m.repeated_string.pop(2)
+    assert_nil m.repeated_string.pop
+  end
+
+
+  def test_each
+    m = TestMessage.new
+    5.times{|i| m.repeated_string << 'string' }
+    count = 0
+    m.repeated_string.each do |val|
+      assert_equal 'string', val
+      count += 1
+    end
+    assert_equal 5, count
+    result = m.repeated_string.each{|val| val + '_junk'}
+    assert_equal ['string'] * 5, result
+  end
+
+
+  def test_empty?
+    m = TestMessage.new
+    assert_equal true, m.repeated_string.empty?
+    m.repeated_string << 'foo'
+    assert_equal false, m.repeated_string.empty?
+    m.repeated_string << 'bar'
+    assert_equal false, m.repeated_string.empty?
+  end
+
+  def test_array_accessor
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[1]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[-2]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[20]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[1, 2]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[0..2]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[-1, 1]
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[10, 12]
+    end
+  end
+
+  def test_array_settor
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[1] = 'junk'
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[-2] = 'snappy'
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr[3] = ''
+    end
+    # slight deviation; we are strongly typed, and nil is not allowed
+    # for string types;
+    m.repeated_string[5] = 'spacious'
+    assert_equal ["foo", "snappy", "baz", "", "", "spacious"], m.repeated_string
+
+    #make sure it sests the default types for other fields besides strings
+    %w(repeated_int32 repeated_int64 repeated_uint32 repeated_uint64).each do |field_name|
+      m.send(field_name)[3] = 10
+      assert_equal [0,0,0,10], m.send(field_name)
+    end
+    m.repeated_float[3] = 10.1
+    #wonky mri float handling
+    assert_equal [0,0,0], m.repeated_float.to_a[0..2]
+    assert_equal 10.1, m.repeated_float[3].round(1)
+    m.repeated_double[3] = 10.1
+    assert_equal [0,0,0,10.1], m.repeated_double
+    m.repeated_bool[3] = true
+    assert_equal [false, false, false, true], m.repeated_bool
+    m.repeated_bytes[3] = "bar".encode!('ASCII-8BIT')
+    assert_equal ['', '', '', "bar".encode!('ASCII-8BIT')], m.repeated_bytes
+    m.repeated_msg[3] = TestMessage2.new(:foo => 1)
+    assert_equal [nil, nil, nil, TestMessage2.new(:foo => 1)], m.repeated_msg
+    m.repeated_enum[3] = :A
+    assert_equal [:Default, :Default, :Default, :A], m.repeated_enum
+
+    # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+    #   arr[20] = 'spacious'
+    # end
+    # TODO: accessor doesn't allow other ruby-like methods
+    # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+    #   arr[1, 2] = 'fizz'
+    # end
+    # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+    #   arr[0..2] = 'buzz'
+    # end
+  end
+
+  def test_push
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.push('fizz')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr << 'fizz'
+    end
+    #TODO: push should support multiple
+    # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+    #   arr.push('fizz', 'buzz')
+    # end
+  end
+
+  def test_clear
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.clear
+    end
+  end
+
+  def test_concat
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    m.repeated_string.concat(['fizz', 'buzz'])
+    assert_equal %w(foo bar baz fizz buzz), m.repeated_string
+    #TODO: concat should return the orig array
+    # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+    #   arr.concat(['fizz', 'buzz'])
+    # end
+  end
+
+  def test_equal
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    assert_equal reference_arr, m.repeated_string
+    reference_arr << 'fizz'
+    assert_not_equal reference_arr, m.repeated_string
+    m.repeated_string << 'fizz'
+    assert_equal reference_arr, m.repeated_string
+  end
+
+  def test_hash
+    # just a sanity check
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    assert m.repeated_string.hash.is_a?(Integer)
+    hash = m.repeated_string.hash
+    assert_equal hash, m.repeated_string.hash
+    m.repeated_string << 'j'
+    assert_not_equal hash, m.repeated_string.hash
+  end
+
+  def test_plus
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr + ['fizz', 'buzz']
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr += ['fizz', 'buzz']
+    end
+  end
+
+  def test_replace
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.replace(['fizz', 'buzz'])
+    end
+  end
+
+  def test_to_a
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.to_a
+    end
+  end
+
+  def test_to_ary
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.to_ary
+    end
+  end
+
+  # emulate Array behavior
+  ##########################
+
+  def test_collect!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.collect!{|x| x + "!" }
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.collect!.with_index{|x, i| x[0...i] }
+    end
+  end
+
+  def test_compact!
+    m = TestMessage.new
+    m.repeated_msg << TestMessage2.new(:foo => 1)
+    m.repeated_msg << nil
+    m.repeated_msg << TestMessage2.new(:foo => 2)
+    reference_arr = m.repeated_string.to_a
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.compact!
+    end
+  end
+
+  def test_delete
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.delete('bar')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.delete('nope')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.delete('nope'){'within'}
+    end
+  end
+
+  def test_delete_at
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.delete_at(2)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.delete_at(10)
+    end
+  end
+
+  def test_fill
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.fill("x")
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.fill("z", 2, 2)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.fill("y", 0..1)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.fill { |i| (i*i).to_s }
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.fill(-2) { |i| (i*i*i).to_s }
+    end
+  end
+
+  def test_flatten!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.flatten!
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.flatten!(1)
+    end
+  end
+
+  def test_insert
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.insert(2, 'fizz')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.insert(3, 'fizz', 'buzz', 'bazz')
+    end
+  end
+
+  def test_inspect
+    m = TestMessage.new
+    assert_equal '[]', m.repeated_string.inspect
+    m.repeated_string << 'foo'
+    assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
+    m.repeated_string << 'bar'
+    assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
+  end
+
+  def test_reverse!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.reverse!
+    end
+  end
+
+  def test_rotate!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.rotate!
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.rotate!(2)
+    end
+  end
+
+  def test_select!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.select! { |v| v =~ /[aeiou]/ }
+    end
+  end
+
+  def test_shift
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    # should return an element
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.shift
+    end
+    # should return an array
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.shift(2)
+    end
+    # should return nil
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.shift
+    end
+  end
+
+  def test_shuffle!
+    m = TestMessage.new
+    m.repeated_string += %w(foo bar baz)
+    orig_repeated_string = m.repeated_string.clone
+    result = m.repeated_string.shuffle!
+    assert_equal m.repeated_string, result
+    # NOTE: sometimes it doesn't change the order...
+    # assert_not_equal m.repeated_string.to_a, orig_repeated_string.to_a
+  end
+
+  def test_slice!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz bar fizz buzz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.slice!(2)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.slice!(1,2)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.slice!(0..1)
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.slice!(10)
+    end
+  end
+
+  def test_sort!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.sort!
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.sort! { |x,y| y <=> x }
+    end
+  end
+
+  def test_sort_by!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.sort_by!
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.sort_by!(&:hash)
+    end
+  end
+
+  def test_uniq!
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.uniq!
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.uniq!{|s| s[0] }
+    end
+  end
+
+  def test_unshift
+    m = TestMessage.new
+    reference_arr = %w(foo bar baz)
+    m.repeated_string += reference_arr.clone
+
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.unshift('1')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.unshift('a', 'b')
+    end
+    check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
+      arr.unshift('')
+    end
+  end
+
+
+  ##### HELPER METHODS
+
+  def check_self_modifying_method(repeated_field, ref_array)
+    expected_result = yield(ref_array)
+    actual_result = yield(repeated_field)
+    if expected_result.is_a?(Enumerator)
+      assert_equal expected_result.to_a, actual_result.to_a
+    else
+      assert_equal expected_result, actual_result
+    end
+    assert_equal ref_array, repeated_field
+  end
+
+
+  def repeated_field_names(klass)
+    klass.descriptor.find_all{|f| f.label == :repeated}.map(&:name)
+  end
+
+
+  def fill_test_msg(test_msg)
+    test_msg.repeated_int32  += [-10, -11]
+    test_msg.repeated_int64  += [-1_000_000, -1_000_001]
+    test_msg.repeated_uint32 += [10, 11]
+    test_msg.repeated_uint64 += [1_000_000, 1_000_001]
+    test_msg.repeated_bool   += [true, false]
+    test_msg.repeated_float  += [-1.01, -1.02]
+    test_msg.repeated_double += [-1.0000000000001, -1.0000000000002]
+    test_msg.repeated_string += %w(foo bar)
+    test_msg.repeated_bytes  += ["bar".encode!('ASCII-8BIT'), "foo".encode!('ASCII-8BIT')]
+    test_msg.repeated_msg    << TestMessage2.new(:foo => 1)
+    test_msg.repeated_msg    << TestMessage2.new(:foo => 2)
+    test_msg.repeated_enum   << :A
+    test_msg.repeated_enum   << :B
+  end
+
+
+  pool = Google::Protobuf::DescriptorPool.new
+  pool.build do
+
+    add_message "TestMessage" do
+      optional :optional_int32,  :int32,        1
+      optional :optional_int64,  :int64,        2
+      optional :optional_uint32, :uint32,       3
+      optional :optional_uint64, :uint64,       4
+      optional :optional_bool,   :bool,         5
+      optional :optional_float,  :float,        6
+      optional :optional_double, :double,       7
+      optional :optional_string, :string,       8
+      optional :optional_bytes,  :bytes,        9
+      optional :optional_msg,    :message,      10, "TestMessage2"
+      optional :optional_enum,   :enum,         11, "TestEnum"
+
+      repeated :repeated_int32,  :int32,        12
+      repeated :repeated_int64,  :int64,        13
+      repeated :repeated_uint32, :uint32,       14
+      repeated :repeated_uint64, :uint64,       15
+      repeated :repeated_bool,   :bool,         16
+      repeated :repeated_float,  :float,        17
+      repeated :repeated_double, :double,       18
+      repeated :repeated_string, :string,       19
+      repeated :repeated_bytes,  :bytes,        20
+      repeated :repeated_msg,    :message,      21, "TestMessage2"
+      repeated :repeated_enum,   :enum,         22, "TestEnum"
+    end
+    add_message "TestMessage2" do
+      optional :foo, :int32, 1
+    end
+
+    add_enum "TestEnum" do
+      value :Default, 0
+      value :A, 1
+      value :B, 2
+      value :C, 3
+    end
+  end
+
+  TestMessage = pool.lookup("TestMessage").msgclass
+  TestMessage2 = pool.lookup("TestMessage2").msgclass
+  TestEnum = pool.lookup("TestEnum").enummodule
+
+
+end
diff --git a/ruby/tests/stress.rb b/ruby/tests/stress.rb
new file mode 100644
index 0000000..082d5e2
--- /dev/null
+++ b/ruby/tests/stress.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/ruby
+
+require 'google/protobuf'
+require 'test/unit'
+
+module StressTest
+  pool = Google::Protobuf::DescriptorPool.new
+  pool.build do
+    add_message "TestMessage" do
+      optional :a,  :int32,        1
+      repeated :b,  :message,      2, "M"
+    end
+    add_message "M" do
+      optional :foo, :string, 1
+    end
+  end
+
+  TestMessage = pool.lookup("TestMessage").msgclass
+  M = pool.lookup("M").msgclass
+
+  class StressTest < Test::Unit::TestCase
+    def get_msg
+      TestMessage.new(:a => 1000,
+                      :b => [M.new(:foo => "hello"),
+                             M.new(:foo => "world")])
+    end
+    def test_stress
+      m = get_msg
+      data = TestMessage.encode(m)
+      100_000.times do
+        mnew = TestMessage.decode(data)
+        mnew = mnew.dup
+        assert_equal mnew.inspect, m.inspect
+        assert TestMessage.encode(mnew) == data
+      end
+    end
+  end
+end
diff --git a/ruby/travis-test.sh b/ruby/travis-test.sh
new file mode 100755
index 0000000..75db7d9
--- /dev/null
+++ b/ruby/travis-test.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# Exit on any error.
+set -e
+
+test_version() {
+  version=$1
+  if [ "$version" == "jruby" ] ; then
+    # No conformance tests yet -- JRuby is too broken to run them.
+    bash --login -c \
+      "rvm install $version && rvm use $version && \
+       which ruby && \
+       gem install bundler && bundle && \
+       rake test"
+  else
+    bash --login -c \
+      "rvm install $version && rvm use $version && \
+       which ruby && \
+       gem install bundler && bundle && \
+       rake test &&
+       cd ../conformance && make test_ruby"
+  fi
+}
+
+test_version $1
diff --git a/six.BUILD b/six.BUILD
new file mode 100644
index 0000000..fb0b360
--- /dev/null
+++ b/six.BUILD
@@ -0,0 +1,13 @@
+genrule(
+  name = "copy_six",
+  srcs = ["six-1.10.0/six.py"],
+  outs = ["six.py"],
+  cmd = "cp $< $(@)",
+)
+
+py_library(
+  name = "six",
+  srcs = ["six.py"],
+  srcs_version = "PY2AND3",
+  visibility = ["//visibility:public"],
+)
diff --git a/src/Makefile.am b/src/Makefile.am
index 7baabbd..8006550 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,17 +4,25 @@
 GZCHECKPROGRAMS = zcgzip zcgunzip
 GZHEADERS = google/protobuf/io/gzip_stream.h
 GZTESTS = google/protobuf/io/gzip_stream_unittest.sh
+ZLIB_DEF = -DHAVE_ZLIB=1
 else
 GZCHECKPROGRAMS =
 GZHEADERS =
 GZTESTS =
+ZLIB_DEF =
+endif
+
+if HAVE_PTHREAD
+PTHREAD_DEF = -DHAVE_PTHREAD=1
+else
+PTHREAD_DEF =
 endif
 
 if GCC
 # These are good warnings to turn on by default
-NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
+NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
 else
-NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS)
+NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF)
 endif
 
 AM_CXXFLAGS = $(NO_OPT_CXXFLAGS) $(PROTOBUF_OPT_FLAG)
@@ -24,7 +32,17 @@
 # If I say "dist_include_DATA", automake complains that $(includedir) is not
 # a "legitimate" directory for DATA.  Screw you, automake.
 protodir = $(includedir)
-nobase_dist_proto_DATA = google/protobuf/descriptor.proto \
+nobase_dist_proto_DATA = google/protobuf/descriptor.proto     \
+                         google/protobuf/any.proto            \
+                         google/protobuf/api.proto            \
+                         google/protobuf/duration.proto       \
+                         google/protobuf/empty.proto          \
+                         google/protobuf/field_mask.proto     \
+                         google/protobuf/source_context.proto \
+                         google/protobuf/struct.proto         \
+                         google/protobuf/timestamp.proto      \
+                         google/protobuf/type.proto           \
+                         google/protobuf/wrappers.proto       \
                          google/protobuf/compiler/plugin.proto
 
 # Not sure why these don't get cleaned automatically.
@@ -38,42 +56,83 @@
   Makefile.in
 
 nobase_include_HEADERS =                                        \
+  google/protobuf/stubs/atomic_sequence_num.h                   \
   google/protobuf/stubs/atomicops.h                             \
-  google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
+  google/protobuf/stubs/atomicops_internals_power.h             \
   google/protobuf/stubs/atomicops_internals_arm64_gcc.h         \
+  google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
   google/protobuf/stubs/atomicops_internals_arm_qnx.h           \
   google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
   google/protobuf/stubs/atomicops_internals_generic_gcc.h       \
   google/protobuf/stubs/atomicops_internals_macosx.h            \
   google/protobuf/stubs/atomicops_internals_mips_gcc.h          \
   google/protobuf/stubs/atomicops_internals_pnacl.h             \
+  google/protobuf/stubs/atomicops_internals_solaris.h           \
   google/protobuf/stubs/atomicops_internals_tsan.h              \
   google/protobuf/stubs/atomicops_internals_x86_gcc.h           \
   google/protobuf/stubs/atomicops_internals_x86_msvc.h          \
+  google/protobuf/stubs/callback.h                              \
+  google/protobuf/stubs/bytestream.h                            \
+  google/protobuf/stubs/casts.h                                 \
   google/protobuf/stubs/common.h                                \
-  google/protobuf/stubs/platform_macros.h                       \
+  google/protobuf/stubs/fastmem.h                               \
+  google/protobuf/stubs/hash.h                                  \
+  google/protobuf/stubs/logging.h                               \
+  google/protobuf/stubs/macros.h                                \
+  google/protobuf/stubs/mutex.h                                 \
   google/protobuf/stubs/once.h                                  \
+  google/protobuf/stubs/platform_macros.h                       \
+  google/protobuf/stubs/port.h                                  \
+  google/protobuf/stubs/scoped_ptr.h                            \
+  google/protobuf/stubs/shared_ptr.h                            \
+  google/protobuf/stubs/singleton.h                             \
+  google/protobuf/stubs/status.h                                \
   google/protobuf/stubs/stl_util.h                              \
+  google/protobuf/stubs/stringpiece.h                           \
   google/protobuf/stubs/template_util.h                         \
   google/protobuf/stubs/type_traits.h                           \
+  google/protobuf/any.pb.h                                      \
+  google/protobuf/api.pb.h                                      \
+  google/protobuf/any.h                                         \
+  google/protobuf/arena.h                                       \
+  google/protobuf/arenastring.h                                 \
+  google/protobuf/descriptor_database.h                         \
   google/protobuf/descriptor.h                                  \
   google/protobuf/descriptor.pb.h                               \
-  google/protobuf/descriptor_database.h                         \
+  google/protobuf/duration.pb.h                                 \
   google/protobuf/dynamic_message.h                             \
+  google/protobuf/empty.pb.h                                    \
   google/protobuf/extension_set.h                               \
+  google/protobuf/field_mask.pb.h                               \
   google/protobuf/generated_enum_reflection.h                   \
-  google/protobuf/generated_message_util.h                      \
+  google/protobuf/generated_enum_util.h                         \
   google/protobuf/generated_message_reflection.h                \
+  google/protobuf/generated_message_util.h                      \
+  google/protobuf/map_entry.h                                   \
+  google/protobuf/map_entry_lite.h                              \
+  google/protobuf/map_field.h                                   \
+  google/protobuf/map_field_inl.h                               \
+  google/protobuf/map_field_lite.h                              \
+  google/protobuf/map.h                                         \
+  google/protobuf/map_type_handler.h                            \
   google/protobuf/message.h                                     \
   google/protobuf/message_lite.h                                \
+  google/protobuf/metadata.h                                    \
+  google/protobuf/reflection.h                                  \
   google/protobuf/reflection_ops.h                              \
   google/protobuf/repeated_field.h                              \
+  google/protobuf/repeated_field_reflection.h                   \
   google/protobuf/service.h                                     \
+  google/protobuf/source_context.pb.h                           \
+  google/protobuf/struct.pb.h                                   \
   google/protobuf/text_format.h                                 \
+  google/protobuf/timestamp.pb.h                                \
+  google/protobuf/type.pb.h                                     \
   google/protobuf/unknown_field_set.h                           \
   google/protobuf/wire_format.h                                 \
   google/protobuf/wire_format_lite.h                            \
   google/protobuf/wire_format_lite_inl.h                        \
+  google/protobuf/wrappers.pb.h                                 \
   google/protobuf/io/coded_stream.h                             \
   $(GZHEADERS)                                                  \
   google/protobuf/io/printer.h                                  \
@@ -89,25 +148,57 @@
   google/protobuf/compiler/plugin.h                             \
   google/protobuf/compiler/plugin.pb.h                          \
   google/protobuf/compiler/cpp/cpp_generator.h                  \
+  google/protobuf/compiler/csharp/csharp_generator.h            \
+  google/protobuf/compiler/csharp/csharp_names.h                \
   google/protobuf/compiler/java/java_generator.h                \
-  google/protobuf/compiler/javamicro/javamicro_generator.h      \
+  google/protobuf/compiler/java/java_names.h                    \
   google/protobuf/compiler/javanano/javanano_generator.h        \
-  google/protobuf/compiler/python/python_generator.h
+  google/protobuf/compiler/js/js_generator.h                    \
+  google/protobuf/compiler/objectivec/objectivec_generator.h    \
+  google/protobuf/compiler/objectivec/objectivec_helpers.h      \
+  google/protobuf/compiler/python/python_generator.h            \
+  google/protobuf/compiler/ruby/ruby_generator.h                \
+  google/protobuf/util/type_resolver.h                          \
+  google/protobuf/util/field_comparator.h                       \
+  google/protobuf/util/field_mask_util.h                        \
+  google/protobuf/util/json_util.h                              \
+  google/protobuf/util/time_util.h                              \
+  google/protobuf/util/type_resolver_util.h                     \
+  google/protobuf/util/message_differencer.h
 
 lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
 
 libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_lite_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
+libprotobuf_lite_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
 libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/stubs/atomicops_internals_x86_gcc.cc         \
   google/protobuf/stubs/atomicops_internals_x86_msvc.cc        \
+  google/protobuf/stubs/bytestream.cc                          \
+  google/protobuf/stubs/bytestream.h                           \
   google/protobuf/stubs/common.cc                              \
-  google/protobuf/stubs/once.cc                                \
   google/protobuf/stubs/hash.h                                 \
+  google/protobuf/stubs/int128.cc                              \
+  google/protobuf/stubs/int128.h                               \
   google/protobuf/stubs/map_util.h                             \
+  google/protobuf/stubs/mathutil.h                             \
+  google/protobuf/stubs/once.cc                                \
   google/protobuf/stubs/shared_ptr.h                           \
+  google/protobuf/stubs/status.cc                              \
+  google/protobuf/stubs/status.h                               \
+  google/protobuf/stubs/status_macros.h                        \
+  google/protobuf/stubs/statusor.cc                            \
+  google/protobuf/stubs/statusor.h                             \
+  google/protobuf/stubs/stringpiece.cc                         \
+  google/protobuf/stubs/stringpiece.h                          \
   google/protobuf/stubs/stringprintf.cc                        \
   google/protobuf/stubs/stringprintf.h                         \
+  google/protobuf/stubs/structurally_valid.cc                  \
+  google/protobuf/stubs/strutil.cc                             \
+  google/protobuf/stubs/strutil.h                              \
+  google/protobuf/stubs/time.cc                                \
+  google/protobuf/stubs/time.h                                 \
+  google/protobuf/arena.cc                                     \
+  google/protobuf/arenastring.cc                               \
   google/protobuf/extension_set.cc                             \
   google/protobuf/generated_message_util.cc                    \
   google/protobuf/message_lite.cc                              \
@@ -119,36 +210,91 @@
   google/protobuf/io/zero_copy_stream_impl_lite.cc
 
 libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
+libprotobuf_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
 libprotobuf_la_SOURCES =                                       \
   $(libprotobuf_lite_la_SOURCES)                               \
-  google/protobuf/stubs/strutil.cc                             \
-  google/protobuf/stubs/strutil.h                              \
-  google/protobuf/stubs/substitute.cc                          \
-  google/protobuf/stubs/substitute.h                           \
-  google/protobuf/stubs/structurally_valid.cc                  \
+  google/protobuf/any.pb.cc                                    \
+  google/protobuf/api.pb.cc                                    \
+  google/protobuf/stubs/mathlimits.cc                          \
+  google/protobuf/stubs/mathlimits.h                           \
+  google/protobuf/any.cc                                       \
   google/protobuf/descriptor.cc                                \
-  google/protobuf/descriptor.pb.cc                             \
   google/protobuf/descriptor_database.cc                       \
+  google/protobuf/descriptor.pb.cc                             \
+  google/protobuf/duration.pb.cc                               \
   google/protobuf/dynamic_message.cc                           \
+  google/protobuf/empty.pb.cc                                  \
   google/protobuf/extension_set_heavy.cc                       \
+  google/protobuf/field_mask.pb.cc                             \
   google/protobuf/generated_message_reflection.cc              \
+  google/protobuf/map_field.cc                                 \
   google/protobuf/message.cc                                   \
+  google/protobuf/reflection_internal.h                        \
   google/protobuf/reflection_ops.cc                            \
   google/protobuf/service.cc                                   \
+  google/protobuf/source_context.pb.cc                         \
+  google/protobuf/struct.pb.cc                                 \
+  google/protobuf/stubs/substitute.cc                          \
+  google/protobuf/stubs/substitute.h                           \
   google/protobuf/text_format.cc                               \
+  google/protobuf/timestamp.pb.cc                              \
+  google/protobuf/type.pb.cc                                   \
   google/protobuf/unknown_field_set.cc                         \
   google/protobuf/wire_format.cc                               \
+  google/protobuf/wrappers.pb.cc                               \
   google/protobuf/io/gzip_stream.cc                            \
   google/protobuf/io/printer.cc                                \
   google/protobuf/io/strtod.cc                                 \
   google/protobuf/io/tokenizer.cc                              \
   google/protobuf/io/zero_copy_stream_impl.cc                  \
   google/protobuf/compiler/importer.cc                         \
-  google/protobuf/compiler/parser.cc
+  google/protobuf/compiler/parser.cc                           \
+  google/protobuf/util/field_comparator.cc                     \
+  google/protobuf/util/field_mask_util.cc                      \
+  google/protobuf/util/internal/constants.h                    \
+  google/protobuf/util/internal/datapiece.cc                   \
+  google/protobuf/util/internal/datapiece.h                    \
+  google/protobuf/util/internal/default_value_objectwriter.cc  \
+  google/protobuf/util/internal/default_value_objectwriter.h   \
+  google/protobuf/util/internal/error_listener.cc              \
+  google/protobuf/util/internal/error_listener.h               \
+  google/protobuf/util/internal/expecting_objectwriter.h       \
+  google/protobuf/util/internal/field_mask_utility.cc          \
+  google/protobuf/util/internal/field_mask_utility.h           \
+  google/protobuf/util/internal/json_escaping.cc               \
+  google/protobuf/util/internal/json_escaping.h                \
+  google/protobuf/util/internal/json_objectwriter.cc           \
+  google/protobuf/util/internal/json_objectwriter.h            \
+  google/protobuf/util/internal/json_stream_parser.cc          \
+  google/protobuf/util/internal/json_stream_parser.h           \
+  google/protobuf/util/internal/location_tracker.h             \
+  google/protobuf/util/internal/mock_error_listener.h          \
+  google/protobuf/util/internal/object_location_tracker.h      \
+  google/protobuf/util/internal/object_source.h                \
+  google/protobuf/util/internal/object_writer.cc               \
+  google/protobuf/util/internal/object_writer.h                \
+  google/protobuf/util/internal/protostream_objectsource.cc    \
+  google/protobuf/util/internal/protostream_objectsource.h     \
+  google/protobuf/util/internal/protostream_objectwriter.cc    \
+  google/protobuf/util/internal/protostream_objectwriter.h     \
+  google/protobuf/util/internal/proto_writer.cc                \
+  google/protobuf/util/internal/proto_writer.h                 \
+  google/protobuf/util/internal/structured_objectwriter.h      \
+  google/protobuf/util/internal/type_info.cc                   \
+  google/protobuf/util/internal/type_info.h                    \
+  google/protobuf/util/internal/type_info_test_helper.cc       \
+  google/protobuf/util/internal/type_info_test_helper.h        \
+  google/protobuf/util/internal/utility.cc                     \
+  google/protobuf/util/internal/utility.h                      \
+  google/protobuf/util/json_util.cc                            \
+  google/protobuf/util/message_differencer.cc                  \
+  google/protobuf/util/time_util.cc                            \
+  google/protobuf/util/type_resolver_util.cc
+
+nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES)
 
 libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
-libprotoc_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
+libprotoc_la_LDFLAGS = -version-info 10:0:0 -export-dynamic -no-undefined
 libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/code_generator.cc                   \
   google/protobuf/compiler/command_line_interface.cc           \
@@ -171,6 +317,8 @@
   google/protobuf/compiler/cpp/cpp_generator.cc                \
   google/protobuf/compiler/cpp/cpp_helpers.cc                  \
   google/protobuf/compiler/cpp/cpp_helpers.h                   \
+  google/protobuf/compiler/cpp/cpp_map_field.cc                \
+  google/protobuf/compiler/cpp/cpp_map_field.h                 \
   google/protobuf/compiler/cpp/cpp_message.cc                  \
   google/protobuf/compiler/cpp/cpp_message.h                   \
   google/protobuf/compiler/cpp/cpp_message_field.cc            \
@@ -185,11 +333,17 @@
   google/protobuf/compiler/java/java_context.cc                \
   google/protobuf/compiler/java/java_context.h                 \
   google/protobuf/compiler/java/java_enum.cc                   \
-  google/protobuf/compiler/java/java_enum.h                    \
+  google/protobuf/compiler/java/java_enum_lite.cc              \
   google/protobuf/compiler/java/java_enum_field.cc             \
   google/protobuf/compiler/java/java_enum_field.h              \
+  google/protobuf/compiler/java/java_enum_field_lite.cc        \
+  google/protobuf/compiler/java/java_enum_field_lite.h         \
+  google/protobuf/compiler/java/java_enum.h                    \
+  google/protobuf/compiler/java/java_enum_lite.h               \
   google/protobuf/compiler/java/java_extension.cc              \
   google/protobuf/compiler/java/java_extension.h               \
+  google/protobuf/compiler/java/java_extension_lite.cc         \
+  google/protobuf/compiler/java/java_extension_lite.h          \
   google/protobuf/compiler/java/java_field.cc                  \
   google/protobuf/compiler/java/java_field.h                   \
   google/protobuf/compiler/java/java_file.cc                   \
@@ -201,59 +355,121 @@
   google/protobuf/compiler/java/java_helpers.h                 \
   google/protobuf/compiler/java/java_lazy_message_field.cc     \
   google/protobuf/compiler/java/java_lazy_message_field.h      \
+  google/protobuf/compiler/java/java_lazy_message_field_lite.cc\
+  google/protobuf/compiler/java/java_lazy_message_field_lite.h \
+  google/protobuf/compiler/java/java_map_field.cc              \
+  google/protobuf/compiler/java/java_map_field.h               \
+  google/protobuf/compiler/java/java_map_field_lite.cc         \
+  google/protobuf/compiler/java/java_map_field_lite.h          \
   google/protobuf/compiler/java/java_message.cc                \
-  google/protobuf/compiler/java/java_message.h                 \
+  google/protobuf/compiler/java/java_message_lite.cc           \
+  google/protobuf/compiler/java/java_message_builder.cc        \
+  google/protobuf/compiler/java/java_message_builder_lite.cc   \
   google/protobuf/compiler/java/java_message_field.cc          \
   google/protobuf/compiler/java/java_message_field.h           \
+  google/protobuf/compiler/java/java_message_field_lite.cc     \
+  google/protobuf/compiler/java/java_message_field_lite.h      \
+  google/protobuf/compiler/java/java_message.h                 \
+  google/protobuf/compiler/java/java_message_lite.h            \
+  google/protobuf/compiler/java/java_message_builder.h         \
+  google/protobuf/compiler/java/java_message_builder_lite.h    \
   google/protobuf/compiler/java/java_name_resolver.cc          \
   google/protobuf/compiler/java/java_name_resolver.h           \
   google/protobuf/compiler/java/java_primitive_field.cc        \
   google/protobuf/compiler/java/java_primitive_field.h         \
+  google/protobuf/compiler/java/java_primitive_field_lite.cc   \
+  google/protobuf/compiler/java/java_primitive_field_lite.h    \
   google/protobuf/compiler/java/java_shared_code_generator.cc  \
   google/protobuf/compiler/java/java_shared_code_generator.h   \
   google/protobuf/compiler/java/java_service.cc                \
   google/protobuf/compiler/java/java_service.h                 \
   google/protobuf/compiler/java/java_string_field.cc           \
   google/protobuf/compiler/java/java_string_field.h            \
+  google/protobuf/compiler/java/java_string_field_lite.cc      \
+  google/protobuf/compiler/java/java_string_field_lite.h       \
   google/protobuf/compiler/java/java_doc_comment.cc            \
   google/protobuf/compiler/java/java_doc_comment.h             \
-  google/protobuf/compiler/javamicro/javamicro_enum.cc         \
-  google/protobuf/compiler/javamicro/javamicro_enum.h          \
-  google/protobuf/compiler/javamicro/javamicro_enum_field.cc   \
-  google/protobuf/compiler/javamicro/javamicro_enum_field.h    \
-  google/protobuf/compiler/javamicro/javamicro_field.cc        \
-  google/protobuf/compiler/javamicro/javamicro_field.h         \
-  google/protobuf/compiler/javamicro/javamicro_file.cc         \
-  google/protobuf/compiler/javamicro/javamicro_file.h          \
-  google/protobuf/compiler/javamicro/javamicro_generator.cc    \
-  google/protobuf/compiler/javamicro/javamicro_helpers.cc      \
-  google/protobuf/compiler/javamicro/javamicro_helpers.h       \
-  google/protobuf/compiler/javamicro/javamicro_message.cc      \
-  google/protobuf/compiler/javamicro/javamicro_message.h       \
-  google/protobuf/compiler/javamicro/javamicro_message_field.cc\
-  google/protobuf/compiler/javamicro/javamicro_message_field.h \
-  google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\
-  google/protobuf/compiler/javamicro/javamicro_primitive_field.h\
-  google/protobuf/compiler/javanano/javanano_enum.cc         \
-  google/protobuf/compiler/javanano/javanano_enum.h          \
-  google/protobuf/compiler/javanano/javanano_enum_field.cc   \
-  google/protobuf/compiler/javanano/javanano_enum_field.h    \
-  google/protobuf/compiler/javanano/javanano_extension.cc    \
-  google/protobuf/compiler/javanano/javanano_extension.h     \
-  google/protobuf/compiler/javanano/javanano_field.cc        \
-  google/protobuf/compiler/javanano/javanano_field.h         \
-  google/protobuf/compiler/javanano/javanano_file.cc         \
-  google/protobuf/compiler/javanano/javanano_file.h          \
-  google/protobuf/compiler/javanano/javanano_generator.cc    \
-  google/protobuf/compiler/javanano/javanano_helpers.cc      \
-  google/protobuf/compiler/javanano/javanano_helpers.h       \
-  google/protobuf/compiler/javanano/javanano_message.cc      \
-  google/protobuf/compiler/javanano/javanano_message.h       \
-  google/protobuf/compiler/javanano/javanano_message_field.cc\
-  google/protobuf/compiler/javanano/javanano_message_field.h \
-  google/protobuf/compiler/javanano/javanano_primitive_field.cc\
-  google/protobuf/compiler/javanano/javanano_primitive_field.h\
-  google/protobuf/compiler/python/python_generator.cc
+  google/protobuf/compiler/js/js_generator.cc                  \
+  google/protobuf/compiler/javanano/javanano_enum.cc           \
+  google/protobuf/compiler/javanano/javanano_enum.h            \
+  google/protobuf/compiler/javanano/javanano_enum_field.cc     \
+  google/protobuf/compiler/javanano/javanano_enum_field.h      \
+  google/protobuf/compiler/javanano/javanano_extension.cc      \
+  google/protobuf/compiler/javanano/javanano_extension.h       \
+  google/protobuf/compiler/javanano/javanano_field.cc          \
+  google/protobuf/compiler/javanano/javanano_field.h           \
+  google/protobuf/compiler/javanano/javanano_file.cc           \
+  google/protobuf/compiler/javanano/javanano_file.h            \
+  google/protobuf/compiler/javanano/javanano_generator.cc      \
+  google/protobuf/compiler/javanano/javanano_generator.h       \
+  google/protobuf/compiler/javanano/javanano_helpers.cc        \
+  google/protobuf/compiler/javanano/javanano_helpers.h         \
+  google/protobuf/compiler/javanano/javanano_map_field.cc      \
+  google/protobuf/compiler/javanano/javanano_map_field.h       \
+  google/protobuf/compiler/javanano/javanano_message.cc        \
+  google/protobuf/compiler/javanano/javanano_message.h         \
+  google/protobuf/compiler/javanano/javanano_message_field.cc  \
+  google/protobuf/compiler/javanano/javanano_message_field.h   \
+  google/protobuf/compiler/javanano/javanano_params.h          \
+  google/protobuf/compiler/javanano/javanano_primitive_field.cc \
+  google/protobuf/compiler/javanano/javanano_primitive_field.h \
+  google/protobuf/compiler/objectivec/objectivec_enum.cc       \
+  google/protobuf/compiler/objectivec/objectivec_enum.h        \
+  google/protobuf/compiler/objectivec/objectivec_enum_field.cc \
+  google/protobuf/compiler/objectivec/objectivec_enum_field.h  \
+  google/protobuf/compiler/objectivec/objectivec_extension.cc  \
+  google/protobuf/compiler/objectivec/objectivec_extension.h   \
+  google/protobuf/compiler/objectivec/objectivec_field.cc      \
+  google/protobuf/compiler/objectivec/objectivec_field.h       \
+  google/protobuf/compiler/objectivec/objectivec_file.cc       \
+  google/protobuf/compiler/objectivec/objectivec_file.h        \
+  google/protobuf/compiler/objectivec/objectivec_generator.cc  \
+  google/protobuf/compiler/objectivec/objectivec_helpers.cc    \
+  google/protobuf/compiler/objectivec/objectivec_helpers.h     \
+  google/protobuf/compiler/objectivec/objectivec_map_field.cc  \
+  google/protobuf/compiler/objectivec/objectivec_map_field.h   \
+  google/protobuf/compiler/objectivec/objectivec_message.cc    \
+  google/protobuf/compiler/objectivec/objectivec_message.h     \
+  google/protobuf/compiler/objectivec/objectivec_message_field.cc \
+  google/protobuf/compiler/objectivec/objectivec_message_field.h \
+  google/protobuf/compiler/objectivec/objectivec_oneof.cc      \
+  google/protobuf/compiler/objectivec/objectivec_oneof.h       \
+  google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \
+  google/protobuf/compiler/objectivec/objectivec_primitive_field.h \
+  google/protobuf/compiler/python/python_generator.cc          \
+  google/protobuf/compiler/ruby/ruby_generator.cc              \
+  google/protobuf/compiler/csharp/csharp_doc_comment.cc        \
+  google/protobuf/compiler/csharp/csharp_doc_comment.h         \
+  google/protobuf/compiler/csharp/csharp_enum.cc               \
+  google/protobuf/compiler/csharp/csharp_enum.h                \
+  google/protobuf/compiler/csharp/csharp_enum_field.cc         \
+  google/protobuf/compiler/csharp/csharp_enum_field.h          \
+  google/protobuf/compiler/csharp/csharp_field_base.cc         \
+  google/protobuf/compiler/csharp/csharp_field_base.h          \
+  google/protobuf/compiler/csharp/csharp_generator.cc          \
+  google/protobuf/compiler/csharp/csharp_helpers.cc            \
+  google/protobuf/compiler/csharp/csharp_helpers.h             \
+  google/protobuf/compiler/csharp/csharp_map_field.cc          \
+  google/protobuf/compiler/csharp/csharp_map_field.h           \
+  google/protobuf/compiler/csharp/csharp_message.cc            \
+  google/protobuf/compiler/csharp/csharp_message.h             \
+  google/protobuf/compiler/csharp/csharp_message_field.cc      \
+  google/protobuf/compiler/csharp/csharp_message_field.h       \
+  google/protobuf/compiler/csharp/csharp_options.h             \
+  google/protobuf/compiler/csharp/csharp_primitive_field.cc    \
+  google/protobuf/compiler/csharp/csharp_primitive_field.h     \
+  google/protobuf/compiler/csharp/csharp_reflection_class.cc     \
+  google/protobuf/compiler/csharp/csharp_reflection_class.h      \
+  google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \
+  google/protobuf/compiler/csharp/csharp_repeated_enum_field.h \
+  google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \
+  google/protobuf/compiler/csharp/csharp_repeated_message_field.h \
+  google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc \
+  google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h \
+  google/protobuf/compiler/csharp/csharp_source_generator_base.cc \
+  google/protobuf/compiler/csharp/csharp_source_generator_base.h \
+  google/protobuf/compiler/csharp/csharp_wrapper_field.cc      \
+  google/protobuf/compiler/csharp/csharp_wrapper_field.h
 
 bin_PROGRAMS = protoc
 protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
@@ -261,21 +477,51 @@
 
 # Tests ==============================================================
 
-protoc_inputs =                                                \
-  google/protobuf/unittest.proto                               \
-  google/protobuf/unittest_empty.proto                         \
-  google/protobuf/unittest_import.proto                        \
-  google/protobuf/unittest_import_public.proto                 \
-  google/protobuf/unittest_mset.proto                          \
-  google/protobuf/unittest_optimize_for.proto                  \
-  google/protobuf/unittest_embed_optimize_for.proto            \
-  google/protobuf/unittest_custom_options.proto                \
-  google/protobuf/unittest_lite.proto                          \
-  google/protobuf/unittest_import_lite.proto                   \
-  google/protobuf/unittest_import_public_lite.proto            \
-  google/protobuf/unittest_lite_imports_nonlite.proto          \
-  google/protobuf/unittest_no_generic_services.proto           \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+protoc_inputs =                                                   \
+  google/protobuf/any_test.proto                                  \
+  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto     \
+  google/protobuf/map_lite_unittest.proto                         \
+  google/protobuf/map_proto2_unittest.proto                       \
+  google/protobuf/map_unittest.proto                              \
+  google/protobuf/unittest_arena.proto                            \
+  google/protobuf/unittest_custom_options.proto                   \
+  google/protobuf/unittest_drop_unknown_fields.proto              \
+  google/protobuf/unittest_embed_optimize_for.proto               \
+  google/protobuf/unittest_empty.proto                            \
+  google/protobuf/unittest_enormous_descriptor.proto              \
+  google/protobuf/unittest_import_lite.proto                      \
+  google/protobuf/unittest_import.proto                           \
+  google/protobuf/unittest_import_public_lite.proto               \
+  google/protobuf/unittest_import_public.proto                    \
+  google/protobuf/unittest_lite_imports_nonlite.proto             \
+  google/protobuf/unittest_lite.proto                             \
+  google/protobuf/unittest_mset.proto                             \
+  google/protobuf/unittest_mset_wire_format.proto                 \
+  google/protobuf/unittest_no_arena_lite.proto                    \
+  google/protobuf/unittest_no_arena_import.proto                  \
+  google/protobuf/unittest_no_arena.proto                         \
+  google/protobuf/unittest_no_field_presence.proto                \
+  google/protobuf/unittest_no_generic_services.proto              \
+  google/protobuf/unittest_optimize_for.proto                     \
+  google/protobuf/unittest_preserve_unknown_enum2.proto           \
+  google/protobuf/unittest_preserve_unknown_enum.proto            \
+  google/protobuf/unittest.proto                                  \
+  google/protobuf/unittest_proto3_arena.proto                     \
+  google/protobuf/unittest_proto3_arena_lite.proto                     \
+  google/protobuf/unittest_proto3_lite.proto                     \
+  google/protobuf/unittest_well_known_types.proto                 \
+  google/protobuf/util/internal/testdata/anys.proto               \
+  google/protobuf/util/internal/testdata/books.proto              \
+  google/protobuf/util/internal/testdata/default_value.proto      \
+  google/protobuf/util/internal/testdata/default_value_test.proto \
+  google/protobuf/util/internal/testdata/field_mask.proto         \
+  google/protobuf/util/internal/testdata/maps.proto               \
+  google/protobuf/util/internal/testdata/oneofs.proto             \
+  google/protobuf/util/internal/testdata/struct.proto             \
+  google/protobuf/util/internal/testdata/timestamp_duration.proto \
+  google/protobuf/util/json_format_proto3.proto                   \
+  google/protobuf/util/message_differencer_unittest.proto         \
+  google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
 
 EXTRA_DIST =                                                   \
   $(protoc_inputs)                                             \
@@ -284,8 +530,10 @@
   google/protobuf/io/gzip_stream_unittest.sh                   \
   google/protobuf/testdata/golden_message                      \
   google/protobuf/testdata/golden_message_oneof_implemented    \
+  google/protobuf/testdata/golden_message_proto3               \
   google/protobuf/testdata/golden_packed_fields_message        \
   google/protobuf/testdata/bad_utf8_string                     \
+  google/protobuf/testdata/map_test_data.txt                   \
   google/protobuf/testdata/text_format_unittest_data.txt       \
   google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt  \
   google/protobuf/testdata/text_format_unittest_data_pointy.txt             \
@@ -294,42 +542,103 @@
   google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt  \
   google/protobuf/package_info.h                               \
   google/protobuf/io/package_info.h                            \
+  google/protobuf/compiler/ruby/ruby_generated_code.proto      \
+  google/protobuf/compiler/ruby/ruby_generated_code.rb         \
   google/protobuf/compiler/package_info.h                      \
-  google/protobuf/compiler/zip_output_unittest.sh              \
-  google/protobuf/unittest_enormous_descriptor.proto
+  google/protobuf/compiler/zip_output_unittest.sh
 
 protoc_lite_outputs =                                          \
+  google/protobuf/map_lite_unittest.pb.cc                      \
+  google/protobuf/map_lite_unittest.pb.h                       \
   google/protobuf/unittest_lite.pb.cc                          \
   google/protobuf/unittest_lite.pb.h                           \
+  google/protobuf/unittest_no_arena_lite.pb.cc                 \
+  google/protobuf/unittest_no_arena_lite.pb.h                  \
   google/protobuf/unittest_import_lite.pb.cc                   \
   google/protobuf/unittest_import_lite.pb.h                    \
   google/protobuf/unittest_import_public_lite.pb.cc            \
   google/protobuf/unittest_import_public_lite.pb.h
 
-protoc_outputs =                                               \
-  $(protoc_lite_outputs)                                       \
-  google/protobuf/unittest.pb.cc                               \
-  google/protobuf/unittest.pb.h                                \
-  google/protobuf/unittest_empty.pb.cc                         \
-  google/protobuf/unittest_empty.pb.h                          \
-  google/protobuf/unittest_import.pb.cc                        \
-  google/protobuf/unittest_import.pb.h                         \
-  google/protobuf/unittest_import_public.pb.cc                 \
-  google/protobuf/unittest_import_public.pb.h                  \
-  google/protobuf/unittest_mset.pb.cc                          \
-  google/protobuf/unittest_mset.pb.h                           \
-  google/protobuf/unittest_optimize_for.pb.cc                  \
-  google/protobuf/unittest_optimize_for.pb.h                   \
-  google/protobuf/unittest_embed_optimize_for.pb.cc            \
-  google/protobuf/unittest_embed_optimize_for.pb.h             \
-  google/protobuf/unittest_custom_options.pb.cc                \
-  google/protobuf/unittest_custom_options.pb.h                 \
-  google/protobuf/unittest_lite_imports_nonlite.pb.cc          \
-  google/protobuf/unittest_lite_imports_nonlite.pb.h           \
-  google/protobuf/unittest_no_generic_services.pb.cc           \
-  google/protobuf/unittest_no_generic_services.pb.h            \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc  \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
+protoc_outputs =                                                  \
+  $(protoc_lite_outputs)                                          \
+  google/protobuf/any_test.pb.cc                                  \
+  google/protobuf/any_test.pb.h                                   \
+  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc     \
+  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h      \
+  google/protobuf/compiler/cpp/cpp_test_large_enum_value.pb.cc    \
+  google/protobuf/compiler/cpp/cpp_test_large_enum_value.pb.h     \
+  google/protobuf/map_proto2_unittest.pb.cc                       \
+  google/protobuf/map_proto2_unittest.pb.h                        \
+  google/protobuf/map_unittest.pb.cc                              \
+  google/protobuf/map_unittest.pb.h                               \
+  google/protobuf/unittest_arena.pb.cc                            \
+  google/protobuf/unittest_arena.pb.h                             \
+  google/protobuf/unittest_custom_options.pb.cc                   \
+  google/protobuf/unittest_custom_options.pb.h                    \
+  google/protobuf/unittest_drop_unknown_fields.pb.cc              \
+  google/protobuf/unittest_drop_unknown_fields.pb.h               \
+  google/protobuf/unittest_embed_optimize_for.pb.cc               \
+  google/protobuf/unittest_embed_optimize_for.pb.h                \
+  google/protobuf/unittest_empty.pb.cc                            \
+  google/protobuf/unittest_empty.pb.h                             \
+  google/protobuf/unittest_enormous_descriptor.pb.cc              \
+  google/protobuf/unittest_enormous_descriptor.pb.h               \
+  google/protobuf/unittest_import.pb.cc                           \
+  google/protobuf/unittest_import.pb.h                            \
+  google/protobuf/unittest_import_public.pb.cc                    \
+  google/protobuf/unittest_import_public.pb.h                     \
+  google/protobuf/unittest_lite_imports_nonlite.pb.cc             \
+  google/protobuf/unittest_lite_imports_nonlite.pb.h              \
+  google/protobuf/unittest_mset.pb.cc                             \
+  google/protobuf/unittest_mset.pb.h                              \
+  google/protobuf/unittest_mset_wire_format.pb.cc                 \
+  google/protobuf/unittest_mset_wire_format.pb.h                  \
+  google/protobuf/unittest_no_arena_import.pb.cc                  \
+  google/protobuf/unittest_no_arena_import.pb.h                   \
+  google/protobuf/unittest_no_arena.pb.cc                         \
+  google/protobuf/unittest_no_arena.pb.h                          \
+  google/protobuf/unittest_no_field_presence.pb.cc                \
+  google/protobuf/unittest_no_field_presence.pb.h                 \
+  google/protobuf/unittest_no_generic_services.pb.cc              \
+  google/protobuf/unittest_no_generic_services.pb.h               \
+  google/protobuf/unittest_optimize_for.pb.cc                     \
+  google/protobuf/unittest_optimize_for.pb.h                      \
+  google/protobuf/unittest.pb.cc                                  \
+  google/protobuf/unittest.pb.h                                   \
+  google/protobuf/unittest_preserve_unknown_enum2.pb.cc           \
+  google/protobuf/unittest_preserve_unknown_enum2.pb.h            \
+  google/protobuf/unittest_preserve_unknown_enum.pb.cc            \
+  google/protobuf/unittest_preserve_unknown_enum.pb.h             \
+  google/protobuf/unittest_proto3_arena.pb.cc                     \
+  google/protobuf/unittest_proto3_arena.pb.h                      \
+  google/protobuf/unittest_proto3_arena_lite.pb.cc                     \
+  google/protobuf/unittest_proto3_arena_lite.pb.h                      \
+  google/protobuf/unittest_proto3_lite.pb.cc                     \
+  google/protobuf/unittest_proto3_lite.pb.h                      \
+  google/protobuf/unittest_well_known_types.pb.cc                 \
+  google/protobuf/unittest_well_known_types.pb.h                  \
+  google/protobuf/util/internal/testdata/anys.pb.cc               \
+  google/protobuf/util/internal/testdata/anys.pb.h                \
+  google/protobuf/util/internal/testdata/books.pb.cc              \
+  google/protobuf/util/internal/testdata/books.pb.h               \
+  google/protobuf/util/internal/testdata/default_value.pb.cc      \
+  google/protobuf/util/internal/testdata/default_value.pb.h       \
+  google/protobuf/util/internal/testdata/default_value_test.pb.cc \
+  google/protobuf/util/internal/testdata/default_value_test.pb.h  \
+  google/protobuf/util/internal/testdata/field_mask.pb.cc         \
+  google/protobuf/util/internal/testdata/field_mask.pb.h          \
+  google/protobuf/util/internal/testdata/maps.pb.cc               \
+  google/protobuf/util/internal/testdata/maps.pb.h                \
+  google/protobuf/util/internal/testdata/oneofs.pb.cc             \
+  google/protobuf/util/internal/testdata/oneofs.pb.h              \
+  google/protobuf/util/internal/testdata/struct.pb.cc             \
+  google/protobuf/util/internal/testdata/struct.pb.h              \
+  google/protobuf/util/internal/testdata/timestamp_duration.pb.cc \
+  google/protobuf/util/internal/testdata/timestamp_duration.pb.h  \
+  google/protobuf/util/json_format_proto3.pb.cc                   \
+  google/protobuf/util/json_format_proto3.pb.h                    \
+  google/protobuf/util/message_differencer_unittest.pb.cc         \
+  google/protobuf/util/message_differencer_unittest.pb.h
 
 BUILT_SOURCES = $(protoc_outputs)
 
@@ -353,6 +662,11 @@
 $(protoc_outputs): unittest_proto_middleman
 
 COMMON_TEST_SOURCES =                                          \
+  google/protobuf/arena_test_util.cc                           \
+  google/protobuf/arena_test_util.h                            \
+  google/protobuf/map_test_util.cc                             \
+  google/protobuf/map_test_util.h                              \
+  google/protobuf/map_test_util_impl.h                         \
   google/protobuf/test_util.cc                                 \
   google/protobuf/test_util.h                                  \
   google/protobuf/testing/googletest.cc                        \
@@ -361,35 +675,55 @@
   google/protobuf/testing/file.h
 
 check_PROGRAMS = protoc protobuf-test protobuf-lazy-descriptor-test \
-                 protobuf-lite-test test_plugin $(GZCHECKPROGRAMS)
+                 protobuf-lite-test test_plugin protobuf-lite-arena-test \
+                 $(GZCHECKPROGRAMS)
 protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
-                      $(top_builddir)/gtest/lib/libgtest.la       \
-                      $(top_builddir)/gtest/lib/libgtest_main.la
-protobuf_test_CPPFLAGS = -I$(top_srcdir)/gtest/include         \
-                         -I$(top_builddir)/gtest/include
+                      ../gmock/gtest/lib/libgtest.la              \
+                      ../gmock/lib/libgmock.la                    \
+                      ../gmock/lib/libgmock_main.la
+protobuf_test_CPPFLAGS = -I$(srcdir)/../gmock/gtest/include \
+                         -I$(srcdir)/../gmock/include
 # Disable optimization for tests unless the user explicitly asked for it,
 # since test_util.cc takes forever to compile with optimization (with GCC).
 # See configure.ac for more info.
 protobuf_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_test_SOURCES =                                        \
+  google/protobuf/stubs/bytestream_unittest.cc                 \
   google/protobuf/stubs/common_unittest.cc                     \
+  google/protobuf/stubs/int128_unittest.cc                     \
   google/protobuf/stubs/once_unittest.cc                       \
-  google/protobuf/stubs/strutil_unittest.cc                    \
-  google/protobuf/stubs/structurally_valid_unittest.cc         \
+  google/protobuf/stubs/statusor_test.cc                       \
+  google/protobuf/stubs/status_test.cc                         \
+  google/protobuf/stubs/stringpiece_unittest.cc                \
   google/protobuf/stubs/stringprintf_unittest.cc               \
+  google/protobuf/stubs/structurally_valid_unittest.cc         \
+  google/protobuf/stubs/strutil_unittest.cc                    \
   google/protobuf/stubs/template_util_unittest.cc              \
+  google/protobuf/stubs/time_test.cc                           \
   google/protobuf/stubs/type_traits_unittest.cc                \
+  google/protobuf/any_test.cc                                  \
+  google/protobuf/arenastring_unittest.cc                      \
+  google/protobuf/arena_unittest.cc                            \
   google/protobuf/descriptor_database_unittest.cc              \
   google/protobuf/descriptor_unittest.cc                       \
+  google/protobuf/drop_unknown_fields_test.cc                  \
   google/protobuf/dynamic_message_unittest.cc                  \
   google/protobuf/extension_set_unittest.cc                    \
   google/protobuf/generated_message_reflection_unittest.cc     \
+  google/protobuf/map_field_test.cc                            \
+  google/protobuf/map_test.cc                                  \
   google/protobuf/message_unittest.cc                          \
+  google/protobuf/no_field_presence_test.cc                    \
+  google/protobuf/preserve_unknown_enum_test.cc                \
+  google/protobuf/proto3_arena_unittest.cc                     \
+  google/protobuf/proto3_arena_lite_unittest.cc                     \
+  google/protobuf/proto3_lite_unittest.cc                     \
   google/protobuf/reflection_ops_unittest.cc                   \
-  google/protobuf/repeated_field_unittest.cc                   \
   google/protobuf/repeated_field_reflection_unittest.cc        \
+  google/protobuf/repeated_field_unittest.cc                   \
   google/protobuf/text_format_unittest.cc                      \
   google/protobuf/unknown_field_set_unittest.cc                \
+  google/protobuf/well_known_types_unittest.cc                 \
   google/protobuf/wire_format_unittest.cc                      \
   google/protobuf/io/coded_stream_unittest.cc                  \
   google/protobuf/io/printer_unittest.cc                       \
@@ -404,19 +738,38 @@
   google/protobuf/compiler/cpp/cpp_unittest.h                  \
   google/protobuf/compiler/cpp/cpp_unittest.cc                 \
   google/protobuf/compiler/cpp/cpp_plugin_unittest.cc          \
+  google/protobuf/compiler/cpp/metadata_test.cc                \
   google/protobuf/compiler/java/java_plugin_unittest.cc        \
   google/protobuf/compiler/java/java_doc_comment_unittest.cc   \
+  google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \
   google/protobuf/compiler/python/python_plugin_unittest.cc    \
+  google/protobuf/compiler/ruby/ruby_generator_unittest.cc     \
+  google/protobuf/compiler/csharp/csharp_generator_unittest.cc \
+  google/protobuf/util/field_comparator_test.cc                \
+  google/protobuf/util/field_mask_util_test.cc                 \
+  google/protobuf/util/internal/default_value_objectwriter_test.cc \
+  google/protobuf/util/internal/json_objectwriter_test.cc      \
+  google/protobuf/util/internal/json_stream_parser_test.cc     \
+  google/protobuf/util/internal/protostream_objectsource_test.cc \
+  google/protobuf/util/internal/protostream_objectwriter_test.cc \
+  google/protobuf/util/internal/type_info_test_helper.cc       \
+  google/protobuf/util/json_util_test.cc                       \
+  google/protobuf/util/message_differencer_unittest.cc         \
+  google/protobuf/util/time_util_test.cc                       \
+  google/protobuf/util/type_resolver_util_test.cc              \
   $(COMMON_TEST_SOURCES)
+
+
 nodist_protobuf_test_SOURCES = $(protoc_outputs)
 
 # Run cpp_unittest again with PROTOBUF_TEST_NO_DESCRIPTORS defined.
 protobuf_lazy_descriptor_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \
                       libprotoc.la                                   \
-                      $(top_builddir)/gtest/lib/libgtest.la          \
-                      $(top_builddir)/gtest/lib/libgtest_main.la
-protobuf_lazy_descriptor_test_CPPFLAGS = -I$(top_srcdir)/gtest/include    \
-                                         -I$(top_builddir)/gtest/include  \
+                      ../gmock/gtest/lib/libgtest.la                 \
+                      ../gmock/lib/libgmock.la                       \
+                      ../gmock/lib/libgmock_main.la
+protobuf_lazy_descriptor_test_CPPFLAGS = -I$(srcdir)/../gmock/include       \
+                                         -I$(srcdir)/../gmock/gtest/include \
                                          -DPROTOBUF_TEST_NO_DESCRIPTORS
 protobuf_lazy_descriptor_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_lazy_descriptor_test_SOURCES =                        \
@@ -424,20 +777,44 @@
   $(COMMON_TEST_SOURCES)
 nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
 
-# Build lite_unittest separately, since it doesn't use gtest.
+COMMON_LITE_TEST_SOURCES =                                             \
+  google/protobuf/arena_test_util.cc                                   \
+  google/protobuf/arena_test_util.h                                    \
+  google/protobuf/map_lite_test_util.cc                                \
+  google/protobuf/map_lite_test_util.h                                 \
+  google/protobuf/test_util_lite.cc                                    \
+  google/protobuf/test_util_lite.h
+
+# Build lite_unittest separately, since it doesn't use gtest. It can't
+# depend on gtest because our internal version of gtest depend on proto
+# full runtime and we want to make sure this test builds without full
+# runtime.
 protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la
 protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_lite_test_SOURCES =                                           \
   google/protobuf/lite_unittest.cc                                     \
-  google/protobuf/test_util_lite.cc                                    \
-  google/protobuf/test_util_lite.h
+  $(COMMON_LITE_TEST_SOURCES)
 nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
 
+# lite_arena_unittest depends on gtest because teboring@ found that without
+# gtest when building the test internally our memory sanitizer doesn't detect
+# memory leaks (don't know why).
+protobuf_lite_arena_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la \
+                      ../gmock/gtest/lib/libgtest.la                 \
+                      ../gmock/lib/libgmock.la                       \
+                      ../gmock/lib/libgmock_main.la
+protobuf_lite_arena_test_CPPFLAGS = -I$(srcdir)/../gmock/include       \
+                                    -I$(srcdir)/../gmock/gtest/include
+protobuf_lite_arena_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
+protobuf_lite_arena_test_SOURCES =       \
+  google/protobuf/lite_arena_unittest.cc \
+  $(COMMON_LITE_TEST_SOURCES)
+nodist_protobuf_lite_arena_test_SOURCES = $(protoc_lite_outputs)
+
 # Test plugin binary.
 test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
-                    $(top_builddir)/gtest/lib/libgtest.la
-test_plugin_CPPFLAGS = -I$(top_srcdir)/gtest/include         \
-                       -I$(top_builddir)/gtest/include
+                    ../gmock/gtest/lib/libgtest.la
+test_plugin_CPPFLAGS = -I$(srcdir)/../gmock/gtest/include
 test_plugin_SOURCES =                                          \
   google/protobuf/compiler/mock_code_generator.cc              \
   google/protobuf/testing/file.cc                              \
@@ -453,4 +830,5 @@
 endif
 
 TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test \
-        google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS)
+        google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS)     \
+        protobuf-lite-arena-test
diff --git a/src/Makefile.in b/src/Makefile.in
deleted file mode 100644
index c6703bb..0000000
--- a/src/Makefile.in
+++ /dev/null
@@ -1,3796 +0,0 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-
-
-
-VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \	]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-bin_PROGRAMS = protoc$(EXEEXT)
-check_PROGRAMS = protoc$(EXEEXT) protobuf-test$(EXEEXT) \
-	protobuf-lazy-descriptor-test$(EXEEXT) \
-	protobuf-lite-test$(EXEEXT) test_plugin$(EXEEXT) \
-	$(am__EXEEXT_1)
-TESTS = protobuf-test$(EXEEXT) protobuf-lazy-descriptor-test$(EXEEXT) \
-	protobuf-lite-test$(EXEEXT) \
-	google/protobuf/compiler/zip_output_unittest.sh \
-	$(am__EXEEXT_2)
-subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/depcomp $(nobase_dist_proto_DATA) \
-	$(am__nobase_include_HEADERS_DIST) $(top_srcdir)/test-driver
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ac_system_extensions.m4 \
-	$(top_srcdir)/m4/acx_check_suncc.m4 \
-	$(top_srcdir)/m4/acx_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/stl_hash.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-	$(ACLOCAL_M4)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
-	"$(DESTDIR)$(protodir)" "$(DESTDIR)$(includedir)"
-LTLIBRARIES = $(lib_LTLIBRARIES)
-am__DEPENDENCIES_1 =
-libprotobuf_lite_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am__dirstamp = $(am__leading_dot)dirstamp
-am_libprotobuf_lite_la_OBJECTS =  \
-	google/protobuf/stubs/atomicops_internals_x86_gcc.lo \
-	google/protobuf/stubs/atomicops_internals_x86_msvc.lo \
-	google/protobuf/stubs/common.lo google/protobuf/stubs/once.lo \
-	google/protobuf/stubs/stringprintf.lo \
-	google/protobuf/extension_set.lo \
-	google/protobuf/generated_message_util.lo \
-	google/protobuf/message_lite.lo \
-	google/protobuf/repeated_field.lo \
-	google/protobuf/wire_format_lite.lo \
-	google/protobuf/io/coded_stream.lo \
-	google/protobuf/io/zero_copy_stream.lo \
-	google/protobuf/io/zero_copy_stream_impl_lite.lo
-libprotobuf_lite_la_OBJECTS = $(am_libprotobuf_lite_la_OBJECTS)
-AM_V_lt = $(am__v_lt_@AM_V@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
-am__v_lt_1 = 
-libprotobuf_lite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(AM_CXXFLAGS) $(CXXFLAGS) $(libprotobuf_lite_la_LDFLAGS) \
-	$(LDFLAGS) -o $@
-libprotobuf_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am__objects_1 = google/protobuf/stubs/atomicops_internals_x86_gcc.lo \
-	google/protobuf/stubs/atomicops_internals_x86_msvc.lo \
-	google/protobuf/stubs/common.lo google/protobuf/stubs/once.lo \
-	google/protobuf/stubs/stringprintf.lo \
-	google/protobuf/extension_set.lo \
-	google/protobuf/generated_message_util.lo \
-	google/protobuf/message_lite.lo \
-	google/protobuf/repeated_field.lo \
-	google/protobuf/wire_format_lite.lo \
-	google/protobuf/io/coded_stream.lo \
-	google/protobuf/io/zero_copy_stream.lo \
-	google/protobuf/io/zero_copy_stream_impl_lite.lo
-am_libprotobuf_la_OBJECTS = $(am__objects_1) \
-	google/protobuf/stubs/strutil.lo \
-	google/protobuf/stubs/substitute.lo \
-	google/protobuf/stubs/structurally_valid.lo \
-	google/protobuf/descriptor.lo google/protobuf/descriptor.pb.lo \
-	google/protobuf/descriptor_database.lo \
-	google/protobuf/dynamic_message.lo \
-	google/protobuf/extension_set_heavy.lo \
-	google/protobuf/generated_message_reflection.lo \
-	google/protobuf/message.lo google/protobuf/reflection_ops.lo \
-	google/protobuf/service.lo google/protobuf/text_format.lo \
-	google/protobuf/unknown_field_set.lo \
-	google/protobuf/wire_format.lo \
-	google/protobuf/io/gzip_stream.lo \
-	google/protobuf/io/printer.lo google/protobuf/io/strtod.lo \
-	google/protobuf/io/tokenizer.lo \
-	google/protobuf/io/zero_copy_stream_impl.lo \
-	google/protobuf/compiler/importer.lo \
-	google/protobuf/compiler/parser.lo
-libprotobuf_la_OBJECTS = $(am_libprotobuf_la_OBJECTS)
-libprotobuf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(AM_CXXFLAGS) $(CXXFLAGS) $(libprotobuf_la_LDFLAGS) \
-	$(LDFLAGS) -o $@
-libprotoc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la
-am_libprotoc_la_OBJECTS = google/protobuf/compiler/code_generator.lo \
-	google/protobuf/compiler/command_line_interface.lo \
-	google/protobuf/compiler/plugin.lo \
-	google/protobuf/compiler/plugin.pb.lo \
-	google/protobuf/compiler/subprocess.lo \
-	google/protobuf/compiler/zip_writer.lo \
-	google/protobuf/compiler/cpp/cpp_enum.lo \
-	google/protobuf/compiler/cpp/cpp_enum_field.lo \
-	google/protobuf/compiler/cpp/cpp_extension.lo \
-	google/protobuf/compiler/cpp/cpp_field.lo \
-	google/protobuf/compiler/cpp/cpp_file.lo \
-	google/protobuf/compiler/cpp/cpp_generator.lo \
-	google/protobuf/compiler/cpp/cpp_helpers.lo \
-	google/protobuf/compiler/cpp/cpp_message.lo \
-	google/protobuf/compiler/cpp/cpp_message_field.lo \
-	google/protobuf/compiler/cpp/cpp_primitive_field.lo \
-	google/protobuf/compiler/cpp/cpp_service.lo \
-	google/protobuf/compiler/cpp/cpp_string_field.lo \
-	google/protobuf/compiler/java/java_context.lo \
-	google/protobuf/compiler/java/java_enum.lo \
-	google/protobuf/compiler/java/java_enum_field.lo \
-	google/protobuf/compiler/java/java_extension.lo \
-	google/protobuf/compiler/java/java_field.lo \
-	google/protobuf/compiler/java/java_file.lo \
-	google/protobuf/compiler/java/java_generator.lo \
-	google/protobuf/compiler/java/java_generator_factory.lo \
-	google/protobuf/compiler/java/java_helpers.lo \
-	google/protobuf/compiler/java/java_lazy_message_field.lo \
-	google/protobuf/compiler/java/java_message.lo \
-	google/protobuf/compiler/java/java_message_field.lo \
-	google/protobuf/compiler/java/java_name_resolver.lo \
-	google/protobuf/compiler/java/java_primitive_field.lo \
-	google/protobuf/compiler/java/java_shared_code_generator.lo \
-	google/protobuf/compiler/java/java_service.lo \
-	google/protobuf/compiler/java/java_string_field.lo \
-	google/protobuf/compiler/java/java_doc_comment.lo \
-	google/protobuf/compiler/javamicro/javamicro_enum.lo \
-	google/protobuf/compiler/javamicro/javamicro_enum_field.lo \
-	google/protobuf/compiler/javamicro/javamicro_field.lo \
-	google/protobuf/compiler/javamicro/javamicro_file.lo \
-	google/protobuf/compiler/javamicro/javamicro_generator.lo \
-	google/protobuf/compiler/javamicro/javamicro_helpers.lo \
-	google/protobuf/compiler/javamicro/javamicro_message.lo \
-	google/protobuf/compiler/javamicro/javamicro_message_field.lo \
-	google/protobuf/compiler/javamicro/javamicro_primitive_field.lo \
-	google/protobuf/compiler/javanano/javanano_enum.lo \
-	google/protobuf/compiler/javanano/javanano_enum_field.lo \
-	google/protobuf/compiler/javanano/javanano_extension.lo \
-	google/protobuf/compiler/javanano/javanano_field.lo \
-	google/protobuf/compiler/javanano/javanano_file.lo \
-	google/protobuf/compiler/javanano/javanano_generator.lo \
-	google/protobuf/compiler/javanano/javanano_helpers.lo \
-	google/protobuf/compiler/javanano/javanano_message.lo \
-	google/protobuf/compiler/javanano/javanano_message_field.lo \
-	google/protobuf/compiler/javanano/javanano_primitive_field.lo \
-	google/protobuf/compiler/python/python_generator.lo
-libprotoc_la_OBJECTS = $(am_libprotoc_la_OBJECTS)
-libprotoc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(libprotoc_la_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_ZLIB_TRUE@am__EXEEXT_1 = zcgzip$(EXEEXT) zcgunzip$(EXEEXT)
-PROGRAMS = $(bin_PROGRAMS)
-am__objects_2 = google/protobuf/protobuf_lazy_descriptor_test-test_util.$(OBJEXT) \
-	google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.$(OBJEXT) \
-	google/protobuf/testing/protobuf_lazy_descriptor_test-file.$(OBJEXT)
-am_protobuf_lazy_descriptor_test_OBJECTS = google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.$(OBJEXT) \
-	$(am__objects_2)
-am__objects_3 = google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.$(OBJEXT)
-am__objects_4 = $(am__objects_3) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.$(OBJEXT) \
-	google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.$(OBJEXT)
-nodist_protobuf_lazy_descriptor_test_OBJECTS = $(am__objects_4)
-protobuf_lazy_descriptor_test_OBJECTS =  \
-	$(am_protobuf_lazy_descriptor_test_OBJECTS) \
-	$(nodist_protobuf_lazy_descriptor_test_OBJECTS)
-protobuf_lazy_descriptor_test_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-	libprotobuf.la libprotoc.la \
-	$(top_builddir)/gtest/lib/libgtest.la \
-	$(top_builddir)/gtest/lib/libgtest_main.la
-protobuf_lazy_descriptor_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) \
-	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-am_protobuf_lite_test_OBJECTS =  \
-	google/protobuf/protobuf_lite_test-lite_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_lite_test-test_util_lite.$(OBJEXT)
-am__objects_5 =  \
-	google/protobuf/protobuf_lite_test-unittest_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lite_test-unittest_import_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.$(OBJEXT)
-nodist_protobuf_lite_test_OBJECTS = $(am__objects_5)
-protobuf_lite_test_OBJECTS = $(am_protobuf_lite_test_OBJECTS) \
-	$(nodist_protobuf_lite_test_OBJECTS)
-protobuf_lite_test_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-	libprotobuf-lite.la
-protobuf_lite_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
-	$(LDFLAGS) -o $@
-am__objects_6 = google/protobuf/protobuf_test-test_util.$(OBJEXT) \
-	google/protobuf/testing/protobuf_test-googletest.$(OBJEXT) \
-	google/protobuf/testing/protobuf_test-file.$(OBJEXT)
-am_protobuf_test_OBJECTS =  \
-	google/protobuf/stubs/protobuf_test-common_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-once_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-strutil_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-structurally_valid_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-stringprintf_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-template_util_unittest.$(OBJEXT) \
-	google/protobuf/stubs/protobuf_test-type_traits_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-descriptor_database_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-descriptor_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-dynamic_message_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-extension_set_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-generated_message_reflection_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-message_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-reflection_ops_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-repeated_field_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-repeated_field_reflection_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-text_format_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-unknown_field_set_unittest.$(OBJEXT) \
-	google/protobuf/protobuf_test-wire_format_unittest.$(OBJEXT) \
-	google/protobuf/io/protobuf_test-coded_stream_unittest.$(OBJEXT) \
-	google/protobuf/io/protobuf_test-printer_unittest.$(OBJEXT) \
-	google/protobuf/io/protobuf_test-tokenizer_unittest.$(OBJEXT) \
-	google/protobuf/io/protobuf_test-zero_copy_stream_unittest.$(OBJEXT) \
-	google/protobuf/compiler/protobuf_test-command_line_interface_unittest.$(OBJEXT) \
-	google/protobuf/compiler/protobuf_test-importer_unittest.$(OBJEXT) \
-	google/protobuf/compiler/protobuf_test-mock_code_generator.$(OBJEXT) \
-	google/protobuf/compiler/protobuf_test-parser_unittest.$(OBJEXT) \
-	google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.$(OBJEXT) \
-	google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.$(OBJEXT) \
-	google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.$(OBJEXT) \
-	google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.$(OBJEXT) \
-	google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.$(OBJEXT) \
-	google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.$(OBJEXT) \
-	$(am__objects_6)
-am__objects_7 =  \
-	google/protobuf/protobuf_test-unittest_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_import_lite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_import_public_lite.pb.$(OBJEXT)
-am__objects_8 = $(am__objects_7) \
-	google/protobuf/protobuf_test-unittest.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_empty.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_import.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_import_public.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_mset.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_optimize_for.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_custom_options.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.$(OBJEXT) \
-	google/protobuf/protobuf_test-unittest_no_generic_services.pb.$(OBJEXT) \
-	google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.$(OBJEXT)
-nodist_protobuf_test_OBJECTS = $(am__objects_8)
-protobuf_test_OBJECTS = $(am_protobuf_test_OBJECTS) \
-	$(nodist_protobuf_test_OBJECTS)
-protobuf_test_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
-	libprotoc.la $(top_builddir)/gtest/lib/libgtest.la \
-	$(top_builddir)/gtest/lib/libgtest_main.la
-protobuf_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(protobuf_test_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-	-o $@
-am_protoc_OBJECTS = google/protobuf/compiler/main.$(OBJEXT)
-protoc_OBJECTS = $(am_protoc_OBJECTS)
-protoc_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
-	libprotoc.la
-am_test_plugin_OBJECTS = google/protobuf/compiler/test_plugin-mock_code_generator.$(OBJEXT) \
-	google/protobuf/testing/test_plugin-file.$(OBJEXT) \
-	google/protobuf/compiler/test_plugin-test_plugin.$(OBJEXT)
-test_plugin_OBJECTS = $(am_test_plugin_OBJECTS)
-test_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) libprotobuf.la \
-	libprotoc.la $(top_builddir)/gtest/lib/libgtest.la
-am__zcgunzip_SOURCES_DIST = google/protobuf/testing/zcgunzip.cc
-@HAVE_ZLIB_TRUE@am_zcgunzip_OBJECTS =  \
-@HAVE_ZLIB_TRUE@	google/protobuf/testing/zcgunzip.$(OBJEXT)
-zcgunzip_OBJECTS = $(am_zcgunzip_OBJECTS)
-@HAVE_ZLIB_TRUE@zcgunzip_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-@HAVE_ZLIB_TRUE@	libprotobuf.la
-am__zcgzip_SOURCES_DIST = google/protobuf/testing/zcgzip.cc
-@HAVE_ZLIB_TRUE@am_zcgzip_OBJECTS =  \
-@HAVE_ZLIB_TRUE@	google/protobuf/testing/zcgzip.$(OBJEXT)
-zcgzip_OBJECTS = $(am_zcgzip_OBJECTS)
-@HAVE_ZLIB_TRUE@zcgzip_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-@HAVE_ZLIB_TRUE@	libprotobuf.la
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__depfiles_maybe = depfiles
-am__mv = mv -f
-CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
-LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
-	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
-	$(AM_CXXFLAGS) $(CXXFLAGS)
-AM_V_CXX = $(am__v_CXX_@AM_V@)
-am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
-am__v_CXX_0 = @echo "  CXX     " $@;
-am__v_CXX_1 = 
-CXXLD = $(CXX)
-CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
-am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
-am__v_CXXLD_0 = @echo "  CXXLD   " $@;
-am__v_CXXLD_1 = 
-COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
-	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
-	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
-	$(AM_CFLAGS) $(CFLAGS)
-AM_V_CC = $(am__v_CC_@AM_V@)
-am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo "  CC      " $@;
-am__v_CC_1 = 
-CCLD = $(CC)
-LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
-	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CCLD = $(am__v_CCLD_@AM_V@)
-am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
-am__v_CCLD_0 = @echo "  CCLD    " $@;
-am__v_CCLD_1 = 
-SOURCES = $(libprotobuf_lite_la_SOURCES) $(libprotobuf_la_SOURCES) \
-	$(libprotoc_la_SOURCES) \
-	$(protobuf_lazy_descriptor_test_SOURCES) \
-	$(nodist_protobuf_lazy_descriptor_test_SOURCES) \
-	$(protobuf_lite_test_SOURCES) \
-	$(nodist_protobuf_lite_test_SOURCES) $(protobuf_test_SOURCES) \
-	$(nodist_protobuf_test_SOURCES) $(protoc_SOURCES) \
-	$(test_plugin_SOURCES) $(zcgunzip_SOURCES) $(zcgzip_SOURCES)
-DIST_SOURCES = $(libprotobuf_lite_la_SOURCES) \
-	$(libprotobuf_la_SOURCES) $(libprotoc_la_SOURCES) \
-	$(protobuf_lazy_descriptor_test_SOURCES) \
-	$(protobuf_lite_test_SOURCES) $(protobuf_test_SOURCES) \
-	$(protoc_SOURCES) $(test_plugin_SOURCES) \
-	$(am__zcgunzip_SOURCES_DIST) $(am__zcgzip_SOURCES_DIST)
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-DATA = $(nobase_dist_proto_DATA)
-am__nobase_include_HEADERS_DIST = google/protobuf/stubs/atomicops.h \
-	google/protobuf/stubs/atomicops_internals_arm_gcc.h \
-	google/protobuf/stubs/atomicops_internals_arm64_gcc.h \
-	google/protobuf/stubs/atomicops_internals_arm_qnx.h \
-	google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
-	google/protobuf/stubs/atomicops_internals_generic_gcc.h \
-	google/protobuf/stubs/atomicops_internals_macosx.h \
-	google/protobuf/stubs/atomicops_internals_mips_gcc.h \
-	google/protobuf/stubs/atomicops_internals_pnacl.h \
-	google/protobuf/stubs/atomicops_internals_tsan.h \
-	google/protobuf/stubs/atomicops_internals_x86_gcc.h \
-	google/protobuf/stubs/atomicops_internals_x86_msvc.h \
-	google/protobuf/stubs/common.h \
-	google/protobuf/stubs/platform_macros.h \
-	google/protobuf/stubs/once.h google/protobuf/stubs/stl_util.h \
-	google/protobuf/stubs/template_util.h \
-	google/protobuf/stubs/type_traits.h \
-	google/protobuf/descriptor.h google/protobuf/descriptor.pb.h \
-	google/protobuf/descriptor_database.h \
-	google/protobuf/dynamic_message.h \
-	google/protobuf/extension_set.h \
-	google/protobuf/generated_enum_reflection.h \
-	google/protobuf/generated_message_util.h \
-	google/protobuf/generated_message_reflection.h \
-	google/protobuf/message.h google/protobuf/message_lite.h \
-	google/protobuf/reflection_ops.h \
-	google/protobuf/repeated_field.h google/protobuf/service.h \
-	google/protobuf/text_format.h \
-	google/protobuf/unknown_field_set.h \
-	google/protobuf/wire_format.h \
-	google/protobuf/wire_format_lite.h \
-	google/protobuf/wire_format_lite_inl.h \
-	google/protobuf/io/coded_stream.h \
-	google/protobuf/io/gzip_stream.h google/protobuf/io/printer.h \
-	google/protobuf/io/strtod.h google/protobuf/io/tokenizer.h \
-	google/protobuf/io/zero_copy_stream.h \
-	google/protobuf/io/zero_copy_stream_impl.h \
-	google/protobuf/io/zero_copy_stream_impl_lite.h \
-	google/protobuf/compiler/code_generator.h \
-	google/protobuf/compiler/command_line_interface.h \
-	google/protobuf/compiler/importer.h \
-	google/protobuf/compiler/parser.h \
-	google/protobuf/compiler/plugin.h \
-	google/protobuf/compiler/plugin.pb.h \
-	google/protobuf/compiler/cpp/cpp_generator.h \
-	google/protobuf/compiler/java/java_generator.h \
-	google/protobuf/compiler/javamicro/javamicro_generator.h \
-	google/protobuf/compiler/javanano/javanano_generator.h \
-	google/protobuf/compiler/python/python_generator.h
-HEADERS = $(nobase_include_HEADERS)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-am__tty_colors_dummy = \
-  mgn= red= grn= lgn= blu= brg= std=; \
-  am__color_tests=no
-am__tty_colors = { \
-  $(am__tty_colors_dummy); \
-  if test "X$(AM_COLOR_TESTS)" = Xno; then \
-    am__color_tests=no; \
-  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
-    am__color_tests=yes; \
-  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
-    am__color_tests=yes; \
-  fi; \
-  if test $$am__color_tests = yes; then \
-    red=''; \
-    grn=''; \
-    lgn=''; \
-    blu=''; \
-    mgn=''; \
-    brg=''; \
-    std=''; \
-  fi; \
-}
-am__recheck_rx = ^[ 	]*:recheck:[ 	]*
-am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
-am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
-# A command that, given a newline-separated list of test names on the
-# standard input, print the name of the tests that are to be re-run
-# upon "make recheck".
-am__list_recheck_tests = $(AWK) '{ \
-  recheck = 1; \
-  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
-    { \
-      if (rc < 0) \
-        { \
-          if ((getline line2 < ($$0 ".log")) < 0) \
-	    recheck = 0; \
-          break; \
-        } \
-      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
-        { \
-          recheck = 0; \
-          break; \
-        } \
-      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
-        { \
-          break; \
-        } \
-    }; \
-  if (recheck) \
-    print $$0; \
-  close ($$0 ".trs"); \
-  close ($$0 ".log"); \
-}'
-# A command that, given a newline-separated list of test names on the
-# standard input, create the global log from their .trs and .log files.
-am__create_global_log = $(AWK) ' \
-function fatal(msg) \
-{ \
-  print "fatal: making $@: " msg | "cat >&2"; \
-  exit 1; \
-} \
-function rst_section(header) \
-{ \
-  print header; \
-  len = length(header); \
-  for (i = 1; i <= len; i = i + 1) \
-    printf "="; \
-  printf "\n\n"; \
-} \
-{ \
-  copy_in_global_log = 1; \
-  global_test_result = "RUN"; \
-  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
-    { \
-      if (rc < 0) \
-         fatal("failed to read from " $$0 ".trs"); \
-      if (line ~ /$(am__global_test_result_rx)/) \
-        { \
-          sub("$(am__global_test_result_rx)", "", line); \
-          sub("[ 	]*$$", "", line); \
-          global_test_result = line; \
-        } \
-      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
-        copy_in_global_log = 0; \
-    }; \
-  if (copy_in_global_log) \
-    { \
-      rst_section(global_test_result ": " $$0); \
-      while ((rc = (getline line < ($$0 ".log"))) != 0) \
-      { \
-        if (rc < 0) \
-          fatal("failed to read from " $$0 ".log"); \
-        print line; \
-      }; \
-      printf "\n"; \
-    }; \
-  close ($$0 ".trs"); \
-  close ($$0 ".log"); \
-}'
-# Restructured Text title.
-am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
-# Solaris 10 'make', and several other traditional 'make' implementations,
-# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
-# by disabling -e (using the XSI extension "set +e") if it's set.
-am__sh_e_setup = case $$- in *e*) set +e;; esac
-# Default flags passed to test drivers.
-am__common_driver_flags = \
-  --color-tests "$$am__color_tests" \
-  --enable-hard-errors "$$am__enable_hard_errors" \
-  --expect-failure "$$am__expect_failure"
-# To be inserted before the command running the test.  Creates the
-# directory for the log if needed.  Stores in $dir the directory
-# containing $f, in $tst the test, in $log the log.  Executes the
-# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
-# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
-# will run the test scripts (or their associated LOG_COMPILER, if
-# thy have one).
-am__check_pre = \
-$(am__sh_e_setup);					\
-$(am__vpath_adj_setup) $(am__vpath_adj)			\
-$(am__tty_colors);					\
-srcdir=$(srcdir); export srcdir;			\
-case "$@" in						\
-  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
-    *) am__odir=.;; 					\
-esac;							\
-test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
-  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
-if test -f "./$$f"; then dir=./;			\
-elif test -f "$$f"; then dir=;				\
-else dir="$(srcdir)/"; fi;				\
-tst=$$dir$$f; log='$@'; 				\
-if test -n '$(DISABLE_HARD_ERRORS)'; then		\
-  am__enable_hard_errors=no; 				\
-else							\
-  am__enable_hard_errors=yes; 				\
-fi; 							\
-case " $(XFAIL_TESTS) " in				\
-  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
-    am__expect_failure=yes;;				\
-  *)							\
-    am__expect_failure=no;;				\
-esac; 							\
-$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
-# A shell command to get the names of the tests scripts with any registered
-# extension removed (i.e., equivalently, the names of the test logs, with
-# the '.log' extension removed).  The result is saved in the shell variable
-# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
-# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
-# since that might cause problem with VPATH rewrites for suffix-less tests.
-# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
-am__set_TESTS_bases = \
-  bases='$(TEST_LOGS)'; \
-  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
-  bases=`echo $$bases`
-RECHECK_LOGS = $(TEST_LOGS)
-AM_RECURSIVE_TARGETS = check recheck
-@HAVE_ZLIB_TRUE@am__EXEEXT_2 =  \
-@HAVE_ZLIB_TRUE@	google/protobuf/io/gzip_stream_unittest.sh
-TEST_SUITE_LOG = test-suite.log
-TEST_EXTENSIONS = @EXEEXT@ .test
-LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
-LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
-am__set_b = \
-  case '$@' in \
-    */*) \
-      case '$*' in \
-        */*) b='$*';; \
-          *) b=`echo '$@' | sed 's/\.log$$//'`; \
-       esac;; \
-    *) \
-      b='$*';; \
-  esac
-am__test_logs1 = $(TESTS:=.log)
-am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
-TEST_LOGS = $(am__test_logs2:.test.log=.log)
-TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
-TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
-	$(TEST_LOG_FLAGS)
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPPFLAGS = @CPPFLAGS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-ISAINFO = @ISAINFO@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-POW_LIB = @POW_LIB@
-PROTOBUF_OPT_FLAG = @PROTOBUF_OPT_FLAG@
-PROTOC = @PROTOC@
-PTHREAD_CC = @PTHREAD_CC@
-PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
-PTHREAD_LIBS = @PTHREAD_LIBS@
-RANLIB = @RANLIB@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-STRIP = @STRIP@
-VERSION = @VERSION@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-acx_pthread_config = @acx_pthread_config@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-subdirs = @subdirs@
-sysconfdir = @sysconfdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-@HAVE_ZLIB_FALSE@GZCHECKPROGRAMS = 
-@HAVE_ZLIB_TRUE@GZCHECKPROGRAMS = zcgzip zcgunzip
-@HAVE_ZLIB_FALSE@GZHEADERS = 
-@HAVE_ZLIB_TRUE@GZHEADERS = google/protobuf/io/gzip_stream.h
-@HAVE_ZLIB_FALSE@GZTESTS = 
-@HAVE_ZLIB_TRUE@GZTESTS = google/protobuf/io/gzip_stream_unittest.sh
-@GCC_FALSE@NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS)
-
-# These are good warnings to turn on by default
-@GCC_TRUE@NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
-AM_CXXFLAGS = $(NO_OPT_CXXFLAGS) $(PROTOBUF_OPT_FLAG)
-AM_LDFLAGS = $(PTHREAD_CFLAGS)
-
-# If I say "dist_include_DATA", automake complains that $(includedir) is not
-# a "legitimate" directory for DATA.  Screw you, automake.
-protodir = $(includedir)
-nobase_dist_proto_DATA = google/protobuf/descriptor.proto \
-                         google/protobuf/compiler/plugin.proto
-
-CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
-             testzip.jar testzip.list testzip.proto testzip.zip
-
-MAINTAINERCLEANFILES = \
-  Makefile.in
-
-nobase_include_HEADERS = \
-  google/protobuf/stubs/atomicops.h                             \
-  google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
-  google/protobuf/stubs/atomicops_internals_arm64_gcc.h         \
-  google/protobuf/stubs/atomicops_internals_arm_qnx.h           \
-  google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
-  google/protobuf/stubs/atomicops_internals_generic_gcc.h       \
-  google/protobuf/stubs/atomicops_internals_macosx.h            \
-  google/protobuf/stubs/atomicops_internals_mips_gcc.h          \
-  google/protobuf/stubs/atomicops_internals_pnacl.h             \
-  google/protobuf/stubs/atomicops_internals_tsan.h              \
-  google/protobuf/stubs/atomicops_internals_x86_gcc.h           \
-  google/protobuf/stubs/atomicops_internals_x86_msvc.h          \
-  google/protobuf/stubs/common.h                                \
-  google/protobuf/stubs/platform_macros.h                       \
-  google/protobuf/stubs/once.h                                  \
-  google/protobuf/stubs/stl_util.h                              \
-  google/protobuf/stubs/template_util.h                         \
-  google/protobuf/stubs/type_traits.h                           \
-  google/protobuf/descriptor.h                                  \
-  google/protobuf/descriptor.pb.h                               \
-  google/protobuf/descriptor_database.h                         \
-  google/protobuf/dynamic_message.h                             \
-  google/protobuf/extension_set.h                               \
-  google/protobuf/generated_enum_reflection.h                   \
-  google/protobuf/generated_message_util.h                      \
-  google/protobuf/generated_message_reflection.h                \
-  google/protobuf/message.h                                     \
-  google/protobuf/message_lite.h                                \
-  google/protobuf/reflection_ops.h                              \
-  google/protobuf/repeated_field.h                              \
-  google/protobuf/service.h                                     \
-  google/protobuf/text_format.h                                 \
-  google/protobuf/unknown_field_set.h                           \
-  google/protobuf/wire_format.h                                 \
-  google/protobuf/wire_format_lite.h                            \
-  google/protobuf/wire_format_lite_inl.h                        \
-  google/protobuf/io/coded_stream.h                             \
-  $(GZHEADERS)                                                  \
-  google/protobuf/io/printer.h                                  \
-  google/protobuf/io/strtod.h                                   \
-  google/protobuf/io/tokenizer.h                                \
-  google/protobuf/io/zero_copy_stream.h                         \
-  google/protobuf/io/zero_copy_stream_impl.h                    \
-  google/protobuf/io/zero_copy_stream_impl_lite.h               \
-  google/protobuf/compiler/code_generator.h                     \
-  google/protobuf/compiler/command_line_interface.h             \
-  google/protobuf/compiler/importer.h                           \
-  google/protobuf/compiler/parser.h                             \
-  google/protobuf/compiler/plugin.h                             \
-  google/protobuf/compiler/plugin.pb.h                          \
-  google/protobuf/compiler/cpp/cpp_generator.h                  \
-  google/protobuf/compiler/java/java_generator.h                \
-  google/protobuf/compiler/javamicro/javamicro_generator.h      \
-  google/protobuf/compiler/javanano/javanano_generator.h        \
-  google/protobuf/compiler/python/python_generator.h
-
-lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
-libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_lite_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
-libprotobuf_lite_la_SOURCES = \
-  google/protobuf/stubs/atomicops_internals_x86_gcc.cc         \
-  google/protobuf/stubs/atomicops_internals_x86_msvc.cc        \
-  google/protobuf/stubs/common.cc                              \
-  google/protobuf/stubs/once.cc                                \
-  google/protobuf/stubs/hash.h                                 \
-  google/protobuf/stubs/map_util.h                             \
-  google/protobuf/stubs/shared_ptr.h                           \
-  google/protobuf/stubs/stringprintf.cc                        \
-  google/protobuf/stubs/stringprintf.h                         \
-  google/protobuf/extension_set.cc                             \
-  google/protobuf/generated_message_util.cc                    \
-  google/protobuf/message_lite.cc                              \
-  google/protobuf/repeated_field.cc                            \
-  google/protobuf/wire_format_lite.cc                          \
-  google/protobuf/io/coded_stream.cc                           \
-  google/protobuf/io/coded_stream_inl.h                        \
-  google/protobuf/io/zero_copy_stream.cc                       \
-  google/protobuf/io/zero_copy_stream_impl_lite.cc
-
-libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
-libprotobuf_la_SOURCES = \
-  $(libprotobuf_lite_la_SOURCES)                               \
-  google/protobuf/stubs/strutil.cc                             \
-  google/protobuf/stubs/strutil.h                              \
-  google/protobuf/stubs/substitute.cc                          \
-  google/protobuf/stubs/substitute.h                           \
-  google/protobuf/stubs/structurally_valid.cc                  \
-  google/protobuf/descriptor.cc                                \
-  google/protobuf/descriptor.pb.cc                             \
-  google/protobuf/descriptor_database.cc                       \
-  google/protobuf/dynamic_message.cc                           \
-  google/protobuf/extension_set_heavy.cc                       \
-  google/protobuf/generated_message_reflection.cc              \
-  google/protobuf/message.cc                                   \
-  google/protobuf/reflection_ops.cc                            \
-  google/protobuf/service.cc                                   \
-  google/protobuf/text_format.cc                               \
-  google/protobuf/unknown_field_set.cc                         \
-  google/protobuf/wire_format.cc                               \
-  google/protobuf/io/gzip_stream.cc                            \
-  google/protobuf/io/printer.cc                                \
-  google/protobuf/io/strtod.cc                                 \
-  google/protobuf/io/tokenizer.cc                              \
-  google/protobuf/io/zero_copy_stream_impl.cc                  \
-  google/protobuf/compiler/importer.cc                         \
-  google/protobuf/compiler/parser.cc
-
-libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
-libprotoc_la_LDFLAGS = -version-info 9:1:0 -export-dynamic -no-undefined
-libprotoc_la_SOURCES = \
-  google/protobuf/compiler/code_generator.cc                   \
-  google/protobuf/compiler/command_line_interface.cc           \
-  google/protobuf/compiler/plugin.cc                           \
-  google/protobuf/compiler/plugin.pb.cc                        \
-  google/protobuf/compiler/subprocess.cc                       \
-  google/protobuf/compiler/subprocess.h                        \
-  google/protobuf/compiler/zip_writer.cc                       \
-  google/protobuf/compiler/zip_writer.h                        \
-  google/protobuf/compiler/cpp/cpp_enum.cc                     \
-  google/protobuf/compiler/cpp/cpp_enum.h                      \
-  google/protobuf/compiler/cpp/cpp_enum_field.cc               \
-  google/protobuf/compiler/cpp/cpp_enum_field.h                \
-  google/protobuf/compiler/cpp/cpp_extension.cc                \
-  google/protobuf/compiler/cpp/cpp_extension.h                 \
-  google/protobuf/compiler/cpp/cpp_field.cc                    \
-  google/protobuf/compiler/cpp/cpp_field.h                     \
-  google/protobuf/compiler/cpp/cpp_file.cc                     \
-  google/protobuf/compiler/cpp/cpp_file.h                      \
-  google/protobuf/compiler/cpp/cpp_generator.cc                \
-  google/protobuf/compiler/cpp/cpp_helpers.cc                  \
-  google/protobuf/compiler/cpp/cpp_helpers.h                   \
-  google/protobuf/compiler/cpp/cpp_message.cc                  \
-  google/protobuf/compiler/cpp/cpp_message.h                   \
-  google/protobuf/compiler/cpp/cpp_message_field.cc            \
-  google/protobuf/compiler/cpp/cpp_message_field.h             \
-  google/protobuf/compiler/cpp/cpp_options.h                   \
-  google/protobuf/compiler/cpp/cpp_primitive_field.cc          \
-  google/protobuf/compiler/cpp/cpp_primitive_field.h           \
-  google/protobuf/compiler/cpp/cpp_service.cc                  \
-  google/protobuf/compiler/cpp/cpp_service.h                   \
-  google/protobuf/compiler/cpp/cpp_string_field.cc             \
-  google/protobuf/compiler/cpp/cpp_string_field.h              \
-  google/protobuf/compiler/java/java_context.cc                \
-  google/protobuf/compiler/java/java_context.h                 \
-  google/protobuf/compiler/java/java_enum.cc                   \
-  google/protobuf/compiler/java/java_enum.h                    \
-  google/protobuf/compiler/java/java_enum_field.cc             \
-  google/protobuf/compiler/java/java_enum_field.h              \
-  google/protobuf/compiler/java/java_extension.cc              \
-  google/protobuf/compiler/java/java_extension.h               \
-  google/protobuf/compiler/java/java_field.cc                  \
-  google/protobuf/compiler/java/java_field.h                   \
-  google/protobuf/compiler/java/java_file.cc                   \
-  google/protobuf/compiler/java/java_file.h                    \
-  google/protobuf/compiler/java/java_generator.cc              \
-  google/protobuf/compiler/java/java_generator_factory.cc      \
-  google/protobuf/compiler/java/java_generator_factory.h       \
-  google/protobuf/compiler/java/java_helpers.cc                \
-  google/protobuf/compiler/java/java_helpers.h                 \
-  google/protobuf/compiler/java/java_lazy_message_field.cc     \
-  google/protobuf/compiler/java/java_lazy_message_field.h      \
-  google/protobuf/compiler/java/java_message.cc                \
-  google/protobuf/compiler/java/java_message.h                 \
-  google/protobuf/compiler/java/java_message_field.cc          \
-  google/protobuf/compiler/java/java_message_field.h           \
-  google/protobuf/compiler/java/java_name_resolver.cc          \
-  google/protobuf/compiler/java/java_name_resolver.h           \
-  google/protobuf/compiler/java/java_primitive_field.cc        \
-  google/protobuf/compiler/java/java_primitive_field.h         \
-  google/protobuf/compiler/java/java_shared_code_generator.cc  \
-  google/protobuf/compiler/java/java_shared_code_generator.h   \
-  google/protobuf/compiler/java/java_service.cc                \
-  google/protobuf/compiler/java/java_service.h                 \
-  google/protobuf/compiler/java/java_string_field.cc           \
-  google/protobuf/compiler/java/java_string_field.h            \
-  google/protobuf/compiler/java/java_doc_comment.cc            \
-  google/protobuf/compiler/java/java_doc_comment.h             \
-  google/protobuf/compiler/javamicro/javamicro_enum.cc         \
-  google/protobuf/compiler/javamicro/javamicro_enum.h          \
-  google/protobuf/compiler/javamicro/javamicro_enum_field.cc   \
-  google/protobuf/compiler/javamicro/javamicro_enum_field.h    \
-  google/protobuf/compiler/javamicro/javamicro_field.cc        \
-  google/protobuf/compiler/javamicro/javamicro_field.h         \
-  google/protobuf/compiler/javamicro/javamicro_file.cc         \
-  google/protobuf/compiler/javamicro/javamicro_file.h          \
-  google/protobuf/compiler/javamicro/javamicro_generator.cc    \
-  google/protobuf/compiler/javamicro/javamicro_helpers.cc      \
-  google/protobuf/compiler/javamicro/javamicro_helpers.h       \
-  google/protobuf/compiler/javamicro/javamicro_message.cc      \
-  google/protobuf/compiler/javamicro/javamicro_message.h       \
-  google/protobuf/compiler/javamicro/javamicro_message_field.cc\
-  google/protobuf/compiler/javamicro/javamicro_message_field.h \
-  google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\
-  google/protobuf/compiler/javamicro/javamicro_primitive_field.h\
-  google/protobuf/compiler/javanano/javanano_enum.cc         \
-  google/protobuf/compiler/javanano/javanano_enum.h          \
-  google/protobuf/compiler/javanano/javanano_enum_field.cc   \
-  google/protobuf/compiler/javanano/javanano_enum_field.h    \
-  google/protobuf/compiler/javanano/javanano_extension.cc    \
-  google/protobuf/compiler/javanano/javanano_extension.h     \
-  google/protobuf/compiler/javanano/javanano_field.cc        \
-  google/protobuf/compiler/javanano/javanano_field.h         \
-  google/protobuf/compiler/javanano/javanano_file.cc         \
-  google/protobuf/compiler/javanano/javanano_file.h          \
-  google/protobuf/compiler/javanano/javanano_generator.cc    \
-  google/protobuf/compiler/javanano/javanano_helpers.cc      \
-  google/protobuf/compiler/javanano/javanano_helpers.h       \
-  google/protobuf/compiler/javanano/javanano_message.cc      \
-  google/protobuf/compiler/javanano/javanano_message.h       \
-  google/protobuf/compiler/javanano/javanano_message_field.cc\
-  google/protobuf/compiler/javanano/javanano_message_field.h \
-  google/protobuf/compiler/javanano/javanano_primitive_field.cc\
-  google/protobuf/compiler/javanano/javanano_primitive_field.h\
-  google/protobuf/compiler/python/python_generator.cc
-
-protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
-protoc_SOURCES = google/protobuf/compiler/main.cc
-
-# Tests ==============================================================
-protoc_inputs = \
-  google/protobuf/unittest.proto                               \
-  google/protobuf/unittest_empty.proto                         \
-  google/protobuf/unittest_import.proto                        \
-  google/protobuf/unittest_import_public.proto                 \
-  google/protobuf/unittest_mset.proto                          \
-  google/protobuf/unittest_optimize_for.proto                  \
-  google/protobuf/unittest_embed_optimize_for.proto            \
-  google/protobuf/unittest_custom_options.proto                \
-  google/protobuf/unittest_lite.proto                          \
-  google/protobuf/unittest_import_lite.proto                   \
-  google/protobuf/unittest_import_public_lite.proto            \
-  google/protobuf/unittest_lite_imports_nonlite.proto          \
-  google/protobuf/unittest_no_generic_services.proto           \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
-
-EXTRA_DIST = \
-  $(protoc_inputs)                                             \
-  solaris/libstdc++.la                                         \
-  google/protobuf/io/gzip_stream.h                             \
-  google/protobuf/io/gzip_stream_unittest.sh                   \
-  google/protobuf/testdata/golden_message                      \
-  google/protobuf/testdata/golden_message_oneof_implemented    \
-  google/protobuf/testdata/golden_packed_fields_message        \
-  google/protobuf/testdata/bad_utf8_string                     \
-  google/protobuf/testdata/text_format_unittest_data.txt       \
-  google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt  \
-  google/protobuf/testdata/text_format_unittest_data_pointy.txt             \
-  google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt       \
-  google/protobuf/testdata/text_format_unittest_extensions_data.txt         \
-  google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt  \
-  google/protobuf/package_info.h                               \
-  google/protobuf/io/package_info.h                            \
-  google/protobuf/compiler/package_info.h                      \
-  google/protobuf/compiler/zip_output_unittest.sh              \
-  google/protobuf/unittest_enormous_descriptor.proto
-
-protoc_lite_outputs = \
-  google/protobuf/unittest_lite.pb.cc                          \
-  google/protobuf/unittest_lite.pb.h                           \
-  google/protobuf/unittest_import_lite.pb.cc                   \
-  google/protobuf/unittest_import_lite.pb.h                    \
-  google/protobuf/unittest_import_public_lite.pb.cc            \
-  google/protobuf/unittest_import_public_lite.pb.h
-
-protoc_outputs = \
-  $(protoc_lite_outputs)                                       \
-  google/protobuf/unittest.pb.cc                               \
-  google/protobuf/unittest.pb.h                                \
-  google/protobuf/unittest_empty.pb.cc                         \
-  google/protobuf/unittest_empty.pb.h                          \
-  google/protobuf/unittest_import.pb.cc                        \
-  google/protobuf/unittest_import.pb.h                         \
-  google/protobuf/unittest_import_public.pb.cc                 \
-  google/protobuf/unittest_import_public.pb.h                  \
-  google/protobuf/unittest_mset.pb.cc                          \
-  google/protobuf/unittest_mset.pb.h                           \
-  google/protobuf/unittest_optimize_for.pb.cc                  \
-  google/protobuf/unittest_optimize_for.pb.h                   \
-  google/protobuf/unittest_embed_optimize_for.pb.cc            \
-  google/protobuf/unittest_embed_optimize_for.pb.h             \
-  google/protobuf/unittest_custom_options.pb.cc                \
-  google/protobuf/unittest_custom_options.pb.h                 \
-  google/protobuf/unittest_lite_imports_nonlite.pb.cc          \
-  google/protobuf/unittest_lite_imports_nonlite.pb.h           \
-  google/protobuf/unittest_no_generic_services.pb.cc           \
-  google/protobuf/unittest_no_generic_services.pb.h            \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc  \
-  google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
-
-BUILT_SOURCES = $(protoc_outputs)
-COMMON_TEST_SOURCES = \
-  google/protobuf/test_util.cc                                 \
-  google/protobuf/test_util.h                                  \
-  google/protobuf/testing/googletest.cc                        \
-  google/protobuf/testing/googletest.h                         \
-  google/protobuf/testing/file.cc                              \
-  google/protobuf/testing/file.h
-
-protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
-                      $(top_builddir)/gtest/lib/libgtest.la       \
-                      $(top_builddir)/gtest/lib/libgtest_main.la
-
-protobuf_test_CPPFLAGS = -I$(top_srcdir)/gtest/include         \
-                         -I$(top_builddir)/gtest/include
-
-# Disable optimization for tests unless the user explicitly asked for it,
-# since test_util.cc takes forever to compile with optimization (with GCC).
-# See configure.ac for more info.
-protobuf_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
-protobuf_test_SOURCES = \
-  google/protobuf/stubs/common_unittest.cc                     \
-  google/protobuf/stubs/once_unittest.cc                       \
-  google/protobuf/stubs/strutil_unittest.cc                    \
-  google/protobuf/stubs/structurally_valid_unittest.cc         \
-  google/protobuf/stubs/stringprintf_unittest.cc               \
-  google/protobuf/stubs/template_util_unittest.cc              \
-  google/protobuf/stubs/type_traits_unittest.cc                \
-  google/protobuf/descriptor_database_unittest.cc              \
-  google/protobuf/descriptor_unittest.cc                       \
-  google/protobuf/dynamic_message_unittest.cc                  \
-  google/protobuf/extension_set_unittest.cc                    \
-  google/protobuf/generated_message_reflection_unittest.cc     \
-  google/protobuf/message_unittest.cc                          \
-  google/protobuf/reflection_ops_unittest.cc                   \
-  google/protobuf/repeated_field_unittest.cc                   \
-  google/protobuf/repeated_field_reflection_unittest.cc        \
-  google/protobuf/text_format_unittest.cc                      \
-  google/protobuf/unknown_field_set_unittest.cc                \
-  google/protobuf/wire_format_unittest.cc                      \
-  google/protobuf/io/coded_stream_unittest.cc                  \
-  google/protobuf/io/printer_unittest.cc                       \
-  google/protobuf/io/tokenizer_unittest.cc                     \
-  google/protobuf/io/zero_copy_stream_unittest.cc              \
-  google/protobuf/compiler/command_line_interface_unittest.cc  \
-  google/protobuf/compiler/importer_unittest.cc                \
-  google/protobuf/compiler/mock_code_generator.cc              \
-  google/protobuf/compiler/mock_code_generator.h               \
-  google/protobuf/compiler/parser_unittest.cc                  \
-  google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc       \
-  google/protobuf/compiler/cpp/cpp_unittest.h                  \
-  google/protobuf/compiler/cpp/cpp_unittest.cc                 \
-  google/protobuf/compiler/cpp/cpp_plugin_unittest.cc          \
-  google/protobuf/compiler/java/java_plugin_unittest.cc        \
-  google/protobuf/compiler/java/java_doc_comment_unittest.cc   \
-  google/protobuf/compiler/python/python_plugin_unittest.cc    \
-  $(COMMON_TEST_SOURCES)
-
-nodist_protobuf_test_SOURCES = $(protoc_outputs)
-
-# Run cpp_unittest again with PROTOBUF_TEST_NO_DESCRIPTORS defined.
-protobuf_lazy_descriptor_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \
-                      libprotoc.la                                   \
-                      $(top_builddir)/gtest/lib/libgtest.la          \
-                      $(top_builddir)/gtest/lib/libgtest_main.la
-
-protobuf_lazy_descriptor_test_CPPFLAGS = -I$(top_srcdir)/gtest/include    \
-                                         -I$(top_builddir)/gtest/include  \
-                                         -DPROTOBUF_TEST_NO_DESCRIPTORS
-
-protobuf_lazy_descriptor_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
-protobuf_lazy_descriptor_test_SOURCES = \
-  google/protobuf/compiler/cpp/cpp_unittest.cc                 \
-  $(COMMON_TEST_SOURCES)
-
-nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
-
-# Build lite_unittest separately, since it doesn't use gtest.
-protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la
-protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
-protobuf_lite_test_SOURCES = \
-  google/protobuf/lite_unittest.cc                                     \
-  google/protobuf/test_util_lite.cc                                    \
-  google/protobuf/test_util_lite.h
-
-nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
-
-# Test plugin binary.
-test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
-                    $(top_builddir)/gtest/lib/libgtest.la
-
-test_plugin_CPPFLAGS = -I$(top_srcdir)/gtest/include         \
-                       -I$(top_builddir)/gtest/include
-
-test_plugin_SOURCES = \
-  google/protobuf/compiler/mock_code_generator.cc              \
-  google/protobuf/testing/file.cc                              \
-  google/protobuf/testing/file.h                               \
-  google/protobuf/compiler/test_plugin.cc
-
-@HAVE_ZLIB_TRUE@zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
-@HAVE_ZLIB_TRUE@zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc
-@HAVE_ZLIB_TRUE@zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
-@HAVE_ZLIB_TRUE@zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
-all: $(BUILT_SOURCES)
-	$(MAKE) $(AM_MAKEFLAGS) all-am
-
-.SUFFIXES:
-.SUFFIXES: .cc .lo .log .o .obj .test .test$(EXEEXT) .trs
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-	@for dep in $?; do \
-	  case '$(am__configure_deps)' in \
-	    *$$dep*) \
-	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-	        && { if test -f $@; then exit 0; else break; fi; }; \
-	      exit 1;; \
-	  esac; \
-	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
-	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign src/Makefile
-.PRECIOUS: Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-	@case '$?' in \
-	  *config.status*) \
-	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-	  *) \
-	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-	esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-install-libLTLIBRARIES: $(lib_LTLIBRARIES)
-	@$(NORMAL_INSTALL)
-	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
-	list2=; for p in $$list; do \
-	  if test -f $$p; then \
-	    list2="$$list2 $$p"; \
-	  else :; fi; \
-	done; \
-	test -z "$$list2" || { \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
-	}
-
-uninstall-libLTLIBRARIES:
-	@$(NORMAL_UNINSTALL)
-	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
-	for p in $$list; do \
-	  $(am__strip_dir) \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
-	done
-
-clean-libLTLIBRARIES:
-	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
-	@list='$(lib_LTLIBRARIES)'; \
-	locs=`for p in $$list; do echo $$p; done | \
-	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
-	      sort -u`; \
-	test -z "$$locs" || { \
-	  echo rm -f $${locs}; \
-	  rm -f $${locs}; \
-	}
-google/protobuf/stubs/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/stubs
-	@: > google/protobuf/stubs/$(am__dirstamp)
-google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/stubs/$(DEPDIR)
-	@: > google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/atomicops_internals_x86_gcc.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/atomicops_internals_x86_msvc.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/common.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/once.lo: google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/stringprintf.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf
-	@: > google/protobuf/$(am__dirstamp)
-google/protobuf/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/$(DEPDIR)
-	@: > google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/extension_set.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/generated_message_util.lo:  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/message_lite.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/repeated_field.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/wire_format_lite.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/io
-	@: > google/protobuf/io/$(am__dirstamp)
-google/protobuf/io/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/io/$(DEPDIR)
-	@: > google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/coded_stream.lo:  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/zero_copy_stream.lo:  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/zero_copy_stream_impl_lite.lo:  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-
-libprotobuf-lite.la: $(libprotobuf_lite_la_OBJECTS) $(libprotobuf_lite_la_DEPENDENCIES) $(EXTRA_libprotobuf_lite_la_DEPENDENCIES) 
-	$(AM_V_CXXLD)$(libprotobuf_lite_la_LINK) -rpath $(libdir) $(libprotobuf_lite_la_OBJECTS) $(libprotobuf_lite_la_LIBADD) $(LIBS)
-google/protobuf/stubs/strutil.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/substitute.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/structurally_valid.lo:  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/descriptor.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/descriptor.pb.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/descriptor_database.lo:  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/dynamic_message.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/extension_set_heavy.lo:  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/generated_message_reflection.lo:  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/message.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/reflection_ops.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/service.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/text_format.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/unknown_field_set.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/wire_format.lo: google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/gzip_stream.lo: google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/printer.lo: google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/strtod.lo: google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/tokenizer.lo: google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/zero_copy_stream_impl.lo:  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler
-	@: > google/protobuf/compiler/$(am__dirstamp)
-google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/$(DEPDIR)
-	@: > google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/importer.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/parser.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-
-libprotobuf.la: $(libprotobuf_la_OBJECTS) $(libprotobuf_la_DEPENDENCIES) $(EXTRA_libprotobuf_la_DEPENDENCIES) 
-	$(AM_V_CXXLD)$(libprotobuf_la_LINK) -rpath $(libdir) $(libprotobuf_la_OBJECTS) $(libprotobuf_la_LIBADD) $(LIBS)
-google/protobuf/compiler/code_generator.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/command_line_interface.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/plugin.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/plugin.pb.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/subprocess.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/zip_writer.lo:  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/cpp
-	@: > google/protobuf/compiler/cpp/$(am__dirstamp)
-google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/cpp/$(DEPDIR)
-	@: > google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_enum.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_enum_field.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_extension.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_field.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_file.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_generator.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_helpers.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_message.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_message_field.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_primitive_field.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_service.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/cpp_string_field.lo:  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/java
-	@: > google/protobuf/compiler/java/$(am__dirstamp)
-google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/java/$(DEPDIR)
-	@: > google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_context.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_enum.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_enum_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_extension.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_file.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_generator.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_generator_factory.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_helpers.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_lazy_message_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_message.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_message_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_name_resolver.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_primitive_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_shared_code_generator.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_service.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_string_field.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/java_doc_comment.lo:  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/javamicro
-	@: > google/protobuf/compiler/javamicro/$(am__dirstamp)
-google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/javamicro/$(DEPDIR)
-	@: > google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_enum.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_enum_field.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_field.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_file.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_generator.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_helpers.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_message.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_message_field.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javamicro/javamicro_primitive_field.lo:  \
-	google/protobuf/compiler/javamicro/$(am__dirstamp) \
-	google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/javanano
-	@: > google/protobuf/compiler/javanano/$(am__dirstamp)
-google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/javanano/$(DEPDIR)
-	@: > google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_enum.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_enum_field.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_extension.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_field.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_file.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_generator.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_helpers.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_message.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_message_field.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/javanano/javanano_primitive_field.lo:  \
-	google/protobuf/compiler/javanano/$(am__dirstamp) \
-	google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/python/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/python
-	@: > google/protobuf/compiler/python/$(am__dirstamp)
-google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/compiler/python/$(DEPDIR)
-	@: > google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/python/python_generator.lo:  \
-	google/protobuf/compiler/python/$(am__dirstamp) \
-	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
-
-libprotoc.la: $(libprotoc_la_OBJECTS) $(libprotoc_la_DEPENDENCIES) $(EXTRA_libprotoc_la_DEPENDENCIES) 
-	$(AM_V_CXXLD)$(libprotoc_la_LINK) -rpath $(libdir) $(libprotoc_la_OBJECTS) $(libprotoc_la_LIBADD) $(LIBS)
-install-binPROGRAMS: $(bin_PROGRAMS)
-	@$(NORMAL_INSTALL)
-	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
-	if test -n "$$list"; then \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
-	fi; \
-	for p in $$list; do echo "$$p $$p"; done | \
-	sed 's/$(EXEEXT)$$//' | \
-	while read p p1; do if test -f $$p \
-	 || test -f $$p1 \
-	  ; then echo "$$p"; echo "$$p"; else :; fi; \
-	done | \
-	sed -e 'p;s,.*/,,;n;h' \
-	    -e 's|.*|.|' \
-	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
-	sed 'N;N;N;s,\n, ,g' | \
-	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
-	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
-	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
-	    else { print "f", $$3 "/" $$4, $$1; } } \
-	  END { for (d in files) print "f", d, files[d] }' | \
-	while read type dir files; do \
-	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
-	    test -z "$$files" || { \
-	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
-	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
-	    } \
-	; done
-
-uninstall-binPROGRAMS:
-	@$(NORMAL_UNINSTALL)
-	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
-	files=`for p in $$list; do echo "$$p"; done | \
-	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-	      -e 's/$$/$(EXEEXT)/' \
-	`; \
-	test -n "$$list" || exit 0; \
-	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
-	cd "$(DESTDIR)$(bindir)" && rm -f $$files
-
-clean-binPROGRAMS:
-	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
-	echo " rm -f" $$list; \
-	rm -f $$list || exit $$?; \
-	test -n "$(EXEEXT)" || exit 0; \
-	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-	echo " rm -f" $$list; \
-	rm -f $$list
-
-clean-checkPROGRAMS:
-	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
-	echo " rm -f" $$list; \
-	rm -f $$list || exit $$?; \
-	test -n "$(EXEEXT)" || exit 0; \
-	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-	echo " rm -f" $$list; \
-	rm -f $$list
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-test_util.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/testing
-	@: > google/protobuf/testing/$(am__dirstamp)
-google/protobuf/testing/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) google/protobuf/testing/$(DEPDIR)
-	@: > google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/protobuf_lazy_descriptor_test-file.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-
-protobuf-lazy-descriptor-test$(EXEEXT): $(protobuf_lazy_descriptor_test_OBJECTS) $(protobuf_lazy_descriptor_test_DEPENDENCIES) $(EXTRA_protobuf_lazy_descriptor_test_DEPENDENCIES) 
-	@rm -f protobuf-lazy-descriptor-test$(EXEEXT)
-	$(AM_V_CXXLD)$(protobuf_lazy_descriptor_test_LINK) $(protobuf_lazy_descriptor_test_OBJECTS) $(protobuf_lazy_descriptor_test_LDADD) $(LIBS)
-google/protobuf/protobuf_lite_test-lite_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lite_test-test_util_lite.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lite_test-unittest_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lite_test-unittest_import_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-
-protobuf-lite-test$(EXEEXT): $(protobuf_lite_test_OBJECTS) $(protobuf_lite_test_DEPENDENCIES) $(EXTRA_protobuf_lite_test_DEPENDENCIES) 
-	@rm -f protobuf-lite-test$(EXEEXT)
-	$(AM_V_CXXLD)$(protobuf_lite_test_LINK) $(protobuf_lite_test_OBJECTS) $(protobuf_lite_test_LDADD) $(LIBS)
-google/protobuf/stubs/protobuf_test-common_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-once_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-strutil_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-structurally_valid_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-stringprintf_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-template_util_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/stubs/protobuf_test-type_traits_unittest.$(OBJEXT):  \
-	google/protobuf/stubs/$(am__dirstamp) \
-	google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-descriptor_database_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-descriptor_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-dynamic_message_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-extension_set_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-generated_message_reflection_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-message_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-reflection_ops_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-repeated_field_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-repeated_field_reflection_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-text_format_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unknown_field_set_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-wire_format_unittest.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/protobuf_test-coded_stream_unittest.$(OBJEXT):  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/protobuf_test-printer_unittest.$(OBJEXT):  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/protobuf_test-tokenizer_unittest.$(OBJEXT):  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/io/protobuf_test-zero_copy_stream_unittest.$(OBJEXT):  \
-	google/protobuf/io/$(am__dirstamp) \
-	google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/protobuf_test-command_line_interface_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/protobuf_test-importer_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/protobuf_test-mock_code_generator.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/protobuf_test-parser_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/java/$(am__dirstamp) \
-	google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.$(OBJEXT):  \
-	google/protobuf/compiler/python/$(am__dirstamp) \
-	google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-test_util.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/protobuf_test-googletest.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/protobuf_test-file.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_import_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_import_public_lite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_empty.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_import.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_import_public.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_mset.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_optimize_for.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_custom_options.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/protobuf_test-unittest_no_generic_services.pb.$(OBJEXT):  \
-	google/protobuf/$(am__dirstamp) \
-	google/protobuf/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.$(OBJEXT):  \
-	google/protobuf/compiler/cpp/$(am__dirstamp) \
-	google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-
-protobuf-test$(EXEEXT): $(protobuf_test_OBJECTS) $(protobuf_test_DEPENDENCIES) $(EXTRA_protobuf_test_DEPENDENCIES) 
-	@rm -f protobuf-test$(EXEEXT)
-	$(AM_V_CXXLD)$(protobuf_test_LINK) $(protobuf_test_OBJECTS) $(protobuf_test_LDADD) $(LIBS)
-google/protobuf/compiler/main.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-
-protoc$(EXEEXT): $(protoc_OBJECTS) $(protoc_DEPENDENCIES) $(EXTRA_protoc_DEPENDENCIES) 
-	@rm -f protoc$(EXEEXT)
-	$(AM_V_CXXLD)$(CXXLINK) $(protoc_OBJECTS) $(protoc_LDADD) $(LIBS)
-google/protobuf/compiler/test_plugin-mock_code_generator.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/testing/test_plugin-file.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-google/protobuf/compiler/test_plugin-test_plugin.$(OBJEXT):  \
-	google/protobuf/compiler/$(am__dirstamp) \
-	google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-
-test_plugin$(EXEEXT): $(test_plugin_OBJECTS) $(test_plugin_DEPENDENCIES) $(EXTRA_test_plugin_DEPENDENCIES) 
-	@rm -f test_plugin$(EXEEXT)
-	$(AM_V_CXXLD)$(CXXLINK) $(test_plugin_OBJECTS) $(test_plugin_LDADD) $(LIBS)
-google/protobuf/testing/zcgunzip.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-
-zcgunzip$(EXEEXT): $(zcgunzip_OBJECTS) $(zcgunzip_DEPENDENCIES) $(EXTRA_zcgunzip_DEPENDENCIES) 
-	@rm -f zcgunzip$(EXEEXT)
-	$(AM_V_CXXLD)$(CXXLINK) $(zcgunzip_OBJECTS) $(zcgunzip_LDADD) $(LIBS)
-google/protobuf/testing/zcgzip.$(OBJEXT):  \
-	google/protobuf/testing/$(am__dirstamp) \
-	google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-
-zcgzip$(EXEEXT): $(zcgzip_OBJECTS) $(zcgzip_DEPENDENCIES) $(EXTRA_zcgzip_DEPENDENCIES) 
-	@rm -f zcgzip$(EXEEXT)
-	$(AM_V_CXXLD)$(CXXLINK) $(zcgzip_OBJECTS) $(zcgzip_LDADD) $(LIBS)
-
-mostlyclean-compile:
-	-rm -f *.$(OBJEXT)
-	-rm -f google/protobuf/*.$(OBJEXT)
-	-rm -f google/protobuf/*.lo
-	-rm -f google/protobuf/compiler/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/*.lo
-	-rm -f google/protobuf/compiler/cpp/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/cpp/*.lo
-	-rm -f google/protobuf/compiler/java/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/java/*.lo
-	-rm -f google/protobuf/compiler/javamicro/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/javamicro/*.lo
-	-rm -f google/protobuf/compiler/javanano/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/javanano/*.lo
-	-rm -f google/protobuf/compiler/python/*.$(OBJEXT)
-	-rm -f google/protobuf/compiler/python/*.lo
-	-rm -f google/protobuf/io/*.$(OBJEXT)
-	-rm -f google/protobuf/io/*.lo
-	-rm -f google/protobuf/stubs/*.$(OBJEXT)
-	-rm -f google/protobuf/stubs/*.lo
-	-rm -f google/protobuf/testing/*.$(OBJEXT)
-
-distclean-compile:
-	-rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor.pb.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/descriptor_database.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/dynamic_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/extension_set.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/extension_set_heavy.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_reflection.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/generated_message_util.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/message_lite.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/reflection_ops.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/repeated_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/service.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/text_format.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/unknown_field_set.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/wire_format.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/$(DEPDIR)/wire_format_lite.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/code_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/command_line_interface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/importer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/parser.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/plugin.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/plugin.pb.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/subprocess.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/$(DEPDIR)/zip_writer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_enum.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_enum_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_extension.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_file.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_helpers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_message_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_primitive_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_service.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/cpp_string_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_context.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_doc_comment.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_enum.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_enum_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_extension.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_file.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_generator_factory.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_helpers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_lazy_message_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_message_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_name_resolver.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_primitive_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_service.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_shared_code_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/java_string_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_enum.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_enum_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_file.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_helpers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_message_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javamicro/$(DEPDIR)/javamicro_primitive_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_enum.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_enum_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_extension.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_file.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_helpers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_message.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_message_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/javanano/$(DEPDIR)/javanano_primitive_field.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/compiler/python/$(DEPDIR)/python_generator.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/coded_stream.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/gzip_stream.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/printer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/strtod.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/tokenizer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/io/$(DEPDIR)/zero_copy_stream_impl_lite.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/atomicops_internals_x86_gcc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/atomicops_internals_x86_msvc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/common.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/once.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/stringprintf.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/structurally_valid.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/strutil.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/stubs/$(DEPDIR)/substitute.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/zcgunzip.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@google/protobuf/testing/$(DEPDIR)/zcgzip.Po@am__quote@
-
-.cc.o:
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
-@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
-
-.cc.obj:
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
-@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
-@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
-
-.cc.lo:
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
-@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
-
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.o: google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_unittest.cc
-
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.obj: google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_unittest.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-test_util.o: google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-test_util.obj: google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-test_util.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_lazy_descriptor_test-test_util.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
-
-google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o: google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
-
-google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj: google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-googletest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
-
-google/protobuf/testing/protobuf_lazy_descriptor_test-file.o: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-file.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-
-google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_lazy_descriptor_test-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_lazy_descriptor_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o: google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj: google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o: google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj: google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_empty.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o: google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj: google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o: google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj: google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_import_public.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o: google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj: google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_mset.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o: google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj: google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o: google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj: google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o: google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj: google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_custom_options.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o: google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj: google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o: google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
-
-google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj: google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lazy_descriptor_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
-
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.o: google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-
-google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.obj: google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_lazy_descriptor_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_lazy_descriptor_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_lazy_descriptor_test-cpp_test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; fi`
-
-google/protobuf/protobuf_lite_test-lite_unittest.o: google/protobuf/lite_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-lite_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo -c -o google/protobuf/protobuf_lite_test-lite_unittest.o `test -f 'google/protobuf/lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_unittest.cc' object='google/protobuf/protobuf_lite_test-lite_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-lite_unittest.o `test -f 'google/protobuf/lite_unittest.cc' || echo '$(srcdir)/'`google/protobuf/lite_unittest.cc
-
-google/protobuf/protobuf_lite_test-lite_unittest.obj: google/protobuf/lite_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-lite_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo -c -o google/protobuf/protobuf_lite_test-lite_unittest.obj `if test -f 'google/protobuf/lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-lite_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/lite_unittest.cc' object='google/protobuf/protobuf_lite_test-lite_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-lite_unittest.obj `if test -f 'google/protobuf/lite_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/lite_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/lite_unittest.cc'; fi`
-
-google/protobuf/protobuf_lite_test-test_util_lite.o: google/protobuf/test_util_lite.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-test_util_lite.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_test-test_util_lite.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-test_util_lite.o `test -f 'google/protobuf/test_util_lite.cc' || echo '$(srcdir)/'`google/protobuf/test_util_lite.cc
-
-google/protobuf/protobuf_lite_test-test_util_lite.obj: google/protobuf/test_util_lite.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-test_util_lite.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo -c -o google/protobuf/protobuf_lite_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-test_util_lite.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util_lite.cc' object='google/protobuf/protobuf_lite_test-test_util_lite.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-test_util_lite.obj `if test -f 'google/protobuf/test_util_lite.cc'; then $(CYGPATH_W) 'google/protobuf/test_util_lite.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util_lite.cc'; fi`
-
-google/protobuf/protobuf_lite_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-
-google/protobuf/protobuf_lite_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-
-google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-
-google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_lite_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(protobuf_lite_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_lite_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-common_unittest.o: google/protobuf/stubs/common_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-common_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-common_unittest.o `test -f 'google/protobuf/stubs/common_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/common_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/common_unittest.cc' object='google/protobuf/stubs/protobuf_test-common_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-common_unittest.o `test -f 'google/protobuf/stubs/common_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/common_unittest.cc
-
-google/protobuf/stubs/protobuf_test-common_unittest.obj: google/protobuf/stubs/common_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-common_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-common_unittest.obj `if test -f 'google/protobuf/stubs/common_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/common_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-common_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/common_unittest.cc' object='google/protobuf/stubs/protobuf_test-common_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-common_unittest.obj `if test -f 'google/protobuf/stubs/common_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/common_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-once_unittest.o: google/protobuf/stubs/once_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-once_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-once_unittest.o `test -f 'google/protobuf/stubs/once_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/once_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/once_unittest.cc' object='google/protobuf/stubs/protobuf_test-once_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-once_unittest.o `test -f 'google/protobuf/stubs/once_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/once_unittest.cc
-
-google/protobuf/stubs/protobuf_test-once_unittest.obj: google/protobuf/stubs/once_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-once_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-once_unittest.obj `if test -f 'google/protobuf/stubs/once_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/once_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/once_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-once_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/once_unittest.cc' object='google/protobuf/stubs/protobuf_test-once_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-once_unittest.obj `if test -f 'google/protobuf/stubs/once_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/once_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/once_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-strutil_unittest.o: google/protobuf/stubs/strutil_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-strutil_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.o `test -f 'google/protobuf/stubs/strutil_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/strutil_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/strutil_unittest.cc' object='google/protobuf/stubs/protobuf_test-strutil_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.o `test -f 'google/protobuf/stubs/strutil_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/strutil_unittest.cc
-
-google/protobuf/stubs/protobuf_test-strutil_unittest.obj: google/protobuf/stubs/strutil_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-strutil_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.obj `if test -f 'google/protobuf/stubs/strutil_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/strutil_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-strutil_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/strutil_unittest.cc' object='google/protobuf/stubs/protobuf_test-strutil_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-strutil_unittest.obj `if test -f 'google/protobuf/stubs/strutil_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/strutil_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o: google/protobuf/stubs/structurally_valid_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o `test -f 'google/protobuf/stubs/structurally_valid_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/structurally_valid_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/structurally_valid_unittest.cc' object='google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.o `test -f 'google/protobuf/stubs/structurally_valid_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/structurally_valid_unittest.cc
-
-google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj: google/protobuf/stubs/structurally_valid_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj `if test -f 'google/protobuf/stubs/structurally_valid_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/structurally_valid_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/structurally_valid_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-structurally_valid_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/structurally_valid_unittest.cc' object='google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-structurally_valid_unittest.obj `if test -f 'google/protobuf/stubs/structurally_valid_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/structurally_valid_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/structurally_valid_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-stringprintf_unittest.o: google/protobuf/stubs/stringprintf_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringprintf_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.o `test -f 'google/protobuf/stubs/stringprintf_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringprintf_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringprintf_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringprintf_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.o `test -f 'google/protobuf/stubs/stringprintf_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/stringprintf_unittest.cc
-
-google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj: google/protobuf/stubs/stringprintf_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj `if test -f 'google/protobuf/stubs/stringprintf_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringprintf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringprintf_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-stringprintf_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/stringprintf_unittest.cc' object='google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-stringprintf_unittest.obj `if test -f 'google/protobuf/stubs/stringprintf_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/stringprintf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/stringprintf_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-template_util_unittest.o: google/protobuf/stubs/template_util_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-template_util_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.o `test -f 'google/protobuf/stubs/template_util_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/template_util_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/template_util_unittest.cc' object='google/protobuf/stubs/protobuf_test-template_util_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.o `test -f 'google/protobuf/stubs/template_util_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/template_util_unittest.cc
-
-google/protobuf/stubs/protobuf_test-template_util_unittest.obj: google/protobuf/stubs/template_util_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-template_util_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.obj `if test -f 'google/protobuf/stubs/template_util_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/template_util_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/template_util_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-template_util_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/template_util_unittest.cc' object='google/protobuf/stubs/protobuf_test-template_util_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-template_util_unittest.obj `if test -f 'google/protobuf/stubs/template_util_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/template_util_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/template_util_unittest.cc'; fi`
-
-google/protobuf/stubs/protobuf_test-type_traits_unittest.o: google/protobuf/stubs/type_traits_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-type_traits_unittest.o -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-type_traits_unittest.o `test -f 'google/protobuf/stubs/type_traits_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/type_traits_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/type_traits_unittest.cc' object='google/protobuf/stubs/protobuf_test-type_traits_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-type_traits_unittest.o `test -f 'google/protobuf/stubs/type_traits_unittest.cc' || echo '$(srcdir)/'`google/protobuf/stubs/type_traits_unittest.cc
-
-google/protobuf/stubs/protobuf_test-type_traits_unittest.obj: google/protobuf/stubs/type_traits_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/stubs/protobuf_test-type_traits_unittest.obj -MD -MP -MF google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Tpo -c -o google/protobuf/stubs/protobuf_test-type_traits_unittest.obj `if test -f 'google/protobuf/stubs/type_traits_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/type_traits_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/type_traits_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Tpo google/protobuf/stubs/$(DEPDIR)/protobuf_test-type_traits_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/stubs/type_traits_unittest.cc' object='google/protobuf/stubs/protobuf_test-type_traits_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/stubs/protobuf_test-type_traits_unittest.obj `if test -f 'google/protobuf/stubs/type_traits_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/stubs/type_traits_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/stubs/type_traits_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-descriptor_database_unittest.o: google/protobuf/descriptor_database_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_database_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_database_unittest.o `test -f 'google/protobuf/descriptor_database_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_database_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_database_unittest.cc' object='google/protobuf/protobuf_test-descriptor_database_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_database_unittest.o `test -f 'google/protobuf/descriptor_database_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_database_unittest.cc
-
-google/protobuf/protobuf_test-descriptor_database_unittest.obj: google/protobuf/descriptor_database_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_database_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_database_unittest.obj `if test -f 'google/protobuf/descriptor_database_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_database_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_database_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_database_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_database_unittest.cc' object='google/protobuf/protobuf_test-descriptor_database_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_database_unittest.obj `if test -f 'google/protobuf/descriptor_database_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_database_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_database_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-descriptor_unittest.o: google/protobuf/descriptor_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_unittest.o `test -f 'google/protobuf/descriptor_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_unittest.cc' object='google/protobuf/protobuf_test-descriptor_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_unittest.o `test -f 'google/protobuf/descriptor_unittest.cc' || echo '$(srcdir)/'`google/protobuf/descriptor_unittest.cc
-
-google/protobuf/protobuf_test-descriptor_unittest.obj: google/protobuf/descriptor_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-descriptor_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo -c -o google/protobuf/protobuf_test-descriptor_unittest.obj `if test -f 'google/protobuf/descriptor_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-descriptor_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/descriptor_unittest.cc' object='google/protobuf/protobuf_test-descriptor_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-descriptor_unittest.obj `if test -f 'google/protobuf/descriptor_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/descriptor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/descriptor_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-dynamic_message_unittest.o: google/protobuf/dynamic_message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-dynamic_message_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo -c -o google/protobuf/protobuf_test-dynamic_message_unittest.o `test -f 'google/protobuf/dynamic_message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/dynamic_message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/dynamic_message_unittest.cc' object='google/protobuf/protobuf_test-dynamic_message_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-dynamic_message_unittest.o `test -f 'google/protobuf/dynamic_message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/dynamic_message_unittest.cc
-
-google/protobuf/protobuf_test-dynamic_message_unittest.obj: google/protobuf/dynamic_message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-dynamic_message_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo -c -o google/protobuf/protobuf_test-dynamic_message_unittest.obj `if test -f 'google/protobuf/dynamic_message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/dynamic_message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/dynamic_message_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-dynamic_message_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/dynamic_message_unittest.cc' object='google/protobuf/protobuf_test-dynamic_message_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-dynamic_message_unittest.obj `if test -f 'google/protobuf/dynamic_message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/dynamic_message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/dynamic_message_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-extension_set_unittest.o: google/protobuf/extension_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-extension_set_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo -c -o google/protobuf/protobuf_test-extension_set_unittest.o `test -f 'google/protobuf/extension_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/extension_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/extension_set_unittest.cc' object='google/protobuf/protobuf_test-extension_set_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-extension_set_unittest.o `test -f 'google/protobuf/extension_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/extension_set_unittest.cc
-
-google/protobuf/protobuf_test-extension_set_unittest.obj: google/protobuf/extension_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-extension_set_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo -c -o google/protobuf/protobuf_test-extension_set_unittest.obj `if test -f 'google/protobuf/extension_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/extension_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/extension_set_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-extension_set_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/extension_set_unittest.cc' object='google/protobuf/protobuf_test-extension_set_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-extension_set_unittest.obj `if test -f 'google/protobuf/extension_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/extension_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/extension_set_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-generated_message_reflection_unittest.o: google/protobuf/generated_message_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_reflection_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.o `test -f 'google/protobuf/generated_message_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_reflection_unittest.cc' object='google/protobuf/protobuf_test-generated_message_reflection_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.o `test -f 'google/protobuf/generated_message_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/generated_message_reflection_unittest.cc
-
-google/protobuf/protobuf_test-generated_message_reflection_unittest.obj: google/protobuf/generated_message_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-generated_message_reflection_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.obj `if test -f 'google/protobuf/generated_message_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_reflection_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-generated_message_reflection_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/generated_message_reflection_unittest.cc' object='google/protobuf/protobuf_test-generated_message_reflection_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-generated_message_reflection_unittest.obj `if test -f 'google/protobuf/generated_message_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/generated_message_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/generated_message_reflection_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-message_unittest.o: google/protobuf/message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-message_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo -c -o google/protobuf/protobuf_test-message_unittest.o `test -f 'google/protobuf/message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/message_unittest.cc' object='google/protobuf/protobuf_test-message_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-message_unittest.o `test -f 'google/protobuf/message_unittest.cc' || echo '$(srcdir)/'`google/protobuf/message_unittest.cc
-
-google/protobuf/protobuf_test-message_unittest.obj: google/protobuf/message_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-message_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo -c -o google/protobuf/protobuf_test-message_unittest.obj `if test -f 'google/protobuf/message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/message_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-message_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/message_unittest.cc' object='google/protobuf/protobuf_test-message_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-message_unittest.obj `if test -f 'google/protobuf/message_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/message_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/message_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-reflection_ops_unittest.o: google/protobuf/reflection_ops_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_ops_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo -c -o google/protobuf/protobuf_test-reflection_ops_unittest.o `test -f 'google/protobuf/reflection_ops_unittest.cc' || echo '$(srcdir)/'`google/protobuf/reflection_ops_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_ops_unittest.cc' object='google/protobuf/protobuf_test-reflection_ops_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_ops_unittest.o `test -f 'google/protobuf/reflection_ops_unittest.cc' || echo '$(srcdir)/'`google/protobuf/reflection_ops_unittest.cc
-
-google/protobuf/protobuf_test-reflection_ops_unittest.obj: google/protobuf/reflection_ops_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-reflection_ops_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo -c -o google/protobuf/protobuf_test-reflection_ops_unittest.obj `if test -f 'google/protobuf/reflection_ops_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_ops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_ops_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-reflection_ops_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/reflection_ops_unittest.cc' object='google/protobuf/protobuf_test-reflection_ops_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-reflection_ops_unittest.obj `if test -f 'google/protobuf/reflection_ops_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/reflection_ops_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/reflection_ops_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-repeated_field_unittest.o: google/protobuf/repeated_field_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_unittest.o `test -f 'google/protobuf/repeated_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_unittest.o `test -f 'google/protobuf/repeated_field_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_unittest.cc
-
-google/protobuf/protobuf_test-repeated_field_unittest.obj: google/protobuf/repeated_field_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_unittest.obj `if test -f 'google/protobuf/repeated_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_unittest.obj `if test -f 'google/protobuf/repeated_field_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-repeated_field_reflection_unittest.o: google/protobuf/repeated_field_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_reflection_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.o `test -f 'google/protobuf/repeated_field_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_reflection_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_reflection_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.o `test -f 'google/protobuf/repeated_field_reflection_unittest.cc' || echo '$(srcdir)/'`google/protobuf/repeated_field_reflection_unittest.cc
-
-google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj: google/protobuf/repeated_field_reflection_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj `if test -f 'google/protobuf/repeated_field_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_reflection_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-repeated_field_reflection_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/repeated_field_reflection_unittest.cc' object='google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-repeated_field_reflection_unittest.obj `if test -f 'google/protobuf/repeated_field_reflection_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/repeated_field_reflection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/repeated_field_reflection_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-text_format_unittest.o: google/protobuf/text_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-text_format_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo -c -o google/protobuf/protobuf_test-text_format_unittest.o `test -f 'google/protobuf/text_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/text_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/text_format_unittest.cc' object='google/protobuf/protobuf_test-text_format_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-text_format_unittest.o `test -f 'google/protobuf/text_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/text_format_unittest.cc
-
-google/protobuf/protobuf_test-text_format_unittest.obj: google/protobuf/text_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-text_format_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo -c -o google/protobuf/protobuf_test-text_format_unittest.obj `if test -f 'google/protobuf/text_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/text_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/text_format_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-text_format_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/text_format_unittest.cc' object='google/protobuf/protobuf_test-text_format_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-text_format_unittest.obj `if test -f 'google/protobuf/text_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/text_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/text_format_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-unknown_field_set_unittest.o: google/protobuf/unknown_field_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unknown_field_set_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.o `test -f 'google/protobuf/unknown_field_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/unknown_field_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unknown_field_set_unittest.cc' object='google/protobuf/protobuf_test-unknown_field_set_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.o `test -f 'google/protobuf/unknown_field_set_unittest.cc' || echo '$(srcdir)/'`google/protobuf/unknown_field_set_unittest.cc
-
-google/protobuf/protobuf_test-unknown_field_set_unittest.obj: google/protobuf/unknown_field_set_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unknown_field_set_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.obj `if test -f 'google/protobuf/unknown_field_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/unknown_field_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unknown_field_set_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unknown_field_set_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unknown_field_set_unittest.cc' object='google/protobuf/protobuf_test-unknown_field_set_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unknown_field_set_unittest.obj `if test -f 'google/protobuf/unknown_field_set_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/unknown_field_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unknown_field_set_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-wire_format_unittest.o: google/protobuf/wire_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-wire_format_unittest.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo -c -o google/protobuf/protobuf_test-wire_format_unittest.o `test -f 'google/protobuf/wire_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/wire_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/wire_format_unittest.cc' object='google/protobuf/protobuf_test-wire_format_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-wire_format_unittest.o `test -f 'google/protobuf/wire_format_unittest.cc' || echo '$(srcdir)/'`google/protobuf/wire_format_unittest.cc
-
-google/protobuf/protobuf_test-wire_format_unittest.obj: google/protobuf/wire_format_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-wire_format_unittest.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo -c -o google/protobuf/protobuf_test-wire_format_unittest.obj `if test -f 'google/protobuf/wire_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/wire_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/wire_format_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Tpo google/protobuf/$(DEPDIR)/protobuf_test-wire_format_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/wire_format_unittest.cc' object='google/protobuf/protobuf_test-wire_format_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-wire_format_unittest.obj `if test -f 'google/protobuf/wire_format_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/wire_format_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/wire_format_unittest.cc'; fi`
-
-google/protobuf/io/protobuf_test-coded_stream_unittest.o: google/protobuf/io/coded_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-coded_stream_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.o `test -f 'google/protobuf/io/coded_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/coded_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/coded_stream_unittest.cc' object='google/protobuf/io/protobuf_test-coded_stream_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.o `test -f 'google/protobuf/io/coded_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/coded_stream_unittest.cc
-
-google/protobuf/io/protobuf_test-coded_stream_unittest.obj: google/protobuf/io/coded_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-coded_stream_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.obj `if test -f 'google/protobuf/io/coded_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/coded_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/coded_stream_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-coded_stream_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/coded_stream_unittest.cc' object='google/protobuf/io/protobuf_test-coded_stream_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-coded_stream_unittest.obj `if test -f 'google/protobuf/io/coded_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/coded_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/coded_stream_unittest.cc'; fi`
-
-google/protobuf/io/protobuf_test-printer_unittest.o: google/protobuf/io/printer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-printer_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-printer_unittest.o `test -f 'google/protobuf/io/printer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/printer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/printer_unittest.cc' object='google/protobuf/io/protobuf_test-printer_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-printer_unittest.o `test -f 'google/protobuf/io/printer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/printer_unittest.cc
-
-google/protobuf/io/protobuf_test-printer_unittest.obj: google/protobuf/io/printer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-printer_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-printer_unittest.obj `if test -f 'google/protobuf/io/printer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/printer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/printer_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-printer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/printer_unittest.cc' object='google/protobuf/io/protobuf_test-printer_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-printer_unittest.obj `if test -f 'google/protobuf/io/printer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/printer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/printer_unittest.cc'; fi`
-
-google/protobuf/io/protobuf_test-tokenizer_unittest.o: google/protobuf/io/tokenizer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-tokenizer_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.o `test -f 'google/protobuf/io/tokenizer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/tokenizer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/tokenizer_unittest.cc' object='google/protobuf/io/protobuf_test-tokenizer_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.o `test -f 'google/protobuf/io/tokenizer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/tokenizer_unittest.cc
-
-google/protobuf/io/protobuf_test-tokenizer_unittest.obj: google/protobuf/io/tokenizer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-tokenizer_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.obj `if test -f 'google/protobuf/io/tokenizer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/tokenizer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/tokenizer_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-tokenizer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/tokenizer_unittest.cc' object='google/protobuf/io/protobuf_test-tokenizer_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-tokenizer_unittest.obj `if test -f 'google/protobuf/io/tokenizer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/tokenizer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/tokenizer_unittest.cc'; fi`
-
-google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o: google/protobuf/io/zero_copy_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o `test -f 'google/protobuf/io/zero_copy_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/zero_copy_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/zero_copy_stream_unittest.cc' object='google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.o `test -f 'google/protobuf/io/zero_copy_stream_unittest.cc' || echo '$(srcdir)/'`google/protobuf/io/zero_copy_stream_unittest.cc
-
-google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj: google/protobuf/io/zero_copy_stream_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj -MD -MP -MF google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj `if test -f 'google/protobuf/io/zero_copy_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/zero_copy_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/zero_copy_stream_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Tpo google/protobuf/io/$(DEPDIR)/protobuf_test-zero_copy_stream_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/io/zero_copy_stream_unittest.cc' object='google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/io/protobuf_test-zero_copy_stream_unittest.obj `if test -f 'google/protobuf/io/zero_copy_stream_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/io/zero_copy_stream_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/io/zero_copy_stream_unittest.cc'; fi`
-
-google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o: google/protobuf/compiler/command_line_interface_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o `test -f 'google/protobuf/compiler/command_line_interface_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/command_line_interface_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/command_line_interface_unittest.cc' object='google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.o `test -f 'google/protobuf/compiler/command_line_interface_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/command_line_interface_unittest.cc
-
-google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj: google/protobuf/compiler/command_line_interface_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj `if test -f 'google/protobuf/compiler/command_line_interface_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/command_line_interface_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/command_line_interface_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-command_line_interface_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/command_line_interface_unittest.cc' object='google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-command_line_interface_unittest.obj `if test -f 'google/protobuf/compiler/command_line_interface_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/command_line_interface_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/command_line_interface_unittest.cc'; fi`
-
-google/protobuf/compiler/protobuf_test-importer_unittest.o: google/protobuf/compiler/importer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-importer_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-importer_unittest.o `test -f 'google/protobuf/compiler/importer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/importer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/importer_unittest.cc' object='google/protobuf/compiler/protobuf_test-importer_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-importer_unittest.o `test -f 'google/protobuf/compiler/importer_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/importer_unittest.cc
-
-google/protobuf/compiler/protobuf_test-importer_unittest.obj: google/protobuf/compiler/importer_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-importer_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-importer_unittest.obj `if test -f 'google/protobuf/compiler/importer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/importer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/importer_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-importer_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/importer_unittest.cc' object='google/protobuf/compiler/protobuf_test-importer_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-importer_unittest.obj `if test -f 'google/protobuf/compiler/importer_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/importer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/importer_unittest.cc'; fi`
-
-google/protobuf/compiler/protobuf_test-mock_code_generator.o: google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-mock_code_generator.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/protobuf_test-mock_code_generator.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
-
-google/protobuf/compiler/protobuf_test-mock_code_generator.obj: google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-mock_code_generator.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-mock_code_generator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/protobuf_test-mock_code_generator.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
-
-google/protobuf/compiler/protobuf_test-parser_unittest.o: google/protobuf/compiler/parser_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-parser_unittest.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-parser_unittest.o `test -f 'google/protobuf/compiler/parser_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/parser_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/parser_unittest.cc' object='google/protobuf/compiler/protobuf_test-parser_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-parser_unittest.o `test -f 'google/protobuf/compiler/parser_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/parser_unittest.cc
-
-google/protobuf/compiler/protobuf_test-parser_unittest.obj: google/protobuf/compiler/parser_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/protobuf_test-parser_unittest.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo -c -o google/protobuf/compiler/protobuf_test-parser_unittest.obj `if test -f 'google/protobuf/compiler/parser_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/parser_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Tpo google/protobuf/compiler/$(DEPDIR)/protobuf_test-parser_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/parser_unittest.cc' object='google/protobuf/compiler/protobuf_test-parser_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/protobuf_test-parser_unittest.obj `if test -f 'google/protobuf/compiler/parser_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/parser_unittest.cc'; fi`
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.o: google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.obj: google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_bootstrap_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_bootstrap_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc'; fi`
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.o: google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_unittest.cc
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.obj: google/protobuf/compiler/cpp/cpp_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_unittest.cc'; fi`
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.o: google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_plugin_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.o `test -f 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.obj: google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_plugin_unittest.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_plugin_unittest.obj `if test -f 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc'; fi`
-
-google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.o: google/protobuf/compiler/java/java_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.o -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.o `test -f 'google/protobuf/compiler/java/java_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/java_plugin_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.o `test -f 'google/protobuf/compiler/java/java_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_plugin_unittest.cc
-
-google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.obj: google/protobuf/compiler/java/java_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.obj `if test -f 'google/protobuf/compiler/java/java_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/java_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/java_plugin_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/java_plugin_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-java_plugin_unittest.obj `if test -f 'google/protobuf/compiler/java/java_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/java_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/java_plugin_unittest.cc'; fi`
-
-google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.o: google/protobuf/compiler/java/java_doc_comment_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.o -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.o `test -f 'google/protobuf/compiler/java/java_doc_comment_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_doc_comment_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/java_doc_comment_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.o `test -f 'google/protobuf/compiler/java/java_doc_comment_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_doc_comment_unittest.cc
-
-google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.obj: google/protobuf/compiler/java/java_doc_comment_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.obj -MD -MP -MF google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Tpo -c -o google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.obj `if test -f 'google/protobuf/compiler/java/java_doc_comment_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/java_doc_comment_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/java_doc_comment_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Tpo google/protobuf/compiler/java/$(DEPDIR)/protobuf_test-java_doc_comment_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/java/java_doc_comment_unittest.cc' object='google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/java/protobuf_test-java_doc_comment_unittest.obj `if test -f 'google/protobuf/compiler/java/java_doc_comment_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/java/java_doc_comment_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/java/java_doc_comment_unittest.cc'; fi`
-
-google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.o: google/protobuf/compiler/python/python_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.o -MD -MP -MF google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Tpo -c -o google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.o `test -f 'google/protobuf/compiler/python/python_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/python_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Tpo google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/python/python_plugin_unittest.cc' object='google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.o `test -f 'google/protobuf/compiler/python/python_plugin_unittest.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/python_plugin_unittest.cc
-
-google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.obj: google/protobuf/compiler/python/python_plugin_unittest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.obj -MD -MP -MF google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Tpo -c -o google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.obj `if test -f 'google/protobuf/compiler/python/python_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/python/python_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/python/python_plugin_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Tpo google/protobuf/compiler/python/$(DEPDIR)/protobuf_test-python_plugin_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/python/python_plugin_unittest.cc' object='google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/python/protobuf_test-python_plugin_unittest.obj `if test -f 'google/protobuf/compiler/python/python_plugin_unittest.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/python/python_plugin_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/python/python_plugin_unittest.cc'; fi`
-
-google/protobuf/protobuf_test-test_util.o: google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo -c -o google/protobuf/protobuf_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_test-test_util.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util.o `test -f 'google/protobuf/test_util.cc' || echo '$(srcdir)/'`google/protobuf/test_util.cc
-
-google/protobuf/protobuf_test-test_util.obj: google/protobuf/test_util.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-test_util.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo -c -o google/protobuf/protobuf_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-test_util.Tpo google/protobuf/$(DEPDIR)/protobuf_test-test_util.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/test_util.cc' object='google/protobuf/protobuf_test-test_util.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-test_util.obj `if test -f 'google/protobuf/test_util.cc'; then $(CYGPATH_W) 'google/protobuf/test_util.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/test_util.cc'; fi`
-
-google/protobuf/testing/protobuf_test-googletest.o: google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-googletest.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_test-googletest.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-googletest.o `test -f 'google/protobuf/testing/googletest.cc' || echo '$(srcdir)/'`google/protobuf/testing/googletest.cc
-
-google/protobuf/testing/protobuf_test-googletest.obj: google/protobuf/testing/googletest.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-googletest.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo -c -o google/protobuf/testing/protobuf_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-googletest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/googletest.cc' object='google/protobuf/testing/protobuf_test-googletest.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-googletest.obj `if test -f 'google/protobuf/testing/googletest.cc'; then $(CYGPATH_W) 'google/protobuf/testing/googletest.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/googletest.cc'; fi`
-
-google/protobuf/testing/protobuf_test-file.o: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo -c -o google/protobuf/testing/protobuf_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_test-file.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-
-google/protobuf/testing/protobuf_test-file.obj: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/protobuf_test-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo -c -o google/protobuf/testing/protobuf_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Tpo google/protobuf/testing/$(DEPDIR)/protobuf_test-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/protobuf_test-file.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/protobuf_test-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_lite.pb.o: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite.pb.o `test -f 'google/protobuf/unittest_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite.pb.cc
-
-google/protobuf/protobuf_test-unittest_lite.pb.obj: google/protobuf/unittest_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite.pb.obj `if test -f 'google/protobuf/unittest_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_import_lite.pb.o: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.o `test -f 'google/protobuf/unittest_import_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_lite.pb.cc
-
-google/protobuf/protobuf_test-unittest_import_lite.pb.obj: google/protobuf/unittest_import_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_lite.pb.obj `if test -f 'google/protobuf/unittest_import_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_import_public_lite.pb.o: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public_lite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public_lite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.o `test -f 'google/protobuf/unittest_import_public_lite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public_lite.pb.cc
-
-google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj: google/protobuf/unittest_import_public_lite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public_lite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public_lite.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public_lite.pb.obj `if test -f 'google/protobuf/unittest_import_public_lite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public_lite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public_lite.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest.pb.o: google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_test-unittest.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest.pb.o `test -f 'google/protobuf/unittest.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest.pb.cc
-
-google/protobuf/protobuf_test-unittest.pb.obj: google/protobuf/unittest.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo -c -o google/protobuf/protobuf_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest.pb.cc' object='google/protobuf/protobuf_test-unittest.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest.pb.obj `if test -f 'google/protobuf/unittest.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_empty.pb.o: google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_empty.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_test-unittest_empty.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_empty.pb.o `test -f 'google/protobuf/unittest_empty.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_empty.pb.cc
-
-google/protobuf/protobuf_test-unittest_empty.pb.obj: google/protobuf/unittest_empty.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_empty.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_empty.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_empty.pb.cc' object='google/protobuf/protobuf_test-unittest_empty.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_empty.pb.obj `if test -f 'google/protobuf/unittest_empty.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_empty.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_empty.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_import.pb.o: google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_test-unittest_import.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import.pb.o `test -f 'google/protobuf/unittest_import.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import.pb.cc
-
-google/protobuf/protobuf_test-unittest_import.pb.obj: google/protobuf/unittest_import.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import.pb.cc' object='google/protobuf/protobuf_test-unittest_import.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import.pb.obj `if test -f 'google/protobuf/unittest_import.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_import_public.pb.o: google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public.pb.o `test -f 'google/protobuf/unittest_import_public.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_import_public.pb.cc
-
-google/protobuf/protobuf_test-unittest_import_public.pb.obj: google/protobuf/unittest_import_public.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_import_public.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_import_public.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_import_public.pb.cc' object='google/protobuf/protobuf_test-unittest_import_public.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_import_public.pb.obj `if test -f 'google/protobuf/unittest_import_public.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_import_public.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_import_public.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_mset.pb.o: google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_test-unittest_mset.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset.pb.o `test -f 'google/protobuf/unittest_mset.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_mset.pb.cc
-
-google/protobuf/protobuf_test-unittest_mset.pb.obj: google/protobuf/unittest_mset.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_mset.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_mset.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_mset.pb.cc' object='google/protobuf/protobuf_test-unittest_mset.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_mset.pb.obj `if test -f 'google/protobuf/unittest_mset.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_mset.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_mset.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_optimize_for.pb.o: google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.o `test -f 'google/protobuf/unittest_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_optimize_for.pb.cc
-
-google/protobuf/protobuf_test-unittest_optimize_for.pb.obj: google/protobuf/unittest_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_optimize_for.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o: google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.o `test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_embed_optimize_for.pb.cc
-
-google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj: google/protobuf/unittest_embed_optimize_for.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_embed_optimize_for.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_embed_optimize_for.pb.cc' object='google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_embed_optimize_for.pb.obj `if test -f 'google/protobuf/unittest_embed_optimize_for.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_embed_optimize_for.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_embed_optimize_for.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_custom_options.pb.o: google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_custom_options.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_test-unittest_custom_options.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.o `test -f 'google/protobuf/unittest_custom_options.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_custom_options.pb.cc
-
-google/protobuf/protobuf_test-unittest_custom_options.pb.obj: google/protobuf/unittest_custom_options.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_custom_options.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_custom_options.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_custom_options.pb.cc' object='google/protobuf/protobuf_test-unittest_custom_options.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_custom_options.pb.obj `if test -f 'google/protobuf/unittest_custom_options.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_custom_options.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_custom_options.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o: google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.o `test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_lite_imports_nonlite.pb.cc
-
-google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj: google/protobuf/unittest_lite_imports_nonlite.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_lite_imports_nonlite.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_lite_imports_nonlite.pb.cc' object='google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_lite_imports_nonlite.pb.obj `if test -f 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_lite_imports_nonlite.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_lite_imports_nonlite.pb.cc'; fi`
-
-google/protobuf/protobuf_test-unittest_no_generic_services.pb.o: google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_generic_services.pb.o -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_test-unittest_no_generic_services.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.o `test -f 'google/protobuf/unittest_no_generic_services.pb.cc' || echo '$(srcdir)/'`google/protobuf/unittest_no_generic_services.pb.cc
-
-google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj: google/protobuf/unittest_no_generic_services.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj -MD -MP -MF google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Tpo google/protobuf/$(DEPDIR)/protobuf_test-unittest_no_generic_services.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/unittest_no_generic_services.pb.cc' object='google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/protobuf_test-unittest_no_generic_services.pb.obj `if test -f 'google/protobuf/unittest_no_generic_services.pb.cc'; then $(CYGPATH_W) 'google/protobuf/unittest_no_generic_services.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/unittest_no_generic_services.pb.cc'; fi`
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.o: google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.o -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.o `test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' || echo '$(srcdir)/'`google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-
-google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.obj: google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.obj -MD -MP -MF google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Tpo -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Tpo google/protobuf/compiler/cpp/$(DEPDIR)/protobuf_test-cpp_test_bad_identifiers.pb.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc' object='google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(protobuf_test_CPPFLAGS) $(CPPFLAGS) $(protobuf_test_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/cpp/protobuf_test-cpp_test_bad_identifiers.pb.obj `if test -f 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc'; fi`
-
-google/protobuf/compiler/test_plugin-mock_code_generator.o: google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-mock_code_generator.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo -c -o google/protobuf/compiler/test_plugin-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/test_plugin-mock_code_generator.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-mock_code_generator.o `test -f 'google/protobuf/compiler/mock_code_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/mock_code_generator.cc
-
-google/protobuf/compiler/test_plugin-mock_code_generator.obj: google/protobuf/compiler/mock_code_generator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-mock_code_generator.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo -c -o google/protobuf/compiler/test_plugin-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-mock_code_generator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/mock_code_generator.cc' object='google/protobuf/compiler/test_plugin-mock_code_generator.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-mock_code_generator.obj `if test -f 'google/protobuf/compiler/mock_code_generator.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/mock_code_generator.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/mock_code_generator.cc'; fi`
-
-google/protobuf/testing/test_plugin-file.o: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/test_plugin-file.o -MD -MP -MF google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo -c -o google/protobuf/testing/test_plugin-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/test_plugin-file.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/test_plugin-file.o `test -f 'google/protobuf/testing/file.cc' || echo '$(srcdir)/'`google/protobuf/testing/file.cc
-
-google/protobuf/testing/test_plugin-file.obj: google/protobuf/testing/file.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/testing/test_plugin-file.obj -MD -MP -MF google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo -c -o google/protobuf/testing/test_plugin-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/testing/$(DEPDIR)/test_plugin-file.Tpo google/protobuf/testing/$(DEPDIR)/test_plugin-file.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/testing/file.cc' object='google/protobuf/testing/test_plugin-file.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/testing/test_plugin-file.obj `if test -f 'google/protobuf/testing/file.cc'; then $(CYGPATH_W) 'google/protobuf/testing/file.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/testing/file.cc'; fi`
-
-google/protobuf/compiler/test_plugin-test_plugin.o: google/protobuf/compiler/test_plugin.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-test_plugin.o -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo -c -o google/protobuf/compiler/test_plugin-test_plugin.o `test -f 'google/protobuf/compiler/test_plugin.cc' || echo '$(srcdir)/'`google/protobuf/compiler/test_plugin.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/test_plugin.cc' object='google/protobuf/compiler/test_plugin-test_plugin.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-test_plugin.o `test -f 'google/protobuf/compiler/test_plugin.cc' || echo '$(srcdir)/'`google/protobuf/compiler/test_plugin.cc
-
-google/protobuf/compiler/test_plugin-test_plugin.obj: google/protobuf/compiler/test_plugin.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT google/protobuf/compiler/test_plugin-test_plugin.obj -MD -MP -MF google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo -c -o google/protobuf/compiler/test_plugin-test_plugin.obj `if test -f 'google/protobuf/compiler/test_plugin.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/test_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/test_plugin.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Tpo google/protobuf/compiler/$(DEPDIR)/test_plugin-test_plugin.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='google/protobuf/compiler/test_plugin.cc' object='google/protobuf/compiler/test_plugin-test_plugin.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_plugin_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o google/protobuf/compiler/test_plugin-test_plugin.obj `if test -f 'google/protobuf/compiler/test_plugin.cc'; then $(CYGPATH_W) 'google/protobuf/compiler/test_plugin.cc'; else $(CYGPATH_W) '$(srcdir)/google/protobuf/compiler/test_plugin.cc'; fi`
-
-mostlyclean-libtool:
-	-rm -f *.lo
-
-clean-libtool:
-	-rm -rf .libs _libs
-	-rm -rf google/protobuf/.libs google/protobuf/_libs
-	-rm -rf google/protobuf/compiler/.libs google/protobuf/compiler/_libs
-	-rm -rf google/protobuf/compiler/cpp/.libs google/protobuf/compiler/cpp/_libs
-	-rm -rf google/protobuf/compiler/java/.libs google/protobuf/compiler/java/_libs
-	-rm -rf google/protobuf/compiler/javamicro/.libs google/protobuf/compiler/javamicro/_libs
-	-rm -rf google/protobuf/compiler/javanano/.libs google/protobuf/compiler/javanano/_libs
-	-rm -rf google/protobuf/compiler/python/.libs google/protobuf/compiler/python/_libs
-	-rm -rf google/protobuf/io/.libs google/protobuf/io/_libs
-	-rm -rf google/protobuf/stubs/.libs google/protobuf/stubs/_libs
-install-nobase_dist_protoDATA: $(nobase_dist_proto_DATA)
-	@$(NORMAL_INSTALL)
-	@list='$(nobase_dist_proto_DATA)'; test -n "$(protodir)" || list=; \
-	if test -n "$$list"; then \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(protodir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(protodir)" || exit 1; \
-	fi; \
-	$(am__nobase_list) | while read dir files; do \
-	  xfiles=; for file in $$files; do \
-	    if test -f "$$file"; then xfiles="$$xfiles $$file"; \
-	    else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
-	  test -z "$$xfiles" || { \
-	    test "x$$dir" = x. || { \
-	      echo " $(MKDIR_P) '$(DESTDIR)$(protodir)/$$dir'"; \
-	      $(MKDIR_P) "$(DESTDIR)$(protodir)/$$dir"; }; \
-	    echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(protodir)/$$dir'"; \
-	    $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(protodir)/$$dir" || exit $$?; }; \
-	done
-
-uninstall-nobase_dist_protoDATA:
-	@$(NORMAL_UNINSTALL)
-	@list='$(nobase_dist_proto_DATA)'; test -n "$(protodir)" || list=; \
-	$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
-	dir='$(DESTDIR)$(protodir)'; $(am__uninstall_files_from_dir)
-install-nobase_includeHEADERS: $(nobase_include_HEADERS)
-	@$(NORMAL_INSTALL)
-	@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
-	if test -n "$$list"; then \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
-	fi; \
-	$(am__nobase_list) | while read dir files; do \
-	  xfiles=; for file in $$files; do \
-	    if test -f "$$file"; then xfiles="$$xfiles $$file"; \
-	    else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
-	  test -z "$$xfiles" || { \
-	    test "x$$dir" = x. || { \
-	      echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \
-	      $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \
-	    echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \
-	    $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \
-	done
-
-uninstall-nobase_includeHEADERS:
-	@$(NORMAL_UNINSTALL)
-	@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
-	$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
-	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
-
-ID: $(am__tagged_files)
-	$(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-	set x; \
-	here=`pwd`; \
-	$(am__define_uniq_tagged_files); \
-	shift; \
-	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-	  test -n "$$unique" || unique=$$empty_fix; \
-	  if test $$# -gt 0; then \
-	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-	      "$$@" $$unique; \
-	  else \
-	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-	      $$unique; \
-	  fi; \
-	fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-	$(am__define_uniq_tagged_files); \
-	test -z "$(CTAGS_ARGS)$$unique" \
-	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-	     $$unique
-
-GTAGS:
-	here=`$(am__cd) $(top_builddir) && pwd` \
-	  && $(am__cd) $(top_srcdir) \
-	  && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
-	list='$(am__tagged_files)'; \
-	case "$(srcdir)" in \
-	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-	  *) sdir=$(subdir)/$(srcdir) ;; \
-	esac; \
-	for i in $$list; do \
-	  if test -f "$$i"; then \
-	    echo "$(subdir)/$$i"; \
-	  else \
-	    echo "$$sdir/$$i"; \
-	  fi; \
-	done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-# Recover from deleted '.trs' file; this should ensure that
-# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
-# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
-# to avoid problems with "make -n".
-.log.trs:
-	rm -f $< $@
-	$(MAKE) $(AM_MAKEFLAGS) $<
-
-# Leading 'am--fnord' is there to ensure the list of targets does not
-# expand to empty, as could happen e.g. with make check TESTS=''.
-am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
-am--force-recheck:
-	@:
-
-$(TEST_SUITE_LOG): $(TEST_LOGS)
-	@$(am__set_TESTS_bases); \
-	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
-	redo_bases=`for i in $$bases; do \
-	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
-	            done`; \
-	if test -n "$$redo_bases"; then \
-	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
-	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
-	  if $(am__make_dryrun); then :; else \
-	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
-	  fi; \
-	fi; \
-	if test -n "$$am__remaking_logs"; then \
-	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
-	       "recursion detected" >&2; \
-	else \
-	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
-	fi; \
-	if $(am__make_dryrun); then :; else \
-	  st=0;  \
-	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
-	  for i in $$redo_bases; do \
-	    test -f $$i.trs && test -r $$i.trs \
-	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
-	    test -f $$i.log && test -r $$i.log \
-	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
-	  done; \
-	  test $$st -eq 0 || exit 1; \
-	fi
-	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
-	ws='[ 	]'; \
-	results=`for b in $$bases; do echo $$b.trs; done`; \
-	test -n "$$results" || results=/dev/null; \
-	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
-	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
-	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
-	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
-	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
-	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
-	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
-	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
-	  success=true; \
-	else \
-	  success=false; \
-	fi; \
-	br='==================='; br=$$br$$br$$br$$br; \
-	result_count () \
-	{ \
-	    if test x"$$1" = x"--maybe-color"; then \
-	      maybe_colorize=yes; \
-	    elif test x"$$1" = x"--no-color"; then \
-	      maybe_colorize=no; \
-	    else \
-	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
-	    fi; \
-	    shift; \
-	    desc=$$1 count=$$2; \
-	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
-	      color_start=$$3 color_end=$$std; \
-	    else \
-	      color_start= color_end=; \
-	    fi; \
-	    echo "$${color_start}# $$desc $$count$${color_end}"; \
-	}; \
-	create_testsuite_report () \
-	{ \
-	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
-	  result_count $$1 "PASS: " $$pass  "$$grn"; \
-	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
-	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
-	  result_count $$1 "FAIL: " $$fail  "$$red"; \
-	  result_count $$1 "XPASS:" $$xpass "$$red"; \
-	  result_count $$1 "ERROR:" $$error "$$mgn"; \
-	}; \
-	{								\
-	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
-	    $(am__rst_title);						\
-	  create_testsuite_report --no-color;				\
-	  echo;								\
-	  echo ".. contents:: :depth: 2";				\
-	  echo;								\
-	  for b in $$bases; do echo $$b; done				\
-	    | $(am__create_global_log);					\
-	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
-	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
-	if $$success; then						\
-	  col="$$grn";							\
-	 else								\
-	  col="$$red";							\
-	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
-	fi;								\
-	echo "$${col}$$br$${std}"; 					\
-	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
-	echo "$${col}$$br$${std}"; 					\
-	create_testsuite_report --maybe-color;				\
-	echo "$$col$$br$$std";						\
-	if $$success; then :; else					\
-	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
-	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
-	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
-	  fi;								\
-	  echo "$$col$$br$$std";					\
-	fi;								\
-	$$success || exit 1
-
-check-TESTS:
-	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
-	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
-	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
-	@set +e; $(am__set_TESTS_bases); \
-	log_list=`for i in $$bases; do echo $$i.log; done`; \
-	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
-	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
-	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
-	exit $$?;
-recheck: all $(check_PROGRAMS)
-	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
-	@set +e; $(am__set_TESTS_bases); \
-	bases=`for i in $$bases; do echo $$i; done \
-	         | $(am__list_recheck_tests)` || exit 1; \
-	log_list=`for i in $$bases; do echo $$i.log; done`; \
-	log_list=`echo $$log_list`; \
-	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
-	        am__force_recheck=am--force-recheck \
-	        TEST_LOGS="$$log_list"; \
-	exit $$?
-protobuf-test.log: protobuf-test$(EXEEXT)
-	@p='protobuf-test$(EXEEXT)'; \
-	b='protobuf-test'; \
-	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-protobuf-lazy-descriptor-test.log: protobuf-lazy-descriptor-test$(EXEEXT)
-	@p='protobuf-lazy-descriptor-test$(EXEEXT)'; \
-	b='protobuf-lazy-descriptor-test'; \
-	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-protobuf-lite-test.log: protobuf-lite-test$(EXEEXT)
-	@p='protobuf-lite-test$(EXEEXT)'; \
-	b='protobuf-lite-test'; \
-	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-google/protobuf/compiler/zip_output_unittest.sh.log: google/protobuf/compiler/zip_output_unittest.sh
-	@p='google/protobuf/compiler/zip_output_unittest.sh'; \
-	b='google/protobuf/compiler/zip_output_unittest.sh'; \
-	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-google/protobuf/io/gzip_stream_unittest.sh.log: google/protobuf/io/gzip_stream_unittest.sh
-	@p='google/protobuf/io/gzip_stream_unittest.sh'; \
-	b='google/protobuf/io/gzip_stream_unittest.sh'; \
-	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-.test.log:
-	@p='$<'; \
-	$(am__set_b); \
-	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
-	--log-file $$b.log --trs-file $$b.trs \
-	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
-	"$$tst" $(AM_TESTS_FD_REDIRECT)
-@am__EXEEXT_TRUE@.test$(EXEEXT).log:
-@am__EXEEXT_TRUE@	@p='$<'; \
-@am__EXEEXT_TRUE@	$(am__set_b); \
-@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
-@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
-@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
-@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
-
-distdir: $(DISTFILES)
-	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-	list='$(DISTFILES)'; \
-	  dist_files=`for file in $$list; do echo $$file; done | \
-	  sed -e "s|^$$srcdirstrip/||;t" \
-	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-	case $$dist_files in \
-	  */*) $(MKDIR_P) `echo "$$dist_files" | \
-			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-			   sort -u` ;; \
-	esac; \
-	for file in $$dist_files; do \
-	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-	  if test -d $$d/$$file; then \
-	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-	    if test -d "$(distdir)/$$file"; then \
-	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-	    fi; \
-	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-	    fi; \
-	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-	  else \
-	    test -f "$(distdir)/$$file" \
-	    || cp -p $$d/$$file "$(distdir)/$$file" \
-	    || exit 1; \
-	  fi; \
-	done
-check-am: all-am
-	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
-	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
-check: $(BUILT_SOURCES)
-	$(MAKE) $(AM_MAKEFLAGS) check-am
-all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
-install-binPROGRAMS: install-libLTLIBRARIES
-
-installdirs:
-	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(protodir)" "$(DESTDIR)$(includedir)"; do \
-	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-	done
-install: $(BUILT_SOURCES)
-	$(MAKE) $(AM_MAKEFLAGS) install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-	if test -z '$(STRIP)'; then \
-	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-	      install; \
-	else \
-	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-	fi
-mostlyclean-generic:
-	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
-	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
-	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
-
-clean-generic:
-	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
-	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-	-rm -f google/protobuf/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/cpp/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/cpp/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/java/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/java/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/javamicro/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/javamicro/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/javanano/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/javanano/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/python/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/compiler/python/$(am__dirstamp)
-	-rm -f google/protobuf/io/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/io/$(am__dirstamp)
-	-rm -f google/protobuf/stubs/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/stubs/$(am__dirstamp)
-	-rm -f google/protobuf/testing/$(DEPDIR)/$(am__dirstamp)
-	-rm -f google/protobuf/testing/$(am__dirstamp)
-
-maintainer-clean-generic:
-	@echo "This command is intended for maintainers to use"
-	@echo "it deletes files that may require special tools to rebuild."
-	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-clean: clean-am
-
-clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
-	clean-libLTLIBRARIES clean-libtool clean-local mostlyclean-am
-
-distclean: distclean-am
-	-rm -rf google/protobuf/$(DEPDIR) google/protobuf/compiler/$(DEPDIR) google/protobuf/compiler/cpp/$(DEPDIR) google/protobuf/compiler/java/$(DEPDIR) google/protobuf/compiler/javamicro/$(DEPDIR) google/protobuf/compiler/javanano/$(DEPDIR) google/protobuf/compiler/python/$(DEPDIR) google/protobuf/io/$(DEPDIR) google/protobuf/stubs/$(DEPDIR) google/protobuf/testing/$(DEPDIR)
-	-rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
-	distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-nobase_dist_protoDATA \
-	install-nobase_includeHEADERS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-	-rm -rf google/protobuf/$(DEPDIR) google/protobuf/compiler/$(DEPDIR) google/protobuf/compiler/cpp/$(DEPDIR) google/protobuf/compiler/java/$(DEPDIR) google/protobuf/compiler/javamicro/$(DEPDIR) google/protobuf/compiler/javanano/$(DEPDIR) google/protobuf/compiler/python/$(DEPDIR) google/protobuf/io/$(DEPDIR) google/protobuf/stubs/$(DEPDIR) google/protobuf/testing/$(DEPDIR)
-	-rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-compile mostlyclean-generic \
-	mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
-	uninstall-nobase_dist_protoDATA \
-	uninstall-nobase_includeHEADERS
-
-.MAKE: all check check-am install install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
-	clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
-	clean-libLTLIBRARIES clean-libtool clean-local cscopelist-am \
-	ctags ctags-am distclean distclean-compile distclean-generic \
-	distclean-libtool distclean-tags distdir dvi dvi-am html \
-	html-am info info-am install install-am install-binPROGRAMS \
-	install-data install-data-am install-dvi install-dvi-am \
-	install-exec install-exec-am install-html install-html-am \
-	install-info install-info-am install-libLTLIBRARIES \
-	install-man install-nobase_dist_protoDATA \
-	install-nobase_includeHEADERS install-pdf install-pdf-am \
-	install-ps install-ps-am install-strip installcheck \
-	installcheck-am installdirs maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-compile \
-	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	recheck tags tags-am uninstall uninstall-am \
-	uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
-	uninstall-nobase_dist_protoDATA \
-	uninstall-nobase_includeHEADERS
-
-
-# Not sure why these don't get cleaned automatically.
-clean-local:
-	rm -f *.loT
-
-@USE_EXTERNAL_PROTOC_TRUE@unittest_proto_middleman: $(protoc_inputs)
-@USE_EXTERNAL_PROTOC_TRUE@	$(PROTOC) -I$(srcdir) --cpp_out=. $^
-@USE_EXTERNAL_PROTOC_TRUE@	touch unittest_proto_middleman
-
-# We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
-# relative to srcdir, which may not be the same as the current directory when
-# building out-of-tree.
-@USE_EXTERNAL_PROTOC_FALSE@unittest_proto_middleman: protoc$(EXEEXT) $(protoc_inputs)
-@USE_EXTERNAL_PROTOC_FALSE@	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd $(protoc_inputs) )
-@USE_EXTERNAL_PROTOC_FALSE@	touch unittest_proto_middleman
-
-$(protoc_outputs): unittest_proto_middleman
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..63d6e24
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,212 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
+
+Copyright 2008 Google Inc.
+
+https://developers.google.com/protocol-buffers/
+
+C++ Installation - Unix
+-----------------------
+
+To build protobuf from source, the following tools are needed:
+
+  * autoconf
+  * automake
+  * libtool
+  * curl (used to download gmock)
+  * make
+  * g++
+  * unzip
+
+On Ubuntu, you can install them with:
+
+  $ sudo apt-get install autoconf automake libtool curl make g++ unzip
+
+On other platforms, please use the corresponding package managing tool to
+install them before proceeding.
+
+If you get the source from github, you need to generate the configure script
+first:
+
+    $ ./autogen.sh
+
+This will download gmock source (which is used for C++ Protocol Buffer
+unit-tests) to the current directory and run automake, autoconf, etc.
+to generate the configure script and various template makefiles.
+
+You can skip this step if you are using a release package (which already
+contains gmock and the configure script).
+
+To build and install the C++ Protocol Buffer runtime and the Protocol
+Buffer compiler (protoc) execute the following:
+
+    $ ./configure
+    $ make
+    $ make check
+    $ sudo make install
+    $ sudo ldconfig # refresh shared library cache.
+
+If "make check" fails, you can still install, but it is likely that
+some features of this library will not work correctly on your system.
+Proceed at your own risk.
+
+For advanced usage information on configure and make, please refer to the
+autoconf documentation:
+
+  http://www.gnu.org/software/autoconf/manual/autoconf.html#Running-configure-Scripts
+
+**Hint on install location**
+
+  By default, the package will be installed to /usr/local.  However,
+  on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
+  You can add it, but it may be easier to just install to /usr
+  instead.  To do this, invoke configure as follows:
+
+    ./configure --prefix=/usr
+
+  If you already built the package with a different prefix, make sure
+  to run "make clean" before building again.
+
+**Compiling dependent packages**
+
+  To compile a package that uses Protocol Buffers, you need to pass
+  various flags to your compiler and linker.  As of version 2.2.0,
+  Protocol Buffers integrates with pkg-config to manage this.  If you
+  have pkg-config installed, then you can invoke it to get a list of
+  flags like so:
+
+    pkg-config --cflags protobuf         # print compiler flags
+    pkg-config --libs protobuf           # print linker flags
+    pkg-config --cflags --libs protobuf  # print both
+
+  For example:
+
+    c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
+
+  Note that packages written prior to the 2.2.0 release of Protocol
+  Buffers may not yet integrate with pkg-config to get flags, and may
+  not pass the correct set of flags to correctly link against
+  libprotobuf.  If the package in question uses autoconf, you can
+  often fix the problem by invoking its configure script like:
+
+    configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
+              LIBS="$(pkg-config --libs protobuf)"
+
+  This will force it to use the correct flags.
+
+  If you are writing an autoconf-based package that uses Protocol
+  Buffers, you should probably use the PKG_CHECK_MODULES macro in your
+  configure script like:
+
+    PKG_CHECK_MODULES([protobuf], [protobuf])
+
+  See the pkg-config man page for more info.
+
+  If you only want protobuf-lite, substitute "protobuf-lite" in place
+  of "protobuf" in these examples.
+
+**Note for Mac users**
+
+  For a Mac system, Unix tools are not available by default. You will first need
+  to install Xcode from the Mac AppStore and then run the following command from
+  a terminal:
+
+    $ sudo xcode-select --install
+
+  To install Unix tools, you can install "port" following the instructions at
+  https://www.macports.org . This will reside in /opt/local/bin/port for most
+  Mac installations.
+
+    $ sudo /opt/local/bin/port install autoconf automake libtool
+
+  Then follow the Unix instructions above.
+
+**Note for cross-compiling**
+
+  The makefiles normally invoke the protoc executable that they just
+  built in order to build tests.  When cross-compiling, the protoc
+  executable may not be executable on the host machine.  In this case,
+  you must build a copy of protoc for the host machine first, then use
+  the --with-protoc option to tell configure to use it instead.  For
+  example:
+
+    ./configure --with-protoc=protoc
+
+  This will use the installed protoc (found in your $PATH) instead of
+  trying to execute the one built during the build process.  You can
+  also use an executable that hasn't been installed.  For example, if
+  you built the protobuf package for your host machine in ../host,
+  you might do:
+
+    ./configure --with-protoc=../host/src/protoc
+
+  Either way, you must make sure that the protoc executable you use
+  has the same version as the protobuf source code you are trying to
+  use it with.
+
+**Note for Solaris users**
+
+  Solaris 10 x86 has a bug that will make linking fail, complaining
+  about libstdc++.la being invalid.  We have included a work-around
+  in this package.  To use the work-around, run configure as follows:
+
+    ./configure LDFLAGS=-L$PWD/src/solaris
+
+  See src/solaris/libstdc++.la for more info on this bug.
+
+**Note for HP C++ Tru64 users**
+
+  To compile invoke configure as follows:
+
+    ./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
+
+  Also, you will need to use gmake instead of make.
+
+**Note for AIX users**
+
+  Compile using the IBM xlC C++ compiler as follows:
+
+    ./configure CXX=xlC
+
+  Also, you will need to use GNU `make` (`gmake`) instead of AIX `make`.
+
+C++ Installation - Windows
+--------------------------
+
+If you only need the protoc binary, you can download it from the release
+page:
+
+  https://github.com/google/protobuf/releases
+
+In the downloads section, download the zip file protoc-$VERSION-win32.zip.
+It contains the protoc binary as well as public proto files of protobuf
+library.
+
+To build from source using Microsoft Visual C++, see [cmake/README.md](../cmake/README.md).
+
+To build from source using Cygwin or MinGW, follow the Unix installation
+instructions, above.
+
+Binary Compatibility Warning
+----------------------------
+
+Due to the nature of C++, it is unlikely that any two versions of the
+Protocol Buffers C++ runtime libraries will have compatible ABIs.
+That is, if you linked an executable against an older version of
+libprotobuf, it is unlikely to work with a newer version without
+re-compiling.  This problem, when it occurs, will normally be detected
+immediately on startup of your app.  Still, you may want to consider
+using static linkage.  You can configure this package to install
+static libraries only using:
+
+    ./configure --disable-shared
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/src/google/protobuf/SEBS b/src/google/protobuf/SEBS
deleted file mode 100644
index ba33c73..0000000
--- a/src/google/protobuf/SEBS
+++ /dev/null
@@ -1,240 +0,0 @@
-# **EXPERIMENTAL**
-#
-# See http://sebs.googlecode.com
-#
-# This is an experimental build definition file using the SEBS build system.
-# I (Kenton Varda, maintainer of Protocol Buffers) happen to be the author of
-# SEBS, though SEBS is not a Google project.  I'm sticking this file in
-# protobuf's SVN because that's the easiest place for me to put it, and it
-# shouldn't harm anyone.  This file is not included in the distribution.
-#
-# Currently, to use this file, you must generate config.h and put it at the
-# top level of the source tree.
-
-_cpp = sebs.import_("//sebs/cpp.sebs")
-
-# ====================================================================
-# Public targets
-
-protobuf_lite = _cpp.Library(
-  name = "protobuf-lite",
-  srcs = [ "stubs/common.cc",
-           "stubs/once.cc",
-           "stubs/hash.cc",
-           "stubs/hash.h",
-           "stubs/map-util.h",
-           "stubs/stl_util-inl.h",
-           "extension_set.cc",
-           "generated_message_util.cc",
-           "message_lite.cc",
-           "repeated_field.cc",
-           "wire_format_lite.cc",
-           "io/coded_stream.cc",
-           "io/zero_copy_stream.cc",
-           "io/zero_copy_stream_impl_lite.cc" ],
-  deps = [ _cpp.SystemLibrary(name = "pthread") ])
-
-protobuf = _cpp.Library(
-  name = "protobuf",
-  srcs = [ "stubs/strutil.cc",
-           "stubs/strutil.h",
-           "stubs/substitute.cc",
-           "stubs/substitute.h",
-           "stubs/structurally_valid.cc",
-           "descriptor.cc",
-           "descriptor.pb.cc",
-           "descriptor_database.cc",
-           "dynamic_message.cc",
-           "extension_set_heavy.cc",
-           "generated_message_reflection.cc",
-           "message.cc",
-           "reflection_ops.cc",
-           "service.cc",
-           "text_format.cc",
-           "unknown_field_set.cc",
-           "wire_format.cc",
-           "io/gzip_stream.cc",
-           "io/printer.cc",
-           "io/tokenizer.cc",
-           "io/zero_copy_stream_impl.cc",
-           "compiler/importer.cc",
-           "compiler/parser.cc" ],
-  deps = [ protobuf_lite,
-           _cpp.SystemLibrary(name = "z") ])
-
-libprotoc = _cpp.Library(
-  name = "protoc",
-  srcs = [ "compiler/code_generator.cc",
-           "compiler/command_line_interface.cc",
-           "compiler/cpp/cpp_enum.cc",
-           "compiler/cpp/cpp_enum.h",
-           "compiler/cpp/cpp_enum_field.cc",
-           "compiler/cpp/cpp_enum_field.h",
-           "compiler/cpp/cpp_extension.cc",
-           "compiler/cpp/cpp_extension.h",
-           "compiler/cpp/cpp_field.cc",
-           "compiler/cpp/cpp_field.h",
-           "compiler/cpp/cpp_file.cc",
-           "compiler/cpp/cpp_file.h",
-           "compiler/cpp/cpp_generator.cc",
-           "compiler/cpp/cpp_helpers.cc",
-           "compiler/cpp/cpp_helpers.h",
-           "compiler/cpp/cpp_message.cc",
-           "compiler/cpp/cpp_message.h",
-           "compiler/cpp/cpp_message_field.cc",
-           "compiler/cpp/cpp_message_field.h",
-           "compiler/cpp/cpp_primitive_field.cc",
-           "compiler/cpp/cpp_primitive_field.h",
-           "compiler/cpp/cpp_service.cc",
-           "compiler/cpp/cpp_service.h",
-           "compiler/cpp/cpp_string_field.cc",
-           "compiler/cpp/cpp_string_field.h",
-           "compiler/java/java_enum.cc",
-           "compiler/java/java_enum.h",
-           "compiler/java/java_enum_field.cc",
-           "compiler/java/java_enum_field.h",
-           "compiler/java/java_extension.cc",
-           "compiler/java/java_extension.h",
-           "compiler/java/java_field.cc",
-           "compiler/java/java_field.h",
-           "compiler/java/java_file.cc",
-           "compiler/java/java_file.h",
-           "compiler/java/java_generator.cc",
-           "compiler/java/java_helpers.cc",
-           "compiler/java/java_helpers.h",
-           "compiler/java/java_message.cc",
-           "compiler/java/java_message.h",
-           "compiler/java/java_message_field.cc",
-           "compiler/java/java_message_field.h",
-           "compiler/java/java_primitive_field.cc",
-           "compiler/java/java_primitive_field.h",
-           "compiler/java/java_service.cc",
-           "compiler/java/java_service.h",
-           "compiler/python/python_generator.cc" ],
-  deps = [ protobuf ])
-
-protoc = _cpp.Binary(
-  name = "protoc",
-  srcs = [ "compiler/main.cc" ],
-  deps = [ libprotoc ])
-
-# ====================================================================
-# ProtobufLibrary rule class
-
-class ProtobufLibrary(sebs.Rule):
-  argument_spec = sebs.ArgumentSpec(srcs = [sebs.Artifact],
-                                    deps = ([sebs.Rule], []),
-                                    lite = (bool, False))
-
-  def _expand(self, args):
-    for dep in args.deps:
-      if not isinstance(dep, ProtobufLibrary):
-        raise sebs.DefinitionError(
-          "Dependency of ProtobufLibrary is not a ProtobufLibrary: %s" % dep)
-
-    protoc.expand_once()
-
-    # We must build protoc for the host configuration to allow cross-compiling.
-    host_protoc = self.context.configured_artifact(protoc.binary, "host")
-
-    protoc_action = self.context.action(self, "protobuf")
-    protoc_args = [host_protoc, "-Isrc", "-Itmp", "-Iinclude","--cpp_out=tmp"]
-
-    cpp_srcs = []
-    for src in args.srcs:
-      protoc_args.append(src)
-
-      # We cannot build .proto files from other packages because the .pb.cc
-      # and .pb.h files would be written to that package, and we aren't allowed
-      # to write to other packages.
-      if self.context.local_filename(src) is None:
-        raise sebs.DefinitionError(
-          "Source file is not in this package: %s" % src)
-
-      cc_artifact = self.context.derived_artifact(src, ".pb.cc", protoc_action)
-      header_artifact = self.context.derived_artifact(
-          src, ".pb.h", protoc_action)
-
-      cpp_srcs.append(cc_artifact)
-      cpp_srcs.append(header_artifact)
-
-    protoc_action.set_command(
-      sebs.SubprocessCommand(protoc_action, protoc_args, implicit = cpp_srcs))
-
-    deps = list(args.deps)
-    if args.lite:
-      deps.append(protobuf_lite)
-    else:
-      deps.append(protobuf)
-
-    self.__cpp_library = _cpp.Library(srcs = cpp_srcs, deps = deps,
-                                      context = self.context)
-    self.__cpp_library.label = self.label
-    self.outputs = []
-
-  def as_cpp_library(self):
-    self.expand_once()
-    return self.__cpp_library
-
-# ====================================================================
-# Tests
-
-_lite_test_protos = ProtobufLibrary(
-  srcs = [ "unittest_lite.proto",
-           "unittest_import_lite.proto" ],
-  lite = True)
-_test_protos = ProtobufLibrary(
-  srcs = [ "unittest.proto",
-           "unittest_empty.proto",
-           "unittest_import.proto",
-           "unittest_mset.proto",
-           "unittest_optimize_for.proto",
-           "unittest_embed_optimize_for.proto",
-           "unittest_custom_options.proto",
-           "unittest_lite_imports_nonlite.proto",
-           "compiler/cpp/cpp_test_bad_identifiers.proto" ],
-  deps = [ _lite_test_protos ])
-
-_test_util = _cpp.Library(
-  name = "test_util",
-  srcs = [ "test_util.cc",
-           "test_util.h",
-           "testing/googletest.cc",
-           "testing/googletest.h",
-           "testing/file.cc",
-           "testing/file.h" ],
-  deps = [ protobuf, _test_protos, _cpp.SystemLibrary(name = "gtest")] )
-
-protobuf_lite_test = _cpp.Test(
-  srcs = [ "lite_unittest.cc",
-           "test_util_lite.cc",
-           "test_util_lite.h" ],
-  deps = [ _lite_test_protos ])
-
-protobuf_test = _cpp.Test(
-  srcs = [ "stubs/common_unittest.cc",
-           "stubs/once_unittest.cc",
-           "stubs/strutil_unittest.cc",
-           "stubs/structurally_valid_unittest.cc",
-           "descriptor_database_unittest.cc",
-           "descriptor_unittest.cc",
-           "dynamic_message_unittest.cc",
-           "extension_set_unittest.cc",
-           "generated_message_reflection_unittest.cc",
-           "message_unittest.cc",
-           "reflection_ops_unittest.cc",
-           "repeated_field_unittest.cc",
-           "text_format_unittest.cc",
-           "unknown_field_set_unittest.cc",
-           "wire_format_unittest.cc",
-           "io/coded_stream_unittest.cc",
-           "io/printer_unittest.cc",
-           "io/tokenizer_unittest.cc",
-           "io/zero_copy_stream_unittest.cc",
-           "compiler/command_line_interface_unittest.cc",
-           "compiler/importer_unittest.cc",
-           "compiler/parser_unittest.cc",
-           "compiler/cpp/cpp_bootstrap_unittest.cc",
-           "compiler/cpp/cpp_unittest.cc" ],
-  deps = [ protobuf, libprotoc, _test_util,
-           _cpp.SystemLibrary(name = "gtest_main") ])
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
new file mode 100644
index 0000000..f7b1d31
--- /dev/null
+++ b/src/google/protobuf/any.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include <google/protobuf/any.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+string GetTypeUrl(const Descriptor* message,
+                  const string& type_url_prefix) {
+  if (!type_url_prefix.empty() &&
+      type_url_prefix[type_url_prefix.size() - 1] == '/') {
+    return type_url_prefix + message->full_name();
+  } else {
+    return type_url_prefix + "/" + message->full_name();
+  }
+}
+}  // namespace
+
+const char kAnyFullTypeName[] = "google.protobuf.Any";
+const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
+
+AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
+    : type_url_(type_url), value_(value) {
+}
+
+void AnyMetadata::PackFrom(const Message& message) {
+  PackFrom(message, kTypeGoogleApisComPrefix);
+}
+
+void AnyMetadata::PackFrom(const Message& message,
+                           const string& type_url_prefix) {
+  type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
+                        GetTypeUrl(message.GetDescriptor(), type_url_prefix));
+  message.SerializeToString(value_->MutableNoArena(
+      &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
+}
+
+bool AnyMetadata::UnpackTo(Message* message) const {
+  if (!InternalIs(message->GetDescriptor())) {
+    return false;
+  }
+  return message->ParseFromString(
+      value_->GetNoArena(&::google::protobuf::internal::GetEmptyString()));
+}
+
+bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
+  const string type_url = type_url_->GetNoArena(
+             &::google::protobuf::internal::GetEmptyString());
+  string full_name;
+  if (!ParseAnyTypeUrl(type_url, &full_name)) {
+    return false;
+  }
+  return full_name == descriptor->full_name();
+}
+
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
+  size_t pos = type_url.find_last_of("/");
+  if (pos == string::npos || pos + 1 == type_url.size()) {
+    return false;
+  }
+  *full_type_name = type_url.substr(pos + 1);
+  return true;
+}
+
+
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field) {
+    const Descriptor* descriptor = message.GetDescriptor();
+    if (descriptor->full_name() != kAnyFullTypeName) {
+      return false;
+    }
+    *type_url_field = descriptor->FindFieldByNumber(1);
+    *value_field = descriptor->FindFieldByNumber(2);
+    return (*type_url_field != NULL &&
+            (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+            *value_field != NULL &&
+            (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
new file mode 100644
index 0000000..04e5416
--- /dev/null
+++ b/src/google/protobuf/any.h
@@ -0,0 +1,107 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_ANY_H__
+#define GOOGLE_PROTOBUF_ANY_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/arenastring.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Helper class used to implement google::protobuf::Any.
+class LIBPROTOBUF_EXPORT AnyMetadata {
+  typedef ArenaStringPtr UrlType;
+  typedef ArenaStringPtr ValueType;
+ public:
+  // AnyMetadata does not take ownership of "type_url" and "value".
+  AnyMetadata(UrlType* type_url, ValueType* value);
+
+  // Packs a message using the default type URL prefix: "type.googleapis.com".
+  // The resulted type URL will be "type.googleapis.com/<message_full_name>".
+  void PackFrom(const Message& message);
+  // Packs a message using the given type URL prefix. The type URL will be
+  // constructed by concatenating the message type's full name to the prefix
+  // with an optional "/" separator if the prefix doesn't already end up "/".
+  // For example, both PackFrom(message, "type.googleapis.com") and
+  // PackFrom(message, "type.googleapis.com/") yield the same result type
+  // URL: "type.googleapis.com/<message_full_name>".
+  void PackFrom(const Message& message, const string& type_url_prefix);
+
+  // Unpacks the payload into the given message. Returns false if the message's
+  // type doesn't match the type specified in the type URL (i.e., the full
+  // name after the last "/" of the type URL doesn't match the message's actaul
+  // full name) or parsing the payload has failed.
+  bool UnpackTo(Message* message) const;
+
+  // Checks whether the type specified in the type URL matches the given type.
+  // A type is consdiered matching if its full name matches the full name after
+  // the last "/" in the type URL.
+  template<typename T>
+  bool Is() const {
+    return InternalIs(T::default_instance().GetDescriptor());
+  }
+
+ private:
+  bool InternalIs(const Descriptor* message) const;
+
+  UrlType* type_url_;
+  ValueType* value_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
+};
+
+extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
+extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
+
+// Get the proto type name from Any::type_url value. For example, passing
+// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
+// *full_type_name. Returns false if type_url does not start with
+// "type.googleapis.com" or "type.googleprod.com".
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
+
+// See if message is of type google.protobuf.Any, if so, return the descriptors
+// for "type_url" and "value" fields.
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field);
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ANY_H__
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
new file mode 100644
index 0000000..fbde4a6
--- /dev/null
+++ b/src/google/protobuf/any.pb.cc
@@ -0,0 +1,499 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/any.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Any_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Any_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/any.proto");
+  GOOGLE_CHECK(file != NULL);
+  Any_descriptor_ = file->message_type(0);
+  static const int Any_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, type_url_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, value_),
+  };
+  Any_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Any_descriptor_,
+      Any::default_instance_,
+      Any_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Any),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Any_descriptor_, &Any::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto() {
+  delete Any::default_instance_;
+  delete Any_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\031google/protobuf/any.proto\022\017google.prot"
+    "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
+    " \001(\014Br\n\023com.google.protobufB\010AnyProtoP\001Z"
+    "%github.com/golang/protobuf/ptypes/any\240\001"
+    "\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes"
+    "b\006proto3", 208);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/any.proto", &protobuf_RegisterTypes);
+  Any::default_instance_ = new Any();
+  Any::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fany_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fany_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fany_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+void Any::PackFrom(const ::google::protobuf::Message& message) {
+  _any_metadata_.PackFrom(message);
+}
+
+void Any::PackFrom(const ::google::protobuf::Message& message,
+                           const ::std::string& type_url_prefix) {
+  _any_metadata_.PackFrom(message, type_url_prefix);
+}
+
+bool Any::UnpackTo(::google::protobuf::Message* message) const {
+  return _any_metadata_.UnpackTo(message);
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Any::kTypeUrlFieldNumber;
+const int Any::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Any::Any()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Any)
+}
+
+void Any::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Any::Any(const Any& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL),
+    _any_metadata_(&type_url_, &value_) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
+}
+
+void Any::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+Any::~Any() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Any)
+  SharedDtor();
+}
+
+void Any::SharedDtor() {
+  type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void Any::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Any::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Any_descriptor_;
+}
+
+const Any& Any::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  return *default_instance_;
+}
+
+Any* Any::default_instance_ = NULL;
+
+Any* Any::New(::google::protobuf::Arena* arena) const {
+  Any* n = new Any;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Any::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool Any::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Any)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string type_url = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type_url()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->type_url().data(), this->type_url().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Any.type_url"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_value;
+        break;
+      }
+
+      // optional bytes value = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Any)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Any)
+  return false;
+#undef DO_
+}
+
+void Any::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Any)
+  // optional string type_url = 1;
+  if (this->type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_url().data(), this->type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Any.type_url");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->type_url(), output);
+  }
+
+  // optional bytes value = 2;
+  if (this->value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      2, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Any)
+}
+
+::google::protobuf::uint8* Any::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
+  // optional string type_url = 1;
+  if (this->type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_url().data(), this->type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Any.type_url");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->type_url(), target);
+  }
+
+  // optional bytes value = 2;
+  if (this->value().size() > 0) {
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+        2, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
+  return target;
+}
+
+int Any::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
+  int total_size = 0;
+
+  // optional string type_url = 1;
+  if (this->type_url().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->type_url());
+  }
+
+  // optional bytes value = 2;
+  if (this->value().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::BytesSize(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Any::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Any* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Any>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Any)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any)
+    MergeFrom(*source);
+  }
+}
+
+void Any::MergeFrom(const Any& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.type_url().size() > 0) {
+
+    type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
+  }
+  if (from.value().size() > 0) {
+
+    value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+  }
+}
+
+void Any::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Any)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Any::CopyFrom(const Any& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Any::IsInitialized() const {
+
+  return true;
+}
+
+void Any::Swap(Any* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Any::InternalSwap(Any* other) {
+  type_url_.Swap(&other->type_url_);
+  value_.Swap(&other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Any::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Any_descriptor_;
+  metadata.reflection = Any_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Any
+
+// optional string type_url = 1;
+void Any::clear_type_url() {
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Any::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
+  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Any::set_type_url(const ::std::string& value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
+}
+ void Any::set_type_url(const char* value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Any.type_url)
+}
+ void Any::set_type_url(const char* value, size_t size) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
+}
+ ::std::string* Any::mutable_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
+  return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Any::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
+  
+  return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Any::set_allocated_type_url(::std::string* type_url) {
+  if (type_url != NULL) {
+    
+  } else {
+    
+  }
+  type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
+}
+
+// optional bytes value = 2;
+void Any::clear_value() {
+  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Any::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
+  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Any::set_value(const ::std::string& value) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
+}
+ void Any::set_value(const char* value) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Any.value)
+}
+ void Any::set_value(const void* value, size_t size) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
+}
+ ::std::string* Any::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
+  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Any::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.value)
+  
+  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Any::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
new file mode 100644
index 0000000..100a67f
--- /dev/null
+++ b/src/google/protobuf/any.pb.h
@@ -0,0 +1,254 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/any.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto();
+
+class Any;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message {
+ public:
+  Any();
+  virtual ~Any();
+
+  Any(const Any& from);
+
+  inline Any& operator=(const Any& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Any& default_instance();
+
+  // implements Any -----------------------------------------------
+
+  void PackFrom(const ::google::protobuf::Message& message);
+  void PackFrom(const ::google::protobuf::Message& message,
+                const ::std::string& type_url_prefix);
+  bool UnpackTo(::google::protobuf::Message* message) const;
+  template<typename T> bool Is() const {
+    return _any_metadata_.Is<T>();
+  }
+
+  void Swap(Any* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Any* New() const { return New(NULL); }
+
+  Any* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Any& from);
+  void MergeFrom(const Any& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Any* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string type_url = 1;
+  void clear_type_url();
+  static const int kTypeUrlFieldNumber = 1;
+  const ::std::string& type_url() const;
+  void set_type_url(const ::std::string& value);
+  void set_type_url(const char* value);
+  void set_type_url(const char* value, size_t size);
+  ::std::string* mutable_type_url();
+  ::std::string* release_type_url();
+  void set_allocated_type_url(::std::string* type_url);
+
+  // optional bytes value = 2;
+  void clear_value();
+  static const int kValueFieldNumber = 2;
+  const ::std::string& value() const;
+  void set_value(const ::std::string& value);
+  void set_value(const char* value);
+  void set_value(const void* value, size_t size);
+  ::std::string* mutable_value();
+  ::std::string* release_value();
+  void set_allocated_value(::std::string* value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Any)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr type_url_;
+  ::google::protobuf::internal::ArenaStringPtr value_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::AnyMetadata _any_metadata_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto();
+
+  void InitAsDefaultInstance();
+  static Any* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Any
+
+// optional string type_url = 1;
+inline void Any::clear_type_url() {
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Any::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
+  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Any::set_type_url(const ::std::string& value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
+}
+inline void Any::set_type_url(const char* value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Any.type_url)
+}
+inline void Any::set_type_url(const char* value, size_t size) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
+}
+inline ::std::string* Any::mutable_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
+  return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Any::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
+  
+  return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Any::set_allocated_type_url(::std::string* type_url) {
+  if (type_url != NULL) {
+    
+  } else {
+    
+  }
+  type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
+}
+
+// optional bytes value = 2;
+inline void Any::clear_value() {
+  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Any::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
+  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Any::set_value(const ::std::string& value) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
+}
+inline void Any::set_value(const char* value) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Any.value)
+}
+inline void Any::set_value(const void* value, size_t size) {
+  
+  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
+}
+inline ::std::string* Any::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
+  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Any::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Any.value)
+  
+  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Any::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
new file mode 100644
index 0000000..45db6ed
--- /dev/null
+++ b/src/google/protobuf/any.proto
@@ -0,0 +1,130 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/any";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+//     Foo foo = ...;
+//     Any any;
+//     any.PackFrom(foo);
+//     ...
+//     if (any.UnpackTo(&foo)) {
+//       ...
+//     }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+//     Foo foo = ...;
+//     Any any = Any.pack(foo);
+//     ...
+//     if (any.is(Foo.class)) {
+//       foo = any.unpack(Foo.class);
+//     }
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+//
+// JSON
+// ====
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+//     package google.profile;
+//     message Person {
+//       string first_name = 1;
+//       string last_name = 2;
+//     }
+//
+//     {
+//       "@type": "type.googleapis.com/google.profile.Person",
+//       "firstName": <string>,
+//       "lastName": <string>
+//     }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+//     {
+//       "@type": "type.googleapis.com/google.protobuf.Duration",
+//       "value": "1.212s"
+//     }
+//
+message Any {
+  // A URL/resource name whose content describes the type of the
+  // serialized protocol buffer message.
+  //
+  // For URLs which use the schema `http`, `https`, or no schema, the
+  // following restrictions and interpretations apply:
+  //
+  // * If no schema is provided, `https` is assumed.
+  // * The last segment of the URL's path must represent the fully
+  //   qualified name of the type (as in `path/google.protobuf.Duration`).
+  //   The name should be in a canonical form (e.g., leading "." is
+  //   not accepted).
+  // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+  //   value in binary format, or produce an error.
+  // * Applications are allowed to cache lookup results based on the
+  //   URL, or have them precompiled into a binary to avoid any
+  //   lookup. Therefore, binary compatibility needs to be preserved
+  //   on changes to types. (Use versioned type names to manage
+  //   breaking changes.)
+  //
+  // Schemas other than `http`, `https` (or the empty schema) might be
+  // used with implementation specific semantics.
+  //
+  string type_url = 1;
+
+  // Must be a valid serialized protocol buffer of the above specified type.
+  bytes value = 2;
+}
diff --git a/src/google/protobuf/any_test.cc b/src/google/protobuf/any_test.cc
new file mode 100644
index 0000000..1bfaa63
--- /dev/null
+++ b/src/google/protobuf/any_test.cc
@@ -0,0 +1,89 @@
+// 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.
+
+#include <google/protobuf/any_test.pb.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(AnyTest, TestPackAndUnpack) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(submessage);
+
+  string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestPackAndUnpackAny) {
+  // We can pack a Any message inside another Any message.
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  google::protobuf::Any any;
+  any.PackFrom(submessage);
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(any);
+
+  string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  ASSERT_TRUE(message.any_value().UnpackTo(&any));
+  ASSERT_TRUE(any.UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestIs) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  google::protobuf::Any any;
+  any.PackFrom(submessage);
+  ASSERT_TRUE(any.ParseFromString(any.SerializeAsString()));
+  EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
+  EXPECT_FALSE(any.Is<google::protobuf::Any>());
+
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(any);
+  ASSERT_TRUE(message.ParseFromString(message.SerializeAsString()));
+  EXPECT_FALSE(message.any_value().Is<protobuf_unittest::TestAny>());
+  EXPECT_TRUE(message.any_value().Is<google::protobuf::Any>());
+}
+
+}  // namespace
+}  // namespace protobuf
+
+}  // namespace google
diff --git a/src/google/protobuf/any_test.proto b/src/google/protobuf/any_test.proto
new file mode 100644
index 0000000..0c5b30b
--- /dev/null
+++ b/src/google/protobuf/any_test.proto
@@ -0,0 +1,41 @@
+// 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.
+
+syntax = "proto3";
+
+package protobuf_unittest;
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  int32 int32_value = 1;
+  google.protobuf.Any any_value = 2;
+  repeated google.protobuf.Any repeated_any_value = 3;
+}
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
new file mode 100644
index 0000000..cbeba30
--- /dev/null
+++ b/src/google/protobuf/api.pb.cc
@@ -0,0 +1,2023 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/api.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Api_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Api_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Method_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Method_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Mixin_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Mixin_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/api.proto");
+  GOOGLE_CHECK(file != NULL);
+  Api_descriptor_ = file->message_type(0);
+  static const int Api_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, methods_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, version_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, source_context_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, mixins_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, syntax_),
+  };
+  Api_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Api_descriptor_,
+      Api::default_instance_,
+      Api_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Api),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, _is_default_instance_));
+  Method_descriptor_ = file->message_type(1);
+  static const int Method_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, request_type_url_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, request_streaming_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, response_type_url_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, response_streaming_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, syntax_),
+  };
+  Method_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Method_descriptor_,
+      Method::default_instance_,
+      Method_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Method),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, _is_default_instance_));
+  Mixin_descriptor_ = file->message_type(2);
+  static const int Mixin_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, root_),
+  };
+  Mixin_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Mixin_descriptor_,
+      Mixin::default_instance_,
+      Mixin_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Mixin),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Api_descriptor_, &Api::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Method_descriptor_, &Method::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Mixin_descriptor_, &Mixin::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto() {
+  delete Api::default_instance_;
+  delete Api_reflection_;
+  delete Method::default_instance_;
+  delete Method_reflection_;
+  delete Mixin::default_instance_;
+  delete Mixin_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\031google/protobuf/api.proto\022\017google.prot"
+    "obuf\032$google/protobuf/source_context.pro"
+    "to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014"
+    "\n\004name\030\001 \001(\t\022(\n\007methods\030\002 \003(\0132\027.google.p"
+    "rotobuf.Method\022(\n\007options\030\003 \003(\0132\027.google"
+    ".protobuf.Option\022\017\n\007version\030\004 \001(\t\0226\n\016sou"
+    "rce_context\030\005 \001(\0132\036.google.protobuf.Sour"
+    "ceContext\022&\n\006mixins\030\006 \003(\0132\026.google.proto"
+    "buf.Mixin\022\'\n\006syntax\030\007 \001(\0162\027.google.proto"
+    "buf.Syntax\"\325\001\n\006Method\022\014\n\004name\030\001 \001(\t\022\030\n\020r"
+    "equest_type_url\030\002 \001(\t\022\031\n\021request_streami"
+    "ng\030\003 \001(\010\022\031\n\021response_type_url\030\004 \001(\t\022\032\n\022r"
+    "esponse_streaming\030\005 \001(\010\022(\n\007options\030\006 \003(\013"
+    "2\027.google.protobuf.Option\022\'\n\006syntax\030\007 \001("
+    "\0162\027.google.protobuf.Syntax\"#\n\005Mixin\022\014\n\004n"
+    "ame\030\001 \001(\t\022\014\n\004root\030\002 \001(\tBK\n\023com.google.pr"
+    "otobufB\010ApiProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Pro"
+    "tobuf.WellKnownTypesb\006proto3", 708);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/api.proto", &protobuf_RegisterTypes);
+  Api::default_instance_ = new Api();
+  Method::default_instance_ = new Method();
+  Mixin::default_instance_ = new Mixin();
+  Api::default_instance_->InitAsDefaultInstance();
+  Method::default_instance_->InitAsDefaultInstance();
+  Mixin::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fapi_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fapi_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fapi_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Api::kNameFieldNumber;
+const int Api::kMethodsFieldNumber;
+const int Api::kOptionsFieldNumber;
+const int Api::kVersionFieldNumber;
+const int Api::kSourceContextFieldNumber;
+const int Api::kMixinsFieldNumber;
+const int Api::kSyntaxFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Api::Api()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Api)
+}
+
+void Api::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+  source_context_ = const_cast< ::google::protobuf::SourceContext*>(&::google::protobuf::SourceContext::default_instance());
+}
+
+Api::Api(const Api& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Api)
+}
+
+void Api::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  version_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  source_context_ = NULL;
+  syntax_ = 0;
+}
+
+Api::~Api() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Api)
+  SharedDtor();
+}
+
+void Api::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  version_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+    delete source_context_;
+  }
+}
+
+void Api::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Api::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Api_descriptor_;
+}
+
+const Api& Api::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  return *default_instance_;
+}
+
+Api* Api::default_instance_ = NULL;
+
+Api* Api::New(::google::protobuf::Arena* arena) const {
+  Api* n = new Api;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Api::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Api)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+  syntax_ = 0;
+  methods_.Clear();
+  options_.Clear();
+  mixins_.Clear();
+}
+
+bool Api::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Api)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Api.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_methods;
+        break;
+      }
+
+      // repeated .google.protobuf.Method methods = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_methods:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_methods:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_methods()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_methods;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 3;
+      case 3: {
+        if (tag == 26) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(34)) goto parse_version;
+        break;
+      }
+
+      // optional string version = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_version:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_version()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->version().data(), this->version().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Api.version"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_source_context;
+        break;
+      }
+
+      // optional .google.protobuf.SourceContext source_context = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_source_context:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_source_context()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_mixins;
+        break;
+      }
+
+      // repeated .google.protobuf.Mixin mixins = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_mixins:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_mixins:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_mixins()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_loop_mixins;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(56)) goto parse_syntax;
+        break;
+      }
+
+      // optional .google.protobuf.Syntax syntax = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_syntax:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_syntax(static_cast< ::google::protobuf::Syntax >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Api)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Api)
+  return false;
+#undef DO_
+}
+
+void Api::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Api)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // repeated .google.protobuf.Method methods = 2;
+  for (unsigned int i = 0, n = this->methods_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->methods(i), output);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, this->options(i), output);
+  }
+
+  // optional string version = 4;
+  if (this->version().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->version().data(), this->version().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.version");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->version(), output);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      5, *this->source_context_, output);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, this->mixins(i), output);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      7, this->syntax(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Api)
+}
+
+::google::protobuf::uint8* Api::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // repeated .google.protobuf.Method methods = 2;
+  for (unsigned int i = 0, n = this->methods_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        2, this->methods(i), target);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        3, this->options(i), target);
+  }
+
+  // optional string version = 4;
+  if (this->version().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->version().data(), this->version().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Api.version");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->version(), target);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        5, *this->source_context_, target);
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        6, this->mixins(i), target);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      7, this->syntax(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api)
+  return target;
+}
+
+int Api::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string version = 4;
+  if (this->version().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->version());
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->source_context_);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax());
+  }
+
+  // repeated .google.protobuf.Method methods = 2;
+  total_size += 1 * this->methods_size();
+  for (int i = 0; i < this->methods_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->methods(i));
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  total_size += 1 * this->mixins_size();
+  for (int i = 0; i < this->mixins_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->mixins(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Api::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Api)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Api* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Api>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Api)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Api)
+    MergeFrom(*source);
+  }
+}
+
+void Api::MergeFrom(const Api& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  methods_.MergeFrom(from.methods_);
+  options_.MergeFrom(from.options_);
+  mixins_.MergeFrom(from.mixins_);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.version().size() > 0) {
+
+    version_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.version_);
+  }
+  if (from.has_source_context()) {
+    mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context());
+  }
+  if (from.syntax() != 0) {
+    set_syntax(from.syntax());
+  }
+}
+
+void Api::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Api)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Api::CopyFrom(const Api& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Api)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Api::IsInitialized() const {
+
+  return true;
+}
+
+void Api::Swap(Api* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Api::InternalSwap(Api* other) {
+  name_.Swap(&other->name_);
+  methods_.UnsafeArenaSwap(&other->methods_);
+  options_.UnsafeArenaSwap(&other->options_);
+  version_.Swap(&other->version_);
+  std::swap(source_context_, other->source_context_);
+  mixins_.UnsafeArenaSwap(&other->mixins_);
+  std::swap(syntax_, other->syntax_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Api::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Api_descriptor_;
+  metadata.reflection = Api_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Api
+
+// optional string name = 1;
+void Api::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Api::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Api::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
+}
+ void Api::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Api.name)
+}
+ void Api::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.name)
+}
+ ::std::string* Api::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Api::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Api::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.name)
+}
+
+// repeated .google.protobuf.Method methods = 2;
+int Api::methods_size() const {
+  return methods_.size();
+}
+void Api::clear_methods() {
+  methods_.Clear();
+}
+const ::google::protobuf::Method& Api::methods(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
+  return methods_.Get(index);
+}
+::google::protobuf::Method* Api::mutable_methods(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
+  return methods_.Mutable(index);
+}
+::google::protobuf::Method* Api::add_methods() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
+  return methods_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
+Api::mutable_methods() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
+  return &methods_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
+Api::methods() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
+  return methods_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+int Api::options_size() const {
+  return options_.size();
+}
+void Api::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& Api::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* Api::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* Api::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Api::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Api::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
+  return options_;
+}
+
+// optional string version = 4;
+void Api::clear_version() {
+  version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Api::version() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
+  return version_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Api::set_version(const ::std::string& value) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
+}
+ void Api::set_version(const char* value) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Api.version)
+}
+ void Api::set_version(const char* value, size_t size) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.version)
+}
+ ::std::string* Api::mutable_version() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
+  return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Api::release_version() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.version)
+  
+  return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Api::set_allocated_version(::std::string* version) {
+  if (version != NULL) {
+    
+  } else {
+    
+  }
+  version_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), version);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.version)
+}
+
+// optional .google.protobuf.SourceContext source_context = 5;
+bool Api::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+void Api::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+const ::google::protobuf::SourceContext& Api::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+::google::protobuf::SourceContext* Api::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
+  return source_context_;
+}
+::google::protobuf::SourceContext* Api::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+void Api::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context)
+}
+
+// repeated .google.protobuf.Mixin mixins = 6;
+int Api::mixins_size() const {
+  return mixins_.size();
+}
+void Api::clear_mixins() {
+  mixins_.Clear();
+}
+const ::google::protobuf::Mixin& Api::mixins(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
+  return mixins_.Get(index);
+}
+::google::protobuf::Mixin* Api::mutable_mixins(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
+  return mixins_.Mutable(index);
+}
+::google::protobuf::Mixin* Api::add_mixins() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
+  return mixins_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
+Api::mutable_mixins() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
+  return &mixins_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
+Api::mixins() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
+  return mixins_;
+}
+
+// optional .google.protobuf.Syntax syntax = 7;
+void Api::clear_syntax() {
+  syntax_ = 0;
+}
+ ::google::protobuf::Syntax Api::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+ void Api::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Method::kNameFieldNumber;
+const int Method::kRequestTypeUrlFieldNumber;
+const int Method::kRequestStreamingFieldNumber;
+const int Method::kResponseTypeUrlFieldNumber;
+const int Method::kResponseStreamingFieldNumber;
+const int Method::kOptionsFieldNumber;
+const int Method::kSyntaxFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Method::Method()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Method)
+}
+
+void Method::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Method::Method(const Method& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Method)
+}
+
+void Method::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  request_type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  request_streaming_ = false;
+  response_type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  response_streaming_ = false;
+  syntax_ = 0;
+}
+
+Method::~Method() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Method)
+  SharedDtor();
+}
+
+void Method::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  request_type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  response_type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void Method::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Method::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Method_descriptor_;
+}
+
+const Method& Method::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  return *default_instance_;
+}
+
+Method* Method::default_instance_ = NULL;
+
+Method* Method::New(::google::protobuf::Arena* arena) const {
+  Method* n = new Method;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Method::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Method)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(Method, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Method*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(request_streaming_, syntax_);
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  options_.Clear();
+}
+
+bool Method::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Method)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Method.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_request_type_url;
+        break;
+      }
+
+      // optional string request_type_url = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_request_type_url:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_request_type_url()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->request_type_url().data(), this->request_type_url().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Method.request_type_url"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_request_streaming;
+        break;
+      }
+
+      // optional bool request_streaming = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_request_streaming:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &request_streaming_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_response_type_url;
+        break;
+      }
+
+      // optional string response_type_url = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_response_type_url:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_response_type_url()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->response_type_url().data(), this->response_type_url().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Method.response_type_url"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_response_streaming;
+        break;
+      }
+
+      // optional bool response_streaming = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_response_streaming:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &response_streaming_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_options;
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_options:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(56)) goto parse_syntax;
+        break;
+      }
+
+      // optional .google.protobuf.Syntax syntax = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_syntax:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_syntax(static_cast< ::google::protobuf::Syntax >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Method)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Method)
+  return false;
+#undef DO_
+}
+
+void Method::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Method)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string request_type_url = 2;
+  if (this->request_type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->request_type_url().data(), this->request_type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.request_type_url");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->request_type_url(), output);
+  }
+
+  // optional bool request_streaming = 3;
+  if (this->request_streaming() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->request_streaming(), output);
+  }
+
+  // optional string response_type_url = 4;
+  if (this->response_type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->response_type_url().data(), this->response_type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.response_type_url");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->response_type_url(), output);
+  }
+
+  // optional bool response_streaming = 5;
+  if (this->response_streaming() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->response_streaming(), output);
+  }
+
+  // repeated .google.protobuf.Option options = 6;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, this->options(i), output);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      7, this->syntax(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Method)
+}
+
+::google::protobuf::uint8* Method::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string request_type_url = 2;
+  if (this->request_type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->request_type_url().data(), this->request_type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.request_type_url");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->request_type_url(), target);
+  }
+
+  // optional bool request_streaming = 3;
+  if (this->request_streaming() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->request_streaming(), target);
+  }
+
+  // optional string response_type_url = 4;
+  if (this->response_type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->response_type_url().data(), this->response_type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Method.response_type_url");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->response_type_url(), target);
+  }
+
+  // optional bool response_streaming = 5;
+  if (this->response_streaming() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->response_streaming(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 6;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        6, this->options(i), target);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      7, this->syntax(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method)
+  return target;
+}
+
+int Method::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string request_type_url = 2;
+  if (this->request_type_url().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->request_type_url());
+  }
+
+  // optional bool request_streaming = 3;
+  if (this->request_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // optional string response_type_url = 4;
+  if (this->response_type_url().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->response_type_url());
+  }
+
+  // optional bool response_streaming = 5;
+  if (this->response_streaming() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  if (this->syntax() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax());
+  }
+
+  // repeated .google.protobuf.Option options = 6;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Method::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Method)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Method* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Method>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Method)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Method)
+    MergeFrom(*source);
+  }
+}
+
+void Method::MergeFrom(const Method& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  options_.MergeFrom(from.options_);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.request_type_url().size() > 0) {
+
+    request_type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.request_type_url_);
+  }
+  if (from.request_streaming() != 0) {
+    set_request_streaming(from.request_streaming());
+  }
+  if (from.response_type_url().size() > 0) {
+
+    response_type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.response_type_url_);
+  }
+  if (from.response_streaming() != 0) {
+    set_response_streaming(from.response_streaming());
+  }
+  if (from.syntax() != 0) {
+    set_syntax(from.syntax());
+  }
+}
+
+void Method::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Method)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Method::CopyFrom(const Method& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Method)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Method::IsInitialized() const {
+
+  return true;
+}
+
+void Method::Swap(Method* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Method::InternalSwap(Method* other) {
+  name_.Swap(&other->name_);
+  request_type_url_.Swap(&other->request_type_url_);
+  std::swap(request_streaming_, other->request_streaming_);
+  response_type_url_.Swap(&other->response_type_url_);
+  std::swap(response_streaming_, other->response_streaming_);
+  options_.UnsafeArenaSwap(&other->options_);
+  std::swap(syntax_, other->syntax_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Method::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Method_descriptor_;
+  metadata.reflection = Method_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Method
+
+// optional string name = 1;
+void Method::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Method::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
+}
+ void Method::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.name)
+}
+ void Method::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.name)
+}
+ ::std::string* Method::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Method::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.name)
+}
+
+// optional string request_type_url = 2;
+void Method::clear_request_type_url() {
+  request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Method::request_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
+  return request_type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_request_type_url(const ::std::string& value) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
+}
+ void Method::set_request_type_url(const char* value) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.request_type_url)
+}
+ void Method::set_request_type_url(const char* value, size_t size) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.request_type_url)
+}
+ ::std::string* Method::mutable_request_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
+  return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Method::release_request_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url)
+  
+  return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_allocated_request_type_url(::std::string* request_type_url) {
+  if (request_type_url != NULL) {
+    
+  } else {
+    
+  }
+  request_type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), request_type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.request_type_url)
+}
+
+// optional bool request_streaming = 3;
+void Method::clear_request_streaming() {
+  request_streaming_ = false;
+}
+ bool Method::request_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_streaming)
+  return request_streaming_;
+}
+ void Method::set_request_streaming(bool value) {
+  
+  request_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_streaming)
+}
+
+// optional string response_type_url = 4;
+void Method::clear_response_type_url() {
+  response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Method::response_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
+  return response_type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_response_type_url(const ::std::string& value) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
+}
+ void Method::set_response_type_url(const char* value) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.response_type_url)
+}
+ void Method::set_response_type_url(const char* value, size_t size) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.response_type_url)
+}
+ ::std::string* Method::mutable_response_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
+  return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Method::release_response_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url)
+  
+  return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Method::set_allocated_response_type_url(::std::string* response_type_url) {
+  if (response_type_url != NULL) {
+    
+  } else {
+    
+  }
+  response_type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), response_type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.response_type_url)
+}
+
+// optional bool response_streaming = 5;
+void Method::clear_response_streaming() {
+  response_streaming_ = false;
+}
+ bool Method::response_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_streaming)
+  return response_streaming_;
+}
+ void Method::set_response_streaming(bool value) {
+  
+  response_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_streaming)
+}
+
+// repeated .google.protobuf.Option options = 6;
+int Method::options_size() const {
+  return options_.size();
+}
+void Method::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& Method::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* Method::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* Method::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Method::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Method::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Method.options)
+  return options_;
+}
+
+// optional .google.protobuf.Syntax syntax = 7;
+void Method::clear_syntax() {
+  syntax_ = 0;
+}
+ ::google::protobuf::Syntax Method::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+ void Method::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Mixin::kNameFieldNumber;
+const int Mixin::kRootFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Mixin::Mixin()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Mixin)
+}
+
+void Mixin::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Mixin::Mixin(const Mixin& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin)
+}
+
+void Mixin::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+Mixin::~Mixin() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Mixin)
+  SharedDtor();
+}
+
+void Mixin::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void Mixin::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Mixin::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Mixin_descriptor_;
+}
+
+const Mixin& Mixin::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  return *default_instance_;
+}
+
+Mixin* Mixin::default_instance_ = NULL;
+
+Mixin* Mixin::New(::google::protobuf::Arena* arena) const {
+  Mixin* n = new Mixin;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Mixin::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool Mixin::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Mixin)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Mixin.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_root;
+        break;
+      }
+
+      // optional string root = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_root:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_root()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->root().data(), this->root().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Mixin.root"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Mixin)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Mixin)
+  return false;
+#undef DO_
+}
+
+void Mixin::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Mixin)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string root = 2;
+  if (this->root().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->root().data(), this->root().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.root");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->root(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Mixin)
+}
+
+::google::protobuf::uint8* Mixin::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string root = 2;
+  if (this->root().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->root().data(), this->root().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Mixin.root");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->root(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin)
+  return target;
+}
+
+int Mixin::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string root = 2;
+  if (this->root().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->root());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Mixin::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Mixin)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Mixin* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Mixin>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Mixin)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Mixin)
+    MergeFrom(*source);
+  }
+}
+
+void Mixin::MergeFrom(const Mixin& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.root().size() > 0) {
+
+    root_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.root_);
+  }
+}
+
+void Mixin::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Mixin)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Mixin::CopyFrom(const Mixin& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Mixin)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Mixin::IsInitialized() const {
+
+  return true;
+}
+
+void Mixin::Swap(Mixin* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Mixin::InternalSwap(Mixin* other) {
+  name_.Swap(&other->name_);
+  root_.Swap(&other->root_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Mixin::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Mixin_descriptor_;
+  metadata.reflection = Mixin_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Mixin
+
+// optional string name = 1;
+void Mixin::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Mixin::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Mixin::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
+}
+ void Mixin::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.name)
+}
+ void Mixin::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name)
+}
+ ::std::string* Mixin::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Mixin::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Mixin::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name)
+}
+
+// optional string root = 2;
+void Mixin::clear_root() {
+  root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Mixin::root() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
+  return root_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Mixin::set_root(const ::std::string& value) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
+}
+ void Mixin::set_root(const char* value) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.root)
+}
+ void Mixin::set_root(const char* value, size_t size) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root)
+}
+ ::std::string* Mixin::mutable_root() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
+  return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Mixin::release_root() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root)
+  
+  return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Mixin::set_allocated_root(::std::string* root) {
+  if (root != NULL) {
+    
+  } else {
+    
+  }
+  root_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
new file mode 100644
index 0000000..bb35e47
--- /dev/null
+++ b/src/google/protobuf/api.pb.h
@@ -0,0 +1,984 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fapi_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fapi_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/source_context.pb.h>
+#include <google/protobuf/type.pb.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
+
+class Api;
+class Method;
+class Mixin;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message {
+ public:
+  Api();
+  virtual ~Api();
+
+  Api(const Api& from);
+
+  inline Api& operator=(const Api& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Api& default_instance();
+
+  void Swap(Api* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Api* New() const { return New(NULL); }
+
+  Api* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Api& from);
+  void MergeFrom(const Api& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Api* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // repeated .google.protobuf.Method methods = 2;
+  int methods_size() const;
+  void clear_methods();
+  static const int kMethodsFieldNumber = 2;
+  const ::google::protobuf::Method& methods(int index) const;
+  ::google::protobuf::Method* mutable_methods(int index);
+  ::google::protobuf::Method* add_methods();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
+      mutable_methods();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
+      methods() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 3;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // optional string version = 4;
+  void clear_version();
+  static const int kVersionFieldNumber = 4;
+  const ::std::string& version() const;
+  void set_version(const ::std::string& value);
+  void set_version(const char* value);
+  void set_version(const char* value, size_t size);
+  ::std::string* mutable_version();
+  ::std::string* release_version();
+  void set_allocated_version(::std::string* version);
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  void clear_source_context();
+  static const int kSourceContextFieldNumber = 5;
+  const ::google::protobuf::SourceContext& source_context() const;
+  ::google::protobuf::SourceContext* mutable_source_context();
+  ::google::protobuf::SourceContext* release_source_context();
+  void set_allocated_source_context(::google::protobuf::SourceContext* source_context);
+
+  // repeated .google.protobuf.Mixin mixins = 6;
+  int mixins_size() const;
+  void clear_mixins();
+  static const int kMixinsFieldNumber = 6;
+  const ::google::protobuf::Mixin& mixins(int index) const;
+  ::google::protobuf::Mixin* mutable_mixins(int index);
+  ::google::protobuf::Mixin* add_mixins();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
+      mutable_mixins();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
+      mixins() const;
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  static const int kSyntaxFieldNumber = 7;
+  ::google::protobuf::Syntax syntax() const;
+  void set_syntax(::google::protobuf::Syntax value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Api)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method > methods_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  ::google::protobuf::internal::ArenaStringPtr version_;
+  ::google::protobuf::SourceContext* source_context_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin > mixins_;
+  int syntax_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
+
+  void InitAsDefaultInstance();
+  static Api* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message {
+ public:
+  Method();
+  virtual ~Method();
+
+  Method(const Method& from);
+
+  inline Method& operator=(const Method& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Method& default_instance();
+
+  void Swap(Method* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Method* New() const { return New(NULL); }
+
+  Method* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Method& from);
+  void MergeFrom(const Method& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Method* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional string request_type_url = 2;
+  void clear_request_type_url();
+  static const int kRequestTypeUrlFieldNumber = 2;
+  const ::std::string& request_type_url() const;
+  void set_request_type_url(const ::std::string& value);
+  void set_request_type_url(const char* value);
+  void set_request_type_url(const char* value, size_t size);
+  ::std::string* mutable_request_type_url();
+  ::std::string* release_request_type_url();
+  void set_allocated_request_type_url(::std::string* request_type_url);
+
+  // optional bool request_streaming = 3;
+  void clear_request_streaming();
+  static const int kRequestStreamingFieldNumber = 3;
+  bool request_streaming() const;
+  void set_request_streaming(bool value);
+
+  // optional string response_type_url = 4;
+  void clear_response_type_url();
+  static const int kResponseTypeUrlFieldNumber = 4;
+  const ::std::string& response_type_url() const;
+  void set_response_type_url(const ::std::string& value);
+  void set_response_type_url(const char* value);
+  void set_response_type_url(const char* value, size_t size);
+  ::std::string* mutable_response_type_url();
+  ::std::string* release_response_type_url();
+  void set_allocated_response_type_url(::std::string* response_type_url);
+
+  // optional bool response_streaming = 5;
+  void clear_response_streaming();
+  static const int kResponseStreamingFieldNumber = 5;
+  bool response_streaming() const;
+  void set_response_streaming(bool value);
+
+  // repeated .google.protobuf.Option options = 6;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 6;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // optional .google.protobuf.Syntax syntax = 7;
+  void clear_syntax();
+  static const int kSyntaxFieldNumber = 7;
+  ::google::protobuf::Syntax syntax() const;
+  void set_syntax(::google::protobuf::Syntax value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Method)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr request_type_url_;
+  ::google::protobuf::internal::ArenaStringPtr response_type_url_;
+  bool request_streaming_;
+  bool response_streaming_;
+  int syntax_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
+
+  void InitAsDefaultInstance();
+  static Method* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message {
+ public:
+  Mixin();
+  virtual ~Mixin();
+
+  Mixin(const Mixin& from);
+
+  inline Mixin& operator=(const Mixin& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Mixin& default_instance();
+
+  void Swap(Mixin* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Mixin* New() const { return New(NULL); }
+
+  Mixin* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Mixin& from);
+  void MergeFrom(const Mixin& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Mixin* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional string root = 2;
+  void clear_root();
+  static const int kRootFieldNumber = 2;
+  const ::std::string& root() const;
+  void set_root(const ::std::string& value);
+  void set_root(const char* value);
+  void set_root(const char* value, size_t size);
+  ::std::string* mutable_root();
+  ::std::string* release_root();
+  void set_allocated_root(::std::string* root);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr root_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
+
+  void InitAsDefaultInstance();
+  static Mixin* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Api
+
+// optional string name = 1;
+inline void Api::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Api::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Api::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
+}
+inline void Api::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Api.name)
+}
+inline void Api::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.name)
+}
+inline ::std::string* Api::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Api::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Api::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.name)
+}
+
+// repeated .google.protobuf.Method methods = 2;
+inline int Api::methods_size() const {
+  return methods_.size();
+}
+inline void Api::clear_methods() {
+  methods_.Clear();
+}
+inline const ::google::protobuf::Method& Api::methods(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
+  return methods_.Get(index);
+}
+inline ::google::protobuf::Method* Api::mutable_methods(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
+  return methods_.Mutable(index);
+}
+inline ::google::protobuf::Method* Api::add_methods() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
+  return methods_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
+Api::mutable_methods() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
+  return &methods_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
+Api::methods() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
+  return methods_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Api::options_size() const {
+  return options_.size();
+}
+inline void Api::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& Api::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Api::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* Api::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Api::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Api::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
+  return options_;
+}
+
+// optional string version = 4;
+inline void Api::clear_version() {
+  version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Api::version() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
+  return version_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Api::set_version(const ::std::string& value) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
+}
+inline void Api::set_version(const char* value) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Api.version)
+}
+inline void Api::set_version(const char* value, size_t size) {
+  
+  version_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.version)
+}
+inline ::std::string* Api::mutable_version() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
+  return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Api::release_version() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.version)
+  
+  return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Api::set_allocated_version(::std::string* version) {
+  if (version != NULL) {
+    
+  } else {
+    
+  }
+  version_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), version);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.version)
+}
+
+// optional .google.protobuf.SourceContext source_context = 5;
+inline bool Api::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+inline void Api::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+inline const ::google::protobuf::SourceContext& Api::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+inline ::google::protobuf::SourceContext* Api::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
+  return source_context_;
+}
+inline ::google::protobuf::SourceContext* Api::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+inline void Api::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context)
+}
+
+// repeated .google.protobuf.Mixin mixins = 6;
+inline int Api::mixins_size() const {
+  return mixins_.size();
+}
+inline void Api::clear_mixins() {
+  mixins_.Clear();
+}
+inline const ::google::protobuf::Mixin& Api::mixins(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
+  return mixins_.Get(index);
+}
+inline ::google::protobuf::Mixin* Api::mutable_mixins(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
+  return mixins_.Mutable(index);
+}
+inline ::google::protobuf::Mixin* Api::add_mixins() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
+  return mixins_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
+Api::mutable_mixins() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
+  return &mixins_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
+Api::mixins() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
+  return mixins_;
+}
+
+// optional .google.protobuf.Syntax syntax = 7;
+inline void Api::clear_syntax() {
+  syntax_ = 0;
+}
+inline ::google::protobuf::Syntax Api::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+inline void Api::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Method
+
+// optional string name = 1;
+inline void Method::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Method::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
+}
+inline void Method::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.name)
+}
+inline void Method::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.name)
+}
+inline ::std::string* Method::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Method::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.name)
+}
+
+// optional string request_type_url = 2;
+inline void Method::clear_request_type_url() {
+  request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Method::request_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
+  return request_type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_request_type_url(const ::std::string& value) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
+}
+inline void Method::set_request_type_url(const char* value) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.request_type_url)
+}
+inline void Method::set_request_type_url(const char* value, size_t size) {
+  
+  request_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.request_type_url)
+}
+inline ::std::string* Method::mutable_request_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
+  return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Method::release_request_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url)
+  
+  return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_allocated_request_type_url(::std::string* request_type_url) {
+  if (request_type_url != NULL) {
+    
+  } else {
+    
+  }
+  request_type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), request_type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.request_type_url)
+}
+
+// optional bool request_streaming = 3;
+inline void Method::clear_request_streaming() {
+  request_streaming_ = false;
+}
+inline bool Method::request_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.request_streaming)
+  return request_streaming_;
+}
+inline void Method::set_request_streaming(bool value) {
+  
+  request_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_streaming)
+}
+
+// optional string response_type_url = 4;
+inline void Method::clear_response_type_url() {
+  response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Method::response_type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
+  return response_type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_response_type_url(const ::std::string& value) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
+}
+inline void Method::set_response_type_url(const char* value) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Method.response_type_url)
+}
+inline void Method::set_response_type_url(const char* value, size_t size) {
+  
+  response_type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.response_type_url)
+}
+inline ::std::string* Method::mutable_response_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
+  return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Method::release_response_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url)
+  
+  return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Method::set_allocated_response_type_url(::std::string* response_type_url) {
+  if (response_type_url != NULL) {
+    
+  } else {
+    
+  }
+  response_type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), response_type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.response_type_url)
+}
+
+// optional bool response_streaming = 5;
+inline void Method::clear_response_streaming() {
+  response_streaming_ = false;
+}
+inline bool Method::response_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.response_streaming)
+  return response_streaming_;
+}
+inline void Method::set_response_streaming(bool value) {
+  
+  response_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_streaming)
+}
+
+// repeated .google.protobuf.Option options = 6;
+inline int Method::options_size() const {
+  return options_.size();
+}
+inline void Method::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& Method::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Method::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* Method::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Method::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Method::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Method.options)
+  return options_;
+}
+
+// optional .google.protobuf.Syntax syntax = 7;
+inline void Method::clear_syntax() {
+  syntax_ = 0;
+}
+inline ::google::protobuf::Syntax Method::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+inline void Method::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Mixin
+
+// optional string name = 1;
+inline void Mixin::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Mixin::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Mixin::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
+}
+inline void Mixin::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.name)
+}
+inline void Mixin::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name)
+}
+inline ::std::string* Mixin::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Mixin::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Mixin::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name)
+}
+
+// optional string root = 2;
+inline void Mixin::clear_root() {
+  root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Mixin::root() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
+  return root_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Mixin::set_root(const ::std::string& value) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
+}
+inline void Mixin::set_root(const char* value) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.root)
+}
+inline void Mixin::set_root(const char* value, size_t size) {
+  
+  root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root)
+}
+inline ::std::string* Mixin::mutable_root() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
+  return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Mixin::release_root() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root)
+  
+  return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Mixin::set_allocated_root(::std::string* root) {
+  if (root != NULL) {
+    
+  } else {
+    
+  }
+  root_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fapi_2eproto__INCLUDED
diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto
new file mode 100644
index 0000000..dbe87b8
--- /dev/null
+++ b/src/google/protobuf/api.proto
@@ -0,0 +1,202 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/source_context.proto";
+import "google/protobuf/type.proto";
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "ApiProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// Api is a light-weight descriptor for a protocol buffer service.
+message Api {
+
+  // The fully qualified name of this api, including package name
+  // followed by the api's simple name.
+  string name = 1;
+
+  // The methods of this api, in unspecified order.
+  repeated Method methods = 2;
+
+  // Any metadata attached to the API.
+  repeated Option options = 3;
+
+  // A version string for this api. If specified, must have the form
+  // `major-version.minor-version`, as in `1.10`. If the minor version
+  // is omitted, it defaults to zero. If the entire version field is
+  // empty, the major version is derived from the package name, as
+  // outlined below. If the field is not empty, the version in the
+  // package name will be verified to be consistent with what is
+  // provided here.
+  //
+  // The versioning schema uses [semantic
+  // versioning](http://semver.org) where the major version number
+  // indicates a breaking change and the minor version an additive,
+  // non-breaking change. Both version numbers are signals to users
+  // what to expect from different versions, and should be carefully
+  // chosen based on the product plan.
+  //
+  // The major version is also reflected in the package name of the
+  // API, which must end in `v<major-version>`, as in
+  // `google.feature.v1`. For major versions 0 and 1, the suffix can
+  // be omitted. Zero major versions must only be used for
+  // experimental, none-GA apis.
+  //
+  //
+  string version = 4;
+
+  // Source context for the protocol buffer service represented by this
+  // message.
+  SourceContext source_context = 5;
+
+  // Included APIs. See [Mixin][].
+  repeated Mixin mixins = 6;
+
+  // The source syntax of the service.
+  Syntax syntax = 7;
+}
+
+// Method represents a method of an api.
+message Method {
+
+  // The simple name of this method.
+  string name = 1;
+
+  // A URL of the input message type.
+  string request_type_url = 2;
+
+  // If true, the request is streamed.
+  bool request_streaming = 3;
+
+  // The URL of the output message type.
+  string response_type_url = 4;
+
+  // If true, the response is streamed.
+  bool response_streaming = 5;
+
+  // Any metadata attached to the method.
+  repeated Option options = 6;
+
+  // The source syntax of this method.
+  Syntax syntax = 7;
+}
+
+// Declares an API to be included in this API. The including API must
+// redeclare all the methods from the included API, but documentation
+// and options are inherited as follows:
+//
+// - If after comment and whitespace stripping, the documentation
+//   string of the redeclared method is empty, it will be inherited
+//   from the original method.
+//
+// - Each annotation belonging to the service config (http,
+//   visibility) which is not set in the redeclared method will be
+//   inherited.
+//
+// - If an http annotation is inherited, the path pattern will be
+//   modified as follows. Any version prefix will be replaced by the
+//   version of the including API plus the [root][] path if specified.
+//
+// Example of a simple mixin:
+//
+//     package google.acl.v1;
+//     service AccessControl {
+//       // Get the underlying ACL object.
+//       rpc GetAcl(GetAclRequest) returns (Acl) {
+//         option (google.api.http).get = "/v1/{resource=**}:getAcl";
+//       }
+//     }
+//
+//     package google.storage.v2;
+//     service Storage {
+//       rpc GetAcl(GetAclRequest) returns (Acl);
+//
+//       // Get a data record.
+//       rpc GetData(GetDataRequest) returns (Data) {
+//         option (google.api.http).get = "/v2/{resource=**}";
+//       }
+//     }
+//
+// Example of a mixin configuration:
+//
+//     apis:
+//     - name: google.storage.v2.Storage
+//       mixins:
+//       - name: google.acl.v1.AccessControl
+//
+// The mixin construct implies that all methods in `AccessControl` are
+// also declared with same name and request/response types in
+// `Storage`. A documentation generator or annotation processor will
+// see the effective `Storage.GetAcl` method after inherting
+// documentation and annotations as follows:
+//
+//     service Storage {
+//       // Get the underlying ACL object.
+//       rpc GetAcl(GetAclRequest) returns (Acl) {
+//         option (google.api.http).get = "/v2/{resource=**}:getAcl";
+//       }
+//       ...
+//     }
+//
+// Note how the version in the path pattern changed from `v1` to `v2`.
+//
+// If the `root` field in the mixin is specified, it should be a
+// relative path under which inherited HTTP paths are placed. Example:
+//
+//     apis:
+//     - name: google.storage.v2.Storage
+//       mixins:
+//       - name: google.acl.v1.AccessControl
+//         root: acls
+//
+// This implies the following inherited HTTP annotation:
+//
+//     service Storage {
+//       // Get the underlying ACL object.
+//       rpc GetAcl(GetAclRequest) returns (Acl) {
+//         option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
+//       }
+//       ...
+//     }
+message Mixin {
+  // The fully qualified name of the API which is included.
+  string name = 1;
+
+  // If non-empty specifies a path under which inherited HTTP paths
+  // are rooted.
+  string root = 2;
+}
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
new file mode 100755
index 0000000..613e589
--- /dev/null
+++ b/src/google/protobuf/arena.cc
@@ -0,0 +1,321 @@
+// 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.
+
+#include <google/protobuf/arena.h>
+
+
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+namespace google {
+namespace protobuf {
+
+
+google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+Arena::ThreadCache& Arena::thread_cache() {
+  static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
+      new internal::ThreadLocalStorage<ThreadCache>();
+  return *thread_cache_->Get();
+}
+#elif defined(PROTOBUF_USE_DLLS)
+Arena::ThreadCache& Arena::thread_cache() {
+  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
+  return thread_cache_;
+}
+#else
+GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
+#endif
+
+void Arena::Init() {
+  lifecycle_id_ = lifecycle_id_generator_.GetNext();
+  blocks_ = 0;
+  hint_ = 0;
+  owns_first_block_ = true;
+  cleanup_list_ = 0;
+
+  if (options_.initial_block != NULL && options_.initial_block_size > 0) {
+    GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
+        << ": Initial block size too small for header.";
+
+    // Add first unowned block to list.
+    Block* first_block = reinterpret_cast<Block*>(options_.initial_block);
+    first_block->size = options_.initial_block_size;
+    first_block->pos = kHeaderSize;
+    first_block->next = NULL;
+    // Thread which calls Init() owns the first block. This allows the
+    // single-threaded case to allocate on the first block without taking any
+    // locks.
+    first_block->owner = &thread_cache();
+    SetThreadCacheBlock(first_block);
+    AddBlockInternal(first_block);
+    owns_first_block_ = false;
+  }
+
+  // Call the initialization hook
+  if (options_.on_arena_init != NULL) {
+    hooks_cookie_ = options_.on_arena_init(this);
+  } else {
+    hooks_cookie_ = NULL;
+  }
+}
+
+Arena::~Arena() {
+  uint64 space_allocated = ResetInternal();
+
+  // Call the destruction hook
+  if (options_.on_arena_destruction != NULL) {
+    options_.on_arena_destruction(this, hooks_cookie_, space_allocated);
+  }
+}
+
+uint64 Arena::Reset() {
+  // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
+  lifecycle_id_ = lifecycle_id_generator_.GetNext();
+  return ResetInternal();
+}
+
+uint64 Arena::ResetInternal() {
+  CleanupList();
+  uint64 space_allocated = FreeBlocks();
+
+  // Call the reset hook
+  if (options_.on_arena_reset != NULL) {
+    options_.on_arena_reset(this, hooks_cookie_, space_allocated);
+  }
+
+  return space_allocated;
+}
+
+Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
+                              size_t start_block_size, size_t max_block_size) {
+  size_t size;
+  if (my_last_block != NULL) {
+    // Double the current block size, up to a limit.
+    size = 2 * (my_last_block->size);
+    if (size > max_block_size) size = max_block_size;
+  } else {
+    size = start_block_size;
+  }
+  if (n > size - kHeaderSize) {
+    // TODO(sanjay): Check if n + kHeaderSize would overflow
+    size = kHeaderSize + n;
+  }
+
+  Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
+  b->pos = kHeaderSize + n;
+  b->size = size;
+  if (b->avail() == 0) {
+    // Do not attempt to reuse this block.
+    b->owner = NULL;
+  } else {
+    b->owner = me;
+  }
+#ifdef ADDRESS_SANITIZER
+  // Poison the rest of the block for ASAN. It was unpoisoned by the underlying
+  // malloc but it's not yet usable until we return it as part of an allocation.
+  ASAN_POISON_MEMORY_REGION(
+      reinterpret_cast<char*>(b) + b->pos, b->size - b->pos);
+#endif
+  return b;
+}
+
+void Arena::AddBlock(Block* b) {
+  MutexLock l(&blocks_lock_);
+  AddBlockInternal(b);
+}
+
+void Arena::AddBlockInternal(Block* b) {
+  b->next = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
+  if (b->avail() != 0) {
+    // Direct future allocations to this block.
+    google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
+  }
+}
+
+void Arena::AddListNode(void* elem, void (*cleanup)(void*)) {
+  Node* node = reinterpret_cast<Node*>(AllocateAligned(sizeof(Node)));
+  node->elem = elem;
+  node->cleanup = cleanup;
+  node->next = reinterpret_cast<Node*>(
+      google::protobuf::internal::NoBarrier_AtomicExchange(&cleanup_list_,
+            reinterpret_cast<google::protobuf::internal::AtomicWord>(node)));
+}
+
+void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) {
+  // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
+  n = (n + 7) & -8;
+
+  // Monitor allocation if needed.
+  if (GOOGLE_PREDICT_FALSE(hooks_cookie_ != NULL) &&
+      options_.on_arena_allocation != NULL) {
+    options_.on_arena_allocation(allocated, n, hooks_cookie_);
+  }
+
+  // If this thread already owns a block in this arena then try to use that.
+  // This fast path optimizes the case where multiple threads allocate from the
+  // same arena.
+  if (thread_cache().last_lifecycle_id_seen == lifecycle_id_ &&
+      thread_cache().last_block_used_ != NULL) {
+    if (thread_cache().last_block_used_->avail() < n) {
+      return SlowAlloc(n);
+    }
+    return AllocFromBlock(thread_cache().last_block_used_, n);
+  }
+
+  // Check whether we own the last accessed block on this arena.
+  // This fast path optimizes the case where a single thread uses multiple
+  // arenas.
+  void* me = &thread_cache();
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
+  if (!b || b->owner != me || b->avail() < n) {
+    return SlowAlloc(n);
+  }
+  return AllocFromBlock(b, n);
+}
+
+void* Arena::AllocFromBlock(Block* b, size_t n) {
+  size_t p = b->pos;
+  b->pos = p + n;
+#ifdef ADDRESS_SANITIZER
+  ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n);
+#endif
+  return reinterpret_cast<char*>(b) + p;
+}
+
+void* Arena::SlowAlloc(size_t n) {
+  void* me = &thread_cache();
+  Block* b = FindBlock(me);  // Find block owned by me.
+  // See if allocation fits in my latest block.
+  if (b != NULL && b->avail() >= n) {
+    SetThreadCacheBlock(b);
+    google::protobuf::internal::NoBarrier_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
+    return AllocFromBlock(b, n);
+  }
+  b = NewBlock(me, b, n, options_.start_block_size, options_.max_block_size);
+  AddBlock(b);
+  if (b->owner == me) {  // If this block can be reused (see NewBlock()).
+    SetThreadCacheBlock(b);
+  }
+  return reinterpret_cast<char*>(b) + kHeaderSize;
+}
+
+uint64 Arena::SpaceAllocated() const {
+  uint64 space_allocated = 0;
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  while (b != NULL) {
+    space_allocated += (b->size);
+    b = b->next;
+  }
+  return space_allocated;
+}
+
+uint64 Arena::SpaceUsed() const {
+  uint64 space_used = 0;
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  while (b != NULL) {
+    space_used += (b->pos - kHeaderSize);
+    b = b->next;
+  }
+  return space_used;
+}
+
+pair<uint64, uint64> Arena::SpaceAllocatedAndUsed() const {
+  uint64 allocated = 0;
+  uint64 used = 0;
+
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  while (b != NULL) {
+    allocated += b->size;
+    used += (b->pos - kHeaderSize);
+    b = b->next;
+  }
+  return std::make_pair(allocated, used);
+}
+
+uint64 Arena::FreeBlocks() {
+  uint64 space_allocated = 0;
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  Block* first_block = NULL;
+  while (b != NULL) {
+    space_allocated += (b->size);
+    Block* next = b->next;
+    if (next != NULL) {
+      options_.block_dealloc(b, b->size);
+    } else {
+      if (owns_first_block_) {
+        options_.block_dealloc(b, b->size);
+      } else {
+        // User passed in the first block, skip free'ing the memory.
+        first_block = b;
+      }
+    }
+    b = next;
+  }
+  blocks_ = 0;
+  hint_ = 0;
+  if (!owns_first_block_) {
+    // Make the first block that was passed in through ArenaOptions
+    // available for reuse.
+    first_block->pos = kHeaderSize;
+    // Thread which calls Reset() owns the first block. This allows the
+    // single-threaded case to allocate on the first block without taking any
+    // locks.
+    first_block->owner = &thread_cache();
+    SetThreadCacheBlock(first_block);
+    AddBlockInternal(first_block);
+  }
+  return space_allocated;
+}
+
+void Arena::CleanupList() {
+  Node* head =
+      reinterpret_cast<Node*>(google::protobuf::internal::NoBarrier_Load(&cleanup_list_));
+  while (head != NULL) {
+    head->cleanup(head->elem);
+    head = head->next;
+  }
+  cleanup_list_ = 0;
+}
+
+Arena::Block* Arena::FindBlock(void* me) {
+  // TODO(sanjay): We might want to keep a separate list with one
+  // entry per thread.
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&blocks_));
+  while (b != NULL && b->owner != me) {
+    b = b->next;
+  }
+  return b;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
new file mode 100644
index 0000000..b4344da
--- /dev/null
+++ b/src/google/protobuf/arena.h
@@ -0,0 +1,925 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_H__
+#define GOOGLE_PROTOBUF_ARENA_H__
+
+#include <limits>
+#ifdef max
+#undef max  // Visual Studio defines this macro
+#endif
+#if __cplusplus >= 201103L
+#include <google/protobuf/stubs/type_traits.h>
+#endif
+#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
+// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
+#include <exception>
+#include <typeinfo>
+namespace std {
+using type_info = ::type_info;
+}
+#else
+#include <typeinfo>
+#endif
+
+#include <google/protobuf/stubs/atomic_sequence_num.h>
+#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/type_traits.h>
+
+
+namespace google {
+namespace protobuf {
+
+class Arena;       // defined below
+class Message;     // message.h
+
+namespace internal {
+class ArenaString; // arenastring.h
+class LazyField;   // lazy_field.h
+
+template<typename Type>
+class GenericTypeHandler; // repeated_field.h
+
+// Templated cleanup methods.
+template<typename T> void arena_destruct_object(void* object) {
+  reinterpret_cast<T*>(object)->~T();
+}
+template<typename T> void arena_delete_object(void* object) {
+  delete reinterpret_cast<T*>(object);
+}
+inline void arena_free(void* object, size_t /* size */) {
+  free(object);
+}
+
+}  // namespace internal
+
+// ArenaOptions provides optional additional parameters to arena construction
+// that control its block-allocation behavior.
+struct ArenaOptions {
+  // This defines the size of the first block requested from the system malloc.
+  // Subsequent block sizes will increase in a geometric series up to a maximum.
+  size_t start_block_size;
+
+  // This defines the maximum block size requested from system malloc (unless an
+  // individual arena allocation request occurs with a size larger than this
+  // maximum). Requested block sizes increase up to this value, then remain
+  // here.
+  size_t max_block_size;
+
+  // An initial block of memory for the arena to use, or NULL for none. If
+  // provided, the block must live at least as long as the arena itself. The
+  // creator of the Arena retains ownership of the block after the Arena is
+  // destroyed.
+  char* initial_block;
+
+  // The size of the initial block, if provided.
+  size_t initial_block_size;
+
+  // A function pointer to an alloc method that returns memory blocks of size
+  // requested. By default, it contains a ptr to the malloc function.
+  //
+  // NOTE: block_alloc and dealloc functions are expected to behave like
+  // malloc and free, including Asan poisoning.
+  void* (*block_alloc)(size_t);
+  // A function pointer to a dealloc method that takes ownership of the blocks
+  // from the arena. By default, it contains a ptr to a wrapper function that
+  // calls free.
+  void (*block_dealloc)(void*, size_t);
+
+  // Hooks for adding external functionality such as user-specific metrics
+  // collection, specific debugging abilities, etc.
+  // Init hook may return a pointer to a cookie to be stored in the arena.
+  // reset and destruction hooks will then be called with the same cookie
+  // pointer. This allows us to save an external object per arena instance and
+  // use it on the other hooks (Note: It is just as legal for init to return
+  // NULL and not use the cookie feature).
+  // on_arena_reset and on_arena_destruction also receive the space used in
+  // the arena just before the reset.
+  void* (*on_arena_init)(Arena* arena);
+  void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
+  void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
+
+  // type_info is promised to be static - its lifetime extends to
+  // match program's lifetime (It is given by typeid operator).
+  // Note: typeid(void) will be passed as allocated_type every time we
+  // intentionally want to avoid monitoring an allocation. (i.e. internal
+  // allocations for managing the arena)
+  void (*on_arena_allocation)(const std::type_info* allocated_type,
+      uint64 alloc_size, void* cookie);
+
+  ArenaOptions()
+      : start_block_size(kDefaultStartBlockSize),
+        max_block_size(kDefaultMaxBlockSize),
+        initial_block(NULL),
+        initial_block_size(0),
+        block_alloc(&malloc),
+        block_dealloc(&internal::arena_free),
+        on_arena_init(NULL),
+        on_arena_reset(NULL),
+        on_arena_destruction(NULL),
+        on_arena_allocation(NULL) {}
+
+ private:
+  // Constants define default starting block size and max block size for
+  // arena allocator behavior -- see descriptions above.
+  static const size_t kDefaultStartBlockSize = 256;
+  static const size_t kDefaultMaxBlockSize   = 8192;
+};
+
+// Support for non-RTTI environments. (The metrics hooks API uses type
+// information.)
+#if !defined(GOOGLE_PROTOBUF_NO_RTTI) && defined(__GXX_RTTI)
+#define RTTI_TYPE_ID(type) (&typeid(type))
+#else
+#define RTTI_TYPE_ID(type) (NULL)
+#endif
+
+// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
+// with new/delete, and improves performance by aggregating allocations into
+// larger blocks and freeing allocations all at once. Protocol messages are
+// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
+// are automatically freed when the arena is destroyed.
+//
+// This is a thread-safe implementation: multiple threads may allocate from the
+// arena concurrently. Destruction is not thread-safe and the destructing
+// thread must synchronize with users of the arena first.
+//
+// An arena provides two allocation interfaces: CreateMessage<T>, which works
+// for arena-enabled proto2 message types as well as other types that satisfy
+// the appropriate protocol (described below), and Create<T>, which works for
+// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
+// because this interface (i) passes the arena pointer to the created object so
+// that its sub-objects and internal allocations can use the arena too, and (ii)
+// elides the object's destructor call when possible. Create<T> does not place
+// any special requirements on the type T, and will invoke the object's
+// destructor when the arena is destroyed.
+//
+// The arena message allocation protocol, required by CreateMessage<T>, is as
+// follows:
+//
+// - The type T must have (at least) two constructors: a constructor with no
+//   arguments, called when a T is allocated on the heap; and a constructor with
+//   a google::protobuf::Arena* argument, called when a T is allocated on an arena. If the
+//   second constructor is called with a NULL arena pointer, it must be
+//   equivalent to invoking the first (no-argument) constructor.
+//
+// - The type T must have a particular type trait: a nested type
+//   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
+//   such type trait exists, then the instantiation CreateMessage<T> will fail
+//   to compile.
+//
+// - The type T *may* have the type trait |DestructorSkippable_|. If this type
+//   trait is present in the type, then its destructor will not be called if and
+//   only if it was passed a non-NULL arena pointer. If this type trait is not
+//   present on the type, then its destructor is always called when the
+//   containing arena is destroyed.
+//
+// - One- and two-user-argument forms of CreateMessage<T>() also exist that
+//   forward these constructor arguments to T's constructor: for example,
+//   CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
+//   arg1, arg2).
+//
+// This protocol is implemented by all arena-enabled proto2 message classes as
+// well as RepeatedPtrField.
+
+#if __cplusplus >= 201103L
+class Arena final {
+#else
+class LIBPROTOBUF_EXPORT Arena {
+#endif
+ public:
+  // Arena constructor taking custom options. See ArenaOptions below for
+  // descriptions of the options available.
+  explicit Arena(const ArenaOptions& options) : options_(options) {
+    Init();
+  }
+
+  // Default constructor with sensible default options, tuned for average
+  // use-cases.
+  Arena() {
+    Init();
+  }
+
+  // Destructor deletes all owned heap allocated objects, and destructs objects
+  // that have non-trivial destructors, except for proto2 message objects whose
+  // destructors can be skipped. Also, frees all blocks except the initial block
+  // if it was passed in.
+  ~Arena();
+
+  // API to create proto2 message objects on the arena. If the arena passed in
+  // is NULL, then a heap allocated object is returned. Type T must be a message
+  // defined in a .proto file with cc_enable_arenas set to true, otherwise a
+  // compilation error will occur.
+  //
+  // RepeatedField and RepeatedPtrField may also be instantiated directly on an
+  // arena with this method.
+  //
+  // This function also accepts any type T that satisfies the arena message
+  // allocation protocol, documented above.
+  template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessage(::google::protobuf::Arena* arena) {
+    if (arena == NULL) {
+      return new T;
+    } else {
+      return arena->CreateMessageInternal<T>(static_cast<T*>(0));
+    }
+  }
+
+  // One-argument form of CreateMessage. This is useful for constructing objects
+  // that implement the arena message construction protocol described above but
+  // take additional constructor arguments.
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessage(::google::protobuf::Arena* arena, const Arg& arg) {
+    if (arena == NULL) {
+      return new T(NULL, arg);
+    } else {
+      return arena->CreateMessageInternal<T>(static_cast<T*>(0),
+                                             arg);
+    }
+  }
+
+  // Two-argument form of CreateMessage. This is useful for constructing objects
+  // that implement the arena message construction protocol described above but
+  // take additional constructor arguments.
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessage(::google::protobuf::Arena* arena,
+                          const Arg1& arg1,
+                          const Arg2& arg2) {
+    if (arena == NULL) {
+      return new T(NULL, arg1, arg2);
+    } else {
+      return arena->CreateMessageInternal<T>(static_cast<T*>(0),
+                                             arg1, arg2);
+    }
+  }
+
+  // API to create any objects on the arena. Note that only the object will
+  // be created on the arena; the underlying ptrs (in case of a proto2 message)
+  // will be still heap allocated. Proto messages should usually be allocated
+  // with CreateMessage<T>() instead.
+  //
+  // Note that even if T satisfies the arena message construction protocol
+  // (InternalArenaConstructable_ trait and optional DestructorSkippable_
+  // trait), as described above, this function does not follow the protocol;
+  // instead, it treats T as a black-box type, just as if it did not have these
+  // traits. Specifically, T's constructor arguments will always be only those
+  // passed to Create<T>() -- no additional arena pointer is implicitly added.
+  // Furthermore, the destructor will always be called at arena destruction time
+  // (unless the destructor is trivial). Hence, from T's point of view, it is as
+  // if the object were allocated on the heap (except that the underlying memory
+  // is obtained from the arena).
+  template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* Create(::google::protobuf::Arena* arena) {
+    if (arena == NULL) {
+      return new T();
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value);
+    }
+  }
+
+  // Version of the above with one constructor argument for the created object.
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* Create(::google::protobuf::Arena* arena, const Arg& arg) {
+    if (arena == NULL) {
+      return new T(arg);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg);
+    }
+  }
+
+  // Version of the above with two constructor arguments for the created object.
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* Create(::google::protobuf::Arena* arena, const Arg1& arg1, const Arg2& arg2) {
+    if (arena == NULL) {
+      return new T(arg1, arg2);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2);
+    }
+  }
+
+  // Version of the above with three constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3);
+    }
+  }
+
+  // Version of the above with four constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4);
+    }
+  }
+
+  // Version of the above with five constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5);
+    }
+  }
+
+  // Version of the above with six constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+  }
+
+  // Version of the above with seven constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6,
+                                           const Arg7& arg7) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+  }
+
+  // Version of the above with eight constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7,
+            typename Arg8>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6,
+                                           const Arg7& arg7, const Arg8& arg8) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    } else {
+      return arena->CreateInternal<T>(
+          google::protobuf::internal::has_trivial_destructor<T>::value,
+          arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    }
+  }
+
+  // Create an array of object type T on the arena *without* invoking the
+  // constructor of T. If `arena` is null, then the return value should be freed
+  // with `delete[] x;` (or `::operator delete[](x);`).
+  // To ensure safe uses, this function checks at compile time
+  // (when compiled as C++11) that T is trivially default-constructible and
+  // trivially destructible.
+  template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
+    GOOGLE_CHECK_LE(num_elements,
+             std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    if (arena == NULL) {
+      return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
+    } else {
+      return arena->CreateInternalRawArray<T>(num_elements);
+    }
+  }
+
+  // Returns the total space used by the arena, which is the sums of the sizes
+  // of the underlying blocks. The total space used may not include the new
+  // blocks that are allocated by this arena from other threads concurrently
+  // with the call to this method.
+  GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceAllocated() const;
+  // As above, but does not include any free space in underlying blocks.
+  GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() const;
+
+  // Combines SpaceAllocated and SpaceUsed. Returns a pair of
+  // <space_allocated, space_used>.
+  GOOGLE_ATTRIBUTE_NOINLINE pair<uint64, uint64> SpaceAllocatedAndUsed() const;
+
+  // Frees all storage allocated by this arena after calling destructors
+  // registered with OwnDestructor() and freeing objects registered with Own().
+  // Any objects allocated on this arena are unusable after this call. It also
+  // returns the total space used by the arena which is the sums of the sizes
+  // of the allocated blocks. This method is not thread-safe.
+  GOOGLE_ATTRIBUTE_NOINLINE uint64 Reset();
+
+  // Adds |object| to a list of heap-allocated objects to be freed with |delete|
+  // when the arena is destroyed or reset.
+  template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
+  void Own(T* object) {
+    OwnInternal(object, google::protobuf::internal::is_convertible<T*, ::google::protobuf::Message*>());
+  }
+
+  // Adds |object| to a list of objects whose destructors will be manually
+  // called when the arena is destroyed or reset. This differs from Own() in
+  // that it does not free the underlying memory with |delete|; hence, it is
+  // normally only used for objects that are placement-newed into
+  // arena-allocated memory.
+  template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
+  void OwnDestructor(T* object) {
+    if (object != NULL) {
+      AddListNode(object, &internal::arena_destruct_object<T>);
+    }
+  }
+
+  // Adds a custom member function on an object to the list of destructors that
+  // will be manually called when the arena is destroyed or reset. This differs
+  // from OwnDestructor() in that any member function may be specified, not only
+  // the class destructor.
+  GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object,
+                                              void (*destruct)(void*)) {
+    AddListNode(object, destruct);
+  }
+
+  // Retrieves the arena associated with |value| if |value| is an arena-capable
+  // message, or NULL otherwise. This differs from value->GetArena() in that the
+  // latter is a virtual call, while this method is a templated call that
+  // resolves at compile-time.
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static ::google::protobuf::Arena* GetArena(const T* value) {
+    return GetArenaInternal(value, static_cast<T*>(0));
+  }
+
+ private:
+  struct InternalIsArenaConstructableHelper {
+    template<typename U>
+    static char ArenaConstructable(
+        const typename U::InternalArenaConstructable_*);
+    template<typename U>
+    static double ArenaConstructable(...);
+  };
+
+ public:
+  // Helper typetrait that indicates support for arenas in a type T at compile
+  // time. This is public only to allow construction of higher-level templated
+  // utilities. is_arena_constructable<T>::value is true if the message type T
+  // has arena support enabled, and false otherwise.
+  //
+  // This is inside Arena because only Arena has the friend relationships
+  // necessary to see the underlying generated code traits.
+  template <typename T>
+  struct is_arena_constructable
+      : public google::protobuf::internal::integral_constant<
+            bool, sizeof(InternalIsArenaConstructableHelper::ArenaConstructable<
+                         const T>(static_cast<const T*>(0))) == sizeof(char)> {
+  };
+
+ private:
+  // Blocks are variable length malloc-ed objects.  The following structure
+  // describes the common header for all blocks.
+  struct Block {
+    void* owner;   // &ThreadCache of thread that owns this block, or
+                   // &this->owner if not yet owned by a thread.
+    Block* next;   // Next block in arena (may have different owner)
+    // ((char*) &block) + pos is next available byte. It is always
+    // aligned at a multiple of 8 bytes.
+    size_t pos;
+    size_t size;  // total size of the block.
+    GOOGLE_ATTRIBUTE_ALWAYS_INLINE size_t avail() const { return size - pos; }
+    // data follows
+  };
+
+  template<typename Type> friend class ::google::protobuf::internal::GenericTypeHandler;
+  friend class MockArena;              // For unit-testing.
+  friend class internal::ArenaString;  // For AllocateAligned.
+  friend class internal::LazyField;    // For CreateMaybeMessage.
+
+  struct ThreadCache {
+    // The ThreadCache is considered valid as long as this matches the
+    // lifecycle_id of the arena being used.
+    int64 last_lifecycle_id_seen;
+    Block* last_block_used_;
+  };
+
+  static const size_t kHeaderSize = sizeof(Block);
+  static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+  // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
+  // local storage class we implemented.
+  // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
+  static ThreadCache& thread_cache();
+#elif defined(PROTOBUF_USE_DLLS)
+  // Thread local variables cannot be exposed through DLL interface but we can
+  // wrap them in static functions.
+  static ThreadCache& thread_cache();
+#else
+  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
+  static ThreadCache& thread_cache() { return thread_cache_; }
+#endif
+
+  // SFINAE for skipping addition to delete list for a message type when created
+  // with CreateMessage. This is mainly to skip proto2/proto1 message objects
+  // with cc_enable_arenas=true from being part of the delete list. Also, note,
+  // compiler will optimize out the branch in CreateInternal<T>.
+  template<typename T>
+  static inline bool SkipDeleteList(typename T::DestructorSkippable_*) {
+    return true;
+  }
+
+  // For message objects that don't have the DestructorSkippable_ trait, we
+  // always add to the delete list.
+  template<typename T>
+  static inline bool SkipDeleteList(...) {
+    return google::protobuf::internal::has_trivial_destructor<T>::value;
+  }
+
+ private:
+  struct InternalIsDestructorSkippableHelper {
+    template<typename U>
+    static char DestructorSkippable(
+        const typename U::DestructorSkippable_*);
+    template<typename U>
+    static double DestructorSkippable(...);
+  };
+
+ public:
+  // Helper typetrait that indicates whether the desctructor of type T should be
+  // called when arena is destroyed at compile time. This is only to allow
+  // construction of higher-level templated utilities.
+  // is_destructor_skippable<T>::value is true if the destructor of the message
+  // type T should not be called when arena is destroyed or false otherwise.
+  // This is inside Arena because only Arena has the friend relationships
+  // necessary to see the underlying generated code traits.
+  template<typename T>
+  struct is_destructor_skippable
+      : public google::protobuf::internal::integral_constant<
+            bool,
+            sizeof(InternalIsDestructorSkippableHelper::DestructorSkippable<
+                   const T>(static_cast<const T*>(0))) == sizeof(char) ||
+                google::protobuf::internal::has_trivial_destructor<T>::value> {};
+
+  // CreateMessage<T> requires that T supports arenas, but this private method
+  // works whether or not T supports arenas. These are not exposed to user code
+  // as it can cause confusing API usages, and end up having double free in
+  // user code. These are used only internally from LazyField and Repeated
+  // fields, since they are designed to work in all mode combinations.
+  template<typename Msg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static Msg* CreateMaybeMessage(
+      Arena* arena, typename Msg::InternalArenaConstructable_*) {
+    return CreateMessage<Msg>(arena);
+  }
+
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMaybeMessage(Arena* arena, ...) {
+    return Create<T>(arena);
+  }
+
+  // Just allocate the required size for the given type assuming the
+  // type has a trivial constructor.
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateInternalRawArray(size_t num_elements) {
+    GOOGLE_CHECK_LE(num_elements,
+             std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
+    return static_cast<T*>(
+        AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements));
+  }
+
+  template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateInternal(bool skip_explicit_ownership) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T();
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateInternal(bool skip_explicit_ownership, const Arg& arg) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateInternal(
+      bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3,
+                                            const Arg4& arg4) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3,
+                                            const Arg4& arg4,
+                                            const Arg5& arg5) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3,
+                                            const Arg4& arg4,
+                                            const Arg5& arg5,
+                                            const Arg6& arg6) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3,
+                                            const Arg4& arg4,
+                                            const Arg5& arg5,
+                                            const Arg6& arg6,
+                                            const Arg7& arg7) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7,
+            typename Arg8>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
+                                            const Arg1& arg1,
+                                            const Arg2& arg2,
+                                            const Arg3& arg3,
+                                            const Arg4& arg4,
+                                            const Arg5& arg5,
+                                            const Arg6& arg6,
+                                            const Arg7& arg7,
+                                            const Arg8& arg8) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
+    return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                     this);
+  }
+
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
+                           const Arg& arg) {
+    return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                     this, arg);
+  }
+
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
+                           const Arg1& arg1, const Arg2& arg2) {
+    return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                     this, arg1, arg2);
+  }
+
+  // CreateInArenaStorage is used to implement map field. Without it,
+  // google::protobuf::Map need to call generated message's protected arena constructor,
+  // which needs to declare google::protobuf::Map as friend of generated message.
+  template <typename T>
+  static void CreateInArenaStorage(T* ptr, Arena* arena) {
+    CreateInArenaStorageInternal(ptr, arena,
+                                 typename is_arena_constructable<T>::type());
+    RegisterDestructorInternal(ptr, arena,
+                               typename is_destructor_skippable<T>::type());
+  }
+
+  template <typename T>
+  static void CreateInArenaStorageInternal(
+      T* ptr, Arena* arena, google::protobuf::internal::true_type) {
+    new (ptr) T(arena);
+  }
+  template <typename T>
+  static void CreateInArenaStorageInternal(
+      T* ptr, Arena*, google::protobuf::internal::false_type) {
+    new (ptr) T;
+  }
+
+  template <typename T>
+  static void RegisterDestructorInternal(
+      T*, Arena*, google::protobuf::internal::true_type) {}
+  template <typename T>
+  static void RegisterDestructorInternal(
+      T* ptr, Arena* arena, google::protobuf::internal::false_type) {
+    arena->OwnDestructor(ptr);
+  }
+
+  // These implement Own(), which registers an object for deletion (destructor
+  // call and operator delete()). The second parameter has type 'true_type' if T
+  // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
+  // all template instantiations to one for generic Message reduces code size,
+  // using the virtual destructor instead.
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  void OwnInternal(T* object, google::protobuf::internal::true_type) {
+    if (object != NULL) {
+      AddListNode(object, &internal::arena_delete_object< ::google::protobuf::Message >);
+    }
+  }
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  void OwnInternal(T* object, google::protobuf::internal::false_type) {
+    if (object != NULL) {
+      AddListNode(object, &internal::arena_delete_object<T>);
+    }
+  }
+
+  // Implementation for GetArena(). Only message objects with
+  // InternalArenaConstructable_ tags can be associated with an arena, and such
+  // objects must implement a GetArenaNoVirtual() method.
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static ::google::protobuf::Arena* GetArenaInternal(
+      const T* value, typename T::InternalArenaConstructable_*) {
+    return value->GetArenaNoVirtual();
+  }
+
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static ::google::protobuf::Arena* GetArenaInternal(const T*, ...) {
+    return NULL;
+  }
+
+  // Allocate and also optionally call on_arena_allocation callback with the
+  // allocated type info when the hooks are in place in ArenaOptions and
+  // the cookie is not null.
+  void* AllocateAligned(const std::type_info* allocated, size_t n);
+
+  // Allocate an internal allocation, avoiding optional typed monitoring.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* AllocateAligned(size_t n) {
+    return AllocateAligned(NULL, n);
+  }
+
+  void Init();
+
+  // Free all blocks and return the total space used which is the sums of sizes
+  // of the all the allocated blocks.
+  uint64 FreeBlocks();
+
+  // Add object pointer and cleanup function pointer to the list.
+  // TODO(rohananil, cfallin): We could pass in a sub-arena into this method
+  // to avoid polluting blocks of this arena with list nodes. This would help in
+  // mixed mode (where many protobufs have cc_enable_arenas=false), and is an
+  // alternative to a chunked linked-list, but with extra overhead of *next.
+  void AddListNode(void* elem, void (*cleanup)(void*));
+  // Delete or Destruct all objects owned by the arena.
+  void CleanupList();
+  uint64 ResetInternal();
+
+  inline void SetThreadCacheBlock(Block* block) {
+    thread_cache().last_block_used_ = block;
+    thread_cache().last_lifecycle_id_seen = lifecycle_id_;
+  }
+
+  int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
+
+  google::protobuf::internal::AtomicWord blocks_;  // Head of linked list of all allocated blocks
+  google::protobuf::internal::AtomicWord hint_;    // Fast thread-local block access
+
+  // Node contains the ptr of the object to be cleaned up and the associated
+  // cleanup function ptr.
+  struct Node {
+    void* elem;              // Pointer to the object to be cleaned up.
+    void (*cleanup)(void*);  // Function pointer to the destructor or deleter.
+    Node* next;              // Next node in the list.
+  };
+
+  google::protobuf::internal::AtomicWord cleanup_list_;  // Head of a linked list of nodes containing object
+                             // ptrs and cleanup methods.
+
+  bool owns_first_block_;    // Indicates that arena owns the first block
+  Mutex blocks_lock_;
+
+  void AddBlock(Block* b);
+  // Access must be synchronized, either by blocks_lock_ or by being called from
+  // Init()/Reset().
+  void AddBlockInternal(Block* b);
+  void* SlowAlloc(size_t n);
+  Block* FindBlock(void* me);
+  Block* NewBlock(void* me, Block* my_last_block, size_t n,
+                  size_t start_block_size, size_t max_block_size);
+  static void* AllocFromBlock(Block* b, size_t n);
+  template <typename Key, typename T>
+  friend class Map;
+
+  // The arena may save a cookie it receives from the external on_init hook
+  // and then use it when calling the on_reset and on_destruction hooks.
+  void* hooks_cookie_;
+
+  ArenaOptions options_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
+};
+
+// Defined above for supporting environments without RTTI.
+#undef RTTI_TYPE_ID
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ARENA_H__
diff --git a/src/google/protobuf/arena_nc.cc b/src/google/protobuf/arena_nc.cc
new file mode 100644
index 0000000..f2f0842
--- /dev/null
+++ b/src/google/protobuf/arena_nc.cc
@@ -0,0 +1,45 @@
+// 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 test for arena usage.
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/unittest.pb.h>
+
+#ifdef TEST_ARENA_PRIVATE_CONSTRUCTOR
+
+namespace google {
+void ArenaPrivateConstructor() {
+  google::protobuf::Arena arena;
+  protobuf_unittest::TestAllTypes message(&arena);
+}
+
+#endif
+}  // namespace google
diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py
new file mode 100644
index 0000000..56a7dd0
--- /dev/null
+++ b/src/google/protobuf/arena_nc_test.py
@@ -0,0 +1,61 @@
+#! /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/arena_test_util.cc b/src/google/protobuf/arena_test_util.cc
new file mode 100644
index 0000000..df9c5bd
--- /dev/null
+++ b/src/google/protobuf/arena_test_util.cc
@@ -0,0 +1,50 @@
+// 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.
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
+
+
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+NoHeapChecker::~NoHeapChecker() {
+  capture_alloc.Unhook();
+  EXPECT_EQ(0, capture_alloc.alloc_count());
+  EXPECT_EQ(0, capture_alloc.free_count());
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
new file mode 100644
index 0000000..690cc70
--- /dev/null
+++ b/src/google/protobuf/arena_test_util.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class NoHeapChecker {
+ public:
+  NoHeapChecker() {
+    capture_alloc.Hook();
+  }
+  ~NoHeapChecker();
+ private:
+  class NewDeleteCapture {
+   public:
+    // TOOD(xiaofeng): Implement this for opensource protobuf.
+    void Hook() {}
+    void Unhook() {}
+    int alloc_count() { return 0; }
+    int free_count() { return 0; }
+  } capture_alloc;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
new file mode 100644
index 0000000..ab25ffe
--- /dev/null
+++ b/src/google/protobuf/arena_unittest.cc
@@ -0,0 +1,1354 @@
+// 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.
+
+#include <google/protobuf/arena.h>
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <typeinfo>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_arena.pb.h>
+#include <google/protobuf/unittest_no_arena.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <gtest/gtest.h>
+
+
+namespace google {
+using proto2_arena_unittest::ArenaMessage;
+using protobuf_unittest::TestAllTypes;
+using protobuf_unittest::TestAllExtensions;
+using protobuf_unittest::TestOneof2;
+using protobuf_unittest::TestEmptyMessage;
+
+namespace protobuf {
+namespace {
+
+class Notifier {
+ public:
+  Notifier() : count_(0) {}
+  void Notify() {
+    count_++;
+  }
+  int GetCount() {
+    return count_;
+  }
+
+ private:
+  int count_;
+};
+
+class SimpleDataType {
+ public:
+  SimpleDataType() : notifier_(NULL) {}
+  void SetNotifier(Notifier* notifier) {
+    notifier_ = notifier;
+  }
+  virtual ~SimpleDataType() {
+    if (notifier_ != NULL) {
+      notifier_->Notify();
+    }
+  };
+ private:
+  Notifier* notifier_;
+};
+
+// A simple class that does not allow copying and so cannot be used as a
+// parameter type without "const &".
+class PleaseDontCopyMe {
+ public:
+  explicit PleaseDontCopyMe(int value) : value_(value) {}
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PleaseDontCopyMe);
+};
+
+// A class that takes four different types as constructor arguments.
+class MustBeConstructedWithOneThroughFour {
+ public:
+  MustBeConstructedWithOneThroughFour(
+      int one, const char* two, const string& three,
+      const PleaseDontCopyMe* four)
+      : one_(one), two_(two), three_(three), four_(four) {}
+
+  int one_;
+  const char* const two_;
+  string three_;
+  const PleaseDontCopyMe* four_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour);
+};
+
+// A class that takes eight different types as constructor arguments.
+class MustBeConstructedWithOneThroughEight {
+ public:
+  MustBeConstructedWithOneThroughEight(
+      int one, const char* two, const string& three,
+      const PleaseDontCopyMe* four, int five, const char* six,
+      const string& seven, const string& eight)
+      : one_(one), two_(two), three_(three), four_(four), five_(five),
+        six_(six), seven_(seven), eight_(eight) {}
+
+  int one_;
+  const char* const two_;
+  string three_;
+  const PleaseDontCopyMe* four_;
+  int five_;
+  const char* const six_;
+  string seven_;
+  string eight_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughEight);
+};
+
+}  // namespace
+
+TEST(ArenaTest, ArenaConstructable) {
+  EXPECT_TRUE(Arena::is_arena_constructable<TestAllTypes>::type::value);
+  EXPECT_TRUE(Arena::is_arena_constructable<const TestAllTypes>::type::value);
+  EXPECT_FALSE(Arena::is_arena_constructable<Arena>::type::value);
+}
+
+TEST(ArenaTest, BasicCreate) {
+  Arena arena;
+  EXPECT_TRUE(Arena::Create<int32>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<int64>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<float>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<double>(&arena) != NULL);
+  EXPECT_TRUE(Arena::Create<string>(&arena) != NULL);
+  arena.Own(new int32);
+  arena.Own(new int64);
+  arena.Own(new float);
+  arena.Own(new double);
+  arena.Own(new string);
+  arena.Own<int>(NULL);
+  Notifier notifier;
+  SimpleDataType* data = Arena::Create<SimpleDataType>(&arena);
+  data->SetNotifier(&notifier);
+  data = new SimpleDataType;
+  data->SetNotifier(&notifier);
+  arena.Own(data);
+  arena.Reset();
+  EXPECT_EQ(2, notifier.GetCount());
+}
+
+TEST(ArenaTest, CreateWithFourConstructorArguments) {
+  Arena arena;
+  const string three("3");
+  const PleaseDontCopyMe four(4);
+  const MustBeConstructedWithOneThroughFour* new_object =
+      Arena::Create<MustBeConstructedWithOneThroughFour>(
+          &arena, 1, "2", three, &four);
+  EXPECT_TRUE(new_object != NULL);
+  ASSERT_EQ(1, new_object->one_);
+  ASSERT_STREQ("2", new_object->two_);
+  ASSERT_EQ("3", new_object->three_);
+  ASSERT_EQ(4, new_object->four_->value());
+}
+
+TEST(ArenaTest, CreateWithEightConstructorArguments) {
+  Arena arena;
+  const string three("3");
+  const PleaseDontCopyMe four(4);
+  const string seven("7");
+  const string eight("8");
+  const MustBeConstructedWithOneThroughEight* new_object =
+      Arena::Create<MustBeConstructedWithOneThroughEight>(
+          &arena, 1, "2", three, &four, 5, "6", seven, eight);
+  EXPECT_TRUE(new_object != NULL);
+  ASSERT_EQ(1, new_object->one_);
+  ASSERT_STREQ("2", new_object->two_);
+  ASSERT_EQ("3", new_object->three_);
+  ASSERT_EQ(4, new_object->four_->value());
+  ASSERT_EQ(5, new_object->five_);
+  ASSERT_STREQ("6", new_object->six_);
+  ASSERT_EQ("7", new_object->seven_);
+  ASSERT_EQ("8", new_object->eight_);
+}
+
+TEST(ArenaTest, InitialBlockTooSmall) {
+  // Construct a small (64 byte) initial block of memory to be used by the
+  // arena allocator; then, allocate an object which will not fit in the
+  // initial block.
+  std::vector<char> arena_block(64);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  char* p = ::google::protobuf::Arena::CreateArray<char>(&arena, 96);
+  uintptr_t allocation = reinterpret_cast<uintptr_t>(p);
+
+  // Ensure that the arena allocator did not return memory pointing into the
+  // initial block of memory.
+  uintptr_t arena_start = reinterpret_cast<uintptr_t>(&arena_block[0]);
+  uintptr_t arena_end = arena_start + arena_block.size();
+  EXPECT_FALSE(allocation >= arena_start && allocation < arena_end);
+
+  // Write to the memory we allocated; this should (but is not guaranteed to)
+  // trigger a check for heap corruption if the object was allocated from the
+  // initially-provided block.
+  memset(p, '\0', 96);
+}
+
+TEST(ArenaTest, Parsing) {
+  TestAllTypes original;
+  TestUtil::SetAllFields(&original);
+
+  // Test memory leak.
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  TestUtil::ExpectAllFieldsSet(*arena_message);
+
+  // Test that string fields have null terminator bytes (earlier bug).
+  EXPECT_EQ(strlen(original.optional_string().c_str()),
+            strlen(arena_message->optional_string().c_str()));
+}
+
+TEST(ArenaTest, UnknownFields) {
+  TestAllTypes original;
+  TestUtil::SetAllFields(&original);
+
+  // Test basic parsing into (populating) and reading out of unknown fields on
+  // an arena.
+  Arena arena;
+  TestEmptyMessage* arena_message =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+
+  TestAllTypes copied;
+  copied.ParseFromString(arena_message->SerializeAsString());
+  TestUtil::ExpectAllFieldsSet(copied);
+
+  // Exercise UFS manual manipulation (setters).
+  arena_message = Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message->mutable_unknown_fields()->AddVarint(
+      TestAllTypes::kOptionalInt32FieldNumber, 42);
+  copied.Clear();
+  copied.ParseFromString(arena_message->SerializeAsString());
+  EXPECT_TRUE(copied.has_optional_int32());
+  EXPECT_EQ(42, copied.optional_int32());
+
+  // Exercise UFS swap path.
+  TestEmptyMessage* arena_message_2 =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message_2->Swap(arena_message);
+  copied.Clear();
+  copied.ParseFromString(arena_message_2->SerializeAsString());
+  EXPECT_TRUE(copied.has_optional_int32());
+  EXPECT_EQ(42, copied.optional_int32());
+
+  // Test field manipulation.
+  TestEmptyMessage* arena_message_3 =
+      Arena::CreateMessage<TestEmptyMessage>(&arena);
+  arena_message_3->mutable_unknown_fields()->AddVarint(1000, 42);
+  arena_message_3->mutable_unknown_fields()->AddFixed32(1001, 42);
+  arena_message_3->mutable_unknown_fields()->AddFixed64(1002, 42);
+  arena_message_3->mutable_unknown_fields()->AddLengthDelimited(1003);
+  arena_message_3->mutable_unknown_fields()->DeleteSubrange(0, 2);
+  arena_message_3->mutable_unknown_fields()->DeleteByNumber(1002);
+  arena_message_3->mutable_unknown_fields()->DeleteByNumber(1003);
+  EXPECT_TRUE(arena_message_3->unknown_fields().empty());
+}
+
+TEST(ArenaTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+  TestAllTypes* arena1_message;
+  TestAllTypes* arena2_message;
+
+  // Case 1: Swap(), no UFS on either message, both messages on different
+  // arenas. Arena pointers should remain the same after swap.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+
+  // Case 2: Swap(), UFS on one message, both messages on different arenas.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->mutable_unknown_fields()->AddVarint(1, 42);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  EXPECT_EQ(0, arena1_message->unknown_fields().field_count());
+  EXPECT_EQ(1, arena2_message->unknown_fields().field_count());
+  EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint());
+
+  // Case 3: Swap(), UFS on both messages, both messages on different arenas.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->mutable_unknown_fields()->AddVarint(1, 42);
+  arena2_message->mutable_unknown_fields()->AddVarint(2, 84);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  EXPECT_EQ(1, arena1_message->unknown_fields().field_count());
+  EXPECT_EQ(1, arena2_message->unknown_fields().field_count());
+  EXPECT_EQ(84, arena1_message->unknown_fields().field(0).varint());
+  EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint());
+}
+
+TEST(ArenaTest, ReflectionSwapFields) {
+  Arena arena1;
+  Arena arena2;
+  TestAllTypes* arena1_message;
+  TestAllTypes* arena2_message;
+
+  // Case 1: messages on different arenas, only one message is set.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  TestUtil::SetAllFields(arena1_message);
+  const Reflection* reflection = arena1_message->GetReflection();
+  std::vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*arena1_message, &fields);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  string output;
+  arena1_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(*arena2_message);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  arena2_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+
+  // Case 2: messages on different arenas, both messages are set.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  TestUtil::SetAllFields(arena1_message);
+  TestUtil::SetAllFields(arena2_message);
+  reflection->SwapFields(arena1_message, arena2_message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+  TestUtil::ExpectAllFieldsSet(*arena2_message);
+
+  // Case 3: messages on different arenas with different lifetimes.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena3;
+    TestAllTypes* arena3_message = Arena::CreateMessage<TestAllTypes>(&arena3);
+    TestUtil::SetAllFields(arena3_message);
+    reflection->SwapFields(arena1_message, arena3_message, fields);
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+
+  // Case 4: one message on arena, the other on heap.
+  arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes message;
+  TestUtil::SetAllFields(arena1_message);
+  reflection->SwapFields(arena1_message, &message, fields);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(NULL, message.GetArena());
+  arena1_message->SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+  TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(ArenaTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+
+  protobuf_unittest_no_arena::TestNoArenaMessage no_arena_message;
+  EXPECT_FALSE(no_arena_message.has_arena_message());
+  no_arena_message.set_allocated_arena_message(NULL);
+  EXPECT_FALSE(no_arena_message.has_arena_message());
+  no_arena_message.set_allocated_arena_message(new ArenaMessage);
+  EXPECT_TRUE(no_arena_message.has_arena_message());
+}
+
+TEST(ArenaTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+
+  TestAllTypes::NestedMessage* released_null =
+      arena_message->release_optional_nested_message();
+  EXPECT_EQ(NULL, released_null);
+}
+
+TEST(ArenaTest, SetAllocatedString) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  string* allocated_str = new string("hello");
+  arena_message->set_allocated_optional_string(allocated_str);
+  EXPECT_EQ("hello", arena_message->optional_string());
+}
+
+TEST(ArenaTest, ReleaseString) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->set_optional_string("hello");
+  google::protobuf::scoped_ptr<string> released_str(
+      arena_message->release_optional_string());
+  EXPECT_EQ("hello", *released_str);
+
+  // Test default value.
+}
+
+
+TEST(ArenaTest, SwapBetweenArenasWithAllFieldsSet) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    arena2_message->Swap(arena1_message);
+    string output;
+    arena2_message->SerializeToString(&output);
+    EXPECT_EQ(0, output.size());
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+}
+
+TEST(ArenaTest, SwapBetweenArenaAndNonArenaWithAllFieldsSet) {
+  TestAllTypes non_arena_message;
+  TestUtil::SetAllFields(&non_arena_message);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    arena2_message->Swap(&non_arena_message);
+    TestUtil::ExpectAllFieldsSet(*arena2_message);
+    TestUtil::ExpectAllFieldsSet(non_arena_message);
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaSwap) {
+  Arena shared_arena;
+  TestAllTypes* message1 = Arena::CreateMessage<TestAllTypes>(&shared_arena);
+  TestAllTypes* message2 = Arena::CreateMessage<TestAllTypes>(&shared_arena);
+  TestUtil::SetAllFields(message1);
+  message1->UnsafeArenaSwap(message2);
+  TestUtil::ExpectAllFieldsSet(*message2);
+}
+
+TEST(ArenaTest, SwapBetweenArenasUsingReflection) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    const Reflection* r = arena2_message->GetReflection();
+    r->Swap(arena1_message, arena2_message);
+    string output;
+    arena2_message->SerializeToString(&output);
+    EXPECT_EQ(0, output.size());
+  }
+  TestUtil::ExpectAllFieldsSet(*arena1_message);
+}
+
+TEST(ArenaTest, SwapBetweenArenaAndNonArenaUsingReflection) {
+  TestAllTypes non_arena_message;
+  TestUtil::SetAllFields(&non_arena_message);
+  {
+    Arena arena2;
+    TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+    TestUtil::SetAllFields(arena2_message);
+    const Reflection* r = arena2_message->GetReflection();
+    r->Swap(&non_arena_message, arena2_message);
+    TestUtil::ExpectAllFieldsSet(*arena2_message);
+    TestUtil::ExpectAllFieldsSet(non_arena_message);
+  }
+}
+
+TEST(ArenaTest, ReleaseFromArenaMessageMakesCopy) {
+  TestAllTypes::NestedMessage* nested_msg = NULL;
+  string* nested_string = NULL;
+  {
+    Arena arena;
+    TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+    arena_message->mutable_optional_nested_message()->set_bb(42);
+    *arena_message->mutable_optional_string() = "Hello";
+    nested_msg = arena_message->release_optional_nested_message();
+    nested_string = arena_message->release_optional_string();
+  }
+  EXPECT_EQ(42, nested_msg->bb());
+  EXPECT_EQ("Hello", *nested_string);
+  delete nested_msg;
+  delete nested_string;
+}
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
+  TestAllTypes::NestedMessage* nested_msg = NULL;
+  // Note: no string: reflection API only supports releasing submessages.
+  {
+    Arena arena;
+    TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+    arena_message->mutable_optional_nested_message()->set_bb(42);
+    const Reflection* r = arena_message->GetReflection();
+    const FieldDescriptor* f = arena_message->GetDescriptor()->FindFieldByName(
+        "optional_nested_message");
+    nested_msg = static_cast<TestAllTypes::NestedMessage*>(
+        r->ReleaseMessage(arena_message, f));
+  }
+  EXPECT_EQ(42, nested_msg->bb());
+  delete nested_msg;
+}
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
+
+TEST(ArenaTest, UnsafeArenaReleaseDoesNotMakeCopy) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested_msg = NULL;
+  TestAllTypes::NestedMessage* orig_nested_msg = NULL;
+  string* nested_string = NULL;
+  string* orig_nested_string = NULL;
+  arena_message->mutable_optional_nested_message()->set_bb(42);
+  *arena_message->mutable_optional_string() = "Hello";
+  orig_nested_msg = arena_message->mutable_optional_nested_message();
+  orig_nested_string = arena_message->mutable_optional_string();
+  nested_msg = arena_message->unsafe_arena_release_optional_nested_message();
+  nested_string = arena_message->unsafe_arena_release_optional_string();
+
+  EXPECT_EQ(orig_nested_msg, nested_msg);
+  EXPECT_EQ(orig_nested_string, nested_string);
+  // Released pointers still on arena; no 'delete' calls needed here.
+}
+
+TEST(ArenaTest, SetAllocatedAcrossArenas) {
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes::NestedMessage* heap_submessage =
+      new TestAllTypes::NestedMessage();
+  heap_submessage->set_bb(42);
+  arena1_message->set_allocated_optional_nested_message(heap_submessage);
+  // Should keep same object and add to arena's Own()-list.
+  EXPECT_EQ(heap_submessage,
+            arena1_message->mutable_optional_nested_message());
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    arena1_message->set_allocated_optional_nested_message(arena2_submessage);
+    EXPECT_NE(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+  heap_message->set_allocated_optional_nested_message(arena1_submessage);
+  EXPECT_NE(arena1_submessage,
+            heap_message->mutable_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, SetAllocatedAcrossArenasWithReflection) {
+  // Same as above, with reflection.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  const FieldDescriptor* msg_field = d->FindFieldByName(
+      "optional_nested_message");
+  TestAllTypes::NestedMessage* heap_submessage =
+      new TestAllTypes::NestedMessage();
+  heap_submessage->set_bb(42);
+  r->SetAllocatedMessage(arena1_message, heap_submessage, msg_field);
+  // Should keep same object and add to arena's Own()-list.
+  EXPECT_EQ(heap_submessage,
+            arena1_message->mutable_optional_nested_message());
+  {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    r->SetAllocatedMessage(arena1_message, arena2_submessage, msg_field);
+    EXPECT_NE(arena2_submessage,
+              arena1_message->mutable_optional_nested_message());
+  }
+
+  TestAllTypes::NestedMessage* arena1_submessage =
+      Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena1);
+  arena1_submessage->set_bb(42);
+  TestAllTypes* heap_message = new TestAllTypes;
+  r->SetAllocatedMessage(heap_message, arena1_submessage, msg_field);
+  EXPECT_NE(arena1_submessage,
+            heap_message->mutable_optional_nested_message());
+  delete heap_message;
+}
+
+TEST(ArenaTest, AddAllocatedWithReflection) {
+  Arena arena1;
+  ArenaMessage* arena1_message = Arena::CreateMessage<ArenaMessage>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  const FieldDescriptor* fd =
+      d->FindFieldByName("repeated_import_no_arena_message");
+  // Message with cc_enable_arenas = false;
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  EXPECT_EQ(3, r->FieldSize(*arena1_message, fd));
+  // Message with cc_enable_arenas = true;
+  fd = d->FindFieldByName("repeated_nested_message");
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  r->AddMessage(arena1_message, fd);
+  EXPECT_EQ(3, r->FieldSize(*arena1_message, fd));
+}
+
+TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) {
+  {
+    RepeatedPtrField<TestAllTypes> repeated_field;
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+    // Ownership is passed to repeated_field.
+    TestAllTypes* cleared = new TestAllTypes();
+    repeated_field.AddCleared(cleared);
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+  }
+  {
+    RepeatedPtrField<TestAllTypes> repeated_field;
+    EXPECT_TRUE(repeated_field.empty());
+    EXPECT_EQ(0, repeated_field.size());
+    // Ownership is passed to repeated_field.
+    TestAllTypes* cleared = new TestAllTypes();
+    repeated_field.AddAllocated(cleared);
+    EXPECT_FALSE(repeated_field.empty());
+    EXPECT_EQ(1, repeated_field.size());
+  }
+}
+
+TEST(ArenaTest, AddAllocatedToRepeatedField) {
+  // Heap->arena case.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* heap_submessage =
+        new TestAllTypes::NestedMessage();
+    heap_submessage->set_bb(42);
+    arena1_message->mutable_repeated_nested_message()->
+        AddAllocated(heap_submessage);
+    // Should not copy object -- will use arena_->Own().
+    EXPECT_EQ(heap_submessage,
+              &arena1_message->repeated_nested_message(i));
+    EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb());
+  }
+
+  // Arena1->Arena2 case.
+  arena1_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    arena1_message->mutable_repeated_nested_message()->
+        AddAllocated(arena2_submessage);
+    // Should copy object.
+    EXPECT_NE(arena2_submessage,
+              &arena1_message->repeated_nested_message(i));
+    EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb());
+  }
+
+  // Arena->heap case.
+  TestAllTypes* heap_message = new TestAllTypes();
+  for (int i = 0; i < 10; i++) {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    heap_message->mutable_repeated_nested_message()->
+        AddAllocated(arena2_submessage);
+    // Should copy object.
+    EXPECT_NE(arena2_submessage,
+              &heap_message->repeated_nested_message(i));
+    EXPECT_EQ(42, heap_message->repeated_nested_message(i).bb());
+  }
+  delete heap_message;
+
+  // Heap-arena case for strings (which are not arena-allocated).
+  arena1_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    string* s = new string("Test");
+    arena1_message->mutable_repeated_string()->
+        AddAllocated(s);
+    // Should not copy.
+    EXPECT_EQ(s, &arena1_message->repeated_string(i));
+    EXPECT_EQ("Test", arena1_message->repeated_string(i));
+  }
+}
+
+TEST(ArenaTest, AddAllocatedToRepeatedFieldViaReflection) {
+  // Heap->arena case.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  const Reflection* r = arena1_message->GetReflection();
+  const Descriptor* d = arena1_message->GetDescriptor();
+  const FieldDescriptor* fd =
+      d->FindFieldByName("repeated_nested_message");
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* heap_submessage =
+        new TestAllTypes::NestedMessage;
+    heap_submessage->set_bb(42);
+    r->AddAllocatedMessage(arena1_message, fd, heap_submessage);
+    // Should not copy object -- will use arena_->Own().
+    EXPECT_EQ(heap_submessage,
+              &arena1_message->repeated_nested_message(i));
+    EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb());
+  }
+
+  // Arena1->Arena2 case.
+  arena1_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    r->AddAllocatedMessage(arena1_message, fd, arena2_submessage);
+    // Should copy object.
+    EXPECT_NE(arena2_submessage,
+              &arena1_message->repeated_nested_message(i));
+    EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb());
+  }
+
+  // Arena->heap case.
+  TestAllTypes* heap_message = new TestAllTypes;
+  for (int i = 0; i < 10; i++) {
+    Arena arena2;
+    TestAllTypes::NestedMessage* arena2_submessage =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena2);
+    arena2_submessage->set_bb(42);
+    r->AddAllocatedMessage(heap_message, fd, arena2_submessage);
+    // Should copy object.
+    EXPECT_NE(arena2_submessage,
+              &heap_message->repeated_nested_message(i));
+    EXPECT_EQ(42, heap_message->repeated_nested_message(i).bb());
+  }
+  delete heap_message;
+}
+
+TEST(ArenaTest, ReleaseLastRepeatedField) {
+  // Release from arena-allocated repeated field and ensure that returned object
+  // is heap-allocated.
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* nested =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena);
+    nested->set_bb(42);
+    arena_message->mutable_repeated_nested_message()->AddAllocated(nested);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    const TestAllTypes::NestedMessage *orig_submessage =
+        &arena_message->repeated_nested_message(10 - 1 - i);  // last element
+    TestAllTypes::NestedMessage *released =
+        arena_message->mutable_repeated_nested_message()->ReleaseLast();
+    EXPECT_NE(released, orig_submessage);
+    EXPECT_EQ(42, released->bb());
+    delete released;
+  }
+
+  // Test UnsafeArenaReleaseLast().
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes::NestedMessage* nested =
+        Arena::CreateMessage<TestAllTypes::NestedMessage>(&arena);
+    nested->set_bb(42);
+    arena_message->mutable_repeated_nested_message()->AddAllocated(nested);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    const TestAllTypes::NestedMessage *orig_submessage =
+        &arena_message->repeated_nested_message(10 - 1 - i);  // last element
+    TestAllTypes::NestedMessage *released =
+        arena_message->mutable_repeated_nested_message()->
+        UnsafeArenaReleaseLast();
+    EXPECT_EQ(released, orig_submessage);
+    EXPECT_EQ(42, released->bb());
+    // no delete -- |released| is on the arena.
+  }
+
+  // Test string case as well. ReleaseLast() in this case must copy the string,
+  // even though it was originally heap-allocated and its pointer was simply
+  // appended to the repeated field's internal vector, because the string was
+  // placed on the arena's destructor list and cannot be removed from that list
+  // (so the arena permanently owns the original instance).
+  arena_message->Clear();
+  for (int i = 0; i < 10; i++) {
+    string* s = new string("Test");
+    arena_message->mutable_repeated_string()->AddAllocated(s);
+  }
+  for (int i = 0; i < 10; i++) {
+    const string* orig_element = &arena_message->repeated_string(10 - 1 - i);
+    string* released = arena_message->mutable_repeated_string()->ReleaseLast();
+    EXPECT_NE(released, orig_element);
+    EXPECT_EQ("Test", *released);
+    delete released;
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaReleaseAdd) {
+  // Use unsafe_arena_release() and unsafe_arena_set_allocated() to transfer an
+  // arena-allocated string from one message to another.
+  Arena arena;
+  TestAllTypes* message1 = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes* message2 = Arena::CreateMessage<TestAllTypes>(&arena);
+  string* arena_string = Arena::Create<string>(&arena);
+  *arena_string = "Test content";
+
+  message1->unsafe_arena_set_allocated_optional_string(arena_string);
+  EXPECT_EQ(arena_string, message1->mutable_optional_string());
+  message2->unsafe_arena_set_allocated_optional_string(
+      message1->unsafe_arena_release_optional_string());
+  EXPECT_EQ(arena_string, message2->mutable_optional_string());
+}
+
+TEST(ArenaTest, UnsafeArenaAddAllocated) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  for (int i = 0; i < 10; i++) {
+    string* arena_string = Arena::Create<string>(&arena);
+    message->mutable_repeated_string()->UnsafeArenaAddAllocated(arena_string);
+    EXPECT_EQ(arena_string, message->mutable_repeated_string(i));
+  }
+}
+
+TEST(ArenaTest, UnsafeArenaRelease) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+
+  string* s = new string("test string");
+  message->unsafe_arena_set_allocated_optional_string(s);
+  EXPECT_TRUE(message->has_optional_string());
+  EXPECT_EQ("test string", message->optional_string());
+  s = message->unsafe_arena_release_optional_string();
+  EXPECT_FALSE(message->has_optional_string());
+  delete s;
+
+  s = new string("test string");
+  message->unsafe_arena_set_allocated_oneof_string(s);
+  EXPECT_TRUE(message->has_oneof_string());
+  EXPECT_EQ("test string", message->oneof_string());
+  s = message->unsafe_arena_release_oneof_string();
+  EXPECT_FALSE(message->has_oneof_string());
+  delete s;
+}
+
+TEST(ArenaTest, ArenaOneofReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Descriptor* desc = message->GetDescriptor();
+  const Reflection* refl = message->GetReflection();
+
+  const FieldDescriptor* string_field = desc->FindFieldByName(
+      "oneof_string");
+  const FieldDescriptor* msg_field = desc->FindFieldByName(
+      "oneof_nested_message");
+  const OneofDescriptor* oneof = desc->FindOneofByName(
+      "oneof_field");
+
+  refl->SetString(message, string_field, "Test value");
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+
+  Message* submsg = refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  submsg = refl->ReleaseMessage(message, msg_field);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  EXPECT_TRUE(submsg->GetArena() == NULL);
+  delete submsg;
+}
+
+namespace {
+void TestSwapRepeatedField(Arena* arena1, Arena* arena2) {
+  // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField
+  // between arenas.
+  RepeatedPtrField<TestAllTypes> field1(arena1);
+  RepeatedPtrField<TestAllTypes> field2(arena2);
+  for (int i = 0; i < 10; i++) {
+    TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena1);
+    t->set_optional_string("field1");
+    t->set_optional_int32(i);
+    if (arena1 != NULL) {
+      field1.UnsafeArenaAddAllocated(t);
+    } else {
+      field1.AddAllocated(t);
+    }
+  }
+  for (int i = 0; i < 5; i++) {
+    TestAllTypes* t = Arena::CreateMessage<TestAllTypes>(arena2);
+    t->set_optional_string("field2");
+    t->set_optional_int32(i);
+    if (arena2 != NULL) {
+      field2.UnsafeArenaAddAllocated(t);
+    } else {
+      field2.AddAllocated(t);
+    }
+  }
+  field1.Swap(&field2);
+  EXPECT_EQ(5, field1.size());
+  EXPECT_EQ(10, field2.size());
+  EXPECT_TRUE(string("field1") == field2.Get(0).optional_string());
+  EXPECT_TRUE(string("field2") == field1.Get(0).optional_string());
+  // Ensure that fields retained their original order:
+  for (int i = 0; i < field1.size(); i++) {
+    EXPECT_EQ(i, field1.Get(i).optional_int32());
+  }
+  for (int i = 0; i < field2.size(); i++) {
+    EXPECT_EQ(i, field2.Get(i).optional_int32());
+  }
+}
+}  // namespace
+
+TEST(ArenaTest, SwapRepeatedField) {
+  Arena arena;
+  TestSwapRepeatedField(&arena, &arena);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithDifferentArenas) {
+  Arena arena1;
+  Arena arena2;
+  TestSwapRepeatedField(&arena1, &arena2);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnRightHandSide) {
+  Arena arena;
+  TestSwapRepeatedField(&arena, NULL);
+}
+
+TEST(ArenaTest, SwapRepeatedFieldWithNoArenaOnLeftHandSide) {
+  Arena arena;
+  TestSwapRepeatedField(NULL, &arena);
+}
+
+TEST(ArenaTest, ExtensionsOnArena) {
+  Arena arena;
+  // Ensure no leaks.
+  TestAllExtensions* message_ext =
+      Arena::CreateMessage<TestAllExtensions>(&arena);
+  message_ext->SetExtension(
+      protobuf_unittest::optional_int32_extension, 42);
+  message_ext->SetExtension(
+      protobuf_unittest::optional_string_extension, string("test"));
+  message_ext->MutableExtension(
+      protobuf_unittest::optional_nested_message_extension)->set_bb(42);
+}
+
+TEST(ArenaTest, RepeatedFieldOnArena) {
+  // Preallocate an initial arena block to avoid mallocs during hooked region.
+  std::vector<char> arena_block(1024 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  {
+    internal::NoHeapChecker no_heap;
+
+    // Fill some repeated fields on the arena to test for leaks. Also verify no
+    // memory allocations.
+    RepeatedField<int32> repeated_int32(&arena);
+    RepeatedPtrField<TestAllTypes> repeated_message(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_int32.Add(42);
+      repeated_message.Add()->set_optional_int32(42);
+      EXPECT_EQ(&arena, repeated_message.Get(0).GetArena());
+      const TestAllTypes* msg_in_repeated_field = &repeated_message.Get(0);
+      TestAllTypes* msg = repeated_message.UnsafeArenaReleaseLast();
+      EXPECT_EQ(msg_in_repeated_field, msg);
+    }
+
+    // UnsafeArenaExtractSubrange (i) should not leak and (ii) should return
+    // on-arena pointers.
+    for (int i = 0; i < 10; i++) {
+      repeated_message.Add()->set_optional_int32(42);
+    }
+    TestAllTypes* extracted_messages[5];
+    repeated_message.UnsafeArenaExtractSubrange(0, 5, extracted_messages);
+    EXPECT_EQ(&arena, repeated_message.Get(0).GetArena());
+    EXPECT_EQ(5, repeated_message.size());
+  }
+
+  // Now, outside the scope of the NoHeapChecker, test ExtractSubrange's copying
+  // semantics.
+  {
+    RepeatedPtrField<TestAllTypes> repeated_message(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_message.Add()->set_optional_int32(42);
+    }
+
+    TestAllTypes* extracted_messages[5];
+    // ExtractSubrange should copy to the heap.
+    repeated_message.ExtractSubrange(0, 5, extracted_messages);
+    EXPECT_EQ(NULL, extracted_messages[0]->GetArena());
+    // We need to free the heap-allocated messages to prevent a leak.
+    for (int i = 0; i < 5; i++) {
+      delete extracted_messages[i];
+      extracted_messages[i] = NULL;
+    }
+  }
+
+  // Now check that we can create RepeatedFields/RepeatedPtrFields themselves on
+  // the arena. They have the necessary type traits so that they can behave like
+  // messages in this way. This is useful for higher-level generic templated
+  // code that may allocate messages or repeated fields of messages on an arena.
+  {
+    RepeatedPtrField<TestAllTypes>* repeated_ptr_on_arena =
+        Arena::CreateMessage< RepeatedPtrField<TestAllTypes> >(&arena);
+    for (int i = 0; i < 10; i++) {
+      // Add some elements and let the leak-checker ensure that everything is
+      // freed.
+      repeated_ptr_on_arena->Add();
+    }
+
+    RepeatedField<int>* repeated_int_on_arena =
+        Arena::CreateMessage< RepeatedField<int> >(&arena);
+    for (int i = 0; i < 100; i++) {
+      repeated_int_on_arena->Add(i);
+    }
+
+  }
+
+  arena.Reset();
+}
+
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+TEST(ArenaTest, MutableMessageReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Reflection* r = message->GetReflection();
+  const Descriptor* d = message->GetDescriptor();
+  const FieldDescriptor* field = d->FindFieldByName("optional_nested_message");
+  TestAllTypes::NestedMessage* submessage =
+      static_cast<TestAllTypes::NestedMessage*>(
+          r->MutableMessage(message, field));
+  TestAllTypes::NestedMessage* submessage_expected =
+      message->mutable_optional_nested_message();
+
+  EXPECT_EQ(submessage_expected, submessage);
+  EXPECT_EQ(&arena, submessage->GetArena());
+
+  const FieldDescriptor* oneof_field = d->FindFieldByName("oneof_nested_message");
+  submessage = static_cast<TestAllTypes::NestedMessage*>(
+      r->MutableMessage(message, oneof_field));
+  submessage_expected = message->mutable_oneof_nested_message();
+
+  EXPECT_EQ(submessage_expected, submessage);
+  EXPECT_EQ(&arena, submessage->GetArena());
+}
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
+
+
+namespace {
+
+void FillArenaAwareFields(TestAllTypes* message) {
+  string test_string = "hello world";
+  message->set_optional_int32(42);
+  message->set_optional_string(test_string);
+  message->set_optional_bytes(test_string);
+  message->mutable_optional_nested_message()->set_bb(42);
+
+  message->set_oneof_uint32(42);
+  message->mutable_oneof_nested_message()->set_bb(42);
+  message->set_oneof_string(test_string);
+  message->set_oneof_bytes(test_string);
+
+  message->add_repeated_int32(42);
+  // No repeated string: not yet arena-aware.
+  message->add_repeated_nested_message()->set_bb(42);
+  message->mutable_optional_lazy_message()->set_bb(42);
+}
+
+}
+
+// Test: no allocations occur on heap while touching all supported field types.
+TEST(ArenaTest, NoHeapAllocationsTest) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  {
+
+    TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+    FillArenaAwareFields(message);
+  }
+
+  arena.Reset();
+}
+
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+// Test construction on an arena via generic MessageLite interface. We should be
+// able to successfully deserialize on the arena without incurring heap
+// allocations, i.e., everything should still be arena-allocation-aware.
+TEST(ArenaTest, MessageLiteOnArena) {
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+  const google::protobuf::MessageLite* prototype = &TestAllTypes::default_instance();
+
+  TestAllTypes initial_message;
+  FillArenaAwareFields(&initial_message);
+  string serialized;
+  initial_message.SerializeToString(&serialized);
+
+  {
+
+    google::protobuf::MessageLite* generic_message = prototype->New(&arena);
+    EXPECT_TRUE(generic_message != NULL);
+    EXPECT_EQ(&arena, generic_message->GetArena());
+    EXPECT_TRUE(generic_message->ParseFromString(serialized));
+    TestAllTypes* deserialized = static_cast<TestAllTypes*>(generic_message);
+    EXPECT_EQ(42, deserialized->optional_int32());
+  }
+
+  arena.Reset();
+}
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
+
+
+// RepeatedField should support non-POD types, and invoke constructors and
+// destructors appropriately, because it's used this way by lots of other code
+// (even if this was not its original intent).
+TEST(ArenaTest, RepeatedFieldWithNonPODType) {
+  {
+    RepeatedField<string> field_on_heap;
+    for (int i = 0; i < 100; i++) {
+      *field_on_heap.Add() = "test string long enough to exceed inline buffer";
+    }
+  }
+  {
+    Arena arena;
+    RepeatedField<string> field_on_arena(&arena);
+    for (int i = 0; i < 100; i++) {
+      *field_on_arena.Add() = "test string long enough to exceed inline buffer";
+    }
+  }
+}
+
+// Align n to next multiple of 8
+namespace {
+uint64 Align8(uint64 n) { return (n + 7) & -8; }
+}  // namespace
+
+TEST(ArenaTest, SpaceAllocated_and_Used) {
+  ArenaOptions options;
+  options.start_block_size = 256;
+  options.max_block_size = 8192;
+  Arena arena_1(options);
+  EXPECT_EQ(0, arena_1.SpaceAllocated());
+  EXPECT_EQ(0, arena_1.SpaceUsed());
+  EXPECT_EQ(0, arena_1.Reset());
+  ::google::protobuf::Arena::CreateArray<char>(&arena_1, 320);
+  // Arena will allocate slightly more than 320 for the block headers.
+  EXPECT_LE(320, arena_1.SpaceAllocated());
+  EXPECT_EQ(Align8(320), arena_1.SpaceUsed());
+  EXPECT_LE(320, arena_1.Reset());
+
+  // Test with initial block.
+  std::vector<char> arena_block(1024);
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena_2(options);
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(0, arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.Reset());
+  ::google::protobuf::Arena::CreateArray<char>(&arena_2, 55);
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(Align8(55), arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.Reset());
+
+  // Reset options to test doubling policy explicitly.
+  options.initial_block = NULL;
+  options.initial_block_size = 0;
+  Arena arena_3(options);
+  EXPECT_EQ(0, arena_3.SpaceUsed());
+  ::google::protobuf::Arena::CreateArray<char>(&arena_3, 190);
+  EXPECT_EQ(256, arena_3.SpaceAllocated());
+  EXPECT_EQ(Align8(190), arena_3.SpaceUsed());
+  ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
+  EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
+  EXPECT_EQ(Align8(190) + Align8(70), arena_3.SpaceUsed());
+  EXPECT_EQ(256 + 512, arena_3.Reset());
+}
+
+TEST(ArenaTest, Alignment) {
+  ::google::protobuf::Arena arena;
+  for (int i = 0; i < 200; i++) {
+    void* p = ::google::protobuf::Arena::CreateArray<char>(&arena, i);
+    GOOGLE_CHECK_EQ(reinterpret_cast<uintptr_t>(p) % 8, 0) << i << ": " << p;
+  }
+}
+
+TEST(ArenaTest, GetArenaShouldReturnTheArenaForArenaAllocatedMessages) {
+  ::google::protobuf::Arena arena;
+  ArenaMessage* message = Arena::CreateMessage<ArenaMessage>(&arena);
+  const ArenaMessage* const_pointer_to_message = message;
+  EXPECT_EQ(&arena, Arena::GetArena(message));
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+}
+
+TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
+  ArenaMessage message;
+  const ArenaMessage* const_pointer_to_message = &message;
+  EXPECT_EQ(NULL, Arena::GetArena(&message));
+  EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
+}
+
+TEST(ArenaTest, UnsafeSetAllocatedOnArena) {
+  ::google::protobuf::Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  EXPECT_FALSE(message->has_optional_string());
+
+  string owned_string = "test with long enough content to heap-allocate";
+  message->unsafe_arena_set_allocated_optional_string(&owned_string);
+  EXPECT_TRUE(message->has_optional_string());
+
+  message->unsafe_arena_set_allocated_optional_string(NULL);
+  EXPECT_FALSE(message->has_optional_string());
+}
+
+// A helper utility class to only contain static hook functions, some
+// counters to be used to verify the counters have been called and a cookie
+// value to be verified.
+class ArenaHooksTestUtil {
+ public:
+  static void* on_init(::google::protobuf::Arena* arena) {
+    ++num_init;
+    int* cookie = new int(kCookieValue);
+    return static_cast<void*>(cookie);
+  }
+
+  static void on_allocation(const std::type_info* /*unused*/, uint64 alloc_size,
+                            void* cookie) {
+    ++num_allocations;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+  }
+
+  static void on_reset(::google::protobuf::Arena* arena, void* cookie,
+                       uint64 space_used) {
+    ++num_reset;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+  }
+
+  static void on_destruction(::google::protobuf::Arena* arena, void* cookie,
+                             uint64 space_used) {
+    ++num_destruct;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+    delete static_cast<int*>(cookie);
+  }
+
+  static const int kCookieValue = 999;
+  static uint32 num_init;
+  static uint32 num_allocations;
+  static uint32 num_reset;
+  static uint32 num_destruct;
+};
+uint32 ArenaHooksTestUtil::num_init = 0;
+uint32 ArenaHooksTestUtil::num_allocations = 0;
+uint32 ArenaHooksTestUtil::num_reset = 0;
+uint32 ArenaHooksTestUtil::num_destruct = 0;
+const int ArenaHooksTestUtil::kCookieValue;
+
+// Test the hooks are correctly called and that the cookie is passed.
+TEST(ArenaTest, ArenaHooksSanity) {
+  ::google::protobuf::ArenaOptions options;
+  options.on_arena_init = ArenaHooksTestUtil::on_init;
+  options.on_arena_allocation = ArenaHooksTestUtil::on_allocation;
+  options.on_arena_reset = ArenaHooksTestUtil::on_reset;
+  options.on_arena_destruction = ArenaHooksTestUtil::on_destruction;
+
+  // Scope for defining the arena
+  {
+    ::google::protobuf::Arena arena(options);
+    EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
+    EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations);
+    ::google::protobuf::Arena::Create<uint64>(&arena);
+    if (google::protobuf::internal::has_trivial_destructor<uint64>::value) {
+      EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations);
+    } else {
+      EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations);
+    }
+    arena.Reset();
+    arena.Reset();
+    EXPECT_EQ(2, ArenaHooksTestUtil::num_reset);
+  }
+  EXPECT_EQ(3, ArenaHooksTestUtil::num_reset);
+  EXPECT_EQ(1, ArenaHooksTestUtil::num_destruct);
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc
new file mode 100644
index 0000000..cce61d7
--- /dev/null
+++ b/src/google/protobuf/arenastring.cc
@@ -0,0 +1,53 @@
+// 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.
+
+// The ArenaString implementation is not included in the open-source release. Do
+// not include this file in the distribution.
+
+#include <google/protobuf/arenastring.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+
+void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
+                                       ArenaStringPtr value) {
+  const ::std::string* me = *UnsafeRawStringPointer();
+  const ::std::string* other = *value.UnsafeRawStringPointer();
+  // If the pointers are the same then do nothing.
+  if (me != other) {
+    SetNoArena(default_value, value.GetNoArena(default_value));
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
new file mode 100755
index 0000000..590ffce
--- /dev/null
+++ b/src/google/protobuf/arenastring.h
@@ -0,0 +1,314 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
+#define GOOGLE_PROTOBUF_ARENASTRING_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/fastmem.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+
+
+
+// This is the implementation of arena string fields written for the open-source
+// release. The ArenaStringPtr struct below is an internal implementation class
+// and *should not be used* by user code. It is used to collect string
+// operations together into one place and abstract away the underlying
+// string-field pointer representation, so that (for example) an alternate
+// implementation that knew more about ::std::string's internals could integrate more
+// closely with the arena allocator.
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+struct LIBPROTOBUF_EXPORT ArenaStringPtr {
+  inline void Set(const ::std::string* default_value,
+                  const ::std::string& value, ::google::protobuf::Arena* arena) {
+    if (ptr_ == default_value) {
+      CreateInstance(arena, &value);
+    } else {
+      *ptr_ = value;
+    }
+  }
+
+  // Basic accessors.
+  inline const ::std::string& Get(const ::std::string* /* default_value */) const {
+    return *ptr_;
+  }
+
+  inline ::std::string* Mutable(const ::std::string* default_value,
+                           ::google::protobuf::Arena* arena) {
+    if (ptr_ == default_value) {
+      CreateInstance(arena, default_value);
+    }
+    return ptr_;
+  }
+
+  // Release returns a ::std::string* instance that is heap-allocated and is not
+  // Own()'d by any arena. If the field was not set, it returns NULL. The caller
+  // retains ownership. Clears this field back to NULL state. Used to implement
+  // release_<field>() methods on generated classes.
+  inline ::std::string* Release(const ::std::string* default_value,
+                           ::google::protobuf::Arena* arena) {
+    if (ptr_ == default_value) {
+      return NULL;
+    }
+    ::std::string* released = NULL;
+    if (arena != NULL) {
+      // ptr_ is owned by the arena -- we need to return a copy.
+      released = new ::std::string(*ptr_);
+    } else {
+      released = ptr_;
+    }
+    ptr_ = const_cast< ::std::string* >(default_value);
+    return released;
+  }
+
+  // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
+  // have its destructor already registered) if arena != NULL. If the field was
+  // not set, this returns NULL. This method clears this field back to NULL
+  // state. Used to implement unsafe_arena_release_<field>() methods on
+  // generated classes.
+  inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
+                                      ::google::protobuf::Arena* /* arena */) {
+    if (ptr_ == default_value) {
+      return NULL;
+    }
+    ::std::string* released = ptr_;
+    ptr_ = const_cast< ::std::string* >(default_value);
+    return released;
+  }
+
+  // Takes a string that is heap-allocated, and takes ownership. The string's
+  // destructor is registered with the arena. Used to implement
+  // set_allocated_<field> in generated classes.
+  inline void SetAllocated(const ::std::string* default_value,
+                           ::std::string* value, ::google::protobuf::Arena* arena) {
+    if (arena == NULL && ptr_ != default_value) {
+      Destroy(default_value, arena);
+    }
+    if (value != NULL) {
+      ptr_ = value;
+      if (arena != NULL) {
+        arena->Own(value);
+      }
+    } else {
+      ptr_ = const_cast< ::std::string* >(default_value);
+    }
+  }
+
+  // Takes a string that has lifetime equal to the arena's lifetime. The arena
+  // must be non-null. It is safe only to pass this method a value returned by
+  // UnsafeArenaRelease() on another field of a message in the same arena. Used
+  // to implement unsafe_arena_set_allocated_<field> in generated classes.
+  inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
+                                      ::std::string* value,
+                                      ::google::protobuf::Arena* /* arena */) {
+    if (value != NULL) {
+      ptr_ = value;
+    } else {
+      ptr_ = const_cast< ::std::string* >(default_value);
+    }
+  }
+
+  // Swaps internal pointers. Arena-safety semantics: this is guarded by the
+  // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
+  // 'unsafe' if called directly.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
+    std::swap(ptr_, other->ptr_);
+  }
+
+  // Frees storage (if not on an arena) and sets field to default value.
+  inline void Destroy(const ::std::string* default_value,
+                      ::google::protobuf::Arena* arena) {
+    if (arena == NULL && ptr_ != default_value) {
+      delete ptr_;
+    }
+    ptr_ = const_cast< ::std::string* >(default_value);
+  }
+
+  // Clears content, but keeps allocated string if arena != NULL, to avoid the
+  // overhead of heap operations. After this returns, the content (as seen by
+  // the user) will always be the empty string. Assumes that |default_value|
+  // is an empty string.
+  inline void ClearToEmpty(const ::std::string* default_value,
+                           ::google::protobuf::Arena* /* arena */) {
+    if (ptr_ == default_value) {
+      // Already set to default (which is empty) -- do nothing.
+    } else {
+      ptr_->clear();
+    }
+  }
+
+  // Clears content, but keeps allocated string if arena != NULL, to avoid the
+  // overhead of heap operations. After this returns, the content (as seen by
+  // the user) will always be equal to |default_value|.
+  inline void ClearToDefault(const ::std::string* default_value,
+                             ::google::protobuf::Arena* /* arena */) {
+    if (ptr_ == default_value) {
+      // Already set to default -- do nothing.
+    } else {
+      // Have another allocated string -- rather than throwing this away and
+      // resetting ptr_ to the canonical default string instance, we just reuse
+      // this instance.
+      *ptr_ = *default_value;
+    }
+  }
+
+  // Called from generated code / reflection runtime only. Resets value to point
+  // to a default string pointer, with the semantics that this ArenaStringPtr
+  // does not own the pointed-to memory. Disregards initial value of ptr_ (so
+  // this is the *ONLY* safe method to call after construction or when
+  // reinitializing after becoming the active field in a oneof union).
+  inline void UnsafeSetDefault(const ::std::string* default_value) {
+    // Casting away 'const' is safe here: accessors ensure that ptr_ is only
+    // returned as a const if it is equal to default_value.
+    ptr_ = const_cast< ::std::string* >(default_value);
+  }
+
+  // The 'NoArena' variants of methods below assume arena == NULL and are
+  // optimized to provide very little overhead relative to a raw string pointer
+  // (while still being in-memory compatible with other code that assumes
+  // ArenaStringPtr). Note the invariant that a class instance that has only
+  // ever been mutated by NoArena methods must *only* be in the String state
+  // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
+  // tagged-pointer manipulations to be avoided.
+  inline void SetNoArena(const ::std::string* default_value,
+                         const ::std::string& value) {
+    if (ptr_ == default_value) {
+      CreateInstanceNoArena(&value);
+    } else {
+      *ptr_ = value;
+    }
+  }
+
+  void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
+
+  inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const {
+    return *ptr_;
+  }
+
+  inline ::std::string* MutableNoArena(const ::std::string* default_value) {
+    if (ptr_ == default_value) {
+      CreateInstanceNoArena(default_value);
+    }
+    return ptr_;
+  }
+
+  inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
+    if (ptr_ == default_value) {
+      return NULL;
+    } else {
+      ::std::string* released = ptr_;
+      ptr_ = const_cast< ::std::string* >(default_value);
+      return released;
+    }
+  }
+
+  inline void SetAllocatedNoArena(const ::std::string* default_value,
+                                  ::std::string* value) {
+    if (ptr_ != default_value) {
+      delete ptr_;
+    }
+    if (value != NULL) {
+      ptr_ = value;
+    } else {
+      ptr_ = const_cast< ::std::string* >(default_value);
+    }
+  }
+
+  inline void DestroyNoArena(const ::std::string* default_value) {
+    if (ptr_ != default_value) {
+      delete ptr_;
+    }
+    ptr_ = NULL;
+  }
+
+  inline void ClearToEmptyNoArena(const ::std::string* default_value) {
+    if (ptr_ == default_value) {
+      // Nothing: already equal to default (which is the empty string).
+    } else {
+      ptr_->clear();
+    }
+  }
+
+  inline void ClearToDefaultNoArena(const ::std::string* default_value) {
+    if (ptr_ == default_value) {
+      // Nothing: already set to default.
+    } else {
+      // Reuse existing allocated instance.
+      *ptr_ = *default_value;
+    }
+  }
+
+  // Internal accessor used only at parse time to provide direct access to the
+  // raw pointer from the shared parse routine (in the non-arenas case). The
+  // parse routine does the string allocation in order to save code size in the
+  // generated parsing code.
+  inline ::std::string** UnsafeRawStringPointer() {
+    return &ptr_;
+  }
+
+ private:
+  ::std::string* ptr_;
+
+  GOOGLE_ATTRIBUTE_NOINLINE void CreateInstance(::google::protobuf::Arena* arena,
+                                         const ::std::string* initial_value) {
+    // Assumes ptr_ is not NULL.
+    if (initial_value != NULL) {
+      ptr_ = new ::std::string(*initial_value);
+    } else {
+      ptr_ = new ::std::string();
+    }
+    if (arena != NULL) {
+      arena->Own(ptr_);
+    }
+  }
+  GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) {
+    if (initial_value != NULL) {
+      ptr_ = new ::std::string(*initial_value);
+    } else {
+      ptr_ = new ::std::string();
+    }
+  }
+};
+
+}  // namespace internal
+}  // namespace protobuf
+
+
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ARENASTRING_H__
diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc
new file mode 100644
index 0000000..ea405d7
--- /dev/null
+++ b/src/google/protobuf/arenastring_unittest.cc
@@ -0,0 +1,110 @@
+// 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.
+
+// Based on mvels@'s frankenstring.
+
+#include <google/protobuf/arenastring.h>
+
+#include <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <cstdlib>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <gtest/gtest.h>
+
+namespace google {
+using google::protobuf::internal::ArenaString;
+using google::protobuf::internal::ArenaStringPtr;
+
+namespace protobuf {
+
+
+static string WrapString(const char* value) {
+  return value;
+}
+
+// Test ArenaStringPtr with arena == NULL.
+TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) {
+  ArenaStringPtr field;
+  ::std::string default_value = "default";
+  field.UnsafeSetDefault(&default_value);
+  EXPECT_EQ(string("default"), field.Get(&default_value));
+  field.Set(&default_value, WrapString("Test short"), NULL);
+  EXPECT_EQ(string("Test short"), field.Get(&default_value));
+  field.Set(&default_value, WrapString("Test long long long long value"), NULL);
+  EXPECT_EQ(string("Test long long long long value"), field.Get(&default_value));
+  field.Set(&default_value, string(""), NULL);
+  field.Destroy(&default_value, NULL);
+
+  ArenaStringPtr field2;
+  field2.UnsafeSetDefault(&default_value);
+  ::std::string* mut = field2.Mutable(&default_value, NULL);
+  EXPECT_EQ(mut, field2.Mutable(&default_value, NULL));
+  EXPECT_EQ(mut, &field2.Get(&default_value));
+  EXPECT_NE(&default_value, mut);
+  EXPECT_EQ(string("default"), *mut);
+  *mut = "Test long long long long value";  // ensure string allocates storage
+  EXPECT_EQ(string("Test long long long long value"), field2.Get(&default_value));
+  field2.Destroy(&default_value, NULL);
+}
+
+TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) {
+  google::protobuf::Arena arena;
+  ArenaStringPtr field;
+  ::std::string default_value = "default";
+  field.UnsafeSetDefault(&default_value);
+  EXPECT_EQ(string("default"), field.Get(&default_value));
+  field.Set(&default_value, WrapString("Test short"), &arena);
+  EXPECT_EQ(string("Test short"), field.Get(&default_value));
+  field.Set(&default_value, WrapString("Test long long long long value"), &arena);
+  EXPECT_EQ(string("Test long long long long value"),
+            field.Get(&default_value));
+  field.Set(&default_value, string(""), &arena);
+  field.Destroy(&default_value, &arena);
+
+  ArenaStringPtr field2;
+  field2.UnsafeSetDefault(&default_value);
+  ::std::string* mut = field2.Mutable(&default_value, &arena);
+  EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
+  EXPECT_EQ(mut, &field2.Get(&default_value));
+  EXPECT_NE(&default_value, mut);
+  EXPECT_EQ(string("default"), *mut);
+  *mut = "Test long long long long value";  // ensure string allocates storage
+  EXPECT_EQ(string("Test long long long long value"),
+            field2.Get(&default_value));
+  field2.Destroy(&default_value, &arena);
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
index 0039b00..473eb4e 100644
--- a/src/google/protobuf/compiler/code_generator.cc
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -34,6 +34,7 @@
 
 #include <google/protobuf/compiler/code_generator.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index 321a8cc..b989f15 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -79,6 +79,37 @@
                         GeneratorContext* generator_context,
                         string* error) const = 0;
 
+  // Generates code for all given proto files, generating one or more files in
+  // the given output directory.
+  //
+  // This method should be called instead of |Generate()| when
+  // |HasGenerateAll()| returns |true|. It is used to emulate legacy semantics
+  // when more than one `.proto` file is specified on one compiler invocation.
+  //
+  // WARNING: Please do not use unless legacy semantics force the code generator
+  // to produce a single output file for all input files, or otherwise require
+  // an examination of all input files first. The canonical code generator
+  // design produces one output file per input .proto file, and we do not wish
+  // to encourage alternate designs.
+  //
+  // A parameter is given as passed on the command line, as in |Generate()|
+  // above.
+  //
+  // Returns true if successful.  Otherwise, sets *error to a description of
+  // the problem (e.g. "invalid parameter") and returns false.
+  virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+                           const string& parameter,
+                           GeneratorContext* generator_context,
+                           string* error) const {
+    *error = "Unimplemented GenerateAll() method.";
+    return false;
+  }
+
+  // Returns true if the code generator expects to receive all FileDescriptors
+  // at once (via |GenerateAll()|), rather than one at a time (via
+  // |Generate()|). This is required to implement legacy semantics.
+  virtual bool HasGenerateAll() const { return false; }
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
 };
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index f9f27bd..fcad6b6 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -33,6 +33,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/stubs/platform_macros.h>
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -45,11 +46,22 @@
 #include <unistd.h>
 #endif
 #include <errno.h>
+#include <fstream>
 #include <iostream>
 #include <ctype.h>
 
-#include <google/protobuf/stubs/hash.h>
+#ifdef GOOGLE_PROTOBUF_ARCH_SPARC
+#include <limits.h> //For PATH_MAX
+#endif
+
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
@@ -64,6 +76,7 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/map_util.h>
@@ -149,7 +162,7 @@
   if (path.empty()) return true;
 
   if (access(path.c_str(), F_OK) == -1) {
-    cerr << path << ": " << strerror(errno) << endl;
+    std::cerr << path << ": " << strerror(errno) << std::endl;
     return false;
   } else {
     return true;
@@ -168,8 +181,8 @@
     path_so_far += parts[i];
     if (mkdir(path_so_far.c_str(), 0777) != 0) {
       if (errno != EEXIST) {
-        cerr << filename << ": while trying to create directory "
-             << path_so_far << ": " << strerror(errno) << endl;
+        std::cerr << filename << ": while trying to create directory "
+                  << path_so_far << ": " << strerror(errno) << std::endl;
         return false;
       }
     }
@@ -179,6 +192,78 @@
   return true;
 }
 
+// Get the absolute path of this protoc binary.
+bool GetProtocAbsolutePath(string* path) {
+#ifdef _WIN32
+  char buffer[MAX_PATH];
+  int len = GetModuleFileNameA(NULL, buffer, MAX_PATH);
+#elif __APPLE__
+  char buffer[PATH_MAX];
+  int len = 0;
+
+  char dirtybuffer[PATH_MAX];
+  uint32_t size = sizeof(dirtybuffer);
+  if (_NSGetExecutablePath(dirtybuffer, &size) == 0) {
+    realpath(dirtybuffer, buffer);
+    len = strlen(buffer);
+  }
+#else
+  char buffer[PATH_MAX];
+  int len = readlink("/proc/self/exe", buffer, PATH_MAX);
+#endif
+  if (len > 0) {
+    path->assign(buffer, len);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// Whether a path is where google/protobuf/descriptor.proto and other well-known
+// type protos are installed.
+bool IsInstalledProtoPath(const string& path) {
+  // Checking the descriptor.proto file should be good enough.
+  string file_path = path + "/google/protobuf/descriptor.proto";
+  return access(file_path.c_str(), F_OK) != -1;
+}
+
+// Add the paths where google/protobuf/descritor.proto and other well-known
+// type protos are installed.
+void AddDefaultProtoPaths(vector<pair<string, string> >* paths) {
+  // TODO(xiaofeng): The code currently only checks relative paths of where
+  // the protoc binary is installed. We probably should make it handle more
+  // cases than that.
+  string path;
+  if (!GetProtocAbsolutePath(&path)) {
+    return;
+  }
+  // Strip the binary name.
+  size_t pos = path.find_last_of("/\\");
+  if (pos == string::npos || pos == 0) {
+    return;
+  }
+  path = path.substr(0, pos);
+  // Check the binary's directory.
+  if (IsInstalledProtoPath(path)) {
+    paths->push_back(pair<string, string>("", path));
+    return;
+  }
+  // Check if there is an include subdirectory.
+  if (IsInstalledProtoPath(path + "/include")) {
+    paths->push_back(pair<string, string>("", path + "/include"));
+    return;
+  }
+  // Check if the upper level directory has an "include" subdirectory.
+  pos = path.find_last_of("/\\");
+  if (pos == string::npos || pos == 0) {
+    return;
+  }
+  path = path.substr(0, pos);
+  if (IsInstalledProtoPath(path + "/include")) {
+    paths->push_back(pair<string, string>("", path + "/include"));
+    return;
+  }
+}
 }  // namespace
 
 // A MultiFileErrorCollector that prints errors to stderr.
@@ -192,15 +277,35 @@
   // implements MultiFileErrorCollector ------------------------------
   void AddError(const string& filename, int line, int column,
                 const string& message) {
+    AddErrorOrWarning(filename, line, column, message, "error", std::cerr);
+  }
 
+  void AddWarning(const string& filename, int line, int column,
+                  const string& message) {
+    AddErrorOrWarning(filename, line, column, message, "warning", std::clog);
+  }
+
+  // implements io::ErrorCollector -----------------------------------
+  void AddError(int line, int column, const string& message) {
+    AddError("input", line, column, message);
+  }
+
+  void AddWarning(int line, int column, const string& message) {
+    AddErrorOrWarning("input", line, column, message, "warning", std::clog);
+  }
+
+ private:
+  void AddErrorOrWarning(
+      const string& filename, int line, int column,
+      const string& message, const string& type, ostream& out) {
     // Print full path when running under MSVS
     string dfile;
     if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
         tree_ != NULL &&
         tree_->VirtualFileToDiskFile(filename, &dfile)) {
-      cerr << dfile;
+      out << dfile;
     } else {
-      cerr << filename;
+      out << filename;
     }
 
     // Users typically expect 1-based line/column numbers, so we add 1
@@ -209,23 +314,22 @@
       // Allow for both GCC- and Visual-Studio-compatible output.
       switch (format_) {
         case CommandLineInterface::ERROR_FORMAT_GCC:
-          cerr << ":" << (line + 1) << ":" << (column + 1);
+          out << ":" << (line + 1) << ":" << (column + 1);
           break;
         case CommandLineInterface::ERROR_FORMAT_MSVS:
-          cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
+          out << "(" << (line + 1) << ") : "
+              << type << " in column=" << (column + 1);
           break;
       }
     }
 
-    cerr << ": " << message << endl;
+    if (type == "warning") {
+      out << ": warning: " << message << std::endl;
+    } else {
+      out << ": " << message << std::endl;
+    }
   }
 
-  // implements io::ErrorCollector -----------------------------------
-  void AddError(int line, int column, const string& message) {
-    AddError("input", line, column, message);
-  }
-
- private:
   const ErrorFormat format_;
   DiskSourceTree *tree_;
 };
@@ -251,6 +355,9 @@
   // format, unless one has already been written.
   void AddJarManifest();
 
+  // Get name of all output files.
+  void GetOutputFilenames(vector<string>* output_filenames);
+
   // implements GeneratorContext --------------------------------------
   io::ZeroCopyOutputStream* Open(const string& filename);
   io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
@@ -297,7 +404,7 @@
   bool append_mode_;
 
   // StringOutputStream writing to data_.
-  scoped_ptr<io::StringOutputStream> inner_;
+  google::protobuf::scoped_ptr<io::StringOutputStream> inner_;
 };
 
 // -------------------------------------------------------------------
@@ -342,7 +449,7 @@
 
     if (file_descriptor < 0) {
       int error = errno;
-      cerr << filename << ": " << strerror(error);
+      std::cerr << filename << ": " << strerror(error);
       return false;
     }
 
@@ -366,9 +473,9 @@
 
         if (write_result < 0) {
           int error = errno;
-          cerr << filename << ": write: " << strerror(error);
+          std::cerr << filename << ": write: " << strerror(error);
         } else {
-          cerr << filename << ": write() returned zero?" << endl;
+          std::cerr << filename << ": write() returned zero?" << std::endl;
         }
         return false;
       }
@@ -379,7 +486,7 @@
 
     if (close(file_descriptor) != 0) {
       int error = errno;
-      cerr << filename << ": close: " << strerror(error);
+      std::cerr << filename << ": close: " << strerror(error);
       return false;
     }
   }
@@ -402,7 +509,7 @@
 
   if (file_descriptor < 0) {
     int error = errno;
-    cerr << filename << ": " << strerror(error);
+    std::cerr << filename << ": " << strerror(error);
     return false;
   }
 
@@ -418,11 +525,11 @@
   zip_writer.WriteDirectory();
 
   if (stream.GetErrno() != 0) {
-    cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
   }
 
   if (!stream.Close()) {
-    cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
   }
 
   return true;
@@ -438,6 +545,14 @@
   }
 }
 
+void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
+    vector<string>* output_filenames) {
+  for (map<string, string*>::iterator iter = files_.begin();
+       iter != files_.end(); ++iter) {
+    output_filenames->push_back(iter->first);
+  }
+}
+
 io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
     const string& filename) {
   return new MemoryOutputStream(this, filename, false);
@@ -487,7 +602,8 @@
       if (append_mode_) {
         (*map_slot)->append(data_);
       } else {
-        cerr << filename_ << ": Tried to write the same file twice." << endl;
+        std::cerr << filename_ << ": Tried to write the same file twice."
+                  << std::endl;
         directory_->had_error_ = true;
       }
       return;
@@ -505,8 +621,9 @@
 
     // Find the file we are going to insert into.
     if (*map_slot == NULL) {
-      cerr << filename_ << ": Tried to insert into file that doesn't exist."
-           << endl;
+      std::cerr << filename_
+                << ": Tried to insert into file that doesn't exist."
+                << std::endl;
       directory_->had_error_ = true;
       return;
     }
@@ -518,8 +635,8 @@
     string::size_type pos = target->find(magic_string);
 
     if (pos == string::npos) {
-      cerr << filename_ << ": insertion point \"" << insertion_point_
-           << "\" not found." << endl;
+      std::cerr << filename_ << ": insertion point \"" << insertion_point_
+                << "\" not found." << std::endl;
       directory_->had_error_ = true;
       return;
     }
@@ -628,6 +745,8 @@
       break;
   }
 
+  AddDefaultProtoPaths(&proto_path_);
+
   // Set up the source tree.
   DiskSourceTree source_tree;
   for (int i = 0; i < proto_path_.size(); i++) {
@@ -667,7 +786,6 @@
   // We construct a separate GeneratorContext for each output location.  Note
   // that two code generators may output to the same location, in which case
   // they should share a single GeneratorContext so that OpenForInsert() works.
-  typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
   GeneratorContextMap output_directories;
 
   // Generate output.
@@ -714,6 +832,13 @@
     }
   }
 
+  if (!dependency_out_name_.empty()) {
+    if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+                                        &source_tree)) {
+      return 1;
+    }
+  }
+
   STLDeleteValues(&output_directories);
 
   if (!descriptor_set_name_.empty()) {
@@ -772,6 +897,7 @@
   output_directives_.clear();
   codec_type_.clear();
   descriptor_set_name_.clear();
+  dependency_out_name_.clear();
 
   mode_ = MODE_COMPILE;
   print_mode_ = PRINT_NONE;
@@ -790,27 +916,31 @@
         input_files_[i] = virtual_file;
         break;
       case DiskSourceTree::SHADOWED:
-        cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
-                "by \"" << shadowing_disk_file << "\".  Either use the latter "
-                "file as your input or reorder the --proto_path so that the "
-                "former file's location comes first." << endl;
+        std::cerr << input_files_[i]
+                  << ": Input is shadowed in the --proto_path by \""
+                  << shadowing_disk_file
+                  << "\".  Either use the latter file as your input or reorder "
+                     "the --proto_path so that the former file's location "
+                     "comes first." << std::endl;
         return false;
       case DiskSourceTree::CANNOT_OPEN:
-        cerr << input_files_[i] << ": " << strerror(errno) << endl;
+        std::cerr << input_files_[i] << ": " << strerror(errno) << std::endl;
         return false;
       case DiskSourceTree::NO_MAPPING:
         // First check if the file exists at all.
         if (access(input_files_[i].c_str(), F_OK) < 0) {
           // File does not even exist.
-          cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
+          std::cerr << input_files_[i] << ": " << strerror(ENOENT) << std::endl;
         } else {
-          cerr << input_files_[i] << ": File does not reside within any path "
-                  "specified using --proto_path (or -I).  You must specify a "
-                  "--proto_path which encompasses this file.  Note that the "
-                  "proto_path must be an exact prefix of the .proto file "
-                  "names -- protoc is too dumb to figure out when two paths "
-                  "(e.g. absolute and relative) are equivalent (it's harder "
-                  "than you think)." << endl;
+          std::cerr
+              << input_files_[i]
+              << ": File does not reside within any path "
+                 "specified using --proto_path (or -I).  You must specify a "
+                 "--proto_path which encompasses this file.  Note that the "
+                 "proto_path must be an exact prefix of the .proto file "
+                 "names -- protoc is too dumb to figure out when two paths "
+                 "(e.g. absolute and relative) are equivalent (it's harder "
+                 "than you think)." << std::endl;
         }
         return false;
     }
@@ -819,25 +949,32 @@
   return true;
 }
 
+
 CommandLineInterface::ParseArgumentStatus
 CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
   executable_name_ = argv[0];
 
+  vector<string> arguments;
+  for (int i = 1; i < argc; ++i) {
+    arguments.push_back(argv[i]);
+  }
+
   // Iterate through all arguments and parse them.
-  for (int i = 1; i < argc; i++) {
+  for (int i = 0; i < arguments.size(); ++i) {
     string name, value;
 
-    if (ParseArgument(argv[i], &name, &value)) {
+    if (ParseArgument(arguments[i].c_str(), &name, &value)) {
       // Returned true => Use the next argument as the flag value.
-      if (i + 1 == argc || argv[i+1][0] == '-') {
-        cerr << "Missing value for flag: " << name << endl;
+      if (i + 1 == arguments.size() || arguments[i + 1][0] == '-') {
+        std::cerr << "Missing value for flag: " << name << std::endl;
         if (name == "--decode") {
-          cerr << "To decode an unknown message, use --decode_raw." << endl;
+          std::cerr << "To decode an unknown message, use --decode_raw."
+                    << std::endl;
         }
         return PARSE_ARGUMENT_FAIL;
       } else {
         ++i;
-        value = argv[i];
+        value = arguments[i];
       }
     }
 
@@ -857,24 +994,36 @@
   // Check some errror cases.
   bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
   if (decoding_raw && !input_files_.empty()) {
-    cerr << "When using --decode_raw, no input files should be given." << endl;
+    std::cerr << "When using --decode_raw, no input files should be given."
+              << std::endl;
     return PARSE_ARGUMENT_FAIL;
   } else if (!decoding_raw && input_files_.empty()) {
-    cerr << "Missing input file." << endl;
+    std::cerr << "Missing input file." << std::endl;
     return PARSE_ARGUMENT_FAIL;
   }
   if (mode_ == MODE_COMPILE && output_directives_.empty() &&
       descriptor_set_name_.empty()) {
-    cerr << "Missing output directives." << endl;
+    std::cerr << "Missing output directives." << std::endl;
+    return PARSE_ARGUMENT_FAIL;
+  }
+  if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) {
+    std::cerr << "Can only use --dependency_out=FILE when generating code."
+              << std::endl;
+    return PARSE_ARGUMENT_FAIL;
+  }
+  if (!dependency_out_name_.empty() && input_files_.size() > 1) {
+    std::cerr
+        << "Can only process one input file when using --dependency_out=FILE."
+        << std::endl;
     return PARSE_ARGUMENT_FAIL;
   }
   if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
-    cerr << "--include_imports only makes sense when combined with "
-            "--descriptor_set_out." << endl;
+    std::cerr << "--include_imports only makes sense when combined with "
+                 "--descriptor_set_out." << std::endl;
   }
   if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
-    cerr << "--include_source_info only makes sense when combined with "
-            "--descriptor_set_out." << endl;
+    std::cerr << "--include_source_info only makes sense when combined with "
+                 "--descriptor_set_out." << std::endl;
   }
 
   return PARSE_ARGUMENT_DONE_AND_CONTINUE;
@@ -947,10 +1096,12 @@
   if (name.empty()) {
     // Not a flag.  Just a filename.
     if (value.empty()) {
-      cerr << "You seem to have passed an empty string as one of the "
-              "arguments to " << executable_name_ << ".  This is actually "
-              "sort of hard to do.  Congrats.  Unfortunately it is not valid "
-              "input so the program is going to die now." << endl;
+      std::cerr
+          << "You seem to have passed an empty string as one of the "
+             "arguments to " << executable_name_
+          << ".  This is actually "
+             "sort of hard to do.  Congrats.  Unfortunately it is not valid "
+             "input so the program is going to die now." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
@@ -977,14 +1128,16 @@
       }
 
       if (disk_path.empty()) {
-        cerr << "--proto_path passed empty directory name.  (Use \".\" for "
-                "current directory.)" << endl;
+        std::cerr
+            << "--proto_path passed empty directory name.  (Use \".\" for "
+               "current directory.)" << std::endl;
         return PARSE_ARGUMENT_FAIL;
       }
 
       // Make sure disk path exists, warn otherwise.
       if (access(disk_path.c_str(), F_OK) < 0) {
-        cerr << disk_path << ": warning: directory does not exist." << endl;
+        std::cerr << disk_path << ": warning: directory does not exist."
+                  << std::endl;
       }
 
       // Don't use make_pair as the old/default standard library on Solaris
@@ -995,30 +1148,42 @@
 
   } else if (name == "-o" || name == "--descriptor_set_out") {
     if (!descriptor_set_name_.empty()) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     if (value.empty()) {
-      cerr << name << " requires a non-empty value." << endl;
+      std::cerr << name << " requires a non-empty value." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     if (mode_ != MODE_COMPILE) {
-      cerr << "Cannot use --encode or --decode and generate descriptors at the "
-              "same time." << endl;
+      std::cerr
+          << "Cannot use --encode or --decode and generate descriptors at the "
+             "same time." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     descriptor_set_name_ = value;
 
+  } else if (name == "--dependency_out") {
+    if (!dependency_out_name_.empty()) {
+      std::cerr << name << " may only be passed once." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    if (value.empty()) {
+      std::cerr << name << " requires a non-empty value." << std::endl;
+      return PARSE_ARGUMENT_FAIL;
+    }
+    dependency_out_name_ = value;
+
   } else if (name == "--include_imports") {
     if (imports_in_descriptor_set_) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     imports_in_descriptor_set_ = true;
 
   } else if (name == "--include_source_info") {
     if (source_info_in_descriptor_set_) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     source_info_in_descriptor_set_ = true;
@@ -1029,7 +1194,7 @@
 
   } else if (name == "--version") {
     if (!version_info_.empty()) {
-      cout << version_info_ << endl;
+      std::cout << version_info_ << std::endl;
     }
     cout << "libprotoc "
          << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
@@ -1042,25 +1207,28 @@
   } else if (name == "--encode" || name == "--decode" ||
              name == "--decode_raw") {
     if (mode_ != MODE_COMPILE) {
-      cerr << "Only one of --encode and --decode can be specified." << endl;
+      std::cerr << "Only one of --encode and --decode can be specified."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
-      cerr << "Cannot use " << name
-           << " and generate code or descriptors at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
     mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
 
     if (value.empty() && name != "--decode_raw") {
-      cerr << "Type name for " << name << " cannot be blank." << endl;
+      std::cerr << "Type name for " << name << " cannot be blank." << std::endl;
       if (name == "--decode") {
-        cerr << "To decode an unknown message, use --decode_raw." << endl;
+        std::cerr << "To decode an unknown message, use --decode_raw."
+                  << std::endl;
       }
       return PARSE_ARGUMENT_FAIL;
     } else if (!value.empty() && name == "--decode_raw") {
-      cerr << "--decode_raw does not take a parameter." << endl;
+      std::cerr << "--decode_raw does not take a parameter." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
@@ -1072,13 +1240,13 @@
     } else if (value == "msvs") {
       error_format_ = ERROR_FORMAT_MSVS;
     } else {
-      cerr << "Unknown error format: " << value << endl;
+      std::cerr << "Unknown error format: " << value << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
   } else if (name == "--plugin") {
     if (plugin_prefix_.empty()) {
-      cerr << "This compiler does not support plugins." << endl;
+      std::cerr << "This compiler does not support plugins." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
@@ -1104,13 +1272,15 @@
 
   } else if (name == "--print_free_field_numbers") {
     if (mode_ != MODE_COMPILE) {
-      cerr << "Cannot use " << name << " and use --encode, --decode or print "
-           << "other info at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and use --encode, --decode or print "
+                << "other info at the same time." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
-      cerr << "Cannot use " << name
-           << " and generate code or descriptors at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     mode_ = MODE_PRINT;
@@ -1124,7 +1294,7 @@
       // Check if it's a generator option flag.
       generator_info = FindOrNull(generators_by_option_name_, name);
       if (generator_info == NULL) {
-        cerr << "Unknown flag: " << name << endl;
+        std::cerr << "Unknown flag: " << name << std::endl;
         return PARSE_ARGUMENT_FAIL;
       } else {
         string* parameters = &generator_parameters_[generator_info->flag_name];
@@ -1136,8 +1306,8 @@
     } else {
       // It's an output flag.  Add it to the output directives.
       if (mode_ != MODE_COMPILE) {
-        cerr << "Cannot use --encode, --decode or print .proto info and "
-                "generate code at the same time." << endl;
+        std::cerr << "Cannot use --encode, --decode or print .proto info and "
+                     "generate code at the same time." << std::endl;
         return PARSE_ARGUMENT_FAIL;
       }
 
@@ -1169,7 +1339,7 @@
 
 void CommandLineInterface::PrintHelpText() {
   // Sorry for indentation here; line wrapping would be uglier.
-  cerr <<
+  std::cerr <<
 "Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
 "Parse PROTO_FILES and generate output based on the options given:\n"
 "  -IPATH, --proto_path=PATH   Specify the directory in which to search for\n"
@@ -1203,6 +1373,9 @@
 "                              include information about the original\n"
 "                              location of each decl in the source file as\n"
 "                              well as surrounding comments.\n"
+"  --dependency_out=FILE       Write a dependency output file in the format\n"
+"                              expected by make. This writes the transitive\n"
+"                              set of input file paths to FILE\n"
 "  --error_format=FORMAT       Set the format in which to print errors.\n"
 "                              FORMAT may be 'gcc' (the default) or 'msvs'\n"
 "                              (Microsoft Visual Studio format).\n"
@@ -1210,9 +1383,10 @@
 "                              defined in the given proto files. Groups share\n"
 "                              the same field number space with the parent \n"
 "                              message. Extension ranges are counted as \n"
-"                              occupied fields numbers."  << endl;
+"                              occupied fields numbers.\n"
+      << std::endl;
   if (!plugin_prefix_.empty()) {
-    cerr <<
+    std::cerr <<
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
 "                              Normally, protoc searches the PATH for\n"
 "                              plugins, but you may specify additional\n"
@@ -1220,7 +1394,7 @@
 "                              Additionally, EXECUTABLE may be of the form\n"
 "                              NAME=PATH, in which case the given plugin name\n"
 "                              is mapped to the given executable even if\n"
-"                              the executable's own name differs." << endl;
+"                              the executable's own name differs." << std::endl;
   }
 
   for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
@@ -1228,9 +1402,9 @@
     // FIXME(kenton):  If the text is long enough it will wrap, which is ugly,
     //   but fixing this nicely (e.g. splitting on spaces) is probably more
     //   trouble than it's worth.
-    cerr << "  " << iter->first << "=OUT_DIR "
-         << string(19 - iter->first.size(), ' ')  // Spaces for alignment.
-         << iter->second.help_text << endl;
+    std::cerr << "  " << iter->first << "=OUT_DIR "
+              << string(19 - iter->first.size(), ' ')  // Spaces for alignment.
+              << iter->second.help_text << std::endl;
   }
 }
 
@@ -1253,7 +1427,7 @@
     if (!GeneratePluginOutput(parsed_files, plugin_name,
                               output_directive.parameter,
                               generator_context, &error)) {
-      cerr << output_directive.name << ": " << error << endl;
+      std::cerr << output_directive.name << ": " << error << std::endl;
       return false;
     }
   } else {
@@ -1265,14 +1439,96 @@
       }
       parameters.append(generator_parameters_[output_directive.name]);
     }
-    for (int i = 0; i < parsed_files.size(); i++) {
-      if (!output_directive.generator->Generate(parsed_files[i], parameters,
-                                                generator_context, &error)) {
-        // Generator returned an error.
-        cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
-             << error << endl;
-        return false;
+    if (output_directive.generator->HasGenerateAll()) {
+      if (!output_directive.generator->GenerateAll(
+          parsed_files, parameters, generator_context, &error)) {
+          // Generator returned an error.
+          std::cerr << output_directive.name << ": "
+                    << ": " << error << std::endl;
+          return false;
       }
+    } else {
+      for (int i = 0; i < parsed_files.size(); i++) {
+        if (!output_directive.generator->Generate(parsed_files[i], parameters,
+                                                  generator_context, &error)) {
+          // Generator returned an error.
+          std::cerr << output_directive.name << ": " << parsed_files[i]->name()
+                    << ": " << error << std::endl;
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+bool CommandLineInterface::GenerateDependencyManifestFile(
+    const vector<const FileDescriptor*>& parsed_files,
+    const GeneratorContextMap& output_directories,
+    DiskSourceTree* source_tree) {
+  FileDescriptorSet file_set;
+
+  set<const FileDescriptor*> already_seen;
+  for (int i = 0; i < parsed_files.size(); i++) {
+    GetTransitiveDependencies(parsed_files[i],
+                              false,
+                              false,
+                              &already_seen,
+                              file_set.mutable_file());
+  }
+
+  vector<string> output_filenames;
+  for (GeneratorContextMap::const_iterator iter = output_directories.begin();
+       iter != output_directories.end(); ++iter) {
+    const string& location = iter->first;
+    GeneratorContextImpl* directory = iter->second;
+    vector<string> relative_output_filenames;
+    directory->GetOutputFilenames(&relative_output_filenames);
+    for (int i = 0; i < relative_output_filenames.size(); i++) {
+      string output_filename = location + relative_output_filenames[i];
+      if (output_filename.compare(0, 2, "./") == 0) {
+        output_filename = output_filename.substr(2);
+      }
+      output_filenames.push_back(output_filename);
+    }
+  }
+
+  int fd;
+  do {
+    fd = open(dependency_out_name_.c_str(),
+              O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+  } while (fd < 0 && errno == EINTR);
+
+  if (fd < 0) {
+    perror(dependency_out_name_.c_str());
+    return false;
+  }
+
+  io::FileOutputStream out(fd);
+  io::Printer printer(&out, '$');
+
+  for (int i = 0; i < output_filenames.size(); i++) {
+    printer.Print(output_filenames[i].c_str());
+    if (i == output_filenames.size() - 1) {
+      printer.Print(":");
+    } else {
+      printer.Print(" \\\n");
+    }
+  }
+
+  for (int i = 0; i < file_set.file_size(); i++) {
+    const FileDescriptorProto& file = file_set.file(i);
+    const string& virtual_file = file.name();
+    string disk_file;
+    if (source_tree &&
+        source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) {
+      printer.Print(" $disk_file$", "disk_file", disk_file);
+      if (i < file_set.file_size() - 1) printer.Print("\\\n");
+    } else {
+      std::cerr << "Unable to identify path for file " << virtual_file
+                << std::endl;
+      return false;
     }
   }
 
@@ -1297,6 +1553,7 @@
   for (int i = 0; i < parsed_files.size(); i++) {
     request.add_file_to_generate(parsed_files[i]->name());
     GetTransitiveDependencies(parsed_files[i],
+                              true,  // Include json_name for plugins.
                               true,  // Include source code info.
                               &already_seen, request.mutable_proto_file());
   }
@@ -1318,7 +1575,7 @@
 
   // Write the files.  We do this even if there was a generator error in order
   // to match the behavior of a compiled-in generator.
-  scoped_ptr<io::ZeroCopyOutputStream> current_output;
+  google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> current_output;
   for (int i = 0; i < response.file_size(); i++) {
     const CodeGeneratorResponse::File& output_file = response.file(i);
 
@@ -1362,12 +1619,12 @@
   // Look up the type.
   const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
   if (type == NULL) {
-    cerr << "Type not defined: " << codec_type_ << endl;
+    std::cerr << "Type not defined: " << codec_type_ << std::endl;
     return false;
   }
 
   DynamicMessageFactory dynamic_factory(pool);
-  scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
+  google::protobuf::scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
 
   if (mode_ == MODE_ENCODE) {
     SetFdToTextMode(STDIN_FILENO);
@@ -1388,32 +1645,32 @@
     parser.AllowPartialMessage(true);
 
     if (!parser.Parse(&in, message.get())) {
-      cerr << "Failed to parse input." << endl;
+      std::cerr << "Failed to parse input." << std::endl;
       return false;
     }
   } else {
     // Input is binary.
     if (!message->ParsePartialFromZeroCopyStream(&in)) {
-      cerr << "Failed to parse input." << endl;
+      std::cerr << "Failed to parse input." << std::endl;
       return false;
     }
   }
 
   if (!message->IsInitialized()) {
-    cerr << "warning:  Input message is missing required fields:  "
-         << message->InitializationErrorString() << endl;
+    std::cerr << "warning:  Input message is missing required fields:  "
+              << message->InitializationErrorString() << std::endl;
   }
 
   if (mode_ == MODE_ENCODE) {
     // Output is binary.
     if (!message->SerializePartialToZeroCopyStream(&out)) {
-      cerr << "output: I/O error." << endl;
+      std::cerr << "output: I/O error." << std::endl;
       return false;
     }
   } else {
     // Output is text.
     if (!TextFormat::Print(*message, &out)) {
-      cerr << "output: I/O error." << endl;
+      std::cerr << "output: I/O error." << std::endl;
       return false;
     }
   }
@@ -1429,13 +1686,19 @@
     set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
       GetTransitiveDependencies(parsed_files[i],
+                                true,  // Include json_name
                                 source_info_in_descriptor_set_,
                                 &already_seen, file_set.mutable_file());
     }
   } else {
+    set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
+      if (!already_seen.insert(parsed_files[i]).second) {
+        continue;
+      }
       FileDescriptorProto* file_proto = file_set.add_file();
       parsed_files[i]->CopyTo(file_proto);
+      parsed_files[i]->CopyJsonNameTo(file_proto);
       if (source_info_in_descriptor_set_) {
         parsed_files[i]->CopySourceCodeInfoTo(file_proto);
       }
@@ -1455,12 +1718,14 @@
 
   io::FileOutputStream out(fd);
   if (!file_set.SerializeToZeroCopyStream(&out)) {
-    cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+    std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+              << std::endl;
     out.Close();
     return false;
   }
   if (!out.Close()) {
-    cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+    std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+              << std::endl;
     return false;
   }
 
@@ -1468,7 +1733,9 @@
 }
 
 void CommandLineInterface::GetTransitiveDependencies(
-    const FileDescriptor* file, bool include_source_code_info,
+    const FileDescriptor* file,
+    bool include_json_name,
+    bool include_source_code_info,
     set<const FileDescriptor*>* already_seen,
     RepeatedPtrField<FileDescriptorProto>* output) {
   if (!already_seen->insert(file).second) {
@@ -1478,13 +1745,18 @@
 
   // Add all dependencies.
   for (int i = 0; i < file->dependency_count(); i++) {
-    GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+    GetTransitiveDependencies(file->dependency(i),
+                              include_json_name,
+                              include_source_code_info,
                               already_seen, output);
   }
 
   // Add this file.
   FileDescriptorProto* new_descriptor = output->Add();
   file->CopyTo(new_descriptor);
+  if (include_json_name) {
+    file->CopyJsonNameTo(new_descriptor);
+  }
   if (include_source_code_info) {
     file->CopySourceCodeInfoTo(new_descriptor);
   }
@@ -1539,6 +1811,10 @@
     ranges->insert(FieldRange(descriptor->extension_range(i)->start,
                               descriptor->extension_range(i)->end));
   }
+  for (int i = 0; i < descriptor->reserved_range_count(); ++i) {
+    ranges->insert(FieldRange(descriptor->reserved_range(i)->start,
+                              descriptor->reserved_range(i)->end));
+  }
   // Handle the nested messages/groups in declaration order to make it
   // post-order strict.
   for (int i = 0; i < descriptor->nested_type_count(); ++i) {
@@ -1579,7 +1855,7 @@
   if (next_free_number <= FieldDescriptor::kMaxNumber) {
     StringAppendF(&output, " %d-INF", next_free_number);
   }
-  cout << output << endl;
+  std::cout << output << std::endl;
 }
 
 }  // namespace
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 47f2891..d137766 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -39,6 +39,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
 #include <string>
 #include <vector>
 #include <map>
@@ -190,6 +191,7 @@
   class ErrorPrinter;
   class GeneratorContextImpl;
   class MemoryOutputStream;
+  typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
 
   // Clear state from previous Run().
   void Clear();
@@ -210,11 +212,12 @@
   // Parse all command-line arguments.
   ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
 
+
   // Parses a command-line argument into a name/value pair.  Returns
   // true if the next argument in the argv should be used as the value,
   // false otherwise.
   //
-  // Exmaples:
+  // Examples:
   //   "-Isrc/protos" ->
   //     name = "-I", value = "src/protos"
   //   "--cpp_out=src/foo.pb2.cc" ->
@@ -247,6 +250,12 @@
   // Implements the --descriptor_set_out option.
   bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files);
 
+  // Implements the --dependency_out option
+  bool GenerateDependencyManifestFile(
+      const vector<const FileDescriptor*>& parsed_files,
+      const GeneratorContextMap& output_directories,
+      DiskSourceTree* source_tree);
+
   // Get all transitive dependencies of the given file (including the file
   // itself), adding them to the given list of FileDescriptorProtos.  The
   // protos will be ordered such that every file is listed before any file that
@@ -254,8 +263,11 @@
   // in order.  Any files in *already_seen will not be added, and each file
   // added will be inserted into *already_seen.  If include_source_code_info is
   // true then include the source code information in the FileDescriptorProtos.
+  // If include_json_name is true, populate the json_name field of
+  // FieldDescriptorProto for all fields.
   static void GetTransitiveDependencies(
       const FileDescriptor* file,
+      bool include_json_name,
       bool include_source_code_info,
       set<const FileDescriptor*>* already_seen,
       RepeatedPtrField<FileDescriptorProto>* output);
@@ -353,6 +365,10 @@
   // FileDescriptorSet should be written.  Otherwise, empty.
   string descriptor_set_name_;
 
+  // If --dependency_out was given, this is the path to the file where the
+  // dependency file will be written. Otherwise, empty.
+  string dependency_out_name_;
+
   // True if --include_imports was given, meaning that we should
   // write all transitive dependencies to the DescriptorSet.  Otherwise, only
   // the .proto files listed on the command-line are added.
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 6bf7357..9b504d2 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -41,6 +41,9 @@
 #include <unistd.h>
 #endif
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/descriptor.pb.h>
@@ -48,6 +51,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/compiler/mock_code_generator.h>
 #include <google/protobuf/compiler/subprocess.h>
 #include <google/protobuf/io/printer.h>
@@ -56,13 +60,19 @@
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
+
 namespace google {
 namespace protobuf {
 namespace compiler {
 
+// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
+// which case tcmalloc will print warnings that fail the plugin tests.
+#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+
 #if defined(_WIN32)
 #ifndef STDIN_FILENO
 #define STDIN_FILENO 0
@@ -77,6 +87,10 @@
 
 namespace {
 
+bool FileExists(const string& path) {
+  return File::Exists(path);
+}
+
 class CommandLineInterfaceTest : public testing::Test {
  protected:
   virtual void SetUp();
@@ -103,6 +117,16 @@
   // Create a subdirectory within temp_directory_.
   void CreateTempDir(const string& name);
 
+#ifdef PROTOBUF_OPENSOURCE
+  // Change working directory to temp directory.
+  void SwitchToTempDirectory() {
+    File::ChangeWorkingDirectory(temp_directory_);
+  }
+#else  // !PROTOBUF_OPENSOURCE
+  // TODO(teboring): Figure out how to change and get working directory in
+  // google3.
+#endif  // !PROTOBUF_OPENSOURCE
+
   void SetInputsAreProtoPathRelative(bool enable) {
     cli_.SetInputsAreProtoPathRelative(enable);
   }
@@ -167,6 +191,9 @@
   void ReadDescriptorSet(const string& filename,
                          FileDescriptorSet* descriptor_set);
 
+  void ExpectFileContent(const string& filename,
+                         const string& content);
+
  private:
   // The object we are testing.
   CommandLineInterface cli_;
@@ -226,7 +253,7 @@
 
   // If the temp directory already exists, it must be left over from a
   // previous run.  Delete it.
-  if (File::Exists(temp_directory_)) {
+  if (FileExists(temp_directory_)) {
     File::DeleteRecursively(temp_directory_, NULL, NULL);
   }
 
@@ -252,7 +279,9 @@
 
 void CommandLineInterfaceTest::TearDown() {
   // Delete the temp directory.
-  File::DeleteRecursively(temp_directory_, NULL, NULL);
+  if (FileExists(temp_directory_)) {
+    File::DeleteRecursively(temp_directory_, NULL, NULL);
+  }
 
   // Delete all the MockCodeGenerators.
   for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
@@ -266,6 +295,11 @@
 
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+    string plugin_path;
+#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
+    plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
+#else
     const char* possible_paths[] = {
       // When building with shared libraries, libtool hides the real executable
       // in .libs and puts a fake wrapper in the current directory.
@@ -283,17 +317,20 @@
       "test_plugin.exe",        // Other Win32 (MSVC)
       "test_plugin",            // Unix
     };
-
-    string plugin_path;
-
     for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) {
       if (access(possible_paths[i], F_OK) == 0) {
         plugin_path = possible_paths[i];
         break;
       }
     }
+#endif
 
     if (plugin_path.empty()) {
+#else
+    string plugin_path = "third_party/protobuf/test_plugin";
+
+    if (access(plugin_path.c_str(), F_OK) != 0) {
+#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
       GOOGLE_LOG(ERROR)
           << "Plugin executable not found.  Plugin tests are likely to fail.";
     } else {
@@ -301,7 +338,7 @@
     }
   }
 
-  scoped_array<const char*> argv(new const char* [args.size()]);
+  google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]);
 
   for (int i = 0; i < args.size(); i++) {
     args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
@@ -333,7 +370,7 @@
   string::size_type slash_pos = name.find_last_of('/');
   if (slash_pos != string::npos) {
     string dir = name.substr(0, slash_pos);
-    if (!File::Exists(temp_directory_ + "/" + dir)) {
+    if (!FileExists(temp_directory_ + "/" + dir)) {
       GOOGLE_CHECK_OK(File::RecursivelyCreateDir(temp_directory_ + "/" + dir,
                                           0777));
     }
@@ -341,7 +378,9 @@
 
   // Write file.
   string full_name = temp_directory_ + "/" + name;
-  GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true));
+  GOOGLE_CHECK_OK(File::SetContents(
+      full_name, StringReplace(contents, "$tmpdir", temp_directory_, true),
+      true));
 }
 
 void CommandLineInterfaceTest::CreateTempDir(const string& name) {
@@ -445,6 +484,17 @@
   EXPECT_EQ(expected_text, captured_stdout_);
 }
 
+
+void CommandLineInterfaceTest::ExpectFileContent(
+    const string& filename, const string& content) {
+  string path = temp_directory_ + "/" + filename;
+  string file_contents;
+  GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
+
+  EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true),
+            file_contents);
+}
+
 // ===================================================================
 
 TEST_F(CommandLineInterfaceTest, BasicOutput) {
@@ -714,7 +764,7 @@
 #endif
 
   Run("protocol_compiler --test_out=$tmpdir "
-      "--proto_path=$tmpdir/a"PATH_SEPARATOR"$tmpdir/b foo.proto");
+      "--proto_path=$tmpdir/a" PATH_SEPARATOR "$tmpdir/b foo.proto");
 
 #undef PATH_SEPARATOR
 
@@ -840,6 +890,47 @@
   EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
   // Descriptor set should not have source code info.
   EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+  // Descriptor set should have json_name.
+  EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+  EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
+}
+
+TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Bar {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+  CreateTempFile("baz.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Baz {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+      "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+  if (HasFatalFailure()) return;
+  EXPECT_EQ(3, descriptor_set.file_size());
+  EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
+  EXPECT_EQ("foo.proto", descriptor_set.file(1).name());
+  EXPECT_EQ("baz.proto", descriptor_set.file(2).name());
+  // Descriptor set should not have source code info.
+  EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+  // Descriptor set should have json_name.
+  EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+  EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
 }
 
 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
@@ -929,6 +1020,81 @@
   EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
 }
 
+#ifdef _WIN32
+// TODO(teboring): Figure out how to write test on windows.
+#else
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Bar {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --dependency_out=$tmpdir/manifest "
+      "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
+
+  ExpectErrorText(
+      "Can only process one input file when using --dependency_out=FILE.\n");
+}
+
+#ifdef PROTOBUF_OPENSOURCE
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Bar {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+
+  string current_working_directory = getcwd(NULL, 0);
+  SwitchToTempDirectory();
+
+  Run("protocol_compiler --dependency_out=manifest --test_out=. "
+      "bar.proto");
+
+  ExpectNoErrors();
+
+  ExpectFileContent("manifest",
+                    "bar.proto.MockCodeGenerator.test_generator: "
+                    "foo.proto\\\n bar.proto");
+
+  File::ChangeWorkingDirectory(current_working_directory);
+}
+#else  // !PROTOBUF_OPENSOURCE
+// TODO(teboring): Figure out how to change and get working directory in
+// google3.
+#endif  // !PROTOBUF_OPENSOURCE
+
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Bar {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --dependency_out=$tmpdir/manifest "
+      "--test_out=$tmpdir --proto_path=$tmpdir bar.proto");
+
+  ExpectNoErrors();
+
+  ExpectFileContent("manifest",
+                    "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
+                    "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
+}
+#endif  // !_WIN32
+
+
 // -------------------------------------------------------------------
 
 TEST_F(CommandLineInterfaceTest, ParseErrors) {
@@ -1260,6 +1426,18 @@
       "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
 }
 
+TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message MockCodeGenerator_HasJsonName {\n"
+    "  optional int32 value = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("Saw json_name: 1");
+}
+
 TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
   // Test what happens if the plugin isn't found.
 
@@ -1539,7 +1717,7 @@
     SplitStringUsing(command, " ", &args);
     args.push_back("--proto_path=" + TestSourceDir());
 
-    scoped_array<const char*> argv(new const char* [args.size()]);
+    google::protobuf::scoped_array<const char * > argv(new const char* [args.size()]);
     for (int i = 0; i < args.size(); i++) {
       argv[i] = args[i].c_str();
     }
@@ -1649,6 +1827,8 @@
 
 }  // anonymous namespace
 
+#endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index 4878819..77451ab 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -54,6 +54,7 @@
 #include <google/protobuf/stubs/substitute.h>
 
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -98,7 +99,8 @@
                           &actual_contents, true));
     EXPECT_TRUE(actual_contents == *expected_contents)
       << physical_filename << " needs to be regenerated.  Please run "
-         "generate_descriptor_proto.sh and add this file "
+         "google/protobuf/compiler/release_compiler.sh and "
+         "generate_descriptor_proto.sh. Then add this file "
          "to your CL.";
   }
 
@@ -106,7 +108,7 @@
 
   virtual io::ZeroCopyOutputStream* Open(const string& filename) {
     string** map_slot = &files_[filename];
-    if (*map_slot != NULL) delete *map_slot;
+    delete *map_slot;
     *map_slot = new string;
 
     return new io::StringOutputStream(*map_slot);
@@ -132,8 +134,7 @@
   CppGenerator generator;
   MockGeneratorContext context;
   string error;
-  string parameter;
-  parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
+  string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
   ASSERT_TRUE(generator.Generate(proto_file, parameter,
                                  &context, &error));
   parameter = "dllexport_decl=LIBPROTOC_EXPORT";
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index c31cb5b..c81c598 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -32,7 +32,6 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#include <set>
 #include <map>
 
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
@@ -47,7 +46,7 @@
 
 namespace {
 // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
-// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
 // generation of the GOOGLE_ARRAYSIZE constant.
 bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
   int32 max_value = descriptor->value(0)->number();
@@ -56,7 +55,7 @@
       max_value = descriptor->value(i)->number();
     }
   }
-  return max_value != kint32max;
+  return max_value != ::google::protobuf::kint32max;
 }
 }  // namespace
 
@@ -70,28 +69,40 @@
 
 EnumGenerator::~EnumGenerator() {}
 
+void EnumGenerator::FillForwardDeclaration(
+    map<string, const EnumDescriptor*>* enum_names) {
+  if (!options_.proto_h) {
+    return;
+  }
+  (*enum_names)[classname_] = descriptor_;
+}
+
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {
   map<string, string> vars;
   vars["classname"] = classname_;
   vars["short_name"] = descriptor_->name();
+  vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
 
-  printer->Print(vars, "enum $classname$ {\n");
+  printer->Print(vars, "enum $enumbase$ {\n");
+  printer->Annotate("enumbase", descriptor_);
   printer->Indent();
 
   const EnumValueDescriptor* min_value = descriptor_->value(0);
   const EnumValueDescriptor* max_value = descriptor_->value(0);
 
   for (int i = 0; i < descriptor_->value_count(); i++) {
-    vars["name"] = descriptor_->value(i)->name();
+    vars["name"] = EnumValueName(descriptor_->value(i));
     // In C++, an value of -2147483648 gets interpreted as the negative of
     // 2147483648, and since 2147483648 can't fit in an integer, this produces a
     // compiler warning.  This works around that issue.
     vars["number"] = Int32ToString(descriptor_->value(i)->number());
     vars["prefix"] = (descriptor_->containing_type() == NULL) ?
       "" : classname_ + "_";
+    vars["deprecation"] = descriptor_->value(i)->options().deprecated() ?
+        " PROTOBUF_DEPRECATED" : "";
 
     if (i > 0) printer->Print(",\n");
-    printer->Print(vars, "$prefix$$name$ = $number$");
+    printer->Print(vars, "$prefix$$name$$deprecation$ = $number$");
 
     if (descriptor_->value(i)->number() < min_value->number()) {
       min_value = descriptor_->value(i);
@@ -101,11 +112,20 @@
     }
   }
 
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    // For new enum semantics: generate min and max sentinel values equal to
+    // INT32_MIN and INT32_MAX
+    if (descriptor_->value_count() > 0) printer->Print(",\n");
+    printer->Print(vars,
+        "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n"
+        "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
+  }
+
   printer->Outdent();
   printer->Print("\n};\n");
 
-  vars["min_name"] = min_value->name();
-  vars["max_name"] = max_value->name();
+  vars["min_name"] = EnumValueName(min_value);
+  vars["max_name"] = EnumValueName(max_value);
 
   if (options_.dllexport_decl.empty()) {
     vars["dllexport"] = "";
@@ -124,15 +144,16 @@
       "$prefix$$short_name$_MAX + 1;\n\n");
   }
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(vars,
       "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
     // The _Name and _Parse methods
-    printer->Print(vars,
-      "inline const ::std::string& $classname$_Name($classname$ value) {\n"
-      "  return ::google::protobuf::internal::NameOfEnum(\n"
-      "    $classname$_descriptor(), value);\n"
-      "}\n");
+    printer->Print(
+        vars,
+        "inline const ::std::string& $classname$_Name($classname$ value) {\n"
+        "  return ::google::protobuf::internal::NameOfEnum(\n"
+        "    $classname$_descriptor(), value);\n"
+        "}\n");
     printer->Print(vars,
       "inline bool $classname$_Parse(\n"
       "    const ::std::string& name, $classname$* value) {\n"
@@ -144,9 +165,12 @@
 
 void EnumGenerator::
 GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_->file())) {
+  printer->Print(
+      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
+      "{};\n",
+      "classname", ClassName(descriptor_, true));
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(
-      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type {};\n"
       "template <>\n"
       "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
       "  return $classname$_descriptor();\n"
@@ -159,12 +183,16 @@
   map<string, string> vars;
   vars["nested_name"] = descriptor_->name();
   vars["classname"] = classname_;
+  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
   printer->Print(vars, "typedef $classname$ $nested_name$;\n");
 
   for (int j = 0; j < descriptor_->value_count(); j++) {
-    vars["tag"] = descriptor_->value(j)->name();
+    vars["tag"] = EnumValueName(descriptor_->value(j));
+    vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
+      "PROTOBUF_DEPRECATED_ATTR " : "";
     printer->Print(vars,
-      "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
+      "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n"
+      "  $classname$_$tag$;\n");
   }
 
   printer->Print(vars,
@@ -181,16 +209,18 @@
       "  $classname$_$nested_name$_ARRAYSIZE;\n");
   }
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(vars,
       "static inline const ::google::protobuf::EnumDescriptor*\n"
       "$nested_name$_descriptor() {\n"
       "  return $classname$_descriptor();\n"
       "}\n");
     printer->Print(vars,
-      "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
-      "  return $classname$_Name(value);\n"
-      "}\n");
+                   "static inline const ::std::string& "
+                   "$nested_name$_Name($nested_name$ value) {"
+                   "\n"
+                   "  return $classname$_Name(value);\n"
+                   "}\n");
     printer->Print(vars,
       "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
       "    $nested_name$* value) {\n"
@@ -218,8 +248,9 @@
 void EnumGenerator::GenerateMethods(io::Printer* printer) {
   map<string, string> vars;
   vars["classname"] = classname_;
+  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(vars,
       "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
       "  protobuf_AssignDescriptorsOnce();\n"
@@ -259,16 +290,16 @@
   if (descriptor_->containing_type() != NULL) {
     // We need to "define" the static constants which were declared in the
     // header, to give the linker a place to put them.  Or at least the C++
-    // standard says we have to.  MSVC actually insists tha we do _not_ define
-    // them again in the .cc file.
-    printer->Print("#ifndef _MSC_VER\n");
+    // standard says we have to.  MSVC actually insists that we do _not_ define
+    // them again in the .cc file, prior to VC++ 2015.
+    printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
 
     vars["parent"] = ClassName(descriptor_->containing_type(), false);
     vars["nested_name"] = descriptor_->name();
     for (int i = 0; i < descriptor_->value_count(); i++) {
-      vars["value"] = descriptor_->value(i)->name();
+      vars["value"] = EnumValueName(descriptor_->value(i));
       printer->Print(vars,
-        "const $classname$ $parent$::$value$;\n");
+        "$constexpr$const $classname$ $parent$::$value$;\n");
     }
     printer->Print(vars,
       "const $classname$ $parent$::$nested_name$_MIN;\n"
@@ -278,7 +309,7 @@
         "const int $parent$::$nested_name$_ARRAYSIZE;\n");
     }
 
-    printer->Print("#endif  // _MSC_VER\n");
+    printer->Print("#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 1ebd7cf..90edf00 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -35,11 +35,12 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 
+#include <map>
+#include <set>
 #include <string>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.h>
 
-
 namespace google {
 namespace protobuf {
   namespace io {
@@ -54,12 +55,19 @@
 class EnumGenerator {
  public:
   // See generator.cc for the meaning of dllexport_decl.
-  explicit EnumGenerator(const EnumDescriptor* descriptor,
-                         const Options& options);
+  EnumGenerator(const EnumDescriptor* descriptor, const Options& options);
   ~EnumGenerator();
 
   // Header stuff.
 
+  // Fills the name to use when declaring the enum. This is for use when
+  // generating other .proto.h files. This code should be placed within the
+  // enum's package namespace, but NOT within any class, even for nested
+  // enums. A given key in enum_names will map from an enum class name to the
+  // EnumDescriptor that was responsible for its inclusion in the map. This can
+  // be used to associate the descriptor with the code generated for it.
+  void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names);
+
   // Generate header code defining the enum.  This code should be placed
   // within the enum's package namespace, but NOT within any class, even for
   // nested enums.
@@ -87,10 +95,10 @@
 
  private:
   const EnumDescriptor* descriptor_;
-  string classname_;
-  Options options_;
+  const string classname_;
+  const Options& options_;
   // whether to generate the *_ARRAYSIZE constant.
-  bool generate_array_size_;
+  const bool generate_array_size_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 20b18ad..10252b3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -35,8 +35,8 @@
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
 
 namespace google {
 namespace protobuf {
@@ -59,10 +59,9 @@
 
 // ===================================================================
 
-EnumFieldGenerator::
-EnumFieldGenerator(const FieldDescriptor* descriptor,
-                   const Options& options)
-  : descriptor_(descriptor) {
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetEnumVariables(descriptor, &variables_, options);
 }
 
@@ -76,20 +75,27 @@
 void EnumFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$() const$deprecation$;\n"
-    "inline void set_$name$($type$ value)$deprecation$;\n");
+    "$deprecated_attr$$type$ $name$() const;\n"
+    "$deprecated_attr$void set_$name$($type$ value);\n");
 }
 
 void EnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_);\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
-    "  assert($type$_IsValid(value));\n"
-    "  set_has_$name$();\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    printer->Print(variables,
+    "  assert($type$_IsValid(value));\n");
+  }
+  printer->Print(variables,
+    "  $set_hasbit$\n"
     "  $name$_ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
@@ -121,21 +127,28 @@
     "int value;\n"
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
-    "       input, &value)));\n"
-    "if ($type$_IsValid(value)) {\n"
-    "  set_$name$(static_cast< $type$ >(value));\n");
-  if (UseUnknownFieldSet(descriptor_->file())) {
+    "       input, &value)));\n");
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
     printer->Print(variables_,
-      "} else {\n"
-      "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+      "set_$name$(static_cast< $type$ >(value));\n");
   } else {
-    printer->Print(
-      "} else {\n"
-      "  unknown_fields_stream.WriteVarint32(tag);\n"
-      "  unknown_fields_stream.WriteVarint32(value);\n");
+    printer->Print(variables_,
+      "if ($type$_IsValid(value)) {\n"
+      "  set_$name$(static_cast< $type$ >(value));\n");
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(variables_,
+        "} else {\n"
+        "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+    } else {
+      printer->Print(
+        "} else {\n"
+        "  unknown_fields_stream.WriteVarint32($tag$);\n"
+        "  unknown_fields_stream.WriteVarint32(value);\n",
+        "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_)));
+    }
+    printer->Print(variables_,
+      "}\n");
   }
-  printer->Print(variables_,
-    "}\n");
 }
 
 void EnumFieldGenerator::
@@ -171,21 +184,30 @@
 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
 
 void EnumOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
     "  }\n"
     "  return static_cast< $type$ >($default$);\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
-    "  assert($type$_IsValid(value));\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    printer->Print(variables,
+    "  assert($type$_IsValid(value));\n");
+  }
+  printer->Print(variables,
     "  if (!has_$name$()) {\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "  }\n"
     "  $oneof_prefix$$name$_ = value;\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
 }
 
@@ -207,10 +229,9 @@
 
 // ===================================================================
 
-RepeatedEnumFieldGenerator::
-RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
-                           const Options& options)
-  : descriptor_(descriptor) {
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetEnumVariables(descriptor, &variables_, options);
 }
 
@@ -220,8 +241,8 @@
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField<int> $name$_;\n");
-  if (descriptor_->options().packed()
-      && HasGeneratedMethods(descriptor_->file())) {
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -230,38 +251,49 @@
 void RepeatedEnumFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$(int index) const$deprecation$;\n"
-    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
-    "inline void add_$name$($type$ value)$deprecation$;\n");
+    "$deprecated_attr$$type$ $name$(int index) const;\n"
+    "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
+    "$deprecated_attr$void add_$name$($type$ value);\n");
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
+    "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n"
+    "$deprecated_attr$::google::protobuf::RepeatedField<int>* mutable_$name$();\n");
 }
 
 void RepeatedEnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_.Get(index));\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, $type$ value) {\n"
-    "  assert($type$_IsValid(value));\n"
+    "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    printer->Print(variables,
+    "  assert($type$_IsValid(value));\n");
+  }
+  printer->Print(variables,
     "  $name$_.Set(index, value);\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
-    "inline void $classname$::add_$name$($type$ value) {\n"
-    "  assert($type$_IsValid(value));\n"
+    "$inline$ void $classname$::add_$name$($type$ value) {\n");
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    printer->Print(variables,
+    "  assert($type$_IsValid(value));\n");
+  }
+  printer->Print(variables,
     "  $name$_.Add(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField<int>&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedField<int>&\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedField<int>*\n"
+    "$inline$ ::google::protobuf::RepeatedField<int>*\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
@@ -280,7 +312,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
 }
 
 void RepeatedEnumFieldGenerator::
@@ -295,32 +327,59 @@
     "int value;\n"
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
-    "       input, &value)));\n"
-    "if ($type$_IsValid(value)) {\n"
-    "  add_$name$(static_cast< $type$ >(value));\n");
-  if (UseUnknownFieldSet(descriptor_->file())) {
+    "       input, &value)));\n");
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
     printer->Print(variables_,
-      "} else {\n"
-      "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+      "add_$name$(static_cast< $type$ >(value));\n");
   } else {
-    printer->Print(
-      "} else {\n"
-      "  unknown_fields_stream.WriteVarint32(tag);\n"
-      "  unknown_fields_stream.WriteVarint32(value);\n");
+    printer->Print(variables_,
+      "if ($type$_IsValid(value)) {\n"
+      "  add_$name$(static_cast< $type$ >(value));\n");
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(variables_,
+        "} else {\n"
+        "  mutable_unknown_fields()->AddVarint($number$, value);\n");
+    } else {
+      printer->Print(
+        "} else {\n"
+        "  unknown_fields_stream.WriteVarint32(tag);\n"
+        "  unknown_fields_stream.WriteVarint32(value);\n");
+    }
+    printer->Print("}\n");
   }
-  printer->Print("}\n");
 }
 
 void RepeatedEnumFieldGenerator::
 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
-  if (!descriptor_->options().packed()) {
-    // We use a non-inlined implementation in this case, since this path will
-    // rarely be executed.
-    printer->Print(variables_,
-      "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
-      "       input,\n"
-      "       &$type$_IsValid,\n"
-      "       this->mutable_$name$())));\n");
+  if (!descriptor_->is_packed()) {
+      // This path is rarely executed, so we use a non-inlined implementation.
+    if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+      printer->Print(variables_,
+        "DO_((::google::protobuf::internal::"
+                    "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       NULL,\n"
+        "       NULL,\n"
+        "       this->mutable_$name$())));\n");
+    } else if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(variables_,
+        "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       $type$_IsValid,\n"
+        "       mutable_unknown_fields(),\n"
+        "       this->mutable_$name$())));\n");
+    } else {
+      printer->Print(variables_,
+        "DO_((::google::protobuf::internal::"
+                     "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       $type$_IsValid,\n"
+        "       &unknown_fields_stream,\n"
+        "       this->mutable_$name$())));\n");
+    }
   } else {
     printer->Print(variables_,
       "::google::protobuf::uint32 length;\n"
@@ -331,10 +390,27 @@
       "  int value;\n"
       "  DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
       "         int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
-      "       input, &value)));\n"
+      "       input, &value)));\n");
+    if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+      printer->Print(variables_,
+      "  add_$name$(static_cast< $type$ >(value));\n");
+    } else {
+      printer->Print(variables_,
       "  if ($type$_IsValid(value)) {\n"
       "    add_$name$(static_cast< $type$ >(value));\n"
-      "  }\n"
+      "  } else {\n");
+      if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+        printer->Print(variables_,
+        "    mutable_unknown_fields()->AddVarint($number$, value);\n");
+      } else {
+        printer->Print(variables_,
+        "    unknown_fields_stream.WriteVarint32(tag);\n"
+        "    unknown_fields_stream.WriteVarint32(value);\n");
+      }
+      printer->Print(
+      "  }\n");
+    }
+    printer->Print(variables_,
       "}\n"
       "input->PopLimit(limit);\n");
   }
@@ -342,7 +418,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -355,7 +431,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
       "    this->$name$(i), output);\n");
@@ -369,7 +445,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -383,7 +459,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
       "    this->$name$(i), target);\n");
@@ -407,7 +483,7 @@
       "    this->$name$(i));\n"
       "}\n");
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
       "  total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index def2b23..fe21c57 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -46,14 +46,14 @@
 
 class EnumFieldGenerator : public FieldGenerator {
  public:
-  explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
-                              const Options& options);
+  EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
   ~EnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -73,12 +73,13 @@
 
 class EnumOneofFieldGenerator : public EnumFieldGenerator {
  public:
-  explicit EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
-                                   const Options& options);
+  EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
   ~EnumOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -89,14 +90,15 @@
 
 class RepeatedEnumFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
-                                      const Options& options);
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
   ~RepeatedEnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 468ca48..c42f162 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -155,7 +155,7 @@
   // Likewise, class members need to declare the field constant variable.
   if (descriptor_->extension_scope() != NULL) {
     printer->Print(vars,
-      "#ifndef _MSC_VER\n"
+      "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
       "const int $scope$$constant_name$;\n"
       "#endif\n");
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h
index d354c16..1c1caf1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -57,7 +57,7 @@
 class ExtensionGenerator {
  public:
   // See generator.cc for the meaning of dllexport_decl.
-  explicit ExtensionGenerator(const FieldDescriptor* desycriptor,
+  explicit ExtensionGenerator(const FieldDescriptor* descriptor,
                               const Options& options);
   ~ExtensionGenerator();
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 1e9a40a..b3ba3a2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -34,15 +34,20 @@
 
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
 #include <google/protobuf/compiler/cpp/cpp_message_field.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 
@@ -62,18 +67,43 @@
   (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
   (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
 
+  // non_null_ptr_to_name is usable only if has_$name$ is true.  It yields a
+  // pointer that will not be NULL.  Subclasses of FieldGenerator may set
+  // (*variables)["non_null_ptr_to_name"] differently.
+  (*variables)["non_null_ptr_to_name"] =
+      StrCat("&this->", FieldName(descriptor), "()");
+
   (*variables)["tag_size"] = SimpleItoa(
     WireFormat::TagSize(descriptor->number(), descriptor->type()));
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? " PROTOBUF_DEPRECATED" : "";
+  (*variables)["deprecated_attr"] = descriptor->options().deprecated()
+      ? "PROTOBUF_DEPRECATED_ATTR " : "";
 
   (*variables)["cppget"] = "Get";
+
+  if (HasFieldPresence(descriptor->file())) {
+    (*variables)["set_hasbit"] =
+        "set_has_" + FieldName(descriptor) + "();";
+    (*variables)["clear_hasbit"] =
+        "clear_has_" + FieldName(descriptor) + "();";
+  } else {
+    (*variables)["set_hasbit"] = "";
+    (*variables)["clear_hasbit"] = "";
+  }
+
+  // By default, empty string, so that generic code used for both oneofs and
+  // singular fields can be written.
+  (*variables)["oneof_prefix"] = "";
 }
 
 void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
                                   map<string, string>* variables) {
-  (*variables)["oneof_prefix"] = descriptor->containing_oneof()->name() + "_.";
+  const string prefix = descriptor->containing_oneof()->name() + "_.";
+  (*variables)["oneof_prefix"] = prefix;
   (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
+  (*variables)["non_null_ptr_to_name"] =
+      StrCat(prefix, (*variables)["name"], "_");
 }
 
 FieldGenerator::~FieldGenerator() {}
@@ -93,8 +123,9 @@
 FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
                                      const Options& options)
     : descriptor_(descriptor),
+      options_(options),
       field_generators_(
-          new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+          new google::protobuf::scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
   // Construct all the FieldGenerators.
   for (int i = 0; i < descriptor->field_count(); i++) {
     field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
@@ -106,7 +137,11 @@
   if (field->is_repeated()) {
     switch (field->cpp_type()) {
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        return new RepeatedMessageFieldGenerator(field, options);
+        if (field->is_map()) {
+          return new MapFieldGenerator(field, options);
+        } else {
+          return new RepeatedMessageFieldGenerator(field, options);
+        }
       case FieldDescriptor::CPPTYPE_STRING:
         switch (field->options().ctype()) {
           default:  // RepeatedStringFieldGenerator handles unknown ctypes.
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index 96c2963..3b01252 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -37,6 +37,9 @@
 
 #include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 
 #include <google/protobuf/descriptor.h>
@@ -66,7 +69,7 @@
 
 class FieldGenerator {
  public:
-  FieldGenerator() {}
+  explicit FieldGenerator(const Options& options) : options_(options) {}
   virtual ~FieldGenerator();
 
   // Generate lines of code declaring members fields of the message class
@@ -77,22 +80,48 @@
   // Generate static default variable for this field. These are placed inside
   // the message class. Most field types don't need this, so the default
   // implementation is empty.
-  virtual void GenerateStaticMembers(io::Printer* printer) const {}
+  virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
+
+  // Generate prototypes for accessors that will manipulate imported
+  // messages inline.  These are for .proto.h headers.
+  //
+  // In .proto.h mode, the headers of imports are not #included. However,
+  // functions that manipulate the imported message types need access to
+  // the class definition of the imported message, meaning that the headers
+  // must be #included. To get around this, functions that manipulate
+  // imported message objects are defined as dependent functions in a base
+  // template class. By making them dependent template functions, the
+  // function templates will not be instantiated until they are called, so
+  // we can defer to those translation units to #include the necessary
+  // generated headers.
+  //
+  // See:
+  // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
+  //
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateDependentAccessorDeclarations(
+      io::Printer* printer) const {}
 
   // Generate prototypes for all of the accessor functions related to this
   // field.  These are placed inside the class definition.
   virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
 
+  // Generate inline definitions of depenent accessor functions for this field.
+  // These are placed inside the header after all class definitions.
+  virtual void GenerateDependentInlineAccessorDefinitions(
+    io::Printer* printer) const {}
+
   // Generate inline definitions of accessor functions for this field.
   // These are placed inside the header after all class definitions.
+  // In non-.proto.h mode, this generates dependent accessor functions as well.
   virtual void GenerateInlineAccessorDefinitions(
-    io::Printer* printer) const = 0;
+    io::Printer* printer, bool is_inline) const = 0;
 
   // Generate definitions of accessors that aren't inlined.  These are
   // placed somewhere in the .cc file.
   // Most field types don't need this, so the default implementation is empty.
   virtual void GenerateNonInlineAccessorDefinitions(
-    io::Printer* printer) const {}
+    io::Printer* /*printer*/) const {}
 
   // Generate lines of code (statements, not declarations) which clear the
   // field.  This is used to define the clear_$name$() method as well as
@@ -122,14 +151,25 @@
   // Generate any code that needs to go in the class's SharedDtor() method,
   // invoked by the destructor.
   // Most field types don't need this, so the default implementation is empty.
-  virtual void GenerateDestructorCode(io::Printer* printer) const {}
+  virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
+
+  // Generate a manual destructor invocation for use when the message is on an
+  // arena. The code that this method generates will be executed inside a
+  // shared-for-the-whole-message-class method registered with OwnDestructor().
+  // The method should return |true| if it generated any code that requires a
+  // call; this allows the message generator to eliminate the OwnDestructor()
+  // registration if no fields require it.
+  virtual bool GenerateArenaDestructorCode(io::Printer* printer) const {
+    return false;
+  }
 
   // Generate code that allocates the fields's default instance.
-  virtual void GenerateDefaultInstanceAllocator(io::Printer* printer) const {}
+  virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/)
+      const {}
 
   // Generate code that should be run when ShutdownProtobufLibrary() is called,
   // to delete all dynamically-allocated objects.
-  virtual void GenerateShutdownCode(io::Printer* printer) const {}
+  virtual void GenerateShutdownCode(io::Printer* /*printer*/) const {}
 
   // Generate lines to decode this field, which will be placed inside the
   // message's MergeFromCodedStream() method.
@@ -154,6 +194,9 @@
   // are placed in the message's ByteSize() method.
   virtual void GenerateByteSize(io::Printer* printer) const = 0;
 
+ protected:
+  const Options& options_;
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
 };
@@ -161,14 +204,15 @@
 // Convenience class which constructs FieldGenerators for a Descriptor.
 class FieldGeneratorMap {
  public:
-  explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
+  FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
   ~FieldGeneratorMap();
 
   const FieldGenerator& get(const FieldDescriptor* field) const;
 
  private:
   const Descriptor* descriptor_;
-  scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+  const Options& options_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGenerator> > field_generators_;
 
   static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
                                        const Options& options);
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index fa19427..385b973 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -33,7 +33,11 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <set>
 
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
@@ -55,15 +59,15 @@
 
 FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
     : file_(file),
+      options_(options),
       message_generators_(
-          new scoped_ptr<MessageGenerator>[file->message_type_count()]),
+          new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
       enum_generators_(
-          new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
+          new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]),
       service_generators_(
-          new scoped_ptr<ServiceGenerator>[file->service_count()]),
+          new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]),
       extension_generators_(
-          new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
-      options_(options) {
+          new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) {
 
   for (int i = 0; i < file->message_type_count(); i++) {
     message_generators_[i].reset(
@@ -90,183 +94,131 @@
 
 FileGenerator::~FileGenerator() {}
 
-void FileGenerator::GenerateHeader(io::Printer* printer) {
+void FileGenerator::GenerateProtoHeader(io::Printer* printer,
+                                        const string& info_path) {
+  if (!options_.proto_h) {
+    return;
+  }
+
   string filename_identifier = FilenameIdentifier(file_->name());
-
-  // Generate top of header.
-  printer->Print(
-    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
-    "// source: $filename$\n"
-    "\n"
-    "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
-    "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
-    "\n"
-    "#include <string>\n"
-    "\n",
-    "filename", file_->name(),
-    "filename_identifier", filename_identifier);
+  GenerateTopHeaderGuard(printer, filename_identifier);
 
 
-  printer->Print(
-    "#include <google/protobuf/stubs/common.h>\n"
-    "\n");
+  GenerateLibraryIncludes(printer);
 
-  // Verify the protobuf library header version is compatible with the protoc
-  // version before going any further.
-  printer->Print(
-    "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
-    "#error This file was generated by a newer version of protoc which is\n"
-    "#error incompatible with your Protocol Buffer headers.  Please update\n"
-    "#error your headers.\n"
-    "#endif\n"
-    "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
-    "#error This file was generated by an older version of protoc which is\n"
-    "#error incompatible with your Protocol Buffer headers.  Please\n"
-    "#error regenerate this file with a newer version of protoc.\n"
-    "#endif\n"
-    "\n",
-    "min_header_version",
-      SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
-    "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
-
-  // OK, it's now safe to #include other files.
-  printer->Print(
-    "#include <google/protobuf/generated_message_util.h>\n");
-  if (file_->message_type_count() > 0) {
-    if (HasDescriptorMethods(file_)) {
-      printer->Print(
-        "#include <google/protobuf/message.h>\n");
-    } else {
-      printer->Print(
-        "#include <google/protobuf/message_lite.h>\n");
-    }
-  }
-  printer->Print(
-    "#include <google/protobuf/repeated_field.h>\n"
-    "#include <google/protobuf/extension_set.h>\n");
-
-  if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
-    printer->Print(
-      "#include <google/protobuf/generated_enum_reflection.h>\n");
-  }
-
-  if (HasGenericServices(file_)) {
-    printer->Print(
-      "#include <google/protobuf/service.h>\n");
-  }
-
-  if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
-    printer->Print(
-      "#include <google/protobuf/unknown_field_set.h>\n");
-  }
-
-
-  set<string> public_import_names;
   for (int i = 0; i < file_->public_dependency_count(); i++) {
-    public_import_names.insert(file_->public_dependency(i)->name());
-  }
-
-  for (int i = 0; i < file_->dependency_count(); i++) {
-    const string& name = file_->dependency(i)->name();
-    bool public_import = (public_import_names.count(name) != 0);
-
-
+    const FileDescriptor* dep = file_->public_dependency(i);
+    const char* extension = ".proto.h";
+    string dependency = StripProto(dep->name()) + extension;
     printer->Print(
-      "#include \"$dependency$.pb.h\"$iwyu$\n",
-      "dependency", StripProto(name),
-      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
+      "#include \"$dependency$\"  // IWYU pragma: export\n",
+      "dependency", dependency);
   }
 
+  GenerateMetadataPragma(printer, info_path);
+
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
 
 
+  GenerateForwardDeclarations(printer);
+
   // Open namespace.
   GenerateNamespaceOpeners(printer);
 
-  // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
-  // functions, so that we can declare them to be friends of each class.
+  GenerateGlobalStateFunctionDeclarations(printer);
+
+  printer->Print("\n");
+
+  GenerateEnumDefinitions(printer);
+
+  printer->Print(kThickSeparator);
+  printer->Print("\n");
+
+  GenerateMessageDefinitions(printer);
+
+  printer->Print("\n");
+  printer->Print(kThickSeparator);
+  printer->Print("\n");
+
+  GenerateServiceDefinitions(printer);
+
+  GenerateExtensionIdentifiers(printer);
+
+  printer->Print("\n");
+  printer->Print(kThickSeparator);
+  printer->Print("\n");
+
+  GenerateInlineFunctionDefinitions(printer);
+
   printer->Print(
     "\n"
-    "// Internal implementation detail -- do not call these.\n"
-    "void $dllexport_decl$ $adddescriptorsname$();\n",
-    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
-    "dllexport_decl", options_.dllexport_decl);
+    "// @@protoc_insertion_point(namespace_scope)\n"
+    "\n");
+
+  // Close up namespace.
+  GenerateNamespaceClosers(printer);
+
+  // We need to specialize some templates in the ::google::protobuf namespace:
+  GenerateProto2NamespaceEnumSpecializations(printer);
 
   printer->Print(
-    // Note that we don't put dllexport_decl on these because they are only
-    // called by the .pb.cc file in which they are defined.
-    "void $assigndescriptorsname$();\n"
-    "void $shutdownfilename$();\n"
-    "\n",
-    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
-    "shutdownfilename", GlobalShutdownFileName(file_->name()));
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n"
+    "\n");
 
-  // Generate forward declarations of classes.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateForwardDeclaration(printer);
+  GenerateBottomHeaderGuard(printer, filename_identifier);
+}
+
+void FileGenerator::GeneratePBHeader(io::Printer* printer,
+                                     const string& info_path) {
+  string filename_identifier =
+      FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : ""));
+  GenerateTopHeaderGuard(printer, filename_identifier);
+
+  if (options_.proto_h) {
+    printer->Print("#include \"$basename$.proto.h\"  // IWYU pragma: export\n",
+                   "basename", StripProto(file_->name()));
+  } else {
+    GenerateLibraryIncludes(printer);
   }
+  GenerateDependencyIncludes(printer);
+  GenerateMetadataPragma(printer, info_path);
 
-  printer->Print("\n");
+  printer->Print(
+    "// @@protoc_insertion_point(includes)\n");
 
-  // Generate enum definitions.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateEnumDefinitions(printer);
-  }
-  for (int i = 0; i < file_->enum_type_count(); i++) {
-    enum_generators_[i]->GenerateDefinition(printer);
-  }
 
-  printer->Print(kThickSeparator);
-  printer->Print("\n");
 
-  // Generate class definitions.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    if (i > 0) {
-      printer->Print("\n");
-      printer->Print(kThinSeparator);
-      printer->Print("\n");
-    }
-    message_generators_[i]->GenerateClassDefinition(printer);
-  }
+  // Open namespace.
+  GenerateNamespaceOpeners(printer);
 
-  printer->Print("\n");
-  printer->Print(kThickSeparator);
-  printer->Print("\n");
+  if (!options_.proto_h) {
+    GenerateGlobalStateFunctionDeclarations(printer);
+    GenerateMessageForwardDeclarations(printer);
 
-  if (HasGenericServices(file_)) {
-    // Generate service definitions.
-    for (int i = 0; i < file_->service_count(); i++) {
-      if (i > 0) {
-        printer->Print("\n");
-        printer->Print(kThinSeparator);
-        printer->Print("\n");
-      }
-      service_generators_[i]->GenerateDeclarations(printer);
-    }
+    printer->Print("\n");
+
+    GenerateEnumDefinitions(printer);
+
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
+
+    GenerateMessageDefinitions(printer);
 
     printer->Print("\n");
     printer->Print(kThickSeparator);
     printer->Print("\n");
-  }
 
-  // Declare extension identifiers.
-  for (int i = 0; i < file_->extension_count(); i++) {
-    extension_generators_[i]->GenerateDeclaration(printer);
-  }
+    GenerateServiceDefinitions(printer);
 
-  printer->Print("\n");
-  printer->Print(kThickSeparator);
-  printer->Print("\n");
+    GenerateExtensionIdentifiers(printer);
 
+    printer->Print("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
 
-  // Generate class inline methods.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    if (i > 0) {
-      printer->Print(kThinSeparator);
-      printer->Print("\n");
-    }
-    message_generators_[i]->GenerateInlineMethods(printer);
+    GenerateInlineFunctionDefinitions(printer);
   }
 
   printer->Print(
@@ -276,27 +228,9 @@
   // Close up namespace.
   GenerateNamespaceClosers(printer);
 
-  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
-  if (HasDescriptorMethods(file_)) {
-    // The SWIG conditional is to avoid a null-pointer dereference
-    // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
-    //   namespace X { void Y<Z::W>(); }
-    // which appears in GetEnumDescriptor() specializations.
-    printer->Print(
-        "\n"
-        "#ifndef SWIG\n"
-        "namespace google {\nnamespace protobuf {\n"
-        "\n");
-    for (int i = 0; i < file_->message_type_count(); i++) {
-      message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
-    }
-    for (int i = 0; i < file_->enum_type_count(); i++) {
-      enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
-    }
-    printer->Print(
-        "\n"
-        "}  // namespace google\n}  // namespace protobuf\n"
-        "#endif  // SWIG\n");
+  if (!options_.proto_h) {
+    // We need to specialize some templates in the ::google::protobuf namespace:
+    GenerateProto2NamespaceEnumSpecializations(printer);
   }
 
   printer->Print(
@@ -304,38 +238,41 @@
     "// @@protoc_insertion_point(global_scope)\n"
     "\n");
 
-  printer->Print(
-    "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
-    "filename_identifier", filename_identifier);
+  GenerateBottomHeaderGuard(printer, filename_identifier);
 }
 
 void FileGenerator::GenerateSource(io::Printer* printer) {
+  const bool use_system_include = IsWellKnownMessage(file_);
+  string header =
+      StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "// source: $filename$\n"
     "\n"
-
     // The generated code calls accessors that might be deprecated. We don't
     // want the compiler to warn in generated code.
     "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
-    "#include \"$basename$.pb.h\"\n"
+    "#include $left$$header$$right$\n"
     "\n"
     "#include <algorithm>\n"    // for swap()
     "\n"
     "#include <google/protobuf/stubs/common.h>\n"
+    "#include <google/protobuf/stubs/port.h>\n"
     "#include <google/protobuf/stubs/once.h>\n"
     "#include <google/protobuf/io/coded_stream.h>\n"
     "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "filename", file_->name(),
-    "basename", StripProto(file_->name()));
+    "header", header,
+    "left", use_system_include ? "<" : "\"",
+    "right", use_system_include ? ">" : "\"");
 
   // Unknown fields implementation in lite mode uses StringOutputStream
-  if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+  if (!UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) {
     printer->Print(
       "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n");
   }
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, options_)) {
     printer->Print(
       "#include <google/protobuf/descriptor.h>\n"
       "#include <google/protobuf/generated_message_reflection.h>\n"
@@ -343,12 +280,24 @@
       "#include <google/protobuf/wire_format.h>\n");
   }
 
+  if (options_.proto_h) {
+    // Use the smaller .proto.h files.
+    for (int i = 0; i < file_->dependency_count(); i++) {
+      const FileDescriptor* dep = file_->dependency(i);
+      const char* extension = ".proto.h";
+      string dependency = StripProto(dep->name()) + extension;
+      printer->Print(
+          "#include \"$dependency$\"\n",
+          "dependency", dependency);
+    }
+  }
+
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
 
   GenerateNamespaceOpeners(printer);
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, options_)) {
     printer->Print(
       "\n"
       "namespace {\n"
@@ -362,7 +311,7 @@
         "name", ClassName(file_->enum_type(i), false));
     }
 
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, options_)) {
       for (int i = 0; i < file_->service_count(); i++) {
         printer->Print(
           "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
@@ -387,13 +336,32 @@
 
   // Generate classes.
   for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i == 0 && HasGeneratedMethods(file_, options_)) {
+      printer->Print(
+          "\n"
+          "namespace {\n"
+          "\n"
+          "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;\n"
+          "static void MergeFromFail(int line) {\n"
+          "  GOOGLE_CHECK(false) << __FILE__ << \":\" << line;\n"
+          "}\n"
+          "\n"
+          "}  // namespace\n"
+          "\n");
+    }
     printer->Print("\n");
     printer->Print(kThickSeparator);
     printer->Print("\n");
     message_generators_[i]->GenerateClassMethods(printer);
+
+    printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+    // Generate class inline methods.
+    message_generators_[i]->GenerateInlineMethods(printer,
+                                                  /* is_inline = */ false);
+    printer->Print("#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS\n");
   }
 
-  if (HasGenericServices(file_)) {
+  if (HasGenericServices(file_, options_)) {
     // Generate services.
     for (int i = 0; i < file_->service_count(); i++) {
       if (i == 0) printer->Print("\n");
@@ -419,6 +387,63 @@
     "// @@protoc_insertion_point(global_scope)\n");
 }
 
+class FileGenerator::ForwardDeclarations {
+ public:
+  ~ForwardDeclarations() {
+    for (map<string, ForwardDeclarations *>::iterator it = namespaces_.begin(),
+                                                      end = namespaces_.end();
+         it != end; ++it) {
+      delete it->second;
+    }
+    namespaces_.clear();
+  }
+
+  ForwardDeclarations* AddOrGetNamespace(const string& ns_name) {
+    ForwardDeclarations*& ns = namespaces_[ns_name];
+    if (ns == NULL) {
+      ns = new ForwardDeclarations;
+    }
+    return ns;
+  }
+
+  map<string, const Descriptor*>& classes() { return classes_; }
+  map<string, const EnumDescriptor*>& enums() { return enums_; }
+
+  void Print(io::Printer* printer) const {
+    for (map<string, const EnumDescriptor *>::const_iterator
+             it = enums_.begin(),
+             end = enums_.end();
+         it != end; ++it) {
+      printer->Print("enum $enumname$ : int;\n", "enumname", it->first);
+      printer->Annotate("enumname", it->second);
+      printer->Print("bool $enumname$_IsValid(int value);\n", "enumname",
+                     it->first);
+    }
+    for (map<string, const Descriptor *>::const_iterator it = classes_.begin(),
+                                                         end = classes_.end();
+         it != end; ++it) {
+      printer->Print("class $classname$;\n", "classname", it->first);
+      printer->Annotate("classname", it->second);
+    }
+    for (map<string, ForwardDeclarations *>::const_iterator
+             it = namespaces_.begin(),
+             end = namespaces_.end();
+         it != end; ++it) {
+      printer->Print("namespace $nsname$ {\n",
+                     "nsname", it->first);
+      it->second->Print(printer);
+      printer->Print("}  // namespace $nsname$\n",
+                     "nsname", it->first);
+    }
+  }
+
+
+ private:
+  map<string, ForwardDeclarations*> namespaces_;
+  map<string, const Descriptor*> classes_;
+  map<string, const EnumDescriptor*> enums_;
+};
+
 void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
   // AddDescriptors() is a file-level procedure which adds the encoded
   // FileDescriptorProto for this .proto file to the global DescriptorPool for
@@ -437,7 +462,7 @@
 
   // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
   // and we only use AddDescriptors() to allocate default instances.
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, options_)) {
     printer->Print(
       "\n"
       "void $assigndescriptorsname$() {\n",
@@ -470,7 +495,7 @@
     for (int i = 0; i < file_->enum_type_count(); i++) {
       enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
     }
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, options_)) {
       for (int i = 0; i < file_->service_count(); i++) {
         service_generators_[i]->GenerateDescriptorInitializer(printer, i);
       }
@@ -536,22 +561,23 @@
 
   // Now generate the AddDescriptors() function.
   PrintHandlingOptionalStaticInitializers(
-    file_, printer,
-    // With static initializers.
-    // Note that we don't need any special synchronization in the following code
-    // because it is called at static init time before any threads exist.
-    "void $adddescriptorsname$() {\n"
-    "  static bool already_here = false;\n"
-    "  if (already_here) return;\n"
-    "  already_here = true;\n"
-    "  GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
-    "\n",
-    // Without.
-    "void $adddescriptorsname$_impl() {\n"
-    "  GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
-    "\n",
-    // Vars.
-    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
+      file_, options_, printer,
+      // With static initializers.
+      // Note that we don't need any special synchronization in the following
+      // code
+      // because it is called at static init time before any threads exist.
+      "void $adddescriptorsname$() {\n"
+      "  static bool already_here = false;\n"
+      "  if (already_here) return;\n"
+      "  already_here = true;\n"
+      "  GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+      "\n",
+      // Without.
+      "void $adddescriptorsname$_impl() {\n"
+      "  GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
+      "\n",
+      // Vars.
+      "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
 
   printer->Indent();
 
@@ -568,7 +594,7 @@
       "name", add_desc_name);
   }
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, options_)) {
     // Embed the descriptor.  We simply serialize the entire FileDescriptorProto
     // and embed it as a string literal, which is parsed and built into real
     // descriptors at initialization time.
@@ -577,20 +603,60 @@
     string file_data;
     file_proto.SerializeToString(&file_data);
 
-    printer->Print(
-      "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
+#ifdef _MSC_VER
+    bool breakdown_large_file = true;
+#else
+    bool breakdown_large_file = false;
+#endif
+    // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535
+    // bytes in length". Declare a static array of characters rather than use a
+    // string literal.
+    if (breakdown_large_file && file_data.size() > 65535) {
+      // This has to be explicitly marked as a signed char because the generated
+      // code puts negative values in the array, and sometimes plain char is
+      // unsigned. That implicit narrowing conversion is not allowed in C++11.
+      // <http://stackoverflow.com/questions/4434140/narrowing-conversions-in-c0x-is-it-just-me-or-does-this-sound-like-a-breakin>
+      // has details on why.
+      printer->Print(
+          "static const signed char descriptor[] = {\n");
+      printer->Indent();
 
-    // Only write 40 bytes per line.
-    static const int kBytesPerLine = 40;
-    for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
-      printer->Print("\n  \"$data$\"",
-                     "data",
-                     EscapeTrigraphs(
-                         CEscape(file_data.substr(i, kBytesPerLine))));
+      // Only write 25 bytes per line.
+      static const int kBytesPerLine = 25;
+      for (int i = 0; i < file_data.size();) {
+          for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+            printer->Print(
+                "$char$, ",
+                "char", SimpleItoa(file_data[i]));
+          }
+          printer->Print(
+              "\n");
+      }
+
+      printer->Outdent();
+      printer->Print(
+          "};\n");
+
+      printer->Print(
+          "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n",
+          "size", SimpleItoa(file_data.size()));
+
+    } else {
+      printer->Print(
+        "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
+
+      // Only write 40 bytes per line.
+      static const int kBytesPerLine = 40;
+      for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+        printer->Print("\n  \"$data$\"",
+                       "data",
+                       EscapeTrigraphs(
+                           CEscape(file_data.substr(i, kBytesPerLine))));
     }
     printer->Print(
         ", $size$);\n",
-      "size", SimpleItoa(file_data.size()));
+        "size", SimpleItoa(file_data.size()));
+    }
 
     // Call MessageFactory::InternalRegisterGeneratedFile().
     printer->Print(
@@ -622,23 +688,23 @@
     "\n");
 
   PrintHandlingOptionalStaticInitializers(
-    file_, printer,
-    // With static initializers.
-    "// Force AddDescriptors() to be called at static initialization time.\n"
-    "struct StaticDescriptorInitializer_$filename$ {\n"
-    "  StaticDescriptorInitializer_$filename$() {\n"
-    "    $adddescriptorsname$();\n"
-    "  }\n"
-    "} static_descriptor_initializer_$filename$_;\n",
-    // Without.
-    "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n"
-    "void $adddescriptorsname$() {\n"
-    "  ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
-    "                 &$adddescriptorsname$_impl);\n"
-    "}\n",
-    // Vars.
-    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
-    "filename", FilenameIdentifier(file_->name()));
+      file_, options_, printer,
+      // With static initializers.
+      "// Force AddDescriptors() to be called at static initialization time.\n"
+      "struct StaticDescriptorInitializer_$filename$ {\n"
+      "  StaticDescriptorInitializer_$filename$() {\n"
+      "    $adddescriptorsname$();\n"
+      "  }\n"
+      "} static_descriptor_initializer_$filename$_;\n",
+      // Without.
+      "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n"
+      "void $adddescriptorsname$() {\n"
+      "  ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n"
+      "                 &$adddescriptorsname$_impl);\n"
+      "}\n",
+      // Vars.
+      "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename",
+      FilenameIdentifier(file_->name()));
 }
 
 void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
@@ -659,6 +725,343 @@
   }
 }
 
+void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
+  ForwardDeclarations decls;
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    FileGenerator dependency(file_->dependency(i), options_);
+    dependency.FillForwardDeclarations(&decls);
+  }
+  FillForwardDeclarations(&decls);
+  decls.Print(printer);
+}
+
+void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) {
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    FileGenerator dependency(file_->public_dependency(i), options_);
+    dependency.FillForwardDeclarations(decls);
+  }
+  for (int i = 0; i < package_parts_.size(); i++) {
+    decls = decls->AddOrGetNamespace(package_parts_[i]);
+  }
+  // Generate enum definitions.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->FillEnumForwardDeclarations(&decls->enums());
+  }
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    enum_generators_[i]->FillForwardDeclaration(&decls->enums());
+  }
+  // Generate forward declarations of classes.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->FillMessageForwardDeclarations(
+        &decls->classes());
+  }
+}
+
+void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer,
+                                           const string& filename_identifier) {
+  // Generate top of header.
+  printer->Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n"
+      "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
+      "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
+      "\n"
+      "#include <string>\n",
+      "filename", file_->name(), "filename_identifier", filename_identifier);
+  printer->Print("\n");
+}
+
+void FileGenerator::GenerateBottomHeaderGuard(
+    io::Printer* printer, const string& filename_identifier) {
+  printer->Print(
+    "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
+    "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+
+  printer->Print(
+    "#include <google/protobuf/stubs/common.h>\n"
+    "\n");
+
+  // Verify the protobuf library header version is compatible with the protoc
+  // version before going any further.
+  printer->Print(
+    "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
+    "#error This file was generated by a newer version of protoc which is\n"
+    "#error incompatible with your Protocol Buffer headers.  Please update\n"
+    "#error your headers.\n"
+    "#endif\n"
+    "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
+    "#error This file was generated by an older version of protoc which is\n"
+    "#error incompatible with your Protocol Buffer headers.  Please\n"
+    "#error regenerate this file with a newer version of protoc.\n"
+    "#endif\n"
+    "\n",
+    "min_header_version",
+      SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
+    "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
+
+  // OK, it's now safe to #include other files.
+  printer->Print(
+    "#include <google/protobuf/arena.h>\n"
+    "#include <google/protobuf/arenastring.h>\n"
+    "#include <google/protobuf/generated_message_util.h>\n");
+  if (UseUnknownFieldSet(file_, options_)) {
+    printer->Print(
+      "#include <google/protobuf/metadata.h>\n");
+  }
+  if (file_->message_type_count() > 0) {
+    if (HasDescriptorMethods(file_, options_)) {
+      printer->Print(
+        "#include <google/protobuf/message.h>\n");
+    } else {
+      printer->Print(
+        "#include <google/protobuf/message_lite.h>\n");
+    }
+  }
+  printer->Print(
+    "#include <google/protobuf/repeated_field.h>\n"
+    "#include <google/protobuf/extension_set.h>\n");
+  if (HasMapFields(file_)) {
+    printer->Print(
+        "#include <google/protobuf/map.h>\n");
+    if (HasDescriptorMethods(file_, options_)) {
+      printer->Print(
+          "#include <google/protobuf/map_field_inl.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/map_field_lite.h>\n");
+    }
+  }
+
+  if (HasEnumDefinitions(file_)) {
+    if (HasDescriptorMethods(file_, options_)) {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_reflection.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_util.h>\n");
+    }
+  }
+
+  if (HasGenericServices(file_, options_)) {
+    printer->Print(
+      "#include <google/protobuf/service.h>\n");
+  }
+
+  if (UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) {
+    printer->Print(
+      "#include <google/protobuf/unknown_field_set.h>\n");
+  }
+
+
+  if (IsAnyMessage(file_)) {
+    printer->Print(
+      "#include <google/protobuf/any.h>\n");
+  }
+}
+
+void FileGenerator::GenerateMetadataPragma(io::Printer* printer,
+                                           const string& info_path) {
+  if (!info_path.empty() && !options_.annotation_pragma_name.empty() &&
+      !options_.annotation_guard_name.empty()) {
+    printer->Print(
+        "#ifdef $guard$\n"
+        "#pragma $pragma$ \"$info_path$\"\n"
+        "#endif  // $guard$\n",
+        "guard", options_.annotation_guard_name, "pragma",
+        options_.annotation_pragma_name, "info_path", info_path);
+  }
+}
+
+void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
+  set<string> public_import_names;
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    public_import_names.insert(file_->public_dependency(i)->name());
+  }
+
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    const bool use_system_include = IsWellKnownMessage(file_->dependency(i));
+    const string& name = file_->dependency(i)->name();
+    bool public_import = (public_import_names.count(name) != 0);
+
+
+    printer->Print(
+      "#include $left$$dependency$.pb.h$right$$iwyu$\n",
+      "dependency", StripProto(name),
+      "iwyu", (public_import) ? "  // IWYU pragma: export" : "",
+      "left", use_system_include ? "<" : "\"",
+      "right", use_system_include ? ">" : "\"");
+  }
+}
+
+void FileGenerator::GenerateGlobalStateFunctionDeclarations(
+    io::Printer* printer) {
+  // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+  // functions, so that we can declare them to be friends of each class.
+  printer->Print(
+    "\n"
+    "// Internal implementation detail -- do not call these.\n"
+    "void $dllexport_decl$$adddescriptorsname$();\n",
+    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
+    "dllexport_decl",
+    options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+
+  printer->Print(
+    // Note that we don't put dllexport_decl on these because they are only
+    // called by the .pb.cc file in which they are defined.
+    "void $assigndescriptorsname$();\n"
+    "void $shutdownfilename$();\n"
+    "\n",
+    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
+    "shutdownfilename", GlobalShutdownFileName(file_->name()));
+}
+
+void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
+  map<string, const Descriptor*> classes;
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->FillMessageForwardDeclarations(&classes);
+  }
+  for (map<string, const Descriptor *>::const_iterator it = classes.begin(),
+                                                       end = classes.end();
+       it != end; ++it) {
+    printer->Print("class $classname$;\n", "classname", it->first);
+    printer->Annotate("classname", it->second);
+  }
+}
+
+void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
+  // Generate class definitions.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print("\n");
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    message_generators_[i]->GenerateClassDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
+  // Generate enum definitions.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateEnumDefinitions(printer);
+  }
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    enum_generators_[i]->GenerateDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
+  if (HasGenericServices(file_, options_)) {
+    // Generate service definitions.
+    for (int i = 0; i < file_->service_count(); i++) {
+      if (i > 0) {
+        printer->Print("\n");
+        printer->Print(kThinSeparator);
+        printer->Print("\n");
+      }
+      service_generators_[i]->GenerateDeclarations(printer);
+    }
+
+    printer->Print("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
+  }
+}
+
+void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
+  // Declare extension identifiers.
+  for (int i = 0; i < file_->extension_count(); i++) {
+    extension_generators_[i]->GenerateDeclaration(printer);
+  }
+}
+
+void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
+  // An aside about inline functions in .proto.h mode:
+  //
+  // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally
+  // moving much of the inline functions to the .pb.cc file, which can be a
+  // significant performance benefit for compilation time, at the expense
+  // of non-inline function calls.
+  //
+  // However, in .proto.h mode, the definition of the internal dependent
+  // base class must remain in the header, and can never be out-lined. The
+  // dependent base class also needs access to has-bit manipuation
+  // functions, so the has-bit functions must be unconditionally inlined in
+  // proto_h mode.
+  //
+  // This gives us three flavors of functions:
+  //
+  //  1. Functions on the message not used by the internal dependent base
+  //     class: in .proto.h mode, only some functions are defined on the
+  //     message class; others are defined on the dependent base class.
+  //     These are guarded and can be out-lined. These are generated by
+  //     GenerateInlineMethods, and include has_* bit functions in
+  //     non-proto_h mode.
+  //
+  //  2. Functions on the internal dependent base class: these functions
+  //     are dependent on a template parameter, so they always need to
+  //     remain in the header.
+  //
+  //  3. Functions on the message that are used by the dependent base: the
+  //     dependent base class down casts itself to the message
+  //     implementation class to access these functions (the has_* bit
+  //     manipulation functions). Unlike #1, these functions must
+  //     unconditionally remain in the header. These are emitted by
+  //     GenerateDependentInlineMethods, even though they are not actually
+  //     dependent.
+
+  printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+  // Generate class inline methods.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    message_generators_[i]->GenerateInlineMethods(printer,
+                                                  /* is_inline = */ true);
+  }
+  printer->Print("#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    // Methods of the dependent base class must always be inline in the header.
+    message_generators_[i]->GenerateDependentInlineMethods(printer);
+  }
+}
+
+void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
+    io::Printer* printer) {
+  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+  if (HasEnumDefinitions(file_)) {
+    // The SWIG conditional is to avoid a null-pointer dereference
+    // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
+    //   namespace X { void Y<Z::W>(); }
+    // which appears in GetEnumDescriptor() specializations.
+    printer->Print(
+        "\n"
+        "#ifndef SWIG\n"
+        "namespace google {\nnamespace protobuf {\n"
+        "\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    printer->Print(
+        "\n"
+        "}  // namespace protobuf\n}  // namespace google\n"
+        "#endif  // SWIG\n");
+  }
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 4e4d8b6..5dcf692 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -36,6 +36,9 @@
 #define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
@@ -62,14 +65,23 @@
 class FileGenerator {
  public:
   // See generator.cc for the meaning of dllexport_decl.
-  explicit FileGenerator(const FileDescriptor* file,
-                         const Options& options);
+  FileGenerator(const FileDescriptor* file, const Options& options);
   ~FileGenerator();
 
-  void GenerateHeader(io::Printer* printer);
+  // info_path, if non-empty, should be the path (relative to printer's output)
+  // to the metadata file describing this proto header.
+  void GenerateProtoHeader(io::Printer* printer,
+                           const string& info_path);
+  // info_path, if non-empty, should be the path (relative to printer's output)
+  // to the metadata file describing this PB header.
+  void GeneratePBHeader(io::Printer* printer,
+                        const string& info_path);
   void GenerateSource(io::Printer* printer);
 
  private:
+  // Internal type used by GenerateForwardDeclarations (defined in file.cc).
+  class ForwardDeclarations;
+
   // Generate the BuildDescriptors() procedure, which builds all descriptors
   // for types defined in the file.
   void GenerateBuildDescriptors(io::Printer* printer);
@@ -77,16 +89,69 @@
   void GenerateNamespaceOpeners(io::Printer* printer);
   void GenerateNamespaceClosers(io::Printer* printer);
 
-  const FileDescriptor* file_;
+  // For other imports, generates their forward-declarations.
+  void GenerateForwardDeclarations(io::Printer* printer);
 
-  scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
-  scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
-  scoped_array<scoped_ptr<ServiceGenerator> > service_generators_;
-  scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+  // Internal helper used by GenerateForwardDeclarations: fills 'decls'
+  // with all necessary forward-declarations for this file and its
+  // transient depednencies.
+  void FillForwardDeclarations(ForwardDeclarations* decls);
+
+  // Generates top or bottom of a header file.
+  void GenerateTopHeaderGuard(io::Printer* printer,
+                              const string& filename_identifier);
+  void GenerateBottomHeaderGuard(io::Printer* printer,
+                                 const string& filename_identifier);
+
+  // Generates #include directives.
+  void GenerateLibraryIncludes(io::Printer* printer);
+  void GenerateDependencyIncludes(io::Printer* printer);
+
+  // Generate a pragma to pull in metadata using the given info_path (if
+  // non-empty). info_path should be relative to printer's output.
+  void GenerateMetadataPragma(io::Printer* printer, const string& info_path);
+
+  // Generates a couple of different pieces before definitions:
+  void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
+
+  // Generates types for classes.
+  void GenerateMessageDefinitions(io::Printer* printer);
+
+  // Generates forward-declarations for just this file's classes. This is
+  // used for .pb.h headers, but not in proto_h mode.
+  void GenerateMessageForwardDeclarations(io::Printer* printer);
+
+  // Fills in types for forward declarations. This is used internally, and
+  // also by other FileGenerators to determine imports' declarations.
+  void FillMessageForwardDeclarations(ForwardDeclarations* decls);
+  void FillMessageDefinitions(ForwardDeclarations* decls);
+
+  // Generates enum definitions.
+  void GenerateEnumForwardDeclarations(io::Printer* printer);
+  void FillEnumForwardDeclarations(ForwardDeclarations* decls);
+  void GenerateEnumDefinitions(io::Printer* printer);
+
+  // Generates generic service definitions.
+  void GenerateServiceDefinitions(io::Printer* printer);
+
+  // Generates extension identifiers.
+  void GenerateExtensionIdentifiers(io::Printer* printer);
+
+  // Generates inline function defintions.
+  void GenerateInlineFunctionDefinitions(io::Printer* printer);
+
+  void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
+
+  const FileDescriptor* file_;
+  const Options options_;
+
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > service_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
 
   // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
   vector<string> package_parts_;
-  const Options options_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 75d558e..31d189c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -36,6 +36,9 @@
 
 #include <vector>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <utility>
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
@@ -79,6 +82,7 @@
   //   }
   // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
   // __declspec(dllimport) depending on what is being compiled.
+  //
   Options file_options;
 
   for (int i = 0; i < options.size(); i++) {
@@ -86,6 +90,14 @@
       file_options.dllexport_decl = options[i].second;
     } else if (options[i].first == "safe_boundary_check") {
       file_options.safe_boundary_check = true;
+    } else if (options[i].first == "annotate_headers") {
+      file_options.annotate_headers = true;
+    } else if (options[i].first == "annotation_pragma_name") {
+      file_options.annotation_pragma_name = options[i].second;
+    } else if (options[i].first == "annotation_guard_name") {
+      file_options.annotation_guard_name = options[i].second;
+    } else if (options[i].first == "lite") {
+      file_options.enforce_lite = true;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
@@ -96,21 +108,52 @@
 
 
   string basename = StripProto(file->name());
-  basename.append(".pb");
 
   FileGenerator file_generator(file, file_options);
 
-  // Generate header.
+  // Generate header(s).
+  if (file_options.proto_h) {
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+        generator_context->Open(basename + ".proto.h"));
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    string info_path = basename + ".proto.h.meta";
+    io::Printer printer(output.get(), '$', file_options.annotate_headers
+                                               ? &annotation_collector
+                                               : NULL);
+    file_generator.GenerateProtoHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
+  }
+
+  basename.append(".pb");
   {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".h"));
-    io::Printer printer(output.get(), '$');
-    file_generator.GenerateHeader(&printer);
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    string info_path = basename + ".h.meta";
+    io::Printer printer(output.get(), '$', file_options.annotate_headers
+                                               ? &annotation_collector
+                                               : NULL);
+    file_generator.GeneratePBHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
   }
 
   // Generate cc file.
   {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".cc"));
     io::Printer printer(output.get(), '$');
     file_generator.GenerateSource(&printer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index b7a47ac..2ad4d36 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -39,6 +39,7 @@
 
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
@@ -51,6 +52,10 @@
 
 namespace {
 
+static const char kAnyMessageName[] = "Any";
+static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+static const char kGoogleProtobufPrefix[] = "google/protobuf/";
+
 string DotsToUnderscores(const string& name) {
   return StringReplace(name, ".", "_", true);
 }
@@ -60,16 +65,18 @@
 }
 
 const char* const kKeywordList[] = {
-  "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
-  "catch", "char", "class", "compl", "const", "const_cast", "continue",
-  "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
-  "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
-  "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
+  "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
+  "bool", "break", "case", "catch", "char", "class", "compl", "const",
+  "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
+  "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern",
+  "false", "float", "for", "friend", "goto", "if", "inline", "int", "long",
+  "mutable", "namespace", "new", "noexcept", "not", "not_eq", "NULL",
   "operator", "or", "or_eq", "private", "protected", "public", "register",
   "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
-  "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
-  "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
-  "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
+  "static_assert", "static_cast", "struct", "switch", "template", "this",
+  "thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
+  "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
+  "while", "xor", "xor_eq"
 };
 
 hash_set<string> MakeKeywordsMap() {
@@ -161,9 +168,22 @@
 }
 
 
-string SuperClassName(const Descriptor* descriptor) {
-  return HasDescriptorMethods(descriptor->file()) ?
-      "::google::protobuf::Message" : "::google::protobuf::MessageLite";
+string DependentBaseClassTemplateName(const Descriptor* descriptor) {
+  return ClassName(descriptor, false) + "_InternalBase";
+}
+
+string SuperClassName(const Descriptor* descriptor, const Options& options) {
+  return HasDescriptorMethods(descriptor->file(), options)
+             ? "::google::protobuf::Message"
+             : "::google::protobuf::MessageLite";
+}
+
+string DependentBaseDownCast() {
+  return "reinterpret_cast<T*>(this)->";
+}
+
+string DependentBaseConstDownCast() {
+  return "reinterpret_cast<const T*>(this)->";
 }
 
 string FieldName(const FieldDescriptor* field) {
@@ -175,6 +195,14 @@
   return result;
 }
 
+string EnumValueName(const EnumValueDescriptor* enum_value) {
+  string result = enum_value->name();
+  if (kKeywords.count(result) > 0) {
+    result.append("_");
+  }
+  return result;
+}
+
 string FieldConstantName(const FieldDescriptor *field) {
   string field_name = UnderscoresToCamelCase(field->name(), true);
   string result = "k" + field_name + "FieldNumber";
@@ -191,6 +219,60 @@
   return result;
 }
 
+bool IsFieldDependent(const FieldDescriptor* field) {
+  if (field->containing_oneof() != NULL &&
+      field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+    return true;
+  }
+  if (field->is_map()) {
+    const Descriptor* map_descriptor = field->message_type();
+    for (int i = 0; i < map_descriptor->field_count(); i++) {
+      if (IsFieldDependent(map_descriptor->field(i))) {
+        return true;
+      }
+    }
+    return false;
+  }
+  if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return false;
+  }
+  if (field->containing_oneof() != NULL) {
+    // Oneof fields will always be dependent.
+    //
+    // This is a unique case for field codegen. Field generators are
+    // responsible for generating all the field-specific accessor
+    // functions, except for the clear_*() function; instead, field
+    // generators produce inline clearing code.
+    //
+    // For non-oneof fields, the Message class uses the inline clearing
+    // code to define the field's clear_*() function, as well as in the
+    // destructor. For oneof fields, the Message class generates a much
+    // more complicated clear_*() function, which clears only the oneof
+    // member that is set, in addition to clearing methods for each of the
+    // oneof members individually.
+    //
+    // Since oneofs do not have their own generator class, the Message code
+    // generation logic would be significantly complicated in order to
+    // split dependent and non-dependent manipulation logic based on
+    // whether the oneof truly needs to be dependent; so, for oneof fields,
+    // we just assume it (and its constituents) should be manipulated by a
+    // dependent base class function.
+    //
+    // This is less precise than how dependent message-typed fields are
+    // handled, but the cost is limited to only the generated code for the
+    // oneof field, which seems like an acceptable tradeoff.
+    return true;
+  }
+  if (field->file() == field->message_type()->file()) {
+    return false;
+  }
+  return true;
+}
+
+string DependentTypeName(const FieldDescriptor* field) {
+  return "InternalBase_" + field->name() + "_T";
+}
+
 string FieldMessageTypeName(const FieldDescriptor* field) {
   // Note:  The Google-internal version of Protocol Buffers uses this function
   //   as a hook point for hacks to support legacy code.
@@ -351,9 +433,7 @@
     } else {
       // Not alphanumeric.  To avoid any possibility of name conflicts we
       // use the hex code for the character.
-      result.push_back('_');
-      char buffer[kFastToBufferSize];
-      result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
+      StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
     }
   }
   return result;
@@ -407,8 +487,9 @@
   return function_name;
 }
 
-bool StaticInitializersForced(const FileDescriptor* file) {
-  if (HasDescriptorMethods(file) || file->extension_count() > 0) {
+bool StaticInitializersForced(const FileDescriptor* file,
+                              const Options& options) {
+  if (HasDescriptorMethods(file, options) || file->extension_count() > 0) {
     return true;
   }
   for (int i = 0; i < file->message_type_count(); ++i) {
@@ -420,10 +501,10 @@
 }
 
 void PrintHandlingOptionalStaticInitializers(
-    const FileDescriptor* file, io::Printer* printer,
+    const FileDescriptor* file, const Options& options, io::Printer* printer,
     const char* with_static_init, const char* without_static_init,
-    const char* var1, const string& val1,
-    const char* var2, const string& val2) {
+    const char* var1, const string& val1, const char* var2,
+    const string& val2) {
   map<string, string> vars;
   if (var1) {
     vars[var1] = val1;
@@ -432,14 +513,16 @@
     vars[var2] = val2;
   }
   PrintHandlingOptionalStaticInitializers(
-      vars, file, printer, with_static_init, without_static_init);
+      vars, file, options, printer, with_static_init, without_static_init);
 }
 
-void PrintHandlingOptionalStaticInitializers(
-    const map<string, string>& vars, const FileDescriptor* file,
-    io::Printer* printer, const char* with_static_init,
-    const char* without_static_init) {
-  if (StaticInitializersForced(file)) {
+void PrintHandlingOptionalStaticInitializers(const map<string, string>& vars,
+                                             const FileDescriptor* file,
+                                             const Options& options,
+                                             io::Printer* printer,
+                                             const char* with_static_init,
+                                             const char* without_static_init) {
+  if (StaticInitializersForced(file, options)) {
     printer->Print(vars, with_static_init);
   } else {
     printer->Print(vars, (string(
@@ -452,6 +535,25 @@
 }
 
 
+static bool HasMapFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (descriptor->field(i)->is_map()) {
+      return true;
+    }
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    if (HasMapFields(descriptor->nested_type(i))) return true;
+  }
+  return false;
+}
+
+bool HasMapFields(const FileDescriptor* file) {
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    if (HasMapFields(file->message_type(i))) return true;
+  }
+  return false;
+}
+
 static bool HasEnumDefinitions(const Descriptor* message_type) {
   if (message_type->enum_type_count() > 0) return true;
   for (int i = 0; i < message_type->nested_type_count(); ++i) {
@@ -488,6 +590,114 @@
   return false;
 }
 
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
+  GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+  // Open-source protobuf release only supports STRING ctype.
+  return FieldOptions::STRING;
+
+}
+
+bool IsAnyMessage(const FileDescriptor* descriptor) {
+  return descriptor->name() == kAnyProtoFile;
+}
+
+bool IsAnyMessage(const Descriptor* descriptor) {
+  return descriptor->name() == kAnyMessageName &&
+         descriptor->file()->name() == kAnyProtoFile;
+}
+
+bool IsWellKnownMessage(const FileDescriptor* descriptor) {
+  return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix);
+}
+
+enum Utf8CheckMode {
+  STRICT = 0,  // Parsing will fail if non UTF-8 data is in string fields.
+  VERIFY = 1,  // Only log an error but parsing will succeed.
+  NONE = 2,  // No UTF-8 check.
+};
+
+// Which level of UTF-8 enforcemant is placed on this file.
+static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
+                                      const Options& options) {
+  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    return STRICT;
+  } else if (GetOptimizeFor(field->file(), options) !=
+             FileOptions::LITE_RUNTIME) {
+    return VERIFY;
+  } else {
+    return NONE;
+  }
+}
+
+static void GenerateUtf8CheckCode(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const map<string, string>& variables,
+                                  const char* parameters,
+                                  const char* strict_function,
+                                  const char* verify_function,
+                                  io::Printer* printer) {
+  switch (GetUtf8CheckMode(field, options)) {
+    case STRICT: {
+      if (for_parse) {
+        printer->Print("DO_(");
+      }
+      printer->Print(
+          "::google::protobuf::internal::WireFormatLite::$function$(\n",
+          "function", strict_function);
+      printer->Indent();
+      printer->Print(variables, parameters);
+      if (for_parse) {
+        printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n");
+      } else {
+        printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n");
+      }
+      printer->Print("\"$full_name$\")", "full_name", field->full_name());
+      if (for_parse) {
+        printer->Print(")");
+      }
+      printer->Print(";\n");
+      printer->Outdent();
+      break;
+    }
+    case VERIFY: {
+      printer->Print(
+          "::google::protobuf::internal::WireFormat::$function$(\n",
+          "function", verify_function);
+      printer->Indent();
+      printer->Print(variables, parameters);
+      if (for_parse) {
+        printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n");
+      } else {
+        printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n");
+      }
+      printer->Print("\"$full_name$\");\n", "full_name", field->full_name());
+      printer->Outdent();
+      break;
+    }
+    case NONE:
+      break;
+  }
+}
+
+void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
+                                    const Options& options, bool for_parse,
+                                    const map<string, string>& variables,
+                                    const char* parameters,
+                                    io::Printer* printer) {
+  GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
+                        "VerifyUtf8String", "VerifyUTF8StringNamedField",
+                        printer);
+}
+
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const map<string, string>& variables,
+                                  const char* parameters,
+                                  io::Printer* printer) {
+  GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
+                        "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer);
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 5d30240..018acfc 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -37,8 +37,9 @@
 
 #include <map>
 #include <string>
-#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
 
 namespace google {
 namespace protobuf {
@@ -66,7 +67,18 @@
 string ClassName(const Descriptor* descriptor, bool qualified);
 string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
 
-string SuperClassName(const Descriptor* descriptor);
+// Name of the CRTP class template (for use with proto_h).
+// This is a class name, like "ProtoName_InternalBase".
+string DependentBaseClassTemplateName(const Descriptor* descriptor);
+
+// Name of the base class: either the dependent base class (for use with
+// proto_h) or google::protobuf::Message.
+string SuperClassName(const Descriptor* descriptor, const Options& options);
+
+// Returns a string that down-casts from the dependent base class to the
+// derived class.
+string DependentBaseDownCast();
+string DependentBaseConstDownCast();
 
 // Get the (unqualified) name that should be used for this field in C++ code.
 // The name is coerced to lower-case to emulate proto1 behavior.  People
@@ -74,6 +86,9 @@
 // anyway, so normally this just returns field->name().
 string FieldName(const FieldDescriptor* field);
 
+// Get the sanitized name that should be used for the given enum in C++ code.
+string EnumValueName(const EnumValueDescriptor* enum_value);
+
 // Get the unqualified name that should be used for a field's field
 // number constant.
 string FieldConstantName(const FieldDescriptor *field);
@@ -85,12 +100,26 @@
     field->extension_scope() : field->containing_type();
 }
 
+// Returns true if the given 'field_descriptor' has a message type that is
+// a dependency of the file where the field is defined (i.e., the field
+// type is defined in a different file than the message holding the field).
+//
+// This only applies to Message-typed fields. Enum-typed fields may refer
+// to an enum in a dependency; however, enums are specified and
+// forward-declared with an enum-base, so the definition is not required to
+// manipulate the field value.
+bool IsFieldDependent(const FieldDescriptor* field_descriptor);
+
+// Returns the name that should be used for forcing dependent lookup from a
+// dependent base class.
+string DependentTypeName(const FieldDescriptor* field);
+
 // Returns the fully-qualified type name field->message_type().  Usually this
 // is just ClassName(field->message_type(), true);
 string FieldMessageTypeName(const FieldDescriptor* field);
 
 // Strips ".proto" or ".protodevel" from the end of a filename.
-string StripProto(const string& filename);
+LIBPROTOC_EXPORT string StripProto(const string& filename);
 
 // Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
 // Note:  non-built-in type names will be qualified, meaning they will start
@@ -135,69 +164,140 @@
                         const FieldDescriptor* field,
                         const string& prefix);
 
-// Do message classes in this file use UnknownFieldSet?
-// Otherwise, messages will store unknown fields in a string
-inline bool UseUnknownFieldSet(const FileDescriptor* file) {
-  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
+// Returns true if unknown fields are preseved after parsing.
+inline bool PreserveUnknownFields(const Descriptor* message) {
+  return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
 }
 
+// Returns the optimize mode for <file>, respecting <options.enforce_lite>.
+::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
+    const FileDescriptor* file, const Options& options);
+
+// If PreserveUnknownFields() is true, determines whether unknown
+// fields will be stored in an UnknownFieldSet or a string.
+// If PreserveUnknownFields() is false, this method will not be
+// used.
+inline bool UseUnknownFieldSet(const FileDescriptor* file,
+                               const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
+}
+
+
+// Does the file have any map fields, necessitating the file to include
+// map_field_inl.h and map.h.
+bool HasMapFields(const FileDescriptor* file);
 
 // Does this file have any enum type definitions?
 bool HasEnumDefinitions(const FileDescriptor* file);
 
 // Does this file have generated parsing, serialization, and other
 // standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const FileDescriptor* file) {
-  return file->options().optimize_for() != FileOptions::CODE_SIZE;
+inline bool HasGeneratedMethods(const FileDescriptor* file,
+                                const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE;
 }
 
 // Do message classes in this file have descriptor and reflection methods?
-inline bool HasDescriptorMethods(const FileDescriptor* file) {
-  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const FileDescriptor* file,
+                                 const Options& options) {
+  return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
 }
 
 // Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor* file) {
+inline bool HasGenericServices(const FileDescriptor* file,
+                               const Options& options) {
   return file->service_count() > 0 &&
-         file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
+         GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME &&
          file->options().cc_generic_services();
 }
 
-// Should string fields in this file verify that their contents are UTF-8?
-inline bool HasUtf8Verification(const FileDescriptor* file) {
-  return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
-}
-
 // Should we generate a separate, super-optimized code path for serializing to
 // flat arrays?  We don't do this in Lite mode because we'd rather reduce code
 // size.
-inline bool HasFastArraySerialization(const FileDescriptor* file) {
-  return file->options().optimize_for() == FileOptions::SPEED;
+inline bool HasFastArraySerialization(const FileDescriptor* file,
+                                      const Options& options) {
+  return GetOptimizeFor(file, options) == FileOptions::SPEED;
 }
 
 // Returns whether we have to generate code with static initializers.
-bool StaticInitializersForced(const FileDescriptor* file);
+bool StaticInitializersForced(const FileDescriptor* file,
+                              const Options& options);
 
 // Prints 'with_static_init' if static initializers have to be used for the
 // provided file. Otherwise emits both 'with_static_init' and
 // 'without_static_init' using #ifdef.
 void PrintHandlingOptionalStaticInitializers(
-    const FileDescriptor* file, io::Printer* printer,
+    const FileDescriptor* file, const Options& options, io::Printer* printer,
     const char* with_static_init, const char* without_static_init,
-    const char* var1 = NULL, const string& val1 = "",
-    const char* var2 = NULL, const string& val2 = "");
+    const char* var1 = NULL, const string& val1 = "", const char* var2 = NULL,
+    const string& val2 = "");
 
-void PrintHandlingOptionalStaticInitializers(
-    const map<string, string>& vars, const FileDescriptor* file,
-    io::Printer* printer, const char* with_static_init,
-    const char* without_static_init);
+void PrintHandlingOptionalStaticInitializers(const map<string, string>& vars,
+                                             const FileDescriptor* file,
+                                             const Options& options,
+                                             io::Printer* printer,
+                                             const char* with_static_init,
+                                             const char* without_static_init);
 
 
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
 // Returns true if the field's CPPTYPE is string or message.
 bool IsStringOrMessage(const FieldDescriptor* field);
 
+// For a string field, returns the effective ctype.  If the actual ctype is
+// not supported, returns the default of STRING.
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field);
+
 string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
 
+inline bool HasFieldPresence(const FileDescriptor* file) {
+  return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// Returns true if 'enum' semantics are such that unknown values are preserved
+// in the enum field itself, rather than going to the UnknownFieldSet.
+inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool SupportsArenas(const FileDescriptor* file) {
+  return file->options().cc_enable_arenas();
+}
+
+inline bool SupportsArenas(const Descriptor* desc) {
+  return SupportsArenas(desc->file());
+}
+
+inline bool SupportsArenas(const FieldDescriptor* field) {
+  return SupportsArenas(field->file());
+}
+
+bool IsAnyMessage(const FileDescriptor* descriptor);
+bool IsAnyMessage(const Descriptor* descriptor);
+
+bool IsWellKnownMessage(const FileDescriptor* descriptor);
+
+void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
+                                    const Options& options, bool for_parse,
+                                    const map<string, string>& variables,
+                                    const char* parameters,
+                                    io::Printer* printer);
+
+void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
+                                  const Options& options, bool for_parse,
+                                  const map<string, string>& variables,
+                                  const char* parameters, io::Printer* printer);
+
+inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor(
+    const FileDescriptor* file, const Options& options) {
+  return options.enforce_lite
+      ? FileOptions::LITE_RUNTIME
+      : file->options().optimize_for();
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
new file mode 100644
index 0000000..f585c31
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -0,0 +1,411 @@
+// 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.
+
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+bool IsProto3Field(const FieldDescriptor* field_descriptor) {
+  const FileDescriptor* file_descriptor = field_descriptor->file();
+  return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         map<string, string>* variables,
+                         const Options& options) {
+  SetCommonFieldVariables(descriptor, variables, options);
+  (*variables)["type"] = FieldMessageTypeName(descriptor);
+  (*variables)["stream_writer"] =
+      (*variables)["declared_type"] +
+      (HasFastArraySerialization(descriptor->message_type()->file(), options)
+           ? "MaybeToArray"
+           : "");
+  (*variables)["full_name"] = descriptor->full_name();
+
+  const FieldDescriptor* key =
+      descriptor->message_type()->FindFieldByName("key");
+  const FieldDescriptor* val =
+      descriptor->message_type()->FindFieldByName("value");
+  (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
+  switch (val->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      (*variables)["val_cpp"] = FieldMessageTypeName(val);
+      (*variables)["wrapper"] = "EntryWrapper";
+      break;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
+      (*variables)["wrapper"] = "EnumEntryWrapper";
+      break;
+    default:
+      (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
+      (*variables)["wrapper"] = "EntryWrapper";
+  }
+  (*variables)["key_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
+      ToUpper(DeclaredTypeMethodName(key->type()));
+  (*variables)["val_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
+      ToUpper(DeclaredTypeMethodName(val->type()));
+  (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+
+  if (HasDescriptorMethods(descriptor->file(), options)) {
+    (*variables)["lite"] = "";
+  } else {
+    (*variables)["lite"] = "Lite";
+  }
+
+  if (!IsProto3Field(descriptor) &&
+      val->type() == FieldDescriptor::TYPE_ENUM) {
+    const EnumValueDescriptor* default_value = val->default_value_enum();
+    (*variables)["default_enum_value"] = Int32ToString(default_value->number());
+  } else {
+    (*variables)["default_enum_value"] = "0";
+  }
+}
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Options& options)
+    : FieldGenerator(options),
+      descriptor_(descriptor),
+      dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
+  SetMessageVariables(descriptor, &variables_, options);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+      "typedef ::google::protobuf::internal::MapEntryLite<\n"
+      "    $key_cpp$, $val_cpp$,\n"
+      "    $key_wire_type$,\n"
+      "    $val_wire_type$,\n"
+      "    $default_enum_value$ >\n"
+      "    $map_classname$;\n"
+      "::google::protobuf::internal::MapField$lite$<\n"
+      "    $key_cpp$, $val_cpp$,\n"
+      "    $key_wire_type$,\n"
+      "    $val_wire_type$,\n"
+      "    $default_enum_value$ > $name$_;\n");
+}
+
+void MapFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+      "    $name$() const;\n"
+      "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+      "    mutable_$name$();\n");
+}
+
+void MapFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+      "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+      "$classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_map:$full_name$)\n"
+      "  return $name$_.GetMap();\n"
+      "}\n"
+      "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+      "$classname$::mutable_$name$() {\n"
+      "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
+      "  return $name$_.MutableMap();\n"
+      "}\n");
+}
+
+void MapFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  printer->Print(variables, "$this_message$$name$_.Clear();\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
+    printer->Print(variables_,
+        "$name$_.SetAssignDescriptorCallback(\n"
+        "    protobuf_AssignDescriptorsOnce);\n"
+        "$name$_.SetEntryDescriptor(\n"
+        "    &$type$_descriptor_);\n");
+  }
+}
+
+void MapFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+  const FieldDescriptor* value_field =
+      descriptor_->message_type()->FindFieldByName("value");
+  printer->Print(variables_,
+      "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
+
+  if (IsProto3Field(descriptor_) ||
+      value_field->type() != FieldDescriptor::TYPE_ENUM) {
+    printer->Print(variables_,
+        "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+        "    input, entry.get()));\n");
+    switch (value_field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        printer->Print(variables_,
+            "(*mutable_$name$())[entry->key()].Swap("
+            "entry->mutable_value());\n");
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        printer->Print(variables_,
+            "(*mutable_$name$())[entry->key()] =\n"
+            "    static_cast< $val_cpp$ >(*entry->mutable_value());\n");
+        break;
+      default:
+        printer->Print(variables_,
+            "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
+        break;
+    }
+  } else {
+    printer->Print(variables_,
+        "{\n"
+        "  ::std::string data;\n"
+        "  DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
+        "  DO_(entry->ParseFromString(data));\n"
+        "  if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
+        "    (*mutable_$name$())[entry->key()] =\n"
+        "        static_cast< $val_cpp$ >(*entry->mutable_value());\n"
+        "  } else {\n");
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      printer->Print(variables_,
+          "    mutable_unknown_fields()"
+          "->AddLengthDelimited($number$, data);\n");
+    } else {
+      printer->Print(variables_,
+          "    unknown_fields_stream.WriteVarint32($tag$);\n"
+          "    unknown_fields_stream.WriteVarint32(data.size());\n"
+          "    unknown_fields_stream.WriteString(data);\n");
+    }
+
+
+    printer->Print(variables_,
+        "  }\n"
+        "}\n");
+  }
+
+  const FieldDescriptor* key_field =
+      descriptor_->message_type()->FindFieldByName("key");
+  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        key_field, options_, true, variables_,
+        "entry->key().data(), entry->key().length(),\n", printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(value_field, options_, true, variables_,
+                                   "entry->mutable_value()->data(),\n"
+                                   "entry->mutable_value()->length(),\n",
+                                   printer);
+  }
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "if (entry->GetArena() != NULL) entry.release();\n");
+  }
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+  printer->Print(variables_,
+      "{\n"
+      "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
+      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+      "    ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
+      "        $number$, *entry, output);\n");
+
+  printer->Indent();
+  printer->Indent();
+
+  const FieldDescriptor* key_field =
+      descriptor_->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value_field =
+      descriptor_->message_type()->FindFieldByName("value");
+  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(key_field, options_, false, variables_,
+                                   "it->first.data(), it->first.length(),\n",
+                                   printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(value_field, options_, false, variables_,
+                                   "it->second.data(), it->second.length(),\n",
+                                   printer);
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
+  printer->Print(variables_,
+      "{\n"
+      "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
+      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+      "    target = ::google::protobuf::internal::WireFormatLite::\n"
+      "        Write$declared_type$NoVirtualToArray(\n"
+      "            $number$, *entry, target);\n");
+
+  printer->Indent();
+  printer->Indent();
+
+  const FieldDescriptor* key_field =
+      descriptor_->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value_field =
+      descriptor_->message_type()->FindFieldByName("value");
+  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(key_field, options_, false, variables_,
+                                   "it->first.data(), it->first.length(),\n",
+                                   printer);
+  }
+  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(value_field, options_, false, variables_,
+                                   "it->second.data(), it->second.length(),\n",
+                                   printer);
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
+}
+
+void MapFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+  printer->Print(variables_,
+      "total_size += $tag_size$ * this->$name$_size();\n"
+      "{\n"
+      "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
+      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+      "    total_size += ::google::protobuf::internal::WireFormatLite::\n"
+      "        $declared_type$SizeNoVirtual(*entry);\n"
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
+}
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
new file mode 100644
index 0000000..087dcde
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/cpp_message_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+  MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+  ~MapFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateAccessorDeclarations(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
+  void GenerateClearingCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSwappingCode(io::Printer* printer) const;
+  void GenerateConstructorCode(io::Printer* printer) const;
+  void GenerateMergeFromCodedStream(io::Printer* printer) const;
+  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+  void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
+  void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index f91a1a6..14a9a99 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -36,7 +36,9 @@
 #include <google/protobuf/stubs/hash.h>
 #include <map>
 #include <memory>
-#include <set>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <utility>
 #include <vector>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
@@ -61,10 +63,15 @@
 
 namespace {
 
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
-  // Print the field's proto-syntax definition as a comment.  We don't want to
-  // print group bodies so we cut off after the first line.
-  string def = field->DebugString();
+template <class T>
+void PrintFieldComment(io::Printer* printer, const T* field) {
+  // Print the field's (or oneof's) proto-syntax definition as a comment.
+  // We don't want to print group bodies so we cut off after the first
+  // line.
+  DebugStringOptions options;
+  options.elide_group_body = true;
+  options.elide_oneof_body = true;
+  string def = field->DebugStringWithOptions(options);
   printer->Print("// $def$\n",
     "def", def.substr(0, def.find_first_of('\n')));
 }
@@ -84,8 +91,8 @@
   for (int i = 0; i < descriptor->field_count(); i++) {
     fields[i] = descriptor->field(i);
   }
-  sort(fields, fields + descriptor->field_count(),
-       FieldOrderingByNumber());
+  std::sort(fields, fields + descriptor->field_count(),
+            FieldOrderingByNumber());
   return fields;
 }
 
@@ -99,8 +106,8 @@
 
 // Returns true if the "required" restriction check should be ignored for the
 // given field.
-inline static bool ShouldIgnoreRequiredFieldCheck(
-    const FieldDescriptor* field) {
+inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
+                                                  const Options& options) {
   return false;
 }
 
@@ -109,9 +116,8 @@
 //
 // already_seen is used to avoid checking the same type multiple times
 // (and also to protect against recursion).
-static bool HasRequiredFields(
-    const Descriptor* type,
-    hash_set<const Descriptor*>* already_seen) {
+static bool HasRequiredFields(const Descriptor* type, const Options& options,
+                              hash_set<const Descriptor*>* already_seen) {
   if (already_seen->count(type) > 0) {
     // Since the first occurrence of a required field causes the whole
     // function to return true, we can assume that if the type is already
@@ -131,8 +137,8 @@
       return true;
     }
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
-        !ShouldIgnoreRequiredFieldCheck(field)) {
-      if (HasRequiredFields(field->message_type(), already_seen)) {
+        !ShouldIgnoreRequiredFieldCheck(field, options)) {
+      if (HasRequiredFields(field->message_type(), options, already_seen)) {
         return true;
       }
     }
@@ -141,9 +147,9 @@
   return false;
 }
 
-static bool HasRequiredFields(const Descriptor* type) {
+static bool HasRequiredFields(const Descriptor* type, const Options& options) {
   hash_set<const Descriptor*> already_seen;
-  return HasRequiredFields(type, &already_seen);
+  return HasRequiredFields(type, options, &already_seen);
 }
 
 // This returns an estimate of the compiler's alignment for the field.  This
@@ -250,7 +256,7 @@
   // Sort by preferred location to keep fields as close to their original
   // location as possible.  Using stable_sort ensures that the output is
   // consistent across runs.
-  stable_sort(aligned_to_4.begin(), aligned_to_4.end());
+  std::stable_sort(aligned_to_4.begin(), aligned_to_4.end());
 
   // Now group fields aligned to 4 bytes (or the 4-field groups created above)
   // into pairs, and treat those like a single field aligned to 8 bytes.
@@ -266,7 +272,7 @@
     aligned_to_8.push_back(field_group);
   }
   // Sort by preferred location.
-  stable_sort(aligned_to_8.begin(), aligned_to_8.end());
+  std::stable_sort(aligned_to_8.begin(), aligned_to_8.end());
 
   // Now pull out all the FieldDescriptors in order.
   fields->clear();
@@ -281,8 +287,92 @@
   return field->message_type()->full_name();
 }
 
+// Emits an if-statement with a condition that evaluates to true if |field| is
+// considered non-default (will be sent over the wire), for message types
+// without true field presence. Should only be called if
+// !HasFieldPresence(message_descriptor).
+bool EmitFieldNonDefaultCondition(io::Printer* printer,
+                                  const string& prefix,
+                                  const FieldDescriptor* field) {
+  // Merge and serialize semantics: primitive fields are merged/serialized only
+  // if non-zero (numeric) or non-empty (string).
+  if (!field->is_repeated() && !field->containing_oneof()) {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+      printer->Print(
+          "if ($prefix$$name$().size() > 0) {\n",
+          "prefix", prefix,
+          "name", FieldName(field));
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Message fields still have has_$name$() methods.
+      printer->Print(
+          "if ($prefix$has_$name$()) {\n",
+          "prefix", prefix,
+          "name", FieldName(field));
+    } else {
+      printer->Print(
+          "if ($prefix$$name$() != 0) {\n",
+          "prefix", prefix,
+          "name", FieldName(field));
+    }
+    printer->Indent();
+    return true;
+  } else if (field->containing_oneof()) {
+    printer->Print(
+        "if (has_$name$()) {\n",
+        "name", FieldName(field));
+    printer->Indent();
+    return true;
+  }
+  return false;
 }
 
+// Does the given field have a has_$name$() method?
+bool HasHasMethod(const FieldDescriptor* field) {
+  if (HasFieldPresence(field->file())) {
+    // In proto1/proto2, every field has a has_$name$() method.
+    return true;
+  }
+  // For message types without true field presence, only fields with a message
+  // type have a has_$name$() method.
+  return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
+}
+
+// Collects map entry message type information.
+void CollectMapInfo(const Descriptor* descriptor,
+                    map<string, string>* variables) {
+  GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+  const FieldDescriptor* key = descriptor->FindFieldByName("key");
+  const FieldDescriptor* val = descriptor->FindFieldByName("value");
+  (*variables)["key"] = PrimitiveTypeName(key->cpp_type());
+  switch (val->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      (*variables)["val"] = FieldMessageTypeName(val);
+      break;
+    case FieldDescriptor::CPPTYPE_ENUM:
+      (*variables)["val"] = ClassName(val->enum_type(), true);
+      break;
+    default:
+      (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
+  }
+  (*variables)["key_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
+      ToUpper(DeclaredTypeMethodName(key->type()));
+  (*variables)["val_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
+      ToUpper(DeclaredTypeMethodName(val->type()));
+}
+
+// Does the given field have a private (internal helper only) has_$name$()
+// method?
+bool HasPrivateHasMethod(const FieldDescriptor* field) {
+  // Only for oneofs in message types with no field presence. has_$name$(),
+  // based on the oneof case, is still useful internally for generated code.
+  return (!HasFieldPresence(field->file()) &&
+          field->containing_oneof() != NULL);
+}
+
+}  // anonymous namespace
+
 // ===================================================================
 
 MessageGenerator::MessageGenerator(const Descriptor* descriptor,
@@ -291,12 +381,13 @@
       classname_(ClassName(descriptor, false)),
       options_(options),
       field_generators_(descriptor, options),
-      nested_generators_(new scoped_ptr<
+      nested_generators_(new google::protobuf::scoped_ptr<
           MessageGenerator>[descriptor->nested_type_count()]),
       enum_generators_(
-          new scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
-      extension_generators_(new scoped_ptr<
-          ExtensionGenerator>[descriptor->extension_count()]) {
+          new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
+      extension_generators_(new google::protobuf::scoped_ptr<
+          ExtensionGenerator>[descriptor->extension_count()]),
+      use_dependent_base_(false) {
 
   for (int i = 0; i < descriptor->nested_type_count(); i++) {
     nested_generators_[i].reset(
@@ -312,17 +403,44 @@
     extension_generators_[i].reset(
       new ExtensionGenerator(descriptor->extension(i), options));
   }
+
+  num_required_fields_ = 0;
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (descriptor->field(i)->is_required()) {
+      ++num_required_fields_;
+    }
+    if (options.proto_h && IsFieldDependent(descriptor->field(i))) {
+      use_dependent_base_ = true;
+    }
+  }
+  if (options.proto_h && descriptor->oneof_decl_count() > 0) {
+    // Always make oneofs dependent.
+    use_dependent_base_ = true;
+  }
 }
 
 MessageGenerator::~MessageGenerator() {}
 
 void MessageGenerator::
-GenerateForwardDeclaration(io::Printer* printer) {
-  printer->Print("class $classname$;\n",
-                 "classname", classname_);
+FillMessageForwardDeclarations(map<string, const Descriptor*>* class_names) {
+  (*class_names)[classname_] = descriptor_;
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
-    nested_generators_[i]->GenerateForwardDeclaration(printer);
+    // map entry message doesn't need forward declaration. Since map entry
+    // message cannot be a top level class, we just need to avoid calling
+    // GenerateForwardDeclaration here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+    nested_generators_[i]->FillMessageForwardDeclarations(class_names);
+  }
+}
+
+void MessageGenerator::
+FillEnumForwardDeclarations(map<string, const EnumDescriptor*>* enum_names) {
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    nested_generators_[i]->FillEnumForwardDeclarations(enum_names);
+  }
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    enum_generators_[i]->FillForwardDeclaration(enum_names);
   }
 }
 
@@ -348,6 +466,28 @@
 }
 
 void MessageGenerator::
+GenerateDependentFieldAccessorDeclarations(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    PrintFieldComment(printer, field);
+
+    map<string, string> vars;
+    SetCommonFieldVariables(field, &vars, options_);
+
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      // If the message is dependent, the inline clear_*() method will need
+      // to delete the message type, so it must be in the dependent base
+      // class. (See also GenerateFieldAccessorDeclarations.)
+      printer->Print(vars, "$deprecated_attr$void clear_$name$();\n");
+    }
+    // Generate type-specific accessor declarations.
+    field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
+    printer->Print("\n");
+  }
+}
+
+void MessageGenerator::
 GenerateFieldAccessorDeclarations(io::Printer* printer) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
@@ -358,14 +498,40 @@
     SetCommonFieldVariables(field, &vars, options_);
     vars["constant_name"] = FieldConstantName(field);
 
-    if (field->is_repeated()) {
-      printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
-    } else {
-      printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
+    bool dependent_field = use_dependent_base_ && IsFieldDependent(field);
+    if (dependent_field &&
+        field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !field->is_map()) {
+      // If this field is dependent, the dependent base class determines
+      // the message type from the derived class (which is a template
+      // parameter). This typedef is for that:
+      printer->Print(
+          "private:\n"
+          "typedef $field_type$ $dependent_type$;\n"
+          "public:\n",
+          "field_type", FieldMessageTypeName(field),
+          "dependent_type", DependentTypeName(field));
     }
 
-    printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
-    printer->Print(vars, "static const int $constant_name$ = $number$;\n");
+    if (field->is_repeated()) {
+      printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n");
+    } else if (HasHasMethod(field)) {
+      printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n");
+    } else if (HasPrivateHasMethod(field)) {
+      printer->Print(vars,
+          "private:\n"
+          "bool has_$name$() const;\n"
+          "public:\n");
+    }
+
+    if (!dependent_field) {
+      // If this field is dependent, then its clear_() method is in the
+      // depenent base class. (See also GenerateDependentAccessorDeclarations.)
+      printer->Print(vars, "$deprecated_attr$void clear_$name$();\n");
+    }
+    printer->Print(vars,
+                   "$deprecated_attr$static const int $constant_name$ = "
+                   "$number$;\n");
 
     // Generate type-specific accessor declarations.
     field_generators_.get(field).GenerateAccessorDeclarations(printer);
@@ -383,7 +549,7 @@
 
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
-        "inline $camel_oneof_name$Case $oneof_name$_case() const;\n",
+        "$camel_oneof_name$Case $oneof_name$_case() const;\n",
         "camel_oneof_name",
         UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
         "oneof_name", descriptor_->oneof_decl(i)->name());
@@ -391,7 +557,191 @@
 }
 
 void MessageGenerator::
-GenerateFieldAccessorDefinitions(io::Printer* printer) {
+GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
+  if (!use_dependent_base_) return;
+
+  printer->Print("// $classname$\n\n", "classname",
+                 DependentBaseClassTemplateName(descriptor_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    PrintFieldComment(printer, field);
+
+    // These functions are not really dependent: they are part of the
+    // (non-dependent) derived class. However, they need to live outside
+    // any #ifdef guards, so we treat them as if they were dependent.
+    //
+    // See the comment in FileGenerator::GenerateInlineFunctionDefinitions
+    // for a more complete explanation.
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      map<string, string> vars;
+      SetCommonFieldVariables(field, &vars, options_);
+      vars["inline"] = "inline ";
+      if (field->containing_oneof()) {
+        vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
+        vars["oneof_name"] = field->containing_oneof()->name();
+        vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
+        GenerateOneofMemberHasBits(field, vars, printer);
+      } else if (!field->is_repeated()) {
+        // There will be no header guard, so this always has to be inline.
+        GenerateSingularFieldHasBits(field, vars, printer);
+      }
+      // vars needed for clear_(), which is in the dependent base:
+      // (See also GenerateDependentFieldAccessorDeclarations.)
+      vars["tmpl"] = "template<class T>\n";
+      vars["dependent_classname"] =
+          DependentBaseClassTemplateName(descriptor_) + "<T>";
+      vars["this_message"] = DependentBaseDownCast();
+      vars["this_const_message"] = DependentBaseConstDownCast();
+      GenerateFieldClear(field, vars, printer);
+    }
+
+    // Generate type-specific accessors.
+    field_generators_.get(field)
+        .GenerateDependentInlineAccessorDefinitions(printer);
+
+    printer->Print("\n");
+  }
+
+  // Generate has_$name$() and clear_has_$name$() functions for oneofs
+  // Similar to other has-bits, these must always be in the header if we
+  // are using a dependent base class.
+  GenerateOneofHasBits(printer, true /* is_inline */);
+}
+
+void MessageGenerator::
+GenerateSingularFieldHasBits(const FieldDescriptor* field,
+                             map<string, string> vars,
+                             io::Printer* printer) {
+  if (HasFieldPresence(descriptor_->file())) {
+    // N.B.: without field presence, we do not use has-bits or generate
+    // has_$name$() methods.
+    vars["has_array_index"] = SimpleItoa(field->index() / 32);
+    vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32),
+                                           strings::ZERO_PAD_8));
+    printer->Print(vars,
+      "$inline$"
+      "bool $classname$::has_$name$() const {\n"
+      "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+      "}\n"
+      "$inline$"
+      "void $classname$::set_has_$name$() {\n"
+      "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
+      "}\n"
+      "$inline$"
+      "void $classname$::clear_has_$name$() {\n"
+      "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
+      "}\n");
+  } else {
+    // Message fields have a has_$name$() method.
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      bool is_lazy = false;
+      if (is_lazy) {
+        printer->Print(vars,
+          "$inline$"
+          "bool $classname$::has_$name$() const {\n"
+          "  return !$name$_.IsCleared();\n"
+          "}\n");
+      } else {
+        printer->Print(vars,
+          "$inline$"
+          "bool $classname$::has_$name$() const {\n"
+          "  return !_is_default_instance_ && $name$_ != NULL;\n"
+          "}\n");
+      }
+    }
+  }
+}
+
+void MessageGenerator::
+GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    map<string, string> vars;
+    vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    vars["cap_oneof_name"] =
+        ToUpper(descriptor_->oneof_decl(i)->name());
+    vars["classname"] = classname_;
+    vars["inline"] = (is_inline ? "inline " : "");
+    printer->Print(
+        vars,
+        "$inline$"
+        "bool $classname$::has_$oneof_name$() const {\n"
+        "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
+        "}\n"
+        "$inline$"
+        "void $classname$::clear_has_$oneof_name$() {\n"
+        "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
+        "}\n");
+  }
+}
+
+void MessageGenerator::
+GenerateOneofMemberHasBits(const FieldDescriptor* field,
+                           const map<string, string>& vars,
+                           io::Printer* printer) {
+  // Singular field in a oneof
+  // N.B.: Without field presence, we do not use has-bits or generate
+  // has_$name$() methods, but oneofs still have set_has_$name$().
+  // Oneofs also have has_$name$() but only as a private helper
+  // method, so that generated code is slightly cleaner (vs.  comparing
+  // _oneof_case_[index] against a constant everywhere).
+  printer->Print(vars,
+    "$inline$"
+    "bool $classname$::has_$name$() const {\n"
+    "  return $oneof_name$_case() == k$field_name$;\n"
+    "}\n");
+  printer->Print(vars,
+    "$inline$"
+    "void $classname$::set_has_$name$() {\n"
+    "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
+    "}\n");
+}
+
+void MessageGenerator::
+GenerateFieldClear(const FieldDescriptor* field,
+                   const map<string, string>& vars,
+                   io::Printer* printer) {
+  // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and
+  // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is
+  // set by the Generate*Definitions functions.)
+  printer->Print(vars,
+    "$tmpl$"
+    "$inline$"
+    "void $dependent_classname$::clear_$name$() {\n");
+
+  printer->Indent();
+
+  if (field->containing_oneof()) {
+    // Clear this field only if it is the active field in this oneof,
+    // otherwise ignore
+    printer->Print(vars,
+      "if ($this_message$has_$name$()) {\n");
+    printer->Indent();
+    field_generators_.get(field)
+        .GenerateClearingCode(printer);
+    printer->Print(vars,
+      "$this_message$clear_has_$oneof_name$();\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  } else {
+    field_generators_.get(field)
+        .GenerateClearingCode(printer);
+    if (HasFieldPresence(descriptor_->file())) {
+      if (!field->is_repeated()) {
+        printer->Print(vars,
+                       "$this_message$clear_has_$name$();\n");
+      }
+    }
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void MessageGenerator::
+GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
   printer->Print("// $classname$\n\n", "classname", classname_);
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -401,93 +751,57 @@
 
     map<string, string> vars;
     SetCommonFieldVariables(field, &vars, options_);
+    vars["inline"] = is_inline ? "inline " : "";
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      vars["tmpl"] = "template<class T>\n";
+      vars["dependent_classname"] =
+          DependentBaseClassTemplateName(descriptor_) + "<T>";
+      vars["this_message"] = "reinterpret_cast<T*>(this)->";
+      vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+    } else {
+      vars["tmpl"] = "";
+      vars["dependent_classname"] = vars["classname"];
+      vars["this_message"] = "";
+      vars["this_const_message"] = "";
+    }
 
     // Generate has_$name$() or $name$_size().
     if (field->is_repeated()) {
       printer->Print(vars,
-        "inline int $classname$::$name$_size() const {\n"
+        "$inline$"
+        "int $classname$::$name$_size() const {\n"
         "  return $name$_.size();\n"
         "}\n");
     } else if (field->containing_oneof()) {
-      // Singular field in a oneof
       vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
       vars["oneof_name"] = field->containing_oneof()->name();
       vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
-      printer->Print(vars,
-        "inline bool $classname$::has_$name$() const {\n"
-        "  return $oneof_name$_case() == k$field_name$;\n"
-        "}\n"
-        "inline void $classname$::set_has_$name$() {\n"
-        "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
-        "}\n");
+      if (!use_dependent_base_ || !IsFieldDependent(field)) {
+        GenerateOneofMemberHasBits(field, vars, printer);
+      }
     } else {
       // Singular field.
-      char buffer[kFastToBufferSize];
-      vars["has_array_index"] = SimpleItoa(field->index() / 32);
-      vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), buffer);
-      printer->Print(vars,
-        "inline bool $classname$::has_$name$() const {\n"
-        "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
-        "}\n"
-        "inline void $classname$::set_has_$name$() {\n"
-        "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
-        "}\n"
-        "inline void $classname$::clear_has_$name$() {\n"
-        "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
-        "}\n"
-        );
-    }
-
-    // Generate clear_$name$()
-    printer->Print(vars,
-      "inline void $classname$::clear_$name$() {\n");
-
-    printer->Indent();
-
-    if (field->containing_oneof()) {
-      // Clear this field only if it is the active field in this oneof,
-      // otherwise ignore
-      printer->Print(vars,
-        "if (has_$name$()) {\n");
-      printer->Indent();
-      field_generators_.get(field).GenerateClearingCode(printer);
-      printer->Print(vars,
-        "clear_has_$oneof_name$();\n");
-      printer->Outdent();
-      printer->Print("}\n");
-    } else {
-      field_generators_.get(field).GenerateClearingCode(printer);
-      if (!field->is_repeated()) {
-        printer->Print(vars,
-                       "clear_has_$name$();\n");
+      if (!use_dependent_base_ || !IsFieldDependent(field)) {
+        GenerateSingularFieldHasBits(field, vars, printer);
       }
     }
 
-    printer->Outdent();
-    printer->Print("}\n");
+    if (!use_dependent_base_ || !IsFieldDependent(field)) {
+      GenerateFieldClear(field, vars, printer);
+    }
 
     // Generate type-specific accessors.
-    field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+    field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
+                                                                   is_inline);
 
     printer->Print("\n");
   }
 
-  // Generate has_$name$() and clear_has_$name$() functions for oneofs
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    map<string, string> vars;
-    vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
-    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
-    vars["cap_oneof_name"] =
-        ToUpper(descriptor_->oneof_decl(i)->name());
-    vars["classname"] = classname_;
-    printer->Print(
-      vars,
-      "inline bool $classname$::has_$oneof_name$() {\n"
-      "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
-      "}\n"
-      "inline void $classname$::clear_has_$oneof_name$() {\n"
-      "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
-      "}\n");
+  if (!use_dependent_base_) {
+    // Generate has_$name$() and clear_has_$name$() functions for oneofs
+    // If we aren't using a dependent base, they can be with the other functions
+    // that are #ifdef-guarded.
+    GenerateOneofHasBits(printer, is_inline);
   }
 }
 
@@ -517,14 +831,51 @@
 }
 
 void MessageGenerator::
+GenerateDependentBaseClassDefinition(io::Printer* printer) {
+  if (!use_dependent_base_) {
+    return;
+  }
+
+  map<string, string> vars;
+  vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+  vars["superclass"] = SuperClassName(descriptor_, options_);
+
+  printer->Print(vars,
+    "template <class T>\n"
+    "class $classname$ : public $superclass$ {\n"
+    " public:\n");
+  printer->Indent();
+
+  printer->Print(vars,
+    "$classname$() {}\n"
+    "virtual ~$classname$() {}\n"
+    "\n");
+
+  // Generate dependent accessor methods for all fields.
+  GenerateDependentFieldAccessorDeclarations(printer);
+
+  printer->Outdent();
+  printer->Print("};\n");
+}
+
+void MessageGenerator::
 GenerateClassDefinition(io::Printer* printer) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // map entry message doesn't need class definition. Since map entry message
+    // cannot be a top level class, we just need to avoid calling
+    // GenerateClassDefinition here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     nested_generators_[i]->GenerateClassDefinition(printer);
     printer->Print("\n");
     printer->Print(kThinSeparator);
     printer->Print("\n");
   }
 
+  if (use_dependent_base_) {
+    GenerateDependentBaseClassDefinition(printer);
+      printer->Print("\n");
+  }
+
   map<string, string> vars;
   vars["classname"] = classname_;
   vars["field_count"] = SimpleItoa(descriptor_->field_count());
@@ -534,11 +885,19 @@
   } else {
     vars["dllexport"] = options_.dllexport_decl + " ";
   }
-  vars["superclass"] = SuperClassName(descriptor_);
-
+  if (use_dependent_base_) {
+    vars["superclass"] =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+  } else {
+    vars["superclass"] = SuperClassName(descriptor_, options_);
+  }
   printer->Print(vars,
-    "class $dllexport$$classname$ : public $superclass$ {\n"
-    " public:\n");
+    "class $dllexport$$classname$ : public $superclass$ {\n");
+  printer->Annotate("classname", descriptor_);
+  if (use_dependent_base_) {
+    printer->Print(vars, "  friend class $superclass$;\n");
+  }
+  printer->Print(" public:\n");
   printer->Indent();
 
   printer->Print(vars,
@@ -553,30 +912,62 @@
     "}\n"
     "\n");
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+        "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
+        "  return _internal_metadata_.unknown_fields();\n"
+        "}\n"
+        "\n"
+        "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
+        "  return _internal_metadata_.mutable_unknown_fields();\n"
+        "}\n"
+        "\n");
+    } else {
+      if (SupportsArenas(descriptor_)) {
+        printer->Print(
+          "inline const ::std::string& unknown_fields() const {\n"
+          "  return _unknown_fields_.Get(\n"
+          "      &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"
+          "}\n"
+          "\n"
+          "inline ::std::string* mutable_unknown_fields() {\n"
+          "  return _unknown_fields_.Mutable(\n"
+          "      &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n"
+          "      GetArenaNoVirtual());\n"
+          "}\n"
+          "\n");
+      } else {
+        printer->Print(
+          "inline const ::std::string& unknown_fields() const {\n"
+          "  return _unknown_fields_.GetNoArena(\n"
+          "      &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"
+          "}\n"
+          "\n"
+          "inline ::std::string* mutable_unknown_fields() {\n"
+          "  return _unknown_fields_.MutableNoArena(\n"
+          "      &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"
+          "}\n"
+          "\n");
+      }
+    }
+  }
+
+  // N.B.: We exclude GetArena() when arena support is disabled, falling back on
+  // MessageLite's implementation which returns NULL rather than generating our
+  // own method which returns NULL, in order to reduce code size.
+  if (SupportsArenas(descriptor_)) {
+    // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a
+    // MessageLite* (e.g., in RepeatedField::AddAllocated()).
     printer->Print(
-      "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
-      "  return _unknown_fields_;\n"
-      "}\n"
-      "\n"
-      "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
-      "  return &_unknown_fields_;\n"
-      "}\n"
-      "\n");
-  } else {
-    printer->Print(
-      "inline const ::std::string& unknown_fields() const {\n"
-      "  return _unknown_fields_;\n"
-      "}\n"
-      "\n"
-      "inline ::std::string* mutable_unknown_fields() {\n"
-      "  return &_unknown_fields_;\n"
-      "}\n"
-      "\n");
+        "inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }\n"
+        "inline void* GetMaybeArenaPointer() const {\n"
+        "  return MaybeArenaPtr();\n"
+        "}\n");
   }
 
   // Only generate this member if it's not disabled.
-  if (HasDescriptorMethods(descriptor_->file()) &&
+  if (HasDescriptorMethods(descriptor_->file(), options_) &&
       !descriptor_->options().no_standard_descriptor_accessor()) {
     printer->Print(vars,
       "static const ::google::protobuf::Descriptor* descriptor();\n");
@@ -613,7 +1004,7 @@
         "\n");
   }
 
-  if (!StaticInitializersForced(descriptor_->file())) {
+  if (!StaticInitializersForced(descriptor_->file(), options_)) {
     printer->Print(vars,
       "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"
       "// Returns the internal default instance pointer. This function can\n"
@@ -628,15 +1019,36 @@
   }
 
 
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(vars,
+      "void UnsafeArenaSwap($classname$* other);\n");
+  }
+
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(vars,
+      "// implements Any -----------------------------------------------\n"
+      "\n"
+      "void PackFrom(const ::google::protobuf::Message& message);\n"
+      "void PackFrom(const ::google::protobuf::Message& message,\n"
+      "              const ::std::string& type_url_prefix);\n"
+      "bool UnpackTo(::google::protobuf::Message* message) const;\n"
+      "template<typename T> bool Is() const {\n"
+      "  return _any_metadata_.Is<T>();\n"
+      "}\n"
+      "\n");
+  }
+
   printer->Print(vars,
     "void Swap($classname$* other);\n"
     "\n"
     "// implements Message ----------------------------------------------\n"
     "\n"
-    "$classname$* New() const;\n");
+    "inline $classname$* New() const { return New(NULL); }\n"
+    "\n"
+    "$classname$* New(::google::protobuf::Arena* arena) const;\n");
 
-  if (HasGeneratedMethods(descriptor_->file())) {
-    if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
       printer->Print(vars,
         "void CopyFrom(const ::google::protobuf::Message& from);\n"
         "void MergeFrom(const ::google::protobuf::Message& from);\n");
@@ -658,11 +1070,11 @@
       "    ::google::protobuf::io::CodedOutputStream* output) const;\n");
     // DiscardUnknownFields() is implemented in message.cc using reflections. We
     // need to implement this function in generated code for messages.
-    if (!UseUnknownFieldSet(descriptor_->file())) {
+    if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
       printer->Print(
         "void DiscardUnknownFields();\n");
     }
-    if (HasFastArraySerialization(descriptor_->file())) {
+    if (HasFastArraySerialization(descriptor_->file(), options_)) {
       printer->Print(
         "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
     }
@@ -684,6 +1096,10 @@
     }
   }
   uses_string_ = false;
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file(), options_)) {
+    uses_string_ = true;
+  }
   for (int i = 0; i < descriptors.size(); i++) {
     const FieldDescriptor* field = descriptors[i];
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
@@ -699,9 +1115,43 @@
     "void SharedCtor();\n"
     "void SharedDtor();\n"
     "void SetCachedSize(int size) const;\n"
-    "public:\n");
+    "void InternalSwap($classname$* other);\n",
+    "classname", classname_);
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(
+      "protected:\n"
+      "explicit $classname$(::google::protobuf::Arena* arena);\n"
+      "private:\n"
+      "static void ArenaDtor(void* object);\n"
+      "inline void RegisterArenaDtor(::google::protobuf::Arena* arena);\n",
+      "classname", classname_);
+  }
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(
+      "private:\n"
+      "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n"
+      "  return _internal_metadata_.arena();\n"
+      "}\n"
+      "inline void* MaybeArenaPtr() const {\n"
+      "  return _internal_metadata_.raw_arena_ptr();\n"
+      "}\n"
+      "public:\n"
+      "\n");
+  } else {
+    printer->Print(
+      "private:\n"
+      "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n"
+      "  return _arena_ptr_;\n"
+      "}\n"
+      "inline ::google::protobuf::Arena* MaybeArenaPtr() const {\n"
+      "  return _arena_ptr_;\n"
+      "}\n"
+      "public:\n"
+      "\n");
+  }
+
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(
       "::google::protobuf::Metadata GetMetadata() const;\n"
       "\n");
@@ -718,9 +1168,11 @@
   // Import all nested message classes into this class's scope with typedefs.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     const Descriptor* nested_type = descriptor_->nested_type(i);
-    printer->Print("typedef $nested_full_name$ $nested_name$;\n",
-                   "nested_name", nested_type->name(),
-                   "nested_full_name", ClassName(nested_type, false));
+    if (!IsMapEntryMessage(nested_type)) {
+      printer->Print("typedef $nested_full_name$ $nested_name$;\n",
+                     "nested_name", nested_type->name(),
+                     "nested_full_name", ClassName(nested_type, false));
+    }
   }
 
   if (descriptor_->nested_type_count() > 0) {
@@ -759,10 +1211,18 @@
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     if (!descriptor_->field(i)->is_repeated()) {
-      printer->Print(
-        "inline void set_has_$name$();\n",
-        "name", FieldName(descriptor_->field(i)));
-      if (!descriptor_->field(i)->containing_oneof()) {
+      // set_has_***() generated in all proto1/2 code and in oneofs (only) for
+      // messages without true field presence.
+      if (HasFieldPresence(descriptor_->file()) ||
+          descriptor_->field(i)->containing_oneof()) {
+        printer->Print(
+          "inline void set_has_$name$();\n",
+          "name", FieldName(descriptor_->field(i)));
+      }
+      // clear_has_***() generated only for non-oneof fields
+      // in proto1/2.
+      if (!descriptor_->field(i)->containing_oneof() &&
+          HasFieldPresence(descriptor_->file())) {
         printer->Print(
           "inline void clear_has_$name$();\n",
           "name", FieldName(descriptor_->field(i)));
@@ -774,12 +1234,20 @@
   // Generate oneof function declarations
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
-        "inline bool has_$oneof_name$();\n"
+        "inline bool has_$oneof_name$() const;\n"
         "void clear_$oneof_name$();\n"
         "inline void clear_has_$oneof_name$();\n\n",
         "oneof_name", descriptor_->oneof_decl(i)->name());
   }
 
+  if (HasGeneratedMethods(descriptor_->file(), options_) &&
+      !descriptor_->options().message_set_wire_format() &&
+      num_required_fields_ > 1) {
+    printer->Print(
+        "// helper for ByteSize()\n"
+        "int RequiredFieldsByteSizeFallback() const;\n\n");
+  }
+
   // Prepare decls for _cached_size_ and _has_bits_.  Their position in the
   // output will be determined later.
 
@@ -814,25 +1282,50 @@
       "\n");
   }
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
     printer->Print(
-      "::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
-      "\n");
+      "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n");
   } else {
     printer->Print(
-      "::std::string _unknown_fields_;\n"
+      "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n"
+      "::google::protobuf::Arena* _arena_ptr_;\n"
       "\n");
   }
 
-  // _has_bits_ is frequently accessed, so to reduce code size and improve
-  // speed, it should be close to the start of the object.  But, try not to
-  // waste space:_has_bits_ by itself always makes sense if its size is a
-  // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together
-  // will work well.
-  printer->Print(has_bits_decl.c_str());
-  if ((sizeof_has_bits % 8) != 0) {
-    printer->Print(cached_size_decl.c_str());
-    need_to_emit_cached_size = false;
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(
+      "friend class ::google::protobuf::Arena;\n"
+      "typedef void InternalArenaConstructable_;\n"
+      "typedef void DestructorSkippable_;\n");
+  }
+
+  if (HasFieldPresence(descriptor_->file())) {
+    // _has_bits_ is frequently accessed, so to reduce code size and improve
+    // speed, it should be close to the start of the object.  But, try not to
+    // waste space:_has_bits_ by itself always makes sense if its size is a
+    // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together
+    // will work well.
+    printer->Print(has_bits_decl.c_str());
+    if ((sizeof_has_bits % 8) != 0) {
+      printer->Print(cached_size_decl.c_str());
+      need_to_emit_cached_size = false;
+    }
+  } else {
+    // Without field presence, we need another way to disambiguate the default
+    // instance, because the default instance's submessage fields (if any) store
+    // pointers to the default instances of the submessages even when they
+    // aren't present. Alternatives to this approach might be to (i) use a
+    // tagged pointer on all message fields, setting a tag bit for "not really
+    // present, just default instance"; or (ii) comparing |this| against the
+    // return value from GeneratedMessageFactory::GetPrototype() in all
+    // has_$field$() calls. However, both of these options are much more
+    // expensive (in code size and CPU overhead) than just checking a field in
+    // the message. Long-term, the best solution would be to rearchitect the
+    // default instance design not to store pointers to submessage default
+    // instances, and have reflection get those some other way; but that change
+    // would have too much impact on proto2.
+    printer->Print(
+      "bool _is_default_instance_;\n");
   }
 
   // Field members:
@@ -871,7 +1364,10 @@
   // For each oneof generate a union
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
-        "union $camel_oneof_name$Union {\n",
+        "union $camel_oneof_name$Union {\n"
+        // explicit empty constructor is needed when union contains
+        // ArenaStringPtr members for string fields.
+        "  $camel_oneof_name$Union() {}\n",
         "camel_oneof_name",
         UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
     printer->Indent();
@@ -903,19 +1399,24 @@
       "\n");
   }
 
+  // Generate _any_metadata_ for the Any type.
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(vars,
+      "::google::protobuf::internal::AnyMetadata _any_metadata_;\n");
+  }
+
   // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
   // friends so that they can access private static variables like
   // default_instance_ and reflection_.
   PrintHandlingOptionalStaticInitializers(
-    descriptor_->file(), printer,
-    // With static initializers.
-    "friend void $dllexport_decl$ $adddescriptorsname$();\n",
-    // Without.
-    "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n",
-    // Vars.
-    "dllexport_decl", options_.dllexport_decl,
-    "adddescriptorsname",
-    GlobalAddDescriptorsName(descriptor_->file()->name()));
+      descriptor_->file(), options_, printer,
+      // With static initializers.
+      "friend void $dllexport_decl$ $adddescriptorsname$();\n",
+      // Without.
+      "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n",
+      // Vars.
+      "dllexport_decl", options_.dllexport_decl, "adddescriptorsname",
+      GlobalAddDescriptorsName(descriptor_->file()->name()));
 
   printer->Print(
     "friend void $assigndescriptorsname$();\n"
@@ -936,14 +1437,33 @@
 }
 
 void MessageGenerator::
-GenerateInlineMethods(io::Printer* printer) {
+GenerateDependentInlineMethods(io::Printer* printer) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
-    nested_generators_[i]->GenerateInlineMethods(printer);
+    // map entry message doesn't need inline methods. Since map entry message
+    // cannot be a top level class, we just need to avoid calling
+    // GenerateInlineMethods here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+    nested_generators_[i]->GenerateDependentInlineMethods(printer);
     printer->Print(kThinSeparator);
     printer->Print("\n");
   }
 
-  GenerateFieldAccessorDefinitions(printer);
+  GenerateDependentFieldAccessorDefinitions(printer);
+}
+
+void MessageGenerator::
+GenerateInlineMethods(io::Printer* printer, bool is_inline) {
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // map entry message doesn't need inline methods. Since map entry message
+    // cannot be a top level class, we just need to avoid calling
+    // GenerateInlineMethods here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+    nested_generators_[i]->GenerateInlineMethods(printer, is_inline);
+    printer->Print(kThinSeparator);
+    printer->Print("\n");
+  }
+
+  GenerateFieldAccessorDefinitions(printer, is_inline);
 
   // Generate oneof_case() functions.
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -953,9 +1473,11 @@
         descriptor_->oneof_decl(i)->name(), true);
     vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
     vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    vars["inline"] = is_inline ? "inline " : "";
     printer->Print(
         vars,
-        "inline $class_name$::$camel_oneof_name$Case $class_name$::"
+        "$inline$"
+        "$class_name$::$camel_oneof_name$Case $class_name$::"
         "$oneof_name$_case() const {\n"
         "  return $class_name$::$camel_oneof_name$Case("
         "_oneof_case_[$oneof_index$]);\n"
@@ -965,11 +1487,17 @@
 
 void MessageGenerator::
 GenerateDescriptorDeclarations(io::Printer* printer) {
-  printer->Print(
-    "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
-    "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
-    "  $name$_reflection_ = NULL;\n",
-    "name", classname_);
+  if (!IsMapEntryMessage(descriptor_)) {
+    printer->Print(
+      "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
+      "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
+      "  $name$_reflection_ = NULL;\n",
+      "name", classname_);
+  } else {
+    printer->Print(
+      "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n",
+      "name", classname_);
+  }
 
   // Generate oneof default instance for reflection usage.
   if (descriptor_->oneof_decl_count() > 0) {
@@ -979,7 +1507,9 @@
       for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
         const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
         printer->Print("  ");
-        if (IsStringOrMessage(field)) {
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+            (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+             EffectiveStringCType(field) != FieldOptions::STRING)) {
           printer->Print("const ");
         }
         field_generators_.get(field).GeneratePrivateMembers(printer);
@@ -1020,19 +1550,44 @@
         "$parent$_descriptor_->nested_type($index$);\n");
   }
 
+  if (IsMapEntryMessage(descriptor_)) return;
+
   // Generate the offsets.
   GenerateOffsets(printer);
 
+  const bool pass_pool_and_factory = false;
+  vars["fn"] = pass_pool_and_factory ?
+      "new ::google::protobuf::internal::GeneratedMessageReflection" :
+      "::google::protobuf::internal::GeneratedMessageReflection"
+      "::NewGeneratedMessageReflection";
   // Construct the reflection object.
   printer->Print(vars,
     "$classname$_reflection_ =\n"
-    "  new ::google::protobuf::internal::GeneratedMessageReflection(\n"
+    "  $fn$(\n"
     "    $classname$_descriptor_,\n"
     "    $classname$::default_instance_,\n"
-    "    $classname$_offsets_,\n"
-    "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n"
+    "    $classname$_offsets_,\n");
+  if (!HasFieldPresence(descriptor_->file())) {
+    // If we don't have field presence, then _has_bits_ does not exist.
+    printer->Print(vars,
+    "    -1,\n");
+  } else {
+    printer->Print(vars,
+    "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n");
+  }
+
+  // Unknown field offset: either points to the unknown field set if embedded
+  // directly, or indicates that the unknown field set is stored as part of the
+  // internal metadata if not.
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(vars,
+    "    -1,\n");
+  } else {
+    printer->Print(vars,
     "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
       "$classname$, _unknown_fields_),\n");
+  }
+
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(vars,
       "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
@@ -1050,12 +1605,39 @@
       "$classname$, _oneof_case_[0]),\n");
   }
 
-  printer->Print(
-    "    ::google::protobuf::DescriptorPool::generated_pool(),\n");
+  if (pass_pool_and_factory) {
+    printer->Print(
+        "    ::google::protobuf::DescriptorPool::generated_pool(),\n");
+      printer->Print(vars,
+                     "    ::google::protobuf::MessageFactory::generated_factory(),\n");
+  }
+
   printer->Print(vars,
-    "    ::google::protobuf::MessageFactory::generated_factory(),\n");
-  printer->Print(vars,
-    "    sizeof($classname$));\n");
+    "    sizeof($classname$),\n");
+
+  // Arena offset: either an offset to the metadata struct that contains the
+  // arena pointer and unknown field set (in a space-efficient way) if we use
+  // that implementation strategy, or an offset directly to the arena pointer if
+  // not (because e.g. we don't have an unknown field set).
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(vars,
+    "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+    "$classname$, _internal_metadata_),\n");
+  } else {
+    printer->Print(vars,
+    "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+    "$classname$, _arena_),\n");
+  }
+
+  // is_default_instance_ offset.
+  if (HasFieldPresence(descriptor_->file())) {
+    printer->Print(vars,
+    "    -1);\n");
+  } else {
+    printer->Print(vars,
+    "    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+    "$classname$, _is_default_instance_));\n");
+  }
 
   // Handle nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -1070,10 +1652,37 @@
 void MessageGenerator::
 GenerateTypeRegistrations(io::Printer* printer) {
   // Register this message type with the message factory.
-  printer->Print(
-    "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
-    "  $classname$_descriptor_, &$classname$::default_instance());\n",
-    "classname", classname_);
+  if (!IsMapEntryMessage(descriptor_)) {
+    printer->Print(
+      "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+      "    $classname$_descriptor_, &$classname$::default_instance());\n",
+      "classname", classname_);
+  }
+  else {
+    map<string, string> vars;
+    CollectMapInfo(descriptor_, &vars);
+    vars["classname"] = classname_;
+
+    const FieldDescriptor* val = descriptor_->FindFieldByName("value");
+    if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+        val->type() == FieldDescriptor::TYPE_ENUM) {
+      const EnumValueDescriptor* default_value = val->default_value_enum();
+      vars["default_enum_value"] = Int32ToString(default_value->number());
+    } else {
+      vars["default_enum_value"] = "0";
+    }
+
+    printer->Print(vars,
+      "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+      "      $classname$_descriptor_,\n"
+      "      ::google::protobuf::internal::MapEntry<\n"
+      "          $key$,\n"
+      "          $val$,\n"
+      "          $key_wire_type$,\n"
+      "          $val_wire_type$,\n"
+      "          $default_enum_value$>::CreateDefaultInstance(\n"
+      "              $classname$_descriptor_));\n");
+  }
 
   // Handle nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -1090,6 +1699,8 @@
                      .GenerateDefaultInstanceAllocator(printer);
   }
 
+  if (IsMapEntryMessage(descriptor_)) return;
+
   // Construct the default instance.  We can't call InitAsDefaultInstance() yet
   // because we need to make sure all default instances that this one might
   // depend on are constructed first.
@@ -1098,9 +1709,9 @@
     "classname", classname_);
 
   if ((descriptor_->oneof_decl_count() > 0) &&
-      HasDescriptorMethods(descriptor_->file())) {
+      HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(
-    "$classname$_default_oneof_instance_ = new $classname$OneofInstance;\n",
+    "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n",
     "classname", classname_);
   }
 
@@ -1124,6 +1735,10 @@
 
   // Handle nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // map entry message doesn't need to initialize default instance manually.
+    // Since map entry message cannot be a top level class, we just need to
+    // avoid calling DefaultInstanceInitializer here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     nested_generators_[i]->GenerateDefaultInstanceInitializer(printer);
   }
 }
@@ -1134,7 +1749,7 @@
     "delete $classname$::default_instance_;\n",
     "classname", classname_);
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     if (descriptor_->oneof_decl_count() > 0) {
       printer->Print(
         "delete $classname$_default_oneof_instance_;\n",
@@ -1153,17 +1768,52 @@
 
   // Handle nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     nested_generators_[i]->GenerateShutdownCode(printer);
   }
 }
 
 void MessageGenerator::
 GenerateClassMethods(io::Printer* printer) {
+  // 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"
+      "  _any_metadata_.PackFrom(message);\n"
+      "}\n"
+      "\n"
+      "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n"
+      "                           const ::std::string& type_url_prefix) {\n"
+      "  _any_metadata_.PackFrom(message, type_url_prefix);\n"
+      "}\n"
+      "\n"
+      "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
+      "  return _any_metadata_.UnpackTo(message);\n"
+      "}\n"
+      "\n",
+      "classname", classname_);
+  }
+
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
     enum_generators_[i]->GenerateMethods(printer);
   }
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // map entry message doesn't need class methods. Since map entry message
+    // cannot be a top level class, we just need to avoid calling
+    // GenerateClassMethods here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     nested_generators_[i]->GenerateClassMethods(printer);
     printer->Print("\n");
     printer->Print(kThinSeparator);
@@ -1177,7 +1827,7 @@
   }
 
   // Generate field number constants.
-  printer->Print("#ifndef _MSC_VER\n");
+  printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor *field = descriptor_->field(i);
     printer->Print(
@@ -1186,7 +1836,7 @@
       "constant_name", FieldConstantName(field));
   }
   printer->Print(
-    "#endif  // !_MSC_VER\n"
+    "#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n"
     "\n");
 
   // Define extension identifiers.
@@ -1202,7 +1852,7 @@
     printer->Print("\n");
   }
 
-  if (HasGeneratedMethods(descriptor_->file())) {
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
     GenerateClear(printer);
     printer->Print("\n");
 
@@ -1212,7 +1862,7 @@
     GenerateSerializeWithCachedSizes(printer);
     printer->Print("\n");
 
-    if (HasFastArraySerialization(descriptor_->file())) {
+    if (HasFastArraySerialization(descriptor_->file(), options_)) {
       GenerateSerializeWithCachedSizesToArray(printer);
       printer->Print("\n");
     }
@@ -1233,7 +1883,7 @@
   GenerateSwap(printer);
   printer->Print("\n");
 
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     printer->Print(
       "::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
       "  protobuf_AssignDescriptorsOnce();\n"
@@ -1258,11 +1908,10 @@
 
 void MessageGenerator::
 GenerateOffsets(io::Printer* printer) {
-  printer->Print(
-    "static const int $classname$_offsets_[$field_count$] = {\n",
-    "classname", classname_,
-    "field_count", SimpleItoa(max(
-        1, descriptor_->field_count() + descriptor_->oneof_decl_count())));
+  printer->Print("static const int $classname$_offsets_[$field_count$] = {\n",
+                 "classname", classname_, "field_count",
+                 SimpleItoa(std::max(1, descriptor_->field_count() +
+                                            descriptor_->oneof_decl_count())));
   printer->Indent();
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1301,10 +1950,22 @@
     "classname", classname_);
   printer->Indent();
 
+  if (!HasFieldPresence(descriptor_->file())) {
+    printer->Print(
+      "  _is_default_instance_ = false;\n");
+  }
+
   printer->Print(StrCat(
       uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "",
       "_cached_size_ = 0;\n").c_str());
 
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(
+        "_unknown_fields_.UnsafeSetDefault(\n"
+        "    &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n");
+  }
+
   for (int i = 0; i < descriptor_->field_count(); i++) {
     if (!descriptor_->field(i)->containing_oneof()) {
       field_generators_.get(descriptor_->field(i))
@@ -1312,8 +1973,10 @@
     }
   }
 
-  printer->Print(
-    "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+  if (HasFieldPresence(descriptor_->file())) {
+    printer->Print(
+      "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+  }
 
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
@@ -1331,6 +1994,30 @@
     "void $classname$::SharedDtor() {\n",
     "classname", classname_);
   printer->Indent();
+  if (SupportsArenas(descriptor_)) {
+    // Do nothing when the message is allocated in an arena.
+    printer->Print(
+      "if (GetArenaNoVirtual() != NULL) {\n"
+      "  return;\n"
+      "}\n"
+      "\n");
+  }
+
+  // Write the desctructor for _unknown_fields_ in lite runtime.
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file(), options_)) {
+    if (SupportsArenas(descriptor_)) {
+      printer->Print(
+          "_unknown_fields_.Destroy(\n"
+          "    &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n"
+          "    GetArenaNoVirtual());\n");
+    } else {
+      printer->Print(
+          "_unknown_fields_.DestroyNoArena(\n"
+          "    &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n");
+    }
+  }
+
   // Write the destructors for each field except oneof members.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     if (!descriptor_->field(i)->containing_oneof()) {
@@ -1349,11 +2036,11 @@
   }
 
   PrintHandlingOptionalStaticInitializers(
-    descriptor_->file(), printer,
-    // With static initializers.
-    "if (this != default_instance_) {\n",
-    // Without.
-    "if (this != &default_instance()) {\n");
+      descriptor_->file(), options_, printer,
+      // With static initializers.
+      "if (this != default_instance_) {\n",
+      // Without.
+      "if (this != &default_instance()) {\n");
 
   // We need to delete all embedded messages.
   // TODO(kenton):  If we make unset messages point at default instances
@@ -1381,25 +2068,128 @@
 }
 
 void MessageGenerator::
-GenerateStructors(io::Printer* printer) {
-  string superclass = SuperClassName(descriptor_);
-
-  // Generate the default constructor.
+GenerateArenaDestructorCode(io::Printer* printer) {
+  // Generate the ArenaDtor() method. Track whether any fields actually produced
+  // code that needs to be called.
   printer->Print(
-    "$classname$::$classname$()\n"
-    "  : $superclass$() {\n"
-    "  SharedCtor();\n"
-    "  // @@protoc_insertion_point(constructor:$full_name$)\n"
-    "}\n",
-    "classname", classname_,
-    "superclass", superclass,
-    "full_name", descriptor_->full_name());
+      "void $classname$::ArenaDtor(void* object) {\n",
+      "classname", classname_);
+  printer->Indent();
+
+  // This code is placed inside a static method, rather than an ordinary one,
+  // since that simplifies Arena's destructor list (ordinary function pointers
+  // rather than member function pointers). _this is the object being
+  // destructed.
+  printer->Print(
+      "$classname$* _this = reinterpret_cast< $classname$* >(object);\n"
+      // avoid an "unused variable" warning in case no fields have dtor code.
+      "(void)_this;\n",
+      "classname", classname_);
+
+  bool need_registration = false;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (field_generators_.get(descriptor_->field(i))
+                         .GenerateArenaDestructorCode(printer)) {
+      need_registration = true;
+    }
+  }
+  printer->Outdent();
+  printer->Print(
+      "}\n");
+
+  if (need_registration) {
+    printer->Print(
+        "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+        "  if (arena != NULL) {\n"
+        "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+        "  }\n"
+        "}\n",
+        "classname", classname_);
+  } else {
+    printer->Print(
+        "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+        "}\n",
+        "classname", classname_);
+  }
+}
+
+void MessageGenerator::
+GenerateStructors(io::Printer* printer) {
+  string superclass;
+  if (use_dependent_base_) {
+    superclass =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+  } else {
+    superclass = SuperClassName(descriptor_, options_);
+  }
+  string initializer_with_arena = superclass + "()";
+
+  if (descriptor_->extension_range_count() > 0) {
+    initializer_with_arena += ",\n  _extensions_(arena)";
+  }
+
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    initializer_with_arena += ",\n  _internal_metadata_(arena)";
+  } else {
+    initializer_with_arena += ",\n  _arena_ptr_(arena)";
+  }
+
+  // Initialize member variables with arena constructor.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    bool has_arena_constructor = descriptor_->field(i)->is_repeated();
+    if (has_arena_constructor) {
+      initializer_with_arena += string(",\n  ") +
+          FieldName(descriptor_->field(i)) + string("_(arena)");
+    }
+  }
+
+  if (IsAnyMessage(descriptor_)) {
+    initializer_with_arena += ",\n  _any_metadata_(&type_url, &value_)";
+  }
+
+  string initializer_null;
+  initializer_null = (UseUnknownFieldSet(descriptor_->file(), options_) ?
+    ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)");
+  if (IsAnyMessage(descriptor_)) {
+    initializer_null += ", _any_metadata_(&type_url_, &value_)";
+  }
+
+  printer->Print(
+      "$classname$::$classname$()\n"
+      "  : $superclass$()$initializer$ {\n"
+      "  SharedCtor();\n"
+      "  // @@protoc_insertion_point(constructor:$full_name$)\n"
+      "}\n",
+      "classname", classname_,
+      "superclass", superclass,
+      "full_name", descriptor_->full_name(),
+      "initializer", initializer_null);
+
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(
+        "\n"
+        "$classname$::$classname$(::google::protobuf::Arena* arena)\n"
+        "  : $initializer$ {\n"
+        "  SharedCtor();\n"
+        "  RegisterArenaDtor(arena);\n"
+        "  // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
+        "}\n",
+        "initializer", initializer_with_arena,
+        "classname", classname_,
+        "superclass", superclass,
+        "full_name", descriptor_->full_name());
+  }
 
   printer->Print(
     "\n"
     "void $classname$::InitAsDefaultInstance() {\n",
     "classname", classname_);
 
+  if (!HasFieldPresence(descriptor_->file())) {
+    printer->Print(
+      "  _is_default_instance_ = true;\n");
+  }
+
   // The default instance needs all of its embedded message pointers
   // cross-linked to other default instances.  We can't do this initialization
   // in the constructor because some other default instances may not have been
@@ -1412,24 +2202,23 @@
     if (!field->is_repeated() &&
         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
         (field->containing_oneof() == NULL ||
-         HasDescriptorMethods(descriptor_->file()))) {
+         HasDescriptorMethods(descriptor_->file(), options_))) {
       string name;
       if (field->containing_oneof()) {
         name = classname_ + "_default_oneof_instance_->";
       }
       name += FieldName(field);
       PrintHandlingOptionalStaticInitializers(
-        descriptor_->file(), printer,
-        // With static initializers.
-        "  $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
-        // Without.
-        "  $name$_ = const_cast< $type$*>(\n"
-        "      $type$::internal_default_instance());\n",
-        // Vars.
-        "name", name,
-        "type", FieldMessageTypeName(field));
+          descriptor_->file(), options_, printer,
+          // With static initializers.
+          "  $name$_ = const_cast< $type$*>(&$type$::default_instance());\n",
+          // Without.
+          "  $name$_ = const_cast< $type$*>(\n"
+          "      $type$::internal_default_instance());\n",
+          // Vars.
+          "name", name, "type", FieldMessageTypeName(field));
     } else if (field->containing_oneof() &&
-               HasDescriptorMethods(descriptor_->file())) {
+               HasDescriptorMethods(descriptor_->file(), options_)) {
       field_generators_.get(descriptor_->field(i))
           .GenerateConstructorCode(printer);
     }
@@ -1441,7 +2230,21 @@
   // Generate the copy constructor.
   printer->Print(
     "$classname$::$classname$(const $classname$& from)\n"
-    "  : $superclass$() {\n"
+    "  : $superclass$()",
+    "classname", classname_,
+    "superclass", superclass,
+    "full_name", descriptor_->full_name());
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(
+        ",\n    _internal_metadata_(NULL)");
+  } else if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
+    printer->Print(",\n    _arena_ptr_(NULL)");
+  }
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(",\n    _any_metadata_(&type_url_, &value_)");
+  }
+  printer->Print(" {\n");
+  printer->Print(
     "  SharedCtor();\n"
     "  MergeFrom(from);\n"
     "  // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
@@ -1467,6 +2270,11 @@
   // Generate the shared destructor code.
   GenerateSharedDestructorCode(printer);
 
+  // Generate the arena-specific destructor code.
+  if (SupportsArenas(descriptor_)) {
+    GenerateArenaDestructorCode(printer);
+  }
+
   // Generate SetCachedSize.
   printer->Print(
     "void $classname$::SetCachedSize(int size) const {\n"
@@ -1477,7 +2285,7 @@
     "classname", classname_);
 
   // Only generate this member if it's not disabled.
-  if (HasDescriptorMethods(descriptor_->file()) &&
+  if (HasDescriptorMethods(descriptor_->file(), options_) &&
       !descriptor_->options().no_standard_descriptor_accessor()) {
     printer->Print(
       "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
@@ -1495,14 +2303,14 @@
     "classname", classname_);
 
   PrintHandlingOptionalStaticInitializers(
-    descriptor_->file(), printer,
-    // With static initializers.
-    "  if (default_instance_ == NULL) $adddescriptorsname$();\n",
-    // Without.
-    "  $adddescriptorsname$();\n",
-    // Vars.
-    "adddescriptorsname",
-    GlobalAddDescriptorsName(descriptor_->file()->name()));
+      descriptor_->file(), options_, printer,
+      // With static initializers.
+      "  if (default_instance_ == NULL) $adddescriptorsname$();\n",
+      // Without.
+      "  $adddescriptorsname$();\n",
+      // Vars.
+      "adddescriptorsname",
+      GlobalAddDescriptorsName(descriptor_->file()->name()));
 
   printer->Print(
     "  return *default_instance_;\n"
@@ -1512,11 +2320,23 @@
     "\n",
     "classname", classname_);
 
-  printer->Print(
-    "$classname$* $classname$::New() const {\n"
-    "  return new $classname$;\n"
-    "}\n",
-    "classname", classname_);
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(
+      "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
+      "  return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n"
+      "}\n",
+      "classname", classname_);
+  } else {
+    printer->Print(
+      "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
+      "  $classname$* n = new $classname$;\n"
+      "  if (arena != NULL) {\n"
+      "    arena->Own(n);\n"
+      "  }\n"
+      "  return n;\n"
+      "}\n",
+      "classname", classname_);
+  }
 
 }
 
@@ -1532,8 +2352,10 @@
 
 void MessageGenerator::
 GenerateClear(io::Printer* printer) {
-  printer->Print("void $classname$::Clear() {\n",
-                 "classname", classname_);
+  printer->Print(
+      "void $classname$::Clear() {\n"
+      "// @@protoc_insertion_point(message_clear_start:$full_name$)\n",
+      "classname", classname_, "full_name", descriptor_->full_name());
   printer->Indent();
 
   // Step 1: Extensions
@@ -1566,17 +2388,24 @@
 
   // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0.
   // The generated code uses two macros to help it clear runs of fields:
-  // OFFSET_OF_FIELD_ computes the offset (in bytes) of a field in the Message.
+  // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the
+  // positions of two fields in the Message.
   // ZR_ zeroes a non-empty range of fields via memset.
   const char* macros =
-      "#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \\\n"
-      "  &reinterpret_cast<$classname$*>(16)->f) - \\\n"
-      "   reinterpret_cast<char*>(16))\n\n"
-      "#define ZR_(first, last) do {                              \\\n"
-      "    size_t f = OFFSET_OF_FIELD_(first);                    \\\n"
-      "    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \\\n"
-      "    ::memset(&(first), 0, n);                              \\\n"
-      "  } while (0)\n\n";
+      "#if defined(__clang__)\n"
+      "#define ZR_HELPER_(f) \\\n"
+      "  _Pragma(\"clang diagnostic push\") \\\n"
+      "  _Pragma(\"clang diagnostic ignored \\\"-Winvalid-offsetof\\\"\") \\\n"
+      "  __builtin_offsetof($classname$, f) \\\n"
+      "  _Pragma(\"clang diagnostic pop\")\n"
+      "#else\n"
+      "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n"
+      "  &reinterpret_cast<$classname$*>(16)->f)\n"
+      "#endif\n\n"
+      "#define ZR_(first, last) do {\\\n"
+      "  ::memset(&(first), 0,\\\n"
+      "           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
+      "} while (0)\n\n";
   for (int i = 0; i < runs_of_fields_.size(); i++) {
     const vector<string>& run = runs_of_fields_[i];
     if (run.size() < 2) continue;
@@ -1616,16 +2445,19 @@
       const string& memsets = memsets_for_chunk[i / 8];
       uint32 mask = fields_mask_for_chunk[i / 8];
       int count = popcnt(mask);
+      GOOGLE_DCHECK_GE(count, 1);
       if (count == 1 ||
           (count <= 4 && count == memset_field_count_for_chunk[i / 8])) {
         // No "if" here because the chunk is trivial.
       } else {
-        printer->Print(
-          "if (_has_bits_[$index$ / 32] & $mask$) {\n",
-          "index", SimpleItoa(i / 8 * 8),
-          "mask", SimpleItoa(mask));
-        printer->Indent();
-        chunk_block_in_progress = true;
+        if (HasFieldPresence(descriptor_->file())) {
+          printer->Print(
+            "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
+            "index", SimpleItoa(i / 8 * 8),
+            "mask", SimpleItoa(mask));
+          printer->Indent();
+          chunk_block_in_progress = true;
+        }
       }
       printer->Print(memsets.c_str());
     }
@@ -1639,14 +2471,22 @@
       field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
       field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
 
-    if (should_check_bit) {
+    bool have_enclosing_if = false;
+    if (should_check_bit &&
+        // If no field presence, then always clear strings/messages as well.
+        HasFieldPresence(descriptor_->file())) {
       printer->Print("if (has_$name$()) {\n", "name", fieldname);
       printer->Indent();
+      have_enclosing_if = true;
     }
 
-    field_generators_.get(field).GenerateClearingCode(printer);
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      printer->Print("clear_$name$();\n", "name", fieldname);
+    } else {
+      field_generators_.get(field).GenerateClearingCode(printer);
+    }
 
-    if (should_check_bit) {
+    if (have_enclosing_if) {
       printer->Outdent();
       printer->Print("}\n");
     }
@@ -1658,7 +2498,7 @@
   }
   if (macros_are_needed) {
     printer->Outdent();
-    printer->Print("\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n");
+    printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n");
     printer->Indent();
   }
 
@@ -1667,7 +2507,11 @@
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (field->is_repeated()) {
-      field_generators_.get(field).GenerateClearingCode(printer);
+      if (use_dependent_base_ && IsFieldDependent(field)) {
+        printer->Print("clear_$name$();\n", "name", FieldName(field));
+      } else {
+        field_generators_.get(field).GenerateClearingCode(printer);
+      }
     }
   }
 
@@ -1678,16 +2522,30 @@
         "oneof_name", descriptor_->oneof_decl(i)->name());
   }
 
-  // Step 5: Everything else.
-  printer->Print(
-    "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+  if (HasFieldPresence(descriptor_->file())) {
+    // Step 5: Everything else.
+    printer->Print(
+      "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+  }
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print(
-      "mutable_unknown_fields()->Clear();\n");
-  } else {
-    printer->Print(
-      "mutable_unknown_fields()->clear();\n");
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+        "if (_internal_metadata_.have_unknown_fields()) {\n"
+        "  mutable_unknown_fields()->Clear();\n"
+        "}\n");
+    } else {
+      if (SupportsArenas(descriptor_)) {
+        printer->Print(
+          "_unknown_fields_.ClearToEmpty(\n"
+          "    &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n"
+          "    GetArenaNoVirtual());\n");
+      } else {
+        printer->Print(
+          "_unknown_fields_.ClearToEmptyNoArena(\n"
+          "    &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n");
+      }
+    }
   }
 
   printer->Outdent();
@@ -1698,14 +2556,19 @@
 GenerateOneofClear(io::Printer* printer) {
   // Generated function clears the active field and union case (e.g. foo_case_).
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print(
-        "void $classname$::clear_$oneofname$() {\n",
-        "classname", classname_,
-        "oneofname", descriptor_->oneof_decl(i)->name());
+    map<string, string> oneof_vars;
+    oneof_vars["classname"] = classname_;
+    oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name();
+    oneof_vars["full_name"] = descriptor_->full_name();
+    string message_class;
+
+    printer->Print(oneof_vars,
+                   "void $classname$::clear_$oneofname$() {\n"
+                   "// @@protoc_insertion_point(one_of_clear_start:"
+                   "$full_name$)\n");
     printer->Indent();
-    printer->Print(
-        "switch($oneofname$_case()) {\n",
-        "oneofname", descriptor_->oneof_decl(i)->name());
+    printer->Print(oneof_vars,
+        "switch($oneofname$_case()) {\n");
     printer->Indent();
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -1748,14 +2611,44 @@
 
 void MessageGenerator::
 GenerateSwap(io::Printer* printer) {
-  // Generate the Swap member function.
-  printer->Print("void $classname$::Swap($classname$* other) {\n",
+  if (SupportsArenas(descriptor_)) {
+    // Generate the Swap member function. This is a lightweight wrapper around
+    // UnsafeArenaSwap() / MergeFrom() with temporaries, depending on the memory
+    // ownership situation: swapping across arenas or between an arena and a
+    // heap requires copying.
+    printer->Print(
+        "void $classname$::Swap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n"
+        "    InternalSwap(other);\n"
+        "  } else {\n"
+        "    $classname$ temp;\n"
+        "    temp.MergeFrom(*this);\n"
+        "    CopyFrom(*other);\n"
+        "    other->CopyFrom(temp);\n"
+        "  }\n"
+        "}\n"
+        "void $classname$::UnsafeArenaSwap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n"
+        "  InternalSwap(other);\n"
+        "}\n",
+        "classname", classname_);
+  } else {
+    printer->Print(
+        "void $classname$::Swap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  InternalSwap(other);\n"
+        "}\n",
+        "classname", classname_);
+  }
+
+  // Generate the UnsafeArenaSwap member function.
+  printer->Print("void $classname$::InternalSwap($classname$* other) {\n",
                  "classname", classname_);
   printer->Indent();
-  printer->Print("if (other != this) {\n");
-  printer->Indent();
 
-  if (HasGeneratedMethods(descriptor_->file())) {
+  if (HasGeneratedMethods(descriptor_->file(), options_)) {
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* field = descriptor_->field(i);
       field_generators_.get(field).GenerateSwappingCode(printer);
@@ -1769,16 +2662,22 @@
         "i", SimpleItoa(i));
     }
 
-    for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
-      printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
-                     "i", SimpleItoa(i));
+    if (HasFieldPresence(descriptor_->file())) {
+      for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
+        printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
+                       "i", SimpleItoa(i));
+      }
     }
 
-    if (UseUnknownFieldSet(descriptor_->file())) {
-      printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+    // Ignore PreserveUnknownFields here - always swap internal_metadata as it
+    // may contain more than just unknown fields.
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+          "_internal_metadata_.Swap(&other->_internal_metadata_);\n");
     } else {
-      printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n");
+      printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
     }
+
     printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
     if (descriptor_->extension_range_count() > 0) {
       printer->Print("_extensions_.Swap(&other->_extensions_);\n");
@@ -1789,19 +2688,19 @@
 
   printer->Outdent();
   printer->Print("}\n");
-  printer->Outdent();
-  printer->Print("}\n");
 }
 
 void MessageGenerator::
 GenerateMergeFrom(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     // Generate the generalized MergeFrom (aka that which takes in the Message
     // base class as a parameter).
     printer->Print(
-      "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
-      "  GOOGLE_CHECK_NE(&from, this);\n",
-      "classname", classname_);
+        "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
+        "// @@protoc_insertion_point(generalized_merge_from_start:"
+        "$full_name$)\n"
+        "  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
+        "classname", classname_, "full_name", descriptor_->full_name());
     printer->Indent();
 
     // Cast the message to the proper type. If we find that the message is
@@ -1809,15 +2708,19 @@
     // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
     // for each message.
     printer->Print(
-      "const $classname$* source =\n"
-      "  ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
-      "    &from);\n"
+      "const $classname$* source = \n"
+      "    ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n"
+      "        &from);\n"
       "if (source == NULL) {\n"
+      "// @@protoc_insertion_point(generalized_merge_from_cast_fail:"
+      "$full_name$)\n"
       "  ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
       "} else {\n"
+      "// @@protoc_insertion_point(generalized_merge_from_cast_success:"
+      "$full_name$)\n"
       "  MergeFrom(*source);\n"
       "}\n",
-      "classname", classname_);
+      "classname", classname_, "full_name", descriptor_->full_name());
 
     printer->Outdent();
     printer->Print("}\n\n");
@@ -1834,9 +2737,11 @@
 
   // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
   printer->Print(
-    "void $classname$::MergeFrom(const $classname$& from) {\n"
-    "  GOOGLE_CHECK_NE(&from, this);\n",
-    "classname", classname_);
+      "void $classname$::MergeFrom(const $classname$& from) {\n"
+      "// @@protoc_insertion_point(class_specific_merge_from_start:"
+      "$full_name$)\n"
+      "  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
+      "classname", classname_, "full_name", descriptor_->full_name());
   printer->Indent();
 
   // Merge Repeated fields. These fields do not require a
@@ -1886,33 +2791,48 @@
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (!field->is_repeated() && !field->containing_oneof()) {
-      // See above in GenerateClear for an explanation of this.
-      if (i / 8 != last_index / 8 || last_index < 0) {
-        if (last_index >= 0) {
-          printer->Outdent();
-          printer->Print("}\n");
+      if (HasFieldPresence(descriptor_->file())) {
+        // See above in GenerateClear for an explanation of this.
+        if (i / 8 != last_index / 8 || last_index < 0) {
+          if (last_index >= 0) {
+            printer->Outdent();
+            printer->Print("}\n");
+          }
+          printer->Print(
+            "if (from._has_bits_[$index$ / 32] & "
+            "(0xffu << ($index$ % 32))) {\n",
+            "index", SimpleItoa(field->index()));
+          printer->Indent();
         }
-        printer->Print(
-          "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
-          "index", SimpleItoa(field->index()));
-        printer->Indent();
       }
 
       last_index = i;
 
-      printer->Print(
-        "if (from.has_$name$()) {\n",
-        "name", FieldName(field));
-      printer->Indent();
+      bool have_enclosing_if = false;
+      if (HasFieldPresence(descriptor_->file())) {
+        printer->Print(
+          "if (from.has_$name$()) {\n",
+          "name", FieldName(field));
+        printer->Indent();
+        have_enclosing_if = true;
+      } else {
+        // Merge semantics without true field presence: primitive fields are
+        // merged only if non-zero (numeric) or non-empty (string).
+        have_enclosing_if = EmitFieldNonDefaultCondition(
+            printer, "from.", field);
+      }
 
       field_generators_.get(field).GenerateMergingCode(printer);
 
-      printer->Outdent();
-      printer->Print("}\n");
+      if (have_enclosing_if) {
+        printer->Outdent();
+        printer->Print("}\n");
+      }
     }
   }
 
-  if (last_index >= 0) {
+  if (HasFieldPresence(descriptor_->file()) &&
+      last_index >= 0) {
     printer->Outdent();
     printer->Print("}\n");
   }
@@ -1921,12 +2841,18 @@
     printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
   }
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print(
-      "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
-  } else {
-    printer->Print(
-      "mutable_unknown_fields()->append(from.unknown_fields());\n");
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+        "if (from._internal_metadata_.have_unknown_fields()) {\n"
+        "  mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n"
+        "}\n");
+    } else {
+      printer->Print(
+        "if (!from.unknown_fields().empty()) {\n"
+        "  mutable_unknown_fields()->append(from.unknown_fields());\n"
+        "}\n");
+    }
   }
 
   printer->Outdent();
@@ -1935,12 +2861,14 @@
 
 void MessageGenerator::
 GenerateCopyFrom(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_->file())) {
+  if (HasDescriptorMethods(descriptor_->file(), options_)) {
     // Generate the generalized CopyFrom (aka that which takes in the Message
     // base class as a parameter).
     printer->Print(
-      "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
-      "classname", classname_);
+        "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n"
+        "// @@protoc_insertion_point(generalized_copy_from_start:"
+        "$full_name$)\n",
+        "classname", classname_, "full_name", descriptor_->full_name());
     printer->Indent();
 
     printer->Print(
@@ -1954,8 +2882,10 @@
 
   // Generate the class-specific CopyFrom.
   printer->Print(
-    "void $classname$::CopyFrom(const $classname$& from) {\n",
-    "classname", classname_);
+      "void $classname$::CopyFrom(const $classname$& from) {\n"
+      "// @@protoc_insertion_point(class_specific_copy_from_start:"
+      "$full_name$)\n",
+      "classname", classname_, "full_name", descriptor_->full_name());
   printer->Indent();
 
   printer->Print(
@@ -1977,15 +2907,15 @@
       "classname", classname_);
 
     PrintHandlingOptionalStaticInitializers(
-      descriptor_->file(), printer,
-      // With static initializers.
-      "  return _extensions_.ParseMessageSet(input, default_instance_,\n"
-      "                                      mutable_unknown_fields());\n",
-      // Without.
-      "  return _extensions_.ParseMessageSet(input, &default_instance(),\n"
-      "                                      mutable_unknown_fields());\n",
-      // Vars.
-      "classname", classname_);
+        descriptor_->file(), options_, printer,
+        // With static initializers.
+        "  return _extensions_.ParseMessageSet(input, default_instance_,\n"
+        "                                      mutable_unknown_fields());\n",
+        // Without.
+        "  return _extensions_.ParseMessageSet(input, &default_instance(),\n"
+        "                                      mutable_unknown_fields());\n",
+        // Vars.
+        "classname", classname_);
 
     printer->Print(
       "}\n");
@@ -1995,16 +2925,22 @@
   printer->Print(
     "bool $classname$::MergePartialFromCodedStream(\n"
     "    ::google::protobuf::io::CodedInputStream* input) {\n"
-    "#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n"
+    "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
     "  ::google::protobuf::uint32 tag;\n",
     "classname", classname_);
 
-  if (!UseUnknownFieldSet(descriptor_->file())) {
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file(), options_)) {
+    // Use LazyStringOutputString to avoid initializing unknown fields string
+    // unless it is actually needed. For the same reason, disable eager refresh
+    // on the CodedOutputStream.
     printer->Print(
-      "  ::google::protobuf::io::StringOutputStream unknown_fields_string(\n"
-      "      mutable_unknown_fields());\n"
+      "  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
+      "      ::google::protobuf::internal::NewPermanentCallback(\n"
+      "          &MutableUnknownFieldsFor$classname$, this));\n"
       "  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
-      "      &unknown_fields_string);\n");
+      "      &unknown_fields_string, false);\n",
+      "classname", classname_);
   }
 
   printer->Print(
@@ -2015,7 +2951,7 @@
   printer->Print("for (;;) {\n");
   printer->Indent();
 
-  scoped_array<const FieldDescriptor*> ordered_fields(
+  google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
       SortFieldsByNumber(descriptor_));
   uint32 maxtag = descriptor_->field_count() == 0 ? 0 :
       WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]);
@@ -2042,8 +2978,24 @@
 
     printer->Indent();
 
+    // Find repeated messages and groups now, to simplify what follows.
+    hash_set<int> fields_with_parse_loop;
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* field = ordered_fields[i];
+      if (field->is_repeated() &&
+          (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+           field->type() == FieldDescriptor::TYPE_GROUP)) {
+        fields_with_parse_loop.insert(i);
+      }
+    }
+
+    // need_label is true if we generated "goto parse_$name$" while handling the
+    // previous field.
+    bool need_label = false;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = ordered_fields[i];
+      const bool loops = fields_with_parse_loop.count(i) > 0;
+      const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0;
 
       PrintFieldComment(printer, field);
 
@@ -2057,14 +3009,21 @@
       printer->Print("if (tag == $commontag$) {\n",
                      "commontag", SimpleItoa(WireFormat::MakeTag(field)));
 
-      if (i > 0 || (field->is_repeated() && !field->options().packed())) {
+      if (need_label ||
+          (field->is_repeated() && !field->is_packed() && !loops)) {
         printer->Print(
-          " parse_$name$:\n",
+            " parse_$name$:\n",
+            "name", field->name());
+      }
+      if (loops) {
+        printer->Print(
+          "  DO_(input->IncrementRecursionDepth());\n"
+          " parse_loop_$name$:\n",
           "name", field->name());
       }
 
       printer->Indent();
-      if (field->options().packed()) {
+      if (field->is_packed()) {
         field_generator.GenerateMergeFromCodedStreamWithPacking(printer);
       } else {
         field_generator.GenerateMergeFromCodedStream(printer);
@@ -2072,7 +3031,7 @@
       printer->Outdent();
 
       // Emit code to parse unexpectedly packed or unpacked values.
-      if (field->is_packable() && field->options().packed()) {
+      if (field->is_packed()) {
         internal::WireFormatLite::WireType wiretype =
             WireFormat::WireTypeForFieldType(field->type());
         printer->Print("} else if (tag == $uncommontag$) {\n",
@@ -2082,7 +3041,7 @@
         printer->Indent();
         field_generator.GenerateMergeFromCodedStream(printer);
         printer->Outdent();
-      } else if (field->is_packable() && !field->options().packed()) {
+      } else if (field->is_packable() && !field->is_packed()) {
         internal::WireFormatLite::WireType wiretype =
             internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
         printer->Print("} else if (tag == $uncommontag$) {\n",
@@ -2101,26 +3060,53 @@
 
       // switch() is slow since it can't be predicted well.  Insert some if()s
       // here that attempt to predict the next tag.
-      if (field->is_repeated() && !field->options().packed()) {
-        // Expect repeats of this field.
+      // For non-packed repeated fields, expect the same tag again.
+      if (loops) {
+        printer->Print(
+          "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n",
+          "tag", SimpleItoa(WireFormat::MakeTag(field)),
+          "name", field->name());
+      } else if (field->is_repeated() && !field->is_packed()) {
         printer->Print(
           "if (input->ExpectTag($tag$)) goto parse_$name$;\n",
           "tag", SimpleItoa(WireFormat::MakeTag(field)),
           "name", field->name());
       }
 
-      if (i + 1 < descriptor_->field_count()) {
-        // Expect the next field in order.
-        const FieldDescriptor* next_field = ordered_fields[i + 1];
+      // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet?
+      bool emitted_goto_next_tag = false;
+
+      // For repeated messages/groups, we need to decrement recursion depth,
+      // unless the next tag is also for a repeated message/group.
+      if (loops) {
+        if (next_field_loops) {
+          const FieldDescriptor* next_field = ordered_fields[i + 1];
+          printer->Print(
+            "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n",
+            "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+            "next_name", next_field->name());
+          emitted_goto_next_tag = true;
+        }
         printer->Print(
-          "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
-          "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
-          "next_name", next_field->name());
-      } else {
-        // Expect EOF.
-        // TODO(kenton):  Expect group end-tag?
-        printer->Print(
-          "if (input->ExpectAtEnd()) goto success;\n");
+          "input->UnsafeDecrementRecursionDepth();\n");
+      }
+
+      // If there are more fields, expect the next one.
+      need_label = false;
+      if (!emitted_goto_next_tag) {
+        if (i + 1 == descriptor_->field_count()) {
+          // Expect EOF.
+          // TODO(kenton):  Expect group end-tag?
+          printer->Print(
+            "if (input->ExpectAtEnd()) goto success;\n");
+        } else {
+          const FieldDescriptor* next_field = ordered_fields[i + 1];
+          printer->Print(
+            "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
+            "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+            "next_name", next_field->name());
+          need_label = true;
+        }
       }
 
       printer->Print(
@@ -2171,24 +3157,33 @@
       }
     }
     printer->Print(") {\n");
-    if (UseUnknownFieldSet(descriptor_->file())) {
-      PrintHandlingOptionalStaticInitializers(
-        descriptor_->file(), printer,
-        // With static initializers.
-        "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
-        "                              mutable_unknown_fields()));\n",
-        // Without.
-        "  DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
-        "                              mutable_unknown_fields()));\n");
+    if (PreserveUnknownFields(descriptor_)) {
+      if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+        PrintHandlingOptionalStaticInitializers(
+            descriptor_->file(), options_, printer,
+            // With static initializers.
+            "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
+            "                              mutable_unknown_fields()));\n",
+            // Without.
+            "  DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
+            "                              mutable_unknown_fields()));\n");
+      } else {
+        PrintHandlingOptionalStaticInitializers(
+            descriptor_->file(), options_, printer,
+            // With static initializers.
+            "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
+            "                              &unknown_fields_stream));\n",
+            // Without.
+            "  DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
+            "                              &unknown_fields_stream));\n");
+      }
     } else {
       PrintHandlingOptionalStaticInitializers(
-        descriptor_->file(), printer,
-        // With static initializers.
-        "  DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
-        "                              &unknown_fields_stream));\n",
-        // Without.
-        "  DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
-        "                              &unknown_fields_stream));\n");
+          descriptor_->file(), options_, printer,
+          // With static initializers.
+          "  DO_(_extensions_.ParseField(tag, input, default_instance_);\n",
+          // Without.
+          "  DO_(_extensions_.ParseField(tag, input, &default_instance());\n");
     }
     printer->Print(
       "  continue;\n"
@@ -2196,14 +3191,19 @@
   }
 
   // We really don't recognize this tag.  Skip it.
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print(
-      "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
-      "      input, tag, mutable_unknown_fields()));\n");
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+        "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
+        "      input, tag, mutable_unknown_fields()));\n");
+    } else {
+      printer->Print(
+        "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
+        "    input, tag, &unknown_fields_stream));\n");
+    }
   } else {
     printer->Print(
-      "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
-      "    input, tag, &unknown_fields_stream));\n");
+      "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
   }
 
   if (descriptor_->field_count() > 0) {
@@ -2232,11 +3232,15 @@
     io::Printer* printer, const FieldDescriptor* field, bool to_array) {
   PrintFieldComment(printer, field);
 
-  if (!field->is_repeated()) {
+  bool have_enclosing_if = false;
+  if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
     printer->Print(
       "if (has_$name$()) {\n",
       "name", FieldName(field));
     printer->Indent();
+    have_enclosing_if = true;
+  } else if (!HasFieldPresence(descriptor_->file())) {
+    have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field);
   }
 
   if (to_array) {
@@ -2246,7 +3250,7 @@
     field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
   }
 
-  if (!field->is_repeated()) {
+  if (have_enclosing_if) {
     printer->Outdent();
     printer->Print("}\n");
   }
@@ -2281,7 +3285,7 @@
       "    ::google::protobuf::io::CodedOutputStream* output) const {\n"
       "  _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
       "classname", classname_);
-    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
+    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
     printer->Print(
       "  ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
       "      unknown_fields(), output);\n");
@@ -2321,7 +3325,7 @@
       "  target =\n"
       "      _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
       "classname", classname_);
-    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
+    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
     printer->Print(
       "  target = ::google::protobuf::internal::WireFormat::\n"
       "             SerializeUnknownMessageSetItemsToArray(\n"
@@ -2356,15 +3360,15 @@
 
 void MessageGenerator::
 GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
-  scoped_array<const FieldDescriptor*> ordered_fields(
+  google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
       SortFieldsByNumber(descriptor_));
 
   vector<const Descriptor::ExtensionRange*> sorted_extensions;
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
     sorted_extensions.push_back(descriptor_->extension_range(i));
   }
-  sort(sorted_extensions.begin(), sorted_extensions.end(),
-       ExtensionRangeSorter());
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeSorter());
 
   // Merge the fields and the extension ranges, both sorted by field number.
   int i, j;
@@ -2386,42 +3390,84 @@
     }
   }
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print("if (!unknown_fields().empty()) {\n");
-    printer->Indent();
-    if (to_array) {
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n");
+      printer->Indent();
+      if (to_array) {
+        printer->Print(
+          "target = "
+              "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
+          "    unknown_fields(), target);\n");
+      } else {
+        printer->Print(
+          "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+          "    unknown_fields(), output);\n");
+      }
+      printer->Outdent();
+
       printer->Print(
-        "target = "
-            "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
-        "    unknown_fields(), target);\n");
+        "}\n");
     } else {
       printer->Print(
-        "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
-        "    unknown_fields(), output);\n");
+        "output->WriteRaw(unknown_fields().data(),\n"
+        "                 static_cast<int>(unknown_fields().size()));\n");
     }
-    printer->Outdent();
-
-    printer->Print(
-      "}\n");
-  } else {
-    printer->Print(
-      "output->WriteRaw(unknown_fields().data(),\n"
-      "                 unknown_fields().size());\n");
   }
 }
 
+static vector<uint32> RequiredFieldsBitMask(const Descriptor* desc) {
+  vector<uint32> result;
+  uint32 mask = 0;
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (i > 0 && i % 32 == 0) {
+      result.push_back(mask);
+      mask = 0;
+    }
+    if (desc->field(i)->is_required()) {
+      mask |= (1 << (i & 31));
+    }
+  }
+  if (mask != 0) {
+    result.push_back(mask);
+  }
+  return result;
+}
+
+// Create an expression that evaluates to
+//  "for all i, (_has_bits_[i] & masks[i]) == masks[i]"
+// masks is allowed to be shorter than _has_bits_, but at least one element of
+// masks must be non-zero.
+static string ConditionalToCheckBitmasks(const vector<uint32>& masks) {
+  vector<string> parts;
+  for (int i = 0; i < masks.size(); i++) {
+    if (masks[i] == 0) continue;
+    string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8));
+    // Each xor evaluates to 0 if the expected bits are present.
+    parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
+  }
+  GOOGLE_CHECK(!parts.empty());
+  // If we have multiple parts, each expected to be 0, then bitwise-or them.
+  string result = parts.size() == 1 ? parts[0] :
+      StrCat("(", Join(parts, "\n       | "), ")");
+  return result + " == 0";
+}
+
 void MessageGenerator::
 GenerateByteSize(io::Printer* printer) {
   if (descriptor_->options().message_set_wire_format()) {
     // Special-case MessageSet.
     printer->Print(
-      "int $classname$::ByteSize() const {\n"
-      "  int total_size = _extensions_.MessageSetByteSize();\n",
-      "classname", classname_);
-    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
+        "int $classname$::ByteSize() const {\n"
+        "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
+        "  int total_size = _extensions_.MessageSetByteSize();\n",
+        "classname", classname_, "full_name", descriptor_->full_name());
+    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
     printer->Print(
+      "if (_internal_metadata_.have_unknown_fields()) {\n"
       "  total_size += ::google::protobuf::internal::WireFormat::\n"
-      "      ComputeUnknownMessageSetItemsSize(unknown_fields());\n");
+      "      ComputeUnknownMessageSetItemsSize(unknown_fields());\n"
+      "}\n");
     printer->Print(
       "  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
       "  _cached_size_ = total_size;\n"
@@ -2431,53 +3477,159 @@
     return;
   }
 
+  if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) {
+    // Emit a function (rarely used, we hope) that handles the required fields
+    // by checking for each one individually.
+    printer->Print(
+        "int $classname$::RequiredFieldsByteSizeFallback() const {\n"
+        "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:"
+        "$full_name$)\n",
+        "classname", classname_, "full_name", descriptor_->full_name());
+    printer->Indent();
+    printer->Print("int total_size = 0;\n");
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_required()) {
+        printer->Print("\n"
+                       "if (has_$name$()) {\n",
+                       "name", FieldName(field));
+        printer->Indent();
+        PrintFieldComment(printer, field);
+        field_generators_.get(field).GenerateByteSize(printer);
+        printer->Outdent();
+        printer->Print("}\n");
+      }
+    }
+    printer->Print("\n"
+                   "return total_size;\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
   printer->Print(
-    "int $classname$::ByteSize() const {\n",
-    "classname", classname_);
+      "int $classname$::ByteSize() const {\n"
+      "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n",
+      "classname", classname_, "full_name", descriptor_->full_name());
   printer->Indent();
   printer->Print(
     "int total_size = 0;\n"
     "\n");
 
-  int last_index = -1;
+  // Handle required fields (if any).  We expect all of them to be
+  // present, so emit one conditional that checks for that.  If they are all
+  // present then the fast path executes; otherwise the slow path executes.
+  if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) {
+    // The fast path works if all required fields are present.
+    vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(descriptor_);
+    printer->Print((string("if (") +
+                    ConditionalToCheckBitmasks(masks_for_has_bits) +
+                    ") {  // All required fields are present.\n").c_str());
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (!field->is_required()) continue;
+      PrintFieldComment(printer, field);
+      field_generators_.get(field).GenerateByteSize(printer);
+      printer->Print("\n");
+    }
+    printer->Outdent();
+    printer->Print("} else {\n"  // the slow path
+                   "  total_size += RequiredFieldsByteSizeFallback();\n"
+                   "}\n");
+  } else {
+    // num_required_fields_ <= 1: no need to be tricky
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (!field->is_required()) continue;
+      PrintFieldComment(printer, field);
+      printer->Print("if (has_$name$()) {\n",
+                     "name", FieldName(field));
+      printer->Indent();
+      field_generators_.get(field).GenerateByteSize(printer);
+      printer->Outdent();
+      printer->Print("}\n");
+    }
+  }
 
+  // Handle optional fields (worry below about repeateds, oneofs, etc.).
+  // These are handled in chunks of 8.  The first chunk is
+  // the non-requireds-non-repeateds-non-unions-non-extensions in
+  //  descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7),
+  // and the second chunk is the same for
+  //  descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15),
+  // etc.
+  hash_map<int, uint32> fields_mask_for_chunk;
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
+    if (!field->is_required() && !field->is_repeated() &&
+        !field->containing_oneof()) {
+      fields_mask_for_chunk[i / 8] |= static_cast<uint32>(1) << (i % 32);
+    }
+  }
 
-    if (!field->is_repeated() && !field->containing_oneof()) {
+  int last_index = -1;
+  bool chunk_block_in_progress = false;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!field->is_required() && !field->is_repeated() &&
+        !field->containing_oneof()) {
       // See above in GenerateClear for an explanation of this.
       // TODO(kenton):  Share code?  Unclear how to do so without
       //   over-engineering.
-      if ((i / 8) != (last_index / 8) ||
-          last_index < 0) {
-        if (last_index >= 0) {
+      if (i / 8 != last_index / 8 || last_index < 0) {
+        // End previous chunk, if there was one.
+        if (chunk_block_in_progress) {
           printer->Outdent();
           printer->Print("}\n");
+          chunk_block_in_progress = false;
         }
-        printer->Print(
-          "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
-          "index", SimpleItoa(field->index()));
-        printer->Indent();
+        // Start chunk.
+        uint32 mask = fields_mask_for_chunk[i / 8];
+        int count = popcnt(mask);
+        GOOGLE_DCHECK_GE(count, 1);
+        if (count == 1) {
+          // No "if" here because the chunk is trivial.
+        } else {
+          if (HasFieldPresence(descriptor_->file())) {
+            printer->Print(
+              "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
+              "index", SimpleItoa(i),
+              "mask", SimpleItoa(mask));
+            printer->Indent();
+            chunk_block_in_progress = true;
+          }
+        }
       }
       last_index = i;
 
       PrintFieldComment(printer, field);
 
-      printer->Print(
-        "if (has_$name$()) {\n",
-        "name", FieldName(field));
-      printer->Indent();
+      bool have_enclosing_if = false;
+      if (HasFieldPresence(descriptor_->file())) {
+        printer->Print(
+          "if (has_$name$()) {\n",
+          "name", FieldName(field));
+        printer->Indent();
+        have_enclosing_if = true;
+      } else {
+        // Without field presence: field is serialized only if it has a
+        // non-default value.
+        have_enclosing_if = EmitFieldNonDefaultCondition(
+            printer, "this->", field);
+      }
 
       field_generators_.get(field).GenerateByteSize(printer);
 
-      printer->Outdent();
-      printer->Print(
-        "}\n"
-        "\n");
+      if (have_enclosing_if) {
+        printer->Outdent();
+        printer->Print(
+          "}\n"
+          "\n");
+      }
     }
   }
 
-  if (last_index >= 0) {
+  if (chunk_block_in_progress) {
     printer->Outdent();
     printer->Print("}\n");
   }
@@ -2532,19 +3684,19 @@
       "\n");
   }
 
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print("if (!unknown_fields().empty()) {\n");
-    printer->Indent();
-    printer->Print(
-      "total_size +=\n"
-      "  ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
-      "    unknown_fields());\n");
-    printer->Outdent();
-    printer->Print("}\n");
-  } else {
-    printer->Print(
-      "total_size += unknown_fields().size();\n"
-      "\n");
+  if (PreserveUnknownFields(descriptor_)) {
+    if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+      printer->Print(
+        "if (_internal_metadata_.have_unknown_fields()) {\n"
+        "  total_size +=\n"
+        "    ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+        "      unknown_fields());\n"
+        "}\n");
+    } else {
+      printer->Print(
+        "total_size += unknown_fields().size();\n"
+        "\n");
+    }
   }
 
   // We update _cached_size_ even though this is a const method.  In theory,
@@ -2569,27 +3721,28 @@
     "classname", classname_);
   printer->Indent();
 
-  // Check that all required fields in this message are set.  We can do this
-  // most efficiently by checking 32 "has bits" at a time.
-  int has_bits_array_size = (descriptor_->field_count() + 31) / 32;
-  for (int i = 0; i < has_bits_array_size; i++) {
-    uint32 mask = 0;
-    for (int bit = 0; bit < 32; bit++) {
-      int index = i * 32 + bit;
-      if (index >= descriptor_->field_count()) break;
-      const FieldDescriptor* field = descriptor_->field(index);
+  if (HasFieldPresence(descriptor_->file())) {
+    // Check that all required fields in this message are set.  We can do this
+    // most efficiently by checking 32 "has bits" at a time.
+    int has_bits_array_size = (descriptor_->field_count() + 31) / 32;
+    for (int i = 0; i < has_bits_array_size; i++) {
+      uint32 mask = 0;
+      for (int bit = 0; bit < 32; bit++) {
+        int index = i * 32 + bit;
+        if (index >= descriptor_->field_count()) break;
+        const FieldDescriptor* field = descriptor_->field(index);
 
-      if (field->is_required()) {
-        mask |= 1 << bit;
+        if (field->is_required()) {
+          mask |= 1 << bit;
+        }
       }
-    }
 
-    if (mask != 0) {
-      char buffer[kFastToBufferSize];
-      printer->Print(
-        "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
-        "i", SimpleItoa(i),
-        "mask", FastHex32ToBuffer(mask, buffer));
+      if (mask != 0) {
+        printer->Print(
+          "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
+          "i", SimpleItoa(i),
+          "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8)));
+      }
     }
   }
 
@@ -2598,22 +3751,22 @@
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
-        !ShouldIgnoreRequiredFieldCheck(field) &&
-        HasRequiredFields(field->message_type())) {
+        !ShouldIgnoreRequiredFieldCheck(field, options_) &&
+        HasRequiredFields(field->message_type(), options_)) {
       if (field->is_repeated()) {
         printer->Print(
           "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
           " return false;\n",
           "name", FieldName(field));
       } else {
-        if (field->options().weak()) {
-          // For weak fields, use the data member (google::protobuf::Message*) instead
+        if (field->options().weak() || !field->containing_oneof()) {
+          // For weak fields, use the data member (::google::protobuf::Message*) instead
           // of the getter to avoid a link dependency on the weak message type
           // which is only forward declared.
           printer->Print(
-            "if (has_$name$()) {\n"
-            "  if (!this->$name$_->IsInitialized()) return false;\n"
-            "}\n",
+              "if (has_$name$()) {\n"
+              "  if (!this->$name$_->IsInitialized()) return false;\n"
+              "}\n",
             "name", FieldName(field));
         } else {
           printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index bfd3cec..31223e1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -36,8 +36,11 @@
 #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <set>
 #include <string>
-#include <vector>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 
@@ -58,14 +61,19 @@
 class MessageGenerator {
  public:
   // See generator.cc for the meaning of dllexport_decl.
-  explicit MessageGenerator(const Descriptor* descriptor,
-                            const Options& options);
+  MessageGenerator(const Descriptor* descriptor, const Options& options);
   ~MessageGenerator();
 
   // Header stuff.
 
-  // Generate foward declarations for this class and all its nested types.
-  void GenerateForwardDeclaration(io::Printer* printer);
+  // Return names for foward declarations of this class and all its nested
+  // types. A given key in {class,enum}_names will map from a class name to the
+  // descriptor that was responsible for its inclusion in the map. This can be
+  // used to associate the descriptor with the code generated for it.
+  void FillMessageForwardDeclarations(
+      map<string, const Descriptor*>* class_names);
+  void FillEnumForwardDeclarations(
+      map<string, const EnumDescriptor*>* enum_names);
 
   // Generate definitions of all nested enums (must come before class
   // definitions because those classes use the enums definitions).
@@ -80,7 +88,10 @@
 
   // Generate definitions of inline methods (placed at the end of the header
   // file).
-  void GenerateInlineMethods(io::Printer* printer);
+  void GenerateInlineMethods(io::Printer* printer, bool is_inline);
+
+  // Dependent methods are always inline.
+  void GenerateDependentInlineMethods(io::Printer* printer);
 
   // Source file stuff.
 
@@ -113,8 +124,11 @@
 
  private:
   // Generate declarations and definitions of accessors for fields.
+  void GenerateDependentBaseClassDefinition(io::Printer* printer);
+  void GenerateDependentFieldAccessorDeclarations(io::Printer* printer);
   void GenerateFieldAccessorDeclarations(io::Printer* printer);
-  void GenerateFieldAccessorDefinitions(io::Printer* printer);
+  void GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
+  void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
 
   // Generate the field offsets array.
   void GenerateOffsets(io::Printer* printer);
@@ -130,6 +144,8 @@
   void GenerateSharedConstructorCode(io::Printer* printer);
   // Generate the shared destructor code.
   void GenerateSharedDestructorCode(io::Printer* printer);
+  // Generate the arena-specific destructor code.
+  void GenerateArenaDestructorCode(io::Printer* printer);
 
   // Generate standard Message methods.
   void GenerateClear(io::Printer* printer);
@@ -154,15 +170,32 @@
       bool unbounded);
 
 
+  // Generates has_foo() functions and variables for singular field has-bits.
+  void GenerateSingularFieldHasBits(const FieldDescriptor* field,
+                                    map<string, string> vars,
+                                    io::Printer* printer);
+  // Generates has_foo() functions and variables for oneof field has-bits.
+  void GenerateOneofHasBits(io::Printer* printer, bool is_inline);
+  // Generates has_foo_bar() functions for oneof members.
+  void GenerateOneofMemberHasBits(const FieldDescriptor* field,
+                                  const map<string, string>& vars,
+                                  io::Printer* printer);
+  // Generates the clear_foo() method for a field.
+  void GenerateFieldClear(const FieldDescriptor* field,
+                          const map<string, string>& vars,
+                          io::Printer* printer);
+
   const Descriptor* descriptor_;
   string classname_;
   Options options_;
   FieldGeneratorMap field_generators_;
   vector< vector<string> > runs_of_fields_;  // that might be trivially cleared
-  scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
-  scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
-  scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
+  int num_required_fields_;
   bool uses_string_;
+  bool use_dependent_base_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 6ac15a5..332c026 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -49,26 +49,40 @@
                          const Options& options) {
   SetCommonFieldVariables(descriptor, variables, options);
   (*variables)["type"] = FieldMessageTypeName(descriptor);
-  (*variables)["stream_writer"] = (*variables)["declared_type"] +
-      (HasFastArraySerialization(descriptor->message_type()->file()) ?
-       "MaybeToArray" :
-       "");
+  if (descriptor->options().weak() || !descriptor->containing_oneof()) {
+    (*variables)["non_null_ptr_to_name"] =
+        StrCat("this->", (*variables)["name"], "_");
+  }
+  (*variables)["stream_writer"] =
+      (*variables)["declared_type"] +
+      (HasFastArraySerialization(descriptor->message_type()->file(), options)
+           ? "MaybeToArray"
+           : "");
   // NOTE: Escaped here to unblock proto1->proto2 migration.
   // TODO(liujisi): Extend this to apply for other conflicting methods.
   (*variables)["release_name"] =
       SafeFunctionName(descriptor->containing_type(),
                        descriptor, "release_");
   (*variables)["full_name"] = descriptor->full_name();
+  if (options.proto_h && IsFieldDependent(descriptor)) {
+    (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor);
+    (*variables)["dependent_typename"] =
+        "typename T::" + DependentTypeName(descriptor);
+  } else {
+    (*variables)["dependent_type"] = FieldMessageTypeName(descriptor);
+    (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor);
+  }
 }
 
 }  // namespace
 
 // ===================================================================
 
-MessageFieldGenerator::
-MessageFieldGenerator(const FieldDescriptor* descriptor,
-                      const Options& options)
-  : descriptor_(descriptor) {
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options)
+    : FieldGenerator(options),
+      descriptor_(descriptor),
+      dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -80,57 +94,390 @@
 }
 
 void MessageFieldGenerator::
-GenerateAccessorDeclarations(io::Printer* printer) const {
+GenerateGetterDeclaration(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const $type$& $name$() const$deprecation$;\n"
-    "inline $type$* mutable_$name$()$deprecation$;\n"
-    "inline $type$* $release_name$()$deprecation$;\n"
-    "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+      "$deprecated_attr$const $type$& $name$() const;\n");
 }
 
 void MessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+  if (!dependent_field_) {
+    return;
+  }
+  // Arena manipulation code is out-of-line in the derived message class.
   printer->Print(variables_,
-    "inline const $type$& $classname$::$name$() const {\n"
+    "$deprecated_attr$$type$* mutable_$name$();\n"
+    "$deprecated_attr$$type$* $release_name$();\n"
+    "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n");
+}
+
+void MessageFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+       "private:\n"
+       "void _slow_mutable_$name$();\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables_,
+       "void _slow_set_allocated_$name$(\n"
+       "    ::google::protobuf::Arena* message_arena, $type$** $name$);\n");
+    }
+    printer->Print(variables_,
+       "$type$* _slow_$release_name$();\n"
+       "public:\n");
+  }
+  GenerateGetterDeclaration(printer);
+  if (!dependent_field_) {
+    printer->Print(variables_,
+      "$deprecated_attr$$type$* mutable_$name$();\n"
+      "$deprecated_attr$$type$* $release_name$();\n"
+      "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n");
+  }
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "$deprecated_attr$$type$* unsafe_arena_release_$name$();\n"
+      "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n"
+      "    $type$* $name$);\n");
+  }
+}
+
+void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "void $classname$::_slow_mutable_$name$() {\n");
+      if (SupportsArenas(descriptor_->message_type())) {
+        printer->Print(variables_,
+          "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
+      } else {
+        printer->Print(variables_,
+          "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
+      }
+    printer->Print(variables_,
+      "}\n"
+      "$type$* $classname$::_slow_$release_name$() {\n"
+      "  if ($name$_ == NULL) {\n"
+      "    return NULL;\n"
+      "  } else {\n"
+      "    $type$* temp = new $type$;\n"
+      "    temp->MergeFrom(*$name$_);\n"
+      "    $name$_ = NULL;\n"
+      "    return temp;\n"
+      "  }\n"
+      "}\n"
+      "$type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $name$_;\n"
+      "  $name$_ = NULL;\n"
+      "  return temp;\n"
+      "}\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      // NOTE: the same logic is mirrored in weak_message_field.cc. Any
+      // arena-related semantics changes should be made in both places.
+      printer->Print(variables_,
+          "void $classname$::_slow_set_allocated_$name$(\n"
+          "    ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
+          "    if (message_arena != NULL && \n"
+          "        ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n"
+          "      message_arena->Own(*$name$);\n"
+          "    } else if (message_arena !=\n"
+          "               ::google::protobuf::Arena::GetArena(*$name$)) {\n"
+          "      $type$* new_$name$ = \n"
+          "            ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+          "            message_arena);\n"
+          "      new_$name$->CopyFrom(**$name$);\n"
+          "      *$name$ = new_$name$;\n"
+          "    }\n"
+          "}\n");
+    }
+    printer->Print(variables_,
+      "void $classname$::unsafe_arena_set_allocated_$name$(\n"
+      "    $type$* $name$) {\n"
+      // If we're not on an arena, free whatever we were holding before.
+      // (If we are on arena, we can just forget the earlier pointer.)
+      "  if (GetArenaNoVirtual() == NULL) {\n"
+      "    delete $name$_;\n"
+      "  }\n"
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
+      ":$full_name$)\n"
+      "}\n");
+  }
+}
+
+void MessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+  if (!dependent_field_) {
+    return;
+  }
+
+  map<string, string> variables(variables_);
+  // For the CRTP base class, all mutation methods are dependent, and so
+  // they must be in the header.
+  variables["dependent_classname"] =
+      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
+  variables["this_message"] = DependentBaseDownCast();
+  if (!variables["set_hasbit"].empty()) {
+    variables["set_hasbit"] =
+        variables["this_message"] + variables["set_hasbit"];
+  }
+  if (!variables["clear_hasbit"].empty()) {
+    variables["clear_hasbit"] =
+        variables["this_message"] + variables["clear_hasbit"];
+  }
+
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "template <class T>\n"
+      "inline $type$* $dependent_classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  if ($name$_ == NULL) {\n"
+      "    $this_message$_slow_mutable_$name$();\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_;\n"
+      "}\n"
+      "template <class T>\n"
+      "inline $type$* $dependent_classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  $clear_hasbit$\n"
+      "  if ($this_message$GetArenaNoVirtual() != NULL) {\n"
+      "    return $this_message$_slow_$release_name$();\n"
+      "  } else {\n"
+      "    $dependent_typename$* temp = $name$_;\n"
+      "    $name$_ = NULL;\n"
+      "    return temp;\n"
+      "  }\n"
+      "}\n"
+      "template <class T>\n"
+      "inline void $dependent_classname$::"
+      "set_allocated_$name$($type$* $name$) {\n"
+      "  ::google::protobuf::Arena* message_arena = $this_message$GetArenaNoVirtual();\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  if (message_arena == NULL) {\n"
+      "    delete $name$_;\n"
+      "  }\n"
+      "  if ($name$ != NULL) {\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      // If we're on an arena and the incoming message is not, simply Own() it
+      // rather than copy to the arena -- either way we need a heap dealloc,
+      // so we might as well defer it. Otherwise, if incoming message is on a
+      // different ownership domain (specific arena, or the heap) than we are,
+      // copy to our arena (or heap, as the case may be).
+      printer->Print(variables,
+        "    $this_message$_slow_set_allocated_$name$(message_arena, "
+        "&$name$);\n");
+    } else {
+      printer->Print(variables,
+        "    if (message_arena != NULL) {\n"
+        "      message_arena->Own($name$);\n"
+        "    }\n");
+    }
+    printer->Print(variables,
+      "  }\n"
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      // TODO(dlj): move insertion points to message class.
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+  } else {
+    printer->Print(variables,
+      "template <class T>\n"
+      "inline $type$* $dependent_classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  if ($name$_ == NULL) {\n"
+      "    $name$_ = new $dependent_typename$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_;\n"
+      "}\n"
+      "template <class T>\n"
+      "inline $type$* $dependent_classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  $dependent_typename$* temp = $name$_;\n"
+      "  $name$_ = NULL;\n"
+      "  return temp;\n"
+      "}\n"
+      "template <class T>\n"
+      "inline void $dependent_classname$::"
+      "set_allocated_$name$($type$* $name$) {\n"
+      "  $dependent_typename$*& $name$_ = $this_message$$name$_;\n"
+      "  delete $name$_;\n");
+
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables,
+      "  if ($name$ != NULL && static_cast< $dependent_typename$* >($name$)"
+      "->GetArena() != NULL) {\n"
+      "    $dependent_typename$* new_$name$ = new $dependent_typename$;\n"
+      "    new_$name$->CopyFrom(*$name$);\n"
+      "    $name$ = new_$name$;\n"
+      "  }\n");
+    }
+
+    printer->Print(variables,
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+  }
+}
+
+void MessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline " : "";
+  printer->Print(variables,
+    "$inline$const $type$& $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n");
 
   PrintHandlingOptionalStaticInitializers(
-    variables_, descriptor_->file(), printer,
-    // With static initializers.
-    "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
-    // Without.
-    "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
+      variables, descriptor_->file(), options_, printer,
+      // With static initializers.
+      "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
+      // Without.
+      "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
+  printer->Print(variables, "}\n");
 
-  printer->Print(variables_,
-    "}\n"
-    "inline $type$* $classname$::mutable_$name$() {\n"
-    "  set_has_$name$();\n"
-    "  if ($name$_ == NULL) $name$_ = new $type$;\n"
-    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-    "  return $name$_;\n"
-    "}\n"
-    "inline $type$* $classname$::$release_name$() {\n"
-    "  clear_has_$name$();\n"
-    "  $type$* temp = $name$_;\n"
-    "  $name$_ = NULL;\n"
-    "  return temp;\n"
-    "}\n"
-    "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
-    "  delete $name$_;\n"
-    "  $name$_ = $name$;\n"
-    "  if ($name$) {\n"
-    "    set_has_$name$();\n"
-    "  } else {\n"
-    "    clear_has_$name$();\n"
-    "  }\n"
-    "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
-    "}\n");
+  if (dependent_field_) {
+    return;
+  }
+
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  if ($name$_ == NULL) {\n"
+      "    _slow_mutable_$name$();\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_;\n"
+      "}\n"
+      "$inline$"
+      "$type$* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  if (GetArenaNoVirtual() != NULL) {\n"
+      "    return _slow_$release_name$();\n"
+      "  } else {\n"
+      "    $type$* temp = $name$_;\n"
+      "    $name$_ = NULL;\n"
+      "    return temp;\n"
+      "  }\n"
+      "}\n"
+      "$inline$ "
+      "void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
+      "  if (message_arena == NULL) {\n"
+      "    delete $name$_;\n"
+      "  }\n"
+      "  if ($name$ != NULL) {\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      // If we're on an arena and the incoming message is not, simply Own() it
+      // rather than copy to the arena -- either way we need a heap dealloc,
+      // so we might as well defer it. Otherwise, if incoming message is on a
+      // different ownership domain (specific arena, or the heap) than we are,
+      // copy to our arena (or heap, as the case may be).
+      printer->Print(variables,
+        "    _slow_set_allocated_$name$(message_arena, &$name$);\n");
+    } else {
+      printer->Print(variables,
+        "    if (message_arena != NULL) {\n"
+        "      message_arena->Own($name$);\n"
+        "    }\n");
+    }
+    printer->Print(variables,
+      "  }\n"
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+  } else {
+    printer->Print(variables,
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  if ($name$_ == NULL) {\n"
+      "    $name$_ = new $type$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_;\n"
+      "}\n"
+      "$inline$"
+      "$type$* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $name$_;\n"
+      "  $name$_ = NULL;\n"
+      "  return temp;\n"
+      "}\n"
+      "$inline$"
+      "void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "  delete $name$_;\n");
+
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables,
+      "  if ($name$ != NULL && $name$->GetArena() != NULL) {\n"
+      "    $type$* new_$name$ = new $type$;\n"
+      "    new_$name$->CopyFrom(*$name$);\n"
+      "    $name$ = new_$name$;\n"
+      "  }\n");
+    }
+
+    printer->Print(variables,
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+  }
 }
 
 void MessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "if ($name$_ != NULL) $name$_->$type$::Clear();\n");
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  if (!HasFieldPresence(descriptor_->file())) {
+    // If we don't have has-bits, message presence is indicated only by ptr !=
+    // NULL. Thus on clear, we need to delete the object.
+    printer->Print(variables,
+      "if ($this_message$GetArenaNoVirtual() == NULL && "
+      "$this_message$$name$_ != NULL) delete $this_message$$name$_;\n"
+      "$this_message$$name$_ = NULL;\n");
+  } else {
+    printer->Print(variables,
+      "if ($this_message$$name$_ != NULL) $this_message$$name$_->"
+      "$dependent_type$::Clear();\n");
+  }
 }
 
 void MessageFieldGenerator::
@@ -166,7 +513,7 @@
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
-    "  $number$, this->$name$(), output);\n");
+    "  $number$, *$non_null_ptr_to_name$, output);\n");
 }
 
 void MessageFieldGenerator::
@@ -174,7 +521,7 @@
   printer->Print(variables_,
     "target = ::google::protobuf::internal::WireFormatLite::\n"
     "  Write$declared_type$NoVirtualToArray(\n"
-    "    $number$, this->$name$(), target);\n");
+    "    $number$, *$non_null_ptr_to_name$, target);\n");
 }
 
 void MessageFieldGenerator::
@@ -182,7 +529,7 @@
   printer->Print(variables_,
     "total_size += $tag_size$ +\n"
     "  ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
-    "    this->$name$());\n");
+    "    *$non_null_ptr_to_name$);\n");
 }
 
 // ===================================================================
@@ -190,51 +537,269 @@
 MessageOneofFieldGenerator::
 MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
                            const Options& options)
-  : MessageFieldGenerator(descriptor, options) {
+  : MessageFieldGenerator(descriptor, options),
+    dependent_base_(options.proto_h) {
   SetCommonOneofFieldVariables(descriptor, &variables_);
 }
 
 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
 
+
 void MessageOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+  // Oneof field getters must be dependent as they call default_instance().
+  // Otherwise, the logic is the same as MessageFields.
+  if (!dependent_field_) {
+    return;
+  }
   printer->Print(variables_,
-    "inline const $type$& $classname$::$name$() const {\n"
-    "  return has_$name$() ? *$oneof_prefix$$name$_\n"
-    "                      : $type$::default_instance();\n"
-    "}\n"
-    "inline $type$* $classname$::mutable_$name$() {\n"
-    "  if (!has_$name$()) {\n"
-    "    clear_$oneof_name$();\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = new $type$;\n"
-    "  }\n"
-    "  return $oneof_prefix$$name$_;\n"
-    "}\n"
-    "inline $type$* $classname$::$release_name$() {\n"
-    "  if (has_$name$()) {\n"
-    "    clear_has_$oneof_name$();\n"
-    "    $type$* temp = $oneof_prefix$$name$_;\n"
-    "    $oneof_prefix$$name$_ = NULL;\n"
-    "    return temp;\n"
-    "  } else {\n"
-    "    return NULL;\n"
-    "  }\n"
-    "}\n"
-    "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
-    "  clear_$oneof_name$();\n"
-    "  if ($name$) {\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = $name$;\n"
-    "  }\n"
+      "$deprecated_attr$const $type$& $name$() const;\n");
+  MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateGetterDeclaration(io::Printer* printer) const {
+  // Oneof field getters must be dependent as they call default_instance().
+  // Unlike MessageField, this means there is no (non-dependent) getter to
+  // generate.
+  if (dependent_field_) {
+    return;
+  }
+  printer->Print(variables_,
+      "$deprecated_attr$const $type$& $name$() const;\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+  // For the CRTP base class, all mutation methods are dependent, and so
+  // they must be in the header.
+  if (!dependent_base_) {
+    return;
+  }
+  map<string, string> variables(variables_);
+  variables["inline"] = "inline ";
+  variables["dependent_classname"] =
+      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
+  variables["this_message"] = "reinterpret_cast<T*>(this)->";
+  // Const message access is needed for the dependent getter.
+  variables["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+  variables["tmpl"] = "template <class T>\n";
+  variables["field_member"] = variables["this_message"] +
+                              variables["oneof_prefix"] + variables["name"] +
+                              "_";
+  InternalGenerateInlineAccessorDefinitions(variables, printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  if (dependent_base_) {
+    return;
+  }
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline " : "";
+  variables["dependent_classname"] = variables["classname"];
+  variables["this_message"] = "";
+  variables["this_const_message"] = "";
+  variables["tmpl"] = "";
+  variables["field_member"] =
+      variables["oneof_prefix"] + variables["name"] + "_";
+  variables["dependent_type"] = variables["type"];
+  InternalGenerateInlineAccessorDefinitions(variables, printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
+  map<string, string> variables(variables_);
+  variables["field_member"] =
+      variables["oneof_prefix"] + variables["name"] + "_";
+
+  //printer->Print(variables,
+}
+
+void MessageOneofFieldGenerator::
+InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables,
+                                          io::Printer* printer) const {
+  printer->Print(variables,
+    "$tmpl$"
+    "$inline$ "
+    "const $type$& $dependent_classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+    "  return $this_const_message$has_$name$()\n"
+    "      ? *$this_const_message$$oneof_prefix$$name$_\n"
+    "      : $dependent_type$::default_instance();\n"
     "}\n");
+
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::mutable_$name$() {\n"
+      "  if (!$this_message$has_$name$()) {\n"
+      "    $this_message$clear_$oneof_name$();\n"
+      "    $this_message$set_has_$name$();\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables,
+         "    $field_member$ = \n"
+         "      ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n"
+         "      $this_message$GetArenaNoVirtual());\n");
+    } else {
+      printer->Print(variables,
+         "    $this_message$$oneof_prefix$$name$_ = \n"
+         "      ::google::protobuf::Arena::Create< $dependent_typename$ >(\n"
+         "      $this_message$GetArenaNoVirtual());\n");
+    }
+    printer->Print(variables,
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $field_member$;\n"
+      "}\n"
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  if ($this_message$has_$name$()) {\n"
+      "    $this_message$clear_has_$oneof_name$();\n"
+      "    if ($this_message$GetArenaNoVirtual() != NULL) {\n"
+      // N.B.: safe to use the underlying field pointer here because we are sure
+      // that it is non-NULL (because has_$name$() returned true).
+      "      $dependent_typename$* temp = new $dependent_typename$;\n"
+      "      temp->MergeFrom(*$field_member$);\n"
+      "      $field_member$ = NULL;\n"
+      "      return temp;\n"
+      "    } else {\n"
+      "      $dependent_typename$* temp = $field_member$;\n"
+      "      $field_member$ = NULL;\n"
+      "      return temp;\n"
+      "    }\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$tmpl$"
+      "$inline$"
+      "void $dependent_classname$::"
+      "set_allocated_$name$($type$* $name$) {\n"
+      "  $this_message$clear_$oneof_name$();\n"
+      "  if ($name$) {\n");
+
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables,
+        // If incoming message is on the heap and we are on an arena, just Own()
+        // it (see above). If it's on a different arena than we are or one of us
+        // is on the heap, we make a copy to our arena/heap.
+        "    if ($this_message$GetArenaNoVirtual() != NULL &&\n"
+        "        ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
+        "      $this_message$GetArenaNoVirtual()->Own($name$);\n"
+        "    } else if ($this_message$GetArenaNoVirtual() !=\n"
+        "               ::google::protobuf::Arena::GetArena($name$)) {\n"
+        "      $dependent_typename$* new_$name$ = \n"
+        "          ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n"
+        "          $this_message$GetArenaNoVirtual());\n"
+        "      new_$name$->CopyFrom(*$name$);\n"
+        "      $name$ = new_$name$;\n"
+        "    }\n");
+    } else {
+      printer->Print(variables,
+        "    if ($this_message$GetArenaNoVirtual() != NULL) {\n"
+        "      $this_message$GetArenaNoVirtual()->Own($name$);\n"
+        "    }\n");
+    }
+
+    printer->Print(variables,
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = $name$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n"
+      "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_release"
+      ":$full_name$)\n"
+      "  if (has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    $type$* temp = $oneof_prefix$$name$_;\n"
+      "    $oneof_prefix$$name$_ = NULL;\n"
+      "    return temp;\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$"
+      "($type$* $name$) {\n"
+      // We rely on the oneof clear method to free the earlier contents of this
+      // oneof. We can directly use the pointer we're given to set the new
+      // value.
+      "  clear_$oneof_name$();\n"
+      "  if ($name$) {\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_ = $name$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
+      "$full_name$)\n"
+      "}\n");
+  } else {
+    printer->Print(variables,
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::mutable_$name$() {\n"
+      "  if (!$this_message$has_$name$()) {\n"
+      "    $this_message$clear_$oneof_name$();\n"
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = new $dependent_typename$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $field_member$;\n"
+      "}\n"
+      "$tmpl$"
+      "$inline$"
+      "$type$* $dependent_classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  if ($this_message$has_$name$()) {\n"
+      "    $this_message$clear_has_$oneof_name$();\n"
+      "    $dependent_typename$* temp = $field_member$;\n"
+      "    $field_member$ = NULL;\n"
+      "    return temp;\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$tmpl$"
+      "$inline$"
+      "void $dependent_classname$::"
+      "set_allocated_$name$($type$* $name$) {\n"
+      "  $this_message$clear_$oneof_name$();\n"
+      "  if ($name$) {\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables,
+        "    if (static_cast< $dependent_typename$*>($name$)->"
+        "GetArena() != NULL) {\n"
+        "      $dependent_typename$* new_$name$ = new $dependent_typename$;\n"
+        "      new_$name$->CopyFrom(*$name$);\n"
+        "      $name$ = new_$name$;\n"
+        "    }\n");
+    }
+    printer->Print(variables,
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = $name$;\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
+  }
 }
 
 void MessageOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-  // if it is the active field, it cannot be NULL.
-  printer->Print(variables_,
-    "delete $oneof_prefix$$name$_;\n");
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "if ($this_message$GetArenaNoVirtual() == NULL) {\n"
+      "  delete $this_message$$oneof_prefix$$name$_;\n"
+      "}\n");
+  } else {
+    printer->Print(variables,
+      "delete $this_message$$oneof_prefix$$name$_;\n");
+  }
 }
 
 void MessageOneofFieldGenerator::
@@ -250,10 +815,12 @@
 
 // ===================================================================
 
-RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
-                              const Options& options)
-  : descriptor_(descriptor) {
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(options),
+      descriptor_(descriptor),
+      dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
+      dependent_getter_(dependent_field_ && options.safe_boundary_check) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -266,49 +833,160 @@
 }
 
 void RepeatedMessageFieldGenerator::
-GenerateAccessorDeclarations(io::Printer* printer) const {
+InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline const $type$& $name$(int index) const$deprecation$;\n"
-    "inline $type$* mutable_$name$(int index)$deprecation$;\n"
-    "inline $type$* add_$name$()$deprecation$;\n");
+    "$deprecated_attr$$type$* mutable_$name$(int index);\n"
+    "$deprecated_attr$$type$* add_$name$();\n");
+  if (dependent_getter_) {
+    printer->Print(variables_,
+      "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "    $name$() const;\n");
+  }
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-    "    $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
-    "    mutable_$name$()$deprecation$;\n");
+    "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
+    "    mutable_$name$();\n");
 }
 
 void RepeatedMessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const $type$& $classname$::$name$(int index) const {\n"
-    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-    "  return $name$_.$cppget$(index);\n"
-    "}\n"
-    "inline $type$* $classname$::mutable_$name$(int index) {\n"
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+  if (dependent_getter_) {
+    printer->Print(variables_,
+      "$deprecated_attr$const $type$& $name$(int index) const;\n");
+  }
+  if (dependent_field_) {
+    InternalGenerateTypeDependentAccessorDeclarations(printer);
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+  if (!dependent_getter_) {
+    printer->Print(variables_,
+      "$deprecated_attr$const $type$& $name$(int index) const;\n");
+  }
+  if (!dependent_field_) {
+    InternalGenerateTypeDependentAccessorDeclarations(printer);
+  }
+  if (!dependent_getter_) {
+    printer->Print(variables_,
+      "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "    $name$() const;\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+  if (!dependent_field_) {
+    return;
+  }
+  map<string, string> variables(variables_);
+  // For the CRTP base class, all mutation methods are dependent, and so
+  // they must be in the header.
+  variables["dependent_classname"] =
+      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
+  variables["this_message"] = DependentBaseDownCast();
+  variables["this_const_message"] = DependentBaseConstDownCast();
+
+  if (dependent_getter_) {
+    printer->Print(variables,
+      "template <class T>\n"
+      "inline const $type$& $dependent_classname$::$name$(int index) const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $this_const_message$$name$_.$cppget$(index);\n"
+      "}\n");
+  }
+
+  // Generate per-element accessors:
+  printer->Print(variables,
+    "template <class T>\n"
+    "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n"
+    // TODO(dlj): move insertion points
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-    "  return $name$_.Mutable(index);\n"
+    "  return $this_message$$name$_.Mutable(index);\n"
     "}\n"
-    "inline $type$* $classname$::add_$name$() {\n"
+    "template <class T>\n"
+    "inline $type$* $dependent_classname$::add_$name$() {\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
-    "  return $name$_.Add();\n"
+    "  return $this_message$$name$_.Add();\n"
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-    "$classname$::$name$() const {\n"
-    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
-    "  return $name$_;\n"
-    "}\n"
+
+
+  if (dependent_getter_) {
+    printer->Print(variables,
+      "template <class T>\n"
+      "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "$dependent_classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "  return $this_const_message$$name$_;\n"
+      "}\n");
+  }
+
+  // Generate mutable access to the entire list:
+  printer->Print(variables,
+    "template <class T>\n"
     "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
-    "$classname$::mutable_$name$() {\n"
+    "$dependent_classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
-    "  return &$name$_;\n"
+    "  return &$this_message$$name$_;\n"
     "}\n");
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline " : "";
+
+  if (!dependent_getter_) {
+    printer->Print(variables,
+      "$inline$"
+      "const $type$& $classname$::$name$(int index) const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $name$_.$cppget$(index);\n"
+      "}\n");
+  }
+
+  if (!dependent_field_) {
+    printer->Print(variables,
+      "$inline$"
+      "$type$* $classname$::mutable_$name$(int index) {\n"
+      // TODO(dlj): move insertion points
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_.Mutable(index);\n"
+      "}\n"
+      "$inline$"
+      "$type$* $classname$::add_$name$() {\n"
+      "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "  return $name$_.Add();\n"
+      "}\n");
+  }
+
+
+  if (!dependent_field_) {
+    printer->Print(variables,
+      "$inline$"
+      "::google::protobuf::RepeatedPtrField< $type$ >*\n"
+      "$classname$::mutable_$name$() {\n"
+      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
+      "  return &$name$_;\n"
+      "}\n");
+  }
+  if (!dependent_getter_) {
+    printer->Print(variables,
+      "$inline$"
+      "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+      "$classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+      "  return $name$_;\n"
+      "}\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Clear();\n");
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  printer->Print(variables, "$this_message$$name$_.Clear();\n");
 }
 
 void RepeatedMessageFieldGenerator::
@@ -318,7 +996,7 @@
 
 void RepeatedMessageFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
 }
 
 void RepeatedMessageFieldGenerator::
@@ -330,11 +1008,13 @@
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::"
+      "ReadMessageNoVirtualNoRecursionDepth(\n"
       "      input, add_$name$()));\n");
   } else {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::"
+      "ReadGroupNoVirtualNoRecursionDepth(\n"
       "      $number$, input, add_$name$()));\n");
   }
 }
@@ -342,7 +1022,7 @@
 void RepeatedMessageFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
-    "for (int i = 0; i < this->$name$_size(); i++) {\n"
+    "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
     "  ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
     "    $number$, this->$name$(i), output);\n"
     "}\n");
@@ -351,7 +1031,7 @@
 void RepeatedMessageFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
-    "for (int i = 0; i < this->$name$_size(); i++) {\n"
+    "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
     "  target = ::google::protobuf::internal::WireFormatLite::\n"
     "    Write$declared_type$NoVirtualToArray(\n"
     "      $number$, this->$name$(i), target);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 2dff314..d8d9279 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -46,14 +46,18 @@
 
 class MessageFieldGenerator : public FieldGenerator {
  public:
-  explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
-                                 const Options& options);
+  MessageFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options);
   ~MessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
+  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -64,7 +68,13 @@
   void GenerateByteSize(io::Printer* printer) const;
 
  protected:
+  void GenerateArenaManipulationCode(const map<string, string>& variables,
+                                     io::Printer* printer) const;
+
+  virtual void GenerateGetterDeclaration(io::Printer* printer) const;
+
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
   map<string, string> variables_;
 
  private:
@@ -73,30 +83,44 @@
 
 class MessageOneofFieldGenerator : public MessageFieldGenerator {
  public:
-  explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
-                                      const Options& options);
+  MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
   ~MessageOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
+  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
 
+ protected:
+  void GenerateGetterDeclaration(io::Printer* printer) const;
+
  private:
+  void InternalGenerateInlineAccessorDefinitions(
+      const map<string, string>& variables, io::Printer* printer) const;
+
+  const bool dependent_base_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
 };
 
 class RepeatedMessageFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
-                                         const Options& options);
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                const Options& options);
   ~RepeatedMessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -107,7 +131,12 @@
   void GenerateByteSize(io::Printer* printer) const;
 
  private:
+  void InternalGenerateTypeDependentAccessorDeclarations(
+      io::Printer* printer) const;
+
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
+  const bool dependent_getter_;
   map<string, string> variables_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 0c99cff..ab1d2ed 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -41,12 +41,21 @@
 namespace compiler {
 namespace cpp {
 
-// Generator options:
+// Generator options (see generator.cc for a description of each):
 struct Options {
-  Options() : safe_boundary_check(false) {
-  }
+  Options()
+      : safe_boundary_check(false),
+        proto_h(false),
+        annotate_headers(false),
+        enforce_lite(false) {}
+
   string dllexport_decl;
   bool safe_boundary_check;
+  bool proto_h;
+  bool annotate_headers;
+  bool enforce_lite;
+  string annotation_pragma_name;
+  string annotation_guard_name;
 };
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 2dbf14c..34a41d8 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -35,15 +35,19 @@
 //   worth.
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/cpp/cpp_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/printer.h>
 
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/testing/file.h>
 
 namespace google {
 namespace protobuf {
@@ -69,12 +73,106 @@
     TryInsert("test.pb.cc", "includes", context);
     TryInsert("test.pb.cc", "namespace_scope", context);
     TryInsert("test.pb.cc", "global_scope", context);
+
+    // Check field accessors for an optional int32:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
+
+    // Check field accessors for a repeated int32:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
+
+    // Check field accessors for a required string:
+    TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
+              context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
+
+    // Check field accessors for a repeated string:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+
+    // Check field accessors for an int inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
+
+    // Check field accessors for a string inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
+    TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
+
+    // Check field accessors for an optional message:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
+
+    // Check field accessors for a repeated message:
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
+              context);
+
+    // Check field accessors for a message inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
+    TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfMessage", context);
+
+    // Check field accessors for an optional enum:
+    TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
+
+    // Check field accessors for a repeated enum:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
+
+    // Check field accessors for an enum inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
+
+    // Check field accessors for a required cord:
+    TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
+
+    // Check field accessors for a repeated cord:
+    TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
+    TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
+
+    // Check field accessors for a cord inside oneof{}:
+    TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
+    TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
+    TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
+
     return true;
   }
 
   void TryInsert(const string& filename, const string& insertion_point,
                  GeneratorContext* context) const {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
@@ -88,8 +186,39 @@
   GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
                              "syntax = \"proto2\";\n"
                              "package foo;\n"
+                             "\n"
+                             "enum Thud { VALUE = 0; }\n"
+                             "\n"
                              "message Bar {\n"
                              "  message Baz {}\n"
+                             "  optional int32 optInt = 1;\n"
+                             "  repeated int32 repeatedInt = 2;\n"
+                             "\n"
+                             "  required string requiredString = 3;\n"
+                             "  repeated string repeatedString = 4;\n"
+                             "\n"
+                             "  optional Baz optMessage = 6;\n"
+                             "  repeated Baz repeatedMessage = 7;\n"
+                             "\n"
+                             "  optional Thud optEnum = 8;\n"
+                             "  repeated Thud repeatedEnum = 9;\n"
+                             "\n"
+                             "  required string requiredCord = 10 [\n"
+                             "    ctype = CORD\n"
+                             "  ];\n"
+                             "  repeated string repeatedCord = 11 [\n"
+                             "    ctype = CORD\n"
+                             "  ];\n"
+                             "\n"
+                             "  oneof Qux {\n"
+                             "    int64 oneOfInt = 20;\n"
+                             "    string oneOfString = 21;\n"
+                             "    Baz oneOfMessage = 22;\n"
+                             "    Thud oneOfEnum = 23;"
+                             "    string oneOfCord = 24 [\n"
+                             "      ctype = CORD\n"
+                             "    ];\n"
+                             "  }\n"
                              "}\n",
                              true));
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 44290a3..650f038 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -100,10 +100,9 @@
 
 // ===================================================================
 
-PrimitiveFieldGenerator::
-PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
-                        const Options& options)
-  : descriptor_(descriptor) {
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetPrimitiveVariables(descriptor, &variables_, options);
 }
 
@@ -117,19 +116,21 @@
 void PrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$() const$deprecation$;\n"
-    "inline void set_$name$($type$ value)$deprecation$;\n");
+    "$deprecated_attr$$type$ $name$() const;\n"
+    "$deprecated_attr$void set_$name$($type$ value);\n");
 }
 
 void PrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
-    "  set_has_$name$();\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n"
+    "  $set_hasbit$\n"
     "  $name$_ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
@@ -161,7 +162,7 @@
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "         $type$, $wire_format_field_type$>(\n"
     "       input, &$name$_)));\n"
-    "set_has_$name$();\n");
+    "$set_hasbit$\n");
 }
 
 void PrimitiveFieldGenerator::
@@ -204,20 +205,24 @@
 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
 
 void PrimitiveOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "    return $oneof_prefix$$name$_;\n"
     "  }\n"
     "  return $default$;\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n"
     "  if (!has_$name$()) {\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "  }\n"
     "  $oneof_prefix$$name$_ = value;\n"
+    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
 }
 
@@ -250,13 +255,12 @@
 
 // ===================================================================
 
-RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
-                                const Options& options)
-  : descriptor_(descriptor) {
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetPrimitiveVariables(descriptor, &variables_, options);
 
-  if (descriptor->options().packed()) {
+  if (descriptor->is_packed()) {
     variables_["packed_reader"] = "ReadPackedPrimitive";
     variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
   } else {
@@ -271,7 +275,8 @@
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
-  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+  if (descriptor_->is_packed() &&
+      HasGeneratedMethods(descriptor_->file(), options_)) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -280,38 +285,40 @@
 void RepeatedPrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
-    "inline $type$ $name$(int index) const$deprecation$;\n"
-    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
-    "inline void add_$name$($type$ value)$deprecation$;\n");
+    "$deprecated_attr$$type$ $name$(int index) const;\n"
+    "$deprecated_attr$void set_$name$(int index, $type$ value);\n"
+    "$deprecated_attr$void add_$name$($type$ value);\n");
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
-    "    $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
-    "    mutable_$name$()$deprecation$;\n");
+    "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n"
+    "    $name$() const;\n"
+    "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n"
+    "    mutable_$name$();\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.Get(index);\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"
     "  $name$_.Set(index, value);\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
-    "inline void $classname$::add_$name$($type$ value) {\n"
+    "$inline$ void $classname$::add_$name$($type$ value) {\n"
     "  $name$_.Add(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+    "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
@@ -330,7 +337,7 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
@@ -356,7 +363,7 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -369,7 +376,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
       "    this->$name$(i), output);\n");
@@ -383,7 +390,7 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -397,7 +404,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  target = ::google::protobuf::internal::WireFormatLite::\n"
       "    Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
@@ -427,7 +434,7 @@
       "data_size = $fixed_size$ * this->$name$_size();\n");
   }
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
       "  total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 97b5e86..655ebde 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -46,14 +46,15 @@
 
 class PrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
-                                   const Options& options);
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
   ~PrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -73,12 +74,13 @@
 
 class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
  public:
-  explicit PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
-                                        const Options& options);
+  PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options);
   ~PrimitiveOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -90,14 +92,15 @@
 
 class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
-                                           const Options& options);
+  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                  const Options& options);
   ~RepeatedPrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index a8f303d..226c2aa 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -301,7 +301,7 @@
   printer->Print(vars_,
     "    default:\n"
     "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
-    "      return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
+    "      return *static_cast< ::google::protobuf::Message*>(NULL);\n"
     "  }\n"
     "}\n"
     "\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 180d236..1d74345 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -52,9 +52,14 @@
   (*variables)["default"] = DefaultValue(descriptor);
   (*variables)["default_length"] =
       SimpleItoa(descriptor->default_value_string().length());
-  (*variables)["default_variable"] = descriptor->default_value_string().empty()
-      ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
-      : "_default_" + FieldName(descriptor) + "_";
+  string default_variable_string =
+      descriptor->default_value_string().empty()
+          ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
+          : "_default_" + FieldName(descriptor) + "_";
+  (*variables)["default_variable"] = default_variable_string;
+  (*variables)["default_value_init"] =
+      descriptor->default_value_string().empty()
+      ? "" : "*" + default_variable_string;
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
   // NOTE: Escaped here to unblock proto1->proto2 migration.
@@ -63,16 +68,17 @@
       SafeFunctionName(descriptor->containing_type(),
                        descriptor, "release_");
   (*variables)["full_name"] = descriptor->full_name();
+
+  (*variables)["string_piece"] = "::std::string";
 }
 
 }  // namespace
 
 // ===================================================================
 
-StringFieldGenerator::
-StringFieldGenerator(const FieldDescriptor* descriptor,
-                     const Options& options)
-  : descriptor_(descriptor) {
+StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
+                                           const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetStringVariables(descriptor, &variables_, options);
 }
 
@@ -80,7 +86,19 @@
 
 void StringFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
-  printer->Print(variables_, "::std::string* $name$_;\n");
+  // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for
+  // string fields, even when SupportArenas(descriptor_) == false. Why?
+  // The simple answer is to avoid unmaintainable complexity. The reflection
+  // code assumes ArenaStringPtrs. These are *almost* in-memory-compatible with
+  // string*, except for the pointer tags and related ownership semantics. We
+  // could modify the runtime code to use string* for the not-supporting-arenas
+  // case, but this would require a way to detect which type of class was
+  // generated (adding overhead and complexity to GeneratedMessageReflection)
+  // and littering the runtime code paths with conditionals. It's simpler to
+  // stick with this but use lightweight accessors that assume arena == NULL.
+  // There should be very little overhead anyway because it's just a tagged
+  // pointer in-memory.
+  printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n");
 }
 
 void StringFieldGenerator::
@@ -108,7 +126,11 @@
   // files that applied the ctype.  The field can still be accessed via the
   // reflection interface since the reflection interface is independent of
   // the string's underlying representation.
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+
+  bool unknown_ctype =
+      descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Print(
       " private:\n"
@@ -117,17 +139,23 @@
   }
 
   printer->Print(variables_,
-    "inline const ::std::string& $name$() const$deprecation$;\n"
-    "inline void set_$name$(const ::std::string& value)$deprecation$;\n"
-    "inline void set_$name$(const char* value)$deprecation$;\n"
-    "inline void set_$name$(const $pointer_type$* value, size_t size)"
-                 "$deprecation$;\n"
-    "inline ::std::string* mutable_$name$()$deprecation$;\n"
-    "inline ::std::string* $release_name$()$deprecation$;\n"
-    "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+    "$deprecated_attr$const ::std::string& $name$() const;\n"
+    "$deprecated_attr$void set_$name$(const ::std::string& value);\n"
+    "$deprecated_attr$void set_$name$(const char* value);\n"
+    "$deprecated_attr$void set_$name$(const $pointer_type$* value, size_t size)"
+                 ";\n"
+    "$deprecated_attr$::std::string* mutable_$name$();\n"
+    "$deprecated_attr$::std::string* $release_name$();\n"
+    "$deprecated_attr$void set_allocated_$name$(::std::string* $name$);\n");
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "$deprecated_attr$::std::string* unsafe_arena_release_$name$();\n"
+      "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n"
+      "    ::std::string* $name$);\n");
+  }
 
 
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Print(" public:\n");
     printer->Indent();
@@ -135,75 +163,120 @@
 }
 
 void StringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const ::std::string& $classname$::$name$() const {\n"
-    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-    "  return *$name$_;\n"
-    "}\n"
-    "inline void $classname$::set_$name$(const ::std::string& value) {\n"
-    "  set_has_$name$();\n"
-    "  if ($name$_ == $default_variable$) {\n"
-    "    $name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $name$_->assign(value);\n"
-    "  // @@protoc_insertion_point(field_set:$full_name$)\n"
-    "}\n"
-    "inline void $classname$::set_$name$(const char* value) {\n"
-    "  set_has_$name$();\n"
-    "  if ($name$_ == $default_variable$) {\n"
-    "    $name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $name$_->assign(value);\n"
-    "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
-    "}\n"
-    "inline "
-    "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
-    "  set_has_$name$();\n"
-    "  if ($name$_ == $default_variable$) {\n"
-    "    $name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
-    "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
-    "}\n"
-    "inline ::std::string* $classname$::mutable_$name$() {\n"
-    "  set_has_$name$();\n"
-    "  if ($name$_ == $default_variable$) {\n");
-  if (descriptor_->default_value_string().empty()) {
-    printer->Print(variables_,
-      "    $name$_ = new ::std::string;\n");
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $name$_.Get($default_variable$);\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.Set($default_variable$, $string_piece$(value),\n"
+      "              GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+      "}\n"
+      "$inline$ "
+      "void $classname$::set_$name$(const $pointer_type$* value,\n"
+      "    size_t size) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.Set($default_variable$, $string_piece$(\n"
+      "      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
+      "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+      "  $clear_hasbit$\n"
+      "  return $name$_.UnsafeArenaRelease($default_variable$,\n"
+      "      GetArenaNoVirtual());\n"
+      "}\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "  if ($name$ != NULL) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  $name$_.SetAllocated($default_variable$, $name$,\n"
+      "      GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n"
+      "    ::std::string* $name$) {\n"
+      "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+      "  if ($name$ != NULL) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
+      "      $name$, GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
+      "$full_name$)\n"
+      "}\n");
   } else {
-    printer->Print(variables_,
-      "    $name$_ = new ::std::string(*$default_variable$);\n");
+    // No-arena case.
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $name$_.GetNoArena($default_variable$);\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.SetNoArena($default_variable$, value);\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
+      "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+      "}\n"
+      "$inline$ "
+      "void $classname$::set_$name$(const $pointer_type$* value, "
+      "size_t size) {\n"
+      "  $set_hasbit$\n"
+      "  $name$_.SetNoArena($default_variable$,\n"
+      "      $string_piece$(reinterpret_cast<const char*>(value), size));\n"
+      "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+      "  $set_hasbit$\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $name$_.MutableNoArena($default_variable$);\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  $clear_hasbit$\n"
+      "  return $name$_.ReleaseNoArena($default_variable$);\n"
+      "}\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "  if ($name$ != NULL) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  $name$_.SetAllocatedNoArena($default_variable$, $name$);\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
   }
-  printer->Print(variables_,
-    "  }\n"
-    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-    "  return $name$_;\n"
-    "}\n"
-    "inline ::std::string* $classname$::$release_name$() {\n"
-    "  clear_has_$name$();\n"
-    "  if ($name$_ == $default_variable$) {\n"
-    "    return NULL;\n"
-    "  } else {\n"
-    "    ::std::string* temp = $name$_;\n"
-    "    $name$_ = const_cast< ::std::string*>($default_variable$);\n"
-    "    return temp;\n"
-    "  }\n"
-    "}\n"
-    "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
-    "  if ($name$_ != $default_variable$) {\n"
-    "    delete $name$_;\n"
-    "  }\n"
-    "  if ($name$) {\n"
-    "    set_has_$name$();\n"
-    "    $name$_ = $name$;\n"
-    "  } else {\n"
-    "    clear_has_$name$();\n"
-    "    $name$_ = const_cast< ::std::string*>($default_variable$);\n"
-    "  }\n"
-    "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
-    "}\n");
 }
 
 void StringFieldGenerator::
@@ -217,41 +290,61 @@
 
 void StringFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-  if (descriptor_->default_value_string().empty()) {
-    printer->Print(variables_,
-      "if ($name$_ != $default_variable$) {\n"
-      "  $name$_->clear();\n"
-      "}\n");
+  // Two-dimension specialization here: supporting arenas or not, and default
+  // value is the empty string or not. Complexity here ensures the minimal
+  // number of branches / amount of extraneous code at runtime (given that the
+  // below methods are inlined one-liners)!
+  if (SupportsArenas(descriptor_)) {
+    if (descriptor_->default_value_string().empty()) {
+      printer->Print(variables_,
+        "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n");
+    }
   } else {
-    printer->Print(variables_,
-      "if ($name$_ != $default_variable$) {\n"
-      "  $name$_->assign(*$default_variable$);\n"
-      "}\n");
+    if (descriptor_->default_value_string().empty()) {
+      printer->Print(variables_,
+        "$name$_.ClearToEmptyNoArena($default_variable$);\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_.ClearToDefaultNoArena($default_variable$);\n");
+    }
   }
 }
 
 void StringFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
-  printer->Print(variables_, "set_$name$(from.$name$());\n");
+  if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
+    // TODO(gpike): improve this
+    printer->Print(variables_, "set_$name$(from.$name$());\n");
+  } else {
+    printer->Print(variables_,
+      "$set_hasbit$\n"
+      "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n");
+  }
 }
 
 void StringFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
 }
 
 void StringFieldGenerator::
 GenerateConstructorCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$_ = const_cast< ::std::string*>($default_variable$);\n");
+      "$name$_.UnsafeSetDefault($default_variable$);\n");
 }
 
 void StringFieldGenerator::
 GenerateDestructorCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "if ($name$_ != $default_variable$) {\n"
-    "  delete $name$_;\n"
-    "}\n");
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "$name$_.Destroy($default_variable$, GetArenaNoVirtual());\n");
+  } else {
+    printer->Print(variables_,
+      "$name$_.DestroyNoArena($default_variable$);\n");
+  }
 }
 
 void StringFieldGenerator::
@@ -276,25 +369,20 @@
   printer->Print(variables_,
     "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
     "      input, this->mutable_$name$()));\n");
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::PARSE,\n"
-      "  \"$name$\");\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, true, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
 }
 
 void StringFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
-      "  \"$name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, false, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
   printer->Print(variables_,
     "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n"
@@ -303,13 +391,10 @@
 
 void StringFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "  this->$name$().data(), this->$name$().length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
-      "  \"$name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, false, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
   }
   printer->Print(variables_,
     "target =\n"
@@ -330,92 +415,218 @@
 StringOneofFieldGenerator::
 StringOneofFieldGenerator(const FieldDescriptor* descriptor,
                           const Options& options)
-  : StringFieldGenerator(descriptor, options) {
+    : StringFieldGenerator(descriptor, options),
+      dependent_field_(options.proto_h) {
   SetCommonOneofFieldVariables(descriptor, &variables_);
 }
 
 StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
 
 void StringOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const ::std::string& $classname$::$name$() const {\n"
-    "  if (has_$name$()) {\n"
-    "    return *$oneof_prefix$$name$_;\n"
-    "  }\n");
-  if (descriptor_->default_value_string().empty()) {
-    printer->Print(variables_,
-      "  return ::google::protobuf::internal::GetEmptyStringAlreadyInited();\n");
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  if (has_$name$()) {\n"
+      "    return $oneof_prefix$$name$_.Get($default_variable$);\n"
+      "  }\n"
+      "  return *$default_variable$;\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.Set($default_variable$, value,\n"
+      "      GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.Set($default_variable$,\n"
+      "      $string_piece$(value), GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+      "}\n"
+      "$inline$ "
+      "void $classname$::set_$name$(const $pointer_type$* value,\n"
+      "                             size_t size) {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n"
+      "      reinterpret_cast<const char*>(value), size),\n"
+      "      GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  return $oneof_prefix$$name$_.Mutable($default_variable$,\n"
+      "      GetArenaNoVirtual());\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  if (has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    return $oneof_prefix$$name$_.Release($default_variable$,\n"
+      "        GetArenaNoVirtual());\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
+      "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+      "  if (has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    return $oneof_prefix$$name$_.UnsafeArenaRelease(\n"
+      "        $default_variable$, GetArenaNoVirtual());\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "  if (!has_$name$()) {\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  clear_$oneof_name$();\n"
+      "  if ($name$ != NULL) {\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n"
+      "        GetArenaNoVirtual());\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
+      "::std::string* $name$) {\n"
+      "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+      "  if (!has_$name$()) {\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  clear_$oneof_name$();\n"
+      "  if ($name$) {\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, "
+      "$name$, GetArenaNoVirtual());\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
+      "$full_name$)\n"
+      "}\n");
   } else {
-    printer->Print(variables_,
-      "  return *$default_variable$;\n");
+    // No-arena case.
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  if (has_$name$()) {\n"
+      "    return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
+      "  }\n"
+      "  return *$default_variable$;\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.SetNoArena($default_variable$,\n"
+      "      $string_piece$(value));\n"
+      "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+      "}\n"
+      "$inline$ "
+      "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  $oneof_prefix$$name$_.SetNoArena($default_variable$, $string_piece$(\n"
+      "      reinterpret_cast<const char*>(value), size));\n"
+      "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
+      "  if (!has_$name$()) {\n"
+      "    clear_$oneof_name$();\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
+      "}\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "  if (has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
+      "  } else {\n"
+      "    return NULL;\n"
+      "  }\n"
+      "}\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "  if (!has_$name$()) {\n"
+      "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+      "  }\n"
+      "  clear_$oneof_name$();\n"
+      "  if ($name$ != NULL) {\n"
+      "    set_has_$name$();\n"
+      "    $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n"
+      "        $name$);\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+      "}\n");
   }
-  printer->Print(variables_,
-    "}\n"
-    "inline void $classname$::set_$name$(const ::std::string& value) {\n"
-    "  if (!has_$name$()) {\n"
-    "    clear_$oneof_name$();\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $oneof_prefix$$name$_->assign(value);\n"
-    "}\n"
-    "inline void $classname$::set_$name$(const char* value) {\n"
-    "  if (!has_$name$()) {\n"
-    "    clear_$oneof_name$();\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $oneof_prefix$$name$_->assign(value);\n"
-    "}\n"
-    "inline "
-    "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
-    "  if (!has_$name$()) {\n"
-    "    clear_$oneof_name$();\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = new ::std::string;\n"
-    "  }\n"
-    "  $oneof_prefix$$name$_->assign(\n"
-    "      reinterpret_cast<const char*>(value), size);\n"
-    "}\n"
-    "inline ::std::string* $classname$::mutable_$name$() {\n"
-    "  if (!has_$name$()) {\n"
-    "    clear_$oneof_name$();\n"
-    "    set_has_$name$();\n");
-  if (descriptor_->default_value_string().empty()) {
-    printer->Print(variables_,
-      "    $oneof_prefix$$name$_ = new ::std::string;\n");
-  } else {
-    printer->Print(variables_,
-      "    $oneof_prefix$$name$_ = new ::std::string(*$default_variable$);\n");
-  }
-  printer->Print(variables_,
-    "  }\n"
-    "  return $oneof_prefix$$name$_;\n"
-    "}\n"
-    "inline ::std::string* $classname$::$release_name$() {\n"
-    "  if (has_$name$()) {\n"
-    "    clear_has_$oneof_name$();\n"
-    "    ::std::string* temp = $oneof_prefix$$name$_;\n"
-    "    $oneof_prefix$$name$_ = NULL;\n"
-    "    return temp;\n"
-    "  } else {\n"
-    "    return NULL;\n"
-    "  }\n"
-    "}\n"
-    "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
-    "  clear_$oneof_name$();\n"
-    "  if ($name$) {\n"
-    "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = $name$;\n"
-    "  }\n"
-    "}\n");
 }
 
 void StringOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
-    printer->Print(variables_,
-      "delete $oneof_prefix$$name$_;\n");
+  map<string, string> variables(variables_);
+  if (dependent_field_) {
+    variables["this_message"] = DependentBaseDownCast();
+    // This clearing code may be in the dependent base class. If the default
+    // value is an empty string, then the $default_variable$ is a global
+    // singleton. If the default is not empty, we need to down-cast to get the
+    // default value's global singleton instance. See SetStringVariables() for
+    // possible values of default_variable.
+    if (!descriptor_->default_value_string().empty()) {
+      variables["default_variable"] =
+          DependentBaseDownCast() + variables["default_variable"];
+    }
+  } else {
+    variables["this_message"] = "";
+  }
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables,
+      "$this_message$$oneof_prefix$$name$_.Destroy($default_variable$,\n"
+      "    $this_message$GetArenaNoVirtual());\n");
+  } else {
+    printer->Print(variables,
+      "$this_message$$oneof_prefix$$name$_."
+      "DestroyNoArena($default_variable$);\n");
+  }
 }
 
 void StringOneofFieldGenerator::
@@ -425,31 +636,46 @@
 
 void StringOneofFieldGenerator::
 GenerateConstructorCode(io::Printer* printer) const {
-  if (!descriptor_->default_value_string().empty()) {
-    printer->Print(variables_,
-      "  $classname$_default_oneof_instance_->$name$_ = "
-      "$classname$::$default_variable$;\n");
-  } else {
-    printer->Print(variables_,
-      "  $classname$_default_oneof_instance_->$name$_ = "
-      "$default_variable$;\n");
-  }
+  printer->Print(variables_,
+    "  $classname$_default_oneof_instance_->$name$_.UnsafeSetDefault("
+    "$default_variable$);\n");
 }
 
 void StringOneofFieldGenerator::
 GenerateDestructorCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "if (has_$name$()) {\n"
-    "  delete $oneof_prefix$$name$_;\n"
-    "}\n");
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "if (has_$name$()) {\n"
+      "  $oneof_prefix$$name$_.Destroy($default_variable$,\n"
+      "      GetArenaNoVirtual());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (has_$name$()) {\n"
+      "  $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"
+      "}\n");
+  }
 }
 
+void StringOneofFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+    printer->Print(variables_,
+      "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+      "      input, this->mutable_$name$()));\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, true, variables_,
+        "this->$name$().data(), this->$name$().length(),\n", printer);
+  }
+}
+
+
 // ===================================================================
 
-RepeatedStringFieldGenerator::
-RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
-                             const Options& options)
-  : descriptor_(descriptor) {
+RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : FieldGenerator(options), descriptor_(descriptor) {
   SetStringVariables(descriptor, &variables_, options);
 }
 
@@ -464,7 +690,10 @@
 void RepeatedStringFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   // See comment above about unknown ctypes.
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  bool unknown_ctype =
+      descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Print(
       " private:\n"
@@ -473,26 +702,26 @@
   }
 
   printer->Print(variables_,
-    "inline const ::std::string& $name$(int index) const$deprecation$;\n"
-    "inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
-    "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
-    "inline void set_$name$(int index, const char* value)$deprecation$;\n"
-    "inline "
-    "void set_$name$(int index, const $pointer_type$* value, size_t size)"
-                 "$deprecation$;\n"
-    "inline ::std::string* add_$name$()$deprecation$;\n"
-    "inline void add_$name$(const ::std::string& value)$deprecation$;\n"
-    "inline void add_$name$(const char* value)$deprecation$;\n"
-    "inline void add_$name$(const $pointer_type$* value, size_t size)"
-                 "$deprecation$;\n");
+    "$deprecated_attr$const ::std::string& $name$(int index) const;\n"
+    "$deprecated_attr$::std::string* mutable_$name$(int index);\n"
+    "$deprecated_attr$void set_$name$(int index, const ::std::string& value);\n"
+    "$deprecated_attr$void set_$name$(int index, const char* value);\n"
+    ""
+    "$deprecated_attr$void set_$name$("
+                 "int index, const $pointer_type$* value, size_t size);\n"
+    "$deprecated_attr$::std::string* add_$name$();\n"
+    "$deprecated_attr$void add_$name$(const ::std::string& value);\n"
+    "$deprecated_attr$void add_$name$(const char* value);\n"
+    "$deprecated_attr$void add_$name$(const $pointer_type$* value, size_t size)"
+                 ";\n");
 
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
-                 "$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
-                 "$deprecation$;\n");
+    "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() "
+                 "const;\n"
+    "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+                 ";\n");
 
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Print(" public:\n");
     printer->Indent();
@@ -500,54 +729,58 @@
 }
 
 void RepeatedStringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const ::std::string& $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ const ::std::string& $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.$cppget$(index);\n"
     "}\n"
-    "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+    "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, const char* value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, const char* value) {\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
     "}\n"
-    "inline void "
+    "$inline$ void "
     "$classname$::set_$name$"
     "(int index, const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Mutable(index)->assign(\n"
     "    reinterpret_cast<const char*>(value), size);\n"
     "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
     "}\n"
-    "inline ::std::string* $classname$::add_$name$() {\n"
+    "$inline$ ::std::string* $classname$::add_$name$() {\n"
+    "  // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
     "  return $name$_.Add();\n"
     "}\n"
-    "inline void $classname$::add_$name$(const ::std::string& value) {\n"
+    "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n"
     "  $name$_.Add()->assign(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n"
-    "inline void $classname$::add_$name$(const char* value) {\n"
+    "$inline$ void $classname$::add_$name$(const char* value) {\n"
     "  $name$_.Add()->assign(value);\n"
     "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
     "}\n"
-    "inline void "
+    "$inline$ void "
     "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
     "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
+    "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
@@ -566,7 +799,7 @@
 
 void RepeatedStringFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+  printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
 }
 
 void RepeatedStringFieldGenerator::
@@ -579,14 +812,12 @@
   printer->Print(variables_,
     "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
     "      input, this->add_$name$()));\n");
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "  this->$name$(this->$name$_size() - 1).data(),\n"
-      "  this->$name$(this->$name$_size() - 1).length(),\n"
-      "  ::google::protobuf::internal::WireFormat::PARSE,\n"
-      "  \"$name$\");\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, true, variables_,
+        "this->$name$(this->$name$_size() - 1).data(),\n"
+        "this->$name$(this->$name$_size() - 1).length(),\n",
+        printer);
   }
 }
 
@@ -594,14 +825,13 @@
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
     "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "  this->$name$(i).data(), this->$name$(i).length(),\n"
-      "  ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
-      "  \"$name$\");\n");
+  printer->Indent();
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, false, variables_,
+        "this->$name$(i).data(), this->$name$(i).length(),\n", printer);
   }
+  printer->Outdent();
   printer->Print(variables_,
     "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
     "    $number$, this->$name$(i), output);\n"
@@ -612,14 +842,13 @@
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
     "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (HasUtf8Verification(descriptor_->file()) &&
-      descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    printer->Print(variables_,
-      "  ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
-      "    this->$name$(i).data(), this->$name$(i).length(),\n"
-      "    ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
-      "    \"$name$\");\n");
+  printer->Indent();
+  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+    GenerateUtf8CheckCodeForString(
+        descriptor_, options_, false, variables_,
+        "this->$name$(i).data(), this->$name$(i).length(),\n", printer);
   }
+  printer->Outdent();
   printer->Print(variables_,
     "  target = ::google::protobuf::internal::WireFormatLite::\n"
     "    Write$declared_type$ToArray($number$, this->$name$(i), target);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 86da38f..cb4e877 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -46,15 +46,16 @@
 
 class StringFieldGenerator : public FieldGenerator {
  public:
-  explicit StringFieldGenerator(const FieldDescriptor* descriptor,
-                                const Options& options);
+  StringFieldGenerator(const FieldDescriptor* descriptor,
+                       const Options& options);
   ~StringFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateStaticMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
@@ -78,31 +79,35 @@
 
 class StringOneofFieldGenerator : public StringFieldGenerator {
  public:
-  explicit StringOneofFieldGenerator(const FieldDescriptor* descriptor,
-                                     const Options& options);
+  StringOneofFieldGenerator(const FieldDescriptor* descriptor,
+                            const Options& options);
   ~StringOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateDestructorCode(io::Printer* printer) const;
+  void GenerateMergeFromCodedStream(io::Printer* printer) const;
 
  private:
+  const bool dependent_field_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
 };
 
 class RepeatedStringFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
-                                        const Options& options);
+  RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options);
   ~RepeatedStringFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 6b7f830..4e25b2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -35,6 +35,7 @@
 // This file tests that various identifiers work as field and type names even
 // though the same identifiers are used internally by the C++ code generator.
 
+syntax = "proto2";
 
 // Some generic_services option(s) added automatically.
 // See:  http://go/proto2-generic-services-default
@@ -58,7 +59,7 @@
   optional int32 total_size = 6;
   optional int32 tag = 7;
 
-  enum TestEnum { FOO = 1; }
+  enum TestEnum { FOO = 0; }
   message Data1 { repeated int32 data = 1; }
   message Data2 { repeated TestEnum data = 1; }
   message Data3 { repeated string data = 1; }
@@ -99,6 +100,8 @@
   optional uint32 int = 30;
   optional uint32 friend = 31;
   optional uint32 class = 37;
+  optional uint32 typedecl = 39;
+  optional uint32 auto = 40;
 
   // The generator used to #define a macro called "DO" inside the .cc file.
   message DO {}
@@ -116,14 +119,35 @@
   // names.
   optional DO release_do = 36;
 
-  extensions 1000 to max;
+  // For clashing local variables in Serialize and ByteSize calculation.
+  optional string target = 38;
+
+  extensions 1000 to max;  // NO_PROTO3
 }
 
-message TestConflictingSymbolNamesExtension {
-  extend TestConflictingSymbolNames {
-    repeated int32 repeated_int32_ext = 20423638 [packed=true];
-  }
-}
+message TestConflictingSymbolNamesExtension {                    // NO_PROTO3
+  extend TestConflictingSymbolNames {                            // NO_PROTO3
+    repeated int32 repeated_int32_ext = 20423638 [packed=true];  // NO_PROTO3
+  }                                                              // NO_PROTO3
+}                                                                // NO_PROTO3
+
+message TestConflictingEnumNames {  // NO_PROTO3
+  enum NestedConflictingEnum {      // NO_PROTO3
+    and = 1;                        // NO_PROTO3
+    class = 2;                      // NO_PROTO3
+    int = 3;                        // NO_PROTO3
+    typedef = 4;                    // NO_PROTO3
+    XOR = 5;                        // NO_PROTO3
+  }                                 // NO_PROTO3
+
+  optional NestedConflictingEnum conflicting_enum = 1;  // NO_PROTO3
+}  // NO_PROTO3
+
+enum ConflictingEnum {  // NO_PROTO3
+  NOT_EQ = 1;           // NO_PROTO3
+  volatile = 2;         // NO_PROTO3
+  return = 3;           // NO_PROTO3
+}  // NO_PROTO3
 
 message DummyMessage {}
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
new file mode 100644
index 0000000..cb6ca1b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
@@ -0,0 +1,43 @@
+// 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.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+  enum EnumWithLargeValue {
+    VALUE_1 = 1;
+    VALUE_MAX = 0x7fffffff;
+  }
+}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 93e1c3f..5d82946 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -47,11 +47,19 @@
 #include <google/protobuf/compiler/cpp/cpp_unittest.h>
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest_optimize_for.pb.h>
 #include <google/protobuf/unittest_embed_optimize_for.pb.h>
+#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER)
+// We exclude this large proto from cmake build because it's too large for
+// visual studio to compile (report internal errors).
+#include <google/protobuf/unittest_enormous_descriptor.pb.h>
+#endif
 #include <google/protobuf/unittest_no_generic_services.pb.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
@@ -63,7 +71,9 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/dynamic_message.h>
 
+#include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/testing/googletest.h>
@@ -127,6 +137,19 @@
             generated_decsriptor_proto.DebugString());
 }
 
+#if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER)
+// Test that generated code has proper descriptors:
+// Touch a descriptor generated from an enormous message to validate special
+// handling for descriptors exceeding the C++ standard's recommended minimum
+// limit for string literal size
+TEST(GeneratedDescriptorTest, EnormousDescriptor) {
+  const Descriptor* generated_descriptor =
+    TestEnormousDescriptor::descriptor();
+
+  EXPECT_TRUE(generated_descriptor != NULL);
+}
+#endif
+
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
 
 // ===================================================================
@@ -150,6 +173,7 @@
             &message.optional_import_message());
 }
 
+#ifndef PROTOBUF_USE_DLLS
 TEST(GeneratedMessageTest, Int32StringConversion) {
   EXPECT_EQ("971", Int32ToString(971));
   EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min));
@@ -162,6 +186,7 @@
   EXPECT_EQ("GOOGLE_LONGLONG(~0x7fffffffffffffff)", Int64ToString(kint64min));
   EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max));
 }
+#endif  // !PROTOBUF_USE_DLLS
 
 TEST(GeneratedMessageTest, FloatingPointDefaults) {
   const unittest::TestExtremeDefaultValues& extreme_default =
@@ -248,7 +273,7 @@
 
   message.set_default_string("blah");
   EXPECT_TRUE(message.has_default_string());
-  scoped_ptr<string> str(message.release_default_string());
+  google::protobuf::scoped_ptr<string> str(message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
   ASSERT_TRUE(str != NULL);
   EXPECT_EQ("blah", *str);
@@ -267,7 +292,7 @@
   EXPECT_FALSE(message.has_optional_nested_message());
 
   message.mutable_optional_nested_message()->set_bb(1);
-  scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
+  google::protobuf::scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
       message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
   ASSERT_TRUE(nest != NULL);
@@ -531,7 +556,7 @@
 
   // Construct a new version of the dynamic message via the factory.
   DynamicMessageFactory factory;
-  scoped_ptr<Message> message1;
+  google::protobuf::scoped_ptr<Message> message1;
   message1.reset(factory.GetPrototype(
                      unittest::TestAllTypes::descriptor())->New());
 
@@ -578,9 +603,9 @@
 
 TEST(GeneratedMessageTest, MergeFromSelf) {
   unittest::TestAllTypes message;
-  EXPECT_DEATH(message.MergeFrom(message), "&from");
+  EXPECT_DEATH(message.MergeFrom(message), "Check failed:.*pb[.]cc");
   EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)),
-               "&from");
+               "Check failed:.*pb[.]cc");
 }
 
 #endif  // PROTOBUF_HAS_DEATH_TEST
@@ -789,6 +814,21 @@
             message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
 }
 
+TEST(GeneratedMessageTest, TestConflictingEnumNames) {
+  protobuf_unittest::TestConflictingEnumNames message;
+  message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_);
+  EXPECT_EQ(1, message.conflicting_enum());
+  message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR);
+  EXPECT_EQ(5, message.conflicting_enum());
+
+
+  protobuf_unittest::ConflictingEnum conflicting_enum;
+  conflicting_enum = protobuf_unittest::NOT_EQ;
+  EXPECT_EQ(1, conflicting_enum);
+  conflicting_enum = protobuf_unittest::return_;
+  EXPECT_EQ(3, conflicting_enum);
+}
+
 #ifndef PROTOBUF_TEST_NO_DESCRIPTORS
 
 TEST(GeneratedMessageTest, TestOptimizedForSize) {
@@ -921,6 +961,22 @@
   EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
 }
 
+TEST(GeneratedMessageTest, ParseFromTruncated) {
+  const string long_string = string(128, 'q');
+  FileDescriptorProto p;
+  p.add_extension()->set_name(long_string);
+  const string msg = p.SerializeAsString();
+  int successful_count = 0;
+  for (int i = 0; i <= msg.size(); i++) {
+    if (p.ParseFromArray(msg.c_str(), i)) {
+      ++successful_count;
+    }
+  }
+  // We don't really care about how often we succeeded.
+  // As long as we didn't crash, we're happy.
+  EXPECT_GE(successful_count, 1);
+}
+
 // ===================================================================
 
 TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
@@ -1196,7 +1252,7 @@
       foo_(descriptor_->FindMethodByName("Foo")),
       bar_(descriptor_->FindMethodByName("Bar")),
       stub_(&mock_channel_),
-      done_(NewPermanentCallback(&DoNothing)) {}
+      done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {}
 
   virtual void SetUp() {
     ASSERT_TRUE(foo_ != NULL);
@@ -1218,7 +1274,7 @@
   unittest::FooResponse foo_response_;
   unittest::BarRequest bar_request_;
   unittest::BarResponse bar_response_;
-  scoped_ptr<Closure> done_;
+  google::protobuf::scoped_ptr<Closure> done_;
 };
 
 TEST_F(GeneratedServiceTest, GetDescriptor) {
@@ -1372,6 +1428,12 @@
       case unittest::TestOneof2::kFooString:
         EXPECT_TRUE(message.has_foo_string());
         break;
+      case unittest::TestOneof2::kFooCord:
+        EXPECT_TRUE(message.has_foo_cord());
+        break;
+      case unittest::TestOneof2::kFooStringPiece:
+        EXPECT_TRUE(message.has_foo_string_piece());
+        break;
       case unittest::TestOneof2::kFooBytes:
         EXPECT_TRUE(message.has_foo_bytes());
         break;
@@ -1384,6 +1446,9 @@
       case unittest::TestOneof2::kFoogroup:
         EXPECT_TRUE(message.has_foogroup());
         break;
+      case unittest::TestOneof2::kFooLazyMessage:
+        EXPECT_TRUE(message.has_foo_lazy_message());
+        break;
       case unittest::TestOneof2::FOO_NOT_SET:
         break;
     }
@@ -1516,7 +1581,7 @@
 
   message.set_foo_string("blah");
   EXPECT_TRUE(message.has_foo_string());
-  scoped_ptr<string> str(message.release_foo_string());
+  google::protobuf::scoped_ptr<string> str(message.release_foo_string());
   EXPECT_FALSE(message.has_foo_string());
   ASSERT_TRUE(str != NULL);
   EXPECT_EQ("blah", *str);
@@ -1570,7 +1635,7 @@
 
   message.mutable_foo_message()->set_qux_int(1);
   EXPECT_TRUE(message.has_foo_message());
-  scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
+  google::protobuf::scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
       message.release_foo_message());
   EXPECT_FALSE(message.has_foo_message());
   ASSERT_TRUE(mes != NULL);
@@ -1687,7 +1752,7 @@
   EXPECT_EQ(message2.foo_string(), "FOO");
 }
 
-TEST_F(OneofTest, CopyContructor) {
+TEST_F(OneofTest, CopyConstructor) {
   unittest::TestOneof2 message1;
   message1.set_foo_bytes("FOO");
 
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
new file mode 100644
index 0000000..edd3078
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -0,0 +1,242 @@
+// 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.
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+namespace {
+
+// A CodeGenerator that captures the FileDescriptor it's passed as a
+// FileDescriptorProto.
+class DescriptorCapturingGenerator : public CodeGenerator {
+ public:
+  // Does not own file; file must outlive the Generator.
+  explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
+      : file_(file) {}
+
+  virtual bool Generate(const FileDescriptor* file, const string& parameter,
+                        GeneratorContext* context, string* error) const {
+    file->CopyTo(file_);
+    return true;
+  }
+
+ private:
+  FileDescriptorProto* file_;
+};
+
+class CppMetadataTest : public ::testing::Test {
+ public:
+  // Adds a file with name `filename` and content `data`.
+  void AddFile(const string& filename, const string& data) {
+    GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
+                               true));
+  }
+
+  // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
+  // code from the previously added file with name `filename`. Returns true on
+  // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
+  // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
+  bool CaptureMetadata(const string& filename, FileDescriptorProto* file,
+                       string* pb_h, GeneratedCodeInfo* pb_h_info,
+                       string* proto_h, GeneratedCodeInfo* proto_h_info,
+                       string* pb_cc) {
+    google::protobuf::compiler::CommandLineInterface cli;
+    cli.SetInputsAreProtoPathRelative(true);
+
+    CppGenerator cpp_generator;
+    DescriptorCapturingGenerator capturing_generator(file);
+    cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
+    cli.RegisterGenerator("--capture_out", &capturing_generator, "");
+
+    string proto_path = "-I" + TestTempDir();
+    string cpp_out =
+        "--cpp_out=annotate_headers=true,"
+        "annotation_pragma_name=pragma_name,"
+        "annotation_guard_name=guard_name:" +
+        TestTempDir();
+    string capture_out = "--capture_out=" + TestTempDir();
+
+    const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
+                          capture_out.c_str(), filename.c_str()};
+
+    if (cli.Run(5, argv) != 0) {
+      return false;
+    }
+
+    string output_base = TestTempDir() + "/" + StripProto(filename);
+
+    if (pb_cc != NULL) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.cc", pb_cc, true));
+    }
+
+    if (pb_h != NULL && pb_h_info != NULL) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.h", pb_h, true));
+      if (!DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
+        return false;
+      }
+    }
+
+    if (proto_h != NULL && proto_h_info != NULL) {
+      GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
+                                 true));
+      if (!DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+ private:
+  // Decodes GeneratedCodeInfo stored in path and copies it to info.
+  // Returns true on success.
+  bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {
+    string data;
+    GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
+    io::ArrayInputStream input(data.data(), data.size());
+    return info->ParseFromZeroCopyStream(&input);
+  }
+};
+
+const char kSmallTestFile[] =
+    "syntax = \"proto2\";\n"
+    "package foo;\n"
+    "enum Enum { VALUE = 0; }\n"
+    "message Message { }\n";
+
+// Finds the Annotation for a given source file and path (or returns null if it
+// couldn't).
+const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
+    const GeneratedCodeInfo& info, const string& source_file,
+    const vector<int>& path) {
+  for (int i = 0; i < info.annotation_size(); ++i) {
+    const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
+    if (annotation->source_file() != source_file ||
+        annotation->path_size() != path.size()) {
+      continue;
+    }
+    int node = 0;
+    for (; node < path.size(); ++node) {
+      if (annotation->path(node) != path[node]) {
+        break;
+      }
+    }
+    if (node == path.size()) {
+      return annotation;
+    }
+  }
+  return NULL;
+}
+
+// Returns true if the provided annotation covers a given substring in
+// file_content.
+bool AnnotationMatchesSubstring(const string& file_content,
+                                const GeneratedCodeInfo::Annotation* annotation,
+                                const string& expected_text) {
+  uint32 begin = annotation->begin();
+  uint32 end = annotation->end();
+  if (end < begin || end > file_content.size()) {
+    return false;
+  }
+  return file_content.substr(begin, end - begin) == expected_text;
+}
+
+TEST_F(CppMetadataTest, CapturesEnumNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_EQ("Enum", file.enum_type(0).name());
+  vector<int> enum_path;
+  enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+  enum_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* enum_annotation =
+      FindAnnotationOnPath(info, "test.proto", enum_path);
+  EXPECT_TRUE(NULL != enum_annotation);
+  EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
+}
+
+TEST_F(CppMetadataTest, AddsPragma) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos);
+  EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
+              string::npos);
+}
+
+TEST_F(CppMetadataTest, CapturesMessageNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  vector<int> message_path;
+  message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+  message_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* message_annotation =
+      FindAnnotationOnPath(info, "test.proto", message_path);
+  EXPECT_TRUE(NULL != message_annotation);
+  EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
+}
+
+}  // namespace
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
new file mode 100644
index 0000000..587e022
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
@@ -0,0 +1,114 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// Functions to create C# XML documentation comments.
+// Currently this only includes documentation comments containing text specified as comments
+// in the .proto file; documentation comments generated just from field/message/enum/proto names
+// is inlined in the relevant code. If more control is required, that code can be moved here.
+
+void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
+    string comments = location.leading_comments.empty() ?
+        location.trailing_comments : location.leading_comments;
+    if (comments.empty()) {
+        return;
+    }
+    // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+    // node of a summary element, not part of an attribute.
+    comments = StringReplace(comments, "&", "&amp;", true);
+    comments = StringReplace(comments, "<", "&lt;", true);
+    vector<string> lines = Split(comments, "\n", false /* skip_empty */);
+    // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+    // but that needs to be part of a bigger effort to understand the markdown better anyway.
+    printer->Print("/// <summary>\n");
+    bool last_was_empty = false;
+    // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+    // to preserve the blank lines themselves, as this is relevant in the markdown.
+    // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+    // (We don't skip "just whitespace" lines, either.)
+    for (std::vector<string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+        string line = *it;
+        if (line.empty()) {
+            last_was_empty = true;
+        } else {
+            if (last_was_empty) {
+                printer->Print("///\n");
+            }
+            last_was_empty = false;
+            printer->Print("/// $line$\n", "line", *it);
+        }
+    }
+    printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(
+    io::Printer* printer, const DescriptorType* descriptor) {
+    SourceLocation location;
+    if (descriptor->GetSourceLocation(&location)) {
+        WriteDocCommentBodyImpl(printer, location);
+    }
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+    WriteDocCommentBody(printer, message);
+}
+
+void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) {
+    WriteDocCommentBody(printer, field);
+}
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) {
+    WriteDocCommentBody(printer, enumDescriptor);
+}
+void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) {
+    WriteDocCommentBody(printer, value);
+}
+
+void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) {
+    WriteDocCommentBody(printer, method);
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_doc_comment.h b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
new file mode 100644
index 0000000..75eb0ea
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
@@ -0,0 +1,51 @@
+// 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.
+
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+    void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+    void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field);
+    void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor);
+    void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value);
+    void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method);
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc
new file mode 100644
index 0000000..bdfcc2b
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -0,0 +1,95 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) :
+    SourceGeneratorBase(descriptor->file(), options),
+    descriptor_(descriptor) {
+}
+
+EnumGenerator::~EnumGenerator() {
+}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+  WriteEnumDocComment(printer, descriptor_);
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print("$access_level$ enum $name$ {\n",
+                 "access_level", class_access_level(),
+                 "name", descriptor_->name());
+  printer->Indent();
+  std::set<string> used_names;
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+      WriteEnumValueDocComment(printer, descriptor_->value(i));
+      string original_name = descriptor_->value(i)->name();
+      string name = options()->legacy_enum_values
+          ? descriptor_->value(i)->name()
+          : GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
+      // Make sure we don't get any duplicate names due to prefix removal.
+      while (!used_names.insert(name).second) {
+        // It's possible we'll end up giving this warning multiple times, but that's better than not at all.
+        GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name
+          << ") in " << descriptor_->name() << "; adding underscore to distinguish";
+        name += "_";
+      }
+      printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n",
+         "original_name", original_name,
+         "name", name,
+         "number", SimpleItoa(descriptor_->value(i)->number()));         
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Print("\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h
new file mode 100644
index 0000000..8925cdf
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.h
@@ -0,0 +1,63 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class EnumGenerator : public SourceGeneratorBase {
+ public:
+  EnumGenerator(const EnumDescriptor* descriptor, const Options* options);
+  ~EnumGenerator();
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const EnumDescriptor* descriptor_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
new file mode 100644
index 0000000..67c0b59
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
@@ -0,0 +1,120 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       int fieldOrdinal, const Options *options)
+    : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) {
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {
+}
+
+void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = ($type_name$) input.ReadEnum();\n");
+}
+
+void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "if ($has_property_check$) {\n"
+    "  output.WriteRawTag($tag_bytes$);\n"
+    "  output.WriteEnum((int) $property_name$);\n"
+    "}\n");
+}
+
+void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+      "  size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
+    "}\n");
+}
+
+void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+    printer->Print(
+        variables_,
+        "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)");
+}
+
+EnumOneofFieldGenerator::EnumOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+  : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) {
+}
+
+EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
+}
+
+void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  // TODO(jonskeet): What about if we read the default value?
+  printer->Print(
+    variables_,
+    "$oneof_name$_ = input.ReadEnum();\n"
+    "$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n");
+}
+
+void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  output.WriteRawTag($tag_bytes$);\n"
+    "  output.WriteEnum((int) $property_name$);\n"
+    "}\n");
+}
+
+void EnumOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
+    "}\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
new file mode 100644
index 0000000..9b7669b
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class EnumFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+  EnumFieldGenerator(const FieldDescriptor* descriptor,
+                     int fieldOrdinal,
+                     const Options *options);
+  ~EnumFieldGenerator();
+
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
+ public:
+  EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
+                          int fieldOrdinal,
+                          const Options *options);
+  ~EnumOneofFieldGenerator();
+
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
new file mode 100644
index 0000000..e3c3404
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -0,0 +1,429 @@
+// 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.
+
+#include <limits>
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+void FieldGeneratorBase::SetCommonFieldVariables(
+    map<string, string>* variables) {
+  // Note: this will be valid even though the tag emitted for packed and unpacked versions of
+  // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
+  // never effects the tag size.
+  int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
+  uint tag = internal::WireFormat::MakeTag(descriptor_);
+  uint8 tag_array[5];
+  io::CodedOutputStream::WriteTagToArray(tag, tag_array);
+  string tag_bytes = SimpleItoa(tag_array[0]);
+  for (int i = 1; i < tag_size; i++) {
+    tag_bytes += ", " + SimpleItoa(tag_array[i]);
+  }
+
+  (*variables)["access_level"] = "public";
+  (*variables)["tag"] = SimpleItoa(tag);
+  (*variables)["tag_size"] = SimpleItoa(tag_size);
+  (*variables)["tag_bytes"] = tag_bytes;
+
+  (*variables)["property_name"] = property_name();
+  (*variables)["type_name"] = type_name();
+  (*variables)["name"] = name();
+  (*variables)["descriptor_name"] = descriptor_->name();
+  (*variables)["default_value"] = default_value();
+  if (has_default_value()) {
+    (*variables)["name_def_message"] =
+      (*variables)["name"] + "_ = " + (*variables)["default_value"];
+  } else {
+    (*variables)["name_def_message"] = (*variables)["name"] + "_";
+  }
+  (*variables)["capitalized_type_name"] = capitalized_type_name();
+  (*variables)["number"] = number();
+  (*variables)["has_property_check"] =
+    (*variables)["property_name"] + " != " + (*variables)["default_value"];
+  (*variables)["other_has_property_check"] = "other." +
+    (*variables)["property_name"] + " != " + (*variables)["default_value"];
+}
+
+void FieldGeneratorBase::SetCommonOneofFieldVariables(
+    map<string, string>* variables) {
+  (*variables)["oneof_name"] = oneof_name();
+  (*variables)["has_property_check"] =
+    oneof_name() + "Case_ == " + oneof_property_name() +
+    "OneofCase." + property_name();
+  (*variables)["oneof_property_name"] = oneof_property_name();
+}
+
+FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
+                                       int fieldOrdinal, const Options* options)
+    : SourceGeneratorBase(descriptor->file(), options),
+      descriptor_(descriptor),
+      fieldOrdinal_(fieldOrdinal) {
+  SetCommonFieldVariables(&variables_);
+}
+
+FieldGeneratorBase::~FieldGeneratorBase() {
+}
+
+void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
+  // No-op: only message fields and repeated fields need
+  // special handling for freezing, so default to not generating any code.
+}
+
+void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
+    // No-op: expect this to be overridden by appropriate types.
+    // Could fail if we get called here though...
+}
+
+void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
+  if (descriptor_->options().deprecated())
+  {
+    printer->Print("[global::System.ObsoleteAttribute()]\n");
+  }
+}
+
+void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
+  AddDeprecatedFlag(printer);
+}
+
+std::string FieldGeneratorBase::oneof_property_name() {
+  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
+}
+
+std::string FieldGeneratorBase::oneof_name() {
+  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
+}
+
+std::string FieldGeneratorBase::property_name() {
+  return GetPropertyName(descriptor_);
+}
+
+std::string FieldGeneratorBase::name() {
+  return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
+}
+
+std::string FieldGeneratorBase::type_name() {
+  return type_name(descriptor_);
+}
+
+std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
+  switch (descriptor->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      return GetClassName(descriptor->enum_type());
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+      if (IsWrapperType(descriptor)) {
+        const FieldDescriptor* wrapped_field =
+            descriptor->message_type()->field(0);
+        string wrapped_field_type_name = type_name(wrapped_field);
+        // String and ByteString go to the same type; other wrapped types
+        // go to the nullable equivalent.
+        if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
+            wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
+          return wrapped_field_type_name;
+        } else {
+          return wrapped_field_type_name + "?";
+        }
+      }
+      return GetClassName(descriptor->message_type());
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::TYPE_INT64:
+      return "long";
+    case FieldDescriptor::TYPE_UINT64:
+      return "ulong";
+    case FieldDescriptor::TYPE_INT32:
+      return "int";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "ulong";
+    case FieldDescriptor::TYPE_FIXED32:
+      return "uint";
+    case FieldDescriptor::TYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::TYPE_STRING:
+      return "string";
+    case FieldDescriptor::TYPE_BYTES:
+      return "pb::ByteString";
+    case FieldDescriptor::TYPE_UINT32:
+      return "uint";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "int";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "long";
+    case FieldDescriptor::TYPE_SINT32:
+      return "int";
+    case FieldDescriptor::TYPE_SINT64:
+      return "long";
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return "";
+  }
+}
+
+bool FieldGeneratorBase::has_default_value() {
+  switch (descriptor_->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+      return true;
+    case FieldDescriptor::TYPE_DOUBLE:
+      return descriptor_->default_value_double() != 0.0;
+    case FieldDescriptor::TYPE_FLOAT:
+      return descriptor_->default_value_float() != 0.0;
+    case FieldDescriptor::TYPE_INT64:
+      return descriptor_->default_value_int64() != 0L;
+    case FieldDescriptor::TYPE_UINT64:
+      return descriptor_->default_value_uint64() != 0L;
+    case FieldDescriptor::TYPE_INT32:
+      return descriptor_->default_value_int32() != 0;
+    case FieldDescriptor::TYPE_FIXED64:
+      return descriptor_->default_value_uint64() != 0L;
+    case FieldDescriptor::TYPE_FIXED32:
+      return descriptor_->default_value_uint32() != 0;
+    case FieldDescriptor::TYPE_BOOL:
+      return descriptor_->default_value_bool();
+    case FieldDescriptor::TYPE_STRING:
+      return true;
+    case FieldDescriptor::TYPE_BYTES:
+      return true;
+    case FieldDescriptor::TYPE_UINT32:
+      return descriptor_->default_value_uint32() != 0;
+    case FieldDescriptor::TYPE_SFIXED32:
+      return descriptor_->default_value_int32() != 0;
+    case FieldDescriptor::TYPE_SFIXED64:
+      return descriptor_->default_value_int64() != 0L;
+    case FieldDescriptor::TYPE_SINT32:
+      return descriptor_->default_value_int32() != 0;
+    case FieldDescriptor::TYPE_SINT64:
+      return descriptor_->default_value_int64() != 0L;
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return true;
+  }
+}
+
+bool FieldGeneratorBase::is_nullable_type() {
+  switch (descriptor_->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_BOOL:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+      return false;
+
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      return true;
+
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return true;
+  }
+}
+
+bool AllPrintableAscii(const std::string& text) {
+  for(int i = 0; i < text.size(); i++) {
+    if (text[i] < 0x20 || text[i] > 0x7e) {
+      return false;
+    }
+  }
+  return true;
+}
+
+std::string FieldGeneratorBase::GetStringDefaultValueInternal() {
+  // No other default values needed for proto3...
+  return "\"\"";
+}
+
+std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
+  // No other default values needed for proto3...
+  return "pb::ByteString.Empty";
+}
+
+std::string FieldGeneratorBase::default_value() {
+    return default_value(descriptor_);
+}
+
+std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
+  switch (descriptor->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      // All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to
+      // any C# enum. This means we don't need to work out what we actually mapped the enum value name to.
+     return "0";
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+      if (IsWrapperType(descriptor)) {
+        const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+        return default_value(wrapped_field);
+      } else {
+        return "null";
+      }
+    case FieldDescriptor::TYPE_DOUBLE: {
+      double value = descriptor->default_value_double();
+      if (value == numeric_limits<double>::infinity()) {
+        return "double.PositiveInfinity";
+      } else if (value == -numeric_limits<double>::infinity()) {
+        return "double.NegativeInfinity";
+      } else if (MathLimits<double>::IsNaN(value)) {
+        return "double.NaN";
+      }
+      return SimpleDtoa(value) + "D";
+    }
+    case FieldDescriptor::TYPE_FLOAT: {
+      float value = descriptor->default_value_float();
+      if (value == numeric_limits<float>::infinity()) {
+        return "float.PositiveInfinity";
+      } else if (value == -numeric_limits<float>::infinity()) {
+        return "float.NegativeInfinity";
+      } else if (MathLimits<float>::IsNaN(value)) {
+        return "float.NaN";
+      }
+      return SimpleFtoa(value) + "F";
+    }
+    case FieldDescriptor::TYPE_INT64:
+      return SimpleItoa(descriptor->default_value_int64()) + "L";
+    case FieldDescriptor::TYPE_UINT64:
+      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
+    case FieldDescriptor::TYPE_INT32:
+      return SimpleItoa(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_FIXED64:
+      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
+    case FieldDescriptor::TYPE_FIXED32:
+      return SimpleItoa(descriptor->default_value_uint32());
+    case FieldDescriptor::TYPE_BOOL:
+      if (descriptor->default_value_bool()) {
+        return "true";
+      } else {
+        return "false";
+      }
+    case FieldDescriptor::TYPE_STRING:
+      return GetStringDefaultValueInternal();
+    case FieldDescriptor::TYPE_BYTES:
+      return GetBytesDefaultValueInternal();
+    case FieldDescriptor::TYPE_UINT32:
+      return SimpleItoa(descriptor->default_value_uint32());
+    case FieldDescriptor::TYPE_SFIXED32:
+      return SimpleItoa(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_SFIXED64:
+      return SimpleItoa(descriptor->default_value_int64()) + "L";
+    case FieldDescriptor::TYPE_SINT32:
+      return SimpleItoa(descriptor->default_value_int32());
+    case FieldDescriptor::TYPE_SINT64:
+      return SimpleItoa(descriptor->default_value_int64()) + "L";
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return "";
+  }
+}
+
+std::string FieldGeneratorBase::number() {
+  return SimpleItoa(descriptor_->number());
+}
+
+std::string FieldGeneratorBase::capitalized_type_name() {
+  switch (descriptor_->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      return "Enum";
+    case FieldDescriptor::TYPE_MESSAGE:
+      return "Message";
+    case FieldDescriptor::TYPE_GROUP:
+      return "Group";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "Double";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "Float";
+    case FieldDescriptor::TYPE_INT64:
+      return "Int64";
+    case FieldDescriptor::TYPE_UINT64:
+      return "UInt64";
+    case FieldDescriptor::TYPE_INT32:
+      return "Int32";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "Fixed64";
+    case FieldDescriptor::TYPE_FIXED32:
+      return "Fixed32";
+    case FieldDescriptor::TYPE_BOOL:
+      return "Bool";
+    case FieldDescriptor::TYPE_STRING:
+      return "String";
+    case FieldDescriptor::TYPE_BYTES:
+      return "Bytes";
+    case FieldDescriptor::TYPE_UINT32:
+      return "UInt32";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "SFixed32";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "SFixed64";
+    case FieldDescriptor::TYPE_SINT32:
+      return "SInt32";
+    case FieldDescriptor::TYPE_SINT64:
+      return "SInt64";
+    default:
+      GOOGLE_LOG(FATAL)<< "Unknown field type.";
+      return "";
+  }
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h
new file mode 100644
index 0000000..4109f3c
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h
@@ -0,0 +1,105 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+
+#include <string>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase : public SourceGeneratorBase {
+ public:
+  FieldGeneratorBase(const FieldDescriptor* descriptor,
+                     int fieldOrdinal,
+                     const Options* options);
+  ~FieldGeneratorBase();
+
+  virtual void GenerateCloningCode(io::Printer* printer) = 0;
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer) = 0;
+  virtual void GenerateMergingCode(io::Printer* printer) = 0;
+  virtual void GenerateParsingCode(io::Printer* printer) = 0;
+  virtual void GenerateSerializationCode(io::Printer* printer) = 0;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) = 0;
+
+  virtual void WriteHash(io::Printer* printer) = 0;
+  virtual void WriteEquals(io::Printer* printer) = 0;
+  // Currently unused, as we use reflection to generate JSON
+  virtual void WriteToString(io::Printer* printer) = 0;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  const int fieldOrdinal_;
+  map<string, string> variables_;
+
+  void AddDeprecatedFlag(io::Printer* printer);
+  void AddNullCheck(io::Printer* printer);
+  void AddNullCheck(io::Printer* printer, const std::string& name);
+
+  void AddPublicMemberAttributes(io::Printer* printer);
+  void SetCommonOneofFieldVariables(map<string, string>* variables);
+
+  std::string oneof_property_name();
+  std::string oneof_name();
+  std::string property_name();
+  std::string name();
+  std::string type_name();
+  std::string type_name(const FieldDescriptor* descriptor);
+  bool has_default_value();
+  bool is_nullable_type();
+  std::string default_value();
+  std::string default_value(const FieldDescriptor* descriptor);
+  std::string number();
+  std::string capitalized_type_name();
+
+ private:
+  void SetCommonFieldVariables(map<string, string>* variables);
+  std::string GetStringDefaultValueInternal();
+  std::string GetBytesDefaultValueInternal();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc
new file mode 100644
index 0000000..d74e8c8
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -0,0 +1,118 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+void GenerateFile(const google::protobuf::FileDescriptor* file,
+                  io::Printer* printer,
+                  const Options* options) {
+  ReflectionClassGenerator reflectionClassGenerator(file, options);
+  reflectionClassGenerator.Generate(printer);
+}
+
+bool Generator::Generate(
+    const FileDescriptor* file,
+    const string& parameter,
+    GeneratorContext* generator_context,
+    string* error) const {
+
+  vector<pair<string, string> > options;
+  ParseGeneratorParameter(parameter, &options);
+
+  // We only support proto3 - but we make an exception for descriptor.proto.
+  if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && !IsDescriptorProto(file)) {
+    *error = "C# code generation only supports proto3 syntax";
+    return false;
+  }
+
+  struct Options cli_options;
+
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "file_extension") {
+      cli_options.file_extension = options[i].second;
+    } else if (options[i].first == "base_namespace") {
+      cli_options.base_namespace = options[i].second;
+      cli_options.base_namespace_specified = true;
+    } else if (options[i].first == "internal_access") {
+      cli_options.internal_access = true;
+    } else if (options[i].first == "legacy_enum_values") {
+      // TODO: Remove this before final release
+      cli_options.legacy_enum_values = true;
+    } else {
+      *error = "Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  string filename_error = "";
+  std::string filename = GetOutputFile(file,
+      cli_options.file_extension,
+      cli_options.base_namespace_specified,
+      cli_options.base_namespace,
+      &filename_error);
+
+  if (filename.empty()) {
+    *error = filename_error;
+    return false;
+  }
+  scoped_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '$');
+
+  GenerateFile(file, &printer, &cli_options);
+
+  return true;
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h
new file mode 100644
index 0000000..9b54e91
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class LIBPROTOC_EXPORT Generator
+    : public google::protobuf::compiler::CodeGenerator {
+  virtual bool Generate(
+      const FileDescriptor* file,
+      const string& parameter,
+      GeneratorContext* generator_context,
+      string* error) const;
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
new file mode 100644
index 0000000..5755fee
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include <memory>
+
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+namespace {
+
+TEST(CSharpEnumValue, PascalCasedPrefixStripping) {
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz"));
+  EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR"));
+  EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
+  EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
+  EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO"));
+  EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___"));
+  // Identifiers can't start with digits
+  EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR"));
+  EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2"));
+}
+
+}  // namespace
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
new file mode 100644
index 0000000..6c154c5
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -0,0 +1,506 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <limits>
+#include <vector>
+
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_map_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+CSharpType GetCSharpType(FieldDescriptor::Type type) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_INT64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_UINT32:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_UINT64:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_SINT32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_SINT64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_FIXED32:
+      return CSHARPTYPE_UINT32;
+    case FieldDescriptor::TYPE_FIXED64:
+      return CSHARPTYPE_UINT64;
+    case FieldDescriptor::TYPE_SFIXED32:
+      return CSHARPTYPE_INT32;
+    case FieldDescriptor::TYPE_SFIXED64:
+      return CSHARPTYPE_INT64;
+    case FieldDescriptor::TYPE_FLOAT:
+      return CSHARPTYPE_FLOAT;
+    case FieldDescriptor::TYPE_DOUBLE:
+      return CSHARPTYPE_DOUBLE;
+    case FieldDescriptor::TYPE_BOOL:
+      return CSHARPTYPE_BOOL;
+    case FieldDescriptor::TYPE_ENUM:
+      return CSHARPTYPE_ENUM;
+    case FieldDescriptor::TYPE_STRING:
+      return CSHARPTYPE_STRING;
+    case FieldDescriptor::TYPE_BYTES:
+      return CSHARPTYPE_BYTESTRING;
+    case FieldDescriptor::TYPE_GROUP:
+      return CSHARPTYPE_MESSAGE;
+    case FieldDescriptor::TYPE_MESSAGE:
+      return CSHARPTYPE_MESSAGE;
+
+      // No default because we want the compiler to complain if any new
+      // types are added.
+  }
+  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  return (CSharpType) -1;
+}
+
+std::string StripDotProto(const std::string& proto_file) {
+  int lastindex = proto_file.find_last_of(".");
+  return proto_file.substr(0, lastindex);
+}
+
+std::string GetFileNamespace(const FileDescriptor* descriptor) {
+  if (descriptor->options().has_csharp_namespace()) {
+    return descriptor->options().csharp_namespace();
+  }
+  return UnderscoresToCamelCase(descriptor->package(), true, true);
+}
+
+// Returns the Pascal-cased last part of the proto file. For example,
+// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
+std::string GetFileNameBase(const FileDescriptor* descriptor) {
+    std::string proto_file = descriptor->name();
+    int lastslash = proto_file.find_last_of("/");
+    std::string base = proto_file.substr(lastslash + 1);
+    return UnderscoresToPascalCase(StripDotProto(base));
+}
+
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
+  // TODO: Detect collisions with existing messages,
+  // and append an underscore if necessary.
+  return GetFileNameBase(descriptor) + "Reflection";
+}
+
+// TODO(jtattermusch): can we reuse a utility function?
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter,
+                                   bool preserve_period) {
+  string result;
+  // Note:  I distrust ctype.h due to locales.
+  for (int i = 0; i < input.size(); i++) {
+    if ('a' <= input[i] && input[i] <= 'z') {
+      if (cap_next_letter) {
+        result += input[i] + ('A' - 'a');
+      } else {
+        result += input[i];
+      }
+      cap_next_letter = false;
+    } else if ('A' <= input[i] && input[i] <= 'Z') {
+      if (i == 0 && !cap_next_letter) {
+        // Force first letter to lower-case unless explicitly told to
+        // capitalize it.
+        result += input[i] + ('a' - 'A');
+      } else {
+        // Capital letters after the first are left as-is.
+        result += input[i];
+      }
+      cap_next_letter = false;
+    } else if ('0' <= input[i] && input[i] <= '9') {
+      result += input[i];
+      cap_next_letter = true;
+    } else {
+      cap_next_letter = true;
+      if (input[i] == '.' && preserve_period) {
+        result += '.';
+      }
+    }
+  }
+  // Add a trailing "_" if the name should be altered.
+  if (input[input.size() - 1] == '#') {
+    result += '_';
+  }
+  return result;
+}
+
+std::string UnderscoresToPascalCase(const std::string& input) {
+  return UnderscoresToCamelCase(input, true);
+}
+
+// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty)
+// into a PascalCase string. Precise rules implemented:
+
+// Previous input character      Current character         Case
+// Any                           Non-alphanumeric          Skipped
+// None - first char of input    Alphanumeric              Upper
+// Non-letter (e.g. _ or 1)      Alphanumeric              Upper
+// Numeric                       Alphanumeric              Upper
+// Lower letter                  Alphanumeric              Same as current
+// Upper letter                  Alphanumeric              Lower
+std::string ShoutyToPascalCase(const std::string& input) {
+  string result;
+  // Simple way of implementing "always start with upper"
+  char previous = '_';
+  for (int i = 0; i < input.size(); i++) {
+    char current = input[i];
+    if (!ascii_isalnum(current)) {
+      previous = current;
+      continue;      
+    }
+    if (!ascii_isalnum(previous)) {
+      result += ascii_toupper(current);
+    } else if (ascii_isdigit(previous)) {
+      result += ascii_toupper(current);
+    } else if (ascii_islower(previous)) {
+      result += current;
+    } else {
+      result += ascii_tolower(current);
+    }
+    previous = current;
+  }
+  return result;
+}
+
+// Attempt to remove a prefix from a value, ignoring casing and skipping underscores.
+// (foo, foo_bar) => bar - underscore after prefix is skipped
+// (FOO, foo_bar) => bar - casing is ignored
+// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored
+// (foobar, foo_barbaz) => baz - underscore in value is ignored
+// (foo, bar) => bar - prefix isn't matched; return original value
+std::string TryRemovePrefix(const std::string& prefix, const std::string& value) {
+  // First normalize to a lower-case no-underscores prefix to match against
+  std::string prefix_to_match = "";
+  for (size_t i = 0; i < prefix.size(); i++) {
+    if (prefix[i] != '_') {
+      prefix_to_match += ascii_tolower(prefix[i]);
+    }
+  }
+  
+  // This keeps track of how much of value we've consumed
+  size_t prefix_index, value_index;
+  for (prefix_index = 0, value_index = 0;
+      prefix_index < prefix_to_match.size() && value_index < value.size();
+      value_index++) {
+    // Skip over underscores in the value
+    if (value[value_index] == '_') {
+      continue;
+    }
+    if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) {
+      // Failed to match the prefix - bail out early.
+      return value;
+    }
+  }
+
+  // If we didn't finish looking through the prefix, we can't strip it.
+  if (prefix_index < prefix_to_match.size()) {
+    return value;
+  }
+
+  // Step over any underscores after the prefix
+  while (value_index < value.size() && value[value_index] == '_') {
+    value_index++;
+  }
+
+  // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip.
+  if (value_index == value.size()) {
+    return value;
+  }
+
+  return value.substr(value_index);
+}
+
+// Format the enum value name in a pleasant way for C#:
+// - Strip the enum name as a prefix if possible
+// - Convert to PascalCase.
+// For example, an enum called Color with a value of COLOR_BLUE should
+// result in an enum value in C# called just Blue
+std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) {
+  std::string stripped = TryRemovePrefix(enum_name, enum_value_name);
+  std::string result = ShoutyToPascalCase(stripped);
+  // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned
+  // string is a valid identifier.
+  if (ascii_isdigit(result[0])) {
+    result = "_" + result;
+  }
+  return result;
+}
+
+std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
+  std::string result = GetFileNamespace(file);
+  if (result != "") {
+    result += '.';
+  }
+  string classname;
+  if (file->package().empty()) {
+    classname = name;
+  } else {
+    // Strip the proto package from full_name since we've replaced it with
+    // the C# namespace.
+    classname = name.substr(file->package().size() + 1);
+  }
+  result += StringReplace(classname, ".", ".Types.", true);
+  return "global::" + result;
+}
+
+std::string GetReflectionClassName(const FileDescriptor* descriptor) {
+  std::string result = GetFileNamespace(descriptor);
+  if (!result.empty()) {
+    result += '.';
+  }
+  result += GetReflectionClassUnqualifiedName(descriptor);
+  return "global::" + result;
+}
+
+std::string GetClassName(const Descriptor* descriptor) {
+  return ToCSharpName(descriptor->full_name(), descriptor->file());
+}
+
+std::string GetClassName(const EnumDescriptor* descriptor) {
+  return ToCSharpName(descriptor->full_name(), descriptor->file());
+}
+
+// Groups are hacky:  The name of the field is just the lower-cased name
+// of the group type.  In C#, though, we would like to retain the original
+// capitalization of the type name.
+std::string GetFieldName(const FieldDescriptor* descriptor) {
+  if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+    return descriptor->message_type()->name();
+  } else {
+    return descriptor->name();
+  }
+}
+
+std::string GetFieldConstantName(const FieldDescriptor* field) {
+  return GetPropertyName(field) + "FieldNumber";
+}
+
+std::string GetPropertyName(const FieldDescriptor* descriptor) {
+  // TODO(jtattermusch): consider introducing csharp_property_name field option
+  std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor));
+  // Avoid either our own type name or reserved names. Note that not all names
+  // are reserved - a field called to_string, write_to etc would still cause a problem.
+  // There are various ways of ending up with naming collisions, but we try to avoid obvious
+  // ones.
+  if (property_name == descriptor->containing_type()->name()
+      || property_name == "Types"
+      || property_name == "Descriptor") {
+    property_name += "_";
+  }
+  return property_name;
+}
+
+std::string GetOutputFile(
+    const google::protobuf::FileDescriptor* descriptor,
+    const std::string file_extension,
+    const bool generate_directories,
+    const std::string base_namespace,
+    string* error) {
+  string relative_filename = GetFileNameBase(descriptor) + file_extension;
+  if (!generate_directories) {
+    return relative_filename;
+  }
+  string ns = GetFileNamespace(descriptor);
+  string namespace_suffix = ns;
+  if (!base_namespace.empty()) {
+    // Check that the base_namespace is either equal to or a leading part of
+    // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
+    // be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
+    // to both.
+    string extended_ns = ns + ".";
+    if (extended_ns.find(base_namespace + ".") != 0) {
+      *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
+      return ""; // This will be ignored, because we've set an error.
+    }
+    namespace_suffix = ns.substr(base_namespace.length());
+    if (namespace_suffix.find(".") == 0) {
+      namespace_suffix = namespace_suffix.substr(1);
+    }
+  }
+
+  string namespace_dir = StringReplace(namespace_suffix, ".", "/", true);
+  if (!namespace_dir.empty()) {
+    namespace_dir += "/";
+  }
+  return namespace_dir + relative_filename;
+}
+
+// TODO: c&p from Java protoc plugin
+// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+// returns -1.
+int GetFixedSize(FieldDescriptor::Type type) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32   : return -1;
+    case FieldDescriptor::TYPE_INT64   : return -1;
+    case FieldDescriptor::TYPE_UINT32  : return -1;
+    case FieldDescriptor::TYPE_UINT64  : return -1;
+    case FieldDescriptor::TYPE_SINT32  : return -1;
+    case FieldDescriptor::TYPE_SINT64  : return -1;
+    case FieldDescriptor::TYPE_FIXED32 : return internal::WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT   : return internal::WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE  : return internal::WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL    : return internal::WireFormatLite::kBoolSize;
+    case FieldDescriptor::TYPE_ENUM    : return -1;
+
+    case FieldDescriptor::TYPE_STRING  : return -1;
+    case FieldDescriptor::TYPE_BYTES   : return -1;
+    case FieldDescriptor::TYPE_GROUP   : return -1;
+    case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return -1;
+}
+
+static const char base64_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+std::string StringToBase64(const std::string& input) {
+  std::string result;
+  size_t remaining = input.size();
+  const unsigned char *src = (const unsigned char*) input.c_str();
+  while (remaining > 2) {
+    result += base64_chars[src[0] >> 2];
+    result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
+    result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)];
+    result += base64_chars[src[2] & 0x3f];
+    remaining -= 3;
+    src += 3;
+  }
+  switch (remaining) {
+    case 2:
+      result += base64_chars[src[0] >> 2];
+      result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)];
+      result += base64_chars[(src[1] & 0xf) << 2];
+      result += '=';
+      src += 2;
+      break;
+    case 1:
+      result += base64_chars[src[0] >> 2];
+      result += base64_chars[((src[0] & 0x3) << 4)];
+      result += '=';
+      result += '=';
+      src += 1;
+      break;
+  }
+  return result;
+}
+
+std::string FileDescriptorToBase64(const FileDescriptor* descriptor) {
+  std::string fdp_bytes;
+  FileDescriptorProto fdp;
+  descriptor->CopyTo(&fdp);
+  fdp.SerializeToString(&fdp_bytes);
+  return StringToBase64(fdp_bytes);
+}
+
+FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
+                                         int fieldOrdinal,
+                                         const Options* options) {
+  switch (descriptor->type()) {
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      if (descriptor->is_repeated()) {
+        if (descriptor->is_map()) {
+          return new MapFieldGenerator(descriptor, fieldOrdinal, options);
+        } else {
+          return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options);
+        }
+      } else {
+        if (IsWrapperType(descriptor)) {
+          if (descriptor->containing_oneof()) {
+            return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options);
+          } else {
+            return new WrapperFieldGenerator(descriptor, fieldOrdinal, options);
+          }
+        } else {
+          if (descriptor->containing_oneof()) {
+            return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options);
+          } else {
+            return new MessageFieldGenerator(descriptor, fieldOrdinal, options);
+          }
+        }
+      }
+    case FieldDescriptor::TYPE_ENUM:
+      if (descriptor->is_repeated()) {
+        return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options);
+      } else {
+        if (descriptor->containing_oneof()) {
+          return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options);
+        } else {
+          return new EnumFieldGenerator(descriptor, fieldOrdinal, options);
+        }
+      }
+    default:
+      if (descriptor->is_repeated()) {
+        return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
+      } else {
+        if (descriptor->containing_oneof()) {
+          return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options);
+        } else {
+          return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options);
+        }
+      }
+  }
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
new file mode 100644
index 0000000..1563ca7
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -0,0 +1,132 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
+
+#include <string>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+class FieldGeneratorBase;
+
+// TODO: start using this enum.
+enum CSharpType {
+  CSHARPTYPE_INT32 = 1,
+  CSHARPTYPE_INT64 = 2,
+  CSHARPTYPE_UINT32 = 3,
+  CSHARPTYPE_UINT64 = 4,
+  CSHARPTYPE_FLOAT = 5,
+  CSHARPTYPE_DOUBLE = 6,
+  CSHARPTYPE_BOOL = 7,
+  CSHARPTYPE_STRING = 8,
+  CSHARPTYPE_BYTESTRING = 9,
+  CSHARPTYPE_MESSAGE = 10,
+  CSHARPTYPE_ENUM = 11,
+  MAX_CSHARPTYPE = 11
+};
+
+// Converts field type to corresponding C# type.
+CSharpType GetCSharpType(FieldDescriptor::Type type);
+
+std::string StripDotProto(const std::string& proto_file);
+
+// Gets unqualified name of the reflection class
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
+
+std::string GetClassName(const EnumDescriptor* descriptor);
+
+std::string GetFieldName(const FieldDescriptor* descriptor);
+
+std::string GetFieldConstantName(const FieldDescriptor* field);
+
+std::string GetPropertyName(const FieldDescriptor* descriptor);
+
+int GetFixedSize(FieldDescriptor::Type type);
+
+std::string UnderscoresToCamelCase(const std::string& input,
+                                   bool cap_next_letter,
+                                   bool preserve_period);
+
+inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) {
+  return UnderscoresToCamelCase(input, cap_next_letter, false);
+}
+
+std::string UnderscoresToPascalCase(const std::string& input);
+
+// Note that we wouldn't normally want to export this (we're not expecting
+// it to be used outside libprotoc itself) but this exposes it for testing.
+std::string LIBPROTOBUF_EXPORT GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name);
+
+// TODO(jtattermusch): perhaps we could move this to strutil
+std::string StringToBase64(const std::string& input);
+
+std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
+
+FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
+                                         int fieldOrdinal,
+                                         const Options* options);
+
+// Determines whether the given message is a map entry message,
+// i.e. one implicitly created by protoc due to a map<key, value> field.
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
+// Determines whether we're generating code for the proto representation of
+// descriptors etc, for use in the runtime. This is the only type which is
+// allowed to use proto2 syntax, and it generates internal classes.
+inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
+  return descriptor->name() == "google/protobuf/descriptor.proto";
+}
+
+inline bool IsWrapperType(const FieldDescriptor* descriptor) {
+  return descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
+      descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
new file mode 100644
index 0000000..565d122
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -0,0 +1,141 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_map_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     int fieldOrdinal,
+                                     const Options* options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+}
+
+MapFieldGenerator::~MapFieldGenerator() {
+}
+
+void MapFieldGenerator::GenerateMembers(io::Printer* printer) {   
+  const FieldDescriptor* key_descriptor =
+      descriptor_->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->FindFieldByName("value");
+  variables_["key_type_name"] = type_name(key_descriptor);
+  variables_["value_type_name"] = type_name(value_descriptor);
+  scoped_ptr<FieldGeneratorBase> key_generator(
+      CreateFieldGenerator(key_descriptor, 1, this->options()));
+  scoped_ptr<FieldGeneratorBase> value_generator(
+      CreateFieldGenerator(value_descriptor, 2, this->options()));
+
+  printer->Print(
+    variables_,
+    "private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n"
+    "    = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec(");
+  key_generator->GenerateCodecCode(printer);
+  printer->Print(", ");
+  value_generator->GenerateCodecCode(printer);
+  printer->Print(
+    variables_,
+    ", $tag$);\n"
+    "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "}\n");
+}
+
+void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "$name$_.Add(other.$name$_);\n");
+}
+
+void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.AddEntriesFrom(input, _map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.WriteTo(output, _map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "size += $name$_.CalculateSize(_map_$name$_codec);\n");
+}
+
+void MapFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "hash ^= $property_name$.GetHashCode();\n");
+}
+void MapFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if (!$property_name$.Equals(other.$property_name$)) return false;\n");
+}
+
+void MapFieldGenerator::WriteToString(io::Printer* printer) {
+    // TODO: If we ever actually use ToString, we'll need to impleme this...
+}
+
+void MapFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$name$_.Clone();\n");
+}
+
+void MapFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.h b/src/google/protobuf/compiler/csharp/csharp_map_field.h
new file mode 100644
index 0000000..84a33a0
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class MapFieldGenerator : public FieldGeneratorBase {
+ public:
+  MapFieldGenerator(const FieldDescriptor* descriptor,
+                    int fieldOrdinal,
+                    const Options* options);
+  ~MapFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
new file mode 100644
index 0000000..532da6b
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -0,0 +1,504 @@
+// 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.
+
+#include <sstream>
+#include <algorithm>
+#include <map>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
+  return d1->number() < d2->number();
+}
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor,
+                                   const Options* options)
+    : SourceGeneratorBase(descriptor->file(), options),
+      descriptor_(descriptor) {
+
+  // sorted field names
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_names_.push_back(descriptor_->field(i)->name());
+  }
+  std::sort(field_names_.begin(), field_names_.end());
+
+  // fields by number
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    fields_by_number_.push_back(descriptor_->field(i));
+  }
+  std::sort(fields_by_number_.begin(), fields_by_number_.end(),
+            CompareFieldNumbers);
+}
+
+MessageGenerator::~MessageGenerator() {
+}
+
+std::string MessageGenerator::class_name() {
+  return descriptor_->name();
+}
+
+std::string MessageGenerator::full_class_name() {
+  return GetClassName(descriptor_);
+}
+
+const std::vector<std::string>& MessageGenerator::field_names() {
+  return field_names_;
+}
+
+const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
+  return fields_by_number_;
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+  map<string, string> vars;
+  vars["class_name"] = class_name();
+  vars["access_level"] = class_access_level();
+
+  WriteMessageDocComment(printer, descriptor_);
+  printer->Print(
+    "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+    vars,
+    "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
+  printer->Indent();
+
+  // All static fields and properties
+  printer->Print(
+      vars,
+      "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n"
+      "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
+
+  // Access the message descriptor via the relevant file descriptor or containing message descriptor.
+  if (!descriptor_->containing_type()) {
+    vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file())
+        + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
+  } else {
+    vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
+        + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]";
+  }
+
+  printer->Print(
+    vars,
+    "public static pbr::MessageDescriptor Descriptor {\n"
+    "  get { return $descriptor_accessor$; }\n"
+    "}\n"
+    "\n"
+    "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
+    "  get { return Descriptor; }\n"
+    "}\n"
+    "\n");
+
+  // Parameterless constructor and partial OnConstruction method.
+  printer->Print(
+    vars,
+    "public $class_name$() {\n"
+    "  OnConstruction();\n"
+    "}\n\n"
+    "partial void OnConstruction();\n\n");
+
+  GenerateCloningCode(printer);
+  GenerateFreezingCode(printer);
+
+  // Fields/properties
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+
+    // Rats: we lose the debug comment here :(
+    printer->Print(
+      "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
+      "public const int $field_constant_name$ = $index$;\n",
+      "field_name", fieldDescriptor->name(),
+      "field_constant_name", GetFieldConstantName(fieldDescriptor),
+      "index", SimpleItoa(fieldDescriptor->number()));
+    scoped_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(fieldDescriptor));
+    generator->GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  // oneof properties
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
+    vars["original_name"] = descriptor_->oneof_decl(i)->name();
+    printer->Print(
+      vars,
+      "private object $name$_;\n"
+      "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
+      "public enum $property_name$OneofCase {\n");
+    printer->Indent();
+    printer->Print("None = 0,\n");
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print("$field_property_name$ = $index$,\n",
+                     "field_property_name", GetPropertyName(field),
+                     "index", SimpleItoa(field->number()));
+    }
+    printer->Outdent();
+    printer->Print("}\n");
+    // TODO: Should we put the oneof .proto comments here?
+    // It's unclear exactly where they should go.
+    printer->Print(
+      vars,
+      "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"
+      "public $property_name$OneofCase $property_name$Case {\n"
+      "  get { return $name$Case_; }\n"
+      "}\n\n"
+      "public void Clear$property_name$() {\n"
+      "  $name$Case_ = $property_name$OneofCase.None;\n"
+      "  $name$_ = null;\n"
+      "}\n\n");
+  }
+
+  // Standard methods
+  GenerateFrameworkMethods(printer);
+  GenerateMessageSerializationMethods(printer);
+  GenerateMergingMethods(printer);
+
+  // Nested messages and enums
+  if (HasNestedGeneratedTypes()) {
+    printer->Print(
+      vars,
+      "#region Nested types\n"
+      "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n"
+      "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+    WriteGeneratedCodeAttributes(printer);
+    printer->Print("public static partial class Types {\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+      EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options());
+      enumGenerator.Generate(printer);
+    }
+    for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+      // Don't generate nested types for maps...
+      if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
+        MessageGenerator messageGenerator(
+            descriptor_->nested_type(i), this->options());
+        messageGenerator.Generate(printer);
+      }
+    }
+    printer->Outdent();
+    printer->Print("}\n"
+                   "#endregion\n"
+                   "\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Print("\n");
+}
+
+// Helper to work out whether we need to generate a class to hold nested types/enums.
+// Only tricky because we don't want to generate map entry types.
+bool MessageGenerator::HasNestedGeneratedTypes()
+{
+  if (descriptor_->enum_type_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
+  map<string, string> vars;
+  vars["class_name"] = class_name();
+    printer->Print(
+    vars,
+    "public $class_name$($class_name$ other) : this() {\n");
+  printer->Indent();
+  // Clone non-oneof fields first
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      scoped_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(descriptor_->field(i)));
+      generator->GenerateCloningCode(printer);
+    }
+  }
+  // Clone just the right field for each oneof
+  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+    vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(
+        descriptor_->oneof_decl(i)->name(), true);
+    printer->Print(vars, "switch (other.$property_name$Case) {\n");
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
+      vars["field_property_name"] = GetPropertyName(field);
+      printer->Print(
+          vars,
+          "case $property_name$OneofCase.$field_property_name$:\n");
+      printer->Indent();
+      generator->GenerateCloningCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Outdent();
+    printer->Print("}\n\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+
+  printer->Print(
+    vars,
+    "public $class_name$ Clone() {\n"
+    "  return new $class_name$(this);\n"
+    "}\n\n");
+}
+
+void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
+    map<string, string> vars;
+    vars["class_name"] = class_name();
+
+    // Equality
+    printer->Print(
+        vars,
+        "public override bool Equals(object other) {\n"
+        "  return Equals(other as $class_name$);\n"
+        "}\n\n"
+        "public bool Equals($class_name$ other) {\n"
+        "  if (ReferenceEquals(other, null)) {\n"
+        "    return false;\n"
+        "  }\n"
+        "  if (ReferenceEquals(other, this)) {\n"
+        "    return true;\n"
+        "  }\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+        scoped_ptr<FieldGeneratorBase> generator(
+            CreateFieldGeneratorInternal(descriptor_->field(i)));
+        generator->WriteEquals(printer);
+    }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+        printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n",
+            "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
+    }
+    printer->Outdent();
+    printer->Print(
+        "  return true;\n"
+        "}\n\n");
+
+    // GetHashCode
+    // Start with a non-zero value to easily distinguish between null and "empty" messages.
+    printer->Print(
+        "public override int GetHashCode() {\n"
+        "  int hash = 1;\n");
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+        scoped_ptr<FieldGeneratorBase> generator(
+            CreateFieldGeneratorInternal(descriptor_->field(i)));
+        generator->WriteHash(printer);
+    }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+        printer->Print("hash ^= (int) $name$Case_;\n",
+            "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false));
+    }
+    printer->Print("return hash;\n");
+    printer->Outdent();
+    printer->Print("}\n\n");
+
+    printer->Print(
+        "public override string ToString() {\n"
+        "  return pb::JsonFormatter.ToDiagnosticString(this);\n"
+        "}\n\n");
+}
+
+void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
+  printer->Print(
+      "public void WriteTo(pb::CodedOutputStream output) {\n");
+  printer->Indent();
+
+  // Serialize all the fields
+  for (int i = 0; i < fields_by_number().size(); i++) {
+    scoped_ptr<FieldGeneratorBase> generator(
+      CreateFieldGeneratorInternal(fields_by_number()[i]));
+    generator->GenerateSerializationCode(printer);
+  }
+
+  // TODO(jonskeet): Memoize size of frozen messages?
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n"
+    "public int CalculateSize() {\n");
+  printer->Indent();
+  printer->Print("int size = 0;\n");
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    scoped_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(descriptor_->field(i)));
+    generator->GenerateSerializedSizeCode(printer);
+  }
+  printer->Print("return size;\n");
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
+  // Note:  These are separate from GenerateMessageSerializationMethods()
+  //   because they need to be generated even for messages that are optimized
+  //   for code size.
+  map<string, string> vars;
+  vars["class_name"] = class_name();
+
+  printer->Print(
+    vars,
+    "public void MergeFrom($class_name$ other) {\n");
+  printer->Indent();
+  printer->Print(
+    "if (other == null) {\n"
+    "  return;\n"
+    "}\n");
+  // Merge non-oneof fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {      
+      scoped_ptr<FieldGeneratorBase> generator(
+          CreateFieldGeneratorInternal(descriptor_->field(i)));
+      generator->GenerateMergingCode(printer);
+    }
+  }
+  // Merge oneof fields
+  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+    vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
+    vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
+    printer->Print(vars, "switch (other.$property_name$Case) {\n");
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      vars["field_property_name"] = GetPropertyName(field);
+      printer->Print(
+        vars,
+        "case $property_name$OneofCase.$field_property_name$:\n"
+        "  $field_property_name$ = other.$field_property_name$;\n"
+        "  break;\n");
+    }
+    printer->Outdent();
+    printer->Print("}\n\n");
+  }
+  printer->Outdent();
+  printer->Print("}\n\n");
+  printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n");
+  printer->Indent();
+  printer->Print(
+    "uint tag;\n"
+    "while ((tag = input.ReadTag()) != 0) {\n"
+    "  switch(tag) {\n");
+  printer->Indent();
+  printer->Indent();
+  printer->Print(
+    "default:\n"
+    "  input.SkipLastField();\n" // We're not storing the data, but we still need to consume it.
+    "  break;\n");
+  for (int i = 0; i < fields_by_number().size(); i++) {
+    const FieldDescriptor* field = fields_by_number()[i];
+    internal::WireFormatLite::WireType wt =
+        internal::WireFormat::WireTypeForFieldType(field->type());
+    uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt);
+    // Handle both packed and unpacked repeated fields with the same Read*Array call;
+    // the two generated cases are the packed and unpacked tags.
+    // TODO(jonskeet): Check that is_packable is equivalent to
+    // is_repeated && wt in { VARINT, FIXED32, FIXED64 }.
+    // It looks like it is...
+    if (field->is_packable()) {
+      printer->Print(
+        "case $packed_tag$:\n",
+        "packed_tag",
+        SimpleItoa(
+            internal::WireFormatLite::MakeTag(
+                field->number(),
+                internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
+    }
+
+    printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag));
+    printer->Indent();
+    scoped_ptr<FieldGeneratorBase> generator(
+        CreateFieldGeneratorInternal(field));
+    generator->GenerateParsingCode(printer);
+    printer->Print("break;\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+  printer->Outdent();
+  printer->Print("}\n"); // switch
+  printer->Outdent();
+  printer->Print("}\n"); // while
+  printer->Outdent();
+  printer->Print("}\n\n"); // method
+}
+
+int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) {
+  for (int i = 0; i < field_names().size(); i++) {
+    if (field_names()[i] == descriptor->name()) {
+      return i;
+    }
+  }
+  GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name();
+  return -1;
+}
+
+FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
+    const FieldDescriptor* descriptor) {
+  return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor), this->options());
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h
new file mode 100644
index 0000000..f794d68
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class FieldGeneratorBase;
+
+class MessageGenerator : public SourceGeneratorBase {
+ public:
+  MessageGenerator(const Descriptor* descriptor, const Options* options);
+  ~MessageGenerator();
+
+  void GenerateCloningCode(io::Printer* printer);
+  void GenerateFreezingCode(io::Printer* printer);
+  void GenerateFrameworkMethods(io::Printer* printer);
+  void Generate(io::Printer* printer);
+
+ private:
+  const Descriptor* descriptor_;
+  std::vector<std::string> field_names_;
+  std::vector<const FieldDescriptor*> fields_by_number_;
+
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateMergingMethods(io::Printer* printer);
+
+  int GetFieldOrdinal(const FieldDescriptor* descriptor);
+  FieldGeneratorBase* CreateFieldGeneratorInternal(
+      const FieldDescriptor* descriptor);
+
+  bool HasNestedGeneratedTypes();
+
+  std::string class_name();
+  std::string full_class_name();
+
+  // field names sorted alphabetically
+  const std::vector<std::string>& field_names();
+
+  // field descriptors sorted by number
+  const std::vector<const FieldDescriptor*>& fields_by_number();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
new file mode 100644
index 0000000..338692f
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -0,0 +1,200 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             int fieldOrdinal,
+                                             const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+  variables_["has_property_check"] = name() + "_ != null";
+  variables_["has_not_property_check"] = name() + "_ == null";
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {
+
+}
+
+void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private $type_name$ $name$_;\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "  set {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if (other.$has_property_check$) {\n"
+    "  if ($has_not_property_check$) {\n"
+    "    $name$_ = new $type_name$();\n"
+    "  }\n"
+    "  $property_name$.MergeFrom(other.$property_name$);\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_not_property_check$) {\n"
+    "  $name$_ = new $type_name$();\n"
+    "}\n"
+    // TODO(jonskeet): Do we really need merging behaviour like this?
+    "input.ReadMessage($name$_);\n"); // No need to support TYPE_GROUP...
+}
+
+void MessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  output.WriteRawTag($tag_bytes$);\n"
+    "  output.WriteMessage($property_name$);\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  size += $tag_size$ + pb::CodedOutputStream.ComputeMessageSize($property_name$);\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+void MessageFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if (!object.Equals($property_name$, other.$property_name$)) return false;\n");
+}
+void MessageFieldGenerator::WriteToString(io::Printer* printer) {
+  variables_["field_name"] = GetFieldName(descriptor_);
+  printer->Print(
+    variables_,
+    "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");
+}
+
+void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$property_name$ = other.$has_property_check$ ? other.$property_name$.Clone() : null;\n");
+}
+
+void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
+}
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+    const FieldDescriptor* descriptor,
+	  int fieldOrdinal,
+    const Options *options)
+    : MessageFieldGenerator(descriptor, fieldOrdinal, options) {
+  SetCommonOneofFieldVariables(&variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {
+
+}
+
+void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
+    "  set {\n"
+    "    $oneof_name$_ = value;\n"
+    "    $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
+    "  }\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  // TODO(jonskeet): We may be able to do better than this
+  printer->Print(
+    variables_,
+    "$type_name$ subBuilder = new $type_name$();\n"
+    "if ($has_property_check$) {\n"
+    "  subBuilder.MergeFrom($property_name$);\n"
+    "}\n"
+    "input.ReadMessage(subBuilder);\n" // No support of TYPE_GROUP
+    "$property_name$ = subBuilder;\n");
+}
+
+void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
+}
+
+void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$property_name$ = other.$property_name$.Clone();\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h
new file mode 100644
index 0000000..7d61475
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h
@@ -0,0 +1,90 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class MessageFieldGenerator : public FieldGeneratorBase {
+ public:
+  MessageFieldGenerator(const FieldDescriptor* descriptor,
+                        int fieldOrdinal,
+                        const Options *options);
+  ~MessageFieldGenerator();
+
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class MessageOneofFieldGenerator : public MessageFieldGenerator {
+ public:
+  MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             int fieldOrdinal,
+                             const Options *options);
+  ~MessageOneofFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_names.h b/src/google/protobuf/compiler/csharp/csharp_names.h
new file mode 100644
index 0000000..3080518
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_names.h
@@ -0,0 +1,103 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Provides a mechanism for mapping a descriptor to the
+// fully-qualified name of the corresponding C# class.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace csharp {
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The namespace to use for given file descriptor.
+string GetFileNamespace(const FileDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified C# class name.
+string GetClassName(const Descriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified name of the C# class that provides
+//   access to the file descriptor. Proto compiler generates
+//   such class for each .proto file processed.
+string GetReflectionClassName(const FileDescriptor* descriptor);
+
+// Generates output file name for given file descriptor. If generate_directories
+// is true, the output file will be put under directory corresponding to file's
+// namespace. base_namespace can be used to strip some of the top level
+// directories. E.g. for file with namespace "Bar.Foo" and base_namespace="Bar",
+// the resulting file will be put under directory "Foo" (and not "Bar/Foo").
+//
+// Requires:
+//   descriptor != NULL
+//   error != NULL
+//
+//  Returns:
+//    The file name to use as output file for given file descriptor. In case
+//    of failure, this function will return empty string and error parameter
+//    will contain the error message.
+string GetOutputFile(
+    const google::protobuf::FileDescriptor* descriptor,
+    const string file_extension,
+    const bool generate_directories,
+    const string base_namespace,
+    string* error);
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h
new file mode 100644
index 0000000..4079bf7
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_options.h
@@ -0,0 +1,86 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// Generator options (used by csharp_generator.cc):
+struct Options {
+  Options() :
+      file_extension(".cs"),
+      base_namespace(""),
+      base_namespace_specified(false),
+      internal_access(false),
+      legacy_enum_values(false) {
+  }
+  // Extension of the generated file. Defaults to ".cs"
+  string file_extension;
+  // Base namespace to use to create directory hierarchy. Defaults to "".
+  // This option allows the simple creation of a conventional C# file layout,
+  // where directories are created relative to a project-specific base
+  // namespace. For example, in a project with a base namespace of PetShop, a
+  // proto of user.proto with a C# namespace of PetShop.Model.Shared would
+  // generate Model/Shared/User.cs underneath the specified --csharp_out
+  // directory.
+  //
+  // If no base namespace is specified, all files are generated in the
+  // --csharp_out directory, with no subdirectories created automatically.
+  string base_namespace;
+  // Whether the base namespace has been explicitly specified by the user.
+  // This is required as the base namespace can be explicitly set to the empty
+  // string, meaning "create a full directory hierarchy, starting from the first
+  // segment of the namespace."
+  bool base_namespace_specified;
+  // Whether the generated classes should have accessibility level of "internal".
+  // Defaults to false that generates "public" classes.
+  bool internal_access;
+  // By default, C# codegen now uses PascalCased enum values names, after
+  // removing the enum type name as a prefix (if it *is* a prefix of the value).
+  // Setting this option reverts to the previous behavior of just copying the
+  // value name specified in the .proto file, allowing gradual migration.
+  // This option will be removed before final release.
+  bool legacy_enum_values;
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
new file mode 100644
index 0000000..3b7ca75
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -0,0 +1,218 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+  // TODO(jonskeet): Make this cleaner...
+  is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING
+      && descriptor->type() != FieldDescriptor::TYPE_BYTES;
+  if (!is_value_type) {
+    variables_["has_property_check"] = variables_["property_name"] + ".Length != 0";
+    variables_["other_has_property_check"] = "other." + variables_["property_name"] + ".Length != 0";
+  }
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
+}
+
+void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
+  // TODO(jonskeet): Work out whether we want to prevent the fields from ever being
+  // null, or whether we just handle it, in the cases of bytes and string.
+  // (Basically, should null-handling code be in the getter or the setter?)
+  printer->Print(
+    variables_,
+    "private $type_name$ $name_def_message$;\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "  set {\n");
+  if (is_value_type) {
+    printer->Print(
+      variables_,
+      "    $name$_ = value;\n");
+  } else {
+    printer->Print(
+      variables_,
+      "    $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
+  }
+  printer->Print(
+    "  }\n"
+    "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($other_has_property_check$) {\n"
+    "  $property_name$ = other.$property_name$;\n"
+    "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  // Note: invoke the property setter rather than writing straight to the field,
+  // so that we can normalize "null to empty" for strings and bytes.
+  printer->Print(
+    variables_,
+    "$property_name$ = input.Read$capitalized_type_name$();\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  output.WriteRawTag($tag_bytes$);\n"
+    "  output.Write$capitalized_type_name$($property_name$);\n"
+    "}\n");
+}
+
+void PrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n");
+  printer->Indent();
+  int fixedSize = GetFixedSize(descriptor_->type());
+  if (fixedSize == -1) {
+    printer->Print(
+      variables_,
+      "size += $tag_size$ + pb::CodedOutputStream.Compute$capitalized_type_name$Size($property_name$);\n");
+  } else {
+    printer->Print(
+      "size += $tag_size$ + $fixed_size$;\n",
+      "fixed_size", SimpleItoa(fixedSize),
+      "tag_size", variables_["tag_size"]);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void PrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+void PrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($property_name$ != other.$property_name$) return false;\n");
+}
+void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n");
+}
+
+void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$name$_;\n");
+}
+
+void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "pb::FieldCodec.For$capitalized_type_name$($tag$)");
+}
+
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) {
+  SetCommonOneofFieldVariables(&variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
+    "  set {\n");
+    if (is_value_type) {
+      printer->Print(
+        variables_,
+        "    $oneof_name$_ = value;\n");
+    } else {
+      printer->Print(
+        variables_,
+        "    $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
+    }
+    printer->Print(
+      variables_,
+      "    $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"
+      "  }\n"
+      "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
+  printer->Print(variables_,
+    "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+    printer->Print(
+      variables_,
+      "$property_name$ = input.Read$capitalized_type_name$();\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$property_name$ = other.$property_name$;\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
new file mode 100644
index 0000000..5f466fc
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
@@ -0,0 +1,94 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class PrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          int fieldOrdinal,
+                          const Options *options);
+  ~PrimitiveFieldGenerator();
+
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ protected:
+  bool is_value_type;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
+ public:
+  PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
+                               int fieldOrdinal,
+                               const Options *options);
+  ~PrimitiveOneofFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
new file mode 100644
index 0000000..f7397c0
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -0,0 +1,293 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+#include <google/protobuf/compiler/csharp/csharp_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file,
+                                                   const Options* options)
+    : SourceGeneratorBase(file, options),
+      file_(file) {
+  namespace_ = GetFileNamespace(file);
+  reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
+}
+
+ReflectionClassGenerator::~ReflectionClassGenerator() {
+}
+
+void ReflectionClassGenerator::Generate(io::Printer* printer) {
+  WriteIntroduction(printer);
+
+  WriteDescriptor(printer);
+  // Close the class declaration.
+  printer->Outdent();
+  printer->Print("}\n");
+
+  // write children: Enums
+  if (file_->enum_type_count() > 0) {
+    printer->Print("#region Enums\n");
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      EnumGenerator enumGenerator(file_->enum_type(i), this->options());
+      enumGenerator.Generate(printer);
+    }
+    printer->Print("#endregion\n");
+    printer->Print("\n");
+  }
+
+  // write children: Messages
+  if (file_->message_type_count() > 0) {
+    printer->Print("#region Messages\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      MessageGenerator messageGenerator(file_->message_type(i), this->options());
+      messageGenerator.Generate(printer);
+    }
+    printer->Print("#endregion\n");
+    printer->Print("\n");
+  }
+
+  // TODO(jtattermusch): add insertion point for services.
+
+  if (!namespace_.empty()) {
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+  printer->Print("\n");
+  printer->Print("#endregion Designer generated code\n");
+}
+
+void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
+  printer->Print(
+    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "// source: $file_name$\n"
+    "#pragma warning disable 1591, 0612, 3021\n"
+    "#region Designer generated code\n"
+    "\n"
+    "using pb = global::Google.Protobuf;\n"
+    "using pbc = global::Google.Protobuf.Collections;\n"
+    "using pbr = global::Google.Protobuf.Reflection;\n"
+    "using scg = global::System.Collections.Generic;\n",
+    "file_name", file_->name());
+
+  if (!namespace_.empty()) {
+    printer->Print("namespace $namespace$ {\n", "namespace", namespace_);
+    printer->Indent();
+    printer->Print("\n");
+  }
+
+  printer->Print(
+    "/// <summary>Holder for reflection information generated from $file_name$</summary>\n"
+    "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n",
+    "file_name", file_->name());
+  WriteGeneratedCodeAttributes(printer);
+  printer->Print(
+    "$access_level$ static partial class $reflection_class_name$ {\n"
+    "\n",
+    "access_level", class_access_level(),
+    "reflection_class_name", reflectionClassname_);
+  printer->Indent();
+}
+
+void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
+  printer->Print(
+    "#region Descriptor\n"
+    "/// <summary>File descriptor for $file_name$</summary>\n"
+    "public static pbr::FileDescriptor Descriptor {\n"
+    "  get { return descriptor; }\n"
+    "}\n"
+    "private static pbr::FileDescriptor descriptor;\n"
+    "\n"
+    "static $reflection_class_name$() {\n",
+    "file_name", file_->name(),
+    "reflection_class_name", reflectionClassname_);
+  printer->Indent();
+  printer->Print(
+    "byte[] descriptorData = global::System.Convert.FromBase64String(\n");
+  printer->Indent();
+  printer->Indent();
+  printer->Print("string.Concat(\n");
+  printer->Indent();
+
+  // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
+  std::string base64 = FileDescriptorToBase64(file_);
+  while (base64.size() > 60) {
+    printer->Print("\"$base64$\",\n", "base64", base64.substr(0, 60));
+    base64 = base64.substr(60);
+  }
+  printer->Print("\"$base64$\"));\n", "base64", base64);
+  printer->Outdent();
+  printer->Outdent();
+  printer->Outdent();
+
+  // -----------------------------------------------------------------
+  // Invoke InternalBuildGeneratedFileFrom() to build the file.
+  printer->Print(
+      "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n");
+  printer->Print("    new pbr::FileDescriptor[] { ");
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    // descriptor.proto is special: we don't allow access to the generated code, but there's
+    // a separately-exposed property to get at the file descriptor, specifically to allow this
+    // kind of dependency.
+    if (IsDescriptorProto(file_->dependency(i))) {
+      printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, ");
+    } else {
+      printer->Print(
+      "$full_reflection_class_name$.Descriptor, ",
+      "full_reflection_class_name",
+      GetReflectionClassName(file_->dependency(i)));
+    }
+  }
+  printer->Print("},\n"
+      "    new pbr::GeneratedClrTypeInfo(");
+  // Specify all the generated code information, recursively.
+  if (file_->enum_type_count() > 0) {
+      printer->Print("new[] {");
+      for (int i = 0; i < file_->enum_type_count(); i++) {
+          printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i)));
+      }
+      printer->Print("}, ");
+  }
+  else {
+      printer->Print("null, ");
+  }
+  if (file_->message_type_count() > 0) {
+      printer->Print("new pbr::GeneratedClrTypeInfo[] {\n");
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      for (int i = 0; i < file_->message_type_count(); i++) {
+          WriteGeneratedCodeInfo(file_->message_type(i), printer, i == file_->message_type_count() - 1);
+      }
+      printer->Outdent();
+      printer->Print("\n}));\n");
+      printer->Outdent();
+      printer->Outdent();
+  }
+  else {
+      printer->Print("null));\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Print("#endregion\n\n");
+}
+
+// Write out the generated code for a particular message. This consists of the CLR type, property names
+// corresponding to fields, names corresponding to oneofs, nested enums, and nested types. Each array part
+// can be specified as null if it would be empty, to make the generated code somewhat simpler to read.
+// We write a line break at the end of each generated code info, so that in the final file we'll see all
+// the types, pre-ordered depth first, one per line. The indentation will be slightly unusual,
+// in that it will look like a single array when it's actually constructing a tree, but it'll be easy to
+// read even with multiple levels of nesting.
+// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
+// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
+// just controlling the formatting in the generated code.
+void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
+  if (IsMapEntryMessage(descriptor)) {
+    printer->Print("null, ");
+    return;
+  }
+  // Generated message type
+  printer->Print("new pbr::GeneratedClrTypeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor));
+  
+  // Fields
+  if (descriptor->field_count() > 0) {
+      std::vector<std::string> fields;
+      for (int i = 0; i < descriptor->field_count(); i++) {
+          fields.push_back(GetPropertyName(descriptor->field(i)));
+      }
+      printer->Print("new[]{ \"$fields$\" }, ", "fields", JoinStrings(fields, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Oneofs
+  if (descriptor->oneof_decl_count() > 0) {
+      std::vector<std::string> oneofs;
+      for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
+          oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
+      }
+      printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", JoinStrings(oneofs, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Nested enums
+  if (descriptor->enum_type_count() > 0) {
+      std::vector<std::string> enums;
+      for (int i = 0; i < descriptor->enum_type_count(); i++) {
+          enums.push_back(GetClassName(descriptor->enum_type(i)));
+      }
+      printer->Print("new[]{ typeof($enums$) }, ", "enums", JoinStrings(enums, "), typeof("));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Nested types
+  if (descriptor->nested_type_count() > 0) {
+      // Need to specify array type explicitly here, as all elements may be null. 
+      printer->Print("new pbr::GeneratedClrTypeInfo[] { ");
+      for (int i = 0; i < descriptor->nested_type_count(); i++) {
+          WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1);
+      }
+      printer->Print("}");
+  }
+  else {
+      printer->Print("null");
+  }
+  printer->Print(last ? ")" : "),\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
new file mode 100644
index 0000000..e0c69f3
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class ReflectionClassGenerator : public SourceGeneratorBase {
+ public:
+  ReflectionClassGenerator(const FileDescriptor* file, const Options* options);
+  ~ReflectionClassGenerator();
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const FileDescriptor* file_;
+
+  std::string namespace_;
+  std::string reflectionClassname_;
+
+  void WriteIntroduction(io::Printer* printer);
+  void WriteDescriptor(io::Printer* printer);
+  void WriteGeneratedCodeInfo(const Descriptor* descriptor,
+                              io::Printer* printer,
+                              bool last);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
new file mode 100644
index 0000000..1befdc1
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
@@ -0,0 +1,127 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {
+
+}
+
+void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n");
+  printer->Print(variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "}\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {  
+  printer->Print(
+    variables_,
+    "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "hash ^= $name$_.GetHashCode();\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+
+void RepeatedEnumFieldGenerator::WriteToString(io::Printer* printer) {
+  printer->Print(variables_,
+    "PrintField(\"$descriptor_name$\", $name$_, writer);\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedEnumFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h
new file mode 100644
index 0000000..819b583
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// TODO(jonskeet): Refactor repeated field support; all the implementations are *really* similar. We
+// should probably have a RepeatedFieldGeneratorBase.
+class RepeatedEnumFieldGenerator : public FieldGeneratorBase {
+ public:
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                             int fieldOrdinal,
+                             const Options *options);
+  ~RepeatedEnumFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
new file mode 100644
index 0000000..d51e638
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -0,0 +1,144 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_message_field.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {
+
+}
+
+void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = ");
+  // Don't want to duplicate the codec code here... maybe we should have a
+  // "create single field generator for this repeated field"
+  // function, but it doesn't seem worth it for just this.
+  if (IsWrapperType(descriptor_)) {
+    scoped_ptr<FieldGeneratorBase> single_generator(
+      new WrapperFieldGenerator(descriptor_, fieldOrdinal_, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  } else {
+    scoped_ptr<FieldGeneratorBase> single_generator(
+      new MessageFieldGenerator(descriptor_, fieldOrdinal_, this->options()));
+    single_generator->GenerateCodecCode(printer);
+  }
+  printer->Print(";\n");
+  printer->Print(
+    variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "}\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "hash ^= $name$_.GetHashCode();\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+
+void RepeatedMessageFieldGenerator::WriteToString(io::Printer* printer) {
+  variables_["field_name"] = GetFieldName(descriptor_);
+  printer->Print(
+    variables_,
+    "PrintField(\"$field_name$\", $name$_, writer);\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedMessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h
new file mode 100644
index 0000000..6e33648
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class RepeatedMessageFieldGenerator : public FieldGeneratorBase {
+ public:
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                int fieldOrdinal,
+                                const Options *options);
+  ~RepeatedMessageFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
new file mode 100644
index 0000000..bee3f36
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
@@ -0,0 +1,125 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/wire_format.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {
+
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
+    "    = pb::FieldCodec.For$capitalized_type_name$($tag$);\n");
+  printer->Print(variables_,
+    "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.Add(other.$name$_);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.AddEntriesFrom(input, _repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$name$_.WriteTo(output, _repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "size += $name$_.CalculateSize(_repeated_$name$_codec);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "hash ^= $name$_.GetHashCode();\n");
+}
+void RepeatedPrimitiveFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if(!$name$_.Equals(other.$name$_)) return false;\n");
+}
+void RepeatedPrimitiveFieldGenerator::WriteToString(io::Printer* printer) {
+  printer->Print(variables_,
+    "PrintField(\"$descriptor_name$\", $name$_, writer);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$name$_ = other.$name$_.Clone();\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
new file mode 100644
index 0000000..a59348a
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase {
+ public:
+  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options);
+  ~RepeatedPrimitiveFieldGenerator();
+
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateFreezingCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
new file mode 100644
index 0000000..16411e4
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
@@ -0,0 +1,73 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor,
+                                         const Options *options)
+    : descriptor_(descriptor), options_(options) {
+}
+
+SourceGeneratorBase::~SourceGeneratorBase() {
+}
+
+void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) {
+  // This hook can be used to reintroduce generated code attributes in the future.
+}
+
+std::string SourceGeneratorBase::class_access_level() {
+  return (IsDescriptorProto(descriptor_) || this->options()->internal_access) ? "internal" : "public";
+}
+
+const Options* SourceGeneratorBase::options() {
+  return this->options_;
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
new file mode 100644
index 0000000..2e73458
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class SourceGeneratorBase {
+ protected:
+  SourceGeneratorBase(const FileDescriptor* descriptor, const Options* options);
+  virtual ~SourceGeneratorBase();
+
+  std::string class_access_level();
+  const Options* options();
+
+  void WriteGeneratedCodeAttributes(io::Printer* printer);
+
+ private:
+  const FileDescriptor* descriptor_;
+  const Options *options_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__
+
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
new file mode 100644
index 0000000..5cb86b6
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -0,0 +1,211 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_options.h>
+#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
+                                       int fieldOrdinal, const Options *options)
+    : FieldGeneratorBase(descriptor, fieldOrdinal, options) {
+  variables_["has_property_check"] = name() + "_ != null";
+  variables_["has_not_property_check"] = name() + "_ == null";
+  const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
+  is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
+      wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
+  if (is_value_type) {
+    variables_["nonnullable_type_name"] = type_name(wrapped_field);
+  }
+}
+
+WrapperFieldGenerator::~WrapperFieldGenerator() {
+}
+
+void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
+  printer->Print(
+        variables_,
+        "private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
+  GenerateCodecCode(printer);
+  printer->Print(
+    variables_,
+    ";\n"
+    "private $type_name$ $name$_;\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $name$_; }\n"
+    "  set {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "}\n");
+}
+
+void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if (other.$has_property_check$) {\n"
+    "  if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
+    "    $property_name$ = other.$property_name$;\n"
+    "  }\n"
+    "}\n");
+}
+
+void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$type_name$ value = _single_$name$_codec.Read(input);\n"
+    "if ($has_not_property_check$ || value != $default_value$) {\n"
+    "  $property_name$ = value;\n"
+    "}\n");
+}
+
+void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
+    "}\n");
+}
+
+void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
+    "}\n");
+}
+
+void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
+}
+
+void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "if ($property_name$ != other.$property_name$) return false;\n");
+}
+
+void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
+  // TODO: Implement if we ever actually need it...
+}
+
+void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
+  printer->Print(variables_,
+    "$property_name$ = other.$property_name$;\n");
+}
+
+void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
+  if (is_value_type) {
+    printer->Print(
+      variables_,
+      "pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
+  } else {
+    printer->Print(
+      variables_,
+      "pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
+  }
+}
+
+WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(
+    const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options)
+    : WrapperFieldGenerator(descriptor, fieldOrdinal, options) {
+    SetCommonOneofFieldVariables(&variables_);
+}
+
+WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
+}
+
+void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  // Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
+  printer->Print(
+        variables_,
+        "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
+  GenerateCodecCode(printer);
+  printer->Print(";\n");
+  WritePropertyDocComment(printer, descriptor_);
+  AddDeprecatedFlag(printer);
+  printer->Print(
+    variables_,
+    "$access_level$ $type_name$ $property_name$ {\n"
+    "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
+    "  set {\n"
+    "    $oneof_name$_ = value;\n"
+    "    $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
+    "  }\n"
+    "}\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
+  printer->Print(
+    variables_,
+    "$property_name$ = _oneof_$name$_codec.Read(input);\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
+  // TODO: I suspect this is wrong...
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
+    "}\n");
+}
+
+void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
+  // TODO: I suspect this is wrong...
+  printer->Print(
+    variables_,
+    "if ($has_property_check$) {\n"
+    "  size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
+    "}\n");
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
new file mode 100644
index 0000000..250dfd2
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+struct Options;
+
+class WrapperFieldGenerator : public FieldGeneratorBase {
+ public:
+  WrapperFieldGenerator(const FieldDescriptor* descriptor,
+                        int fieldOrdinal,
+                        const Options *options);
+  ~WrapperFieldGenerator();
+
+  virtual void GenerateCodecCode(io::Printer* printer);
+  virtual void GenerateCloningCode(io::Printer* printer);
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateMergingCode(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+  virtual void WriteHash(io::Printer* printer);
+  virtual void WriteEquals(io::Printer* printer);
+  virtual void WriteToString(io::Printer* printer);
+
+ private:
+  bool is_value_type; // True for int32 etc; false for bytes and string
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperFieldGenerator);
+};
+
+class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
+ public:
+  WrapperOneofFieldGenerator(const FieldDescriptor* descriptor,
+                             int fieldOrdinal,
+                             const Options *options);
+  ~WrapperOneofFieldGenerator();
+
+  virtual void GenerateMembers(io::Printer* printer);
+  virtual void GenerateParsingCode(io::Printer* printer);
+  virtual void GenerateSerializationCode(io::Printer* printer);
+  virtual void GenerateSerializedSizeCode(io::Printer* printer);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperOneofFieldGenerator);
+};
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index e6c446a..0d9093c 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -44,6 +44,9 @@
 
 #include <algorithm>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/importer.h>
 
@@ -122,7 +125,7 @@
 
 bool SourceTreeDescriptorDatabase::FindFileByName(
     const string& filename, FileDescriptorProto* output) {
-  scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
+  google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
   if (input == NULL) {
     if (error_collector_ != NULL) {
       error_collector_->AddError(filename, -1, 0,
@@ -182,6 +185,19 @@
   owner_->error_collector_->AddError(filename, line, column, message);
 }
 
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
+    const string& filename,
+    const string& element_name,
+    const Message* descriptor,
+    ErrorLocation location,
+    const string& message) {
+  if (owner_->error_collector_ == NULL) return;
+
+  int line, column;
+  owner_->source_locations_.Find(descriptor, location, &line, &column);
+  owner_->error_collector_->AddWarning(filename, line, column, message);
+}
+
 // ===================================================================
 
 Importer::Importer(SourceTree* source_tree,
@@ -400,7 +416,7 @@
   // Verify that we can open the file.  Note that this also has the side-effect
   // of verifying that we are not canonicalizing away any non-existent
   // directories.
-  scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
+  google::protobuf::scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
   if (stream == NULL) {
     return CANNOT_OPEN;
   }
@@ -410,7 +426,7 @@
 
 bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file,
                                            string* disk_file) {
-  scoped_ptr<io::ZeroCopyInputStream> stream(
+  google::protobuf::scoped_ptr<io::ZeroCopyInputStream> stream(
       OpenVirtualFile(virtual_file, disk_file));
   return stream != NULL;
 }
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index f010fd0..cc8fcc3 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -121,6 +121,12 @@
                   ErrorLocation location,
                   const string& message);
 
+    virtual void AddWarning(const string& filename,
+                            const string& element_name,
+                            const Message* descriptor,
+                            ErrorLocation location,
+                            const string& message);
+
    private:
     SourceTreeDescriptorDatabase* owner_;
   };
@@ -188,6 +194,9 @@
   virtual void AddError(const string& filename, int line, int column,
                         const string& message) = 0;
 
+  virtual void AddWarning(const string& filename, int line, int column,
+                          const string& message) {}
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
 };
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index 387f135..1b6e970 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -32,20 +32,26 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/compiler/importer.h>
+
 #include <google/protobuf/stubs/hash.h>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
-#include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-
-#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
+#include <google/protobuf/stubs/map_util.h>
 
 namespace google {
 namespace protobuf {
@@ -53,6 +59,10 @@
 
 namespace {
 
+bool FileExists(const string& path) {
+  return File::Exists(path);
+}
+
 #define EXPECT_SUBSTRING(needle, haystack) \
   EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack))
 
@@ -62,6 +72,7 @@
   ~MockErrorCollector() {}
 
   string text_;
+  string warning_text_;
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const string& filename, int line, int column,
@@ -69,6 +80,12 @@
     strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
                                  filename, line, column, message);
   }
+
+  void AddWarning(const string& filename, int line, int column,
+                  const string& message) {
+    strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n",
+                                 filename, line, column, message);
+  }
 };
 
 // -------------------------------------------------------------------
@@ -114,6 +131,7 @@
 
   // Return the collected error text
   string error() const { return error_collector_.text_; }
+  string warning() const { return error_collector_.warning_text_; }
 
   MockErrorCollector error_collector_;
   MockSourceTree source_tree_;
@@ -215,120 +233,6 @@
     error_collector_.text_);
 }
 
-// TODO(sanjay): The MapField tests below more properly belong in
-// descriptor_unittest, but are more convenient to test here.
-TEST_F(ImporterTest, MapFieldValid) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Item {\n"
-      "  required string key = 1;\n"
-      "}\n"
-      "message Map {\n"
-      "  repeated Item items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  const FileDescriptor* file = importer_.Import("map.proto");
-  ASSERT_TRUE(file != NULL) << error_collector_.text_;
-  EXPECT_EQ("", error_collector_.text_);
-
-  // Check that Map::items points to Item::key
-  const Descriptor* item_type = file->FindMessageTypeByName("Item");
-  ASSERT_TRUE(item_type != NULL);
-  const Descriptor* map_type = file->FindMessageTypeByName("Map");
-  ASSERT_TRUE(map_type != NULL);
-  const FieldDescriptor* key_field = item_type->FindFieldByName("key");
-  ASSERT_TRUE(key_field != NULL);
-  const FieldDescriptor* items_field = map_type->FindFieldByName("items");
-  ASSERT_TRUE(items_field != NULL);
-  EXPECT_EQ(items_field->experimental_map_key(), key_field);
-}
-
-TEST_F(ImporterTest, MapFieldNotRepeated) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Item {\n"
-      "  required string key = 1;\n"
-      "}\n"
-      "message Map {\n"
-      "  required Item items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("only allowed for repeated fields", error());
-}
-
-TEST_F(ImporterTest, MapFieldNotMessageType) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Map {\n"
-      "  repeated int32 items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("only allowed for fields with a message type", error());
-}
-
-TEST_F(ImporterTest, MapFieldTypeNotFound) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Map {\n"
-      "  repeated Unknown items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("not defined", error());
-}
-
-TEST_F(ImporterTest, MapFieldKeyNotFound) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Item {\n"
-      "  required string key = 1;\n"
-      "}\n"
-      "message Map {\n"
-      "  repeated Item items = 1 [experimental_map_key = \"badkey\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("Could not find field", error());
-}
-
-TEST_F(ImporterTest, MapFieldKeyRepeated) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message Item {\n"
-      "  repeated string key = 1;\n"
-      "}\n"
-      "message Map {\n"
-      "  repeated Item items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("must not name a repeated field", error());
-}
-
-TEST_F(ImporterTest, MapFieldKeyNotScalar) {
-  AddFile(
-      "map.proto",
-      "syntax = \"proto2\";\n"
-      "message ItemKey { }\n"
-      "message Item {\n"
-      "  required ItemKey key = 1;\n"
-      "}\n"
-      "message Map {\n"
-      "  repeated Item items = 1 [experimental_map_key = \"key\"];\n"
-      "}\n"
-      );
-  EXPECT_TRUE(importer_.Import("map.proto") == NULL);
-  EXPECT_SUBSTRING("must name a scalar or string", error());
-}
-
 
 // ===================================================================
 
@@ -339,7 +243,7 @@
     dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2");
 
     for (int i = 0; i < dirnames_.size(); i++) {
-      if (File::Exists(dirnames_[i])) {
+      if (FileExists(dirnames_[i])) {
         File::DeleteRecursively(dirnames_[i], NULL, NULL);
       }
       GOOGLE_CHECK_OK(File::CreateDir(dirnames_[i], 0777));
@@ -348,7 +252,9 @@
 
   virtual void TearDown() {
     for (int i = 0; i < dirnames_.size(); i++) {
-      File::DeleteRecursively(dirnames_[i], NULL, NULL);
+      if (FileExists(dirnames_[i])) {
+        File::DeleteRecursively(dirnames_[i], NULL, NULL);
+      }
     }
   }
 
@@ -362,7 +268,7 @@
 
   void ExpectFileContents(const string& filename,
                           const char* expected_contents) {
-    scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+    google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
 
     ASSERT_FALSE(input == NULL);
 
@@ -379,7 +285,7 @@
 
   void ExpectCannotOpenFile(const string& filename,
                             const string& error_message) {
-    scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
+    google::protobuf::scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
     EXPECT_TRUE(input == NULL);
     EXPECT_EQ(error_message, source_tree_.GetLastErrorMessage());
   }
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index 7d21fe6..0a11288 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -43,7 +43,7 @@
 namespace java {
 
 Context::Context(const FileDescriptor* file)
-    : name_resolver_(new ClassNameResolver) {
+    : name_resolver_(new ClassNameResolver), enforce_lite_(false) {
   InitializeFieldGeneratorInfo(file);
 }
 
@@ -189,6 +189,13 @@
   return result;
 }
 
+// Does this message class have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
+  return enforce_lite_ || descriptor->file()->options().optimize_for() !=
+           FileOptions::CODE_SIZE;
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
index 5791445..a480e45 100644
--- a/src/google/protobuf/compiler/java/java_context.h
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -33,6 +33,9 @@
 
 #include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
@@ -43,6 +46,7 @@
   class FieldDescriptor;
   class OneofDescriptor;
   class Descriptor;
+  class EnumDescriptor;
   namespace compiler {
     namespace java {
       class ClassNameResolver;  // name_resolver.h
@@ -75,15 +79,30 @@
   const OneofGeneratorInfo* GetOneofGeneratorInfo(
       const OneofDescriptor* oneof) const;
 
+  // Enforces all the files (including transitive dependencies) to use
+  // LiteRuntime.
+  void SetEnforceLite(bool enforce_lite) {
+    enforce_lite_ = enforce_lite;
+  }
+
+  bool EnforceLite() const {
+    return enforce_lite_;
+  }
+
+  // Does this message class have generated parsing, serialization, and other
+  // standard methods for which reflection-based fallback implementations exist?
+  bool HasGeneratedMethods(const Descriptor* descriptor) const;
+
  private:
   void InitializeFieldGeneratorInfo(const FileDescriptor* file);
   void InitializeFieldGeneratorInfoForMessage(const Descriptor* message);
   void InitializeFieldGeneratorInfoForFields(
       const vector<const FieldDescriptor*>& fields);
 
-  scoped_ptr<ClassNameResolver> name_resolver_;
+  google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
   map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
   map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
+  bool enforce_lite_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
 };
 
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc
index 663f0c9..0b5caba 100644
--- a/src/google/protobuf/compiler/java/java_doc_comment.cc
+++ b/src/google/protobuf/compiler/java/java_doc_comment.cc
@@ -120,9 +120,7 @@
       lines.pop_back();
     }
 
-    printer->Print(
-        " *\n"
-        " * <pre>\n");
+    printer->Print(" * <pre>\n");
     for (int i = 0; i < lines.size(); i++) {
       // Most lines should start with a space.  Watch out for lines that start
       // with a /, since putting that right after the leading asterisk will
@@ -133,7 +131,9 @@
         printer->Print(" *$line$\n", "line", lines[i]);
       }
     }
-    printer->Print(" * </pre>\n");
+    printer->Print(
+        " * </pre>\n"
+        " *\n");
   }
 }
 
@@ -163,12 +163,12 @@
 }
 
 void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
-  printer->Print(
-    "/**\n"
-    " * Protobuf type {@code $fullname$}\n",
-    "fullname", EscapeJavadoc(message->full_name()));
+  printer->Print("/**\n");
   WriteDocCommentBody(printer, message);
-  printer->Print(" */\n");
+  printer->Print(
+    " * Protobuf type {@code $fullname$}\n"
+    " */\n",
+    "fullname", EscapeJavadoc(message->full_name()));
 }
 
 void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
@@ -176,55 +176,55 @@
   // etc., but in practice everyone already knows the difference between these
   // so it's redundant information.
 
-  // We use the field declaration as the first line of the comment, e.g.:
+  // We start the comment with the main body based on the comments from the
+  // .proto file (if present). We then end with the field declaration, e.g.:
   //   optional string foo = 5;
-  // This communicates a lot of information about the field in a small space.
   // If the field is a group, the debug string might end with {.
+  printer->Print("/**\n");
+  WriteDocCommentBody(printer, field);
   printer->Print(
-    "/**\n"
     " * <code>$def$</code>\n",
     "def", EscapeJavadoc(FirstLineOf(field->DebugString())));
-  WriteDocCommentBody(printer, field);
   printer->Print(" */\n");
 }
 
 void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) {
-  printer->Print(
-    "/**\n"
-    " * Protobuf enum {@code $fullname$}\n",
-    "fullname", EscapeJavadoc(enum_->full_name()));
+  printer->Print("/**\n");
   WriteDocCommentBody(printer, enum_);
-  printer->Print(" */\n");
+  printer->Print(
+    " * Protobuf enum {@code $fullname$}\n"
+    " */\n",
+    "fullname", EscapeJavadoc(enum_->full_name()));
 }
 
 void WriteEnumValueDocComment(io::Printer* printer,
                               const EnumValueDescriptor* value) {
-  printer->Print(
-    "/**\n"
-    " * <code>$def$</code>\n",
-    "def", EscapeJavadoc(FirstLineOf(value->DebugString())));
+  printer->Print("/**\n");
   WriteDocCommentBody(printer, value);
-  printer->Print(" */\n");
+  printer->Print(
+    " * <code>$def$</code>\n"
+    " */\n",
+    "def", EscapeJavadoc(FirstLineOf(value->DebugString())));
 }
 
 void WriteServiceDocComment(io::Printer* printer,
                             const ServiceDescriptor* service) {
-  printer->Print(
-    "/**\n"
-    " * Protobuf service {@code $fullname$}\n",
-    "fullname", EscapeJavadoc(service->full_name()));
+  printer->Print("/**\n");
   WriteDocCommentBody(printer, service);
-  printer->Print(" */\n");
+  printer->Print(
+    " * Protobuf service {@code $fullname$}\n"
+    " */\n",
+    "fullname", EscapeJavadoc(service->full_name()));
 }
 
 void WriteMethodDocComment(io::Printer* printer,
                            const MethodDescriptor* method) {
-  printer->Print(
-    "/**\n"
-    " * <code>$def$</code>\n",
-    "def", EscapeJavadoc(FirstLineOf(method->DebugString())));
+  printer->Print("/**\n");
   WriteDocCommentBody(printer, method);
-  printer->Print(" */\n");
+  printer->Print(
+    " * <code>$def$</code>\n"
+    " */\n",
+    "def", EscapeJavadoc(FirstLineOf(method->DebugString())));
 }
 
 }  // namespace java
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 668377a..947b80e 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -64,6 +64,7 @@
                              bool immutable_api,
                              Context* context)
   : descriptor_(descriptor), immutable_api_(immutable_api),
+    context_(context),
     name_resolver_(context->GetNameResolver())  {
   for (int i = 0; i < descriptor_->value_count(); i++) {
     const EnumValueDescriptor* value = descriptor_->value(i);
@@ -85,19 +86,22 @@
 
 void EnumGenerator::Generate(io::Printer* printer) {
   WriteEnumDocComment(printer, descriptor_);
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
-      "classname", descriptor_->name());
-  } else {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.Internal.EnumLite {\n",
-      "classname", descriptor_->name());
-  }
+  printer->Print(
+    "public enum $classname$\n"
+    "    implements com.google.protobuf.ProtocolMessageEnum {\n",
+    "classname", descriptor_->name());
   printer->Indent();
 
+  bool ordinal_is_index = true;
+  string index_text = "ordinal()";
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    if (canonical_values_[i]->index() != i) {
+      ordinal_is_index = false;
+      index_text = "index";
+      break;
+    }
+  }
+
   for (int i = 0; i < canonical_values_.size(); i++) {
     map<string, string> vars;
     vars["name"] = canonical_values_[i]->name();
@@ -107,8 +111,21 @@
     if (canonical_values_[i]->options().deprecated()) {
       printer->Print("@java.lang.Deprecated\n");
     }
-    printer->Print(vars,
-      "$name$($index$, $number$),\n");
+    if (ordinal_is_index) {
+      printer->Print(vars,
+        "$name$($number$),\n");
+    } else {
+      printer->Print(vars,
+        "$name$($index$, $number$),\n");
+    }
+  }
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    if (ordinal_is_index) {
+      printer->Print("UNRECOGNIZED(-1),\n");
+    } else {
+      printer->Print("UNRECOGNIZED(-1, -1),\n");
+    }
   }
 
   printer->Print(
@@ -141,9 +158,35 @@
 
   printer->Print(
     "\n"
-    "public final int getNumber() { return value; }\n"
+    "public final int getNumber() {\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    if (ordinal_is_index) {
+      printer->Print(
+        "  if (this == UNRECOGNIZED) {\n"
+        "    throw new java.lang.IllegalArgumentException(\n"
+        "        \"Can't get the number of an unknown enum value.\");\n"
+        "  }\n");
+    } else {
+      printer->Print(
+        "  if (index == -1) {\n"
+        "    throw new java.lang.IllegalArgumentException(\n"
+        "        \"Can't get the number of an unknown enum value.\");\n"
+        "  }\n");
+    }
+  }
+  printer->Print(
+    "  return value;\n"
+    "}\n"
     "\n"
+    "/**\n"
+    " * @deprecated Use {@link #forNumber(int)} instead.\n"
+    " */\n"
+    "@java.lang.Deprecated\n"
     "public static $classname$ valueOf(int value) {\n"
+    "  return forNumber(value);\n"
+    "}\n"
+    "\n"
+    "public static $classname$ forNumber(int value) {\n"
     "  switch (value) {\n",
     "classname", descriptor_->name());
   printer->Indent();
@@ -167,11 +210,11 @@
     "    internalGetValueMap() {\n"
     "  return internalValueMap;\n"
     "}\n"
-    "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
-    "    internalValueMap =\n"
+    "private static final com.google.protobuf.Internal.EnumLiteMap<\n"
+    "    $classname$> internalValueMap =\n"
     "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
     "        public $classname$ findValueByNumber(int number) {\n"
-    "          return $classname$.valueOf(number);\n"
+    "          return $classname$.forNumber(number);\n"
     "        }\n"
     "      };\n"
     "\n",
@@ -180,18 +223,19 @@
   // -----------------------------------------------------------------
   // Reflection
 
-  if (HasDescriptorMethods(descriptor_)) {
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
     printer->Print(
       "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
       "    getValueDescriptor() {\n"
-      "  return getDescriptor().getValues().get(index);\n"
+      "  return getDescriptor().getValues().get($index_text$);\n"
       "}\n"
       "public final com.google.protobuf.Descriptors.EnumDescriptor\n"
       "    getDescriptorForType() {\n"
       "  return getDescriptor();\n"
       "}\n"
       "public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
-      "    getDescriptor() {\n");
+      "    getDescriptor() {\n",
+      "index_text", index_text);
 
     // TODO(kenton):  Cache statically?  Note that we can't access descriptors
     //   at module init time because it wouldn't work with descriptor.proto, but
@@ -222,7 +266,7 @@
             "      (com.google.protobuf.Descriptors.FileDescriptor)\n"
             "          m.invoke(immutableFileClass);\n"
             "  return file.getEnumTypes().get($index$);\n"
-            "} catch (Exception e) {\n"
+            "} catch (java.lang.Exception e) {\n"
             // Immutable classes cannot be found. Proceed as if custom options
             // don't exist.
             "}\n",
@@ -231,11 +275,12 @@
             "index", SimpleItoa(descriptor_->index()));
         }
         printer->Print(
-          "return $immutable_package$.$descriptor_class$.getDescriptor()\n"
+          "return $immutable_package$.$descriptor_class$.$descriptor$\n"
           "    .getEnumTypes().get($index$);\n",
           "immutable_package", FileJavaPackage(descriptor_->file(), true),
           "descriptor_class",
           name_resolver_->GetDescriptorClassName(descriptor_->file()),
+          "descriptor", "getDescriptor()",
           "index", SimpleItoa(descriptor_->index()));
         printer->Outdent();
       }
@@ -283,23 +328,40 @@
       "  if (desc.getType() != getDescriptor()) {\n"
       "    throw new java.lang.IllegalArgumentException(\n"
       "      \"EnumValueDescriptor is not for this type.\");\n"
-      "  }\n"
+      "  }\n",
+      "classname", descriptor_->name());
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+        "  if (desc.getIndex() == -1) {\n"
+        "    return UNRECOGNIZED;\n"
+        "  }\n");
+    }
+    printer->Print(
       "  return VALUES[desc.getIndex()];\n"
       "}\n"
-      "\n",
-      "classname", descriptor_->name());
+      "\n");
 
-    // index is only used for reflection; lite implementation does not need it
-    printer->Print("private final int index;\n");
+    if (!ordinal_is_index) {
+      printer->Print("private final int index;\n");
+    }
   }
 
   // -----------------------------------------------------------------
 
   printer->Print(
-    "private final int value;\n\n"
-    "private $classname$(int index, int value) {\n",
-    "classname", descriptor_->name());
-  if (HasDescriptorMethods(descriptor_)) {
+    "private final int value;\n\n");
+
+  if (ordinal_is_index) {
+    printer->Print(
+      "private $classname$(int value) {\n",
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "private $classname$(int index, int value) {\n",
+      "classname", descriptor_->name());
+  }
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) &&
+      !ordinal_is_index) {
     printer->Print("  this.index = index;\n");
   }
   printer->Print(
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 1f0c4af..3e54be3 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -35,6 +35,7 @@
 #include <map>
 #include <string>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
@@ -65,6 +66,8 @@
   (*variables)["mutable_type"] =
       name_resolver->GetMutableClassName(descriptor->enum_type());
   (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_number"] = SimpleItoa(
+      descriptor->default_value_enum()->number());
   (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
@@ -72,8 +75,7 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -95,7 +97,8 @@
     (*variables)["clear_has_field_bit_builder"] = "";
 
     (*variables)["is_field_present_message"] =
-          (*variables)["name"] + "_ != " + (*variables)["default"];
+        (*variables)["name"] + "_ != " +
+        (*variables)["default"] + ".getNumber()";
   }
 
   // For repated builders, one bit is used for whether the array is immutable.
@@ -114,6 +117,12 @@
       GenerateGetBitFromLocal(builderBitIndex);
   (*variables)["set_has_field_bit_to_local"] =
       GenerateSetBitToLocal(messageBitIndex);
+
+  if (SupportUnknownEnumValue(descriptor->file())) {
+    (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED";
+  } else {
+    (*variables)["unknown"] = (*variables)["default"];
+  }
 }
 
 }  // namespace
@@ -150,6 +159,11 @@
     printer->Print(variables_,
       "$deprecation$boolean has$capitalized_name$();\n");
   }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value();\n");
+  }
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$$type$ get$capitalized_name$();\n");
@@ -158,7 +172,7 @@
 void ImmutableEnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private $type$ $name$_;\n");
+    "private int $name$_;\n");
   PrintExtraFieldInfo(variables_, printer);
   if (SupportFieldPresence(descriptor_->file())) {
     WriteFieldDocComment(printer, descriptor_);
@@ -167,17 +181,25 @@
       "  return $get_has_field_bit_message$;\n"
       "}\n");
   }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  }
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  return $name$_;\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
+    "  return result == null ? $unknown$ : result;\n"
     "}\n");
 }
 
 void ImmutableEnumFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private $type$ $name$_ = $default$;\n");
+    "private int $name$_ = $default_number$;\n");
   if (SupportFieldPresence(descriptor_->file())) {
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -185,10 +207,25 @@
       "  return $get_has_field_bit_builder$;\n"
       "}\n");
   }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return $name$_;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  $name$_ = value;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  }
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  return $name$_;\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
+    "  return result == null ? $unknown$ : result;\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -197,7 +234,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  $set_has_field_bit_builder$\n"
-    "  $name$_ = value;\n"
+    "  $name$_ = value.getNumber();\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -205,7 +242,7 @@
   printer->Print(variables_,
     "$deprecation$public Builder clear$capitalized_name$() {\n"
     "  $clear_has_field_bit_builder$\n"
-    "  $name$_ = $default$;\n"
+    "  $name$_ = $default_number$;\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -218,13 +255,13 @@
 
 void ImmutableEnumFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_ = $default$;\n");
+  printer->Print(variables_, "$name$_ = $default_number$;\n");
 }
 
 void ImmutableEnumFieldGenerator::
 GenerateBuilderClearCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$_ = $default$;\n"
+    "$name$_ = $default_number$;\n"
     "$clear_has_field_bit_builder$\n");
 }
 
@@ -235,11 +272,13 @@
       "if (other.has$capitalized_name$()) {\n"
       "  set$capitalized_name$(other.get$capitalized_name$());\n"
       "}\n");
-  } else {
+  } else if (SupportUnknownEnumValue(descriptor_->file())) {
     printer->Print(variables_,
-      "if (other.get$capitalized_name$() != $default$) {\n"
-      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "if (other.$name$_ != $default_number$) {\n"
+      "  set$capitalized_name$Value(other.get$capitalized_name$Value());\n"
       "}\n");
+  } else {
+    GOOGLE_LOG(FATAL) << "Can't reach here.";
   }
 }
 
@@ -257,23 +296,26 @@
 
 void ImmutableEnumFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "int rawValue = input.readEnum();\n"
-    "$type$ value = $type$.valueOf(rawValue);\n"
-    "if (value == null) {\n");
-  if (UseUnknownFieldSet(descriptor_->containing_type())) {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
     printer->Print(variables_,
-      "  unknownFields.mergeVarintField($number$, rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = rawValue;\n");
   } else {
     printer->Print(variables_,
-      "  unknownFieldsCodedOutput.writeRawVarint32(tag);\n"
-      "  unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_has_field_bit_message$\n"
+      "  $name$_ = rawValue;\n"
+      "}\n");
   }
-  printer->Print(variables_,
-    "} else {\n"
-    "  $set_has_field_bit_message$\n"
-    "  $name$_ = value;\n"
-    "}\n");
 }
 
 void ImmutableEnumFieldGenerator::
@@ -285,7 +327,7 @@
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
-    "  output.writeEnum($number$, $name$_.getNumber());\n"
+    "  output.writeEnum($number$, $name$_);\n"
     "}\n");
 }
 
@@ -294,23 +336,21 @@
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSize($number$, $name$_.getNumber());\n"
+    "    .computeEnumSize($number$, $name$_);\n"
     "}\n");
 }
 
 void ImmutableEnumFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "result = result &&\n"
-    "    (get$capitalized_name$() == other.get$capitalized_name$());\n");
+    "result = result && $name$_ == other.$name$_;\n");
 }
 
 void ImmutableEnumFieldGenerator::
 GenerateHashCode(io::Printer* printer) const {
   printer->Print(variables_,
     "hash = (37 * hash) + $constant_name$;\n"
-    "hash = (53 * hash) + com.google.protobuf.Internal.hashEnum(\n"
-    "    get$capitalized_name$());\n");
+    "hash = (53 * hash) + $name$_;\n");
 }
 
 string ImmutableEnumFieldGenerator::GetBoxedType() const {
@@ -344,11 +384,22 @@
       "  return $has_oneof_case_message$;\n"
       "}\n");
   }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    return (java.lang.Integer) $oneof_name$_;\n"
+      "  }\n"
+      "  return $default_number$;\n"
+      "}\n");
+  }
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    return ($type$) $oneof_name$_;\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+    "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
     "}\n");
@@ -363,11 +414,30 @@
       "  return $has_oneof_case_message$;\n"
       "}\n");
   }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    return ((java.lang.Integer) $oneof_name$_).intValue();\n"
+      "  }\n"
+      "  return $default_number$;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = value;\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  }
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    return ($type$) $oneof_name$_;\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+    "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
     "}\n");
@@ -378,7 +448,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  $set_oneof_case_message$;\n"
-    "  $oneof_name$_ = value;\n"
+    "  $oneof_name$_ = value.getNumber();\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -404,36 +474,44 @@
 
 void ImmutableEnumOneofFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "set$capitalized_name$(other.get$capitalized_name$());\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "set$capitalized_name$Value(other.get$capitalized_name$Value());\n");
+  } else {
+    printer->Print(variables_,
+      "set$capitalized_name$(other.get$capitalized_name$());\n");
+  }
 }
 
 void ImmutableEnumOneofFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "int rawValue = input.readEnum();\n"
-    "$type$ value = $type$.valueOf(rawValue);\n"
-    "if (value == null) {\n");
-  if (UseUnknownFieldSet(descriptor_->containing_type())) {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
     printer->Print(variables_,
-      "  unknownFields.mergeVarintField($number$, rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = rawValue;\n");
   } else {
     printer->Print(variables_,
-      "  unknownFieldsCodedOutput.writeRawVarint32(tag);\n"
-      "  unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = rawValue;\n"
+      "}\n");
   }
-  printer->Print(variables_,
-    "} else {\n"
-    "  $set_oneof_case_message$;\n"
-    "  $oneof_name$_ = value;\n"
-    "}\n");
 }
 
 void ImmutableEnumOneofFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($has_oneof_case_message$) {\n"
-    "  output.writeEnum($number$, (($type$) $oneof_name$_).getNumber());\n"
+    "  output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
     "}\n");
 }
 
@@ -442,10 +520,36 @@
   printer->Print(variables_,
     "if ($has_oneof_case_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSize($number$, (($type$) $oneof_name$_).getNumber());\n"
+    "    .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n"
     "}\n");
 }
 
+void ImmutableEnumOneofFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$Value()\n"
+      "    == other.get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$()\n"
+      "    .equals(other.get$capitalized_name$());\n");
+  }
+}
+
+void ImmutableEnumOneofFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
+  }
+}
+
 // ===================================================================
 
 RepeatedImmutableEnumFieldGenerator::
@@ -482,17 +586,36 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value(int index);\n");
+  }
 }
 
 void RepeatedImmutableEnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.util.List<$type$> $name$_;\n");
+    "private java.util.List<java.lang.Integer> $name$_;\n"
+    "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "    java.lang.Integer, $type$> $name$_converter_ =\n"
+    "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "            java.lang.Integer, $type$>() {\n"
+    "          public $type$ convert(java.lang.Integer from) {\n"
+    "            $type$ result = $type$.forNumber(from);\n"
+    "            return result == null ? $unknown$ : result;\n"
+    "          }\n"
+    "        };\n");
   PrintExtraFieldInfo(variables_, printer);
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
-    "  return $name$_;\n"   // note:  unmodifiable list
+    "  return new com.google.protobuf.Internal.ListAdapter<\n"
+    "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -502,11 +625,24 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
-    "  return $name$_.get(index);\n"
+    "  return $name$_converter_.convert($name$_.get(index));\n"
     "}\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return $name$_;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n");
+  }
 
-  if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+  if (descriptor_->is_packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
   }
@@ -524,12 +660,12 @@
     // memory allocations. Note, immutable is a strong guarantee here -- not
     // just that the list cannot be modified via the reference but that the
     // list can never be modified.
-    "private java.util.List<$type$> $name$_ =\n"
+    "private java.util.List<java.lang.Integer> $name$_ =\n"
     "  java.util.Collections.emptyList();\n"
 
     "private void ensure$capitalized_name$IsMutable() {\n"
     "  if (!$get_mutable_bit_builder$) {\n"
-    "    $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
+    "    $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n"
     "    $set_mutable_bit_builder$;\n"
     "  }\n"
     "}\n");
@@ -541,7 +677,8 @@
     //   has been built, thus mutating the message which is supposed to be
     //   immutable.
     "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
-    "  return java.util.Collections.unmodifiableList($name$_);\n"
+    "  return new com.google.protobuf.Internal.ListAdapter<\n"
+    "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -551,7 +688,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
-    "  return $name$_.get(index);\n"
+    "  return $name$_converter_.convert($name$_.get(index));\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -561,7 +698,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  ensure$capitalized_name$IsMutable();\n"
-    "  $name$_.set(index, value);\n"
+    "  $name$_.set(index, value.getNumber());\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -572,7 +709,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  ensure$capitalized_name$IsMutable();\n"
-    "  $name$_.add(value);\n"
+    "  $name$_.add(value.getNumber());\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -581,8 +718,9 @@
     "$deprecation$public Builder addAll$capitalized_name$(\n"
     "    java.lang.Iterable<? extends $type$> values) {\n"
     "  ensure$capitalized_name$IsMutable();\n"
-    "  com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
-    "      values, $name$_);\n"
+    "  for ($type$ value : values) {\n"
+    "    $name$_.add(value.getNumber());\n"
+    "  }\n"
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
@@ -594,6 +732,48 @@
     "  $on_changed$\n"
     "  return this;\n"
     "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return java.util.Collections.unmodifiableList($name$_);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(\n"
+      "    int index, int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.set(index, value);\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder add$capitalized_name$Value(int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.add(value);\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder addAll$capitalized_name$Value(\n"
+      "    java.lang.Iterable<java.lang.Integer> values) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  for (int value : values) {\n"
+      "    $name$_.add(value);\n"
+      "  }\n"
+      "  $on_changed$\n"
+      "  return this;\n"
+      "}\n");
+  }
 }
 
 void RepeatedImmutableEnumFieldGenerator::
@@ -648,26 +828,32 @@
 void RepeatedImmutableEnumFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   // Read and store the enum
-  printer->Print(variables_,
-    "int rawValue = input.readEnum();\n"
-    "$type$ value = $type$.valueOf(rawValue);\n"
-    "if (value == null) {\n");
-  if (UseUnknownFieldSet(descriptor_->containing_type())) {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
     printer->Print(variables_,
-      "  unknownFields.mergeVarintField($number$, rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "if (!$get_mutable_bit_parser$) {\n"
+      "  $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+      "  $set_mutable_bit_parser$;\n"
+      "}\n"
+      "$name$_.add(rawValue);\n");
   } else {
     printer->Print(variables_,
-      "  unknownFieldsCodedOutput.writeRawVarint32(tag);\n"
-      "  unknownFieldsCodedOutput.writeRawVarint32(rawValue);\n");
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+        "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  if (!$get_mutable_bit_parser$) {\n"
+      "    $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+      "    $set_mutable_bit_parser$;\n"
+      "  }\n"
+      "  $name$_.add(rawValue);\n"
+      "}\n");
   }
-  printer->Print(variables_,
-    "  } else {\n"
-    "  if (!$get_mutable_bit_parser$) {\n"
-    "    $name$_ = new java.util.ArrayList<$type$>();\n"
-    "    $set_mutable_bit_parser$;\n"
-    "  }\n"
-    "  $name$_.add(value);\n"
-    "}\n");
 }
 
 void RepeatedImmutableEnumFieldGenerator::
@@ -698,19 +884,19 @@
 
 void RepeatedImmutableEnumFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
       "  output.writeRawVarint32($tag$);\n"
       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeEnumNoTag($name$_.get(i).getNumber());\n"
+      "  output.writeEnumNoTag($name$_.get(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeEnum($number$, $name$_.get(i).getNumber());\n"
+      "  output.writeEnum($number$, $name$_.get(i));\n"
       "}\n");
   }
 }
@@ -725,11 +911,11 @@
   printer->Print(variables_,
     "for (int i = 0; i < $name$_.size(); i++) {\n"
     "  dataSize += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSizeNoTag($name$_.get(i).getNumber());\n"
+    "    .computeEnumSizeNoTag($name$_.get(i));\n"
     "}\n");
   printer->Print(
     "size += dataSize;\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (!get$capitalized_name$List().isEmpty()) {"
       "  size += $tag_size$;\n"
@@ -742,7 +928,7 @@
   }
 
   // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "$name$MemoizedSerializedSize = dataSize;\n");
   }
@@ -754,8 +940,7 @@
 void RepeatedImmutableEnumFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "result = result && get$capitalized_name$List()\n"
-    "    .equals(other.get$capitalized_name$List());\n");
+    "result = result && $name$_.equals(other.$name$_);\n");
 }
 
 void RepeatedImmutableEnumFieldGenerator::
@@ -763,8 +948,7 @@
   printer->Print(variables_,
     "if (get$capitalized_name$Count() > 0) {\n"
     "  hash = (37 * hash) + $constant_name$;\n"
-    "  hash = (53 * hash) + com.google.protobuf.Internal.hashEnumList(\n"
-    "      get$capitalized_name$List());\n"
+    "  hash = (53 * hash) + $name$_.hashCode();\n"
     "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 6a9535a..b8ff734 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -106,6 +106,8 @@
   void GenerateParsingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldGenerator);
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
new file mode 100644
index 0000000..908d6db
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -0,0 +1,960 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex,
+                      const FieldGeneratorInfo* info,
+                      ClassNameResolver* name_resolver,
+                      map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->enum_type());
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->enum_type());
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_number"] = SimpleItoa(
+      descriptor->default_value_enum()->number());
+  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != " +
+        (*variables)["default"] + ".getNumber()";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+
+  if (SupportUnknownEnumValue(descriptor->file())) {
+    (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED";
+  } else {
+    (*variables)["unknown"] = (*variables)["default"];
+  }
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableEnumFieldLiteGenerator::
+ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                            int messageBitIndex,
+                            int builderBitIndex,
+                            Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex),
+    name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor),
+                   name_resolver_, &variables_);
+}
+
+ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private int $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
+    "  return result == null ? $unknown$ : result;\n"
+    "}\n");
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(int value) {\n"
+      "  $set_has_field_bit_message$"
+      "  $name$_ = value;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value.getNumber();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n"
+    "  $name$_ = $default_number$;\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return instance.get$capitalized_name$Value();\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(value);\n"
+      "  return this;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default_number$;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_ = visitor.visitInt(has$capitalized_name$(), $name$_,\n"
+      "    other.has$capitalized_name$(), other.$name$_);\n");
+  } else if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_ = visitor.visitInt($name$_ != $default_number$, $name$_,"
+      "    other.$name$_ != $default_number$, other.$name$_);\n");
+  } else {
+    GOOGLE_LOG(FATAL) << "Can't reach here.";
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = rawValue;\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  super.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_has_field_bit_message$\n"
+      "  $name$_ = rawValue;\n"
+      "}\n");
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.writeEnum($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSize($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && $name$_ == other.$name$_;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + $name$_;\n");
+}
+
+string ImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+ImmutableEnumOneofFieldLiteGenerator::
+ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutableEnumFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableEnumOneofFieldLiteGenerator::
+~ImmutableEnumOneofFieldLiteGenerator() {}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    return (java.lang.Integer) $oneof_name$_;\n"
+      "  }\n"
+      "  return $default_number$;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+    "    return result == null ? $unknown$ : result;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n");
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(int value) {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = value;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value.getNumber();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return instance.get$capitalized_name$Value();\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(value);\n"
+      "  return this;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$oneof_name$_ = visitor.visitOneofInt(\n"
+    "   $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = rawValue;\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  super.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = rawValue;\n"
+      "}\n");
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$Value()\n"
+      "    == other.get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$()\n"
+      "    .equals(other.get$capitalized_name$());\n");
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
+  }
+}
+
+// ===================================================================
+
+RepeatedImmutableEnumFieldLiteGenerator::
+RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                    int messageBitIndex,
+                                    int builderBitIndex,
+                                    Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor),
+                   name_resolver_, &variables_);
+}
+
+RepeatedImmutableEnumFieldLiteGenerator::
+~RepeatedImmutableEnumFieldLiteGenerator() {}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value(int index);\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.IntList $name$_;\n"
+    "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "    java.lang.Integer, $type$> $name$_converter_ =\n"
+    "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "            java.lang.Integer, $type$>() {\n"
+    "          public $type$ convert(java.lang.Integer from) {\n"
+    "            $type$ result = $type$.forNumber(from);\n"
+    "            return result == null ? $unknown$ : result;\n"
+    "          }\n"
+    "        };\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return new com.google.protobuf.Internal.ListAdapter<\n"
+    "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_converter_.convert($name$_.getInt(index));\n"
+    "}\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return $name$_;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return $name$_.getInt(index);\n"
+      "}\n");
+  }
+
+  if (descriptor_->options().packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize;\n");
+  }
+
+  // Generate private setters for the builder to proxy into.
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ =\n"
+    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.setInt(index, value.getNumber());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.addInt(value.getNumber());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  for ($type$ value : values) {\n"
+    "    $name$_.addInt(value.getNumber());\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyIntList();\n"
+    "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(\n"
+      "    int index, int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.setInt(index, value);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void add$capitalized_name$Value(int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.addInt(value);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void addAll$capitalized_name$Value(\n"
+      "    java.lang.Iterable<java.lang.Integer> values) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  for (int value : values) {\n"
+      "    $name$_.addInt(value);\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return instance.get$capitalized_name$List();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return java.util.Collections.unmodifiableList(\n"
+      "      instance.get$capitalized_name$ValueList());\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return instance.get$capitalized_name$Value(index);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(\n"
+      "    int index, int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(index, value);\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder add$capitalized_name$Value(int value) {\n"
+      "  instance.add$capitalized_name$Value(value);\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder addAll$capitalized_name$Value(\n"
+      "    java.lang.Iterable<java.lang.Integer> values) {\n"
+      "  copyOnWrite();\n"
+      "  instance.addAll$capitalized_name$Value(values);\n"
+      "  return this;\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyIntList();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_= visitor.visitIntList($name$_, other.$name$_);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  // Read and store the enum
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_.addInt(input.readEnum());\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n"
+      // We store the unknown value in unknown fields.
+      "  super.mergeVarintField($number$, rawValue);\n"
+      "} else {\n"
+      "  $name$_.addInt(rawValue);\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int oldLimit = input.pushLimit(length);\n"
+    "while(input.getBytesUntilLimit() > 0) {\n");
+  printer->Indent();
+
+  // Read and store the enum
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_.addInt(input.readEnum());\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
+      "if (value == null) {\n"
+      // We store the unknown value in unknown fields.
+      "  super.mergeVarintField($number$, rawValue);\n"
+      "} else {\n"
+      "  $name$_.addInt(rawValue);\n"
+      "}\n");
+  }
+
+  printer->Outdent();
+  printer->Print(variables_,
+    "}\n"
+    "input.popLimit(oldLimit);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (get$capitalized_name$List().size() > 0) {\n"
+      "  output.writeRawVarint32($tag$);\n"
+      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "}\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnumNoTag($name$_.getInt(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnum($number$, $name$_.getInt(i));\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  dataSize += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSizeNoTag($name$_.getInt(i));\n"
+    "}\n");
+  printer->Print(
+    "size += dataSize;\n");
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (!get$capitalized_name$List().isEmpty()) {"
+      "  size += $tag_size$;\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "    .computeRawVarint32Size(dataSize);\n"
+      "}");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * $name$_.size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && $name$_.equals(other.$name$_);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + $name$_.hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h
new file mode 100644
index 0000000..9201b8d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h
@@ -0,0 +1,159 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;            // context.h
+      class ClassNameResolver;  // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableEnumFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableEnumFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator);
+};
+
+class ImmutableEnumOneofFieldLiteGenerator
+    : public ImmutableEnumFieldLiteGenerator {
+ public:
+  ImmutableEnumOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableEnumOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableEnumFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableEnumFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableEnumFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
new file mode 100644
index 0000000..c22da8d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -0,0 +1,218 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool EnumHasCustomOptions(const EnumDescriptor* descriptor) {
+  if (descriptor->options().unknown_fields().field_count() > 0) return true;
+  for (int i = 0; i < descriptor->value_count(); ++i) {
+    const EnumValueDescriptor* value = descriptor->value(i);
+    if (value->options().unknown_fields().field_count() > 0) return true;
+  }
+  return false;
+}
+}  // namespace
+
+EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor,
+                             bool immutable_api,
+                             Context* context)
+  : descriptor_(descriptor), immutable_api_(immutable_api),
+    name_resolver_(context->GetNameResolver())  {
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    const EnumValueDescriptor* value = descriptor_->value(i);
+    const EnumValueDescriptor* canonical_value =
+      descriptor_->FindValueByNumber(value->number());
+
+    if (value == canonical_value) {
+      canonical_values_.push_back(value);
+    } else {
+      Alias alias;
+      alias.value = value;
+      alias.canonical_value = canonical_value;
+      aliases_.push_back(alias);
+    }
+  }
+}
+
+EnumLiteGenerator::~EnumLiteGenerator() {}
+
+void EnumLiteGenerator::Generate(io::Printer* printer) {
+  WriteEnumDocComment(printer, descriptor_);
+  printer->Print(
+    "public enum $classname$\n"
+    "    implements com.google.protobuf.Internal.EnumLite {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    map<string, string> vars;
+    vars["name"] = canonical_values_[i]->name();
+    vars["number"] = SimpleItoa(canonical_values_[i]->number());
+    WriteEnumValueDocComment(printer, canonical_values_[i]);
+    if (canonical_values_[i]->options().deprecated()) {
+      printer->Print("@java.lang.Deprecated\n");
+    }
+    printer->Print(vars,
+      "$name$($number$),\n");
+  }
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print("UNRECOGNIZED(-1),\n");
+  }
+
+  printer->Print(
+    ";\n"
+    "\n");
+
+  // -----------------------------------------------------------------
+
+  for (int i = 0; i < aliases_.size(); i++) {
+    map<string, string> vars;
+    vars["classname"] = descriptor_->name();
+    vars["name"] = aliases_[i].value->name();
+    vars["canonical_name"] = aliases_[i].canonical_value->name();
+    WriteEnumValueDocComment(printer, aliases_[i].value);
+    printer->Print(vars,
+      "public static final $classname$ $name$ = $canonical_name$;\n");
+  }
+
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    map<string, string> vars;
+    vars["name"] = descriptor_->value(i)->name();
+    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+    WriteEnumValueDocComment(printer, descriptor_->value(i));
+    printer->Print(vars,
+      "public static final int $name$_VALUE = $number$;\n");
+  }
+  printer->Print("\n");
+
+  // -----------------------------------------------------------------
+
+  printer->Print(
+    "\n"
+    "public final int getNumber() {\n"
+    "  return value;\n"
+    "}\n"
+    "\n"
+    "/**\n"
+    " * @deprecated Use {@link #forNumber(int)} instead.\n"
+    " */\n"
+    "@java.lang.Deprecated\n"
+    "public static $classname$ valueOf(int value) {\n"
+    "  return forNumber(value);\n"
+    "}\n"
+    "\n"
+    "public static $classname$ forNumber(int value) {\n"
+    "  switch (value) {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+  printer->Indent();
+
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    printer->Print(
+      "case $number$: return $name$;\n",
+      "name", canonical_values_[i]->name(),
+      "number", SimpleItoa(canonical_values_[i]->number()));
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+    "    default: return null;\n"
+    "  }\n"
+    "}\n"
+    "\n"
+    "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
+    "    internalGetValueMap() {\n"
+    "  return internalValueMap;\n"
+    "}\n"
+    "private static final com.google.protobuf.Internal.EnumLiteMap<\n"
+    "    $classname$> internalValueMap =\n"
+    "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
+    "        public $classname$ findValueByNumber(int number) {\n"
+    "          return $classname$.forNumber(number);\n"
+    "        }\n"
+    "      };\n"
+    "\n",
+    "classname", descriptor_->name());
+
+  printer->Print(
+    "private final int value;\n\n"
+    "private $classname$(int value) {\n",
+    "classname", descriptor_->name());
+  printer->Print(
+    "  this.value = value;\n"
+    "}\n");
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(enum_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+bool EnumLiteGenerator::CanUseEnumValues() {
+  if (canonical_values_.size() != descriptor_->value_count()) {
+    return false;
+  }
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    if (descriptor_->value(i)->name() != canonical_values_[i]->name()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h
new file mode 100644
index 0000000..ee2f5f7
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_lite.h
@@ -0,0 +1,99 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__
+
+#include <string>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class EnumLiteGenerator {
+ public:
+  explicit EnumLiteGenerator(const EnumDescriptor* descriptor,
+                         bool immutable_api,
+                         Context* context);
+  ~EnumLiteGenerator();
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const EnumDescriptor* descriptor_;
+
+  // The proto language allows multiple enum constants to have the same numeric
+  // value.  Java, however, does not allow multiple enum constants to be
+  // considered equivalent.  We treat the first defined constant for any
+  // given numeric value as "canonical" and the rest as aliases of that
+  // canonical value.
+  vector<const EnumValueDescriptor*> canonical_values_;
+
+  struct Alias {
+    const EnumValueDescriptor* value;
+    const EnumValueDescriptor* canonical_value;
+  };
+  vector<Alias> aliases_;
+
+  bool immutable_api_;
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  bool CanUseEnumValues();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 27cf416..46b5faa 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -118,87 +118,54 @@
       "public static final int $constant_name$ = $number$;\n");
 
   WriteFieldDocComment(printer, descriptor_);
-  if (HasDescriptorMethods(descriptor_->file())) {
-    // Non-lite extensions
-    if (descriptor_->extension_scope() == NULL) {
-      // Non-nested
-      printer->Print(
-          vars,
-          "public static final\n"
-          "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
-          "    $containing_type$,\n"
-          "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
-          "        .newFileScopedGeneratedExtension(\n"
-          "      $singular_type$.class,\n"
-          "      $prototype$);\n");
-    } else {
-      // Nested
-      printer->Print(
-          vars,
-          "public static final\n"
-          "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
-          "    $containing_type$,\n"
-          "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
-          "        .newMessageScopedGeneratedExtension(\n"
-          "      $scope$.getDefaultInstance(),\n"
-          "      $index$,\n"
-          "      $singular_type$.class,\n"
-          "      $prototype$);\n");
-    }
+  if (descriptor_->extension_scope() == NULL) {
+    // Non-nested
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+        "        .newFileScopedGeneratedExtension(\n"
+        "      $singular_type$.class,\n"
+        "      $prototype$);\n");
   } else {
-    // Lite extensions
-    if (descriptor_->is_repeated()) {
-      printer->Print(
-          vars,
-          "public static final\n"
-          "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
-          "    $containing_type$,\n"
-          "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
-          "        .newRepeatedGeneratedExtension(\n"
-          "      $containing_type$.getDefaultInstance(),\n"
-          "      $prototype$,\n"
-          "      $enum_map$,\n"
-          "      $number$,\n"
-          "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
-          "      $packed$,\n"
-          "      $singular_type$.class);\n");
-    } else {
-      printer->Print(
-          vars,
-          "public static final\n"
-          "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
-          "    $containing_type$,\n"
-          "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
-          "        .newSingularGeneratedExtension(\n"
-          "      $containing_type$.getDefaultInstance(),\n"
-          "      $default$,\n"
-          "      $prototype$,\n"
-          "      $enum_map$,\n"
-          "      $number$,\n"
-          "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
-          "      $singular_type$.class);\n");
-    }
+    // Nested
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+        "        .newMessageScopedGeneratedExtension(\n"
+        "      $scope$.getDefaultInstance(),\n"
+        "      $index$,\n"
+        "      $singular_type$.class,\n"
+        "      $prototype$);\n");
   }
 }
 
-void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
+int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
     io::Printer* printer) {
-  if (descriptor_->extension_scope() == NULL &&
-      HasDescriptorMethods(descriptor_->file())) {
-    // Only applies to non-nested, non-lite extensions.
+  int bytecode_estimate = 0;
+  if (descriptor_->extension_scope() == NULL) {
+    // Only applies to non-nested extensions.
     printer->Print(
         "$name$.internalInit(descriptor.getExtensions().get($index$));\n",
         "name", UnderscoresToCamelCase(descriptor_),
         "index", SimpleItoa(descriptor_->index()));
+    bytecode_estimate += 21;
   }
+  return bytecode_estimate;
 }
 
-void ImmutableExtensionGenerator::GenerateRegistrationCode(
+int ImmutableExtensionGenerator::GenerateRegistrationCode(
     io::Printer* printer) {
   printer->Print(
     "registry.add($scope$.$name$);\n",
     "scope", scope_,
     "name", UnderscoresToCamelCase(descriptor_));
+  return 7;
 }
 
 }  // namespace java
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
index f1701fb..bdd4226 100644
--- a/src/google/protobuf/compiler/java/java_extension.h
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -67,8 +67,12 @@
   virtual ~ExtensionGenerator() {}
 
   virtual void Generate(io::Printer* printer) = 0;
-  virtual void GenerateNonNestedInitializationCode(io::Printer* printer) = 0;
-  virtual void GenerateRegistrationCode(io::Printer* printer) = 0;
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateNonNestedInitializationCode(io::Printer* printer) = 0;
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateRegistrationCode(io::Printer* printer) = 0;
 
  protected:
   static void InitTemplateVars(const FieldDescriptor* descriptor,
@@ -88,8 +92,8 @@
   virtual ~ImmutableExtensionGenerator();
 
   virtual void Generate(io::Printer* printer);
-  virtual void GenerateNonNestedInitializationCode(io::Printer* printer);
-  virtual void GenerateRegistrationCode(io::Printer* printer);
+  virtual int GenerateNonNestedInitializationCode(io::Printer* printer);
+  virtual int GenerateRegistrationCode(io::Printer* printer);
 
  protected:
   const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc
new file mode 100644
index 0000000..23261ba
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
@@ -0,0 +1,118 @@
+// 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.
+
+#include <google/protobuf/compiler/java/java_extension_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator(
+    const FieldDescriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  if (descriptor_->extension_scope() != NULL) {
+    scope_ = name_resolver_->GetImmutableClassName(
+        descriptor_->extension_scope());
+  } else {
+    scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
+  }
+}
+
+ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {}
+
+void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) {
+  map<string, string> vars;
+  const bool kUseImmutableNames = true;
+  InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+                   &vars);
+  printer->Print(vars,
+      "public static final int $constant_name$ = $number$;\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  if (descriptor_->is_repeated()) {
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+        "        .newRepeatedGeneratedExtension(\n"
+        "      $containing_type$.getDefaultInstance(),\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+        "      $packed$,\n"
+        "      $singular_type$.class);\n");
+  } else {
+    printer->Print(
+        vars,
+        "public static final\n"
+        "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+        "    $containing_type$,\n"
+        "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+        "        .newSingularGeneratedExtension(\n"
+        "      $containing_type$.getDefaultInstance(),\n"
+        "      $default$,\n"
+        "      $prototype$,\n"
+        "      $enum_map$,\n"
+        "      $number$,\n"
+        "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+        "      $singular_type$.class);\n");
+  }
+}
+
+int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode(
+    io::Printer* printer) {
+  return 0;
+}
+
+int ImmutableExtensionLiteGenerator::GenerateRegistrationCode(
+    io::Printer* printer) {
+  printer->Print(
+    "registry.add($scope$.$name$);\n",
+    "scope", scope_,
+    "name", UnderscoresToCamelCase(descriptor_));
+  return 7;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h
new file mode 100644
index 0000000..4cd49bd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension_lite.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generates code for a lite extension, which may be within the scope of some
+// message or may be at file scope.  This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ImmutableExtensionLiteGenerator : public ExtensionGenerator {
+ public:
+  explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor,
+                                           Context* context);
+  virtual ~ImmutableExtensionLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateNonNestedInitializationCode(io::Printer* printer);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateRegistrationCode(io::Printer* printer);
+
+ private:
+  const FieldDescriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  string scope_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index d7b0f3f..3c7bc5c 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -35,19 +35,31 @@
 #include <google/protobuf/compiler/java/java_field.h>
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_lazy_message_field.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_map_field.h>
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
 #include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
 #include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
 #include <google/protobuf/compiler/java/java_string_field.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 
+
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -61,12 +73,17 @@
   if (field->is_repeated()) {
     switch (GetJavaType(field)) {
       case JAVATYPE_MESSAGE:
-        if (IsLazy(field)) {
-          return new RepeatedImmutableLazyMessageFieldGenerator(
+        if (IsMapEntry(field->message_type())) {
+          return new ImmutableMapFieldGenerator(
               field, messageBitIndex, builderBitIndex, context);
         } else {
-          return new RepeatedImmutableMessageFieldGenerator(
-              field, messageBitIndex, builderBitIndex, context);
+          if (IsLazy(field, context->EnforceLite())) {
+            return new RepeatedImmutableLazyMessageFieldGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new RepeatedImmutableMessageFieldGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
         }
       case JAVATYPE_ENUM:
         return new RepeatedImmutableEnumFieldGenerator(
@@ -82,7 +99,7 @@
     if (field->containing_oneof()) {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageOneofFieldGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -102,7 +119,7 @@
     } else {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageFieldGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -123,6 +140,79 @@
   }
 }
 
+ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
+    const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
+    Context* context) {
+  if (field->is_repeated()) {
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        if (IsMapEntry(field->message_type())) {
+          return new ImmutableMapFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        } else {
+          if (IsLazy(field, context->EnforceLite())) {
+            return new RepeatedImmutableLazyMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new RepeatedImmutableMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        }
+      case JAVATYPE_ENUM:
+        return new RepeatedImmutableEnumFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      case JAVATYPE_STRING:
+        return new RepeatedImmutableStringFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      default:
+        return new RepeatedImmutablePrimitiveFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+    }
+  } else {
+    if (field->containing_oneof()) {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          if (IsLazy(field, context->EnforceLite())) {
+            return new ImmutableLazyMessageOneofFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new ImmutableMessageOneofFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+      }
+    } else {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          if (IsLazy(field, context->EnforceLite())) {
+            return new ImmutableLazyMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new ImmutableMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+      }
+    }
+  }
+}
+
 
 static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
   // Reaching here indicates a bug. Cases are:
@@ -143,13 +233,20 @@
   ReportUnexpectedPackedFieldsCall(printer);
 }
 
+ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
+
+void ImmutableFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  ReportUnexpectedPackedFieldsCall(printer);
+}
+
 // ===================================================================
 
 template <>
 FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
     const Descriptor* descriptor, Context* context)
     : descriptor_(descriptor),
-      field_generators_(new scoped_ptr<
+      field_generators_(new google::protobuf::scoped_ptr<
           ImmutableFieldGenerator>[descriptor->field_count()]) {
 
   // Construct all the FieldGenerators and assign them bit indices for their
@@ -168,6 +265,28 @@
 template<>
 FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
 
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context)
+    : descriptor_(descriptor),
+      field_generators_(new google::protobuf::scoped_ptr<
+          ImmutableFieldLiteGenerator>[descriptor->field_count()]) {
+  // Construct all the FieldGenerators and assign them bit indices for their
+  // bit fields.
+  int messageBitIndex = 0;
+  int builderBitIndex = 0;
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator(
+        descriptor->field(i), messageBitIndex, builderBitIndex, context);
+    field_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+    builderBitIndex += generator->GetNumBitsForBuilder();
+  }
+}
+
+template<>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {}
+
 
 void SetCommonFieldVariables(const FieldDescriptor* descriptor,
                              const FieldGeneratorInfo* info,
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index db339d5..4dd4f57 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -37,10 +37,14 @@
 
 #include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/logging.h>
 
 namespace google {
 namespace protobuf {
@@ -90,6 +94,37 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator);
 };
 
+class ImmutableFieldLiteGenerator {
+ public:
+  ImmutableFieldLiteGenerator() {}
+  virtual ~ImmutableFieldLiteGenerator();
+
+  virtual int GetNumBitsForMessage() const = 0;
+  virtual int GetNumBitsForBuilder() const = 0;
+  virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
+  virtual void GenerateMembers(io::Printer* printer) const = 0;
+  virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
+  virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
+  virtual void GenerateVisitCode(io::Printer* printer) const = 0;
+  virtual void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer)
+      const = 0;
+  virtual void GenerateParsingCode(io::Printer* printer) const = 0;
+  virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+  virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
+      const = 0;
+
+  virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+  virtual void GenerateHashCode(io::Printer* printer) const = 0;
+
+  virtual string GetBoxedType() const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator);
+};
+
 
 // Convenience class which constructs FieldGenerators for a Descriptor.
 template<typename FieldGeneratorType>
@@ -105,7 +140,7 @@
   const Descriptor* descriptor_;
   Context* context_;
   ClassNameResolver* name_resolver_;
-  scoped_array<scoped_ptr<FieldGeneratorType> > field_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGeneratorType> > field_generators_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
 };
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 231b144..c53aae6 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -35,9 +35,14 @@
 #include <google/protobuf/compiler/java/java_file.h>
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <set>
 
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
 #include <google/protobuf/compiler/java/java_extension.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
@@ -59,6 +64,19 @@
 
 namespace {
 
+struct FieldDescriptorCompare {
+  bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) {
+    if(f1 == NULL) {
+      return false;
+    }
+    if(f2 == NULL) {
+      return true;
+    }
+    return f1->full_name() < f2->full_name();
+  }
+};
+
+typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet;
 
 // Recursively searches the given message to collect extensions.
 // Returns true if all the extensions can be recognized. The extensions will be
@@ -66,7 +84,7 @@
 // Returns false when there are unknown fields, in which case the data in the
 // extensions output parameter is not reliable and should be discarded.
 bool CollectExtensions(const Message& message,
-                       vector<const FieldDescriptor*>* extensions) {
+                       FieldDescriptorSet* extensions) {
   const Reflection* reflection = message.GetReflection();
 
   // There are unknown fields that could be extensions, thus this call fails.
@@ -76,7 +94,7 @@
   reflection->ListFields(message, &fields);
 
   for (int i = 0; i < fields.size(); i++) {
-    if (fields[i]->is_extension()) extensions->push_back(fields[i]);
+    if (fields[i]->is_extension()) extensions->insert(fields[i]);
 
     if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
       if (fields[i]->is_repeated()) {
@@ -103,7 +121,7 @@
 // in order to handle this case.
 void CollectExtensions(const FileDescriptorProto& file_proto,
                        const DescriptorPool& alternate_pool,
-                       vector<const FieldDescriptor*>* extensions,
+                       FieldDescriptorSet* extensions,
                        const string& file_data) {
   if (!CollectExtensions(file_proto, extensions)) {
     // There are unknown fields in the file_proto, which are probably
@@ -118,7 +136,7 @@
            "descriptor.proto is not in the transitive dependencies. "
            "This normally should not happen. Please report a bug.";
     DynamicMessageFactory factory;
-    scoped_ptr<Message> dynamic_file_proto(
+    google::protobuf::scoped_ptr<Message> dynamic_file_proto(
         factory.GetPrototype(file_proto_desc)->New());
     GOOGLE_CHECK(dynamic_file_proto.get() != NULL);
     GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data));
@@ -136,20 +154,58 @@
   }
 }
 
+// Compare two field descriptors, returning true if the first should come
+// before the second.
+bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) {
+  return a->full_name() < b->full_name();
+}
+
+// Our static initialization methods can become very, very large.
+// So large that if we aren't careful we end up blowing the JVM's
+// 64K bytes of bytecode/method. Fortunately, since these static
+// methods are executed only once near the beginning of a program,
+// there's usually plenty of stack space available and we can
+// extend our methods by simply chaining them to another method
+// with a tail call. This inserts the sequence call-next-method,
+// end this one, begin-next-method as needed.
+void MaybeRestartJavaMethod(io::Printer* printer,
+                            int *bytecode_estimate,
+                            int *method_num,
+                            const char *chain_statement,
+                            const char *method_decl) {
+  // The goal here is to stay under 64K bytes of jvm bytecode/method,
+  // since otherwise we hit a hardcoded limit in the jvm and javac will
+  // then fail with the error "code too large". This limit lets our
+  // estimates be off by a factor of two and still we're okay.
+  static const int bytesPerMethod = kMaxStaticSize;
+
+  if ((*bytecode_estimate) > bytesPerMethod) {
+    ++(*method_num);
+    printer->Print(chain_statement, "method_num", SimpleItoa(*method_num));
+    printer->Outdent();
+    printer->Print("}\n");
+    printer->Print(method_decl, "method_num", SimpleItoa(*method_num));
+    printer->Indent();
+    *bytecode_estimate = 0;
+  }
+}
+
 
 }  // namespace
 
-FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
+FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api,
+                             bool enforce_lite)
     : file_(file),
       java_package_(FileJavaPackage(file, immutable_api)),
       message_generators_(
-          new scoped_ptr<MessageGenerator>[file->message_type_count()]),
+          new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
       extension_generators_(
-          new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
+          new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
       context_(new Context(file)),
       name_resolver_(context_->GetNameResolver()),
       immutable_api_(immutable_api) {
   classname_ = name_resolver_->GetFileClassName(file, immutable_api);
+  context_->SetEnforceLite(enforce_lite);
   generator_factory_.reset(
       new ImmutableGeneratorFactory(context_.get()));
   for (int i = 0; i < file_->message_type_count(); ++i) {
@@ -180,29 +236,6 @@
       "option to specify a different outer class name for the .proto file.");
     return false;
   }
-  // If java_outer_classname option is not set and the default outer class name
-  // conflicts with a type defined in the message, we will append a suffix to
-  // avoid the conflict. This allows proto1 API protos to be dual-compiled into
-  // proto2 API without code change. When this happens we'd like to issue an
-  // warning to let the user know that the outer class name has been changed.
-  // Although we only do this automatic naming fix for immutable API, mutable
-  // outer class name will also be affected as it's contructed from immutable
-  // outer class name with an additional "Mutable" prefix. Since the naming
-  // change in mutable API is not caused by a naming conflict, we generate the
-  // warning for immutable API only.
-  if (immutable_api_ && !file_->options().has_java_outer_classname()) {
-    string default_classname =
-        name_resolver_->GetFileDefaultImmutableClassName(file_);
-    if (default_classname != classname_) {
-      GOOGLE_LOG(WARNING) << file_->name() << ": The default outer class name, \""
-                   << default_classname << "\", conflicts with a type "
-                   << "declared in the proto file and an alternative outer "
-                   << "class name is used: \"" << classname_ << "\". To avoid "
-                   << "this warning, please use the java_outer_classname "
-                   << "option to specify a different outer class name for "
-                   << "the .proto file.";
-    }
-  }
   return true;
 }
 
@@ -231,7 +264,8 @@
   printer->Print(
     "public static void registerAllExtensions(\n"
     "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
-    "lite", HasDescriptorMethods(file_) ? "" : "Lite");
+    "lite",
+    HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite");
 
   printer->Indent();
 
@@ -251,16 +285,21 @@
 
   if (!MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
-          .Generate(printer);
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+        EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      } else {
+        EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      }
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       message_generators_[i]->GenerateInterface(printer);
       message_generators_[i]->Generate(printer);
     }
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, context_->EnforceLite())) {
       for (int i = 0; i < file_->service_count(); i++) {
-        scoped_ptr<ServiceGenerator> generator(
+        google::protobuf::scoped_ptr<ServiceGenerator> generator(
             generator_factory_->NewServiceGenerator(file_->service(i)));
         generator->Generate(printer);
       }
@@ -273,14 +312,18 @@
     extension_generators_[i]->Generate(printer);
   }
 
-  // Static variables.
+  // Static variables. We'd like them to be final if possible, but due to
+  // the JVM's 64k size limit on static blocks, we have to initialize some
+  // of them in methods; thus they cannot be final.
+  int static_block_bytecode_estimate = 0;
   for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateStaticVariables(printer);
+    message_generators_[i]->GenerateStaticVariables(
+        printer, &static_block_bytecode_estimate);
   }
 
   printer->Print("\n");
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, context_->EnforceLite())) {
     if (immutable_api_) {
       GenerateDescriptorInitializationCodeForImmutable(printer);
     } else {
@@ -290,9 +333,16 @@
     printer->Print(
       "static {\n");
     printer->Indent();
+    int bytecode_estimate = 0;
+    int method_num = 0;
 
     for (int i = 0; i < file_->message_type_count(); i++) {
-      message_generators_[i]->GenerateStaticVariableInitializers(printer);
+      bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
+      MaybeRestartJavaMethod(
+        printer,
+        &bytecode_estimate, &method_num,
+        "_clinit_autosplit_$method_num$();\n",
+        "private static void _clinit_autosplit_$method_num$() {\n");
     }
 
     printer->Outdent();
@@ -315,19 +365,34 @@
     "    getDescriptor() {\n"
     "  return descriptor;\n"
     "}\n"
-    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+    "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n"
     "    descriptor;\n"
-    "static {\n");
+    "static {\n",
+    // TODO(dweis): Mark this as final.
+    "final", "");
   printer->Indent();
 
   SharedCodeGenerator shared_code_generator(file_);
   shared_code_generator.GenerateDescriptors(printer);
 
+  int bytecode_estimate = 0;
+  int method_num = 0;
+
   for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateStaticVariableInitializers(printer);
+    bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
+    MaybeRestartJavaMethod(
+      printer,
+      &bytecode_estimate, &method_num,
+      "_clinit_autosplit_dinit_$method_num$();\n",
+      "private static void _clinit_autosplit_dinit_$method_num$() {\n");
   }
   for (int i = 0; i < file_->extension_count(); i++) {
-    extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+    bytecode_estimate += extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
+    MaybeRestartJavaMethod(
+      printer,
+      &bytecode_estimate, &method_num,
+      "_clinit_autosplit_dinit_$method_num$();\n",
+      "private static void _clinit_autosplit_dinit_$method_num$() {\n");
   }
 
   // Proto compiler builds a DescriptorPool, which holds all the descriptors to
@@ -349,7 +414,7 @@
   file_->CopyTo(&file_proto);
   string file_data;
   file_proto.SerializeToString(&file_data);
-  vector<const FieldDescriptor*> extensions;
+  FieldDescriptorSet extensions;
   CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
 
   if (extensions.size() > 0) {
@@ -358,10 +423,17 @@
     printer->Print(
       "com.google.protobuf.ExtensionRegistry registry =\n"
       "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
-    for (int i = 0; i < extensions.size(); i++) {
-      scoped_ptr<ExtensionGenerator> generator(
-          generator_factory_->NewExtensionGenerator(extensions[i]));
-      generator->GenerateRegistrationCode(printer);
+    FieldDescriptorSet::iterator it;
+    for (it = extensions.begin(); it != extensions.end(); it++) {
+      google::protobuf::scoped_ptr<ExtensionGenerator> generator(
+          generator_factory_->NewExtensionGenerator(*it));
+      bytecode_estimate += generator->GenerateRegistrationCode(printer);
+      MaybeRestartJavaMethod(
+        printer,
+        &bytecode_estimate, &method_num,
+        "_clinit_autosplit_dinit_$method_num$(registry);\n",
+        "private static void _clinit_autosplit_dinit_$method_num$(\n"
+        "    com.google.protobuf.ExtensionRegistry registry) {\n");
     }
     printer->Print(
       "com.google.protobuf.Descriptors.FileDescriptor\n"
@@ -390,7 +462,7 @@
     "    getDescriptor() {\n"
     "  return descriptor;\n"
     "}\n"
-    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+    "private static final com.google.protobuf.Descriptors.FileDescriptor\n"
     "    descriptor;\n"
     "static {\n");
   printer->Indent();
@@ -413,7 +485,7 @@
   file_->CopyTo(&file_proto);
   string file_data;
   file_proto.SerializeToString(&file_data);
-  vector<const FieldDescriptor*> extensions;
+  FieldDescriptorSet extensions;
   CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
 
   if (extensions.size() > 0) {
@@ -463,7 +535,7 @@
   string filename = package_dir + descriptor->name() + name_suffix + ".java";
   file_list->push_back(filename);
 
-  scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
   io::Printer printer(output.get(), '$');
 
   printer.Print(
@@ -486,13 +558,23 @@
                                      vector<string>* file_list) {
   if (MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      EnumGenerator generator(file_->enum_type(i), immutable_api_,
-                              context_.get());
-      GenerateSibling<EnumGenerator>(package_dir, java_package_,
-                                     file_->enum_type(i),
-                                     context, file_list, "",
-                                     &generator,
-                                     &EnumGenerator::Generate);
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+        EnumGenerator generator(file_->enum_type(i), immutable_api_,
+                                context_.get());
+        GenerateSibling<EnumGenerator>(package_dir, java_package_,
+                                       file_->enum_type(i),
+                                       context, file_list, "",
+                                       &generator,
+                                       &EnumGenerator::Generate);
+      } else {
+        EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
+                                    context_.get());
+        GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
+                                           file_->enum_type(i),
+                                           context, file_list, "",
+                                           &generator,
+                                           &EnumLiteGenerator::Generate);
+      }
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       if (immutable_api_) {
@@ -509,9 +591,9 @@
                                         message_generators_[i].get(),
                                         &MessageGenerator::Generate);
     }
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, context_->EnforceLite())) {
       for (int i = 0; i < file_->service_count(); i++) {
-        scoped_ptr<ServiceGenerator> generator(
+        google::protobuf::scoped_ptr<ServiceGenerator> generator(
             generator_factory_->NewServiceGenerator(file_->service(i)));
         GenerateSibling<ServiceGenerator>(package_dir, java_package_,
                                           file_->service(i),
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index c805b9a..7dbeb94 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -36,6 +36,9 @@
 #define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
@@ -64,7 +67,8 @@
 
 class FileGenerator {
  public:
-  FileGenerator(const FileDescriptor* file, bool immutable_api = true);
+  FileGenerator(const FileDescriptor* file, bool immutable_api = true,
+                bool enforce_lite = false);
   ~FileGenerator();
 
   // Checks for problems that would otherwise lead to cryptic compile errors.
@@ -96,10 +100,10 @@
   string java_package_;
   string classname_;
 
-  scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
-  scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
-  scoped_ptr<GeneratorFactory> generator_factory_;
-  scoped_ptr<Context> context_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
+  google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
+  google::protobuf::scoped_ptr<GeneratorFactory> generator_factory_;
+  google::protobuf::scoped_ptr<Context> context_;
   ClassNameResolver* name_resolver_;
   bool immutable_api_;
 
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index c3a47e3..a46c7fc 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -35,6 +35,9 @@
 #include <google/protobuf/compiler/java/java_generator.h>
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/java/java_file.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
@@ -72,6 +75,7 @@
   bool generate_immutable_code = false;
   bool generate_mutable_code = false;
   bool generate_shared_code = false;
+  bool enforce_lite = false;
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "output_list_file") {
       output_list_file = options[i].second;
@@ -81,12 +85,21 @@
       generate_mutable_code = true;
     } else if (options[i].first == "shared") {
       generate_shared_code = true;
+    } else if (options[i].first == "lite") {
+      // When set, the protoc will generate the current files and all the
+      // transitive dependencies as lite runtime.
+      enforce_lite = true;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
     }
   }
 
+  if (enforce_lite && generate_mutable_code) {
+    *error = "lite runtime generator option cannot be used with mutable API.";
+    return false;
+  }
+
   // By default we generate immutable code and shared code for immutable API.
   if (!generate_immutable_code && !generate_mutable_code &&
       !generate_shared_code) {
@@ -99,9 +112,15 @@
 
   vector<string> all_files;
 
+
   vector<FileGenerator*> file_generators;
   if (generate_immutable_code) {
-    file_generators.push_back(new FileGenerator(file, /* immutable = */ true));
+    file_generators.push_back(
+        new FileGenerator(file, /* immutable = */ true, enforce_lite));
+  }
+  if (generate_mutable_code) {
+    file_generators.push_back(
+        new FileGenerator(file, /* mutable = */ false, enforce_lite));
   }
   for (int i = 0; i < file_generators.size(); ++i) {
     if (!file_generators[i]->Validate(error)) {
@@ -123,7 +142,7 @@
     all_files.push_back(java_filename);
 
     // Generate main java file.
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->Open(java_filename));
     io::Printer printer(output.get(), '$');
     file_generator->Generate(&printer);
@@ -141,7 +160,7 @@
   if (!output_list_file.empty()) {
     // Generate output list.  This is just a simple text file placed in a
     // deterministic location which lists the .java files being generated.
-    scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
         context->Open(output_list_file));
     io::Printer srclist_printer(srclist_raw_output.get(), '$');
     for (int i = 0; i < all_files.size(); i++) {
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 2d1437f..3218b41 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -35,9 +35,11 @@
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
 #include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
 #include <google/protobuf/compiler/java/java_field.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_message_lite.h>
 #include <google/protobuf/compiler/java/java_service.h>
 
 namespace google {
@@ -57,12 +59,20 @@
 
 MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
     const Descriptor* descriptor) const {
-  return new ImmutableMessageGenerator(descriptor, context_);
+  if (HasDescriptorMethods(descriptor, context_->EnforceLite())) {
+    return new ImmutableMessageGenerator(descriptor, context_);
+  } else {
+    return new ImmutableMessageLiteGenerator(descriptor, context_);
+  }
 }
 
 ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
     const FieldDescriptor* descriptor) const {
-  return new ImmutableExtensionGenerator(descriptor, context_);
+  if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) {
+    return new ImmutableExtensionGenerator(descriptor, context_);
+  } else {
+    return new ImmutableExtensionLiteGenerator(descriptor, context_);
+  }
 }
 
 ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 3efd7ed..e24894b 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -306,6 +306,26 @@
   return JAVATYPE_INT;
 }
 
+const char* PrimitiveTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT    : return "int";
+    case JAVATYPE_LONG   : return "long";
+    case JAVATYPE_FLOAT  : return "float";
+    case JAVATYPE_DOUBLE : return "double";
+    case JAVATYPE_BOOLEAN: return "boolean";
+    case JAVATYPE_STRING : return "java.lang.String";
+    case JAVATYPE_BYTES  : return "com.google.protobuf.ByteString";
+    case JAVATYPE_ENUM   : return NULL;
+    case JAVATYPE_MESSAGE: return NULL;
+
+    // No default because we want the compiler to complain if any new
+    // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
 const char* BoxedPrimitiveTypeName(JavaType type) {
   switch (type) {
     case JAVATYPE_INT    : return "java.lang.Integer";
@@ -670,8 +690,8 @@
   for (int i = 0; i < descriptor->field_count(); i++) {
     fields[i] = descriptor->field(i);
   }
-  sort(fields, fields + descriptor->field_count(),
-       FieldOrderingByNumber());
+  std::sort(fields, fields + descriptor->field_count(),
+            FieldOrderingByNumber());
   return fields;
 }
 
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 93f23a9..c850423 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -132,7 +132,7 @@
 
 // Returns the type of the FieldDescriptor.
 // This does nothing interesting for the open source release, but is used for
-// hacks that improve compatability with version 1 protocol buffers at Google.
+// hacks that improve compatibility with version 1 protocol buffers at Google.
 FieldDescriptor::Type GetType(const FieldDescriptor* field);
 
 enum JavaType {
@@ -149,6 +149,8 @@
 
 JavaType GetJavaType(const FieldDescriptor* field);
 
+const char* PrimitiveTypeName(JavaType type);
+
 // Get the fully-qualified class name for a boxed primitive type, e.g.
 // "java.lang.Integer" for JAVATYPE_INT.  Returns NULL for enum and message
 // types.
@@ -168,57 +170,41 @@
 }
 bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
 
-// Does this message class use UnknownFieldSet?
-// Otherwise, unknown fields will be stored in a ByteString object
-inline bool UseUnknownFieldSet(const Descriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
-}
-
-// Does this message class have generated parsing, serialization, and other
-// standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const Descriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::CODE_SIZE;
-}
-
 // Does this message have specialized equals() and hashCode() methods?
 inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
   return descriptor->file()->options().java_generate_equals_and_hash();
 }
 
 // Does this message class have descriptor and reflection methods?
-inline bool HasDescriptorMethods(const Descriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const Descriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->file()->options().optimize_for() !=
+             FileOptions::LITE_RUNTIME;
 }
-inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const EnumDescriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->file()->options().optimize_for() !=
+             FileOptions::LITE_RUNTIME;
 }
-inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
-  return descriptor->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
-}
-
-inline bool HasNestedBuilders(const Descriptor* descriptor) {
-  // The proto-lite version doesn't support nested builders.
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const FileDescriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->options().optimize_for() != FileOptions::LITE_RUNTIME;
 }
 
 // Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor *file) {
+inline bool HasGenericServices(const FileDescriptor *file, bool enforce_lite) {
   return file->service_count() > 0 &&
-         file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
+         HasDescriptorMethods(file, enforce_lite) &&
          file->options().java_generic_services();
 }
 
-inline bool IsLazy(const FieldDescriptor* descriptor) {
+inline bool IsLazy(const FieldDescriptor* descriptor, bool enforce_lite) {
   // Currently, the proto-lite version suports lazy field.
   // TODO(niwasaki): Support lazy fields also for other proto runtimes.
-  if (descriptor->file()->options().optimize_for() !=
-      FileOptions::LITE_RUNTIME) {
+  if (HasDescriptorMethods(descriptor->file(), enforce_lite)) {
     return false;
   }
   return descriptor->options().lazy();
@@ -302,18 +288,62 @@
 // and return it. The caller should delete the returned array.
 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
 
+// Does this message class have any packed fields?
+inline bool HasPackedFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (descriptor->field(i)->is_packed()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Check a message type and its sub-message types recursively to see if any of
 // them has a required field. Return true if a required field is found.
 bool HasRequiredFields(const Descriptor* descriptor);
 
 // Whether a .proto file supports field presence test for non-message types.
 inline bool SupportFieldPresence(const FileDescriptor* descriptor) {
-  return true;
+  return descriptor->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// Whether generate classes expose public PARSER instances.
+inline bool ExposePublicParser(const FileDescriptor* descriptor) {
+  // TODO(liujisi): Mark the PARSER private in 3.1.x releases.
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
+// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet
+// but in the message and can be queried using additional getters that return
+// ints.
+inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) {
+  return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
 }
 
 // Check whether a mesasge has repeated fields.
 bool HasRepeatedFields(const Descriptor* descriptor);
 
+inline bool IsMapEntry(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
+inline bool IsMapField(const FieldDescriptor* descriptor) {
+  return descriptor->is_map();
+}
+
+inline bool PreserveUnknownFields(const Descriptor* descriptor) {
+  return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool IsAnyMessage(const Descriptor* descriptor) {
+  return descriptor->full_name() == "google.protobuf.Any";
+}
+
+inline bool CheckUtf8(const FieldDescriptor* descriptor) {
+  return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
+      descriptor->file()->options().java_string_check_utf8();
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
index 21cab7d..0de8cbe 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -72,14 +72,12 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
-   "}\n");
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  return $name$_;\n"
-      "}\n");
-  }
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  return $name$_;\n"
+    "}\n");
 }
 
 void ImmutableLazyMessageFieldGenerator::
@@ -92,14 +90,12 @@
     "private com.google.protobuf.LazyFieldLite $name$_ =\n"
     "    new com.google.protobuf.LazyFieldLite();\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -179,39 +175,37 @@
     "$clear_has_field_bit_builder$;\n"
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  $set_has_field_bit_builder$;\n"
-      "  $on_changed$\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n"
-      "    return $name$_;\n"
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $on_changed$\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    return $name$_;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 
@@ -243,9 +237,8 @@
       "}\n");
 
   printer->Print(variables_,
-      "result.$name$_.setByteString(\n"
-      "    $name$_.toByteString(),\n"
-      "    $name$_.getExtensionRegistry());\n");
+      "result.$name$_.set(\n"
+      "    $name$_);\n");
 }
 
 void ImmutableLazyMessageFieldGenerator::
@@ -425,9 +418,8 @@
 
   printer->Print(variables_,
       "result.$oneof_name$_ = new $lazy_type$();\n"
-      "(($lazy_type$) result.$oneof_name$_).setByteString(\n"
-      "    (($lazy_type$) $oneof_name$_).toByteString(),\n"
-      "    (($lazy_type$) $oneof_name$_).getExtensionRegistry());\n");
+      "(($lazy_type$) result.$oneof_name$_).set(\n"
+      "    (($lazy_type$) $oneof_name$_));\n");
   printer->Outdent();
   printer->Print("}\n");
 }
@@ -540,14 +532,12 @@
     "}\n"
     "\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // repeated field of type "Field" called "RepeatedField".
@@ -725,70 +715,68 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index) {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    return $name$_.get(index);"
-      "  } else {\n"
-      "    return $name$Builder_.getMessageOrBuilder(index);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    return $name$_.get(index);"
+    "  } else {\n"
+    "    return $name$Builder_.getMessageOrBuilder(index);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
-      "     get$capitalized_name$OrBuilderList() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilderList();\n"
-      "  } else {\n"
-      "    return java.util.Collections.unmodifiableList($name$_);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "     get$capitalized_name$OrBuilderList() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilderList();\n"
+    "  } else {\n"
+    "    return java.util.Collections.unmodifiableList($name$_);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      index, $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<$type$.Builder> \n"
-      "     get$capitalized_name$BuilderList() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
-      "}\n"
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            $get_mutable_bit_builder$,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      index, $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$.Builder> \n"
+    "     get$capitalized_name$BuilderList() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
+    "}\n"
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            $get_mutable_bit_builder$,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void RepeatedImmutableLazyMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
new file mode 100644
index 0000000..62f3930
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -0,0 +1,706 @@
+// 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.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableLazyMessageFieldLiteGenerator::
+ImmutableLazyMessageFieldLiteGenerator(
+    const FieldDescriptor* descriptor,
+    int messageBitIndex,
+    int builderBitIndex,
+    Context* context)
+    : ImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+ImmutableLazyMessageFieldLiteGenerator::
+~ImmutableLazyMessageFieldLiteGenerator() {}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.LazyFieldLite $name$_ =\n"
+    "    new com.google.protobuf.LazyFieldLite();\n");
+
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
+   "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $name$_.setValue(value);\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $name$_.setValue(builderForValue.build());\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($get_has_field_bit_message$ &&\n"
+    "      !$name$_.containsDefaultInstance()) {\n"
+    "    $name$_.setValue(\n"
+    "      $type$.newBuilder(\n"
+    "          get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+    "  } else {\n"
+    "    $name$_.setValue(value);\n"
+    "  }\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_.clear();\n"
+    "  $clear_has_field_bit_message$;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_.clear();\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = visitor.visitLazyMessage(\n"
+    "    has$capitalized_name$(), $name$_,\n"
+    "    other.has$capitalized_name$(), other.$name$_);\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.mergeFrom(input, extensionRegistry);\n");
+  printer->Print(variables_,
+    "$set_has_field_bit_message$;\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Do not de-serialize lazy fields.
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.writeBytes($number$, $name$_.toByteString());\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, $name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+ImmutableLazyMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            int builderBitIndex,
+                                            Context* context)
+    : ImmutableLazyMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+  variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite";
+}
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+~ImmutableLazyMessageOneofFieldLiteGenerator() {}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case_message$;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n"
+    "        $type$.getDefaultInstance());\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  if (!($has_oneof_case_message$)) {\n"
+    "    $oneof_name$_ = new $lazy_type$();\n"
+    "    $set_oneof_case_message$;\n"
+    "  }\n"
+    "  (($lazy_type$) $oneof_name$_).setValue(value);\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  if (!($has_oneof_case_message$)) {\n"
+    "    $oneof_name$_ = new $lazy_type$();\n"
+    "    $set_oneof_case_message$;\n"
+    "  }\n"
+    "  (($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($has_oneof_case_message$ &&\n"
+    "      !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n"
+    "    (($lazy_type$) $oneof_name$_).setValue(\n"
+    "       $type$.newBuilder(\n"
+    "          get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+    "  } else {\n"
+    "    if (!($has_oneof_case_message$)) {\n"
+    "      $oneof_name$_ = new $lazy_type$();\n"
+    "      $set_oneof_case_message$;\n"
+    "    }\n"
+    "    (($lazy_type$) $oneof_name$_).setValue(value);\n"
+    "  }\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$oneof_name$_ = visitor.visitOneofLazyMessage(\n"
+    "    $has_oneof_case_message$,\n"
+    "    ($lazy_type$) $oneof_name$_,\n"
+    "    ($lazy_type$) other.$oneof_name$_);\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!($has_oneof_case_message$)) {\n"
+    "  $oneof_name$_ = new $lazy_type$();\n"
+    "}\n"
+    "(($lazy_type$) $oneof_name$_).mergeFrom(input, extensionRegistry);\n"
+    "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Do not de-serialize lazy fields.
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeBytes(\n"
+    "      $number$, (($lazy_type$) $oneof_name$_).toByteString());\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+RepeatedImmutableLazyMessageFieldLiteGenerator(
+    const FieldDescriptor* descriptor,
+    int messageBitIndex,
+    int builderBitIndex,
+    Context* context)
+    : RepeatedImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+~RepeatedImmutableLazyMessageFieldLiteGenerator() {}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.ProtobufList<\n"
+    "    com.google.protobuf.LazyFieldLite> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  java.util.List<$type$> list =\n"
+    "      new java.util.ArrayList<$type$>($name$_.size());\n"
+    "  for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n"
+    "    list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n"
+    "  }\n"
+    // TODO(dweis): Make this list immutable?
+    "  return list;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder>\n"
+    "    get$capitalized_name$OrBuilderList() {\n"
+    "  return get$capitalized_name$List();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return ($type$)\n"
+    "      $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  return ($type$OrBuilder)\n"
+    "      $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ =\n"
+    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "   }\n"
+    "}\n"
+    "\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(\n"
+    "      index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(\n"
+    "      index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  for (com.google.protobuf.MessageLite v : values) {\n"
+    "    $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n"
+    "  }\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyProtobufList();\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void remove$capitalized_name$(int index) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.remove(index);\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // List<Field> getRepeatedFieldList()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+    "  copyOnWrite();\n"
+    "  instance.remove$capitalized_name$(index);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n"
+    "$name$_.add(new com.google.protobuf.LazyFieldLite(\n"
+    "    extensionRegistry, input.readBytes()));\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.writeBytes($number$, $name$_.get(i).toByteString());\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
new file mode 100644
index 0000000..47ebeb4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
@@ -0,0 +1,118 @@
+// 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.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;  // context.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableLazyMessageFieldLiteGenerator
+    : public ImmutableMessageFieldLiteGenerator {
+ public:
+  explicit ImmutableLazyMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableLazyMessageFieldLiteGenerator();
+
+  // overroads ImmutableMessageFieldLiteGenerator ------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldLiteGenerator);
+};
+
+class ImmutableLazyMessageOneofFieldLiteGenerator
+    : public ImmutableLazyMessageFieldLiteGenerator {
+ public:
+  ImmutableLazyMessageOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableLazyMessageOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableLazyMessageFieldLiteGenerator
+    : public RepeatedImmutableMessageFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableLazyMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableLazyMessageFieldLiteGenerator();
+
+  // overroads RepeatedImmutableMessageFieldLiteGenerator ----------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
new file mode 100644
index 0000000..2a551ca
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -0,0 +1,497 @@
+// 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.
+
+#include <google/protobuf/compiler/java/java_map_field.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("value");
+}
+
+string TypeName(const FieldDescriptor* field,
+                ClassNameResolver* name_resolver,
+                bool boxed) {
+  if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+    return name_resolver->GetImmutableClassName(field->message_type());
+  } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+    return name_resolver->GetImmutableClassName(field->enum_type());
+  } else {
+    return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
+                 : PrimitiveTypeName(GetJavaType(field));
+  }
+}
+
+string WireType(const FieldDescriptor* field) {
+  return "com.google.protobuf.WireFormat.FieldType." +
+      string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
+                         const FieldGeneratorInfo* info,
+                         Context* context,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+  ClassNameResolver* name_resolver = context->GetNameResolver();
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  (*variables)["key_type"] = TypeName(key, name_resolver, false);
+  (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+  (*variables)["key_wire_type"] = WireType(key);
+  (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  if (GetJavaType(value) == JAVATYPE_ENUM) {
+    // We store enums as Integers internally.
+    (*variables)["value_type"] = "int";
+    (*variables)["boxed_value_type"] = "java.lang.Integer";
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver) + ".getNumber()";
+
+    (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
+
+    if (SupportUnknownEnumValue(descriptor->file())) {
+      // Map unknown values to a special UNRECOGNIZED value if supported.
+      (*variables)["unrecognized_value"] =
+          (*variables)["value_enum_type"] + ".UNRECOGNIZED";
+    } else {
+      // Map unknown values to the default value if we don't have UNRECOGNIZED.
+      (*variables)["unrecognized_value"] =
+          DefaultValue(value, true, name_resolver);
+    }
+  } else {
+    (*variables)["value_type"] = TypeName(value, name_resolver, false);
+    (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver);
+  }
+  (*variables)["type_parameters"] =
+      (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  (*variables)["on_changed"] = "onChanged();";
+
+  // For repeated fields, one bit is used for whether the array is immutable
+  // in the parsing constructor.
+  (*variables)["get_mutable_bit_parser"] =
+      GenerateGetBitMutableLocal(builderBitIndex);
+  (*variables)["set_mutable_bit_parser"] =
+      GenerateSetBitMutableLocal(builderBitIndex);
+
+  (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+      "DefaultEntryHolder.defaultEntry";
+  (*variables)["lite"] = "";
+  (*variables)["map_field_parameter"] = (*variables)["default_entry"];
+  (*variables)["descriptor"] =
+      name_resolver->GetImmutableClassName(descriptor->file()) +
+      ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
+      "_descriptor, ";
+}
+
+}  // namespace
+
+ImmutableMapFieldGenerator::
+ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex,
+                                       int builderBitIndex,
+                                       Context* context)
+  : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      context, &variables_);
+}
+
+ImmutableMapFieldGenerator::
+~ImmutableMapFieldGenerator() {}
+
+int ImmutableMapFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void ImmutableMapFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$();\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$java.util.Map<$type_parameters$>\n"
+          "get$capitalized_name$Value();\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$type_parameters$>\n"
+        "get$capitalized_name$();\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntry$lite$\n"
+      "          .<$type_parameters$>newDefaultInstance(\n"
+      "              $descriptor$\n"
+      "              $key_wire_type$,\n"
+      "              $key_default_value$,\n"
+      "              $value_wire_type$,\n"
+      "              $value_default_value$);\n"
+      "}\n");
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.MapField$lite$<\n"
+      "    $type_parameters$> $name$_;\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  if ($name$_ == null) {\n"
+      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "        $map_field_parameter$);\n"
+      "  }\n"
+      "  return $name$_;\n"
+      "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "private static final\n"
+        "com.google.protobuf.Internal.MapAdapter.Converter<\n"
+        "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
+        "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
+        "            $value_enum_type$.internalGetValueMap(),\n"
+        "            $unrecognized_value$);\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.MapField$lite$<\n"
+      "    $type_parameters$> $name$_;\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  if ($name$_ == null) {\n"
+      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "        $map_field_parameter$);\n"
+      "  }\n"
+      "  return $name$_;\n"
+      "}\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGetMutable$capitalized_name$() {\n"
+      "  $on_changed$;\n"
+      "  if ($name$_ == null) {\n"
+      "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+      "        $map_field_parameter$);\n"
+      "  }\n"
+      "  if (!$name$_.isMutable()) {\n"
+      "    $name$_ = $name$_.copy();\n"
+      "  }\n"
+      "  return $name$_;\n"
+      "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder putAll$capitalized_name$(\n"
+        "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
+        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$public Builder putAll$capitalized_name$Value(\n"
+          "    java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
+          "  getMutable$capitalized_name$Value().putAll(values);\n"
+          "  return this;\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder putAll$capitalized_name$(\n"
+        "    java.util.Map<$type_parameters$> values) {\n"
+        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "internalGetMutable$capitalized_name$().clear();\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "internalGetMutable$capitalized_name$().mergeFrom(\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "result.$name$_ = internalGet$capitalized_name$();\n"
+      "result.$name$_.makeImmutable();\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!$get_mutable_bit_parser$) {\n"
+      "  $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+      "      $map_field_parameter$);\n"
+      "  $set_mutable_bit_parser$;\n"
+      "}\n");
+  if (!SupportUnknownEnumValue(descriptor_->file()) &&
+      GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.ByteString bytes = input.readBytes();\n"
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+    printer->Print(
+        variables_,
+        "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
+        "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
+        "} else {\n"
+        "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+        "}\n");
+  } else {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = input.readMessage(\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
+        "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // Nothing to do here.
+}
+
+void ImmutableMapFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  output.writeMessage($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeMessageSize($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "result = result && internalGet$capitalized_name$().equals(\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+      "  hash = (37 * hash) + $constant_name$;\n"
+      "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
+      "}\n");
+}
+
+string ImmutableMapFieldGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
new file mode 100644
index 0000000..f2768f3
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
+ public:
+  explicit ImmutableMapFieldGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMapFieldGenerator();
+
+  // implements ImmutableFieldGenerator ---------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateBuilderClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  ClassNameResolver* name_resolver_;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
new file mode 100644
index 0000000..b80d413
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -0,0 +1,482 @@
+// 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.
+
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("value");
+}
+
+string TypeName(const FieldDescriptor* field,
+                ClassNameResolver* name_resolver,
+                bool boxed) {
+  if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+    return name_resolver->GetImmutableClassName(field->message_type());
+  } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+    return name_resolver->GetImmutableClassName(field->enum_type());
+  } else {
+    return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
+                 : PrimitiveTypeName(GetJavaType(field));
+  }
+}
+
+string WireType(const FieldDescriptor* field) {
+  return "com.google.protobuf.WireFormat.FieldType." +
+      string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
+                         const FieldGeneratorInfo* info,
+                         Context* context,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  ClassNameResolver* name_resolver = context->GetNameResolver();
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  (*variables)["key_type"] = TypeName(key, name_resolver, false);
+  (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+  (*variables)["key_wire_type"] = WireType(key);
+  (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  if (GetJavaType(value) == JAVATYPE_ENUM) {
+    // We store enums as Integers internally.
+    (*variables)["value_type"] = "int";
+    (*variables)["boxed_value_type"] = "java.lang.Integer";
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver) + ".getNumber()";
+
+    (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
+
+    if (SupportUnknownEnumValue(descriptor->file())) {
+      // Map unknown values to a special UNRECOGNIZED value if supported.
+      (*variables)["unrecognized_value"] =
+          (*variables)["value_enum_type"] + ".UNRECOGNIZED";
+    } else {
+      // Map unknown values to the default value if we don't have UNRECOGNIZED.
+      (*variables)["unrecognized_value"] =
+          DefaultValue(value, true, name_resolver);
+    }
+  } else {
+    (*variables)["value_type"] = TypeName(value, name_resolver, false);
+    (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver);
+  }
+  (*variables)["type_parameters"] =
+      (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+
+  (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+      "DefaultEntryHolder.defaultEntry";
+  (*variables)["lite"] = "Lite";
+  (*variables)["descriptor"] = "";
+}
+
+}  // namespace
+
+ImmutableMapFieldLiteGenerator::
+ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex,
+                                       int builderBitIndex,
+                                       Context* context)
+  : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      context, &variables_);
+}
+
+ImmutableMapFieldLiteGenerator::
+~ImmutableMapFieldLiteGenerator() {}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$();\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$java.util.Map<$type_parameters$>\n"
+          "get$capitalized_name$Value();\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$type_parameters$>\n"
+        "get$capitalized_name$();\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntry$lite$\n"
+      "          .<$type_parameters$>newDefaultInstance(\n"
+      "              $descriptor$\n"
+      "              $key_wire_type$,\n"
+      "              $key_default_value$,\n"
+      "              $value_wire_type$,\n"
+      "              $value_default_value$);\n"
+      "}\n");
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.MapField$lite$<\n"
+      "    $type_parameters$> $name$_ =\n"
+      "        com.google.protobuf.MapField$lite$.emptyMapField();\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  return $name$_;\n"
+      "}\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGetMutable$capitalized_name$() {\n"
+      "  if (!$name$_.isMutable()) {\n"
+      "    $name$_ = $name$_.copy();\n"
+      "  }\n"
+      "  return $name$_;\n"
+      "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "private static final\n"
+        "com.google.protobuf.Internal.MapAdapter.Converter<\n"
+        "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
+        "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
+        "            $value_enum_type$.internalGetValueMap(),\n"
+        "            $unrecognized_value$);\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
+        "}\n");
+  }
+
+  // Generate private setters for the builder to proxy into.
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "private java.util.Map<$type_parameters$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return instance.get$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  copyOnWrite();\n"
+        "  return instance.getMutable$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder putAll$capitalized_name$(\n"
+        "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
+        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return instance.get$capitalized_name$Value();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  copyOnWrite();\n"
+          "  return instance.getMutable$capitalized_name$Value();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$public Builder putAll$capitalized_name$Value(\n"
+          "    java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
+          "  getMutable$capitalized_name$Value().putAll(values);\n"
+          "  return this;\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return instance.get$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  copyOnWrite();\n"
+        "  return instance.getMutable$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public Builder putAll$capitalized_name$(\n"
+        "    java.util.Map<$type_parameters$> values) {\n"
+        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  return this;\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "$name$_ = visitor.visitMap(internalGetMutable$capitalized_name$(),\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!$name$_.isMutable()) {\n"
+      "  $name$_ = $name$_.copy();\n"
+      "}\n");
+  if (!SupportUnknownEnumValue(descriptor_->file()) &&
+      GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.ByteString bytes = input.readBytes();\n"
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+    printer->Print(
+        variables_,
+        "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
+        "  super.mergeLengthDelimitedField($number$, bytes);\n"
+        "} else {\n"
+        "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+        "}\n");
+  } else {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = input.readMessage(\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
+        "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // Nothing to do here.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  output.writeMessage($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeMessageSize($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "result = result && internalGet$capitalized_name$().equals(\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+      "  hash = (37 * hash) + $constant_name$;\n"
+      "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
+      "}\n");
+}
+
+string ImmutableMapFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h
new file mode 100644
index 0000000..555b5c5
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMapFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMapFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  ClassNameResolver* name_resolver_;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 8aa89ac..4c474a4 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -38,6 +38,9 @@
 #include <google/protobuf/stubs/hash.h>
 #include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/compiler/java/java_context.h>
@@ -46,6 +49,8 @@
 #include <google/protobuf/compiler/java/java_extension.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/printer.h>
@@ -67,6 +72,13 @@
   return SupportFieldPresence(descriptor->file()) ||
       HasRepeatedFields(descriptor);
 }
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
 }  // namespace
 
 // ===================================================================
@@ -77,95 +89,108 @@
 MessageGenerator::~MessageGenerator() {}
 
 // ===================================================================
-// TODO(api): Move this class to a separate immutable_message.cc file.
 ImmutableMessageGenerator::ImmutableMessageGenerator(
     const Descriptor* descriptor, Context* context)
   : MessageGenerator(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
 }
 
 ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
 
-void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
-    // used in the construction of descriptors, we have a tricky bootstrapping
-    // problem.  To help control static initialization order, we make sure all
-    // descriptors and other static data that depends on them are members of
-    // the outermost class in the file.  This way, they will be initialized in
-    // a deterministic order.
+void ImmutableMessageGenerator::GenerateStaticVariables(
+    io::Printer* printer, int* bytecode_estimate) {
+  // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+  // used in the construction of descriptors, we have a tricky bootstrapping
+  // problem.  To help control static initialization order, we make sure all
+  // descriptors and other static data that depends on them are members of
+  // the outermost class in the file.  This way, they will be initialized in
+  // a deterministic order.
 
-    map<string, string> vars;
-    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-    vars["index"] = SimpleItoa(descriptor_->index());
-    vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
-    if (descriptor_->containing_type() != NULL) {
-      vars["parent"] = UniqueFileScopeIdentifier(
-          descriptor_->containing_type());
-    }
-    if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
-      // We can only make these package-private since the classes that use them
-      // are in separate files.
-      vars["private"] = "";
-    } else {
-      vars["private"] = "private ";
-    }
-
-    // The descriptor for this type.
-    printer->Print(vars,
-      "$private$static final com.google.protobuf.Descriptors.Descriptor\n"
-      "  internal_$identifier$_descriptor;\n");
-
-    // And the FieldAccessorTable.
-    GenerateFieldAccessorTable(printer);
+  map<string, string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = SimpleItoa(descriptor_->index());
+  vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+  if (descriptor_->containing_type() != NULL) {
+    vars["parent"] = UniqueFileScopeIdentifier(
+        descriptor_->containing_type());
   }
+  if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+    // We can only make these package-private since the classes that use them
+    // are in separate files.
+    vars["private"] = "";
+  } else {
+    vars["private"] = "private ";
+  }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
+
+  // The descriptor for this type.
+  printer->Print(vars,
+    // TODO(teboring): final needs to be added back. The way to fix it is to
+    // generate methods that can construct the types, and then still declare the
+    // types, and then init them in clinit with the new method calls.
+    "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n"
+    "  internal_$identifier$_descriptor;\n");
+  *bytecode_estimate += 30;
+
+  // And the FieldAccessorTable.
+  GenerateFieldAccessorTable(printer, bytecode_estimate);
 
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
     ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
-      .GenerateStaticVariables(printer);
+        .GenerateStaticVariables(printer, bytecode_estimate);
   }
 }
 
-void ImmutableMessageGenerator::GenerateStaticVariableInitializers(
+int ImmutableMessageGenerator::GenerateStaticVariableInitializers(
     io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    map<string, string> vars;
-    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-    vars["index"] = SimpleItoa(descriptor_->index());
-    vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
-    if (descriptor_->containing_type() != NULL) {
-      vars["parent"] = UniqueFileScopeIdentifier(
-          descriptor_->containing_type());
-    }
-
-    // The descriptor for this type.
-    if (descriptor_->containing_type() == NULL) {
-      printer->Print(vars,
-        "internal_$identifier$_descriptor =\n"
-        "  getDescriptor().getMessageTypes().get($index$);\n");
-    } else {
-      printer->Print(vars,
-        "internal_$identifier$_descriptor =\n"
-        "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
-    }
-
-    // And the FieldAccessorTable.
-    GenerateFieldAccessorTableInitializer(printer);
+  int bytecode_estimate = 0;
+  map<string, string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = SimpleItoa(descriptor_->index());
+  vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+  if (descriptor_->containing_type() != NULL) {
+    vars["parent"] = UniqueFileScopeIdentifier(
+        descriptor_->containing_type());
   }
 
+  // The descriptor for this type.
+  if (descriptor_->containing_type() == NULL) {
+    printer->Print(vars,
+      "internal_$identifier$_descriptor =\n"
+      "  getDescriptor().getMessageTypes().get($index$);\n");
+    bytecode_estimate += 30;
+  } else {
+    printer->Print(vars,
+      "internal_$identifier$_descriptor =\n"
+      "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
+    bytecode_estimate += 30;
+  }
+
+  // And the FieldAccessorTable.
+  bytecode_estimate += GenerateFieldAccessorTableInitializer(printer);
+
   // Generate static member initializers for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
-    ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
-      .GenerateStaticVariableInitializers(printer);
+    bytecode_estimate +=
+        ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
   }
+  return bytecode_estimate;
 }
 
 void ImmutableMessageGenerator::
-GenerateFieldAccessorTable(io::Printer* printer) {
+GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate) {
   map<string, string> vars;
   vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
   if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
@@ -175,14 +200,24 @@
   } else {
     vars["private"] = "private ";
   }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
   printer->Print(vars,
-    "$private$static\n"
+    "$private$static $final$\n"
     "  com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
     "    internal_$identifier$_fieldAccessorTable;\n");
+
+  // 6 bytes per field and oneof
+  *bytecode_estimate += 10 + 6 * descriptor_->field_count()
+      + 6 * descriptor_->oneof_decl_count();
 }
 
-void ImmutableMessageGenerator::
+int ImmutableMessageGenerator::
 GenerateFieldAccessorTableInitializer(io::Printer* printer) {
+  int bytecode_estimate = 10;
   printer->Print(
     "internal_$identifier$_fieldAccessorTable = new\n"
     "  com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
@@ -193,6 +228,7 @@
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    bytecode_estimate += 6;
     printer->Print(
       "\"$field_name$\", ",
       "field_name", info->capitalized_name);
@@ -200,50 +236,33 @@
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
     const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof);
+    bytecode_estimate += 6;
     printer->Print(
       "\"$oneof_name$\", ",
       "oneof_name", info->capitalized_name);
   }
   printer->Print("});\n");
+  return bytecode_estimate;
 }
 
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
   if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.GeneratedMessage.\n"
-        "        ExtendableMessageOrBuilder<$classname$> {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    } else {
-      printer->Print(
-        "public interface $classname$OrBuilder extends \n"
-        "    $extra_interfaces$\n"
-        "     com.google.protobuf.GeneratedMessageLite.\n"
-        "          ExtendableMessageOrBuilder<$classname$> {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    }
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.GeneratedMessage.\n"
+      "        ExtendableMessageOrBuilder<$classname$> {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
   } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.MessageOrBuilder {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    } else {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.MessageLiteOrBuilder {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    }
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.MessageOrBuilder {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
   }
 
   printer->Indent();
@@ -252,6 +271,18 @@
       field_generators_.get(descriptor_->field(i))
                        .GenerateInterfaceMembers(printer);
     }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+      printer->Print(
+          "\n"
+          "public $classname$.$oneof_capitalized_name$Case "
+          "get$oneof_capitalized_name$Case();\n",
+          "oneof_capitalized_name",
+          context_->GetOneofGeneratorInfo(
+              descriptor_->oneof_decl(i))->capitalized_name,
+          "classname",
+          context_->GetNameResolver()->GetImmutableClassName(
+              descriptor_));
+    }
   printer->Outdent();
 
   printer->Print("}\n");
@@ -264,60 +295,32 @@
     descriptor_->containing_type() == NULL &&
     MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
 
+  map<string, string> variables;
+  variables["static"] = is_own_file ? " " : " static ";
+  variables["classname"] = descriptor_->name();
+  variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+
   WriteMessageDocComment(printer, descriptor_);
 
   // The builder_type stores the super type name of the nested Builder class.
   string builder_type;
   if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public$static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-        "      $classname$> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "static", is_own_file ? " " : " static ",
-        "classname", descriptor_->name(),
-        "extra_interfaces", ExtraMessageInterfaces(descriptor_));
-      builder_type = strings::Substitute(
-          "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
-          name_resolver_->GetImmutableClassName(descriptor_));
-    } else {
-      printer->Print(
-        "public$static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
-        "      $classname$> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "static", is_own_file ? " " : " static ",
-        "classname", descriptor_->name(),
-        "extra_interfaces", ExtraMessageInterfaces(descriptor_));
-      builder_type = strings::Substitute(
-          "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>",
-          name_resolver_->GetImmutableClassName(descriptor_));
-    }
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+      "      $classname$> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
+    builder_type = strings::Substitute(
+             "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
+             name_resolver_->GetImmutableClassName(descriptor_));
   } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public$static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "static", is_own_file ? " " : " static ",
-        "classname", descriptor_->name(),
-        "extra_interfaces", ExtraMessageInterfaces(descriptor_));
-      builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>";
-    } else {
-      printer->Print(
-        "public$static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessageLite implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "static", is_own_file ? " " : " static ",
-        "classname", descriptor_->name(),
-        "extra_interfaces", ExtraMessageInterfaces(descriptor_));
-      builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
-    }
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessage implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
+    builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>";
   }
   printer->Indent();
   // Using builder_type, instead of Builder, prevents the Builder class from
@@ -328,52 +331,38 @@
     "// Use $classname$.newBuilder() to construct.\n"
     "private $classname$($buildertype$ builder) {\n"
     "  super(builder);\n"
-    "$set_unknown_fields$\n"
     "}\n",
     "classname", descriptor_->name(),
-    "buildertype", builder_type,
-    "set_unknown_fields",
-    "  this.unknownFields = builder.getUnknownFields();");
+    "buildertype", builder_type);
   printer->Print(
-    // Used when constructing the default instance, which cannot be initialized
-    // immediately because it may cyclically refer to other default instances.
-    "private $classname$(boolean noInit) {$set_default_unknown_fields$}\n"
-    "\n"
-    "private static final $classname$ defaultInstance;\n"
-    "public static $classname$ getDefaultInstance() {\n"
-    "  return defaultInstance;\n"
+    "private $classname$() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+  GenerateInitializers(printer);
+  printer->Outdent();
+  printer->Print(
     "}\n"
-    "\n"
-    "public $classname$ getDefaultInstanceForType() {\n"
-    "  return defaultInstance;\n"
-    "}\n"
-    "\n",
-    "classname", descriptor_->name(),
-    "set_default_unknown_fields", UseUnknownFieldSet(descriptor_)
-        ? " this.unknownFields ="
-          " com.google.protobuf.UnknownFieldSet.getDefaultInstance(); "
-        : " this.unknownFields = com.google.protobuf.ByteString.EMPTY;");
+    "\n");
 
-  if (UseUnknownFieldSet(descriptor_)) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public final com.google.protobuf.UnknownFieldSet\n"
+    "getUnknownFields() {\n");
+  if (PreserveUnknownFields(descriptor_)) {
     printer->Print(
-        "private final com.google.protobuf.UnknownFieldSet unknownFields;\n"
-        ""
-        "@java.lang.Override\n"
-        "public final com.google.protobuf.UnknownFieldSet\n"
-        "    getUnknownFields() {\n"
-        "  return this.unknownFields;\n"
-        "}\n");
+      "  return this.unknownFields;\n");
   } else {
     printer->Print(
-        "private final com.google.protobuf.ByteString unknownFields;\n");
+      "  return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
   }
+  printer->Print(
+    "}\n");
 
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     GenerateParsingConstructor(printer);
   }
 
   GenerateDescriptorMethods(printer);
-  GenerateParser(printer);
 
   // Nested types
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -382,6 +371,8 @@
   }
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // Don't generate Java classes for map entry messages.
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
     ImmutableMessageGenerator messageGenerator(
         descriptor_->nested_type(i), context_);
     messageGenerator.GenerateInterface(printer);
@@ -433,12 +424,20 @@
       "cap_oneof_name",
       ToUpper(vars["oneof_name"]));
     printer->Print(vars,
-      "private int value = 0;\n"
+      "private final int value;\n"
       "private $oneof_capitalized_name$Case(int value) {\n"
       "  this.value = value;\n"
       "}\n");
     printer->Print(vars,
+      "/**\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
       "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
       "  switch (value) {\n");
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -451,8 +450,7 @@
     }
     printer->Print(
       "    case 0: return $cap_oneof_name$_NOT_SET;\n"
-      "    default: throw new java.lang.IllegalArgumentException(\n"
-      "      \"Value is undefined for this oneof enum.\");\n"
+      "    default: return null;\n"
       "  }\n"
       "}\n"
       "public int getNumber() {\n"
@@ -465,12 +463,16 @@
     printer->Print(vars,
       "public $oneof_capitalized_name$Case\n"
       "get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
       "      $oneof_name$Case_);\n"
       "}\n"
       "\n");
   }
 
+  if (IsAnyMessage(descriptor_)) {
+    GenerateAnyMethods(printer);
+  }
+
   // Fields
   for (int i = 0; i < descriptor_->field_count(); i++) {
     printer->Print("public static final int $constant_name$ = $number$;\n",
@@ -480,22 +482,8 @@
     printer->Print("\n");
   }
 
-  // Called by the constructor, except in the case of the default instance,
-  // in which case this is called by static init code later on.
-  printer->Print("private void initFields() {\n");
-  printer->Indent();
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    if (!descriptor_->field(i)->containing_oneof()) {
-      field_generators_.get(descriptor_->field(i))
-          .GenerateInitializationCode(printer);
-    }
-  }
-
-  printer->Outdent();
-  printer->Print("}\n");
-
-  if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer, MEMOIZE);
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
   }
 
@@ -507,21 +495,42 @@
   GenerateParseFromMethods(printer);
   GenerateBuilder(printer);
 
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+
   // Carefully initialize the default instance in such a way that it doesn't
   // conflict with other initialization.
   printer->Print(
-    "\n"
+    "private static final $classname$ DEFAULT_INSTANCE;\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  printer->Print(
     "static {\n"
-    "  defaultInstance = new $classname$(true);\n"
-    "  defaultInstance.initFields();\n"
+    "  DEFAULT_INSTANCE = new $classname$();\n"
     "}\n"
-    "\n"
-    "// @@protoc_insertion_point(class_scope:$full_name$)\n",
-    "classname", descriptor_->name(),
-    "full_name", descriptor_->full_name());
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
-  // Extensions must be declared after the defaultInstance is initialized
-  // because the defaultInstance is used by the extension to lazily retrieve
+  printer->Print(
+      "public static $classname$ getDefaultInstance() {\n"
+      "  return DEFAULT_INSTANCE;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  GenerateParser(printer);
+
+  printer->Print(
+    "public $classname$ getDefaultInstanceForType() {\n"
+    "  return DEFAULT_INSTANCE;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+  // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
   // the outer class's FileDescriptor.
   for (int i = 0; i < descriptor_->extension_count(); i++) {
     ImmutableExtensionGenerator(descriptor_->extension(i), context_)
@@ -537,43 +546,43 @@
 
 void ImmutableMessageGenerator::
 GenerateMessageSerializationMethods(io::Printer* printer) {
-  scoped_array<const FieldDescriptor*> sorted_fields(
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
       SortFieldsByNumber(descriptor_));
 
   vector<const Descriptor::ExtensionRange*> sorted_extensions;
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
     sorted_extensions.push_back(descriptor_->extension_range(i));
   }
-  sort(sorted_extensions.begin(), sorted_extensions.end(),
-       ExtensionRangeOrdering());
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeOrdering());
 
   printer->Print(
     "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
     "                    throws java.io.IOException {\n");
   printer->Indent();
-  // writeTo(CodedOutputStream output) might be invoked without
-  // getSerializedSize() ever being called, but we need the memoized
-  // sizes in case this message has packed fields. Rather than emit checks for
-  // each packed field, just call getSerializedSize() up front for all messages.
-  // In most cases, getSerializedSize() will have already been called anyway by
-  // one of the wrapper writeTo() methods, making this call cheap.
-  printer->Print(
-    "getSerializedSize();\n");
+  if (HasPackedFields(descriptor_)) {
+    // writeTo(CodedOutputStream output) might be invoked without
+    // getSerializedSize() ever being called, but we need the memoized
+    // sizes in case this message has packed fields. Rather than emit checks for
+    // each packed field, just call getSerializedSize() up front.
+    // In most cases, getSerializedSize() will have already been called anyway
+    // by one of the wrapper writeTo() methods, making this call cheap.
+    printer->Print(
+      "getSerializedSize();\n");
+  }
 
   if (descriptor_->extension_range_count() > 0) {
     if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
-        "com.google.protobuf.GeneratedMessage$lite$\n"
-        "  .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
-        "    newMessageSetExtensionWriter();\n",
-        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newMessageSetExtensionWriter();\n",
         "classname", name_resolver_->GetImmutableClassName(descriptor_));
     } else {
       printer->Print(
-        "com.google.protobuf.GeneratedMessage$lite$\n"
-        "  .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
-        "    newExtensionWriter();\n",
-        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newExtensionWriter();\n",
         "classname", name_resolver_->GetImmutableClassName(descriptor_));
     }
   }
@@ -593,26 +602,22 @@
     }
   }
 
-  if (UseUnknownFieldSet(descriptor_)) {
+  if (PreserveUnknownFields(descriptor_)) {
     if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
-        "getUnknownFields().writeAsMessageSetTo(output);\n");
+        "unknownFields.writeAsMessageSetTo(output);\n");
     } else {
       printer->Print(
-        "getUnknownFields().writeTo(output);\n");
+        "unknownFields.writeTo(output);\n");
     }
-  } else {
-    printer->Print(
-      "output.writeRawBytes(unknownFields);\n");
   }
 
   printer->Outdent();
   printer->Print(
     "}\n"
     "\n"
-    "private int memoizedSerializedSize = -1;\n"
     "public int getSerializedSize() {\n"
-    "  int size = memoizedSerializedSize;\n"
+    "  int size = memoizedSize;\n"
     "  if (size != -1) return size;\n"
     "\n"
     "  size = 0;\n");
@@ -632,34 +637,25 @@
     }
   }
 
-  if (UseUnknownFieldSet(descriptor_)) {
+  if (PreserveUnknownFields(descriptor_)) {
     if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
-        "size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
+        "size += unknownFields.getSerializedSizeAsMessageSet();\n");
     } else {
       printer->Print(
-        "size += getUnknownFields().getSerializedSize();\n");
+        "size += unknownFields.getSerializedSize();\n");
     }
-  } else {
-    printer->Print(
-      "size += unknownFields.size();\n");
   }
 
   printer->Outdent();
   printer->Print(
-    "  memoizedSerializedSize = size;\n"
+    "  memoizedSize = size;\n"
     "  return size;\n"
     "}\n"
     "\n");
 
   printer->Print(
-    "private static final long serialVersionUID = 0L;\n"
-    "@java.lang.Override\n"
-    "protected java.lang.Object writeReplace()\n"
-    "    throws java.io.ObjectStreamException {\n"
-    "  return super.writeReplace();\n"
-    "}\n"
-    "\n");
+    "private static final long serialVersionUID = 0L;\n");
 }
 
 void ImmutableMessageGenerator::
@@ -691,34 +687,40 @@
     "}\n"
     "public static $classname$ parseFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseDelimitedFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseDelimitedWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -739,485 +741,115 @@
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
+  // LITE_RUNTIME implements this at the GeneratedMessageLite level.
   printer->Print(
-    "public static Builder newBuilder() { return Builder.create(); }\n"
-    "public Builder newBuilderForType() { return newBuilder(); }\n"
-    "public static Builder newBuilder($classname$ prototype) {\n"
-    "  return newBuilder().mergeFrom(prototype);\n"
+    "public Builder newBuilderForType() { return newBuilder(); }\n");
+
+  printer->Print(
+    "public static Builder newBuilder() {\n"
+    "  return DEFAULT_INSTANCE.toBuilder();\n"
     "}\n"
-    "public Builder toBuilder() { return newBuilder(this); }\n"
+    "public static Builder newBuilder($classname$ prototype) {\n"
+    "  return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
+    "}\n"
+    "public Builder toBuilder() {\n"
+    "  return this == DEFAULT_INSTANCE\n"
+    "      ? new Builder() : new Builder().mergeFrom(this);\n"
+    "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
-  if (HasNestedBuilders(descriptor_)) {
-     printer->Print(
-      "@java.lang.Override\n"
-      "protected Builder newBuilderForType(\n"
-      "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
-      "  Builder builder = new Builder(parent);\n"
-      "  return builder;\n"
-      "}\n");
-  }
-
-  WriteMessageDocComment(printer, descriptor_);
-
-  if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
-        "      $classname$, Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    } else {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
-        "      $classname$, Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    }
-  } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    } else {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.Builder<\n"
-        "      $classname$, Builder>\n"
-        "    implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    }
-  }
-  printer->Indent();
-
-  GenerateDescriptorMethods(printer);
-  GenerateCommonBuilderMethods(printer);
-
-  if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer, DONT_MEMOIZE);
-    GenerateBuilderParsingMethods(printer);
-  }
-
-  // oneof
-  map<string, string> vars;
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
-        descriptor_->oneof_decl(i))->name;
-    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
-        descriptor_->oneof_decl(i))->capitalized_name;
-    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
-    // oneofCase_ and oneof_
-    printer->Print(vars,
-      "private int $oneof_name$Case_ = 0;\n"
-      "private java.lang.Object $oneof_name$_;\n");
-    // oneofCase() and clearOneof()
-    printer->Print(vars,
-      "public $oneof_capitalized_name$Case\n"
-      "    get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
-      "      $oneof_name$Case_);\n"
-      "}\n"
-      "\n"
-      "public Builder clear$oneof_capitalized_name$() {\n"
-      "  $oneof_name$Case_ = 0;\n"
-      "  $oneof_name$_ = null;\n");
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print("  onChanged();\n");
-    }
-    printer->Print(
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForBuilder();
-    }
-    int totalInts = (totalBits + 31) / 32;
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print("private int $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-  }
-
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    printer->Print("\n");
-    field_generators_.get(descriptor_->field(i))
-                     .GenerateBuilderMembers(printer);
-  }
-
   printer->Print(
-    "\n"
-    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
-    "full_name", descriptor_->full_name());
+    "@java.lang.Override\n"
+    "protected Builder newBuilderForType(\n"
+    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "  Builder builder = new Builder(parent);\n"
+    "  return builder;\n"
+    "}\n");
 
-  printer->Outdent();
-  printer->Print("}\n");
+  MessageBuilderGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
 }
 
 void ImmutableMessageGenerator::
 GenerateDescriptorMethods(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    if (!descriptor_->options().no_standard_descriptor_accessor()) {
-      printer->Print(
-        "public static final com.google.protobuf.Descriptors.Descriptor\n"
-        "    getDescriptor() {\n"
-        "  return $fileclass$.internal_$identifier$_descriptor;\n"
-        "}\n"
-        "\n",
-        "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-        "identifier", UniqueFileScopeIdentifier(descriptor_));
-    }
+  if (!descriptor_->options().no_standard_descriptor_accessor()) {
     printer->Print(
-      "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
-      "    internalGetFieldAccessorTable() {\n"
-      "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
-      "      .ensureFieldAccessorsInitialized(\n"
-      "          $classname$.class, $classname$.Builder.class);\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_),
-      "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-      "identifier", UniqueFileScopeIdentifier(descriptor_));
-  }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateCommonBuilderMethods(io::Printer* printer) {
-  printer->Print(
-    "// Construct using $classname$.newBuilder()\n"
-    "private Builder() {\n"
-    "  maybeForceBuilderInitialization();\n"
-    "}\n"
-    "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "private Builder(\n"
-      "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
-      "  super(parent);\n"
-      "  maybeForceBuilderInitialization();\n"
-      "}\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
-
-
-  if (HasNestedBuilders(descriptor_)) {
-    printer->Print(
-      "private void maybeForceBuilderInitialization() {\n"
-      "  if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
-
-    printer->Indent();
-    printer->Indent();
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      if (!descriptor_->field(i)->containing_oneof()) {
-        field_generators_.get(descriptor_->field(i))
-            .GenerateFieldBuilderInitializationCode(printer);
-      }
-    }
-    printer->Outdent();
-    printer->Outdent();
-
-    printer->Print(
-      "  }\n"
-      "}\n");
-  } else {
-    printer->Print(
-      "private void maybeForceBuilderInitialization() {\n"
-      "}\n");
-  }
-
-  printer->Print(
-    "private static Builder create() {\n"
-    "  return new Builder();\n"
-    "}\n"
-    "\n"
-    "public Builder clear() {\n"
-    "  super.clear();\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  printer->Indent();
-
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    if (!descriptor_->field(i)->containing_oneof()) {
-      field_generators_.get(descriptor_->field(i))
-          .GenerateBuilderClearCode(printer);
-    }
-  }
-
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print(
-      "$oneof_name$Case_ = 0;\n"
-      "$oneof_name$_ = null;\n",
-      "oneof_name", context_->GetOneofGeneratorInfo(
-          descriptor_->oneof_decl(i))->name);
-  }
-
-  printer->Outdent();
-
-  printer->Print(
-    "  return this;\n"
-    "}\n"
-    "\n"
-    "public Builder clone() {\n"
-    "  return create().mergeFrom(buildPartial());\n"
-    "}\n"
-    "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public com.google.protobuf.Descriptors.Descriptor\n"
-      "    getDescriptorForType() {\n"
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
       "  return $fileclass$.internal_$identifier$_descriptor;\n"
       "}\n"
       "\n",
       "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
       "identifier", UniqueFileScopeIdentifier(descriptor_));
   }
-  printer->Print(
-    "public $classname$ getDefaultInstanceForType() {\n"
-    "  return $classname$.getDefaultInstance();\n"
-    "}\n"
-    "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  // -----------------------------------------------------------------
-
-  printer->Print(
-    "public $classname$ build() {\n"
-    "  $classname$ result = buildPartial();\n"
-    "  if (!result.isInitialized()) {\n"
-    "    throw newUninitializedMessageException(result);\n"
-    "  }\n"
-    "  return result;\n"
-    "}\n"
-    "\n"
-    "public $classname$ buildPartial() {\n"
-    "  $classname$ result = new $classname$(this);\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  printer->Indent();
-
-  int totalBuilderBits = 0;
-  int totalMessageBits = 0;
+  vector<const FieldDescriptor*> map_fields;
   for (int i = 0; i < descriptor_->field_count(); i++) {
-    const ImmutableFieldGenerator& field =
-        field_generators_.get(descriptor_->field(i));
-    totalBuilderBits += field.GetNumBitsForBuilder();
-    totalMessageBits += field.GetNumBitsForMessage();
-  }
-  int totalBuilderInts = (totalBuilderBits + 31) / 32;
-  int totalMessageInts = (totalMessageBits + 31) / 32;
-
-  if (GenerateHasBits(descriptor_)) {
-    // Local vars for from and to bit fields to avoid accessing the builder and
-    // message over and over for these fields. Seems to provide a slight
-    // perforamance improvement in micro benchmark and this is also what proto1
-    // code does.
-    for (int i = 0; i < totalBuilderInts; i++) {
-      printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("int to_$bit_field_name$ = 0;\n",
-        "bit_field_name", GetBitFieldName(i));
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        IsMapEntry(field->message_type())) {
+      map_fields.push_back(field);
     }
   }
-
-  // Output generation code for each field.
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
-  }
-
-  if (GenerateHasBits(descriptor_)) {
-    // Copy the bit field results to the generated message
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-  }
-
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
-                   "oneof_name", context_->GetOneofGeneratorInfo(
-                       descriptor_->oneof_decl(i))->name);
-  }
-
-  printer->Outdent();
-
-  if (HasDescriptorMethods(descriptor_)) {
+  if (!map_fields.empty()) {
     printer->Print(
-    "  onBuilt();\n");
-  }
-
-  printer->Print(
-    "  return result;\n"
-    "}\n"
-    "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  // -----------------------------------------------------------------
-
-  if (HasGeneratedMethods(descriptor_)) {
-    // MergeFrom(Message other) requires the ability to distinguish the other
-    // messages type by its descriptor.
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
-        "  if (other instanceof $classname$) {\n"
-        "    return mergeFrom(($classname$)other);\n"
-        "  } else {\n"
-        "    super.mergeFrom(other);\n"
-        "    return this;\n"
-        "  }\n"
-        "}\n"
-        "\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-    }
-
-    printer->Print(
-      "public Builder mergeFrom($classname$ other) {\n"
-      // Optimization:  If other is the default instance, we know none of its
-      //   fields are set so we can skip the merge.
-      "  if (other == $classname$.getDefaultInstance()) return this;\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
     printer->Indent();
-
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      if (!descriptor_->field(i)->containing_oneof()) {
-        field_generators_.get(
-            descriptor_->field(i)).GenerateMergingCode(printer);
-      }
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      printer->Print(
+        "case $number$:\n"
+        "  return internalGet$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
     }
-
-    // Merge oneof fields.
-    for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
-      printer->Print(
-        "switch (other.get$oneof_capitalized_name$Case()) {\n",
-        "oneof_capitalized_name",
-        context_->GetOneofGeneratorInfo(
-            descriptor_->oneof_decl(i))->capitalized_name);
-      printer->Indent();
-      for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
-        const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
-        printer->Print(
-          "case $field_name$: {\n",
-          "field_name",
-          ToUpper(field->name()));
-        printer->Indent();
-        field_generators_.get(field).GenerateMergingCode(printer);
-        printer->Print(
-            "break;\n");
-        printer->Outdent();
-        printer->Print(
-            "}\n");
-      }
-      printer->Print(
-        "case $cap_oneof_name$_NOT_SET: {\n"
-        "  break;\n"
-        "}\n",
-        "cap_oneof_name",
-        ToUpper(context_->GetOneofGeneratorInfo(
-            descriptor_->oneof_decl(i))->name));
-      printer->Outdent();
-      printer->Print(
-          "}\n");
-    }
-
-    printer->Outdent();
-
-    // if message type has extensions
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "  this.mergeExtensionFields(other);\n");
-    }
-
-    if (UseUnknownFieldSet(descriptor_)) {
-      printer->Print(
-        "  this.mergeUnknownFields(other.getUnknownFields());\n");
-    } else {
-      printer->Print(
-        "  setUnknownFields(\n"
-        "      getUnknownFields().concat(other.unknownFields));\n");
-    }
-
     printer->Print(
-      "  return this;\n"
-      "}\n"
-      "\n");
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
   }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateBuilderParsingMethods(io::Printer* printer) {
   printer->Print(
-    "public Builder mergeFrom(\n"
-    "    com.google.protobuf.CodedInputStream input,\n"
-    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
-    "    throws java.io.IOException {\n"
-    "  $classname$ parsedMessage = null;\n"
-    "  try {\n"
-    "    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
-    "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-    "    parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
-    "    throw e;\n"
-    "  } finally {\n"
-    "    if (parsedMessage != null) {\n"
-    "      mergeFrom(parsedMessage);\n"
-    "    }\n"
-    "  }\n"
-    "  return this;\n"
-    "}\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "    internalGetFieldAccessorTable() {\n"
+    "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+    "      .ensureFieldAccessorsInitialized(\n"
+    "          $classname$.class, $classname$.Builder.class);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
 }
 
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateIsInitialized(
-    io::Printer* printer, UseMemoization useMemoization) {
-  bool memoization = useMemoization == MEMOIZE;
-  if (memoization) {
-    // Memoizes whether the protocol buffer is fully initialized (has all
-    // required fields). -1 means not yet computed. 0 means false and 1 means
-    // true.
-    printer->Print(
-      "private byte memoizedIsInitialized = -1;\n");
-  }
+    io::Printer* printer) {
+  // Memoizes whether the protocol buffer is fully initialized (has all
+  // required fields). -1 means not yet computed. 0 means false and 1 means
+  // true.
+  printer->Print(
+    "private byte memoizedIsInitialized = -1;\n");
   printer->Print(
     "public final boolean isInitialized() {\n");
   printer->Indent();
 
-  if (memoization) {
-    // Don't directly compare to -1 to avoid an Android x86 JIT bug.
-    printer->Print(
-      "byte isInitialized = memoizedIsInitialized;\n"
-      "if (isInitialized == 1) return true;\n"
-      "if (isInitialized == 0) return false;\n"
-      "\n");
-  }
+  // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+  printer->Print(
+    "byte isInitialized = memoizedIsInitialized;\n"
+    "if (isInitialized == 1) return true;\n"
+    "if (isInitialized == 0) return false;\n"
+    "\n");
 
   // Check that all required fields in this message are set.
   // TODO(kenton):  We can optimize this when we switch to putting all the
@@ -1229,11 +861,10 @@
     if (field->is_required()) {
       printer->Print(
         "if (!has$name$()) {\n"
-        "  $memoize$\n"
+        "  memoizedIsInitialized = 0;\n"
         "  return false;\n"
         "}\n",
-        "name", info->capitalized_name,
-        "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+        "name", info->capitalized_name);
     }
   }
 
@@ -1247,39 +878,60 @@
         case FieldDescriptor::LABEL_REQUIRED:
           printer->Print(
             "if (!get$name$().isInitialized()) {\n"
-             "  $memoize$\n"
+             "  memoizedIsInitialized = 0;\n"
              "  return false;\n"
              "}\n",
             "type", name_resolver_->GetImmutableClassName(
                 field->message_type()),
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+            "name", info->capitalized_name);
           break;
         case FieldDescriptor::LABEL_OPTIONAL:
+          if (!SupportFieldPresence(descriptor_->file()) &&
+              field->containing_oneof() != NULL) {
+            const OneofDescriptor* oneof = field->containing_oneof();
+            const OneofGeneratorInfo* oneof_info =
+                context_->GetOneofGeneratorInfo(oneof);
+            printer->Print(
+              "if ($oneof_name$Case_ == $field_number$) {\n",
+              "oneof_name", oneof_info->name,
+              "field_number", SimpleItoa(field->number()));
+          } else {
+            printer->Print(
+              "if (has$name$()) {\n",
+              "name", info->capitalized_name);
+          }
           printer->Print(
-            "if (has$name$()) {\n"
             "  if (!get$name$().isInitialized()) {\n"
-            "    $memoize$\n"
+            "    memoizedIsInitialized = 0;\n"
             "    return false;\n"
             "  }\n"
             "}\n",
-            "type", name_resolver_->GetImmutableClassName(
-                field->message_type()),
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+            "name", info->capitalized_name);
           break;
         case FieldDescriptor::LABEL_REPEATED:
-          printer->Print(
-            "for (int i = 0; i < get$name$Count(); i++) {\n"
-            "  if (!get$name$(i).isInitialized()) {\n"
-            "    $memoize$\n"
-            "    return false;\n"
-            "  }\n"
-            "}\n",
-            "type", name_resolver_->GetImmutableClassName(
-                field->message_type()),
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+          if (IsMapEntry(field->message_type())) {
+            printer->Print(
+              "for ($type$ item : get$name$().values()) {\n"
+              "  if (!item.isInitialized()) {\n"
+              "    memoizedIsInitialized = 0;\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", MapValueImmutableClassdName(field->message_type(),
+                                                  name_resolver_),
+              "name", info->capitalized_name);
+          } else {
+            printer->Print(
+              "for (int i = 0; i < get$name$Count(); i++) {\n"
+              "  if (!get$name$(i).isInitialized()) {\n"
+              "    memoizedIsInitialized = 0;\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", name_resolver_->GetImmutableClassName(
+                  field->message_type()),
+              "name", info->capitalized_name);
+          }
           break;
       }
     }
@@ -1288,18 +940,15 @@
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
       "if (!extensionsAreInitialized()) {\n"
-      "  $memoize$\n"
+      "  memoizedIsInitialized = 0;\n"
       "  return false;\n"
-      "}\n",
-      "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+      "}\n");
   }
 
   printer->Outdent();
 
-  if (memoization) {
-    printer->Print(
-      "  memoizedIsInitialized = 1;\n");
-  }
+  printer->Print(
+    "  memoizedIsInitialized = 1;\n");
 
   printer->Print(
     "  return true;\n"
@@ -1342,31 +991,69 @@
   printer->Print("boolean result = true;\n");
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
-    if (check_has_bits) {
-      printer->Print(
-        "result = result && (has$name$() == other.has$name$());\n"
-        "if (has$name$()) {\n",
-        "name", info->capitalized_name);
-      printer->Indent();
-    }
-    field_generators_.get(field).GenerateEqualsCode(printer);
-    if (check_has_bits) {
-      printer->Outdent();
-      printer->Print(
-        "}\n");
+    if (field->containing_oneof() == NULL) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+          "result = result && (has$name$() == other.has$name$());\n"
+          "if (has$name$()) {\n",
+          "name", info->capitalized_name);
+        printer->Indent();
+      }
+      field_generators_.get(field).GenerateEqualsCode(printer);
+      if (check_has_bits) {
+        printer->Outdent();
+        printer->Print(
+          "}\n");
+      }
     }
   }
-  if (HasDescriptorMethods(descriptor_)) {
+
+  // Compare oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "result = result && get$oneof_capitalized_name$Case().equals(\n"
+      "    other.get$oneof_capitalized_name$Case());\n",
+      "oneof_capitalized_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->capitalized_name);
+    printer->Print(
+      "if (!result) return false;\n"
+      "switch ($oneof_name$Case_) {\n",
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_number$:\n",
+        "field_number",
+        SimpleItoa(field->number()));
+      printer->Indent();
+      field_generators_.get(field).GenerateEqualsCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Print(
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    // Always consider unknown fields for equality. This will sometimes return
+    // false for non-canonical ordering when running in LITE_RUNTIME but it's
+    // the best we can do.
+    printer->Print(
+      "result = result && unknownFields.equals(other.unknownFields);\n");
+  }
+  if (descriptor_->extension_range_count() > 0) {
     printer->Print(
       "result = result &&\n"
-      "    getUnknownFields().equals(other.getUnknownFields());\n");
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "result = result &&\n"
-        "    getExtensionFields().equals(other.getExtensionFields());\n");
-    }
+      "    getExtensionFields().equals(other.getExtensionFields());\n");
   }
   printer->Print(
     "return result;\n");
@@ -1389,45 +1076,61 @@
     "}\n"
     "int hash = 41;\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
-  } else {
-    // Include the hash of the class so that two objects with different types
-    // but the same field values will probably have different hashes.
-    printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
+  printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
 
+  // hashCode non-oneofs.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
-    if (check_has_bits) {
-      printer->Print(
-        "if (has$name$()) {\n",
-        "name", info->capitalized_name);
-      printer->Indent();
-    }
-    field_generators_.get(field).GenerateHashCode(printer);
-    if (check_has_bits) {
-      printer->Outdent();
-      printer->Print("}\n");
-    }
-  }
-  if (HasDescriptorMethods(descriptor_)) {
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "hash = hashFields(hash, getExtensionFields());\n");
+    if (field->containing_oneof() == NULL) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+          "if (has$name$()) {\n",
+          "name", info->capitalized_name);
+        printer->Indent();
+      }
+      field_generators_.get(field).GenerateHashCode(printer);
+      if (check_has_bits) {
+        printer->Outdent();
+        printer->Print("}\n");
+      }
     }
   }
 
-  if (UseUnknownFieldSet(descriptor_)) {
+  // hashCode oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
-      "hash = (29 * hash) + getUnknownFields().hashCode();\n");
-  } else {
+      "switch ($oneof_name$Case_) {\n",
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_number$:\n",
+        "field_number",
+        SimpleItoa(field->number()));
+      printer->Indent();
+      field_generators_.get(field).GenerateHashCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
     printer->Print(
-      "hash = (29 * hash) + unknownFields.hashCode();\n");
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
   }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "hash = hashFields(hash, getExtensionFields());\n");
+  }
+
+  printer->Print(
+    "hash = (29 * hash) + unknownFields.hashCode();\n");
   printer->Print(
     "memoizedHashCode = hash;\n"
     "return hash;\n");
@@ -1455,7 +1158,7 @@
 // ===================================================================
 void ImmutableMessageGenerator::
 GenerateParsingConstructor(io::Printer* printer) {
-  scoped_array<const FieldDescriptor*> sorted_fields(
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
       SortFieldsByNumber(descriptor_));
 
   printer->Print(
@@ -1468,7 +1171,7 @@
 
   // Initialize all fields to default.
   printer->Print(
-      "initFields();\n");
+      "this();\n");
 
   // Use builder bits to track mutable repeated fields.
   int totalBuilderBits = 0;
@@ -1483,17 +1186,10 @@
       "bit_field_name", GetBitFieldName(i));
   }
 
-  if (UseUnknownFieldSet(descriptor_)) {
+  if (PreserveUnknownFields(descriptor_)) {
     printer->Print(
       "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
       "    com.google.protobuf.UnknownFieldSet.newBuilder();\n");
-  } else {
-    printer->Print(
-      "com.google.protobuf.ByteString.Output unknownFieldsOutput =\n"
-      "    com.google.protobuf.ByteString.newOutput();\n"
-      "com.google.protobuf.CodedOutputStream unknownFieldsCodedOutput =\n"
-      "    com.google.protobuf.CodedOutputStream.newInstance(\n"
-      "        unknownFieldsOutput);\n");
   }
 
   printer->Print(
@@ -1513,16 +1209,27 @@
   printer->Print(
     "case 0:\n"          // zero signals EOF / limit reached
     "  done = true;\n"
-    "  break;\n"
-    "default: {\n"
-    "  if (!parseUnknownField(input,$unknown_fields$\n"
-    "                         extensionRegistry, tag)) {\n"
-    "    done = true;\n"  // it's an endgroup tag
-    "  }\n"
-    "  break;\n"
-    "}\n",
-    "unknown_fields", UseUnknownFieldSet(descriptor_)
-        ? " unknownFields," : " unknownFieldsCodedOutput,");
+    "  break;\n");
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "default: {\n"
+      "  if (!parseUnknownField(input, unknownFields,\n"
+      "                         extensionRegistry, tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
+  } else {
+    printer->Print(
+      "default: {\n"
+      "  if (!input.skipField(tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n");
+    printer->Print(
+      "  break;\n"
+      "}\n");
+  }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = sorted_fields[i];
@@ -1572,7 +1279,7 @@
       "  throw e.setUnfinishedMessage(this);\n"
       "} catch (java.io.IOException e) {\n"
       "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
-      "      e.getMessage()).setUnfinishedMessage(this);\n"
+      "      e).setUnfinishedMessage(this);\n"
       "} finally {\n");
   printer->Indent();
 
@@ -1582,19 +1289,9 @@
     field_generators_.get(field).GenerateParsingDoneCode(printer);
   }
 
-  // Make unknown fields immutable.
-  if (UseUnknownFieldSet(descriptor_)) {
-    printer->Print(
-        "this.unknownFields = unknownFields.build();\n");
-  } else {
-    printer->Print(
-        "try {\n"
-        "  unknownFieldsCodedOutput.flush();\n"
-        "} catch (java.io.IOException e) {\n"
-        "// Should not happen\n"
-        "} finally {\n"
-        "  unknownFields = unknownFieldsOutput.toByteString();\n"
-        "}\n");
+  if (PreserveUnknownFields(descriptor_)) {
+    // Make unknown fields immutable.
+    printer->Print("this.unknownFields = unknownFields.build();\n");
   }
 
   // Make extensions immutable.
@@ -1611,8 +1308,11 @@
 // ===================================================================
 void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
   printer->Print(
-      "public static com.google.protobuf.Parser<$classname$> PARSER =\n"
-      "    new com.google.protobuf.AbstractParser<$classname$>() {\n",
+      "$visibility$ static final com.google.protobuf.Parser<$classname$>\n"
+      "    PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n",
+      "visibility",
+      ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public"
+                                              : "private",
       "classname", descriptor_->name());
   printer->Indent();
   printer->Print(
@@ -1621,14 +1321,14 @@
       "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
       "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
       "classname", descriptor_->name());
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     printer->Print(
-        "  return new $classname$(input, extensionRegistry);\n",
+        "    return new $classname$(input, extensionRegistry);\n",
         "classname", descriptor_->name());
   } else {
-    // When parsing constructor isn't generated, use builder to parse messages.
-    // Note, will fallback to use reflection based mergeFieldFrom() in
-    // AbstractMessage.Builder.
+    // When parsing constructor isn't generated, use builder to parse
+    // messages. Note, will fallback to use reflection based mergeFieldFrom()
+    // in AbstractMessage.Builder.
     printer->Indent();
     printer->Print(
         "Builder builder = newBuilder();\n"
@@ -1638,7 +1338,8 @@
         "  throw e.setUnfinishedMessage(builder.buildPartial());\n"
         "} catch (java.io.IOException e) {\n"
         "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
-        "      e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n"
+        "      e.getMessage()).setUnfinishedMessage(\n"
+        "          builder.buildPartial());\n"
         "}\n"
         "return builder.buildPartial();\n");
     printer->Outdent();
@@ -1651,6 +1352,10 @@
       "\n");
 
   printer->Print(
+      "public static com.google.protobuf.Parser<$classname$> parser() {\n"
+      "  return PARSER;\n"
+      "}\n"
+      "\n"
       "@java.lang.Override\n"
       "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
       "  return PARSER;\n"
@@ -1659,6 +1364,85 @@
       "classname", descriptor_->name());
 }
 
+// ===================================================================
+void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitializationCode(printer);
+    }
+  }
+}
+
+
+void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
+  printer->Print(
+    "private static String getTypeUrl(\n"
+    "    java.lang.String typeUrlPrefix,\n"
+    "    com.google.protobuf.Descriptors.Descriptor descriptor) {\n"
+    "  return typeUrlPrefix.endsWith(\"/\")\n"
+    "      ? typeUrlPrefix + descriptor.getFullName()\n"
+    "      : typeUrlPrefix + \"/\" + descriptor.getFullName();\n"
+    "}\n"
+    "\n"
+    "private static String getTypeNameFromTypeUrl(\n"
+    "    java.lang.String typeUrl) {\n"
+    "  int pos = typeUrl.lastIndexOf('/');\n"
+    "  return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n"
+    "}\n"
+    "\n"
+    "public static <T extends com.google.protobuf.Message> Any pack(\n"
+    "    T message) {\n"
+    "  return Any.newBuilder()\n"
+    "      .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n"
+    "                             message.getDescriptorForType()))\n"
+    "      .setValue(message.toByteString())\n"
+    "      .build();\n"
+    "}\n"
+    "\n"
+    "/**\n"
+    " * Packs a message uisng the given type URL prefix. The type URL will\n"
+    " * be constructed by concatenating the message type's full name to the\n"
+    " * prefix with an optional \"/\" separator if the prefix doesn't end\n"
+    " * with \"/\" already.\n"
+    " */\n"
+    "public static <T extends com.google.protobuf.Message> Any pack(\n"
+    "    T message, java.lang.String typeUrlPrefix) {\n"
+    "  return Any.newBuilder()\n"
+    "      .setTypeUrl(getTypeUrl(typeUrlPrefix,\n"
+    "                             message.getDescriptorForType()))\n"
+    "      .setValue(message.toByteString())\n"
+    "      .build();\n"
+    "}\n"
+    "\n"
+    "public <T extends com.google.protobuf.Message> boolean is(\n"
+    "    java.lang.Class<T> clazz) {\n"
+    "  T defaultInstance =\n"
+    "      com.google.protobuf.Internal.getDefaultInstance(clazz);\n"
+    "  return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n"
+    "      defaultInstance.getDescriptorForType().getFullName());\n"
+    "}\n"
+    "\n"
+    "private volatile com.google.protobuf.Message cachedUnpackValue;\n"
+    "\n"
+    "public <T extends com.google.protobuf.Message> T unpack(\n"
+    "    java.lang.Class<T> clazz)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  if (!is(clazz)) {\n"
+    "    throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+    "        \"Type of the Any message does not match the given class.\");\n"
+    "  }\n"
+    "  if (cachedUnpackValue != null) {\n"
+    "    return (T) cachedUnpackValue;\n"
+    "  }\n"
+    "  T defaultInstance =\n"
+    "      com.google.protobuf.Internal.getDefaultInstance(clazz);\n"
+    "  T result = (T) defaultInstance.getParserForType()\n"
+    "      .parseFrom(getValue());\n"
+    "  cachedUnpackValue = result;\n"
+    "  return result;\n"
+    "}\n");
+}
 
 }  // namespace java
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index fece1c2..e9fc57c 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -56,6 +56,8 @@
 namespace compiler {
 namespace java {
 
+static const int kMaxStaticSize = 1 << 15;  // aka 32k
+
 class MessageGenerator {
  public:
   explicit MessageGenerator(const Descriptor* descriptor);
@@ -64,11 +66,12 @@
   // All static variables have to be declared at the top-level of the file
   // so that we can control initialization order, which is important for
   // DescriptorProto bootstrapping to work.
-  virtual void GenerateStaticVariables(io::Printer* printer) = 0;
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate) = 0;
 
   // Output code which initializes the static variables generated by
-  // GenerateStaticVariables().
-  virtual void GenerateStaticVariableInitializers(io::Printer* printer) = 0;
+  // GenerateStaticVariables(). Returns an estimate of bytecode size.
+  virtual int GenerateStaticVariableInitializers(io::Printer* printer) = 0;
 
   // Generate the class itself.
   virtual void Generate(io::Printer* printer) = 0;
@@ -96,17 +99,18 @@
   virtual void Generate(io::Printer* printer);
   virtual void GenerateInterface(io::Printer* printer);
   virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
-  virtual void GenerateStaticVariables(io::Printer* printer);
-  virtual void GenerateStaticVariableInitializers(io::Printer* printer);
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateStaticVariableInitializers(io::Printer* printer);
 
  private:
-  enum UseMemoization {
-    MEMOIZE,
-    DONT_MEMOIZE
-  };
 
-  void GenerateFieldAccessorTable(io::Printer* printer);
-  void GenerateFieldAccessorTableInitializer(io::Printer* printer);
+  void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  int GenerateFieldAccessorTableInitializer(io::Printer* printer);
 
   void GenerateMessageSerializationMethods(io::Printer* printer);
   void GenerateParseFromMethods(io::Printer* printer);
@@ -116,14 +120,13 @@
       io::Printer* printer, const Descriptor::ExtensionRange* range);
 
   void GenerateBuilder(io::Printer* printer);
-  void GenerateCommonBuilderMethods(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer);
   void GenerateDescriptorMethods(io::Printer* printer);
-  void GenerateBuilderParsingMethods(io::Printer* printer);
-  void GenerateIsInitialized(io::Printer* printer,
-      UseMemoization useMemoization);
+  void GenerateInitializers(io::Printer* printer);
   void GenerateEqualsAndHashCode(io::Printer* printer);
   void GenerateParser(io::Printer* printer);
   void GenerateParsingConstructor(io::Printer* printer);
+  void GenerateAnyMethods(io::Printer* printer);
 
   Context* context_;
   ClassNameResolver* name_resolver_;
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
new file mode 100644
index 0000000..b3e9e98
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -0,0 +1,662 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+MessageBuilderGenerator::MessageBuilderGenerator(
+    const Descriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
+}
+
+MessageBuilderGenerator::~MessageBuilderGenerator() {}
+
+void MessageBuilderGenerator::
+Generate(io::Printer* printer) {
+  WriteMessageDocComment(printer, descriptor_);
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "public static final class Builder extends\n"
+      "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+      "      $classname$, Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_),
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+  } else {
+    printer->Print(
+      "public static final class Builder extends\n"
+      "    com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_),
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+  }
+  printer->Indent();
+
+  GenerateDescriptorMethods(printer);
+  GenerateCommonBuilderMethods(printer);
+
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer);
+    GenerateBuilderParsingMethods(printer);
+  }
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+      "private int $oneof_name$Case_ = 0;\n"
+      "private java.lang.Object $oneof_name$_;\n");
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "    get$oneof_capitalized_name$Case() {\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
+      "      $oneof_name$Case_);\n"
+      "}\n"
+      "\n"
+      "public Builder clear$oneof_capitalized_name$() {\n"
+      "  $oneof_name$Case_ = 0;\n"
+      "  $oneof_name$_ = null;\n");
+    printer->Print("  onChanged();\n");
+    printer->Print(
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForBuilder();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+                     .GenerateBuilderMembers(printer);
+  }
+
+  if (!PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "public final Builder setUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n"
+      "public final Builder mergeUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateDescriptorMethods(io::Printer* printer) {
+  if (!descriptor_->options().no_standard_descriptor_accessor()) {
+    printer->Print(
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
+      "  return $fileclass$.internal_$identifier$_descriptor;\n"
+      "}\n"
+      "\n",
+      "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+      "identifier", UniqueFileScopeIdentifier(descriptor_));
+  }
+  vector<const FieldDescriptor*> map_fields;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        IsMapEntry(field->message_type())) {
+      map_fields.push_back(field);
+    }
+  }
+  if (!map_fields.empty()) {
+    printer->Print(
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      printer->Print(
+        "case $number$:\n"
+        "  return internalGet$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
+    }
+    printer->Print(
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
+    printer->Print(
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMutableMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info =
+          context_->GetFieldGeneratorInfo(field);
+      printer->Print(
+        "case $number$:\n"
+        "  return internalGetMutable$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
+    }
+    printer->Print(
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
+  }
+  printer->Print(
+    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "    internalGetFieldAccessorTable() {\n"
+    "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+    "      .ensureFieldAccessorsInitialized(\n"
+    "          $classname$.class, $classname$.Builder.class);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+  printer->Print(
+      "// Construct using $classname$.newBuilder()\n"
+      "private Builder() {\n"
+      "  maybeForceBuilderInitialization();\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "private Builder(\n"
+    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "  super(parent);\n"
+    "  maybeForceBuilderInitialization();\n"
+    "}\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "private void maybeForceBuilderInitialization() {\n"
+    "  if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
+
+  printer->Indent();
+  printer->Indent();
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateFieldBuilderInitializationCode(printer);
+    }
+  }
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+    "  }\n"
+    "}\n");
+
+  printer->Print(
+    "public Builder clear() {\n"
+    "  super.clear();\n");
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateBuilderClearCode(printer);
+    }
+  }
+
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "$oneof_name$Case_ = 0;\n"
+      "$oneof_name$_ = null;\n",
+      "oneof_name", context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  return this;\n"
+    "}\n"
+    "\n");
+
+  printer->Print(
+    "public com.google.protobuf.Descriptors.Descriptor\n"
+    "    getDescriptorForType() {\n"
+    "  return $fileclass$.internal_$identifier$_descriptor;\n"
+    "}\n"
+    "\n",
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+  // LITE runtime implements this in GeneratedMessageLite.
+  printer->Print(
+    "public $classname$ getDefaultInstanceForType() {\n"
+    "  return $classname$.getDefaultInstance();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "public $classname$ build() {\n"
+    "  $classname$ result = buildPartial();\n"
+    "  if (!result.isInitialized()) {\n"
+    "    throw newUninitializedMessageException(result);\n"
+    "  }\n"
+    "  return result;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "public $classname$ buildPartial() {\n"
+    "  $classname$ result = new $classname$(this);\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Indent();
+
+  int totalBuilderBits = 0;
+  int totalMessageBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const ImmutableFieldGenerator& field =
+        field_generators_.get(descriptor_->field(i));
+    totalBuilderBits += field.GetNumBitsForBuilder();
+    totalMessageBits += field.GetNumBitsForMessage();
+  }
+  int totalBuilderInts = (totalBuilderBits + 31) / 32;
+  int totalMessageInts = (totalMessageBits + 31) / 32;
+
+  if (GenerateHasBits(descriptor_)) {
+    // Local vars for from and to bit fields to avoid accessing the builder and
+    // message over and over for these fields. Seems to provide a slight
+    // perforamance improvement in micro benchmark and this is also what proto1
+    // code does.
+    for (int i = 0; i < totalBuilderInts; i++) {
+      printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+    for (int i = 0; i < totalMessageInts; i++) {
+      printer->Print("int to_$bit_field_name$ = 0;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  // Output generation code for each field.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Copy the bit field results to the generated message
+    for (int i = 0; i < totalMessageInts; i++) {
+      printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
+                   "oneof_name", context_->GetOneofGeneratorInfo(
+                       descriptor_->oneof_decl(i))->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  onBuilt();\n");
+
+  printer->Print(
+    "  return result;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // -----------------------------------------------------------------
+
+  if (context_->HasGeneratedMethods(descriptor_)) {
+    printer->Print(
+      "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
+      "  if (other instanceof $classname$) {\n"
+      "    return mergeFrom(($classname$)other);\n"
+      "  } else {\n"
+      "    super.mergeFrom(other);\n"
+      "    return this;\n"
+      "  }\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+    printer->Print(
+      "public Builder mergeFrom($classname$ other) {\n"
+      // Optimization:  If other is the default instance, we know none of its
+      //   fields are set so we can skip the merge.
+      "  if (other == $classname$.getDefaultInstance()) return this;\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    printer->Indent();
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      if (!descriptor_->field(i)->containing_oneof()) {
+        field_generators_.get(
+            descriptor_->field(i)).GenerateMergingCode(printer);
+      }
+    }
+
+    // Merge oneof fields.
+    for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+      printer->Print(
+        "switch (other.get$oneof_capitalized_name$Case()) {\n",
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(
+            descriptor_->oneof_decl(i))->capitalized_name);
+      printer->Indent();
+      for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+        const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+        printer->Print(
+          "case $field_name$: {\n",
+          "field_name",
+          ToUpper(field->name()));
+        printer->Indent();
+        field_generators_.get(field).GenerateMergingCode(printer);
+        printer->Print(
+            "break;\n");
+        printer->Outdent();
+        printer->Print(
+            "}\n");
+      }
+      printer->Print(
+        "case $cap_oneof_name$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        "cap_oneof_name",
+        ToUpper(context_->GetOneofGeneratorInfo(
+            descriptor_->oneof_decl(i))->name));
+      printer->Outdent();
+      printer->Print(
+          "}\n");
+    }
+
+    printer->Outdent();
+
+    // if message type has extensions
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print(
+        "  this.mergeExtensionFields(other);\n");
+    }
+
+    if (PreserveUnknownFields(descriptor_)) {
+      printer->Print(
+        "  this.mergeUnknownFields(other.unknownFields);\n");
+    }
+
+    printer->Print(
+      "  onChanged();\n");
+
+    printer->Print(
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateBuilderParsingMethods(io::Printer* printer) {
+  printer->Print(
+    "public Builder mergeFrom(\n"
+    "    com.google.protobuf.CodedInputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  $classname$ parsedMessage = null;\n"
+    "  try {\n"
+    "    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
+    "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+    "    parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
+    "    throw e.unwrapIOException();\n"
+    "  } finally {\n"
+    "    if (parsedMessage != null) {\n"
+    "      mergeFrom(parsedMessage);\n"
+    "    }\n"
+    "  }\n"
+    "  return this;\n"
+    "}\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateIsInitialized(
+    io::Printer* printer) {
+  printer->Print(
+    "public final boolean isInitialized() {\n");
+  printer->Indent();
+
+  // Check that all required fields in this message are set.
+  // TODO(kenton):  We can optimize this when we switch to putting all the
+  //   "has" fields into a single bitfield.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+    if (field->is_required()) {
+      printer->Print(
+        "if (!has$name$()) {\n"
+        "  return false;\n"
+        "}\n",
+        "name", info->capitalized_name);
+    }
+  }
+
+  // Now check that all embedded messages are initialized.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        HasRequiredFields(field->message_type())) {
+      switch (field->label()) {
+        case FieldDescriptor::LABEL_REQUIRED:
+          printer->Print(
+            "if (!get$name$().isInitialized()) {\n"
+             "  return false;\n"
+             "}\n",
+            "type", name_resolver_->GetImmutableClassName(
+                field->message_type()),
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          if (!SupportFieldPresence(descriptor_->file()) &&
+              field->containing_oneof() != NULL) {
+            const OneofDescriptor* oneof = field->containing_oneof();
+            const OneofGeneratorInfo* oneof_info =
+                context_->GetOneofGeneratorInfo(oneof);
+            printer->Print(
+              "if ($oneof_name$Case_ == $field_number$) {\n",
+              "oneof_name", oneof_info->name,
+              "field_number", SimpleItoa(field->number()));
+          } else {
+            printer->Print(
+              "if (has$name$()) {\n",
+              "name", info->capitalized_name);
+          }
+          printer->Print(
+            "  if (!get$name$().isInitialized()) {\n"
+            "    return false;\n"
+            "  }\n"
+            "}\n",
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_REPEATED:
+          if (IsMapEntry(field->message_type())) {
+            printer->Print(
+              "for ($type$ item : get$name$().values()) {\n"
+              "  if (!item.isInitialized()) {\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", MapValueImmutableClassdName(field->message_type(),
+                                                  name_resolver_),
+              "name", info->capitalized_name);
+          } else {
+            printer->Print(
+              "for (int i = 0; i < get$name$Count(); i++) {\n"
+              "  if (!get$name$(i).isInitialized()) {\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", name_resolver_->GetImmutableClassName(
+                  field->message_type()),
+              "name", info->capitalized_name);
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "if (!extensionsAreInitialized()) {\n"
+      "  return false;\n"
+      "}\n");
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  return true;\n"
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h
new file mode 100644
index 0000000..015ea06
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.h
@@ -0,0 +1,86 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderGenerator {
+ public:
+  explicit MessageBuilderGenerator(const Descriptor* descriptor,
+                                   Context* context);
+  virtual ~MessageBuilderGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+ private:
+  void GenerateCommonBuilderMethods(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer);
+  void GenerateBuilderParsingMethods(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer);
+
+  const Descriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
new file mode 100644
index 0000000..dd429dc
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -0,0 +1,179 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
+}
+
+MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {}
+
+void MessageBuilderLiteGenerator::
+Generate(io::Printer* printer) {
+  WriteMessageDocComment(printer, descriptor_);
+  printer->Print(
+    "public static final class Builder extends\n"
+    "    com.google.protobuf.GeneratedMessageLite.$extendible$Builder<\n"
+    "      $classname$, Builder> implements\n"
+    "    $extra_interfaces$\n"
+    "    $classname$OrBuilder {\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "extra_interfaces", ExtraBuilderInterfaces(descriptor_),
+    "extendible",
+    descriptor_->extension_range_count() > 0 ? "Extendable" : "");
+  printer->Indent();
+
+  GenerateCommonBuilderMethods(printer);
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "    get$oneof_capitalized_name$Case() {\n"
+      "  return instance.get$oneof_capitalized_name$Case();\n"
+      "}\n"
+      "\n"
+      "public Builder clear$oneof_capitalized_name$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$oneof_capitalized_name$();\n"
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForBuilder();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+                     .GenerateBuilderMembers(printer);
+  }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderLiteGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+  printer->Print(
+    "// Construct using $classname$.newBuilder()\n"
+    "private Builder() {\n"
+    "  super(DEFAULT_INSTANCE);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.h b/src/google/protobuf/compiler/java/java_message_builder_lite.h
new file mode 100644
index 0000000..8597b2e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.h
@@ -0,0 +1,83 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderLiteGenerator {
+ public:
+  explicit MessageBuilderLiteGenerator(const Descriptor* descriptor,
+                                   Context* context);
+  virtual ~MessageBuilderLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+ private:
+  void GenerateCommonBuilderMethods(io::Printer* printer);
+
+  const Descriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index e681314..455516f 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -70,8 +70,7 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -157,11 +156,9 @@
   printer->Print(variables_,
     "$deprecation$$type$ get$capitalized_name$();\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
 }
 
 void ImmutableMessageFieldGenerator::
@@ -179,17 +176,15 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
       "$deprecation$public $type$ get$capitalized_name$() {\n"
-      "  return $name$_;\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
       "}\n");
 
-    if (HasNestedBuilders(descriptor_->containing_type())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(variables_,
-        "$deprecation$public $type$OrBuilder "
-        "get$capitalized_name$OrBuilder() {\n"
-        "  return $name$_;\n"
-        "}\n");
-    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$OrBuilder "
+      "get$capitalized_name$OrBuilder() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
   } else {
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -202,14 +197,12 @@
       "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
       "}\n");
 
-    if (HasNestedBuilders(descriptor_->containing_type())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(variables_,
-        "$deprecation$public $type$OrBuilder "
-        "get$capitalized_name$OrBuilder() {\n"
-        "  return get$capitalized_name$();\n"
-        "}\n");
-    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$OrBuilder "
+      "get$capitalized_name$OrBuilder() {\n"
+      "  return get$capitalized_name$();\n"
+      "}\n");
   }
 }
 
@@ -217,19 +210,15 @@
     io::Printer* printer,
     const char* regular_case,
     const char* nested_builder_case) const {
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-     printer->Print(variables_, "if ($name$Builder_ == null) {\n");
-     printer->Indent();
-     printer->Print(variables_, regular_case);
-     printer->Outdent();
-     printer->Print("} else {\n");
-     printer->Indent();
-     printer->Print(variables_, nested_builder_case);
-     printer->Outdent();
-     printer->Print("}\n");
-   } else {
-     printer->Print(variables_, regular_case);
-   }
+  printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+  printer->Indent();
+  printer->Print(variables_, regular_case);
+  printer->Outdent();
+  printer->Print("} else {\n");
+  printer->Indent();
+  printer->Print(variables_, nested_builder_case);
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -257,23 +246,15 @@
 
   bool support_field_presence = SupportFieldPresence(descriptor_->file());
 
-  if (support_field_presence) {
-    printer->Print(variables_,
-      // Used when the builder is null.
-      "private $type$ $name$_ = $type$.getDefaultInstance();\n");
-  } else {
-    printer->Print(variables_,
-      "private $type$ $name$_ = null;\n");
-  }
+  printer->Print(variables_,
+    "private $type$ $name$_ = null;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
+  printer->Print(variables_,
       // If this builder is non-null, it is used and the other fields are
       // ignored.
       "private com.google.protobuf.SingleFieldBuilder<\n"
       "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
       "\n");
-  }
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -296,13 +277,8 @@
   WriteFieldDocComment(printer, descriptor_);
   PrintNestedBuilderFunction(printer,
     "$deprecation$public $type$ get$capitalized_name$()",
-
-    support_field_presence
-        ?  "return $name$_;\n"
-        : "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n",
-
+    "return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n",
     "return $name$Builder_.getMessage();\n",
-
     NULL);
 
   // Field.Builder setField(Field value)
@@ -342,6 +318,7 @@
 
     support_field_presence
         ? "if ($get_has_field_bit_builder$ &&\n"
+          "    $name$_ != null &&\n"
           "    $name$_ != $type$.getDefaultInstance()) {\n"
           "  $name$_ =\n"
           "    $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
@@ -367,11 +344,8 @@
   PrintNestedBuilderFunction(printer,
     "$deprecation$public Builder clear$capitalized_name$()",
 
-    support_field_presence
-        ? "$name$_ = $type$.getDefaultInstance();\n"
-          "$on_changed$\n"
-        : "$name$_ = null;\n"
-          "$on_changed$\n",
+    "$name$_ = null;\n"
+    "$on_changed$\n",
 
     support_field_presence
         ? "$name$Builder_.clear();\n"
@@ -381,47 +355,38 @@
     "$clear_has_field_bit_builder$\n"
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  $set_has_field_bit_builder$\n"
-      "  $on_changed$\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n");
-    if (support_field_presence) {
-      printer->Print(variables_,
-        "    return $name$_;\n");
-    } else {
-      printer->Print(variables_,
-        "    return $name$_ == null ?\n"
-        "        $type$.getDefaultInstance() : $name$_;\n");
-    }
-    printer->Print(variables_,
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            get$capitalized_name$(),\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  $set_has_field_bit_builder$\n"
+    "  $on_changed$\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    return $name$_ == null ?\n"
+    "        $type$.getDefaultInstance() : $name$_;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            get$capitalized_name$(),\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void ImmutableMessageFieldGenerator::
@@ -434,17 +399,13 @@
 
 
 void ImmutableMessageFieldGenerator::
-GenerateInitializationCode(io::Printer* printer) const {
-  if (SupportFieldPresence(descriptor_->file())) {
-    printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n");
-  }
-}
+GenerateInitializationCode(io::Printer* printer) const {}
 
 void ImmutableMessageFieldGenerator::
 GenerateBuilderClearCode(io::Printer* printer) const {
   if (SupportFieldPresence(descriptor_->file())) {
     PrintNestedBuilderCondition(printer,
-      "$name$_ = $type$.getDefaultInstance();\n",
+      "$name$_ = null;\n",
 
       "$name$Builder_.clear();\n");
     printer->Print(variables_, "$clear_has_field_bit_builder$\n");
@@ -490,11 +451,11 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$name$_ = input.readGroup($number$, $type$.PARSER,\n"
+      "$name$_ = input.readGroup($number$, $type$.parser(),\n"
       "    extensionRegistry);\n");
   } else {
     printer->Print(variables_,
-      "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+      "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n");
   }
 
   printer->Print(variables_,
@@ -514,7 +475,7 @@
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
-    "  output.write$group_or_message$($number$, $name$_);\n"
+    "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
     "}\n");
 }
 
@@ -523,7 +484,7 @@
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .compute$group_or_message$Size($number$, $name$_);\n"
+    "    .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
     "}\n");
 }
 
@@ -581,16 +542,14 @@
     "  return $type$.getDefaultInstance();\n"
     "}\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($has_oneof_case_message$) {\n"
-      "     return ($type$) $oneof_name$_;\n"
-      "  }\n"
-      "  return $type$.getDefaultInstance();\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "     return ($type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
 }
 
 void ImmutableMessageOneofFieldGenerator::
@@ -598,14 +557,12 @@
   // When using nested-builders, the code initially works just like the
   // non-nested builder case. It only creates a nested builder lazily on
   // demand and then forever delegates to it after creation.
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -707,44 +664,43 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n"
-      "    if ($has_oneof_case_message$) {\n"
-      "      return ($type$) $oneof_name$_;\n"
-      "    }\n"
-      "    return $type$.getDefaultInstance();\n"
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    if (!($has_oneof_case_message$)) {\n"
-      "      $oneof_name$_ = $type$.getDefaultInstance();\n"
-      "    }\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            ($type$) $oneof_name$_,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $oneof_name$_ = null;\n"
-      "  }\n"
-      "  $set_oneof_case_message$;\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    if ($has_oneof_case_message$) {\n"
+    "      return ($type$) $oneof_name$_;\n"
+    "    }\n"
+    "    return $type$.getDefaultInstance();\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    if (!($has_oneof_case_message$)) {\n"
+    "      $oneof_name$_ = $type$.getDefaultInstance();\n"
+    "    }\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            ($type$) $oneof_name$_,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "  $on_changed$;\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void ImmutableMessageOneofFieldGenerator::
@@ -779,11 +735,12 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n"
+      "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n"
       "    extensionRegistry);\n");
   } else {
     printer->Print(variables_,
-      "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+      "$oneof_name$_ =\n"
+      "    input.readMessage($type$.parser(), extensionRegistry);\n");
   }
 
   printer->Print(variables_,
@@ -854,16 +811,15 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$int get$capitalized_name$Count();\n");
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
-      "    get$capitalized_name$OrBuilderList();\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index);\n");
-  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
+    "    get$capitalized_name$OrBuilderList();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index);\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::
@@ -905,19 +861,15 @@
     io::Printer* printer,
     const char* regular_case,
     const char* nested_builder_case) const {
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-     printer->Print(variables_, "if ($name$Builder_ == null) {\n");
-     printer->Indent();
-     printer->Print(variables_, regular_case);
-     printer->Outdent();
-     printer->Print("} else {\n");
-     printer->Indent();
-     printer->Print(variables_, nested_builder_case);
-     printer->Outdent();
-     printer->Print("}\n");
-   } else {
-     printer->Print(variables_, regular_case);
-   }
+  printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+  printer->Indent();
+  printer->Print(variables_, regular_case);
+  printer->Outdent();
+  printer->Print("} else {\n");
+  printer->Indent();
+  printer->Print(variables_, nested_builder_case);
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -965,14 +917,12 @@
     "}\n"
     "\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // repeated field of type "Field" called "RepeatedField".
@@ -1139,70 +1089,68 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index) {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    return $name$_.get(index);"
-      "  } else {\n"
-      "    return $name$Builder_.getMessageOrBuilder(index);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    return $name$_.get(index);"
+    "  } else {\n"
+    "    return $name$Builder_.getMessageOrBuilder(index);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
-      "     get$capitalized_name$OrBuilderList() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilderList();\n"
-      "  } else {\n"
-      "    return java.util.Collections.unmodifiableList($name$_);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "     get$capitalized_name$OrBuilderList() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilderList();\n"
+    "  } else {\n"
+    "    return java.util.Collections.unmodifiableList($name$_);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      index, $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<$type$.Builder> \n"
-      "     get$capitalized_name$BuilderList() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
-      "}\n"
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            $get_mutable_bit_builder$,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      index, $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$.Builder> \n"
+    "     get$capitalized_name$BuilderList() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
+    "}\n"
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            $get_mutable_bit_builder$,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::
@@ -1284,11 +1232,11 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$name$_.add(input.readGroup($number$, $type$.PARSER,\n"
+      "$name$_.add(input.readGroup($number$, $type$.parser(),\n"
       "    extensionRegistry));\n");
   } else {
     printer->Print(variables_,
-      "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
+      "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
new file mode 100644
index 0000000..1428181
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -0,0 +1,941 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
+                         const FieldGeneratorInfo* info,
+                         ClassNameResolver* name_resolver,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->message_type());
+  (*variables)["group_or_message"] =
+    (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ?
+    "Group" : "Message";
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != null";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableMessageFieldLiteGenerator::
+ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex,
+                      Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+    SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  // TODO(jonp): In the future, consider having a method specific to the
+  // interface so that builders can choose dynamically to either return a
+  // message or a nested builder, so that asking for the interface doesn't
+  // cause a message to ever be built.
+  if (SupportFieldPresence(descriptor_->file()) ||
+      descriptor_->containing_oneof() == NULL) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$ get$capitalized_name$() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $name$_ != null;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$ get$capitalized_name$() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
+  }
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $name$_ = value;\n"
+    "  $set_has_field_bit_message$\n"
+    "  }\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $name$_ = builderForValue.build();\n"
+    "  $set_has_field_bit_message$\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($name$_ != null &&\n"
+    "      $name$_ != $type$.getDefaultInstance()) {\n"
+    "    $name$_ =\n"
+    "      $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+    "  } else {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "  $set_has_field_bit_message$\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {"
+    "  $name$_ = null;\n"
+    "  $clear_has_field_bit_message$\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "  }\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "get$capitalized_name$FieldBuilder();\n");
+  }
+}
+
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = visitor.visitMessage($name$_, other.$name$_);\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  // TODO(dweis): Update this code to avoid the builder allocation and instead
+  // only allocate a submessage that isn't made immutable. Rely on the top
+  // message calling makeImmutable once done to actually traverse the tree and
+  // finalize state. This will avoid:
+  // - transitive builder allocations
+  // - the extra transitive iteration for streamed fields
+  // - reallocations for copying repeated fields
+  printer->Print(variables_,
+      "$type$.Builder subBuilder = null;\n"
+      "if ($is_field_present_message$) {\n"
+      "  subBuilder = $name$_.toBuilder();\n"
+      "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$name$_ = input.readGroup($number$, $type$.parser(),\n"
+        "    extensionRegistry);\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n");
+    }
+
+  printer->Print(variables_,
+    "if (subBuilder != null) {\n"
+    "  subBuilder.mergeFrom($name$_);\n"
+    "  $name$_ = subBuilder.buildPartial();\n"
+    "}\n"
+    "$set_has_field_bit_message$\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for messages.
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldLiteGenerator::
+ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableMessageOneofFieldLiteGenerator::
+~ImmutableMessageOneofFieldLiteGenerator() {}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "     return ($type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $oneof_name$_ = value;\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $oneof_name$_ = builderForValue.build();\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($has_oneof_case_message$ &&\n"
+    "      $oneof_name$_ != $type$.getDefaultInstance()) {\n"
+    "    $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n"
+    "        .mergeFrom(value).buildPartial();\n"
+    "  } else {\n"
+    "    $oneof_name$_ = value;\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    // boolean hasField()
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$oneof_name$_ = visitor.visitOneofMessage(\n"
+    "    $has_oneof_case_message$,\n"
+    "    $oneof_name$_,\n"
+    "    other.$oneof_name$_);\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$type$.Builder subBuilder = null;\n"
+    "if ($has_oneof_case_message$) {\n"
+    "  subBuilder = (($type$) $oneof_name$_).toBuilder();\n"
+    "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n"
+        "    extensionRegistry);\n");
+    } else {
+      printer->Print(variables_,
+        "$oneof_name$_ =\n"
+        "     input.readMessage($type$.parser(), extensionRegistry);\n");
+    }
+
+  printer->Print(variables_,
+    "if (subBuilder != null) {\n"
+    "  subBuilder.mergeFrom(($type$) $oneof_name$_);\n"
+    "  $oneof_name$_ = subBuilder.buildPartial();\n"
+    "}\n");
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableMessageFieldLiteGenerator::
+RepeatedImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex,
+                                       int builderBitIndex,
+                                       Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver())  {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      name_resolver_, &variables_);
+}
+
+RepeatedImmutableMessageFieldLiteGenerator::
+~RepeatedImmutableMessageFieldLiteGenerator() {}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  // TODO(jonp): In the future, consider having methods specific to the
+  // interface so that builders can choose dynamically to either return a
+  // message or a nested builder, so that asking for the interface doesn't
+  // cause a message to ever be built.
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> \n"
+    "    get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.ProtobufList<$type$> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "    get$capitalized_name$OrBuilderList() {\n"
+    "  return $name$_;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ =\n"
+    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "   }\n"
+    "}\n"
+    "\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, builderForValue.build());\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, value);\n"
+    "}\n");
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(builderForValue.build());\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, builderForValue.build());\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyProtobufList();\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void remove$capitalized_name$(int index) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.remove(index);\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // repeated field of type "Field" called "RepeatedField".
+
+  // List<Field> getRepeatedFieldList()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}");
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+    "  copyOnWrite();\n"
+    "  instance.remove$capitalized_name$(index);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  printer->Print(variables_,
+    "get$capitalized_name$FieldBuilder();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$name$_= visitor.visitList($name$_, other.$name$_);\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$name$_.add(input.readGroup($number$, $type$.parser(),\n"
+        "    extensionRegistry));\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_.add(\n"
+        "    input.readMessage($type$.parser(), extensionRegistry));\n");
+    }
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.write$group_or_message$($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
new file mode 100644
index 0000000..6132154
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -0,0 +1,157 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMessageFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator);
+};
+
+class ImmutableMessageOneofFieldLiteGenerator
+    : public ImmutableMessageFieldLiteGenerator {
+ public:
+  ImmutableMessageOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMessageOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableMessageFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableMessageFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
new file mode 100644
index 0000000..d4d2593
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -0,0 +1,1094 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+// ===================================================================
+ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+  : MessageGenerator(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
+}
+
+ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
+
+void ImmutableMessageLiteGenerator::GenerateStaticVariables(
+    io::Printer* printer, int* bytecode_estimate) {
+  // Generate static members for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+        .GenerateStaticVariables(printer, bytecode_estimate);
+  }
+}
+
+int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers(
+    io::Printer* printer) {
+  int bytecode_estimate = 0;
+  // Generate static member initializers for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    bytecode_estimate +=
+        ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
+  }
+  return bytecode_estimate;
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "public interface $classname$OrBuilder extends \n"
+      "    $extra_interfaces$\n"
+      "     com.google.protobuf.GeneratedMessageLite.\n"
+      "          ExtendableMessageOrBuilder<\n"
+      "              $classname$, $classname$.Builder> {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.MessageLiteOrBuilder {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
+  }
+
+  printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      printer->Print("\n");
+      field_generators_.get(descriptor_->field(i))
+                       .GenerateInterfaceMembers(printer);
+    }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+      printer->Print(
+          "\n"
+          "public $classname$.$oneof_capitalized_name$Case "
+          "get$oneof_capitalized_name$Case();\n",
+          "oneof_capitalized_name",
+          context_->GetOneofGeneratorInfo(
+              descriptor_->oneof_decl(i))->capitalized_name,
+          "classname",
+          context_->GetNameResolver()->GetImmutableClassName(descriptor_));
+    }
+  printer->Outdent();
+
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
+  bool is_own_file =
+    descriptor_->containing_type() == NULL &&
+    MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+
+  map<string, string> variables;
+  variables["static"] = is_own_file ? " " : " static ";
+  variables["classname"] = descriptor_->name();
+  variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+
+  WriteMessageDocComment(printer, descriptor_);
+
+  // The builder_type stores the super type name of the nested Builder class.
+  string builder_type;
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
+      "      $classname$, $classname$.Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
+    builder_type = strings::Substitute(
+        "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>",
+        name_resolver_->GetImmutableClassName(descriptor_));
+  } else {
+    printer->Print(variables,
+        "public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite<\n"
+        "        $classname$, $classname$.Builder> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+
+    builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
+  }
+  printer->Indent();
+
+
+  GenerateConstructor(printer);
+
+  // Nested types
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumLiteGenerator(descriptor_->enum_type(i), true, context_)
+        .Generate(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // Don't generate Java classes for map entry messages.
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageLiteGenerator messageGenerator(
+        descriptor_->nested_type(i), context_);
+    messageGenerator.GenerateInterface(printer);
+    messageGenerator.Generate(printer);
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForMessage();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+      "private int $oneof_name$Case_ = 0;\n"
+      "private java.lang.Object $oneof_name$_;\n");
+    // OneofCase enum
+    printer->Print(vars,
+      "public enum $oneof_capitalized_name$Case\n"
+      "    implements com.google.protobuf.Internal.EnumLite {\n");
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "$field_name$($field_number$),\n",
+        "field_name",
+        ToUpper(field->name()),
+        "field_number",
+        SimpleItoa(field->number()));
+    }
+    printer->Print(
+      "$cap_oneof_name$_NOT_SET(0);\n",
+      "cap_oneof_name",
+      ToUpper(vars["oneof_name"]));
+    printer->Print(vars,
+      "private final int value;\n"
+      "private $oneof_capitalized_name$Case(int value) {\n"
+      "  this.value = value;\n"
+      "}\n");
+    printer->Print(vars,
+      "/**\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
+      "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
+      "  switch (value) {\n");
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "    case $field_number$: return $field_name$;\n",
+        "field_number",
+        SimpleItoa(field->number()),
+        "field_name",
+        ToUpper(field->name()));
+    }
+    printer->Print(
+      "    case 0: return $cap_oneof_name$_NOT_SET;\n"
+      "    default: return null;\n"
+      "  }\n"
+      "}\n"
+      "public int getNumber() {\n"
+      "  return this.value;\n"
+      "}\n",
+      "cap_oneof_name", ToUpper(vars["oneof_name"]));
+    printer->Outdent();
+    printer->Print("};\n\n");
+    // oneofCase()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "get$oneof_capitalized_name$Case() {\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
+      "      $oneof_name$Case_);\n"
+      "}\n"
+      "\n"
+      "private void clear$oneof_capitalized_name$() {\n"
+      "  $oneof_name$Case_ = 0;\n"
+      "  $oneof_name$_ = null;\n"
+      "}\n"
+      "\n");
+  }
+
+  // Fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("public static final int $constant_name$ = $number$;\n",
+      "constant_name", FieldConstantName(descriptor_->field(i)),
+      "number", SimpleItoa(descriptor_->field(i)->number()));
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  GenerateMessageSerializationMethods(printer);
+
+  GenerateParseFromMethods(printer);
+  GenerateBuilder(printer);
+
+  if (HasRequiredFields(descriptor_)) {
+    // Memoizes whether the protocol buffer is fully initialized (has all
+    // required fields). -1 means not yet computed. 0 means false and 1 means
+    // true.
+    printer->Print(
+      "private byte memoizedIsInitialized = -1;\n");
+  }
+
+  printer->Print(
+    "protected final Object dynamicMethod(\n"
+    "    com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n"
+    "    Object arg0, Object arg1) {\n"
+    "  switch (method) {\n"
+    "    case NEW_MUTABLE_INSTANCE: {\n"
+    "      return new $classname$();\n"
+    "    }\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Indent();
+  printer->Indent();
+
+  printer->Print(
+    "case IS_INITIALIZED: {\n");
+  printer->Indent();
+  GenerateDynamicMethodIsInitialized(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case MAKE_IMMUTABLE: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodMakeImmutable(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case NEW_BUILDER: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodNewBuilder(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case VISIT: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodVisit(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case MERGE_FROM_STREAM: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodMergeFromStream(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case GET_DEFAULT_INSTANCE: {\n"
+    "  return DEFAULT_INSTANCE;\n"
+    "}\n"
+    "case GET_PARSER: {\n"
+    // Generally one would use the lazy initialization holder pattern for
+    // manipulating static fields but that has exceptional cost on Android as
+    // it will generate an extra class for every message. Instead, use the
+    // double-check locking pattern which works just as well.
+    "  if (PARSER == null) {"
+    "    synchronized ($classname$.class) {\n"
+    "      if (PARSER == null) {\n"
+    "        PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n"
+    "      }\n"
+    "    }\n"
+    "  }\n"
+    "  return PARSER;\n"
+    "}\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+    "  }\n"
+    "  throw new UnsupportedOperationException();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+
+  // Carefully initialize the default instance in such a way that it doesn't
+  // conflict with other initialization.
+  printer->Print(
+    "private static final $classname$ DEFAULT_INSTANCE;\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "static {\n"
+    "  DEFAULT_INSTANCE = new $classname$();\n"
+    "  DEFAULT_INSTANCE.makeImmutable();\n"
+    "}\n"
+    "\n",
+    "classname", descriptor_->name());
+  printer->Print(
+      "public static $classname$ getDefaultInstance() {\n"
+      "  return DEFAULT_INSTANCE;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  GenerateParser(printer);
+
+  // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+  // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
+  // the outer class's FileDescriptor.
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
+        .Generate(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+      SortFieldsByNumber(descriptor_));
+
+  vector<const Descriptor::ExtensionRange*> sorted_extensions;
+  for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+    sorted_extensions.push_back(descriptor_->extension_range(i));
+  }
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeOrdering());
+
+  printer->Print(
+    "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
+    "                    throws java.io.IOException {\n");
+  printer->Indent();
+  if (HasPackedFields(descriptor_)) {
+    // writeTo(CodedOutputStream output) might be invoked without
+    // getSerializedSize() ever being called, but we need the memoized
+    // sizes in case this message has packed fields. Rather than emit checks for
+    // each packed field, just call getSerializedSize() up front.
+    // In most cases, getSerializedSize() will have already been called anyway
+    // by one of the wrapper writeTo() methods, making this call cheap.
+    printer->Print(
+      "getSerializedSize();\n");
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessageLite\n"
+        "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+        "    .ExtensionWriter extensionWriter =\n"
+        "      newMessageSetExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    } else {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessageLite\n"
+        "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+        "    .ExtensionWriter extensionWriter =\n"
+        "      newExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    }
+  }
+
+  // Merge the fields and the extension ranges, both sorted by field number.
+  for (int i = 0, j = 0;
+       i < descriptor_->field_count() || j < sorted_extensions.size();
+       ) {
+    if (i == descriptor_->field_count()) {
+      GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+    } else if (j == sorted_extensions.size()) {
+      GenerateSerializeOneField(printer, sorted_fields[i++]);
+    } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) {
+      GenerateSerializeOneField(printer, sorted_fields[i++]);
+    } else {
+      GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+    }
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "unknownFields.writeTo(output);\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n"
+    "public int getSerializedSize() {\n"
+    "  int size = memoizedSerializedSize;\n"
+    "  if (size != -1) return size;\n"
+    "\n"
+    "  size = 0;\n");
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "size += extensionsSerializedSizeAsMessageSet();\n");
+    } else {
+      printer->Print(
+        "size += extensionsSerializedSize();\n");
+    }
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "size += unknownFields.getSerializedSize();\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  memoizedSerializedSize = size;\n"
+    "  return size;\n"
+    "}\n"
+    "\n");
+}
+
+void ImmutableMessageLiteGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+  // Note:  These are separate from GenerateMessageSerializationMethods()
+  //   because they need to be generated even for messages that are optimized
+  //   for code size.
+  printer->Print(
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.ByteString data)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.ByteString data,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(byte[] data)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    byte[] data,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    java.io.InputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n"
+    "}\n"
+    "public static $classname$ parseDelimitedFrom(\n"
+    "    java.io.InputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.CodedInputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.CodedInputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneField(
+    io::Printer* printer, const FieldDescriptor* field) {
+  field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneExtensionRange(
+    io::Printer* printer, const Descriptor::ExtensionRange* range) {
+  printer->Print(
+    "extensionWriter.writeUntil($end$, output);\n",
+    "end", SimpleItoa(range->end));
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) {
+  printer->Print(
+    "public static Builder newBuilder() {\n"
+    "  return DEFAULT_INSTANCE.toBuilder();\n"
+    "}\n"
+    "public static Builder newBuilder($classname$ prototype) {\n"
+    "  return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  MessageBuilderLiteGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized(
+    io::Printer* printer) {
+  // Returns null for false, DEFAULT_INSTANCE for true.
+  if (!HasRequiredFields(descriptor_)) {
+    printer->Print("return DEFAULT_INSTANCE;\n");
+    return;
+  }
+
+  // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+  printer->Print(
+    "byte isInitialized = memoizedIsInitialized;\n"
+    "if (isInitialized == 1) return DEFAULT_INSTANCE;\n"
+    "if (isInitialized == 0) return null;\n"
+    "\n"
+    "boolean shouldMemoize = ((Boolean) arg0).booleanValue();\n");
+
+  // Check that all required fields in this message are set.
+  // TODO(kenton):  We can optimize this when we switch to putting all the
+  //   "has" fields into a single bitfield.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+    if (field->is_required()) {
+      printer->Print(
+        "if (!has$name$()) {\n"
+        "  if (shouldMemoize) {\n"
+        "    memoizedIsInitialized = 0;\n"
+        "  }\n"
+        "  return null;\n"
+        "}\n",
+        "name", info->capitalized_name);
+    }
+  }
+
+  // Now check that all embedded messages are initialized.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        HasRequiredFields(field->message_type())) {
+      switch (field->label()) {
+        case FieldDescriptor::LABEL_REQUIRED:
+          printer->Print(
+            "if (!get$name$().isInitialized()) {\n"
+            "  if (shouldMemoize) {\n"
+            "    memoizedIsInitialized = 0;\n"
+            "  }\n"
+            "  return null;\n"
+            "}\n",
+            "type", name_resolver_->GetImmutableClassName(
+                field->message_type()),
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          if (!SupportFieldPresence(descriptor_->file()) &&
+              field->containing_oneof() != NULL) {
+            const OneofDescriptor* oneof = field->containing_oneof();
+            const OneofGeneratorInfo* oneof_info =
+                context_->GetOneofGeneratorInfo(oneof);
+            printer->Print(
+              "if ($oneof_name$Case_ == $field_number$) {\n",
+              "oneof_name", oneof_info->name,
+              "field_number", SimpleItoa(field->number()));
+          } else {
+            printer->Print(
+              "if (has$name$()) {\n",
+              "name", info->capitalized_name);
+          }
+          printer->Print(
+            "  if (!get$name$().isInitialized()) {\n"
+            "    if (shouldMemoize) {\n"
+            "      memoizedIsInitialized = 0;\n"
+            "    }\n"
+            "    return null;\n"
+            "  }\n"
+            "}\n",
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_REPEATED:
+          if (IsMapEntry(field->message_type())) {
+            printer->Print(
+              "for ($type$ item : get$name$().values()) {\n"
+              "  if (!item.isInitialized()) {\n"
+              "    if (shouldMemoize) {\n"
+              "      memoizedIsInitialized = 0;\n"
+              "    }\n"
+              "    return null;\n"
+              "  }\n"
+              "}\n",
+              "type", MapValueImmutableClassdName(field->message_type(),
+                                                  name_resolver_),
+              "name", info->capitalized_name);
+          } else {
+            printer->Print(
+              "for (int i = 0; i < get$name$Count(); i++) {\n"
+              "  if (!get$name$(i).isInitialized()) {\n"
+              "    if (shouldMemoize) {\n"
+              "      memoizedIsInitialized = 0;\n"
+              "    }\n"
+              "    return null;\n"
+              "  }\n"
+              "}\n",
+              "type", name_resolver_->GetImmutableClassName(
+                  field->message_type()),
+              "name", info->capitalized_name);
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "if (!extensionsAreInitialized()) {\n"
+      "  if (shouldMemoize) {\n"
+      "    memoizedIsInitialized = 0;\n"
+      "  }\n"
+      "  return null;\n"
+      "}\n");
+  }
+
+  printer->Print(
+    "if (shouldMemoize) memoizedIsInitialized = 1;\n");
+
+  printer->Print(
+    "return DEFAULT_INSTANCE;\n"
+    "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable(
+    io::Printer* printer) {
+
+  // Output generation code for each field.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateDynamicMethodMakeImmutableCode(printer);
+  }
+
+  printer->Print(
+    "return null;\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder(
+    io::Printer* printer) {
+  printer->Print(
+    "return new Builder();\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodVisit(
+    io::Printer* printer) {
+  printer->Print(
+    "Visitor visitor = (Visitor) arg0;\n"
+    "$classname$ other = ($classname$) arg1;\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(
+          descriptor_->field(i)).GenerateVisitCode(printer);
+    }
+  }
+
+  // Merge oneof fields.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+    printer->Print(
+      "switch (other.get$oneof_capitalized_name$Case()) {\n",
+      "oneof_capitalized_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->capitalized_name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_name$: {\n",
+        "field_name",
+        ToUpper(field->name()));
+      printer->Indent();
+      field_generators_.get(field).GenerateVisitCode(printer);
+      printer->Print(
+          "break;\n");
+      printer->Outdent();
+      printer->Print(
+          "}\n");
+    }
+    printer->Print(
+      "case $cap_oneof_name$_NOT_SET: {\n"
+      "  visitor.visitOneofNotSet($oneof_name$Case_ != 0);\n"
+      "  break;\n"
+      "}\n",
+      "cap_oneof_name",
+      ToUpper(context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name),
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Outdent();
+    printer->Print(
+      "}\n");
+  }
+
+  printer->Print(
+    "if (visitor == com.google.protobuf.GeneratedMessageLite.MergeFromVisitor\n"
+    "    .INSTANCE) {\n");
+  printer->Indent();
+  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+    const OneofDescriptor* field = descriptor_->oneof_decl(i);
+    printer->Print(
+      "if (other.$oneof_name$Case_ != 0) {\n"
+      "  $oneof_name$Case_ = other.$oneof_name$Case_;\n"
+      "}\n",
+      "oneof_name", context_->GetOneofGeneratorInfo(field)->name);
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForMessage();
+    }
+    int totalInts = (totalBits + 31) / 32;
+
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print(
+        "$bit_field_name$ |= other.$bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+  printer->Outdent();
+  printer->Print(
+    "}\n");
+
+
+  printer->Print(
+    "return this;\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream(
+    io::Printer* printer) {
+  printer->Print(
+      "com.google.protobuf.CodedInputStream input =\n"
+      "    (com.google.protobuf.CodedInputStream) arg0;\n"
+      "com.google.protobuf.ExtensionRegistryLite extensionRegistry =\n"
+      "    (com.google.protobuf.ExtensionRegistryLite) arg1;\n"
+      "try {\n");
+  printer->Indent();
+
+  printer->Print(
+    "boolean done = false;\n"
+    "while (!done) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "int tag = input.readTag();\n"
+    "switch (tag) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "case 0:\n"          // zero signals EOF / limit reached
+    "  done = true;\n"
+    "  break;\n");
+
+  if (PreserveUnknownFields(descriptor_)) {
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print(
+        "default: {\n"
+        "  if (!parseUnknownField(getDefaultInstanceForType(),\n"
+        "                         input, extensionRegistry, tag)) {\n"
+        "    done = true;\n"  // it's an endgroup tag
+        "  }\n"
+        "  break;\n"
+        "}\n");
+    } else {
+      printer->Print(
+        "default: {\n"
+        "  if (!parseUnknownField(tag, input)) {\n"
+        "    done = true;\n"  // it's an endgroup tag
+        "  }\n"
+        "  break;\n"
+        "}\n");
+    }
+  } else {
+    printer->Print(
+      "default: {\n"
+      "  if (!input.skipField(tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
+  }
+
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+      SortFieldsByNumber(descriptor_));
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    uint32 tag = WireFormatLite::MakeTag(field->number(),
+      WireFormat::WireTypeForFieldType(field->type()));
+
+    printer->Print(
+      "case $tag$: {\n",
+      "tag", SimpleItoa(tag));
+    printer->Indent();
+
+    field_generators_.get(field).GenerateParsingCode(printer);
+
+    printer->Outdent();
+    printer->Print(
+      "  break;\n"
+      "}\n");
+
+    if (field->is_packable()) {
+      // To make packed = true wire compatible, we generate parsing code from a
+      // packed version of this field regardless of field->options().packed().
+      uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+      printer->Print(
+        "case $tag$: {\n",
+        "tag", SimpleItoa(packed_tag));
+      printer->Indent();
+
+      field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
+
+      printer->Outdent();
+      printer->Print(
+        "  break;\n"
+        "}\n");
+    }
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "  }\n"     // switch (tag)
+      "}\n");     // while (!done)
+
+  printer->Outdent();
+  printer->Print(
+      "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+      "  throw new RuntimeException(e.setUnfinishedMessage(this));\n"
+      "} catch (java.io.IOException e) {\n"
+      "  throw new RuntimeException(\n"
+      "      new com.google.protobuf.InvalidProtocolBufferException(\n"
+      "          e.getMessage()).setUnfinishedMessage(this));\n"
+      "} finally {\n");
+  printer->Indent();
+
+  printer->Outdent();
+  printer->Print(
+      "}\n");     // finally
+}
+
+// ===================================================================
+
+namespace {
+bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
+  if (field->is_repeated()) {
+    return false;
+  }
+  if (SupportFieldPresence(field->file())) {
+    return true;
+  }
+  return GetJavaType(field) == JAVATYPE_MESSAGE &&
+      field->containing_oneof() == NULL;
+}
+}  // namespace
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateExtensionRegistrationCode(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
+      .GenerateRegistrationCode(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+      .GenerateExtensionRegistrationCode(printer);
+  }
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::
+GenerateConstructor(io::Printer* printer) {
+  printer->Print(
+      "private $classname$() {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+
+  // Initialize all fields to default.
+  GenerateInitializers(printer);
+
+  printer->Outdent();
+  printer->Print(
+      "}\n");
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) {
+  printer->Print(
+      "private static volatile com.google.protobuf.Parser<$classname$> PARSER;\n"
+      "\n"
+      "public static com.google.protobuf.Parser<$classname$> parser() {\n"
+      "  return DEFAULT_INSTANCE.getParserForType();\n"
+      "}\n",
+      "classname", descriptor_->name());
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitializationCode(printer);
+    }
+  }
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
new file mode 100644
index 0000000..292c1c5
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -0,0 +1,93 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageLiteGenerator : public MessageGenerator {
+ public:
+  explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor,
+                                     Context* context);
+  virtual ~ImmutableMessageLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+  virtual void GenerateInterface(io::Printer* printer);
+  virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate);
+  virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+
+ private:
+
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateParseFromMethods(io::Printer* printer);
+  void GenerateSerializeOneField(io::Printer* printer,
+                                 const FieldDescriptor* field);
+  void GenerateSerializeOneExtensionRange(
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+  void GenerateBuilder(io::Printer* printer);
+  void GenerateDynamicMethodIsInitialized(io::Printer* printer);
+  void GenerateDynamicMethodMakeImmutable(io::Printer* printer);
+  void GenerateDynamicMethodVisit(io::Printer* printer);
+  void GenerateDynamicMethodMergeFromStream(io::Printer* printer);
+  void GenerateDynamicMethodNewBuilder(io::Printer* printer);
+  void GenerateInitializers(io::Printer* printer);
+  void GenerateEqualsAndHashCode(io::Printer* printer);
+  void GenerateParser(io::Printer* printer);
+  void GenerateConstructor(io::Printer* printer);
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index 0c363f9..bffe4f1 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -259,6 +259,13 @@
       descriptor->file(), true);
 }
 
+string ClassNameResolver::GetJavaImmutableClassName(
+    const EnumDescriptor* descriptor) {
+  return GetJavaClassFullName(
+      ClassNameWithoutPackage(descriptor, true),
+      descriptor->file(), true);
+}
+
 
 }  // namespace java
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index ab60b0a..570d8d8 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -98,6 +98,7 @@
   // For example:
   //   com.package.OuterClass$OuterMessage$InnerMessage
   string GetJavaImmutableClassName(const Descriptor* descriptor);
+  string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
  private:
   // Get the full name of a Java class by prepending the Java package name
   // or outer class name.
diff --git a/src/google/protobuf/compiler/java/java_names.h b/src/google/protobuf/compiler/java/java_names.h
new file mode 100644
index 0000000..0d61433
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_names.h
@@ -0,0 +1,87 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Provides a mechanism for mapping a descriptor to the
+// fully-qualified name of the corresponding Java class.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FileDescriptor;
+class ServiceDescriptor;
+
+namespace compiler {
+namespace java {
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+string ClassName(const Descriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+string ClassName(const EnumDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+string ClassName(const FileDescriptor* descriptor);
+
+// Requires:
+//   descriptor != NULL
+//
+// Returns:
+//   The fully-qualified Java class name.
+string ClassName(const ServiceDescriptor* descriptor);
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
index c4d6995..3e4910c 100644
--- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
@@ -35,15 +35,19 @@
 //   worth.
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/java/java_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/printer.h>
 
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/testing/file.h>
 
 namespace google {
 namespace protobuf {
@@ -72,7 +76,7 @@
 
   void TryInsert(const string& filename, const string& insertion_point,
                  GeneratorContext* context) const {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 6713d29..e42ec28 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -35,6 +35,7 @@
 #include <map>
 #include <string>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
@@ -55,26 +56,6 @@
 
 namespace {
 
-const char* PrimitiveTypeName(JavaType type) {
-  switch (type) {
-    case JAVATYPE_INT    : return "int";
-    case JAVATYPE_LONG   : return "long";
-    case JAVATYPE_FLOAT  : return "float";
-    case JAVATYPE_DOUBLE : return "double";
-    case JAVATYPE_BOOLEAN: return "boolean";
-    case JAVATYPE_STRING : return "java.lang.String";
-    case JAVATYPE_BYTES  : return "com.google.protobuf.ByteString";
-    case JAVATYPE_ENUM   : return NULL;
-    case JAVATYPE_MESSAGE: return NULL;
-
-    // No default because we want the compiler to complain if any new
-    // JavaTypes are added.
-  }
-
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return NULL;
-}
-
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
                            int messageBitIndex,
                            int builderBitIndex,
@@ -113,8 +94,7 @@
   if (fixed_size != -1) {
     (*variables)["fixed_size"] = SimpleItoa(fixed_size);
   }
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -619,8 +599,8 @@
     "  return $name$_.get(index);\n"
     "}\n");
 
-  if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+  if (descriptor_->is_packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
   }
@@ -791,7 +771,10 @@
 
 void RepeatedImmutablePrimitiveFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
+    // We invoke getSerializedSize in writeTo for messages that have packed
+    // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+    // That makes it safe to rely on the memoized size here.
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
       "  output.writeRawVarint32($tag$);\n"
@@ -829,7 +812,7 @@
   printer->Print(
       "size += dataSize;\n");
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (!get$capitalized_name$List().isEmpty()) {\n"
       "  size += $tag_size$;\n"
@@ -842,7 +825,7 @@
   }
 
   // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "$name$MemoizedSerializedSize = dataSize;\n");
   }
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
new file mode 100644
index 0000000..690dad1
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -0,0 +1,900 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["field_type"] = (*variables)["type"];
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
+      "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
+  (*variables)["capitalized_type"] =
+      GetCapitalizedType(descriptor, /* immutable = */ true);
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+
+  string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(
+        GetJavaType(descriptor)), true /* cap_next_letter */);
+  switch (GetJavaType(descriptor)) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_FLOAT:
+    case JAVATYPE_DOUBLE:
+    case JAVATYPE_BOOLEAN:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal." + capitalized_type + "List";
+      (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_get"] =
+          (*variables)["name"] + "_.get" + capitalized_type;
+      (*variables)["repeated_add"] =
+          (*variables)["name"] + "_.add" + capitalized_type;
+      (*variables)["repeated_set"] =
+          (*variables)["name"] + "_.set" + capitalized_type;
+      (*variables)["visit_type"] = capitalized_type;
+      (*variables)["visit_type_list"] = "visit" + capitalized_type + "List";
+      break;
+    default:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal.ProtobufList<" +
+          (*variables)["boxed_type"] + ">";
+      (*variables)["empty_list"] = "emptyProtobufList()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_get"] = (*variables)["name"] + "_.get";
+      (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
+      (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
+      (*variables)["visit_type"] = "ByteString";
+      (*variables)["visit_type_list"] = "visitList";
+  }
+
+  if (IsReferenceType(GetJavaType(descriptor))) {
+    (*variables)["null_check"] =
+        "  if (value == null) {\n"
+        "    throw new NullPointerException();\n"
+        "  }\n";
+  } else {
+    (*variables)["null_check"] = "";
+  }
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  int fixed_size = FixedSize(GetType(descriptor));
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+  }
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+      (*variables)["is_field_present_message"] =
+          "!" + (*variables)["name"] + "_.isEmpty()";
+    } else {
+      (*variables)["is_field_present_message"] =
+          (*variables)["name"] + "_ != " + (*variables)["default"];
+    }
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutablePrimitiveFieldLiteGenerator::
+ImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $field_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n");
+  JavaType type = GetJavaType(descriptor_);
+  if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
+    // The default value is not a simple literal so we want to avoid executing
+    // it multiple times.  Instead, get the default out of the default instance.
+    printer->Print(variables_,
+      "  $name$_ = getDefaultInstance().get$capitalized_name$();\n");
+  } else {
+    printer->Print(variables_,
+      "  $name$_ = $default$;\n");
+  }
+  printer->Print(variables_,
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_ = visitor.visit$visit_type$(\n"
+      "    has$capitalized_name$(), $name$_,\n"
+      "    other.has$capitalized_name$(), other.$name$_);\n");
+  } else {
+    printer->Print(variables_,
+      "$name$_ = visitor.visit$visit_type$($name$_ != $default$, $name$_,\n"
+      "    other.$name$_ != $default$, other.$name$_);\n");
+  }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$set_has_field_bit_message$\n"
+    "$name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for primitives.
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.write$capitalized_type$($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$capitalized_type$Size($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  switch (GetJavaType(descriptor_)) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+        "result = result && (get$capitalized_name$()\n"
+        "    == other.get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(variables_,
+        "result = result && (\n"
+        "    java.lang.Float.floatToIntBits(get$capitalized_name$())\n"
+        "    == java.lang.Float.floatToIntBits(\n"
+        "        other.get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "result = result && (\n"
+        "    java.lang.Double.doubleToLongBits(get$capitalized_name$())\n"
+        "    == java.lang.Double.doubleToLongBits(\n"
+        "        other.get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+      printer->Print(variables_,
+        "result = result && get$capitalized_name$()\n"
+        "    .equals(other.get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_ENUM:
+    case JAVATYPE_MESSAGE:
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      break;
+  }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n");
+  switch (GetJavaType(descriptor_)) {
+    case JAVATYPE_INT:
+      printer->Print(variables_,
+        "hash = (53 * hash) + get$capitalized_name$();\n");
+      break;
+
+    case JAVATYPE_LONG:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(variables_,
+        "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+        "    java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+      printer->Print(variables_,
+        "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+      break;
+
+    case JAVATYPE_ENUM:
+    case JAVATYPE_MESSAGE:
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      break;
+  }
+}
+
+string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutablePrimitiveFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+~ImmutablePrimitiveOneofFieldLiteGenerator() {}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    return ($boxed_type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$oneof_name$_ = visitor.visitOneof$visit_type$(\n"
+      "    $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n"
+    "$oneof_name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.write$capitalized_type$(\n"
+    "      $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$capitalized_type$Size(\n"
+    "        $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+RepeatedImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                         int messageBitIndex,
+                                         int builderBitIndex,
+                                         Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+~RepeatedImmutablePrimitiveFieldLiteGenerator() {}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+}
+
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $field_list_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $repeated_get$(index);\n"
+    "}\n");
+
+  if (descriptor_->options().packed() &&
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ =\n"
+    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "   }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $repeated_set$(index, value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $repeated_add$(value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$name$_= visitor.$visit_type_list$($name$_, other.$name$_);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  // TODO(dweis): Scan the input buffer to count, then initialize
+  // appropriately.
+  // TODO(dweis): Scan the input buffer to count and ensure capacity.
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n"
+    "$repeated_add$(input.read$capitalized_type$());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int limit = input.pushLimit(length);\n"
+    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n");
+
+  int fixed_size = FixedSize(GetType(descriptor_));
+  if (fixed_size == -1) {
+    // TODO(dweis): Scan the input buffer to count, then initialize
+    // appropriately.
+    printer->Print(variables_,
+      "  $name$_ =\n"
+      "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n");
+  } else {
+    printer->Print(variables_,
+      "  final int currentSize = $name$_.size();\n"
+      "  $name$_ = $name$_.mutableCopyWithCapacity(\n"
+      "      currentSize + (length/$fixed_size$));\n");
+  }
+
+  // TODO(dweis): Scan the input buffer to count and ensure capacity.
+  printer->Print(variables_,
+    "}\n"
+    "while (input.getBytesUntilLimit() > 0) {\n"
+    "  $repeated_add$(input.read$capitalized_type$());\n"
+    "}\n"
+    "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $make_name_unmodifiable$;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    // We invoke getSerializedSize in writeTo for messages that have packed
+    // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+    // That makes it safe to rely on the memoized size here.
+    printer->Print(variables_,
+      "if (get$capitalized_name$List().size() > 0) {\n"
+      "  output.writeRawVarint32($tag$);\n"
+      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "}\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$NoTag($repeated_get$(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$($number$, $repeated_get$(i));\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  if (FixedSize(GetType(descriptor_)) == -1) {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  dataSize += com.google.protobuf.CodedOutputStream\n"
+      "    .compute$capitalized_type$SizeNoTag($repeated_get$(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  printer->Print(
+      "size += dataSize;\n");
+
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (!get$capitalized_name$List().isEmpty()) {\n"
+      "  size += $tag_size$;\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeInt32SizeNoTag(dataSize);\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
new file mode 100644
index 0000000..6cfbbb9
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -0,0 +1,163 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutablePrimitiveFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateBuilderClearCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldLiteGenerator
+    : public ImmutablePrimitiveFieldLiteGenerator {
+ public:
+  ImmutablePrimitiveOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutablePrimitiveOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  virtual ~RepeatedImmutablePrimitiveFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateBuilderClearCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 7baead1..11bfc12 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -39,7 +39,6 @@
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index ea77f79..74253c3 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -33,6 +33,9 @@
 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
@@ -49,8 +52,9 @@
 namespace java {
 
 SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
-  : name_resolver_(new ClassNameResolver), file_(file) {
-}
+    : name_resolver_(new ClassNameResolver),
+      enforce_lite_(false),
+      file_(file) {}
 
 SharedCodeGenerator::~SharedCodeGenerator() {
 }
@@ -60,13 +64,13 @@
   string java_package = FileJavaPackage(file_);
   string package_dir = JavaPackageToDir(java_package);
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, enforce_lite_)) {
     // Generate descriptors.
     string classname = name_resolver_->GetDescriptorClassName(file_);
     string filename = package_dir + classname + ".java";
     file_list->push_back(filename);
-    scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
-    scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$'));
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+    google::protobuf::scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$'));
 
     printer->Print(
       "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
@@ -168,7 +172,7 @@
       string classname = FileJavaPackage(file_->dependency(i)) + "." +
                          name_resolver_->GetDescriptorClassName(
                              file_->dependency(i));
-      dependencies.push_back(make_pair(filename, classname));
+      dependencies.push_back(std::make_pair(filename, classname));
     }
   }
 
@@ -176,7 +180,8 @@
   // Invoke internalBuildGeneratedFileFrom() to build the file.
   printer->Print(
     "com.google.protobuf.Descriptors.FileDescriptor\n"
-    "  .internalBuildGeneratedFileFrom(descriptorData,\n"
+    "  .internalBuildGeneratedFileFrom(descriptorData,\n");
+  printer->Print(
     "    new com.google.protobuf.Descriptors.FileDescriptor[] {\n");
 
   for (int i = 0; i < dependencies.size(); i++) {
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
index 1bb2f3d..3b573c0 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.h
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -36,6 +36,9 @@
 #define GOOGLE_PROTOBUF_COMPILER_JAVA_SHARED_CODE_GENERATOR_H__
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <vector>
 
@@ -68,6 +71,11 @@
 
   void Generate(GeneratorContext* generator_context,
                 vector<string>* file_list);
+
+  void SetEnforceLite(bool value) {
+    enforce_lite_ = value;
+  }
+
   void GenerateDescriptors(io::Printer* printer);
 
  private:
@@ -76,7 +84,8 @@
   // improve compatibility with version 1 of protocol buffers.
   bool ShouldIncludeDependency(const FileDescriptor* descriptor);
 
-  scoped_ptr<ClassNameResolver> name_resolver_;
+  google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
+  bool enforce_lite_;
   const FileDescriptor* file_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
 };
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 8889a74..b67eeb5 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -36,6 +36,7 @@
 #include <map>
 #include <string>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
@@ -77,13 +78,16 @@
       "  if (value == null) {\n"
       "    throw new NullPointerException();\n"
       "  }\n";
+  (*variables)["writeString"] =
+      "com.google.protobuf.GeneratedMessage.writeString";
+  (*variables)["computeStringSize"] =
+      "com.google.protobuf.GeneratedMessage.computeStringSize";
 
   // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -126,10 +130,6 @@
       GenerateSetBitToLocal(messageBitIndex);
 }
 
-bool CheckUtf8(const FieldDescriptor* descriptor) {
-  return descriptor->file()->options().java_string_check_utf8();
-}
-
 }  // namespace
 
 // ===================================================================
@@ -208,7 +208,7 @@
 void ImmutableStringFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.lang.Object $name$_;\n");
+    "private volatile java.lang.Object $name$_;\n");
   PrintExtraFieldInfo(variables_, printer);
 
   if (SupportFieldPresence(descriptor_->file())) {
@@ -404,7 +404,7 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-      "String s = input.readStringRequireUtf8();\n"
+      "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_has_field_bit_message$\n"
       "$name$_ = s;\n");
   } else {
@@ -424,7 +424,7 @@
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
-    "  output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+    "  $writeString$(output, $number$, $name$_);\n"
     "}\n");
 }
 
@@ -432,8 +432,7 @@
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($is_field_present_message$) {\n"
-    "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+    "  size += $computeStringSize$($number$, $name$_);\n"
     "}\n");
 }
 
@@ -656,9 +655,9 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-      "String s = input.readStringRequireUtf8();\n"
+      "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_oneof_case_message$;\n"
-      "$oneof_name$_ = s;\n}\n");
+      "$oneof_name$_ = s;\n");
   } else {
     printer->Print(variables_,
       "com.google.protobuf.ByteString bs = input.readBytes();\n"
@@ -671,7 +670,7 @@
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($has_oneof_case_message$) {\n"
-    "  output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+    "  $writeString$(output, $number$, $oneof_name$_);\n"
     "}\n");
 }
 
@@ -679,8 +678,7 @@
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($has_oneof_case_message$) {\n"
-    "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+    "  size += $computeStringSize$($number$, $oneof_name$_);\n"
     "}\n");
 }
 
@@ -756,12 +754,6 @@
     "    get$capitalized_name$Bytes(int index) {\n"
     "  return $name$_.getByteString(index);\n"
     "}\n");
-
-  if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      "private int $name$MemoizedSerializedSize = -1;\n");
-  }
 }
 
 void RepeatedImmutableStringFieldGenerator::
@@ -922,7 +914,7 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-    "String s = input.readStringRequireUtf8();\n");
+    "java.lang.String s = input.readStringRequireUtf8();\n");
   } else {
     printer->Print(variables_,
     "com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -942,30 +934,6 @@
 }
 
 void RepeatedImmutableStringFieldGenerator::
-GenerateParsingCodeFromPacked(io::Printer* printer) const {
-  printer->Print(variables_,
-    "int length = input.readRawVarint32();\n"
-    "int limit = input.pushLimit(length);\n"
-    "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
-    "  $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
-    "  $set_mutable_bit_parser$;\n"
-    "}\n"
-    "while (input.getBytesUntilLimit() > 0) {\n");
-  if (CheckUtf8(descriptor_)) {
-    printer->Print(variables_,
-      "  String s = input.readStringRequireUtf8();\n");
-  } else {
-    printer->Print(variables_,
-      "  String s = input.readString();\n");
-  }
-  printer->Print(variables_,
-    "  $name$.add(s);\n");
-  printer->Print(variables_,
-    "}\n"
-    "input.popLimit(limit);\n");
-}
-
-void RepeatedImmutableStringFieldGenerator::
 GenerateParsingDoneCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($get_mutable_bit_parser$) {\n"
@@ -975,21 +943,10 @@
 
 void RepeatedImmutableStringFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
-      "}\n"
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.write$capitalized_type$NoTag($name$_.get(i));\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeBytes($number$, $name$_.getByteString(i));\n"
-      "}\n");
-  }
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  $writeString$(output, $number$, $name$_.getRaw(i));\n"
+    "}\n");
 }
 
 void RepeatedImmutableStringFieldGenerator::
@@ -1001,30 +958,14 @@
 
   printer->Print(variables_,
     "for (int i = 0; i < $name$_.size(); i++) {\n"
-    "  dataSize += com.google.protobuf.CodedOutputStream\n"
-    "    .computeBytesSizeNoTag($name$_.getByteString(i));\n"
+    "  dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n"
     "}\n");
 
   printer->Print(
       "size += dataSize;\n");
 
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (!get$capitalized_name$List().isEmpty()) {\n"
-      "  size += $tag_size$;\n"
-      "  size += com.google.protobuf.CodedOutputStream\n"
-      "      .computeInt32SizeNoTag(dataSize);\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "size += $tag_size$ * get$capitalized_name$List().size();\n");
-  }
-
-  // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "$name$MemoizedSerializedSize = dataSize;\n");
-  }
+  printer->Print(variables_,
+    "size += $tag_size$ * get$capitalized_name$List().size();\n");
 
   printer->Outdent();
   printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 1ea44de..a3b5735 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -131,7 +131,6 @@
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateBuildingCode(io::Printer* printer) const;
   void GenerateParsingCode(io::Printer* printer) const;
-  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
   void GenerateParsingDoneCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
new file mode 100644
index 0000000..0b92c02
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -0,0 +1,872 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["empty_list"] =
+      "com.google.protobuf.GeneratedMessageLite.emptyProtobufList()";
+
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] =
+      "= " + ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["capitalized_type"] = "String";
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  (*variables)["null_check"] =
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n";
+
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        "!" + (*variables)["name"] + "_.isEmpty()";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableStringFieldLiteGenerator::
+ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                              int messageBitIndex,
+                              int builderBitIndex,
+                              Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes,
+// strings are not stored as java.lang.String in the Message because of two
+// issues:
+//
+//  1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded
+//     strings, but rather fields that were raw bytes incorrectly marked
+//     as strings in the proto file. This is common because in the proto1
+//     syntax, string was the way to indicate bytes and C++ engineers can
+//     easily make this mistake without affecting the C++ API. By converting to
+//     strings immediately, some java code might corrupt these byte arrays as
+//     it passes through a java server even if the field was never accessed by
+//     application code.
+//
+//  2. There's a performance hit to converting between bytes and strings and
+//     it many cases, the field is never even read by the application code. This
+//     avoids unnecessary conversions in the common use cases.
+//
+// In the LITE_RUNTIME, we store strings as java.lang.String because we assume
+// that the users of this runtime are not subject to proto1 constraints and are
+// running code on devices that are user facing. That is, the developers are
+// properly incentivized to only fetch the data they need to read and wish to
+// reduce the number of allocations incurred when running on a user's device.
+
+// TODO(dweis): Consider dropping all of the *Bytes() methods. They really
+//     shouldn't be necessary or used on devices.
+void ImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.lang.String get$capitalized_name$();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes();\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private java.lang.String $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n"
+    // The default value is not a simple literal so we want to avoid executing
+    // it multiple times.  Instead, get the default out of the default instance.
+    "  $name$_ = getDefaultInstance().get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value.toStringUtf8();\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  return instance.get$capitalized_name$Bytes();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_ = visitor.visitString(\n"
+      "    has$capitalized_name$(), $name$_,\n"
+      "    other.has$capitalized_name$(), other.$name$_);\n");
+  } else {
+    printer->Print(variables_,
+      "$name$_ = visitor.visitString(!$name$_.isEmpty(), $name$_,\n"
+      "    !other.$name$_.isEmpty(), other.$name$_);\n");
+  }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "String s = input.readStringRequireUtf8();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = s;\n");
+  } else {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+      "String s = input.readString();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = s;\n");
+  }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by serializing the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.writeString($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by computing on the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeStringSize($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n");
+  printer->Print(variables_,
+    "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldLiteGenerator::
+ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                   int messageBitIndex,
+                                   int builderBitIndex,
+                                   Context* context)
+    : ImmutableStringFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableStringOneofFieldLiteGenerator::
+~ImmutableStringOneofFieldLiteGenerator() {}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case_message$;\n"
+    "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  java.lang.String ref $default_init$;\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    ref = (java.lang.String) $oneof_name$_;\n"
+    "  }\n"
+    "  return ref;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  java.lang.String ref $default_init$;\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    ref = (java.lang.String) $oneof_name$_;\n"
+    "  }\n"
+    "  return com.google.protobuf.ByteString.copyFromUtf8(ref);\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value.toStringUtf8();\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  return instance.get$capitalized_name$Bytes();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$oneof_name$_ = visitor.visitOneofString(\n"
+    "   $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "String s = input.readStringRequireUtf8();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = s;\n");
+  } else {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+      "String s = input.readString();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = s;\n");
+  }
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by serializing the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeString($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by computing on the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeStringSize($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableStringFieldLiteGenerator::
+RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                      int messageBitIndex,
+                                      int builderBitIndex,
+                                      Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutableStringFieldLiteGenerator::
+~RepeatedImmutableStringFieldLiteGenerator() {}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<String>\n"
+    "    get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index);\n");
+}
+
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.ProtobufList<String> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<String> get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index) {\n"
+    "  return com.google.protobuf.ByteString.copyFromUtf8(\n"
+    "      $name$_.get(index));\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ =\n"
+    "        com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "   }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, java.lang.String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<java.lang.String> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value.toStringUtf8());\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<String>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index) {\n"
+    "  return instance.get$capitalized_name$Bytes(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<java.lang.String> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for strings
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateVisitCode(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$name$_= visitor.visitList($name$_, other.$name$_);\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+    "String s = input.readStringRequireUtf8();\n");
+  } else {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+    "String s = input.readString();\n");
+  }
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ =\n"
+    "      com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"
+    "}\n");
+  printer->Print(variables_,
+    "$name$_.add(s);\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by serializing the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.writeString($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  // Lite runtime should reduce allocations by computing on the string directly.
+  // This avoids spurious intermediary ByteString allocations, cutting overall
+  // allocations in half.
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  dataSize += com.google.protobuf.CodedOutputStream\n"
+    "    .computeStringSizeNoTag($name$_.get(i));\n"
+    "}\n");
+
+  printer->Print(
+      "size += dataSize;\n");
+
+
+  printer->Print(variables_,
+    "size += $tag_size$ * get$capitalized_name$List().size();\n");
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "String";
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
new file mode 100644
index 0000000..4148aa4
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -0,0 +1,157 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableStringFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableStringFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator);
+};
+
+class ImmutableStringOneofFieldLiteGenerator
+    : public ImmutableStringFieldLiteGenerator {
+ public:
+  ImmutableStringOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableStringOneofFieldLiteGenerator();
+
+ private:
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableStringFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableStringFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableStringFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateVisitCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.h b/src/google/protobuf/compiler/javanano/javanano_enum.h
index d6f463e..10dd364 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
 
 #include <string>
 #include <vector>
@@ -84,4 +84,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 8622463..b94790d 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
 
 #include <map>
 #include <string>
@@ -123,4 +123,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.h b/src/google/protobuf/compiler/javanano/javanano_extension.h
index c6543eb..4843e29 100644
--- a/src/google/protobuf/compiler/javanano/javanano_extension.h
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/javanano/javanano_params.h>
@@ -71,4 +71,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.cc b/src/google/protobuf/compiler/javanano/javanano_field.cc
index e3e4cef..85257f3 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_field.cc
@@ -36,6 +36,7 @@
 #include <google/protobuf/compiler/javanano/javanano_helpers.h>
 #include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
 #include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
 #include <google/protobuf/compiler/javanano/javanano_message_field.h>
 #include <google/protobuf/stubs/common.h>
 
@@ -97,12 +98,24 @@
   if (field->is_repeated()) {
     switch (java_type) {
       case JAVATYPE_MESSAGE:
-        return new RepeatedMessageFieldGenerator(field, params);
+        if (IsMapEntry(field->message_type())) {
+          return new MapFieldGenerator(field, params);
+        } else {
+          return new RepeatedMessageFieldGenerator(field, params);
+        }
       case JAVATYPE_ENUM:
         return new RepeatedEnumFieldGenerator(field, params);
       default:
         return new RepeatedPrimitiveFieldGenerator(field, params);
     }
+  } else if (field->containing_oneof()) {
+    switch (java_type) {
+      case JAVATYPE_MESSAGE:
+        return new MessageOneofFieldGenerator(field, params);
+      case JAVATYPE_ENUM:
+      default:
+        return new PrimitiveOneofFieldGenerator(field, params);
+    }
   } else if (params.optional_field_accessors() && field->is_optional()
       && java_type != JAVATYPE_MESSAGE) {
     // We need a has-bit for each primitive/enum field because their default
@@ -137,6 +150,59 @@
   return *field_generators_[field->index()];
 }
 
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+                             map<string, string>* variables) {
+  (*variables)["oneof_name"] =
+      UnderscoresToCamelCase(descriptor->containing_oneof());
+  (*variables)["oneof_capitalized_name"] =
+      UnderscoresToCapitalizedCamelCase(descriptor->containing_oneof());
+  (*variables)["oneof_index"] =
+      SimpleItoa(descriptor->containing_oneof()->index());
+  (*variables)["set_oneof_case"] =
+      "this." + (*variables)["oneof_name"] +
+      "Case_ = " + SimpleItoa(descriptor->number());
+  (*variables)["clear_oneof_case"] =
+      "this." + (*variables)["oneof_name"] + "Case_ = 0";
+  (*variables)["has_oneof_case"] =
+      "this." + (*variables)["oneof_name"] + "Case_ == " +
+      SimpleItoa(descriptor->number());
+}
+
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+                              const map<string, string>& variables,
+                              io::Printer* printer) {
+  if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+    printer->Print(variables,
+      "if (this.has$capitalized_name$()) {\n"
+      "  if (!java.util.Arrays.equals((byte[]) this.$oneof_name$_,\n"
+      "                               (byte[]) other.$oneof_name$_)) {\n"
+      "    return false;\n"
+      "  }\n"
+      "}\n");
+  } else {
+    printer->Print(variables,
+      "if (this.has$capitalized_name$()) {\n"
+      "  if (!this.$oneof_name$_.equals(other.$oneof_name$_)) {\n"
+      "    return false;\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+                                const map<string, string>& variables,
+                                io::Printer* printer) {
+  if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
+    printer->Print(variables,
+      "result = 31 * result + ($has_oneof_case$\n"
+      "   ? java.util.Arrays.hashCode((byte[]) this.$oneof_name$_) : 0);\n");
+  } else {
+    printer->Print(variables,
+      "result = 31 * result +\n"
+      "  ($has_oneof_case$ ? this.$oneof_name$_.hashCode() : 0);\n");
+  }
+}
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index e015259..57c221f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -32,9 +32,10 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
 
+#include <map>
 #include <string>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
@@ -112,9 +113,18 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
 };
 
+void SetCommonOneofVariables(const FieldDescriptor* descriptor,
+                             map<string, string>* variables);
+void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
+                              const map<string, string>& variables,
+                              io::Printer* printer);
+void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
+                                const map<string, string>& variables,
+                                io::Printer* printer);
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc
index d8c5111..3676ab9 100644
--- a/src/google/protobuf/compiler/javanano/javanano_file.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_file.cc
@@ -171,8 +171,6 @@
       "package", java_package_);
   }
 
-  printer->Print("\n// @@protoc_insertion_point(imports_scope)\n");
-
   // Note: constants (from enums, emitted in the loop below) may have the same names as constants
   // in the nested classes. This causes Java warnings, but is not fatal, so we suppress those
   // warnings here in the top-most class declaration.
@@ -217,7 +215,7 @@
 static void GenerateSibling(const string& package_dir,
                             const string& java_package,
                             const DescriptorClass* descriptor,
-                            OutputDirectory* output_directory,
+                            GeneratorContext* output_directory,
                             vector<string>* file_list,
                             const Params& params) {
   string filename = package_dir + descriptor->name() + ".java";
@@ -240,7 +238,7 @@
 }
 
 void FileGenerator::GenerateSiblings(const string& package_dir,
-                                     OutputDirectory* output_directory,
+                                     GeneratorContext* output_directory,
                                      vector<string>* file_list) {
   if (params_.java_multiple_files(file_->name())) {
     for (int i = 0; i < file_->message_type_count(); i++) {
diff --git a/src/google/protobuf/compiler/javanano/javanano_file.h b/src/google/protobuf/compiler/javanano/javanano_file.h
index cfcd7c6..217eafe 100644
--- a/src/google/protobuf/compiler/javanano/javanano_file.h
+++ b/src/google/protobuf/compiler/javanano/javanano_file.h
@@ -32,13 +32,12 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
 
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/javanano/javanano_params.h>
 
 namespace google {
@@ -47,6 +46,9 @@
   namespace io {
     class Printer;             // printer.h
   }
+  namespace compiler {
+    class GeneratorContext;     // code_generator.h
+  }
 }
 
 namespace protobuf {
@@ -69,7 +71,7 @@
   // files other than the outer file (i.e. one for each message, enum, and
   // service type).
   void GenerateSiblings(const string& package_dir,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* output_directory,
                         vector<string>* file_list);
 
   const string& java_package() { return java_package_; }
@@ -89,4 +91,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index e842791..23d2437 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -67,8 +67,13 @@
       file->name(), file->options().java_outer_classname());
   }
   if (file->options().has_java_package()) {
+    string result = file->options().java_package();
+    if (!result.empty()) {
+      result += ".";
+    }
+    result += "nano";
     params.set_java_package(
-      file->name(), file->options().java_package());
+      file->name(), result);
   }
   if (file->options().has_java_multiple_files()) {
     params.set_java_multiple_files(
@@ -87,7 +92,7 @@
 
 bool JavaNanoGenerator::Generate(const FileDescriptor* file,
                              const string& parameter,
-                             OutputDirectory* output_directory,
+                             GeneratorContext* output_directory,
                              string* error) const {
   vector<pair<string, string> > options;
 
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.h b/src/google/protobuf/compiler/javanano/javanano_generator.h
index 0c1e3a4..6f9f7f2 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.h
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.h
@@ -34,8 +34,8 @@
 //
 // Generates Java nano code for a given .proto file.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
 
 #include <string>
 #include <google/protobuf/compiler/code_generator.h>
@@ -57,7 +57,7 @@
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file,
                 const string& parameter,
-                OutputDirectory* output_directory,
+                GeneratorContext* output_directory,
                 string* error) const;
 
  private:
@@ -69,4 +69,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index 2149418..02811a2 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -154,6 +154,14 @@
   return UnderscoresToCamelCaseImpl(method->name(), false);
 }
 
+string UnderscoresToCamelCase(const OneofDescriptor* oneof) {
+  return UnderscoresToCamelCaseImpl(oneof->name(), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof) {
+  return UnderscoresToCamelCaseImpl(oneof->name(), true);
+}
+
 string RenameJavaKeywords(const string& input) {
   return sRenameKeywords.RenameJavaKeywordsImpl(input);
 }
@@ -192,6 +200,12 @@
       if (!result.empty()) result += '.';
       result += file->package();
     }
+
+    if (!result.empty()) {
+      result += ".";
+    }
+    result += "nano";
+
     return result;
   }
 }
@@ -560,6 +574,17 @@
   (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
 }
 
+bool HasMapField(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
+        IsMapEntry(field->message_type())) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h
index 886bff8..014c85a 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.h
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
 
 #include <string>
 #include <google/protobuf/compiler/javanano/javanano_params.h>
@@ -54,7 +54,9 @@
 // Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
 // "fooBarBaz" or "FooBarBaz", respectively.
 string UnderscoresToCamelCase(const FieldDescriptor* field);
+string UnderscoresToCamelCase(const OneofDescriptor* oneof);
 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
+string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof);
 
 // Appends an "_" to the end of a field where the name is a reserved java
 // keyword.  For example int32 public = 1 will generate int public_.
@@ -181,9 +183,17 @@
 void SetBitOperationVariables(const string name,
     int bitIndex, map<string, string>* variables);
 
+inline bool IsMapEntry(const Descriptor* descriptor) {
+  // TODO(liujisi): Add an option to turn on maps for proto2 syntax as well.
+  return descriptor->options().map_entry() &&
+      descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool HasMapField(const Descriptor* descriptor);
+
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.cc b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
new file mode 100644
index 0000000..83b2b0c
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.cc
@@ -0,0 +1,186 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+#include <google/protobuf/compiler/javanano/javanano_map_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+string TypeName(const Params& params, const FieldDescriptor* field,
+                bool boxed) {
+  JavaType java_type = GetJavaType(field);
+  switch (java_type) {
+    case JAVATYPE_MESSAGE:
+      return ClassName(params, field->message_type());
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_FLOAT:
+    case JAVATYPE_DOUBLE:
+    case JAVATYPE_BOOLEAN:
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+    case JAVATYPE_ENUM:
+      if (boxed) {
+        return BoxedPrimitiveTypeName(java_type);
+      } else {
+        return PrimitiveTypeName(java_type);
+      }
+    // No default because we want the compiler to complain if any new JavaTypes
+    // are added..
+  }
+
+  GOOGLE_LOG(FATAL) << "should not reach here.";
+  return "";
+}
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("value");
+}
+
+void SetMapVariables(const Params& params,
+    const FieldDescriptor* descriptor, map<string, string>* variables) {
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  (*variables)["name"] =
+    RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["key_type"] = TypeName(params, key, false);
+  (*variables)["boxed_key_type"] = TypeName(params,key, true);
+  (*variables)["key_desc_type"] =
+      "TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type()));
+  (*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key));
+  (*variables)["value_type"] = TypeName(params, value, false);
+  (*variables)["boxed_value_type"] = TypeName(params, value, true);
+  (*variables)["value_desc_type"] =
+      "TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type()));
+  (*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value));
+  (*variables)["type_parameters"] =
+      (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+  (*variables)["value_default"] =
+      value->type() == FieldDescriptor::TYPE_MESSAGE
+          ? "new " + (*variables)["value_type"] + "()"
+          : "null";
+}
+}  // namespace
+
+// ===================================================================
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Params& params)
+    : FieldGenerator(params), descriptor_(descriptor) {
+  SetMapVariables(params, descriptor, &variables_);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+  printer->Print(variables_,
+    "public java.util.Map<$type_parameters$> $name$;\n");
+}
+
+void MapFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$ = null;\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "this.$name$ = com.google.protobuf.nano.InternalNano.mergeMapEntry(\n"
+    "  input, this.$name$, mapFactory,\n"
+    "  com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+    "  com.google.protobuf.nano.InternalNano.$value_desc_type$,\n"
+    "  $value_default$,\n"
+    "  $key_tag$, $value_tag$);\n"
+    "\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null) {\n"
+    "  com.google.protobuf.nano.InternalNano.serializeMapField(\n"
+    "    output, this.$name$, $number$,\n"
+    "  com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+    "  com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+    "}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null) {\n"
+    "  size += com.google.protobuf.nano.InternalNano.computeMapFieldSize(\n"
+    "    this.$name$, $number$,\n"
+    "  com.google.protobuf.nano.InternalNano.$key_desc_type$,\n"
+    "  com.google.protobuf.nano.InternalNano.$value_desc_type$);\n"
+    "}\n");
+}
+
+void MapFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+    "  this.$name$, other.$name$)) {\n"
+    "  return false;\n"
+    "}\n");
+}
+
+void MapFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = 31 * result +\n"
+    "    com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+}  // namespace javanano
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.h b/src/google/protobuf/compiler/javanano/javanano_map_field.h
new file mode 100644
index 0000000..c01bde3
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_map_field.h
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+  explicit MapFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
+  ~MapFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+}  // namespace javanano
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index b639435..a41da5a 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -90,6 +90,7 @@
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
     MessageGenerator(descriptor_->nested_type(i), params_)
       .GenerateStaticVariables(printer);
   }
@@ -100,6 +101,7 @@
   // Generate static member initializers for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
    // TODO(kenton):  Reuse MessageGenerator objects?
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
     MessageGenerator(descriptor_->nested_type(i), params_)
       .GenerateStaticVariableInitializers(printer);
   }
@@ -175,9 +177,44 @@
   }
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
     MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
   }
 
+  // oneof
+  map<string, string> vars;
+  vars["message_name"] = descriptor_->name();
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+    vars["oneof_name"] = UnderscoresToCamelCase(oneof_desc);
+    vars["oneof_capitalized_name"] =
+        UnderscoresToCapitalizedCamelCase(oneof_desc);
+    vars["oneof_index"] = SimpleItoa(oneof_desc->index());
+    // Oneof Constants
+    for (int j = 0; j < oneof_desc->field_count(); j++) {
+      const FieldDescriptor* field = oneof_desc->field(j);
+      vars["number"] = SimpleItoa(field->number());
+      vars["cap_field_name"] = ToUpper(field->name());
+      printer->Print(vars,
+        "public static final int $cap_field_name$_FIELD_NUMBER = $number$;\n");
+    }
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+      "private int $oneof_name$Case_ = 0;\n"
+      "private java.lang.Object $oneof_name$_;\n");
+    printer->Print(vars,
+      "public int get$oneof_capitalized_name$Case() {\n"
+      "  return this.$oneof_name$Case_;\n"
+      "}\n");
+    // Oneof clear
+    printer->Print(vars,
+      "public $message_name$ clear$oneof_capitalized_name$() {\n"
+      "  this.$oneof_name$Case_ = 0;\n"
+      "  this.$oneof_name$_ = null;\n"
+      "  return this;\n"
+      "}\n");
+  }
+
   // Lazy initialization of otherwise static final fields can help prevent the
   // class initializer from being generated. We want to prevent it because it
   // stops ProGuard from inlining any methods in this class into call sites and
@@ -232,10 +269,6 @@
         printer, lazy_init);
   }
 
-  // Insertion point for proto compiler plugins
-  printer->Print("\n// @@protoc_insertion_point(class_scope:$classname$)\n",
-                 "classname", descriptor_->full_name());
-
   // Constructor, with lazy init code if needed
   if (lazy_init && field_generators_.saved_defaults_needed()) {
     printer->Print(
@@ -370,6 +403,11 @@
     "classname", descriptor_->name());
 
   printer->Indent();
+  if (HasMapField(descriptor_)) {
+    printer->Print(
+      "com.google.protobuf.nano.MapFactories.MapFactory mapFactory =\n"
+      "  com.google.protobuf.nano.MapFactories.getMapFactory();\n");
+  }
 
   printer->Print(
     "while (true) {\n");
@@ -388,7 +426,7 @@
   printer->Indent();
   if (params_.store_unknown_fields()) {
     printer->Print(
-        "if (!super.storeUnknownField(input, tag)) {\n"
+        "if (!storeUnknownField(input, tag)) {\n"
         "  return this;\n"
         "}\n");
   } else {
@@ -503,6 +541,14 @@
     field_generators_.get(field).GenerateClearCode(printer);
   }
 
+  // Clear oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "clear$oneof_capitalized_name$();\n",
+      "oneof_capitalized_name", UnderscoresToCapitalizedCamelCase(
+          descriptor_->oneof_decl(i)));
+  }
+
   // Clear unknown fields.
   if (params_.store_unknown_fields()) {
     printer->Print("unknownFieldData = null;\n");
@@ -560,6 +606,16 @@
     "$classname$ other = ($classname$) o;\n",
     "classname", descriptor_->name());
 
+  // Checking oneof case before checking each oneof field.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof_desc = descriptor_->oneof_decl(i);
+    printer->Print(
+      "if (this.$oneof_name$Case_ != other.$oneof_name$Case_) {\n"
+      "  return false;\n"
+      "}\n",
+      "oneof_name", UnderscoresToCamelCase(oneof_desc));
+  }
+
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     field_generators_.get(field).GenerateEqualsCode(printer);
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index 1bb6557..281ec64 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
 
 #include <string>
 #include <google/protobuf/compiler/javanano/javanano_helpers.h>
@@ -94,4 +94,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index 4752644..d1d04b5 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -154,12 +154,95 @@
     "result = 31 * result +\n"
     "    (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
 }
+// ===================================================================
+
+MessageOneofFieldGenerator::MessageOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Params& params)
+    : FieldGenerator(params), descriptor_(descriptor) {
+    SetMessageVariables(params, descriptor, &variables_);
+    SetCommonOneofVariables(descriptor, &variables_);
+}
+
+MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
+
+void MessageOneofFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+  printer->Print(variables_,
+    "public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case$;\n"
+    "}\n"
+    "public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case$) {\n"
+    "    return ($type$) this.$oneof_name$_;\n"
+    "  }\n"
+    "  return null;\n"
+    "}\n"
+    "public $message_name$ set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) { throw new java.lang.NullPointerException(); }\n"
+    "  $set_oneof_case$;\n"
+    "  this.$oneof_name$_ = value;\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+  // No clear method for oneof fields.
+}
+
+void MessageOneofFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!($has_oneof_case$)) {\n"
+    "  this.$oneof_name$_ = new $type$();\n"
+    "}\n"
+    "input.readMessage(\n"
+    "    (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+    "$set_oneof_case$;\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case$) {\n"
+    "  output.writeMessage($number$,\n"
+    "      (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case$) {\n"
+    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+    "    .computeMessageSize($number$,\n"
+    "        (com.google.protobuf.nano.MessageNano) this.$oneof_name$_);\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$oneof_name$ != null) {\n"
+    "  cloned.$oneof_name$ = this.$oneof_name$.clone();\n"
+    "}\n");
+}
+
+void MessageOneofFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void MessageOneofFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+  GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
 
 // ===================================================================
 
-RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
-  : FieldGenerator(params), descriptor_(descriptor) {
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor, const Params& params)
+    : FieldGenerator(params), descriptor_(descriptor) {
   SetMessageVariables(params, descriptor, &variables_);
 }
 
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index 1edff25..e074735 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -32,8 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
-#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
 
 #include <map>
 #include <string>
@@ -67,6 +67,29 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
 };
 
+class MessageOneofFieldGenerator : public FieldGenerator {
+ public:
+  explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
+                                      const Params& params);
+  ~MessageOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCodeCode(io::Printer* printer) const;
+  void GenerateFixClonedCode(io::Printer* printer) const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
+};
+
 class RepeatedMessageFieldGenerator : public FieldGenerator {
  public:
   explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
@@ -95,4 +118,4 @@
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index 7a1655e..0935945 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -155,28 +155,6 @@
   return -1;
 }
 
-// Return true if the type is a that has variable length
-// for instance String's.
-bool IsVariableLenType(JavaType type) {
-  switch (type) {
-    case JAVATYPE_INT    : return false;
-    case JAVATYPE_LONG   : return false;
-    case JAVATYPE_FLOAT  : return false;
-    case JAVATYPE_DOUBLE : return false;
-    case JAVATYPE_BOOLEAN: return false;
-    case JAVATYPE_STRING : return true;
-    case JAVATYPE_BYTES  : return true;
-    case JAVATYPE_ENUM   : return false;
-    case JAVATYPE_MESSAGE: return true;
-
-    // No default because we want the compiler to complain if any new
-    // JavaTypes are added.
-  }
-
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return false;
-}
-
 bool AllAscii(const string& text) {
   for (int i = 0; i < text.size(); i++) {
     if ((text[i] & 0x80) != 0) {
@@ -186,6 +164,7 @@
   return true;
 }
 
+
 void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
                            map<string, string>* variables) {
   (*variables)["name"] =
@@ -640,7 +619,6 @@
 
 void AccessorPrimitiveFieldGenerator::
 GenerateClearCode(io::Printer* printer) const {
-  
   printer->Print(variables_,
     "$name$_ = $default_copy_if_needed$;\n");
 }
@@ -768,8 +746,79 @@
 
 // ===================================================================
 
-RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
+    const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+    SetPrimitiveVariables(descriptor, params, &variables_);
+    SetCommonOneofVariables(descriptor, &variables_);
+}
+
+PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
+
+void PrimitiveOneofFieldGenerator::GenerateMembers(
+    io::Printer* printer, bool /*unused lazy_init*/) const {
+  printer->Print(variables_,
+    "public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case$;\n"
+    "}\n"
+    "public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case$) {\n"
+    "    return ($type$) ($boxed_type$) this.$oneof_name$_;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n"
+    "public $message_name$ set$capitalized_name$($type$ value) {\n"
+    "  $set_oneof_case$;\n"
+    "  this.$oneof_name$_ = value;\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateClearCode(
+    io::Printer* printer) const {
+  // No clear method for oneof fields.
+}
+
+void PrimitiveOneofFieldGenerator::GenerateMergingCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+    "this.$oneof_name$_ = input.read$capitalized_type$();\n"
+    "$set_oneof_case$;\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializationCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case$) {\n"
+    "  output.write$capitalized_type$(\n"
+    "      $number$, ($boxed_type$) this.$oneof_name$_);\n"
+    "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateSerializedSizeCode(
+    io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case$) {\n"
+    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+    "      .compute$capitalized_type$Size(\n"
+    "          $number$, ($boxed_type$) this.$oneof_name$_);\n"
+    "}\n");
+}
+
+void PrimitiveOneofFieldGenerator::GenerateEqualsCode(
+    io::Printer* printer) const {
+  GenerateOneofFieldEquals(descriptor_, variables_, printer);
+}
+
+void PrimitiveOneofFieldGenerator::GenerateHashCodeCode(
+    io::Printer* printer) const {
+  GenerateOneofFieldHashCode(descriptor_, variables_, printer);
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Params& params)
   : FieldGenerator(params), descriptor_(descriptor) {
   SetPrimitiveVariables(descriptor, params, &variables_);
 }
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index daa712e..394cb10 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -47,7 +47,7 @@
 class PrimitiveFieldGenerator : public FieldGenerator {
  public:
   explicit PrimitiveFieldGenerator(
-      const FieldDescriptor* descriptor, const Params &params);
+      const FieldDescriptor* descriptor, const Params& params);
   ~PrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
@@ -96,9 +96,32 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator);
 };
 
+class PrimitiveOneofFieldGenerator : public FieldGenerator {
+ public:
+  explicit PrimitiveOneofFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
+  ~PrimitiveOneofFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+  void GenerateClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator);
+};
+
 class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                           const Params& params);
   ~RepeatedPrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
new file mode 100755
index 0000000..3de61e8
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -0,0 +1,3053 @@
+// 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.
+
+#include "google/protobuf/compiler/js/js_generator.h"
+
+#include <assert.h>
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace js {
+
+// Sorted list of JavaScript keywords. These cannot be used as names. If they
+// appear, we prefix them with "pb_".
+const char* kKeyword[] = {
+  "abstract",
+  "boolean",
+  "break",
+  "byte",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "const",
+  "continue",
+  "debugger",
+  "default",
+  "delete",
+  "do",
+  "double",
+  "else",
+  "enum",
+  "export",
+  "extends",
+  "false",
+  "final",
+  "finally",
+  "float",
+  "for",
+  "function",
+  "goto",
+  "if",
+  "implements",
+  "import",
+  "in",
+  "instanceof",
+  "int",
+  "interface",
+  "long",
+  "native",
+  "new",
+  "null",
+  "package",
+  "private",
+  "protected",
+  "public",
+  "return",
+  "short",
+  "static",
+  "super",
+  "switch",
+  "synchronized",
+  "this",
+  "throw",
+  "throws",
+  "transient",
+  "try",
+  "typeof",
+  "var",
+  "void",
+  "volatile",
+  "while",
+  "with",
+};
+
+static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
+
+namespace {
+
+// The mode of operation for bytes fields. Historically JSPB always carried
+// bytes as JS {string}, containing base64 content by convention. With binary
+// and proto3 serialization the new convention is to represent it as binary
+// data in Uint8Array. See b/26173701 for background on the migration.
+enum BytesMode {
+  BYTES_DEFAULT,  // Default type for getBytesField to return.
+  BYTES_B64,      // Explicitly coerce to base64 string where needed.
+  BYTES_U8,       // Explicitly coerce to Uint8Array where needed.
+};
+
+bool IsReserved(const string& ident) {
+  for (int i = 0; i < kNumKeyword; i++) {
+    if (ident == kKeyword[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
+// suffix stripped.
+// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc.
+string StripProto(const string& filename) {
+  const char* suffix = HasSuffixString(filename, ".protodevel")
+      ? ".protodevel" : ".proto";
+  return StripSuffixString(filename, suffix);
+}
+
+// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
+// file foo/bar/baz.js.
+string GetJSFilename(const string& filename) {
+  return StripProto(filename) + "_pb.js";
+}
+
+// Given a filename like foo/bar/baz.proto, returns the root directory
+// path ../../
+string GetRootPath(const string& filename) {
+  size_t slashes = std::count(filename.begin(), filename.end(), '/');
+  if (slashes == 0) {
+    return "./";
+  }
+  string result = "";
+  for (size_t i = 0; i < slashes; i++) {
+    result += "../";
+  }
+  return result;
+}
+
+// Returns the alias we assign to the module of the given .proto filename
+// when importing.
+string ModuleAlias(const string& filename) {
+  // This scheme could technically cause problems if a file includes any 2 of:
+  //   foo/bar_baz.proto
+  //   foo_bar_baz.proto
+  //   foo_bar/baz.proto
+  //
+  // We'll worry about this problem if/when we actually see it.  This name isn't
+  // exposed to users so we can change it later if we need to.
+  string basename = StripProto(filename);
+  StripString(&basename, "-", '$');
+  StripString(&basename, "/", '_');
+  return basename + "_pb";
+}
+
+// Returns the fully normalized JavaScript path for the given
+// file descriptor's package.
+string GetPath(const GeneratorOptions& options,
+               const FileDescriptor* file) {
+  if (!options.namespace_prefix.empty()) {
+    return options.namespace_prefix;
+  } else if (!file->package().empty()) {
+    return "proto." + file->package();
+  } else {
+    return "proto";
+  }
+}
+
+// Forward declare, so that GetPrefix can call this method,
+// which in turn, calls GetPrefix.
+string GetPath(const GeneratorOptions& options,
+               const Descriptor* descriptor);
+
+// Returns the path prefix for a message or enumeration that
+// lives under the given file and containing type.
+string GetPrefix(const GeneratorOptions& options,
+                 const FileDescriptor* file_descriptor,
+                 const Descriptor* containing_type) {
+  string prefix = "";
+
+  if (containing_type == NULL) {
+    prefix = GetPath(options, file_descriptor);
+  } else {
+    prefix = GetPath(options, containing_type);
+  }
+
+  if (!prefix.empty()) {
+    prefix += ".";
+  }
+
+  return prefix;
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// message descriptor.
+string GetPath(const GeneratorOptions& options,
+               const Descriptor* descriptor) {
+  return GetPrefix(
+      options, descriptor->file(),
+      descriptor->containing_type()) + descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// field's containing message descriptor.
+string GetPath(const GeneratorOptions& options,
+               const FieldDescriptor* descriptor) {
+  return GetPath(options, descriptor->containing_type());
+}
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration descriptor.
+string GetPath(const GeneratorOptions& options,
+               const EnumDescriptor* enum_descriptor) {
+  return GetPrefix(
+      options, enum_descriptor->file(),
+      enum_descriptor->containing_type()) + enum_descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration value descriptor.
+string GetPath(const GeneratorOptions& options,
+               const EnumValueDescriptor* value_descriptor) {
+  return GetPath(
+      options,
+      value_descriptor->type()) + "." + value_descriptor->name();
+}
+
+string MaybeCrossFileRef(const GeneratorOptions& options,
+                         const FileDescriptor* from_file,
+                         const Descriptor* to_message) {
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS &&
+      from_file != to_message->file()) {
+    // Cross-file ref in CommonJS needs to use the module alias instead of
+    // the global name.
+    return ModuleAlias(to_message->file()->name()) + "." + to_message->name();
+  } else {
+    // Within a single file we use a full name.
+    return GetPath(options, to_message);
+  }
+}
+
+string SubmessageTypeRef(const GeneratorOptions& options,
+                         const FieldDescriptor* field) {
+  GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+  return MaybeCrossFileRef(options, field->file(), field->message_type());
+}
+
+// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
+// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
+// and with reserved words triggering a "pb_" prefix.
+// - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
+// (use the name directly), then append "List" if appropriate, then append "$"
+// if resulting name is equal to a reserved word.
+// - Enums: just uppercase.
+
+// Locale-independent version of ToLower that deals only with ASCII A-Z.
+char ToLowerASCII(char c) {
+  if (c >= 'A' && c <= 'Z') {
+    return (c - 'A') + 'a';
+  } else {
+    return c;
+  }
+}
+
+vector<string> ParseLowerUnderscore(const string& input) {
+  vector<string> words;
+  string running = "";
+  for (int i = 0; i < input.size(); i++) {
+    if (input[i] == '_') {
+      if (!running.empty()) {
+        words.push_back(running);
+        running.clear();
+      }
+    } else {
+      running += ToLowerASCII(input[i]);
+    }
+  }
+  if (!running.empty()) {
+    words.push_back(running);
+  }
+  return words;
+}
+
+vector<string> ParseUpperCamel(const string& input) {
+  vector<string> words;
+  string running = "";
+  for (int i = 0; i < input.size(); i++) {
+    if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
+      words.push_back(running);
+      running.clear();
+    }
+    running += ToLowerASCII(input[i]);
+  }
+  if (!running.empty()) {
+    words.push_back(running);
+  }
+  return words;
+}
+
+string ToLowerCamel(const vector<string>& words) {
+  string result;
+  for (int i = 0; i < words.size(); i++) {
+    string word = words[i];
+    if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) {
+      word[0] = (word[0] - 'A') + 'a';
+    } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) {
+      word[0] = (word[0] - 'a') + 'A';
+    }
+    result += word;
+  }
+  return result;
+}
+
+string ToUpperCamel(const vector<string>& words) {
+  string result;
+  for (int i = 0; i < words.size(); i++) {
+    string word = words[i];
+    if (word[0] >= 'a' && word[0] <= 'z') {
+      word[0] = (word[0] - 'a') + 'A';
+    }
+    result += word;
+  }
+  return result;
+}
+
+// Based on code from descriptor.cc (Thanks Kenton!)
+// Uppercases the entire string, turning ValueName into
+// VALUENAME.
+string ToEnumCase(const string& input) {
+  string result;
+  result.reserve(input.size());
+
+  for (int i = 0; i < input.size(); i++) {
+    if ('a' <= input[i] && input[i] <= 'z') {
+      result.push_back(input[i] - 'a' + 'A');
+    } else {
+      result.push_back(input[i]);
+    }
+  }
+
+  return result;
+}
+
+string ToFileName(const string& input) {
+  string result;
+  result.reserve(input.size());
+
+  for (int i = 0; i < input.size(); i++) {
+    if ('A' <= input[i] && input[i] <= 'Z') {
+      result.push_back(input[i] - 'A' + 'a');
+    } else {
+      result.push_back(input[i]);
+    }
+  }
+
+  return result;
+}
+
+// When we're generating one output file per type name, this is the filename
+// that top-level extensions should go in.
+string GetExtensionFileName(const GeneratorOptions& options,
+                            const FileDescriptor* file) {
+  return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetMessageFileName(const GeneratorOptions& options,
+                          const Descriptor* desc) {
+  return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetEnumFileName(const GeneratorOptions& options,
+                       const EnumDescriptor* desc) {
+  return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
+// Returns the message/response ID, if set.
+string GetMessageId(const Descriptor* desc) {
+  return string();
+}
+
+bool IgnoreExtensionField(const FieldDescriptor* field) {
+  // Exclude descriptor extensions from output "to avoid clutter" (from original
+  // codegen).
+  return field->is_extension() &&
+         field->containing_type()->file()->name() ==
+             "google/protobuf/descriptor.proto";
+}
+
+
+// Used inside Google only -- do not remove.
+bool IsResponse(const Descriptor* desc) { return false; }
+
+bool IgnoreField(const FieldDescriptor* field) {
+  return IgnoreExtensionField(field);
+}
+
+
+// Does JSPB ignore this entire oneof? True only if all fields are ignored.
+bool IgnoreOneof(const OneofDescriptor* oneof) {
+  for (int i = 0; i < oneof->field_count(); i++) {
+    if (!IgnoreField(oneof->field(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+string JSIdent(const FieldDescriptor* field,
+               bool is_upper_camel,
+               bool is_map) {
+  string result;
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    result = is_upper_camel ?
+        ToUpperCamel(ParseUpperCamel(field->message_type()->name())) :
+        ToLowerCamel(ParseUpperCamel(field->message_type()->name()));
+  } else {
+    result = is_upper_camel ?
+        ToUpperCamel(ParseLowerUnderscore(field->name())) :
+        ToLowerCamel(ParseLowerUnderscore(field->name()));
+  }
+  if (is_map) {
+    result += "Map";
+  } else if (field->is_repeated()) {
+    result += "List";
+  }
+  return result;
+}
+
+string JSObjectFieldName(const FieldDescriptor* field) {
+  string name = JSIdent(
+      field,
+      /* is_upper_camel = */ false,
+      /* is_map = */ false);
+  if (IsReserved(name)) {
+    name = "pb_" + name;
+  }
+  return name;
+}
+
+string JSByteGetterSuffix(BytesMode bytes_mode) {
+  switch (bytes_mode) {
+    case BYTES_DEFAULT:
+      return "";
+    case BYTES_B64:
+      return "B64";
+    case BYTES_U8:
+      return "U8";
+    default:
+      assert(false);
+  }
+}
+
+// Returns the field name as a capitalized portion of a getter/setter method
+// name, e.g. MyField for .getMyField().
+string JSGetterName(const FieldDescriptor* field,
+                    BytesMode bytes_mode = BYTES_DEFAULT) {
+  string name = JSIdent(field,
+                        /* is_upper_camel = */ true,
+                        /* is_map = */ false);
+  if (field->type() == FieldDescriptor::TYPE_BYTES) {
+    string suffix = JSByteGetterSuffix(bytes_mode);
+    if (!suffix.empty()) {
+      name += "_as" + suffix;
+    }
+  }
+  if (name == "Extension" || name == "JsPbMessageId") {
+    // Avoid conflicts with base-class names.
+    name += "$";
+  }
+  return name;
+}
+
+string JSMapGetterName(const FieldDescriptor* field) {
+  return JSIdent(field,
+                 /* is_upper_camel = */ true,
+                 /* is_map = */ true);
+}
+
+
+
+string JSOneofName(const OneofDescriptor* oneof) {
+  return ToUpperCamel(ParseLowerUnderscore(oneof->name()));
+}
+
+// Returns the index corresponding to this field in the JSPB array (underlying
+// data storage array).
+string JSFieldIndex(const FieldDescriptor* field) {
+  // Determine whether this field is a member of a group. Group fields are a bit
+  // wonky: their "containing type" is a message type created just for the
+  // group, and that type's parent type has a field with the group-message type
+  // as its message type and TYPE_GROUP as its field type. For such fields, the
+  // index we use is relative to the field number of the group submessage field.
+  // For all other fields, we just use the field number.
+  const Descriptor* containing_type = field->containing_type();
+  const Descriptor* parent_type = containing_type->containing_type();
+  if (parent_type != NULL) {
+    for (int i = 0; i < parent_type->field_count(); i++) {
+      if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP &&
+          parent_type->field(i)->message_type() == containing_type) {
+        return SimpleItoa(field->number() - parent_type->field(i)->number());
+      }
+    }
+  }
+  return SimpleItoa(field->number());
+}
+
+string JSOneofIndex(const OneofDescriptor* oneof) {
+  int index = -1;
+  for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) {
+    const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i);
+    // If at least one field in this oneof is not JSPB-ignored, count the oneof.
+    for (int j = 0; j < o->field_count(); j++) {
+      const FieldDescriptor* f = o->field(j);
+      if (!IgnoreField(f)) {
+        index++;
+        break;  // inner loop
+      }
+    }
+    if (o == oneof) {
+      break;
+    }
+  }
+  return SimpleItoa(index);
+}
+
+// Decodes a codepoint in \x0000 -- \xFFFF.
+uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
+  if (*length == 0) {
+    return 0;
+  }
+  size_t expected = 0;
+  if ((*bytes & 0x80) == 0) {
+    expected = 1;
+  } else if ((*bytes & 0xe0) == 0xc0) {
+    expected = 2;
+  } else if ((*bytes & 0xf0) == 0xe0) {
+    expected = 3;
+  } else {
+    // Too long -- don't accept.
+    *length = 0;
+    return 0;
+  }
+
+  if (*length < expected) {
+    // Not enough bytes -- don't accept.
+    *length = 0;
+    return 0;
+  }
+
+  *length = expected;
+  switch (expected) {
+    case 1: return bytes[0];
+    case 2: return ((bytes[0] & 0x1F) << 6)  |
+                   ((bytes[1] & 0x3F) << 0);
+    case 3: return ((bytes[0] & 0x0F) << 12) |
+                   ((bytes[1] & 0x3F) << 6)  |
+                   ((bytes[2] & 0x3F) << 0);
+    default: return 0;
+  }
+}
+
+// Escapes the contents of a string to be included within double-quotes ("") in
+// JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
+// Returns false if |out| was truncated because |in| contained invalid UTF-8 or
+// codepoints outside the BMP.
+// TODO(lukestebbing): Support codepoints outside the BMP.
+bool EscapeJSString(const string& in, string* out) {
+  size_t decoded = 0;
+  for (size_t i = 0; i < in.size(); i += decoded) {
+    uint16 codepoint = 0;
+    // Decode the next UTF-8 codepoint.
+    size_t have_bytes = in.size() - i;
+    uint8 bytes[3] = {
+        static_cast<uint8>(in[i]),
+        static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
+        static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
+    };
+    codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
+    if (have_bytes == 0) {
+      return false;
+    }
+    decoded = have_bytes;
+
+    switch (codepoint) {
+      case '\'': *out += "\\x27"; break;
+      case '"': *out += "\\x22"; break;
+      case '<': *out += "\\x3c"; break;
+      case '=': *out += "\\x3d"; break;
+      case '>': *out += "\\x3e"; break;
+      case '&': *out += "\\x26"; break;
+      case '\b': *out += "\\b"; break;
+      case '\t': *out += "\\t"; break;
+      case '\n': *out += "\\n"; break;
+      case '\f': *out += "\\f"; break;
+      case '\r': *out += "\\r"; break;
+      case '\\': *out += "\\\\"; break;
+      default:
+        // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
+        // use a single Unicode codepoint escape if the output language is
+        // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
+        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
+        if (codepoint >= 0x20 && codepoint <= 0x7e) {
+          *out += static_cast<char>(codepoint);
+        } else if (codepoint >= 0x100) {
+          *out += StringPrintf("\\u%04x", codepoint);
+        } else {
+          *out += StringPrintf("\\x%02x", codepoint);
+        }
+        break;
+    }
+  }
+  return true;
+}
+
+string EscapeBase64(const string& in) {
+  static const char* kAlphabet =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  string result;
+
+  for (size_t i = 0; i < in.size(); i += 3) {
+    int value = (in[i] << 16) |
+        (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
+        (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0);
+    result += kAlphabet[(value >> 18) & 0x3f];
+    result += kAlphabet[(value >> 12) & 0x3f];
+    if ((i + 1) < in.size()) {
+      result += kAlphabet[(value >>  6) & 0x3f];
+    } else {
+      result += '=';
+    }
+    if ((i + 2) < in.size()) {
+      result += kAlphabet[(value >>  0) & 0x3f];
+    } else {
+      result += '=';
+    }
+  }
+
+  return result;
+}
+
+// Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the
+// original codegen's formatting (which is just .toString() on java.lang.Double
+// or java.lang.Float).
+string PostProcessFloat(string result) {
+  // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN.
+  if (result == "inf") {
+    return "Infinity";
+  } else if (result == "-inf") {
+    return "-Infinity";
+  } else if (result == "nan") {
+    return "NaN";
+  }
+
+  // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii)
+  // ensure that the mantissa (portion prior to the "e") has at least one
+  // fractional digit (after the decimal point), and (iii) strip any unnecessary
+  // leading zeroes and/or '+' signs from the exponent.
+  string::size_type exp_pos = result.find('e');
+  if (exp_pos != string::npos) {
+    string mantissa = result.substr(0, exp_pos);
+    string exponent = result.substr(exp_pos + 1);
+
+    // Add ".0" to mantissa if no fractional part exists.
+    if (mantissa.find('.') == string::npos) {
+      mantissa += ".0";
+    }
+
+    // Strip the sign off the exponent and store as |exp_neg|.
+    bool exp_neg = false;
+    if (!exponent.empty() && exponent[0] == '+') {
+      exponent = exponent.substr(1);
+    } else if (!exponent.empty() && exponent[0] == '-') {
+      exp_neg = true;
+      exponent = exponent.substr(1);
+    }
+
+    // Strip any leading zeroes off the exponent.
+    while (exponent.size() > 1 && exponent[0] == '0') {
+      exponent = exponent.substr(1);
+    }
+
+    return mantissa + "E" + string(exp_neg ? "-" : "") + exponent;
+  }
+
+  // Otherwise, this is an ordinary decimal number. Append ".0" if result has no
+  // decimal/fractional part in order to match output of original codegen.
+  if (result.find('.') == string::npos) {
+    result += ".0";
+  }
+
+  return result;
+}
+
+string FloatToString(float value) {
+  string result = SimpleFtoa(value);
+  return PostProcessFloat(result);
+}
+
+string DoubleToString(double value) {
+  string result = SimpleDtoa(value);
+  return PostProcessFloat(result);
+}
+
+string MaybeNumberString(const FieldDescriptor* field, const string& orig) {
+  return orig;
+}
+
+string JSFieldDefault(const FieldDescriptor* field) {
+  assert(field->has_default_value());
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return MaybeNumberString(
+          field, SimpleItoa(field->default_value_int32()));
+    case FieldDescriptor::CPPTYPE_UINT32:
+      // The original codegen is in Java, and Java protobufs store unsigned
+      // integer values as signed integer values. In order to exactly match the
+      // output, we need to reinterpret as base-2 signed. Ugh.
+      return MaybeNumberString(
+          field, SimpleItoa(static_cast<int32>(field->default_value_uint32())));
+    case FieldDescriptor::CPPTYPE_INT64:
+      return MaybeNumberString(
+          field, SimpleItoa(field->default_value_int64()));
+    case FieldDescriptor::CPPTYPE_UINT64:
+      // See above note for uint32 -- reinterpreting as signed.
+      return MaybeNumberString(
+          field, SimpleItoa(static_cast<int64>(field->default_value_uint64())));
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return SimpleItoa(field->default_value_enum()->number());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return FloatToString(field->default_value_float());
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return DoubleToString(field->default_value_double());
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->type() == FieldDescriptor::TYPE_STRING) {
+        string out;
+        bool is_valid = EscapeJSString(field->default_value_string(), &out);
+        if (!is_valid) {
+          // TODO(lukestebbing): Decide whether this should be a hard error.
+          GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
+                       << " was truncated since it contained invalid UTF-8 or"
+                          " codepoints outside the basic multilingual plane.";
+        }
+        return "\"" + out + "\"";
+      } else {  // Bytes
+        return "\"" + EscapeBase64(field->default_value_string()) + "\"";
+      }
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "null";
+  }
+  GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
+  return "";
+}
+
+string ProtoTypeName(const GeneratorOptions& options,
+                     const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::TYPE_INT32:
+      return "int32";
+    case FieldDescriptor::TYPE_UINT32:
+      return "uint32";
+    case FieldDescriptor::TYPE_SINT32:
+      return "sint32";
+    case FieldDescriptor::TYPE_FIXED32:
+      return "fixed32";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "sfixed32";
+    case FieldDescriptor::TYPE_INT64:
+      return "int64";
+    case FieldDescriptor::TYPE_UINT64:
+      return "uint64";
+    case FieldDescriptor::TYPE_SINT64:
+      return "sint64";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "fixed64";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "sfixed64";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::TYPE_STRING:
+      return "string";
+    case FieldDescriptor::TYPE_BYTES:
+      return "bytes";
+    case FieldDescriptor::TYPE_GROUP:
+      return GetPath(options, field->message_type());
+    case FieldDescriptor::TYPE_ENUM:
+      return GetPath(options, field->enum_type());
+    case FieldDescriptor::TYPE_MESSAGE:
+      return GetPath(options, field->message_type());
+    default:
+      return "";
+  }
+}
+
+string JSIntegerTypeName(const FieldDescriptor* field) {
+  return "number";
+}
+
+string JSStringTypeName(const GeneratorOptions& options,
+                        const FieldDescriptor* field,
+                        BytesMode bytes_mode) {
+  if (field->type() == FieldDescriptor::TYPE_BYTES) {
+    switch (bytes_mode) {
+      case BYTES_DEFAULT:
+        return "(string|Uint8Array)";
+      case BYTES_B64:
+        return "string";
+      case BYTES_U8:
+        return "Uint8Array";
+      default:
+        assert(false);
+    }
+  }
+  return "string";
+}
+
+string JSTypeName(const GeneratorOptions& options,
+                  const FieldDescriptor* field,
+                  BytesMode bytes_mode) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "boolean";
+    case FieldDescriptor::CPPTYPE_INT32:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_INT64:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "number";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "number";
+    case FieldDescriptor::CPPTYPE_STRING:
+      return JSStringTypeName(options, field, bytes_mode);
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return GetPath(options, field->enum_type());
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return GetPath(options, field->message_type());
+    default:
+      return "";
+  }
+}
+
+bool HasFieldPresence(const FieldDescriptor* field);
+
+string JSFieldTypeAnnotation(const GeneratorOptions& options,
+                             const FieldDescriptor* field,
+                             bool force_optional,
+                             bool force_present,
+                             bool singular_if_not_packed,
+                             BytesMode bytes_mode = BYTES_DEFAULT) {
+  bool is_primitive =
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
+       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+        (field->type() != FieldDescriptor::TYPE_BYTES ||
+            bytes_mode == BYTES_B64));
+
+  string jstype = JSTypeName(options, field, bytes_mode);
+
+  if (field->is_repeated() &&
+      (field->is_packed() || !singular_if_not_packed)) {
+    if (field->type() == FieldDescriptor::TYPE_BYTES &&
+        bytes_mode == BYTES_DEFAULT) {
+      jstype = "(Array<!Uint8Array>|Array<string>)";
+    } else {
+      if (!is_primitive) {
+        jstype = "!" + jstype;
+      }
+      jstype = "Array.<" + jstype + ">";
+    }
+    if (!force_optional) {
+      jstype = "!" + jstype;
+    }
+  }
+
+  if (field->is_optional() && is_primitive &&
+      (!field->has_default_value() || force_optional) && !force_present) {
+    jstype += "?";
+  } else if (field->is_required() && !is_primitive && !force_optional) {
+    jstype = "!" + jstype;
+  }
+
+  if (force_optional && HasFieldPresence(field)) {
+    jstype += "|undefined";
+  }
+  if (force_present && jstype[0] != '!' && !is_primitive) {
+    jstype = "!" + jstype;
+  }
+
+  return jstype;
+}
+
+string JSBinaryReaderMethodType(const FieldDescriptor* field) {
+  string name = field->type_name();
+  if (name[0] >= 'a' && name[0] <= 'z') {
+    name[0] = (name[0] - 'a') + 'A';
+  }
+
+  return name;
+}
+
+string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
+                                   bool is_writer) {
+  string name = JSBinaryReaderMethodType(field);
+  if (field->is_packed()) {
+    name = "Packed" + name;
+  } else if (is_writer && field->is_repeated()) {
+    name = "Repeated" + name;
+  }
+  return name;
+}
+
+string JSBinaryReaderMethodName(const FieldDescriptor* field) {
+  return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+}
+
+string JSBinaryWriterMethodName(const FieldDescriptor* field) {
+  return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+}
+
+string JSReturnClause(const FieldDescriptor* desc) {
+  return "";
+}
+
+string JSReturnDoc(const GeneratorOptions& options,
+                   const FieldDescriptor* desc) {
+  return "";
+}
+
+bool HasRepeatedFields(const Descriptor* desc) {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->is_repeated()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static const char* kRepeatedFieldArrayName = ".repeatedFields_";
+
+string RepeatedFieldsArrayName(const GeneratorOptions& options,
+                               const Descriptor* desc) {
+  return HasRepeatedFields(desc) ?
+      (GetPath(options, desc) + kRepeatedFieldArrayName) : "null";
+}
+
+bool HasOneofFields(const Descriptor* desc) {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->containing_oneof()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static const char* kOneofGroupArrayName = ".oneofGroups_";
+
+string OneofFieldsArrayName(const GeneratorOptions& options,
+                            const Descriptor* desc) {
+  return HasOneofFields(desc) ?
+      (GetPath(options, desc) + kOneofGroupArrayName) : "null";
+}
+
+string RepeatedFieldNumberList(const Descriptor* desc) {
+  std::vector<string> numbers;
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->is_repeated()) {
+      numbers.push_back(JSFieldIndex(desc->field(i)));
+    }
+  }
+  return "[" + Join(numbers, ",") + "]";
+}
+
+string OneofGroupList(const Descriptor* desc) {
+  // List of arrays (one per oneof), each of which is a list of field indices
+  std::vector<string> oneof_entries;
+  for (int i = 0; i < desc->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = desc->oneof_decl(i);
+    if (IgnoreOneof(oneof)) {
+      continue;
+    }
+
+    std::vector<string> oneof_fields;
+    for (int j = 0; j < oneof->field_count(); j++) {
+      if (IgnoreField(oneof->field(j))) {
+        continue;
+      }
+      oneof_fields.push_back(JSFieldIndex(oneof->field(j)));
+    }
+    oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]");
+  }
+  return "[" + Join(oneof_entries, ",") + "]";
+}
+
+string JSOneofArray(const GeneratorOptions& options,
+                    const FieldDescriptor* field) {
+  return OneofFieldsArrayName(options, field->containing_type()) + "[" +
+      JSOneofIndex(field->containing_oneof()) + "]";
+}
+
+string RelativeTypeName(const FieldDescriptor* field) {
+  assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
+         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+  // For a field with an enum or message type, compute a name relative to the
+  // path name of the message type containing this field.
+  string package = field->file()->package();
+  string containing_type = field->containing_type()->full_name() + ".";
+  string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) ?
+      field->enum_type()->full_name() : field->message_type()->full_name();
+
+  // |prefix| is advanced as we find separators '.' past the common package
+  // prefix that yield common prefixes in the containing type's name and this
+  // type's name.
+  int prefix = 0;
+  for (int i = 0; i < type.size() && i < containing_type.size(); i++) {
+    if (type[i] != containing_type[i]) {
+      break;
+    }
+    if (type[i] == '.' && i >= package.size()) {
+      prefix = i + 1;
+    }
+  }
+
+  return type.substr(prefix);
+}
+
+string JSExtensionsObjectName(const GeneratorOptions& options,
+                              const FileDescriptor* from_file,
+                              const Descriptor* desc) {
+  if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
+    // TODO(haberman): fix this for the IMPORT_COMMONJS case.
+    return "jspb.Message.messageSetExtensions";
+  } else {
+    return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
+  }
+}
+
+string FieldDefinition(const GeneratorOptions& options,
+                       const FieldDescriptor* field) {
+  string qualifier = field->is_repeated() ? "repeated" :
+      (field->is_optional() ? "optional" : "required");
+  string type, name;
+  if (field->type() == FieldDescriptor::TYPE_ENUM ||
+      field->type() == FieldDescriptor::TYPE_MESSAGE) {
+    type = RelativeTypeName(field);
+    name = field->name();
+  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    type = "group";
+    name = field->message_type()->name();
+  } else {
+    type = ProtoTypeName(options, field);
+    name = field->name();
+  }
+  return StringPrintf("%s %s %s = %d;",
+                      qualifier.c_str(),
+                      type.c_str(),
+                      name.c_str(),
+                      field->number());
+}
+
+string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
+  string comments;
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
+    comments +=
+        " * Note that Boolean fields may be set to 0/1 when serialized from "
+        "a Java server.\n"
+        " * You should avoid comparisons like {@code val === true/false} in "
+        "those cases.\n";
+  }
+  if (field->is_repeated()) {
+    comments +=
+        " * If you change this array by adding, removing or replacing "
+        "elements, or if you\n"
+        " * replace the array itself, then you must call the setter to "
+        "update it.\n";
+  }
+  if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
+    comments +=
+        " * Note that Uint8Array is not supported on all browsers.\n"
+        " * @see http://caniuse.com/Uint8Array\n";
+  }
+  return comments;
+}
+
+bool ShouldGenerateExtension(const FieldDescriptor* field) {
+  return
+      field->is_extension() &&
+      !IgnoreField(field);
+}
+
+bool HasExtensions(const Descriptor* desc) {
+  for (int i = 0; i < desc->extension_count(); i++) {
+    if (ShouldGenerateExtension(desc->extension(i))) {
+      return true;
+    }
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    if (HasExtensions(desc->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool HasExtensions(const FileDescriptor* file) {
+  for (int i = 0; i < file->extension_count(); i++) {
+    if (ShouldGenerateExtension(file->extension(i))) {
+      return true;
+    }
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (HasExtensions(file->message_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsExtendable(const Descriptor* desc) {
+  return desc->extension_range_count() > 0;
+}
+
+// Returns the max index in the underlying data storage array beyond which the
+// extension object is used.
+string GetPivot(const Descriptor* desc) {
+  static const int kDefaultPivot = (1 << 29);  // max field number (29 bits)
+
+  // Find the max field number
+  int max_field_number = 0;
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (!IgnoreField(desc->field(i)) &&
+        desc->field(i)->number() > max_field_number) {
+      max_field_number = desc->field(i)->number();
+    }
+  }
+
+  int pivot = -1;
+  if (IsExtendable(desc)) {
+    pivot = ((max_field_number + 1) < kDefaultPivot) ?
+        (max_field_number + 1) : kDefaultPivot;
+  }
+
+  return SimpleItoa(pivot);
+}
+
+// Returns true for fields that represent "null" as distinct from the default
+// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
+bool HasFieldPresence(const FieldDescriptor* field) {
+  return
+      (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
+      (field->containing_oneof() != NULL) ||
+      (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3);
+}
+
+// For proto3 fields without presence, returns a string representing the default
+// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more
+// information.
+string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      return "0";
+    }
+
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "0";
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "false";
+
+    case FieldDescriptor::CPPTYPE_STRING:  // includes BYTES
+      return "\"\"";
+
+    default:
+      // MESSAGE is handled separately.
+      assert(false);
+      return "";
+  }
+}
+
+// We use this to implement the semantics that same file can be generated
+// multiple times, but the last one wins.  We never actually write the files,
+// but we keep a set of which descriptors were the final one for a given
+// filename.
+class FileDeduplicator {
+ public:
+  explicit FileDeduplicator(const GeneratorOptions& options)
+      : error_on_conflict_(options.error_on_name_conflict) {}
+
+  bool AddFile(const string& filename, const void* desc, string* error) {
+    if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
+      if (error_on_conflict_) {
+        *error = "Name conflict: file name " + filename +
+                 " would be generated by two descriptors";
+        return false;
+      }
+      allowed_descs_.erase(descs_by_filename_[filename]);
+    }
+
+    descs_by_filename_[filename] = desc;
+    allowed_descs_.insert(desc);
+    return true;
+  }
+
+  void GetAllowedSet(set<const void*>* allowed_set) {
+    *allowed_set = allowed_descs_;
+  }
+
+ private:
+  bool error_on_conflict_;
+  map<string, const void*> descs_by_filename_;
+  set<const void*> allowed_descs_;
+};
+
+void DepthFirstSearch(const FileDescriptor* file,
+                      vector<const FileDescriptor*>* list,
+                      set<const FileDescriptor*>* seen) {
+  if (!seen->insert(file).second) {
+    return;
+  }
+
+  // Add all dependencies.
+  for (int i = 0; i < file->dependency_count(); i++) {
+    DepthFirstSearch(file->dependency(i), list, seen);
+  }
+
+  // Add this file.
+  list->push_back(file);
+}
+
+// A functor for the predicate to remove_if() below.  Returns true if a given
+// FileDescriptor is not in the given set.
+class NotInSet {
+ public:
+  explicit NotInSet(const set<const FileDescriptor*>& file_set)
+      : file_set_(file_set) {}
+
+  bool operator()(const FileDescriptor* file) {
+    return file_set_.count(file) == 0;
+  }
+
+ private:
+  const set<const FileDescriptor*>& file_set_;
+};
+
+// This function generates an ordering of the input FileDescriptors that matches
+// the logic of the old code generator.  The order is significant because two
+// different input files can generate the same output file, and the last one
+// needs to win.
+void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input,
+                           vector<const FileDescriptor*>* ordered) {
+  // First generate an ordering of all reachable files (including dependencies)
+  // with depth-first search.  This mimics the behavior of --include_imports,
+  // which is what the old codegen used.
+  ordered->clear();
+  set<const FileDescriptor*> seen;
+  set<const FileDescriptor*> input_set;
+  for (int i = 0; i < input.size(); i++) {
+    DepthFirstSearch(input[i], ordered, &seen);
+    input_set.insert(input[i]);
+  }
+
+  // Now remove the entries that are not actually in our input list.
+  ordered->erase(
+      std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
+      ordered->end());
+}
+
+// If we're generating code in file-per-type mode, avoid overwriting files
+// by choosing the last descriptor that writes each filename and permitting
+// only those to generate code.
+
+bool GenerateJspbAllowedSet(const GeneratorOptions& options,
+                            const vector<const FileDescriptor*>& files,
+                            set<const void*>* allowed_set,
+                            string* error) {
+  vector<const FileDescriptor*> files_ordered;
+  GenerateJspbFileOrder(files, &files_ordered);
+
+  // Choose the last descriptor for each filename.
+  FileDeduplicator dedup(options);
+  for (int i = 0; i < files_ordered.size(); i++) {
+    for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
+      const Descriptor* desc = files_ordered[i]->message_type(j);
+      if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
+        return false;
+      }
+    }
+    for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
+      const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
+      if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
+        return false;
+      }
+    }
+
+    // Pull out all free-floating extensions and generate files for those too.
+    bool has_extension = false;
+
+    for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
+      if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
+        has_extension = true;
+      }
+    }
+
+    if (has_extension) {
+      if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
+                         files_ordered[i], error)) {
+        return false;
+      }
+    }
+  }
+
+  dedup.GetAllowedSet(allowed_set);
+
+  return true;
+}
+
+}  // anonymous namespace
+
+void Generator::GenerateHeader(const GeneratorOptions& options,
+                               io::Printer* printer) const {
+  printer->Print("/**\n"
+                 " * @fileoverview\n"
+                 " * @enhanceable\n"
+                 " * @public\n"
+                 " */\n"
+                 "// GENERATED CODE -- DO NOT EDIT!\n"
+                 "\n");
+}
+
+void Generator::FindProvidesForFile(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const FileDescriptor* file,
+                                    std::set<string>* provided) const {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    FindProvidesForMessage(options, printer, file->message_type(i), provided);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    FindProvidesForEnum(options, printer, file->enum_type(i), provided);
+  }
+}
+
+void Generator::FindProvides(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const vector<const FileDescriptor*>& files,
+                             std::set<string>* provided) const {
+  for (int i = 0; i < files.size(); i++) {
+    FindProvidesForFile(options, printer, files[i], provided);
+  }
+
+  printer->Print("\n");
+}
+
+void Generator::FindProvidesForMessage(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const Descriptor* desc,
+    std::set<string>* provided) const {
+  string name = GetPath(options, desc);
+  provided->insert(name);
+
+  for (int i = 0; i < desc->enum_type_count(); i++) {
+    FindProvidesForEnum(options, printer, desc->enum_type(i),
+                        provided);
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    FindProvidesForMessage(options, printer, desc->nested_type(i),
+                           provided);
+  }
+}
+
+void Generator::FindProvidesForEnum(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const EnumDescriptor* enumdesc,
+                                    std::set<string>* provided) const {
+  string name = GetPath(options, enumdesc);
+  provided->insert(name);
+}
+
+void Generator::FindProvidesForFields(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const vector<const FieldDescriptor*>& fields,
+    std::set<string>* provided) const {
+  for (int i = 0; i < fields.size(); i++) {
+    const FieldDescriptor* field = fields[i];
+
+    if (IgnoreField(field)) {
+      continue;
+    }
+
+    string name =
+        GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+    provided->insert(name);
+  }
+}
+
+void Generator::GenerateProvides(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 std::set<string>* provided) const {
+  for (std::set<string>::iterator it = provided->begin();
+       it != provided->end(); ++it) {
+    printer->Print("goog.provide('$name$');\n",
+                   "name", *it);
+  }
+}
+
+void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const Descriptor* desc,
+                                           std::set<string>* provided) const {
+  std::set<string> required;
+  std::set<string> forwards;
+  bool have_message = false;
+  FindRequiresForMessage(options, desc,
+                         &required, &forwards, &have_message);
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ have_message,
+                       /* require_extension = */ HasExtensions(desc));
+}
+
+void Generator::GenerateRequiresForLibrary(
+    const GeneratorOptions& options, io::Printer* printer,
+    const vector<const FileDescriptor*>& files,
+    std::set<string>* provided) const {
+  GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE);
+  // For Closure imports we need to import every message type individually.
+  std::set<string> required;
+  std::set<string> forwards;
+  bool have_extensions = false;
+  bool have_message = false;
+
+  for (int i = 0; i < files.size(); i++) {
+    for (int j = 0; j < files[i]->message_type_count(); j++) {
+      FindRequiresForMessage(options,
+                             files[i]->message_type(j),
+                             &required, &forwards, &have_message);
+    }
+    if (!have_extensions && HasExtensions(files[i])) {
+      have_extensions = true;
+    }
+
+    for (int j = 0; j < files[i]->extension_count(); j++) {
+      const FieldDescriptor* extension = files[i]->extension(j);
+      if (IgnoreField(extension)) {
+        continue;
+      }
+      if (extension->containing_type()->full_name() !=
+        "google.protobuf.bridge.MessageSet") {
+        required.insert(GetPath(options, extension->containing_type()));
+      }
+      FindRequiresForField(options, extension, &required, &forwards);
+      have_extensions = true;
+    }
+  }
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ have_message,
+                       /* require_extension = */ have_extensions);
+}
+
+void Generator::GenerateRequiresForExtensions(
+    const GeneratorOptions& options, io::Printer* printer,
+    const vector<const FieldDescriptor*>& fields,
+    std::set<string>* provided) const {
+  std::set<string> required;
+  std::set<string> forwards;
+  for (int i = 0; i < fields.size(); i++) {
+    const FieldDescriptor* field = fields[i];
+    if (IgnoreField(field)) {
+      continue;
+    }
+    FindRequiresForExtension(options, field, &required, &forwards);
+  }
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ false,
+                       /* require_extension = */ fields.size() > 0);
+}
+
+void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
+                                     io::Printer* printer,
+                                     std::set<string>* required,
+                                     std::set<string>* forwards,
+                                     std::set<string>* provided,
+                                     bool require_jspb,
+                                     bool require_extension) const {
+  if (require_jspb) {
+    printer->Print(
+        "goog.require('jspb.Message');\n");
+    if (options.binary) {
+      printer->Print(
+          "goog.require('jspb.BinaryReader');\n"
+          "goog.require('jspb.BinaryWriter');\n");
+    }
+  }
+  if (require_extension) {
+    printer->Print(
+        "goog.require('jspb.ExtensionFieldInfo');\n");
+  }
+
+  std::set<string>::iterator it;
+  for (it = required->begin(); it != required->end(); ++it) {
+    if (provided->find(*it) != provided->end()) {
+      continue;
+    }
+    printer->Print("goog.require('$name$');\n",
+                   "name", *it);
+  }
+
+  printer->Print("\n");
+
+  for (it = forwards->begin(); it != forwards->end(); ++it) {
+    if (provided->find(*it) != provided->end()) {
+      continue;
+    }
+    printer->Print("goog.forwardDeclare('$name$');\n",
+                   "name", *it);
+  }
+}
+
+bool NamespaceOnly(const Descriptor* desc) {
+  return false;
+}
+
+void Generator::FindRequiresForMessage(
+    const GeneratorOptions& options,
+    const Descriptor* desc,
+    std::set<string>* required,
+    std::set<string>* forwards,
+    bool* have_message) const {
+
+
+  if (!NamespaceOnly(desc)) {
+    *have_message = true;
+    for (int i = 0; i < desc->field_count(); i++) {
+      const FieldDescriptor* field = desc->field(i);
+      if (IgnoreField(field)) {
+        continue;
+      }
+      FindRequiresForField(options, field, required, forwards);
+    }
+  }
+
+  for (int i = 0; i < desc->extension_count(); i++) {
+    const FieldDescriptor* field = desc->extension(i);
+    if (IgnoreField(field)) {
+      continue;
+    }
+    FindRequiresForExtension(options, field, required, forwards);
+  }
+
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    FindRequiresForMessage(options, desc->nested_type(i), required, forwards,
+                           have_message);
+  }
+}
+
+void Generator::FindRequiresForField(const GeneratorOptions& options,
+                                     const FieldDescriptor* field,
+                                     std::set<string>* required,
+                                     std::set<string>* forwards) const {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+        // N.B.: file-level extensions with enum type do *not* create
+        // dependencies, as per original codegen.
+        !(field->is_extension() && field->extension_scope() == NULL)) {
+      if (options.add_require_for_enums) {
+        required->insert(GetPath(options, field->enum_type()));
+      } else {
+        forwards->insert(GetPath(options, field->enum_type()));
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      required->insert(GetPath(options, field->message_type()));
+    }
+}
+
+void Generator::FindRequiresForExtension(const GeneratorOptions& options,
+                                         const FieldDescriptor* field,
+                                         std::set<string>* required,
+                                         std::set<string>* forwards) const {
+    if (field->containing_type()->full_name() != "google.protobuf.bridge.MessageSet") {
+      required->insert(GetPath(options, field->containing_type()));
+    }
+    FindRequiresForField(options, field, required, forwards);
+}
+
+void Generator::GenerateTestOnly(const GeneratorOptions& options,
+                                 io::Printer* printer) const {
+  if (options.testonly) {
+    printer->Print("goog.setTestOnly();\n\n");
+  }
+  printer->Print("\n");
+}
+
+void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
+                                        io::Printer* printer,
+                                        const FileDescriptor* file) const {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateClass(options, printer, file->message_type(i));
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnum(options, printer, file->enum_type(i));
+  }
+}
+
+void Generator::GenerateClass(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc) const {
+  if (!NamespaceOnly(desc)) {
+    printer->Print("\n");
+    GenerateClassConstructor(options, printer, desc);
+    GenerateClassFieldInfo(options, printer, desc);
+
+
+    GenerateClassToObject(options, printer, desc);
+    if (options.binary) {
+      // These must come *before* the extension-field info generation in
+      // GenerateClassRegistration so that references to the binary
+      // serialization/deserialization functions may be placed in the extension
+      // objects.
+      GenerateClassDeserializeBinary(options, printer, desc);
+      GenerateClassSerializeBinary(options, printer, desc);
+    }
+    GenerateClassClone(options, printer, desc);
+    GenerateClassRegistration(options, printer, desc);
+    GenerateClassFields(options, printer, desc);
+    if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
+      GenerateClassExtensionFieldInfo(options, printer, desc);
+    }
+
+    if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) {
+      for (int i = 0; i < desc->extension_count(); i++) {
+        GenerateExtension(options, printer, desc->extension(i));
+      }
+    }
+  }
+
+  // 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,
+                                         io::Printer* printer,
+                                         const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Generated by JsPbCodeGenerator.\n"
+      " * @param {Array=} opt_data Optional initial data array, typically "
+      "from a\n"
+      " * server response, or constructed directly in Javascript. The array "
+      "is used\n"
+      " * in place and becomes part of the constructed object. It is not "
+      "cloned.\n"
+      " * If no data is provided, the constructed object will be empty, but "
+      "still\n"
+      " * valid.\n"
+      " * @extends {jspb.Message}\n"
+      " * @constructor\n"
+      " */\n"
+      "$classname$ = function(opt_data) {\n",
+      "classname", GetPath(options, desc));
+  string message_id = GetMessageId(desc);
+  printer->Print(
+      "  jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, "
+      "$rptfields$, $oneoffields$);\n",
+      "messageId", !message_id.empty() ?
+                   ("'" + message_id + "'") :
+                   (IsResponse(desc) ? "''" : "0"),
+      "pivot", GetPivot(desc),
+      "rptfields", RepeatedFieldsArrayName(options, desc),
+      "oneoffields", OneofFieldsArrayName(options, desc));
+  printer->Print(
+      "};\n"
+      "goog.inherits($classname$, jspb.Message);\n"
+      "if (goog.DEBUG && !COMPILED) {\n"
+      "  $classname$.displayName = '$classname$';\n"
+      "}\n",
+      "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
+                                       io::Printer* printer,
+                                       const Descriptor* desc) const {
+  if (HasRepeatedFields(desc)) {
+    printer->Print(
+        "/**\n"
+        " * List of repeated fields within this message type.\n"
+        " * @private {!Array<number>}\n"
+        " * @const\n"
+        " */\n"
+        "$classname$$rptfieldarray$ = $rptfields$;\n"
+        "\n",
+        "classname", GetPath(options, desc),
+        "rptfieldarray", kRepeatedFieldArrayName,
+        "rptfields", RepeatedFieldNumberList(desc));
+  }
+
+  if (HasOneofFields(desc)) {
+    printer->Print(
+        "/**\n"
+        " * Oneof group definitions for this message. Each group defines the "
+        "field\n"
+        " * numbers belonging to that group. When of these fields' value is "
+        "set, all\n"
+        " * other fields in the group are cleared. During deserialization, if "
+        "multiple\n"
+        " * fields are encountered for a group, only the last value seen will "
+        "be kept.\n"
+        " * @private {!Array<!Array<number>>}\n"
+        " * @const\n"
+        " */\n"
+        "$classname$$oneofgrouparray$ = $oneofgroups$;\n"
+        "\n",
+        "classname", GetPath(options, desc),
+        "oneofgrouparray", kOneofGroupArrayName,
+        "oneofgroups", OneofGroupList(desc));
+
+    for (int i = 0; i < desc->oneof_decl_count(); i++) {
+      if (IgnoreOneof(desc->oneof_decl(i))) {
+        continue;
+      }
+      GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i));
+    }
+  }
+}
+
+void Generator::GenerateClassXid(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const Descriptor* desc) const {
+  printer->Print(
+      "\n"
+      "\n"
+      "$class$.prototype.messageXid = xid('$class$');\n",
+      "class", GetPath(options, desc));
+}
+
+void Generator::GenerateOneofCaseDefinition(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const OneofDescriptor* oneof) const {
+  printer->Print(
+      "/**\n"
+      " * @enum {number}\n"
+      " */\n"
+      "$classname$.$oneof$Case = {\n"
+      "  $upcase$_NOT_SET: 0",
+      "classname", GetPath(options, oneof->containing_type()),
+      "oneof", JSOneofName(oneof),
+      "upcase", ToEnumCase(oneof->name()));
+
+  for (int i = 0; i < oneof->field_count(); i++) {
+    if (IgnoreField(oneof->field(i))) {
+      continue;
+    }
+
+    printer->Print(
+        ",\n"
+        "  $upcase$: $number$",
+        "upcase", ToEnumCase(oneof->field(i)->name()),
+        "number", JSFieldIndex(oneof->field(i)));
+  }
+
+  printer->Print(
+      "\n"
+      "};\n"
+      "\n"
+      "/**\n"
+      " * @return {$class$.$oneof$Case}\n"
+      " */\n"
+      "$class$.prototype.get$oneof$Case = function() {\n"
+      "  return /** @type {$class$.$oneof$Case} */(jspb.Message."
+      "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n"
+      "};\n"
+      "\n",
+      "class", GetPath(options, oneof->containing_type()),
+      "oneof", JSOneofName(oneof),
+      "oneofindex", JSOneofIndex(oneof));
+}
+
+void Generator::GenerateClassToObject(const GeneratorOptions& options,
+                                      io::Printer* printer,
+                                      const Descriptor* desc) const {
+  printer->Print(
+      "\n"
+      "\n"
+      "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
+      "/**\n"
+      " * Creates an object representation of this proto suitable for use in "
+      "Soy templates.\n"
+      " * Field names that are reserved in JavaScript and will be renamed to "
+      "pb_name.\n"
+      " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
+      " * For the list of reserved names please see:\n"
+      " *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.\n"
+      " * @param {boolean=} opt_includeInstance Whether to include the JSPB "
+      "instance\n"
+      " *     for transitional soy proto support: http://goto/soy-param-"
+      "migration\n"
+      " * @return {!Object}\n"
+      " */\n"
+      "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
+      "  return $classname$.toObject(opt_includeInstance, this);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Static version of the {@see toObject} method.\n"
+      " * @param {boolean|undefined} includeInstance Whether to include the "
+      "JSPB\n"
+      " *     instance for transitional soy proto support:\n"
+      " *     http://goto/soy-param-migration\n"
+      " * @param {!$classname$} msg The msg instance to transform.\n"
+      " * @return {!Object}\n"
+      " */\n"
+      "$classname$.toObject = function(includeInstance, msg) {\n"
+      "  var f, obj = {",
+      "classname", GetPath(options, desc));
+
+  bool first = true;
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    if (IgnoreField(field)) {
+      continue;
+    }
+
+    if (!first) {
+      printer->Print(",\n    ");
+    } else {
+      printer->Print("\n    ");
+      first = false;
+    }
+
+    GenerateClassFieldToObject(options, printer, field);
+  }
+
+  if (!first) {
+    printer->Print("\n  };\n\n");
+  } else {
+    printer->Print("\n\n  };\n\n");
+  }
+
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "  jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
+        "obj,\n"
+        "      $extObject$, $class$.prototype.getExtension,\n"
+        "      includeInstance);\n",
+        "extObject", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  }
+
+  printer->Print(
+      "  if (includeInstance) {\n"
+      "    obj.$$jspbMessageInstance = msg;\n"
+      "  }\n"
+      "  return obj;\n"
+      "};\n"
+      "}\n"
+      "\n"
+      "\n",
+      "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const FieldDescriptor* field) const {
+  printer->Print("$fieldname$: ",
+                 "fieldname", JSObjectFieldName(field));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message field.
+    if (field->is_repeated()) {
+      {
+        printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
+                       "    $type$.toObject, includeInstance)",
+                       "getter", JSGetterName(field),
+                       "type", SubmessageTypeRef(options, field));
+      }
+    } else {
+      printer->Print("(f = msg.get$getter$()) && "
+                     "$type$.toObject(includeInstance, f)",
+                     "getter", JSGetterName(field),
+                     "type", SubmessageTypeRef(options, field));
+    }
+  } else {
+    // Simple field (singular or repeated).
+    if ((!HasFieldPresence(field) && !field->is_repeated()) ||
+        field->type() == FieldDescriptor::TYPE_BYTES) {
+      // Delegate to the generated get<field>() method in order not to duplicate
+      // the proto3-field-default-value or byte-coercion logic here.
+      printer->Print("msg.get$getter$()",
+                     "getter", JSGetterName(field, BYTES_B64));
+    } else {
+      if (field->has_default_value()) {
+        printer->Print("jspb.Message.getField(msg, $index$) == null ? "
+                       "$defaultValue$ : ",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(field));
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+          field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+        if (field->is_repeated()) {
+          printer->Print("jspb.Message.getRepeatedFloatingPointField("
+                         "msg, $index$)",
+                         "index", JSFieldIndex(field));
+        } else if (field->is_optional() && !field->has_default_value()) {
+          printer->Print("jspb.Message.getOptionalFloatingPointField("
+                         "msg, $index$)",
+                         "index", JSFieldIndex(field));
+        } else {
+          // Convert "NaN" to NaN.
+          printer->Print("+jspb.Message.getField(msg, $index$)",
+                         "index", JSFieldIndex(field));
+        }
+      } else {
+        printer->Print("jspb.Message.getField(msg, $index$)",
+                       "index", JSFieldIndex(field));
+      }
+    }
+  }
+}
+
+void Generator::GenerateClassFromObject(const GeneratorOptions& options,
+                                        io::Printer* printer,
+                                        const Descriptor* desc) const {
+  printer->Print(
+      "if (jspb.Message.GENERATE_FROM_OBJECT) {\n"
+      "/**\n"
+      " * Loads data from an object into a new instance of this proto.\n"
+      " * @param {!Object} obj The object representation of this proto to\n"
+      " *     load the data from.\n"
+      " * @return {!$classname$}\n"
+      " */\n"
+      "$classname$.fromObject = function(obj) {\n"
+      "  var f, msg = new $classname$();\n",
+      "classname", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    GenerateClassFieldFromObject(options, printer, field);
+  }
+
+  printer->Print(
+      "  return msg;\n"
+      "};\n"
+      "}\n");
+}
+
+void Generator::GenerateClassFieldFromObject(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message field (singular or repeated)
+    if (field->is_repeated()) {
+      {
+        printer->Print(
+            "  goog.isDef(obj.$name$) && "
+            "jspb.Message.setRepeatedWrapperField(\n"
+            "      msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
+            "        return $fieldclass$.fromObject(i);\n"
+            "      }));\n",
+            "name", JSObjectFieldName(field),
+            "index", JSFieldIndex(field),
+            "fieldclass", SubmessageTypeRef(options, field));
+      }
+    } else {
+      printer->Print(
+          "  goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
+          "      msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
+          "name", JSObjectFieldName(field),
+          "index", JSFieldIndex(field),
+          "fieldclass", SubmessageTypeRef(options, field));
+    }
+  } else {
+    // Simple (primitive) field.
+    printer->Print(
+        "  goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
+        "obj.$name$);\n",
+        "name", JSObjectFieldName(field),
+        "index", JSFieldIndex(field));
+  }
+}
+
+void Generator::GenerateClassClone(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Creates a deep clone of this proto. No data is shared with the "
+      "original.\n"
+      " * @return {!$name$} The clone.\n"
+      " */\n"
+      "$name$.prototype.cloneMessage = function() {\n"
+      "  return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n"
+      "};\n\n\n",
+      "name", GetPath(options, desc));
+}
+
+void Generator::GenerateClassRegistration(const GeneratorOptions& options,
+                                          io::Printer* printer,
+                                          const Descriptor* desc) const {
+  // Register any extensions defined inside this message type.
+  for (int i = 0; i < desc->extension_count(); i++) {
+    const FieldDescriptor* extension = desc->extension(i);
+    if (ShouldGenerateExtension(extension)) {
+      GenerateExtension(options, printer, extension);
+    }
+  }
+
+}
+
+void Generator::GenerateClassFields(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const Descriptor* desc) const {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (!IgnoreField(desc->field(i))) {
+      GenerateClassField(options, printer, desc->field(i));
+    }
+  }
+}
+
+void GenerateBytesWrapper(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const FieldDescriptor* field,
+                          BytesMode bytes_mode) {
+  string type =
+      JSFieldTypeAnnotation(options, field,
+                            /* force_optional = */ false,
+                            /* force_present = */ !HasFieldPresence(field),
+                            /* singular_if_not_packed = */ false,
+                            bytes_mode);
+  printer->Print(
+      "/**\n"
+      " * $fielddef$\n"
+      "$comment$"
+      " * This is a type-conversion wrapper around `get$defname$()`\n"
+      " * @return {$type$}\n"
+      " */\n"
+      "$class$.prototype.get$name$ = function() {\n"
+      "  return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
+      "      this.get$defname$()));\n"
+      "};\n"
+      "\n"
+      "\n",
+      "fielddef", FieldDefinition(options, field),
+      "comment", FieldComments(field, bytes_mode),
+      "type", type,
+      "class", GetPath(options, field->containing_type()),
+      "name", JSGetterName(field, bytes_mode),
+      "list", field->is_repeated() ? "List" : "",
+      "suffix", JSByteGetterSuffix(bytes_mode),
+      "defname", JSGetterName(field, BYTES_DEFAULT));
+}
+
+
+void Generator::GenerateClassField(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const FieldDescriptor* field) const {
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "/**\n"
+        " * $fielddef$\n"
+        "$comment$"
+        " * @return {$type$}\n"
+        " */\n",
+        "fielddef", FieldDefinition(options, field),
+        "comment", FieldComments(field, BYTES_DEFAULT),
+        "type", JSFieldTypeAnnotation(options, field,
+                                      /* force_optional = */ false,
+                                      /* force_present = */ false,
+                                      /* singular_if_not_packed = */ false));
+    printer->Print(
+        "$class$.prototype.get$name$ = function() {\n"
+        "  return /** @type{$type$} */ (\n"
+        "    jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
+        "$index$$required$));\n"
+        "};\n"
+        "\n"
+        "\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "type", JSFieldTypeAnnotation(options, field,
+                                      /* force_optional = */ false,
+                                      /* force_present = */ false,
+                                      /* singular_if_not_packed = */ false),
+        "rpt", (field->is_repeated() ? "Repeated" : ""),
+        "index", JSFieldIndex(field),
+        "wrapperclass", SubmessageTypeRef(options, field),
+        "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
+                     ", 1" : ""));
+    printer->Print(
+        "/** @param {$optionaltype$} value $returndoc$ */\n"
+        "$class$.prototype.set$name$ = function(value) {\n"
+        "  jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
+        "optionaltype",
+        JSFieldTypeAnnotation(options, field,
+                              /* force_optional = */ true,
+                              /* force_present = */ false,
+                              /* singular_if_not_packed = */ false),
+        "returndoc", JSReturnDoc(options, field),
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+        "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
+
+    printer->Print(
+        "this, $index$$oneofgroup$, value);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "index", JSFieldIndex(field),
+        "oneofgroup", (field->containing_oneof() ?
+                       (", " + JSOneofArray(options, field)) : ""),
+        "returnvalue", JSReturnClause(field));
+
+    printer->Print(
+        "$class$.prototype.clear$name$ = function() {\n"
+        "  this.set$name$($clearedvalue$);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+        "returnvalue", JSReturnClause(field));
+
+  } else {
+    bool untyped =
+        false;
+
+    // Simple (primitive) field, either singular or repeated.
+
+    // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type;
+    // at this point we "lie" to non-binary users and tell the the return
+    // type is always base64 string, pending a LSC to migrate to typed getters.
+    BytesMode bytes_mode =
+        field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ?
+            BYTES_B64 : BYTES_DEFAULT;
+    string typed_annotation =
+        JSFieldTypeAnnotation(options, field,
+                              /* force_optional = */ false,
+                              /* force_present = */ !HasFieldPresence(field),
+                              /* singular_if_not_packed = */ false,
+                              /* bytes_mode = */ bytes_mode);
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * @return {?} Raw field, untyped.\n"
+          " */\n");
+    } else {
+      printer->Print(
+          "/**\n"
+          " * $fielddef$\n"
+          "$comment$"
+          " * @return {$type$}\n"
+          " */\n",
+          "fielddef", FieldDefinition(options, field),
+          "comment", FieldComments(field, bytes_mode),
+          "type", typed_annotation);
+    }
+
+    printer->Print(
+        "$class$.prototype.get$name$ = function() {\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field));
+
+    if (untyped) {
+      printer->Print(
+          "  return ");
+    } else {
+      printer->Print(
+          "  return /** @type {$type$} */ (",
+          "type", typed_annotation);
+    }
+
+    // For proto3 fields without presence, use special getters that will return
+    // defaults when the field is unset, possibly constructing a value if
+    // required.
+    if (!HasFieldPresence(field) && !field->is_repeated()) {
+      printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)",
+                     "index", JSFieldIndex(field),
+                     "default", Proto3PrimitiveFieldDefault(field));
+    } else {
+      if (field->has_default_value()) {
+        printer->Print("jspb.Message.getField(this, $index$) == null ? "
+                       "$defaultValue$ : ",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(field));
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+          field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+        if (field->is_repeated()) {
+          printer->Print("jspb.Message.getRepeatedFloatingPointField("
+                         "this, $index$)",
+                         "index", JSFieldIndex(field));
+        } else if (field->is_optional() && !field->has_default_value()) {
+          printer->Print("jspb.Message.getOptionalFloatingPointField("
+                         "this, $index$)",
+                         "index", JSFieldIndex(field));
+        } else {
+          // Convert "NaN" to NaN.
+          printer->Print("+jspb.Message.getField(this, $index$)",
+                         "index", JSFieldIndex(field));
+        }
+      } else {
+        printer->Print("jspb.Message.getField(this, $index$)",
+                       "index", JSFieldIndex(field));
+      }
+    }
+
+    if (untyped) {
+      printer->Print(
+          ";\n"
+          "};\n"
+          "\n"
+          "\n");
+    } else {
+      printer->Print(
+          ");\n"
+          "};\n"
+          "\n"
+          "\n");
+    }
+
+    if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
+      GenerateBytesWrapper(options, printer, field, BYTES_B64);
+      GenerateBytesWrapper(options, printer, field, BYTES_U8);
+    }
+
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * @param {*} value $returndoc$\n"
+          " */\n",
+          "returndoc", JSReturnDoc(options, field));
+    } else {
+      printer->Print(
+          "/** @param {$optionaltype$} value $returndoc$ */\n",
+          "optionaltype",
+          JSFieldTypeAnnotation(options, field,
+                                /* force_optional = */ true,
+                                /* force_present = */ !HasFieldPresence(field),
+                                /* singular_if_not_packed = */ false),
+          "returndoc", JSReturnDoc(options, field));
+    }
+    printer->Print(
+        "$class$.prototype.set$name$ = function(value) {\n"
+        "  jspb.Message.set$oneoftag$Field(this, $index$",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+        "index", JSFieldIndex(field));
+    printer->Print(
+        "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "type",
+        untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
+        "typeclose", untyped ? ")" : "",
+        "oneofgroup",
+        (field->containing_oneof() ? (", " + JSOneofArray(options, field))
+                                   : ""),
+        "returnvalue", JSReturnClause(field), "rptvalueinit",
+        (field->is_repeated() ? " || []" : ""));
+
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * Clears the value. $returndoc$\n"
+          " */\n",
+          "returndoc", JSReturnDoc(options, field));
+    }
+
+    if (HasFieldPresence(field)) {
+      printer->Print(
+          "$class$.prototype.clear$name$ = function() {\n"
+          "  jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
+          "class", GetPath(options, field->containing_type()),
+          "name", JSGetterName(field),
+          "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+          "oneofgroup", (field->containing_oneof() ?
+                         (", " + JSOneofArray(options, field)) : ""),
+          "index", JSFieldIndex(field));
+      printer->Print(
+          "$clearedvalue$);$returnvalue$\n"
+          "};\n"
+          "\n"
+          "\n",
+          "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+          "returnvalue", JSReturnClause(field));
+    }
+  }
+}
+
+void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+                                                io::Printer* printer,
+                                                const Descriptor* desc) const {
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "\n"
+        "/**\n"
+        " * The extensions registered with this message class. This is a "
+        "map of\n"
+        " * extension field number to fieldInfo object.\n"
+        " *\n"
+        " * For example:\n"
+        " *     { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
+        "ctor: proto.example.MyMessage} }\n"
+        " *\n"
+        " * fieldName contains the JsCompiler renamed field name property "
+        "so that it\n"
+        " * works in OPTIMIZED mode.\n"
+        " *\n"
+        " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n"
+        " */\n"
+        "$class$.extensions = {};\n"
+        "\n",
+        "class", GetPath(options, desc));
+  }
+}
+
+
+void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
+                                               io::Printer* printer,
+                                               const Descriptor* desc) const {
+  // TODO(cfallin): Handle lazy decoding when requested by field option and/or
+  // by default for 'bytes' fields and packed repeated fields.
+
+  printer->Print(
+      "/**\n"
+      " * Deserializes binary data (in protobuf wire format).\n"
+      " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n"
+      " * @return {!$class$}\n"
+      " */\n"
+      "$class$.deserializeBinary = function(bytes) {\n"
+      "  var reader = new jspb.BinaryReader(bytes);\n"
+      "  var msg = new $class$;\n"
+      "  return $class$.deserializeBinaryFromReader(msg, reader);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Deserializes binary data (in protobuf wire format) from the\n"
+      " * given reader into the given message object.\n"
+      " * @param {!$class$} msg The message object to deserialize into.\n"
+      " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n"
+      " * @return {!$class$}\n"
+      " */\n"
+      "$class$.deserializeBinaryFromReader = function(msg, reader) {\n"
+      "  while (reader.nextField()) {\n"
+      "    if (reader.isEndGroup()) {\n"
+      "      break;\n"
+      "    }\n"
+      "    var field = reader.getFieldNumber();\n"
+      "    switch (field) {\n",
+      "class", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
+  }
+
+  printer->Print(
+      "    default:\n");
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "      jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
+        "        $class$.prototype.getExtension,\n"
+        "        $class$.prototype.setExtension);\n"
+        "      break;\n",
+        "extobj", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  } else {
+    printer->Print(
+        "      reader.skipField();\n"
+        "      break;\n");
+  }
+
+  printer->Print(
+      "    }\n"
+      "  }\n"
+      "  return msg;\n"
+      "};\n"
+      "\n"
+      "\n");
+}
+
+void Generator::GenerateClassDeserializeBinaryField(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+
+  printer->Print("    case $num$:\n",
+                 "num", SimpleItoa(field->number()));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "      var value = new $fieldclass$;\n"
+        "      reader.read$msgOrGroup$($grpfield$value,"
+        "$fieldclass$.deserializeBinaryFromReader);\n",
+        "fieldclass", SubmessageTypeRef(options, field),
+        "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                      "Group" : "Message",
+        "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                    (SimpleItoa(field->number()) + ", ") : "");
+  } else {
+    printer->Print(
+        "      var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
+        "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+                                           /* singular_if_not_packed = */ true,
+                                           BYTES_U8),
+        "reader", JSBinaryReaderMethodName(field));
+  }
+
+  if (field->is_repeated() && !field->is_packed()) {
+    // Repeated fields receive a |value| one at at a time; append to array
+    // returned by get$name$(). Annoyingly, we have to call 'set' after
+    // changing the array.
+    printer->Print("      msg.get$name$().push(value);\n", "name",
+                   JSGetterName(field));
+    printer->Print("      msg.set$name$(msg.get$name$());\n", "name",
+                   JSGetterName(field));
+  } else {
+    // Singular fields, and packed repeated fields, receive a |value| either as
+    // the field's value or as the array of all the field's values; set this as
+    // the field's value directly.
+    printer->Print(
+        "      msg.set$name$(value);\n",
+        "name", JSGetterName(field));
+  }
+
+  printer->Print("      break;\n");
+}
+
+void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
+                                             io::Printer* printer,
+                                             const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Class method variant: serializes the given message to binary data\n"
+      " * (in protobuf wire format), writing to the given BinaryWriter.\n"
+      " * @param {!$class$} message\n"
+      " * @param {!jspb.BinaryWriter} writer\n"
+      " */\n"
+      "$class$.serializeBinaryToWriter = function(message, "
+      "writer) {\n"
+      "  message.serializeBinaryToWriter(writer);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Serializes the message to binary data (in protobuf wire format).\n"
+      " * @return {!Uint8Array}\n"
+      " */\n"
+      "$class$.prototype.serializeBinary = function() {\n"
+      "  var writer = new jspb.BinaryWriter();\n"
+      "  this.serializeBinaryToWriter(writer);\n"
+      "  return writer.getResultBuffer();\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Serializes the message to binary data (in protobuf wire format),\n"
+      " * writing to the given BinaryWriter.\n"
+      " * @param {!jspb.BinaryWriter} writer\n"
+      " */\n"
+      "$class$.prototype.serializeBinaryToWriter = function (writer) {\n"
+      "  var f = undefined;\n",
+      "class", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    GenerateClassSerializeBinaryField(options, printer, desc->field(i));
+  }
+
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "  jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
+        "    $class$.prototype.getExtension);\n",
+        "extobj", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  }
+
+  printer->Print(
+      "};\n"
+      "\n"
+      "\n");
+}
+
+void Generator::GenerateClassSerializeBinaryField(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+  printer->Print(
+      "  f = this.get$name$();\n",
+      "name", JSGetterName(field, BYTES_U8));
+
+  if (field->is_repeated()) {
+    printer->Print(
+        "  if (f.length > 0) {\n");
+  } else {
+    if (HasFieldPresence(field)) {
+      printer->Print(
+          "  if (f != null) {\n");
+    } else {
+      // No field presence: serialize onto the wire only if value is
+      // non-default.  Defaults are documented here:
+      // https://goto.google.com/lhdfm
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+        case FieldDescriptor::CPPTYPE_INT64:
+        case FieldDescriptor::CPPTYPE_UINT32:
+        case FieldDescriptor::CPPTYPE_UINT64: {
+          {
+            printer->Print("  if (f !== 0) {\n");
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_ENUM:
+        case FieldDescriptor::CPPTYPE_FLOAT:
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          printer->Print(
+              "  if (f !== 0.0) {\n");
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          printer->Print(
+              "  if (f) {\n");
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          printer->Print(
+              "  if (f.length > 0) {\n");
+          break;
+        default:
+          assert(false);
+          break;
+      }
+    }
+  }
+
+  printer->Print(
+      "    writer.$writer$(\n"
+      "      $index$,\n"
+      "      f",
+      "writer", JSBinaryWriterMethodName(field),
+      "index", SimpleItoa(field->number()));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        ",\n"
+        "      $submsg$.serializeBinaryToWriter\n",
+        "submsg", SubmessageTypeRef(options, field));
+  } else {
+    printer->Print("\n");
+  }
+  printer->Print(
+      "    );\n"
+      "  }\n");
+}
+
+void Generator::GenerateEnum(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const EnumDescriptor* enumdesc) const {
+  printer->Print(
+      "/**\n"
+      " * @enum {number}\n"
+      " */\n"
+      "$name$ = {\n",
+      "name", GetPath(options, enumdesc));
+
+  for (int i = 0; i < enumdesc->value_count(); i++) {
+    const EnumValueDescriptor* value = enumdesc->value(i);
+    printer->Print(
+        "  $name$: $value$$comma$\n",
+        "name", ToEnumCase(value->name()),
+        "value", SimpleItoa(value->number()),
+        "comma", (i == enumdesc->value_count() - 1) ? "" : ",");
+  }
+
+  printer->Print(
+      "};\n"
+      "\n");
+}
+
+void Generator::GenerateExtension(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const FieldDescriptor* field) const {
+  string extension_scope =
+      (field->extension_scope() ?
+       GetPath(options, field->extension_scope()) :
+       GetPath(options, field->file()));
+
+  printer->Print(
+      "\n"
+      "/**\n"
+      " * A tuple of {field number, class constructor} for the extension\n"
+      " * field named `$name$`.\n"
+      " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
+      " */\n"
+      "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
+      "name", JSObjectFieldName(field),
+      "class", extension_scope,
+      "extensionType", JSFieldTypeAnnotation(
+          options, field,
+          /* force_optional = */ false,
+          /* force_present = */ true,
+          /* singular_if_not_packed = */ false));
+  printer->Print(
+      "    $index$,\n"
+      "    {$name$: 0},\n"
+      "    $ctor$,\n"
+      "     /** @type {?function((boolean|undefined),!jspb.Message=): "
+      "!Object} */ (\n"
+      "         $toObject$),\n"
+      "    $repeated$",
+      "index", SimpleItoa(field->number()),
+      "name", JSObjectFieldName(field),
+      "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+               SubmessageTypeRef(options, field) : string("null")),
+      "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+                   (SubmessageTypeRef(options, field) + ".toObject") :
+                   string("null")),
+      "repeated", (field->is_repeated() ? "1" : "0"));
+
+  if (options.binary) {
+    printer->Print(
+        ",\n"
+        "    jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
+        "    jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+        "    $binaryMessageSerializeFn$,\n"
+        "    $binaryMessageDeserializeFn$,\n"
+        "    $isPacked$);\n",
+        "binaryReaderFn", JSBinaryReaderMethodName(field),
+        "binaryWriterFn", JSBinaryWriterMethodName(field),
+        "binaryMessageSerializeFn",
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+        (SubmessageTypeRef(options, field) +
+         ".serializeBinaryToWriter") : "null",
+        "binaryMessageDeserializeFn",
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+        (SubmessageTypeRef(options, field) +
+         ".deserializeBinaryFromReader") : "null",
+        "isPacked", (field->is_packed() ? "true" : "false"));
+  } else {
+    printer->Print(");\n");
+  }
+
+  printer->Print(
+      "// This registers the extension field with the extended class, so that\n"
+      "// toObject() will function correctly.\n"
+      "$extendName$[$index$] = $class$.$name$;\n"
+      "\n",
+      "extendName", JSExtensionsObjectName(options, field->file(),
+                                           field->containing_type()),
+      "index", SimpleItoa(field->number()),
+      "class", extension_scope,
+      "name", JSObjectFieldName(field));
+}
+
+bool GeneratorOptions::ParseFromOptions(
+    const vector< pair< string, string > >& options,
+    string* error) {
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "add_require_for_enums") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for add_require_for_enums";
+        return false;
+      }
+      add_require_for_enums = true;
+    } else if (options[i].first == "binary") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for binary";
+        return false;
+      }
+      binary = true;
+    } else if (options[i].first == "testonly") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for testonly";
+        return false;
+      }
+      testonly = true;
+    } else if (options[i].first == "error_on_name_conflict") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for error_on_name_conflict";
+        return false;
+      }
+      error_on_name_conflict = true;
+    } else if (options[i].first == "output_dir") {
+      output_dir = options[i].second;
+    } else if (options[i].first == "namespace_prefix") {
+      namespace_prefix = options[i].second;
+    } else if (options[i].first == "library") {
+      library = options[i].second;
+    } else if (options[i].first == "import_style") {
+      if (options[i].second == "closure") {
+        import_style = IMPORT_CLOSURE;
+      } else if (options[i].second == "commonjs") {
+        import_style = IMPORT_COMMONJS;
+      } else if (options[i].second == "browser") {
+        import_style = IMPORT_BROWSER;
+      } else if (options[i].second == "es6") {
+        import_style = IMPORT_ES6;
+      } else {
+        *error = "Unknown import style " + options[i].second + ", expected " +
+                 "one of: closure, commonjs, browser, es6.";
+      }
+    } else {
+      // Assume any other option is an output directory, as long as it is a bare
+      // `key` rather than a `key=value` option.
+      if (options[i].second != "") {
+        *error = "Unknown option: " + options[i].first;
+        return false;
+      }
+      output_dir = options[i].first;
+    }
+  }
+
+  if (!library.empty() && import_style != IMPORT_CLOSURE) {
+    *error = "The library option should only be used for "
+             "import_style=closure";
+  }
+
+  return true;
+}
+
+void Generator::GenerateFilesInDepOrder(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const vector<const FileDescriptor*>& files) const {
+  // Build a std::set over all files so that the DFS can detect when it recurses
+  // into a dep not specified in the user's command line.
+  std::set<const FileDescriptor*> all_files(files.begin(), files.end());
+  // Track the in-progress set of files that have been generated already.
+  std::set<const FileDescriptor*> generated;
+  for (int i = 0; i < files.size(); i++) {
+    GenerateFileAndDeps(options, printer, files[i], &all_files, &generated);
+  }
+}
+
+void Generator::GenerateFileAndDeps(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FileDescriptor* root,
+    std::set<const FileDescriptor*>* all_files,
+    std::set<const FileDescriptor*>* generated) const {
+  // Skip if already generated.
+  if (generated->find(root) != generated->end()) {
+    return;
+  }
+  generated->insert(root);
+
+  // Generate all dependencies before this file's content.
+  for (int i = 0; i < root->dependency_count(); i++) {
+    const FileDescriptor* dep = root->dependency(i);
+    GenerateFileAndDeps(options, printer, dep, all_files, generated);
+  }
+
+  // Generate this file's content.  Only generate if the file is part of the
+  // original set requested to be generated; i.e., don't take all transitive
+  // deps down to the roots.
+  if (all_files->find(root) != all_files->end()) {
+    GenerateClassesAndEnums(options, printer, root);
+  }
+}
+
+void Generator::GenerateFile(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const FileDescriptor* file) const {
+  GenerateHeader(options, printer);
+
+  // Generate "require" statements.
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
+    printer->Print("var jspb = require('google-protobuf');\n");
+    printer->Print("var goog = jspb;\n");
+    printer->Print("var global = Function('return this')();\n\n");
+
+    for (int i = 0; i < file->dependency_count(); i++) {
+      const string& name = file->dependency(i)->name();
+      printer->Print(
+          "var $alias$ = require('$file$');\n",
+          "alias", ModuleAlias(name),
+          "file", GetRootPath(file->name()) + GetJSFilename(name));
+    }
+  }
+
+  // We aren't using Closure's import system, but we use goog.exportSymbol()
+  // to construct the expected tree of objects, eg.
+  //
+  //   goog.exportSymbol('foo.bar.Baz', null, this);
+  //
+  //   // Later generated code expects foo.bar = {} to exist:
+  //   foo.bar.Baz = function() { /* ... */ }
+  set<string> provided;
+
+  // Cover the case where this file declares extensions but no messages.
+  // This will ensure that the file-level object will be declared to hold
+  // the extensions.
+  for (int i = 0; i < file->extension_count(); i++) {
+    provided.insert(file->extension(i)->full_name());
+  }
+
+  FindProvidesForFile(options, printer, file, &provided);
+  for (std::set<string>::iterator it = provided.begin();
+       it != provided.end(); ++it) {
+    printer->Print("goog.exportSymbol('$name$', null, global);\n",
+                   "name", *it);
+  }
+
+  GenerateClassesAndEnums(options, printer, file);
+
+  // Extensions nested inside messages are emitted inside
+  // GenerateClassesAndEnums().
+  for (int i = 0; i < file->extension_count(); i++) {
+    GenerateExtension(options, printer, file->extension(i));
+  }
+
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
+    printer->Print("goog.object.extend(exports, $package$);\n",
+                   "package", GetPath(options, file));
+  }
+}
+
+bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
+                            const string& parameter,
+                            GeneratorContext* context,
+                            string* error) const {
+  vector< pair< string, string > > option_pairs;
+  ParseGeneratorParameter(parameter, &option_pairs);
+  GeneratorOptions options;
+  if (!options.ParseFromOptions(option_pairs, error)) {
+    return false;
+  }
+
+
+  // There are three schemes for where output files go:
+  //
+  // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file
+  // - import_style = IMPORT_CLOSURE, library empty: one output file per type
+  // - import_style != IMPORT_CLOSURE: one output file per .proto file
+  if (options.import_style == GeneratorOptions::IMPORT_CLOSURE &&
+      options.library != "") {
+    // All output should go in a single file.
+    string filename = options.output_dir + "/" + options.library + ".js";
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+    GOOGLE_CHECK(output.get());
+    io::Printer printer(output.get(), '$');
+
+    // Pull out all extensions -- we need these to generate all
+    // provides/requires.
+    vector<const FieldDescriptor*> extensions;
+    for (int i = 0; i < files.size(); i++) {
+      for (int j = 0; j < files[i]->extension_count(); j++) {
+        const FieldDescriptor* extension = files[i]->extension(j);
+        extensions.push_back(extension);
+      }
+    }
+
+    GenerateHeader(options, &printer);
+
+    std::set<string> provided;
+    FindProvides(options, &printer, files, &provided);
+    FindProvidesForFields(options, &printer, extensions, &provided);
+    GenerateProvides(options, &printer, &provided);
+    GenerateTestOnly(options, &printer);
+    GenerateRequiresForLibrary(options, &printer, files, &provided);
+
+    GenerateFilesInDepOrder(options, &printer, files);
+
+    for (int i = 0; i < extensions.size(); i++) {
+      if (ShouldGenerateExtension(extensions[i])) {
+        GenerateExtension(options, &printer, extensions[i]);
+      }
+    }
+
+    if (printer.failed()) {
+      return false;
+    }
+  } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
+    set<const void*> allowed_set;
+    if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
+      return false;
+    }
+
+    for (int i = 0; i < files.size(); i++) {
+      const FileDescriptor* file = files[i];
+      for (int j = 0; j < file->message_type_count(); j++) {
+        const Descriptor* desc = file->message_type(j);
+        if (allowed_set.count(desc) == 0) {
+          continue;
+        }
+
+        string filename = GetMessageFileName(options, desc);
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
+
+        GenerateHeader(options, &printer);
+
+        std::set<string> provided;
+        FindProvidesForMessage(options, &printer, desc, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+        GenerateRequiresForMessage(options, &printer, desc, &provided);
+
+        GenerateClass(options, &printer, desc);
+
+        if (printer.failed()) {
+          return false;
+        }
+      }
+      for (int j = 0; j < file->enum_type_count(); j++) {
+        const EnumDescriptor* enumdesc = file->enum_type(j);
+        if (allowed_set.count(enumdesc) == 0) {
+          continue;
+        }
+
+        string filename = GetEnumFileName(options, enumdesc);
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
+
+        GenerateHeader(options, &printer);
+
+        std::set<string> provided;
+        FindProvidesForEnum(options, &printer, enumdesc, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+
+        GenerateEnum(options, &printer, enumdesc);
+
+        if (printer.failed()) {
+          return false;
+        }
+      }
+      // File-level extensions (message-level extensions are generated under
+      // the enclosing message).
+      if (allowed_set.count(file) == 1) {
+        string filename = GetExtensionFileName(options, file);
+
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
+
+        GenerateHeader(options, &printer);
+
+        std::set<string> provided;
+        vector<const FieldDescriptor*> fields;
+
+        for (int j = 0; j < files[i]->extension_count(); j++) {
+          if (ShouldGenerateExtension(files[i]->extension(j))) {
+            fields.push_back(files[i]->extension(j));
+          }
+        }
+
+        FindProvidesForFields(options, &printer, fields, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+        GenerateRequiresForExtensions(options, &printer, fields, &provided);
+
+        for (int j = 0; j < files[i]->extension_count(); j++) {
+          if (ShouldGenerateExtension(files[i]->extension(j))) {
+            GenerateExtension(options, &printer, files[i]->extension(j));
+          }
+        }
+      }
+    }
+  } else {
+    // Generate one output file per input (.proto) file.
+
+    for (int i = 0; i < files.size(); i++) {
+      const google::protobuf::FileDescriptor* file = files[i];
+
+      string filename = options.output_dir + "/" + GetJSFilename(file->name());
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+      GOOGLE_CHECK(output.get());
+      io::Printer printer(output.get(), '$');
+
+      GenerateFile(options, &printer, file);
+
+      if (printer.failed()) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+}  // namespace js
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
new file mode 100755
index 0000000..6fd7ca5
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -0,0 +1,281 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+
+#include <string>
+#include <set>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class FileDescriptor;
+
+namespace io { class Printer; }
+
+namespace compiler {
+namespace js {
+
+struct GeneratorOptions {
+  // Add a `goog.requires()` call for each enum type used. If not set, a forward
+  // declaration with `goog.forwardDeclare` is produced instead.
+  bool add_require_for_enums;
+  // Set this as a test-only module via `goog.setTestOnly();`.
+  bool testonly;
+  // Output path.
+  string output_dir;
+  // Namespace prefix.
+  string namespace_prefix;
+  // Create a library with name <name>_lib.js rather than a separate .js file
+  // per type?
+  string library;
+  // Error if there are two types that would generate the same output file?
+  bool error_on_name_conflict;
+  // Enable binary-format support?
+  bool binary;
+  // What style of imports should be used.
+  enum ImportStyle {
+    IMPORT_CLOSURE,    // goog.require()
+    IMPORT_COMMONJS,   // require()
+    IMPORT_BROWSER,    // no import statements
+    IMPORT_ES6,        // import { member } from ''
+  } import_style;
+
+  GeneratorOptions()
+      : add_require_for_enums(false),
+        testonly(false),
+        output_dir("."),
+        namespace_prefix(""),
+        library(""),
+        error_on_name_conflict(false),
+        binary(false),
+        import_style(IMPORT_CLOSURE) {}
+
+  bool ParseFromOptions(
+      const vector< pair< string, string > >& options,
+      string* error);
+};
+
+class LIBPROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+  Generator() {}
+  virtual ~Generator() {}
+
+  virtual bool Generate(const FileDescriptor* file,
+                        const string& parameter,
+                        GeneratorContext* context,
+                        string* error) const {
+    *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+    return false;
+  }
+
+  virtual bool HasGenerateAll() const { return true; }
+
+  virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+                           const string& parameter,
+                           GeneratorContext* context,
+                           string* error) const;
+
+ private:
+  void GenerateHeader(const GeneratorOptions& options,
+                      io::Printer* printer) const;
+
+  // Generate goog.provides() calls.
+  void FindProvides(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const vector<const FileDescriptor*>& file,
+                    std::set<string>* provided) const;
+  void FindProvidesForFile(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const FileDescriptor* file,
+                           std::set<string>* provided) const;
+  void FindProvidesForMessage(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc,
+                              std::set<string>* provided) const;
+  void FindProvidesForEnum(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const EnumDescriptor* enumdesc,
+                           std::set<string>* provided) const;
+  // For extension fields at file scope.
+  void FindProvidesForFields(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const vector<const FieldDescriptor*>& fields,
+                             std::set<string>* provided) const;
+  // Print the goog.provides() found by the methods above.
+  void GenerateProvides(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        std::set<string>* provided) const;
+
+  // Generate goog.setTestOnly() if indicated.
+  void GenerateTestOnly(const GeneratorOptions& options,
+                        io::Printer* printer) const;
+
+  // Generate goog.requires() calls.
+  void GenerateRequiresForLibrary(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const vector<const FileDescriptor*>& files,
+                                  std::set<string>* provided) const;
+  void GenerateRequiresForMessage(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const Descriptor* desc,
+                        std::set<string>* provided) const;
+  // For extension fields at file scope.
+  void GenerateRequiresForExtensions(
+      const GeneratorOptions& options, io::Printer* printer,
+      const vector<const FieldDescriptor*>& fields,
+      std::set<string>* provided) const;
+  void GenerateRequiresImpl(const GeneratorOptions& options,
+                            io::Printer* printer,
+                            std::set<string>* required,
+                            std::set<string>* forwards,
+                            std::set<string>* provided,
+                            bool require_jspb,
+                            bool require_extension) const;
+  void FindRequiresForMessage(const GeneratorOptions& options,
+                              const Descriptor* desc,
+                              std::set<string>* required,
+                              std::set<string>* forwards,
+                              bool* have_message) const;
+  void FindRequiresForField(const GeneratorOptions& options,
+                            const FieldDescriptor* field,
+                            std::set<string>* required,
+                            std::set<string>* forwards) const;
+  void FindRequiresForExtension(const GeneratorOptions& options,
+                                const FieldDescriptor* field,
+                                std::set<string>* required,
+                                std::set<string>* forwards) const;
+
+  void GenerateFile(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const FileDescriptor* file) const;
+
+  // Generate definitions for all message classes and enums in all files,
+  // processing the files in dependence order.
+  void GenerateFilesInDepOrder(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const vector<const FileDescriptor*>& file) const;
+  // Helper for above.
+  void GenerateFileAndDeps(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const FileDescriptor* root,
+                           std::set<const FileDescriptor*>* all_files,
+                           std::set<const FileDescriptor*>* generated) const;
+
+  // Generate definitions for all message classes and enums.
+  void GenerateClassesAndEnums(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const FileDescriptor* file) const;
+
+  // Generate definition for one class.
+  void GenerateClass(const GeneratorOptions& options,
+                     io::Printer* printer,
+                     const Descriptor* desc) const;
+  void GenerateClassConstructor(const GeneratorOptions& options,
+                                io::Printer* printer,
+                                const Descriptor* desc) const;
+  void GenerateClassFieldInfo(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc) const;
+  void GenerateClassXid(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const Descriptor* desc) const;
+  void GenerateOneofCaseDefinition(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const OneofDescriptor* oneof) const;
+  void GenerateClassToObject(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const Descriptor* desc) const;
+  void GenerateClassFieldToObject(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const FieldDescriptor* field) const;
+  void GenerateClassFromObject(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const Descriptor* desc) const;
+  void GenerateClassFieldFromObject(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const FieldDescriptor* field) const;
+  void GenerateClassClone(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const Descriptor* desc) const;
+  void GenerateClassRegistration(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const Descriptor* desc) const;
+  void GenerateClassFields(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const Descriptor* desc) const;
+  void GenerateClassField(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const FieldDescriptor* desc) const;
+  void GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+                                       io::Printer* printer,
+                                       const Descriptor* desc) const;
+  void GenerateClassDeserialize(const GeneratorOptions& options,
+                                io::Printer* printer,
+                                const Descriptor* desc) const;
+  void GenerateClassDeserializeBinary(const GeneratorOptions& options,
+                                      io::Printer* printer,
+                                      const Descriptor* desc) const;
+  void GenerateClassDeserializeBinaryField(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const FieldDescriptor* field) const;
+  void GenerateClassSerializeBinary(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const Descriptor* desc) const;
+  void GenerateClassSerializeBinaryField(const GeneratorOptions& options,
+                                         io::Printer* printer,
+                                         const FieldDescriptor* field) const;
+
+  // Generate definition for one enum.
+  void GenerateEnum(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const EnumDescriptor* enumdesc) const;
+
+  // Generate an extension definition.
+  void GenerateExtension(const GeneratorOptions& options,
+                         io::Printer* printer,
+                         const FieldDescriptor* field) const;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
+};
+
+}  // namespace js
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 1fc60ce..400c556 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -36,7 +36,10 @@
 #include <google/protobuf/compiler/java/java_generator.h>
 #include <google/protobuf/compiler/javamicro/javamicro_generator.h>
 #include <google/protobuf/compiler/javanano/javanano_generator.h>
-
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/csharp/csharp_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/js/js_generator.h>
 
 int main(int argc, char* argv[]) {
 
@@ -59,15 +62,35 @@
   cli.RegisterGenerator("--python_out", &py_generator,
                         "Generate Python source file.");
 
-  // Proto2 JavaMicro
-  google::protobuf::compiler::javamicro::JavaMicroGenerator javamicro_generator;
-  cli.RegisterGenerator("--javamicro_out", &javamicro_generator,
-                        "Generate Java source file micro runtime.");
-
-  // Proto2 JavaNano
+  // Java Nano
   google::protobuf::compiler::javanano::JavaNanoGenerator javanano_generator;
   cli.RegisterGenerator("--javanano_out", &javanano_generator,
-                        "Generate Java source file nano runtime.");
+                        "Generate Java Nano source file.");
+
+  // Java Micro
+  google::protobuf::compiler::javamicro::JavaMicroGenerator javamicro_generator;
+  cli.RegisterGenerator("--javamicro_out", &javamicro_generator,
+                        "Generate Java Micro source file.");
+
+  // Ruby
+  google::protobuf::compiler::ruby::Generator rb_generator;
+  cli.RegisterGenerator("--ruby_out", &rb_generator,
+                        "Generate Ruby source file.");
+
+  // CSharp
+  google::protobuf::compiler::csharp::Generator csharp_generator;
+  cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator,
+                        "Generate C# source file.");
+
+  // Objective C
+  google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator;
+  cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator,
+                        "Generate Objective C header and source.");
+
+  // JavaScript
+  google::protobuf::compiler::js::Generator js_generator;
+  cli.RegisterGenerator("--js_out", &js_generator,
+                        "Generate JavaScript source.");
 
   return cli.Run(argc, argv);
 }
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 916b0cc..82bb342 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -32,17 +32,26 @@
 
 #include <google/protobuf/compiler/mock_code_generator.h>
 
+#include <stdlib.h>
+#include <iostream>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
 
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util.h>
 
 namespace google {
 namespace protobuf {
@@ -130,10 +139,10 @@
         *error = "Saw message type MockCodeGenerator_Error.";
         return false;
       } else if (command == "Exit") {
-        cerr << "Saw message type MockCodeGenerator_Exit." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
         exit(123);
       } else if (command == "Abort") {
-        cerr << "Saw message type MockCodeGenerator_Abort." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
         abort();
       } else if (command == "HasSourceCodeInfo") {
         FileDescriptorProto file_descriptor_proto;
@@ -141,8 +150,14 @@
         bool has_source_code_info =
             file_descriptor_proto.has_source_code_info() &&
             file_descriptor_proto.source_code_info().location_size() > 0;
-        cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
-             << has_source_code_info << "." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
+                  << has_source_code_info << "." << std::endl;
+        abort();
+      } else if (command == "HasJsonName") {
+        FieldDescriptorProto field_descriptor_proto;
+        file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto);
+        std::cerr << "Saw json_name: "
+                  << field_descriptor_proto.has_json_name() << std::endl;
         abort();
       } else {
         GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
@@ -157,7 +172,7 @@
 
     for (int i = 0; i < insert_into.size(); i++) {
       {
-        scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
             GetOutputFileName(insert_into[i], file), kFirstInsertionPointName));
         io::Printer printer(output.get(), '$');
         printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
@@ -169,7 +184,7 @@
       }
 
       {
-        scoped_ptr<io::ZeroCopyOutputStream> output(
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
             context->OpenForInsert(GetOutputFileName(insert_into[i], file),
                                    kSecondInsertionPointName));
         io::Printer printer(output.get(), '$');
@@ -182,7 +197,7 @@
       }
     }
   } else {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->Open(GetOutputFileName(name_, file)));
 
     io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 8c8348d..e1665f8 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -34,10 +34,15 @@
 #define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
 
 #include <string>
+
 #include <google/protobuf/compiler/code_generator.h>
 
 namespace google {
 namespace protobuf {
+class FileDescriptor;
+}  // namespace protobuf
+
+namespace protobuf {
 namespace compiler {
 
 // A mock CodeGenerator, used by command_line_interface_unittest.  This is in
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
new file mode 100644
index 0000000..e76f8e9
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
@@ -0,0 +1,219 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
+    : descriptor_(descriptor),
+      name_(EnumName(descriptor_)) {
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    const EnumValueDescriptor* value = descriptor_->value(i);
+    const EnumValueDescriptor* canonical_value =
+        descriptor_->FindValueByNumber(value->number());
+
+    if (value == canonical_value) {
+      base_values_.push_back(value);
+    }
+    all_values_.push_back(value);
+  }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::GenerateHeader(io::Printer* printer) {
+  string enum_comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    enum_comments = BuildCommentsString(location);
+  } else {
+    enum_comments = "";
+  }
+
+  printer->Print(
+      "#pragma mark - Enum $name$\n"
+      "\n",
+      "name", name_);
+
+  printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n",
+                 "comments", enum_comments,
+                 "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_),
+                 "name", name_);
+  printer->Indent();
+
+  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    // Include the unknown value.
+    printer->Print(
+      "/// Value used if any message's field encounters a value that is not defined\n"
+      "/// by this enum. The message will also have C functions to get/set the rawValue\n"
+      "/// of the field.\n"
+      "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n",
+      "name", name_);
+  }
+  for (int i = 0; i < all_values_.size(); i++) {
+    SourceLocation location;
+    if (all_values_[i]->GetSourceLocation(&location)) {
+      string comments = BuildCommentsString(location).c_str();
+      if (comments.length() > 0) {
+        if (i > 0) {
+          printer->Print("\n");
+        }
+        printer->Print(comments.c_str());
+      }
+    }
+
+    printer->Print(
+        "$name$$deprecated_attribute$ = $value$,\n",
+        "name", EnumValueName(all_values_[i]),
+        "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]),
+        "value", SimpleItoa(all_values_[i]->number()));
+  }
+  printer->Outdent();
+  printer->Print(
+      "};\n"
+      "\n"
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
+      "\n"
+      "/// Checks to see if the given value is defined by the enum or was not known at\n"
+      "/// the time this source was generated.\n"
+      "BOOL $name$_IsValidValue(int32_t value);\n"
+      "\n",
+      "name", name_);
+}
+
+void EnumGenerator::GenerateSource(io::Printer* printer) {
+  printer->Print(
+      "#pragma mark - Enum $name$\n"
+      "\n",
+      "name", name_);
+
+  // Note: For the TextFormat decode info, we can't use the enum value as
+  // the key because protocol buffer enums have 'allow_alias', which lets
+  // a value be used more than once. Instead, the index into the list of
+  // enum value descriptions is used. Note: start with -1 so the first one
+  // will be zero.
+  TextFormatDecodeData text_format_decode_data;
+  int enum_value_description_key = -1;
+  string text_blob;
+
+  for (int i = 0; i < all_values_.size(); i++) {
+    ++enum_value_description_key;
+    string short_name(EnumValueShortName(all_values_[i]));
+    text_blob += short_name + '\0';
+    if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) {
+      text_format_decode_data.AddString(enum_value_description_key, short_name,
+                                        all_values_[i]->name());
+    }
+  }
+
+  printer->Print(
+      "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n"
+      "  static GPBEnumDescriptor *descriptor = NULL;\n"
+      "  if (!descriptor) {\n",
+      "name", name_);
+
+  static const int kBytesPerLine = 40;  // allow for escaping
+  printer->Print(
+      "    static const char *valueNames =");
+  for (int i = 0; i < text_blob.size(); i += kBytesPerLine) {
+    printer->Print(
+        "\n        \"$data$\"",
+        "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine))));
+  }
+  printer->Print(
+      ";\n"
+      "    static const int32_t values[] = {\n");
+  for (int i = 0; i < all_values_.size(); i++) {
+    printer->Print("        $name$,\n",  "name", EnumValueName(all_values_[i]));
+  }
+  printer->Print("    };\n");
+
+  if (text_format_decode_data.num_entries() == 0) {
+    printer->Print(
+        "    GPBEnumDescriptor *worker =\n"
+        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                       valueNames:valueNames\n"
+        "                                           values:values\n"
+        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
+        "                                     enumVerifier:$name$_IsValidValue];\n",
+        "name", name_);
+    } else {
+      printer->Print(
+        "    static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
+        "    GPBEnumDescriptor *worker =\n"
+        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
+        "                                       valueNames:valueNames\n"
+        "                                           values:values\n"
+        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
+        "                                     enumVerifier:$name$_IsValidValue\n"
+        "                              extraTextFormatInfo:extraTextFormatInfo];\n",
+        "name", name_,
+        "extraTextFormatInfo", CEscape(text_format_decode_data.Data()));
+    }
+    printer->Print(
+      "    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {\n"
+      "      [worker release];\n"
+      "    }\n"
+      "  }\n"
+      "  return descriptor;\n"
+      "}\n\n");
+
+  printer->Print(
+      "BOOL $name$_IsValidValue(int32_t value__) {\n"
+      "  switch (value__) {\n",
+      "name", name_);
+
+  for (int i = 0; i < base_values_.size(); i++) {
+    printer->Print(
+        "    case $name$:\n",
+        "name", EnumValueName(base_values_[i]));
+  }
+
+  printer->Print(
+      "      return YES;\n"
+      "    default:\n"
+      "      return NO;\n"
+      "  }\n"
+      "}\n\n");
+}
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
new file mode 100644
index 0000000..0b41cf7
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator {
+ public:
+  explicit EnumGenerator(const EnumDescriptor* descriptor);
+  ~EnumGenerator();
+
+  void GenerateHeader(io::Printer* printer);
+  void GenerateSource(io::Printer* printer);
+
+  const string& name() const { return name_; }
+
+ private:
+  const EnumDescriptor* descriptor_;
+  vector<const EnumValueDescriptor*> base_values_;
+  vector<const EnumValueDescriptor*> all_values_;
+  const string name_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
new file mode 100644
index 0000000..b63bc0d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -0,0 +1,147 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+                      map<string, string>* variables) {
+  string type = EnumName(descriptor->enum_type());
+  (*variables)["storage_type"] = type;
+  // For non repeated fields, if it was defined in a different file, the
+  // property decls need to use "enum NAME" rather than just "NAME" to support
+  // the forward declaration of the enums.
+  if (!descriptor->is_repeated() &&
+      (descriptor->file() != descriptor->enum_type()->file())) {
+    (*variables)["property_type"] = "enum " + type;
+  }
+  (*variables)["enum_verifier"] = type + "_IsValidValue";
+  (*variables)["enum_desc_func"] = type + "_EnumDescriptor";
+
+  (*variables)["dataTypeSpecific_name"] = "enumDescFunc";
+  (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"];
+
+  const Descriptor* msg_descriptor = descriptor->containing_type();
+  (*variables)["owning_message_class"] = ClassName(msg_descriptor);
+}
+}  // namespace
+
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
+  SetEnumVariables(descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::GenerateCFunctionDeclarations(
+    io::Printer* printer) const {
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    return;
+  }
+
+  printer->Print(
+      variables_,
+      "/// Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n"
+      "/// if the value was not defined by the enum at the time the code was generated.\n"
+      "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n"
+      "/// Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n"
+      "/// it to be set to a value that was not defined by the enum at the time the code\n"
+      "/// was generated.\n"
+      "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n"
+      "\n");
+}
+
+void EnumFieldGenerator::GenerateCFunctionImplementations(
+    io::Printer* printer) const {
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return;
+
+  printer->Print(
+      variables_,
+      "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n"
+      "  GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n"
+      "  GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n"
+      "  return GPBGetMessageInt32Field(message, field);\n"
+      "}\n"
+      "\n"
+      "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value) {\n"
+      "  GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n"
+      "  GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n"
+      "  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);\n"
+      "}\n"
+      "\n");
+}
+
+void EnumFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  // If it is an enum defined in a different file, then we'll need a forward
+  // declaration for it.  When it is in our file, all the enums are output
+  // before the message, so it will be declared before it is needed.
+  if (descriptor_->file() != descriptor_->enum_type()->file()) {
+    // Enum name is already in "storage_type".
+    const string& name = variable("storage_type");
+    fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")");
+  }
+}
+
+RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
+  SetEnumVariables(descriptor, &variables_);
+  variables_["array_storage_type"] = "GPBEnumArray";
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  variables_["array_comment"] =
+      "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
new file mode 100644
index 0000000..946faa8
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumFieldGenerator : public SingleFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ public:
+  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ protected:
+  EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+  virtual ~EnumFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ public:
+  virtual void FinishInitialization();
+
+ protected:
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
+  virtual ~RepeatedEnumFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
new file mode 100644
index 0000000..3f7ab9d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -0,0 +1,136 @@
+// 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.
+
+#include <iostream>
+
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+ExtensionGenerator::ExtensionGenerator(const string& root_class_name,
+                                       const FieldDescriptor* descriptor)
+    : method_name_(ExtensionMethodName(descriptor)),
+      root_class_and_method_name_(root_class_name + "_" + method_name_),
+      descriptor_(descriptor) {
+  if (descriptor->is_map()) {
+    // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+    // error cases, so it seems to be ok to use as a back door for errors.
+    cerr << "error: Extension is a map<>!"
+         << " That used to be blocked by the compiler." << endl;
+    cerr.flush();
+    abort();
+  }
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) {
+  map<string, string> vars;
+  vars["method_name"] = method_name_;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    vars["comments"] = BuildCommentsString(location);
+  } else {
+    vars["comments"] = "";
+  }
+  printer->Print(vars,
+                 "$comments$"
+                 "+ (GPBExtensionDescriptor *)$method_name$;\n");
+}
+
+void ExtensionGenerator::GenerateStaticVariablesInitialization(
+    io::Printer* printer) {
+  map<string, string> vars;
+  vars["root_class_and_method_name"] = root_class_and_method_name_;
+  vars["extended_type"] = ClassName(descriptor_->containing_type());
+  vars["number"] = SimpleItoa(descriptor_->number());
+
+  std::vector<string> options;
+  if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated");
+  if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked");
+  if (descriptor_->containing_type()->options().message_set_wire_format())
+    options.push_back("GPBExtensionSetWireFormat");
+
+  vars["options"] = BuildFlagsString(options);
+
+  ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
+  string singular_type;
+  if (objc_type == OBJECTIVECTYPE_MESSAGE) {
+    vars["type"] = string("GPBStringifySymbol(") +
+                   ClassName(descriptor_->message_type()) + ")";
+  } else {
+    vars["type"] = "NULL";
+  }
+
+  vars["default_name"] = GPBGenericValueFieldName(descriptor_);
+  if (descriptor_->is_repeated()) {
+    vars["default"] = "nil";
+  } else {
+    vars["default"] = DefaultValue(descriptor_);
+  }
+  string type = GetCapitalizedType(descriptor_);
+  vars["extension_type"] = string("GPBDataType") + type;
+
+  if (objc_type == OBJECTIVECTYPE_ENUM) {
+    vars["enum_desc_func_name"] =
+         EnumName(descriptor_->enum_type()) + "_EnumDescriptor";
+  } else {
+    vars["enum_desc_func_name"] = "NULL";
+  }
+
+  printer->Print(vars,
+                 "{\n"
+                 "  .defaultValue.$default_name$ = $default$,\n"
+                 "  .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n"
+                 "  .extendedClass = GPBStringifySymbol($extended_type$),\n"
+                 "  .messageOrGroupClassName = $type$,\n"
+                 "  .enumDescriptorFunc = $enum_desc_func_name$,\n"
+                 "  .fieldNumber = $number$,\n"
+                 "  .dataType = $extension_type$,\n"
+                 "  .options = $options$,\n"
+                 "},\n");
+}
+
+void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) {
+  printer->Print(
+      "[registry addExtension:$root_class_and_method_name$];\n",
+      "root_class_and_method_name", root_class_and_method_name_);
+}
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
new file mode 100644
index 0000000..e361e63
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FieldDescriptor;  // descriptor.h
+namespace io {
+class Printer;  // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator {
+ public:
+  ExtensionGenerator(const string& root_class_name,
+                     const FieldDescriptor* descriptor);
+  ~ExtensionGenerator();
+
+  void GenerateMembersHeader(io::Printer* printer);
+  void GenerateStaticVariablesInitialization(io::Printer* printer);
+  void GenerateRegistrationSource(io::Printer* printer);
+
+ private:
+  string method_name_;
+  string root_class_and_method_name_;
+  const FieldDescriptor* descriptor_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
new file mode 100644
index 0000000..66cb4a1
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -0,0 +1,477 @@
+// 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.
+
+#include <iostream>
+
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetCommonFieldVariables(const FieldDescriptor* descriptor,
+                             map<string, string>* variables) {
+  string camel_case_name = FieldName(descriptor);
+  string raw_field_name;
+  if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
+    raw_field_name = descriptor->message_type()->name();
+  } else {
+    raw_field_name = descriptor->name();
+  }
+  // The logic here has to match -[GGPBFieldDescriptor textFormatName].
+  const string un_camel_case_name(
+      UnCamelCaseFieldName(camel_case_name, descriptor));
+  const bool needs_custom_name = (raw_field_name != un_camel_case_name);
+
+  SourceLocation location;
+  if (descriptor->GetSourceLocation(&location)) {
+    (*variables)["comments"] = BuildCommentsString(location);
+  } else {
+    (*variables)["comments"] = "\n";
+  }
+  const string& classname = ClassName(descriptor->containing_type());
+  (*variables)["classname"] = classname;
+  (*variables)["name"] = camel_case_name;
+  const string& capitalized_name = FieldNameCapitalized(descriptor);
+  (*variables)["capitalized_name"] = capitalized_name;
+  (*variables)["raw_field_name"] = raw_field_name;
+  (*variables)["field_number_name"] =
+      classname + "_FieldNumber_" + capitalized_name;
+  (*variables)["field_number"] = SimpleItoa(descriptor->number());
+  (*variables)["field_type"] = GetCapitalizedType(descriptor);
+  (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor);
+  std::vector<string> field_flags;
+  if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated");
+  if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired");
+  if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional");
+  if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked");
+
+  // ObjC custom flags.
+  if (descriptor->has_default_value())
+    field_flags.push_back("GPBFieldHasDefaultValue");
+  if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom");
+  if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
+    field_flags.push_back("GPBFieldHasEnumDescriptor");
+  }
+
+  (*variables)["fieldflags"] = BuildFlagsString(field_flags);
+
+  (*variables)["default"] = DefaultValue(descriptor);
+  (*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
+
+  (*variables)["dataTypeSpecific_name"] = "className";
+  (*variables)["dataTypeSpecific_value"] = "NULL";
+
+  (*variables)["storage_offset_value"] =
+      "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")";
+  (*variables)["storage_offset_comment"] = "";
+
+  // Clear some common things so they can be set just when needed.
+  (*variables)["storage_attribute"] = "";
+}
+
+}  // namespace
+
+FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                     const Options& options) {
+  FieldGenerator* result = NULL;
+  if (field->is_repeated()) {
+    switch (GetObjectiveCType(field)) {
+      case OBJECTIVECTYPE_MESSAGE: {
+        if (field->is_map()) {
+          result = new MapFieldGenerator(field, options);
+        } else {
+          result = new RepeatedMessageFieldGenerator(field, options);
+        }
+        break;
+      }
+      case OBJECTIVECTYPE_ENUM:
+        result = new RepeatedEnumFieldGenerator(field, options);
+        break;
+      default:
+        result = new RepeatedPrimitiveFieldGenerator(field, options);
+        break;
+    }
+  } else {
+    switch (GetObjectiveCType(field)) {
+      case OBJECTIVECTYPE_MESSAGE: {
+        result = new MessageFieldGenerator(field, options);
+        break;
+      }
+      case OBJECTIVECTYPE_ENUM:
+        result = new EnumFieldGenerator(field, options);
+        break;
+      default:
+        if (IsReferenceType(field)) {
+          result = new PrimitiveObjFieldGenerator(field, options);
+        } else {
+          result = new PrimitiveFieldGenerator(field, options);
+        }
+        break;
+    }
+  }
+  result->FinishInitialization();
+  return result;
+}
+
+FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options)
+    : descriptor_(descriptor) {
+  SetCommonFieldVariables(descriptor, &variables_);
+}
+
+FieldGenerator::~FieldGenerator() {}
+
+void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "$field_number_name$ = $field_number$,\n");
+}
+
+void FieldGenerator::GenerateCFunctionDeclarations(
+    io::Printer* printer) const {
+  // Nothing
+}
+
+void FieldGenerator::GenerateCFunctionImplementations(
+    io::Printer* printer) const {
+  // Nothing
+}
+
+void FieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  // Nothing
+}
+
+void FieldGenerator::GenerateFieldDescription(
+    io::Printer* printer, bool include_default) const {
+  // Printed in the same order as the structure decl.
+  if (include_default) {
+    printer->Print(
+        variables_,
+        "{\n"
+        "  .defaultValue.$default_name$ = $default$,\n"
+        "  .core.name = \"$name$\",\n"
+        "  .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
+        "  .core.number = $field_number_name$,\n"
+        "  .core.hasIndex = $has_index$,\n"
+        "  .core.offset = $storage_offset_value$,$storage_offset_comment$\n"
+        "  .core.flags = $fieldflags$,\n"
+        "  .core.dataType = GPBDataType$field_type$,\n"
+        "},\n");
+  } else {
+    printer->Print(
+        variables_,
+        "{\n"
+        "  .name = \"$name$\",\n"
+        "  .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
+        "  .number = $field_number_name$,\n"
+        "  .hasIndex = $has_index$,\n"
+        "  .offset = $storage_offset_value$,$storage_offset_comment$\n"
+        "  .flags = $fieldflags$,\n"
+        "  .dataType = GPBDataType$field_type$,\n"
+        "},\n");
+  }
+}
+
+void FieldGenerator::SetRuntimeHasBit(int has_index) {
+  variables_["has_index"] = SimpleItoa(has_index);
+}
+
+void FieldGenerator::SetNoHasBit(void) {
+  variables_["has_index"] = "GPBNoHasBit";
+}
+
+int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
+  return 0;
+}
+
+void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) {
+  // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+  // error cases, so it seems to be ok to use as a back door for errors.
+  cerr << "Error: should have overriden SetExtraRuntimeHasBitsBase()." << endl;
+  cerr.flush();
+  abort();
+}
+
+void FieldGenerator::SetOneofIndexBase(int index_base) {
+  if (descriptor_->containing_oneof() != NULL) {
+    int index = descriptor_->containing_oneof()->index() + index_base;
+    // Flip the sign to mark it as a oneof.
+    variables_["has_index"] = SimpleItoa(-index);
+  }
+}
+
+void FieldGenerator::FinishInitialization(void) {
+  // If "property_type" wasn't set, make it "storage_type".
+  if ((variables_.find("property_type") == variables_.end()) &&
+      (variables_.find("storage_type") != variables_.end())) {
+    variables_["property_type"] = variable("storage_type");
+  }
+}
+
+SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor,
+                                           const Options& options)
+    : FieldGenerator(descriptor, options) {
+  // Nothing
+}
+
+SingleFieldGenerator::~SingleFieldGenerator() {}
+
+void SingleFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$storage_type$ $name$;\n");
+}
+
+void SingleFieldGenerator::GeneratePropertyDeclaration(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$comments$");
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n"
+      "\n");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
+  }
+}
+
+void SingleFieldGenerator::GeneratePropertyImplementation(
+    io::Printer* printer) const {
+  if (WantsHasProperty()) {
+    printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n");
+  } else {
+    printer->Print(variables_, "@dynamic $name$;\n");
+  }
+}
+
+bool SingleFieldGenerator::WantsHasProperty(void) const {
+  if (descriptor_->containing_oneof() != NULL) {
+    // If in a oneof, it uses the oneofcase instead of a has bit.
+    return false;
+  }
+  if (HasFieldPresence(descriptor_->file())) {
+    // In proto1/proto2, every field has a has_$name$() method.
+    return true;
+  }
+  return false;
+}
+
+bool SingleFieldGenerator::RuntimeUsesHasBit(void) const {
+  if (descriptor_->containing_oneof() != NULL) {
+    // The oneof tracks what is set instead.
+    return false;
+  }
+  return true;
+}
+
+ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
+  variables_["property_storage_attribute"] = "strong";
+  if (IsRetainedName(variables_["name"])) {
+    variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
+  }
+}
+
+ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {}
+
+void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$storage_type$ *$name$;\n");
+}
+
+void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
+    io::Printer* printer) const {
+
+  // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that
+  // it uses pointers and deals with Objective C's rules around storage name
+  // conventions (init*, new*, etc.)
+
+  printer->Print(variables_, "$comments$");
+  printer->Print(
+      variables_,
+      "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n");
+  if (WantsHasProperty()) {
+    printer->Print(
+        variables_,
+        "/// Test to see if @c $name$ has been set.\n"
+        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
+  }
+  if (IsInitName(variables_.find("name")->second)) {
+    // If property name starts with init we need to annotate it to get past ARC.
+    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+    printer->Print(variables_,
+                   "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
+  }
+  printer->Print("\n");
+}
+
+RepeatedFieldGenerator::RepeatedFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
+  // Default to no comment and let the cases needing it fill it in.
+  variables_["array_comment"] = "";
+}
+
+RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
+
+void RepeatedFieldGenerator::FinishInitialization(void) {
+  FieldGenerator::FinishInitialization();
+  if (variables_.find("array_property_type") == variables_.end()) {
+    variables_["array_property_type"] = variable("array_storage_type");
+  }
+}
+
+void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  printer->Print(variables_, "$array_storage_type$ *$name$;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyImplementation(
+    io::Printer* printer) const {
+  printer->Print(variables_, "@dynamic $name$, $name$_Count;\n");
+}
+
+void RepeatedFieldGenerator::GeneratePropertyDeclaration(
+    io::Printer* printer) const {
+
+  // Repeated fields don't need the has* properties, but they do expose a
+  // *Count (to check without autocreation).  So for the field property we need
+  // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for
+  // dealing with needing Objective C's rules around storage name conventions
+  // (init*, new*, etc.)
+
+  printer->Print(
+      variables_,
+      "$comments$"
+      "$array_comment$"
+      "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
+      "/// The number of items in @c $name$ without causing the array to be created.\n"
+      "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
+  if (IsInitName(variables_.find("name")->second)) {
+    // If property name starts with init we need to annotate it to get past ARC.
+    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
+    printer->Print(variables_,
+                   "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
+  }
+  printer->Print("\n");
+}
+
+bool RepeatedFieldGenerator::WantsHasProperty(void) const {
+  // Consumer check the array size/existance rather than a has bit.
+  return false;
+}
+
+bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const {
+  return false;  // The array having anything is what is used.
+}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
+                                     const Options& options)
+    : descriptor_(descriptor),
+      field_generators_(
+          new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
+      extension_generators_(
+          new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+  // Construct all the FieldGenerators.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    field_generators_[i].reset(
+        FieldGenerator::Make(descriptor->field(i), options));
+  }
+  for (int i = 0; i < descriptor->extension_count(); i++) {
+    extension_generators_[i].reset(
+        FieldGenerator::Make(descriptor->extension(i), options));
+  }
+}
+
+FieldGeneratorMap::~FieldGeneratorMap() {}
+
+const FieldGenerator& FieldGeneratorMap::get(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+  return *field_generators_[field->index()];
+}
+
+const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
+  return *extension_generators_[index];
+}
+
+int FieldGeneratorMap::CalculateHasBits(void) {
+  int total_bits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (field_generators_[i]->RuntimeUsesHasBit()) {
+      field_generators_[i]->SetRuntimeHasBit(total_bits);
+      ++total_bits;
+    } else {
+      field_generators_[i]->SetNoHasBit();
+    }
+    int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded();
+    if (extra_bits) {
+      field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits);
+      total_bits += extra_bits;
+    }
+  }
+  return total_bits;
+}
+
+void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_[i]->SetOneofIndexBase(index_base);
+  }
+}
+
+bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (HasNonZeroDefaultValue(descriptor_->field(i))) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h
new file mode 100644
index 0000000..a3a4b1b
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h
@@ -0,0 +1,194 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class Printer;  // printer.h
+}  // namespace io
+
+namespace compiler {
+namespace objectivec {
+
+class FieldGenerator {
+ public:
+  static FieldGenerator* Make(const FieldDescriptor* field,
+                              const Options& options);
+
+  virtual ~FieldGenerator();
+
+  // Exposed for subclasses to fill in.
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0;
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0;
+
+  // Called by GenerateFieldDescription, exposed for classes that need custom
+  // generation.
+
+  // Exposed for subclasses to extend, base does nothing.
+  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
+  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+
+  // Exposed for subclasses, should always call it on the parent class also.
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+  // Used during generation, not intended to be extended by subclasses.
+  void GenerateFieldDescription(
+      io::Printer* printer, bool include_default) const;
+  void GenerateFieldNumberConstant(io::Printer* printer) const;
+
+  // Exposed to get and set the has bits information.
+  virtual bool RuntimeUsesHasBit(void) const = 0;
+  void SetRuntimeHasBit(int has_index);
+  void SetNoHasBit(void);
+  virtual int ExtraRuntimeHasBitsNeeded(void) const;
+  virtual void SetExtraRuntimeHasBitsBase(int index_base);
+  void SetOneofIndexBase(int index_base);
+
+  string variable(const char* key) const {
+    return variables_.find(key)->second;
+  }
+
+  bool needs_textformat_name_support() const {
+    const string& field_flags = variable("fieldflags");
+    return field_flags.find("GPBFieldTextFormatNameCustom") != string::npos;
+  }
+  string generated_objc_name() const { return variable("name"); }
+  string raw_field_name() const { return variable("raw_field_name"); }
+
+ protected:
+  FieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+
+  virtual void FinishInitialization(void);
+  virtual bool WantsHasProperty(void) const = 0;
+
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+class SingleFieldGenerator : public FieldGenerator {
+ public:
+  virtual ~SingleFieldGenerator();
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const;
+
+  virtual bool RuntimeUsesHasBit(void) const;
+
+ protected:
+  SingleFieldGenerator(const FieldDescriptor* descriptor,
+                       const Options& options);
+  virtual bool WantsHasProperty(void) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingleFieldGenerator);
+};
+
+// Subclass with common support for when the field ends up as an ObjC Object.
+class ObjCObjFieldGenerator : public SingleFieldGenerator {
+ public:
+  virtual ~ObjCObjFieldGenerator();
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+ protected:
+  ObjCObjFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator);
+};
+
+class RepeatedFieldGenerator : public ObjCObjFieldGenerator {
+ public:
+  virtual ~RepeatedFieldGenerator();
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+  virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
+
+  virtual void GeneratePropertyImplementation(io::Printer* printer) const;
+
+  virtual bool RuntimeUsesHasBit(void) const;
+
+ protected:
+  RepeatedFieldGenerator(const FieldDescriptor* descriptor,
+                         const Options& options);
+  virtual void FinishInitialization(void);
+  virtual bool WantsHasProperty(void) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedFieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+  FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
+  ~FieldGeneratorMap();
+
+  const FieldGenerator& get(const FieldDescriptor* field) const;
+  const FieldGenerator& get_extension(int index) const;
+
+  // Assigns the has bits and returns the number of bits needed.
+  int CalculateHasBits(void);
+
+  void SetOneofIndexBase(int index_base);
+
+  // Check if any field of this message has a non zero default.
+  bool DoesAnyFieldHaveNonZeroDefault(void) const;
+
+ private:
+  const Descriptor* descriptor_;
+  scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+  scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
new file mode 100644
index 0000000..ed4fc6a
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -0,0 +1,382 @@
+// 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.
+
+#include <google/protobuf/compiler/objectivec/objectivec_file.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <sstream>
+
+namespace google {
+namespace protobuf {
+
+// This is also found in GPBBootstrap.h, and needs to be kept in sync.  It
+// is the version check done to ensure generated code works with the current
+// runtime being used.
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
+
+namespace compiler {
+namespace objectivec {
+
+FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
+    : file_(file),
+      root_class_name_(FileClassName(file)),
+      is_public_dep_(false),
+      options_(options) {
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
+    enum_generators_.push_back(generator);
+  }
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    MessageGenerator *generator =
+        new MessageGenerator(root_class_name_, file_->message_type(i), options_);
+    message_generators_.push_back(generator);
+  }
+  for (int i = 0; i < file_->extension_count(); i++) {
+    ExtensionGenerator *generator =
+        new ExtensionGenerator(root_class_name_, file_->extension(i));
+    extension_generators_.push_back(generator);
+  }
+}
+
+FileGenerator::~FileGenerator() {
+  STLDeleteContainerPointers(dependency_generators_.begin(),
+                             dependency_generators_.end());
+  STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
+  STLDeleteContainerPointers(message_generators_.begin(),
+                             message_generators_.end());
+  STLDeleteContainerPointers(extension_generators_.begin(),
+                             extension_generators_.end());
+}
+
+void FileGenerator::GenerateHeader(io::Printer *printer) {
+  printer->Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n",
+      "filename", file_->name());
+
+  printer->Print(
+      "#import \"GPBProtocolBuffers.h\"\n"
+      "\n");
+
+  // Add some verification that the generated code matches the source the
+  // code is being compiled with.
+  printer->Print(
+      "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
+      "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
+      "#endif\n"
+      "\n",
+      "protoc_gen_objc_version",
+      SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
+
+  const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
+  for (vector<FileGenerator *>::const_iterator iter =
+           dependency_generators.begin();
+       iter != dependency_generators.end(); ++iter) {
+    if ((*iter)->IsPublicDependency()) {
+      printer->Print("#import \"$header$.pbobjc.h\"\n",
+                     "header", (*iter)->Path());
+    }
+  }
+
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n"
+      "#pragma clang diagnostic push\n"
+      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
+      "\n"
+      "CF_EXTERN_C_BEGIN\n"
+      "\n");
+
+  set<string> fwd_decls;
+  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+       iter != message_generators_.end(); ++iter) {
+    (*iter)->DetermineForwardDeclarations(&fwd_decls);
+  }
+  for (set<string>::const_iterator i(fwd_decls.begin());
+       i != fwd_decls.end(); ++i) {
+    printer->Print("$value$;\n", "value", *i);
+  }
+  if (fwd_decls.begin() != fwd_decls.end()) {
+    printer->Print("\n");
+  }
+
+  printer->Print(
+      "NS_ASSUME_NONNULL_BEGIN\n"
+      "\n");
+
+  // need to write out all enums first
+  for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
+       iter != enum_generators_.end(); ++iter) {
+    (*iter)->GenerateHeader(printer);
+  }
+
+  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+       iter != message_generators_.end(); ++iter) {
+    (*iter)->GenerateEnumHeader(printer);
+  }
+
+  // For extensions to chain together, the Root gets created even if there
+  // are no extensions.
+  printer->Print(
+      "#pragma mark - $root_class_name$\n"
+      "\n"
+      "/// Exposes the extension registry for this file.\n"
+      "///\n"
+      "/// The base class provides:\n"
+      "/// @code\n"
+      "///   + (GPBExtensionRegistry *)extensionRegistry;\n"
+      "/// @endcode\n"
+      "/// which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
+      "/// this file and all files that it depends on.\n"
+      "@interface $root_class_name$ : GPBRootObject\n"
+      "@end\n"
+      "\n",
+      "root_class_name", root_class_name_);
+
+  if (extension_generators_.size() > 0) {
+    // The dynamic methods block is only needed if there are extensions.
+    printer->Print(
+        "@interface $root_class_name$ (DynamicMethods)\n",
+        "root_class_name", root_class_name_);
+
+    for (vector<ExtensionGenerator *>::iterator iter =
+             extension_generators_.begin();
+         iter != extension_generators_.end(); ++iter) {
+      (*iter)->GenerateMembersHeader(printer);
+    }
+
+    printer->Print("@end\n\n");
+  }  // extension_generators_.size() > 0
+
+  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+       iter != message_generators_.end(); ++iter) {
+    (*iter)->GenerateMessageHeader(printer);
+  }
+
+  printer->Print(
+      "NS_ASSUME_NONNULL_END\n"
+      "\n"
+      "CF_EXTERN_C_END\n"
+      "\n"
+      "#pragma clang diagnostic pop\n"
+      "\n"
+      "// @@protoc_insertion_point(global_scope)\n");
+}
+
+void FileGenerator::GenerateSource(io::Printer *printer) {
+  printer->Print(
+      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+      "// source: $filename$\n"
+      "\n",
+      "filename", file_->name());
+
+  string header_file = Path() + ".pbobjc.h";
+  printer->Print(
+      "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
+      "#import \"$header_file$\"\n",
+      "header_file", header_file);
+  const vector<FileGenerator *> &dependency_generators =
+      DependencyGenerators();
+  for (vector<FileGenerator *>::const_iterator iter =
+           dependency_generators.begin();
+       iter != dependency_generators.end(); ++iter) {
+    if (!(*iter)->IsPublicDependency()) {
+      printer->Print("#import \"$header$.pbobjc.h\"\n",
+                     "header", (*iter)->Path());
+    }
+  }
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n"
+      "#pragma clang diagnostic push\n"
+      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
+      "\n");
+
+  printer->Print(
+      "#pragma mark - $root_class_name$\n"
+      "\n"
+      "@implementation $root_class_name$\n\n",
+      "root_class_name", root_class_name_);
+
+  // Generate the extension initialization structures for the top level and
+  // any nested messages.
+  ostringstream extensions_stringstream;
+  if (file_->extension_count() + file_->message_type_count() > 0) {
+    io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
+    io::Printer extensions_printer(&extensions_outputstream, '$');
+    for (vector<ExtensionGenerator *>::iterator iter =
+             extension_generators_.begin();
+         iter != extension_generators_.end(); ++iter) {
+      (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
+    }
+    for (vector<MessageGenerator *>::iterator iter =
+             message_generators_.begin();
+         iter != message_generators_.end(); ++iter) {
+      (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
+    }
+    extensions_stringstream.flush();
+  }
+
+  // If there were any extensions or this file has any dependencies, output
+  // a registry to override to create the file specific registry.
+  const string& extensions_str = extensions_stringstream.str();
+  if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
+    printer->Print(
+        "+ (GPBExtensionRegistry*)extensionRegistry {\n"
+        "  // This is called by +initialize so there is no need to worry\n"
+        "  // about thread safety and initialization of registry.\n"
+        "  static GPBExtensionRegistry* registry = nil;\n"
+        "  if (!registry) {\n"
+        "    GPBDebugCheckRuntimeVersion();\n"
+        "    registry = [[GPBExtensionRegistry alloc] init];\n");
+
+    printer->Indent();
+    printer->Indent();
+
+    if (extensions_str.length() > 0) {
+      printer->Print(
+          "static GPBExtensionDescription descriptions[] = {\n");
+      printer->Indent();
+      printer->Print(extensions_str.c_str());
+      printer->Outdent();
+      printer->Print(
+          "};\n"
+          "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
+          "  GPBExtensionDescriptor *extension =\n"
+          "      [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n"
+          "  [registry addExtension:extension];\n"
+          "  [self globallyRegisterExtension:extension];\n"
+          "  [extension release];\n"
+          "}\n");
+    }
+
+    const vector<FileGenerator *> &dependency_generators =
+        DependencyGenerators();
+    for (vector<FileGenerator *>::const_iterator iter =
+             dependency_generators.begin();
+         iter != dependency_generators.end(); ++iter) {
+      printer->Print(
+          "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
+          "dependency", (*iter)->RootClassName());
+    }
+
+    printer->Outdent();
+    printer->Outdent();
+
+    printer->Print(
+        "  }\n"
+        "  return registry;\n"
+        "}\n"
+        "\n");
+  }
+
+  printer->Print("@end\n\n");
+
+  // File descriptor only needed if there are messages to use it.
+  if (message_generators_.size() > 0) {
+    string syntax;
+    switch (file_->syntax()) {
+      case FileDescriptor::SYNTAX_UNKNOWN:
+        syntax = "GPBFileSyntaxUnknown";
+        break;
+      case FileDescriptor::SYNTAX_PROTO2:
+        syntax = "GPBFileSyntaxProto2";
+        break;
+      case FileDescriptor::SYNTAX_PROTO3:
+        syntax = "GPBFileSyntaxProto3";
+        break;
+    }
+    printer->Print(
+        "#pragma mark - $root_class_name$_FileDescriptor\n"
+        "\n"
+        "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
+        "  // This is called by +initialize so there is no need to worry\n"
+        "  // about thread safety of the singleton.\n"
+        "  static GPBFileDescriptor *descriptor = NULL;\n"
+        "  if (!descriptor) {\n"
+        "    GPBDebugCheckRuntimeVersion();\n"
+        "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+        "                                                     syntax:$syntax$];\n"
+        "  }\n"
+        "  return descriptor;\n"
+        "}\n"
+        "\n",
+        "root_class_name", root_class_name_,
+        "package", file_->package(),
+        "syntax", syntax);
+  }
+
+  for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
+       iter != enum_generators_.end(); ++iter) {
+    (*iter)->GenerateSource(printer);
+  }
+  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+       iter != message_generators_.end(); ++iter) {
+    (*iter)->GenerateSource(printer);
+  }
+
+  printer->Print(
+    "\n"
+    "#pragma clang diagnostic pop\n"
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n");
+}
+
+const string FileGenerator::Path() const { return FilePath(file_); }
+
+const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
+  if (file_->dependency_count() != dependency_generators_.size()) {
+    set<string> public_import_names;
+    for (int i = 0; i < file_->public_dependency_count(); i++) {
+      public_import_names.insert(file_->public_dependency(i)->name());
+    }
+    for (int i = 0; i < file_->dependency_count(); i++) {
+      FileGenerator *generator =
+          new FileGenerator(file_->dependency(i), options_);
+      const string& name = file_->dependency(i)->name();
+      bool public_import = (public_import_names.count(name) != 0);
+      generator->SetIsPublicDependency(public_import);
+      dependency_generators_.push_back(generator);
+    }
+  }
+  return dependency_generators_;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
new file mode 100644
index 0000000..4c0fcd3
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -0,0 +1,99 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+class FileDescriptor;  // descriptor.h
+namespace io {
+class Printer;  // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class EnumGenerator;
+class ExtensionGenerator;
+class MessageGenerator;
+
+class FileGenerator {
+ public:
+  FileGenerator(const FileDescriptor* file, const Options& options);
+  ~FileGenerator();
+
+  void GenerateSource(io::Printer* printer);
+  void GenerateHeader(io::Printer* printer);
+
+  const string& RootClassName() const { return root_class_name_; }
+  const string Path() const;
+
+  bool IsPublicDependency() const { return is_public_dep_; }
+
+ protected:
+  void SetIsPublicDependency(bool is_public_dep) {
+    is_public_dep_ = is_public_dep;
+  }
+
+ private:
+  const FileDescriptor* file_;
+  string root_class_name_;
+
+  // Access this field through the DependencyGenerators accessor call below.
+  // Do not reference it directly.
+  vector<FileGenerator*> dependency_generators_;
+
+  vector<EnumGenerator*> enum_generators_;
+  vector<MessageGenerator*> message_generators_;
+  vector<ExtensionGenerator*> extension_generators_;
+  bool is_public_dep_;
+
+  const Options options_;
+
+  const vector<FileGenerator*>& DependencyGenerators();
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
new file mode 100644
index 0000000..72e295d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -0,0 +1,101 @@
+// 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.
+
+#include <iostream>
+#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/objectivec/objectivec_file.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+ObjectiveCGenerator::ObjectiveCGenerator() {}
+
+ObjectiveCGenerator::~ObjectiveCGenerator() {}
+
+bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
+                                   const string& parameter,
+                                   OutputDirectory* output_directory,
+                                   string* error) const {
+  // -----------------------------------------------------------------
+  // Parse generator options.
+
+  Options generation_options;
+
+  vector<pair<string, string> > options;
+  ParseGeneratorParameter(parameter, &options);
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "expected_prefixes_path") {
+      generation_options.expected_prefixes_path = options[i].second;
+    } else {
+      *error = "error: Unknown generator option: " + options[i].first;
+      return false;
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  // Validate the objc prefix/package pairing.
+  if (!ValidateObjCClassPrefix(file, generation_options, error)) {
+    // *error will have been filled in.
+    return false;
+  }
+
+  FileGenerator file_generator(file, generation_options);
+  string filepath = FilePath(file);
+
+  // Generate header.
+  {
+    scoped_ptr<io::ZeroCopyOutputStream> output(
+        output_directory->Open(filepath + ".pbobjc.h"));
+    io::Printer printer(output.get(), '$');
+    file_generator.GenerateHeader(&printer);
+  }
+
+  // Generate m file.
+  {
+    scoped_ptr<io::ZeroCopyOutputStream> output(
+        output_directory->Open(filepath + ".pbobjc.m"));
+    io::Printer printer(output.get(), '$');
+    file_generator.GenerateSource(&printer);
+  }
+
+  return true;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
new file mode 100644
index 0000000..09266b0
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
@@ -0,0 +1,61 @@
+// 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.
+
+// Generates ObjectiveC code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator {
+ public:
+  ObjectiveCGenerator();
+  ~ObjectiveCGenerator();
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file, const string& parameter,
+                OutputDirectory* output_directory, string* error) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
new file mode 100644
index 0000000..196b39d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -0,0 +1,1295 @@
+// 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.
+
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <climits>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+#include <vector>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+// error cases, so it seems to be ok to use as a back door for errors.
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+Options::Options() {
+  // Default is the value of the env for the package prefixes.
+  const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
+  if (file_path) {
+    expected_prefixes_path = file_path;
+  }
+}
+
+namespace {
+
+hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) {
+  hash_set<string> result;
+  for (int i = 0; i < num_words; i++) {
+    result.insert(words[i]);
+  }
+  return result;
+}
+
+const char* const kUpperSegmentsList[] = {"url", "http", "https"};
+
+hash_set<string> kUpperSegments =
+    MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
+
+// Internal helper for name handing.
+// Do not expose this outside of helpers, stick to having functions for specific
+// cases (ClassName(), FieldName()), so there is always consistent suffix rules.
+string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
+  vector<string> values;
+  string current;
+
+  bool last_char_was_number = false;
+  bool last_char_was_lower = false;
+  bool last_char_was_upper = false;
+  for (int i = 0; i < input.size(); i++) {
+    char c = input[i];
+    if (ascii_isdigit(c)) {
+      if (!last_char_was_number) {
+        values.push_back(current);
+        current = "";
+      }
+      current += c;
+      last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+      last_char_was_number = true;
+    } else if (ascii_islower(c)) {
+      // lowercase letter can follow a lowercase or uppercase letter
+      if (!last_char_was_lower && !last_char_was_upper) {
+        values.push_back(current);
+        current = "";
+      }
+      current += c;  // already lower
+      last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+      last_char_was_lower = true;
+    } else if (ascii_isupper(c)) {
+      if (!last_char_was_upper) {
+        values.push_back(current);
+        current = "";
+      }
+      current += ascii_tolower(c);
+      last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+      last_char_was_upper = true;
+    } else {
+      last_char_was_number = last_char_was_lower = last_char_was_upper = false;
+    }
+  }
+  values.push_back(current);
+
+  string result;
+  bool first_segment_forces_upper = false;
+  for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
+    string value = *i;
+    bool all_upper = (kUpperSegments.count(value) > 0);
+    if (all_upper && (result.length() == 0)) {
+      first_segment_forces_upper = true;
+    }
+    for (int j = 0; j < value.length(); j++) {
+      if (j == 0 || all_upper) {
+        value[j] = ascii_toupper(value[j]);
+      } else {
+        // Nothing, already in lower.
+      }
+    }
+    result += value;
+  }
+  if ((result.length() != 0) &&
+      !first_capitalized &&
+      !first_segment_forces_upper) {
+    result[0] = ascii_tolower(result[0]);
+  }
+  return result;
+}
+
+const char* const kReservedWordList[] = {
+    // Objective C "keywords" that aren't in C
+    // From
+    // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
+    "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
+    "self",
+
+    // C/C++ keywords (Incl C++ 0x11)
+    // From http://en.cppreference.com/w/cpp/keywords
+    "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
+    "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
+    "compl", "const", "constexpr", "const_cast", "continue", "decltype",
+    "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
+    "export", "extern ", "false", "float", "for", "friend", "goto", "if",
+    "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
+    "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
+    "public", "register", "reinterpret_cast", "return", "short", "signed",
+    "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
+    "template", "this", "thread_local", "throw", "true", "try", "typedef",
+    "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
+    "volatile", "wchar_t", "while", "xor", "xor_eq",
+
+    // C99 keywords
+    // From
+    // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
+    "restrict",
+
+    // Objective-C Runtime typedefs
+    // From <obc/runtime.h>
+    "Category", "Ivar", "Method", "Protocol",
+
+    // NSObject Methods
+    // new is covered by C++ keywords.
+    "description", "debugDescription", "finalize", "hash", "dealloc", "init",
+    "class", "superclass", "retain", "release", "autorelease", "retainCount",
+    "zone", "isProxy", "copy", "mutableCopy", "classForCoder",
+
+    // GPBMessage Methods
+    // Only need to add instance methods that may conflict with
+    // method declared in protos. The main cases are methods
+    // that take no arguments, or setFoo:/hasFoo: type methods.
+    "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
+    "extensionsCurrentlySet", "isInitialized", "serializedSize",
+    "sortedExtensionsInUse", "unknownFields",
+
+    // MacTypes.h names
+    "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
+    "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
+    "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
+    "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
+    "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
+};
+
+hash_set<string> kReservedWords =
+    MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
+
+string SanitizeNameForObjC(const string& input, const string& extension) {
+  if (kReservedWords.count(input) > 0) {
+    return input + extension;
+  }
+  return input;
+}
+
+string NameFromFieldDescriptor(const FieldDescriptor* field) {
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    return field->message_type()->name();
+  } else {
+    return field->name();
+  }
+}
+
+void PathSplit(const string& path, string* directory, string* basename) {
+  string::size_type last_slash = path.rfind('/');
+  if (last_slash == string::npos) {
+    if (directory) {
+      *directory = "";
+    }
+    if (basename) {
+      *basename = path;
+    }
+  } else {
+    if (directory) {
+      *directory = path.substr(0, last_slash);
+    }
+    if (basename) {
+      *basename = path.substr(last_slash + 1);
+    }
+  }
+}
+
+bool IsSpecialName(const string& name, const string* special_names,
+                   size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    size_t length = special_names[i].length();
+    if (name.compare(0, length, special_names[i]) == 0) {
+      if (name.length() > length) {
+        // If name is longer than the retained_name[i] that it matches
+        // the next character must be not lower case (newton vs newTon vs
+        // new_ton).
+        return !ascii_islower(name[length]);
+      } else {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+// Escape C++ trigraphs by escaping question marks to \?
+string EscapeTrigraphs(const string& to_escape) {
+  return StringReplace(to_escape, "?", "\\?", true);
+}
+
+string StripProto(const string& filename) {
+  if (HasSuffixString(filename, ".protodevel")) {
+    return StripSuffixString(filename, ".protodevel");
+  } else {
+    return StripSuffixString(filename, ".proto");
+  }
+}
+
+bool IsRetainedName(const string& name) {
+  // List of prefixes from
+  // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
+  static const string retained_names[] = {"new", "alloc", "copy",
+                                          "mutableCopy"};
+  return IsSpecialName(name, retained_names,
+                       sizeof(retained_names) / sizeof(retained_names[0]));
+}
+
+bool IsInitName(const string& name) {
+  static const string init_names[] = {"init"};
+  return IsSpecialName(name, init_names,
+                       sizeof(init_names) / sizeof(init_names[0]));
+}
+
+string BaseFileName(const FileDescriptor* file) {
+  string basename;
+  PathSplit(file->name(), NULL, &basename);
+  return basename;
+}
+
+string FileName(const FileDescriptor* file) {
+  string path = FilePath(file);
+  string basename;
+  PathSplit(path, NULL, &basename);
+  return basename;
+}
+
+string FilePath(const FileDescriptor* file) {
+  string output;
+  string basename;
+  string directory;
+  PathSplit(file->name(), &directory, &basename);
+  if (directory.length() > 0) {
+    output = directory + "/";
+  }
+  basename = StripProto(basename);
+
+  // CamelCase to be more ObjC friendly.
+  basename = UnderscoresToCamelCase(basename, true);
+
+  output += basename;
+  return output;
+}
+
+string FileClassPrefix(const FileDescriptor* file) {
+  // Default is empty string, no need to check has_objc_class_prefix.
+  string result = file->options().objc_class_prefix();
+  return result;
+}
+
+string FileClassName(const FileDescriptor* file) {
+  string name = FileClassPrefix(file);
+  name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
+  name += "Root";
+  // There aren't really any reserved words that end in "Root", but playing
+  // it safe and checking.
+  return SanitizeNameForObjC(name, "_RootClass");
+}
+
+string ClassNameWorker(const Descriptor* descriptor) {
+  string name;
+  if (descriptor->containing_type() != NULL) {
+    name = ClassNameWorker(descriptor->containing_type());
+    name += "_";
+  }
+  return name + descriptor->name();
+}
+
+string ClassNameWorker(const EnumDescriptor* descriptor) {
+  string name;
+  if (descriptor->containing_type() != NULL) {
+    name = ClassNameWorker(descriptor->containing_type());
+    name += "_";
+  }
+  return name + descriptor->name();
+}
+
+string ClassName(const Descriptor* descriptor) {
+  // 1. Message names are used as is (style calls for CamelCase, trust it).
+  // 2. Check for reserved word at the very end and then suffix things.
+  string prefix = FileClassPrefix(descriptor->file());
+  string name = ClassNameWorker(descriptor);
+  return SanitizeNameForObjC(prefix + name, "_Class");
+}
+
+string EnumName(const EnumDescriptor* descriptor) {
+  // 1. Enum names are used as is (style calls for CamelCase, trust it).
+  // 2. Check for reserved word at the every end and then suffix things.
+  //      message Fixed {
+  //        message Size {...}
+  //        enum Mumble {...}
+  //      ...
+  //      }
+  //    yields Fixed_Class, Fixed_Size.
+  string name = FileClassPrefix(descriptor->file());
+  name += ClassNameWorker(descriptor);
+  return SanitizeNameForObjC(name, "_Enum");
+}
+
+string EnumValueName(const EnumValueDescriptor* descriptor) {
+  // Because of the Switch enum compatibility, the name on the enum has to have
+  // the suffix handing, so it slightly diverges from how nested classes work.
+  //   enum Fixed {
+  //     FOO = 1
+  //   }
+  // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
+  const string& class_name = EnumName(descriptor->type());
+  const string& value_str = UnderscoresToCamelCase(descriptor->name(), true);
+  const string& name = class_name + "_" + value_str;
+  // There aren't really any reserved words with an underscore and a leading
+  // capital letter, but playing it safe and checking.
+  return SanitizeNameForObjC(name, "_Value");
+}
+
+string EnumValueShortName(const EnumValueDescriptor* descriptor) {
+  // Enum value names (EnumValueName above) are the enum name turned into
+  // a class name and then the value name is CamelCased and concatenated; the
+  // whole thing then gets sanitized for reserved words.
+  // The "short name" is intended to be the final leaf, the value name; but
+  // you can't simply send that off to sanitize as that could result in it
+  // getting modified when the full name didn't.  For example enum
+  // "StorageModes" has a value "retain".  So the full name is
+  // "StorageModes_Retain", but if we sanitize "retain" it would become
+  // "RetainValue".
+  // So the right way to get the short name is to take the full enum name
+  // and then strip off the enum name (leaving the value name and anything
+  // done by sanitize).
+  const string& class_name = EnumName(descriptor->type());
+  const string& long_name_prefix = class_name + "_";
+  const string& long_name = EnumValueName(descriptor);
+  return StripPrefixString(long_name, long_name_prefix);
+}
+
+string UnCamelCaseEnumShortName(const string& name) {
+  string result;
+  for (int i = 0; i < name.size(); i++) {
+    char c = name[i];
+    if (i > 0 && ascii_isupper(c)) {
+      result += '_';
+    }
+    result += ascii_toupper(c);
+  }
+  return result;
+}
+
+string ExtensionMethodName(const FieldDescriptor* descriptor) {
+  const string& name = NameFromFieldDescriptor(descriptor);
+  const string& result = UnderscoresToCamelCase(name, false);
+  return SanitizeNameForObjC(result, "_Extension");
+}
+
+string FieldName(const FieldDescriptor* field) {
+  const string& name = NameFromFieldDescriptor(field);
+  string result = UnderscoresToCamelCase(name, false);
+  if (field->is_repeated() && !field->is_map()) {
+    // Add "Array" before do check for reserved worlds.
+    result += "Array";
+  } else {
+    // If it wasn't repeated, but ends in "Array", force on the _p suffix.
+    if (HasSuffixString(result, "Array")) {
+      result += "_p";
+    }
+  }
+  return SanitizeNameForObjC(result, "_p");
+}
+
+string FieldNameCapitalized(const FieldDescriptor* field) {
+  // Want the same suffix handling, so upcase the first letter of the other
+  // name.
+  string result = FieldName(field);
+  if (result.length() > 0) {
+    result[0] = ascii_toupper(result[0]);
+  }
+  return result;
+}
+
+string OneofEnumName(const OneofDescriptor* descriptor) {
+  const Descriptor* fieldDescriptor = descriptor->containing_type();
+  string name = ClassName(fieldDescriptor);
+  name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase";
+  // No sanitize needed because the OS never has names that end in _OneOfCase.
+  return name;
+}
+
+string OneofName(const OneofDescriptor* descriptor) {
+  string name = UnderscoresToCamelCase(descriptor->name(), false);
+  // No sanitize needed because it gets OneOfCase added and that shouldn't
+  // ever conflict.
+  return name;
+}
+
+string OneofNameCapitalized(const OneofDescriptor* descriptor) {
+  // Use the common handling and then up-case the first letter.
+  string result = OneofName(descriptor);
+  if (result.length() > 0) {
+    result[0] = ascii_toupper(result[0]);
+  }
+  return result;
+}
+
+string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field) {
+  string worker(name);
+  if (HasSuffixString(worker, "_p")) {
+    worker = StripSuffixString(worker, "_p");
+  }
+  if (field->is_repeated() && HasSuffixString(worker, "Array")) {
+    worker = StripSuffixString(worker, "Array");
+  }
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    if (worker.length() > 0) {
+      if (ascii_islower(worker[0])) {
+        worker[0] = ascii_toupper(worker[0]);
+      }
+    }
+    return worker;
+  } else {
+    string result;
+    for (int i = 0; i < worker.size(); i++) {
+      char c = worker[i];
+      if (ascii_isupper(c)) {
+        if (i > 0) {
+          result += '_';
+        }
+        result += ascii_tolower(c);
+      } else {
+        result += c;
+      }
+    }
+    return result;
+  }
+}
+
+string GetCapitalizedType(const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32:
+      return "Int32";
+    case FieldDescriptor::TYPE_UINT32:
+      return "UInt32";
+    case FieldDescriptor::TYPE_SINT32:
+      return "SInt32";
+    case FieldDescriptor::TYPE_FIXED32:
+      return "Fixed32";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "SFixed32";
+    case FieldDescriptor::TYPE_INT64:
+      return "Int64";
+    case FieldDescriptor::TYPE_UINT64:
+      return "UInt64";
+    case FieldDescriptor::TYPE_SINT64:
+      return "SInt64";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "Fixed64";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "SFixed64";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "Float";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "Double";
+    case FieldDescriptor::TYPE_BOOL:
+      return "Bool";
+    case FieldDescriptor::TYPE_STRING:
+      return "String";
+    case FieldDescriptor::TYPE_BYTES:
+      return "Bytes";
+    case FieldDescriptor::TYPE_ENUM:
+      return "Enum";
+    case FieldDescriptor::TYPE_GROUP:
+      return "Group";
+    case FieldDescriptor::TYPE_MESSAGE:
+      return "Message";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
+  switch (field_type) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SFIXED32:
+      return OBJECTIVECTYPE_INT32;
+
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_FIXED32:
+      return OBJECTIVECTYPE_UINT32;
+
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      return OBJECTIVECTYPE_INT64;
+
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+      return OBJECTIVECTYPE_UINT64;
+
+    case FieldDescriptor::TYPE_FLOAT:
+      return OBJECTIVECTYPE_FLOAT;
+
+    case FieldDescriptor::TYPE_DOUBLE:
+      return OBJECTIVECTYPE_DOUBLE;
+
+    case FieldDescriptor::TYPE_BOOL:
+      return OBJECTIVECTYPE_BOOLEAN;
+
+    case FieldDescriptor::TYPE_STRING:
+      return OBJECTIVECTYPE_STRING;
+
+    case FieldDescriptor::TYPE_BYTES:
+      return OBJECTIVECTYPE_DATA;
+
+    case FieldDescriptor::TYPE_ENUM:
+      return OBJECTIVECTYPE_ENUM;
+
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      return OBJECTIVECTYPE_MESSAGE;
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return OBJECTIVECTYPE_INT32;
+}
+
+bool IsPrimitiveType(const FieldDescriptor* field) {
+  ObjectiveCType type = GetObjectiveCType(field);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+    case OBJECTIVECTYPE_UINT32:
+    case OBJECTIVECTYPE_INT64:
+    case OBJECTIVECTYPE_UINT64:
+    case OBJECTIVECTYPE_FLOAT:
+    case OBJECTIVECTYPE_DOUBLE:
+    case OBJECTIVECTYPE_BOOLEAN:
+    case OBJECTIVECTYPE_ENUM:
+      return true;
+      break;
+    default:
+      return false;
+  }
+}
+
+bool IsReferenceType(const FieldDescriptor* field) {
+  return !IsPrimitiveType(field);
+}
+
+static string HandleExtremeFloatingPoint(string val, bool add_float_suffix) {
+  if (val == "nan") {
+    return "NAN";
+  } else if (val == "inf") {
+    return "INFINITY";
+  } else if (val == "-inf") {
+    return "-INFINITY";
+  } else {
+    // float strings with ., e or E need to have f appended
+    if (add_float_suffix &&
+        (val.find(".") != string::npos || val.find("e") != string::npos ||
+         val.find("E") != string::npos)) {
+      val += "f";
+    }
+    return val;
+  }
+}
+
+string GPBGenericValueFieldName(const FieldDescriptor* field) {
+  // Returns the field within the GPBGenericValue union to use for the given
+  // field.
+  if (field->is_repeated()) {
+      return "valueMessage";
+  }
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return "valueInt32";
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return "valueUInt32";
+    case FieldDescriptor::CPPTYPE_INT64:
+      return "valueInt64";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return "valueUInt64";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "valueFloat";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "valueDouble";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "valueBool";
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->type() == FieldDescriptor::TYPE_BYTES) {
+        return "valueData";
+      } else {
+        return "valueString";
+      }
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return "valueEnum";
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "valueMessage";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+
+string DefaultValue(const FieldDescriptor* field) {
+  // Repeated fields don't have defaults.
+  if (field->is_repeated()) {
+    return "nil";
+  }
+
+  // Switch on cpp_type since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      // gcc and llvm reject the decimal form of kint32min and kint64min.
+      if (field->default_value_int32() == INT_MIN) {
+        return "-0x80000000";
+      }
+      return SimpleItoa(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return SimpleItoa(field->default_value_uint32()) + "U";
+    case FieldDescriptor::CPPTYPE_INT64:
+      // gcc and llvm reject the decimal form of kint32min and kint64min.
+      if (field->default_value_int64() == LLONG_MIN) {
+        return "-0x8000000000000000LL";
+      }
+      return SimpleItoa(field->default_value_int64()) + "LL";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return SimpleItoa(field->default_value_uint64()) + "ULL";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return HandleExtremeFloatingPoint(
+          SimpleDtoa(field->default_value_double()), false);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return HandleExtremeFloatingPoint(
+          SimpleFtoa(field->default_value_float()), true);
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "YES" : "NO";
+    case FieldDescriptor::CPPTYPE_STRING: {
+      const bool has_default_value = field->has_default_value();
+      const string& default_string = field->default_value_string();
+      if (!has_default_value || default_string.length() == 0) {
+        // If the field is defined as being the empty string,
+        // then we will just assign to nil, as the empty string is the
+        // default for both strings and data.
+        return "nil";
+      }
+      if (field->type() == FieldDescriptor::TYPE_BYTES) {
+        // We want constant fields in our data structures so we can
+        // declare them as static. To achieve this we cheat and stuff
+        // a escaped c string (prefixed with a length) into the data
+        // field, and cast it to an (NSData*) so it will compile.
+        // The runtime library knows how to handle it.
+
+        // Must convert to a standard byte order for packing length into
+        // a cstring.
+        uint32 length = ghtonl(default_string.length());
+        string bytes((const char*)&length, sizeof(length));
+        bytes.append(default_string);
+        return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\"";
+      } else {
+        return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\"";
+      }
+    }
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return EnumValueName(field->default_value_enum());
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "nil";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
+  // Repeated fields don't have defaults.
+  if (field->is_repeated()) {
+    return false;
+  }
+
+  // As much as checking field->has_default_value() seems useful, it isn't
+  // because of enums. proto2 syntax allows the first item in an enum (the
+  // default) to be non zero. So checking field->has_default_value() would
+  // result in missing this non zero default.  See MessageWithOneBasedEnum in
+  // objectivec/Tests/unittest_objc.proto for a test Message to confirm this.
+
+  // Some proto file set the default to the zero value, so make sure the value
+  // isn't the zero case.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return field->default_value_int32() != 0;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return field->default_value_uint32() != 0U;
+    case FieldDescriptor::CPPTYPE_INT64:
+      return field->default_value_int64() != 0LL;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return field->default_value_uint64() != 0ULL;
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return field->default_value_double() != 0.0;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return field->default_value_float() != 0.0f;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool();
+    case FieldDescriptor::CPPTYPE_STRING: {
+      const string& default_string = field->default_value_string();
+      return default_string.length() != 0;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return field->default_value_enum()->number() != 0;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return false;
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+string BuildFlagsString(const vector<string>& strings) {
+  if (strings.size() == 0) {
+    return "0";
+  }
+  string string;
+  for (size_t i = 0; i != strings.size(); ++i) {
+    if (i > 0) {
+      string.append(" | ");
+    }
+    string.append(strings[i]);
+  }
+  return string;
+}
+
+string BuildCommentsString(const SourceLocation& location) {
+  const string& comments = location.leading_comments.empty()
+                               ? location.trailing_comments
+                               : location.leading_comments;
+  vector<string> lines;
+  SplitStringAllowEmpty(comments, "\n", &lines);
+  while (!lines.empty() && lines.back().empty()) {
+    lines.pop_back();
+  }
+  string prefix("///");
+  string suffix("\n");
+  string final_comments;
+  for (int i = 0; i < lines.size(); i++) {
+    // HeaderDoc uses '\' and '@' for markers; escape them.
+    const string line = StringReplace(lines[i], "\\", "\\\\", true);
+    final_comments +=
+        prefix + StringReplace(line, "@", "\\@", true) + suffix;
+  }
+  return final_comments;
+}
+
+namespace {
+
+// Internal helper class that parses the expected package to prefix mappings
+// file.
+class Parser {
+ public:
+  Parser(map<string, string>* inout_package_to_prefix_map)
+      : prefix_map_(inout_package_to_prefix_map), line_(0) {}
+
+  // Parses a check of input, returning success/failure.
+  bool ParseChunk(StringPiece chunk);
+
+  // Should be called to finish parsing (after all input has been provided via
+  // ParseChunk()).  Returns success/failure.
+  bool Finish();
+
+  int last_line() const { return line_; }
+  string error_str() const { return error_str_; }
+
+ private:
+  bool ParseLoop();
+
+  map<string, string>* prefix_map_;
+  int line_;
+  string error_str_;
+  StringPiece p_;
+  string leftover_;
+};
+
+bool Parser::ParseChunk(StringPiece chunk) {
+  if (!leftover_.empty()) {
+    chunk.AppendToString(&leftover_);
+    p_ = StringPiece(leftover_);
+  } else {
+    p_ = chunk;
+  }
+  bool result = ParseLoop();
+  if (p_.empty()) {
+    leftover_.clear();
+  } else {
+    leftover_ = p_.ToString();
+  }
+  return result;
+}
+
+bool Parser::Finish() {
+  if (leftover_.empty()) {
+    return true;
+  }
+  // Force a newline onto the end to finish parsing.
+  p_ = StringPiece(leftover_ + "\n");
+  if (!ParseLoop()) {
+    return false;
+  }
+  return p_.empty();  // Everything used?
+}
+
+static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; }
+
+bool ReadLine(StringPiece* input, StringPiece* line) {
+  for (int len = 0; len < input->size(); ++len) {
+    if (ascii_isnewline((*input)[len])) {
+      *line = StringPiece(input->data(), len);
+      ++len;  // advance over the newline
+      *input = StringPiece(input->data() + len, input->size() - len);
+      return true;
+    }
+  }
+  return false;  // Ran out of input with no newline.
+}
+
+void TrimWhitespace(StringPiece* input) {
+  while (!input->empty() && ascii_isspace(*input->data())) {
+    input->remove_prefix(1);
+  }
+  while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
+    input->remove_suffix(1);
+  }
+}
+
+void RemoveComment(StringPiece* input) {
+  int offset = input->find('#');
+  if (offset != StringPiece::npos) {
+    input->remove_suffix(input->length() - offset);
+  }
+}
+
+bool Parser::ParseLoop() {
+  StringPiece line;
+  while (ReadLine(&p_, &line)) {
+    ++line_;
+    RemoveComment(&line);
+    TrimWhitespace(&line);
+    if (line.size() == 0) {
+      continue;  // Blank line.
+    }
+    int offset = line.find('=');
+    if (offset == StringPiece::npos) {
+      error_str_ =
+          string("Line without equal sign: '") + line.ToString() + "'.";
+      return false;
+    }
+    StringPiece package(line, 0, offset);
+    StringPiece prefix(line, offset + 1, line.length() - offset - 1);
+    TrimWhitespace(&package);
+    TrimWhitespace(&prefix);
+    // Don't really worry about error checking the package/prefix for
+    // being valid.  Assume the file is validated when it is created/edited.
+    (*prefix_map_)[package.ToString()] = prefix.ToString();
+  }
+  return true;
+}
+
+bool LoadExpectedPackagePrefixes(const Options &generation_options,
+                                 map<string, string>* prefix_map,
+                                 string* out_error) {
+  if (generation_options.expected_prefixes_path.empty()) {
+    return true;
+  }
+
+  int fd;
+  do {
+    fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY);
+  } while (fd < 0 && errno == EINTR);
+  if (fd < 0) {
+    *out_error =
+        string("error: Unable to open \"") +
+        generation_options.expected_prefixes_path +
+        "\", " + strerror(errno);
+    return false;
+  }
+  io::FileInputStream file_stream(fd);
+  file_stream.SetCloseOnDelete(true);
+
+  Parser parser(prefix_map);
+  const void* buf;
+  int buf_len;
+  while (file_stream.Next(&buf, &buf_len)) {
+    if (buf_len == 0) {
+      continue;
+    }
+
+    if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
+      *out_error =
+          string("error: ") + generation_options.expected_prefixes_path +
+          " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
+      return false;
+    }
+  }
+  return parser.Finish();
+}
+
+}  // namespace
+
+bool ValidateObjCClassPrefix(const FileDescriptor* file,
+                             const Options& generation_options,
+                             string* out_error) {
+  const string prefix = file->options().objc_class_prefix();
+  const string package = file->package();
+
+  // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+  // error cases, so it seems to be ok to use as a back door for warnings.
+
+  // Load any expected package prefixes to validate against those.
+  map<string, string> expected_package_prefixes;
+  if (!LoadExpectedPackagePrefixes(generation_options,
+                                   &expected_package_prefixes,
+                                   out_error)) {
+    return false;
+  }
+
+  // Check: Error - See if there was an expected prefix for the package and
+  // report if it doesn't match (wrong or missing).
+  map<string, string>::iterator package_match =
+      expected_package_prefixes.find(package);
+  if (package_match != expected_package_prefixes.end()) {
+    // There was an entry, and...
+    if (package_match->second == prefix) {
+      // ...it matches.  All good, out of here!
+      return true;
+    } else {
+      // ...it didn't match!
+      *out_error = "error: Expected 'option objc_class_prefix = \"" +
+                   package_match->second + "\";' for package '" + package +
+                   "' in '" + file->name() + "'";
+      if (prefix.length()) {
+        *out_error += "; but found '" + prefix + "' instead";
+      }
+      *out_error += ".";
+      return false;
+    }
+  }
+
+  // If there was no prefix option, we're done at this point.
+  if (prefix.length() == 0) {
+    // No prefix, nothing left to check.
+    return true;
+  }
+
+  // Check: Error - Make sure the prefix wasn't expected for a different
+  // package (overlap is allowed, but it has to be listed as an expected
+  // overlap).
+  for (map<string, string>::iterator i = expected_package_prefixes.begin();
+       i != expected_package_prefixes.end(); ++i) {
+    if (i->second == prefix) {
+      *out_error =
+          "error: Found 'option objc_class_prefix = \"" + prefix +
+          "\";' in '" + file->name() +
+          "'; that prefix is already used for 'package " + i->first +
+          ";'. It can only be reused by listing it in the expected file (" +
+          generation_options.expected_prefixes_path + ").";
+      return false;  // Only report first usage of the prefix.
+    }
+  }
+
+  // Check: Warning - Make sure the prefix is is a reasonable value according
+  // to Apple's rules (the checks above implicitly whitelist anything that
+  // doesn't meet these rules).
+  if (!ascii_isupper(prefix[0])) {
+    cerr << endl
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " it should start with a capital letter." << endl;
+    cerr.flush();
+  }
+  if (prefix.length() < 3) {
+    // Apple reserves 2 character prefixes for themselves. They do use some
+    // 3 character prefixes, but they haven't updated the rules/docs.
+    cerr << endl
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " Apple recommends they should be at least 3 characters long."
+         << endl;
+    cerr.flush();
+  }
+
+  // Check: Warning - If the given package/prefix pair wasn't expected, issue a
+  // warning issue a warning suggesting it gets added to the file.
+  if (!expected_package_prefixes.empty()) {
+    cerr << endl
+         << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " consider adding it to the expected prefixes file ("
+         << generation_options.expected_prefixes_path << ")." << endl;
+    cerr.flush();
+  }
+
+  return true;
+}
+
+void TextFormatDecodeData::AddString(int32 key,
+                                     const string& input_for_decode,
+                                     const string& desired_output) {
+  for (vector<DataEntry>::const_iterator i = entries_.begin();
+       i != entries_.end(); ++i) {
+    if (i->first == key) {
+      cerr << "error: duplicate key (" << key
+           << ") making TextFormat data, input: \"" << input_for_decode
+           << "\", desired: \"" << desired_output << "\"." << endl;
+      cerr.flush();
+      abort();
+    }
+  }
+
+  const string& data = TextFormatDecodeData::DecodeDataForString(
+      input_for_decode, desired_output);
+  entries_.push_back(DataEntry(key, data));
+}
+
+string TextFormatDecodeData::Data() const {
+  ostringstream data_stringstream;
+
+  if (num_entries() > 0) {
+    io::OstreamOutputStream data_outputstream(&data_stringstream);
+    io::CodedOutputStream output_stream(&data_outputstream);
+
+    output_stream.WriteVarint32(num_entries());
+    for (vector<DataEntry>::const_iterator i = entries_.begin();
+         i != entries_.end(); ++i) {
+      output_stream.WriteVarint32(i->first);
+      output_stream.WriteString(i->second);
+    }
+  }
+
+  data_stringstream.flush();
+  return data_stringstream.str();
+}
+
+namespace {
+
+// Helper to build up the decode data for a string.
+class DecodeDataBuilder {
+ public:
+  DecodeDataBuilder() { Reset(); }
+
+  bool AddCharacter(const char desired, const char input);
+  void AddUnderscore() {
+    Push();
+    need_underscore_ = true;
+  }
+  string Finish() {
+    Push();
+    return decode_data_;
+  }
+
+ private:
+  static const uint8 kAddUnderscore = 0x80;
+
+  static const uint8 kOpAsIs        = 0x00;
+  static const uint8 kOpFirstUpper  = 0x40;
+  static const uint8 kOpFirstLower  = 0x20;
+  static const uint8 kOpAllUpper    = 0x60;
+
+  static const int kMaxSegmentLen     = 0x1f;
+
+  void AddChar(const char desired) {
+    ++segment_len_;
+    is_all_upper_ &= ascii_isupper(desired);
+  }
+
+  void Push() {
+    uint8 op = (op_ | segment_len_);
+    if (need_underscore_) op |= kAddUnderscore;
+    if (op != 0) {
+      decode_data_ += (char)op;
+    }
+    Reset();
+  }
+
+  bool AddFirst(const char desired, const char input) {
+    if (desired == input) {
+      op_ = kOpAsIs;
+    } else if (desired == ascii_toupper(input)) {
+      op_ = kOpFirstUpper;
+    } else if (desired == ascii_tolower(input)) {
+      op_ = kOpFirstLower;
+    } else {
+      // Can't be transformed to match.
+      return false;
+    }
+    AddChar(desired);
+    return true;
+  }
+
+  void Reset() {
+    need_underscore_ = false;
+    op_ = 0;
+    segment_len_ = 0;
+    is_all_upper_ = true;
+  }
+
+  bool need_underscore_;
+  bool is_all_upper_;
+  uint8 op_;
+  int segment_len_;
+
+  string decode_data_;
+};
+
+bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
+  // If we've hit the max size, push to start a new segment.
+  if (segment_len_ == kMaxSegmentLen) {
+    Push();
+  }
+  if (segment_len_ == 0) {
+    return AddFirst(desired, input);
+  }
+
+  // Desired and input match...
+  if (desired == input) {
+    // If we aren't transforming it, or we're upper casing it and it is
+    // supposed to be uppercase; just add it to the segment.
+    if ((op_ != kOpAllUpper) || ascii_isupper(desired)) {
+      AddChar(desired);
+      return true;
+    }
+
+    // Add the current segment, and start the next one.
+    Push();
+    return AddFirst(desired, input);
+  }
+
+  // If we need to uppercase, and everything so far has been uppercase,
+  // promote op to AllUpper.
+  if ((desired == ascii_toupper(input)) && is_all_upper_) {
+    op_ = kOpAllUpper;
+    AddChar(desired);
+    return true;
+  }
+
+  // Give up, push and start a new segment.
+  Push();
+  return AddFirst(desired, input);
+}
+
+// If decode data can't be generated, a directive for the raw string
+// is used instead.
+string DirectDecodeString(const string& str) {
+  string result;
+  result += (char)'\0';  // Marker for full string.
+  result += str;
+  result += (char)'\0';  // End of string.
+  return result;
+}
+
+}  // namespace
+
+// static
+string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode,
+                                                 const string& desired_output) {
+  if ((input_for_decode.size() == 0) || (desired_output.size() == 0)) {
+    cerr << "error: got empty string for making TextFormat data, input: \""
+         << input_for_decode << "\", desired: \"" << desired_output << "\"."
+         << endl;
+    cerr.flush();
+    abort();
+  }
+  if ((input_for_decode.find('\0') != string::npos) ||
+      (desired_output.find('\0') != string::npos)) {
+    cerr << "error: got a null char in a string for making TextFormat data,"
+         << " input: \"" << CEscape(input_for_decode) << "\", desired: \""
+         << CEscape(desired_output) << "\"." << endl;
+    cerr.flush();
+    abort();
+  }
+
+  DecodeDataBuilder builder;
+
+  // Walk the output building it from the input.
+  int x = 0;
+  for (int y = 0; y < desired_output.size(); y++) {
+    const char d = desired_output[y];
+    if (d == '_') {
+      builder.AddUnderscore();
+      continue;
+    }
+
+    if (x >= input_for_decode.size()) {
+      // Out of input, no way to encode it, just return a full decode.
+      return DirectDecodeString(desired_output);
+    }
+    if (builder.AddCharacter(d, input_for_decode[x])) {
+      ++x;  // Consumed one input
+    } else {
+      // Couldn't transform for the next character, just return a full decode.
+      return DirectDecodeString(desired_output);
+    }
+  }
+
+  if (x != input_for_decode.size()) {
+    // Extra input (suffix from name sanitizing?), just return a full decode.
+    return DirectDecodeString(desired_output);
+  }
+
+  // Add the end marker.
+  return builder.Finish() + (char)'\0';
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
new file mode 100644
index 0000000..3f56d94
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -0,0 +1,204 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// Generator options (see objectivec_generator.cc for a description of each):
+struct Options {
+  Options();
+  string expected_prefixes_path;
+};
+
+// Escape C++ trigraphs by escaping question marks to "\?".
+string EscapeTrigraphs(const string& to_escape);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Returns true if the name requires a ns_returns_not_retained attribute applied
+// to it.
+bool IsRetainedName(const string& name);
+
+// Returns true if the name starts with "init" and will need to have special
+// handling under ARC.
+bool IsInitName(const string& name);
+
+// Gets the name of the file we're going to generate (sans the .pb.h
+// extension).  This does not include the path to that file.
+string FileName(const FileDescriptor* file);
+
+// Gets the path of the file we're going to generate (sans the .pb.h
+// extension).  The path will be dependent on the objectivec package
+// declared in the proto package.
+string FilePath(const FileDescriptor* file);
+
+// Gets the name of the root class we'll generate in the file.  This class
+// is not meant for external consumption, but instead contains helpers that
+// the rest of the classes need
+string FileClassName(const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+string ClassName(const Descriptor* descriptor);
+string EnumName(const EnumDescriptor* descriptor);
+
+// Returns the fully-qualified name of the enum value corresponding to the
+// the descriptor.
+string EnumValueName(const EnumValueDescriptor* descriptor);
+
+// Returns the name of the enum value corresponding to the descriptor.
+string EnumValueShortName(const EnumValueDescriptor* descriptor);
+
+// Reverse what an enum does.
+string UnCamelCaseEnumShortName(const string& name);
+
+// Returns the name to use for the extension (used as the method off the file's
+// Root class).
+string ExtensionMethodName(const FieldDescriptor* descriptor);
+
+// Returns the transformed field name.
+string FieldName(const FieldDescriptor* field);
+string FieldNameCapitalized(const FieldDescriptor* field);
+
+// Returns the transformed oneof name.
+string OneofEnumName(const OneofDescriptor* descriptor);
+string OneofName(const OneofDescriptor* descriptor);
+string OneofNameCapitalized(const OneofDescriptor* descriptor);
+
+inline bool HasFieldPresence(const FileDescriptor* file) {
+  return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+  return descriptor->options().map_entry();
+}
+
+// Reverse of the above.
+string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field);
+
+enum ObjectiveCType {
+  OBJECTIVECTYPE_INT32,
+  OBJECTIVECTYPE_UINT32,
+  OBJECTIVECTYPE_INT64,
+  OBJECTIVECTYPE_UINT64,
+  OBJECTIVECTYPE_FLOAT,
+  OBJECTIVECTYPE_DOUBLE,
+  OBJECTIVECTYPE_BOOLEAN,
+  OBJECTIVECTYPE_STRING,
+  OBJECTIVECTYPE_DATA,
+  OBJECTIVECTYPE_ENUM,
+  OBJECTIVECTYPE_MESSAGE
+};
+
+template<class TDescriptor>
+string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) {
+  if (descriptor->options().deprecated()) {
+    string result = "DEPRECATED_ATTRIBUTE";
+    if (preSpace) {
+      result.insert(0, " ");
+    }
+    if (postNewline) {
+      result.append("\n");
+    }
+    return result;
+  } else {
+    return "";
+  }
+}
+
+string GetCapitalizedType(const FieldDescriptor* field);
+
+ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type);
+
+inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) {
+  return GetObjectiveCType(field->type());
+}
+
+bool IsPrimitiveType(const FieldDescriptor* field);
+bool IsReferenceType(const FieldDescriptor* field);
+
+string GPBGenericValueFieldName(const FieldDescriptor* field);
+string DefaultValue(const FieldDescriptor* field);
+bool HasNonZeroDefaultValue(const FieldDescriptor* field);
+
+string BuildFlagsString(const vector<string>& strings);
+
+// Builds a HeaderDoc style comment out of the comments in the .proto file.
+string BuildCommentsString(const SourceLocation& location);
+
+// Checks the prefix for a given file and outputs any warnings needed, if
+// there are flat out errors, then out_error is filled in and the result is
+// false.
+bool ValidateObjCClassPrefix(const FileDescriptor* file,
+                             const Options& generation_options,
+                             string* out_error);
+
+// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
+// the input into the expected output.
+class LIBPROTOC_EXPORT TextFormatDecodeData {
+ public:
+  TextFormatDecodeData() {}
+
+  void AddString(int32 key, const string& input_for_decode,
+                 const string& desired_output);
+  size_t num_entries() const { return entries_.size(); }
+  string Data() const;
+
+  static string DecodeDataForString(const string& input_for_decode,
+                                    const string& desired_output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormatDecodeData);
+
+  typedef std::pair<int32, string> DataEntry;
+  vector<DataEntry> entries_;
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
new file mode 100644
index 0000000..dc1cef5
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
@@ -0,0 +1,257 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+namespace {
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_RawStrings) {
+  string input_for_decode("abcdefghIJ");
+  string desired_output_for_decode;
+  string expected;
+  string result;
+
+  // Different data, can't transform.
+
+  desired_output_for_decode = "zbcdefghIJ";
+  expected = string("\0zbcdefghIJ\0", 12);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  desired_output_for_decode = "abcdezghIJ";
+  expected = string("\0abcdezghIJ\0", 12);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  // Shortened data, can't transform.
+
+  desired_output_for_decode = "abcdefghI";
+  expected = string("\0abcdefghI\0", 11);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  // Extra data, can't transform.
+
+  desired_output_for_decode = "abcdefghIJz";
+  expected = string("\0abcdefghIJz\0", 13);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+}
+
+TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_ByteCodes) {
+  string input_for_decode("abcdefghIJ");
+  string desired_output_for_decode;
+  string expected;
+  string result;
+
+  desired_output_for_decode = "abcdefghIJ";
+  expected = string("\x0A\x0", 2);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  desired_output_for_decode = "_AbcdefghIJ";
+  expected = string("\xCA\x0", 2);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  desired_output_for_decode = "ABCD__EfghI_j";
+  expected = string("\x64\x80\xC5\xA1\x0", 5);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+
+  // Long name so multiple decode ops are needed.
+
+  input_for_decode =
+      "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000";
+  desired_output_for_decode =
+      "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000";
+  expected = string("\x04\xA5\xA4\xA2\xBF\x1F\x0E\x84\x0", 9);
+  result = TextFormatDecodeData::DecodeDataForString(input_for_decode,
+                                                     desired_output_for_decode);
+  EXPECT_EQ(expected, result);
+}
+
+// Death tests do not work on Windows as of yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(ObjCHelperDeathTest, TextFormatDecodeData_DecodeDataForString_Failures) {
+  // Empty inputs.
+
+  EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", ""),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+  EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("a", ""),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+  EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", "a"),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+
+  // Null char in the string.
+
+  string str_with_null_char("ab\0c", 4);
+  EXPECT_EXIT(
+      TextFormatDecodeData::DecodeDataForString(str_with_null_char, "def"),
+      ::testing::KilledBySignal(SIGABRT),
+      "error: got a null char in a string for making TextFormat data, input:");
+  EXPECT_EXIT(
+      TextFormatDecodeData::DecodeDataForString("def", str_with_null_char),
+      ::testing::KilledBySignal(SIGABRT),
+      "error: got a null char in a string for making TextFormat data, input:");
+}
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST(ObjCHelper, TextFormatDecodeData_RawStrings) {
+  TextFormatDecodeData decode_data;
+
+  // Different data, can't transform.
+  decode_data.AddString(1, "abcdefghIJ", "zbcdefghIJ");
+  decode_data.AddString(3, "abcdefghIJ", "abcdezghIJ");
+  // Shortened data, can't transform.
+  decode_data.AddString(2, "abcdefghIJ", "abcdefghI");
+  // Extra data, can't transform.
+  decode_data.AddString(4, "abcdefghIJ", "abcdefghIJz");
+
+  EXPECT_EQ(4, decode_data.num_entries());
+
+  uint8 expected_data[] = {
+      0x4,
+      0x1, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
+      0x3, 0x0, 'a', 'b', 'c', 'd', 'e', 'z', 'g', 'h', 'I', 'J', 0x0,
+      0x2, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 0x0,
+      0x4, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 'z', 0x0,
+  };
+  string expected((const char*)expected_data, sizeof(expected_data));
+
+  EXPECT_EQ(expected, decode_data.Data());
+}
+
+TEST(ObjCHelper, TextFormatDecodeData_ByteCodes) {
+  TextFormatDecodeData decode_data;
+
+  decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ");
+  decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ");
+  decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ");
+  decode_data.AddString(4, "abcdefghIJ", "ABCD__EfghI_j");
+  decode_data.AddString(1000,
+                        "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000",
+                        "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000");
+
+  EXPECT_EQ(5, decode_data.num_entries());
+
+  uint8 expected_data[] = {
+      0x5,
+      // All as is (00 op)
+      0x1,  0x0A, 0x0,
+      // Underscore, upper + 9 (10 op)
+      0x3,  0xCA, 0x0,
+      //  Upper + 3 (10 op), underscore, upper + 5 (10 op)
+      0x2,  0x44, 0xC6, 0x0,
+      // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op),
+      // underscore, lower + 0 (01 op)
+      0x4,  0x64, 0x80, 0xC5, 0xA1, 0x0,
+      // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op),
+      //   underscore, lower + 3 (01 op), underscore, lower + 1 (01 op),
+      //   underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00
+      //   op),
+      //   underscore, as is + 3 (00 op)
+      0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0,
+  };
+  string expected((const char*)expected_data, sizeof(expected_data));
+
+  EXPECT_EQ(expected, decode_data.Data());
+}
+
+
+// Death tests do not work on Windows as of yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) {
+  TextFormatDecodeData decode_data;
+
+  // Empty inputs.
+
+  EXPECT_EXIT(decode_data.AddString(1, "", ""),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+  EXPECT_EXIT(decode_data.AddString(1, "a", ""),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+  EXPECT_EXIT(decode_data.AddString(1, "", "a"),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: got empty string for making TextFormat data, input:");
+
+  // Null char in the string.
+
+  string str_with_null_char("ab\0c", 4);
+  EXPECT_EXIT(
+      decode_data.AddString(1, str_with_null_char, "def"),
+      ::testing::KilledBySignal(SIGABRT),
+      "error: got a null char in a string for making TextFormat data, input:");
+  EXPECT_EXIT(
+      decode_data.AddString(1, "def", str_with_null_char),
+      ::testing::KilledBySignal(SIGABRT),
+      "error: got a null char in a string for making TextFormat data, input:");
+
+  // Duplicate keys
+
+  decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ");
+  decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ");
+  decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ");
+  EXPECT_EXIT(decode_data.AddString(2, "xyz", "x_yz"),
+              ::testing::KilledBySignal(SIGABRT),
+              "error: duplicate key \\(2\\) making TextFormat data, input:");
+}
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+// TODO(thomasvl): Should probably add some unittests for all the special cases
+// of name mangling (class name, field name, enum names).  Rather than doing
+// this with an ObjC test in the objectivec directory, we should be able to
+// use src/google/protobuf/compiler/importer* (like other tests) to support a
+// virtual file system to feed in protos, once we have the Descriptor tree, the
+// tests could use the helper methods for generating names and validate the
+// right things are happening.
+
+}  // namespace
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
new file mode 100644
index 0000000..ac5d8ae
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -0,0 +1,180 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+// MapFieldGenerator uses RepeatedFieldGenerator as the parent because it
+// provides a bunch of things (no has* methods, comments for contained type,
+// etc.).
+
+namespace {
+
+const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) {
+  ObjectiveCType type = GetObjectiveCType(descriptor);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+      return "Int32";
+    case OBJECTIVECTYPE_UINT32:
+      return "UInt32";
+    case OBJECTIVECTYPE_INT64:
+      return "Int64";
+    case OBJECTIVECTYPE_UINT64:
+      return "UInt64";
+    case OBJECTIVECTYPE_FLOAT:
+      return "Float";
+    case OBJECTIVECTYPE_DOUBLE:
+      return "Double";
+    case OBJECTIVECTYPE_BOOLEAN:
+      return "Bool";
+    case OBJECTIVECTYPE_STRING:
+      return (isKey ? "String" : "Object");
+    case OBJECTIVECTYPE_DATA:
+      return "Object";
+    case OBJECTIVECTYPE_ENUM:
+      return "Enum";
+    case OBJECTIVECTYPE_MESSAGE:
+      return "Object";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+}  // namespace
+
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
+  const FieldDescriptor* key_descriptor =
+      descriptor->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value_descriptor =
+      descriptor->message_type()->FindFieldByName("value");
+  value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options));
+
+  // Pull over some variables_ from the value.
+  variables_["field_type"] = value_field_generator_->variable("field_type");
+  variables_["default"] = value_field_generator_->variable("default");
+  variables_["default_name"] = value_field_generator_->variable("default_name");
+
+  // Build custom field flags.
+  std::vector<string> field_flags;
+  field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor));
+  // Pull over the current text format custom name values that was calculated.
+  if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") !=
+      string::npos) {
+    field_flags.push_back("GPBFieldTextFormatNameCustom");
+  }
+  // Pull over some info from the value's flags.
+  const string& value_field_flags =
+      value_field_generator_->variable("fieldflags");
+  if (value_field_flags.find("GPBFieldHasDefaultValue") != string::npos) {
+    field_flags.push_back("GPBFieldHasDefaultValue");
+  }
+  if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) {
+    field_flags.push_back("GPBFieldHasEnumDescriptor");
+  }
+  variables_["fieldflags"] = BuildFlagsString(field_flags);
+
+  ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
+  const bool value_is_object_type =
+      ((value_objc_type == OBJECTIVECTYPE_STRING) ||
+       (value_objc_type == OBJECTIVECTYPE_DATA) ||
+       (value_objc_type == OBJECTIVECTYPE_MESSAGE));
+  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+      value_is_object_type) {
+    variables_["array_storage_type"] = "NSMutableDictionary";
+    variables_["array_property_type"] =
+        "NSMutableDictionary<NSString*, " +
+        value_field_generator_->variable("storage_type") + "*>";
+  } else {
+    string class_name("GPB");
+    class_name += MapEntryTypeName(key_descriptor, true);
+    class_name += MapEntryTypeName(value_descriptor, false);
+    class_name += "Dictionary";
+    variables_["array_storage_type"] = class_name;
+    if (value_is_object_type) {
+      variables_["array_property_type"] =
+          class_name + "<" +
+          value_field_generator_->variable("storage_type") + "*>";
+    }
+  }
+
+  variables_["dataTypeSpecific_name"] =
+      value_field_generator_->variable("dataTypeSpecific_name");
+  variables_["dataTypeSpecific_value"] =
+      value_field_generator_->variable("dataTypeSpecific_value");
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  // Use the array_comment support in RepeatedFieldGenerator to output what the
+  // values in the map are.
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->FindFieldByName("value");
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
+    variables_["array_comment"] =
+        "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
+  }
+}
+
+void MapFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->FindFieldByName("value");
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
+    const string& value_storage_type =
+        value_field_generator_->variable("storage_type");
+    fwd_decls->insert("@class " + value_storage_type);
+  }
+}
+
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
new file mode 100644
index 0000000..bc68a68
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class MapFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ public:
+  virtual void FinishInitialization(void);
+
+ protected:
+  MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+  virtual ~MapFieldGenerator();
+
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ private:
+  scoped_ptr<FieldGenerator> value_field_generator_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
new file mode 100644
index 0000000..bf27259
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -0,0 +1,600 @@
+// 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.
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/objectivec/objectivec_message.h>
+#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
+#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/stubs/stl_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+struct FieldOrderingByNumber {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    return a->number() < b->number();
+  }
+};
+
+int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
+  // The first item in the object structure is our uint32[] for has bits.
+  // We then want to order things to make the instances as small as
+  // possible. So we follow the has bits with:
+  //   1. Anything always 4 bytes - float, *32, enums
+  //   2. Anything that is always a pointer (they will be 8 bytes on 64 bit
+  //      builds and 4 bytes on 32bit builds.
+  //   3. Anything always 8 bytes - double, *64
+  //
+  // NOTE: Bools aren't listed, they were stored in the has bits.
+  //
+  // Why? Using 64bit builds as an example, this means worse case, we have
+  // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
+  // are wasted before the 4 byte values. Then if we have an odd number of
+  // those 4 byte values, the 8 byte values will be pushed down by 32bits to
+  // keep them aligned. But the structure will end 8 byte aligned, so no
+  // waste on the end. If you did the reverse order, you could waste 4 bytes
+  // before the first 8 byte value (after the has array), then a single
+  // bool on the end would need 7 bytes of padding to make the overall
+  // structure 8 byte aligned; so 11 bytes, wasted total.
+
+  // Anything repeated is a GPB*Array/NSArray, so pointer.
+  if (descriptor->is_repeated()) {
+    return 3;
+  }
+
+  switch (descriptor->type()) {
+    // All always 8 bytes.
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_FIXED64:
+      return 4;
+
+    // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes
+    // depending on the build architecture.
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      return 3;
+
+    // All always 4 bytes (enums are int32s).
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_ENUM:
+      return 2;
+
+    // 0 bytes. Stored in the has bits.
+    case FieldDescriptor::TYPE_BOOL:
+      return 99;  // End of the list (doesn't really matter).
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return 0;
+}
+
+struct FieldOrderingByStorageSize {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    // Order by grouping.
+    const int order_group_a = OrderGroupForFieldDescriptor(a);
+    const int order_group_b = OrderGroupForFieldDescriptor(b);
+    if (order_group_a != order_group_b) {
+      return order_group_a < order_group_b;
+    }
+    // Within the group, order by field number (provides stable ordering).
+    return a->number() < b->number();
+  }
+};
+
+struct ExtensionRangeOrdering {
+  bool operator()(const Descriptor::ExtensionRange* a,
+                  const Descriptor::ExtensionRange* b) const {
+    return a->start < b->start;
+  }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+  const FieldDescriptor** fields =
+      new const FieldDescriptor* [descriptor->field_count()];
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields[i] = descriptor->field(i);
+  }
+  sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber());
+  return fields;
+}
+
+// Sort the fields of the given Descriptor by storage size into a new[]'d
+// array and return it.
+const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) {
+  const FieldDescriptor** fields =
+      new const FieldDescriptor* [descriptor->field_count()];
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields[i] = descriptor->field(i);
+  }
+  sort(fields, fields + descriptor->field_count(),
+       FieldOrderingByStorageSize());
+  return fields;
+}
+}  // namespace
+
+MessageGenerator::MessageGenerator(const string& root_classname,
+                                   const Descriptor* descriptor,
+                                   const Options& options)
+    : root_classname_(root_classname),
+      descriptor_(descriptor),
+      field_generators_(descriptor, options),
+      class_name_(ClassName(descriptor_)) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    extension_generators_.push_back(
+        new ExtensionGenerator(class_name_, descriptor_->extension(i)));
+  }
+
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
+    oneof_generators_.push_back(generator);
+  }
+
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
+    enum_generators_.push_back(generator);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    MessageGenerator* generator =
+        new MessageGenerator(root_classname_,
+                             descriptor_->nested_type(i),
+                             options);
+    nested_message_generators_.push_back(generator);
+  }
+}
+
+MessageGenerator::~MessageGenerator() {
+  STLDeleteContainerPointers(extension_generators_.begin(),
+                             extension_generators_.end());
+  STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
+  STLDeleteContainerPointers(nested_message_generators_.begin(),
+                             nested_message_generators_.end());
+  STLDeleteContainerPointers(oneof_generators_.begin(),
+                             oneof_generators_.end());
+}
+
+void MessageGenerator::GenerateStaticVariablesInitialization(
+    io::Printer* printer) {
+  for (vector<ExtensionGenerator*>::iterator iter =
+           extension_generators_.begin();
+       iter != extension_generators_.end(); ++iter) {
+    (*iter)->GenerateStaticVariablesInitialization(printer);
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->GenerateStaticVariablesInitialization(printer);
+  }
+}
+
+void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) {
+  if (!IsMapEntryMessage(descriptor_)) {
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+      field_generators_.get(fieldDescriptor)
+          .DetermineForwardDeclarations(fwd_decls);
+    }
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->DetermineForwardDeclarations(fwd_decls);
+  }
+}
+
+void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
+  for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+       iter != enum_generators_.end(); ++iter) {
+    (*iter)->GenerateHeader(printer);
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->GenerateEnumHeader(printer);
+  }
+}
+
+void MessageGenerator::GenerateExtensionRegistrationSource(
+    io::Printer* printer) {
+  for (vector<ExtensionGenerator*>::iterator iter =
+           extension_generators_.begin();
+       iter != extension_generators_.end(); ++iter) {
+    (*iter)->GenerateRegistrationSource(printer);
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->GenerateExtensionRegistrationSource(printer);
+  }
+}
+
+void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
+  // This a a map entry message, just recurse and do nothing directly.
+  if (IsMapEntryMessage(descriptor_)) {
+    for (vector<MessageGenerator*>::iterator iter =
+             nested_message_generators_.begin();
+         iter != nested_message_generators_.end(); ++iter) {
+      (*iter)->GenerateMessageHeader(printer);
+    }
+    return;
+  }
+
+  printer->Print(
+      "#pragma mark - $classname$\n"
+      "\n",
+      "classname", class_name_);
+
+  if (descriptor_->field_count()) {
+    scoped_array<const FieldDescriptor*> sorted_fields(
+        SortFieldsByNumber(descriptor_));
+
+    printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n",
+                   "classname", class_name_);
+    printer->Indent();
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(sorted_fields[i])
+          .GenerateFieldNumberConstant(printer);
+    }
+
+    printer->Outdent();
+    printer->Print("};\n\n");
+  }
+
+  for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+       iter != oneof_generators_.end(); ++iter) {
+    (*iter)->GenerateCaseEnum(printer);
+  }
+
+  string message_comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    message_comments = BuildCommentsString(location);
+  } else {
+    message_comments = "";
+  }
+
+  printer->Print(
+      "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n",
+      "classname", class_name_,
+      "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, false, true),
+      "comments", message_comments);
+
+  vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->containing_oneof() != NULL) {
+      const int oneof_index = field->containing_oneof()->index();
+      if (!seen_oneofs[oneof_index]) {
+        seen_oneofs[oneof_index] = 1;
+        oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
+            printer);
+      }
+    }
+    field_generators_.get(field).GeneratePropertyDeclaration(printer);
+  }
+
+  printer->Print("@end\n\n");
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateCFunctionDeclarations(printer);
+  }
+
+  if (!oneof_generators_.empty()) {
+    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+         iter != oneof_generators_.end(); ++iter) {
+      (*iter)->GenerateClearFunctionDeclaration(printer);
+    }
+    printer->Print("\n");
+  }
+
+  if (descriptor_->extension_count() > 0) {
+    printer->Print("@interface $classname$ (DynamicMethods)\n\n",
+                   "classname", class_name_);
+    for (vector<ExtensionGenerator*>::iterator iter =
+             extension_generators_.begin();
+         iter != extension_generators_.end(); ++iter) {
+      (*iter)->GenerateMembersHeader(printer);
+    }
+    printer->Print("@end\n\n");
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->GenerateMessageHeader(printer);
+  }
+}
+
+void MessageGenerator::GenerateSource(io::Printer* printer) {
+  if (!IsMapEntryMessage(descriptor_)) {
+    printer->Print(
+        "#pragma mark - $classname$\n"
+        "\n",
+        "classname", class_name_);
+
+    printer->Print("@implementation $classname$\n\n",
+                   "classname", class_name_);
+
+    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+         iter != oneof_generators_.end(); ++iter) {
+      (*iter)->GeneratePropertyImplementation(printer);
+    }
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(descriptor_->field(i))
+          .GeneratePropertyImplementation(printer);
+    }
+
+    scoped_array<const FieldDescriptor*> sorted_fields(
+        SortFieldsByNumber(descriptor_));
+    scoped_array<const FieldDescriptor*> size_order_fields(
+        SortFieldsByStorageSize(descriptor_));
+
+    vector<const Descriptor::ExtensionRange*> sorted_extensions;
+    for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+      sorted_extensions.push_back(descriptor_->extension_range(i));
+    }
+
+    sort(sorted_extensions.begin(), sorted_extensions.end(),
+         ExtensionRangeOrdering());
+
+    // Assign has bits:
+    // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
+    //    who needs has bits and assigning them.
+    // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
+    //    index that groups all the elements in the oneof.
+    size_t num_has_bits = field_generators_.CalculateHasBits();
+    size_t sizeof_has_storage = (num_has_bits + 31) / 32;
+    if (sizeof_has_storage == 0) {
+      // In the case where no field needs has bits, don't let the _has_storage_
+      // end up as zero length (zero length arrays are sort of a grey area
+      // since it has to be at the start of the struct). This also ensures a
+      // field with only oneofs keeps the required negative indices they need.
+      sizeof_has_storage = 1;
+    }
+    // Tell all the fields the oneof base.
+    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+         iter != oneof_generators_.end(); ++iter) {
+      (*iter)->SetOneofIndexBase(sizeof_has_storage);
+    }
+    field_generators_.SetOneofIndexBase(sizeof_has_storage);
+    // sizeof_has_storage needs enough bits for the single fields that aren't in
+    // any oneof, and then one int32 for each oneof (to store the field number).
+    sizeof_has_storage += descriptor_->oneof_decl_count();
+
+    printer->Print(
+        "\n"
+        "typedef struct $classname$__storage_ {\n"
+        "  uint32_t _has_storage_[$sizeof_has_storage$];\n",
+        "classname", class_name_,
+        "sizeof_has_storage", SimpleItoa(sizeof_has_storage));
+    printer->Indent();
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(size_order_fields[i])
+          .GenerateFieldStorageDeclaration(printer);
+    }
+    printer->Outdent();
+
+    printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);
+
+
+    printer->Print(
+        "// This method is threadsafe because it is initially called\n"
+        "// in +initialize for each subclass.\n"
+        "+ (GPBDescriptor *)descriptor {\n"
+        "  static GPBDescriptor *descriptor = nil;\n"
+        "  if (!descriptor) {\n");
+
+    TextFormatDecodeData text_format_decode_data;
+    bool has_fields = descriptor_->field_count() > 0;
+    bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
+    string field_description_type;
+    if (need_defaults) {
+      field_description_type = "GPBMessageFieldDescriptionWithDefault";
+    } else {
+      field_description_type = "GPBMessageFieldDescription";
+    }
+    if (has_fields) {
+      printer->Print(
+          "    static $field_description_type$ fields[] = {\n",
+          "field_description_type", field_description_type);
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      for (int i = 0; i < descriptor_->field_count(); ++i) {
+        const FieldGenerator& field_generator =
+            field_generators_.get(sorted_fields[i]);
+        field_generator.GenerateFieldDescription(printer, need_defaults);
+        if (field_generator.needs_textformat_name_support()) {
+          text_format_decode_data.AddString(sorted_fields[i]->number(),
+                                            field_generator.generated_objc_name(),
+                                            field_generator.raw_field_name());
+        }
+      }
+      printer->Outdent();
+      printer->Outdent();
+      printer->Outdent();
+      printer->Print(
+          "    };\n");
+    }
+
+    map<string, string> vars;
+    vars["classname"] = class_name_;
+    vars["rootclassname"] = root_classname_;
+    vars["fields"] = has_fields ? "fields" : "NULL";
+    if (has_fields) {
+      vars["fields_count"] =
+          "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
+    } else {
+      vars["fields_count"] = "0";
+    }
+
+    std::vector<string> init_flags;
+    if (need_defaults) {
+      init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
+    }
+    if (descriptor_->options().message_set_wire_format()) {
+      init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
+    }
+    vars["init_flags"] = BuildFlagsString(init_flags);
+
+    printer->Print(
+        vars,
+        "    GPBDescriptor *localDescriptor =\n"
+        "        [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
+        "                                     rootClass:[$rootclassname$ class]\n"
+        "                                          file:$rootclassname$_FileDescriptor()\n"
+        "                                        fields:$fields$\n"
+        "                                    fieldCount:$fields_count$\n"
+        "                                   storageSize:sizeof($classname$__storage_)\n"
+        "                                         flags:$init_flags$];\n");
+    if (oneof_generators_.size() != 0) {
+      printer->Print(
+          "    static const char *oneofs[] = {\n");
+      for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+           iter != oneof_generators_.end(); ++iter) {
+        printer->Print(
+            "      \"$name$\",\n",
+            "name", (*iter)->DescriptorName());
+      }
+      printer->Print(
+          "    };\n"
+          "    [localDescriptor setupOneofs:oneofs\n"
+          "                           count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
+          "                   firstHasIndex:$first_has_index$];\n",
+          "first_has_index", oneof_generators_[0]->HasIndexAsString());
+    }
+    if (text_format_decode_data.num_entries() != 0) {
+      const string text_format_data_str(text_format_decode_data.Data());
+      printer->Print(
+          "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
+          "    static const char *extraTextFormatInfo =");
+      static const int kBytesPerLine = 40;  // allow for escaping
+      for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
+        printer->Print(
+            "\n        \"$data$\"",
+            "data", EscapeTrigraphs(
+                CEscape(text_format_data_str.substr(i, kBytesPerLine))));
+      }
+      printer->Print(
+          ";\n"
+          "    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
+          "#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
+    }
+    if (sorted_extensions.size() != 0) {
+      printer->Print(
+          "    static const GPBExtensionRange ranges[] = {\n");
+      for (int i = 0; i < sorted_extensions.size(); i++) {
+        printer->Print("      { .start = $start$, .end = $end$ },\n",
+                       "start", SimpleItoa(sorted_extensions[i]->start),
+                       "end", SimpleItoa(sorted_extensions[i]->end));
+      }
+      printer->Print(
+          "    };\n"
+          "    [localDescriptor setupExtensionRanges:ranges\n"
+          "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
+    }
+    printer->Print(
+        "    NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
+        "    descriptor = localDescriptor;\n"
+        "  }\n"
+        "  return descriptor;\n"
+        "}\n\n"
+        "@end\n\n");
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateCFunctionImplementations(printer);
+    }
+
+    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
+         iter != oneof_generators_.end(); ++iter) {
+      (*iter)->GenerateClearFunctionImplementation(printer);
+    }
+  }
+
+  for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
+       iter != enum_generators_.end(); ++iter) {
+    (*iter)->GenerateSource(printer);
+  }
+
+  for (vector<MessageGenerator*>::iterator iter =
+           nested_message_generators_.begin();
+       iter != nested_message_generators_.end(); ++iter) {
+    (*iter)->GenerateSource(printer);
+  }
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h
new file mode 100644
index 0000000..8565e76
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/compiler/objectivec/objectivec_oneof.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+namespace io {
+class Printer;  // printer.h
+}  // namespace io
+
+namespace compiler {
+namespace objectivec {
+
+class ExtensionGenerator;
+class EnumGenerator;
+
+class MessageGenerator {
+ public:
+  MessageGenerator(const string& root_classname,
+                   const Descriptor* descriptor,
+                   const Options& options);
+  ~MessageGenerator();
+
+  void GenerateStaticVariablesInitialization(io::Printer* printer);
+  void GenerateEnumHeader(io::Printer* printer);
+  void GenerateMessageHeader(io::Printer* printer);
+  void GenerateSource(io::Printer* printer);
+  void GenerateExtensionRegistrationSource(io::Printer* printer);
+  void DetermineForwardDeclarations(set<string>* fwd_decls);
+
+ private:
+  void GenerateParseFromMethodsHeader(io::Printer* printer);
+
+  void GenerateSerializeOneFieldSource(io::Printer* printer,
+                                       const FieldDescriptor* field);
+  void GenerateSerializeOneExtensionRangeSource(
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+  void GenerateMessageDescriptionSource(io::Printer* printer);
+  void GenerateDescriptionOneFieldSource(io::Printer* printer,
+                                         const FieldDescriptor* field);
+
+  const string root_classname_;
+  const Descriptor* descriptor_;
+  FieldGeneratorMap field_generators_;
+  const string class_name_;
+  vector<ExtensionGenerator*> extension_generators_;
+  vector<EnumGenerator*> enum_generators_;
+  vector<MessageGenerator*> nested_message_generators_;
+  vector<OneofGenerator*> oneof_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
new file mode 100644
index 0000000..d6ccd6d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -0,0 +1,108 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         map<string, string>* variables) {
+  const string& message_type = ClassName(descriptor->message_type());
+  (*variables)["type"] = message_type;
+  (*variables)["containing_class"] = ClassName(descriptor->containing_type());
+  (*variables)["storage_type"] = message_type;
+  (*variables)["group_or_message"] =
+      (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message";
+
+  (*variables)["dataTypeSpecific_value"] = "GPBStringifySymbol(" + message_type + ")";
+}
+
+}  // namespace
+
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
+  SetMessageVariables(descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  // Class name is already in "storage_type".
+  fwd_decls->insert("@class " + variable("storage_type"));
+}
+
+bool MessageFieldGenerator::WantsHasProperty(void) const {
+  if (descriptor_->containing_oneof() != NULL) {
+    // If in a oneof, it uses the oneofcase instead of a has bit.
+    return false;
+  }
+  // In both proto2 & proto3, message fields have a has* property to tell
+  // when it is a non default value.
+  return true;
+}
+
+RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
+  SetMessageVariables(descriptor, &variables_);
+  variables_["array_storage_type"] = "NSMutableArray";
+  variables_["array_property_type"] =
+      "NSMutableArray<" + variables_["storage_type"] + "*>";
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  // Class name is already in "storage_type".
+  fwd_decls->insert("@class " + variable("storage_type"));
+}
+
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
new file mode 100644
index 0000000..d2dba15
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class MessageFieldGenerator : public ObjCObjFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ protected:
+  MessageFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options);
+  virtual ~MessageFieldGenerator();
+  virtual bool WantsHasProperty(void) const;
+
+ public:
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ protected:
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                const Options& options);
+  virtual ~RepeatedMessageFieldGenerator();
+
+ public:
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
new file mode 100644
index 0000000..44bafd7
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
@@ -0,0 +1,138 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_oneof.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor)
+    : descriptor_(descriptor) {
+  variables_["enum_name"] = OneofEnumName(descriptor_);
+  variables_["name"] = OneofName(descriptor_);
+  variables_["capitalized_name"] = OneofNameCapitalized(descriptor_);
+  variables_["raw_index"] = SimpleItoa(descriptor_->index());
+  const Descriptor* msg_descriptor = descriptor_->containing_type();
+  variables_["owning_message_class"] = ClassName(msg_descriptor);
+
+  string comments;
+  SourceLocation location;
+  if (descriptor_->GetSourceLocation(&location)) {
+    comments = BuildCommentsString(location);
+  } else {
+    comments = "";
+  }
+  variables_["comments"] = comments;
+}
+
+OneofGenerator::~OneofGenerator() {}
+
+void OneofGenerator::SetOneofIndexBase(int index_base) {
+  int index = descriptor_->index() + index_base;
+  // Flip the sign to mark it as a oneof.
+  variables_["index"] = SimpleItoa(-index);
+}
+
+void OneofGenerator::GenerateCaseEnum(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "typedef GPB_ENUM($enum_name$) {\n");
+  printer->Indent();
+  printer->Print(
+      variables_,
+      "$enum_name$_GPBUnsetOneOfCase = 0,\n");
+  string enum_name = variables_["enum_name"];
+  for (int j = 0; j < descriptor_->field_count(); j++) {
+    const FieldDescriptor* field = descriptor_->field(j);
+    string field_name = FieldNameCapitalized(field);
+    printer->Print(
+        "$enum_name$_$field_name$ = $field_number$,\n",
+        "enum_name", enum_name,
+        "field_name", field_name,
+        "field_number", SimpleItoa(field->number()));
+  }
+  printer->Outdent();
+  printer->Print(
+      "};\n"
+      "\n");
+}
+
+void OneofGenerator::GeneratePublicCasePropertyDeclaration(
+    io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "$comments$"
+      "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n"
+      "\n");
+}
+
+void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "/// Clears whatever value was set for the oneof '$name$'.\n"
+      "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n");
+}
+
+void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "@dynamic $name$OneOfCase;\n");
+}
+
+void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) {
+  printer->Print(
+      variables_,
+      "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n"
+      "  GPBDescriptor *descriptor = [message descriptor];\n"
+      "  GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n"
+      "  GPBMaybeClearOneof(message, oneof, $index$, 0);\n"
+      "}\n");
+}
+
+string OneofGenerator::DescriptorName(void) const {
+  return variables_.find("name")->second;
+}
+
+string OneofGenerator::HasIndexAsString(void) const {
+  return variables_.find("index")->second;
+}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
new file mode 100644
index 0000000..3d9df4d
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
+
+#include <string>
+#include <set>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class Printer;  // printer.h
+}
+}
+
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class OneofGenerator {
+ public:
+  explicit OneofGenerator(const OneofDescriptor* descriptor);
+  ~OneofGenerator();
+
+  void SetOneofIndexBase(int index_base);
+
+  void GenerateCaseEnum(io::Printer* printer);
+
+  void GeneratePublicCasePropertyDeclaration(io::Printer* printer);
+  void GenerateClearFunctionDeclaration(io::Printer* printer);
+
+  void GeneratePropertyImplementation(io::Printer* printer);
+  void GenerateClearFunctionImplementation(io::Printer* printer);
+
+  string DescriptorName(void) const;
+  string HasIndexAsString(void) const;
+
+ private:
+  const OneofDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
new file mode 100644
index 0000000..d49350f
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
@@ -0,0 +1,192 @@
+// 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.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* PrimitiveTypeName(const FieldDescriptor* descriptor) {
+  ObjectiveCType type = GetObjectiveCType(descriptor);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+      return "int32_t";
+    case OBJECTIVECTYPE_UINT32:
+      return "uint32_t";
+    case OBJECTIVECTYPE_INT64:
+      return "int64_t";
+    case OBJECTIVECTYPE_UINT64:
+      return "uint64_t";
+    case OBJECTIVECTYPE_FLOAT:
+      return "float";
+    case OBJECTIVECTYPE_DOUBLE:
+      return "double";
+    case OBJECTIVECTYPE_BOOLEAN:
+      return "BOOL";
+    case OBJECTIVECTYPE_STRING:
+      return "NSString";
+    case OBJECTIVECTYPE_DATA:
+      return "NSData";
+    case OBJECTIVECTYPE_ENUM:
+      return "int32_t";
+    case OBJECTIVECTYPE_MESSAGE:
+      return NULL;  // Messages go through objectivec_message_field.cc|h.
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) {
+  ObjectiveCType type = GetObjectiveCType(descriptor);
+  switch (type) {
+    case OBJECTIVECTYPE_INT32:
+      return "Int32";
+    case OBJECTIVECTYPE_UINT32:
+      return "UInt32";
+    case OBJECTIVECTYPE_INT64:
+      return "Int64";
+    case OBJECTIVECTYPE_UINT64:
+      return "UInt64";
+    case OBJECTIVECTYPE_FLOAT:
+      return "Float";
+    case OBJECTIVECTYPE_DOUBLE:
+      return "Double";
+    case OBJECTIVECTYPE_BOOLEAN:
+      return "Bool";
+    case OBJECTIVECTYPE_STRING:
+      return "";  // Want NSArray
+    case OBJECTIVECTYPE_DATA:
+      return "";  // Want NSArray
+    case OBJECTIVECTYPE_ENUM:
+      return "Enum";
+    case OBJECTIVECTYPE_MESSAGE:
+      // Want NSArray (but goes through objectivec_message_field.cc|h).
+      return "";
+  }
+
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           map<string, string>* variables) {
+  std::string primitive_name = PrimitiveTypeName(descriptor);
+  (*variables)["type"] = primitive_name;
+  (*variables)["storage_type"] = primitive_name;
+}
+
+}  // namespace
+
+PrimitiveFieldGenerator::PrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
+  SetPrimitiveVariables(descriptor, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration(
+    io::Printer* printer) const {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Nothing, BOOLs are stored in the has bits.
+  } else {
+    SingleFieldGenerator::GenerateFieldStorageDeclaration(printer);
+  }
+}
+
+int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Reserve a bit for the storage of the boolean.
+    return 1;
+  }
+  return 0;
+}
+
+void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) {
+  if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) {
+    // Set into the offset the has bit to use for the actual value.
+    variables_["storage_offset_value"] = SimpleItoa(has_base);
+    variables_["storage_offset_comment"] =
+        "  // Stored in _has_storage_ to save space.";
+  }
+}
+
+PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
+  SetPrimitiveVariables(descriptor, &variables_);
+  variables_["property_storage_attribute"] = "copy";
+}
+
+PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {}
+
+RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
+  SetPrimitiveVariables(descriptor, &variables_);
+
+  string base_name = PrimitiveArrayTypeName(descriptor);
+  if (base_name.length()) {
+    variables_["array_storage_type"] = "GPB" + base_name + "Array";
+  } else {
+    variables_["array_storage_type"] = "NSMutableArray";
+    variables_["array_property_type"] =
+        "NSMutableArray<" + variables_["storage_type"] + "*>";
+  }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
new file mode 100644
index 0000000..69bb1fd
--- /dev/null
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/objectivec/objectivec_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace objectivec {
+
+class PrimitiveFieldGenerator : public SingleFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ protected:
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
+  virtual ~PrimitiveFieldGenerator();
+
+  virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const;
+
+  virtual int ExtraRuntimeHasBitsNeeded(void) const;
+  virtual void SetExtraRuntimeHasBitsBase(int index_base);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ protected:
+  PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
+  virtual ~PrimitiveObjFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveObjFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator {
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
+
+ protected:
+  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                  const Options& options);
+  virtual ~RepeatedPrimitiveFieldGenerator();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+}  // namespace objectivec
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 474a8f8..90ded4d 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -44,6 +44,7 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
@@ -84,6 +85,32 @@
 
 const TypeNameMap kTypeNames = MakeTypeNameTable();
 
+// Camel-case the field name and append "Entry" for generated map entry name.
+// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
+string MapEntryName(const string& field_name) {
+  string result;
+  static const char kSuffix[] = "Entry";
+  result.reserve(field_name.size() + sizeof(kSuffix));
+  bool cap_next = true;
+  for (int i = 0; i < field_name.size(); ++i) {
+    if (field_name[i] == '_') {
+      cap_next = true;
+    } else if (cap_next) {
+      // Note: Do not use ctype.h due to locales.
+      if ('a' <= field_name[i] && field_name[i] <= 'z') {
+        result.push_back(field_name[i] - 'a' + 'A');
+      } else {
+        result.push_back(field_name[i]);
+      }
+      cap_next = false;
+    } else {
+      result.push_back(field_name[i]);
+    }
+  }
+  result.append(kSuffix);
+  return result;
+}
+
 }  // anonymous namespace
 
 // Makes code slightly more readable.  The meaning of "DO(foo)" is
@@ -251,27 +278,39 @@
   }
 }
 
-bool Parser::TryConsumeEndOfDeclaration(const char* text,
-                                        const LocationRecorder* location) {
+bool Parser::TryConsumeEndOfDeclaration(
+    const char* text, const LocationRecorder* location) {
   if (LookingAt(text)) {
     string leading, trailing;
-    input_->NextWithComments(&trailing, NULL, &leading);
+    vector<string> detached;
+    input_->NextWithComments(&trailing, &detached, &leading);
 
     // Save the leading comments for next time, and recall the leading comments
     // from last time.
     leading.swap(upcoming_doc_comments_);
 
     if (location != NULL) {
-      location->AttachComments(&leading, &trailing);
+      upcoming_detached_comments_.swap(detached);
+      location->AttachComments(&leading, &trailing, &detached);
+    } else if (strcmp(text, "}") == 0) {
+      // If the current location is null and we are finishing the current scope,
+      // drop pending upcoming detached comments.
+      upcoming_detached_comments_.swap(detached);
+    } else {
+      // Otherwise, append the new detached comments to the existing upcoming
+      // detached comments.
+      upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+                                         detached.begin(), detached.end());
     }
+
     return true;
   } else {
     return false;
   }
 }
 
-bool Parser::ConsumeEndOfDeclaration(const char* text,
-                                     const LocationRecorder* location) {
+bool Parser::ConsumeEndOfDeclaration(
+    const char* text, const LocationRecorder* location) {
   if (TryConsumeEndOfDeclaration(text, location)) {
     return true;
   } else {
@@ -364,7 +403,8 @@
 }
 
 void Parser::LocationRecorder::AttachComments(
-    string* leading, string* trailing) const {
+    string* leading, string* trailing,
+    vector<string>* detached_comments) const {
   GOOGLE_CHECK(!location_->has_leading_comments());
   GOOGLE_CHECK(!location_->has_trailing_comments());
 
@@ -374,6 +414,11 @@
   if (!trailing->empty()) {
     location_->mutable_trailing_comments()->swap(*trailing);
   }
+  for (int i = 0; i < detached_comments->size(); ++i) {
+    location_->add_leading_detached_comments()->swap(
+        (*detached_comments)[i]);
+  }
+  detached_comments->clear();
 }
 
 // -------------------------------------------------------------------
@@ -413,6 +458,61 @@
 
 // ===================================================================
 
+bool Parser::ValidateEnum(const EnumDescriptorProto* proto) {
+  bool has_allow_alias = false;
+  bool allow_alias = false;
+
+  for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) {
+    const UninterpretedOption option = proto->options().uninterpreted_option(i);
+    if (option.name_size() > 1) {
+      continue;
+    }
+    if (!option.name(0).is_extension() &&
+        option.name(0).name_part() == "allow_alias") {
+      has_allow_alias = true;
+      if (option.identifier_value() == "true") {
+        allow_alias = true;
+      }
+      break;
+    }
+  }
+
+  if (has_allow_alias && !allow_alias) {
+    string error =
+        "\"" + proto->name() +
+        "\" declares 'option allow_alias = false;' which has no effect. "
+        "Please remove the declaration.";
+    // This needlessly clutters declarations with nops.
+    AddError(error);
+    return false;
+  }
+
+  set<int> used_values;
+  bool has_duplicates = false;
+  for (int i = 0; i < proto->value_size(); ++i) {
+    const EnumValueDescriptorProto enum_value = proto->value(i);
+    if (used_values.find(enum_value.number()) != used_values.end()) {
+      has_duplicates = true;
+      break;
+    } else {
+      used_values.insert(enum_value.number());
+    }
+  }
+  if (allow_alias && !has_duplicates) {
+    string error =
+        "\"" + proto->name() +
+        "\" declares support for enum aliases but no enum values share field "
+        "numbers. Please remove the unnecessary 'option allow_alias = true;' "
+        "declaration.";
+    // Generate an error if an enum declares support for duplicate enum values
+    // and does not use it protect future authors.
+    AddError(error);
+    return false;
+  }
+
+  return true;
+}
+
 bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
   input_ = input;
   had_errors_ = false;
@@ -425,21 +525,29 @@
   SourceCodeInfo source_code_info;
   source_code_info_ = &source_code_info;
 
+  vector<string> top_doc_comments;
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
     // Advance to first token.
-    input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+    input_->NextWithComments(NULL, &upcoming_detached_comments_,
+                             &upcoming_doc_comments_);
   }
 
   {
     LocationRecorder root_location(this);
 
     if (require_syntax_identifier_ || LookingAt("syntax")) {
-      if (!ParseSyntaxIdentifier()) {
+      if (!ParseSyntaxIdentifier(root_location)) {
         // Don't attempt to parse the file if we didn't recognize the syntax
         // identifier.
         return false;
       }
+      // Store the syntax into the file.
+      if (file != NULL) file->set_syntax(syntax_identifier_);
     } else if (!stop_after_syntax_identifier_) {
+      GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: "
+                   << file->name() << ". Please use 'syntax = \"proto2\";' "
+                   << "or 'syntax = \"proto3\";' to specify a syntax "
+                   << "version. (Defaulted to proto2 syntax.)";
       syntax_identifier_ = "proto2";
     }
 
@@ -454,7 +562,8 @@
 
         if (LookingAt("}")) {
           AddError("Unmatched \"}\".");
-          input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+          input_->NextWithComments(NULL, &upcoming_detached_comments_,
+                                   &upcoming_doc_comments_);
         }
       }
     }
@@ -466,20 +575,25 @@
   return !had_errors_;
 }
 
-bool Parser::ParseSyntaxIdentifier() {
-  DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'."));
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+  LocationRecorder syntax_location(parent,
+                                   FileDescriptorProto::kSyntaxFieldNumber);
+  DO(Consume(
+      "syntax",
+      "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
   DO(Consume("="));
   io::Tokenizer::Token syntax_token = input_->current();
   string syntax;
   DO(ConsumeString(&syntax, "Expected syntax identifier."));
-  DO(ConsumeEndOfDeclaration(";", NULL));
+  DO(ConsumeEndOfDeclaration(";", &syntax_location));
 
   syntax_identifier_ = syntax;
 
-  if (syntax != "proto2" && !stop_after_syntax_identifier_) {
+  if (syntax != "proto2" && syntax != "proto3" &&
+      !stop_after_syntax_identifier_) {
     AddError(syntax_token.line, syntax_token.column,
       "Unrecognized syntax identifier \"" + syntax + "\".  This parser "
-      "only recognizes \"proto2\".");
+      "only recognizes \"proto2\" and \"proto3\".");
     return false;
   }
 
@@ -628,6 +742,8 @@
     LocationRecorder location(message_location,
                               DescriptorProto::kExtensionRangeFieldNumber);
     return ParseExtensions(message, location, containing_file);
+  } else if (LookingAt("reserved")) {
+    return ParseReserved(message, message_location);
   } else if (LookingAt("extend")) {
     LocationRecorder location(message_location,
                               DescriptorProto::kExtensionFieldNumber);
@@ -673,8 +789,16 @@
     LocationRecorder location(field_location,
                               FieldDescriptorProto::kLabelFieldNumber);
     FieldDescriptorProto::Label label;
-    DO(ParseLabel(&label, containing_file));
-    field->set_label(label);
+    if (ParseLabel(&label, containing_file)) {
+      field->set_label(label);
+      if (label == FieldDescriptorProto::LABEL_OPTIONAL &&
+          syntax_identifier_ == "proto3") {
+        AddError(
+            "Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+            "To define 'optional' fields in Proto3, simply remove the "
+            "'optional' label, as fields are 'optional' by default.");
+      }
+    }
   }
 
   return ParseMessageFieldNoLabel(field, messages, parent_location,
@@ -690,20 +814,75 @@
     int location_field_number_for_nested_type,
     const LocationRecorder& field_location,
     const FileDescriptorProto* containing_file) {
+  MapField map_field;
   // Parse type.
   {
     LocationRecorder location(field_location);  // add path later
     location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
 
+    bool type_parsed = false;
     FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
     string type_name;
-    DO(ParseType(&type, &type_name));
-    if (type_name.empty()) {
-      location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
-      field->set_type(type);
-    } else {
+
+    // Special case map field. We only treat the field as a map field if the
+    // field type name starts with the word "map" with a following "<".
+    if (TryConsume("map")) {
+      if (LookingAt("<")) {
+        map_field.is_map_field = true;
+      } else {
+        // False positive
+        type_parsed = true;
+        type_name = "map";
+      }
+    }
+    if (map_field.is_map_field) {
+      if (field->has_oneof_index()) {
+        AddError("Map fields are not allowed in oneofs.");
+        return false;
+      }
+      if (field->has_label()) {
+        AddError(
+            "Field labels (required/optional/repeated) are not allowed on "
+            "map fields.");
+        return false;
+      }
+      if (field->has_extendee()) {
+        AddError("Map fields are not allowed to be extensions.");
+        return false;
+      }
+      field->set_label(FieldDescriptorProto::LABEL_REPEATED);
+      DO(Consume("<"));
+      DO(ParseType(&map_field.key_type, &map_field.key_type_name));
+      DO(Consume(","));
+      DO(ParseType(&map_field.value_type, &map_field.value_type_name));
+      DO(Consume(">"));
+      // Defer setting of the type name of the map field until the
+      // field name is parsed. Add the source location though.
       location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
-      field->set_type_name(type_name);
+    } else {
+      // Handle the case where no explicit label is given for a non-map field.
+      if (!field->has_label() && DefaultToOptionalFields()) {
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+      if (!field->has_label()) {
+        AddError("Expected \"required\", \"optional\", or \"repeated\".");
+        // We can actually reasonably recover here by just assuming the user
+        // forgot the label altogether.
+        field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+      }
+
+      // Handle the case where the actual type is a message or enum named "map",
+      // which we already consumed in the code above.
+      if (!type_parsed) {
+        DO(ParseType(&type, &type_name));
+      }
+      if (type_name.empty()) {
+        location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
+        field->set_type(type);
+      } else {
+        location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+        field->set_type_name(type_name);
+      }
     }
   }
 
@@ -781,9 +960,78 @@
     DO(ConsumeEndOfDeclaration(";", &field_location));
   }
 
+  // Create a map entry type if this is a map field.
+  if (map_field.is_map_field) {
+    GenerateMapEntry(map_field, field, messages);
+  }
+
   return true;
 }
 
+void Parser::GenerateMapEntry(const MapField& map_field,
+                              FieldDescriptorProto* field,
+                              RepeatedPtrField<DescriptorProto>* messages) {
+  DescriptorProto* entry = messages->Add();
+  string entry_name = MapEntryName(field->name());
+  field->set_type_name(entry_name);
+  entry->set_name(entry_name);
+  entry->mutable_options()->set_map_entry(true);
+  FieldDescriptorProto* key_field = entry->add_field();
+  key_field->set_name("key");
+  key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  key_field->set_number(1);
+  if (map_field.key_type_name.empty()) {
+    key_field->set_type(map_field.key_type);
+  } else {
+    key_field->set_type_name(map_field.key_type_name);
+  }
+  FieldDescriptorProto* value_field = entry->add_field();
+  value_field->set_name("value");
+  value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
+  value_field->set_number(2);
+  if (map_field.value_type_name.empty()) {
+    value_field->set_type(map_field.value_type);
+  } else {
+    value_field->set_type_name(map_field.value_type_name);
+  }
+  // Propagate the "enforce_utf8" option to key and value fields if they
+  // are strings. This helps simplify the implementation of code generators
+  // and also reflection-based parsing code.
+  //
+  // The following definition:
+  //   message Foo {
+  //     map<string, string> value = 1 [enforce_utf8 = false];
+  //   }
+  // will be interpreted as:
+  //   message Foo {
+  //     message ValueEntry {
+  //       option map_entry = true;
+  //       string key = 1 [enforce_utf8 = false];
+  //       string value = 2 [enforce_utf8 = false];
+  //     }
+  //     repeated ValueEntry value = 1 [enforce_utf8 = false];
+  //  }
+  //
+  // TODO(xiaofeng): Remove this when the "enforce_utf8" option is removed
+  // from protocol compiler.
+  for (int i = 0; i < field->options().uninterpreted_option_size(); ++i) {
+    const UninterpretedOption& option =
+        field->options().uninterpreted_option(i);
+    if (option.name_size() == 1 &&
+        option.name(0).name_part() == "enforce_utf8" &&
+        !option.name(0).is_extension()) {
+      if (key_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        key_field->mutable_options()->add_uninterpreted_option()
+            ->CopyFrom(option);
+      }
+      if (value_field->type() == FieldDescriptorProto::TYPE_STRING) {
+        value_field->mutable_options()->add_uninterpreted_option()
+            ->CopyFrom(option);
+      }
+    }
+  }
+}
+
 bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
                                const LocationRecorder& field_location,
                                const FileDescriptorProto* containing_file) {
@@ -800,6 +1048,9 @@
       // We intentionally pass field_location rather than location here, since
       // the default value is not actually an option.
       DO(ParseDefaultAssignment(field, field_location, containing_file));
+    } else if (LookingAt("json_name")) {
+      // Like default value, this "json_name" is not an actual option.
+      DO(ParseJsonName(field, field_location, containing_file));
     } else {
       DO(ParseOption(field->mutable_options(), location,
                      containing_file, OPTION_ASSIGNMENT));
@@ -947,6 +1198,28 @@
   return true;
 }
 
+bool Parser::ParseJsonName(
+    FieldDescriptorProto* field,
+    const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  if (field->has_json_name()) {
+    AddError("Already set option \"json_name\".");
+    field->clear_json_name();
+  }
+
+  DO(Consume("json_name"));
+  DO(Consume("="));
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kJsonNameFieldNumber);
+  location.RecordLegacyLocation(
+      field, DescriptorPool::ErrorCollector::OPTION_VALUE);
+  DO(ConsumeString(field->mutable_json_name(),
+                   "Expected string for JSON name."));
+  return true;
+}
+
+
 bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
                                  const LocationRecorder& part_location,
                                  const FileDescriptorProto* containing_file) {
@@ -1147,7 +1420,6 @@
     DO(ConsumeEndOfDeclaration(";", &location));
   }
 
-
   return true;
 }
 
@@ -1207,6 +1479,77 @@
   return true;
 }
 
+// This is similar to extension range parsing, except that "max" is not
+// supported, and accepts field name literals.
+bool Parser::ParseReserved(DescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedNameFieldNumber);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedRangeFieldNumber);
+    return ParseReservedNumbers(message, location);
+  }
+}
+
+
+bool Parser::ParseReservedNames(DescriptorProto* message,
+                                const LocationRecorder& parent_location) {
+  do {
+    LocationRecorder location(parent_location, message->reserved_name_size());
+    DO(ConsumeString(message->add_reserved_name(), "Expected field name."));
+  } while (TryConsume(","));
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReservedNumbers(DescriptorProto* message,
+                                  const LocationRecorder& parent_location) {
+  bool first = true;
+  do {
+    LocationRecorder location(parent_location, message->reserved_range_size());
+
+    DescriptorProto::ReservedRange* range = message->add_reserved_range();
+    int start, end;
+    io::Tokenizer::Token start_token;
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ReservedRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, (first ?
+                                 "Expected field name or number range." :
+                                 "Expected field number range.")));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      DO(ConsumeInteger(&end, "Expected integer."));
+    } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    // Users like to specify inclusive ranges, but in code we like the end
+    // number to be exclusive.
+    ++end;
+
+    range->set_start(start);
+    range->set_end(end);
+    first = false;
+  } while (TryConsume(","));
+
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
 bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
                          RepeatedPtrField<DescriptorProto>* messages,
                          const LocationRecorder& parent_location,
@@ -1339,6 +1682,9 @@
   }
 
   DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+  DO(ValidateEnum(enum_type));
+
   return true;
 }
 
@@ -1512,6 +1858,15 @@
   // Parse input type.
   DO(Consume("("));
   {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+      location.RecordLegacyLocation(
+          method, DescriptorPool::ErrorCollector::OTHER);
+      method->set_client_streaming(true);
+      DO(Consume("stream"));
+
+    }
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kInputTypeFieldNumber);
     location.RecordLegacyLocation(
@@ -1524,6 +1879,15 @@
   DO(Consume("returns"));
   DO(Consume("("));
   {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+      location.RecordLegacyLocation(
+          method, DescriptorPool::ErrorCollector::OTHER);
+      DO(Consume("stream"));
+      method->set_server_streaming(true);
+
+    }
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kOutputTypeFieldNumber);
     location.RecordLegacyLocation(
@@ -1534,10 +1898,9 @@
 
   if (LookingAt("{")) {
     // Options!
-    DO(ParseOptions(method_location,
-                    containing_file,
-                    MethodDescriptorProto::kOptionsFieldNumber,
-                    method->mutable_options()));
+    DO(ParseMethodOptions(method_location, containing_file,
+                          MethodDescriptorProto::kOptionsFieldNumber,
+                          method->mutable_options()));
   } else {
     DO(ConsumeEndOfDeclaration(";", &method_location));
   }
@@ -1546,10 +1909,10 @@
 }
 
 
-bool Parser::ParseOptions(const LocationRecorder& parent_location,
-                          const FileDescriptorProto* containing_file,
-                          const int optionsFieldNumber,
-                          Message* mutable_options) {
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+                                const FileDescriptorProto* containing_file,
+                                const int optionsFieldNumber,
+                                Message* mutable_options) {
   // Options!
   ConsumeEndOfDeclaration("{", &parent_location);
   while (!TryConsumeEndOfDeclaration("}", NULL)) {
@@ -1563,8 +1926,8 @@
     } else {
       LocationRecorder location(parent_location,
                                 optionsFieldNumber);
-      if (!ParseOption(mutable_options, location, containing_file,
-                       OPTION_STATEMENT)) {
+      if (!ParseOption(mutable_options, location,
+                       containing_file, OPTION_STATEMENT)) {
         // This statement failed to parse.  Skip it, but keep looping to
         // parse other statements.
         SkipStatement();
@@ -1588,13 +1951,8 @@
   } else if (TryConsume("required")) {
     *label = FieldDescriptorProto::LABEL_REQUIRED;
     return true;
-  } else {
-    AddError("Expected \"required\", \"optional\", or \"repeated\".");
-    // We can actually reasonably recover here by just assuming the user
-    // forgot the label altogether.
-    *label = FieldDescriptorProto::LABEL_OPTIONAL;
-    return true;
   }
+  return false;
 }
 
 bool Parser::ParseType(FieldDescriptorProto::Type* type,
@@ -1722,7 +2080,7 @@
     DescriptorPool::ErrorCollector::ErrorLocation location,
     int* line, int* column) const {
   const pair<int, int>* result =
-    FindOrNull(location_map_, make_pair(descriptor, location));
+      FindOrNull(location_map_, std::make_pair(descriptor, location));
   if (result == NULL) {
     *line   = -1;
     *column = 0;
@@ -1738,7 +2096,8 @@
     const Message* descriptor,
     DescriptorPool::ErrorCollector::ErrorLocation location,
     int line, int column) {
-  location_map_[make_pair(descriptor, location)] = make_pair(line, column);
+  location_map_[std::make_pair(descriptor, location)] =
+      std::make_pair(line, column);
 }
 
 void SourceLocationTable::Clear() {
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index d0a2359..2c561c2 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -185,10 +185,13 @@
   //   have been passed around by const reference, for no particularly good
   //   reason.  We should probably go through and change them all to mutable
   //   pointer to make this more intuitive.
-  bool TryConsumeEndOfDeclaration(const char* text,
-                                  const LocationRecorder* location);
-  bool ConsumeEndOfDeclaration(const char* text,
-                               const LocationRecorder* location);
+  bool TryConsumeEndOfDeclaration(
+      const char* text, const LocationRecorder* location);
+  bool TryConsumeEndOfDeclarationFinishScope(
+      const char* text, const LocationRecorder* location);
+
+  bool ConsumeEndOfDeclaration(
+      const char* text, const LocationRecorder* location);
 
   // -----------------------------------------------------------------
   // Error logging helpers
@@ -253,9 +256,13 @@
     //
     // TODO(kenton):  See comment on TryConsumeEndOfDeclaration(), above, for
     //   why this is const.
-    void AttachComments(string* leading, string* trailing) const;
+    void AttachComments(string* leading, string* trailing,
+                        vector<string>* detached_comments) const;
 
    private:
+    // Indexes of parent and current location in the parent
+    // SourceCodeInfo.location repeated field. For top-level elements,
+    // parent_index_ is -1.
     Parser* parser_;
     SourceCodeInfo::Location* location_;
 
@@ -268,7 +275,7 @@
   // Parses the "syntax = \"proto2\";" line at the top of the file.  Returns
   // false if it failed to parse or if the syntax identifier was not
   // recognized.
-  bool ParseSyntaxIdentifier();
+  bool ParseSyntaxIdentifier(const LocationRecorder& parent);
 
   // These methods parse various individual bits of code.  They return
   // false if they completely fail to parse the construct.  In this case,
@@ -302,9 +309,6 @@
                    RepeatedField<int32>* weak_dependency,
                    const LocationRecorder& root_location,
                    const FileDescriptorProto* containing_file);
-  bool ParseOption(Message* options,
-                   const LocationRecorder& options_location,
-                   const FileDescriptorProto* containing_file);
 
   // These methods parse the contents of a message, enum, or service type and
   // add them to the given object.  They consume the entire block including
@@ -319,7 +323,7 @@
                          const LocationRecorder& service_location,
                          const FileDescriptorProto* containing_file);
 
-  // Parse one statement within a message, enum, or service block, inclunding
+  // Parse one statement within a message, enum, or service block, including
   // final semicolon.
   bool ParseMessageStatement(DescriptorProto* message,
                              const LocationRecorder& message_location,
@@ -360,6 +364,14 @@
                        const LocationRecorder& extensions_location,
                        const FileDescriptorProto* containing_file);
 
+  // Parse a "reserved" declaration.
+  bool ParseReserved(DescriptorProto* message,
+                     const LocationRecorder& message_location);
+  bool ParseReservedNames(DescriptorProto* message,
+                          const LocationRecorder& parent_location);
+  bool ParseReservedNumbers(DescriptorProto* message,
+                            const LocationRecorder& parent_location);
+
   // Parse an "extend" declaration.  (See also comments for
   // ParseMessageField().)
   bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
@@ -397,13 +409,13 @@
 
 
   // Parse options of a single method or stream.
-  bool ParseOptions(const LocationRecorder& parent_location,
-                    const FileDescriptorProto* containing_file,
-                    const int optionsFieldNumber,
-                    Message* mutable_options);
+  bool ParseMethodOptions(const LocationRecorder& parent_location,
+                          const FileDescriptorProto* containing_file,
+                          const int optionsFieldNumber,
+                          Message* mutable_options);
 
   // Parse "required", "optional", or "repeated" and fill in "label"
-  // with the value.
+  // with the value. Returns true if such a label is consumed.
   bool ParseLabel(FieldDescriptorProto::Label* label,
                   const FileDescriptorProto* containing_file);
 
@@ -427,6 +439,10 @@
                               const LocationRecorder& field_location,
                               const FileDescriptorProto* containing_file);
 
+  bool ParseJsonName(FieldDescriptorProto* field,
+                     const LocationRecorder& field_location,
+                     const FileDescriptorProto* containing_file);
+
   enum OptionStyle {
     OPTION_ASSIGNMENT,  // just "name = value"
     OPTION_STATEMENT    // "option name = value;"
@@ -460,6 +476,30 @@
   // the ending brace.
   bool ParseUninterpretedBlock(string* value);
 
+  struct MapField {
+    // Whether the field is a map field.
+    bool is_map_field;
+    // The types of the key and value if they are primitive types.
+    FieldDescriptorProto::Type key_type;
+    FieldDescriptorProto::Type value_type;
+    // Or the type names string if the types are customized types.
+    string key_type_name;
+    string value_type_name;
+
+    MapField() : is_map_field(false) {}
+  };
+  // Desugar the map syntax to generate a nested map entry message.
+  void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field,
+                        RepeatedPtrField<DescriptorProto>* messages);
+
+  // Whether fields without label default to optional fields.
+  bool DefaultToOptionalFields() const {
+    return syntax_identifier_ == "proto3";
+  }
+
+
+  bool ValidateEnum(const EnumDescriptorProto* proto);
+
   // =================================================================
 
   io::Tokenizer* input_;
@@ -475,6 +515,13 @@
   // yet; use ConsumeEndOfDeclaration() to get the complete comments.
   string upcoming_doc_comments_;
 
+  // Detached comments are not connected to any syntax entities. Elements in
+  // this vector are paragraphs of comments separated by empty lines. The
+  // detached comments will be put into the leading_detached_comments field for
+  // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+  // ConsumeEndOfDeclaration() is called.
+  vector<string> upcoming_detached_comments_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
 };
 
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 9ec29a4..1d623dd 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -33,6 +33,9 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 #include <algorithm>
 #include <map>
@@ -175,9 +178,9 @@
   MockErrorCollector error_collector_;
   DescriptorPool pool_;
 
-  scoped_ptr<io::ZeroCopyInputStream> raw_input_;
-  scoped_ptr<io::Tokenizer> input_;
-  scoped_ptr<Parser> parser_;
+  google::protobuf::scoped_ptr<io::ZeroCopyInputStream> raw_input_;
+  google::protobuf::scoped_ptr<io::Tokenizer> input_;
+  google::protobuf::scoped_ptr<Parser> parser_;
   bool require_syntax_identifier_;
 };
 
@@ -213,10 +216,45 @@
   EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
 }
 
+TEST_F(ParserTest, WarnIfSyntaxIdentifierOmmitted) {
+  SetupParser("message A {}");
+  FileDescriptorProto file;
+  CaptureTestStderr();
+  EXPECT_TRUE(parser_->Parse(input_.get(), &file));
+  EXPECT_TRUE(
+      GetCapturedTestStderr().find("No syntax specified") != string::npos);
+}
+
 // ===================================================================
 
 typedef ParserTest ParseMessageTest;
 
+TEST_F(ParseMessageTest, IgnoreBOM) {
+  char input[] = "   message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n";
+  // Set UTF-8 BOM.
+  input[0] = (char)0xEF;
+  input[1] = (char)0xBB;
+  input[2] = (char)0xBF;
+  ExpectParsesTo(input,
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+    "}");
+}
+
+TEST_F(ParseMessageTest, BOMError) {
+  char input[] = "   message TestMessage {\n"
+      "  required int32 foo = 1;\n"
+      "}\n";
+  input[0] = (char)0xEF;
+  ExpectHasErrors(input,
+                  "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
+                  "Only UTF-8 is accepted for proto file.\n"
+                  "0:0: Expected top-level statement (e.g. \"message\").\n");
+}
+
 TEST_F(ParseMessageTest, SimpleMessage) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -250,6 +288,7 @@
     "  required int32 foo = 1;\n"
     "}\n",
 
+    "syntax: 'proto2' "
     "message_type {"
     "  name: \"TestMessage\""
     "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
@@ -265,6 +304,7 @@
     "  required int32 foo = 1;\n"
     "}\n",
 
+    "syntax: 'proto2' "
     "message_type {"
     "  name: \"TestMessage\""
     "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
@@ -365,39 +405,67 @@
 #define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
     "message_type {"
     "  name: \"TestMessage\""
-    "  field { type:TYPE_INT32   default_value:\"1\"         "ETC" }"
-    "  field { type:TYPE_INT32   default_value:\"-2\"        "ETC" }"
-    "  field { type:TYPE_INT64   default_value:\"3\"         "ETC" }"
-    "  field { type:TYPE_INT64   default_value:\"-4\"        "ETC" }"
-    "  field { type:TYPE_UINT32  default_value:\"5\"         "ETC" }"
-    "  field { type:TYPE_UINT64  default_value:\"6\"         "ETC" }"
-    "  field { type:TYPE_FLOAT   default_value:\"7.5\"       "ETC" }"
-    "  field { type:TYPE_FLOAT   default_value:\"-8.5\"      "ETC" }"
-    "  field { type:TYPE_FLOAT   default_value:\"9\"         "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"10.5\"      "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"-11.5\"     "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"12\"        "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"inf\"       "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"-inf\"      "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"nan\"       "ETC" }"
-    "  field { type:TYPE_STRING  default_value:\"13\\001\"   "ETC" }"
-    "  field { type:TYPE_STRING  default_value:\"abc\"       "ETC" }"
-    "  field { type:TYPE_BYTES   default_value:\"14\\\\002\" "ETC" }"
-    "  field { type:TYPE_BYTES   default_value:\"abc\"       "ETC" }"
-    "  field { type:TYPE_BOOL    default_value:\"true\"      "ETC" }"
-    "  field { type_name:\"Foo\" default_value:\"FOO\"       "ETC" }"
+    "  field { type:TYPE_INT32   default_value:\"1\"         " ETC " }"
+    "  field { type:TYPE_INT32   default_value:\"-2\"        " ETC " }"
+    "  field { type:TYPE_INT64   default_value:\"3\"         " ETC " }"
+    "  field { type:TYPE_INT64   default_value:\"-4\"        " ETC " }"
+    "  field { type:TYPE_UINT32  default_value:\"5\"         " ETC " }"
+    "  field { type:TYPE_UINT64  default_value:\"6\"         " ETC " }"
+    "  field { type:TYPE_FLOAT   default_value:\"7.5\"       " ETC " }"
+    "  field { type:TYPE_FLOAT   default_value:\"-8.5\"      " ETC " }"
+    "  field { type:TYPE_FLOAT   default_value:\"9\"         " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"10.5\"      " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"-11.5\"     " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"12\"        " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"inf\"       " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"-inf\"      " ETC " }"
+    "  field { type:TYPE_DOUBLE  default_value:\"nan\"       " ETC " }"
+    "  field { type:TYPE_STRING  default_value:\"13\\001\"   " ETC " }"
+    "  field { type:TYPE_STRING  default_value:\"abc\"       " ETC " }"
+    "  field { type:TYPE_BYTES   default_value:\"14\\\\002\" " ETC " }"
+    "  field { type:TYPE_BYTES   default_value:\"abc\"       " ETC " }"
+    "  field { type:TYPE_BOOL    default_value:\"true\"      " ETC " }"
+    "  field { type_name:\"Foo\" default_value:\"FOO\"       " ETC " }"
 
-    "  field { type:TYPE_INT32   default_value:\"2147483647\"           "ETC" }"
-    "  field { type:TYPE_INT32   default_value:\"-2147483648\"          "ETC" }"
-    "  field { type:TYPE_UINT32  default_value:\"4294967295\"           "ETC" }"
-    "  field { type:TYPE_INT64   default_value:\"9223372036854775807\"  "ETC" }"
-    "  field { type:TYPE_INT64   default_value:\"-9223372036854775808\" "ETC" }"
-    "  field { type:TYPE_UINT64  default_value:\"18446744073709551615\" "ETC" }"
-    "  field { type:TYPE_DOUBLE  default_value:\"43981\"                "ETC" }"
+    "  field {"
+    "    type:TYPE_INT32   default_value:\"2147483647\"           " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_INT32   default_value:\"-2147483648\"          " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_UINT32  default_value:\"4294967295\"           " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_INT64   default_value:\"9223372036854775807\"  " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_INT64   default_value:\"-9223372036854775808\" " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_UINT64  default_value:\"18446744073709551615\" " ETC
+    "  }"
+    "  field {"
+    "    type:TYPE_DOUBLE  default_value:\"43981\"                " ETC
+    "  }"
     "}");
 #undef ETC
 }
 
+TEST_F(ParseMessageTest, FieldJsonName) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  optional string foo = 1 [json_name = \"@type\"];\n"
+    "}\n",
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field {\n"
+    "    name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
+    "    json_name: \"@type\"\n"
+    "  }\n"
+    "}\n");
+}
+
 TEST_F(ParseMessageTest, FieldOptions) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -500,6 +568,54 @@
     "}");
 }
 
+TEST_F(ParseMessageTest, Maps) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  map<int32, string> primitive_type_map = 1;\n"
+    "  map<KeyType, ValueType> composite_type_map = 2;\n"
+    "}\n",
+
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  nested_type {"
+    "    name: \"PrimitiveTypeMapEntry\""
+    "    field { "
+    "       name: \"key\" number: 1 label:LABEL_OPTIONAL"
+    "       type:TYPE_INT32"
+    "    }"
+    "    field { "
+    "       name: \"value\" number: 2 label:LABEL_OPTIONAL"
+    "       type:TYPE_STRING"
+    "    }"
+    "    options { map_entry: true }"
+    "  }"
+    "  nested_type {"
+    "    name: \"CompositeTypeMapEntry\""
+    "    field { "
+    "       name: \"key\" number: 1 label:LABEL_OPTIONAL"
+    "       type_name: \"KeyType\""
+    "    }"
+    "    field { "
+    "       name: \"value\" number: 2 label:LABEL_OPTIONAL"
+    "       type_name: \"ValueType\""
+    "    }"
+    "    options { map_entry: true }"
+    "  }"
+    "  field {"
+    "    name: \"primitive_type_map\""
+    "    label: LABEL_REPEATED"
+    "    type_name: \"PrimitiveTypeMapEntry\""
+    "    number: 1"
+    "  }"
+    "  field {"
+    "    name: \"composite_type_map\""
+    "    label: LABEL_REPEATED"
+    "    type_name: \"CompositeTypeMapEntry\""
+    "    number: 2"
+    "  }"
+    "}");
+}
+
 TEST_F(ParseMessageTest, Group) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -544,6 +660,36 @@
     "}");
 }
 
+TEST_F(ParseMessageTest, ReservedRange) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  required int32 foo = 1;\n"
+    "  reserved 2, 15, 9 to 11, 3;\n"
+    "}\n",
+
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+    "  reserved_range { start:2   end:3         }"
+    "  reserved_range { start:15  end:16        }"
+    "  reserved_range { start:9   end:12        }"
+    "  reserved_range { start:3   end:4         }"
+    "}");
+}
+
+TEST_F(ParseMessageTest, ReservedNames) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  reserved \"foo\", \"bar\";\n"
+    "}\n",
+
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "}");
+}
+
 TEST_F(ParseMessageTest, ExtensionRange) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -639,6 +785,18 @@
     "            type_name:\"TestMessage\" extendee: \"Extendee1\" }");
 }
 
+TEST_F(ParseMessageTest, OptionalLabelProto3) {
+  ExpectParsesTo(
+    "syntax = \"proto3\";\n"
+    "message TestMessage {\n"
+    "  int32 foo = 1;\n"
+    "}\n",
+
+    "syntax: \"proto3\" "
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }");
+}
 
 // ===================================================================
 
@@ -828,9 +986,9 @@
 
 TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
   require_syntax_identifier_ = true;
-  ExpectHasEarlyExitErrors(
-    "message TestMessage {}",
-    "0:0: File must begin with 'syntax = \"proto2\";'.\n");
+  ExpectHasEarlyExitErrors("message TestMessage {}",
+                           "0:0: File must begin with a syntax statement, e.g. "
+                           "'syntax = \"proto2\";'.\n");
   EXPECT_EQ("", parser_->GetSyntaxIdentifier());
 }
 
@@ -838,7 +996,7 @@
   ExpectHasEarlyExitErrors(
     "syntax = \"no_such_syntax\";",
     "0:9: Unrecognized syntax identifier \"no_such_syntax\".  This parser "
-      "only recognizes \"proto2\".\n");
+      "only recognizes \"proto2\" and \"proto3\".\n");
   EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
 }
 
@@ -982,6 +1140,22 @@
     "6:36: Integer out of range.\n");
 }
 
+TEST_F(ParseErrorTest, JsonNameNotString) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  optional string foo = 1 [json_name=1];\n"
+    "}\n",
+    "1:37: Expected string for JSON name.\n");
+}
+
+TEST_F(ParseErrorTest, DuplicateJsonName) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
+    "}\n",
+    "1:41: Already set option \"json_name\".\n");
+}
+
 TEST_F(ParseErrorTest, EnumValueOutOfRange) {
   ExpectHasErrors(
     "enum TestEnum {\n"
@@ -996,6 +1170,29 @@
     "4:19: Integer out of range.\n");
 }
 
+TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
+  ExpectHasErrors(
+    "enum Foo {\n"
+    "  option allow_alias = false;\n"
+    "  BAR = 1;\n"
+    "  BAZ = 2;\n"
+    "}\n",
+    "5:0: \"Foo\" declares 'option allow_alias = false;' which has no effect. "
+    "Please remove the declaration.\n");
+}
+
+TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
+  ExpectHasErrors(
+    "enum Foo {\n"
+    "  option allow_alias = true;\n"
+    "  BAR = 1;\n"
+    "  BAZ = 2;\n"
+    "}\n",
+    "5:0: \"Foo\" declares support for enum aliases but no enum values share "
+    "field numbers. Please remove the unnecessary 'option allow_alias = true;' "
+    "declaration.\n");
+}
+
 TEST_F(ParseErrorTest, DefaultValueMissing) {
   ExpectHasErrors(
     "message TestMessage {\n"
@@ -1041,6 +1238,55 @@
       "/ repeated).\n");
 }
 
+TEST_F(ParseErrorTest, MapInOneof) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  oneof foo {\n"
+    "    map<int32, int32> foo_map = 1;\n"
+    "    map message_field = 2;\n"  // a normal message field is OK
+    "  }\n"
+    "}\n",
+    "2:7: Map fields are not allowed in oneofs.\n");
+}
+
+TEST_F(ParseErrorTest, LabelForMap) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  optional map<int32, int32> int_map = 1;\n"
+    "  required map<int32, int32> int_map2 = 2;\n"
+    "  repeated map<int32, int32> int_map3 = 3;\n"
+    "  optional map map_message = 4;\n"  // a normal message field is OK
+    "}\n",
+    "1:14: Field labels (required/optional/repeated) are not allowed on map "
+    "fields.\n"
+    "2:14: Field labels (required/optional/repeated) are not allowed on map "
+    "fields.\n"
+    "3:14: Field labels (required/optional/repeated) are not allowed on map "
+    "fields.\n");
+}
+
+TEST_F(ParseErrorTest, MalformedMaps) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  map map_message = 1;\n"   // a normal message field lacking label
+    "  map<string> str_map = 2;\n"
+    "  map<string,> str_map2 = 3;\n"
+    "  map<,string> str_map3 = 4;\n"
+    "  map<> empty_map = 5;\n"
+    "  map<string,string str_map6 = 6;\n"
+    "}"
+    "extend SomeMessage {\n"
+    "  map<int32, int32> int_map = 1;\n"
+    "}",
+    "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
+    "2:12: Expected \",\".\n"
+    "3:13: Expected type name.\n"
+    "4:6: Expected type name.\n"
+    "5:6: Expected type name.\n"
+    "6:20: Expected \">\".\n"
+    "8:5: Map fields are not allowed to be extensions.\n");
+}
+
 TEST_F(ParseErrorTest, GroupNotCapitalized) {
   ExpectHasErrors(
     "message TestMessage {\n"
@@ -1091,6 +1337,18 @@
       "1:0: Unexpected end of stream while parsing aggregate value.\n");
 }
 
+TEST_F(ParseErrorTest, ExplicitOptionalLabelProto3) {
+  ExpectHasErrors(
+      "syntax = 'proto3';\n"
+      "message TestMessage {\n"
+      "  optional int32 foo = 1;\n"
+      "}\n",
+      "2:11: Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+      "To define 'optional' fields in Proto3, simply remove the 'optional' "
+      "label, as fields are 'optional' by default.\n");
+}
+
+
 // -------------------------------------------------------------------
 // Enum errors
 
@@ -1109,6 +1367,33 @@
 }
 
 // -------------------------------------------------------------------
+// Reserved field number errors
+
+TEST_F(ParseErrorTest, ReservedMaxNotAllowed) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved 10 to max;\n"
+    "}\n",
+    "1:17: Expected integer.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved 10, \"foo\";\n"
+    "}\n",
+    "1:15: Expected field number range.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMissingQuotes) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved foo;\n"
+    "}\n",
+    "1:11: Expected field name or number range.\n");
+}
+
+// -------------------------------------------------------------------
 // Service errors
 
 TEST_F(ParseErrorTest, EofInService) {
@@ -1413,7 +1698,7 @@
 // definitions again afoter parsing (note, however, that the order of messages
 // cannot be guaranteed to be the same)
 
-typedef ParserTest ParseDecriptorDebugTest;
+typedef ParserTest ParseDescriptorDebugTest;
 
 class CompareDescriptorNames {
  public:
@@ -1432,7 +1717,7 @@
   }
   DescriptorProto **data =
     descriptor_proto->mutable_nested_type()->mutable_data();
-  sort(data, data + size, CompareDescriptorNames());
+  std::sort(data, data + size, CompareDescriptorNames());
 }
 
 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
@@ -1444,10 +1729,31 @@
   }
   DescriptorProto **data =
     file_descriptor_proto->mutable_message_type()->mutable_data();
-  sort(data, data + size, CompareDescriptorNames());
+  std::sort(data, data + size, CompareDescriptorNames());
 }
 
-TEST_F(ParseDecriptorDebugTest, TestAllDescriptorTypes) {
+// Strips the message and enum field type names for comparison purpose only.
+void StripFieldTypeName(DescriptorProto* proto) {
+  for (int i = 0; i < proto->field_size(); ++i) {
+    string type_name = proto->field(i).type_name();
+    string::size_type pos = type_name.find_last_of(".");
+    if (pos != string::npos) {
+      proto->mutable_field(i)->mutable_type_name()->assign(
+          type_name.begin() + pos + 1, type_name.end());
+    }
+  }
+  for (int i = 0; i < proto->nested_type_size(); ++i) {
+    StripFieldTypeName(proto->mutable_nested_type(i));
+  }
+}
+
+void StripFieldTypeName(FileDescriptorProto* file_proto) {
+  for (int i = 0; i < file_proto->message_type_size(); ++i) {
+    StripFieldTypeName(file_proto->mutable_message_type(i));
+  }
+}
+
+TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
   const FileDescriptor* original_file =
      protobuf_unittest::TestAllTypes::descriptor()->file();
   FileDescriptorProto expected;
@@ -1499,7 +1805,7 @@
   EXPECT_EQ(expected.DebugString(), parsed.DebugString());
 }
 
-TEST_F(ParseDecriptorDebugTest, TestCustomOptions) {
+TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
   const FileDescriptor* original_file =
      protobuf_unittest::AggregateMessage::descriptor()->file();
   FileDescriptorProto expected;
@@ -1538,6 +1844,160 @@
   EXPECT_EQ(expected.DebugString(), parsed.DebugString());
 }
 
+// Ensure that DebugStringWithOptions(), with |include_comments| set to true,
+// includes comments from the original parser input in all of the appropriate
+// places.
+TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
+  SetupParser(
+      "// Detached comment before syntax.\n"
+      "\n"
+      "// Syntax comment.\n"
+      "syntax = \"proto2\";\n"
+      "\n"
+      "// Detached comment before package.\n"
+      "\n"
+      "// Package comment.\n"
+      "package comment_test;\n"
+      "\n"
+      "// Detached comment before TestMessage1.\n"
+      "\n"
+      "// Message comment.\n"
+      "//\n"
+      "// More detail in message comment.\n"
+      "message TestMessage1 {\n"
+      "\n"
+      "  // Detached comment before foo.\n"
+      "\n"
+      "  // Field comment.\n"
+      "  optional int32 foo = 1;\n"
+      "\n"
+      "  // Detached comment before NestedMessage.\n"
+      "\n"
+      "  // Nested-message comment.\n"
+      "  message NestedMessage {\n"
+      "    optional int32 bar = 1;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "// Detached comment before MyEnumType.\n"
+      "\n"
+      "// Enum comment.\n"
+      "enum MyEnumType {\n"
+      "\n"
+      "  // Detached comment before ASDF.\n"
+      "\n"
+      "  // Enum-value comment.\n"
+      "  ASDF = 1;\n"
+      "}\n"
+      "\n"
+      "// Detached comment before MyService.\n"
+      "\n"
+      "// Service comment.\n"
+      "service MyService {\n"
+      "\n"
+      "  // Detached comment before MyRPCCall.\n"
+      "\n"
+      "  // RPC comment.\n"
+      "  rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
+      "}\n");
+
+  FileDescriptorProto parsed_desc;
+  parsed_desc.set_name("foo.proto");
+  SourceLocationTable source_locations;
+  parser_->RecordSourceLocationsTo(&source_locations);
+  parser_->Parse(input_.get(), &parsed_desc);
+  EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+  ASSERT_EQ("", error_collector_.text_);
+
+  // We need to import the FileDescriptorProto to get a FileDescriptor.
+  MockValidationErrorCollector collector(source_locations, &error_collector_);
+  const FileDescriptor* descriptor =
+      pool_.BuildFileCollectingErrors(parsed_desc, &collector);
+  ASSERT_TRUE(descriptor != NULL);
+
+  // Ensure that each of the comments appears somewhere in the DebugString().
+  // We don't test the exact comment placement or formatting, because we do not
+  // want to be too fragile here.
+  const char* expected_comments[] = {
+    "Detached comment before syntax.",
+    "Syntax comment.",
+    "Detached comment before package.",
+    "Package comment.",
+    "Detached comment before TestMessage1.",
+    "Message comment.",
+    "More detail in message comment.",
+    "Detached comment before foo.",
+    "Field comment",
+    "Detached comment before NestedMessage.",
+    "Nested-message comment",
+    "Detached comment before MyEnumType.",
+    "Enum comment",
+    "Detached comment before ASDF.",
+    "Enum-value comment",
+    "Detached comment before MyService.",
+    "Service comment",
+    "Detached comment before MyRPCCall.",
+    "RPC comment",
+  };
+
+  DebugStringOptions debug_string_options;
+  debug_string_options.include_comments = true;
+
+  {
+    const string debug_string =
+        descriptor->DebugStringWithOptions(debug_string_options);
+
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
+      string::size_type found_pos = debug_string.find(expected_comments[i]);
+      EXPECT_TRUE(found_pos != string::npos)
+          << "\"" << expected_comments[i] << "\" not found.";
+    }
+
+    // Result of DebugStringWithOptions should be parseable.
+    SetupParser(debug_string.c_str());
+    FileDescriptorProto parsed;
+    parser_->Parse(input_.get(), &parsed);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+    ASSERT_EQ("", error_collector_.text_)
+        << "Failed to parse:\n" << debug_string;
+  }
+
+}
+
+TEST_F(ParseDescriptorDebugTest, TestMaps) {
+  SetupParser(
+      "syntax = \"proto3\"; "
+      "message Foo { "
+      "  message Bar { } "
+      "  map<int32, Bar> enum_message_map = 1; "
+      "  map<string, float> primitive_map = 2; "
+      "} ");
+  FileDescriptorProto original;
+  EXPECT_TRUE(parser_->Parse(input_.get(), &original));
+  original.set_name("foo.proto");
+  const FileDescriptor* file = pool_.BuildFile(original);
+  ASSERT_TRUE(file != NULL);
+
+  // Make sure the debug string uses map syntax and does not have the auto
+  // generated entry.
+  string debug_string = file->DebugString();
+  EXPECT_TRUE(debug_string.find("map<") != string::npos);
+  EXPECT_TRUE(debug_string.find("option map_entry") == string::npos);
+  EXPECT_TRUE(debug_string.find("MapEntry") == string::npos);
+
+  // Make sure the descriptor debug string is parsable.
+  FileDescriptorProto parsed;
+  SetupParser(debug_string.c_str());
+  parsed.set_name("foo.proto");
+  ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
+
+  original.clear_source_code_info();
+  parsed.clear_source_code_info();
+  StripFieldTypeName(&original);
+  StripFieldTypeName(&parsed);
+  EXPECT_EQ(original.DebugString(), parsed.DebugString());
+}
+
 // ===================================================================
 // SourceCodeInfo tests.
 
@@ -1670,8 +2130,8 @@
         return false;
       }
 
-      spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
-                              &location));
+      spans_.insert(
+          std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
     }
 
     return true;
@@ -1692,16 +2152,18 @@
   bool HasSpan(char start_marker, char end_marker,
                const Message& descriptor_proto) {
     return HasSpanWithComment(
-        start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL);
+        start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
   }
 
   bool HasSpanWithComment(char start_marker, char end_marker,
                           const Message& descriptor_proto,
                           const char* expected_leading_comments,
-                          const char* expected_trailing_comments) {
+                          const char* expected_trailing_comments,
+                          const char* expected_leading_detached_comments) {
     return HasSpanWithComment(
         start_marker, end_marker, descriptor_proto, NULL, -1,
-        expected_leading_comments, expected_trailing_comments);
+        expected_leading_comments, expected_trailing_comments,
+        expected_leading_detached_comments);
   }
 
   bool HasSpan(char start_marker, char end_marker,
@@ -1713,14 +2175,15 @@
                const Message& descriptor_proto, const string& field_name,
                int index) {
     return HasSpan(start_marker, end_marker, descriptor_proto,
-                   field_name, index, NULL, NULL);
+                   field_name, index, NULL, NULL, NULL);
   }
 
   bool HasSpan(char start_marker, char end_marker,
                const Message& descriptor_proto,
                const string& field_name, int index,
                const char* expected_leading_comments,
-               const char* expected_trailing_comments) {
+               const char* expected_trailing_comments,
+               const char* expected_leading_detached_comments) {
     const FieldDescriptor* field =
         descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
     if (field == NULL) {
@@ -1731,12 +2194,13 @@
 
     return HasSpanWithComment(
         start_marker, end_marker, descriptor_proto, field, index,
-        expected_leading_comments, expected_trailing_comments);
+        expected_leading_comments, expected_trailing_comments,
+        expected_leading_detached_comments);
   }
 
   bool HasSpan(const Message& descriptor_proto) {
     return HasSpanWithComment(
-        '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL);
+        '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
   }
 
   bool HasSpan(const Message& descriptor_proto, const string& field_name) {
@@ -1748,11 +2212,12 @@
     return HasSpan('\0', '\0', descriptor_proto, field_name, index);
   }
 
-  bool HasSpanWithComment(char start_marker, char end_marker,
-                          const Message& descriptor_proto,
-                          const FieldDescriptor* field, int index,
-                          const char* expected_leading_comments,
-                          const char* expected_trailing_comments) {
+  bool HasSpanWithComment(
+      char start_marker, char end_marker, const Message& descriptor_proto,
+      const FieldDescriptor* field, int index,
+      const char* expected_leading_comments,
+      const char* expected_trailing_comments,
+      const char* expected_leading_detached_comments) {
     pair<SpanMap::iterator, SpanMap::iterator> range =
         spans_.equal_range(SpanKey(descriptor_proto, field, index));
 
@@ -1791,6 +2256,13 @@
             EXPECT_EQ(expected_trailing_comments,
                       iter->second->trailing_comments());
           }
+          if (expected_leading_detached_comments == NULL) {
+            EXPECT_EQ(0, iter->second->leading_detached_comments_size());
+          } else {
+            EXPECT_EQ(
+                expected_leading_detached_comments,
+                Join(iter->second->leading_detached_comments(), "\n"));
+          }
 
           spans_.erase(iter);
           return true;
@@ -1841,7 +2313,7 @@
           text_without_markers_ += '$';
           ++column;
         } else {
-          markers_[*text] = make_pair(line, column);
+          markers_[*text] = std::make_pair(line, column);
           ++text;
           GOOGLE_CHECK_EQ('$', *text);
         }
@@ -1860,7 +2332,7 @@
 
 TEST_F(SourceInfoTest, BasicFileDecls) {
   EXPECT_TRUE(Parse(
-      "$a$syntax = \"proto2\";\n"
+      "$a$syntax = \"proto2\";$i$\n"
       "package $b$foo.bar$c$;\n"
       "import $d$\"baz.proto\"$e$;\n"
       "import $f$\"qux.proto\"$g$;$h$\n"
@@ -1871,6 +2343,7 @@
   EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
   EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
   EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
+  EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
 }
 
 TEST_F(SourceInfoTest, Messages) {
@@ -2301,6 +2774,9 @@
     "  rpc M(X) returns(Y) {\n"
     "    $g$option mopt = 1;$h$\n"
     "  }\n"
+    "  rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
+    "    $k$option mopt = 1;$l$\n"
+    "  }\n"
     "}\n"));
 
   EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
@@ -2360,6 +2836,26 @@
                       .uninterpreted_option(0).name(0), "name_part"));
   EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
                       .uninterpreted_option(0), "positive_int_value"));
+
+  EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+  EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
+                      "client_streaming"));
+  EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
+                      "server_streaming"));
 }
 
 TEST_F(SourceInfoTest, FieldOptions) {
@@ -2445,7 +2941,7 @@
       "  // Foo trailing\n"
       "  // line 2\n"
       "\n"
-      "  // ignored\n"
+      "  // detached\n"
       "\n"
       "  // bar leading\n"
       "  $b$optional int32 bar = 1;$c$\n"
@@ -2459,10 +2955,12 @@
 
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
       " Foo leading\n line 2\n",
-      " Foo trailing\n line 2\n"));
+      " Foo trailing\n line 2\n",
+      NULL));
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      " detached\n"));
 
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
@@ -2475,21 +2973,23 @@
 
 TEST_F(SourceInfoTest, DocComments2) {
   EXPECT_TRUE(Parse(
-      "// ignored\n"
-      "syntax = \"proto2\";\n"
+      "// detached before message.\n"
+      "\n"
       "// Foo leading\n"
       "// line 2\n"
       "$a$message Foo {\n"
       "  /* Foo trailing\n"
       "   * line 2 */\n"
-      "  // ignored\n"
+      "  // detached\n"
       "  /* bar leading\n"
       "   */"
       "  $b$optional int32 bar = 1;$c$  // bar trailing\n"
-      "  // ignored\n"
+      "  // ignored detached\n"
       "}$d$\n"
       "// ignored\n"
       "\n"
+      "// detached before option\n"
+      "\n"
       "// option leading\n"
       "$e$option baz = 123;$f$\n"
       "// option trailing\n"
@@ -2501,13 +3001,16 @@
 
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
       " Foo leading\n line 2\n",
-      " Foo trailing\n line 2 "));
+      " Foo trailing\n line 2 ",
+      " detached before message.\n"));
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      " detached\n"));
   EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
       " option leading\n",
-      " option trailing\n"));
+      " option trailing\n",
+      " detached before option\n"));
 
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
@@ -2538,7 +3041,8 @@
 
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      NULL));
 
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
@@ -2558,25 +3062,63 @@
       bar.options().uninterpreted_option(0), "aggregate_value"));
 }
 
+TEST_F(SourceInfoTest, DocCommentsTopLevel) {
+  EXPECT_TRUE(Parse(
+      "// detached before syntax paragraph 1\n"
+      "\n"
+      "// detached before syntax paragraph 2\n"
+      "\n"
+      "// syntax leading\n"
+      "$a$syntax = \"proto2\";$b$\n"
+      "// syntax trailing\n"
+      "\n"
+      "// syntax-package detached comments\n"
+      "\n"
+      ";\n"
+      "\n"
+      "// detached after empty before package\n"
+      "\n"
+      "// package leading\n"
+      "package $c$foo$d$;\n"
+      "// package trailing\n"
+      "\n"
+      "// ignored detach\n"
+      "\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
+      " syntax leading\n",
+      " syntax trailing\n",
+      " detached before syntax paragraph 1\n"
+      "\n"
+      " detached before syntax paragraph 2\n"));
+  EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
+      " package leading\n",
+      " package trailing\n",
+      " syntax-package detached comments\n"
+      "\n"
+      " detached after empty before package\n"));
+
+  // ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
 TEST_F(SourceInfoTest, DocCommentsOneof) {
   EXPECT_TRUE(Parse(
-      "// ignored\n"
-      "syntax = \"proto2\";\n"
       "// Foo leading\n"
       "$a$message Foo {\n"
       "  /* Foo trailing\n"
       "   */\n"
-      "  // ignored\n"
+      "  // detached before oneof\n"
       "  /* bar leading\n"
       "   * line 2 */\n"
       "  $b$oneof bar {\n"
       "  /* bar trailing\n"
       "   * line 2 */\n"
-      "  // ignored\n"
+      "  // detached before bar_int\n"
       "  /* bar_int leading\n"
       "   */\n"
       "  $c$int32 bar_int = 1;$d$  // bar_int trailing\n"
-      "  // ignored\n"
+      "  // detach comment ignored\n"
       "  }$e$\n"
       "}$f$\n"));
 
@@ -2586,13 +3128,16 @@
 
   EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
       " Foo leading\n",
-      " Foo trailing\n"));
+      " Foo trailing\n",
+      NULL));
   EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
       " bar leading\n line 2 ",
-      " bar trailing\n line 2 "));
+      " bar trailing\n line 2 ",
+      " detached before oneof\n"));
   EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
       " bar_int leading\n",
-      " bar_int trailing\n"));
+      " bar_int trailing\n",
+      " detached before bar_int\n"));
 
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 9011a6b..2ff50f6 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -48,6 +48,7 @@
 #include <unistd.h>
 #endif
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/plugin.pb.h>
 #include <google/protobuf/compiler/code_generator.h>
@@ -92,10 +93,69 @@
   const vector<const FileDescriptor*>& parsed_files_;
 };
 
+bool GenerateCode(const CodeGeneratorRequest& request,
+    const CodeGenerator& generator, CodeGeneratorResponse* response,
+    string* error_msg) {
+  DescriptorPool pool;
+  for (int i = 0; i < request.proto_file_size(); i++) {
+    const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
+    if (file == NULL) {
+      // BuildFile() already wrote an error message.
+      return false;
+    }
+  }
+
+  vector<const FileDescriptor*> parsed_files;
+  for (int i = 0; i < request.file_to_generate_size(); i++) {
+    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
+    if (parsed_files.back() == NULL) {
+      *error_msg = "protoc asked plugin to generate a file but "
+                   "did not provide a descriptor for the file: " +
+                   request.file_to_generate(i);
+      return false;
+    }
+  }
+
+  GeneratorResponseContext context(response, parsed_files);
+
+  if (generator.HasGenerateAll()) {
+    string error;
+    bool succeeded = generator.GenerateAll(
+        parsed_files, request.parameter(), &context, &error);
+
+    if (!succeeded && error.empty()) {
+      error = "Code generator returned false but provided no error "
+              "description.";
+    }
+    if (!error.empty()) {
+      response->set_error(error);
+    }
+  } else {
+    for (int i = 0; i < parsed_files.size(); i++) {
+      const FileDescriptor* file = parsed_files[i];
+
+      string error;
+      bool succeeded = generator.Generate(
+          file, request.parameter(), &context, &error);
+
+      if (!succeeded && error.empty()) {
+        error = "Code generator returned false but provided no error "
+                "description.";
+      }
+      if (!error.empty()) {
+        response->set_error(file->name() + ": " + error);
+        break;
+      }
+    }
+  }
+
+  return true;
+}
+
 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
 
   if (argc > 1) {
-    cerr << argv[0] << ": Unknown option: " << argv[1] << endl;
+    std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
     return 1;
   }
 
@@ -106,52 +166,23 @@
 
   CodeGeneratorRequest request;
   if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
-    cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl;
+    std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+              << std::endl;
     return 1;
   }
 
-  DescriptorPool pool;
-  for (int i = 0; i < request.proto_file_size(); i++) {
-    const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
-    if (file == NULL) {
-      // BuildFile() already wrote an error message.
-      return 1;
-    }
-  }
-
-  vector<const FileDescriptor*> parsed_files;
-  for (int i = 0; i < request.file_to_generate_size(); i++) {
-    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
-    if (parsed_files.back() == NULL) {
-      cerr << argv[0] << ": protoc asked plugin to generate a file but "
-              "did not provide a descriptor for the file: "
-           << request.file_to_generate(i) << endl;
-      return 1;
-    }
-  }
-
+  string error_msg;
   CodeGeneratorResponse response;
-  GeneratorResponseContext context(&response, parsed_files);
 
-  for (int i = 0; i < parsed_files.size(); i++) {
-    const FileDescriptor* file = parsed_files[i];
-
-    string error;
-    bool succeeded = generator->Generate(
-        file, request.parameter(), &context, &error);
-
-    if (!succeeded && error.empty()) {
-      error = "Code generator returned false but provided no error "
-              "description.";
+  if (GenerateCode(request, *generator, &response, &error_msg)) {
+    if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
+      std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
+      return 1;
     }
-    if (!error.empty()) {
-      response.set_error(file->name() + ": " + error);
-      break;
+  } else {
+    if (!error_msg.empty()) {
+      std::cerr << argv[0] << ": " << error_msg << std::endl;
     }
-  }
-
-  if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
-    cerr << argv[0] << ": Error writing to stdout." << endl;
     return 1;
   }
 
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 679f9bd..d2793a9 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -40,6 +40,13 @@
 //   }
 // You must link your plugin against libprotobuf and libprotoc.
 //
+// The core part of PluginMain is to invoke the given CodeGenerator on a
+// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is
+// abstracted out and made into function GenerateCode so that it can be reused,
+// for example, to implement a variant of PluginMain that does some
+// preprocessing on the input CodeGeneratorRequest before feeding the request
+// to the given code generator.
+//
 // To get protoc to use the plugin, do one of the following:
 // * Place the plugin binary somewhere in the PATH and give it the name
 //   "protoc-gen-NAME" (replacing "NAME" with the name of your plugin).  If you
@@ -55,16 +62,27 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
 #define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
 
+#include <string>
+
 #include <google/protobuf/stubs/common.h>
 namespace google {
 namespace protobuf {
 namespace compiler {
 
 class CodeGenerator;    // code_generator.h
+class CodeGeneratorRequest;
+class CodeGeneratorResponse;
 
 // Implements main() for a protoc plugin exposing the given code generator.
 LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
 
+// Generates code using the given code generator. Returns true if the code
+// generation is successful. If the code geneartion fails, error_msg may be
+// populated to describe the failure cause.
+bool GenerateCode(const CodeGeneratorRequest& request,
+    const CodeGenerator& generator, CodeGeneratorResponse* response,
+    string* error_msg);
+
 }  // namespace compiler
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index b5cd01b..e9d50a1 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/compiler/plugin.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/compiler/plugin.pb.h"
+#include <google/protobuf/compiler/plugin.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -48,32 +49,32 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, proto_file_),
   };
   CodeGeneratorRequest_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       CodeGeneratorRequest_descriptor_,
       CodeGeneratorRequest::default_instance_,
       CodeGeneratorRequest_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(CodeGeneratorRequest));
+      -1,
+      sizeof(CodeGeneratorRequest),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_),
+      -1);
   CodeGeneratorResponse_descriptor_ = file->message_type(1);
   static const int CodeGeneratorResponse_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, file_),
   };
   CodeGeneratorResponse_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       CodeGeneratorResponse_descriptor_,
       CodeGeneratorResponse::default_instance_,
       CodeGeneratorResponse_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(CodeGeneratorResponse));
+      -1,
+      sizeof(CodeGeneratorResponse),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_),
+      -1);
   CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0);
   static const int CodeGeneratorResponse_File_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_),
@@ -81,16 +82,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, content_),
   };
   CodeGeneratorResponse_File_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       CodeGeneratorResponse_File_descriptor_,
       CodeGeneratorResponse_File::default_instance_,
       CodeGeneratorResponse_File_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(CodeGeneratorResponse_File));
+      -1,
+      sizeof(CodeGeneratorResponse_File),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_),
+      -1);
 }
 
 namespace {
@@ -104,11 +105,11 @@
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance());
+      CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance());
+      CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance());
+      CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance());
 }
 
 }  // namespace
@@ -140,8 +141,8 @@
     "\01324.google.protobuf.compiler.CodeGenerat"
     "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
     "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
-    ",\n\034com.google.protobuf.compilerB\014PluginP"
-    "rotos", 445);
+    "7\n\034com.google.protobuf.compilerB\014PluginP"
+    "rotosZ\tplugin_go", 456);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
   CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
@@ -160,16 +161,26 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_;
 
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
 const int CodeGeneratorRequest::kParameterFieldNumber;
 const int CodeGeneratorRequest::kProtoFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorRequest::CodeGeneratorRequest()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest)
 }
@@ -178,7 +189,8 @@
 }
 
 CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorRequest)
@@ -187,7 +199,7 @@
 void CodeGeneratorRequest::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  parameter_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -197,9 +209,7 @@
 }
 
 void CodeGeneratorRequest::SharedDtor() {
-  if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete parameter_;
-  }
+  parameter_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -221,25 +231,30 @@
 
 CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL;
 
-CodeGeneratorRequest* CodeGeneratorRequest::New() const {
-  return new CodeGeneratorRequest;
+CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena) const {
+  CodeGeneratorRequest* n = new CodeGeneratorRequest;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void CodeGeneratorRequest::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest)
   if (has_parameter()) {
-    if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-      parameter_->clear();
-    }
+    parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
   file_to_generate_.Clear();
   proto_file_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool CodeGeneratorRequest::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorRequest)
   for (;;) {
@@ -257,7 +272,7 @@
             this->file_to_generate(this->file_to_generate_size() - 1).data(),
             this->file_to_generate(this->file_to_generate_size() - 1).length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "file_to_generate");
+            "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
         } else {
           goto handle_unusual;
         }
@@ -275,7 +290,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->parameter().data(), this->parameter().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "parameter");
+            "google.protobuf.compiler.CodeGeneratorRequest.parameter");
         } else {
           goto handle_unusual;
         }
@@ -287,12 +302,15 @@
       case 15: {
         if (tag == 122) {
          parse_proto_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_proto_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_proto_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(122)) goto parse_proto_file;
+        if (input->ExpectTag(122)) goto parse_loop_proto_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -324,10 +342,10 @@
   // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorRequest)
   // repeated string file_to_generate = 1;
   for (int i = 0; i < this->file_to_generate_size(); i++) {
-  ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
-    this->file_to_generate(i).data(), this->file_to_generate(i).length(),
-    ::google::protobuf::internal::WireFormat::SERIALIZE,
-    "file_to_generate");
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->file_to_generate(i).data(), this->file_to_generate(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
     ::google::protobuf::internal::WireFormatLite::WriteString(
       1, this->file_to_generate(i), output);
   }
@@ -337,18 +355,18 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->parameter().data(), this->parameter().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "parameter");
+      "google.protobuf.compiler.CodeGeneratorRequest.parameter");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       2, this->parameter(), output);
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (int i = 0; i < this->proto_file_size(); i++) {
+  for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       15, this->proto_file(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -363,7 +381,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->file_to_generate(i).data(), this->file_to_generate(i).length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "file_to_generate");
+      "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
     target = ::google::protobuf::internal::WireFormatLite::
       WriteStringToArray(1, this->file_to_generate(i), target);
   }
@@ -373,20 +391,20 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->parameter().data(), this->parameter().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "parameter");
+      "google.protobuf.compiler.CodeGeneratorRequest.parameter");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         2, this->parameter(), target);
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (int i = 0; i < this->proto_file_size(); i++) {
+  for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         15, this->proto_file(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -395,17 +413,16 @@
 }
 
 int CodeGeneratorRequest::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest)
   int total_size = 0;
 
-  if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
-    // optional string parameter = 2;
-    if (has_parameter()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->parameter());
-    }
-
+  // optional string parameter = 2;
+  if (has_parameter()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->parameter());
   }
+
   // repeated string file_to_generate = 1;
   total_size += 1 * this->file_to_generate_size();
   for (int i = 0; i < this->file_to_generate_size(); i++) {
@@ -421,7 +438,7 @@
         this->proto_file(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -433,36 +450,45 @@
 }
 
 void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const CodeGeneratorRequest* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const CodeGeneratorRequest* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorRequest)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorRequest)
     MergeFrom(*source);
   }
 }
 
 void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   file_to_generate_.MergeFrom(from.file_to_generate_);
   proto_file_.MergeFrom(from.proto_file_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
     if (from.has_parameter()) {
-      set_parameter(from.parameter());
+      set_has_parameter();
+      parameter_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.parameter_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -475,14 +501,16 @@
 }
 
 void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) {
-  if (other != this) {
-    file_to_generate_.Swap(&other->file_to_generate_);
-    std::swap(parameter_, other->parameter_);
-    proto_file_.Swap(&other->proto_file_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
+  file_to_generate_.UnsafeArenaSwap(&other->file_to_generate_);
+  parameter_.Swap(&other->parameter_);
+  proto_file_.UnsafeArenaSwap(&other->proto_file_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const {
@@ -493,17 +521,160 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorRequest
+
+// repeated string file_to_generate = 1;
+int CodeGeneratorRequest::file_to_generate_size() const {
+  return file_to_generate_.size();
+}
+void CodeGeneratorRequest::clear_file_to_generate() {
+  file_to_generate_.Clear();
+}
+ const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_.Get(index);
+}
+ ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_.Mutable(index);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  file_to_generate_.Mutable(index)->assign(value);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
+  file_to_generate_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
+  file_to_generate_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ ::std::string* CodeGeneratorRequest::add_file_to_generate() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_.Add();
+}
+ void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
+  file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value) {
+  file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
+  file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+CodeGeneratorRequest::file_to_generate() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+CodeGeneratorRequest::mutable_file_to_generate() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return &file_to_generate_;
+}
+
+// optional string parameter = 2;
+bool CodeGeneratorRequest::has_parameter() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void CodeGeneratorRequest::set_has_parameter() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void CodeGeneratorRequest::clear_has_parameter() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void CodeGeneratorRequest::clear_parameter() {
+  parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_parameter();
+}
+ const ::std::string& CodeGeneratorRequest::parameter() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ ::std::string* CodeGeneratorRequest::mutable_parameter() {
+  set_has_parameter();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorRequest::release_parameter() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  clear_has_parameter();
+  return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+  if (parameter != NULL) {
+    set_has_parameter();
+  } else {
+    clear_has_parameter();
+  }
+  parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+
+// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+int CodeGeneratorRequest::proto_file_size() const {
+  return proto_file_.size();
+}
+void CodeGeneratorRequest::clear_proto_file() {
+  proto_file_.Clear();
+}
+const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Get(index);
+}
+::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Mutable(index);
+}
+::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+CodeGeneratorRequest::mutable_proto_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return &proto_file_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorResponse_File::kNameFieldNumber;
 const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
 const int CodeGeneratorResponse_File::kContentFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorResponse_File::CodeGeneratorResponse_File()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
 }
@@ -512,7 +683,8 @@
 }
 
 CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
@@ -521,9 +693,9 @@
 void CodeGeneratorResponse_File::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  insertion_point_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  content_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -533,15 +705,9 @@
 }
 
 void CodeGeneratorResponse_File::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete insertion_point_;
-  }
-  if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete content_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  insertion_point_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  content_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -563,35 +729,36 @@
 
 CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL;
 
-CodeGeneratorResponse_File* CodeGeneratorResponse_File::New() const {
-  return new CodeGeneratorResponse_File;
+CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf::Arena* arena) const {
+  CodeGeneratorResponse_File* n = new CodeGeneratorResponse_File;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void CodeGeneratorResponse_File::Clear() {
-  if (_has_bits_[0 / 32] & 7) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  if (_has_bits_[0 / 32] & 7u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_insertion_point()) {
-      if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        insertion_point_->clear();
-      }
+      insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_content()) {
-      if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        content_->clear();
-      }
+      content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   for (;;) {
@@ -607,7 +774,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.compiler.CodeGeneratorResponse.File.name");
         } else {
           goto handle_unusual;
         }
@@ -624,7 +791,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->insertion_point().data(), this->insertion_point().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "insertion_point");
+            "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
         } else {
           goto handle_unusual;
         }
@@ -641,7 +808,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->content().data(), this->content().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "content");
+            "google.protobuf.compiler.CodeGeneratorResponse.File.content");
         } else {
           goto handle_unusual;
         }
@@ -679,7 +846,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
@@ -689,7 +856,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->insertion_point().data(), this->insertion_point().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "insertion_point");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       2, this->insertion_point(), output);
   }
@@ -699,12 +866,12 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->content().data(), this->content().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "content");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.content");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       15, this->content(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -719,7 +886,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
@@ -730,7 +897,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->insertion_point().data(), this->insertion_point().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "insertion_point");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         2, this->insertion_point(), target);
@@ -741,13 +908,13 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->content().data(), this->content().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "content");
+      "google.protobuf.compiler.CodeGeneratorResponse.File.content");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         15, this->content(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -756,9 +923,10 @@
 }
 
 int CodeGeneratorResponse_File::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 7u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -781,7 +949,7 @@
     }
 
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -793,40 +961,51 @@
 }
 
 void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const CodeGeneratorResponse_File* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const CodeGeneratorResponse_File* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse.File)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse.File)
     MergeFrom(*source);
   }
 }
 
 void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_insertion_point()) {
-      set_insertion_point(from.insertion_point());
+      set_has_insertion_point();
+      insertion_point_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.insertion_point_);
     }
     if (from.has_content()) {
-      set_content(from.content());
+      set_has_content();
+      content_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.content_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -838,14 +1017,16 @@
 }
 
 void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(insertion_point_, other->insertion_point_);
-    std::swap(content_, other->content_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) {
+  name_.Swap(&other->name_);
+  insertion_point_.Swap(&other->insertion_point_);
+  content_.Swap(&other->content_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const {
@@ -859,13 +1040,13 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorResponse::kErrorFieldNumber;
 const int CodeGeneratorResponse::kFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorResponse::CodeGeneratorResponse()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse)
 }
@@ -874,7 +1055,8 @@
 }
 
 CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse)
@@ -883,7 +1065,7 @@
 void CodeGeneratorResponse::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  error_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -893,9 +1075,7 @@
 }
 
 void CodeGeneratorResponse::SharedDtor() {
-  if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete error_;
-  }
+  error_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -917,24 +1097,29 @@
 
 CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL;
 
-CodeGeneratorResponse* CodeGeneratorResponse::New() const {
-  return new CodeGeneratorResponse;
+CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* arena) const {
+  CodeGeneratorResponse* n = new CodeGeneratorResponse;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void CodeGeneratorResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse)
   if (has_error()) {
-    if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-      error_->clear();
-    }
+    error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
   file_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool CodeGeneratorResponse::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse)
   for (;;) {
@@ -950,7 +1135,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->error().data(), this->error().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "error");
+            "google.protobuf.compiler.CodeGeneratorResponse.error");
         } else {
           goto handle_unusual;
         }
@@ -962,12 +1147,15 @@
       case 15: {
         if (tag == 122) {
          parse_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(122)) goto parse_file;
+        if (input->ExpectTag(122)) goto parse_loop_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1002,18 +1190,18 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->error().data(), this->error().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "error");
+      "google.protobuf.compiler.CodeGeneratorResponse.error");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->error(), output);
   }
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (int i = 0; i < this->file_size(); i++) {
+  for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       15, this->file(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -1028,20 +1216,20 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->error().data(), this->error().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "error");
+      "google.protobuf.compiler.CodeGeneratorResponse.error");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->error(), target);
   }
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (int i = 0; i < this->file_size(); i++) {
+  for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         15, this->file(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -1050,17 +1238,16 @@
 }
 
 int CodeGeneratorResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // optional string error = 1;
-    if (has_error()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->error());
-    }
-
+  // optional string error = 1;
+  if (has_error()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->error());
   }
+
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
   total_size += 1 * this->file_size();
   for (int i = 0; i < this->file_size(); i++) {
@@ -1069,7 +1256,7 @@
         this->file(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -1081,35 +1268,44 @@
 }
 
 void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const CodeGeneratorResponse* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const CodeGeneratorResponse* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse)
     MergeFrom(*source);
   }
 }
 
 void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   file_.MergeFrom(from.file_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_error()) {
-      set_error(from.error());
+      set_has_error();
+      error_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.error_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -1121,13 +1317,15 @@
 }
 
 void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) {
-  if (other != this) {
-    std::swap(error_, other->error_);
-    file_.Swap(&other->file_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
+  error_.Swap(&other->error_);
+  file_.UnsafeArenaSwap(&other->file_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const {
@@ -1138,6 +1336,260 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorResponse_File
+
+// optional string name = 1;
+bool CodeGeneratorResponse_File::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void CodeGeneratorResponse_File::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void CodeGeneratorResponse_File::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& CodeGeneratorResponse_File::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+
+// optional string insertion_point = 2;
+bool CodeGeneratorResponse_File::has_insertion_point() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_insertion_point() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void CodeGeneratorResponse_File::clear_has_insertion_point() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void CodeGeneratorResponse_File::clear_insertion_point() {
+  insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_insertion_point();
+}
+ const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+  set_has_insertion_point();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  clear_has_insertion_point();
+  return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+  if (insertion_point != NULL) {
+    set_has_insertion_point();
+  } else {
+    clear_has_insertion_point();
+  }
+  insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+
+// optional string content = 15;
+bool CodeGeneratorResponse_File::has_content() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void CodeGeneratorResponse_File::set_has_content() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void CodeGeneratorResponse_File::clear_has_content() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void CodeGeneratorResponse_File::clear_content() {
+  content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_content();
+}
+ const ::std::string& CodeGeneratorResponse_File::content() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_content() {
+  set_has_content();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_content() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  clear_has_content();
+  return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+  if (content != NULL) {
+    set_has_content();
+  } else {
+    clear_has_content();
+  }
+  content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse
+
+// optional string error = 1;
+bool CodeGeneratorResponse::has_error() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void CodeGeneratorResponse::set_has_error() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void CodeGeneratorResponse::clear_has_error() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void CodeGeneratorResponse::clear_error() {
+  error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_error();
+}
+ const ::std::string& CodeGeneratorResponse::error() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_error(const ::std::string& value) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value, size_t size) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ ::std::string* CodeGeneratorResponse::mutable_error() {
+  set_has_error();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse::release_error() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error)
+  clear_has_error();
+  return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+  if (error != NULL) {
+    set_has_error();
+  } else {
+    clear_has_error();
+  }
+  error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+
+// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+int CodeGeneratorResponse::file_size() const {
+  return file_.size();
+}
+void CodeGeneratorResponse::clear_file() {
+  file_.Clear();
+}
+const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Get(index);
+}
+::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Mutable(index);
+}
+::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+CodeGeneratorResponse::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return &file_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 65634da..510202f 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -8,23 +8,26 @@
 
 #include <google/protobuf/stubs/common.h>
 
-#if GOOGLE_PROTOBUF_VERSION < 2006000
+#if GOOGLE_PROTOBUF_VERSION < 3000000
 #error This file was generated by a newer version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please update
 #error your headers.
 #endif
-#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
 #error This file was generated by an older version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please
 #error regenerate this file with a newer version of protoc.
 #endif
 
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
 // @@protoc_insertion_point(includes)
 
 namespace google {
@@ -55,11 +58,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -69,7 +72,9 @@
 
   // implements Message ----------------------------------------------
 
-  CodeGeneratorRequest* New() const;
+  inline CodeGeneratorRequest* New() const { return New(NULL); }
+
+  CodeGeneratorRequest* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const CodeGeneratorRequest& from);
@@ -88,7 +93,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(CodeGeneratorRequest* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -96,56 +110,55 @@
   // accessors -------------------------------------------------------
 
   // repeated string file_to_generate = 1;
-  inline int file_to_generate_size() const;
-  inline void clear_file_to_generate();
+  int file_to_generate_size() const;
+  void clear_file_to_generate();
   static const int kFileToGenerateFieldNumber = 1;
-  inline const ::std::string& file_to_generate(int index) const;
-  inline ::std::string* mutable_file_to_generate(int index);
-  inline void set_file_to_generate(int index, const ::std::string& value);
-  inline void set_file_to_generate(int index, const char* value);
-  inline void set_file_to_generate(int index, const char* value, size_t size);
-  inline ::std::string* add_file_to_generate();
-  inline void add_file_to_generate(const ::std::string& value);
-  inline void add_file_to_generate(const char* value);
-  inline void add_file_to_generate(const char* value, size_t size);
-  inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
-  inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
+  const ::std::string& file_to_generate(int index) const;
+  ::std::string* mutable_file_to_generate(int index);
+  void set_file_to_generate(int index, const ::std::string& value);
+  void set_file_to_generate(int index, const char* value);
+  void set_file_to_generate(int index, const char* value, size_t size);
+  ::std::string* add_file_to_generate();
+  void add_file_to_generate(const ::std::string& value);
+  void add_file_to_generate(const char* value);
+  void add_file_to_generate(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
 
   // optional string parameter = 2;
-  inline bool has_parameter() const;
-  inline void clear_parameter();
+  bool has_parameter() const;
+  void clear_parameter();
   static const int kParameterFieldNumber = 2;
-  inline const ::std::string& parameter() const;
-  inline void set_parameter(const ::std::string& value);
-  inline void set_parameter(const char* value);
-  inline void set_parameter(const char* value, size_t size);
-  inline ::std::string* mutable_parameter();
-  inline ::std::string* release_parameter();
-  inline void set_allocated_parameter(::std::string* parameter);
+  const ::std::string& parameter() const;
+  void set_parameter(const ::std::string& value);
+  void set_parameter(const char* value);
+  void set_parameter(const char* value, size_t size);
+  ::std::string* mutable_parameter();
+  ::std::string* release_parameter();
+  void set_allocated_parameter(::std::string* parameter);
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  inline int proto_file_size() const;
-  inline void clear_proto_file();
+  int proto_file_size() const;
+  void clear_proto_file();
   static const int kProtoFileFieldNumber = 15;
-  inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
-  inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
-  inline ::google::protobuf::FileDescriptorProto* add_proto_file();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-      proto_file() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+  const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
+  ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
+  ::google::protobuf::FileDescriptorProto* add_proto_file();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
       mutable_proto_file();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+      proto_file() const;
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
  private:
   inline void set_has_parameter();
   inline void clear_has_parameter();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_;
-  ::std::string* parameter_;
+  ::google::protobuf::internal::ArenaStringPtr parameter_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_;
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
@@ -169,11 +182,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -183,7 +196,9 @@
 
   // implements Message ----------------------------------------------
 
-  CodeGeneratorResponse_File* New() const;
+  inline CodeGeneratorResponse_File* New() const { return New(NULL); }
+
+  CodeGeneratorResponse_File* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const CodeGeneratorResponse_File& from);
@@ -202,7 +217,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(CodeGeneratorResponse_File* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -210,40 +234,40 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // optional string insertion_point = 2;
-  inline bool has_insertion_point() const;
-  inline void clear_insertion_point();
+  bool has_insertion_point() const;
+  void clear_insertion_point();
   static const int kInsertionPointFieldNumber = 2;
-  inline const ::std::string& insertion_point() const;
-  inline void set_insertion_point(const ::std::string& value);
-  inline void set_insertion_point(const char* value);
-  inline void set_insertion_point(const char* value, size_t size);
-  inline ::std::string* mutable_insertion_point();
-  inline ::std::string* release_insertion_point();
-  inline void set_allocated_insertion_point(::std::string* insertion_point);
+  const ::std::string& insertion_point() const;
+  void set_insertion_point(const ::std::string& value);
+  void set_insertion_point(const char* value);
+  void set_insertion_point(const char* value, size_t size);
+  ::std::string* mutable_insertion_point();
+  ::std::string* release_insertion_point();
+  void set_allocated_insertion_point(::std::string* insertion_point);
 
   // optional string content = 15;
-  inline bool has_content() const;
-  inline void clear_content();
+  bool has_content() const;
+  void clear_content();
   static const int kContentFieldNumber = 15;
-  inline const ::std::string& content() const;
-  inline void set_content(const ::std::string& value);
-  inline void set_content(const char* value);
-  inline void set_content(const char* value, size_t size);
-  inline ::std::string* mutable_content();
-  inline ::std::string* release_content();
-  inline void set_allocated_content(::std::string* content);
+  const ::std::string& content() const;
+  void set_content(const ::std::string& value);
+  void set_content(const char* value);
+  void set_content(const char* value, size_t size);
+  ::std::string* mutable_content();
+  ::std::string* release_content();
+  void set_allocated_content(::std::string* content);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
  private:
@@ -254,13 +278,12 @@
   inline void set_has_content();
   inline void clear_has_content();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
-  ::std::string* insertion_point_;
-  ::std::string* content_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr insertion_point_;
+  ::google::protobuf::internal::ArenaStringPtr content_;
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
@@ -283,11 +306,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -297,7 +320,9 @@
 
   // implements Message ----------------------------------------------
 
-  CodeGeneratorResponse* New() const;
+  inline CodeGeneratorResponse* New() const { return New(NULL); }
+
+  CodeGeneratorResponse* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const CodeGeneratorResponse& from);
@@ -316,7 +341,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(CodeGeneratorResponse* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -326,39 +360,38 @@
   // accessors -------------------------------------------------------
 
   // optional string error = 1;
-  inline bool has_error() const;
-  inline void clear_error();
+  bool has_error() const;
+  void clear_error();
   static const int kErrorFieldNumber = 1;
-  inline const ::std::string& error() const;
-  inline void set_error(const ::std::string& value);
-  inline void set_error(const char* value);
-  inline void set_error(const char* value, size_t size);
-  inline ::std::string* mutable_error();
-  inline ::std::string* release_error();
-  inline void set_allocated_error(::std::string* error);
+  const ::std::string& error() const;
+  void set_error(const ::std::string& value);
+  void set_error(const char* value);
+  void set_error(const char* value, size_t size);
+  ::std::string* mutable_error();
+  ::std::string* release_error();
+  void set_allocated_error(::std::string* error);
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  inline int file_size() const;
-  inline void clear_file();
+  int file_size() const;
+  void clear_file();
   static const int kFileFieldNumber = 15;
-  inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
-  inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
-  inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
-      file() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+  const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
+  ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
+  ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
       mutable_file();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+      file() const;
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
  private:
   inline void set_has_error();
   inline void clear_has_error();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* error_;
+  ::google::protobuf::internal::ArenaStringPtr error_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
@@ -372,6 +405,7 @@
 
 // ===================================================================
 
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // CodeGeneratorRequest
 
 // repeated string file_to_generate = 1;
@@ -403,6 +437,7 @@
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
 }
 inline ::std::string* CodeGeneratorRequest::add_file_to_generate() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
   return file_to_generate_.Add();
 }
 inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
@@ -439,68 +474,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void CodeGeneratorRequest::clear_parameter() {
-  if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    parameter_->clear();
-  }
+  parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_parameter();
 }
 inline const ::std::string& CodeGeneratorRequest::parameter() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
-  return *parameter_;
+  return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
   set_has_parameter();
-  if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    parameter_ = new ::std::string;
-  }
-  parameter_->assign(value);
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
 inline void CodeGeneratorRequest::set_parameter(const char* value) {
   set_has_parameter();
-  if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    parameter_ = new ::std::string;
-  }
-  parameter_->assign(value);
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
 inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
   set_has_parameter();
-  if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    parameter_ = new ::std::string;
-  }
-  parameter_->assign(reinterpret_cast<const char*>(value), size);
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
 inline ::std::string* CodeGeneratorRequest::mutable_parameter() {
   set_has_parameter();
-  if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    parameter_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
-  return parameter_;
+  return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* CodeGeneratorRequest::release_parameter() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter)
   clear_has_parameter();
-  if (parameter_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = parameter_;
-    parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
-  if (parameter_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete parameter_;
-  }
-  if (parameter) {
+  if (parameter != NULL) {
     set_has_parameter();
-    parameter_ = parameter;
   } else {
     clear_has_parameter();
-    parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
 
@@ -523,16 +536,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   return proto_file_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-CodeGeneratorRequest::proto_file() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
-  return proto_file_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
 CodeGeneratorRequest::mutable_proto_file() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   return &proto_file_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_;
+}
 
 // -------------------------------------------------------------------
 
@@ -549,68 +562,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void CodeGeneratorResponse_File::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& CodeGeneratorResponse_File::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
 inline void CodeGeneratorResponse_File::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
 inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* CodeGeneratorResponse_File::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
 
@@ -625,68 +616,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void CodeGeneratorResponse_File::clear_insertion_point() {
-  if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    insertion_point_->clear();
-  }
+  insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_insertion_point();
 }
 inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
-  return *insertion_point_;
+  return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
   set_has_insertion_point();
-  if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    insertion_point_ = new ::std::string;
-  }
-  insertion_point_->assign(value);
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
   set_has_insertion_point();
-  if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    insertion_point_ = new ::std::string;
-  }
-  insertion_point_->assign(value);
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
   set_has_insertion_point();
-  if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    insertion_point_ = new ::std::string;
-  }
-  insertion_point_->assign(reinterpret_cast<const char*>(value), size);
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
   set_has_insertion_point();
-  if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    insertion_point_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
-  return insertion_point_;
+  return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
   clear_has_insertion_point();
-  if (insertion_point_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = insertion_point_;
-    insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
-  if (insertion_point_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete insertion_point_;
-  }
-  if (insertion_point) {
+  if (insertion_point != NULL) {
     set_has_insertion_point();
-    insertion_point_ = insertion_point;
   } else {
     clear_has_insertion_point();
-    insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
 
@@ -701,68 +670,46 @@
   _has_bits_[0] &= ~0x00000004u;
 }
 inline void CodeGeneratorResponse_File::clear_content() {
-  if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    content_->clear();
-  }
+  content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_content();
 }
 inline const ::std::string& CodeGeneratorResponse_File::content() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
-  return *content_;
+  return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
   set_has_content();
-  if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    content_ = new ::std::string;
-  }
-  content_->assign(value);
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
 inline void CodeGeneratorResponse_File::set_content(const char* value) {
   set_has_content();
-  if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    content_ = new ::std::string;
-  }
-  content_->assign(value);
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
 inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
   set_has_content();
-  if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    content_ = new ::std::string;
-  }
-  content_->assign(reinterpret_cast<const char*>(value), size);
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
   set_has_content();
-  if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    content_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
-  return content_;
+  return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* CodeGeneratorResponse_File::release_content() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content)
   clear_has_content();
-  if (content_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = content_;
-    content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
-  if (content_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete content_;
-  }
-  if (content) {
+  if (content != NULL) {
     set_has_content();
-    content_ = content;
   } else {
     clear_has_content();
-    content_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
 
@@ -781,68 +728,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void CodeGeneratorResponse::clear_error() {
-  if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    error_->clear();
-  }
+  error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_error();
 }
 inline const ::std::string& CodeGeneratorResponse::error() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
-  return *error_;
+  return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse::set_error(const ::std::string& value) {
   set_has_error();
-  if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    error_ = new ::std::string;
-  }
-  error_->assign(value);
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
 inline void CodeGeneratorResponse::set_error(const char* value) {
   set_has_error();
-  if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    error_ = new ::std::string;
-  }
-  error_->assign(value);
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
 inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
   set_has_error();
-  if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    error_ = new ::std::string;
-  }
-  error_->assign(reinterpret_cast<const char*>(value), size);
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
 inline ::std::string* CodeGeneratorResponse::mutable_error() {
   set_has_error();
-  if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    error_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
-  return error_;
+  return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* CodeGeneratorResponse::release_error() {
+  // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error)
   clear_has_error();
-  if (error_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = error_;
-    error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
-  if (error_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete error_;
-  }
-  if (error) {
+  if (error != NULL) {
     set_has_error();
-    error_ = error;
   } else {
     clear_has_error();
-    error_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
 
@@ -865,16 +790,21 @@
   // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
   return file_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
-CodeGeneratorResponse::file() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
-  return file_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
 CodeGeneratorResponse::mutable_file() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
   return &file_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_;
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
 
 
 // @@protoc_insertion_point(namespace_scope)
@@ -883,15 +813,6 @@
 }  // namespace protobuf
 }  // namespace google
 
-#ifndef SWIG
-namespace google {
-namespace protobuf {
-
-
-}  // namespace google
-}  // namespace protobuf
-#endif  // SWIG
-
 // @@protoc_insertion_point(global_scope)
 
 #endif  // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
index b65379d..acaee1f 100644
--- a/src/google/protobuf/compiler/plugin.proto
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -44,10 +44,13 @@
 // plugin should be named "protoc-gen-$NAME", and will then be used when the
 // flag "--${NAME}_out" is passed to protoc.
 
+syntax = "proto2";
 package google.protobuf.compiler;
 option java_package = "com.google.protobuf.compiler";
 option java_outer_classname = "PluginProtos";
 
+option go_package = "plugin_go";
+
 import "google/protobuf/descriptor.proto";
 
 // An encoded CodeGeneratorRequest is written to the plugin's stdin.
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 15e05da..0553dd0 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -44,16 +44,21 @@
 // performance-minded Python code leverage the fast C++ implementation
 // directly.
 
+#include <google/protobuf/stubs/hash.h>
 #include <limits>
 #include <map>
-#include <utility>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <google/protobuf/compiler/python/python_generator.h>
 #include <google/protobuf/descriptor.pb.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/io/printer.h>
@@ -88,6 +93,37 @@
 }
 
 
+// Returns the alias we assign to the module of the given .proto filename
+// when importing. See testPackageInitializationImport in
+// google/protobuf/python/reflection_test.py
+// to see why we need the alias.
+string ModuleAlias(const string& filename) {
+  string module_name = ModuleName(filename);
+  // We can't have dots in the module name, so we replace each with _dot_.
+  // But that could lead to a collision between a.b and a_dot_b, so we also
+  // duplicate each underscore.
+  GlobalReplaceSubstring("_", "__", &module_name);
+  GlobalReplaceSubstring(".", "_dot_", &module_name);
+  return module_name;
+}
+
+
+// Returns an import statement of form "from X.Y.Z import T" for the given
+// .proto filename.
+string ModuleImportStatement(const string& filename) {
+  string module_name = ModuleName(filename);
+  int last_dot_pos = module_name.rfind('.');
+  if (last_dot_pos == string::npos) {
+    // NOTE(petya): this is not tested as it would require a protocol buffer
+    // outside of any package, and I don't think that is easily achievable.
+    return "import " + module_name;
+  } else {
+    return "from " + module_name.substr(0, last_dot_pos) + " import " +
+        module_name.substr(last_dot_pos + 1);
+  }
+}
+
+
 // Returns the name of all containing types for descriptor,
 // in order from outermost to innermost, followed by descriptor's
 // own name.  Each name is separated by |separator|.
@@ -199,7 +235,7 @@
         // infinity * 0 = nan
         return "(1e10000 * 0)";
       } else {
-        return SimpleDtoa(value);
+        return "float(" + SimpleDtoa(value) + ")";
       }
     }
     case FieldDescriptor::CPPTYPE_FLOAT: {
@@ -215,7 +251,7 @@
         // infinity - infinity = nan
         return "(1e10000 * 0)";
       } else {
-        return SimpleFtoa(value);
+        return "float(" + SimpleFtoa(value) + ")";
       }
     }
     case FieldDescriptor::CPPTYPE_BOOL:
@@ -238,6 +274,19 @@
   return "";
 }
 
+string StringifySyntax(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case FileDescriptor::SYNTAX_PROTO2:
+      return "proto2";
+    case FileDescriptor::SYNTAX_PROTO3:
+      return "proto3";
+    case FileDescriptor::SYNTAX_UNKNOWN:
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports proto2 "
+                    "and proto3 syntax.";
+      return "";
+  }
+}
 
 
 }  // namespace
@@ -273,7 +322,7 @@
   fdp.SerializeToString(&file_descriptor_serialized_);
 
 
-  scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
   GOOGLE_CHECK(output.get());
   io::Printer printer(output.get(), '$');
   printer_ = &printer;
@@ -309,9 +358,12 @@
 // Prints Python imports for all modules imported by |file|.
 void Generator::PrintImports() const {
   for (int i = 0; i < file_->dependency_count(); ++i) {
-    string module_name = ModuleName(file_->dependency(i)->name());
-    printer_->Print("import $module$\n", "module",
-                    module_name);
+    const string& filename = file_->dependency(i)->name();
+    string import_statement = ModuleImportStatement(filename);
+    string module_alias = ModuleAlias(filename);
+    printer_->Print("$statement$ as $alias$\n", "statement",
+                    import_statement, "alias", module_alias);
+    CopyPublicDependenciesAliases(module_alias, file_->dependency(i));
   }
   printer_->Print("\n");
 
@@ -329,10 +381,12 @@
   m["descriptor_name"] = kDescriptorKey;
   m["name"] = file_->name();
   m["package"] = file_->package();
+  m["syntax"] = StringifySyntax(file_->syntax());
   const char file_descriptor_template[] =
       "$descriptor_name$ = _descriptor.FileDescriptor(\n"
       "  name='$name$',\n"
-      "  package='$package$',\n";
+      "  package='$package$',\n"
+      "  syntax='$syntax$',\n";
   printer_->Print(m, file_descriptor_template);
   printer_->Indent();
   printer_->Print(
@@ -342,8 +396,9 @@
   if (file_->dependency_count() != 0) {
     printer_->Print(",\ndependencies=[");
     for (int i = 0; i < file_->dependency_count(); ++i) {
-      string module_name = ModuleName(file_->dependency(i)->name());
-      printer_->Print("$module_name$.DESCRIPTOR,", "module_name", module_name);
+      string module_alias = ModuleAlias(file_->dependency(i)->name());
+      printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
+                      module_alias);
     }
     printer_->Print("]");
   }
@@ -375,7 +430,7 @@
     for (int j = 0; j < enum_descriptor.value_count(); ++j) {
       const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j);
       top_level_enum_values.push_back(
-          make_pair(value_descriptor.name(), value_descriptor.number()));
+          std::make_pair(value_descriptor.name(), value_descriptor.number()));
     }
   }
 
@@ -541,12 +596,9 @@
   printer_->Print("])\n\n");
 }
 
-void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
-  // Print the service.
-  printer_->Print("$class_name$ = service_reflection.GeneratedServiceType("
-                  "'$class_name$', (_service.Service,), dict(\n",
-                  "class_name", descriptor.name());
-  printer_->Indent();
+
+void Generator::PrintDescriptorKeyAndModuleName(
+    const ServiceDescriptor& descriptor) const {
   printer_->Print(
       "$descriptor_key$ = $descriptor_name$,\n",
       "descriptor_key", kDescriptorKey,
@@ -554,6 +606,15 @@
   printer_->Print(
       "__module__ = '$module_name$'\n",
       "module_name", ModuleName(file_->name()));
+}
+
+void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {
+  // Print the service.
+  printer_->Print("$class_name$ = service_reflection.GeneratedServiceType("
+                  "'$class_name$', (_service.Service,), dict(\n",
+                  "class_name", descriptor.name());
+  printer_->Indent();
+  Generator::PrintDescriptorKeyAndModuleName(descriptor);
   printer_->Print("))\n\n");
   printer_->Outdent();
 }
@@ -565,13 +626,7 @@
                   "'$class_name$_Stub', ($class_name$,), dict(\n",
                   "class_name", descriptor.name());
   printer_->Indent();
-  printer_->Print(
-      "$descriptor_key$ = $descriptor_name$,\n",
-      "descriptor_key", kDescriptorKey,
-      "descriptor_name", ModuleLevelServiceDescriptorName(descriptor));
-  printer_->Print(
-      "__module__ = '$module_name$'\n",
-      "module_name", ModuleName(file_->name()));
+  Generator::PrintDescriptorKeyAndModuleName(descriptor);
   printer_->Print("))\n\n");
   printer_->Outdent();
 }
@@ -626,10 +681,12 @@
   message_descriptor.options().SerializeToString(&options_string);
   printer_->Print(
       "options=$options_value$,\n"
-      "is_extendable=$extendable$",
+      "is_extendable=$extendable$,\n"
+      "syntax='$syntax$'",
       "options_value", OptionsValue("MessageOptions", options_string),
       "extendable", message_descriptor.extension_range_count() > 0 ?
-                      "True" : "False");
+                      "True" : "False",
+      "syntax", StringifySyntax(message_descriptor.file()->syntax()));
   printer_->Print(",\n");
 
   // Extension ranges
@@ -1084,7 +1141,7 @@
   // We now have the name relative to its own module.  Also qualify with
   // the module name iff this descriptor is from a different .proto file.
   if (descriptor.file() != file_) {
-    name = ModuleName(descriptor.file()->name()) + "." + name;
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
   }
   return name;
 }
@@ -1096,7 +1153,7 @@
 string Generator::ModuleLevelMessageName(const Descriptor& descriptor) const {
   string name = NamePrefixedWithNestedTypes(descriptor, ".");
   if (descriptor.file() != file_) {
-    name = ModuleName(descriptor.file()->name()) + "." + name;
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
   }
   return name;
 }
@@ -1109,7 +1166,7 @@
   UpperString(&name);
   name = "_" + name;
   if (descriptor.file() != file_) {
-    name = ModuleName(descriptor.file()->name()) + "." + name;
+    name = ModuleAlias(descriptor.file()->name()) + "." + name;
   }
   return name;
 }
@@ -1256,6 +1313,18 @@
   }
 }
 
+// If a dependency forwards other files through public dependencies, let's
+// copy over the corresponding module aliases.
+void Generator::CopyPublicDependenciesAliases(
+    const string& copy_from, const FileDescriptor* file) const {
+  for (int i = 0; i < file->public_dependency_count(); ++i) {
+    string module_alias = ModuleAlias(file->public_dependency(i)->name());
+    printer_->Print("$alias$ = $copy_from$.$alias$\n", "alias", module_alias,
+                    "copy_from", copy_from);
+    CopyPublicDependenciesAliases(copy_from, file->public_dependency(i));
+  }
+}
+
 }  // namespace python
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index f86e9ea..aa0f5fc 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -38,6 +38,7 @@
 #include <string>
 
 #include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -127,6 +128,8 @@
   void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const;
   void PrintServiceClass(const ServiceDescriptor& descriptor) const;
   void PrintServiceStub(const ServiceDescriptor& descriptor) const;
+  void PrintDescriptorKeyAndModuleName(
+      const ServiceDescriptor& descriptor) const ;
 
   void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const;
   string OptionsValue(const string& class_name,
@@ -148,6 +151,9 @@
   void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
   void FixOptionsForMessage(const Descriptor& descriptor) const;
 
+  void CopyPublicDependenciesAliases(
+      const string& copy_from, const FileDescriptor* file) const;
+
   // Very coarse-grained lock to ensure that Generate() is reentrant.
   // Guards file_, printer_ and file_descriptor_serialized_.
   mutable Mutex mutex_;
diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
index 09dbc65..23f2449 100644
--- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -35,15 +35,19 @@
 //   worth.
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/compiler/python/python_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/printer.h>
 
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/testing/file.h>
 
 namespace google {
 namespace protobuf {
@@ -69,7 +73,7 @@
 
   void TryInsert(const string& filename, const string& insertion_point,
                  GeneratorContext* context) const {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code.proto b/src/google/protobuf/compiler/ruby/ruby_generated_code.proto
new file mode 100644
index 0000000..42d82a6
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code.proto
@@ -0,0 +1,67 @@
+syntax = "proto3";
+
+package A.B.C;
+
+message TestMessage {
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  bool optional_bool = 5;
+  double optional_double = 6;
+  float optional_float = 7;
+  string optional_string = 8;
+  bytes optional_bytes = 9;
+  TestEnum optional_enum = 10;
+  TestMessage optional_msg = 11;
+
+  repeated int32 repeated_int32 = 21;
+  repeated int64 repeated_int64 = 22;
+  repeated uint32 repeated_uint32 = 23;
+  repeated uint64 repeated_uint64 = 24;
+  repeated bool repeated_bool = 25;
+  repeated double repeated_double = 26;
+  repeated float repeated_float = 27;
+  repeated string repeated_string = 28;
+  repeated bytes repeated_bytes = 29;
+  repeated TestEnum repeated_enum = 30;
+  repeated TestMessage repeated_msg = 31;
+
+  oneof my_oneof {
+    int32 oneof_int32 = 41;
+    int64 oneof_int64 = 42;
+    uint32 oneof_uint32 = 43;
+    uint64 oneof_uint64 = 44;
+    bool oneof_bool = 45;
+    double oneof_double = 46;
+    float oneof_float = 47;
+    string oneof_string = 48;
+    bytes oneof_bytes = 49;
+    TestEnum oneof_enum = 50;
+    TestMessage oneof_msg = 51;
+  }
+
+  map<int32, string> map_int32_string = 61;
+  map<int64, string> map_int64_string = 62;
+  map<uint32, string> map_uint32_string = 63;
+  map<uint64, string> map_uint64_string = 64;
+  map<bool, string> map_bool_string = 65;
+  map<string, string> map_string_string = 66;
+  map<string, TestMessage> map_string_msg = 67;
+  map<string, TestEnum> map_string_enum = 68;
+  map<string, int32> map_string_int32 = 69;
+  map<string, bool> map_string_bool = 70;
+
+  message NestedMessage {
+    int32 foo = 1;
+  }
+
+  NestedMessage nested_message = 80;
+}
+
+enum TestEnum {
+  Default = 0;
+  A = 1;
+  B = 2;
+  C = 3;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code.rb
new file mode 100644
index 0000000..49b23fb
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code.rb
@@ -0,0 +1,74 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ruby_generated_code.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "A.B.C.TestMessage" do
+    optional :optional_int32, :int32, 1
+    optional :optional_int64, :int64, 2
+    optional :optional_uint32, :uint32, 3
+    optional :optional_uint64, :uint64, 4
+    optional :optional_bool, :bool, 5
+    optional :optional_double, :double, 6
+    optional :optional_float, :float, 7
+    optional :optional_string, :string, 8
+    optional :optional_bytes, :bytes, 9
+    optional :optional_enum, :enum, 10, "A.B.C.TestEnum"
+    optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+    repeated :repeated_int32, :int32, 21
+    repeated :repeated_int64, :int64, 22
+    repeated :repeated_uint32, :uint32, 23
+    repeated :repeated_uint64, :uint64, 24
+    repeated :repeated_bool, :bool, 25
+    repeated :repeated_double, :double, 26
+    repeated :repeated_float, :float, 27
+    repeated :repeated_string, :string, 28
+    repeated :repeated_bytes, :bytes, 29
+    repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
+    repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
+    map :map_int32_string, :int32, :string, 61
+    map :map_int64_string, :int64, :string, 62
+    map :map_uint32_string, :uint32, :string, 63
+    map :map_uint64_string, :uint64, :string, 64
+    map :map_bool_string, :bool, :string, 65
+    map :map_string_string, :string, :string, 66
+    map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage"
+    map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum"
+    map :map_string_int32, :string, :int32, 69
+    map :map_string_bool, :string, :bool, 70
+    optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+    oneof :my_oneof do
+      optional :oneof_int32, :int32, 41
+      optional :oneof_int64, :int64, 42
+      optional :oneof_uint32, :uint32, 43
+      optional :oneof_uint64, :uint64, 44
+      optional :oneof_bool, :bool, 45
+      optional :oneof_double, :double, 46
+      optional :oneof_float, :float, 47
+      optional :oneof_string, :string, 48
+      optional :oneof_bytes, :bytes, 49
+      optional :oneof_enum, :enum, 50, "A.B.C.TestEnum"
+      optional :oneof_msg, :message, 51, "A.B.C.TestMessage"
+    end
+  end
+  add_message "A.B.C.TestMessage.NestedMessage" do
+    optional :foo, :int32, 1
+  end
+  add_enum "A.B.C.TestEnum" do
+    value :Default, 0
+    value :A, 1
+    value :B, 2
+    value :C, 3
+  end
+end
+
+module A
+  module B
+    module C
+      TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass
+      TestMessage::NestedMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass
+      TestEnum = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule
+    end
+  end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
new file mode 100644
index 0000000..92c76fb
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -0,0 +1,463 @@
+// 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.
+
+#include <sstream>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+
+using google::protobuf::internal::scoped_ptr;
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+// Forward decls.
+std::string IntToString(int32 value);
+std::string StripDotProto(const std::string& proto_file);
+std::string LabelForField(google::protobuf::FieldDescriptor* field);
+std::string TypeName(google::protobuf::FieldDescriptor* field);
+void GenerateMessage(const google::protobuf::Descriptor* message,
+                     google::protobuf::io::Printer* printer);
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+                  google::protobuf::io::Printer* printer);
+void GenerateMessageAssignment(
+    const std::string& prefix,
+    const google::protobuf::Descriptor* message,
+    google::protobuf::io::Printer* printer);
+void GenerateEnumAssignment(
+    const std::string& prefix,
+    const google::protobuf::EnumDescriptor* en,
+    google::protobuf::io::Printer* printer);
+
+std::string IntToString(int32 value) {
+  std::ostringstream os;
+  os << value;
+  return os.str();
+}
+
+std::string StripDotProto(const std::string& proto_file) {
+  int lastindex = proto_file.find_last_of(".");
+  return proto_file.substr(0, lastindex);
+}
+
+std::string GetOutputFilename(const std::string& proto_file) {
+  return StripDotProto(proto_file) + ".rb";
+}
+
+std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
+  switch (field->label()) {
+    case FieldDescriptor::LABEL_OPTIONAL: return "optional";
+    case FieldDescriptor::LABEL_REQUIRED: return "required";
+    case FieldDescriptor::LABEL_REPEATED: return "repeated";
+    default: assert(false); return "";
+  }
+}
+
+std::string TypeName(const google::protobuf::FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32: return "int32";
+    case FieldDescriptor::TYPE_INT64: return "int64";
+    case FieldDescriptor::TYPE_UINT32: return "uint32";
+    case FieldDescriptor::TYPE_UINT64: return "uint64";
+    case FieldDescriptor::TYPE_SINT32: return "sint32";
+    case FieldDescriptor::TYPE_SINT64: return "sint64";
+    case FieldDescriptor::TYPE_FIXED32: return "fixed32";
+    case FieldDescriptor::TYPE_FIXED64: return "fixed64";
+    case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
+    case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
+    case FieldDescriptor::TYPE_DOUBLE: return "double";
+    case FieldDescriptor::TYPE_FLOAT: return "float";
+    case FieldDescriptor::TYPE_BOOL: return "bool";
+    case FieldDescriptor::TYPE_ENUM: return "enum";
+    case FieldDescriptor::TYPE_STRING: return "string";
+    case FieldDescriptor::TYPE_BYTES: return "bytes";
+    case FieldDescriptor::TYPE_MESSAGE: return "message";
+    case FieldDescriptor::TYPE_GROUP: return "group";
+    default: assert(false); return "";
+  }
+}
+
+void GenerateField(const google::protobuf::FieldDescriptor* field,
+                   google::protobuf::io::Printer* printer) {
+
+  if (field->is_map()) {
+    const FieldDescriptor* key_field =
+        field->message_type()->FindFieldByNumber(1);
+    const FieldDescriptor* value_field =
+        field->message_type()->FindFieldByNumber(2);
+
+    printer->Print(
+      "map :$name$, :$key_type$, :$value_type$, $number$",
+      "name", field->name(),
+      "key_type", TypeName(key_field),
+      "value_type", TypeName(value_field),
+      "number", IntToString(field->number()));
+
+    if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+        "subtype", value_field->message_type()->full_name());
+    } else if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+        "subtype", value_field->enum_type()->full_name());
+    } else {
+      printer->Print("\n");
+    }
+  } else {
+
+    printer->Print(
+      "$label$ :$name$, ",
+      "label", LabelForField(field),
+      "name", field->name());
+    printer->Print(
+      ":$type$, $number$",
+      "type", TypeName(field),
+      "number", IntToString(field->number()));
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+       "subtype", field->message_type()->full_name());
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+      printer->Print(
+        ", \"$subtype$\"\n",
+        "subtype", field->enum_type()->full_name());
+    } else {
+      printer->Print("\n");
+    }
+  }
+}
+
+void GenerateOneof(const google::protobuf::OneofDescriptor* oneof,
+                   google::protobuf::io::Printer* printer) {
+  printer->Print(
+      "oneof :$name$ do\n",
+      "name", oneof->name());
+  printer->Indent();
+
+  for (int i = 0; i < oneof->field_count(); i++) {
+    const FieldDescriptor* field = oneof->field(i);
+    GenerateField(field, printer);
+  }
+
+  printer->Outdent();
+  printer->Print("end\n");
+}
+
+void GenerateMessage(const google::protobuf::Descriptor* message,
+                     google::protobuf::io::Printer* printer) {
+
+  // Don't generate MapEntry messages -- we use the Ruby extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return;
+  }
+
+  printer->Print(
+    "add_message \"$name$\" do\n",
+    "name", message->full_name());
+  printer->Indent();
+
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if (!field->containing_oneof()) {
+      GenerateField(field, printer);
+    }
+  }
+
+  for (int i = 0; i < message->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = message->oneof_decl(i);
+    GenerateOneof(oneof, printer);
+  }
+
+  printer->Outdent();
+  printer->Print("end\n");
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateMessage(message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnum(message->enum_type(i), printer);
+  }
+}
+
+void GenerateEnum(const google::protobuf::EnumDescriptor* en,
+                  google::protobuf::io::Printer* printer) {
+  printer->Print(
+    "add_enum \"$name$\" do\n",
+    "name", en->full_name());
+  printer->Indent();
+
+  for (int i = 0; i < en->value_count(); i++) {
+    const EnumValueDescriptor* value = en->value(i);
+    printer->Print(
+      "value :$name$, $number$\n",
+      "name", value->name(),
+      "number", IntToString(value->number()));
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "end\n");
+}
+
+// Module names, class names, and enum value names need to be Ruby constants,
+// which must start with a capital letter.
+std::string RubifyConstant(const std::string& name) {
+  std::string ret = name;
+  if (!ret.empty()) {
+    if (ret[0] >= 'a' && ret[0] <= 'z') {
+      // If it starts with a lowercase letter, capitalize it.
+      ret[0] = ret[0] - 'a' + 'A';
+    } else if (ret[0] < 'A' || ret[0] > 'Z') {
+      // Otherwise (e.g. if it begins with an underscore), we need to come up
+      // with some prefix that starts with a capital letter. We could be smarter
+      // here, e.g. try to strip leading underscores, but this may cause other
+      // problems if the user really intended the name. So let's just prepend a
+      // well-known suffix.
+      ret = "PB_" + ret;
+    }
+  }
+  return ret;
+}
+
+void GenerateMessageAssignment(
+    const std::string& prefix,
+    const google::protobuf::Descriptor* message,
+    google::protobuf::io::Printer* printer) {
+
+  // Don't generate MapEntry messages -- we use the Ruby extension's native
+  // support for map fields instead.
+  if (message->options().map_entry()) {
+    return;
+  }
+
+  printer->Print(
+    "$prefix$$name$ = ",
+    "prefix", prefix,
+    "name", RubifyConstant(message->name()));
+  printer->Print(
+    "Google::Protobuf::DescriptorPool.generated_pool."
+    "lookup(\"$full_name$\").msgclass\n",
+    "full_name", message->full_name());
+
+  std::string nested_prefix = prefix + message->name() + "::";
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    GenerateMessageAssignment(nested_prefix, message->nested_type(i), printer);
+  }
+  for (int i = 0; i < message->enum_type_count(); i++) {
+    GenerateEnumAssignment(nested_prefix, message->enum_type(i), printer);
+  }
+}
+
+void GenerateEnumAssignment(
+    const std::string& prefix,
+    const google::protobuf::EnumDescriptor* en,
+    google::protobuf::io::Printer* printer) {
+  printer->Print(
+    "$prefix$$name$ = ",
+    "prefix", prefix,
+    "name", RubifyConstant(en->name()));
+  printer->Print(
+    "Google::Protobuf::DescriptorPool.generated_pool."
+    "lookup(\"$full_name$\").enummodule\n",
+    "full_name", en->full_name());
+}
+
+int GeneratePackageModules(
+    std::string package_name,
+    google::protobuf::io::Printer* printer) {
+  int levels = 0;
+  while (!package_name.empty()) {
+    size_t dot_index = package_name.find(".");
+    string component;
+    if (dot_index == string::npos) {
+      component = package_name;
+      package_name = "";
+    } else {
+      component = package_name.substr(0, dot_index);
+      package_name = package_name.substr(dot_index + 1);
+    }
+    component = RubifyConstant(component);
+    printer->Print(
+      "module $name$\n",
+      "name", component);
+    printer->Indent();
+    levels++;
+  }
+  return levels;
+}
+
+void EndPackageModules(
+    int levels,
+    google::protobuf::io::Printer* printer) {
+  while (levels > 0) {
+    levels--;
+    printer->Outdent();
+    printer->Print(
+      "end\n");
+  }
+}
+
+bool UsesTypeFromFile(const Descriptor* message, const FileDescriptor* file,
+                      string* error) {
+  for (int i = 0; i < message->field_count(); i++) {
+    const FieldDescriptor* field = message->field(i);
+    if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+         field->message_type()->file() == file) ||
+        (field->type() == FieldDescriptor::TYPE_ENUM &&
+         field->enum_type()->file() == file)) {
+      *error = "proto3 message field " + field->full_name() + " in file " +
+               file->name() + " has a dependency on a type from proto2 file " +
+               file->name() +
+               ".  Ruby doesn't support proto2 yet, so we must fail.";
+      return true;
+    }
+  }
+
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    if (UsesTypeFromFile(message->nested_type(i), file, error)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Ruby doesn't currently support proto2.  This causes a failure even for proto3
+// files that import proto2.  But in some cases, the proto2 file is only being
+// imported to extend another proto2 message.  The prime example is declaring
+// custom options by extending FileOptions/FieldOptions/etc.
+//
+// If the proto3 messages don't have any proto2 submessages, it is safe to omit
+// the dependency completely.  Users won't be able to use any proto2 extensions,
+// but they already couldn't because proto2 messages aren't supported.
+//
+// If/when we add proto2 support, we should remove this.
+bool MaybeEmitDependency(const FileDescriptor* import,
+                         const FileDescriptor* from,
+                         io::Printer* printer,
+                         string* error) {
+  if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+    for (int i = 0; i < from->message_type_count(); i++) {
+      if (UsesTypeFromFile(from->message_type(i), import, error)) {
+        // Error text was already set by UsesTypeFromFile().
+        return false;
+      }
+    }
+
+    // Ok to omit this proto2 dependency -- so we won't print anything.
+    GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name()
+                        << "' from proto3 output file '"
+                        << GetOutputFilename(from->name())
+                        << "' because we don't support proto2 and no proto2 "
+                           "types from that file are being used.";
+    return true;
+  } else {
+    printer->Print(
+      "require '$name$'\n", "name", StripDotProto(import->name()));
+    return true;
+  }
+}
+
+bool GenerateFile(const FileDescriptor* file, io::Printer* printer,
+                  string* error) {
+  printer->Print(
+    "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "# source: $filename$\n"
+    "\n",
+    "filename", file->name());
+
+  printer->Print(
+    "require 'google/protobuf'\n\n");
+
+  for (int i = 0; i < file->dependency_count(); i++) {
+    if (!MaybeEmitDependency(file->dependency(i), file, printer, error)) {
+      return false;
+    }
+  }
+
+  printer->Print(
+    "Google::Protobuf::DescriptorPool.generated_pool.build do\n");
+  printer->Indent();
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateMessage(file->message_type(i), printer);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnum(file->enum_type(i), printer);
+  }
+  printer->Outdent();
+  printer->Print(
+    "end\n\n");
+
+  int levels = GeneratePackageModules(file->package(), printer);
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateMessageAssignment("", file->message_type(i), printer);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnumAssignment("", file->enum_type(i), printer);
+  }
+  EndPackageModules(levels, printer);
+  return true;
+}
+
+bool Generator::Generate(
+    const FileDescriptor* file,
+    const string& parameter,
+    GeneratorContext* generator_context,
+    string* error) const {
+
+  if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+    *error =
+        "Can only generate Ruby code for proto3 .proto files.\n"
+        "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
+    return false;
+  }
+
+  scoped_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(GetOutputFilename(file->name())));
+  io::Printer printer(output.get(), '$');
+
+  return GenerateFile(file, &printer, error);
+}
+
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.h b/src/google/protobuf/compiler/ruby/ruby_generator.h
new file mode 100644
index 0000000..75555c3
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+
+class LIBPROTOC_EXPORT Generator
+    : public google::protobuf::compiler::CodeGenerator {
+  virtual bool Generate(
+      const FileDescriptor* file,
+      const string& parameter,
+      GeneratorContext* generator_context,
+      string* error) const;
+};
+
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_RUBY_GENERATOR_H__
+
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
new file mode 100644
index 0000000..1b04cb3
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#include <memory>
+
+#include <google/protobuf/compiler/ruby/ruby_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/printer.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/testing/file.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace ruby {
+namespace {
+
+string FindRubyTestDir(const string& file) {
+  // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+  string prefix = ".";
+  while (!File::Exists(prefix + "/src/google/protobuf/compiler/ruby" + file)) {
+    if (!File::Exists(prefix)) {
+      GOOGLE_LOG(FATAL)
+          << "Could not find Ruby test directory. Please run tests from "
+             "somewhere within the protobuf source package.";
+    }
+    prefix += "/..";
+  }
+  return prefix + "/src/google/protobuf/compiler/ruby";
+#else
+  return "third_party/protobuf/src/google/protobuf/compiler/ruby";
+#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
+}
+
+// This test is a simple golden-file test over the output of the Ruby code
+// generator. When we make changes to the Ruby extension and alter the Ruby code
+// generator to use those changes, we should (i) manually test the output of the
+// code generator with the extension, and (ii) update the golden output above.
+// Some day, we may integrate build systems between protoc and the language
+// extensions to the point where we can do this test in a more automated way.
+
+TEST(RubyGeneratorTest, GeneratorTest) {
+  string ruby_tests = FindRubyTestDir("/ruby_generated_code.proto");
+
+  google::protobuf::compiler::CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+
+  ruby::Generator ruby_generator;
+  cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+  // Copy generated_code.proto to the temporary test directory.
+  string test_input;
+  GOOGLE_CHECK_OK(File::GetContents(
+      ruby_tests + "/ruby_generated_code.proto",
+      &test_input,
+      true));
+  GOOGLE_CHECK_OK(File::SetContents(
+      TestTempDir() + "/ruby_generated_code.proto",
+      test_input,
+      true));
+
+  // Invoke the proto compiler (we will be inside TestTempDir() at this point).
+  string ruby_out = "--ruby_out=" + TestTempDir();
+  string proto_path = "--proto_path=" + TestTempDir();
+  const char* argv[] = {
+    "protoc",
+    ruby_out.c_str(),
+    proto_path.c_str(),
+    "ruby_generated_code.proto",
+  };
+
+  EXPECT_EQ(0, cli.Run(4, argv));
+
+  // Load the generated output and compare to the expected result.
+  string output;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestTempDir() + "/ruby_generated_code.rb",
+      &output,
+      true));
+  string expected_output;
+  GOOGLE_CHECK_OK(File::GetContents(
+      ruby_tests + "/ruby_generated_code.rb",
+      &expected_output,
+      true));
+  EXPECT_EQ(expected_output, output);
+}
+
+}  // namespace
+}  // namespace ruby
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 61ae438..6e25866 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -42,10 +42,12 @@
 #include <signal.h>
 #endif
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/stubs/substitute.h>
 
+
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -171,7 +173,7 @@
     DWORD wait_result =
         WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
 
-    HANDLE signaled_handle;
+    HANDLE signaled_handle = NULL;
     if (wait_result >= WAIT_OBJECT_0 &&
         wait_result < WAIT_OBJECT_0 + handle_count) {
       signaled_handle = handles[wait_result - WAIT_OBJECT_0];
@@ -359,7 +361,7 @@
   string output_data;
 
   int input_pos = 0;
-  int max_fd = max(child_stdin_, child_stdout_);
+  int max_fd = std::max(child_stdin_, child_stdout_);
 
   while (child_stdout_ != -1) {
     fd_set read_fds;
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 21dda59..56e11fa 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -34,6 +34,10 @@
 
 #include <google/protobuf/stubs/hash.h>
 #include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <set>
 #include <string>
 #include <vector>
@@ -53,7 +57,10 @@
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/map_util.h>
@@ -134,9 +141,22 @@
   "repeated",  // LABEL_REPEATED
 };
 
+const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) {
+  switch (syntax) {
+    case SYNTAX_PROTO2:
+      return "proto2";
+    case SYNTAX_PROTO3:
+      return "proto3";
+    case SYNTAX_UNKNOWN:
+      return "unknown";
+  }
+  GOOGLE_LOG(FATAL) << "can't reach here.";
+  return NULL;
+}
+
 static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
 
-#ifndef _MSC_VER  // MSVC doesn't need these and won't even accept them.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldDescriptor::kMaxNumber;
 const int FieldDescriptor::kFirstReservedNumber;
 const int FieldDescriptor::kLastReservedNumber;
@@ -144,8 +164,8 @@
 
 namespace {
 
-string ToCamelCase(const string& input) {
-  bool capitalize_next = false;
+string ToCamelCase(const string& input, bool lower_first) {
+  bool capitalize_next = !lower_first;
   string result;
   result.reserve(input.size());
 
@@ -166,8 +186,8 @@
   }
 
   // Lower-case the first letter.
-  if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') {
-    result[0] = result[0] - 'A' + 'a';
+  if (lower_first && !result.empty() && 'A' <= result[0] && result[0] <= 'Z') {
+      result[0] = result[0] - 'A' + 'a';
   }
 
   return result;
@@ -327,6 +347,43 @@
 typedef map<DescriptorIntPair, const FieldDescriptor*>
   ExtensionsGroupedByDescriptorMap;
 typedef hash_map<string, const SourceCodeInfo_Location*> LocationsByPathMap;
+
+set<string>* allowed_proto3_extendees_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_);
+
+void DeleteAllowedProto3Extendee() {
+  delete allowed_proto3_extendees_;
+}
+
+void InitAllowedProto3Extendee() {
+  allowed_proto3_extendees_ = new set<string>;
+  const char* kOptionNames[] = {
+      "FileOptions",      "MessageOptions", "FieldOptions", "EnumOptions",
+      "EnumValueOptions", "ServiceOptions", "MethodOptions"};
+  for (int i = 0; i < GOOGLE_ARRAYSIZE(kOptionNames); ++i) {
+    // descriptor.proto has a different package name in opensource. We allow
+    // both so the opensource protocol compiler can also compile internal
+    // proto3 files with custom options. See: b/27567912
+    allowed_proto3_extendees_->insert(string("google.protobuf.") +
+                                      kOptionNames[i]);
+    // Split the word to trick the opensource processing scripts so they
+    // will keep the origial package name.
+    allowed_proto3_extendees_->insert(string("proto") + "2." + kOptionNames[i]);
+  }
+
+  google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee);
+}
+
+// Checks whether the extendee type is allowed in proto3.
+// Only extensions to descriptor options are allowed. We use name comparison
+// instead of comparing the descriptor directly because the extensions may be
+// defined in a different pool.
+bool AllowedExtendeeInProto3(const string& name) {
+  ::google::protobuf::GoogleOnceInit(&allowed_proto3_extendees_init_, &InitAllowedProto3Extendee);
+  return allowed_proto3_extendees_->find(name) !=
+         allowed_proto3_extendees_->end();
+}
+
 }  // anonymous namespace
 
 // ===================================================================
@@ -510,7 +567,7 @@
   ~FileDescriptorTables();
 
   // Empty table, used with placeholder files.
-  static const FileDescriptorTables kEmpty;
+  inline static const FileDescriptorTables& GetEmptyInstance();
 
   // -----------------------------------------------------------------
   // Finding items.
@@ -532,6 +589,9 @@
     const void* parent, const string& camelcase_name) const;
   inline const EnumValueDescriptor* FindEnumValueByNumber(
     const EnumDescriptor* parent, int number) const;
+  // This creates a new EnumValueDescriptor if not found, in a thread-safe way.
+  inline const EnumValueDescriptor* FindEnumValueByNumberCreatingIfUnknown(
+      const EnumDescriptor* parent, int number) const;
 
   // -----------------------------------------------------------------
   // Adding items.
@@ -567,10 +627,16 @@
   FieldsByNameMap       fields_by_camelcase_name_;
   FieldsByNumberMap     fields_by_number_;       // Not including extensions.
   EnumValuesByNumberMap enum_values_by_number_;
+  mutable EnumValuesByNumberMap unknown_enum_values_by_number_
+      GOOGLE_GUARDED_BY(unknown_enum_values_mu_);
 
   // Populated on first request to save space, hence constness games.
   mutable GoogleOnceDynamic locations_by_path_once_;
   mutable LocationsByPathMap locations_by_path_;
+
+  // Mutex to protect the unknown-enum-value map due to dynamic
+  // EnumValueDescriptor creation on unknown values.
+  mutable Mutex unknown_enum_values_mu_;
 };
 
 DescriptorPool::Tables::Tables()
@@ -600,12 +666,38 @@
       fields_by_lowercase_name_(3),
       fields_by_camelcase_name_(3),
       fields_by_number_(3),
-      enum_values_by_number_(3) {
+      enum_values_by_number_(3),
+      unknown_enum_values_by_number_(3) {
 }
 
 FileDescriptorTables::~FileDescriptorTables() {}
 
-const FileDescriptorTables FileDescriptorTables::kEmpty;
+namespace {
+
+FileDescriptorTables* file_descriptor_tables_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_);
+
+void DeleteFileDescriptorTables() {
+  delete file_descriptor_tables_;
+  file_descriptor_tables_ = NULL;
+}
+
+void InitFileDescriptorTables() {
+  file_descriptor_tables_ = new FileDescriptorTables();
+  internal::OnShutdown(&DeleteFileDescriptorTables);
+}
+
+inline void InitFileDescriptorTablesOnce() {
+  ::google::protobuf::GoogleOnceInit(
+      &file_descriptor_tables_once_init_, &InitFileDescriptorTables);
+}
+
+}  // anonymous namespace
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+  InitFileDescriptorTablesOnce();
+  return *file_descriptor_tables_;
+}
 
 void DescriptorPool::Tables::AddCheckpoint() {
   checkpoints_.push_back(CheckPoint(this));
@@ -729,7 +821,7 @@
 
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
     const Descriptor* parent, int number) const {
-  return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
+  return FindPtrOrNull(fields_by_number_, std::make_pair(parent, number));
 }
 
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
@@ -746,18 +838,71 @@
 
 inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
     const EnumDescriptor* parent, int number) const {
-  return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
+  return FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
 }
 
+inline const EnumValueDescriptor*
+FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
+    const EnumDescriptor* parent, int number) const {
+  // First try, with map of compiled-in values.
+  {
+    const EnumValueDescriptor* desc =
+        FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
+    if (desc != NULL) {
+      return desc;
+    }
+  }
+  // Second try, with reader lock held on unknown enum values: common case.
+  {
+    ReaderMutexLock l(&unknown_enum_values_mu_);
+    const EnumValueDescriptor* desc = FindPtrOrNull(
+        unknown_enum_values_by_number_, std::make_pair(parent, number));
+    if (desc != NULL) {
+      return desc;
+    }
+  }
+  // If not found, try again with writer lock held, and create new descriptor if
+  // necessary.
+  {
+    WriterMutexLock l(&unknown_enum_values_mu_);
+    const EnumValueDescriptor* desc = FindPtrOrNull(
+        unknown_enum_values_by_number_, std::make_pair(parent, number));
+    if (desc != NULL) {
+      return desc;
+    }
+
+    // Create an EnumValueDescriptor dynamically. We don't insert it into the
+    // EnumDescriptor (it's not a part of the enum as originally defined), but
+    // we do insert it into the table so that we can return the same pointer
+    // later.
+    string enum_value_name = StringPrintf(
+        "UNKNOWN_ENUM_VALUE_%s_%d", parent->name().c_str(), number);
+    DescriptorPool::Tables* tables =
+        const_cast<DescriptorPool::Tables*>(DescriptorPool::generated_pool()->
+                                            tables_.get());
+    EnumValueDescriptor* result = tables->Allocate<EnumValueDescriptor>();
+    result->name_ = tables->AllocateString(enum_value_name);
+    result->full_name_ = tables->AllocateString(parent->full_name() +
+                                                "." + enum_value_name);
+    result->number_ = number;
+    result->type_ = parent;
+    result->options_ = &EnumValueOptions::default_instance();
+    InsertIfNotPresent(&unknown_enum_values_by_number_,
+                       std::make_pair(parent, number), result);
+    return result;
+  }
+}
+
+
 inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
     const Descriptor* extendee, int number) {
-  return FindPtrOrNull(extensions_, make_pair(extendee, number));
+  return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
 }
 
 inline void DescriptorPool::Tables::FindAllExtensions(
     const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
   ExtensionsGroupedByDescriptorMap::const_iterator it =
-      extensions_.lower_bound(make_pair(extendee, 0));
+      extensions_.lower_bound(std::make_pair(extendee, 0));
   for (; it != extensions_.end() && it->first.first == extendee; ++it) {
     out->push_back(it->second);
   }
@@ -885,7 +1030,7 @@
 const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
     const vector<int>& path, const SourceCodeInfo* info) const {
   pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
-      make_pair(this, info));
+      std::make_pair(this, info));
   locations_by_path_once_.Init(&FileDescriptorTables::BuildLocationsByPath, &p);
   return FindPtrOrNull(locations_by_path_, Join(path, ","));
 }
@@ -985,6 +1130,7 @@
   return generated_pool_;
 }
 
+
 DescriptorPool* DescriptorPool::internal_generated_pool() {
   InitGeneratedPoolOnce();
   return generated_pool_;
@@ -1311,6 +1457,11 @@
   return file()->tables_->FindEnumValueByNumber(this, key);
 }
 
+const EnumValueDescriptor*
+EnumDescriptor::FindValueByNumberCreatingIfUnknown(int key) const {
+  return file()->tables_->FindEnumValueByNumberCreatingIfUnknown(this, key);
+}
+
 const MethodDescriptor*
 ServiceDescriptor::FindMethodByName(const string& key) const {
   Symbol result =
@@ -1406,6 +1557,18 @@
   return NULL;
 }
 
+const Descriptor::ReservedRange*
+Descriptor::FindReservedRangeContainingNumber(int number) const {
+  // TODO(chrisn): Consider a non-linear search.
+  for (int i = 0; i < reserved_range_count(); i++) {
+    if (number >= reserved_range(i)->start &&
+        number <  reserved_range(i)->end) {
+      return reserved_range(i);
+    }
+  }
+  return NULL;
+}
+
 // -------------------------------------------------------------------
 
 bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
@@ -1511,6 +1674,10 @@
 
 // ===================================================================
 
+bool FieldDescriptor::is_map() const {
+  return type() == TYPE_MESSAGE && message_type()->options().map_entry();
+}
+
 string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const {
   GOOGLE_CHECK(has_default_value()) << "No default value";
   switch (cpp_type()) {
@@ -1562,6 +1729,8 @@
 void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
   proto->set_name(name());
   if (!package().empty()) proto->set_package(package());
+  // TODO(liujisi): Also populate when syntax="proto2".
+  if (syntax() == SYNTAX_PROTO3) proto->set_syntax(SyntaxName(syntax()));
 
   for (int i = 0; i < dependency_count(); i++) {
     proto->add_dependency(dependency(i)->name());
@@ -1593,8 +1762,23 @@
   }
 }
 
+void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const {
+  if (message_type_count() != proto->message_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < message_type_count(); i++) {
+    message_type(i)->CopyJsonNameTo(proto->mutable_message_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
 void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
-  if (source_code_info_ != &SourceCodeInfo::default_instance()) {
+  if (source_code_info_ &&
+      source_code_info_ != &SourceCodeInfo::default_instance()) {
     proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
   }
 }
@@ -1622,15 +1806,44 @@
   for (int i = 0; i < extension_count(); i++) {
     extension(i)->CopyTo(proto->add_extension());
   }
+  for (int i = 0; i < reserved_range_count(); i++) {
+    DescriptorProto::ReservedRange* range = proto->add_reserved_range();
+    range->set_start(reserved_range(i)->start);
+    range->set_end(reserved_range(i)->end);
+  }
+  for (int i = 0; i < reserved_name_count(); i++) {
+    proto->add_reserved_name(reserved_name(i));
+  }
 
   if (&options() != &MessageOptions::default_instance()) {
     proto->mutable_options()->CopyFrom(options());
   }
 }
 
+void Descriptor::CopyJsonNameTo(DescriptorProto* proto) const {
+  if (field_count() != proto->field_size() ||
+      nested_type_count() != proto->nested_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < field_count(); i++) {
+    field(i)->CopyJsonNameTo(proto->mutable_field(i));
+  }
+  for (int i = 0; i < nested_type_count(); i++) {
+    nested_type(i)->CopyJsonNameTo(proto->mutable_nested_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
 void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
   proto->set_name(name());
   proto->set_number(number());
+  if (has_json_name_) {
+    proto->set_json_name(json_name());
+  }
 
   // Some compilers do not allow static_cast directly between two enum types,
   // so we must cast to int first.
@@ -1677,6 +1890,10 @@
   }
 }
 
+void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
+  proto->set_json_name(json_name());
+}
+
 void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
   proto->set_name(name());
 }
@@ -1730,6 +1947,13 @@
   if (&options() != &MethodOptions::default_instance()) {
     proto->mutable_options()->CopyFrom(options());
   }
+
+  if (client_streaming_) {
+    proto->set_client_streaming(true);
+  }
+  if (server_streaming_) {
+    proto->set_server_streaming(true);
+  }
 }
 
 // DebugString methods ===============================================
@@ -1802,10 +2026,93 @@
   return !all_options.empty();
 }
 
+class SourceLocationCommentPrinter {
+ public:
+  template<typename DescType>
+  SourceLocationCommentPrinter(const DescType* desc,
+                               const string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ = options.include_comments &&
+        desc->GetSourceLocation(&source_loc_);
+  }
+  SourceLocationCommentPrinter(const FileDescriptor* file,
+                               const vector<int>& path,
+                               const string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ = options.include_comments &&
+        file->GetSourceLocation(path, &source_loc_);
+  }
+  void AddPreComment(string* output) {
+    if (have_source_loc_) {
+      // Detached leading comments.
+      for (int i = 0 ; i < source_loc_.leading_detached_comments.size(); ++i) {
+        *output += FormatComment(source_loc_.leading_detached_comments[i]);
+        *output += "\n";
+      }
+      // Attached leading comments.
+      if (!source_loc_.leading_comments.empty()) {
+        *output += FormatComment(source_loc_.leading_comments);
+      }
+    }
+  }
+  void AddPostComment(string* output) {
+    if (have_source_loc_ && source_loc_.trailing_comments.size() > 0) {
+      *output += FormatComment(source_loc_.trailing_comments);
+    }
+  }
+
+  // Format comment such that each line becomes a full-line C++-style comment in
+  // the DebugString() output.
+  string FormatComment(const string& comment_text) {
+    string stripped_comment = comment_text;
+    StripWhitespace(&stripped_comment);
+    vector<string> lines = Split(stripped_comment, "\n");
+    string output;
+    for (int i = 0; i < lines.size(); ++i) {
+      const string& line = lines[i];
+      strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line);
+    }
+    return output;
+  }
+
+ private:
+
+  bool have_source_loc_;
+  SourceLocation source_loc_;
+  DebugStringOptions options_;
+  string prefix_;
+};
+
 }  // anonymous namespace
 
 string FileDescriptor::DebugString() const {
-  string contents = "syntax = \"proto2\";\n\n";
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+string FileDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
+  string contents;
+  {
+    vector<int> path;
+    path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
+    SourceLocationCommentPrinter syntax_comment(
+        this, path, "", debug_string_options);
+    syntax_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
+                                 SyntaxName(syntax()));
+    syntax_comment.AddPostComment(&contents);
+  }
+
+  SourceLocationCommentPrinter
+      comment_printer(this, "", debug_string_options);
+  comment_printer.AddPreComment(&contents);
 
   set<int> public_dependencies;
   set<int> weak_dependencies;
@@ -1828,7 +2135,13 @@
   }
 
   if (!package().empty()) {
+    vector<int> path;
+    path.push_back(FileDescriptorProto::kPackageFieldNumber);
+    SourceLocationCommentPrinter package_comment(
+        this, path, "", debug_string_options);
+    package_comment.AddPreComment(&contents);
     strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+    package_comment.AddPostComment(&contents);
   }
 
   if (FormatLineOptions(0, options(), &contents)) {
@@ -1836,7 +2149,7 @@
   }
 
   for (int i = 0; i < enum_type_count(); i++) {
-    enum_type(i)->DebugString(0, &contents);
+    enum_type(i)->DebugString(0, &contents, debug_string_options);
     contents.append("\n");
   }
 
@@ -1851,15 +2164,14 @@
 
   for (int i = 0; i < message_type_count(); i++) {
     if (groups.count(message_type(i)) == 0) {
-      strings::SubstituteAndAppend(&contents, "message $0",
-                                   message_type(i)->name());
-      message_type(i)->DebugString(0, &contents);
+      message_type(i)->DebugString(0, &contents, debug_string_options,
+                                   /* include_opening_clause */ true);
       contents.append("\n");
     }
   }
 
   for (int i = 0; i < service_count(); i++) {
-    service(i)->DebugString(&contents);
+    service(i)->DebugString(&contents, debug_string_options);
     contents.append("\n");
   }
 
@@ -1871,23 +2183,46 @@
       strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
                                    containing_type->full_name());
     }
-    extension(i)->DebugString(1, FieldDescriptor::PRINT_LABEL, &contents);
+    extension(i)->DebugString(1, FieldDescriptor::PRINT_LABEL, &contents,
+                              debug_string_options);
   }
   if (extension_count() > 0) contents.append("}\n\n");
 
+  comment_printer.AddPostComment(&contents);
+
   return contents;
 }
 
 string Descriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+string Descriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  strings::SubstituteAndAppend(&contents, "message $0", name());
-  DebugString(0, &contents);
+  DebugString(0, &contents, options, /* include_opening_clause */ true);
   return contents;
 }
 
-void Descriptor::DebugString(int depth, string *contents) const {
+void Descriptor::DebugString(int depth, string *contents,
+                             const DebugStringOptions&
+                             debug_string_options,
+                             bool include_opening_clause) const {
+  if (options().map_entry()) {
+    // Do not generate debug string for auto-generated map-entry type.
+    return;
+  }
   string prefix(depth * 2, ' ');
   ++depth;
+
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  if (include_opening_clause) {
+    strings::SubstituteAndAppend(contents, "$0message $1", prefix, name());
+  }
   contents->append(" {\n");
 
   FormatLineOptions(depth, options(), contents);
@@ -1909,20 +2244,21 @@
 
   for (int i = 0; i < nested_type_count(); i++) {
     if (groups.count(nested_type(i)) == 0) {
-      strings::SubstituteAndAppend(contents, "$0  message $1",
-                                   prefix, nested_type(i)->name());
-      nested_type(i)->DebugString(depth, contents);
+      nested_type(i)->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ true);
     }
   }
   for (int i = 0; i < enum_type_count(); i++) {
-    enum_type(i)->DebugString(depth, contents);
+    enum_type(i)->DebugString(depth, contents, debug_string_options);
   }
   for (int i = 0; i < field_count(); i++) {
     if (field(i)->containing_oneof() == NULL) {
-      field(i)->DebugString(depth, FieldDescriptor::PRINT_LABEL, contents);
+      field(i)->DebugString(depth, FieldDescriptor::PRINT_LABEL, contents,
+                            debug_string_options);
     } else if (field(i)->containing_oneof()->field(0) == field(i)) {
       // This is the first field in this oneof, so print the whole oneof.
-      field(i)->containing_oneof()->DebugString(depth, contents);
+      field(i)->containing_oneof()->DebugString(depth, contents,
+                                                debug_string_options);
     }
   }
 
@@ -1943,15 +2279,46 @@
                                    prefix, containing_type->full_name());
     }
     extension(i)->DebugString(
-        depth + 1, FieldDescriptor::PRINT_LABEL, contents);
+        depth + 1, FieldDescriptor::PRINT_LABEL, contents,
+        debug_string_options);
   }
   if (extension_count() > 0)
     strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
 
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const Descriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start + 1) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else {
+        strings::SubstituteAndAppend(contents, "$0 to $1, ",
+                                     range->start, range->end - 1);
+      }
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  if (reserved_name_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_name_count(); i++) {
+      strings::SubstituteAndAppend(contents, "\"$0\", ",
+                                   CEscape(reserved_name(i)));
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
   strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+  comment_printer.AddPostComment(contents);
 }
 
 string FieldDescriptor::DebugString() const {
+  DebugStringOptions options;  // default options
+  return DebugStringWithOptions(options);
+}
+
+string FieldDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& debug_string_options) const {
   string contents;
   int depth = 0;
   if (is_extension()) {
@@ -1959,35 +2326,53 @@
                                  containing_type()->full_name());
     depth = 1;
   }
-  DebugString(depth, PRINT_LABEL, &contents);
+  DebugString(depth, PRINT_LABEL, &contents, debug_string_options);
   if (is_extension()) {
     contents.append("}\n");
   }
   return contents;
 }
 
+// The field type string used in FieldDescriptor::DebugString()
+string FieldDescriptor::FieldTypeNameDebugString() const {
+  switch(type()) {
+    case TYPE_MESSAGE:
+      return "." + message_type()->full_name();
+    case TYPE_ENUM:
+      return "." + enum_type()->full_name();
+    default:
+      return kTypeToName[type()];
+  }
+}
+
 void FieldDescriptor::DebugString(int depth,
                                   PrintLabelFlag print_label_flag,
-                                  string *contents) const {
+                                  string *contents,
+                                  const DebugStringOptions&
+                                  debug_string_options) const {
   string prefix(depth * 2, ' ');
   string field_type;
-  switch (type()) {
-    case TYPE_MESSAGE:
-      field_type = "." + message_type()->full_name();
-      break;
-    case TYPE_ENUM:
-      field_type = "." + enum_type()->full_name();
-      break;
-    default:
-      field_type = kTypeToName[type()];
+
+  // Special case map fields.
+  if (is_map()) {
+    strings::SubstituteAndAppend(
+        &field_type, "map<$0, $1>",
+        message_type()->field(0)->FieldTypeNameDebugString(),
+        message_type()->field(1)->FieldTypeNameDebugString());
+  } else {
+    field_type = FieldTypeNameDebugString();
   }
 
   string label;
-  if (print_label_flag == PRINT_LABEL) {
+  if (print_label_flag == PRINT_LABEL && !is_map()) {
     label = kLabelToName[this->label()];
     label.push_back(' ');
   }
 
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
+
   strings::SubstituteAndAppend(contents, "$0$1$2 $3 = $4",
                                prefix,
                                label,
@@ -2015,57 +2400,109 @@
   }
 
   if (type() == TYPE_GROUP) {
-    message_type()->DebugString(depth, contents);
+    if (debug_string_options.elide_group_body) {
+      contents->append(" { ... };\n");
+    } else {
+      message_type()->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ false);
+    }
   } else {
     contents->append(";\n");
   }
+
+  comment_printer.AddPostComment(contents);
 }
 
 string OneofDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+string OneofDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  DebugString(0, &contents);
+  DebugString(0, &contents, options);
   return contents;
 }
 
-void OneofDescriptor::DebugString(int depth, string* contents) const {
+void OneofDescriptor::DebugString(int depth, string* contents,
+                                  const DebugStringOptions&
+                                  debug_string_options) const {
   string prefix(depth * 2, ' ');
   ++depth;
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
   strings::SubstituteAndAppend(
-      contents, "$0 oneof $1 {\n", prefix, name());
-  for (int i = 0; i < field_count(); i++) {
-    field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents);
+      contents, "$0 oneof $1 {", prefix, name());
+  if (debug_string_options.elide_oneof_body) {
+    contents->append(" ... }\n");
+  } else {
+    for (int i = 0; i < field_count(); i++) {
+      field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents,
+                            debug_string_options);
+    }
+    strings::SubstituteAndAppend(contents, "$0}\n", prefix);
   }
-  strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+  comment_printer.AddPostComment(contents);
 }
 
 string EnumDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+string EnumDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  DebugString(0, &contents);
+  DebugString(0, &contents, options);
   return contents;
 }
 
-void EnumDescriptor::DebugString(int depth, string *contents) const {
+void EnumDescriptor::DebugString(int depth, string *contents,
+                                 const DebugStringOptions&
+                                 debug_string_options) const {
   string prefix(depth * 2, ' ');
   ++depth;
+
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
+
   strings::SubstituteAndAppend(contents, "$0enum $1 {\n",
                                prefix, name());
 
   FormatLineOptions(depth, options(), contents);
 
   for (int i = 0; i < value_count(); i++) {
-    value(i)->DebugString(depth, contents);
+    value(i)->DebugString(depth, contents, debug_string_options);
   }
   strings::SubstituteAndAppend(contents, "$0}\n", prefix);
+
+  comment_printer.AddPostComment(contents);
 }
 
 string EnumValueDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+string EnumValueDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  DebugString(0, &contents);
+  DebugString(0, &contents, options);
   return contents;
 }
 
-void EnumValueDescriptor::DebugString(int depth, string *contents) const {
+void EnumValueDescriptor::DebugString(int depth, string *contents,
+                                      const DebugStringOptions&
+                                      debug_string_options) const {
   string prefix(depth * 2, ' ');
+
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
+
   strings::SubstituteAndAppend(contents, "$0$1 = $2",
                                prefix, name(), number());
 
@@ -2074,39 +2511,70 @@
     strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
   }
   contents->append(";\n");
+
+  comment_printer.AddPostComment(contents);
 }
 
 string ServiceDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+string ServiceDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  DebugString(&contents);
+  DebugString(&contents, options);
   return contents;
 }
 
-void ServiceDescriptor::DebugString(string *contents) const {
+void ServiceDescriptor::DebugString(string *contents,
+                                    const DebugStringOptions&
+                                    debug_string_options) const {
+  SourceLocationCommentPrinter
+      comment_printer(this, /* prefix */ "", debug_string_options);
+  comment_printer.AddPreComment(contents);
+
   strings::SubstituteAndAppend(contents, "service $0 {\n", name());
 
   FormatLineOptions(1, options(), contents);
 
   for (int i = 0; i < method_count(); i++) {
-    method(i)->DebugString(1, contents);
+    method(i)->DebugString(1, contents, debug_string_options);
   }
 
   contents->append("}\n");
+
+  comment_printer.AddPostComment(contents);
 }
 
 string MethodDescriptor::DebugString() const {
+  DebugStringOptions options;  // default values
+  return DebugStringWithOptions(options);
+}
+
+string MethodDescriptor::DebugStringWithOptions(
+    const DebugStringOptions& options) const {
   string contents;
-  DebugString(0, &contents);
+  DebugString(0, &contents, options);
   return contents;
 }
 
-void MethodDescriptor::DebugString(int depth, string *contents) const {
+void MethodDescriptor::DebugString(int depth, string *contents,
+                                   const DebugStringOptions&
+                                   debug_string_options) const {
   string prefix(depth * 2, ' ');
   ++depth;
-  strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)",
+
+  SourceLocationCommentPrinter
+      comment_printer(this, prefix, debug_string_options);
+  comment_printer.AddPreComment(contents);
+
+  strings::SubstituteAndAppend(contents, "$0rpc $1($4.$2) returns ($5.$3)",
                                prefix, name(),
                                input_type()->full_name(),
-                               output_type()->full_name());
+                               output_type()->full_name(),
+                               client_streaming() ? "stream " : "",
+                               server_streaming() ? "stream " : "");
 
   string formatted_options;
   if (FormatLineOptions(depth, options(), &formatted_options)) {
@@ -2115,6 +2583,8 @@
   } else {
     contents->append(";\n");
   }
+
+  comment_printer.AddPostComment(contents);
 }
 
 
@@ -2135,6 +2605,9 @@
 
         out_location->leading_comments = loc->leading_comments();
         out_location->trailing_comments = loc->trailing_comments();
+        out_location->leading_detached_comments.assign(
+            loc->leading_detached_comments().begin(),
+            loc->leading_detached_comments().end());
         return true;
       }
     }
@@ -2142,8 +2615,18 @@
   return false;
 }
 
+bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const {
+  vector<int> path;  // empty path for root FileDescriptor
+  return GetSourceLocation(path, out_location);
+}
+
 bool FieldDescriptor::is_packed() const {
-  return is_packable() && (options_ != NULL) && options_->packed();
+  if (!is_packable()) return false;
+  if (file_->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+    return (options_ != NULL) && options_->packed();
+  } else {
+    return options_ == NULL || !options_->has_packed() || options_->packed();
+  }
 }
 
 bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
@@ -2256,7 +2739,7 @@
 namespace {
 
 // Represents an options message to interpret. Extension names in the option
-// name are respolved relative to name_scope. element_name and orig_opt are
+// name are resolved relative to name_scope. element_name and orig_opt are
 // used only for error reporting (since the parser records locations against
 // pointers in the original options, not the mutable copy). The Message must be
 // one of the Options messages in descriptor.proto.
@@ -2290,6 +2773,9 @@
  private:
   friend class OptionInterpreter;
 
+  // Non-recursive part of BuildFile functionality.
+  const FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto);
+
   const DescriptorPool* pool_;
   DescriptorPool::Tables* tables_;  // for convenience
   DescriptorPool::ErrorCollector* error_collector_;
@@ -2409,7 +2895,7 @@
 
   // Creates a placeholder file.  Never returns NULL.  This is used when an
   // import is not found and AllowUnknownDependencies() is enabled.
-  const FileDescriptor* NewPlaceholderFile(const string& name);
+  FileDescriptor* NewPlaceholderFile(const string& name);
 
   // Calls tables_->AddSymbol() and records an error if it fails.  Returns
   // true if successful or false if failed, though most callers can ignore
@@ -2482,6 +2968,9 @@
   void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
                            const Descriptor* parent,
                            Descriptor::ExtensionRange* result);
+  void BuildReservedRange(const DescriptorProto::ReservedRange& proto,
+                           const Descriptor* parent,
+                           Descriptor::ReservedRange* result);
   void BuildOneof(const OneofDescriptorProto& proto,
                   Descriptor* parent,
                   OneofDescriptor* result);
@@ -2498,7 +2987,8 @@
                    const ServiceDescriptor* parent,
                    MethodDescriptor* result);
 
-  void LogUnusedDependency(const FileDescriptor* result);
+  void LogUnusedDependency(const FileDescriptorProto& proto,
+                           const FileDescriptor* result);
 
   // Must be run only after building.
   //
@@ -2667,9 +3157,24 @@
                               const ServiceDescriptorProto& proto);
   void ValidateMethodOptions(MethodDescriptor* method,
                              const MethodDescriptorProto& proto);
+  void ValidateProto3(FileDescriptor* file,
+                      const FileDescriptorProto& proto);
+  void ValidateProto3Message(Descriptor* message,
+                             const DescriptorProto& proto);
+  void ValidateProto3Field(FieldDescriptor* field,
+                           const FieldDescriptorProto& proto);
+  void ValidateProto3Enum(EnumDescriptor* enm,
+                          const EnumDescriptorProto& proto);
 
-  void ValidateMapKey(FieldDescriptor* field,
-                      const FieldDescriptorProto& proto);
+  // Returns true if the map entry message is compatible with the
+  // auto-generated entry message from map fields syntax.
+  bool ValidateMapEntry(FieldDescriptor* field,
+                        const FieldDescriptorProto& proto);
+
+  // Recursively detects naming conflicts with map entry types for a
+  // better error message.
+  void DetectMapConflicts(const Descriptor* message,
+                          const DescriptorProto& proto);
 
 };
 
@@ -2992,19 +3497,9 @@
   }
 
   // Create the placeholders.
-  FileDescriptor* placeholder_file = tables_->Allocate<FileDescriptor>();
-  memset(placeholder_file, 0, sizeof(*placeholder_file));
-
-  placeholder_file->source_code_info_ = &SourceCodeInfo::default_instance();
-
-  placeholder_file->name_ =
-    tables_->AllocateString(*placeholder_full_name + ".placeholder.proto");
+  FileDescriptor* placeholder_file = NewPlaceholderFile(
+      *placeholder_full_name + ".placeholder.proto");
   placeholder_file->package_ = placeholder_package;
-  placeholder_file->pool_ = pool_;
-  placeholder_file->options_ = &FileOptions::default_instance();
-  placeholder_file->tables_ = &FileDescriptorTables::kEmpty;
-  placeholder_file->is_placeholder_ = true;
-  // All other fields are zero or NULL.
 
   if (placeholder_type == PLACEHOLDER_ENUM) {
     placeholder_file->enum_type_count_ = 1;
@@ -3068,7 +3563,7 @@
   }
 }
 
-const FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
+FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
     const string& name) {
   FileDescriptor* placeholder = tables_->Allocate<FileDescriptor>();
   memset(placeholder, 0, sizeof(*placeholder));
@@ -3077,8 +3572,10 @@
   placeholder->package_ = &internal::GetEmptyString();
   placeholder->pool_ = pool_;
   placeholder->options_ = &FileOptions::default_instance();
-  placeholder->tables_ = &FileDescriptorTables::kEmpty;
+  placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
+  placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
   placeholder->is_placeholder_ = true;
+  placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2;
   // All other fields are zero or NULL.
 
   return placeholder;
@@ -3285,6 +3782,14 @@
                                      const FileDescriptorProto& proto) {
   FileDescriptorProto existing_proto;
   existing_file->CopyTo(&existing_proto);
+  // TODO(liujisi): Remove it when CopyTo supports copying syntax params when
+  // syntax="proto2".
+  if (existing_file->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+      proto.has_syntax()) {
+    existing_proto.set_syntax(
+        existing_file->SyntaxName(existing_file->syntax()));
+  }
+
   return existing_proto.SerializeAsString() == proto.SerializeAsString();
 }
 
@@ -3296,7 +3801,7 @@
   // Note:  This only works if the input is canonical -- that is, it
   //   fully-qualifies all type names, has no UninterpretedOptions, etc.
   //   This is fine, because this idempotency "feature" really only exists to
-  //   accomodate one hack in the proto1->proto2 migration layer.
+  //   accommodate one hack in the proto1->proto2 migration layer.
   const FileDescriptor* existing_file = tables_->FindFile(filename_);
   if (existing_file != NULL) {
     // File already in pool.  Compare the existing one to the input.
@@ -3339,7 +3844,11 @@
     }
     tables_->pending_files_.pop_back();
   }
+  return BuildFileImpl(proto);
+}
 
+const FileDescriptor* DescriptorBuilder::BuildFileImpl(
+    const FileDescriptorProto& proto) {
   // Checkpoint the tables so that we can roll back if something goes wrong.
   tables_->AddCheckpoint();
 
@@ -3363,6 +3872,18 @@
              "Missing field: FileDescriptorProto.name.");
   }
 
+  // TODO(liujisi): Report error when the syntax is empty after all the protos
+  // have added the syntax statement.
+  if (proto.syntax().empty() || proto.syntax() == "proto2") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO2;
+  } else if (proto.syntax() == "proto3") {
+    file_->syntax_ = FileDescriptor::SYNTAX_PROTO3;
+  } else {
+    file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
+    AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Unrecognized syntax: " + proto.syntax());
+  }
+
   result->name_ = tables_->AllocateString(proto.name());
   if (proto.has_package()) {
     result->package_ = tables_->AllocateString(proto.package());
@@ -3506,9 +4027,17 @@
     ValidateFileOptions(result, proto);
   }
 
+  // Additional naming conflict check for map entry types. Only need to check
+  // this if there are already errors.
+  if (had_errors_) {
+    for (int i = 0; i < proto.message_type_size(); ++i) {
+      DetectMapConflicts(result->message_type(i), proto.message_type(i));
+    }
+  }
+
 
   if (!unused_dependency_.empty()) {
-    LogUnusedDependency(result);
+    LogUnusedDependency(proto, result);
   }
 
   if (had_errors_) {
@@ -3545,6 +4074,17 @@
   BUILD_ARRAY(proto, result, enum_type      , BuildEnum          , result);
   BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
   BUILD_ARRAY(proto, result, extension      , BuildExtension     , result);
+  BUILD_ARRAY(proto, result, reserved_range , BuildReservedRange , result);
+
+  // Copy reserved names.
+  int reserved_name_count = proto.reserved_name_size();
+  result->reserved_name_count_ = reserved_name_count;
+  result->reserved_names_ =
+      tables_->AllocateArray<const string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        tables_->AllocateString(proto.reserved_name(i));
+  }
 
   // Copy options.
   if (!proto.has_options()) {
@@ -3556,7 +4096,34 @@
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 
-  // Check that no fields have numbers in extension ranges.
+  for (int i = 0; i < proto.reserved_range_size(); i++) {
+    const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i);
+    for (int j = i + 1; j < proto.reserved_range_size(); j++) {
+      const DescriptorProto_ReservedRange& range2 = proto.reserved_range(j);
+      if (range1.end() > range2.start() && range2.end() > range1.start()) {
+        AddError(result->full_name(), proto.reserved_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Reserved range $0 to $1 overlaps with "
+                                     "already-defined range $2 to $3.",
+                                     range2.start(), range2.end() - 1,
+                                     range1.start(), range1.end() - 1));
+      }
+    }
+  }
+
+  hash_set<string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const string& name = proto.reserved_name(i);
+    if (reserved_name_set.find(name) == reserved_name_set.end()) {
+      reserved_name_set.insert(name);
+    } else {
+      AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute(
+                 "Field name \"$0\" is reserved multiple times.",
+                 name));
+    }
+  }
+
   for (int i = 0; i < result->field_count(); i++) {
     const FieldDescriptor* field = result->field(i);
     for (int j = 0; j < result->extension_range_count(); j++) {
@@ -3570,11 +4137,39 @@
                    field->name(), field->number()));
       }
     }
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range = result->reserved_range(j);
+      if (range->start <= field->number() && field->number() < range->end) {
+        AddError(field->full_name(), proto.reserved_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute(
+                   "Field \"$0\" uses reserved number $1.",
+                   field->name(), field->number()));
+      }
+    }
+    if (reserved_name_set.find(field->name()) != reserved_name_set.end()) {
+      AddError(field->full_name(), proto.field(i),
+               DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute(
+                 "Field name \"$0\" is reserved.", field->name()));
+    }
   }
 
-  // Check that extension ranges don't overlap.
+  // Check that extension ranges don't overlap and don't include
+  // reserved field numbers.
   for (int i = 0; i < result->extension_range_count(); i++) {
     const Descriptor::ExtensionRange* range1 = result->extension_range(i);
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range2 = result->reserved_range(j);
+      if (range1->end > range2->start && range2->end > range1->start) {
+        AddError(result->full_name(), proto.extension_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Extension range $0 to $1 overlaps with "
+                                     "reserved range $2 to $3.",
+                                     range1->start, range1->end - 1,
+                                     range2->start, range2->end - 1));
+      }
+    }
     for (int j = i + 1; j < result->extension_range_count(); j++) {
       const Descriptor::ExtensionRange* range2 = result->extension_range(j);
       if (range1->end > range2->start && range2->end > range1->start) {
@@ -3589,6 +4184,7 @@
   }
 }
 
+
 void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
                                               const Descriptor* parent,
                                               FieldDescriptor* result,
@@ -3621,7 +4217,17 @@
   // Don't bother with the above optimization for camel-case names since
   // .proto files that follow the guide shouldn't be using names in this
   // format, so the optimization wouldn't help much.
-  result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name()));
+  result->camelcase_name_ =
+      tables_->AllocateString(ToCamelCase(proto.name(),
+                                          /* lower_first = */ true));
+
+  if (proto.has_json_name()) {
+    result->has_json_name_ = true;
+    result->json_name_ = tables_->AllocateString(proto.json_name());
+  } else {
+    result->has_json_name_ = false;
+    result->json_name_ = result->camelcase_name_;
+  }
 
   // Some compilers do not allow static_cast directly between two enum types,
   // so we must cast to int first.
@@ -3646,7 +4252,6 @@
   // Some of these may be filled in when cross-linking.
   result->containing_type_ = NULL;
   result->extension_scope_ = NULL;
-  result->experimental_map_key_ = NULL;
   result->message_type_ = NULL;
   result->enum_type_ = NULL;
 
@@ -3685,8 +4290,8 @@
           } else if (proto.default_value() == "nan") {
             result->default_value_float_ = numeric_limits<float>::quiet_NaN();
           } else  {
-            result->default_value_float_ =
-              io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+            result->default_value_float_ = io::SafeDoubleToFloat(
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos));
           }
           break;
         case FieldDescriptor::CPPTYPE_DOUBLE:
@@ -3858,6 +4463,7 @@
     AllocateOptions(proto.options(), result);
   }
 
+
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 }
@@ -3886,6 +4492,19 @@
   }
 }
 
+void DescriptorBuilder::BuildReservedRange(
+    const DescriptorProto::ReservedRange& proto,
+    const Descriptor* parent,
+    Descriptor::ReservedRange* result) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    AddError(parent->full_name(), proto,
+             DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved numbers must be positive integers.");
+  }
+}
+
 void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
                                    Descriptor* parent,
                                    OneofDescriptor* result) {
@@ -4065,6 +4684,9 @@
     AllocateOptions(proto.options(), result);
   }
 
+  result->client_streaming_ = proto.client_streaming();
+  result->server_streaming_ = proto.server_streaming();
+
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 }
@@ -4124,6 +4746,23 @@
   for (int i = 0; i < message->field_count(); i++) {
     const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
     if (oneof_decl != NULL) {
+      // Make sure fields belonging to the same oneof are defined consecutively.
+      // This enables optimizations in codegens and reflection libraries to
+      // skip fields in the oneof group, as only one of the field can be set.
+      // Note that field_count() returns how many fields in this oneof we have
+      // seen so far. field_count() > 0 guarantees that i > 0, so field(i-1) is
+      // safe.
+      if (oneof_decl->field_count() > 0 &&
+          message->field(i - 1)->containing_oneof() != oneof_decl) {
+        AddError(
+            message->full_name() + "." + message->field(i - 1)->name(),
+            proto.field(i - 1), DescriptorPool::ErrorCollector::OTHER,
+            strings::Substitute(
+                "Fields in the same oneof must be defined consecutively. "
+                "\"$0\" cannot be defined before the completion of the "
+                "\"$1\" oneof definition.",
+                message->field(i - 1)->name(), oneof_decl->name()));
+      }
       // Must go through oneof_decls_ array to get a non-const version of the
       // OneofDescriptor.
       ++message->oneof_decls_[oneof_decl->index()].field_count_;
@@ -4472,8 +5111,131 @@
       }
     }
   }
+  if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    ValidateProto3(file, proto);
+  }
 }
 
+void DescriptorBuilder::ValidateProto3(
+    FileDescriptor* file, const FileDescriptorProto& proto) {
+  for (int i = 0; i < file->extension_count(); ++i) {
+    ValidateProto3Field(file->extensions_ + i, proto.extension(i));
+  }
+  for (int i = 0; i < file->message_type_count(); ++i) {
+    ValidateProto3Message(file->message_types_ + i, proto.message_type(i));
+  }
+  for (int i = 0; i < file->enum_type_count(); ++i) {
+    ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i));
+  }
+}
+
+static string ToLowercaseWithoutUnderscores(const string& name) {
+  string result;
+  for (int i = 0; i < name.size(); ++i) {
+    if (name[i] != '_') {
+      if (name[i] >= 'A' && name[i] <= 'Z') {
+        result.push_back(name[i] - 'A' + 'a');
+      } else {
+        result.push_back(name[i]);
+      }
+    }
+  }
+  return result;
+}
+
+void DescriptorBuilder::ValidateProto3Message(
+    Descriptor* message, const DescriptorProto& proto) {
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    ValidateProto3Message(message->nested_types_ + i,
+                                 proto.nested_type(i));
+  }
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    ValidateProto3Enum(message->enum_types_ + i,
+                              proto.enum_type(i));
+  }
+  for (int i = 0; i < message->field_count(); ++i) {
+    ValidateProto3Field(message->fields_ + i, proto.field(i));
+  }
+  for (int i = 0; i < message->extension_count(); ++i) {
+    ValidateProto3Field(message->extensions_ +i, proto.extension(i));
+  }
+  if (message->extension_range_count() > 0) {
+    AddError(message->full_name(), proto,
+             DescriptorPool::ErrorCollector::OTHER,
+             "Extension ranges are not allowed in proto3.");
+  }
+  if (message->options().message_set_wire_format()) {
+    // Using MessageSet doesn't make sense since we disallow extensions.
+    AddError(message->full_name(), proto,
+             DescriptorPool::ErrorCollector::OTHER,
+             "MessageSet is not supported in proto3.");
+  }
+
+  // In proto3, we reject field names if they conflict in camelCase.
+  // Note that we currently enforce a stricter rule: Field names must be
+  // unique after being converted to lowercase with underscores removed.
+  map<string, const FieldDescriptor*> name_to_field;
+  for (int i = 0; i < message->field_count(); ++i) {
+    string lowercase_name = ToLowercaseWithoutUnderscores(
+        message->field(i)->name());
+    if (name_to_field.find(lowercase_name) != name_to_field.end()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::OTHER,
+               "The JSON camcel-case name of field \"" +
+               message->field(i)->name() + "\" conflicts with field \"" +
+               name_to_field[lowercase_name]->name() + "\". This is not " +
+               "allowed in proto3.");
+    } else {
+      name_to_field[lowercase_name] = message->field(i);
+    }
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Field(
+    FieldDescriptor* field, const FieldDescriptorProto& proto) {
+  if (field->is_extension() &&
+      !AllowedExtendeeInProto3(field->containing_type()->full_name())) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::OTHER,
+             "Extensions in proto3 are only allowed for defining options.");
+  }
+  if (field->is_required()) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::OTHER,
+             "Required fields are not allowed in proto3.");
+  }
+  if (field->has_default_value()) {
+    AddError(
+        field->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
+        "Explicit default values are not allowed in proto3.");
+  }
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+      field->enum_type() &&
+      field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+    // Proto3 messages can only use Proto3 enum types; otherwise we can't
+    // guarantee that the default value is zero.
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::TYPE,
+             "Enum type \"" + field->enum_type()->full_name() +
+             "\" is not a proto3 enum, but is used in \"" +
+             field->containing_type()->full_name() +
+             "\" which is a proto3 message type.");
+  }
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::TYPE,
+             "Groups are not supported in proto3 syntax.");
+  }
+}
+
+void DescriptorBuilder::ValidateProto3Enum(
+    EnumDescriptor* enm, const EnumDescriptorProto& proto) {
+  if (enm->value_count() > 0 && enm->value(0)->number() != 0) {
+    AddError(
+        enm->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
+        "The first enum value must be zero in proto3.");
+  }
+}
 
 void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
                                                const DescriptorProto& proto) {
@@ -4499,10 +5261,6 @@
 
 void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
     const FieldDescriptorProto& proto) {
-  if (field->options().has_experimental_map_key()) {
-    ValidateMapKey(field, proto);
-  }
-
   // Only message type fields may be lazy.
   if (field->options().lazy()) {
     if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
@@ -4551,6 +5309,16 @@
              "a lite type, but the reverse is allowed.");
   }
 
+  // Validate map types.
+  if (field->is_map()) {
+    if (!ValidateMapEntry(field, proto)) {
+      AddError(field->full_name(), proto,
+               DescriptorPool::ErrorCollector::OTHER,
+               "map_entry should not be set explicitly. Use map<KeyType, "
+               "ValueType> instead.");
+    }
+  }
+
 }
 
 void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
@@ -4608,57 +5376,135 @@
   // Nothing to do so far.
 }
 
-void DescriptorBuilder::ValidateMapKey(FieldDescriptor* field,
-                                       const FieldDescriptorProto& proto) {
-  if (!field->is_repeated()) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "map type is only allowed for repeated fields.");
-    return;
+bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field,
+                                         const FieldDescriptorProto& proto) {
+  const Descriptor* message = field->message_type();
+  if (// Must not contain extensions, extension range or nested message or
+      // enums
+      message->extension_count() != 0 ||
+      field->label() != FieldDescriptor::LABEL_REPEATED ||
+      message->extension_range_count() != 0 ||
+      message->nested_type_count() != 0 || message->enum_type_count() != 0 ||
+      // Must contain exactly two fields
+      message->field_count() != 2 ||
+      // Field name and message name must match
+      message->name() != ToCamelCase(field->name(), false) + "Entry" ||
+      // Entry message must be in the same containing type of the field.
+      field->containing_type() != message->containing_type()) {
+    return false;
   }
 
-  if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "map type is only allowed for fields with a message type.");
-    return;
+  const FieldDescriptor* key = message->field(0);
+  const FieldDescriptor* value = message->field(1);
+  if (key->label() != FieldDescriptor::LABEL_OPTIONAL || key->number() != 1 ||
+      key->name() != "key") {
+    return false;
+  }
+  if (value->label() != FieldDescriptor::LABEL_OPTIONAL ||
+      value->number() != 2 || value->name() != "value") {
+    return false;
   }
 
-  const Descriptor* item_type = field->message_type();
-  if (item_type == NULL) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "Could not find field type.");
-    return;
+  // Check key types are legal.
+  switch (key->type()) {
+    case FieldDescriptor::TYPE_ENUM:
+      AddError(
+          field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+          "Key in map fields cannot be enum types.");
+      break;
+    case FieldDescriptor::TYPE_FLOAT:
+    case FieldDescriptor::TYPE_DOUBLE:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_BYTES:
+      AddError(
+          field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+          "Key in map fields cannot be float/double, bytes or message types.");
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_SFIXED64:
+      // Legal cases
+      break;
+    // Do not add a default, so that the compiler will complain when new types
+    // are added.
   }
 
-  // Find the field in item_type named by "experimental_map_key"
-  const string& key_name = field->options().experimental_map_key();
-  const Symbol key_symbol = LookupSymbol(
-      key_name,
-      // We append ".key_name" to the containing type's name since
-      // LookupSymbol() searches for peers of the supplied name, not
-      // children of the supplied name.
-      item_type->full_name() + "." + key_name);
-
-  if (key_symbol.IsNull() || key_symbol.field_descriptor->is_extension()) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "Could not find field named \"" + key_name + "\" in type \"" +
-             item_type->full_name() + "\".");
-    return;
-  }
-  const FieldDescriptor* key_field = key_symbol.field_descriptor;
-
-  if (key_field->is_repeated()) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "map_key must not name a repeated field.");
-    return;
+  if (value->type() == FieldDescriptor::TYPE_ENUM) {
+    if (value->enum_type()->value(0)->number() != 0) {
+      AddError(
+          field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
+          "Enum value in map must define 0 as the first value.");
+    }
   }
 
-  if (key_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-    AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
-             "map key must name a scalar or string field.");
-    return;
-  }
+  return true;
+}
 
-  field->experimental_map_key_ = key_field;
+void DescriptorBuilder::DetectMapConflicts(const Descriptor* message,
+                                           const DescriptorProto& proto) {
+  map<string, const Descriptor*> seen_types;
+  for (int i = 0; i < message->nested_type_count(); ++i) {
+    const Descriptor* nested = message->nested_type(i);
+    pair<map<string, const Descriptor*>::iterator, bool> result =
+        seen_types.insert(std::make_pair(nested->name(), nested));
+    if (!result.second) {
+      if (result.first->second->options().map_entry() ||
+          nested->options().map_entry()) {
+        AddError(message->full_name(), proto,
+                 DescriptorPool::ErrorCollector::NAME,
+                 "Expanded map entry type " + nested->name() +
+                 " conflicts with an existing nested message type.");
+      }
+    }
+    // Recursively test on the nested types.
+    DetectMapConflicts(message->nested_type(i), proto.nested_type(i));
+  }
+  // Check for conflicted field names.
+  for (int i = 0; i < message->field_count(); ++i) {
+    const FieldDescriptor* field = message->field(i);
+    map<string, const Descriptor*>::iterator iter =
+        seen_types.find(field->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+               " conflicts with an existing field.");
+    }
+  }
+  // Check for conflicted enum names.
+  for (int i = 0; i < message->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_desc = message->enum_type(i);
+    map<string, const Descriptor*>::iterator iter =
+        seen_types.find(enum_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+               " conflicts with an existing enum type.");
+    }
+  }
+  // Check for conflicted oneof names.
+  for (int i = 0; i < message->oneof_decl_count(); ++i) {
+    const OneofDescriptor* oneof_desc = message->oneof_decl(i);
+    map<string, const Descriptor*>::iterator iter =
+        seen_types.find(oneof_desc->name());
+    if (iter != seen_types.end() && iter->second->options().map_entry()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::NAME,
+               "Expanded map entry type " + iter->second->name() +
+               " conflicts with an existing oneof type.");
+    }
+  }
 }
 
 
@@ -4725,11 +5571,19 @@
     // UnknownFieldSet and wait there until the message is parsed by something
     // that does know about the options.
     string buf;
-    options->AppendToString(&buf);
-    GOOGLE_CHECK(options->ParseFromString(buf))
+    GOOGLE_CHECK(options->AppendPartialToString(&buf))
+        << "Protocol message could not be serialized.";
+    GOOGLE_CHECK(options->ParsePartialFromString(buf))
         << "Protocol message serialized itself in invalid fashion.";
+    if (!options->IsInitialized()) {
+      builder_->AddWarning(
+          options_to_interpret->element_name, *original_options,
+          DescriptorPool::ErrorCollector::OTHER,
+          "Options could not be fully parsed using the proto descriptors "
+          "compiled into this binary. Missing required fields: " +
+          options->InitializationErrorString());
+    }
   }
-
   return !failed;
 }
 
@@ -4878,7 +5732,7 @@
 
   // First set the value on the UnknownFieldSet corresponding to the
   // innermost message.
-  scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
+  google::protobuf::scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
   if (!SetOptionValue(field, unknown_fields.get())) {
     return false;  // SetOptionValue() already added the error.
   }
@@ -4888,7 +5742,8 @@
   for (vector<const FieldDescriptor*>::reverse_iterator iter =
            intermediate_fields.rbegin();
        iter != intermediate_fields.rend(); ++iter) {
-    scoped_ptr<UnknownFieldSet> parent_unknown_fields(new UnknownFieldSet());
+    google::protobuf::scoped_ptr<UnknownFieldSet> parent_unknown_fields(
+        new UnknownFieldSet());
     switch ((*iter)->type()) {
       case FieldDescriptor::TYPE_MESSAGE: {
         io::StringOutputStream outstr(
@@ -5274,7 +6129,7 @@
   }
 
   const Descriptor* type = option_field->message_type();
-  scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
+  google::protobuf::scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
   GOOGLE_CHECK(dynamic.get() != NULL)
       << "Could not create an instance of " << option_field->DebugString();
 
@@ -5382,7 +6237,8 @@
   }
 }
 
-void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
+                                            const FileDescriptor* result) {
 
   if (!unused_dependency_.empty()) {
     std::set<string> annotation_extensions;
@@ -5408,9 +6264,9 @@
       }
       // Log warnings for unused imported files.
       if (i == (*it)->extension_count()) {
-        GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name()
-                     << "\" imports \"" << (*it)->name()
-                     << "\" which is not used.";
+        string error_message = "Import " + (*it)->name() + " but not used.";
+        AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::OTHER,
+                   error_message);
       }
     }
   }
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index fef4780..3ecc0a9 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -54,11 +54,20 @@
 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
 #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <set>
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 
+// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
+#ifdef TYPE_BOOL
+#undef TYPE_BOOL
+#endif  // TYPE_BOOL
 
 namespace google {
 namespace protobuf {
@@ -104,6 +113,25 @@
 // Defined in unknown_field_set.h.
 class UnknownField;
 
+// Defined in generated_message_reflection.h.
+namespace internal {
+class GeneratedMessageReflection;
+}  // namespace internal
+
+// Defined in command_line_interface.cc
+namespace compiler {
+class CommandLineInterface;
+}  // namespace compiler
+
+namespace descriptor_unittest {
+class DescriptorTest;
+}  // namespace descriptor_unittest
+
+// Defined in printer.h
+namespace io {
+class Printer;
+}  // namespace io
+
 // NB, all indices are zero-based.
 struct SourceLocation {
   int start_line;
@@ -112,10 +140,28 @@
   int end_column;
 
   // Doc comments found at the source location.
-  // TODO(kenton):  Maybe this struct should have been named SourceInfo or
-  //   something instead.  Oh well.
+  // See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
   string leading_comments;
   string trailing_comments;
+  vector<string> leading_detached_comments;
+};
+
+// Options when generating machine-parsable output from a descriptor with
+// DebugString().
+struct DebugStringOptions {
+  // include original user comments as recorded in SourceLocation entries. N.B.
+  // that this must be |false| by default: several other pieces of code (for
+  // example, the C++ code generation for fields in the proto compiler) rely on
+  // DebugString() output being unobstructed by user comments.
+  bool include_comments;
+  // If true, elide the braced body in the debug string.
+  bool elide_group_body;
+  bool elide_oneof_body;
+
+  DebugStringOptions()
+      : include_comments(false),
+        elide_group_body(false),
+        elide_oneof_body(false) {}
 };
 
 // Describes a type of protocol message, or a particular group within a
@@ -162,6 +208,10 @@
   // will be suitable for re-parsing.
   string DebugString() const;
 
+  // Similar to DebugString(), but additionally takes options (e.g.,
+  // include original user comments in output).
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
   // Returns true if this is a placeholder for an unknown type. This will
   // only be the case if this descriptor comes from a DescriptorPool
   // with AllowUnknownDependencies() set.
@@ -271,6 +321,36 @@
   // this message type's scope.
   const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
 
+  // Reserved fields -------------------------------------------------
+
+  // A range of reserved field numbers.
+  struct ReservedRange {
+    int start;  // inclusive
+    int end;    // exclusive
+  };
+
+  // The number of reserved ranges in this message type.
+  int reserved_range_count() const;
+  // Gets an reserved range by index, where 0 <= index <
+  // reserved_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const ReservedRange* reserved_range(int index) const;
+
+  // Returns true if the number is in one of the reserved ranges.
+  bool IsReservedNumber(int number) const;
+
+  // Returns NULL if no reserved range contains the given number.
+  const ReservedRange* FindReservedRangeContainingNumber(int number) const;
+
+  // The number of reserved field names in this message type.
+  int reserved_name_count() const;
+
+  // Gets a reserved name by index, where 0 <= index < reserved_name_count().
+  const string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(const string& name) const;
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -281,9 +361,22 @@
  private:
   typedef MessageOptions OptionsType;
 
+  // Allows tests to test CopyTo(proto, true).
+  friend class ::google::protobuf::descriptor_unittest::DescriptorTest;
+
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(DescriptorProto* proto) const;
+
   // Internal version of DebugString; controls the level of indenting for
-  // correct depth
-  void DebugString(int depth, string *contents) const;
+  // correct depth. Takes |options| to control debug-string options, and
+  // |include_opening_clause| to indicate whether the "message ... " part of the
+  // clause has already been generated (this varies depending on context).
+  void DebugString(int depth, string *contents,
+                   const DebugStringOptions& options,
+                   bool include_opening_clause) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -312,6 +405,10 @@
   ExtensionRange* extension_ranges_;
   int extension_count_;
   FieldDescriptor* extensions_;
+  int reserved_range_count_;
+  ReservedRange* reserved_ranges_;
+  int reserved_name_count_;
+  const string** reserved_names_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
   // and update them to initialize the field.
@@ -414,6 +511,7 @@
 
   const string& name() const;        // Name of this field within the message.
   const string& full_name() const;   // Fully-qualified name of the field.
+  const string& json_name() const;   // JSON name of this field.
   const FileDescriptor* file() const;// File in which this field was defined.
   bool is_extension() const;         // Is this an extension field?
   int number() const;                // Declared tag number.
@@ -450,6 +548,8 @@
                                  //               IsTypePackable(type())
   bool is_packed() const;        // shorthand for is_packable() &&
                                  //               options().packed()
+  bool is_map() const;           // shorthand for type() == TYPE_MESSAGE &&
+                                 // message_type()->options().map_entry()
 
   // Index of this field within the message's field array, or the file or
   // extension scope's extensions array.
@@ -513,12 +613,6 @@
   // returns null.
   const EnumDescriptor* enum_type() const;
 
-  // EXPERIMENTAL; DO NOT USE.
-  // If this field is a map field, experimental_map_key() is the field
-  // that is the key for this map.
-  // experimental_map_key()->containing_type() is the same as message_type().
-  const FieldDescriptor* experimental_map_key() const;
-
   // Get the FieldOptions for this field.  This includes things listed in
   // square brackets after the field definition.  E.g., the field:
   //   optional string text = 1 [ctype=CORD];
@@ -533,6 +627,9 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
   // Helper method to get the CppType for a particular Type.
   static CppType TypeToCppType(Type type);
 
@@ -555,16 +652,25 @@
  private:
   typedef FieldOptions OptionsType;
 
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(FieldDescriptorProto* proto) const;
+
   // See Descriptor::DebugString().
   enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL };
   void DebugString(int depth, PrintLabelFlag print_label_flag,
-                   string* contents) const;
+                   string* contents, const DebugStringOptions& options) const;
 
   // formats the default value appropriately and returns it as a string.
   // Must have a default value to call this. If quote_string_type is true, then
   // types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped.
   string DefaultValueAsString(bool quote_string_type) const;
 
+  // Helper function that returns the field type name for DebugString.
+  string FieldTypeNameDebugString() const;
+
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   void GetLocationPath(std::vector<int>* output) const;
@@ -573,6 +679,12 @@
   const string* full_name_;
   const string* lowercase_name_;
   const string* camelcase_name_;
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name_;
+  // If has_json_name_ is true, it's the value specified by the user.
+  // Otherwise, it has the same value as lowercase_name_.
+  const string* json_name_;
   const FileDescriptor* file_;
   int number_;
   Type type_;
@@ -584,7 +696,6 @@
   const Descriptor* extension_scope_;
   const Descriptor* message_type_;
   const EnumDescriptor* enum_type_;
-  const FieldDescriptor* experimental_map_key_;
   const FieldOptions* options_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
@@ -645,6 +756,9 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -653,8 +767,12 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
   // See Descriptor::DebugString().
-  void DebugString(int depth, string* contents) const;
+  void DebugString(int depth, string* contents,
+                   const DebugStringOptions& options) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -723,6 +841,10 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+
   // Returns true if this is a placeholder for an unknown enum. This will
   // only be the case if this descriptor comes from a DescriptorPool
   // with AllowUnknownDependencies() set.
@@ -738,8 +860,24 @@
  private:
   typedef EnumOptions OptionsType;
 
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
+  // Looks up a value by number.  If the value does not exist, dynamically
+  // creates a new EnumValueDescriptor for that value, assuming that it was
+  // unknown. If a new descriptor is created, this is done in a thread-safe way,
+  // and future calls will return the same value descriptor pointer.
+  //
+  // This is private but is used by GeneratedMessageReflection (which is
+  // friended below) to return a valid EnumValueDescriptor from GetEnum() when
+  // this feature is enabled.
+  const EnumValueDescriptor*
+      FindValueByNumberCreatingIfUnknown(int number) const;
+
+
   // See Descriptor::DebugString().
-  void DebugString(int depth, string *contents) const;
+  void DebugString(int depth, string *contents,
+                   const DebugStringOptions& options) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -769,6 +907,7 @@
   friend class FieldDescriptor;
   friend class EnumValueDescriptor;
   friend class FileDescriptor;
+  friend class internal::GeneratedMessageReflection;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
 };
 
@@ -806,6 +945,10 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -816,8 +959,12 @@
  private:
   typedef EnumValueOptions OptionsType;
 
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
   // See Descriptor::DebugString().
-  void DebugString(int depth, string *contents) const;
+  void DebugString(int depth, string *contents,
+                   const DebugStringOptions& options) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -836,6 +983,7 @@
   EnumValueDescriptor() {}
   friend class DescriptorBuilder;
   friend class EnumDescriptor;
+  friend class FileDescriptorTables;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
 };
 
@@ -876,6 +1024,10 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -886,8 +1038,11 @@
  private:
   typedef ServiceOptions OptionsType;
 
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
   // See Descriptor::DebugString().
-  void DebugString(string *contents) const;
+  void DebugString(string *contents, const DebugStringOptions& options) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -932,6 +1087,11 @@
   // Gets the type of protocol message which this message produces as output.
   const Descriptor* output_type() const;
 
+  // Gets whether the client streams multiple requests.
+  bool client_streaming() const;
+  // Gets whether the server streams multiple responses.
+  bool server_streaming() const;
+
   // Get options for this method.  These are specified in the .proto file by
   // placing lines like "option foo = 1234;" in curly-braces after a method
   // declaration.  Allowed options are defined by MethodOptions in
@@ -945,6 +1105,10 @@
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -955,8 +1119,12 @@
  private:
   typedef MethodOptions OptionsType;
 
+  // Allows access to GetLocationPath for annotations.
+  friend class ::google::protobuf::io::Printer;
+
   // See Descriptor::DebugString().
-  void DebugString(int depth, string *contents) const;
+  void DebugString(int depth, string *contents,
+                   const DebugStringOptions& options) const;
 
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
@@ -968,6 +1136,8 @@
   const Descriptor* input_type_;
   const Descriptor* output_type_;
   const MethodOptions* options_;
+  bool client_streaming_;
+  bool server_streaming_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in
   // descriptor.cc and update them to initialize the field.
@@ -1052,6 +1222,15 @@
   // message.
   const FileOptions& options() const;
 
+  // Syntax of this file.
+  enum Syntax {
+    SYNTAX_UNKNOWN = 0,
+    SYNTAX_PROTO2  = 2,
+    SYNTAX_PROTO3  = 3,
+  };
+  Syntax syntax() const;
+  static const char* SyntaxName(Syntax syntax);
+
   // Find a top-level message type by name.  Returns NULL if not found.
   const Descriptor* FindMessageTypeByName(const string& name) const;
   // Find a top-level enum type by name.  Returns NULL if not found.
@@ -1078,17 +1257,24 @@
   // Write the source code information of this FileDescriptor into the given
   // FileDescriptorProto.  See CopyTo() above.
   void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
+  // Fill the json_name field of FieldDescriptorProto for all fields. Can only
+  // be called after CopyTo().
+  void CopyJsonNameTo(FileDescriptorProto* proto) const;
 
   // See Descriptor::DebugString().
   string DebugString() const;
 
+  // See Descriptor::DebugStringWithOptions().
+  string DebugStringWithOptions(const DebugStringOptions& options) const;
+
   // Returns true if this is a placeholder for an unknown file. This will
   // only be the case if this descriptor comes from a DescriptorPool
   // with AllowUnknownDependencies() set.
   bool is_placeholder() const;
 
- private:
-  // Source Location ---------------------------------------------------
+  // Updates |*out_location| to the source location of the complete extent of
+  // this file declaration (namely, the empty path).
+  bool GetSourceLocation(SourceLocation* out_location) const;
 
   // Updates |*out_location| to the source location of the complete
   // extent of the declaration or declaration-part denoted by |path|.
@@ -1098,6 +1284,7 @@
   bool GetSourceLocation(const std::vector<int>& path,
                          SourceLocation* out_location) const;
 
+ private:
   typedef FileOptions OptionsType;
 
   const string* name_;
@@ -1116,6 +1303,7 @@
   int service_count_;
   ServiceDescriptor* services_;
   int extension_count_;
+  Syntax syntax_;
   bool is_placeholder_;
   FieldDescriptor* extensions_;
   const FileOptions* options_;
@@ -1203,6 +1391,7 @@
   // this pool.  Do not add your own descriptors to this pool.
   static const DescriptorPool* generated_pool();
 
+
   // Find a FileDescriptor in the pool by file name.  Returns NULL if not
   // found.
   const FileDescriptor* FindFileByName(const string& name) const;
@@ -1268,7 +1457,7 @@
     };
 
     // Reports an error in the FileDescriptorProto. Use this function if the
-    // problem occured should interrupt building the FileDescriptorProto.
+    // problem occurred should interrupt building the FileDescriptorProto.
     virtual void AddError(
       const string& filename,      // File name in which the error occurred.
       const string& element_name,  // Full name of the erroneous element.
@@ -1278,7 +1467,7 @@
       ) = 0;
 
     // Reports a warning in the FileDescriptorProto. Use this function if the
-    // problem occured should NOT interrupt building the FileDescriptorProto.
+    // problem occurred should NOT interrupt building the FileDescriptorProto.
     virtual void AddWarning(
       const string& /*filename*/,      // File name in which the error occurred.
       const string& /*element_name*/,  // Full name of the erroneous element.
@@ -1394,6 +1583,7 @@
   friend class ServiceDescriptor;
   friend class FileDescriptor;
   friend class DescriptorBuilder;
+  friend class FileDescriptorTables;
 
   // Return true if the given name is a sub-symbol of any non-package
   // descriptor that already exists in the descriptor pool.  (The full
@@ -1427,7 +1617,7 @@
   // This class contains a lot of hash maps with complicated types that
   // we'd like to keep out of the header.
   class Tables;
-  scoped_ptr<Tables> tables_;
+  google::protobuf::scoped_ptr<Tables> tables_;
 
   bool enforce_dependencies_;
   bool allow_unknown_;
@@ -1475,11 +1665,18 @@
                                const Descriptor::ExtensionRange*)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension,
                                const FieldDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_range_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range,
+                               const Descriptor::ReservedRange*)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
+
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, json_name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
@@ -1494,8 +1691,6 @@
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, extension_scope, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*)
-PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key,
-                         const FieldDescriptor*)
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 )
@@ -1521,7 +1716,7 @@
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
                                const EnumValueDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
@@ -1536,14 +1731,17 @@
 PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
                                const MethodDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
+PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
+
 PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
@@ -1554,7 +1752,7 @@
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
@@ -1574,6 +1772,25 @@
   return FindExtensionRangeContainingNumber(number) != NULL;
 }
 
+inline bool Descriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != NULL;
+}
+
+inline bool Descriptor::IsReservedName(const string& name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == reserved_name(i)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because reserved_names_ is actually
+// an array of pointers rather than the usual array of objects.
+inline const string& Descriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
 inline bool FieldDescriptor::is_required() const {
   return label() == LABEL_REQUIRED;
 }
@@ -1679,6 +1896,10 @@
   return dependencies_[weak_dependencies_[index]];
 }
 
+inline FileDescriptor::Syntax FileDescriptor::syntax() const {
+  return syntax_;
+}
+
 // Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because fields_ is actually an array
 // of pointers rather than the usual array of objects.
 inline const FieldDescriptor* OneofDescriptor::field(int index) const {
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 0bed03e..0c9af58 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/descriptor.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -33,6 +34,9 @@
 const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   DescriptorProto_ExtensionRange_reflection_ = NULL;
+const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DescriptorProto_ReservedRange_reflection_ = NULL;
 const ::google::protobuf::Descriptor* FieldDescriptorProto_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   FieldDescriptorProto_reflection_ = NULL;
@@ -64,6 +68,7 @@
 const ::google::protobuf::internal::GeneratedMessageReflection*
   FieldOptions_reflection_ = NULL;
 const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor_ = NULL;
 const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   EnumOptions_reflection_ = NULL;
@@ -88,6 +93,12 @@
 const ::google::protobuf::Descriptor* SourceCodeInfo_Location_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   SourceCodeInfo_Location_reflection_ = NULL;
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GeneratedCodeInfo_reflection_ = NULL;
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GeneratedCodeInfo_Annotation_reflection_ = NULL;
 
 }  // namespace
 
@@ -103,18 +114,18 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, file_),
   };
   FileDescriptorSet_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       FileDescriptorSet_descriptor_,
       FileDescriptorSet::default_instance_,
       FileDescriptorSet_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(FileDescriptorSet));
+      -1,
+      sizeof(FileDescriptorSet),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_),
+      -1);
   FileDescriptorProto_descriptor_ = file->message_type(1);
-  static const int FileDescriptorProto_offsets_[11] = {
+  static const int FileDescriptorProto_offsets_[12] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, dependency_),
@@ -126,20 +137,21 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, extension_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, options_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, source_code_info_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, syntax_),
   };
   FileDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       FileDescriptorProto_descriptor_,
       FileDescriptorProto::default_instance_,
       FileDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(FileDescriptorProto));
+      -1,
+      sizeof(FileDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_),
+      -1);
   DescriptorProto_descriptor_ = file->message_type(2);
-  static const int DescriptorProto_offsets_[8] = {
+  static const int DescriptorProto_offsets_[10] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_),
@@ -148,36 +160,54 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, oneof_decl_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_range_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_name_),
   };
   DescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       DescriptorProto_descriptor_,
       DescriptorProto::default_instance_,
       DescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(DescriptorProto));
+      -1,
+      sizeof(DescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_),
+      -1);
   DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0);
   static const int DescriptorProto_ExtensionRange_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, end_),
   };
   DescriptorProto_ExtensionRange_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       DescriptorProto_ExtensionRange_descriptor_,
       DescriptorProto_ExtensionRange::default_instance_,
       DescriptorProto_ExtensionRange_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(DescriptorProto_ExtensionRange));
+      -1,
+      sizeof(DescriptorProto_ExtensionRange),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_),
+      -1);
+  DescriptorProto_ReservedRange_descriptor_ = DescriptorProto_descriptor_->nested_type(1);
+  static const int DescriptorProto_ReservedRange_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, start_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, end_),
+  };
+  DescriptorProto_ReservedRange_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DescriptorProto_ReservedRange_descriptor_,
+      DescriptorProto_ReservedRange::default_instance_,
+      DescriptorProto_ReservedRange_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(DescriptorProto_ReservedRange),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_),
+      -1);
   FieldDescriptorProto_descriptor_ = file->message_type(3);
-  static const int FieldDescriptorProto_offsets_[9] = {
+  static const int FieldDescriptorProto_offsets_[10] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_),
@@ -186,19 +216,20 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, json_name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_),
   };
   FieldDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       FieldDescriptorProto_descriptor_,
       FieldDescriptorProto::default_instance_,
       FieldDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(FieldDescriptorProto));
+      -1,
+      sizeof(FieldDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_),
+      -1);
   FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0);
   FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1);
   OneofDescriptorProto_descriptor_ = file->message_type(4);
@@ -206,16 +237,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, name_),
   };
   OneofDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       OneofDescriptorProto_descriptor_,
       OneofDescriptorProto::default_instance_,
       OneofDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(OneofDescriptorProto));
+      -1,
+      sizeof(OneofDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_),
+      -1);
   EnumDescriptorProto_descriptor_ = file->message_type(5);
   static const int EnumDescriptorProto_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_),
@@ -223,16 +254,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, options_),
   };
   EnumDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       EnumDescriptorProto_descriptor_,
       EnumDescriptorProto::default_instance_,
       EnumDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(EnumDescriptorProto));
+      -1,
+      sizeof(EnumDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_),
+      -1);
   EnumValueDescriptorProto_descriptor_ = file->message_type(6);
   static const int EnumValueDescriptorProto_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_),
@@ -240,16 +271,16 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, options_),
   };
   EnumValueDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       EnumValueDescriptorProto_descriptor_,
       EnumValueDescriptorProto::default_instance_,
       EnumValueDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(EnumValueDescriptorProto));
+      -1,
+      sizeof(EnumValueDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_),
+      -1);
   ServiceDescriptorProto_descriptor_ = file->message_type(7);
   static const int ServiceDescriptorProto_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_),
@@ -257,36 +288,38 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, options_),
   };
   ServiceDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       ServiceDescriptorProto_descriptor_,
       ServiceDescriptorProto::default_instance_,
       ServiceDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(ServiceDescriptorProto));
+      -1,
+      sizeof(ServiceDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_),
+      -1);
   MethodDescriptorProto_descriptor_ = file->message_type(8);
-  static const int MethodDescriptorProto_offsets_[4] = {
+  static const int MethodDescriptorProto_offsets_[6] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, output_type_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, client_streaming_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, server_streaming_),
   };
   MethodDescriptorProto_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MethodDescriptorProto_descriptor_,
       MethodDescriptorProto::default_instance_,
       MethodDescriptorProto_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MethodDescriptorProto));
+      -1,
+      sizeof(MethodDescriptorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_),
+      -1);
   FileOptions_descriptor_ = file->message_type(9);
-  static const int FileOptions_offsets_[13] = {
+  static const int FileOptions_offsets_[15] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_),
@@ -298,61 +331,65 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, deprecated_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, javanano_use_deprecated_package_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, csharp_namespace_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_),
   };
   FileOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       FileOptions_descriptor_,
       FileOptions::default_instance_,
       FileOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(FileOptions));
+      sizeof(FileOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_),
+      -1);
   FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0);
   MessageOptions_descriptor_ = file->message_type(10);
-  static const int MessageOptions_offsets_[4] = {
+  static const int MessageOptions_offsets_[5] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, message_set_wire_format_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, no_standard_descriptor_accessor_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, deprecated_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, map_entry_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, uninterpreted_option_),
   };
   MessageOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MessageOptions_descriptor_,
       MessageOptions::default_instance_,
       MessageOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MessageOptions));
+      sizeof(MessageOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_),
+      -1);
   FieldOptions_descriptor_ = file->message_type(11);
   static const int FieldOptions_offsets_[7] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, jstype_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, lazy_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_),
-    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, weak_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_),
   };
   FieldOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       FieldOptions_descriptor_,
       FieldOptions::default_instance_,
       FieldOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(FieldOptions));
+      sizeof(FieldOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_),
+      -1);
   FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
+  FieldOptions_JSType_descriptor_ = FieldOptions_descriptor_->enum_type(1);
   EnumOptions_descriptor_ = file->message_type(12);
   static const int EnumOptions_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
@@ -360,64 +397,64 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, uninterpreted_option_),
   };
   EnumOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       EnumOptions_descriptor_,
       EnumOptions::default_instance_,
       EnumOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(EnumOptions));
+      sizeof(EnumOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_),
+      -1);
   EnumValueOptions_descriptor_ = file->message_type(13);
   static const int EnumValueOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_),
   };
   EnumValueOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       EnumValueOptions_descriptor_,
       EnumValueOptions::default_instance_,
       EnumValueOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(EnumValueOptions));
+      sizeof(EnumValueOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_),
+      -1);
   ServiceOptions_descriptor_ = file->message_type(14);
   static const int ServiceOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_),
   };
   ServiceOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       ServiceOptions_descriptor_,
       ServiceOptions::default_instance_,
       ServiceOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(ServiceOptions));
+      sizeof(ServiceOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_),
+      -1);
   MethodOptions_descriptor_ = file->message_type(15);
   static const int MethodOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_),
   };
   MethodOptions_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       MethodOptions_descriptor_,
       MethodOptions::default_instance_,
       MethodOptions_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _unknown_fields_),
+      -1,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_),
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(MethodOptions));
+      sizeof(MethodOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_),
+      -1);
   UninterpretedOption_descriptor_ = file->message_type(16);
   static const int UninterpretedOption_offsets_[7] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_),
@@ -429,65 +466,99 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, aggregate_value_),
   };
   UninterpretedOption_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       UninterpretedOption_descriptor_,
       UninterpretedOption::default_instance_,
       UninterpretedOption_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(UninterpretedOption));
+      -1,
+      sizeof(UninterpretedOption),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_),
+      -1);
   UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0);
   static const int UninterpretedOption_NamePart_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, is_extension_),
   };
   UninterpretedOption_NamePart_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       UninterpretedOption_NamePart_descriptor_,
       UninterpretedOption_NamePart::default_instance_,
       UninterpretedOption_NamePart_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(UninterpretedOption_NamePart));
+      -1,
+      sizeof(UninterpretedOption_NamePart),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_),
+      -1);
   SourceCodeInfo_descriptor_ = file->message_type(17);
   static const int SourceCodeInfo_offsets_[1] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_),
   };
   SourceCodeInfo_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       SourceCodeInfo_descriptor_,
       SourceCodeInfo::default_instance_,
       SourceCodeInfo_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(SourceCodeInfo));
+      -1,
+      sizeof(SourceCodeInfo),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_),
+      -1);
   SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0);
-  static const int SourceCodeInfo_Location_offsets_[4] = {
+  static const int SourceCodeInfo_Location_offsets_[5] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, span_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, leading_comments_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, trailing_comments_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, leading_detached_comments_),
   };
   SourceCodeInfo_Location_reflection_ =
-    new ::google::protobuf::internal::GeneratedMessageReflection(
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
       SourceCodeInfo_Location_descriptor_,
       SourceCodeInfo_Location::default_instance_,
       SourceCodeInfo_Location_offsets_,
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _has_bits_[0]),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _unknown_fields_),
       -1,
-      ::google::protobuf::DescriptorPool::generated_pool(),
-      ::google::protobuf::MessageFactory::generated_factory(),
-      sizeof(SourceCodeInfo_Location));
+      -1,
+      sizeof(SourceCodeInfo_Location),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_),
+      -1);
+  GeneratedCodeInfo_descriptor_ = file->message_type(18);
+  static const int GeneratedCodeInfo_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, annotation_),
+  };
+  GeneratedCodeInfo_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GeneratedCodeInfo_descriptor_,
+      GeneratedCodeInfo::default_instance_,
+      GeneratedCodeInfo_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(GeneratedCodeInfo),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _internal_metadata_),
+      -1);
+  GeneratedCodeInfo_Annotation_descriptor_ = GeneratedCodeInfo_descriptor_->nested_type(0);
+  static const int GeneratedCodeInfo_Annotation_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, path_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, source_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, begin_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, end_),
+  };
+  GeneratedCodeInfo_Annotation_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GeneratedCodeInfo_Annotation_descriptor_,
+      GeneratedCodeInfo_Annotation::default_instance_,
+      GeneratedCodeInfo_Annotation_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(GeneratedCodeInfo_Annotation),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _internal_metadata_),
+      -1);
 }
 
 namespace {
@@ -501,47 +572,53 @@
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance());
+      FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance());
+      FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    DescriptorProto_descriptor_, &DescriptorProto::default_instance());
+      DescriptorProto_descriptor_, &DescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
+      DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
+      DescriptorProto_ReservedRange_descriptor_, &DescriptorProto_ReservedRange::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    OneofDescriptorProto_descriptor_, &OneofDescriptorProto::default_instance());
+      FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance());
+      OneofDescriptorProto_descriptor_, &OneofDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance());
+      EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance());
+      EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance());
+      ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    FileOptions_descriptor_, &FileOptions::default_instance());
+      MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MessageOptions_descriptor_, &MessageOptions::default_instance());
+      FileOptions_descriptor_, &FileOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    FieldOptions_descriptor_, &FieldOptions::default_instance());
+      MessageOptions_descriptor_, &MessageOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    EnumOptions_descriptor_, &EnumOptions::default_instance());
+      FieldOptions_descriptor_, &FieldOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
+      EnumOptions_descriptor_, &EnumOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    ServiceOptions_descriptor_, &ServiceOptions::default_instance());
+      EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    MethodOptions_descriptor_, &MethodOptions::default_instance());
+      ServiceOptions_descriptor_, &ServiceOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    UninterpretedOption_descriptor_, &UninterpretedOption::default_instance());
+      MethodOptions_descriptor_, &MethodOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance());
+      UninterpretedOption_descriptor_, &UninterpretedOption::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance());
+      UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-    SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance());
+      SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GeneratedCodeInfo_descriptor_, &GeneratedCodeInfo::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GeneratedCodeInfo_Annotation_descriptor_, &GeneratedCodeInfo_Annotation::default_instance());
 }
 
 }  // namespace
@@ -555,6 +632,8 @@
   delete DescriptorProto_reflection_;
   delete DescriptorProto_ExtensionRange::default_instance_;
   delete DescriptorProto_ExtensionRange_reflection_;
+  delete DescriptorProto_ReservedRange::default_instance_;
+  delete DescriptorProto_ReservedRange_reflection_;
   delete FieldDescriptorProto::default_instance_;
   delete FieldDescriptorProto_reflection_;
   delete OneofDescriptorProto::default_instance_;
@@ -589,6 +668,10 @@
   delete SourceCodeInfo_reflection_;
   delete SourceCodeInfo_Location::default_instance_;
   delete SourceCodeInfo_Location_reflection_;
+  delete GeneratedCodeInfo::default_instance_;
+  delete GeneratedCodeInfo_reflection_;
+  delete GeneratedCodeInfo_Annotation::default_instance_;
+  delete GeneratedCodeInfo_Annotation_reflection_;
 }
 
 void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
@@ -601,7 +684,7 @@
     "\n google/protobuf/descriptor.proto\022\017goog"
     "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
     "\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
-    "roto\"\313\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
+    "roto\"\333\003\n\023FileDescriptorProto\022\014\n\004name\030\001 \001"
     "(\t\022\017\n\007package\030\002 \001(\t\022\022\n\ndependency\030\003 \003(\t\022"
     "\031\n\021public_dependency\030\n \003(\005\022\027\n\017weak_depen"
     "dency\030\013 \003(\005\0226\n\014message_type\030\004 \003(\0132 .goog"
@@ -612,111 +695,128 @@
     "\0132%.google.protobuf.FieldDescriptorProto"
     "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File"
     "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog"
-    "le.protobuf.SourceCodeInfo\"\344\003\n\017Descripto"
-    "rProto\022\014\n\004name\030\001 \001(\t\0224\n\005field\030\002 \003(\0132%.go"
-    "ogle.protobuf.FieldDescriptorProto\0228\n\tex"
-    "tension\030\006 \003(\0132%.google.protobuf.FieldDes"
-    "criptorProto\0225\n\013nested_type\030\003 \003(\0132 .goog"
-    "le.protobuf.DescriptorProto\0227\n\tenum_type"
-    "\030\004 \003(\0132$.google.protobuf.EnumDescriptorP"
-    "roto\022H\n\017extension_range\030\005 \003(\0132/.google.p"
-    "rotobuf.DescriptorProto.ExtensionRange\0229"
-    "\n\noneof_decl\030\010 \003(\0132%.google.protobuf.One"
-    "ofDescriptorProto\0220\n\007options\030\007 \001(\0132\037.goo"
-    "gle.protobuf.MessageOptions\032,\n\016Extension"
-    "Range\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024Fi"
-    "eldDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006numb"
-    "er\030\003 \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobu"
-    "f.FieldDescriptorProto.Label\0228\n\004type\030\005 \001"
-    "(\0162*.google.protobuf.FieldDescriptorProt"
-    "o.Type\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 "
-    "\001(\t\022\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_inde"
-    "x\030\t \001(\005\022.\n\007options\030\010 \001(\0132\035.google.protob"
-    "uf.FieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020"
-    "\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYP"
-    "E_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED"
-    "64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n"
-    "\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_M"
-    "ESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020"
-    "\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rT"
-    "YPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_"
-    "SINT64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n"
-    "\016LABEL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n"
-    "\024OneofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023"
-    "EnumDescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005val"
-    "ue\030\002 \003(\0132).google.protobuf.EnumValueDesc"
-    "riptorProto\022-\n\007options\030\003 \001(\0132\034.google.pr"
-    "otobuf.EnumOptions\"l\n\030EnumValueDescripto"
-    "rProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007"
-    "options\030\003 \001(\0132!.google.protobuf.EnumValu"
-    "eOptions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004n"
-    "ame\030\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.proto"
-    "buf.MethodDescriptorProto\0220\n\007options\030\003 \001"
-    "(\0132\037.google.protobuf.ServiceOptions\"\177\n\025M"
-    "ethodDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\nin"
-    "put_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007o"
-    "ptions\030\004 \001(\0132\036.google.protobuf.MethodOpt"
-    "ions\"\324\004\n\013FileOptions\022\024\n\014java_package\030\001 \001"
-    "(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023java"
-    "_multiple_files\030\n \001(\010:\005false\022,\n\035java_gen"
-    "erate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026ja"
-    "va_string_check_utf8\030\033 \001(\010:\005false\022F\n\014opt"
-    "imize_for\030\t \001(\0162).google.protobuf.FileOp"
-    "tions.OptimizeMode:\005SPEED\022\022\n\ngo_package\030"
-    "\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fals"
-    "e\022$\n\025java_generic_services\030\021 \001(\010:\005false\022"
-    "\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n\nd"
-    "eprecated\030\027 \001(\010:\005false\022\'\n\037javanano_use_d"
-    "eprecated_package\030& \001(\010\022C\n\024uninterpreted"
-    "_option\030\347\007 \003(\0132$.google.protobuf.Uninter"
-    "pretedOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022"
-    "\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200"
-    "\200\200\002\"\323\001\n\016MessageOptions\022&\n\027message_set_wi"
-    "re_format\030\001 \001(\010:\005false\022.\n\037no_standard_de"
-    "scriptor_accessor\030\002 \001(\010:\005false\022\031\n\ndeprec"
-    "ated\030\003 \001(\010:\005false\022C\n\024uninterpreted_optio"
-    "n\030\347\007 \003(\0132$.google.protobuf.Uninterpreted"
-    "Option*\t\010\350\007\020\200\200\200\200\002\"\276\002\n\014FieldOptions\022:\n\005ct"
-    "ype\030\001 \001(\0162#.google.protobuf.FieldOptions"
-    ".CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005"
-    " \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\034"
-    "\n\024experimental_map_key\030\t \001(\t\022\023\n\004weak\030\n \001"
-    "(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(\013"
-    "2$.google.protobuf.UninterpretedOption\"/"
-    "\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_"
-    "PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013al"
-    "low_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fal"
-    "se\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog"
-    "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200"
-    "\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001"
-    "(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(\013"
+    "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001"
+    "(\t\"\360\004\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
+    "field\030\002 \003(\0132%.google.protobuf.FieldDescr"
+    "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p"
+    "rotobuf.FieldDescriptorProto\0225\n\013nested_t"
+    "ype\030\003 \003(\0132 .google.protobuf.DescriptorPr"
+    "oto\0227\n\tenum_type\030\004 \003(\0132$.google.protobuf"
+    ".EnumDescriptorProto\022H\n\017extension_range\030"
+    "\005 \003(\0132/.google.protobuf.DescriptorProto."
+    "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo"
+    "gle.protobuf.OneofDescriptorProto\0220\n\007opt"
+    "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti"
+    "ons\022F\n\016reserved_range\030\t \003(\0132..google.pro"
+    "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
+    "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005"
+    "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang"
+    "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\274\005\n\024FieldD"
+    "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003"
+    " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi"
+    "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*"
+    ".google.protobuf.FieldDescriptorProto.Ty"
+    "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022"
+    "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t "
+    "\001(\005\022\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001(\0132"
+    "\035.google.protobuf.FieldOptions\"\266\002\n\004Type\022"
+    "\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE"
+    "_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020"
+    "\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n"
+    "\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GR"
+    "OUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022"
+    "\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_"
+    "SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI"
+    "NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE"
+    "L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE"
+    "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004"
+    "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na"
+    "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu"
+    "f.EnumValueDescriptorProto\022-\n\007options\030\003 "
+    "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu"
+    "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n"
+    "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr"
+    "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr"
+    "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013"
+    "2&.google.protobuf.MethodDescriptorProto"
+    "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv"
+    "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004"
+    "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output"
+    "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr"
+    "otobuf.MethodOptions\022\037\n\020client_streaming"
+    "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:"
+    "\005false\"\207\005\n\013FileOptions\022\024\n\014java_package\030\001"
+    " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja"
+    "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g"
+    "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026"
+    "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o"
+    "ptimize_for\030\t \001(\0162).google.protobuf.File"
+    "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag"
+    "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa"
+    "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals"
+    "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n"
+    "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar"
+    "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$"
+    " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024uninte"
+    "rpreted_option\030\347\007 \003(\0132$.google.protobuf."
+    "UninterpretedOption\":\n\014OptimizeMode\022\t\n\005S"
+    "PEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*"
+    "\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOptions\022&\n\027m"
+    "essage_set_wire_format\030\001 \001(\010:\005false\022.\n\037n"
+    "o_standard_descriptor_accessor\030\002 \001(\010:\005fa"
+    "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_en"
+    "try\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\013"
     "2$.google.protobuf.UninterpretedOption*\t"
-    "\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecate"
-    "d\030! \001(\010:\005false\022C\n\024uninterpreted_option\030\347"
-    "\007 \003(\0132$.google.protobuf.UninterpretedOpt"
-    "ion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepre"
-    "cated\030! \001(\010:\005false\022C\n\024uninterpreted_opti"
-    "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete"
-    "dOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpti"
-    "on\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unint"
-    "erpretedOption.NamePart\022\030\n\020identifier_va"
-    "lue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n"
-    "\022negative_int_value\030\005 \001(\003\022\024\n\014double_valu"
-    "e\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggrega"
-    "te_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030"
-    "\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\261\001\n\016SourceCo"
-    "deInfo\022:\n\010location\030\001 \003(\0132(.google.protob"
-    "uf.SourceCodeInfo.Location\032c\n\010Location\022\020"
-    "\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020le"
-    "ading_comments\030\003 \001(\t\022\031\n\021trailing_comment"
-    "s\030\004 \001(\tB)\n\023com.google.protobufB\020Descript"
-    "orProtosH\001", 4490);
+    "\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001("
+    "\0162#.google.protobuf.FieldOptions.CType:\006"
+    "STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$"
+    ".google.protobuf.FieldOptions.JSType:\tJS"
+    "_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecat"
+    "ed\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024"
+    "uninterpreted_option\030\347\007 \003(\0132$.google.pro"
+    "tobuf.UninterpretedOption\"/\n\005CType\022\n\n\006ST"
+    "RING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JS"
+    "Type\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS"
+    "_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013"
+    "allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f"
+    "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+    "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
+    "\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001"
+    " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
+    "(\0132$.google.protobuf.UninterpretedOption"
+    "*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepreca"
+    "ted\030! \001(\010:\005false\022C\n\024uninterpreted_option"
+    "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO"
+    "ption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndep"
+    "recated\030! \001(\010:\005false\022C\n\024uninterpreted_op"
+    "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
+    "tedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOp"
+    "tion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uni"
+    "nterpretedOption.NamePart\022\030\n\020identifier_"
+    "value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022"
+    "\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_va"
+    "lue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggre"
+    "gate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_par"
+    "t\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016Source"
+    "CodeInfo\022:\n\010location\030\001 \003(\0132(.google.prot"
+    "obuf.SourceCodeInfo.Location\032\206\001\n\010Locatio"
+    "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n"
+    "\020leading_comments\030\003 \001(\t\022\031\n\021trailing_comm"
+    "ents\030\004 \001(\t\022!\n\031leading_detached_comments\030"
+    "\006 \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotatio"
+    "n\030\001 \003(\0132-.google.protobuf.GeneratedCodeI"
+    "nfo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003"
+    "(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001"
+    "(\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020"
+    "DescriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032G"
+    "oogle.Protobuf.Reflection", 5145);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   FileDescriptorSet::default_instance_ = new FileDescriptorSet();
   FileDescriptorProto::default_instance_ = new FileDescriptorProto();
   DescriptorProto::default_instance_ = new DescriptorProto();
   DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange();
+  DescriptorProto_ReservedRange::default_instance_ = new DescriptorProto_ReservedRange();
   FieldDescriptorProto::default_instance_ = new FieldDescriptorProto();
   OneofDescriptorProto::default_instance_ = new OneofDescriptorProto();
   EnumDescriptorProto::default_instance_ = new EnumDescriptorProto();
@@ -734,10 +834,13 @@
   UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart();
   SourceCodeInfo::default_instance_ = new SourceCodeInfo();
   SourceCodeInfo_Location::default_instance_ = new SourceCodeInfo_Location();
+  GeneratedCodeInfo::default_instance_ = new GeneratedCodeInfo();
+  GeneratedCodeInfo_Annotation::default_instance_ = new GeneratedCodeInfo_Annotation();
   FileDescriptorSet::default_instance_->InitAsDefaultInstance();
   FileDescriptorProto::default_instance_->InitAsDefaultInstance();
   DescriptorProto::default_instance_->InitAsDefaultInstance();
   DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance();
+  DescriptorProto_ReservedRange::default_instance_->InitAsDefaultInstance();
   FieldDescriptorProto::default_instance_->InitAsDefaultInstance();
   OneofDescriptorProto::default_instance_->InitAsDefaultInstance();
   EnumDescriptorProto::default_instance_->InitAsDefaultInstance();
@@ -755,6 +858,8 @@
   UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance();
   SourceCodeInfo::default_instance_->InitAsDefaultInstance();
   SourceCodeInfo_Location::default_instance_->InitAsDefaultInstance();
+  GeneratedCodeInfo::default_instance_->InitAsDefaultInstance();
+  GeneratedCodeInfo_Annotation::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto);
 }
 
@@ -765,14 +870,24 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_;
 
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileDescriptorSet::kFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileDescriptorSet::FileDescriptorSet()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorSet)
 }
@@ -781,7 +896,8 @@
 }
 
 FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorSet)
@@ -819,19 +935,26 @@
 
 FileDescriptorSet* FileDescriptorSet::default_instance_ = NULL;
 
-FileDescriptorSet* FileDescriptorSet::New() const {
-  return new FileDescriptorSet;
+FileDescriptorSet* FileDescriptorSet::New(::google::protobuf::Arena* arena) const {
+  FileDescriptorSet* n = new FileDescriptorSet;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void FileDescriptorSet::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorSet)
   file_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool FileDescriptorSet::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorSet)
   for (;;) {
@@ -842,13 +965,15 @@
       // repeated .google.protobuf.FileDescriptorProto file = 1;
       case 1: {
         if (tag == 10) {
-         parse_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_file;
+        if (input->ExpectTag(10)) goto parse_loop_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -879,12 +1004,12 @@
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:google.protobuf.FileDescriptorSet)
   // repeated .google.protobuf.FileDescriptorProto file = 1;
-  for (int i = 0; i < this->file_size(); i++) {
+  for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       1, this->file(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -895,13 +1020,13 @@
     ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
   // repeated .google.protobuf.FileDescriptorProto file = 1;
-  for (int i = 0; i < this->file_size(); i++) {
+  for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         1, this->file(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -910,6 +1035,7 @@
 }
 
 int FileDescriptorSet::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet)
   int total_size = 0;
 
   // repeated .google.protobuf.FileDescriptorProto file = 1;
@@ -920,7 +1046,7 @@
         this->file(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -932,30 +1058,38 @@
 }
 
 void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const FileDescriptorSet* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorSet*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorSet)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FileDescriptorSet* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorSet>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorSet)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorSet)
     MergeFrom(*source);
   }
 }
 
 void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   file_.MergeFrom(from.file_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void FileDescriptorSet::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorSet)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorSet)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -968,12 +1102,14 @@
 }
 
 void FileDescriptorSet::Swap(FileDescriptorSet* other) {
-  if (other != this) {
-    file_.Swap(&other->file_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) {
+  file_.UnsafeArenaSwap(&other->file_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata FileDescriptorSet::GetMetadata() const {
@@ -984,10 +1120,44 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileDescriptorSet
+
+// repeated .google.protobuf.FileDescriptorProto file = 1;
+int FileDescriptorSet::file_size() const {
+  return file_.size();
+}
+void FileDescriptorSet::clear_file() {
+  file_.Clear();
+}
+const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file)
+  return file_.Get(index);
+}
+::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file)
+  return file_.Mutable(index);
+}
+::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
+  return file_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+FileDescriptorSet::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
+  return &file_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+FileDescriptorSet::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
+  return file_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileDescriptorProto::kNameFieldNumber;
 const int FileDescriptorProto::kPackageFieldNumber;
 const int FileDescriptorProto::kDependencyFieldNumber;
@@ -999,10 +1169,11 @@
 const int FileDescriptorProto::kExtensionFieldNumber;
 const int FileDescriptorProto::kOptionsFieldNumber;
 const int FileDescriptorProto::kSourceCodeInfoFieldNumber;
-#endif  // !_MSC_VER
+const int FileDescriptorProto::kSyntaxFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileDescriptorProto::FileDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorProto)
 }
@@ -1013,7 +1184,8 @@
 }
 
 FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FileDescriptorProto)
@@ -1022,10 +1194,11 @@
 void FileDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   source_code_info_ = NULL;
+  syntax_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -1035,12 +1208,9 @@
 }
 
 void FileDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete package_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  syntax_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
     delete source_code_info_;
@@ -1064,30 +1234,34 @@
 
 FileDescriptorProto* FileDescriptorProto::default_instance_ = NULL;
 
-FileDescriptorProto* FileDescriptorProto::New() const {
-  return new FileDescriptorProto;
+FileDescriptorProto* FileDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  FileDescriptorProto* n = new FileDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void FileDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 3) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorProto)
+  if (_has_bits_[0 / 32] & 3u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_package()) {
-      if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        package_->clear();
-      }
+      package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
-  if (_has_bits_[8 / 32] & 1536) {
+  if (_has_bits_[8 / 32] & 3584u) {
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
     }
     if (has_source_code_info()) {
       if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
     }
+    if (has_syntax()) {
+      syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
   }
   dependency_.Clear();
   public_dependency_.Clear();
@@ -1097,12 +1271,14 @@
   service_.Clear();
   extension_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool FileDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorProto)
   for (;;) {
@@ -1118,7 +1294,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.FileDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -1135,7 +1311,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->package().data(), this->package().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "package");
+            "google.protobuf.FileDescriptorProto.package");
         } else {
           goto handle_unusual;
         }
@@ -1153,7 +1329,7 @@
             this->dependency(this->dependency_size() - 1).data(),
             this->dependency(this->dependency_size() - 1).length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "dependency");
+            "google.protobuf.FileDescriptorProto.dependency");
         } else {
           goto handle_unusual;
         }
@@ -1166,54 +1342,63 @@
       case 4: {
         if (tag == 34) {
          parse_message_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_message_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_message_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(34)) goto parse_message_type;
-        if (input->ExpectTag(42)) goto parse_enum_type;
+        if (input->ExpectTag(34)) goto parse_loop_message_type;
+        if (input->ExpectTag(42)) goto parse_loop_enum_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
       case 5: {
         if (tag == 42) {
-         parse_enum_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enum_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_enum_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(42)) goto parse_enum_type;
-        if (input->ExpectTag(50)) goto parse_service;
+        if (input->ExpectTag(42)) goto parse_loop_enum_type;
+        if (input->ExpectTag(50)) goto parse_loop_service;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.ServiceDescriptorProto service = 6;
       case 6: {
         if (tag == 50) {
-         parse_service:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_service:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_service()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(50)) goto parse_service;
-        if (input->ExpectTag(58)) goto parse_extension;
+        if (input->ExpectTag(50)) goto parse_loop_service;
+        if (input->ExpectTag(58)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.FieldDescriptorProto extension = 7;
       case 7: {
         if (tag == 58) {
-         parse_extension:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(58)) goto parse_extension;
+        if (input->ExpectTag(58)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(66)) goto parse_options;
         break;
       }
@@ -1278,6 +1463,23 @@
           goto handle_unusual;
         }
         if (input->ExpectTag(88)) goto parse_weak_dependency;
+        if (input->ExpectTag(98)) goto parse_syntax;
+        break;
+      }
+
+      // optional string syntax = 12;
+      case 12: {
+        if (tag == 98) {
+         parse_syntax:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_syntax()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->syntax().data(), this->syntax().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.FileDescriptorProto.syntax");
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1312,7 +1514,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.FileDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
@@ -1322,41 +1524,41 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->package().data(), this->package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "package");
+      "google.protobuf.FileDescriptorProto.package");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       2, this->package(), output);
   }
 
   // repeated string dependency = 3;
   for (int i = 0; i < this->dependency_size(); i++) {
-  ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
-    this->dependency(i).data(), this->dependency(i).length(),
-    ::google::protobuf::internal::WireFormat::SERIALIZE,
-    "dependency");
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->dependency(i).data(), this->dependency(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.dependency");
     ::google::protobuf::internal::WireFormatLite::WriteString(
       3, this->dependency(i), output);
   }
 
   // repeated .google.protobuf.DescriptorProto message_type = 4;
-  for (int i = 0; i < this->message_type_size(); i++) {
+  for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       4, this->message_type(i), output);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  for (int i = 0; i < this->enum_type_size(); i++) {
+  for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       5, this->enum_type(i), output);
   }
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  for (int i = 0; i < this->service_size(); i++) {
+  for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       6, this->service(i), output);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  for (int i = 0; i < this->extension_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       7, this->extension(i), output);
   }
@@ -1364,13 +1566,13 @@
   // optional .google.protobuf.FileOptions options = 8;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      8, this->options(), output);
+      8, *this->options_, output);
   }
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
   if (has_source_code_info()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      9, this->source_code_info(), output);
+      9, *this->source_code_info_, output);
   }
 
   // repeated int32 public_dependency = 10;
@@ -1385,7 +1587,17 @@
       11, this->weak_dependency(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional string syntax = 12;
+  if (has_syntax()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->syntax().data(), this->syntax().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.syntax");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      12, this->syntax(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -1400,7 +1612,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.FileDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
@@ -1411,7 +1623,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->package().data(), this->package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "package");
+      "google.protobuf.FileDescriptorProto.package");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         2, this->package(), target);
@@ -1422,34 +1634,34 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->dependency(i).data(), this->dependency(i).length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "dependency");
+      "google.protobuf.FileDescriptorProto.dependency");
     target = ::google::protobuf::internal::WireFormatLite::
       WriteStringToArray(3, this->dependency(i), target);
   }
 
   // repeated .google.protobuf.DescriptorProto message_type = 4;
-  for (int i = 0; i < this->message_type_size(); i++) {
+  for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         4, this->message_type(i), target);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  for (int i = 0; i < this->enum_type_size(); i++) {
+  for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         5, this->enum_type(i), target);
   }
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  for (int i = 0; i < this->service_size(); i++) {
+  for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         6, this->service(i), target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  for (int i = 0; i < this->extension_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         7, this->extension(i), target);
@@ -1459,14 +1671,14 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        8, this->options(), target);
+        8, *this->options_, target);
   }
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
   if (has_source_code_info()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        9, this->source_code_info(), target);
+        9, *this->source_code_info_, target);
   }
 
   // repeated int32 public_dependency = 10;
@@ -1481,7 +1693,18 @@
       WriteInt32ToArray(11, this->weak_dependency(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional string syntax = 12;
+  if (has_syntax()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->syntax().data(), this->syntax().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileDescriptorProto.syntax");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        12, this->syntax(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -1490,9 +1713,10 @@
 }
 
 int FileDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -1508,19 +1732,26 @@
     }
 
   }
-  if (_has_bits_[9 / 32] & (0xffu << (9 % 32))) {
+  if (_has_bits_[9 / 32] & 3584u) {
     // optional .google.protobuf.FileOptions options = 8;
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
     // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
     if (has_source_code_info()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->source_code_info());
+          *this->source_code_info_);
+    }
+
+    // optional string syntax = 12;
+    if (has_syntax()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->syntax());
     }
 
   }
@@ -1583,7 +1814,7 @@
         this->extension(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -1595,19 +1826,23 @@
 }
 
 void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const FileDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FileDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   dependency_.MergeFrom(from.dependency_);
   public_dependency_.MergeFrom(from.public_dependency_);
   weak_dependency_.MergeFrom(from.weak_dependency_);
@@ -1617,10 +1852,12 @@
   extension_.MergeFrom(from.extension_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_package()) {
-      set_package(from.package());
+      set_has_package();
+      package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.package_);
     }
   }
   if (from._has_bits_[9 / 32] & (0xffu << (9 % 32))) {
@@ -1630,17 +1867,25 @@
     if (from.has_source_code_info()) {
       mutable_source_code_info()->::google::protobuf::SourceCodeInfo::MergeFrom(from.source_code_info());
     }
+    if (from.has_syntax()) {
+      set_has_syntax();
+      syntax_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.syntax_);
+    }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -1653,28 +1898,31 @@
   if (!::google::protobuf::internal::AllAreInitialized(this->service())) return false;
   if (!::google::protobuf::internal::AllAreInitialized(this->extension())) return false;
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void FileDescriptorProto::Swap(FileDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(package_, other->package_);
-    dependency_.Swap(&other->dependency_);
-    public_dependency_.Swap(&other->public_dependency_);
-    weak_dependency_.Swap(&other->weak_dependency_);
-    message_type_.Swap(&other->message_type_);
-    enum_type_.Swap(&other->enum_type_);
-    service_.Swap(&other->service_);
-    extension_.Swap(&other->extension_);
-    std::swap(options_, other->options_);
-    std::swap(source_code_info_, other->source_code_info_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  package_.Swap(&other->package_);
+  dependency_.UnsafeArenaSwap(&other->dependency_);
+  public_dependency_.UnsafeArenaSwap(&other->public_dependency_);
+  weak_dependency_.UnsafeArenaSwap(&other->weak_dependency_);
+  message_type_.UnsafeArenaSwap(&other->message_type_);
+  enum_type_.UnsafeArenaSwap(&other->enum_type_);
+  service_.UnsafeArenaSwap(&other->service_);
+  extension_.UnsafeArenaSwap(&other->extension_);
+  std::swap(options_, other->options_);
+  std::swap(source_code_info_, other->source_code_info_);
+  syntax_.Swap(&other->syntax_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata FileDescriptorProto::GetMetadata() const {
@@ -1685,16 +1933,505 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileDescriptorProto
+
+// optional string name = 1;
+bool FileDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FileDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FileDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FileDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& FileDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.name)
+}
+ void FileDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.name)
+}
+ void FileDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.name)
+}
+ ::std::string* FileDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
+}
+
+// optional string package = 2;
+bool FileDescriptorProto::has_package() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FileDescriptorProto::set_has_package() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FileDescriptorProto::clear_has_package() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FileDescriptorProto::clear_package() {
+  package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_package();
+}
+ const ::std::string& FileDescriptorProto::package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
+  return package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_package(const ::std::string& value) {
+  set_has_package();
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package)
+}
+ void FileDescriptorProto::set_package(const char* value) {
+  set_has_package();
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.package)
+}
+ void FileDescriptorProto::set_package(const char* value, size_t size) {
+  set_has_package();
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.package)
+}
+ ::std::string* FileDescriptorProto::mutable_package() {
+  set_has_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
+  return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package)
+  clear_has_package();
+  return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_package(::std::string* package) {
+  if (package != NULL) {
+    set_has_package();
+  } else {
+    clear_has_package();
+  }
+  package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), package);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
+}
+
+// repeated string dependency = 3;
+int FileDescriptorProto::dependency_size() const {
+  return dependency_.size();
+}
+void FileDescriptorProto::clear_dependency() {
+  dependency_.Clear();
+}
+ const ::std::string& FileDescriptorProto::dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.dependency)
+  return dependency_.Get(index);
+}
+ ::std::string* FileDescriptorProto::mutable_dependency(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return dependency_.Mutable(index);
+}
+ void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.dependency)
+  dependency_.Mutable(index)->assign(value);
+}
+ void FileDescriptorProto::set_dependency(int index, const char* value) {
+  dependency_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) {
+  dependency_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+ ::std::string* FileDescriptorProto::add_dependency() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency)
+  return dependency_.Add();
+}
+ void FileDescriptorProto::add_dependency(const ::std::string& value) {
+  dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::add_dependency(const char* value) {
+  dependency_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FileDescriptorProto.dependency)
+}
+ void FileDescriptorProto::add_dependency(const char* value, size_t size) {
+  dependency_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FileDescriptorProto.dependency)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FileDescriptorProto::dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.dependency)
+  return dependency_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+FileDescriptorProto::mutable_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.dependency)
+  return &dependency_;
+}
+
+// repeated int32 public_dependency = 10;
+int FileDescriptorProto::public_dependency_size() const {
+  return public_dependency_.size();
+}
+void FileDescriptorProto::clear_public_dependency() {
+  public_dependency_.Clear();
+}
+ ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.public_dependency)
+  return public_dependency_.Get(index);
+}
+ void FileDescriptorProto::set_public_dependency(int index, ::google::protobuf::int32 value) {
+  public_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.public_dependency)
+}
+ void FileDescriptorProto::add_public_dependency(::google::protobuf::int32 value) {
+  public_dependency_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.public_dependency)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::public_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return public_dependency_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_public_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.public_dependency)
+  return &public_dependency_;
+}
+
+// repeated int32 weak_dependency = 11;
+int FileDescriptorProto::weak_dependency_size() const {
+  return weak_dependency_.size();
+}
+void FileDescriptorProto::clear_weak_dependency() {
+  weak_dependency_.Clear();
+}
+ ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.weak_dependency)
+  return weak_dependency_.Get(index);
+}
+ void FileDescriptorProto::set_weak_dependency(int index, ::google::protobuf::int32 value) {
+  weak_dependency_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+ void FileDescriptorProto::add_weak_dependency(::google::protobuf::int32 value) {
+  weak_dependency_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.weak_dependency)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+FileDescriptorProto::weak_dependency() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return weak_dependency_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+FileDescriptorProto::mutable_weak_dependency() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.weak_dependency)
+  return &weak_dependency_;
+}
+
+// repeated .google.protobuf.DescriptorProto message_type = 4;
+int FileDescriptorProto::message_type_size() const {
+  return message_type_.size();
+}
+void FileDescriptorProto::clear_message_type() {
+  message_type_.Clear();
+}
+const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type)
+  return message_type_.Get(index);
+}
+::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type)
+  return message_type_.Mutable(index);
+}
+::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
+  return message_type_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+FileDescriptorProto::mutable_message_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
+  return &message_type_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
+  return message_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
+int FileDescriptorProto::enum_type_size() const {
+  return enum_type_.size();
+}
+void FileDescriptorProto::clear_enum_type() {
+  enum_type_.Clear();
+}
+const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type)
+  return enum_type_.Get(index);
+}
+::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type)
+  return enum_type_.Mutable(index);
+}
+::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
+  return enum_type_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+FileDescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
+  return &enum_type_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
+  return enum_type_;
+}
+
+// repeated .google.protobuf.ServiceDescriptorProto service = 6;
+int FileDescriptorProto::service_size() const {
+  return service_.size();
+}
+void FileDescriptorProto::clear_service() {
+  service_.Clear();
+}
+const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service)
+  return service_.Get(index);
+}
+::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service)
+  return service_.Mutable(index);
+}
+::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
+  return service_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+FileDescriptorProto::mutable_service() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
+  return &service_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
+  return service_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 7;
+int FileDescriptorProto::extension_size() const {
+  return extension_.size();
+}
+void FileDescriptorProto::clear_extension() {
+  extension_.Clear();
+}
+const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension)
+  return extension_.Get(index);
+}
+::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension)
+  return extension_.Mutable(index);
+}
+::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
+  return extension_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+FileDescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
+  return &extension_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
+  return extension_;
+}
+
+// optional .google.protobuf.FileOptions options = 8;
+bool FileDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void FileDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void FileDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void FileDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::FileOptions& FileDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::FileOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::FileOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.options)
+}
+
+// optional .google.protobuf.SourceCodeInfo source_code_info = 9;
+bool FileDescriptorProto::has_source_code_info() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void FileDescriptorProto::set_has_source_code_info() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void FileDescriptorProto::clear_has_source_code_info() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void FileDescriptorProto::clear_source_code_info() {
+  if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
+  clear_has_source_code_info();
+}
+const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info)
+  return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_;
+}
+::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() {
+  set_has_source_code_info();
+  if (source_code_info_ == NULL) {
+    source_code_info_ = new ::google::protobuf::SourceCodeInfo;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
+  return source_code_info_;
+}
+::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info)
+  clear_has_source_code_info();
+  ::google::protobuf::SourceCodeInfo* temp = source_code_info_;
+  source_code_info_ = NULL;
+  return temp;
+}
+void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) {
+  delete source_code_info_;
+  source_code_info_ = source_code_info;
+  if (source_code_info) {
+    set_has_source_code_info();
+  } else {
+    clear_has_source_code_info();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
+}
+
+// optional string syntax = 12;
+bool FileDescriptorProto::has_syntax() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void FileDescriptorProto::set_has_syntax() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void FileDescriptorProto::clear_has_syntax() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void FileDescriptorProto::clear_syntax() {
+  syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_syntax();
+}
+ const ::std::string& FileDescriptorProto::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+  return syntax_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_syntax(const ::std::string& value) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+ void FileDescriptorProto::set_syntax(const char* value) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.syntax)
+}
+ void FileDescriptorProto::set_syntax(const char* value, size_t size) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.syntax)
+}
+ ::std::string* FileDescriptorProto::mutable_syntax() {
+  set_has_syntax();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax)
+  return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileDescriptorProto::release_syntax() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax)
+  clear_has_syntax();
+  return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileDescriptorProto::set_allocated_syntax(::std::string* syntax) {
+  if (syntax != NULL) {
+    set_has_syntax();
+  } else {
+    clear_has_syntax();
+  }
+  syntax_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), syntax);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DescriptorProto_ExtensionRange::kStartFieldNumber;
 const int DescriptorProto_ExtensionRange::kEndFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ExtensionRange)
 }
@@ -1703,7 +2440,8 @@
 }
 
 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ExtensionRange)
@@ -1743,33 +2481,46 @@
 
 DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::default_instance_ = NULL;
 
-DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New() const {
-  return new DescriptorProto_ExtensionRange;
+DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New(::google::protobuf::Arena* arena) const {
+  DescriptorProto_ExtensionRange* n = new DescriptorProto_ExtensionRange;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void DescriptorProto_ExtensionRange::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<DescriptorProto_ExtensionRange*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ExtensionRange)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(DescriptorProto_ExtensionRange, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DescriptorProto_ExtensionRange*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(start_, end_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ExtensionRange)
   for (;;) {
@@ -1841,7 +2592,7 @@
     ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -1861,7 +2612,7 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -1870,9 +2621,10 @@
 }
 
 int DescriptorProto_ExtensionRange::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional int32 start = 1;
     if (has_start()) {
       total_size += 1 +
@@ -1888,7 +2640,7 @@
     }
 
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -1900,19 +2652,23 @@
 }
 
 void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const DescriptorProto_ExtensionRange* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto_ExtensionRange*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DescriptorProto_ExtensionRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ExtensionRange>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ExtensionRange)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ExtensionRange)
     MergeFrom(*source);
   }
 }
 
 void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_start()) {
       set_start(from.start());
@@ -1921,16 +2677,20 @@
       set_end(from.end());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -1942,13 +2702,15 @@
 }
 
 void DescriptorProto_ExtensionRange::Swap(DescriptorProto_ExtensionRange* other) {
-  if (other != this) {
-    std::swap(start_, other->start_);
-    std::swap(end_, other->end_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange* other) {
+  std::swap(start_, other->start_);
+  std::swap(end_, other->end_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata DescriptorProto_ExtensionRange::GetMetadata() const {
@@ -1962,7 +2724,306 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DescriptorProto_ReservedRange::kStartFieldNumber;
+const int DescriptorProto_ReservedRange::kEndFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+void DescriptorProto_ReservedRange::InitAsDefaultInstance() {
+}
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+void DescriptorProto_ReservedRange::SharedCtor() {
+  _cached_size_ = 0;
+  start_ = 0;
+  end_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange)
+  SharedDtor();
+}
+
+void DescriptorProto_ReservedRange::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void DescriptorProto_ReservedRange::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DescriptorProto_ReservedRange_descriptor_;
+}
+
+const DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::default_instance_ = NULL;
+
+DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::New(::google::protobuf::Arena* arena) const {
+  DescriptorProto_ReservedRange* n = new DescriptorProto_ReservedRange;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DescriptorProto_ReservedRange::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ReservedRange)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(DescriptorProto_ReservedRange, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DescriptorProto_ReservedRange*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(start_, end_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DescriptorProto_ReservedRange::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ReservedRange)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 start = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &start_)));
+          set_has_start();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_end;
+        break;
+      }
+
+      // optional int32 end = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_end:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &end_)));
+          set_has_end();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.DescriptorProto.ReservedRange)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.DescriptorProto.ReservedRange)
+  return false;
+#undef DO_
+}
+
+void DescriptorProto_ReservedRange::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ReservedRange)
+  // optional int32 start = 1;
+  if (has_start()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output);
+  }
+
+  // optional int32 end = 2;
+  if (has_end()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+::google::protobuf::uint8* DescriptorProto_ReservedRange::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
+  // optional int32 start = 1;
+  if (has_start()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (has_end()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
+  return target;
+}
+
+int DescriptorProto_ReservedRange::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange)
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional int32 start = 1;
+    if (has_start()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->start());
+    }
+
+    // optional int32 end = 2;
+    if (has_end()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->end());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DescriptorProto_ReservedRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ReservedRange>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ReservedRange)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ReservedRange)
+    MergeFrom(*source);
+  }
+}
+
+void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_start()) {
+      set_start(from.start());
+    }
+    if (from.has_end()) {
+      set_end(from.end());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ReservedRange)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ReservedRange::IsInitialized() const {
+
+  return true;
+}
+
+void DescriptorProto_ReservedRange::Swap(DescriptorProto_ReservedRange* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* other) {
+  std::swap(start_, other->start_);
+  std::swap(end_, other->end_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DescriptorProto_ReservedRange_descriptor_;
+  metadata.reflection = DescriptorProto_ReservedRange_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DescriptorProto::kNameFieldNumber;
 const int DescriptorProto::kFieldFieldNumber;
 const int DescriptorProto::kExtensionFieldNumber;
@@ -1971,10 +3032,12 @@
 const int DescriptorProto::kExtensionRangeFieldNumber;
 const int DescriptorProto::kOneofDeclFieldNumber;
 const int DescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+const int DescriptorProto::kReservedRangeFieldNumber;
+const int DescriptorProto::kReservedNameFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DescriptorProto::DescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto)
 }
@@ -1984,7 +3047,8 @@
 }
 
 DescriptorProto::DescriptorProto(const DescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto)
@@ -1993,7 +3057,7 @@
 void DescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -2004,9 +3068,7 @@
 }
 
 void DescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -2029,16 +3091,19 @@
 
 DescriptorProto* DescriptorProto::default_instance_ = NULL;
 
-DescriptorProto* DescriptorProto::New() const {
-  return new DescriptorProto;
+DescriptorProto* DescriptorProto::New(::google::protobuf::Arena* arena) const {
+  DescriptorProto* n = new DescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void DescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 129) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto)
+  if (_has_bits_[0 / 32] & 129u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
@@ -2050,13 +3115,17 @@
   enum_type_.Clear();
   extension_range_.Clear();
   oneof_decl_.Clear();
+  reserved_range_.Clear();
+  reserved_name_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool DescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto)
   for (;;) {
@@ -2072,7 +3141,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.DescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -2084,68 +3153,79 @@
       case 2: {
         if (tag == 18) {
          parse_field:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_field:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_field()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_field;
-        if (input->ExpectTag(26)) goto parse_nested_type;
+        if (input->ExpectTag(18)) goto parse_loop_field;
+        if (input->ExpectTag(26)) goto parse_loop_nested_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.DescriptorProto nested_type = 3;
       case 3: {
         if (tag == 26) {
-         parse_nested_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_nested_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_nested_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(26)) goto parse_nested_type;
-        if (input->ExpectTag(34)) goto parse_enum_type;
+        if (input->ExpectTag(26)) goto parse_loop_nested_type;
+        if (input->ExpectTag(34)) goto parse_loop_enum_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
       case 4: {
         if (tag == 34) {
-         parse_enum_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enum_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_enum_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(34)) goto parse_enum_type;
-        if (input->ExpectTag(42)) goto parse_extension_range;
+        if (input->ExpectTag(34)) goto parse_loop_enum_type;
+        if (input->ExpectTag(42)) goto parse_loop_extension_range;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
       case 5: {
         if (tag == 42) {
-         parse_extension_range:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension_range:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension_range()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(42)) goto parse_extension_range;
-        if (input->ExpectTag(50)) goto parse_extension;
+        if (input->ExpectTag(42)) goto parse_loop_extension_range;
+        if (input->ExpectTag(50)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.FieldDescriptorProto extension = 6;
       case 6: {
         if (tag == 50) {
-         parse_extension:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(50)) goto parse_extension;
+        if (input->ExpectTag(50)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(58)) goto parse_options;
         break;
       }
@@ -2167,12 +3247,50 @@
       case 8: {
         if (tag == 66) {
          parse_oneof_decl:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_oneof_decl:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_oneof_decl()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(66)) goto parse_oneof_decl;
+        if (input->ExpectTag(66)) goto parse_loop_oneof_decl;
+        if (input->ExpectTag(74)) goto parse_loop_reserved_range;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+      case 9: {
+        if (tag == 74) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_reserved_range:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_reserved_range()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(74)) goto parse_loop_reserved_range;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(82)) goto parse_reserved_name;
+        break;
+      }
+
+      // repeated string reserved_name = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_reserved_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_reserved_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->reserved_name(this->reserved_name_size() - 1).data(),
+            this->reserved_name(this->reserved_name_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.DescriptorProto.reserved_name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(82)) goto parse_reserved_name;
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -2207,37 +3325,37 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.DescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  for (int i = 0; i < this->field_size(); i++) {
+  for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       2, this->field(i), output);
   }
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  for (int i = 0; i < this->nested_type_size(); i++) {
+  for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       3, this->nested_type(i), output);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  for (int i = 0; i < this->enum_type_size(); i++) {
+  for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       4, this->enum_type(i), output);
   }
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  for (int i = 0; i < this->extension_range_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       5, this->extension_range(i), output);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  for (int i = 0; i < this->extension_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       6, this->extension(i), output);
   }
@@ -2245,16 +3363,32 @@
   // optional .google.protobuf.MessageOptions options = 7;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      7, this->options(), output);
+      7, *this->options_, output);
   }
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  for (int i = 0; i < this->oneof_decl_size(); i++) {
+  for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       8, this->oneof_decl(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      9, this->reserved_range(i), output);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->reserved_name(i).data(), this->reserved_name(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.reserved_name");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      10, this->reserved_name(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -2269,42 +3403,42 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.DescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  for (int i = 0; i < this->field_size(); i++) {
+  for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         2, this->field(i), target);
   }
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  for (int i = 0; i < this->nested_type_size(); i++) {
+  for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         3, this->nested_type(i), target);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  for (int i = 0; i < this->enum_type_size(); i++) {
+  for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         4, this->enum_type(i), target);
   }
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  for (int i = 0; i < this->extension_range_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         5, this->extension_range(i), target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  for (int i = 0; i < this->extension_size(); i++) {
+  for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         6, this->extension(i), target);
@@ -2314,17 +3448,34 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        7, this->options(), target);
+        7, *this->options_, target);
   }
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  for (int i = 0; i < this->oneof_decl_size(); i++) {
+  for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         8, this->oneof_decl(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        9, this->reserved_range(i), target);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->reserved_name(i).data(), this->reserved_name(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.reserved_name");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(10, this->reserved_name(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -2333,9 +3484,10 @@
 }
 
 int DescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 129u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -2347,7 +3499,7 @@
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
   }
@@ -2399,7 +3551,22 @@
         this->oneof_decl(i));
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  total_size += 1 * this->reserved_range_size();
+  for (int i = 0; i < this->reserved_range_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->reserved_range(i));
+  }
+
+  // repeated string reserved_name = 10;
+  total_size += 1 * this->reserved_name_size();
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->reserved_name(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -2411,43 +3578,54 @@
 }
 
 void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const DescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void DescriptorProto::MergeFrom(const DescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   field_.MergeFrom(from.field_);
   extension_.MergeFrom(from.extension_);
   nested_type_.MergeFrom(from.nested_type_);
   enum_type_.MergeFrom(from.enum_type_);
   extension_range_.MergeFrom(from.extension_range_);
   oneof_decl_.MergeFrom(from.oneof_decl_);
+  reserved_range_.MergeFrom(from.reserved_range_);
+  reserved_name_.MergeFrom(from.reserved_name_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::MessageOptions::MergeFrom(from.options());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void DescriptorProto::CopyFrom(const DescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -2460,25 +3638,29 @@
   if (!::google::protobuf::internal::AllAreInitialized(this->nested_type())) return false;
   if (!::google::protobuf::internal::AllAreInitialized(this->enum_type())) return false;
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void DescriptorProto::Swap(DescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    field_.Swap(&other->field_);
-    extension_.Swap(&other->extension_);
-    nested_type_.Swap(&other->nested_type_);
-    enum_type_.Swap(&other->enum_type_);
-    extension_range_.Swap(&other->extension_range_);
-    oneof_decl_.Swap(&other->oneof_decl_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DescriptorProto::InternalSwap(DescriptorProto* other) {
+  name_.Swap(&other->name_);
+  field_.UnsafeArenaSwap(&other->field_);
+  extension_.UnsafeArenaSwap(&other->extension_);
+  nested_type_.UnsafeArenaSwap(&other->nested_type_);
+  enum_type_.UnsafeArenaSwap(&other->enum_type_);
+  extension_range_.UnsafeArenaSwap(&other->extension_range_);
+  oneof_decl_.UnsafeArenaSwap(&other->oneof_decl_);
+  std::swap(options_, other->options_);
+  reserved_range_.UnsafeArenaSwap(&other->reserved_range_);
+  reserved_name_.UnsafeArenaSwap(&other->reserved_name_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata DescriptorProto::GetMetadata() const {
@@ -2489,6 +3671,477 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DescriptorProto_ExtensionRange
+
+// optional int32 start = 1;
+bool DescriptorProto_ExtensionRange::has_start() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DescriptorProto_ExtensionRange::set_has_start() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DescriptorProto_ExtensionRange::clear_has_start() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DescriptorProto_ExtensionRange::clear_start() {
+  start_ = 0;
+  clear_has_start();
+}
+ ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.start)
+  return start_;
+}
+ void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) {
+  set_has_start();
+  start_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.start)
+}
+
+// optional int32 end = 2;
+bool DescriptorProto_ExtensionRange::has_end() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void DescriptorProto_ExtensionRange::set_has_end() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void DescriptorProto_ExtensionRange::clear_has_end() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void DescriptorProto_ExtensionRange::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+ ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ExtensionRange.end)
+  return end_;
+}
+ void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ExtensionRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+bool DescriptorProto_ReservedRange::has_start() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DescriptorProto_ReservedRange::set_has_start() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DescriptorProto_ReservedRange::clear_has_start() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DescriptorProto_ReservedRange::clear_start() {
+  start_ = 0;
+  clear_has_start();
+}
+ ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return start_;
+}
+ void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) {
+  set_has_start();
+  start_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+bool DescriptorProto_ReservedRange::has_end() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void DescriptorProto_ReservedRange::set_has_end() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void DescriptorProto_ReservedRange::clear_has_end() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void DescriptorProto_ReservedRange::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+ ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return end_;
+}
+ void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
+// DescriptorProto
+
+// optional string name = 1;
+bool DescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& DescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void DescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.name)
+}
+ void DescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.name)
+}
+ void DescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.name)
+}
+ ::std::string* DescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* DescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void DescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
+}
+
+// repeated .google.protobuf.FieldDescriptorProto field = 2;
+int DescriptorProto::field_size() const {
+  return field_.size();
+}
+void DescriptorProto::clear_field() {
+  field_.Clear();
+}
+const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field)
+  return field_.Get(index);
+}
+::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field)
+  return field_.Mutable(index);
+}
+::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
+  return field_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_field() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
+  return &field_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::field() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
+  return field_;
+}
+
+// repeated .google.protobuf.FieldDescriptorProto extension = 6;
+int DescriptorProto::extension_size() const {
+  return extension_.size();
+}
+void DescriptorProto::clear_extension() {
+  extension_.Clear();
+}
+const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension)
+  return extension_.Get(index);
+}
+::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension)
+  return extension_.Mutable(index);
+}
+::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
+  return extension_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+DescriptorProto::mutable_extension() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
+  return &extension_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
+  return extension_;
+}
+
+// repeated .google.protobuf.DescriptorProto nested_type = 3;
+int DescriptorProto::nested_type_size() const {
+  return nested_type_.size();
+}
+void DescriptorProto::clear_nested_type() {
+  nested_type_.Clear();
+}
+const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type)
+  return nested_type_.Get(index);
+}
+::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type)
+  return nested_type_.Mutable(index);
+}
+::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
+  return nested_type_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+DescriptorProto::mutable_nested_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
+  return &nested_type_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+DescriptorProto::nested_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
+  return nested_type_;
+}
+
+// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
+int DescriptorProto::enum_type_size() const {
+  return enum_type_.size();
+}
+void DescriptorProto::clear_enum_type() {
+  enum_type_.Clear();
+}
+const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type)
+  return enum_type_.Get(index);
+}
+::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type)
+  return enum_type_.Mutable(index);
+}
+::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
+  return enum_type_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+DescriptorProto::mutable_enum_type() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
+  return &enum_type_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
+  return enum_type_;
+}
+
+// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
+int DescriptorProto::extension_range_size() const {
+  return extension_range_.size();
+}
+void DescriptorProto::clear_extension_range() {
+  extension_range_.Clear();
+}
+const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range)
+  return extension_range_.Get(index);
+}
+::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range)
+  return extension_range_.Mutable(index);
+}
+::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
+  return extension_range_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+DescriptorProto::mutable_extension_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
+  return &extension_range_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
+  return extension_range_;
+}
+
+// repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
+int DescriptorProto::oneof_decl_size() const {
+  return oneof_decl_.size();
+}
+void DescriptorProto::clear_oneof_decl() {
+  oneof_decl_.Clear();
+}
+const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl)
+  return oneof_decl_.Get(index);
+}
+::google::protobuf::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl)
+  return oneof_decl_.Mutable(index);
+}
+::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
+  return oneof_decl_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+DescriptorProto::mutable_oneof_decl() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
+  return &oneof_decl_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+  return oneof_decl_;
+}
+
+// optional .google.protobuf.MessageOptions options = 7;
+bool DescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void DescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void DescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void DescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::MessageOptions& DescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::MessageOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
+  return options_;
+}
+::google::protobuf::MessageOptions* DescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::MessageOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
+}
+
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+int DescriptorProto::reserved_range_size() const {
+  return reserved_range_.size();
+}
+void DescriptorProto::clear_reserved_range() {
+  reserved_range_.Clear();
+}
+const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Get(index);
+}
+::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Mutable(index);
+}
+::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &reserved_range_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+int DescriptorProto::reserved_name_size() const {
+  return reserved_name_.size();
+}
+void DescriptorProto::clear_reserved_name() {
+  reserved_name_.Clear();
+}
+ const ::std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Get(index);
+}
+ ::std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Mutable(index);
+}
+ void DescriptorProto::set_reserved_name(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+  reserved_name_.Mutable(index)->assign(value);
+}
+ void DescriptorProto::set_reserved_name(int index, const char* value) {
+  reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+ ::std::string* DescriptorProto::add_reserved_name() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Add();
+}
+ void DescriptorProto::add_reserved_name(const ::std::string& value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::add_reserved_name(const char* value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::add_reserved_name(const char* value, size_t size) {
+  reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &reserved_name_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
@@ -2522,7 +4175,7 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
@@ -2544,7 +4197,7 @@
 const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
 const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
 const int FieldDescriptorProto::Type_ARRAYSIZE;
-#endif  // _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
   protobuf_AssignDescriptorsOnce();
   return FieldDescriptorProto_Label_descriptor_;
@@ -2560,15 +4213,15 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
 const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
 const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
 const int FieldDescriptorProto::Label_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldDescriptorProto::kNameFieldNumber;
 const int FieldDescriptorProto::kNumberFieldNumber;
 const int FieldDescriptorProto::kLabelFieldNumber;
@@ -2577,11 +4230,12 @@
 const int FieldDescriptorProto::kExtendeeFieldNumber;
 const int FieldDescriptorProto::kDefaultValueFieldNumber;
 const int FieldDescriptorProto::kOneofIndexFieldNumber;
+const int FieldDescriptorProto::kJsonNameFieldNumber;
 const int FieldDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldDescriptorProto::FieldDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldDescriptorProto)
 }
@@ -2591,7 +4245,8 @@
 }
 
 FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldDescriptorProto)
@@ -2600,14 +4255,15 @@
 void FieldDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   number_ = 0;
   label_ = 1;
   type_ = 1;
-  type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   oneof_index_ = 0;
+  json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -2618,18 +4274,11 @@
 }
 
 void FieldDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete type_name_;
-  }
-  if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete extendee_;
-  }
-  if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete default_value_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -2652,47 +4301,51 @@
 
 FieldDescriptorProto* FieldDescriptorProto::default_instance_ = NULL;
 
-FieldDescriptorProto* FieldDescriptorProto::New() const {
-  return new FieldDescriptorProto;
+FieldDescriptorProto* FieldDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  FieldDescriptorProto* n = new FieldDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void FieldDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 255) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldDescriptorProto)
+  if (_has_bits_[0 / 32] & 255u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     number_ = 0;
     label_ = 1;
     type_ = 1;
     if (has_type_name()) {
-      if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        type_name_->clear();
-      }
+      type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_extendee()) {
-      if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        extendee_->clear();
-      }
+      extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_default_value()) {
-      if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        default_value_->clear();
-      }
+      default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     oneof_index_ = 0;
   }
-  if (has_options()) {
-    if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+  if (_has_bits_[8 / 32] & 768u) {
+    if (has_json_name()) {
+      json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_options()) {
+      if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+    }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool FieldDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.FieldDescriptorProto)
   for (;;) {
@@ -2708,7 +4361,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.FieldDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -2725,7 +4378,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->extendee().data(), this->extendee().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "extendee");
+            "google.protobuf.FieldDescriptorProto.extendee");
         } else {
           goto handle_unusual;
         }
@@ -2797,7 +4450,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->type_name().data(), this->type_name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "type_name");
+            "google.protobuf.FieldDescriptorProto.type_name");
         } else {
           goto handle_unusual;
         }
@@ -2814,7 +4467,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->default_value().data(), this->default_value().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "default_value");
+            "google.protobuf.FieldDescriptorProto.default_value");
         } else {
           goto handle_unusual;
         }
@@ -2846,6 +4499,23 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(82)) goto parse_json_name;
+        break;
+      }
+
+      // optional string json_name = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_json_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_json_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->json_name().data(), this->json_name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.FieldDescriptorProto.json_name");
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -2880,7 +4550,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.FieldDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
@@ -2890,7 +4560,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->extendee().data(), this->extendee().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "extendee");
+      "google.protobuf.FieldDescriptorProto.extendee");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       2, this->extendee(), output);
   }
@@ -2917,7 +4587,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->type_name().data(), this->type_name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "type_name");
+      "google.protobuf.FieldDescriptorProto.type_name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       6, this->type_name(), output);
   }
@@ -2927,7 +4597,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->default_value().data(), this->default_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "default_value");
+      "google.protobuf.FieldDescriptorProto.default_value");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       7, this->default_value(), output);
   }
@@ -2935,7 +4605,7 @@
   // optional .google.protobuf.FieldOptions options = 8;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      8, this->options(), output);
+      8, *this->options_, output);
   }
 
   // optional int32 oneof_index = 9;
@@ -2943,7 +4613,17 @@
     ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional string json_name = 10;
+  if (has_json_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      10, this->json_name(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -2958,7 +4638,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.FieldDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
@@ -2969,7 +4649,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->extendee().data(), this->extendee().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "extendee");
+      "google.protobuf.FieldDescriptorProto.extendee");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         2, this->extendee(), target);
@@ -2997,7 +4677,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->type_name().data(), this->type_name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "type_name");
+      "google.protobuf.FieldDescriptorProto.type_name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         6, this->type_name(), target);
@@ -3008,7 +4688,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->default_value().data(), this->default_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "default_value");
+      "google.protobuf.FieldDescriptorProto.default_value");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         7, this->default_value(), target);
@@ -3018,7 +4698,7 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        8, this->options(), target);
+        8, *this->options_, target);
   }
 
   // optional int32 oneof_index = 9;
@@ -3026,7 +4706,18 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional string json_name = 10;
+  if (has_json_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        10, this->json_name(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -3035,9 +4726,10 @@
 }
 
 int FieldDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 255u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -3093,16 +4785,23 @@
     }
 
   }
-  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+  if (_has_bits_[8 / 32] & 768u) {
+    // optional string json_name = 10;
+    if (has_json_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->json_name());
+    }
+
     // optional .google.protobuf.FieldOptions options = 8;
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -3114,22 +4813,27 @@
 }
 
 void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const FieldDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FieldDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_number()) {
       set_number(from.number());
@@ -3141,33 +4845,44 @@
       set_type(from.type());
     }
     if (from.has_type_name()) {
-      set_type_name(from.type_name());
+      set_has_type_name();
+      type_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_name_);
     }
     if (from.has_extendee()) {
-      set_extendee(from.extendee());
+      set_has_extendee();
+      extendee_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.extendee_);
     }
     if (from.has_default_value()) {
-      set_default_value(from.default_value());
+      set_has_default_value();
+      default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_);
     }
     if (from.has_oneof_index()) {
       set_oneof_index(from.oneof_index());
     }
   }
   if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_json_name()) {
+      set_has_json_name();
+      json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
+    }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -3176,26 +4891,29 @@
 bool FieldDescriptorProto::IsInitialized() const {
 
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void FieldDescriptorProto::Swap(FieldDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(number_, other->number_);
-    std::swap(label_, other->label_);
-    std::swap(type_, other->type_);
-    std::swap(type_name_, other->type_name_);
-    std::swap(extendee_, other->extendee_);
-    std::swap(default_value_, other->default_value_);
-    std::swap(oneof_index_, other->oneof_index_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  std::swap(number_, other->number_);
+  std::swap(label_, other->label_);
+  std::swap(type_, other->type_);
+  type_name_.Swap(&other->type_name_);
+  extendee_.Swap(&other->extendee_);
+  default_value_.Swap(&other->default_value_);
+  std::swap(oneof_index_, other->oneof_index_);
+  json_name_.Swap(&other->json_name_);
+  std::swap(options_, other->options_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata FieldDescriptorProto::GetMetadata() const {
@@ -3206,15 +4924,431 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldDescriptorProto
+
+// optional string name = 1;
+bool FieldDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FieldDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FieldDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FieldDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& FieldDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.name)
+}
+ void FieldDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.name)
+}
+ void FieldDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.name)
+}
+ ::std::string* FieldDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
+}
+
+// optional int32 number = 3;
+bool FieldDescriptorProto::has_number() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FieldDescriptorProto::set_has_number() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FieldDescriptorProto::clear_has_number() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FieldDescriptorProto::clear_number() {
+  number_ = 0;
+  clear_has_number();
+}
+ ::google::protobuf::int32 FieldDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.number)
+  return number_;
+}
+ void FieldDescriptorProto::set_number(::google::protobuf::int32 value) {
+  set_has_number();
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.number)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
+bool FieldDescriptorProto::has_label() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void FieldDescriptorProto::set_has_label() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void FieldDescriptorProto::clear_has_label() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void FieldDescriptorProto::clear_label() {
+  label_ = 1;
+  clear_has_label();
+}
+ ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.label)
+  return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_);
+}
+ void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) {
+  assert(::google::protobuf::FieldDescriptorProto_Label_IsValid(value));
+  set_has_label();
+  label_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.label)
+}
+
+// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
+bool FieldDescriptorProto::has_type() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void FieldDescriptorProto::set_has_type() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void FieldDescriptorProto::clear_has_type() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void FieldDescriptorProto::clear_type() {
+  type_ = 1;
+  clear_has_type();
+}
+ ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type)
+  return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_);
+}
+ void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) {
+  assert(::google::protobuf::FieldDescriptorProto_Type_IsValid(value));
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type)
+}
+
+// optional string type_name = 6;
+bool FieldDescriptorProto::has_type_name() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void FieldDescriptorProto::set_has_type_name() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void FieldDescriptorProto::clear_has_type_name() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void FieldDescriptorProto::clear_type_name() {
+  type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_type_name();
+}
+ const ::std::string& FieldDescriptorProto::type_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
+  return type_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_type_name(const ::std::string& value) {
+  set_has_type_name();
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name)
+}
+ void FieldDescriptorProto::set_type_name(const char* value) {
+  set_has_type_name();
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.type_name)
+}
+ void FieldDescriptorProto::set_type_name(const char* value, size_t size) {
+  set_has_type_name();
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.type_name)
+}
+ ::std::string* FieldDescriptorProto::mutable_type_name() {
+  set_has_type_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
+  return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_type_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name)
+  clear_has_type_name();
+  return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) {
+  if (type_name != NULL) {
+    set_has_type_name();
+  } else {
+    clear_has_type_name();
+  }
+  type_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
+}
+
+// optional string extendee = 2;
+bool FieldDescriptorProto::has_extendee() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void FieldDescriptorProto::set_has_extendee() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void FieldDescriptorProto::clear_has_extendee() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void FieldDescriptorProto::clear_extendee() {
+  extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_extendee();
+}
+ const ::std::string& FieldDescriptorProto::extendee() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
+  return extendee_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_extendee(const ::std::string& value) {
+  set_has_extendee();
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee)
+}
+ void FieldDescriptorProto::set_extendee(const char* value) {
+  set_has_extendee();
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.extendee)
+}
+ void FieldDescriptorProto::set_extendee(const char* value, size_t size) {
+  set_has_extendee();
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.extendee)
+}
+ ::std::string* FieldDescriptorProto::mutable_extendee() {
+  set_has_extendee();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
+  return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_extendee() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee)
+  clear_has_extendee();
+  return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) {
+  if (extendee != NULL) {
+    set_has_extendee();
+  } else {
+    clear_has_extendee();
+  }
+  extendee_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extendee);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
+}
+
+// optional string default_value = 7;
+bool FieldDescriptorProto::has_default_value() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void FieldDescriptorProto::set_has_default_value() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void FieldDescriptorProto::clear_has_default_value() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void FieldDescriptorProto::clear_default_value() {
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_default_value();
+}
+ const ::std::string& FieldDescriptorProto::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_default_value(const ::std::string& value) {
+  set_has_default_value();
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value)
+}
+ void FieldDescriptorProto::set_default_value(const char* value) {
+  set_has_default_value();
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.default_value)
+}
+ void FieldDescriptorProto::set_default_value(const char* value, size_t size) {
+  set_has_default_value();
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.default_value)
+}
+ ::std::string* FieldDescriptorProto::mutable_default_value() {
+  set_has_default_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value)
+  clear_has_default_value();
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) {
+  if (default_value != NULL) {
+    set_has_default_value();
+  } else {
+    clear_has_default_value();
+  }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
+}
+
+// optional int32 oneof_index = 9;
+bool FieldDescriptorProto::has_oneof_index() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void FieldDescriptorProto::set_has_oneof_index() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void FieldDescriptorProto::clear_has_oneof_index() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void FieldDescriptorProto::clear_oneof_index() {
+  oneof_index_ = 0;
+  clear_has_oneof_index();
+}
+ ::google::protobuf::int32 FieldDescriptorProto::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.oneof_index)
+  return oneof_index_;
+}
+ void FieldDescriptorProto::set_oneof_index(::google::protobuf::int32 value) {
+  set_has_oneof_index();
+  oneof_index_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
+}
+
+// optional string json_name = 10;
+bool FieldDescriptorProto::has_json_name() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void FieldDescriptorProto::set_has_json_name() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void FieldDescriptorProto::clear_has_json_name() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void FieldDescriptorProto::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_json_name();
+}
+ const ::std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_json_name(const ::std::string& value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+ void FieldDescriptorProto::set_json_name(const char* value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
+}
+ void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
+}
+ ::std::string* FieldDescriptorProto::mutable_json_name() {
+  set_has_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name)
+  clear_has_json_name();
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    set_has_json_name();
+  } else {
+    clear_has_json_name();
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+bool FieldDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void FieldDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void FieldDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void FieldDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::FieldOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::FieldOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.options)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int OneofDescriptorProto::kNameFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 OneofDescriptorProto::OneofDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto)
 }
@@ -3223,7 +5357,8 @@
 }
 
 OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofDescriptorProto)
@@ -3232,7 +5367,7 @@
 void OneofDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -3242,9 +5377,7 @@
 }
 
 void OneofDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -3266,23 +5399,28 @@
 
 OneofDescriptorProto* OneofDescriptorProto::default_instance_ = NULL;
 
-OneofDescriptorProto* OneofDescriptorProto::New() const {
-  return new OneofDescriptorProto;
+OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  OneofDescriptorProto* n = new OneofDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void OneofDescriptorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto)
   if (has_name()) {
-    if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-      name_->clear();
-    }
+    name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool OneofDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.OneofDescriptorProto)
   for (;;) {
@@ -3298,7 +5436,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.OneofDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -3336,12 +5474,12 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.OneofDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -3356,13 +5494,13 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.OneofDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -3371,18 +5509,17 @@
 }
 
 int OneofDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // optional string name = 1;
-    if (has_name()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->name());
-    }
-
+  // optional string name = 1;
+  if (has_name()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
   }
-  if (!unknown_fields().empty()) {
+
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -3394,34 +5531,43 @@
 }
 
 void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const OneofDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const OneofDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OneofDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const OneofDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.OneofDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.OneofDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void OneofDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.OneofDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -3433,12 +5579,14 @@
 }
 
 void OneofDescriptorProto::Swap(OneofDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata OneofDescriptorProto::GetMetadata() const {
@@ -3449,17 +5597,75 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OneofDescriptorProto
+
+// optional string name = 1;
+bool OneofDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void OneofDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void OneofDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void OneofDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& OneofDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void OneofDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
+}
+ void OneofDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.OneofDescriptorProto.name)
+}
+ void OneofDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.OneofDescriptorProto.name)
+}
+ ::std::string* OneofDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* OneofDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void OneofDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumDescriptorProto::kNameFieldNumber;
 const int EnumDescriptorProto::kValueFieldNumber;
 const int EnumDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumDescriptorProto::EnumDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumDescriptorProto)
 }
@@ -3469,7 +5675,8 @@
 }
 
 EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumDescriptorProto)
@@ -3478,7 +5685,7 @@
 void EnumDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -3489,9 +5696,7 @@
 }
 
 void EnumDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -3514,16 +5719,19 @@
 
 EnumDescriptorProto* EnumDescriptorProto::default_instance_ = NULL;
 
-EnumDescriptorProto* EnumDescriptorProto::New() const {
-  return new EnumDescriptorProto;
+EnumDescriptorProto* EnumDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  EnumDescriptorProto* n = new EnumDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void EnumDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 5) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto)
+  if (_has_bits_[0 / 32] & 5u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
@@ -3531,12 +5739,14 @@
   }
   value_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool EnumDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.EnumDescriptorProto)
   for (;;) {
@@ -3552,7 +5762,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.EnumDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -3564,12 +5774,15 @@
       case 2: {
         if (tag == 18) {
          parse_value:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_value()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_value;
+        if (input->ExpectTag(18)) goto parse_loop_value;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_options;
         break;
       }
@@ -3617,13 +5830,13 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.EnumDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
 
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  for (int i = 0; i < this->value_size(); i++) {
+  for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       2, this->value(i), output);
   }
@@ -3631,10 +5844,10 @@
   // optional .google.protobuf.EnumOptions options = 3;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, this->options(), output);
+      3, *this->options_, output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -3649,14 +5862,14 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.EnumDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  for (int i = 0; i < this->value_size(); i++) {
+  for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         2, this->value(i), target);
@@ -3666,10 +5879,10 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        3, this->options(), target);
+        3, *this->options_, target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -3678,9 +5891,10 @@
 }
 
 int EnumDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 5u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -3692,7 +5906,7 @@
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
   }
@@ -3704,7 +5918,7 @@
         this->value(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -3716,38 +5930,47 @@
 }
 
 void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const EnumDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   value_.MergeFrom(from.value_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::EnumOptions::MergeFrom(from.options());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -3757,20 +5980,22 @@
 
   if (!::google::protobuf::internal::AllAreInitialized(this->value())) return false;
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void EnumDescriptorProto::Swap(EnumDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    value_.Swap(&other->value_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  value_.UnsafeArenaSwap(&other->value_);
+  std::swap(options_, other->options_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata EnumDescriptorProto::GetMetadata() const {
@@ -3781,17 +6006,149 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumDescriptorProto
+
+// optional string name = 1;
+bool EnumDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void EnumDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void EnumDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void EnumDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& EnumDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.name)
+}
+ void EnumDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.name)
+}
+ void EnumDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.name)
+}
+ ::std::string* EnumDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* EnumDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
+}
+
+// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
+int EnumDescriptorProto::value_size() const {
+  return value_.size();
+}
+void EnumDescriptorProto::clear_value() {
+  value_.Clear();
+}
+const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value)
+  return value_.Get(index);
+}
+::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value)
+  return value_.Mutable(index);
+}
+::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() {
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
+  return value_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+EnumDescriptorProto::mutable_value() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
+  return &value_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
+  return value_;
+}
+
+// optional .google.protobuf.EnumOptions options = 3;
+bool EnumDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void EnumDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void EnumDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void EnumDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::EnumOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::EnumOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.options)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumValueDescriptorProto::kNameFieldNumber;
 const int EnumValueDescriptorProto::kNumberFieldNumber;
 const int EnumValueDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumValueDescriptorProto::EnumValueDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueDescriptorProto)
 }
@@ -3801,7 +6158,8 @@
 }
 
 EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueDescriptorProto)
@@ -3810,7 +6168,7 @@
 void EnumValueDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   number_ = 0;
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -3822,9 +6180,7 @@
 }
 
 void EnumValueDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -3847,16 +6203,19 @@
 
 EnumValueDescriptorProto* EnumValueDescriptorProto::default_instance_ = NULL;
 
-EnumValueDescriptorProto* EnumValueDescriptorProto::New() const {
-  return new EnumValueDescriptorProto;
+EnumValueDescriptorProto* EnumValueDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  EnumValueDescriptorProto* n = new EnumValueDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void EnumValueDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 7) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueDescriptorProto)
+  if (_has_bits_[0 / 32] & 7u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     number_ = 0;
     if (has_options()) {
@@ -3864,12 +6223,14 @@
     }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool EnumValueDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueDescriptorProto)
   for (;;) {
@@ -3885,7 +6246,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.EnumValueDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -3951,7 +6312,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.EnumValueDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
@@ -3964,10 +6325,10 @@
   // optional .google.protobuf.EnumValueOptions options = 3;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, this->options(), output);
+      3, *this->options_, output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -3982,7 +6343,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.EnumValueDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
@@ -3997,10 +6358,10 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        3, this->options(), target);
+        3, *this->options_, target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -4009,9 +6370,10 @@
 }
 
 int EnumValueDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 7u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -4030,11 +6392,11 @@
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -4046,22 +6408,27 @@
 }
 
 void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const EnumValueDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumValueDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_number()) {
       set_number(from.number());
@@ -4070,16 +6437,20 @@
       mutable_options()->::google::protobuf::EnumValueOptions::MergeFrom(from.options());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -4088,20 +6459,22 @@
 bool EnumValueDescriptorProto::IsInitialized() const {
 
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void EnumValueDescriptorProto::Swap(EnumValueDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(number_, other->number_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  std::swap(number_, other->number_);
+  std::swap(options_, other->options_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata EnumValueDescriptorProto::GetMetadata() const {
@@ -4112,17 +6485,143 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumValueDescriptorProto
+
+// optional string name = 1;
+bool EnumValueDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void EnumValueDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void EnumValueDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void EnumValueDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& EnumValueDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValueDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.name)
+}
+ void EnumValueDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValueDescriptorProto.name)
+}
+ void EnumValueDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValueDescriptorProto.name)
+}
+ ::std::string* EnumValueDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* EnumValueDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValueDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
+}
+
+// optional int32 number = 2;
+bool EnumValueDescriptorProto::has_number() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void EnumValueDescriptorProto::set_has_number() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void EnumValueDescriptorProto::clear_has_number() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void EnumValueDescriptorProto::clear_number() {
+  number_ = 0;
+  clear_has_number();
+}
+ ::google::protobuf::int32 EnumValueDescriptorProto::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.number)
+  return number_;
+}
+ void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) {
+  set_has_number();
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.number)
+}
+
+// optional .google.protobuf.EnumValueOptions options = 3;
+bool EnumValueDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void EnumValueDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void EnumValueDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void EnumValueDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::EnumValueOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::EnumValueOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.options)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int ServiceDescriptorProto::kNameFieldNumber;
 const int ServiceDescriptorProto::kMethodFieldNumber;
 const int ServiceDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 ServiceDescriptorProto::ServiceDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceDescriptorProto)
 }
@@ -4132,7 +6631,8 @@
 }
 
 ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceDescriptorProto)
@@ -4141,7 +6641,7 @@
 void ServiceDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -4152,9 +6652,7 @@
 }
 
 void ServiceDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -4177,16 +6675,19 @@
 
 ServiceDescriptorProto* ServiceDescriptorProto::default_instance_ = NULL;
 
-ServiceDescriptorProto* ServiceDescriptorProto::New() const {
-  return new ServiceDescriptorProto;
+ServiceDescriptorProto* ServiceDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  ServiceDescriptorProto* n = new ServiceDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void ServiceDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 5) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceDescriptorProto)
+  if (_has_bits_[0 / 32] & 5u) {
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
@@ -4194,12 +6695,14 @@
   }
   method_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool ServiceDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.ServiceDescriptorProto)
   for (;;) {
@@ -4215,7 +6718,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.ServiceDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -4227,12 +6730,15 @@
       case 2: {
         if (tag == 18) {
          parse_method:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_method:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_method()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_method;
+        if (input->ExpectTag(18)) goto parse_loop_method;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_options;
         break;
       }
@@ -4280,13 +6786,13 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.ServiceDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
 
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  for (int i = 0; i < this->method_size(); i++) {
+  for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       2, this->method(i), output);
   }
@@ -4294,10 +6800,10 @@
   // optional .google.protobuf.ServiceOptions options = 3;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, this->options(), output);
+      3, *this->options_, output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -4312,14 +6818,14 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.ServiceDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  for (int i = 0; i < this->method_size(); i++) {
+  for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         2, this->method(i), target);
@@ -4329,10 +6835,10 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        3, this->options(), target);
+        3, *this->options_, target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -4341,9 +6847,10 @@
 }
 
 int ServiceDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 5u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -4355,7 +6862,7 @@
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
     }
 
   }
@@ -4367,7 +6874,7 @@
         this->method(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -4379,38 +6886,47 @@
 }
 
 void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const ServiceDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ServiceDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   method_.MergeFrom(from.method_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::ServiceOptions::MergeFrom(from.options());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -4420,20 +6936,22 @@
 
   if (!::google::protobuf::internal::AllAreInitialized(this->method())) return false;
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void ServiceDescriptorProto::Swap(ServiceDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    method_.Swap(&other->method_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  method_.UnsafeArenaSwap(&other->method_);
+  std::swap(options_, other->options_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata ServiceDescriptorProto::GetMetadata() const {
@@ -4444,18 +6962,152 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServiceDescriptorProto
+
+// optional string name = 1;
+bool ServiceDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ServiceDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ServiceDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ServiceDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& ServiceDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceDescriptorProto.name)
+}
+ void ServiceDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.ServiceDescriptorProto.name)
+}
+ void ServiceDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.ServiceDescriptorProto.name)
+}
+ ::std::string* ServiceDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServiceDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
+}
+
+// repeated .google.protobuf.MethodDescriptorProto method = 2;
+int ServiceDescriptorProto::method_size() const {
+  return method_.size();
+}
+void ServiceDescriptorProto::clear_method() {
+  method_.Clear();
+}
+const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method)
+  return method_.Get(index);
+}
+::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method)
+  return method_.Mutable(index);
+}
+::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() {
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
+  return method_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+ServiceDescriptorProto::mutable_method() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
+  return &method_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
+  return method_;
+}
+
+// optional .google.protobuf.ServiceOptions options = 3;
+bool ServiceDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ServiceDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ServiceDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ServiceDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::ServiceOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::ServiceOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.options)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MethodDescriptorProto::kNameFieldNumber;
 const int MethodDescriptorProto::kInputTypeFieldNumber;
 const int MethodDescriptorProto::kOutputTypeFieldNumber;
 const int MethodDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+const int MethodDescriptorProto::kClientStreamingFieldNumber;
+const int MethodDescriptorProto::kServerStreamingFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MethodDescriptorProto::MethodDescriptorProto()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto)
 }
@@ -4465,7 +7117,8 @@
 }
 
 MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodDescriptorProto)
@@ -4474,10 +7127,12 @@
 void MethodDescriptorProto::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  input_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  output_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
+  client_streaming_ = false;
+  server_streaming_ = false;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -4487,15 +7142,9 @@
 }
 
 void MethodDescriptorProto::SharedDtor() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete input_type_;
-  }
-  if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete output_type_;
-  }
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  input_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  output_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -4518,38 +7167,60 @@
 
 MethodDescriptorProto* MethodDescriptorProto::default_instance_ = NULL;
 
-MethodDescriptorProto* MethodDescriptorProto::New() const {
-  return new MethodDescriptorProto;
+MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* arena) const {
+  MethodDescriptorProto* n = new MethodDescriptorProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MethodDescriptorProto::Clear() {
-  if (_has_bits_[0 / 32] & 15) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodDescriptorProto)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MethodDescriptorProto, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MethodDescriptorProto*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 63u) {
+    ZR_(client_streaming_, server_streaming_);
     if (has_name()) {
-      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_->clear();
-      }
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_input_type()) {
-      if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        input_type_->clear();
-      }
+      input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_output_type()) {
-      if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        output_type_->clear();
-      }
+      output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_options()) {
       if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
     }
   }
+
+#undef ZR_HELPER_
+#undef ZR_
+
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MethodDescriptorProto::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.MethodDescriptorProto)
   for (;;) {
@@ -4565,7 +7236,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name().data(), this->name().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name");
+            "google.protobuf.MethodDescriptorProto.name");
         } else {
           goto handle_unusual;
         }
@@ -4582,7 +7253,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->input_type().data(), this->input_type().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "input_type");
+            "google.protobuf.MethodDescriptorProto.input_type");
         } else {
           goto handle_unusual;
         }
@@ -4599,7 +7270,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->output_type().data(), this->output_type().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "output_type");
+            "google.protobuf.MethodDescriptorProto.output_type");
         } else {
           goto handle_unusual;
         }
@@ -4616,6 +7287,36 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(40)) goto parse_client_streaming;
+        break;
+      }
+
+      // optional bool client_streaming = 5 [default = false];
+      case 5: {
+        if (tag == 40) {
+         parse_client_streaming:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &client_streaming_)));
+          set_has_client_streaming();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_server_streaming;
+        break;
+      }
+
+      // optional bool server_streaming = 6 [default = false];
+      case 6: {
+        if (tag == 48) {
+         parse_server_streaming:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &server_streaming_)));
+          set_has_server_streaming();
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -4650,7 +7351,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.MethodDescriptorProto.name");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name(), output);
   }
@@ -4660,7 +7361,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->input_type().data(), this->input_type().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "input_type");
+      "google.protobuf.MethodDescriptorProto.input_type");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       2, this->input_type(), output);
   }
@@ -4670,7 +7371,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->output_type().data(), this->output_type().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "output_type");
+      "google.protobuf.MethodDescriptorProto.output_type");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       3, this->output_type(), output);
   }
@@ -4678,10 +7379,20 @@
   // optional .google.protobuf.MethodOptions options = 4;
   if (has_options()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4, this->options(), output);
+      4, *this->options_, output);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional bool client_streaming = 5 [default = false];
+  if (has_client_streaming()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->client_streaming(), output);
+  }
+
+  // optional bool server_streaming = 6 [default = false];
+  if (has_server_streaming()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->server_streaming(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -4696,7 +7407,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name");
+      "google.protobuf.MethodDescriptorProto.name");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name(), target);
@@ -4707,7 +7418,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->input_type().data(), this->input_type().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "input_type");
+      "google.protobuf.MethodDescriptorProto.input_type");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         2, this->input_type(), target);
@@ -4718,7 +7429,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->output_type().data(), this->output_type().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "output_type");
+      "google.protobuf.MethodDescriptorProto.output_type");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         3, this->output_type(), target);
@@ -4728,10 +7439,20 @@
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
-        4, this->options(), target);
+        4, *this->options_, target);
   }
 
-  if (!unknown_fields().empty()) {
+  // optional bool client_streaming = 5 [default = false];
+  if (has_client_streaming()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->client_streaming(), target);
+  }
+
+  // optional bool server_streaming = 6 [default = false];
+  if (has_server_streaming()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->server_streaming(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -4740,9 +7461,10 @@
 }
 
 int MethodDescriptorProto::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 63u) {
     // optional string name = 1;
     if (has_name()) {
       total_size += 1 +
@@ -4768,11 +7490,21 @@
     if (has_options()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-          this->options());
+          *this->options_);
+    }
+
+    // optional bool client_streaming = 5 [default = false];
+    if (has_client_streaming()) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool server_streaming = 6 [default = false];
+    if (has_server_streaming()) {
+      total_size += 1 + 1;
     }
 
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -4784,43 +7516,60 @@
 }
 
 void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MethodDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodDescriptorProto*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const MethodDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodDescriptorProto>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodDescriptorProto)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodDescriptorProto)
     MergeFrom(*source);
   }
 }
 
 void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
-      set_name(from.name());
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
     if (from.has_input_type()) {
-      set_input_type(from.input_type());
+      set_has_input_type();
+      input_type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.input_type_);
     }
     if (from.has_output_type()) {
-      set_output_type(from.output_type());
+      set_has_output_type();
+      output_type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.output_type_);
     }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options());
     }
+    if (from.has_client_streaming()) {
+      set_client_streaming(from.client_streaming());
+    }
+    if (from.has_server_streaming()) {
+      set_server_streaming(from.server_streaming());
+    }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodDescriptorProto)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -4829,21 +7578,25 @@
 bool MethodDescriptorProto::IsInitialized() const {
 
   if (has_options()) {
-    if (!this->options().IsInitialized()) return false;
+    if (!this->options_->IsInitialized()) return false;
   }
   return true;
 }
 
 void MethodDescriptorProto::Swap(MethodDescriptorProto* other) {
-  if (other != this) {
-    std::swap(name_, other->name_);
-    std::swap(input_type_, other->input_type_);
-    std::swap(output_type_, other->output_type_);
-    std::swap(options_, other->options_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) {
+  name_.Swap(&other->name_);
+  input_type_.Swap(&other->input_type_);
+  output_type_.Swap(&other->output_type_);
+  std::swap(options_, other->options_);
+  std::swap(client_streaming_, other->client_streaming_);
+  std::swap(server_streaming_, other->server_streaming_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata MethodDescriptorProto::GetMetadata() const {
@@ -4854,6 +7607,264 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MethodDescriptorProto
+
+// optional string name = 1;
+bool MethodDescriptorProto::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MethodDescriptorProto::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MethodDescriptorProto::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MethodDescriptorProto::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& MethodDescriptorProto::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.name)
+}
+ void MethodDescriptorProto::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.name)
+}
+ void MethodDescriptorProto::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.name)
+}
+ ::std::string* MethodDescriptorProto::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
+}
+
+// optional string input_type = 2;
+bool MethodDescriptorProto::has_input_type() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MethodDescriptorProto::set_has_input_type() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MethodDescriptorProto::clear_has_input_type() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MethodDescriptorProto::clear_input_type() {
+  input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_input_type();
+}
+ const ::std::string& MethodDescriptorProto::input_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
+  return input_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_input_type(const ::std::string& value) {
+  set_has_input_type();
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type)
+}
+ void MethodDescriptorProto::set_input_type(const char* value) {
+  set_has_input_type();
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.input_type)
+}
+ void MethodDescriptorProto::set_input_type(const char* value, size_t size) {
+  set_has_input_type();
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.input_type)
+}
+ ::std::string* MethodDescriptorProto::mutable_input_type() {
+  set_has_input_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
+  return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_input_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type)
+  clear_has_input_type();
+  return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) {
+  if (input_type != NULL) {
+    set_has_input_type();
+  } else {
+    clear_has_input_type();
+  }
+  input_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), input_type);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
+}
+
+// optional string output_type = 3;
+bool MethodDescriptorProto::has_output_type() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void MethodDescriptorProto::set_has_output_type() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void MethodDescriptorProto::clear_has_output_type() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void MethodDescriptorProto::clear_output_type() {
+  output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_output_type();
+}
+ const ::std::string& MethodDescriptorProto::output_type() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
+  return output_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_output_type(const ::std::string& value) {
+  set_has_output_type();
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type)
+}
+ void MethodDescriptorProto::set_output_type(const char* value) {
+  set_has_output_type();
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.output_type)
+}
+ void MethodDescriptorProto::set_output_type(const char* value, size_t size) {
+  set_has_output_type();
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.output_type)
+}
+ ::std::string* MethodDescriptorProto::mutable_output_type() {
+  set_has_output_type();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
+  return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* MethodDescriptorProto::release_output_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type)
+  clear_has_output_type();
+  return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) {
+  if (output_type != NULL) {
+    set_has_output_type();
+  } else {
+    clear_has_output_type();
+  }
+  output_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), output_type);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
+}
+
+// optional .google.protobuf.MethodOptions options = 4;
+bool MethodDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void MethodDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void MethodDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void MethodDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::MethodOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::MethodOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
+}
+
+// optional bool client_streaming = 5 [default = false];
+bool MethodDescriptorProto::has_client_streaming() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void MethodDescriptorProto::set_has_client_streaming() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void MethodDescriptorProto::clear_has_client_streaming() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void MethodDescriptorProto::clear_client_streaming() {
+  client_streaming_ = false;
+  clear_has_client_streaming();
+}
+ bool MethodDescriptorProto::client_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+  return client_streaming_;
+}
+ void MethodDescriptorProto::set_client_streaming(bool value) {
+  set_has_client_streaming();
+  client_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+bool MethodDescriptorProto::has_server_streaming() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void MethodDescriptorProto::set_has_server_streaming() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void MethodDescriptorProto::clear_has_server_streaming() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void MethodDescriptorProto::clear_server_streaming() {
+  server_streaming_ = false;
+  clear_has_server_streaming();
+}
+ bool MethodDescriptorProto::server_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+  return server_streaming_;
+}
+ void MethodDescriptorProto::set_server_streaming(bool value) {
+  set_has_server_streaming();
+  server_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
@@ -4872,15 +7883,15 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FileOptions_OptimizeMode FileOptions::SPEED;
 const FileOptions_OptimizeMode FileOptions::CODE_SIZE;
 const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
 const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
 const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
 const int FileOptions::OptimizeMode_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileOptions::kJavaPackageFieldNumber;
 const int FileOptions::kJavaOuterClassnameFieldNumber;
 const int FileOptions::kJavaMultipleFilesFieldNumber;
@@ -4892,12 +7903,14 @@
 const int FileOptions::kJavaGenericServicesFieldNumber;
 const int FileOptions::kPyGenericServicesFieldNumber;
 const int FileOptions::kDeprecatedFieldNumber;
-const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber;
+const int FileOptions::kCcEnableArenasFieldNumber;
+const int FileOptions::kObjcClassPrefixFieldNumber;
+const int FileOptions::kCsharpNamespaceFieldNumber;
 const int FileOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileOptions::FileOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileOptions)
 }
@@ -4906,7 +7919,8 @@
 }
 
 FileOptions::FileOptions(const FileOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FileOptions)
@@ -4915,18 +7929,20 @@
 void FileOptions::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  java_package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  java_outer_classname_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   java_multiple_files_ = false;
   java_generate_equals_and_hash_ = false;
   java_string_check_utf8_ = false;
   optimize_for_ = 1;
-  go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  go_package_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   cc_generic_services_ = false;
   java_generic_services_ = false;
   py_generic_services_ = false;
   deprecated_ = false;
-  javanano_use_deprecated_package_ = false;
+  cc_enable_arenas_ = false;
+  objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  csharp_namespace_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -4936,15 +7952,11 @@
 }
 
 void FileOptions::SharedDtor() {
-  if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete java_package_;
-  }
-  if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete java_outer_classname_;
-  }
-  if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete go_package_;
-  }
+  java_package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  java_outer_classname_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  go_package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  objc_class_prefix_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  csharp_namespace_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -4966,54 +7978,69 @@
 
 FileOptions* FileOptions::default_instance_ = NULL;
 
-FileOptions* FileOptions::New() const {
-  return new FileOptions;
+FileOptions* FileOptions::New(::google::protobuf::Arena* arena) const {
+  FileOptions* n = new FileOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void FileOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FileOptions)
   _extensions_.Clear();
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<FileOptions*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(FileOptions, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<FileOptions*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
-  if (_has_bits_[0 / 32] & 255) {
+  if (_has_bits_[0 / 32] & 255u) {
     ZR_(java_multiple_files_, cc_generic_services_);
     if (has_java_package()) {
-      if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        java_package_->clear();
-      }
+      java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_java_outer_classname()) {
-      if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        java_outer_classname_->clear();
-      }
+      java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     optimize_for_ = 1;
     if (has_go_package()) {
-      if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        go_package_->clear();
-      }
+      go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
-  ZR_(java_generic_services_, javanano_use_deprecated_package_);
+  if (_has_bits_[8 / 32] & 16128u) {
+    ZR_(java_generic_services_, cc_enable_arenas_);
+    if (has_objc_class_prefix()) {
+      objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_csharp_namespace()) {
+      csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool FileOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.FileOptions)
   for (;;) {
@@ -5029,7 +8056,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->java_package().data(), this->java_package().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "java_package");
+            "google.protobuf.FileOptions.java_package");
         } else {
           goto handle_unusual;
         }
@@ -5046,7 +8073,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->java_outer_classname().data(), this->java_outer_classname().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "java_outer_classname");
+            "google.protobuf.FileOptions.java_outer_classname");
         } else {
           goto handle_unusual;
         }
@@ -5098,7 +8125,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->go_package().data(), this->go_package().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "go_package");
+            "google.protobuf.FileOptions.go_package");
         } else {
           goto handle_unusual;
         }
@@ -5192,18 +8219,52 @@
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(304)) goto parse_javanano_use_deprecated_package;
+        if (input->ExpectTag(248)) goto parse_cc_enable_arenas;
         break;
       }
 
-      // optional bool javanano_use_deprecated_package = 38;
-      case 38: {
-        if (tag == 304) {
-         parse_javanano_use_deprecated_package:
+      // optional bool cc_enable_arenas = 31 [default = false];
+      case 31: {
+        if (tag == 248) {
+         parse_cc_enable_arenas:
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
-                 input, &javanano_use_deprecated_package_)));
-          set_has_javanano_use_deprecated_package();
+                 input, &cc_enable_arenas_)));
+          set_has_cc_enable_arenas();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(290)) goto parse_objc_class_prefix;
+        break;
+      }
+
+      // optional string objc_class_prefix = 36;
+      case 36: {
+        if (tag == 290) {
+         parse_objc_class_prefix:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_objc_class_prefix()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.FileOptions.objc_class_prefix");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(298)) goto parse_csharp_namespace;
+        break;
+      }
+
+      // optional string csharp_namespace = 37;
+      case 37: {
+        if (tag == 298) {
+         parse_csharp_namespace:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_csharp_namespace()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->csharp_namespace().data(), this->csharp_namespace().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.FileOptions.csharp_namespace");
         } else {
           goto handle_unusual;
         }
@@ -5215,12 +8276,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -5260,7 +8324,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->java_package().data(), this->java_package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "java_package");
+      "google.protobuf.FileOptions.java_package");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->java_package(), output);
   }
@@ -5270,7 +8334,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->java_outer_classname().data(), this->java_outer_classname().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "java_outer_classname");
+      "google.protobuf.FileOptions.java_outer_classname");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       8, this->java_outer_classname(), output);
   }
@@ -5291,7 +8355,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->go_package().data(), this->go_package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "go_package");
+      "google.protobuf.FileOptions.go_package");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       11, this->go_package(), output);
   }
@@ -5326,13 +8390,33 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(27, this->java_string_check_utf8(), output);
   }
 
-  // optional bool javanano_use_deprecated_package = 38;
-  if (has_javanano_use_deprecated_package()) {
-    ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output);
+  // optional bool cc_enable_arenas = 31 [default = false];
+  if (has_cc_enable_arenas()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(31, this->cc_enable_arenas(), output);
+  }
+
+  // optional string objc_class_prefix = 36;
+  if (has_objc_class_prefix()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.objc_class_prefix");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      36, this->objc_class_prefix(), output);
+  }
+
+  // optional string csharp_namespace = 37;
+  if (has_csharp_namespace()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->csharp_namespace().data(), this->csharp_namespace().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.csharp_namespace");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      37, this->csharp_namespace(), output);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -5341,7 +8425,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -5356,7 +8440,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->java_package().data(), this->java_package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "java_package");
+      "google.protobuf.FileOptions.java_package");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->java_package(), target);
@@ -5367,7 +8451,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->java_outer_classname().data(), this->java_outer_classname().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "java_outer_classname");
+      "google.protobuf.FileOptions.java_outer_classname");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         8, this->java_outer_classname(), target);
@@ -5389,7 +8473,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->go_package().data(), this->go_package().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "go_package");
+      "google.protobuf.FileOptions.go_package");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         11, this->go_package(), target);
@@ -5425,13 +8509,35 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(27, this->java_string_check_utf8(), target);
   }
 
-  // optional bool javanano_use_deprecated_package = 38;
-  if (has_javanano_use_deprecated_package()) {
-    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target);
+  // optional bool cc_enable_arenas = 31 [default = false];
+  if (has_cc_enable_arenas()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(31, this->cc_enable_arenas(), target);
+  }
+
+  // optional string objc_class_prefix = 36;
+  if (has_objc_class_prefix()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->objc_class_prefix().data(), this->objc_class_prefix().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.objc_class_prefix");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        36, this->objc_class_prefix(), target);
+  }
+
+  // optional string csharp_namespace = 37;
+  if (has_csharp_namespace()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->csharp_namespace().data(), this->csharp_namespace().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FileOptions.csharp_namespace");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        37, this->csharp_namespace(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -5441,7 +8547,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -5450,9 +8556,10 @@
 }
 
 int FileOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 255u) {
     // optional string java_package = 1;
     if (has_java_package()) {
       total_size += 1 +
@@ -5501,7 +8608,7 @@
     }
 
   }
-  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+  if (_has_bits_[8 / 32] & 16128u) {
     // optional bool java_generic_services = 17 [default = false];
     if (has_java_generic_services()) {
       total_size += 2 + 1;
@@ -5517,11 +8624,25 @@
       total_size += 2 + 1;
     }
 
-    // optional bool javanano_use_deprecated_package = 38;
-    if (has_javanano_use_deprecated_package()) {
+    // optional bool cc_enable_arenas = 31 [default = false];
+    if (has_cc_enable_arenas()) {
       total_size += 2 + 1;
     }
 
+    // optional string objc_class_prefix = 36;
+    if (has_objc_class_prefix()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->objc_class_prefix());
+    }
+
+    // optional string csharp_namespace = 37;
+    if (has_csharp_namespace()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->csharp_namespace());
+    }
+
   }
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
@@ -5533,7 +8654,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -5545,26 +8666,32 @@
 }
 
 void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const FileOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FileOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileOptions)
     MergeFrom(*source);
   }
 }
 
 void FileOptions::MergeFrom(const FileOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_java_package()) {
-      set_java_package(from.java_package());
+      set_has_java_package();
+      java_package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.java_package_);
     }
     if (from.has_java_outer_classname()) {
-      set_java_outer_classname(from.java_outer_classname());
+      set_has_java_outer_classname();
+      java_outer_classname_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.java_outer_classname_);
     }
     if (from.has_java_multiple_files()) {
       set_java_multiple_files(from.java_multiple_files());
@@ -5579,7 +8706,8 @@
       set_optimize_for(from.optimize_for());
     }
     if (from.has_go_package()) {
-      set_go_package(from.go_package());
+      set_has_go_package();
+      go_package_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.go_package_);
     }
     if (from.has_cc_generic_services()) {
       set_cc_generic_services(from.cc_generic_services());
@@ -5595,21 +8723,33 @@
     if (from.has_deprecated()) {
       set_deprecated(from.deprecated());
     }
-    if (from.has_javanano_use_deprecated_package()) {
-      set_javanano_use_deprecated_package(from.javanano_use_deprecated_package());
+    if (from.has_cc_enable_arenas()) {
+      set_cc_enable_arenas(from.cc_enable_arenas());
+    }
+    if (from.has_objc_class_prefix()) {
+      set_has_objc_class_prefix();
+      objc_class_prefix_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.objc_class_prefix_);
+    }
+    if (from.has_csharp_namespace()) {
+      set_has_csharp_namespace();
+      csharp_namespace_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.csharp_namespace_);
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void FileOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void FileOptions::CopyFrom(const FileOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -5623,25 +8763,29 @@
 }
 
 void FileOptions::Swap(FileOptions* other) {
-  if (other != this) {
-    std::swap(java_package_, other->java_package_);
-    std::swap(java_outer_classname_, other->java_outer_classname_);
-    std::swap(java_multiple_files_, other->java_multiple_files_);
-    std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_);
-    std::swap(java_string_check_utf8_, other->java_string_check_utf8_);
-    std::swap(optimize_for_, other->optimize_for_);
-    std::swap(go_package_, other->go_package_);
-    std::swap(cc_generic_services_, other->cc_generic_services_);
-    std::swap(java_generic_services_, other->java_generic_services_);
-    std::swap(py_generic_services_, other->py_generic_services_);
-    std::swap(deprecated_, other->deprecated_);
-    std::swap(javanano_use_deprecated_package_, other->javanano_use_deprecated_package_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FileOptions::InternalSwap(FileOptions* other) {
+  java_package_.Swap(&other->java_package_);
+  java_outer_classname_.Swap(&other->java_outer_classname_);
+  std::swap(java_multiple_files_, other->java_multiple_files_);
+  std::swap(java_generate_equals_and_hash_, other->java_generate_equals_and_hash_);
+  std::swap(java_string_check_utf8_, other->java_string_check_utf8_);
+  std::swap(optimize_for_, other->optimize_for_);
+  go_package_.Swap(&other->go_package_);
+  std::swap(cc_generic_services_, other->cc_generic_services_);
+  std::swap(java_generic_services_, other->java_generic_services_);
+  std::swap(py_generic_services_, other->py_generic_services_);
+  std::swap(deprecated_, other->deprecated_);
+  std::swap(cc_enable_arenas_, other->cc_enable_arenas_);
+  objc_class_prefix_.Swap(&other->objc_class_prefix_);
+  csharp_namespace_.Swap(&other->csharp_namespace_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata FileOptions::GetMetadata() const {
@@ -5652,18 +8796,540 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileOptions
+
+// optional string java_package = 1;
+bool FileOptions::has_java_package() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FileOptions::set_has_java_package() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FileOptions::clear_has_java_package() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FileOptions::clear_java_package() {
+  java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_java_package();
+}
+ const ::std::string& FileOptions::java_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
+  return java_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_java_package(const ::std::string& value) {
+  set_has_java_package();
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package)
+}
+ void FileOptions::set_java_package(const char* value) {
+  set_has_java_package();
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_package)
+}
+ void FileOptions::set_java_package(const char* value, size_t size) {
+  set_has_java_package();
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_package)
+}
+ ::std::string* FileOptions::mutable_java_package() {
+  set_has_java_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
+  return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_java_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package)
+  clear_has_java_package();
+  return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_java_package(::std::string* java_package) {
+  if (java_package != NULL) {
+    set_has_java_package();
+  } else {
+    clear_has_java_package();
+  }
+  java_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_package);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
+}
+
+// optional string java_outer_classname = 8;
+bool FileOptions::has_java_outer_classname() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FileOptions::set_has_java_outer_classname() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FileOptions::clear_has_java_outer_classname() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FileOptions::clear_java_outer_classname() {
+  java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_java_outer_classname();
+}
+ const ::std::string& FileOptions::java_outer_classname() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
+  return java_outer_classname_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_java_outer_classname(const ::std::string& value) {
+  set_has_java_outer_classname();
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname)
+}
+ void FileOptions::set_java_outer_classname(const char* value) {
+  set_has_java_outer_classname();
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_outer_classname)
+}
+ void FileOptions::set_java_outer_classname(const char* value, size_t size) {
+  set_has_java_outer_classname();
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_outer_classname)
+}
+ ::std::string* FileOptions::mutable_java_outer_classname() {
+  set_has_java_outer_classname();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
+  return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_java_outer_classname() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname)
+  clear_has_java_outer_classname();
+  return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) {
+  if (java_outer_classname != NULL) {
+    set_has_java_outer_classname();
+  } else {
+    clear_has_java_outer_classname();
+  }
+  java_outer_classname_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_outer_classname);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
+}
+
+// optional bool java_multiple_files = 10 [default = false];
+bool FileOptions::has_java_multiple_files() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void FileOptions::set_has_java_multiple_files() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void FileOptions::clear_has_java_multiple_files() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void FileOptions::clear_java_multiple_files() {
+  java_multiple_files_ = false;
+  clear_has_java_multiple_files();
+}
+ bool FileOptions::java_multiple_files() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_multiple_files)
+  return java_multiple_files_;
+}
+ void FileOptions::set_java_multiple_files(bool value) {
+  set_has_java_multiple_files();
+  java_multiple_files_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_multiple_files)
+}
+
+// optional bool java_generate_equals_and_hash = 20 [default = false];
+bool FileOptions::has_java_generate_equals_and_hash() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void FileOptions::set_has_java_generate_equals_and_hash() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void FileOptions::clear_has_java_generate_equals_and_hash() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void FileOptions::clear_java_generate_equals_and_hash() {
+  java_generate_equals_and_hash_ = false;
+  clear_has_java_generate_equals_and_hash();
+}
+ bool FileOptions::java_generate_equals_and_hash() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generate_equals_and_hash)
+  return java_generate_equals_and_hash_;
+}
+ void FileOptions::set_java_generate_equals_and_hash(bool value) {
+  set_has_java_generate_equals_and_hash();
+  java_generate_equals_and_hash_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generate_equals_and_hash)
+}
+
+// optional bool java_string_check_utf8 = 27 [default = false];
+bool FileOptions::has_java_string_check_utf8() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void FileOptions::set_has_java_string_check_utf8() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void FileOptions::clear_has_java_string_check_utf8() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void FileOptions::clear_java_string_check_utf8() {
+  java_string_check_utf8_ = false;
+  clear_has_java_string_check_utf8();
+}
+ bool FileOptions::java_string_check_utf8() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_string_check_utf8)
+  return java_string_check_utf8_;
+}
+ void FileOptions::set_java_string_check_utf8(bool value) {
+  set_has_java_string_check_utf8();
+  java_string_check_utf8_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_string_check_utf8)
+}
+
+// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+bool FileOptions::has_optimize_for() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void FileOptions::set_has_optimize_for() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void FileOptions::clear_has_optimize_for() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void FileOptions::clear_optimize_for() {
+  optimize_for_ = 1;
+  clear_has_optimize_for();
+}
+ ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.optimize_for)
+  return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_);
+}
+ void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) {
+  assert(::google::protobuf::FileOptions_OptimizeMode_IsValid(value));
+  set_has_optimize_for();
+  optimize_for_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.optimize_for)
+}
+
+// optional string go_package = 11;
+bool FileOptions::has_go_package() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void FileOptions::set_has_go_package() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void FileOptions::clear_has_go_package() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void FileOptions::clear_go_package() {
+  go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_go_package();
+}
+ const ::std::string& FileOptions::go_package() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package)
+  return go_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_go_package(const ::std::string& value) {
+  set_has_go_package();
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
+}
+ void FileOptions::set_go_package(const char* value) {
+  set_has_go_package();
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.go_package)
+}
+ void FileOptions::set_go_package(const char* value, size_t size) {
+  set_has_go_package();
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.go_package)
+}
+ ::std::string* FileOptions::mutable_go_package() {
+  set_has_go_package();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
+  return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_go_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package)
+  clear_has_go_package();
+  return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_go_package(::std::string* go_package) {
+  if (go_package != NULL) {
+    set_has_go_package();
+  } else {
+    clear_has_go_package();
+  }
+  go_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), go_package);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
+}
+
+// optional bool cc_generic_services = 16 [default = false];
+bool FileOptions::has_cc_generic_services() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void FileOptions::set_has_cc_generic_services() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void FileOptions::clear_has_cc_generic_services() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void FileOptions::clear_cc_generic_services() {
+  cc_generic_services_ = false;
+  clear_has_cc_generic_services();
+}
+ bool FileOptions::cc_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_generic_services)
+  return cc_generic_services_;
+}
+ void FileOptions::set_cc_generic_services(bool value) {
+  set_has_cc_generic_services();
+  cc_generic_services_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_generic_services)
+}
+
+// optional bool java_generic_services = 17 [default = false];
+bool FileOptions::has_java_generic_services() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void FileOptions::set_has_java_generic_services() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void FileOptions::clear_has_java_generic_services() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void FileOptions::clear_java_generic_services() {
+  java_generic_services_ = false;
+  clear_has_java_generic_services();
+}
+ bool FileOptions::java_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_generic_services)
+  return java_generic_services_;
+}
+ void FileOptions::set_java_generic_services(bool value) {
+  set_has_java_generic_services();
+  java_generic_services_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_generic_services)
+}
+
+// optional bool py_generic_services = 18 [default = false];
+bool FileOptions::has_py_generic_services() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void FileOptions::set_has_py_generic_services() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void FileOptions::clear_has_py_generic_services() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void FileOptions::clear_py_generic_services() {
+  py_generic_services_ = false;
+  clear_has_py_generic_services();
+}
+ bool FileOptions::py_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.py_generic_services)
+  return py_generic_services_;
+}
+ void FileOptions::set_py_generic_services(bool value) {
+  set_has_py_generic_services();
+  py_generic_services_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
+}
+
+// optional bool deprecated = 23 [default = false];
+bool FileOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void FileOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void FileOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void FileOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool FileOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.deprecated)
+  return deprecated_;
+}
+ void FileOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
+}
+
+// optional bool cc_enable_arenas = 31 [default = false];
+bool FileOptions::has_cc_enable_arenas() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void FileOptions::set_has_cc_enable_arenas() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void FileOptions::clear_has_cc_enable_arenas() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void FileOptions::clear_cc_enable_arenas() {
+  cc_enable_arenas_ = false;
+  clear_has_cc_enable_arenas();
+}
+ bool FileOptions::cc_enable_arenas() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+  return cc_enable_arenas_;
+}
+ void FileOptions::set_cc_enable_arenas(bool value) {
+  set_has_cc_enable_arenas();
+  cc_enable_arenas_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+bool FileOptions::has_objc_class_prefix() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void FileOptions::set_has_objc_class_prefix() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void FileOptions::clear_has_objc_class_prefix() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void FileOptions::clear_objc_class_prefix() {
+  objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_objc_class_prefix();
+}
+ const ::std::string& FileOptions::objc_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+  return objc_class_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_objc_class_prefix(const ::std::string& value) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+ void FileOptions::set_objc_class_prefix(const char* value) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.objc_class_prefix)
+}
+ void FileOptions::set_objc_class_prefix(const char* value, size_t size) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.objc_class_prefix)
+}
+ ::std::string* FileOptions::mutable_objc_class_prefix() {
+  set_has_objc_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+  return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_objc_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix)
+  clear_has_objc_class_prefix();
+  return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_objc_class_prefix(::std::string* objc_class_prefix) {
+  if (objc_class_prefix != NULL) {
+    set_has_objc_class_prefix();
+  } else {
+    clear_has_objc_class_prefix();
+  }
+  objc_class_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), objc_class_prefix);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
+}
+
+// optional string csharp_namespace = 37;
+bool FileOptions::has_csharp_namespace() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void FileOptions::set_has_csharp_namespace() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void FileOptions::clear_has_csharp_namespace() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void FileOptions::clear_csharp_namespace() {
+  csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_csharp_namespace();
+}
+ const ::std::string& FileOptions::csharp_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace)
+  return csharp_namespace_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_csharp_namespace(const ::std::string& value) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace)
+}
+ void FileOptions::set_csharp_namespace(const char* value) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.csharp_namespace)
+}
+ void FileOptions::set_csharp_namespace(const char* value, size_t size) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.csharp_namespace)
+}
+ ::std::string* FileOptions::mutable_csharp_namespace() {
+  set_has_csharp_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace)
+  return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FileOptions::release_csharp_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace)
+  clear_has_csharp_namespace();
+  return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_namespace) {
+  if (csharp_namespace != NULL) {
+    set_has_csharp_namespace();
+  } else {
+    clear_has_csharp_namespace();
+  }
+  csharp_namespace_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), csharp_namespace);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int FileOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void FileOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+FileOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FileOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageOptions::kMessageSetWireFormatFieldNumber;
 const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber;
 const int MessageOptions::kDeprecatedFieldNumber;
+const int MessageOptions::kMapEntryFieldNumber;
 const int MessageOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageOptions::MessageOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MessageOptions)
 }
@@ -5672,7 +9338,8 @@
 }
 
 MessageOptions::MessageOptions(const MessageOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.MessageOptions)
@@ -5683,6 +9350,7 @@
   message_set_wire_format_ = false;
   no_standard_descriptor_accessor_ = false;
   deprecated_ = false;
+  map_entry_ = false;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -5713,35 +9381,48 @@
 
 MessageOptions* MessageOptions::default_instance_ = NULL;
 
-MessageOptions* MessageOptions::New() const {
-  return new MessageOptions;
+MessageOptions* MessageOptions::New(::google::protobuf::Arena* arena) const {
+  MessageOptions* n = new MessageOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MessageOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MessageOptions)
   _extensions_.Clear();
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<MessageOptions*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MessageOptions, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MessageOptions*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
-  ZR_(message_set_wire_format_, deprecated_);
+  ZR_(message_set_wire_format_, map_entry_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MessageOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.MessageOptions)
   for (;;) {
@@ -5789,6 +9470,21 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(56)) goto parse_map_entry;
+        break;
+      }
+
+      // optional bool map_entry = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_map_entry:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &map_entry_)));
+          set_has_map_entry();
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
         break;
       }
@@ -5797,12 +9493,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -5852,8 +9551,13 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
   }
 
+  // optional bool map_entry = 7;
+  if (has_map_entry()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->map_entry(), output);
+  }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -5862,7 +9566,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -5887,8 +9591,13 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
   }
 
+  // optional bool map_entry = 7;
+  if (has_map_entry()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->map_entry(), target);
+  }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -5898,7 +9607,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -5907,9 +9616,10 @@
 }
 
 int MessageOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 15u) {
     // optional bool message_set_wire_format = 1 [default = false];
     if (has_message_set_wire_format()) {
       total_size += 1 + 1;
@@ -5925,6 +9635,11 @@
       total_size += 1 + 1;
     }
 
+    // optional bool map_entry = 7;
+    if (has_map_entry()) {
+      total_size += 1 + 1;
+    }
+
   }
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
@@ -5936,7 +9651,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -5948,19 +9663,23 @@
 }
 
 void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MessageOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MessageOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const MessageOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MessageOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MessageOptions)
     MergeFrom(*source);
   }
 }
 
 void MessageOptions::MergeFrom(const MessageOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_message_set_wire_format()) {
@@ -5972,18 +9691,25 @@
     if (from.has_deprecated()) {
       set_deprecated(from.deprecated());
     }
+    if (from.has_map_entry()) {
+      set_map_entry(from.map_entry());
+    }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MessageOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MessageOptions::CopyFrom(const MessageOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MessageOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -5997,16 +9723,19 @@
 }
 
 void MessageOptions::Swap(MessageOptions* other) {
-  if (other != this) {
-    std::swap(message_set_wire_format_, other->message_set_wire_format_);
-    std::swap(no_standard_descriptor_accessor_, other->no_standard_descriptor_accessor_);
-    std::swap(deprecated_, other->deprecated_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MessageOptions::InternalSwap(MessageOptions* other) {
+  std::swap(message_set_wire_format_, other->message_set_wire_format_);
+  std::swap(no_standard_descriptor_accessor_, other->no_standard_descriptor_accessor_);
+  std::swap(deprecated_, other->deprecated_);
+  std::swap(map_entry_, other->map_entry_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata MessageOptions::GetMetadata() const {
@@ -6017,6 +9746,136 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MessageOptions
+
+// optional bool message_set_wire_format = 1 [default = false];
+bool MessageOptions::has_message_set_wire_format() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MessageOptions::set_has_message_set_wire_format() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MessageOptions::clear_has_message_set_wire_format() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MessageOptions::clear_message_set_wire_format() {
+  message_set_wire_format_ = false;
+  clear_has_message_set_wire_format();
+}
+ bool MessageOptions::message_set_wire_format() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.message_set_wire_format)
+  return message_set_wire_format_;
+}
+ void MessageOptions::set_message_set_wire_format(bool value) {
+  set_has_message_set_wire_format();
+  message_set_wire_format_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.message_set_wire_format)
+}
+
+// optional bool no_standard_descriptor_accessor = 2 [default = false];
+bool MessageOptions::has_no_standard_descriptor_accessor() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MessageOptions::set_has_no_standard_descriptor_accessor() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MessageOptions::clear_has_no_standard_descriptor_accessor() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MessageOptions::clear_no_standard_descriptor_accessor() {
+  no_standard_descriptor_accessor_ = false;
+  clear_has_no_standard_descriptor_accessor();
+}
+ bool MessageOptions::no_standard_descriptor_accessor() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+  return no_standard_descriptor_accessor_;
+}
+ void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
+  set_has_no_standard_descriptor_accessor();
+  no_standard_descriptor_accessor_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.no_standard_descriptor_accessor)
+}
+
+// optional bool deprecated = 3 [default = false];
+bool MessageOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void MessageOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void MessageOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void MessageOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool MessageOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.deprecated)
+  return deprecated_;
+}
+ void MessageOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated)
+}
+
+// optional bool map_entry = 7;
+bool MessageOptions::has_map_entry() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void MessageOptions::set_has_map_entry() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void MessageOptions::clear_has_map_entry() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void MessageOptions::clear_map_entry() {
+  map_entry_ = false;
+  clear_has_map_entry();
+}
+ bool MessageOptions::map_entry() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry)
+  return map_entry_;
+}
+ void MessageOptions::set_map_entry(bool value) {
+  set_has_map_entry();
+  map_entry_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.map_entry)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int MessageOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void MessageOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+MessageOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MessageOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
@@ -6035,26 +9894,49 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldOptions_CType FieldOptions::STRING;
 const FieldOptions_CType FieldOptions::CORD;
 const FieldOptions_CType FieldOptions::STRING_PIECE;
 const FieldOptions_CType FieldOptions::CType_MIN;
 const FieldOptions_CType FieldOptions::CType_MAX;
 const int FieldOptions::CType_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FieldOptions_JSType_descriptor_;
+}
+bool FieldOptions_JSType_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const FieldOptions_JSType FieldOptions::JS_NORMAL;
+const FieldOptions_JSType FieldOptions::JS_STRING;
+const FieldOptions_JSType FieldOptions::JS_NUMBER;
+const FieldOptions_JSType FieldOptions::JSType_MIN;
+const FieldOptions_JSType FieldOptions::JSType_MAX;
+const int FieldOptions::JSType_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldOptions::kCtypeFieldNumber;
 const int FieldOptions::kPackedFieldNumber;
+const int FieldOptions::kJstypeFieldNumber;
 const int FieldOptions::kLazyFieldNumber;
 const int FieldOptions::kDeprecatedFieldNumber;
-const int FieldOptions::kExperimentalMapKeyFieldNumber;
 const int FieldOptions::kWeakFieldNumber;
 const int FieldOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldOptions::FieldOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldOptions)
 }
@@ -6063,20 +9945,20 @@
 }
 
 FieldOptions::FieldOptions(const FieldOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldOptions)
 }
 
 void FieldOptions::SharedCtor() {
-  ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
   ctype_ = 0;
   packed_ = false;
+  jstype_ = 0;
   lazy_ = false;
   deprecated_ = false;
-  experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   weak_ = false;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -6087,9 +9969,6 @@
 }
 
 void FieldOptions::SharedDtor() {
-  if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete experimental_map_key_;
-  }
   if (this != default_instance_) {
   }
 }
@@ -6111,42 +9990,51 @@
 
 FieldOptions* FieldOptions::default_instance_ = NULL;
 
-FieldOptions* FieldOptions::New() const {
-  return new FieldOptions;
+FieldOptions* FieldOptions::New(::google::protobuf::Arena* arena) const {
+  FieldOptions* n = new FieldOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void FieldOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldOptions)
   _extensions_.Clear();
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<FieldOptions*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(FieldOptions, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<FieldOptions*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
-  if (_has_bits_[0 / 32] & 63) {
-    ZR_(ctype_, weak_);
-    if (has_experimental_map_key()) {
-      if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        experimental_map_key_->clear();
-      }
-    }
+  if (_has_bits_[0 / 32] & 63u) {
+    ZR_(ctype_, jstype_);
+    ZR_(packed_, weak_);
   }
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool FieldOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.FieldOptions)
   for (;;) {
@@ -6214,20 +10102,23 @@
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(74)) goto parse_experimental_map_key;
+        if (input->ExpectTag(48)) goto parse_jstype;
         break;
       }
 
-      // optional string experimental_map_key = 9;
-      case 9: {
-        if (tag == 74) {
-         parse_experimental_map_key:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
-                input, this->mutable_experimental_map_key()));
-          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->experimental_map_key().data(), this->experimental_map_key().length(),
-            ::google::protobuf::internal::WireFormat::PARSE,
-            "experimental_map_key");
+      // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+      case 6: {
+        if (tag == 48) {
+         parse_jstype:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::google::protobuf::FieldOptions_JSType_IsValid(value)) {
+            set_jstype(static_cast< ::google::protobuf::FieldOptions_JSType >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(6, value);
+          }
         } else {
           goto handle_unusual;
         }
@@ -6254,12 +10145,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -6315,14 +10209,10 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output);
   }
 
-  // optional string experimental_map_key = 9;
-  if (has_experimental_map_key()) {
-    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->experimental_map_key().data(), this->experimental_map_key().length(),
-      ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "experimental_map_key");
-    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
-      9, this->experimental_map_key(), output);
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (has_jstype()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->jstype(), output);
   }
 
   // optional bool weak = 10 [default = false];
@@ -6331,7 +10221,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -6340,7 +10230,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -6371,15 +10261,10 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target);
   }
 
-  // optional string experimental_map_key = 9;
-  if (has_experimental_map_key()) {
-    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->experimental_map_key().data(), this->experimental_map_key().length(),
-      ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "experimental_map_key");
-    target =
-      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
-        9, this->experimental_map_key(), target);
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (has_jstype()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->jstype(), target);
   }
 
   // optional bool weak = 10 [default = false];
@@ -6388,7 +10273,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -6398,7 +10283,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -6407,9 +10292,10 @@
 }
 
 int FieldOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 63u) {
     // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
     if (has_ctype()) {
       total_size += 1 +
@@ -6421,6 +10307,12 @@
       total_size += 1 + 1;
     }
 
+    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    if (has_jstype()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->jstype());
+    }
+
     // optional bool lazy = 5 [default = false];
     if (has_lazy()) {
       total_size += 1 + 1;
@@ -6431,13 +10323,6 @@
       total_size += 1 + 1;
     }
 
-    // optional string experimental_map_key = 9;
-    if (has_experimental_map_key()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->experimental_map_key());
-    }
-
     // optional bool weak = 10 [default = false];
     if (has_weak()) {
       total_size += 1 + 1;
@@ -6454,7 +10339,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -6466,19 +10351,23 @@
 }
 
 void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const FieldOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FieldOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldOptions)
     MergeFrom(*source);
   }
 }
 
 void FieldOptions::MergeFrom(const FieldOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_ctype()) {
@@ -6487,30 +10376,34 @@
     if (from.has_packed()) {
       set_packed(from.packed());
     }
+    if (from.has_jstype()) {
+      set_jstype(from.jstype());
+    }
     if (from.has_lazy()) {
       set_lazy(from.lazy());
     }
     if (from.has_deprecated()) {
       set_deprecated(from.deprecated());
     }
-    if (from.has_experimental_map_key()) {
-      set_experimental_map_key(from.experimental_map_key());
-    }
     if (from.has_weak()) {
       set_weak(from.weak());
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void FieldOptions::CopyFrom(const FieldOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -6524,19 +10417,21 @@
 }
 
 void FieldOptions::Swap(FieldOptions* other) {
-  if (other != this) {
-    std::swap(ctype_, other->ctype_);
-    std::swap(packed_, other->packed_);
-    std::swap(lazy_, other->lazy_);
-    std::swap(deprecated_, other->deprecated_);
-    std::swap(experimental_map_key_, other->experimental_map_key_);
-    std::swap(weak_, other->weak_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FieldOptions::InternalSwap(FieldOptions* other) {
+  std::swap(ctype_, other->ctype_);
+  std::swap(packed_, other->packed_);
+  std::swap(jstype_, other->jstype_);
+  std::swap(lazy_, other->lazy_);
+  std::swap(deprecated_, other->deprecated_);
+  std::swap(weak_, other->weak_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata FieldOptions::GetMetadata() const {
@@ -6547,17 +10442,197 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldOptions
+
+// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
+bool FieldOptions::has_ctype() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FieldOptions::set_has_ctype() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FieldOptions::clear_has_ctype() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FieldOptions::clear_ctype() {
+  ctype_ = 0;
+  clear_has_ctype();
+}
+ ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.ctype)
+  return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_);
+}
+ void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) {
+  assert(::google::protobuf::FieldOptions_CType_IsValid(value));
+  set_has_ctype();
+  ctype_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.ctype)
+}
+
+// optional bool packed = 2;
+bool FieldOptions::has_packed() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FieldOptions::set_has_packed() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FieldOptions::clear_has_packed() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FieldOptions::clear_packed() {
+  packed_ = false;
+  clear_has_packed();
+}
+ bool FieldOptions::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.packed)
+  return packed_;
+}
+ void FieldOptions::set_packed(bool value) {
+  set_has_packed();
+  packed_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
+}
+
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+bool FieldOptions::has_jstype() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void FieldOptions::set_has_jstype() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void FieldOptions::clear_has_jstype() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void FieldOptions::clear_jstype() {
+  jstype_ = 0;
+  clear_has_jstype();
+}
+ ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_);
+}
+ void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) {
+  assert(::google::protobuf::FieldOptions_JSType_IsValid(value));
+  set_has_jstype();
+  jstype_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+bool FieldOptions::has_lazy() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void FieldOptions::set_has_lazy() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void FieldOptions::clear_has_lazy() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void FieldOptions::clear_lazy() {
+  lazy_ = false;
+  clear_has_lazy();
+}
+ bool FieldOptions::lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.lazy)
+  return lazy_;
+}
+ void FieldOptions::set_lazy(bool value) {
+  set_has_lazy();
+  lazy_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
+}
+
+// optional bool deprecated = 3 [default = false];
+bool FieldOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void FieldOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void FieldOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void FieldOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool FieldOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.deprecated)
+  return deprecated_;
+}
+ void FieldOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated)
+}
+
+// optional bool weak = 10 [default = false];
+bool FieldOptions::has_weak() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void FieldOptions::set_has_weak() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void FieldOptions::clear_has_weak() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void FieldOptions::clear_weak() {
+  weak_ = false;
+  clear_has_weak();
+}
+ bool FieldOptions::weak() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.weak)
+  return weak_;
+}
+ void FieldOptions::set_weak(bool value) {
+  set_has_weak();
+  weak_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.weak)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int FieldOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void FieldOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+FieldOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FieldOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumOptions::kAllowAliasFieldNumber;
 const int EnumOptions::kDeprecatedFieldNumber;
 const int EnumOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumOptions::EnumOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumOptions)
 }
@@ -6566,7 +10641,8 @@
 }
 
 EnumOptions::EnumOptions(const EnumOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumOptions)
@@ -6606,35 +10682,48 @@
 
 EnumOptions* EnumOptions::default_instance_ = NULL;
 
-EnumOptions* EnumOptions::New() const {
-  return new EnumOptions;
+EnumOptions* EnumOptions::New(::google::protobuf::Arena* arena) const {
+  EnumOptions* n = new EnumOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void EnumOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumOptions)
   _extensions_.Clear();
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<EnumOptions*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(EnumOptions, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<EnumOptions*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
   ZR_(allow_alias_, deprecated_);
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool EnumOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.EnumOptions)
   for (;;) {
@@ -6675,12 +10764,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -6726,7 +10818,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -6735,7 +10827,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -6756,7 +10848,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -6766,7 +10858,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -6775,9 +10867,10 @@
 }
 
 int EnumOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (_has_bits_[0 / 32] & 3u) {
     // optional bool allow_alias = 2;
     if (has_allow_alias()) {
       total_size += 1 + 1;
@@ -6799,7 +10892,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -6811,19 +10904,23 @@
 }
 
 void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const EnumOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumOptions)
     MergeFrom(*source);
   }
 }
 
 void EnumOptions::MergeFrom(const EnumOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_allow_alias()) {
@@ -6834,16 +10931,20 @@
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void EnumOptions::CopyFrom(const EnumOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -6857,15 +10958,17 @@
 }
 
 void EnumOptions::Swap(EnumOptions* other) {
-  if (other != this) {
-    std::swap(allow_alias_, other->allow_alias_);
-    std::swap(deprecated_, other->deprecated_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EnumOptions::InternalSwap(EnumOptions* other) {
+  std::swap(allow_alias_, other->allow_alias_);
+  std::swap(deprecated_, other->deprecated_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata EnumOptions::GetMetadata() const {
@@ -6876,16 +10979,98 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumOptions
+
+// optional bool allow_alias = 2;
+bool EnumOptions::has_allow_alias() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void EnumOptions::set_has_allow_alias() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void EnumOptions::clear_has_allow_alias() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void EnumOptions::clear_allow_alias() {
+  allow_alias_ = false;
+  clear_has_allow_alias();
+}
+ bool EnumOptions::allow_alias() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.allow_alias)
+  return allow_alias_;
+}
+ void EnumOptions::set_allow_alias(bool value) {
+  set_has_allow_alias();
+  allow_alias_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.allow_alias)
+}
+
+// optional bool deprecated = 3 [default = false];
+bool EnumOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void EnumOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void EnumOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void EnumOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool EnumOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.deprecated)
+  return deprecated_;
+}
+ void EnumOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int EnumOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void EnumOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+EnumOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumValueOptions::kDeprecatedFieldNumber;
 const int EnumValueOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumValueOptions::EnumValueOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueOptions)
 }
@@ -6894,7 +11079,8 @@
 }
 
 EnumValueOptions::EnumValueOptions(const EnumValueOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValueOptions)
@@ -6933,21 +11119,28 @@
 
 EnumValueOptions* EnumValueOptions::default_instance_ = NULL;
 
-EnumValueOptions* EnumValueOptions::New() const {
-  return new EnumValueOptions;
+EnumValueOptions* EnumValueOptions::New(::google::protobuf::Arena* arena) const {
+  EnumValueOptions* n = new EnumValueOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void EnumValueOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueOptions)
   _extensions_.Clear();
   deprecated_ = false;
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool EnumValueOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueOptions)
   for (;;) {
@@ -6973,12 +11166,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -7019,7 +11215,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -7028,7 +11224,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -7044,7 +11240,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -7054,7 +11250,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -7063,15 +11259,14 @@
 }
 
 int EnumValueOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // optional bool deprecated = 1 [default = false];
-    if (has_deprecated()) {
-      total_size += 1 + 1;
-    }
-
+  // optional bool deprecated = 1 [default = false];
+  if (has_deprecated()) {
+    total_size += 1 + 1;
   }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
   for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -7082,7 +11277,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -7094,19 +11289,23 @@
 }
 
 void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const EnumValueOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumValueOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueOptions)
     MergeFrom(*source);
   }
 }
 
 void EnumValueOptions::MergeFrom(const EnumValueOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -7114,16 +11313,20 @@
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void EnumValueOptions::CopyFrom(const EnumValueOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -7137,14 +11340,16 @@
 }
 
 void EnumValueOptions::Swap(EnumValueOptions* other) {
-  if (other != this) {
-    std::swap(deprecated_, other->deprecated_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EnumValueOptions::InternalSwap(EnumValueOptions* other) {
+  std::swap(deprecated_, other->deprecated_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata EnumValueOptions::GetMetadata() const {
@@ -7155,16 +11360,74 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumValueOptions
+
+// optional bool deprecated = 1 [default = false];
+bool EnumValueOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void EnumValueOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void EnumValueOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void EnumValueOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool EnumValueOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.deprecated)
+  return deprecated_;
+}
+ void EnumValueOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValueOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int EnumValueOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void EnumValueOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+EnumValueOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumValueOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int ServiceOptions::kDeprecatedFieldNumber;
 const int ServiceOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 ServiceOptions::ServiceOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceOptions)
 }
@@ -7173,7 +11436,8 @@
 }
 
 ServiceOptions::ServiceOptions(const ServiceOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.ServiceOptions)
@@ -7212,21 +11476,28 @@
 
 ServiceOptions* ServiceOptions::default_instance_ = NULL;
 
-ServiceOptions* ServiceOptions::New() const {
-  return new ServiceOptions;
+ServiceOptions* ServiceOptions::New(::google::protobuf::Arena* arena) const {
+  ServiceOptions* n = new ServiceOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void ServiceOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceOptions)
   _extensions_.Clear();
   deprecated_ = false;
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool ServiceOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.ServiceOptions)
   for (;;) {
@@ -7252,12 +11523,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -7298,7 +11572,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -7307,7 +11581,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -7323,7 +11597,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -7333,7 +11607,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -7342,15 +11616,14 @@
 }
 
 int ServiceOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // optional bool deprecated = 33 [default = false];
-    if (has_deprecated()) {
-      total_size += 2 + 1;
-    }
-
+  // optional bool deprecated = 33 [default = false];
+  if (has_deprecated()) {
+    total_size += 2 + 1;
   }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
   for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -7361,7 +11634,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -7373,19 +11646,23 @@
 }
 
 void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const ServiceOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ServiceOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceOptions)
     MergeFrom(*source);
   }
 }
 
 void ServiceOptions::MergeFrom(const ServiceOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -7393,16 +11670,20 @@
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void ServiceOptions::CopyFrom(const ServiceOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -7416,14 +11697,16 @@
 }
 
 void ServiceOptions::Swap(ServiceOptions* other) {
-  if (other != this) {
-    std::swap(deprecated_, other->deprecated_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ServiceOptions::InternalSwap(ServiceOptions* other) {
+  std::swap(deprecated_, other->deprecated_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata ServiceOptions::GetMetadata() const {
@@ -7434,16 +11717,74 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServiceOptions
+
+// optional bool deprecated = 33 [default = false];
+bool ServiceOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ServiceOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ServiceOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ServiceOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool ServiceOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.deprecated)
+  return deprecated_;
+}
+ void ServiceOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.ServiceOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int ServiceOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void ServiceOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+ServiceOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ServiceOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MethodOptions::kDeprecatedFieldNumber;
 const int MethodOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MethodOptions::MethodOptions()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodOptions)
 }
@@ -7452,7 +11793,8 @@
 }
 
 MethodOptions::MethodOptions(const MethodOptions& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.MethodOptions)
@@ -7491,21 +11833,28 @@
 
 MethodOptions* MethodOptions::default_instance_ = NULL;
 
-MethodOptions* MethodOptions::New() const {
-  return new MethodOptions;
+MethodOptions* MethodOptions::New(::google::protobuf::Arena* arena) const {
+  MethodOptions* n = new MethodOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void MethodOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodOptions)
   _extensions_.Clear();
   deprecated_ = false;
   uninterpreted_option_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool MethodOptions::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.MethodOptions)
   for (;;) {
@@ -7531,12 +11880,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -7577,7 +11929,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       999, this->uninterpreted_option(i), output);
   }
@@ -7586,7 +11938,7 @@
   _extensions_.SerializeWithCachedSizes(
       1000, 536870912, output);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -7602,7 +11954,7 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         999, this->uninterpreted_option(i), target);
@@ -7612,7 +11964,7 @@
   target = _extensions_.SerializeWithCachedSizesToArray(
       1000, 536870912, target);
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -7621,15 +11973,14 @@
 }
 
 int MethodOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // optional bool deprecated = 33 [default = false];
-    if (has_deprecated()) {
-      total_size += 2 + 1;
-    }
-
+  // optional bool deprecated = 33 [default = false];
+  if (has_deprecated()) {
+    total_size += 2 + 1;
   }
+
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   total_size += 2 * this->uninterpreted_option_size();
   for (int i = 0; i < this->uninterpreted_option_size(); i++) {
@@ -7640,7 +11991,7 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -7652,19 +12003,23 @@
 }
 
 void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const MethodOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodOptions*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const MethodOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodOptions>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodOptions)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodOptions)
     MergeFrom(*source);
   }
 }
 
 void MethodOptions::MergeFrom(const MethodOptions& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -7672,16 +12027,20 @@
     }
   }
   _extensions_.MergeFrom(from._extensions_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void MethodOptions::CopyFrom(const MethodOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodOptions)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -7695,14 +12054,16 @@
 }
 
 void MethodOptions::Swap(MethodOptions* other) {
-  if (other != this) {
-    std::swap(deprecated_, other->deprecated_);
-    uninterpreted_option_.Swap(&other->uninterpreted_option_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-    _extensions_.Swap(&other->_extensions_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MethodOptions::InternalSwap(MethodOptions* other) {
+  std::swap(deprecated_, other->deprecated_);
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
 }
 
 ::google::protobuf::Metadata MethodOptions::GetMetadata() const {
@@ -7713,16 +12074,74 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MethodOptions
+
+// optional bool deprecated = 33 [default = false];
+bool MethodOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MethodOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MethodOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MethodOptions::clear_deprecated() {
+  deprecated_ = false;
+  clear_has_deprecated();
+}
+ bool MethodOptions::deprecated() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.deprecated)
+  return deprecated_;
+}
+ void MethodOptions::set_deprecated(bool value) {
+  set_has_deprecated();
+  deprecated_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodOptions.deprecated)
+}
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int MethodOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void MethodOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+MethodOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MethodOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UninterpretedOption_NamePart::kNamePartFieldNumber;
 const int UninterpretedOption_NamePart::kIsExtensionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UninterpretedOption_NamePart::UninterpretedOption_NamePart()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption.NamePart)
 }
@@ -7731,7 +12150,8 @@
 }
 
 UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption.NamePart)
@@ -7740,7 +12160,7 @@
 void UninterpretedOption_NamePart::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  name_part_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   is_extension_ = false;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -7751,9 +12171,7 @@
 }
 
 void UninterpretedOption_NamePart::SharedDtor() {
-  if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_part_;
-  }
+  name_part_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -7775,26 +12193,31 @@
 
 UninterpretedOption_NamePart* UninterpretedOption_NamePart::default_instance_ = NULL;
 
-UninterpretedOption_NamePart* UninterpretedOption_NamePart::New() const {
-  return new UninterpretedOption_NamePart;
+UninterpretedOption_NamePart* UninterpretedOption_NamePart::New(::google::protobuf::Arena* arena) const {
+  UninterpretedOption_NamePart* n = new UninterpretedOption_NamePart;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void UninterpretedOption_NamePart::Clear() {
-  if (_has_bits_[0 / 32] & 3) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption.NamePart)
+  if (_has_bits_[0 / 32] & 3u) {
     if (has_name_part()) {
-      if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        name_part_->clear();
-      }
+      name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     is_extension_ = false;
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool UninterpretedOption_NamePart::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption.NamePart)
   for (;;) {
@@ -7810,7 +12233,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->name_part().data(), this->name_part().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "name_part");
+            "google.protobuf.UninterpretedOption.NamePart.name_part");
         } else {
           goto handle_unusual;
         }
@@ -7863,7 +12286,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name_part().data(), this->name_part().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name_part");
+      "google.protobuf.UninterpretedOption.NamePart.name_part");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       1, this->name_part(), output);
   }
@@ -7873,7 +12296,7 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->is_extension(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -7888,7 +12311,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->name_part().data(), this->name_part().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "name_part");
+      "google.protobuf.UninterpretedOption.NamePart.name_part");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         1, this->name_part(), target);
@@ -7899,7 +12322,7 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->is_extension(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -7907,24 +12330,41 @@
   return target;
 }
 
-int UninterpretedOption_NamePart::ByteSize() const {
+int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const {
+// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart)
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+  if (has_name_part()) {
     // required string name_part = 1;
-    if (has_name_part()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::StringSize(
-          this->name_part());
-    }
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name_part());
+  }
+
+  if (has_is_extension()) {
+    // required bool is_extension = 2;
+    total_size += 1 + 1;
+  }
+
+  return total_size;
+}
+int UninterpretedOption_NamePart::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart)
+  int total_size = 0;
+
+  if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
+    // required string name_part = 1;
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name_part());
 
     // required bool is_extension = 2;
-    if (has_is_extension()) {
-      total_size += 1 + 1;
-    }
+    total_size += 1 + 1;
 
+  } else {
+    total_size += RequiredFieldsByteSizeFallback();
   }
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -7936,37 +12376,46 @@
 }
 
 void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const UninterpretedOption_NamePart* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption_NamePart*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UninterpretedOption_NamePart* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption_NamePart>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption.NamePart)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption.NamePart)
     MergeFrom(*source);
   }
 }
 
 void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name_part()) {
-      set_name_part(from.name_part());
+      set_has_name_part();
+      name_part_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_part_);
     }
     if (from.has_is_extension()) {
       set_is_extension(from.is_extension());
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void UninterpretedOption_NamePart::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption.NamePart)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption.NamePart)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -7979,13 +12428,15 @@
 }
 
 void UninterpretedOption_NamePart::Swap(UninterpretedOption_NamePart* other) {
-  if (other != this) {
-    std::swap(name_part_, other->name_part_);
-    std::swap(is_extension_, other->is_extension_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void UninterpretedOption_NamePart::InternalSwap(UninterpretedOption_NamePart* other) {
+  name_part_.Swap(&other->name_part_);
+  std::swap(is_extension_, other->is_extension_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata UninterpretedOption_NamePart::GetMetadata() const {
@@ -7999,7 +12450,7 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UninterpretedOption::kNameFieldNumber;
 const int UninterpretedOption::kIdentifierValueFieldNumber;
 const int UninterpretedOption::kPositiveIntValueFieldNumber;
@@ -8007,10 +12458,10 @@
 const int UninterpretedOption::kDoubleValueFieldNumber;
 const int UninterpretedOption::kStringValueFieldNumber;
 const int UninterpretedOption::kAggregateValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UninterpretedOption::UninterpretedOption()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption)
 }
@@ -8019,7 +12470,8 @@
 }
 
 UninterpretedOption::UninterpretedOption(const UninterpretedOption& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.UninterpretedOption)
@@ -8028,12 +12480,12 @@
 void UninterpretedOption::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  identifier_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   positive_int_value_ = GOOGLE_ULONGLONG(0);
   negative_int_value_ = GOOGLE_LONGLONG(0);
   double_value_ = 0;
-  string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  aggregate_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -8043,15 +12495,9 @@
 }
 
 void UninterpretedOption::SharedDtor() {
-  if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete identifier_value_;
-  }
-  if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete string_value_;
-  }
-  if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete aggregate_value_;
-  }
+  identifier_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  aggregate_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -8073,51 +12519,58 @@
 
 UninterpretedOption* UninterpretedOption::default_instance_ = NULL;
 
-UninterpretedOption* UninterpretedOption::New() const {
-  return new UninterpretedOption;
+UninterpretedOption* UninterpretedOption::New(::google::protobuf::Arena* arena) const {
+  UninterpretedOption* n = new UninterpretedOption;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void UninterpretedOption::Clear() {
-#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
-  &reinterpret_cast<UninterpretedOption*>(16)->f) - \
-   reinterpret_cast<char*>(16))
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(UninterpretedOption, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<UninterpretedOption*>(16)->f)
+#endif
 
-#define ZR_(first, last) do {                              \
-    size_t f = OFFSET_OF_FIELD_(first);                    \
-    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
-    ::memset(&(first), 0, n);                              \
-  } while (0)
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
 
-  if (_has_bits_[0 / 32] & 126) {
+  if (_has_bits_[0 / 32] & 126u) {
     ZR_(positive_int_value_, double_value_);
     if (has_identifier_value()) {
-      if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        identifier_value_->clear();
-      }
+      identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_string_value()) {
-      if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        string_value_->clear();
-      }
+      string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_aggregate_value()) {
-      if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        aggregate_value_->clear();
-      }
+      aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
 
-#undef OFFSET_OF_FIELD_
+#undef ZR_HELPER_
 #undef ZR_
 
   name_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool UninterpretedOption::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption)
   for (;;) {
@@ -8128,13 +12581,15 @@
       // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
       case 2: {
         if (tag == 18) {
-         parse_name:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_name()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_name;
+        if (input->ExpectTag(18)) goto parse_loop_name;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_identifier_value;
         break;
       }
@@ -8148,7 +12603,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->identifier_value().data(), this->identifier_value().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "identifier_value");
+            "google.protobuf.UninterpretedOption.identifier_value");
         } else {
           goto handle_unusual;
         }
@@ -8223,7 +12678,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->aggregate_value().data(), this->aggregate_value().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "aggregate_value");
+            "google.protobuf.UninterpretedOption.aggregate_value");
         } else {
           goto handle_unusual;
         }
@@ -8257,7 +12712,7 @@
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:google.protobuf.UninterpretedOption)
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  for (int i = 0; i < this->name_size(); i++) {
+  for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       2, this->name(i), output);
   }
@@ -8267,7 +12722,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->identifier_value().data(), this->identifier_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "identifier_value");
+      "google.protobuf.UninterpretedOption.identifier_value");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       3, this->identifier_value(), output);
   }
@@ -8298,12 +12753,12 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->aggregate_value().data(), this->aggregate_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "aggregate_value");
+      "google.protobuf.UninterpretedOption.aggregate_value");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       8, this->aggregate_value(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -8314,7 +12769,7 @@
     ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  for (int i = 0; i < this->name_size(); i++) {
+  for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         2, this->name(i), target);
@@ -8325,7 +12780,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->identifier_value().data(), this->identifier_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "identifier_value");
+      "google.protobuf.UninterpretedOption.identifier_value");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         3, this->identifier_value(), target);
@@ -8358,13 +12813,13 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->aggregate_value().data(), this->aggregate_value().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "aggregate_value");
+      "google.protobuf.UninterpretedOption.aggregate_value");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         8, this->aggregate_value(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -8373,9 +12828,10 @@
 }
 
 int UninterpretedOption::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption)
   int total_size = 0;
 
-  if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
+  if (_has_bits_[1 / 32] & 126u) {
     // optional string identifier_value = 3;
     if (has_identifier_value()) {
       total_size += 1 +
@@ -8425,7 +12881,7 @@
         this->name(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -8437,23 +12893,28 @@
 }
 
 void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const UninterpretedOption* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UninterpretedOption* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption)
     MergeFrom(*source);
   }
 }
 
 void UninterpretedOption::MergeFrom(const UninterpretedOption& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   name_.MergeFrom(from.name_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
     if (from.has_identifier_value()) {
-      set_identifier_value(from.identifier_value());
+      set_has_identifier_value();
+      identifier_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.identifier_value_);
     }
     if (from.has_positive_int_value()) {
       set_positive_int_value(from.positive_int_value());
@@ -8465,22 +12926,28 @@
       set_double_value(from.double_value());
     }
     if (from.has_string_value()) {
-      set_string_value(from.string_value());
+      set_has_string_value();
+      string_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.string_value_);
     }
     if (from.has_aggregate_value()) {
-      set_aggregate_value(from.aggregate_value());
+      set_has_aggregate_value();
+      aggregate_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.aggregate_value_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void UninterpretedOption::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -8493,18 +12960,20 @@
 }
 
 void UninterpretedOption::Swap(UninterpretedOption* other) {
-  if (other != this) {
-    name_.Swap(&other->name_);
-    std::swap(identifier_value_, other->identifier_value_);
-    std::swap(positive_int_value_, other->positive_int_value_);
-    std::swap(negative_int_value_, other->negative_int_value_);
-    std::swap(double_value_, other->double_value_);
-    std::swap(string_value_, other->string_value_);
-    std::swap(aggregate_value_, other->aggregate_value_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void UninterpretedOption::InternalSwap(UninterpretedOption* other) {
+  name_.UnsafeArenaSwap(&other->name_);
+  identifier_value_.Swap(&other->identifier_value_);
+  std::swap(positive_int_value_, other->positive_int_value_);
+  std::swap(negative_int_value_, other->negative_int_value_);
+  std::swap(double_value_, other->double_value_);
+  string_value_.Swap(&other->string_value_);
+  aggregate_value_.Swap(&other->aggregate_value_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata UninterpretedOption::GetMetadata() const {
@@ -8515,18 +12984,369 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// UninterpretedOption_NamePart
+
+// required string name_part = 1;
+bool UninterpretedOption_NamePart::has_name_part() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void UninterpretedOption_NamePart::set_has_name_part() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void UninterpretedOption_NamePart::clear_has_name_part() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void UninterpretedOption_NamePart::clear_name_part() {
+  name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name_part();
+}
+ const ::std::string& UninterpretedOption_NamePart::name_part() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return name_part_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) {
+  set_has_name_part();
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ void UninterpretedOption_NamePart::set_name_part(const char* value) {
+  set_has_name_part();
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) {
+  set_has_name_part();
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+ ::std::string* UninterpretedOption_NamePart::mutable_name_part() {
+  set_has_name_part();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
+  return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption_NamePart::release_name_part() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part)
+  clear_has_name_part();
+  return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) {
+  if (name_part != NULL) {
+    set_has_name_part();
+  } else {
+    clear_has_name_part();
+  }
+  name_part_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name_part);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
+}
+
+// required bool is_extension = 2;
+bool UninterpretedOption_NamePart::has_is_extension() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void UninterpretedOption_NamePart::set_has_is_extension() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void UninterpretedOption_NamePart::clear_has_is_extension() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void UninterpretedOption_NamePart::clear_is_extension() {
+  is_extension_ = false;
+  clear_has_is_extension();
+}
+ bool UninterpretedOption_NamePart::is_extension() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.is_extension)
+  return is_extension_;
+}
+ void UninterpretedOption_NamePart::set_is_extension(bool value) {
+  set_has_is_extension();
+  is_extension_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.is_extension)
+}
+
+// -------------------------------------------------------------------
+
+// UninterpretedOption
+
+// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
+int UninterpretedOption::name_size() const {
+  return name_.size();
+}
+void UninterpretedOption::clear_name() {
+  name_.Clear();
+}
+const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name)
+  return name_.Get(index);
+}
+::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name)
+  return name_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() {
+  // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
+  return name_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
+UninterpretedOption::mutable_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
+  return &name_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+UninterpretedOption::name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
+  return name_;
+}
+
+// optional string identifier_value = 3;
+bool UninterpretedOption::has_identifier_value() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void UninterpretedOption::set_has_identifier_value() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void UninterpretedOption::clear_has_identifier_value() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void UninterpretedOption::clear_identifier_value() {
+  identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_identifier_value();
+}
+ const ::std::string& UninterpretedOption::identifier_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
+  return identifier_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_identifier_value(const ::std::string& value) {
+  set_has_identifier_value();
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value)
+}
+ void UninterpretedOption::set_identifier_value(const char* value) {
+  set_has_identifier_value();
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.identifier_value)
+}
+ void UninterpretedOption::set_identifier_value(const char* value, size_t size) {
+  set_has_identifier_value();
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.identifier_value)
+}
+ ::std::string* UninterpretedOption::mutable_identifier_value() {
+  set_has_identifier_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
+  return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_identifier_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value)
+  clear_has_identifier_value();
+  return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) {
+  if (identifier_value != NULL) {
+    set_has_identifier_value();
+  } else {
+    clear_has_identifier_value();
+  }
+  identifier_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), identifier_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
+}
+
+// optional uint64 positive_int_value = 4;
+bool UninterpretedOption::has_positive_int_value() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void UninterpretedOption::set_has_positive_int_value() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void UninterpretedOption::clear_has_positive_int_value() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void UninterpretedOption::clear_positive_int_value() {
+  positive_int_value_ = GOOGLE_ULONGLONG(0);
+  clear_has_positive_int_value();
+}
+ ::google::protobuf::uint64 UninterpretedOption::positive_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.positive_int_value)
+  return positive_int_value_;
+}
+ void UninterpretedOption::set_positive_int_value(::google::protobuf::uint64 value) {
+  set_has_positive_int_value();
+  positive_int_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.positive_int_value)
+}
+
+// optional int64 negative_int_value = 5;
+bool UninterpretedOption::has_negative_int_value() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void UninterpretedOption::set_has_negative_int_value() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void UninterpretedOption::clear_has_negative_int_value() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void UninterpretedOption::clear_negative_int_value() {
+  negative_int_value_ = GOOGLE_LONGLONG(0);
+  clear_has_negative_int_value();
+}
+ ::google::protobuf::int64 UninterpretedOption::negative_int_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.negative_int_value)
+  return negative_int_value_;
+}
+ void UninterpretedOption::set_negative_int_value(::google::protobuf::int64 value) {
+  set_has_negative_int_value();
+  negative_int_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.negative_int_value)
+}
+
+// optional double double_value = 6;
+bool UninterpretedOption::has_double_value() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void UninterpretedOption::set_has_double_value() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void UninterpretedOption::clear_has_double_value() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void UninterpretedOption::clear_double_value() {
+  double_value_ = 0;
+  clear_has_double_value();
+}
+ double UninterpretedOption::double_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.double_value)
+  return double_value_;
+}
+ void UninterpretedOption::set_double_value(double value) {
+  set_has_double_value();
+  double_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.double_value)
+}
+
+// optional bytes string_value = 7;
+bool UninterpretedOption::has_string_value() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void UninterpretedOption::set_has_string_value() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void UninterpretedOption::clear_has_string_value() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void UninterpretedOption::clear_string_value() {
+  string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_string_value();
+}
+ const ::std::string& UninterpretedOption::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
+  return string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_string_value(const ::std::string& value) {
+  set_has_string_value();
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value)
+}
+ void UninterpretedOption::set_string_value(const char* value) {
+  set_has_string_value();
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.string_value)
+}
+ void UninterpretedOption::set_string_value(const void* value, size_t size) {
+  set_has_string_value();
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.string_value)
+}
+ ::std::string* UninterpretedOption::mutable_string_value() {
+  set_has_string_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
+  return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value)
+  clear_has_string_value();
+  return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_string_value(::std::string* string_value) {
+  if (string_value != NULL) {
+    set_has_string_value();
+  } else {
+    clear_has_string_value();
+  }
+  string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), string_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
+}
+
+// optional string aggregate_value = 8;
+bool UninterpretedOption::has_aggregate_value() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void UninterpretedOption::set_has_aggregate_value() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void UninterpretedOption::clear_has_aggregate_value() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void UninterpretedOption::clear_aggregate_value() {
+  aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_aggregate_value();
+}
+ const ::std::string& UninterpretedOption::aggregate_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
+  return aggregate_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_aggregate_value(const ::std::string& value) {
+  set_has_aggregate_value();
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ void UninterpretedOption::set_aggregate_value(const char* value) {
+  set_has_aggregate_value();
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ void UninterpretedOption::set_aggregate_value(const char* value, size_t size) {
+  set_has_aggregate_value();
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.aggregate_value)
+}
+ ::std::string* UninterpretedOption::mutable_aggregate_value() {
+  set_has_aggregate_value();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
+  return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* UninterpretedOption::release_aggregate_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value)
+  clear_has_aggregate_value();
+  return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) {
+  if (aggregate_value != NULL) {
+    set_has_aggregate_value();
+  } else {
+    clear_has_aggregate_value();
+  }
+  aggregate_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), aggregate_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int SourceCodeInfo_Location::kPathFieldNumber;
 const int SourceCodeInfo_Location::kSpanFieldNumber;
 const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber;
 const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber;
-#endif  // !_MSC_VER
+const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceCodeInfo_Location::SourceCodeInfo_Location()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo.Location)
 }
@@ -8535,7 +13355,8 @@
 }
 
 SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo.Location)
@@ -8544,8 +13365,8 @@
 void SourceCodeInfo_Location::SharedCtor() {
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
-  leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  leading_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  trailing_comments_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -8555,12 +13376,8 @@
 }
 
 void SourceCodeInfo_Location::SharedDtor() {
-  if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete leading_comments_;
-  }
-  if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete trailing_comments_;
-  }
+  leading_comments_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  trailing_comments_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -8582,32 +13399,36 @@
 
 SourceCodeInfo_Location* SourceCodeInfo_Location::default_instance_ = NULL;
 
-SourceCodeInfo_Location* SourceCodeInfo_Location::New() const {
-  return new SourceCodeInfo_Location;
+SourceCodeInfo_Location* SourceCodeInfo_Location::New(::google::protobuf::Arena* arena) const {
+  SourceCodeInfo_Location* n = new SourceCodeInfo_Location;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void SourceCodeInfo_Location::Clear() {
-  if (_has_bits_[0 / 32] & 12) {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo.Location)
+  if (_has_bits_[0 / 32] & 12u) {
     if (has_leading_comments()) {
-      if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        leading_comments_->clear();
-      }
+      leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
     if (has_trailing_comments()) {
-      if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-        trailing_comments_->clear();
-      }
+      trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     }
   }
   path_.Clear();
   span_.Clear();
+  leading_detached_comments_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool SourceCodeInfo_Location::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo.Location)
   for (;;) {
@@ -8659,7 +13480,7 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->leading_comments().data(), this->leading_comments().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "leading_comments");
+            "google.protobuf.SourceCodeInfo.Location.leading_comments");
         } else {
           goto handle_unusual;
         }
@@ -8676,10 +13497,29 @@
           ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
             this->trailing_comments().data(), this->trailing_comments().length(),
             ::google::protobuf::internal::WireFormat::PARSE,
-            "trailing_comments");
+            "google.protobuf.SourceCodeInfo.Location.trailing_comments");
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(50)) goto parse_leading_detached_comments;
+        break;
+      }
+
+      // repeated string leading_detached_comments = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_leading_detached_comments:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_leading_detached_comments()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->leading_detached_comments(this->leading_detached_comments_size() - 1).data(),
+            this->leading_detached_comments(this->leading_detached_comments_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_leading_detached_comments;
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -8734,7 +13574,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->leading_comments().data(), this->leading_comments().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "leading_comments");
+      "google.protobuf.SourceCodeInfo.Location.leading_comments");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       3, this->leading_comments(), output);
   }
@@ -8744,12 +13584,22 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->trailing_comments().data(), this->trailing_comments().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "trailing_comments");
+      "google.protobuf.SourceCodeInfo.Location.trailing_comments");
     ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
       4, this->trailing_comments(), output);
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated string leading_detached_comments = 6;
+  for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->leading_detached_comments(i).data(), this->leading_detached_comments(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      6, this->leading_detached_comments(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -8792,7 +13642,7 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->leading_comments().data(), this->leading_comments().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "leading_comments");
+      "google.protobuf.SourceCodeInfo.Location.leading_comments");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         3, this->leading_comments(), target);
@@ -8803,13 +13653,23 @@
     ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
       this->trailing_comments().data(), this->trailing_comments().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE,
-      "trailing_comments");
+      "google.protobuf.SourceCodeInfo.Location.trailing_comments");
     target =
       ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
         4, this->trailing_comments(), target);
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated string leading_detached_comments = 6;
+  for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->leading_detached_comments(i).data(), this->leading_detached_comments(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(6, this->leading_detached_comments(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -8818,9 +13678,10 @@
 }
 
 int SourceCodeInfo_Location::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location)
   int total_size = 0;
 
-  if (_has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+  if (_has_bits_[2 / 32] & 12u) {
     // optional string leading_comments = 3;
     if (has_leading_comments()) {
       total_size += 1 +
@@ -8870,7 +13731,14 @@
     total_size += data_size;
   }
 
-  if (!unknown_fields().empty()) {
+  // repeated string leading_detached_comments = 6;
+  total_size += 1 * this->leading_detached_comments_size();
+  for (int i = 0; i < this->leading_detached_comments_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->leading_detached_comments(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -8882,39 +13750,50 @@
 }
 
 void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const SourceCodeInfo_Location* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo_Location*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo.Location)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SourceCodeInfo_Location* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo_Location>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo.Location)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo.Location)
     MergeFrom(*source);
   }
 }
 
 void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   path_.MergeFrom(from.path_);
   span_.MergeFrom(from.span_);
+  leading_detached_comments_.MergeFrom(from.leading_detached_comments_);
   if (from._has_bits_[2 / 32] & (0xffu << (2 % 32))) {
     if (from.has_leading_comments()) {
-      set_leading_comments(from.leading_comments());
+      set_has_leading_comments();
+      leading_comments_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.leading_comments_);
     }
     if (from.has_trailing_comments()) {
-      set_trailing_comments(from.trailing_comments());
+      set_has_trailing_comments();
+      trailing_comments_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.trailing_comments_);
     }
   }
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo.Location)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo.Location)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -8926,15 +13805,18 @@
 }
 
 void SourceCodeInfo_Location::Swap(SourceCodeInfo_Location* other) {
-  if (other != this) {
-    path_.Swap(&other->path_);
-    span_.Swap(&other->span_);
-    std::swap(leading_comments_, other->leading_comments_);
-    std::swap(trailing_comments_, other->trailing_comments_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SourceCodeInfo_Location::InternalSwap(SourceCodeInfo_Location* other) {
+  path_.UnsafeArenaSwap(&other->path_);
+  span_.UnsafeArenaSwap(&other->span_);
+  leading_comments_.Swap(&other->leading_comments_);
+  trailing_comments_.Swap(&other->trailing_comments_);
+  leading_detached_comments_.UnsafeArenaSwap(&other->leading_detached_comments_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata SourceCodeInfo_Location::GetMetadata() const {
@@ -8948,12 +13830,12 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int SourceCodeInfo::kLocationFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceCodeInfo::SourceCodeInfo()
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo)
 }
@@ -8962,7 +13844,8 @@
 }
 
 SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from)
-  : ::google::protobuf::Message() {
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo)
@@ -9000,19 +13883,26 @@
 
 SourceCodeInfo* SourceCodeInfo::default_instance_ = NULL;
 
-SourceCodeInfo* SourceCodeInfo::New() const {
-  return new SourceCodeInfo;
+SourceCodeInfo* SourceCodeInfo::New(::google::protobuf::Arena* arena) const {
+  SourceCodeInfo* n = new SourceCodeInfo;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
 }
 
 void SourceCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo)
   location_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
-  mutable_unknown_fields()->Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
 }
 
 bool SourceCodeInfo::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo)
   for (;;) {
@@ -9023,13 +13913,15 @@
       // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
       case 1: {
         if (tag == 10) {
-         parse_location:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_location:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_location()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_location;
+        if (input->ExpectTag(10)) goto parse_loop_location;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -9060,12 +13952,12 @@
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:google.protobuf.SourceCodeInfo)
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  for (int i = 0; i < this->location_size(); i++) {
+  for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
       1, this->location(i), output);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
   }
@@ -9076,13 +13968,13 @@
     ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  for (int i = 0; i < this->location_size(); i++) {
+  for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
       WriteMessageNoVirtualToArray(
         1, this->location(i), target);
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
   }
@@ -9091,6 +13983,7 @@
 }
 
 int SourceCodeInfo::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo)
   int total_size = 0;
 
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
@@ -9101,7 +13994,7 @@
         this->location(i));
   }
 
-  if (!unknown_fields().empty()) {
+  if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
         unknown_fields());
@@ -9113,30 +14006,38 @@
 }
 
 void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  const SourceCodeInfo* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo*>(
-      &from);
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SourceCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo>(
+          &from);
   if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo)
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo)
     MergeFrom(*source);
   }
 }
 
 void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) {
-  GOOGLE_CHECK_NE(&from, this);
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   location_.MergeFrom(from.location_);
-  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
 }
 
 void SourceCodeInfo::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
 }
 
 void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo)
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -9148,12 +14049,14 @@
 }
 
 void SourceCodeInfo::Swap(SourceCodeInfo* other) {
-  if (other != this) {
-    location_.Swap(&other->location_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    _unknown_fields_.Swap(&other->_unknown_fields_);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) {
+  location_.UnsafeArenaSwap(&other->location_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata SourceCodeInfo::GetMetadata() const {
@@ -9164,6 +14067,1098 @@
   return metadata;
 }
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SourceCodeInfo_Location
+
+// repeated int32 path = 1 [packed = true];
+int SourceCodeInfo_Location::path_size() const {
+  return path_.size();
+}
+void SourceCodeInfo_Location::clear_path() {
+  path_.Clear();
+}
+ ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.path)
+  return path_.Get(index);
+}
+ void SourceCodeInfo_Location::set_path(int index, ::google::protobuf::int32 value) {
+  path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.path)
+}
+ void SourceCodeInfo_Location::add_path(::google::protobuf::int32 value) {
+  path_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.path)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SourceCodeInfo_Location::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.path)
+  return path_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SourceCodeInfo_Location::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.path)
+  return &path_;
+}
+
+// repeated int32 span = 2 [packed = true];
+int SourceCodeInfo_Location::span_size() const {
+  return span_.size();
+}
+void SourceCodeInfo_Location::clear_span() {
+  span_.Clear();
+}
+ ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.span)
+  return span_.Get(index);
+}
+ void SourceCodeInfo_Location::set_span(int index, ::google::protobuf::int32 value) {
+  span_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.span)
+}
+ void SourceCodeInfo_Location::add_span(::google::protobuf::int32 value) {
+  span_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.span)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SourceCodeInfo_Location::span() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.span)
+  return span_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SourceCodeInfo_Location::mutable_span() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.span)
+  return &span_;
+}
+
+// optional string leading_comments = 3;
+bool SourceCodeInfo_Location::has_leading_comments() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void SourceCodeInfo_Location::set_has_leading_comments() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void SourceCodeInfo_Location::clear_has_leading_comments() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void SourceCodeInfo_Location::clear_leading_comments() {
+  leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_leading_comments();
+}
+ const ::std::string& SourceCodeInfo_Location::leading_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return leading_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) {
+  set_has_leading_comments();
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ void SourceCodeInfo_Location::set_leading_comments(const char* value) {
+  set_has_leading_comments();
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) {
+  set_has_leading_comments();
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+ ::std::string* SourceCodeInfo_Location::mutable_leading_comments() {
+  set_has_leading_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* SourceCodeInfo_Location::release_leading_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments)
+  clear_has_leading_comments();
+  return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) {
+  if (leading_comments != NULL) {
+    set_has_leading_comments();
+  } else {
+    clear_has_leading_comments();
+  }
+  leading_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), leading_comments);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
+}
+
+// optional string trailing_comments = 4;
+bool SourceCodeInfo_Location::has_trailing_comments() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void SourceCodeInfo_Location::set_has_trailing_comments() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void SourceCodeInfo_Location::clear_has_trailing_comments() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void SourceCodeInfo_Location::clear_trailing_comments() {
+  trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_trailing_comments();
+}
+ const ::std::string& SourceCodeInfo_Location::trailing_comments() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return trailing_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) {
+  set_has_trailing_comments();
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const char* value) {
+  set_has_trailing_comments();
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) {
+  set_has_trailing_comments();
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+ ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
+  set_has_trailing_comments();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* SourceCodeInfo_Location::release_trailing_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+  clear_has_trailing_comments();
+  return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) {
+  if (trailing_comments != NULL) {
+    set_has_trailing_comments();
+  } else {
+    clear_has_trailing_comments();
+  }
+  trailing_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), trailing_comments);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
+}
+
+// repeated string leading_detached_comments = 6;
+int SourceCodeInfo_Location::leading_detached_comments_size() const {
+  return leading_detached_comments_.size();
+}
+void SourceCodeInfo_Location::clear_leading_detached_comments() {
+  leading_detached_comments_.Clear();
+}
+ const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Get(index);
+}
+ ::std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Mutable(index);
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  leading_detached_comments_.Mutable(index)->assign(value);
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+  leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+  leading_detached_comments_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Add();
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) {
+  leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+  leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+  leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return &leading_detached_comments_;
+}
+
+// -------------------------------------------------------------------
+
+// SourceCodeInfo
+
+// repeated .google.protobuf.SourceCodeInfo.Location location = 1;
+int SourceCodeInfo::location_size() const {
+  return location_.size();
+}
+void SourceCodeInfo::clear_location() {
+  location_.Clear();
+}
+const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location)
+  return location_.Get(index);
+}
+::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location)
+  return location_.Mutable(index);
+}
+::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() {
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
+  return location_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
+SourceCodeInfo::mutable_location() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
+  return &location_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+SourceCodeInfo::location() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
+  return location_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GeneratedCodeInfo_Annotation::kPathFieldNumber;
+const int GeneratedCodeInfo_Annotation::kSourceFileFieldNumber;
+const int GeneratedCodeInfo_Annotation::kBeginFieldNumber;
+const int GeneratedCodeInfo_Annotation::kEndFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+void GeneratedCodeInfo_Annotation::InitAsDefaultInstance() {
+}
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+void GeneratedCodeInfo_Annotation::SharedCtor() {
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  source_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  begin_ = 0;
+  end_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation)
+  SharedDtor();
+}
+
+void GeneratedCodeInfo_Annotation::SharedDtor() {
+  source_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GeneratedCodeInfo_Annotation_descriptor_;
+}
+
+const GeneratedCodeInfo_Annotation& GeneratedCodeInfo_Annotation::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::default_instance_ = NULL;
+
+GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::New(::google::protobuf::Arena* arena) const {
+  GeneratedCodeInfo_Annotation* n = new GeneratedCodeInfo_Annotation;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void GeneratedCodeInfo_Annotation::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo.Annotation)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(GeneratedCodeInfo_Annotation, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<GeneratedCodeInfo_Annotation*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 14u) {
+    ZR_(begin_, end_);
+    if (has_source_file()) {
+      source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  path_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated int32 path = 1 [packed = true];
+      case 1: {
+        if (tag == 10) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_path())));
+        } else if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 10, input, this->mutable_path())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_source_file;
+        break;
+      }
+
+      // optional string source_file = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_source_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source_file().data(), this->source_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_begin;
+        break;
+      }
+
+      // optional int32 begin = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_begin:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &begin_)));
+          set_has_begin();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_end;
+        break;
+      }
+
+      // optional int32 end = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_end:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &end_)));
+          set_has_end();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo.Annotation)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo.Annotation)
+  return false;
+#undef DO_
+}
+
+void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  // repeated int32 path = 1 [packed = true];
+  if (this->path_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_path_cached_byte_size_);
+  }
+  for (int i = 0; i < this->path_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+      this->path(i), output);
+  }
+
+  // optional string source_file = 2;
+  if (has_source_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source_file().data(), this->source_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->source_file(), output);
+  }
+
+  // optional int32 begin = 3;
+  if (has_begin()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->begin(), output);
+  }
+
+  // optional int32 end = 4;
+  if (has_end()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->end(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+::google::protobuf::uint8* GeneratedCodeInfo_Annotation::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  // repeated int32 path = 1 [packed = true];
+  if (this->path_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      1,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _path_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->path_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32NoTagToArray(this->path(i), target);
+  }
+
+  // optional string source_file = 2;
+  if (has_source_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source_file().data(), this->source_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->source_file(), target);
+  }
+
+  // optional int32 begin = 3;
+  if (has_begin()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->begin(), target);
+  }
+
+  // optional int32 end = 4;
+  if (has_end()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->end(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
+  return target;
+}
+
+int GeneratedCodeInfo_Annotation::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  int total_size = 0;
+
+  if (_has_bits_[1 / 32] & 14u) {
+    // optional string source_file = 2;
+    if (has_source_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source_file());
+    }
+
+    // optional int32 begin = 3;
+    if (has_begin()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->begin());
+    }
+
+    // optional int32 end = 4;
+    if (has_end()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->end());
+    }
+
+  }
+  // repeated int32 path = 1 [packed = true];
+  {
+    int data_size = 0;
+    for (int i = 0; i < this->path_size(); i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->path(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _path_cached_byte_size_ = data_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GeneratedCodeInfo_Annotation::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo_Annotation* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo.Annotation)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo.Annotation)
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  path_.MergeFrom(from.path_);
+  if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
+    if (from.has_source_file()) {
+      set_has_source_file();
+      source_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_file_);
+    }
+    if (from.has_begin()) {
+      set_begin(from.begin());
+    }
+    if (from.has_end()) {
+      set_end(from.end());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo_Annotation::IsInitialized() const {
+
+  return true;
+}
+
+void GeneratedCodeInfo_Annotation::Swap(GeneratedCodeInfo_Annotation* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) {
+  path_.UnsafeArenaSwap(&other->path_);
+  source_file_.Swap(&other->source_file_);
+  std::swap(begin_, other->begin_);
+  std::swap(end_, other->end_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GeneratedCodeInfo_Annotation_descriptor_;
+  metadata.reflection = GeneratedCodeInfo_Annotation_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GeneratedCodeInfo::kAnnotationFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GeneratedCodeInfo::GeneratedCodeInfo()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+void GeneratedCodeInfo::InitAsDefaultInstance() {
+}
+
+GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+void GeneratedCodeInfo::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+GeneratedCodeInfo::~GeneratedCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo)
+  SharedDtor();
+}
+
+void GeneratedCodeInfo::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void GeneratedCodeInfo::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GeneratedCodeInfo::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GeneratedCodeInfo_descriptor_;
+}
+
+const GeneratedCodeInfo& GeneratedCodeInfo::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+GeneratedCodeInfo* GeneratedCodeInfo::default_instance_ = NULL;
+
+GeneratedCodeInfo* GeneratedCodeInfo::New(::google::protobuf::Arena* arena) const {
+  GeneratedCodeInfo* n = new GeneratedCodeInfo;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void GeneratedCodeInfo::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo)
+  annotation_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool GeneratedCodeInfo::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_annotation:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_annotation()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_annotation;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo)
+  return false;
+#undef DO_
+}
+
+void GeneratedCodeInfo::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo)
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->annotation(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo)
+}
+
+::google::protobuf::uint8* GeneratedCodeInfo::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        1, this->annotation(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
+  return target;
+}
+
+int GeneratedCodeInfo::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo)
+  int total_size = 0;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  total_size += 1 * this->annotation_size();
+  for (int i = 0; i < this->annotation_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->annotation(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GeneratedCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo)
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  annotation_.MergeFrom(from.annotation_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void GeneratedCodeInfo::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo::IsInitialized() const {
+
+  return true;
+}
+
+void GeneratedCodeInfo::Swap(GeneratedCodeInfo* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) {
+  annotation_.UnsafeArenaSwap(&other->annotation_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GeneratedCodeInfo::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GeneratedCodeInfo_descriptor_;
+  metadata.reflection = GeneratedCodeInfo_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+int GeneratedCodeInfo_Annotation::path_size() const {
+  return path_.size();
+}
+void GeneratedCodeInfo_Annotation::clear_path() {
+  path_.Clear();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_.Get(index);
+}
+ void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) {
+  path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+ void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) {
+  path_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return &path_;
+}
+
+// optional string source_file = 2;
+bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_source_file() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_source_file() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void GeneratedCodeInfo_Annotation::clear_source_file() {
+  source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source_file();
+}
+ const ::std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const char* value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  set_has_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  clear_has_source_file();
+  return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) {
+  if (source_file != NULL) {
+    set_has_source_file();
+  } else {
+    clear_has_source_file();
+  }
+  source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_begin() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_begin() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void GeneratedCodeInfo_Annotation::clear_begin() {
+  begin_ = 0;
+  clear_has_begin();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return begin_;
+}
+ void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) {
+  set_has_begin();
+  begin_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+bool GeneratedCodeInfo_Annotation::has_end() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_end() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_end() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void GeneratedCodeInfo_Annotation::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return end_;
+}
+ void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+int GeneratedCodeInfo::annotation_size() const {
+  return annotation_.size();
+}
+void GeneratedCodeInfo::clear_annotation() {
+  annotation_.Clear();
+}
+const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Get(index);
+}
+::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Mutable(index);
+}
+::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &annotation_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 91a20b8..92a0a3a 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -8,18 +8,21 @@
 
 #include <google/protobuf/stubs/common.h>
 
-#if GOOGLE_PROTOBUF_VERSION < 2006000
+#if GOOGLE_PROTOBUF_VERSION < 3000000
 #error This file was generated by a newer version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please update
 #error your headers.
 #endif
-#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
 #error This file was generated by an older version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please
 #error regenerate this file with a newer version of protoc.
 #endif
 
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
@@ -35,27 +38,30 @@
 void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
 void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
 
-class FileDescriptorSet;
-class FileDescriptorProto;
 class DescriptorProto;
 class DescriptorProto_ExtensionRange;
-class FieldDescriptorProto;
-class OneofDescriptorProto;
+class DescriptorProto_ReservedRange;
 class EnumDescriptorProto;
-class EnumValueDescriptorProto;
-class ServiceDescriptorProto;
-class MethodDescriptorProto;
-class FileOptions;
-class MessageOptions;
-class FieldOptions;
 class EnumOptions;
+class EnumValueDescriptorProto;
 class EnumValueOptions;
-class ServiceOptions;
+class FieldDescriptorProto;
+class FieldOptions;
+class FileDescriptorProto;
+class FileDescriptorSet;
+class FileOptions;
+class GeneratedCodeInfo;
+class GeneratedCodeInfo_Annotation;
+class MessageOptions;
+class MethodDescriptorProto;
 class MethodOptions;
-class UninterpretedOption;
-class UninterpretedOption_NamePart;
+class OneofDescriptorProto;
+class ServiceDescriptorProto;
+class ServiceOptions;
 class SourceCodeInfo;
 class SourceCodeInfo_Location;
+class UninterpretedOption;
+class UninterpretedOption_NamePart;
 
 enum FieldDescriptorProto_Type {
   FieldDescriptorProto_Type_TYPE_DOUBLE = 1,
@@ -152,6 +158,26 @@
   return ::google::protobuf::internal::ParseNamedEnum<FieldOptions_CType>(
     FieldOptions_CType_descriptor(), name, value);
 }
+enum FieldOptions_JSType {
+  FieldOptions_JSType_JS_NORMAL = 0,
+  FieldOptions_JSType_JS_STRING = 1,
+  FieldOptions_JSType_JS_NUMBER = 2
+};
+LIBPROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
+const FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
+const FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
+const int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor();
+inline const ::std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    FieldOptions_JSType_descriptor(), value);
+}
+inline bool FieldOptions_JSType_Parse(
+    const ::std::string& name, FieldOptions_JSType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<FieldOptions_JSType>(
+    FieldOptions_JSType_descriptor(), name, value);
+}
 // ===================================================================
 
 class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message {
@@ -167,11 +193,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -181,7 +207,9 @@
 
   // implements Message ----------------------------------------------
 
-  FileDescriptorSet* New() const;
+  inline FileDescriptorSet* New() const { return New(NULL); }
+
+  FileDescriptorSet* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const FileDescriptorSet& from);
@@ -200,7 +228,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(FileDescriptorSet* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -208,22 +245,21 @@
   // accessors -------------------------------------------------------
 
   // repeated .google.protobuf.FileDescriptorProto file = 1;
-  inline int file_size() const;
-  inline void clear_file();
+  int file_size() const;
+  void clear_file();
   static const int kFileFieldNumber = 1;
-  inline const ::google::protobuf::FileDescriptorProto& file(int index) const;
-  inline ::google::protobuf::FileDescriptorProto* mutable_file(int index);
-  inline ::google::protobuf::FileDescriptorProto* add_file();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-      file() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+  const ::google::protobuf::FileDescriptorProto& file(int index) const;
+  ::google::protobuf::FileDescriptorProto* mutable_file(int index);
+  ::google::protobuf::FileDescriptorProto* add_file();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
       mutable_file();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+      file() const;
 
   // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
  private:
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_;
@@ -249,11 +285,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -263,7 +299,9 @@
 
   // implements Message ----------------------------------------------
 
-  FileDescriptorProto* New() const;
+  inline FileDescriptorProto* New() const { return New(NULL); }
+
+  FileDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const FileDescriptorProto& from);
@@ -282,7 +320,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(FileDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -290,134 +337,146 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // optional string package = 2;
-  inline bool has_package() const;
-  inline void clear_package();
+  bool has_package() const;
+  void clear_package();
   static const int kPackageFieldNumber = 2;
-  inline const ::std::string& package() const;
-  inline void set_package(const ::std::string& value);
-  inline void set_package(const char* value);
-  inline void set_package(const char* value, size_t size);
-  inline ::std::string* mutable_package();
-  inline ::std::string* release_package();
-  inline void set_allocated_package(::std::string* package);
+  const ::std::string& package() const;
+  void set_package(const ::std::string& value);
+  void set_package(const char* value);
+  void set_package(const char* value, size_t size);
+  ::std::string* mutable_package();
+  ::std::string* release_package();
+  void set_allocated_package(::std::string* package);
 
   // repeated string dependency = 3;
-  inline int dependency_size() const;
-  inline void clear_dependency();
+  int dependency_size() const;
+  void clear_dependency();
   static const int kDependencyFieldNumber = 3;
-  inline const ::std::string& dependency(int index) const;
-  inline ::std::string* mutable_dependency(int index);
-  inline void set_dependency(int index, const ::std::string& value);
-  inline void set_dependency(int index, const char* value);
-  inline void set_dependency(int index, const char* value, size_t size);
-  inline ::std::string* add_dependency();
-  inline void add_dependency(const ::std::string& value);
-  inline void add_dependency(const char* value);
-  inline void add_dependency(const char* value, size_t size);
-  inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
-  inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
+  const ::std::string& dependency(int index) const;
+  ::std::string* mutable_dependency(int index);
+  void set_dependency(int index, const ::std::string& value);
+  void set_dependency(int index, const char* value);
+  void set_dependency(int index, const char* value, size_t size);
+  ::std::string* add_dependency();
+  void add_dependency(const ::std::string& value);
+  void add_dependency(const char* value);
+  void add_dependency(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency();
 
   // repeated int32 public_dependency = 10;
-  inline int public_dependency_size() const;
-  inline void clear_public_dependency();
+  int public_dependency_size() const;
+  void clear_public_dependency();
   static const int kPublicDependencyFieldNumber = 10;
-  inline ::google::protobuf::int32 public_dependency(int index) const;
-  inline void set_public_dependency(int index, ::google::protobuf::int32 value);
-  inline void add_public_dependency(::google::protobuf::int32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+  ::google::protobuf::int32 public_dependency(int index) const;
+  void set_public_dependency(int index, ::google::protobuf::int32 value);
+  void add_public_dependency(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
       public_dependency() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
       mutable_public_dependency();
 
   // repeated int32 weak_dependency = 11;
-  inline int weak_dependency_size() const;
-  inline void clear_weak_dependency();
+  int weak_dependency_size() const;
+  void clear_weak_dependency();
   static const int kWeakDependencyFieldNumber = 11;
-  inline ::google::protobuf::int32 weak_dependency(int index) const;
-  inline void set_weak_dependency(int index, ::google::protobuf::int32 value);
-  inline void add_weak_dependency(::google::protobuf::int32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+  ::google::protobuf::int32 weak_dependency(int index) const;
+  void set_weak_dependency(int index, ::google::protobuf::int32 value);
+  void add_weak_dependency(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
       weak_dependency() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
       mutable_weak_dependency();
 
   // repeated .google.protobuf.DescriptorProto message_type = 4;
-  inline int message_type_size() const;
-  inline void clear_message_type();
+  int message_type_size() const;
+  void clear_message_type();
   static const int kMessageTypeFieldNumber = 4;
-  inline const ::google::protobuf::DescriptorProto& message_type(int index) const;
-  inline ::google::protobuf::DescriptorProto* mutable_message_type(int index);
-  inline ::google::protobuf::DescriptorProto* add_message_type();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-      message_type() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+  const ::google::protobuf::DescriptorProto& message_type(int index) const;
+  ::google::protobuf::DescriptorProto* mutable_message_type(int index);
+  ::google::protobuf::DescriptorProto* add_message_type();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
       mutable_message_type();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+      message_type() const;
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  inline int enum_type_size() const;
-  inline void clear_enum_type();
+  int enum_type_size() const;
+  void clear_enum_type();
   static const int kEnumTypeFieldNumber = 5;
-  inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
-  inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
-  inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-      enum_type() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+  const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+  ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+  ::google::protobuf::EnumDescriptorProto* add_enum_type();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
       mutable_enum_type();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+      enum_type() const;
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  inline int service_size() const;
-  inline void clear_service();
+  int service_size() const;
+  void clear_service();
   static const int kServiceFieldNumber = 6;
-  inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
-  inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
-  inline ::google::protobuf::ServiceDescriptorProto* add_service();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
-      service() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
+  const ::google::protobuf::ServiceDescriptorProto& service(int index) const;
+  ::google::protobuf::ServiceDescriptorProto* mutable_service(int index);
+  ::google::protobuf::ServiceDescriptorProto* add_service();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
       mutable_service();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+      service() const;
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  inline int extension_size() const;
-  inline void clear_extension();
+  int extension_size() const;
+  void clear_extension();
   static const int kExtensionFieldNumber = 7;
-  inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
-  inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
-  inline ::google::protobuf::FieldDescriptorProto* add_extension();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      extension() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+  const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+  ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+  ::google::protobuf::FieldDescriptorProto* add_extension();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_extension();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      extension() const;
 
   // optional .google.protobuf.FileOptions options = 8;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 8;
-  inline const ::google::protobuf::FileOptions& options() const;
-  inline ::google::protobuf::FileOptions* mutable_options();
-  inline ::google::protobuf::FileOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::FileOptions* options);
+  const ::google::protobuf::FileOptions& options() const;
+  ::google::protobuf::FileOptions* mutable_options();
+  ::google::protobuf::FileOptions* release_options();
+  void set_allocated_options(::google::protobuf::FileOptions* options);
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
-  inline bool has_source_code_info() const;
-  inline void clear_source_code_info();
+  bool has_source_code_info() const;
+  void clear_source_code_info();
   static const int kSourceCodeInfoFieldNumber = 9;
-  inline const ::google::protobuf::SourceCodeInfo& source_code_info() const;
-  inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info();
-  inline ::google::protobuf::SourceCodeInfo* release_source_code_info();
-  inline void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info);
+  const ::google::protobuf::SourceCodeInfo& source_code_info() const;
+  ::google::protobuf::SourceCodeInfo* mutable_source_code_info();
+  ::google::protobuf::SourceCodeInfo* release_source_code_info();
+  void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info);
+
+  // optional string syntax = 12;
+  bool has_syntax() const;
+  void clear_syntax();
+  static const int kSyntaxFieldNumber = 12;
+  const ::std::string& syntax() const;
+  void set_syntax(const ::std::string& value);
+  void set_syntax(const char* value);
+  void set_syntax(const char* value, size_t size);
+  ::std::string* mutable_syntax();
+  ::std::string* release_syntax();
+  void set_allocated_syntax(::std::string* syntax);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
  private:
@@ -429,13 +488,14 @@
   inline void clear_has_options();
   inline void set_has_source_code_info();
   inline void clear_has_source_code_info();
+  inline void set_has_syntax();
+  inline void clear_has_syntax();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
-  ::std::string* package_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr package_;
   ::google::protobuf::RepeatedPtrField< ::std::string> dependency_;
   ::google::protobuf::RepeatedField< ::google::protobuf::int32 > public_dependency_;
   ::google::protobuf::RepeatedField< ::google::protobuf::int32 > weak_dependency_;
@@ -445,6 +505,7 @@
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
   ::google::protobuf::FileOptions* options_;
   ::google::protobuf::SourceCodeInfo* source_code_info_;
+  ::google::protobuf::internal::ArenaStringPtr syntax_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -467,11 +528,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -481,7 +542,9 @@
 
   // implements Message ----------------------------------------------
 
-  DescriptorProto_ExtensionRange* New() const;
+  inline DescriptorProto_ExtensionRange* New() const { return New(NULL); }
+
+  DescriptorProto_ExtensionRange* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const DescriptorProto_ExtensionRange& from);
@@ -500,7 +563,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(DescriptorProto_ExtensionRange* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -508,18 +580,18 @@
   // accessors -------------------------------------------------------
 
   // optional int32 start = 1;
-  inline bool has_start() const;
-  inline void clear_start();
+  bool has_start() const;
+  void clear_start();
   static const int kStartFieldNumber = 1;
-  inline ::google::protobuf::int32 start() const;
-  inline void set_start(::google::protobuf::int32 value);
+  ::google::protobuf::int32 start() const;
+  void set_start(::google::protobuf::int32 value);
 
   // optional int32 end = 2;
-  inline bool has_end() const;
-  inline void clear_end();
+  bool has_end() const;
+  void clear_end();
   static const int kEndFieldNumber = 2;
-  inline ::google::protobuf::int32 end() const;
-  inline void set_end(::google::protobuf::int32 value);
+  ::google::protobuf::int32 end() const;
+  void set_end(::google::protobuf::int32 value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
  private:
@@ -528,8 +600,7 @@
   inline void set_has_end();
   inline void clear_has_end();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::int32 start_;
@@ -543,6 +614,105 @@
 };
 // -------------------------------------------------------------------
 
+class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message {
+ public:
+  DescriptorProto_ReservedRange();
+  virtual ~DescriptorProto_ReservedRange();
+
+  DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from);
+
+  inline DescriptorProto_ReservedRange& operator=(const DescriptorProto_ReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DescriptorProto_ReservedRange& default_instance();
+
+  void Swap(DescriptorProto_ReservedRange* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DescriptorProto_ReservedRange* New() const { return New(NULL); }
+
+  DescriptorProto_ReservedRange* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DescriptorProto_ReservedRange& from);
+  void MergeFrom(const DescriptorProto_ReservedRange& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DescriptorProto_ReservedRange* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 start = 1;
+  bool has_start() const;
+  void clear_start();
+  static const int kStartFieldNumber = 1;
+  ::google::protobuf::int32 start() const;
+  void set_start(::google::protobuf::int32 value);
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  void clear_end();
+  static const int kEndFieldNumber = 2;
+  ::google::protobuf::int32 end() const;
+  void set_end(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange)
+ private:
+  inline void set_has_start();
+  inline void clear_has_start();
+  inline void set_has_end();
+  inline void clear_has_end();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::int32 start_;
+  ::google::protobuf::int32 end_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static DescriptorProto_ReservedRange* default_instance_;
+};
+// -------------------------------------------------------------------
+
 class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
  public:
   DescriptorProto();
@@ -556,11 +726,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -570,7 +740,9 @@
 
   // implements Message ----------------------------------------------
 
-  DescriptorProto* New() const;
+  inline DescriptorProto* New() const { return New(NULL); }
+
+  DescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const DescriptorProto& from);
@@ -589,107 +761,145 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(DescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
 
   typedef DescriptorProto_ExtensionRange ExtensionRange;
+  typedef DescriptorProto_ReservedRange ReservedRange;
 
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  inline int field_size() const;
-  inline void clear_field();
+  int field_size() const;
+  void clear_field();
   static const int kFieldFieldNumber = 2;
-  inline const ::google::protobuf::FieldDescriptorProto& field(int index) const;
-  inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
-  inline ::google::protobuf::FieldDescriptorProto* add_field();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      field() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+  const ::google::protobuf::FieldDescriptorProto& field(int index) const;
+  ::google::protobuf::FieldDescriptorProto* mutable_field(int index);
+  ::google::protobuf::FieldDescriptorProto* add_field();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_field();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      field() const;
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  inline int extension_size() const;
-  inline void clear_extension();
+  int extension_size() const;
+  void clear_extension();
   static const int kExtensionFieldNumber = 6;
-  inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
-  inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
-  inline ::google::protobuf::FieldDescriptorProto* add_extension();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-      extension() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
+  const ::google::protobuf::FieldDescriptorProto& extension(int index) const;
+  ::google::protobuf::FieldDescriptorProto* mutable_extension(int index);
+  ::google::protobuf::FieldDescriptorProto* add_extension();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
       mutable_extension();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+      extension() const;
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  inline int nested_type_size() const;
-  inline void clear_nested_type();
+  int nested_type_size() const;
+  void clear_nested_type();
   static const int kNestedTypeFieldNumber = 3;
-  inline const ::google::protobuf::DescriptorProto& nested_type(int index) const;
-  inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
-  inline ::google::protobuf::DescriptorProto* add_nested_type();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-      nested_type() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
+  const ::google::protobuf::DescriptorProto& nested_type(int index) const;
+  ::google::protobuf::DescriptorProto* mutable_nested_type(int index);
+  ::google::protobuf::DescriptorProto* add_nested_type();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
       mutable_nested_type();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+      nested_type() const;
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  inline int enum_type_size() const;
-  inline void clear_enum_type();
+  int enum_type_size() const;
+  void clear_enum_type();
   static const int kEnumTypeFieldNumber = 4;
-  inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
-  inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
-  inline ::google::protobuf::EnumDescriptorProto* add_enum_type();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-      enum_type() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
+  const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const;
+  ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index);
+  ::google::protobuf::EnumDescriptorProto* add_enum_type();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
       mutable_enum_type();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+      enum_type() const;
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  inline int extension_range_size() const;
-  inline void clear_extension_range();
+  int extension_range_size() const;
+  void clear_extension_range();
   static const int kExtensionRangeFieldNumber = 5;
-  inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const;
-  inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
-  inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
-      extension_range() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
+  const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const;
+  ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index);
+  ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
       mutable_extension_range();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+      extension_range() const;
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  inline int oneof_decl_size() const;
-  inline void clear_oneof_decl();
+  int oneof_decl_size() const;
+  void clear_oneof_decl();
   static const int kOneofDeclFieldNumber = 8;
-  inline const ::google::protobuf::OneofDescriptorProto& oneof_decl(int index) const;
-  inline ::google::protobuf::OneofDescriptorProto* mutable_oneof_decl(int index);
-  inline ::google::protobuf::OneofDescriptorProto* add_oneof_decl();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
-      oneof_decl() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
+  const ::google::protobuf::OneofDescriptorProto& oneof_decl(int index) const;
+  ::google::protobuf::OneofDescriptorProto* mutable_oneof_decl(int index);
+  ::google::protobuf::OneofDescriptorProto* add_oneof_decl();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
       mutable_oneof_decl();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+      oneof_decl() const;
 
   // optional .google.protobuf.MessageOptions options = 7;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 7;
-  inline const ::google::protobuf::MessageOptions& options() const;
-  inline ::google::protobuf::MessageOptions* mutable_options();
-  inline ::google::protobuf::MessageOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::MessageOptions* options);
+  const ::google::protobuf::MessageOptions& options() const;
+  ::google::protobuf::MessageOptions* mutable_options();
+  ::google::protobuf::MessageOptions* release_options();
+  void set_allocated_options(::google::protobuf::MessageOptions* options);
+
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  int reserved_range_size() const;
+  void clear_reserved_range();
+  static const int kReservedRangeFieldNumber = 9;
+  const ::google::protobuf::DescriptorProto_ReservedRange& reserved_range(int index) const;
+  ::google::protobuf::DescriptorProto_ReservedRange* mutable_reserved_range(int index);
+  ::google::protobuf::DescriptorProto_ReservedRange* add_reserved_range();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+      mutable_reserved_range();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+      reserved_range() const;
+
+  // repeated string reserved_name = 10;
+  int reserved_name_size() const;
+  void clear_reserved_name();
+  static const int kReservedNameFieldNumber = 10;
+  const ::std::string& reserved_name(int index) const;
+  ::std::string* mutable_reserved_name(int index);
+  void set_reserved_name(int index, const ::std::string& value);
+  void set_reserved_name(int index, const char* value);
+  void set_reserved_name(int index, const char* value, size_t size);
+  ::std::string* add_reserved_name();
+  void add_reserved_name(const ::std::string& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& reserved_name() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_reserved_name();
 
   // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
  private:
@@ -698,11 +908,10 @@
   inline void set_has_options();
   inline void clear_has_options();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > nested_type_;
@@ -710,6 +919,8 @@
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto > oneof_decl_;
   ::google::protobuf::MessageOptions* options_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange > reserved_range_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> reserved_name_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -732,11 +943,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -746,7 +957,9 @@
 
   // implements Message ----------------------------------------------
 
-  FieldDescriptorProto* New() const;
+  inline FieldDescriptorProto* New() const { return New(NULL); }
+
+  FieldDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const FieldDescriptorProto& from);
@@ -765,30 +978,57 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(FieldDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
 
   typedef FieldDescriptorProto_Type Type;
-  static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE;
-  static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT;
-  static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64;
-  static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64;
-  static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32;
-  static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64;
-  static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32;
-  static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL;
-  static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING;
-  static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP;
-  static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE;
-  static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES;
-  static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32;
-  static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM;
-  static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32;
-  static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64;
-  static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32;
-  static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64;
+  static const Type TYPE_DOUBLE =
+    FieldDescriptorProto_Type_TYPE_DOUBLE;
+  static const Type TYPE_FLOAT =
+    FieldDescriptorProto_Type_TYPE_FLOAT;
+  static const Type TYPE_INT64 =
+    FieldDescriptorProto_Type_TYPE_INT64;
+  static const Type TYPE_UINT64 =
+    FieldDescriptorProto_Type_TYPE_UINT64;
+  static const Type TYPE_INT32 =
+    FieldDescriptorProto_Type_TYPE_INT32;
+  static const Type TYPE_FIXED64 =
+    FieldDescriptorProto_Type_TYPE_FIXED64;
+  static const Type TYPE_FIXED32 =
+    FieldDescriptorProto_Type_TYPE_FIXED32;
+  static const Type TYPE_BOOL =
+    FieldDescriptorProto_Type_TYPE_BOOL;
+  static const Type TYPE_STRING =
+    FieldDescriptorProto_Type_TYPE_STRING;
+  static const Type TYPE_GROUP =
+    FieldDescriptorProto_Type_TYPE_GROUP;
+  static const Type TYPE_MESSAGE =
+    FieldDescriptorProto_Type_TYPE_MESSAGE;
+  static const Type TYPE_BYTES =
+    FieldDescriptorProto_Type_TYPE_BYTES;
+  static const Type TYPE_UINT32 =
+    FieldDescriptorProto_Type_TYPE_UINT32;
+  static const Type TYPE_ENUM =
+    FieldDescriptorProto_Type_TYPE_ENUM;
+  static const Type TYPE_SFIXED32 =
+    FieldDescriptorProto_Type_TYPE_SFIXED32;
+  static const Type TYPE_SFIXED64 =
+    FieldDescriptorProto_Type_TYPE_SFIXED64;
+  static const Type TYPE_SINT32 =
+    FieldDescriptorProto_Type_TYPE_SINT32;
+  static const Type TYPE_SINT64 =
+    FieldDescriptorProto_Type_TYPE_SINT64;
   static inline bool Type_IsValid(int value) {
     return FieldDescriptorProto_Type_IsValid(value);
   }
@@ -811,9 +1051,12 @@
   }
 
   typedef FieldDescriptorProto_Label Label;
-  static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
-  static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
-  static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED;
+  static const Label LABEL_OPTIONAL =
+    FieldDescriptorProto_Label_LABEL_OPTIONAL;
+  static const Label LABEL_REQUIRED =
+    FieldDescriptorProto_Label_LABEL_REQUIRED;
+  static const Label LABEL_REPEATED =
+    FieldDescriptorProto_Label_LABEL_REPEATED;
   static inline bool Label_IsValid(int value) {
     return FieldDescriptorProto_Label_IsValid(value);
   }
@@ -838,89 +1081,101 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // optional int32 number = 3;
-  inline bool has_number() const;
-  inline void clear_number();
+  bool has_number() const;
+  void clear_number();
   static const int kNumberFieldNumber = 3;
-  inline ::google::protobuf::int32 number() const;
-  inline void set_number(::google::protobuf::int32 value);
+  ::google::protobuf::int32 number() const;
+  void set_number(::google::protobuf::int32 value);
 
   // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
-  inline bool has_label() const;
-  inline void clear_label();
+  bool has_label() const;
+  void clear_label();
   static const int kLabelFieldNumber = 4;
-  inline ::google::protobuf::FieldDescriptorProto_Label label() const;
-  inline void set_label(::google::protobuf::FieldDescriptorProto_Label value);
+  ::google::protobuf::FieldDescriptorProto_Label label() const;
+  void set_label(::google::protobuf::FieldDescriptorProto_Label value);
 
   // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
-  inline bool has_type() const;
-  inline void clear_type();
+  bool has_type() const;
+  void clear_type();
   static const int kTypeFieldNumber = 5;
-  inline ::google::protobuf::FieldDescriptorProto_Type type() const;
-  inline void set_type(::google::protobuf::FieldDescriptorProto_Type value);
+  ::google::protobuf::FieldDescriptorProto_Type type() const;
+  void set_type(::google::protobuf::FieldDescriptorProto_Type value);
 
   // optional string type_name = 6;
-  inline bool has_type_name() const;
-  inline void clear_type_name();
+  bool has_type_name() const;
+  void clear_type_name();
   static const int kTypeNameFieldNumber = 6;
-  inline const ::std::string& type_name() const;
-  inline void set_type_name(const ::std::string& value);
-  inline void set_type_name(const char* value);
-  inline void set_type_name(const char* value, size_t size);
-  inline ::std::string* mutable_type_name();
-  inline ::std::string* release_type_name();
-  inline void set_allocated_type_name(::std::string* type_name);
+  const ::std::string& type_name() const;
+  void set_type_name(const ::std::string& value);
+  void set_type_name(const char* value);
+  void set_type_name(const char* value, size_t size);
+  ::std::string* mutable_type_name();
+  ::std::string* release_type_name();
+  void set_allocated_type_name(::std::string* type_name);
 
   // optional string extendee = 2;
-  inline bool has_extendee() const;
-  inline void clear_extendee();
+  bool has_extendee() const;
+  void clear_extendee();
   static const int kExtendeeFieldNumber = 2;
-  inline const ::std::string& extendee() const;
-  inline void set_extendee(const ::std::string& value);
-  inline void set_extendee(const char* value);
-  inline void set_extendee(const char* value, size_t size);
-  inline ::std::string* mutable_extendee();
-  inline ::std::string* release_extendee();
-  inline void set_allocated_extendee(::std::string* extendee);
+  const ::std::string& extendee() const;
+  void set_extendee(const ::std::string& value);
+  void set_extendee(const char* value);
+  void set_extendee(const char* value, size_t size);
+  ::std::string* mutable_extendee();
+  ::std::string* release_extendee();
+  void set_allocated_extendee(::std::string* extendee);
 
   // optional string default_value = 7;
-  inline bool has_default_value() const;
-  inline void clear_default_value();
+  bool has_default_value() const;
+  void clear_default_value();
   static const int kDefaultValueFieldNumber = 7;
-  inline const ::std::string& default_value() const;
-  inline void set_default_value(const ::std::string& value);
-  inline void set_default_value(const char* value);
-  inline void set_default_value(const char* value, size_t size);
-  inline ::std::string* mutable_default_value();
-  inline ::std::string* release_default_value();
-  inline void set_allocated_default_value(::std::string* default_value);
+  const ::std::string& default_value() const;
+  void set_default_value(const ::std::string& value);
+  void set_default_value(const char* value);
+  void set_default_value(const char* value, size_t size);
+  ::std::string* mutable_default_value();
+  ::std::string* release_default_value();
+  void set_allocated_default_value(::std::string* default_value);
 
   // optional int32 oneof_index = 9;
-  inline bool has_oneof_index() const;
-  inline void clear_oneof_index();
+  bool has_oneof_index() const;
+  void clear_oneof_index();
   static const int kOneofIndexFieldNumber = 9;
-  inline ::google::protobuf::int32 oneof_index() const;
-  inline void set_oneof_index(::google::protobuf::int32 value);
+  ::google::protobuf::int32 oneof_index() const;
+  void set_oneof_index(::google::protobuf::int32 value);
+
+  // optional string json_name = 10;
+  bool has_json_name() const;
+  void clear_json_name();
+  static const int kJsonNameFieldNumber = 10;
+  const ::std::string& json_name() const;
+  void set_json_name(const ::std::string& value);
+  void set_json_name(const char* value);
+  void set_json_name(const char* value, size_t size);
+  ::std::string* mutable_json_name();
+  ::std::string* release_json_name();
+  void set_allocated_json_name(::std::string* json_name);
 
   // optional .google.protobuf.FieldOptions options = 8;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 8;
-  inline const ::google::protobuf::FieldOptions& options() const;
-  inline ::google::protobuf::FieldOptions* mutable_options();
-  inline ::google::protobuf::FieldOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::FieldOptions* options);
+  const ::google::protobuf::FieldOptions& options() const;
+  ::google::protobuf::FieldOptions* mutable_options();
+  ::google::protobuf::FieldOptions* release_options();
+  void set_allocated_options(::google::protobuf::FieldOptions* options);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
  private:
@@ -940,21 +1195,23 @@
   inline void clear_has_default_value();
   inline void set_has_oneof_index();
   inline void clear_has_oneof_index();
+  inline void set_has_json_name();
+  inline void clear_has_json_name();
   inline void set_has_options();
   inline void clear_has_options();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::int32 number_;
   int label_;
-  ::std::string* type_name_;
-  ::std::string* extendee_;
+  ::google::protobuf::internal::ArenaStringPtr type_name_;
+  ::google::protobuf::internal::ArenaStringPtr extendee_;
   int type_;
   ::google::protobuf::int32 oneof_index_;
-  ::std::string* default_value_;
+  ::google::protobuf::internal::ArenaStringPtr default_value_;
+  ::google::protobuf::internal::ArenaStringPtr json_name_;
   ::google::protobuf::FieldOptions* options_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -978,11 +1235,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -992,7 +1249,9 @@
 
   // implements Message ----------------------------------------------
 
-  OneofDescriptorProto* New() const;
+  inline OneofDescriptorProto* New() const { return New(NULL); }
+
+  OneofDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const OneofDescriptorProto& from);
@@ -1011,7 +1270,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(OneofDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1019,27 +1287,26 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
  private:
   inline void set_has_name();
   inline void clear_has_name();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1062,11 +1329,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1076,7 +1343,9 @@
 
   // implements Message ----------------------------------------------
 
-  EnumDescriptorProto* New() const;
+  inline EnumDescriptorProto* New() const { return New(NULL); }
+
+  EnumDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const EnumDescriptorProto& from);
@@ -1095,7 +1364,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(EnumDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1103,37 +1381,37 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  inline int value_size() const;
-  inline void clear_value();
+  int value_size() const;
+  void clear_value();
   static const int kValueFieldNumber = 2;
-  inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
-  inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
-  inline ::google::protobuf::EnumValueDescriptorProto* add_value();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
-      value() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
+  const ::google::protobuf::EnumValueDescriptorProto& value(int index) const;
+  ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index);
+  ::google::protobuf::EnumValueDescriptorProto* add_value();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
       mutable_value();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+      value() const;
 
   // optional .google.protobuf.EnumOptions options = 3;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 3;
-  inline const ::google::protobuf::EnumOptions& options() const;
-  inline ::google::protobuf::EnumOptions* mutable_options();
-  inline ::google::protobuf::EnumOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::EnumOptions* options);
+  const ::google::protobuf::EnumOptions& options() const;
+  ::google::protobuf::EnumOptions* mutable_options();
+  ::google::protobuf::EnumOptions* release_options();
+  void set_allocated_options(::google::protobuf::EnumOptions* options);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
  private:
@@ -1142,11 +1420,10 @@
   inline void set_has_options();
   inline void clear_has_options();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_;
   ::google::protobuf::EnumOptions* options_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1171,11 +1448,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1185,7 +1462,9 @@
 
   // implements Message ----------------------------------------------
 
-  EnumValueDescriptorProto* New() const;
+  inline EnumValueDescriptorProto* New() const { return New(NULL); }
+
+  EnumValueDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const EnumValueDescriptorProto& from);
@@ -1204,7 +1483,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(EnumValueDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1212,32 +1500,32 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // optional int32 number = 2;
-  inline bool has_number() const;
-  inline void clear_number();
+  bool has_number() const;
+  void clear_number();
   static const int kNumberFieldNumber = 2;
-  inline ::google::protobuf::int32 number() const;
-  inline void set_number(::google::protobuf::int32 value);
+  ::google::protobuf::int32 number() const;
+  void set_number(::google::protobuf::int32 value);
 
   // optional .google.protobuf.EnumValueOptions options = 3;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 3;
-  inline const ::google::protobuf::EnumValueOptions& options() const;
-  inline ::google::protobuf::EnumValueOptions* mutable_options();
-  inline ::google::protobuf::EnumValueOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::EnumValueOptions* options);
+  const ::google::protobuf::EnumValueOptions& options() const;
+  ::google::protobuf::EnumValueOptions* mutable_options();
+  ::google::protobuf::EnumValueOptions* release_options();
+  void set_allocated_options(::google::protobuf::EnumValueOptions* options);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
  private:
@@ -1248,11 +1536,10 @@
   inline void set_has_options();
   inline void clear_has_options();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::EnumValueOptions* options_;
   ::google::protobuf::int32 number_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1277,11 +1564,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1291,7 +1578,9 @@
 
   // implements Message ----------------------------------------------
 
-  ServiceDescriptorProto* New() const;
+  inline ServiceDescriptorProto* New() const { return New(NULL); }
+
+  ServiceDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const ServiceDescriptorProto& from);
@@ -1310,7 +1599,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(ServiceDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1318,37 +1616,37 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  inline int method_size() const;
-  inline void clear_method();
+  int method_size() const;
+  void clear_method();
   static const int kMethodFieldNumber = 2;
-  inline const ::google::protobuf::MethodDescriptorProto& method(int index) const;
-  inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
-  inline ::google::protobuf::MethodDescriptorProto* add_method();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
-      method() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
+  const ::google::protobuf::MethodDescriptorProto& method(int index) const;
+  ::google::protobuf::MethodDescriptorProto* mutable_method(int index);
+  ::google::protobuf::MethodDescriptorProto* add_method();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
       mutable_method();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+      method() const;
 
   // optional .google.protobuf.ServiceOptions options = 3;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 3;
-  inline const ::google::protobuf::ServiceOptions& options() const;
-  inline ::google::protobuf::ServiceOptions* mutable_options();
-  inline ::google::protobuf::ServiceOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::ServiceOptions* options);
+  const ::google::protobuf::ServiceOptions& options() const;
+  ::google::protobuf::ServiceOptions* mutable_options();
+  ::google::protobuf::ServiceOptions* release_options();
+  void set_allocated_options(::google::protobuf::ServiceOptions* options);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
  private:
@@ -1357,11 +1655,10 @@
   inline void set_has_options();
   inline void clear_has_options();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_;
   ::google::protobuf::ServiceOptions* options_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1386,11 +1683,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1400,7 +1697,9 @@
 
   // implements Message ----------------------------------------------
 
-  MethodDescriptorProto* New() const;
+  inline MethodDescriptorProto* New() const { return New(NULL); }
+
+  MethodDescriptorProto* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MethodDescriptorProto& from);
@@ -1419,7 +1718,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MethodDescriptorProto* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1427,49 +1735,63 @@
   // accessors -------------------------------------------------------
 
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
   // optional string input_type = 2;
-  inline bool has_input_type() const;
-  inline void clear_input_type();
+  bool has_input_type() const;
+  void clear_input_type();
   static const int kInputTypeFieldNumber = 2;
-  inline const ::std::string& input_type() const;
-  inline void set_input_type(const ::std::string& value);
-  inline void set_input_type(const char* value);
-  inline void set_input_type(const char* value, size_t size);
-  inline ::std::string* mutable_input_type();
-  inline ::std::string* release_input_type();
-  inline void set_allocated_input_type(::std::string* input_type);
+  const ::std::string& input_type() const;
+  void set_input_type(const ::std::string& value);
+  void set_input_type(const char* value);
+  void set_input_type(const char* value, size_t size);
+  ::std::string* mutable_input_type();
+  ::std::string* release_input_type();
+  void set_allocated_input_type(::std::string* input_type);
 
   // optional string output_type = 3;
-  inline bool has_output_type() const;
-  inline void clear_output_type();
+  bool has_output_type() const;
+  void clear_output_type();
   static const int kOutputTypeFieldNumber = 3;
-  inline const ::std::string& output_type() const;
-  inline void set_output_type(const ::std::string& value);
-  inline void set_output_type(const char* value);
-  inline void set_output_type(const char* value, size_t size);
-  inline ::std::string* mutable_output_type();
-  inline ::std::string* release_output_type();
-  inline void set_allocated_output_type(::std::string* output_type);
+  const ::std::string& output_type() const;
+  void set_output_type(const ::std::string& value);
+  void set_output_type(const char* value);
+  void set_output_type(const char* value, size_t size);
+  ::std::string* mutable_output_type();
+  ::std::string* release_output_type();
+  void set_allocated_output_type(::std::string* output_type);
 
   // optional .google.protobuf.MethodOptions options = 4;
-  inline bool has_options() const;
-  inline void clear_options();
+  bool has_options() const;
+  void clear_options();
   static const int kOptionsFieldNumber = 4;
-  inline const ::google::protobuf::MethodOptions& options() const;
-  inline ::google::protobuf::MethodOptions* mutable_options();
-  inline ::google::protobuf::MethodOptions* release_options();
-  inline void set_allocated_options(::google::protobuf::MethodOptions* options);
+  const ::google::protobuf::MethodOptions& options() const;
+  ::google::protobuf::MethodOptions* mutable_options();
+  ::google::protobuf::MethodOptions* release_options();
+  void set_allocated_options(::google::protobuf::MethodOptions* options);
+
+  // optional bool client_streaming = 5 [default = false];
+  bool has_client_streaming() const;
+  void clear_client_streaming();
+  static const int kClientStreamingFieldNumber = 5;
+  bool client_streaming() const;
+  void set_client_streaming(bool value);
+
+  // optional bool server_streaming = 6 [default = false];
+  bool has_server_streaming() const;
+  void clear_server_streaming();
+  static const int kServerStreamingFieldNumber = 6;
+  bool server_streaming() const;
+  void set_server_streaming(bool value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
  private:
@@ -1481,15 +1803,20 @@
   inline void clear_has_output_type();
   inline void set_has_options();
   inline void clear_has_options();
+  inline void set_has_client_streaming();
+  inline void clear_has_client_streaming();
+  inline void set_has_server_streaming();
+  inline void clear_has_server_streaming();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_;
-  ::std::string* input_type_;
-  ::std::string* output_type_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr input_type_;
+  ::google::protobuf::internal::ArenaStringPtr output_type_;
   ::google::protobuf::MethodOptions* options_;
+  bool client_streaming_;
+  bool server_streaming_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1512,11 +1839,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1526,7 +1853,9 @@
 
   // implements Message ----------------------------------------------
 
-  FileOptions* New() const;
+  inline FileOptions* New() const { return New(NULL); }
+
+  FileOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const FileOptions& from);
@@ -1545,15 +1874,27 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(FileOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
 
   typedef FileOptions_OptimizeMode OptimizeMode;
-  static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
-  static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
-  static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME;
+  static const OptimizeMode SPEED =
+    FileOptions_OptimizeMode_SPEED;
+  static const OptimizeMode CODE_SIZE =
+    FileOptions_OptimizeMode_CODE_SIZE;
+  static const OptimizeMode LITE_RUNTIME =
+    FileOptions_OptimizeMode_LITE_RUNTIME;
   static inline bool OptimizeMode_IsValid(int value) {
     return FileOptions_OptimizeMode_IsValid(value);
   }
@@ -1578,115 +1919,139 @@
   // accessors -------------------------------------------------------
 
   // optional string java_package = 1;
-  inline bool has_java_package() const;
-  inline void clear_java_package();
+  bool has_java_package() const;
+  void clear_java_package();
   static const int kJavaPackageFieldNumber = 1;
-  inline const ::std::string& java_package() const;
-  inline void set_java_package(const ::std::string& value);
-  inline void set_java_package(const char* value);
-  inline void set_java_package(const char* value, size_t size);
-  inline ::std::string* mutable_java_package();
-  inline ::std::string* release_java_package();
-  inline void set_allocated_java_package(::std::string* java_package);
+  const ::std::string& java_package() const;
+  void set_java_package(const ::std::string& value);
+  void set_java_package(const char* value);
+  void set_java_package(const char* value, size_t size);
+  ::std::string* mutable_java_package();
+  ::std::string* release_java_package();
+  void set_allocated_java_package(::std::string* java_package);
 
   // optional string java_outer_classname = 8;
-  inline bool has_java_outer_classname() const;
-  inline void clear_java_outer_classname();
+  bool has_java_outer_classname() const;
+  void clear_java_outer_classname();
   static const int kJavaOuterClassnameFieldNumber = 8;
-  inline const ::std::string& java_outer_classname() const;
-  inline void set_java_outer_classname(const ::std::string& value);
-  inline void set_java_outer_classname(const char* value);
-  inline void set_java_outer_classname(const char* value, size_t size);
-  inline ::std::string* mutable_java_outer_classname();
-  inline ::std::string* release_java_outer_classname();
-  inline void set_allocated_java_outer_classname(::std::string* java_outer_classname);
+  const ::std::string& java_outer_classname() const;
+  void set_java_outer_classname(const ::std::string& value);
+  void set_java_outer_classname(const char* value);
+  void set_java_outer_classname(const char* value, size_t size);
+  ::std::string* mutable_java_outer_classname();
+  ::std::string* release_java_outer_classname();
+  void set_allocated_java_outer_classname(::std::string* java_outer_classname);
 
   // optional bool java_multiple_files = 10 [default = false];
-  inline bool has_java_multiple_files() const;
-  inline void clear_java_multiple_files();
+  bool has_java_multiple_files() const;
+  void clear_java_multiple_files();
   static const int kJavaMultipleFilesFieldNumber = 10;
-  inline bool java_multiple_files() const;
-  inline void set_java_multiple_files(bool value);
+  bool java_multiple_files() const;
+  void set_java_multiple_files(bool value);
 
   // optional bool java_generate_equals_and_hash = 20 [default = false];
-  inline bool has_java_generate_equals_and_hash() const;
-  inline void clear_java_generate_equals_and_hash();
+  bool has_java_generate_equals_and_hash() const;
+  void clear_java_generate_equals_and_hash();
   static const int kJavaGenerateEqualsAndHashFieldNumber = 20;
-  inline bool java_generate_equals_and_hash() const;
-  inline void set_java_generate_equals_and_hash(bool value);
+  bool java_generate_equals_and_hash() const;
+  void set_java_generate_equals_and_hash(bool value);
 
   // optional bool java_string_check_utf8 = 27 [default = false];
-  inline bool has_java_string_check_utf8() const;
-  inline void clear_java_string_check_utf8();
+  bool has_java_string_check_utf8() const;
+  void clear_java_string_check_utf8();
   static const int kJavaStringCheckUtf8FieldNumber = 27;
-  inline bool java_string_check_utf8() const;
-  inline void set_java_string_check_utf8(bool value);
+  bool java_string_check_utf8() const;
+  void set_java_string_check_utf8(bool value);
 
   // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
-  inline bool has_optimize_for() const;
-  inline void clear_optimize_for();
+  bool has_optimize_for() const;
+  void clear_optimize_for();
   static const int kOptimizeForFieldNumber = 9;
-  inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
-  inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
+  ::google::protobuf::FileOptions_OptimizeMode optimize_for() const;
+  void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value);
 
   // optional string go_package = 11;
-  inline bool has_go_package() const;
-  inline void clear_go_package();
+  bool has_go_package() const;
+  void clear_go_package();
   static const int kGoPackageFieldNumber = 11;
-  inline const ::std::string& go_package() const;
-  inline void set_go_package(const ::std::string& value);
-  inline void set_go_package(const char* value);
-  inline void set_go_package(const char* value, size_t size);
-  inline ::std::string* mutable_go_package();
-  inline ::std::string* release_go_package();
-  inline void set_allocated_go_package(::std::string* go_package);
+  const ::std::string& go_package() const;
+  void set_go_package(const ::std::string& value);
+  void set_go_package(const char* value);
+  void set_go_package(const char* value, size_t size);
+  ::std::string* mutable_go_package();
+  ::std::string* release_go_package();
+  void set_allocated_go_package(::std::string* go_package);
 
   // optional bool cc_generic_services = 16 [default = false];
-  inline bool has_cc_generic_services() const;
-  inline void clear_cc_generic_services();
+  bool has_cc_generic_services() const;
+  void clear_cc_generic_services();
   static const int kCcGenericServicesFieldNumber = 16;
-  inline bool cc_generic_services() const;
-  inline void set_cc_generic_services(bool value);
+  bool cc_generic_services() const;
+  void set_cc_generic_services(bool value);
 
   // optional bool java_generic_services = 17 [default = false];
-  inline bool has_java_generic_services() const;
-  inline void clear_java_generic_services();
+  bool has_java_generic_services() const;
+  void clear_java_generic_services();
   static const int kJavaGenericServicesFieldNumber = 17;
-  inline bool java_generic_services() const;
-  inline void set_java_generic_services(bool value);
+  bool java_generic_services() const;
+  void set_java_generic_services(bool value);
 
   // optional bool py_generic_services = 18 [default = false];
-  inline bool has_py_generic_services() const;
-  inline void clear_py_generic_services();
+  bool has_py_generic_services() const;
+  void clear_py_generic_services();
   static const int kPyGenericServicesFieldNumber = 18;
-  inline bool py_generic_services() const;
-  inline void set_py_generic_services(bool value);
+  bool py_generic_services() const;
+  void set_py_generic_services(bool value);
 
   // optional bool deprecated = 23 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 23;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
-  // optional bool javanano_use_deprecated_package = 38;
-  inline bool has_javanano_use_deprecated_package() const;
-  inline void clear_javanano_use_deprecated_package();
-  static const int kJavananoUseDeprecatedPackageFieldNumber = 38;
-  inline bool javanano_use_deprecated_package() const;
-  inline void set_javanano_use_deprecated_package(bool value);
+  // optional bool cc_enable_arenas = 31 [default = false];
+  bool has_cc_enable_arenas() const;
+  void clear_cc_enable_arenas();
+  static const int kCcEnableArenasFieldNumber = 31;
+  bool cc_enable_arenas() const;
+  void set_cc_enable_arenas(bool value);
+
+  // optional string objc_class_prefix = 36;
+  bool has_objc_class_prefix() const;
+  void clear_objc_class_prefix();
+  static const int kObjcClassPrefixFieldNumber = 36;
+  const ::std::string& objc_class_prefix() const;
+  void set_objc_class_prefix(const ::std::string& value);
+  void set_objc_class_prefix(const char* value);
+  void set_objc_class_prefix(const char* value, size_t size);
+  ::std::string* mutable_objc_class_prefix();
+  ::std::string* release_objc_class_prefix();
+  void set_allocated_objc_class_prefix(::std::string* objc_class_prefix);
+
+  // optional string csharp_namespace = 37;
+  bool has_csharp_namespace() const;
+  void clear_csharp_namespace();
+  static const int kCsharpNamespaceFieldNumber = 37;
+  const ::std::string& csharp_namespace() const;
+  void set_csharp_namespace(const ::std::string& value);
+  void set_csharp_namespace(const char* value);
+  void set_csharp_namespace(const char* value, size_t size);
+  ::std::string* mutable_csharp_namespace();
+  ::std::string* release_csharp_namespace();
+  void set_allocated_csharp_namespace(::std::string* csharp_namespace);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
@@ -1713,28 +2078,33 @@
   inline void clear_has_py_generic_services();
   inline void set_has_deprecated();
   inline void clear_has_deprecated();
-  inline void set_has_javanano_use_deprecated_package();
-  inline void clear_has_javanano_use_deprecated_package();
+  inline void set_has_cc_enable_arenas();
+  inline void clear_has_cc_enable_arenas();
+  inline void set_has_objc_class_prefix();
+  inline void clear_has_objc_class_prefix();
+  inline void set_has_csharp_namespace();
+  inline void clear_has_csharp_namespace();
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* java_package_;
-  ::std::string* java_outer_classname_;
+  ::google::protobuf::internal::ArenaStringPtr java_package_;
+  ::google::protobuf::internal::ArenaStringPtr java_outer_classname_;
   bool java_multiple_files_;
   bool java_generate_equals_and_hash_;
   bool java_string_check_utf8_;
   bool cc_generic_services_;
   int optimize_for_;
-  ::std::string* go_package_;
+  ::google::protobuf::internal::ArenaStringPtr go_package_;
+  ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_;
+  ::google::protobuf::internal::ArenaStringPtr csharp_namespace_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   bool java_generic_services_;
   bool py_generic_services_;
   bool deprecated_;
-  bool javanano_use_deprecated_package_;
+  bool cc_enable_arenas_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1757,11 +2127,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1771,7 +2141,9 @@
 
   // implements Message ----------------------------------------------
 
-  MessageOptions* New() const;
+  inline MessageOptions* New() const { return New(NULL); }
+
+  MessageOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MessageOptions& from);
@@ -1790,7 +2162,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MessageOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -1798,37 +2179,44 @@
   // accessors -------------------------------------------------------
 
   // optional bool message_set_wire_format = 1 [default = false];
-  inline bool has_message_set_wire_format() const;
-  inline void clear_message_set_wire_format();
+  bool has_message_set_wire_format() const;
+  void clear_message_set_wire_format();
   static const int kMessageSetWireFormatFieldNumber = 1;
-  inline bool message_set_wire_format() const;
-  inline void set_message_set_wire_format(bool value);
+  bool message_set_wire_format() const;
+  void set_message_set_wire_format(bool value);
 
   // optional bool no_standard_descriptor_accessor = 2 [default = false];
-  inline bool has_no_standard_descriptor_accessor() const;
-  inline void clear_no_standard_descriptor_accessor();
+  bool has_no_standard_descriptor_accessor() const;
+  void clear_no_standard_descriptor_accessor();
   static const int kNoStandardDescriptorAccessorFieldNumber = 2;
-  inline bool no_standard_descriptor_accessor() const;
-  inline void set_no_standard_descriptor_accessor(bool value);
+  bool no_standard_descriptor_accessor() const;
+  void set_no_standard_descriptor_accessor(bool value);
 
   // optional bool deprecated = 3 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 3;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
+
+  // optional bool map_entry = 7;
+  bool has_map_entry() const;
+  void clear_map_entry();
+  static const int kMapEntryFieldNumber = 7;
+  bool map_entry() const;
+  void set_map_entry(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
@@ -1839,17 +2227,19 @@
   inline void clear_has_no_standard_descriptor_accessor();
   inline void set_has_deprecated();
   inline void clear_has_deprecated();
+  inline void set_has_map_entry();
+  inline void clear_has_map_entry();
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   bool message_set_wire_format_;
   bool no_standard_descriptor_accessor_;
   bool deprecated_;
+  bool map_entry_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1872,11 +2262,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -1886,7 +2276,9 @@
 
   // implements Message ----------------------------------------------
 
-  FieldOptions* New() const;
+  inline FieldOptions* New() const { return New(NULL); }
+
+  FieldOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const FieldOptions& from);
@@ -1905,15 +2297,27 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(FieldOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
 
   typedef FieldOptions_CType CType;
-  static const CType STRING = FieldOptions_CType_STRING;
-  static const CType CORD = FieldOptions_CType_CORD;
-  static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE;
+  static const CType STRING =
+    FieldOptions_CType_STRING;
+  static const CType CORD =
+    FieldOptions_CType_CORD;
+  static const CType STRING_PIECE =
+    FieldOptions_CType_STRING_PIECE;
   static inline bool CType_IsValid(int value) {
     return FieldOptions_CType_IsValid(value);
   }
@@ -1935,66 +2339,89 @@
     return FieldOptions_CType_Parse(name, value);
   }
 
+  typedef FieldOptions_JSType JSType;
+  static const JSType JS_NORMAL =
+    FieldOptions_JSType_JS_NORMAL;
+  static const JSType JS_STRING =
+    FieldOptions_JSType_JS_STRING;
+  static const JSType JS_NUMBER =
+    FieldOptions_JSType_JS_NUMBER;
+  static inline bool JSType_IsValid(int value) {
+    return FieldOptions_JSType_IsValid(value);
+  }
+  static const JSType JSType_MIN =
+    FieldOptions_JSType_JSType_MIN;
+  static const JSType JSType_MAX =
+    FieldOptions_JSType_JSType_MAX;
+  static const int JSType_ARRAYSIZE =
+    FieldOptions_JSType_JSType_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  JSType_descriptor() {
+    return FieldOptions_JSType_descriptor();
+  }
+  static inline const ::std::string& JSType_Name(JSType value) {
+    return FieldOptions_JSType_Name(value);
+  }
+  static inline bool JSType_Parse(const ::std::string& name,
+      JSType* value) {
+    return FieldOptions_JSType_Parse(name, value);
+  }
+
   // accessors -------------------------------------------------------
 
   // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
-  inline bool has_ctype() const;
-  inline void clear_ctype();
+  bool has_ctype() const;
+  void clear_ctype();
   static const int kCtypeFieldNumber = 1;
-  inline ::google::protobuf::FieldOptions_CType ctype() const;
-  inline void set_ctype(::google::protobuf::FieldOptions_CType value);
+  ::google::protobuf::FieldOptions_CType ctype() const;
+  void set_ctype(::google::protobuf::FieldOptions_CType value);
 
   // optional bool packed = 2;
-  inline bool has_packed() const;
-  inline void clear_packed();
+  bool has_packed() const;
+  void clear_packed();
   static const int kPackedFieldNumber = 2;
-  inline bool packed() const;
-  inline void set_packed(bool value);
+  bool packed() const;
+  void set_packed(bool value);
+
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  bool has_jstype() const;
+  void clear_jstype();
+  static const int kJstypeFieldNumber = 6;
+  ::google::protobuf::FieldOptions_JSType jstype() const;
+  void set_jstype(::google::protobuf::FieldOptions_JSType value);
 
   // optional bool lazy = 5 [default = false];
-  inline bool has_lazy() const;
-  inline void clear_lazy();
+  bool has_lazy() const;
+  void clear_lazy();
   static const int kLazyFieldNumber = 5;
-  inline bool lazy() const;
-  inline void set_lazy(bool value);
+  bool lazy() const;
+  void set_lazy(bool value);
 
   // optional bool deprecated = 3 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 3;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
-
-  // optional string experimental_map_key = 9;
-  inline bool has_experimental_map_key() const;
-  inline void clear_experimental_map_key();
-  static const int kExperimentalMapKeyFieldNumber = 9;
-  inline const ::std::string& experimental_map_key() const;
-  inline void set_experimental_map_key(const ::std::string& value);
-  inline void set_experimental_map_key(const char* value);
-  inline void set_experimental_map_key(const char* value, size_t size);
-  inline ::std::string* mutable_experimental_map_key();
-  inline ::std::string* release_experimental_map_key();
-  inline void set_allocated_experimental_map_key(::std::string* experimental_map_key);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
   // optional bool weak = 10 [default = false];
-  inline bool has_weak() const;
-  inline void clear_weak();
+  bool has_weak() const;
+  void clear_weak();
   static const int kWeakFieldNumber = 10;
-  inline bool weak() const;
-  inline void set_weak(bool value);
+  bool weak() const;
+  void set_weak(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
@@ -2003,28 +2430,27 @@
   inline void clear_has_ctype();
   inline void set_has_packed();
   inline void clear_has_packed();
+  inline void set_has_jstype();
+  inline void clear_has_jstype();
   inline void set_has_lazy();
   inline void clear_has_lazy();
   inline void set_has_deprecated();
   inline void clear_has_deprecated();
-  inline void set_has_experimental_map_key();
-  inline void clear_has_experimental_map_key();
   inline void set_has_weak();
   inline void clear_has_weak();
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   int ctype_;
+  int jstype_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   bool packed_;
   bool lazy_;
   bool deprecated_;
   bool weak_;
-  ::std::string* experimental_map_key_;
-  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2047,11 +2473,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2061,7 +2487,9 @@
 
   // implements Message ----------------------------------------------
 
-  EnumOptions* New() const;
+  inline EnumOptions* New() const { return New(NULL); }
+
+  EnumOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const EnumOptions& from);
@@ -2080,7 +2508,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(EnumOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2088,30 +2525,30 @@
   // accessors -------------------------------------------------------
 
   // optional bool allow_alias = 2;
-  inline bool has_allow_alias() const;
-  inline void clear_allow_alias();
+  bool has_allow_alias() const;
+  void clear_allow_alias();
   static const int kAllowAliasFieldNumber = 2;
-  inline bool allow_alias() const;
-  inline void set_allow_alias(bool value);
+  bool allow_alias() const;
+  void set_allow_alias(bool value);
 
   // optional bool deprecated = 3 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 3;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
@@ -2123,8 +2560,7 @@
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
@@ -2152,11 +2588,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2166,7 +2602,9 @@
 
   // implements Message ----------------------------------------------
 
-  EnumValueOptions* New() const;
+  inline EnumValueOptions* New() const { return New(NULL); }
+
+  EnumValueOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const EnumValueOptions& from);
@@ -2185,7 +2623,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(EnumValueOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2193,23 +2640,23 @@
   // accessors -------------------------------------------------------
 
   // optional bool deprecated = 1 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 1;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
@@ -2219,8 +2666,7 @@
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
@@ -2247,11 +2693,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2261,7 +2707,9 @@
 
   // implements Message ----------------------------------------------
 
-  ServiceOptions* New() const;
+  inline ServiceOptions* New() const { return New(NULL); }
+
+  ServiceOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const ServiceOptions& from);
@@ -2280,7 +2728,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(ServiceOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2288,23 +2745,23 @@
   // accessors -------------------------------------------------------
 
   // optional bool deprecated = 33 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 33;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
@@ -2314,8 +2771,7 @@
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
@@ -2342,11 +2798,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2356,7 +2812,9 @@
 
   // implements Message ----------------------------------------------
 
-  MethodOptions* New() const;
+  inline MethodOptions* New() const { return New(NULL); }
+
+  MethodOptions* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const MethodOptions& from);
@@ -2375,7 +2833,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(MethodOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2383,23 +2850,23 @@
   // accessors -------------------------------------------------------
 
   // optional bool deprecated = 33 [default = false];
-  inline bool has_deprecated() const;
-  inline void clear_deprecated();
+  bool has_deprecated() const;
+  void clear_deprecated();
   static const int kDeprecatedFieldNumber = 33;
-  inline bool deprecated() const;
-  inline void set_deprecated(bool value);
+  bool deprecated() const;
+  void set_deprecated(bool value);
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  inline int uninterpreted_option_size() const;
-  inline void clear_uninterpreted_option();
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
   static const int kUninterpretedOptionFieldNumber = 999;
-  inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
-  inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
-  inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-      uninterpreted_option() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
       mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
 
   GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions)
   // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
@@ -2409,8 +2876,7 @@
 
   ::google::protobuf::internal::ExtensionSet _extensions_;
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
@@ -2437,11 +2903,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2451,7 +2917,9 @@
 
   // implements Message ----------------------------------------------
 
-  UninterpretedOption_NamePart* New() const;
+  inline UninterpretedOption_NamePart* New() const { return New(NULL); }
+
+  UninterpretedOption_NamePart* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const UninterpretedOption_NamePart& from);
@@ -2470,7 +2938,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(UninterpretedOption_NamePart* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2478,23 +2955,23 @@
   // accessors -------------------------------------------------------
 
   // required string name_part = 1;
-  inline bool has_name_part() const;
-  inline void clear_name_part();
+  bool has_name_part() const;
+  void clear_name_part();
   static const int kNamePartFieldNumber = 1;
-  inline const ::std::string& name_part() const;
-  inline void set_name_part(const ::std::string& value);
-  inline void set_name_part(const char* value);
-  inline void set_name_part(const char* value, size_t size);
-  inline ::std::string* mutable_name_part();
-  inline ::std::string* release_name_part();
-  inline void set_allocated_name_part(::std::string* name_part);
+  const ::std::string& name_part() const;
+  void set_name_part(const ::std::string& value);
+  void set_name_part(const char* value);
+  void set_name_part(const char* value, size_t size);
+  ::std::string* mutable_name_part();
+  ::std::string* release_name_part();
+  void set_allocated_name_part(::std::string* name_part);
 
   // required bool is_extension = 2;
-  inline bool has_is_extension() const;
-  inline void clear_is_extension();
+  bool has_is_extension() const;
+  void clear_is_extension();
   static const int kIsExtensionFieldNumber = 2;
-  inline bool is_extension() const;
-  inline void set_is_extension(bool value);
+  bool is_extension() const;
+  void set_is_extension(bool value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
  private:
@@ -2503,11 +2980,13 @@
   inline void set_has_is_extension();
   inline void clear_has_is_extension();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
+  // helper for ByteSize()
+  int RequiredFieldsByteSizeFallback() const;
 
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
-  ::std::string* name_part_;
+  ::google::protobuf::internal::ArenaStringPtr name_part_;
   bool is_extension_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2531,11 +3010,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2545,7 +3024,9 @@
 
   // implements Message ----------------------------------------------
 
-  UninterpretedOption* New() const;
+  inline UninterpretedOption* New() const { return New(NULL); }
+
+  UninterpretedOption* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const UninterpretedOption& from);
@@ -2564,7 +3045,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(UninterpretedOption* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2574,73 +3064,73 @@
   // accessors -------------------------------------------------------
 
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  inline int name_size() const;
-  inline void clear_name();
+  int name_size() const;
+  void clear_name();
   static const int kNameFieldNumber = 2;
-  inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const;
-  inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index);
-  inline ::google::protobuf::UninterpretedOption_NamePart* add_name();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
-      name() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
+  const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const;
+  ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index);
+  ::google::protobuf::UninterpretedOption_NamePart* add_name();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
       mutable_name();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+      name() const;
 
   // optional string identifier_value = 3;
-  inline bool has_identifier_value() const;
-  inline void clear_identifier_value();
+  bool has_identifier_value() const;
+  void clear_identifier_value();
   static const int kIdentifierValueFieldNumber = 3;
-  inline const ::std::string& identifier_value() const;
-  inline void set_identifier_value(const ::std::string& value);
-  inline void set_identifier_value(const char* value);
-  inline void set_identifier_value(const char* value, size_t size);
-  inline ::std::string* mutable_identifier_value();
-  inline ::std::string* release_identifier_value();
-  inline void set_allocated_identifier_value(::std::string* identifier_value);
+  const ::std::string& identifier_value() const;
+  void set_identifier_value(const ::std::string& value);
+  void set_identifier_value(const char* value);
+  void set_identifier_value(const char* value, size_t size);
+  ::std::string* mutable_identifier_value();
+  ::std::string* release_identifier_value();
+  void set_allocated_identifier_value(::std::string* identifier_value);
 
   // optional uint64 positive_int_value = 4;
-  inline bool has_positive_int_value() const;
-  inline void clear_positive_int_value();
+  bool has_positive_int_value() const;
+  void clear_positive_int_value();
   static const int kPositiveIntValueFieldNumber = 4;
-  inline ::google::protobuf::uint64 positive_int_value() const;
-  inline void set_positive_int_value(::google::protobuf::uint64 value);
+  ::google::protobuf::uint64 positive_int_value() const;
+  void set_positive_int_value(::google::protobuf::uint64 value);
 
   // optional int64 negative_int_value = 5;
-  inline bool has_negative_int_value() const;
-  inline void clear_negative_int_value();
+  bool has_negative_int_value() const;
+  void clear_negative_int_value();
   static const int kNegativeIntValueFieldNumber = 5;
-  inline ::google::protobuf::int64 negative_int_value() const;
-  inline void set_negative_int_value(::google::protobuf::int64 value);
+  ::google::protobuf::int64 negative_int_value() const;
+  void set_negative_int_value(::google::protobuf::int64 value);
 
   // optional double double_value = 6;
-  inline bool has_double_value() const;
-  inline void clear_double_value();
+  bool has_double_value() const;
+  void clear_double_value();
   static const int kDoubleValueFieldNumber = 6;
-  inline double double_value() const;
-  inline void set_double_value(double value);
+  double double_value() const;
+  void set_double_value(double value);
 
   // optional bytes string_value = 7;
-  inline bool has_string_value() const;
-  inline void clear_string_value();
+  bool has_string_value() const;
+  void clear_string_value();
   static const int kStringValueFieldNumber = 7;
-  inline const ::std::string& string_value() const;
-  inline void set_string_value(const ::std::string& value);
-  inline void set_string_value(const char* value);
-  inline void set_string_value(const void* value, size_t size);
-  inline ::std::string* mutable_string_value();
-  inline ::std::string* release_string_value();
-  inline void set_allocated_string_value(::std::string* string_value);
+  const ::std::string& string_value() const;
+  void set_string_value(const ::std::string& value);
+  void set_string_value(const char* value);
+  void set_string_value(const void* value, size_t size);
+  ::std::string* mutable_string_value();
+  ::std::string* release_string_value();
+  void set_allocated_string_value(::std::string* string_value);
 
   // optional string aggregate_value = 8;
-  inline bool has_aggregate_value() const;
-  inline void clear_aggregate_value();
+  bool has_aggregate_value() const;
+  void clear_aggregate_value();
   static const int kAggregateValueFieldNumber = 8;
-  inline const ::std::string& aggregate_value() const;
-  inline void set_aggregate_value(const ::std::string& value);
-  inline void set_aggregate_value(const char* value);
-  inline void set_aggregate_value(const char* value, size_t size);
-  inline ::std::string* mutable_aggregate_value();
-  inline ::std::string* release_aggregate_value();
-  inline void set_allocated_aggregate_value(::std::string* aggregate_value);
+  const ::std::string& aggregate_value() const;
+  void set_aggregate_value(const ::std::string& value);
+  void set_aggregate_value(const char* value);
+  void set_aggregate_value(const char* value, size_t size);
+  ::std::string* mutable_aggregate_value();
+  ::std::string* release_aggregate_value();
+  void set_allocated_aggregate_value(::std::string* aggregate_value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
  private:
@@ -2657,17 +3147,16 @@
   inline void set_has_aggregate_value();
   inline void clear_has_aggregate_value();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart > name_;
-  ::std::string* identifier_value_;
+  ::google::protobuf::internal::ArenaStringPtr identifier_value_;
   ::google::protobuf::uint64 positive_int_value_;
   ::google::protobuf::int64 negative_int_value_;
   double double_value_;
-  ::std::string* string_value_;
-  ::std::string* aggregate_value_;
+  ::google::protobuf::internal::ArenaStringPtr string_value_;
+  ::google::protobuf::internal::ArenaStringPtr aggregate_value_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2690,11 +3179,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2704,7 +3193,9 @@
 
   // implements Message ----------------------------------------------
 
-  SourceCodeInfo_Location* New() const;
+  inline SourceCodeInfo_Location* New() const { return New(NULL); }
+
+  SourceCodeInfo_Location* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const SourceCodeInfo_Location& from);
@@ -2723,7 +3214,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(SourceCodeInfo_Location* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2731,52 +3231,68 @@
   // accessors -------------------------------------------------------
 
   // repeated int32 path = 1 [packed = true];
-  inline int path_size() const;
-  inline void clear_path();
+  int path_size() const;
+  void clear_path();
   static const int kPathFieldNumber = 1;
-  inline ::google::protobuf::int32 path(int index) const;
-  inline void set_path(int index, ::google::protobuf::int32 value);
-  inline void add_path(::google::protobuf::int32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+  ::google::protobuf::int32 path(int index) const;
+  void set_path(int index, ::google::protobuf::int32 value);
+  void add_path(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
       path() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
       mutable_path();
 
   // repeated int32 span = 2 [packed = true];
-  inline int span_size() const;
-  inline void clear_span();
+  int span_size() const;
+  void clear_span();
   static const int kSpanFieldNumber = 2;
-  inline ::google::protobuf::int32 span(int index) const;
-  inline void set_span(int index, ::google::protobuf::int32 value);
-  inline void add_span(::google::protobuf::int32 value);
-  inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+  ::google::protobuf::int32 span(int index) const;
+  void set_span(int index, ::google::protobuf::int32 value);
+  void add_span(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
       span() const;
-  inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
       mutable_span();
 
   // optional string leading_comments = 3;
-  inline bool has_leading_comments() const;
-  inline void clear_leading_comments();
+  bool has_leading_comments() const;
+  void clear_leading_comments();
   static const int kLeadingCommentsFieldNumber = 3;
-  inline const ::std::string& leading_comments() const;
-  inline void set_leading_comments(const ::std::string& value);
-  inline void set_leading_comments(const char* value);
-  inline void set_leading_comments(const char* value, size_t size);
-  inline ::std::string* mutable_leading_comments();
-  inline ::std::string* release_leading_comments();
-  inline void set_allocated_leading_comments(::std::string* leading_comments);
+  const ::std::string& leading_comments() const;
+  void set_leading_comments(const ::std::string& value);
+  void set_leading_comments(const char* value);
+  void set_leading_comments(const char* value, size_t size);
+  ::std::string* mutable_leading_comments();
+  ::std::string* release_leading_comments();
+  void set_allocated_leading_comments(::std::string* leading_comments);
 
   // optional string trailing_comments = 4;
-  inline bool has_trailing_comments() const;
-  inline void clear_trailing_comments();
+  bool has_trailing_comments() const;
+  void clear_trailing_comments();
   static const int kTrailingCommentsFieldNumber = 4;
-  inline const ::std::string& trailing_comments() const;
-  inline void set_trailing_comments(const ::std::string& value);
-  inline void set_trailing_comments(const char* value);
-  inline void set_trailing_comments(const char* value, size_t size);
-  inline ::std::string* mutable_trailing_comments();
-  inline ::std::string* release_trailing_comments();
-  inline void set_allocated_trailing_comments(::std::string* trailing_comments);
+  const ::std::string& trailing_comments() const;
+  void set_trailing_comments(const ::std::string& value);
+  void set_trailing_comments(const char* value);
+  void set_trailing_comments(const char* value, size_t size);
+  ::std::string* mutable_trailing_comments();
+  ::std::string* release_trailing_comments();
+  void set_allocated_trailing_comments(::std::string* trailing_comments);
+
+  // repeated string leading_detached_comments = 6;
+  int leading_detached_comments_size() const;
+  void clear_leading_detached_comments();
+  static const int kLeadingDetachedCommentsFieldNumber = 6;
+  const ::std::string& leading_detached_comments(int index) const;
+  ::std::string* mutable_leading_detached_comments(int index);
+  void set_leading_detached_comments(int index, const ::std::string& value);
+  void set_leading_detached_comments(int index, const char* value);
+  void set_leading_detached_comments(int index, const char* value, size_t size);
+  ::std::string* add_leading_detached_comments();
+  void add_leading_detached_comments(const ::std::string& value);
+  void add_leading_detached_comments(const char* value);
+  void add_leading_detached_comments(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& leading_detached_comments() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_leading_detached_comments();
 
   // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
  private:
@@ -2785,16 +3301,16 @@
   inline void set_has_trailing_comments();
   inline void clear_has_trailing_comments();
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_;
   mutable int _path_cached_byte_size_;
   ::google::protobuf::RepeatedField< ::google::protobuf::int32 > span_;
   mutable int _span_cached_byte_size_;
-  ::std::string* leading_comments_;
-  ::std::string* trailing_comments_;
+  ::google::protobuf::internal::ArenaStringPtr leading_comments_;
+  ::google::protobuf::internal::ArenaStringPtr trailing_comments_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> leading_detached_comments_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2817,11 +3333,11 @@
   }
 
   inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
-    return _unknown_fields_;
+    return _internal_metadata_.unknown_fields();
   }
 
   inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
-    return &_unknown_fields_;
+    return _internal_metadata_.mutable_unknown_fields();
   }
 
   static const ::google::protobuf::Descriptor* descriptor();
@@ -2831,7 +3347,9 @@
 
   // implements Message ----------------------------------------------
 
-  SourceCodeInfo* New() const;
+  inline SourceCodeInfo* New() const { return New(NULL); }
+
+  SourceCodeInfo* New(::google::protobuf::Arena* arena) const;
   void CopyFrom(const ::google::protobuf::Message& from);
   void MergeFrom(const ::google::protobuf::Message& from);
   void CopyFrom(const SourceCodeInfo& from);
@@ -2850,7 +3368,16 @@
   void SharedCtor();
   void SharedDtor();
   void SetCachedSize(int size) const;
+  void InternalSwap(SourceCodeInfo* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
   public:
+
   ::google::protobuf::Metadata GetMetadata() const;
 
   // nested types ----------------------------------------------------
@@ -2860,22 +3387,21 @@
   // accessors -------------------------------------------------------
 
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  inline int location_size() const;
-  inline void clear_location();
+  int location_size() const;
+  void clear_location();
   static const int kLocationFieldNumber = 1;
-  inline const ::google::protobuf::SourceCodeInfo_Location& location(int index) const;
-  inline ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index);
-  inline ::google::protobuf::SourceCodeInfo_Location* add_location();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
-      location() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
+  const ::google::protobuf::SourceCodeInfo_Location& location(int index) const;
+  ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index);
+  ::google::protobuf::SourceCodeInfo_Location* add_location();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
       mutable_location();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+      location() const;
 
   // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
  private:
 
-  ::google::protobuf::UnknownFieldSet _unknown_fields_;
-
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_;
@@ -2886,11 +3412,234 @@
   void InitAsDefaultInstance();
   static SourceCodeInfo* default_instance_;
 };
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message {
+ public:
+  GeneratedCodeInfo_Annotation();
+  virtual ~GeneratedCodeInfo_Annotation();
+
+  GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from);
+
+  inline GeneratedCodeInfo_Annotation& operator=(const GeneratedCodeInfo_Annotation& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GeneratedCodeInfo_Annotation& default_instance();
+
+  void Swap(GeneratedCodeInfo_Annotation* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GeneratedCodeInfo_Annotation* New() const { return New(NULL); }
+
+  GeneratedCodeInfo_Annotation* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GeneratedCodeInfo_Annotation& from);
+  void MergeFrom(const GeneratedCodeInfo_Annotation& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GeneratedCodeInfo_Annotation* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  void clear_path();
+  static const int kPathFieldNumber = 1;
+  ::google::protobuf::int32 path(int index) const;
+  void set_path(int index, ::google::protobuf::int32 value);
+  void add_path(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      path() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_path();
+
+  // optional string source_file = 2;
+  bool has_source_file() const;
+  void clear_source_file();
+  static const int kSourceFileFieldNumber = 2;
+  const ::std::string& source_file() const;
+  void set_source_file(const ::std::string& value);
+  void set_source_file(const char* value);
+  void set_source_file(const char* value, size_t size);
+  ::std::string* mutable_source_file();
+  ::std::string* release_source_file();
+  void set_allocated_source_file(::std::string* source_file);
+
+  // optional int32 begin = 3;
+  bool has_begin() const;
+  void clear_begin();
+  static const int kBeginFieldNumber = 3;
+  ::google::protobuf::int32 begin() const;
+  void set_begin(::google::protobuf::int32 value);
+
+  // optional int32 end = 4;
+  bool has_end() const;
+  void clear_end();
+  static const int kEndFieldNumber = 4;
+  ::google::protobuf::int32 end() const;
+  void set_end(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
+ private:
+  inline void set_has_source_file();
+  inline void clear_has_source_file();
+  inline void set_has_begin();
+  inline void clear_has_begin();
+  inline void set_has_end();
+  inline void clear_has_end();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_;
+  mutable int _path_cached_byte_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_file_;
+  ::google::protobuf::int32 begin_;
+  ::google::protobuf::int32 end_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static GeneratedCodeInfo_Annotation* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message {
+ public:
+  GeneratedCodeInfo();
+  virtual ~GeneratedCodeInfo();
+
+  GeneratedCodeInfo(const GeneratedCodeInfo& from);
+
+  inline GeneratedCodeInfo& operator=(const GeneratedCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GeneratedCodeInfo& default_instance();
+
+  void Swap(GeneratedCodeInfo* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GeneratedCodeInfo* New() const { return New(NULL); }
+
+  GeneratedCodeInfo* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GeneratedCodeInfo& from);
+  void MergeFrom(const GeneratedCodeInfo& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GeneratedCodeInfo* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef GeneratedCodeInfo_Annotation Annotation;
+
+  // accessors -------------------------------------------------------
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  int annotation_size() const;
+  void clear_annotation();
+  static const int kAnnotationFieldNumber = 1;
+  const ::google::protobuf::GeneratedCodeInfo_Annotation& annotation(int index) const;
+  ::google::protobuf::GeneratedCodeInfo_Annotation* mutable_annotation(int index);
+  ::google::protobuf::GeneratedCodeInfo_Annotation* add_annotation();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+      mutable_annotation();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+      annotation() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation > annotation_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static GeneratedCodeInfo* default_instance_;
+};
 // ===================================================================
 
 
 // ===================================================================
 
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // FileDescriptorSet
 
 // repeated .google.protobuf.FileDescriptorProto file = 1;
@@ -2912,16 +3661,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file)
   return file_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
-FileDescriptorSet::file() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
-  return file_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
 FileDescriptorSet::mutable_file() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file)
   return &file_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+FileDescriptorSet::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file)
+  return file_;
+}
 
 // -------------------------------------------------------------------
 
@@ -2938,68 +3687,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void FileDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& FileDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.name)
 }
 inline void FileDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.name)
 }
 inline void FileDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.name)
 }
 inline ::std::string* FileDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FileDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.name)
 }
 
@@ -3014,68 +3741,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void FileDescriptorProto::clear_package() {
-  if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    package_->clear();
-  }
+  package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_package();
 }
 inline const ::std::string& FileDescriptorProto::package() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.package)
-  return *package_;
+  return package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileDescriptorProto::set_package(const ::std::string& value) {
   set_has_package();
-  if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    package_ = new ::std::string;
-  }
-  package_->assign(value);
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.package)
 }
 inline void FileDescriptorProto::set_package(const char* value) {
   set_has_package();
-  if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    package_ = new ::std::string;
-  }
-  package_->assign(value);
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.package)
 }
 inline void FileDescriptorProto::set_package(const char* value, size_t size) {
   set_has_package();
-  if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    package_ = new ::std::string;
-  }
-  package_->assign(reinterpret_cast<const char*>(value), size);
+  package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.package)
 }
 inline ::std::string* FileDescriptorProto::mutable_package() {
   set_has_package();
-  if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    package_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.package)
-  return package_;
+  return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FileDescriptorProto::release_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package)
   clear_has_package();
-  if (package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = package_;
-    package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileDescriptorProto::set_allocated_package(::std::string* package) {
-  if (package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete package_;
-  }
-  if (package) {
+  if (package != NULL) {
     set_has_package();
-    package_ = package;
   } else {
     clear_has_package();
-    package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), package);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.package)
 }
 
@@ -3108,6 +3813,7 @@
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency)
 }
 inline ::std::string* FileDescriptorProto::add_dependency() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency)
   return dependency_.Add();
 }
 inline void FileDescriptorProto::add_dependency(const ::std::string& value) {
@@ -3212,16 +3918,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type)
   return message_type_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-FileDescriptorProto::message_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
-  return message_type_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
 FileDescriptorProto::mutable_message_type() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type)
   return &message_type_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+FileDescriptorProto::message_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type)
+  return message_type_;
+}
 
 // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
 inline int FileDescriptorProto::enum_type_size() const {
@@ -3242,16 +3948,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type)
   return enum_type_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-FileDescriptorProto::enum_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
-  return enum_type_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
 FileDescriptorProto::mutable_enum_type() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type)
   return &enum_type_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+FileDescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type)
+  return enum_type_;
+}
 
 // repeated .google.protobuf.ServiceDescriptorProto service = 6;
 inline int FileDescriptorProto::service_size() const {
@@ -3272,16 +3978,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service)
   return service_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
-FileDescriptorProto::service() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
-  return service_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >*
 FileDescriptorProto::mutable_service() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service)
   return &service_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >&
+FileDescriptorProto::service() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service)
+  return service_;
+}
 
 // repeated .google.protobuf.FieldDescriptorProto extension = 7;
 inline int FileDescriptorProto::extension_size() const {
@@ -3302,16 +4008,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension)
   return extension_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-FileDescriptorProto::extension() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
-  return extension_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
 FileDescriptorProto::mutable_extension() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension)
   return &extension_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+FileDescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension)
+  return extension_;
+}
 
 // optional .google.protobuf.FileOptions options = 8;
 inline bool FileDescriptorProto::has_options() const {
@@ -3333,11 +4039,14 @@
 }
 inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::FileOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::FileOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::FileOptions* temp = options_;
   options_ = NULL;
@@ -3374,11 +4083,14 @@
 }
 inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() {
   set_has_source_code_info();
-  if (source_code_info_ == NULL) source_code_info_ = new ::google::protobuf::SourceCodeInfo;
+  if (source_code_info_ == NULL) {
+    source_code_info_ = new ::google::protobuf::SourceCodeInfo;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info)
   return source_code_info_;
 }
 inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info)
   clear_has_source_code_info();
   ::google::protobuf::SourceCodeInfo* temp = source_code_info_;
   source_code_info_ = NULL;
@@ -3395,6 +4107,60 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.source_code_info)
 }
 
+// optional string syntax = 12;
+inline bool FileDescriptorProto::has_syntax() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void FileDescriptorProto::set_has_syntax() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void FileDescriptorProto::clear_has_syntax() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void FileDescriptorProto::clear_syntax() {
+  syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_syntax();
+}
+inline const ::std::string& FileDescriptorProto::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.syntax)
+  return syntax_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_syntax(const ::std::string& value) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileDescriptorProto.syntax)
+}
+inline void FileDescriptorProto::set_syntax(const char* value) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileDescriptorProto.syntax)
+}
+inline void FileDescriptorProto::set_syntax(const char* value, size_t size) {
+  set_has_syntax();
+  syntax_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.syntax)
+}
+inline ::std::string* FileDescriptorProto::mutable_syntax() {
+  set_has_syntax();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.syntax)
+  return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileDescriptorProto::release_syntax() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax)
+  clear_has_syntax();
+  return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileDescriptorProto::set_allocated_syntax(::std::string* syntax) {
+  if (syntax != NULL) {
+    set_has_syntax();
+  } else {
+    clear_has_syntax();
+  }
+  syntax_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), syntax);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileDescriptorProto.syntax)
+}
+
 // -------------------------------------------------------------------
 
 // DescriptorProto_ExtensionRange
@@ -3449,6 +4215,58 @@
 
 // -------------------------------------------------------------------
 
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ReservedRange::has_start() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DescriptorProto_ReservedRange::set_has_start() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DescriptorProto_ReservedRange::clear_has_start() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DescriptorProto_ReservedRange::clear_start() {
+  start_ = 0;
+  clear_has_start();
+}
+inline ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return start_;
+}
+inline void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) {
+  set_has_start();
+  start_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ReservedRange::has_end() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DescriptorProto_ReservedRange::set_has_end() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DescriptorProto_ReservedRange::clear_has_end() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DescriptorProto_ReservedRange::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+inline ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return end_;
+}
+inline void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
 // DescriptorProto
 
 // optional string name = 1;
@@ -3462,68 +4280,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void DescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& DescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void DescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.name)
 }
 inline void DescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.name)
 }
 inline void DescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.name)
 }
 inline ::std::string* DescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* DescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void DescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.name)
 }
 
@@ -3546,16 +4342,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field)
   return field_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-DescriptorProto::field() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
-  return field_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
 DescriptorProto::mutable_field() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field)
   return &field_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::field() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field)
+  return field_;
+}
 
 // repeated .google.protobuf.FieldDescriptorProto extension = 6;
 inline int DescriptorProto::extension_size() const {
@@ -3576,16 +4372,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension)
   return extension_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
-DescriptorProto::extension() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
-  return extension_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >*
 DescriptorProto::mutable_extension() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension)
   return &extension_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >&
+DescriptorProto::extension() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension)
+  return extension_;
+}
 
 // repeated .google.protobuf.DescriptorProto nested_type = 3;
 inline int DescriptorProto::nested_type_size() const {
@@ -3606,16 +4402,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type)
   return nested_type_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
-DescriptorProto::nested_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
-  return nested_type_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >*
 DescriptorProto::mutable_nested_type() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type)
   return &nested_type_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >&
+DescriptorProto::nested_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type)
+  return nested_type_;
+}
 
 // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
 inline int DescriptorProto::enum_type_size() const {
@@ -3636,16 +4432,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type)
   return enum_type_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
-DescriptorProto::enum_type() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
-  return enum_type_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >*
 DescriptorProto::mutable_enum_type() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type)
   return &enum_type_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >&
+DescriptorProto::enum_type() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type)
+  return enum_type_;
+}
 
 // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
 inline int DescriptorProto::extension_range_size() const {
@@ -3666,16 +4462,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range)
   return extension_range_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
-DescriptorProto::extension_range() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
-  return extension_range_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >*
 DescriptorProto::mutable_extension_range() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range)
   return &extension_range_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >&
+DescriptorProto::extension_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range)
+  return extension_range_;
+}
 
 // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
 inline int DescriptorProto::oneof_decl_size() const {
@@ -3696,16 +4492,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl)
   return oneof_decl_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
-DescriptorProto::oneof_decl() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
-  return oneof_decl_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >*
 DescriptorProto::mutable_oneof_decl() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl)
   return &oneof_decl_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >&
+DescriptorProto::oneof_decl() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl)
+  return oneof_decl_;
+}
 
 // optional .google.protobuf.MessageOptions options = 7;
 inline bool DescriptorProto::has_options() const {
@@ -3727,11 +4523,14 @@
 }
 inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::MessageOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options)
   clear_has_options();
   ::google::protobuf::MessageOptions* temp = options_;
   options_ = NULL;
@@ -3748,6 +4547,91 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
 }
 
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+inline int DescriptorProto::reserved_range_size() const {
+  return reserved_range_.size();
+}
+inline void DescriptorProto::clear_reserved_range() {
+  reserved_range_.Clear();
+}
+inline const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Get(index);
+}
+inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Mutable(index);
+}
+inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &reserved_range_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+inline int DescriptorProto::reserved_name_size() const {
+  return reserved_name_.size();
+}
+inline void DescriptorProto::clear_reserved_name() {
+  reserved_name_.Clear();
+}
+inline const ::std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Get(index);
+}
+inline ::std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Mutable(index);
+}
+inline void DescriptorProto::set_reserved_name(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+  reserved_name_.Mutable(index)->assign(value);
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value) {
+  reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline ::std::string* DescriptorProto::add_reserved_name() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Add();
+}
+inline void DescriptorProto::add_reserved_name(const ::std::string& value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value, size_t size) {
+  reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &reserved_name_;
+}
+
 // -------------------------------------------------------------------
 
 // FieldDescriptorProto
@@ -3763,68 +4647,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void FieldDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& FieldDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.name)
 }
 inline void FieldDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.name)
 }
 inline void FieldDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.name)
 }
 inline ::std::string* FieldDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FieldDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.name)
 }
 
@@ -3913,68 +4775,46 @@
   _has_bits_[0] &= ~0x00000010u;
 }
 inline void FieldDescriptorProto::clear_type_name() {
-  if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    type_name_->clear();
-  }
+  type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_type_name();
 }
 inline const ::std::string& FieldDescriptorProto::type_name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.type_name)
-  return *type_name_;
+  return type_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_type_name(const ::std::string& value) {
   set_has_type_name();
-  if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    type_name_ = new ::std::string;
-  }
-  type_name_->assign(value);
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.type_name)
 }
 inline void FieldDescriptorProto::set_type_name(const char* value) {
   set_has_type_name();
-  if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    type_name_ = new ::std::string;
-  }
-  type_name_->assign(value);
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.type_name)
 }
 inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) {
   set_has_type_name();
-  if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    type_name_ = new ::std::string;
-  }
-  type_name_->assign(reinterpret_cast<const char*>(value), size);
+  type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.type_name)
 }
 inline ::std::string* FieldDescriptorProto::mutable_type_name() {
   set_has_type_name();
-  if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    type_name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.type_name)
-  return type_name_;
+  return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FieldDescriptorProto::release_type_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name)
   clear_has_type_name();
-  if (type_name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = type_name_;
-    type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) {
-  if (type_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete type_name_;
-  }
-  if (type_name) {
+  if (type_name != NULL) {
     set_has_type_name();
-    type_name_ = type_name;
   } else {
     clear_has_type_name();
-    type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  type_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.type_name)
 }
 
@@ -3989,68 +4829,46 @@
   _has_bits_[0] &= ~0x00000020u;
 }
 inline void FieldDescriptorProto::clear_extendee() {
-  if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    extendee_->clear();
-  }
+  extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_extendee();
 }
 inline const ::std::string& FieldDescriptorProto::extendee() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.extendee)
-  return *extendee_;
+  return extendee_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_extendee(const ::std::string& value) {
   set_has_extendee();
-  if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    extendee_ = new ::std::string;
-  }
-  extendee_->assign(value);
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.extendee)
 }
 inline void FieldDescriptorProto::set_extendee(const char* value) {
   set_has_extendee();
-  if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    extendee_ = new ::std::string;
-  }
-  extendee_->assign(value);
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.extendee)
 }
 inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) {
   set_has_extendee();
-  if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    extendee_ = new ::std::string;
-  }
-  extendee_->assign(reinterpret_cast<const char*>(value), size);
+  extendee_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.extendee)
 }
 inline ::std::string* FieldDescriptorProto::mutable_extendee() {
   set_has_extendee();
-  if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    extendee_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.extendee)
-  return extendee_;
+  return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FieldDescriptorProto::release_extendee() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee)
   clear_has_extendee();
-  if (extendee_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = extendee_;
-    extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) {
-  if (extendee_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete extendee_;
-  }
-  if (extendee) {
+  if (extendee != NULL) {
     set_has_extendee();
-    extendee_ = extendee;
   } else {
     clear_has_extendee();
-    extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  extendee_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extendee);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.extendee)
 }
 
@@ -4065,68 +4883,46 @@
   _has_bits_[0] &= ~0x00000040u;
 }
 inline void FieldDescriptorProto::clear_default_value() {
-  if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    default_value_->clear();
-  }
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_default_value();
 }
 inline const ::std::string& FieldDescriptorProto::default_value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.default_value)
-  return *default_value_;
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_default_value(const ::std::string& value) {
   set_has_default_value();
-  if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    default_value_ = new ::std::string;
-  }
-  default_value_->assign(value);
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.default_value)
 }
 inline void FieldDescriptorProto::set_default_value(const char* value) {
   set_has_default_value();
-  if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    default_value_ = new ::std::string;
-  }
-  default_value_->assign(value);
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.default_value)
 }
 inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) {
   set_has_default_value();
-  if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    default_value_ = new ::std::string;
-  }
-  default_value_->assign(reinterpret_cast<const char*>(value), size);
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.default_value)
 }
 inline ::std::string* FieldDescriptorProto::mutable_default_value() {
   set_has_default_value();
-  if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    default_value_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.default_value)
-  return default_value_;
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FieldDescriptorProto::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value)
   clear_has_default_value();
-  if (default_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = default_value_;
-    default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) {
-  if (default_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete default_value_;
-  }
-  if (default_value) {
+  if (default_value != NULL) {
     set_has_default_value();
-    default_value_ = default_value;
   } else {
     clear_has_default_value();
-    default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.default_value)
 }
 
@@ -4154,16 +4950,70 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
 }
 
-// optional .google.protobuf.FieldOptions options = 8;
-inline bool FieldDescriptorProto::has_options() const {
+// optional string json_name = 10;
+inline bool FieldDescriptorProto::has_json_name() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
-inline void FieldDescriptorProto::set_has_options() {
+inline void FieldDescriptorProto::set_has_json_name() {
   _has_bits_[0] |= 0x00000100u;
 }
-inline void FieldDescriptorProto::clear_has_options() {
+inline void FieldDescriptorProto::clear_has_json_name() {
   _has_bits_[0] &= ~0x00000100u;
 }
+inline void FieldDescriptorProto::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_json_name();
+}
+inline const ::std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_json_name(const ::std::string& value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline void FieldDescriptorProto::set_json_name(const char* value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline ::std::string* FieldDescriptorProto::mutable_json_name() {
+  set_has_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FieldDescriptorProto::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name)
+  clear_has_json_name();
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    set_has_json_name();
+  } else {
+    clear_has_json_name();
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+inline bool FieldDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void FieldDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void FieldDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000200u;
+}
 inline void FieldDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
   clear_has_options();
@@ -4174,11 +5024,14 @@
 }
 inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::FieldOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::FieldOptions* temp = options_;
   options_ = NULL;
@@ -4210,68 +5063,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void OneofDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& OneofDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void OneofDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.OneofDescriptorProto.name)
 }
 inline void OneofDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.OneofDescriptorProto.name)
 }
 inline void OneofDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.OneofDescriptorProto.name)
 }
 inline ::std::string* OneofDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* OneofDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void OneofDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
 }
 
@@ -4290,68 +5121,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void EnumDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& EnumDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void EnumDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.EnumDescriptorProto.name)
 }
 inline void EnumDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.EnumDescriptorProto.name)
 }
 inline void EnumDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumDescriptorProto.name)
 }
 inline ::std::string* EnumDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* EnumDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void EnumDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumDescriptorProto.name)
 }
 
@@ -4374,16 +5183,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value)
   return value_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
-EnumDescriptorProto::value() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
-  return value_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >*
 EnumDescriptorProto::mutable_value() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value)
   return &value_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >&
+EnumDescriptorProto::value() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value)
+  return value_;
+}
 
 // optional .google.protobuf.EnumOptions options = 3;
 inline bool EnumDescriptorProto::has_options() const {
@@ -4405,11 +5214,14 @@
 }
 inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::EnumOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::EnumOptions* temp = options_;
   options_ = NULL;
@@ -4441,68 +5253,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void EnumValueDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& EnumValueDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void EnumValueDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.EnumValueDescriptorProto.name)
 }
 inline void EnumValueDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValueDescriptorProto.name)
 }
 inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValueDescriptorProto.name)
 }
 inline ::std::string* EnumValueDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* EnumValueDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void EnumValueDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValueDescriptorProto.name)
 }
 
@@ -4550,11 +5340,14 @@
 }
 inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::EnumValueOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::EnumValueOptions* temp = options_;
   options_ = NULL;
@@ -4586,68 +5379,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void ServiceDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& ServiceDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void ServiceDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.ServiceDescriptorProto.name)
 }
 inline void ServiceDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.ServiceDescriptorProto.name)
 }
 inline void ServiceDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.ServiceDescriptorProto.name)
 }
 inline ::std::string* ServiceDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* ServiceDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void ServiceDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.ServiceDescriptorProto.name)
 }
 
@@ -4670,16 +5441,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method)
   return method_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
-ServiceDescriptorProto::method() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
-  return method_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >*
 ServiceDescriptorProto::mutable_method() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method)
   return &method_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >&
+ServiceDescriptorProto::method() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method)
+  return method_;
+}
 
 // optional .google.protobuf.ServiceOptions options = 3;
 inline bool ServiceDescriptorProto::has_options() const {
@@ -4701,11 +5472,14 @@
 }
 inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::ServiceOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::ServiceOptions* temp = options_;
   options_ = NULL;
@@ -4737,68 +5511,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void MethodDescriptorProto::clear_name() {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_->clear();
-  }
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
 inline const ::std::string& MethodDescriptorProto::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.name)
-  return *name_;
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_name(const ::std::string& value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.name)
 }
 inline void MethodDescriptorProto::set_name(const char* value) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(value);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.name)
 }
 inline void MethodDescriptorProto::set_name(const char* value, size_t size) {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
-  name_->assign(reinterpret_cast<const char*>(value), size);
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.name)
 }
 inline ::std::string* MethodDescriptorProto::mutable_name() {
   set_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.name)
-  return name_;
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* MethodDescriptorProto::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name)
   clear_has_name();
-  if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_;
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_allocated_name(::std::string* name) {
-  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_;
-  }
-  if (name) {
+  if (name != NULL) {
     set_has_name();
-    name_ = name;
   } else {
     clear_has_name();
-    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.name)
 }
 
@@ -4813,68 +5565,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void MethodDescriptorProto::clear_input_type() {
-  if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    input_type_->clear();
-  }
+  input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_input_type();
 }
 inline const ::std::string& MethodDescriptorProto::input_type() const {
   // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.input_type)
-  return *input_type_;
+  return input_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_input_type(const ::std::string& value) {
   set_has_input_type();
-  if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    input_type_ = new ::std::string;
-  }
-  input_type_->assign(value);
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.input_type)
 }
 inline void MethodDescriptorProto::set_input_type(const char* value) {
   set_has_input_type();
-  if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    input_type_ = new ::std::string;
-  }
-  input_type_->assign(value);
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.input_type)
 }
 inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) {
   set_has_input_type();
-  if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    input_type_ = new ::std::string;
-  }
-  input_type_->assign(reinterpret_cast<const char*>(value), size);
+  input_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.input_type)
 }
 inline ::std::string* MethodDescriptorProto::mutable_input_type() {
   set_has_input_type();
-  if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    input_type_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.input_type)
-  return input_type_;
+  return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* MethodDescriptorProto::release_input_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type)
   clear_has_input_type();
-  if (input_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = input_type_;
-    input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) {
-  if (input_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete input_type_;
-  }
-  if (input_type) {
+  if (input_type != NULL) {
     set_has_input_type();
-    input_type_ = input_type;
   } else {
     clear_has_input_type();
-    input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  input_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), input_type);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.input_type)
 }
 
@@ -4889,68 +5619,46 @@
   _has_bits_[0] &= ~0x00000004u;
 }
 inline void MethodDescriptorProto::clear_output_type() {
-  if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    output_type_->clear();
-  }
+  output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_output_type();
 }
 inline const ::std::string& MethodDescriptorProto::output_type() const {
   // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.output_type)
-  return *output_type_;
+  return output_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_output_type(const ::std::string& value) {
   set_has_output_type();
-  if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    output_type_ = new ::std::string;
-  }
-  output_type_->assign(value);
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.output_type)
 }
 inline void MethodDescriptorProto::set_output_type(const char* value) {
   set_has_output_type();
-  if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    output_type_ = new ::std::string;
-  }
-  output_type_->assign(value);
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.MethodDescriptorProto.output_type)
 }
 inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) {
   set_has_output_type();
-  if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    output_type_ = new ::std::string;
-  }
-  output_type_->assign(reinterpret_cast<const char*>(value), size);
+  output_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.MethodDescriptorProto.output_type)
 }
 inline ::std::string* MethodDescriptorProto::mutable_output_type() {
   set_has_output_type();
-  if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    output_type_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.output_type)
-  return output_type_;
+  return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* MethodDescriptorProto::release_output_type() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type)
   clear_has_output_type();
-  if (output_type_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = output_type_;
-    output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) {
-  if (output_type_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete output_type_;
-  }
-  if (output_type) {
+  if (output_type != NULL) {
     set_has_output_type();
-    output_type_ = output_type;
   } else {
     clear_has_output_type();
-    output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  output_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), output_type);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.output_type)
 }
 
@@ -4974,11 +5682,14 @@
 }
 inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() {
   set_has_options();
-  if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions;
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::MethodOptions;
+  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options)
   return options_;
 }
 inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options)
   clear_has_options();
   ::google::protobuf::MethodOptions* temp = options_;
   options_ = NULL;
@@ -4995,6 +5706,54 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options)
 }
 
+// optional bool client_streaming = 5 [default = false];
+inline bool MethodDescriptorProto::has_client_streaming() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void MethodDescriptorProto::set_has_client_streaming() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void MethodDescriptorProto::clear_has_client_streaming() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void MethodDescriptorProto::clear_client_streaming() {
+  client_streaming_ = false;
+  clear_has_client_streaming();
+}
+inline bool MethodDescriptorProto::client_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming)
+  return client_streaming_;
+}
+inline void MethodDescriptorProto::set_client_streaming(bool value) {
+  set_has_client_streaming();
+  client_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming)
+}
+
+// optional bool server_streaming = 6 [default = false];
+inline bool MethodDescriptorProto::has_server_streaming() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void MethodDescriptorProto::set_has_server_streaming() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void MethodDescriptorProto::clear_has_server_streaming() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void MethodDescriptorProto::clear_server_streaming() {
+  server_streaming_ = false;
+  clear_has_server_streaming();
+}
+inline bool MethodDescriptorProto::server_streaming() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming)
+  return server_streaming_;
+}
+inline void MethodDescriptorProto::set_server_streaming(bool value) {
+  set_has_server_streaming();
+  server_streaming_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming)
+}
+
 // -------------------------------------------------------------------
 
 // FileOptions
@@ -5010,68 +5769,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void FileOptions::clear_java_package() {
-  if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_package_->clear();
-  }
+  java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_package();
 }
 inline const ::std::string& FileOptions::java_package() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_package)
-  return *java_package_;
+  return java_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_java_package(const ::std::string& value) {
   set_has_java_package();
-  if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_package_ = new ::std::string;
-  }
-  java_package_->assign(value);
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_package)
 }
 inline void FileOptions::set_java_package(const char* value) {
   set_has_java_package();
-  if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_package_ = new ::std::string;
-  }
-  java_package_->assign(value);
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_package)
 }
 inline void FileOptions::set_java_package(const char* value, size_t size) {
   set_has_java_package();
-  if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_package_ = new ::std::string;
-  }
-  java_package_->assign(reinterpret_cast<const char*>(value), size);
+  java_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_package)
 }
 inline ::std::string* FileOptions::mutable_java_package() {
   set_has_java_package();
-  if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_package_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_package)
-  return java_package_;
+  return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FileOptions::release_java_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package)
   clear_has_java_package();
-  if (java_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = java_package_;
-    java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_allocated_java_package(::std::string* java_package) {
-  if (java_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete java_package_;
-  }
-  if (java_package) {
+  if (java_package != NULL) {
     set_has_java_package();
-    java_package_ = java_package;
   } else {
     clear_has_java_package();
-    java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  java_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_package);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_package)
 }
 
@@ -5086,68 +5823,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void FileOptions::clear_java_outer_classname() {
-  if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_outer_classname_->clear();
-  }
+  java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_outer_classname();
 }
 inline const ::std::string& FileOptions::java_outer_classname() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.java_outer_classname)
-  return *java_outer_classname_;
+  return java_outer_classname_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_java_outer_classname(const ::std::string& value) {
   set_has_java_outer_classname();
-  if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_outer_classname_ = new ::std::string;
-  }
-  java_outer_classname_->assign(value);
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.java_outer_classname)
 }
 inline void FileOptions::set_java_outer_classname(const char* value) {
   set_has_java_outer_classname();
-  if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_outer_classname_ = new ::std::string;
-  }
-  java_outer_classname_->assign(value);
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.java_outer_classname)
 }
 inline void FileOptions::set_java_outer_classname(const char* value, size_t size) {
   set_has_java_outer_classname();
-  if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_outer_classname_ = new ::std::string;
-  }
-  java_outer_classname_->assign(reinterpret_cast<const char*>(value), size);
+  java_outer_classname_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.java_outer_classname)
 }
 inline ::std::string* FileOptions::mutable_java_outer_classname() {
   set_has_java_outer_classname();
-  if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    java_outer_classname_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.java_outer_classname)
-  return java_outer_classname_;
+  return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FileOptions::release_java_outer_classname() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname)
   clear_has_java_outer_classname();
-  if (java_outer_classname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = java_outer_classname_;
-    java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) {
-  if (java_outer_classname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete java_outer_classname_;
-  }
-  if (java_outer_classname) {
+  if (java_outer_classname != NULL) {
     set_has_java_outer_classname();
-    java_outer_classname_ = java_outer_classname;
   } else {
     clear_has_java_outer_classname();
-    java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  java_outer_classname_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), java_outer_classname);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.java_outer_classname)
 }
 
@@ -5259,68 +5974,46 @@
   _has_bits_[0] &= ~0x00000040u;
 }
 inline void FileOptions::clear_go_package() {
-  if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    go_package_->clear();
-  }
+  go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_go_package();
 }
 inline const ::std::string& FileOptions::go_package() const {
   // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.go_package)
-  return *go_package_;
+  return go_package_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_go_package(const ::std::string& value) {
   set_has_go_package();
-  if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    go_package_ = new ::std::string;
-  }
-  go_package_->assign(value);
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.go_package)
 }
 inline void FileOptions::set_go_package(const char* value) {
   set_has_go_package();
-  if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    go_package_ = new ::std::string;
-  }
-  go_package_->assign(value);
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.go_package)
 }
 inline void FileOptions::set_go_package(const char* value, size_t size) {
   set_has_go_package();
-  if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    go_package_ = new ::std::string;
-  }
-  go_package_->assign(reinterpret_cast<const char*>(value), size);
+  go_package_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.go_package)
 }
 inline ::std::string* FileOptions::mutable_go_package() {
   set_has_go_package();
-  if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    go_package_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.go_package)
-  return go_package_;
+  return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* FileOptions::release_go_package() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package)
   clear_has_go_package();
-  if (go_package_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = go_package_;
-    go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void FileOptions::set_allocated_go_package(::std::string* go_package) {
-  if (go_package_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete go_package_;
-  }
-  if (go_package) {
+  if (go_package != NULL) {
     set_has_go_package();
-    go_package_ = go_package;
   } else {
     clear_has_go_package();
-    go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  go_package_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), go_package);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.go_package)
 }
 
@@ -5420,28 +6113,136 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.deprecated)
 }
 
-// optional bool javanano_use_deprecated_package = 38;
-inline bool FileOptions::has_javanano_use_deprecated_package() const {
+// optional bool cc_enable_arenas = 31 [default = false];
+inline bool FileOptions::has_cc_enable_arenas() const {
   return (_has_bits_[0] & 0x00000800u) != 0;
 }
-inline void FileOptions::set_has_javanano_use_deprecated_package() {
+inline void FileOptions::set_has_cc_enable_arenas() {
   _has_bits_[0] |= 0x00000800u;
 }
-inline void FileOptions::clear_has_javanano_use_deprecated_package() {
+inline void FileOptions::clear_has_cc_enable_arenas() {
   _has_bits_[0] &= ~0x00000800u;
 }
-inline void FileOptions::clear_javanano_use_deprecated_package() {
-  javanano_use_deprecated_package_ = false;
-  clear_has_javanano_use_deprecated_package();
+inline void FileOptions::clear_cc_enable_arenas() {
+  cc_enable_arenas_ = false;
+  clear_has_cc_enable_arenas();
 }
-inline bool FileOptions::javanano_use_deprecated_package() const {
-  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package)
-  return javanano_use_deprecated_package_;
+inline bool FileOptions::cc_enable_arenas() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.cc_enable_arenas)
+  return cc_enable_arenas_;
 }
-inline void FileOptions::set_javanano_use_deprecated_package(bool value) {
-  set_has_javanano_use_deprecated_package();
-  javanano_use_deprecated_package_ = value;
-  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.javanano_use_deprecated_package)
+inline void FileOptions::set_cc_enable_arenas(bool value) {
+  set_has_cc_enable_arenas();
+  cc_enable_arenas_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.cc_enable_arenas)
+}
+
+// optional string objc_class_prefix = 36;
+inline bool FileOptions::has_objc_class_prefix() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void FileOptions::set_has_objc_class_prefix() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void FileOptions::clear_has_objc_class_prefix() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void FileOptions::clear_objc_class_prefix() {
+  objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_objc_class_prefix();
+}
+inline const ::std::string& FileOptions::objc_class_prefix() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.objc_class_prefix)
+  return objc_class_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_objc_class_prefix(const ::std::string& value) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline void FileOptions::set_objc_class_prefix(const char* value) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline void FileOptions::set_objc_class_prefix(const char* value, size_t size) {
+  set_has_objc_class_prefix();
+  objc_class_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.objc_class_prefix)
+}
+inline ::std::string* FileOptions::mutable_objc_class_prefix() {
+  set_has_objc_class_prefix();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.objc_class_prefix)
+  return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileOptions::release_objc_class_prefix() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix)
+  clear_has_objc_class_prefix();
+  return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_objc_class_prefix(::std::string* objc_class_prefix) {
+  if (objc_class_prefix != NULL) {
+    set_has_objc_class_prefix();
+  } else {
+    clear_has_objc_class_prefix();
+  }
+  objc_class_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), objc_class_prefix);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix)
+}
+
+// optional string csharp_namespace = 37;
+inline bool FileOptions::has_csharp_namespace() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void FileOptions::set_has_csharp_namespace() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void FileOptions::clear_has_csharp_namespace() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void FileOptions::clear_csharp_namespace() {
+  csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_csharp_namespace();
+}
+inline const ::std::string& FileOptions::csharp_namespace() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace)
+  return csharp_namespace_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_csharp_namespace(const ::std::string& value) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace)
+}
+inline void FileOptions::set_csharp_namespace(const char* value) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.csharp_namespace)
+}
+inline void FileOptions::set_csharp_namespace(const char* value, size_t size) {
+  set_has_csharp_namespace();
+  csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.csharp_namespace)
+}
+inline ::std::string* FileOptions::mutable_csharp_namespace() {
+  set_has_csharp_namespace();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace)
+  return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FileOptions::release_csharp_namespace() {
+  // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace)
+  clear_has_csharp_namespace();
+  return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_namespace) {
+  if (csharp_namespace != NULL) {
+    set_has_csharp_namespace();
+  } else {
+    clear_has_csharp_namespace();
+  }
+  csharp_namespace_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), csharp_namespace);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
@@ -5463,16 +6264,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-FileOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 FileOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FileOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5550,6 +6351,30 @@
   // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.deprecated)
 }
 
+// optional bool map_entry = 7;
+inline bool MessageOptions::has_map_entry() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void MessageOptions::set_has_map_entry() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void MessageOptions::clear_has_map_entry() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void MessageOptions::clear_map_entry() {
+  map_entry_ = false;
+  clear_has_map_entry();
+}
+inline bool MessageOptions::map_entry() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.map_entry)
+  return map_entry_;
+}
+inline void MessageOptions::set_map_entry(bool value) {
+  set_has_map_entry();
+  map_entry_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.MessageOptions.map_entry)
+}
+
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
 inline int MessageOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
@@ -5569,16 +6394,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-MessageOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 MessageOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MessageOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5633,16 +6458,41 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
 }
 
-// optional bool lazy = 5 [default = false];
-inline bool FieldOptions::has_lazy() const {
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+inline bool FieldOptions::has_jstype() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
-inline void FieldOptions::set_has_lazy() {
+inline void FieldOptions::set_has_jstype() {
   _has_bits_[0] |= 0x00000004u;
 }
-inline void FieldOptions::clear_has_lazy() {
+inline void FieldOptions::clear_has_jstype() {
   _has_bits_[0] &= ~0x00000004u;
 }
+inline void FieldOptions::clear_jstype() {
+  jstype_ = 0;
+  clear_has_jstype();
+}
+inline ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_);
+}
+inline void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) {
+  assert(::google::protobuf::FieldOptions_JSType_IsValid(value));
+  set_has_jstype();
+  jstype_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::has_lazy() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void FieldOptions::set_has_lazy() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void FieldOptions::clear_has_lazy() {
+  _has_bits_[0] &= ~0x00000008u;
+}
 inline void FieldOptions::clear_lazy() {
   lazy_ = false;
   clear_has_lazy();
@@ -5659,13 +6509,13 @@
 
 // optional bool deprecated = 3 [default = false];
 inline bool FieldOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00000008u) != 0;
+  return (_has_bits_[0] & 0x00000010u) != 0;
 }
 inline void FieldOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00000008u;
+  _has_bits_[0] |= 0x00000010u;
 }
 inline void FieldOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00000008u;
+  _has_bits_[0] &= ~0x00000010u;
 }
 inline void FieldOptions::clear_deprecated() {
   deprecated_ = false;
@@ -5681,82 +6531,6 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.deprecated)
 }
 
-// optional string experimental_map_key = 9;
-inline bool FieldOptions::has_experimental_map_key() const {
-  return (_has_bits_[0] & 0x00000010u) != 0;
-}
-inline void FieldOptions::set_has_experimental_map_key() {
-  _has_bits_[0] |= 0x00000010u;
-}
-inline void FieldOptions::clear_has_experimental_map_key() {
-  _has_bits_[0] &= ~0x00000010u;
-}
-inline void FieldOptions::clear_experimental_map_key() {
-  if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    experimental_map_key_->clear();
-  }
-  clear_has_experimental_map_key();
-}
-inline const ::std::string& FieldOptions::experimental_map_key() const {
-  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.experimental_map_key)
-  return *experimental_map_key_;
-}
-inline void FieldOptions::set_experimental_map_key(const ::std::string& value) {
-  set_has_experimental_map_key();
-  if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    experimental_map_key_ = new ::std::string;
-  }
-  experimental_map_key_->assign(value);
-  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.experimental_map_key)
-}
-inline void FieldOptions::set_experimental_map_key(const char* value) {
-  set_has_experimental_map_key();
-  if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    experimental_map_key_ = new ::std::string;
-  }
-  experimental_map_key_->assign(value);
-  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldOptions.experimental_map_key)
-}
-inline void FieldOptions::set_experimental_map_key(const char* value, size_t size) {
-  set_has_experimental_map_key();
-  if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    experimental_map_key_ = new ::std::string;
-  }
-  experimental_map_key_->assign(reinterpret_cast<const char*>(value), size);
-  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldOptions.experimental_map_key)
-}
-inline ::std::string* FieldOptions::mutable_experimental_map_key() {
-  set_has_experimental_map_key();
-  if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    experimental_map_key_ = new ::std::string;
-  }
-  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.experimental_map_key)
-  return experimental_map_key_;
-}
-inline ::std::string* FieldOptions::release_experimental_map_key() {
-  clear_has_experimental_map_key();
-  if (experimental_map_key_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = experimental_map_key_;
-    experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
-}
-inline void FieldOptions::set_allocated_experimental_map_key(::std::string* experimental_map_key) {
-  if (experimental_map_key_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete experimental_map_key_;
-  }
-  if (experimental_map_key) {
-    set_has_experimental_map_key();
-    experimental_map_key_ = experimental_map_key;
-  } else {
-    clear_has_experimental_map_key();
-    experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  }
-  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldOptions.experimental_map_key)
-}
-
 // optional bool weak = 10 [default = false];
 inline bool FieldOptions::has_weak() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
@@ -5800,16 +6574,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-FieldOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 FieldOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+FieldOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5882,16 +6656,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-EnumOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 EnumOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5940,16 +6714,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-EnumValueOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 EnumValueOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+EnumValueOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -5998,16 +6772,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-ServiceOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 ServiceOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+ServiceOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -6056,16 +6830,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option)
   return uninterpreted_option_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
-MethodOptions::uninterpreted_option() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
-  return uninterpreted_option_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
 MethodOptions::mutable_uninterpreted_option() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option)
   return &uninterpreted_option_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+MethodOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
 
 // -------------------------------------------------------------------
 
@@ -6082,68 +6856,46 @@
   _has_bits_[0] &= ~0x00000001u;
 }
 inline void UninterpretedOption_NamePart::clear_name_part() {
-  if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_part_->clear();
-  }
+  name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name_part();
 }
 inline const ::std::string& UninterpretedOption_NamePart::name_part() const {
   // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.NamePart.name_part)
-  return *name_part_;
+  return name_part_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) {
   set_has_name_part();
-  if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_part_ = new ::std::string;
-  }
-  name_part_->assign(value);
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.NamePart.name_part)
 }
 inline void UninterpretedOption_NamePart::set_name_part(const char* value) {
   set_has_name_part();
-  if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_part_ = new ::std::string;
-  }
-  name_part_->assign(value);
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.NamePart.name_part)
 }
 inline void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) {
   set_has_name_part();
-  if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_part_ = new ::std::string;
-  }
-  name_part_->assign(reinterpret_cast<const char*>(value), size);
+  name_part_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.NamePart.name_part)
 }
 inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() {
   set_has_name_part();
-  if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    name_part_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.NamePart.name_part)
-  return name_part_;
+  return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* UninterpretedOption_NamePart::release_name_part() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part)
   clear_has_name_part();
-  if (name_part_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = name_part_;
-    name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) {
-  if (name_part_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete name_part_;
-  }
-  if (name_part) {
+  if (name_part != NULL) {
     set_has_name_part();
-    name_part_ = name_part;
   } else {
     clear_has_name_part();
-    name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  name_part_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name_part);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.NamePart.name_part)
 }
 
@@ -6194,16 +6946,16 @@
   // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name)
   return name_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
-UninterpretedOption::name() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
-  return name_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >*
 UninterpretedOption::mutable_name() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name)
   return &name_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >&
+UninterpretedOption::name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name)
+  return name_;
+}
 
 // optional string identifier_value = 3;
 inline bool UninterpretedOption::has_identifier_value() const {
@@ -6216,68 +6968,46 @@
   _has_bits_[0] &= ~0x00000002u;
 }
 inline void UninterpretedOption::clear_identifier_value() {
-  if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    identifier_value_->clear();
-  }
+  identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_identifier_value();
 }
 inline const ::std::string& UninterpretedOption::identifier_value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.identifier_value)
-  return *identifier_value_;
+  return identifier_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_identifier_value(const ::std::string& value) {
   set_has_identifier_value();
-  if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    identifier_value_ = new ::std::string;
-  }
-  identifier_value_->assign(value);
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.identifier_value)
 }
 inline void UninterpretedOption::set_identifier_value(const char* value) {
   set_has_identifier_value();
-  if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    identifier_value_ = new ::std::string;
-  }
-  identifier_value_->assign(value);
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.identifier_value)
 }
 inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) {
   set_has_identifier_value();
-  if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    identifier_value_ = new ::std::string;
-  }
-  identifier_value_->assign(reinterpret_cast<const char*>(value), size);
+  identifier_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.identifier_value)
 }
 inline ::std::string* UninterpretedOption::mutable_identifier_value() {
   set_has_identifier_value();
-  if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    identifier_value_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.identifier_value)
-  return identifier_value_;
+  return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* UninterpretedOption::release_identifier_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value)
   clear_has_identifier_value();
-  if (identifier_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = identifier_value_;
-    identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) {
-  if (identifier_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete identifier_value_;
-  }
-  if (identifier_value) {
+  if (identifier_value != NULL) {
     set_has_identifier_value();
-    identifier_value_ = identifier_value;
   } else {
     clear_has_identifier_value();
-    identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  identifier_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), identifier_value);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.identifier_value)
 }
 
@@ -6364,68 +7094,46 @@
   _has_bits_[0] &= ~0x00000020u;
 }
 inline void UninterpretedOption::clear_string_value() {
-  if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    string_value_->clear();
-  }
+  string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_string_value();
 }
 inline const ::std::string& UninterpretedOption::string_value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.string_value)
-  return *string_value_;
+  return string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_string_value(const ::std::string& value) {
   set_has_string_value();
-  if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    string_value_ = new ::std::string;
-  }
-  string_value_->assign(value);
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.string_value)
 }
 inline void UninterpretedOption::set_string_value(const char* value) {
   set_has_string_value();
-  if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    string_value_ = new ::std::string;
-  }
-  string_value_->assign(value);
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.string_value)
 }
 inline void UninterpretedOption::set_string_value(const void* value, size_t size) {
   set_has_string_value();
-  if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    string_value_ = new ::std::string;
-  }
-  string_value_->assign(reinterpret_cast<const char*>(value), size);
+  string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.string_value)
 }
 inline ::std::string* UninterpretedOption::mutable_string_value() {
   set_has_string_value();
-  if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    string_value_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.string_value)
-  return string_value_;
+  return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* UninterpretedOption::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value)
   clear_has_string_value();
-  if (string_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = string_value_;
-    string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_allocated_string_value(::std::string* string_value) {
-  if (string_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete string_value_;
-  }
-  if (string_value) {
+  if (string_value != NULL) {
     set_has_string_value();
-    string_value_ = string_value;
   } else {
     clear_has_string_value();
-    string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), string_value);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.string_value)
 }
 
@@ -6440,68 +7148,46 @@
   _has_bits_[0] &= ~0x00000040u;
 }
 inline void UninterpretedOption::clear_aggregate_value() {
-  if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    aggregate_value_->clear();
-  }
+  aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_aggregate_value();
 }
 inline const ::std::string& UninterpretedOption::aggregate_value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.aggregate_value)
-  return *aggregate_value_;
+  return aggregate_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_aggregate_value(const ::std::string& value) {
   set_has_aggregate_value();
-  if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    aggregate_value_ = new ::std::string;
-  }
-  aggregate_value_->assign(value);
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.UninterpretedOption.aggregate_value)
 }
 inline void UninterpretedOption::set_aggregate_value(const char* value) {
   set_has_aggregate_value();
-  if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    aggregate_value_ = new ::std::string;
-  }
-  aggregate_value_->assign(value);
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.UninterpretedOption.aggregate_value)
 }
 inline void UninterpretedOption::set_aggregate_value(const char* value, size_t size) {
   set_has_aggregate_value();
-  if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    aggregate_value_ = new ::std::string;
-  }
-  aggregate_value_->assign(reinterpret_cast<const char*>(value), size);
+  aggregate_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.UninterpretedOption.aggregate_value)
 }
 inline ::std::string* UninterpretedOption::mutable_aggregate_value() {
   set_has_aggregate_value();
-  if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    aggregate_value_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.aggregate_value)
-  return aggregate_value_;
+  return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* UninterpretedOption::release_aggregate_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value)
   clear_has_aggregate_value();
-  if (aggregate_value_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = aggregate_value_;
-    aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) {
-  if (aggregate_value_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete aggregate_value_;
-  }
-  if (aggregate_value) {
+  if (aggregate_value != NULL) {
     set_has_aggregate_value();
-    aggregate_value_ = aggregate_value;
   } else {
     clear_has_aggregate_value();
-    aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  aggregate_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), aggregate_value);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.UninterpretedOption.aggregate_value)
 }
 
@@ -6580,68 +7266,46 @@
   _has_bits_[0] &= ~0x00000004u;
 }
 inline void SourceCodeInfo_Location::clear_leading_comments() {
-  if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    leading_comments_->clear();
-  }
+  leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_leading_comments();
 }
 inline const ::std::string& SourceCodeInfo_Location::leading_comments() const {
   // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_comments)
-  return *leading_comments_;
+  return leading_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) {
   set_has_leading_comments();
-  if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    leading_comments_ = new ::std::string;
-  }
-  leading_comments_->assign(value);
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_comments)
 }
 inline void SourceCodeInfo_Location::set_leading_comments(const char* value) {
   set_has_leading_comments();
-  if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    leading_comments_ = new ::std::string;
-  }
-  leading_comments_->assign(value);
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_comments)
 }
 inline void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) {
   set_has_leading_comments();
-  if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    leading_comments_ = new ::std::string;
-  }
-  leading_comments_->assign(reinterpret_cast<const char*>(value), size);
+  leading_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_comments)
 }
 inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() {
   set_has_leading_comments();
-  if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    leading_comments_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_comments)
-  return leading_comments_;
+  return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* SourceCodeInfo_Location::release_leading_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments)
   clear_has_leading_comments();
-  if (leading_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = leading_comments_;
-    leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) {
-  if (leading_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete leading_comments_;
-  }
-  if (leading_comments) {
+  if (leading_comments != NULL) {
     set_has_leading_comments();
-    leading_comments_ = leading_comments;
   } else {
     clear_has_leading_comments();
-    leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  leading_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), leading_comments);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.leading_comments)
 }
 
@@ -6656,71 +7320,104 @@
   _has_bits_[0] &= ~0x00000008u;
 }
 inline void SourceCodeInfo_Location::clear_trailing_comments() {
-  if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    trailing_comments_->clear();
-  }
+  trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_trailing_comments();
 }
 inline const ::std::string& SourceCodeInfo_Location::trailing_comments() const {
   // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.trailing_comments)
-  return *trailing_comments_;
+  return trailing_comments_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) {
   set_has_trailing_comments();
-  if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    trailing_comments_ = new ::std::string;
-  }
-  trailing_comments_->assign(value);
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
   // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.trailing_comments)
 }
 inline void SourceCodeInfo_Location::set_trailing_comments(const char* value) {
   set_has_trailing_comments();
-  if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    trailing_comments_ = new ::std::string;
-  }
-  trailing_comments_->assign(value);
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
   // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.trailing_comments)
 }
 inline void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) {
   set_has_trailing_comments();
-  if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    trailing_comments_ = new ::std::string;
-  }
-  trailing_comments_->assign(reinterpret_cast<const char*>(value), size);
+  trailing_comments_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.trailing_comments)
 }
 inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() {
   set_has_trailing_comments();
-  if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    trailing_comments_ = new ::std::string;
-  }
   // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.trailing_comments)
-  return trailing_comments_;
+  return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments)
   clear_has_trailing_comments();
-  if (trailing_comments_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    return NULL;
-  } else {
-    ::std::string* temp = trailing_comments_;
-    trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-    return temp;
-  }
+  return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) {
-  if (trailing_comments_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
-    delete trailing_comments_;
-  }
-  if (trailing_comments) {
+  if (trailing_comments != NULL) {
     set_has_trailing_comments();
-    trailing_comments_ = trailing_comments;
   } else {
     clear_has_trailing_comments();
-    trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   }
+  trailing_comments_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), trailing_comments);
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceCodeInfo.Location.trailing_comments)
 }
 
+// repeated string leading_detached_comments = 6;
+inline int SourceCodeInfo_Location::leading_detached_comments_size() const {
+  return leading_detached_comments_.size();
+}
+inline void SourceCodeInfo_Location::clear_leading_detached_comments() {
+  leading_detached_comments_.Clear();
+}
+inline const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Get(index);
+}
+inline ::std::string* SourceCodeInfo_Location::mutable_leading_detached_comments(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Mutable(index);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  leading_detached_comments_.Mutable(index)->assign(value);
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value) {
+  leading_detached_comments_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, const char* value, size_t size) {
+  leading_detached_comments_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_.Add();
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) {
+  leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value) {
+  leading_detached_comments_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline void SourceCodeInfo_Location::add_leading_detached_comments(const char* value, size_t size) {
+  leading_detached_comments_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SourceCodeInfo_Location::leading_detached_comments() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return leading_detached_comments_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+SourceCodeInfo_Location::mutable_leading_detached_comments() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.Location.leading_detached_comments)
+  return &leading_detached_comments_;
+}
+
 // -------------------------------------------------------------------
 
 // SourceCodeInfo
@@ -6744,16 +7441,233 @@
   // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location)
   return location_.Add();
 }
-inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
-SourceCodeInfo::location() const {
-  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
-  return location_;
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >*
 SourceCodeInfo::mutable_location() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location)
   return &location_;
 }
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >&
+SourceCodeInfo::location() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location)
+  return location_;
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+inline int GeneratedCodeInfo_Annotation::path_size() const {
+  return path_.size();
+}
+inline void GeneratedCodeInfo_Annotation::clear_path() {
+  path_.Clear();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_.Get(index);
+}
+inline void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) {
+  path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) {
+  path_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return &path_;
+}
+
+// optional string source_file = 2;
+inline bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_source_file() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_source_file() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_source_file() {
+  source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source_file();
+}
+inline const ::std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  set_has_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  clear_has_source_file();
+  return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) {
+  if (source_file != NULL) {
+    set_has_source_file();
+  } else {
+    clear_has_source_file();
+  }
+  source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+inline bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_begin() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_begin() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_begin() {
+  begin_ = 0;
+  clear_has_begin();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return begin_;
+}
+inline void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) {
+  set_has_begin();
+  begin_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+inline bool GeneratedCodeInfo_Annotation::has_end() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_end() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_end() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return end_;
+}
+inline void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+inline int GeneratedCodeInfo::annotation_size() const {
+  return annotation_.size();
+}
+inline void GeneratedCodeInfo::clear_annotation() {
+  annotation_.Clear();
+}
+inline const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Get(index);
+}
+inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Mutable(index);
+}
+inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &annotation_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_;
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
 
 
 // @@protoc_insertion_point(namespace_scope)
@@ -6785,9 +7699,14 @@
 inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() {
   return ::google::protobuf::FieldOptions_CType_descriptor();
 }
+template <> struct is_proto_enum< ::google::protobuf::FieldOptions_JSType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_JSType>() {
+  return ::google::protobuf::FieldOptions_JSType_descriptor();
+}
 
-}  // namespace google
 }  // namespace protobuf
+}  // namespace google
 #endif  // SWIG
 
 // @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index eb8fe28..08b1555 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -37,10 +37,14 @@
 // without any other information (e.g. without reading its imports).
 
 
+syntax = "proto2";
 
 package google.protobuf;
+option go_package = "descriptor";
 option java_package = "com.google.protobuf";
 option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
 
 // descriptor.proto must be optimized for speed because reflection-based
 // algorithms don't work during bootstrapping.
@@ -74,10 +78,14 @@
   optional FileOptions options = 8;
 
   // This field contains optional information about the original source code.
-  // You may safely remove this entire field whithout harming runtime
+  // You may safely remove this entire field without harming runtime
   // functionality of the descriptors -- the information is needed only by
   // development tools.
   optional SourceCodeInfo source_code_info = 9;
+
+  // The syntax of the proto file.
+  // The supported values are "proto2" and "proto3".
+  optional string syntax = 12;
 }
 
 // Describes a message type.
@@ -99,6 +107,18 @@
   repeated OneofDescriptorProto oneof_decl = 8;
 
   optional MessageOptions options = 7;
+
+  // Range of reserved tag numbers. Reserved tag numbers may not be used by
+  // fields or extension ranges in the same message. Reserved ranges may
+  // not overlap.
+  message ReservedRange {
+    optional int32 start = 1; // Inclusive.
+    optional int32 end = 2;   // Exclusive.
+  }
+  repeated ReservedRange reserved_range = 9;
+  // Reserved field names, which may not be used by fields in the same message.
+  // A given name may only be reserved once.
+  repeated string reserved_name = 10;
 }
 
 // Describes a field within a message.
@@ -167,11 +187,15 @@
   optional string default_value = 7;
 
   // If set, gives the index of a oneof in the containing type's oneof_decl
-  // list.  This field is a member of that oneof.  Extensions of a oneof should
-  // not set this since the oneof to which they belong will be inferred based
-  // on the extension range containing the extension's field number.
+  // list.  This field is a member of that oneof.
   optional int32 oneof_index = 9;
 
+  // JSON name of this field. The value is set by protocol compiler. If the
+  // user has set a "json_name" option on this field, that option's value
+  // will be used. Otherwise, it's deduced from the field's name by converting
+  // it to camelCase.
+  optional string json_name = 10;
+
   optional FieldOptions options = 8;
 }
 
@@ -215,6 +239,11 @@
   optional string output_type = 3;
 
   optional MethodOptions options = 4;
+
+  // Identifies if client streams multiple client messages
+  optional bool client_streaming = 5 [default=false];
+  // Identifies if server streams multiple server messages
+  optional bool server_streaming = 6 [default=false];
 }
 
 
@@ -241,11 +270,11 @@
 // * For options which will be published and used publicly by multiple
 //   independent entities, e-mail protobuf-global-extension-registry@google.com
 //   to reserve extension numbers. Simply provide your project name (e.g.
-//   Object-C plugin) and your porject website (if available) -- there's no need
-//   to explain how you intend to use them. Usually you only need one extension
-//   number. You can declare multiple options with only one extension number by
-//   putting them in a sub-message. See the Custom Options section of the docs
-//   for examples:
+//   Objective-C plugin) and your project website (if available) -- there's no
+//   need to explain how you intend to use them. Usually you only need one
+//   extension number. You can declare multiple options with only one extension
+//   number by putting them in a sub-message. See the Custom Options section of
+//   the docs for examples:
 //   https://developers.google.com/protocol-buffers/docs/proto#options
 //   If this turns out to be popular, a web service will be set up
 //   to automatically assign option numbers.
@@ -277,10 +306,12 @@
 
   // If set true, then the Java code generator will generate equals() and
   // hashCode() methods for all messages defined in the .proto file.
-  // - In the full runtime, this is purely a speed optimization, as the
+  // This increases generated code size, potentially substantially for large
+  // protos, which may harm a memory-constrained application.
+  // - In the full runtime this is a speed optimization, as the
   // AbstractMessage base class includes reflection-based implementations of
   // these methods.
-  //- In the lite runtime, setting this option changes the semantics of
+  // - In the lite runtime, setting this option changes the semantics of
   // equals() and hashCode() to more closely match those of the full runtime;
   // the generated methods compute their results based on field values rather
   // than object identity. (Implementations should not assume that hashcodes
@@ -306,7 +337,10 @@
   optional OptimizeMode optimize_for = 9 [default=SPEED];
 
   // Sets the Go package where structs generated from this .proto will be
-  // placed.  There is no default.
+  // placed. If omitted, the Go package will be derived from the following:
+  //   - The basename of the package import path, if provided.
+  //   - Otherwise, the package statement in the .proto file, if present.
+  //   - Otherwise, the basename of the .proto file, without extension.
   optional string go_package = 11;
 
 
@@ -315,7 +349,7 @@
   // are not specific to any particular RPC system.  They are generated by the
   // main code generators in each language (without additional plugins).
   // Generic services were the only kind of service generation supported by
-  // early versions of proto2.
+  // early versions of google.protobuf.
   //
   // Generic services are now considered deprecated in favor of using plugins
   // that generate code specific to your particular RPC system.  Therefore,
@@ -331,15 +365,25 @@
   // least, this is a formalization for deprecating files.
   optional bool deprecated = 23 [default=false];
 
-  // Whether the nano proto compiler should generate in the deprecated non-nano
-  // suffixed package.
-  optional bool javanano_use_deprecated_package = 38;
+  // Enables the use of arenas for the proto messages in this file. This applies
+  // only to generated classes for C++.
+  optional bool cc_enable_arenas = 31 [default=false];
+
+
+  // Sets the objective c class prefix which is prepended to all objective c
+  // generated classes from this .proto. There is no default.
+  optional string objc_class_prefix = 36;
+
+  // Namespace for generated classes; defaults to the package.
+  optional string csharp_namespace = 37;
 
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
   // Clients can define custom options in extensions of this message. See above.
   extensions 1000 to max;
+
+  reserved 38;
 }
 
 message MessageOptions {
@@ -374,6 +418,29 @@
   // this is a formalization for deprecating messages.
   optional bool deprecated = 3 [default=false];
 
+  // Whether the message is an automatically generated map entry type for the
+  // maps field.
+  //
+  // For maps fields:
+  //     map<KeyType, ValueType> map_field = 1;
+  // The parsed descriptor looks like:
+  //     message MapFieldEntry {
+  //         option map_entry = true;
+  //         optional KeyType key = 1;
+  //         optional ValueType value = 2;
+  //     }
+  //     repeated MapFieldEntry map_field = 1;
+  //
+  // Implementations may choose not to generate the map_entry=true message, but
+  // use a native map in the target language to hold the keys and values.
+  // The reflection APIs in such implementions still need to work as
+  // if the field is a repeated message field.
+  //
+  // NOTE: Do not set the option in .proto files. Always use the maps syntax
+  // instead. The option should only be implicitly set by the proto compiler
+  // parser.
+  optional bool map_entry = 7;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -398,10 +465,31 @@
   // The packed option can be enabled for repeated primitive fields to enable
   // a more efficient representation on the wire. Rather than repeatedly
   // writing the tag and type for each element, the entire array is encoded as
-  // a single length-delimited blob.
+  // a single length-delimited blob. In proto3, only explicit setting it to
+  // false will avoid using packed encoding.
   optional bool packed = 2;
 
 
+  // The jstype option determines the JavaScript type used for values of the
+  // field.  The option is permitted only for 64 bit integral and fixed types
+  // (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+  // represented as JavaScript strings.  This avoids loss of precision that can
+  // happen when a large value is converted to a floating point JavaScript
+  // numbers.  Specifying JS_NUMBER for the jstype causes the generated
+  // JavaScript code to use the JavaScript "number" type instead of strings.
+  // This option is an enum to permit additional types to be added,
+  // e.g. goog.math.Integer.
+  optional JSType jstype = 6 [default = JS_NORMAL];
+  enum JSType {
+    // Use the default type.
+    JS_NORMAL = 0;
+
+    // Use JavaScript strings.
+    JS_STRING = 1;
+
+    // Use JavaScript numbers.
+    JS_NUMBER = 2;
+  }
 
   // Should this field be parsed lazily?  Lazy applies only to message-type
   // fields.  It means that when the outer message is initially parsed, the
@@ -439,25 +527,10 @@
   // is a formalization for deprecating fields.
   optional bool deprecated = 3 [default=false];
 
-  // EXPERIMENTAL.  DO NOT USE.
-  // For "map" fields, the name of the field in the enclosed type that
-  // is the key for this map.  For example, suppose we have:
-  //   message Item {
-  //     required string name = 1;
-  //     required string value = 2;
-  //   }
-  //   message Config {
-  //     repeated Item items = 1 [experimental_map_key="name"];
-  //   }
-  // In this situation, the map key for Item will be set to "name".
-  // TODO: Fully-implement this, then remove the "experimental_" prefix.
-  optional string experimental_map_key = 9;
-
   // For Google-internal migration only. Do not use.
   optional bool weak = 10 [default=false];
 
 
-
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -657,6 +730,11 @@
     // A series of line comments appearing on consecutive lines, with no other
     // tokens appearing on those lines, will be treated as a single comment.
     //
+    // leading_detached_comments will keep paragraphs of comments that appear
+    // before (but not connected to) the current element. Each paragraph,
+    // separated by empty lines, will be one comment element in the repeated
+    // field.
+    //
     // Only the comment content is provided; comment markers (e.g. //) are
     // stripped out.  For block comments, leading whitespace and an asterisk
     // will be stripped from the beginning of each line other than the first.
@@ -677,6 +755,12 @@
     //   // Another line attached to qux.
     //   optional double qux = 4;
     //
+    //   // Detached comment for corge. This is not leading or trailing comments
+    //   // to qux or corge because there are blank lines separating it from
+    //   // both.
+    //
+    //   // Detached comment for corge paragraph 2.
+    //
     //   optional string corge = 5;
     //   /* Block comment attached
     //    * to corge.  Leading asterisks
@@ -684,7 +768,36 @@
     //   /* Block comment attached to
     //    * grault. */
     //   optional int32 grault = 6;
+    //
+    //   // ignored detached comments.
     optional string leading_comments = 3;
     optional string trailing_comments = 4;
+    repeated string leading_detached_comments = 6;
+  }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+  // An Annotation connects some span of text in generated code to an element
+  // of its generating .proto file.
+  repeated Annotation annotation = 1;
+  message Annotation {
+    // Identifies the element in the original source .proto file. This field
+    // is formatted the same as SourceCodeInfo.Location.path.
+    repeated int32 path = 1 [packed=true];
+
+    // Identifies the filesystem path to the original source .proto.
+    optional string source_file = 2;
+
+    // Identifies the starting offset in bytes in the generated code
+    // that relates to the identified object.
+    optional int32 begin = 3;
+
+    // Identifies the ending offset in bytes in the generated code that
+    // relates to the identified offset. The end offset should be one past
+    // the last relevant byte (so the length of the text = end - begin).
+    optional int32 end = 4;
   }
 }
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
index d024eab..2117c02 100644
--- a/src/google/protobuf/descriptor_database.cc
+++ b/src/google/protobuf/descriptor_database.cc
@@ -153,10 +153,10 @@
   if (!field.extendee().empty() && field.extendee()[0] == '.') {
     // The extension is fully-qualified.  We can use it as a lookup key in
     // the by_symbol_ table.
-    if (!InsertIfNotPresent(&by_extension_,
-                            make_pair(field.extendee().substr(1),
-                                      field.number()),
-                            value)) {
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            std::make_pair(field.extendee().substr(1), field.number()),
+            value)) {
       GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
                     "extend " << field.extendee() << " { "
                  << field.name() << " = " << field.number() << " }";
@@ -189,17 +189,16 @@
 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
     const string& containing_type,
     int field_number) {
-  return FindWithDefault(by_extension_,
-                         make_pair(containing_type, field_number),
-                         Value());
+  return FindWithDefault(
+      by_extension_, std::make_pair(containing_type, field_number), Value());
 }
 
 template <typename Value>
 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
     const string& containing_type,
     vector<int>* output) {
-  typename map<pair<string, int>, Value >::const_iterator it =
-      by_extension_.lower_bound(make_pair(containing_type, 0));
+  typename map<pair<string, int>, Value>::const_iterator it =
+      by_extension_.lower_bound(std::make_pair(containing_type, 0));
   bool success = false;
 
   for (; it != by_extension_.end() && it->first.first == containing_type;
@@ -310,7 +309,7 @@
     const void* encoded_file_descriptor, int size) {
   FileDescriptorProto file;
   if (file.ParseFromArray(encoded_file_descriptor, size)) {
-    return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
+    return index_.AddFile(file, std::make_pair(encoded_file_descriptor, size));
   } else {
     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
                   "EncodedDescriptorDatabase::Add().";
@@ -525,15 +524,16 @@
 
   for (int i = 0; i < sources_.size(); i++) {
     if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
-      copy(results.begin(), results.end(),
-           insert_iterator<set<int> >(merged_results, merged_results.begin()));
+      std::copy(
+          results.begin(), results.end(),
+          insert_iterator<set<int> >(merged_results, merged_results.begin()));
       success = true;
     }
     results.clear();
   }
 
-  copy(merged_results.begin(), merged_results.end(),
-       insert_iterator<vector<int> >(*output, output->end()));
+  std::copy(merged_results.begin(), merged_results.end(),
+            insert_iterator<vector<int> >(*output, output->end()));
 
   return success;
 }
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index 934e402..86002d5 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -312,7 +312,7 @@
 // A DescriptorDatabase that fetches files from a given pool.
 class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
  public:
-  DescriptorPoolDatabase(const DescriptorPool& pool);
+  explicit DescriptorPoolDatabase(const DescriptorPool& pool);
   ~DescriptorPoolDatabase();
 
   // implements DescriptorDatabase -----------------------------------
@@ -341,7 +341,7 @@
   // Merge more than two databases.  The sources remain property of the caller.
   // The vector may be deleted after the constructor returns but the
   // DescriptorDatabases need to stick around.
-  MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
+  explicit MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
   ~MergedDescriptorDatabase();
 
   // implements DescriptorDatabase -----------------------------------
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index 6642d71..1fc3816 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -35,6 +35,10 @@
 // This file makes extensive use of RFC 3092.  :)
 
 #include <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/descriptor_database.h>
 #include <google/protobuf/descriptor.h>
@@ -42,7 +46,9 @@
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -175,7 +181,7 @@
     EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
   }
 
-  scoped_ptr<DescriptorDatabaseTestCase> test_case_;
+  google::protobuf::scoped_ptr<DescriptorDatabaseTestCase> test_case_;
   DescriptorDatabase* database_;
 };
 
@@ -408,7 +414,7 @@
     vector<int> numbers;
     EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(5, numbers[0]);
     EXPECT_EQ(32, numbers[1]);
   }
@@ -722,7 +728,7 @@
     vector<int> numbers;
     EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(13, numbers[1]);
   }
@@ -731,7 +737,7 @@
     vector<int> numbers;
     EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(13, numbers[1]);
   }
diff --git a/src/google/protobuf/descriptor_pb2_test.py b/src/google/protobuf/descriptor_pb2_test.py
deleted file mode 100644
index 48a0d48..0000000
--- a/src/google/protobuf/descriptor_pb2_test.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#! /usr/bin/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.
-
-# Verify that prebuild and checkedin version of descriptor_pb2.py is up to date.
-
-from google3.pyglib import resources
-import unittest
-
-_DESC = 'google3/net/proto2/proto/descriptor_pb2.'
-_OLD = _DESC + 'py-prebuilt'
-_NEW = _DESC + 'compiled'
-
-
-class PregeneratedFileChanged(unittest.TestCase):
-
-  def testSameText(self):
-    generated = resources.GetResource(_NEW)
-    checkedin = resources.GetResource(_OLD)
-    self.assertMultiLineEqual(
-        generated, checkedin, 'It seems that protoc _pb2 generator changed. '
-        'Please run google/protobuf/generate_descriptor_proto.sh to '
-        'regnerate a new version of %s and add it to your CL' % _OLD)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index ac96160..f937b9e 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -34,6 +34,10 @@
 //
 // This file makes extensive use of RFC 3092.  :)
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/compiler/importer.h>
@@ -49,6 +53,9 @@
 #include <google/protobuf/stubs/substitute.h>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -139,6 +146,14 @@
   return result;
 }
 
+DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent,
+                                                 int start, int end) {
+  DescriptorProto::ReservedRange* result = parent->add_reserved_range();
+  result->set_start(start);
+  result->set_end(end);
+  return result;
+}
+
 EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
                                        const string& name, int number) {
   EnumValueDescriptorProto* result = enum_proto->add_value();
@@ -164,6 +179,61 @@
   AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
 }
 
+class MockErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() {}
+
+  string text_;
+  string warning_text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const string& filename,
+                const string& element_name, const Message* descriptor,
+                ErrorLocation location, const string& message) {
+    const char* location_name = NULL;
+    switch (location) {
+      case NAME         : location_name = "NAME"         ; break;
+      case NUMBER       : location_name = "NUMBER"       ; break;
+      case TYPE         : location_name = "TYPE"         ; break;
+      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
+      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
+      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
+      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
+      case OTHER        : location_name = "OTHER"        ; break;
+    }
+
+    strings::SubstituteAndAppend(
+      &text_, "$0: $1: $2: $3\n",
+      filename, element_name, location_name, message);
+  }
+
+  // implements ErrorCollector ---------------------------------------
+  void AddWarning(const string& filename, const string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const string& message) {
+    const char* location_name = NULL;
+    switch (location) {
+      case NAME         : location_name = "NAME"         ; break;
+      case NUMBER       : location_name = "NUMBER"       ; break;
+      case TYPE         : location_name = "TYPE"         ; break;
+      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
+      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
+      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
+      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
+      case OTHER        : location_name = "OTHER"        ; break;
+    }
+
+    strings::SubstituteAndAppend(
+      &warning_text_, "$0: $1: $2: $3\n",
+      filename, element_name, location_name, message);
+  }
+};
+
 // ===================================================================
 
 // Test simple files.
@@ -360,6 +430,65 @@
   EXPECT_TRUE(pool_.BuildFile(file) == NULL);
 }
 
+TEST_F(FileDescriptorTest, BuildAgainWithSyntax) {
+  // Test that if te call BuildFile again on the same input we get the same
+  // FileDescriptor back even if syntax param is specified.
+  FileDescriptorProto proto_syntax2;
+  proto_syntax2.set_name("foo_syntax2");
+  proto_syntax2.set_syntax("proto2");
+
+  const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2);
+  EXPECT_TRUE(proto2_descriptor != NULL);
+  EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2));
+
+  FileDescriptorProto implicit_proto2;
+  implicit_proto2.set_name("foo_implicit_syntax2");
+
+  const FileDescriptor* implicit_proto2_descriptor =
+      pool_.BuildFile(implicit_proto2);
+  EXPECT_TRUE(implicit_proto2_descriptor != NULL);
+  // We get the same FileDescriptor back if syntax param is explicitly
+  // specified.
+  implicit_proto2.set_syntax("proto2");
+  EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2));
+
+  FileDescriptorProto proto_syntax3;
+  proto_syntax3.set_name("foo_syntax3");
+  proto_syntax3.set_syntax("proto3");
+
+  const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3);
+  EXPECT_TRUE(proto3_descriptor != NULL);
+  EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3));
+}
+
+TEST_F(FileDescriptorTest, Syntax) {
+  FileDescriptorProto proto;
+  proto.set_name("foo");
+  // Enable the test when we also populate the syntax for proto2.
+#if 0
+  {
+    proto.set_syntax("proto2");
+    DescriptorPool pool;
+    const FileDescriptor* file = pool.BuildFile(proto);
+    EXPECT_TRUE(file != NULL);
+    EXPECT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax());
+    FileDescriptorProto other;
+    file->CopyTo(&other);
+    EXPECT_EQ("proto2", other.syntax());
+  }
+#endif
+  {
+    proto.set_syntax("proto3");
+    DescriptorPool pool;
+    const FileDescriptor* file = pool.BuildFile(proto);
+    EXPECT_TRUE(file != NULL);
+    EXPECT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax());
+    FileDescriptorProto other;
+    file->CopyTo(&other);
+    EXPECT_EQ("proto3", other.syntax());
+  }
+}
+
 // ===================================================================
 
 // Test simple flat messages and fields.
@@ -387,6 +516,21 @@
     //     required string quux = 6;
     //   }
     //
+    //   // in "map.proto"
+    //   message TestMessage3 {
+    //     map<int32, int32> map_int32_int32 = 1;
+    //   }
+    //
+    //   // in "json.proto"
+    //   message TestMessage4 {
+    //     optional int32 field_name1 = 1;
+    //     optional int32 fieldName2 = 2;
+    //     optional int32 FieldName3 = 3;
+    //     optional int32 _field_name4 = 4;
+    //     optional int32 FIELD_NAME5 = 5;
+    //     optional int32 field_name6 = 6 [json_name = "@type"];
+    //   }
+    //
     // We cheat and use TestForeign as the type for qux rather than create
     // an actual nested type.
     //
@@ -434,6 +578,48 @@
              FieldDescriptorProto::LABEL_REQUIRED,
              FieldDescriptorProto::TYPE_STRING);
 
+    FileDescriptorProto map_file;
+    map_file.set_name("map.proto");
+    DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3");
+
+    DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry");
+    AddField(entry, "key", 1,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(entry, "value", 2,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    entry->mutable_options()->set_map_entry(true);
+
+    AddField(message3, "map_int32_int32", 1,
+             FieldDescriptorProto::LABEL_REPEATED,
+             FieldDescriptorProto::TYPE_MESSAGE)
+        ->set_type_name("MapInt32Int32Entry");
+
+    FileDescriptorProto json_file;
+    json_file.set_name("json.proto");
+    json_file.set_syntax("proto3");
+    DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
+    AddField(message4, "field_name1", 1,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "fieldName2", 2,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FieldName3", 3,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "_field_name4", 4,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FIELD_NAME5", 5,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "field_name6", 6,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32)
+        ->set_json_name("@type");
+
     // Build the descriptors and get the pointers.
     foo_file_ = pool_.BuildFile(foo_file);
     ASSERT_TRUE(foo_file_ != NULL);
@@ -441,6 +627,12 @@
     bar_file_ = pool_.BuildFile(bar_file);
     ASSERT_TRUE(bar_file_ != NULL);
 
+    map_file_ = pool_.BuildFile(map_file);
+    ASSERT_TRUE(map_file_ != NULL);
+
+    json_file_ = pool_.BuildFile(json_file);
+    ASSERT_TRUE(json_file_ != NULL);
+
     ASSERT_EQ(1, foo_file_->enum_type_count());
     enum_ = foo_file_->enum_type(0);
 
@@ -461,15 +653,33 @@
     foo2_  = message2_->field(0);
     bar2_  = message2_->field(1);
     quux2_ = message2_->field(2);
+
+    ASSERT_EQ(1, map_file_->message_type_count());
+    message3_ = map_file_->message_type(0);
+
+    ASSERT_EQ(1, message3_->field_count());
+    map_  = message3_->field(0);
+
+    ASSERT_EQ(1, json_file_->message_type_count());
+    message4_ = json_file_->message_type(0);
+  }
+
+  void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
+    message->CopyTo(proto);
+    message->CopyJsonNameTo(proto);
   }
 
   DescriptorPool pool_;
 
   const FileDescriptor* foo_file_;
   const FileDescriptor* bar_file_;
+  const FileDescriptor* map_file_;
+  const FileDescriptor* json_file_;
 
   const Descriptor* message_;
   const Descriptor* message2_;
+  const Descriptor* message3_;
+  const Descriptor* message4_;
   const Descriptor* foreign_;
   const EnumDescriptor* enum_;
 
@@ -481,6 +691,8 @@
   const FieldDescriptor* foo2_;
   const FieldDescriptor* bar2_;
   const FieldDescriptor* quux2_;
+
+  const FieldDescriptor* map_;
 };
 
 TEST_F(DescriptorTest, Name) {
@@ -559,6 +771,35 @@
   EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name());
 }
 
+TEST_F(DescriptorTest, FieldJsonName) {
+  EXPECT_EQ("fieldName1", message4_->field(0)->json_name());
+  EXPECT_EQ("fieldName2", message4_->field(1)->json_name());
+  EXPECT_EQ("fieldName3", message4_->field(2)->json_name());
+  EXPECT_EQ("fieldName4", message4_->field(3)->json_name());
+  EXPECT_EQ("fIELDNAME5", message4_->field(4)->json_name());
+  EXPECT_EQ("@type", message4_->field(5)->json_name());
+
+  DescriptorProto proto;
+  message4_->CopyTo(&proto);
+  ASSERT_EQ(6, proto.field_size());
+  EXPECT_FALSE(proto.field(0).has_json_name());
+  EXPECT_FALSE(proto.field(1).has_json_name());
+  EXPECT_FALSE(proto.field(2).has_json_name());
+  EXPECT_FALSE(proto.field(3).has_json_name());
+  EXPECT_FALSE(proto.field(4).has_json_name());
+  EXPECT_EQ("@type", proto.field(5).json_name());
+
+  proto.Clear();
+  CopyWithJsonName(message4_, &proto);
+  ASSERT_EQ(6, proto.field_size());
+  EXPECT_EQ("fieldName1", proto.field(0).json_name());
+  EXPECT_EQ("fieldName2", proto.field(1).json_name());
+  EXPECT_EQ("fieldName3", proto.field(2).json_name());
+  EXPECT_EQ("fieldName4", proto.field(3).json_name());
+  EXPECT_EQ("fIELDNAME5", proto.field(4).json_name());
+  EXPECT_EQ("@type", proto.field(5).json_name());
+}
+
 TEST_F(DescriptorTest, FieldFile) {
   EXPECT_EQ(foo_file_, foo_->file());
   EXPECT_EQ(foo_file_, bar_->file());
@@ -610,6 +851,12 @@
   EXPECT_TRUE (baz_->is_repeated());
 }
 
+TEST_F(DescriptorTest, IsMap) {
+  EXPECT_TRUE(map_->is_map());
+  EXPECT_FALSE(baz_->is_map());
+  EXPECT_TRUE(map_->message_type()->options().map_entry());
+}
+
 TEST_F(DescriptorTest, FieldHasDefault) {
   EXPECT_FALSE(foo_->has_default_value());
   EXPECT_FALSE(bar_->has_default_value());
@@ -1650,6 +1897,84 @@
 
 // ===================================================================
 
+// Test reserved fields.
+class ReservedDescriptorTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Build descriptors for the following definitions:
+    //
+    //   message Foo {
+    //     reserved 2, 9 to 11, 15;
+    //     reserved "foo", "bar";
+    //   }
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+    AddReservedRange(foo, 2, 3);
+    AddReservedRange(foo, 9, 12);
+    AddReservedRange(foo, 15, 16);
+
+    foo->add_reserved_name("foo");
+    foo->add_reserved_name("bar");
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != NULL);
+
+    ASSERT_EQ(1, foo_file_->message_type_count());
+    foo_ = foo_file_->message_type(0);
+  }
+
+  DescriptorPool pool_;
+  const FileDescriptor* foo_file_;
+  const Descriptor* foo_;
+};
+
+TEST_F(ReservedDescriptorTest, ReservedRanges) {
+  ASSERT_EQ(3, foo_->reserved_range_count());
+
+  EXPECT_EQ(2, foo_->reserved_range(0)->start);
+  EXPECT_EQ(3, foo_->reserved_range(0)->end);
+
+  EXPECT_EQ(9, foo_->reserved_range(1)->start);
+  EXPECT_EQ(12, foo_->reserved_range(1)->end);
+
+  EXPECT_EQ(15, foo_->reserved_range(2)->start);
+  EXPECT_EQ(16, foo_->reserved_range(2)->end);
+};
+
+TEST_F(ReservedDescriptorTest, IsReservedNumber) {
+  EXPECT_FALSE(foo_->IsReservedNumber(1));
+  EXPECT_TRUE (foo_->IsReservedNumber(2));
+  EXPECT_FALSE(foo_->IsReservedNumber(3));
+  EXPECT_FALSE(foo_->IsReservedNumber(8));
+  EXPECT_TRUE (foo_->IsReservedNumber(9));
+  EXPECT_TRUE (foo_->IsReservedNumber(10));
+  EXPECT_TRUE (foo_->IsReservedNumber(11));
+  EXPECT_FALSE(foo_->IsReservedNumber(12));
+  EXPECT_FALSE(foo_->IsReservedNumber(13));
+  EXPECT_FALSE(foo_->IsReservedNumber(14));
+  EXPECT_TRUE (foo_->IsReservedNumber(15));
+  EXPECT_FALSE(foo_->IsReservedNumber(16));
+};
+
+TEST_F(ReservedDescriptorTest, ReservedNames) {
+  ASSERT_EQ(2, foo_->reserved_name_count());
+
+  EXPECT_EQ("foo", foo_->reserved_name(0));
+  EXPECT_EQ("bar", foo_->reserved_name(1));
+};
+
+TEST_F(ReservedDescriptorTest, IsReservedName) {
+  EXPECT_TRUE (foo_->IsReservedName("foo"));
+  EXPECT_TRUE (foo_->IsReservedName("bar"));
+  EXPECT_FALSE(foo_->IsReservedName("baz"));
+};
+
+// ===================================================================
+
 class MiscTest : public testing::Test {
  protected:
   // Function which makes a field descriptor of the given type.
@@ -1711,7 +2036,7 @@
     return field != NULL ? field->enum_type() : NULL;
   }
 
-  scoped_ptr<DescriptorPool> pool_;
+  google::protobuf::scoped_ptr<DescriptorPool> pool_;
 };
 
 TEST_F(MiscTest, TypeNames) {
@@ -2141,7 +2466,7 @@
   const FieldDescriptor* qux_field_;
 
   SimpleDescriptorDatabase db_;        // used if in FALLBACK_DATABASE mode.
-  scoped_ptr<DescriptorPool> pool_;
+  google::protobuf::scoped_ptr<DescriptorPool> pool_;
 };
 
 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
@@ -2157,6 +2482,12 @@
   // Placeholder files should not be findable.
   EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
   EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == NULL);
+
+  // Copy*To should not crash for placeholder files.
+  FileDescriptorProto baz_file_proto;
+  baz_file->CopyTo(&baz_file_proto);
+  baz_file->CopySourceCodeInfoTo(&baz_file_proto);
+  EXPECT_FALSE(baz_file_proto.has_source_code_info());
 }
 
 TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
@@ -2845,86 +3176,104 @@
       ->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
 
-
   pool.AddUnusedImportTrackFile("custom_options_import.proto");
   ASSERT_TRUE(TextFormat::ParseFromString(
     "name: \"custom_options_import.proto\" "
     "package: \"protobuf_unittest\" "
     "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
     &file_proto));
-  pool.BuildFile(file_proto);
+
+  MockErrorCollector error_collector;
+  EXPECT_TRUE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
+  EXPECT_EQ("", error_collector.warning_text_);
+}
+
+// Verifies that proto files can correctly be parsed, even if the
+// custom options defined in the file are incompatible with those
+// compiled in the binary. See http://b/19276250.
+TEST(CustomOptions, OptionsWithRequiredEnums) {
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  MessageOptions::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // Create a new file descriptor proto containing a subset of the
+  // messages defined in google/protobuf/unittest_custom_options.proto.
+  file_proto.Clear();
+  file_proto.set_name("unittest_custom_options.proto");
+  file_proto.set_package("protobuf_unittest");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+
+  // Add the "required_enum_opt" extension.
+  FieldDescriptorProto* extension = file_proto.add_extension();
+  protobuf_unittest::OldOptionType::descriptor()->file()
+      ->FindExtensionByName("required_enum_opt")->CopyTo(extension);
+
+  // Add a test message that uses the "required_enum_opt" option.
+  DescriptorProto* test_message_type = file_proto.add_message_type();
+  protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor()
+      ->CopyTo(test_message_type);
+
+  // Instruct the extension to use NewOptionType instead of
+  // OldOptionType, and add the descriptor of NewOptionType.
+  extension->set_type_name(".protobuf_unittest.NewOptionType");
+  DescriptorProto* new_option_type = file_proto.add_message_type();
+  protobuf_unittest::NewOptionType::descriptor()
+      ->CopyTo(new_option_type);
+
+  // Replace the value of the "required_enum_opt" option used in the
+  // test message with an enum value that only exists in NewOptionType.
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "uninterpreted_option { "
+      "  name { "
+      "    name_part: 'required_enum_opt' "
+      "    is_extension: true "
+      "  } "
+      "  aggregate_value: 'value: NEW_VALUE' "
+      "}",
+      test_message_type->mutable_options()));
+
+  // Add the file descriptor to the pool.
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // Find the test message.
+  const Descriptor* test_message = pool.FindMessageTypeByName(
+      "protobuf_unittest.TestMessageWithRequiredEnumOption");
+  ASSERT_TRUE(test_message != NULL);
+
+  const MessageOptions& options = test_message->options();
+  // Extract the "required_enum_opt" option. Since the binary does not
+  // know that the extension was updated, this will still return an
+  // OldOptionType message.
+  ASSERT_TRUE(
+      options.HasExtension(protobuf_unittest::required_enum_opt));
+  const protobuf_unittest::OldOptionType& old_enum_opt =
+      options.GetExtension(protobuf_unittest::required_enum_opt);
+
+  // Confirm that the required enum field is missing.
+  EXPECT_FALSE(old_enum_opt.IsInitialized());
+  EXPECT_FALSE(old_enum_opt.has_value());
+
+  string buf;
+  // Verify that the required enum field does show up when the option
+  // is re-parsed as a NewOptionType message;
+  protobuf_unittest::NewOptionType new_enum_opt;
+  EXPECT_TRUE(old_enum_opt.AppendPartialToString(&buf));
+  EXPECT_TRUE(new_enum_opt.ParseFromString(buf));
+  EXPECT_EQ(protobuf_unittest::NewOptionType::NEW_VALUE, new_enum_opt.value());
 }
 
 // ===================================================================
 
-// The tests below trigger every unique call to AddError() in descriptor.cc,
-// in the order in which they appear in that file.  I'm using TextFormat here
-// to specify the input descriptors because building them using code would
-// be too bulky.
-
-class MockErrorCollector : public DescriptorPool::ErrorCollector {
- public:
-  MockErrorCollector() {}
-  ~MockErrorCollector() {}
-
-  string text_;
-  string warning_text_;
-
-  // implements ErrorCollector ---------------------------------------
-  void AddError(const string& filename,
-                const string& element_name, const Message* descriptor,
-                ErrorLocation location, const string& message) {
-    const char* location_name = NULL;
-    switch (location) {
-      case NAME         : location_name = "NAME"         ; break;
-      case NUMBER       : location_name = "NUMBER"       ; break;
-      case TYPE         : location_name = "TYPE"         ; break;
-      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
-      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
-      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
-      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
-      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
-      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
-      case OTHER        : location_name = "OTHER"        ; break;
-    }
-
-    strings::SubstituteAndAppend(
-      &text_, "$0: $1: $2: $3\n",
-      filename, element_name, location_name, message);
-  }
-
-  // implements ErrorCollector ---------------------------------------
-  void AddWarning(const string& filename, const string& element_name,
-                  const Message* descriptor, ErrorLocation location,
-                  const string& message) {
-    const char* location_name = NULL;
-    switch (location) {
-      case NAME         : location_name = "NAME"         ; break;
-      case NUMBER       : location_name = "NUMBER"       ; break;
-      case TYPE         : location_name = "TYPE"         ; break;
-      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
-      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
-      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
-      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
-      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
-      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
-      case OTHER        : location_name = "OTHER"        ; break;
-    }
-
-    strings::SubstituteAndAppend(
-      &warning_text_, "$0: $1: $2: $3\n",
-      filename, element_name, location_name, message);
-  }
-};
-
 class ValidationErrorTest : public testing::Test {
  protected:
   // Parse file_text as a FileDescriptorProto in text format and add it
   // to the DescriptorPool.  Expect no errors.
-  void BuildFile(const string& file_text) {
+  const FileDescriptor* BuildFile(const string& file_text) {
     FileDescriptorProto file_proto;
-    ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
-    ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
+    EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+    return GOOGLE_CHECK_NOTNULL(pool_.BuildFile(file_proto));
   }
 
   // Parse file_text as a FileDescriptorProto in text format and add it
@@ -3175,6 +3524,102 @@
       "already-defined range 20 to 29.\n");
 }
 
+TEST_F(ValidationErrorTest, ReservedFieldError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  reserved_range { start: 10 end: 20 }"
+    "}",
+
+    "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedExtensionRangeError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  extension_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 15 }"
+    "}",
+
+    "foo.proto: Foo: NUMBER: Extension range 10 to 19"
+    " overlaps with reserved range 5 to 14.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) {
+  BuildFile(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  extension_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 10 }"
+    "}");
+}
+
+TEST_F(ValidationErrorTest, ReservedRangeOverlap) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 15 }"
+    "}",
+
+    "foo.proto: Foo: NUMBER: Reserved range 5 to 14"
+    " overlaps with already-defined range 10 to 19.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedNameError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "}",
+
+    "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n"
+    "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedNameRedundant) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"foo\""
+    "}",
+
+    "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedFieldsDebugString) {
+  const FileDescriptor* file = BuildFile(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "  reserved_range { start: 5 end: 6 }"
+    "  reserved_range { start: 10 end: 20 }"
+    "}");
+
+  ASSERT_EQ(
+    "syntax = \"proto2\";\n\n"
+    "message Foo {\n"
+    "  reserved 5, 10 to 19;\n"
+    "  reserved \"foo\", \"bar\";\n"
+    "}\n\n",
+    file->DebugString());
+}
+
 TEST_F(ValidationErrorTest, InvalidDefaults) {
   BuildFileWithErrors(
     "name: \"foo.proto\" "
@@ -3323,6 +3768,67 @@
       "range for type \"Foo\".\n");
 }
 
+TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) {
+  // Fields belonging to the same oneof must be defined consecutively.
+  BuildFileWithErrors(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  oneof_decl { name:\"foos\" }"
+      "}",
+
+      "foo.proto: Foo.bar: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"bar\" cannot be defined before the completion of the "
+      "\"foos\" oneof definition.\n");
+
+  // Prevent interleaved fields, which belong to different oneofs.
+  BuildFileWithErrors(
+      "name: \"foo2.proto\" "
+      "message_type {"
+      "  name: \"Foo2\""
+      "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  oneof_decl { name:\"foos\" }"
+      "  oneof_decl { name:\"bars\" }"
+      "}",
+      "foo2.proto: Foo2.bar1: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"bar1\" cannot be defined before the completion of the "
+      "\"foos\" oneof definition.\n"
+      "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"foo2\" cannot be defined before the completion of the "
+      "\"bars\" oneof definition.\n");
+
+  // Another case for normal fields and different oneof fields interleave.
+  BuildFileWithErrors(
+      "name: \"foo3.proto\" "
+      "message_type {"
+      "  name: \"Foo3\""
+      "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  oneof_decl { name:\"foos\" }"
+      "  oneof_decl { name:\"bars\" }"
+      "}",
+      "foo3.proto: Foo3.baz: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"baz\" cannot be defined before the completion of the "
+      "\"foos\" oneof definition.\n");
+}
+
 TEST_F(ValidationErrorTest, FieldNumberConflict) {
   BuildFileWithErrors(
     "name: \"foo.proto\" "
@@ -4691,7 +5197,6 @@
 }
 
 TEST_F(ValidationErrorTest, UnusedImportWarning) {
-
   pool_.AddUnusedImportTrackFile("bar.proto");
   BuildFile(
     "name: \"bar.proto\" "
@@ -4723,7 +5228,7 @@
   // }
   //
   pool_.AddUnusedImportTrackFile("forward.proto");
-  BuildFile(
+  BuildFileWithWarnings(
     "name: \"forward.proto\""
     "dependency: \"base.proto\""
     "dependency: \"bar.proto\""
@@ -4733,9 +5238,616 @@
     "message_type {"
     "  name: \"Forward\""
     "  field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }"
-    "}");
+    "}",
+    "forward.proto: bar.proto: OTHER: Import bar.proto but not used.\n");
 }
 
+namespace {
+void FillValidMapEntry(FileDescriptorProto* file_proto) {
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "name: 'foo.proto' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { "
+      "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
+      "    type_name: 'FooMapEntry' "
+      "  } "
+      "  nested_type { "
+      "    name: 'FooMapEntry' "
+      "    options {  map_entry: true } "
+      "    field { "
+      "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
+      "    } "
+      "    field { "
+      "      name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL "
+      "    } "
+      "  } "
+      "} "
+      "message_type { "
+      "  name: 'Bar' "
+      "  extension_range { start: 1 end: 10 }"
+      "} ",
+      file_proto));
+}
+static const char* kMapEntryErrorMessage =
+    "foo.proto: Foo.foo_map: OTHER: map_entry should not be set explicitly. "
+    "Use map<KeyType, ValueType> instead.\n";
+static const char* kMapEntryKeyTypeErrorMessage =
+    "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, "
+    "bytes or message types.\n";
+
+}  // namespace
+
+TEST_F(ValidationErrorTest, MapEntryBase) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  BuildFile(file_proto.DebugString());
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtensionRange) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "extension_range { "
+      "  start: 10 end: 20 "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtension) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "extension { "
+      "  name: 'foo_ext' extendee: '.Bar' number: 5"
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryNestedType) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "nested_type { "
+      "  name: 'Bar' "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryEnumTypes) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "enum_type { "
+      "  name: 'BarEnum' "
+      "  value { name: 'BAR_BAR' number:0 } "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryExtraField) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "field { "
+      "  name: 'other_field' "
+      "  label: LABEL_OPTIONAL "
+      "  type: TYPE_INT32 "
+      "  number: 3 "
+      "} ",
+      file_proto.mutable_message_type(0)->mutable_nested_type(0));
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryMessageName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name(
+      "OtherMapEntry");
+  file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name(
+      "OtherMapEntry");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  file_proto.mutable_message_type(0)->mutable_field(0)->set_label(
+      FieldDescriptorProto::LABEL_OPTIONAL);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  // Move the nested MapEntry message into the top level, which should not pass
+  // the validation.
+  file_proto.mutable_message_type()->AddAllocated(
+      file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast());
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_name("Key");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyLabel) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_label(FieldDescriptorProto::LABEL_REQUIRED);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyNumber) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_number(3);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueName) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(1);
+  value->set_name("Value");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueLabel) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(1);
+  value->set_label(FieldDescriptorProto::LABEL_REQUIRED);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryValueNumber) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* value = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(1);
+  value->set_number(3);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_type(FieldDescriptorProto::TYPE_FLOAT);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_type(FieldDescriptorProto::TYPE_DOUBLE);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->set_type(FieldDescriptorProto::TYPE_BYTES);
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->clear_type();
+  key->set_type_name("BarEnum");
+  EnumDescriptorProto* enum_proto = file_proto.add_enum_type();
+  enum_proto->set_name("BarEnum");
+  EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value();
+  enum_value_proto->set_name("BAR_VALUE0");
+  enum_value_proto->set_number(0);
+  BuildFileWithErrors(file_proto.DebugString(),
+                      "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
+                      "be enum types.\n");
+  // Enum keys are not allowed in proto3 as well.
+  // Get rid of extensions for proto3 to make it proto3 compatible.
+  file_proto.mutable_message_type()->RemoveLast();
+  file_proto.set_syntax("proto3");
+  BuildFileWithErrors(file_proto.DebugString(),
+                      "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
+                      "be enum types.\n");
+}
+
+
+TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  FieldDescriptorProto* key = file_proto.mutable_message_type(0)
+      ->mutable_nested_type(0)
+      ->mutable_field(0);
+  key->clear_type();
+  key->set_type_name(".Bar");
+  BuildFileWithErrors(file_proto.DebugString(), kMapEntryKeyTypeErrorMessage);
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithField) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "field { "
+      "  name: 'FooMapEntry' "
+      "  type: TYPE_INT32 "
+      "  label: LABEL_OPTIONAL "
+      "  number: 100 "
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing field.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "nested_type { "
+      "  name: 'FooMapEntry' "
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing nested message type.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "enum_type { "
+      "  name: 'FooMapEntry' "
+      "  value { name: 'ENTRY_FOO' number: 0 }"
+      "}",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing enum type.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) {
+  FileDescriptorProto file_proto;
+  FillValidMapEntry(&file_proto);
+  TextFormat::MergeFromString(
+      "oneof_decl { "
+      "  name: 'FooMapEntry' "
+      "}"
+      "field { "
+      "  name: 'int_field' "
+      "  type: TYPE_INT32 "
+      "  label: LABEL_OPTIONAL "
+      "  oneof_index: 0 "
+      "  number: 100 "
+      "} ",
+      file_proto.mutable_message_type(0));
+  BuildFileWithErrors(
+      file_proto.DebugString(),
+      "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
+      "\"Foo\".\n"
+      "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
+      "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
+      "with an existing oneof type.\n");
+}
+
+TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "enum_type {"
+    "  name: \"Bar\""
+    "  value { name:\"ENUM_A\" number:1 }"
+    "  value { name:\"ENUM_B\" number:2 }"
+    "}"
+    "message_type {"
+    "  name: 'Foo' "
+    "  field { "
+    "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
+    "    type_name: 'FooMapEntry' "
+    "  } "
+    "  nested_type { "
+    "    name: 'FooMapEntry' "
+    "    options {  map_entry: true } "
+    "    field { "
+    "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
+    "    } "
+    "    field { "
+    "      name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL "
+    "    } "
+    "  } "
+    "}",
+    "foo.proto: Foo.foo_map: "
+    "TYPE: Enum value in map must define 0 as the first value.\n");
+}
+
+TEST_F(ValidationErrorTest, Proto3RequiredFields) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
+      "}",
+      "foo.proto: Foo.foo: OTHER: Required fields are not allowed in "
+      "proto3.\n");
+
+  // applied to nested types as well.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar.bar: OTHER: Required fields are not allowed in "
+      "proto3.\n");
+
+  // optional and repeated fields are OK.
+  BuildFile(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "  field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } "
+      "}");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          default_value: '1' }"
+      "}",
+      "foo.proto: Foo.foo: OTHER: Explicit default values are not allowed in "
+      "proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "            default_value: '1' }"
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar.bar: OTHER: Explicit default values are not allowed "
+      "in proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "  extension_range { start:10 end:100 } "
+      "}",
+      "foo.proto: Foo: OTHER: Extension ranges are not allowed in "
+      "proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name : 'Bar' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
+      "    extension_range { start:10 end:100 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.Bar: OTHER: Extension ranges are not allowed in "
+      "proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  options { message_set_wire_format: true } "
+      "}",
+      "foo.proto: Foo: OTHER: MessageSet is not supported "
+      "in proto3.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Enum) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_FOO' number:1 } "
+      "}",
+      "foo.proto: FooEnum: OTHER: The first enum value must be "
+      "zero in proto3.\n");
+
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  enum_type { "
+      "    name: 'FooEnum' "
+      "    value { name: 'FOO_FOO' number:1 } "
+      "  } "
+      "}",
+      "foo.proto: Foo.FooEnum: OTHER: The first enum value must be "
+      "zero in proto3.\n");
+
+  // valid case.
+  BuildFile(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'FOO_FOO' number:0 } "
+      "}");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Group) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name: 'FooGroup' "
+      "  } "
+      "  field { name:'foo_group' number: 1 label:LABEL_OPTIONAL "
+      "          type: TYPE_GROUP type_name:'FooGroup' } "
+      "}",
+      "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 "
+      "syntax.\n");
+}
+
+
+TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) {
+  // Define an enum in a proto2 file.
+  BuildFile(
+      "name: 'foo.proto' "
+      "package: 'foo' "
+      "syntax: 'proto2' "
+      "enum_type { "
+      "  name: 'FooEnum' "
+      "  value { name: 'DEFAULT_OPTION' number:0 } "
+      "}");
+
+  // Now try to refer to it. (All tests in the fixture use the same pool, so we
+  // can refer to the enum above in this definition.)
+  BuildFileWithErrors(
+      "name: 'bar.proto' "
+      "dependency: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM "
+      "            type_name: 'foo.FooEnum' }"
+      "}",
+      "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not a proto3 "
+      "enum, but is used in \"Foo\" which is a proto3 message type.\n");
+}
+
+TEST_F(ValidationErrorTest, ValidateProto3Extension) {
+  // Valid for options.
+  DescriptorPool pool;
+  FileDescriptorProto file_proto;
+  // Add "google/protobuf/descriptor.proto".
+  FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+  // Add "foo.proto":
+  //   import "google/protobuf/descriptor.proto";
+  //   extend google.protobuf.FieldOptions {
+  //     optional int32 option1 = 1000;
+  //   }
+  file_proto.Clear();
+  file_proto.set_name("foo.proto");
+  file_proto.set_syntax("proto3");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+  AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000,
+               FieldDescriptorProto::LABEL_OPTIONAL,
+               FieldDescriptorProto::TYPE_INT32);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // Copy and change the package of the descriptor.proto
+  BuildFile(
+      "name: 'google.protobuf.proto' "
+      "syntax: 'proto2' "
+      "message_type { "
+      "  name: 'Container' extension_range { start: 1 end: 1000 } "
+      "}");
+  BuildFileWithErrors(
+      "name: 'bar.proto' "
+      "syntax: 'proto3' "
+      "dependency: 'google.protobuf.proto' "
+      "extension { "
+      "  name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 "
+      "  extendee: 'Container' "
+      "}",
+      "bar.proto: bar: OTHER: Extensions in proto3 are only allowed for "
+      "defining options.\n");
+}
+
+// Test that field names that may conflict in JSON is not allowed by protoc.
+TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
+  // The comparison is case-insensitive.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" "
+      "conflicts with field \"name\". This is not allowed in proto3.\n");
+  // Underscores are ignored.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" "
+      "conflicts with field \"ab\". This is not allowed in proto3.\n");
+}
 
 // ===================================================================
 // DescriptorDatabase
@@ -5260,8 +6372,8 @@
       const Message *message,
       ErrorLocation location,
       const string &error_message) {
-    GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << ": "
-               << error_message;
+    GOOGLE_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " ["
+               << element_name << "]: " << error_message;
   }
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AbortingErrorCollector);
@@ -5481,9 +6593,9 @@
 
   file_desc->CopySourceCodeInfoTo(&file_desc_proto);
   const SourceCodeInfo& info = file_desc_proto.source_code_info();
-  ASSERT_EQ(3, info.location_size());
+  ASSERT_EQ(4, info.location_size());
   // Get the Foo message location
-  const SourceCodeInfo_Location& foo_location = info.location(1);
+  const SourceCodeInfo_Location& foo_location = info.location(2);
   ASSERT_EQ(2, foo_location.path_size());
   EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
   EXPECT_EQ(0, foo_location.path(1));      // Foo is the first message defined
diff --git a/src/google/protobuf/drop_unknown_fields_test.cc b/src/google/protobuf/drop_unknown_fields_test.cc
new file mode 100644
index 0000000..6f16dc5
--- /dev/null
+++ b/src/google/protobuf/drop_unknown_fields_test.cc
@@ -0,0 +1,88 @@
+// 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.
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/unittest_drop_unknown_fields.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <gtest/gtest.h>
+
+namespace google {
+using unittest_drop_unknown_fields::Foo;
+using unittest_drop_unknown_fields::FooWithExtraFields;
+
+namespace protobuf {
+
+TEST(DropUnknownFieldsTest, GeneratedMessage) {
+  FooWithExtraFields foo_with_extra_fields;
+  foo_with_extra_fields.set_int32_value(1);
+  foo_with_extra_fields.set_enum_value(FooWithExtraFields::QUX);
+  foo_with_extra_fields.set_extra_int32_value(2);
+
+  Foo foo;
+  ASSERT_TRUE(foo.ParseFromString(foo_with_extra_fields.SerializeAsString()));
+  EXPECT_EQ(1, foo.int32_value());
+  EXPECT_EQ(static_cast<int>(FooWithExtraFields::QUX),
+            static_cast<int>(foo.enum_value()));
+  // We don't generate unknown field accessors but the UnknownFieldSet is
+  // still exposed through reflection API.
+  EXPECT_TRUE(foo.GetReflection()->GetUnknownFields(foo).empty());
+
+  ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo.SerializeAsString()));
+  EXPECT_EQ(1, foo_with_extra_fields.int32_value());
+  EXPECT_EQ(FooWithExtraFields::QUX, foo_with_extra_fields.enum_value());
+  // The "extra_int32_value" field should be lost.
+  EXPECT_EQ(0, foo_with_extra_fields.extra_int32_value());
+}
+
+TEST(DropUnknownFieldsTest, DynamicMessage) {
+  FooWithExtraFields foo_with_extra_fields;
+  foo_with_extra_fields.set_int32_value(1);
+  foo_with_extra_fields.set_enum_value(FooWithExtraFields::QUX);
+  foo_with_extra_fields.set_extra_int32_value(2);
+
+  google::protobuf::DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<google::protobuf::Message> foo(
+      factory.GetPrototype(Foo::descriptor())->New());
+  ASSERT_TRUE(foo->ParseFromString(foo_with_extra_fields.SerializeAsString()));
+  EXPECT_TRUE(foo->GetReflection()->GetUnknownFields(*foo).empty());
+
+  ASSERT_TRUE(foo_with_extra_fields.ParseFromString(foo->SerializeAsString()));
+  EXPECT_EQ(1, foo_with_extra_fields.int32_value());
+  EXPECT_EQ(FooWithExtraFields::QUX, foo_with_extra_fields.enum_value());
+  // The "extra_int32_value" field should be lost.
+  EXPECT_EQ(0, foo_with_extra_fields.extra_int32_value());
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
new file mode 100644
index 0000000..e363934
--- /dev/null
+++ b/src/google/protobuf/duration.pb.cc
@@ -0,0 +1,425 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/duration.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Duration_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Duration_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/duration.proto");
+  GOOGLE_CHECK(file != NULL);
+  Duration_descriptor_ = file->message_type(0);
+  static const int Duration_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Duration, seconds_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Duration, nanos_),
+  };
+  Duration_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Duration_descriptor_,
+      Duration::default_instance_,
+      Duration_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Duration),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Duration, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Duration, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Duration_descriptor_, &Duration::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fduration_2eproto() {
+  delete Duration::default_instance_;
+  delete Duration_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\036google/protobuf/duration.proto\022\017google"
+    ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
+    "\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu"
+    "rationProtoP\001Z*github.com/golang/protobu"
+    "f/ptypes/duration\240\001\001\242\002\003GPB\252\002\036Google.Prot"
+    "obuf.WellKnownTypesb\006proto3", 227);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/duration.proto", &protobuf_RegisterTypes);
+  Duration::default_instance_ = new Duration();
+  Duration::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fduration_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fduration_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fduration_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fduration_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Duration::kSecondsFieldNumber;
+const int Duration::kNanosFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Duration::Duration()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Duration)
+}
+
+void Duration::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Duration::Duration(const Duration& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Duration)
+}
+
+void Duration::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  seconds_ = GOOGLE_LONGLONG(0);
+  nanos_ = 0;
+}
+
+Duration::~Duration() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Duration)
+  SharedDtor();
+}
+
+void Duration::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void Duration::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Duration::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Duration_descriptor_;
+}
+
+const Duration& Duration::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
+  return *default_instance_;
+}
+
+Duration* Duration::default_instance_ = NULL;
+
+Duration* Duration::New(::google::protobuf::Arena* arena) const {
+  Duration* n = new Duration;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Duration::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(Duration, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Duration*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(seconds_, nanos_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+}
+
+bool Duration::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Duration)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int64 seconds = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &seconds_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_nanos;
+        break;
+      }
+
+      // optional int32 nanos = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_nanos:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &nanos_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Duration)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Duration)
+  return false;
+#undef DO_
+}
+
+void Duration::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Duration)
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->seconds(), output);
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->nanos(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Duration)
+}
+
+::google::protobuf::uint8* Duration::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(1, this->seconds(), target);
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->nanos(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
+  return target;
+}
+
+int Duration::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration)
+  int total_size = 0;
+
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int64Size(
+        this->seconds());
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->nanos());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Duration::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Duration)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Duration* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Duration>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Duration)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Duration)
+    MergeFrom(*source);
+  }
+}
+
+void Duration::MergeFrom(const Duration& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.seconds() != 0) {
+    set_seconds(from.seconds());
+  }
+  if (from.nanos() != 0) {
+    set_nanos(from.nanos());
+  }
+}
+
+void Duration::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Duration)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Duration::CopyFrom(const Duration& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Duration::IsInitialized() const {
+
+  return true;
+}
+
+void Duration::Swap(Duration* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Duration::InternalSwap(Duration* other) {
+  std::swap(seconds_, other->seconds_);
+  std::swap(nanos_, other->nanos_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Duration::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Duration_descriptor_;
+  metadata.reflection = Duration_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Duration
+
+// optional int64 seconds = 1;
+void Duration::clear_seconds() {
+  seconds_ = GOOGLE_LONGLONG(0);
+}
+ ::google::protobuf::int64 Duration::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.seconds)
+  return seconds_;
+}
+ void Duration::set_seconds(::google::protobuf::int64 value) {
+  
+  seconds_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.seconds)
+}
+
+// optional int32 nanos = 2;
+void Duration::clear_nanos() {
+  nanos_ = 0;
+}
+ ::google::protobuf::int32 Duration::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.nanos)
+  return nanos_;
+}
+ void Duration::set_nanos(::google::protobuf::int32 value) {
+  
+  nanos_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.nanos)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
new file mode 100644
index 0000000..215a52c
--- /dev/null
+++ b/src/google/protobuf/duration.pb.h
@@ -0,0 +1,172 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fduration_2eproto();
+
+class Duration;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message {
+ public:
+  Duration();
+  virtual ~Duration();
+
+  Duration(const Duration& from);
+
+  inline Duration& operator=(const Duration& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Duration& default_instance();
+
+  void Swap(Duration* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Duration* New() const { return New(NULL); }
+
+  Duration* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Duration& from);
+  void MergeFrom(const Duration& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Duration* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int64 seconds = 1;
+  void clear_seconds();
+  static const int kSecondsFieldNumber = 1;
+  ::google::protobuf::int64 seconds() const;
+  void set_seconds(::google::protobuf::int64 value);
+
+  // optional int32 nanos = 2;
+  void clear_nanos();
+  static const int kNanosFieldNumber = 2;
+  ::google::protobuf::int32 nanos() const;
+  void set_nanos(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Duration)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::int64 seconds_;
+  ::google::protobuf::int32 nanos_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fduration_2eproto();
+
+  void InitAsDefaultInstance();
+  static Duration* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Duration
+
+// optional int64 seconds = 1;
+inline void Duration::clear_seconds() {
+  seconds_ = GOOGLE_LONGLONG(0);
+}
+inline ::google::protobuf::int64 Duration::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.seconds)
+  return seconds_;
+}
+inline void Duration::set_seconds(::google::protobuf::int64 value) {
+  
+  seconds_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.seconds)
+}
+
+// optional int32 nanos = 2;
+inline void Duration::clear_nanos() {
+  nanos_ = 0;
+}
+inline ::google::protobuf::int32 Duration::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Duration.nanos)
+  return nanos_;
+}
+inline void Duration::set_nanos(::google::protobuf::int32 value) {
+  
+  nanos_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Duration.nanos)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto
new file mode 100644
index 0000000..96c1796
--- /dev/null
+++ b/src/google/protobuf/duration.proto
@@ -0,0 +1,98 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/duration";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DurationProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// A Duration represents a signed, fixed-length span of time represented
+// as a count of seconds and fractions of seconds at nanosecond
+// resolution. It is independent of any calendar and concepts like "day"
+// or "month". It is related to Timestamp in that the difference between
+// two Timestamp values is a Duration and it can be added or subtracted
+// from a Timestamp. Range is approximately +-10,000 years.
+//
+// Example 1: Compute Duration from two Timestamps in pseudo code.
+//
+//     Timestamp start = ...;
+//     Timestamp end = ...;
+//     Duration duration = ...;
+//
+//     duration.seconds = end.seconds - start.seconds;
+//     duration.nanos = end.nanos - start.nanos;
+//
+//     if (duration.seconds < 0 && duration.nanos > 0) {
+//       duration.seconds += 1;
+//       duration.nanos -= 1000000000;
+//     } else if (durations.seconds > 0 && duration.nanos < 0) {
+//       duration.seconds -= 1;
+//       duration.nanos += 1000000000;
+//     }
+//
+// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
+//
+//     Timestamp start = ...;
+//     Duration duration = ...;
+//     Timestamp end = ...;
+//
+//     end.seconds = start.seconds + duration.seconds;
+//     end.nanos = start.nanos + duration.nanos;
+//
+//     if (end.nanos < 0) {
+//       end.seconds -= 1;
+//       end.nanos += 1000000000;
+//     } else if (end.nanos >= 1000000000) {
+//       end.seconds += 1;
+//       end.nanos -= 1000000000;
+//     }
+//
+//
+message Duration {
+
+  // Signed seconds of the span of time. Must be from -315,576,000,000
+  // to +315,576,000,000 inclusive.
+  int64 seconds = 1;
+
+  // Signed fractions of a second at nanosecond resolution of the span
+  // of time. Durations less than one second are represented with a 0
+  // `seconds` field and a positive or negative `nanos` field. For durations
+  // of one second or more, a non-zero value for the `nanos` field must be
+  // of the same sign as the `seconds` field. Must be from -999,999,999
+  // to +999,999,999 inclusive.
+  int32 nanos = 2;
+}
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 4cca986..9e83bd2 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -64,18 +64,27 @@
 
 #include <algorithm>
 #include <google/protobuf/stubs/hash.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/reflection_ops.h>
 #include <google/protobuf/repeated_field.h>
+#include <google/protobuf/map_type_handler.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format.h>
+#include <google/protobuf/map_field.h>
 
 namespace google {
 namespace protobuf {
@@ -83,13 +92,21 @@
 using internal::WireFormat;
 using internal::ExtensionSet;
 using internal::GeneratedMessageReflection;
+using internal::MapField;
+using internal::DynamicMapField;
 
 
+using internal::ArenaStringPtr;
+
 // ===================================================================
 // Some helper tables and functions...
 
 namespace {
 
+bool IsMapFieldInApi(const FieldDescriptor* field) {
+  return field->is_map();
+}
+
 // Compute the byte size of the in-memory representation of the field.
 int FieldSpaceUsed(const FieldDescriptor* field) {
   typedef FieldDescriptor FD;  // avoid line wrapping
@@ -103,7 +120,12 @@
       case FD::CPPTYPE_FLOAT  : return sizeof(RepeatedField<float   >);
       case FD::CPPTYPE_BOOL   : return sizeof(RepeatedField<bool    >);
       case FD::CPPTYPE_ENUM   : return sizeof(RepeatedField<int     >);
-      case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
+      case FD::CPPTYPE_MESSAGE:
+        if (IsMapFieldInApi(field)) {
+          return sizeof(DynamicMapField);
+        } else {
+          return sizeof(RepeatedPtrField<Message>);
+        }
 
       case FD::CPPTYPE_STRING:
         switch (field->options().ctype()) {
@@ -131,7 +153,7 @@
         switch (field->options().ctype()) {
           default:  // TODO(kenton):  Support other string reps.
           case FieldOptions::STRING:
-            return sizeof(string*);
+            return sizeof(ArenaStringPtr);
         }
         break;
     }
@@ -162,7 +184,7 @@
       switch (field->options().ctype()) {
         default:
         case FieldOptions::STRING:
-          return sizeof(string*);
+          return sizeof(ArenaStringPtr);
       }
       break;
   }
@@ -202,6 +224,7 @@
     int oneof_case_offset;
     int unknown_fields_offset;
     int extensions_offset;
+    int is_default_instance_offset;
 
     // Not owned by the TypeInfo.
     DynamicMessageFactory* factory;  // The factory that created this object.
@@ -210,8 +233,8 @@
 
     // Warning:  The order in which the following pointers are defined is
     //   important (the prototype must be deleted *before* the offsets).
-    scoped_array<int> offsets;
-    scoped_ptr<const GeneratedMessageReflection> reflection;
+    google::protobuf::scoped_array<int> offsets;
+    google::protobuf::scoped_ptr<const GeneratedMessageReflection> reflection;
     // Don't use a scoped_ptr to hold the prototype: the destructor for
     // DynamicMessage needs to know whether it is the prototype, and does so by
     // looking back at this field. This would assume details about the
@@ -236,15 +259,29 @@
   // implements Message ----------------------------------------------
 
   Message* New() const;
+  Message* New(::google::protobuf::Arena* arena) const;
+  ::google::protobuf::Arena* GetArena() const { return NULL; };
 
   int GetCachedSize() const;
   void SetCachedSize(int size) const;
 
   Metadata GetMetadata() const;
 
+  // We actually allocate more memory than sizeof(*this) when this
+  // class's memory is allocated via the global operator new. Thus, we need to
+  // manually call the global operator delete. Calling the destructor is taken
+  // care of for us. This makes DynamicMessage compatible with -fsized-delete.
+  // It doesn't work for MSVC though.
+#ifndef _MSC_VER
+  static void operator delete(void* ptr) {
+    ::operator delete(ptr);
+  }
+#endif  // !_MSC_VER
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
+  DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena);
+  void SharedCtor();
 
   inline bool is_prototype() const {
     return type_info_->prototype == this ||
@@ -261,7 +298,6 @@
   }
 
   const TypeInfo* type_info_;
-
   // TODO(kenton):  Make this an atomic<int> when C++ supports it.
   mutable int cached_byte_size_;
 };
@@ -269,6 +305,17 @@
 DynamicMessage::DynamicMessage(const TypeInfo* type_info)
   : type_info_(type_info),
     cached_byte_size_(0) {
+  SharedCtor();
+}
+
+DynamicMessage::DynamicMessage(const TypeInfo* type_info,
+                               ::google::protobuf::Arena* arena)
+  : type_info_(type_info),
+    cached_byte_size_(0) {
+  SharedCtor();
+}
+
+void DynamicMessage::SharedCtor() {
   // We need to call constructors for various fields manually and set
   // default values where appropriate.  We use placement new to call
   // constructors.  If you haven't heard of placement new, I suggest Googling
@@ -286,6 +333,11 @@
         uint32(0);
   }
 
+  if (type_info_->is_default_instance_offset != -1) {
+    *reinterpret_cast<bool*>(
+        OffsetToPointer(type_info_->is_default_instance_offset)) = false;
+  }
+
   new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
 
   if (type_info_->extensions_offset != -1) {
@@ -330,15 +382,17 @@
           default:  // TODO(kenton):  Support other string reps.
           case FieldOptions::STRING:
             if (!field->is_repeated()) {
+              const string* default_value;
               if (is_prototype()) {
-                new(field_ptr) const string*(&field->default_value_string());
+                default_value = &field->default_value_string();
               } else {
-                string* default_value =
-                  *reinterpret_cast<string* const*>(
+                default_value =
+                  &(reinterpret_cast<const ArenaStringPtr*>(
                     type_info_->prototype->OffsetToPointer(
-                      type_info_->offsets[i]));
-                new(field_ptr) string*(default_value);
+                      type_info_->offsets[i]))->Get(NULL));
               }
+              ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr();
+              asp->UnsafeSetDefault(default_value);
             } else {
               new(field_ptr) RepeatedPtrField<string>();
             }
@@ -350,7 +404,12 @@
         if (!field->is_repeated()) {
           new(field_ptr) Message*(NULL);
         } else {
-          new(field_ptr) RepeatedPtrField<Message>();
+          if (IsMapFieldInApi(field)) {
+            new (field_ptr) DynamicMapField(
+                type_info_->factory->GetPrototypeNoLock(field->message_type()));
+          } else {
+            new (field_ptr) RepeatedPtrField<Message>();
+          }
         }
         break;
       }
@@ -370,7 +429,7 @@
   }
 
   // We need to manually run the destructors for repeated fields and strings,
-  // just as we ran their constructors in the the DynamicMessage constructor.
+  // just as we ran their constructors in the DynamicMessage constructor.
   // We also need to manually delete oneof fields if it is set and is string
   // or message.
   // Additionally, if any singular embedded messages have been allocated, we
@@ -390,9 +449,17 @@
         if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
           switch (field->options().ctype()) {
             default:
-            case FieldOptions::STRING:
-              delete *reinterpret_cast<string**>(field_ptr);
+            case FieldOptions::STRING: {
+              const ::std::string* default_value =
+                  &(reinterpret_cast<const ArenaStringPtr*>(
+                      reinterpret_cast<uint8*>(
+                          type_info_->default_oneof_instance)
+                      + type_info_->offsets[i])
+                    ->Get(NULL));
+              reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
+                  default_value, NULL);
               break;
+            }
           }
         } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
             delete *reinterpret_cast<Message**>(field_ptr);
@@ -431,8 +498,12 @@
           break;
 
         case FieldDescriptor::CPPTYPE_MESSAGE:
-          reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
-              ->~RepeatedPtrField<Message>();
+          if (IsMapFieldInApi(field)) {
+            reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField();
+          } else {
+            reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
+                ->~RepeatedPtrField<Message>();
+          }
           break;
       }
 
@@ -440,10 +511,12 @@
       switch (field->options().ctype()) {
         default:  // TODO(kenton):  Support other string reps.
         case FieldOptions::STRING: {
-          string* ptr = *reinterpret_cast<string**>(field_ptr);
-          if (ptr != &field->default_value_string()) {
-            delete ptr;
-          }
+          const ::std::string* default_value =
+              &(reinterpret_cast<const ArenaStringPtr*>(
+                  type_info_->prototype->OffsetToPointer(
+                      type_info_->offsets[i]))->Get(NULL));
+          reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
+              default_value, NULL);
           break;
         }
       }
@@ -484,6 +557,14 @@
         factory->GetPrototypeNoLock(field->message_type());
     }
   }
+
+  // Set as the default instance -- this affects field-presence semantics for
+  // proto3.
+  if (type_info_->is_default_instance_offset != -1) {
+    void* is_default_instance_ptr =
+        OffsetToPointer(type_info_->is_default_instance_offset);
+    *reinterpret_cast<bool*>(is_default_instance_ptr) = true;
+  }
 }
 
 Message* DynamicMessage::New() const {
@@ -492,6 +573,16 @@
   return new(new_base) DynamicMessage(type_info_);
 }
 
+Message* DynamicMessage::New(::google::protobuf::Arena* arena) const {
+  if (arena != NULL) {
+    Message* message = New();
+    arena->Own(message);
+    return message;
+  } else {
+    return New();
+  }
+}
+
 int DynamicMessage::GetCachedSize() const {
   return cached_byte_size_;
 }
@@ -583,11 +674,24 @@
   size = AlignOffset(size);
 
   // Next the has_bits, which is an array of uint32s.
-  type_info->has_bits_offset = size;
-  int has_bits_array_size =
-    DivideRoundingUp(type->field_count(), bitsizeof(uint32));
-  size += has_bits_array_size * sizeof(uint32);
-  size = AlignOffset(size);
+  if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    type_info->has_bits_offset = -1;
+  } else {
+    type_info->has_bits_offset = size;
+    int has_bits_array_size =
+      DivideRoundingUp(type->field_count(), bitsizeof(uint32));
+    size += has_bits_array_size * sizeof(uint32);
+    size = AlignOffset(size);
+  }
+
+  // The is_default_instance member, if any.
+  if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    type_info->is_default_instance_offset = size;
+    size += sizeof(bool);
+    size = AlignOffset(size);
+  } else {
+    type_info->is_default_instance_offset = -1;
+  }
 
   // The oneof_case, if any. It is an array of uint32s.
   if (type->oneof_decl_count() > 0) {
@@ -612,7 +716,7 @@
     // Oneof fields do not use any space.
     if (!type->field(i)->containing_oneof()) {
       int field_size = FieldSpaceUsed(type->field(i));
-      size = AlignTo(size, min(kSafeAlignment, field_size));
+      size = AlignTo(size, std::min(kSafeAlignment, field_size));
       offsets[i] = size;
       size += field_size;
     }
@@ -638,8 +742,14 @@
   // Allocate the prototype.
   void* base = operator new(size);
   memset(base, 0, size);
+  // The prototype in type_info has to be set before creating the prototype
+  // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When
+  // creating prototype for Foo, prototype of the map entry will also be
+  // created, which needs the address of the prototype of Foo (the value in
+  // map). To break the cyclic dependency, we have to assgin the address of
+  // prototype into type_info first.
+  type_info->prototype = static_cast<DynamicMessage*>(base);
   DynamicMessage* prototype = new(base) DynamicMessage(type_info);
-  type_info->prototype = prototype;
 
   // Construct the reflection object.
   if (type->oneof_decl_count() > 0) {
@@ -650,7 +760,7 @@
       for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
         const FieldDescriptor* field = type->oneof_decl(i)->field(j);
         int field_size = OneofFieldSpaceUsed(field);
-        oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size));
+        oneof_size = AlignTo(oneof_size, std::min(kSafeAlignment, field_size));
         offsets[field->index()] = oneof_size;
         oneof_size += field_size;
       }
@@ -672,7 +782,9 @@
             type_info->oneof_case_offset,
             type_info->pool,
             this,
-            type_info->size));
+            type_info->size,
+            -1 /* arena_offset */,
+            type_info->is_default_instance_offset));
   } else {
     type_info->reflection.reset(
         new GeneratedMessageReflection(
@@ -684,7 +796,9 @@
             type_info->extensions_offset,
             type_info->pool,
             this,
-            type_info->size));
+            type_info->size,
+            -1 /* arena_offset */,
+            type_info->is_default_instance_offset));
   }
   // Cross link prototypes.
   prototype->CrossLinkPrototypes();
@@ -723,12 +837,8 @@
           switch (field->options().ctype()) {
             default:
             case FieldOptions::STRING:
-              if (field->has_default_value()) {
-                new(field_ptr) const string*(&field->default_value_string());
-              } else {
-                new(field_ptr) string*(
-                    const_cast<string*>(&internal::GetEmptyString()));
-              }
+              ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
+              asp->UnsafeSetDefault(&field->default_value_string());
               break;
           }
           break;
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index 10ed700..f74cd7d 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -39,9 +39,13 @@
 #define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
 
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/message.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
 
 namespace google {
 namespace protobuf {
@@ -123,7 +127,7 @@
   // public header (for good reason), but dynamic_message.h is, and public
   // headers may only #include other public headers.
   struct PrototypeMap;
-  scoped_ptr<PrototypeMap> prototypes_;
+  google::protobuf::scoped_ptr<PrototypeMap> prototypes_;
   mutable Mutex prototypes_mutex_;
 
   friend class DynamicMessage;
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index a1c1661..70e437d 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -40,13 +40,21 @@
 // reflection_ops_unittest, cover the rest of the functionality used by
 // DynamicMessage.
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_no_field_presence.pb.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -65,6 +73,8 @@
   const Message* packed_prototype_;
   const Descriptor* oneof_descriptor_;
   const Message* oneof_prototype_;
+  const Descriptor* proto3_descriptor_;
+  const Message* proto3_prototype_;
 
   DynamicMessageTest(): factory_(&pool_) {}
 
@@ -76,16 +86,20 @@
     FileDescriptorProto unittest_file;
     FileDescriptorProto unittest_import_file;
     FileDescriptorProto unittest_import_public_file;
+    FileDescriptorProto unittest_no_field_presence_file;
 
     unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
     unittest_import::ImportMessage::descriptor()->file()->CopyTo(
       &unittest_import_file);
     unittest_import::PublicImportMessage::descriptor()->file()->CopyTo(
       &unittest_import_public_file);
+    proto2_nofieldpresence_unittest::TestAllTypes::descriptor()->
+        file()->CopyTo(&unittest_no_field_presence_file);
 
     ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL);
     ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
     ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
+    ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != NULL);
 
     descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
     ASSERT_TRUE(descriptor_ != NULL);
@@ -105,6 +119,12 @@
       pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2");
     ASSERT_TRUE(oneof_descriptor_ != NULL);
     oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_);
+
+    proto3_descriptor_ =
+      pool_.FindMessageTypeByName(
+          "proto2_nofieldpresence_unittest.TestAllTypes");
+    ASSERT_TRUE(proto3_descriptor_ != NULL);
+    proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_);
   }
 };
 
@@ -129,7 +149,7 @@
   // Check that all fields have independent offsets by setting each
   // one to a unique value then checking that they all still have those
   // unique values (i.e. they don't stomp each other).
-  scoped_ptr<Message> message(prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(prototype_->New());
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
   reflection_tester.SetAllFieldsViaReflection(message.get());
@@ -138,7 +158,7 @@
 
 TEST_F(DynamicMessageTest, Extensions) {
   // Check that extensions work.
-  scoped_ptr<Message> message(extensions_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(extensions_prototype_->New());
   TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
 
   reflection_tester.SetAllFieldsViaReflection(message.get());
@@ -147,7 +167,7 @@
 
 TEST_F(DynamicMessageTest, PackedFields) {
   // Check that packed fields work properly.
-  scoped_ptr<Message> message(packed_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(packed_prototype_->New());
   TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
 
   reflection_tester.SetPackedFieldsViaReflection(message.get());
@@ -156,7 +176,7 @@
 
 TEST_F(DynamicMessageTest, Oneof) {
   // Check that oneof fields work properly.
-  scoped_ptr<Message> message(oneof_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(oneof_prototype_->New());
 
   // Check default values.
   const Descriptor* descriptor = message->GetDescriptor();
@@ -217,7 +237,7 @@
   // Since we share the implementation with generated messages, we don't need
   // to test very much here.  Just make sure it appears to be working.
 
-  scoped_ptr<Message> message(prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(prototype_->New());
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
   int initial_space_used = message->SpaceUsed();
@@ -226,5 +246,47 @@
   EXPECT_LT(initial_space_used, message->SpaceUsed());
 }
 
+TEST_F(DynamicMessageTest, Arena) {
+  Arena arena;
+  Message* message = prototype_->New(&arena);
+  (void)message;  // avoid unused-variable error.
+  // Return without freeing: should not leak.
+}
+
+TEST_F(DynamicMessageTest, Proto3) {
+  Message* message = proto3_prototype_->New();
+  const Reflection* refl = message->GetReflection();
+  const Descriptor* desc = message->GetDescriptor();
+
+  // Just test a single primtive and single message field here to make sure we
+  // are getting the no-field-presence semantics elsewhere. DynamicMessage uses
+  // GeneratedMessageReflection under the hood, so the rest should be fine as
+  // long as GMR recognizes that we're using a proto3 message.
+  const FieldDescriptor* optional_int32 =
+      desc->FindFieldByName("optional_int32");
+  const FieldDescriptor* optional_msg =
+      desc->FindFieldByName("optional_nested_message");
+  EXPECT_TRUE(optional_int32 != NULL);
+  EXPECT_TRUE(optional_msg != NULL);
+
+  EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+  refl->SetInt32(message, optional_int32, 42);
+  EXPECT_EQ(true, refl->HasField(*message, optional_int32));
+  refl->SetInt32(message, optional_int32, 0);
+  EXPECT_EQ(false, refl->HasField(*message, optional_int32));
+
+  EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+  refl->MutableMessage(message, optional_msg);
+  EXPECT_EQ(true, refl->HasField(*message, optional_msg));
+  delete refl->ReleaseMessage(message, optional_msg);
+  EXPECT_EQ(false, refl->HasField(*message, optional_msg));
+
+  // Also ensure that the default instance handles field presence properly.
+  EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg));
+
+  delete message;
+}
+
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
new file mode 100644
index 0000000..dcf8426
--- /dev/null
+++ b/src/google/protobuf/empty.pb.cc
@@ -0,0 +1,319 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/empty.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Empty_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Empty_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/empty.proto");
+  GOOGLE_CHECK(file != NULL);
+  Empty_descriptor_ = file->message_type(0);
+  static const int Empty_offsets_[1] = {
+  };
+  Empty_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Empty_descriptor_,
+      Empty::default_instance_,
+      Empty_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Empty),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Empty, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Empty, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Empty_descriptor_, &Empty::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fempty_2eproto() {
+  delete Empty::default_instance_;
+  delete Empty_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\033google/protobuf/empty.proto\022\017google.pr"
+    "otobuf\"\007\n\005EmptyBy\n\023com.google.protobufB\n"
+    "EmptyProtoP\001Z\'github.com/golang/protobuf"
+    "/ptypes/empty\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Proto"
+    "buf.WellKnownTypesb\006proto3", 186);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/empty.proto", &protobuf_RegisterTypes);
+  Empty::default_instance_ = new Empty();
+  Empty::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fempty_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fempty_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fempty_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fempty_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Empty::Empty()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Empty)
+}
+
+Empty::Empty(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
+}
+
+void Empty::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Empty::Empty(const Empty& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Empty)
+}
+
+void Empty::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+}
+
+Empty::~Empty() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Empty)
+  SharedDtor();
+}
+
+void Empty::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void Empty::ArenaDtor(void* object) {
+  Empty* _this = reinterpret_cast< Empty* >(object);
+  (void)_this;
+}
+void Empty::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void Empty::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Empty::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Empty_descriptor_;
+}
+
+const Empty& Empty::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
+  return *default_instance_;
+}
+
+Empty* Empty::default_instance_ = NULL;
+
+Empty* Empty::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
+}
+
+void Empty::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Empty)
+}
+
+bool Empty::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Empty)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+  handle_unusual:
+    if (tag == 0 ||
+        ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+        ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+      goto success;
+    }
+    DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Empty)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Empty)
+  return false;
+#undef DO_
+}
+
+void Empty::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Empty)
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Empty)
+}
+
+::google::protobuf::uint8* Empty::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
+  return target;
+}
+
+int Empty::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty)
+  int total_size = 0;
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Empty::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Empty)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Empty* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Empty>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Empty)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Empty)
+    MergeFrom(*source);
+  }
+}
+
+void Empty::MergeFrom(const Empty& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+}
+
+void Empty::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Empty)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Empty::CopyFrom(const Empty& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Empty)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Empty::IsInitialized() const {
+
+  return true;
+}
+
+void Empty::Swap(Empty* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Empty temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Empty::UnsafeArenaSwap(Empty* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void Empty::InternalSwap(Empty* other) {
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Empty::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Empty_descriptor_;
+  metadata.reflection = Empty_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Empty
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
new file mode 100644
index 0000000..868009f
--- /dev/null
+++ b/src/google/protobuf/empty.pb.h
@@ -0,0 +1,143 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fempty_2eproto();
+
+class Empty;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
+ public:
+  Empty();
+  virtual ~Empty();
+
+  Empty(const Empty& from);
+
+  inline Empty& operator=(const Empty& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Empty& default_instance();
+
+  void UnsafeArenaSwap(Empty* other);
+  void Swap(Empty* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Empty* New() const { return New(NULL); }
+
+  Empty* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Empty& from);
+  void MergeFrom(const Empty& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Empty* other);
+  protected:
+  explicit Empty(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Empty)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fempty_2eproto();
+
+  void InitAsDefaultInstance();
+  static Empty* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Empty
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto
new file mode 100644
index 0000000..37f4cd1
--- /dev/null
+++ b/src/google/protobuf/empty.proto
@@ -0,0 +1,53 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/empty";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+//     service Foo {
+//       rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+//     }
+//
+// The JSON representation for `Empty` is empty JSON object `{}`.
+message Empty {}
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 274554b..9afb236 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -71,6 +71,8 @@
     // Do not add a default statement. Let the compiler complain when someone
     // adds a new wire type.
   }
+  GOOGLE_LOG(FATAL) << "can't reach here.";
+  return false;
 }
 
 // Registry stuff.
@@ -95,7 +97,7 @@
               int number, ExtensionInfo info) {
   ::google::protobuf::GoogleOnceInit(&registry_init_, &InitRegistry);
 
-  if (!InsertIfNotPresent(registry_, make_pair(containing_type, number),
+  if (!InsertIfNotPresent(registry_, std::make_pair(containing_type, number),
                           info)) {
     GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
                << containing_type->GetTypeName()
@@ -105,8 +107,9 @@
 
 const ExtensionInfo* FindRegisteredExtension(
     const MessageLite* containing_type, int number) {
-  return (registry_ == NULL) ? NULL :
-         FindOrNull(*registry_, make_pair(containing_type, number));
+  return (registry_ == NULL)
+             ? NULL
+             : FindOrNull(*registry_, std::make_pair(containing_type, number));
 }
 
 }  // namespace
@@ -174,12 +177,21 @@
 // ===================================================================
 // Constructors and basic methods.
 
-ExtensionSet::ExtensionSet() {}
+ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena) : arena_(arena) {
+  if (arena_ != NULL) {
+    arena_->OwnDestructor(&extensions_);
+  }
+}
+
+ExtensionSet::ExtensionSet() : arena_(NULL) {}
 
 ExtensionSet::~ExtensionSet() {
-  for (map<int, Extension>::iterator iter = extensions_.begin();
-       iter != extensions_.end(); ++iter) {
-    iter->second.Free();
+  // Deletes all allocated extensions.
+  if (arena_ == NULL) {
+    for (map<int, Extension>::iterator iter = extensions_.begin();
+         iter != extensions_.end(); ++iter) {
+      iter->second.Free();
+    }
   }
 }
 
@@ -301,7 +313,8 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \
     extension->is_repeated = true;                                             \
     extension->is_packed = packed;                                             \
-    extension->repeated_##LOWERCASE##_value = new RepeatedField<LOWERCASE>();  \
+    extension->repeated_##LOWERCASE##_value =                                  \
+      Arena::CreateMessage<RepeatedField<LOWERCASE> >(arena_);                 \
   } else {                                                                     \
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                              \
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                   \
@@ -345,34 +358,44 @@
     switch (WireFormatLite::FieldTypeToCppType(
         static_cast<WireFormatLite::FieldType>(field_type))) {
       case WireFormatLite::CPPTYPE_INT32:
-        extension->repeated_int32_value = new RepeatedField<int32>();
+        extension->repeated_int32_value =
+            Arena::CreateMessage<RepeatedField<int32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_INT64:
-        extension->repeated_int64_value = new RepeatedField<int64>();
+        extension->repeated_int64_value =
+            Arena::CreateMessage<RepeatedField<int64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT32:
-        extension->repeated_uint32_value = new RepeatedField<uint32>();
+        extension->repeated_uint32_value =
+            Arena::CreateMessage<RepeatedField<uint32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT64:
-        extension->repeated_uint64_value = new RepeatedField<uint64>();
+        extension->repeated_uint64_value =
+            Arena::CreateMessage<RepeatedField<uint64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_DOUBLE:
-        extension->repeated_double_value = new RepeatedField<double>();
+        extension->repeated_double_value =
+            Arena::CreateMessage<RepeatedField<double> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_FLOAT:
-        extension->repeated_float_value = new RepeatedField<float>();
+        extension->repeated_float_value =
+            Arena::CreateMessage<RepeatedField<float> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_BOOL:
-        extension->repeated_bool_value = new RepeatedField<bool>();
+        extension->repeated_bool_value =
+            Arena::CreateMessage<RepeatedField<bool> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_ENUM:
-        extension->repeated_enum_value = new RepeatedField<int>();
+        extension->repeated_enum_value =
+            Arena::CreateMessage<RepeatedField<int> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_STRING:
-        extension->repeated_string_value = new RepeatedPtrField< ::std::string>();
+        extension->repeated_string_value =
+            Arena::CreateMessage<RepeatedPtrField< ::std::string> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_MESSAGE:
-        extension->repeated_message_value = new RepeatedPtrField<MessageLite>();
+        extension->repeated_message_value =
+            Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
         break;
     }
   }
@@ -444,7 +467,8 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
     extension->is_repeated = true;
     extension->is_packed = packed;
-    extension->repeated_enum_value = new RepeatedField<int>();
+    extension->repeated_enum_value =
+        Arena::CreateMessage<RepeatedField<int> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);
@@ -474,7 +498,7 @@
     extension->type = type;
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
     extension->is_repeated = false;
-    extension->string_value = new string;
+    extension->string_value = Arena::Create<string>(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING);
   }
@@ -504,7 +528,8 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
     extension->is_repeated = true;
     extension->is_packed = false;
-    extension->repeated_string_value = new RepeatedPtrField<string>();
+    extension->repeated_string_value =
+        Arena::CreateMessage<RepeatedPtrField<string> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
   }
@@ -544,7 +569,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
     extension->is_repeated = false;
     extension->is_lazy = false;
-    extension->message_value = prototype.New();
+    extension->message_value = prototype.New(arena_);
     extension->is_cleared = false;
     return extension->message_value;
   } else {
@@ -570,6 +595,51 @@
     ClearExtension(number);
     return;
   }
+  ::google::protobuf::Arena* message_arena = message->GetArena();
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    if (message_arena == arena_) {
+      extension->message_value = message;
+    } else if (message_arena == NULL) {
+      extension->message_value = message;
+      arena_->Own(message);  // not NULL because not equal to message_arena
+    } else {
+      extension->message_value = message->New(arena_);
+      extension->message_value->CheckTypeAndMergeFrom(*message);
+    }
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->SetAllocatedMessage(message);
+    } else {
+      if (arena_ == NULL) {
+        delete extension->message_value;
+      }
+      if (message_arena == arena_) {
+        extension->message_value = message;
+      } else if (message_arena == NULL) {
+        extension->message_value = message;
+        arena_->Own(message);  // not NULL because not equal to message_arena
+      } else {
+        extension->message_value = message->New(arena_);
+        extension->message_value->CheckTypeAndMergeFrom(*message);
+      }
+    }
+  }
+  extension->is_cleared = false;
+}
+
+void ExtensionSet::UnsafeArenaSetAllocatedMessage(
+    int number, FieldType type, const FieldDescriptor* descriptor,
+    MessageLite* message) {
+  if (message == NULL) {
+    ClearExtension(number);
+    return;
+  }
   Extension* extension;
   if (MaybeNewExtension(number, descriptor, &extension)) {
     extension->type = type;
@@ -580,15 +650,18 @@
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
     if (extension->is_lazy) {
-      extension->lazymessage_value->SetAllocatedMessage(message);
+      extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message);
     } else {
-      delete extension->message_value;
+      if (arena_ == NULL) {
+        delete extension->message_value;
+      }
       extension->message_value = message;
     }
   }
   extension->is_cleared = false;
 }
 
+
 MessageLite* ExtensionSet::ReleaseMessage(int number,
                                           const MessageLite& prototype) {
   map<int, Extension>::iterator iter = extensions_.find(number);
@@ -600,7 +673,39 @@
     MessageLite* ret = NULL;
     if (iter->second.is_lazy) {
       ret = iter->second.lazymessage_value->ReleaseMessage(prototype);
-      delete iter->second.lazymessage_value;
+      if (arena_ == NULL) {
+        delete iter->second.lazymessage_value;
+      }
+    } else {
+      if (arena_ == NULL) {
+        ret = iter->second.message_value;
+      } else {
+        // ReleaseMessage() always returns a heap-allocated message, and we are
+        // on an arena, so we need to make a copy of this message to return.
+        ret = (iter->second.message_value)->New();
+        ret->CheckTypeAndMergeFrom(*iter->second.message_value);
+      }
+    }
+    extensions_.erase(number);
+    return ret;
+  }
+}
+
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    int number, const MessageLite& prototype) {
+  map<int, Extension>::iterator iter = extensions_.find(number);
+  if (iter == extensions_.end()) {
+    // Not present.  Return NULL.
+    return NULL;
+  } else {
+    GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+    MessageLite* ret = NULL;
+    if (iter->second.is_lazy) {
+      ret =
+        iter->second.lazymessage_value->UnsafeArenaReleaseMessage(prototype);
+      if (arena_ == NULL) {
+        delete iter->second.lazymessage_value;
+      }
     } else {
       ret = iter->second.message_value;
     }
@@ -637,7 +742,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
     extension->is_repeated = true;
     extension->repeated_message_value =
-      new RepeatedPtrField<MessageLite>();
+        Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
   }
@@ -647,7 +752,7 @@
   MessageLite* result = extension->repeated_message_value
       ->AddFromCleared<GenericTypeHandler<MessageLite> >();
   if (result == NULL) {
-    result = prototype.New();
+    result = prototype.New(arena_);
     extension->repeated_message_value->AddAllocated(result);
   }
   return result;
@@ -765,138 +870,142 @@
   for (map<int, Extension>::const_iterator iter = other.extensions_.begin();
        iter != other.extensions_.end(); ++iter) {
     const Extension& other_extension = iter->second;
+    InternalExtensionMergeFrom(iter->first, other_extension);
+  }
+}
 
-    if (other_extension.is_repeated) {
-      Extension* extension;
-      bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor,
-                                      &extension);
-      if (is_new) {
-        // Extension did not already exist in set.
-        extension->type = other_extension.type;
-        extension->is_packed = other_extension.is_packed;
-        extension->is_repeated = true;
-      } else {
-        GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
-        GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
-        GOOGLE_DCHECK(extension->is_repeated);
-      }
-
-      switch (cpp_type(other_extension.type)) {
-#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE)             \
-        case WireFormatLite::CPPTYPE_##UPPERCASE:                    \
-          if (is_new) {                                              \
-            extension->repeated_##LOWERCASE##_value =                \
-              new REPEATED_TYPE;                                     \
-          }                                                          \
-          extension->repeated_##LOWERCASE##_value->MergeFrom(        \
-            *other_extension.repeated_##LOWERCASE##_value);          \
-          break;
-
-        HANDLE_TYPE(  INT32,   int32, RepeatedField   <  int32>);
-        HANDLE_TYPE(  INT64,   int64, RepeatedField   <  int64>);
-        HANDLE_TYPE( UINT32,  uint32, RepeatedField   < uint32>);
-        HANDLE_TYPE( UINT64,  uint64, RepeatedField   < uint64>);
-        HANDLE_TYPE(  FLOAT,   float, RepeatedField   <  float>);
-        HANDLE_TYPE( DOUBLE,  double, RepeatedField   < double>);
-        HANDLE_TYPE(   BOOL,    bool, RepeatedField   <   bool>);
-        HANDLE_TYPE(   ENUM,    enum, RepeatedField   <    int>);
-        HANDLE_TYPE( STRING,  string, RepeatedPtrField< string>);
-#undef HANDLE_TYPE
-
-        case WireFormatLite::CPPTYPE_MESSAGE:
-          if (is_new) {
-            extension->repeated_message_value =
-              new RepeatedPtrField<MessageLite>();
-          }
-          // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
-          // it would attempt to allocate new objects.
-          RepeatedPtrField<MessageLite>* other_repeated_message =
-              other_extension.repeated_message_value;
-          for (int i = 0; i < other_repeated_message->size(); i++) {
-            const MessageLite& other_message = other_repeated_message->Get(i);
-            MessageLite* target = extension->repeated_message_value
-                     ->AddFromCleared<GenericTypeHandler<MessageLite> >();
-            if (target == NULL) {
-              target = other_message.New();
-              extension->repeated_message_value->AddAllocated(target);
-            }
-            target->CheckTypeAndMergeFrom(other_message);
-          }
-          break;
-      }
+void ExtensionSet::InternalExtensionMergeFrom(
+  int number, const Extension& other_extension) {
+  if (other_extension.is_repeated) {
+    Extension* extension;
+    bool is_new = MaybeNewExtension(number, other_extension.descriptor,
+                                    &extension);
+    if (is_new) {
+      // Extension did not already exist in set.
+      extension->type = other_extension.type;
+      extension->is_packed = other_extension.is_packed;
+      extension->is_repeated = true;
     } else {
-      if (!other_extension.is_cleared) {
-        switch (cpp_type(other_extension.type)) {
-#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE)                         \
-          case WireFormatLite::CPPTYPE_##UPPERCASE:                          \
-            Set##CAMELCASE(iter->first, other_extension.type,                \
-                           other_extension.LOWERCASE##_value,                \
-                           other_extension.descriptor);                      \
-            break;
+      GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+      GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
+      GOOGLE_DCHECK(extension->is_repeated);
+    }
 
-          HANDLE_TYPE( INT32,  int32,  Int32);
-          HANDLE_TYPE( INT64,  int64,  Int64);
-          HANDLE_TYPE(UINT32, uint32, UInt32);
-          HANDLE_TYPE(UINT64, uint64, UInt64);
-          HANDLE_TYPE( FLOAT,  float,  Float);
-          HANDLE_TYPE(DOUBLE, double, Double);
-          HANDLE_TYPE(  BOOL,   bool,   Bool);
-          HANDLE_TYPE(  ENUM,   enum,   Enum);
+    switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE)                    \
+      case WireFormatLite::CPPTYPE_##UPPERCASE:                             \
+        if (is_new) {                                                       \
+          extension->repeated_##LOWERCASE##_value =                         \
+            Arena::CreateMessage<REPEATED_TYPE >(arena_);                   \
+        }                                                                   \
+        extension->repeated_##LOWERCASE##_value->MergeFrom(                 \
+          *other_extension.repeated_##LOWERCASE##_value);                   \
+        break;
+
+      HANDLE_TYPE(  INT32,   int32, RepeatedField   <  int32>);
+      HANDLE_TYPE(  INT64,   int64, RepeatedField   <  int64>);
+      HANDLE_TYPE( UINT32,  uint32, RepeatedField   < uint32>);
+      HANDLE_TYPE( UINT64,  uint64, RepeatedField   < uint64>);
+      HANDLE_TYPE(  FLOAT,   float, RepeatedField   <  float>);
+      HANDLE_TYPE( DOUBLE,  double, RepeatedField   < double>);
+      HANDLE_TYPE(   BOOL,    bool, RepeatedField   <   bool>);
+      HANDLE_TYPE(   ENUM,    enum, RepeatedField   <    int>);
+      HANDLE_TYPE( STRING,  string, RepeatedPtrField< string>);
 #undef HANDLE_TYPE
-          case WireFormatLite::CPPTYPE_STRING:
-            SetString(iter->first, other_extension.type,
-                      *other_extension.string_value,
-                      other_extension.descriptor);
-            break;
-          case WireFormatLite::CPPTYPE_MESSAGE: {
-            Extension* extension;
-            bool is_new = MaybeNewExtension(iter->first,
-                                            other_extension.descriptor,
-                                            &extension);
-            if (is_new) {
-              extension->type = other_extension.type;
-              extension->is_packed = other_extension.is_packed;
-              extension->is_repeated = false;
-              if (other_extension.is_lazy) {
-                extension->is_lazy = true;
-                extension->lazymessage_value =
-                    other_extension.lazymessage_value->New();
+
+      case WireFormatLite::CPPTYPE_MESSAGE:
+        if (is_new) {
+          extension->repeated_message_value =
+              Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
+        }
+        // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
+        // it would attempt to allocate new objects.
+        RepeatedPtrField<MessageLite>* other_repeated_message =
+            other_extension.repeated_message_value;
+        for (int i = 0; i < other_repeated_message->size(); i++) {
+          const MessageLite& other_message = other_repeated_message->Get(i);
+          MessageLite* target = extension->repeated_message_value
+                   ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+          if (target == NULL) {
+            target = other_message.New(arena_);
+            extension->repeated_message_value->AddAllocated(target);
+          }
+          target->CheckTypeAndMergeFrom(other_message);
+        }
+        break;
+    }
+  } else {
+    if (!other_extension.is_cleared) {
+      switch (cpp_type(other_extension.type)) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE)                       \
+        case WireFormatLite::CPPTYPE_##UPPERCASE:                          \
+          Set##CAMELCASE(number, other_extension.type,                     \
+                         other_extension.LOWERCASE##_value,                \
+                         other_extension.descriptor);                      \
+          break;
+
+        HANDLE_TYPE( INT32,  int32,  Int32);
+        HANDLE_TYPE( INT64,  int64,  Int64);
+        HANDLE_TYPE(UINT32, uint32, UInt32);
+        HANDLE_TYPE(UINT64, uint64, UInt64);
+        HANDLE_TYPE( FLOAT,  float,  Float);
+        HANDLE_TYPE(DOUBLE, double, Double);
+        HANDLE_TYPE(  BOOL,   bool,   Bool);
+        HANDLE_TYPE(  ENUM,   enum,   Enum);
+#undef HANDLE_TYPE
+        case WireFormatLite::CPPTYPE_STRING:
+          SetString(number, other_extension.type,
+                    *other_extension.string_value,
+                    other_extension.descriptor);
+          break;
+        case WireFormatLite::CPPTYPE_MESSAGE: {
+          Extension* extension;
+          bool is_new = MaybeNewExtension(number,
+                                          other_extension.descriptor,
+                                          &extension);
+          if (is_new) {
+            extension->type = other_extension.type;
+            extension->is_packed = other_extension.is_packed;
+            extension->is_repeated = false;
+            if (other_extension.is_lazy) {
+              extension->is_lazy = true;
+              extension->lazymessage_value =
+                  other_extension.lazymessage_value->New(arena_);
+              extension->lazymessage_value->MergeFrom(
+                  *other_extension.lazymessage_value);
+            } else {
+              extension->is_lazy = false;
+              extension->message_value =
+                  other_extension.message_value->New(arena_);
+              extension->message_value->CheckTypeAndMergeFrom(
+                  *other_extension.message_value);
+            }
+          } else {
+            GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
+            GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed);
+            GOOGLE_DCHECK(!extension->is_repeated);
+            if (other_extension.is_lazy) {
+              if (extension->is_lazy) {
                 extension->lazymessage_value->MergeFrom(
                     *other_extension.lazymessage_value);
               } else {
-                extension->is_lazy = false;
-                extension->message_value =
-                    other_extension.message_value->New();
+                extension->message_value->CheckTypeAndMergeFrom(
+                    other_extension.lazymessage_value->GetMessage(
+                        *extension->message_value));
+              }
+            } else {
+              if (extension->is_lazy) {
+                extension->lazymessage_value->MutableMessage(
+                    *other_extension.message_value)->CheckTypeAndMergeFrom(
+                        *other_extension.message_value);
+              } else {
                 extension->message_value->CheckTypeAndMergeFrom(
                     *other_extension.message_value);
               }
-            } else {
-              GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
-              GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed);
-              GOOGLE_DCHECK(!extension->is_repeated);
-              if (other_extension.is_lazy) {
-                if (extension->is_lazy) {
-                  extension->lazymessage_value->MergeFrom(
-                      *other_extension.lazymessage_value);
-                } else {
-                  extension->message_value->CheckTypeAndMergeFrom(
-                      other_extension.lazymessage_value->GetMessage(
-                          *extension->message_value));
-                }
-              } else {
-                if (extension->is_lazy) {
-                  extension->lazymessage_value->MutableMessage(
-                      *other_extension.message_value)->CheckTypeAndMergeFrom(
-                          *other_extension.message_value);
-                } else {
-                  extension->message_value->CheckTypeAndMergeFrom(
-                      *other_extension.message_value);
-                }
-              }
             }
-            extension->is_cleared = false;
-            break;
           }
+          extension->is_cleared = false;
+          break;
         }
       }
     }
@@ -904,7 +1013,19 @@
 }
 
 void ExtensionSet::Swap(ExtensionSet* x) {
-  extensions_.swap(x->extensions_);
+  if (GetArenaNoVirtual() == x->GetArenaNoVirtual()) {
+    extensions_.swap(x->extensions_);
+  } else {
+    // TODO(cfallin, rohananil): We maybe able to optimize a case where we are
+    // swapping from heap to arena-allocated extension set, by just Own()'ing
+    // the extensions.
+    ExtensionSet extension_set;
+    extension_set.MergeFrom(*x);
+    x->Clear();
+    x->MergeFrom(*this);
+    Clear();
+    MergeFrom(extension_set);
+  }
 }
 
 void ExtensionSet::SwapExtension(ExtensionSet* other,
@@ -920,18 +1041,42 @@
 
   if (this_iter != extensions_.end() &&
       other_iter != other->extensions_.end()) {
-    std::swap(this_iter->second, other_iter->second);
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      using std::swap;
+      swap(this_iter->second, other_iter->second);
+    } else {
+      // TODO(cfallin, rohananil): We could further optimize these cases,
+      // especially avoid creation of ExtensionSet, and move MergeFrom logic
+      // into Extensions itself (which takes arena as an argument).
+      // We do it this way to reuse the copy-across-arenas logic already
+      // implemented in ExtensionSet's MergeFrom.
+      ExtensionSet temp;
+      temp.InternalExtensionMergeFrom(number, other_iter->second);
+      map<int, Extension>::iterator temp_iter = temp.extensions_.find(number);
+      other_iter->second.Clear();
+      other->InternalExtensionMergeFrom(number, this_iter->second);
+      this_iter->second.Clear();
+      InternalExtensionMergeFrom(number, temp_iter->second);
+    }
     return;
   }
 
   if (this_iter == extensions_.end()) {
-    extensions_.insert(make_pair(number, other_iter->second));
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      extensions_.insert(std::make_pair(number, other_iter->second));
+    } else {
+      InternalExtensionMergeFrom(number, other_iter->second);
+    }
     other->extensions_.erase(number);
     return;
   }
 
   if (other_iter == other->extensions_.end()) {
-    other->extensions_.insert(make_pair(number, this_iter->second));
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      other->extensions_.insert(std::make_pair(number, this_iter->second));
+    } else {
+      other->InternalExtensionMergeFrom(number, this_iter->second);
+    }
     extensions_.erase(number);
     return;
   }
@@ -1061,6 +1206,9 @@
                   extension.enum_validity_check.arg, value)) {
             AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
                     value, extension.descriptor);
+          } else {
+            // Invalid value.  Treat as unknown.
+            field_skipper->SkipUnknownEnum(number, value);
           }
         }
         break;
@@ -1223,7 +1371,7 @@
                                      const FieldDescriptor* descriptor,
                                      Extension** result) {
   pair<map<int, Extension>::iterator, bool> insert_result =
-      extensions_.insert(make_pair(number, Extension()));
+      extensions_.insert(std::make_pair(number, Extension()));
   *result = &insert_result.first->second;
   (*result)->descriptor = descriptor;
   return insert_result.second;
@@ -1554,6 +1702,8 @@
   return 0;
 }
 
+// This function deletes all allocated objects. This function should be only
+// called if the Extension was created with an arena.
 void ExtensionSet::Extension::Free() {
   if (is_repeated) {
     switch (cpp_type(type)) {
@@ -1598,66 +1748,68 @@
 // ==================================================================
 // Default repeated field instances for iterator-compatible accessors
 
+GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_primitive_generic_type_traits_once_init_);
+GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_string_type_traits_once_init_);
+GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_message_generic_type_traits_once_init_);
+
+void RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields() {
+  default_repeated_field_int32_ = new RepeatedField<int32>;
+  default_repeated_field_int64_ = new RepeatedField<int64>;
+  default_repeated_field_uint32_ = new RepeatedField<uint32>;
+  default_repeated_field_uint64_ = new RepeatedField<uint64>;
+  default_repeated_field_double_ = new RepeatedField<double>;
+  default_repeated_field_float_ = new RepeatedField<float>;
+  default_repeated_field_bool_ = new RepeatedField<bool>;
+  OnShutdown(&DestroyDefaultRepeatedFields);
+}
+
+void RepeatedPrimitiveGenericTypeTraits::DestroyDefaultRepeatedFields() {
+  delete default_repeated_field_int32_;
+  delete default_repeated_field_int64_;
+  delete default_repeated_field_uint32_;
+  delete default_repeated_field_uint64_;
+  delete default_repeated_field_double_;
+  delete default_repeated_field_float_;
+  delete default_repeated_field_bool_;
+}
+
+void RepeatedStringTypeTraits::InitializeDefaultRepeatedFields() {
+  default_repeated_field_ = new RepeatedFieldType;
+  OnShutdown(&DestroyDefaultRepeatedFields);
+}
+
+void RepeatedStringTypeTraits::DestroyDefaultRepeatedFields() {
+  delete default_repeated_field_;
+}
+
+void RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields() {
+  default_repeated_field_ = new RepeatedFieldType;
+  OnShutdown(&DestroyDefaultRepeatedFields);
+}
+
+void RepeatedMessageGenericTypeTraits::DestroyDefaultRepeatedFields() {
+  delete default_repeated_field_;
+}
+
+const RepeatedField<int32>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_ = NULL;
+const RepeatedField<int64>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_ = NULL;
+const RepeatedField<uint32>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_ = NULL;
+const RepeatedField<uint64>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_ = NULL;
+const RepeatedField<double>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_ = NULL;
+const RepeatedField<float>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_ = NULL;
+const RepeatedField<bool>*
+RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_ = NULL;
 const RepeatedStringTypeTraits::RepeatedFieldType*
 RepeatedStringTypeTraits::default_repeated_field_ = NULL;
-
 const RepeatedMessageGenericTypeTraits::RepeatedFieldType*
 RepeatedMessageGenericTypeTraits::default_repeated_field_ = NULL;
 
-#define PROTOBUF_DEFINE_DEFAULT_REPEATED(TYPE)                                 \
-    const RepeatedField<TYPE>*                                                 \
-    RepeatedPrimitiveGenericTypeTraits::default_repeated_field_##TYPE##_ = NULL;
-
-PROTOBUF_DEFINE_DEFAULT_REPEATED(int32)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(int64)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(uint32)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(uint64)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(double)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(float)
-PROTOBUF_DEFINE_DEFAULT_REPEATED(bool)
-
-#undef PROTOBUF_DEFINE_DEFAULT_REPEATED
-
-struct StaticDefaultRepeatedFieldsInitializer {
-  StaticDefaultRepeatedFieldsInitializer() {
-    InitializeDefaultRepeatedFields();
-    OnShutdown(&DestroyDefaultRepeatedFields);
-  }
-} static_repeated_fields_initializer;
-
-void InitializeDefaultRepeatedFields() {
-  RepeatedStringTypeTraits::default_repeated_field_ =
-      new RepeatedStringTypeTraits::RepeatedFieldType;
-  RepeatedMessageGenericTypeTraits::default_repeated_field_ =
-      new RepeatedMessageGenericTypeTraits::RepeatedFieldType;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_ =
-      new RepeatedField<int32>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_ =
-      new RepeatedField<int64>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_ =
-      new RepeatedField<uint32>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_ =
-      new RepeatedField<uint64>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_ =
-      new RepeatedField<double>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_ =
-      new RepeatedField<float>;
-  RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_ =
-      new RepeatedField<bool>;
-}
-
-void DestroyDefaultRepeatedFields() {
-  delete RepeatedStringTypeTraits::default_repeated_field_;
-  delete RepeatedMessageGenericTypeTraits::default_repeated_field_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_;
-  delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_;
-}
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index d6fc45d..bca179b 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -45,12 +45,15 @@
 
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/once.h>
 
 #include <google/protobuf/repeated_field.h>
 
 namespace google {
 
 namespace protobuf {
+  class Arena;
   class Descriptor;                                    // descriptor.h
   class FieldDescriptor;                               // descriptor.h
   class DescriptorPool;                                // descriptor.h
@@ -157,6 +160,7 @@
 class LIBPROTOBUF_EXPORT ExtensionSet {
  public:
   ExtensionSet();
+  explicit ExtensionSet(::google::protobuf::Arena* arena);
   ~ExtensionSet();
 
   // These are called at startup by protocol-compiler-generated code to
@@ -192,7 +196,7 @@
   // directly, unless you are doing low-level memory management.
   //
   // When calling any of these accessors, the extension number requested
-  // MUST exist in the DescriptorPool provided to the constructor.  Otheriwse,
+  // MUST exist in the DescriptorPool provided to the constructor.  Otherwise,
   // the method will fail an assert.  Normally, though, you would not call
   // these directly; you would either call the generated accessors of your
   // message class (e.g. GetExtension()) or you would call the accessors
@@ -260,10 +264,17 @@
   void SetAllocatedMessage(int number, FieldType type,
                            const FieldDescriptor* descriptor,
                            MessageLite* message);
+  void UnsafeArenaSetAllocatedMessage(int number, FieldType type,
+                                      const FieldDescriptor* descriptor,
+                                      MessageLite* message);
   MessageLite* ReleaseMessage(int number, const MessageLite& prototype);
+  MessageLite* UnsafeArenaReleaseMessage(
+      int number, const MessageLite& prototype);
+
   MessageLite* ReleaseMessage(const FieldDescriptor* descriptor,
                               MessageFactory* factory);
 #undef desc
+  ::google::protobuf::Arena* GetArenaNoVirtual() const { return arena_; }
 
   // repeated fields -------------------------------------------------
 
@@ -321,6 +332,8 @@
                           const MessageLite& prototype, desc);
   MessageLite* AddMessage(const FieldDescriptor* descriptor,
                           MessageFactory* factory);
+  void AddAllocatedMessage(const FieldDescriptor* descriptor,
+                           MessageLite* new_entry);
 #undef desc
 
   void RemoveLast(int number);
@@ -421,12 +434,15 @@
     LazyMessageExtension() {}
     virtual ~LazyMessageExtension() {}
 
-    virtual LazyMessageExtension* New() const = 0;
+    virtual LazyMessageExtension* New(::google::protobuf::Arena* arena) const = 0;
     virtual const MessageLite& GetMessage(
         const MessageLite& prototype) const = 0;
     virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0;
     virtual void SetAllocatedMessage(MessageLite *message) = 0;
+    virtual void UnsafeArenaSetAllocatedMessage(MessageLite *message) = 0;
     virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0;
+    virtual MessageLite* UnsafeArenaReleaseMessage(
+        const MessageLite& prototype) = 0;
 
     virtual bool IsInitialized() const = 0;
     virtual int ByteSize() const = 0;
@@ -524,6 +540,9 @@
   };
 
 
+  // Merges existing Extension from other_extension
+  void InternalExtensionMergeFrom(int number, const Extension& other_extension);
+
   // Returns true and fills field_number and extension if extension is found.
   // Note to support packed repeated field compatibility, it also fills whether
   // the tag on wire is packed, which can be different from
@@ -563,13 +582,16 @@
   bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
                          Extension** result);
 
+  // Gets the repeated extension for the given descriptor, creating it if
+  // it does not exist.
+  Extension* MaybeNewRepeatedExtension(const FieldDescriptor* descriptor);
+
   // Parse a single MessageSet item -- called just after the item group start
   // tag has been read.
   bool ParseMessageSetItem(io::CodedInputStream* input,
                            ExtensionFinder* extension_finder,
                            MessageSetFieldSkipper* field_skipper);
 
-
   // Hack:  RepeatedPtrFieldBase declares ExtensionSet as a friend.  This
   //   friendship should automatically extend to ExtensionSet::Extension, but
   //   unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
@@ -587,7 +609,7 @@
   // for 100 elements or more.  Also, we want AppendToList() to order fields
   // by field number.
   std::map<int, Extension> extensions_;
-
+  ::google::protobuf::Arena* arena_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
 };
 
@@ -702,15 +724,13 @@
   static const RepeatedFieldType* GetDefaultRepeatedField();
 };
 
-// Declared here so that this can be friended below.
-void InitializeDefaultRepeatedFields();
-void DestroyDefaultRepeatedFields();
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_;
 
 class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
  private:
   template<typename Type> friend class RepeatedPrimitiveTypeTraits;
-  friend void InitializeDefaultRepeatedFields();
-  friend void DestroyDefaultRepeatedFields();
+  static void InitializeDefaultRepeatedFields();
+  static void DestroyDefaultRepeatedFields();
   static const RepeatedField<int32>* default_repeated_field_int32_;
   static const RepeatedField<int64>* default_repeated_field_int64_;
   static const RepeatedField<uint32>* default_repeated_field_uint32_;
@@ -745,6 +765,9 @@
 }                                                                          \
 template<> inline const RepeatedField<TYPE>*                               \
     RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() {         \
+  ::google::protobuf::GoogleOnceInit(                                                          \
+      &repeated_primitive_generic_type_traits_once_init_,                  \
+      &RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \
   return RepeatedPrimitiveGenericTypeTraits::                              \
       default_repeated_field_##TYPE##_;                                    \
 }                                                                          \
@@ -798,6 +821,8 @@
   }
 };
 
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_;
+
 class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
  public:
   typedef const string& ConstType;
@@ -841,12 +866,14 @@
   }
 
   static const RepeatedFieldType* GetDefaultRepeatedField() {
+    ::google::protobuf::GoogleOnceInit(&repeated_string_type_traits_once_init_,
+                   &InitializeDefaultRepeatedFields);
     return default_repeated_field_;
   }
 
  private:
-  friend void InitializeDefaultRepeatedFields();
-  friend void DestroyDefaultRepeatedFields();
+  static void InitializeDefaultRepeatedFields();
+  static void DestroyDefaultRepeatedFields();
   static const RepeatedFieldType *default_repeated_field_;
 };
 
@@ -1005,6 +1032,8 @@
   static const RepeatedFieldType* GetDefaultRepeatedField();
 };
 
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_once_init_;
+
 // This class exists only to hold a generic default empty repeated field for all
 // message-type repeated field extensions.
 class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits {
@@ -1012,14 +1041,17 @@
   typedef RepeatedPtrField< ::google::protobuf::MessageLite*> RepeatedFieldType;
  private:
   template<typename Type> friend class RepeatedMessageTypeTraits;
-  friend void InitializeDefaultRepeatedFields();
-  friend void DestroyDefaultRepeatedFields();
+  static void InitializeDefaultRepeatedFields();
+  static void DestroyDefaultRepeatedFields();
   static const RepeatedFieldType* default_repeated_field_;
 };
 
 template<typename Type> inline
     const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
     RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
+  ::google::protobuf::GoogleOnceInit(
+      &repeated_message_generic_type_traits_once_init_,
+      &RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields);
   return reinterpret_cast<const RepeatedFieldType*>(
       RepeatedMessageGenericTypeTraits::default_repeated_field_);
 }
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index a50efac..82e3e09 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -91,9 +91,10 @@
   const Descriptor* containing_type_;
 };
 
-void ExtensionSet::AppendToList(const Descriptor* containing_type,
-                                const DescriptorPool* pool,
-                                std::vector<const FieldDescriptor*>* output) const {
+void ExtensionSet::AppendToList(
+    const Descriptor* containing_type,
+    const DescriptorPool* pool,
+    std::vector<const FieldDescriptor*>* output) const {
   for (map<int, Extension>::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     bool has = false;
@@ -169,7 +170,7 @@
     const MessageLite* prototype =
         factory->GetPrototype(descriptor->message_type());
     extension->is_lazy = false;
-    extension->message_value = prototype->New();
+    extension->message_value = prototype->New(arena_);
     extension->is_cleared = false;
     return extension->message_value;
   } else {
@@ -196,27 +197,39 @@
     if (iter->second.is_lazy) {
       ret = iter->second.lazymessage_value->ReleaseMessage(
           *factory->GetPrototype(descriptor->message_type()));
-      delete iter->second.lazymessage_value;
+      if (arena_ == NULL) {
+        delete iter->second.lazymessage_value;
+      }
     } else {
-      ret = iter->second.message_value;
+      if (arena_ != NULL) {
+        ret = (iter->second.message_value)->New();
+        ret->CheckTypeAndMergeFrom(*(iter->second.message_value));
+      } else {
+        ret = iter->second.message_value;
+      }
     }
     extensions_.erase(descriptor->number());
     return ret;
   }
 }
 
-MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
-                                      MessageFactory* factory) {
+ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) {
   Extension* extension;
   if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
     extension->type = descriptor->type();
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
     extension->is_repeated = true;
     extension->repeated_message_value =
-      new RepeatedPtrField<MessageLite>();
+        ::google::protobuf::Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
   }
+  return extension;
+}
+
+MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
+                                      MessageFactory* factory) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
 
   // RepeatedPtrField<Message> does not know how to Add() since it cannot
   // allocate an abstract object, so we have to be tricky.
@@ -230,12 +243,19 @@
     } else {
       prototype = &extension->repeated_message_value->Get(0);
     }
-    result = prototype->New();
+    result = prototype->New(arena_);
     extension->repeated_message_value->AddAllocated(result);
   }
   return result;
 }
 
+void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor,
+                                       MessageLite* new_entry) {
+  Extension* extension = MaybeNewRepeatedExtension(descriptor);
+
+  extension->repeated_message_value->AddAllocated(new_entry);
+}
+
 static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
   return reinterpret_cast<const EnumDescriptor*>(arg)
       ->FindValueByNumber(number) != NULL;
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index 8a00baf..f40fcbc 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -37,12 +37,14 @@
 #include <google/protobuf/unittest_mset.pb.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/arena.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/testing/googletest.h>
@@ -172,7 +174,7 @@
 }
 
 TEST(ExtensionSetTest, ReleaseExtension) {
-  unittest::TestMessageSet message;
+  proto2_wireformat_unittest::TestMessageSet message;
   EXPECT_FALSE(message.HasExtension(
       unittest::TestMessageSetExtension1::message_set_extension));
   // Add a extension using SetAllocatedExtension
@@ -319,6 +321,116 @@
   TestUtil::ExpectAllExtensionsSet(message2);
 }
 
+TEST(ExtensionSetTest, ArenaSetAllExtension) {
+  ::google::protobuf::Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+}
+
+TEST(ExtensionSetTest, ArenaCopyConstructor) {
+  ::google::protobuf::Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  unittest::TestAllExtensions message2(*message1);
+  arena1.Reset();
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaMergeFrom) {
+  ::google::protobuf::Arena arena1;
+  unittest::TestAllExtensions* message1 =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  TestUtil::SetAllExtensions(message1);
+  unittest::TestAllExtensions message2;
+  message2.MergeFrom(*message1);
+  arena1.Reset();
+  TestUtil::ExpectAllExtensionsSet(message2);
+}
+
+TEST(ExtensionSetTest, ArenaSetAllocatedMessageAndRelease) {
+  ::google::protobuf::Arena arena;
+  unittest::TestAllExtensions* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  EXPECT_FALSE(message->HasExtension(
+      unittest::optional_foreign_message_extension));
+  // Add a extension using SetAllocatedExtension
+  unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
+  message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
+                                 foreign_message);
+  // foreign_message is now owned by the arena.
+  EXPECT_EQ(foreign_message,
+            message->MutableExtension(
+                unittest::optional_foreign_message_extension));
+
+  // Underlying message is copied, and returned.
+  unittest::ForeignMessage* released_message = message->ReleaseExtension(
+      unittest::optional_foreign_message_extension);
+  delete released_message;
+  EXPECT_FALSE(message->HasExtension(
+      unittest::optional_foreign_message_extension));
+}
+
+TEST(ExtensionSetTest, SwapExtensionBothFullWithArena) {
+  ::google::protobuf::Arena arena1;
+  google::protobuf::scoped_ptr<google::protobuf::Arena> arena2(new ::google::protobuf::Arena());
+
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  unittest::TestAllExtensions* message2 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(arena2.get());
+
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::SetAllExtensions(message2);
+  message1->SetExtension(unittest::optional_int32_extension, 1);
+  message2->SetExtension(unittest::optional_int32_extension, 2);
+  message1->Swap(message2);
+  EXPECT_EQ(2, message1->GetExtension(unittest::optional_int32_extension));
+  EXPECT_EQ(1, message2->GetExtension(unittest::optional_int32_extension));
+  // Re-set the original values so ExpectAllExtensionsSet is happy.
+  message1->SetExtension(unittest::optional_int32_extension, 101);
+  message2->SetExtension(unittest::optional_int32_extension, 101);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+  arena2.reset(NULL);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  // Test corner cases, when one is empty and other is not.
+  ::google::protobuf::Arena arena3, arena4;
+
+  unittest::TestAllExtensions* message3 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena3);
+  unittest::TestAllExtensions* message4 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena4);
+  TestUtil::SetAllExtensions(message3);
+  message3->Swap(message4);
+  arena3.Reset();
+  TestUtil::ExpectAllExtensionsSet(*message4);
+}
+
+TEST(ExtensionSetTest, SwapFieldsOfExtensionBothFullWithArena) {
+  google::protobuf::Arena arena1;
+  google::protobuf::Arena* arena2 = new ::google::protobuf::Arena();
+
+  unittest::TestAllExtensions* message1 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(&arena1);
+  unittest::TestAllExtensions* message2 =
+      Arena::CreateMessage<unittest::TestAllExtensions>(arena2);
+
+  TestUtil::SetAllExtensions(message1);
+  TestUtil::SetAllExtensions(message2);
+
+  const Reflection* reflection = message1->GetReflection();
+  vector<const FieldDescriptor*> fields;
+  reflection->ListFields(*message1, &fields);
+  reflection->SwapFields(message1, message2, fields);
+  TestUtil::ExpectAllExtensionsSet(*message1);
+  TestUtil::ExpectAllExtensionsSet(*message2);
+  delete arena2;
+  TestUtil::ExpectAllExtensionsSet(*message1);
+}
+
 TEST(ExtensionSetTest, SwapExtensionWithSelf) {
   unittest::TestAllExtensions message1;
 
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
new file mode 100644
index 0000000..c49ebce
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -0,0 +1,405 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/field_mask.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* FieldMask_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FieldMask_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/field_mask.proto");
+  GOOGLE_CHECK(file != NULL);
+  FieldMask_descriptor_ = file->message_type(0);
+  static const int FieldMask_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldMask, paths_),
+  };
+  FieldMask_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FieldMask_descriptor_,
+      FieldMask::default_instance_,
+      FieldMask_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(FieldMask),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldMask, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldMask, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FieldMask_descriptor_, &FieldMask::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2ffield_5fmask_2eproto() {
+  delete FieldMask::default_instance_;
+  delete FieldMask_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n google/protobuf/field_mask.proto\022\017goog"
+    "le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
+    "Q\n\023com.google.protobufB\016FieldMaskProtoP\001"
+    "\240\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTyp"
+    "esb\006proto3", 170);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/field_mask.proto", &protobuf_RegisterTypes);
+  FieldMask::default_instance_ = new FieldMask();
+  FieldMask::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2ffield_5fmask_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2ffield_5fmask_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2ffield_5fmask_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2ffield_5fmask_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FieldMask::kPathsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FieldMask::FieldMask()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.FieldMask)
+}
+
+void FieldMask::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+FieldMask::FieldMask(const FieldMask& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldMask)
+}
+
+void FieldMask::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+}
+
+FieldMask::~FieldMask() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FieldMask)
+  SharedDtor();
+}
+
+void FieldMask::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void FieldMask::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FieldMask::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FieldMask_descriptor_;
+}
+
+const FieldMask& FieldMask::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+  return *default_instance_;
+}
+
+FieldMask* FieldMask::default_instance_ = NULL;
+
+FieldMask* FieldMask::New(::google::protobuf::Arena* arena) const {
+  FieldMask* n = new FieldMask;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void FieldMask::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
+  paths_.Clear();
+}
+
+bool FieldMask::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.FieldMask)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated string paths = 1;
+      case 1: {
+        if (tag == 10) {
+         parse_paths:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_paths()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->paths(this->paths_size() - 1).data(),
+            this->paths(this->paths_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.FieldMask.paths"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_paths;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.FieldMask)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.FieldMask)
+  return false;
+#undef DO_
+}
+
+void FieldMask::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.FieldMask)
+  // repeated string paths = 1;
+  for (int i = 0; i < this->paths_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->paths(i).data(), this->paths(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.FieldMask.paths");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      1, this->paths(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.FieldMask)
+}
+
+::google::protobuf::uint8* FieldMask::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
+  // repeated string paths = 1;
+  for (int i = 0; i < this->paths_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->paths(i).data(), this->paths(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.FieldMask.paths");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(1, this->paths(i), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
+  return target;
+}
+
+int FieldMask::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask)
+  int total_size = 0;
+
+  // repeated string paths = 1;
+  total_size += 1 * this->paths_size();
+  for (int i = 0; i < this->paths_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->paths(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FieldMask::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldMask)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FieldMask* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldMask)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldMask)
+    MergeFrom(*source);
+  }
+}
+
+void FieldMask::MergeFrom(const FieldMask& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  paths_.MergeFrom(from.paths_);
+}
+
+void FieldMask::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldMask)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FieldMask::CopyFrom(const FieldMask& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FieldMask::IsInitialized() const {
+
+  return true;
+}
+
+void FieldMask::Swap(FieldMask* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FieldMask::InternalSwap(FieldMask* other) {
+  paths_.UnsafeArenaSwap(&other->paths_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FieldMask::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FieldMask_descriptor_;
+  metadata.reflection = FieldMask_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldMask
+
+// repeated string paths = 1;
+int FieldMask::paths_size() const {
+  return paths_.size();
+}
+void FieldMask::clear_paths() {
+  paths_.Clear();
+}
+ const ::std::string& FieldMask::paths(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
+  return paths_.Get(index);
+}
+ ::std::string* FieldMask::mutable_paths(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldMask.paths)
+  return paths_.Mutable(index);
+}
+ void FieldMask::set_paths(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+  paths_.Mutable(index)->assign(value);
+}
+ void FieldMask::set_paths(int index, const char* value) {
+  paths_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldMask.paths)
+}
+ void FieldMask::set_paths(int index, const char* value, size_t size) {
+  paths_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths)
+}
+ ::std::string* FieldMask::add_paths() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
+  return paths_.Add();
+}
+ void FieldMask::add_paths(const ::std::string& value) {
+  paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+ void FieldMask::add_paths(const char* value) {
+  paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FieldMask.paths)
+}
+ void FieldMask::add_paths(const char* value, size_t size) {
+  paths_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FieldMask.paths)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FieldMask::paths() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldMask.paths)
+  return paths_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+FieldMask::mutable_paths() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldMask.paths)
+  return &paths_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
new file mode 100644
index 0000000..f5e0b65
--- /dev/null
+++ b/src/google/protobuf/field_mask.pb.h
@@ -0,0 +1,202 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2ffield_5fmask_2eproto();
+
+class FieldMask;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message {
+ public:
+  FieldMask();
+  virtual ~FieldMask();
+
+  FieldMask(const FieldMask& from);
+
+  inline FieldMask& operator=(const FieldMask& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FieldMask& default_instance();
+
+  void Swap(FieldMask* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FieldMask* New() const { return New(NULL); }
+
+  FieldMask* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FieldMask& from);
+  void MergeFrom(const FieldMask& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FieldMask* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated string paths = 1;
+  int paths_size() const;
+  void clear_paths();
+  static const int kPathsFieldNumber = 1;
+  const ::std::string& paths(int index) const;
+  ::std::string* mutable_paths(int index);
+  void set_paths(int index, const ::std::string& value);
+  void set_paths(int index, const char* value);
+  void set_paths(int index, const char* value, size_t size);
+  ::std::string* add_paths();
+  void add_paths(const ::std::string& value);
+  void add_paths(const char* value);
+  void add_paths(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& paths() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_paths();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> paths_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ffield_5fmask_2eproto();
+
+  void InitAsDefaultInstance();
+  static FieldMask* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// FieldMask
+
+// repeated string paths = 1;
+inline int FieldMask::paths_size() const {
+  return paths_.size();
+}
+inline void FieldMask::clear_paths() {
+  paths_.Clear();
+}
+inline const ::std::string& FieldMask::paths(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
+  return paths_.Get(index);
+}
+inline ::std::string* FieldMask::mutable_paths(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldMask.paths)
+  return paths_.Mutable(index);
+}
+inline void FieldMask::set_paths(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
+  paths_.Mutable(index)->assign(value);
+}
+inline void FieldMask::set_paths(int index, const char* value) {
+  paths_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::set_paths(int index, const char* value, size_t size) {
+  paths_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths)
+}
+inline ::std::string* FieldMask::add_paths() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
+  return paths_.Add();
+}
+inline void FieldMask::add_paths(const ::std::string& value) {
+  paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(const char* value) {
+  paths_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.FieldMask.paths)
+}
+inline void FieldMask::add_paths(const char* value, size_t size) {
+  paths_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.FieldMask.paths)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FieldMask::paths() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.FieldMask.paths)
+  return paths_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+FieldMask::mutable_paths() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldMask.paths)
+  return &paths_;
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
new file mode 100644
index 0000000..6af6dbe
--- /dev/null
+++ b/src/google/protobuf/field_mask.proto
@@ -0,0 +1,194 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option java_generate_equals_and_hash = true;
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+//     paths: "f.a"
+//     paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+//
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//         x : 2
+//       }
+//       y : 13
+//     }
+//     z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (their value will be set to the default, and omitted in proto text
+// output):
+//
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//       }
+//     }
+//
+// A repeated field is not allowed except at the last position of a
+// field mask.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily apply to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API.  In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+//
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+//
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+//
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+//     message Profile {
+//       User user = 1;
+//       Photo photo = 2;
+//     }
+//     message User {
+//       string display_name = 1;
+//       string address = 2;
+//     }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+//     mask {
+//       paths: "user.display_name"
+//       paths: "photo"
+//     }
+//
+// In JSON, the same mask is represented as below:
+//
+//     {
+//       mask: "user.displayName,photo"
+//     }
+//
+// # Field Masks and Oneof Fields
+//
+// Field masks treat fields in oneofs just as regular fields. Consider the
+// following message:
+//
+//     message SampleMessage {
+//       oneof test_oneof {
+//         string name = 4;
+//         SubMessage sub_message = 9;
+//       }
+//     }
+//
+// The field mask can be:
+//
+//     mask {
+//       paths: "name"
+//     }
+//
+// Or:
+//
+//     mask {
+//       paths: "sub_message"
+//     }
+//
+// Note that oneof type names ("test_oneof" in this case) cannot be used in
+// paths.
+message FieldMask {
+  // The set of field mask paths.
+  repeated string paths = 1;
+}
diff --git a/src/google/protobuf/generated_enum_reflection.h b/src/google/protobuf/generated_enum_reflection.h
index 3852cea..fdcdc27 100644
--- a/src/google/protobuf/generated_enum_reflection.h
+++ b/src/google/protobuf/generated_enum_reflection.h
@@ -42,6 +42,7 @@
 #include <string>
 
 #include <google/protobuf/stubs/template_util.h>
+#include <google/protobuf/generated_enum_util.h>
 
 namespace google {
 namespace protobuf {
@@ -50,10 +51,6 @@
 
 namespace protobuf {
 
-// This type trait can be used to cause templates to only match proto2 enum
-// types.
-template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
-
 // Returns the EnumDescriptor for enum type E, which must be a
 // proto-declared enum type.  Code generated by the protocol compiler
 // will include specializations of this template for each enum type declared.
diff --git a/src/google/protobuf/generated_enum_util.h b/src/google/protobuf/generated_enum_util.h
new file mode 100644
index 0000000..e424205
--- /dev/null
+++ b/src/google/protobuf/generated_enum_util.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+
+#include <google/protobuf/stubs/template_util.h>
+
+namespace google {
+namespace protobuf {
+
+// This type trait can be used to cause templates to only match proto2 enum
+// types.
+template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 536de7d..2313181 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -34,13 +34,17 @@
 
 #include <algorithm>
 #include <set>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/generated_message_reflection.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_util.h>
+
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/repeated_field.h>
+
 
 #define GOOGLE_PROTOBUF_HAS_ONEOF
 
@@ -48,17 +52,11 @@
 namespace protobuf {
 namespace internal {
 
-int StringSpaceUsedExcludingSelf(const string& str) {
-  const void* start = &str;
-  const void* end = &str + 1;
-
-  if (start <= str.data() && str.data() < end) {
-    // The string's data is stored inside the string object itself.
-    return 0;
-  } else {
-    return str.capacity();
-  }
+namespace {
+bool IsMapFieldInApi(const FieldDescriptor* field) {
+  return field->is_map();
 }
+}  // anonymous namespace
 
 bool ParseNamedEnum(const EnumDescriptor* descriptor,
                     const string& name,
@@ -74,6 +72,12 @@
   return (d == NULL ? GetEmptyString() : d->name());
 }
 
+namespace {
+inline bool SupportsArenas(const Descriptor* descriptor) {
+  return descriptor->file()->options().cc_enable_arenas();
+}
+}  // anonymous namespace
+
 // ===================================================================
 // Helpers for reporting usage errors (e.g. trying to use GetInt32() on
 // a string field).
@@ -177,13 +181,17 @@
     int extensions_offset,
     const DescriptorPool* descriptor_pool,
     MessageFactory* factory,
-    int object_size)
+    int object_size,
+    int arena_offset,
+    int is_default_instance_offset)
   : descriptor_       (descriptor),
     default_instance_ (default_instance),
     offsets_          (offsets),
     has_bits_offset_  (has_bits_offset),
     unknown_fields_offset_(unknown_fields_offset),
     extensions_offset_(extensions_offset),
+    arena_offset_     (arena_offset),
+    is_default_instance_offset_(is_default_instance_offset),
     object_size_      (object_size),
     descriptor_pool_  ((descriptor_pool == NULL) ?
                          DescriptorPool::generated_pool() :
@@ -202,7 +210,9 @@
     int oneof_case_offset,
     const DescriptorPool* descriptor_pool,
     MessageFactory* factory,
-    int object_size)
+    int object_size,
+    int arena_offset,
+    int is_default_instance_offset)
   : descriptor_       (descriptor),
     default_instance_ (default_instance),
     default_oneof_instance_ (default_oneof_instance),
@@ -211,6 +221,8 @@
     oneof_case_offset_(oneof_case_offset),
     unknown_fields_offset_(unknown_fields_offset),
     extensions_offset_(extensions_offset),
+    arena_offset_     (arena_offset),
+    is_default_instance_offset_(is_default_instance_offset),
     object_size_      (object_size),
     descriptor_pool_  ((descriptor_pool == NULL) ?
                          DescriptorPool::generated_pool() :
@@ -220,14 +232,45 @@
 
 GeneratedMessageReflection::~GeneratedMessageReflection() {}
 
+namespace {
+UnknownFieldSet* empty_unknown_field_set_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(empty_unknown_field_set_once_);
+
+void DeleteEmptyUnknownFieldSet() {
+  delete empty_unknown_field_set_;
+  empty_unknown_field_set_ = NULL;
+}
+
+void InitEmptyUnknownFieldSet() {
+  empty_unknown_field_set_ = new UnknownFieldSet;
+  internal::OnShutdown(&DeleteEmptyUnknownFieldSet);
+}
+
+const UnknownFieldSet& GetEmptyUnknownFieldSet() {
+  ::google::protobuf::GoogleOnceInit(&empty_unknown_field_set_once_, &InitEmptyUnknownFieldSet);
+  return *empty_unknown_field_set_;
+}
+}  // namespace
+
 const UnknownFieldSet& GeneratedMessageReflection::GetUnknownFields(
     const Message& message) const {
+  if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+    return GetEmptyUnknownFieldSet();
+  }
+  if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) {
+    return GetInternalMetadataWithArena(message).unknown_fields();
+  }
   const void* ptr = reinterpret_cast<const uint8*>(&message) +
                     unknown_fields_offset_;
   return *reinterpret_cast<const UnknownFieldSet*>(ptr);
 }
+
 UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields(
     Message* message) const {
+  if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) {
+    return MutableInternalMetadataWithArena(message)->
+        mutable_unknown_fields();
+  }
   void* ptr = reinterpret_cast<uint8*>(message) + unknown_fields_offset_;
   return reinterpret_cast<UnknownFieldSet*>(ptr);
 }
@@ -276,11 +319,17 @@
           break;
 
         case FieldDescriptor::CPPTYPE_MESSAGE:
-          // We don't know which subclass of RepeatedPtrFieldBase the type is,
-          // so we use RepeatedPtrFieldBase directly.
-          total_size +=
-              GetRaw<RepeatedPtrFieldBase>(message, field)
-                .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
+          if (IsMapFieldInApi(field)) {
+            total_size +=
+                GetRaw<MapFieldBase>(message, field).SpaceUsedExcludingSelf();
+          } else {
+            // We don't know which subclass of RepeatedPtrFieldBase the type is,
+            // so we use RepeatedPtrFieldBase directly.
+            total_size +=
+                GetRaw<RepeatedPtrFieldBase>(message, field)
+                  .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
+          }
+
           break;
       }
     } else {
@@ -303,12 +352,13 @@
           switch (field->options().ctype()) {
             default:  // TODO(kenton):  Support other string reps.
             case FieldOptions::STRING: {
-              const string* ptr = GetField<const string*>(message, field);
-
               // Initially, the string points to the default value stored in
               // the prototype. Only count the string if it has been changed
               // from the default value.
-              const string* default_ptr = DefaultRaw<const string*>(field);
+              const string* default_ptr =
+                  &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+              const string* ptr =
+                  &GetField<ArenaStringPtr>(message, field).Get(default_ptr);
 
               if (ptr != default_ptr) {
                 // string fields are represented by just a pointer, so also
@@ -362,9 +412,27 @@
 #undef SWAP_ARRAYS
 
       case FieldDescriptor::CPPTYPE_STRING:
+        switch (field->options().ctype()) {
+          default:  // TODO(kenton):  Support other string reps.
+          case FieldOptions::STRING:
+            MutableRaw<RepeatedPtrFieldBase>(message1, field)->
+                Swap<GenericTypeHandler<string> >(
+                    MutableRaw<RepeatedPtrFieldBase>(message2, field));
+            break;
+        }
+        break;
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        MutableRaw<RepeatedPtrFieldBase>(message1, field)->Swap(
-            MutableRaw<RepeatedPtrFieldBase>(message2, field));
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message1, field)->
+            MutableRepeatedField()->
+              Swap<GenericTypeHandler<google::protobuf::Message> >(
+                MutableRaw<MapFieldBase>(message2, field)->
+                  MutableRepeatedField());
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message1, field)->
+            Swap<GenericTypeHandler<google::protobuf::Message> >(
+              MutableRaw<RepeatedPtrFieldBase>(message2, field));
+        }
         break;
 
       default:
@@ -388,16 +456,50 @@
       SWAP_VALUES(ENUM  , int   );
 #undef SWAP_VALUES
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        std::swap(*MutableRaw<Message*>(message1, field),
-                  *MutableRaw<Message*>(message2, field));
+        if (GetArena(message1) == GetArena(message2)) {
+          std::swap(*MutableRaw<Message*>(message1, field),
+                    *MutableRaw<Message*>(message2, field));
+        } else {
+          Message** sub_msg1 = MutableRaw<Message*>(message1, field);
+          Message** sub_msg2 = MutableRaw<Message*>(message2, field);
+          if (*sub_msg1 == NULL && *sub_msg2 == NULL) break;
+          if (*sub_msg1 && *sub_msg2) {
+            (*sub_msg1)->GetReflection()->Swap(*sub_msg1, *sub_msg2);
+            break;
+          }
+          if (*sub_msg1 == NULL) {
+            *sub_msg1 = (*sub_msg2)->New(message1->GetArena());
+            (*sub_msg1)->CopyFrom(**sub_msg2);
+            ClearField(message2, field);
+          } else {
+            *sub_msg2 = (*sub_msg1)->New(message2->GetArena());
+            (*sub_msg2)->CopyFrom(**sub_msg1);
+            ClearField(message1, field);
+          }
+        }
         break;
 
       case FieldDescriptor::CPPTYPE_STRING:
         switch (field->options().ctype()) {
           default:  // TODO(kenton):  Support other string reps.
           case FieldOptions::STRING:
-            std::swap(*MutableRaw<string*>(message1, field),
-                      *MutableRaw<string*>(message2, field));
+            {
+              Arena* arena1 = GetArena(message1);
+              Arena* arena2 = GetArena(message2);
+              ArenaStringPtr* string1 =
+                  MutableRaw<ArenaStringPtr>(message1, field);
+              ArenaStringPtr* string2 =
+                  MutableRaw<ArenaStringPtr>(message2, field);
+              if (arena1 == arena2) {
+                string1->Swap(string2);
+              } else {
+                const string* default_ptr =
+                    &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+                const string temp = string1->Get(default_ptr);
+                string1->Set(default_ptr, string2->Get(default_ptr), arena1);
+                string2->Set(default_ptr, temp, arena2);
+              }
+            }
             break;
         }
         break;
@@ -423,11 +525,11 @@
   double temp_double;
   bool temp_bool;
   int temp_int;
-  Message* temp_message;
+  Message* temp_message = NULL;
   string temp_string;
 
   // Stores message1's oneof field to a temp variable.
-  const FieldDescriptor* field1;
+  const FieldDescriptor* field1 = NULL;
   if (oneof_case1 > 0) {
     field1 = descriptor_->FindFieldByNumber(oneof_case1);
     //oneof_descriptor->field(oneof_case1);
@@ -549,12 +651,29 @@
     << "\").  Note that the exact same class is required; not just the same "
        "descriptor.";
 
-  uint32* has_bits1 = MutableHasBits(message1);
-  uint32* has_bits2 = MutableHasBits(message2);
-  int has_bits_size = (descriptor_->field_count() + 31) / 32;
+  // Check that both messages are in the same arena (or both on the heap). We
+  // need to copy all data if not, due to ownership semantics.
+  if (GetArena(message1) != GetArena(message2)) {
+    // Slow copy path.
+    // Use our arena as temp space, if available.
+    Message* temp = message1->New(GetArena(message1));
+    temp->MergeFrom(*message1);
+    message1->CopyFrom(*message2);
+    message2->CopyFrom(*temp);
+    if (GetArena(message1) == NULL) {
+      delete temp;
+    }
+    return;
+  }
 
-  for (int i = 0; i < has_bits_size; i++) {
-    std::swap(has_bits1[i], has_bits2[i]);
+  if (has_bits_offset_ != -1) {
+    uint32* has_bits1 = MutableHasBits(message1);
+    uint32* has_bits2 = MutableHasBits(message2);
+    int has_bits_size = (descriptor_->field_count() + 31) / 32;
+
+    for (int i = 0; i < has_bits_size; i++) {
+      std::swap(has_bits1[i], has_bits2[i]);
+    }
   }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -667,7 +786,11 @@
 
       case FieldDescriptor::CPPTYPE_STRING:
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+        if (IsMapFieldInApi(field)) {
+          return GetRaw<MapFieldBase>(message, field).GetRepeatedField().size();
+        } else {
+          return GetRaw<RepeatedPtrFieldBase>(message, field).size();
+        }
     }
 
     GOOGLE_LOG(FATAL) << "Can't get here.";
@@ -715,23 +838,28 @@
         case FieldDescriptor::CPPTYPE_STRING: {
           switch (field->options().ctype()) {
             default:  // TODO(kenton):  Support other string reps.
-            case FieldOptions::STRING:
-              const string* default_ptr = DefaultRaw<const string*>(field);
-              string** value = MutableRaw<string*>(message, field);
-              if (*value != default_ptr) {
-                if (field->has_default_value()) {
-                  (*value)->assign(field->default_value_string());
-                } else {
-                  (*value)->clear();
-                }
-              }
+            case FieldOptions::STRING: {
+              const string* default_ptr =
+                  &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+              MutableRaw<ArenaStringPtr>(message, field)->Destroy(default_ptr,
+                  GetArena(message));
               break;
+            }
           }
           break;
         }
 
         case FieldDescriptor::CPPTYPE_MESSAGE:
-          (*MutableRaw<Message*>(message, field))->Clear();
+          if (has_bits_offset_ == -1) {
+            // Proto3 does not have has-bits and we need to set a message field
+            // to NULL in order to indicate its un-presence.
+            if (GetArena(message) == NULL) {
+              delete *MutableRaw<Message*>(message, field);
+            }
+            *MutableRaw<Message*>(message, field) = NULL;
+          } else {
+            (*MutableRaw<Message*>(message, field))->Clear();
+          }
           break;
       }
     }
@@ -763,10 +891,16 @@
       }
 
       case FieldDescriptor::CPPTYPE_MESSAGE: {
-        // We don't know which subclass of RepeatedPtrFieldBase the type is,
-        // so we use RepeatedPtrFieldBase directly.
-        MutableRaw<RepeatedPtrFieldBase>(message, field)
-            ->Clear<GenericTypeHandler<Message> >();
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->Clear<GenericTypeHandler<Message> >();
+        } else {
+          // We don't know which subclass of RepeatedPtrFieldBase the type is,
+          // so we use RepeatedPtrFieldBase directly.
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
+              ->Clear<GenericTypeHandler<Message> >();
+        }
         break;
       }
     }
@@ -808,8 +942,14 @@
         break;
 
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        MutableRaw<RepeatedPtrFieldBase>(message, field)
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->RemoveLast<GenericTypeHandler<Message> >();
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
             ->RemoveLast<GenericTypeHandler<Message> >();
+        }
         break;
     }
   }
@@ -824,8 +964,14 @@
     return static_cast<Message*>(
         MutableExtensionSet(message)->ReleaseLast(field->number()));
   } else {
-    return MutableRaw<RepeatedPtrFieldBase>(message, field)
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->ReleaseLast<GenericTypeHandler<Message> >();
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
         ->ReleaseLast<GenericTypeHandler<Message> >();
+    }
   }
 }
 
@@ -859,8 +1005,14 @@
 
       case FieldDescriptor::CPPTYPE_STRING:
       case FieldDescriptor::CPPTYPE_MESSAGE:
-        MutableRaw<RepeatedPtrFieldBase>(message, field)
+        if (IsMapFieldInApi(field)) {
+          MutableRaw<MapFieldBase>(message, field)
+              ->MutableRepeatedField()
+              ->SwapElements(index1, index2);
+        } else {
+          MutableRaw<RepeatedPtrFieldBase>(message, field)
             ->SwapElements(index1, index2);
+        }
         break;
     }
   }
@@ -884,6 +1036,7 @@
   // Optimization:  The default instance never has any fields set.
   if (&message == default_instance_) return;
 
+  output->reserve(descriptor_->field_count());
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     if (field->is_repeated()) {
@@ -907,7 +1060,7 @@
   }
 
   // ListFields() must sort output by field number.
-  sort(output->begin(), output->end(), FieldNumberSorter());
+  std::sort(output->begin(), output->end(), FieldNumberSorter());
 }
 
 // -------------------------------------------------------------------
@@ -994,8 +1147,11 @@
   } else {
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
-      case FieldOptions::STRING:
-        return *GetField<const string*>(message, field);
+      case FieldOptions::STRING: {
+        const string* default_ptr =
+            &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+        return GetField<ArenaStringPtr>(message, field).Get(default_ptr);
+      }
     }
 
     GOOGLE_LOG(FATAL) << "Can't get here.";
@@ -1013,8 +1169,11 @@
   } else {
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
-      case FieldOptions::STRING:
-        return *GetField<const string*>(message, field);
+      case FieldOptions::STRING: {
+        const string* default_ptr =
+            &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+        return GetField<ArenaStringPtr>(message, field).Get(default_ptr);
+      }
     }
 
     GOOGLE_LOG(FATAL) << "Can't get here.";
@@ -1034,16 +1193,15 @@
     switch (field->options().ctype()) {
       default:  // TODO(kenton):  Support other string reps.
       case FieldOptions::STRING: {
+        const string* default_ptr =
+            &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
         if (field->containing_oneof() && !HasOneofField(*message, field)) {
           ClearOneof(message, field->containing_oneof());
-          *MutableField<string*>(message, field) = new string;
+          MutableField<ArenaStringPtr>(message, field)->UnsafeSetDefault(
+              default_ptr);
         }
-        string** ptr = MutableField<string*>(message, field);
-        if (*ptr == DefaultRaw<const string*>(field)) {
-          *ptr = new string(value);
-        } else {
-          (*ptr)->assign(value);
-        }
+        MutableField<ArenaStringPtr>(message, field)->Set(default_ptr,
+            value, GetArena(message));
         break;
       }
     }
@@ -1125,42 +1283,80 @@
 
 // -------------------------------------------------------------------
 
+inline bool CreateUnknownEnumValues(const FileDescriptor* file) {
+  return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
 const EnumValueDescriptor* GeneratedMessageReflection::GetEnum(
     const Message& message, const FieldDescriptor* field) const {
-  USAGE_CHECK_ALL(GetEnum, SINGULAR, ENUM);
+  // Usage checked by GetEnumValue.
+  int value = GetEnumValue(message, field);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
 
-  int value;
+int GeneratedMessageReflection::GetEnumValue(
+    const Message& message, const FieldDescriptor* field) const {
+  USAGE_CHECK_ALL(GetEnumValue, SINGULAR, ENUM);
+
+  int32 value;
   if (field->is_extension()) {
     value = GetExtensionSet(message).GetEnum(
       field->number(), field->default_value_enum()->number());
   } else {
     value = GetField<int>(message, field);
   }
-  const EnumValueDescriptor* result =
-    field->enum_type()->FindValueByNumber(value);
-  GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field "
-                        << field->full_name() << " of type "
-                        << field->enum_type()->full_name() << ".";
-  return result;
+  return value;
 }
 
 void GeneratedMessageReflection::SetEnum(
     Message* message, const FieldDescriptor* field,
     const EnumValueDescriptor* value) const {
-  USAGE_CHECK_ALL(SetEnum, SINGULAR, ENUM);
+  // Usage checked by SetEnumValue.
   USAGE_CHECK_ENUM_VALUE(SetEnum);
+  SetEnumValueInternal(message, field, value->number());
+}
 
+void GeneratedMessageReflection::SetEnumValue(
+    Message* message, const FieldDescriptor* field,
+    int value) const {
+  USAGE_CHECK_ALL(SetEnumValue, SINGULAR, ENUM);
+  if (!CreateUnknownEnumValues(descriptor_->file())) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == NULL) {
+      GOOGLE_LOG(DFATAL) << "SetEnumValue accepts only valid integer values: value "
+                  << value << " unexpected for field " << field->full_name();
+      // In production builds, DFATAL will not terminate the program, so we have
+      // to do something reasonable: just set the default value.
+      value = field->default_value_enum()->number();
+    }
+  }
+  SetEnumValueInternal(message, field, value);
+}
+
+void GeneratedMessageReflection::SetEnumValueInternal(
+    Message* message, const FieldDescriptor* field,
+    int value) const {
   if (field->is_extension()) {
     MutableExtensionSet(message)->SetEnum(field->number(), field->type(),
-                                          value->number(), field);
+                                          value, field);
   } else {
-    SetField<int>(message, field, value->number());
+    SetField<int>(message, field, value);
   }
 }
 
 const EnumValueDescriptor* GeneratedMessageReflection::GetRepeatedEnum(
     const Message& message, const FieldDescriptor* field, int index) const {
-  USAGE_CHECK_ALL(GetRepeatedEnum, REPEATED, ENUM);
+  // Usage checked by GetRepeatedEnumValue.
+  int value = GetRepeatedEnumValue(message, field, index);
+  return field->enum_type()->FindValueByNumberCreatingIfUnknown(value);
+}
+
+int GeneratedMessageReflection::GetRepeatedEnumValue(
+    const Message& message, const FieldDescriptor* field, int index) const {
+  USAGE_CHECK_ALL(GetRepeatedEnumValue, REPEATED, ENUM);
 
   int value;
   if (field->is_extension()) {
@@ -1168,41 +1364,89 @@
   } else {
     value = GetRepeatedField<int>(message, field, index);
   }
-  const EnumValueDescriptor* result =
-    field->enum_type()->FindValueByNumber(value);
-  GOOGLE_CHECK(result != NULL) << "Value " << value << " is not valid for field "
-                        << field->full_name() << " of type "
-                        << field->enum_type()->full_name() << ".";
-  return result;
+  return value;
 }
 
 void GeneratedMessageReflection::SetRepeatedEnum(
     Message* message,
     const FieldDescriptor* field, int index,
     const EnumValueDescriptor* value) const {
-  USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM);
+  // Usage checked by SetRepeatedEnumValue.
   USAGE_CHECK_ENUM_VALUE(SetRepeatedEnum);
+  SetRepeatedEnumValueInternal(message, field, index, value->number());
+}
 
+void GeneratedMessageReflection::SetRepeatedEnumValue(
+    Message* message,
+    const FieldDescriptor* field, int index,
+    int value) const {
+  USAGE_CHECK_ALL(SetRepeatedEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(descriptor_->file())) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == NULL) {
+      GOOGLE_LOG(DFATAL) << "SetRepeatedEnumValue accepts only valid integer values: "
+                  << "value " << value << " unexpected for field "
+                  << field->full_name();
+      // In production builds, DFATAL will not terminate the program, so we have
+      // to do something reasonable: just set the default value.
+      value = field->default_value_enum()->number();
+    }
+  }
+  SetRepeatedEnumValueInternal(message, field, index, value);
+}
+
+void GeneratedMessageReflection::SetRepeatedEnumValueInternal(
+    Message* message,
+    const FieldDescriptor* field, int index,
+    int value) const {
   if (field->is_extension()) {
     MutableExtensionSet(message)->SetRepeatedEnum(
-      field->number(), index, value->number());
+      field->number(), index, value);
   } else {
-    SetRepeatedField<int>(message, field, index, value->number());
+    SetRepeatedField<int>(message, field, index, value);
   }
 }
 
 void GeneratedMessageReflection::AddEnum(
     Message* message, const FieldDescriptor* field,
     const EnumValueDescriptor* value) const {
-  USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM);
+  // Usage checked by AddEnumValue.
   USAGE_CHECK_ENUM_VALUE(AddEnum);
+  AddEnumValueInternal(message, field, value->number());
+}
 
+void GeneratedMessageReflection::AddEnumValue(
+    Message* message, const FieldDescriptor* field,
+    int value) const {
+  USAGE_CHECK_ALL(AddEnum, REPEATED, ENUM);
+  if (!CreateUnknownEnumValues(descriptor_->file())) {
+    // Check that the value is valid if we don't support direct storage of
+    // unknown enum values.
+    const EnumValueDescriptor* value_desc =
+        field->enum_type()->FindValueByNumber(value);
+    if (value_desc == NULL) {
+      GOOGLE_LOG(DFATAL) << "AddEnumValue accepts only valid integer values: value "
+                  << value << " unexpected for field " << field->full_name();
+      // In production builds, DFATAL will not terminate the program, so we have
+      // to do something reasonable: just set the default value.
+      value = field->default_value_enum()->number();
+    }
+  }
+  AddEnumValueInternal(message, field, value);
+}
+
+void GeneratedMessageReflection::AddEnumValueInternal(
+    Message* message, const FieldDescriptor* field,
+    int value) const {
   if (field->is_extension()) {
     MutableExtensionSet(message)->AddEnum(field->number(), field->type(),
                                           field->options().packed(),
-                                          value->number(), field);
+                                          value, field);
   } else {
-    AddField<int>(message, field, value->number());
+    AddField<int>(message, field, value);
   }
 }
 
@@ -1232,6 +1476,8 @@
 Message* GeneratedMessageReflection::MutableMessage(
     Message* message, const FieldDescriptor* field,
     MessageFactory* factory) const {
+  USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+
   if (factory == NULL) factory = message_factory_;
 
   if (field->is_extension()) {
@@ -1246,7 +1492,7 @@
         ClearOneof(message, field->containing_oneof());
         result_holder = MutableField<Message*>(message, field);
         const Message* default_message = DefaultRaw<const Message*>(field);
-        *result_holder = default_message->New();
+        *result_holder = default_message->New(message->GetArena());
       }
     } else {
       SetBit(message, field);
@@ -1254,14 +1500,14 @@
 
     if (*result_holder == NULL) {
       const Message* default_message = DefaultRaw<const Message*>(field);
-      *result_holder = default_message->New();
+      *result_holder = default_message->New(message->GetArena());
     }
     result = *result_holder;
     return result;
   }
 }
 
-void GeneratedMessageReflection::SetAllocatedMessage(
+void GeneratedMessageReflection::UnsafeArenaSetAllocatedMessage(
     Message* message,
     Message* sub_message,
     const FieldDescriptor* field) const {
@@ -1288,12 +1534,42 @@
       SetBit(message, field);
     }
     Message** sub_message_holder = MutableRaw<Message*>(message, field);
-    delete *sub_message_holder;
+    if (GetArena(message) == NULL) {
+      delete *sub_message_holder;
+    }
     *sub_message_holder = sub_message;
   }
 }
 
-Message* GeneratedMessageReflection::ReleaseMessage(
+void GeneratedMessageReflection::SetAllocatedMessage(
+    Message* message,
+    Message* sub_message,
+    const FieldDescriptor* field) const {
+  // If message and sub-message are in different memory ownership domains
+  // (different arenas, or one is on heap and one is not), then we may need to
+  // do a copy.
+  if (sub_message != NULL &&
+      sub_message->GetArena() != message->GetArena()) {
+    if (sub_message->GetArena() == NULL && message->GetArena() != NULL) {
+      // Case 1: parent is on an arena and child is heap-allocated. We can add
+      // the child to the arena's Own() list to free on arena destruction, then
+      // set our pointer.
+      message->GetArena()->Own(sub_message);
+      UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+    } else {
+      // Case 2: all other cases. We need to make a copy. MutableMessage() will
+      // either get the existing message object, or instantiate a new one as
+      // appropriate w.r.t. our arena.
+      Message* sub_message_copy = MutableMessage(message, field);
+      sub_message_copy->CopyFrom(*sub_message);
+    }
+  } else {
+    // Same memory ownership domains.
+    UnsafeArenaSetAllocatedMessage(message, sub_message, field);
+  }
+}
+
+Message* GeneratedMessageReflection::UnsafeArenaReleaseMessage(
     Message* message,
     const FieldDescriptor* field,
     MessageFactory* factory) const {
@@ -1320,6 +1596,19 @@
   }
 }
 
+Message* GeneratedMessageReflection::ReleaseMessage(
+    Message* message,
+    const FieldDescriptor* field,
+    MessageFactory* factory) const {
+  Message* released = UnsafeArenaReleaseMessage(message, field, factory);
+  if (GetArena(message) != NULL && released != NULL) {
+    Message* copy_from_arena = released->New();
+    copy_from_arena->CopyFrom(*released);
+    released = copy_from_arena;
+  }
+  return released;
+}
+
 const Message& GeneratedMessageReflection::GetRepeatedMessage(
     const Message& message, const FieldDescriptor* field, int index) const {
   USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
@@ -1328,8 +1617,14 @@
     return static_cast<const Message&>(
         GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
   } else {
-    return GetRaw<RepeatedPtrFieldBase>(message, field)
-        .Get<GenericTypeHandler<Message> >(index);
+    if (IsMapFieldInApi(field)) {
+      return GetRaw<MapFieldBase>(message, field)
+          .GetRepeatedField()
+          .Get<GenericTypeHandler<Message> >(index);
+    } else {
+      return GetRaw<RepeatedPtrFieldBase>(message, field)
+          .Get<GenericTypeHandler<Message> >(index);
+    }
   }
 }
 
@@ -1342,8 +1637,14 @@
         MutableExtensionSet(message)->MutableRepeatedMessage(
           field->number(), index));
   } else {
-    return MutableRaw<RepeatedPtrFieldBase>(message, field)
+    if (IsMapFieldInApi(field)) {
+      return MutableRaw<MapFieldBase>(message, field)
+          ->MutableRepeatedField()
+          ->Mutable<GenericTypeHandler<Message> >(index);
+    } else {
+      return MutableRaw<RepeatedPtrFieldBase>(message, field)
         ->Mutable<GenericTypeHandler<Message> >(index);
+    }
   }
 }
 
@@ -1358,11 +1659,18 @@
     return static_cast<Message*>(
         MutableExtensionSet(message)->AddMessage(field, factory));
   } else {
+    Message* result = NULL;
+
     // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
     // know how to allocate one.
-    RepeatedPtrFieldBase* repeated =
-        MutableRaw<RepeatedPtrFieldBase>(message, field);
-    Message* result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
+    RepeatedPtrFieldBase* repeated = NULL;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
     if (result == NULL) {
       // We must allocate a new object.
       const Message* prototype;
@@ -1371,13 +1679,36 @@
       } else {
         prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
       }
-      result = prototype->New();
-      repeated->AddAllocated<GenericTypeHandler<Message> >(result);
+      result = prototype->New(message->GetArena());
+      // We can guarantee here that repeated and result are either both heap
+      // allocated or arena owned. So it is safe to call the unsafe version
+      // of AddAllocated.
+      repeated->UnsafeArenaAddAllocated<GenericTypeHandler<Message> >(result);
     }
+
     return result;
   }
 }
 
+void GeneratedMessageReflection::AddAllocatedMessage(
+    Message* message, const FieldDescriptor* field,
+    Message* new_entry) const {
+  USAGE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE);
+
+  if (field->is_extension()) {
+    MutableExtensionSet(message)->AddAllocatedMessage(field, new_entry);
+  } else {
+    RepeatedPtrFieldBase* repeated = NULL;
+    if (IsMapFieldInApi(field)) {
+      repeated =
+          MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField();
+    } else {
+      repeated = MutableRaw<RepeatedPtrFieldBase>(message, field);
+    }
+    repeated->AddAllocated<GenericTypeHandler<Message> >(new_entry);
+  }
+}
+
 void* GeneratedMessageReflection::MutableRawRepeatedField(
     Message* message, const FieldDescriptor* field,
     FieldDescriptor::CppType cpptype,
@@ -1390,11 +1721,49 @@
     GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch";
   if (desc != NULL)
     GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
-  if (field->is_extension())
+  if (field->is_extension()) {
     return MutableExtensionSet(message)->MutableRawRepeatedField(
         field->number(), field->type(), field->is_packed(), field);
-  else
+  } else {
+    // Trigger transform for MapField
+    if (IsMapFieldInApi(field)) {
+      return reinterpret_cast<MapFieldBase*>(reinterpret_cast<uint8*>(message) +
+                                             offsets_[field->index()])
+          ->MutableRepeatedField();
+    }
     return reinterpret_cast<uint8*>(message) + offsets_[field->index()];
+  }
+}
+
+const void* GeneratedMessageReflection::GetRawRepeatedField(
+    const Message& message, const FieldDescriptor* field,
+    FieldDescriptor::CppType cpptype,
+    int ctype, const Descriptor* desc) const {
+  USAGE_CHECK_REPEATED("GetRawRepeatedField");
+  if (field->cpp_type() != cpptype)
+    ReportReflectionUsageTypeError(descriptor_,
+        field, "GetRawRepeatedField", cpptype);
+  if (ctype >= 0)
+    GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch";
+  if (desc != NULL)
+    GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
+  if (field->is_extension()) {
+    // Should use extension_set::GetRawRepeatedField. However, the required
+    // parameter "default repeated value" is not very easy to get here.
+    // Map is not supported in extensions, it is acceptable to use
+    // extension_set::MutableRawRepeatedField which does not change the message.
+    return MutableExtensionSet(const_cast<Message*>(&message))
+        ->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    // Trigger transform for MapField
+    if (IsMapFieldInApi(field)) {
+      return &(reinterpret_cast<const MapFieldBase*>(
+          reinterpret_cast<const uint8*>(&message) +
+          offsets_[field->index()])->GetRepeatedField());
+    }
+    return reinterpret_cast<const uint8*>(&message) + offsets_[field->index()];
+  }
 }
 
 const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor(
@@ -1407,6 +1776,70 @@
   return descriptor_->FindFieldByNumber(field_number);
 }
 
+bool GeneratedMessageReflection::ContainsMapKey(
+    const Message& message,
+    const FieldDescriptor* field,
+    const MapKey& key) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "LookupMapValue",
+              "Field is not a map field.");
+  return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key);
+}
+
+bool GeneratedMessageReflection::InsertOrLookupMapValue(
+    Message* message,
+    const FieldDescriptor* field,
+    const MapKey& key,
+    MapValueRef* val) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "InsertOrLookupMapValue",
+              "Field is not a map field.");
+  val->SetType(field->message_type()->FindFieldByName("value")->cpp_type());
+  return MutableRaw<MapFieldBase>(message, field)->InsertOrLookupMapValue(
+      key, val);
+}
+
+bool GeneratedMessageReflection::DeleteMapValue(
+    Message* message,
+    const FieldDescriptor* field,
+    const MapKey& key) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "DeleteMapValue",
+              "Field is not a map field.");
+  return MutableRaw<MapFieldBase>(message, field)->DeleteMapValue(key);
+}
+
+MapIterator GeneratedMessageReflection::MapBegin(
+    Message* message,
+    const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "MapBegin",
+              "Field is not a map field.");
+  MapIterator iter(message, field);
+  GetRaw<MapFieldBase>(*message, field).MapBegin(&iter);
+  return iter;
+}
+
+MapIterator GeneratedMessageReflection::MapEnd(
+    Message* message,
+    const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "MapEnd",
+              "Field is not a map field.");
+  MapIterator iter(message, field);
+  GetRaw<MapFieldBase>(*message, field).MapEnd(&iter);
+  return iter;
+}
+
+int GeneratedMessageReflection::MapSize(
+    const Message& message,
+    const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "MapSize",
+              "Field is not a map field.");
+  return GetRaw<MapFieldBase>(message, field).size();
+}
+
 // -----------------------------------------------------------------------------
 
 const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName(
@@ -1445,6 +1878,10 @@
   return descriptor_pool_->FindExtensionByNumber(descriptor_, number);
 }
 
+bool GeneratedMessageReflection::SupportsUnknownEnumValues() const {
+  return CreateUnknownEnumValues(descriptor_->file());
+}
+
 // ===================================================================
 // Some private helpers.
 
@@ -1487,11 +1924,17 @@
 
 inline const uint32* GeneratedMessageReflection::GetHasBits(
     const Message& message) const {
+  if (has_bits_offset_ == -1) {  // proto3 with no has-bits.
+    return NULL;
+  }
   const void* ptr = reinterpret_cast<const uint8*>(&message) + has_bits_offset_;
   return reinterpret_cast<const uint32*>(ptr);
 }
 inline uint32* GeneratedMessageReflection::MutableHasBits(
     Message* message) const {
+  if (has_bits_offset_ == -1) {
+    return NULL;
+  }
   void* ptr = reinterpret_cast<uint8*>(message) + has_bits_offset_;
   return reinterpret_cast<uint32*>(ptr);
 }
@@ -1525,25 +1968,125 @@
   return reinterpret_cast<ExtensionSet*>(ptr);
 }
 
+inline Arena* GeneratedMessageReflection::GetArena(Message* message) const {
+  if (arena_offset_ == kNoArenaPointer) {
+    return NULL;
+  }
+
+  if (unknown_fields_offset_ == kUnknownFieldSetInMetadata) {
+    // zero-overhead arena pointer overloading UnknownFields
+    return GetInternalMetadataWithArena(*message).arena();
+  }
+
+  // Baseline case: message class has a dedicated arena pointer.
+  void* ptr = reinterpret_cast<uint8*>(message) + arena_offset_;
+  return *reinterpret_cast<Arena**>(ptr);
+}
+
+inline const InternalMetadataWithArena&
+GeneratedMessageReflection::GetInternalMetadataWithArena(
+    const Message& message) const {
+  const void* ptr = reinterpret_cast<const uint8*>(&message) + arena_offset_;
+  return *reinterpret_cast<const InternalMetadataWithArena*>(ptr);
+}
+
+inline InternalMetadataWithArena*
+GeneratedMessageReflection::MutableInternalMetadataWithArena(
+    Message* message) const {
+  void* ptr = reinterpret_cast<uint8*>(message) + arena_offset_;
+  return reinterpret_cast<InternalMetadataWithArena*>(ptr);
+}
+
+inline bool
+GeneratedMessageReflection::GetIsDefaultInstance(
+    const Message& message) const {
+  if (is_default_instance_offset_ == kHasNoDefaultInstanceField) {
+    return false;
+  }
+  const void* ptr = reinterpret_cast<const uint8*>(&message) +
+      is_default_instance_offset_;
+  return *reinterpret_cast<const bool*>(ptr);
+}
+
 // Simple accessors for manipulating has_bits_.
 inline bool GeneratedMessageReflection::HasBit(
     const Message& message, const FieldDescriptor* field) const {
+  if (has_bits_offset_ == -1) {
+    // proto3: no has-bits. All fields present except messages, which are
+    // present only if their message-field pointer is non-NULL.
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      return !GetIsDefaultInstance(message) &&
+          GetRaw<const Message*>(message, field) != NULL;
+    } else {
+      // Non-message field (and non-oneof, since that was handled in HasField()
+      // before calling us), and singular (again, checked in HasField). So, this
+      // field must be a scalar.
+
+      // Scalar primitive (numeric or string/bytes) fields are present if
+      // their value is non-zero (numeric) or non-empty (string/bytes).  N.B.:
+      // we must use this definition here, rather than the "scalar fields
+      // always present" in the proto3 docs, because MergeFrom() semantics
+      // require presence as "present on wire", and reflection-based merge
+      // (which uses HasField()) needs to be consistent with this.
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_STRING:
+          switch (field->options().ctype()) {
+            default: {
+              const string* default_ptr =
+                  &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+              return GetField<ArenaStringPtr>(message, field).Get(
+                  default_ptr).size() > 0;
+            }
+          }
+          return false;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          return GetRaw<bool>(message, field) != false;
+        case FieldDescriptor::CPPTYPE_INT32:
+          return GetRaw<int32>(message, field) != 0;
+        case FieldDescriptor::CPPTYPE_INT64:
+          return GetRaw<int64>(message, field) != 0;
+        case FieldDescriptor::CPPTYPE_UINT32:
+          return GetRaw<uint32>(message, field) != 0;
+        case FieldDescriptor::CPPTYPE_UINT64:
+          return GetRaw<uint64>(message, field) != 0;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+          return GetRaw<float>(message, field) != 0.0;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          return GetRaw<double>(message, field) != 0.0;
+        case FieldDescriptor::CPPTYPE_ENUM:
+          return GetRaw<int>(message, field) != 0;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          // handled above; avoid warning
+          GOOGLE_LOG(FATAL) << "Reached impossible case in HasBit().";
+          break;
+      }
+    }
+  }
   return GetHasBits(message)[field->index() / 32] &
     (1 << (field->index() % 32));
 }
 
 inline void GeneratedMessageReflection::SetBit(
     Message* message, const FieldDescriptor* field) const {
+  if (has_bits_offset_ == -1) {
+    return;
+  }
   MutableHasBits(message)[field->index() / 32] |= (1 << (field->index() % 32));
 }
 
 inline void GeneratedMessageReflection::ClearBit(
     Message* message, const FieldDescriptor* field) const {
+  if (has_bits_offset_ == -1) {
+    return;
+  }
   MutableHasBits(message)[field->index() / 32] &= ~(1 << (field->index() % 32));
 }
 
 inline void GeneratedMessageReflection::SwapBit(
     Message* message1, Message* message2, const FieldDescriptor* field) const {
+  if (has_bits_offset_ == -1) {
+    return;
+  }
   bool temp_has_bit = HasBit(*message1, field);
   if (HasBit(*message2, field)) {
     SetBit(message1, field);
@@ -1587,22 +2130,28 @@
   uint32 oneof_case = GetOneofCase(*message, oneof_descriptor);
   if (oneof_case > 0) {
     const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
-    switch (field->cpp_type()) {
-      case FieldDescriptor::CPPTYPE_STRING: {
-        switch (field->options().ctype()) {
-          default:  // TODO(kenton):  Support other string reps.
-          case FieldOptions::STRING:
-            delete *MutableRaw<string*>(message, field);
-            break;
+    if (GetArena(message) == NULL) {
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING: {
+              const string* default_ptr =
+                  &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+              MutableField<ArenaStringPtr>(message, field)->
+                  Destroy(default_ptr, GetArena(message));
+              break;
+            }
+          }
+          break;
         }
-        break;
-      }
 
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        delete *MutableRaw<Message*>(message, field);
-        break;
-      default:
-        break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          delete *MutableRaw<Message*>(message, field);
+          break;
+        default:
+          break;
+      }
     }
 
     *MutableOneofCase(message, oneof_descriptor) = 0;
@@ -1678,6 +2227,92 @@
   return repeated->Add();
 }
 
+MessageFactory* GeneratedMessageReflection::GetMessageFactory() const {
+  return message_factory_;
+}
+
+void* GeneratedMessageReflection::RepeatedFieldData(
+    Message* message, const FieldDescriptor* field,
+    FieldDescriptor::CppType cpp_type,
+    const Descriptor* message_type) const {
+  GOOGLE_CHECK(field->is_repeated());
+  GOOGLE_CHECK(field->cpp_type() == cpp_type ||
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+         cpp_type == FieldDescriptor::CPPTYPE_INT32))
+      << "The type parameter T in RepeatedFieldRef<T> API doesn't match "
+      << "the actual field type (for enums T should be the generated enum "
+      << "type or int32).";
+  if (message_type != NULL) {
+    GOOGLE_CHECK_EQ(message_type, field->message_type());
+  }
+  if (field->is_extension()) {
+    return MutableExtensionSet(message)->MutableRawRepeatedField(
+        field->number(), field->type(), field->is_packed(), field);
+  } else {
+    return reinterpret_cast<uint8*>(message) + offsets_[field->index()];
+  }
+}
+
+MapFieldBase* GeneratedMessageReflection::MapData(
+    Message* message, const FieldDescriptor* field) const {
+  USAGE_CHECK(IsMapFieldInApi(field),
+              "GetMapData",
+              "Field is not a map field.");
+  return MutableRaw<MapFieldBase>(message, field);
+}
+
+GeneratedMessageReflection*
+GeneratedMessageReflection::NewGeneratedMessageReflection(
+    const Descriptor* descriptor,
+    const Message* default_instance,
+    const int offsets[],
+    int has_bits_offset,
+    int unknown_fields_offset,
+    int extensions_offset,
+    const void* default_oneof_instance,
+    int oneof_case_offset,
+    int object_size,
+    int arena_offset,
+    int is_default_instance_offset) {
+  return new GeneratedMessageReflection(descriptor,
+                                        default_instance,
+                                        offsets,
+                                        has_bits_offset,
+                                        unknown_fields_offset,
+                                        extensions_offset,
+                                        default_oneof_instance,
+                                        oneof_case_offset,
+                                        DescriptorPool::generated_pool(),
+                                        MessageFactory::generated_factory(),
+                                        object_size,
+                                        arena_offset,
+                                        is_default_instance_offset);
+}
+
+GeneratedMessageReflection*
+GeneratedMessageReflection::NewGeneratedMessageReflection(
+    const Descriptor* descriptor,
+    const Message* default_instance,
+    const int offsets[],
+    int has_bits_offset,
+    int unknown_fields_offset,
+    int extensions_offset,
+    int object_size,
+    int arena_offset,
+    int is_default_instance_offset) {
+  return new GeneratedMessageReflection(descriptor,
+                                        default_instance,
+                                        offsets,
+                                        has_bits_offset,
+                                        unknown_fields_offset,
+                                        extensions_offset,
+                                        DescriptorPool::generated_pool(),
+                                        MessageFactory::generated_factory(),
+                                        object_size,
+                                        arena_offset,
+                                        is_default_instance_offset);
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index e0e041a..4f25d4b 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -40,11 +40,13 @@
 
 #include <string>
 #include <vector>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
 // TODO(jasonh): Remove this once the compiler change to directly include this
 // is released to components.
 #include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/metadata.h>
 #include <google/protobuf/unknown_field_set.h>
 
 
@@ -56,7 +58,9 @@
 }  // namespace upb
 
 namespace protobuf {
-  class DescriptorPool;
+class DescriptorPool;
+class MapKey;
+class MapValueRef;
 }
 
 namespace protobuf {
@@ -134,7 +138,9 @@
                              int extensions_offset,
                              const DescriptorPool* pool,
                              MessageFactory* factory,
-                             int object_size);
+                             int object_size,
+                             int arena_offset,
+                             int is_default_instance_offset = -1);
 
   // Similar with the construction above. Call this construction if the
   // message has oneof definition.
@@ -170,9 +176,39 @@
                              int oneof_case_offset,
                              const DescriptorPool* pool,
                              MessageFactory* factory,
-                             int object_size);
+                             int object_size,
+                             int arena_offset,
+                             int is_default_instance_offset = -1);
   ~GeneratedMessageReflection();
 
+  // Shorter-to-call helpers for the above two constructions that work if the
+  // pool and factory are the usual, namely, DescriptorPool::generated_pool()
+  // and MessageFactory::generated_factory().
+
+  static GeneratedMessageReflection* NewGeneratedMessageReflection(
+      const Descriptor* descriptor,
+      const Message* default_instance,
+      const int offsets[],
+      int has_bits_offset,
+      int unknown_fields_offset,
+      int extensions_offset,
+      const void* default_oneof_instance,
+      int oneof_case_offset,
+      int object_size,
+      int arena_offset,
+      int is_default_instance_offset = -1);
+
+  static GeneratedMessageReflection* NewGeneratedMessageReflection(
+      const Descriptor* descriptor,
+      const Message* default_instance,
+      const int offsets[],
+      int has_bits_offset,
+      int unknown_fields_offset,
+      int extensions_offset,
+      int object_size,
+      int arena_offset,
+      int is_default_instance_offset = -1);
+
   // implements Reflection -------------------------------------------
 
   const UnknownFieldSet& GetUnknownFields(const Message& message) const;
@@ -217,6 +253,8 @@
                                    string* scratch) const;
   const EnumValueDescriptor* GetEnum(const Message& message,
                                      const FieldDescriptor* field) const;
+  int GetEnumValue(const Message& message,
+                   const FieldDescriptor* field) const;
   const Message& GetMessage(const Message& message,
                             const FieldDescriptor* field,
                             MessageFactory* factory = NULL) const;
@@ -225,6 +263,25 @@
       const Message& message,
       const OneofDescriptor* oneof_descriptor) const;
 
+ private:
+  bool ContainsMapKey(const Message& message,
+                      const FieldDescriptor* field,
+                      const MapKey& key) const;
+  bool InsertOrLookupMapValue(Message* message,
+                              const FieldDescriptor* field,
+                              const MapKey& key,
+                              MapValueRef* val) const;
+  bool DeleteMapValue(Message* message,
+                      const FieldDescriptor* field,
+                      const MapKey& key) const;
+  MapIterator MapBegin(
+      Message* message,
+      const FieldDescriptor* field) const;
+  MapIterator MapEnd(
+      Message* message,
+      const FieldDescriptor* field) const;
+  int MapSize(const Message& message, const FieldDescriptor* field) const;
+
  public:
   void SetInt32 (Message* message,
                  const FieldDescriptor* field, int32  value) const;
@@ -245,6 +302,8 @@
                  const string& value) const;
   void SetEnum  (Message* message, const FieldDescriptor* field,
                  const EnumValueDescriptor* value) const;
+  void SetEnumValue(Message* message, const FieldDescriptor* field,
+                    int value) const;
   Message* MutableMessage(Message* message, const FieldDescriptor* field,
                           MessageFactory* factory = NULL) const;
   void SetAllocatedMessage(Message* message,
@@ -275,6 +334,9 @@
   const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
                                              const FieldDescriptor* field,
                                              int index) const;
+  int GetRepeatedEnumValue(const Message& message,
+                           const FieldDescriptor* field,
+                           int index) const;
   const Message& GetRepeatedMessage(const Message& message,
                                     const FieldDescriptor* field,
                                     int index) const;
@@ -299,6 +361,8 @@
                          const string& value) const;
   void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
                        int index, const EnumValueDescriptor* value) const;
+  void SetRepeatedEnumValue(Message* message, const FieldDescriptor* field,
+                            int index, int value) const;
   // Get a mutable pointer to a field with a message type.
   Message* MutableRepeatedMessage(Message* message,
                                   const FieldDescriptor* field,
@@ -323,23 +387,56 @@
   void AddEnum(Message* message,
                const FieldDescriptor* field,
                const EnumValueDescriptor* value) const;
+  void AddEnumValue(Message* message,
+                    const FieldDescriptor* field,
+                    int value) const;
   Message* AddMessage(Message* message, const FieldDescriptor* field,
                       MessageFactory* factory = NULL) const;
+  void AddAllocatedMessage(
+      Message* message, const FieldDescriptor* field,
+      Message* new_entry) const;
 
   const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
   const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
 
+  bool SupportsUnknownEnumValues() const;
+
+  // This value for arena_offset_ indicates that there is no arena pointer in
+  // this message (e.g., old generated code).
+  static const int kNoArenaPointer = -1;
+
+  // This value for unknown_field_offset_ indicates that there is no
+  // UnknownFieldSet in this message, and that instead, we are using the
+  // Zero-Overhead Arena Pointer trick. When this is the case, arena_offset_
+  // actually indexes to an InternalMetadataWithArena instance, which can return
+  // either an arena pointer or an UnknownFieldSet or both. It is never the case
+  // that unknown_field_offset_ == kUnknownFieldSetInMetadata && arena_offset_
+  // == kNoArenaPointer.
+  static const int kUnknownFieldSetInMetadata = -1;
+
  protected:
-  virtual void* MutableRawRepeatedField(
+  void* MutableRawRepeatedField(
       Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
       int ctype, const Descriptor* desc) const;
 
+  const void* GetRawRepeatedField(
+      const Message& message, const FieldDescriptor* field,
+      FieldDescriptor::CppType, int ctype,
+      const Descriptor* desc) const;
+
+  virtual MessageFactory* GetMessageFactory() const;
+
+  virtual void* RepeatedFieldData(
+      Message* message, const FieldDescriptor* field,
+      FieldDescriptor::CppType cpp_type,
+      const Descriptor* message_type) const;
+
  private:
   friend class GeneratedMessage;
 
   // To parse directly into a proto2 generated class, the class GMR_Handlers
   // needs access to member offsets and hasbits.
-  friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
+  friend class upb::google_opensource::GMR_Handlers;
 
   const Descriptor* descriptor_;
   const Message* default_instance_;
@@ -350,8 +447,12 @@
   int oneof_case_offset_;
   int unknown_fields_offset_;
   int extensions_offset_;
+  int arena_offset_;
+  int is_default_instance_offset_;
   int object_size_;
 
+  static const int kHasNoDefaultInstanceField = -1;
+
   const DescriptorPool* descriptor_pool_;
   MessageFactory* message_factory_;
 
@@ -376,6 +477,13 @@
       const OneofDescriptor* oneof_descriptor) const;
   inline const ExtensionSet& GetExtensionSet(const Message& message) const;
   inline ExtensionSet* MutableExtensionSet(Message* message) const;
+  inline Arena* GetArena(Message* message) const;
+  inline const internal::InternalMetadataWithArena&
+      GetInternalMetadataWithArena(const Message& message) const;
+  inline internal::InternalMetadataWithArena*
+      MutableInternalMetadataWithArena(Message* message) const;
+
+  inline bool GetIsDefaultInstance(const Message& message) const;
 
   inline bool HasBit(const Message& message,
                      const FieldDescriptor* field) const;
@@ -438,6 +546,31 @@
 
   int GetExtensionNumberOrDie(const Descriptor* type) const;
 
+  // Internal versions of EnumValue API perform no checking. Called after checks
+  // by public methods.
+  void SetEnumValueInternal(Message* message,
+                            const FieldDescriptor* field,
+                            int value) const;
+  void SetRepeatedEnumValueInternal(Message* message,
+                                    const FieldDescriptor* field,
+                                    int index,
+                                    int value) const;
+  void AddEnumValueInternal(Message* message,
+                            const FieldDescriptor* field,
+                            int value) const;
+
+
+  Message* UnsafeArenaReleaseMessage(Message* message,
+                                     const FieldDescriptor* field,
+                                     MessageFactory* factory = NULL) const;
+
+  void UnsafeArenaSetAllocatedMessage(Message* message,
+                                      Message* sub_message,
+                                      const FieldDescriptor* field) const;
+
+  internal::MapFieldBase* MapData(
+      Message* message, const FieldDescriptor* field) const;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
 };
 
@@ -449,7 +582,16 @@
 // which the offsets of the direct fields of a class are non-constant.
 // Fields inherited from superclasses *can* have non-constant offsets,
 // but that's not what this macro will be used for.
-//
+#if defined(__clang__)
+// For Clang we use __builtin_offsetof() and suppress the warning,
+// to avoid Control Flow Integrity and UBSan vptr sanitizers from
+// crashing while trying to validate the invalid reinterpet_casts.
+#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD)    \
+  _Pragma("clang diagnostic push")                            \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"")  \
+  __builtin_offsetof(TYPE, FIELD)                             \
+  _Pragma("clang diagnostic pop")
+#else
 // Note that we calculate relative to the pointer value 16 here since if we
 // just use zero, GCC complains about dereferencing a NULL pointer.  We
 // choose 16 rather than some other number just in case the compiler would
@@ -459,6 +601,7 @@
       reinterpret_cast<const char*>(                          \
           &reinterpret_cast<const TYPE*>(16)->FIELD) -        \
       reinterpret_cast<const char*>(16))
+#endif
 
 #define PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ONEOF, FIELD)     \
   static_cast<int>(                                                   \
@@ -490,7 +633,8 @@
 // On MSVC, this should be detected automatically.
 template<typename To, typename From>
 inline To dynamic_cast_if_available(From from) {
-#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) || defined(__GXX_RTTI) || \
+  (defined(_MSC_VER)&&!defined(_CPPRTTI))
   // Avoid the compiler warning about unused variables.
   (void)from;
   return NULL;
@@ -499,6 +643,42 @@
 #endif
 }
 
+// Tries to downcast this message to a generated message type.
+// Returns NULL if this class is not an instance of T.
+//
+// This is like dynamic_cast_if_available, except it works even when
+// dynamic_cast is not available by using Reflection.  However it only works
+// with Message objects.
+//
+// TODO(haberman): can we remove dynamic_cast_if_available in favor of this?
+template <typename T>
+T* DynamicCastToGenerated(const Message* from) {
+  // Compile-time assert that T is a generated type that has a
+  // default_instance() accessor, but avoid actually calling it.
+  const T&(*get_default_instance)() = &T::default_instance;
+  (void)get_default_instance;
+
+  // Compile-time assert that T is a subclass of google::protobuf::Message.
+  const Message* unused = static_cast<T*>(NULL);
+  (void)unused;
+
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) || defined(__GXX_RTTI) || \
+  (defined(_MSC_VER)&&!defined(_CPPRTTI))
+  bool ok = &T::default_instance() ==
+            from->GetReflection()->GetMessageFactory()->GetPrototype(
+                from->GetDescriptor());
+  return ok ? down_cast<T*>(from) : NULL;
+#else
+  return dynamic_cast<T*>(from);
+#endif
+}
+
+template <typename T>
+T* DynamicCastToGenerated(Message* from) {
+  const Message* message_const = from;
+  return const_cast<T*>(DynamicCastToGenerated<const T>(message_const));
+}
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index ca1a291..85ebdef 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -43,10 +43,16 @@
 // rather than generated accessors.
 
 #include <google/protobuf/generated_message_reflection.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -353,7 +359,7 @@
   ASSERT_EQ(2, message.repeated_foreign_message_size());
   const protobuf_unittest::ForeignMessage* expected =
       message.mutable_repeated_foreign_message(1);
-  scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+  google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
       &message, descriptor->FindFieldByName("repeated_foreign_message")));
   EXPECT_EQ(expected, released.get());
 }
@@ -376,9 +382,9 @@
       unittest::repeated_foreign_message_extension));
   const protobuf_unittest::ForeignMessage* expected = message.MutableExtension(
       unittest::repeated_foreign_message_extension, 1);
-  scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+  google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
       &message, descriptor->file()->FindExtensionByName(
-          "repeated_foreign_message_extension")));
+                    "repeated_foreign_message_extension")));
   EXPECT_EQ(expected, released.get());
 
 }
@@ -546,6 +552,57 @@
       &to_message, TestUtil::ReflectionTester::IS_NULL);
 }
 
+TEST(GeneratedMessageReflectionTest, AddRepeatedMessage) {
+  unittest::TestAllTypes message;
+
+  const Reflection* reflection = message.GetReflection();
+  const Reflection* nested_reflection =
+      unittest::TestAllTypes::NestedMessage::default_instance().GetReflection();
+
+  const FieldDescriptor* nested_bb =
+      unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName(
+          "bb");
+
+  Message* nested = reflection->AddMessage(
+      &message, F("repeated_nested_message"));
+  nested_reflection->SetInt32(nested, nested_bb, 11);
+
+  EXPECT_EQ(11, message.repeated_nested_message(0).bb());
+}
+
+TEST(GeneratedMessageReflectionTest, MutableRepeatedMessage) {
+  unittest::TestAllTypes message;
+
+  const Reflection* reflection = message.GetReflection();
+  const Reflection* nested_reflection =
+      unittest::TestAllTypes::NestedMessage::default_instance().GetReflection();
+
+  const FieldDescriptor* nested_bb =
+      unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName(
+          "bb");
+
+  message.add_repeated_nested_message()->set_bb(12);
+
+  Message* nested = reflection->MutableRepeatedMessage(
+      &message, F("repeated_nested_message"), 0);
+  EXPECT_EQ(12, nested_reflection->GetInt32(*nested, nested_bb));
+  nested_reflection->SetInt32(nested, nested_bb, 13);
+  EXPECT_EQ(13, message.repeated_nested_message(0).bb());
+}
+
+TEST(GeneratedMessageReflectionTest, AddAllocatedMessage) {
+  unittest::TestAllTypes message;
+
+  const Reflection* reflection = message.GetReflection();
+
+  unittest::TestAllTypes::NestedMessage* nested =
+      new unittest::TestAllTypes::NestedMessage();
+  nested->set_bb(11);
+  reflection->AddAllocatedMessage(&message, F("repeated_nested_message"), nested);
+  EXPECT_EQ(1, message.repeated_nested_message_size());
+  EXPECT_EQ(11, message.repeated_nested_message(0).bb());
+}
+
 TEST(GeneratedMessageReflectionTest, ListFieldsOneOf) {
   unittest::TestOneof2 message;
   TestUtil::SetOneof1(&message);
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 0c20d81..7b813f8 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -36,6 +36,7 @@
 
 #include <limits>
 
+
 namespace google {
 namespace protobuf {
 namespace internal {
@@ -59,6 +60,18 @@
   OnShutdown(&DeleteEmptyString);
 }
 
+int StringSpaceUsedExcludingSelf(const string& str) {
+  const void* start = &str;
+  const void* end = &str + 1;
+  if (start <= str.data() && str.data() < end) {
+    // The string's data is stored inside the string object itself.
+    return 0;
+  } else {
+    return str.capacity();
+  }
+}
+
+
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 678f92a..4475556 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -42,11 +42,15 @@
 #include <string>
 
 #include <google/protobuf/stubs/once.h>
-
 #include <google/protobuf/stubs/common.h>
+
 namespace google {
 
 namespace protobuf {
+
+class Arena;
+namespace io { class CodedInputStream; }
+
 namespace internal {
 
 
@@ -59,6 +63,8 @@
 #undef DEPRECATED_PROTOBUF_FIELD
 #define PROTOBUF_DEPRECATED
 
+#define PROTOBUF_DEPRECATED_ATTR
+
 
 // Constants for special floating point values.
 LIBPROTOBUF_EXPORT double Infinity();
@@ -85,12 +91,6 @@
   return GetEmptyStringAlreadyInited();
 }
 
-// Defined in generated_message_reflection.cc -- not actually part of the lite
-// library.
-//
-// TODO(jasonh): The various callers get this declaration from a variety of
-// places: probably in most cases repeated_field.h. Clean these up so they all
-// get the declaration from this file.
 LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
 
 
@@ -106,6 +106,15 @@
   return true;
 }
 
+class ArenaString;
+
+// Read a length (varint32), followed by a string, from *input.  Return a
+// pointer to a copy of the string that resides in *arena.  Requires both
+// args to be non-NULL.  If something goes wrong while reading the data
+// then NULL is returned (e.g., input does not start with a valid varint).
+ArenaString* ReadArenaString(::google::protobuf::io::CodedInputStream* input,
+                             ::google::protobuf::Arena* arena);
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 5344975..d8354c1 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -40,8 +40,11 @@
 
 #include <google/protobuf/io/coded_stream_inl.h>
 #include <algorithm>
+#include <utility>
 #include <limits.h>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stl_util.h>
 
@@ -102,7 +105,7 @@
 
 inline void CodedInputStream::RecomputeBufferLimits() {
   buffer_end_ += buffer_size_after_limit_;
-  int closest_limit = min(current_limit_, total_bytes_limit_);
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
   if (closest_limit < total_bytes_read_) {
     // The limit position is in the current buffer.  We must adjust
     // the buffer size accordingly.
@@ -132,7 +135,7 @@
   // We need to enforce all limits, not just the new one, so if the previous
   // limit was before the new requested limit, we continue to enforce the
   // previous limit.
-  current_limit_ = min(current_limit_, old_limit);
+  current_limit_ = std::min(current_limit_, old_limit);
 
   RecomputeBufferLimits();
   return old_limit;
@@ -149,6 +152,30 @@
   legitimate_message_end_ = false;
 }
 
+std::pair<CodedInputStream::Limit, int>
+CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
+  return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
+}
+
+CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
+  uint32 length;
+  return PushLimit(ReadVarint32(&length) ? length : 0);
+}
+
+bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_);
+  ++recursion_budget_;
+  return result;
+}
+
+bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  return result;
+}
+
 int CodedInputStream::BytesUntilLimit() const {
   if (current_limit_ == INT_MAX) return -1;
   int current_position = CurrentPosition();
@@ -161,7 +188,7 @@
   // Make sure the limit isn't already past, since this could confuse other
   // code.
   int current_position = CurrentPosition();
-  total_bytes_limit_ = max(current_position, total_bytes_limit);
+  total_bytes_limit_ = std::max(current_position, total_bytes_limit);
   if (warning_threshold >= 0) {
     total_bytes_warning_threshold_ = warning_threshold;
   } else {
@@ -206,7 +233,7 @@
   buffer_end_ = buffer_;
 
   // Make sure this skip doesn't try to skip past the current limit.
-  int closest_limit = min(current_limit_, total_bytes_limit_);
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
   int bytes_until_limit = closest_limit - total_bytes_read_;
   if (bytes_until_limit < count) {
     // We hit the limit.  Skip up to it then fail.
@@ -230,20 +257,7 @@
 }
 
 bool CodedInputStream::ReadRaw(void* buffer, int size) {
-  int current_buffer_size;
-  while ((current_buffer_size = BufferSize()) < size) {
-    // Reading past end of buffer.  Copy what we have, then refresh.
-    memcpy(buffer, buffer_, current_buffer_size);
-    buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
-    size -= current_buffer_size;
-    Advance(current_buffer_size);
-    if (!Refresh()) return false;
-  }
-
-  memcpy(buffer, buffer_, size);
-  Advance(size);
-
-  return true;
+  return InternalReadRawInline(buffer, size);
 }
 
 bool CodedInputStream::ReadString(string* buffer, int size) {
@@ -256,7 +270,7 @@
     buffer->clear();
   }
 
-  int closest_limit = min(current_limit_, total_bytes_limit_);
+  int closest_limit = std::min(current_limit_, total_bytes_limit_);
   if (closest_limit != INT_MAX) {
     int bytes_to_limit = closest_limit - CurrentPosition();
     if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
@@ -321,17 +335,23 @@
 
 namespace {
 
-inline const uint8* ReadVarint32FromArray(
-    const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
+// Read a varint from the given buffer, write it to *value, and return a pair.
+// The first part of the pair is true iff the read was successful.  The second
+// part is buffer + (number of bytes read).  This function is always inlined,
+// so returning a pair is costless.
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE ::std::pair<bool, const uint8*> ReadVarint32FromArray(
+    uint32 first_byte, const uint8* buffer,
+    uint32* value);
+inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
+    uint32 first_byte, const uint8* buffer, uint32* value) {
   // Fast path:  We have enough bytes left in the buffer to guarantee that
   // this read won't cross the end, so we can skip the checks.
+  GOOGLE_DCHECK_EQ(*buffer, first_byte);
+  GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
   const uint8* ptr = buffer;
   uint32 b;
-  uint32 result;
-
-  b = *(ptr++); result  = b      ; if (!(b & 0x80)) goto done;
-  result -= 0x80;
+  uint32 result = first_byte - 0x80;
+  ++ptr;  // We just processed the first byte.  Move on to the second.
   b = *(ptr++); result += b <<  7; if (!(b & 0x80)) goto done;
   result -= 0x80 << 7;
   b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
@@ -349,38 +369,42 @@
 
   // We have overrun the maximum size of a varint (10 bytes).  Assume
   // the data is corrupt.
-  return NULL;
+  return std::make_pair(false, ptr);
 
  done:
   *value = result;
-  return ptr;
+  return std::make_pair(true, ptr);
 }
 
 }  // namespace
 
 bool CodedInputStream::ReadVarint32Slow(uint32* value) {
-  uint64 result;
   // Directly invoke ReadVarint64Fallback, since we already tried to optimize
   // for one-byte varints.
-  if (!ReadVarint64Fallback(&result)) return false;
-  *value = (uint32)result;
-  return true;
+  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  *value = static_cast<uint32>(p.first);
+  return p.second;
 }
 
-bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
+int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
-    const uint8* end = ReadVarint32FromArray(buffer_, value);
-    if (end == NULL) return false;
-    buffer_ = end;
-    return true;
+    GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
+        << "Caller should provide us with *buffer_ when buffer is non-empty";
+    uint32 temp;
+    ::std::pair<bool, const uint8*> p =
+          ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
+    if (!p.first) return -1;
+    buffer_ = p.second;
+    return temp;
   } else {
     // Really slow case: we will incur the cost of an extra function call here,
     // but moving this out of line reduces the size of this function, which
     // improves the common case. In micro benchmarks, this is worth about 10-15%
-    return ReadVarint32Slow(value);
+    uint32 temp;
+    return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
   }
 }
 
@@ -410,18 +434,24 @@
   return static_cast<uint32>(result);
 }
 
-uint32 CodedInputStream::ReadTagFallback() {
+uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
   const int buf_size = BufferSize();
   if (buf_size >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
-    uint32 tag;
-    const uint8* end = ReadVarint32FromArray(buffer_, &tag);
-    if (end == NULL) {
+    GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
+    if (first_byte_or_zero == 0) {
+      ++buffer_;
       return 0;
     }
-    buffer_ = end;
+    uint32 tag;
+    ::std::pair<bool, const uint8*> p =
+        ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
+    if (!p.first) {
+      return 0;
+    }
+    buffer_ = p.second;
     return tag;
   } else {
     // We are commonly at a limit when attempting to read tags. Try to quickly
@@ -464,7 +494,7 @@
   return true;
 }
 
-bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
+std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
@@ -502,16 +532,18 @@
 
     // We have overrun the maximum size of a varint (10 bytes).  The data
     // must be corrupt.
-    return false;
+    return std::make_pair(0, false);
 
    done:
     Advance(ptr - buffer_);
-    *value = (static_cast<uint64>(part0)      ) |
-             (static_cast<uint64>(part1) << 28) |
-             (static_cast<uint64>(part2) << 56);
-    return true;
+    return std::make_pair((static_cast<uint64>(part0)) |
+                              (static_cast<uint64>(part1) << 28) |
+                              (static_cast<uint64>(part2) << 56),
+                          true);
   } else {
-    return ReadVarint64Slow(value);
+    uint64 temp;
+    bool success = ReadVarint64Slow(&temp);
+    return std::make_pair(temp, success);
   }
 }
 
@@ -597,9 +629,34 @@
   had_error_ = false;
 }
 
+CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
+                                     bool do_eager_refresh)
+  : output_(output),
+    buffer_(NULL),
+    buffer_size_(0),
+    total_bytes_(0),
+    had_error_(false),
+    aliasing_enabled_(false) {
+  if (do_eager_refresh) {
+    // Eagerly Refresh() so buffer space is immediately available.
+    Refresh();
+    // The Refresh() may have failed. If the client doesn't write any data,
+    // though, don't consider this an error. If the client does write data, then
+    // another Refresh() will be attempted and it will set the error once again.
+    had_error_ = false;
+  }
+}
+
 CodedOutputStream::~CodedOutputStream() {
+  Trim();
+}
+
+void CodedOutputStream::Trim() {
   if (buffer_size_ > 0) {
     output_->BackUp(buffer_size_);
+    total_bytes_ -= buffer_size_;
+    buffer_size_ = 0;
+    buffer_ = NULL;
   }
 }
 
@@ -647,12 +704,7 @@
       ) {
     WriteRaw(data, size);
   } else {
-    if (buffer_size_ > 0) {
-      output_->BackUp(buffer_size_);
-      total_bytes_ -= buffer_size_;
-      buffer_ = NULL;
-      buffer_size_ = 0;
-    }
+    Trim();
 
     total_bytes_ += size;
     had_error_ |= !output_->WriteAliasedRaw(data, size);
@@ -689,61 +741,12 @@
   }
 }
 
-inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
-    uint32 value, uint8* target) {
-  target[0] = static_cast<uint8>(value | 0x80);
-  if (value >= (1 << 7)) {
-    target[1] = static_cast<uint8>((value >>  7) | 0x80);
-    if (value >= (1 << 14)) {
-      target[2] = static_cast<uint8>((value >> 14) | 0x80);
-      if (value >= (1 << 21)) {
-        target[3] = static_cast<uint8>((value >> 21) | 0x80);
-        if (value >= (1 << 28)) {
-          target[4] = static_cast<uint8>(value >> 28);
-          return target + 5;
-        } else {
-          target[3] &= 0x7F;
-          return target + 4;
-        }
-      } else {
-        target[2] &= 0x7F;
-        return target + 3;
-      }
-    } else {
-      target[1] &= 0x7F;
-      return target + 2;
-    }
-  } else {
-    target[0] &= 0x7F;
-    return target + 1;
-  }
-}
-
-void CodedOutputStream::WriteVarint32(uint32 value) {
-  if (buffer_size_ >= kMaxVarint32Bytes) {
-    // Fast path:  We have enough bytes left in the buffer to guarantee that
-    // this write won't cross the end, so we can skip the checks.
-    uint8* target = buffer_;
-    uint8* end = WriteVarint32FallbackToArrayInline(value, target);
-    int size = end - target;
-    Advance(size);
-  } else {
-    // Slow path:  This write might cross the end of the buffer, so we
-    // compose the bytes first then use WriteRaw().
-    uint8 bytes[kMaxVarint32Bytes];
-    int size = 0;
-    while (value > 0x7F) {
-      bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
-      value >>= 7;
-    }
-    bytes[size++] = static_cast<uint8>(value) & 0x7F;
-    WriteRaw(bytes, size);
-  }
-}
-
-uint8* CodedOutputStream::WriteVarint32FallbackToArray(
-    uint32 value, uint8* target) {
-  return WriteVarint32FallbackToArrayInline(value, target);
+void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
+  uint8 bytes[kMaxVarint32Bytes];
+  uint8* target = &bytes[0];
+  uint8* end = WriteVarint32ToArray(value, target);
+  int size = end - target;
+  WriteRaw(bytes, size);
 }
 
 inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 81fabb1..c81a33a 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -49,7 +49,7 @@
 //   // to identify the file type, then write a length-delimited string.  The
 //   // string is composed of a varint giving the length followed by the raw
 //   // bytes.
-//   int fd = open("myfile", O_WRONLY);
+//   int fd = open("myfile", O_CREAT | O_WRONLY);
 //   ZeroCopyOutputStream* raw_output = new FileOutputStream(fd);
 //   CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
 //
@@ -109,28 +109,31 @@
 #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 
+#include <assert.h>
 #include <string>
+#include <utility>
 #ifdef _MSC_VER
-  #if defined(_M_IX86) && \
-      !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+  // Assuming windows is always little-endian.
+  #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
     #define PROTOBUF_LITTLE_ENDIAN 1
   #endif
-  #if _MSC_VER >= 1300
+  #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
     // If MSVC has "/RTCc" set, it will complain about truncating casts at
     // runtime.  This file contains some intentional truncating casts.
     #pragma runtime_checks("c", off)
   #endif
 #else
   #include <sys/param.h>   // __BYTE_ORDER
-  #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && \
+  #if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
+         (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)) && \
       !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
     #define PROTOBUF_LITTLE_ENDIAN 1
   #endif
 #endif
 #include <google/protobuf/stubs/common.h>
 
-
 namespace google {
+
 namespace protobuf {
 
 class DescriptorPool;
@@ -189,12 +192,16 @@
 
   // Like GetDirectBufferPointer, but this method is inlined, and does not
   // attempt to Refresh() if the buffer is currently empty.
-  inline void GetDirectBufferPointerInline(const void** data,
-                                           int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void GetDirectBufferPointerInline(const void** data,
+                                                            int* size);
 
   // Read raw bytes, copying them into the given buffer.
   bool ReadRaw(void* buffer, int size);
 
+  // Like the above, with inlined optimizations. This should only be used
+  // by the protobuf implementation.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadRawInline(void* buffer, int size);
+
   // Like ReadRaw, but reads into a string.
   //
   // Implementation Note:  ReadString() grows the string gradually as it
@@ -205,8 +212,8 @@
   bool ReadString(string* buffer, int size);
   // Like the above, with inlined optimizations. This should only be used
   // by the protobuf implementation.
-  inline bool InternalReadStringInline(string* buffer,
-                                       int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadStringInline(string* buffer,
+                                                        int size);
 
 
   // Read a 32-bit little-endian integer.
@@ -236,7 +243,7 @@
   // Always inline because this is only called in one place per parse loop
   // but it is called for every iteration of said loop, so it should be fast.
   // GCC doesn't want to inline this by default.
-  uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTag();
 
   // This usually a faster alternative to ReadTag() when cutoff is a manifest
   // constant.  It does particularly well for cutoff >= 127.  The first part
@@ -246,8 +253,8 @@
   // above cutoff or is 0.  (There's intentional wiggle room when tag is 0,
   // because that can arise in several ways, and for best performance we want
   // to avoid an extra "is tag == 0?" check here.)
-  inline std::pair<uint32, bool> ReadTagWithCutoff(uint32 cutoff)
-      GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE std::pair<uint32, bool> ReadTagWithCutoff(
+      uint32 cutoff);
 
   // Usually returns true if calling ReadVarint32() now would produce the given
   // value.  Will always return false if ReadVarint32() would not return the
@@ -256,7 +263,7 @@
   // parameter.
   // Always inline because this collapses to a small number of instructions
   // when given a constant parameter, but GCC doesn't want to inline by default.
-  bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool ExpectTag(uint32 expected);
 
   // Like above, except this reads from the specified buffer. The caller is
   // responsible for ensuring that the buffer is large enough to read a varint
@@ -265,9 +272,9 @@
   //
   // Returns a pointer beyond the expected tag if it was found, or NULL if it
   // was not.
-  static const uint8* ExpectTagFromArray(
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static const uint8* ExpectTagFromArray(
       const uint8* buffer,
-      uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+      uint32 expected);
 
   // Usually returns true if no more bytes can be read.  Always returns false
   // if more bytes can be read.  If ExpectAtEnd() returns true, a subsequent
@@ -385,9 +392,41 @@
   // under the limit, false if it has gone over.
   bool IncrementRecursionDepth();
 
-  // Decrements the recursion depth.
+  // Decrements the recursion depth if possible.
   void DecrementRecursionDepth();
 
+  // Decrements the recursion depth blindly.  This is faster than
+  // DecrementRecursionDepth().  It should be used only if all previous
+  // increments to recursion depth were successful.
+  void UnsafeDecrementRecursionDepth();
+
+  // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_).
+  // Using this can reduce code size and complexity in some cases.  The caller
+  // is expected to check that the second part of the result is non-negative (to
+  // bail out if the depth of recursion is too high) and, if all is well, to
+  // later pass the first part of the result to PopLimit() or similar.
+  std::pair<CodedInputStream::Limit, int> IncrementRecursionDepthAndPushLimit(
+      int byte_limit);
+
+  // Shorthand for PushLimit(ReadVarint32(&length) ? length : 0).
+  Limit ReadLengthAndPushLimit();
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  UnsafeDecrementRecursionDepth();
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  // Do not use unless the current recursion depth is greater than zero.
+  bool DecrementRecursionDepthAndPopLimit(Limit limit);
+
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  bool CheckEntireMessageConsumedAndPopLimit(Limit limit);
+
   // Extension Registry ----------------------------------------------
   // ADVANCED USAGE:  99.9% of people can ignore this section.
   //
@@ -470,9 +509,9 @@
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream);
 
-  ZeroCopyInputStream* input_;
   const uint8* buffer_;
   const uint8* buffer_end_;     // pointer to the end of the buffer.
+  ZeroCopyInputStream* input_;
   int total_bytes_read_;  // total bytes read from input_, including
                           // the current buffer
 
@@ -513,9 +552,10 @@
   // If -2: Internal: Limit has been reached, print full size when destructing.
   int total_bytes_warning_threshold_;
 
-  // Current recursion depth, controlled by IncrementRecursionDepth() and
-  // DecrementRecursionDepth().
-  int recursion_depth_;
+  // Current recursion budget, controlled by IncrementRecursionDepth() and
+  // similar.  Starts at recursion_limit_ and goes down: if this reaches
+  // -1 we are over budget.
+  int recursion_budget_;
   // Recursion depth limit, set by SetRecursionLimit().
   int recursion_limit_;
 
@@ -548,9 +588,13 @@
   // optimization. The Slow method is yet another fallback when the buffer is
   // not large enough. Making the slow path out-of-line speeds up the common
   // case by 10-15%. The slow path is fairly uncommon: it only triggers when a
-  // message crosses multiple buffers.
-  bool ReadVarint32Fallback(uint32* value);
-  bool ReadVarint64Fallback(uint64* value);
+  // message crosses multiple buffers.  Note: ReadVarint32Fallback() and
+  // ReadVarint64Fallback() are called frequently and generally not inlined, so
+  // they have been optimized to avoid "out" parameters.  The former returns -1
+  // if it fails and the uint32 it read otherwise.  The latter has a bool
+  // indicating success or failure as part of its return type.
+  int64 ReadVarint32Fallback(uint32 first_byte_or_zero);
+  std::pair<uint64, bool> ReadVarint64Fallback();
   bool ReadVarint32Slow(uint32* value);
   bool ReadVarint64Slow(uint64* value);
   bool ReadLittleEndian32Fallback(uint32* value);
@@ -558,7 +602,7 @@
   // Fallback/slow methods for reading tags. These do not update last_tag_,
   // but will set legitimate_message_end_ if we are at the end of the input
   // stream.
-  uint32 ReadTagFallback();
+  uint32 ReadTagFallback(uint32 first_byte_or_zero);
   uint32 ReadTagSlow();
   bool ReadStringFallback(string* buffer, int size);
 
@@ -622,11 +666,19 @@
  public:
   // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
   explicit CodedOutputStream(ZeroCopyOutputStream* output);
+  CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh);
 
   // Destroy the CodedOutputStream and position the underlying
   // ZeroCopyOutputStream immediately after the last byte written.
   ~CodedOutputStream();
 
+  // Trims any unused space in the underlying buffer so that its size matches
+  // the number of bytes written by this stream. The underlying buffer will
+  // automatically be trimmed when this stream is destroyed; this call is only
+  // necessary if the underlying buffer is accessed *before* the stream is
+  // destroyed.
+  void Trim();
+
   // Skips a number of bytes, leaving the bytes unmodified in the underlying
   // buffer.  Returns false if an underlying write error occurs.  This is
   // mainly useful with GetDirectBufferPointer().
@@ -715,8 +767,8 @@
   // but GCC by default doesn't want to inline this.
   void WriteTag(uint32 value);
   // Like WriteTag()  but writing directly to the target array.
-  static uint8* WriteTagToArray(
-      uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteTagToArray(uint32 value,
+                                                        uint8* target);
 
   // Returns the number of bytes needed to encode the given value as a varint.
   static int VarintSize32(uint32 value);
@@ -769,7 +821,9 @@
   // ZeroCopyOutputStream supports it.
   void WriteAliasedRaw(const void* buffer, int size);
 
-  static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target);
+  // If this write might cross the end of the buffer, we compose the bytes first
+  // then use WriteRaw().
+  void WriteVarint32SlowPath(uint32 value);
 
   // Always-inlined versions of WriteVarint* functions so that code can be
   // reused, while still controlling size. For instance, WriteVarint32ToArray()
@@ -778,10 +832,8 @@
   // WriteVarint32FallbackToArray.  Meanwhile, WriteVarint32() is already
   // out-of-line, so it should just invoke this directly to avoid any extra
   // function call overhead.
-  static uint8* WriteVarint32FallbackToArrayInline(
-      uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-  static uint8* WriteVarint64ToArrayInline(
-      uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteVarint64ToArrayInline(
+      uint64 value, uint8* target);
 
   static int VarintSize32Fallback(uint32 value);
 };
@@ -791,13 +843,18 @@
 // methods optimize for that case.
 
 inline bool CodedInputStream::ReadVarint32(uint32* value) {
-  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) {
-    *value = *buffer_;
-    Advance(1);
-    return true;
-  } else {
-    return ReadVarint32Fallback(value);
+  uint32 v = 0;
+  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
   }
+  int64 result = ReadVarint32Fallback(v);
+  *value = static_cast<uint32>(result);
+  return result >= 0;
 }
 
 inline bool CodedInputStream::ReadVarint64(uint64* value) {
@@ -805,9 +862,10 @@
     *value = *buffer_;
     Advance(1);
     return true;
-  } else {
-    return ReadVarint64Fallback(value);
   }
+  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  *value = p.first;
+  return p.second;
 }
 
 // static
@@ -876,14 +934,17 @@
 }
 
 inline uint32 CodedInputStream::ReadTag() {
-  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) {
-    last_tag_ = buffer_[0];
-    Advance(1);
-    return last_tag_;
-  } else {
-    last_tag_ = ReadTagFallback();
-    return last_tag_;
+  uint32 v = 0;
+  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      last_tag_ = v;
+      Advance(1);
+      return v;
+    }
   }
+  last_tag_ = ReadTagFallback(v);
+  return last_tag_;
 }
 
 inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
@@ -891,15 +952,17 @@
   // In performance-sensitive code we can expect cutoff to be a compile-time
   // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
   // compile time.
+  uint32 first_byte_or_zero = 0;
   if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
     // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
     // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
     // is large enough then is it better to check for the two-byte case first?
+    first_byte_or_zero = buffer_[0];
     if (static_cast<int8>(buffer_[0]) > 0) {
       const uint32 kMax1ByteVarint = 0x7f;
       uint32 tag = last_tag_ = buffer_[0];
       Advance(1);
-      return make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
+      return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
     }
     // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
     // and tag is two bytes.  The latter is tested by bitwise-and-not of the
@@ -917,12 +980,12 @@
       // so we don't have to check for tag == 0.  We may need to check whether
       // it exceeds cutoff.
       bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
-      return make_pair(tag, at_or_below_cutoff);
+      return std::make_pair(tag, at_or_below_cutoff);
     }
   }
   // Slow path
-  last_tag_ = ReadTagFallback();
-  return make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
+  last_tag_ = ReadTagFallback(first_byte_or_zero);
+  return std::make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
 }
 
 inline bool CodedInputStream::LastTagWas(uint32 expected) {
@@ -974,7 +1037,7 @@
 inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
                                                            int* size) {
   *data = buffer_;
-  *size = buffer_end_ - buffer_;
+  *size = static_cast<int>(buffer_end_ - buffer_);
 }
 
 inline bool CodedInputStream::ExpectAtEnd() {
@@ -1007,13 +1070,14 @@
 }
 
 inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
-                                                        uint8* target) {
-  if (value < 0x80) {
-    *target = value;
-    return target + 1;
-  } else {
-    return WriteVarint32FallbackToArray(value, target);
+                                                      uint8* target) {
+  while (value >= 0x80) {
+    *target = static_cast<uint8>(value | 0x80);
+    value >>= 7;
+    ++target;
   }
+  *target = static_cast<uint8>(value);
+  return target + 1;
 }
 
 inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
@@ -1066,22 +1130,26 @@
   return target + sizeof(value);
 }
 
+inline void CodedOutputStream::WriteVarint32(uint32 value) {
+  if (buffer_size_ >= 5) {
+    // Fast path:  We have enough bytes left in the buffer to guarantee that
+    // this write won't cross the end, so we can skip the checks.
+    uint8* target = buffer_;
+    uint8* end = WriteVarint32ToArray(value, target);
+    int size = static_cast<int>(end - target);
+    Advance(size);
+  } else {
+    WriteVarint32SlowPath(value);
+  }
+}
+
 inline void CodedOutputStream::WriteTag(uint32 value) {
   WriteVarint32(value);
 }
 
 inline uint8* CodedOutputStream::WriteTagToArray(
     uint32 value, uint8* target) {
-  if (value < (1 << 7)) {
-    target[0] = value;
-    return target + 1;
-  } else if (value < (1 << 14)) {
-    target[0] = static_cast<uint8>(value | 0x80);
-    target[1] = static_cast<uint8>(value >> 7);
-    return target + 2;
-  } else {
-    return WriteVarint32FallbackToArray(value, target);
-  }
+  return WriteVarint32ToArray(value, target);
 }
 
 inline int CodedOutputStream::VarintSize32(uint32 value) {
@@ -1132,16 +1200,22 @@
 }
 
 inline void CodedInputStream::SetRecursionLimit(int limit) {
+  recursion_budget_ += limit - recursion_limit_;
   recursion_limit_ = limit;
 }
 
 inline bool CodedInputStream::IncrementRecursionDepth() {
-  ++recursion_depth_;
-  return recursion_depth_ <= recursion_limit_;
+  --recursion_budget_;
+  return recursion_budget_ >= 0;
 }
 
 inline void CodedInputStream::DecrementRecursionDepth() {
-  if (recursion_depth_ > 0) --recursion_depth_;
+  if (recursion_budget_ < recursion_limit_) ++recursion_budget_;
+}
+
+inline void CodedInputStream::UnsafeDecrementRecursionDepth() {
+  assert(recursion_budget_ < recursion_limit_);
+  ++recursion_budget_;
 }
 
 inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
@@ -1159,13 +1233,13 @@
 }
 
 inline int CodedInputStream::BufferSize() const {
-  return buffer_end_ - buffer_;
+  return static_cast<int>(buffer_end_ - buffer_);
 }
 
 inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
-  : input_(input),
-    buffer_(NULL),
+  : buffer_(NULL),
     buffer_end_(NULL),
+    input_(input),
     total_bytes_read_(0),
     overflow_bytes_(0),
     last_tag_(0),
@@ -1175,7 +1249,7 @@
     buffer_size_after_limit_(0),
     total_bytes_limit_(kDefaultTotalBytesLimit),
     total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
-    recursion_depth_(0),
+    recursion_budget_(default_recursion_limit_),
     recursion_limit_(default_recursion_limit_),
     extension_pool_(NULL),
     extension_factory_(NULL) {
@@ -1184,9 +1258,9 @@
 }
 
 inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
-  : input_(NULL),
-    buffer_(buffer),
+  : buffer_(buffer),
     buffer_end_(buffer + size),
+    input_(NULL),
     total_bytes_read_(size),
     overflow_bytes_(0),
     last_tag_(0),
@@ -1196,7 +1270,7 @@
     buffer_size_after_limit_(0),
     total_bytes_limit_(kDefaultTotalBytesLimit),
     total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
-    recursion_depth_(0),
+    recursion_budget_(default_recursion_limit_),
     recursion_limit_(default_recursion_limit_),
     extension_pool_(NULL),
     extension_factory_(NULL) {
@@ -1212,9 +1286,9 @@
 }  // namespace protobuf
 
 
-#if defined(_MSC_VER) && _MSC_VER >= 1300
+#if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
   #pragma runtime_checks("c", restore)
-#endif  // _MSC_VER
+#endif  // _MSC_VER && !defined(__INTEL_COMPILER)
 
 }  // namespace google
 #endif  // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h
index 88c14ca..d95b06e 100644
--- a/src/google/protobuf/io/coded_stream_inl.h
+++ b/src/google/protobuf/io/coded_stream_inl.h
@@ -36,6 +36,8 @@
 #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
 #define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
 
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <string>
@@ -51,10 +53,12 @@
 
   if (BufferSize() >= size) {
     STLStringResizeUninitialized(buffer, size);
-    // When buffer is empty, string_as_array(buffer) will return NULL but memcpy
-    // requires non-NULL pointers even when size is 0. Hench this check.
-    if (size > 0) {
-      memcpy(mutable_string_data(buffer), buffer_, size);
+    std::pair<char*, bool> z = as_string_data(buffer);
+    if (z.second) {
+      // Oddly enough, memcpy() requires its first two args to be non-NULL even
+      // if we copy 0 bytes.  So, we have ensured that z.first is non-NULL here.
+      GOOGLE_DCHECK(z.first != NULL);
+      memcpy(z.first, buffer_, size);
       Advance(size);
     }
     return true;
@@ -63,6 +67,23 @@
   return ReadStringFallback(buffer, size);
 }
 
+inline bool CodedInputStream::InternalReadRawInline(void* buffer, int size) {
+  int current_buffer_size;
+  while ((current_buffer_size = BufferSize()) < size) {
+    // Reading past end of buffer.  Copy what we have, then refresh.
+    memcpy(buffer, buffer_, current_buffer_size);
+    buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  memcpy(buffer, buffer_, size);
+  Advance(size);
+
+  return true;
+}
+
 }  // namespace io
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index f4cb5ea..a8108e4 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -34,6 +34,10 @@
 //
 // This file contains tests and benchmarks.
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/io/coded_stream.h>
@@ -41,6 +45,8 @@
 #include <limits.h>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -144,6 +150,7 @@
 // checks.
 const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
 
+
 // -------------------------------------------------------------------
 // Varint tests.
 
@@ -501,11 +508,11 @@
 };
 
 inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
-  return os << "0x" << hex << c.value << dec;
+  return os << "0x" << std::hex << c.value << std::dec;
 }
 
 inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
-  return os << "0x" << hex << c.value << dec;
+  return os << "0x" << std::hex << c.value << std::dec;
 }
 
 Fixed32Case kFixed32Cases[] = {
@@ -676,7 +683,7 @@
 }
 
 TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
-  scoped_array<uint8> buffer(new uint8[8]);
+  google::protobuf::scoped_array<uint8> buffer(new uint8[8]);
   CodedInputStream coded_input(buffer.get(), 8);
   string str;
   EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index ee28696..9c621b6 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -33,12 +33,12 @@
 // This file contains the implementation of classes GzipInputStream and
 // GzipOutputStream.
 
-#include "config.h"
 
 #if HAVE_ZLIB
 #include <google/protobuf/io/gzip_stream.h>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 
 namespace google {
 namespace protobuf {
@@ -48,7 +48,8 @@
 
 GzipInputStream::GzipInputStream(
     ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
-    : format_(format), sub_stream_(sub_stream), zerror_(Z_OK) {
+    : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
+  zcontext_.state = Z_NULL;
   zcontext_.zalloc = Z_NULL;
   zcontext_.zfree = Z_NULL;
   zcontext_.opaque = Z_NULL;
@@ -134,6 +135,7 @@
     if (zcontext_.next_out != NULL) {
       // sub_stream_ may have concatenated streams to follow
       zerror_ = inflateEnd(&zcontext_);
+      byte_count_ += zcontext_.total_out;
       if (zerror_ != Z_OK) {
         return false;
       }
@@ -178,8 +180,12 @@
   return ok;
 }
 int64 GzipInputStream::ByteCount() const {
-  return zcontext_.total_out +
-    (((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_));
+  int64 ret = byte_count_ + zcontext_.total_out;
+  if (zcontext_.next_out != NULL && output_position_ != NULL) {
+    ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
+           reinterpret_cast<uintptr_t>(output_position_);
+  }
+  return ret;
 }
 
 // =========================================================================
@@ -235,9 +241,7 @@
 
 GzipOutputStream::~GzipOutputStream() {
   Close();
-  if (input_buffer_ != NULL) {
-    operator delete(input_buffer_);
-  }
+  operator delete(input_buffer_);
 }
 
 // private
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
index c7ccc26..15b02fe 100644
--- a/src/google/protobuf/io/gzip_stream.h
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -43,10 +43,9 @@
 #ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
 #define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
 
-#include <zlib.h>
-
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <zlib.h>
 
 namespace google {
 namespace protobuf {
@@ -99,6 +98,7 @@
   void* output_buffer_;
   void* output_position_;
   size_t output_buffer_length_;
+  int64 byte_count_;
 
   int Inflate(int flush);
   void DoNextOutput(const void** data, int* size);
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index c8df417..7532b09 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -34,6 +34,7 @@
 
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -41,13 +42,25 @@
 namespace io {
 
 Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
-  : variable_delimiter_(variable_delimiter),
-    output_(output),
-    buffer_(NULL),
-    buffer_size_(0),
-    at_start_of_line_(true),
-    failed_(false) {
-}
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(NULL) {}
+
+Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+                 AnnotationCollector* annotation_collector)
+    : variable_delimiter_(variable_delimiter),
+      output_(output),
+      buffer_(NULL),
+      buffer_size_(0),
+      offset_(0),
+      at_start_of_line_(true),
+      failed_(false),
+      annotation_collector_(annotation_collector) {}
 
 Printer::~Printer() {
   // Only BackUp() if we have called Next() at least once and never failed.
@@ -56,9 +69,47 @@
   }
 }
 
+bool Printer::GetSubstitutionRange(const char* varname,
+                                   pair<size_t, size_t>* range) {
+  map<string, pair<size_t, size_t> >::const_iterator iter =
+      substitutions_.find(varname);
+  if (iter == substitutions_.end()) {
+    GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
+    return false;
+  }
+  if (iter->second.first > iter->second.second) {
+    GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
+                << varname;
+    return false;
+  }
+  *range = iter->second;
+  return true;
+}
+
+void Printer::Annotate(const char* begin_varname, const char* end_varname,
+                       const string& file_path, const vector<int>& path) {
+  if (annotation_collector_ == NULL) {
+    // Can't generate signatures with this Printer.
+    return;
+  }
+  pair<size_t, size_t> begin, end;
+  if (!GetSubstitutionRange(begin_varname, &begin) ||
+      !GetSubstitutionRange(end_varname, &end)) {
+    return;
+  }
+  if (begin.first > end.second) {
+    GOOGLE_LOG(DFATAL) << "  Annotation has negative length from " << begin_varname
+                << " to " << end_varname;
+  } else {
+    annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
+                                         path);
+  }
+}
+
 void Printer::Print(const map<string, string>& variables, const char* text) {
   int size = strlen(text);
   int pos = 0;  // The number of bytes we've written so far.
+  substitutions_.clear();
 
   for (int i = 0; i < size; i++) {
     if (text[i] == '\n') {
@@ -96,7 +147,17 @@
         if (iter == variables.end()) {
           GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
         } else {
+          size_t begin = offset_;
           WriteRaw(iter->second.data(), iter->second.size());
+          pair<map<string, pair<size_t, size_t> >::iterator, bool> inserted =
+              substitutions_.insert(
+                  std::make_pair(varname, std::make_pair(begin, offset_)));
+          if (!inserted.second) {
+            // This variable was used multiple times.  Make its span have
+            // negative length so we can detect it if it gets used in an
+            // annotation.
+            inserted.first->second = std::make_pair(1, 0);
+          }
         }
       }
 
@@ -142,6 +203,91 @@
   Print(vars, text);
 }
 
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6,
+                    const char* variable7, const string& value7) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  vars[variable7] = value7;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6,
+                    const char* variable7, const string& value7,
+                    const char* variable8, const string& value8) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  vars[variable7] = value7;
+  vars[variable8] = value8;
+  Print(vars, text);
+}
+
 void Printer::Indent() {
   indent_ += "  ";
 }
@@ -179,6 +325,7 @@
     // Data exceeds space in the buffer.  Copy what we can and request a
     // new buffer.
     memcpy(buffer_, data, buffer_size_);
+    offset_ += buffer_size_;
     data += buffer_size_;
     size -= buffer_size_;
     void* void_buffer;
@@ -191,6 +338,7 @@
   memcpy(buffer_, data, size);
   buffer_ += size;
   buffer_size_ -= size;
+  offset_ += size;
 }
 
 }  // namespace io
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index f06cbf2..2ba8455 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -39,6 +39,7 @@
 
 #include <string>
 #include <map>
+#include <vector>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -47,6 +48,47 @@
 
 class ZeroCopyOutputStream;     // zero_copy_stream.h
 
+// Records annotations about a Printer's output.
+class LIBPROTOBUF_EXPORT AnnotationCollector {
+ public:
+  // Records that the bytes in file_path beginning with begin_offset and ending
+  // before end_offset are associated with the SourceCodeInfo-style path.
+  virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
+                             const string& file_path,
+                             const vector<int>& path) = 0;
+
+  virtual ~AnnotationCollector() {}
+};
+
+// Records annotations about a Printer's output to the given protocol buffer,
+// assuming that the buffer has an ::Annotation message exposing path,
+// source_file, begin and end fields.
+template <typename AnnotationProto>
+class AnnotationProtoCollector : public AnnotationCollector {
+ public:
+  // annotation_proto is the protocol buffer to which new Annotations should be
+  // added. It is not owned by the AnnotationProtoCollector.
+  explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
+      : annotation_proto_(annotation_proto) {}
+
+  // Override for AnnotationCollector::AddAnnotation.
+  virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
+                             const string& file_path, const vector<int>& path) {
+    typename AnnotationProto::Annotation* annotation =
+        annotation_proto_->add_annotation();
+    for (int i = 0; i < path.size(); ++i) {
+      annotation->add_path(path[i]);
+    }
+    annotation->set_source_file(file_path);
+    annotation->set_begin(begin_offset);
+    annotation->set_end(end_offset);
+  }
+
+ private:
+  // The protocol buffer to which new annotations should be added.
+  AnnotationProto* const annotation_proto_;
+};
+
 // This simple utility class assists in code generation.  It basically
 // allows the caller to define a set of variables and then output some
 // text with variable substitutions.  Example usage:
@@ -61,13 +103,103 @@
 // Printer aggressively enforces correct usage, crashing (with assert failures)
 // in the case of undefined variables in debug builds. This helps greatly in
 // debugging code which uses it.
+//
+// If a Printer is constructed with an AnnotationCollector, it will provide it
+// with annotations that connect the Printer's output to paths that can identify
+// various descriptors.  In the above example, if person_ is a descriptor that
+// identifies Bob, we can associate the output string "My name is Bob." with
+// a source path pointing to that descriptor with:
+//
+//   printer.Annotate("name", person_);
+//
+// The AnnotationCollector will be sent an annotation linking the output range
+// covering "Bob" to the logical path provided by person_.  Tools may use
+// this association to (for example) link "Bob" in the output back to the
+// source file that defined the person_ descriptor identifying Bob.
+//
+// Annotate can only examine variables substituted during the last call to
+// Print.  It is invalid to refer to a variable that was used multiple times
+// in a single Print call.
+//
+// In full generality, one may specify a range of output text using a beginning
+// substitution variable and an ending variable.  The resulting annotation will
+// span from the first character of the substituted value for the beginning
+// variable to the last character of the substituted value for the ending
+// variable.  For example, the Annotate call above is equivalent to this one:
+//
+//   printer.Annotate("name", "name", person_);
+//
+// This is useful if multiple variables combine to form a single span of output
+// that should be annotated with the same source path.  For example:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["first"] = "Alice";
+//   vars["last"] = "Smith";
+//   printer.Print(vars, "My name is $first$ $last$.");
+//   printer.Annotate("first", "last", person_);
+//
+// This code would associate the span covering "Alice Smith" in the output with
+// the person_ descriptor.
+//
+// Note that the beginning variable must come before (or overlap with, in the
+// case of zero-sized substitution values) the ending variable.
+//
+// It is also sometimes useful to use variables with zero-sized values as
+// markers.  This avoids issues with multiple references to the same variable
+// and also allows annotation ranges to span literal text from the Print
+// templates:
+//
+//   Printer printer(output, '$');
+//   map<string, string> vars;
+//   vars["foo"] = "bar";
+//   vars["function"] = "call";
+//   vars["mark"] = "";
+//   printer.Print(vars, "$function$($foo$,$foo$)$mark$");
+//   printer.Annotate("function", "rmark", call_);
+//
+// This code associates the span covering "call(bar,bar)" in the output with the
+// call_ descriptor.
+
 class LIBPROTOBUF_EXPORT Printer {
  public:
   // Create a printer that writes text to the given output stream.  Use the
   // given character as the delimiter for variables.
   Printer(ZeroCopyOutputStream* output, char variable_delimiter);
+
+  // Create a printer that writes text to the given output stream.  Use the
+  // given character as the delimiter for variables.  If annotation_collector
+  // is not null, Printer will provide it with annotations about code written
+  // to the stream.  annotation_collector is not owned by Printer.
+  Printer(ZeroCopyOutputStream* output, char variable_delimiter,
+          AnnotationCollector* annotation_collector);
+
   ~Printer();
 
+  // Link a subsitution variable emitted by the last call to Print to the object
+  // described by descriptor.
+  template <typename SomeDescriptor>
+  void Annotate(const char* varname, const SomeDescriptor* descriptor) {
+    Annotate(varname, varname, descriptor);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object described by descriptor. The range
+  // begins at begin_varname's value and ends after the last character of the
+  // value substituted for end_varname.
+  template <typename SomeDescriptor>
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const SomeDescriptor* descriptor) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer, so don't pay the cost
+      // of building the location path.
+      return;
+    }
+    vector<int> path;
+    descriptor->GetLocationPath(&path);
+    Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
+  }
+
   // Print some text after applying variable substitutions.  If a particular
   // variable in the text is not defined, this will crash.  Variables to be
   // substituted are identified by their names surrounded by delimiter
@@ -86,8 +218,41 @@
   void Print(const char* text, const char* variable1, const string& value1,
                                const char* variable2, const string& value2,
                                const char* variable3, const string& value3);
-  // TODO(kenton):  Overloaded versions with more variables?  Three seems
-  //   to be enough.
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6,
+                               const char* variable7, const string& value7);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6,
+                               const char* variable7, const string& value7,
+                               const char* variable8, const string& value8);
 
   // Indent text by two spaces.  After calling Indent(), two spaces will be
   // inserted at the beginning of each line of text.  Indent() may be called
@@ -116,16 +281,48 @@
   bool failed() const { return failed_; }
 
  private:
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the object found at the SourceCodeInfo-style path
+  // in a file with path file_path. The range begins at the start of
+  // begin_varname's value and ends after the last character of the value
+  // substituted for end_varname. Note that begin_varname and end_varname
+  // may refer to the same variable.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const string& file_path, const vector<int>& path);
+
   const char variable_delimiter_;
 
   ZeroCopyOutputStream* const output_;
   char* buffer_;
   int buffer_size_;
+  // The current position, in bytes, in the output stream.  This is equivalent
+  // to the total number of bytes that have been written so far.  This value is
+  // used to calculate annotation ranges in the substitutions_ map below.
+  size_t offset_;
 
   string indent_;
   bool at_start_of_line_;
   bool failed_;
 
+  // A map from variable name to [start, end) offsets in the output buffer.
+  // These refer to the offsets used for a variable after the last call to
+  // Print.  If a variable was used more than once, the entry used in
+  // this map is set to a negative-length span.  For singly-used variables, the
+  // start offset is the beginning of the substitution; the end offset is the
+  // last byte of the substitution plus one (such that (end - start) is the
+  // length of the substituted string).
+  map<string, pair<size_t, size_t> > substitutions_;
+
+  // Returns true and sets range to the substitution range in the output for
+  // varname if varname was used once in the last call to Print. If varname
+  // was not used, or if it was used multiple times, returns false (and
+  // fails a debug assertion).
+  bool GetSubstitutionRange(const char* varname, pair<size_t, size_t>* range);
+
+  // If non-null, annotation_collector_ is used to store annotations about
+  // generated code.
+  AnnotationCollector* const annotation_collector_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
 };
 
diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc
index 1331a8d..95f3afa 100644
--- a/src/google/protobuf/io/printer_unittest.cc
+++ b/src/google/protobuf/io/printer_unittest.cc
@@ -36,7 +36,9 @@
 
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -168,6 +170,196 @@
                buffer);
 }
 
+// MockDescriptorFile defines only those members that Printer uses to write out
+// annotations.
+class MockDescriptorFile {
+ public:
+  explicit MockDescriptorFile(const string& file) : file_(file) {}
+
+  // The mock filename for this file.
+  const string& name() const { return file_; }
+
+ private:
+  string file_;
+};
+
+// MockDescriptor defines only those members that Printer uses to write out
+// annotations.
+class MockDescriptor {
+ public:
+  MockDescriptor(const string& file, const vector<int>& path)
+      : file_(file), path_(path) {}
+
+  // The mock file in which this descriptor was defined.
+  const MockDescriptorFile* file() const { return &file_; }
+
+ private:
+  // Allows access to GetLocationPath.
+  friend class ::google::protobuf::io::Printer;
+
+  // Copies the pre-stored path to output.
+  void GetLocationPath(std::vector<int>* output) const { *output = path_; }
+
+  MockDescriptorFile file_;
+  vector<int> path_;
+};
+
+TEST(Printer, AnnotateMap) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    map<string, string> vars;
+    vars["foo"] = "3";
+    vars["bar"] = "5";
+    printer.Print(vars, "012$foo$4$bar$\n");
+    vector<int> path_1;
+    path_1.push_back(33);
+    vector<int> path_2;
+    path_2.push_back(11);
+    path_2.push_back(22);
+    MockDescriptor descriptor_1("path_1", path_1);
+    MockDescriptor descriptor_2("path_2", path_2);
+    printer.Annotate("foo", "foo", &descriptor_1);
+    printer.Annotate("bar", "bar", &descriptor_2);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(2, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(0)
+                                                 : &info.annotation(1);
+  const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(1)
+                                                 : &info.annotation(0);
+  ASSERT_EQ(1, foo->path_size());
+  ASSERT_EQ(2, bar->path_size());
+  EXPECT_EQ(33, foo->path(0));
+  EXPECT_EQ(11, bar->path(0));
+  EXPECT_EQ(22, bar->path(1));
+  EXPECT_EQ("path_1", foo->source_file());
+  EXPECT_EQ("path_2", bar->source_file());
+  EXPECT_EQ(3, foo->begin());
+  EXPECT_EQ(4, foo->end());
+  EXPECT_EQ(5, bar->begin());
+  EXPECT_EQ(6, bar->end());
+}
+
+TEST(Printer, AnnotateInline) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    vector<int> path_1;
+    path_1.push_back(33);
+    vector<int> path_2;
+    path_2.push_back(11);
+    path_2.push_back(22);
+    MockDescriptor descriptor_1("path_1", path_1);
+    MockDescriptor descriptor_2("path_2", path_2);
+    printer.Annotate("foo", "foo", &descriptor_1);
+    printer.Annotate("bar", "bar", &descriptor_2);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(2, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(0)
+                                                 : &info.annotation(1);
+  const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1
+                                                 ? &info.annotation(1)
+                                                 : &info.annotation(0);
+  ASSERT_EQ(1, foo->path_size());
+  ASSERT_EQ(2, bar->path_size());
+  EXPECT_EQ(33, foo->path(0));
+  EXPECT_EQ(11, bar->path(0));
+  EXPECT_EQ(22, bar->path(1));
+  EXPECT_EQ("path_1", foo->source_file());
+  EXPECT_EQ("path_2", bar->source_file());
+  EXPECT_EQ(3, foo->begin());
+  EXPECT_EQ(4, foo->end());
+  EXPECT_EQ(5, bar->begin());
+  EXPECT_EQ(6, bar->end());
+}
+
+TEST(Printer, AnnotateRange) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("foo", "bar", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0);
+  ASSERT_EQ(1, foobar->path_size());
+  EXPECT_EQ(33, foobar->path(0));
+  EXPECT_EQ("path", foobar->source_file());
+  EXPECT_EQ(3, foobar->begin());
+  EXPECT_EQ(6, foobar->end());
+}
+
+TEST(Printer, AnnotateEmptyRange) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz",
+                  "", "bam", "");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("baz", "bam", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("012345\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0);
+  ASSERT_EQ(1, bazbam->path_size());
+  EXPECT_EQ(33, bazbam->path(0));
+  EXPECT_EQ("path", bazbam->source_file());
+  EXPECT_EQ(5, bazbam->begin());
+  EXPECT_EQ(5, bazbam->end());
+}
+
+TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    printer.Annotate("bar", "bar", &descriptor);
+  }
+  buffer[output.ByteCount()] = '\0';
+  EXPECT_STREQ("0123435\n", buffer);
+  ASSERT_EQ(1, info.annotation_size());
+  const GeneratedCodeInfo::Annotation* bar = &info.annotation(0);
+  ASSERT_EQ(1, bar->path_size());
+  EXPECT_EQ(33, bar->path(0));
+  EXPECT_EQ("path", bar->source_file());
+  EXPECT_EQ(6, bar->begin());
+  EXPECT_EQ(7, bar->end());
+}
+
 TEST(Printer, Indenting) {
   char buffer[8192];
 
@@ -231,6 +423,52 @@
   EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
   EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
 }
+
+TEST(Printer, AnnotateMultipleUsesDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$\n", "foo", "3");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple");
+  }
+}
+
+TEST(Printer, AnnotateNegativeLengthDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative");
+  }
+}
+
+TEST(Printer, AnnotateUndefinedDeath) {
+  char buffer[8192];
+  ArrayOutputStream output(buffer, sizeof(buffer));
+  GeneratedCodeInfo info;
+  AnnotationProtoCollector<GeneratedCodeInfo> info_collector(&info);
+  {
+    Printer printer(&output, '$', &info_collector);
+    printer.Print("012$foo$4$foo$\n", "foo", "3");
+    vector<int> path;
+    path.push_back(33);
+    MockDescriptor descriptor("path", path);
+    EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor),
+                       "Undefined");
+  }
+}
 #endif  // PROTOBUF_HAS_DEATH_TEST
 
 TEST(Printer, WriteFailurePartial) {
diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc
index 5697343..a90bb9a 100644
--- a/src/google/protobuf/io/strtod.cc
+++ b/src/google/protobuf/io/strtod.cc
@@ -32,8 +32,10 @@
 
 #include <cstdio>
 #include <cstring>
+#include <limits>
 #include <string>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -108,6 +110,16 @@
   return result;
 }
 
+float SafeDoubleToFloat(double value) {
+  if (value > std::numeric_limits<float>::max()) {
+    return std::numeric_limits<float>::infinity();
+  } else if (value < -std::numeric_limits<float>::max()) {
+    return -std::numeric_limits<float>::infinity();
+  } else {
+    return static_cast<float>(value);
+  }
+}
+
 }  // namespace io
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h
index c2efc8d..f56e41c 100644
--- a/src/google/protobuf/io/strtod.h
+++ b/src/google/protobuf/io/strtod.h
@@ -43,6 +43,11 @@
 // uses a dot as the decimal separator.
 double NoLocaleStrtod(const char* str, char** endptr);
 
+// Casts a double value to a float value. If the value is outside of the
+// representable range of float, it will be converted to positive or negative
+// infinity.
+float SafeDoubleToFloat(double value);
+
 }  // namespace io
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index ef2de30..b3550df 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -90,6 +90,7 @@
 
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/io/strtod.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -374,7 +375,7 @@
           // Possibly followed by two more octal digits, but these will
           // just be consumed by the main loop anyway so we don't need
           // to do so explicitly here.
-        } else if (TryConsume('x') || TryConsume('X')) {
+        } else if (TryConsume('x')) {
           if (!TryConsumeOne<HexDigit>()) {
             AddError("Expected hex digits for escape sequence.");
           }
@@ -762,6 +763,15 @@
                              next_leading_comments);
 
   if (current_.type == TYPE_START) {
+    // Ignore unicode byte order mark(BOM) if it appears at the file
+    // beginning. Only UTF-8 BOM (0xEF 0xBB 0xBF) is accepted.
+    if (TryConsume((char)0xEF)) {
+      if (!TryConsume((char)0xBB) || !TryConsume((char)0xBF)) {
+        AddError("Proto file starts with 0xEF but not UTF-8 BOM. "
+                 "Only UTF-8 is accepted for proto file.");
+        return false;
+      }
+    }
     collector.DetachFromPrev();
   } else {
     // A comment appearing on the same line must be attached to the previous
@@ -871,9 +881,11 @@
   uint64 result = 0;
   for (; *ptr != '\0'; ptr++) {
     int digit = DigitValue(*ptr);
-    GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base)
-      << " Tokenizer::ParseInteger() passed text that could not have been"
-         " tokenized as an integer: " << CEscape(text);
+    if (digit < 0 || digit >= base) {
+      // The token provided by Tokenizer is invalid. i.e., 099 is an invalid
+      // token, but Tokenizer still think it's integer.
+      return false;
+    }
     if (digit > max_value || result > (max_value - digit) / base) {
       // Overflow.
       return false;
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index 8c6220a..64ee7d8 100644
--- a/src/google/protobuf/io/tokenizer.h
+++ b/src/google/protobuf/io/tokenizer.h
@@ -40,6 +40,7 @@
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 
 namespace google {
 namespace protobuf {
@@ -51,6 +52,12 @@
 class ErrorCollector;
 class Tokenizer;
 
+// By "column number", the proto compiler refers to a count of the number
+// of bytes before a given byte, except that a tab character advances to
+// the next multiple of 8 bytes.  Note in particular that column numbers
+// are zero-based, while many user interfaces use one-based column numbers.
+typedef int ColumnNumber;
+
 // Abstract interface for an object which collects the errors that occur
 // during parsing.  A typical implementation might simply print the errors
 // to stdout.
@@ -62,13 +69,14 @@
   // Indicates that there was an error in the input at the given line and
   // column numbers.  The numbers are zero-based, so you may want to add
   // 1 to each before printing them.
-  virtual void AddError(int line, int column, const string& message) = 0;
+  virtual void AddError(int line, ColumnNumber column,
+                        const string& message) = 0;
 
   // Indicates that there was a warning in the input at the given line and
   // column numbers.  The numbers are zero-based, so you may want to add
   // 1 to each before printing them.
-  virtual void AddWarning(int /* line */, int /* column */,
-                          const string& /* message */) { }
+  virtual void AddWarning(int line, ColumnNumber column,
+                          const string& message) { }
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
@@ -123,8 +131,8 @@
     // "line" and "column" specify the position of the first character of
     // the token within the input stream.  They are zero-based.
     int line;
-    int column;
-    int end_column;
+    ColumnNumber column;
+    ColumnNumber end_column;
   };
 
   // Get the current token.  This is updated when Next() is called.  Before
@@ -262,7 +270,7 @@
 
   // Line and column number of current_char_ within the whole input stream.
   int line_;
-  int column_;
+  ColumnNumber column_;
 
   // String to which text should be appended as we advance through it.
   // Call RecordTo(&str) to start recording and StopRecording() to stop.
@@ -279,6 +287,7 @@
 
   // Since we count columns we need to interpret tabs somehow.  We'll take
   // the standard 8-character definition for lack of any way to do better.
+  // This must match the documentation of ColumnNumber.
   static const int kTabWidth = 8;
 
   // -----------------------------------------------------------------
@@ -350,7 +359,7 @@
 
   // -----------------------------------------------------------------
   // These helper methods make the parsing code more readable.  The
-  // "character classes" refered to are defined at the top of the .cc file.
+  // "character classes" referred to are defined at the top of the .cc file.
   // Basically it is a C++ class with one method:
   //   static bool InClass(char c);
   // The method returns true if c is a member of this "class", like "Letter"
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index de096fb..ae0811f 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -41,6 +41,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/testing/googletest.h>
@@ -735,19 +736,13 @@
   EXPECT_EQ(0, ParseInteger("0x"));
 
   uint64 i;
-#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet
+
   // Test invalid integers that will never be tokenized as integers.
-  EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i),
-    "passed text that could not have been tokenized as an integer");
-  EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("1.2", kuint64max, &i),
-    "passed text that could not have been tokenized as an integer");
-  EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("08", kuint64max, &i),
-    "passed text that could not have been tokenized as an integer");
-  EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("0xg", kuint64max, &i),
-    "passed text that could not have been tokenized as an integer");
-  EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i),
-    "passed text that could not have been tokenized as an integer");
-#endif  // PROTOBUF_HAS_DEATH_TEST
+  EXPECT_FALSE(Tokenizer::ParseInteger("zxy", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("1.2", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("08", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("0xg", kuint64max, &i));
+  EXPECT_FALSE(Tokenizer::ParseInteger("-1", kuint64max, &i));
 
   // Test overflows.
   EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i));
@@ -874,6 +869,8 @@
   // String errors.
   { "'\\l' foo", true,
     "0:2: Invalid escape sequence in string literal.\n" },
+  { "'\\X' foo", true,
+    "0:2: Invalid escape sequence in string literal.\n" },
   { "'\\x' foo", true,
     "0:3: Expected hex digits for escape sequence.\n" },
   { "'foo", false,
diff --git a/src/google/protobuf/io/zero_copy_stream.cc b/src/google/protobuf/io/zero_copy_stream.cc
index f77c768..186de00 100644
--- a/src/google/protobuf/io/zero_copy_stream.cc
+++ b/src/google/protobuf/io/zero_copy_stream.cc
@@ -34,6 +34,7 @@
 
 #include <google/protobuf/io/zero_copy_stream.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index f7901b2..7ec2b5d 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -46,6 +46,7 @@
 
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
index 58aff0e..e6ca88c 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -37,7 +37,9 @@
 #include <algorithm>
 #include <limits>
 
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 namespace google {
@@ -67,7 +69,7 @@
 
 bool ArrayInputStream::Next(const void** data, int* size) {
   if (position_ < size_) {
-    last_returned_size_ = min(block_size_, size_ - position_);
+    last_returned_size_ = std::min(block_size_, size_ - position_);
     *data = data_ + position_;
     *size = last_returned_size_;
     position_ += last_returned_size_;
@@ -120,7 +122,7 @@
 
 bool ArrayOutputStream::Next(void** data, int* size) {
   if (position_ < size_) {
-    last_returned_size_ = min(block_size_, size_ - position_);
+    last_returned_size_ = std::min(block_size_, size_ - position_);
     *data = data_ + position_;
     *size = last_returned_size_;
     position_ += last_returned_size_;
@@ -155,6 +157,7 @@
 }
 
 bool StringOutputStream::Next(void** data, int* size) {
+  GOOGLE_CHECK(target_ != NULL);
   int old_size = target_->size();
 
   // Grow the string.
@@ -174,9 +177,9 @@
     // Double the size, also make sure that the new size is at least
     // kMinimumSize.
     STLStringResizeUninitialized(
-      target_,
-      max(old_size * 2,
-          kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
+        target_,
+        std::max(old_size * 2,
+                 kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
   }
 
   *data = mutable_string_data(target_) + old_size;
@@ -186,14 +189,44 @@
 
 void StringOutputStream::BackUp(int count) {
   GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK(target_ != NULL);
   GOOGLE_CHECK_LE(count, target_->size());
   target_->resize(target_->size() - count);
 }
 
 int64 StringOutputStream::ByteCount() const {
+  GOOGLE_CHECK(target_ != NULL);
   return target_->size();
 }
 
+void StringOutputStream::SetString(string* target) {
+  target_ = target;
+}
+
+// ===================================================================
+
+LazyStringOutputStream::LazyStringOutputStream(
+    ResultCallback<string*>* callback)
+    : StringOutputStream(NULL),
+      callback_(GOOGLE_CHECK_NOTNULL(callback)),
+      string_is_set_(false) {
+}
+
+LazyStringOutputStream::~LazyStringOutputStream() {
+}
+
+bool LazyStringOutputStream::Next(void** data, int* size) {
+  if (!string_is_set_) {
+    SetString(callback_->Run());
+    string_is_set_ = true;
+  }
+  return StringOutputStream::Next(data, size);
+}
+
+int64 LazyStringOutputStream::ByteCount() const {
+  return string_is_set_ ? StringOutputStream::ByteCount() : 0;
+}
+
 // ===================================================================
 
 CopyingInputStream::~CopyingInputStream() {}
@@ -202,8 +235,8 @@
   char junk[4096];
   int skipped = 0;
   while (skipped < count) {
-    int bytes = Read(junk, min(count - skipped,
-                               implicit_cast<int>(sizeof(junk))));
+    int bytes =
+        Read(junk, std::min(count - skipped, implicit_cast<int>(sizeof(junk))));
     if (bytes <= 0) {
       // EOF or read error.
       return skipped;
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
index e18da72..9d81ccf 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -44,10 +44,16 @@
 #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
 #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <iosfwd>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 
@@ -127,8 +133,10 @@
 class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
  public:
   // Create a StringOutputStream which appends bytes to the given string.
-  // The string remains property of the caller, but it MUST NOT be accessed
-  // in any way until the stream is destroyed.
+  // The string remains property of the caller, but it is mutated in arbitrary
+  // ways and MUST NOT be accessed in any way until you're done with the
+  // stream. Either be sure there's no further usage, or (safest) destroy the
+  // stream before using the contents.
   //
   // Hint:  If you call target->reserve(n) before creating the stream,
   //   the first call to Next() will return at least n bytes of buffer
@@ -141,6 +149,9 @@
   void BackUp(int count);
   int64 ByteCount() const;
 
+ protected:
+  void SetString(string* target);
+
  private:
   static const int kMinimumSize = 16;
 
@@ -149,6 +160,27 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
 };
 
+// LazyStringOutputStream is a StringOutputStream with lazy acquisition of
+// the output string from a callback. The string is owned externally, and not
+// deleted in the stream destructor.
+class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream {
+ public:
+  // Callback should be permanent (non-self-deleting). Ownership is transferred
+  // to the LazyStringOutputStream.
+  explicit LazyStringOutputStream(ResultCallback<string*>* callback);
+  ~LazyStringOutputStream();
+
+  // implements ZeroCopyOutputStream, overriding StringOutputStream -----------
+  bool Next(void** data, int* size);
+  int64 ByteCount() const;
+
+ private:
+  const google::protobuf::scoped_ptr<ResultCallback<string*> > callback_;
+  bool string_is_set_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream);
+};
+
 // Note:  There is no StringInputStream.  Instead, just create an
 // ArrayInputStream as follows:
 //   ArrayInputStream input(str.data(), str.size());
@@ -232,7 +264,7 @@
 
   // Data is read into this buffer.  It may be NULL if no buffer is currently
   // in use.  Otherwise, it points to an array of size buffer_size_.
-  scoped_array<uint8> buffer_;
+  google::protobuf::scoped_array<uint8> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
@@ -321,7 +353,7 @@
 
   // Data is written from this buffer.  It may be NULL if no buffer is
   // currently in use.  Otherwise, it points to an array of size buffer_size_.
-  scoped_array<uint8> buffer_;
+  google::protobuf::scoped_array<uint8> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
@@ -334,6 +366,18 @@
 
 // ===================================================================
 
+// mutable_string_data() and as_string_data() are workarounds to improve
+// the performance of writing new data to an existing string.  Unfortunately
+// the methods provided by the string class are suboptimal, and using memcpy()
+// is mildly annoying because it requires its pointer args to be non-NULL even
+// if we ask it to copy 0 bytes.  Furthermore, string_as_array() has the
+// property that it always returns NULL if its arg is the empty string, exactly
+// what we want to avoid if we're using it in conjunction with memcpy()!
+// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size),
+// where s is a string*.  Without C++11, &(*s)[0] is not guaranteed to be safe,
+// so we use string_as_array(), and live with the extra logic that tests whether
+// *s is empty.
+
 // Return a pointer to mutable characters underlying the given string.  The
 // return value is valid until the next time the string is resized.  We
 // trust the caller to treat the return value as an array of length s->size().
@@ -347,6 +391,19 @@
 #endif
 }
 
+// as_string_data(s) is equivalent to
+//  ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); })
+// Sometimes it's faster: in some scenarios p cannot be NULL, and then the
+// code can avoid that check.
+inline std::pair<char*, bool> as_string_data(string* s) {
+  char *p = mutable_string_data(s);
+#ifdef LANG_CXX11
+  return std::make_pair(p, true);
+#else
+  return make_pair(p, p != NULL);
+#endif
+}
+
 }  // namespace io
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
index bf978cc..a9db887 100644
--- a/src/google/protobuf/io/zero_copy_stream_unittest.cc
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -46,7 +46,6 @@
 //   "parametized tests" so that one set of tests can be used on all the
 //   implementations.
 
-#include "config.h"
 
 #ifdef _MSC_VER
 #include <io.h>
@@ -58,16 +57,22 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <sstream>
 
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
 
 #if HAVE_ZLIB
 #include <google/protobuf/io/gzip_stream.h>
 #endif
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/testing/googletest.h>
 #include <google/protobuf/testing/file.h>
 #include <gtest/gtest.h>
@@ -196,7 +201,7 @@
 }
 
 void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
-  scoped_array<char> buffer(new char[str.size() + 1]);
+  google::protobuf::scoped_array<char> buffer(new char[str.size() + 1]);
   buffer[str.size()] = '\0';
   EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
   EXPECT_STREQ(str.c_str(), buffer.get());
@@ -656,6 +661,43 @@
   delete [] temp_buffer;
   delete [] buffer;
 }
+
+TEST_F(IoTest, GzipInputByteCountAfterClosed) {
+  string golden = "abcdefghijklmnopqrstuvwxyz";
+  string compressed = Compress(golden, GzipOutputStream::Options());
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ArrayInputStream arr_input(compressed.data(), compressed.size(),
+                               kBlockSizes[i]);
+    GzipInputStream gz_input(&arr_input);
+    const void* buffer;
+    int size;
+    while (gz_input.Next(&buffer, &size)) {
+      EXPECT_LE(gz_input.ByteCount(), golden.size());
+    }
+    EXPECT_EQ(golden.size(), gz_input.ByteCount());
+  }
+}
+
+TEST_F(IoTest, GzipInputByteCountAfterClosedConcatenatedStreams) {
+  string golden1 = "abcdefghijklmnopqrstuvwxyz";
+  string golden2 = "the quick brown fox jumps over the lazy dog";
+  const size_t total_size = golden1.size() + golden2.size();
+  string compressed = Compress(golden1, GzipOutputStream::Options()) +
+                      Compress(golden2, GzipOutputStream::Options());
+
+  for (int i = 0; i < kBlockSizeCount; i++) {
+    ArrayInputStream arr_input(compressed.data(), compressed.size(),
+                               kBlockSizes[i]);
+    GzipInputStream gz_input(&arr_input);
+    const void* buffer;
+    int size;
+    while (gz_input.Next(&buffer, &size)) {
+      EXPECT_LE(gz_input.ByteCount(), total_size);
+    }
+    EXPECT_EQ(total_size, gz_input.ByteCount());
+  }
+}
 #endif
 
 // There is no string input, only string output.  Also, it doesn't support
diff --git a/src/google/protobuf/lite_arena_unittest.cc b/src/google/protobuf/lite_arena_unittest.cc
new file mode 100644
index 0000000..f0bee88
--- /dev/null
+++ b/src/google/protobuf/lite_arena_unittest.cc
@@ -0,0 +1,83 @@
+// 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.
+
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_lite_test_util.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(LiteArenaTest, MapNoHeapAllocation) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  google::protobuf::ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  google::protobuf::Arena arena(options);
+  string data;
+  data.reserve(128 * 1024);
+
+  {
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in
+    // Map.
+    // google::protobuf::internal::NoHeapChecker no_heap;
+
+    protobuf_unittest::TestArenaMapLite* from =
+        google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(&arena);
+    google::protobuf::MapLiteTestUtil::SetArenaMapFields(from);
+    from->SerializeToString(&data);
+
+    protobuf_unittest::TestArenaMapLite* to =
+        google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(&arena);
+    to->ParseFromString(data);
+    google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to);
+  }
+}
+
+TEST(LiteArenaTest, UnknownFieldMemLeak) {
+  google::protobuf::Arena arena;
+  protobuf_unittest::ForeignMessageArenaLite* message =
+      google::protobuf::Arena::CreateMessage<protobuf_unittest::ForeignMessageArenaLite>(
+          &arena);
+  string data = "\012\000";
+  int original_capacity = data.capacity();
+  while (data.capacity() <= original_capacity) {
+    data.append("a");
+  }
+  data[1] = data.size() - 2;
+  message->ParseFromString(data);
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index a370526..3ca3fba 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -33,13 +33,18 @@
 #include <string>
 #include <iostream>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/map_lite_test_util.h>
 #include <google/protobuf/test_util_lite.h>
 #include <google/protobuf/unittest_lite.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/stubs/strutil.h>
 
 using namespace std;
 
@@ -84,6 +89,12 @@
 
 }  // namespace
 
+#define EXPECT_TRUE GOOGLE_CHECK
+#define ASSERT_TRUE GOOGLE_CHECK
+#define EXPECT_FALSE(COND) GOOGLE_CHECK(!(COND))
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+#define ASSERT_EQ GOOGLE_CHECK_EQ
+
 int main(int argc, char* argv[]) {
   string data, data2, packed_data;
 
@@ -345,6 +356,363 @@
     GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
   }
 
-  cout << "PASS" << endl;
+  // Tests for map lite =============================================
+
+  {
+    // Accessors
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    google::protobuf::MapLiteTestUtil::ModifyMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message);
+  }
+
+  {
+    // SetMapFieldsInitialized
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFieldsInitialized(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSetInitialized(message);
+  }
+
+  {
+    // Clear
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    message.Clear();
+    google::protobuf::MapLiteTestUtil::ExpectClear(message);
+  }
+
+  {
+    // ClearMessageMap
+    protobuf_unittest::TestMessageMapLite message;
+
+    // Creates a TestAllTypes with default value
+    google::protobuf::TestUtilLite::ExpectClear(
+        (*message.mutable_map_int32_message())[0]);
+  }
+
+  {
+    // CopyFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    message2.CopyFrom(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Copying from self should be a no-op.
+    message2.CopyFrom(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyFromMessageMap
+    protobuf_unittest::TestMessageMapLite message1, message2;
+
+    (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+    (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+    message1.CopyFrom(message2);
+
+    // Checks repeated field is overwritten.
+    EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+    EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+  }
+
+  {
+    // SwapWithEmpty
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1);
+    google::protobuf::MapLiteTestUtil::ExpectClear(message2);
+
+    message1.Swap(&message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+    google::protobuf::MapLiteTestUtil::ExpectClear(message1);
+  }
+
+  {
+    // SwapWithSelf
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    message.Swap(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // SwapWithOther
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message2);
+    google::protobuf::MapLiteTestUtil::ModifyMapFields(&message2);
+
+    message1.Swap(&message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyConstructor
+    protobuf_unittest::TestMapLite message1;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyAssignmentOperator
+    protobuf_unittest::TestMapLite message1;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2;
+    message2 = message1;
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Make sure that self-assignment does something sane.
+    message2.operator=(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // NonEmptyMergeFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    // This field will test merging into an empty spot.
+    (*message2.mutable_map_int32_int32())[1] = 1;
+    message1.mutable_map_int32_int32()->erase(1);
+
+    // This tests overwriting.
+    (*message2.mutable_map_int32_double())[1] = 1;
+    (*message1.mutable_map_int32_double())[1] = 2;
+
+    message1.MergeFrom(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1);
+  }
+
+  {
+    // MergeFromMessageMap
+    protobuf_unittest::TestMessageMapLite message1, message2;
+
+    (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+    (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+    message1.MergeFrom(message2);
+
+    // Checks repeated field is overwritten.
+    EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+    EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+  }
+
+  {
+    // Test the generated SerializeWithCachedSizesToArray()
+    protobuf_unittest::TestMapLite message1, message2;
+    string data;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    int size = message1.ByteSize();
+    data.resize(size);
+    ::google::protobuf::uint8* start = reinterpret_cast< ::google::protobuf::uint8*>(::google::protobuf::string_as_array(&data));
+    ::google::protobuf::uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // Test the generated SerializeWithCachedSizes()
+    protobuf_unittest::TestMapLite message1, message2;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    int size = message1.ByteSize();
+    string data;
+    data.resize(size);
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      google::protobuf::io::ArrayOutputStream array_stream(
+          ::google::protobuf::string_as_array(&data), size, 1);
+      google::protobuf::io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+    EXPECT_TRUE(message2.ParseFromString(data));
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+
+  {
+    // Proto2UnknownEnum
+    protobuf_unittest::TestEnumMapPlusExtraLite from;
+    (*from.mutable_known_map_field())[0] =
+        protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE;
+    (*from.mutable_unknown_map_field())[0] =
+        protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE;
+    string data;
+    from.SerializeToString(&data);
+
+    protobuf_unittest::TestEnumMapLite to;
+    EXPECT_TRUE(to.ParseFromString(data));
+    EXPECT_EQ(0, to.unknown_map_field().size());
+    EXPECT_FALSE(to.mutable_unknown_fields()->empty());
+    EXPECT_EQ(1, to.known_map_field().size());
+    EXPECT_EQ(protobuf_unittest::PROTO2_MAP_ENUM_FOO_LITE,
+              to.known_map_field().at(0));
+
+    data.clear();
+    from.Clear();
+    to.SerializeToString(&data);
+    EXPECT_TRUE(from.ParseFromString(data));
+    EXPECT_EQ(1, from.known_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE,
+              from.known_map_field().at(0));
+    EXPECT_EQ(1, from.unknown_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE,
+              from.unknown_map_field().at(0));
+  }
+
+  {
+    // StandardWireFormat
+    protobuf_unittest::TestMapLite message;
+    string data = "\x0A\x04\x08\x01\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(1));
+  }
+
+  {
+    // UnorderedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // put value before key in wire format
+    string data = "\x0A\x04\x10\x01\x08\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+
+  {
+    // DuplicatedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two key fields in wire format
+    string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+
+  {
+    // DuplicatedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two value fields in wire format
+    string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(2, message.map_int32_int32().at(1));
+  }
+
+  {
+    // MissedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No key field in wire format
+    string data = "\x0A\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(0));
+  }
+
+  {
+    // MissedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No value field in wire format
+    string data = "\x0A\x02\x08\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(0, message.map_int32_int32().at(1));
+  }
+
+  {
+    // UnknownFieldWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Unknown field in wire format
+    string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(3, message.map_int32_int32().at(2));
+  }
+
+  {
+    // CorruptedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // corrupted data in wire format
+    string data = "\x0A\x06\x08\x02\x11\x03";
+
+    EXPECT_FALSE(message.ParseFromString(data));
+  }
+
+  {
+    // IsInitialized
+    protobuf_unittest::TestRequiredMessageMapLite map_message;
+
+    // Add an uninitialized message.
+    (*map_message.mutable_map_field())[0];
+    EXPECT_FALSE(map_message.IsInitialized());
+
+    // Initialize uninitialized message
+    (*map_message.mutable_map_field())[0].set_a(0);
+    (*map_message.mutable_map_field())[0].set_b(0);
+    (*map_message.mutable_map_field())[0].set_c(0);
+    EXPECT_TRUE(map_message.IsInitialized());
+  }
+
+  {
+      // Check that adding more values to enum does not corrupt message
+      // when passed through an old client.
+      protobuf_unittest::V2MessageLite v2_message;
+      v2_message.set_int_field(800);
+      // Set enum field to the value not understood by the old client.
+      v2_message.set_enum_field(protobuf_unittest::V2_SECOND);
+      string v2_bytes = v2_message.SerializeAsString();
+
+      protobuf_unittest::V1MessageLite v1_message;
+      v1_message.ParseFromString(v2_bytes);
+      EXPECT_TRUE(v1_message.IsInitialized());
+      EXPECT_EQ(v1_message.int_field(), v2_message.int_field());
+      // V1 client does not understand V2_SECOND value, so it discards it and
+      // uses default value instead.
+      EXPECT_EQ(v1_message.enum_field(), protobuf_unittest::V1_FIRST);
+
+      // However, when re-serialized, it should preserve enum value.
+      string v1_bytes = v1_message.SerializeAsString();
+
+      protobuf_unittest::V2MessageLite same_v2_message;
+      same_v2_message.ParseFromString(v1_bytes);
+
+      EXPECT_EQ(v2_message.int_field(), same_v2_message.int_field());
+      EXPECT_EQ(v2_message.enum_field(), same_v2_message.enum_field());
+  }
+
+  std::cout << "PASS" << std::endl;
   return 0;
 }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
new file mode 100644
index 0000000..6f1a71e
--- /dev/null
+++ b/src/google/protobuf/map.h
@@ -0,0 +1,1721 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_H__
+#define GOOGLE_PROTOBUF_MAP_H__
+
+#include <google/protobuf/stubs/hash.h>
+#include <iterator>
+#include <limits>  // To support Visual Studio 2008
+#include <set>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_enum_util.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/descriptor.h>
+#if __cpp_exceptions && LANG_CXX11
+#include <random>
+#endif
+
+namespace google {
+namespace protobuf {
+
+// The Map and MapIterator types are provided by this header file.
+// Please avoid using other types defined here, unless they are public
+// types within Map or MapIterator, such as Map::value_type.
+template <typename Key, typename T>
+class Map;
+
+class MapIterator;
+
+template <typename Enum> struct is_proto_enum;
+
+namespace internal {
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+class MapFieldLite;
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+class MapField;
+
+template <typename Key, typename T>
+class TypeDefinedMapFieldBase;
+
+class DynamicMapField;
+
+class GeneratedMessageReflection;
+}  // namespace internal
+
+#define TYPE_CHECK(EXPECTEDTYPE, METHOD)                        \
+  if (type() != EXPECTEDTYPE) {                                 \
+    GOOGLE_LOG(FATAL)                                                  \
+        << "Protocol Buffer map usage error:\n"                 \
+        << METHOD << " type does not match\n"                   \
+        << "  Expected : "                                      \
+        << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n"   \
+        << "  Actual   : "                                      \
+        << FieldDescriptor::CppTypeName(type());                \
+  }
+
+// MapKey is an union type for representing any possible
+// map key.
+class LIBPROTOBUF_EXPORT MapKey {
+ public:
+  MapKey() : type_(0) {
+  }
+  MapKey(const MapKey& other) : type_(0) {
+    CopyFrom(other);
+  }
+
+  ~MapKey() {
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      delete val_.string_value_;
+    }
+  }
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == 0) {
+      GOOGLE_LOG(FATAL)
+          << "Protocol Buffer map usage error:\n"
+          << "MapKey::type MapKey is not initialized. "
+          << "Call set methods to initialize MapKey.";
+    }
+    return (FieldDescriptor::CppType)type_;
+  }
+
+  void SetInt64Value(int64 value) {
+    SetType(FieldDescriptor::CPPTYPE_INT64);
+    val_.int64_value_ = value;
+  }
+  void SetUInt64Value(uint64 value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT64);
+    val_.uint64_value_ = value;
+  }
+  void SetInt32Value(int32 value) {
+    SetType(FieldDescriptor::CPPTYPE_INT32);
+    val_.int32_value_ = value;
+  }
+  void SetUInt32Value(uint32 value) {
+    SetType(FieldDescriptor::CPPTYPE_UINT32);
+    val_.uint32_value_ = value;
+  }
+  void SetBoolValue(bool value) {
+    SetType(FieldDescriptor::CPPTYPE_BOOL);
+    val_.bool_value_ = value;
+  }
+  void SetStringValue(const string& val) {
+    SetType(FieldDescriptor::CPPTYPE_STRING);
+    *val_.string_value_ = val;
+  }
+
+  int64 GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
+               "MapKey::GetInt64Value");
+    return val_.int64_value_;
+  }
+  uint64 GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
+               "MapKey::GetUInt64Value");
+    return val_.uint64_value_;
+  }
+  int32 GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
+               "MapKey::GetInt32Value");
+    return val_.int32_value_;
+  }
+  uint32 GetUInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
+               "MapKey::GetUInt32Value");
+    return val_.uint32_value_;
+  }
+  bool GetBoolValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL,
+               "MapKey::GetBoolValue");
+    return val_.bool_value_;
+  }
+  const string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING,
+               "MapKey::GetStringValue");
+    return *val_.string_value_;
+  }
+
+  bool operator<(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // We could define a total order that handles this case, but
+      // there currently no need.  So, for now, fail.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        return false;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return *val_.string_value_ < *other.val_.string_value_;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ < other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ < other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ < other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ < other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ < other.val_.bool_value_;
+    }
+    return false;
+  }
+
+  bool operator==(const MapKey& other) const {
+    if (type_ != other.type_) {
+      // To be consistent with operator<, we don't allow this either.
+      GOOGLE_LOG(FATAL) << "Unsupported: type mismatch";
+    }
+    switch (type()) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        return *val_.string_value_ == *other.val_.string_value_;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return val_.int64_value_ == other.val_.int64_value_;
+      case FieldDescriptor::CPPTYPE_INT32:
+        return val_.int32_value_ == other.val_.int32_value_;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return val_.uint64_value_ == other.val_.uint64_value_;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return val_.uint32_value_ == other.val_.uint32_value_;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return val_.bool_value_ == other.val_.bool_value_;
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return false;
+  }
+
+  void CopyFrom(const MapKey& other) {
+    SetType(other.type());
+    switch (type_) {
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+      case FieldDescriptor::CPPTYPE_FLOAT:
+      case FieldDescriptor::CPPTYPE_ENUM:
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        *val_.string_value_ = *other.val_.string_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        val_.int64_value_ = other.val_.int64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_INT32:
+        val_.int32_value_ = other.val_.int32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        val_.uint64_value_ = other.val_.uint64_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        val_.uint32_value_ = other.val_.uint32_value_;
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        val_.bool_value_ = other.val_.bool_value_;
+        break;
+    }
+  }
+
+ private:
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class MapIterator;
+  friend class internal::DynamicMapField;
+
+  union KeyValue {
+    KeyValue() {}
+    string* string_value_;
+    int64 int64_value_;
+    int32 int32_value_;
+    uint64 uint64_value_;
+    uint32 uint32_value_;
+    bool bool_value_;
+  } val_;
+
+  void SetType(FieldDescriptor::CppType type) {
+    if (type_ == type) return;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      delete val_.string_value_;
+    }
+    type_ = type;
+    if (type_ == FieldDescriptor::CPPTYPE_STRING) {
+      val_.string_value_ = new string;
+    }
+  }
+
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  int type_;
+};
+
+// MapValueRef points to a map value.
+class LIBPROTOBUF_EXPORT MapValueRef {
+ public:
+  MapValueRef() : data_(NULL), type_(0) {}
+
+  void SetInt64Value(int64 value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
+               "MapValueRef::SetInt64Value");
+    *reinterpret_cast<int64*>(data_) = value;
+  }
+  void SetUInt64Value(uint64 value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
+               "MapValueRef::SetUInt64Value");
+    *reinterpret_cast<uint64*>(data_) = value;
+  }
+  void SetInt32Value(int32 value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
+               "MapValueRef::SetInt32Value");
+    *reinterpret_cast<int32*>(data_) = value;
+  }
+  void SetUInt32Value(uint32 value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
+               "MapValueRef::SetUInt32Value");
+    *reinterpret_cast<uint32*>(data_) = value;
+  }
+  void SetBoolValue(bool value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL,
+               "MapValueRef::SetBoolValue");
+    *reinterpret_cast<bool*>(data_) = value;
+  }
+  // TODO(jieluo) - Checks that enum is member.
+  void SetEnumValue(int value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM,
+               "MapValueRef::SetEnumValue");
+    *reinterpret_cast<int*>(data_) = value;
+  }
+  void SetStringValue(const string& value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING,
+               "MapValueRef::SetStringValue");
+    *reinterpret_cast<string*>(data_) = value;
+  }
+  void SetFloatValue(float value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT,
+               "MapValueRef::SetFloatValue");
+    *reinterpret_cast<float*>(data_) = value;
+  }
+  void SetDoubleValue(double value) {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE,
+               "MapValueRef::SetDoubleValue");
+    *reinterpret_cast<double*>(data_) = value;
+  }
+
+  int64 GetInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64,
+               "MapValueRef::GetInt64Value");
+    return *reinterpret_cast<int64*>(data_);
+  }
+  uint64 GetUInt64Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64,
+               "MapValueRef::GetUInt64Value");
+    return *reinterpret_cast<uint64*>(data_);
+  }
+  int32 GetInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32,
+               "MapValueRef::GetInt32Value");
+    return *reinterpret_cast<int32*>(data_);
+  }
+  uint32 GetUInt32Value() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
+               "MapValueRef::GetUInt32Value");
+    return *reinterpret_cast<uint32*>(data_);
+  }
+  bool GetBoolValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL,
+               "MapValueRef::GetBoolValue");
+    return *reinterpret_cast<bool*>(data_);
+  }
+  int GetEnumValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM,
+               "MapValueRef::GetEnumValue");
+    return *reinterpret_cast<int*>(data_);
+  }
+  const string& GetStringValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING,
+               "MapValueRef::GetStringValue");
+    return *reinterpret_cast<string*>(data_);
+  }
+  float GetFloatValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT,
+               "MapValueRef::GetFloatValue");
+    return *reinterpret_cast<float*>(data_);
+  }
+  double GetDoubleValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE,
+               "MapValueRef::GetDoubleValue");
+    return *reinterpret_cast<double*>(data_);
+  }
+
+  const Message& GetMessageValue() const {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueRef::GetMessageValue");
+    return *reinterpret_cast<Message*>(data_);
+  }
+
+  Message* MutableMessageValue() {
+    TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE,
+               "MapValueRef::MutableMessageValue");
+    return reinterpret_cast<Message*>(data_);
+  }
+
+ private:
+  template <typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type,
+            int default_enum_value>
+  friend class internal::MapField;
+  template <typename K, typename V>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class MapIterator;
+  friend class internal::GeneratedMessageReflection;
+  friend class internal::DynamicMapField;
+
+  void SetType(FieldDescriptor::CppType type) {
+    type_ = type;
+  }
+
+  FieldDescriptor::CppType type() const {
+    if (type_ == 0 || data_ == NULL) {
+      GOOGLE_LOG(FATAL)
+          << "Protocol Buffer map usage error:\n"
+          << "MapValueRef::type MapValueRef is not initialized.";
+    }
+    return (FieldDescriptor::CppType)type_;
+  }
+  void SetValue(const void* val) {
+    data_ = const_cast<void*>(val);
+  }
+  void CopyFrom(const MapValueRef& other) {
+    type_ = other.type_;
+    data_ = other.data_;
+  }
+  // Only used in DynamicMapField
+  void DeleteData() {
+    switch (type_) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                              \
+      case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: {        \
+        delete reinterpret_cast<TYPE*>(data_);                  \
+        break;                                                  \
+      }
+      HANDLE_TYPE(INT32, int32);
+      HANDLE_TYPE(INT64, int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(ENUM, int32);
+      HANDLE_TYPE(MESSAGE, Message);
+#undef HANDLE_TYPE
+    }
+  }
+  // data_ point to a map value. MapValueRef does not
+  // own this value.
+  void* data_;
+  // type_ is 0 or a valid FieldDescriptor::CppType.
+  int type_;
+};
+
+#undef TYPE_CHECK
+
+// This is the class for google::protobuf::Map's internal value_type. Instead of using
+// std::pair as value_type, we use this class which provides us more control of
+// its process of construction and destruction.
+template <typename Key, typename T>
+class MapPair {
+ public:
+  typedef const Key first_type;
+  typedef T second_type;
+
+  MapPair(const Key& other_first, const T& other_second)
+      : first(other_first), second(other_second) {}
+  explicit MapPair(const Key& other_first) : first(other_first), second() {}
+  MapPair(const MapPair& other)
+      : first(other.first), second(other.second) {}
+
+  ~MapPair() {}
+
+  // Implicitly convertible to std::pair of compatible types.
+  template <typename T1, typename T2>
+  operator std::pair<T1, T2>() const {
+    return std::pair<T1, T2>(first, second);
+  }
+
+  const Key first;
+  T second;
+
+ private:
+  friend class ::google::protobuf::Arena;
+  friend class Map<Key, T>;
+};
+
+// google::protobuf::Map is an associative container type used to store protobuf map
+// fields.  Each Map instance may or may not use a different hash function, a
+// different iteration order, and so on.  E.g., please don't examine
+// implementation details to decide if the following would work:
+//  Map<int, int> m0, m1;
+//  m0[0] = m1[0] = m0[1] = m1[1] = 0;
+//  assert(m0.begin()->first == m1.begin()->first);  // Bug!
+//
+// Map's interface is similar to std::unordered_map, except that Map is not
+// designed to play well with exceptions.
+template <typename Key, typename T>
+class Map {
+ public:
+  typedef Key key_type;
+  typedef T mapped_type;
+  typedef MapPair<Key, T> value_type;
+
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+
+  typedef size_t size_type;
+  typedef hash<Key> hasher;
+
+  Map(bool old_style = true)
+      : arena_(NULL),
+        default_enum_value_(0),
+        old_style_(old_style) {
+    Init();
+  }
+  explicit Map(Arena* arena, bool old_style = true)
+      : arena_(arena),
+        default_enum_value_(0),
+        old_style_(old_style) {
+    Init();
+  }
+  Map(const Map& other)
+      : arena_(NULL),
+        default_enum_value_(other.default_enum_value_),
+        old_style_(other.old_style_) {
+    Init();
+    insert(other.begin(), other.end());
+  }
+  template <class InputIt>
+  Map(const InputIt& first, const InputIt& last, bool old_style = true)
+      : arena_(NULL),
+        default_enum_value_(0),
+        old_style_(old_style) {
+    Init();
+    insert(first, last);
+  }
+
+  ~Map() {
+    clear();
+    if (arena_ == NULL) {
+      if (old_style_)
+        delete deprecated_elements_;
+      else
+        delete elements_;
+    }
+  }
+
+ private:
+  void Init() {
+    if (old_style_)
+      deprecated_elements_ = Arena::Create<DeprecatedInnerMap>(
+          arena_, 0, hasher(), equal_to<Key>(),
+          MapAllocator<std::pair<const Key, MapPair<Key, T>*> >(arena_));
+    else
+      elements_ =
+          Arena::Create<InnerMap>(arena_, 0, hasher(), Allocator(arena_));
+  }
+
+  // re-implement std::allocator to use arena allocator for memory allocation.
+  // Used for google::protobuf::Map implementation. Users should not use this class
+  // directly.
+  template <typename U>
+  class MapAllocator {
+   public:
+    typedef U value_type;
+    typedef value_type* pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type& reference;
+    typedef const value_type& const_reference;
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+
+    MapAllocator() : arena_(NULL) {}
+    explicit MapAllocator(Arena* arena) : arena_(arena) {}
+    template <typename X>
+    MapAllocator(const MapAllocator<X>& allocator)
+        : arena_(allocator.arena_) {}
+
+    pointer allocate(size_type n, const_pointer hint = 0) {
+      // If arena is not given, malloc needs to be called which doesn't
+      // construct element object.
+      if (arena_ == NULL) {
+        return reinterpret_cast<pointer>(malloc(n * sizeof(value_type)));
+      } else {
+        return reinterpret_cast<pointer>(
+            Arena::CreateArray<uint8>(arena_, n * sizeof(value_type)));
+      }
+    }
+
+    void deallocate(pointer p, size_type n) {
+      if (arena_ == NULL) {
+        free(p);
+      }
+    }
+
+#if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \
+    !defined(GOOGLE_PROTOBUF_OS_NACL) &&                            \
+    !defined(GOOGLE_PROTOBUF_OS_ANDROID) &&                         \
+    !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN)
+    template<class NodeType, class... Args>
+    void construct(NodeType* p, Args&&... args) {
+      // Clang 3.6 doesn't compile static casting to void* directly. (Issue
+      // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall
+      // not cast away constness". So first the maybe const pointer is casted to
+      // const void* and after the const void* is const casted.
+      new (const_cast<void*>(static_cast<const void*>(p)))
+          NodeType(std::forward<Args>(args)...);
+    }
+
+    template<class NodeType>
+    void destroy(NodeType* p) {
+      p->~NodeType();
+    }
+#else
+    void construct(pointer p, const_reference t) { new (p) value_type(t); }
+
+    void destroy(pointer p) { p->~value_type(); }
+#endif
+
+    template <typename X>
+    struct rebind {
+      typedef MapAllocator<X> other;
+    };
+
+    template <typename X>
+    bool operator==(const MapAllocator<X>& other) const {
+      return arena_ == other.arena_;
+    }
+
+    template <typename X>
+    bool operator!=(const MapAllocator<X>& other) const {
+      return arena_ != other.arena_;
+    }
+
+    // To support Visual Studio 2008
+    size_type max_size() const {
+      return std::numeric_limits<size_type>::max();
+    }
+
+   private:
+    typedef void DestructorSkippable_;
+    Arena* const arena_;
+
+    template <typename X>
+    friend class MapAllocator;
+  };
+
+  // InnerMap's key type is Key and its value type is value_type*.  We use a
+  // custom class here and for Node, below, to ensure that k_ is at offset 0,
+  // allowing safe conversion from pointer to Node to pointer to Key, and vice
+  // versa when appropriate.
+  class KeyValuePair {
+   public:
+    KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {}
+
+    const Key& key() const { return k_; }
+    Key& key() { return k_; }
+    value_type* const value() const { return v_; }
+    value_type*& value() { return v_; }
+
+   private:
+    Key k_;
+    value_type* v_;
+  };
+
+  typedef MapAllocator<KeyValuePair> Allocator;
+
+  // InnerMap is a generic hash-based map.  It doesn't contain any
+  // protocol-buffer-specific logic.  It is a chaining hash map with the
+  // additional feature that some buckets can be converted to use an ordered
+  // container.  This ensures O(lg n) bounds on find, insert, and erase, while
+  // avoiding the overheads of ordered containers most of the time.
+  //
+  // The implementation doesn't need the full generality of unordered_map,
+  // and it doesn't have it.  More bells and whistles can be added as needed.
+  // Some implementation details:
+  // 1. The hash function has type hasher and the equality function
+  //    equal_to<Key>.  We inherit from hasher to save space
+  //    (empty-base-class optimization).
+  // 2. The number of buckets is a power of two.
+  // 3. Buckets are converted to trees in pairs: if we convert bucket b then
+  //    buckets b and b^1 will share a tree.  Invariant: buckets b and b^1 have
+  //    the same non-NULL value iff they are sharing a tree.  (An alternative
+  //    implementation strategy would be to have a tag bit per bucket.)
+  // 4. As is typical for hash_map and such, the Keys and Values are always
+  //    stored in linked list nodes.  Pointers to elements are never invalidated
+  //    until the element is deleted.
+  // 5. The trees' payload type is pointer to linked-list node.  Tree-converting
+  //    a bucket doesn't copy Key-Value pairs.
+  // 6. Once we've tree-converted a bucket, it is never converted back. However,
+  //    the items a tree contains may wind up assigned to trees or lists upon a
+  //    rehash.
+  // 7. The code requires no C++ features from C++11 or later.
+  // 8. Mutations to a map do not invalidate the map's iterators, pointers to
+  //    elements, or references to elements.
+  // 9. Except for erase(iterator), any non-const method can reorder iterators.
+  class InnerMap : private hasher {
+   public:
+    typedef value_type* Value;
+
+    InnerMap(size_type n, hasher h, Allocator alloc)
+        : hasher(h),
+          num_elements_(0),
+          seed_(Seed()),
+          table_(NULL),
+          alloc_(alloc) {
+      n = TableSize(n);
+      table_ = CreateEmptyTable(n);
+      num_buckets_ = index_of_first_non_null_ = n;
+    }
+
+    ~InnerMap() {
+      if (table_ != NULL) {
+        clear();
+        Dealloc<void*>(table_, num_buckets_);
+      }
+    }
+
+   private:
+    enum { kMinTableSize = 8 };
+
+    // Linked-list nodes, as one would expect for a chaining hash table.
+    struct Node {
+      KeyValuePair kv;
+      Node* next;
+    };
+
+    // This is safe only if the given pointer is known to point to a Key that is
+    // part of a Node.
+    static Node* NodePtrFromKeyPtr(Key* k) {
+      return reinterpret_cast<Node*>(k);
+    }
+
+    static Key* KeyPtrFromNodePtr(Node* node) { return &node->kv.key(); }
+
+    // Trees.  The payload type is pointer to Key, so that we can query the tree
+    // with Keys that are not in any particular data structure.  When we insert,
+    // though, the pointer is always pointing to a Key that is inside a Node.
+    struct KeyCompare {
+      bool operator()(const Key* n0, const Key* n1) const { return *n0 < *n1; }
+    };
+    typedef typename Allocator::template rebind<Key*>::other KeyPtrAllocator;
+    typedef std::set<Key*, KeyCompare, KeyPtrAllocator> Tree;
+
+    // iterator and const_iterator are instantiations of iterator_base.
+    template <typename KeyValueType>
+    class iterator_base {
+     public:
+      typedef KeyValueType& reference;
+      typedef KeyValueType* pointer;
+      typedef typename Tree::iterator TreeIterator;
+
+      // Invariants:
+      // node_ is always correct. This is handy because the most common
+      // operations are operator* and operator-> and they only use node_.
+      // When node_ is set to a non-NULL value, all the other non-const fields
+      // are updated to be correct also, but those fields can become stale
+      // if the underlying map is modified.  When those fields are needed they
+      // are rechecked, and updated if necessary.
+      iterator_base() : node_(NULL) {}
+
+      explicit iterator_base(const InnerMap* m) : m_(m) {
+        SearchFrom(m->index_of_first_non_null_);
+      }
+
+      // Any iterator_base can convert to any other.  This is overkill, and we
+      // rely on the enclosing class to use it wisely.  The standard "iterator
+      // can convert to const_iterator" is OK but the reverse direction is not.
+      template <typename U>
+      explicit iterator_base(const iterator_base<U>& it)
+          : node_(it.node_),
+            m_(it.m_),
+            bucket_index_(it.bucket_index_),
+            tree_it_(it.tree_it_) {}
+
+      iterator_base(Node* n, const InnerMap* m, size_type index)
+          : node_(n),
+            m_(m),
+            bucket_index_(index) {}
+
+      iterator_base(TreeIterator tree_it, const InnerMap* m, size_type index)
+          : node_(NodePtrFromKeyPtr(*tree_it)),
+            m_(m),
+            bucket_index_(index),
+            tree_it_(tree_it) {
+        // Invariant: iterators that use tree_it_ have an even bucket_index_.
+        GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0);
+      }
+
+      // Advance through buckets, looking for the first that isn't empty.
+      // If nothing non-empty is found then leave node_ == NULL.
+      void SearchFrom(size_type start_bucket) {
+        GOOGLE_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ ||
+               m_->table_[m_->index_of_first_non_null_] != NULL);
+        node_ = NULL;
+        for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_;
+             bucket_index_++) {
+          if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+            node_ = static_cast<Node*>(m_->table_[bucket_index_]);
+            break;
+          } else if (m_->TableEntryIsTree(bucket_index_)) {
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            GOOGLE_DCHECK(!tree->empty());
+            tree_it_ = tree->begin();
+            node_ = NodePtrFromKeyPtr(*tree_it_);
+            break;
+          }
+        }
+      }
+
+      reference operator*() const { return node_->kv; }
+      pointer operator->() const { return &(operator*()); }
+
+      friend bool operator==(const iterator_base& a, const iterator_base& b) {
+        return a.node_ == b.node_;
+      }
+      friend bool operator!=(const iterator_base& a, const iterator_base& b) {
+        return a.node_ != b.node_;
+      }
+
+      iterator_base& operator++() {
+        if (node_->next == NULL) {
+          const bool is_list = revalidate_if_necessary();
+          if (is_list) {
+            SearchFrom(bucket_index_ + 1);
+          } else {
+            GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0);
+            Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
+            if (++tree_it_ == tree->end()) {
+              SearchFrom(bucket_index_ + 2);
+            } else {
+              node_ = NodePtrFromKeyPtr(*tree_it_);
+            }
+          }
+        } else {
+          node_ = node_->next;
+        }
+        return *this;
+      }
+
+      iterator_base operator++(int /* unused */) {
+        iterator_base tmp = *this;
+        ++*this;
+        return tmp;
+      }
+
+      // Assumes node_ and m_ are correct and non-NULL, but other fields may be
+      // stale.  Fix them as needed.  Then return true iff node_ points to a
+      // Node in a list.
+      bool revalidate_if_necessary() {
+        GOOGLE_DCHECK(node_ != NULL && m_ != NULL);
+        // Force bucket_index_ to be in range.
+        bucket_index_ &= (m_->num_buckets_ - 1);
+        // Common case: the bucket we think is relevant points to node_.
+        if (m_->table_[bucket_index_] == static_cast<void*>(node_))
+          return true;
+        // Less common: the bucket is a linked list with node_ somewhere in it,
+        // but not at the head.
+        if (m_->TableEntryIsNonEmptyList(bucket_index_)) {
+          Node* l = static_cast<Node*>(m_->table_[bucket_index_]);
+          while ((l = l->next) != NULL) {
+            if (l == node_) {
+              return true;
+            }
+          }
+        }
+        // Well, bucket_index_ still might be correct, but probably
+        // not.  Revalidate just to be sure.  This case is rare enough that we
+        // don't worry about potential optimizations, such as having a custom
+        // find-like method that compares Node* instead of const Key&.
+        iterator_base i(m_->find(*KeyPtrFromNodePtr(node_)));
+        bucket_index_ = i.bucket_index_;
+        tree_it_ = i.tree_it_;
+        return m_->TableEntryIsList(bucket_index_);
+      }
+
+      Node* node_;
+      const InnerMap* m_;
+      size_type bucket_index_;
+      TreeIterator tree_it_;
+    };
+
+   public:
+    typedef iterator_base<KeyValuePair> iterator;
+    typedef iterator_base<const KeyValuePair> const_iterator;
+
+    iterator begin() { return iterator(this); }
+    iterator end() { return iterator(); }
+    const_iterator begin() const { return const_iterator(this); }
+    const_iterator end() const { return const_iterator(); }
+
+    void clear() {
+      for (size_type b = 0; b < num_buckets_; b++) {
+        if (TableEntryIsNonEmptyList(b)) {
+          Node* node = static_cast<Node*>(table_[b]);
+          table_[b] = NULL;
+          do {
+            Node* next = node->next;
+            DestroyNode(node);
+            node = next;
+          } while (node != NULL);
+        } else if (TableEntryIsTree(b)) {
+          Tree* tree = static_cast<Tree*>(table_[b]);
+          GOOGLE_DCHECK(table_[b] == table_[b + 1] && (b & 1) == 0);
+          table_[b] = table_[b + 1] = NULL;
+          typename Tree::iterator tree_it = tree->begin();
+          do {
+            Node* node = NodePtrFromKeyPtr(*tree_it);
+            typename Tree::iterator next = tree_it;
+            ++next;
+            tree->erase(tree_it);
+            DestroyNode(node);
+            tree_it = next;
+          } while (tree_it != tree->end());
+          DestroyTree(tree);
+          b++;
+        }
+      }
+      num_elements_ = 0;
+      index_of_first_non_null_ = num_buckets_;
+    }
+
+    const hasher& hash_function() const { return *this; }
+
+    static size_type max_size() {
+      return static_cast<size_type>(1) << (sizeof(void**) >= 8 ? 60 : 28);
+    }
+    size_type size() const { return num_elements_; }
+    bool empty() const { return size() == 0; }
+
+    iterator find(const Key& k) { return iterator(FindHelper(k).first); }
+    const_iterator find(const Key& k) const { return FindHelper(k).first; }
+
+    // In traditional C++ style, this performs "insert if not present."
+    std::pair<iterator, bool> insert(const KeyValuePair& kv) {
+      std::pair<const_iterator, size_type> p = FindHelper(kv.key());
+      // Case 1: key was already present.
+      if (p.first.node_ != NULL)
+        return std::make_pair(iterator(p.first), false);
+      // Case 2: insert.
+      if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
+        p = FindHelper(kv.key());
+      }
+      const size_type b = p.second;  // bucket number
+      Node* node = Alloc<Node>(1);
+      alloc_.construct(&node->kv, kv);
+      iterator result = InsertUnique(b, node);
+      ++num_elements_;
+      return std::make_pair(result, true);
+    }
+
+    // The same, but if an insertion is necessary then the value portion of the
+    // inserted key-value pair is left uninitialized.
+    std::pair<iterator, bool> insert(const Key& k) {
+      std::pair<const_iterator, size_type> p = FindHelper(k);
+      // Case 1: key was already present.
+      if (p.first.node_ != NULL)
+        return std::make_pair(iterator(p.first), false);
+      // Case 2: insert.
+      if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
+        p = FindHelper(k);
+      }
+      const size_type b = p.second;  // bucket number
+      Node* node = Alloc<Node>(1);
+      typedef typename Allocator::template rebind<Key>::other KeyAllocator;
+      KeyAllocator(alloc_).construct(&node->kv.key(), k);
+      iterator result = InsertUnique(b, node);
+      ++num_elements_;
+      return std::make_pair(result, true);
+    }
+
+    Value& operator[](const Key& k) {
+      KeyValuePair kv(k, Value());
+      return insert(kv).first->value();
+    }
+
+    void erase(iterator it) {
+      GOOGLE_DCHECK_EQ(it.m_, this);
+      const bool is_list = it.revalidate_if_necessary();
+      size_type b = it.bucket_index_;
+      Node* const item = it.node_;
+      if (is_list) {
+        GOOGLE_DCHECK(TableEntryIsNonEmptyList(b));
+        Node* head = static_cast<Node*>(table_[b]);
+        head = EraseFromLinkedList(item, head);
+        table_[b] = static_cast<void*>(head);
+      } else {
+        GOOGLE_DCHECK(TableEntryIsTree(b));
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        tree->erase(it.tree_it_);
+        if (tree->empty()) {
+          // Force b to be the minimum of b and b ^ 1.  This is important
+          // only because we want index_of_first_non_null_ to be correct.
+          b &= ~static_cast<size_type>(1);
+          DestroyTree(tree);
+          table_[b] = table_[b + 1] = NULL;
+        }
+      }
+      DestroyNode(item);
+      --num_elements_;
+      if (GOOGLE_PREDICT_FALSE(b == index_of_first_non_null_)) {
+        while (index_of_first_non_null_ < num_buckets_ &&
+               table_[index_of_first_non_null_] == NULL) {
+          ++index_of_first_non_null_;
+        }
+      }
+    }
+
+   private:
+    std::pair<const_iterator, size_type> FindHelper(const Key& k) const {
+      size_type b = BucketNumber(k);
+      if (TableEntryIsNonEmptyList(b)) {
+        Node* node = static_cast<Node*>(table_[b]);
+        do {
+          if (IsMatch(*KeyPtrFromNodePtr(node), k)) {
+            return std::make_pair(const_iterator(node, this, b), b);
+          } else {
+            node = node->next;
+          }
+        } while (node != NULL);
+      } else if (TableEntryIsTree(b)) {
+        GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+        b &= ~static_cast<size_t>(1);
+        Tree* tree = static_cast<Tree*>(table_[b]);
+        Key* key = const_cast<Key*>(&k);
+        typename Tree::iterator tree_it = tree->find(key);
+        if (tree_it != tree->end()) {
+          return std::make_pair(const_iterator(tree_it, this, b), b);
+        }
+      }
+      return std::make_pair(end(), b);
+    }
+
+    // Insert the given Node in bucket b.  If that would make bucket b too big,
+    // and bucket b is not a tree, create a tree for buckets b and b^1 to share.
+    // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
+    // bucket.  num_elements_ is not modified.
+    iterator InsertUnique(size_type b, Node* node) {
+      GOOGLE_DCHECK(index_of_first_non_null_ == num_buckets_ ||
+             table_[index_of_first_non_null_] != NULL);
+      // In practice, the code that led to this point may have already
+      // determined whether we are inserting into an empty list, a short list,
+      // or whatever.  But it's probably cheap enough to recompute that here;
+      // it's likely that we're inserting into an empty or short list.
+      iterator result;
+      GOOGLE_DCHECK(find(*KeyPtrFromNodePtr(node)) == end());
+      if (TableEntryIsEmpty(b)) {
+        result = InsertUniqueInList(b, node);
+      } else if (TableEntryIsNonEmptyList(b)) {
+        if (GOOGLE_PREDICT_FALSE(TableEntryIsTooLong(b))) {
+          TreeConvert(b);
+          result = InsertUniqueInTree(b, node);
+          GOOGLE_DCHECK_EQ(result.bucket_index_, b & ~static_cast<size_type>(1));
+        } else {
+          // Insert into a pre-existing list.  This case cannot modify
+          // index_of_first_non_null_, so we skip the code to update it.
+          return InsertUniqueInList(b, node);
+        }
+      } else {
+        // Insert into a pre-existing tree.  This case cannot modify
+        // index_of_first_non_null_, so we skip the code to update it.
+        return InsertUniqueInTree(b, node);
+      }
+      index_of_first_non_null_ =
+          std::min(index_of_first_non_null_, result.bucket_index_);
+      return result;
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b is a
+    // not-too-long linked list.
+    iterator InsertUniqueInList(size_type b, Node* node) {
+      node->next = static_cast<Node*>(table_[b]);
+      table_[b] = static_cast<void*>(node);
+      return iterator(node, this, b);
+    }
+
+    // Helper for InsertUnique.  Handles the case where bucket b points to a
+    // Tree.
+    iterator InsertUniqueInTree(size_type b, Node* node) {
+      GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]);
+      // Maintain the invariant that node->next is NULL for all Nodes in Trees.
+      node->next = NULL;
+      return iterator(static_cast<Tree*>(table_[b])
+                      ->insert(KeyPtrFromNodePtr(node))
+                      .first,
+                      this, b & ~static_cast<size_t>(1));
+    }
+
+    // Returns whether it did resize.  Currently this is only used when
+    // num_elements_ increases, though it could be used in other situations.
+    // It checks for load too low as well as load too high: because any number
+    // of erases can occur between inserts, the load could be as low as 0 here.
+    // Resizing to a lower size is not always helpful, but failing to do so can
+    // destroy the expected big-O bounds for some operations. By having the
+    // policy that sometimes we resize down as well as up, clients can easily
+    // keep O(size()) = O(number of buckets) if they want that.
+    bool ResizeIfLoadIsOutOfRange(size_type new_size) {
+      const size_type kMaxMapLoadTimes16 = 12;  // controls RAM vs CPU tradeoff
+      const size_type hi_cutoff = num_buckets_ * kMaxMapLoadTimes16 / 16;
+      const size_type lo_cutoff = hi_cutoff / 4;
+      // We don't care how many elements are in trees.  If a lot are,
+      // we may resize even though there are many empty buckets.  In
+      // practice, this seems fine.
+      if (GOOGLE_PREDICT_FALSE(new_size >= hi_cutoff)) {
+        if (num_buckets_ <= max_size() / 2) {
+          Resize(num_buckets_ * 2);
+          return true;
+        }
+      } else if (GOOGLE_PREDICT_FALSE(new_size <= lo_cutoff &&
+                               num_buckets_ > kMinTableSize)) {
+        size_type lg2_of_size_reduction_factor = 1;
+        // It's possible we want to shrink a lot here... size() could even be 0.
+        // So, estimate how much to shrink by making sure we don't shrink so
+        // much that we would need to grow the table after a few inserts.
+        const size_type hypothetical_size = new_size * 5 / 4 + 1;
+        while ((hypothetical_size << lg2_of_size_reduction_factor) <
+               hi_cutoff) {
+          ++lg2_of_size_reduction_factor;
+        }
+        size_type new_num_buckets = std::max<size_type>(
+            kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor);
+        if (new_num_buckets != num_buckets_) {
+          Resize(new_num_buckets);
+          return true;
+        }
+      }
+      return false;
+    }
+
+    // Resize to the given number of buckets.
+    void Resize(size_t new_num_buckets) {
+      GOOGLE_DCHECK_GE(new_num_buckets, kMinTableSize);
+      void** const old_table = table_;
+      const size_type old_table_size = num_buckets_;
+      num_buckets_ = new_num_buckets;
+      table_ = CreateEmptyTable(num_buckets_);
+      const size_type start = index_of_first_non_null_;
+      index_of_first_non_null_ = num_buckets_;
+      for (size_type i = start; i < old_table_size; i++) {
+        if (TableEntryIsNonEmptyList(old_table, i)) {
+          TransferList(old_table, i);
+        } else if (TableEntryIsTree(old_table, i)) {
+          TransferTree(old_table, i++);
+        }
+      }
+      Dealloc<void*>(old_table, old_table_size);
+    }
+
+    void TransferList(void* const* table, size_type index) {
+      Node* node = static_cast<Node*>(table[index]);
+      do {
+        Node* next = node->next;
+        InsertUnique(BucketNumber(*KeyPtrFromNodePtr(node)), node);
+        node = next;
+      } while (node != NULL);
+    }
+
+    void TransferTree(void* const* table, size_type index) {
+      Tree* tree = static_cast<Tree*>(table[index]);
+      typename Tree::iterator tree_it = tree->begin();
+      do {
+        Node* node = NodePtrFromKeyPtr(*tree_it);
+        InsertUnique(BucketNumber(**tree_it), node);
+      } while (++tree_it != tree->end());
+      DestroyTree(tree);
+    }
+
+    Node* EraseFromLinkedList(Node* item, Node* head) {
+      if (head == item) {
+        return head->next;
+      } else {
+        head->next = EraseFromLinkedList(item, head->next);
+        return head;
+      }
+    }
+
+    bool TableEntryIsEmpty(size_type b) const {
+      return TableEntryIsEmpty(table_, b);
+    }
+    bool TableEntryIsNonEmptyList(size_type b) const {
+      return TableEntryIsNonEmptyList(table_, b);
+    }
+    bool TableEntryIsTree(size_type b) const {
+      return TableEntryIsTree(table_, b);
+    }
+    bool TableEntryIsList(size_type b) const {
+      return TableEntryIsList(table_, b);
+    }
+    static bool TableEntryIsEmpty(void* const* table, size_type b) {
+      return table[b] == NULL;
+    }
+    static bool TableEntryIsNonEmptyList(void* const* table, size_type b) {
+      return table[b] != NULL && table[b] != table[b ^ 1];
+    }
+    static bool TableEntryIsTree(void* const* table, size_type b) {
+      return !TableEntryIsEmpty(table, b) &&
+          !TableEntryIsNonEmptyList(table, b);
+    }
+    static bool TableEntryIsList(void* const* table, size_type b) {
+      return !TableEntryIsTree(table, b);
+    }
+
+    void TreeConvert(size_type b) {
+      GOOGLE_DCHECK(!TableEntryIsTree(b) && !TableEntryIsTree(b ^ 1));
+      typename Allocator::template rebind<Tree>::other tree_allocator(alloc_);
+      Tree* tree = tree_allocator.allocate(1);
+      // We want to use the three-arg form of construct, if it exists, but we
+      // create a temporary and use the two-arg construct that's known to exist.
+      // It's clunky, but the compiler should be able to generate more-or-less
+      // the same code.
+      tree_allocator.construct(tree,
+                               Tree(KeyCompare(), KeyPtrAllocator(alloc_)));
+      // Now the tree is ready to use.
+      size_type count = CopyListToTree(b, tree) + CopyListToTree(b ^ 1, tree);
+      GOOGLE_DCHECK_EQ(count, tree->size());
+      table_[b] = table_[b ^ 1] = static_cast<void*>(tree);
+    }
+
+    // Copy a linked list in the given bucket to a tree.
+    // Returns the number of things it copied.
+    size_type CopyListToTree(size_type b, Tree* tree) {
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      while (node != NULL) {
+        tree->insert(KeyPtrFromNodePtr(node));
+        ++count;
+        Node* next = node->next;
+        node->next = NULL;
+        node = next;
+      }
+      return count;
+    }
+
+    // Return whether table_[b] is a linked list that seems awfully long.
+    // Requires table_[b] to point to a non-empty linked list.
+    bool TableEntryIsTooLong(size_type b) {
+      const int kMaxLength = 8;
+      size_type count = 0;
+      Node* node = static_cast<Node*>(table_[b]);
+      do {
+        ++count;
+        node = node->next;
+      } while (node != NULL);
+      // Invariant: no linked list ever is more than kMaxLength in length.
+      GOOGLE_DCHECK_LE(count, kMaxLength);
+      return count >= kMaxLength;
+    }
+
+    size_type BucketNumber(const Key& k) const {
+      // We inherit from hasher, so one-arg operator() provides a hash function.
+      size_type h = (*const_cast<InnerMap*>(this))(k);
+      // To help prevent people from making assumptions about the hash function,
+      // we use the seed differently depending on NDEBUG.  The default hash
+      // function, the seeding, etc., are all likely to change in the future.
+#ifndef NDEBUG
+      return (h * (seed_ | 1)) & (num_buckets_ - 1);
+#else
+      return (h + seed_) & (num_buckets_ - 1);
+#endif
+    }
+
+    bool IsMatch(const Key& k0, const Key& k1) const {
+      return std::equal_to<Key>()(k0, k1);
+    }
+
+    // Return a power of two no less than max(kMinTableSize, n).
+    // Assumes either n < kMinTableSize or n is a power of two.
+    size_type TableSize(size_type n) {
+      return n < kMinTableSize ? kMinTableSize : n;
+    }
+
+    // Use alloc_ to allocate an array of n objects of type U.
+    template <typename U>
+    U* Alloc(size_type n) {
+      typedef typename Allocator::template rebind<U>::other alloc_type;
+      return alloc_type(alloc_).allocate(n);
+    }
+
+    // Use alloc_ to deallocate an array of n objects of type U.
+    template <typename U>
+    void Dealloc(U* t, size_type n) {
+      typedef typename Allocator::template rebind<U>::other alloc_type;
+      alloc_type(alloc_).deallocate(t, n);
+    }
+
+    void DestroyNode(Node* node) {
+      alloc_.destroy(&node->kv);
+      Dealloc<Node>(node, 1);
+    }
+
+    void DestroyTree(Tree* tree) {
+      typename Allocator::template rebind<Tree>::other tree_allocator(alloc_);
+      tree_allocator.destroy(tree);
+      tree_allocator.deallocate(tree, 1);
+    }
+
+    void** CreateEmptyTable(size_type n) {
+      GOOGLE_DCHECK(n >= kMinTableSize);
+      GOOGLE_DCHECK_EQ(n & (n - 1), 0);
+      void** result = Alloc<void*>(n);
+      memset(result, 0, n * sizeof(result[0]));
+      return result;
+    }
+
+    // Return a randomish value.
+    size_type Seed() const {
+      // random_device can throw, so avoid it unless we are compiling with
+      // exceptions enabled.
+#if __cpp_exceptions && LANG_CXX11
+      try {
+        std::random_device rd;
+        std::knuth_b knuth(rd());
+        std::uniform_int_distribution<size_type> u;
+        return u(knuth);
+      } catch (...) { }
+#endif
+      size_type s = static_cast<size_type>(reinterpret_cast<uintptr_t>(this));
+#if defined(__x86_64__) && defined(__GNUC__)
+      uint32 hi, lo;
+      asm("rdtsc" : "=a" (lo), "=d" (hi));
+      s += ((static_cast<uint64>(hi) << 32) | lo);
+#endif
+      return s;
+    }
+
+    size_type num_elements_;
+    size_type num_buckets_;
+    size_type seed_;
+    size_type index_of_first_non_null_;
+    void** table_;  // an array with num_buckets_ entries
+    Allocator alloc_;
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap);
+  };  // end of class InnerMap
+
+  typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
+                   MapAllocator<std::pair<const Key, MapPair<Key, T>*> > >
+      DeprecatedInnerMap;
+
+ public:
+  // Iterators
+  class iterator_base {
+   public:
+    // We support "old style" and "new style" iterators for now. This is
+    // temporary.  Also, for "iterator()" we have an unknown category.
+    // TODO(gpike): get rid of this.
+    enum IteratorStyle { kUnknown, kOld, kNew };
+    explicit iterator_base(IteratorStyle style) : iterator_style_(style) {}
+
+    bool OldStyle() const {
+      GOOGLE_DCHECK_NE(iterator_style_, kUnknown);
+      return iterator_style_ == kOld;
+    }
+    bool UnknownStyle() const {
+      return iterator_style_ == kUnknown;
+    }
+    bool SameStyle(const iterator_base& other) const {
+      return iterator_style_ == other.iterator_style_;
+    }
+
+   private:
+    IteratorStyle iterator_style_;
+  };
+
+  class const_iterator
+      : private iterator_base,
+        public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
+                             const value_type*, const value_type&> {
+    typedef typename InnerMap::const_iterator InnerIt;
+    typedef typename DeprecatedInnerMap::const_iterator DeprecatedInnerIt;
+
+   public:
+    const_iterator() : iterator_base(iterator_base::kUnknown) {}
+    explicit const_iterator(const DeprecatedInnerIt& dit)
+        : iterator_base(iterator_base::kOld), dit_(dit) {}
+    explicit const_iterator(const InnerIt& it)
+        : iterator_base(iterator_base::kNew), it_(it) {}
+
+    const_iterator(const const_iterator& other)
+        : iterator_base(other), it_(other.it_), dit_(other.dit_) {}
+
+    const_reference operator*() const {
+      return this->OldStyle() ? *dit_->second : *it_->value();
+    }
+    const_pointer operator->() const { return &(operator*()); }
+
+    const_iterator& operator++() {
+      if (this->OldStyle())
+        ++dit_;
+      else
+        ++it_;
+      return *this;
+    }
+    const_iterator operator++(int) {
+      return this->OldStyle() ? const_iterator(dit_++) : const_iterator(it_++);
+    }
+
+    friend bool operator==(const const_iterator& a, const const_iterator& b) {
+      if (!a.SameStyle(b)) return false;
+      if (a.UnknownStyle()) return true;
+      return a.OldStyle() ? (a.dit_ == b.dit_) : (a.it_ == b.it_);
+    }
+    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    InnerIt it_;
+    DeprecatedInnerIt dit_;
+  };
+
+  class iterator : private iterator_base,
+                   public std::iterator<std::forward_iterator_tag, value_type> {
+    typedef typename InnerMap::iterator InnerIt;
+    typedef typename DeprecatedInnerMap::iterator DeprecatedInnerIt;
+
+   public:
+    iterator() : iterator_base(iterator_base::kUnknown) {}
+    explicit iterator(const DeprecatedInnerIt& dit)
+        : iterator_base(iterator_base::kOld), dit_(dit) {}
+    explicit iterator(const InnerIt& it)
+        : iterator_base(iterator_base::kNew), it_(it) {}
+
+    reference operator*() const {
+      return this->OldStyle() ? *dit_->second : *it_->value();
+    }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator& operator++() {
+      if (this->OldStyle())
+        ++dit_;
+      else
+        ++it_;
+      return *this;
+    }
+    iterator operator++(int) {
+      return this->OldStyle() ? iterator(dit_++) : iterator(it_++);
+    }
+
+    // Allow implicit conversion to const_iterator.
+    operator const_iterator() const {
+      return this->OldStyle() ?
+          const_iterator(typename DeprecatedInnerMap::const_iterator(dit_)) :
+          const_iterator(typename InnerMap::const_iterator(it_));
+    }
+
+    friend bool operator==(const iterator& a, const iterator& b) {
+      if (!a.SameStyle(b)) return false;
+      if (a.UnknownStyle()) return true;
+      return a.OldStyle() ? a.dit_ == b.dit_ : a.it_ == b.it_;
+    }
+    friend bool operator!=(const iterator& a, const iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    friend class Map;
+
+    InnerIt it_;
+    DeprecatedInnerIt dit_;
+  };
+
+  iterator begin() {
+    return old_style_ ? iterator(deprecated_elements_->begin())
+                      : iterator(elements_->begin());
+  }
+  iterator end() {
+    return old_style_ ? iterator(deprecated_elements_->end())
+                      : iterator(elements_->end());
+  }
+  const_iterator begin() const {
+    return old_style_ ? const_iterator(deprecated_elements_->begin())
+                      : const_iterator(iterator(elements_->begin()));
+  }
+  const_iterator end() const {
+    return old_style_ ? const_iterator(deprecated_elements_->end())
+                      : const_iterator(iterator(elements_->end()));
+  }
+  const_iterator cbegin() const { return begin(); }
+  const_iterator cend() const { return end(); }
+
+  // Capacity
+  size_type size() const {
+    return old_style_ ? deprecated_elements_->size() : elements_->size();
+  }
+  bool empty() const { return size() == 0; }
+
+  // Element access
+  T& operator[](const key_type& key) {
+    value_type** value =
+        old_style_ ? &(*deprecated_elements_)[key] : &(*elements_)[key];
+    if (*value == NULL) {
+      *value = CreateValueTypeInternal(key);
+      internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value,
+                                    T>::Initialize((*value)->second,
+                                                   default_enum_value_);
+    }
+    return (*value)->second;
+  }
+  const T& at(const key_type& key) const {
+    const_iterator it = find(key);
+    GOOGLE_CHECK(it != end());
+    return it->second;
+  }
+  T& at(const key_type& key) {
+    iterator it = find(key);
+    GOOGLE_CHECK(it != end());
+    return it->second;
+  }
+
+  // Lookup
+  size_type count(const key_type& key) const {
+    if (find(key) != end()) assert(key == find(key)->first);
+    return find(key) == end() ? 0 : 1;
+  }
+  const_iterator find(const key_type& key) const {
+    return old_style_ ? const_iterator(deprecated_elements_->find(key))
+        : const_iterator(iterator(elements_->find(key)));
+  }
+  iterator find(const key_type& key) {
+    return old_style_ ? iterator(deprecated_elements_->find(key))
+                      : iterator(elements_->find(key));
+  }
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_type& key) const {
+    const_iterator it = find(key);
+    if (it == end()) {
+      return std::pair<const_iterator, const_iterator>(it, it);
+    } else {
+      const_iterator begin = it++;
+      return std::pair<const_iterator, const_iterator>(begin, it);
+    }
+  }
+  std::pair<iterator, iterator> equal_range(const key_type& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return std::pair<iterator, iterator>(it, it);
+    } else {
+      iterator begin = it++;
+      return std::pair<iterator, iterator>(begin, it);
+    }
+  }
+
+  // insert
+  std::pair<iterator, bool> insert(const value_type& value) {
+    if (old_style_) {
+      iterator it = find(value.first);
+      if (it != end()) {
+        return std::pair<iterator, bool>(it, false);
+      } else {
+        return std::pair<iterator, bool>(
+            iterator(deprecated_elements_->insert(std::pair<Key, value_type*>(
+                value.first, CreateValueTypeInternal(value))).first), true);
+      }
+    } else {
+      std::pair<typename InnerMap::iterator, bool> p =
+          elements_->insert(value.first);
+      if (p.second) {
+        p.first->value() = CreateValueTypeInternal(value);
+      }
+      return std::pair<iterator, bool>(iterator(p.first), p.second);
+    }
+  }
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (InputIt it = first; it != last; ++it) {
+      iterator exist_it = find(it->first);
+      if (exist_it == end()) {
+        operator[](it->first) = it->second;
+      }
+    }
+  }
+
+  // Erase and clear
+  size_type erase(const key_type& key) {
+    iterator it = find(key);
+    if (it == end()) {
+      return 0;
+    } else {
+      erase(it);
+      return 1;
+    }
+  }
+  iterator erase(iterator pos) {
+    if (arena_ == NULL) delete pos.operator->();
+    iterator i = pos++;
+    if (old_style_)
+      deprecated_elements_->erase(i.dit_);
+    else
+      elements_->erase(i.it_);
+    return pos;
+  }
+  void erase(iterator first, iterator last) {
+    while (first != last) {
+      first = erase(first);
+    }
+  }
+  void clear() { erase(begin(), end()); }
+
+  // Assign
+  Map& operator=(const Map& other) {
+    if (this != &other) {
+      clear();
+      insert(other.begin(), other.end());
+    }
+    return *this;
+  }
+
+  // Access to hasher.  Currently this returns a copy, but it may
+  // be modified to return a const reference in the future.
+  hasher hash_function() const {
+    return old_style_ ? deprecated_elements_->hash_function()
+                      : elements_->hash_function();
+  }
+
+ private:
+  // Set default enum value only for proto2 map field whose value is enum type.
+  void SetDefaultEnumValue(int default_enum_value) {
+    default_enum_value_ = default_enum_value;
+  }
+
+  value_type* CreateValueTypeInternal(const Key& key) {
+    if (arena_ == NULL) {
+      return new value_type(key);
+    } else {
+      value_type* value = reinterpret_cast<value_type*>(
+          Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+      Arena::CreateInArenaStorage(const_cast<Key*>(&value->first), arena_);
+      Arena::CreateInArenaStorage(&value->second, arena_);
+      const_cast<Key&>(value->first) = key;
+      return value;
+    }
+  }
+
+  value_type* CreateValueTypeInternal(const value_type& value) {
+    if (arena_ == NULL) {
+      return new value_type(value);
+    } else {
+      value_type* p = reinterpret_cast<value_type*>(
+          Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+      Arena::CreateInArenaStorage(const_cast<Key*>(&p->first), arena_);
+      Arena::CreateInArenaStorage(&p->second, arena_);
+      const_cast<Key&>(p->first) = value.first;
+      p->second = value.second;
+      return p;
+    }
+  }
+
+  Arena* arena_;
+  int default_enum_value_;
+  // The following is a tagged union because we support two map styles
+  // for now.
+  // TODO(gpike): get rid of the old style.
+  const bool old_style_;
+  union {
+    InnerMap* elements_;
+    DeprecatedInnerMap* deprecated_elements_;
+  };
+
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  template <typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type,
+            int default_enum_value>
+  friend class internal::MapFieldLite;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
+template<>
+struct hash<google::protobuf::MapKey> {
+  size_t
+  operator()(const google::protobuf::MapKey& map_key) const {
+    switch (map_key.type()) {
+      case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
+      case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
+      case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Unsupported";
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
+        return hash<string>()(map_key.GetStringValue());
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
+        return hash< ::google::protobuf::int64>()(map_key.GetInt64Value());
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
+        return hash< ::google::protobuf::int32>()(map_key.GetInt32Value());
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
+        return hash< ::google::protobuf::uint64>()(map_key.GetUInt64Value());
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
+        return hash< ::google::protobuf::uint32>()(map_key.GetUInt32Value());
+      case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
+        return hash<bool>()(map_key.GetBoolValue());
+    }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
+  }
+  bool
+  operator()(const google::protobuf::MapKey& map_key1,
+             const google::protobuf::MapKey& map_key2) const {
+    return map_key1 < map_key2;
+  }
+};
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
+
+#endif  // GOOGLE_PROTOBUF_MAP_H__
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
new file mode 100644
index 0000000..987c4e2
--- /dev/null
+++ b/src/google/protobuf/map_entry.h
@@ -0,0 +1,308 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_H__
+
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+class MapField;
+}
+}
+
+namespace protobuf {
+namespace internal {
+
+// Register all MapEntry default instances so we can delete them in
+// ShutdownProtobufLibrary().
+void LIBPROTOBUF_EXPORT RegisterMapEntryDefaultInstance(
+    MessageLite* default_instance);
+
+// This is the common base class for MapEntry. It is used by MapFieldBase in
+// reflection api, in which the static type of key and value is unknown.
+class LIBPROTOBUF_EXPORT MapEntryBase : public Message {
+ public:
+  ::google::protobuf::Metadata GetMetadata() const {
+    ::google::protobuf::Metadata metadata;
+    metadata.descriptor = descriptor_;
+    metadata.reflection = reflection_;
+    return metadata;
+  }
+
+ protected:
+  MapEntryBase() : descriptor_(NULL), reflection_(NULL) {  }
+  virtual ~MapEntryBase() {}
+
+  const Descriptor* descriptor_;
+  const Reflection* reflection_;
+};
+
+// MapEntry is the returned google::protobuf::Message when calling AddMessage of
+// google::protobuf::Reflection. In order to let it work with generated message
+// reflection, its in-memory type is the same as generated message with the same
+// fields. However, in order to decide the in-memory type of key/value, we need
+// to know both their cpp type in generated api and proto type. In
+// implmentation, all in-memory types have related wire format functions to
+// support except ArenaStringPtr. Therefore, we need to define another type with
+// supporting wire format functions. Since this type is only used as return type
+// of MapEntry accessors, it's named MapEntry accessor type.
+//
+// cpp type:               the type visible to users in public API.
+// proto type:             WireFormatLite::FieldType of the field.
+// in-memory type:         type of the data member used to stored this field.
+// MapEntry accessor type: type used in MapEntry getters/mutators to access the
+//                         field.
+//
+// cpp type | proto type  | in-memory type | MapEntry accessor type
+// int32      TYPE_INT32    int32            int32
+// int32      TYPE_FIXED32  int32            int32
+// string     TYPE_STRING   ArenaStringPtr   string
+// FooEnum    TYPE_ENUM     int              int
+// FooMessage TYPE_MESSAGE  FooMessage*      FooMessage
+//
+// The in-memory types of primitive types can be inferred from its proto type,
+// while we need to explicitly specify the cpp type if proto type is
+// TYPE_MESSAGE to infer the in-memory type.  Moreover, default_enum_value is
+// used to initialize enum field in proto2.
+template <typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+class MapEntry : public MapEntryBase {
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type
+  // which will replace Enum with int.
+  typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
+  typedef typename ValueTypeHandler::MapEntryAccessorType
+      ValueMapEntryAccessorType;
+
+  // Abbreviation for MapEntry
+  typedef typename google::protobuf::internal::MapEntry<
+      Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> EntryType;
+
+  // Abbreviation for MapEntryLite
+  typedef typename google::protobuf::internal::MapEntryLite<
+      Key, Value, kKeyFieldType, kValueFieldType, default_enum_value>
+      EntryLiteType;
+
+ public:
+  ~MapEntry() {
+    if (this == default_instance_) {
+      delete reflection_;
+    }
+  }
+
+  // accessors ======================================================
+
+  virtual inline const KeyMapEntryAccessorType& key() const {
+    return entry_lite_.key();
+  }
+  inline KeyMapEntryAccessorType* mutable_key() {
+    return entry_lite_.mutable_key();
+  }
+  virtual inline const ValueMapEntryAccessorType& value() const {
+    return entry_lite_.value();
+  }
+  inline ValueMapEntryAccessorType* mutable_value() {
+    return entry_lite_.mutable_value();
+  }
+
+  // implements Message =============================================
+
+  bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+    return entry_lite_.MergePartialFromCodedStream(input);
+  }
+
+  int ByteSize() const {
+    return entry_lite_.ByteSize();
+  }
+
+  void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
+    entry_lite_.SerializeWithCachedSizes(output);
+  }
+
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return entry_lite_.SerializeWithCachedSizesToArray(output);
+  }
+
+  int GetCachedSize() const {
+    return entry_lite_.GetCachedSize();
+  }
+
+  bool IsInitialized() const {
+    return entry_lite_.IsInitialized();
+  }
+
+  Message* New() const {
+    MapEntry* entry = new MapEntry;
+    entry->descriptor_ = descriptor_;
+    entry->reflection_ = reflection_;
+    entry->set_default_instance(default_instance_);
+    return entry;
+  }
+
+  Message* New(Arena* arena) const {
+    MapEntry* entry = Arena::CreateMessage<MapEntry>(arena);
+    entry->descriptor_ = descriptor_;
+    entry->reflection_ = reflection_;
+    entry->set_default_instance(default_instance_);
+    return entry;
+  }
+
+  int SpaceUsed() const {
+    int size = sizeof(MapEntry);
+    size += entry_lite_.SpaceUsed();
+    return size;
+  }
+
+  void CopyFrom(const ::google::protobuf::Message& from) {
+    Clear();
+    MergeFrom(from);
+  }
+
+  void MergeFrom(const ::google::protobuf::Message& from) {
+    GOOGLE_CHECK_NE(&from, this);
+    const MapEntry* source = dynamic_cast_if_available<const MapEntry*>(&from);
+    if (source == NULL) {
+      ReflectionOps::Merge(from, this);
+    } else {
+      MergeFrom(*source);
+    }
+  }
+
+  void CopyFrom(const MapEntry& from) {
+    Clear();
+    MergeFrom(from);
+  }
+
+  void MergeFrom(const MapEntry& from) {
+    entry_lite_.MergeFrom(from.entry_lite_);
+  }
+
+  void Clear() {
+    entry_lite_.Clear();
+  }
+
+  void InitAsDefaultInstance() {
+    entry_lite_.InitAsDefaultInstance();
+  }
+
+  Arena* GetArena() const {
+    return entry_lite_.GetArena();
+  }
+
+  // Create default MapEntry instance for given descriptor. Descriptor has to be
+  // given when creating default MapEntry instance because different map field
+  // may have the same type and MapEntry class. The given descriptor is needed
+  // to distinguish instances of the same MapEntry class.
+  static MapEntry* CreateDefaultInstance(const Descriptor* descriptor) {
+    MapEntry* entry = new MapEntry;
+    const Reflection* reflection = new GeneratedMessageReflection(
+        descriptor, entry, offsets_,
+        GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_._has_bits_),
+        GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _unknown_fields_), -1,
+        DescriptorPool::generated_pool(),
+        ::google::protobuf::MessageFactory::generated_factory(),
+        sizeof(MapEntry),
+        GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _internal_metadata_));
+    entry->descriptor_ = descriptor;
+    entry->reflection_ = reflection;
+    entry->set_default_instance(entry);
+    entry->InitAsDefaultInstance();
+    RegisterMapEntryDefaultInstance(entry);
+    return entry;
+  }
+
+ private:
+  MapEntry()
+      : _internal_metadata_(NULL), default_instance_(NULL), entry_lite_() {}
+
+  explicit MapEntry(Arena* arena)
+      : _internal_metadata_(arena),
+        default_instance_(NULL),
+        entry_lite_(arena) {}
+
+  inline Arena* GetArenaNoVirtual() const {
+    return entry_lite_.GetArenaNoVirtual();
+  }
+
+  void set_default_instance(MapEntry* default_instance) {
+    default_instance_ = default_instance;
+    entry_lite_.set_default_instance(&default_instance->entry_lite_);
+  }
+
+  static int offsets_[2];
+  UnknownFieldSet _unknown_fields_;
+  InternalMetadataWithArena _internal_metadata_;
+  MapEntry* default_instance_;
+  EntryLiteType entry_lite_;
+
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+            WireFormatLite::FieldType, int default_enum>
+  friend class internal::MapField;
+  friend class internal::GeneratedMessageReflection;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
+};
+
+template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType, int default_enum_value>
+int MapEntry<Key, Value, kKeyFieldType, kValueFieldType,
+             default_enum_value>::offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_.key_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_.value_),
+};
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_H__
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
new file mode 100644
index 0000000..7cdf1b9
--- /dev/null
+++ b/src/google/protobuf/map_entry_lite.h
@@ -0,0 +1,401 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+class Arena;
+namespace internal {
+template <typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+class MapEntry;
+template <typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+class MapFieldLite;
+}  // namespace internal
+}  // namespace protobuf
+
+namespace protobuf {
+namespace internal {
+
+// MapEntryLite is used to implement parsing and serialization of map for lite
+// runtime.
+template <typename Key, typename Value,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+class MapEntryLite : public MessageLite {
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+
+  // Define internal memory layout. Strings and messages are stored as
+  // pointers, while other types are stored as values.
+  typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
+  typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
+
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type
+  // which will replace Enum with int.
+  typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
+  typedef typename ValueTypeHandler::MapEntryAccessorType
+      ValueMapEntryAccessorType;
+
+  // Constants for field number.
+  static const int kKeyFieldNumber = 1;
+  static const int kValueFieldNumber = 2;
+
+  // Constants for field tag.
+  static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kKeyFieldNumber, KeyTypeHandler::kWireType);
+  static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
+      kValueFieldNumber, ValueTypeHandler::kWireType);
+  static const int kTagSize = 1;
+
+ public:
+  ~MapEntryLite() {
+    if (this != default_instance_) {
+      if (GetArenaNoVirtual() != NULL) return;
+      KeyTypeHandler::DeleteNoArena(key_);
+      ValueTypeHandler::DeleteNoArena(value_);
+    }
+  }
+
+  // accessors ======================================================
+
+  virtual inline const KeyMapEntryAccessorType& key() const {
+    return KeyTypeHandler::GetExternalReference(key_);
+  }
+  virtual inline const ValueMapEntryAccessorType& value() const {
+    GOOGLE_CHECK(default_instance_ != NULL);
+    return ValueTypeHandler::DefaultIfNotInitialized(value_,
+                                                    default_instance_->value_);
+  }
+  inline KeyMapEntryAccessorType* mutable_key() {
+    set_has_key();
+    return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+  }
+  inline ValueMapEntryAccessorType* mutable_value() {
+    set_has_value();
+    return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
+  }
+
+  // implements MessageLite =========================================
+
+  // MapEntryLite is for implementation only and this function isn't called
+  // anywhere. Just provide a fake implementation here for MessageLite.
+  string GetTypeName() const { return ""; }
+
+  void CheckTypeAndMergeFrom(const MessageLite& other) {
+    MergeFrom(*::google::protobuf::down_cast<const MapEntryLite*>(&other));
+  }
+
+  bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+    uint32 tag;
+
+    for (;;) {
+      // 1) corrupted data: return false;
+      // 2) unknown field: skip without putting into unknown field set;
+      // 3) unknown enum value: keep it in parsing. In proto2, caller should
+      // check the value and put this entry into containing message's unknown
+      // field set if the value is an unknown enum. In proto3, caller doesn't
+      // need to care whether the value is unknown enum;
+      // 4) missing key/value: missed key/value will have default value. caller
+      // should take this entry as if key/value is set to default value.
+      tag = input->ReadTag();
+      switch (tag) {
+        case kKeyTag:
+          if (!KeyTypeHandler::Read(input, mutable_key())) {
+            return false;
+          }
+          set_has_key();
+          if (!input->ExpectTag(kValueTag)) break;
+          GOOGLE_FALLTHROUGH_INTENDED;
+
+        case kValueTag:
+          if (!ValueTypeHandler::Read(input, mutable_value())) {
+            return false;
+          }
+          set_has_value();
+          if (input->ExpectAtEnd()) return true;
+          break;
+
+        default:
+          if (tag == 0 ||
+              WireFormatLite::GetTagWireType(tag) ==
+              WireFormatLite::WIRETYPE_END_GROUP) {
+            return true;
+          }
+          if (!WireFormatLite::SkipField(input, tag)) return false;
+          break;
+      }
+    }
+  }
+
+  int ByteSize() const {
+    int size = 0;
+    size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0;
+    size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0;
+    return size;
+  }
+
+  void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
+    KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
+    ValueTypeHandler::Write(kValueFieldNumber, value(), output);
+  }
+
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
+    output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
+    return output;
+  }
+
+  int GetCachedSize() const {
+    int size = 0;
+    size += has_key()
+        ? kTagSize + KeyTypeHandler::GetCachedSize(key())
+        : 0;
+    size += has_value()
+        ? kTagSize + ValueTypeHandler::GetCachedSize(
+            value())
+        : 0;
+    return size;
+  }
+
+  bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); }
+
+  MessageLite* New() const {
+    MapEntryLite* entry = new MapEntryLite;
+    entry->default_instance_ = default_instance_;
+    return entry;
+  }
+
+  MessageLite* New(Arena* arena) const {
+    MapEntryLite* entry = Arena::CreateMessage<MapEntryLite>(arena);
+    entry->default_instance_ = default_instance_;
+    return entry;
+  }
+
+  int SpaceUsed() const {
+    int size = sizeof(MapEntryLite);
+    size += KeyTypeHandler::SpaceUsedInMapEntry(key_);
+    size += ValueTypeHandler::SpaceUsedInMapEntry(value_);
+    return size;
+  }
+
+  void MergeFrom(const MapEntryLite& from) {
+    if (from._has_bits_[0]) {
+      if (from.has_key()) {
+        KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
+        KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual());
+        set_has_key();
+      }
+      if (from.has_value()) {
+        ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
+        ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual());
+        set_has_value();
+      }
+    }
+  }
+
+  void Clear() {
+    KeyTypeHandler::Clear(&key_, GetArenaNoVirtual());
+    ValueTypeHandler::ClearMaybeByDefaultEnum(
+        &value_, GetArenaNoVirtual(), default_enum_value);
+    clear_has_key();
+    clear_has_value();
+  }
+
+  void InitAsDefaultInstance() {
+    KeyTypeHandler::AssignDefaultValue(&key_);
+    ValueTypeHandler::AssignDefaultValue(&value_);
+  }
+
+  Arena* GetArena() const {
+    return GetArenaNoVirtual();
+  }
+
+  // Create a MapEntryLite for given key and value from google::protobuf::Map in
+  // serialization. This function is only called when value is enum. Enum is
+  // treated differently because its type in MapEntry is int and its type in
+  // google::protobuf::Map is enum. We cannot create a reference to int from an enum.
+  static MapEntryLite* EnumWrap(const Key& key, const Value value,
+                                Arena* arena) {
+    return Arena::CreateMessage<MapEnumEntryWrapper<
+        Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >(
+        arena, key, value);
+  }
+
+  // Like above, but for all the other types. This avoids value copy to create
+  // MapEntryLite from google::protobuf::Map in serialization.
+  static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) {
+    return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType,
+                                                kValueFieldType,
+                                                default_enum_value> >(
+        arena, key, value);
+  }
+
+ protected:
+  void set_has_key() { _has_bits_[0] |= 0x00000001u; }
+  bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
+  void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
+  void set_has_value() { _has_bits_[0] |= 0x00000002u; }
+  bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
+  void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
+
+ private:
+  // Serializing a generated message containing map field involves serializing
+  // key-value pairs from google::protobuf::Map. The wire format of each key-value pair
+  // after serialization should be the same as that of a MapEntry message
+  // containing the same key and value inside it.  However, google::protobuf::Map doesn't
+  // store key and value as MapEntry message, which disables us to use existing
+  // code to serialize message. In order to use existing code to serialize
+  // message, we need to construct a MapEntry from key-value pair. But it
+  // involves copy of key and value to construct a MapEntry. In order to avoid
+  // this copy in constructing a MapEntry, we need the following class which
+  // only takes references of given key and value.
+  template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+            WireFormatLite::FieldType v_wire_type, int default_enum>
+  class MapEntryWrapper
+      : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
+    typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
+    typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
+    typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
+
+   public:
+    MapEntryWrapper(Arena* arena, const K& key, const V& value)
+        : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
+          key_(key),
+          value_(value) {
+      Base::set_has_key();
+      Base::set_has_value();
+    }
+    inline const KeyMapEntryAccessorType& key() const { return key_; }
+    inline const ValueMapEntryAccessorType& value() const { return value_; }
+
+   private:
+    const Key& key_;
+    const Value& value_;
+
+    friend class ::google::protobuf::Arena;
+    typedef void InternalArenaConstructable_;
+    typedef void DestructorSkippable_;
+  };
+
+  // Like above, but for enum value only, which stores value instead of
+  // reference of value field inside. This is needed because the type of value
+  // field in constructor is an enum, while we need to store it as an int. If we
+  // initialize a reference to int with a reference to enum, compiler will
+  // generate a temporary int from enum and initialize the reference to int with
+  // the temporary.
+  template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
+            WireFormatLite::FieldType v_wire_type, int default_enum>
+  class MapEnumEntryWrapper
+      : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
+    typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
+    typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
+    typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
+
+   public:
+    MapEnumEntryWrapper(Arena* arena, const K& key, const V& value)
+        : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
+          key_(key),
+          value_(value) {
+      Base::set_has_key();
+      Base::set_has_value();
+    }
+    inline const KeyMapEntryAccessorType& key() const { return key_; }
+    inline const ValueMapEntryAccessorType& value() const { return value_; }
+
+   private:
+    const KeyMapEntryAccessorType& key_;
+    const ValueMapEntryAccessorType value_;
+
+    friend class google::protobuf::Arena;
+    typedef void DestructorSkippable_;
+  };
+
+  MapEntryLite() : default_instance_(NULL), arena_(NULL) {
+    KeyTypeHandler::Initialize(&key_, NULL);
+    ValueTypeHandler::InitializeMaybeByDefaultEnum(
+        &value_, default_enum_value, NULL);
+    _has_bits_[0] = 0;
+  }
+
+  explicit MapEntryLite(Arena* arena)
+      : default_instance_(NULL), arena_(arena) {
+    KeyTypeHandler::Initialize(&key_, arena);
+    ValueTypeHandler::InitializeMaybeByDefaultEnum(
+        &value_, default_enum_value, arena);
+    _has_bits_[0] = 0;
+  }
+
+  inline Arena* GetArenaNoVirtual() const {
+    return arena_;
+  }
+
+  void set_default_instance(MapEntryLite* default_instance) {
+    default_instance_ = default_instance;
+  }
+
+  MapEntryLite* default_instance_;
+
+  KeyOnMemory key_;
+  ValueOnMemory value_;
+  Arena* arena_;
+  uint32 _has_bits_[1];
+
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  template <typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType, int>
+  friend class internal::MapEntry;
+  template <typename K, typename V, WireFormatLite::FieldType,
+            WireFormatLite::FieldType, int>
+  friend class internal::MapFieldLite;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
+};
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
new file mode 100644
index 0000000..49f9181
--- /dev/null
+++ b/src/google/protobuf/map_field.cc
@@ -0,0 +1,471 @@
+// 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.
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_field_inl.h>
+
+#include <vector>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+ProtobufOnceType map_entry_default_instances_once_;
+Mutex* map_entry_default_instances_mutex_;
+vector<MessageLite*>* map_entry_default_instances_;
+
+void DeleteMapEntryDefaultInstances() {
+  for (int i = 0; i < map_entry_default_instances_->size(); ++i) {
+    delete map_entry_default_instances_->at(i);
+  }
+  delete map_entry_default_instances_mutex_;
+  delete map_entry_default_instances_;
+}
+
+void InitMapEntryDefaultInstances() {
+  map_entry_default_instances_mutex_ = new Mutex();
+  map_entry_default_instances_ = new vector<MessageLite*>();
+  OnShutdown(&DeleteMapEntryDefaultInstances);
+}
+
+void RegisterMapEntryDefaultInstance(MessageLite* default_instance) {
+  ::google::protobuf::GoogleOnceInit(&map_entry_default_instances_once_,
+                 &InitMapEntryDefaultInstances);
+  MutexLock lock(map_entry_default_instances_mutex_);
+  map_entry_default_instances_->push_back(default_instance);
+}
+
+MapFieldBase::~MapFieldBase() {
+  if (repeated_field_ != NULL && arena_ == NULL) delete repeated_field_;
+}
+
+const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
+  SyncRepeatedFieldWithMap();
+  return *repeated_field_;
+}
+
+RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() {
+  SyncRepeatedFieldWithMap();
+  SetRepeatedDirty();
+  return repeated_field_;
+}
+
+int MapFieldBase::SpaceUsedExcludingSelf() const {
+  mutex_.Lock();
+  int size = SpaceUsedExcludingSelfNoLock();
+  mutex_.Unlock();
+  return size;
+}
+
+int MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
+  if (repeated_field_ != NULL) {
+    return repeated_field_->SpaceUsedExcludingSelf();
+  } else {
+    return 0;
+  }
+}
+
+void MapFieldBase::InitMetadataOnce() const {
+  GOOGLE_CHECK(entry_descriptor_ != NULL);
+  GOOGLE_CHECK(assign_descriptor_callback_ != NULL);
+  (*assign_descriptor_callback_)();
+}
+
+void MapFieldBase::SetMapDirty() { state_ = STATE_MODIFIED_MAP; }
+
+void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; }
+
+void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; }
+
+void MapFieldBase::SyncRepeatedFieldWithMap() const {
+  // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
+  // executed before state_ is checked.
+  Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
+  if (state == STATE_MODIFIED_MAP) {
+    mutex_.Lock();
+    // Double check state, because another thread may have seen the same state
+    // and done the synchronization before the current thread.
+    if (state_ == STATE_MODIFIED_MAP) {
+      SyncRepeatedFieldWithMapNoLock();
+      // "Release" insures state_ can only be changed "after"
+      // SyncRepeatedFieldWithMapNoLock is finished.
+      google::protobuf::internal::Release_Store(&state_, CLEAN);
+    }
+    mutex_.Unlock();
+  }
+}
+
+void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
+  if (repeated_field_ == NULL) {
+    repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
+  }
+}
+
+void MapFieldBase::SyncMapWithRepeatedField() const {
+  // "Acquire" insures the operation after SyncMapWithRepeatedField won't get
+  // executed before state_ is checked.
+  Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
+  if (state == STATE_MODIFIED_REPEATED) {
+    mutex_.Lock();
+    // Double check state, because another thread may have seen the same state
+    // and done the synchronization before the current thread.
+    if (state_ == STATE_MODIFIED_REPEATED) {
+      SyncMapWithRepeatedFieldNoLock();
+      // "Release" insures state_ can only be changed "after"
+      // SyncRepeatedFieldWithMapNoLock is finished.
+      google::protobuf::internal::Release_Store(&state_, CLEAN);
+    }
+    mutex_.Unlock();
+  }
+}
+
+// ------------------DynamicMapField------------------
+DynamicMapField::DynamicMapField(const Message* default_entry)
+    : default_entry_(default_entry) {
+}
+
+DynamicMapField::DynamicMapField(const Message* default_entry,
+                                 Arena* arena)
+    : TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena),
+      default_entry_(default_entry) {
+}
+
+DynamicMapField::~DynamicMapField() {
+  // DynamicMapField owns map values. Need to delete them before clearing
+  // the map.
+  for (Map<MapKey, MapValueRef>::iterator iter = map_.begin();
+       iter != map_.end(); ++iter) {
+    iter->second.DeleteData();
+  }
+  map_.clear();
+}
+
+int DynamicMapField::size() const {
+  return GetMap().size();
+}
+
+bool DynamicMapField::ContainsMapKey(
+    const MapKey& map_key) const {
+  const Map<MapKey, MapValueRef>& map = GetMap();
+  Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
+  return iter != map.end();
+}
+
+bool DynamicMapField::InsertOrLookupMapValue(
+    const MapKey& map_key, MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
+  if (iter == map->end()) {
+    // Insert
+    MapValueRef& map_val = (*map)[map_key];
+    const FieldDescriptor* val_des =
+        default_entry_->GetDescriptor()->FindFieldByName("value");
+    map_val.SetType(val_des->cpp_type());
+    // Allocate memory for the inserted MapValueRef, and initialize to
+    // default value.
+    switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                              \
+      case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: {        \
+        TYPE * value = new TYPE();                              \
+        map_val.SetValue(value);                                \
+        break;                                                  \
+      }
+      HANDLE_TYPE(INT32, int32);
+      HANDLE_TYPE(INT64, int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(ENUM, int32);
+#undef HANDLE_TYPE
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = default_entry_->GetReflection()->GetMessage(
+            *default_entry_, val_des);
+        Message* value = message.New();
+        map_val.SetValue(value);
+        break;
+      }
+    }
+    val->CopyFrom(map_val);
+    return true;
+  }
+  // map_key is already in the map. Make sure (*map)[map_key] is not called.
+  // [] may reorder the map and iterators.
+  val->CopyFrom(iter->second);
+  return false;
+}
+
+bool DynamicMapField::DeleteMapValue(const MapKey& map_key) {
+  MapFieldBase::SyncMapWithRepeatedField();
+  Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key);
+  if (iter == map_.end()) {
+    return false;
+  }
+  // Set map dirty only if the delete is successful.
+  MapFieldBase::SetMapDirty();
+  iter->second.DeleteData();
+  map_.erase(iter);
+  return true;
+}
+
+const Map<MapKey, MapValueRef>& DynamicMapField::GetMap() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return map_;
+}
+
+Map<MapKey, MapValueRef>* DynamicMapField::MutableMap() {
+  MapFieldBase::SyncMapWithRepeatedField();
+  MapFieldBase::SetMapDirty();
+  return &map_;
+}
+
+void DynamicMapField::SetMapIteratorValue(MapIterator* map_iter) const {
+  Map<MapKey, MapValueRef>::const_iterator iter =
+      TypeDefinedMapFieldBase<MapKey, MapValueRef>::InternalGetIterator(
+          map_iter);
+  if (iter == map_.end()) return;
+  map_iter->key_.CopyFrom(iter->first);
+  map_iter->value_.CopyFrom(iter->second);
+}
+
+void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
+  const Reflection* reflection = default_entry_->GetReflection();
+  const FieldDescriptor* key_des =
+      default_entry_->GetDescriptor()->FindFieldByName("key");
+  const FieldDescriptor* val_des =
+      default_entry_->GetDescriptor()->FindFieldByName("value");
+  if (MapFieldBase::repeated_field_ == NULL) {
+    if (MapFieldBase::arena_ == NULL) {
+      MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>();
+    } else {
+      MapFieldBase::repeated_field_ =
+          Arena::CreateMessage<RepeatedPtrField<Message> >(
+              MapFieldBase::arena_);
+    }
+  }
+
+  MapFieldBase::repeated_field_->Clear();
+
+  for (Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
+       it != map_.end(); ++it) {
+    Message* new_entry = default_entry_->New();
+    MapFieldBase::repeated_field_->AddAllocated(new_entry);
+    const MapKey& map_key = it->first;
+    switch (key_des->cpp_type()) {
+      case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, key_des, map_key.GetStringValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
+      case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
+      case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+        break;
+    }
+    const MapValueRef& map_val = it->second;
+    switch (val_des->cpp_type()) {
+      case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
+        reflection->SetString(new_entry, val_des, map_val.GetStringValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
+        reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
+        reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
+        reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
+        reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
+        reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
+        reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
+        reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
+        reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = map_val.GetMessageValue();
+        reflection->MutableMessage(new_entry, val_des)->CopyFrom(message);
+        break;
+      }
+    }
+  }
+}
+
+void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
+  Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
+  const Reflection* reflection = default_entry_->GetReflection();
+  const FieldDescriptor* key_des =
+      default_entry_->GetDescriptor()->FindFieldByName("key");
+  const FieldDescriptor* val_des =
+      default_entry_->GetDescriptor()->FindFieldByName("value");
+  // DynamicMapField owns map values. Need to delete them before clearing
+  // the map.
+  for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
+       iter != map->end(); ++iter) {
+    iter->second.DeleteData();
+  }
+  map->clear();
+  for (RepeatedPtrField<Message>::iterator it =
+           MapFieldBase::repeated_field_->begin();
+       it != MapFieldBase::repeated_field_->end(); ++it) {
+    MapKey map_key;
+    switch (key_des->cpp_type()) {
+      case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
+        map_key.SetStringValue(reflection->GetString(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
+        map_key.SetInt64Value(reflection->GetInt64(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
+        map_key.SetInt32Value(reflection->GetInt32(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
+        map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
+        map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
+        map_key.SetBoolValue(reflection->GetBool(*it, key_des));
+        break;
+      case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
+      case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
+      case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Can't get here.";
+        break;
+    }
+    MapValueRef& map_val = (*map)[map_key];
+    map_val.SetType(val_des->cpp_type());
+    switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD)                      \
+      case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: {        \
+        TYPE * value = new TYPE;                                \
+        *value = reflection->Get##METHOD(*it, val_des);         \
+            map_val.SetValue(value);                            \
+            break;                                              \
+      }
+      HANDLE_TYPE(INT32, int32, Int32);
+      HANDLE_TYPE(INT64, int64, Int64);
+      HANDLE_TYPE(UINT32, uint32, UInt32);
+      HANDLE_TYPE(UINT64, uint64, UInt64);
+      HANDLE_TYPE(DOUBLE, double, Double);
+      HANDLE_TYPE(FLOAT, float, Float);
+      HANDLE_TYPE(BOOL, bool, Bool);
+      HANDLE_TYPE(STRING, string, String);
+      HANDLE_TYPE(ENUM, int32, EnumValue);
+#undef HANDLE_TYPE
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+        const Message& message = reflection->GetMessage(*it, val_des);
+        Message* value = message.New();
+        value->CopyFrom(message);
+        map_val.SetValue(value);
+        break;
+      }
+    }
+  }
+}
+
+int DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
+  int size = 0;
+  if (MapFieldBase::repeated_field_ != NULL) {
+    size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelf();
+  }
+  size += sizeof(map_);
+  int map_size = map_.size();
+  if (map_size) {
+    Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
+    size += sizeof(it->first) * map_size;
+    size += sizeof(it->second) * map_size;
+    // If key is string, add the allocated space.
+    if (it->first.type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING) {
+      size += sizeof(string) * map_size;
+    }
+    // Add the allocated space in MapValueRef.
+    switch (it->second.type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                              \
+      case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: {        \
+        size += sizeof(TYPE) * map_size;                        \
+        break;                                                  \
+      }
+      HANDLE_TYPE(INT32, int32);
+      HANDLE_TYPE(INT64, int64);
+      HANDLE_TYPE(UINT32, uint32);
+      HANDLE_TYPE(UINT64, uint64);
+      HANDLE_TYPE(DOUBLE, double);
+      HANDLE_TYPE(FLOAT, float);
+      HANDLE_TYPE(BOOL, bool);
+      HANDLE_TYPE(STRING, string);
+      HANDLE_TYPE(ENUM, int32);
+#undef HANDLE_TYPE
+      case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
+        while (it != map_.end()) {
+          const Message& message = it->second.GetMessageValue();
+          size += message.GetReflection()->SpaceUsed(message);
+          ++it;
+        }
+        break;
+      }
+    }
+  }
+  return size;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
new file mode 100644
index 0000000..4b46f3a
--- /dev/null
+++ b/src/google/protobuf/map_field.h
@@ -0,0 +1,397 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_H__
+
+#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/map_entry.h>
+#include <google/protobuf/map_field_lite.h>
+#include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+
+
+namespace google {
+namespace protobuf {
+class DynamicMessage;
+class MapKey;
+namespace internal {
+
+class ContendedMapCleanTest;
+class GeneratedMessageReflection;
+class MapFieldAccessor;
+
+// This class provides accesss to map field using reflection, which is the same
+// as those provided for RepeatedPtrField<Message>. It is used for internal
+// reflection implentation only. Users should never use this directly.
+class LIBPROTOBUF_EXPORT MapFieldBase {
+ public:
+  MapFieldBase()
+      : arena_(NULL),
+        repeated_field_(NULL),
+        entry_descriptor_(NULL),
+        assign_descriptor_callback_(NULL),
+        state_(STATE_MODIFIED_MAP) {}
+  explicit MapFieldBase(Arena* arena)
+      : arena_(arena),
+        repeated_field_(NULL),
+        entry_descriptor_(NULL),
+        assign_descriptor_callback_(NULL),
+        state_(STATE_MODIFIED_MAP) {
+    // Mutex's destructor needs to be called explicitly to release resources
+    // acquired in its constructor.
+    arena->OwnDestructor(&mutex_);
+  }
+  virtual ~MapFieldBase();
+
+  // Returns reference to internal repeated field. Data written using
+  // google::protobuf::Map's api prior to calling this function is guarantted to be
+  // included in repeated field.
+  const RepeatedPtrFieldBase& GetRepeatedField() const;
+
+  // Like above. Returns mutable pointer to the internal repeated field.
+  RepeatedPtrFieldBase* MutableRepeatedField();
+
+  // Pure virtual map APIs for Map Reflection.
+  virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
+  virtual bool InsertOrLookupMapValue(
+      const MapKey& map_key, MapValueRef* val) = 0;
+  virtual bool DeleteMapValue(const MapKey& map_key) = 0;
+  virtual bool EqualIterator(const MapIterator& a,
+                             const MapIterator& b) const = 0;
+  virtual void MapBegin(MapIterator* map_iter) const = 0;
+  virtual void MapEnd(MapIterator* map_iter) const = 0;
+  // Sync Map with repeated field and returns the size of map.
+  virtual int size() const = 0;
+
+  // Returns the number of bytes used by the repeated field, excluding
+  // sizeof(*this)
+  int SpaceUsedExcludingSelf() const;
+
+ protected:
+  // Gets the size of space used by map field.
+  virtual int SpaceUsedExcludingSelfNoLock() const;
+
+  // Synchronizes the content in Map to RepeatedPtrField if there is any change
+  // to Map after last synchronization.
+  void SyncRepeatedFieldWithMap() const;
+  virtual void SyncRepeatedFieldWithMapNoLock() const;
+
+  // Synchronizes the content in RepeatedPtrField to Map if there is any change
+  // to RepeatedPtrField after last synchronization.
+  void SyncMapWithRepeatedField() const;
+  virtual void SyncMapWithRepeatedFieldNoLock() const {}
+
+  // Tells MapFieldBase that there is new change to Map.
+  void SetMapDirty();
+
+  // Tells MapFieldBase that there is new change to RepeatedPTrField.
+  void SetRepeatedDirty();
+
+  // Provides derived class the access to repeated field.
+  void* MutableRepeatedPtrField() const;
+
+  // Creates descriptor for only one time.
+  void InitMetadataOnce() const;
+
+  enum State {
+    STATE_MODIFIED_MAP = 0,       // map has newly added data that has not been
+                                  // synchronized to repeated field
+    STATE_MODIFIED_REPEATED = 1,  // repeated field has newly added data that
+                                  // has not been synchronized to map
+    CLEAN = 2,  // data in map and repeated field are same
+  };
+
+  Arena* arena_;
+  mutable RepeatedPtrField<Message>* repeated_field_;
+  // MapEntry can only be created from MapField. To create MapEntry, MapField
+  // needs to know its descriptor, because MapEntry is not generated class which
+  // cannot initialize its own descriptor by calling generated
+  // descriptor-assign-function. Thus, we need to register a callback to
+  // initialize MapEntry's descriptor.
+  const Descriptor** entry_descriptor_;
+  void (*assign_descriptor_callback_)();
+
+  mutable Mutex mutex_;  // The thread to synchronize map and repeated field
+                         // needs to get lock first;
+  mutable volatile Atomic32 state_;  // 0: STATE_MODIFIED_MAP
+                                     // 1: STATE_MODIFIED_REPEATED
+                                     // 2: CLEAN
+
+ private:
+  friend class ContendedMapCleanTest;
+  friend class GeneratedMessageReflection;
+  friend class MapFieldAccessor;
+  friend class ::google::protobuf::DynamicMessage;
+
+  // Virtual helper methods for MapIterator. MapIterator doesn't have the
+  // type helper for key and value. Call these help methods to deal with
+  // different types. Real helper methods are implemented in
+  // TypeDefinedMapFieldBase.
+  friend class ::google::protobuf::MapIterator;
+  // Allocate map<...>::iterator for MapIterator.
+  virtual void InitializeIterator(MapIterator* map_iter) const = 0;
+
+  // DeleteIterator() is called by the destructor of MapIterator only.
+  // It deletes map<...>::iterator for MapIterator.
+  virtual void DeleteIterator(MapIterator* map_iter) const = 0;
+
+  // Copy the map<...>::iterator from other_iterator to
+  // this_iterator.
+  virtual void CopyIterator(MapIterator* this_iterator,
+                            const MapIterator& other_iterator) const = 0;
+
+  // IncreaseIterator() is called by operator++() of MapIterator only.
+  // It implements the ++ operator of MapIterator.
+  virtual void IncreaseIterator(MapIterator* map_iter) const = 0;
+};
+
+// This class provides common Map Reflection implementations for generated
+// message and dynamic message.
+template<typename Key, typename T>
+class TypeDefinedMapFieldBase : public MapFieldBase {
+ public:
+  TypeDefinedMapFieldBase() {}
+  explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
+  ~TypeDefinedMapFieldBase() {}
+  void MapBegin(MapIterator* map_iter) const;
+  void MapEnd(MapIterator* map_iter) const;
+  bool EqualIterator(const MapIterator& a, const MapIterator& b) const;
+
+  virtual const Map<Key, T>& GetMap() const = 0;
+  virtual Map<Key, T>* MutableMap() = 0;
+
+ protected:
+  typename Map<Key, T>::const_iterator& InternalGetIterator(
+      const MapIterator* map_iter) const;
+
+ private:
+  void InitializeIterator(MapIterator* map_iter) const;
+  void DeleteIterator(MapIterator* map_iter) const;
+  void CopyIterator(MapIterator* this_iteratorm,
+                    const MapIterator& that_iterator) const;
+  void IncreaseIterator(MapIterator* map_iter) const;
+
+  virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0;
+};
+
+// This class provides accesss to map field using generated api. It is used for
+// internal generated message implentation only. Users should never use this
+// directly.
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value = 0>
+class MapField : public TypeDefinedMapFieldBase<Key, T>,
+                 public MapFieldLite<Key, T, kKeyFieldType, kValueFieldType,
+                                     default_enum_value> {
+  // Provide utilities to parse/serialize key/value.  Provide utilities to
+  // manipulate internal stored type.
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, T> ValueTypeHandler;
+
+  // Define message type for internal repeated field.
+  typedef MapEntry<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>
+      EntryType;
+  typedef MapEntryLite<Key, T, kKeyFieldType, kValueFieldType,
+                       default_enum_value> EntryLiteType;
+
+  // Define abbreviation for parent MapFieldLite
+  typedef MapFieldLite<Key, T, kKeyFieldType, kValueFieldType,
+                       default_enum_value> MapFieldLiteType;
+
+  // Enum needs to be handled differently from other types because it has
+  // different exposed type in google::protobuf::Map's api and repeated field's api. For
+  // details see the comment in the implementation of
+  // SyncMapWithRepeatedFieldNoLock.
+  static const bool kIsValueEnum = ValueTypeHandler::kIsEnum;
+  typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
+
+ public:
+  MapField();
+  explicit MapField(Arena* arena);
+  // MapField doesn't own the default_entry, which means default_entry must
+  // outlive the lifetime of MapField.
+  MapField(const Message* default_entry);
+  // For tests only.
+  MapField(Arena* arena, const Message* default_entry);
+  ~MapField();
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val);
+  bool DeleteMapValue(const MapKey& map_key);
+
+  // Accessors
+  const Map<Key, T>& GetMap() const;
+  Map<Key, T>* MutableMap();
+
+  // Convenient methods for generated message implementation.
+  int size() const;
+  void Clear();
+  void MergeFrom(const MapFieldLiteType& other);
+  void Swap(MapFieldLiteType* other);
+
+  // Allocates metadata only if this MapField is part of a generated message.
+  void SetEntryDescriptor(const Descriptor** descriptor);
+  void SetAssignDescriptorCallback(void (*callback)());
+
+ private:
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+
+  // MapField needs MapEntry's default instance to create new MapEntry.
+  void InitDefaultEntryOnce() const;
+
+  // Manually set default entry instance. For test only.
+  void SetDefaultEntryOnce(const EntryType* default_entry) const;
+
+  // Convenient methods to get internal google::protobuf::Map
+  const Map<Key, T>& GetInternalMap() const;
+  Map<Key, T>* MutableInternalMap();
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const;
+  void SyncMapWithRepeatedFieldNoLock() const;
+  int SpaceUsedExcludingSelfNoLock() const;
+
+  void SetMapIteratorValue(MapIterator* map_iter) const;
+
+  mutable const EntryType* default_entry_;
+
+  friend class ::google::protobuf::Arena;
+};
+
+class LIBPROTOBUF_EXPORT DynamicMapField: public TypeDefinedMapFieldBase<MapKey, MapValueRef> {
+ public:
+  explicit DynamicMapField(const Message* default_entry);
+  DynamicMapField(const Message* default_entry, Arena* arena);
+  ~DynamicMapField();
+
+  // Implement MapFieldBase
+  bool ContainsMapKey(const MapKey& map_key) const;
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val);
+  bool DeleteMapValue(const MapKey& map_key);
+
+  const Map<MapKey, MapValueRef>& GetMap() const;
+  Map<MapKey, MapValueRef>* MutableMap();
+
+  int size() const;
+
+ private:
+  Map<MapKey, MapValueRef> map_;
+  const Message* default_entry_;
+
+  // Implements MapFieldBase
+  void SyncRepeatedFieldWithMapNoLock() const;
+  void SyncMapWithRepeatedFieldNoLock() const;
+  int SpaceUsedExcludingSelfNoLock() const;
+  void SetMapIteratorValue(MapIterator* map_iter) const;
+};
+
+}  // namespace internal
+
+class LIBPROTOBUF_EXPORT MapIterator {
+ public:
+  MapIterator(Message* message, const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    map_ = reflection->MapData(message, field);
+    key_.SetType(field->message_type()->FindFieldByName("key")->cpp_type());
+    value_.SetType(field->message_type()->FindFieldByName("value")->cpp_type());
+    map_->InitializeIterator(this);
+  }
+  MapIterator(const MapIterator& other) {
+    map_ = other.map_;
+    map_->InitializeIterator(this);
+    map_->CopyIterator(this, other);
+  }
+  ~MapIterator() {
+    map_->DeleteIterator(this);
+  }
+  friend bool operator==(const MapIterator& a, const MapIterator& b) {
+    return a.map_->EqualIterator(a, b);
+  }
+  friend bool operator!=(const MapIterator& a, const MapIterator& b) {
+    return !a.map_->EqualIterator(a, b);
+  }
+  MapIterator& operator++() {
+    map_->IncreaseIterator(this);
+    return *this;
+  }
+  MapIterator operator++(int) {
+    // iter_ is copied from Map<...>::iterator, no need to
+    // copy from its self again. Use the same implementation
+    // with operator++()
+    map_->IncreaseIterator(this);
+    return *this;
+  }
+  const MapKey& GetKey() {
+    return key_;
+  }
+  const MapValueRef& GetValueRef() {
+    return value_;
+  }
+  MapValueRef* MutableValueRef() {
+    map_->SetMapDirty();
+    return &value_;
+  }
+
+ private:
+  template <typename Key, typename T>
+  friend class internal::TypeDefinedMapFieldBase;
+  friend class internal::DynamicMapField;
+  template <typename Key, typename T,
+            internal::WireFormatLite::FieldType kKeyFieldType,
+            internal::WireFormatLite::FieldType kValueFieldType,
+            int default_enum_value>
+  friend class internal::MapField;
+
+  // reinterpret_cast from heap-allocated Map<...>::iterator*. MapIterator owns
+  // the iterator. It is allocated by MapField<...>::InitializeIterator() called
+  // in constructor and deleted by MapField<...>::DeleteIterator() called in
+  // destructor.
+  void* iter_;
+  // Point to a MapField to call helper methods implemented in MapField.
+  // MapIterator does not own this object.
+  internal::MapFieldBase* map_;
+  MapKey key_;
+  MapValueRef value_;
+};
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_H__
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
new file mode 100644
index 0000000..01c9b89
--- /dev/null
+++ b/src/google/protobuf/map_field_inl.h
@@ -0,0 +1,489 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map_type_handler.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// UnwrapMapKey template
+template<typename T>
+T UnwrapMapKey(const MapKey& map_key);
+template<>
+inline int32 UnwrapMapKey<int32>(const MapKey& map_key) {
+  return map_key.GetInt32Value();
+}
+template<>
+inline uint32 UnwrapMapKey<uint32>(const MapKey& map_key) {
+  return map_key.GetUInt32Value();
+}
+template<>
+inline int64 UnwrapMapKey<int64>(const MapKey& map_key) {
+  return map_key.GetInt64Value();
+}
+template<>
+inline uint64 UnwrapMapKey<uint64>(const MapKey& map_key) {
+  return map_key.GetUInt64Value();
+}
+template<>
+inline bool UnwrapMapKey<bool>(const MapKey& map_key) {
+  return map_key.GetBoolValue();
+}
+template<>
+inline string UnwrapMapKey<string>(const MapKey& map_key) {
+  return map_key.GetStringValue();
+}
+
+// SetMapKey template
+template<typename T>
+inline void SetMapKey(MapKey* map_key, const T& value);
+template<>
+inline void SetMapKey<int32>(MapKey* map_key, const int32& value) {
+  map_key->SetInt32Value(value);
+}
+template<>
+inline void SetMapKey<uint32>(MapKey* map_key, const uint32& value) {
+  map_key->SetUInt32Value(value);
+}
+template<>
+inline void SetMapKey<int64>(MapKey* map_key, const int64& value) {
+  map_key->SetInt64Value(value);
+}
+template<>
+inline void SetMapKey<uint64>(MapKey* map_key, const uint64& value) {
+  map_key->SetUInt64Value(value);
+}
+template<>
+inline void SetMapKey<bool>(MapKey* map_key, const bool& value) {
+  map_key->SetBoolValue(value);
+}
+template<>
+inline void SetMapKey<string>(MapKey* map_key, const string& value) {
+  map_key->SetStringValue(value);
+}
+
+// ------------------------TypeDefinedMapFieldBase---------------
+template <typename Key, typename T>
+typename Map<Key, T>::const_iterator&
+TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(
+    const MapIterator* map_iter) const {
+  return *reinterpret_cast<typename Map<Key, T>::const_iterator *>(
+      map_iter->iter_);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::MapBegin(MapIterator* map_iter) const {
+  InternalGetIterator(map_iter) = GetMap().begin();
+  SetMapIteratorValue(map_iter);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::MapEnd(MapIterator* map_iter) const {
+  InternalGetIterator(map_iter) = GetMap().end();
+}
+
+template <typename Key, typename T>
+bool TypeDefinedMapFieldBase<Key, T>::EqualIterator(const MapIterator& a,
+                                                    const MapIterator& b)
+    const {
+  return InternalGetIterator(&a) == InternalGetIterator(&b);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::IncreaseIterator(MapIterator* map_iter)
+    const {
+  ++InternalGetIterator(map_iter);
+  SetMapIteratorValue(map_iter);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::InitializeIterator(
+    MapIterator* map_iter) const {
+  map_iter->iter_ = new typename Map<Key, T>::const_iterator;
+  GOOGLE_CHECK(map_iter->iter_ != NULL);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::DeleteIterator(MapIterator* map_iter)
+    const {
+  delete reinterpret_cast<typename Map<Key, T>::const_iterator *>(
+      map_iter->iter_);
+}
+
+template <typename Key, typename T>
+void TypeDefinedMapFieldBase<Key, T>::CopyIterator(
+    MapIterator* this_iter,
+    const MapIterator& that_iter) const {
+  InternalGetIterator(this_iter) = InternalGetIterator(&that_iter);
+  this_iter->key_.SetType(that_iter.key_.type());
+  // MapValueRef::type() fails when containing data is null. However, if
+  // this_iter points to MapEnd, data can be null.
+  this_iter->value_.SetType(
+      static_cast<FieldDescriptor::CppType>(that_iter.value_.type_));
+  SetMapIteratorValue(this_iter);
+}
+
+// ----------------------------------------------------------------------
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField()
+    : default_entry_(NULL) {}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+    Arena* arena)
+    : TypeDefinedMapFieldBase<Key, T>(arena),
+      MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
+          arena),
+      default_entry_(NULL) {}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+    const Message* default_entry)
+    : default_entry_(down_cast<const EntryType*>(default_entry)) {}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField(
+    Arena* arena, const Message* default_entry)
+    : TypeDefinedMapFieldBase<Key, T>(arena),
+      MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>(
+          arena),
+      default_entry_(down_cast<const EntryType*>(default_entry)) {}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::~MapField() {}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+int
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::size() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return MapFieldLiteType::GetInternalMap().size();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::Clear() {
+  MapFieldBase::SyncMapWithRepeatedField();
+  MapFieldLiteType::MutableInternalMap()->clear();
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void MapField<Key, T, kKeyFieldType, kValueFieldType,
+              default_enum_value>::SetMapIteratorValue(
+                  MapIterator* map_iter) const {
+  const Map<Key, T>& map = GetMap();
+  typename Map<Key, T>::const_iterator iter =
+      TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(map_iter);
+  if (iter == map.end()) return;
+  SetMapKey(&map_iter->key_, iter->first);
+  map_iter->value_.SetValue(&iter->second);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+bool MapField<Key, T, kKeyFieldType, kValueFieldType,
+              default_enum_value>::ContainsMapKey(
+                  const MapKey& map_key) const {
+  const Map<Key, T>& map = GetMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::const_iterator iter = map.find(key);
+  return iter != map.end();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+bool MapField<Key, T, kKeyFieldType, kValueFieldType,
+              default_enum_value>::InsertOrLookupMapValue(
+                  const MapKey& map_key,
+                  MapValueRef* val) {
+  // Always use mutable map because users may change the map value by
+  // MapValueRef.
+  Map<Key, T>* map = MutableMap();
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  typename Map<Key, T>::iterator iter = map->find(key);
+  if (map->end() == iter) {
+    val->SetValue(&((*map)[key]));
+    return true;
+  }
+  // Key is already in the map. Make sure (*map)[key] is not called.
+  // [] may reorder the map and iterators.
+  val->SetValue(&(iter->second));
+  return false;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+bool MapField<Key, T, kKeyFieldType, kValueFieldType,
+              default_enum_value>::DeleteMapValue(
+                  const MapKey& map_key) {
+  const Key& key = UnwrapMapKey<Key>(map_key);
+  return MutableMap()->erase(key);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+const Map<Key, T>&
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::GetMap() const {
+  MapFieldBase::SyncMapWithRepeatedField();
+  return MapFieldLiteType::GetInternalMap();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+Map<Key, T>*
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::MutableMap() {
+  MapFieldBase::SyncMapWithRepeatedField();
+  Map<Key, T>* result = MapFieldLiteType::MutableInternalMap();
+  MapFieldBase::SetMapDirty();
+  return result;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::MergeFrom(
+    const MapFieldLiteType& other) {
+  const MapField& down_other = down_cast<const MapField&>(other);
+  MapFieldBase::SyncMapWithRepeatedField();
+  down_other.SyncMapWithRepeatedField();
+  MapFieldLiteType::MergeFrom(other);
+  MapFieldBase::SetMapDirty();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::Swap(
+    MapFieldLiteType* other) {
+  MapField* down_other = down_cast<MapField*>(other);
+  std::swap(MapFieldBase::repeated_field_, down_other->repeated_field_);
+  MapFieldLiteType::Swap(other);
+  std::swap(MapFieldBase::state_, down_other->state_);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::SetEntryDescriptor(
+    const Descriptor** descriptor) {
+  MapFieldBase::entry_descriptor_ = descriptor;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::SetAssignDescriptorCallback(void (*callback)()) {
+  MapFieldBase::assign_descriptor_callback_ = callback;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+const Map<Key, T>&
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::GetInternalMap() const {
+  return MapFieldLiteType::GetInternalMap();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+Map<Key, T>*
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::MutableInternalMap() {
+  return MapFieldLiteType::MutableInternalMap();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::SyncRepeatedFieldWithMapNoLock() const {
+  if (MapFieldBase::repeated_field_ == NULL) {
+    if (MapFieldBase::arena_ == NULL) {
+      MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>();
+    } else {
+      MapFieldBase::repeated_field_ =
+          Arena::CreateMessage<RepeatedPtrField<Message> >(
+              MapFieldBase::arena_);
+    }
+  }
+  const Map<Key, T>& map = GetInternalMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          MapFieldBase::repeated_field_);
+
+  repeated_field->Clear();
+
+  for (typename Map<Key, T>::const_iterator it = map.begin();
+       it != map.end(); ++it) {
+    InitDefaultEntryOnce();
+    GOOGLE_CHECK(default_entry_ != NULL);
+    EntryType* new_entry =
+        down_cast<EntryType*>(default_entry_->New(MapFieldBase::arena_));
+    repeated_field->AddAllocated(new_entry);
+    (*new_entry->mutable_key()) = it->first;
+    (*new_entry->mutable_value()) = it->second;
+  }
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::SyncMapWithRepeatedFieldNoLock() const {
+  Map<Key, T>* map = const_cast<MapField*>(this)->MutableInternalMap();
+  RepeatedPtrField<EntryType>* repeated_field =
+      reinterpret_cast<RepeatedPtrField<EntryType>*>(
+          MapFieldBase::repeated_field_);
+  GOOGLE_CHECK(MapFieldBase::repeated_field_ != NULL);
+  map->clear();
+  for (typename RepeatedPtrField<EntryType>::iterator it =
+           repeated_field->begin(); it != repeated_field->end(); ++it) {
+    // Cast is needed because Map's api and internal storage is different when
+    // value is enum. For enum, we cannot cast an int to enum. Thus, we have to
+    // copy value. For other types, they have same exposed api type and internal
+    // stored type. We should not introduce value copy for them. We achieve this
+    // by casting to value for enum while casting to reference for other types.
+    (*map)[it->key()] = static_cast<CastValueType>(it->value());
+  }
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+int
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::SpaceUsedExcludingSelfNoLock() const {
+  int size = 0;
+  if (MapFieldBase::repeated_field_ != NULL) {
+    size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelf();
+  }
+  Map<Key, T>* map = const_cast<MapField*>(this)->MutableInternalMap();
+  size += sizeof(*map);
+  for (typename Map<Key, T>::iterator it = map->begin();
+       it != map->end(); ++it) {
+    size += KeyTypeHandler::SpaceUsedInMap(it->first);
+    size += ValueTypeHandler::SpaceUsedInMap(it->second);
+  }
+  return size;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType,
+          int default_enum_value>
+void
+MapField<Key, T, kKeyFieldType, kValueFieldType,
+         default_enum_value>::InitDefaultEntryOnce()
+    const {
+  if (default_entry_ == NULL) {
+    MapFieldBase::InitMetadataOnce();
+    GOOGLE_CHECK(*MapFieldBase::entry_descriptor_ != NULL);
+    default_entry_ = down_cast<const EntryType*>(
+        MessageFactory::generated_factory()->GetPrototype(
+            *MapFieldBase::entry_descriptor_));
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
new file mode 100644
index 0000000..860dae5
--- /dev/null
+++ b/src/google/protobuf/map_field_lite.h
@@ -0,0 +1,278 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
+
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_entry_lite.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This class provides accesss to map field using generated api. It is used for
+// internal generated message implentation only. Users should never use this
+// directly.
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value = 0>
+class MapFieldLite {
+  // Define message type for internal repeated field.
+  typedef MapEntryLite<Key, T, key_wire_type, value_wire_type,
+                       default_enum_value> EntryType;
+
+ public:
+  MapFieldLite();
+  explicit MapFieldLite(Arena* arena);
+  virtual ~MapFieldLite();
+
+  // Accessors
+  virtual const Map<Key, T>& GetMap() const;
+  virtual Map<Key, T>* MutableMap();
+
+  // Convenient methods for generated message implementation.
+  virtual int size() const;
+  virtual void Clear();
+  virtual void MergeFrom(const MapFieldLite& other);
+  virtual void Swap(MapFieldLite* other);
+
+  // Set default enum value only for proto2 map field whose value is enum type.
+  void SetDefaultEnumValue();
+
+  // Used in the implementation of parsing. Caller should take the ownership.
+  EntryType* NewEntry() const;
+  // Used in the implementation of serializing enum value type. Caller should
+  // take the ownership.
+  EntryType* NewEnumEntryWrapper(const Key& key, const T t) const;
+  // Used in the implementation of serializing other value types. Caller should
+  // take the ownership.
+  EntryType* NewEntryWrapper(const Key& key, const T& t) const;
+
+ protected:
+  // Convenient methods to get internal google::protobuf::Map
+  virtual const Map<Key, T>& GetInternalMap() const;
+  virtual Map<Key, T>* MutableInternalMap();
+
+ private:
+  typedef void DestructorSkippable_;
+
+  Arena* arena_;
+  Map<Key, T>* map_;
+
+  friend class ::google::protobuf::Arena;
+};
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::MapFieldLite()
+    : arena_(NULL) {
+  map_ = new Map<Key, T>;
+  SetDefaultEnumValue();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::MapFieldLite(Arena* arena)
+  : arena_(arena) {
+  map_ = Arena::CreateMessage<Map<Key, T> >(arena);
+  SetDefaultEnumValue();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::~MapFieldLite() {
+  delete map_;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+const Map<Key, T>&
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::GetMap() const {
+  return *map_;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+Map<Key, T>*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::MutableMap() {
+  return map_;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+int
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::size() const {
+  return map_->size();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::Clear() {
+  map_->clear();
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::MergeFrom(
+    const MapFieldLite& other) {
+  for (typename Map<Key, T>::const_iterator it = other.map_->begin();
+       it != other.map_->end(); ++it) {
+    (*map_)[it->first] = it->second;
+  }
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::Swap(
+    MapFieldLite* other) {
+  std::swap(map_, other->map_);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+void
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::SetDefaultEnumValue() {
+  MutableInternalMap()->SetDefaultEnumValue(default_enum_value);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+const Map<Key, T>&
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::GetInternalMap() const {
+  return *map_;
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+Map<Key, T>*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::MutableInternalMap() {
+  return map_;
+}
+
+#define EntryType \
+  MapEntryLite<Key, T, key_wire_type, value_wire_type, default_enum_value>
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::NewEntry() const {
+  if (arena_ == NULL) {
+    return new EntryType();
+  } else {
+    return Arena::CreateMessage<EntryType>(arena_);
+  }
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::NewEnumEntryWrapper(const Key& key,
+                                                      const T t) const {
+  return EntryType::EnumWrap(key, t, arena_);
+}
+
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+EntryType*
+MapFieldLite<Key, T, key_wire_type, value_wire_type,
+             default_enum_value>::NewEntryWrapper(const Key& key,
+                                                  const T& t) const {
+  return EntryType::Wrap(key, t, arena_);
+}
+
+#undef EntryType
+
+// True if IsInitialized() is true for value field in all elements of t. T is
+// expected to be message.  It's useful to have this helper here to keep the
+// protobuf compiler from ever having to emit loops in IsInitialized() methods.
+// We want the C++ compiler to inline this or not as it sees fit.
+template <typename Key, typename T>
+bool AllAreInitialized(const Map<Key, T>& t) {
+  for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
+       ++it) {
+    if (!it->second.IsInitialized()) return false;
+  }
+  return true;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
new file mode 100644
index 0000000..223d42f
--- /dev/null
+++ b/src/google/protobuf/map_field_test.cc
@@ -0,0 +1,494 @@
+// 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.
+
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace internal {
+
+using unittest::TestAllTypes;
+
+class MapFieldBaseStub : public MapFieldBase {
+ public:
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  MapFieldBaseStub() {}
+  explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
+  void SyncRepeatedFieldWithMap() const {
+    MapFieldBase::SyncRepeatedFieldWithMap();
+  }
+  void SyncMapWithRepeatedField() const {
+    MapFieldBase::SyncMapWithRepeatedField();
+  }
+  // Get underlined repeated field without synchronizing map.
+  RepeatedPtrField<Message>* InternalRepeatedField() {
+    return repeated_field_;
+  }
+  bool IsMapClean() { return state_ != 0; }
+  bool IsRepeatedClean() { return state_ != 1; }
+  void SetMapDirty() { state_ = 0; }
+  void SetRepeatedDirty() { state_ = 1; }
+  bool ContainsMapKey(const MapKey& map_key) const {
+    return false;
+  }
+  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) {
+    return false;
+  }
+  bool DeleteMapValue(const MapKey& map_key) {
+    return false;
+  }
+  bool EqualIterator(const MapIterator& a, const MapIterator& b) const {
+    return false;
+  }
+  int size() const { return 0; }
+  void MapBegin(MapIterator* map_iter) const {}
+  void MapEnd(MapIterator* map_iter) const {}
+  void InitializeIterator(MapIterator* map_iter) const {}
+  void DeleteIterator(MapIterator* map_iter) const {}
+  void CopyIterator(MapIterator* this_iterator,
+                    const MapIterator& other_iterator) const {}
+  void IncreaseIterator(MapIterator* map_iter) const {}
+  void SetDefaultMessageEntry(const Message* message) const {}
+  const Message* GetDefaultMessageEntry() const { return NULL; }
+};
+
+class MapFieldBasePrimitiveTest : public ::testing::Test {
+ protected:
+  typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
+                   WireFormatLite::TYPE_INT32, false> MapFieldType;
+
+  MapFieldBasePrimitiveTest() {
+    // Get descriptors
+    map_descriptor_ = unittest::TestMap::descriptor()
+                          ->FindFieldByName("map_int32_int32")
+                          ->message_type();
+    key_descriptor_ = map_descriptor_->FindFieldByName("key");
+    value_descriptor_ = map_descriptor_->FindFieldByName("value");
+
+    // Build map field
+    default_entry_ =
+        MessageFactory::generated_factory()->GetPrototype(map_descriptor_);
+    map_field_.reset(new MapFieldType(default_entry_));
+    map_field_base_ = map_field_.get();
+    map_ = map_field_->MutableMap();
+    initial_value_map_[0] = 100;
+    initial_value_map_[1] = 101;
+    map_->insert(initial_value_map_.begin(), initial_value_map_.end());
+    EXPECT_EQ(2, map_->size());
+  }
+
+  google::protobuf::scoped_ptr<MapFieldType> map_field_;
+  MapFieldBase* map_field_base_;
+  Map<int32, int32>* map_;
+  const Descriptor* map_descriptor_;
+  const FieldDescriptor* key_descriptor_;
+  const FieldDescriptor* value_descriptor_;
+  const Message* default_entry_;
+  std::map<int32, int32> initial_value_map_;  // copy of initial values inserted
+};
+
+TEST_F(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
+  EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
+}
+
+TEST_F(MapFieldBasePrimitiveTest, GetRepeatedField) {
+  const RepeatedPtrField<Message>& repeated =
+      reinterpret_cast<const RepeatedPtrField<Message>&>(
+          map_field_base_->GetRepeatedField());
+  EXPECT_EQ(2, repeated.size());
+  for (int i = 0; i < repeated.size(); i++) {
+    const Message& message = repeated.Get(i);
+    int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+    int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+    EXPECT_EQ(value, initial_value_map_[key]);
+  }
+}
+
+TEST_F(MapFieldBasePrimitiveTest, MutableRepeatedField) {
+  RepeatedPtrField<Message>* repeated =
+      reinterpret_cast<RepeatedPtrField<Message>*>(
+          map_field_base_->MutableRepeatedField());
+  EXPECT_EQ(2, repeated->size());
+  for (int i = 0; i < repeated->size(); i++) {
+    const Message& message = repeated->Get(i);
+    int key = message.GetReflection()->GetInt32(message, key_descriptor_);
+    int value = message.GetReflection()->GetInt32(message, value_descriptor_);
+    EXPECT_EQ(value, initial_value_map_[key]);
+  }
+}
+
+TEST_F(MapFieldBasePrimitiveTest, Arena) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  {
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
+
+    MapFieldType* map_field =
+        Arena::CreateMessage<MapFieldType>(&arena, default_entry_);
+
+    // Set content in map
+    (*map_field->MutableMap())[100] = 101;
+
+    // Trigger conversion to repeated field.
+    map_field->GetRepeatedField();
+  }
+
+  {
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
+
+    MapFieldBaseStub* map_field =
+        Arena::CreateMessage<MapFieldBaseStub>(&arena);
+
+    // Trigger conversion to repeated field.
+    EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
+  }
+}
+
+namespace {
+enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
+}  // anonymous namespace
+
+class MapFieldStateTest
+    : public testing::TestWithParam<State> {
+ public:
+ protected:
+  typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
+                   WireFormatLite::TYPE_INT32, false> MapFieldType;
+  typedef MapFieldLite<int32, int32, WireFormatLite::TYPE_INT32,
+                       WireFormatLite::TYPE_INT32, false> MapFieldLiteType;
+  MapFieldStateTest() : state_(GetParam()) {
+    // Build map field
+    const Descriptor* map_descriptor =
+        unittest::TestMap::descriptor()
+            ->FindFieldByName("map_int32_int32")
+            ->message_type();
+    default_entry_ =
+        MessageFactory::generated_factory()->GetPrototype(map_descriptor);
+    map_field_.reset(new MapFieldType(default_entry_));
+    map_field_base_ = map_field_.get();
+
+    Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+    switch (state_) {
+      case CLEAN:
+        AddOneStillClean(map_field_.get());
+        break;
+      case MAP_DIRTY:
+        MakeMapDirty(map_field_.get());
+        break;
+      case REPEATED_DIRTY:
+        MakeRepeatedDirty(map_field_.get());
+        break;
+      default:
+        break;
+    }
+  }
+
+  void AddOneStillClean(MapFieldType* map_field) {
+    MapFieldBase* map_field_base = map_field;
+    Map<int32, int32>* map = map_field->MutableMap();
+    (*map)[0] = 0;
+    map_field_base->GetRepeatedField();
+    Expect(map_field, CLEAN, 1, 1, false);
+  }
+
+  void MakeMapDirty(MapFieldType* map_field) {
+    Map<int32, int32>* map = map_field->MutableMap();
+    (*map)[0] = 0;
+    Expect(map_field, MAP_DIRTY, 1, 0, true);
+  }
+
+  void MakeRepeatedDirty(MapFieldType* map_field) {
+    MakeMapDirty(map_field);
+    MapFieldBase* map_field_base = map_field;
+    map_field_base->MutableRepeatedField();
+    Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
+                                 ->MapFieldLiteType::MutableMap();
+    map->clear();
+
+    Expect(map_field, REPEATED_DIRTY, 0, 1, false);
+  }
+
+  void Expect(MapFieldType* map_field, State state, int map_size,
+              int repeated_size, bool is_repeated_null) {
+    MapFieldBase* map_field_base = map_field;
+    MapFieldBaseStub* stub =
+        reinterpret_cast<MapFieldBaseStub*>(map_field_base);
+
+    Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
+                                 ->MapFieldLiteType::MutableMap();
+    RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
+
+    switch (state) {
+      case MAP_DIRTY:
+        EXPECT_FALSE(stub->IsMapClean());
+        EXPECT_TRUE(stub->IsRepeatedClean());
+        break;
+      case REPEATED_DIRTY:
+        EXPECT_TRUE(stub->IsMapClean());
+        EXPECT_FALSE(stub->IsRepeatedClean());
+        break;
+      case CLEAN:
+        EXPECT_TRUE(stub->IsMapClean());
+        EXPECT_TRUE(stub->IsRepeatedClean());
+        break;
+      default:
+        FAIL();
+    }
+
+    EXPECT_EQ(map_size, map->size());
+    if (is_repeated_null) {
+      EXPECT_TRUE(repeated_field == NULL);
+    } else {
+      EXPECT_EQ(repeated_size, repeated_field->size());
+    }
+  }
+
+  google::protobuf::scoped_ptr<MapFieldType> map_field_;
+  MapFieldBase* map_field_base_;
+  State state_;
+  const Message* default_entry_;
+};
+
+INSTANTIATE_TEST_CASE_P(MapFieldStateTestInstance, MapFieldStateTest,
+                        ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
+
+TEST_P(MapFieldStateTest, GetMap) {
+  map_field_->GetMap();
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), CLEAN, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+}
+
+TEST_P(MapFieldStateTest, MutableMap) {
+  map_field_->MutableMap();
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+}
+
+TEST_P(MapFieldStateTest, MergeFromClean) {
+  MapFieldType other(default_entry_);
+  AddOneStillClean(&other);
+
+  map_field_->MergeFrom(other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(&other, CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, MergeFromMapDirty) {
+  MapFieldType other(default_entry_);
+  MakeMapDirty(&other);
+
+  map_field_->MergeFrom(other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(&other, MAP_DIRTY, 1, 0, true);
+}
+
+TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
+  MapFieldType other(default_entry_);
+  MakeRepeatedDirty(&other);
+
+  map_field_->MergeFrom(other);
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+  }
+
+  Expect(&other, CLEAN, 1, 1, false);
+}
+
+TEST_P(MapFieldStateTest, SwapClean) {
+  MapFieldType other(default_entry_);
+  AddOneStillClean(&other);
+
+  map_field_->Swap(&other);
+
+  Expect(map_field_.get(), CLEAN, 1, 1, false);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(&other, CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(&other, MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(&other, REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, SwapMapDirty) {
+  MapFieldType other(default_entry_);
+  MakeMapDirty(&other);
+
+  map_field_->Swap(&other);
+
+  Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(&other, CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(&other, MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(&other, REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
+  MapFieldType other(default_entry_);
+  MakeRepeatedDirty(&other);
+
+  map_field_->Swap(&other);
+
+  Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+
+  switch (state_) {
+    case CLEAN:
+      Expect(&other, CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(&other, MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(&other, REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, Clear) {
+  map_field_->Clear();
+
+  if (state_ != MAP_DIRTY) {
+    Expect(map_field_.get(), MAP_DIRTY, 0, 1, false);
+  } else {
+    Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
+  }
+}
+
+TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
+  map_field_base_->SpaceUsedExcludingSelf();
+
+  switch (state_) {
+    case CLEAN:
+      Expect(map_field_.get(), CLEAN, 1, 1, false);
+      break;
+    case MAP_DIRTY:
+      Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
+      break;
+    case REPEATED_DIRTY:
+      Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+      break;
+    default:
+      break;
+  }
+}
+
+TEST_P(MapFieldStateTest, GetMapField) {
+  map_field_base_->GetRepeatedField();
+
+  if (state_ != REPEATED_DIRTY) {
+    Expect(map_field_.get(), CLEAN, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+  }
+}
+
+TEST_P(MapFieldStateTest, MutableMapField) {
+  map_field_base_->MutableRepeatedField();
+
+  if (state_ != REPEATED_DIRTY) {
+    Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
+  } else {
+    Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
+  }
+}
+
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.cc b/src/google/protobuf/map_lite_test_util.cc
new file mode 100644
index 0000000..b65b4d6
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.cc
@@ -0,0 +1,93 @@
+// 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.
+
+#include <google/protobuf/map_lite_test_util.h>
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/map_test_util_impl.h>
+
+namespace google {
+namespace protobuf {
+
+void MapLiteTestUtil::SetMapFields(unittest::TestMapLite* message) {
+  MapTestUtilImpl::SetMapFields<unittest::MapEnumLite,
+                                unittest::MAP_ENUM_BAR_LITE,
+                                unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetArenaMapFields(unittest::TestArenaMapLite* message) {
+  MapTestUtilImpl::SetArenaMapFields<unittest::MapEnumLite,
+                                     unittest::MAP_ENUM_BAR_LITE,
+                                     unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::SetMapFieldsInitialized(unittest::TestMapLite* message) {
+  MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+void MapLiteTestUtil::ModifyMapFields(unittest::TestMapLite* message) {
+  MapTestUtilImpl::ModifyMapFields<unittest::MapEnumLite,
+                                   unittest::MAP_ENUM_FOO_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectClear(const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectClear(message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSet(const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnumLite,
+                                      unittest::MAP_ENUM_BAR_LITE,
+                                      unittest::MAP_ENUM_BAZ_LITE>(message);
+}
+
+void MapLiteTestUtil::ExpectArenaMapFieldsSet(
+    const unittest::TestArenaMapLite& message) {
+  MapTestUtilImpl::ExpectArenaMapFieldsSet<unittest::MapEnumLite,
+                                           unittest::MAP_ENUM_BAR_LITE,
+                                           unittest::MAP_ENUM_BAZ_LITE>(
+      message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsSetInitialized(
+    const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnumLite,
+                                                 unittest::MAP_ENUM_FOO_LITE>(
+      message);
+}
+
+void MapLiteTestUtil::ExpectMapFieldsModified(
+    const unittest::TestMapLite& message) {
+  MapTestUtilImpl::ExpectMapFieldsModified<unittest::MapEnumLite,
+                                           unittest::MAP_ENUM_BAR_LITE,
+                                           unittest::MAP_ENUM_FOO_LITE>(
+      message);
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
new file mode 100644
index 0000000..66dedde
--- /dev/null
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
+
+#include <google/protobuf/map_lite_unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+class MapLiteTestUtil {
+ public:
+  // Set every field in the TestMapLite message to a unique value.
+  static void SetMapFields(protobuf_unittest::TestMapLite* message);
+
+  // Set every field in the TestArenaMapLite message to a unique value.
+  static void SetArenaMapFields(protobuf_unittest::TestArenaMapLite* message);
+
+  // Set every field in the message to a default value.
+  static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  static void ExpectMapFieldsSet(const protobuf_unittest::TestMapLite& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMapLite.
+  static void ExpectArenaMapFieldsSet(
+      const protobuf_unittest::TestArenaMapLite& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  static void ExpectMapFieldsSetInitialized(
+      const protobuf_unittest::TestMapLite& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  static void ExpectMapFieldsModified(
+      const protobuf_unittest::TestMapLite& message);
+
+  // Check that all fields are empty.
+  static void ExpectClear(const protobuf_unittest::TestMapLite& message);
+};
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_LITE_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto
new file mode 100644
index 0000000..0592dd7
--- /dev/null
+++ b/src/google/protobuf/map_lite_unittest.proto
@@ -0,0 +1,130 @@
+// 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.
+
+syntax = "proto2";
+
+option cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+
+import "google/protobuf/unittest_lite.proto";
+import "google/protobuf/unittest_no_arena_lite.proto";
+
+package protobuf_unittest;
+
+message TestMapLite {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<string  , string  > map_string_string     = 14;
+  map<int32   , bytes   > map_int32_bytes       = 15;
+  map<int32   , MapEnumLite> map_int32_enum     = 16;
+  map<int32   , ForeignMessageLite> map_int32_foreign_message = 17;
+  map<int32, int32> teboring = 18;
+}
+
+message TestArenaMapLite {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<string  , string  > map_string_string     = 14;
+  map<int32   , bytes   > map_int32_bytes       = 15;
+  map<int32   , MapEnumLite> map_int32_enum     = 16;
+  map<int32   , ForeignMessageArenaLite> map_int32_foreign_message = 17;
+  map<int32, .protobuf_unittest_no_arena.ForeignMessageLite>
+      map_int32_foreign_message_no_arena = 18;
+}
+
+// Test embeded message with required fields
+message TestRequiredMessageMapLite {
+  map<int32, TestRequiredLite> map_field = 1;
+}
+
+message TestEnumMapLite {
+  map<int32, Proto2MapEnumLite> known_map_field = 101;
+  map<int32, Proto2MapEnumLite> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtraLite {
+  map<int32, Proto2MapEnumPlusExtraLite> known_map_field = 101;
+  map<int32, Proto2MapEnumPlusExtraLite> unknown_map_field = 102;
+}
+
+message TestMessageMapLite {
+  map<int32, TestAllTypesLite> map_int32_message = 1;
+}
+
+enum Proto2MapEnumLite {
+  PROTO2_MAP_ENUM_FOO_LITE = 0;
+  PROTO2_MAP_ENUM_BAR_LITE = 1;
+  PROTO2_MAP_ENUM_BAZ_LITE = 2;
+}
+
+enum Proto2MapEnumPlusExtraLite {
+  E_PROTO2_MAP_ENUM_FOO_LITE   = 0;
+  E_PROTO2_MAP_ENUM_BAR_LITE   = 1;
+  E_PROTO2_MAP_ENUM_BAZ_LITE   = 2;
+  E_PROTO2_MAP_ENUM_EXTRA_LITE = 3;
+}
+
+enum MapEnumLite {
+  MAP_ENUM_FOO_LITE = 0;
+  MAP_ENUM_BAR_LITE = 1;
+  MAP_ENUM_BAZ_LITE = 2;
+}
+
+message TestRequiredLite {
+  required int32 a = 1;
+  required int32 b = 2;
+  required int32 c = 3;
+}
+
+message ForeignMessageArenaLite {
+  optional int32 c = 1;
+}
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
new file mode 100644
index 0000000..916cc54
--- /dev/null
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -0,0 +1,66 @@
+// 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.
+
+syntax = "proto2";
+
+
+import "google/protobuf/unittest_import.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+enum Proto2MapEnum {
+  PROTO2_MAP_ENUM_FOO   = 0;
+  PROTO2_MAP_ENUM_BAR   = 1;
+  PROTO2_MAP_ENUM_BAZ   = 2;
+}
+
+enum Proto2MapEnumPlusExtra {
+  E_PROTO2_MAP_ENUM_FOO   = 0;
+  E_PROTO2_MAP_ENUM_BAR   = 1;
+  E_PROTO2_MAP_ENUM_BAZ   = 2;
+  E_PROTO2_MAP_ENUM_EXTRA = 3;
+}
+
+message TestEnumMap {
+  map<int32, Proto2MapEnum> known_map_field = 101;
+  map<int32, Proto2MapEnum> unknown_map_field = 102;
+}
+
+message TestEnumMapPlusExtra {
+  map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
+  map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
+}
+
+message TestImportEnumMap {
+  map<int32, protobuf_unittest_import.ImportEnumForMap> import_enum_amp = 1;
+}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
new file mode 100644
index 0000000..9d4d6c1
--- /dev/null
+++ b/src/google/protobuf/map_test.cc
@@ -0,0 +1,2788 @@
+// 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.
+
+// A hack to include windows.h first, which ensures the GetMessage macro can
+// be undefined when we include <google/protobuf/stubs/common.h>
+#if defined(_WIN32)
+#define _WINSOCKAPI_  // to avoid re-definition in WinSock2.h
+#define NOMINMAX      // to avoid defining min/max macros
+#include <windows.h>
+#endif  // _WIN32
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <set>
+#include <sstream>
+#include <vector>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_proto2_unittest.pb.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/util/time_util.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+
+using google::protobuf::unittest::ForeignMessage;
+using google::protobuf::unittest::TestAllTypes;
+using google::protobuf::unittest::TestMap;
+using google::protobuf::unittest::TestRecursiveMapMessage;
+
+namespace protobuf {
+namespace internal {
+
+// Map API Test =====================================================
+
+// Parameterized tests on whether to use old style maps.
+class MapImplTest : public testing::TestWithParam<bool> {
+ protected:
+  MapImplTest()
+      : map_ptr_(new Map<int32, int32>(GetParam())),
+        map_(*map_ptr_),
+        const_map_(*map_ptr_) {
+    EXPECT_TRUE(map_.empty());
+    EXPECT_EQ(0, map_.size());
+  }
+  ~MapImplTest() {}
+
+  void ExpectSingleElement(int32 key, int32 value) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(1, map_.size());
+    ExpectElement(key, value);
+  }
+
+  void ExpectElements(const std::map<int32, int32>& map) {
+    EXPECT_FALSE(map_.empty());
+    EXPECT_EQ(map.size(), map_.size());
+    for (std::map<int32, int32>::const_iterator it = map.begin();
+         it != map.end(); ++it) {
+      ExpectElement(it->first, it->second);
+    }
+  }
+
+  void ExpectElement(int32 key, int32 value) {
+    // Test map size is correct.
+    EXPECT_EQ(value, map_[key]);
+    EXPECT_EQ(1, map_.count(key));
+
+    // Check mutable at and find work correctly.
+    EXPECT_EQ(value, map_.at(key));
+    Map<int32, int32>::iterator it = map_.find(key);
+
+    // interator dereferenceable
+    EXPECT_EQ(key,   (*it).first);
+    EXPECT_EQ(value, (*it).second);
+    EXPECT_EQ(key,   it->first);
+    EXPECT_EQ(value, it->second);
+
+    // iterator mutable
+    ((*it).second) = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    ((*it).second) = value;
+    EXPECT_EQ(value, map_[key]);
+
+    it->second = value + 1;
+    EXPECT_EQ(value + 1, map_[key]);
+    it->second = value;
+    EXPECT_EQ(value, map_[key]);
+
+    // copy constructor
+    Map<int32, int32>::iterator it_copy = it;
+    EXPECT_EQ(key, it_copy->first);
+    EXPECT_EQ(value, it_copy->second);
+
+    // Immutable API ================================================
+
+    // Check immutable at and find work correctly.
+    EXPECT_EQ(value, const_map_.at(key));
+    Map<int32, int32>::const_iterator const_it = const_map_.find(key);
+
+    // interator dereferenceable
+    EXPECT_EQ(key, (*const_it).first);
+    EXPECT_EQ(value, (*const_it).second);
+    EXPECT_EQ(key, const_it->first);
+    EXPECT_EQ(value, const_it->second);
+
+    // copy constructor
+    Map<int32, int32>::const_iterator const_it_copy = const_it;
+    EXPECT_EQ(key, const_it_copy->first);
+    EXPECT_EQ(value, const_it_copy->second);
+  }
+
+  google::protobuf::scoped_ptr<Map<int32, int32> > map_ptr_;
+  Map<int32, int32>& map_;
+  const Map<int32, int32>& const_map_;
+};
+
+TEST_P(MapImplTest, OperatorBracket) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  EXPECT_EQ(0, map_[key]);
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_[key] = value2;
+  ExpectSingleElement(key, value2);
+}
+
+TEST_P(MapImplTest, OperatorBracketNonExist) {
+  int32 key = 0;
+  int32 default_value = 0;
+
+  EXPECT_EQ(default_value, map_[key]);
+  ExpectSingleElement(key, default_value);
+}
+
+TEST_P(MapImplTest, MutableAt) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  map_[key] = value1;
+  ExpectSingleElement(key, value1);
+
+  map_.at(key) = value2;
+  ExpectSingleElement(key, value2);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+TEST_P(MapImplTest, MutableAtNonExistDeathTest) {
+  EXPECT_DEATH(map_.at(0), "");
+}
+
+TEST_P(MapImplTest, ImmutableAtNonExistDeathTest) {
+  EXPECT_DEATH(const_map_.at(0), "");
+}
+
+TEST_P(MapImplTest, UsageErrors) {
+  MapKey key;
+  key.SetInt64Value(1);
+  EXPECT_DEATH(key.GetUInt64Value(),
+               "Protocol Buffer map usage error:\n"
+               "MapKey::GetUInt64Value type does not match\n"
+               "  Expected : uint64\n"
+               "  Actual   : int64");
+
+  MapValueRef value;
+  EXPECT_DEATH(value.SetFloatValue(0.1),
+               "Protocol Buffer map usage error:\n"
+               "MapValueRef::type MapValueRef is not initialized.");
+}
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST_P(MapImplTest, CountNonExist) {
+  EXPECT_EQ(0, map_.count(0));
+}
+
+TEST_P(MapImplTest, MutableFindNonExist) {
+  EXPECT_TRUE(map_.end() == map_.find(0));
+}
+
+TEST_P(MapImplTest, ImmutableFindNonExist) {
+  EXPECT_TRUE(const_map_.end() == const_map_.find(0));
+}
+
+TEST_P(MapImplTest, ConstEnd) {
+  EXPECT_TRUE(const_map_.end() == const_map_.cend());
+}
+
+TEST_P(MapImplTest, GetReferenceFromIterator) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  for (Map<int32, int32>::const_iterator it = map_.cbegin();
+       it != map_.cend();) {
+    Map<int32, int32>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32, int32>::const_iterator it = const_map_.begin();
+       it != const_map_.end();) {
+    Map<int32, int32>::const_reference entry = *it++;
+    EXPECT_EQ(entry.first, entry.second);
+  }
+
+  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+    Map<int32, int32>::reference entry = *it++;
+    EXPECT_EQ(entry.first + 1, ++entry.second);
+  }
+}
+
+TEST_P(MapImplTest, IteratorBasic) {
+  map_[0] = 0;
+
+  // Default constructible (per forward iterator requirements).
+  Map<int, int>::const_iterator cit;
+  Map<int, int>::iterator it;
+
+  it = map_.begin();
+  cit = it;  // Converts to const_iterator
+
+  // Can compare between them.
+  EXPECT_TRUE(it == cit);
+  EXPECT_FALSE(cit != it);
+
+  // Pre increment.
+  EXPECT_FALSE(it == ++cit);
+
+  // Post increment.
+  EXPECT_FALSE(it++ == cit);
+  EXPECT_TRUE(it == cit);
+}
+
+template <typename Iterator>
+static int64 median(Iterator i0, Iterator i1) {
+  vector<int64> v(i0, i1);
+  std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
+  return v[v.size() / 2];
+}
+
+static int64 Now() {
+  return google::protobuf::util::TimeUtil::TimestampToNanoseconds(
+      google::protobuf::util::TimeUtil::GetCurrentTime());
+}
+
+// Arbitrary odd integers for creating test data.
+static int k0 = 812398771;
+static int k1 = 1312938717;
+static int k2 = 1321555333;
+
+// A naive begin() implementation will cause begin() to get slower and slower
+// if one erases elements at the "front" of the hash map, and we'd like to
+// avoid that, as std::unordered_map does.
+TEST_P(MapImplTest, BeginIsFast) {
+  // Disable this test for both new and old implementations.
+  if (/*GetParam()*/true) return;
+  Map<int32, int32> map(false);  // This test uses new-style maps only.
+  const int kTestSize = 250000;
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  uint32 frog = 123983;
+  int last_key = 0;
+  int counter = 0;
+  while (map.size() < kTestSize) {
+    frog *= static_cast<uint32>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    map[last_key] = last_key ^ 1;
+  }
+  vector<int64> times;
+  // We're going to do map.erase(map.begin()) over and over again.  But,
+  // just in case one iteration is fast compared to the granularity of
+  // our time keeping, we measure kChunkSize iterations per outer-loop iter.
+  const int kChunkSize = 1000;
+  GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
+  do {
+    const int64 start = Now();
+    for (int i = 0; i < kChunkSize; i++) {
+      map.erase(map.begin());
+    }
+    const int64 end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+  } while (!map.empty());
+  if (times.size() < .99 * kTestSize / kChunkSize) {
+    GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
+    return;
+  }
+  int64 x0 = median(times.begin(), times.begin() + 9);
+  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // And we'll probably time out and never get here.  So, this test is
+  // intentionally loose: we check that x0 and x1 are within a factor of 8.
+  EXPECT_GE(x1, x0 / 8);
+  EXPECT_GE(x0, x1 / 8);
+}
+
+// Try to create kTestSize keys that will land in just a few buckets, and
+// time the insertions, to get a rough estimate of whether an O(n^2) worst case
+// was triggered.  This test is a hacky, but probably better than nothing.
+TEST_P(MapImplTest, HashFlood) {
+  const int kTestSize = 1024;  // must be a power of 2
+  std::set<int> s;
+  for (int i = 0; s.size() < kTestSize; i++) {
+    if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) {
+      s.insert(i);
+    }
+  }
+  // Create hash table with kTestSize entries that hash flood a table with
+  // 1024 (or 512 or 2048 or ...) entries.  This assumes that map_ uses powers
+  // of 2 for table sizes, and that it's sufficient to "flood" with respect to
+  // the low bits of the output of map_.hash_function().
+  vector<int64> times;
+  std::set<int>::iterator it = s.begin();
+  int count = 0;
+  do {
+    const int64 start = Now();
+    map_[*it] = 0;
+    const int64 end = Now();
+    if (end > start) {
+      times.push_back(end - start);
+    }
+    ++count;
+    ++it;
+  } while (it != s.end());
+  if (times.size() < .99 * count) return;
+  int64 x0 = median(times.begin(), times.begin() + 9);
+  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
+  // But we want to allow O(n log n).  A factor of 20 should be generous enough.
+  EXPECT_LE(x1, x0 * 20);
+}
+
+template <typename T, typename U>
+static void TestValidityForAllKeysExcept(int key_to_avoid,
+                                         const T& check_map,
+                                         const U& map) {
+  typedef typename U::value_type value_type;  // a key-value pair
+  for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) {
+    const int key = it->first;
+    if (key == key_to_avoid) continue;
+    // All iterators relevant to this key, whether old (from check_map) or new,
+    // must point to the same memory.  So, test pointer equality here.
+    const value_type* check_val = &*check_map.find(key)->second;
+    EXPECT_EQ(check_val, &*it);
+    EXPECT_EQ(check_val, &*map.find(key));
+  }
+}
+
+// EXPECT i0 and i1 to be the same.  Advancing them should have the same effect,
+// too.
+template <typename Iter>
+static void TestEqualIterators(Iter i0, Iter i1, Iter end) {
+  const int kMaxAdvance = 10;
+  for (int i = 0; i < kMaxAdvance; i++) {
+    EXPECT_EQ(i0 == end, i1 == end);
+    if (i0 == end) return;
+    EXPECT_EQ(&*i0, &*i1) << "iter " << i;
+    ++i0;
+    ++i1;
+  }
+}
+
+template <typename IteratorType>
+static void TestOldVersusNewIterator(int skip, Map<int, int>* m) {
+  const int initial_size = m->size();
+  IteratorType it = m->begin();
+  for (int i = 0; i < skip && it != m->end(); it++, i++) {}
+  if (it == m->end()) return;
+  const IteratorType old = it;
+  GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first;
+  const int target_size =
+      initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4;
+  for (int i = 0; m->size() <= target_size; i++) {
+    (*m)[i] = 0;
+  }
+  // Iterator 'old' should still work just fine despite the growth of *m.
+  const IteratorType after_growth = m->find(old->first);
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+
+  // Now shrink the number of elements.  Do this with a mix of erases and
+  // inserts to increase the chance that the hashtable will resize to a lower
+  // number of buckets.  (But, in any case, the test is still useful.)
+  for (int i = 0; i < 2 * (target_size - initial_size); i++) {
+    if (i != old->first) {
+      m->erase(i);
+    }
+    if (((i ^ m->begin()->first) & 15) == 0) {
+      (*m)[i * 342] = i;
+    }
+  }
+  // Now, the table has grown and shrunk; test again.
+  TestEqualIterators<IteratorType>(old, m->find(old->first), m->end());
+  TestEqualIterators<IteratorType>(old, after_growth, m->end());
+}
+
+// Create and test an n-element Map, with emphasis on iterator correctness.
+static void StressTestIterators(int n, bool test_old_style_proto2_maps) {
+  GOOGLE_LOG(INFO) << "StressTestIterators " << n;
+  GOOGLE_CHECK_GT(n, 0);
+  // Create a random-looking map of size n.  Use non-negative integer keys.
+  Map<int, int> m(test_old_style_proto2_maps);
+  uint32 frog = 123987 + n;
+  int last_key = 0;
+  int counter = 0;
+  while (m.size() < n) {
+    frog *= static_cast<uint32>(k0);
+    frog ^= frog >> 17;
+    frog += counter++;
+    last_key =
+        static_cast<int>(frog) >= 0 ? static_cast<int>(frog) : last_key ^ 1;
+    GOOGLE_DCHECK_GE(last_key, 0);
+    m[last_key] = last_key ^ 1;
+  }
+  // Test it.
+  ASSERT_EQ(n, m.size());
+  // Create maps of pointers and iterators.
+  // These should remain valid even if we modify m.
+  hash_map<int, Map<int, int>::value_type*> mp(n);
+  hash_map<int, Map<int, int>::iterator> mi(n);
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    mp[it->first] = &*it;
+    mi[it->first] = it;
+  }
+  ASSERT_EQ(m.size(), mi.size());
+  ASSERT_EQ(m.size(), mp.size());
+  m.erase(last_key);
+  ASSERT_EQ(n - 1, m.size());
+  TestValidityForAllKeysExcept(last_key, mp, m);
+  TestValidityForAllKeysExcept(last_key, mi, m);
+
+  m[last_key] = 0;
+  ASSERT_EQ(n, m.size());
+  // Test old iterator vs new iterator, with table modification in between.
+  TestOldVersusNewIterator<Map<int, int>::const_iterator>(n % 3, &m);
+  TestOldVersusNewIterator<Map<int, int>::iterator>(n % (1 + (n / 40)), &m);
+  // Finally, ensure erase(iterator) doesn't reorder anything, becuase that is
+  // what its documentation says.
+  m[last_key] = m[last_key ^ 999] = 0;
+  vector<Map<int, int>::iterator> v;
+  v.reserve(m.size());
+  int position_of_last_key = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it) {
+    if (it->first == last_key) {
+      position_of_last_key = v.size();
+    }
+    v.push_back(it);
+  }
+  ASSERT_EQ(m.size(), v.size());
+  const Map<int, int>::iterator erase_result = m.erase(m.find(last_key));
+  int index = 0;
+  for (Map<int, int>::iterator it = m.begin(); it != m.end(); ++it, ++index) {
+    if (index == position_of_last_key) {
+      EXPECT_EQ(&*erase_result, &*v[++index]);
+    }
+    ASSERT_EQ(&*it, &*v[index]);
+  }
+}
+
+TEST_P(MapImplTest, IteratorInvalidation) {
+  // As multiple underlying hash_map implementations do not follow the
+  // validation requirement, the test is disabled for old-style maps.
+  if (GetParam()) return;
+  // Create a set of pseudo-random sizes to test.
+#ifndef NDEBUG
+  const int kMaxSizeToTest = 100 * 1000;
+#else
+  const int kMaxSizeToTest = 1000 * 1000;
+#endif
+  std::set<int> s;
+  int n = kMaxSizeToTest;
+  int frog = k1 + n;
+  while (n > 1 && s.size() < 25) {
+    s.insert(n);
+    n = static_cast<int>(n * 100 / (101.0 + (frog & 63)));
+    frog *= k2;
+    frog ^= frog >> 17;
+  }
+  // Ensure we test a few small sizes.
+  s.insert(1);
+  s.insert(2);
+  s.insert(3);
+  // Now, the real work.
+  for (std::set<int>::iterator i = s.begin(); i != s.end(); ++i) {
+    StressTestIterators(*i, GetParam());
+  }
+}
+
+// Test that erase() revalidates iterators.
+TEST_P(MapImplTest, EraseRevalidates) {
+  // As multiple underlying hash_map implementations do not follow the
+  // validation requirement, the test is disabled for old-style maps.
+  if (GetParam()) return;
+  map_[3] = map_[13] = map_[20] = 0;
+  const int initial_size = map_.size();
+  EXPECT_EQ(3, initial_size);
+  vector<Map<int, int>::iterator> v;
+  for (Map<int, int>::iterator it = map_.begin(); it != map_.end(); ++it) {
+    v.push_back(it);
+  }
+  EXPECT_EQ(initial_size, v.size());
+  for (int i = 0; map_.size() <= initial_size * 20; i++) {
+    map_[i] = 0;
+  }
+  const int larger_size = map_.size();
+  // We've greatly increased the size of the map, so it is highly likely that
+  // the following will corrupt m if erase() doesn't properly revalidate
+  // iterators passed to it.  Finishing this routine without crashing indicates
+  // success.
+  for (int i = 0; i < v.size(); i++) {
+    map_.erase(v[i]);
+  }
+  EXPECT_EQ(larger_size - v.size(), map_.size());
+}
+
+template <typename T>
+bool IsConstHelper(T& /*t*/) {  // NOLINT. We want to catch non-const refs here.
+  return false;
+}
+template <typename T>
+bool IsConstHelper(const T& /*t*/) {
+  return true;
+}
+
+TEST_P(MapImplTest, IteratorConstness) {
+  map_[0] = 0;
+  EXPECT_TRUE(IsConstHelper(*map_.cbegin()));
+  EXPECT_TRUE(IsConstHelper(*const_map_.begin()));
+  EXPECT_FALSE(IsConstHelper(*map_.begin()));
+}
+
+bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; }
+template <typename T>
+bool IsForwardIteratorHelper(T /*t*/) {
+  return false;
+}
+
+TEST_P(MapImplTest, IteratorCategory) {
+  EXPECT_TRUE(IsForwardIteratorHelper(
+      std::iterator_traits<Map<int, int>::iterator>::iterator_category()));
+  EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits<
+      Map<int, int>::const_iterator>::iterator_category()));
+}
+
+TEST_P(MapImplTest, InsertSingle) {
+  int32 key = 0;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  // Insert a non-existed key.
+  std::pair<Map<int32, int32>::iterator, bool> result1 =
+      map_.insert(Map<int32, int32>::value_type(key, value1));
+  ExpectSingleElement(key, value1);
+
+  Map<int32, int32>::iterator it1 = result1.first;
+  EXPECT_EQ(key, it1->first);
+  EXPECT_EQ(value1, it1->second);
+  EXPECT_TRUE(result1.second);
+
+  // Insert an existed key.
+  std::pair<Map<int32, int32>::iterator, bool> result2 =
+      map_.insert(Map<int32, int32>::value_type(key, value2));
+  ExpectSingleElement(key, value1);
+
+  Map<int32, int32>::iterator it2 = result2.first;
+  EXPECT_TRUE(it1 == it2);
+  EXPECT_FALSE(result2.second);
+}
+
+TEST_P(MapImplTest, InsertByIterator) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1a = 100;
+  int32 value1b = 101;
+  int32 value2a = 200;
+  int32 value2b = 201;
+
+  std::map<int32, int32> map1;
+  map1[key1] = value1a;
+  map1[key2] = value2a;
+
+  map_.insert(map1.begin(), map1.end());
+  ExpectElements(map1);
+
+  std::map<int32, int32> map2;
+  map2[key1] = value1b;
+  map2[key2] = value2b;
+
+  map_.insert(map2.begin(), map2.end());
+  ExpectElements(map1);
+}
+
+TEST_P(MapImplTest, EraseSingleByKey) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  // Erase an existing key.
+  EXPECT_EQ(1, map_.erase(key));
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+
+  // Erase a non-existing key.
+  EXPECT_EQ(0, map_.erase(key));
+}
+
+TEST_P(MapImplTest, EraseMutipleByKey) {
+  // erase in one specific order to trigger corner cases
+  for (int i = 0; i < 5; i++) {
+    map_[i] = i;
+  }
+
+  map_.erase(0);
+  EXPECT_EQ(4, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(0));
+
+  map_.erase(1);
+  EXPECT_EQ(3, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(1));
+
+  map_.erase(3);
+  EXPECT_EQ(2, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(3));
+
+  map_.erase(4);
+  EXPECT_EQ(1, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(4));
+
+  map_.erase(2);
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(2));
+}
+
+TEST_P(MapImplTest, EraseSingleByIterator) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  Map<int32, int32>::iterator it = map_.find(key);
+  map_.erase(it);
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_P(MapImplTest, ValidIteratorAfterErase) {
+  for (int i = 0; i < 10; i++) {
+    map_[i] = i;
+  }
+
+  int count = 0;
+
+  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+    count++;
+    if (it->first % 2 == 1) {
+      map_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+
+  EXPECT_EQ(10, count);
+  EXPECT_EQ(5, map_.size());
+}
+
+TEST_P(MapImplTest, EraseByIterator) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+  ExpectElements(map);
+
+  map_.erase(map_.begin(), map_.end());
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key1));
+  EXPECT_TRUE(map_.end() == map_.find(key2));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+TEST_P(MapImplTest, Clear) {
+  int32 key = 0;
+  int32 value = 100;
+
+  map_[key] = value;
+  ExpectSingleElement(key, value);
+
+  map_.clear();
+
+  EXPECT_TRUE(map_.empty());
+  EXPECT_EQ(0, map_.size());
+  EXPECT_TRUE(map_.end() == map_.find(key));
+  EXPECT_TRUE(map_.begin() == map_.end());
+}
+
+static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  m->insert(map.begin(), map.end());
+
+  Map<int32, int32> other(*m);
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+}
+
+TEST_P(MapImplTest, CopyConstructorWithArena) {
+  Arena a;
+  CopyConstructorHelper(&a, &map_);
+}
+
+TEST_P(MapImplTest, CopyConstructorWithoutArena) {
+  CopyConstructorHelper(NULL, &map_);
+}
+
+TEST_P(MapImplTest, IterConstructor) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  Map<int32, int32> new_map(map.begin(), map.end(),
+                            GetParam());
+
+  EXPECT_EQ(2, new_map.size());
+  EXPECT_EQ(value1, new_map.at(key1));
+  EXPECT_EQ(value2, new_map.at(key2));
+}
+
+TEST_P(MapImplTest, Assigner) {
+  int32 key1 = 0;
+  int32 key2 = 1;
+  int32 value1 = 100;
+  int32 value2 = 101;
+
+  std::map<int32, int32> map;
+  map[key1] = value1;
+  map[key2] = value2;
+
+  map_.insert(map.begin(), map.end());
+
+  Map<int32, int32> other(GetParam());
+  int32 key_other = 123;
+  int32 value_other = 321;
+  other[key_other] = value_other;
+  EXPECT_EQ(1, other.size());
+
+  other = map_;
+
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+  EXPECT_TRUE(other.find(key_other) == other.end());
+
+  // Self assign
+  other = other;
+  EXPECT_EQ(2, other.size());
+  EXPECT_EQ(value1, other.at(key1));
+  EXPECT_EQ(value2, other.at(key2));
+
+  // Try assignment to a map with a different choice of "style."
+  Map<int32, int32> m(!GetParam());
+  m = other;
+  EXPECT_EQ(2, m.size());
+  EXPECT_EQ(value1, m.at(key1));
+  EXPECT_EQ(value2, m.at(key2));
+}
+
+TEST_P(MapImplTest, Rehash) {
+  const int test_size = 50;
+  std::map<int32, int32> reference_map;
+  for (int i = 0; i < test_size; i++) {
+    reference_map[i] = i;
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_[i] = reference_map[i];
+    EXPECT_EQ(reference_map[i], map_[i]);
+  }
+  for (int i = 0; i < test_size; i++) {
+    map_.erase(i);
+    EXPECT_TRUE(map_.end() == map_.find(i));
+  }
+  EXPECT_TRUE(map_.empty());
+}
+
+TEST_P(MapImplTest, EqualRange) {
+  int key = 100, key_missing = 101;
+  map_[key] = 100;
+
+  std::pair<google::protobuf::Map<int32, int32>::iterator,
+            google::protobuf::Map<int32, int32>::iterator> range = map_.equal_range(key);
+  EXPECT_TRUE(map_.find(key) == range.first);
+  EXPECT_TRUE(++map_.find(key) == range.second);
+
+  range = map_.equal_range(key_missing);
+  EXPECT_TRUE(map_.end() == range.first);
+  EXPECT_TRUE(map_.end() == range.second);
+
+  std::pair<google::protobuf::Map<int32, int32>::const_iterator,
+            google::protobuf::Map<int32, int32>::const_iterator> const_range =
+      const_map_.equal_range(key);
+  EXPECT_TRUE(const_map_.find(key) == const_range.first);
+  EXPECT_TRUE(++const_map_.find(key) == const_range.second);
+
+  const_range = const_map_.equal_range(key_missing);
+  EXPECT_TRUE(const_map_.end() == const_range.first);
+  EXPECT_TRUE(const_map_.end() == const_range.second);
+}
+
+TEST_P(MapImplTest, ConvertToStdMap) {
+  map_[100] = 101;
+  std::map<int32, int32> std_map(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_map.size());
+  EXPECT_EQ(101, std_map[100]);
+}
+
+TEST_P(MapImplTest, ConvertToStdVectorOfPairs) {
+  map_[100] = 101;
+  std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
+  EXPECT_EQ(1, std_vec.size());
+  EXPECT_EQ(100, std_vec[0].first);
+  EXPECT_EQ(101, std_vec[0].second);
+}
+
+INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool());
+
+// Map Field Reflection Test ========================================
+
+static int Func(int i, int j) {
+  return i * j;
+}
+
+static string StrFunc(int i, int j) {
+  string str;
+  SStringPrintf(&str, "%d", Func(i, j));
+  return str;
+}
+
+static int Int(const string& value) {
+  int result = 0;
+  std::istringstream(value) >> result;
+  return result;
+}
+
+class MapFieldReflectionTest : public testing::Test {
+ protected:
+  typedef FieldDescriptor FD;
+};
+
+TEST_F(MapFieldReflectionTest, RegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<string, string>* map_string_string = message.mutable_map_string_string();
+  Map<int32, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+  // Get RepeatedPtrField objects for all fields of interest.
+  const RepeatedPtrField<Message>& mf_int32_int32 =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_int32);
+  const RepeatedPtrField<Message>& mf_int32_double =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_int32_double);
+  const RepeatedPtrField<Message>& mf_string_string =
+      refl->GetRepeatedPtrField<Message>(message, fd_map_string_string);
+  const RepeatedPtrField<Message>&
+      mf_int32_foreign_message =
+          refl->GetRepeatedPtrField<Message>(
+              message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedPtrField objects for all fields of interest.
+  RepeatedPtrField<Message>* mmf_int32_int32 =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_int32);
+  RepeatedPtrField<Message>* mmf_int32_double =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_int32_double);
+  RepeatedPtrField<Message>* mmf_string_string =
+      refl->MutableRepeatedPtrField<Message>(&message, fd_map_string_string);
+  RepeatedPtrField<Message>* mmf_int32_foreign_message =
+      refl->MutableRepeatedPtrField<Message>(
+          &message, fd_map_int32_foreign_message);
+
+  // Make sure we can do gets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 = mf_int32_int32.Get(i);
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mf_int32_double.Get(i);
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mf_string_string.Get(i);
+      string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mf_int32_foreign_message.Get(i);
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()
+                  ->GetMessage(message_int32_message,
+                               fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 = mmf_int32_int32->Get(i);
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double = mmf_int32_double->Get(i);
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string = mmf_string_string->Get(i);
+      string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()
+                  ->GetMessage(message_int32_message,
+                               fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Do sets through the RepeatedPtrField objects.
+  for (int i = 0; i < 10; i++) {
+    {
+      Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
+      int32 key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
+          *message_int32_int32, fd_map_int32_in32_key);
+      message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
+                                                     fd_map_int32_in32_value,
+                                                     Func(key_int32_int32, -1));
+
+      Message* message_int32_double = mmf_int32_double->Mutable(i);
+      int32 key_int32_double = message_int32_double->GetReflection()->GetInt32(
+          *message_int32_double, fd_map_int32_double_key);
+      message_int32_double->GetReflection()->SetDouble(
+          message_int32_double, fd_map_int32_double_value,
+          Func(key_int32_double, -2));
+
+      Message* message_string_string = mmf_string_string->Mutable(i);
+      string key_string_string =
+          message_string_string->GetReflection()->GetString(
+              *message_string_string, fd_map_string_string_key);
+      message_string_string->GetReflection()->SetString(
+          message_string_string, fd_map_string_string_value,
+          StrFunc(Int(key_string_string), -5));
+
+      Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
+      int32 key_int32_message =
+          message_int32_message->GetReflection()->GetInt32(
+              *message_int32_message, fd_map_int32_foreign_message_key);
+      ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
+          message_int32_message->GetReflection()
+              ->MutableMessage(message_int32_message,
+                               fd_map_int32_foreign_message_value));
+      value_int32_message->set_c(Func(key_int32_message, -6));
+    }
+  }
+
+  // Check gets through mutable objects.
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+  TestMap message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<string, string>* map_string_string = message.mutable_map_string_string();
+  Map<int32, ForeignMessage>* map_int32_foreign_message =
+      message.mutable_map_int32_foreign_message();
+
+  for (int i = 0; i < 10; ++i) {
+    (*map_int32_int32)[i] = Func(i, 1);
+    (*map_int32_double)[i] = Func(i, 2);
+    (*map_string_string)[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*map_int32_foreign_message)[i].set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+  const FieldDescriptor* fd_map_int32_in32_key =
+      fd_map_int32_int32->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_in32_value =
+      fd_map_int32_int32->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_double_key =
+      fd_map_int32_double->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_double_value =
+      fd_map_int32_double->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_string_string_key =
+      fd_map_string_string->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_string_string_value =
+      fd_map_string_string->message_type()->FindFieldByName("value");
+  const FieldDescriptor* fd_map_int32_foreign_message_key =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+  const FieldDescriptor* fd_map_int32_foreign_message_value =
+      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+
+  // Get RepeatedFieldRef objects for all fields of interest.
+  const RepeatedFieldRef<Message> mf_int32_int32 =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_int32);
+  const RepeatedFieldRef<Message> mf_int32_double =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_double);
+  const RepeatedFieldRef<Message> mf_string_string =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_string_string);
+  const RepeatedFieldRef<Message> mf_int32_foreign_message =
+      refl->GetRepeatedFieldRef<Message>(message, fd_map_int32_foreign_message);
+
+  // Get mutable RepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(&message, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message>
+      mmf_int32_foreign_message =
+          refl->GetMutableRepeatedFieldRef<Message>(
+              &message, fd_map_int32_foreign_message);
+
+  // Get entry default instances
+  google::protobuf::scoped_ptr<Message> entry_int32_int32(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_int32->message_type())
+          ->New());
+  google::protobuf::scoped_ptr<Message> entry_int32_double(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_double->message_type())
+          ->New());
+  google::protobuf::scoped_ptr<Message> entry_string_string(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_string_string->message_type())
+          ->New());
+  google::protobuf::scoped_ptr<Message> entry_int32_foreign_message(
+      MessageFactory::generated_factory()
+          ->GetPrototype(fd_map_int32_foreign_message->message_type())
+          ->New());
+
+  EXPECT_EQ(10, mf_int32_int32.size());
+  EXPECT_EQ(10, mmf_int32_int32.size());
+  EXPECT_EQ(10, mf_int32_double.size());
+  EXPECT_EQ(10, mmf_int32_double.size());
+  EXPECT_EQ(10, mf_string_string.size());
+  EXPECT_EQ(10, mmf_string_string.size());
+  EXPECT_EQ(10, mf_int32_foreign_message.size());
+  EXPECT_EQ(10, mmf_int32_foreign_message.size());
+
+  EXPECT_FALSE(mf_int32_int32.empty());
+  EXPECT_FALSE(mmf_int32_int32.empty());
+  EXPECT_FALSE(mf_int32_double.empty());
+  EXPECT_FALSE(mmf_int32_double.empty());
+  EXPECT_FALSE(mf_string_string.empty());
+  EXPECT_FALSE(mmf_string_string.empty());
+  EXPECT_FALSE(mf_int32_foreign_message.empty());
+  EXPECT_FALSE(mmf_int32_foreign_message.empty());
+
+  // Make sure we can do gets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; ++i) {
+    {
+      // Check gets through const objects.
+      const Message& message_int32_int32 =
+          mf_int32_int32.Get(i, entry_int32_int32.get());
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mf_int32_double.Get(i, entry_int32_double.get());
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mf_string_string.Get(i, entry_string_string.get());
+      string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()
+                  ->GetMessage(message_int32_message,
+                               fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+
+    {
+      // Check gets through mutable objects.
+      const Message& message_int32_int32 =
+          mmf_int32_int32.Get(i, entry_int32_int32.get());
+      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_key);
+      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+          message_int32_int32, fd_map_int32_in32_value);
+      EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
+
+      const Message& message_int32_double =
+          mmf_int32_double.Get(i, entry_int32_double.get());
+      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+          message_int32_double, fd_map_int32_double_key);
+      double value_int32_double =
+          message_int32_double.GetReflection()->GetDouble(
+              message_int32_double, fd_map_int32_double_value);
+      EXPECT_EQ(value_int32_double, Func(key_int32_double, 2));
+
+      const Message& message_string_string =
+          mmf_string_string.Get(i, entry_string_string.get());
+      string key_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_key);
+      string value_string_string =
+          message_string_string.GetReflection()->GetString(
+              message_string_string, fd_map_string_string_value);
+      EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
+
+      const Message& message_int32_message =
+          mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
+      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
+          message_int32_message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& value_int32_message =
+          down_cast<const ForeignMessage&>(
+              message_int32_message.GetReflection()
+                  ->GetMessage(message_int32_message,
+                               fd_map_int32_foreign_message_value));
+      EXPECT_EQ(value_int32_message.c(), Func(key_int32_message, 6));
+    }
+  }
+
+  // Make sure we can do sets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; i++) {
+    const Message& message_int32_int32 =
+        mmf_int32_int32.Get(i, entry_int32_int32.get());
+    int key = message_int32_int32.GetReflection()->GetInt32(
+        message_int32_int32, fd_map_int32_in32_key);
+
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+        key);
+    entry_int32_int32->GetReflection()->SetInt32(
+        entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+        Func(key, -1));
+    entry_int32_double->GetReflection()->SetInt32(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+        key);
+    entry_int32_double->GetReflection()->SetDouble(
+        entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+        Func(key, -2));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(0), StrFunc(key, 1));
+    entry_string_string->GetReflection()->SetString(
+        entry_string_string.get(),
+        fd_map_string_string->message_type()->field(1), StrFunc(key, -5));
+    entry_int32_foreign_message->GetReflection()->SetInt32(
+        entry_int32_foreign_message.get(),
+        fd_map_int32_foreign_message->message_type()->field(0), key);
+    Message* value_message =
+        entry_int32_foreign_message->GetReflection()->MutableMessage(
+            entry_int32_foreign_message.get(),
+            fd_map_int32_foreign_message->message_type()->field(1));
+    value_message->GetReflection()->SetInt32(
+        value_message, value_message->GetDescriptor()->FindFieldByName("c"),
+        Func(key, -6));
+
+    mmf_int32_int32.Set(i, *entry_int32_int32);
+    mmf_int32_double.Set(i, *entry_int32_double);
+    mmf_string_string.Set(i, *entry_string_string);
+    mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message);
+  }
+
+  for (int i = 0; i < 10; i++) {
+    EXPECT_EQ(Func(i, -1), message.map_int32_int32().at(i));
+    EXPECT_EQ(Func(i, -2), message.map_int32_double().at(i));
+    EXPECT_EQ(StrFunc(i, -5), message.map_string_string().at(StrFunc(i, 1)));
+    EXPECT_EQ(Func(i, -6), message.map_int32_foreign_message().at(i).c());
+  }
+
+  // Test iterators.
+  {
+    int index = 0;
+    hash_map<int32, int32> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
+         it != mf_int32_int32.end(); ++it) {
+      const Message& message = *it;
+      int32 key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
+      int32 value =
+          message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (hash_map<int32, int32>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    hash_map<int32, double> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
+         it != mf_int32_double.end(); ++it) {
+      const Message& message = *it;
+      int32 key =
+          message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
+      double value = message.GetReflection()->GetDouble(
+          message, fd_map_int32_double_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (hash_map<int32, double>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    hash_map<string, string> result;
+    for (RepeatedFieldRef<Message>::iterator it = mf_string_string.begin();
+         it != mf_string_string.end(); ++it) {
+      const Message& message = *it;
+      string key =
+          message.GetReflection()->GetString(message, fd_map_string_string_key);
+      string value = message.GetReflection()->GetString(
+          message, fd_map_string_string_value);
+      result[key] = value;
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (hash_map<string, string>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_string_string().at(it->first), it->second);
+    }
+  }
+
+  {
+    int index = 0;
+    std::map<int32, ForeignMessage> result;
+    for (RepeatedFieldRef<Message>::iterator it =
+             mf_int32_foreign_message.begin();
+         it != mf_int32_foreign_message.end(); ++it) {
+      const Message& message = *it;
+      int32 key = message.GetReflection()->GetInt32(
+          message, fd_map_int32_foreign_message_key);
+      const ForeignMessage& sub_message = down_cast<const ForeignMessage&>(
+          message.GetReflection()
+              ->GetMessage(message, fd_map_int32_foreign_message_value));
+      result[key].MergeFrom(sub_message);
+      ++index;
+    }
+    EXPECT_EQ(10, index);
+    for (std::map<int32, ForeignMessage>::const_iterator it = result.begin();
+         it != result.end(); ++it) {
+      EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
+                it->second.c());
+    }
+  }
+
+  // Test MutableRepeatedFieldRef::Add()
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(0),
+      4321);
+  entry_int32_int32->GetReflection()->SetInt32(
+      entry_int32_int32.get(), fd_map_int32_int32->message_type()->field(1),
+      1234);
+  mmf_int32_int32.Add(*entry_int32_int32);
+  EXPECT_EQ(1234, message.map_int32_int32().at(4321));
+
+  entry_int32_double->GetReflection()->SetInt32(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(0),
+      4321);
+  entry_int32_double->GetReflection()->SetDouble(
+      entry_int32_double.get(), fd_map_int32_double->message_type()->field(1),
+      1234.0);
+  mmf_int32_double.Add(*entry_int32_double);
+  EXPECT_EQ(1234.0, message.map_int32_double().at(4321));
+
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(),
+      fd_map_string_string->message_type()->field(0), "4321");
+  entry_string_string->GetReflection()->SetString(
+      entry_string_string.get(), fd_map_string_string->message_type()->field(1),
+      "1234");
+  mmf_string_string.Add(*entry_string_string);
+  EXPECT_EQ("1234", message.map_string_string().at("4321"));
+
+  entry_int32_foreign_message->GetReflection()->SetInt32(
+      entry_int32_foreign_message.get(),
+      fd_map_int32_foreign_message->message_type()->field(0), 4321);
+  Message* value_message =
+      entry_int32_foreign_message->GetReflection()->MutableMessage(
+          entry_int32_foreign_message.get(),
+          fd_map_int32_foreign_message->message_type()->field(1));
+  ForeignMessage foreign_message;
+  foreign_message.set_c(1234);
+  value_message->CopyFrom(foreign_message);
+
+  mmf_int32_foreign_message.Add(*entry_int32_foreign_message);
+  EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c());
+
+  // Test Reflection::AddAllocatedMessage
+  Message* free_entry_string_string = MessageFactory::generated_factory()
+      ->GetPrototype(fd_map_string_string->message_type())
+      ->New();
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string,
+      fd_map_string_string->message_type()->field(0), "4321");
+  entry_string_string->GetReflection()->SetString(
+      free_entry_string_string, fd_map_string_string->message_type()->field(1),
+      "1234");
+  refl->AddAllocatedMessage(&message, fd_map_string_string,
+                            free_entry_string_string);
+
+  // Test MutableRepeatedFieldRef::RemoveLast()
+  mmf_int32_int32.RemoveLast();
+  mmf_int32_double.RemoveLast();
+  mmf_string_string.RemoveLast();
+  mmf_int32_foreign_message.RemoveLast();
+  EXPECT_EQ(10, message.map_int32_int32().size());
+  EXPECT_EQ(10, message.map_int32_double().size());
+  EXPECT_EQ(11, message.map_string_string().size());
+  EXPECT_EQ(10, message.map_int32_foreign_message().size());
+
+  // Test MutableRepeatedFieldRef::SwapElements()
+  {
+    const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32 int32_value0a =
+        message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
+    const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32 int32_value9a =
+        message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
+
+    mmf_int32_int32.SwapElements(0, 9);
+
+    const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
+    int32 int32_value0b =
+        message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
+    const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
+    int32 int32_value9b =
+        message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0a = message0a.GetReflection()->GetDouble(
+        message0a, fd_map_int32_double_value);
+    const Message& message9a =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9a = message9a.GetReflection()->GetDouble(
+        message9a, fd_map_int32_double_value);
+
+    mmf_int32_double.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_double.Get(0, entry_int32_double.get());
+    double double_value0b = message0b.GetReflection()->GetDouble(
+        message0b, fd_map_int32_double_value);
+    const Message& message9b =
+        mmf_int32_double.Get(9, entry_int32_double.get());
+    double double_value9b = message9b.GetReflection()->GetDouble(
+        message9b, fd_map_int32_double_value);
+
+    EXPECT_EQ(double_value9a, double_value0b);
+    EXPECT_EQ(double_value0a, double_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_string_string.Get(0, entry_string_string.get());
+    string string_value0a = message0a.GetReflection()->GetString(
+        message0a, fd_map_string_string_value);
+    const Message& message9a =
+        mmf_string_string.Get(9, entry_string_string.get());
+    string string_value9a = message9a.GetReflection()->GetString(
+        message9a, fd_map_string_string_value);
+
+    mmf_string_string.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_string_string.Get(0, entry_string_string.get());
+    string string_value0b = message0b.GetReflection()->GetString(
+        message0b, fd_map_string_string_value);
+    const Message& message9b =
+        mmf_string_string.Get(9, entry_string_string.get());
+    string string_value9b = message9b.GetReflection()->GetString(
+        message9b, fd_map_string_string_value);
+
+    EXPECT_EQ(string_value9a, string_value0b);
+    EXPECT_EQ(string_value0a, string_value9b);
+  }
+
+  {
+    const Message& message0a =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0a = down_cast<const ForeignMessage&>(
+        message0a.GetReflection()
+            ->GetMessage(message0a, fd_map_int32_foreign_message_value));
+    int32 int32_value0a = sub_message0a.c();
+    const Message& message9a =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9a = down_cast<const ForeignMessage&>(
+        message9a.GetReflection()
+            ->GetMessage(message9a, fd_map_int32_foreign_message_value));
+    int32 int32_value9a = sub_message9a.c();
+
+    mmf_int32_foreign_message.SwapElements(0, 9);
+
+    const Message& message0b =
+        mmf_int32_foreign_message.Get(0, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message0b = down_cast<const ForeignMessage&>(
+        message0b.GetReflection()
+            ->GetMessage(message0b, fd_map_int32_foreign_message_value));
+    int32 int32_value0b = sub_message0b.c();
+    const Message& message9b =
+        mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
+    const ForeignMessage& sub_message9b = down_cast<const ForeignMessage&>(
+        message9b.GetReflection()
+            ->GetMessage(message9b, fd_map_int32_foreign_message_value));
+    int32 int32_value9b = sub_message9b.c();
+
+    EXPECT_EQ(int32_value9a, int32_value0b);
+    EXPECT_EQ(int32_value0a, int32_value9b);
+  }
+}
+
+TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+  // Set-up message content.
+  TestMap m0, m1, m2;
+  for (int i = 0; i < 10; ++i) {
+    (*m0.mutable_map_int32_int32())[i] = Func(i, 1);
+    (*m0.mutable_map_int32_double())[i] = Func(i, 2);
+    (*m0.mutable_map_string_string())[StrFunc(i, 1)] = StrFunc(i, 5);
+    (*m0.mutable_map_int32_foreign_message())[i].set_c(Func(i, 6));
+    (*m1.mutable_map_int32_int32())[i + 10] = Func(i, 11);
+    (*m1.mutable_map_int32_double())[i + 10] = Func(i, 12);
+    (*m1.mutable_map_string_string())[StrFunc(i + 10, 1)] = StrFunc(i, 15);
+    (*m1.mutable_map_int32_foreign_message())[i + 10].set_c(Func(i, 16));
+    (*m2.mutable_map_int32_int32())[i + 20] = Func(i, 21);
+    (*m2.mutable_map_int32_double())[i + 20] = Func(i, 22);
+    (*m2.mutable_map_string_string())[StrFunc(i + 20, 1)] = StrFunc(i, 25);
+    (*m2.mutable_map_int32_foreign_message())[i + 20].set_c(Func(i, 26));
+  }
+
+  const Reflection* refl = m0.GetReflection();
+  const Descriptor* desc = m0.GetDescriptor();
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_map_int32_int32 =
+      desc->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* fd_map_int32_double =
+      desc->FindFieldByName("map_int32_double");
+  const FieldDescriptor* fd_map_string_string =
+      desc->FindFieldByName("map_string_string");
+  const FieldDescriptor* fd_map_int32_foreign_message =
+      desc->FindFieldByName("map_int32_foreign_message");
+
+    // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<Message> mmf_int32_int32 =
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m0, fd_map_int32_int32);
+  const MutableRepeatedFieldRef<Message> mmf_int32_double =
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m0, fd_map_int32_double);
+  const MutableRepeatedFieldRef<Message> mmf_string_string =
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m0, fd_map_string_string);
+  const MutableRepeatedFieldRef<Message>
+      mmf_int32_foreign_message =
+          refl->GetMutableRepeatedFieldRef<Message>(
+              &m0, fd_map_int32_foreign_message);
+
+  // Test MutableRepeatedRef::CopyFrom
+  mmf_int32_int32.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m1, fd_map_int32_int32));
+  mmf_int32_double.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m1, fd_map_int32_double));
+  mmf_string_string.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m1, fd_map_string_string));
+  mmf_int32_foreign_message.CopyFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m1, fd_map_int32_foreign_message));
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 11), m0.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m0.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m0.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m0.map_int32_foreign_message().at(i + 10).c());
+  }
+
+  // Test MutableRepeatedRef::MergeFrom
+  mmf_int32_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m2, fd_map_int32_int32));
+  mmf_int32_double.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m2, fd_map_int32_double));
+  mmf_string_string.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m2, fd_map_string_string));
+  mmf_int32_foreign_message.MergeFrom(
+      refl->GetRepeatedFieldRef<Message>(
+          m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // Test MutableRepeatedRef::Swap
+  // Swap between m0 and m2.
+  mmf_int32_int32.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m2, fd_map_int32_int32));
+  mmf_int32_double.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m2, fd_map_int32_double));
+  mmf_string_string.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m2, fd_map_string_string));
+  mmf_int32_foreign_message.Swap(
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &m2, fd_map_int32_foreign_message));
+  for (int i = 0; i < 10; ++i) {
+    // Check the content of m0.
+    EXPECT_EQ(Func(i, 21), m0.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m0.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m0.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m0.map_int32_foreign_message().at(i + 20).c());
+
+    // Check the content of m2.
+    EXPECT_EQ(Func(i, 11), m2.map_int32_int32().at(i + 10));
+    EXPECT_EQ(Func(i, 12), m2.map_int32_double().at(i + 10));
+    EXPECT_EQ(StrFunc(i, 15), m2.map_string_string().at(StrFunc(i + 10, 1)));
+    EXPECT_EQ(Func(i, 16), m2.map_int32_foreign_message().at(i + 10).c());
+    EXPECT_EQ(Func(i, 21), m2.map_int32_int32().at(i + 20));
+    EXPECT_EQ(Func(i, 22), m2.map_int32_double().at(i + 20));
+    EXPECT_EQ(StrFunc(i, 25), m2.map_string_string().at(StrFunc(i + 20, 1)));
+    EXPECT_EQ(Func(i, 26), m2.map_int32_foreign_message().at(i + 20).c());
+  }
+
+  // TODO(teboring): add test for duplicated key
+}
+
+// Generated Message Test ===========================================
+
+TEST(GeneratedMapFieldTest, Accessors) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapTestUtil::ModifyMapFields(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFieldsInitialized(&message);
+  MapTestUtil::ExpectMapFieldsSetInitialized(message);
+}
+
+TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) {
+  unittest::TestEnumMap message;
+  EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO,
+            (*message.mutable_known_map_field())[0]);
+}
+
+TEST(GeneratedMapFieldTest, Clear) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  message.Clear();
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(GeneratedMapFieldTest, ClearMessageMap) {
+  unittest::TestMessageMap message;
+
+  // Creates a TestAllTypes with default value
+  TestUtil::ExpectClear((*message.mutable_map_int32_message())[0]);
+}
+
+TEST(GeneratedMapFieldTest, CopyFrom) {
+  unittest::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  message2.CopyFrom(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  message2.CopyFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromMessageMap) {
+  unittest::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.CopyFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+TEST(GeneratedMapFieldTest, SwapWithEmpty) {
+  unittest::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+  MapTestUtil::ExpectClear(message1);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithSelf) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  message.Swap(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(GeneratedMapFieldTest, SwapWithOther) {
+  unittest::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  message1.Swap(&message2);
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyConstructor) {
+  unittest::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  unittest::TestMap message2(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyAssignmentOperator) {
+  unittest::TestMap message1;
+  MapTestUtil::SetMapFields(&message1);
+
+  unittest::TestMap message2;
+  message2 = message1;
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Make sure that self-assignment does something sane.
+  message2.operator=(message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+        !defined(GOOGLE_PROTOBUF_NO_RTTI)
+TEST(GeneratedMapFieldTest, UpcastCopyFrom) {
+  // Test the CopyFrom method that takes in the generic const Message&
+  // parameter.
+  unittest::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Message* source = implicit_cast<const Message*>(&message1);
+  message2.CopyFrom(*source);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+#endif
+
+#ifndef PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) {
+  // Test copying from a DynamicMessage, which must fall back to using
+  // reflection.
+  unittest::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message1;
+  message1.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) {
+  unittest::TestMap message2;
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message1;
+  message1.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  message2.CopyFrom(*message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
+  // Test copying to a DynamicMessage, which must fall back to using reflection.
+  unittest::TestMap message2;
+  MapTestUtil::SetMapFields(&message2);
+
+  // Construct a new version of the dynamic message via the factory.
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message1;
+  message1.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  message1->MergeFrom(message2);
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+}
+
+TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) {
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  unittest::TestMap message2;
+  reflection_tester.SetMapFieldsViaMapReflection(&message2);
+
+  // Construct a dynamic message via the factory.
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message1;
+  message1.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+
+  message1->MergeFrom(message2);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message1);
+}
+
+TEST(GeneratedMapFieldTest, SyncDynamicMapWithRepeatedField) {
+  // Construct a dynamic message via the factory.
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message;
+  message.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
+
+TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) {
+  unittest::TestMap message1, message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  // This field will test merging into an empty spot.
+  (*message2.mutable_map_int32_int32())[1] = 1;
+  message1.mutable_map_int32_int32()->erase(1);
+
+  // This tests overwriting.
+  (*message2.mutable_map_int32_double())[1] = 1;
+  (*message1.mutable_map_int32_double())[1] = 2;
+
+  message1.MergeFrom(message2);
+  MapTestUtil::ExpectMapFieldsSet(message1);
+}
+
+TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
+  unittest::TestMessageMap message1, message2;
+
+  (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+  (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+  message1.MergeFrom(message2);
+
+  // Checks repeated field is overwritten.
+  EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+  EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+}
+
+// Test the generated SerializeWithCachedSizesToArray()
+TEST(GeneratedMapFieldTest, SerializationToArray) {
+  unittest::TestMap message1, message2;
+  string data;
+  MapTestUtil::SetMapFields(&message1);
+  int size = message1.ByteSize();
+  data.resize(size);
+  uint8* start = reinterpret_cast<uint8*>(string_as_array(&data));
+  uint8* end = message1.SerializeWithCachedSizesToArray(start);
+  EXPECT_EQ(size, end - start);
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+// Test the generated SerializeWithCachedSizes()
+TEST(GeneratedMapFieldTest, SerializationToStream) {
+  unittest::TestMap message1, message2;
+  MapTestUtil::SetMapFields(&message1);
+  int size = message1.ByteSize();
+  string data;
+  data.resize(size);
+  {
+    // Allow the output stream to buffer only one byte at a time.
+    io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
+    io::CodedOutputStream output_stream(&array_stream);
+    message1.SerializeWithCachedSizes(&output_stream);
+    EXPECT_FALSE(output_stream.HadError());
+    EXPECT_EQ(size, output_stream.ByteCount());
+  }
+  EXPECT_TRUE(message2.ParseFromString(data));
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+
+TEST(GeneratedMapFieldTest, SameTypeMaps) {
+  const Descriptor* map1 = unittest::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map1")
+                               ->message_type();
+  const Descriptor* map2 = unittest::TestSameTypeMap::descriptor()
+                               ->FindFieldByName("map2")
+                               ->message_type();
+
+  const Message* map1_entry =
+      MessageFactory::generated_factory()->GetPrototype(map1);
+  const Message* map2_entry =
+      MessageFactory::generated_factory()->GetPrototype(map2);
+
+  EXPECT_EQ(map1, map1_entry->GetDescriptor());
+  EXPECT_EQ(map2, map2_entry->GetDescriptor());
+}
+
+TEST(GeneratedMapFieldTest, Proto2UnknownEnum) {
+  unittest::TestEnumMapPlusExtra from;
+  (*from.mutable_known_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_FOO;
+  (*from.mutable_unknown_map_field())[0] = unittest::E_PROTO2_MAP_ENUM_EXTRA;
+  string data;
+  from.SerializeToString(&data);
+
+  unittest::TestEnumMap to;
+  EXPECT_TRUE(to.ParseFromString(data));
+  EXPECT_EQ(0, to.unknown_map_field().size());
+  const UnknownFieldSet& unknown_field_set =
+      to.GetReflection()->GetUnknownFields(to);
+  EXPECT_EQ(1, unknown_field_set.field_count());
+  EXPECT_EQ(1, to.known_map_field().size());
+  EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
+
+  data.clear();
+  from.Clear();
+  to.SerializeToString(&data);
+  EXPECT_TRUE(from.ParseFromString(data));
+  EXPECT_EQ(0, from.GetReflection()->GetUnknownFields(from).field_count());
+  EXPECT_EQ(1, from.known_map_field().size());
+  EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_FOO, from.known_map_field().at(0));
+  EXPECT_EQ(1, from.unknown_map_field().size());
+  EXPECT_EQ(unittest::E_PROTO2_MAP_ENUM_EXTRA, from.unknown_map_field().at(0));
+}
+
+TEST(GeneratedMapFieldTest, StandardWireFormat) {
+  unittest::TestMap message;
+  string data = "\x0A\x04\x08\x01\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, UnorderedWireFormat) {
+  unittest::TestMap message;
+
+  // put value before key in wire format
+  string data = "\x0A\x04\x10\x01\x08\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) {
+  unittest::TestMap message;
+
+  // Two key fields in wire format
+  string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
+  unittest::TestMap message;
+
+  // Two value fields in wire format
+  string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedKeyWireFormat) {
+  unittest::TestMap message;
+
+  // No key field in wire format
+  string data = "\x0A\x02\x10\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int32_int32().at(0));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueWireFormat) {
+  unittest::TestMap message;
+
+  // No value field in wire format
+  string data = "\x0A\x02\x08\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(0, message.map_int32_int32().at(1));
+}
+
+TEST(GeneratedMapFieldTest, MissedValueTextFormat) {
+  unittest::TestMap message;
+
+  // No value field in text format
+  string text =
+      "map_int32_foreign_message {\n"
+      "  key: 1234567890\n"
+      "}";
+
+  EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(text, &message));
+  EXPECT_EQ(1, message.map_int32_foreign_message().size());
+  EXPECT_EQ(11, message.ByteSize());
+}
+
+TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) {
+  unittest::TestMap message;
+
+  // Unknown field in wire format
+  string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+  EXPECT_TRUE(message.ParseFromString(data));
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(3, message.map_int32_int32().at(2));
+}
+
+TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
+  unittest::TestMap message;
+
+  // corrupted data in wire format
+  string data = "\x0A\x06\x08\x02\x11\x03";
+
+  EXPECT_FALSE(message.ParseFromString(data));
+}
+
+TEST(GeneratedMapFieldTest, IsInitialized) {
+  unittest::TestRequiredMessageMap map_message;
+
+  // Add an uninitialized message.
+  (*map_message.mutable_map_field())[0];
+  EXPECT_FALSE(map_message.IsInitialized());
+
+  // Initialize uninitialized message
+  (*map_message.mutable_map_field())[0].set_a(0);
+  (*map_message.mutable_map_field())[0].set_b(0);
+  (*map_message.mutable_map_field())[0].set_c(0);
+  EXPECT_TRUE(map_message.IsInitialized());
+}
+
+// Generated Message Reflection Test ================================
+
+TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+    unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+
+  EXPECT_LT(0, message.GetReflection()->SpaceUsed(message));
+}
+
+TEST(GeneratedMapFieldReflectionTest, Accessors) {
+  // Set every field to a unique value then go back and check all those
+  // values.
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+    unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+
+  reflection_tester.ModifyMapFieldsViaReflection(&message);
+  MapTestUtil::ExpectMapFieldsModified(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Swap) {
+  unittest::TestMap message1;
+  unittest::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectClear(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapWithBothSet) {
+  unittest::TestMap message1;
+  unittest::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+  MapTestUtil::ModifyMapFields(&message2);
+
+  const Reflection* reflection = message1.GetReflection();
+  reflection->Swap(&message1, &message2);
+
+  MapTestUtil::ExpectMapFieldsModified(message1);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapFields) {
+  unittest::TestMap message1;
+  unittest::TestMap message2;
+
+  MapTestUtil::SetMapFields(&message2);
+
+  vector<const FieldDescriptor*> fields;
+  const Reflection* reflection = message1.GetReflection();
+  reflection->ListFields(message2, &fields);
+  reflection->SwapFields(&message1, &message2, fields);
+
+  MapTestUtil::ExpectMapFieldsSet(message1);
+  MapTestUtil::ExpectClear(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ClearField) {
+  unittest::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  reflection_tester.ClearMapFieldsViaReflection(&message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, RemoveLast) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expected_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+
+  reflection_tester.RemoveLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+  std::vector<const Message*> remained_entries =
+      MapTestUtil::GetMapEntries(message, 0);
+  EXPECT_TRUE(expected_entries == remained_entries);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ReleaseLast) {
+  unittest::TestMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  MapReflectionTester reflection_tester(descriptor);
+
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+
+  reflection_tester.ReleaseLastMapsViaReflection(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 1);
+
+  // Now test that we actually release the right message.
+  message.Clear();
+  MapTestUtil::SetMapFields(&message);
+
+  MapTestUtil::ExpectMapsSize(message, 2);
+  std::vector<const Message*> expect_last =
+      MapTestUtil::GetMapEntries(message, 1);
+  std::vector<const Message*> release_last =
+      MapTestUtil::GetMapEntriesFromRelease(&message);
+  MapTestUtil::ExpectMapsSize(message, 1);
+  EXPECT_TRUE(expect_last == release_last);
+  for (std::vector<const Message*>::iterator it = release_last.begin();
+       it != release_last.end(); ++it) {
+    delete *it;
+  }
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapElements) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+    unittest::TestMap::descriptor());
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Get pointers of map entries at their original position
+  std::vector<const Message*> entries0 = MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1 = MapTestUtil::GetMapEntries(message, 1);
+
+  // Swap the first time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_once =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_once =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries1_once);
+  EXPECT_TRUE(entries1 == entries0_once);
+
+  // Swap the second time.
+  reflection_tester.SwapMapsViaReflection(&message);
+
+  // Get pointer of map entry after swap once.
+  std::vector<const Message*> entries0_twice =
+      MapTestUtil::GetMapEntries(message, 0);
+  std::vector<const Message*> entries1_twice =
+      MapTestUtil::GetMapEntries(message, 1);
+
+  // Test map entries are swapped back.
+  MapTestUtil::ExpectMapsSize(message, 2);
+  EXPECT_TRUE(entries0 == entries0_twice);
+  EXPECT_TRUE(entries1 == entries1_twice);
+}
+
+TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+    unittest::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, EmbedProto2Message) {
+  unittest::TestMessageMap message;
+
+  const FieldDescriptor* map_field =
+      unittest::TestMessageMap::descriptor()->FindFieldByName(
+          "map_int32_message");
+  const FieldDescriptor* value =
+      map_field->message_type()->FindFieldByName("value");
+
+  Message* entry_message =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_EQ(
+      &entry_message->GetReflection()->GetMessage(*entry_message, value),
+      reinterpret_cast<const Message*>(&TestAllTypes::default_instance()));
+
+  Message* proto2_message =
+      entry_message->GetReflection()->MutableMessage(entry_message, value);
+  EXPECT_EQ(unittest::TestAllTypes::descriptor(),
+            proto2_message->GetDescriptor());
+  ASSERT_EQ(1, message.map_int32_message().size());
+}
+
+TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) {
+  unittest::TestMap message;
+  const FieldDescriptor* map_field =
+      unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
+  const FieldDescriptor* key =
+      map_field->message_type()->FindFieldByName("key");
+  const FieldDescriptor* value =
+      map_field->message_type()->FindFieldByName("value");
+
+  Message* entry_message1 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+
+  Message* entry_message2 =
+      message.GetReflection()->AddMessage(&message, map_field);
+  EXPECT_FALSE(entry_message2->GetReflection()->HasField(*entry_message2, key));
+  EXPECT_FALSE(
+      entry_message2->GetReflection()->HasField(*entry_message2, value));
+
+  entry_message1->MergeFrom(*entry_message2);
+  EXPECT_FALSE(entry_message1->GetReflection()->HasField(*entry_message1, key));
+  EXPECT_FALSE(
+      entry_message1->GetReflection()->HasField(*entry_message1, value));
+}
+
+TEST(GeneratedMapFieldReflectionTest, MapEntryClear) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+    unittest::TestMap::descriptor());
+  reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) {
+  unittest::TestEnumMap message;
+  const Descriptor* descriptor = message.GetDescriptor();
+  const FieldDescriptor* field_descriptor =
+      descriptor->FindFieldByName("known_map_field");
+  const FieldDescriptor* value_descriptor =
+      field_descriptor->message_type()->FindFieldByName("value");
+  Message* sub_message =
+      message.GetReflection()->AddMessage(&message, field_descriptor);
+  EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message,
+                                                          value_descriptor));
+}
+
+// Map Reflection API Test =========================================
+
+TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) {
+  unittest::TestMap message;
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+}
+
+// Dynamic Message Test =============================================
+
+class MapFieldInDynamicMessageTest : public testing::Test {
+ protected:
+  const DescriptorPool* pool_;
+  DynamicMessageFactory factory_;
+  const Descriptor* map_descriptor_;
+  const Descriptor* recursive_map_descriptor_;
+  const Message* map_prototype_;
+
+  MapFieldInDynamicMessageTest()
+      : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
+
+  virtual void SetUp() {
+    map_descriptor_ =
+      pool_->FindMessageTypeByName("protobuf_unittest.TestMap");
+    recursive_map_descriptor_ =
+        pool_->FindMessageTypeByName("protobuf_unittest.TestRecursiveMapMessage");
+    ASSERT_TRUE(map_descriptor_ != NULL);
+    ASSERT_TRUE(recursive_map_descriptor_ != NULL);
+    map_prototype_ = factory_.GetPrototype(map_descriptor_);
+  }
+};
+
+TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) {
+  // Check that all fields have independent offsets by setting each
+  // one to a unique value then checking that they all still have those
+  // unique values (i.e. they don't stomp each other).
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
+  // Check that map fields work properly.
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
+
+  // Check set functions.
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
+  // Test that SpaceUsed() works properly
+
+  // Since we share the implementation with generated messages, we don't need
+  // to test very much here.  Just make sure it appears to be working.
+
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+
+  int initial_space_used = message->SpaceUsed();
+
+  reflection_tester.SetMapFieldsViaReflection(message.get());
+  EXPECT_LT(initial_space_used, message->SpaceUsed());
+}
+
+TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) {
+  TestRecursiveMapMessage from;
+  (*from.mutable_a())[""];
+  string data = from.SerializeAsString();
+  google::protobuf::scoped_ptr<Message> to(
+      factory_.GetPrototype(recursive_map_descriptor_)->New());
+  ASSERT_TRUE(to->ParseFromString(data));
+}
+
+// ReflectionOps Test ===============================================
+
+TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapCopy) {
+  unittest::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Copy(message, &message2);
+
+  MapTestUtil::ExpectMapFieldsSet(message2);
+
+  // Copying from self should be a no-op.
+  ReflectionOps::Copy(message2, &message2);
+  MapTestUtil::ExpectMapFieldsSet(message2);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MergeMap) {
+  // Note:  Copy is implemented in terms of Merge() so technically the Copy
+  //   test already tested most of this.
+
+  unittest::TestMap message, message2;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Merge(message2, &message);
+
+  MapTestUtil::ExpectMapFieldsSet(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, ClearMap) {
+  unittest::TestMap message;
+
+  MapTestUtil::SetMapFields(&message);
+
+  ReflectionOps::Clear(&message);
+
+  MapTestUtil::ExpectClear(message);
+}
+
+TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
+  unittest::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  // Set some unknown fields in message.
+  message.GetReflection()->MutableUnknownFields(&message)->
+      AddVarint(123456, 654321);
+
+  // Discard them.
+  ReflectionOps::DiscardUnknownFields(&message);
+  MapTestUtil::ExpectMapFieldsSet(message);
+
+  EXPECT_EQ(0, message.GetReflection()->
+      GetUnknownFields(message).field_count());
+}
+
+// Wire Format Test =================================================
+
+TEST(WireFormatForMapFieldTest, ParseMap) {
+  unittest::TestMap source, dest;
+  string data;
+
+  // Serialize using the generated code.
+  MapTestUtil::SetMapFields(&source);
+  source.SerializeToString(&data);
+
+  // Parse using WireFormat.
+  io::ArrayInputStream raw_input(data.data(), data.size());
+  io::CodedInputStream input(&raw_input);
+  WireFormat::ParseAndMergePartial(&input, &dest);
+
+  // Check.
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(WireFormatForMapFieldTest, MapByteSize) {
+  unittest::TestMap message;
+  MapTestUtil::SetMapFields(&message);
+
+  EXPECT_EQ(message.ByteSize(), WireFormat::ByteSize(message));
+  message.Clear();
+  EXPECT_EQ(0, message.ByteSize());
+  EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatForMapFieldTest, SerializeMap) {
+  unittest::TestMap message;
+  string generated_data;
+  string dynamic_data;
+
+  MapTestUtil::SetMapFields(&message);
+
+  // Serialize using the generated code.
+  {
+    message.ByteSize();
+    io::StringOutputStream raw_output(&generated_data);
+    io::CodedOutputStream output(&raw_output);
+    message.SerializeWithCachedSizes(&output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Serialize using WireFormat.
+  {
+    io::StringOutputStream raw_output(&dynamic_data);
+    io::CodedOutputStream output(&raw_output);
+    int size = WireFormat::ByteSize(message);
+    WireFormat::SerializeWithCachedSizes(message, size, &output);
+    ASSERT_FALSE(output.HadError());
+  }
+
+  // Should be the same.
+  // Don't use EXPECT_EQ here because we're comparing raw binary data and
+  // we really don't want it dumped to stdout on failure.
+  EXPECT_TRUE(dynamic_data == generated_data);
+}
+
+TEST(WireFormatForMapFieldTest, MapParseHelpers) {
+  string data;
+
+  {
+    // Set up.
+    protobuf_unittest::TestMap message;
+    MapTestUtil::SetMapFields(&message);
+    message.SerializeToString(&data);
+  }
+
+  {
+    // Test ParseFromString.
+    protobuf_unittest::TestMap message;
+    EXPECT_TRUE(message.ParseFromString(data));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromIstream.
+    protobuf_unittest::TestMap message;
+    stringstream stream(data);
+    EXPECT_TRUE(message.ParseFromIstream(&stream));
+    EXPECT_TRUE(stream.eof());
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test ParseFromBoundedZeroCopyStream.
+    string data_with_junk(data);
+    data_with_junk.append("some junk on the end");
+    io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+    protobuf_unittest::TestMap message;
+    EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+    MapTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+    // EOF is reached before the expected number of bytes.
+    io::ArrayInputStream stream(data.data(), data.size());
+    protobuf_unittest::TestAllTypes message;
+    EXPECT_FALSE(
+      message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+  }
+}
+
+// Text Format Test =================================================
+
+TEST(TextFormatMapTest, SerializeAndParse) {
+  unittest::TestMap source;
+  unittest::TestMap dest;
+  MapTestUtil::SetMapFields(&source);
+  string output;
+
+  // Test compact ASCII
+  TextFormat::Printer printer;
+  printer.PrintToString(source, &output);
+  TextFormat::Parser parser;
+  EXPECT_TRUE(parser.ParseFromString(output, &dest));
+  MapTestUtil::ExpectMapFieldsSet(dest);
+}
+
+TEST(TextFormatMapTest, Sorted) {
+  unittest::TestMap message;
+  MapReflectionTester tester(message.GetDescriptor());
+  tester.SetMapFieldsViaReflection(&message);
+
+  string expected_text;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestSourceDir() +
+          "/google/protobuf/"
+          "testdata/map_test_data.txt",
+      &expected_text, true));
+
+  EXPECT_EQ(message.DebugString(), expected_text);
+
+  // Test again on the reverse order.
+  unittest::TestMap message2;
+  tester.SetMapFieldsViaReflection(&message2);
+  tester.SwapMapsViaReflection(&message2);
+  EXPECT_EQ(message2.DebugString(), expected_text);
+}
+
+
+// arena support =================================================
+TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
+  // Allocate a large initial block to avoid mallocs during hooked test.
+  std::vector<char> arena_block(128 * 1024);
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+  string data;
+  data.reserve(128 * 1024);
+
+  {
+    // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map.
+    // NoHeapChecker no_heap;
+
+    unittest::TestArenaMap* from =
+        Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+    MapTestUtil::SetArenaMapFields(from);
+    from->SerializeToString(&data);
+
+    unittest::TestArenaMap* to =
+        Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+    to->ParseFromString(data);
+    MapTestUtil::ExpectArenaMapFieldsSet(*to);
+  }
+}
+
+// Use text format parsing and serializing to test reflection api.
+TEST(ArenaTest, RelfectionInTextFormat) {
+  Arena arena;
+  string data;
+
+  TextFormat::Printer printer;
+  TextFormat::Parser parser;
+
+  unittest::TestArenaMap* from =
+      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+  unittest::TestArenaMap* to =
+      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+
+  MapTestUtil::SetArenaMapFields(from);
+  printer.PrintToString(*from, &data);
+
+  EXPECT_TRUE(parser.ParseFromString(data, to));
+  MapTestUtil::ExpectArenaMapFieldsSet(*to);
+}
+
+// Make sure the memory allocated for string in map is deallocated.
+TEST(ArenaTest, StringMapNoLeak) {
+  Arena arena;
+  unittest::TestArenaMap* message =
+      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+  string data;
+  // String with length less than 16 will not be allocated from heap.
+  int original_capacity = data.capacity();
+  while (data.capacity() <= original_capacity) {
+    data.append("a");
+  }
+  (*message->mutable_map_string_string())[data] = data;
+  // We rely on heap checkers to detect memory leak for us.
+  ASSERT_FALSE(message == NULL);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_test_util.cc b/src/google/protobuf/map_test_util.cc
new file mode 100644
index 0000000..ae09464
--- /dev/null
+++ b/src/google/protobuf/map_test_util.cc
@@ -0,0 +1,1801 @@
+// 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.
+
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/map_test_util_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+
+void MapTestUtil::SetMapFields(unittest::TestMap* message) {
+  MapTestUtilImpl::SetMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+                                unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::SetArenaMapFields(unittest::TestArenaMap* message) {
+  MapTestUtilImpl::SetArenaMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+                                     unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::SetMapFieldsInitialized(unittest::TestMap* message) {
+  MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+void MapTestUtil::ModifyMapFields(unittest::TestMap* message) {
+  MapTestUtilImpl::ModifyMapFields<unittest::MapEnum, unittest::MAP_ENUM_FOO>(
+      message);
+}
+
+void MapTestUtil::ExpectClear(const unittest::TestMap& message) {
+  MapTestUtilImpl::ExpectClear(message);
+}
+
+void MapTestUtil::ExpectMapFieldsSet(const unittest::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnum, unittest::MAP_ENUM_BAR,
+                                      unittest::MAP_ENUM_BAZ>(message);
+}
+
+void MapTestUtil::ExpectArenaMapFieldsSet(
+    const unittest::TestArenaMap& message) {
+  MapTestUtilImpl::ExpectArenaMapFieldsSet<
+      unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_BAZ>(
+      message);
+}
+
+void MapTestUtil::ExpectMapFieldsSetInitialized(
+    const unittest::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnum,
+                                                 unittest::MAP_ENUM_FOO>(
+      message);
+}
+
+void MapTestUtil::ExpectMapFieldsModified(
+    const unittest::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsModified<
+      unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_FOO>(
+      message);
+}
+
+void MapTestUtil::ExpectMapsSize(
+    const unittest::TestMap& message, int size) {
+  const Descriptor* descriptor = message.GetDescriptor();
+
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int32_int32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int64_int64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_uint32_uint32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_uint64_uint64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_sint32_sint32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_sint64_sint64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int32_float")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int32_double")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_bool_bool")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_string_string")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int32_bytes")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+    message, descriptor->FindFieldByName("map_int32_foreign_message")));
+}
+
+std::vector<const Message*> MapTestUtil::GetMapEntries(
+    const unittest::TestMap& message, int index) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_int32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int64_int64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_uint32_uint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_uint64_uint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_sint32_sint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_sint64_sint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_fixed32_fixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_fixed64_fixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_sfixed32_sfixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_sfixed64_sfixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_float"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_double"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_bool_bool"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_string_string"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_bytes"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_enum"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+    message, descriptor->FindFieldByName("map_int32_foreign_message"), index));
+
+  return result;
+}
+
+std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease(
+    unittest::TestMap* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_int32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int64_int64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_uint32_uint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_uint64_uint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_sint32_sint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_sint64_sint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_float")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_double")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_bool_bool")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_string_string")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_bytes")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_enum")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+    message, descriptor->FindFieldByName("map_int32_foreign_message")));
+
+  return result;
+}
+
+MapReflectionTester::MapReflectionTester(
+    const Descriptor* base_descriptor)
+  : base_descriptor_(base_descriptor) {
+  const DescriptorPool* pool = base_descriptor->file()->pool();
+
+  map_enum_foo_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_FOO");
+  map_enum_bar_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAR");
+  map_enum_baz_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAZ");
+
+  foreign_c_ = pool->FindFieldByName(
+      "protobuf_unittest.ForeignMessage.c");
+  map_int32_int32_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32Int32Entry.key");
+  map_int32_int32_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32Int32Entry.value");
+  map_int64_int64_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt64Int64Entry.key");
+  map_int64_int64_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt64Int64Entry.value");
+  map_uint32_uint32_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapUint32Uint32Entry.key");
+  map_uint32_uint32_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapUint32Uint32Entry.value");
+  map_uint64_uint64_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapUint64Uint64Entry.key");
+  map_uint64_uint64_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapUint64Uint64Entry.value");
+  map_sint32_sint32_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSint32Sint32Entry.key");
+  map_sint32_sint32_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSint32Sint32Entry.value");
+  map_sint64_sint64_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSint64Sint64Entry.key");
+  map_sint64_sint64_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSint64Sint64Entry.value");
+  map_fixed32_fixed32_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.key");
+  map_fixed32_fixed32_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.value");
+  map_fixed64_fixed64_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.key");
+  map_fixed64_fixed64_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.value");
+  map_sfixed32_sfixed32_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.key");
+  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.value");
+  map_sfixed64_sfixed64_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.key");
+  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.value");
+  map_int32_float_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32FloatEntry.key");
+  map_int32_float_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32FloatEntry.value");
+  map_int32_double_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32DoubleEntry.key");
+  map_int32_double_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32DoubleEntry.value");
+  map_bool_bool_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapBoolBoolEntry.key");
+  map_bool_bool_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapBoolBoolEntry.value");
+  map_string_string_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapStringStringEntry.key");
+  map_string_string_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapStringStringEntry.value");
+  map_int32_bytes_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32BytesEntry.key");
+  map_int32_bytes_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32BytesEntry.value");
+  map_int32_enum_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32EnumEntry.key");
+  map_int32_enum_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32EnumEntry.value");
+  map_int32_foreign_message_key_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.key");
+  map_int32_foreign_message_val_ = pool->FindFieldByName(
+      "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.value");
+
+  EXPECT_FALSE(map_enum_foo_ == NULL);
+  EXPECT_FALSE(map_enum_bar_ == NULL);
+  EXPECT_FALSE(map_enum_baz_ == NULL);
+  EXPECT_FALSE(map_int32_int32_key_ == NULL);
+  EXPECT_FALSE(map_int32_int32_val_ == NULL);
+  EXPECT_FALSE(map_int64_int64_key_ == NULL);
+  EXPECT_FALSE(map_int64_int64_val_ == NULL);
+  EXPECT_FALSE(map_uint32_uint32_key_ == NULL);
+  EXPECT_FALSE(map_uint32_uint32_val_ == NULL);
+  EXPECT_FALSE(map_uint64_uint64_key_ == NULL);
+  EXPECT_FALSE(map_uint64_uint64_val_ == NULL);
+  EXPECT_FALSE(map_sint32_sint32_key_ == NULL);
+  EXPECT_FALSE(map_sint32_sint32_val_ == NULL);
+  EXPECT_FALSE(map_sint64_sint64_key_ == NULL);
+  EXPECT_FALSE(map_sint64_sint64_val_ == NULL);
+  EXPECT_FALSE(map_fixed32_fixed32_key_ == NULL);
+  EXPECT_FALSE(map_fixed32_fixed32_val_ == NULL);
+  EXPECT_FALSE(map_fixed64_fixed64_key_ == NULL);
+  EXPECT_FALSE(map_fixed64_fixed64_val_ == NULL);
+  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == NULL);
+  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == NULL);
+  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == NULL);
+  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == NULL);
+  EXPECT_FALSE(map_int32_float_key_ == NULL);
+  EXPECT_FALSE(map_int32_float_val_ == NULL);
+  EXPECT_FALSE(map_int32_double_key_ == NULL);
+  EXPECT_FALSE(map_int32_double_val_ == NULL);
+  EXPECT_FALSE(map_bool_bool_key_ == NULL);
+  EXPECT_FALSE(map_bool_bool_val_ == NULL);
+  EXPECT_FALSE(map_string_string_key_ == NULL);
+  EXPECT_FALSE(map_string_string_val_ == NULL);
+  EXPECT_FALSE(map_int32_bytes_key_ == NULL);
+  EXPECT_FALSE(map_int32_bytes_val_ == NULL);
+  EXPECT_FALSE(map_int32_enum_key_ == NULL);
+  EXPECT_FALSE(map_int32_enum_val_ == NULL);
+  EXPECT_FALSE(map_int32_foreign_message_key_ == NULL);
+  EXPECT_FALSE(map_int32_foreign_message_val_ == NULL);
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
+const FieldDescriptor* MapReflectionTester::F(const string& name) {
+  const FieldDescriptor* result = NULL;
+  result = base_descriptor_->FindFieldByName(name);
+  GOOGLE_CHECK(result != NULL);
+  return result;
+}
+
+void MapReflectionTester::SetMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = NULL;
+  Message* sub_foreign_message = NULL;
+
+  // Add first element.
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_int32_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_int32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_int64_int64_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_int64_int64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_uint32_uint32_key_, 0);
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_uint32_uint32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_uint64_uint64_key_, 0);
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_uint64_uint64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sint32_sint32_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sint32_sint32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sint64_sint64_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sint64_sint64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_fixed32_fixed32_key_, 0);
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_fixed64_fixed64_key_, 0);
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sfixed32_sfixed32_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sfixed64_sfixed64_key_, 0);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_float_key_, 0);
+  sub_message->GetReflection()
+      ->SetFloat(sub_message, map_int32_float_val_, 0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_double_key_, 0);
+  sub_message->GetReflection()
+      ->SetDouble(sub_message, map_int32_double_val_, 0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()
+      ->SetBool(sub_message, map_bool_bool_key_, false);
+  sub_message->GetReflection()
+      ->SetBool(sub_message, map_bool_bool_val_, false);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_string_string_key_, "0");
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_string_string_val_, "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_bytes_key_, 0);
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_int32_bytes_val_, "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_enum_key_, 0);
+  sub_message->GetReflection()
+      ->SetEnum(sub_message, map_int32_enum_val_, map_enum_bar_);
+
+  sub_message = reflection
+      ->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_foreign_message_key_, 0);
+  sub_foreign_message = sub_message->GetReflection()->
+      MutableMessage(sub_message, map_int32_foreign_message_val_, NULL);
+  sub_foreign_message->GetReflection()->
+      SetInt32(sub_foreign_message, foreign_c_, 0);
+
+  // Add second element
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_int32_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_int32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_int64_int64_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_int64_int64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_uint32_uint32_key_, 1);
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_uint32_uint32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_uint64_uint64_key_, 1);
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_uint64_uint64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sint32_sint32_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sint32_sint32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sint64_sint64_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sint64_sint64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_fixed32_fixed32_key_, 1);
+  sub_message->GetReflection()
+      ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_fixed64_fixed64_key_, 1);
+  sub_message->GetReflection()
+      ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sfixed32_sfixed32_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sfixed64_sfixed64_key_, 1);
+  sub_message->GetReflection()
+      ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_float_key_, 1);
+  sub_message->GetReflection()
+      ->SetFloat(sub_message, map_int32_float_val_, 1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_double_key_, 1);
+  sub_message->GetReflection()
+      ->SetDouble(sub_message, map_int32_double_val_, 1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()
+      ->SetBool(sub_message, map_bool_bool_key_, true);
+  sub_message->GetReflection()
+      ->SetBool(sub_message, map_bool_bool_val_, true);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_string_string_key_, "1");
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_string_string_val_, "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_bytes_key_, 1);
+  sub_message->GetReflection()
+      ->SetString(sub_message, map_int32_bytes_val_, "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_enum_key_, 1);
+  sub_message->GetReflection()
+      ->SetEnum(sub_message, map_int32_enum_val_, map_enum_baz_);
+
+  sub_message = reflection
+      ->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()
+      ->SetInt32(sub_message, map_int32_foreign_message_key_, 1);
+  sub_foreign_message = sub_message->GetReflection()->
+      MutableMessage(sub_message, map_int32_foreign_message_val_, NULL);
+  sub_foreign_message->GetReflection()->
+      SetInt32(sub_foreign_message, foreign_c_, 1);
+}
+
+void MapReflectionTester::SetMapFieldsViaMapReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  Message* sub_foreign_message = NULL;
+  MapValueRef map_val;
+
+  // Add first element.
+  MapKey map_key;
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_int32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int64_int64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint64_uint64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint32_sint32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint64_sint64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed32_fixed32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed64_fixed64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_float"), map_key, &map_val));
+  map_val.SetFloatValue(0.0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_double"), map_key, &map_val));
+  map_val.SetDoubleValue(0.0);
+
+  map_key.SetBoolValue(false);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_bool_bool"), map_key, &map_val));
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("0");
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_bytes"), map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_enum"), map_key, &map_val));
+  map_val.SetEnumValue(map_enum_bar_->number());
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(
+      sub_foreign_message, foreign_c_, 0);
+
+  // Add second element
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_int32"), map_key, &map_val));
+  map_val.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_int32"), map_key, &map_val));
+
+  map_key.SetInt64Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int64_int64"), map_key, &map_val));
+  map_val.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int64_int64"), map_key, &map_val));
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_uint64_uint64"), map_key, &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sint32_sint32"), map_key, &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sint64_sint64"), map_key, &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_fixed32_fixed32"), map_key, &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_fixed64_fixed64"), map_key, &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed32_sfixed32"), map_key, &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed64_sfixed64"), map_key, &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_float"), map_key, &map_val);
+  map_val.SetFloatValue(1.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_double"), map_key, &map_val);
+  map_val.SetDoubleValue(1.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_bool_bool"), map_key, &map_val);
+  map_val.SetBoolValue(true);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_bytes"), map_key, &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_enum"), map_key, &map_val);
+  map_val.SetEnumValue(map_enum_baz_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(
+      sub_foreign_message, foreign_c_, 1);
+}
+
+void MapReflectionTester::ClearMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, F("map_int32_int32"));
+  reflection->ClearField(message, F("map_int64_int64"));
+  reflection->ClearField(message, F("map_uint32_uint32"));
+  reflection->ClearField(message, F("map_uint64_uint64"));
+  reflection->ClearField(message, F("map_sint32_sint32"));
+  reflection->ClearField(message, F("map_sint64_sint64"));
+  reflection->ClearField(message, F("map_fixed32_fixed32"));
+  reflection->ClearField(message, F("map_fixed64_fixed64"));
+  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
+  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
+  reflection->ClearField(message, F("map_int32_float"));
+  reflection->ClearField(message, F("map_int32_double"));
+  reflection->ClearField(message, F("map_bool_bool"));
+  reflection->ClearField(message, F("map_string_string"));
+  reflection->ClearField(message, F("map_int32_bytes"));
+  reflection->ClearField(message, F("map_int32_enum"));
+  reflection->ClearField(message, F("map_int32_foreign_message"));
+}
+
+void MapReflectionTester::ModifyMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  MapValueRef map_val;
+  Message* sub_foreign_message;
+
+  // Modify the second element
+  MapKey map_key;
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_int32"), map_key, &map_val));
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int64_int64"), map_key, &map_val));
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_uint64_uint64"), map_key, &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sint32_sint32"), map_key, &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sint64_sint64"), map_key, &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_fixed32_fixed32"), map_key, &map_val);
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_fixed64_fixed64"), map_key, &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed32_sfixed32"), map_key, &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed64_sfixed64"), map_key, &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_float"), map_key, &map_val);
+  map_val.SetFloatValue(2.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_double"), map_key, &map_val);
+  map_val.SetDoubleValue(2.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_bool_bool"), map_key, &map_val);
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_bytes"), map_key, &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(
+      message, F("map_int32_enum"), map_key, &map_val);
+  map_val.SetEnumValue(map_enum_foo_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(
+      sub_foreign_message, foreign_c_, 2);
+}
+
+void MapReflectionTester::RemoveLastMapsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->RemoveLast(message, field);
+  }
+}
+
+void MapReflectionTester::ReleaseLastMapsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    Message* released = reflection->ReleaseLast(message, field);
+    ASSERT_TRUE(released != NULL) << "ReleaseLast returned NULL for: "
+                                  << field->name();
+    delete released;
+  }
+}
+
+void MapReflectionTester::SwapMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->SwapElements(message, field, 0, 1);
+  }
+}
+
+void MapReflectionTester::
+    MutableUnknownFieldsOfMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = NULL;
+
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              NULL);
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflection(
+    const Message& message) {
+  string scratch;
+  const Reflection* reflection = message.GetReflection();
+  const Message* sub_message;
+  MapKey map_key;
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_int32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_int32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_TRUE(reflection->ContainsMapKey(
+          message, F("map_int32_int32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_int64_int64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_int64_int64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_TRUE(reflection->ContainsMapKey(
+          message, F("map_int64_int64"), map_key));
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+      uint32 key = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_uint32_uint32_key_);
+      uint32 val = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_uint32_uint32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt32Value(key);
+      EXPECT_TRUE(reflection->ContainsMapKey(
+          message, F("map_uint32_uint32"), map_key));
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+      uint64 key = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_uint64_uint64_key_);
+      uint64 val = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_uint64_uint64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt64Value(key);
+      EXPECT_TRUE(reflection->ContainsMapKey(
+          message, F("map_uint64_uint64"), map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sint32_sint32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sint32_sint32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_sint32_sint32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sint64_sint64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sint64_sint64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_sint64_sint64"), map_key));
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_fixed32_fixed32"), i);
+      uint32 key = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_fixed32_fixed32_key_);
+      uint32 val = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_fixed32_fixed32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_fixed32_fixed32"), map_key));
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_fixed64_fixed64"), i);
+      uint64 key = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_fixed64_fixed64_key_);
+      uint64 val = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_fixed64_fixed64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_fixed64_fixed64"), map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_sfixed32_sfixed32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sfixed32_sfixed32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sfixed32_sfixed32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_sfixed32_sfixed32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_sfixed64_sfixed64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sfixed64_sfixed64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sfixed64_sfixed64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_sfixed64_sfixed64"), map_key));
+    }
+  }
+  {
+    std::map<int32, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+      int32  key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_float_key_);
+      float val = sub_message->GetReflection()->GetFloat(
+          *sub_message, map_int32_float_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_int32_float"), map_key));
+    }
+  }
+  {
+    std::map<int32, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+      int32  key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_double_key_);
+      double val = sub_message->GetReflection()->GetDouble(
+          *sub_message, map_int32_double_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_int32_double"), map_key));
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+      bool key = sub_message->GetReflection()->GetBool(
+          *sub_message, map_bool_bool_key_);
+      bool val = sub_message->GetReflection()->GetBool(
+          *sub_message, map_bool_bool_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetBoolValue(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_bool_bool"), map_key));
+    }
+  }
+  {
+    std::map<string, string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+      string  key = sub_message->GetReflection()->GetString(
+          *sub_message, map_string_string_key_);
+      string val = sub_message->GetReflection()->GetString(
+          *sub_message, map_string_string_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetStringValue(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_string_string"), map_key));
+    }
+  }
+  {
+    std::map<int32, string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+      int32  key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_bytes_key_);
+      string val = sub_message->GetReflection()->GetString(
+          *sub_message, map_int32_bytes_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_int32_bytes"), map_key));
+    }
+  }
+  {
+    std::map<int32, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_int32_enum"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_enum_key_);
+      const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+          *sub_message, map_int32_enum_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_int32_enum"), map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_int32_foreign_message"), i);
+      int32  key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_foreign_message_key_);
+      const Message& foreign_message = sub_message->GetReflection()->GetMessage(
+          *sub_message, map_int32_foreign_message_val_);
+      int32 val = foreign_message.GetReflection()->GetInt32(
+          foreign_message, foreign_c_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+          message, F("map_int32_foreign_message"), map_key));
+    }
+  }
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    Message* message) {
+  string scratch;
+  string serialized;
+  const Reflection* reflection = message->GetReflection();
+
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32"));
+         iter != reflection->MapEnd(message, F("map_int32_int32"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsed();
+      message->ByteSize();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64"));
+         iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_uint32_uint32"));
+         iter != reflection->MapEnd(message, F("map_uint32_uint32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_uint64_uint64"));
+         iter != reflection->MapEnd(message, F("map_uint64_uint64"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_sint32_sint32"));
+         iter != reflection->MapEnd(message, F("map_sint32_sint32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_sint64_sint64"));
+         iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_fixed32_fixed32"));
+         iter != reflection->MapEnd(message, F("map_fixed32_fixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_fixed64_fixed64"));
+         iter != reflection->MapEnd(message, F("map_fixed64_fixed64"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_sfixed32_sfixed32"));
+         iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int32, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float"));
+         iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetFloatValue());
+    }
+  }
+  {
+    std::map<int32, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_int32_double"));
+         iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetDoubleValue());
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool"));
+         iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetBoolValue()],
+                iter.GetValueRef().GetBoolValue());
+    }
+  }
+  {
+    std::map<string, string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    int size = 0;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_string_string"));
+         iter != reflection->MapEnd(message, F("map_string_string"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsed();
+      message->ByteSize();
+      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
+                iter.GetValueRef().GetStringValue());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int32, string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes"));
+         iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetStringValue());
+    }
+  }
+  {
+    std::map<int32, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum"));
+         iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
+                iter.GetValueRef().GetEnumValue());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter = reflection->MapBegin(
+             message, F("map_int32_foreign_message"));
+         iter != reflection->MapEnd(message, F("map_int32_foreign_message"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsed();
+      message->ByteSize();
+      const Message& sub_message = iter.GetValueRef().GetMessageValue();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
+    }
+    EXPECT_EQ(size, 2);
+  }
+}
+
+void MapReflectionTester::ExpectClearViaReflection(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  // Map fields are empty.
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+}
+
+void MapReflectionTester::ExpectClearViaReflectionIterator(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) ==
+              reflection->MapEnd(message, F("map_int32_int32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) ==
+              reflection->MapEnd(message, F("map_int64_int64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) ==
+              reflection->MapEnd(message, F("map_uint32_uint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) ==
+              reflection->MapEnd(message, F("map_uint64_uint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) ==
+              reflection->MapEnd(message, F("map_sint32_sint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) ==
+              reflection->MapEnd(message, F("map_sint64_sint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) ==
+              reflection->MapEnd(message, F("map_fixed32_fixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) ==
+              reflection->MapEnd(message, F("map_fixed64_fixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) ==
+              reflection->MapEnd(message, F("map_sfixed32_sfixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) ==
+              reflection->MapEnd(message, F("map_sfixed64_sfixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) ==
+              reflection->MapEnd(message, F("map_int32_float")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) ==
+              reflection->MapEnd(message, F("map_int32_double")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) ==
+              reflection->MapEnd(message, F("map_bool_bool")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) ==
+              reflection->MapEnd(message, F("map_string_string")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) ==
+              reflection->MapEnd(message, F("map_int32_bytes")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) ==
+              reflection->MapEnd(message, F("map_int32_enum")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) ==
+              reflection->MapEnd(message, F("map_int32_foreign_message")));
+}
+
+void MapReflectionTester::ExpectMapEntryClearViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  const Message* sub_message;
+
+  {
+    const FieldDescriptor* descriptor = F("map_int32_int32");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_int64_int64");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_uint32_uint32");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+                                                         key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+                                                         value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_uint64_uint64");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+                                                         key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+                                                         value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_sint32_sint32");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_sint64_sint64");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_fixed32_fixed32");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+                                                         key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt32(*sub_message,
+                                                         value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_fixed64_fixed64");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+                                                         key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetUInt64(*sub_message,
+                                                         value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_sfixed32_sfixed32");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_sfixed64_sfixed64");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt64(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_int32_float");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int32_float"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetFloat(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_int32_double");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int32_double"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetDouble(*sub_message,
+                                                         value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_bool_bool");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+    EXPECT_EQ(false, sub_message->GetReflection()->GetBool(*sub_message,
+                                                           key_descriptor));
+    EXPECT_EQ(false, sub_message->GetReflection()->GetBool(*sub_message,
+                                                           value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_string_string");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_string_string"));
+    EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+                                                          key_descriptor));
+    EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+                                                          value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_int32_bytes");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ("", sub_message->GetReflection()->GetString(*sub_message,
+                                                        value_descriptor));
+  }
+  {
+    const FieldDescriptor* descriptor = F("map_int32_enum");
+    const FieldDescriptor* key_descriptor =
+        descriptor->message_type()->FindFieldByName("key");
+    const FieldDescriptor* value_descriptor =
+        descriptor->message_type()->FindFieldByName("value");
+    sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+    EXPECT_EQ(0, sub_message->GetReflection()->GetInt32(*sub_message,
+                                                        key_descriptor));
+    EXPECT_EQ(0, sub_message->GetReflection()
+                     ->GetEnum(*sub_message, value_descriptor)
+                     ->number());
+  }
+  // Map using message as value has been tested in other place. Thus, we don't
+  // test it here.
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
new file mode 100644
index 0000000..deaf0f4
--- /dev/null
+++ b/src/google/protobuf/map_test_util.h
@@ -0,0 +1,159 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
+
+#include <google/protobuf/map_unittest.pb.h>
+
+namespace google {
+namespace protobuf {
+
+namespace unittest = ::protobuf_unittest;
+
+class MapTestUtil {
+ public:
+  // Set every field in the TestMap message to a unique value.
+  static void SetMapFields(unittest::TestMap* message);
+
+  // Set every field in the TestArenaMap message to a unique value.
+  static void SetArenaMapFields(unittest::TestArenaMap* message);
+
+  // Set every field in the message to a default value.
+  static void SetMapFieldsInitialized(unittest::TestMap* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  static void ModifyMapFields(unittest::TestMap* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  static void ExpectMapFieldsSet(const unittest::TestMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMap.
+  static void ExpectArenaMapFieldsSet(const unittest::TestArenaMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  static void ExpectMapFieldsSetInitialized(
+      const unittest::TestMap& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  static void ExpectMapFieldsModified(const unittest::TestMap& message);
+
+  // Check that all fields are empty.
+  static void ExpectClear(const unittest::TestMap& message);
+
+  // Check that all map fields have the given size.
+  static void ExpectMapsSize(const unittest::TestMap& message, int size);
+
+  // Get pointers of map entries at given index.
+  static std::vector<const Message*> GetMapEntries(
+      const unittest::TestMap& message, int index);
+
+  // Get pointers of map entries from release.
+  static std::vector<const Message*> GetMapEntriesFromRelease(
+      unittest::TestMap* message);
+};
+
+// Like above, but use the reflection interface.
+class MapReflectionTester {
+ public:
+  // base_descriptor must be a descriptor for TestMap, which is used for
+  // MapReflectionTester to fetch the FieldDescriptors needed to use the
+  // reflection interface.
+  explicit MapReflectionTester(const Descriptor* base_descriptor);
+
+  void SetMapFieldsViaReflection(Message* message);
+  void SetMapFieldsViaMapReflection(Message* message);
+  void ClearMapFieldsViaReflection(Message* message);
+  void ModifyMapFieldsViaReflection(Message* message);
+  void RemoveLastMapsViaReflection(Message* message);
+  void ReleaseLastMapsViaReflection(Message* message);
+  void SwapMapsViaReflection(Message* message);
+  void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
+  void ExpectMapFieldsSetViaReflection(const Message& message);
+  void ExpectMapFieldsSetViaReflectionIterator(Message* message);
+  void ExpectClearViaReflection(const Message& message);
+  void ExpectClearViaReflectionIterator(Message* message);
+  void ExpectMapEntryClearViaReflection(Message* message);
+
+ private:
+  const FieldDescriptor* F(const string& name);
+
+  const Descriptor* base_descriptor_;
+
+  const EnumValueDescriptor* map_enum_bar_;
+  const EnumValueDescriptor* map_enum_baz_;
+  const EnumValueDescriptor* map_enum_foo_;
+
+  const FieldDescriptor* foreign_c_;
+  const FieldDescriptor* map_int32_int32_key_;
+  const FieldDescriptor* map_int32_int32_val_;
+  const FieldDescriptor* map_int64_int64_key_;
+  const FieldDescriptor* map_int64_int64_val_;
+  const FieldDescriptor* map_uint32_uint32_key_;
+  const FieldDescriptor* map_uint32_uint32_val_;
+  const FieldDescriptor* map_uint64_uint64_key_;
+  const FieldDescriptor* map_uint64_uint64_val_;
+  const FieldDescriptor* map_sint32_sint32_key_;
+  const FieldDescriptor* map_sint32_sint32_val_;
+  const FieldDescriptor* map_sint64_sint64_key_;
+  const FieldDescriptor* map_sint64_sint64_val_;
+  const FieldDescriptor* map_fixed32_fixed32_key_;
+  const FieldDescriptor* map_fixed32_fixed32_val_;
+  const FieldDescriptor* map_fixed64_fixed64_key_;
+  const FieldDescriptor* map_fixed64_fixed64_val_;
+  const FieldDescriptor* map_sfixed32_sfixed32_key_;
+  const FieldDescriptor* map_sfixed32_sfixed32_val_;
+  const FieldDescriptor* map_sfixed64_sfixed64_key_;
+  const FieldDescriptor* map_sfixed64_sfixed64_val_;
+  const FieldDescriptor* map_int32_float_key_;
+  const FieldDescriptor* map_int32_float_val_;
+  const FieldDescriptor* map_int32_double_key_;
+  const FieldDescriptor* map_int32_double_val_;
+  const FieldDescriptor* map_bool_bool_key_;
+  const FieldDescriptor* map_bool_bool_val_;
+  const FieldDescriptor* map_string_string_key_;
+  const FieldDescriptor* map_string_string_val_;
+  const FieldDescriptor* map_int32_bytes_key_;
+  const FieldDescriptor* map_int32_bytes_val_;
+  const FieldDescriptor* map_int32_enum_key_;
+  const FieldDescriptor* map_int32_enum_val_;
+  const FieldDescriptor* map_int32_foreign_message_key_;
+  const FieldDescriptor* map_int32_foreign_message_val_;
+};
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
new file mode 100644
index 0000000..b3ba4e0
--- /dev/null
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -0,0 +1,490 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
+#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+
+#define EXPECT_TRUE GOOGLE_CHECK
+#define ASSERT_TRUE GOOGLE_CHECK
+#define EXPECT_FALSE(COND) GOOGLE_CHECK(!(COND))
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+#define ASSERT_EQ GOOGLE_CHECK_EQ
+
+namespace google {
+namespace protobuf_unittest {}  // forward declaration
+
+namespace protobuf {
+
+namespace unittest = ::protobuf_unittest;
+
+class MapTestUtilImpl {
+ public:
+  // Set every field in the TestMap message to a unique value.
+  template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+  static void SetMapFields(MapMessage* message);
+
+  // Set every field in the TestArenaMap message to a unique value.
+  template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+  static void SetArenaMapFields(MapMessage* message);
+
+  // Set every field in the message to a default value.
+  template <typename MapMessage>
+  static void SetMapFieldsInitialized(MapMessage* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  template <typename EnumType, EnumType enum_value, typename MapMessage>
+  static void ModifyMapFields(MapMessage* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+  static void ExpectMapFieldsSet(const MapMessage& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMap.
+  template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+  static void ExpectArenaMapFieldsSet(const MapMessage& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  template <typename EnumType, EnumType enum_value, typename MapMessage>
+  static void ExpectMapFieldsSetInitialized(const MapMessage& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+  static void ExpectMapFieldsModified(const MapMessage& message);
+
+  // Check that all fields are empty.
+  template <typename MapMessage>
+  static void ExpectClear(const MapMessage& message);
+
+  // // Check that all map fields have the given size.
+  // template <typename MapMessage>
+  // static void ExpectMapsSize(const MapMessage& message, int size);
+
+  // // Get pointers of map entries at given index.
+  // static std::vector<const Message*> GetMapEntries(
+  //     const MapMessage& message, int index);
+
+  // // Get pointers of map entries from release.
+  // static std::vector<const Message*> GetMapEntriesFromRelease(
+  //     MapMessage* message);
+};
+
+template <typename EnumType, EnumType enum_value0,
+          EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::SetMapFields(MapMessage* message) {
+  // Add first element.
+  (*message->mutable_map_int32_int32())[0] = 0;
+  (*message->mutable_map_int64_int64())[0] = 0;
+  (*message->mutable_map_uint32_uint32())[0] = 0;
+  (*message->mutable_map_uint64_uint64())[0] = 0;
+  (*message->mutable_map_sint32_sint32())[0] = 0;
+  (*message->mutable_map_sint64_sint64())[0] = 0;
+  (*message->mutable_map_fixed32_fixed32())[0] = 0;
+  (*message->mutable_map_fixed64_fixed64())[0] = 0;
+  (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+  (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+  (*message->mutable_map_int32_float())[0] = 0.0;
+  (*message->mutable_map_int32_double())[0] = 0.0;
+  (*message->mutable_map_bool_bool())[0] = false;
+  (*message->mutable_map_string_string())["0"] = "0";
+  (*message->mutable_map_int32_bytes())[0] = "0";
+  (*message->mutable_map_int32_enum())[0] = enum_value0;
+  (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+
+  // Add second element
+  (*message->mutable_map_int32_int32())[1] = 1;
+  (*message->mutable_map_int64_int64())[1] = 1;
+  (*message->mutable_map_uint32_uint32())[1] = 1;
+  (*message->mutable_map_uint64_uint64())[1] = 1;
+  (*message->mutable_map_sint32_sint32())[1] = 1;
+  (*message->mutable_map_sint64_sint64())[1] = 1;
+  (*message->mutable_map_fixed32_fixed32())[1] = 1;
+  (*message->mutable_map_fixed64_fixed64())[1] = 1;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+  (*message->mutable_map_int32_float())[1] = 1.0;
+  (*message->mutable_map_int32_double())[1] = 1.0;
+  (*message->mutable_map_bool_bool())[1] = true;
+  (*message->mutable_map_string_string())["1"] = "1";
+  (*message->mutable_map_int32_bytes())[1] = "1";
+  (*message->mutable_map_int32_enum())[1] = enum_value1;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+}
+
+template <typename EnumType, EnumType enum_value0,
+          EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) {
+  // Add first element.
+  (*message->mutable_map_int32_int32())[0] = 0;
+  (*message->mutable_map_int64_int64())[0] = 0;
+  (*message->mutable_map_uint32_uint32())[0] = 0;
+  (*message->mutable_map_uint64_uint64())[0] = 0;
+  (*message->mutable_map_sint32_sint32())[0] = 0;
+  (*message->mutable_map_sint64_sint64())[0] = 0;
+  (*message->mutable_map_fixed32_fixed32())[0] = 0;
+  (*message->mutable_map_fixed64_fixed64())[0] = 0;
+  (*message->mutable_map_sfixed32_sfixed32())[0] = 0;
+  (*message->mutable_map_sfixed64_sfixed64())[0] = 0;
+  (*message->mutable_map_int32_float())[0] = 0.0;
+  (*message->mutable_map_int32_double())[0] = 0.0;
+  (*message->mutable_map_bool_bool())[0] = false;
+  (*message->mutable_map_string_string())["0"] = "0";
+  (*message->mutable_map_int32_bytes())[0] = "0";
+  (*message->mutable_map_int32_enum())[0] = enum_value0;
+  (*message->mutable_map_int32_foreign_message())[0].set_c(0);
+  (*message->mutable_map_int32_foreign_message_no_arena())[0].set_c(0);
+
+  // Add second element
+  (*message->mutable_map_int32_int32())[1] = 1;
+  (*message->mutable_map_int64_int64())[1] = 1;
+  (*message->mutable_map_uint32_uint32())[1] = 1;
+  (*message->mutable_map_uint64_uint64())[1] = 1;
+  (*message->mutable_map_sint32_sint32())[1] = 1;
+  (*message->mutable_map_sint64_sint64())[1] = 1;
+  (*message->mutable_map_fixed32_fixed32())[1] = 1;
+  (*message->mutable_map_fixed64_fixed64())[1] = 1;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 1;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 1;
+  (*message->mutable_map_int32_float())[1] = 1.0;
+  (*message->mutable_map_int32_double())[1] = 1.0;
+  (*message->mutable_map_bool_bool())[1] = true;
+  (*message->mutable_map_string_string())["1"] = "1";
+  (*message->mutable_map_int32_bytes())[1] = "1";
+  (*message->mutable_map_int32_enum())[1] = enum_value1;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(1);
+  (*message->mutable_map_int32_foreign_message_no_arena())[1].set_c(1);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::SetMapFieldsInitialized(MapMessage* message) {
+  // Add first element using bracket operator, which should assign default
+  // value automatically.
+  (*message->mutable_map_int32_int32())[0];
+  (*message->mutable_map_int64_int64())[0];
+  (*message->mutable_map_uint32_uint32())[0];
+  (*message->mutable_map_uint64_uint64())[0];
+  (*message->mutable_map_sint32_sint32())[0];
+  (*message->mutable_map_sint64_sint64())[0];
+  (*message->mutable_map_fixed32_fixed32())[0];
+  (*message->mutable_map_fixed64_fixed64())[0];
+  (*message->mutable_map_sfixed32_sfixed32())[0];
+  (*message->mutable_map_sfixed64_sfixed64())[0];
+  (*message->mutable_map_int32_float())[0];
+  (*message->mutable_map_int32_double())[0];
+  (*message->mutable_map_bool_bool())[0];
+  (*message->mutable_map_string_string())["0"];
+  (*message->mutable_map_int32_bytes())[0];
+  (*message->mutable_map_int32_enum())[0];
+  (*message->mutable_map_int32_foreign_message())[0];
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ModifyMapFields(MapMessage* message) {
+  (*message->mutable_map_int32_int32())[1] = 2;
+  (*message->mutable_map_int64_int64())[1] = 2;
+  (*message->mutable_map_uint32_uint32())[1] = 2;
+  (*message->mutable_map_uint64_uint64())[1] = 2;
+  (*message->mutable_map_sint32_sint32())[1] = 2;
+  (*message->mutable_map_sint64_sint64())[1] = 2;
+  (*message->mutable_map_fixed32_fixed32())[1] = 2;
+  (*message->mutable_map_fixed64_fixed64())[1] = 2;
+  (*message->mutable_map_sfixed32_sfixed32())[1] = 2;
+  (*message->mutable_map_sfixed64_sfixed64())[1] = 2;
+  (*message->mutable_map_int32_float())[1] = 2.0;
+  (*message->mutable_map_int32_double())[1] = 2.0;
+  (*message->mutable_map_bool_bool())[1] = false;
+  (*message->mutable_map_string_string())["1"] = "2";
+  (*message->mutable_map_int32_bytes())[1] = "2";
+  (*message->mutable_map_int32_enum())[1] = enum_value;
+  (*message->mutable_map_int32_foreign_message())[1].set_c(2);
+}
+
+template <typename MapMessage>
+void MapTestUtilImpl::ExpectClear(const MapMessage& message) {
+  EXPECT_EQ(0, message.map_int32_int32().size());
+  EXPECT_EQ(0, message.map_int64_int64().size());
+  EXPECT_EQ(0, message.map_uint32_uint32().size());
+  EXPECT_EQ(0, message.map_uint64_uint64().size());
+  EXPECT_EQ(0, message.map_sint32_sint32().size());
+  EXPECT_EQ(0, message.map_sint64_sint64().size());
+  EXPECT_EQ(0, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(0, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(0, message.map_int32_float().size());
+  EXPECT_EQ(0, message.map_int32_double().size());
+  EXPECT_EQ(0, message.map_bool_bool().size());
+  EXPECT_EQ(0, message.map_string_string().size());
+  EXPECT_EQ(0, message.map_int32_bytes().size());
+  EXPECT_EQ(0, message.map_int32_enum().size());
+  EXPECT_EQ(0, message.map_int32_foreign_message().size());
+}
+
+
+
+template <typename EnumType, EnumType enum_value0,
+          EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSet(const MapMessage& message) {
+  EXPECT_EQ(2, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int64_int64().size());
+  EXPECT_EQ(2, message.map_uint32_uint32().size());
+  EXPECT_EQ(2, message.map_uint64_uint64().size());
+  EXPECT_EQ(2, message.map_sint32_sint32().size());
+  EXPECT_EQ(2, message.map_sint64_sint64().size());
+  EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(2, message.map_int32_float().size());
+  EXPECT_EQ(2, message.map_int32_double().size());
+  EXPECT_EQ(2, message.map_bool_bool().size());
+  EXPECT_EQ(2, message.map_string_string().size());
+  EXPECT_EQ(2, message.map_int32_bytes().size());
+  EXPECT_EQ(2, message.map_int32_enum().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+  EXPECT_EQ(1, message.map_int64_int64().at(1));
+  EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(1, message.map_int32_float().at(1));
+  EXPECT_EQ(1, message.map_int32_double().at(1));
+  EXPECT_EQ(true, message.map_bool_bool().at(1));
+  EXPECT_EQ("1", message.map_string_string().at("1"));
+  EXPECT_EQ("1", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value0,
+          EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) {
+  EXPECT_EQ(2, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int64_int64().size());
+  EXPECT_EQ(2, message.map_uint32_uint32().size());
+  EXPECT_EQ(2, message.map_uint64_uint64().size());
+  EXPECT_EQ(2, message.map_sint32_sint32().size());
+  EXPECT_EQ(2, message.map_sint64_sint64().size());
+  EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(2, message.map_int32_float().size());
+  EXPECT_EQ(2, message.map_int32_double().size());
+  EXPECT_EQ(2, message.map_bool_bool().size());
+  EXPECT_EQ(2, message.map_string_string().size());
+  EXPECT_EQ(2, message.map_int32_bytes().size());
+  EXPECT_EQ(2, message.map_int32_enum().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message_no_arena().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+  EXPECT_EQ(0, message.map_int32_foreign_message_no_arena().at(0).c());
+
+  EXPECT_EQ(1, message.map_int32_int32().at(1));
+  EXPECT_EQ(1, message.map_int64_int64().at(1));
+  EXPECT_EQ(1, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(1, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(1, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(1, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(1, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(1, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(1, message.map_int32_float().at(1));
+  EXPECT_EQ(1, message.map_int32_double().at(1));
+  EXPECT_EQ(true, message.map_bool_bool().at(1));
+  EXPECT_EQ("1", message.map_string_string().at("1"));
+  EXPECT_EQ("1", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c());
+  EXPECT_EQ(1, message.map_int32_foreign_message_no_arena().at(1).c());
+}
+
+template <typename EnumType, EnumType enum_value, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsSetInitialized(
+    const MapMessage& message) {
+  EXPECT_EQ(1, message.map_int32_int32().size());
+  EXPECT_EQ(1, message.map_int64_int64().size());
+  EXPECT_EQ(1, message.map_uint32_uint32().size());
+  EXPECT_EQ(1, message.map_uint64_uint64().size());
+  EXPECT_EQ(1, message.map_sint32_sint32().size());
+  EXPECT_EQ(1, message.map_sint64_sint64().size());
+  EXPECT_EQ(1, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(1, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(1, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(1, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(1, message.map_int32_float().size());
+  EXPECT_EQ(1, message.map_int32_double().size());
+  EXPECT_EQ(1, message.map_bool_bool().size());
+  EXPECT_EQ(1, message.map_string_string().size());
+  EXPECT_EQ(1, message.map_int32_bytes().size());
+  EXPECT_EQ(1, message.map_int32_enum().size());
+  EXPECT_EQ(1, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("", message.map_string_string().at("0"));
+  EXPECT_EQ("", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).ByteSize());
+}
+
+template <typename EnumType, EnumType enum_value0,
+            EnumType enum_value1, typename MapMessage>
+void MapTestUtilImpl::ExpectMapFieldsModified(
+    const MapMessage& message) {
+  // ModifyMapFields only sets the second element of each field.  In addition to
+  // verifying this, we also verify that the first element and size were *not*
+  // modified.
+  EXPECT_EQ(2, message.map_int32_int32().size());
+  EXPECT_EQ(2, message.map_int64_int64().size());
+  EXPECT_EQ(2, message.map_uint32_uint32().size());
+  EXPECT_EQ(2, message.map_uint64_uint64().size());
+  EXPECT_EQ(2, message.map_sint32_sint32().size());
+  EXPECT_EQ(2, message.map_sint64_sint64().size());
+  EXPECT_EQ(2, message.map_fixed32_fixed32().size());
+  EXPECT_EQ(2, message.map_fixed64_fixed64().size());
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().size());
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().size());
+  EXPECT_EQ(2, message.map_int32_float().size());
+  EXPECT_EQ(2, message.map_int32_double().size());
+  EXPECT_EQ(2, message.map_bool_bool().size());
+  EXPECT_EQ(2, message.map_string_string().size());
+  EXPECT_EQ(2, message.map_int32_bytes().size());
+  EXPECT_EQ(2, message.map_int32_enum().size());
+  EXPECT_EQ(2, message.map_int32_foreign_message().size());
+
+  EXPECT_EQ(0, message.map_int32_int32().at(0));
+  EXPECT_EQ(0, message.map_int64_int64().at(0));
+  EXPECT_EQ(0, message.map_uint32_uint32().at(0));
+  EXPECT_EQ(0, message.map_uint64_uint64().at(0));
+  EXPECT_EQ(0, message.map_sint32_sint32().at(0));
+  EXPECT_EQ(0, message.map_sint64_sint64().at(0));
+  EXPECT_EQ(0, message.map_fixed32_fixed32().at(0));
+  EXPECT_EQ(0, message.map_fixed64_fixed64().at(0));
+  EXPECT_EQ(0, message.map_sfixed32_sfixed32().at(0));
+  EXPECT_EQ(0, message.map_sfixed64_sfixed64().at(0));
+  EXPECT_EQ(0, message.map_int32_float().at(0));
+  EXPECT_EQ(0, message.map_int32_double().at(0));
+  EXPECT_EQ(false, message.map_bool_bool().at(0));
+  EXPECT_EQ("0", message.map_string_string().at("0"));
+  EXPECT_EQ("0", message.map_int32_bytes().at(0));
+  EXPECT_EQ(enum_value0, message.map_int32_enum().at(0));
+  EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c());
+
+  // Actually verify the second (modified) elements now.
+  EXPECT_EQ(2, message.map_int32_int32().at(1));
+  EXPECT_EQ(2, message.map_int64_int64().at(1));
+  EXPECT_EQ(2, message.map_uint32_uint32().at(1));
+  EXPECT_EQ(2, message.map_uint64_uint64().at(1));
+  EXPECT_EQ(2, message.map_sint32_sint32().at(1));
+  EXPECT_EQ(2, message.map_sint64_sint64().at(1));
+  EXPECT_EQ(2, message.map_fixed32_fixed32().at(1));
+  EXPECT_EQ(2, message.map_fixed64_fixed64().at(1));
+  EXPECT_EQ(2, message.map_sfixed32_sfixed32().at(1));
+  EXPECT_EQ(2, message.map_sfixed64_sfixed64().at(1));
+  EXPECT_EQ(2, message.map_int32_float().at(1));
+  EXPECT_EQ(2, message.map_int32_double().at(1));
+  EXPECT_EQ(false, message.map_bool_bool().at(1));
+  EXPECT_EQ("2", message.map_string_string().at("1"));
+  EXPECT_EQ("2", message.map_int32_bytes().at(1));
+  EXPECT_EQ(enum_value1, message.map_int32_enum().at(1));
+  EXPECT_EQ(2, message.map_int32_foreign_message().at(1).c());
+}
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
new file mode 100644
index 0000000..f8ad758
--- /dev/null
+++ b/src/google/protobuf/map_type_handler.h
@@ -0,0 +1,727 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_TYPE_HANDLER_H__
+#define GOOGLE_PROTOBUF_TYPE_HANDLER_H__
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Used for compile time type selection. MapIf::type will be TrueType if Flag is
+// true and FalseType otherwise.
+template<bool Flag, typename TrueType, typename FalseType>
+struct MapIf;
+
+template<typename TrueType, typename FalseType>
+struct MapIf<true, TrueType, FalseType> {
+  typedef TrueType type;
+};
+
+template<typename TrueType, typename FalseType>
+struct MapIf<false, TrueType, FalseType> {
+  typedef FalseType type;
+};
+
+// In proto2 Map, enum needs to be initialized to given default value, while
+// other types' default value can be inferred from the type.
+template <bool IsEnum, typename Type>
+class MapValueInitializer {
+ public:
+  static inline void Initialize(Type& type, int default_enum_value);
+};
+
+template <typename Type>
+class MapValueInitializer<true, Type> {
+ public:
+  static inline void Initialize(Type& value, int default_enum_value) {
+    value = static_cast<Type>(default_enum_value);
+  }
+};
+
+template <typename Type>
+class MapValueInitializer<false, Type> {
+ public:
+  static inline void Initialize(Type& value, int default_enum_value) {}
+};
+
+template <typename Type, bool is_arena_constructable>
+class MapArenaMessageCreator {
+ public:
+  // Use arena to create message if Type is arena constructable. Otherwise,
+  // create the message on heap.
+  static inline Type* CreateMessage(Arena* arena);
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, true> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::CreateMessage<Type>(arena);
+  }
+};
+template <typename Type>
+class MapArenaMessageCreator<Type, false> {
+ public:
+  static inline Type* CreateMessage(Arena* arena) {
+    return Arena::Create<Type>(arena);
+  }
+};
+
+// Define constants for given wire field type
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapWireFieldTypeTraits {};
+
+#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum)   \
+  template <typename Type>                                                 \
+  class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> {   \
+   public:                                                                 \
+    static const bool kIsMessage = IsMessage;                              \
+    static const bool kIsEnum = IsEnum;                                    \
+    typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory;   \
+    typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \
+    static const WireFormatLite::WireType kWireType =                      \
+        WireFormatLite::WIRETYPE_##WireFormatType;                         \
+  };
+
+TYPE_TRAITS(MESSAGE , Type, LENGTH_DELIMITED, true, false)
+TYPE_TRAITS(STRING  , ArenaStringPtr, LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(BYTES   , ArenaStringPtr ,  LENGTH_DELIMITED, false, false)
+TYPE_TRAITS(INT64   , int64  ,  VARINT , false, false)
+TYPE_TRAITS(UINT64  , uint64 ,  VARINT , false, false)
+TYPE_TRAITS(INT32   , int32  ,  VARINT , false, false)
+TYPE_TRAITS(UINT32  , uint32 ,  VARINT , false, false)
+TYPE_TRAITS(SINT64  , int64  ,  VARINT , false, false)
+TYPE_TRAITS(SINT32  , int32  ,  VARINT , false, false)
+TYPE_TRAITS(ENUM    , int    ,  VARINT , false, true )
+TYPE_TRAITS(DOUBLE  , double ,  FIXED64, false, false)
+TYPE_TRAITS(FLOAT   , float  ,  FIXED32, false, false)
+TYPE_TRAITS(FIXED64 , uint64 ,  FIXED64, false, false)
+TYPE_TRAITS(FIXED32 , uint32 ,  FIXED32, false, false)
+TYPE_TRAITS(SFIXED64, int64  ,  FIXED64, false, false)
+TYPE_TRAITS(SFIXED32, int32  ,  FIXED32, false, false)
+TYPE_TRAITS(BOOL    , bool   ,  VARINT , false, false)
+
+#undef TYPE_TRAITS
+
+template <WireFormatLite::FieldType field_type, typename Type>
+class MapTypeHandler {};
+
+template <typename Type>
+class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
+ public:
+  // Enum type cannot be used for MapTypeHandler::Read. Define a type which will
+  // replace Enum with int.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+      Type>::MapEntryAccessorType MapEntryAccessorType;
+  // Internal stored type in MapEntryLite for given wire field type.
+  typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE,
+                                          Type>::TypeOnMemory TypeOnMemory;
+  // Corresponding wire type for field type.
+  static const WireFormatLite::WireType kWireType =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
+  // Whether wire type is for message.
+  static const bool kIsMessage =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
+  // Whether wire type is for enum.
+  static const bool kIsEnum =
+      MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
+
+  // Functions used in parsing and serialization. ===================
+  static inline int ByteSize(const MapEntryAccessorType& value);
+  static inline int GetCachedSize(const MapEntryAccessorType& value);
+  static inline bool Read(io::CodedInputStream* input,
+                          MapEntryAccessorType* value);
+  static inline void Write(int field, const MapEntryAccessorType& value,
+                           io::CodedOutputStream* output);
+  static inline uint8* WriteToArray(int field,
+                                    const MapEntryAccessorType& value,
+                                    uint8* output);
+
+  // Functions to manipulate data on memory. ========================
+  static inline const Type& GetExternalReference(const Type* value);
+  static inline void DeleteNoArena(const Type* x);
+  static inline void Merge(const Type& from, Type** to, Arena* arena);
+  static inline void Clear(Type** value, Arena* arena);
+  static inline void ClearMaybeByDefaultEnum(Type** value, Arena* arena,
+                                             int default_enum_value);
+  static inline void Initialize(Type** x, Arena* arena);
+
+  static inline void InitializeMaybeByDefaultEnum(Type** x,
+                                                  int default_enum_value,
+                                                  Arena* arena);
+  static inline Type* EnsureMutable(Type** value, Arena* arena);
+  // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
+  // those already calculate in sizeof(MapField).
+  static inline int SpaceUsedInMapEntry(const Type* value);
+  // Return bytes used by value in Map.
+  static inline int SpaceUsedInMap(const Type& value);
+  // Assign default value to given instance.
+  static inline void AssignDefaultValue(Type** value);
+  // Return default instance if value is not initialized when calling const
+  // reference accessor.
+  static inline const Type& DefaultIfNotInitialized(
+      const Type* value, const Type* default_value);
+  // Check if all required fields have values set.
+  static inline bool IsInitialized(Type* value);
+};
+
+#define MAP_HANDLER(FieldType)                                                \
+  template <typename Type>                                                    \
+  class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> {              \
+   public:                                                                    \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
+                                            Type>::MapEntryAccessorType       \
+        MapEntryAccessorType;                                                 \
+    typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
+                                            Type>::TypeOnMemory TypeOnMemory; \
+    static const WireFormatLite::WireType kWireType =                         \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
+                               Type>::kWireType;                              \
+    static const bool kIsMessage =                                            \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
+                               Type>::kIsMessage;                             \
+    static const bool kIsEnum =                                               \
+        MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType,              \
+                               Type>::kIsEnum;                                \
+    static inline int ByteSize(const MapEntryAccessorType& value);            \
+    static inline int GetCachedSize(const MapEntryAccessorType& value);       \
+    static inline bool Read(io::CodedInputStream* input,                      \
+                            MapEntryAccessorType* value);                     \
+    static inline void Write(int field, const MapEntryAccessorType& value,    \
+                             io::CodedOutputStream* output);                  \
+    static inline uint8* WriteToArray(int field,                              \
+                                      const MapEntryAccessorType& value,      \
+                                      uint8* output);                         \
+    static inline const MapEntryAccessorType& GetExternalReference(           \
+        const TypeOnMemory& value);                                           \
+    static inline void DeleteNoArena(const TypeOnMemory& x);                  \
+    static inline void Merge(const MapEntryAccessorType& from,                \
+                             TypeOnMemory* to, Arena* arena);                 \
+    static inline void Clear(TypeOnMemory* value, Arena* arena);              \
+    static inline void ClearMaybeByDefaultEnum(TypeOnMemory* value,           \
+                                               Arena* arena,                  \
+                                               int default_enum);             \
+    static inline int SpaceUsedInMapEntry(const TypeOnMemory& value);         \
+    static inline int SpaceUsedInMap(const TypeOnMemory& value);              \
+    static inline int SpaceUsedInMap(const string& value);                    \
+    static inline void AssignDefaultValue(TypeOnMemory* value);               \
+    static inline const MapEntryAccessorType& DefaultIfNotInitialized(        \
+        const TypeOnMemory& value, const TypeOnMemory& default_value);        \
+    static inline bool IsInitialized(const TypeOnMemory& value);              \
+    static void DeleteNoArena(TypeOnMemory& value);                           \
+    static inline void Initialize(TypeOnMemory* value, Arena* arena);         \
+    static inline void InitializeMaybeByDefaultEnum(TypeOnMemory* value,      \
+                                                    int default_enum_value,   \
+                                                    Arena* arena);            \
+    static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value,    \
+                                                      Arena* arena);          \
+  };
+MAP_HANDLER(STRING)
+MAP_HANDLER(BYTES)
+MAP_HANDLER(INT64)
+MAP_HANDLER(UINT64)
+MAP_HANDLER(INT32)
+MAP_HANDLER(UINT32)
+MAP_HANDLER(SINT64)
+MAP_HANDLER(SINT32)
+MAP_HANDLER(ENUM)
+MAP_HANDLER(DOUBLE)
+MAP_HANDLER(FLOAT)
+MAP_HANDLER(FIXED64)
+MAP_HANDLER(FIXED32)
+MAP_HANDLER(SFIXED64)
+MAP_HANDLER(SFIXED32)
+MAP_HANDLER(BOOL)
+#undef MAP_HANDLER
+
+template <typename Type>
+inline int
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize(
+    const MapEntryAccessorType& value) {
+  return WireFormatLite::MessageSizeNoVirtual(value);
+}
+
+#define GOOGLE_PROTOBUF_BYTE_SIZE(FieldType, DeclaredType)                     \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& value) {                                     \
+    return WireFormatLite::DeclaredType##Size(value);                          \
+  }
+
+GOOGLE_PROTOBUF_BYTE_SIZE(STRING, String)
+GOOGLE_PROTOBUF_BYTE_SIZE(BYTES , Bytes)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT64 , Int64)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT64, UInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(INT32 , Int32)
+GOOGLE_PROTOBUF_BYTE_SIZE(UINT32, UInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT64, SInt64)
+GOOGLE_PROTOBUF_BYTE_SIZE(SINT32, SInt32)
+GOOGLE_PROTOBUF_BYTE_SIZE(ENUM  , Enum)
+
+#undef GOOGLE_PROTOBUF_BYTE_SIZE
+
+#define FIXED_BYTE_SIZE(FieldType, DeclaredType)                               \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \
+      const MapEntryAccessorType& value) {                                     \
+    return WireFormatLite::k##DeclaredType##Size;                              \
+  }
+
+FIXED_BYTE_SIZE(DOUBLE  , Double)
+FIXED_BYTE_SIZE(FLOAT   , Float)
+FIXED_BYTE_SIZE(FIXED64 , Fixed64)
+FIXED_BYTE_SIZE(FIXED32 , Fixed32)
+FIXED_BYTE_SIZE(SFIXED64, SFixed64)
+FIXED_BYTE_SIZE(SFIXED32, SFixed32)
+FIXED_BYTE_SIZE(BOOL    , Bool)
+
+#undef FIXED_BYTE_SIZE
+
+template <typename Type>
+inline int
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetCachedSize(
+    const MapEntryAccessorType& value) {
+  return WireFormatLite::LengthDelimitedSize(value.GetCachedSize());
+}
+
+#define GET_CACHED_SIZE(FieldType, DeclaredType)                         \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& value) {                               \
+    return WireFormatLite::DeclaredType##Size(value);                    \
+  }
+
+GET_CACHED_SIZE(STRING, String)
+GET_CACHED_SIZE(BYTES , Bytes)
+GET_CACHED_SIZE(INT64 , Int64)
+GET_CACHED_SIZE(UINT64, UInt64)
+GET_CACHED_SIZE(INT32 , Int32)
+GET_CACHED_SIZE(UINT32, UInt32)
+GET_CACHED_SIZE(SINT64, SInt64)
+GET_CACHED_SIZE(SINT32, SInt32)
+GET_CACHED_SIZE(ENUM  , Enum)
+
+#undef GET_CACHED_SIZE
+
+#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType)                   \
+  template <typename Type>                                               \
+  inline int                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \
+      const MapEntryAccessorType& value) {                               \
+    return WireFormatLite::k##DeclaredType##Size;                        \
+  }
+
+GET_FIXED_CACHED_SIZE(DOUBLE  , Double)
+GET_FIXED_CACHED_SIZE(FLOAT   , Float)
+GET_FIXED_CACHED_SIZE(FIXED64 , Fixed64)
+GET_FIXED_CACHED_SIZE(FIXED32 , Fixed32)
+GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64)
+GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32)
+GET_FIXED_CACHED_SIZE(BOOL    , Bool)
+
+#undef GET_FIXED_CACHED_SIZE
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
+    int field, const MapEntryAccessorType& value,
+    io::CodedOutputStream* output) {
+  WireFormatLite::WriteMessageMaybeToArray(field, value, output);
+}
+
+template <typename Type>
+inline uint8*
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray(
+    int field, const MapEntryAccessorType& value, uint8* output) {
+  return WireFormatLite::WriteMessageToArray(field, value, output);
+}
+
+#define WRITE_METHOD(FieldType, DeclaredType)                                  \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(   \
+      int field, const MapEntryAccessorType& value,                            \
+      io::CodedOutputStream* output) {                                         \
+    return WireFormatLite::Write##DeclaredType(field, value, output);          \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline uint8*                                                                \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray(        \
+      int field, const MapEntryAccessorType& value, uint8* output) {           \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
+  }
+
+WRITE_METHOD(STRING  , String)
+WRITE_METHOD(BYTES   , Bytes)
+WRITE_METHOD(INT64   , Int64)
+WRITE_METHOD(UINT64  , UInt64)
+WRITE_METHOD(INT32   , Int32)
+WRITE_METHOD(UINT32  , UInt32)
+WRITE_METHOD(SINT64  , SInt64)
+WRITE_METHOD(SINT32  , SInt32)
+WRITE_METHOD(ENUM    , Enum)
+WRITE_METHOD(DOUBLE  , Double)
+WRITE_METHOD(FLOAT   , Float)
+WRITE_METHOD(FIXED64 , Fixed64)
+WRITE_METHOD(FIXED32 , Fixed32)
+WRITE_METHOD(SFIXED64, SFixed64)
+WRITE_METHOD(SFIXED32, SFixed32)
+WRITE_METHOD(BOOL    , Bool)
+
+#undef WRITE_METHOD
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadMessageNoVirtual(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadString(input, value);
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    io::CodedInputStream* input, MapEntryAccessorType* value) {
+  return WireFormatLite::ReadBytes(input, value);
+}
+
+#define READ_METHOD(FieldType)                                              \
+  template <typename Type>                                                  \
+  inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
+      io::CodedInputStream* input, MapEntryAccessorType* value) {           \
+    return WireFormatLite::ReadPrimitive<TypeOnMemory,                      \
+                                         WireFormatLite::TYPE_##FieldType>( \
+        input, value);                                                      \
+  }
+
+READ_METHOD(INT64)
+READ_METHOD(UINT64)
+READ_METHOD(INT32)
+READ_METHOD(UINT32)
+READ_METHOD(SINT64)
+READ_METHOD(SINT32)
+READ_METHOD(ENUM)
+READ_METHOD(DOUBLE)
+READ_METHOD(FLOAT)
+READ_METHOD(FIXED64)
+READ_METHOD(FIXED32)
+READ_METHOD(SFIXED64)
+READ_METHOD(SFIXED32)
+READ_METHOD(BOOL)
+
+#undef READ_METHOD
+
+// Definition for message handler
+
+template <typename Type>
+inline const Type&
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                        Type>::GetExternalReference(const Type* value) {
+  return *value;
+}
+
+template <typename Type>
+inline int
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                        Type>::SpaceUsedInMapEntry(const Type* value) {
+  return value->SpaceUsed();
+}
+
+template <typename Type>
+int MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::SpaceUsedInMap(
+    const Type& value) {
+  return value.SpaceUsed();
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear(
+    Type** value, Arena* arena) {
+  if (*value != NULL) (*value)->Clear();
+}
+template <typename Type>
+inline void
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                        Type>::ClearMaybeByDefaultEnum(Type** value,
+                                                       Arena* arena,
+                                                       int default_enum_value) {
+  if (*value != NULL) (*value)->Clear();
+}
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Merge(
+    const Type& from, Type** to, Arena* arena) {
+  (*to)->MergeFrom(from);
+}
+
+template <typename Type>
+void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena(
+    const Type* ptr) {
+  delete ptr;
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                                    Type>::AssignDefaultValue(Type** value) {
+  *value = const_cast<Type*>(&Type::default_instance());
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                                    Type>::Initialize(Type** x,
+                                                      Arena* arena) {
+  *x = NULL;
+}
+
+template <typename Type>
+inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::
+    InitializeMaybeByDefaultEnum(Type** x, int default_enum_value,
+                                 Arena* arena) {
+  *x = NULL;
+}
+
+template <typename Type>
+inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                                     Type>::EnsureMutable(Type** value,
+                                                          Arena* arena) {
+  if (*value == NULL) {
+    *value =
+        MapArenaMessageCreator<Type, Arena::is_arena_constructable<Type>::
+                                         type::value>::CreateMessage(arena);
+  }
+  return *value;
+}
+
+template <typename Type>
+inline const Type& MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::
+    DefaultIfNotInitialized(const Type* value, const Type* default_value) {
+  return value != NULL ? *value : *default_value;
+}
+
+template <typename Type>
+inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
+                                    Type>::IsInitialized(Type* value) {
+  return value->IsInitialized();
+}
+
+// Definition for string/bytes handler
+
+#define STRING_OR_BYTES_HANDLER_FUNCTIONS(FieldType)                           \
+  template <typename Type>                                                     \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,       \
+                                       Type>::MapEntryAccessorType&            \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::GetExternalReference(const TypeOnMemory& value) {      \
+    return value.Get(&::google::protobuf::internal::GetEmptyString());                   \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline int                                                                   \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapEntry( \
+      const TypeOnMemory& value) {                                             \
+    return sizeof(value);                                                      \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType,                  \
+                            Type>::SpaceUsedInMap(const TypeOnMemory& value) { \
+    return sizeof(value);                                                      \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType,                  \
+                            Type>::SpaceUsedInMap(const string& value) {       \
+    return sizeof(value);                                                      \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear(   \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    value->ClearToEmpty(&::google::protobuf::internal::GetEmptyString(), arena);         \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::ClearMaybeByDefaultEnum(TypeOnMemory* value,           \
+                                                Arena* arena,                  \
+                                                int default_enum) {            \
+    Clear(value, arena);                                                       \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge(   \
+      const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) {      \
+    to->Set(&::google::protobuf::internal::GetEmptyString(), from, arena);               \
+  }                                                                            \
+  template <typename Type>                                                     \
+  void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena(  \
+      TypeOnMemory& value) {                                                   \
+    value.DestroyNoArena(&::google::protobuf::internal::GetEmptyString());               \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
+                             Type>::AssignDefaultValue(TypeOnMemory* value) {} \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize(          \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    value->UnsafeSetDefault(&::google::protobuf::internal::GetEmptyString());            \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::InitializeMaybeByDefaultEnum(TypeOnMemory* value,      \
+                                                     int default_enum_value,   \
+                                                     Arena* arena) {           \
+    Initialize(value, arena);                                                  \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,             \
+                                 Type>::MapEntryAccessorType*                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(       \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    return value->Mutable(&::google::protobuf::internal::GetEmptyString(), arena);       \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,       \
+                                       Type>::MapEntryAccessorType&            \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::DefaultIfNotInitialized(const TypeOnMemory& value,     \
+                                                const TypeOnMemory&            \
+                                                    default_value) {           \
+    return value.Get(&::google::protobuf::internal::GetEmptyString());                   \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
+                             Type>::IsInitialized(const TypeOnMemory& value) { \
+    return true;                                                               \
+  }
+STRING_OR_BYTES_HANDLER_FUNCTIONS(STRING)
+STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES)
+#undef STRING_OR_BYTES_HANDLER_FUNCTIONS
+
+#define PRIMITIVE_HANDLER_FUNCTIONS(FieldType)                                 \
+  template <typename Type>                                                     \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,       \
+                                       Type>::MapEntryAccessorType&            \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::GetExternalReference(const TypeOnMemory& value) {      \
+    return value;                                                              \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline int                                                                   \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapEntry( \
+      const TypeOnMemory& value) {                                             \
+    return 0;                                                                  \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType,                  \
+                            Type>::SpaceUsedInMap(const TypeOnMemory& value) { \
+    return sizeof(Type);                                                       \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear(   \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    *value = 0;                                                                \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::ClearMaybeByDefaultEnum(TypeOnMemory* value,           \
+                                                Arena* arena,                  \
+                                                int default_enum_value) {      \
+    *value = static_cast<TypeOnMemory>(default_enum_value);                    \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge(   \
+      const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) {      \
+    *to = from;                                                                \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
+                             Type>::DeleteNoArena(TypeOnMemory& x) {}          \
+  template <typename Type>                                                     \
+  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
+                             Type>::AssignDefaultValue(TypeOnMemory* value) {} \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize(          \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    *value = 0;                                                                \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline void                                                                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::InitializeMaybeByDefaultEnum(TypeOnMemory* value,      \
+                                                     int default_enum_value,   \
+                                                     Arena* arena) {           \
+    *value = static_cast<TypeOnMemory>(default_enum_value);                    \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,             \
+                                 Type>::MapEntryAccessorType*                  \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(       \
+      TypeOnMemory* value, Arena* arena) {                                     \
+    return value;                                                              \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,       \
+                                       Type>::MapEntryAccessorType&            \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::DefaultIfNotInitialized(const TypeOnMemory& value,     \
+                                                const TypeOnMemory&            \
+                                                    default_value) {           \
+    return value;                                                              \
+  }                                                                            \
+  template <typename Type>                                                     \
+  inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
+                             Type>::IsInitialized(const TypeOnMemory& value) { \
+    return true;                                                               \
+  }
+PRIMITIVE_HANDLER_FUNCTIONS(INT64)
+PRIMITIVE_HANDLER_FUNCTIONS(UINT64)
+PRIMITIVE_HANDLER_FUNCTIONS(INT32)
+PRIMITIVE_HANDLER_FUNCTIONS(UINT32)
+PRIMITIVE_HANDLER_FUNCTIONS(SINT64)
+PRIMITIVE_HANDLER_FUNCTIONS(SINT32)
+PRIMITIVE_HANDLER_FUNCTIONS(ENUM)
+PRIMITIVE_HANDLER_FUNCTIONS(DOUBLE)
+PRIMITIVE_HANDLER_FUNCTIONS(FLOAT)
+PRIMITIVE_HANDLER_FUNCTIONS(FIXED64)
+PRIMITIVE_HANDLER_FUNCTIONS(FIXED32)
+PRIMITIVE_HANDLER_FUNCTIONS(SFIXED64)
+PRIMITIVE_HANDLER_FUNCTIONS(SFIXED32)
+PRIMITIVE_HANDLER_FUNCTIONS(BOOL)
+#undef PRIMITIVE_HANDLER_FUNCTIONS
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_TYPE_HANDLER_H__
diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto
new file mode 100644
index 0000000..aea1e8c
--- /dev/null
+++ b/src/google/protobuf/map_unittest.proto
@@ -0,0 +1,129 @@
+// 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.
+
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest.proto";
+import "google/protobuf/unittest_no_arena.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Tests maps.
+message TestMap {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<string  , string  > map_string_string     = 14;
+  map<int32   , bytes   > map_int32_bytes       = 15;
+  map<int32   , MapEnum > map_int32_enum        = 16;
+  map<int32   , ForeignMessage> map_int32_foreign_message = 17;
+  map<string  , ForeignMessage> map_string_foreign_message = 18;
+}
+
+message TestMapSubmessage {
+  TestMap test_map = 1;
+}
+
+message TestMessageMap {
+  map<int32, TestAllTypes> map_int32_message = 1;
+}
+
+// Two map fields share the same entry default instance.
+message TestSameTypeMap {
+  map<int32, int32> map1 = 1;
+  map<int32, int32> map2 = 2;
+}
+
+
+enum MapEnum {
+  MAP_ENUM_FOO = 0;
+  MAP_ENUM_BAR = 1;
+  MAP_ENUM_BAZ = 2;
+}
+
+// Test embeded message with required fields
+message TestRequiredMessageMap {
+  map<int32, TestRequired> map_field = 1;
+}
+
+message TestArenaMap {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<string  , string  > map_string_string     = 14;
+  map<int32   , bytes   > map_int32_bytes       = 15;
+  map<int32   , MapEnum > map_int32_enum        = 16;
+  map<int32   , ForeignMessage> map_int32_foreign_message = 17;
+  map<int32, .protobuf_unittest_no_arena.ForeignMessage>
+      map_int32_foreign_message_no_arena = 18;
+}
+
+// Previously, message containing enum called Type cannot be used as value of
+// map field.
+message MessageContainingEnumCalledType {
+  enum Type {
+    TYPE_FOO = 0;
+  }
+  map<string, MessageContainingEnumCalledType> type = 1;
+}
+
+// Previously, message cannot contain map field called "entry".
+message MessageContainingMapCalledEntry {
+  map<int32, int32> entry = 1;
+}
+
+message TestRecursiveMapMessage {
+  map<string, TestRecursiveMapMessage> a = 1;
+}
diff --git a/src/google/protobuf/map_unittest_proto3.proto b/src/google/protobuf/map_unittest_proto3.proto
new file mode 100644
index 0000000..16be277
--- /dev/null
+++ b/src/google/protobuf/map_unittest_proto3.proto
@@ -0,0 +1,120 @@
+// 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.
+
+// This file is mostly equivalent to map_unittest.proto, but imports
+// unittest_proto3.proto instead of unittest.proto, so that it only
+// uses proto3 messages. This makes it suitable for testing
+// implementations which only support proto3.
+// The TestRequiredMessageMap message has been removed as there are no
+// required fields in proto3.
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+import "google/protobuf/unittest_proto3.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Tests maps.
+message TestMap {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<string  , string  > map_string_string     = 14;
+  map<int32   , bytes   > map_int32_bytes       = 15;
+  map<int32   , MapEnum > map_int32_enum        = 16;
+  map<int32   , ForeignMessage> map_int32_foreign_message = 17;
+}
+
+message TestMapSubmessage {
+  TestMap test_map = 1;
+}
+
+message TestMessageMap {
+  map<int32, TestAllTypes> map_int32_message = 1;
+}
+
+// Two map fields share the same entry default instance.
+message TestSameTypeMap {
+  map<int32, int32> map1 = 1;
+  map<int32, int32> map2 = 2;
+}
+
+enum MapEnum {
+  MAP_ENUM_FOO = 0;
+  MAP_ENUM_BAR = 1;
+  MAP_ENUM_BAZ = 2;
+}
+
+message TestArenaMap {
+  map<int32   , int32   > map_int32_int32       = 1;
+  map<int64   , int64   > map_int64_int64       = 2;
+  map<uint32  , uint32  > map_uint32_uint32     = 3;
+  map<uint64  , uint64  > map_uint64_uint64     = 4;
+  map<sint32  , sint32  > map_sint32_sint32     = 5;
+  map<sint64  , sint64  > map_sint64_sint64     = 6;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 7;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 8;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
+  map<int32   , float   > map_int32_float       = 11;
+  map<int32   , double  > map_int32_double      = 12;
+  map<bool    , bool    > map_bool_bool         = 13;
+  map<int32   , MapEnum > map_int32_enum        = 14;
+  map<int32   , ForeignMessage> map_int32_foreign_message = 15;
+}
+
+// Previously, message containing enum called Type cannot be used as value of
+// map field.
+message MessageContainingEnumCalledType {
+  enum Type {
+    TYPE_FOO = 0;
+  }
+  map<int32, MessageContainingEnumCalledType> type = 1;
+}
+
+// Previously, message cannot contain map field called "entry".
+message MessageContainingMapCalledEntry {
+  map<int32, int32> entry = 1;
+}
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 1324ed9..d62ca79 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -38,17 +38,22 @@
 
 #include <google/protobuf/message.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/once.h>
+#include <google/protobuf/reflection_internal.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/map_field.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/reflection_ops.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/singleton.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 namespace google {
@@ -64,7 +69,7 @@
   GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
     << ": Tried to merge from a message with a different type.  "
        "to: " << descriptor->full_name() << ", "
-       "from:" << from.GetDescriptor()->full_name();
+       "from: " << from.GetDescriptor()->full_name();
   ReflectionOps::Merge(from, this);
 }
 
@@ -77,7 +82,7 @@
   GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
     << ": Tried to copy from a message with a different type. "
        "to: " << descriptor->full_name() << ", "
-       "from:" << from.GetDescriptor()->full_name();
+       "from: " << from.GetDescriptor()->full_name();
   ReflectionOps::Copy(from, this);
 }
 
@@ -222,6 +227,54 @@
 }
 
 
+// Default EnumValue API implementations. Real reflection implementations should
+// override these. However, there are several legacy implementations that do
+// not, and cannot easily be changed at the same time as the Reflection API, so
+// we provide these for now.
+// TODO: Remove these once all Reflection implementations are updated.
+int Reflection::GetEnumValue(const Message& message,
+                             const FieldDescriptor* field) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API.";
+  return 0;
+}
+void Reflection::SetEnumValue(Message* message,
+                  const FieldDescriptor* field,
+                  int value) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API.";
+}
+int Reflection::GetRepeatedEnumValue(
+    const Message& message,
+    const FieldDescriptor* field, int index) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API.";
+  return 0;
+}
+void Reflection::SetRepeatedEnumValue(Message* message,
+                                  const FieldDescriptor* field, int index,
+                                  int value) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API.";
+}
+void Reflection::AddEnumValue(Message* message,
+                  const FieldDescriptor* field,
+                  int value) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API.";
+}
+
+MapIterator Reflection::MapBegin(
+    Message* message,
+    const FieldDescriptor* field) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API.";
+  MapIterator iter(message, field);
+  return iter;
+}
+
+MapIterator Reflection::MapEnd(
+    Message* message,
+    const FieldDescriptor* field) const {
+  GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API.";
+  MapIterator iter(message, field);
+  return iter;
+}
+
 // =============================================================================
 // MessageFactory
 
@@ -354,5 +407,111 @@
 }
 
 
+MessageFactory* Reflection::GetMessageFactory() const {
+  GOOGLE_LOG(FATAL) << "Not implemented.";
+  return NULL;
+}
+
+void* Reflection::RepeatedFieldData(
+    Message* message, const FieldDescriptor* field,
+    FieldDescriptor::CppType cpp_type,
+    const Descriptor* message_type) const {
+  GOOGLE_LOG(FATAL) << "Not implemented.";
+  return NULL;
+}
+
+namespace internal {
+RepeatedFieldAccessor::~RepeatedFieldAccessor() {
+}
+}  // namespace internal
+
+const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK(field->is_repeated());
+  switch (field->cpp_type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
+    case FieldDescriptor::CPPTYPE_ ## TYPE: \
+      return internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<type> >::get();
+    HANDLE_PRIMITIVE_TYPE(INT32, int32)
+    HANDLE_PRIMITIVE_TYPE(UINT32, uint32)
+    HANDLE_PRIMITIVE_TYPE(INT64, int64)
+    HANDLE_PRIMITIVE_TYPE(UINT64, uint64)
+    HANDLE_PRIMITIVE_TYPE(FLOAT, float)
+    HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
+    HANDLE_PRIMITIVE_TYPE(BOOL, bool)
+    HANDLE_PRIMITIVE_TYPE(ENUM, int32)
+#undef HANDLE_PRIMITIVE_TYPE
+    case FieldDescriptor::CPPTYPE_STRING:
+      switch (field->options().ctype()) {
+        default:
+        case FieldOptions::STRING:
+          return internal::Singleton<internal::RepeatedPtrFieldStringAccessor>::get();
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      if (field->is_map()) {
+        return internal::Singleton<internal::MapFieldAccessor>::get();
+      } else {
+        return internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::get();
+      }
+  }
+  GOOGLE_LOG(FATAL) << "Should not reach here.";
+  return NULL;
+}
+
+namespace internal {
+namespace {
+void ShutdownRepeatedFieldAccessor() {
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int32> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint32> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int64> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint64> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<float> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<double> >::ShutDown();
+  internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<bool> >::ShutDown();
+  internal::Singleton<internal::RepeatedPtrFieldStringAccessor>::ShutDown();
+  internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::ShutDown();
+  internal::Singleton<internal::MapFieldAccessor>::ShutDown();
+}
+
+struct ShutdownRepeatedFieldRegister {
+  ShutdownRepeatedFieldRegister() {
+    OnShutdown(&ShutdownRepeatedFieldAccessor);
+  }
+} shutdown_;
+
+}  // namespace
+}  // namespace internal
+
+namespace internal {
+template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
+Message* GenericTypeHandler<Message>::NewFromPrototype(
+    const Message* prototype, google::protobuf::Arena* arena) {
+  return prototype->New(arena);
+}
+template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
+google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
+    Message* value) {
+  return value->GetArena();
+}
+template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
+void* GenericTypeHandler<Message>::GetMaybeArenaPointer(
+    Message* value) {
+  return value->GetMaybeArenaPointer();
+}
+}  // namespace internal
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index ff2fcd8..a4d9277 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -98,11 +98,11 @@
 //
 //     // Use the reflection interface to examine the contents.
 //     const Reflection* reflection = foo->GetReflection();
-//     assert(reflection->GetString(foo, text_field) == "Hello World!");
-//     assert(reflection->FieldSize(foo, numbers_field) == 3);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42);
+//     assert(reflection->GetString(*foo, text_field) == "Hello World!");
+//     assert(reflection->FieldSize(*foo, numbers_field) == 3);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 0) == 1);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 1) == 5);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 2) == 42);
 //
 //     delete foo;
 //   }
@@ -112,8 +112,10 @@
 
 #include <iosfwd>
 #include <string>
+#include <google/protobuf/stubs/type_traits.h>
 #include <vector>
 
+#include <google/protobuf/arena.h>
 #include <google/protobuf/message_lite.h>
 
 #include <google/protobuf/stubs/common.h>
@@ -121,6 +123,7 @@
 
 
 #define GOOGLE_PROTOBUF_HAS_ONEOF
+#define GOOGLE_PROTOBUF_HAS_ARENAS
 
 namespace google {
 namespace protobuf {
@@ -131,12 +134,23 @@
 class MessageFactory;
 
 // Defined in other files.
+class MapKey;
+class MapValueRef;
+class MapIterator;
+class MapReflectionTester;
+
+namespace internal {
+class MapFieldBase;
+}
 class UnknownFieldSet;         // unknown_field_set.h
 namespace io {
-  class ZeroCopyInputStream;   // zero_copy_stream.h
-  class ZeroCopyOutputStream;  // zero_copy_stream.h
-  class CodedInputStream;      // coded_stream.h
-  class CodedOutputStream;     // coded_stream.h
+class ZeroCopyInputStream;     // zero_copy_stream.h
+class ZeroCopyOutputStream;    // zero_copy_stream.h
+class CodedInputStream;        // coded_stream.h
+class CodedOutputStream;       // coded_stream.h
+}
+namespace python {
+class MapReflectionFriend;     // scalar_map_container.h
 }
 
 
@@ -174,6 +188,17 @@
   // for return-type covariance.)
   virtual Message* New() const = 0;
 
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a NULL. Default implementation allows for API compatibility
+  // during the Arena transition.
+  virtual Message* New(::google::protobuf::Arena* arena) const {
+    Message* message = New();
+    if (arena != NULL) {
+      arena->Own(message);
+    }
+    return message;
+  }
+
   // Make this message into a copy of the given message.  The given message
   // must have the same descriptor, but need not necessarily be the same class.
   // By default this is just implemented as "Clear(); MergeFrom(from);".
@@ -215,6 +240,11 @@
   // Computes (an estimate of) the total number of bytes currently used for
   // storing the message in memory.  The default implementation calls the
   // Reflection object's SpaceUsed() method.
+  //
+  // SpaceUsed() is noticeably slower than ByteSize(), as it is implemented
+  // using reflection (rather than the generated code implementation for
+  // ByteSize()). Like ByteSize(), its CPU time is linear in the number of
+  // fields defined for the proto.
   virtual int SpaceUsed() const;
 
   // Debugging & Testing----------------------------------------------
@@ -313,6 +343,20 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
 };
 
+namespace internal {
+// Forward-declare interfaces used to implement RepeatedFieldRef.
+// These are protobuf internals that users shouldn't care about.
+class RepeatedFieldAccessor;
+}  // namespace internal
+
+// Forward-declare RepeatedFieldRef templates. The second type parameter is
+// used for SFINAE tricks. Users should ignore it.
+template<typename T, typename Enable = void>
+class RepeatedFieldRef;
+
+template<typename T, typename Enable = void>
+class MutableRepeatedFieldRef;
+
 // This interface contains methods that can be used to dynamically access
 // and modify the fields of a protocol message.  Their semantics are
 // similar to the accessors the protocol compiler generates.
@@ -361,12 +405,15 @@
 
   // Get the UnknownFieldSet for the message.  This contains fields which
   // were seen when the Message was parsed but were not recognized according
-  // to the Message's definition.
+  // to the Message's definition. For proto3 protos, this method will always
+  // return an empty UnknownFieldSet.
   virtual const UnknownFieldSet& GetUnknownFields(
       const Message& message) const = 0;
   // Get a mutable pointer to the UnknownFieldSet for the message.  This
   // contains fields which were seen when the Message was parsed but were not
-  // recognized according to the Message's definition.
+  // recognized according to the Message's definition. For proto3 protos, this
+  // method will return a valid mutable UnknownFieldSet pointer but modifying
+  // it won't affect the serialized bytes of the message.
   virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
 
   // Estimate the amount of memory used by the message object.
@@ -385,7 +432,7 @@
   virtual void ClearField(Message* message,
                           const FieldDescriptor* field) const = 0;
 
-  // Check if the oneof is set. Returns ture if any field in oneof
+  // Check if the oneof is set. Returns true if any field in oneof
   // is set, false otherwise.
   // TODO(jieluo) - make it pure virtual after updating all
   // the subclasses.
@@ -439,8 +486,9 @@
   // return true and repeated fields will only be listed if FieldSize(field)
   // would return non-zero.  Fields (both normal fields and extension fields)
   // will be listed ordered by field number.
-  virtual void ListFields(const Message& message,
-                          std::vector<const FieldDescriptor*>* output) const = 0;
+  virtual void ListFields(
+      const Message& message,
+      std::vector<const FieldDescriptor*>* output) const = 0;
 
   // Singular field getters ------------------------------------------
   // These get the value of a non-repeated field.  They return the default
@@ -464,6 +512,15 @@
                            const FieldDescriptor* field) const = 0;
   virtual const EnumValueDescriptor* GetEnum(
       const Message& message, const FieldDescriptor* field) const = 0;
+
+  // GetEnumValue() returns an enum field's value as an integer rather than
+  // an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  virtual int GetEnumValue(
+      const Message& message, const FieldDescriptor* field) const;
+
   // See MutableMessage() for the meaning of the "factory" parameter.
   virtual const Message& GetMessage(const Message& message,
                                     const FieldDescriptor* field,
@@ -483,7 +540,7 @@
   //   regardless of the field's underlying representation.  When initializing
   //   a newly-constructed string, though, it's just as fast and more readable
   //   to use code like:
-  //     string str = reflection->GetString(field);
+  //     string str = reflection->GetString(message, field);
   virtual const string& GetStringReference(const Message& message,
                                            const FieldDescriptor* field,
                                            string* scratch) const = 0;
@@ -512,6 +569,14 @@
   virtual void SetEnum  (Message* message,
                          const FieldDescriptor* field,
                          const EnumValueDescriptor* value) const = 0;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // If the value does not correspond to a known enum value, either behavior is
+  // undefined (for proto2 messages), or the value is accepted silently for
+  // messages with new unknown-enum-value semantics.
+  virtual void SetEnumValue(Message* message,
+                            const FieldDescriptor* field,
+                            int value) const;
+
   // Get a mutable pointer to a field with a message type.  If a MessageFactory
   // is provided, it will be used to construct instances of the sub-message;
   // otherwise, the default factory is used.  If the field is an extension that
@@ -574,6 +639,14 @@
   virtual const EnumValueDescriptor* GetRepeatedEnum(
       const Message& message,
       const FieldDescriptor* field, int index) const = 0;
+  // GetRepeatedEnumValue() returns an enum field's value as an integer rather
+  // than an EnumValueDescriptor*. If the integer value does not correspond to a
+  // known value descriptor, a new value descriptor is created. (Such a value
+  // will only be present when the new unknown-enum-value semantics are enabled
+  // for a message.)
+  virtual int GetRepeatedEnumValue(
+      const Message& message,
+      const FieldDescriptor* field, int index) const;
   virtual const Message& GetRepeatedMessage(
       const Message& message,
       const FieldDescriptor* field, int index) const = 0;
@@ -614,6 +687,13 @@
   virtual void SetRepeatedEnum(Message* message,
                                const FieldDescriptor* field, int index,
                                const EnumValueDescriptor* value) const = 0;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // If the value does not correspond to a known enum value, either behavior is
+  // undefined (for proto2 messages), or the value is accepted silently for
+  // messages with new unknown-enum-value semantics.
+  virtual void SetRepeatedEnumValue(Message* message,
+                                    const FieldDescriptor* field, int index,
+                                    int value) const;
   // Get a mutable pointer to an element of a repeated field with a message
   // type.
   virtual Message* MutableRepeatedMessage(
@@ -643,12 +723,65 @@
   virtual void AddEnum  (Message* message,
                          const FieldDescriptor* field,
                          const EnumValueDescriptor* value) const = 0;
+  // Set an enum field's value with an integer rather than EnumValueDescriptor.
+  // If the value does not correspond to a known enum value, either behavior is
+  // undefined (for proto2 messages), or the value is accepted silently for
+  // messages with new unknown-enum-value semantics.
+  virtual void AddEnumValue(Message* message,
+                            const FieldDescriptor* field,
+                            int value) const;
   // See MutableMessage() for comments on the "factory" parameter.
   virtual Message* AddMessage(Message* message,
                               const FieldDescriptor* field,
                               MessageFactory* factory = NULL) const = 0;
 
+  // Appends an already-allocated object 'new_entry' to the repeated field
+  // specifyed by 'field' passing ownership to the message.
+  // TODO(tmarek): Make virtual after all subclasses have been
+  // updated.
+  virtual void AddAllocatedMessage(Message* /* message */,
+                                   const FieldDescriptor* /*field */,
+                                   Message* /* new_entry */) const {}
 
+
+  // Get a RepeatedFieldRef object that can be used to read the underlying
+  // repeated field. The type parameter T must be set according to the
+  // field's cpp type. The following table shows the mapping from cpp type
+  // to acceptable T.
+  //
+  //   field->cpp_type()      T
+  //   CPPTYPE_INT32        int32
+  //   CPPTYPE_UINT32       uint32
+  //   CPPTYPE_INT64        int64
+  //   CPPTYPE_UINT64       uint64
+  //   CPPTYPE_DOUBLE       double
+  //   CPPTYPE_FLOAT        float
+  //   CPPTYPE_BOOL         bool
+  //   CPPTYPE_ENUM         generated enum type or int32
+  //   CPPTYPE_STRING       string
+  //   CPPTYPE_MESSAGE      generated message type or google::protobuf::Message
+  //
+  // A RepeatedFieldRef object can be copied and the resulted object will point
+  // to the same repeated field in the same message. The object can be used as
+  // long as the message is not destroyed.
+  //
+  // Note that to use this method users need to include the header file
+  // "google/protobuf/reflection.h" (which defines the RepeatedFieldRef
+  // class templates).
+  template<typename T>
+  RepeatedFieldRef<T> GetRepeatedFieldRef(
+      const Message& message, const FieldDescriptor* field) const;
+
+  // Like GetRepeatedFieldRef() but return an object that can also be used
+  // manipulate the underlying repeated field.
+  template<typename T>
+  MutableRepeatedFieldRef<T> GetMutableRepeatedFieldRef(
+      Message* message, const FieldDescriptor* field) const;
+
+  // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field
+  // access. The following repeated field accesors will be removed in the
+  // future.
+  //
   // Repeated field accessors  -------------------------------------------------
   // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular
   // access to the data in a RepeatedField.  The methods below provide aggregate
@@ -659,22 +792,30 @@
   //
   // Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
 
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
   // for T = Cord and all protobuf scalar types except enums.
   template<typename T>
   const RepeatedField<T>& GetRepeatedField(
       const Message&, const FieldDescriptor*) const;
 
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
   // for T = Cord and all protobuf scalar types except enums.
   template<typename T>
   RepeatedField<T>* MutableRepeatedField(
       Message*, const FieldDescriptor*) const;
 
+  // DEPRECATED. Please use GetRepeatedFieldRef().
+  //
   // for T = string, google::protobuf::internal::StringPieceField
   //         google::protobuf::Message & descendants.
   template<typename T>
   const RepeatedPtrField<T>& GetRepeatedPtrField(
       const Message&, const FieldDescriptor*) const;
 
+  // DEPRECATED. Please use GetMutableRepeatedFieldRef().
+  //
   // for T = string, google::protobuf::internal::StringPieceField
   //         google::protobuf::Message & descendants.
   template<typename T>
@@ -693,6 +834,52 @@
   virtual const FieldDescriptor* FindKnownExtensionByNumber(
       int number) const = 0;
 
+  // Feature Flags -------------------------------------------------------------
+
+  // Does this message support storing arbitrary integer values in enum fields?
+  // If |true|, GetEnumValue/SetEnumValue and associated repeated-field versions
+  // take arbitrary integer values, and the legacy GetEnum() getter will
+  // dynamically create an EnumValueDescriptor for any integer value without
+  // one. If |false|, setting an unknown enum value via the integer-based
+  // setters results in undefined behavior (in practice, GOOGLE_DCHECK-fails).
+  //
+  // Generic code that uses reflection to handle messages with enum fields
+  // should check this flag before using the integer-based setter, and either
+  // downgrade to a compatible value or use the UnknownFieldSet if not. For
+  // example:
+  //
+  // int new_value = GetValueFromApplicationLogic();
+  // if (reflection->SupportsUnknownEnumValues()) {
+  //     reflection->SetEnumValue(message, field, new_value);
+  // } else {
+  //     if (field_descriptor->enum_type()->
+  //             FindValueByNumver(new_value) != NULL) {
+  //         reflection->SetEnumValue(message, field, new_value);
+  //     } else if (emit_unknown_enum_values) {
+  //         reflection->MutableUnknownFields(message)->AddVarint(
+  //             field->number(),
+  //             new_value);
+  //     } else {
+  //         // convert value to a compatible/default value.
+  //         new_value = CompatibleDowngrade(new_value);
+  //         reflection->SetEnumValue(message, field, new_value);
+  //     }
+  // }
+  virtual bool SupportsUnknownEnumValues() const { return false; }
+
+  // Returns the MessageFactory associated with this message.  This can be
+  // useful for determining if a message is a generated message or not, for
+  // example:
+  //
+  // if (message->GetReflection()->GetMessageFactory() ==
+  //     google::protobuf::MessageFactory::generated_factory()) {
+  //   // This is a generated message.
+  // }
+  //
+  // It can also be used to create more messages of this type, though
+  // Message::New() is an easier way to accomplish this.
+  virtual MessageFactory* GetMessageFactory() const;
+
   // ---------------------------------------------------------------------------
 
  protected:
@@ -700,19 +887,118 @@
   //   on field->cpp_type(),
   //   on field->field_option().ctype() (if ctype >= 0)
   //   of field->message_type() (if message_type != NULL).
-  // We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer).
+  // We use 2 routine rather than 4 (const vs mutable) x (scalar vs pointer).
   virtual void* MutableRawRepeatedField(
       Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
       int ctype, const Descriptor* message_type) const = 0;
 
+  // TODO(jieluo) - make it pure virtual after updating all the subclasses.
+  virtual const void* GetRawRepeatedField(
+      const Message& message, const FieldDescriptor* field,
+      FieldDescriptor::CppType cpptype, int ctype,
+      const Descriptor* message_type) const {
+    return MutableRawRepeatedField(
+        const_cast<Message*>(&message), field, cpptype, ctype, message_type);
+  }
+
+  // The following methods are used to implement (Mutable)RepeatedFieldRef.
+  // A Ref object will store a raw pointer to the repeated field data (obtained
+  // from RepeatedFieldData()) and a pointer to a Accessor (obtained from
+  // RepeatedFieldAccessor) which will be used to access the raw data.
+  //
+  // TODO(xiaofeng): Make these methods pure-virtual.
+
+  // Returns a raw pointer to the repeated field
+  //
+  // "cpp_type" and "message_type" are decuded from the type parameter T passed
+  // to Get(Mutable)RepeatedFieldRef. If T is a generated message type,
+  // "message_type" should be set to its descriptor. Otherwise "message_type"
+  // should be set to NULL. Implementations of this method should check whether
+  // "cpp_type"/"message_type" is consistent with the actual type of the field.
+  // We use 1 routine rather than 2 (const vs mutable) because it is protected
+  // and it doesn't change the message.
+  virtual void* RepeatedFieldData(
+      Message* message, const FieldDescriptor* field,
+      FieldDescriptor::CppType cpp_type,
+      const Descriptor* message_type) const;
+
+  // The returned pointer should point to a singleton instance which implements
+  // the RepeatedFieldAccessor interface.
+  virtual const internal::RepeatedFieldAccessor* RepeatedFieldAccessor(
+      const FieldDescriptor* field) const;
+
  private:
+  template<typename T, typename Enable>
+  friend class RepeatedFieldRef;
+  template<typename T, typename Enable>
+  friend class MutableRepeatedFieldRef;
+  friend class ::google::protobuf::python::MapReflectionFriend;
+
   // Special version for specialized implementations of string.  We can't call
   // MutableRawRepeatedField directly here because we don't have access to
   // FieldOptions::* which are defined in descriptor.pb.h.  Including that
   // file here is not possible because it would cause a circular include cycle.
+  // We use 1 routine rather than 2 (const vs mutable) because it is private
+  // and mutable a repeated string field doesn't change the message.
   void* MutableRawRepeatedString(
       Message* message, const FieldDescriptor* field, bool is_string) const;
 
+  friend class MapReflectionTester;
+  // TODO(jieluo) - make the map APIs pure virtual after updating
+  // all the subclasses.
+  // Returns true if key is in map. Returns false if key is not in map field.
+  virtual bool ContainsMapKey(const Message& /* message*/,
+                              const FieldDescriptor* /* field */,
+                              const MapKey& /* key */) const {
+    return false;
+  }
+
+  // If key is in map field: Saves the value pointer to val and returns
+  // false. If key in not in map field: Insert the key into map, saves
+  // value pointer to val and retuns true.
+  virtual bool InsertOrLookupMapValue(Message* /* message */,
+                                      const FieldDescriptor* /* field */,
+                                      const MapKey& /* key */,
+                                      MapValueRef* /* val */) const {
+    return false;
+  }
+
+  // Delete and returns true if key is in the map field. Returns false
+  // otherwise.
+  virtual bool DeleteMapValue(Message* /* mesage */,
+                              const FieldDescriptor* /* field */,
+                              const MapKey& /* key */) const {
+    return false;
+  }
+
+  // Returns a MapIterator referring to the first element in the map field.
+  // If the map field is empty, this function returns the same as
+  // reflection::MapEnd. Mutation to the field may invalidate the iterator.
+  virtual MapIterator MapBegin(
+      Message* message,
+      const FieldDescriptor* field) const;
+
+  // Returns a MapIterator referring to the theoretical element that would
+  // follow the last element in the map field. It does not point to any
+  // real element. Mutation to the field may invalidate the iterator.
+  virtual MapIterator MapEnd(
+      Message* message,
+      const FieldDescriptor* field) const;
+
+  // Get the number of <key, value> pair of a map field. The result may be
+  // different from FieldSize which can have duplicate keys.
+  virtual int MapSize(const Message& /* message */,
+                      const FieldDescriptor* /* field */) const {
+    return 0;
+  }
+
+  // Help method for MapIterator.
+  friend class MapIterator;
+  virtual internal::MapFieldBase* MapData(
+      Message* /* message */, const FieldDescriptor* /* field */) const {
+    return NULL;
+  }
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
 };
 
@@ -787,6 +1073,7 @@
     const Message& message, const FieldDescriptor* field) const; \
                                                                  \
 template<>                                                       \
+LIBPROTOBUF_EXPORT                                               \
 RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>(     \
     Message* message, const FieldDescriptor* field) const;
 
@@ -827,10 +1114,9 @@
 template<>
 inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrField(
     const Message& message, const FieldDescriptor* field) const {
-  return *static_cast<RepeatedPtrField<Message>* >(
-      MutableRawRepeatedField(const_cast<Message*>(&message), field,
-          FieldDescriptor::CPPTYPE_MESSAGE, -1,
-          NULL));
+  return *static_cast<const RepeatedPtrField<Message>* >(
+      GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE,
+                          -1, NULL));
 }
 
 template<>
@@ -845,10 +1131,9 @@
 template<typename PB>
 inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrField(
     const Message& message, const FieldDescriptor* field) const {
-  return *static_cast<RepeatedPtrField<PB>* >(
-      MutableRawRepeatedField(const_cast<Message*>(&message), field,
-          FieldDescriptor::CPPTYPE_MESSAGE, -1,
-          PB::default_instance().GetDescriptor()));
+  return *static_cast<const RepeatedPtrField<PB>* >(
+      GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE,
+                          -1, PB::default_instance().GetDescriptor()));
 }
 
 template<typename PB>
@@ -859,7 +1144,6 @@
           FieldDescriptor::CPPTYPE_MESSAGE, -1,
           PB::default_instance().GetDescriptor()));
 }
-
 }  // namespace protobuf
 
 }  // namespace google
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 14cdc91..9d7b64f 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -34,7 +34,10 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/repeated_field.h>
 #include <string>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
@@ -59,13 +62,15 @@
 // provide a useful error message.
 void ByteSizeConsistencyError(int byte_size_before_serialization,
                               int byte_size_after_serialization,
-                              int bytes_produced_by_serialization) {
+                              int bytes_produced_by_serialization,
+                              const MessageLite& message) {
   GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
-      << "Protocol message was modified concurrently during serialization.";
+      << message.GetTypeName()
+      << " was modified concurrently during serialization.";
   GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
       << "Byte size calculation and serialization were inconsistent.  This "
          "may indicate a bug in protocol buffers or it may be caused by "
-         "concurrent modification of the message.";
+         "concurrent modification of " << message.GetTypeName() << ".";
   GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
 }
 
@@ -97,27 +102,19 @@
 // call MergePartialFromCodedStream().  However, when parsing very small
 // messages, every function call introduces significant overhead.  To avoid
 // this without reproducing code, we use these forced-inline helpers.
-//
-// Note:  GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not
-//   definitions.
-inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
-                                       MessageLite* message)
-                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
-                                       MessageLite* message)
-                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
-                                              MessageLite* message)
-                                              GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline bool InlineParseFromArray(const void* data, int size,
-                                 MessageLite* message)
-                                 GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline bool InlineParsePartialFromArray(const void* data, int size,
-                                        MessageLite* message)
-                                        GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream(
+    io::CodedInputStream* input, MessageLite* message);
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream(
+    io::CodedInputStream* input, MessageLite* message);
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream(
+    io::CodedInputStream* input, MessageLite* message);
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray(
+    const void* data, int size, MessageLite* message);
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray(
+    const void* data, int size, MessageLite* message);
 
-bool InlineMergeFromCodedStream(io::CodedInputStream* input,
-                                MessageLite* message) {
+inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
+                                       MessageLite* message) {
   if (!message->MergePartialFromCodedStream(input)) return false;
   if (!message->IsInitialized()) {
     GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
@@ -126,26 +123,27 @@
   return true;
 }
 
-bool InlineParseFromCodedStream(io::CodedInputStream* input,
-                                MessageLite* message) {
+inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
+                                       MessageLite* message) {
   message->Clear();
   return InlineMergeFromCodedStream(input, message);
 }
 
-bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
-                                       MessageLite* message) {
+inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
+                                              MessageLite* message) {
   message->Clear();
   return message->MergePartialFromCodedStream(input);
 }
 
-bool InlineParseFromArray(const void* data, int size, MessageLite* message) {
+inline bool InlineParseFromArray(
+    const void* data, int size, MessageLite* message) {
   io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
   return InlineParseFromCodedStream(&input, message) &&
          input.ConsumedEntireMessage();
 }
 
-bool InlineParsePartialFromArray(const void* data, int size,
-                                 MessageLite* message) {
+inline bool InlineParsePartialFromArray(
+    const void* data, int size, MessageLite* message) {
   io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
   return InlineParsePartialFromCodedStream(&input, message) &&
          input.ConsumedEntireMessage();
@@ -153,6 +151,15 @@
 
 }  // namespace
 
+
+MessageLite* MessageLite::New(::google::protobuf::Arena* arena) const {
+  MessageLite* message = New();
+  if (arena != NULL) {
+    arena->Own(message);
+  }
+  return message;
+}
+
 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
   return InlineMergeFromCodedStream(input, this);
 }
@@ -233,11 +240,17 @@
 bool MessageLite::SerializePartialToCodedStream(
     io::CodedOutputStream* output) const {
   const int size = ByteSize();  // Force size to be cached.
+  if (size < 0) {
+    // Messages >2G cannot be serialized due to overflow computing ByteSize.
+    GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?).";
+    return false;
+  }
+
   uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
   if (buffer != NULL) {
     uint8* end = SerializeWithCachedSizesToArray(buffer);
     if (end - buffer != size) {
-      ByteSizeConsistencyError(size, ByteSize(), end - buffer);
+      ByteSizeConsistencyError(size, ByteSize(), end - buffer, *this);
     }
     return true;
   } else {
@@ -250,7 +263,7 @@
 
     if (final_byte_count - original_byte_count != size) {
       ByteSizeConsistencyError(size, ByteSize(),
-                               final_byte_count - original_byte_count);
+                               final_byte_count - original_byte_count, *this);
     }
 
     return true;
@@ -277,12 +290,18 @@
 bool MessageLite::AppendPartialToString(string* output) const {
   int old_size = output->size();
   int byte_size = ByteSize();
+  if (byte_size < 0) {
+    // Messages >2G cannot be serialized due to overflow computing ByteSize.
+    GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?).";
+    return false;
+  }
+
   STLStringResizeUninitialized(output, old_size + byte_size);
   uint8* start =
       reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
   uint8* end = SerializeWithCachedSizesToArray(start);
   if (end - start != byte_size) {
-    ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
+    ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this);
   }
   return true;
 }
@@ -308,14 +327,14 @@
   uint8* start = reinterpret_cast<uint8*>(data);
   uint8* end = SerializeWithCachedSizesToArray(start);
   if (end - start != byte_size) {
-    ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
+    ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this);
   }
   return true;
 }
 
 string MessageLite::SerializeAsString() const {
   // If the compiler implements the (Named) Return Value Optimization,
-  // the local variable 'result' will not actually reside on the stack
+  // the local variable 'output' will not actually reside on the stack
   // of this function, but will be overlaid with the object that the
   // caller supplied for the return value to be constructed in.
   string output;
@@ -331,5 +350,23 @@
   return output;
 }
 
+namespace internal {
+template<>
+MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, google::protobuf::Arena* arena) {
+  return prototype->New(arena);
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to) {
+  to->CheckTypeAndMergeFrom(from);
+}
+template<>
+void GenericTypeHandler<string>::Merge(const string& from,
+                                              string* to) {
+  *to = from;
+}
+}  // namespace internal
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 027cabf..4c16f4c 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -41,9 +41,10 @@
 
 #include <google/protobuf/stubs/common.h>
 
+
 namespace google {
 namespace protobuf {
-
+  class Arena;
 namespace io {
   class CodedInputStream;
   class CodedOutputStream;
@@ -88,6 +89,27 @@
   // caller.
   virtual MessageLite* New() const = 0;
 
+  // Construct a new instance on the arena. Ownership is passed to the caller
+  // if arena is a NULL. Default implementation for backwards compatibility.
+  virtual MessageLite* New(::google::protobuf::Arena* arena) const;
+
+  // Get the arena, if any, associated with this message. Virtual method
+  // required for generic operations but most arena-related operations should
+  // use the GetArenaNoVirtual() generated-code method. Default implementation
+  // to reduce code size by avoiding the need for per-type implementations when
+  // types do not implement arena support.
+  virtual ::google::protobuf::Arena* GetArena() const { return NULL; }
+
+  // Get a pointer that may be equal to this message's arena, or may not be. If
+  // the value returned by this method is equal to some arena pointer, then this
+  // message is on that arena; however, if this message is on some arena, this
+  // method may or may not return that arena's pointer. As a tradeoff, this
+  // method may be more efficient than GetArena(). The intent is to allow
+  // underlying representations that use e.g. tagged pointers to sometimes store
+  // the arena pointer directly, and sometimes in a more indirect way, and allow
+  // a fastpath comparison against the arena pointer when it's easy to obtain.
+  virtual void* GetMaybeArenaPointer() const { return GetArena(); }
+
   // Clear all fields of the message and set them to their default values.
   // Clear() avoids freeing memory, assuming that any memory allocated
   // to hold parts of the message will be needed again to hold the next
@@ -112,9 +134,10 @@
   // just simple wrappers around MergeFromCodedStream().  Clear() will be called
   // before merging the input.
 
-  // Fill the message with a protocol buffer parsed from the given input
-  // stream.  Returns false on a read error or if the input is in the
-  // wrong format.
+  // Fill the message with a protocol buffer parsed from the given input stream.
+  // Returns false on a read error or if the input is in the wrong format.  A
+  // successful return does not indicate the entire input is consumed, ensure
+  // you call ConsumedEntireMessage() to check that if applicable.
   bool ParseFromCodedStream(io::CodedInputStream* input);
   // Like ParseFromCodedStream(), but accepts messages that are missing
   // required fields.
@@ -133,7 +156,11 @@
   // missing required fields.
   bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
                                              int size);
-  // Parse a protocol buffer contained in a string.
+  // Parses a protocol buffer contained in a string. Returns true on success.
+  // This function takes a string in the (non-human-readable) binary wire
+  // format, matching the encoding output by MessageLite::SerializeToString().
+  // If you'd like to convert a human-readable string into a protocol buffer
+  // object, see google::protobuf::TextFormat::ParseFromString().
   bool ParseFromString(const string& data);
   // Like ParseFromString(), but accepts messages that are missing
   // required fields.
@@ -211,6 +238,9 @@
   // Computes the serialized size of the message.  This recursively calls
   // ByteSize() on all embedded messages.  If a subclass does not override
   // this, it MUST override SetCachedSize().
+  //
+  // ByteSize() is generally linear in the number of fields defined for the
+  // proto.
   virtual int ByteSize() const = 0;
 
   // Serializes the message without recomputing the size.  The message must
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
index a5f339f..d668a1a 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -45,14 +45,17 @@
 #include <sstream>
 #include <fstream>
 
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -205,6 +208,28 @@
   EXPECT_EQ("a, b, c", message.InitializationErrorString());
 }
 
+TEST(MessageTest, DynamicCastToGenerated) {
+  unittest::TestAllTypes test_all_types;
+
+  google::protobuf::Message* test_all_types_pointer = &test_all_types;
+  EXPECT_EQ(&test_all_types,
+            google::protobuf::internal::DynamicCastToGenerated<unittest::TestAllTypes>(
+                test_all_types_pointer));
+  EXPECT_EQ(NULL,
+            google::protobuf::internal::DynamicCastToGenerated<unittest::TestRequired>(
+                test_all_types_pointer));
+
+  const google::protobuf::Message* test_all_types_pointer_const = &test_all_types;
+  EXPECT_EQ(
+      &test_all_types,
+      google::protobuf::internal::DynamicCastToGenerated<const unittest::TestAllTypes>(
+          test_all_types_pointer_const));
+  EXPECT_EQ(
+      NULL,
+      google::protobuf::internal::DynamicCastToGenerated<const unittest::TestRequired>(
+          test_all_types_pointer_const));
+}
+
 #ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet.
 
 TEST(MessageTest, SerializeFailsIfNotInitialized) {
@@ -242,6 +267,25 @@
 
 #endif  // PROTOBUF_HAS_DEATH_TEST
 
+namespace {
+
+class NegativeByteSize : public unittest::TestRequired {
+ public:
+  virtual int ByteSize() const { return -1; }
+};
+
+}  // namespace
+
+TEST(MessageTest, SerializationFailsOnNegativeByteSize) {
+  NegativeByteSize message;
+  string string_output;
+  EXPECT_FALSE(message.AppendPartialToString(&string_output));
+
+  io::ArrayOutputStream coded_raw_output(NULL, 100);
+  io::CodedOutputStream coded_output(&coded_raw_output);
+  EXPECT_FALSE(message.SerializePartialToCodedStream(&coded_output));
+}
+
 TEST(MessageTest, BypassInitializationCheckOnSerialize) {
   unittest::TestRequired message;
   io::ArrayOutputStream raw_output(NULL, 0);
diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h
new file mode 100644
index 0000000..fdee150
--- /dev/null
+++ b/src/google/protobuf/metadata.h
@@ -0,0 +1,163 @@
+// 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.
+
+// This header file defines an internal class that encapsulates internal message
+// metadata (Unknown-field set, Arena pointer, ...) and allows its
+// representation to be made more space-efficient via various optimizations.
+//
+// Note that this is distinct from google::protobuf::Metadata, which encapsulates
+// Descriptor and Reflection pointers.
+
+#ifndef GOOGLE_PROTOBUF_METADATA_H__
+#define GOOGLE_PROTOBUF_METADATA_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/unknown_field_set.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// This is the representation for messages that support arena allocation. It
+// uses a tagged pointer to either store the Arena pointer, if there are no
+// unknown fields, or a pointer to a block of memory with both the Arena pointer
+// and the UnknownFieldSet, if there are unknown fields. This optimization
+// allows for "zero-overhead" storage of the Arena pointer, relative to the
+// above baseline implementation.
+//
+// The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to
+// indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container
+// pointer.
+class LIBPROTOBUF_EXPORT InternalMetadataWithArena {
+ public:
+  InternalMetadataWithArena() : ptr_(NULL) {}
+  explicit InternalMetadataWithArena(Arena* arena)
+      : ptr_ (arena) {}
+
+  ~InternalMetadataWithArena() {
+    if (have_unknown_fields() && arena() == NULL) {
+      delete PtrValue<Container>();
+    }
+    ptr_ = NULL;
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE const UnknownFieldSet& unknown_fields() const {
+    if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<Container>()->unknown_fields_;
+    } else {
+      return *UnknownFieldSet::default_instance();
+    }
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE UnknownFieldSet* mutable_unknown_fields() {
+    if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) {
+      return &PtrValue<Container>()->unknown_fields_;
+    } else {
+      return mutable_unknown_fields_slow();
+    }
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const {
+    if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) {
+      return PtrValue<Container>()->arena_;
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const {
+    return PtrTag() == kTagContainer;
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(InternalMetadataWithArena* other) {
+    // Semantics here are that we swap only the unknown fields, not the arena
+    // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
+    // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
+    // different states (direct arena pointer vs. container with UFS) so we
+    // cannot simply swap ptr_ and then restore the arena pointers. We reuse
+    // UFS's swap implementation instead.
+    if (have_unknown_fields() || other->have_unknown_fields()) {
+      mutable_unknown_fields()->Swap(other->mutable_unknown_fields());
+    }
+  }
+
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const {
+    return ptr_;
+  }
+
+ private:
+  void* ptr_;
+
+  // Tagged pointer implementation.
+  enum {
+    // ptr_ is an Arena*.
+    kTagArena = 0,
+    // ptr_ is a Container*.
+    kTagContainer = 1,
+  };
+  static const intptr_t kPtrTagMask = 1;
+  static const intptr_t kPtrValueMask = ~kPtrTagMask;
+
+  // Accessors for pointer tag and pointer value.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const {
+    return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask;
+  }
+
+  template<typename T> T* PtrValue() const {
+    return reinterpret_cast<T*>(
+        reinterpret_cast<intptr_t>(ptr_) & kPtrValueMask);
+  }
+
+  // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
+  struct Container {
+    UnknownFieldSet unknown_fields_;
+    Arena* arena_;
+  };
+
+  GOOGLE_ATTRIBUTE_NOINLINE UnknownFieldSet* mutable_unknown_fields_slow() {
+    Arena* my_arena = arena();
+    Container* container = Arena::Create<Container>(my_arena);
+    ptr_ = reinterpret_cast<void*>(
+        reinterpret_cast<intptr_t>(container) | kTagContainer);
+    container->arena_ = my_arena;
+    return &(container->unknown_fields_);
+  }
+};
+
+// Temporary compatibility typedef. Remove once this is released in components
+// and upb CL is submitted.
+typedef InternalMetadataWithArena InternalMetadata;
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_METADATA_H__
diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc
new file mode 100644
index 0000000..bc41bee
--- /dev/null
+++ b/src/google/protobuf/no_field_presence_test.cc
@@ -0,0 +1,577 @@
+// 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.
+
+#include <string>
+
+#include <google/protobuf/unittest_no_field_presence.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// Helper: checks that all fields have default (zero/empty) values.
+void CheckDefaultValues(
+    const proto2_nofieldpresence_unittest::TestAllTypes& m) {
+  EXPECT_EQ(0, m.optional_int32());
+  EXPECT_EQ(0, m.optional_int64());
+  EXPECT_EQ(0, m.optional_uint32());
+  EXPECT_EQ(0, m.optional_uint64());
+  EXPECT_EQ(0, m.optional_sint32());
+  EXPECT_EQ(0, m.optional_sint64());
+  EXPECT_EQ(0, m.optional_fixed32());
+  EXPECT_EQ(0, m.optional_fixed64());
+  EXPECT_EQ(0, m.optional_sfixed32());
+  EXPECT_EQ(0, m.optional_sfixed64());
+  EXPECT_EQ(0, m.optional_float());
+  EXPECT_EQ(0, m.optional_double());
+  EXPECT_EQ(false, m.optional_bool());
+  EXPECT_EQ(0, m.optional_string().size());
+  EXPECT_EQ(0, m.optional_bytes().size());
+
+  EXPECT_EQ(false, m.has_optional_nested_message());
+  // accessor for message fields returns default instance when not present
+  EXPECT_EQ(0, m.optional_nested_message().bb());
+  EXPECT_EQ(false, m.has_optional_proto2_message());
+  // Embedded proto2 messages still have proto2 semantics, e.g. non-zero default
+  // values. Here the submessage is not present but its accessor returns the
+  // default instance.
+  EXPECT_EQ(41, m.optional_proto2_message().default_int32());
+  EXPECT_EQ(false, m.has_optional_foreign_message());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_FOO,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_FOO,
+            m.optional_foreign_enum());
+
+
+  EXPECT_EQ(0, m.repeated_int32_size());
+  EXPECT_EQ(0, m.repeated_int64_size());
+  EXPECT_EQ(0, m.repeated_uint32_size());
+  EXPECT_EQ(0, m.repeated_uint64_size());
+  EXPECT_EQ(0, m.repeated_sint32_size());
+  EXPECT_EQ(0, m.repeated_sint64_size());
+  EXPECT_EQ(0, m.repeated_fixed32_size());
+  EXPECT_EQ(0, m.repeated_fixed64_size());
+  EXPECT_EQ(0, m.repeated_sfixed32_size());
+  EXPECT_EQ(0, m.repeated_sfixed64_size());
+  EXPECT_EQ(0, m.repeated_float_size());
+  EXPECT_EQ(0, m.repeated_double_size());
+  EXPECT_EQ(0, m.repeated_bool_size());
+  EXPECT_EQ(0, m.repeated_string_size());
+  EXPECT_EQ(0, m.repeated_bytes_size());
+  EXPECT_EQ(0, m.repeated_nested_message_size());
+  EXPECT_EQ(0, m.repeated_foreign_message_size());
+  EXPECT_EQ(0, m.repeated_proto2_message_size());
+  EXPECT_EQ(0, m.repeated_nested_enum_size());
+  EXPECT_EQ(0, m.repeated_foreign_enum_size());
+  EXPECT_EQ(0, m.repeated_lazy_message_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::ONEOF_FIELD_NOT_SET,
+            m.oneof_field_case());
+}
+
+void FillValues(proto2_nofieldpresence_unittest::TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_int64(101);
+  m->set_optional_uint32(102);
+  m->set_optional_uint64(103);
+  m->set_optional_sint32(104);
+  m->set_optional_sint64(105);
+  m->set_optional_fixed32(106);
+  m->set_optional_fixed64(107);
+  m->set_optional_sfixed32(108);
+  m->set_optional_sfixed64(109);
+  m->set_optional_float(110.0);
+  m->set_optional_double(111.0);
+  m->set_optional_bool(true);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->mutable_optional_proto2_message()->set_optional_int32(44);
+  m->set_optional_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->set_optional_foreign_enum(
+      proto2_nofieldpresence_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_int64(101);
+  m->add_repeated_uint32(102);
+  m->add_repeated_uint64(103);
+  m->add_repeated_sint32(104);
+  m->add_repeated_sint64(105);
+  m->add_repeated_fixed32(106);
+  m->add_repeated_fixed64(107);
+  m->add_repeated_sfixed32(108);
+  m->add_repeated_sfixed64(109);
+  m->add_repeated_float(110.0);
+  m->add_repeated_double(111.0);
+  m->add_repeated_bool(true);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_proto2_message()->set_optional_int32(48);
+  m->add_repeated_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->add_repeated_foreign_enum(
+      proto2_nofieldpresence_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void CheckNonDefaultValues(
+const proto2_nofieldpresence_unittest::TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ(101, m.optional_int64());
+  EXPECT_EQ(102, m.optional_uint32());
+  EXPECT_EQ(103, m.optional_uint64());
+  EXPECT_EQ(104, m.optional_sint32());
+  EXPECT_EQ(105, m.optional_sint64());
+  EXPECT_EQ(106, m.optional_fixed32());
+  EXPECT_EQ(107, m.optional_fixed64());
+  EXPECT_EQ(108, m.optional_sfixed32());
+  EXPECT_EQ(109, m.optional_sfixed64());
+  EXPECT_EQ(110.0, m.optional_float());
+  EXPECT_EQ(111.0, m.optional_double());
+  EXPECT_EQ(true, m.optional_bool());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(true, m.has_optional_proto2_message());
+  EXPECT_EQ(44, m.optional_proto2_message().optional_int32());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_int64_size());
+  EXPECT_EQ(101, m.repeated_int64(0));
+  EXPECT_EQ(1, m.repeated_uint32_size());
+  EXPECT_EQ(102, m.repeated_uint32(0));
+  EXPECT_EQ(1, m.repeated_uint64_size());
+  EXPECT_EQ(103, m.repeated_uint64(0));
+  EXPECT_EQ(1, m.repeated_sint32_size());
+  EXPECT_EQ(104, m.repeated_sint32(0));
+  EXPECT_EQ(1, m.repeated_sint64_size());
+  EXPECT_EQ(105, m.repeated_sint64(0));
+  EXPECT_EQ(1, m.repeated_fixed32_size());
+  EXPECT_EQ(106, m.repeated_fixed32(0));
+  EXPECT_EQ(1, m.repeated_fixed64_size());
+  EXPECT_EQ(107, m.repeated_fixed64(0));
+  EXPECT_EQ(1, m.repeated_sfixed32_size());
+  EXPECT_EQ(108, m.repeated_sfixed32(0));
+  EXPECT_EQ(1, m.repeated_sfixed64_size());
+  EXPECT_EQ(109, m.repeated_sfixed64(0));
+  EXPECT_EQ(1, m.repeated_float_size());
+  EXPECT_EQ(110.0, m.repeated_float(0));
+  EXPECT_EQ(1, m.repeated_double_size());
+  EXPECT_EQ(111.0, m.repeated_double(0));
+  EXPECT_EQ(1, m.repeated_bool_size());
+  EXPECT_EQ(true, m.repeated_bool(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_proto2_message_size());
+  EXPECT_EQ(48, m.repeated_proto2_message(0).optional_int32());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto2_nofieldpresence_unittest::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+TEST(NoFieldPresenceTest, BasicMessageTest) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  // Check default values, fill all fields, check values. We just want to
+  // exercise the basic getters/setter paths here to make sure no
+  // field-presence-related changes broke these.
+  CheckDefaultValues(message);
+  FillValues(&message);
+  CheckNonDefaultValues(message);
+
+  // Clear() should be equivalent to getting a freshly-constructed message.
+  message.Clear();
+  CheckDefaultValues(message);
+}
+
+TEST(NoFieldPresenceTest, MessageFieldPresenceTest) {
+  // check that presence still works properly for message fields.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  EXPECT_EQ(false, message.has_optional_nested_message());
+  // Getter should fetch default instance, and not cause the field to become
+  // present.
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+  EXPECT_EQ(false, message.has_optional_nested_message());
+  message.mutable_optional_nested_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_nested_message());
+  message.clear_optional_nested_message();
+  EXPECT_EQ(false, message.has_optional_nested_message());
+
+  // Likewise for a lazy message field.
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  // Getter should fetch default instance, and not cause the field to become
+  // present.
+  EXPECT_EQ(0, message.optional_lazy_message().bb());
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  message.mutable_optional_lazy_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_lazy_message());
+  message.clear_optional_lazy_message();
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+
+  // Test field presence of a message field on the default instance.
+  EXPECT_EQ(false, proto2_nofieldpresence_unittest::TestAllTypes::
+            default_instance().has_optional_nested_message());
+}
+
+TEST(NoFieldPresenceTest, ReflectionHasFieldTest) {
+  // check that HasField reports true on all scalar fields. Check that it
+  // behaves properly for message fields.
+
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* desc = message.GetDescriptor();
+
+  // Check initial state: scalars not present (due to need to be consistent with
+  // MergeFrom()), message fields not present, oneofs not present.
+  for (int i = 0; i < desc->field_count(); i++) {
+    const google::protobuf::FieldDescriptor* field = desc->field(i);
+    if (field->is_repeated()) continue;
+    EXPECT_EQ(false, r->HasField(message, field));
+  }
+
+  // Test field presence of a message field on the default instance.
+  const google::protobuf::FieldDescriptor* msg_field =
+      desc->FindFieldByName("optional_nested_message");
+  EXPECT_EQ(false, r->HasField(
+      proto2_nofieldpresence_unittest::TestAllTypes::
+      default_instance(), msg_field));
+
+  // Fill all fields, expect everything to report true (check oneofs below).
+  FillValues(&message);
+  for (int i = 0; i < desc->field_count(); i++) {
+    const google::protobuf::FieldDescriptor* field = desc->field(i);
+    if (field->is_repeated() || field->containing_oneof()) {
+      continue;
+    }
+    if (field->options().ctype() != google::protobuf::FieldOptions::STRING) {
+      continue;
+    }
+    EXPECT_EQ(true, r->HasField(message, field));
+  }
+
+  message.Clear();
+
+  // Check zero/empty-means-not-present semantics.
+  const google::protobuf::FieldDescriptor* field_int32 = desc->FindFieldByName(
+      "optional_int32");
+  const google::protobuf::FieldDescriptor* field_double = desc->FindFieldByName(
+      "optional_double");
+  const google::protobuf::FieldDescriptor* field_string = desc->FindFieldByName(
+      "optional_string");
+
+  EXPECT_EQ(false, r->HasField(message, field_int32));
+  EXPECT_EQ(false, r->HasField(message, field_double));
+  EXPECT_EQ(false, r->HasField(message, field_string));
+
+  message.set_optional_int32(42);
+  EXPECT_EQ(true, r->HasField(message, field_int32));
+  message.set_optional_int32(0);
+  EXPECT_EQ(false, r->HasField(message, field_int32));
+
+  message.set_optional_double(42.0);
+  EXPECT_EQ(true, r->HasField(message, field_double));
+  message.set_optional_double(0.0);
+  EXPECT_EQ(false, r->HasField(message, field_double));
+
+  message.set_optional_string("test");
+  EXPECT_EQ(true, r->HasField(message, field_string));
+  message.set_optional_string("");
+  EXPECT_EQ(false, r->HasField(message, field_string));
+}
+
+TEST(NoFieldPresenceTest, ReflectionClearFieldTest) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* desc = message.GetDescriptor();
+
+  const google::protobuf::FieldDescriptor* field_int32 = desc->FindFieldByName(
+      "optional_int32");
+  const google::protobuf::FieldDescriptor* field_double = desc->FindFieldByName(
+      "optional_double");
+  const google::protobuf::FieldDescriptor* field_string = desc->FindFieldByName(
+      "optional_string");
+  const google::protobuf::FieldDescriptor* field_message = desc->FindFieldByName(
+      "optional_nested_message");
+  const google::protobuf::FieldDescriptor* field_lazy = desc->FindFieldByName(
+      "optional_lazy_message");
+
+  message.set_optional_int32(42);
+  r->ClearField(&message, field_int32);
+  EXPECT_EQ(0, message.optional_int32());
+
+  message.set_optional_double(42.0);
+  r->ClearField(&message, field_double);
+  EXPECT_EQ(0.0, message.optional_double());
+
+  message.set_optional_string("test");
+  r->ClearField(&message, field_string);
+  EXPECT_EQ("", message.optional_string());
+
+  message.mutable_optional_nested_message()->set_bb(1234);
+  r->ClearField(&message, field_message);
+  EXPECT_FALSE(message.has_optional_nested_message());
+  EXPECT_EQ(0, message.optional_nested_message().bb());
+
+  message.mutable_optional_lazy_message()->set_bb(42);
+  r->ClearField(&message, field_lazy);
+  EXPECT_FALSE(message.has_optional_lazy_message());
+  EXPECT_EQ(0, message.optional_lazy_message().bb());
+}
+
+TEST(NoFieldPresenceTest, HasFieldOneofsTest) {
+  // check that HasField behaves properly for oneofs.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* desc = message.GetDescriptor();
+  const google::protobuf::FieldDescriptor* desc_oneof_uint32 =
+      desc->FindFieldByName("oneof_uint32");
+  const google::protobuf::FieldDescriptor* desc_oneof_nested_message =
+      desc->FindFieldByName("oneof_nested_message");
+  const google::protobuf::FieldDescriptor* desc_oneof_string =
+      desc->FindFieldByName("oneof_string");
+  GOOGLE_CHECK_NOTNULL(desc_oneof_uint32);
+  GOOGLE_CHECK_NOTNULL(desc_oneof_nested_message);
+  GOOGLE_CHECK_NOTNULL(desc_oneof_string);
+
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+
+  message.set_oneof_string("test");
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(true, r->HasField(message, desc_oneof_string));
+  message.mutable_oneof_nested_message()->set_bb(42);
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(true, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+
+  message.Clear();
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_uint32));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_nested_message));
+  EXPECT_EQ(false, r->HasField(message, desc_oneof_string));
+}
+
+TEST(NoFieldPresenceTest, DontSerializeDefaultValuesTest) {
+  // check that serialized data contains only non-zero numeric fields/non-empty
+  // string/byte fields.
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  string output;
+
+  // All default values -> no output.
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+
+  // Zero values -> still no output.
+  message.set_optional_int32(0);
+  message.set_optional_int64(0);
+  message.set_optional_uint32(0);
+  message.set_optional_uint64(0);
+  message.set_optional_sint32(0);
+  message.set_optional_sint64(0);
+  message.set_optional_fixed32(0);
+  message.set_optional_fixed64(0);
+  message.set_optional_sfixed32(0);
+  message.set_optional_sfixed64(0);
+  message.set_optional_float(0);
+  message.set_optional_double(0);
+  message.set_optional_bool(0);
+  message.set_optional_string("");
+  message.set_optional_bytes("");
+  message.set_optional_nested_enum(
+      proto2_nofieldpresence_unittest::TestAllTypes_NestedEnum_FOO);  // first enum entry
+  message.set_optional_foreign_enum(
+      proto2_nofieldpresence_unittest::FOREIGN_FOO);  // first enum entry
+
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+
+  message.set_optional_int32(1);
+  message.SerializeToString(&output);
+  EXPECT_EQ(2, output.size());
+  EXPECT_EQ("\x08\x01", output);
+
+  message.set_optional_int32(0);
+  message.SerializeToString(&output);
+  EXPECT_EQ(0, output.size());
+}
+
+TEST(NoFieldPresenceTest, MergeFromIfNonzeroTest) {
+  // check that MergeFrom copies if nonzero/nondefault only.
+  proto2_nofieldpresence_unittest::TestAllTypes source;
+  proto2_nofieldpresence_unittest::TestAllTypes dest;
+
+  dest.set_optional_int32(42);
+  dest.set_optional_string("test");
+  source.set_optional_int32(0);
+  source.set_optional_string("");
+  // MergeFrom() copies only if present in serialization, i.e., non-zero.
+  dest.MergeFrom(source);
+  EXPECT_EQ(42, dest.optional_int32());
+  EXPECT_EQ("test", dest.optional_string());
+
+  source.set_optional_int32(84);
+  source.set_optional_string("test2");
+  dest.MergeFrom(source);
+  EXPECT_EQ(84, dest.optional_int32());
+  EXPECT_EQ("test2", dest.optional_string());
+}
+
+TEST(NoFieldPresenceTest, IsInitializedTest) {
+  // Check that IsInitialized works properly.
+  proto2_nofieldpresence_unittest::TestProto2Required message;
+
+  EXPECT_EQ(true, message.IsInitialized());
+  message.mutable_proto2()->set_a(1);
+  EXPECT_EQ(false, message.IsInitialized());
+  message.mutable_proto2()->set_b(1);
+  EXPECT_EQ(false, message.IsInitialized());
+  message.mutable_proto2()->set_c(1);
+  EXPECT_EQ(true, message.IsInitialized());
+}
+
+TEST(NoFieldPresenceTest, LazyMessageFieldHasBit) {
+  // Check that has-bit interaction with lazy message works (has-bit before and
+  // after lazy decode).
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* desc = message.GetDescriptor();
+  const google::protobuf::FieldDescriptor* field = desc->FindFieldByName(
+      "optional_lazy_message");
+  GOOGLE_CHECK_NOTNULL(field);
+
+  EXPECT_EQ(false, message.has_optional_lazy_message());
+  EXPECT_EQ(false, r->HasField(message, field));
+
+  message.mutable_optional_lazy_message()->set_bb(42);
+  EXPECT_EQ(true, message.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message, field));
+
+  // Serialize and parse with a new message object so that lazy field on new
+  // object is in unparsed state.
+  string output;
+  message.SerializeToString(&output);
+  proto2_nofieldpresence_unittest::TestAllTypes message2;
+  message2.ParseFromString(output);
+
+  EXPECT_EQ(true, message2.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message2, field));
+
+  // Access field to force lazy parse.
+  EXPECT_EQ(42, message.optional_lazy_message().bb());
+  EXPECT_EQ(true, message2.has_optional_lazy_message());
+  EXPECT_EQ(true, r->HasField(message2, field));
+}
+
+TEST(NoFieldPresenceTest, OneofPresence) {
+  proto2_nofieldpresence_unittest::TestAllTypes message;
+  // oneof fields still have field presence -- ensure that this goes on the wire
+  // even though its value is the empty string.
+  message.set_oneof_string("");
+  string serialized;
+  message.SerializeToString(&serialized);
+  // Tag: 113 --> tag is (113 << 3) | 2 (length delimited) = 906
+  // varint: 0x8a 0x07
+  // Length: 0x00
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_EQ(static_cast<char>(0x8a), serialized.at(0));
+  EXPECT_EQ(static_cast<char>(0x07), serialized.at(1));
+  EXPECT_EQ(static_cast<char>(0x00), serialized.at(2));
+
+  message.Clear();
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofString,
+            message.oneof_field_case());
+
+  // Also test int32 and enum fields.
+  message.Clear();
+  message.set_oneof_uint32(0);  // would not go on wire if ordinary field.
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofUint32,
+            message.oneof_field_case());
+
+  message.Clear();
+  message.set_oneof_enum(proto2_nofieldpresence_unittest::
+                         TestAllTypes_NestedEnum_FOO);  // default value.
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(3, serialized.size());
+  EXPECT_TRUE(message.ParseFromString(serialized));
+  EXPECT_EQ(proto2_nofieldpresence_unittest::TestAllTypes::kOneofEnum,
+            message.oneof_field_case());
+
+  message.Clear();
+  message.set_oneof_string("test");
+  message.clear_oneof_string();
+  EXPECT_EQ(0, message.ByteSize());
+}
+
+}  // namespace
+}  // namespace protobuf
+
+}  // namespace google
diff --git a/src/google/protobuf/preserve_unknown_enum_test.cc b/src/google/protobuf/preserve_unknown_enum_test.cc
new file mode 100644
index 0000000..1673e8a
--- /dev/null
+++ b/src/google/protobuf/preserve_unknown_enum_test.cc
@@ -0,0 +1,289 @@
+// 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.
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum.pb.h>
+#include <google/protobuf/unittest_preserve_unknown_enum2.pb.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/descriptor.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+void FillMessage(
+    proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra* message) {
+  message->set_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_packed_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->add_repeated_packed_unexpected_e(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+  message->set_oneof_e_1(
+      proto3_preserve_unknown_enum_unittest::E_EXTRA);
+}
+
+void CheckMessage(
+    const proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra& message) {
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.e());
+  EXPECT_EQ(1, message.repeated_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_e(0));
+  EXPECT_EQ(1, message.repeated_packed_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_packed_e(0));
+  EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.repeated_packed_unexpected_e(0));
+  EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
+            message.oneof_e_1());
+}
+
+void CheckMessage(
+    const proto3_preserve_unknown_enum_unittest::MyMessage& message) {
+  EXPECT_EQ(static_cast<int>(
+              proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.e()));
+  EXPECT_EQ(1, message.repeated_e_size());
+  EXPECT_EQ(static_cast<int>(
+              proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_e(0)));
+  EXPECT_EQ(1, message.repeated_packed_e_size());
+  EXPECT_EQ(static_cast<int>(
+              proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_packed_e(0)));
+  EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
+  EXPECT_EQ(static_cast<int>(
+              proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.repeated_packed_unexpected_e(0)));
+  EXPECT_EQ(static_cast<int>(
+              proto3_preserve_unknown_enum_unittest::E_EXTRA),
+            static_cast<int>(message.oneof_e_1()));
+}
+
+}  // anonymous namespace
+
+// Test that parsing preserves an unknown value in the enum field and does not
+// punt it to the UnknownFieldSet.
+TEST(PreserveUnknownEnumTest, PreserveParseAndSerialize) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  CheckMessage(message);
+
+  serialized.clear();
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that reflection based implementation also keeps unknown enum values and
+// doesn't put them into UnknownFieldSet.
+TEST(PreserveUnknownEnumTest, PreserveParseAndSerializeDynamicMessage) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  string serialized = orig_message.SerializeAsString();
+
+  google::protobuf::DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
+      proto3_preserve_unknown_enum_unittest::MyMessage::descriptor())->New());
+  EXPECT_EQ(true, message->ParseFromString(serialized));
+  message->DiscardUnknownFields();
+
+  serialized = message->SerializeAsString();
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that for proto2 messages, unknown values are in unknown fields.
+TEST(PreserveUnknownEnumTest, Proto2HidesUnknownValues) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+
+  string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto2_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  // The intermediate message has everything in its "unknown fields".
+  proto2_preserve_unknown_enum_unittest::MyMessage message2 = message;
+  message2.DiscardUnknownFields();
+  EXPECT_EQ(0, message2.ByteSize());
+
+  // But when we pass it to the correct structure, all values are there.
+  serialized.clear();
+  message.SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Same as before, for a dynamic message.
+TEST(PreserveUnknownEnumTest, DynamicProto2HidesUnknownValues) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+
+  string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  google::protobuf::DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
+      proto2_preserve_unknown_enum_unittest::MyMessage::descriptor())->New());
+  EXPECT_EQ(true, message->ParseFromString(serialized));
+  // The intermediate message has everything in its "unknown fields".
+  proto2_preserve_unknown_enum_unittest::MyMessage message2;
+  message2.CopyFrom(*message);
+  message2.DiscardUnknownFields();
+  EXPECT_EQ(0, message2.ByteSize());
+
+  // But when we pass it to the correct structure, all values are there.
+  serialized.clear();
+  message->SerializeToString(&serialized);
+  EXPECT_EQ(true, orig_message.ParseFromString(serialized));
+  CheckMessage(orig_message);
+}
+
+// Test that reflection provides EnumValueDescriptors for unknown values.
+TEST(PreserveUnknownEnumTest, DynamicEnumValueDescriptors) {
+  proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
+  FillMessage(&orig_message);
+  string serialized;
+  orig_message.SerializeToString(&serialized);
+
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  EXPECT_EQ(true, message.ParseFromString(serialized));
+  CheckMessage(message);
+
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* d = message.GetDescriptor();
+  const google::protobuf::FieldDescriptor* field = d->FindFieldByName("e");
+
+  // This should dynamically create an EnumValueDescriptor.
+  const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message, field);
+  EXPECT_EQ(enum_value->number(),
+            static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
+
+  // Fetching value for a second time should return the same pointer.
+  const google::protobuf::EnumValueDescriptor* enum_value_second =
+      r->GetEnum(message, field);
+  EXPECT_EQ(enum_value, enum_value_second);
+
+  // Check the repeated case too.
+  const google::protobuf::FieldDescriptor* repeated_field =
+      d->FindFieldByName("repeated_e");
+  enum_value = r->GetRepeatedEnum(message, repeated_field, 0);
+  EXPECT_EQ(enum_value->number(),
+            static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
+  // Should reuse the same EnumValueDescriptor, even for a different field.
+  EXPECT_EQ(enum_value, enum_value_second);
+
+  // We should be able to use the returned value descriptor to set a value on
+  // another message.
+  google::protobuf::Message* m = message.New();
+  r->SetEnum(m, field, enum_value);
+  EXPECT_EQ(enum_value, r->GetEnum(*m, field));
+  delete m;
+}
+
+// Test that the new integer-based enum reflection API works.
+TEST(PreserveUnknownEnumTest, IntegerEnumReflectionAPI) {
+  proto3_preserve_unknown_enum_unittest::MyMessage message;
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* d = message.GetDescriptor();
+
+  const google::protobuf::FieldDescriptor* singular_field = d->FindFieldByName("e");
+  const google::protobuf::FieldDescriptor* repeated_field =
+      d->FindFieldByName("repeated_e");
+
+  r->SetEnumValue(&message, singular_field, 42);
+  EXPECT_EQ(42, r->GetEnumValue(message, singular_field));
+  r->AddEnumValue(&message, repeated_field, 42);
+  r->AddEnumValue(&message, repeated_field, 42);
+  EXPECT_EQ(42, r->GetRepeatedEnumValue(message, repeated_field, 0));
+  r->SetRepeatedEnumValue(&message, repeated_field, 1, 84);
+  EXPECT_EQ(84, r->GetRepeatedEnumValue(message, repeated_field, 1));
+  const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message,
+                                                             singular_field);
+  EXPECT_EQ(42, enum_value->number());
+}
+
+// Test that the EnumValue API works properly for proto2 messages as well.
+TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) {
+  protobuf_unittest::TestAllTypes message;  // proto2 message
+  const google::protobuf::Reflection* r = message.GetReflection();
+  const google::protobuf::Descriptor* d = message.GetDescriptor();
+  const google::protobuf::FieldDescriptor* repeated_field =
+      d->FindFieldByName("repeated_nested_enum");
+  // Add one element to the repeated field so that we can test
+  // SetRepeatedEnumValue.
+  const google::protobuf::EnumValueDescriptor* enum_value =
+      repeated_field->enum_type()->FindValueByName("BAR");
+  EXPECT_TRUE(enum_value != NULL);
+  r->AddEnum(&message, repeated_field, enum_value);
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+  const google::protobuf::FieldDescriptor* singular_field =
+      d->FindFieldByName("optional_nested_enum");
+  // Enum-field integer-based setters GOOGLE_DCHECK-fail on invalid values, in order to
+  // remain consistent with proto2 generated code.
+  EXPECT_DEBUG_DEATH({
+    r->SetEnumValue(&message, singular_field, 4242);
+    r->GetEnum(message, singular_field)->number();
+  }, "SetEnumValue accepts only valid integer values");
+  EXPECT_DEBUG_DEATH({
+    r->SetRepeatedEnumValue(&message, repeated_field, 0, 4242);
+    r->GetRepeatedEnum(message, repeated_field, 0);
+  }, "SetRepeatedEnumValue accepts only valid integer values");
+  EXPECT_DEBUG_DEATH({
+    r->AddEnumValue(&message, repeated_field, 4242);
+    r->GetRepeatedEnum(message, repeated_field, 1);
+  }, "AddEnumValue accepts only valid integer values");
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST(PreserveUnknownEnumTest, SupportsUnknownEnumValuesAPI) {
+  protobuf_unittest::TestAllTypes proto2_message;
+  proto3_preserve_unknown_enum_unittest::MyMessage new_message;
+
+  const google::protobuf::Reflection* proto2_reflection = proto2_message.GetReflection();
+  const google::protobuf::Reflection* new_reflection = new_message.GetReflection();
+
+  EXPECT_FALSE(proto2_reflection->SupportsUnknownEnumValues());
+  EXPECT_TRUE(new_reflection->SupportsUnknownEnumValues());
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_arena_lite_unittest.cc b/src/google/protobuf/proto3_arena_lite_unittest.cc
new file mode 100644
index 0000000..0f18c02
--- /dev/null
+++ b/src/google/protobuf/proto3_arena_lite_unittest.cc
@@ -0,0 +1,164 @@
+// 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.
+
+#include <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena_lite.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+using proto3_arena_lite_unittest::TestAllTypes;
+
+namespace protobuf {
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of arena support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(
+      proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->set_optional_foreign_enum(
+      proto3_arena_lite_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(
+      proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->add_repeated_foreign_enum(
+      proto3_arena_lite_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of arena support in
+// proto3 and expect the arena support to be fully tested in proto2 unittests
+// because proto3 shares most code with proto2.
+
+TEST(Proto3ArenaLiteTest, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+}
+
+TEST(Proto3ArenaLiteTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+
+  // Test Swap().
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+}
+
+TEST(Proto3ArenaLiteTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+}
+
+TEST(Proto3ArenaLiteTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc
new file mode 100644
index 0000000..2838e0f
--- /dev/null
+++ b/src/google/protobuf/proto3_arena_unittest.cc
@@ -0,0 +1,209 @@
+// 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.
+
+#include <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+using proto3_arena_unittest::TestAllTypes;
+
+namespace protobuf {
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of arena support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(
+      proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->set_optional_foreign_enum(
+      proto3_arena_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(
+      proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->add_repeated_foreign_enum(
+      proto3_arena_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto3_arena_unittest::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto3_arena_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of arena support in
+// proto3 and expect the arena support to be fully tested in proto2 unittests
+// because proto3 shares most code with proto2.
+
+TEST(Proto3ArenaTest, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+}
+
+TEST(Proto3ArenaTest, UnknownFields) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(*arena_message);
+
+  // In proto3 we can still get a pointer to the UnknownFieldSet through
+  // reflection API.
+  UnknownFieldSet* unknown_fields =
+      arena_message->GetReflection()->MutableUnknownFields(arena_message);
+  // We can modify this UnknownFieldSet.
+  unknown_fields->AddVarint(1, 2);
+  // But the change will never will serialized back.
+  ASSERT_EQ(original.ByteSize(), arena_message->ByteSize());
+  ASSERT_TRUE(
+      arena_message->GetReflection()->GetUnknownFields(*arena_message).empty());
+}
+
+TEST(Proto3ArenaTest, Swap) {
+  Arena arena1;
+  Arena arena2;
+
+  // Test Swap().
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
+  TestAllTypes* arena2_message = Arena::CreateMessage<TestAllTypes>(&arena2);
+  arena1_message->Swap(arena2_message);
+  EXPECT_EQ(&arena1, arena1_message->GetArena());
+  EXPECT_EQ(&arena2, arena2_message->GetArena());
+}
+
+TEST(Proto3ArenaTest, SetAllocatedMessage) {
+  Arena arena;
+  TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage;
+  nested->set_bb(118);
+  arena_message->set_allocated_optional_nested_message(nested);
+  EXPECT_EQ(118, arena_message->optional_nested_message().bb());
+}
+
+TEST(Proto3ArenaTest, ReleaseMessage) {
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
+      arena_message->release_optional_nested_message());
+  EXPECT_EQ(118, nested->bb());
+}
+
+TEST(Proto3ArenaTest, MessageFieldClear) {
+  // GitHub issue #310: https://github.com/google/protobuf/issues/310
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  // This should not crash, but prior to the bugfix, it tried to use `operator
+  // delete` the nested message (which is on the arena):
+  arena_message->Clear();
+}
+
+TEST(Proto3ArenaTest, MessageFieldClearViaReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Reflection* r = message->GetReflection();
+  const Descriptor* d = message->GetDescriptor();
+  const FieldDescriptor* msg_field = d->FindFieldByName(
+      "optional_nested_message");
+
+  message->mutable_optional_nested_message()->set_bb(1);
+  r->ClearField(message, msg_field);
+  EXPECT_FALSE(message->has_optional_nested_message());
+  EXPECT_EQ(0, message->optional_nested_message().bb());
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/proto3_lite_unittest.cc b/src/google/protobuf/proto3_lite_unittest.cc
new file mode 100644
index 0000000..2e2beea
--- /dev/null
+++ b/src/google/protobuf/proto3_lite_unittest.cc
@@ -0,0 +1,145 @@
+// 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.
+
+#include <string>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_lite.pb.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+using proto3_lite_unittest::TestAllTypes;
+
+namespace protobuf {
+namespace {
+// We selectively set/check a few representative fields rather than all fields
+// as this test is only expected to cover the basics of lite support.
+void SetAllFields(TestAllTypes* m) {
+  m->set_optional_int32(100);
+  m->set_optional_string("asdf");
+  m->set_optional_bytes("jkl;");
+  m->mutable_optional_nested_message()->set_bb(42);
+  m->mutable_optional_foreign_message()->set_c(43);
+  m->set_optional_nested_enum(
+      proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->set_optional_foreign_enum(
+      proto3_lite_unittest::FOREIGN_BAZ);
+  m->mutable_optional_lazy_message()->set_bb(45);
+  m->add_repeated_int32(100);
+  m->add_repeated_string("asdf");
+  m->add_repeated_bytes("jkl;");
+  m->add_repeated_nested_message()->set_bb(46);
+  m->add_repeated_foreign_message()->set_c(47);
+  m->add_repeated_nested_enum(
+      proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ);
+  m->add_repeated_foreign_enum(
+      proto3_lite_unittest::FOREIGN_BAZ);
+  m->add_repeated_lazy_message()->set_bb(49);
+
+  m->set_oneof_uint32(1);
+  m->mutable_oneof_nested_message()->set_bb(50);
+  m->set_oneof_string("test");  // only this one remains set
+}
+
+void ExpectAllFieldsSet(const TestAllTypes& m) {
+  EXPECT_EQ(100, m.optional_int32());
+  EXPECT_EQ("asdf", m.optional_string());
+  EXPECT_EQ("jkl;", m.optional_bytes());
+  EXPECT_EQ(true, m.has_optional_nested_message());
+  EXPECT_EQ(42, m.optional_nested_message().bb());
+  EXPECT_EQ(true, m.has_optional_foreign_message());
+  EXPECT_EQ(43, m.optional_foreign_message().c());
+  EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.optional_nested_enum());
+  EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ,
+            m.optional_foreign_enum());
+  EXPECT_EQ(true, m.has_optional_lazy_message());
+  EXPECT_EQ(45, m.optional_lazy_message().bb());
+
+  EXPECT_EQ(1, m.repeated_int32_size());
+  EXPECT_EQ(100, m.repeated_int32(0));
+  EXPECT_EQ(1, m.repeated_string_size());
+  EXPECT_EQ("asdf", m.repeated_string(0));
+  EXPECT_EQ(1, m.repeated_bytes_size());
+  EXPECT_EQ("jkl;", m.repeated_bytes(0));
+  EXPECT_EQ(1, m.repeated_nested_message_size());
+  EXPECT_EQ(46, m.repeated_nested_message(0).bb());
+  EXPECT_EQ(1, m.repeated_foreign_message_size());
+  EXPECT_EQ(47, m.repeated_foreign_message(0).c());
+  EXPECT_EQ(1, m.repeated_nested_enum_size());
+  EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ,
+            m.repeated_nested_enum(0));
+  EXPECT_EQ(1, m.repeated_foreign_enum_size());
+  EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ,
+            m.repeated_foreign_enum(0));
+  EXPECT_EQ(1, m.repeated_lazy_message_size());
+  EXPECT_EQ(49, m.repeated_lazy_message(0).bb());
+
+  EXPECT_EQ(proto3_lite_unittest::TestAllTypes::kOneofString,
+            m.oneof_field_case());
+  EXPECT_EQ("test", m.oneof_string());
+}
+
+// In this file we only test some basic functionalities of in proto3 and expect
+// the rest is fully tested in proto2 unittests because proto3 shares most code
+// with proto2.
+
+TEST(Proto3LiteTest, Parsing) {
+  TestAllTypes original;
+  SetAllFields(&original);
+
+  TestAllTypes msg;
+  msg.ParseFromString(original.SerializeAsString());
+  ExpectAllFieldsSet(msg);
+}
+
+TEST(Proto3LiteTest, Swap) {
+  // Test Swap().
+  TestAllTypes msg1;
+  TestAllTypes msg2;
+  msg1.set_optional_string("123");
+  msg2.set_optional_string("3456");
+  msg1.Swap(&msg2);
+  EXPECT_EQ("3456", msg1.optional_string());
+  EXPECT_EQ("123", msg2.optional_string());
+  EXPECT_EQ(msg1.ByteSize(), msg2.ByteSize() + 1);
+}
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
new file mode 100755
index 0000000..671aafd
--- /dev/null
+++ b/src/google/protobuf/reflection.h
@@ -0,0 +1,600 @@
+// 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.
+
+// This header defines the RepeatedFieldRef class template used to access
+// repeated fields with protobuf reflection API.
+#ifndef GOOGLE_PROTOBUF_REFLECTION_H__
+#define GOOGLE_PROTOBUF_REFLECTION_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/generated_enum_util.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<typename T, typename Enable = void>
+struct RefTypeTraits;
+}  // namespace internal
+
+template<typename T>
+RepeatedFieldRef<T> Reflection::GetRepeatedFieldRef(
+    const Message& message, const FieldDescriptor* field) const {
+  return RepeatedFieldRef<T>(message, field);
+}
+
+template<typename T>
+MutableRepeatedFieldRef<T> Reflection::GetMutableRepeatedFieldRef(
+    Message* message, const FieldDescriptor* field) const {
+  return MutableRepeatedFieldRef<T>(message, field);
+}
+
+// RepeatedFieldRef definition for non-message types.
+template<typename T>
+class RepeatedFieldRef<
+    T, typename internal::enable_if<!internal::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const {
+    return accessor_->IsEmpty(data_);
+  }
+  int size() const {
+    return accessor_->Size(data_);
+  }
+  T Get(int index) const {
+    return accessor_->template Get<T>(data_, index);
+  }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  iterator begin() const {
+    return iterator(data_, accessor_, true);
+  }
+  iterator end() const {
+    return iterator(data_, accessor_, false);
+  }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(
+      const Message& message,
+      const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        const_cast<Message*>(&message), field,
+        internal::RefTypeTraits<T>::cpp_type, NULL);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+};
+
+// MutableRepeatedFieldRef definition for non-message types.
+template<typename T>
+class MutableRepeatedFieldRef<
+    T, typename internal::enable_if<!internal::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const {
+    return accessor_->IsEmpty(data_);
+  }
+  int size() const {
+    return accessor_->Size(data_);
+  }
+  T Get(int index) const {
+    return accessor_->template Get<T>(data_, index);
+  }
+
+  void Set(int index, const T& value) const {
+    accessor_->template Set<T>(data_, index, value);
+  }
+  void Add(const T& value) const {
+    accessor_->template Add<T>(data_, value);
+  }
+  void RemoveLast() const {
+    accessor_->RemoveLast(data_);
+  }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const {
+    accessor_->Clear(data_);
+  }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template<typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template<typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(
+      Message* message,
+      const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type, NULL);
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+};
+
+// RepeatedFieldRef definition for message types.
+template<typename T>
+class RepeatedFieldRef<
+    T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::iterator IteratorType;
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const {
+    return accessor_->IsEmpty(data_);
+  }
+  int size() const {
+    return accessor_->Size(data_);
+  }
+  // This method returns a reference to the underlying message object if it
+  // exists. If a message object doesn't exist (e.g., data stored in serialized
+  // form), scratch_space will be filled with the data and a reference to it
+  // will be returned.
+  //
+  // Example:
+  //   RepeatedFieldRef<Message> h = ...
+  //   unique_ptr<Message> scratch_space(h.NewMessage());
+  //   const Message& item = h.Get(index, scratch_space.get());
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const {
+    return static_cast<T*>(default_instance_->New());
+  }
+
+  typedef IteratorType iterator;
+  typedef IteratorType const_iterator;
+  iterator begin() const {
+    return iterator(data_, accessor_, true, NewMessage());
+  }
+  iterator end() const {
+    return iterator(data_, accessor_, false, NewMessage());
+  }
+
+ private:
+  friend class Reflection;
+  RepeatedFieldRef(
+      const Message& message,
+      const FieldDescriptor* field) {
+    const Reflection* reflection = message.GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        const_cast<Message*>(&message), field,
+        internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  const void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+// MutableRepeatedFieldRef definition for message types.
+template<typename T>
+class MutableRepeatedFieldRef<
+    T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+  typedef typename internal::RefTypeTraits<T>::AccessorType AccessorType;
+
+ public:
+  bool empty() const {
+    return accessor_->IsEmpty(data_);
+  }
+  int size() const {
+    return accessor_->Size(data_);
+  }
+  // See comments for RepeatedFieldRef<Message>::Get()
+  const T& Get(int index, T* scratch_space) const {
+    return *static_cast<const T*>(accessor_->Get(data_, index, scratch_space));
+  }
+  // Create a new message of the same type as the messages stored in this
+  // repeated field. Caller takes ownership of the returned object.
+  T* NewMessage() const {
+    return static_cast<T*>(default_instance_->New());
+  }
+
+  void Set(int index, const T& value) const {
+    accessor_->Set(data_, index, &value);
+  }
+  void Add(const T& value) const {
+    accessor_->Add(data_, &value);
+  }
+  void RemoveLast() const {
+    accessor_->RemoveLast(data_);
+  }
+  void SwapElements(int index1, int index2) const {
+    accessor_->SwapElements(data_, index1, index2);
+  }
+  void Clear() const {
+    accessor_->Clear(data_);
+  }
+
+  void Swap(const MutableRepeatedFieldRef& other) const {
+    accessor_->Swap(data_, other.accessor_, other.data_);
+  }
+
+  template<typename Container>
+  void MergeFrom(const Container& container) const {
+    typedef typename Container::const_iterator Iterator;
+    for (Iterator it = container.begin(); it != container.end(); ++it) {
+      Add(*it);
+    }
+  }
+  template<typename Container>
+  void CopyFrom(const Container& container) const {
+    Clear();
+    MergeFrom(container);
+  }
+
+ private:
+  friend class Reflection;
+  MutableRepeatedFieldRef(
+      Message* message,
+      const FieldDescriptor* field) {
+    const Reflection* reflection = message->GetReflection();
+    data_ = reflection->RepeatedFieldData(
+        message, field, internal::RefTypeTraits<T>::cpp_type,
+        internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
+    accessor_ = reflection->RepeatedFieldAccessor(field);
+    default_instance_ =
+        reflection->GetMessageFactory()->GetPrototype(field->message_type());
+  }
+
+  void* data_;
+  const AccessorType* accessor_;
+  const Message* default_instance_;
+};
+
+namespace internal {
+// Interfaces used to implement reflection RepeatedFieldRef API.
+// Reflection::GetRepeatedAccessor() should return a pointer to an singleton
+// object that implements the below interface.
+//
+// This interface passes/returns values using void pointers. The actual type
+// of the value depends on the field's cpp_type. Following is a mapping from
+// cpp_type to the type that should be used in this interface:
+//
+//   field->cpp_type()      T                Actual type of void*
+//   CPPTYPE_INT32        int32                   int32
+//   CPPTYPE_UINT32       uint32                  uint32
+//   CPPTYPE_INT64        int64                   int64
+//   CPPTYPE_UINT64       uint64                  uint64
+//   CPPTYPE_DOUBLE       double                  double
+//   CPPTYPE_FLOAT        float                   float
+//   CPPTYPE_BOOL         bool                    bool
+//   CPPTYPE_ENUM         generated enum type     int32
+//   CPPTYPE_STRING       string                  string
+//   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
+//                        or google::protobuf::Message
+//
+// Note that for enums we use int32 in the interface.
+//
+// You can map from T to the actual type using RefTypeTraits:
+//   typedef RefTypeTraits<T>::AccessorValueType ActualType;
+class LIBPROTOBUF_EXPORT RepeatedFieldAccessor {
+ public:
+  // Typedefs for clarity.
+  typedef void Field;
+  typedef void Value;
+  typedef void Iterator;
+
+  virtual ~RepeatedFieldAccessor();
+  virtual bool IsEmpty(const Field* data) const = 0;
+  virtual int Size(const Field* data) const = 0;
+  // Depends on the underlying representation of the repeated field, this
+  // method can return a pointer to the underlying object if such an object
+  // exists, or fill the data into scratch_space and return scratch_space.
+  // Callers of this method must ensure scratch_space is a valid pointer
+  // to a mutable object of the correct type.
+  virtual const Value* Get(
+      const Field* data, int index, Value* scratch_space) const = 0;
+
+  virtual void Clear(Field* data) const = 0;
+  virtual void Set(Field* data, int index, const Value* value) const = 0;
+  virtual void Add(Field* data, const Value* value) const = 0;
+  virtual void RemoveLast(Field* data) const = 0;
+  virtual void SwapElements(Field* data, int index1, int index2) const = 0;
+  virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator,
+                    Field* other_data) const = 0;
+
+  // Create an iterator that points at the begining of the repeated field.
+  virtual Iterator* BeginIterator(const Field* data) const = 0;
+  // Create an iterator that points at the end of the repeated field.
+  virtual Iterator* EndIterator(const Field* data) const = 0;
+  // Make a copy of an iterator and return the new copy.
+  virtual Iterator* CopyIterator(const Field* data,
+                                 const Iterator* iterator) const = 0;
+  // Move an iterator to point to the next element.
+  virtual Iterator* AdvanceIterator(const Field* data,
+                                    Iterator* iterator) const = 0;
+  // Compare whether two iterators point to the same element.
+  virtual bool EqualsIterator(const Field* data, const Iterator* a,
+                              const Iterator* b) const = 0;
+  // Delete an iterator created by BeginIterator(), EndIterator() and
+  // CopyIterator().
+  virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0;
+  // Like Get() but for iterators.
+  virtual const Value* GetIteratorValue(const Field* data,
+                                        const Iterator* iterator,
+                                        Value* scratch_space) const = 0;
+
+  // Templated methods that make using this interface easier for non-message
+  // types.
+  template<typename T>
+  T Get(const Field* data, int index) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    ActualType scratch_space;
+    return static_cast<T>(
+        *reinterpret_cast<const ActualType*>(
+            Get(data, index, static_cast<Value*>(&scratch_space))));
+  }
+
+  template<typename T, typename ValueType>
+  void Set(Field* data, int index, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Set(data, index, static_cast<const Value*>(&tmp));
+  }
+
+  template<typename T, typename ValueType>
+  void Add(Field* data, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Add(data, static_cast<const Value*>(&tmp));
+  }
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template<typename T>
+class RepeatedFieldRefIterator
+    : public std::iterator<std::forward_iterator_tag, T> {
+  typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+  typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+  typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType;
+
+ public:
+  // Constructor for non-message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor,
+                           bool begin)
+      : data_(data), accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data) :
+                          accessor->EndIterator(data)),
+        scratch_space_(new AccessorValueType) {
+  }
+  // Constructor for message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor,
+                           bool begin,
+                           AccessorValueType* scratch_space)
+      : data_(data), accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data) :
+                          accessor->EndIterator(data)),
+        scratch_space_(scratch_space) {
+  }
+  ~RepeatedFieldRefIterator() {
+    accessor_->DeleteIterator(data_, iterator_);
+  }
+  RepeatedFieldRefIterator operator++(int) {
+    RepeatedFieldRefIterator tmp(*this);
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return tmp;
+  }
+  RepeatedFieldRefIterator& operator++() {
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return *this;
+  }
+  IteratorValueType operator*() const {
+    return static_cast<IteratorValueType>(
+        *static_cast<const AccessorValueType*>(
+            accessor_->GetIteratorValue(
+                data_, iterator_, scratch_space_.get())));
+  }
+  IteratorPointerType operator->() const {
+    return static_cast<IteratorPointerType>(
+        accessor_->GetIteratorValue(
+            data_, iterator_, scratch_space_.get()));
+  }
+  bool operator!=(const RepeatedFieldRefIterator& other) const {
+    assert(data_ == other.data_);
+    assert(accessor_ == other.accessor_);
+    return !accessor_->EqualsIterator(data_, iterator_, other.iterator_);
+  }
+  bool operator==(const RepeatedFieldRefIterator& other) const {
+    return !this->operator!=(other);
+  }
+
+  RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other)
+      : data_(other.data_), accessor_(other.accessor_),
+        iterator_(accessor_->CopyIterator(data_, other.iterator_)) {
+  }
+  RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) {
+    if (this != &other) {
+      accessor_->DeleteIterator(data_, iterator_);
+      data_ = other.data_;
+      accessor_ = other.accessor_;
+      iterator_ = accessor_->CopyIterator(data_, other.iterator_);
+    }
+    return *this;
+  }
+
+ protected:
+  const void* data_;
+  const RepeatedFieldAccessor* accessor_;
+  void* iterator_;
+  google::protobuf::scoped_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template<typename T>
+struct PrimitiveTraits {
+  static const bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type) \
+    template<> struct PrimitiveTraits<type> { \
+      static const bool is_primitive = true; \
+      static const FieldDescriptor::CppType cpp_type = \
+          FieldDescriptor::CPPTYPE_ ## TYPE; \
+    };
+DEFINE_PRIMITIVE(INT32, int32)
+DEFINE_PRIMITIVE(UINT32, uint32)
+DEFINE_PRIMITIVE(INT64, int64)
+DEFINE_PRIMITIVE(UINT64, uint64)
+DEFINE_PRIMITIVE(FLOAT, float)
+DEFINE_PRIMITIVE(DOUBLE, double)
+DEFINE_PRIMITIVE(BOOL, bool)
+#undef DEFINE_PRIMITIVE
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef T AccessorValueType;
+  typedef T IteratorValueType;
+  typedef T* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      PrimitiveTraits<T>::cpp_type;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<is_proto_enum<T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  // We use int32 for repeated enums in RepeatedFieldAccessor.
+  typedef int32 AccessorValueType;
+  typedef T IteratorValueType;
+  typedef int32* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_ENUM;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if< ::google::protobuf::internal::is_same<string, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef string AccessorValueType;
+  typedef string IteratorValueType;
+  typedef string* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_STRING;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct MessageDescriptorGetter {
+  static const Descriptor* get() {
+    return T::default_instance().GetDescriptor();
+  }
+};
+template<>
+struct MessageDescriptorGetter<Message> {
+  static const Descriptor* get() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef Message AccessorValueType;
+  typedef const T& IteratorValueType;
+  typedef const T* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_MESSAGE;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return MessageDescriptorGetter<T>::get();
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_REFLECTION_H__
diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h
new file mode 100644
index 0000000..fcb4247
--- /dev/null
+++ b/src/google/protobuf/reflection_internal.h
@@ -0,0 +1,378 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+#define GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
+
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/reflection.h>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// A base class for RepeatedFieldAccessor implementations that can support
+// random-access efficiently. All iterator methods delegates the work to
+// corresponding random-access methods.
+class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
+ public:
+  virtual ~RandomAccessRepeatedFieldAccessor() {}
+
+  virtual Iterator* BeginIterator(const Field* data) const {
+    return PositionToIterator(0);
+  }
+  virtual Iterator* EndIterator(const Field* data) const {
+    return PositionToIterator(this->Size(data));
+  }
+  virtual Iterator* CopyIterator(const Field* data,
+                                 const Iterator* iterator) const {
+    return const_cast<Iterator*>(iterator);
+  }
+  virtual Iterator* AdvanceIterator(const Field* data,
+                                    Iterator* iterator) const {
+    return PositionToIterator(IteratorToPosition(iterator) + 1);
+  }
+  virtual bool EqualsIterator(const Field* data,
+                              const Iterator* a,
+                              const Iterator* b) const {
+    return a == b;
+  }
+  virtual void DeleteIterator(const Field* data, Iterator* iterator) const {
+  }
+  virtual const Value* GetIteratorValue(const Field* data,
+                                        const Iterator* iterator,
+                                        Value* scratch_space) const {
+    return Get(data, static_cast<int>(IteratorToPosition(iterator)),
+               scratch_space);
+  }
+
+ private:
+  static intptr_t IteratorToPosition(const Iterator* iterator) {
+    return reinterpret_cast<intptr_t>(iterator);
+  }
+  static Iterator* PositionToIterator(intptr_t position) {
+    return reinterpret_cast<Iterator*>(position);
+  }
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedField<T>.
+template<typename T>
+class RepeatedFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  RepeatedFieldWrapper() {}
+  virtual ~RepeatedFieldWrapper() {}
+  virtual bool IsEmpty(const Field* data) const {
+    return GetRepeatedField(data)->empty();
+  }
+  virtual int Size(const Field* data) const {
+    return GetRepeatedField(data)->size();
+  }
+  virtual const Value* Get(const Field* data, int index,
+                          Value* scratch_space) const {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  virtual void Clear(Field* data) const {
+    MutableRepeatedField(data)->Clear();
+  }
+  virtual void Set(Field* data, int index, const Value* value) const {
+    MutableRepeatedField(data)->Set(index, ConvertToT(value));
+  }
+  virtual void Add(Field* data, const Value* value) const {
+    MutableRepeatedField(data)->Add(ConvertToT(value));
+  }
+  virtual void RemoveLast(Field* data) const {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  virtual void SwapElements(Field* data, int index1, int index2) const {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  typedef RepeatedField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Convert an object recevied by this accessor to an object to be stored in
+  // the underlying RepeatedField.
+  virtual T ConvertToT(const Value* value) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true
+  // for string fields with ctype=STRING), a pointer to the source object can
+  // be returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// Base class for RepeatedFieldAccessor implementations that manipulates
+// RepeatedPtrField<T>.
+template<typename T>
+class RepeatedPtrFieldWrapper : public RandomAccessRepeatedFieldAccessor {
+ public:
+  RepeatedPtrFieldWrapper() {}
+  virtual ~RepeatedPtrFieldWrapper() {}
+  virtual bool IsEmpty(const Field* data) const {
+    return GetRepeatedField(data)->empty();
+  }
+  virtual int Size(const Field* data) const {
+    return GetRepeatedField(data)->size();
+  }
+  virtual const Value* Get(const Field* data, int index,
+                           Value* scratch_space) const {
+    return ConvertFromT(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  virtual void Clear(Field* data) const {
+    MutableRepeatedField(data)->Clear();
+  }
+  virtual void Set(Field* data, int index, const Value* value) const {
+    ConvertToT(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  virtual void Add(Field* data, const Value* value) const {
+    T* allocated = New(value);
+    ConvertToT(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  virtual void RemoveLast(Field* data) const {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  virtual void SwapElements(Field* data, int index1, int index2) const {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+
+ protected:
+  typedef RepeatedPtrField<T> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(data);
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(data);
+  }
+
+  // Create a new T instance. For repeated message fields, T can be specified
+  // as google::protobuf::Message so we can't use "new T()" directly. In that case, value
+  // should be a message of the same type (it's ensured by the caller) and a
+  // new message object will be created using it.
+  virtual T* New(const Value* value) const = 0;
+
+  // Convert an object received by this accessor to an object that will be
+  // stored in the underlying RepeatedPtrField.
+  virtual void ConvertToT(const Value* value, T* result) const = 0;
+
+  // Convert an object stored in RepeatedPtrField to an object that will be
+  // returned by this accessor. If the two objects have the same type (true
+  // for string fields with ctype=STRING), a pointer to the source object can
+  // be returned directly. Otherwise, data should be copied from value to
+  // scratch_space and scratch_space should be returned.
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const = 0;
+};
+
+// An implementation of RandomAccessRepeatedFieldAccessor that manipulates
+// MapFieldBase.
+class MapFieldAccessor : public RandomAccessRepeatedFieldAccessor {
+ public:
+  MapFieldAccessor() {}
+  virtual ~MapFieldAccessor() {}
+  virtual bool IsEmpty(const Field* data) const {
+    return GetRepeatedField(data)->empty();
+  }
+  virtual int Size(const Field* data) const {
+    return GetRepeatedField(data)->size();
+  }
+  virtual const Value* Get(const Field* data, int index,
+                           Value* scratch_space) const {
+    return ConvertFromEntry(GetRepeatedField(data)->Get(index), scratch_space);
+  }
+  virtual void Clear(Field* data) const {
+    MutableRepeatedField(data)->Clear();
+  }
+  virtual void Set(Field* data, int index, const Value* value) const {
+    ConvertToEntry(value, MutableRepeatedField(data)->Mutable(index));
+  }
+  virtual void Add(Field* data, const Value* value) const {
+    Message* allocated = New(value);
+    ConvertToEntry(value, allocated);
+    MutableRepeatedField(data)->AddAllocated(allocated);
+  }
+  virtual void RemoveLast(Field* data) const {
+    MutableRepeatedField(data)->RemoveLast();
+  }
+  virtual void SwapElements(Field* data, int index1, int index2) const {
+    MutableRepeatedField(data)->SwapElements(index1, index2);
+  }
+  virtual void Swap(
+      Field* data,
+      const internal::RepeatedFieldAccessor* other_mutator,
+      Field* other_data) const {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  typedef RepeatedPtrField<Message> RepeatedFieldType;
+  static const RepeatedFieldType* GetRepeatedField(const Field* data) {
+    return reinterpret_cast<const RepeatedFieldType*>(
+        (&reinterpret_cast<const MapFieldBase*>(data)->GetRepeatedField()));
+  }
+  static RepeatedFieldType* MutableRepeatedField(Field* data) {
+    return reinterpret_cast<RepeatedFieldType*>(
+        reinterpret_cast<MapFieldBase*>(data)->MutableRepeatedField());
+  }
+  virtual Message* New(const Value* value) const {
+    return static_cast<const Message*>(value)->New();
+  }
+  // Convert an object received by this accessor to an MapEntry message to be
+  // stored in the underlying MapFieldBase.
+  virtual void ConvertToEntry(const Value* value, Message* result) const {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  // Convert a MapEntry message stored in the underlying MapFieldBase to an
+  // object that will be returned by this accessor.
+  virtual const Value* ConvertFromEntry(const Message& value,
+                                        Value* scratch_space) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementations of RepeatedFieldAccessor for primitive types.
+template<typename T>
+class RepeatedFieldPrimitiveAccessor : public RepeatedFieldWrapper<T> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldWrapper<T>::MutableRepeatedField;
+
+ public:
+  RepeatedFieldPrimitiveAccessor() {}
+  virtual ~RepeatedFieldPrimitiveAccessor() {}
+  virtual void Swap(
+      Field* data,
+      const internal::RepeatedFieldAccessor* other_mutator,
+      Field* other_data) const {
+    // Currently RepeatedFieldPrimitiveAccessor is the only implementation of
+    // RepeatedFieldAccessor for primitive types. As we are using singletons
+    // for these accessors, here "other_mutator" must be "this".
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  virtual T ConvertToT(const Value* value) const {
+    return *static_cast<const T*>(value);
+  }
+  virtual const Value* ConvertFromT(const T& value,
+                                    Value* scratch_space) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+// Default implementation of RepeatedFieldAccessor for string fields with
+// ctype=STRING.
+class RepeatedPtrFieldStringAccessor : public RepeatedPtrFieldWrapper<string> {
+  typedef void Field;
+  typedef void Value;
+  using RepeatedFieldAccessor::Add;
+
+ public:
+  RepeatedPtrFieldStringAccessor() {}
+  virtual ~RepeatedPtrFieldStringAccessor() {}
+  virtual void Swap(
+      Field* data,
+      const internal::RepeatedFieldAccessor* other_mutator,
+      Field* other_data) const {
+    if (this == other_mutator) {
+      MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+    } else {
+      RepeatedPtrField<string> tmp;
+      tmp.Swap(MutableRepeatedField(data));
+      int other_size = other_mutator->Size(other_data);
+      for (int i = 0; i < other_size; ++i) {
+        Add<string>(data, other_mutator->Get<string>(other_data, i));
+      }
+      int size = Size(data);
+      other_mutator->Clear(other_data);
+      for (int i = 0; i < size; ++i) {
+        other_mutator->Add<string>(other_data, tmp.Get(i));
+      }
+    }
+  }
+
+ protected:
+  virtual string* New(const Value*) const {
+    return new string();
+  }
+  virtual void ConvertToT(const Value* value, string* result) const {
+    *result = *static_cast<const string*>(value);
+  }
+  virtual const Value* ConvertFromT(const string& value,
+                                    Value* scratch_space) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+
+
+class RepeatedPtrFieldMessageAccessor
+    : public RepeatedPtrFieldWrapper<Message> {
+  typedef void Field;
+  typedef void Value;
+
+ public:
+  RepeatedPtrFieldMessageAccessor() {}
+  virtual ~RepeatedPtrFieldMessageAccessor() {}
+  virtual void Swap(
+      Field* data,
+      const internal::RepeatedFieldAccessor* other_mutator,
+      Field* other_data) const {
+    GOOGLE_CHECK(this == other_mutator);
+    MutableRepeatedField(data)->Swap(MutableRepeatedField(other_data));
+  }
+
+ protected:
+  virtual Message* New(const Value* value) const {
+    return static_cast<const Message*>(value)->New();
+  }
+  virtual void ConvertToT(const Value* value, Message* result) const {
+    result->CopyFrom(*static_cast<const Message*>(value));
+  }
+  virtual const Value* ConvertFromT(const Message& value,
+                                    Value* scratch_space) const {
+    return static_cast<const Value*>(&value);
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_REFLECTION_INTERNAL_H__
diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc
index 32740ea..88d6bfb 100644
--- a/src/google/protobuf/reflection_ops_unittest.cc
+++ b/src/google/protobuf/reflection_ops_unittest.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/test_util.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
index b400732..77004f5 100644
--- a/src/google/protobuf/repeated_field.cc
+++ b/src/google/protobuf/repeated_field.cc
@@ -35,6 +35,7 @@
 #include <algorithm>
 
 #include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -42,42 +43,56 @@
 
 namespace internal {
 
-void RepeatedPtrFieldBase::Reserve(int new_size) {
-  if (total_size_ >= new_size) return;
+void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
+  int new_size = current_size_ + extend_amount;
+  if (total_size_ >= new_size) {
+    // N.B.: rep_ is non-NULL because extend_amount is always > 0, hence
+    // total_size must be non-zero since it is lower-bounded by new_size.
+    return &rep_->elements[current_size_];
+  }
+  Rep* old_rep = rep_;
+  Arena* arena = GetArenaNoVirtual();
+  new_size = std::max(kMinRepeatedFieldAllocationSize,
+                      std::max(total_size_ * 2, new_size));
+  GOOGLE_CHECK_LE(new_size,
+           (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
+           sizeof(old_rep->elements[0]))
+      << "Requested size is too large to fit into size_t.";
+  if (arena == NULL) {
+    rep_ = reinterpret_cast<Rep*>(
+        new char[kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size]);
+  } else {
+    rep_ = reinterpret_cast<Rep*>(
+        ::google::protobuf::Arena::CreateArray<char>(arena,
+            kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size));
+  }
+  total_size_ = new_size;
+  if (old_rep && old_rep->allocated_size > 0) {
+    memcpy(rep_->elements, old_rep->elements,
+           old_rep->allocated_size * sizeof(rep_->elements[0]));
+    rep_->allocated_size = old_rep->allocated_size;
+  } else {
+    rep_->allocated_size = 0;
+  }
+  if (arena == NULL) {
+    delete [] reinterpret_cast<char*>(old_rep);
+  }
+  return &rep_->elements[current_size_];
+}
 
-  void** old_elements = elements_;
-  total_size_ = max(kMinRepeatedFieldAllocationSize,
-                    max(total_size_ * 2, new_size));
-  elements_ = new void*[total_size_];
-  if (old_elements != NULL) {
-    memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
-    delete [] old_elements;
+void RepeatedPtrFieldBase::Reserve(int new_size) {
+  if (new_size > current_size_) {
+    InternalExtend(new_size - current_size_);
   }
 }
 
-void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
-  if (this == other) return;
-  void** swap_elements       = elements_;
-  int    swap_current_size   = current_size_;
-  int    swap_allocated_size = allocated_size_;
-  int    swap_total_size     = total_size_;
-
-  elements_       = other->elements_;
-  current_size_   = other->current_size_;
-  allocated_size_ = other->allocated_size_;
-  total_size_     = other->total_size_;
-
-  other->elements_       = swap_elements;
-  other->current_size_   = swap_current_size;
-  other->allocated_size_ = swap_allocated_size;
-  other->total_size_     = swap_total_size;
-}
-
-string* StringTypeHandlerBase::New() {
-  return new string;
-}
-void StringTypeHandlerBase::Delete(string* value) {
-  delete value;
+void RepeatedPtrFieldBase::CloseGap(int start, int num) {
+  if (rep_ == NULL) return;
+  // Close up a gap of "num" elements starting at offset "start".
+  for (int i = start + num; i < rep_->allocated_size; ++i)
+    rep_->elements[i - num] = rep_->elements[i];
+  current_size_ -= num;
+  rep_->allocated_size -= num;
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 816ea68..1961bc4 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -53,8 +53,11 @@
 
 #include <string>
 #include <iterator>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/type_traits.h>
+#include <google/protobuf/arena.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message_lite.h>
 
@@ -84,7 +87,7 @@
 
 template <typename Iter>
 inline int CalculateReserve(Iter /*begin*/, Iter /*end*/,
-                            std::input_iterator_tag) {
+                            std::input_iterator_tag /*unused*/) {
   return -1;
 }
 
@@ -104,6 +107,7 @@
 class RepeatedField {
  public:
   RepeatedField();
+  explicit RepeatedField(Arena* arena);
   RepeatedField(const RepeatedField& other);
   template <typename Iter>
   RepeatedField(Iter begin, const Iter& end);
@@ -153,9 +157,16 @@
   Element* mutable_data();
   const Element* data() const;
 
-  // Swap entire contents with "other".
+  // Swap entire contents with "other". If they are separate arenas then, copies
+  // data between each other.
   void Swap(RepeatedField* other);
 
+  // Swap entire contents with "other". Should be called only if the caller can
+  // guarantee that both repeated fields are on the same arena or are on the
+  // heap. Swapping between different arenas is disallowed and caught by a
+  // GOOGLE_DCHECK (see API docs for details).
+  void UnsafeArenaSwap(RepeatedField* other);
+
   // Swap two elements.
   void SwapElements(int index1, int index2);
 
@@ -172,8 +183,10 @@
 
   iterator begin();
   const_iterator begin() const;
+  const_iterator cbegin() const;
   iterator end();
   const_iterator end() const;
+  const_iterator cend() const;
 
   // Reverse iterator support
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
@@ -195,22 +208,92 @@
   // sizeof(*this)
   int SpaceUsedExcludingSelf() const;
 
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
+  iterator erase(const_iterator position);
+
+  // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
+  iterator erase(const_iterator first, const_iterator last);
+
+  // Get the Arena on which this RepeatedField stores its elements.
+  ::google::protobuf::Arena* GetArena() const {
+    return GetArenaNoVirtual();
+  }
+
  private:
   static const int kInitialSize = 0;
+  // A note on the representation here (see also comment below for
+  // RepeatedPtrFieldBase's struct Rep):
+  //
+  // We maintain the same sizeof(RepeatedField) as before we added arena support
+  // so that we do not degrade performance by bloating memory usage. Directly
+  // adding an arena_ element to RepeatedField is quite costly. By using
+  // indirection in this way, we keep the same size when the RepeatedField is
+  // empty (common case), and add only an 8-byte header to the elements array
+  // when non-empty. We make sure to place the size fields directly in the
+  // RepeatedField class to avoid costly cache misses due to the indirection.
+  int current_size_;
+  int total_size_;
+  struct Rep {
+    Arena* arena;
+    Element elements[1];
+  };
+  // We can not use sizeof(Rep) - sizeof(Element) due to the trailing padding on
+  // the struct. We can not use sizeof(Arena*) as well because there might be
+  // a "gap" after the field arena and before the field elements (e.g., when
+  // Element is double and pointer is 32bit).
+  static const size_t kRepHeaderSize;
+  // Contains arena ptr and the elements array. We also keep the invariant that
+  // if rep_ is NULL, then arena is NULL.
+  Rep* rep_;
 
-  Element* elements_;
-  int      current_size_;
-  int      total_size_;
+  friend class Arena;
+  typedef void InternalArenaConstructable_;
 
   // Move the contents of |from| into |to|, possibly clobbering |from| in the
   // process.  For primitive types this is just a memcpy(), but it could be
   // specialized for non-primitive types to, say, swap each element instead.
-  void MoveArray(Element to[], Element from[], int size);
+  void MoveArray(Element* to, Element* from, int size);
 
   // Copy the elements of |from| into |to|.
-  void CopyArray(Element to[], const Element from[], int size);
+  void CopyArray(Element* to, const Element* from, int size);
+
+  inline void InternalSwap(RepeatedField* other);
+
+  // Internal helper expected by Arena methods.
+  inline Arena* GetArenaNoVirtual() const {
+    return (rep_ == NULL) ? NULL : rep_->arena;
+  }
+
+  // Internal helper to delete all elements and deallocate the storage.
+  // If Element has a trivial destructor (for example, if it's a fundamental
+  // type, like int32), the loop will be removed by the optimizer.
+  void InternalDeallocate(Rep* rep, int size) {
+    if (rep != NULL) {
+      Element* e = &rep->elements[0];
+      Element* limit = &rep->elements[size];
+      for (; e < limit; e++) {
+        e->Element::~Element();
+      }
+      if (rep->arena == NULL) {
+        delete[] reinterpret_cast<char*>(rep);
+      }
+    }
+  }
 };
 
+template<typename Element>
+const size_t RepeatedField<Element>::kRepHeaderSize =
+    reinterpret_cast<size_t>(&reinterpret_cast<Rep*>(16)->elements[0]) - 16;
+
 namespace internal {
 template <typename It> class RepeatedPtrIterator;
 template <typename It, typename VoidPtr> class RepeatedPtrOverPtrsIterator;
@@ -225,13 +308,48 @@
 template <typename Element,
           bool HasTrivialCopy = has_trivial_copy<Element>::value>
 struct ElementCopier {
-  void operator()(Element to[], const Element from[], int array_size);
+  void operator()(Element* to, const Element* from, int array_size);
 };
 
 }  // namespace internal
 
 namespace internal {
 
+// type-traits helper for RepeatedPtrFieldBase: we only want to invoke
+// arena-related "copy if on different arena" behavior if the necessary methods
+// exist on the contained type. In particular, we rely on MergeFrom() existing
+// as a general proxy for the fact that a copy will work, and we also provide a
+// specific override for string*.
+template<typename T>
+struct TypeImplementsMergeBehavior {
+  typedef char HasMerge;
+  typedef long HasNoMerge;
+
+  // We accept either of:
+  // - void MergeFrom(const T& other)
+  // - bool MergeFrom(const T& other)
+  //
+  // We mangle these names a bit to avoid compatibility issues in 'unclean'
+  // include environments that may have, e.g., "#define test ..." (yes, this
+  // exists).
+  template<typename U, typename RetType, RetType (U::*)(const U& arg)>
+      struct CheckType;
+  template<typename U> static HasMerge Check(
+      CheckType<U, void, &U::MergeFrom>*);
+  template<typename U> static HasMerge Check(
+      CheckType<U, bool, &U::MergeFrom>*);
+  template<typename U> static HasNoMerge Check(...);
+
+  // Resovles to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
+  typedef google::protobuf::internal::integral_constant<bool,
+               (sizeof(Check<T>(0)) == sizeof(HasMerge))> type;
+};
+
+template<>
+struct TypeImplementsMergeBehavior< ::std::string > {
+  typedef google::protobuf::internal::true_type type;
+};
+
 // This is the common base class for RepeatedPtrFields.  It deals only in void*
 // pointers.  Users should not use this interface directly.
 //
@@ -262,11 +380,18 @@
   // use of AddFromCleared(), which is not part of the public interface.
   friend class ExtensionSet;
 
+  // The MapFieldBase implementation needs to call protected methods directly,
+  // reinterpreting pointers as being to Message instead of a specific Message
+  // subclass.
+  friend class MapFieldBase;
+
   // To parse directly into a proto2 generated class, the upb class GMR_Handlers
   // needs to be able to modify a RepeatedPtrFieldBase directly.
-  friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
+  friend class upb::google_opensource::GMR_Handlers;
 
   RepeatedPtrFieldBase();
+  explicit RepeatedPtrFieldBase(::google::protobuf::Arena* arena);
+  ~RepeatedPtrFieldBase() {}
 
   // Must be called from destructor.
   template <typename TypeHandler>
@@ -280,7 +405,10 @@
   template <typename TypeHandler>
   typename TypeHandler::Type* Mutable(int index);
   template <typename TypeHandler>
-  typename TypeHandler::Type* Add();
+  void Delete(int index);
+  template <typename TypeHandler>
+  typename TypeHandler::Type* Add(typename TypeHandler::Type* prototype = NULL);
+
   template <typename TypeHandler>
   void RemoveLast();
   template <typename TypeHandler>
@@ -290,13 +418,7 @@
   template <typename TypeHandler>
   void CopyFrom(const RepeatedPtrFieldBase& other);
 
-  void CloseGap(int start, int num) {
-    // Close up a gap of "num" elements starting at offset "start".
-    for (int i = start + num; i < allocated_size_; ++i)
-      elements_[i - num] = elements_[i];
-    current_size_ -= num;
-    allocated_size_ -= num;
-  }
+  void CloseGap(int start, int num);
 
   void Reserve(int new_size);
 
@@ -311,7 +433,8 @@
   template <typename TypeHandler>
   const typename TypeHandler::Type* const* data() const;
 
-  void Swap(RepeatedPtrFieldBase* other);
+  template <typename TypeHandler>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(RepeatedPtrFieldBase* other);
 
   void SwapElements(int index1, int index2);
 
@@ -325,10 +448,25 @@
   template <typename TypeHandler>
   typename TypeHandler::Type* AddFromCleared();
 
+  template<typename TypeHandler>
+  void AddAllocated(typename TypeHandler::Type* value) {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    AddAllocatedInternal<TypeHandler>(value, t);
+  }
+
   template <typename TypeHandler>
-  void AddAllocated(typename TypeHandler::Type* value);
+  void UnsafeArenaAddAllocated(typename TypeHandler::Type* value);
+
   template <typename TypeHandler>
-  typename TypeHandler::Type* ReleaseLast();
+  typename TypeHandler::Type* ReleaseLast() {
+    typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
+    return ReleaseLastInternal<TypeHandler>(t);
+  }
+
+  // Releases last element and returns it, but does not do out-of-arena copy.
+  // And just returns the raw pointer to the contained element in the arena.
+  template <typename TypeHandler>
+  typename TypeHandler::Type* UnsafeArenaReleaseLast();
 
   int ClearedCount() const;
   template <typename TypeHandler>
@@ -336,13 +474,59 @@
   template <typename TypeHandler>
   typename TypeHandler::Type* ReleaseCleared();
 
+ protected:
+  inline void InternalSwap(RepeatedPtrFieldBase* other);
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(typename TypeHandler::Type* value,
+                            google::protobuf::internal::true_type);
+  template <typename TypeHandler>
+  void AddAllocatedInternal(typename TypeHandler::Type* value,
+                            google::protobuf::internal::false_type);
+
+  template <typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE
+  void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value,
+                                Arena* value_arena,
+                                Arena* my_arena);
+  template <typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE
+  void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value);
+
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::true_type);
+  template <typename TypeHandler>
+  typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::false_type);
+
+  template<typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE
+  void SwapFallback(RepeatedPtrFieldBase* other);
+
+  inline Arena* GetArenaNoVirtual() const {
+    return arena_;
+  }
+
  private:
   static const int kInitialSize = 0;
-
-  void** elements_;
+  // A few notes on internal representation:
+  //
+  // We use an indirected approach, with struct Rep, to keep
+  // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support
+  // was added, namely, 3 8-byte machine words on x86-64. An instance of Rep is
+  // allocated only when the repeated field is non-empty, and it is a
+  // dynamically-sized struct (the header is directly followed by elements[]).
+  // We place arena_ and current_size_ directly in the object to avoid cache
+  // misses due to the indirection, because these fields are checked frequently.
+  // Placing all fields directly in the RepeatedPtrFieldBase instance costs
+  // significant performance for memory-sensitive workloads.
+  Arena* arena_;
   int    current_size_;
-  int    allocated_size_;
   int    total_size_;
+  struct Rep {
+    int    allocated_size;
+    void*  elements[1];
+  };
+  static const size_t kRepHeaderSize = sizeof(Rep) - sizeof(void*);
+  // Contains arena ptr and the elements array. We also keep the invariant that
+  // if rep_ is NULL, then arena is NULL.
+  Rep* rep_;
 
   template <typename TypeHandler>
   static inline typename TypeHandler::Type* cast(void* element) {
@@ -353,6 +537,22 @@
     return reinterpret_cast<const typename TypeHandler::Type*>(element);
   }
 
+  // Non-templated inner function to avoid code duplication. Takes a function
+  // pointer to the type-specific (templated) inner allocate/merge loop.
+  void MergeFromInternal(
+      const RepeatedPtrFieldBase& other,
+      void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int));
+
+  template<typename TypeHandler>
+  void MergeFromInnerLoop(
+      void** our_elems, void** other_elems, int length, int already_allocated);
+
+  // Internal helper: extend array space if necessary to contain |extend_amount|
+  // more elements, and return a pointer to the element immediately following
+  // the old list of elements.  This interface factors out common behavior from
+  // Reserve() and MergeFrom() to reduce code size. |extend_amount| must be > 0.
+  void** InternalExtend(int extend_amount);
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
 };
 
@@ -360,21 +560,100 @@
 class GenericTypeHandler {
  public:
   typedef GenericType Type;
-  static GenericType* New() { return new GenericType; }
-  static void Delete(GenericType* value) { delete value; }
-  static void Clear(GenericType* value) { value->Clear(); }
-  static void Merge(const GenericType& from, GenericType* to) {
-    to->MergeFrom(from);
+  static inline GenericType* New(Arena* arena) {
+    return ::google::protobuf::Arena::CreateMaybeMessage<Type>(
+        arena, static_cast<GenericType*>(0));
   }
-  static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); }
-  static const Type& default_instance() { return Type::default_instance(); }
+  // We force NewFromPrototype() and Delete() to be non-inline to reduce code
+  // size: else, several other methods get inlined copies of message types'
+  // constructors and destructors.
+  GOOGLE_ATTRIBUTE_NOINLINE static GenericType* NewFromPrototype(
+      const GenericType* prototype, ::google::protobuf::Arena* arena = NULL);
+  GOOGLE_ATTRIBUTE_NOINLINE static void Delete(GenericType* value, Arena* arena);
+  static inline ::google::protobuf::Arena* GetArena(GenericType* value) {
+    return ::google::protobuf::Arena::GetArena<Type>(value);
+  }
+  static inline void* GetMaybeArenaPointer(GenericType* value) {
+    return ::google::protobuf::Arena::GetArena<Type>(value);
+  }
+
+  static inline void Clear(GenericType* value) { value->Clear(); }
+  GOOGLE_ATTRIBUTE_NOINLINE static void Merge(const GenericType& from,
+                                       GenericType* to);
+  static inline int SpaceUsed(const GenericType& value) {
+    return value.SpaceUsed();
+  }
+  static inline const Type& default_instance() {
+    return Type::default_instance();
+  }
 };
 
-template <>
-inline void GenericTypeHandler<MessageLite>::Merge(
-    const MessageLite& from, MessageLite* to) {
-  to->CheckTypeAndMergeFrom(from);
+template <typename GenericType>
+GenericType* GenericTypeHandler<GenericType>::NewFromPrototype(
+    const GenericType* /* prototype */, ::google::protobuf::Arena* arena) {
+  return New(arena);
 }
+template <typename GenericType>
+void GenericTypeHandler<GenericType>::Delete(GenericType* value, Arena* arena) {
+  if (arena == NULL) {
+    delete value;
+  }
+}
+template <typename GenericType>
+void GenericTypeHandler<GenericType>::Merge(const GenericType& from,
+                                            GenericType* to) {
+  to->MergeFrom(from);
+}
+
+// NewFromPrototype() and Merge() cannot be defined here; if they're declared
+// inline the compiler will complain about not matching GOOGLE_ATTRIBUTE_NOINLINE
+// above, and if not, compilation will result in multiple definitions.  These
+// are therefore declared as specializations here and defined in
+// message_lite.cc.
+template<>
+MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, google::protobuf::Arena* arena);
+template<>
+inline google::protobuf::Arena* GenericTypeHandler<MessageLite>::GetArena(
+    MessageLite* value) {
+  return value->GetArena();
+}
+template<>
+inline void* GenericTypeHandler<MessageLite>::GetMaybeArenaPointer(
+    MessageLite* value) {
+  return value->GetMaybeArenaPointer();
+}
+template <>
+void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
+                                            MessageLite* to);
+template<>
+inline void GenericTypeHandler<string>::Clear(string* value) {
+  value->clear();
+}
+template<>
+void GenericTypeHandler<string>::Merge(const string& from,
+                                       string* to);
+
+// Declarations of the specialization as we cannot define them here, as the
+// header that defines ProtocolMessage depends on types defined in this header.
+#define DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(TypeName)                 \
+    template<>                                                                 \
+    TypeName* GenericTypeHandler<TypeName>::NewFromPrototype(                  \
+        const TypeName* prototype, google::protobuf::Arena* arena);                      \
+    template<>                                                                 \
+    google::protobuf::Arena* GenericTypeHandler<TypeName>::GetArena(                     \
+        TypeName* value);                                                      \
+    template<>                                                                 \
+    void* GenericTypeHandler<TypeName>::GetMaybeArenaPointer(                  \
+        TypeName* value);
+
+// Message specialization bodies defined in message.cc. This split is necessary
+// to allow proto2-lite (which includes this header) to be independent of
+// Message.
+DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message)
+
+
+#undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES
 
 template <>
 inline const MessageLite& GenericTypeHandler<MessageLite>::default_instance() {
@@ -402,15 +681,33 @@
 //   StringTypeHandler is exported.  So, we factor out StringTypeHandlerBase,
 //   export that, then make StringTypeHandler be a subclass which is NOT
 //   exported.
-// TODO(kenton):  There has to be a better way.
+// TODO(kenton):  Now that StringSpaceUsedExcludingSelf() is in the lite
+//   library, this can be cleaned up.
 class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
  public:
   typedef string Type;
-  static string* New();
-  static void Delete(string* value);
-  static void Clear(string* value) { value->clear(); }
-  static void Merge(const string& from, string* to) { *to = from; }
-  static const Type& default_instance() {
+
+  static inline string* New(Arena* arena) {
+    return Arena::Create<string>(arena);
+  }
+  static inline string* NewFromPrototype(const string*,
+                                         ::google::protobuf::Arena* arena) {
+    return New(arena);
+  }
+  static inline ::google::protobuf::Arena* GetArena(string*) {
+    return NULL;
+  }
+  static inline void* GetMaybeArenaPointer(string* /* value */) {
+    return NULL;
+  }
+  static inline void Delete(string* value, Arena* arena) {
+    if (arena == NULL) {
+      delete value;
+    }
+  }
+  static inline void Clear(string* value) { value->clear(); }
+  static inline void Merge(const string& from, string* to) { *to = from; }
+  static inline const Type& default_instance() {
     return ::google::protobuf::internal::GetEmptyString();
   }
 };
@@ -418,7 +715,7 @@
 class StringTypeHandler : public StringTypeHandlerBase {
  public:
   static int SpaceUsed(const string& value)  {
-    return sizeof(value) + StringSpaceUsedExcludingSelf(value);
+    return static_cast<int>(sizeof(value)) + StringSpaceUsedExcludingSelf(value);
   }
 };
 
@@ -431,6 +728,8 @@
 class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
  public:
   RepeatedPtrField();
+  explicit RepeatedPtrField(::google::protobuf::Arena* arena);
+
   RepeatedPtrField(const RepeatedPtrField& other);
   template <typename Iter>
   RepeatedPtrField(Iter begin, const Iter& end);
@@ -470,9 +769,16 @@
   Element** mutable_data();
   const Element* const* data() const;
 
-  // Swap entire contents with "other".
+  // Swap entire contents with "other". If they are on separate arenas, then
+  // copies data.
   void Swap(RepeatedPtrField* other);
 
+  // Swap entire contents with "other". Caller should guarantee that either both
+  // fields are on the same arena or both are on the heap. Swapping between
+  // different arenas with this function is disallowed and is caught via
+  // GOOGLE_DCHECK.
+  void UnsafeArenaSwap(RepeatedPtrField* other);
+
   // Swap two elements.
   void SwapElements(int index1, int index2);
 
@@ -489,8 +795,10 @@
 
   iterator begin();
   const_iterator begin() const;
+  const_iterator cbegin() const;
   iterator end();
   const_iterator end() const;
+  const_iterator cend() const;
 
   // Reverse iterator support
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
@@ -529,11 +837,45 @@
 
   // Add an already-allocated object, passing ownership to the
   // RepeatedPtrField.
+  //
+  // Note that some special behavior occurs with respect to arenas:
+  //
+  //   (i) if this field holds submessages, the new submessage will be copied if
+  //   the original is in an arena and this RepeatedPtrField is either in a
+  //   different arena, or on the heap.
+  //   (ii) if this field holds strings, the passed-in string *must* be
+  //   heap-allocated, not arena-allocated. There is no way to dynamically check
+  //   this at runtime, so User Beware.
   void AddAllocated(Element* value);
+
   // Remove the last element and return it, passing ownership to the caller.
   // Requires:  size() > 0
+  //
+  // If this RepeatedPtrField is on an arena, an object copy is required to pass
+  // ownership back to the user (for compatible semantics). Use
+  // UnsafeArenaReleaseLast() if this behavior is undesired.
   Element* ReleaseLast();
 
+  // Add an already-allocated object, skipping arena-ownership checks. The user
+  // must guarantee that the given object is in the same arena as this
+  // RepeatedPtrField.
+  // It is also useful in legacy code that uses temporary ownership to avoid
+  // copies. Example:
+  // RepeatedPtrField<T> temp_field;
+  // temp_field.AddAllocated(new T);
+  // ... // Do something with temp_field
+  // temp_field.ExtractSubrange(0, temp_field.size(), NULL);
+  // If you put temp_field on the arena this fails, because the ownership
+  // transfers to the arena at the "AddAllocated" call and is not released
+  // anymore causing a double delete. UnsafeArenaAddAllocated prevents this.
+  void UnsafeArenaAddAllocated(Element* value);
+
+  // Remove the last element and return it.  Works only when operating on an
+  // arena. The returned pointer is to the original object in the arena, hence
+  // has the arena's lifetime.
+  // Requires:  current_size_ > 0
+  Element* UnsafeArenaReleaseLast();
+
   // Extract elements with indices in the range "[start .. start+num-1]".
   // The caller assumes ownership of the extracted elements and is responsible
   // for deleting them when they are no longer needed.
@@ -543,8 +885,20 @@
   // to perform any further operations (like deletion) on these elements.
   // Caution: implementation also moves elements with indices [start+num ..].
   // Calling this routine inside a loop can cause quadratic behavior.
+  //
+  // Memory copying behavior is identical to ReleaseLast(), described above: if
+  // this RepeatedPtrField is on an arena, an object copy is performed for each
+  // returned element, so that all returned element pointers are to
+  // heap-allocated copies. If this copy is not desired, the user should call
+  // UnsafeArenaExtractSubrange().
   void ExtractSubrange(int start, int num, Element** elements);
 
+  // Identical to ExtractSubrange() described above, except that when this
+  // repeated field is on an arena, no object copies are performed. Instead, the
+  // raw object pointers are returned. Thus, if on an arena, the returned
+  // objects must not be freed, because they will not be heap-allocated objects.
+  void UnsafeArenaExtractSubrange(int start, int num, Element** elements);
+
   // When elements are removed by calls to RemoveLast() or Clear(), they
   // are not actually freed.  Instead, they are cleared and kept so that
   // they can be reused later.  This can save lots of CPU time when
@@ -559,12 +913,39 @@
   // Add an element to the pool of cleared objects, passing ownership to
   // the RepeatedPtrField.  The element must be cleared prior to calling
   // this method.
+  //
+  // This method cannot be called when the repeated field is on an arena or when
+  // |value| is; both cases will trigger a GOOGLE_DCHECK-failure.
   void AddCleared(Element* value);
   // Remove a single element from the cleared pool and return it, passing
   // ownership to the caller.  The element is guaranteed to be cleared.
   // Requires:  ClearedCount() > 0
+  //
+  //
+  // This method cannot be called when the repeated field is on an arena; doing
+  // so will trigger a GOOGLE_DCHECK-failure.
   Element* ReleaseCleared();
 
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
+  iterator erase(const_iterator position);
+
+  // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
+  iterator erase(const_iterator first, const_iterator last);
+
+  // Gets the arena on which this RepeatedPtrField stores its elements.
+  ::google::protobuf::Arena* GetArena() const {
+    return GetArenaNoVirtual();
+  }
+
  protected:
   // Note:  RepeatedPtrField SHOULD NOT be subclassed by users.  We only
   //   subclass it in one place as a hack for compatibility with proto1.  The
@@ -572,31 +953,61 @@
   //   methods on RepeatedPtrFieldBase.
   class TypeHandler;
 
+  // Internal arena accessor expected by helpers in Arena.
+  inline Arena* GetArenaNoVirtual() const;
+
+ private:
+  // Implementations for ExtractSubrange(). The copying behavior must be
+  // included only if the type supports the necessary operations (e.g.,
+  // MergeFrom()), so we must resolve this at compile time. ExtractSubrange()
+  // uses SFINAE to choose one of the below implementations.
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               google::protobuf::internal::true_type);
+  void ExtractSubrangeInternal(int start, int num, Element** elements,
+                               google::protobuf::internal::false_type);
+
+  friend class Arena;
+  typedef void InternalArenaConstructable_;
+
 };
 
 // implementation ====================================================
 
 template <typename Element>
 inline RepeatedField<Element>::RepeatedField()
-  : elements_(NULL),
-    current_size_(0),
-    total_size_(kInitialSize) {
+  : current_size_(0),
+    total_size_(0),
+    rep_(NULL) {
+}
+
+template <typename Element>
+inline RepeatedField<Element>::RepeatedField(Arena* arena)
+  : current_size_(0),
+    total_size_(0),
+    rep_(NULL) {
+ // In case arena is NULL, then we do not create rep_, as code has an invariant
+ // `rep_ == NULL then arena == NULL`.
+ if (arena != NULL) {
+  rep_ = reinterpret_cast<Rep*>(
+      ::google::protobuf::Arena::CreateArray<char>(arena, kRepHeaderSize));
+  rep_->arena = arena;
+ }
 }
 
 template <typename Element>
 inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
-  : elements_(NULL),
-    current_size_(0),
-    total_size_(kInitialSize) {
+  : current_size_(0),
+    total_size_(0),
+    rep_(NULL) {
   CopyFrom(other);
 }
 
 template <typename Element>
 template <typename Iter>
-inline RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
-  : elements_(NULL),
-    current_size_(0),
-    total_size_(kInitialSize) {
+RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
+  : current_size_(0),
+    total_size_(0),
+    rep_(NULL) {
   int reserve = internal::CalculateReserve(begin, end);
   if (reserve != -1) {
     Reserve(reserve);
@@ -612,7 +1023,9 @@
 
 template <typename Element>
 RepeatedField<Element>::~RepeatedField() {
-  delete [] elements_;
+  // See explanation in Reserve(): we need to invoke destructors here for the
+  // case that Element has a non-trivial destructor.
+  InternalDeallocate(rep_, total_size_);
 }
 
 template <typename Element>
@@ -640,22 +1053,23 @@
 
 template<typename Element>
 inline void RepeatedField<Element>::AddAlreadyReserved(const Element& value) {
-  GOOGLE_DCHECK_LT(size(), Capacity());
-  elements_[current_size_++] = value;
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  rep_->elements[current_size_++] = value;
 }
 
 template<typename Element>
 inline Element* RepeatedField<Element>::AddAlreadyReserved() {
-  GOOGLE_DCHECK_LT(size(), Capacity());
-  return &elements_[current_size_++];
+  GOOGLE_DCHECK_LT(current_size_, total_size_);
+  return &rep_->elements[current_size_++];
 }
 
 template<typename Element>
 inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
   GOOGLE_DCHECK_GE(new_size, 0);
-  if (new_size > size()) {
+  if (new_size > current_size_) {
     Reserve(new_size);
-    std::fill(&elements_[current_size_], &elements_[new_size], value);
+    std::fill(&rep_->elements[current_size_],
+              &rep_->elements[new_size], value);
   }
   current_size_ = new_size;
 }
@@ -663,40 +1077,40 @@
 template <typename Element>
 inline const Element& RepeatedField<Element>::Get(int index) const {
   GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, size());
-  return elements_[index];
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return rep_->elements[index];
 }
 
 template <typename Element>
 inline Element* RepeatedField<Element>::Mutable(int index) {
   GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, size());
-  return elements_ + index;
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return &rep_->elements[index];
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::Set(int index, const Element& value) {
   GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, size());
-  elements_[index] = value;
+  GOOGLE_DCHECK_LT(index, current_size_);
+  rep_->elements[index] = value;
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::Add(const Element& value) {
   if (current_size_ == total_size_) Reserve(total_size_ + 1);
-  elements_[current_size_++] = value;
+  rep_->elements[current_size_++] = value;
 }
 
 template <typename Element>
 inline Element* RepeatedField<Element>::Add() {
   if (current_size_ == total_size_) Reserve(total_size_ + 1);
-  return &elements_[current_size_++];
+  return &rep_->elements[current_size_++];
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::RemoveLast() {
   GOOGLE_DCHECK_GT(current_size_, 0);
-  --current_size_;
+  current_size_--;
 }
 
 template <typename Element>
@@ -704,7 +1118,7 @@
     int start, int num, Element* elements) {
   GOOGLE_DCHECK_GE(start, 0);
   GOOGLE_DCHECK_GE(num, 0);
-  GOOGLE_DCHECK_LE(start + num, this->size());
+  GOOGLE_DCHECK_LE(start + num, this->current_size_);
 
   // Save the values of the removed elements if requested.
   if (elements != NULL) {
@@ -714,9 +1128,9 @@
 
   // Slide remaining elements down to fill the gap.
   if (num > 0) {
-    for (int i = start + num; i < this->size(); ++i)
+    for (int i = start + num; i < this->current_size_; ++i)
       this->Set(i - num, this->Get(i));
-    this->Truncate(this->size() - num);
+    this->Truncate(this->current_size_ - num);
   }
 }
 
@@ -730,7 +1144,8 @@
   GOOGLE_CHECK_NE(&other, this);
   if (other.current_size_ != 0) {
     Reserve(current_size_ + other.current_size_);
-    CopyArray(elements_ + current_size_, other.elements_, other.current_size_);
+    CopyArray(rep_->elements + current_size_,
+              other.rep_->elements, other.current_size_);
     current_size_ += other.current_size_;
   }
 }
@@ -743,62 +1158,100 @@
 }
 
 template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
+    const_iterator first, const_iterator last) {
+  size_type first_offset = first - cbegin();
+  if (first != last) {
+    Truncate(std::copy(last, cend(), begin() + first_offset) - cbegin());
+  }
+  return begin() + first_offset;
+}
+
+template <typename Element>
 inline Element* RepeatedField<Element>::mutable_data() {
-  return elements_;
+  return rep_ ? rep_->elements : NULL;
 }
 
 template <typename Element>
 inline const Element* RepeatedField<Element>::data() const {
-  return elements_;
+  return rep_ ? rep_->elements : NULL;
 }
 
 
 template <typename Element>
+inline void RepeatedField<Element>::InternalSwap(RepeatedField* other) {
+  std::swap(rep_, other->rep_);
+  std::swap(current_size_, other->current_size_);
+  std::swap(total_size_, other->total_size_);
+}
+
+template <typename Element>
 void RepeatedField<Element>::Swap(RepeatedField* other) {
   if (this == other) return;
-  Element* swap_elements     = elements_;
-  int      swap_current_size = current_size_;
-  int      swap_total_size   = total_size_;
+  if (GetArenaNoVirtual() ==  other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    RepeatedField<Element> temp(other->GetArenaNoVirtual());
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->UnsafeArenaSwap(&temp);
+  }
+}
 
-  elements_     = other->elements_;
-  current_size_ = other->current_size_;
-  total_size_   = other->total_size_;
-
-  other->elements_     = swap_elements;
-  other->current_size_ = swap_current_size;
-  other->total_size_   = swap_total_size;
+template <typename Element>
+void RepeatedField<Element>::UnsafeArenaSwap(RepeatedField* other) {
+  if (this == other) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
 }
 
 template <typename Element>
 void RepeatedField<Element>::SwapElements(int index1, int index2) {
   using std::swap;  // enable ADL with fallback
-  swap(elements_[index1], elements_[index2]);
+  swap(rep_->elements[index1], rep_->elements[index2]);
 }
 
 template <typename Element>
 inline typename RepeatedField<Element>::iterator
 RepeatedField<Element>::begin() {
-  return elements_;
+  return rep_ ? rep_->elements : NULL;
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::begin() const {
-  return elements_;
+  return rep_ ? rep_->elements : NULL;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cbegin() const {
+  return rep_ ? rep_->elements : NULL;
 }
 template <typename Element>
 inline typename RepeatedField<Element>::iterator
 RepeatedField<Element>::end() {
-  return elements_ + current_size_;
+  return rep_ ? rep_->elements + current_size_ : NULL;
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::end() const {
-  return elements_ + current_size_;
+  return rep_ ? rep_->elements + current_size_ : NULL;
+}
+template <typename Element>
+inline typename RepeatedField<Element>::const_iterator
+RepeatedField<Element>::cend() const {
+  return rep_ ? rep_->elements + current_size_ : NULL;
 }
 
 template <typename Element>
 inline int RepeatedField<Element>::SpaceUsedExcludingSelf() const {
-  return (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0;
+  return rep_ ?
+      (total_size_ * sizeof(Element) + kRepHeaderSize) : 0;
 }
 
 // Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
@@ -806,32 +1259,65 @@
 template <typename Element>
 void RepeatedField<Element>::Reserve(int new_size) {
   if (total_size_ >= new_size) return;
-
-  Element* old_elements = elements_;
-  total_size_ = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
-                    max(total_size_ * 2, new_size));
-  elements_ = new Element[total_size_];
-  if (old_elements != NULL) {
-    MoveArray(elements_, old_elements, current_size_);
-    delete [] old_elements;
+  Rep* old_rep = rep_;
+  Arena* arena = GetArenaNoVirtual();
+  new_size = std::max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
+                      std::max(total_size_ * 2, new_size));
+  GOOGLE_CHECK_LE(static_cast<size_t>(new_size),
+           (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
+           sizeof(Element))
+      << "Requested size is too large to fit into size_t.";
+  if (arena == NULL) {
+    rep_ = reinterpret_cast<Rep*>(
+        new char[kRepHeaderSize + sizeof(Element) * new_size]);
+  } else {
+    rep_ = reinterpret_cast<Rep*>(
+            ::google::protobuf::Arena::CreateArray<char>(arena,
+                kRepHeaderSize + sizeof(Element) * new_size));
   }
+  rep_->arena = arena;
+  int old_total_size = total_size_;
+  total_size_ = new_size;
+  // Invoke placement-new on newly allocated elements. We shouldn't have to do
+  // this, since Element is supposed to be POD, but a previous version of this
+  // code allocated storage with "new Element[size]" and some code uses
+  // RepeatedField with non-POD types, relying on constructor invocation. If
+  // Element has a trivial constructor (e.g., int32), gcc (tested with -O2)
+  // completely removes this loop because the loop body is empty, so this has no
+  // effect unless its side-effects are required for correctness.
+  // Note that we do this before MoveArray() below because Element's copy
+  // assignment implementation will want an initialized instance first.
+  Element* e = &rep_->elements[0];
+  Element* limit = &rep_->elements[total_size_];
+  for (; e < limit; e++) {
+    new (e) Element();
+  }
+  if (current_size_ > 0) {
+    MoveArray(rep_->elements, old_rep->elements, current_size_);
+  }
+
+  // Likewise, we need to invoke destructors on the old array.
+  InternalDeallocate(old_rep, old_total_size);
+
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::Truncate(int new_size) {
   GOOGLE_DCHECK_LE(new_size, current_size_);
-  current_size_ = new_size;
+  if (current_size_ > 0) {
+    current_size_ = new_size;
+  }
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::MoveArray(
-    Element to[], Element from[], int array_size) {
+  Element* to, Element* from, int array_size) {
   CopyArray(to, from, array_size);
 }
 
 template <typename Element>
 inline void RepeatedField<Element>::CopyArray(
-    Element to[], const Element from[], int array_size) {
+  Element* to, const Element* from, int array_size) {
   internal::ElementCopier<Element>()(to, from, array_size);
 }
 
@@ -839,13 +1325,13 @@
 
 template <typename Element, bool HasTrivialCopy>
 void ElementCopier<Element, HasTrivialCopy>::operator()(
-    Element to[], const Element from[], int array_size) {
+  Element* to, const Element* from, int array_size) {
   std::copy(from, from + array_size, to);
 }
 
 template <typename Element>
 struct ElementCopier<Element, true> {
-  void operator()(Element to[], const Element from[], int array_size) {
+  void operator()(Element* to, const Element* from, int array_size) {
     memcpy(to, from, array_size * sizeof(Element));
   }
 };
@@ -858,18 +1344,55 @@
 namespace internal {
 
 inline RepeatedPtrFieldBase::RepeatedPtrFieldBase()
-  : elements_(NULL),
+  : arena_(NULL),
     current_size_(0),
-    allocated_size_(0),
-    total_size_(kInitialSize) {
+    total_size_(0),
+    rep_(NULL) {
+}
+
+inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(::google::protobuf::Arena* arena)
+  : arena_(arena),
+    current_size_(0),
+    total_size_(0),
+    rep_(NULL) {
 }
 
 template <typename TypeHandler>
 void RepeatedPtrFieldBase::Destroy() {
-  for (int i = 0; i < allocated_size_; i++) {
-    TypeHandler::Delete(cast<TypeHandler>(elements_[i]));
+  if (rep_ != NULL) {
+    for (int i = 0; i < rep_->allocated_size; i++) {
+      TypeHandler::Delete(cast<TypeHandler>(rep_->elements[i]), arena_);
+    }
+    if (arena_ == NULL) {
+      delete [] reinterpret_cast<char*>(rep_);
+    }
   }
-  delete [] elements_;
+  rep_ = NULL;
+}
+
+template <typename TypeHandler>
+inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
+  if (other->GetArenaNoVirtual() == GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    SwapFallback<TypeHandler>(other);
+  }
+}
+
+template <typename TypeHandler>
+void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) {
+  GOOGLE_DCHECK(other->GetArenaNoVirtual() != GetArenaNoVirtual());
+
+  // Copy semantics in this case. We try to improve efficiency by placing the
+  // temporary on |other|'s arena so that messages are copied cross-arena only
+  // once, not twice.
+  RepeatedPtrFieldBase temp(other->GetArenaNoVirtual());
+  temp.MergeFrom<TypeHandler>(*this);
+  this->Clear<TypeHandler>();
+  this->MergeFrom<TypeHandler>(*other);
+  other->Clear<TypeHandler>();
+  other->InternalSwap(&temp);
+  temp.Destroy<TypeHandler>();  // Frees rep_ if `other` had no arena.
 }
 
 inline bool RepeatedPtrFieldBase::empty() const {
@@ -884,8 +1407,8 @@
 inline const typename TypeHandler::Type&
 RepeatedPtrFieldBase::Get(int index) const {
   GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, size());
-  return *cast<TypeHandler>(elements_[index]);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return *cast<TypeHandler>(rep_->elements[index]);
 }
 
 
@@ -893,42 +1416,106 @@
 inline typename TypeHandler::Type*
 RepeatedPtrFieldBase::Mutable(int index) {
   GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, size());
-  return cast<TypeHandler>(elements_[index]);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  return cast<TypeHandler>(rep_->elements[index]);
 }
 
 template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() {
-  if (current_size_ < allocated_size_) {
-    return cast<TypeHandler>(elements_[current_size_++]);
+inline void RepeatedPtrFieldBase::Delete(int index) {
+  GOOGLE_DCHECK_GE(index, 0);
+  GOOGLE_DCHECK_LT(index, current_size_);
+  TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
+}
+
+template <typename TypeHandler>
+inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add(
+    typename TypeHandler::Type* prototype) {
+  if (rep_ != NULL && current_size_ < rep_->allocated_size) {
+    return cast<TypeHandler>(rep_->elements[current_size_++]);
   }
-  if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
-  typename TypeHandler::Type* result = TypeHandler::New();
-  ++allocated_size_;
-  elements_[current_size_++] = result;
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    Reserve(total_size_ + 1);
+  }
+  ++rep_->allocated_size;
+  typename TypeHandler::Type* result =
+      TypeHandler::NewFromPrototype(prototype, arena_);
+  rep_->elements[current_size_++] = result;
   return result;
 }
 
 template <typename TypeHandler>
 inline void RepeatedPtrFieldBase::RemoveLast() {
   GOOGLE_DCHECK_GT(current_size_, 0);
-  TypeHandler::Clear(cast<TypeHandler>(elements_[--current_size_]));
+  TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
 }
 
 template <typename TypeHandler>
 void RepeatedPtrFieldBase::Clear() {
-  for (int i = 0; i < current_size_; i++) {
-    TypeHandler::Clear(cast<TypeHandler>(elements_[i]));
+  const int n = current_size_;
+  GOOGLE_DCHECK_GE(n, 0);
+  if (n > 0) {
+    void* const* elements = rep_->elements;
+    int i = 0;
+    do {
+      TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
+    } while (i < n);
+    current_size_ = 0;
   }
-  current_size_ = 0;
 }
 
+// To avoid unnecessary code duplication and reduce binary size, we use a
+// layered approach to implementing MergeFrom(). The toplevel method is
+// templated, so we get a small thunk per concrete message type in the binary.
+// This calls a shared implementation with most of the logic, passing a function
+// pointer to another type-specific piece of code that calls the object-allocate
+// and merge handlers.
 template <typename TypeHandler>
 inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) {
-  GOOGLE_CHECK_NE(&other, this);
-  Reserve(current_size_ + other.current_size_);
-  for (int i = 0; i < other.current_size_; i++) {
-    TypeHandler::Merge(other.template Get<TypeHandler>(i), Add<TypeHandler>());
+  GOOGLE_DCHECK_NE(&other, this);
+  if (other.current_size_ == 0) return;
+  MergeFromInternal(
+      other, &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
+}
+
+inline void RepeatedPtrFieldBase::MergeFromInternal(
+    const RepeatedPtrFieldBase& other,
+    void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)) {
+  // Note: wrapper has already guaranteed that other.rep_ != NULL here.
+  int other_size = other.current_size_;
+  void** other_elements = other.rep_->elements;
+  void** new_elements = InternalExtend(other_size);
+  int allocated_elems = rep_->allocated_size - current_size_;
+  (this->*inner_loop)(new_elements, other_elements,
+                      other_size, allocated_elems);
+  current_size_ += other_size;
+  if (rep_->allocated_size < current_size_) {
+    rep_->allocated_size = current_size_;
+  }
+}
+
+// Merges other_elems to our_elems.
+template<typename TypeHandler>
+void RepeatedPtrFieldBase::MergeFromInnerLoop(
+    void** our_elems, void** other_elems, int length, int already_allocated) {
+  // Split into two loops, over ranges [0, allocated) and [allocated, length),
+  // to avoid a branch within the loop.
+  for (int i = 0; i < already_allocated && i < length; i++) {
+    // Already allocated: use existing element.
+    typename TypeHandler::Type* other_elem =
+        reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
+    typename TypeHandler::Type* new_elem =
+        reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
+    TypeHandler::Merge(*other_elem, new_elem);
+  }
+  Arena* arena = GetArenaNoVirtual();
+  for (int i = already_allocated; i < length; i++) {
+    // Not allocated: alloc a new element first, then merge it.
+    typename TypeHandler::Type* other_elem =
+        reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
+    typename TypeHandler::Type* new_elem =
+        TypeHandler::NewFromPrototype(other_elem, arena);
+    TypeHandler::Merge(*other_elem, new_elem);
+    our_elems[i] = new_elem;
   }
 }
 
@@ -944,18 +1531,18 @@
 }
 
 inline void* const* RepeatedPtrFieldBase::raw_data() const {
-  return elements_;
+  return rep_ ? rep_->elements : NULL;
 }
 
 inline void** RepeatedPtrFieldBase::raw_mutable_data() const {
-  return elements_;
+  return rep_ ? const_cast<void**>(rep_->elements) : NULL;
 }
 
 template <typename TypeHandler>
 inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() {
   // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
   //   method entirely.
-  return reinterpret_cast<typename TypeHandler::Type**>(elements_);
+  return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
 }
 
 template <typename TypeHandler>
@@ -963,89 +1550,212 @@
 RepeatedPtrFieldBase::data() const {
   // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
   //   method entirely.
-  return reinterpret_cast<const typename TypeHandler::Type* const*>(elements_);
+  return reinterpret_cast<const typename TypeHandler::Type* const*>(raw_data());
 }
 
 inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) {
   using std::swap;  // enable ADL with fallback
-  swap(elements_[index1], elements_[index2]);
+  swap(rep_->elements[index1], rep_->elements[index2]);
 }
 
 template <typename TypeHandler>
 inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const {
-  int allocated_bytes =
-      (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0;
-  for (int i = 0; i < allocated_size_; ++i) {
-    allocated_bytes += TypeHandler::SpaceUsed(*cast<TypeHandler>(elements_[i]));
+  int allocated_bytes = total_size_ * sizeof(void*);
+  if (rep_ != NULL) {
+    for (int i = 0; i < rep_->allocated_size; ++i) {
+      allocated_bytes += TypeHandler::SpaceUsed(
+          *cast<TypeHandler>(rep_->elements[i]));
+    }
+    allocated_bytes += kRepHeaderSize;
   }
   return allocated_bytes;
 }
 
 template <typename TypeHandler>
 inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() {
-  if (current_size_ < allocated_size_) {
-    return cast<TypeHandler>(elements_[current_size_++]);
+  if (rep_ != NULL && current_size_ < rep_->allocated_size) {
+    return cast<TypeHandler>(rep_->elements[current_size_++]);
   } else {
     return NULL;
   }
 }
 
+// AddAllocated version that implements arena-safe copying behavior.
 template <typename TypeHandler>
-void RepeatedPtrFieldBase::AddAllocated(
+void RepeatedPtrFieldBase::AddAllocatedInternal(
+    typename TypeHandler::Type* value,
+    google::protobuf::internal::true_type) {
+  Arena* element_arena = reinterpret_cast<Arena*>(
+      TypeHandler::GetMaybeArenaPointer(value));
+  Arena* arena = GetArenaNoVirtual();
+  if (arena == element_arena && rep_ &&
+      rep_->allocated_size < total_size_) {
+    // Fast path: underlying arena representation (tagged pointer) is equal to
+    // our arena pointer, and we can add to array without resizing it (at least
+    // one slot that is not allocated).
+    void** elems = rep_->elements;
+    if (current_size_ < rep_->allocated_size) {
+      // Make space at [current] by moving first allocated element to end of
+      // allocated list.
+      elems[rep_->allocated_size] = elems[current_size_];
+    }
+    elems[current_size_] = value;
+    current_size_ = current_size_ + 1;
+    rep_->allocated_size = rep_->allocated_size + 1;
+    return;
+  } else {
+    AddAllocatedSlowWithCopy<TypeHandler>(
+        value, TypeHandler::GetArena(value), arena);
+  }
+}
+
+// Slowpath handles all cases, copying if necessary.
+template<typename TypeHandler>
+void RepeatedPtrFieldBase::AddAllocatedSlowWithCopy(
+    // Pass value_arena and my_arena to avoid duplicate virtual call (value) or
+    // load (mine).
+    typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
+  // Ensure that either the value is in the same arena, or if not, we do the
+  // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy
+  // it to our arena/heap (otherwise).
+  if (my_arena != NULL && value_arena == NULL) {
+    my_arena->Own(value);
+  } else if (my_arena != value_arena) {
+    typename TypeHandler::Type* new_value =
+        TypeHandler::NewFromPrototype(value, my_arena);
+    TypeHandler::Merge(*value, new_value);
+    TypeHandler::Delete(value, value_arena);
+    value = new_value;
+  }
+
+  UnsafeArenaAddAllocated<TypeHandler>(value);
+}
+
+// AddAllocated version that does not implement arena-safe copying behavior.
+template <typename TypeHandler>
+void RepeatedPtrFieldBase::AddAllocatedInternal(
+    typename TypeHandler::Type* value,
+    google::protobuf::internal::false_type) {
+  if (rep_ &&  rep_->allocated_size < total_size_) {
+    // Fast path: underlying arena representation (tagged pointer) is equal to
+    // our arena pointer, and we can add to array without resizing it (at least
+    // one slot that is not allocated).
+    void** elems = rep_->elements;
+    if (current_size_ < rep_->allocated_size) {
+      // Make space at [current] by moving first allocated element to end of
+      // allocated list.
+      elems[rep_->allocated_size] = elems[current_size_];
+    }
+    elems[current_size_] = value;
+    current_size_ = current_size_ + 1;
+    ++rep_->allocated_size;
+    return;
+  } else {
+    UnsafeArenaAddAllocated<TypeHandler>(value);
+  }
+}
+
+template <typename TypeHandler>
+void RepeatedPtrFieldBase::UnsafeArenaAddAllocated(
     typename TypeHandler::Type* value) {
   // Make room for the new pointer.
-  if (current_size_ == total_size_) {
+  if (!rep_ || current_size_ == total_size_) {
     // The array is completely full with no cleared objects, so grow it.
     Reserve(total_size_ + 1);
-    ++allocated_size_;
-  } else if (allocated_size_ == total_size_) {
+    ++rep_->allocated_size;
+  } else if (rep_->allocated_size == total_size_) {
     // There is no more space in the pointer array because it contains some
     // cleared objects awaiting reuse.  We don't want to grow the array in this
     // case because otherwise a loop calling AddAllocated() followed by Clear()
     // would leak memory.
-    TypeHandler::Delete(cast<TypeHandler>(elements_[current_size_]));
-  } else if (current_size_ < allocated_size_) {
+    TypeHandler::Delete(
+        cast<TypeHandler>(rep_->elements[current_size_]), arena_);
+  } else if (current_size_ < rep_->allocated_size) {
     // We have some cleared objects.  We don't care about their order, so we
     // can just move the first one to the end to make space.
-    elements_[allocated_size_] = elements_[current_size_];
-    ++allocated_size_;
+    rep_->elements[rep_->allocated_size] = rep_->elements[current_size_];
+    ++rep_->allocated_size;
   } else {
     // There are no cleared objects.
-    ++allocated_size_;
+    ++rep_->allocated_size;
   }
 
-  elements_[current_size_++] = value;
+  rep_->elements[current_size_++] = value;
+}
+
+// ReleaseLast() for types that implement merge/copy behavior.
+template <typename TypeHandler>
+inline typename TypeHandler::Type*
+RepeatedPtrFieldBase::ReleaseLastInternal(google::protobuf::internal::true_type) {
+  // First, release an element.
+  typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
+  // Now perform a copy if we're on an arena.
+  Arena* arena = GetArenaNoVirtual();
+  if (arena == NULL) {
+    return result;
+  } else {
+    typename TypeHandler::Type* new_result =
+        TypeHandler::NewFromPrototype(result, NULL);
+    TypeHandler::Merge(*result, new_result);
+    return new_result;
+  }
+}
+
+// ReleaseLast() for types that *do not* implement merge/copy behavior -- this
+// is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if we're on
+// an arena, since the user really should implement the copy operation in this
+// case.
+template <typename TypeHandler>
+inline typename TypeHandler::Type*
+RepeatedPtrFieldBase::ReleaseLastInternal(google::protobuf::internal::false_type) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() == NULL)
+      << "ReleaseLast() called on a RepeatedPtrField that is on an arena, "
+      << "with a type that does not implement MergeFrom. This is unsafe; "
+      << "please implement MergeFrom for your type.";
+  return UnsafeArenaReleaseLast<TypeHandler>();
 }
 
 template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() {
+inline typename TypeHandler::Type*
+  RepeatedPtrFieldBase::UnsafeArenaReleaseLast() {
   GOOGLE_DCHECK_GT(current_size_, 0);
   typename TypeHandler::Type* result =
-      cast<TypeHandler>(elements_[--current_size_]);
-  --allocated_size_;
-  if (current_size_ < allocated_size_) {
+      cast<TypeHandler>(rep_->elements[--current_size_]);
+  --rep_->allocated_size;
+  if (current_size_ < rep_->allocated_size) {
     // There are cleared elements on the end; replace the removed element
     // with the last allocated element.
-    elements_[current_size_] = elements_[allocated_size_];
+    rep_->elements[current_size_] = rep_->elements[rep_->allocated_size];
   }
   return result;
 }
 
 inline int RepeatedPtrFieldBase::ClearedCount() const {
-  return allocated_size_ - current_size_;
+  return rep_ ? (rep_->allocated_size - current_size_) : 0;
 }
 
 template <typename TypeHandler>
 inline void RepeatedPtrFieldBase::AddCleared(
     typename TypeHandler::Type* value) {
-  if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
-  elements_[allocated_size_++] = value;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == NULL)
+      << "AddCleared() can only be used on a RepeatedPtrField not on an arena.";
+  GOOGLE_DCHECK(TypeHandler::GetArena(value) == NULL)
+      << "AddCleared() can only accept values not on an arena.";
+  if (!rep_ || rep_->allocated_size == total_size_) {
+    Reserve(total_size_ + 1);
+  }
+  rep_->elements[rep_->allocated_size++] = value;
 }
 
 template <typename TypeHandler>
 inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
-  GOOGLE_DCHECK_GT(allocated_size_, current_size_);
-  return cast<TypeHandler>(elements_[--allocated_size_]);
+  GOOGLE_DCHECK(GetArenaNoVirtual() == NULL)
+      << "ReleaseCleared() can only be used on a RepeatedPtrField not on "
+      << "an arena.";
+  GOOGLE_DCHECK(GetArenaNoVirtual() == NULL);
+  GOOGLE_DCHECK(rep_ != NULL);
+  GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_);
+  return cast<TypeHandler>(rep_->elements[--rep_->allocated_size]);
 }
 
 }  // namespace internal
@@ -1064,12 +1774,17 @@
 
 
 template <typename Element>
-inline RepeatedPtrField<Element>::RepeatedPtrField() {}
+inline RepeatedPtrField<Element>::RepeatedPtrField()
+  : RepeatedPtrFieldBase() {}
+
+template <typename Element>
+inline RepeatedPtrField<Element>::RepeatedPtrField(::google::protobuf::Arena* arena) :
+  RepeatedPtrFieldBase(arena) {}
 
 template <typename Element>
 inline RepeatedPtrField<Element>::RepeatedPtrField(
     const RepeatedPtrField& other)
-    : RepeatedPtrFieldBase() {
+  : RepeatedPtrFieldBase() {
   CopyFrom(other);
 }
 
@@ -1135,14 +1850,71 @@
   GOOGLE_DCHECK_GE(start, 0);
   GOOGLE_DCHECK_GE(num, 0);
   GOOGLE_DCHECK_LE(start + num, size());
-  for (int i = 0; i < num; ++i)
-    delete RepeatedPtrFieldBase::Mutable<TypeHandler>(start + i);
+  for (int i = 0; i < num; ++i) {
+    RepeatedPtrFieldBase::Delete<TypeHandler>(start + i);
+  }
   ExtractSubrange(start, num, NULL);
 }
 
 template <typename Element>
 inline void RepeatedPtrField<Element>::ExtractSubrange(
     int start, int num, Element** elements) {
+  typename internal::TypeImplementsMergeBehavior<
+      typename TypeHandler::Type>::type t;
+  ExtractSubrangeInternal(start, num, elements, t);
+}
+
+// ExtractSubrange() implementation for types that implement merge/copy
+// behavior.
+template <typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, google::protobuf::internal::true_type) {
+  GOOGLE_DCHECK_GE(start, 0);
+  GOOGLE_DCHECK_GE(num, 0);
+  GOOGLE_DCHECK_LE(start + num, size());
+
+  if (num > 0) {
+    // Save the values of the removed elements if requested.
+    if (elements != NULL) {
+      if (GetArenaNoVirtual() != NULL) {
+        // If we're on an arena, we perform a copy for each element so that the
+        // returned elements are heap-allocated.
+        for (int i = 0; i < num; ++i) {
+          Element* element = RepeatedPtrFieldBase::
+              Mutable<TypeHandler>(i + start);
+          typename TypeHandler::Type* new_value =
+              TypeHandler::NewFromPrototype(element, NULL);
+          TypeHandler::Merge(*element, new_value);
+          elements[i] = new_value;
+        }
+      } else {
+        for (int i = 0; i < num; ++i) {
+          elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+        }
+      }
+    }
+    CloseGap(start, num);
+  }
+}
+
+// ExtractSubrange() implementation for types that do not implement merge/copy
+// behavior.
+template<typename Element>
+inline void RepeatedPtrField<Element>::ExtractSubrangeInternal(
+    int start, int num, Element** elements, google::protobuf::internal::false_type) {
+  // This case is identical to UnsafeArenaExtractSubrange(). However, since
+  // ExtractSubrange() must return heap-allocated objects by contract, and we
+  // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that
+  // we are not on an arena.
+  GOOGLE_DCHECK(GetArenaNoVirtual() == NULL)
+      << "ExtractSubrange() when arena is non-NULL is only supported when "
+      << "the Element type supplies a MergeFrom() operation to make copies.";
+  UnsafeArenaExtractSubrange(start, num, elements);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaExtractSubrange(
+    int start, int num, Element** elements) {
   GOOGLE_DCHECK_GE(start, 0);
   GOOGLE_DCHECK_GE(num, 0);
   GOOGLE_DCHECK_LE(start + num, size());
@@ -1150,8 +1922,9 @@
   if (num > 0) {
     // Save the values of the removed elements if requested.
     if (elements != NULL) {
-      for (int i = 0; i < num; ++i)
+      for (int i = 0; i < num; ++i) {
         elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
+      }
     }
     CloseGap(start, num);
   }
@@ -1175,6 +1948,21 @@
 }
 
 template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator position) {
+  return erase(position, position + 1);
+}
+
+template <typename Element>
+inline typename RepeatedPtrField<Element>::iterator
+RepeatedPtrField<Element>::erase(const_iterator first, const_iterator last) {
+  size_type pos_offset = std::distance(cbegin(), first);
+  size_type last_offset = std::distance(cbegin(), last);
+  DeleteSubrange(pos_offset, last_offset - pos_offset);
+  return begin() + pos_offset;
+}
+
+template <typename Element>
 inline Element** RepeatedPtrField<Element>::mutable_data() {
   return RepeatedPtrFieldBase::mutable_data<TypeHandler>();
 }
@@ -1185,16 +1973,32 @@
 }
 
 template <typename Element>
-void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
-  RepeatedPtrFieldBase::Swap(other);
+inline void RepeatedPtrField<Element>::Swap(RepeatedPtrField* other) {
+  if (this == other)
+    return;
+  RepeatedPtrFieldBase::Swap<TypeHandler>(other);
 }
 
 template <typename Element>
-void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
+inline void RepeatedPtrField<Element>::UnsafeArenaSwap(
+    RepeatedPtrField* other) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  if (this == other)
+      return;
+  RepeatedPtrFieldBase::InternalSwap(other);
+}
+
+template <typename Element>
+inline void RepeatedPtrField<Element>::SwapElements(int index1, int index2) {
   RepeatedPtrFieldBase::SwapElements(index1, index2);
 }
 
 template <typename Element>
+inline Arena* RepeatedPtrField<Element>::GetArenaNoVirtual() const {
+  return RepeatedPtrFieldBase::GetArenaNoVirtual();
+}
+
+template <typename Element>
 inline int RepeatedPtrField<Element>::SpaceUsedExcludingSelf() const {
   return RepeatedPtrFieldBase::SpaceUsedExcludingSelf<TypeHandler>();
 }
@@ -1205,10 +2009,19 @@
 }
 
 template <typename Element>
+inline void RepeatedPtrField<Element>::UnsafeArenaAddAllocated(Element* value) {
+  RepeatedPtrFieldBase::UnsafeArenaAddAllocated<TypeHandler>(value);
+}
+
+template <typename Element>
 inline Element* RepeatedPtrField<Element>::ReleaseLast() {
   return RepeatedPtrFieldBase::ReleaseLast<TypeHandler>();
 }
 
+template <typename Element>
+inline Element* RepeatedPtrField<Element>::UnsafeArenaReleaseLast() {
+  return RepeatedPtrFieldBase::UnsafeArenaReleaseLast<TypeHandler>();
+}
 
 template <typename Element>
 inline int RepeatedPtrField<Element>::ClearedCount() const {
@@ -1308,11 +2121,11 @@
     it_ += d;
     return *this;
   }
-  friend iterator operator+(iterator it, difference_type d) {
+  friend iterator operator+(iterator it, const difference_type d) {
     it += d;
     return it;
   }
-  friend iterator operator+(difference_type d, iterator it) {
+  friend iterator operator+(const difference_type d, iterator it) {
     it += d;
     return it;
   }
@@ -1423,6 +2236,12 @@
   VoidPtr* it_;
 };
 
+void RepeatedPtrFieldBase::InternalSwap(RepeatedPtrFieldBase* other) {
+  std::swap(rep_, other->rep_);
+  std::swap(current_size_, other->current_size_);
+  std::swap(total_size_, other->total_size_);
+}
+
 }  // namespace internal
 
 template <typename Element>
@@ -1436,6 +2255,11 @@
   return iterator(raw_data());
 }
 template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cbegin() const {
+  return begin();
+}
+template <typename Element>
 inline typename RepeatedPtrField<Element>::iterator
 RepeatedPtrField<Element>::end() {
   return iterator(raw_data() + size());
@@ -1445,6 +2269,11 @@
 RepeatedPtrField<Element>::end() const {
   return iterator(raw_data() + size());
 }
+template <typename Element>
+inline typename RepeatedPtrField<Element>::const_iterator
+RepeatedPtrField<Element>::cend() const {
+  return end();
+}
 
 template <typename Element>
 inline typename RepeatedPtrField<Element>::pointer_iterator
@@ -1471,7 +2300,7 @@
 
 // Iterators and helper functions that follow the spirit of the STL
 // std::back_insert_iterator and std::back_inserter but are tailor-made
-// for RepeatedField and RepatedPtrField. Typical usage would be:
+// for RepeatedField and RepeatedPtrField. Typical usage would be:
 //
 //   std::copy(some_sequence.begin(), some_sequence.end(),
 //             google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence()));
@@ -1564,6 +2393,37 @@
  private:
   RepeatedPtrField<T>* field_;
 };
+
+// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one
+// uses the UnsafeArenaAddAllocated instead.
+template<typename T>
+class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator
+    : public std::iterator<std::output_iterator_tag, T> {
+ public:
+  explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator(
+    ::google::protobuf::RepeatedPtrField<T>* const mutable_field)
+  : field_(mutable_field) {
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
+    T const* const ptr_to_value) {
+    field_->UnsafeArenaAddAllocated(const_cast<T*>(ptr_to_value));
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() {
+    return *this;
+  }
+  UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
+      int /* unused */) {
+    return *this;
+  }
+
+ private:
+  ::google::protobuf::RepeatedPtrField<T>* field_;
+};
+
 }  // namespace internal
 
 // Provides a back insert iterator for RepeatedField instances,
@@ -1598,6 +2458,25 @@
       mutable_field);
 }
 
+// Similar to AllocatedRepeatedPtrFieldBackInserter, using
+// UnsafeArenaAddAllocated instead of AddAllocated.
+// This is slightly faster if that matters. It is also useful in legacy code
+// that uses temporary ownership to avoid copies. Example:
+// RepeatedPtrField<T> temp_field;
+// temp_field.AddAllocated(new T);
+// ... // Do something with temp_field
+// temp_field.ExtractSubrange(0, temp_field.size(), NULL);
+// If you put temp_field on the arena this fails, because the ownership
+// transfers to the arena at the "AddAllocated" call and is not released anymore
+// causing a double delete. Using UnsafeArenaAddAllocated prevents this.
+template<typename T>
+internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>
+UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+    ::google::protobuf::RepeatedPtrField<T>* const mutable_field) {
+  return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>(
+      mutable_field);
+}
+
 }  // namespace protobuf
 
 }  // namespace google
diff --git a/src/google/protobuf/repeated_field_reflection.h b/src/google/protobuf/repeated_field_reflection.h
new file mode 100644
index 0000000..44d14d5
--- /dev/null
+++ b/src/google/protobuf/repeated_field_reflection.h
@@ -0,0 +1,337 @@
+// 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.
+
+// This header file is protobuf internal. Users should not include this
+// file directly.
+#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
+#define GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/generated_enum_reflection.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// Interfaces used to implement reflection RepeatedFieldRef API.
+// Reflection::GetRepeatedAccessor() should return a pointer to an singleton
+// object that implements the below interface.
+//
+// This interface passes/returns values using void pointers. The actual type
+// of the value depends on the field's cpp_type. Following is a mapping from
+// cpp_type to the type that should be used in this interface:
+//
+//   field->cpp_type()      T                Actual type of void*
+//   CPPTYPE_INT32        int32                   int32
+//   CPPTYPE_UINT32       uint32                  uint32
+//   CPPTYPE_INT64        int64                   int64
+//   CPPTYPE_UINT64       uint64                  uint64
+//   CPPTYPE_DOUBLE       double                  double
+//   CPPTYPE_FLOAT        float                   float
+//   CPPTYPE_BOOL         bool                    bool
+//   CPPTYPE_ENUM         generated enum type     int32
+//   CPPTYPE_STRING       string                  string
+//   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
+//                        or google::protobuf::Message
+//
+// Note that for enums we use int32 in the interface.
+//
+// You can map from T to the actual type using RefTypeTraits:
+//   typedef RefTypeTraits<T>::AccessorValueType ActualType;
+class LIBPROTOBUF_EXPORT RepeatedFieldAccessor {
+ public:
+  // Typedefs for clarity.
+  typedef void Field;
+  typedef void Value;
+  typedef void Iterator;
+
+  virtual ~RepeatedFieldAccessor();
+  virtual bool IsEmpty(const Field* data) const = 0;
+  virtual int Size(const Field* data) const = 0;
+  // Depends on the underlying representation of the repeated field, this
+  // method can return a pointer to the underlying object if such an object
+  // exists, or fill the data into scratch_space and return scratch_space.
+  // Callers of this method must ensure scratch_space is a valid pointer
+  // to a mutable object of the correct type.
+  virtual const Value* Get(
+      const Field* data, int index, Value* scratch_space) const = 0;
+
+  virtual void Clear(Field* data) const = 0;
+  virtual void Set(Field* data, int index, const Value* value) const = 0;
+  virtual void Add(Field* data, const Value* value) const = 0;
+  virtual void RemoveLast(Field* data) const = 0;
+  virtual void SwapElements(Field* data, int index1, int index2) const = 0;
+  virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator,
+                    Field* other_data) const = 0;
+
+  // Create an iterator that points at the begining of the repeated field.
+  virtual Iterator* BeginIterator(const Field* data) const = 0;
+  // Create an iterator that points at the end of the repeated field.
+  virtual Iterator* EndIterator(const Field* data) const = 0;
+  // Make a copy of an iterator and return the new copy.
+  virtual Iterator* CopyIterator(const Field* data,
+                                 const Iterator* iterator) const = 0;
+  // Move an iterator to point to the next element.
+  virtual Iterator* AdvanceIterator(const Field* data,
+                                    Iterator* iterator) const = 0;
+  // Compare whether two iterators point to the same element.
+  virtual bool EqualsIterator(const Field* data, const Iterator* a,
+                              const Iterator* b) const = 0;
+  // Delete an iterator created by BeginIterator(), EndIterator() and
+  // CopyIterator().
+  virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0;
+  // Like Get() but for iterators.
+  virtual const Value* GetIteratorValue(const Field* data,
+                                        const Iterator* iterator,
+                                        Value* scratch_space) const = 0;
+
+  // Templated methods that make using this interface easier for non-message
+  // types.
+  template<typename T>
+  T Get(const Field* data, int index) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    ActualType scratch_space;
+    return static_cast<T>(
+        *reinterpret_cast<const ActualType*>(
+            Get(data, index, static_cast<Value*>(&scratch_space))));
+  }
+
+  template<typename T, typename ValueType>
+  void Set(Field* data, int index, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Set(data, index, static_cast<const Value*>(&tmp));
+  }
+
+  template<typename T, typename ValueType>
+  void Add(Field* data, const ValueType& value) const {
+    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
+    // In this RepeatedFieldAccessor interface we pass/return data using
+    // raw pointers. Type of the data these raw pointers point to should
+    // be ActualType. Here we have a ValueType object and want a ActualType
+    // pointer. We can't cast a ValueType pointer to an ActualType pointer
+    // directly because their type might be different (for enums ValueType
+    // may be a generated enum type while ActualType is int32). To be safe
+    // we make a copy to get a temporary ActualType object and use it.
+    ActualType tmp = static_cast<ActualType>(value);
+    Add(data, static_cast<const Value*>(&tmp));
+  }
+};
+
+// Implement (Mutable)RepeatedFieldRef::iterator
+template<typename T>
+class RepeatedFieldRefIterator
+    : public std::iterator<std::forward_iterator_tag, T> {
+  typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
+  typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
+  typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType;
+
+ public:
+  // Constructor for non-message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor,
+                           bool begin)
+      : data_(data), accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data) :
+                          accessor->EndIterator(data)),
+        scratch_space_(new AccessorValueType) {
+  }
+  // Constructor for message fields.
+  RepeatedFieldRefIterator(const void* data,
+                           const RepeatedFieldAccessor* accessor,
+                           bool begin,
+                           AccessorValueType* scratch_space)
+      : data_(data), accessor_(accessor),
+        iterator_(begin ? accessor->BeginIterator(data) :
+                          accessor->EndIterator(data)),
+        scratch_space_(scratch_space) {
+  }
+  ~RepeatedFieldRefIterator() {
+    accessor_->DeleteIterator(data_, iterator_);
+  }
+  RepeatedFieldRefIterator operator++(int) {
+    RepeatedFieldRefIterator tmp(*this);
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return tmp;
+  }
+  RepeatedFieldRefIterator& operator++() {
+    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
+    return *this;
+  }
+  IteratorValueType operator*() const {
+    return static_cast<IteratorValueType>(
+        *static_cast<const AccessorValueType*>(
+            accessor_->GetIteratorValue(
+                data_, iterator_, scratch_space_.get())));
+  }
+  IteratorPointerType operator->() const {
+    return static_cast<IteratorPointerType>(
+        accessor_->GetIteratorValue(
+            data_, iterator_, scratch_space_.get()));
+  }
+  bool operator!=(const RepeatedFieldRefIterator& other) const {
+    assert(data_ == other.data_);
+    assert(accessor_ == other.accessor_);
+    return !accessor_->EqualsIterator(data_, iterator_, other.iterator_);
+  }
+  bool operator==(const RepeatedFieldRefIterator& other) const {
+    return !this->operator!=(other);
+  }
+
+  RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other)
+      : data_(other.data_), accessor_(other.accessor_),
+        iterator_(accessor_->CopyIterator(data_, other.iterator_)) {
+  }
+  RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) {
+    if (this != &other) {
+      accessor_->DeleteIterator(data_, iterator_);
+      data_ = other.data_;
+      accessor_ = other.accessor_;
+      iterator_ = accessor_->CopyIterator(data_, other.iterator_);
+    }
+    return *this;
+  }
+
+ protected:
+  const void* data_;
+  const RepeatedFieldAccessor* accessor_;
+  void* iterator_;
+  google::protobuf::scoped_ptr<AccessorValueType> scratch_space_;
+};
+
+// TypeTraits that maps the type parameter T of RepeatedFieldRef or
+// MutableRepeatedFieldRef to corresponding iterator type,
+// RepeatedFieldAccessor type, etc.
+template<typename T>
+struct PrimitiveTraits {
+  static const bool is_primitive = false;
+};
+#define DEFINE_PRIMITIVE(TYPE, type) \
+    template<> struct PrimitiveTraits<type> { \
+      static const bool is_primitive = true; \
+      static const FieldDescriptor::CppType cpp_type = \
+          FieldDescriptor::CPPTYPE_ ## TYPE; \
+    };
+DEFINE_PRIMITIVE(INT32, int32)
+DEFINE_PRIMITIVE(UINT32, uint32)
+DEFINE_PRIMITIVE(INT64, int64)
+DEFINE_PRIMITIVE(UINT64, uint64)
+DEFINE_PRIMITIVE(FLOAT, float)
+DEFINE_PRIMITIVE(DOUBLE, double)
+DEFINE_PRIMITIVE(BOOL, bool)
+#undef DEFINE_PRIMITIVE
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef T AccessorValueType;
+  typedef T IteratorValueType;
+  typedef T* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      PrimitiveTraits<T>::cpp_type;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<is_proto_enum<T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  // We use int32 for repeated enums in RepeatedFieldAccessor.
+  typedef int32 AccessorValueType;
+  typedef T IteratorValueType;
+  typedef int32* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_ENUM;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<internal::is_same<string, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef string AccessorValueType;
+  typedef string IteratorValueType;
+  typedef string* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_STRING;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct MessageDescriptorGetter {
+  static const Descriptor* get() {
+    return T::default_instance().GetDescriptor();
+  }
+};
+template<>
+struct MessageDescriptorGetter<Message> {
+  static const Descriptor* get() {
+    return NULL;
+  }
+};
+
+template<typename T>
+struct RefTypeTraits<
+    T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
+  typedef RepeatedFieldRefIterator<T> iterator;
+  typedef RepeatedFieldAccessor AccessorType;
+  typedef Message AccessorValueType;
+  typedef const T& IteratorValueType;
+  typedef const T* IteratorPointerType;
+  static const FieldDescriptor::CppType cpp_type =
+      FieldDescriptor::CPPTYPE_MESSAGE;
+  static const Descriptor* GetMessageFieldDescriptor() {
+    return MessageDescriptorGetter<T>::get();
+  }
+};
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc
index 62833aa..fcebe5c 100644
--- a/src/google/protobuf/repeated_field_reflection_unittest.cc
+++ b/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -33,10 +33,12 @@
 // Test reflection methods for aggregate access to Repeated[Ptr]Fields.
 // This test proto2 methods on a proto2 layout.
 
-#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/test_util.h>
+#include <google/protobuf/reflection.h>
 #include <gtest/gtest.h>
 
 namespace google {
@@ -58,7 +60,6 @@
   return str;
 }
 
-
 TEST(RepeatedFieldReflectionTest, RegularFields) {
   TestAllTypes message;
   const Reflection* refl = message.GetReflection();
@@ -113,7 +114,7 @@
       refl->MutableRepeatedPtrField<Message>(
           &message, fd_repeated_foreign_message);
 
-  // Make sure we can do get and sets through the Repeated[Ptr]Field objects.
+  // Make sure we can do gets and sets through the Repeated[Ptr]Field objects.
   for (int i = 0; i < 10; ++i) {
     // Check gets through const objects.
     EXPECT_EQ(rf_int32.Get(i), Func(i, 1));
@@ -158,8 +159,6 @@
 }
 
 
-
-
 TEST(RepeatedFieldReflectionTest, ExtensionFields) {
   TestAllExtensions extended_message;
   const Reflection* refl = extended_message.GetReflection();
@@ -190,6 +189,518 @@
   }
 }
 
+template<typename Ref, typename MessageType, typename ValueType>
+void TestRepeatedFieldRefIterator(
+    const Ref& handle, const MessageType& message,
+    ValueType (MessageType::*GetFunc)(int) const) {
+  int index = 0;
+  for (typename Ref::const_iterator it = handle.begin();
+       it != handle.end(); ++it) {
+    EXPECT_EQ((message.*GetFunc)(index), *it);
+    ++index;
+  }
+  EXPECT_EQ(handle.size(), index);
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+  TestAllTypes message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    message.add_repeated_int32(Func(i, 1));
+    message.add_repeated_double(Func(i, 2));
+    message.add_repeated_string(StrFunc(i, 5));
+    message.add_repeated_foreign_message()->set_c(Func(i, 6));
+  }
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+  const FieldDescriptor* fd_repeated_double =
+      desc->FindFieldByName("repeated_double");
+  const FieldDescriptor* fd_repeated_string =
+      desc->FindFieldByName("repeated_string");
+  const FieldDescriptor* fd_repeated_foreign_message =
+      desc->FindFieldByName("repeated_foreign_message");
+
+  // Get RepeatedFieldRef objects for all fields of interest.
+  const RepeatedFieldRef<int32> rf_int32 =
+      refl->GetRepeatedFieldRef<int32>(message, fd_repeated_int32);
+  const RepeatedFieldRef<double> rf_double =
+      refl->GetRepeatedFieldRef<double>(message, fd_repeated_double);
+  const RepeatedFieldRef<string> rf_string =
+      refl->GetRepeatedFieldRef<string>(message, fd_repeated_string);
+  const RepeatedFieldRef<ForeignMessage> rf_foreign_message =
+      refl->GetRepeatedFieldRef<ForeignMessage>(
+          message, fd_repeated_foreign_message);
+  const RepeatedFieldRef<Message> rf_message =
+      refl->GetRepeatedFieldRef<Message>(
+          message, fd_repeated_foreign_message);
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<int32> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32>(&message, fd_repeated_int32);
+  const MutableRepeatedFieldRef<double> mrf_double =
+      refl->GetMutableRepeatedFieldRef<double>(&message, fd_repeated_double);
+  const MutableRepeatedFieldRef<string> mrf_string =
+      refl->GetMutableRepeatedFieldRef<string>(&message, fd_repeated_string);
+  const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+      refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+          &message, fd_repeated_foreign_message);
+  const MutableRepeatedFieldRef<Message> mrf_message =
+      refl->GetMutableRepeatedFieldRef<Message>(
+          &message, fd_repeated_foreign_message);
+
+  EXPECT_EQ(message.repeated_int32_size(), rf_int32.size());
+  EXPECT_EQ(message.repeated_int32_size(), mrf_int32.size());
+  EXPECT_EQ(message.repeated_double_size(), rf_double.size());
+  EXPECT_EQ(message.repeated_double_size(), mrf_double.size());
+  EXPECT_EQ(message.repeated_string_size(), rf_string.size());
+  EXPECT_EQ(message.repeated_string_size(), mrf_string.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(),
+            rf_foreign_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(),
+            mrf_foreign_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(), rf_message.size());
+  EXPECT_EQ(message.repeated_foreign_message_size(), mrf_message.size());
+
+  EXPECT_FALSE(rf_int32.empty());
+  EXPECT_FALSE(mrf_int32.empty());
+  EXPECT_FALSE(rf_double.empty());
+  EXPECT_FALSE(mrf_double.empty());
+  EXPECT_FALSE(rf_string.empty());
+  EXPECT_FALSE(mrf_string.empty());
+  EXPECT_FALSE(rf_foreign_message.empty());
+  EXPECT_FALSE(mrf_foreign_message.empty());
+  EXPECT_FALSE(rf_message.empty());
+  EXPECT_FALSE(mrf_message.empty());
+
+  // Make sure we can do gets and sets through the RepeatedFieldRef objects.
+  for (int i = 0; i < 10; ++i) {
+    // Check gets through const objects.
+    EXPECT_EQ(rf_int32.Get(i), Func(i, 1));
+    EXPECT_EQ(rf_double.Get(i), Func(i, 2));
+    EXPECT_EQ(rf_string.Get(i), StrFunc(i, 5));
+    ForeignMessage scratch_space;
+    EXPECT_EQ(rf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6));
+    EXPECT_EQ(down_cast<const ForeignMessage&>(
+        rf_message.Get(i, &scratch_space)).c(), Func(i, 6));
+
+    // Check gets through mutable objects.
+    EXPECT_EQ(mrf_int32.Get(i), Func(i, 1));
+    EXPECT_EQ(mrf_double.Get(i), Func(i, 2));
+    EXPECT_EQ(mrf_string.Get(i), StrFunc(i, 5));
+    EXPECT_EQ(mrf_foreign_message.Get(i, &scratch_space).c(), Func(i, 6));
+    EXPECT_EQ(down_cast<const ForeignMessage&>(
+        mrf_message.Get(i, &scratch_space)).c(), Func(i, 6));
+
+    // Check sets through mutable objects.
+    mrf_int32.Set(i, Func(i, -1));
+    mrf_double.Set(i, Func(i, -2));
+    mrf_string.Set(i, StrFunc(i, -5));
+    ForeignMessage foreign_message;
+    foreign_message.set_c(Func(i, -6));
+    mrf_foreign_message.Set(i, foreign_message);
+    EXPECT_EQ(message.repeated_int32(i), Func(i, -1));
+    EXPECT_EQ(message.repeated_double(i), Func(i, -2));
+    EXPECT_EQ(message.repeated_string(i), StrFunc(i, -5));
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, -6));
+    foreign_message.set_c(Func(i, 7));
+    mrf_message.Set(i, foreign_message);
+    EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
+  }
+
+  // Test iterators.
+  TestRepeatedFieldRefIterator(rf_int32, message,
+                               &TestAllTypes::repeated_int32);
+  TestRepeatedFieldRefIterator(rf_double, message,
+                               &TestAllTypes::repeated_double);
+  TestRepeatedFieldRefIterator(rf_string, message,
+                               &TestAllTypes::repeated_string);
+
+  // Test iterators for message fields.
+  typedef RepeatedFieldRef<ForeignMessage>::iterator MessageIterator;
+  int index = 0;
+  for (MessageIterator it = rf_foreign_message.begin();
+       it != rf_foreign_message.end(); ++it) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), it->c());
+    ++index;
+  }
+  EXPECT_EQ(10, index);
+
+  // Test iterator operators that are not ususally used in regular for-loops.
+  // Including: post increment, assign, ==.
+  MessageIterator old_it = rf_foreign_message.begin();
+  MessageIterator new_it = old_it++;
+  EXPECT_FALSE(old_it == new_it);
+  // Check that old_it++ increments old_it once.
+  for (index = 1; old_it != rf_foreign_message.end(); ++old_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c());
+  }
+  EXPECT_EQ(10, index);
+  // Test assign operator.
+  old_it = new_it;
+  for (index = 0; old_it != rf_foreign_message.end(); ++old_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), old_it->c());
+  }
+  EXPECT_EQ(10, index);
+  // Check that the returned value of old_it++ is the one before increment.
+  for (index = 0; new_it != rf_foreign_message.end(); ++new_it, ++index) {
+    EXPECT_EQ(message.repeated_foreign_message(index).c(), new_it->c());
+  }
+  EXPECT_EQ(10, index);
+
+  // Test MutableRepeatedFieldRef::Add()
+  mrf_int32.Add(1234);
+  mrf_double.Add(1234.0);
+  mrf_string.Add("1234");
+  ForeignMessage foreign_message;
+  foreign_message.set_c(1234);
+  mrf_foreign_message.Add(foreign_message);
+  EXPECT_EQ(1234, message.repeated_int32(10));
+  EXPECT_EQ(1234.0, message.repeated_double(10));
+  EXPECT_EQ("1234", message.repeated_string(10));
+  EXPECT_EQ(1234, message.repeated_foreign_message(10).c());
+
+  // Test MutableRepeatedFieldRef::RemoveLast()
+  mrf_int32.RemoveLast();
+  mrf_double.RemoveLast();
+  mrf_string.RemoveLast();
+  mrf_foreign_message.RemoveLast();
+  EXPECT_EQ(10, message.repeated_int32_size());
+  EXPECT_EQ(10, message.repeated_double_size());
+  EXPECT_EQ(10, message.repeated_string_size());
+  EXPECT_EQ(10, message.repeated_foreign_message_size());
+
+  // Test MutableRepeatedFieldRef::SwapElements()
+  mrf_int32.SwapElements(0, 9);
+  mrf_double.SwapElements(0, 9);
+  mrf_string.SwapElements(0, 9);
+  mrf_foreign_message.SwapElements(0, 9);
+  EXPECT_EQ(Func(9, -1), message.repeated_int32(0));
+  EXPECT_EQ(Func(0, -1), message.repeated_int32(9));
+  EXPECT_EQ(Func(9, -2), message.repeated_double(0));
+  EXPECT_EQ(Func(0, -2), message.repeated_double(9));
+  EXPECT_EQ(StrFunc(9, -5), message.repeated_string(0));
+  EXPECT_EQ(StrFunc(0, -5), message.repeated_string(9));
+  EXPECT_EQ(Func(9, 7), message.repeated_foreign_message(0).c());
+  EXPECT_EQ(Func(0, 7), message.repeated_foreign_message(9).c());
+
+  // Test MutableRepeatedFieldRef::Clear()
+  mrf_int32.Clear();
+  mrf_double.Clear();
+  mrf_string.Clear();
+  mrf_foreign_message.Clear();
+  EXPECT_EQ(0, message.repeated_int32_size());
+  EXPECT_EQ(0, message.repeated_double_size());
+  EXPECT_EQ(0, message.repeated_string_size());
+  EXPECT_EQ(0, message.repeated_foreign_message_size());
+
+  // Test (Mutable)RepeatedFieldRef::empty()
+  EXPECT_TRUE(rf_int32.empty());
+  EXPECT_TRUE(mrf_int32.empty());
+  EXPECT_TRUE(rf_double.empty());
+  EXPECT_TRUE(mrf_double.empty());
+  EXPECT_TRUE(rf_string.empty());
+  EXPECT_TRUE(mrf_string.empty());
+  EXPECT_TRUE(rf_foreign_message.empty());
+  EXPECT_TRUE(mrf_foreign_message.empty());
+  EXPECT_TRUE(rf_message.empty());
+  EXPECT_TRUE(mrf_message.empty());
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+
+  // Make sure types are checked correctly at runtime.
+  const FieldDescriptor* fd_optional_int32 =
+      desc->FindFieldByName("optional_int32");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<int32>(
+      message, fd_optional_int32), "");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<double>(
+      message, fd_repeated_int32), "");
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<TestAllTypes>(
+      message, fd_repeated_foreign_message), "");
+
+#endif  // PROTOBUF_HAS_DEATH_TEST
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForEnums) {
+  TestAllTypes message;
+  const Reflection* refl = message.GetReflection();
+  const Descriptor* desc = message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    message.add_repeated_nested_enum(TestAllTypes::BAR);
+  }
+
+  const FieldDescriptor* fd_repeated_nested_enum =
+      desc->FindFieldByName("repeated_nested_enum");
+  const RepeatedFieldRef<TestAllTypes::NestedEnum> enum_ref =
+      refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          message, fd_repeated_nested_enum);
+  const MutableRepeatedFieldRef<TestAllTypes::NestedEnum>
+  mutable_enum_ref =
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &message, fd_repeated_nested_enum);
+  const RepeatedFieldRef<int32> int32_ref =
+      refl->GetRepeatedFieldRef<int32>(
+          message, fd_repeated_nested_enum);
+  const MutableRepeatedFieldRef<int32> mutable_int32_ref =
+      refl->GetMutableRepeatedFieldRef<int32>(
+          &message, fd_repeated_nested_enum);
+
+  EXPECT_EQ(message.repeated_nested_enum_size(), enum_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), mutable_enum_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), int32_ref.size());
+  EXPECT_EQ(message.repeated_nested_enum_size(), mutable_int32_ref.size());
+
+  EXPECT_FALSE(enum_ref.empty());
+  EXPECT_FALSE(mutable_enum_ref.empty());
+  EXPECT_FALSE(int32_ref.empty());
+  EXPECT_FALSE(mutable_int32_ref.empty());
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAR, mutable_enum_ref.Get(i));
+    mutable_enum_ref.Set(i, TestAllTypes::BAZ);
+    EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i));
+
+    message.set_repeated_nested_enum(i, TestAllTypes::BAR);
+    EXPECT_EQ(TestAllTypes::BAR, int32_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAR, mutable_int32_ref.Get(i));
+    mutable_int32_ref.Set(i, TestAllTypes::BAZ);
+    EXPECT_EQ(TestAllTypes::BAZ, int32_ref.Get(i));
+    EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(i));
+  }
+
+  TestRepeatedFieldRefIterator(enum_ref, message,
+                               &TestAllTypes::repeated_nested_enum);
+  TestRepeatedFieldRefIterator(int32_ref, message,
+                               &TestAllTypes::repeated_nested_enum);
+
+  // Test Add()
+  mutable_enum_ref.Add(TestAllTypes::FOO);
+  EXPECT_EQ(TestAllTypes::FOO, message.repeated_nested_enum(10));
+  mutable_int32_ref.Add(TestAllTypes::BAR);
+  EXPECT_EQ(TestAllTypes::BAR, message.repeated_nested_enum(11));
+
+  // Test RemoveLast()
+  mutable_enum_ref.RemoveLast();
+  EXPECT_EQ(11, message.repeated_nested_enum_size());
+  mutable_int32_ref.RemoveLast();
+  EXPECT_EQ(10, message.repeated_nested_enum_size());
+
+  // Test SwapElements()
+  mutable_enum_ref.Set(0, TestAllTypes::BAR);
+  mutable_enum_ref.Set(9, TestAllTypes::BAZ);
+  mutable_enum_ref.SwapElements(0, 9);
+  EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(0));
+  EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(9));
+  mutable_int32_ref.SwapElements(0, 9);
+  EXPECT_EQ(TestAllTypes::BAR, enum_ref.Get(0));
+  EXPECT_EQ(TestAllTypes::BAZ, enum_ref.Get(9));
+
+  // Test Clear()
+  mutable_enum_ref.Clear();
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+  mutable_enum_ref.Add(TestAllTypes::FOO);
+  EXPECT_EQ(1, message.repeated_nested_enum_size());
+  mutable_int32_ref.Clear();
+  EXPECT_EQ(0, message.repeated_nested_enum_size());
+
+  // Test empty()
+  EXPECT_TRUE(enum_ref.empty());
+  EXPECT_TRUE(mutable_enum_ref.empty());
+  EXPECT_TRUE(int32_ref.empty());
+  EXPECT_TRUE(mutable_int32_ref.empty());
+}
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefForExtensionFields) {
+  TestAllExtensions extended_message;
+  const Reflection* refl = extended_message.GetReflection();
+  const Descriptor* desc = extended_message.GetDescriptor();
+
+  for (int i = 0; i < 10; ++i) {
+    extended_message.AddExtension(
+        unittest::repeated_int64_extension, Func(i, 1));
+  }
+
+  const FieldDescriptor* fd_repeated_int64_extension =
+      desc->file()->FindExtensionByName("repeated_int64_extension");
+  GOOGLE_CHECK(fd_repeated_int64_extension != NULL);
+
+  const RepeatedFieldRef<int64> rf_int64_extension =
+      refl->GetRepeatedFieldRef<int64>(extended_message,
+                                          fd_repeated_int64_extension);
+
+  const MutableRepeatedFieldRef<int64> mrf_int64_extension =
+      refl->GetMutableRepeatedFieldRef<int64>(&extended_message,
+                                                 fd_repeated_int64_extension);
+
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
+    mrf_int64_extension.Set(i, Func(i, -1));
+    EXPECT_EQ(Func(i, -1),
+        extended_message.GetExtension(unittest::repeated_int64_extension, i));
+  }
+}
+
+
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+  // Set-up message content.
+  TestAllTypes m0, m1, m2;
+  for (int i = 0; i < 10; ++i) {
+    m0.add_repeated_int32(Func(i, 1));
+    m0.add_repeated_double(Func(i, 2));
+    m0.add_repeated_string(StrFunc(i, 5));
+    m0.add_repeated_foreign_message()->set_c(Func(i, 6));
+    m0.add_repeated_nested_enum(TestAllTypes::FOO);
+    m1.add_repeated_int32(Func(i, 11));
+    m1.add_repeated_double(Func(i, 12));
+    m1.add_repeated_string(StrFunc(i, 15));
+    m1.add_repeated_foreign_message()->set_c(Func(i, 16));
+    m1.add_repeated_nested_enum(TestAllTypes::BAR);
+    m2.add_repeated_int32(Func(i, 21));
+    m2.add_repeated_double(Func(i, 22));
+    m2.add_repeated_string(StrFunc(i, 25));
+    m2.add_repeated_foreign_message()->set_c(Func(i, 26));
+    m2.add_repeated_nested_enum(TestAllTypes::BAZ);
+  }
+
+  const Reflection* refl = m0.GetReflection();
+  const Descriptor* desc = m0.GetDescriptor();
+
+  // Get FieldDescriptors for all the fields of interest.
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+  const FieldDescriptor* fd_repeated_double =
+      desc->FindFieldByName("repeated_double");
+  const FieldDescriptor* fd_repeated_string =
+      desc->FindFieldByName("repeated_string");
+  const FieldDescriptor* fd_repeated_foreign_message =
+      desc->FindFieldByName("repeated_foreign_message");
+  const FieldDescriptor* fd_repeated_nested_enum =
+      desc->FindFieldByName("repeated_nested_enum");
+
+  // Get MutableRepeatedFieldRef objects for all fields of interest.
+  const MutableRepeatedFieldRef<int32> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32>(&m0, fd_repeated_int32);
+  const MutableRepeatedFieldRef<double> mrf_double =
+      refl->GetMutableRepeatedFieldRef<double>(&m0, fd_repeated_double);
+  const MutableRepeatedFieldRef<string> mrf_string =
+      refl->GetMutableRepeatedFieldRef<string>(&m0, fd_repeated_string);
+  const MutableRepeatedFieldRef<ForeignMessage> mrf_foreign_message =
+      refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+          &m0, fd_repeated_foreign_message);
+  const MutableRepeatedFieldRef<TestAllTypes::NestedEnum>
+  mrf_nested_enum =
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &m0, fd_repeated_nested_enum);
+
+  // Test MutableRepeatedRef::CopyFrom
+  mrf_int32.CopyFrom(
+      refl->GetRepeatedFieldRef<int32>(m1, fd_repeated_int32));
+  mrf_double.CopyFrom(
+      refl->GetRepeatedFieldRef<double>(m1, fd_repeated_double));
+  mrf_string.CopyFrom(
+      refl->GetRepeatedFieldRef<string>(m1, fd_repeated_string));
+  mrf_foreign_message.CopyFrom(
+      refl->GetRepeatedFieldRef<ForeignMessage>(
+          m1, fd_repeated_foreign_message));
+  mrf_nested_enum.CopyFrom(
+      refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          m1, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 11), m0.repeated_int32(i));
+    EXPECT_EQ(Func(i, 12), m0.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 15), m0.repeated_string(i));
+    EXPECT_EQ(Func(i, 16), m0.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAR, m0.repeated_nested_enum(i));
+  }
+
+  // Test MutableRepeatedRef::MergeFrom
+  mrf_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<int32>(m2, fd_repeated_int32));
+  mrf_double.MergeFrom(
+      refl->GetRepeatedFieldRef<double>(m2, fd_repeated_double));
+  mrf_string.MergeFrom(
+      refl->GetRepeatedFieldRef<string>(m2, fd_repeated_string));
+  mrf_foreign_message.MergeFrom(
+      refl->GetRepeatedFieldRef<ForeignMessage>(
+          m2, fd_repeated_foreign_message));
+  mrf_nested_enum.MergeFrom(
+      refl->GetRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          m2, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    EXPECT_EQ(Func(i, 21), m0.repeated_int32(i + 10));
+    EXPECT_EQ(Func(i, 22), m0.repeated_double(i + 10));
+    EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i + 10));
+    EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i + 10).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i + 10));
+  }
+
+  // Test MutableRepeatedRef::Swap
+  // Swap between m0 and m2.
+  mrf_int32.Swap(
+      refl->GetMutableRepeatedFieldRef<int32>(&m2, fd_repeated_int32));
+  mrf_double.Swap(
+      refl->GetMutableRepeatedFieldRef<double>(&m2, fd_repeated_double));
+  mrf_string.Swap(
+      refl->GetMutableRepeatedFieldRef<string>(&m2, fd_repeated_string));
+  mrf_foreign_message.Swap(
+      refl->GetMutableRepeatedFieldRef<ForeignMessage>(
+          &m2, fd_repeated_foreign_message));
+  mrf_nested_enum.Swap(
+      refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
+          &m2, fd_repeated_nested_enum));
+  for (int i = 0; i < 10; ++i) {
+    // Check the content of m0.
+    EXPECT_EQ(Func(i, 21), m0.repeated_int32(i));
+    EXPECT_EQ(Func(i, 22), m0.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 25), m0.repeated_string(i));
+    EXPECT_EQ(Func(i, 26), m0.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m0.repeated_nested_enum(i));
+
+    // Check the content of m2.
+    EXPECT_EQ(Func(i, 11), m2.repeated_int32(i));
+    EXPECT_EQ(Func(i, 12), m2.repeated_double(i));
+    EXPECT_EQ(StrFunc(i, 15), m2.repeated_string(i));
+    EXPECT_EQ(Func(i, 16), m2.repeated_foreign_message(i).c());
+    EXPECT_EQ(TestAllTypes::BAR, m2.repeated_nested_enum(i));
+    EXPECT_EQ(Func(i, 21), m2.repeated_int32(i + 10));
+    EXPECT_EQ(Func(i, 22), m2.repeated_double(i + 10));
+    EXPECT_EQ(StrFunc(i, 25), m2.repeated_string(i + 10));
+    EXPECT_EQ(Func(i, 26), m2.repeated_foreign_message(i + 10).c());
+    EXPECT_EQ(TestAllTypes::BAZ, m2.repeated_nested_enum(i + 10));
+  }
+}
+
+// Test that GetRepeatedFieldRef/MutableRepeatedFieldRef works with
+// DynamicMessage.
+TEST(RepeatedFieldReflectionTest, RepeatedFieldRefDynamicMessage) {
+  // DynamicMessage shares the same memory layout as generated message
+  // and use the same GeneratedMessageReflection code for reflection.
+  // All code paths should already be covered by the other tests for
+  // generated messages. Here we just test one field.
+
+  const Descriptor* desc = TestAllTypes::descriptor();
+  const FieldDescriptor* fd_repeated_int32 =
+      desc->FindFieldByName("repeated_int32");
+
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> dynamic_message(factory.GetPrototype(desc)->New());
+  const Reflection* refl = dynamic_message->GetReflection();
+
+  MutableRepeatedFieldRef<int32> rf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32>(
+          dynamic_message.get(), fd_repeated_int32);
+  rf_int32.Add(1234);
+  EXPECT_EQ(1, refl->FieldSize(*dynamic_message, fd_repeated_int32));
+  EXPECT_EQ(1234, refl->GetRepeatedInt32(*dynamic_message,
+                                         fd_repeated_int32, 0));
+}
+
 }  // namespace
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index f4d48f5..39b24b3 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -42,6 +42,7 @@
 
 #include <google/protobuf/repeated_field.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/stubs/strutil.h>
@@ -92,7 +93,8 @@
 
   EXPECT_TRUE(field.empty());
   EXPECT_EQ(field.size(), 0);
-  int expected_usage = 4 * sizeof(int);
+  // Additional bytes are for 'struct Rep' header.
+  int expected_usage = 4 * sizeof(int) + sizeof(Arena*);
   EXPECT_EQ(field.SpaceUsedExcludingSelf(), expected_usage);
 }
 
@@ -295,6 +297,39 @@
   EXPECT_EQ(3, me.Get(0));
 }
 
+TEST(RepeatedField, Erase) {
+  RepeatedField<int> me;
+  RepeatedField<int>::iterator it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  me.Add(1);
+  me.Add(2);
+  me.Add(3);
+  it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  me.Add(4);
+  me.Add(5);
+  me.Add(6);
+  it = me.erase(me.begin() + 2, me.end());
+  EXPECT_TRUE(me.begin() + 2 == it);
+  EXPECT_EQ(2, me.size());
+  EXPECT_EQ(4, me.Get(0));
+  EXPECT_EQ(5, me.Get(1));
+
+  me.Add(6);
+  me.Add(7);
+  me.Add(8);
+  it = me.erase(me.begin() + 1, me.begin() + 3);
+  EXPECT_TRUE(me.begin() + 1 == it);
+  EXPECT_EQ(3, me.size());
+  EXPECT_EQ(4, me.Get(0));
+  EXPECT_EQ(7, me.Get(1));
+  EXPECT_EQ(8, me.Get(2));
+}
+
 TEST(RepeatedField, CopyConstruct) {
   RepeatedField<int> source;
   source.Add(1);
@@ -422,6 +457,28 @@
   }
 }
 
+TEST(RepeatedField, ClearThenReserveMore) {
+  // Test that Reserve properly destroys the old internal array when it's forced
+  // to allocate a new one, even when cleared-but-not-deleted objects are
+  // present. Use a 'string' and > 16 bytes length so that the elements are
+  // non-POD and allocate -- the leak checker will catch any skipped destructor
+  // calls here.
+  RepeatedField<string> field;
+  for (int i = 0; i < 32; i++) {
+    field.Add(string("abcdefghijklmnopqrstuvwxyz0123456789"));
+  }
+  EXPECT_EQ(32, field.size());
+  field.Clear();
+  EXPECT_EQ(0, field.size());
+  EXPECT_EQ(32, field.Capacity());
+
+  field.Reserve(1024);
+  EXPECT_EQ(0, field.size());
+  EXPECT_EQ(1024, field.Capacity());
+  // Finish test -- |field| should destroy the cleared-but-not-yet-destroyed
+  // strings.
+}
+
 // ===================================================================
 // RepeatedPtrField tests.  These pretty much just mirror the RepeatedField
 // tests above.
@@ -741,6 +798,39 @@
   EXPECT_EQ("1", me.Get(0));
 }
 
+TEST(RepeatedPtrField, Erase) {
+  RepeatedPtrField<string> me;
+  RepeatedPtrField<string>::iterator it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  *me.Add() = "1";
+  *me.Add() = "2";
+  *me.Add() = "3";
+  it = me.erase(me.begin(), me.end());
+  EXPECT_TRUE(me.begin() == it);
+  EXPECT_EQ(0, me.size());
+
+  *me.Add() = "4";
+  *me.Add() = "5";
+  *me.Add() = "6";
+  it = me.erase(me.begin() + 2, me.end());
+  EXPECT_TRUE(me.begin() + 2 == it);
+  EXPECT_EQ(2, me.size());
+  EXPECT_EQ("4", me.Get(0));
+  EXPECT_EQ("5", me.Get(1));
+
+  *me.Add() = "6";
+  *me.Add() = "7";
+  *me.Add() = "8";
+  it = me.erase(me.begin() + 1, me.begin() + 3);
+  EXPECT_TRUE(me.begin() + 1 == it);
+  EXPECT_EQ(3, me.size());
+  EXPECT_EQ("4", me.Get(0));
+  EXPECT_EQ("7", me.Get(1));
+  EXPECT_EQ("8", me.Get(2));
+}
+
 TEST(RepeatedPtrField, CopyConstruct) {
   RepeatedPtrField<string> source;
   source.Add()->assign("1");
@@ -1064,7 +1154,7 @@
 
   string v = "f";
   RepeatedPtrField<string>::const_iterator it =
-      lower_bound(proto_array_.begin(), proto_array_.end(), v);
+      std::lower_bound(proto_array_.begin(), proto_array_.end(), v);
 
   EXPECT_EQ(*it, "n");
   EXPECT_TRUE(it == proto_array_.begin() + 3);
@@ -1225,8 +1315,8 @@
   {
     string v = "f";
     RepeatedPtrField<string>::pointer_iterator it =
-        lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
-                    &v, StringLessThan());
+        std::lower_bound(proto_array_.pointer_begin(),
+                         proto_array_.pointer_end(), &v, StringLessThan());
 
     GOOGLE_CHECK(*it != NULL);
 
@@ -1235,10 +1325,9 @@
   }
   {
     string v = "f";
-    RepeatedPtrField<string>::const_pointer_iterator it =
-        lower_bound(const_proto_array_->pointer_begin(),
-                    const_proto_array_->pointer_end(),
-                    &v, StringLessThan());
+    RepeatedPtrField<string>::const_pointer_iterator it = std::lower_bound(
+        const_proto_array_->pointer_begin(), const_proto_array_->pointer_end(),
+        &v, StringLessThan());
 
     GOOGLE_CHECK(*it != NULL);
 
@@ -1276,9 +1365,8 @@
   EXPECT_EQ("foo", proto_array_.Get(0));
   EXPECT_EQ("n", proto_array_.Get(5));
   EXPECT_EQ("x", proto_array_.Get(9));
-  sort(proto_array_.pointer_begin(),
-       proto_array_.pointer_end(),
-       StringLessThan());
+  std::sort(proto_array_.pointer_begin(), proto_array_.pointer_end(),
+            StringLessThan());
   EXPECT_EQ("a", proto_array_.Get(0));
   EXPECT_EQ("baz", proto_array_.Get(2));
   EXPECT_EQ("y", proto_array_.Get(9));
@@ -1342,7 +1430,6 @@
     std::copy(nested_ptrs.begin(), nested_ptrs.end(),
               RepeatedFieldBackInserter(
                   protobuffer.mutable_repeated_nested_message()));
-
   }
 
   virtual void TearDown() {
@@ -1411,9 +1498,9 @@
     new_data->set_bb(i);
   }
   TestAllTypes testproto;
-  copy(data.begin(), data.end(),
-       AllocatedRepeatedPtrFieldBackInserter(
-           testproto.mutable_repeated_nested_message()));
+  std::copy(data.begin(), data.end(),
+            AllocatedRepeatedPtrFieldBackInserter(
+                testproto.mutable_repeated_nested_message()));
   EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
 }
 
@@ -1430,9 +1517,46 @@
     *new_data = "name-" + SimpleItoa(i);
   }
   TestAllTypes testproto;
-  copy(data.begin(), data.end(),
-       AllocatedRepeatedPtrFieldBackInserter(
-           testproto.mutable_repeated_string()));
+  std::copy(data.begin(), data.end(), AllocatedRepeatedPtrFieldBackInserter(
+                                          testproto.mutable_repeated_string()));
+  EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       UnsafeArenaAllocatedRepeatedPtrFieldWithStringIntData) {
+  vector<Nested*> data;
+  TestAllTypes goldenproto;
+  for (int i = 0; i < 10; ++i) {
+    Nested* new_data = new Nested;
+    new_data->set_bb(i);
+    data.push_back(new_data);
+
+    new_data = goldenproto.add_repeated_nested_message();
+    new_data->set_bb(i);
+  }
+  TestAllTypes testproto;
+  std::copy(data.begin(), data.end(),
+            UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+                testproto.mutable_repeated_nested_message()));
+  EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
+}
+
+TEST_F(RepeatedFieldInsertionIteratorsTest,
+       UnsafeArenaAllocatedRepeatedPtrFieldWithString) {
+  vector<string*> data;
+  TestAllTypes goldenproto;
+  for (int i = 0; i < 10; ++i) {
+    string* new_data = new string;
+    *new_data = "name-" + SimpleItoa(i);
+    data.push_back(new_data);
+
+    new_data = goldenproto.add_repeated_string();
+    *new_data = "name-" + SimpleItoa(i);
+  }
+  TestAllTypes testproto;
+  std::copy(data.begin(), data.end(),
+            UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
+                testproto.mutable_repeated_string()));
   EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
 }
 
diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h
index cc0b45d..ad6f968 100644
--- a/src/google/protobuf/service.h
+++ b/src/google/protobuf/service.h
@@ -74,12 +74,12 @@
 //
 // To call a remote MyServiceImpl, first you need an RpcChannel connected to it.
 // How to construct a channel depends, again, on your RPC implementation.
-// Here we use a hypothentical "MyRpcChannel" as an example:
+// Here we use a hypothetical "MyRpcChannel" as an example:
 //   MyRpcChannel channel("rpc:hostname:1234/myservice");
 //   MyRpcController controller;
 //   MyServiceImpl::Stub stub(&channel);
 //   FooRequest request;
-//   FooRespnose response;
+//   FooResponse response;
 //
 //   // ... fill in request ...
 //
@@ -102,6 +102,7 @@
 
 #include <string>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/callback.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
new file mode 100644
index 0000000..c67cd10
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.cc
@@ -0,0 +1,397 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/source_context.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* SourceContext_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SourceContext_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/source_context.proto");
+  GOOGLE_CHECK(file != NULL);
+  SourceContext_descriptor_ = file->message_type(0);
+  static const int SourceContext_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceContext, file_name_),
+  };
+  SourceContext_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SourceContext_descriptor_,
+      SourceContext::default_instance_,
+      SourceContext_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(SourceContext),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceContext, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceContext, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SourceContext_descriptor_, &SourceContext::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fsource_5fcontext_2eproto() {
+  delete SourceContext::default_instance_;
+  delete SourceContext_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n$google/protobuf/source_context.proto\022\017"
+    "google.protobuf\"\"\n\rSourceContext\022\021\n\tfile"
+    "_name\030\001 \001(\tBU\n\023com.google.protobufB\022Sour"
+    "ceContextProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Proto"
+    "buf.WellKnownTypesb\006proto3", 186);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/source_context.proto", &protobuf_RegisterTypes);
+  SourceContext::default_instance_ = new SourceContext();
+  SourceContext::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fsource_5fcontext_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fsource_5fcontext_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fsource_5fcontext_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fsource_5fcontext_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SourceContext::kFileNameFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SourceContext::SourceContext()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.SourceContext)
+}
+
+void SourceContext::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+SourceContext::SourceContext(const SourceContext& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.SourceContext)
+}
+
+void SourceContext::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  file_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+SourceContext::~SourceContext() {
+  // @@protoc_insertion_point(destructor:google.protobuf.SourceContext)
+  SharedDtor();
+}
+
+void SourceContext::SharedDtor() {
+  file_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void SourceContext::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SourceContext::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SourceContext_descriptor_;
+}
+
+const SourceContext& SourceContext::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  return *default_instance_;
+}
+
+SourceContext* SourceContext::default_instance_ = NULL;
+
+SourceContext* SourceContext::New(::google::protobuf::Arena* arena) const {
+  SourceContext* n = new SourceContext;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SourceContext::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceContext)
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool SourceContext::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.SourceContext)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string file_name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_file_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->file_name().data(), this->file_name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.SourceContext.file_name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.SourceContext)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.SourceContext)
+  return false;
+#undef DO_
+}
+
+void SourceContext::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.SourceContext)
+  // optional string file_name = 1;
+  if (this->file_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->file_name().data(), this->file_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.SourceContext.file_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->file_name(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.SourceContext)
+}
+
+::google::protobuf::uint8* SourceContext::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
+  // optional string file_name = 1;
+  if (this->file_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->file_name().data(), this->file_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.SourceContext.file_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->file_name(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceContext)
+  return target;
+}
+
+int SourceContext::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext)
+  int total_size = 0;
+
+  // optional string file_name = 1;
+  if (this->file_name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->file_name());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SourceContext::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceContext)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SourceContext* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceContext>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceContext)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceContext)
+    MergeFrom(*source);
+  }
+}
+
+void SourceContext::MergeFrom(const SourceContext& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.file_name().size() > 0) {
+
+    file_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.file_name_);
+  }
+}
+
+void SourceContext::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceContext)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SourceContext::CopyFrom(const SourceContext& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceContext)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool SourceContext::IsInitialized() const {
+
+  return true;
+}
+
+void SourceContext::Swap(SourceContext* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SourceContext::InternalSwap(SourceContext* other) {
+  file_name_.Swap(&other->file_name_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SourceContext::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SourceContext_descriptor_;
+  metadata.reflection = SourceContext_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SourceContext
+
+// optional string file_name = 1;
+void SourceContext::clear_file_name() {
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& SourceContext::file_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceContext.file_name)
+  return file_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceContext::set_file_name(const ::std::string& value) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceContext.file_name)
+}
+ void SourceContext::set_file_name(const char* value) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceContext.file_name)
+}
+ void SourceContext::set_file_name(const char* value, size_t size) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceContext.file_name)
+}
+ ::std::string* SourceContext::mutable_file_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceContext.file_name)
+  return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* SourceContext::release_file_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name)
+  
+  return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void SourceContext::set_allocated_file_name(::std::string* file_name) {
+  if (file_name != NULL) {
+    
+  } else {
+    
+  }
+  file_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), file_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceContext.file_name)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
new file mode 100644
index 0000000..ccfd365
--- /dev/null
+++ b/src/google/protobuf/source_context.pb.h
@@ -0,0 +1,186 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fsource_5fcontext_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fsource_5fcontext_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fsource_5fcontext_2eproto();
+
+class SourceContext;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message {
+ public:
+  SourceContext();
+  virtual ~SourceContext();
+
+  SourceContext(const SourceContext& from);
+
+  inline SourceContext& operator=(const SourceContext& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SourceContext& default_instance();
+
+  void Swap(SourceContext* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SourceContext* New() const { return New(NULL); }
+
+  SourceContext* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SourceContext& from);
+  void MergeFrom(const SourceContext& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SourceContext* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string file_name = 1;
+  void clear_file_name();
+  static const int kFileNameFieldNumber = 1;
+  const ::std::string& file_name() const;
+  void set_file_name(const ::std::string& value);
+  void set_file_name(const char* value);
+  void set_file_name(const char* value, size_t size);
+  ::std::string* mutable_file_name();
+  ::std::string* release_file_name();
+  void set_allocated_file_name(::std::string* file_name);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.SourceContext)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr file_name_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fsource_5fcontext_2eproto();
+
+  void InitAsDefaultInstance();
+  static SourceContext* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// SourceContext
+
+// optional string file_name = 1;
+inline void SourceContext::clear_file_name() {
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& SourceContext::file_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.SourceContext.file_name)
+  return file_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceContext::set_file_name(const ::std::string& value) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.SourceContext.file_name)
+}
+inline void SourceContext::set_file_name(const char* value) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.SourceContext.file_name)
+}
+inline void SourceContext::set_file_name(const char* value, size_t size) {
+  
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceContext.file_name)
+}
+inline ::std::string* SourceContext::mutable_file_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.SourceContext.file_name)
+  return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SourceContext::release_file_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name)
+  
+  return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SourceContext::set_allocated_file_name(::std::string* file_name) {
+  if (file_name != NULL) {
+    
+  } else {
+    
+  }
+  file_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), file_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.SourceContext.file_name)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fsource_5fcontext_2eproto__INCLUDED
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
new file mode 100644
index 0000000..d76252c
--- /dev/null
+++ b/src/google/protobuf/source_context.proto
@@ -0,0 +1,48 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "SourceContextProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// `SourceContext` represents information about the source of a
+// protobuf element, like the file in which it is defined.
+message SourceContext {
+  // The path-qualified name of the .proto file that contained the associated
+  // protobuf element.  For example: `"google/protobuf/source.proto"`.
+  string file_name = 1;
+}
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
new file mode 100644
index 0000000..11ccabb
--- /dev/null
+++ b/src/google/protobuf/struct.pb.cc
@@ -0,0 +1,1500 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/struct.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Struct_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Struct_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Struct_FieldsEntry_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Value_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Value_reflection_ = NULL;
+struct ValueOneofInstance {
+  int null_value_;
+  double number_value_;
+  ::google::protobuf::internal::ArenaStringPtr string_value_;
+  bool bool_value_;
+  const ::google::protobuf::Struct* struct_value_;
+  const ::google::protobuf::ListValue* list_value_;
+}* Value_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* ListValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ListValue_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* NullValue_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/struct.proto");
+  GOOGLE_CHECK(file != NULL);
+  Struct_descriptor_ = file->message_type(0);
+  static const int Struct_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Struct, fields_),
+  };
+  Struct_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Struct_descriptor_,
+      Struct::default_instance_,
+      Struct_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Struct),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Struct, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Struct, _is_default_instance_));
+  Struct_FieldsEntry_descriptor_ = Struct_descriptor_->nested_type(0);
+  Value_descriptor_ = file->message_type(1);
+  static const int Value_offsets_[7] = {
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, null_value_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, number_value_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, string_value_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, bool_value_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, struct_value_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Value_default_oneof_instance_, list_value_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Value, kind_),
+  };
+  Value_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Value_descriptor_,
+      Value::default_instance_,
+      Value_offsets_,
+      -1,
+      -1,
+      -1,
+      Value_default_oneof_instance_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Value, _oneof_case_[0]),
+      sizeof(Value),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Value, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Value, _is_default_instance_));
+  ListValue_descriptor_ = file->message_type(2);
+  static const int ListValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListValue, values_),
+  };
+  ListValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ListValue_descriptor_,
+      ListValue::default_instance_,
+      ListValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(ListValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListValue, _is_default_instance_));
+  NullValue_descriptor_ = file->enum_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Struct_descriptor_, &Struct::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+        Struct_FieldsEntry_descriptor_,
+        ::google::protobuf::internal::MapEntry<
+            ::std::string,
+            ::google::protobuf::Value,
+            ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+            ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+            0>::CreateDefaultInstance(
+                Struct_FieldsEntry_descriptor_));
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Value_descriptor_, &Value::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ListValue_descriptor_, &ListValue::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto() {
+  delete Struct::default_instance_;
+  delete Struct_reflection_;
+  delete Value::default_instance_;
+  delete Value_default_oneof_instance_;
+  delete Value_reflection_;
+  delete ListValue::default_instance_;
+  delete ListValue_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\034google/protobuf/struct.proto\022\017google.p"
+    "rotobuf\"\204\001\n\006Struct\0223\n\006fields\030\001 \003(\0132#.goo"
+    "gle.protobuf.Struct.FieldsEntry\032E\n\013Field"
+    "sEntry\022\013\n\003key\030\001 \001(\t\022%\n\005value\030\002 \001(\0132\026.goo"
+    "gle.protobuf.Value:\0028\001\"\352\001\n\005Value\0220\n\nnull"
+    "_value\030\001 \001(\0162\032.google.protobuf.NullValue"
+    "H\000\022\026\n\014number_value\030\002 \001(\001H\000\022\026\n\014string_val"
+    "ue\030\003 \001(\tH\000\022\024\n\nbool_value\030\004 \001(\010H\000\022/\n\014stru"
+    "ct_value\030\005 \001(\0132\027.google.protobuf.StructH"
+    "\000\0220\n\nlist_value\030\006 \001(\0132\032.google.protobuf."
+    "ListValueH\000B\006\n\004kind\"3\n\tListValue\022&\n\006valu"
+    "es\030\001 \003(\0132\026.google.protobuf.Value*\033\n\tNull"
+    "Value\022\016\n\nNULL_VALUE\020\000B\201\001\n\023com.google.pro"
+    "tobufB\013StructProtoP\001Z1github.com/golang/"
+    "protobuf/ptypes/struct;structpb\240\001\001\242\002\003GPB"
+    "\252\002\036Google.Protobuf.WellKnownTypesb\006proto"
+    "3", 641);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/struct.proto", &protobuf_RegisterTypes);
+  Struct::default_instance_ = new Struct();
+  Value::default_instance_ = new Value();
+  Value_default_oneof_instance_ = new ValueOneofInstance();
+  ListValue::default_instance_ = new ListValue();
+  Struct::default_instance_->InitAsDefaultInstance();
+  Value::default_instance_->InitAsDefaultInstance();
+  ListValue::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fstruct_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fstruct_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fstruct_2eproto_;
+const ::google::protobuf::EnumDescriptor* NullValue_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NullValue_descriptor_;
+}
+bool NullValue_IsValid(int value) {
+  switch(value) {
+    case 0:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Struct::kFieldsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Struct::Struct()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Struct)
+}
+
+void Struct::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Struct::Struct(const Struct& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Struct)
+}
+
+void Struct::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  fields_.SetAssignDescriptorCallback(
+      protobuf_AssignDescriptorsOnce);
+  fields_.SetEntryDescriptor(
+      &::google::protobuf::Struct_FieldsEntry_descriptor_);
+}
+
+Struct::~Struct() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Struct)
+  SharedDtor();
+}
+
+void Struct::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void Struct::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Struct::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Struct_descriptor_;
+}
+
+const Struct& Struct::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  return *default_instance_;
+}
+
+Struct* Struct::default_instance_ = NULL;
+
+Struct* Struct::New(::google::protobuf::Arena* arena) const {
+  Struct* n = new Struct;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Struct::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Struct)
+  fields_.Clear();
+}
+
+bool Struct::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Struct)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // map<string, .google.protobuf.Value> fields = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_fields:
+          ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry(fields_.NewEntry());
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+              input, entry.get()));
+          (*mutable_fields())[entry->key()].Swap(entry->mutable_value());
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            entry->key().data(), entry->key().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Struct.FieldsEntry.key"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_fields;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Struct)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Struct)
+  return false;
+#undef DO_
+}
+
+void Struct::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Struct)
+  // map<string, .google.protobuf.Value> fields = 1;
+  {
+    ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
+      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
+      ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+          1, *entry, output);
+      ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+        it->first.data(), it->first.length(),
+        ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+        "google.protobuf.Struct.FieldsEntry.key");
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Struct)
+}
+
+::google::protobuf::uint8* Struct::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
+  // map<string, .google.protobuf.Value> fields = 1;
+  {
+    ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
+      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
+      target = ::google::protobuf::internal::WireFormatLite::
+          WriteMessageNoVirtualToArray(
+              1, *entry, target);
+      ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+        it->first.data(), it->first.length(),
+        ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+        "google.protobuf.Struct.FieldsEntry.key");
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Struct)
+  return target;
+}
+
+int Struct::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct)
+  int total_size = 0;
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  total_size += 1 * this->fields_size();
+  {
+    ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
+      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
+      total_size += ::google::protobuf::internal::WireFormatLite::
+          MessageSizeNoVirtual(*entry);
+    }
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Struct::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Struct)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Struct* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Struct>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Struct)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Struct)
+    MergeFrom(*source);
+  }
+}
+
+void Struct::MergeFrom(const Struct& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  fields_.MergeFrom(from.fields_);
+}
+
+void Struct::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Struct)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Struct::CopyFrom(const Struct& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Struct)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Struct::IsInitialized() const {
+
+  return true;
+}
+
+void Struct::Swap(Struct* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Struct::InternalSwap(Struct* other) {
+  fields_.Swap(&other->fields_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Struct::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Struct_descriptor_;
+  metadata.reflection = Struct_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Struct
+
+// map<string, .google.protobuf.Value> fields = 1;
+int Struct::fields_size() const {
+  return fields_.size();
+}
+void Struct::clear_fields() {
+  fields_.Clear();
+}
+ const ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >&
+Struct::fields() const {
+  // @@protoc_insertion_point(field_map:google.protobuf.Struct.fields)
+  return fields_.GetMap();
+}
+ ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >*
+Struct::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_map:google.protobuf.Struct.fields)
+  return fields_.MutableMap();
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Value::kNullValueFieldNumber;
+const int Value::kNumberValueFieldNumber;
+const int Value::kStringValueFieldNumber;
+const int Value::kBoolValueFieldNumber;
+const int Value::kStructValueFieldNumber;
+const int Value::kListValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Value::Value()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Value)
+}
+
+void Value::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+  Value_default_oneof_instance_->null_value_ = 0;
+  Value_default_oneof_instance_->number_value_ = 0;
+  Value_default_oneof_instance_->string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  Value_default_oneof_instance_->bool_value_ = false;
+  Value_default_oneof_instance_->struct_value_ = const_cast< ::google::protobuf::Struct*>(&::google::protobuf::Struct::default_instance());
+  Value_default_oneof_instance_->list_value_ = const_cast< ::google::protobuf::ListValue*>(&::google::protobuf::ListValue::default_instance());
+}
+
+Value::Value(const Value& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Value)
+}
+
+void Value::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  clear_has_kind();
+}
+
+Value::~Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Value)
+  SharedDtor();
+}
+
+void Value::SharedDtor() {
+  if (has_kind()) {
+    clear_kind();
+  }
+  if (this != default_instance_) {
+  }
+}
+
+void Value::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Value::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Value_descriptor_;
+}
+
+const Value& Value::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  return *default_instance_;
+}
+
+Value* Value::default_instance_ = NULL;
+
+Value* Value::New(::google::protobuf::Arena* arena) const {
+  Value* n = new Value;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Value::clear_kind() {
+// @@protoc_insertion_point(one_of_clear_start:google.protobuf.Value)
+  switch(kind_case()) {
+    case kNullValue: {
+      // No need to clear
+      break;
+    }
+    case kNumberValue: {
+      // No need to clear
+      break;
+    }
+    case kStringValue: {
+      kind_.string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+      break;
+    }
+    case kBoolValue: {
+      // No need to clear
+      break;
+    }
+    case kStructValue: {
+      delete kind_.struct_value_;
+      break;
+    }
+    case kListValue: {
+      delete kind_.list_value_;
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  _oneof_case_[0] = KIND_NOT_SET;
+}
+
+
+void Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Value)
+  clear_kind();
+}
+
+bool Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Value)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .google.protobuf.NullValue null_value = 1;
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_null_value(static_cast< ::google::protobuf::NullValue >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(17)) goto parse_number_value;
+        break;
+      }
+
+      // optional double number_value = 2;
+      case 2: {
+        if (tag == 17) {
+         parse_number_value:
+          clear_kind();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, &kind_.number_value_)));
+          set_has_number_value();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_string_value;
+        break;
+      }
+
+      // optional string string_value = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_string_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_string_value()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->string_value().data(), this->string_value().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Value.string_value"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_bool_value;
+        break;
+      }
+
+      // optional bool bool_value = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_bool_value:
+          clear_kind();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &kind_.bool_value_)));
+          set_has_bool_value();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_struct_value;
+        break;
+      }
+
+      // optional .google.protobuf.Struct struct_value = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_struct_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_struct_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_list_value;
+        break;
+      }
+
+      // optional .google.protobuf.ListValue list_value = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_list_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_list_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Value)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Value)
+  return false;
+#undef DO_
+}
+
+void Value::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Value)
+  // optional .google.protobuf.NullValue null_value = 1;
+  if (has_null_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->null_value(), output);
+  }
+
+  // optional double number_value = 2;
+  if (has_number_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteDouble(2, this->number_value(), output);
+  }
+
+  // optional string string_value = 3;
+  if (has_string_value()) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->string_value().data(), this->string_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Value.string_value");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      3, this->string_value(), output);
+  }
+
+  // optional bool bool_value = 4;
+  if (has_bool_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->bool_value(), output);
+  }
+
+  // optional .google.protobuf.Struct struct_value = 5;
+  if (has_struct_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      5, *kind_.struct_value_, output);
+  }
+
+  // optional .google.protobuf.ListValue list_value = 6;
+  if (has_list_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, *kind_.list_value_, output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Value)
+}
+
+::google::protobuf::uint8* Value::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
+  // optional .google.protobuf.NullValue null_value = 1;
+  if (has_null_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->null_value(), target);
+  }
+
+  // optional double number_value = 2;
+  if (has_number_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(2, this->number_value(), target);
+  }
+
+  // optional string string_value = 3;
+  if (has_string_value()) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->string_value().data(), this->string_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Value.string_value");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        3, this->string_value(), target);
+  }
+
+  // optional bool bool_value = 4;
+  if (has_bool_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(4, this->bool_value(), target);
+  }
+
+  // optional .google.protobuf.Struct struct_value = 5;
+  if (has_struct_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        5, *kind_.struct_value_, target);
+  }
+
+  // optional .google.protobuf.ListValue list_value = 6;
+  if (has_list_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        6, *kind_.list_value_, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
+  return target;
+}
+
+int Value::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value)
+  int total_size = 0;
+
+  switch (kind_case()) {
+    // optional .google.protobuf.NullValue null_value = 1;
+    case kNullValue: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->null_value());
+      break;
+    }
+    // optional double number_value = 2;
+    case kNumberValue: {
+      total_size += 1 + 8;
+      break;
+    }
+    // optional string string_value = 3;
+    case kStringValue: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->string_value());
+      break;
+    }
+    // optional bool bool_value = 4;
+    case kBoolValue: {
+      total_size += 1 + 1;
+      break;
+    }
+    // optional .google.protobuf.Struct struct_value = 5;
+    case kStructValue: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *kind_.struct_value_);
+      break;
+    }
+    // optional .google.protobuf.ListValue list_value = 6;
+    case kListValue: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *kind_.list_value_);
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Value::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Value>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Value)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Value)
+    MergeFrom(*source);
+  }
+}
+
+void Value::MergeFrom(const Value& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  switch (from.kind_case()) {
+    case kNullValue: {
+      set_null_value(from.null_value());
+      break;
+    }
+    case kNumberValue: {
+      set_number_value(from.number_value());
+      break;
+    }
+    case kStringValue: {
+      set_string_value(from.string_value());
+      break;
+    }
+    case kBoolValue: {
+      set_bool_value(from.bool_value());
+      break;
+    }
+    case kStructValue: {
+      mutable_struct_value()->::google::protobuf::Struct::MergeFrom(from.struct_value());
+      break;
+    }
+    case kListValue: {
+      mutable_list_value()->::google::protobuf::ListValue::MergeFrom(from.list_value());
+      break;
+    }
+    case KIND_NOT_SET: {
+      break;
+    }
+  }
+}
+
+void Value::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Value::CopyFrom(const Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Value::IsInitialized() const {
+
+  return true;
+}
+
+void Value::Swap(Value* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Value::InternalSwap(Value* other) {
+  std::swap(kind_, other->kind_);
+  std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Value::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Value_descriptor_;
+  metadata.reflection = Value_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Value
+
+// optional .google.protobuf.NullValue null_value = 1;
+bool Value::has_null_value() const {
+  return kind_case() == kNullValue;
+}
+void Value::set_has_null_value() {
+  _oneof_case_[0] = kNullValue;
+}
+void Value::clear_null_value() {
+  if (has_null_value()) {
+    kind_.null_value_ = 0;
+    clear_has_kind();
+  }
+}
+ ::google::protobuf::NullValue Value::null_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.null_value)
+  if (has_null_value()) {
+    return static_cast< ::google::protobuf::NullValue >(kind_.null_value_);
+  }
+  return static_cast< ::google::protobuf::NullValue >(0);
+}
+ void Value::set_null_value(::google::protobuf::NullValue value) {
+  if (!has_null_value()) {
+    clear_kind();
+    set_has_null_value();
+  }
+  kind_.null_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.null_value)
+}
+
+// optional double number_value = 2;
+bool Value::has_number_value() const {
+  return kind_case() == kNumberValue;
+}
+void Value::set_has_number_value() {
+  _oneof_case_[0] = kNumberValue;
+}
+void Value::clear_number_value() {
+  if (has_number_value()) {
+    kind_.number_value_ = 0;
+    clear_has_kind();
+  }
+}
+ double Value::number_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.number_value)
+  if (has_number_value()) {
+    return kind_.number_value_;
+  }
+  return 0;
+}
+ void Value::set_number_value(double value) {
+  if (!has_number_value()) {
+    clear_kind();
+    set_has_number_value();
+  }
+  kind_.number_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.number_value)
+}
+
+// optional string string_value = 3;
+bool Value::has_string_value() const {
+  return kind_case() == kStringValue;
+}
+void Value::set_has_string_value() {
+  _oneof_case_[0] = kStringValue;
+}
+void Value::clear_string_value() {
+  if (has_string_value()) {
+    kind_.string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    clear_has_kind();
+  }
+}
+ const ::std::string& Value::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.string_value)
+  if (has_string_value()) {
+    return kind_.string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+ void Value::set_string_value(const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+}
+ void Value::set_string_value(const char* value) {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Value.string_value)
+}
+ void Value::set_string_value(const char* value, size_t size) {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Value.string_value)
+}
+ ::std::string* Value::mutable_string_value() {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.string_value)
+  return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Value::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value)
+  if (has_string_value()) {
+    clear_has_kind();
+    return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  } else {
+    return NULL;
+  }
+}
+ void Value::set_allocated_string_value(::std::string* string_value) {
+  if (!has_string_value()) {
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_kind();
+  if (string_value != NULL) {
+    set_has_string_value();
+    kind_.string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        string_value);
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.string_value)
+}
+
+// optional bool bool_value = 4;
+bool Value::has_bool_value() const {
+  return kind_case() == kBoolValue;
+}
+void Value::set_has_bool_value() {
+  _oneof_case_[0] = kBoolValue;
+}
+void Value::clear_bool_value() {
+  if (has_bool_value()) {
+    kind_.bool_value_ = false;
+    clear_has_kind();
+  }
+}
+ bool Value::bool_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.bool_value)
+  if (has_bool_value()) {
+    return kind_.bool_value_;
+  }
+  return false;
+}
+ void Value::set_bool_value(bool value) {
+  if (!has_bool_value()) {
+    clear_kind();
+    set_has_bool_value();
+  }
+  kind_.bool_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.bool_value)
+}
+
+// optional .google.protobuf.Struct struct_value = 5;
+bool Value::has_struct_value() const {
+  return kind_case() == kStructValue;
+}
+void Value::set_has_struct_value() {
+  _oneof_case_[0] = kStructValue;
+}
+void Value::clear_struct_value() {
+  if (has_struct_value()) {
+    delete kind_.struct_value_;
+    clear_has_kind();
+  }
+}
+ const ::google::protobuf::Struct& Value::struct_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value)
+  return has_struct_value()
+      ? *kind_.struct_value_
+      : ::google::protobuf::Struct::default_instance();
+}
+::google::protobuf::Struct* Value::mutable_struct_value() {
+  if (!has_struct_value()) {
+    clear_kind();
+    set_has_struct_value();
+    kind_.struct_value_ = new ::google::protobuf::Struct;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.struct_value)
+  return kind_.struct_value_;
+}
+::google::protobuf::Struct* Value::release_struct_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value)
+  if (has_struct_value()) {
+    clear_has_kind();
+    ::google::protobuf::Struct* temp = kind_.struct_value_;
+    kind_.struct_value_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+void Value::set_allocated_struct_value(::google::protobuf::Struct* struct_value) {
+  clear_kind();
+  if (struct_value) {
+    set_has_struct_value();
+    kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.struct_value)
+}
+
+// optional .google.protobuf.ListValue list_value = 6;
+bool Value::has_list_value() const {
+  return kind_case() == kListValue;
+}
+void Value::set_has_list_value() {
+  _oneof_case_[0] = kListValue;
+}
+void Value::clear_list_value() {
+  if (has_list_value()) {
+    delete kind_.list_value_;
+    clear_has_kind();
+  }
+}
+ const ::google::protobuf::ListValue& Value::list_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value)
+  return has_list_value()
+      ? *kind_.list_value_
+      : ::google::protobuf::ListValue::default_instance();
+}
+::google::protobuf::ListValue* Value::mutable_list_value() {
+  if (!has_list_value()) {
+    clear_kind();
+    set_has_list_value();
+    kind_.list_value_ = new ::google::protobuf::ListValue;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.list_value)
+  return kind_.list_value_;
+}
+::google::protobuf::ListValue* Value::release_list_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value)
+  if (has_list_value()) {
+    clear_has_kind();
+    ::google::protobuf::ListValue* temp = kind_.list_value_;
+    kind_.list_value_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+void Value::set_allocated_list_value(::google::protobuf::ListValue* list_value) {
+  clear_kind();
+  if (list_value) {
+    set_has_list_value();
+    kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
+}
+
+bool Value::has_kind() const {
+  return kind_case() != KIND_NOT_SET;
+}
+void Value::clear_has_kind() {
+  _oneof_case_[0] = KIND_NOT_SET;
+}
+Value::KindCase Value::kind_case() const {
+  return Value::KindCase(_oneof_case_[0]);
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ListValue::kValuesFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ListValue::ListValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.ListValue)
+}
+
+void ListValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+ListValue::ListValue(const ListValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.ListValue)
+}
+
+void ListValue::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+}
+
+ListValue::~ListValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.ListValue)
+  SharedDtor();
+}
+
+void ListValue::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void ListValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ListValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ListValue_descriptor_;
+}
+
+const ListValue& ListValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  return *default_instance_;
+}
+
+ListValue* ListValue::default_instance_ = NULL;
+
+ListValue* ListValue::New(::google::protobuf::Arena* arena) const {
+  ListValue* n = new ListValue;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ListValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.ListValue)
+  values_.Clear();
+}
+
+bool ListValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.ListValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .google.protobuf.Value values = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_values:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_values()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_values;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.ListValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.ListValue)
+  return false;
+#undef DO_
+}
+
+void ListValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.ListValue)
+  // repeated .google.protobuf.Value values = 1;
+  for (unsigned int i = 0, n = this->values_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->values(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.ListValue)
+}
+
+::google::protobuf::uint8* ListValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
+  // repeated .google.protobuf.Value values = 1;
+  for (unsigned int i = 0, n = this->values_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        1, this->values(i), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
+  return target;
+}
+
+int ListValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue)
+  int total_size = 0;
+
+  // repeated .google.protobuf.Value values = 1;
+  total_size += 1 * this->values_size();
+  for (int i = 0; i < this->values_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->values(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ListValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ListValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ListValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ListValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ListValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ListValue)
+    MergeFrom(*source);
+  }
+}
+
+void ListValue::MergeFrom(const ListValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  values_.MergeFrom(from.values_);
+}
+
+void ListValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ListValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ListValue::CopyFrom(const ListValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ListValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool ListValue::IsInitialized() const {
+
+  return true;
+}
+
+void ListValue::Swap(ListValue* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ListValue::InternalSwap(ListValue* other) {
+  values_.UnsafeArenaSwap(&other->values_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ListValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ListValue_descriptor_;
+  metadata.reflection = ListValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ListValue
+
+// repeated .google.protobuf.Value values = 1;
+int ListValue::values_size() const {
+  return values_.size();
+}
+void ListValue::clear_values() {
+  values_.Clear();
+}
+const ::google::protobuf::Value& ListValue::values(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ListValue.values)
+  return values_.Get(index);
+}
+::google::protobuf::Value* ListValue::mutable_values(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ListValue.values)
+  return values_.Mutable(index);
+}
+::google::protobuf::Value* ListValue::add_values() {
+  // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values)
+  return values_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >*
+ListValue::mutable_values() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values)
+  return &values_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >&
+ListValue::values() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values)
+  return values_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
new file mode 100644
index 0000000..6a4764a
--- /dev/null
+++ b/src/google/protobuf/struct.pb.h
@@ -0,0 +1,769 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fstruct_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fstruct_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto();
+
+class ListValue;
+class Struct;
+class Value;
+
+enum NullValue {
+  NULL_VALUE = 0,
+  NullValue_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,
+  NullValue_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max
+};
+LIBPROTOBUF_EXPORT bool NullValue_IsValid(int value);
+const NullValue NullValue_MIN = NULL_VALUE;
+const NullValue NullValue_MAX = NULL_VALUE;
+const int NullValue_ARRAYSIZE = NullValue_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* NullValue_descriptor();
+inline const ::std::string& NullValue_Name(NullValue value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    NullValue_descriptor(), value);
+}
+inline bool NullValue_Parse(
+    const ::std::string& name, NullValue* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<NullValue>(
+    NullValue_descriptor(), name, value);
+}
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message {
+ public:
+  Struct();
+  virtual ~Struct();
+
+  Struct(const Struct& from);
+
+  inline Struct& operator=(const Struct& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Struct& default_instance();
+
+  void Swap(Struct* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Struct* New() const { return New(NULL); }
+
+  Struct* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Struct& from);
+  void MergeFrom(const Struct& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Struct* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  // map<string, .google.protobuf.Value> fields = 1;
+  int fields_size() const;
+  void clear_fields();
+  static const int kFieldsFieldNumber = 1;
+  const ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >&
+      fields() const;
+  ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >*
+      mutable_fields();
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Struct)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  typedef ::google::protobuf::internal::MapEntryLite<
+      ::std::string, ::google::protobuf::Value,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 >
+      Struct_FieldsEntry;
+  ::google::protobuf::internal::MapField<
+      ::std::string, ::google::protobuf::Value,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 > fields_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto();
+
+  void InitAsDefaultInstance();
+  static Struct* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message {
+ public:
+  Value();
+  virtual ~Value();
+
+  Value(const Value& from);
+
+  inline Value& operator=(const Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Value& default_instance();
+
+  enum KindCase {
+    kNullValue = 1,
+    kNumberValue = 2,
+    kStringValue = 3,
+    kBoolValue = 4,
+    kStructValue = 5,
+    kListValue = 6,
+    KIND_NOT_SET = 0,
+  };
+
+  void Swap(Value* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Value* New() const { return New(NULL); }
+
+  Value* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Value& from);
+  void MergeFrom(const Value& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Value* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .google.protobuf.NullValue null_value = 1;
+  private:
+  bool has_null_value() const;
+  public:
+  void clear_null_value();
+  static const int kNullValueFieldNumber = 1;
+  ::google::protobuf::NullValue null_value() const;
+  void set_null_value(::google::protobuf::NullValue value);
+
+  // optional double number_value = 2;
+  private:
+  bool has_number_value() const;
+  public:
+  void clear_number_value();
+  static const int kNumberValueFieldNumber = 2;
+  double number_value() const;
+  void set_number_value(double value);
+
+  // optional string string_value = 3;
+  private:
+  bool has_string_value() const;
+  public:
+  void clear_string_value();
+  static const int kStringValueFieldNumber = 3;
+  const ::std::string& string_value() const;
+  void set_string_value(const ::std::string& value);
+  void set_string_value(const char* value);
+  void set_string_value(const char* value, size_t size);
+  ::std::string* mutable_string_value();
+  ::std::string* release_string_value();
+  void set_allocated_string_value(::std::string* string_value);
+
+  // optional bool bool_value = 4;
+  private:
+  bool has_bool_value() const;
+  public:
+  void clear_bool_value();
+  static const int kBoolValueFieldNumber = 4;
+  bool bool_value() const;
+  void set_bool_value(bool value);
+
+  // optional .google.protobuf.Struct struct_value = 5;
+  bool has_struct_value() const;
+  void clear_struct_value();
+  static const int kStructValueFieldNumber = 5;
+  const ::google::protobuf::Struct& struct_value() const;
+  ::google::protobuf::Struct* mutable_struct_value();
+  ::google::protobuf::Struct* release_struct_value();
+  void set_allocated_struct_value(::google::protobuf::Struct* struct_value);
+
+  // optional .google.protobuf.ListValue list_value = 6;
+  bool has_list_value() const;
+  void clear_list_value();
+  static const int kListValueFieldNumber = 6;
+  const ::google::protobuf::ListValue& list_value() const;
+  ::google::protobuf::ListValue* mutable_list_value();
+  ::google::protobuf::ListValue* release_list_value();
+  void set_allocated_list_value(::google::protobuf::ListValue* list_value);
+
+  KindCase kind_case() const;
+  // @@protoc_insertion_point(class_scope:google.protobuf.Value)
+ private:
+  inline void set_has_null_value();
+  inline void set_has_number_value();
+  inline void set_has_string_value();
+  inline void set_has_bool_value();
+  inline void set_has_struct_value();
+  inline void set_has_list_value();
+
+  inline bool has_kind() const;
+  void clear_kind();
+  inline void clear_has_kind();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  union KindUnion {
+    KindUnion() {}
+    int null_value_;
+    double number_value_;
+    ::google::protobuf::internal::ArenaStringPtr string_value_;
+    bool bool_value_;
+    ::google::protobuf::Struct* struct_value_;
+    ::google::protobuf::ListValue* list_value_;
+  } kind_;
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _oneof_case_[1];
+
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto();
+
+  void InitAsDefaultInstance();
+  static Value* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message {
+ public:
+  ListValue();
+  virtual ~ListValue();
+
+  ListValue(const ListValue& from);
+
+  inline ListValue& operator=(const ListValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ListValue& default_instance();
+
+  void Swap(ListValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ListValue* New() const { return New(NULL); }
+
+  ListValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ListValue& from);
+  void MergeFrom(const ListValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ListValue* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .google.protobuf.Value values = 1;
+  int values_size() const;
+  void clear_values();
+  static const int kValuesFieldNumber = 1;
+  const ::google::protobuf::Value& values(int index) const;
+  ::google::protobuf::Value* mutable_values(int index);
+  ::google::protobuf::Value* add_values();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >*
+      mutable_values();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >&
+      values() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.ListValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value > values_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto();
+
+  void InitAsDefaultInstance();
+  static ListValue* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Struct
+
+// map<string, .google.protobuf.Value> fields = 1;
+inline int Struct::fields_size() const {
+  return fields_.size();
+}
+inline void Struct::clear_fields() {
+  fields_.Clear();
+}
+inline const ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >&
+Struct::fields() const {
+  // @@protoc_insertion_point(field_map:google.protobuf.Struct.fields)
+  return fields_.GetMap();
+}
+inline ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >*
+Struct::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_map:google.protobuf.Struct.fields)
+  return fields_.MutableMap();
+}
+
+// -------------------------------------------------------------------
+
+// Value
+
+// optional .google.protobuf.NullValue null_value = 1;
+inline bool Value::has_null_value() const {
+  return kind_case() == kNullValue;
+}
+inline void Value::set_has_null_value() {
+  _oneof_case_[0] = kNullValue;
+}
+inline void Value::clear_null_value() {
+  if (has_null_value()) {
+    kind_.null_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline ::google::protobuf::NullValue Value::null_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.null_value)
+  if (has_null_value()) {
+    return static_cast< ::google::protobuf::NullValue >(kind_.null_value_);
+  }
+  return static_cast< ::google::protobuf::NullValue >(0);
+}
+inline void Value::set_null_value(::google::protobuf::NullValue value) {
+  if (!has_null_value()) {
+    clear_kind();
+    set_has_null_value();
+  }
+  kind_.null_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.null_value)
+}
+
+// optional double number_value = 2;
+inline bool Value::has_number_value() const {
+  return kind_case() == kNumberValue;
+}
+inline void Value::set_has_number_value() {
+  _oneof_case_[0] = kNumberValue;
+}
+inline void Value::clear_number_value() {
+  if (has_number_value()) {
+    kind_.number_value_ = 0;
+    clear_has_kind();
+  }
+}
+inline double Value::number_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.number_value)
+  if (has_number_value()) {
+    return kind_.number_value_;
+  }
+  return 0;
+}
+inline void Value::set_number_value(double value) {
+  if (!has_number_value()) {
+    clear_kind();
+    set_has_number_value();
+  }
+  kind_.number_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.number_value)
+}
+
+// optional string string_value = 3;
+inline bool Value::has_string_value() const {
+  return kind_case() == kStringValue;
+}
+inline void Value::set_has_string_value() {
+  _oneof_case_[0] = kStringValue;
+}
+inline void Value::clear_string_value() {
+  if (has_string_value()) {
+    kind_.string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    clear_has_kind();
+  }
+}
+inline const ::std::string& Value::string_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.string_value)
+  if (has_string_value()) {
+    return kind_.string_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void Value::set_string_value(const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
+}
+inline void Value::set_string_value(const char* value) {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Value.string_value)
+}
+inline void Value::set_string_value(const char* value, size_t size) {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  kind_.string_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Value.string_value)
+}
+inline ::std::string* Value::mutable_string_value() {
+  if (!has_string_value()) {
+    clear_kind();
+    set_has_string_value();
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.string_value)
+  return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Value::release_string_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value)
+  if (has_string_value()) {
+    clear_has_kind();
+    return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  } else {
+    return NULL;
+  }
+}
+inline void Value::set_allocated_string_value(::std::string* string_value) {
+  if (!has_string_value()) {
+    kind_.string_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_kind();
+  if (string_value != NULL) {
+    set_has_string_value();
+    kind_.string_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        string_value);
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.string_value)
+}
+
+// optional bool bool_value = 4;
+inline bool Value::has_bool_value() const {
+  return kind_case() == kBoolValue;
+}
+inline void Value::set_has_bool_value() {
+  _oneof_case_[0] = kBoolValue;
+}
+inline void Value::clear_bool_value() {
+  if (has_bool_value()) {
+    kind_.bool_value_ = false;
+    clear_has_kind();
+  }
+}
+inline bool Value::bool_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.bool_value)
+  if (has_bool_value()) {
+    return kind_.bool_value_;
+  }
+  return false;
+}
+inline void Value::set_bool_value(bool value) {
+  if (!has_bool_value()) {
+    clear_kind();
+    set_has_bool_value();
+  }
+  kind_.bool_value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Value.bool_value)
+}
+
+// optional .google.protobuf.Struct struct_value = 5;
+inline bool Value::has_struct_value() const {
+  return kind_case() == kStructValue;
+}
+inline void Value::set_has_struct_value() {
+  _oneof_case_[0] = kStructValue;
+}
+inline void Value::clear_struct_value() {
+  if (has_struct_value()) {
+    delete kind_.struct_value_;
+    clear_has_kind();
+  }
+}
+inline  const ::google::protobuf::Struct& Value::struct_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value)
+  return has_struct_value()
+      ? *kind_.struct_value_
+      : ::google::protobuf::Struct::default_instance();
+}
+inline ::google::protobuf::Struct* Value::mutable_struct_value() {
+  if (!has_struct_value()) {
+    clear_kind();
+    set_has_struct_value();
+    kind_.struct_value_ = new ::google::protobuf::Struct;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.struct_value)
+  return kind_.struct_value_;
+}
+inline ::google::protobuf::Struct* Value::release_struct_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value)
+  if (has_struct_value()) {
+    clear_has_kind();
+    ::google::protobuf::Struct* temp = kind_.struct_value_;
+    kind_.struct_value_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline void Value::set_allocated_struct_value(::google::protobuf::Struct* struct_value) {
+  clear_kind();
+  if (struct_value) {
+    set_has_struct_value();
+    kind_.struct_value_ = struct_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.struct_value)
+}
+
+// optional .google.protobuf.ListValue list_value = 6;
+inline bool Value::has_list_value() const {
+  return kind_case() == kListValue;
+}
+inline void Value::set_has_list_value() {
+  _oneof_case_[0] = kListValue;
+}
+inline void Value::clear_list_value() {
+  if (has_list_value()) {
+    delete kind_.list_value_;
+    clear_has_kind();
+  }
+}
+inline  const ::google::protobuf::ListValue& Value::list_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value)
+  return has_list_value()
+      ? *kind_.list_value_
+      : ::google::protobuf::ListValue::default_instance();
+}
+inline ::google::protobuf::ListValue* Value::mutable_list_value() {
+  if (!has_list_value()) {
+    clear_kind();
+    set_has_list_value();
+    kind_.list_value_ = new ::google::protobuf::ListValue;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Value.list_value)
+  return kind_.list_value_;
+}
+inline ::google::protobuf::ListValue* Value::release_list_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value)
+  if (has_list_value()) {
+    clear_has_kind();
+    ::google::protobuf::ListValue* temp = kind_.list_value_;
+    kind_.list_value_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline void Value::set_allocated_list_value(::google::protobuf::ListValue* list_value) {
+  clear_kind();
+  if (list_value) {
+    set_has_list_value();
+    kind_.list_value_ = list_value;
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
+}
+
+inline bool Value::has_kind() const {
+  return kind_case() != KIND_NOT_SET;
+}
+inline void Value::clear_has_kind() {
+  _oneof_case_[0] = KIND_NOT_SET;
+}
+inline Value::KindCase Value::kind_case() const {
+  return Value::KindCase(_oneof_case_[0]);
+}
+// -------------------------------------------------------------------
+
+// ListValue
+
+// repeated .google.protobuf.Value values = 1;
+inline int ListValue::values_size() const {
+  return values_.size();
+}
+inline void ListValue::clear_values() {
+  values_.Clear();
+}
+inline const ::google::protobuf::Value& ListValue::values(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.ListValue.values)
+  return values_.Get(index);
+}
+inline ::google::protobuf::Value* ListValue::mutable_values(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.ListValue.values)
+  return values_.Mutable(index);
+}
+inline ::google::protobuf::Value* ListValue::add_values() {
+  // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values)
+  return values_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >*
+ListValue::mutable_values() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values)
+  return &values_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >&
+ListValue::values() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values)
+  return values_;
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <> struct is_proto_enum< ::google::protobuf::NullValue> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::NullValue>() {
+  return ::google::protobuf::NullValue_descriptor();
+}
+
+}  // namespace protobuf
+}  // namespace google
+#endif  // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fstruct_2eproto__INCLUDED
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
new file mode 100644
index 0000000..beeba81
--- /dev/null
+++ b/src/google/protobuf/struct.proto
@@ -0,0 +1,96 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+//
+// The JSON representation for `Struct` is JSON object.
+message Struct {
+  // Unordered map of dynamically typed values.
+  map<string, Value> fields = 1;
+}
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of that
+// variants, absence of any variant indicates an error.
+//
+// The JSON representation for `Value` is JSON value.
+message Value {
+  // The kind of value.
+  oneof kind {
+    // Represents a null value.
+    NullValue null_value = 1;
+    // Represents a double value.
+    double number_value = 2;
+    // Represents a string value.
+    string string_value = 3;
+    // Represents a boolean value.
+    bool bool_value = 4;
+    // Represents a structured value.
+    Struct struct_value = 5;
+    // Represents a repeated `Value`.
+    ListValue list_value = 6;
+  }
+}
+
+// `NullValue` is a singleton enumeration to represent the null value for the
+// `Value` type union.
+//
+//  The JSON representation for `NullValue` is JSON `null`.
+enum NullValue {
+  // Null value.
+  NULL_VALUE = 0;
+}
+
+// `ListValue` is a wrapper around a repeated field of values.
+//
+// The JSON representation for `ListValue` is JSON array.
+message ListValue {
+  // Repeated field of dynamically typed values.
+  repeated Value values = 1;
+}
diff --git a/src/google/protobuf/stubs/atomic_sequence_num.h b/src/google/protobuf/stubs/atomic_sequence_num.h
new file mode 100644
index 0000000..bb20942
--- /dev/null
+++ b/src/google/protobuf/stubs/atomic_sequence_num.h
@@ -0,0 +1,54 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+#ifndef GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_
+#define GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_
+
+#include <google/protobuf/stubs/atomicops.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class SequenceNumber {
+ public:
+  SequenceNumber() : word_(0) {}
+
+  AtomicWord GetNext() {
+    return NoBarrier_AtomicIncrement(&word_, 1) - 1;
+  }
+ private:
+  AtomicWord word_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ATOMIC_SEQUENCE_NUM_H_
diff --git a/src/google/protobuf/stubs/atomicops.h b/src/google/protobuf/stubs/atomicops.h
index b1336e3..9b3d1e6 100644
--- a/src/google/protobuf/stubs/atomicops.h
+++ b/src/google/protobuf/stubs/atomicops.h
@@ -56,17 +56,27 @@
 // Don't include this file for people not concerned about thread safety.
 #ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
 
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/platform_macros.h>
 
 namespace google {
 namespace protobuf {
 namespace internal {
 
+#if defined(GOOGLE_PROTOBUF_ARCH_POWER)
+#if defined(_LP64) || defined(__LP64__)
+typedef int32 Atomic32;
+typedef intptr_t Atomic64;
+#else
+typedef intptr_t Atomic32;
+typedef int64 Atomic64;
+#endif
+#else
 typedef int32 Atomic32;
 #ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
 // We need to be able to go between Atomic64 and AtomicWord implicitly.  This
 // means Atomic64 and AtomicWord should be the same type on 64-bit.
-#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) || defined(GOOGLE_PROTOBUF_ARCH_SPARC)
+#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL)
 // NaCl's intptr_t is not actually 64-bits on 64-bit!
 // http://code.google.com/p/nativeclient/issues/detail?id=1162
 // sparcv9's pointer type is 32bits
@@ -75,6 +85,7 @@
 typedef intptr_t Atomic64;
 #endif
 #endif
+#endif
 
 // Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
 // Atomic64 routines below, depending on your architecture.
@@ -162,7 +173,7 @@
 
 // Include our platform specific implementation.
 #define GOOGLE_PROTOBUF_ATOMICOPS_ERROR \
-#error "Atomic operations are not supported on your platform"
+"Atomic operations are not supported on your platform"
 
 // ThreadSanitizer, http://clang.llvm.org/docs/ThreadSanitizer.html.
 #if defined(THREAD_SANITIZER)
@@ -172,13 +183,17 @@
 #if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
 #include <google/protobuf/stubs/atomicops_internals_x86_msvc.h>
 #else
-GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#error GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 #endif
 
 // Solaris
 #elif defined(GOOGLE_PROTOBUF_OS_SOLARIS)
 #include <google/protobuf/stubs/atomicops_internals_solaris.h>
 
+// AIX
+#elif defined(GOOGLE_PROTOBUF_OS_AIX)
+#include <google/protobuf/stubs/atomicops_internals_power.h>
+
 // Apple.
 #elif defined(GOOGLE_PROTOBUF_OS_APPLE)
 #include <google/protobuf/stubs/atomicops_internals_macosx.h>
@@ -195,23 +210,27 @@
 #include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64)
 #include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_POWER)
+#include <google/protobuf/stubs/atomicops_internals_power.h>
 #elif defined(__native_client__)
 #include <google/protobuf/stubs/atomicops_internals_pnacl.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_PPC)
+#include <google/protobuf/stubs/atomicops_internals_ppc_gcc.h>
 #elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
 #include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
 #elif defined(__clang__)
 #if __has_extension(c_atomic)
 #include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
 #else
-GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#error GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 #endif
 #else
-GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#error GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 #endif
 
 // Unknown.
 #else
-GOOGLE_PROTOBUF_ATOMICOPS_ERROR
+#error GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 #endif
 
 // On some platforms we need additional declarations to make AtomicWord
diff --git a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
index dd7abf6..a0116a6 100644
--- a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
+++ b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
@@ -61,8 +61,8 @@
 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                        Atomic32 old_value,
                                        Atomic32 new_value) {
-  __atomic_compare_exchange(ptr, &old_value, &new_value, true,
-                            __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+  __atomic_compare_exchange_n(ptr, &old_value, new_value, true,
+                              __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
   return old_value;
 }
 
diff --git a/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
index e3cd14c..f5837c9 100644
--- a/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
+++ b/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
@@ -65,7 +65,7 @@
                        "2:\n"
                        ".set pop\n"
                        : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
                        : "memory");
   return prev;
 }
@@ -197,7 +197,7 @@
                        "2:\n"
                        ".set pop\n"
                        : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
-                       : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
                        : "memory");
   return prev;
 }
diff --git a/src/google/protobuf/stubs/atomicops_internals_pnacl.h b/src/google/protobuf/stubs/atomicops_internals_pnacl.h
index b10ac02..3b314fd 100644
--- a/src/google/protobuf/stubs/atomicops_internals_pnacl.h
+++ b/src/google/protobuf/stubs/atomicops_internals_pnacl.h
@@ -33,39 +33,197 @@
 #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
 #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
 
+#include <atomic>
+
 namespace google {
 namespace protobuf {
 namespace internal {
 
+// This implementation is transitional and maintains the original API for
+// atomicops.h. This requires casting memory locations to the atomic types, and
+// assumes that the API and the C++11 implementation are layout-compatible,
+// which isn't true for all implementations or hardware platforms. The static
+// assertion should detect this issue, were it to fire then this header
+// shouldn't be used.
+//
+// TODO(jfb) If this header manages to stay committed then the API should be
+//           modified, and all call sites updated.
+typedef volatile std::atomic<Atomic32>* AtomicLocation32;
+static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
+              "incompatible 32-bit atomic layout");
+
+inline void MemoryBarrier() {
+#if defined(__GLIBCXX__)
+  // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
+  // not defined, leading to the linker complaining about undefined references.
+  __atomic_thread_fence(std::memory_order_seq_cst);
+#else
+  std::atomic_thread_fence(std::memory_order_seq_cst);
+#endif
+}
+
 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
                                          Atomic32 old_value,
                                          Atomic32 new_value) {
-  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
 }
 
-inline void MemoryBarrier() {
-  __sync_synchronize();
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  return ((AtomicLocation32)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return increment +
+         ((AtomicLocation32)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
 }
 
 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                        Atomic32 old_value,
                                        Atomic32 new_value) {
-  Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
   MemoryBarrier();
-  return ret;
 }
 
 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
-  MemoryBarrier();
-  *ptr = value;
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
 }
 
 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
-  Atomic32 value = *ptr;
-  MemoryBarrier();
-  return value;
+  return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
 }
 
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+#if defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
+
+typedef volatile std::atomic<Atomic64>* AtomicLocation64;
+static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
+              "incompatible 64-bit atomic layout");
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  return ((AtomicLocation64)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return increment +
+         ((AtomicLocation64)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+#endif  // defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/stubs/atomicops_internals_power.h b/src/google/protobuf/stubs/atomicops_internals_power.h
new file mode 100644
index 0000000..b8a42f2
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_power.h
@@ -0,0 +1,440 @@
+// Copyright 2014 Bloomberg Finance LP. All rights reserved.
+//
+// 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 Bloomberg Finance LP. 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.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 result;
+
+  asm volatile (
+      "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpw %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+      "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
+      "       bne- 1b                         \n\t"
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 result;
+
+  asm volatile (
+      "1:     lwarx %[res], %[zero], %[obj]       \n\t"
+      "       stwcx. %[val], %[zero], %[obj]      \n\t"
+      "       bne- 1b                             \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 result;
+
+  asm volatile (
+      "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       add %[res], %[val], %[res]      \n\t"  // add the operand
+      "       stwcx. %[res], %[zero], %[obj]  \n\t"  // store old value
+                                                     // if still reserved
+      "       bne- 1b                         \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (increment),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline void MemoryBarrier(void) {
+  asm volatile (
+      "       lwsync                          \n\t"
+      "       isync                           \n\t"
+              :
+              :
+              : "memory");
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  Atomic32 result;
+
+  asm volatile (
+      "       lwsync                          \n\t"
+
+      "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       add %[res], %[val], %[res]      \n\t"  // add the operand
+      "       stwcx. %[res], %[zero], %[obj]  \n\t"  // store old value
+                                                     // if still reserved
+      "       bne- 1b                         \n\t"
+      "       isync                           \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (increment),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 result;
+
+  asm volatile (
+      "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpw %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+      "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
+      "       bne- 1b                         \n\t"
+
+      "       isync                           \n\t"
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 result;
+
+  asm volatile (
+      "       lwsync                          \n\t"
+
+      "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpw %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+      "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
+      "       bne- 1b                         \n\t"
+
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  asm volatile (
+      "       stw %[val], %[obj]      \n\t"
+      "       isync                   \n\t"
+              : [obj] "=m" (*ptr)
+              : [val]  "b"  (value));
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  asm volatile (
+      "       lwsync                  \n\t"
+      "       stw %[val], %[obj]      \n\t"
+              : [obj] "=m" (*ptr)
+              : [val]  "b"  (value));
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 result;
+
+  asm volatile (
+      "1:     lwz %[res], %[obj]              \n\t"
+      "       cmpw %[res], %[res]             \n\t" // create data
+                                                    // dependency for
+                                                    // load/load ordering
+      "       bne- 1b                         \n\t" // never taken
+
+      "       isync                           \n\t"
+              : [res]  "=b" (result)
+              : [obj]  "m"  (*ptr),
+                [zero] "i"  (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  Atomic32 result;
+
+  asm volatile (
+      "       lwsync                          \n\t"
+
+      "1:     lwz %[res], %[obj]              \n\t"
+      "       cmpw %[res], %[res]             \n\t" // create data
+                                                    // dependency for
+                                                    // load/load ordering
+      "       bne- 1b                         \n\t" // never taken
+              : [res]  "=b" (result)
+              : [obj]  "m"  (*ptr),
+                [zero] "i"  (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 result;
+
+  asm volatile (
+      "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpd %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+
+      "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
+      "       bne- 1b                         \n\t"
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 result;
+
+  asm volatile (
+      "1:     ldarx %[res], %[zero], %[obj]       \n\t"
+      "       stdcx. %[val], %[zero], %[obj]      \n\t"
+      "       bne- 1b                             \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 result;
+
+  asm volatile (
+      "1:     ldarx %[res], %[zero], %[obj]   \n\t" // load and reserve
+      "       add %[res], %[res], %[val]      \n\t" // add the operand
+      "       stdcx. %[res], %[zero], %[obj]  \n\t" // store old value if
+                                                    // still reserved
+
+      "       bne- 1b                         \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (increment),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+
+  Atomic64 result;
+
+  asm volatile (
+      "       lwsync                          \n\t"
+
+      "1:     ldarx %[res], %[zero], %[obj]   \n\t" // load and reserve
+      "       add %[res], %[res], %[val]      \n\t" // add the operand
+      "       stdcx. %[res], %[zero], %[obj]  \n\t" // store old value if
+                                                    // still reserved
+
+      "       bne- 1b                         \n\t"
+
+      "       isync                           \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [val]  "b"   (increment),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 result;
+
+  asm volatile (
+      "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpd %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+
+      "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
+      "       bne- 1b                         \n\t"
+      "       isync                           \n\t"
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 result;
+
+  asm volatile (
+      "       lwsync                          \n\t"
+
+      "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
+      "       cmpd %[cmp], %[res]             \n\t"  // compare values
+      "       bne- 2f                         \n\t"
+
+      "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
+      "       bne- 1b                         \n\t"
+      "2:                                     \n\t"
+              : [res]  "=&b" (result)
+              : [obj]  "b"   (ptr),
+                [cmp]  "b"   (old_value),
+                [val]  "b"   (new_value),
+                [zero] "i"   (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  asm volatile (
+      "       std %[val], %[obj]          \n\t"
+      "       isync                       \n\t"
+              : [obj] "=m" (*ptr)
+              : [val] "b"  (value));
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  asm volatile (
+      "       lwsync                      \n\t"
+      "       std %[val], %[obj]          \n\t"
+              : [obj] "=m" (*ptr)
+              : [val] "b"  (value));
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 result;
+
+  asm volatile (
+      "1:     ld %[res], %[obj]                   \n\t"
+      "       cmpd %[res], %[res]                 \n\t" // create data
+                                                        // dependency for
+                                                        // load/load ordering
+      "       bne- 1b                             \n\t" // never taken
+
+      "       isync                               \n\t"
+              : [res]  "=b" (result)
+              : [obj]  "m"  (*ptr),
+                [zero] "i"  (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  Atomic64 result;
+
+  asm volatile (
+      "       lwsync                              \n\t"
+
+      "1:     ld %[res], %[obj]                   \n\t"
+      "       cmpd %[res], %[res]                 \n\t" // create data
+                                                        // dependency for
+                                                        // load/load ordering
+      "       bne- 1b                             \n\t" // never taken
+              : [res]  "=b" (result)
+              : [obj]  "m"  (*ptr),
+                [zero] "i"  (0)
+              : "cr0", "ctr");
+
+  return result;
+}
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
diff --git a/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h
new file mode 100644
index 0000000..8231a57
--- /dev/null
+++ b/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h
@@ -0,0 +1,155 @@
+// 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.
+
+// Author: ogabbay@advaoptical.com (Oded Gabbay)
+// Cleaned up by: bsilver16384@gmail.com (Brian Silverman)
+//
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+
+  __asm__ __volatile__(
+      "0:                                  \n\t"
+      "lwarx %[prev],0,%[ptr]              \n\t"
+      "cmpw 0,%[prev],%[old_value]         \n\t"
+      "bne- 1f                             \n\t"
+      "stwcx. %[new_value],0,%[ptr]        \n\t"
+      "bne- 0b                             \n\t"
+      "1:                                  \n\t"
+      : [prev] "=&r"(prev), "+m"(*ptr)
+      : [ptr] "r"(ptr), [old_value] "r"(old_value), [new_value] "r"(new_value)
+      : "cc", "memory");
+
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old;
+
+  __asm__ __volatile__(
+      "0:                                  \n\t"
+      "lwarx %[old],0,%[ptr]               \n\t"
+      "stwcx. %[new_value],0,%[ptr]        \n\t"
+      "bne- 0b                             \n\t"
+      : [old] "=&r"(old), "+m"(*ptr)
+      : [ptr] "r"(ptr), [new_value] "r"(new_value)
+      : "cc", "memory");
+
+  return old;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp;
+
+  __asm__ __volatile__(
+      "0:                                  \n\t"
+      "lwarx %[temp],0,%[ptr]              \n\t"
+      "add %[temp],%[increment],%[temp]    \n\t"
+      "stwcx. %[temp],0,%[ptr]             \n\t"
+      "bne- 0b                             \n\t"
+      : [temp] "=&r"(temp)
+      : [increment] "r"(increment), [ptr] "r"(ptr)
+      : "cc", "memory");
+
+  return temp;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value, Atomic32 new_value) {
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value, Atomic32 new_value) {
+  MemoryBarrier();
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  return res;
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() { __asm__ __volatile__("sync" : : : "memory"); }
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) { return *ptr; }
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PPC_GCC_H_
diff --git a/src/google/protobuf/stubs/bytestream.cc b/src/google/protobuf/stubs/bytestream.cc
new file mode 100644
index 0000000..f4af6a5
--- /dev/null
+++ b/src/google/protobuf/stubs/bytestream.cc
@@ -0,0 +1,196 @@
+// 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.
+
+#include <google/protobuf/stubs/bytestream.h>
+
+#include <string.h>
+#include <algorithm>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+void ByteSource::CopyTo(ByteSink* sink, size_t n) {
+  while (n > 0) {
+    StringPiece fragment = Peek();
+    if (fragment.empty()) {
+      GOOGLE_LOG(DFATAL) << "ByteSource::CopyTo() overran input.";
+      break;
+    }
+    std::size_t fragment_size = std::min<std::size_t>(n, fragment.size());
+    sink->Append(fragment.data(), fragment_size);
+    Skip(fragment_size);
+    n -= fragment_size;
+  }
+}
+
+void ByteSink::Flush() {}
+
+void UncheckedArrayByteSink::Append(const char* data, size_t n) {
+  if (data != dest_) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    GOOGLE_DCHECK(!(dest_ <= data && data < (dest_ + n)))
+        << "Append() data[] overlaps with dest_[]";
+    memcpy(dest_, data, n);
+  }
+  dest_ += n;
+}
+
+CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, size_t capacity)
+    : outbuf_(outbuf), capacity_(capacity), size_(0), overflowed_(false) {
+}
+
+void CheckedArrayByteSink::Append(const char* bytes, size_t n) {
+  size_t available = capacity_ - size_;
+  if (n > available) {
+    n = available;
+    overflowed_ = true;
+  }
+  if (n > 0 && bytes != (outbuf_ + size_)) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    GOOGLE_DCHECK(!(outbuf_ <= bytes && bytes < (outbuf_ + capacity_)))
+        << "Append() bytes[] overlaps with outbuf_[]";
+    memcpy(outbuf_ + size_, bytes, n);
+  }
+  size_ += n;
+}
+
+GrowingArrayByteSink::GrowingArrayByteSink(size_t estimated_size)
+    : capacity_(estimated_size),
+      buf_(new char[estimated_size]),
+      size_(0) {
+}
+
+GrowingArrayByteSink::~GrowingArrayByteSink() {
+  delete[] buf_;  // Just in case the user didn't call GetBuffer.
+}
+
+void GrowingArrayByteSink::Append(const char* bytes, size_t n) {
+  size_t available = capacity_ - size_;
+  if (bytes != (buf_ + size_)) {
+    // Catch cases where the pointer returned by GetAppendBuffer() was modified.
+    // We need to test for this before calling Expand() which may reallocate.
+    GOOGLE_DCHECK(!(buf_ <= bytes && bytes < (buf_ + capacity_)))
+        << "Append() bytes[] overlaps with buf_[]";
+  }
+  if (n > available) {
+    Expand(n - available);
+  }
+  if (n > 0 && bytes != (buf_ + size_)) {
+    memcpy(buf_ + size_, bytes, n);
+  }
+  size_ += n;
+}
+
+char* GrowingArrayByteSink::GetBuffer(size_t* nbytes) {
+  ShrinkToFit();
+  char* b = buf_;
+  *nbytes = size_;
+  buf_ = NULL;
+  size_ = capacity_ = 0;
+  return b;
+}
+
+void GrowingArrayByteSink::Expand(size_t amount) {  // Expand by at least 50%.
+  size_t new_capacity = std::max(capacity_ + amount, (3 * capacity_) / 2);
+  char* bigger = new char[new_capacity];
+  memcpy(bigger, buf_, size_);
+  delete[] buf_;
+  buf_ = bigger;
+  capacity_ = new_capacity;
+}
+
+void GrowingArrayByteSink::ShrinkToFit() {
+  // Shrink only if the buffer is large and size_ is less than 3/4
+  // of capacity_.
+  if (capacity_ > 256 && size_ < (3 * capacity_) / 4) {
+    char* just_enough = new char[size_];
+    memcpy(just_enough, buf_, size_);
+    delete[] buf_;
+    buf_ = just_enough;
+    capacity_ = size_;
+  }
+}
+
+void StringByteSink::Append(const char* data, size_t n) {
+  dest_->append(data, n);
+}
+
+size_t ArrayByteSource::Available() const {
+  return input_.size();
+}
+
+StringPiece ArrayByteSource::Peek() {
+  return input_;
+}
+
+void ArrayByteSource::Skip(size_t n) {
+  GOOGLE_DCHECK_LE(n, input_.size());
+  input_.remove_prefix(n);
+}
+
+LimitByteSource::LimitByteSource(ByteSource *source, size_t limit)
+  : source_(source),
+    limit_(limit) {
+}
+
+size_t LimitByteSource::Available() const {
+  size_t available = source_->Available();
+  if (available > limit_) {
+    available = limit_;
+  }
+
+  return available;
+}
+
+StringPiece LimitByteSource::Peek() {
+  StringPiece piece(source_->Peek());
+  if (piece.size() > limit_) {
+    piece.set(piece.data(), limit_);
+  }
+
+  return piece;
+}
+
+void LimitByteSource::Skip(size_t n) {
+  GOOGLE_DCHECK_LE(n, limit_);
+  source_->Skip(n);
+  limit_ -= n;
+}
+
+void LimitByteSource::CopyTo(ByteSink *sink, size_t n) {
+  GOOGLE_DCHECK_LE(n, limit_);
+  source_->CopyTo(sink, n);
+  limit_ -= n;
+}
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/bytestream.h b/src/google/protobuf/stubs/bytestream.h
new file mode 100644
index 0000000..de8e020
--- /dev/null
+++ b/src/google/protobuf/stubs/bytestream.h
@@ -0,0 +1,348 @@
+// 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.
+
+// This file declares the ByteSink and ByteSource abstract interfaces. These
+// interfaces represent objects that consume (ByteSink) or produce (ByteSource)
+// a sequence of bytes. Using these abstract interfaces in your APIs can help
+// make your code work with a variety of input and output types.
+//
+// This file also declares the following commonly used implementations of these
+// interfaces.
+//
+//   ByteSink:
+//      UncheckedArrayByteSink  Writes to an array, without bounds checking
+//      CheckedArrayByteSink    Writes to an array, with bounds checking
+//      GrowingArrayByteSink    Allocates and writes to a growable buffer
+//      StringByteSink          Writes to an STL string
+//      NullByteSink            Consumes a never-ending stream of bytes
+//
+//   ByteSource:
+//      ArrayByteSource         Reads from an array or string/StringPiece
+//      LimitedByteSource       Limits the number of bytes read from an
+
+#ifndef GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
+#define GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
+
+#include <stddef.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+class CordByteSink;
+class MemBlock;
+
+namespace google {
+namespace protobuf {
+namespace strings {
+
+// An abstract interface for an object that consumes a sequence of bytes. This
+// interface offers 3 different ways to append data, and a Flush() function.
+//
+// Example:
+//
+//   string my_data;
+//   ...
+//   ByteSink* sink = ...
+//   sink->Append(my_data.data(), my_data.size());
+//   sink->Flush();
+//
+class LIBPROTOBUF_EXPORT ByteSink {
+ public:
+  ByteSink() {}
+  virtual ~ByteSink() {}
+
+  // Appends the "n" bytes starting at "bytes".
+  virtual void Append(const char* bytes, size_t n) = 0;
+
+  // Flushes internal buffers. The default implemenation does nothing. ByteSink
+  // subclasses may use internal buffers that require calling Flush() at the end
+  // of the stream.
+  virtual void Flush();
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSink);
+};
+
+// An abstract interface for an object that produces a fixed-size sequence of
+// bytes.
+//
+// Example:
+//
+//   ByteSource* source = ...
+//   while (source->Available() > 0) {
+//     StringPiece data = source->Peek();
+//     ... do something with "data" ...
+//     source->Skip(data.length());
+//   }
+//
+class LIBPROTOBUF_EXPORT ByteSource {
+ public:
+  ByteSource() {}
+  virtual ~ByteSource() {}
+
+  // Returns the number of bytes left to read from the source. Available()
+  // should decrease by N each time Skip(N) is called. Available() may not
+  // increase. Available() returning 0 indicates that the ByteSource is
+  // exhausted.
+  //
+  // Note: Size() may have been a more appropriate name as it's more
+  //       indicative of the fixed-size nature of a ByteSource.
+  virtual size_t Available() const = 0;
+
+  // Returns a StringPiece of the next contiguous region of the source. Does not
+  // reposition the source. The returned region is empty iff Available() == 0.
+  //
+  // The returned region is valid until the next call to Skip() or until this
+  // object is destroyed, whichever occurs first.
+  //
+  // The length of the returned StringPiece will be <= Available().
+  virtual StringPiece Peek() = 0;
+
+  // Skips the next n bytes. Invalidates any StringPiece returned by a previous
+  // call to Peek().
+  //
+  // REQUIRES: Available() >= n
+  virtual void Skip(size_t n) = 0;
+
+  // Writes the next n bytes in this ByteSource to the given ByteSink, and
+  // advances this ByteSource past the copied bytes. The default implementation
+  // of this method just copies the bytes normally, but subclasses might
+  // override CopyTo to optimize certain cases.
+  //
+  // REQUIRES: Available() >= n
+  virtual void CopyTo(ByteSink* sink, size_t n);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSource);
+};
+
+//
+// Some commonly used implementations of ByteSink
+//
+
+// Implementation of ByteSink that writes to an unsized byte array. No
+// bounds-checking is performed--it is the caller's responsibility to ensure
+// that the destination array is large enough.
+//
+// Example:
+//
+//   char buf[10];
+//   UncheckedArrayByteSink sink(buf);
+//   sink.Append("hi", 2);    // OK
+//   sink.Append(data, 100);  // WOOPS! Overflows buf[10].
+//
+class LIBPROTOBUF_EXPORT UncheckedArrayByteSink : public ByteSink {
+ public:
+  explicit UncheckedArrayByteSink(char* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n);
+
+  // Returns the current output pointer so that a caller can see how many bytes
+  // were produced.
+  //
+  // Note: this method is not part of the ByteSink interface.
+  char* CurrentDestination() const { return dest_; }
+
+ private:
+  char* dest_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UncheckedArrayByteSink);
+};
+
+// Implementation of ByteSink that writes to a sized byte array. This sink will
+// not write more than "capacity" bytes to outbuf. Once "capacity" bytes are
+// appended, subsequent bytes will be ignored and Overflowed() will return true.
+// Overflowed() does not cause a runtime error (i.e., it does not CHECK fail).
+//
+// Example:
+//
+//   char buf[10];
+//   CheckedArrayByteSink sink(buf, 10);
+//   sink.Append("hi", 2);    // OK
+//   sink.Append(data, 100);  // Will only write 8 more bytes
+//
+class LIBPROTOBUF_EXPORT CheckedArrayByteSink : public ByteSink {
+ public:
+  CheckedArrayByteSink(char* outbuf, size_t capacity);
+  virtual void Append(const char* bytes, size_t n);
+
+  // Returns the number of bytes actually written to the sink.
+  size_t NumberOfBytesWritten() const { return size_; }
+
+  // Returns true if any bytes were discarded, i.e., if there was an
+  // attempt to write more than 'capacity' bytes.
+  bool Overflowed() const { return overflowed_; }
+
+ private:
+  char* outbuf_;
+  const size_t capacity_;
+  size_t size_;
+  bool overflowed_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CheckedArrayByteSink);
+};
+
+// Implementation of ByteSink that allocates an internal buffer (a char array)
+// and expands it as needed to accomodate appended data (similar to a string),
+// and allows the caller to take ownership of the internal buffer via the
+// GetBuffer() method. The buffer returned from GetBuffer() must be deleted by
+// the caller with delete[]. GetBuffer() also sets the internal buffer to be
+// empty, and subsequent appends to the sink will create a new buffer. The
+// destructor will free the internal buffer if GetBuffer() was not called.
+//
+// Example:
+//
+//   GrowingArrayByteSink sink(10);
+//   sink.Append("hi", 2);
+//   sink.Append(data, n);
+//   const char* buf = sink.GetBuffer();  // Ownership transferred
+//   delete[] buf;
+//
+class LIBPROTOBUF_EXPORT GrowingArrayByteSink : public strings::ByteSink {
+ public:
+  explicit GrowingArrayByteSink(size_t estimated_size);
+  virtual ~GrowingArrayByteSink();
+  virtual void Append(const char* bytes, size_t n);
+
+  // Returns the allocated buffer, and sets nbytes to its size. The caller takes
+  // ownership of the buffer and must delete it with delete[].
+  char* GetBuffer(size_t* nbytes);
+
+ private:
+  void Expand(size_t amount);
+  void ShrinkToFit();
+
+  size_t capacity_;
+  char* buf_;
+  size_t size_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GrowingArrayByteSink);
+};
+
+// Implementation of ByteSink that appends to the given string.
+// Existing contents of "dest" are not modified; new data is appended.
+//
+// Example:
+//
+//   string dest = "Hello ";
+//   StringByteSink sink(&dest);
+//   sink.Append("World", 5);
+//   assert(dest == "Hello World");
+//
+class LIBPROTOBUF_EXPORT StringByteSink : public ByteSink {
+ public:
+  explicit StringByteSink(string* dest) : dest_(dest) {}
+  virtual void Append(const char* data, size_t n);
+
+ private:
+  string* dest_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringByteSink);
+};
+
+// Implementation of ByteSink that discards all data.
+//
+// Example:
+//
+//   NullByteSink sink;
+//   sink.Append(data, data.size());  // All data ignored.
+//
+class LIBPROTOBUF_EXPORT NullByteSink : public ByteSink {
+ public:
+  NullByteSink() {}
+  virtual void Append(const char *data, size_t n) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NullByteSink);
+};
+
+//
+// Some commonly used implementations of ByteSource
+//
+
+// Implementation of ByteSource that reads from a StringPiece.
+//
+// Example:
+//
+//   string data = "Hello";
+//   ArrayByteSource source(data);
+//   assert(source.Available() == 5);
+//   assert(source.Peek() == "Hello");
+//
+class LIBPROTOBUF_EXPORT ArrayByteSource : public ByteSource {
+ public:
+  explicit ArrayByteSource(StringPiece s) : input_(s) {}
+
+  virtual size_t Available() const;
+  virtual StringPiece Peek();
+  virtual void Skip(size_t n);
+
+ private:
+  StringPiece   input_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayByteSource);
+};
+
+// Implementation of ByteSource that wraps another ByteSource, limiting the
+// number of bytes returned.
+//
+// The caller maintains ownership of the underlying source, and may not use the
+// underlying source while using the LimitByteSource object.  The underlying
+// source's pointer is advanced by n bytes every time this LimitByteSource
+// object is advanced by n.
+//
+// Example:
+//
+//   string data = "Hello World";
+//   ArrayByteSource abs(data);
+//   assert(abs.Available() == data.size());
+//
+//   LimitByteSource limit(abs, 5);
+//   assert(limit.Available() == 5);
+//   assert(limit.Peek() == "Hello");
+//
+class LIBPROTOBUF_EXPORT LimitByteSource : public ByteSource {
+ public:
+  // Returns at most "limit" bytes from "source".
+  LimitByteSource(ByteSource* source, size_t limit);
+
+  virtual size_t Available() const;
+  virtual StringPiece Peek();
+  virtual void Skip(size_t n);
+
+  // We override CopyTo so that we can forward to the underlying source, in
+  // case it has an efficient implementation of CopyTo.
+  virtual void CopyTo(ByteSink* sink, size_t n);
+
+ private:
+  ByteSource* source_;
+  size_t limit_;
+};
+
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
diff --git a/src/google/protobuf/stubs/bytestream_unittest.cc b/src/google/protobuf/stubs/bytestream_unittest.cc
new file mode 100644
index 0000000..06f114a
--- /dev/null
+++ b/src/google/protobuf/stubs/bytestream_unittest.cc
@@ -0,0 +1,146 @@
+// 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.
+
+#include <google/protobuf/stubs/bytestream.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace strings {
+namespace {
+
+// We use this class instead of ArrayByteSource to simulate a ByteSource that
+// contains multiple fragments.  ArrayByteSource returns the entire array in
+// one fragment.
+class MockByteSource : public ByteSource {
+ public:
+  MockByteSource(StringPiece data, int block_size)
+    : data_(data), block_size_(block_size) {}
+
+  size_t Available() const { return data_.size(); }
+  StringPiece Peek() {
+    return data_.substr(0, block_size_);
+  }
+  void Skip(size_t n) { data_.remove_prefix(n); }
+
+ private:
+  StringPiece data_;
+  int block_size_;
+};
+
+TEST(ByteSourceTest, CopyTo) {
+  StringPiece data("Hello world!");
+  MockByteSource source(data, 3);
+  string str;
+  StringByteSink sink(&str);
+
+  source.CopyTo(&sink, data.size());
+  EXPECT_EQ(data, str);
+}
+
+TEST(ByteSourceTest, CopySubstringTo) {
+  StringPiece data("Hello world!");
+  MockByteSource source(data, 3);
+  source.Skip(1);
+  string str;
+  StringByteSink sink(&str);
+
+  source.CopyTo(&sink, data.size() - 2);
+  EXPECT_EQ(data.substr(1, data.size() - 2), str);
+  EXPECT_EQ("!", source.Peek());
+}
+
+TEST(ByteSourceTest, LimitByteSource) {
+  StringPiece data("Hello world!");
+  MockByteSource source(data, 3);
+  LimitByteSource limit_source(&source, 6);
+  EXPECT_EQ(6, limit_source.Available());
+  limit_source.Skip(1);
+  EXPECT_EQ(5, limit_source.Available());
+
+  {
+    string str;
+    StringByteSink sink(&str);
+    limit_source.CopyTo(&sink, limit_source.Available());
+    EXPECT_EQ("ello ", str);
+    EXPECT_EQ(0, limit_source.Available());
+    EXPECT_EQ(6, source.Available());
+  }
+
+  {
+    string str;
+    StringByteSink sink(&str);
+    source.CopyTo(&sink, source.Available());
+    EXPECT_EQ("world!", str);
+    EXPECT_EQ(0, source.Available());
+  }
+}
+
+TEST(ByteSourceTest, CopyToStringByteSink) {
+  StringPiece data("Hello world!");
+  MockByteSource source(data, 3);
+  string str;
+  StringByteSink sink(&str);
+  source.CopyTo(&sink, data.size());
+  EXPECT_EQ(data, str);
+}
+
+// Verify that ByteSink is subclassable and Flush() overridable.
+class FlushingByteSink : public StringByteSink {
+ public:
+  explicit FlushingByteSink(string* dest) : StringByteSink(dest) {}
+  virtual void Flush() { Append("z", 1); }
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FlushingByteSink);
+};
+
+// Write and Flush via the ByteSink superclass interface.
+void WriteAndFlush(ByteSink* s) {
+  s->Append("abc", 3);
+  s->Flush();
+}
+
+TEST(ByteSinkTest, Flush) {
+  string str;
+  FlushingByteSink f_sink(&str);
+  WriteAndFlush(&f_sink);
+  EXPECT_STREQ("abcz", str.c_str());
+}
+
+}  // namespace
+}  // namespace strings
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
new file mode 100644
index 0000000..87271c5
--- /dev/null
+++ b/src/google/protobuf/stubs/callback.h
@@ -0,0 +1,546 @@
+#ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+#define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/type_traits.h>
+
+// ===================================================================
+// emulates google3/base/callback.h
+
+namespace google {
+namespace protobuf {
+
+// Abstract interface for a callback.  When calling an RPC, you must provide
+// a Closure to call when the procedure completes.  See the Service interface
+// in service.h.
+//
+// To automatically construct a Closure which calls a particular function or
+// method with a particular set of parameters, use the NewCallback() function.
+// Example:
+//   void FooDone(const FooResponse* response) {
+//     ...
+//   }
+//
+//   void CallFoo() {
+//     ...
+//     // When done, call FooDone() and pass it a pointer to the response.
+//     Closure* callback = NewCallback(&FooDone, response);
+//     // Make the call.
+//     service->Foo(controller, request, response, callback);
+//   }
+//
+// Example that calls a method:
+//   class Handler {
+//    public:
+//     ...
+//
+//     void FooDone(const FooResponse* response) {
+//       ...
+//     }
+//
+//     void CallFoo() {
+//       ...
+//       // When done, call FooDone() and pass it a pointer to the response.
+//       Closure* callback = NewCallback(this, &Handler::FooDone, response);
+//       // Make the call.
+//       service->Foo(controller, request, response, callback);
+//     }
+//   };
+//
+// Currently NewCallback() supports binding zero, one, or two arguments.
+//
+// Callbacks created with NewCallback() automatically delete themselves when
+// executed.  They should be used when a callback is to be called exactly
+// once (usually the case with RPC callbacks).  If a callback may be called
+// a different number of times (including zero), create it with
+// NewPermanentCallback() instead.  You are then responsible for deleting the
+// callback (using the "delete" keyword as normal).
+//
+// Note that NewCallback() is a bit touchy regarding argument types.  Generally,
+// the values you provide for the parameter bindings must exactly match the
+// types accepted by the callback function.  For example:
+//   void Foo(string s);
+//   NewCallback(&Foo, "foo");          // WON'T WORK:  const char* != string
+//   NewCallback(&Foo, string("foo"));  // WORKS
+// Also note that the arguments cannot be references:
+//   void Foo(const string& s);
+//   string my_str;
+//   NewCallback(&Foo, my_str);  // WON'T WORK:  Can't use referecnes.
+// However, correctly-typed pointers will work just fine.
+class LIBPROTOBUF_EXPORT Closure {
+ public:
+  Closure() {}
+  virtual ~Closure();
+
+  virtual void Run() = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
+};
+
+template<typename R>
+class ResultCallback {
+ public:
+  ResultCallback() {}
+  virtual ~ResultCallback() {}
+
+  virtual R Run() = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
+};
+
+template<typename R, typename A1>
+class LIBPROTOBUF_EXPORT ResultCallback1 {
+ public:
+  ResultCallback1() {}
+  virtual ~ResultCallback1() {}
+
+  virtual R Run(A1) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback1);
+};
+
+template<typename R, typename A1, typename A2>
+class LIBPROTOBUF_EXPORT ResultCallback2 {
+ public:
+  ResultCallback2() {}
+  virtual ~ResultCallback2() {}
+
+  virtual R Run(A1,A2) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback2);
+};
+
+namespace internal {
+
+class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure {
+ public:
+  typedef void (*FunctionType)();
+
+  FunctionClosure0(FunctionType function, bool self_deleting)
+    : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionClosure0();
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_();
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template <typename Class>
+class MethodClosure0 : public Closure {
+ public:
+  typedef void (Class::*MethodType)();
+
+  MethodClosure0(Class* object, MethodType method, bool self_deleting)
+    : object_(object), method_(method), self_deleting_(self_deleting) {}
+  ~MethodClosure0() {}
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)();
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+};
+
+template <typename Arg1>
+class FunctionClosure1 : public Closure {
+ public:
+  typedef void (*FunctionType)(Arg1 arg1);
+
+  FunctionClosure1(FunctionType function, bool self_deleting,
+                   Arg1 arg1)
+    : function_(function), self_deleting_(self_deleting),
+      arg1_(arg1) {}
+  ~FunctionClosure1() {}
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_(arg1_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  Arg1 arg1_;
+};
+
+template <typename Class, typename Arg1>
+class MethodClosure1 : public Closure {
+ public:
+  typedef void (Class::*MethodType)(Arg1 arg1);
+
+  MethodClosure1(Class* object, MethodType method, bool self_deleting,
+                 Arg1 arg1)
+    : object_(object), method_(method), self_deleting_(self_deleting),
+      arg1_(arg1) {}
+  ~MethodClosure1() {}
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)(arg1_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+  Arg1 arg1_;
+};
+
+template <typename Arg1, typename Arg2>
+class FunctionClosure2 : public Closure {
+ public:
+  typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2);
+
+  FunctionClosure2(FunctionType function, bool self_deleting,
+                   Arg1 arg1, Arg2 arg2)
+    : function_(function), self_deleting_(self_deleting),
+      arg1_(arg1), arg2_(arg2) {}
+  ~FunctionClosure2() {}
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    function_(arg1_, arg2_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template <typename Class, typename Arg1, typename Arg2>
+class MethodClosure2 : public Closure {
+ public:
+  typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2);
+
+  MethodClosure2(Class* object, MethodType method, bool self_deleting,
+                 Arg1 arg1, Arg2 arg2)
+    : object_(object), method_(method), self_deleting_(self_deleting),
+      arg1_(arg1), arg2_(arg2) {}
+  ~MethodClosure2() {}
+
+  void Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    (object_->*method_)(arg1_, arg2_);
+    if (needs_delete) delete this;
+  }
+
+ private:
+  Class* object_;
+  MethodType method_;
+  bool self_deleting_;
+  Arg1 arg1_;
+  Arg2 arg2_;
+};
+
+template<typename R>
+class FunctionResultCallback_0_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)();
+
+  FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
+      : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionResultCallback_0_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_();
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template<typename R, typename P1>
+class FunctionResultCallback_1_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)(P1);
+
+  FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
+                             P1 p1)
+      : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+  ~FunctionResultCallback_1_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(p1_);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  P1 p1_;
+};
+
+template<typename R, typename Arg1>
+class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
+ public:
+  typedef R (*FunctionType)(Arg1 arg1);
+
+  FunctionResultCallback_0_1(FunctionType function, bool self_deleting)
+      : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionResultCallback_0_1() {}
+
+  R Run(Arg1 a1) {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(a1);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template<typename R, typename P1, typename A1>
+class FunctionResultCallback_1_1 : public ResultCallback1<R, A1> {
+ public:
+  typedef R (*FunctionType)(P1, A1);
+
+  FunctionResultCallback_1_1(FunctionType function, bool self_deleting,
+                             P1 p1)
+      : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+  ~FunctionResultCallback_1_1() {}
+
+  R Run(A1 a1) {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(p1_, a1);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  P1 p1_;
+};
+
+template <typename T>
+struct InternalConstRef {
+  typedef typename remove_reference<T>::type base_type;
+  typedef const base_type& type;
+};
+
+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> {
+ public:
+  typedef R (T::*MethodType)(P1, P2, P3, P4, P5, A1, A2);
+  MethodResultCallback_5_2(T* object, MethodType method, bool self_deleting,
+                           P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+      : object_(object),
+        method_(method),
+        self_deleting_(self_deleting),
+        p1_(p1),
+        p2_(p2),
+        p3_(p3),
+        p4_(p4),
+        p5_(p5) {}
+  ~MethodResultCallback_5_2() {}
+
+  R Run(A1 a1, A2 a2) {
+    bool needs_delete = self_deleting_;
+    R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, a1, a2);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  T* object_;
+  MethodType method_;
+  bool self_deleting_;
+  typename remove_reference<P1>::type p1_;
+  typename remove_reference<P2>::type p2_;
+  typename remove_reference<P3>::type p3_;
+  typename remove_reference<P4>::type p4_;
+  typename remove_reference<P5>::type p5_;
+};
+
+// See Closure.
+inline Closure* NewCallback(void (*function)()) {
+  return new internal::FunctionClosure0(function, true);
+}
+
+// See Closure.
+inline Closure* NewPermanentCallback(void (*function)()) {
+  return new internal::FunctionClosure0(function, false);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewCallback(Class* object, void (Class::*method)()) {
+  return new internal::MethodClosure0<Class>(object, method, true);
+}
+
+// See Closure.
+template <typename Class>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
+  return new internal::MethodClosure0<Class>(object, method, false);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewCallback(void (*function)(Arg1),
+                            Arg1 arg1) {
+  return new internal::FunctionClosure1<Arg1>(function, true, arg1);
+}
+
+// See Closure.
+template <typename Arg1>
+inline Closure* NewPermanentCallback(void (*function)(Arg1),
+                                     Arg1 arg1) {
+  return new internal::FunctionClosure1<Arg1>(function, false, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
+                            Arg1 arg1) {
+  return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
+}
+
+// See Closure.
+template <typename Class, typename Arg1>
+inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
+                                     Arg1 arg1) {
+  return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewCallback(void (*function)(Arg1, Arg2),
+                            Arg1 arg1, Arg2 arg2) {
+  return new internal::FunctionClosure2<Arg1, Arg2>(
+    function, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
+                                     Arg1 arg1, Arg2 arg2) {
+  return new internal::FunctionClosure2<Arg1, Arg2>(
+    function, false, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
+                            Arg1 arg1, Arg2 arg2) {
+  return new internal::MethodClosure2<Class, Arg1, Arg2>(
+    object, method, true, arg1, arg2);
+}
+
+// See Closure.
+template <typename Class, typename Arg1, typename Arg2>
+inline Closure* NewPermanentCallback(
+    Class* object, void (Class::*method)(Arg1, Arg2),
+    Arg1 arg1, Arg2 arg2) {
+  return new internal::MethodClosure2<Class, Arg1, Arg2>(
+    object, method, false, arg1, arg2);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, true);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, false);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, true, p1);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewPermanentCallback(
+    R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, false, p1);
+}
+
+// See ResultCallback1
+template<typename R, typename A1>
+inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
+  return new internal::FunctionResultCallback_0_1<R, A1>(function, true);
+}
+
+// See ResultCallback1
+template<typename R, typename A1>
+inline ResultCallback1<R, A1>* NewPermanentCallback(R (*function)(A1)) {
+  return new internal::FunctionResultCallback_0_1<R, A1>(function, false);
+}
+
+// See ResultCallback1
+template<typename R, typename P1, typename A1>
+inline ResultCallback1<R, A1>* NewCallback(R (*function)(P1, A1), P1 p1) {
+  return new internal::FunctionResultCallback_1_1<R, P1, A1>(
+      function, true, p1);
+}
+
+// See ResultCallback1
+template<typename R, typename P1, typename A1>
+inline ResultCallback1<R, A1>* NewPermanentCallback(
+    R (*function)(P1, A1), P1 p1) {
+  return new internal::FunctionResultCallback_1_1<R, P1, A1>(
+      function, false, p1);
+}
+
+// See MethodResultCallback_5_2
+template <typename R, typename T, typename P1, typename P2, typename P3,
+          typename P4, typename P5, typename A1, typename A2>
+inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
+    T* object, R (T::*function)(P1, P2, P3, P4, P5, A1, A2),
+    typename internal::InternalConstRef<P1>::type p1,
+    typename internal::InternalConstRef<P2>::type p2,
+    typename internal::InternalConstRef<P3>::type p3,
+    typename internal::InternalConstRef<P4>::type p4,
+    typename internal::InternalConstRef<P5>::type p5) {
+  return new internal::MethodResultCallback_5_2<R, T, P1, P2, P3, P4, P5, A1,
+                                                A2>(object, function, false, p1,
+                                                    p2, p3, p4, p5);
+}
+
+}  // namespace internal
+
+// A function which does nothing.  Useful for creating no-op callbacks, e.g.:
+//   Closure* nothing = NewCallback(&DoNothing);
+void LIBPROTOBUF_EXPORT DoNothing();
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
diff --git a/src/google/protobuf/stubs/casts.h b/src/google/protobuf/stubs/casts.h
new file mode 100644
index 0000000..be65284
--- /dev/null
+++ b/src/google/protobuf/stubs/casts.h
@@ -0,0 +1,133 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+#ifndef GOOGLE_PROTOBUF_CASTS_H__
+#define GOOGLE_PROTOBUF_CASTS_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/type_traits.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertable to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+
+#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
+  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
+#endif
+  return static_cast<To>(f);
+}
+
+template<typename To, typename From>    // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) {
+  typedef typename remove_reference<To>::type* ToAsPointer;
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, ToAsPointer>(0);
+  }
+
+#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
+  // RTTI: debug mode only!
+  assert(dynamic_cast<ToAsPointer>(&f) != NULL);
+#endif
+  return *static_cast<ToAsPointer>(&f);
+}
+
+template<typename To, typename From>
+inline To bit_cast(const From& from) {
+  GOOGLE_COMPILE_ASSERT(sizeof(From) == sizeof(To),
+                        bit_cast_with_different_sizes);
+  To dest;
+  memcpy(&dest, &from, sizeof(dest));
+  return dest;
+}
+
+}  // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::implicit_cast;
+using internal::down_cast;
+using internal::bit_cast;
+
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_CASTS_H__
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index 1e02b22..d443e8a 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -32,8 +32,13 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/once.h>
-#include <stdio.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/int128.h>
 #include <errno.h>
+#include <sstream>
+#include <stdio.h>
 #include <vector>
 
 #include "config.h"
@@ -47,6 +52,9 @@
 #else
 #error "No suitable threading library available."
 #endif
+#if defined(__ANDROID__)
+#include <android/log.h>
+#endif
 
 namespace google {
 namespace protobuf {
@@ -103,7 +111,43 @@
 // emulates google3/base/logging.cc
 
 namespace internal {
+#if defined(__ANDROID__)
+inline void DefaultLogHandler(LogLevel level, const char* filename, int line,
+                              const string& message) {
+#ifdef GOOGLE_PROTOBUF_MIN_LOG_LEVEL
+  if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
+    return;
+  }
+  static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
 
+  static const int android_log_levels[] = {
+      ANDROID_LOG_INFO,   // LOG(INFO),
+      ANDROID_LOG_WARN,   // LOG(WARNING)
+      ANDROID_LOG_ERROR,  // LOG(ERROR)
+      ANDROID_LOG_FATAL,  // LOG(FATAL)
+  };
+
+  // Bound the logging level.
+  const int android_log_level = android_log_levels[level];
+  ::std::ostringstream ostr;
+  ostr << "[libprotobuf " << level_names[level] << " " << filename << ":"
+       << line << "] " << message.c_str();
+
+  // Output the log string the Android log at the appropriate level.
+  __android_log_write(android_log_level, "libprotobuf-native",
+                      ostr.str().c_str());
+  // Also output to std::cerr.
+  fprintf(stderr, "%s", ostr.str().c_str());
+  fflush(stderr);
+
+  // Indicate termination if needed.
+  if (android_log_level == ANDROID_LOG_FATAL) {
+    __android_log_write(ANDROID_LOG_FATAL, "libprotobuf-native",
+                        "terminating.\n");
+  }
+#endif
+}
+#else
 void DefaultLogHandler(LogLevel level, const char* filename, int line,
                        const string& message) {
   static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
@@ -114,6 +158,7 @@
           level_names[level], filename, line, message.c_str());
   fflush(stderr);  // Needed on MSVC.
 }
+#endif
 
 void NullLogHandler(LogLevel /* level */, const char* /* filename */,
                     int /* line */, const string& /* message */) {
@@ -148,6 +193,24 @@
   return *this;
 }
 
+LogMessage& LogMessage::operator<<(const StringPiece& value) {
+  message_ += value.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(
+    const ::google::protobuf::util::Status& status) {
+  message_ += status.ToString();
+  return *this;
+}
+
+LogMessage& LogMessage::operator<<(const uint128& value) {
+  std::ostringstream str;
+  str << value;
+  message_ += str.str();
+  return *this;
+}
+
 // Since this is just for logging, we don't care if the current locale changes
 // the results -- in fact, we probably prefer that.  So we use snprintf()
 // instead of Simple*toa().
@@ -167,10 +230,13 @@
 
 DECLARE_STREAM_OPERATOR(char         , "%c" )
 DECLARE_STREAM_OPERATOR(int          , "%d" )
-DECLARE_STREAM_OPERATOR(uint         , "%u" )
+DECLARE_STREAM_OPERATOR(unsigned int , "%u" )
 DECLARE_STREAM_OPERATOR(long         , "%ld")
 DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
 DECLARE_STREAM_OPERATOR(double       , "%g" )
+DECLARE_STREAM_OPERATOR(void*        , "%p" )
+DECLARE_STREAM_OPERATOR(long long         , "%" GOOGLE_LL_FORMAT "d")
+DECLARE_STREAM_OPERATOR(unsigned long long, "%" GOOGLE_LL_FORMAT "u")
 #undef DECLARE_STREAM_OPERATOR
 
 LogMessage::LogMessage(LogLevel level, const char* filename, int line)
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index f096fa9..9c05cac 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -35,18 +35,17 @@
 #ifndef GOOGLE_PROTOBUF_COMMON_H__
 #define GOOGLE_PROTOBUF_COMMON_H__
 
-#include <assert.h>
-#include <stdlib.h>
-#include <cstddef>
 #include <string>
-#include <string.h>
-#if defined(__osf__)
-// Tru64 lacks stdint.h, but has inttypes.h which defines a superset of
-// what stdint.h would define.
-#include <inttypes.h>
-#elif !defined(_MSC_VER)
-#include <stdint.h>
-#endif
+
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/platform_macros.h>
+
+// TODO(liujisi): Remove the following includes after the include clean-up.
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/callback.h>
 
 #ifndef PROTOBUF_USE_EXCEPTIONS
 #if defined(_MSC_VER) && defined(_CPPUNWIND)
@@ -61,6 +60,13 @@
 #if PROTOBUF_USE_EXCEPTIONS
 #include <exception>
 #endif
+#if defined(__APPLE__)
+#include <TargetConditionals.h>  // for TARGET_OS_IPHONE
+#endif
+
+#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
+#include <pthread.h>
+#endif
 
 #if defined(_WIN32) && defined(GetMessage)
 // Allow GetMessage to be used as a valid method name in protobuf classes.
@@ -79,33 +85,10 @@
 }
 #endif
 
-
 namespace std {}
 
 namespace google {
 namespace protobuf {
-
-#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
-#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
-  TypeName(const TypeName&);                           \
-  void operator=(const TypeName&)
-
-#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
-  #ifdef LIBPROTOBUF_EXPORTS
-    #define LIBPROTOBUF_EXPORT __declspec(dllexport)
-  #else
-    #define LIBPROTOBUF_EXPORT __declspec(dllimport)
-  #endif
-  #ifdef LIBPROTOC_EXPORTS
-    #define LIBPROTOC_EXPORT   __declspec(dllexport)
-  #else
-    #define LIBPROTOC_EXPORT   __declspec(dllimport)
-  #endif
-#else
-  #define LIBPROTOBUF_EXPORT
-  #define LIBPROTOC_EXPORT
-#endif
-
 namespace internal {
 
 // Some of these constants are macros rather than const ints so that they can
@@ -113,24 +96,24 @@
 
 // The current version, represented as a single integer to make comparison
 // easier:  major * 10^6 + minor * 10^3 + micro
-#define GOOGLE_PROTOBUF_VERSION 2006001
+#define GOOGLE_PROTOBUF_VERSION 3000000
 
 // The minimum library version which works with the current version of the
 // headers.
-#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2006000
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3000000
 
 // The minimum header version which works with the current version of
 // the library.  This constant should only be used by protoc's C++ code
 // generator.
-static const int kMinHeaderVersionForLibrary = 2006000;
+static const int kMinHeaderVersionForLibrary = 3000000;
 
 // The minimum protoc version which works with the current version of the
 // headers.
-#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2006000
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3000000
 
 // The minimum header version which works with the current version of
 // protoc.  This constant should only be used in VerifyVersion().
-static const int kMinHeaderVersionForProtoc = 2006000;
+static const int kMinHeaderVersionForProtoc = 3000000;
 
 // Verifies that the headers and libraries are compatible.  Use the macro
 // below to call this.
@@ -151,1025 +134,41 @@
     GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION,         \
     __FILE__)
 
-// ===================================================================
-// from google3/base/port.h
-
-typedef unsigned int uint;
-
-#ifdef _MSC_VER
-typedef __int8  int8;
-typedef __int16 int16;
-typedef __int32 int32;
-typedef __int64 int64;
-
-typedef unsigned __int8  uint8;
-typedef unsigned __int16 uint16;
-typedef unsigned __int32 uint32;
-typedef unsigned __int64 uint64;
-#else
-typedef int8_t  int8;
-typedef int16_t int16;
-typedef int32_t int32;
-typedef int64_t int64;
-
-typedef uint8_t  uint8;
-typedef uint16_t uint16;
-typedef uint32_t uint32;
-typedef uint64_t uint64;
-#endif
-
-// long long macros to be used because gcc and vc++ use different suffixes,
-// and different size specifiers in format strings
-#undef GOOGLE_LONGLONG
-#undef GOOGLE_ULONGLONG
-#undef GOOGLE_LL_FORMAT
-
-#ifdef _MSC_VER
-#define GOOGLE_LONGLONG(x) x##I64
-#define GOOGLE_ULONGLONG(x) x##UI64
-#define GOOGLE_LL_FORMAT "I64"  // As in printf("%I64d", ...)
-#else
-#define GOOGLE_LONGLONG(x) x##LL
-#define GOOGLE_ULONGLONG(x) x##ULL
-#define GOOGLE_LL_FORMAT "ll"  // As in "%lld". Note that "q" is poor form also.
-#endif
-
-static const int32 kint32max = 0x7FFFFFFF;
-static const int32 kint32min = -kint32max - 1;
-static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF);
-static const int64 kint64min = -kint64max - 1;
-static const uint32 kuint32max = 0xFFFFFFFFu;
-static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
-
-// -------------------------------------------------------------------
-// Annotations:  Some parts of the code have been annotated in ways that might
-//   be useful to some compilers or tools, but are not supported universally.
-//   You can #define these annotations yourself if the default implementation
-//   is not right for you.
-
-#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
-// For functions we want to force inline.
-// Introduced in gcc 3.1.
-#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
-#else
-// Other compilers will have to figure it out for themselves.
-#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-#endif
-#endif
-
-#ifndef GOOGLE_ATTRIBUTE_DEPRECATED
-#ifdef __GNUC__
-// If the method/variable/type is used anywhere, produce a warning.
-#define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated))
-#else
-#define GOOGLE_ATTRIBUTE_DEPRECATED
-#endif
-#endif
-
-#ifndef GOOGLE_PREDICT_TRUE
-#ifdef __GNUC__
-// Provided at least since GCC 3.0.
-#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#else
-#define GOOGLE_PREDICT_TRUE
-#endif
-#endif
-
-// Delimits a block of code which may write to memory which is simultaneously
-// written by other threads, but which has been determined to be thread-safe
-// (e.g. because it is an idempotent write).
-#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN
-#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN()
-#endif
-#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END
-#define GOOGLE_SAFE_CONCURRENT_WRITES_END()
-#endif
-
-// ===================================================================
-// from google3/base/basictypes.h
-
-// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
-// The expression is a compile-time constant, and therefore can be
-// used in defining new arrays, for example.
-//
-// GOOGLE_ARRAYSIZE catches a few type errors.  If you see a compiler error
-//
-//   "warning: division by zero in ..."
-//
-// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
-// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
-//
-// The following comments are on the implementation details, and can
-// be ignored by the users.
-//
-// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
-// the array) and sizeof(*(arr)) (the # of bytes in one array
-// element).  If the former is divisible by the latter, perhaps arr is
-// indeed an array, in which case the division result is the # of
-// elements in the array.  Otherwise, arr cannot possibly be an array,
-// and we generate a compiler error to prevent the code from
-// compiling.
-//
-// Since the size of bool is implementation-defined, we need to cast
-// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
-// result has type size_t.
-//
-// This macro is not perfect as it wrongfully accepts certain
-// pointers, namely where the pointer size is divisible by the pointee
-// size.  Since all our code has to go through a 32-bit compiler,
-// where a pointer is 4 bytes, this means all pointers to a type whose
-// size is 3 or greater than 4 will be (righteously) rejected.
-//
-// Kudos to Jorg Brown for this simple and elegant implementation.
-
-#undef GOOGLE_ARRAYSIZE
-#define GOOGLE_ARRAYSIZE(a) \
-  ((sizeof(a) / sizeof(*(a))) / \
-   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-
-namespace internal {
-
-// Use implicit_cast as a safe version of static_cast or const_cast
-// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
-// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
-// a const pointer to Foo).
-// When you use implicit_cast, the compiler checks that the cast is safe.
-// Such explicit implicit_casts are necessary in surprisingly many
-// situations where C++ demands an exact type match instead of an
-// argument type convertable to a target type.
-//
-// The From type can be inferred, so the preferred syntax for using
-// implicit_cast is the same as for static_cast etc.:
-//
-//   implicit_cast<ToType>(expr)
-//
-// implicit_cast would have been part of the C++ standard library,
-// but the proposal was submitted too late.  It will probably make
-// its way into the language in the future.
-template<typename To, typename From>
-inline To implicit_cast(From const &f) {
-  return f;
-}
-
-// When you upcast (that is, cast a pointer from type Foo to type
-// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
-// always succeed.  When you downcast (that is, cast a pointer from
-// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
-// how do you know the pointer is really of type SubclassOfFoo?  It
-// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
-// when you downcast, you should use this macro.  In debug mode, we
-// use dynamic_cast<> to double-check the downcast is legal (we die
-// if it's not).  In normal mode, we do the efficient static_cast<>
-// instead.  Thus, it's important to test in debug mode to make sure
-// the cast is legal!
-//    This is the only place in the code we should use dynamic_cast<>.
-// In particular, you SHOULDN'T be using dynamic_cast<> in order to
-// do RTTI (eg code like this:
-//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
-//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
-// You should design the code some other way not to need this.
-
-template<typename To, typename From>     // use like this: down_cast<T*>(foo);
-inline To down_cast(From* f) {                   // so we only accept pointers
-  // Ensures that To is a sub-type of From *.  This test is here only
-  // for compile-time type checking, and has no overhead in an
-  // optimized build at run-time, as it will be optimized away
-  // completely.
-  if (false) {
-    implicit_cast<From*, To>(0);
-  }
-
-#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
-  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
-#endif
-  return static_cast<To>(f);
-}
-
-}  // namespace internal
-
-// We made these internal so that they would show up as such in the docs,
-// but we don't want to stick "internal::" in front of them everywhere.
-using internal::implicit_cast;
-using internal::down_cast;
-
-// The COMPILE_ASSERT macro can be used to verify that a compile time
-// expression is true. For example, you could use it to verify the
-// size of a static array:
-//
-//   COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
-//                  content_type_names_incorrect_size);
-//
-// or to make sure a struct is smaller than a certain size:
-//
-//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
-//
-// The second argument to the macro is the name of the variable. If
-// the expression is false, most compilers will issue a warning/error
-// containing the name of the variable.
-
-namespace internal {
-
-template <bool>
-struct CompileAssert {
-};
-
-}  // namespace internal
-
-#undef GOOGLE_COMPILE_ASSERT
-#define GOOGLE_COMPILE_ASSERT(expr, msg) \
-  typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \
-          msg[bool(expr) ? 1 : -1]
-
-
-// Implementation details of COMPILE_ASSERT:
-//
-// - COMPILE_ASSERT works by defining an array type that has -1
-//   elements (and thus is invalid) when the expression is false.
-//
-// - The simpler definition
-//
-//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
-//
-//   does not work, as gcc supports variable-length arrays whose sizes
-//   are determined at run-time (this is gcc's extension and not part
-//   of the C++ standard).  As a result, gcc fails to reject the
-//   following code with the simple definition:
-//
-//     int foo;
-//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
-//                               // not a compile-time constant.
-//
-// - By using the type CompileAssert<(bool(expr))>, we ensures that
-//   expr is a compile-time constant.  (Template arguments must be
-//   determined at compile-time.)
-//
-// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
-//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
-//
-//     CompileAssert<bool(expr)>
-//
-//   instead, these compilers will refuse to compile
-//
-//     COMPILE_ASSERT(5 > 0, some_message);
-//
-//   (They seem to think the ">" in "5 > 0" marks the end of the
-//   template argument list.)
-//
-// - The array size is (bool(expr) ? 1 : -1), instead of simply
-//
-//     ((expr) ? 1 : -1).
-//
-//   This is to avoid running into a bug in MS VC 7.1, which
-//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
-
-// ===================================================================
-// from google3/base/scoped_ptr.h
-
-namespace internal {
-
-//  This is an implementation designed to match the anticipated future TR2
-//  implementation of the scoped_ptr class, and its closely-related brethren,
-//  scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
-
-template <class C> class scoped_ptr;
-template <class C> class scoped_array;
-
-// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
-// automatically deletes the pointer it holds (if any).
-// That is, scoped_ptr<T> owns the T object that it points to.
-// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
-//
-// The size of a scoped_ptr is small:
-// sizeof(scoped_ptr<C>) == sizeof(C*)
-template <class C>
-class scoped_ptr {
- public:
-
-  // The element type
-  typedef C element_type;
-
-  // Constructor.  Defaults to intializing with NULL.
-  // There is no way to create an uninitialized scoped_ptr.
-  // The input parameter must be allocated with new.
-  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
-
-  // Destructor.  If there is a C object, delete it.
-  // We don't need to test ptr_ == NULL because C++ does that for us.
-  ~scoped_ptr() {
-    enum { type_must_be_complete = sizeof(C) };
-    delete ptr_;
-  }
-
-  // Reset.  Deletes the current owned object, if any.
-  // Then takes ownership of a new object, if given.
-  // this->reset(this->get()) works.
-  void reset(C* p = NULL) {
-    if (p != ptr_) {
-      enum { type_must_be_complete = sizeof(C) };
-      delete ptr_;
-      ptr_ = p;
-    }
-  }
-
-  // Accessors to get the owned object.
-  // operator* and operator-> will assert() if there is no current object.
-  C& operator*() const {
-    assert(ptr_ != NULL);
-    return *ptr_;
-  }
-  C* operator->() const  {
-    assert(ptr_ != NULL);
-    return ptr_;
-  }
-  C* get() const { return ptr_; }
-
-  // Comparison operators.
-  // These return whether two scoped_ptr refer to the same object, not just to
-  // two different but equal objects.
-  bool operator==(C* p) const { return ptr_ == p; }
-  bool operator!=(C* p) const { return ptr_ != p; }
-
-  // Swap two scoped pointers.
-  void swap(scoped_ptr& p2) {
-    C* tmp = ptr_;
-    ptr_ = p2.ptr_;
-    p2.ptr_ = tmp;
-  }
-
-  // Release a pointer.
-  // The return value is the current pointer held by this object.
-  // If this object holds a NULL pointer, the return value is NULL.
-  // After this operation, this object will hold a NULL pointer,
-  // and will not own the object any more.
-  C* release() {
-    C* retVal = ptr_;
-    ptr_ = NULL;
-    return retVal;
-  }
-
- private:
-  C* ptr_;
-
-  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't
-  // make sense, and if C2 == C, it still doesn't make sense because you should
-  // never have the same object owned by two different scoped_ptrs.
-  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
-  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
-
-  // Disallow evil constructors
-  scoped_ptr(const scoped_ptr&);
-  void operator=(const scoped_ptr&);
-};
-
-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
-// with new [] and the destructor deletes objects with delete [].
-//
-// As with scoped_ptr<C>, a scoped_array<C> either points to an object
-// or is NULL.  A scoped_array<C> owns the object that it points to.
-//
-// Size: sizeof(scoped_array<C>) == sizeof(C*)
-template <class C>
-class scoped_array {
- public:
-
-  // The element type
-  typedef C element_type;
-
-  // Constructor.  Defaults to intializing with NULL.
-  // There is no way to create an uninitialized scoped_array.
-  // The input parameter must be allocated with new [].
-  explicit scoped_array(C* p = NULL) : array_(p) { }
-
-  // Destructor.  If there is a C object, delete it.
-  // We don't need to test ptr_ == NULL because C++ does that for us.
-  ~scoped_array() {
-    enum { type_must_be_complete = sizeof(C) };
-    delete[] array_;
-  }
-
-  // Reset.  Deletes the current owned object, if any.
-  // Then takes ownership of a new object, if given.
-  // this->reset(this->get()) works.
-  void reset(C* p = NULL) {
-    if (p != array_) {
-      enum { type_must_be_complete = sizeof(C) };
-      delete[] array_;
-      array_ = p;
-    }
-  }
-
-  // Get one element of the current object.
-  // Will assert() if there is no current object, or index i is negative.
-  C& operator[](std::ptrdiff_t i) const {
-    assert(i >= 0);
-    assert(array_ != NULL);
-    return array_[i];
-  }
-
-  // Get a pointer to the zeroth element of the current object.
-  // If there is no current object, return NULL.
-  C* get() const {
-    return array_;
-  }
-
-  // Comparison operators.
-  // These return whether two scoped_array refer to the same object, not just to
-  // two different but equal objects.
-  bool operator==(C* p) const { return array_ == p; }
-  bool operator!=(C* p) const { return array_ != p; }
-
-  // Swap two scoped arrays.
-  void swap(scoped_array& p2) {
-    C* tmp = array_;
-    array_ = p2.array_;
-    p2.array_ = tmp;
-  }
-
-  // Release an array.
-  // The return value is the current pointer held by this object.
-  // If this object holds a NULL pointer, the return value is NULL.
-  // After this operation, this object will hold a NULL pointer,
-  // and will not own the object any more.
-  C* release() {
-    C* retVal = array_;
-    array_ = NULL;
-    return retVal;
-  }
-
- private:
-  C* array_;
-
-  // Forbid comparison of different scoped_array types.
-  template <class C2> bool operator==(scoped_array<C2> const& p2) const;
-  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
-
-  // Disallow evil constructors
-  scoped_array(const scoped_array&);
-  void operator=(const scoped_array&);
-};
-
-}  // namespace internal
-
-// We made these internal so that they would show up as such in the docs,
-// but we don't want to stick "internal::" in front of them everywhere.
-using internal::scoped_ptr;
-using internal::scoped_array;
-
-// ===================================================================
-// emulates google3/base/logging.h
-
-enum LogLevel {
-  LOGLEVEL_INFO,     // Informational.  This is never actually used by
-                     // libprotobuf.
-  LOGLEVEL_WARNING,  // Warns about issues that, although not technically a
-                     // problem now, could cause problems in the future.  For
-                     // example, a // warning will be printed when parsing a
-                     // message that is near the message size limit.
-  LOGLEVEL_ERROR,    // An error occurred which should never happen during
-                     // normal use.
-  LOGLEVEL_FATAL,    // An error occurred from which the library cannot
-                     // recover.  This usually indicates a programming error
-                     // in the code which calls the library, especially when
-                     // compiled in debug mode.
-
-#ifdef NDEBUG
-  LOGLEVEL_DFATAL = LOGLEVEL_ERROR
-#else
-  LOGLEVEL_DFATAL = LOGLEVEL_FATAL
-#endif
-};
-
-namespace internal {
-
-class LogFinisher;
-
-class LIBPROTOBUF_EXPORT LogMessage {
- public:
-  LogMessage(LogLevel level, const char* filename, int line);
-  ~LogMessage();
-
-  LogMessage& operator<<(const std::string& value);
-  LogMessage& operator<<(const char* value);
-  LogMessage& operator<<(char value);
-  LogMessage& operator<<(int value);
-  LogMessage& operator<<(uint value);
-  LogMessage& operator<<(long value);
-  LogMessage& operator<<(unsigned long value);
-  LogMessage& operator<<(double value);
-
- private:
-  friend class LogFinisher;
-  void Finish();
-
-  LogLevel level_;
-  const char* filename_;
-  int line_;
-  std::string message_;
-};
-
-// Used to make the entire "LOG(BLAH) << etc." expression have a void return
-// type and print a newline after each message.
-class LIBPROTOBUF_EXPORT LogFinisher {
- public:
-  void operator=(LogMessage& other);
-};
-
-}  // namespace internal
-
-// Undef everything in case we're being mixed with some other Google library
-// which already defined them itself.  Presumably all Google libraries will
-// support the same syntax for these so it should not be a big deal if they
-// end up using our definitions instead.
-#undef GOOGLE_LOG
-#undef GOOGLE_LOG_IF
-
-#undef GOOGLE_CHECK
-#undef GOOGLE_CHECK_OK
-#undef GOOGLE_CHECK_EQ
-#undef GOOGLE_CHECK_NE
-#undef GOOGLE_CHECK_LT
-#undef GOOGLE_CHECK_LE
-#undef GOOGLE_CHECK_GT
-#undef GOOGLE_CHECK_GE
-#undef GOOGLE_CHECK_NOTNULL
-
-#undef GOOGLE_DLOG
-#undef GOOGLE_DCHECK
-#undef GOOGLE_DCHECK_EQ
-#undef GOOGLE_DCHECK_NE
-#undef GOOGLE_DCHECK_LT
-#undef GOOGLE_DCHECK_LE
-#undef GOOGLE_DCHECK_GT
-#undef GOOGLE_DCHECK_GE
-
-#define GOOGLE_LOG(LEVEL)                                                 \
-  ::google::protobuf::internal::LogFinisher() =                           \
-    ::google::protobuf::internal::LogMessage(                             \
-      ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
-#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
-  !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
-
-#define GOOGLE_CHECK(EXPRESSION) \
-  GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
-#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(A)
-#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
-#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
-#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) <  (B))
-#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
-#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) >  (B))
-#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
-
-namespace internal {
-template<typename T>
-T* CheckNotNull(const char* /* file */, int /* line */,
-                const char* name, T* val) {
-  if (val == NULL) {
-    GOOGLE_LOG(FATAL) << name;
-  }
-  return val;
-}
-}  // namespace internal
-#define GOOGLE_CHECK_NOTNULL(A) \
-  internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A))
-
-#ifdef NDEBUG
-
-#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false)
-
-#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
-#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
-#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
-#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) <  (B))
-#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
-#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) >  (B))
-#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
-
-#else  // NDEBUG
-
-#define GOOGLE_DLOG GOOGLE_LOG
-
-#define GOOGLE_DCHECK    GOOGLE_CHECK
-#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
-#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
-#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
-#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
-#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
-#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
-
-#endif  // !NDEBUG
-
-typedef void LogHandler(LogLevel level, const char* filename, int line,
-                        const std::string& message);
-
-// The protobuf library sometimes writes warning and error messages to
-// stderr.  These messages are primarily useful for developers, but may
-// also help end users figure out a problem.  If you would prefer that
-// these messages be sent somewhere other than stderr, call SetLogHandler()
-// to set your own handler.  This returns the old handler.  Set the handler
-// to NULL to ignore log messages (but see also LogSilencer, below).
-//
-// Obviously, SetLogHandler is not thread-safe.  You should only call it
-// at initialization time, and probably not from library code.  If you
-// simply want to suppress log messages temporarily (e.g. because you
-// have some code that tends to trigger them frequently and you know
-// the warnings are not important to you), use the LogSilencer class
-// below.
-LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
-
-// Create a LogSilencer if you want to temporarily suppress all log
-// messages.  As long as any LogSilencer objects exist, non-fatal
-// log messages will be discarded (the current LogHandler will *not*
-// be called).  Constructing a LogSilencer is thread-safe.  You may
-// accidentally suppress log messages occurring in another thread, but
-// since messages are generally for debugging purposes only, this isn't
-// a big deal.  If you want to intercept log messages, use SetLogHandler().
-class LIBPROTOBUF_EXPORT LogSilencer {
- public:
-  LogSilencer();
-  ~LogSilencer();
-};
-
-// ===================================================================
-// emulates google3/base/callback.h
-
-// Abstract interface for a callback.  When calling an RPC, you must provide
-// a Closure to call when the procedure completes.  See the Service interface
-// in service.h.
-//
-// To automatically construct a Closure which calls a particular function or
-// method with a particular set of parameters, use the NewCallback() function.
-// Example:
-//   void FooDone(const FooResponse* response) {
-//     ...
-//   }
-//
-//   void CallFoo() {
-//     ...
-//     // When done, call FooDone() and pass it a pointer to the response.
-//     Closure* callback = NewCallback(&FooDone, response);
-//     // Make the call.
-//     service->Foo(controller, request, response, callback);
-//   }
-//
-// Example that calls a method:
-//   class Handler {
-//    public:
-//     ...
-//
-//     void FooDone(const FooResponse* response) {
-//       ...
-//     }
-//
-//     void CallFoo() {
-//       ...
-//       // When done, call FooDone() and pass it a pointer to the response.
-//       Closure* callback = NewCallback(this, &Handler::FooDone, response);
-//       // Make the call.
-//       service->Foo(controller, request, response, callback);
-//     }
-//   };
-//
-// Currently NewCallback() supports binding zero, one, or two arguments.
-//
-// Callbacks created with NewCallback() automatically delete themselves when
-// executed.  They should be used when a callback is to be called exactly
-// once (usually the case with RPC callbacks).  If a callback may be called
-// a different number of times (including zero), create it with
-// NewPermanentCallback() instead.  You are then responsible for deleting the
-// callback (using the "delete" keyword as normal).
-//
-// Note that NewCallback() is a bit touchy regarding argument types.  Generally,
-// the values you provide for the parameter bindings must exactly match the
-// types accepted by the callback function.  For example:
-//   void Foo(string s);
-//   NewCallback(&Foo, "foo");          // WON'T WORK:  const char* != string
-//   NewCallback(&Foo, string("foo"));  // WORKS
-// Also note that the arguments cannot be references:
-//   void Foo(const string& s);
-//   string my_str;
-//   NewCallback(&Foo, my_str);  // WON'T WORK:  Can't use referecnes.
-// However, correctly-typed pointers will work just fine.
-class LIBPROTOBUF_EXPORT Closure {
- public:
-  Closure() {}
-  virtual ~Closure();
-
-  virtual void Run() = 0;
-
- private:
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
-};
-
-namespace internal {
-
-class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure {
- public:
-  typedef void (*FunctionType)();
-
-  FunctionClosure0(FunctionType function, bool self_deleting)
-    : function_(function), self_deleting_(self_deleting) {}
-  ~FunctionClosure0();
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    function_();
-    if (needs_delete) delete this;
-  }
-
- private:
-  FunctionType function_;
-  bool self_deleting_;
-};
-
-template <typename Class>
-class MethodClosure0 : public Closure {
- public:
-  typedef void (Class::*MethodType)();
-
-  MethodClosure0(Class* object, MethodType method, bool self_deleting)
-    : object_(object), method_(method), self_deleting_(self_deleting) {}
-  ~MethodClosure0() {}
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    (object_->*method_)();
-    if (needs_delete) delete this;
-  }
-
- private:
-  Class* object_;
-  MethodType method_;
-  bool self_deleting_;
-};
-
-template <typename Arg1>
-class FunctionClosure1 : public Closure {
- public:
-  typedef void (*FunctionType)(Arg1 arg1);
-
-  FunctionClosure1(FunctionType function, bool self_deleting,
-                   Arg1 arg1)
-    : function_(function), self_deleting_(self_deleting),
-      arg1_(arg1) {}
-  ~FunctionClosure1() {}
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    function_(arg1_);
-    if (needs_delete) delete this;
-  }
-
- private:
-  FunctionType function_;
-  bool self_deleting_;
-  Arg1 arg1_;
-};
-
-template <typename Class, typename Arg1>
-class MethodClosure1 : public Closure {
- public:
-  typedef void (Class::*MethodType)(Arg1 arg1);
-
-  MethodClosure1(Class* object, MethodType method, bool self_deleting,
-                 Arg1 arg1)
-    : object_(object), method_(method), self_deleting_(self_deleting),
-      arg1_(arg1) {}
-  ~MethodClosure1() {}
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    (object_->*method_)(arg1_);
-    if (needs_delete) delete this;
-  }
-
- private:
-  Class* object_;
-  MethodType method_;
-  bool self_deleting_;
-  Arg1 arg1_;
-};
-
-template <typename Arg1, typename Arg2>
-class FunctionClosure2 : public Closure {
- public:
-  typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2);
-
-  FunctionClosure2(FunctionType function, bool self_deleting,
-                   Arg1 arg1, Arg2 arg2)
-    : function_(function), self_deleting_(self_deleting),
-      arg1_(arg1), arg2_(arg2) {}
-  ~FunctionClosure2() {}
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    function_(arg1_, arg2_);
-    if (needs_delete) delete this;
-  }
-
- private:
-  FunctionType function_;
-  bool self_deleting_;
-  Arg1 arg1_;
-  Arg2 arg2_;
-};
-
-template <typename Class, typename Arg1, typename Arg2>
-class MethodClosure2 : public Closure {
- public:
-  typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2);
-
-  MethodClosure2(Class* object, MethodType method, bool self_deleting,
-                 Arg1 arg1, Arg2 arg2)
-    : object_(object), method_(method), self_deleting_(self_deleting),
-      arg1_(arg1), arg2_(arg2) {}
-  ~MethodClosure2() {}
-
-  void Run() {
-    bool needs_delete = self_deleting_;  // read in case callback deletes
-    (object_->*method_)(arg1_, arg2_);
-    if (needs_delete) delete this;
-  }
-
- private:
-  Class* object_;
-  MethodType method_;
-  bool self_deleting_;
-  Arg1 arg1_;
-  Arg2 arg2_;
-};
-
-}  // namespace internal
-
-// See Closure.
-inline Closure* NewCallback(void (*function)()) {
-  return new internal::FunctionClosure0(function, true);
-}
-
-// See Closure.
-inline Closure* NewPermanentCallback(void (*function)()) {
-  return new internal::FunctionClosure0(function, false);
-}
-
-// See Closure.
-template <typename Class>
-inline Closure* NewCallback(Class* object, void (Class::*method)()) {
-  return new internal::MethodClosure0<Class>(object, method, true);
-}
-
-// See Closure.
-template <typename Class>
-inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
-  return new internal::MethodClosure0<Class>(object, method, false);
-}
-
-// See Closure.
-template <typename Arg1>
-inline Closure* NewCallback(void (*function)(Arg1),
-                            Arg1 arg1) {
-  return new internal::FunctionClosure1<Arg1>(function, true, arg1);
-}
-
-// See Closure.
-template <typename Arg1>
-inline Closure* NewPermanentCallback(void (*function)(Arg1),
-                                     Arg1 arg1) {
-  return new internal::FunctionClosure1<Arg1>(function, false, arg1);
-}
-
-// See Closure.
-template <typename Class, typename Arg1>
-inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
-                            Arg1 arg1) {
-  return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
-}
-
-// See Closure.
-template <typename Class, typename Arg1>
-inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
-                                     Arg1 arg1) {
-  return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
-}
-
-// See Closure.
-template <typename Arg1, typename Arg2>
-inline Closure* NewCallback(void (*function)(Arg1, Arg2),
-                            Arg1 arg1, Arg2 arg2) {
-  return new internal::FunctionClosure2<Arg1, Arg2>(
-    function, true, arg1, arg2);
-}
-
-// See Closure.
-template <typename Arg1, typename Arg2>
-inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
-                                     Arg1 arg1, Arg2 arg2) {
-  return new internal::FunctionClosure2<Arg1, Arg2>(
-    function, false, arg1, arg2);
-}
-
-// See Closure.
-template <typename Class, typename Arg1, typename Arg2>
-inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
-                            Arg1 arg1, Arg2 arg2) {
-  return new internal::MethodClosure2<Class, Arg1, Arg2>(
-    object, method, true, arg1, arg2);
-}
-
-// See Closure.
-template <typename Class, typename Arg1, typename Arg2>
-inline Closure* NewPermanentCallback(
-    Class* object, void (Class::*method)(Arg1, Arg2),
-    Arg1 arg1, Arg2 arg2) {
-  return new internal::MethodClosure2<Class, Arg1, Arg2>(
-    object, method, false, arg1, arg2);
-}
-
-// A function which does nothing.  Useful for creating no-op callbacks, e.g.:
-//   Closure* nothing = NewCallback(&DoNothing);
-void LIBPROTOBUF_EXPORT DoNothing();
-
-// ===================================================================
-// emulates google3/base/mutex.h
-
-namespace internal {
-
-// A Mutex is a non-reentrant (aka non-recursive) mutex.  At most one thread T
-// may hold a mutex at a given time.  If T attempts to Lock() the same Mutex
-// while holding it, T will deadlock.
-class LIBPROTOBUF_EXPORT Mutex {
- public:
-  // Create a Mutex that is not held by anybody.
-  Mutex();
-
-  // Destructor
-  ~Mutex();
-
-  // Block if necessary until this Mutex is free, then acquire it exclusively.
-  void Lock();
-
-  // Release this Mutex.  Caller must hold it exclusively.
-  void Unlock();
-
-  // Crash if this Mutex is not held exclusively by this thread.
-  // May fail to crash when it should; will never crash when it should not.
-  void AssertHeld();
-
- private:
-  struct Internal;
-  Internal* mInternal;
-
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex);
-};
-
-// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
-class LIBPROTOBUF_EXPORT MutexLock {
- public:
-  explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
-  ~MutexLock() { this->mu_->Unlock(); }
- private:
-  Mutex *const mu_;
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
-};
-
-// TODO(kenton):  Implement these?  Hard to implement portably.
-typedef MutexLock ReaderMutexLock;
-typedef MutexLock WriterMutexLock;
-
-// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
-class LIBPROTOBUF_EXPORT MutexLockMaybe {
- public:
-  explicit MutexLockMaybe(Mutex *mu) :
-    mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
-  ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } }
- private:
-  Mutex *const mu_;
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
-};
-
-}  // namespace internal
-
-// We made these internal so that they would show up as such in the docs,
-// but we don't want to stick "internal::" in front of them everywhere.
-using internal::Mutex;
-using internal::MutexLock;
-using internal::ReaderMutexLock;
-using internal::WriterMutexLock;
-using internal::MutexLockMaybe;
 
 // ===================================================================
 // from google3/util/utf8/public/unilib.h
 
+class StringPiece;
 namespace internal {
 
 // Checks if the buffer contains structurally-valid UTF-8.  Implemented in
 // structurally_valid.cc.
 LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
 
+inline bool IsStructurallyValidUTF8(const std::string& str) {
+  return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
+}
+
+// Returns initial number of bytes of structually valid UTF-8.
+LIBPROTOBUF_EXPORT int UTF8SpnStructurallyValid(const StringPiece& str);
+
+// Coerce UTF-8 byte string in src_str to be
+// a structurally-valid equal-length string by selectively
+// overwriting illegal bytes with replace_char (typically ' ' or '?').
+// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
+// src_str is read-only.
+//
+// Returns pointer to output buffer, src_str.data() if no changes were made,
+//  or idst if some bytes were changed. idst is allocated by the caller
+//  and must be at least as big as src_str
+//
+// Optimized for: all structurally valid and no byte copying is done.
+//
+LIBPROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid(
+    const StringPiece& str, char* dst, char replace_char);
+
 }  // namespace internal
 
-// ===================================================================
-// from google3/util/endian/endian.h
-LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
 
 // ===================================================================
 // Shutdown support.
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index cb89207..25bae9b 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -31,6 +31,7 @@
 // Author: kenton@google.com (Kenton Varda)
 
 #include <vector>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
@@ -38,10 +39,10 @@
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
-#include "config.h"
-
 namespace google {
 namespace protobuf {
+using internal::NewCallback;
+using internal::NewPermanentCallback;
 namespace {
 
 // TODO(kenton):  More tests.
@@ -94,9 +95,9 @@
 
   string text = GetCapturedTestStderr();
   EXPECT_EQ(
-    "[libprotobuf INFO "__FILE__":" + SimpleItoa(line + 1) + "] A message.\n"
-    "[libprotobuf WARNING "__FILE__":" + SimpleItoa(line + 2) + "] A warning.\n"
-    "[libprotobuf ERROR "__FILE__":" + SimpleItoa(line + 3) + "] An error.\n",
+    "[libprotobuf INFO " __FILE__ ":" + SimpleItoa(line + 1) + "] A message.\n"
+    "[libprotobuf WARNING " __FILE__ ":" + SimpleItoa(line + 2) + "] A warning.\n"
+    "[libprotobuf ERROR " __FILE__ ":" + SimpleItoa(line + 3) + "] An error.\n",
     text);
 }
 
@@ -127,10 +128,10 @@
 
   ASSERT_EQ(2, captured_messages_.size());
   EXPECT_EQ(
-    "2 "__FILE__":" + SimpleItoa(start_line + 1) + ": An error.",
+    "2 " __FILE__ ":" + SimpleItoa(start_line + 1) + ": An error.",
     captured_messages_[0]);
   EXPECT_EQ(
-    "1 "__FILE__":" + SimpleItoa(start_line + 2) + ": A warning.",
+    "1 " __FILE__ ":" + SimpleItoa(start_line + 2) + ": A warning.",
     captured_messages_[1]);
 }
 
@@ -153,10 +154,10 @@
 
   ASSERT_EQ(2, captured_messages_.size());
   EXPECT_EQ(
-    "0 "__FILE__":" + SimpleItoa(line1) + ": Visible1",
+    "0 " __FILE__ ":" + SimpleItoa(line1) + ": Visible1",
     captured_messages_[0]);
   EXPECT_EQ(
-    "0 "__FILE__":" + SimpleItoa(line2) + ": Visible2",
+    "0 " __FILE__ ":" + SimpleItoa(line2) + ": Visible2",
     captured_messages_[1]);
 }
 
diff --git a/src/google/protobuf/stubs/fastmem.h b/src/google/protobuf/stubs/fastmem.h
new file mode 100644
index 0000000..763a6e6
--- /dev/null
+++ b/src/google/protobuf/stubs/fastmem.h
@@ -0,0 +1,152 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+
+// Fast memory copying and comparison routines.
+//   strings::fastmemcmp_inlined() replaces memcmp()
+//   strings::memcpy_inlined() replaces memcpy()
+//   strings::memeq(a, b, n) replaces memcmp(a, b, n) == 0
+//
+// strings::*_inlined() routines are inline versions of the
+// routines exported by this module.  Sometimes using the inlined
+// versions is faster.  Measure before using the inlined versions.
+//
+// Performance measurement:
+//   strings::fastmemcmp_inlined
+//     Analysis: memcmp, fastmemcmp_inlined, fastmemcmp
+//     2012-01-30
+
+#ifndef GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
+#define GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Return true if the n bytes at a equal the n bytes at b.
+// The regions are allowed to overlap.
+//
+// The performance is similar to the performance memcmp(), but faster for
+// moderately-sized inputs, or inputs that share a common prefix and differ
+// somewhere in their last 8 bytes. Further optimizations can be added later
+// if it makes sense to do so.:w
+inline bool memeq(const char* a, const char* b, size_t n) {
+  size_t n_rounded_down = n & ~static_cast<size_t>(7);
+  if (GOOGLE_PREDICT_FALSE(n_rounded_down == 0)) {  // n <= 7
+    return memcmp(a, b, n) == 0;
+  }
+  // n >= 8
+  uint64 u = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
+  uint64 v = GOOGLE_UNALIGNED_LOAD64(a + n - 8) ^ GOOGLE_UNALIGNED_LOAD64(b + n - 8);
+  if ((u | v) != 0) {  // The first or last 8 bytes differ.
+    return false;
+  }
+  a += 8;
+  b += 8;
+  n = n_rounded_down - 8;
+  if (n > 128) {
+    // As of 2012, memcmp on x86-64 uses a big unrolled loop with SSE2
+    // instructions, and while we could try to do something faster, it
+    // doesn't seem worth pursuing.
+    return memcmp(a, b, n) == 0;
+  }
+  for (; n >= 16; n -= 16) {
+    uint64 x = GOOGLE_UNALIGNED_LOAD64(a) ^ GOOGLE_UNALIGNED_LOAD64(b);
+    uint64 y = GOOGLE_UNALIGNED_LOAD64(a + 8) ^ GOOGLE_UNALIGNED_LOAD64(b + 8);
+    if ((x | y) != 0) {
+      return false;
+    }
+    a += 16;
+    b += 16;
+  }
+  // n must be 0 or 8 now because it was a multiple of 8 at the top of the loop.
+  return n == 0 || GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b);
+}
+
+inline int fastmemcmp_inlined(const char *a, const char *b, size_t n) {
+  if (n >= 64) {
+    return memcmp(a, b, n);
+  }
+  const char* a_limit = a + n;
+  while (a + sizeof(uint64) <= a_limit &&
+         GOOGLE_UNALIGNED_LOAD64(a) == GOOGLE_UNALIGNED_LOAD64(b)) {
+    a += sizeof(uint64);
+    b += sizeof(uint64);
+  }
+  if (a + sizeof(uint32) <= a_limit &&
+      GOOGLE_UNALIGNED_LOAD32(a) == GOOGLE_UNALIGNED_LOAD32(b)) {
+    a += sizeof(uint32);
+    b += sizeof(uint32);
+  }
+  while (a < a_limit) {
+    int d = static_cast<uint32>(*a++) - static_cast<uint32>(*b++);
+    if (d) return d;
+  }
+  return 0;
+}
+
+// The standard memcpy operation is slow for variable small sizes.
+// This implementation inlines the optimal realization for sizes 1 to 16.
+// To avoid code bloat don't use it in case of not performance-critical spots,
+// nor when you don't expect very frequent values of size <= 16.
+inline void memcpy_inlined(char *dst, const char *src, size_t size) {
+  // Compiler inlines code with minimal amount of data movement when third
+  // parameter of memcpy is a constant.
+  switch (size) {
+    case  1: memcpy(dst, src, 1); break;
+    case  2: memcpy(dst, src, 2); break;
+    case  3: memcpy(dst, src, 3); break;
+    case  4: memcpy(dst, src, 4); break;
+    case  5: memcpy(dst, src, 5); break;
+    case  6: memcpy(dst, src, 6); break;
+    case  7: memcpy(dst, src, 7); break;
+    case  8: memcpy(dst, src, 8); break;
+    case  9: memcpy(dst, src, 9); break;
+    case 10: memcpy(dst, src, 10); break;
+    case 11: memcpy(dst, src, 11); break;
+    case 12: memcpy(dst, src, 12); break;
+    case 13: memcpy(dst, src, 13); break;
+    case 14: memcpy(dst, src, 14); break;
+    case 15: memcpy(dst, src, 15); break;
+    case 16: memcpy(dst, src, 16); break;
+    default: memcpy(dst, src, size); break;
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_FASTMEM_H_
diff --git a/src/google/protobuf/stubs/hash.cc b/src/google/protobuf/stubs/hash.cc
deleted file mode 100644
index 9eaf4a1..0000000
--- a/src/google/protobuf/stubs/hash.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: kenton@google.com (Kenton Varda)
-
-#include <google/protobuf/stubs/hash.h>
-
-namespace google {
-namespace protobuf {
-
-// Nothing needed here right now.
-
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index 5b6a073..4eac7d5 100644
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -37,13 +37,134 @@
 
 #include <string.h>
 #include <google/protobuf/stubs/common.h>
-#include "config.h"
 
-#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
-#include HASH_MAP_H
-#include HASH_SET_H
+#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
+#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
+
+// Android
+#if defined(__ANDROID__)
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+
+// Use C++11 unordered_{map|set} if available.
+#elif ((_LIBCPP_STD_VER >= 11) || \
+      (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
+      (__GLIBCXX__ > 20090421)))
+# define GOOGLE_PROTOBUF_HAS_CXX11_HASH
+
+// For XCode >= 4.6:  the compiler is clang with libc++.
+// For earlier XCode version: the compiler is gcc-4.2.1 with libstdc++.
+// libc++ provides <unordered_map> and friends even in non C++11 mode,
+// and it does not provide the tr1 library. Therefore the following macro
+// checks against this special case.
+// Note that we should not test the __APPLE_CC__ version number or the
+// __clang__ macro, since the new compiler can still use -stdlib=libstdc++, in
+// which case <unordered_map> is not compilable without -std=c++11
+#elif defined(__APPLE_CC__)
+# if __GNUC__ >= 4
+#  define GOOGLE_PROTOBUF_HAS_TR1
+# else
+// Not tested for gcc < 4... These setting can compile under 4.2.1 though.
+#  define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx
+#  include <ext/hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <ext/hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+# endif
+
+// Version checks for gcc.
+#elif defined(__GNUC__)
+// For GCC 4.x+, use tr1::unordered_map/set; otherwise, follow the
+// instructions from:
+// https://gcc.gnu.org/onlinedocs/libstdc++/manual/backwards.html
+# if __GNUC__ >= 4
+#  define GOOGLE_PROTOBUF_HAS_TR1
+# elif __GNUC__ >= 3
+#  include <backward/hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <backward/hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#  if __GNUC__ == 3 && __GNUC_MINOR__ == 0
+#   define GOOGLE_PROTOBUF_HASH_NAMESPACE std       // GCC 3.0
+#  else
+#   define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx // GCC 3.1 and later
+#  endif
+# else
+#  define GOOGLE_PROTOBUF_HASH_NAMESPACE
+#  include <hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+# endif
+
+// Version checks for MSC.
+// Apparently Microsoft decided to move hash_map *back* to the std namespace in
+// MSVC 2010:
+// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
+// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That
+// said, use unordered_map for MSVC 2010 and beyond is our safest bet.
+#elif defined(_MSC_VER)
+# if _MSC_VER >= 1600  // Since Visual Studio 2010
+#  define GOOGLE_PROTOBUF_HAS_CXX11_HASH
+#  define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare
+# elif _MSC_VER >= 1500  // Since Visual Studio 2008
+#  define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
+#  include <hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
+#  define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+# elif _MSC_VER >= 1310
+#  define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
+#  include <hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
+# else
+#  define GOOGLE_PROTOBUF_HASH_NAMESPACE std
+#  include <hash_map>
+#  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
+#  include <hash_set>
+#  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
+#  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
+# endif
+
+// **ADD NEW COMPILERS SUPPORT HERE.**
+// For other compilers, undefine the macro and fallback to use std::map, in
+// google/protobuf/stubs/hash.h
 #else
-#define MISSING_HASH
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+# undef GOOGLE_PROTOBUF_HAVE_HASH_SET
+#endif
+
+#if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH)
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE std
+# include <unordered_map>
+# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
+# include <unordered_set>
+# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
+#elif defined(GOOGLE_PROTOBUF_HAS_TR1)
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1
+# include <tr1/unordered_map>
+# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
+# include <tr1/unordered_set>
+# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
+#endif
+
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
+  namespace google {                                      \
+  namespace protobuf {
+# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
+
+#undef GOOGLE_PROTOBUF_HAS_CXX11_HASH
+#undef GOOGLE_PROTOBUF_HAS_TR1
+
+#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \
+    defined(GOOGLE_PROTOBUF_HAVE_HASH_SET)
+#else
+#define GOOGLE_PROTOBUF_MISSING_HASH
 #include <map>
 #include <set>
 #endif
@@ -51,7 +172,8 @@
 namespace google {
 namespace protobuf {
 
-#ifdef MISSING_HASH
+#ifdef GOOGLE_PROTOBUF_MISSING_HASH
+#undef GOOGLE_PROTOBUF_MISSING_HASH
 
 // This system doesn't have hash_map or hash_set.  Emulate them using map and
 // set.
@@ -88,24 +210,33 @@
 
 template <typename Key, typename Data,
           typename HashFcn = hash<Key>,
-          typename EqualKey = int >
-class hash_map : public std::map<Key, Data, HashFcn> {
+          typename EqualKey = std::equal_to<Key>,
+          typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map : public std::map<Key, Data, HashFcn, Alloc> {
+  typedef std::map<Key, Data, HashFcn, Alloc> BaseClass;
+
  public:
-  hash_map(int = 0) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(b, d) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
 template <typename Key,
           typename HashFcn = hash<Key>,
-          typename EqualKey = int >
+          typename EqualKey = std::equal_to<Key> >
 class hash_set : public std::set<Key, HashFcn> {
  public:
   hash_set(int = 0) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
 #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
 
 template <typename Key>
-struct hash : public HASH_NAMESPACE::hash_compare<Key> {
+struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
 };
 
 // MSVC's hash_compare<const char*> hashes based on the string contents but
@@ -119,31 +250,88 @@
 
 template <>
 struct hash<const char*>
-  : public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
+    : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
+
+#ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+
+template <typename Key, typename HashFcn, typename EqualKey>
+struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
+  InternalHashCompare() {}
+  InternalHashCompare(HashFcn hashfcn, EqualKey equalkey)
+      : hashfcn_(hashfcn), equalkey_(equalkey) {}
+  size_t operator()(const Key& key) const { return hashfcn_(key); }
+  bool operator()(const Key& key1, const Key& key2) const {
+    return !equalkey_(key1, key2);
+  }
+  HashFcn hashfcn_;
+  EqualKey equalkey_;
 };
 
 template <typename Key, typename Data,
           typename HashFcn = hash<Key>,
-          typename EqualKey = int >
-class hash_map : public HASH_NAMESPACE::hash_map<
-    Key, Data, HashFcn> {
+          typename EqualKey = std::equal_to<Key>,
+          typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+          Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> {
+  typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+      Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> BaseClass;
+
  public:
-  hash_map(int = 0) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(), const Alloc& d = Alloc())
+      : BaseClass(InternalHashCompare<Key, HashFcn, EqualKey>(b, c), d) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
-template <typename Key,
-          typename HashFcn = hash<Key>,
-          typename EqualKey = int >
-class hash_set : public HASH_NAMESPACE::hash_set<
-    Key, HashFcn> {
+template <typename Key, typename HashFcn = hash<Key>,
+          typename EqualKey = std::equal_to<Key> >
+class hash_set
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+          Key, InternalHashCompare<Key, HashFcn, EqualKey> > {
  public:
   hash_set(int = 0) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
-#else
+#else  // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+
+template <typename Key, typename Data,
+          typename HashFcn = hash<Key>,
+          typename EqualKey = std::equal_to<Key>,
+          typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+          Key, Data, HashFcn, EqualKey, Alloc> {
+  typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+      Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
+
+ public:
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
+};
+
+template <typename Key, typename HashFcn = hash<Key>,
+          typename EqualKey = std::equal_to<Key> >
+class hash_set
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+          Key, HashFcn, EqualKey> {
+ public:
+  hash_set(int = 0) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
+};
+#endif  // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
+
+#else  // defined(_MSC_VER) && !defined(_STLPORT_VERSION)
 
 template <typename Key>
-struct hash : public HASH_NAMESPACE::hash<Key> {
+struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
 };
 
 template <typename Key>
@@ -166,25 +354,43 @@
   }
 };
 
+template<>
+struct hash<bool> {
+  size_t operator()(bool x) const {
+    return static_cast<size_t>(x);
+  }
+};
+
 template <typename Key, typename Data,
           typename HashFcn = hash<Key>,
-          typename EqualKey = std::equal_to<Key> >
-class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
-    Key, Data, HashFcn, EqualKey> {
+          typename EqualKey = std::equal_to<Key>,
+          typename Alloc = std::allocator< std::pair<const Key, Data> > >
+class hash_map
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+          Key, Data, HashFcn, EqualKey, Alloc> {
+  typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
+      Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
+
  public:
-  hash_map(int = 0) {}
+  hash_map(int a = 0, const HashFcn& b = HashFcn(),
+           const EqualKey& c = EqualKey(),
+           const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
-template <typename Key,
-          typename HashFcn = hash<Key>,
+template <typename Key, typename HashFcn = hash<Key>,
           typename EqualKey = std::equal_to<Key> >
-class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
-    Key, HashFcn, EqualKey> {
+class hash_set
+    : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
+          Key, HashFcn, EqualKey> {
  public:
   hash_set(int = 0) {}
+
+  HashFcn hash_function() const { return HashFcn(); }
 };
 
-#endif
+#endif  // !GOOGLE_PROTOBUF_MISSING_HASH
 
 template <>
 struct hash<string> {
@@ -194,7 +400,7 @@
 
   static const size_t bucket_size = 4;
   static const size_t min_buckets = 8;
-  inline size_t operator()(const string& a, const string& b) const {
+  inline bool operator()(const string& a, const string& b) const {
     return a < b;
   }
 };
@@ -212,7 +418,7 @@
 
   static const size_t bucket_size = 4;
   static const size_t min_buckets = 8;
-  inline size_t operator()(const pair<First, Second>& a,
+  inline bool operator()(const pair<First, Second>& a,
                            const pair<First, Second>& b) const {
     return a < b;
   }
diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc
new file mode 100644
index 0000000..3a36b4b
--- /dev/null
+++ b/src/google/protobuf/stubs/int128.cc
@@ -0,0 +1,201 @@
+// 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.
+
+#include <google/protobuf/stubs/int128.h>
+
+#include <iomanip>
+#include <ostream>  // NOLINT(readability/streams)
+#include <sstream>
+
+namespace google {
+namespace protobuf {
+
+const uint128_pod kuint128max = {
+    static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)),
+    static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF))
+};
+
+// Returns the 0-based position of the last set bit (i.e., most significant bit)
+// in the given uint64. The argument may not be 0.
+//
+// For example:
+//   Given: 5 (decimal) == 101 (binary)
+//   Returns: 2
+#define STEP(T, n, pos, sh)                   \
+  do {                                        \
+    if ((n) >= (static_cast<T>(1) << (sh))) { \
+      (n) = (n) >> (sh);                      \
+      (pos) |= (sh);                          \
+    }                                         \
+  } while (0)
+static inline int Fls64(uint64 n) {
+  GOOGLE_DCHECK_NE(0, n);
+  int pos = 0;
+  STEP(uint64, n, pos, 0x20);
+  uint32 n32 = n;
+  STEP(uint32, n32, pos, 0x10);
+  STEP(uint32, n32, pos, 0x08);
+  STEP(uint32, n32, pos, 0x04);
+  return pos + ((GOOGLE_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
+}
+#undef STEP
+
+// Like Fls64() above, but returns the 0-based position of the last set bit
+// (i.e., most significant bit) in the given uint128. The argument may not be 0.
+static inline int Fls128(uint128 n) {
+  if (uint64 hi = Uint128High64(n)) {
+    return Fls64(hi) + 64;
+  }
+  return Fls64(Uint128Low64(n));
+}
+
+// Long division/modulo for uint128 implemented using the shift-subtract
+// division algorithm adapted from:
+// http://stackoverflow.com/questions/5386377/division-without-using
+void uint128::DivModImpl(uint128 dividend, uint128 divisor,
+                         uint128* quotient_ret, uint128* remainder_ret) {
+  if (divisor == 0) {
+    GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
+                      << ", lo=" << dividend.lo_;
+  }
+
+  if (divisor > dividend) {
+    *quotient_ret = 0;
+    *remainder_ret = dividend;
+    return;
+  }
+
+  if (divisor == dividend) {
+    *quotient_ret = 1;
+    *remainder_ret = 0;
+    return;
+  }
+
+  uint128 denominator = divisor;
+  uint128 position = 1;
+  uint128 quotient = 0;
+
+  // Left aligns the MSB of the denominator and the dividend.
+  int shift = Fls128(dividend) - Fls128(denominator);
+  denominator <<= shift;
+  position <<= shift;
+
+  // Uses shift-subtract algorithm to divide dividend by denominator. The
+  // remainder will be left in dividend.
+  while (position > 0) {
+    if (dividend >= denominator) {
+      dividend -= denominator;
+      quotient |= position;
+    }
+    position >>= 1;
+    denominator >>= 1;
+  }
+
+  *quotient_ret = quotient;
+  *remainder_ret = dividend;
+}
+
+uint128& uint128::operator/=(const uint128& divisor) {
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(*this, divisor, &quotient, &remainder);
+  *this = quotient;
+  return *this;
+}
+uint128& uint128::operator%=(const uint128& divisor) {
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(*this, divisor, &quotient, &remainder);
+  *this = remainder;
+  return *this;
+}
+
+std::ostream& operator<<(std::ostream& o, const uint128& b) {
+  std::ios_base::fmtflags flags = o.flags();
+
+  // Select a divisor which is the largest power of the base < 2^64.
+  uint128 div;
+  std::streamsize div_base_log;
+  switch (flags & std::ios::basefield) {
+    case std::ios::hex:
+      div = GOOGLE_ULONGLONG(0x1000000000000000);  // 16^15
+      div_base_log = 15;
+      break;
+    case std::ios::oct:
+      div = GOOGLE_ULONGLONG(01000000000000000000000);  // 8^21
+      div_base_log = 21;
+      break;
+    default:  // std::ios::dec
+      div = GOOGLE_ULONGLONG(10000000000000000000);  // 10^19
+      div_base_log = 19;
+      break;
+  }
+
+  // Now piece together the uint128 representation from three chunks of
+  // the original value, each less than "div" and therefore representable
+  // as a uint64.
+  std::ostringstream os;
+  std::ios_base::fmtflags copy_mask =
+      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
+  os.setf(flags & copy_mask, copy_mask);
+  uint128 high = b;
+  uint128 low;
+  uint128::DivModImpl(high, div, &high, &low);
+  uint128 mid;
+  uint128::DivModImpl(high, div, &high, &mid);
+  if (high.lo_ != 0) {
+    os << high.lo_;
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+    os << mid.lo_;
+    os << std::setw(div_base_log);
+  } else if (mid.lo_ != 0) {
+    os << mid.lo_;
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+  }
+  os << low.lo_;
+  std::string rep = os.str();
+
+  // Add the requisite padding.
+  std::streamsize width = o.width(0);
+  if (width > rep.size()) {
+    if ((flags & std::ios::adjustfield) == std::ios::left) {
+      rep.append(width - rep.size(), o.fill());
+    } else {
+      rep.insert(static_cast<std::string::size_type>(0),
+                 width - rep.size(), o.fill());
+    }
+  }
+
+  // Stream the final representation in a single "<<" call.
+  return o << rep;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/int128.h b/src/google/protobuf/stubs/int128.h
new file mode 100644
index 0000000..1499bb7
--- /dev/null
+++ b/src/google/protobuf/stubs/int128.h
@@ -0,0 +1,383 @@
+// 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.
+#ifndef GOOGLE_PROTOBUF_STUBS_INT128_H_
+#define GOOGLE_PROTOBUF_STUBS_INT128_H_
+
+#include <google/protobuf/stubs/common.h>
+
+#include <iosfwd>
+
+namespace google {
+namespace protobuf {
+
+struct uint128_pod;
+
+// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
+// available.
+#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
+# define UINT128_CONSTEXPR constexpr
+#else
+# define UINT128_CONSTEXPR
+#endif
+
+// An unsigned 128-bit integer type. Thread-compatible.
+class LIBPROTOBUF_EXPORT uint128 {
+ public:
+  UINT128_CONSTEXPR uint128();  // Sets to 0, but don't trust on this behavior.
+  UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom);
+#ifndef SWIG
+  UINT128_CONSTEXPR uint128(int bottom);
+  UINT128_CONSTEXPR uint128(uint32 bottom);   // Top 96 bits = 0
+#endif
+  UINT128_CONSTEXPR uint128(uint64 bottom);   // hi_ = 0
+  UINT128_CONSTEXPR uint128(const uint128_pod &val);
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  void Initialize(uint64 top, uint64 bottom);
+
+  // Arithmetic operators.
+  uint128& operator+=(const uint128& b);
+  uint128& operator-=(const uint128& b);
+  uint128& operator*=(const uint128& b);
+  // Long division/modulo for uint128.
+  uint128& operator/=(const uint128& b);
+  uint128& operator%=(const uint128& b);
+  uint128 operator++(int);
+  uint128 operator--(int);
+  uint128& operator<<=(int);
+  uint128& operator>>=(int);
+  uint128& operator&=(const uint128& b);
+  uint128& operator|=(const uint128& b);
+  uint128& operator^=(const uint128& b);
+  uint128& operator++();
+  uint128& operator--();
+
+  friend uint64 Uint128Low64(const uint128& v);
+  friend uint64 Uint128High64(const uint128& v);
+
+  // We add "std::" to avoid including all of port.h.
+  LIBPROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
+                                                     const uint128& b);
+
+ private:
+  static void DivModImpl(uint128 dividend, uint128 divisor,
+                         uint128* quotient_ret, uint128* remainder_ret);
+
+  // Little-endian memory order optimizations can benefit from
+  // having lo_ first, hi_ last.
+  // See util/endian/endian.h and Load128/Store128 for storing a uint128.
+  uint64        lo_;
+  uint64        hi_;
+
+  // Not implemented, just declared for catching automatic type conversions.
+  uint128(uint8);
+  uint128(uint16);
+  uint128(float v);
+  uint128(double v);
+};
+
+// This is a POD form of uint128 which can be used for static variables which
+// need to be operated on as uint128.
+struct uint128_pod {
+  // Note: The ordering of fields is different than 'class uint128' but the
+  // same as its 2-arg constructor.  This enables more obvious initialization
+  // of static instances, which is the primary reason for this struct in the
+  // first place.  This does not seem to defeat any optimizations wrt
+  // operations involving this struct.
+  uint64 hi;
+  uint64 lo;
+};
+
+LIBPROTOBUF_EXPORT extern const uint128_pod kuint128max;
+
+// allow uint128 to be logged
+LIBPROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                                   const uint128& b);
+
+// Methods to access low and high pieces of 128-bit value.
+// Defined externally from uint128 to facilitate conversion
+// to native 128-bit types when compilers support them.
+inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
+inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
+
+// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
+
+// --------------------------------------------------------------------------
+//                      Implementation details follow
+// --------------------------------------------------------------------------
+inline bool operator==(const uint128& lhs, const uint128& rhs) {
+  return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
+          Uint128High64(lhs) == Uint128High64(rhs));
+}
+inline bool operator!=(const uint128& lhs, const uint128& rhs) {
+  return !(lhs == rhs);
+}
+
+inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
+inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom)
+    : lo_(bottom), hi_(top) {}
+inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
+    : lo_(v.lo), hi_(v.hi) {}
+inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom)
+    : lo_(bottom), hi_(0) {}
+#ifndef SWIG
+inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom)
+    : lo_(bottom), hi_(0) {}
+inline UINT128_CONSTEXPR uint128::uint128(int bottom)
+    : lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {}
+#endif
+
+#undef UINT128_CONSTEXPR
+
+inline void uint128::Initialize(uint64 top, uint64 bottom) {
+  hi_ = top;
+  lo_ = bottom;
+}
+
+// Comparison operators.
+
+#define CMP128(op)                                                \
+inline bool operator op(const uint128& lhs, const uint128& rhs) { \
+  return (Uint128High64(lhs) == Uint128High64(rhs)) ?             \
+      (Uint128Low64(lhs) op Uint128Low64(rhs)) :                  \
+      (Uint128High64(lhs) op Uint128High64(rhs));                 \
+}
+
+CMP128(<)
+CMP128(>)
+CMP128(>=)
+CMP128(<=)
+
+#undef CMP128
+
+// Unary operators
+
+inline uint128 operator-(const uint128& val) {
+  const uint64 hi_flip = ~Uint128High64(val);
+  const uint64 lo_flip = ~Uint128Low64(val);
+  const uint64 lo_add = lo_flip + 1;
+  if (lo_add < lo_flip) {
+    return uint128(hi_flip + 1, lo_add);
+  }
+  return uint128(hi_flip, lo_add);
+}
+
+inline bool operator!(const uint128& val) {
+  return !Uint128High64(val) && !Uint128Low64(val);
+}
+
+// Logical operators.
+
+inline uint128 operator~(const uint128& val) {
+  return uint128(~Uint128High64(val), ~Uint128Low64(val));
+}
+
+#define LOGIC128(op)                                                 \
+inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
+  return uint128(Uint128High64(lhs) op Uint128High64(rhs),           \
+                 Uint128Low64(lhs) op Uint128Low64(rhs));            \
+}
+
+LOGIC128(|)
+LOGIC128(&)
+LOGIC128(^)
+
+#undef LOGIC128
+
+#define LOGICASSIGN128(op)                                   \
+inline uint128& uint128::operator op(const uint128& other) { \
+  hi_ op other.hi_;                                          \
+  lo_ op other.lo_;                                          \
+  return *this;                                              \
+}
+
+LOGICASSIGN128(|=)
+LOGICASSIGN128(&=)
+LOGICASSIGN128(^=)
+
+#undef LOGICASSIGN128
+
+// Shift operators.
+
+inline uint128 operator<<(const uint128& val, int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount == 0) {
+      return val;
+    }
+    uint64 new_hi = (Uint128High64(val) << amount) |
+                    (Uint128Low64(val) >> (64 - amount));
+    uint64 new_lo = Uint128Low64(val) << amount;
+    return uint128(new_hi, new_lo);
+  } else if (amount < 128) {
+    return uint128(Uint128Low64(val) << (amount - 64), 0);
+  } else {
+    return uint128(0, 0);
+  }
+}
+
+inline uint128 operator>>(const uint128& val, int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount == 0) {
+      return val;
+    }
+    uint64 new_hi = Uint128High64(val) >> amount;
+    uint64 new_lo = (Uint128Low64(val) >> amount) |
+                    (Uint128High64(val) << (64 - amount));
+    return uint128(new_hi, new_lo);
+  } else if (amount < 128) {
+    return uint128(0, Uint128High64(val) >> (amount - 64));
+  } else {
+    return uint128(0, 0);
+  }
+}
+
+inline uint128& uint128::operator<<=(int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
+      lo_ = lo_ << amount;
+    }
+  } else if (amount < 128) {
+    hi_ = lo_ << (amount - 64);
+    lo_ = 0;
+  } else {
+    hi_ = 0;
+    lo_ = 0;
+  }
+  return *this;
+}
+
+inline uint128& uint128::operator>>=(int amount) {
+  // uint64 shifts of >= 64 are undefined, so we will need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
+      hi_ = hi_ >> amount;
+    }
+  } else if (amount < 128) {
+    lo_ = hi_ >> (amount - 64);
+    hi_ = 0;
+  } else {
+    lo_ = 0;
+    hi_ = 0;
+  }
+  return *this;
+}
+
+inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) += rhs;
+}
+
+inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) -= rhs;
+}
+
+inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) *= rhs;
+}
+
+inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) /= rhs;
+}
+
+inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
+  return uint128(lhs) %= rhs;
+}
+
+inline uint128& uint128::operator+=(const uint128& b) {
+  hi_ += b.hi_;
+  uint64 lolo = lo_ + b.lo_;
+  if (lolo < lo_)
+    ++hi_;
+  lo_ = lolo;
+  return *this;
+}
+
+inline uint128& uint128::operator-=(const uint128& b) {
+  hi_ -= b.hi_;
+  if (b.lo_ > lo_)
+    --hi_;
+  lo_ -= b.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator*=(const uint128& b) {
+  uint64 a96 = hi_ >> 32;
+  uint64 a64 = hi_ & 0xffffffffu;
+  uint64 a32 = lo_ >> 32;
+  uint64 a00 = lo_ & 0xffffffffu;
+  uint64 b96 = b.hi_ >> 32;
+  uint64 b64 = b.hi_ & 0xffffffffu;
+  uint64 b32 = b.lo_ >> 32;
+  uint64 b00 = b.lo_ & 0xffffffffu;
+  // multiply [a96 .. a00] x [b96 .. b00]
+  // terms higher than c96 disappear off the high side
+  // terms c96 and c64 are safe to ignore carry bit
+  uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
+  uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64;
+  this->hi_ = (c96 << 32) + c64;
+  this->lo_ = 0;
+  // add terms after this one at a time to capture carry
+  *this += uint128(a32 * b00) << 32;
+  *this += uint128(a00 * b32) << 32;
+  *this += a00 * b00;
+  return *this;
+}
+
+inline uint128 uint128::operator++(int) {
+  uint128 tmp(*this);
+  *this += 1;
+  return tmp;
+}
+
+inline uint128 uint128::operator--(int) {
+  uint128 tmp(*this);
+  *this -= 1;
+  return tmp;
+}
+
+inline uint128& uint128::operator++() {
+  *this += 1;
+  return *this;
+}
+
+inline uint128& uint128::operator--() {
+  *this -= 1;
+  return *this;
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_INT128_H_
diff --git a/src/google/protobuf/stubs/int128_unittest.cc b/src/google/protobuf/stubs/int128_unittest.cc
new file mode 100644
index 0000000..5d33292
--- /dev/null
+++ b/src/google/protobuf/stubs/int128_unittest.cc
@@ -0,0 +1,513 @@
+// 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.
+
+#include <google/protobuf/stubs/int128.h>
+
+#include <algorithm>
+#include <sstream>
+#include <utility>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+TEST(Int128, AllTests) {
+  uint128 zero(0);
+  uint128 one(1);
+  uint128 one_2arg(0, 1);
+  uint128 two(0, 2);
+  uint128 three(0, 3);
+  uint128 big(2000, 2);
+  uint128 big_minus_one(2000, 1);
+  uint128 bigger(2001, 1);
+  uint128 biggest(kuint128max);
+  uint128 high_low(1, 0);
+  uint128 low_high(0, kuint64max);
+  EXPECT_LT(one, two);
+  EXPECT_GT(two, one);
+  EXPECT_LT(one, big);
+  EXPECT_LT(one, big);
+  EXPECT_EQ(one, one_2arg);
+  EXPECT_NE(one, two);
+  EXPECT_GT(big, one);
+  EXPECT_GE(big, two);
+  EXPECT_GE(big, big_minus_one);
+  EXPECT_GT(big, big_minus_one);
+  EXPECT_LT(big_minus_one, big);
+  EXPECT_LE(big_minus_one, big);
+  EXPECT_NE(big_minus_one, big);
+  EXPECT_LT(big, biggest);
+  EXPECT_LE(big, biggest);
+  EXPECT_GT(biggest, big);
+  EXPECT_GE(biggest, big);
+  EXPECT_EQ(big, ~~big);
+  EXPECT_EQ(one, one | one);
+  EXPECT_EQ(big, big | big);
+  EXPECT_EQ(one, one | zero);
+  EXPECT_EQ(one, one & one);
+  EXPECT_EQ(big, big & big);
+  EXPECT_EQ(zero, one & zero);
+  EXPECT_EQ(zero, big & ~big);
+  EXPECT_EQ(zero, one ^ one);
+  EXPECT_EQ(zero, big ^ big);
+  EXPECT_EQ(one, one ^ zero);
+
+  // Shift operators.
+  EXPECT_EQ(big, big << 0);
+  EXPECT_EQ(big, big >> 0);
+  EXPECT_GT(big << 1, big);
+  EXPECT_LT(big >> 1, big);
+  EXPECT_EQ(big, (big << 10) >> 10);
+  EXPECT_EQ(big, (big >> 1) << 1);
+  EXPECT_EQ(one, (one << 80) >> 80);
+  EXPECT_EQ(zero, (one >> 80) << 80);
+  EXPECT_EQ(zero, big >> 128);
+  EXPECT_EQ(zero, big << 128);
+
+  // Shift assignments.
+  uint128 big_copy = big;
+  EXPECT_EQ(big << 0, big_copy <<= 0);
+  big_copy = big;
+  EXPECT_EQ(big >> 0, big_copy >>= 0);
+  big_copy = big;
+  EXPECT_EQ(big << 1, big_copy <<= 1);
+  big_copy = big;
+  EXPECT_EQ(big >> 1, big_copy >>= 1);
+  big_copy = big;
+  EXPECT_EQ(big << 10, big_copy <<= 10);
+  big_copy = big;
+  EXPECT_EQ(big >> 10, big_copy >>= 10);
+  big_copy = big;
+  EXPECT_EQ(big << 64, big_copy <<= 64);
+  big_copy = big;
+  EXPECT_EQ(big >> 64, big_copy >>= 64);
+  big_copy = big;
+  EXPECT_EQ(big << 73, big_copy <<= 73);
+  big_copy = big;
+  EXPECT_EQ(big >> 73, big_copy >>= 73);
+  big_copy = big;
+  EXPECT_EQ(big << 128, big_copy <<= 128);
+  big_copy = big;
+  EXPECT_EQ(big >> 128, big_copy >>= 128);
+
+  EXPECT_EQ(Uint128High64(biggest), kuint64max);
+  EXPECT_EQ(Uint128Low64(biggest), kuint64max);
+  EXPECT_EQ(zero + one, one);
+  EXPECT_EQ(one + one, two);
+  EXPECT_EQ(big_minus_one + one, big);
+  EXPECT_EQ(one - one, zero);
+  EXPECT_EQ(one - zero, one);
+  EXPECT_EQ(zero - one, biggest);
+  EXPECT_EQ(big - big, zero);
+  EXPECT_EQ(big - one, big_minus_one);
+  EXPECT_EQ(big + kuint64max, bigger);
+  EXPECT_EQ(biggest + 1, zero);
+  EXPECT_EQ(zero - 1, biggest);
+  EXPECT_EQ(high_low - one, low_high);
+  EXPECT_EQ(low_high + one, high_low);
+  EXPECT_EQ(Uint128High64((uint128(1) << 64) - 1), 0);
+  EXPECT_EQ(Uint128Low64((uint128(1) << 64) - 1), kuint64max);
+  EXPECT_TRUE(!!one);
+  EXPECT_TRUE(!!high_low);
+  EXPECT_FALSE(!!zero);
+  EXPECT_FALSE(!one);
+  EXPECT_FALSE(!high_low);
+  EXPECT_TRUE(!zero);
+  EXPECT_TRUE(zero == 0);
+  EXPECT_FALSE(zero != 0);
+  EXPECT_FALSE(one == 0);
+  EXPECT_TRUE(one != 0);
+
+  uint128 test = zero;
+  EXPECT_EQ(++test, one);
+  EXPECT_EQ(test, one);
+  EXPECT_EQ(test++, one);
+  EXPECT_EQ(test, two);
+  EXPECT_EQ(test -= 2, zero);
+  EXPECT_EQ(test, zero);
+  EXPECT_EQ(test += 2, two);
+  EXPECT_EQ(test, two);
+  EXPECT_EQ(--test, one);
+  EXPECT_EQ(test, one);
+  EXPECT_EQ(test--, one);
+  EXPECT_EQ(test, zero);
+  EXPECT_EQ(test |= three, three);
+  EXPECT_EQ(test &= one, one);
+  EXPECT_EQ(test ^= three, two);
+  EXPECT_EQ(test >>= 1, one);
+  EXPECT_EQ(test <<= 1, two);
+
+  EXPECT_EQ(big, -(-big));
+  EXPECT_EQ(two, -((-one) - 1));
+  EXPECT_EQ(kuint128max, -one);
+  EXPECT_EQ(zero, -zero);
+
+  GOOGLE_LOG(INFO) << one;
+  GOOGLE_LOG(INFO) << big_minus_one;
+}
+
+TEST(Int128, PodTests) {
+  uint128_pod pod = { 12345, 67890 };
+  uint128 from_pod(pod);
+  EXPECT_EQ(12345, Uint128High64(from_pod));
+  EXPECT_EQ(67890, Uint128Low64(from_pod));
+
+  uint128 zero(0);
+  uint128_pod zero_pod = {0, 0};
+  uint128 one(1);
+  uint128_pod one_pod = {0, 1};
+  uint128 two(2);
+  uint128_pod two_pod = {0, 2};
+  uint128 three(3);
+  uint128_pod three_pod = {0, 3};
+  uint128 big(1, 0);
+  uint128_pod big_pod = {1, 0};
+
+  EXPECT_EQ(zero, zero_pod);
+  EXPECT_EQ(zero_pod, zero);
+  EXPECT_EQ(zero_pod, zero_pod);
+  EXPECT_EQ(one, one_pod);
+  EXPECT_EQ(one_pod, one);
+  EXPECT_EQ(one_pod, one_pod);
+  EXPECT_EQ(two, two_pod);
+  EXPECT_EQ(two_pod, two);
+  EXPECT_EQ(two_pod, two_pod);
+
+  EXPECT_NE(one, two_pod);
+  EXPECT_NE(one_pod, two);
+  EXPECT_NE(one_pod, two_pod);
+
+  EXPECT_LT(one, two_pod);
+  EXPECT_LT(one_pod, two);
+  EXPECT_LT(one_pod, two_pod);
+  EXPECT_LE(one, one_pod);
+  EXPECT_LE(one_pod, one);
+  EXPECT_LE(one_pod, one_pod);
+  EXPECT_LE(one, two_pod);
+  EXPECT_LE(one_pod, two);
+  EXPECT_LE(one_pod, two_pod);
+
+  EXPECT_GT(two, one_pod);
+  EXPECT_GT(two_pod, one);
+  EXPECT_GT(two_pod, one_pod);
+  EXPECT_GE(two, two_pod);
+  EXPECT_GE(two_pod, two);
+  EXPECT_GE(two_pod, two_pod);
+  EXPECT_GE(two, one_pod);
+  EXPECT_GE(two_pod, one);
+  EXPECT_GE(two_pod, one_pod);
+
+  EXPECT_EQ(three, one | two_pod);
+  EXPECT_EQ(three, one_pod | two);
+  EXPECT_EQ(three, one_pod | two_pod);
+  EXPECT_EQ(one, three & one_pod);
+  EXPECT_EQ(one, three_pod & one);
+  EXPECT_EQ(one, three_pod & one_pod);
+  EXPECT_EQ(two, three ^ one_pod);
+  EXPECT_EQ(two, three_pod ^ one);
+  EXPECT_EQ(two, three_pod ^ one_pod);
+  EXPECT_EQ(two, three & (~one));
+  EXPECT_EQ(three, ~~three);
+
+  EXPECT_EQ(two, two_pod << 0);
+  EXPECT_EQ(two, one_pod << 1);
+  EXPECT_EQ(big, one_pod << 64);
+  EXPECT_EQ(zero, one_pod << 128);
+  EXPECT_EQ(two, two_pod >> 0);
+  EXPECT_EQ(one, two_pod >> 1);
+  EXPECT_EQ(one, big_pod >> 64);
+
+  EXPECT_EQ(one, zero + one_pod);
+  EXPECT_EQ(one, zero_pod + one);
+  EXPECT_EQ(one, zero_pod + one_pod);
+  EXPECT_EQ(one, two - one_pod);
+  EXPECT_EQ(one, two_pod - one);
+  EXPECT_EQ(one, two_pod - one_pod);
+}
+
+TEST(Int128, OperatorAssignReturnRef) {
+  uint128 v(1);
+  (v += 4) -= 3;
+  EXPECT_EQ(2, v);
+}
+
+TEST(Int128, Multiply) {
+  uint128 a, b, c;
+
+  // Zero test.
+  a = 0;
+  b = 0;
+  c = a * b;
+  EXPECT_EQ(0, c);
+
+  // Max carries.
+  a = uint128(0) - 1;
+  b = uint128(0) - 1;
+  c = a * b;
+  EXPECT_EQ(1, c);
+
+  // Self-operation with max carries.
+  c = uint128(0) - 1;
+  c *= c;
+  EXPECT_EQ(1, c);
+
+  // 1-bit x 1-bit.
+  for (int i = 0; i < 64; ++i) {
+    for (int j = 0; j < 64; ++j) {
+      a = uint128(1) << i;
+      b = uint128(1) << j;
+      c = a * b;
+      EXPECT_EQ(uint128(1) << (i+j), c);
+    }
+  }
+
+  // Verified with dc.
+  a = uint128(GOOGLE_ULONGLONG(0xffffeeeeddddcccc),
+              GOOGLE_ULONGLONG(0xbbbbaaaa99998888));
+  b = uint128(GOOGLE_ULONGLONG(0x7777666655554444),
+              GOOGLE_ULONGLONG(0x3333222211110000));
+  c = a * b;
+  EXPECT_EQ(uint128(GOOGLE_ULONGLONG(0x530EDA741C71D4C3),
+                    GOOGLE_ULONGLONG(0xBF25975319080000)), c);
+  EXPECT_EQ(0, c - b * a);
+  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+
+  // Verified with dc.
+  a = uint128(GOOGLE_ULONGLONG(0x0123456789abcdef),
+              GOOGLE_ULONGLONG(0xfedcba9876543210));
+  b = uint128(GOOGLE_ULONGLONG(0x02468ace13579bdf),
+              GOOGLE_ULONGLONG(0xfdb97531eca86420));
+  c = a * b;
+  EXPECT_EQ(uint128(GOOGLE_ULONGLONG(0x97a87f4f261ba3f2),
+                    GOOGLE_ULONGLONG(0x342d0bbf48948200)), c);
+  EXPECT_EQ(0, c - b * a);
+  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+}
+
+TEST(Int128, AliasTests) {
+  uint128 x1(1, 2);
+  uint128 x2(2, 4);
+  x1 += x1;
+  EXPECT_EQ(x2, x1);
+
+  uint128 x3(1, static_cast<uint64>(1) << 63);
+  uint128 x4(3, 0);
+  x3 += x3;
+  EXPECT_EQ(x4, x3);
+}
+
+#ifdef PROTOBUF_HAS_DEATH_TEST
+TEST(Int128, DivideByZeroCheckFails) {
+  uint128 a = 0;
+  uint128 b = 0;
+  EXPECT_DEATH(a / b, "Division or mod by zero:");
+  a = 123;
+  EXPECT_DEATH(a / b, "Division or mod by zero:");
+}
+
+TEST(Int128, ModByZeroCheckFails) {
+  uint128 a = 0;
+  uint128 b = 0;
+  EXPECT_DEATH(a % b, "Division or mod by zero:");
+  a = 123;
+  EXPECT_DEATH(a % b, "Division or mod by zero:");
+}
+#endif  // PROTOBUF_HAS_DEATH_TEST
+
+TEST(Int128, DivideAndMod) {
+  // a := q * b + r
+  uint128 a, b, q, r;
+
+  // Zero test.
+  a = 0;
+  b = 123;
+  q = a / b;
+  r = a % b;
+  EXPECT_EQ(0, q);
+  EXPECT_EQ(0, r);
+
+  a = uint128(GOOGLE_ULONGLONG(0x530eda741c71d4c3),
+              GOOGLE_ULONGLONG(0xbf25975319080000));
+  q = uint128(GOOGLE_ULONGLONG(0x4de2cab081),
+              GOOGLE_ULONGLONG(0x14c34ab4676e4bab));
+  b = uint128(0x1110001);
+  r = uint128(0x3eb455);
+  ASSERT_EQ(a, q * b + r);  // Sanity-check.
+
+  uint128 result_q, result_r;
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(q, result_q);
+  EXPECT_EQ(r, result_r);
+
+  // Try the other way around.
+  swap(q, b);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(q, result_q);
+  EXPECT_EQ(r, result_r);
+  // Restore.
+  swap(b, q);
+
+  // Dividend < divisor; result should be q:0 r:<dividend>.
+  swap(a, b);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(0, result_q);
+  EXPECT_EQ(a, result_r);
+  // Try the other way around.
+  swap(a, q);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(0, result_q);
+  EXPECT_EQ(a, result_r);
+  // Restore.
+  swap(q, a);
+  swap(b, a);
+
+  // Try a large remainder.
+  b = a / 2 + 1;
+  uint128 expected_r(GOOGLE_ULONGLONG(0x29876d3a0e38ea61),
+                     GOOGLE_ULONGLONG(0xdf92cba98c83ffff));
+  // Sanity checks.
+  ASSERT_EQ(a / 2 - 1, expected_r);
+  ASSERT_EQ(a, b + expected_r);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(1, result_q);
+  EXPECT_EQ(expected_r, result_r);
+}
+
+static uint64 RandomUint64() {
+  uint64 v1 = rand();
+  uint64 v2 = rand();
+  uint64 v3 = rand();
+  return v1 * v2 + v3;
+}
+
+TEST(Int128, DivideAndModRandomInputs) {
+  const int kNumIters = 1 << 18;
+  for (int i = 0; i < kNumIters; ++i) {
+    const uint128 a(RandomUint64(), RandomUint64());
+    const uint128 b(RandomUint64(), RandomUint64());
+    if (b == 0) {
+      continue;  // Avoid a div-by-zero.
+    }
+    const uint128 q = a / b;
+    const uint128 r = a % b;
+    ASSERT_EQ(a, b * q + r);
+  }
+}
+
+#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
+TEST(Int128, ConstexprTest) {
+  constexpr uint128 zero;
+  constexpr uint128 one = 1;
+  constexpr uint128_pod pod = {2, 3};
+  constexpr uint128 from_pod = pod;
+  constexpr uint128 minus_two = -2;
+  EXPECT_EQ(one, uint128(1));
+  EXPECT_EQ(from_pod, uint128(2, 3));
+  EXPECT_EQ(minus_two, uint128(-1ULL, -2ULL));
+}
+
+TEST(Int128, Traits) {
+  EXPECT_TRUE(std::is_trivially_copy_constructible<uint128>::value);
+  EXPECT_TRUE(std::is_trivially_copy_assignable<uint128>::value);
+  EXPECT_TRUE(std::is_trivially_destructible<uint128>::value);
+}
+#endif  // GOOGLE_PROTOBUF_HAS_CONSTEXPR
+
+TEST(Int128, OStream) {
+  struct {
+    uint128 val;
+    std::ios_base::fmtflags flags;
+    std::streamsize width;
+    char fill;
+    const char* rep;
+  } cases[] = {
+        // zero with different bases
+        {uint128(0), std::ios::dec, 0, '_', "0"},
+        {uint128(0), std::ios::oct, 0, '_', "0"},
+        {uint128(0), std::ios::hex, 0, '_', "0"},
+        // crossover between lo_ and hi_
+        {uint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
+        {uint128(0, -1), std::ios::oct, 0, '_', "1777777777777777777777"},
+        {uint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
+        {uint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
+        {uint128(1, 0), std::ios::oct, 0, '_', "2000000000000000000000"},
+        {uint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
+        // just the top bit
+        {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::dec, 0, '_',
+         "170141183460469231731687303715884105728"},
+        {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::oct, 0, '_',
+         "2000000000000000000000000000000000000000000"},
+        {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::hex, 0, '_',
+         "80000000000000000000000000000000"},
+        // maximum uint128 value
+        {uint128(-1, -1), std::ios::dec, 0, '_',
+         "340282366920938463463374607431768211455"},
+        {uint128(-1, -1), std::ios::oct, 0, '_',
+         "3777777777777777777777777777777777777777777"},
+        {uint128(-1, -1), std::ios::hex, 0, '_',
+         "ffffffffffffffffffffffffffffffff"},
+        // uppercase
+        {uint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
+         "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
+        // showbase
+        {uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"},
+        {uint128(1), std::ios::oct | std::ios::showbase, 0, '_', "01"},
+        {uint128(1), std::ios::hex | std::ios::showbase, 0, '_', "0x1"},
+        // showbase does nothing on zero
+        {uint128(0), std::ios::dec | std::ios::showbase, 0, '_', "0"},
+        {uint128(0), std::ios::oct | std::ios::showbase, 0, '_', "0"},
+        {uint128(0), std::ios::hex | std::ios::showbase, 0, '_', "0"},
+        // showpos does nothing on unsigned types
+        {uint128(1), std::ios::dec | std::ios::showpos, 0, '_', "1"},
+        // padding
+        {uint128(9), std::ios::dec, 6, '_', "_____9"},
+        {uint128(12345), std::ios::dec, 6, '_', "_12345"},
+        // left adjustment
+        {uint128(9), std::ios::dec | std::ios::left, 6, '_', "9_____"},
+        {uint128(12345), std::ios::dec | std::ios::left, 6, '_', "12345_"},
+  };
+  for (size_t i = 0; i < GOOGLE_ARRAYSIZE(cases); ++i) {
+    ostringstream os;
+    os.flags(cases[i].flags);
+    os.width(cases[i].width);
+    os.fill(cases[i].fill);
+    os << cases[i].val;
+    EXPECT_EQ(cases[i].rep, os.str());
+  }
+}
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/logging.h b/src/google/protobuf/stubs/logging.h
new file mode 100644
index 0000000..f69605d
--- /dev/null
+++ b/src/google/protobuf/stubs/logging.h
@@ -0,0 +1,237 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_
+
+#include <google/protobuf/stubs/macros.h>
+#include <google/protobuf/stubs/port.h>
+
+// ===================================================================
+// emulates google3/base/logging.h
+
+namespace google {
+namespace protobuf {
+
+enum LogLevel {
+  LOGLEVEL_INFO,     // Informational.  This is never actually used by
+                     // libprotobuf.
+  LOGLEVEL_WARNING,  // Warns about issues that, although not technically a
+                     // problem now, could cause problems in the future.  For
+                     // example, a // warning will be printed when parsing a
+                     // message that is near the message size limit.
+  LOGLEVEL_ERROR,    // An error occurred which should never happen during
+                     // normal use.
+  LOGLEVEL_FATAL,    // An error occurred from which the library cannot
+                     // recover.  This usually indicates a programming error
+                     // in the code which calls the library, especially when
+                     // compiled in debug mode.
+
+#ifdef NDEBUG
+  LOGLEVEL_DFATAL = LOGLEVEL_ERROR
+#else
+  LOGLEVEL_DFATAL = LOGLEVEL_FATAL
+#endif
+};
+
+class StringPiece;
+namespace util {
+class Status;
+}
+class uint128;
+namespace internal {
+
+class LogFinisher;
+
+class LIBPROTOBUF_EXPORT LogMessage {
+ public:
+  LogMessage(LogLevel level, const char* filename, int line);
+  ~LogMessage();
+
+  LogMessage& operator<<(const std::string& value);
+  LogMessage& operator<<(const char* value);
+  LogMessage& operator<<(char value);
+  LogMessage& operator<<(int value);
+  LogMessage& operator<<(uint value);
+  LogMessage& operator<<(long value);
+  LogMessage& operator<<(unsigned long value);
+  LogMessage& operator<<(long long value);
+  LogMessage& operator<<(unsigned long long value);
+  LogMessage& operator<<(double value);
+  LogMessage& operator<<(void* value);
+  LogMessage& operator<<(const StringPiece& value);
+  LogMessage& operator<<(const ::google::protobuf::util::Status& status);
+  LogMessage& operator<<(const uint128& value);
+
+ private:
+  friend class LogFinisher;
+  void Finish();
+
+  LogLevel level_;
+  const char* filename_;
+  int line_;
+  std::string message_;
+};
+
+// Used to make the entire "LOG(BLAH) << etc." expression have a void return
+// type and print a newline after each message.
+class LIBPROTOBUF_EXPORT LogFinisher {
+ public:
+  void operator=(LogMessage& other);
+};
+
+template<typename T>
+bool IsOk(T status) { return status.ok(); }
+template<>
+inline bool IsOk(bool status) { return status; }
+
+}  // namespace internal
+
+// Undef everything in case we're being mixed with some other Google library
+// which already defined them itself.  Presumably all Google libraries will
+// support the same syntax for these so it should not be a big deal if they
+// end up using our definitions instead.
+#undef GOOGLE_LOG
+#undef GOOGLE_LOG_IF
+
+#undef GOOGLE_CHECK
+#undef GOOGLE_CHECK_OK
+#undef GOOGLE_CHECK_EQ
+#undef GOOGLE_CHECK_NE
+#undef GOOGLE_CHECK_LT
+#undef GOOGLE_CHECK_LE
+#undef GOOGLE_CHECK_GT
+#undef GOOGLE_CHECK_GE
+#undef GOOGLE_CHECK_NOTNULL
+
+#undef GOOGLE_DLOG
+#undef GOOGLE_DCHECK
+#undef GOOGLE_DCHECK_OK
+#undef GOOGLE_DCHECK_EQ
+#undef GOOGLE_DCHECK_NE
+#undef GOOGLE_DCHECK_LT
+#undef GOOGLE_DCHECK_LE
+#undef GOOGLE_DCHECK_GT
+#undef GOOGLE_DCHECK_GE
+
+#define GOOGLE_LOG(LEVEL)                                                 \
+  ::google::protobuf::internal::LogFinisher() =                           \
+    ::google::protobuf::internal::LogMessage(                             \
+      ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
+#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
+  !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
+
+#define GOOGLE_CHECK(EXPRESSION) \
+  GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
+#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(::google::protobuf::internal::IsOk(A))
+#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
+#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
+#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) <  (B))
+#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
+#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) >  (B))
+#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
+
+namespace internal {
+template<typename T>
+T* CheckNotNull(const char* /* file */, int /* line */,
+                const char* name, T* val) {
+  if (val == NULL) {
+    GOOGLE_LOG(FATAL) << name;
+  }
+  return val;
+}
+}  // namespace internal
+#define GOOGLE_CHECK_NOTNULL(A) \
+  ::google::protobuf::internal::CheckNotNull(\
+      __FILE__, __LINE__, "'" #A "' must not be NULL", (A))
+
+#ifdef NDEBUG
+
+#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false)
+
+#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
+#define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E))
+#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
+#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
+#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) <  (B))
+#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
+#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) >  (B))
+#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
+
+#else  // NDEBUG
+
+#define GOOGLE_DLOG GOOGLE_LOG
+
+#define GOOGLE_DCHECK    GOOGLE_CHECK
+#define GOOGLE_DCHECK_OK GOOGLE_CHECK_OK
+#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
+#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
+#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
+#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
+#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
+#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
+
+#endif  // !NDEBUG
+
+typedef void LogHandler(LogLevel level, const char* filename, int line,
+                        const std::string& message);
+
+// The protobuf library sometimes writes warning and error messages to
+// stderr.  These messages are primarily useful for developers, but may
+// also help end users figure out a problem.  If you would prefer that
+// these messages be sent somewhere other than stderr, call SetLogHandler()
+// to set your own handler.  This returns the old handler.  Set the handler
+// to NULL to ignore log messages (but see also LogSilencer, below).
+//
+// Obviously, SetLogHandler is not thread-safe.  You should only call it
+// at initialization time, and probably not from library code.  If you
+// simply want to suppress log messages temporarily (e.g. because you
+// have some code that tends to trigger them frequently and you know
+// the warnings are not important to you), use the LogSilencer class
+// below.
+LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
+
+// Create a LogSilencer if you want to temporarily suppress all log
+// messages.  As long as any LogSilencer objects exist, non-fatal
+// log messages will be discarded (the current LogHandler will *not*
+// be called).  Constructing a LogSilencer is thread-safe.  You may
+// accidentally suppress log messages occurring in another thread, but
+// since messages are generally for debugging purposes only, this isn't
+// a big deal.  If you want to intercept log messages, use SetLogHandler().
+class LIBPROTOBUF_EXPORT LogSilencer {
+ public:
+  LogSilencer();
+  ~LogSilencer();
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_LOGGING_H_
diff --git a/src/google/protobuf/stubs/macros.h b/src/google/protobuf/stubs/macros.h
new file mode 100644
index 0000000..0e9a9ec
--- /dev/null
+++ b/src/google/protobuf/stubs/macros.h
@@ -0,0 +1,168 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_MACROS_H__
+#define GOOGLE_PROTOBUF_MACROS_H__
+
+#include <google/protobuf/stubs/port.h>
+
+namespace google {
+namespace protobuf {
+
+#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
+#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
+  TypeName(const TypeName&);                           \
+  void operator=(const TypeName&)
+
+#undef GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS
+#define GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                           \
+  TypeName(const TypeName&);                            \
+  void operator=(const TypeName&)
+
+// ===================================================================
+// from google3/base/basictypes.h
+
+// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.
+//
+// GOOGLE_ARRAYSIZE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
+// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+//
+// Kudos to Jorg Brown for this simple and elegant implementation.
+
+#undef GOOGLE_ARRAYSIZE
+#define GOOGLE_ARRAYSIZE(a) \
+  ((sizeof(a) / sizeof(*(a))) / \
+   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+namespace internal {
+
+template <bool>
+struct CompileAssert {
+};
+
+}  // namespace internal
+
+#undef GOOGLE_COMPILE_ASSERT
+#if __cplusplus >= 201103L
+#define GOOGLE_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
+#else
+#define GOOGLE_COMPILE_ASSERT(expr, msg) \
+  ::google::protobuf::internal::CompileAssert<(bool(expr))> \
+          msg[bool(expr) ? 1 : -1]; \
+  (void)msg
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+//                               // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     COMPILE_ASSERT(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+#endif  // __cplusplus >= 201103L
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_MACROS_H__
diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h
deleted file mode 100644
index f5c9d6b..0000000
--- a/src/google/protobuf/stubs/map-util.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// from google3/util/gtl/map-util.h
-// Author: Anton Carver
-
-#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
-#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
-
-#include <google/protobuf/stubs/common.h>
-
-namespace google {
-namespace protobuf {
-
-// Perform a lookup in a map or hash_map.
-// If the key is present in the map then the value associated with that
-// key is returned, otherwise the value passed as a default is returned.
-template <class Collection>
-const typename Collection::value_type::second_type&
-FindWithDefault(const Collection& collection,
-                const typename Collection::value_type::first_type& key,
-                const typename Collection::value_type::second_type& value) {
-  typename Collection::const_iterator it = collection.find(key);
-  if (it == collection.end()) {
-    return value;
-  }
-  return it->second;
-}
-
-// Perform a lookup in a map or hash_map.
-// If the key is present a const pointer to the associated value is returned,
-// otherwise a NULL pointer is returned.
-template <class Collection>
-const typename Collection::value_type::second_type*
-FindOrNull(const Collection& collection,
-           const typename Collection::value_type::first_type& key) {
-  typename Collection::const_iterator it = collection.find(key);
-  if (it == collection.end()) {
-    return 0;
-  }
-  return &it->second;
-}
-
-// Perform a lookup in a map or hash_map whose values are pointers.
-// If the key is present a const pointer to the associated value is returned,
-// otherwise a NULL pointer is returned.
-// This function does not distinguish between a missing key and a key mapped
-// to a NULL value.
-template <class Collection>
-const typename Collection::value_type::second_type
-FindPtrOrNull(const Collection& collection,
-              const typename Collection::value_type::first_type& key) {
-  typename Collection::const_iterator it = collection.find(key);
-  if (it == collection.end()) {
-    return 0;
-  }
-  return it->second;
-}
-
-// Change the value associated with a particular key in a map or hash_map.
-// If the key is not present in the map the key and value are inserted,
-// otherwise the value is updated to be a copy of the value provided.
-// True indicates that an insert took place, false indicates an update.
-template <class Collection, class Key, class Value>
-bool InsertOrUpdate(Collection * const collection,
-                   const Key& key, const Value& value) {
-  pair<typename Collection::iterator, bool> ret =
-    collection->insert(typename Collection::value_type(key, value));
-  if (!ret.second) {
-    // update
-    ret.first->second = value;
-    return false;
-  }
-  return true;
-}
-
-// Insert a new key and value into a map or hash_map.
-// If the key is not present in the map the key and value are
-// inserted, otherwise nothing happens. True indicates that an insert
-// took place, false indicates the key was already present.
-template <class Collection, class Key, class Value>
-bool InsertIfNotPresent(Collection * const collection,
-                        const Key& key, const Value& value) {
-  pair<typename Collection::iterator, bool> ret =
-    collection->insert(typename Collection::value_type(key, value));
-  return ret.second;
-}
-
-}  // namespace protobuf
-}  // namespace google
-
-#endif  // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
index 7495cb6..a29ed38 100644
--- a/src/google/protobuf/stubs/map_util.h
+++ b/src/google/protobuf/stubs/map_util.h
@@ -208,7 +208,7 @@
 FindLinkedPtrOrDie(const Collection& collection,
                    const typename Collection::value_type::first_type& key) {
   typename Collection::const_iterator it = collection.find(key);
-  CHECK(it != collection.end()) <<  "key not found: " << key;
+  GOOGLE_CHECK(it != collection.end()) <<  "key not found: " << key;
   // Since linked_ptr::operator*() is a const member returning a non const,
   // we do not need a version of this function taking a non const collection.
   return *it->second;
@@ -337,14 +337,14 @@
 template <class Collection>
 void InsertOrDie(Collection* const collection,
                  const typename Collection::value_type& value) {
-  CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
 }
 
 // Same as above except doesn't log the value on error.
 template <class Collection>
 void InsertOrDieNoPrint(Collection* const collection,
                         const typename Collection::value_type& value) {
-  CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
 }
 
 // Inserts the key-value pair into the collection. Dies if key was already
@@ -353,7 +353,6 @@
 void InsertOrDie(Collection* const collection,
                  const typename Collection::value_type::first_type& key,
                  const typename Collection::value_type::second_type& data) {
-  typedef typename Collection::value_type value_type;
   GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
       << "duplicate key: " << key;
 }
@@ -364,7 +363,6 @@
     Collection* const collection,
     const typename Collection::value_type::first_type& key,
     const typename Collection::value_type::second_type& data) {
-  typedef typename Collection::value_type value_type;
   GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
 }
 
diff --git a/src/google/protobuf/stubs/mathlimits.cc b/src/google/protobuf/stubs/mathlimits.cc
new file mode 100644
index 0000000..0373b2b
--- /dev/null
+++ b/src/google/protobuf/stubs/mathlimits.cc
@@ -0,0 +1,144 @@
+// 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.
+
+// All Rights Reserved.
+//
+// Author: Maxim Lifantsev
+//
+
+#include <google/protobuf/stubs/mathlimits.h>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+// MSVC++ 2005 and older compilers think the header declaration was a
+// definition, and erroneously flag these as a duplicate definition.
+#if defined(COMPILER_MSVC) || __cpluscplus < 201103L
+
+#define DEF_COMMON_LIMITS(Type)
+#define DEF_UNSIGNED_INT_LIMITS(Type)
+#define DEF_SIGNED_INT_LIMITS(Type)
+#define DEF_PRECISION_LIMITS(Type)
+
+#else
+
+#define DEF_COMMON_LIMITS(Type) \
+const bool MathLimits<Type>::kIsSigned; \
+const bool MathLimits<Type>::kIsInteger; \
+const int MathLimits<Type>::kMin10Exp; \
+const int MathLimits<Type>::kMax10Exp;
+
+#define DEF_UNSIGNED_INT_LIMITS(Type) \
+DEF_COMMON_LIMITS(Type) \
+const Type MathLimits<Type>::kPosMin; \
+const Type MathLimits<Type>::kPosMax; \
+const Type MathLimits<Type>::kMin; \
+const Type MathLimits<Type>::kMax; \
+const Type MathLimits<Type>::kEpsilon; \
+const Type MathLimits<Type>::kStdError;
+
+#define DEF_SIGNED_INT_LIMITS(Type) \
+DEF_UNSIGNED_INT_LIMITS(Type) \
+const Type MathLimits<Type>::kNegMin; \
+const Type MathLimits<Type>::kNegMax;
+
+#define DEF_PRECISION_LIMITS(Type) \
+const int MathLimits<Type>::kPrecisionDigits;
+
+#endif  // not COMPILER_MSVC
+
+// http://en.wikipedia.org/wiki/Quadruple_precision_floating-point_format#Double-double_arithmetic
+// With some compilers (gcc 4.6.x) on some platforms (powerpc64),
+// "long double" is implemented as a pair of double: "double double" format.
+// This causes a problem with epsilon (eps).
+// eps is the smallest positive number such that 1.0 + eps > 1.0
+//
+// Normal format:  1.0 + e = 1.0...01      // N-1 zeros for N fraction bits
+// D-D format:     1.0 + e = 1.000...0001  // epsilon can be very small
+//
+// In the normal format, 1.0 + e has to fit in one stretch of bits.
+// The maximum rounding error is half of eps.
+//
+// In the double-double format, 1.0 + e splits across two doubles:
+// 1.0 in the high double, e in the low double, and they do not have to
+// be contiguous.  The maximum rounding error on a value close to 1.0 is
+// much larger than eps.
+//
+// Some code checks for errors by comparing a computed value to a golden
+// value +/- some multiple of the maximum rounding error.  The maximum
+// rounding error is not available so we use eps as an approximation
+// instead.  That fails when long double is in the double-double format.
+// Therefore, we define kStdError as a multiple of
+// max(DBL_EPSILON * DBL_EPSILON, kEpsilon) rather than a multiple of kEpsilon.
+
+#define DEF_FP_LIMITS(Type, PREFIX) \
+DEF_COMMON_LIMITS(Type) \
+const Type MathLimits<Type>::kPosMin = PREFIX##_MIN; \
+const Type MathLimits<Type>::kPosMax = PREFIX##_MAX; \
+const Type MathLimits<Type>::kMin = -MathLimits<Type>::kPosMax; \
+const Type MathLimits<Type>::kMax = MathLimits<Type>::kPosMax; \
+const Type MathLimits<Type>::kNegMin = -MathLimits<Type>::kPosMin; \
+const Type MathLimits<Type>::kNegMax = -MathLimits<Type>::kPosMax; \
+const Type MathLimits<Type>::kEpsilon = PREFIX##_EPSILON; \
+/* 32 is 5 bits of mantissa error; should be adequate for common errors */ \
+const Type MathLimits<Type>::kStdError = \
+  32 * (DBL_EPSILON * DBL_EPSILON > MathLimits<Type>::kEpsilon \
+      ? DBL_EPSILON * DBL_EPSILON : MathLimits<Type>::kEpsilon); \
+DEF_PRECISION_LIMITS(Type) \
+const Type MathLimits<Type>::kNaN = HUGE_VAL - HUGE_VAL; \
+const Type MathLimits<Type>::kPosInf = HUGE_VAL; \
+const Type MathLimits<Type>::kNegInf = -HUGE_VAL;
+
+// The following are *not* casts!
+DEF_SIGNED_INT_LIMITS(int8)
+DEF_SIGNED_INT_LIMITS(int16)  // NOLINT(readability/casting)
+DEF_SIGNED_INT_LIMITS(int32)  // NOLINT(readability/casting)
+DEF_SIGNED_INT_LIMITS(int64)  // NOLINT(readability/casting)
+DEF_UNSIGNED_INT_LIMITS(uint8)
+DEF_UNSIGNED_INT_LIMITS(uint16)  // NOLINT(readability/casting)
+DEF_UNSIGNED_INT_LIMITS(uint32)  // NOLINT(readability/casting)
+DEF_UNSIGNED_INT_LIMITS(uint64)  // NOLINT(readability/casting)
+
+DEF_SIGNED_INT_LIMITS(long int)
+DEF_UNSIGNED_INT_LIMITS(unsigned long int)
+
+DEF_FP_LIMITS(float, FLT)
+DEF_FP_LIMITS(double, DBL)
+DEF_FP_LIMITS(long double, LDBL);
+
+#undef DEF_COMMON_LIMITS
+#undef DEF_SIGNED_INT_LIMITS
+#undef DEF_UNSIGNED_INT_LIMITS
+#undef DEF_FP_LIMITS
+#undef DEF_PRECISION_LIMITS
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/mathlimits.h b/src/google/protobuf/stubs/mathlimits.h
new file mode 100644
index 0000000..d984694
--- /dev/null
+++ b/src/google/protobuf/stubs/mathlimits.h
@@ -0,0 +1,279 @@
+// 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.
+
+// All Rights Reserved.
+//
+// Author: Maxim Lifantsev
+//
+// Useful integer and floating point limits and type traits.
+//
+// This partially replaces/duplictes numeric_limits<> from <limits>.
+// We get a Google-style class that we have a greater control over
+// and thus can add new features to it or fix whatever happens to be broken in
+// numeric_limits for the compilers we use.
+//
+
+#ifndef UTIL_MATH_MATHLIMITS_H__
+#define UTIL_MATH_MATHLIMITS_H__
+
+// <math.h> lacks a lot of prototypes. However, this file needs <math.h> to
+// access old-fashioned isinf et al. Even worse more: this file must not
+// include <cmath> because that breaks the definition of isinf with gcc 4.9.
+//
+// TODO(mec): after C++11 everywhere, use <cmath> and std::isinf in this file.
+#include <math.h>
+#include <string.h>
+
+#include <cfloat>
+
+#include <google/protobuf/stubs/common.h>
+
+// ========================================================================= //
+
+// Useful integer and floating point limits and type traits.
+// This is just for the documentation;
+// real members are defined in our specializations below.
+namespace google {
+namespace protobuf {
+template<typename T> struct MathLimits {
+  // Type name.
+  typedef T Type;
+  // Unsigned version of the Type with the same byte size.
+  // Same as Type for floating point and unsigned types.
+  typedef T UnsignedType;
+  // If the type supports negative values.
+  static const bool kIsSigned;
+  // If the type supports only integer values.
+  static const bool kIsInteger;
+  // Magnitude-wise smallest representable positive value.
+  static const Type kPosMin;
+  // Magnitude-wise largest representable positive value.
+  static const Type kPosMax;
+  // Smallest representable value.
+  static const Type kMin;
+  // Largest representable value.
+  static const Type kMax;
+  // Magnitude-wise smallest representable negative value.
+  // Present only if kIsSigned.
+  static const Type kNegMin;
+  // Magnitude-wise largest representable negative value.
+  // Present only if kIsSigned.
+  static const Type kNegMax;
+  // Smallest integer x such that 10^x is representable.
+  static const int kMin10Exp;
+  // Largest integer x such that 10^x is representable.
+  static const int kMax10Exp;
+  // Smallest positive value such that Type(1) + kEpsilon != Type(1)
+  static const Type kEpsilon;
+  // Typical rounding error that is enough to cover
+  // a few simple floating-point operations.
+  // Slightly larger than kEpsilon to account for a few rounding errors.
+  // Is zero if kIsInteger.
+  static const Type kStdError;
+  // Number of decimal digits of mantissa precision.
+  // Present only if !kIsInteger.
+  static const int kPrecisionDigits;
+  // Not a number, i.e. result of 0/0.
+  // Present only if !kIsInteger.
+  static const Type kNaN;
+  // Positive infinity, i.e. result of 1/0.
+  // Present only if !kIsInteger.
+  static const Type kPosInf;
+  // Negative infinity, i.e. result of -1/0.
+  // Present only if !kIsInteger.
+  static const Type kNegInf;
+
+  // NOTE: Special floating point values behave
+  // in a special (but mathematically-logical) way
+  // in terms of (in)equalty comparison and mathematical operations
+  // -- see out unittest for examples.
+
+  // Special floating point value testers.
+  // Present in integer types for convenience.
+  static bool IsFinite(const Type x);
+  static bool IsNaN(const Type x);
+  static bool IsInf(const Type x);
+  static bool IsPosInf(const Type x);
+  static bool IsNegInf(const Type x);
+};
+
+// ========================================================================= //
+
+// All #define-s below are simply to refactor the declarations of
+// MathLimits template specializations.
+// They are all #undef-ined below.
+
+// The hoop-jumping in *_INT_(MAX|MIN) below is so that the compiler does not
+// get an overflow while computing the constants.
+
+#define SIGNED_INT_MAX(Type) \
+  (((Type(1) << (sizeof(Type)*8 - 2)) - 1) + (Type(1) << (sizeof(Type)*8 - 2)))
+
+#define SIGNED_INT_MIN(Type) \
+  (-(Type(1) << (sizeof(Type)*8 - 2)) - (Type(1) << (sizeof(Type)*8 - 2)))
+
+#define UNSIGNED_INT_MAX(Type) \
+  (((Type(1) << (sizeof(Type)*8 - 1)) - 1) + (Type(1) << (sizeof(Type)*8 - 1)))
+
+// Compile-time selected log10-related constants for integer types.
+#define SIGNED_MAX_10_EXP(Type) \
+  (sizeof(Type) == 1 ? 2 : ( \
+    sizeof(Type) == 2 ? 4 : ( \
+      sizeof(Type) == 4 ? 9 : ( \
+        sizeof(Type) == 8 ? 18 : -1))))
+
+#define UNSIGNED_MAX_10_EXP(Type) \
+  (sizeof(Type) == 1 ? 2 : ( \
+    sizeof(Type) == 2 ? 4 : ( \
+      sizeof(Type) == 4 ? 9 : ( \
+        sizeof(Type) == 8 ? 19 : -1))))
+
+#define DECL_INT_LIMIT_FUNCS \
+  static bool IsFinite(const Type /*x*/) { return true; } \
+  static bool IsNaN(const Type /*x*/) { return false; } \
+  static bool IsInf(const Type /*x*/) { return false; } \
+  static bool IsPosInf(const Type /*x*/) { return false; } \
+  static bool IsNegInf(const Type /*x*/) { return false; }
+
+#define DECL_SIGNED_INT_LIMITS(IntType, UnsignedIntType) \
+template<> \
+struct LIBPROTOBUF_EXPORT MathLimits<IntType> { \
+  typedef IntType Type; \
+  typedef UnsignedIntType UnsignedType; \
+  static const bool kIsSigned = true; \
+  static const bool kIsInteger = true; \
+  static const Type kPosMin = 1; \
+  static const Type kPosMax = SIGNED_INT_MAX(Type); \
+  static const Type kMin = SIGNED_INT_MIN(Type); \
+  static const Type kMax = kPosMax; \
+  static const Type kNegMin = -1; \
+  static const Type kNegMax = kMin; \
+  static const int kMin10Exp = 0; \
+  static const int kMax10Exp = SIGNED_MAX_10_EXP(Type); \
+  static const Type kEpsilon = 1; \
+  static const Type kStdError = 0; \
+  DECL_INT_LIMIT_FUNCS \
+};
+
+#define DECL_UNSIGNED_INT_LIMITS(IntType) \
+template<> \
+struct LIBPROTOBUF_EXPORT MathLimits<IntType> { \
+  typedef IntType Type; \
+  typedef IntType UnsignedType; \
+  static const bool kIsSigned = false; \
+  static const bool kIsInteger = true; \
+  static const Type kPosMin = 1; \
+  static const Type kPosMax = UNSIGNED_INT_MAX(Type); \
+  static const Type kMin = 0; \
+  static const Type kMax = kPosMax; \
+  static const int kMin10Exp = 0; \
+  static const int kMax10Exp = UNSIGNED_MAX_10_EXP(Type); \
+  static const Type kEpsilon = 1; \
+  static const Type kStdError = 0; \
+  DECL_INT_LIMIT_FUNCS \
+};
+
+DECL_SIGNED_INT_LIMITS(signed char, unsigned char)
+DECL_SIGNED_INT_LIMITS(signed short int, unsigned short int)
+DECL_SIGNED_INT_LIMITS(signed int, unsigned int)
+DECL_SIGNED_INT_LIMITS(signed long int, unsigned long int)
+DECL_SIGNED_INT_LIMITS(signed long long int, unsigned long long int)
+DECL_UNSIGNED_INT_LIMITS(unsigned char)
+DECL_UNSIGNED_INT_LIMITS(unsigned short int)
+DECL_UNSIGNED_INT_LIMITS(unsigned int)
+DECL_UNSIGNED_INT_LIMITS(unsigned long int)
+DECL_UNSIGNED_INT_LIMITS(unsigned long long int)
+
+#undef DECL_SIGNED_INT_LIMITS
+#undef DECL_UNSIGNED_INT_LIMITS
+#undef SIGNED_INT_MAX
+#undef SIGNED_INT_MIN
+#undef UNSIGNED_INT_MAX
+#undef SIGNED_MAX_10_EXP
+#undef UNSIGNED_MAX_10_EXP
+#undef DECL_INT_LIMIT_FUNCS
+
+// ========================================================================= //
+#ifdef WIN32  // Lacks built-in isnan() and isinf()
+#define DECL_FP_LIMIT_FUNCS \
+  static bool IsFinite(const Type x) { return _finite(x); } \
+  static bool IsNaN(const Type x) { return _isnan(x); } \
+  static bool IsInf(const Type x) { return (_fpclass(x) & (_FPCLASS_NINF | _FPCLASS_PINF)) != 0; } \
+  static bool IsPosInf(const Type x) { return _fpclass(x) == _FPCLASS_PINF; } \
+  static bool IsNegInf(const Type x) { return _fpclass(x) == _FPCLASS_NINF; }
+#else
+#define DECL_FP_LIMIT_FUNCS \
+  static bool IsFinite(const Type x) { return !isinf(x)  &&  !isnan(x); } \
+  static bool IsNaN(const Type x) { return isnan(x); } \
+  static bool IsInf(const Type x) { return isinf(x); } \
+  static bool IsPosInf(const Type x) { return isinf(x)  &&  x > 0; } \
+  static bool IsNegInf(const Type x) { return isinf(x)  &&  x < 0; }
+#endif
+
+// We can't put floating-point constant values in the header here because
+// such constants are not considered to be primitive-type constants by gcc.
+// CAVEAT: Hence, they are going to be initialized only during
+// the global objects construction time.
+#define DECL_FP_LIMITS(FP_Type, PREFIX) \
+template<> \
+struct LIBPROTOBUF_EXPORT MathLimits<FP_Type> { \
+  typedef FP_Type Type; \
+  typedef FP_Type UnsignedType; \
+  static const bool kIsSigned = true; \
+  static const bool kIsInteger = false; \
+  static const Type kPosMin; \
+  static const Type kPosMax; \
+  static const Type kMin; \
+  static const Type kMax; \
+  static const Type kNegMin; \
+  static const Type kNegMax; \
+  static const int kMin10Exp = PREFIX##_MIN_10_EXP; \
+  static const int kMax10Exp = PREFIX##_MAX_10_EXP; \
+  static const Type kEpsilon; \
+  static const Type kStdError; \
+  static const int kPrecisionDigits = PREFIX##_DIG; \
+  static const Type kNaN; \
+  static const Type kPosInf; \
+  static const Type kNegInf; \
+  DECL_FP_LIMIT_FUNCS \
+};
+
+DECL_FP_LIMITS(float, FLT)
+DECL_FP_LIMITS(double, DBL)
+DECL_FP_LIMITS(long double, LDBL)
+
+#undef DECL_FP_LIMITS
+#undef DECL_FP_LIMIT_FUNCS
+
+// ========================================================================= //
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // UTIL_MATH_MATHLIMITS_H__
diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h
new file mode 100644
index 0000000..27956a8
--- /dev/null
+++ b/src/google/protobuf/stubs/mathutil.h
@@ -0,0 +1,162 @@
+// 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.
+#ifndef GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
+#define GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
+
+#include <float.h>
+#include <math.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mathlimits.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<typename T>
+bool IsNan(T value) {
+  return false;
+}
+template<>
+inline bool IsNan(float value) {
+#ifdef _MSC_VER
+  return _isnan(value);
+#else
+  return isnan(value);
+#endif
+}
+template<>
+inline bool IsNan(double value) {
+#ifdef _MSC_VER
+  return _isnan(value);
+#else
+  return isnan(value);
+#endif
+}
+
+template<typename T>
+bool AlmostEquals(T a, T b) {
+  return a == b;
+}
+template<>
+inline bool AlmostEquals(float a, float b) {
+  return fabs(a - b) < 32 * FLT_EPSILON;
+}
+
+template<>
+inline bool AlmostEquals(double a, double b) {
+  return fabs(a - b) < 32 * DBL_EPSILON;
+}
+}  // namespace internal
+
+class MathUtil {
+ public:
+  template<typename T>
+  static T Sign(T value) {
+    if (value == T(0) || ::google::protobuf::internal::IsNan<T>(value)) {
+      return value;
+    }
+    return value > T(0) ? 1 : -1;
+  }
+
+  template<typename T>
+  static bool AlmostEquals(T a, T b) {
+    return ::google::protobuf::internal::AlmostEquals(a, b);
+  }
+
+  // Largest of two values.
+  // Works correctly for special floating point values.
+  // Note: 0.0 and -0.0 are not differentiated by Max (Max(0.0, -0.0) is -0.0),
+  // which should be OK because, although they (can) have different
+  // bit representation, they are observably the same when examined
+  // with arithmetic and (in)equality operators.
+  template<typename T>
+  static T Max(const T x, const T y) {
+    return MathLimits<T>::IsNaN(x) || x > y ? x : y;
+  }
+
+  // Absolute value of x
+  // Works correctly for unsigned types and
+  // for special floating point values.
+  // Note: 0.0 and -0.0 are not differentiated by Abs (Abs(0.0) is -0.0),
+  // which should be OK: see the comment for Max above.
+  template<typename T>
+  static T Abs(const T x) {
+    return x > T(0) ? x : -x;
+  }
+
+  // Absolute value of the difference between two numbers.
+  // Works correctly for signed types and special floating point values.
+  template<typename T>
+  static typename MathLimits<T>::UnsignedType AbsDiff(const T x, const T y) {
+    // Carries out arithmetic as unsigned to avoid overflow.
+    typedef typename MathLimits<T>::UnsignedType R;
+    return x > y ? R(x) - R(y) : R(y) - R(x);
+  }
+
+  // If two (usually floating point) numbers are within a certain
+  // fraction of their magnitude or within a certain absolute margin of error.
+  // This is the same as the following but faster:
+  //   WithinFraction(x, y, fraction)  ||  WithinMargin(x, y, margin)
+  // E.g. WithinFraction(0.0, 1e-10, 1e-5) is false but
+  //      WithinFractionOrMargin(0.0, 1e-10, 1e-5, 1e-5) is true.
+  template<typename T>
+  static bool WithinFractionOrMargin(const T x, const T y,
+                                     const T fraction, const T margin);
+};
+
+template<typename T>
+bool MathUtil::WithinFractionOrMargin(const T x, const T y,
+                                      const T fraction, const T margin) {
+  // Not just "0 <= fraction" to fool the compiler for unsigned types.
+  GOOGLE_DCHECK((T(0) < fraction || T(0) == fraction) &&
+         fraction < T(1) &&
+         margin >= T(0));
+
+  // Template specialization will convert the if() condition to a constant,
+  // which will cause the compiler to generate code for either the "if" part
+  // or the "then" part.  In this way we avoid a compiler warning
+  // about a potential integer overflow in crosstool v12 (gcc 4.3.1).
+  if (MathLimits<T>::kIsInteger) {
+    return x == y;
+  } else {
+    // IsFinite checks are to make kPosInf and kNegInf not within fraction
+    if (!MathLimits<T>::IsFinite(x) && !MathLimits<T>::IsFinite(y)) {
+      return false;
+    }
+    T relative_margin = static_cast<T>(fraction * Max(Abs(x), Abs(y)));
+    return AbsDiff(x, y) <= Max(margin, relative_margin);
+  }
+}
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
diff --git a/src/google/protobuf/stubs/mutex.h b/src/google/protobuf/stubs/mutex.h
new file mode 100644
index 0000000..7ef1cb6
--- /dev/null
+++ b/src/google/protobuf/stubs/mutex.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_MUTEX_H_
+#define GOOGLE_PROTOBUF_STUBS_MUTEX_H_
+
+#ifdef GOOGLE_PROTOBUF_NO_THREADLOCAL
+#include <pthread.h>
+#endif
+
+#include <google/protobuf/stubs/macros.h>
+
+// ===================================================================
+// emulates google3/base/mutex.h
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// A Mutex is a non-reentrant (aka non-recursive) mutex.  At most one thread T
+// may hold a mutex at a given time.  If T attempts to Lock() the same Mutex
+// while holding it, T will deadlock.
+class LIBPROTOBUF_EXPORT Mutex {
+ public:
+  // Create a Mutex that is not held by anybody.
+  Mutex();
+
+  // Destructor
+  ~Mutex();
+
+  // Block if necessary until this Mutex is free, then acquire it exclusively.
+  void Lock();
+
+  // Release this Mutex.  Caller must hold it exclusively.
+  void Unlock();
+
+  // Crash if this Mutex is not held exclusively by this thread.
+  // May fail to crash when it should; will never crash when it should not.
+  void AssertHeld();
+
+ private:
+  struct Internal;
+  Internal* mInternal;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex);
+};
+
+// Undefine the macros  to workaround the conflicts with Google internal
+// MutexLock implementation.
+// TODO(liujisi): Remove the undef once internal macros are removed.
+#undef MutexLock
+#undef ReaderMutexLock
+#undef WriterMutexLock
+#undef MutexLockMaybe
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class LIBPROTOBUF_EXPORT MutexLock {
+ public:
+  explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
+  ~MutexLock() { this->mu_->Unlock(); }
+ private:
+  Mutex *const mu_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
+};
+
+// TODO(kenton):  Implement these?  Hard to implement portably.
+typedef MutexLock ReaderMutexLock;
+typedef MutexLock WriterMutexLock;
+
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL.
+class LIBPROTOBUF_EXPORT MutexLockMaybe {
+ public:
+  explicit MutexLockMaybe(Mutex *mu) :
+    mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } }
+  ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } }
+ private:
+  Mutex *const mu_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
+};
+
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+template<typename T>
+class ThreadLocalStorage {
+ public:
+  ThreadLocalStorage() {
+    pthread_key_create(&key_, &ThreadLocalStorage::Delete);
+  }
+  ~ThreadLocalStorage() {
+    pthread_key_delete(key_);
+  }
+  T* Get() {
+    T* result = static_cast<T*>(pthread_getspecific(key_));
+    if (result == NULL) {
+      result = new T();
+      pthread_setspecific(key_, result);
+    }
+    return result;
+  }
+ private:
+  static void Delete(void* value) {
+    delete static_cast<T*>(value);
+  }
+  pthread_key_t key_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
+};
+#endif
+
+}  // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::Mutex;
+using internal::MutexLock;
+using internal::ReaderMutexLock;
+using internal::WriterMutexLock;
+using internal::MutexLockMaybe;
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h
index cc62bba..1f082c3 100644
--- a/src/google/protobuf/stubs/once.h
+++ b/src/google/protobuf/stubs/once.h
@@ -79,6 +79,7 @@
 #define GOOGLE_PROTOBUF_STUBS_ONCE_H__
 
 #include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index cb5a20d..37def58 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -43,6 +43,7 @@
 
 namespace google {
 namespace protobuf {
+using internal::NewCallback;
 namespace {
 
 class OnceInitTest : public testing::Test {
@@ -127,10 +128,11 @@
   };
 
   TestThread* RunInitOnceInNewThread() {
-    return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
+    return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce));
   }
   TestThread* RunInitRecursiveOnceInNewThread() {
-    return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce));
+    return new TestThread(
+        internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce));
   }
 
   enum State {
diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h
index 7956d07..4ba4b34 100644
--- a/src/google/protobuf/stubs/platform_macros.h
+++ b/src/google/protobuf/stubs/platform_macros.h
@@ -31,8 +31,6 @@
 #ifndef GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
 #define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
 
-#include <google/protobuf/stubs/common.h>
-
 #define GOOGLE_PROTOBUF_PLATFORM_ERROR \
 #error "Host platform was not detected as supported by protobuf"
 
@@ -67,11 +65,17 @@
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #elif defined(sparc)
 #define GOOGLE_PROTOBUF_ARCH_SPARC 1
-#ifdef SOLARIS_64BIT_ENABLED
+#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1
 #else
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #endif
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
+#define GOOGLE_PROTOBUF_ARCH_POWER 1
+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
+#elif defined(__PPC__)
+#define GOOGLE_PROTOBUF_ARCH_PPC 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #elif defined(__GNUC__)
 # if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
 // We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
@@ -92,12 +96,30 @@
 
 #if defined(__APPLE__)
 #define GOOGLE_PROTOBUF_OS_APPLE
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#define GOOGLE_PROTOBUF_OS_IPHONE
+#endif
+#elif defined(__EMSCRIPTEN__)
+#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
 #elif defined(__native_client__)
 #define GOOGLE_PROTOBUF_OS_NACL
 #elif defined(sun)
 #define GOOGLE_PROTOBUF_OS_SOLARIS
+#elif defined(_AIX)
+#define GOOGLE_PROTOBUF_OS_AIX
+#elif defined(__ANDROID__)
+#define GOOGLE_PROTOBUF_OS_ANDROID
 #endif
 
 #undef GOOGLE_PROTOBUF_PLATFORM_ERROR
 
+#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
+// Android ndk does not support the __thread keyword very well yet. Here
+// we use pthread_key_create()/pthread_getspecific()/... methods for
+// TLS support on android.
+// iOS also does not support the __thread keyword.
+#define GOOGLE_PROTOBUF_NO_THREADLOCAL
+#endif
+
 #endif  // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
new file mode 100644
index 0000000..1036dff
--- /dev/null
+++ b/src/google/protobuf/stubs/port.h
@@ -0,0 +1,384 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_PORT_H_
+#define GOOGLE_PROTOBUF_STUBS_PORT_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <cstddef>
+#include <string>
+#include <string.h>
+#if defined(__osf__)
+// Tru64 lacks stdint.h, but has inttypes.h which defines a superset of
+// what stdint.h would define.
+#include <inttypes.h>
+#elif !defined(_MSC_VER)
+#include <stdint.h>
+#endif
+
+#undef PROTOBUF_LITTLE_ENDIAN
+#ifdef _WIN32
+  // Assuming windows is always little-endian.
+  // TODO(xiaofeng): The PROTOBUF_LITTLE_ENDIAN is not only used for
+  // optimization but also for correctness. We should define an
+  // different macro to test the big-endian code path in coded_stream.
+  #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+    #define PROTOBUF_LITTLE_ENDIAN 1
+  #endif
+  #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
+    // If MSVC has "/RTCc" set, it will complain about truncating casts at
+    // runtime.  This file contains some intentional truncating casts.
+    #pragma runtime_checks("c", off)
+  #endif
+#else
+  #include <sys/param.h>   // __BYTE_ORDER
+  #if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
+         (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)) && \
+      !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
+    #define PROTOBUF_LITTLE_ENDIAN 1
+  #endif
+#endif
+#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
+  #ifdef LIBPROTOBUF_EXPORTS
+    #define LIBPROTOBUF_EXPORT __declspec(dllexport)
+  #else
+    #define LIBPROTOBUF_EXPORT __declspec(dllimport)
+  #endif
+  #ifdef LIBPROTOC_EXPORTS
+    #define LIBPROTOC_EXPORT   __declspec(dllexport)
+  #else
+    #define LIBPROTOC_EXPORT   __declspec(dllimport)
+  #endif
+#else
+  #define LIBPROTOBUF_EXPORT
+  #define LIBPROTOC_EXPORT
+#endif
+
+// These #includes are for the byte swap functions declared later on.
+#ifdef _MSC_VER
+#include <stdlib.h>  // NOLINT(build/include)
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#elif defined(__GLIBC__) || defined(__CYGWIN__)
+#include <byteswap.h>  // IWYU pragma: export
+#endif
+
+// ===================================================================
+// from google3/base/port.h
+namespace google {
+namespace protobuf {
+
+typedef unsigned int uint;
+
+#ifdef _MSC_VER
+typedef signed __int8  int8;
+typedef __int16 int16;
+typedef __int32 int32;
+typedef __int64 int64;
+
+typedef unsigned __int8  uint8;
+typedef unsigned __int16 uint16;
+typedef unsigned __int32 uint32;
+typedef unsigned __int64 uint64;
+#else
+typedef signed char  int8;
+typedef short int16;
+typedef int int32;
+typedef long long int64;
+
+typedef unsigned char  uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+#endif
+
+// long long macros to be used because gcc and vc++ use different suffixes,
+// and different size specifiers in format strings
+#undef GOOGLE_LONGLONG
+#undef GOOGLE_ULONGLONG
+#undef GOOGLE_LL_FORMAT
+
+#ifdef _MSC_VER
+#define GOOGLE_LONGLONG(x) x##I64
+#define GOOGLE_ULONGLONG(x) x##UI64
+#define GOOGLE_LL_FORMAT "I64"  // As in printf("%I64d", ...)
+#else
+#define GOOGLE_LONGLONG(x) x##LL
+#define GOOGLE_ULONGLONG(x) x##ULL
+#define GOOGLE_LL_FORMAT "ll"  // As in "%lld". Note that "q" is poor form also.
+#endif
+
+static const int32 kint32max = 0x7FFFFFFF;
+static const int32 kint32min = -kint32max - 1;
+static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF);
+static const int64 kint64min = -kint64max - 1;
+static const uint32 kuint32max = 0xFFFFFFFFu;
+static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
+
+// -------------------------------------------------------------------
+// Annotations:  Some parts of the code have been annotated in ways that might
+//   be useful to some compilers or tools, but are not supported universally.
+//   You can #define these annotations yourself if the default implementation
+//   is not right for you.
+
+#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+// For functions we want to force inline.
+// Introduced in gcc 3.1.
+#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
+#else
+// Other compilers will have to figure it out for themselves.
+#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+#endif
+#endif
+
+#ifndef GOOGLE_ATTRIBUTE_NOINLINE
+#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+// For functions we want to force not inline.
+// Introduced in gcc 3.1.
+#define GOOGLE_ATTRIBUTE_NOINLINE __attribute__ ((noinline))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+// Seems to have been around since at least Visual Studio 2005
+#define GOOGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+// Other compilers will have to figure it out for themselves.
+#define GOOGLE_ATTRIBUTE_NOINLINE
+#endif
+#endif
+
+#ifndef GOOGLE_ATTRIBUTE_DEPRECATED
+#ifdef __GNUC__
+// If the method/variable/type is used anywhere, produce a warning.
+#define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated))
+#else
+#define GOOGLE_ATTRIBUTE_DEPRECATED
+#endif
+#endif
+
+#ifndef GOOGLE_PREDICT_TRUE
+#ifdef __GNUC__
+// Provided at least since GCC 3.0.
+#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#else
+#define GOOGLE_PREDICT_TRUE(x) (x)
+#endif
+#endif
+
+#ifndef GOOGLE_PREDICT_FALSE
+#ifdef __GNUC__
+// Provided at least since GCC 3.0.
+#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#else
+#define GOOGLE_PREDICT_FALSE(x) (x)
+#endif
+#endif
+
+// Delimits a block of code which may write to memory which is simultaneously
+// written by other threads, but which has been determined to be thread-safe
+// (e.g. because it is an idempotent write).
+#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN
+#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN()
+#endif
+#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END
+#define GOOGLE_SAFE_CONCURRENT_WRITES_END()
+#endif
+
+#if defined(__clang__) && defined(__has_cpp_attribute) \
+    && !defined(GOOGLE_PROTOBUF_OS_APPLE)
+# if defined(GOOGLE_PROTOBUF_OS_NACL) || defined(EMSCRIPTEN) || \
+     __has_cpp_attribute(clang::fallthrough)
+#  define GOOGLE_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+# endif
+#endif
+
+#ifndef GOOGLE_FALLTHROUGH_INTENDED
+# define GOOGLE_FALLTHROUGH_INTENDED
+#endif
+
+#define GOOGLE_GUARDED_BY(x)
+#define GOOGLE_ATTRIBUTE_COLD
+
+// x86 and x86-64 can perform unaligned loads/stores directly.
+#if defined(_M_X64) || defined(__x86_64__) || \
+    defined(_M_IX86) || defined(__i386__)
+
+#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
+#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
+#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
+
+#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
+#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
+
+#else
+inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) {
+  uint16 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) {
+  uint32 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) {
+  uint64 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) {
+  memcpy(p, &v, sizeof v);
+}
+
+inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) {
+  memcpy(p, &v, sizeof v);
+}
+#endif
+
+#if defined(_MSC_VER)
+#define GOOGLE_THREAD_LOCAL __declspec(thread)
+#else
+#define GOOGLE_THREAD_LOCAL __thread
+#endif
+
+// The following guarantees declaration of the byte swap functions, and
+// defines __BYTE_ORDER for MSVC
+#ifdef _MSC_VER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define bswap_16(x) _byteswap_ushort(x)
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+// Mac OS X / Darwin features
+#define bswap_16(x) OSSwapInt16(x)
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif !defined(__GLIBC__) && !defined(__CYGWIN__)
+
+static inline uint16 bswap_16(uint16 x) {
+  return static_cast<uint16>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
+}
+#define bswap_16(x) bswap_16(x)
+static inline uint32 bswap_32(uint32 x) {
+  return (((x & 0xFF) << 24) |
+          ((x & 0xFF00) << 8) |
+          ((x & 0xFF0000) >> 8) |
+          ((x & 0xFF000000) >> 24));
+}
+#define bswap_32(x) bswap_32(x)
+static inline uint64 bswap_64(uint64 x) {
+  return (((x & GOOGLE_ULONGLONG(0xFF)) << 56) |
+          ((x & GOOGLE_ULONGLONG(0xFF00)) << 40) |
+          ((x & GOOGLE_ULONGLONG(0xFF0000)) << 24) |
+          ((x & GOOGLE_ULONGLONG(0xFF000000)) << 8) |
+          ((x & GOOGLE_ULONGLONG(0xFF00000000)) >> 8) |
+          ((x & GOOGLE_ULONGLONG(0xFF0000000000)) >> 24) |
+          ((x & GOOGLE_ULONGLONG(0xFF000000000000)) >> 40) |
+          ((x & GOOGLE_ULONGLONG(0xFF00000000000000)) >> 56));
+}
+#define bswap_64(x) bswap_64(x)
+
+#endif
+
+// ===================================================================
+// from google3/util/endian/endian.h
+LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
+
+class BigEndian {
+ public:
+#ifdef PROTOBUF_LITTLE_ENDIAN
+
+  static uint16 FromHost16(uint16 x) { return bswap_16(x); }
+  static uint16 ToHost16(uint16 x) { return bswap_16(x); }
+
+  static uint32 FromHost32(uint32 x) { return bswap_32(x); }
+  static uint32 ToHost32(uint32 x) { return bswap_32(x); }
+
+  static uint64 FromHost64(uint64 x) { return bswap_64(x); }
+  static uint64 ToHost64(uint64 x) { return bswap_64(x); }
+
+  static bool IsLittleEndian() { return true; }
+
+#else
+
+  static uint16 FromHost16(uint16 x) { return x; }
+  static uint16 ToHost16(uint16 x) { return x; }
+
+  static uint32 FromHost32(uint32 x) { return x; }
+  static uint32 ToHost32(uint32 x) { return x; }
+
+  static uint64 FromHost64(uint64 x) { return x; }
+  static uint64 ToHost64(uint64 x) { return x; }
+
+  static bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+  // Functions to do unaligned loads and stores in big-endian order.
+  static uint16 Load16(const void *p) {
+    return ToHost16(GOOGLE_UNALIGNED_LOAD16(p));
+  }
+
+  static void Store16(void *p, uint16 v) {
+    GOOGLE_UNALIGNED_STORE16(p, FromHost16(v));
+  }
+
+  static uint32 Load32(const void *p) {
+    return ToHost32(GOOGLE_UNALIGNED_LOAD32(p));
+  }
+
+  static void Store32(void *p, uint32 v) {
+    GOOGLE_UNALIGNED_STORE32(p, FromHost32(v));
+  }
+
+  static uint64 Load64(const void *p) {
+    return ToHost64(GOOGLE_UNALIGNED_LOAD64(p));
+  }
+
+  static void Store64(void *p, uint64 v) {
+    GOOGLE_UNALIGNED_STORE64(p, FromHost64(v));
+  }
+};
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_PORT_H_
diff --git a/src/google/protobuf/stubs/scoped_ptr.h b/src/google/protobuf/stubs/scoped_ptr.h
new file mode 100644
index 0000000..4423c11
--- /dev/null
+++ b/src/google/protobuf/stubs/scoped_ptr.h
@@ -0,0 +1,236 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_SCOPED_PTR_H_
+#define GOOGLE_PROTOBUF_STUBS_SCOPED_PTR_H_
+
+#include <google/protobuf/stubs/port.h>
+
+namespace google {
+namespace protobuf {
+
+// ===================================================================
+// from google3/base/scoped_ptr.h
+
+namespace internal {
+
+//  This is an implementation designed to match the anticipated future TR2
+//  implementation of the scoped_ptr class, and its closely-related brethren,
+//  scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
+
+template <class C> class scoped_ptr;
+template <class C> class scoped_array;
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+//
+// The size of a scoped_ptr is small:
+// sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized scoped_ptr.
+  // The input parameter must be allocated with new.
+  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_ptr() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete ptr_;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != ptr_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete ptr_;
+      ptr_ = p;
+    }
+  }
+
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  C& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+  C* operator->() const  {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+  C* get() const { return ptr_; }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return ptr_ == p; }
+  bool operator!=(C* p) const { return ptr_ != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    C* tmp = ptr_;
+    ptr_ = p2.ptr_;
+    p2.ptr_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() {
+    C* retVal = ptr_;
+    ptr_ = NULL;
+    return retVal;
+  }
+
+ private:
+  C* ptr_;
+
+  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't
+  // make sense, and if C2 == C, it still doesn't make sense because you should
+  // never have the same object owned by two different scoped_ptrs.
+  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+  // Disallow evil constructors
+  scoped_ptr(const scoped_ptr&);
+  void operator=(const scoped_ptr&);
+};
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL.  A scoped_array<C> owns the object that it points to.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  // There is no way to create an uninitialized scoped_array.
+  // The input parameter must be allocated with new [].
+  explicit scoped_array(C* p = NULL) : array_(p) { }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_array() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete[] array_;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != array_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete[] array_;
+      array_ = p;
+    }
+  }
+
+  // Get one element of the current object.
+  // Will assert() if there is no current object, or index i is negative.
+  C& operator[](std::ptrdiff_t i) const {
+    assert(i >= 0);
+    assert(array_ != NULL);
+    return array_[i];
+  }
+
+  // Get a pointer to the zeroth element of the current object.
+  // If there is no current object, return NULL.
+  C* get() const {
+    return array_;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_array refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return array_ == p; }
+  bool operator!=(C* p) const { return array_ != p; }
+
+  // Swap two scoped arrays.
+  void swap(scoped_array& p2) {
+    C* tmp = array_;
+    array_ = p2.array_;
+    p2.array_ = tmp;
+  }
+
+  // Release an array.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() {
+    C* retVal = array_;
+    array_ = NULL;
+    return retVal;
+  }
+
+ private:
+  C* array_;
+
+  // Forbid comparison of different scoped_array types.
+  template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+  // Disallow evil constructors
+  scoped_array(const scoped_array&);
+  void operator=(const scoped_array&);
+};
+
+}  // namespace internal
+
+// We made these internal so that they would show up as such in the docs,
+// but we don't want to stick "internal::" in front of them everywhere.
+using internal::scoped_ptr;
+using internal::scoped_array;
+
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_SCOPED_PTR_H_
diff --git a/src/google/protobuf/stubs/shared_ptr.h b/src/google/protobuf/stubs/shared_ptr.h
index d250bf4..bca8280 100644
--- a/src/google/protobuf/stubs/shared_ptr.h
+++ b/src/google/protobuf/stubs/shared_ptr.h
@@ -428,18 +428,18 @@
   shared_ptr<T> shared_from_this() {
     // Behavior is undefined if the precondition isn't satisfied; we choose
     // to die with a CHECK failure.
-    CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
+    GOOGLE_CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
     return weak_this_.lock();
   }
   shared_ptr<const T> shared_from_this() const {
-    CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
+    GOOGLE_CHECK(!weak_this_.expired()) << "No shared_ptr owns this object";
     return weak_this_.lock();
   }
 
  protected:
   enable_shared_from_this() { }
-  enable_shared_from_this(const enable_shared_from_this& other) { }
-  enable_shared_from_this& operator=(const enable_shared_from_this& other) {
+  enable_shared_from_this(const enable_shared_from_this&) { }
+  enable_shared_from_this& operator=(const enable_shared_from_this&) {
     return *this;
   }
   ~enable_shared_from_this() { }
@@ -456,7 +456,7 @@
 template<typename T>
 void shared_ptr<T>::MaybeSetupWeakThis(enable_shared_from_this<T>* ptr) {
   if (ptr) {
-    CHECK(ptr->weak_this_.expired()) << "Object already owned by a shared_ptr";
+    GOOGLE_CHECK(ptr->weak_this_.expired()) << "Object already owned by a shared_ptr";
     ptr->weak_this_ = *this;
   }
 }
diff --git a/src/google/protobuf/stubs/singleton.h b/src/google/protobuf/stubs/singleton.h
new file mode 100644
index 0000000..9301f54
--- /dev/null
+++ b/src/google/protobuf/stubs/singleton.h
@@ -0,0 +1,68 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.
+#ifndef GOOGLE_PROTOBUF_STUBS_SINGLETON_H__
+#define GOOGLE_PROTOBUF_STUBS_SINGLETON_H__
+
+#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+template<typename T>
+class Singleton {
+ public:
+  static T* get() {
+    GoogleOnceInit(&once_, &Singleton<T>::Init);
+    return instance_;
+  }
+  static void ShutDown() {
+    delete instance_;
+    instance_ = NULL;
+  }
+ private:
+  static void Init() {
+    instance_ = new T();
+  }
+  static ProtobufOnceType once_;
+  static T* instance_;
+};
+
+template<typename T>
+ProtobufOnceType Singleton<T>::once_;
+
+template<typename T>
+T* Singleton<T>::instance_ = NULL;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_SINGLETON_H__
diff --git a/src/google/protobuf/stubs/status.cc b/src/google/protobuf/stubs/status.cc
new file mode 100644
index 0000000..dd1bd61
--- /dev/null
+++ b/src/google/protobuf/stubs/status.cc
@@ -0,0 +1,134 @@
+// 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.
+#include <google/protobuf/stubs/status.h>
+
+#include <ostream>
+#include <stdio.h>
+#include <string>
+#include <utility>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace error {
+inline string CodeEnumToString(error::Code code) {
+  switch (code) {
+    case OK:
+      return "OK";
+    case CANCELLED:
+      return "CANCELLED";
+    case UNKNOWN:
+      return "UNKNOWN";
+    case INVALID_ARGUMENT:
+      return "INVALID_ARGUMENT";
+    case DEADLINE_EXCEEDED:
+      return "DEADLINE_EXCEEDED";
+    case NOT_FOUND:
+      return "NOT_FOUND";
+    case ALREADY_EXISTS:
+      return "ALREADY_EXISTS";
+    case PERMISSION_DENIED:
+      return "PERMISSION_DENIED";
+    case UNAUTHENTICATED:
+      return "UNAUTHENTICATED";
+    case RESOURCE_EXHAUSTED:
+      return "RESOURCE_EXHAUSTED";
+    case FAILED_PRECONDITION:
+      return "FAILED_PRECONDITION";
+    case ABORTED:
+      return "ABORTED";
+    case OUT_OF_RANGE:
+      return "OUT_OF_RANGE";
+    case UNIMPLEMENTED:
+      return "UNIMPLEMENTED";
+    case INTERNAL:
+      return "INTERNAL";
+    case UNAVAILABLE:
+      return "UNAVAILABLE";
+    case DATA_LOSS:
+      return "DATA_LOSS";
+  }
+
+  // No default clause, clang will abort if a code is missing from
+  // above switch.
+  return "UNKNOWN";
+}
+}  // namespace error.
+
+const Status Status::OK = Status();
+const Status Status::CANCELLED = Status(error::CANCELLED, "");
+const Status Status::UNKNOWN = Status(error::UNKNOWN, "");
+
+Status::Status() : error_code_(error::OK) {
+}
+
+Status::Status(error::Code error_code, StringPiece error_message)
+    : error_code_(error_code) {
+  if (error_code != error::OK) {
+    error_message_ = error_message.ToString();
+  }
+}
+
+Status::Status(const Status& other)
+    : error_code_(other.error_code_), error_message_(other.error_message_) {
+}
+
+Status& Status::operator=(const Status& other) {
+  error_code_ = other.error_code_;
+  error_message_ = other.error_message_;
+  return *this;
+}
+
+bool Status::operator==(const Status& x) const {
+  return error_code_ == x.error_code_ &&
+      error_message_ == x.error_message_;
+}
+
+string Status::ToString() const {
+  if (error_code_ == error::OK) {
+    return "OK";
+  } else {
+    if (error_message_.empty()) {
+      return error::CodeEnumToString(error_code_);
+    } else {
+      return error::CodeEnumToString(error_code_) + ":" +
+          error_message_;
+    }
+  }
+}
+
+ostream& operator<<(ostream& os, const Status& x) {
+  os << x.ToString();
+  return os;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/status.h b/src/google/protobuf/stubs/status.h
new file mode 100644
index 0000000..614ab99
--- /dev/null
+++ b/src/google/protobuf/stubs/status.h
@@ -0,0 +1,116 @@
+// 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.
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUS_H_
+
+#include <iosfwd>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace error {
+// These values must match error codes defined in google/rpc/code.proto.
+enum Code {
+  OK = 0,
+  CANCELLED = 1,
+  UNKNOWN = 2,
+  INVALID_ARGUMENT = 3,
+  DEADLINE_EXCEEDED = 4,
+  NOT_FOUND = 5,
+  ALREADY_EXISTS = 6,
+  PERMISSION_DENIED = 7,
+  UNAUTHENTICATED = 16,
+  RESOURCE_EXHAUSTED = 8,
+  FAILED_PRECONDITION = 9,
+  ABORTED = 10,
+  OUT_OF_RANGE = 11,
+  UNIMPLEMENTED = 12,
+  INTERNAL = 13,
+  UNAVAILABLE = 14,
+  DATA_LOSS = 15,
+};
+}  // namespace error
+
+class LIBPROTOBUF_EXPORT Status {
+ public:
+  // Creates a "successful" status.
+  Status();
+
+  // Create a status in the canonical error space with the specified
+  // code, and error message.  If "code == 0", error_message is
+  // ignored and a Status object identical to Status::OK is
+  // constructed.
+  Status(error::Code error_code, StringPiece error_message);
+  Status(const Status&);
+  Status& operator=(const Status& x);
+  ~Status() {}
+
+  // Some pre-defined Status objects
+  static const Status OK;             // Identical to 0-arg constructor
+  static const Status CANCELLED;
+  static const Status UNKNOWN;
+
+  // Accessor
+  bool ok() const {
+    return error_code_ == error::OK;
+  }
+  int error_code() const {
+    return error_code_;
+  }
+  StringPiece error_message() const {
+    return error_message_;
+  }
+
+  bool operator==(const Status& x) const;
+  bool operator!=(const Status& x) const {
+    return !operator==(x);
+  }
+
+  // Return a combination of the error code name and message.
+  string ToString() const;
+
+ private:
+  error::Code error_code_;
+  string error_message_;
+};
+
+// Prints a human-readable representation of 'x' to 'os'.
+LIBPROTOBUF_EXPORT ostream& operator<<(ostream& os, const Status& x);
+
+#define EXPECT_OK(value) EXPECT_TRUE((value).ok())
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUS_H_
diff --git a/src/google/protobuf/stubs/status_macros.h b/src/google/protobuf/stubs/status_macros.h
new file mode 100644
index 0000000..743e79a
--- /dev/null
+++ b/src/google/protobuf/stubs/status_macros.h
@@ -0,0 +1,89 @@
+// 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.
+
+// From: util/task/contrib/status_macros/status_macros.h
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Run a command that returns a util::Status.  If the called code returns an
+// error status, return that status up out of this method too.
+//
+// Example:
+//   RETURN_IF_ERROR(DoThings(4));
+#define RETURN_IF_ERROR(expr) \
+  do { \
+    /* Using _status below to avoid capture problems if expr is "status". */ \
+    const ::google::protobuf::util::Status _status = (expr); \
+    if (GOOGLE_PREDICT_FALSE(!_status.ok())) return _status; \
+  } while (0)
+
+// Internal helper for concatenating macro values.
+#define STATUS_MACROS_CONCAT_NAME_INNER(x, y) x##y
+#define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y)
+
+template<typename T>
+Status DoAssignOrReturn(T& lhs, StatusOr<T> result) {
+  if (result.ok()) {
+    lhs = result.ValueOrDie();
+  }
+  return result.status();
+}
+
+#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \
+  Status status = DoAssignOrReturn(lhs, (rexpr)); \
+  if (GOOGLE_PREDICT_FALSE(!status.ok())) return status;
+
+// Executes an expression that returns a util::StatusOr, extracting its value
+// into the variable defined by lhs (or returning on error).
+//
+// Example: Assigning to an existing value
+//   ValueType value;
+//   ASSIGN_OR_RETURN(value, MaybeGetValue(arg));
+//
+// WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
+//  in a single statement (e.g. as the body of an if statement without {})!
+#define ASSIGN_OR_RETURN(lhs, rexpr) \
+  ASSIGN_OR_RETURN_IMPL( \
+      STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr);
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUS_H_
diff --git a/src/google/protobuf/stubs/status_test.cc b/src/google/protobuf/stubs/status_test.cc
new file mode 100644
index 0000000..c70c33c
--- /dev/null
+++ b/src/google/protobuf/stubs/status_test.cc
@@ -0,0 +1,131 @@
+// 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.
+#include <google/protobuf/stubs/status.h>
+
+#include <stdio.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+TEST(Status, Empty) {
+  util::Status status;
+  EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+  EXPECT_EQ("OK", util::Status::OK.ToString());
+}
+
+TEST(Status, GenericCodes) {
+  EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+  EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.error_code());
+  EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.error_code());
+}
+
+TEST(Status, ConstructorZero) {
+  util::Status status(util::error::OK, "msg");
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ("OK", status.ToString());
+}
+
+TEST(Status, CheckOK) {
+  util::Status status;
+  GOOGLE_CHECK_OK(status);
+  GOOGLE_CHECK_OK(status) << "Failed";
+  GOOGLE_DCHECK_OK(status) << "Failed";
+}
+
+TEST(Status, ErrorMessage) {
+  util::Status status(util::error::INVALID_ARGUMENT, "");
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ("", status.error_message().ToString());
+  EXPECT_EQ("INVALID_ARGUMENT", status.ToString());
+  status = util::Status(util::error::INVALID_ARGUMENT, "msg");
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ("msg", status.error_message().ToString());
+  EXPECT_EQ("INVALID_ARGUMENT:msg", status.ToString());
+  status = util::Status(util::error::OK, "msg");
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ("", status.error_message().ToString());
+  EXPECT_EQ("OK", status.ToString());
+}
+
+TEST(Status, Copy) {
+  util::Status a(util::error::UNKNOWN, "message");
+  util::Status b(a);
+  ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, Assign) {
+  util::Status a(util::error::UNKNOWN, "message");
+  util::Status b;
+  b = a;
+  ASSERT_EQ(a.ToString(), b.ToString());
+}
+
+TEST(Status, AssignEmpty) {
+  util::Status a(util::error::UNKNOWN, "message");
+  util::Status b;
+  a = b;
+  ASSERT_EQ(string("OK"), a.ToString());
+  ASSERT_TRUE(b.ok());
+  ASSERT_TRUE(a.ok());
+}
+
+TEST(Status, EqualsOK) {
+  ASSERT_EQ(util::Status::OK, util::Status());
+}
+
+TEST(Status, EqualsSame) {
+  const util::Status a = util::Status(util::error::CANCELLED, "message");
+  const util::Status b = util::Status(util::error::CANCELLED, "message");
+  ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsCopy) {
+  const util::Status a = util::Status(util::error::CANCELLED, "message");
+  const util::Status b = a;
+  ASSERT_EQ(a, b);
+}
+
+TEST(Status, EqualsDifferentCode) {
+  const util::Status a = util::Status(util::error::CANCELLED, "message");
+  const util::Status b = util::Status(util::error::UNKNOWN, "message");
+  ASSERT_NE(a, b);
+}
+
+TEST(Status, EqualsDifferentMessage) {
+  const util::Status a = util::Status(util::error::CANCELLED, "message");
+  const util::Status b = util::Status(util::error::CANCELLED, "another");
+  ASSERT_NE(a, b);
+}
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/statusor.cc b/src/google/protobuf/stubs/statusor.cc
new file mode 100644
index 0000000..48d1402
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor.cc
@@ -0,0 +1,46 @@
+// 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.
+
+#include <google/protobuf/stubs/statusor.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace internal {
+
+void StatusOrHelper::Crash(const Status& status) {
+  GOOGLE_LOG(FATAL) << "Attempting to fetch value instead of handling error "
+                    << status.ToString();
+}
+
+}  // namespace internal
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h
new file mode 100644
index 0000000..29f869a
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor.h
@@ -0,0 +1,259 @@
+// 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.
+
+// StatusOr<T> is the union of a Status object and a T
+// object. StatusOr models the concept of an object that is either a
+// usable value, or an error Status explaining why such a value is
+// not present. To this end, StatusOr<T> does not allow its Status
+// value to be Status::OK. Further, StatusOr<T*> does not allow the
+// contained pointer to be NULL.
+//
+// The primary use-case for StatusOr<T> is as the return value of a
+// function which may fail.
+//
+// Example client usage for a StatusOr<T>, where T is not a pointer:
+//
+//  StatusOr<float> result = DoBigCalculationThatCouldFail();
+//  if (result.ok()) {
+//    float answer = result.ValueOrDie();
+//    printf("Big calculation yielded: %f", answer);
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example client usage for a StatusOr<T*>:
+//
+//  StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
+//  if (result.ok()) {
+//    std::unique_ptr<Foo> foo(result.ValueOrDie());
+//    foo->DoSomethingCool();
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example client usage for a StatusOr<std::unique_ptr<T>>:
+//
+//  StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+//  if (result.ok()) {
+//    std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
+//    foo->DoSomethingCool();
+//  } else {
+//    LOG(ERROR) << result.status();
+//  }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+//  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+//    if (arg <= 0) {
+//      return ::util::Status(::util::error::INVALID_ARGUMENT,
+//                            "Arg must be positive");
+//    } else {
+//      return new Foo(arg);
+//    }
+//  }
+//
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
+#define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
+
+#include <new>
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+template<typename T>
+class StatusOr {
+  template<typename U> friend class StatusOr;
+
+ public:
+  // Construct a new StatusOr with Status::UNKNOWN status
+  StatusOr();
+
+  // Construct a new StatusOr with the given non-ok status. After calling
+  // this constructor, calls to ValueOrDie() will CHECK-fail.
+  //
+  // NOTE: Not explicit - we want to use StatusOr<T> as a return
+  // value, so it is convenient and sensible to be able to do 'return
+  // Status()' when the return type is StatusOr<T>.
+  //
+  // REQUIRES: status != Status::OK. This requirement is DCHECKed.
+  // In optimized builds, passing Status::OK here will have the effect
+  // of passing PosixErrorSpace::EINVAL as a fallback.
+  StatusOr(const Status& status);  // NOLINT
+
+  // Construct a new StatusOr with the given value. If T is a plain pointer,
+  // value must not be NULL. After calling this constructor, calls to
+  // ValueOrDie() will succeed, and calls to status() will return OK.
+  //
+  // NOTE: Not explicit - we want to use StatusOr<T> as a return type
+  // so it is convenient and sensible to be able to do 'return T()'
+  // when when the return type is StatusOr<T>.
+  //
+  // REQUIRES: if T is a plain pointer, value != NULL. This requirement is
+  // DCHECKed. In optimized builds, passing a NULL pointer here will have
+  // the effect of passing PosixErrorSpace::EINVAL as a fallback.
+  StatusOr(const T& value);  // NOLINT
+
+  // Copy constructor.
+  StatusOr(const StatusOr& other);
+
+  // Conversion copy constructor, T must be copy constructible from U
+  template<typename U>
+  StatusOr(const StatusOr<U>& other);
+
+  // Assignment operator.
+  StatusOr& operator=(const StatusOr& other);
+
+  // Conversion assignment operator, T must be assignable from U
+  template<typename U>
+  StatusOr& operator=(const StatusOr<U>& other);
+
+  // Returns a reference to our status. If this contains a T, then
+  // returns Status::OK.
+  const Status& status() const;
+
+  // Returns this->status().ok()
+  bool ok() const;
+
+  // Returns a reference to our current value, or CHECK-fails if !this->ok().
+  // If you need to initialize a T object from the stored value,
+  // ConsumeValueOrDie() may be more efficient.
+  const T& ValueOrDie() const;
+
+ private:
+  Status status_;
+  T value_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation details for StatusOr<T>
+
+namespace internal {
+
+class LIBPROTOBUF_EXPORT StatusOrHelper {
+ public:
+  // Move type-agnostic error handling to the .cc.
+  static void Crash(const util::Status& status);
+
+  // Customized behavior for StatusOr<T> vs. StatusOr<T*>
+  template<typename T>
+  struct Specialize;
+};
+
+template<typename T>
+struct StatusOrHelper::Specialize {
+  // For non-pointer T, a reference can never be NULL.
+  static inline bool IsValueNull(const T& t) { return false; }
+};
+
+template<typename T>
+struct StatusOrHelper::Specialize<T*> {
+  static inline bool IsValueNull(const T* t) { return t == NULL; }
+};
+
+}  // namespace internal
+
+template<typename T>
+inline StatusOr<T>::StatusOr()
+    : status_(util::Status::UNKNOWN) {
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const Status& status) {
+  if (status.ok()) {
+    status_ = Status(error::INTERNAL, "Status::OK is not a valid argument.");
+  } else {
+    status_ = status;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const T& value) {
+  if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) {
+    status_ = Status(error::INTERNAL, "NULL is not a vaild argument.");
+  } else {
+    status_ = Status::OK;
+    value_ = value;
+  }
+}
+
+template<typename T>
+inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
+    : status_(other.status_), value_(other.value_) {
+}
+
+template<typename T>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
+  status_ = other.status_;
+  value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+    : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
+}
+
+template<typename T>
+template<typename U>
+inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+  status_ = other.status_;
+  if (status_.ok()) value_ = other.value_;
+  return *this;
+}
+
+template<typename T>
+inline const Status& StatusOr<T>::status() const {
+  return status_;
+}
+
+template<typename T>
+inline bool StatusOr<T>::ok() const {
+  return status().ok();
+}
+
+template<typename T>
+inline const T& StatusOr<T>::ValueOrDie() const {
+  if (!status_.ok()) {
+    internal::StatusOrHelper::Crash(status_);
+  }
+  return value_;
+}
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
diff --git a/src/google/protobuf/stubs/statusor_test.cc b/src/google/protobuf/stubs/statusor_test.cc
new file mode 100644
index 0000000..6e2a9e5
--- /dev/null
+++ b/src/google/protobuf/stubs/statusor_test.cc
@@ -0,0 +1,274 @@
+// 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.
+
+#include <google/protobuf/stubs/statusor.h>
+
+#include <errno.h>
+#include <memory>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+
+class Base1 {
+ public:
+  virtual ~Base1() {}
+  int pad;
+};
+
+class Base2 {
+ public:
+  virtual ~Base2() {}
+  int yetotherpad;
+};
+
+class Derived : public Base1, public Base2 {
+ public:
+  virtual ~Derived() {}
+  int evenmorepad;
+};
+
+class CopyNoAssign {
+ public:
+  explicit CopyNoAssign(int value) : foo(value) {}
+  CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
+  int foo;
+ private:
+  const CopyNoAssign& operator=(const CopyNoAssign&);
+};
+
+TEST(StatusOr, TestDefaultCtor) {
+  StatusOr<int> thing;
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(Status::UNKNOWN, thing.status());
+}
+
+TEST(StatusOr, TestStatusCtor) {
+  StatusOr<int> thing(Status::CANCELLED);
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(Status::CANCELLED, thing.status());
+}
+
+TEST(StatusOr, TestValueCtor) {
+  const int kI = 4;
+  StatusOr<int> thing(kI);
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusOk) {
+  const int kI = 4;
+  StatusOr<int> original(kI);
+  StatusOr<int> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOk) {
+  StatusOr<int> original(Status::CANCELLED);
+  StatusOr<int> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+}
+
+TEST(StatusOr, TestCopyCtorStatusOKConverting) {
+  const int kI = 4;
+  StatusOr<int>    original(kI);
+  StatusOr<double> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
+  StatusOr<int>    original(Status::CANCELLED);
+  StatusOr<double> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+}
+
+TEST(StatusOr, TestAssignmentStatusOk) {
+  const int kI = 4;
+  StatusOr<int> source(kI);
+  StatusOr<int> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+  EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOk) {
+  StatusOr<int> source(Status::CANCELLED);
+  StatusOr<int> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+}
+
+TEST(StatusOr, TestAssignmentStatusOKConverting) {
+  const int kI = 4;
+  StatusOr<int>    source(kI);
+  StatusOr<double> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+  EXPECT_DOUBLE_EQ(source.ValueOrDie(), target.ValueOrDie());
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
+  StatusOr<int>    source(Status::CANCELLED);
+  StatusOr<double> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+}
+
+TEST(StatusOr, TestStatus) {
+  StatusOr<int> good(4);
+  EXPECT_TRUE(good.ok());
+  StatusOr<int> bad(Status::CANCELLED);
+  EXPECT_FALSE(bad.ok());
+  EXPECT_EQ(Status::CANCELLED, bad.status());
+}
+
+TEST(StatusOr, TestValue) {
+  const int kI = 4;
+  StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestValueConst) {
+  const int kI = 4;
+  const StatusOr<int> thing(kI);
+  EXPECT_EQ(kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerDefaultCtor) {
+  StatusOr<int*> thing;
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(Status::UNKNOWN, thing.status());
+}
+
+TEST(StatusOr, TestPointerStatusCtor) {
+  StatusOr<int*> thing(Status::CANCELLED);
+  EXPECT_FALSE(thing.ok());
+  EXPECT_EQ(Status::CANCELLED, thing.status());
+}
+
+TEST(StatusOr, TestPointerValueCtor) {
+  const int kI = 4;
+  StatusOr<const int*> thing(&kI);
+  EXPECT_TRUE(thing.ok());
+  EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOk) {
+  const int kI = 0;
+  StatusOr<const int*> original(&kI);
+  StatusOr<const int*> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+  EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
+  StatusOr<int*> original(Status::CANCELLED);
+  StatusOr<int*> copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
+  Derived derived;
+  StatusOr<Derived*> original(&derived);
+  StatusOr<Base2*>   copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+  EXPECT_EQ(static_cast<const Base2*>(original.ValueOrDie()),
+            copy.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
+  StatusOr<Derived*> original(Status::CANCELLED);
+  StatusOr<Base2*>   copy(original);
+  EXPECT_EQ(original.status(), copy.status());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOk) {
+  const int kI = 0;
+  StatusOr<const int*> source(&kI);
+  StatusOr<const int*> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+  EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
+  StatusOr<int*> source(Status::CANCELLED);
+  StatusOr<int*> target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
+  Derived derived;
+  StatusOr<Derived*> source(&derived);
+  StatusOr<Base2*>   target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+  EXPECT_EQ(static_cast<const Base2*>(source.ValueOrDie()),
+            target.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
+  StatusOr<Derived*> source(Status::CANCELLED);
+  StatusOr<Base2*>   target;
+  target = source;
+  EXPECT_EQ(source.status(), target.status());
+}
+
+TEST(StatusOr, TestPointerStatus) {
+  const int kI = 0;
+  StatusOr<const int*> good(&kI);
+  EXPECT_TRUE(good.ok());
+  StatusOr<const int*> bad(Status::CANCELLED);
+  EXPECT_EQ(Status::CANCELLED, bad.status());
+}
+
+TEST(StatusOr, TestPointerValue) {
+  const int kI = 0;
+  StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+TEST(StatusOr, TestPointerValueConst) {
+  const int kI = 0;
+  const StatusOr<const int*> thing(&kI);
+  EXPECT_EQ(&kI, thing.ValueOrDie());
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stl_util-inl.h b/src/google/protobuf/stubs/stl_util-inl.h
deleted file mode 100644
index a2e671b..0000000
--- a/src/google/protobuf/stubs/stl_util-inl.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// from google3/util/gtl/stl_util-inl.h
-
-#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
-#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
-
-#include <google/protobuf/stubs/common.h>
-
-namespace google {
-namespace protobuf {
-
-// STLDeleteContainerPointers()
-//  For a range within a container of pointers, calls delete
-//  (non-array version) on these pointers.
-// NOTE: for these three functions, we could just implement a DeleteObject
-// functor and then call for_each() on the range and functor, but this
-// requires us to pull in all of algorithm.h, which seems expensive.
-// For hash_[multi]set, it is important that this deletes behind the iterator
-// because the hash_set may call the hash function on the iterator when it is
-// advanced, which could result in the hash function trying to deference a
-// stale pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPointers(ForwardIterator begin,
-                                ForwardIterator end) {
-  while (begin != end) {
-    ForwardIterator temp = begin;
-    ++begin;
-    delete *temp;
-  }
-}
-
-// Inside Google, this function implements a horrible, disgusting hack in which
-// we reach into the string's private implementation and resize it without
-// initializing the new bytes.  In some cases doing this can significantly
-// improve performance.  However, since it's totally non-portable it has no
-// place in open source code.  Feel free to fill this function in with your
-// own disgusting hack if you want the perf boost.
-inline void STLStringResizeUninitialized(string* s, size_t new_size) {
-  s->resize(new_size);
-}
-
-// Return a mutable char* pointing to a string's internal buffer,
-// which may not be null-terminated. Writing through this pointer will
-// modify the string.
-//
-// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
-// next call to a string method that invalidates iterators.
-//
-// As of 2006-04, there is no standard-blessed way of getting a
-// mutable reference to a string's internal buffer. However, issue 530
-// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
-// proposes this as the method. According to Matt Austern, this should
-// already work on all current implementations.
-inline char* string_as_array(string* str) {
-  // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
-  return str->empty() ? NULL : &*str->begin();
-}
-
-// STLDeleteElements() deletes all the elements in an STL container and clears
-// the container.  This function is suitable for use with a vector, set,
-// hash_set, or any other STL container which defines sensible begin(), end(),
-// and clear() methods.
-//
-// If container is NULL, this function is a no-op.
-//
-// As an alternative to calling STLDeleteElements() directly, consider
-// ElementDeleter (defined below), which ensures that your container's elements
-// are deleted when the ElementDeleter goes out of scope.
-template <class T>
-void STLDeleteElements(T *container) {
-  if (!container) return;
-  STLDeleteContainerPointers(container->begin(), container->end());
-  container->clear();
-}
-
-// Given an STL container consisting of (key, value) pairs, STLDeleteValues
-// deletes all the "value" components and clears the container.  Does nothing
-// in the case it's given a NULL pointer.
-
-template <class T>
-void STLDeleteValues(T *v) {
-  if (!v) return;
-  for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
-    delete i->second;
-  }
-  v->clear();
-}
-
-}  // namespace protobuf
-}  // namespace google
-
-#endif  // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
diff --git a/src/google/protobuf/stubs/stringpiece.cc b/src/google/protobuf/stubs/stringpiece.cc
new file mode 100644
index 0000000..989474b
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece.cc
@@ -0,0 +1,268 @@
+// 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.
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <string.h>
+#include <algorithm>
+#include <climits>
+#include <string>
+#include <ostream>
+
+namespace google {
+namespace protobuf {
+std::ostream& operator<<(std::ostream& o, StringPiece piece) {
+  o.write(piece.data(), piece.size());
+  return o;
+}
+
+// Out-of-line error path.
+void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
+  GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
+}
+
+StringPiece::StringPiece(StringPiece x, stringpiece_ssize_type pos)
+    : ptr_(x.ptr_ + pos), length_(x.length_ - pos) {
+  GOOGLE_DCHECK_LE(0, pos);
+  GOOGLE_DCHECK_LE(pos, x.length_);
+}
+
+StringPiece::StringPiece(StringPiece x,
+                         stringpiece_ssize_type pos,
+                         stringpiece_ssize_type len)
+    : ptr_(x.ptr_ + pos), length_(std::min(len, x.length_ - pos)) {
+  GOOGLE_DCHECK_LE(0, pos);
+  GOOGLE_DCHECK_LE(pos, x.length_);
+  GOOGLE_DCHECK_GE(len, 0);
+}
+
+void StringPiece::CopyToString(string* target) const {
+  target->assign(ptr_, length_);
+}
+
+void StringPiece::AppendToString(string* target) const {
+  target->append(ptr_, length_);
+}
+
+bool StringPiece::Consume(StringPiece x) {
+  if (starts_with(x)) {
+    ptr_ += x.length_;
+    length_ -= x.length_;
+    return true;
+  }
+  return false;
+}
+
+bool StringPiece::ConsumeFromEnd(StringPiece x) {
+  if (ends_with(x)) {
+    length_ -= x.length_;
+    return true;
+  }
+  return false;
+}
+
+stringpiece_ssize_type StringPiece::copy(char* buf,
+                                         size_type n,
+                                         size_type pos) const {
+  stringpiece_ssize_type ret = std::min(length_ - pos, n);
+  memcpy(buf, ptr_ + pos, ret);
+  return ret;
+}
+
+bool StringPiece::contains(StringPiece s) const {
+  return find(s, 0) != npos;
+}
+
+stringpiece_ssize_type StringPiece::find(StringPiece s, size_type pos) const {
+  if (length_ <= 0 || pos > static_cast<size_type>(length_)) {
+    if (length_ == 0 && pos == 0 && s.length_ == 0) return 0;
+    return npos;
+  }
+  const char *result = std::search(ptr_ + pos, ptr_ + length_,
+                                   s.ptr_, s.ptr_ + s.length_);
+  return result == ptr_ + length_ ? npos : result - ptr_;
+}
+
+stringpiece_ssize_type StringPiece::find(char c, size_type pos) const {
+  if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
+    return npos;
+  }
+  const char* result = static_cast<const char*>(
+      memchr(ptr_ + pos, c, length_ - pos));
+  return result != NULL ? result - ptr_ : npos;
+}
+
+stringpiece_ssize_type StringPiece::rfind(StringPiece s, size_type pos) const {
+  if (length_ < s.length_) return npos;
+  const size_t ulen = length_;
+  if (s.length_ == 0) return std::min(ulen, pos);
+
+  const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
+  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+  return result != last ? result - ptr_ : npos;
+}
+
+// Search range is [0..pos] inclusive.  If pos == npos, search everything.
+stringpiece_ssize_type StringPiece::rfind(char c, size_type pos) const {
+  // Note: memrchr() is not available on Windows.
+  if (length_ <= 0) return npos;
+  for (stringpiece_ssize_type i =
+      std::min(pos, static_cast<size_type>(length_ - 1));
+       i >= 0; --i) {
+    if (ptr_[i] == c) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table.  This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char.  Thus it should be be declared
+// as follows:
+//   bool table[UCHAR_MAX + 1]
+static inline void BuildLookupTable(StringPiece characters_wanted,
+                                    bool* table) {
+  const stringpiece_ssize_type length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (stringpiece_ssize_type i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+stringpiece_ssize_type StringPiece::find_first_of(StringPiece s,
+                                                  size_type pos) const {
+  if (length_ <= 0 || s.length_ <= 0) {
+    return npos;
+  }
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (stringpiece_ssize_type i = pos; i < length_; ++i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+stringpiece_ssize_type StringPiece::find_first_not_of(StringPiece s,
+                                                      size_type pos) const {
+  if (length_ <= 0) return npos;
+  if (s.length_ <= 0) return 0;
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (stringpiece_ssize_type i = pos; i < length_; ++i) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+stringpiece_ssize_type StringPiece::find_first_not_of(char c,
+                                                      size_type pos) const {
+  if (length_ <= 0) return npos;
+
+  for (; pos < static_cast<size_type>(length_); ++pos) {
+    if (ptr_[pos] != c) {
+      return pos;
+    }
+  }
+  return npos;
+}
+
+stringpiece_ssize_type StringPiece::find_last_of(StringPiece s,
+                                                 size_type pos) const {
+  if (length_ <= 0 || s.length_ <= 0) return npos;
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (stringpiece_ssize_type i =
+       std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
+    if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+stringpiece_ssize_type StringPiece::find_last_not_of(StringPiece s,
+                                                     size_type pos) const {
+  if (length_ <= 0) return npos;
+
+  stringpiece_ssize_type i = std::min(pos, static_cast<size_type>(length_ - 1));
+  if (s.length_ <= 0) return i;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (; i >= 0; --i) {
+    if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+stringpiece_ssize_type StringPiece::find_last_not_of(char c,
+                                                     size_type pos) const {
+  if (length_ <= 0) return npos;
+
+  for (stringpiece_ssize_type i =
+       std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
+    if (ptr_[i] != c) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+StringPiece StringPiece::substr(size_type pos, size_type n) const {
+  if (pos > length_) pos = length_;
+  if (n > length_ - pos) n = length_ - pos;
+  return StringPiece(ptr_ + pos, n);
+}
+
+const StringPiece::size_type StringPiece::npos = size_type(-1);
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stringpiece.h b/src/google/protobuf/stubs/stringpiece.h
new file mode 100644
index 0000000..9167165
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece.h
@@ -0,0 +1,491 @@
+// 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.
+
+// A StringPiece points to part or all of a string, Cord, double-quoted string
+// literal, or other string-like object.  A StringPiece does *not* own the
+// string to which it points.  A StringPiece is not null-terminated.
+//
+// You can use StringPiece as a function or method parameter.  A StringPiece
+// parameter can receive a double-quoted string literal argument, a "const
+// char*" argument, a string argument, or a StringPiece argument with no data
+// copying.  Systematic use of StringPiece for arguments reduces data
+// copies and strlen() calls.
+//
+// Prefer passing StringPieces by value:
+//   void MyFunction(StringPiece arg);
+// If circumstances require, you may also pass by const reference:
+//   void MyFunction(const StringPiece& arg);  // not preferred
+// Both of these have the same lifetime semantics.  Passing by value
+// generates slightly smaller code.  For more discussion, see the thread
+// go/stringpiecebyvalue on c-users.
+//
+// StringPiece is also suitable for local variables if you know that
+// the lifetime of the underlying object is longer than the lifetime
+// of your StringPiece variable.
+//
+// Beware of binding a StringPiece to a temporary:
+//   StringPiece sp = obj.MethodReturningString();  // BAD: lifetime problem
+//
+// This code is okay:
+//   string str = obj.MethodReturningString();  // str owns its contents
+//   StringPiece sp(str);  // GOOD, because str outlives sp
+//
+// StringPiece is sometimes a poor choice for a return value and usually a poor
+// choice for a data member.  If you do use a StringPiece this way, it is your
+// responsibility to ensure that the object pointed to by the StringPiece
+// outlives the StringPiece.
+//
+// A StringPiece may represent just part of a string; thus the name "Piece".
+// For example, when splitting a string, vector<StringPiece> is a natural data
+// type for the output.  For another example, a Cord is a non-contiguous,
+// potentially very long string-like object.  The Cord class has an interface
+// that iteratively provides StringPiece objects that point to the
+// successive pieces of a Cord object.
+//
+// A StringPiece is not null-terminated.  If you write code that scans a
+// StringPiece, you must check its length before reading any characters.
+// Common idioms that work on null-terminated strings do not work on
+// StringPiece objects.
+//
+// There are several ways to create a null StringPiece:
+//   StringPiece()
+//   StringPiece(NULL)
+//   StringPiece(NULL, 0)
+// For all of the above, sp.data() == NULL, sp.length() == 0,
+// and sp.empty() == true.  Also, if you create a StringPiece with
+// a non-NULL pointer then sp.data() != NULL.  Once created,
+// sp.data() will stay either NULL or not-NULL, except if you call
+// sp.clear() or sp.set().
+//
+// Thus, you can use StringPiece(NULL) to signal an out-of-band value
+// that is different from other StringPiece values.  This is similar
+// to the way that const char* p1 = NULL; is different from
+// const char* p2 = "";.
+//
+// There are many ways to create an empty StringPiece:
+//   StringPiece()
+//   StringPiece(NULL)
+//   StringPiece(NULL, 0)
+//   StringPiece("")
+//   StringPiece("", 0)
+//   StringPiece("abcdef", 0)
+//   StringPiece("abcdef"+6, 0)
+// For all of the above, sp.length() will be 0 and sp.empty() will be true.
+// For some empty StringPiece values, sp.data() will be NULL.
+// For some empty StringPiece values, sp.data() will not be NULL.
+//
+// Be careful not to confuse: null StringPiece and empty StringPiece.
+// The set of empty StringPieces properly includes the set of null StringPieces.
+// That is, every null StringPiece is an empty StringPiece,
+// but some non-null StringPieces are empty Stringpieces too.
+//
+// All empty StringPiece values compare equal to each other.
+// Even a null StringPieces compares equal to a non-null empty StringPiece:
+//  StringPiece() == StringPiece("", 0)
+//  StringPiece(NULL) == StringPiece("abc", 0)
+//  StringPiece(NULL, 0) == StringPiece("abcdef"+6, 0)
+//
+// Look carefully at this example:
+//   StringPiece("") == NULL
+// True or false?  TRUE, because StringPiece::operator== converts
+// the right-hand side from NULL to StringPiece(NULL),
+// and then compares two zero-length spans of characters.
+// However, we are working to make this example produce a compile error.
+//
+// Suppose you want to write:
+//   bool TestWhat?(StringPiece sp) { return sp == NULL; }  // BAD
+// Do not do that.  Write one of these instead:
+//   bool TestNull(StringPiece sp) { return sp.data() == NULL; }
+//   bool TestEmpty(StringPiece sp) { return sp.empty(); }
+// The intent of TestWhat? is unclear.  Did you mean TestNull or TestEmpty?
+// Right now, TestWhat? behaves likes TestEmpty.
+// We are working to make TestWhat? produce a compile error.
+// TestNull is good to test for an out-of-band signal.
+// TestEmpty is good to test for an empty StringPiece.
+//
+// Caveats (again):
+// (1) The lifetime of the pointed-to string (or piece of a string)
+//     must be longer than the lifetime of the StringPiece.
+// (2) There may or may not be a '\0' character after the end of
+//     StringPiece data.
+// (3) A null StringPiece is empty.
+//     An empty StringPiece may or may not be a null StringPiece.
+
+#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
+#define GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <iosfwd>
+#include <limits>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
+
+namespace google {
+namespace protobuf {
+// StringPiece has *two* size types.
+// StringPiece::size_type
+//   is unsigned
+//   is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
+//   no future changes intended
+// stringpiece_ssize_type
+//   is signed
+//   is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
+//   future changes intended: http://go/64BitStringPiece
+//
+typedef string::difference_type stringpiece_ssize_type;
+
+// STRINGPIECE_CHECK_SIZE protects us from 32-bit overflows.
+// TODO(mec): delete this after stringpiece_ssize_type goes 64 bit.
+#if !defined(NDEBUG)
+#define STRINGPIECE_CHECK_SIZE 1
+#elif defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
+#define STRINGPIECE_CHECK_SIZE 1
+#else
+#define STRINGPIECE_CHECK_SIZE 0
+#endif
+
+class LIBPROTOBUF_EXPORT StringPiece {
+ private:
+  const char* ptr_;
+  stringpiece_ssize_type length_;
+
+  // Prevent overflow in debug mode or fortified mode.
+  // sizeof(stringpiece_ssize_type) may be smaller than sizeof(size_t).
+  static stringpiece_ssize_type CheckedSsizeTFromSizeT(size_t size) {
+#if STRINGPIECE_CHECK_SIZE > 0
+#ifdef max
+#undef max
+#endif
+    if (size > static_cast<size_t>(
+        std::numeric_limits<stringpiece_ssize_type>::max())) {
+      // Some people grep for this message in logs
+      // so take care if you ever change it.
+      LogFatalSizeTooBig(size, "size_t to int conversion");
+    }
+#endif
+    return static_cast<stringpiece_ssize_type>(size);
+  }
+
+  // Out-of-line error path.
+  static void LogFatalSizeTooBig(size_t size, const char* details);
+
+ public:
+  // We provide non-explicit singleton constructors so users can pass
+  // in a "const char*" or a "string" wherever a "StringPiece" is
+  // expected.
+  //
+  // Style guide exception granted:
+  // http://goto/style-guide-exception-20978288
+  StringPiece() : ptr_(NULL), length_(0) {}
+
+  StringPiece(const char* str)  // NOLINT(runtime/explicit)
+      : ptr_(str), length_(0) {
+    if (str != NULL) {
+      length_ = CheckedSsizeTFromSizeT(strlen(str));
+    }
+  }
+
+  template <class Allocator>
+  StringPiece(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>& str)
+      : ptr_(str.data()), length_(0) {
+    length_ = CheckedSsizeTFromSizeT(str.size());
+  }
+#if defined(HAS_GLOBAL_STRING)
+  template <class Allocator>
+  StringPiece(  // NOLINT(runtime/explicit)
+      const basic_string<char, std::char_traits<char>, Allocator>& str)
+      : ptr_(str.data()), length_(0) {
+    length_ = CheckedSsizeTFromSizeT(str.size());
+  }
+#endif
+
+  StringPiece(const char* offset, stringpiece_ssize_type len)
+      : ptr_(offset), length_(len) {
+    assert(len >= 0);
+  }
+
+  // Substring of another StringPiece.
+  // pos must be non-negative and <= x.length().
+  StringPiece(StringPiece x, stringpiece_ssize_type pos);
+  // Substring of another StringPiece.
+  // pos must be non-negative and <= x.length().
+  // len must be non-negative and will be pinned to at most x.length() - pos.
+  StringPiece(StringPiece x,
+              stringpiece_ssize_type pos,
+              stringpiece_ssize_type len);
+
+  // data() may return a pointer to a buffer with embedded NULs, and the
+  // returned buffer may or may not be null terminated.  Therefore it is
+  // typically a mistake to pass data() to a routine that expects a NUL
+  // terminated string.
+  const char* data() const { return ptr_; }
+  stringpiece_ssize_type size() const { return length_; }
+  stringpiece_ssize_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  void clear() {
+    ptr_ = NULL;
+    length_ = 0;
+  }
+
+  void set(const char* data, stringpiece_ssize_type len) {
+    assert(len >= 0);
+    ptr_ = data;
+    length_ = len;
+  }
+
+  void set(const char* str) {
+    ptr_ = str;
+    if (str != NULL)
+      length_ = CheckedSsizeTFromSizeT(strlen(str));
+    else
+      length_ = 0;
+  }
+
+  void set(const void* data, stringpiece_ssize_type len) {
+    ptr_ = reinterpret_cast<const char*>(data);
+    length_ = len;
+  }
+
+  char operator[](stringpiece_ssize_type i) const {
+    assert(0 <= i);
+    assert(i < length_);
+    return ptr_[i];
+  }
+
+  void remove_prefix(stringpiece_ssize_type n) {
+    assert(length_ >= n);
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(stringpiece_ssize_type n) {
+    assert(length_ >= n);
+    length_ -= n;
+  }
+
+  // returns {-1, 0, 1}
+  int compare(StringPiece x) const {
+    const stringpiece_ssize_type min_size =
+        length_ < x.length_ ? length_ : x.length_;
+    int r = memcmp(ptr_, x.ptr_, min_size);
+    if (r < 0) return -1;
+    if (r > 0) return 1;
+    if (length_ < x.length_) return -1;
+    if (length_ > x.length_) return 1;
+    return 0;
+  }
+
+  string as_string() const {
+    return ToString();
+  }
+  // We also define ToString() here, since many other string-like
+  // interfaces name the routine that converts to a C++ string
+  // "ToString", and it's confusing to have the method that does that
+  // for a StringPiece be called "as_string()".  We also leave the
+  // "as_string()" method defined here for existing code.
+  string ToString() const {
+    if (ptr_ == NULL) return string();
+    return string(data(), size());
+  }
+
+  operator string() const {
+    return ToString();
+  }
+
+  void CopyToString(string* target) const;
+  void AppendToString(string* target) const;
+
+  bool starts_with(StringPiece x) const {
+    return (length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0);
+  }
+
+  bool ends_with(StringPiece x) const {
+    return ((length_ >= x.length_) &&
+            (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
+  }
+
+  // Checks whether StringPiece starts with x and if so advances the beginning
+  // of it to past the match.  It's basically a shortcut for starts_with
+  // followed by remove_prefix.
+  bool Consume(StringPiece x);
+  // Like above but for the end of the string.
+  bool ConsumeFromEnd(StringPiece x);
+
+  // standard STL container boilerplate
+  typedef char value_type;
+  typedef const char* pointer;
+  typedef const char& reference;
+  typedef const char& const_reference;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+  static const size_type npos;
+  typedef const char* const_iterator;
+  typedef const char* iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  iterator begin() const { return ptr_; }
+  iterator end() const { return ptr_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(ptr_ + length_);
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ptr_);
+  }
+  stringpiece_ssize_type max_size() const { return length_; }
+  stringpiece_ssize_type capacity() const { return length_; }
+
+  // cpplint.py emits a false positive [build/include_what_you_use]
+  stringpiece_ssize_type copy(char* buf, size_type n, size_type pos = 0) const;  // NOLINT
+
+  bool contains(StringPiece s) const;
+
+  stringpiece_ssize_type find(StringPiece s, size_type pos = 0) const;
+  stringpiece_ssize_type find(char c, size_type pos = 0) const;
+  stringpiece_ssize_type rfind(StringPiece s, size_type pos = npos) const;
+  stringpiece_ssize_type rfind(char c, size_type pos = npos) const;
+
+  stringpiece_ssize_type find_first_of(StringPiece s, size_type pos = 0) const;
+  stringpiece_ssize_type find_first_of(char c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+  stringpiece_ssize_type find_first_not_of(StringPiece s,
+                                           size_type pos = 0) const;
+  stringpiece_ssize_type find_first_not_of(char c, size_type pos = 0) const;
+  stringpiece_ssize_type find_last_of(StringPiece s,
+                                      size_type pos = npos) const;
+  stringpiece_ssize_type find_last_of(char c, size_type pos = npos) const {
+    return rfind(c, pos);
+  }
+  stringpiece_ssize_type find_last_not_of(StringPiece s,
+                                          size_type pos = npos) const;
+  stringpiece_ssize_type find_last_not_of(char c, size_type pos = npos) const;
+
+  StringPiece substr(size_type pos, size_type n = npos) const;
+};
+
+// This large function is defined inline so that in a fairly common case where
+// one of the arguments is a literal, the compiler can elide a lot of the
+// following comparisons.
+inline bool operator==(StringPiece x, StringPiece y) {
+  stringpiece_ssize_type len = x.size();
+  if (len != y.size()) {
+    return false;
+  }
+
+  return x.data() == y.data() || len <= 0 ||
+      memcmp(x.data(), y.data(), len) == 0;
+}
+
+inline bool operator!=(StringPiece x, StringPiece y) {
+  return !(x == y);
+}
+
+inline bool operator<(StringPiece x, StringPiece y) {
+  const stringpiece_ssize_type min_size =
+      x.size() < y.size() ? x.size() : y.size();
+  const int r = memcmp(x.data(), y.data(), min_size);
+  return (r < 0) || (r == 0 && x.size() < y.size());
+}
+
+inline bool operator>(StringPiece x, StringPiece y) {
+  return y < x;
+}
+
+inline bool operator<=(StringPiece x, StringPiece y) {
+  return !(x > y);
+}
+
+inline bool operator>=(StringPiece x, StringPiece y) {
+  return !(x < y);
+}
+
+// allow StringPiece to be logged
+extern std::ostream& operator<<(std::ostream& o, StringPiece piece);
+
+namespace internal {
+// StringPiece is not a POD and can not be used in an union (pre C++11). We
+// need a POD version of it.
+struct StringPiecePod {
+  // Create from a StringPiece.
+  static StringPiecePod CreateFromStringPiece(StringPiece str) {
+    StringPiecePod pod;
+    pod.data_ = str.data();
+    pod.size_ = str.size();
+    return pod;
+  }
+
+  // Cast to StringPiece.
+  operator StringPiece() const { return StringPiece(data_, size_); }
+
+  bool operator==(const char* value) const {
+    return StringPiece(data_, size_) == StringPiece(value);
+  }
+
+  char operator[](stringpiece_ssize_type i) const {
+    assert(0 <= i);
+    assert(i < size_);
+    return data_[i];
+  }
+
+  const char* data() const { return data_; }
+
+  stringpiece_ssize_type size() const {
+    return size_;
+  }
+
+  std::string ToString() const { return std::string(data_, size_); }
+ private:
+  const char* data_;
+  stringpiece_ssize_type size_;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
+template<> struct hash<StringPiece> {
+  size_t operator()(const StringPiece& s) const {
+    size_t result = 0;
+    for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {  
+      result = 5 * result + *str;
+    }
+    return result;
+  }
+};
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
+
+#endif  // STRINGS_STRINGPIECE_H_
diff --git a/src/google/protobuf/stubs/stringpiece_unittest.cc b/src/google/protobuf/stubs/stringpiece_unittest.cc
new file mode 100644
index 0000000..a52d81f
--- /dev/null
+++ b/src/google/protobuf/stubs/stringpiece_unittest.cc
@@ -0,0 +1,794 @@
+// 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.
+#include <google/protobuf/stubs/stringpiece.h>
+
+#include <iterator>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/stubs/hash.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+TEST(StringPiece, Ctor) {
+  {
+    // Null.
+    StringPiece s10;
+    EXPECT_TRUE(s10.data() == NULL);
+    EXPECT_EQ(0, s10.length());
+  }
+
+  {
+    // const char* without length.
+    const char* hello = "hello";
+    StringPiece s20(hello);
+    EXPECT_TRUE(s20.data() == hello);
+    EXPECT_EQ(5, s20.length());
+
+    // const char* with length.
+    StringPiece s21(hello, 4);
+    EXPECT_TRUE(s21.data() == hello);
+    EXPECT_EQ(4, s21.length());
+
+    // Not recommended, but valid C++
+    StringPiece s22(hello, 6);
+    EXPECT_TRUE(s22.data() == hello);
+    EXPECT_EQ(6, s22.length());
+  }
+
+  {
+    // std::string.
+    std::string hola = "hola";
+    StringPiece s30(hola);
+    EXPECT_TRUE(s30.data() == hola.data());
+    EXPECT_EQ(4, s30.length());
+
+    // std::string with embedded '\0'.
+    hola.push_back('\0');
+    hola.append("h2");
+    hola.push_back('\0');
+    StringPiece s31(hola);
+    EXPECT_TRUE(s31.data() == hola.data());
+    EXPECT_EQ(8, s31.length());
+  }
+
+#if defined(HAS_GLOBAL_STRING)
+  {
+    // ::string
+    string bonjour = "bonjour";
+    StringPiece s40(bonjour);
+    EXPECT_TRUE(s40.data() == bonjour.data());
+    EXPECT_EQ(7, s40.length());
+  }
+#endif
+
+  // TODO(mec): StringPiece(StringPiece x, int pos);
+  // TODO(mec): StringPiece(StringPiece x, int pos, int len);
+  // TODO(mec): StringPiece(const StringPiece&);
+}
+
+TEST(StringPiece, STLComparator) {
+  string s1("foo");
+  string s2("bar");
+  string s3("baz");
+
+  StringPiece p1(s1);
+  StringPiece p2(s2);
+  StringPiece p3(s3);
+
+  typedef std::map<StringPiece, int> TestMap;
+  TestMap map;
+
+  map.insert(std::make_pair(p1, 0));
+  map.insert(std::make_pair(p2, 1));
+  map.insert(std::make_pair(p3, 2));
+  EXPECT_EQ(map.size(), 3);
+
+  TestMap::const_iterator iter = map.begin();
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  EXPECT_EQ(iter->second, 0);
+  ++iter;
+  EXPECT_TRUE(iter == map.end());
+
+  TestMap::iterator new_iter = map.find("zot");
+  EXPECT_TRUE(new_iter == map.end());
+
+  new_iter = map.find("bar");
+  EXPECT_TRUE(new_iter != map.end());
+
+  map.erase(new_iter);
+  EXPECT_EQ(map.size(), 2);
+
+  iter = map.begin();
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  EXPECT_EQ(iter->second, 0);
+  ++iter;
+  EXPECT_TRUE(iter == map.end());
+}
+
+TEST(StringPiece, ComparisonOperators) {
+#define COMPARE(result, op, x, y) \
+  EXPECT_EQ(result, StringPiece((x)) op StringPiece((y))); \
+  EXPECT_EQ(result, StringPiece((x)).compare(StringPiece((y))) op 0)
+
+  COMPARE(true, ==, "",   "");
+  COMPARE(true, ==, "", NULL);
+  COMPARE(true, ==, NULL, "");
+  COMPARE(true, ==, "a",  "a");
+  COMPARE(true, ==, "aa", "aa");
+  COMPARE(false, ==, "a",  "");
+  COMPARE(false, ==, "",   "a");
+  COMPARE(false, ==, "a",  "b");
+  COMPARE(false, ==, "a",  "aa");
+  COMPARE(false, ==, "aa", "a");
+
+  COMPARE(false, !=, "",   "");
+  COMPARE(false, !=, "a",  "a");
+  COMPARE(false, !=, "aa", "aa");
+  COMPARE(true, !=, "a",  "");
+  COMPARE(true, !=, "",   "a");
+  COMPARE(true, !=, "a",  "b");
+  COMPARE(true, !=, "a",  "aa");
+  COMPARE(true, !=, "aa", "a");
+
+  COMPARE(true, <, "a",  "b");
+  COMPARE(true, <, "a",  "aa");
+  COMPARE(true, <, "aa", "b");
+  COMPARE(true, <, "aa", "bb");
+  COMPARE(false, <, "a",  "a");
+  COMPARE(false, <, "b",  "a");
+  COMPARE(false, <, "aa", "a");
+  COMPARE(false, <, "b",  "aa");
+  COMPARE(false, <, "bb", "aa");
+
+  COMPARE(true, <=, "a",  "a");
+  COMPARE(true, <=, "a",  "b");
+  COMPARE(true, <=, "a",  "aa");
+  COMPARE(true, <=, "aa", "b");
+  COMPARE(true, <=, "aa", "bb");
+  COMPARE(false, <=, "b",  "a");
+  COMPARE(false, <=, "aa", "a");
+  COMPARE(false, <=, "b",  "aa");
+  COMPARE(false, <=, "bb", "aa");
+
+  COMPARE(false, >=, "a",  "b");
+  COMPARE(false, >=, "a",  "aa");
+  COMPARE(false, >=, "aa", "b");
+  COMPARE(false, >=, "aa", "bb");
+  COMPARE(true, >=, "a",  "a");
+  COMPARE(true, >=, "b",  "a");
+  COMPARE(true, >=, "aa", "a");
+  COMPARE(true, >=, "b",  "aa");
+  COMPARE(true, >=, "bb", "aa");
+
+  COMPARE(false, >, "a",  "a");
+  COMPARE(false, >, "a",  "b");
+  COMPARE(false, >, "a",  "aa");
+  COMPARE(false, >, "aa", "b");
+  COMPARE(false, >, "aa", "bb");
+  COMPARE(true, >, "b",  "a");
+  COMPARE(true, >, "aa", "a");
+  COMPARE(true, >, "b",  "aa");
+  COMPARE(true, >, "bb", "aa");
+
+  string x;
+  for (int i = 0; i < 256; i++) {
+    x += 'a';
+    string y = x;
+    COMPARE(true, ==, x, y);
+    for (int j = 0; j < i; j++) {
+      string z = x;
+      z[j] = 'b';       // Differs in position 'j'
+      COMPARE(false, ==, x, z);
+      COMPARE(true, <, x, z);
+      COMPARE(true, >, z, x);
+      if (j + 1 < i) {
+        z[j + 1] = 'A';  // Differs in position 'j+1' as well
+        COMPARE(false, ==, x, z);
+        COMPARE(true, <, x, z);
+        COMPARE(true, >, z, x);
+        z[j + 1] = 'z';  // Differs in position 'j+1' as well
+        COMPARE(false, ==, x, z);
+        COMPARE(true, <, x, z);
+        COMPARE(true, >, z, x);
+      }
+    }
+  }
+
+#undef COMPARE
+}
+
+TEST(StringPiece, STL1) {
+  const StringPiece a("abcdefghijklmnopqrstuvwxyz");
+  const StringPiece b("abc");
+  const StringPiece c("xyz");
+  const StringPiece d("foobar");
+  const StringPiece e;
+  string temp("123");
+  temp += '\0';
+  temp += "456";
+  const StringPiece f(temp);
+
+  EXPECT_EQ(a[6], 'g');
+  EXPECT_EQ(b[0], 'a');
+  EXPECT_EQ(c[2], 'z');
+  EXPECT_EQ(f[3], '\0');
+  EXPECT_EQ(f[5], '5');
+
+  EXPECT_EQ(*d.data(), 'f');
+  EXPECT_EQ(d.data()[5], 'r');
+  EXPECT_TRUE(e.data() == NULL);
+
+  EXPECT_EQ(*a.begin(), 'a');
+  EXPECT_EQ(*(b.begin() + 2), 'c');
+  EXPECT_EQ(*(c.end() - 1), 'z');
+
+  EXPECT_EQ(*a.rbegin(), 'z');
+  EXPECT_EQ(*(b.rbegin() + 2), 'a');
+  EXPECT_EQ(*(c.rend() - 1), 'x');
+  EXPECT_TRUE(a.rbegin() + 26 == a.rend());
+
+  EXPECT_EQ(a.size(), 26);
+  EXPECT_EQ(b.size(), 3);
+  EXPECT_EQ(c.size(), 3);
+  EXPECT_EQ(d.size(), 6);
+  EXPECT_EQ(e.size(), 0);
+  EXPECT_EQ(f.size(), 7);
+
+  EXPECT_TRUE(!d.empty());
+  EXPECT_TRUE(d.begin() != d.end());
+  EXPECT_TRUE(d.begin() + 6 == d.end());
+
+  EXPECT_TRUE(e.empty());
+  EXPECT_TRUE(e.begin() == e.end());
+
+  EXPECT_GE(a.max_size(), a.capacity());
+  EXPECT_GE(a.capacity(), a.size());
+
+  char buf[4] = { '%', '%', '%', '%' };
+  EXPECT_EQ(a.copy(buf, 4), 4);
+  EXPECT_EQ(buf[0], a[0]);
+  EXPECT_EQ(buf[1], a[1]);
+  EXPECT_EQ(buf[2], a[2]);
+  EXPECT_EQ(buf[3], a[3]);
+  EXPECT_EQ(a.copy(buf, 3, 7), 3);
+  EXPECT_EQ(buf[0], a[7]);
+  EXPECT_EQ(buf[1], a[8]);
+  EXPECT_EQ(buf[2], a[9]);
+  EXPECT_EQ(buf[3], a[3]);
+  EXPECT_EQ(c.copy(buf, 99), 3);
+  EXPECT_EQ(buf[0], c[0]);
+  EXPECT_EQ(buf[1], c[1]);
+  EXPECT_EQ(buf[2], c[2]);
+  EXPECT_EQ(buf[3], a[3]);
+}
+
+// Separated from STL1() because some compilers produce an overly
+// large stack frame for the combined function.
+TEST(StringPiece, STL2) {
+  const StringPiece a("abcdefghijklmnopqrstuvwxyz");
+  const StringPiece b("abc");
+  const StringPiece c("xyz");
+  StringPiece d("foobar");
+  const StringPiece e;
+  const StringPiece f("123" "\0" "456", 7);
+
+  d.clear();
+  EXPECT_EQ(d.size(), 0);
+  EXPECT_TRUE(d.empty());
+  EXPECT_TRUE(d.data() == NULL);
+  EXPECT_TRUE(d.begin() == d.end());
+
+  EXPECT_EQ(StringPiece::npos, string::npos);
+
+  EXPECT_EQ(a.find(b), 0);
+  EXPECT_EQ(a.find(b, 1), StringPiece::npos);
+  EXPECT_EQ(a.find(c), 23);
+  EXPECT_EQ(a.find(c, 9), 23);
+  EXPECT_EQ(a.find(c, StringPiece::npos), StringPiece::npos);
+  EXPECT_EQ(b.find(c), StringPiece::npos);
+  EXPECT_EQ(b.find(c, StringPiece::npos), StringPiece::npos);
+  EXPECT_EQ(a.find(d), 0);
+  EXPECT_EQ(a.find(e), 0);
+  EXPECT_EQ(a.find(d, 12), 12);
+  EXPECT_EQ(a.find(e, 17), 17);
+  StringPiece g("xx not found bb");
+  EXPECT_EQ(a.find(g), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(d.find(b), StringPiece::npos);
+  EXPECT_EQ(e.find(b), StringPiece::npos);
+  EXPECT_EQ(d.find(b, 4), StringPiece::npos);
+  EXPECT_EQ(e.find(b, 7), StringPiece::npos);
+
+  size_t empty_search_pos = string().find(string());
+  EXPECT_EQ(d.find(d), empty_search_pos);
+  EXPECT_EQ(d.find(e), empty_search_pos);
+  EXPECT_EQ(e.find(d), empty_search_pos);
+  EXPECT_EQ(e.find(e), empty_search_pos);
+  EXPECT_EQ(d.find(d, 4), string().find(string(), 4));
+  EXPECT_EQ(d.find(e, 4), string().find(string(), 4));
+  EXPECT_EQ(e.find(d, 4), string().find(string(), 4));
+  EXPECT_EQ(e.find(e, 4), string().find(string(), 4));
+
+  EXPECT_EQ(a.find('a'), 0);
+  EXPECT_EQ(a.find('c'), 2);
+  EXPECT_EQ(a.find('z'), 25);
+  EXPECT_EQ(a.find('$'), StringPiece::npos);
+  EXPECT_EQ(a.find('\0'), StringPiece::npos);
+  EXPECT_EQ(f.find('\0'), 3);
+  EXPECT_EQ(f.find('3'), 2);
+  EXPECT_EQ(f.find('5'), 5);
+  EXPECT_EQ(g.find('o'), 4);
+  EXPECT_EQ(g.find('o', 4), 4);
+  EXPECT_EQ(g.find('o', 5), 8);
+  EXPECT_EQ(a.find('b', 5), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(d.find('\0'), StringPiece::npos);
+  EXPECT_EQ(e.find('\0'), StringPiece::npos);
+  EXPECT_EQ(d.find('\0', 4), StringPiece::npos);
+  EXPECT_EQ(e.find('\0', 7), StringPiece::npos);
+  EXPECT_EQ(d.find('x'), StringPiece::npos);
+  EXPECT_EQ(e.find('x'), StringPiece::npos);
+  EXPECT_EQ(d.find('x', 4), StringPiece::npos);
+  EXPECT_EQ(e.find('x', 7), StringPiece::npos);
+
+  EXPECT_EQ(a.rfind(b), 0);
+  EXPECT_EQ(a.rfind(b, 1), 0);
+  EXPECT_EQ(a.rfind(c), 23);
+  EXPECT_EQ(a.rfind(c, 22), StringPiece::npos);
+  EXPECT_EQ(a.rfind(c, 1), StringPiece::npos);
+  EXPECT_EQ(a.rfind(c, 0), StringPiece::npos);
+  EXPECT_EQ(b.rfind(c), StringPiece::npos);
+  EXPECT_EQ(b.rfind(c, 0), StringPiece::npos);
+  EXPECT_EQ(a.rfind(d), a.as_string().rfind(string()));
+  EXPECT_EQ(a.rfind(e), a.as_string().rfind(string()));
+  EXPECT_EQ(a.rfind(d, 12), 12);
+  EXPECT_EQ(a.rfind(e, 17), 17);
+  EXPECT_EQ(a.rfind(g), StringPiece::npos);
+  EXPECT_EQ(d.rfind(b), StringPiece::npos);
+  EXPECT_EQ(e.rfind(b), StringPiece::npos);
+  EXPECT_EQ(d.rfind(b, 4), StringPiece::npos);
+  EXPECT_EQ(e.rfind(b, 7), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(d.rfind(d, 4), string().rfind(string()));
+  EXPECT_EQ(e.rfind(d, 7), string().rfind(string()));
+  EXPECT_EQ(d.rfind(e, 4), string().rfind(string()));
+  EXPECT_EQ(e.rfind(e, 7), string().rfind(string()));
+  EXPECT_EQ(d.rfind(d), string().rfind(string()));
+  EXPECT_EQ(e.rfind(d), string().rfind(string()));
+  EXPECT_EQ(d.rfind(e), string().rfind(string()));
+  EXPECT_EQ(e.rfind(e), string().rfind(string()));
+
+  EXPECT_EQ(g.rfind('o'), 8);
+  EXPECT_EQ(g.rfind('q'), StringPiece::npos);
+  EXPECT_EQ(g.rfind('o', 8), 8);
+  EXPECT_EQ(g.rfind('o', 7), 4);
+  EXPECT_EQ(g.rfind('o', 3), StringPiece::npos);
+  EXPECT_EQ(f.rfind('\0'), 3);
+  EXPECT_EQ(f.rfind('\0', 12), 3);
+  EXPECT_EQ(f.rfind('3'), 2);
+  EXPECT_EQ(f.rfind('5'), 5);
+  // empty string nonsense
+  EXPECT_EQ(d.rfind('o'), StringPiece::npos);
+  EXPECT_EQ(e.rfind('o'), StringPiece::npos);
+  EXPECT_EQ(d.rfind('o', 4), StringPiece::npos);
+  EXPECT_EQ(e.rfind('o', 7), StringPiece::npos);
+
+  EXPECT_EQ(a.find_first_of(b), 0);
+  EXPECT_EQ(a.find_first_of(b, 0), 0);
+  EXPECT_EQ(a.find_first_of(b, 1), 1);
+  EXPECT_EQ(a.find_first_of(b, 2), 2);
+  EXPECT_EQ(a.find_first_of(b, 3), StringPiece::npos);
+  EXPECT_EQ(a.find_first_of(c), 23);
+  EXPECT_EQ(a.find_first_of(c, 23), 23);
+  EXPECT_EQ(a.find_first_of(c, 24), 24);
+  EXPECT_EQ(a.find_first_of(c, 25), 25);
+  EXPECT_EQ(a.find_first_of(c, 26), StringPiece::npos);
+  EXPECT_EQ(g.find_first_of(b), 13);
+  EXPECT_EQ(g.find_first_of(c), 0);
+  EXPECT_EQ(a.find_first_of(f), StringPiece::npos);
+  EXPECT_EQ(f.find_first_of(a), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(a.find_first_of(d), StringPiece::npos);
+  EXPECT_EQ(a.find_first_of(e), StringPiece::npos);
+  EXPECT_EQ(d.find_first_of(b), StringPiece::npos);
+  EXPECT_EQ(e.find_first_of(b), StringPiece::npos);
+  EXPECT_EQ(d.find_first_of(d), StringPiece::npos);
+  EXPECT_EQ(e.find_first_of(d), StringPiece::npos);
+  EXPECT_EQ(d.find_first_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_first_of(e), StringPiece::npos);
+
+  EXPECT_EQ(a.find_first_not_of(b), 3);
+  EXPECT_EQ(a.find_first_not_of(c), 0);
+  EXPECT_EQ(b.find_first_not_of(a), StringPiece::npos);
+  EXPECT_EQ(c.find_first_not_of(a), StringPiece::npos);
+  EXPECT_EQ(f.find_first_not_of(a), 0);
+  EXPECT_EQ(a.find_first_not_of(f), 0);
+  EXPECT_EQ(a.find_first_not_of(d), 0);
+  EXPECT_EQ(a.find_first_not_of(e), 0);
+  // empty string nonsense
+  EXPECT_EQ(d.find_first_not_of(a), StringPiece::npos);
+  EXPECT_EQ(e.find_first_not_of(a), StringPiece::npos);
+  EXPECT_EQ(d.find_first_not_of(d), StringPiece::npos);
+  EXPECT_EQ(e.find_first_not_of(d), StringPiece::npos);
+  EXPECT_EQ(d.find_first_not_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_first_not_of(e), StringPiece::npos);
+
+  StringPiece h("====");
+  EXPECT_EQ(h.find_first_not_of('='), StringPiece::npos);
+  EXPECT_EQ(h.find_first_not_of('=', 3), StringPiece::npos);
+  EXPECT_EQ(h.find_first_not_of('\0'), 0);
+  EXPECT_EQ(g.find_first_not_of('x'), 2);
+  EXPECT_EQ(f.find_first_not_of('\0'), 0);
+  EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
+  EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
+  // empty string nonsense
+  EXPECT_EQ(d.find_first_not_of('x'), StringPiece::npos);
+  EXPECT_EQ(e.find_first_not_of('x'), StringPiece::npos);
+  EXPECT_EQ(d.find_first_not_of('\0'), StringPiece::npos);
+  EXPECT_EQ(e.find_first_not_of('\0'), StringPiece::npos);
+
+  //  StringPiece g("xx not found bb");
+  StringPiece i("56");
+  EXPECT_EQ(h.find_last_of(a), StringPiece::npos);
+  EXPECT_EQ(g.find_last_of(a), g.size()-1);
+  EXPECT_EQ(a.find_last_of(b), 2);
+  EXPECT_EQ(a.find_last_of(c), a.size()-1);
+  EXPECT_EQ(f.find_last_of(i), 6);
+  EXPECT_EQ(a.find_last_of('a'), 0);
+  EXPECT_EQ(a.find_last_of('b'), 1);
+  EXPECT_EQ(a.find_last_of('z'), 25);
+  EXPECT_EQ(a.find_last_of('a', 5), 0);
+  EXPECT_EQ(a.find_last_of('b', 5), 1);
+  EXPECT_EQ(a.find_last_of('b', 0), StringPiece::npos);
+  EXPECT_EQ(a.find_last_of('z', 25), 25);
+  EXPECT_EQ(a.find_last_of('z', 24), StringPiece::npos);
+  EXPECT_EQ(f.find_last_of(i, 5), 5);
+  EXPECT_EQ(f.find_last_of(i, 6), 6);
+  EXPECT_EQ(f.find_last_of(a, 4), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(f.find_last_of(d), StringPiece::npos);
+  EXPECT_EQ(f.find_last_of(e), StringPiece::npos);
+  EXPECT_EQ(f.find_last_of(d, 4), StringPiece::npos);
+  EXPECT_EQ(f.find_last_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(d), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(d), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(e), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(f), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(f), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(d, 4), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(d, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(d.find_last_of(f, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_of(f, 4), StringPiece::npos);
+
+  EXPECT_EQ(a.find_last_not_of(b), a.size()-1);
+  EXPECT_EQ(a.find_last_not_of(c), 22);
+  EXPECT_EQ(b.find_last_not_of(a), StringPiece::npos);
+  EXPECT_EQ(b.find_last_not_of(b), StringPiece::npos);
+  EXPECT_EQ(f.find_last_not_of(i), 4);
+  EXPECT_EQ(a.find_last_not_of(c, 24), 22);
+  EXPECT_EQ(a.find_last_not_of(b, 3), 3);
+  EXPECT_EQ(a.find_last_not_of(b, 2), StringPiece::npos);
+  // empty string nonsense
+  EXPECT_EQ(f.find_last_not_of(d), f.size()-1);
+  EXPECT_EQ(f.find_last_not_of(e), f.size()-1);
+  EXPECT_EQ(f.find_last_not_of(d, 4), 4);
+  EXPECT_EQ(f.find_last_not_of(e, 4), 4);
+  EXPECT_EQ(d.find_last_not_of(d), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of(e), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(d), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(e), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of(f), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(f), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of(d, 4), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(d, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(e, 4), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of(f, 4), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of(f, 4), StringPiece::npos);
+
+  EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
+  EXPECT_EQ(h.find_last_not_of('='), StringPiece::npos);
+  EXPECT_EQ(b.find_last_not_of('c'), 1);
+  EXPECT_EQ(h.find_last_not_of('x', 2), 2);
+  EXPECT_EQ(h.find_last_not_of('=', 2), StringPiece::npos);
+  EXPECT_EQ(b.find_last_not_of('b', 1), 0);
+  // empty string nonsense
+  EXPECT_EQ(d.find_last_not_of('x'), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of('x'), StringPiece::npos);
+  EXPECT_EQ(d.find_last_not_of('\0'), StringPiece::npos);
+  EXPECT_EQ(e.find_last_not_of('\0'), StringPiece::npos);
+
+  EXPECT_EQ(a.substr(0, 3), b);
+  EXPECT_EQ(a.substr(23), c);
+  EXPECT_EQ(a.substr(23, 3), c);
+  EXPECT_EQ(a.substr(23, 99), c);
+  EXPECT_EQ(a.substr(0), a);
+  EXPECT_EQ(a.substr(3, 2), "de");
+  // empty string nonsense
+  EXPECT_EQ(a.substr(99, 2), e);
+  EXPECT_EQ(d.substr(99), e);
+  EXPECT_EQ(d.substr(0, 99), e);
+  EXPECT_EQ(d.substr(99, 99), e);
+  // use of npos
+  EXPECT_EQ(a.substr(0, StringPiece::npos), a);
+  EXPECT_EQ(a.substr(23, StringPiece::npos), c);
+  EXPECT_EQ(a.substr(StringPiece::npos, 0), e);
+  EXPECT_EQ(a.substr(StringPiece::npos, 1), e);
+  EXPECT_EQ(a.substr(StringPiece::npos, StringPiece::npos), e);
+
+  // Substring constructors.
+  EXPECT_EQ(StringPiece(a, 0, 3), b);
+  EXPECT_EQ(StringPiece(a, 23), c);
+  EXPECT_EQ(StringPiece(a, 23, 3), c);
+  EXPECT_EQ(StringPiece(a, 23, 99), c);
+  EXPECT_EQ(StringPiece(a, 0), a);
+  EXPECT_EQ(StringPiece(a, 3, 2), "de");
+  // empty string nonsense
+  EXPECT_EQ(StringPiece(d, 0, 99), e);
+  // Verify that they work taking an actual string, not just a StringPiece.
+  string a2 = a.as_string();
+  EXPECT_EQ(StringPiece(a2, 0, 3), b);
+  EXPECT_EQ(StringPiece(a2, 23), c);
+  EXPECT_EQ(StringPiece(a2, 23, 3), c);
+  EXPECT_EQ(StringPiece(a2, 23, 99), c);
+  EXPECT_EQ(StringPiece(a2, 0), a);
+  EXPECT_EQ(StringPiece(a2, 3, 2), "de");
+}
+
+TEST(StringPiece, Custom) {
+  StringPiece a("foobar");
+  string s1("123");
+  s1 += '\0';
+  s1 += "456";
+  StringPiece b(s1);
+  StringPiece e;
+  string s2;
+
+  // CopyToString
+  a.CopyToString(&s2);
+  EXPECT_EQ(s2.size(), 6);
+  EXPECT_EQ(s2, "foobar");
+  b.CopyToString(&s2);
+  EXPECT_EQ(s2.size(), 7);
+  EXPECT_EQ(s1, s2);
+  e.CopyToString(&s2);
+  EXPECT_TRUE(s2.empty());
+
+  // AppendToString
+  s2.erase();
+  a.AppendToString(&s2);
+  EXPECT_EQ(s2.size(), 6);
+  EXPECT_EQ(s2, "foobar");
+  a.AppendToString(&s2);
+  EXPECT_EQ(s2.size(), 12);
+  EXPECT_EQ(s2, "foobarfoobar");
+
+  // starts_with
+  EXPECT_TRUE(a.starts_with(a));
+  EXPECT_TRUE(a.starts_with("foo"));
+  EXPECT_TRUE(a.starts_with(e));
+  EXPECT_TRUE(b.starts_with(s1));
+  EXPECT_TRUE(b.starts_with(b));
+  EXPECT_TRUE(b.starts_with(e));
+  EXPECT_TRUE(e.starts_with(""));
+  EXPECT_TRUE(!a.starts_with(b));
+  EXPECT_TRUE(!b.starts_with(a));
+  EXPECT_TRUE(!e.starts_with(a));
+
+  // ends with
+  EXPECT_TRUE(a.ends_with(a));
+  EXPECT_TRUE(a.ends_with("bar"));
+  EXPECT_TRUE(a.ends_with(e));
+  EXPECT_TRUE(b.ends_with(s1));
+  EXPECT_TRUE(b.ends_with(b));
+  EXPECT_TRUE(b.ends_with(e));
+  EXPECT_TRUE(e.ends_with(""));
+  EXPECT_TRUE(!a.ends_with(b));
+  EXPECT_TRUE(!b.ends_with(a));
+  EXPECT_TRUE(!e.ends_with(a));
+
+  // remove_prefix
+  StringPiece c(a);
+  c.remove_prefix(3);
+  EXPECT_EQ(c, "bar");
+  c = a;
+  c.remove_prefix(0);
+  EXPECT_EQ(c, a);
+  c.remove_prefix(c.size());
+  EXPECT_EQ(c, e);
+
+  // remove_suffix
+  c = a;
+  c.remove_suffix(3);
+  EXPECT_EQ(c, "foo");
+  c = a;
+  c.remove_suffix(0);
+  EXPECT_EQ(c, a);
+  c.remove_suffix(c.size());
+  EXPECT_EQ(c, e);
+
+  // set
+  c.set("foobar", 6);
+  EXPECT_EQ(c, a);
+  c.set("foobar", 0);
+  EXPECT_EQ(c, e);
+  c.set("foobar", 7);
+  EXPECT_NE(c, a);
+
+  c.set("foobar");
+  EXPECT_EQ(c, a);
+
+  c.set(static_cast<const void*>("foobar"), 6);
+  EXPECT_EQ(c, a);
+  c.set(static_cast<const void*>("foobar"), 0);
+  EXPECT_EQ(c, e);
+  c.set(static_cast<const void*>("foobar"), 7);
+  EXPECT_NE(c, a);
+
+  // as_string
+  string s3(a.as_string().c_str(), 7);
+  EXPECT_EQ(c, s3);
+  string s4(e.as_string());
+  EXPECT_TRUE(s4.empty());
+
+  // ToString
+  {
+    string s5(a.ToString().c_str(), 7);
+    EXPECT_EQ(c, s5);
+    string s6(e.ToString());
+    EXPECT_TRUE(s6.empty());
+  }
+
+  // Consume
+  a.set("foobar");
+  EXPECT_TRUE(a.Consume("foo"));
+  EXPECT_EQ(a, "bar");
+  EXPECT_FALSE(a.Consume("foo"));
+  EXPECT_FALSE(a.Consume("barbar"));
+  EXPECT_FALSE(a.Consume("ar"));
+  EXPECT_EQ(a, "bar");
+
+  a.set("foobar");
+  EXPECT_TRUE(a.ConsumeFromEnd("bar"));
+  EXPECT_EQ(a, "foo");
+  EXPECT_FALSE(a.ConsumeFromEnd("bar"));
+  EXPECT_FALSE(a.ConsumeFromEnd("foofoo"));
+  EXPECT_FALSE(a.ConsumeFromEnd("fo"));
+  EXPECT_EQ(a, "foo");
+}
+
+TEST(StringPiece, Contains) {
+  StringPiece a("abcdefg");
+  StringPiece b("abcd");
+  StringPiece c("efg");
+  StringPiece d("gh");
+  EXPECT_TRUE(a.contains(b));
+  EXPECT_TRUE(a.contains(c));
+  EXPECT_TRUE(!a.contains(d));
+}
+
+TEST(StringPiece, NULLInput) {
+  // we used to crash here, but now we don't.
+  StringPiece s(NULL);
+  EXPECT_EQ(s.data(), (const char*)NULL);
+  EXPECT_EQ(s.size(), 0);
+
+  s.set(NULL);
+  EXPECT_EQ(s.data(), (const char*)NULL);
+  EXPECT_EQ(s.size(), 0);
+
+  // .ToString() on a StringPiece with NULL should produce the empty string.
+  EXPECT_EQ("", s.ToString());
+  EXPECT_EQ("", s.as_string());
+}
+
+TEST(StringPiece, Comparisons2) {
+  StringPiece abc("abcdefghijklmnopqrstuvwxyz");
+
+  // check comparison operations on strings longer than 4 bytes.
+  EXPECT_EQ(abc, StringPiece("abcdefghijklmnopqrstuvwxyz"));
+  EXPECT_EQ(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyz")), 0);
+
+  EXPECT_LT(abc, StringPiece("abcdefghijklmnopqrstuvwxzz"));
+  EXPECT_LT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxzz")), 0);
+
+  EXPECT_GT(abc, StringPiece("abcdefghijklmnopqrstuvwxyy"));
+  EXPECT_GT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyy")), 0);
+
+  // starts_with
+  EXPECT_TRUE(abc.starts_with(abc));
+  EXPECT_TRUE(abc.starts_with("abcdefghijklm"));
+  EXPECT_TRUE(!abc.starts_with("abcdefguvwxyz"));
+
+  // ends_with
+  EXPECT_TRUE(abc.ends_with(abc));
+  EXPECT_TRUE(!abc.ends_with("abcdefguvwxyz"));
+  EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz"));
+}
+
+TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
+  EXPECT_EQ("hello", string("hello"));
+  EXPECT_LT("hello", string("world"));
+}
+
+TEST(ComparisonOpsTest, HeterogenousStringPieceEquals) {
+  EXPECT_EQ(StringPiece("hello"), string("hello"));
+  EXPECT_EQ("hello", StringPiece("hello"));
+}
+
+TEST(FindOneCharTest, EdgeCases) {
+  StringPiece a("xxyyyxx");
+
+  // Set a = "xyyyx".
+  a.remove_prefix(1);
+  a.remove_suffix(1);
+
+  EXPECT_EQ(0, a.find('x'));
+  EXPECT_EQ(0, a.find('x', 0));
+  EXPECT_EQ(4, a.find('x', 1));
+  EXPECT_EQ(4, a.find('x', 4));
+  EXPECT_EQ(StringPiece::npos, a.find('x', 5));
+
+  EXPECT_EQ(4, a.rfind('x'));
+  EXPECT_EQ(4, a.rfind('x', 5));
+  EXPECT_EQ(4, a.rfind('x', 4));
+  EXPECT_EQ(0, a.rfind('x', 3));
+  EXPECT_EQ(0, a.rfind('x', 0));
+
+  // Set a = "yyy".
+  a.remove_prefix(1);
+  a.remove_suffix(1);
+
+  EXPECT_EQ(StringPiece::npos, a.find('x'));
+  EXPECT_EQ(StringPiece::npos, a.rfind('x'));
+}
+
+#ifndef NDEBUG
+TEST(NonNegativeLenTest, NonNegativeLen) {
+  EXPECT_DEATH(StringPiece("xyz", -1), "len >= 0");
+}
+#endif  // ndef DEBUG
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc
index 3272d8e..83fdfe4 100644
--- a/src/google/protobuf/stubs/stringprintf.cc
+++ b/src/google/protobuf/stubs/stringprintf.cc
@@ -37,7 +37,6 @@
 #include <stdio.h> // MSVC requires this for _vsnprintf
 #include <vector>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/testing/googletest.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/stubs/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc
index 0f6afe6..d79a6ee 100644
--- a/src/google/protobuf/stubs/structurally_valid.cc
+++ b/src/google/protobuf/stubs/structurally_valid.cc
@@ -3,6 +3,8 @@
 
 #include <google/protobuf/stubs/common.h>
 
+#include <google/protobuf/stubs/stringpiece.h>
+
 namespace google {
 namespace protobuf {
 namespace internal {
@@ -531,6 +533,56 @@
   return (bytes_consumed == len);
 }
 
+int UTF8SpnStructurallyValid(const StringPiece& str) {
+  if (!module_initialized_) return str.size();
+
+  int bytes_consumed = 0;
+  UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
+                           str.data(), str.size(), &bytes_consumed);
+  return bytes_consumed;
+}
+
+// Coerce UTF-8 byte string in src_str to be
+// a structurally-valid equal-length string by selectively
+// overwriting illegal bytes with replace_char (typically blank).
+// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
+// src_str is read-only. If any overwriting is needed, a modified byte string
+// is created in idst, length isrclen.
+//
+// Returns pointer to output buffer, isrc if no changes were made,
+//  or idst if some bytes were changed.
+//
+// Fast case: all is structurally valid and no byte copying is done.
+//
+char* UTF8CoerceToStructurallyValid(const StringPiece& src_str,
+                                    char* idst,
+                                    const char replace_char) {
+  const char* isrc = src_str.data();
+  const int len = src_str.length();
+  int n = UTF8SpnStructurallyValid(src_str);
+  if (n == len) {               // Normal case -- all is cool, return
+    return const_cast<char*>(isrc);
+  } else {                      // Unusual case -- copy w/o bad bytes
+    const char* src = isrc;
+    const char* srclimit = isrc + len;
+    char* dst = idst;
+    memmove(dst, src, n);       // Copy initial good chunk
+    src += n;
+    dst += n;
+    while (src < srclimit) {    // src points to bogus byte or is off the end
+      dst[0] = replace_char;                    // replace one bad byte
+      src++;
+      dst++;
+      StringPiece str2(src, srclimit - src);
+      n = UTF8SpnStructurallyValid(str2);       // scan the remainder
+      memmove(dst, src, n);                     // copy next good chunk
+      src += n;
+      dst += n;
+    }
+  }
+  return idst;
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index a898259..7ba92e8 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -31,6 +31,8 @@
 // from google3/strings/strutil.cc
 
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
+
 #include <errno.h>
 #include <float.h>    // FLT_DIG and DBL_DIG
 #include <limits>
@@ -38,6 +40,8 @@
 #include <stdio.h>
 #include <iterator>
 
+#include <google/protobuf/stubs/stl_util.h>
+
 #ifdef _WIN32
 // MSVC has only _snprintf, not snprintf.
 //
@@ -55,11 +59,6 @@
 namespace google {
 namespace protobuf {
 
-inline bool IsNaN(double value) {
-  // NaN is never equal to anything, even itself.
-  return value != value;
-}
-
 // These are defined as macros on some platforms.  #undef them so that we can
 // redefine them.
 #undef isxdigit
@@ -94,6 +93,34 @@
   }
 }
 
+void StripWhitespace(string* str) {
+  int str_length = str->length();
+
+  // Strip off leading whitespace.
+  int first = 0;
+  while (first < str_length && ascii_isspace(str->at(first))) {
+    ++first;
+  }
+  // If entire string is white space.
+  if (first == str_length) {
+    str->clear();
+    return;
+  }
+  if (first > 0) {
+    str->erase(0, first);
+    str_length -= first;
+  }
+
+  // Strip off trailing whitespace.
+  int last = str_length - 1;
+  while (last >= 0 && ascii_isspace(str->at(last))) {
+    --last;
+  }
+  if (last != (str_length - 1) && last >= 0) {
+    str->erase(last + 1, string::npos);
+  }
+}
+
 // ----------------------------------------------------------------------
 // StringReplace()
 //    Replace the "old" pattern with the "new" pattern in a string,
@@ -281,17 +308,6 @@
 
 #define IS_OCTAL_DIGIT(c) (((c) >= '0') && ((c) <= '7'))
 
-inline int hex_digit_to_int(char c) {
-  /* Assume ASCII. */
-  assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61);
-  assert(isxdigit(c));
-  int x = static_cast<unsigned char>(c);
-  if (x > '9') {
-    x += 9;
-  }
-  return x & 0xf;
-}
-
 // Protocol buffers doesn't ever care about errors, but I don't want to remove
 // the code.
 #define LOG_STRING(LEVEL, VECTOR) GOOGLE_LOG_IF(LEVEL, false)
@@ -508,27 +524,81 @@
   return used;
 }
 
-int CEscapeString(const char* src, int src_len, char* dest, int dest_len) {
-  return CEscapeInternal(src, src_len, dest, dest_len, false, false);
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+static inline size_t CEscapedLength(StringPiece src) {
+  static char c_escaped_len[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  };
+
+  size_t escaped_len = 0;
+  for (int i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    escaped_len += c_escaped_len[c];
+  }
+  return escaped_len;
 }
 
 // ----------------------------------------------------------------------
-// CEscape()
-// CHexEscape()
-//    Copies 'src' to result, escaping dangerous characters using
-//    C-style escape sequences. This is very useful for preparing query
-//    flags. 'src' and 'dest' should not overlap. The 'Hex' version
-//    hexadecimal rather than octal sequences.
-//
-//    Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// Escapes 'src' using C-style escape sequences, and appends the escaped string
+// to 'dest'. This version is faster than calling CEscapeInternal as it computes
+// the required space using a lookup table, and also does not do any special
+// handling for Hex or UTF-8 characters.
 // ----------------------------------------------------------------------
+void CEscapeAndAppend(StringPiece src, string* dest) {
+  size_t escaped_len = CEscapedLength(src);
+  if (escaped_len == src.size()) {
+    dest->append(src.data(), src.size());
+    return;
+  }
+
+  size_t cur_dest_len = dest->size();
+  dest->resize(cur_dest_len + escaped_len);
+  char* append_ptr = &(*dest)[cur_dest_len];
+
+  for (int i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    switch (c) {
+      case '\n': *append_ptr++ = '\\'; *append_ptr++ = 'n'; break;
+      case '\r': *append_ptr++ = '\\'; *append_ptr++ = 'r'; break;
+      case '\t': *append_ptr++ = '\\'; *append_ptr++ = 't'; break;
+      case '\"': *append_ptr++ = '\\'; *append_ptr++ = '\"'; break;
+      case '\'': *append_ptr++ = '\\'; *append_ptr++ = '\''; break;
+      case '\\': *append_ptr++ = '\\'; *append_ptr++ = '\\'; break;
+      default:
+        if (!isprint(c)) {
+          *append_ptr++ = '\\';
+          *append_ptr++ = '0' + c / 64;
+          *append_ptr++ = '0' + (c % 64) / 8;
+          *append_ptr++ = '0' + c % 8;
+        } else {
+          *append_ptr++ = c;
+        }
+        break;
+    }
+  }
+}
+
 string CEscape(const string& src) {
-  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
-  scoped_array<char> dest(new char[dest_length]);
-  const int len = CEscapeInternal(src.data(), src.size(),
-                                  dest.get(), dest_length, false, false);
-  GOOGLE_DCHECK_GE(len, 0);
-  return string(dest.get(), len);
+  string dest;
+  CEscapeAndAppend(src, &dest);
+  return dest;
 }
 
 namespace strings {
@@ -624,14 +694,15 @@
   return true;
 }
 
-inline bool safe_parse_positive_int(
-    string text, int32* value_p) {
+template<typename IntType>
+bool safe_parse_positive_int(
+    string text, IntType* value_p) {
   int base = 10;
-  int32 value = 0;
-  const int32 vmax = std::numeric_limits<int32>::max();
+  IntType value = 0;
+  const IntType vmax = std::numeric_limits<IntType>::max();
   assert(vmax > 0);
   assert(vmax >= base);
-  const int32 vmax_over_base = vmax / base;
+  const IntType vmax_over_base = vmax / base;
   const char* start = text.data();
   const char* end = start + text.size();
   // loop over digits
@@ -657,14 +728,15 @@
   return true;
 }
 
-inline bool safe_parse_negative_int(
-    string text, int32* value_p) {
+template<typename IntType>
+bool safe_parse_negative_int(
+    const string& text, IntType* value_p) {
   int base = 10;
-  int32 value = 0;
-  const int32 vmin = std::numeric_limits<int32>::min();
+  IntType value = 0;
+  const IntType vmin = std::numeric_limits<IntType>::min();
   assert(vmin < 0);
   assert(vmin <= 0 - base);
-  int32 vmin_over_base = vmin / base;
+  IntType vmin_over_base = vmin / base;
   // 2003 c++ standard [expr.mul]
   // "... the sign of the remainder is implementation-defined."
   // Although (vmin/base)*base + vmin%base is always vmin.
@@ -697,7 +769,8 @@
   return true;
 }
 
-bool safe_int(string text, int32* value_p) {
+template<typename IntType>
+bool safe_int_internal(string text, IntType* value_p) {
   *value_p = 0;
   bool negative;
   if (!safe_parse_sign(&text, &negative)) {
@@ -710,6 +783,16 @@
   }
 }
 
+template<typename IntType>
+bool safe_uint_internal(string text, IntType* value_p) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign(&text, &negative) || negative) {
+    return false;
+  }
+  return safe_parse_positive_int(text, value_p);
+}
+
 // ----------------------------------------------------------------------
 // FastIntToBuffer()
 // FastInt64ToBuffer()
@@ -843,13 +926,6 @@
   return InternalFastHexToBuffer(value, buffer, 8);
 }
 
-static inline char* PlaceNum(char* p, int num, char prev_sep) {
-   *p-- = '0' + num % 10;
-   *p-- = '0' + num / 10;
-   *p-- = prev_sep;
-   return p;
-}
-
 // ----------------------------------------------------------------------
 // FastInt32ToBufferLeft()
 // FastUInt32ToBufferLeft()
@@ -1177,7 +1253,7 @@
   } else if (value == -numeric_limits<double>::infinity()) {
     strcpy(buffer, "-inf");
     return buffer;
-  } else if (IsNaN(value)) {
+  } else if (MathLimits<double>::IsNaN(value)) {
     strcpy(buffer, "nan");
     return buffer;
   }
@@ -1208,6 +1284,41 @@
   return buffer;
 }
 
+static int memcasecmp(const char *s1, const char *s2, size_t len) {
+  const unsigned char *us1 = reinterpret_cast<const unsigned char *>(s1);
+  const unsigned char *us2 = reinterpret_cast<const unsigned char *>(s2);
+
+  for ( int i = 0; i < len; i++ ) {
+    const int diff =
+      static_cast<int>(static_cast<unsigned char>(ascii_tolower(us1[i]))) -
+      static_cast<int>(static_cast<unsigned char>(ascii_tolower(us2[i])));
+    if (diff != 0) return diff;
+  }
+  return 0;
+}
+
+inline bool CaseEqual(StringPiece s1, StringPiece s2) {
+  if (s1.size() != s2.size()) return false;
+  return memcasecmp(s1.data(), s2.data(), s1.size()) == 0;
+}
+
+bool safe_strtob(StringPiece str, bool* value) {
+  GOOGLE_CHECK(value != NULL) << "NULL output boolean given.";
+  if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
+      CaseEqual(str, "yes") || CaseEqual(str, "y") ||
+      CaseEqual(str, "1")) {
+    *value = true;
+    return true;
+  }
+  if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
+      CaseEqual(str, "no") || CaseEqual(str, "n") ||
+      CaseEqual(str, "0")) {
+    *value = false;
+    return true;
+  }
+  return false;
+}
+
 bool safe_strtof(const char* str, float* value) {
   char* endptr;
   errno = 0;  // errno only gets set on errors
@@ -1219,6 +1330,34 @@
   return *str != 0 && *endptr == 0 && errno == 0;
 }
 
+bool safe_strtod(const char* str, double* value) {
+  char* endptr;
+  *value = strtod(str, &endptr);
+  if (endptr != str) {
+    while (ascii_isspace(*endptr)) ++endptr;
+  }
+  // Ignore range errors from strtod.  The values it
+  // returns on underflow and overflow are the right
+  // fallback in a robust setting.
+  return *str != '\0' && *endptr == '\0';
+}
+
+bool safe_strto32(const string& str, int32* value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou32(const string& str, uint32* value) {
+  return safe_uint_internal(str, value);
+}
+
+bool safe_strto64(const string& str, int64* value) {
+  return safe_int_internal(str, value);
+}
+
+bool safe_strtou64(const string& str, uint64* value) {
+  return safe_uint_internal(str, value);
+}
+
 char* FloatToBuffer(float value, char* buffer) {
   // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all
   // platforms these days.  Just in case some system exists where FLT_DIG
@@ -1232,7 +1371,7 @@
   } else if (value == -numeric_limits<double>::infinity()) {
     strcpy(buffer, "-inf");
     return buffer;
-  } else if (IsNaN(value)) {
+  } else if (MathLimits<float>::IsNaN(value)) {
     strcpy(buffer, "nan");
     return buffer;
   }
@@ -1257,22 +1396,893 @@
   return buffer;
 }
 
-string ToHex(uint64 num) {
-  if (num == 0) {
-    return string("0");
+namespace strings {
+
+AlphaNum::AlphaNum(strings::Hex hex) {
+  char *const end = &digits[kFastToBufferSize];
+  char *writer = end;
+  uint64 value = hex.value;
+  uint64 width = hex.spec;
+  // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
+  // where 0x10000 is the smallest hex number that is as wide as the user
+  // asked for.
+  uint64 mask = ((static_cast<uint64>(1) << (width - 1) * 4)) | value;
+  static const char hexdigits[] = "0123456789abcdef";
+  do {
+    *--writer = hexdigits[value & 0xF];
+    value >>= 4;
+    mask >>= 4;
+  } while (mask != 0);
+  piece_data_ = writer;
+  piece_size_ = end - writer;
+}
+
+}  // namespace strings
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or integers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, C++ strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.  It comes in multiple flavors to minimize
+// call overhead.
+static char *Append1(char *out, const AlphaNum &x) {
+  memcpy(out, x.data(), x.size());
+  return out + x.size();
+}
+
+static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
+  memcpy(out, x1.data(), x1.size());
+  out += x1.size();
+
+  memcpy(out, x2.data(), x2.size());
+  return out + x2.size();
+}
+
+static char *Append4(char *out,
+                     const AlphaNum &x1, const AlphaNum &x2,
+                     const AlphaNum &x3, const AlphaNum &x4) {
+  memcpy(out, x1.data(), x1.size());
+  out += x1.size();
+
+  memcpy(out, x2.data(), x2.size());
+  out += x2.size();
+
+  memcpy(out, x3.data(), x3.size());
+  out += x3.size();
+
+  memcpy(out, x4.data(), x4.size());
+  return out + x4.size();
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b) {
+  string result;
+  result.resize(a.size() + b.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+  string result;
+  result.resize(a.size() + b.size() + c.size());
+  char *const begin = &*result.begin();
+  char *out = Append2(begin, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d, const AlphaNum &e) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append1(out, e);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+              const AlphaNum &g) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append2(out, e, f);
+  out = Append1(out, g);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+              const AlphaNum &g, const AlphaNum &h) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
+              const AlphaNum &d, const AlphaNum &e, const AlphaNum &f,
+              const AlphaNum &g, const AlphaNum &h, const AlphaNum &i) {
+  string result;
+  result.resize(a.size() + b.size() + c.size() + d.size() + e.size() +
+                f.size() + g.size() + h.size() + i.size());
+  char *const begin = &*result.begin();
+  char *out = Append4(begin, a, b, c, d);
+  out = Append4(out, e, f, g, h);
+  out = Append1(out, i);
+  GOOGLE_DCHECK_EQ(out, begin + result.size());
+  return result;
+}
+
+// It's possible to call StrAppend with a char * pointer that is partway into
+// the string we're appending to.  However the results of this are random.
+// Therefore, check for this in debug mode.  Use unsigned math so we only have
+// to do one comparison.
+#define GOOGLE_DCHECK_NO_OVERLAP(dest, src) \
+    GOOGLE_DCHECK_GT(uintptr_t((src).data() - (dest).data()), \
+                     uintptr_t((dest).size()))
+
+void StrAppend(string *result, const AlphaNum &a) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  result->append(a.data(), a.size());
+}
+
+void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(string *result,
+               const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size());
+  char *const begin = &*result->begin();
+  char *out = Append2(begin + old_size, a, b);
+  out = Append1(out, c);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+void StrAppend(string *result,
+               const AlphaNum &a, const AlphaNum &b,
+               const AlphaNum &c, const AlphaNum &d) {
+  GOOGLE_DCHECK_NO_OVERLAP(*result, a);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, b);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, c);
+  GOOGLE_DCHECK_NO_OVERLAP(*result, d);
+  string::size_type old_size = result->size();
+  result->resize(old_size + a.size() + b.size() + c.size() + d.size());
+  char *const begin = &*result->begin();
+  char *out = Append4(begin + old_size, a, b, c, d);
+  GOOGLE_DCHECK_EQ(out, begin + result->size());
+}
+
+int GlobalReplaceSubstring(const string& substring,
+                           const string& replacement,
+                           string* s) {
+  GOOGLE_CHECK(s != NULL);
+  if (s->empty() || substring.empty())
+    return 0;
+  string tmp;
+  int num_replacements = 0;
+  int pos = 0;
+  for (int match_pos = s->find(substring.data(), pos, substring.length());
+       match_pos != string::npos;
+       pos = match_pos + substring.length(),
+           match_pos = s->find(substring.data(), pos, substring.length())) {
+    ++num_replacements;
+    // Append the original content before the match.
+    tmp.append(*s, pos, match_pos - pos);
+    // Append the replacement for the match.
+    tmp.append(replacement.begin(), replacement.end());
+  }
+  // Append the content after the last match. If no replacements were made, the
+  // original string is left untouched.
+  if (num_replacements > 0) {
+    tmp.append(*s, pos, s->length() - pos);
+    s->swap(tmp);
+  }
+  return num_replacements;
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+  // Base64 encodes three bytes of input at a time. If the input is not
+  // divisible by three, we pad as appropriate.
+  //
+  // (from http://tools.ietf.org/html/rfc3548)
+  // Special processing is performed if fewer than 24 bits are available
+  // at the end of the data being encoded.  A full encoding quantum is
+  // always completed at the end of a quantity.  When fewer than 24 input
+  // bits are available in an input group, zero bits are added (on the
+  // right) to form an integral number of 6-bit groups.  Padding at the
+  // end of the data is performed using the '=' character.  Since all base
+  // 64 input is an integral number of octets, only the following cases
+  // can arise:
+
+
+  // Base64 encodes each three bytes of input into four bytes of output.
+  int len = (input_len / 3) * 4;
+
+  if (input_len % 3 == 0) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (1) the final quantum of encoding input is an integral multiple of 24
+    // bits; here, the final unit of encoded output will be an integral
+    // multiple of 4 characters with no "=" padding,
+  } else if (input_len % 3 == 1) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (2) the final quantum of encoding input is exactly 8 bits; here, the
+    // final unit of encoded output will be two characters followed by two
+    // "=" padding characters, or
+    len += 2;
+    if (do_padding) {
+      len += 2;
+    }
+  } else {  // (input_len % 3 == 2)
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (3) the final quantum of encoding input is exactly 16 bits; here, the
+    // final unit of encoded output will be three characters followed by one
+    // "=" padding character.
+    len += 3;
+    if (do_padding) {
+      len += 1;
+    }
   }
 
-  // Compute hex bytes in reverse order, writing to the back of the
-  // buffer.
-  char buf[16];  // No more than 16 hex digits needed.
-  char* bufptr = buf + 16;
-  static const char kHexChars[] = "0123456789abcdef";
-  while (num != 0) {
-    *--bufptr = kHexChars[num & 0xf];
-    num >>= 4;
+  assert(len >= input_len);  // make sure we didn't overflow
+  return len;
+}
+
+// Base64Escape does padding, so this calculation includes padding.
+int CalculateBase64EscapedLen(int input_len) {
+  return CalculateBase64EscapedLen(input_len, true);
+}
+
+// ----------------------------------------------------------------------
+// int Base64Unescape() - base64 decoder
+// int Base64Escape() - base64 encoder
+// int WebSafeBase64Unescape() - Google's variation of base64 decoder
+// int WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://tools.ietf.org/html/rfc2045 for formal description, but what we
+// care about is that...
+//   Take the encoded stuff in groups of 4 characters and turn each
+//   character into a code 0 to 63 thus:
+//           A-Z map to 0 to 25
+//           a-z map to 26 to 51
+//           0-9 map to 52 to 61
+//           +(- for WebSafe) maps to 62
+//           /(_ for WebSafe) maps to 63
+//   There will be four numbers, all less than 64 which can be represented
+//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+//   Arrange the 6 digit binary numbers into three bytes as such:
+//   aaaaaabb bbbbcccc ccdddddd
+//   Equals signs (one or two) are used at the end of the encoded block to
+//   indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+int Base64UnescapeInternal(const char *src_param, int szsrc,
+                           char *dest, int szdest,
+                           const signed char* unbase64) {
+  static const char kPad64Equals = '=';
+  static const char kPad64Dot = '.';
+
+  int decode = 0;
+  int destidx = 0;
+  int state = 0;
+  unsigned int ch = 0;
+  unsigned int temp = 0;
+
+  // If "char" is signed by default, using *src as an array index results in
+  // accessing negative array elements. Treat the input as a pointer to
+  // unsigned char to avoid this.
+  const unsigned char *src = reinterpret_cast<const unsigned char*>(src_param);
+
+  // The GET_INPUT macro gets the next input character, skipping
+  // over any whitespace, and stopping when we reach the end of the
+  // string or when we read any non-data character.  The arguments are
+  // an arbitrary identifier (used as a label for goto) and the number
+  // of data bytes that must remain in the input to avoid aborting the
+  // loop.
+#define GET_INPUT(label, remain)                 \
+  label:                                         \
+    --szsrc;                                     \
+    ch = *src++;                                 \
+    decode = unbase64[ch];                       \
+    if (decode < 0) {                            \
+      if (ascii_isspace(ch) && szsrc >= remain)  \
+        goto label;                              \
+      state = 4 - remain;                        \
+      break;                                     \
+    }
+
+  // if dest is null, we're just checking to see if it's legal input
+  // rather than producing output.  (I suspect this could just be done
+  // with a regexp...).  We duplicate the loop so this test can be
+  // outside it instead of in every iteration.
+
+  if (dest) {
+    // This loop consumes 4 input bytes and produces 3 output bytes
+    // per iteration.  We can't know at the start that there is enough
+    // data left in the string for a full iteration, so the loop may
+    // break out in the middle; if so 'state' will be set to the
+    // number of input bytes read.
+
+    while (szsrc >= 4)  {
+      // We'll start by optimistically assuming that the next four
+      // bytes of the string (src[0..3]) are four good data bytes
+      // (that is, no nulls, whitespace, padding chars, or illegal
+      // chars).  We need to test src[0..2] for nulls individually
+      // before constructing temp to preserve the property that we
+      // never read past a null in the string (no matter how long
+      // szsrc claims the string is).
+
+      if (!src[0] || !src[1] || !src[2] ||
+          (temp = ((unsigned(unbase64[src[0]]) << 18) |
+                   (unsigned(unbase64[src[1]]) << 12) |
+                   (unsigned(unbase64[src[2]]) << 6) |
+                   (unsigned(unbase64[src[3]])))) & 0x80000000) {
+        // Iff any of those four characters was bad (null, illegal,
+        // whitespace, padding), then temp's high bit will be set
+        // (because unbase64[] is -1 for all bad characters).
+        //
+        // We'll back up and resort to the slower decoder, which knows
+        // how to handle those cases.
+
+        GET_INPUT(first, 4);
+        temp = decode;
+        GET_INPUT(second, 3);
+        temp = (temp << 6) | decode;
+        GET_INPUT(third, 2);
+        temp = (temp << 6) | decode;
+        GET_INPUT(fourth, 1);
+        temp = (temp << 6) | decode;
+      } else {
+        // We really did have four good data bytes, so advance four
+        // characters in the string.
+
+        szsrc -= 4;
+        src += 4;
+        decode = -1;
+        ch = '\0';
+      }
+
+      // temp has 24 bits of input, so write that out as three bytes.
+
+      if (destidx+3 > szdest) return -1;
+      dest[destidx+2] = temp;
+      temp >>= 8;
+      dest[destidx+1] = temp;
+      temp >>= 8;
+      dest[destidx] = temp;
+      destidx += 3;
+    }
+  } else {
+    while (szsrc >= 4)  {
+      if (!src[0] || !src[1] || !src[2] ||
+          (temp = ((unsigned(unbase64[src[0]]) << 18) |
+                   (unsigned(unbase64[src[1]]) << 12) |
+                   (unsigned(unbase64[src[2]]) << 6) |
+                   (unsigned(unbase64[src[3]])))) & 0x80000000) {
+        GET_INPUT(first_no_dest, 4);
+        GET_INPUT(second_no_dest, 3);
+        GET_INPUT(third_no_dest, 2);
+        GET_INPUT(fourth_no_dest, 1);
+      } else {
+        szsrc -= 4;
+        src += 4;
+        decode = -1;
+        ch = '\0';
+      }
+      destidx += 3;
+    }
   }
 
-  return string(bufptr, buf + 16 - bufptr);
+#undef GET_INPUT
+
+  // if the loop terminated because we read a bad character, return
+  // now.
+  if (decode < 0 && ch != '\0' &&
+      ch != kPad64Equals && ch != kPad64Dot && !ascii_isspace(ch))
+    return -1;
+
+  if (ch == kPad64Equals || ch == kPad64Dot) {
+    // if we stopped by hitting an '=' or '.', un-read that character -- we'll
+    // look at it again when we count to check for the proper number of
+    // equals signs at the end.
+    ++szsrc;
+    --src;
+  } else {
+    // This loop consumes 1 input byte per iteration.  It's used to
+    // clean up the 0-3 input bytes remaining when the first, faster
+    // loop finishes.  'temp' contains the data from 'state' input
+    // characters read by the first loop.
+    while (szsrc > 0)  {
+      --szsrc;
+      ch = *src++;
+      decode = unbase64[ch];
+      if (decode < 0) {
+        if (ascii_isspace(ch)) {
+          continue;
+        } else if (ch == '\0') {
+          break;
+        } else if (ch == kPad64Equals || ch == kPad64Dot) {
+          // back up one character; we'll read it again when we check
+          // for the correct number of pad characters at the end.
+          ++szsrc;
+          --src;
+          break;
+        } else {
+          return -1;
+        }
+      }
+
+      // Each input character gives us six bits of output.
+      temp = (temp << 6) | decode;
+      ++state;
+      if (state == 4) {
+        // If we've accumulated 24 bits of output, write that out as
+        // three bytes.
+        if (dest) {
+          if (destidx+3 > szdest) return -1;
+          dest[destidx+2] = temp;
+          temp >>= 8;
+          dest[destidx+1] = temp;
+          temp >>= 8;
+          dest[destidx] = temp;
+        }
+        destidx += 3;
+        state = 0;
+        temp = 0;
+      }
+    }
+  }
+
+  // Process the leftover data contained in 'temp' at the end of the input.
+  int expected_equals = 0;
+  switch (state) {
+    case 0:
+      // Nothing left over; output is a multiple of 3 bytes.
+      break;
+
+    case 1:
+      // Bad input; we have 6 bits left over.
+      return -1;
+
+    case 2:
+      // Produce one more output byte from the 12 input bits we have left.
+      if (dest) {
+        if (destidx+1 > szdest) return -1;
+        temp >>= 4;
+        dest[destidx] = temp;
+      }
+      ++destidx;
+      expected_equals = 2;
+      break;
+
+    case 3:
+      // Produce two more output bytes from the 18 input bits we have left.
+      if (dest) {
+        if (destidx+2 > szdest) return -1;
+        temp >>= 2;
+        dest[destidx+1] = temp;
+        temp >>= 8;
+        dest[destidx] = temp;
+      }
+      destidx += 2;
+      expected_equals = 1;
+      break;
+
+    default:
+      // state should have no other values at this point.
+      GOOGLE_LOG(FATAL) << "This can't happen; base64 decoder state = " << state;
+  }
+
+  // The remainder of the string should be all whitespace, mixed with
+  // exactly 0 equals signs, or exactly 'expected_equals' equals
+  // signs.  (Always accepting 0 equals signs is a google extension
+  // not covered in the RFC, as is accepting dot as the pad character.)
+
+  int equals = 0;
+  while (szsrc > 0 && *src) {
+    if (*src == kPad64Equals || *src == kPad64Dot)
+      ++equals;
+    else if (!ascii_isspace(*src))
+      return -1;
+    --szsrc;
+    ++src;
+  }
+
+  return (equals == 0 || equals == expected_equals) ? destidx : -1;
+}
+
+// The arrays below were generated by the following code
+// #include <sys/time.h>
+// #include <stdlib.h>
+// #include <string.h>
+// main()
+// {
+//   static const char Base64[] =
+//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+//   char *pos;
+//   int idx, i, j;
+//   printf("    ");
+//   for (i = 0; i < 255; i += 8) {
+//     for (j = i; j < i + 8; j++) {
+//       pos = strchr(Base64, j);
+//       if ((pos == NULL) || (j == 0))
+//         idx = -1;
+//       else
+//         idx = pos - Base64;
+//       if (idx == -1)
+//         printf(" %2d,     ", idx);
+//       else
+//         printf(" %2d/*%c*/,", idx, j);
+//     }
+//     printf("\n    ");
+//   }
+// }
+//
+// where the value of "Base64[]" was replaced by one of the base-64 conversion
+// tables from the functions below.
+static const signed char kUnBase64[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+  07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+static const signed char kUnWebSafeBase64[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      62/*-*/, -1,      -1,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+  07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      63/*_*/,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+  return Base64UnescapeInternal(src, szsrc, dest, szdest, kUnWebSafeBase64);
+}
+
+static bool Base64UnescapeInternal(const char* src, int slen, string* dest,
+                                   const signed char* unbase64) {
+  // Determine the size of the output string.  Base64 encodes every 3 bytes into
+  // 4 characters.  any leftover chars are added directly for good measure.
+  // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
+  const int dest_len = 3 * (slen / 4) + (slen % 4);
+
+  dest->resize(dest_len);
+
+  // We are getting the destination buffer by getting the beginning of the
+  // string and converting it into a char *.
+  const int len = Base64UnescapeInternal(src, slen, string_as_array(dest),
+                                         dest_len, unbase64);
+  if (len < 0) {
+    dest->clear();
+    return false;
+  }
+
+  // could be shorter if there was padding
+  GOOGLE_DCHECK_LE(len, dest_len);
+  dest->erase(len);
+
+  return true;
+}
+
+bool Base64Unescape(StringPiece src, string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(StringPiece src, string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
+}
+
+int Base64EscapeInternal(const unsigned char *src, int szsrc,
+                         char *dest, int szdest, const char *base64,
+                         bool do_padding) {
+  static const char kPad64 = '=';
+
+  if (szsrc <= 0) return 0;
+
+  if (szsrc * 4 > szdest * 3) return 0;
+
+  char *cur_dest = dest;
+  const unsigned char *cur_src = src;
+
+  char *limit_dest = dest + szdest;
+  const unsigned char *limit_src = src + szsrc;
+
+  // Three bytes of data encodes to four characters of cyphertext.
+  // So we can pump through three-byte chunks atomically.
+  while (cur_src < limit_src - 3) {  // keep going as long as we have >= 32 bits
+    uint32 in = BigEndian::Load32(cur_src) >> 8;
+
+    cur_dest[0] = base64[in >> 18];
+    in &= 0x3FFFF;
+    cur_dest[1] = base64[in >> 12];
+    in &= 0xFFF;
+    cur_dest[2] = base64[in >> 6];
+    in &= 0x3F;
+    cur_dest[3] = base64[in];
+
+    cur_dest += 4;
+    cur_src += 3;
+  }
+  // To save time, we didn't update szdest or szsrc in the loop.  So do it now.
+  szdest = limit_dest - cur_dest;
+  szsrc = limit_src - cur_src;
+
+  /* now deal with the tail (<=3 bytes) */
+  switch (szsrc) {
+    case 0:
+      // Nothing left; nothing more to do.
+      break;
+    case 1: {
+      // One byte left: this encodes to two characters, and (optionally)
+      // two pad characters to round out the four-character cypherblock.
+      if ((szdest -= 2) < 0) return 0;
+      uint32 in = cur_src[0];
+      cur_dest[0] = base64[in >> 2];
+      in &= 0x3;
+      cur_dest[1] = base64[in << 4];
+      cur_dest += 2;
+      if (do_padding) {
+        if ((szdest -= 2) < 0) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest[1] = kPad64;
+        cur_dest += 2;
+      }
+      break;
+    }
+    case 2: {
+      // Two bytes left: this encodes to three characters, and (optionally)
+      // one pad character to round out the four-character cypherblock.
+      if ((szdest -= 3) < 0) return 0;
+      uint32 in = BigEndian::Load16(cur_src);
+      cur_dest[0] = base64[in >> 10];
+      in &= 0x3FF;
+      cur_dest[1] = base64[in >> 4];
+      in &= 0x00F;
+      cur_dest[2] = base64[in << 2];
+      cur_dest += 3;
+      if (do_padding) {
+        if ((szdest -= 1) < 0) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest += 1;
+      }
+      break;
+    }
+    case 3: {
+      // Three bytes left: same as in the big loop above.  We can't do this in
+      // the loop because the loop above always reads 4 bytes, and the fourth
+      // byte is past the end of the input.
+      if ((szdest -= 4) < 0) return 0;
+      uint32 in = (cur_src[0] << 16) + BigEndian::Load16(cur_src + 1);
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+      cur_dest += 4;
+      break;
+    }
+    default:
+      // Should not be reached: blocks of 4 bytes are handled
+      // in the while loop before this switch statement.
+      GOOGLE_LOG(FATAL) << "Logic problem? szsrc = " << szsrc;
+      break;
+  }
+  return (cur_dest - dest);
+}
+
+static const char kBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const char kWebSafeBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
+  return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
+}
+int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
+                        int szdest, bool do_padding) {
+  return Base64EscapeInternal(src, szsrc, dest, szdest,
+                              kWebSafeBase64Chars, do_padding);
+}
+
+void Base64EscapeInternal(const unsigned char* src, int szsrc,
+                          string* dest, bool do_padding,
+                          const char* base64_chars) {
+  const int calc_escaped_size =
+    CalculateBase64EscapedLen(szsrc, do_padding);
+  dest->resize(calc_escaped_size);
+  const int escaped_len = Base64EscapeInternal(src, szsrc,
+                                               string_as_array(dest),
+                                               dest->size(),
+                                               base64_chars,
+                                               do_padding);
+  GOOGLE_DCHECK_EQ(calc_escaped_size, escaped_len);
+  dest->erase(escaped_len);
+}
+
+void Base64Escape(const unsigned char *src, int szsrc,
+                  string* dest, bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kBase64Chars);
+}
+
+void WebSafeBase64Escape(const unsigned char *src, int szsrc,
+                         string *dest, bool do_padding) {
+  Base64EscapeInternal(src, szsrc, dest, do_padding, kWebSafeBase64Chars);
+}
+
+void Base64Escape(StringPiece src, string* dest) {
+  Base64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+               src.size(), dest, true);
+}
+
+void WebSafeBase64Escape(StringPiece src, string* dest) {
+  WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+                      src.size(), dest, false);
+}
+
+void WebSafeBase64EscapeWithPadding(StringPiece src, string* dest) {
+  WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.data()),
+                      src.size(), dest, true);
+}
+
+// Helper to append a Unicode code point to a string as UTF8, without bringing
+// in any external dependencies.
+int EncodeAsUTF8Char(uint32 code_point, char* output) {
+  uint32 tmp = 0;
+  int len = 0;
+  if (code_point <= 0x7f) {
+    tmp = code_point;
+    len = 1;
+  } else if (code_point <= 0x07ff) {
+    tmp = 0x0000c080 |
+        ((code_point & 0x07c0) << 2) |
+        (code_point & 0x003f);
+    len = 2;
+  } else if (code_point <= 0xffff) {
+    tmp = 0x00e08080 |
+        ((code_point & 0xf000) << 4) |
+        ((code_point & 0x0fc0) << 2) |
+        (code_point & 0x003f);
+    len = 3;
+  } else {
+    // UTF-16 is only defined for code points up to 0x10FFFF, and UTF-8 is
+    // normally only defined up to there as well.
+    tmp = 0xf0808080 |
+        ((code_point & 0x1c0000) << 6) |
+        ((code_point & 0x03f000) << 4) |
+        ((code_point & 0x000fc0) << 2) |
+        (code_point & 0x003f);
+    len = 4;
+  }
+  tmp = ghtonl(tmp);
+  memcpy(output, reinterpret_cast<const char*>(&tmp) + sizeof(tmp) - len, len);
+  return len;
+}
+
+// Table of UTF-8 character lengths, based on first byte
+static const unsigned char kUTF8LenTbl[256] = {
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4
+};
+
+// Return length of a single UTF-8 source character
+int UTF8FirstLetterNumBytes(const char* src, int len) {
+  if (len == 0) {
+    return 0;
+  }
+  return kUTF8LenTbl[*reinterpret_cast<const uint8*>(src)];
 }
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index 4178ac9..8bdd611 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
 
 namespace google {
 namespace protobuf {
@@ -57,6 +58,8 @@
 //    strings, so locale should not be taken into account.
 // ascii_isdigit()
 //    Like above, but only accepts digits.
+// ascii_isspace()
+//    Check if the character is a space character.
 // ----------------------------------------------------------------------
 
 inline bool ascii_isalnum(char c) {
@@ -69,6 +72,36 @@
   return ('0' <= c && c <= '9');
 }
 
+inline bool ascii_isspace(char c) {
+  return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
+      c == '\r';
+}
+
+inline bool ascii_isupper(char c) {
+  return c >= 'A' && c <= 'Z';
+}
+
+inline bool ascii_islower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+inline char ascii_toupper(char c) {
+  return ascii_islower(c) ? c - ('a' - 'A') : c;
+}
+
+inline char ascii_tolower(char c) {
+  return ascii_isupper(c) ? c + ('a' - 'A') : c;
+}
+
+inline int hex_digit_to_int(char c) {
+  /* Assume ASCII. */
+  int x = static_cast<unsigned char>(c);
+  if (x > '9') {
+    x += 9;
+  }
+  return x & 0xf;
+}
+
 // ----------------------------------------------------------------------
 // HasPrefixString()
 //    Check if a string begins with a given prefix.
@@ -119,10 +152,15 @@
 //    in 'remove') with the character 'replacewith'.
 //    Good for keeping html characters or protocol characters (\t) out
 //    of places where they might cause a problem.
+// StripWhitespace
+//    Removes whitespaces from both ends of the given string.
 // ----------------------------------------------------------------------
 LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove,
                                     char replacewith);
 
+LIBPROTOBUF_EXPORT void StripWhitespace(string* s);
+
+
 // ----------------------------------------------------------------------
 // LowerString()
 // UpperString()
@@ -276,27 +314,21 @@
 LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
 
 // ----------------------------------------------------------------------
-// CEscapeString()
-//    Copies 'src' to 'dest', escaping dangerous characters using
-//    C-style escape sequences. This is very useful for preparing query
-//    flags. 'src' and 'dest' should not overlap.
-//    Returns the number of bytes written to 'dest' (not including the \0)
-//    or -1 if there was insufficient space.
-//
-//    Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
-// ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len,
-                                     char* dest, int dest_len);
-
-// ----------------------------------------------------------------------
 // CEscape()
-//    More convenient form of CEscapeString: returns result as a "string".
-//    This version is slower than CEscapeString() because it does more
-//    allocation.  However, it is much more convenient to use in
-//    non-speed-critical code like logging messages etc.
+//    Escapes 'src' using C-style escape sequences and returns the resulting
+//    string.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !isprint().
 // ----------------------------------------------------------------------
 LIBPROTOBUF_EXPORT string CEscape(const string& src);
 
+// ----------------------------------------------------------------------
+// CEscapeAndAppend()
+//    Escapes 'src' using C-style escape sequences, and appends the escaped
+//    string to 'dest'.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, string* dest);
+
 namespace strings {
 // Like CEscape() but does not escape bytes with the upper bit set.
 LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src);
@@ -349,12 +381,59 @@
 }
 
 // ----------------------------------------------------------------------
+// safe_strtob()
 // safe_strto32()
+// safe_strtou32()
+// safe_strto64()
+// safe_strtou64()
+// safe_strtof()
+// safe_strtod()
 // ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT bool safe_int(string text, int32* value_p);
+LIBPROTOBUF_EXPORT bool safe_strtob(StringPiece str, bool* value);
 
-inline bool safe_strto32(string text, int32* value) {
-  return safe_int(text, value);
+LIBPROTOBUF_EXPORT bool safe_strto32(const string& str, int32* value);
+LIBPROTOBUF_EXPORT bool safe_strtou32(const string& str, uint32* value);
+inline bool safe_strto32(const char* str, int32* value) {
+  return safe_strto32(string(str), value);
+}
+inline bool safe_strto32(StringPiece str, int32* value) {
+  return safe_strto32(str.ToString(), value);
+}
+inline bool safe_strtou32(const char* str, uint32* value) {
+  return safe_strtou32(string(str), value);
+}
+inline bool safe_strtou32(StringPiece str, uint32* value) {
+  return safe_strtou32(str.ToString(), value);
+}
+
+LIBPROTOBUF_EXPORT bool safe_strto64(const string& str, int64* value);
+LIBPROTOBUF_EXPORT bool safe_strtou64(const string& str, uint64* value);
+inline bool safe_strto64(const char* str, int64* value) {
+  return safe_strto64(string(str), value);
+}
+inline bool safe_strto64(StringPiece str, int64* value) {
+  return safe_strto64(str.ToString(), value);
+}
+inline bool safe_strtou64(const char* str, uint64* value) {
+  return safe_strtou64(string(str), value);
+}
+inline bool safe_strtou64(StringPiece str, uint64* value) {
+  return safe_strtou64(str.ToString(), value);
+}
+
+LIBPROTOBUF_EXPORT bool safe_strtof(const char* str, float* value);
+LIBPROTOBUF_EXPORT bool safe_strtod(const char* str, double* value);
+inline bool safe_strtof(const string& str, float* value) {
+  return safe_strtof(str.c_str(), value);
+}
+inline bool safe_strtod(const string& str, double* value) {
+  return safe_strtod(str.c_str(), value);
+}
+inline bool safe_strtof(StringPiece str, float* value) {
+  return safe_strtof(str.ToString(), value);
+}
+inline bool safe_strtod(StringPiece str, double* value) {
+  return safe_strtod(str.ToString(), value);
 }
 
 // ----------------------------------------------------------------------
@@ -440,6 +519,10 @@
   return buffer;
 }
 
+inline string SimpleBtoa(bool value) {
+  return value ? "true" : "false";
+}
+
 // ----------------------------------------------------------------------
 // SimpleItoa()
 //    Description: converts an integer to a string.
@@ -484,47 +567,185 @@
 static const int kDoubleToBufferSize = 32;
 static const int kFloatToBufferSize = 24;
 
-// ----------------------------------------------------------------------
-// ToString() are internal help methods used in StrCat() and Join()
-// ----------------------------------------------------------------------
-namespace internal {
-inline string ToString(int i) {
-  return SimpleItoa(i);
-}
+namespace strings {
 
-inline string ToString(string a) {
-  return a;
-}
-}  // namespace internal
+enum PadSpec {
+  NO_PAD = 1,
+  ZERO_PAD_2,
+  ZERO_PAD_3,
+  ZERO_PAD_4,
+  ZERO_PAD_5,
+  ZERO_PAD_6,
+  ZERO_PAD_7,
+  ZERO_PAD_8,
+  ZERO_PAD_9,
+  ZERO_PAD_10,
+  ZERO_PAD_11,
+  ZERO_PAD_12,
+  ZERO_PAD_13,
+  ZERO_PAD_14,
+  ZERO_PAD_15,
+  ZERO_PAD_16,
+};
+
+struct Hex {
+  uint64 value;
+  enum PadSpec spec;
+  template <class Int>
+  explicit Hex(Int v, PadSpec s = NO_PAD)
+      : spec(s) {
+    // Prevent sign-extension by casting integers to
+    // their unsigned counterparts.
+#ifdef LANG_CXX11
+    static_assert(
+        sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
+        "Unknown integer type");
+#endif
+    value = sizeof(v) == 1 ? static_cast<uint8>(v)
+          : sizeof(v) == 2 ? static_cast<uint16>(v)
+          : sizeof(v) == 4 ? static_cast<uint32>(v)
+          : static_cast<uint64>(v);
+  }
+};
+
+struct LIBPROTOBUF_EXPORT AlphaNum {
+  const char *piece_data_;  // move these to string_ref eventually
+  size_t piece_size_;       // move these to string_ref eventually
+
+  char digits[kFastToBufferSize];
+
+  // No bool ctor -- bools convert to an integral type.
+  // A bool ctor would also convert incoming pointers (bletch).
+
+  AlphaNum(int32 i32)
+      : piece_data_(digits),
+        piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
+  AlphaNum(uint32 u32)
+      : piece_data_(digits),
+        piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
+  AlphaNum(int64 i64)
+      : piece_data_(digits),
+        piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
+  AlphaNum(uint64 u64)
+      : piece_data_(digits),
+        piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
+
+  AlphaNum(float f)
+    : piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
+  AlphaNum(double f)
+    : piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
+
+  AlphaNum(Hex hex);
+
+  AlphaNum(const char* c_str)
+      : piece_data_(c_str), piece_size_(strlen(c_str)) {}
+  // TODO: Add a string_ref constructor, eventually
+  // AlphaNum(const StringPiece &pc) : piece(pc) {}
+
+  AlphaNum(const string& str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
+  AlphaNum(StringPiece str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
+  AlphaNum(internal::StringPiecePod str)
+      : piece_data_(str.data()), piece_size_(str.size()) {}
+
+  size_t size() const { return piece_size_; }
+  const char *data() const { return piece_data_; }
+
+ private:
+  // Use ":" not ':'
+  AlphaNum(char c);  // NOLINT(runtime/explicit)
+
+  // Disallow copy and assign.
+  AlphaNum(const AlphaNum&);
+  void operator=(const AlphaNum&);
+};
+
+}  // namespace strings
+
+using strings::AlphaNum;
 
 // ----------------------------------------------------------------------
 // StrCat()
-//    These methods join some strings together.
+//    This merges the given strings or numbers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, strings, bool values,
+//    and numeric values.
+//
+//    Don't use this for user-visible strings.  The localization process
+//    works poorly on strings built up out of fragments.
+//
+//    For clarity and performance, don't use StrCat when appending to a
+//    string.  In particular, avoid using any of these (anti-)patterns:
+//      str.append(StrCat(...)
+//      str += StrCat(...)
+//      str = StrCat(str, ...)
+//    where the last is the worse, with the potential to change a loop
+//    from a linear time operation with O(1) dynamic allocations into a
+//    quadratic time operation with O(n) dynamic allocations.  StrAppend
+//    is a better choice than any of the above, subject to the restriction
+//    of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
+//    be a reference into str.
 // ----------------------------------------------------------------------
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-string StrCat(
-    const T1& a, const T2& b, const T3& c, const T4& d, const T5& e) {
-  return internal::ToString(a) + internal::ToString(b) +
-      internal::ToString(c) + internal::ToString(d) + internal::ToString(e);
-}
 
-template <typename T1, typename T2, typename T3, typename T4>
-string StrCat(
-    const T1& a, const T2& b, const T3& c, const T4& d) {
-  return internal::ToString(a) + internal::ToString(b) +
-      internal::ToString(c) + internal::ToString(d);
-}
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d,
+                                 const AlphaNum& e);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d,
+                                 const AlphaNum& e, const AlphaNum& f);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d,
+                                 const AlphaNum& e, const AlphaNum& f,
+                                 const AlphaNum& g);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d,
+                                 const AlphaNum& e, const AlphaNum& f,
+                                 const AlphaNum& g, const AlphaNum& h);
+LIBPROTOBUF_EXPORT string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                 const AlphaNum& c, const AlphaNum& d,
+                                 const AlphaNum& e, const AlphaNum& f,
+                                 const AlphaNum& g, const AlphaNum& h,
+                                 const AlphaNum& i);
 
-template <typename T1, typename T2, typename T3>
-string StrCat(const T1& a, const T2& b, const T3& c) {
-  return internal::ToString(a) + internal::ToString(b) +
-      internal::ToString(c);
-}
+inline string StrCat(const AlphaNum& a) { return string(a.data(), a.size()); }
 
-template <typename T1, typename T2>
-string StrCat(const T1& a, const T2& b) {
-  return internal::ToString(a) + internal::ToString(b);
-}
+// ----------------------------------------------------------------------
+// StrAppend()
+//    Same as above, but adds the output to the given string.
+//    WARNING: For speed, StrAppend does not try to check each of its input
+//    arguments to be sure that they are not a subset of the string being
+//    appended to.  That is, while this will work:
+//
+//    string s = "foo";
+//    s += s;
+//
+//    This will not (necessarily) work:
+//
+//    string s = "foo";
+//    StrAppend(&s, s);
+//
+//    Note: while StrCat supports appending up to 9 arguments, StrAppend
+//    is currently limited to 4.  That's rarely an issue except when
+//    automatically transforming StrCat to StrAppend, and can easily be
+//    worked around as consecutive calls to StrAppend are quite efficient.
+// ----------------------------------------------------------------------
+
+LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a);
+LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
+                                  const AlphaNum& b);
+LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
+                                  const AlphaNum& b, const AlphaNum& c);
+LIBPROTOBUF_EXPORT void StrAppend(string* dest, const AlphaNum& a,
+                                  const AlphaNum& b, const AlphaNum& c,
+                                  const AlphaNum& d);
 
 // ----------------------------------------------------------------------
 // Join()
@@ -538,7 +759,7 @@
     if (it != start) {
       result->append(delim);
     }
-    result->append(internal::ToString(*it));
+    StrAppend(result, *it);
   }
 }
 
@@ -556,6 +777,99 @@
 // ----------------------------------------------------------------------
 LIBPROTOBUF_EXPORT string ToHex(uint64 num);
 
+// ----------------------------------------------------------------------
+// GlobalReplaceSubstring()
+//    Replaces all instances of a substring in a string.  Does nothing
+//    if 'substring' is empty.  Returns the number of replacements.
+//
+//    NOTE: The string pieces must not overlap s.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int GlobalReplaceSubstring(const string& substring,
+                                              const string& replacement,
+                                              string* s);
+
+// ----------------------------------------------------------------------
+// Base64Unescape()
+//    Converts "src" which is encoded in Base64 to its binary equivalent and
+//    writes it to "dest". If src contains invalid characters, dest is cleared
+//    and the function returns false. Returns true on success.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT bool Base64Unescape(StringPiece src, string* dest);
+
+// ----------------------------------------------------------------------
+// WebSafeBase64Unescape()
+//    This is a variation of Base64Unescape which uses '-' instead of '+', and
+//    '_' instead of '/'. src is not null terminated, instead specify len. I
+//    recommend that slen<szdest, but we honor szdest anyway.
+//    RETURNS the length of dest, or -1 if src contains invalid chars.
+
+//    The variation that stores into a string clears the string first, and
+//    returns false (with dest empty) if src contains invalid chars; for
+//    this version src and dest must be different strings.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int WebSafeBase64Unescape(const char* src, int slen,
+                                             char* dest, int szdest);
+LIBPROTOBUF_EXPORT bool WebSafeBase64Unescape(StringPiece src, string* dest);
+
+// Return the length to use for the output buffer given to the base64 escape
+// routines. Make sure to use the same value for do_padding in both.
+// This function may return incorrect results if given input_len values that
+// are extremely high, which should happen rarely.
+LIBPROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len,
+                                                 bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+LIBPROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len);
+
+// ----------------------------------------------------------------------
+// Base64Escape()
+// WebSafeBase64Escape()
+//    Encode "src" to "dest" using base64 encoding.
+//    src is not null terminated, instead specify len.
+//    'dest' should have at least CalculateBase64EscapedLen() length.
+//    RETURNS the length of dest.
+//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'
+//    so that we can place the out in the URL or cookies without having
+//    to escape them.  It also has an extra parameter "do_padding",
+//    which when set to false will prevent padding with "=".
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int Base64Escape(const unsigned char* src, int slen,
+                                    char* dest, int szdest);
+LIBPROTOBUF_EXPORT int WebSafeBase64Escape(
+    const unsigned char* src, int slen, char* dest,
+    int szdest, bool do_padding);
+// Encode src into dest with padding.
+LIBPROTOBUF_EXPORT void Base64Escape(StringPiece src, string* dest);
+// Encode src into dest web-safely without padding.
+LIBPROTOBUF_EXPORT void WebSafeBase64Escape(StringPiece src, string* dest);
+// Encode src into dest web-safely with padding.
+LIBPROTOBUF_EXPORT void WebSafeBase64EscapeWithPadding(StringPiece src,
+                                                       string* dest);
+
+LIBPROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc,
+                                     string* dest, bool do_padding);
+LIBPROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc,
+                                            string* dest, bool do_padding);
+
+inline bool IsValidCodePoint(uint32 code_point) {
+  return code_point < 0xD800 ||
+         (code_point >= 0xE000 && code_point <= 0x10FFFF);
+}
+
+static const int UTFmax = 4;
+// ----------------------------------------------------------------------
+// EncodeAsUTF8Char()
+//  Helper to append a Unicode code point to a string as UTF8, without bringing
+//  in any external dependencies. The output buffer must be as least 4 bytes
+//  large.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int EncodeAsUTF8Char(uint32 code_point, char* output);
+
+// ----------------------------------------------------------------------
+// UTF8FirstLetterNumBytes()
+//   Length of the first UTF-8 character.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT int UTF8FirstLetterNumBytes(const char* src, int len);
+
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/stubs/strutil_unittest.cc b/src/google/protobuf/stubs/strutil_unittest.cc
index 7f27dca..5d62fc4 100644
--- a/src/google/protobuf/stubs/strutil_unittest.cc
+++ b/src/google/protobuf/stubs/strutil_unittest.cc
@@ -32,9 +32,15 @@
 
 #include <google/protobuf/stubs/strutil.h>
 
+#include <locale.h>
+
+#include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <locale.h>
+
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
 
 namespace google {
 namespace protobuf {
@@ -68,6 +74,737 @@
   setlocale(LC_NUMERIC, old_locale.c_str());
 }
 
+#define EXPECT_EQ_ARRAY(len, x, y, msg)                     \
+  for (int j = 0; j < len; ++j) {                           \
+    EXPECT_EQ(x[j], y[j]) << "" # x << " != " # y           \
+                          << " byte " << j << ": " << msg;  \
+  }
+
+static struct {
+  int plain_length;
+  const char* plaintext;
+  const char* cyphertext;
+} base64_tests[] = {
+  // Empty string.
+  { 0, "", ""},
+
+  // Basic bit patterns;
+  // values obtained with "echo -n '...' | uuencode -m test"
+
+  { 1, "\000", "AA==" },
+  { 1, "\001", "AQ==" },
+  { 1, "\002", "Ag==" },
+  { 1, "\004", "BA==" },
+  { 1, "\010", "CA==" },
+  { 1, "\020", "EA==" },
+  { 1, "\040", "IA==" },
+  { 1, "\100", "QA==" },
+  { 1, "\200", "gA==" },
+
+  { 1, "\377", "/w==" },
+  { 1, "\376", "/g==" },
+  { 1, "\375", "/Q==" },
+  { 1, "\373", "+w==" },
+  { 1, "\367", "9w==" },
+  { 1, "\357", "7w==" },
+  { 1, "\337", "3w==" },
+  { 1, "\277", "vw==" },
+  { 1, "\177", "fw==" },
+  { 2, "\000\000", "AAA=" },
+  { 2, "\000\001", "AAE=" },
+  { 2, "\000\002", "AAI=" },
+  { 2, "\000\004", "AAQ=" },
+  { 2, "\000\010", "AAg=" },
+  { 2, "\000\020", "ABA=" },
+  { 2, "\000\040", "ACA=" },
+  { 2, "\000\100", "AEA=" },
+  { 2, "\000\200", "AIA=" },
+  { 2, "\001\000", "AQA=" },
+  { 2, "\002\000", "AgA=" },
+  { 2, "\004\000", "BAA=" },
+  { 2, "\010\000", "CAA=" },
+  { 2, "\020\000", "EAA=" },
+  { 2, "\040\000", "IAA=" },
+  { 2, "\100\000", "QAA=" },
+  { 2, "\200\000", "gAA=" },
+
+  { 2, "\377\377", "//8=" },
+  { 2, "\377\376", "//4=" },
+  { 2, "\377\375", "//0=" },
+  { 2, "\377\373", "//s=" },
+  { 2, "\377\367", "//c=" },
+  { 2, "\377\357", "/+8=" },
+  { 2, "\377\337", "/98=" },
+  { 2, "\377\277", "/78=" },
+  { 2, "\377\177", "/38=" },
+  { 2, "\376\377", "/v8=" },
+  { 2, "\375\377", "/f8=" },
+  { 2, "\373\377", "+/8=" },
+  { 2, "\367\377", "9/8=" },
+  { 2, "\357\377", "7/8=" },
+  { 2, "\337\377", "3/8=" },
+  { 2, "\277\377", "v/8=" },
+  { 2, "\177\377", "f/8=" },
+
+  { 3, "\000\000\000", "AAAA" },
+  { 3, "\000\000\001", "AAAB" },
+  { 3, "\000\000\002", "AAAC" },
+  { 3, "\000\000\004", "AAAE" },
+  { 3, "\000\000\010", "AAAI" },
+  { 3, "\000\000\020", "AAAQ" },
+  { 3, "\000\000\040", "AAAg" },
+  { 3, "\000\000\100", "AABA" },
+  { 3, "\000\000\200", "AACA" },
+  { 3, "\000\001\000", "AAEA" },
+  { 3, "\000\002\000", "AAIA" },
+  { 3, "\000\004\000", "AAQA" },
+  { 3, "\000\010\000", "AAgA" },
+  { 3, "\000\020\000", "ABAA" },
+  { 3, "\000\040\000", "ACAA" },
+  { 3, "\000\100\000", "AEAA" },
+  { 3, "\000\200\000", "AIAA" },
+  { 3, "\001\000\000", "AQAA" },
+  { 3, "\002\000\000", "AgAA" },
+  { 3, "\004\000\000", "BAAA" },
+  { 3, "\010\000\000", "CAAA" },
+  { 3, "\020\000\000", "EAAA" },
+  { 3, "\040\000\000", "IAAA" },
+  { 3, "\100\000\000", "QAAA" },
+  { 3, "\200\000\000", "gAAA" },
+
+  { 3, "\377\377\377", "////" },
+  { 3, "\377\377\376", "///+" },
+  { 3, "\377\377\375", "///9" },
+  { 3, "\377\377\373", "///7" },
+  { 3, "\377\377\367", "///3" },
+  { 3, "\377\377\357", "///v" },
+  { 3, "\377\377\337", "///f" },
+  { 3, "\377\377\277", "//+/" },
+  { 3, "\377\377\177", "//9/" },
+  { 3, "\377\376\377", "//7/" },
+  { 3, "\377\375\377", "//3/" },
+  { 3, "\377\373\377", "//v/" },
+  { 3, "\377\367\377", "//f/" },
+  { 3, "\377\357\377", "/+//" },
+  { 3, "\377\337\377", "/9//" },
+  { 3, "\377\277\377", "/7//" },
+  { 3, "\377\177\377", "/3//" },
+  { 3, "\376\377\377", "/v//" },
+  { 3, "\375\377\377", "/f//" },
+  { 3, "\373\377\377", "+///" },
+  { 3, "\367\377\377", "9///" },
+  { 3, "\357\377\377", "7///" },
+  { 3, "\337\377\377", "3///" },
+  { 3, "\277\377\377", "v///" },
+  { 3, "\177\377\377", "f///" },
+
+  // Random numbers: values obtained with
+  //
+  //  #! /bin/bash
+  //  dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
+  //  od -N $1 -t o1 /tmp/bar.random
+  //  uuencode -m test < /tmp/bar.random
+  //
+  // where $1 is the number of bytes (2, 3)
+
+  { 2, "\243\361", "o/E=" },
+  { 2, "\024\167", "FHc=" },
+  { 2, "\313\252", "y6o=" },
+  { 2, "\046\041", "JiE=" },
+  { 2, "\145\236", "ZZ4=" },
+  { 2, "\254\325", "rNU=" },
+  { 2, "\061\330", "Mdg=" },
+  { 2, "\245\032", "pRo=" },
+  { 2, "\006\000", "BgA=" },
+  { 2, "\375\131", "/Vk=" },
+  { 2, "\303\210", "w4g=" },
+  { 2, "\040\037", "IB8=" },
+  { 2, "\261\372", "sfo=" },
+  { 2, "\335\014", "3Qw=" },
+  { 2, "\233\217", "m48=" },
+  { 2, "\373\056", "+y4=" },
+  { 2, "\247\232", "p5o=" },
+  { 2, "\107\053", "Rys=" },
+  { 2, "\204\077", "hD8=" },
+  { 2, "\276\211", "vok=" },
+  { 2, "\313\110", "y0g=" },
+  { 2, "\363\376", "8/4=" },
+  { 2, "\251\234", "qZw=" },
+  { 2, "\103\262", "Q7I=" },
+  { 2, "\142\312", "Yso=" },
+  { 2, "\067\211", "N4k=" },
+  { 2, "\220\001", "kAE=" },
+  { 2, "\152\240", "aqA=" },
+  { 2, "\367\061", "9zE=" },
+  { 2, "\133\255", "W60=" },
+  { 2, "\176\035", "fh0=" },
+  { 2, "\032\231", "Gpk=" },
+
+  { 3, "\013\007\144", "Cwdk" },
+  { 3, "\030\112\106", "GEpG" },
+  { 3, "\047\325\046", "J9Um" },
+  { 3, "\310\160\022", "yHAS" },
+  { 3, "\131\100\237", "WUCf" },
+  { 3, "\064\342\134", "NOJc" },
+  { 3, "\010\177\004", "CH8E" },
+  { 3, "\345\147\205", "5WeF" },
+  { 3, "\300\343\360", "wOPw" },
+  { 3, "\061\240\201", "MaCB" },
+  { 3, "\225\333\044", "ldsk" },
+  { 3, "\215\137\352", "jV/q" },
+  { 3, "\371\147\160", "+Wdw" },
+  { 3, "\030\320\051", "GNAp" },
+  { 3, "\044\174\241", "JHyh" },
+  { 3, "\260\127\037", "sFcf" },
+  { 3, "\111\045\033", "SSUb" },
+  { 3, "\202\114\107", "gkxH" },
+  { 3, "\057\371\042", "L/ki" },
+  { 3, "\223\247\244", "k6ek" },
+  { 3, "\047\216\144", "J45k" },
+  { 3, "\203\070\327", "gzjX" },
+  { 3, "\247\140\072", "p2A6" },
+  { 3, "\124\115\116", "VE1O" },
+  { 3, "\157\162\050", "b3Io" },
+  { 3, "\357\223\004", "75ME" },
+  { 3, "\052\117\156", "Kk9u" },
+  { 3, "\347\154\000", "52wA" },
+  { 3, "\303\012\142", "wwpi" },
+  { 3, "\060\035\362", "MB3y" },
+  { 3, "\130\226\361", "WJbx" },
+  { 3, "\173\013\071", "ews5" },
+  { 3, "\336\004\027", "3gQX" },
+  { 3, "\357\366\234", "7/ac" },
+  { 3, "\353\304\111", "68RJ" },
+  { 3, "\024\264\131", "FLRZ" },
+  { 3, "\075\114\251", "PUyp" },
+  { 3, "\315\031\225", "zRmV" },
+  { 3, "\154\201\276", "bIG+" },
+  { 3, "\200\066\072", "gDY6" },
+  { 3, "\142\350\267", "Yui3" },
+  { 3, "\033\000\166", "GwB2" },
+  { 3, "\210\055\077", "iC0/" },
+  { 3, "\341\037\124", "4R9U" },
+  { 3, "\161\103\152", "cUNq" },
+  { 3, "\270\142\131", "uGJZ" },
+  { 3, "\337\076\074", "3z48" },
+  { 3, "\375\106\362", "/Uby" },
+  { 3, "\227\301\127", "l8FX" },
+  { 3, "\340\002\234", "4AKc" },
+  { 3, "\121\064\033", "UTQb" },
+  { 3, "\157\134\143", "b1xj" },
+  { 3, "\247\055\327", "py3X" },
+  { 3, "\340\142\005", "4GIF" },
+  { 3, "\060\260\143", "MLBj" },
+  { 3, "\075\203\170", "PYN4" },
+  { 3, "\143\160\016", "Y3AO" },
+  { 3, "\313\013\063", "ywsz" },
+  { 3, "\174\236\135", "fJ5d" },
+  { 3, "\103\047\026", "QycW" },
+  { 3, "\365\005\343", "9QXj" },
+  { 3, "\271\160\223", "uXCT" },
+  { 3, "\362\255\172", "8q16" },
+  { 3, "\113\012\015", "SwoN" },
+
+  // various lengths, generated by this python script:
+  //
+  // from string import lowercase as lc
+  // for i in range(27):
+  //   print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
+  //                                     lc[:i].encode('base64').strip())
+
+  {  0, "",                           "" },
+  {  1, "a",                          "YQ==" },
+  {  2, "ab",                         "YWI=" },
+  {  3, "abc",                        "YWJj" },
+  {  4, "abcd",                       "YWJjZA==" },
+  {  5, "abcde",                      "YWJjZGU=" },
+  {  6, "abcdef",                     "YWJjZGVm" },
+  {  7, "abcdefg",                    "YWJjZGVmZw==" },
+  {  8, "abcdefgh",                   "YWJjZGVmZ2g=" },
+  {  9, "abcdefghi",                  "YWJjZGVmZ2hp" },
+  { 10, "abcdefghij",                 "YWJjZGVmZ2hpag==" },
+  { 11, "abcdefghijk",                "YWJjZGVmZ2hpams=" },
+  { 12, "abcdefghijkl",               "YWJjZGVmZ2hpamts" },
+  { 13, "abcdefghijklm",              "YWJjZGVmZ2hpamtsbQ==" },
+  { 14, "abcdefghijklmn",             "YWJjZGVmZ2hpamtsbW4=" },
+  { 15, "abcdefghijklmno",            "YWJjZGVmZ2hpamtsbW5v" },
+  { 16, "abcdefghijklmnop",           "YWJjZGVmZ2hpamtsbW5vcA==" },
+  { 17, "abcdefghijklmnopq",          "YWJjZGVmZ2hpamtsbW5vcHE=" },
+  { 18, "abcdefghijklmnopqr",         "YWJjZGVmZ2hpamtsbW5vcHFy" },
+  { 19, "abcdefghijklmnopqrs",        "YWJjZGVmZ2hpamtsbW5vcHFycw==" },
+  { 20, "abcdefghijklmnopqrst",       "YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
+  { 21, "abcdefghijklmnopqrstu",      "YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
+  { 22, "abcdefghijklmnopqrstuv",     "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
+  { 23, "abcdefghijklmnopqrstuvw",    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
+  { 24, "abcdefghijklmnopqrstuvwx",   "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
+  { 25, "abcdefghijklmnopqrstuvwxy",  "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
+  { 26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
+};
+
+static struct {
+  const char* plaintext;
+  const char* cyphertext;
+} base64_strings[] = {
+  // Some google quotes
+  // Cyphertext created with "uuencode (GNU sharutils) 4.6.3"
+  // (Note that we're testing the websafe encoding, though, so if
+  // you add messages, be sure to run "tr -- '+/' '-_'" on the output)
+  { "I was always good at math and science, and I never realized "
+    "that was unusual or somehow undesirable. So one of the things "
+    "I care a lot about is helping to remove that stigma, "
+    "to show girls that you can be feminine, you can like the things "
+    "that girls like, but you can also be really good at technology. "
+    "You can be really good at building things."
+    " - Marissa Meyer, Newsweek, 2010-12-22" "\n",
+
+    "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg"
+    "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu"
+    "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg"
+    "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo"
+    "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp"
+    "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs"
+    "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy"
+    "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll"
+    "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" },
+
+  { "Typical first year for a new cluster: "
+    "~0.5 overheating "
+    "~1 PDU failure "
+    "~1 rack-move "
+    "~1 network rewiring "
+    "~20 rack failures "
+    "~5 racks go wonky "
+    "~8 network maintenances "
+    "~12 router reloads "
+    "~3 router failures "
+    "~dozens of minor 30-second blips for dns "
+    "~1000 individual machine failures "
+    "~thousands of hard drive failures "
+    "slow disks, bad memory, misconfigured machines, flaky machines, etc."
+    " - Jeff Dean, The Joys of Real Hardware" "\n",
+
+    "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92"
+    "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3"
+    "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv"
+    "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk"
+    "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv"
+    "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp"
+    "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg"
+    "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs"
+    "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS"
+    "ZWFsIEhhcmR3YXJlCg" },
+
+  { "I'm the head of the webspam team at Google.  "
+    "That means that if you type your name into Google and get porn back, "
+    "it's my fault. Unless you're a porn star, in which case porn is a "
+    "completely reasonable response."
+    " - Matt Cutts, Google Plus" "\n",
+
+    "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg"
+    "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv"
+    "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz"
+    "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg"
+    "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs"
+    "IEdvb2dsZSBQbHVzCg" },
+
+  { "It will still be a long time before machines approach human intelligence. "
+    "But luckily, machines don't actually have to be intelligent; "
+    "they just have to fake it. Access to a wealth of information, "
+    "combined with a rudimentary decision-making capacity, "
+    "can often be almost as useful. Of course, the results are better yet "
+    "when coupled with intelligence. A reference librarian with access to "
+    "a good search engine is a formidable tool."
+    " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" "\n",
+
+    "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg"
+    "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj"
+    "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg"
+    "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo"
+    "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg"
+    "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0"
+    "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy"
+    "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl"
+    "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu"
+    "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp"
+    "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw"
+    "NAo" },
+
+  // Degenerate edge case
+  { "",
+    "" },
+};
+
+TEST(Base64, EscapeAndUnescape) {
+  // Check the short strings; this tests the math (and boundaries)
+  for (int i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i) {
+    char encode_buffer[100];
+    int encode_length;
+    char decode_buffer[100];
+    int decode_length;
+    int cypher_length;
+    string decode_str;
+
+    const unsigned char* unsigned_plaintext =
+      reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);
+
+    StringPiece plaintext(base64_tests[i].plaintext,
+                          base64_tests[i].plain_length);
+
+    cypher_length = strlen(base64_tests[i].cyphertext);
+
+    // The basic escape function:
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = Base64Escape(unsigned_plaintext,
+                                 base64_tests[i].plain_length,
+                                 encode_buffer,
+                                 sizeof(encode_buffer));
+    //    Is it of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+    // Would it have been okay to allocate only CalculateBase64EscapeLen()?
+    EXPECT_EQ(CalculateBase64EscapedLen(base64_tests[i].plain_length),
+              encode_length);
+
+    //    Is it the expected encoded value?
+    ASSERT_STREQ(encode_buffer, base64_tests[i].cyphertext);
+
+    // If we encode it into a buffer of exactly the right length...
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = Base64Escape(unsigned_plaintext,
+                                          base64_tests[i].plain_length,
+                                          encode_buffer,
+                                          cypher_length);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+
+    //    And is the value still correct?  (i.e., not losing the last byte)
+    EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext);
+
+    // If we decode it back:
+    decode_str.clear();
+    EXPECT_TRUE(Base64Unescape(
+        StringPiece(encode_buffer, cypher_length), &decode_str));
+
+    //    Is it of the expected length?
+    EXPECT_EQ(base64_tests[i].plain_length, decode_str.length());
+
+    //    Is it the expected decoded value?
+    EXPECT_EQ(plaintext, decode_str);
+
+    // Let's try with a pre-populated string.
+    string encoded("this junk should be ignored");
+    Base64Escape(string(base64_tests[i].plaintext,
+                        base64_tests[i].plain_length),
+                 &encoded);
+    EXPECT_EQ(encoded, string(encode_buffer, cypher_length));
+
+    string decoded("this junk should be ignored");
+    EXPECT_TRUE(Base64Unescape(
+        StringPiece(encode_buffer, cypher_length), &decoded));
+    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+    // Our decoder treats the padding '=' characters at the end as
+    // optional (but if there are any, there must be the correct
+    // number of them.)  If encode_buffer has any, run some additional
+    // tests that fiddle with them.
+    char* first_equals = strchr(encode_buffer, '=');
+    if (first_equals) {
+      // How many equals signs does the string start with?
+      int equals = (*(first_equals+1) == '=') ? 2 : 1;
+
+      // Try chopping off the equals sign(s) entirely.  The decoder
+      // should still be okay with this.
+      string decoded2("this junk should also be ignored");
+      *first_equals = '\0';
+      EXPECT_TRUE(Base64Unescape(
+          StringPiece(encode_buffer, first_equals - encode_buffer), &decoded2));
+      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+      // Now test chopping off the equals sign(s) and adding
+      // whitespace.  Our decoder should still accept this.
+      decoded2.assign("this junk should be ignored");
+      *first_equals = ' ';
+      *(first_equals+1) = '\0';
+      EXPECT_TRUE(Base64Unescape(
+          StringPiece(encode_buffer, first_equals - encode_buffer + 1),
+          &decoded2));
+      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+      // Now stick a bad character at the end of the string.  The decoder
+      // should refuse this string.
+      decoded2.assign("this junk should be ignored");
+      *first_equals = '?';
+      *(first_equals+1) = '\0';
+      EXPECT_TRUE(
+          !Base64Unescape(
+              StringPiece(encode_buffer, first_equals - encode_buffer + 1),
+              &decoded2));
+
+      int len;
+
+      // Test whitespace mixed with the padding.  (eg "AA = = ")  The
+      // decoder should accept this.
+      if (equals == 2) {
+        snprintf(first_equals, 6, " = = ");
+        len = first_equals - encode_buffer + 5;
+      } else {
+        snprintf(first_equals, 6, " = ");
+        len = first_equals - encode_buffer + 3;
+      }
+      decoded2.assign("this junk should be ignored");
+      EXPECT_TRUE(
+          Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
+      EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+      EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+      // Test whitespace mixed with the padding, but with the wrong
+      // number of equals signs (eg "AA = ").  The decoder should
+      // refuse these strings.
+      if (equals == 1) {
+        snprintf(first_equals, 6, " = = ");
+        len = first_equals - encode_buffer + 5;
+      } else {
+        snprintf(first_equals, 6, " = ");
+        len = first_equals - encode_buffer + 3;
+      }
+      EXPECT_TRUE(
+          !Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
+    }
+
+    // Cool! the basic Base64 encoder/decoder works.
+    // Let's try the alternate alphabet: tr -- '+/' '-_'
+
+    char websafe[100];
+    memset(websafe, 0, sizeof(websafe));
+    strncpy(websafe, base64_tests[i].cyphertext, cypher_length);
+    for (int c = 0; c < sizeof(websafe); ++c) {
+      if ('+' == websafe[c]) { websafe[c] = '-'; }
+      if ('/' == websafe[c]) { websafe[c] = '_'; }
+    }
+
+    // The websafe escape function:
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                 base64_tests[i].plain_length,
+                                                 encode_buffer,
+                                                 sizeof(encode_buffer),
+                                                 true);
+    //    Is it of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+    EXPECT_EQ(
+        CalculateBase64EscapedLen(base64_tests[i].plain_length, true),
+        encode_length);
+
+    //    Is it the expected encoded value?
+    EXPECT_STREQ(encode_buffer, websafe);
+
+    //    If we encode it into a buffer of exactly the right length...
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                 base64_tests[i].plain_length,
+                                                 encode_buffer,
+                                                 cypher_length,
+                                                 true);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+
+    //    And is the value still correct?  (i.e., not losing the last byte)
+    EXPECT_STREQ(encode_buffer, websafe);
+
+    //    Let's try the string version of the encoder
+    encoded = "this junk should be ignored";
+    WebSafeBase64Escape(
+        unsigned_plaintext, base64_tests[i].plain_length,
+        &encoded, true);
+    EXPECT_EQ(encoded.size(), cypher_length);
+    EXPECT_STREQ(encoded.c_str(), websafe);
+
+    //    If we decode it back:
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   sizeof(decode_buffer));
+
+    //    Is it of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    //    Is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+    //    If we decode it into a buffer of exactly the right length...
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   decode_length);
+
+    //    Is it still of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    //    And is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+    // Try using '.' for the pad character.
+    for (int c = cypher_length - 1; c >= 0 && '=' == encode_buffer[c]; --c) {
+      encode_buffer[c] = '.';
+    }
+
+    // If we decode it back:
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   sizeof(decode_buffer));
+
+    // Is it of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    // Is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+    // If we decode it into a buffer of exactly the right length...
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   decode_length);
+
+    // Is it still of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    // And is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+    // Let's try the string version of the decoder
+    decoded = "this junk should be ignored";
+    EXPECT_TRUE(WebSafeBase64Unescape(
+        StringPiece(encode_buffer, cypher_length), &decoded));
+    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+    // Okay! the websafe Base64 encoder/decoder works.
+    // Let's try the unpadded version
+
+    for (int c = 0; c < sizeof(websafe); ++c) {
+      if ('=' == websafe[c]) {
+        websafe[c] = '\0';
+        cypher_length = c;
+        break;
+      }
+    }
+
+    // The websafe escape function:
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                 base64_tests[i].plain_length,
+                                                 encode_buffer,
+                                                 sizeof(encode_buffer),
+                                                 false);
+    //    Is it of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+    EXPECT_EQ(
+        CalculateBase64EscapedLen(base64_tests[i].plain_length, false),
+        encode_length);
+
+    //    Is it the expected encoded value?
+    EXPECT_STREQ(encode_buffer, websafe);
+
+    //    If we encode it into a buffer of exactly the right length...
+    memset(encode_buffer, 0, sizeof(encode_buffer));
+    encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                 base64_tests[i].plain_length,
+                                                 encode_buffer,
+                                                 cypher_length,
+                                                 false);
+    //    Is it still of the expected length?
+    EXPECT_EQ(encode_length, cypher_length);
+
+    //    And is the value still correct?  (i.e., not losing the last byte)
+    EXPECT_STREQ(encode_buffer, websafe);
+
+    // Let's try the (other) string version of the encoder
+    string plain(base64_tests[i].plaintext, base64_tests[i].plain_length);
+    encoded = "this junk should be ignored";
+    WebSafeBase64Escape(plain, &encoded);
+    EXPECT_EQ(encoded.size(), cypher_length);
+    EXPECT_STREQ(encoded.c_str(), websafe);
+
+    //    If we decode it back:
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   sizeof(decode_buffer));
+
+    //    Is it of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    //    Is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+    //    If we decode it into a buffer of exactly the right length...
+    memset(decode_buffer, 0, sizeof(decode_buffer));
+    decode_length = WebSafeBase64Unescape(encode_buffer,
+                                                   cypher_length,
+                                                   decode_buffer,
+                                                   decode_length);
+
+    //    Is it still of the expected length?
+    EXPECT_EQ(decode_length, base64_tests[i].plain_length);
+
+    //    And is it the expected decoded value?
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+
+
+    // Let's try the string version of the decoder
+    decoded = "this junk should be ignored";
+    EXPECT_TRUE(WebSafeBase64Unescape(
+        StringPiece(encode_buffer, cypher_length), &decoded));
+    EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
+    EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
+
+    // This value works.  Try the next.
+  }
+
+  // Now try the long strings, this tests the streaming
+  for (int i = 0; i < sizeof(base64_strings) / sizeof(base64_strings[0]);
+       ++i) {
+    const unsigned char* unsigned_plaintext =
+      reinterpret_cast<const unsigned char*>(base64_strings[i].plaintext);
+    int plain_length = strlen(base64_strings[i].plaintext);
+    int cypher_length = strlen(base64_strings[i].cyphertext);
+    vector<char> buffer(cypher_length+1);
+    int encode_length = WebSafeBase64Escape(unsigned_plaintext,
+                                                     plain_length,
+                                                     &buffer[0],
+                                                     buffer.size(),
+                                                     false);
+    EXPECT_EQ(cypher_length, encode_length);
+    EXPECT_EQ(
+        CalculateBase64EscapedLen(plain_length, false), encode_length);
+    buffer[ encode_length ] = '\0';
+    EXPECT_STREQ(base64_strings[i].cyphertext, &buffer[0]);
+  }
+
+  // Verify the behavior when decoding bad data
+  {
+    const char* bad_data = "ab-/";
+    string buf;
+    EXPECT_FALSE(Base64Unescape(StringPiece(bad_data), &buf));
+    EXPECT_TRUE(!WebSafeBase64Unescape(bad_data, &buf));
+    EXPECT_TRUE(buf.empty());
+  }
+}
+
 }  // anonymous namespace
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/stubs/template_util.h b/src/google/protobuf/stubs/template_util.h
index 4f30ffa..feef904 100644
--- a/src/google/protobuf/stubs/template_util.h
+++ b/src/google/protobuf/stubs/template_util.h
@@ -37,7 +37,7 @@
 // any changes here, make sure that you're not breaking any platforms.
 //
 //
-// The names choosen here reflect those used in tr1 and the boost::mpl
+// The names chosen here reflect those used in tr1 and the boost::mpl
 // library, there are similar operations used in the Loki library as
 // well.  I prefer the boost names for 2 reasons:
 // 1.  I think that portions of the Boost libraries are more likely to
diff --git a/src/google/protobuf/stubs/time.cc b/src/google/protobuf/stubs/time.cc
new file mode 100644
index 0000000..49c0412
--- /dev/null
+++ b/src/google/protobuf/stubs/time.cc
@@ -0,0 +1,365 @@
+#include <google/protobuf/stubs/time.h>
+
+#include <ctime>
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+static const int64 kSecondsPerMinute = 60;
+static const int64 kSecondsPerHour = 3600;
+static const int64 kSecondsPerDay = kSecondsPerHour * 24;
+static const int64 kSecondsPer400Years =
+    kSecondsPerDay * (400 * 365 + 400 / 4 - 3);
+// Seconds from 0001-01-01T00:00:00 to 1970-01-01T:00:00:00
+static const int64 kSecondsFromEraToEpoch = 62135596800LL;
+// The range of timestamp values we support.
+static const int64 kMinTime = -62135596800LL;  // 0001-01-01T00:00:00
+static const int64 kMaxTime = 253402300799LL;  // 9999-12-31T23:59:59
+
+static const int kNanosPerMillisecond = 1000000;
+static const int kNanosPerMicrosecond = 1000;
+
+// Count the seconds from the given year (start at Jan 1, 00:00) to 100 years
+// after.
+int64 SecondsPer100Years(int year) {
+  if (year % 400 == 0 || year % 400 > 300) {
+    return kSecondsPerDay * (100 * 365 + 100 / 4);
+  } else {
+    return kSecondsPerDay * (100 * 365 + 100 / 4 - 1);
+  }
+}
+
+// Count the seconds from the given year (start at Jan 1, 00:00) to 4 years
+// after.
+int64 SecondsPer4Years(int year) {
+  if ((year % 100 == 0 || year % 100 > 96) &&
+      !(year % 400 == 0 || year % 400 > 396)) {
+    // No leap years.
+    return kSecondsPerDay * (4 * 365);
+  } else {
+    // One leap years.
+    return kSecondsPerDay * (4 * 365 + 1);
+  }
+}
+
+bool IsLeapYear(int year) {
+  return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
+}
+
+int64 SecondsPerYear(int year) {
+  return kSecondsPerDay * (IsLeapYear(year) ? 366 : 365);
+}
+
+static const int kDaysInMonth[13] = {
+  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+int64 SecondsPerMonth(int month, bool leap) {
+  if (month == 2 && leap) {
+    return kSecondsPerDay * (kDaysInMonth[month] + 1);
+  }
+  return kSecondsPerDay * kDaysInMonth[month];
+}
+
+static const int kDaysSinceJan[13] = {
+  0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+};
+
+bool ValidateDateTime(const DateTime& time) {
+  if (time.year < 1 || time.year > 9999 ||
+      time.month < 1 || time.month > 12 ||
+      time.day < 1 || time.day > 31 ||
+      time.hour < 0 || time.hour > 23 ||
+      time.minute < 0 || time.minute > 59 ||
+      time.second < 0 || time.second > 59) {
+    return false;
+  }
+  if (time.month == 2 && IsLeapYear(time.year)) {
+    return time.month <= kDaysInMonth[time.month] + 1;
+  } else {
+    return time.month <= kDaysInMonth[time.month];
+  }
+}
+
+// Count the number of seconds elapsed from 0001-01-01T00:00:00 to the given
+// time.
+int64 SecondsSinceCommonEra(const DateTime& time) {
+  int64 result = 0;
+  // Years should be between 1 and 9999.
+  assert(time.year >= 1 && time.year <= 9999);
+  int year = 1;
+  if ((time.year - year) >= 400) {
+    int count_400years = (time.year - year) / 400;
+    result += kSecondsPer400Years * count_400years;
+    year += count_400years * 400;
+  }
+  while ((time.year - year) >= 100) {
+    result += SecondsPer100Years(year);
+    year += 100;
+  }
+  while ((time.year - year) >= 4) {
+    result += SecondsPer4Years(year);
+    year += 4;
+  }
+  while (time.year > year) {
+    result += SecondsPerYear(year);
+    ++year;
+  }
+  // Months should be between 1 and 12.
+  assert(time.month >= 1 && time.month <= 12);
+  int month = time.month;
+  result += kSecondsPerDay * kDaysSinceJan[month];
+  if (month > 2 && IsLeapYear(year)) {
+    result += kSecondsPerDay;
+  }
+  assert(time.day >= 1 &&
+         time.day <= (month == 2 && IsLeapYear(year)
+                          ? kDaysInMonth[month] + 1
+                          : kDaysInMonth[month]));
+  result += kSecondsPerDay * (time.day - 1);
+  result += kSecondsPerHour * time.hour +
+      kSecondsPerMinute * time.minute +
+      time.second;
+  return result;
+}
+
+// Format nanoseconds with either 3, 6, or 9 digits depending on the required
+// precision to represent the exact value.
+string FormatNanos(int32 nanos) {
+  if (nanos % kNanosPerMillisecond == 0) {
+    return StringPrintf("%03d", nanos / kNanosPerMillisecond);
+  } else if (nanos % kNanosPerMicrosecond == 0) {
+    return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
+  } else {
+    return StringPrintf("%09d", nanos);
+  }
+}
+
+// Parses an integer from a null-terminated char sequence. The method
+// consumes at most "width" chars. Returns a pointer after the consumed
+// integer, or NULL if the data does not start with an integer or the
+// integer value does not fall in the range of [min_value, max_value].
+const char* ParseInt(const char* data, int width, int min_value,
+                     int max_value, int* result) {
+  if (!ascii_isdigit(*data)) {
+    return NULL;
+  }
+  int value = 0;
+  for (int i = 0; i < width; ++i, ++data) {
+    if (ascii_isdigit(*data)) {
+      value = value * 10 + (*data - '0');
+    } else {
+      break;
+    }
+  }
+  if (value >= min_value && value <= max_value) {
+    *result = value;
+    return data;
+  } else {
+    return NULL;
+  }
+}
+
+// Consumes the fractional parts of a second into nanos. For example,
+// "010" will be parsed to 10000000 nanos.
+const char* ParseNanos(const char* data, int32* nanos) {
+  if (!ascii_isdigit(*data)) {
+    return NULL;
+  }
+  int value = 0;
+  int len = 0;
+  // Consume as many digits as there are but only take the first 9 into
+  // account.
+  while (ascii_isdigit(*data)) {
+    if (len < 9) {
+      value = value * 10 + *data - '0';
+    }
+    ++len;
+    ++data;
+  }
+  while (len < 9) {
+    value = value * 10;
+    ++len;
+  }
+  *nanos = value;
+  return data;
+}
+
+const char* ParseTimezoneOffset(const char* data, int64* offset) {
+  // Accept format "HH:MM". E.g., "08:00"
+  int hour;
+  if ((data = ParseInt(data, 2, 0, 23, &hour)) == NULL) {
+    return NULL;
+  }
+  if (*data++ != ':') {
+    return NULL;
+  }
+  int minute;
+  if ((data = ParseInt(data, 2, 0, 59, &minute)) == NULL) {
+    return NULL;
+  }
+  *offset = (hour * 60 + minute) * 60;
+  return data;
+}
+}  // namespace
+
+bool SecondsToDateTime(int64 seconds, DateTime* time) {
+  if (seconds < kMinTime || seconds > kMaxTime) {
+    return false;
+  }
+  // It's easier to calcuate the DateTime starting from 0001-01-01T00:00:00
+  seconds = seconds + kSecondsFromEraToEpoch;
+  int year = 1;
+  if (seconds >= kSecondsPer400Years) {
+    int count_400years = seconds / kSecondsPer400Years;
+    year += 400 * count_400years;
+    seconds %= kSecondsPer400Years;
+  }
+  while (seconds >= SecondsPer100Years(year)) {
+    seconds -= SecondsPer100Years(year);
+    year += 100;
+  }
+  while (seconds >= SecondsPer4Years(year)) {
+    seconds -= SecondsPer4Years(year);
+    year += 4;
+  }
+  while (seconds >= SecondsPerYear(year)) {
+    seconds -= SecondsPerYear(year);
+    year += 1;
+  }
+  bool leap = IsLeapYear(year);
+  int month = 1;
+  while (seconds >= SecondsPerMonth(month, leap)) {
+    seconds -= SecondsPerMonth(month, leap);
+    ++month;
+  }
+  int day = 1 + seconds / kSecondsPerDay;
+  seconds %= kSecondsPerDay;
+  int hour = seconds / kSecondsPerHour;
+  seconds %= kSecondsPerHour;
+  int minute = seconds / kSecondsPerMinute;
+  seconds %= kSecondsPerMinute;
+  time->year = year;
+  time->month = month;
+  time->day = day;
+  time->hour = hour;
+  time->minute = minute;
+  time->second = static_cast<int>(seconds);
+  return true;
+}
+
+bool DateTimeToSeconds(const DateTime& time, int64* seconds) {
+  if (!ValidateDateTime(time)) {
+    return false;
+  }
+  *seconds = SecondsSinceCommonEra(time) - kSecondsFromEraToEpoch;
+  return true;
+}
+
+void GetCurrentTime(int64* seconds, int32* nanos) {
+  // TODO(xiaofeng): Improve the accuracy of this implementation (or just
+  // remove this method from protobuf).
+  *seconds = time(NULL);
+  *nanos = 0;
+}
+
+string FormatTime(int64 seconds, int32 nanos) {
+  DateTime time;
+  if (nanos < 0 || nanos > 999999999 || !SecondsToDateTime(seconds, &time)) {
+    return "InvalidTime";
+  }
+  string result = StringPrintf("%04d-%02d-%02dT%02d:%02d:%02d",
+                               time.year, time.month, time.day,
+                               time.hour, time.minute, time.second);
+  if (nanos != 0) {
+    result += "." + FormatNanos(nanos);
+  }
+  return result + "Z";
+}
+
+bool ParseTime(const string& value, int64* seconds, int32* nanos) {
+  DateTime time;
+  const char* data = value.c_str();
+  // We only accept:
+  //   Z-normalized: 2015-05-20T13:29:35.120Z
+  //   With UTC offset: 2015-05-20T13:29:35.120-08:00
+
+  // Parse year
+  if ((data = ParseInt(data, 4, 1, 9999, &time.year)) == NULL) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse month
+  if ((data = ParseInt(data, 2, 1, 12, &time.month)) == NULL) {
+    return false;
+  }
+  // Expect '-'
+  if (*data++ != '-') return false;
+  // Parse day
+  if ((data = ParseInt(data, 2, 1, 31, &time.day)) == NULL) {
+    return false;
+  }
+  // Expect 'T'
+  if (*data++ != 'T') return false;
+  // Parse hour
+  if ((data = ParseInt(data, 2, 0, 23, &time.hour)) == NULL) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse minute
+  if ((data = ParseInt(data, 2, 0, 59, &time.minute)) == NULL) {
+    return false;
+  }
+  // Expect ':'
+  if (*data++ != ':') return false;
+  // Parse second
+  if ((data = ParseInt(data, 2, 0, 59, &time.second)) == NULL) {
+    return false;
+  }
+  if (!DateTimeToSeconds(time, seconds)) {
+    return false;
+  }
+  // Parse nanoseconds.
+  if (*data == '.') {
+    ++data;
+    // Parse nanoseconds.
+    if ((data = ParseNanos(data, nanos)) == NULL) {
+      return false;
+    }
+  } else {
+    *nanos = 0;
+  }
+  // Parse UTC offsets.
+  if (*data == 'Z') {
+    ++data;
+  } else if (*data == '+') {
+    ++data;
+    int64 offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == NULL) {
+      return false;
+    }
+    *seconds -= offset;
+  } else if (*data == '-') {
+    ++data;
+    int64 offset;
+    if ((data = ParseTimezoneOffset(data, &offset)) == NULL) {
+      return false;
+    }
+    *seconds += offset;
+  } else {
+    return false;
+  }
+  // Done with parsing.
+  return *data == 0;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/time.h b/src/google/protobuf/stubs/time.h
new file mode 100644
index 0000000..20a6b56
--- /dev/null
+++ b/src/google/protobuf/stubs/time.h
@@ -0,0 +1,75 @@
+// 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.
+#ifndef GOOGLE_PROTOBUF_STUBS_TIME_H_
+#define GOOGLE_PROTOBUF_STUBS_TIME_H_
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+struct DateTime {
+  int year;
+  int month;
+  int day;
+  int hour;
+  int minute;
+  int second;
+};
+
+// Converts a timestamp (seconds elapsed since 1970-01-01T00:00:00, could be
+// negative to represent time before 1970-01-01) to DateTime. Returns false
+// if the timestamp is not in the range between 0001-01-01T00:00:00 and
+// 9999-12-31T23:59:59.
+bool LIBPROTOBUF_EXPORT SecondsToDateTime(int64 seconds, DateTime* time);
+// Converts DateTime to a timestamp (seconds since 1970-01-01T00:00:00).
+// Returns false if the DateTime is not valid or is not in the valid range.
+bool LIBPROTOBUF_EXPORT DateTimeToSeconds(const DateTime& time, int64* seconds);
+
+void LIBPROTOBUF_EXPORT GetCurrentTime(int64* seconds, int32* nanos);
+
+// Formats a time string in RFC3339 fromat.
+//
+// For example, "2015-05-20T13:29:35.120Z". For nanos, 0, 3, 6 or 9 fractional
+// digits will be used depending on how many are required to represent the exact
+// value.
+//
+// Note that "nanos" must in the range of [0, 999999999].
+string LIBPROTOBUF_EXPORT FormatTime(int64 seconds, int32 nanos);
+// Parses a time string. This method accepts RFC3339 date/time string with UTC
+// offset. For example, "2015-05-20T13:29:35.120-08:00".
+bool LIBPROTOBUF_EXPORT ParseTime(const string& vaule, int64* seconds, int32* nanos);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_STUBS_TIME_H_
diff --git a/src/google/protobuf/stubs/time_test.cc b/src/google/protobuf/stubs/time_test.cc
new file mode 100644
index 0000000..59e9d1c
--- /dev/null
+++ b/src/google/protobuf/stubs/time_test.cc
@@ -0,0 +1,208 @@
+// 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.
+#include <google/protobuf/stubs/time.h>
+
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+static const int64 kSecondsPerDay = 3600 * 24;
+
+// For DateTime, tests will mostly focuse on the date part because that's
+// the tricky one.
+int64 CreateTimestamp(int year, int month, int day) {
+  DateTime time;
+  time.year = year;
+  time.month = month;
+  time.day = day;
+  time.hour = time.minute = time.second = 0;
+  int64 result;
+  GOOGLE_CHECK(DateTimeToSeconds(time, &result));
+  // Check that a roundtrip produces the same result.
+  GOOGLE_CHECK(SecondsToDateTime(result, &time));
+  GOOGLE_CHECK(time.year == year);
+  GOOGLE_CHECK(time.month == month);
+  GOOGLE_CHECK(time.day == day);
+  return result;
+}
+
+TEST(DateTimeTest, SimpleTime) {
+  DateTime time;
+  ASSERT_TRUE(SecondsToDateTime(1, &time));
+  EXPECT_EQ(1970, time.year);
+  EXPECT_EQ(1, time.month);
+  EXPECT_EQ(1, time.day);
+  EXPECT_EQ(0, time.hour);
+  EXPECT_EQ(0, time.minute);
+  EXPECT_EQ(1, time.second);
+  int64 seconds;
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  EXPECT_EQ(1, seconds);
+
+  ASSERT_TRUE(SecondsToDateTime(-1, &time));
+  EXPECT_EQ(1969, time.year);
+  EXPECT_EQ(12, time.month);
+  EXPECT_EQ(31, time.day);
+  EXPECT_EQ(23, time.hour);
+  EXPECT_EQ(59, time.minute);
+  EXPECT_EQ(59, time.second);
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  EXPECT_EQ(-1, seconds);
+
+  DateTime start, end;
+  start.year = 1;
+  start.month = 1;
+  start.day = 1;
+  start.hour = 0;
+  start.minute = 0;
+  start.second = 0;
+  end.year = 9999;
+  end.month = 12;
+  end.day = 31;
+  end.hour = 23;
+  end.minute = 59;
+  end.second = 59;
+  int64 start_time, end_time;
+  ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
+  ASSERT_TRUE(DateTimeToSeconds(end, &end_time));
+  EXPECT_EQ(315537897599LL, end_time - start_time);
+  ASSERT_TRUE(SecondsToDateTime(start_time, &time));
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  EXPECT_EQ(start_time, seconds);
+  ASSERT_TRUE(SecondsToDateTime(end_time, &time));
+  ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
+  EXPECT_EQ(end_time, seconds);
+}
+
+TEST(DateTimeTest, DayInMonths) {
+  // Check that month boundaries are handled correctly.
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 1, 1) - CreateTimestamp(2014, 12, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 2, 1) - CreateTimestamp(2015, 1, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 4, 1) - CreateTimestamp(2015, 3, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 5, 1) - CreateTimestamp(2015, 4, 30));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 6, 1) - CreateTimestamp(2015, 5, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 7, 1) - CreateTimestamp(2015, 6, 30));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 8, 1) - CreateTimestamp(2015, 7, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 9, 1) - CreateTimestamp(2015, 8, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 10, 1) - CreateTimestamp(2015, 9, 30));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 11, 1) - CreateTimestamp(2015, 10, 31));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 12, 1) - CreateTimestamp(2015, 11, 30));
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2016, 1, 1) - CreateTimestamp(2015, 12, 31));
+}
+
+TEST(DateTimeTest, LeapYear) {
+  // Non-leap year.
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
+  // Leap year.
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2016, 3, 1) - CreateTimestamp(2016, 2, 29));
+  // Non-leap year.
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2100, 3, 1) - CreateTimestamp(2100, 2, 28));
+  // Leap year.
+  EXPECT_EQ(kSecondsPerDay,
+            CreateTimestamp(2400, 3, 1) - CreateTimestamp(2400, 2, 29));
+}
+
+TEST(DateTimeTest, StringFormat) {
+  DateTime start, end;
+  start.year = 1;
+  start.month = 1;
+  start.day = 1;
+  start.hour = 0;
+  start.minute = 0;
+  start.second = 0;
+  end.year = 9999;
+  end.month = 12;
+  end.day = 31;
+  end.hour = 23;
+  end.minute = 59;
+  end.second = 59;
+  int64 start_time, end_time;
+  ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
+  ASSERT_TRUE(DateTimeToSeconds(end, &end_time));
+
+  EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(start_time, 0));
+  EXPECT_EQ("9999-12-31T23:59:59Z", FormatTime(end_time, 0));
+
+  // Make sure the nanoseconds part is formated correctly.
+  EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(0, 10000000));
+  EXPECT_EQ("1970-01-01T00:00:00.000010Z", FormatTime(0, 10000));
+  EXPECT_EQ("1970-01-01T00:00:00.000000010Z", FormatTime(0, 10));
+}
+
+TEST(DateTimeTest, ParseString) {
+  int64 seconds;
+  int32 nanos;
+  ASSERT_TRUE(ParseTime("0001-01-01T00:00:00Z", &seconds, &nanos));
+  EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(seconds, nanos));
+  ASSERT_TRUE(ParseTime("9999-12-31T23:59:59.999999999Z", &seconds, &nanos));
+  EXPECT_EQ("9999-12-31T23:59:59.999999999Z", FormatTime(seconds, nanos));
+
+  // Test time zone offsets.
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00-08:00", &seconds, &nanos));
+  EXPECT_EQ("1970-01-01T08:00:00Z", FormatTime(seconds, nanos));
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00+08:00", &seconds, &nanos));
+  EXPECT_EQ("1969-12-31T16:00:00Z", FormatTime(seconds, nanos));
+
+  // Test nanoseconds.
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.01Z", &seconds, &nanos));
+  EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(seconds, nanos));
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00001-08:00", &seconds, &nanos));
+  EXPECT_EQ("1970-01-01T08:00:00.000010Z", FormatTime(seconds, nanos));
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00000001+08:00", &seconds, &nanos));
+  EXPECT_EQ("1969-12-31T16:00:00.000000010Z", FormatTime(seconds, nanos));
+  // Fractional parts less than 1 nanosecond will be ignored.
+  ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.0123456789Z", &seconds, &nanos));
+  EXPECT_EQ("1970-01-01T00:00:00.012345678Z", FormatTime(seconds, nanos));
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h
index e41f5e6..0d8127e 100644
--- a/src/google/protobuf/stubs/type_traits.h
+++ b/src/google/protobuf/stubs/type_traits.h
@@ -35,6 +35,7 @@
 // any changes here, make sure that you're not breaking any platforms.
 //
 // Define a small subset of tr1 type traits. The traits we define are:
+//   enable_if
 //   is_integral
 //   is_floating_point
 //   is_pointer
@@ -58,6 +59,7 @@
 #ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_
 #define GOOGLE_PROTOBUF_TYPE_TRAITS_H_
 
+#include <cstddef>                  // for NULL
 #include <utility>                  // For pair
 
 #include <google/protobuf/stubs/template_util.h>  // For true_type and false_type
@@ -66,6 +68,24 @@
 namespace protobuf {
 namespace internal {
 
+template<typename B, typename D>
+struct is_base_of {
+  typedef char (&yes)[1];
+  typedef char (&no)[2];
+
+  // BEGIN GOOGLE LOCAL MODIFICATION -- check is a #define on Mac.
+  #undef check
+  // END GOOGLE LOCAL MODIFICATION
+
+  static yes check(const B*);
+  static no check(const void*);
+
+  enum {
+    value = sizeof(check(static_cast<const D*>(NULL))) == sizeof(yes),
+  };
+};
+
+template <bool cond, class T = void> struct enable_if;
 template <class T> struct is_integral;
 template <class T> struct is_floating_point;
 template <class T> struct is_pointer;
@@ -87,10 +107,17 @@
 template <class T> struct add_reference;
 template <class T> struct remove_pointer;
 template <class T, class U> struct is_same;
-#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
 template <class From, class To> struct is_convertible;
 #endif
 
+// enable_if, equivalent semantics to c++11 std::enable_if, specifically:
+//   "If B is true, the member typedef type shall equal T; otherwise, there
+//    shall be no member typedef type."
+// Specified by 20.9.7.6 [Other transformations]
+
+template<bool cond, class T> struct enable_if { typedef T type; };
+template<class T> struct enable_if<false, T> {};
 // is_integral is false except for the built-in integer types. A
 // cv-qualified type is integral if and only if the underlying type is.
 template <class T> struct is_integral : false_type { };
@@ -144,7 +171,7 @@
 
 #if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
 
-namespace internal {
+namespace type_traits_internal {
 
 template <class T> struct is_class_or_union {
   template <class U> static small_ tester(void (U::*)());
@@ -159,7 +186,7 @@
 
 template <class T> struct is_enum_impl<true, T> : false_type { };
 
-}  // namespace internal
+}  // namespace type_traits_internal
 
 // Specified by TR1 [4.5.1] primary type categories.
 
@@ -177,12 +204,12 @@
 // because it can't be used with some types (e.g. void or classes with
 // inaccessible conversion operators).
 template <class T> struct is_enum
-    : internal::is_enum_impl<
+    : type_traits_internal::is_enum_impl<
           is_same<T, void>::value ||
               is_integral<T>::value ||
               is_floating_point<T>::value ||
               is_reference<T>::value ||
-              internal::is_class_or_union<T>::value,
+              type_traits_internal::is_class_or_union<T>::value,
           T> { };
 
 template <class T> struct is_enum<const T> : is_enum<T> { };
@@ -299,8 +326,8 @@
 template<typename T> struct is_same<T, T> : public true_type { };
 
 // Specified by TR1 [4.6] Relationships between types
-#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
-namespace internal {
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
+namespace type_traits_internal {
 
 // This class is an implementation detail for is_convertible, and you
 // don't need to know how it works to use is_convertible. For those
@@ -316,16 +343,17 @@
   static small_ Test(To);
   static big_ Test(...);
   static From Create();
+  enum {
+    value = sizeof(Test(Create())) == sizeof(small_)
+  };
 };
-}  // namespace internal
+}  // namespace type_traits_internal
 
 // Inherits from true_type if From is convertible to To, false_type otherwise.
 template <typename From, typename To>
 struct is_convertible
     : integral_constant<bool,
-                        sizeof(internal::ConvertHelper<From, To>::Test(
-                                  internal::ConvertHelper<From, To>::Create()))
-                        == sizeof(small_)> {
+                        type_traits_internal::ConvertHelper<From, To>::value> {
 };
 #endif
 
diff --git a/src/google/protobuf/stubs/type_traits_unittest.cc b/src/google/protobuf/stubs/type_traits_unittest.cc
index 7a8cbfb..49c10ac 100644
--- a/src/google/protobuf/stubs/type_traits_unittest.cc
+++ b/src/google/protobuf/stubs/type_traits_unittest.cc
@@ -41,7 +41,10 @@
 #include <gtest/gtest.h>
 
 typedef int int32;
+// IBM AIX typedefs `int64` in `sys/inttypes.h`, included transitively above.
+#ifndef _AIX
 typedef long int64;
+#endif
 
 using std::string;
 using std::vector;
@@ -607,7 +610,7 @@
 }
 
 TEST(TypeTraitsTest, TestConvertible) {
-#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
+#if !(defined(__GNUC__) && __GNUC__ <= 3)
   EXPECT_TRUE((is_convertible<int, int>::value));
   EXPECT_TRUE((is_convertible<int, long>::value));
   EXPECT_TRUE((is_convertible<long, int>::value));
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index be1c90e..07aa1d7 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -42,6 +42,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index d449c00..1c13a1a 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -65,7 +65,7 @@
   static void SetOneof2(unittest::TestOneof2* message);
 
   // Use the repeated versions of the set_*() accessors to modify all the
-  // repeated fields of the messsage (which should already have been
+  // repeated fields of the message (which should already have been
   // initialized with Set*Fields()).  Set*Fields() itself only tests
   // the add_*() accessors.
   static void ModifyRepeatedFields(unittest::TestAllTypes* message);
diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc
index 88eca0a..388c0cb 100644
--- a/src/google/protobuf/test_util_lite.cc
+++ b/src/google/protobuf/test_util_lite.cc
@@ -33,6 +33,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/test_util_lite.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
 
diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h
index f250c93..47a2269 100644
--- a/src/google/protobuf/test_util_lite.h
+++ b/src/google/protobuf/test_util_lite.h
@@ -52,7 +52,7 @@
   static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message);
 
   // Use the repeated versions of the set_*() accessors to modify all the
-  // repeated fields of the messsage (which should already have been
+  // repeated fields of the message (which should already have been
   // initialized with Set*Fields()).  Set*Fields() itself only tests
   // the add_*() accessors.
   static void ModifyRepeatedFields(unittest::TestAllTypesLite* message);
diff --git a/src/google/protobuf/testdata/golden_message_proto3 b/src/google/protobuf/testdata/golden_message_proto3
new file mode 100644
index 0000000..bd646a0
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_proto3
Binary files differ
diff --git a/src/google/protobuf/testdata/map_test_data.txt b/src/google/protobuf/testdata/map_test_data.txt
new file mode 100644
index 0000000..bc27232
--- /dev/null
+++ b/src/google/protobuf/testdata/map_test_data.txt
@@ -0,0 +1,140 @@
+map_int32_int32 {
+  key: 0
+  value: 0
+}
+map_int32_int32 {
+  key: 1
+  value: 1
+}
+map_int64_int64 {
+  key: 0
+  value: 0
+}
+map_int64_int64 {
+  key: 1
+  value: 1
+}
+map_uint32_uint32 {
+  key: 0
+  value: 0
+}
+map_uint32_uint32 {
+  key: 1
+  value: 1
+}
+map_uint64_uint64 {
+  key: 0
+  value: 0
+}
+map_uint64_uint64 {
+  key: 1
+  value: 1
+}
+map_sint32_sint32 {
+  key: 0
+  value: 0
+}
+map_sint32_sint32 {
+  key: 1
+  value: 1
+}
+map_sint64_sint64 {
+  key: 0
+  value: 0
+}
+map_sint64_sint64 {
+  key: 1
+  value: 1
+}
+map_fixed32_fixed32 {
+  key: 0
+  value: 0
+}
+map_fixed32_fixed32 {
+  key: 1
+  value: 1
+}
+map_fixed64_fixed64 {
+  key: 0
+  value: 0
+}
+map_fixed64_fixed64 {
+  key: 1
+  value: 1
+}
+map_sfixed32_sfixed32 {
+  key: 0
+  value: 0
+}
+map_sfixed32_sfixed32 {
+  key: 1
+  value: 1
+}
+map_sfixed64_sfixed64 {
+  key: 0
+  value: 0
+}
+map_sfixed64_sfixed64 {
+  key: 1
+  value: 1
+}
+map_int32_float {
+  key: 0
+  value: 0
+}
+map_int32_float {
+  key: 1
+  value: 1
+}
+map_int32_double {
+  key: 0
+  value: 0
+}
+map_int32_double {
+  key: 1
+  value: 1
+}
+map_bool_bool {
+  key: false
+  value: false
+}
+map_bool_bool {
+  key: true
+  value: true
+}
+map_string_string {
+  key: "0"
+  value: "0"
+}
+map_string_string {
+  key: "1"
+  value: "1"
+}
+map_int32_bytes {
+  key: 0
+  value: "0"
+}
+map_int32_bytes {
+  key: 1
+  value: "1"
+}
+map_int32_enum {
+  key: 0
+  value: MAP_ENUM_BAR
+}
+map_int32_enum {
+  key: 1
+  value: MAP_ENUM_BAZ
+}
+map_int32_foreign_message {
+  key: 0
+  value {
+    c: 0
+  }
+}
+map_int32_foreign_message {
+  key: 1
+  value {
+    c: 1
+  }
+}
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
index 20e01a1..3d07b12 100644
--- a/src/google/protobuf/testing/file.cc
+++ b/src/google/protobuf/testing/file.cc
@@ -133,6 +133,8 @@
 
 void File::DeleteRecursively(const string& name,
                              void* dummy1, void* dummy2) {
+  if (name.empty()) return;
+
   // We don't care too much about error checking here since this is only used
   // in tests to delete temporary directories that are under /tmp anyway.
 
@@ -190,5 +192,9 @@
 #endif
 }
 
+bool File::ChangeWorkingDirectory(const string& new_working_directory) {
+  return chdir(new_working_directory.c_str()) == 0;
+}
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/testing/file.h b/src/google/protobuf/testing/file.h
index d2aeabf..2f63f80 100644
--- a/src/google/protobuf/testing/file.h
+++ b/src/google/protobuf/testing/file.h
@@ -77,6 +77,9 @@
   static void DeleteRecursively(const string& name,
                                 void* dummy1, void* dummy2);
 
+  // Change working directory to given directory.
+  static bool ChangeWorkingDirectory(const string& new_working_directory);
+
   static bool GetContents(
       const string& name, string* output, bool /*is_default*/) {
     return ReadFileToString(name, output);
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index d72fa5c..2b9cdde 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -65,7 +65,15 @@
 #endif
 
 string TestSourceDir() {
-#ifdef _MSC_VER
+#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+#ifndef _MSC_VER
+  // automake sets the "srcdir" environment variable.
+  char* result = getenv("srcdir");
+  if (result != NULL) {
+    return result;
+  }
+#endif  // _MSC_VER
+
   // Look for the "src" directory.
   string prefix = ".";
 
@@ -79,20 +87,20 @@
   }
   return prefix + "/src";
 #else
-  // automake sets the "srcdir" environment variable.
-  char* result = getenv("srcdir");
-  if (result == NULL) {
-    // Otherwise, the test must be run from the source directory.
-    return ".";
-  } else {
-    return result;
-  }
-#endif
+  return "third_party/protobuf/src";
+#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
 }
 
 namespace {
 
 string GetTemporaryDirectoryName() {
+  // Tests run under Bazel "should not" use /tmp. Bazel sets this environment
+  // variable for tests to use instead.
+  char *from_environment = getenv("TEST_TMPDIR");
+  if (from_environment != NULL && from_environment[0] != '\0') {
+    return string(from_environment) + "/protobuf_tmpdir";
+  }
+
   // tmpnam() is generally not considered safe but we're only using it for
   // testing.  We cannot use tmpfile() or mkstemp() since we're creating a
   // directory.
@@ -104,6 +112,10 @@
   if (HasPrefixString(result, "\\")) {
     result.erase(0, 1);
   }
+  // The Win32 API accepts forward slashes as a path delimiter even though
+  // backslashes are standard.  Let's avoid confusion and use only forward
+  // slashes.
+  result = StringReplace(result, "\\", "/", true);
 #endif  // _WIN32
   return result;
 }
diff --git a/src/google/protobuf/testing/zcgunzip.cc b/src/google/protobuf/testing/zcgunzip.cc
index daf74ff..76f8cfe 100644
--- a/src/google/protobuf/testing/zcgunzip.cc
+++ b/src/google/protobuf/testing/zcgunzip.cc
@@ -38,13 +38,20 @@
 // Reads gzip stream on standard input and writes decompressed data to standard
 // output.
 
-#include "config.h"
-
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 
+#ifdef _WIN32
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#endif
+
 #include <google/protobuf/io/gzip_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
diff --git a/src/google/protobuf/testing/zcgzip.cc b/src/google/protobuf/testing/zcgzip.cc
index a410199..992ddc6 100644
--- a/src/google/protobuf/testing/zcgzip.cc
+++ b/src/google/protobuf/testing/zcgzip.cc
@@ -38,12 +38,19 @@
 // Reads data on standard input and writes compressed gzip stream to standard
 // output.
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 
+#ifdef _WIN32
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#endif
+
 #include <google/protobuf/io/gzip_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 84cdbb5..c0dfd53 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -43,13 +43,18 @@
 #include <google/protobuf/text_format.h>
 
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
@@ -69,12 +74,27 @@
           (str[1] >= '0' && str[1] < '8'));
 }
 
+inline bool GetAnyFieldDescriptors(const Message& message,
+                                   const FieldDescriptor** type_url_field,
+                                   const FieldDescriptor** value_field) {
+    const Descriptor* descriptor = message.GetDescriptor();
+    *type_url_field = descriptor->FindFieldByNumber(1);
+    *value_field = descriptor->FindFieldByNumber(2);
+    return (*type_url_field != NULL &&
+            (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+            *value_field != NULL &&
+            (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
 }  // namespace
 
 string Message::DebugString() const {
   string debug_string;
 
-  TextFormat::PrintToString(*this, &debug_string);
+  TextFormat::Printer printer;
+  printer.SetExpandAny(true);
+
+  printer.PrintToString(*this, &debug_string);
 
   return debug_string;
 }
@@ -84,6 +104,7 @@
 
   TextFormat::Printer printer;
   printer.SetSingleLineMode(true);
+  printer.SetExpandAny(true);
 
   printer.PrintToString(*this, &debug_string);
   // Single line mode currently might have an extra space at the end.
@@ -100,6 +121,7 @@
 
   TextFormat::Printer printer;
   printer.SetUseUtf8StringEscaping(true);
+  printer.SetExpandAny(true);
 
   printer.PrintToString(*this, &debug_string);
 
@@ -319,17 +341,27 @@
                   message);
   }
 
-  // Consumes the specified message with the given starting delimeter.
-  // This method checks to see that the end delimeter at the conclusion of
-  // the consumption matches the starting delimeter passed in here.
-  bool ConsumeMessage(Message* message, const string delimeter) {
+  // Consumes the specified message with the given starting delimiter.
+  // This method checks to see that the end delimiter at the conclusion of
+  // the consumption matches the starting delimiter passed in here.
+  bool ConsumeMessage(Message* message, const string delimiter) {
     while (!LookingAt(">") &&  !LookingAt("}")) {
       DO(ConsumeField(message));
     }
 
-    // Confirm that we have a valid ending delimeter.
-    DO(Consume(delimeter));
+    // Confirm that we have a valid ending delimiter.
+    DO(Consume(delimiter));
+    return true;
+  }
 
+  // Consume either "<" or "{".
+  bool ConsumeMessageDelimiter(string* delimiter) {
+    if (TryConsume("<")) {
+      *delimiter = ">";
+    } else {
+      DO(Consume("{"));
+      *delimiter = "}";
+    }
     return true;
   }
 
@@ -346,15 +378,28 @@
     int start_line = tokenizer_.current().line;
     int start_column = tokenizer_.current().column;
 
+    const FieldDescriptor* any_type_url_field;
+    const FieldDescriptor* any_value_field;
+    if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field,
+                                         &any_value_field) &&
+        TryConsume("[")) {
+      string full_type_name, prefix;
+      DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
+      DO(Consume("]"));
+      TryConsume(":");  // ':' is optional between message labels and values.
+      string serialized_value;
+      DO(ConsumeAnyValue(full_type_name,
+                         message->GetDescriptor()->file()->pool(),
+                         &serialized_value));
+      reflection->SetString(
+          message, any_type_url_field,
+          string(prefix + full_type_name));
+      reflection->SetString(message, any_value_field, serialized_value);
+      return true;
+    }
     if (TryConsume("[")) {
       // Extension.
-      DO(ConsumeIdentifier(&field_name));
-      while (TryConsume(".")) {
-        string part;
-        DO(ConsumeIdentifier(&part));
-        field_name += ".";
-        field_name += part;
-      }
+      DO(ConsumeFullTypeName(&field_name));
       DO(Consume("]"));
 
       field = (finder_ != NULL
@@ -428,7 +473,7 @@
       // Try to guess the type of this field.
       // If this field is not a message, there should be a ":" between the
       // field name and the field value and also the field value should not
-      // start with "{" or "<" which indicates the begining of a message body.
+      // start with "{" or "<" which indicates the beginning of a message body.
       // If there is no ":" or there is a "{" or "<" after ":", this field has
       // to be a message or the input is ill-formed.
       if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
@@ -511,13 +556,7 @@
     string field_name;
     if (TryConsume("[")) {
       // Extension name.
-      DO(ConsumeIdentifier(&field_name));
-      while (TryConsume(".")) {
-        string part;
-        DO(ConsumeIdentifier(&part));
-        field_name += ".";
-        field_name += part;
-      }
+      DO(ConsumeFullTypeName(&field_name));
       DO(Consume("]"));
     } else {
       DO(ConsumeIdentifier(&field_name));
@@ -526,7 +565,7 @@
     // Try to guess the type of this field.
     // If this field is not a message, there should be a ":" between the
     // field name and the field value and also the field value should not
-    // start with "{" or "<" which indicates the begining of a message body.
+    // start with "{" or "<" which indicates the beginning of a message body.
     // If there is no ":" or there is a "{" or "<" after ":", this field has
     // to be a message or the input is ill-formed.
     if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
@@ -551,19 +590,13 @@
       parse_info_tree_ = CreateNested(parent, field);
     }
 
-    string delimeter;
-    if (TryConsume("<")) {
-      delimeter = ">";
-    } else {
-      DO(Consume("{"));
-      delimeter = "}";
-    }
-
+    string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
     if (field->is_repeated()) {
-      DO(ConsumeMessage(reflection->AddMessage(message, field), delimeter));
+      DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter));
     } else {
       DO(ConsumeMessage(reflection->MutableMessage(message, field),
-                        delimeter));
+                        delimiter));
     }
 
     // Reset the parse information tree.
@@ -571,20 +604,15 @@
     return true;
   }
 
-  // Skips the whole body of a message including the begining delimeter and
-  // the ending delimeter.
+  // Skips the whole body of a message including the beginning delimiter and
+  // the ending delimiter.
   bool SkipFieldMessage() {
-    string delimeter;
-    if (TryConsume("<")) {
-      delimeter = ">";
-    } else {
-      DO(Consume("{"));
-      delimeter = "}";
-    }
+    string delimiter;
+    DO(ConsumeMessageDelimiter(&delimiter));
     while (!LookingAt(">") &&  !LookingAt("}")) {
       DO(SkipField());
     }
-    DO(Consume(delimeter));
+    DO(Consume(delimiter));
     return true;
   }
 
@@ -634,7 +662,7 @@
       case FieldDescriptor::CPPTYPE_FLOAT: {
         double value;
         DO(ConsumeDouble(&value));
-        SET_FIELD(Float, static_cast<float>(value));
+        SET_FIELD(Float, io::SafeDoubleToFloat(value));
         break;
       }
 
@@ -807,6 +835,18 @@
     return false;
   }
 
+  // Consume a string of form "<id1>.<id2>....<idN>".
+  bool ConsumeFullTypeName(string* name) {
+    DO(ConsumeIdentifier(name));
+    while (TryConsume(".")) {
+      string part;
+      DO(ConsumeIdentifier(&part));
+      *name += ".";
+      *name += part;
+    }
+    return true;
+  }
+
   // Consumes a string and saves its value in the text parameter.
   // Returns false if the token is not of type STRING.
   bool ConsumeString(string* text) {
@@ -946,6 +986,57 @@
     return true;
   }
 
+  // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
+  // or "type.googleprod.com/full.type.Name"
+  bool ConsumeAnyTypeUrl(string* full_type_name, string* prefix) {
+    // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
+    // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
+    string url1, url2, url3;
+    DO(ConsumeIdentifier(&url1));  // type
+    DO(Consume("."));
+    DO(ConsumeIdentifier(&url2));  // googleapis
+    DO(Consume("."));
+    DO(ConsumeIdentifier(&url3));  // com
+    DO(Consume("/"));
+    DO(ConsumeFullTypeName(full_type_name));
+
+    *prefix = url1 + "." + url2 + "." + url3 + "/";
+    if (*prefix != internal::kTypeGoogleApisComPrefix &&
+        *prefix != internal::kTypeGoogleProdComPrefix) {
+      ReportError("TextFormat::Parser for Any supports only "
+                  "type.googleapis.com and type.googleprod.com, "
+                  "but found \"" + *prefix + "\"");
+      return false;
+    }
+    return true;
+  }
+
+  // A helper function for reconstructing Any::value. Consumes a text of
+  // full_type_name, then serializes it into serialized_value. "pool" is used to
+  // look up and create a temporary object with full_type_name.
+  bool ConsumeAnyValue(const string& full_type_name, const DescriptorPool* pool,
+                       string* serialized_value) {
+    const Descriptor* value_descriptor =
+        pool->FindMessageTypeByName(full_type_name);
+    if (value_descriptor == NULL) {
+      ReportError("Could not find type \"" + full_type_name +
+                  "\" stored in google.protobuf.Any.");
+      return false;
+    }
+    DynamicMessageFactory factory;
+    const Message* value_prototype = factory.GetPrototype(value_descriptor);
+    if (value_prototype == NULL) {
+      return false;
+    }
+    google::protobuf::scoped_ptr<Message> value(value_prototype->New());
+    string sub_delimiter;
+    DO(ConsumeMessageDelimiter(&sub_delimiter));
+    DO(ConsumeMessage(value.get(), sub_delimiter));
+
+    value->AppendToString(serialized_value);
+    return true;
+  }
+
   // Consumes a token and confirms that it matches that specified in the
   // value parameter. Returns false if the token found does not match that
   // which was specified.
@@ -1067,10 +1158,10 @@
   }
 
   // Print text to the output stream.
-  void Print(const char* text, int size) {
-    int pos = 0;  // The number of bytes we've written so far.
+  void Print(const char* text, size_t size) {
+    size_t pos = 0;  // The number of bytes we've written so far.
 
-    for (int i = 0; i < size; i++) {
+    for (size_t i = 0; i < size; i++) {
       if (text[i] == '\n') {
         // Saw newline.  If there is more text, we may need to insert an indent
         // here.  So, write what we have so far, including the '\n'.
@@ -1095,7 +1186,7 @@
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
 
-  void Write(const char* data, int size) {
+  void Write(const char* data, size_t size) {
     if (failed_) return;
     if (size == 0) return;
 
@@ -1272,7 +1363,10 @@
   return SimpleDtoa(val);
 }
 string TextFormat::FieldValuePrinter::PrintString(const string& val) const {
-  return StrCat("\"", CEscape(val), "\"");
+  string printed("\"");
+  CEscapeAndAppend(val, &printed);
+  printed.push_back('\"');
+  return printed;
 }
 string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const {
   return PrintString(val);
@@ -1337,7 +1431,9 @@
     use_field_number_(false),
     use_short_repeated_primitives_(false),
     hide_unknown_fields_(false),
-    print_message_fields_in_index_order_(false) {
+    print_message_fields_in_index_order_(false),
+    expand_any_(false),
+    truncate_string_field_longer_than_(0LL) {
   SetUseUtf8StringEscaping(false);
 }
 
@@ -1359,9 +1455,8 @@
 bool TextFormat::Printer::RegisterFieldValuePrinter(
     const FieldDescriptor* field,
     const FieldValuePrinter* printer) {
-  return field != NULL
-      && printer != NULL
-      && custom_printers_.insert(make_pair(field, printer)).second;
+  return field != NULL && printer != NULL &&
+         custom_printers_.insert(std::make_pair(field, printer)).second;
 }
 
 bool TextFormat::Printer::PrintToString(const Message& message,
@@ -1413,15 +1508,67 @@
     return left->index() < right->index();
   }
 };
+
 }  // namespace
 
+bool TextFormat::Printer::PrintAny(const Message& message,
+                                   TextGenerator& generator) const {
+  const FieldDescriptor* type_url_field;
+  const FieldDescriptor* value_field;
+  if (!internal::GetAnyFieldDescriptors(message, &type_url_field,
+                                        &value_field)) {
+    return false;
+  }
+
+  const Reflection* reflection = message.GetReflection();
+
+  // Extract the full type name from the type_url field.
+  const string& type_url = reflection->GetString(message, type_url_field);
+  string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+    return false;
+  }
+
+  // Print the "value" in text.
+  const google::protobuf::Descriptor* value_descriptor =
+      message.GetDescriptor()->file()->pool()->FindMessageTypeByName(
+          full_type_name);
+  if (value_descriptor == NULL) {
+    GOOGLE_LOG(WARNING) << "Proto type " << type_url << " not found";
+    return false;
+  }
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<google::protobuf::Message> value_message(
+      factory.GetPrototype(value_descriptor)->New());
+  string serialized_value = reflection->GetString(message, value_field);
+  if (!value_message->ParseFromString(serialized_value)) {
+    GOOGLE_LOG(WARNING) << type_url << ": failed to parse contents";
+    return false;
+  }
+  generator.Print(StrCat("[", type_url, "]"));
+  const FieldValuePrinter* printer = FindWithDefault(
+      custom_printers_, value_field, default_field_value_printer_.get());
+  generator.Print(
+      printer->PrintMessageStart(message, -1, 0, single_line_mode_));
+  generator.Indent();
+  Print(*value_message, generator);
+  generator.Outdent();
+  generator.Print(printer->PrintMessageEnd(message, -1, 0, single_line_mode_));
+  return true;
+}
+
 void TextFormat::Printer::Print(const Message& message,
                                 TextGenerator& generator) const {
+  const Descriptor* descriptor = message.GetDescriptor();
   const Reflection* reflection = message.GetReflection();
+  if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
+      PrintAny(message, generator)) {
+    return;
+  }
   vector<const FieldDescriptor*> fields;
   reflection->ListFields(message, &fields);
   if (print_message_fields_in_index_order_) {
-    sort(fields.begin(), fields.end(), FieldIndexSorter());
+    std::sort(fields.begin(), fields.end(), FieldIndexSorter());
   }
   for (int i = 0; i < fields.size(); i++) {
     PrintField(message, reflection, fields[i], generator);
@@ -1446,6 +1593,54 @@
   PrintFieldValue(message, message.GetReflection(), field, index, generator);
 }
 
+class MapEntryMessageComparator {
+ public:
+  explicit MapEntryMessageComparator(const Descriptor* descriptor)
+      : field_(descriptor->field(0)) {}
+
+  bool operator()(const Message* a, const Message* b) {
+    const Reflection* reflection = a->GetReflection();
+    switch (field_->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_BOOL: {
+          bool first = reflection->GetBool(*a, field_);
+          bool second = reflection->GetBool(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT32: {
+          int32 first = reflection->GetInt32(*a, field_);
+          int32 second = reflection->GetInt32(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+          int64 first = reflection->GetInt64(*a, field_);
+          int64 second = reflection->GetInt64(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+          uint32 first = reflection->GetUInt32(*a, field_);
+          uint32 second = reflection->GetUInt32(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+          uint64 first = reflection->GetUInt64(*a, field_);
+          uint64 second = reflection->GetUInt64(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+          string first = reflection->GetString(*a, field_);
+          string second = reflection->GetString(*b, field_);
+          return first < second;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+        return true;
+    }
+  }
+
+ private:
+  const FieldDescriptor* field_;
+};
+
 void TextFormat::Printer::PrintField(const Message& message,
                                      const Reflection* reflection,
                                      const FieldDescriptor* field,
@@ -1466,6 +1661,21 @@
     count = 1;
   }
 
+  std::vector<const Message*> sorted_map_field;
+  if (field->is_map()) {
+    const RepeatedPtrField<Message>& map_field =
+        reflection->GetRepeatedPtrField<Message>(message, field);
+    for (RepeatedPtrField<Message>::const_pointer_iterator it =
+             map_field.pointer_begin();
+         it != map_field.pointer_end(); ++it) {
+      sorted_map_field.push_back(*it);
+    }
+
+    MapEntryMessageComparator comparator(field->message_type());
+    std::stable_sort(sorted_map_field.begin(), sorted_map_field.end(),
+                     comparator);
+  }
+
   for (int j = 0; j < count; ++j) {
     const int field_index = field->is_repeated() ? j : -1;
 
@@ -1475,8 +1685,10 @@
       const FieldValuePrinter* printer = FindWithDefault(
           custom_printers_, field, default_field_value_printer_.get());
       const Message& sub_message =
-              field->is_repeated()
-              ? reflection->GetRepeatedMessage(message, field, j)
+          field->is_repeated()
+              ? (field->is_map()
+                     ? *sorted_map_field[j]
+                     : reflection->GetRepeatedMessage(message, field, j))
               : reflection->GetMessage(message, field);
       generator.Print(
           printer->PrintMessageStart(
@@ -1573,20 +1785,41 @@
           ? reflection->GetRepeatedStringReference(
               message, field, index, &scratch)
           : reflection->GetStringReference(message, field, &scratch);
+      const string* value_to_print = &value;
+      string truncated_value;
+      if (truncate_string_field_longer_than_ > 0 &&
+          truncate_string_field_longer_than_ < value.size()) {
+        truncated_value = value.substr(0, truncate_string_field_longer_than_) +
+                          "...<truncated>...";
+        value_to_print = &truncated_value;
+      }
       if (field->type() == FieldDescriptor::TYPE_STRING) {
-        generator.Print(printer->PrintString(value));
+        generator.Print(printer->PrintString(*value_to_print));
       } else {
         GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
-        generator.Print(printer->PrintBytes(value));
+        generator.Print(printer->PrintBytes(*value_to_print));
       }
       break;
     }
 
     case FieldDescriptor::CPPTYPE_ENUM: {
-      const EnumValueDescriptor *enum_val = field->is_repeated()
-          ? reflection->GetRepeatedEnum(message, field, index)
-          : reflection->GetEnum(message, field);
-      generator.Print(printer->PrintEnum(enum_val->number(), enum_val->name()));
+      int enum_value = field->is_repeated()
+          ? reflection->GetRepeatedEnumValue(message, field, index)
+          : reflection->GetEnumValue(message, field);
+      const EnumValueDescriptor* enum_desc =
+          field->enum_type()->FindValueByNumber(enum_value);
+      if (enum_desc != NULL) {
+        generator.Print(printer->PrintEnum(enum_value, enum_desc->name()));
+      } else {
+        // Ordinarily, enum_desc should not be null, because proto2 has the
+        // invariant that set enum field values must be in-range, but with the
+        // new integer-based API for enums (or the RepeatedField<int> loophole),
+        // it is possible for the user to force an unknown integer value.  So we
+        // simply use the integer value itself as the enum value name in this
+        // case.
+        generator.Print(printer->PrintEnum(enum_value,
+                                           StringPrintf("%d", enum_value)));
+      }
       break;
     }
 
@@ -1667,8 +1900,8 @@
       case UnknownField::TYPE_FIXED32: {
         generator.Print(field_number);
         generator.Print(": 0x");
-        char buffer[kFastToBufferSize];
-        generator.Print(FastHex32ToBuffer(field.fixed32(), buffer));
+        generator.Print(
+            StrCat(strings::Hex(field.fixed32(), strings::ZERO_PAD_8)));
         if (single_line_mode_) {
           generator.Print(" ");
         } else {
@@ -1679,8 +1912,8 @@
       case UnknownField::TYPE_FIXED64: {
         generator.Print(field_number);
         generator.Print(": 0x");
-        char buffer[kFastToBufferSize];
-        generator.Print(FastHex64ToBuffer(field.fixed64(), buffer));
+        generator.Print(
+            StrCat(strings::Hex(field.fixed64(), strings::ZERO_PAD_16)));
         if (single_line_mode_) {
           generator.Print(" ");
         } else {
@@ -1711,14 +1944,10 @@
         } else {
           // This field is not parseable as a Message.
           // So it is probably just a plain string.
-          generator.Print(": \"");
-          generator.Print(CEscape(value));
-          generator.Print("\"");
-          if (single_line_mode_) {
-            generator.Print(" ");
-          } else {
-            generator.Print("\n");
-          }
+          string printed(": \"");
+          CEscapeAndAppend(value, &printed);
+          printed.append(single_line_mode_ ? "\" " : "\"\n");
+          generator.Print(printed);
         }
         break;
       }
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 2954941..ef3d4a8 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -40,6 +40,9 @@
 
 #include <map>
 #include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <vector>
 
@@ -205,6 +208,29 @@
           print_message_fields_in_index_order;
     }
 
+    // If expand==true, expand google.protobuf.Any payloads. The output
+    // will be of form
+    //    [type_url] { <value_printed_in_text> }
+    //
+    // If expand==false, print Any using the default printer. The output will
+    // look like
+    //    type_url: "<type_url>"  value: "serialized_content"
+    void SetExpandAny(bool expand) {
+      expand_any_ = expand;
+    }
+
+    // If non-zero, we truncate all string fields that are  longer than this
+    // threshold.  This is useful when the proto message has very long strings,
+    // e.g., dump of encoded image file.
+    //
+    // NOTE(hfgong):  Setting a non-zero value breaks round-trip safe
+    // property of TextFormat::Printer.  That is, from the printed message, we
+    // cannot fully recover the original string field any more.
+    void SetTruncateStringFieldLongerThan(
+        const int64 truncate_string_field_longer_than) {
+      truncate_string_field_longer_than_ = truncate_string_field_longer_than;
+    }
+
     // Register a custom field-specific FieldValuePrinter for fields
     // with a particular FieldDescriptor.
     // Returns "true" if the registration succeeded, or "false", if there is
@@ -256,6 +282,8 @@
     void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
                             TextGenerator& generator) const;
 
+    bool PrintAny(const Message& message, TextGenerator& generator) const;
+
     int initial_indent_level_;
 
     bool single_line_mode_;
@@ -268,15 +296,31 @@
 
     bool print_message_fields_in_index_order_;
 
-    scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
+    bool expand_any_;
+
+    int64 truncate_string_field_longer_than_;
+
+    google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
     typedef map<const FieldDescriptor*,
                 const FieldValuePrinter*> CustomPrinterMap;
     CustomPrinterMap custom_printers_;
   };
 
   // Parses a text-format protocol message from the given input stream to
-  // the given message object.  This function parses the format written
-  // by Print().
+  // the given message object. This function parses the human-readable format
+  // written by Print(). Returns true on success. The message is cleared first,
+  // even if the function fails -- See Merge() to avoid this behavior.
+  //
+  // Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
+  //
+  // One use for this function is parsing handwritten strings in test code.
+  // Another use is to parse the output from google::protobuf::Message::DebugString()
+  // (or ShortDebugString()), because these functions output using
+  // google::protobuf::TextFormat::Print().
+  //
+  // If you would like to read a protocol buffer serialized in the
+  // (non-human-readable) binary wire format, see
+  // google::protobuf::MessageLite::ParseFromString().
   static bool Parse(io::ZeroCopyInputStream* input, Message* output);
   // Like Parse(), but reads directly from a string.
   static bool ParseFromString(const string& input, Message* output);
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 5573268..58aa3f8 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -32,23 +32,33 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/text_format.h>
+
 #include <math.h>
 #include <stdlib.h>
 #include <limits>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest_mset.pb.h>
-#include <google/protobuf/test_util.h>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/testing/file.h>
-#include <google/protobuf/testing/googletest.h>
-#include <gtest/gtest.h>
+#include <google/protobuf/unittest_mset_wire_format.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/mathlimits.h>
+
 
 namespace google {
 namespace protobuf {
@@ -56,11 +66,6 @@
 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
 namespace text_format_unittest {
 
-inline bool IsNaN(double value) {
-  // NaN is never equal to anything, even itself.
-  return value != value;
-}
-
 // A basic string with different escapable characters for testing.
 const string kEscapeTestString =
   "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
@@ -263,7 +268,7 @@
 }
 
 TEST_F(TextFormatTest, PrintUnknownFieldsHidden) {
-  // Test printing of unknown fields in a message when supressed.
+  // Test printing of unknown fields in a message when suppressed.
 
   unittest::OneString message;
   message.set_data("data");
@@ -451,7 +456,7 @@
 class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
   virtual string PrintInt32(int32 v) const {
-    return StrCat(FieldValuePrinter::PrintInt32(v), "  # x", ToHex(v));
+    return StrCat(FieldValuePrinter::PrintInt32(v), "  # x", strings::Hex(v));
   }
 
   virtual string PrintMessageStart(const Message& message,
@@ -586,7 +591,7 @@
   // Compare.
   EXPECT_EQ("foobar", proto_.optional_string());
 
-  // Create a parse string with multiple parts on seperate lines.
+  // Create a parse string with multiple parts on separate lines.
   parse_string = "optional_string: \"foo\"\n"
                  "\"bar\"\n";
 
@@ -897,8 +902,8 @@
   EXPECT_EQ(message.repeated_double(8), numeric_limits<double>::infinity());
   EXPECT_EQ(message.repeated_double(9), -numeric_limits<double>::infinity());
   EXPECT_EQ(message.repeated_double(10), -numeric_limits<double>::infinity());
-  EXPECT_TRUE(IsNaN(message.repeated_double(11)));
-  EXPECT_TRUE(IsNaN(message.repeated_double(12)));
+  EXPECT_TRUE(MathLimits<double>::IsNaN(message.repeated_double(11)));
+  EXPECT_TRUE(MathLimits<double>::IsNaN(message.repeated_double(12)));
 
   // Note:  Since these string literals have \0's in them, we must explicitly
   //   pass their sizes to string's constructor.
@@ -932,7 +937,7 @@
  protected:
   void ExpectFailure(const string& input, const string& message, int line,
                      int col) {
-    scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
+    google::protobuf::scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
     ExpectFailure(input, message, line, col, proto.get());
   }
 
@@ -993,7 +998,7 @@
 };
 
 TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
-  scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
   const Descriptor* d = message->GetDescriptor();
 
   string stringData =
@@ -1058,7 +1063,7 @@
 }
 
 TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
-  scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
   const Descriptor* d = message->GetDescriptor();
 
 #define EXPECT_FIELD(name, value, valuestring) \
@@ -1324,12 +1329,12 @@
       "Expected \":\", found \"{\".", 1, 22);
 }
 
-TEST_F(TextFormatParserTest, MessageDelimeters) {
-  // Non-matching delimeters.
+TEST_F(TextFormatParserTest, MessageDelimiters) {
+  // Non-matching delimiters.
   ExpectFailure("OptionalGroup <\n \n}\n", "Expected \">\", found \"}\".",
                 3, 1);
 
-  // Invalid delimeters.
+  // Invalid delimiters.
   ExpectFailure("OptionalGroup [\n \n]\n", "Expected \"{\", found \"[\".",
                 1, 15);
 
@@ -1340,7 +1345,7 @@
 }
 
 TEST_F(TextFormatParserTest, UnknownExtension) {
-  // Non-matching delimeters.
+  // Non-matching delimiters.
   ExpectFailure("[blahblah]: 123",
                 "Extension \"blahblah\" is not defined or is not an "
                 "extension of \"protobuf_unittest.TestAllTypes\".",
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
new file mode 100644
index 0000000..7cdf509
--- /dev/null
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -0,0 +1,451 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/timestamp.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Timestamp_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Timestamp_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/timestamp.proto");
+  GOOGLE_CHECK(file != NULL);
+  Timestamp_descriptor_ = file->message_type(0);
+  static const int Timestamp_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Timestamp, seconds_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Timestamp, nanos_),
+  };
+  Timestamp_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Timestamp_descriptor_,
+      Timestamp::default_instance_,
+      Timestamp_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Timestamp),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Timestamp, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Timestamp, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Timestamp_descriptor_, &Timestamp::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2ftimestamp_2eproto() {
+  delete Timestamp::default_instance_;
+  delete Timestamp_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\037google/protobuf/timestamp.proto\022\017googl"
+    "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
+    "\022\r\n\005nanos\030\002 \001(\005B\201\001\n\023com.google.protobufB"
+    "\016TimestampProtoP\001Z+github.com/golang/pro"
+    "tobuf/ptypes/timestamp\240\001\001\370\001\001\242\002\003GPB\252\002\036Goo"
+    "gle.Protobuf.WellKnownTypesb\006proto3", 235);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/timestamp.proto", &protobuf_RegisterTypes);
+  Timestamp::default_instance_ = new Timestamp();
+  Timestamp::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2ftimestamp_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2ftimestamp_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2ftimestamp_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2ftimestamp_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Timestamp::kSecondsFieldNumber;
+const int Timestamp::kNanosFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Timestamp::Timestamp()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Timestamp)
+}
+
+Timestamp::Timestamp(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
+}
+
+void Timestamp::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Timestamp::Timestamp(const Timestamp& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Timestamp)
+}
+
+void Timestamp::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  seconds_ = GOOGLE_LONGLONG(0);
+  nanos_ = 0;
+}
+
+Timestamp::~Timestamp() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Timestamp)
+  SharedDtor();
+}
+
+void Timestamp::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void Timestamp::ArenaDtor(void* object) {
+  Timestamp* _this = reinterpret_cast< Timestamp* >(object);
+  (void)_this;
+}
+void Timestamp::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void Timestamp::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Timestamp::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Timestamp_descriptor_;
+}
+
+const Timestamp& Timestamp::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
+  return *default_instance_;
+}
+
+Timestamp* Timestamp::default_instance_ = NULL;
+
+Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<Timestamp>(arena);
+}
+
+void Timestamp::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Timestamp)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(Timestamp, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Timestamp*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(seconds_, nanos_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+}
+
+bool Timestamp::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Timestamp)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int64 seconds = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &seconds_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_nanos;
+        break;
+      }
+
+      // optional int32 nanos = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_nanos:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &nanos_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Timestamp)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Timestamp)
+  return false;
+#undef DO_
+}
+
+void Timestamp::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Timestamp)
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->seconds(), output);
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->nanos(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Timestamp)
+}
+
+::google::protobuf::uint8* Timestamp::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(1, this->seconds(), target);
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->nanos(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Timestamp)
+  return target;
+}
+
+int Timestamp::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp)
+  int total_size = 0;
+
+  // optional int64 seconds = 1;
+  if (this->seconds() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int64Size(
+        this->seconds());
+  }
+
+  // optional int32 nanos = 2;
+  if (this->nanos() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->nanos());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Timestamp::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Timestamp)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Timestamp* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Timestamp>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Timestamp)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Timestamp)
+    MergeFrom(*source);
+  }
+}
+
+void Timestamp::MergeFrom(const Timestamp& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.seconds() != 0) {
+    set_seconds(from.seconds());
+  }
+  if (from.nanos() != 0) {
+    set_nanos(from.nanos());
+  }
+}
+
+void Timestamp::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Timestamp)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Timestamp::CopyFrom(const Timestamp& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Timestamp)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Timestamp::IsInitialized() const {
+
+  return true;
+}
+
+void Timestamp::Swap(Timestamp* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Timestamp temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Timestamp::UnsafeArenaSwap(Timestamp* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void Timestamp::InternalSwap(Timestamp* other) {
+  std::swap(seconds_, other->seconds_);
+  std::swap(nanos_, other->nanos_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Timestamp::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Timestamp_descriptor_;
+  metadata.reflection = Timestamp_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Timestamp
+
+// optional int64 seconds = 1;
+void Timestamp::clear_seconds() {
+  seconds_ = GOOGLE_LONGLONG(0);
+}
+ ::google::protobuf::int64 Timestamp::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.seconds)
+  return seconds_;
+}
+ void Timestamp::set_seconds(::google::protobuf::int64 value) {
+  
+  seconds_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.seconds)
+}
+
+// optional int32 nanos = 2;
+void Timestamp::clear_nanos() {
+  nanos_ = 0;
+}
+ ::google::protobuf::int32 Timestamp::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.nanos)
+  return nanos_;
+}
+ void Timestamp::set_nanos(::google::protobuf::int32 value) {
+  
+  nanos_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.nanos)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
new file mode 100644
index 0000000..7bf6259
--- /dev/null
+++ b/src/google/protobuf/timestamp.pb.h
@@ -0,0 +1,185 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2ftimestamp_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2ftimestamp_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2ftimestamp_2eproto();
+
+class Timestamp;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
+ public:
+  Timestamp();
+  virtual ~Timestamp();
+
+  Timestamp(const Timestamp& from);
+
+  inline Timestamp& operator=(const Timestamp& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Timestamp& default_instance();
+
+  void UnsafeArenaSwap(Timestamp* other);
+  void Swap(Timestamp* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Timestamp* New() const { return New(NULL); }
+
+  Timestamp* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Timestamp& from);
+  void MergeFrom(const Timestamp& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Timestamp* other);
+  protected:
+  explicit Timestamp(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int64 seconds = 1;
+  void clear_seconds();
+  static const int kSecondsFieldNumber = 1;
+  ::google::protobuf::int64 seconds() const;
+  void set_seconds(::google::protobuf::int64 value);
+
+  // optional int32 nanos = 2;
+  void clear_nanos();
+  static const int kNanosFieldNumber = 2;
+  ::google::protobuf::int32 nanos() const;
+  void set_nanos(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Timestamp)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::int64 seconds_;
+  ::google::protobuf::int32 nanos_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftimestamp_2eproto();
+
+  void InitAsDefaultInstance();
+  static Timestamp* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Timestamp
+
+// optional int64 seconds = 1;
+inline void Timestamp::clear_seconds() {
+  seconds_ = GOOGLE_LONGLONG(0);
+}
+inline ::google::protobuf::int64 Timestamp::seconds() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.seconds)
+  return seconds_;
+}
+inline void Timestamp::set_seconds(::google::protobuf::int64 value) {
+  
+  seconds_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.seconds)
+}
+
+// optional int32 nanos = 2;
+inline void Timestamp::clear_nanos() {
+  nanos_ = 0;
+}
+inline ::google::protobuf::int32 Timestamp::nanos() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Timestamp.nanos)
+  return nanos_;
+}
+inline void Timestamp::set_nanos(::google::protobuf::int32 value) {
+  
+  nanos_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Timestamp.nanos)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2ftimestamp_2eproto__INCLUDED
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
new file mode 100644
index 0000000..7992a85
--- /dev/null
+++ b/src/google/protobuf/timestamp.proto
@@ -0,0 +1,111 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "github.com/golang/protobuf/ptypes/timestamp";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// A Timestamp represents a point in time independent of any time zone
+// or calendar, represented as seconds and fractions of seconds at
+// nanosecond resolution in UTC Epoch time. It is encoded using the
+// Proleptic Gregorian Calendar which extends the Gregorian calendar
+// backwards to year one. It is encoded assuming all minutes are 60
+// seconds long, i.e. leap seconds are "smeared" so that no leap second
+// table is needed for interpretation. Range is from
+// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+// By restricting to that range, we ensure that we can convert to
+// and from  RFC 3339 date strings.
+// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+//
+// Example 1: Compute Timestamp from POSIX `time()`.
+//
+//     Timestamp timestamp;
+//     timestamp.set_seconds(time(NULL));
+//     timestamp.set_nanos(0);
+//
+// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+//
+//     struct timeval tv;
+//     gettimeofday(&tv, NULL);
+//
+//     Timestamp timestamp;
+//     timestamp.set_seconds(tv.tv_sec);
+//     timestamp.set_nanos(tv.tv_usec * 1000);
+//
+// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+//
+//     FILETIME ft;
+//     GetSystemTimeAsFileTime(&ft);
+//     UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+//
+//     // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+//     // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+//     Timestamp timestamp;
+//     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+//     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+//
+// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+//
+//     long millis = System.currentTimeMillis();
+//
+//     Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+//         .setNanos((int) ((millis % 1000) * 1000000)).build();
+//
+//
+// Example 5: Compute Timestamp from current time in Python.
+//
+//     now = time.time()
+//     seconds = int(now)
+//     nanos = int((now - seconds) * 10**9)
+//     timestamp = Timestamp(seconds=seconds, nanos=nanos)
+//
+//
+message Timestamp {
+
+  // Represents seconds of UTC time since Unix epoch
+  // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+  // 9999-12-31T23:59:59Z inclusive.
+  int64 seconds = 1;
+
+  // Non-negative fractions of a second at nanosecond resolution. Negative
+  // second values with fractions must still have non-negative nanos values
+  // that count forward in time. Must be from 0 to 999,999,999
+  // inclusive.
+  int32 nanos = 2;
+}
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
new file mode 100644
index 0000000..759cab2
--- /dev/null
+++ b/src/google/protobuf/type.pb.cc
@@ -0,0 +1,3291 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/type.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Type_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Type_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Field_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Field_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Field_Kind_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Enum_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Enum_reflection_ = NULL;
+const ::google::protobuf::Descriptor* EnumValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  EnumValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Option_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Option_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Syntax_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/type.proto");
+  GOOGLE_CHECK(file != NULL);
+  Type_descriptor_ = file->message_type(0);
+  static const int Type_offsets_[6] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, fields_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, oneofs_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, source_context_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, syntax_),
+  };
+  Type_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Type_descriptor_,
+      Type::default_instance_,
+      Type_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Type),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _is_default_instance_));
+  Field_descriptor_ = file->message_type(1);
+  static const int Field_offsets_[10] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, kind_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, cardinality_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, number_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, type_url_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, oneof_index_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, packed_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, json_name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, default_value_),
+  };
+  Field_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Field_descriptor_,
+      Field::default_instance_,
+      Field_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Field),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, _is_default_instance_));
+  Field_Kind_descriptor_ = Field_descriptor_->enum_type(0);
+  Field_Cardinality_descriptor_ = Field_descriptor_->enum_type(1);
+  Enum_descriptor_ = file->message_type(2);
+  static const int Enum_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, enumvalue_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, source_context_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, syntax_),
+  };
+  Enum_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Enum_descriptor_,
+      Enum::default_instance_,
+      Enum_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Enum),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, _is_default_instance_));
+  EnumValue_descriptor_ = file->message_type(3);
+  static const int EnumValue_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValue, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValue, number_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValue, options_),
+  };
+  EnumValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      EnumValue_descriptor_,
+      EnumValue::default_instance_,
+      EnumValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(EnumValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValue, _is_default_instance_));
+  Option_descriptor_ = file->message_type(4);
+  static const int Option_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, value_),
+  };
+  Option_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Option_descriptor_,
+      Option::default_instance_,
+      Option_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Option),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, _is_default_instance_));
+  Syntax_descriptor_ = file->enum_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Type_descriptor_, &Type::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Field_descriptor_, &Field::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Enum_descriptor_, &Enum::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      EnumValue_descriptor_, &EnumValue::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Option_descriptor_, &Option::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto() {
+  delete Type::default_instance_;
+  delete Type_reflection_;
+  delete Field::default_instance_;
+  delete Field_reflection_;
+  delete Enum::default_instance_;
+  delete Enum_reflection_;
+  delete EnumValue::default_instance_;
+  delete EnumValue_reflection_;
+  delete Option::default_instance_;
+  delete Option_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\032google/protobuf/type.proto\022\017google.pro"
+    "tobuf\032\031google/protobuf/any.proto\032$google"
+    "/protobuf/source_context.proto\"\327\001\n\004Type\022"
+    "\014\n\004name\030\001 \001(\t\022&\n\006fields\030\002 \003(\0132\026.google.p"
+    "rotobuf.Field\022\016\n\006oneofs\030\003 \003(\t\022(\n\007options"
+    "\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc"
+    "e_context\030\005 \001(\0132\036.google.protobuf.Source"
+    "Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu"
+    "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
+    "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001"
+    "(\0162\".google.protobuf.Field.Cardinality\022\016"
+    "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url"
+    "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 "
+    "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O"
+    "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu"
+    "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY"
+    "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6"
+    "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014"
+    "TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE"
+    "_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n"
+    "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY"
+    "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE"
+    "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020"
+    "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR"
+    "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION"
+    "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN"
+    "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022"
+    "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu"
+    "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu"
+    "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl"
+    "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016"
+    "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014"
+    "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030"
+    "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option"
+    "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p"
+    "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000"
+    "\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023com.google.protob"
+    "ufB\tTypeProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protob"
+    "uf.WellKnownTypesb\006proto3", 1545);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/type.proto", &protobuf_RegisterTypes);
+  Type::default_instance_ = new Type();
+  Field::default_instance_ = new Field();
+  Enum::default_instance_ = new Enum();
+  EnumValue::default_instance_ = new EnumValue();
+  Option::default_instance_ = new Option();
+  Type::default_instance_->InitAsDefaultInstance();
+  Field::default_instance_->InitAsDefaultInstance();
+  Enum::default_instance_->InitAsDefaultInstance();
+  EnumValue::default_instance_->InitAsDefaultInstance();
+  Option::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2ftype_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2ftype_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2ftype_2eproto_;
+const ::google::protobuf::EnumDescriptor* Syntax_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Syntax_descriptor_;
+}
+bool Syntax_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Type::kNameFieldNumber;
+const int Type::kFieldsFieldNumber;
+const int Type::kOneofsFieldNumber;
+const int Type::kOptionsFieldNumber;
+const int Type::kSourceContextFieldNumber;
+const int Type::kSyntaxFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Type::Type()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Type)
+}
+
+void Type::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+  source_context_ = const_cast< ::google::protobuf::SourceContext*>(&::google::protobuf::SourceContext::default_instance());
+}
+
+Type::Type(const Type& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Type)
+}
+
+void Type::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  source_context_ = NULL;
+  syntax_ = 0;
+}
+
+Type::~Type() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Type)
+  SharedDtor();
+}
+
+void Type::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+    delete source_context_;
+  }
+}
+
+void Type::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Type::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Type_descriptor_;
+}
+
+const Type& Type::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  return *default_instance_;
+}
+
+Type* Type::default_instance_ = NULL;
+
+Type* Type::New(::google::protobuf::Arena* arena) const {
+  Type* n = new Type;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Type::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Type)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+  syntax_ = 0;
+  fields_.Clear();
+  oneofs_.Clear();
+  options_.Clear();
+}
+
+bool Type::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Type)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Type.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_fields;
+        break;
+      }
+
+      // repeated .google.protobuf.Field fields = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_fields:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_fields:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_fields()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_fields;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(26)) goto parse_oneofs;
+        break;
+      }
+
+      // repeated string oneofs = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_oneofs:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_oneofs()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->oneofs(this->oneofs_size() - 1).data(),
+            this->oneofs(this->oneofs_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Type.oneofs"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_oneofs;
+        if (input->ExpectTag(34)) goto parse_options;
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_options:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(42)) goto parse_source_context;
+        break;
+      }
+
+      // optional .google.protobuf.SourceContext source_context = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_source_context:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_source_context()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_syntax;
+        break;
+      }
+
+      // optional .google.protobuf.Syntax syntax = 6;
+      case 6: {
+        if (tag == 48) {
+         parse_syntax:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_syntax(static_cast< ::google::protobuf::Syntax >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Type)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Type)
+  return false;
+#undef DO_
+}
+
+void Type::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Type)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // repeated .google.protobuf.Field fields = 2;
+  for (unsigned int i = 0, n = this->fields_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->fields(i), output);
+  }
+
+  // repeated string oneofs = 3;
+  for (int i = 0; i < this->oneofs_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->oneofs(i).data(), this->oneofs(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.oneofs");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->oneofs(i), output);
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, this->options(i), output);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      5, *this->source_context_, output);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 6;
+  if (this->syntax() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->syntax(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Type)
+}
+
+::google::protobuf::uint8* Type::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // repeated .google.protobuf.Field fields = 2;
+  for (unsigned int i = 0, n = this->fields_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        2, this->fields(i), target);
+  }
+
+  // repeated string oneofs = 3;
+  for (int i = 0; i < this->oneofs_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->oneofs(i).data(), this->oneofs(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Type.oneofs");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->oneofs(i), target);
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        4, this->options(i), target);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        5, *this->source_context_, target);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 6;
+  if (this->syntax() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->syntax(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type)
+  return target;
+}
+
+int Type::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  if (this->has_source_context()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->source_context_);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 6;
+  if (this->syntax() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax());
+  }
+
+  // repeated .google.protobuf.Field fields = 2;
+  total_size += 1 * this->fields_size();
+  for (int i = 0; i < this->fields_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->fields(i));
+  }
+
+  // repeated string oneofs = 3;
+  total_size += 1 * this->oneofs_size();
+  for (int i = 0; i < this->oneofs_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->oneofs(i));
+  }
+
+  // repeated .google.protobuf.Option options = 4;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Type::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Type)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Type* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Type>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Type)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Type)
+    MergeFrom(*source);
+  }
+}
+
+void Type::MergeFrom(const Type& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  fields_.MergeFrom(from.fields_);
+  oneofs_.MergeFrom(from.oneofs_);
+  options_.MergeFrom(from.options_);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.has_source_context()) {
+    mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context());
+  }
+  if (from.syntax() != 0) {
+    set_syntax(from.syntax());
+  }
+}
+
+void Type::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Type)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Type::CopyFrom(const Type& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Type)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Type::IsInitialized() const {
+
+  return true;
+}
+
+void Type::Swap(Type* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Type::InternalSwap(Type* other) {
+  name_.Swap(&other->name_);
+  fields_.UnsafeArenaSwap(&other->fields_);
+  oneofs_.UnsafeArenaSwap(&other->oneofs_);
+  options_.UnsafeArenaSwap(&other->options_);
+  std::swap(source_context_, other->source_context_);
+  std::swap(syntax_, other->syntax_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Type::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Type_descriptor_;
+  metadata.reflection = Type_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Type
+
+// optional string name = 1;
+void Type::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Type::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Type::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.name)
+}
+ void Type::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Type.name)
+}
+ void Type::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.name)
+}
+ ::std::string* Type::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Type::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Type::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.name)
+}
+
+// repeated .google.protobuf.Field fields = 2;
+int Type::fields_size() const {
+  return fields_.size();
+}
+void Type::clear_fields() {
+  fields_.Clear();
+}
+const ::google::protobuf::Field& Type::fields(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.fields)
+  return fields_.Get(index);
+}
+::google::protobuf::Field* Type::mutable_fields(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.fields)
+  return fields_.Mutable(index);
+}
+::google::protobuf::Field* Type::add_fields() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.fields)
+  return fields_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >*
+Type::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields)
+  return &fields_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >&
+Type::fields() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.fields)
+  return fields_;
+}
+
+// repeated string oneofs = 3;
+int Type::oneofs_size() const {
+  return oneofs_.size();
+}
+void Type::clear_oneofs() {
+  oneofs_.Clear();
+}
+ const ::std::string& Type::oneofs(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.oneofs)
+  return oneofs_.Get(index);
+}
+ ::std::string* Type::mutable_oneofs(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.oneofs)
+  return oneofs_.Mutable(index);
+}
+ void Type::set_oneofs(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+  oneofs_.Mutable(index)->assign(value);
+}
+ void Type::set_oneofs(int index, const char* value) {
+  oneofs_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Type.oneofs)
+}
+ void Type::set_oneofs(int index, const char* value, size_t size) {
+  oneofs_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs)
+}
+ ::std::string* Type::add_oneofs() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs)
+  return oneofs_.Add();
+}
+ void Type::add_oneofs(const ::std::string& value) {
+  oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+ void Type::add_oneofs(const char* value) {
+  oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.Type.oneofs)
+}
+ void Type::add_oneofs(const char* value, size_t size) {
+  oneofs_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.Type.oneofs)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+Type::oneofs() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.oneofs)
+  return oneofs_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+Type::mutable_oneofs() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.oneofs)
+  return &oneofs_;
+}
+
+// repeated .google.protobuf.Option options = 4;
+int Type::options_size() const {
+  return options_.size();
+}
+void Type::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& Type::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* Type::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* Type::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Type::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Type::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.options)
+  return options_;
+}
+
+// optional .google.protobuf.SourceContext source_context = 5;
+bool Type::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+void Type::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+const ::google::protobuf::SourceContext& Type::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+::google::protobuf::SourceContext* Type::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.source_context)
+  return source_context_;
+}
+::google::protobuf::SourceContext* Type::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+void Type::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context)
+}
+
+// optional .google.protobuf.Syntax syntax = 6;
+void Type::clear_syntax() {
+  syntax_ = 0;
+}
+ ::google::protobuf::Syntax Type::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+ void Type::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Field_Kind_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Field_Kind_descriptor_;
+}
+bool Field_Kind_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const Field_Kind Field::TYPE_UNKNOWN;
+const Field_Kind Field::TYPE_DOUBLE;
+const Field_Kind Field::TYPE_FLOAT;
+const Field_Kind Field::TYPE_INT64;
+const Field_Kind Field::TYPE_UINT64;
+const Field_Kind Field::TYPE_INT32;
+const Field_Kind Field::TYPE_FIXED64;
+const Field_Kind Field::TYPE_FIXED32;
+const Field_Kind Field::TYPE_BOOL;
+const Field_Kind Field::TYPE_STRING;
+const Field_Kind Field::TYPE_GROUP;
+const Field_Kind Field::TYPE_MESSAGE;
+const Field_Kind Field::TYPE_BYTES;
+const Field_Kind Field::TYPE_UINT32;
+const Field_Kind Field::TYPE_ENUM;
+const Field_Kind Field::TYPE_SFIXED32;
+const Field_Kind Field::TYPE_SFIXED64;
+const Field_Kind Field::TYPE_SINT32;
+const Field_Kind Field::TYPE_SINT64;
+const Field_Kind Field::Kind_MIN;
+const Field_Kind Field::Kind_MAX;
+const int Field::Kind_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Field_Cardinality_descriptor_;
+}
+bool Field_Cardinality_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const Field_Cardinality Field::CARDINALITY_UNKNOWN;
+const Field_Cardinality Field::CARDINALITY_OPTIONAL;
+const Field_Cardinality Field::CARDINALITY_REQUIRED;
+const Field_Cardinality Field::CARDINALITY_REPEATED;
+const Field_Cardinality Field::Cardinality_MIN;
+const Field_Cardinality Field::Cardinality_MAX;
+const int Field::Cardinality_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Field::kKindFieldNumber;
+const int Field::kCardinalityFieldNumber;
+const int Field::kNumberFieldNumber;
+const int Field::kNameFieldNumber;
+const int Field::kTypeUrlFieldNumber;
+const int Field::kOneofIndexFieldNumber;
+const int Field::kPackedFieldNumber;
+const int Field::kOptionsFieldNumber;
+const int Field::kJsonNameFieldNumber;
+const int Field::kDefaultValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Field::Field()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Field)
+}
+
+void Field::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Field::Field(const Field& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Field)
+}
+
+void Field::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  kind_ = 0;
+  cardinality_ = 0;
+  number_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  oneof_index_ = 0;
+  packed_ = false;
+  json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+Field::~Field() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Field)
+  SharedDtor();
+}
+
+void Field::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void Field::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Field::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Field_descriptor_;
+}
+
+const Field& Field::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  return *default_instance_;
+}
+
+Field* Field::default_instance_ = NULL;
+
+Field* Field::New(::google::protobuf::Arena* arena) const {
+  Field* n = new Field;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Field::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Field)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(Field, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Field*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(kind_, cardinality_);
+  ZR_(number_, oneof_index_);
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  packed_ = false;
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  options_.Clear();
+}
+
+bool Field::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Field)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .google.protobuf.Field.Kind kind = 1;
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_kind(static_cast< ::google::protobuf::Field_Kind >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_cardinality;
+        break;
+      }
+
+      // optional .google.protobuf.Field.Cardinality cardinality = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_cardinality:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_cardinality(static_cast< ::google::protobuf::Field_Cardinality >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_number;
+        break;
+      }
+
+      // optional int32 number = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_number:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &number_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_name;
+        break;
+      }
+
+      // optional string name = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Field.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_type_url;
+        break;
+      }
+
+      // optional string type_url = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_type_url:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type_url()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->type_url().data(), this->type_url().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Field.type_url"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_oneof_index;
+        break;
+      }
+
+      // optional int32 oneof_index = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_oneof_index:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &oneof_index_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_packed;
+        break;
+      }
+
+      // optional bool packed = 8;
+      case 8: {
+        if (tag == 64) {
+         parse_packed:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &packed_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(74)) goto parse_options;
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 9;
+      case 9: {
+        if (tag == 74) {
+         parse_options:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(74)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(82)) goto parse_json_name;
+        break;
+      }
+
+      // optional string json_name = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_json_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_json_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->json_name().data(), this->json_name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Field.json_name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(90)) goto parse_default_value;
+        break;
+      }
+
+      // optional string default_value = 11;
+      case 11: {
+        if (tag == 90) {
+         parse_default_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_default_value()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->default_value().data(), this->default_value().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Field.default_value"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Field)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Field)
+  return false;
+#undef DO_
+}
+
+void Field::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Field)
+  // optional .google.protobuf.Field.Kind kind = 1;
+  if (this->kind() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->kind(), output);
+  }
+
+  // optional .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->cardinality() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      2, this->cardinality(), output);
+  }
+
+  // optional int32 number = 3;
+  if (this->number() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->number(), output);
+  }
+
+  // optional string name = 4;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->name(), output);
+  }
+
+  // optional string type_url = 6;
+  if (this->type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_url().data(), this->type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.type_url");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      6, this->type_url(), output);
+  }
+
+  // optional int32 oneof_index = 7;
+  if (this->oneof_index() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->oneof_index(), output);
+  }
+
+  // optional bool packed = 8;
+  if (this->packed() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(8, this->packed(), output);
+  }
+
+  // repeated .google.protobuf.Option options = 9;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      9, this->options(i), output);
+  }
+
+  // optional string json_name = 10;
+  if (this->json_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.json_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      10, this->json_name(), output);
+  }
+
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->default_value().data(), this->default_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      11, this->default_value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Field)
+}
+
+::google::protobuf::uint8* Field::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
+  // optional .google.protobuf.Field.Kind kind = 1;
+  if (this->kind() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->kind(), target);
+  }
+
+  // optional .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->cardinality() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      2, this->cardinality(), target);
+  }
+
+  // optional int32 number = 3;
+  if (this->number() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target);
+  }
+
+  // optional string name = 4;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->name(), target);
+  }
+
+  // optional string type_url = 6;
+  if (this->type_url().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_url().data(), this->type_url().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.type_url");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        6, this->type_url(), target);
+  }
+
+  // optional int32 oneof_index = 7;
+  if (this->oneof_index() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(7, this->oneof_index(), target);
+  }
+
+  // optional bool packed = 8;
+  if (this->packed() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(8, this->packed(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 9;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        9, this->options(i), target);
+  }
+
+  // optional string json_name = 10;
+  if (this->json_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.json_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        10, this->json_name(), target);
+  }
+
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->default_value().data(), this->default_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        11, this->default_value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
+  return target;
+}
+
+int Field::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field)
+  int total_size = 0;
+
+  // optional .google.protobuf.Field.Kind kind = 1;
+  if (this->kind() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->kind());
+  }
+
+  // optional .google.protobuf.Field.Cardinality cardinality = 2;
+  if (this->cardinality() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->cardinality());
+  }
+
+  // optional int32 number = 3;
+  if (this->number() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->number());
+  }
+
+  // optional string name = 4;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string type_url = 6;
+  if (this->type_url().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->type_url());
+  }
+
+  // optional int32 oneof_index = 7;
+  if (this->oneof_index() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->oneof_index());
+  }
+
+  // optional bool packed = 8;
+  if (this->packed() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // optional string json_name = 10;
+  if (this->json_name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->json_name());
+  }
+
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->default_value());
+  }
+
+  // repeated .google.protobuf.Option options = 9;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Field::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Field)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Field* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Field>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Field)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Field)
+    MergeFrom(*source);
+  }
+}
+
+void Field::MergeFrom(const Field& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  options_.MergeFrom(from.options_);
+  if (from.kind() != 0) {
+    set_kind(from.kind());
+  }
+  if (from.cardinality() != 0) {
+    set_cardinality(from.cardinality());
+  }
+  if (from.number() != 0) {
+    set_number(from.number());
+  }
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.type_url().size() > 0) {
+
+    type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
+  }
+  if (from.oneof_index() != 0) {
+    set_oneof_index(from.oneof_index());
+  }
+  if (from.packed() != 0) {
+    set_packed(from.packed());
+  }
+  if (from.json_name().size() > 0) {
+
+    json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
+  }
+  if (from.default_value().size() > 0) {
+
+    default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_);
+  }
+}
+
+void Field::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Field)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Field::CopyFrom(const Field& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Field)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Field::IsInitialized() const {
+
+  return true;
+}
+
+void Field::Swap(Field* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Field::InternalSwap(Field* other) {
+  std::swap(kind_, other->kind_);
+  std::swap(cardinality_, other->cardinality_);
+  std::swap(number_, other->number_);
+  name_.Swap(&other->name_);
+  type_url_.Swap(&other->type_url_);
+  std::swap(oneof_index_, other->oneof_index_);
+  std::swap(packed_, other->packed_);
+  options_.UnsafeArenaSwap(&other->options_);
+  json_name_.Swap(&other->json_name_);
+  default_value_.Swap(&other->default_value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Field::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Field_descriptor_;
+  metadata.reflection = Field_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Field
+
+// optional .google.protobuf.Field.Kind kind = 1;
+void Field::clear_kind() {
+  kind_ = 0;
+}
+ ::google::protobuf::Field_Kind Field::kind() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.kind)
+  return static_cast< ::google::protobuf::Field_Kind >(kind_);
+}
+ void Field::set_kind(::google::protobuf::Field_Kind value) {
+  
+  kind_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.kind)
+}
+
+// optional .google.protobuf.Field.Cardinality cardinality = 2;
+void Field::clear_cardinality() {
+  cardinality_ = 0;
+}
+ ::google::protobuf::Field_Cardinality Field::cardinality() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.cardinality)
+  return static_cast< ::google::protobuf::Field_Cardinality >(cardinality_);
+}
+ void Field::set_cardinality(::google::protobuf::Field_Cardinality value) {
+  
+  cardinality_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.cardinality)
+}
+
+// optional int32 number = 3;
+void Field::clear_number() {
+  number_ = 0;
+}
+ ::google::protobuf::int32 Field::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.number)
+  return number_;
+}
+ void Field::set_number(::google::protobuf::int32 value) {
+  
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.number)
+}
+
+// optional string name = 4;
+void Field::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.name)
+}
+ void Field::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.name)
+}
+ void Field::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.name)
+}
+ ::std::string* Field::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.name)
+}
+
+// optional string type_url = 6;
+void Field::clear_type_url() {
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.type_url)
+  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_type_url(const ::std::string& value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.type_url)
+}
+ void Field::set_type_url(const char* value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.type_url)
+}
+ void Field::set_type_url(const char* value, size_t size) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.type_url)
+}
+ ::std::string* Field::mutable_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.type_url)
+  return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url)
+  
+  return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_type_url(::std::string* type_url) {
+  if (type_url != NULL) {
+    
+  } else {
+    
+  }
+  type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.type_url)
+}
+
+// optional int32 oneof_index = 7;
+void Field::clear_oneof_index() {
+  oneof_index_ = 0;
+}
+ ::google::protobuf::int32 Field::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.oneof_index)
+  return oneof_index_;
+}
+ void Field::set_oneof_index(::google::protobuf::int32 value) {
+  
+  oneof_index_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.oneof_index)
+}
+
+// optional bool packed = 8;
+void Field::clear_packed() {
+  packed_ = false;
+}
+ bool Field::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.packed)
+  return packed_;
+}
+ void Field::set_packed(bool value) {
+  
+  packed_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.packed)
+}
+
+// repeated .google.protobuf.Option options = 9;
+int Field::options_size() const {
+  return options_.size();
+}
+void Field::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& Field::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* Field::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* Field::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Field.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Field::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Field::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Field.options)
+  return options_;
+}
+
+// optional string json_name = 10;
+void Field::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_json_name(const ::std::string& value) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name)
+}
+ void Field::set_json_name(const char* value) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.json_name)
+}
+ void Field::set_json_name(const char* value, size_t size) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.json_name)
+}
+ ::std::string* Field::mutable_json_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name)
+  
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    
+  } else {
+    
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
+}
+
+// optional string default_value = 11;
+void Field::clear_default_value() {
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_default_value(const ::std::string& value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value, size_t size) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+ ::std::string* Field::mutable_default_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value)
+  
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_default_value(::std::string* default_value) {
+  if (default_value != NULL) {
+    
+  } else {
+    
+  }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Enum::kNameFieldNumber;
+const int Enum::kEnumvalueFieldNumber;
+const int Enum::kOptionsFieldNumber;
+const int Enum::kSourceContextFieldNumber;
+const int Enum::kSyntaxFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Enum::Enum()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Enum)
+}
+
+void Enum::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+  source_context_ = const_cast< ::google::protobuf::SourceContext*>(&::google::protobuf::SourceContext::default_instance());
+}
+
+Enum::Enum(const Enum& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Enum)
+}
+
+void Enum::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  source_context_ = NULL;
+  syntax_ = 0;
+}
+
+Enum::~Enum() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Enum)
+  SharedDtor();
+}
+
+void Enum::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+    delete source_context_;
+  }
+}
+
+void Enum::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Enum::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Enum_descriptor_;
+}
+
+const Enum& Enum::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  return *default_instance_;
+}
+
+Enum* Enum::default_instance_ = NULL;
+
+Enum* Enum::New(::google::protobuf::Arena* arena) const {
+  Enum* n = new Enum;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Enum::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Enum)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+  syntax_ = 0;
+  enumvalue_.Clear();
+  options_.Clear();
+}
+
+bool Enum::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Enum)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Enum.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_enumvalue;
+        break;
+      }
+
+      // repeated .google.protobuf.EnumValue enumvalue = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_enumvalue:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enumvalue:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_enumvalue()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_enumvalue;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 3;
+      case 3: {
+        if (tag == 26) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(34)) goto parse_source_context;
+        break;
+      }
+
+      // optional .google.protobuf.SourceContext source_context = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_source_context:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_source_context()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_syntax;
+        break;
+      }
+
+      // optional .google.protobuf.Syntax syntax = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_syntax:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_syntax(static_cast< ::google::protobuf::Syntax >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Enum)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Enum)
+  return false;
+#undef DO_
+}
+
+void Enum::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Enum)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Enum.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  for (unsigned int i = 0, n = this->enumvalue_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->enumvalue(i), output);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, this->options(i), output);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 4;
+  if (this->has_source_context()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, *this->source_context_, output);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 5;
+  if (this->syntax() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      5, this->syntax(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Enum)
+}
+
+::google::protobuf::uint8* Enum::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Enum.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  for (unsigned int i = 0, n = this->enumvalue_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        2, this->enumvalue(i), target);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        3, this->options(i), target);
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 4;
+  if (this->has_source_context()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        4, *this->source_context_, target);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 5;
+  if (this->syntax() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      5, this->syntax(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum)
+  return target;
+}
+
+int Enum::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional .google.protobuf.SourceContext source_context = 4;
+  if (this->has_source_context()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->source_context_);
+  }
+
+  // optional .google.protobuf.Syntax syntax = 5;
+  if (this->syntax() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax());
+  }
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  total_size += 1 * this->enumvalue_size();
+  for (int i = 0; i < this->enumvalue_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->enumvalue(i));
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Enum::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Enum)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Enum* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Enum>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Enum)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Enum)
+    MergeFrom(*source);
+  }
+}
+
+void Enum::MergeFrom(const Enum& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  enumvalue_.MergeFrom(from.enumvalue_);
+  options_.MergeFrom(from.options_);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.has_source_context()) {
+    mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context());
+  }
+  if (from.syntax() != 0) {
+    set_syntax(from.syntax());
+  }
+}
+
+void Enum::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Enum)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Enum::CopyFrom(const Enum& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Enum)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Enum::IsInitialized() const {
+
+  return true;
+}
+
+void Enum::Swap(Enum* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Enum::InternalSwap(Enum* other) {
+  name_.Swap(&other->name_);
+  enumvalue_.UnsafeArenaSwap(&other->enumvalue_);
+  options_.UnsafeArenaSwap(&other->options_);
+  std::swap(source_context_, other->source_context_);
+  std::swap(syntax_, other->syntax_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Enum::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Enum_descriptor_;
+  metadata.reflection = Enum_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Enum
+
+// optional string name = 1;
+void Enum::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Enum::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Enum::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.name)
+}
+ void Enum::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Enum.name)
+}
+ void Enum::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Enum.name)
+}
+ ::std::string* Enum::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Enum::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Enum::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.name)
+}
+
+// repeated .google.protobuf.EnumValue enumvalue = 2;
+int Enum::enumvalue_size() const {
+  return enumvalue_.size();
+}
+void Enum::clear_enumvalue() {
+  enumvalue_.Clear();
+}
+const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Get(index);
+}
+::google::protobuf::EnumValue* Enum::mutable_enumvalue(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Mutable(index);
+}
+::google::protobuf::EnumValue* Enum::add_enumvalue() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >*
+Enum::mutable_enumvalue() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue)
+  return &enumvalue_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >&
+Enum::enumvalue() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue)
+  return enumvalue_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+int Enum::options_size() const {
+  return options_.size();
+}
+void Enum::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& Enum::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* Enum::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* Enum::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Enum::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Enum::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.options)
+  return options_;
+}
+
+// optional .google.protobuf.SourceContext source_context = 4;
+bool Enum::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+void Enum::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+const ::google::protobuf::SourceContext& Enum::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+::google::protobuf::SourceContext* Enum::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.source_context)
+  return source_context_;
+}
+::google::protobuf::SourceContext* Enum::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+void Enum::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context)
+}
+
+// optional .google.protobuf.Syntax syntax = 5;
+void Enum::clear_syntax() {
+  syntax_ = 0;
+}
+ ::google::protobuf::Syntax Enum::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+ void Enum::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int EnumValue::kNameFieldNumber;
+const int EnumValue::kNumberFieldNumber;
+const int EnumValue::kOptionsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+EnumValue::EnumValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.EnumValue)
+}
+
+void EnumValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+EnumValue::EnumValue(const EnumValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.EnumValue)
+}
+
+void EnumValue::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  number_ = 0;
+}
+
+EnumValue::~EnumValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.EnumValue)
+  SharedDtor();
+}
+
+void EnumValue::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void EnumValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* EnumValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return EnumValue_descriptor_;
+}
+
+const EnumValue& EnumValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  return *default_instance_;
+}
+
+EnumValue* EnumValue::default_instance_ = NULL;
+
+EnumValue* EnumValue::New(::google::protobuf::Arena* arena) const {
+  EnumValue* n = new EnumValue;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void EnumValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValue)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  number_ = 0;
+  options_.Clear();
+}
+
+bool EnumValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.EnumValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.EnumValue.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_number;
+        break;
+      }
+
+      // optional int32 number = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_number:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &number_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_options;
+        break;
+      }
+
+      // repeated .google.protobuf.Option options = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_options:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_options()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.EnumValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.EnumValue)
+  return false;
+#undef DO_
+}
+
+void EnumValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValue)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.EnumValue.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional int32 number = 2;
+  if (this->number() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->number(), output);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, this->options(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValue)
+}
+
+::google::protobuf::uint8* EnumValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.EnumValue.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional int32 number = 2;
+  if (this->number() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target);
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        3, this->options(i), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
+  return target;
+}
+
+int EnumValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional int32 number = 2;
+  if (this->number() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->number());
+  }
+
+  // repeated .google.protobuf.Option options = 3;
+  total_size += 1 * this->options_size();
+  for (int i = 0; i < this->options_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->options(i));
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void EnumValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EnumValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValue)
+    MergeFrom(*source);
+  }
+}
+
+void EnumValue::MergeFrom(const EnumValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  options_.MergeFrom(from.options_);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.number() != 0) {
+    set_number(from.number());
+  }
+}
+
+void EnumValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void EnumValue::CopyFrom(const EnumValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool EnumValue::IsInitialized() const {
+
+  return true;
+}
+
+void EnumValue::Swap(EnumValue* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EnumValue::InternalSwap(EnumValue* other) {
+  name_.Swap(&other->name_);
+  std::swap(number_, other->number_);
+  options_.UnsafeArenaSwap(&other->options_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata EnumValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = EnumValue_descriptor_;
+  metadata.reflection = EnumValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EnumValue
+
+// optional string name = 1;
+void EnumValue::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& EnumValue::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValue::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.name)
+}
+ void EnumValue::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValue.name)
+}
+ void EnumValue::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValue.name)
+}
+ ::std::string* EnumValue::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* EnumValue::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void EnumValue::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValue.name)
+}
+
+// optional int32 number = 2;
+void EnumValue::clear_number() {
+  number_ = 0;
+}
+ ::google::protobuf::int32 EnumValue::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.number)
+  return number_;
+}
+ void EnumValue::set_number(::google::protobuf::int32 value) {
+  
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.number)
+}
+
+// repeated .google.protobuf.Option options = 3;
+int EnumValue::options_size() const {
+  return options_.size();
+}
+void EnumValue::clear_options() {
+  options_.Clear();
+}
+const ::google::protobuf::Option& EnumValue::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.options)
+  return options_.Get(index);
+}
+::google::protobuf::Option* EnumValue::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.options)
+  return options_.Mutable(index);
+}
+::google::protobuf::Option* EnumValue::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options)
+  return options_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+EnumValue::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options)
+  return &options_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+EnumValue::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options)
+  return options_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Option::kNameFieldNumber;
+const int Option::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Option::Option()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Option)
+}
+
+void Option::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+  value_ = const_cast< ::google::protobuf::Any*>(&::google::protobuf::Any::default_instance());
+}
+
+Option::Option(const Option& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Option)
+}
+
+void Option::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_ = NULL;
+}
+
+Option::~Option() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Option)
+  SharedDtor();
+}
+
+void Option::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+    delete value_;
+  }
+}
+
+void Option::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Option::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Option_descriptor_;
+}
+
+const Option& Option::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  return *default_instance_;
+}
+
+Option* Option::default_instance_ = NULL;
+
+Option* Option::New(::google::protobuf::Arena* arena) const {
+  Option* n = new Option;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Option::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Option)
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
+  value_ = NULL;
+}
+
+bool Option::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Option)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Option.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_value;
+        break;
+      }
+
+      // optional .google.protobuf.Any value = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Option)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Option)
+  return false;
+#undef DO_
+}
+
+void Option::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Option)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Option.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional .google.protobuf.Any value = 2;
+  if (this->has_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, *this->value_, output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Option)
+}
+
+::google::protobuf::uint8* Option::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Option.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional .google.protobuf.Any value = 2;
+  if (this->has_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        2, *this->value_, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
+  return target;
+}
+
+int Option::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option)
+  int total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional .google.protobuf.Any value = 2;
+  if (this->has_value()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->value_);
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Option::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Option)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Option* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Option>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Option)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Option)
+    MergeFrom(*source);
+  }
+}
+
+void Option::MergeFrom(const Option& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.name().size() > 0) {
+
+    name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+  }
+  if (from.has_value()) {
+    mutable_value()->::google::protobuf::Any::MergeFrom(from.value());
+  }
+}
+
+void Option::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Option)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Option::CopyFrom(const Option& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Option)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Option::IsInitialized() const {
+
+  return true;
+}
+
+void Option::Swap(Option* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Option::InternalSwap(Option* other) {
+  name_.Swap(&other->name_);
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Option::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Option_descriptor_;
+  metadata.reflection = Option_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Option
+
+// optional string name = 1;
+void Option::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Option::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Option::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Option.name)
+}
+ void Option::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Option.name)
+}
+ void Option::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Option.name)
+}
+ ::std::string* Option::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Option::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Option::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.name)
+}
+
+// optional .google.protobuf.Any value = 2;
+bool Option::has_value() const {
+  return !_is_default_instance_ && value_ != NULL;
+}
+void Option::clear_value() {
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
+  value_ = NULL;
+}
+const ::google::protobuf::Any& Option::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.value)
+  return value_ != NULL ? *value_ : *default_instance_->value_;
+}
+::google::protobuf::Any* Option::mutable_value() {
+  
+  if (value_ == NULL) {
+    value_ = new ::google::protobuf::Any;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.value)
+  return value_;
+}
+::google::protobuf::Any* Option::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.value)
+  
+  ::google::protobuf::Any* temp = value_;
+  value_ = NULL;
+  return temp;
+}
+void Option::set_allocated_value(::google::protobuf::Any* value) {
+  delete value_;
+  value_ = value;
+  if (value) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
new file mode 100644
index 0000000..4255fa8
--- /dev/null
+++ b/src/google/protobuf/type.pb.h
@@ -0,0 +1,1731 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2ftype_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2ftype_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/source_context.pb.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+class Enum;
+class EnumValue;
+class Field;
+class Option;
+class Type;
+
+enum Field_Kind {
+  Field_Kind_TYPE_UNKNOWN = 0,
+  Field_Kind_TYPE_DOUBLE = 1,
+  Field_Kind_TYPE_FLOAT = 2,
+  Field_Kind_TYPE_INT64 = 3,
+  Field_Kind_TYPE_UINT64 = 4,
+  Field_Kind_TYPE_INT32 = 5,
+  Field_Kind_TYPE_FIXED64 = 6,
+  Field_Kind_TYPE_FIXED32 = 7,
+  Field_Kind_TYPE_BOOL = 8,
+  Field_Kind_TYPE_STRING = 9,
+  Field_Kind_TYPE_GROUP = 10,
+  Field_Kind_TYPE_MESSAGE = 11,
+  Field_Kind_TYPE_BYTES = 12,
+  Field_Kind_TYPE_UINT32 = 13,
+  Field_Kind_TYPE_ENUM = 14,
+  Field_Kind_TYPE_SFIXED32 = 15,
+  Field_Kind_TYPE_SFIXED64 = 16,
+  Field_Kind_TYPE_SINT32 = 17,
+  Field_Kind_TYPE_SINT64 = 18,
+  Field_Kind_Field_Kind_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,
+  Field_Kind_Field_Kind_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max
+};
+LIBPROTOBUF_EXPORT bool Field_Kind_IsValid(int value);
+const Field_Kind Field_Kind_Kind_MIN = Field_Kind_TYPE_UNKNOWN;
+const Field_Kind Field_Kind_Kind_MAX = Field_Kind_TYPE_SINT64;
+const int Field_Kind_Kind_ARRAYSIZE = Field_Kind_Kind_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Field_Kind_descriptor();
+inline const ::std::string& Field_Kind_Name(Field_Kind value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    Field_Kind_descriptor(), value);
+}
+inline bool Field_Kind_Parse(
+    const ::std::string& name, Field_Kind* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<Field_Kind>(
+    Field_Kind_descriptor(), name, value);
+}
+enum Field_Cardinality {
+  Field_Cardinality_CARDINALITY_UNKNOWN = 0,
+  Field_Cardinality_CARDINALITY_OPTIONAL = 1,
+  Field_Cardinality_CARDINALITY_REQUIRED = 2,
+  Field_Cardinality_CARDINALITY_REPEATED = 3,
+  Field_Cardinality_Field_Cardinality_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,
+  Field_Cardinality_Field_Cardinality_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max
+};
+LIBPROTOBUF_EXPORT bool Field_Cardinality_IsValid(int value);
+const Field_Cardinality Field_Cardinality_Cardinality_MIN = Field_Cardinality_CARDINALITY_UNKNOWN;
+const Field_Cardinality Field_Cardinality_Cardinality_MAX = Field_Cardinality_CARDINALITY_REPEATED;
+const int Field_Cardinality_Cardinality_ARRAYSIZE = Field_Cardinality_Cardinality_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor();
+inline const ::std::string& Field_Cardinality_Name(Field_Cardinality value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    Field_Cardinality_descriptor(), value);
+}
+inline bool Field_Cardinality_Parse(
+    const ::std::string& name, Field_Cardinality* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<Field_Cardinality>(
+    Field_Cardinality_descriptor(), name, value);
+}
+enum Syntax {
+  SYNTAX_PROTO2 = 0,
+  SYNTAX_PROTO3 = 1,
+  Syntax_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,
+  Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max
+};
+LIBPROTOBUF_EXPORT bool Syntax_IsValid(int value);
+const Syntax Syntax_MIN = SYNTAX_PROTO2;
+const Syntax Syntax_MAX = SYNTAX_PROTO3;
+const int Syntax_ARRAYSIZE = Syntax_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Syntax_descriptor();
+inline const ::std::string& Syntax_Name(Syntax value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    Syntax_descriptor(), value);
+}
+inline bool Syntax_Parse(
+    const ::std::string& name, Syntax* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<Syntax>(
+    Syntax_descriptor(), name, value);
+}
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message {
+ public:
+  Type();
+  virtual ~Type();
+
+  Type(const Type& from);
+
+  inline Type& operator=(const Type& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Type& default_instance();
+
+  void Swap(Type* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Type* New() const { return New(NULL); }
+
+  Type* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Type& from);
+  void MergeFrom(const Type& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Type* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // repeated .google.protobuf.Field fields = 2;
+  int fields_size() const;
+  void clear_fields();
+  static const int kFieldsFieldNumber = 2;
+  const ::google::protobuf::Field& fields(int index) const;
+  ::google::protobuf::Field* mutable_fields(int index);
+  ::google::protobuf::Field* add_fields();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >*
+      mutable_fields();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >&
+      fields() const;
+
+  // repeated string oneofs = 3;
+  int oneofs_size() const;
+  void clear_oneofs();
+  static const int kOneofsFieldNumber = 3;
+  const ::std::string& oneofs(int index) const;
+  ::std::string* mutable_oneofs(int index);
+  void set_oneofs(int index, const ::std::string& value);
+  void set_oneofs(int index, const char* value);
+  void set_oneofs(int index, const char* value, size_t size);
+  ::std::string* add_oneofs();
+  void add_oneofs(const ::std::string& value);
+  void add_oneofs(const char* value);
+  void add_oneofs(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& oneofs() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_oneofs();
+
+  // repeated .google.protobuf.Option options = 4;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 4;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // optional .google.protobuf.SourceContext source_context = 5;
+  bool has_source_context() const;
+  void clear_source_context();
+  static const int kSourceContextFieldNumber = 5;
+  const ::google::protobuf::SourceContext& source_context() const;
+  ::google::protobuf::SourceContext* mutable_source_context();
+  ::google::protobuf::SourceContext* release_source_context();
+  void set_allocated_source_context(::google::protobuf::SourceContext* source_context);
+
+  // optional .google.protobuf.Syntax syntax = 6;
+  void clear_syntax();
+  static const int kSyntaxFieldNumber = 6;
+  ::google::protobuf::Syntax syntax() const;
+  void set_syntax(::google::protobuf::Syntax value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Type)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field > fields_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> oneofs_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  ::google::protobuf::SourceContext* source_context_;
+  int syntax_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+  void InitAsDefaultInstance();
+  static Type* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
+ public:
+  Field();
+  virtual ~Field();
+
+  Field(const Field& from);
+
+  inline Field& operator=(const Field& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Field& default_instance();
+
+  void Swap(Field* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Field* New() const { return New(NULL); }
+
+  Field* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Field& from);
+  void MergeFrom(const Field& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Field* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef Field_Kind Kind;
+  static const Kind TYPE_UNKNOWN =
+    Field_Kind_TYPE_UNKNOWN;
+  static const Kind TYPE_DOUBLE =
+    Field_Kind_TYPE_DOUBLE;
+  static const Kind TYPE_FLOAT =
+    Field_Kind_TYPE_FLOAT;
+  static const Kind TYPE_INT64 =
+    Field_Kind_TYPE_INT64;
+  static const Kind TYPE_UINT64 =
+    Field_Kind_TYPE_UINT64;
+  static const Kind TYPE_INT32 =
+    Field_Kind_TYPE_INT32;
+  static const Kind TYPE_FIXED64 =
+    Field_Kind_TYPE_FIXED64;
+  static const Kind TYPE_FIXED32 =
+    Field_Kind_TYPE_FIXED32;
+  static const Kind TYPE_BOOL =
+    Field_Kind_TYPE_BOOL;
+  static const Kind TYPE_STRING =
+    Field_Kind_TYPE_STRING;
+  static const Kind TYPE_GROUP =
+    Field_Kind_TYPE_GROUP;
+  static const Kind TYPE_MESSAGE =
+    Field_Kind_TYPE_MESSAGE;
+  static const Kind TYPE_BYTES =
+    Field_Kind_TYPE_BYTES;
+  static const Kind TYPE_UINT32 =
+    Field_Kind_TYPE_UINT32;
+  static const Kind TYPE_ENUM =
+    Field_Kind_TYPE_ENUM;
+  static const Kind TYPE_SFIXED32 =
+    Field_Kind_TYPE_SFIXED32;
+  static const Kind TYPE_SFIXED64 =
+    Field_Kind_TYPE_SFIXED64;
+  static const Kind TYPE_SINT32 =
+    Field_Kind_TYPE_SINT32;
+  static const Kind TYPE_SINT64 =
+    Field_Kind_TYPE_SINT64;
+  static inline bool Kind_IsValid(int value) {
+    return Field_Kind_IsValid(value);
+  }
+  static const Kind Kind_MIN =
+    Field_Kind_Kind_MIN;
+  static const Kind Kind_MAX =
+    Field_Kind_Kind_MAX;
+  static const int Kind_ARRAYSIZE =
+    Field_Kind_Kind_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Kind_descriptor() {
+    return Field_Kind_descriptor();
+  }
+  static inline const ::std::string& Kind_Name(Kind value) {
+    return Field_Kind_Name(value);
+  }
+  static inline bool Kind_Parse(const ::std::string& name,
+      Kind* value) {
+    return Field_Kind_Parse(name, value);
+  }
+
+  typedef Field_Cardinality Cardinality;
+  static const Cardinality CARDINALITY_UNKNOWN =
+    Field_Cardinality_CARDINALITY_UNKNOWN;
+  static const Cardinality CARDINALITY_OPTIONAL =
+    Field_Cardinality_CARDINALITY_OPTIONAL;
+  static const Cardinality CARDINALITY_REQUIRED =
+    Field_Cardinality_CARDINALITY_REQUIRED;
+  static const Cardinality CARDINALITY_REPEATED =
+    Field_Cardinality_CARDINALITY_REPEATED;
+  static inline bool Cardinality_IsValid(int value) {
+    return Field_Cardinality_IsValid(value);
+  }
+  static const Cardinality Cardinality_MIN =
+    Field_Cardinality_Cardinality_MIN;
+  static const Cardinality Cardinality_MAX =
+    Field_Cardinality_Cardinality_MAX;
+  static const int Cardinality_ARRAYSIZE =
+    Field_Cardinality_Cardinality_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Cardinality_descriptor() {
+    return Field_Cardinality_descriptor();
+  }
+  static inline const ::std::string& Cardinality_Name(Cardinality value) {
+    return Field_Cardinality_Name(value);
+  }
+  static inline bool Cardinality_Parse(const ::std::string& name,
+      Cardinality* value) {
+    return Field_Cardinality_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .google.protobuf.Field.Kind kind = 1;
+  void clear_kind();
+  static const int kKindFieldNumber = 1;
+  ::google::protobuf::Field_Kind kind() const;
+  void set_kind(::google::protobuf::Field_Kind value);
+
+  // optional .google.protobuf.Field.Cardinality cardinality = 2;
+  void clear_cardinality();
+  static const int kCardinalityFieldNumber = 2;
+  ::google::protobuf::Field_Cardinality cardinality() const;
+  void set_cardinality(::google::protobuf::Field_Cardinality value);
+
+  // optional int32 number = 3;
+  void clear_number();
+  static const int kNumberFieldNumber = 3;
+  ::google::protobuf::int32 number() const;
+  void set_number(::google::protobuf::int32 value);
+
+  // optional string name = 4;
+  void clear_name();
+  static const int kNameFieldNumber = 4;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional string type_url = 6;
+  void clear_type_url();
+  static const int kTypeUrlFieldNumber = 6;
+  const ::std::string& type_url() const;
+  void set_type_url(const ::std::string& value);
+  void set_type_url(const char* value);
+  void set_type_url(const char* value, size_t size);
+  ::std::string* mutable_type_url();
+  ::std::string* release_type_url();
+  void set_allocated_type_url(::std::string* type_url);
+
+  // optional int32 oneof_index = 7;
+  void clear_oneof_index();
+  static const int kOneofIndexFieldNumber = 7;
+  ::google::protobuf::int32 oneof_index() const;
+  void set_oneof_index(::google::protobuf::int32 value);
+
+  // optional bool packed = 8;
+  void clear_packed();
+  static const int kPackedFieldNumber = 8;
+  bool packed() const;
+  void set_packed(bool value);
+
+  // repeated .google.protobuf.Option options = 9;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 9;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // optional string json_name = 10;
+  void clear_json_name();
+  static const int kJsonNameFieldNumber = 10;
+  const ::std::string& json_name() const;
+  void set_json_name(const ::std::string& value);
+  void set_json_name(const char* value);
+  void set_json_name(const char* value, size_t size);
+  ::std::string* mutable_json_name();
+  ::std::string* release_json_name();
+  void set_allocated_json_name(::std::string* json_name);
+
+  // optional string default_value = 11;
+  void clear_default_value();
+  static const int kDefaultValueFieldNumber = 11;
+  const ::std::string& default_value() const;
+  void set_default_value(const ::std::string& value);
+  void set_default_value(const char* value);
+  void set_default_value(const char* value, size_t size);
+  ::std::string* mutable_default_value();
+  ::std::string* release_default_value();
+  void set_allocated_default_value(::std::string* default_value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Field)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  int kind_;
+  int cardinality_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::int32 number_;
+  ::google::protobuf::int32 oneof_index_;
+  ::google::protobuf::internal::ArenaStringPtr type_url_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  ::google::protobuf::internal::ArenaStringPtr json_name_;
+  ::google::protobuf::internal::ArenaStringPtr default_value_;
+  bool packed_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+  void InitAsDefaultInstance();
+  static Field* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message {
+ public:
+  Enum();
+  virtual ~Enum();
+
+  Enum(const Enum& from);
+
+  inline Enum& operator=(const Enum& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Enum& default_instance();
+
+  void Swap(Enum* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Enum* New() const { return New(NULL); }
+
+  Enum* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Enum& from);
+  void MergeFrom(const Enum& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Enum* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // repeated .google.protobuf.EnumValue enumvalue = 2;
+  int enumvalue_size() const;
+  void clear_enumvalue();
+  static const int kEnumvalueFieldNumber = 2;
+  const ::google::protobuf::EnumValue& enumvalue(int index) const;
+  ::google::protobuf::EnumValue* mutable_enumvalue(int index);
+  ::google::protobuf::EnumValue* add_enumvalue();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >*
+      mutable_enumvalue();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >&
+      enumvalue() const;
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 3;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // optional .google.protobuf.SourceContext source_context = 4;
+  bool has_source_context() const;
+  void clear_source_context();
+  static const int kSourceContextFieldNumber = 4;
+  const ::google::protobuf::SourceContext& source_context() const;
+  ::google::protobuf::SourceContext* mutable_source_context();
+  ::google::protobuf::SourceContext* release_source_context();
+  void set_allocated_source_context(::google::protobuf::SourceContext* source_context);
+
+  // optional .google.protobuf.Syntax syntax = 5;
+  void clear_syntax();
+  static const int kSyntaxFieldNumber = 5;
+  ::google::protobuf::Syntax syntax() const;
+  void set_syntax(::google::protobuf::Syntax value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Enum)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue > enumvalue_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  ::google::protobuf::SourceContext* source_context_;
+  int syntax_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+  void InitAsDefaultInstance();
+  static Enum* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message {
+ public:
+  EnumValue();
+  virtual ~EnumValue();
+
+  EnumValue(const EnumValue& from);
+
+  inline EnumValue& operator=(const EnumValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const EnumValue& default_instance();
+
+  void Swap(EnumValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline EnumValue* New() const { return New(NULL); }
+
+  EnumValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const EnumValue& from);
+  void MergeFrom(const EnumValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(EnumValue* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional int32 number = 2;
+  void clear_number();
+  static const int kNumberFieldNumber = 2;
+  ::google::protobuf::int32 number() const;
+  void set_number(::google::protobuf::int32 value);
+
+  // repeated .google.protobuf.Option options = 3;
+  int options_size() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 3;
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* mutable_options(int index);
+  ::google::protobuf::Option* add_options();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+      mutable_options();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+      options() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.EnumValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
+  ::google::protobuf::int32 number_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+  void InitAsDefaultInstance();
+  static EnumValue* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message {
+ public:
+  Option();
+  virtual ~Option();
+
+  Option(const Option& from);
+
+  inline Option& operator=(const Option& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Option& default_instance();
+
+  void Swap(Option* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Option* New() const { return New(NULL); }
+
+  Option* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Option& from);
+  void MergeFrom(const Option& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Option* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional .google.protobuf.Any value = 2;
+  bool has_value() const;
+  void clear_value();
+  static const int kValueFieldNumber = 2;
+  const ::google::protobuf::Any& value() const;
+  ::google::protobuf::Any* mutable_value();
+  ::google::protobuf::Any* release_value();
+  void set_allocated_value(::google::protobuf::Any* value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Option)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::Any* value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto();
+
+  void InitAsDefaultInstance();
+  static Option* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// Type
+
+// optional string name = 1;
+inline void Type::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Type::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Type::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.name)
+}
+inline void Type::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Type.name)
+}
+inline void Type::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.name)
+}
+inline ::std::string* Type::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Type::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Type::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.name)
+}
+
+// repeated .google.protobuf.Field fields = 2;
+inline int Type::fields_size() const {
+  return fields_.size();
+}
+inline void Type::clear_fields() {
+  fields_.Clear();
+}
+inline const ::google::protobuf::Field& Type::fields(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.fields)
+  return fields_.Get(index);
+}
+inline ::google::protobuf::Field* Type::mutable_fields(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.fields)
+  return fields_.Mutable(index);
+}
+inline ::google::protobuf::Field* Type::add_fields() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.fields)
+  return fields_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >*
+Type::mutable_fields() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields)
+  return &fields_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >&
+Type::fields() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.fields)
+  return fields_;
+}
+
+// repeated string oneofs = 3;
+inline int Type::oneofs_size() const {
+  return oneofs_.size();
+}
+inline void Type::clear_oneofs() {
+  oneofs_.Clear();
+}
+inline const ::std::string& Type::oneofs(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.oneofs)
+  return oneofs_.Get(index);
+}
+inline ::std::string* Type::mutable_oneofs(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.oneofs)
+  return oneofs_.Mutable(index);
+}
+inline void Type::set_oneofs(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.oneofs)
+  oneofs_.Mutable(index)->assign(value);
+}
+inline void Type::set_oneofs(int index, const char* value) {
+  oneofs_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Type.oneofs)
+}
+inline void Type::set_oneofs(int index, const char* value, size_t size) {
+  oneofs_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs)
+}
+inline ::std::string* Type::add_oneofs() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs)
+  return oneofs_.Add();
+}
+inline void Type::add_oneofs(const ::std::string& value) {
+  oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(const char* value) {
+  oneofs_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.Type.oneofs)
+}
+inline void Type::add_oneofs(const char* value, size_t size) {
+  oneofs_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.Type.oneofs)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+Type::oneofs() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.oneofs)
+  return oneofs_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+Type::mutable_oneofs() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.oneofs)
+  return &oneofs_;
+}
+
+// repeated .google.protobuf.Option options = 4;
+inline int Type::options_size() const {
+  return options_.size();
+}
+inline void Type::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& Type::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Type::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* Type::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Type.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Type::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Type::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Type.options)
+  return options_;
+}
+
+// optional .google.protobuf.SourceContext source_context = 5;
+inline bool Type::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+inline void Type::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+inline const ::google::protobuf::SourceContext& Type::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+inline ::google::protobuf::SourceContext* Type::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Type.source_context)
+  return source_context_;
+}
+inline ::google::protobuf::SourceContext* Type::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+inline void Type::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context)
+}
+
+// optional .google.protobuf.Syntax syntax = 6;
+inline void Type::clear_syntax() {
+  syntax_ = 0;
+}
+inline ::google::protobuf::Syntax Type::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+inline void Type::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// Field
+
+// optional .google.protobuf.Field.Kind kind = 1;
+inline void Field::clear_kind() {
+  kind_ = 0;
+}
+inline ::google::protobuf::Field_Kind Field::kind() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.kind)
+  return static_cast< ::google::protobuf::Field_Kind >(kind_);
+}
+inline void Field::set_kind(::google::protobuf::Field_Kind value) {
+  
+  kind_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.kind)
+}
+
+// optional .google.protobuf.Field.Cardinality cardinality = 2;
+inline void Field::clear_cardinality() {
+  cardinality_ = 0;
+}
+inline ::google::protobuf::Field_Cardinality Field::cardinality() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.cardinality)
+  return static_cast< ::google::protobuf::Field_Cardinality >(cardinality_);
+}
+inline void Field::set_cardinality(::google::protobuf::Field_Cardinality value) {
+  
+  cardinality_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.cardinality)
+}
+
+// optional int32 number = 3;
+inline void Field::clear_number() {
+  number_ = 0;
+}
+inline ::google::protobuf::int32 Field::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.number)
+  return number_;
+}
+inline void Field::set_number(::google::protobuf::int32 value) {
+  
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.number)
+}
+
+// optional string name = 4;
+inline void Field::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.name)
+}
+inline void Field::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.name)
+}
+inline void Field::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.name)
+}
+inline ::std::string* Field::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.name)
+}
+
+// optional string type_url = 6;
+inline void Field::clear_type_url() {
+  type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::type_url() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.type_url)
+  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_type_url(const ::std::string& value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.type_url)
+}
+inline void Field::set_type_url(const char* value) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.type_url)
+}
+inline void Field::set_type_url(const char* value, size_t size) {
+  
+  type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.type_url)
+}
+inline ::std::string* Field::mutable_type_url() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.type_url)
+  return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_type_url() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url)
+  
+  return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_type_url(::std::string* type_url) {
+  if (type_url != NULL) {
+    
+  } else {
+    
+  }
+  type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.type_url)
+}
+
+// optional int32 oneof_index = 7;
+inline void Field::clear_oneof_index() {
+  oneof_index_ = 0;
+}
+inline ::google::protobuf::int32 Field::oneof_index() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.oneof_index)
+  return oneof_index_;
+}
+inline void Field::set_oneof_index(::google::protobuf::int32 value) {
+  
+  oneof_index_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.oneof_index)
+}
+
+// optional bool packed = 8;
+inline void Field::clear_packed() {
+  packed_ = false;
+}
+inline bool Field::packed() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.packed)
+  return packed_;
+}
+inline void Field::set_packed(bool value) {
+  
+  packed_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.packed)
+}
+
+// repeated .google.protobuf.Option options = 9;
+inline int Field::options_size() const {
+  return options_.size();
+}
+inline void Field::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& Field::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Field::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* Field::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Field.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Field::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Field::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Field.options)
+  return options_;
+}
+
+// optional string json_name = 10;
+inline void Field::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_json_name(const ::std::string& value) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name)
+}
+inline void Field::set_json_name(const char* value) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.json_name)
+}
+inline void Field::set_json_name(const char* value, size_t size) {
+  
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.json_name)
+}
+inline ::std::string* Field::mutable_json_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_json_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name)
+  
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    
+  } else {
+    
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
+}
+
+// optional string default_value = 11;
+inline void Field::clear_default_value() {
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_default_value(const ::std::string& value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value, size_t size) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+inline ::std::string* Field::mutable_default_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_default_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value)
+  
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_default_value(::std::string* default_value) {
+  if (default_value != NULL) {
+    
+  } else {
+    
+  }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
+// -------------------------------------------------------------------
+
+// Enum
+
+// optional string name = 1;
+inline void Enum::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Enum::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Enum::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.name)
+}
+inline void Enum::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Enum.name)
+}
+inline void Enum::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Enum.name)
+}
+inline ::std::string* Enum::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Enum::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Enum::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.name)
+}
+
+// repeated .google.protobuf.EnumValue enumvalue = 2;
+inline int Enum::enumvalue_size() const {
+  return enumvalue_.size();
+}
+inline void Enum::clear_enumvalue() {
+  enumvalue_.Clear();
+}
+inline const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Get(index);
+}
+inline ::google::protobuf::EnumValue* Enum::mutable_enumvalue(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Mutable(index);
+}
+inline ::google::protobuf::EnumValue* Enum::add_enumvalue() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue)
+  return enumvalue_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >*
+Enum::mutable_enumvalue() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue)
+  return &enumvalue_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >&
+Enum::enumvalue() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue)
+  return enumvalue_;
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int Enum::options_size() const {
+  return options_.size();
+}
+inline void Enum::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& Enum::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Enum::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* Enum::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Enum.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+Enum::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+Enum::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.Enum.options)
+  return options_;
+}
+
+// optional .google.protobuf.SourceContext source_context = 4;
+inline bool Enum::has_source_context() const {
+  return !_is_default_instance_ && source_context_ != NULL;
+}
+inline void Enum::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
+  source_context_ = NULL;
+}
+inline const ::google::protobuf::SourceContext& Enum::source_context() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.source_context)
+  return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_;
+}
+inline ::google::protobuf::SourceContext* Enum::mutable_source_context() {
+  
+  if (source_context_ == NULL) {
+    source_context_ = new ::google::protobuf::SourceContext;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.source_context)
+  return source_context_;
+}
+inline ::google::protobuf::SourceContext* Enum::release_source_context() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context)
+  
+  ::google::protobuf::SourceContext* temp = source_context_;
+  source_context_ = NULL;
+  return temp;
+}
+inline void Enum::set_allocated_source_context(::google::protobuf::SourceContext* source_context) {
+  delete source_context_;
+  source_context_ = source_context;
+  if (source_context) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context)
+}
+
+// optional .google.protobuf.Syntax syntax = 5;
+inline void Enum::clear_syntax() {
+  syntax_ = 0;
+}
+inline ::google::protobuf::Syntax Enum::syntax() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax)
+  return static_cast< ::google::protobuf::Syntax >(syntax_);
+}
+inline void Enum::set_syntax(::google::protobuf::Syntax value) {
+  
+  syntax_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax)
+}
+
+// -------------------------------------------------------------------
+
+// EnumValue
+
+// optional string name = 1;
+inline void EnumValue::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& EnumValue::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void EnumValue::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.name)
+}
+inline void EnumValue::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.EnumValue.name)
+}
+inline void EnumValue::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.EnumValue.name)
+}
+inline ::std::string* EnumValue::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* EnumValue::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void EnumValue::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.EnumValue.name)
+}
+
+// optional int32 number = 2;
+inline void EnumValue::clear_number() {
+  number_ = 0;
+}
+inline ::google::protobuf::int32 EnumValue::number() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.number)
+  return number_;
+}
+inline void EnumValue::set_number(::google::protobuf::int32 value) {
+  
+  number_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.EnumValue.number)
+}
+
+// repeated .google.protobuf.Option options = 3;
+inline int EnumValue::options_size() const {
+  return options_.size();
+}
+inline void EnumValue::clear_options() {
+  options_.Clear();
+}
+inline const ::google::protobuf::Option& EnumValue::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* EnumValue::mutable_options(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.options)
+  return options_.Mutable(index);
+}
+inline ::google::protobuf::Option* EnumValue::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options)
+  return options_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
+EnumValue::mutable_options() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options)
+  return &options_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
+EnumValue::options() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options)
+  return options_;
+}
+
+// -------------------------------------------------------------------
+
+// Option
+
+// optional string name = 1;
+inline void Option::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Option::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Option::set_name(const ::std::string& value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Option.name)
+}
+inline void Option::set_name(const char* value) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Option.name)
+}
+inline void Option::set_name(const char* value, size_t size) {
+  
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Option.name)
+}
+inline ::std::string* Option::mutable_name() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Option::release_name() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.name)
+  
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Option::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    
+  } else {
+    
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.name)
+}
+
+// optional .google.protobuf.Any value = 2;
+inline bool Option::has_value() const {
+  return !_is_default_instance_ && value_ != NULL;
+}
+inline void Option::clear_value() {
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
+  value_ = NULL;
+}
+inline const ::google::protobuf::Any& Option::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Option.value)
+  return value_ != NULL ? *value_ : *default_instance_->value_;
+}
+inline ::google::protobuf::Any* Option::mutable_value() {
+  
+  if (value_ == NULL) {
+    value_ = new ::google::protobuf::Any;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Option.value)
+  return value_;
+}
+inline ::google::protobuf::Any* Option::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.Option.value)
+  
+  ::google::protobuf::Any* temp = value_;
+  value_ = NULL;
+  return temp;
+}
+inline void Option::set_allocated_value(::google::protobuf::Any* value) {
+  delete value_;
+  value_ = value;
+  if (value) {
+    
+  } else {
+    
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Option.value)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <> struct is_proto_enum< ::google::protobuf::Field_Kind> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::Field_Kind>() {
+  return ::google::protobuf::Field_Kind_descriptor();
+}
+template <> struct is_proto_enum< ::google::protobuf::Field_Cardinality> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::Field_Cardinality>() {
+  return ::google::protobuf::Field_Cardinality_descriptor();
+}
+template <> struct is_proto_enum< ::google::protobuf::Syntax> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::Syntax>() {
+  return ::google::protobuf::Syntax_descriptor();
+}
+
+}  // namespace protobuf
+}  // namespace google
+#endif  // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2ftype_2eproto__INCLUDED
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
new file mode 100644
index 0000000..1c9cf53
--- /dev/null
+++ b/src/google/protobuf/type.proto
@@ -0,0 +1,180 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/source_context.proto";
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TypeProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// A protocol buffer message type.
+message Type {
+  // The fully qualified message name.
+  string name = 1;
+  // The list of fields.
+  repeated Field fields = 2;
+  // The list of types appearing in `oneof` definitions in this type.
+  repeated string oneofs = 3;
+  // The protocol buffer options.
+  repeated Option options = 4;
+  // The source context.
+  SourceContext source_context = 5;
+  // The source syntax.
+  Syntax syntax = 6;
+}
+
+// A single field of a message type.
+message Field {
+  // Basic field types.
+  enum Kind {
+    // Field type unknown.
+    TYPE_UNKNOWN        = 0;
+    // Field type double.
+    TYPE_DOUBLE         = 1;
+    // Field type float.
+    TYPE_FLOAT          = 2;
+    // Field type int64.
+    TYPE_INT64          = 3;
+    // Field type uint64.
+    TYPE_UINT64         = 4;
+    // Field type int32.
+    TYPE_INT32          = 5;
+    // Field type fixed64.
+    TYPE_FIXED64        = 6;
+    // Field type fixed32.
+    TYPE_FIXED32        = 7;
+    // Field type bool.
+    TYPE_BOOL           = 8;
+    // Field type string.
+    TYPE_STRING         = 9;
+    // Field type group. Proto2 syntax only, and deprecated.
+    TYPE_GROUP          = 10;
+    // Field type message.
+    TYPE_MESSAGE        = 11;
+    // Field type bytes.
+    TYPE_BYTES          = 12;
+    // Field type uint32.
+    TYPE_UINT32         = 13;
+    // Field type enum.
+    TYPE_ENUM           = 14;
+    // Field type sfixed32.
+    TYPE_SFIXED32       = 15;
+    // Field type sfixed64.
+    TYPE_SFIXED64       = 16;
+    // Field type sint32.
+    TYPE_SINT32         = 17;
+    // Field type sint64.
+    TYPE_SINT64         = 18;
+  };
+
+  // Whether a field is optional, required, or repeated.
+  enum Cardinality {
+    // For fields with unknown cardinality.
+    CARDINALITY_UNKNOWN = 0;
+    // For optional fields.
+    CARDINALITY_OPTIONAL = 1;
+    // For required fields. Proto2 syntax only.
+    CARDINALITY_REQUIRED = 2;
+    // For repeated fields.
+    CARDINALITY_REPEATED = 3;
+  };
+
+  // The field type.
+  Kind kind = 1;
+  // The field cardinality.
+  Cardinality cardinality = 2;
+  // The field number.
+  int32 number = 3;
+  // The field name.
+  string name = 4;
+  // The field type URL, without the scheme, for message or enumeration
+  // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+  string type_url = 6;
+  // The index of the field type in `Type.oneofs`, for message or enumeration
+  // types. The first type has index 1; zero means the type is not in the list.
+  int32 oneof_index = 7;
+  // Whether to use alternative packed wire representation.
+  bool packed = 8;
+  // The protocol buffer options.
+  repeated Option options = 9;
+  // The field JSON name.
+  string json_name = 10;
+  // The string value of the default value of this field. Proto2 syntax only.
+  string default_value = 11;
+}
+
+// Enum type definition.
+message Enum {
+  // Enum type name.
+  string name = 1;
+  // Enum value definitions.
+  repeated EnumValue enumvalue = 2;
+  // Protocol buffer options.
+  repeated Option options = 3;
+  // The source context.
+  SourceContext source_context = 4;
+  // The source syntax.
+  Syntax syntax = 5;
+}
+
+// Enum value definition.
+message EnumValue {
+  // Enum value name.
+  string name = 1;
+  // Enum value number.
+  int32 number = 2;
+  // Protocol buffer options.
+  repeated Option options = 3;
+}
+
+// A protocol buffer option, which can be attached to a message, field,
+// enumeration, etc.
+message Option {
+  // The option's name. For example, `"java_package"`.
+  string name = 1;
+  // The option's value. For example, `"com.google.protobuf"`.
+  Any value = 2;
+}
+
+// The syntax in which a protocol buffer element is defined.
+enum Syntax {
+  // Syntax `proto2`.
+  SYNTAX_PROTO2 = 0;
+  // Syntax `proto3`.
+  SYNTAX_PROTO3 = 1;
+}
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index c48cc92..da56ae0 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -34,12 +34,14 @@
 //
 // A proto file we will use for unit testing.
 
+syntax = "proto2";
 
 // Some generic_services option(s) added automatically.
 // See:  http://go/proto2-generic-services-default
 option cc_generic_services = true;     // auto-added
 option java_generic_services = true;   // auto-added
 option py_generic_services = true;     // auto-added
+option cc_enable_arenas = true;
 
 import "google/protobuf/unittest_import.proto";
 
@@ -182,6 +184,7 @@
 message NestedTestAllTypes {
   optional NestedTestAllTypes child = 1;
   optional TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
 }
 
 message TestDeprecatedFields {
@@ -200,6 +203,11 @@
   FOREIGN_BAZ = 6;
 }
 
+message TestReservedFields {
+  reserved 2, 15, 9 to 11;
+  reserved "bar", "baz";
+}
+
 message TestAllExtensions {
   extensions 1 to max;
 }
@@ -429,7 +437,7 @@
 }
 
 // Test that groups have disjoint field numbers from their siblings and
-// parents.  This is NOT possible in proto1; only proto2.  When attempting
+// parents.  This is NOT possible in proto1; only google.protobuf.  When attempting
 // to compile with proto1, this will emit an error; so we only include it
 // in protobuf_unittest_proto.
 message TestDupFieldNumber {                        // NO_PROTO1
@@ -505,6 +513,15 @@
   optional int64 my_int = 1;
   extensions 12 to 100;
   optional float my_float = 101;
+  message NestedMessage {
+    optional int64 oo = 2;
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  optional NestedMessage optional_nested_message  = 200;
 }
 
 
@@ -679,6 +696,7 @@
   }
 }
 
+
 // Test messages for packed fields
 
 message TestPackedTypes {
diff --git a/src/google/protobuf/unittest_accessors_nano.proto b/src/google/protobuf/unittest_accessors_nano.proto
deleted file mode 100644
index f1d4d34..0000000
--- a/src/google/protobuf/unittest_accessors_nano.proto
+++ /dev/null
@@ -1,118 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "NanoAccessorsOuterClass";
-
-message TestNanoAccessors {
-
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  // Singular
-  optional int32  optional_int32    =  1;
-  optional float  optional_float    = 11;
-  optional double optional_double   = 12;
-  optional string optional_string   = 14;
-  optional bytes  optional_bytes    = 15;
-
-  optional NestedMessage optional_nested_message = 18;
-
-  optional NestedEnum optional_nested_enum = 21;
-
-  // Repeated
-  repeated int32  repeated_int32    = 31;
-  repeated string repeated_string   = 44;
-  repeated bytes  repeated_bytes    = 45;
-
-  repeated NestedMessage repeated_nested_message  = 48;
-
-  repeated NestedEnum repeated_nested_enum  = 51;
-
-  // Singular with defaults
-  optional int32  default_int32    = 61 [default =  41    ];
-  optional string default_string   = 74 [default = "hello"];
-  optional bytes  default_bytes    = 75 [default = "world"];
-
-  optional float default_float_nan = 99  [default =  nan];
-
-  optional NestedEnum default_nested_enum = 81 [default = BAR];
-
-  // Required
-  required int32 id = 86;
-
-  // Add enough optional fields to make 2 bit fields in total
-  optional int32 filler100 = 100;
-  optional int32 filler101 = 101;
-  optional int32 filler102 = 102;
-  optional int32 filler103 = 103;
-  optional int32 filler104 = 104;
-  optional int32 filler105 = 105;
-  optional int32 filler106 = 106;
-  optional int32 filler107 = 107;
-  optional int32 filler108 = 108;
-  optional int32 filler109 = 109;
-  optional int32 filler110 = 110;
-  optional int32 filler111 = 111;
-  optional int32 filler112 = 112;
-  optional int32 filler113 = 113;
-  optional int32 filler114 = 114;
-  optional int32 filler115 = 115;
-  optional int32 filler116 = 116;
-  optional int32 filler117 = 117;
-  optional int32 filler118 = 118;
-  optional int32 filler119 = 119;
-  optional int32 filler120 = 120;
-  optional int32 filler121 = 121;
-  optional int32 filler122 = 122;
-  optional int32 filler123 = 123;
-  optional int32 filler124 = 124;
-  optional int32 filler125 = 125;
-  optional int32 filler126 = 126;
-  optional int32 filler127 = 127;
-  optional int32 filler128 = 128;
-  optional int32 filler129 = 129;
-  optional int32 filler130 = 130;
-
-  optional int32 before_bit_field_check = 139;
-  optional int32 bit_field_check = 140;
-  optional int32 after_bit_field_check = 141;
-}
diff --git a/src/google/protobuf/unittest_arena.proto b/src/google/protobuf/unittest_arena.proto
new file mode 100644
index 0000000..cd7e437
--- /dev/null
+++ b/src/google/protobuf/unittest_arena.proto
@@ -0,0 +1,46 @@
+// 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.
+
+syntax = "proto2";
+
+import "google/protobuf/unittest_no_arena_import.proto";
+
+package proto2_arena_unittest;
+
+option cc_enable_arenas = true;
+
+message NestedMessage {
+  optional int32 d = 1;
+}
+
+message ArenaMessage {
+  repeated NestedMessage  repeated_nested_message = 1;
+  repeated ImportNoArenaNestedMessage  repeated_import_no_arena_message = 2;
+};
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index 0bb12e1..4cc0e36 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -32,8 +32,9 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //
-// A proto file used to test the "custom options" feature of proto2.
+// A proto file used to test the "custom options" feature of google.protobuf.
 
+syntax = "proto2";
 
 // Some generic_services option(s) added automatically.
 // See:  http://go/proto2-generic-services-default
@@ -391,3 +392,30 @@
     optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
   }
 }
+
+// Custom message option that has a required enum field.
+// WARNING: this is strongly discouraged!
+message OldOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+  }
+  required TestEnum value = 1;
+}
+
+// Updated version of the custom option above.
+message NewOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+    NEW_VALUE = 1;
+  }
+  required TestEnum value = 1;
+}
+
+extend google.protobuf.MessageOptions {
+  optional OldOptionType required_enum_opt = 106161807;
+}
+
+// Test message using the "required_enum_opt" option defined above.
+message TestMessageWithRequiredEnumOption {
+  option (required_enum_opt) = { value: OLD_VALUE };
+}
diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto
new file mode 100644
index 0000000..8aa3a37
--- /dev/null
+++ b/src/google/protobuf/unittest_drop_unknown_fields.proto
@@ -0,0 +1,58 @@
+// 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.
+
+syntax = "proto3";
+
+package unittest_drop_unknown_fields;
+option objc_class_prefix = "DropUnknowns";
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+message Foo {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+}
+
+message FooWithExtraFields {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+    QUX = 3;
+  }
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+  int32 extra_int32_value = 3;
+}
diff --git a/src/google/protobuf/unittest_embed_optimize_for.proto b/src/google/protobuf/unittest_embed_optimize_for.proto
index ad51513..d8b0f9b 100644
--- a/src/google/protobuf/unittest_embed_optimize_for.proto
+++ b/src/google/protobuf/unittest_embed_optimize_for.proto
@@ -34,6 +34,7 @@
 //
 // A proto file which imports a proto file that uses optimize_for = CODE_SIZE.
 
+syntax = "proto2";
 import "google/protobuf/unittest_optimize_for.proto";
 
 package protobuf_unittest;
diff --git a/src/google/protobuf/unittest_empty.proto b/src/google/protobuf/unittest_empty.proto
index b7337ef..36443e7 100644
--- a/src/google/protobuf/unittest_empty.proto
+++ b/src/google/protobuf/unittest_empty.proto
@@ -35,3 +35,4 @@
 // This file intentionally left blank.  (At one point this wouldn't compile
 // correctly.)
 
+syntax = "proto2";
diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto
index 3ba8b41..6e65dc1 100644
--- a/src/google/protobuf/unittest_enormous_descriptor.proto
+++ b/src/google/protobuf/unittest_enormous_descriptor.proto
@@ -33,8 +33,10 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //
 // A proto file that has an extremely large descriptor.  Used to test that
-// descriptors over 64k don't break the string literal length limit in Java.
+// descriptors over 64k don't break language-specific limits in generated code,
+// such as the string literal length limit in Java.
 
+syntax = "proto2";
 
 package google.protobuf;
 option java_package = "com.google.protobuf";
diff --git a/src/google/protobuf/unittest_enum_class_multiple_nano.proto b/src/google/protobuf/unittest_enum_class_multiple_nano.proto
deleted file mode 100644
index 8adb756..0000000
--- a/src/google/protobuf/unittest_enum_class_multiple_nano.proto
+++ /dev/null
@@ -1,48 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_multiple_files = true;
-
-enum FileScopeEnumMultiple {
-  THREE = 3;
-}
-
-message EnumClassNanoMultiple {
-  enum MessageScopeEnumMultiple {
-    FOUR = 4;
-  }
-  optional FileScopeEnumMultiple three = 3 [ default = THREE ];
-  optional MessageScopeEnumMultiple four = 4 [ default = FOUR ];
-}
diff --git a/src/google/protobuf/unittest_enum_class_nano.proto b/src/google/protobuf/unittest_enum_class_nano.proto
deleted file mode 100644
index 3727d68..0000000
--- a/src/google/protobuf/unittest_enum_class_nano.proto
+++ /dev/null
@@ -1,48 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "EnumClassNanos";
-
-enum FileScopeEnum {
-  ONE = 1;
-}
-
-message EnumClassNano {
-  enum MessageScopeEnum {
-    TWO = 2;
-  }
-  optional FileScopeEnum one = 1 [ default = ONE ];
-  optional MessageScopeEnum two = 2 [ default = TWO ];
-}
diff --git a/src/google/protobuf/unittest_enum_validity_nano.proto b/src/google/protobuf/unittest_enum_validity_nano.proto
deleted file mode 100644
index f7f5742..0000000
--- a/src/google/protobuf/unittest_enum_validity_nano.proto
+++ /dev/null
@@ -1,28 +0,0 @@
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "EnumValidity";
-
-enum E {
-  default = 1; // test java keyword renaming
-  FOO = 2;
-  BAR = 3;
-  BAZ = 4;
-}
-
-message M {
-  optional E optional_e = 1;
-  optional E default_e = 2 [ default = BAZ ];
-  repeated E repeated_e = 3;
-  repeated E packed_e = 4 [ packed = true ];
-  repeated E repeated_e2 = 5;
-  repeated E packed_e2 = 6 [ packed = true ];
-  repeated E repeated_e3 = 7;
-  repeated E packed_e3 = 8 [ packed = true ];
-}
-
-message Alt {
-  optional E repeated_e2_as_optional = 5;
-  repeated E packed_e2_as_non_packed = 6;
-  repeated E non_packed_e3_as_packed = 7 [ packed = true ];
-}
diff --git a/src/google/protobuf/unittest_extension_packed_nano.proto b/src/google/protobuf/unittest_extension_packed_nano.proto
deleted file mode 100644
index 3586de7..0000000
--- a/src/google/protobuf/unittest_extension_packed_nano.proto
+++ /dev/null
@@ -1,29 +0,0 @@
-syntax = "proto2";
-
-option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
-
-import "google/protobuf/unittest_extension_nano.proto";
-
-// Must be compiled separately due to extension number reuse.
-// The reuse is deliberate, for testing wire compatibility.
-
-message PackedExtensions {
-  extend ExtendableMessage {
-    repeated int32    packed_int32    = 10 [ packed = true ];
-    repeated uint32   packed_uint32   = 11 [ packed = true ];
-    repeated sint32   packed_sint32   = 12 [ packed = true ];
-    repeated int64    packed_int64    = 13 [ packed = true ];
-    repeated uint64   packed_uint64   = 14 [ packed = true ];
-    repeated sint64   packed_sint64   = 15 [ packed = true ];
-    repeated fixed32  packed_fixed32  = 16 [ packed = true ];
-    repeated sfixed32 packed_sfixed32 = 17 [ packed = true ];
-    repeated fixed64  packed_fixed64  = 18 [ packed = true ];
-    repeated sfixed64 packed_sfixed64 = 19 [ packed = true ];
-    repeated bool     packed_bool     = 20 [ packed = true ];
-    repeated float    packed_float    = 21 [ packed = true ];
-    repeated double   packed_double   = 22 [ packed = true ];
-    repeated AnEnum   packed_enum     = 23 [ packed = true ];
-    // Non-packable types omitted.
-  }
-}
diff --git a/src/google/protobuf/unittest_extension_repeated_nano.proto b/src/google/protobuf/unittest_extension_repeated_nano.proto
deleted file mode 100644
index 546c2df..0000000
--- a/src/google/protobuf/unittest_extension_repeated_nano.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-syntax = "proto2";
-
-option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
-
-import "google/protobuf/unittest_extension_nano.proto";
-
-// Must be compiled separately due to extension number reuse.
-// The reuse is deliberate, for testing wire compatibility.
-
-message RepeatedExtensions {
-  extend ExtendableMessage {
-    repeated int32          repeated_int32    = 10;
-    repeated uint32         repeated_uint32   = 11;
-    repeated sint32         repeated_sint32   = 12;
-    repeated int64          repeated_int64    = 13;
-    repeated uint64         repeated_uint64   = 14;
-    repeated sint64         repeated_sint64   = 15;
-    repeated fixed32        repeated_fixed32  = 16;
-    repeated sfixed32       repeated_sfixed32 = 17;
-    repeated fixed64        repeated_fixed64  = 18;
-    repeated sfixed64       repeated_sfixed64 = 19;
-    repeated bool           repeated_bool     = 20;
-    repeated float          repeated_float    = 21;
-    repeated double         repeated_double   = 22;
-    repeated AnEnum         repeated_enum     = 23;
-    repeated string         repeated_string   = 24;
-    repeated bytes          repeated_bytes    = 25;
-    repeated AnotherMessage repeated_message  = 26;
-    repeated group          RepeatedGroup     = 27 {
-      optional int32 a = 1;
-    }
-  }
-}
diff --git a/src/google/protobuf/unittest_extension_singular_nano.proto b/src/google/protobuf/unittest_extension_singular_nano.proto
deleted file mode 100644
index 35d9e6e..0000000
--- a/src/google/protobuf/unittest_extension_singular_nano.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-syntax = "proto2";
-
-option java_multiple_files = true;
-option java_package = "com.google.protobuf.nano";
-
-import "google/protobuf/unittest_extension_nano.proto";
-
-// Must be compiled separately due to extension number reuse.
-// The reuse is deliberate, for testing wire compatibility.
-
-message SingularExtensions {
-  extend ExtendableMessage {
-    optional int32          some_int32    = 10;
-    optional uint32         some_uint32   = 11;
-    optional sint32         some_sint32   = 12;
-    optional int64          some_int64    = 13;
-    optional uint64         some_uint64   = 14;
-    optional sint64         some_sint64   = 15;
-    optional fixed32        some_fixed32  = 16;
-    optional sfixed32       some_sfixed32 = 17;
-    optional fixed64        some_fixed64  = 18;
-    optional sfixed64       some_sfixed64 = 19;
-    optional bool           some_bool     = 20;
-    optional float          some_float    = 21;
-    optional double         some_double   = 22;
-    optional AnEnum         some_enum     = 23;
-    optional string         some_string   = 24;
-    optional bytes          some_bytes    = 25;
-    optional AnotherMessage some_message  = 26;
-    optional group          SomeGroup     = 27 {
-      optional int32 a = 1;
-    }
-  }
-}
diff --git a/src/google/protobuf/unittest_has_nano.proto b/src/google/protobuf/unittest_has_nano.proto
deleted file mode 100644
index 289d08a..0000000
--- a/src/google/protobuf/unittest_has_nano.proto
+++ /dev/null
@@ -1,82 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: ulas@google.com (Ulas Kirazci)
-
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "NanoHasOuterClass";
-
-message TestAllTypesNanoHas {
-
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  // Singular
-  optional int32  optional_int32    =  1;
-  optional float  optional_float    = 11;
-  optional double optional_double   = 12;
-  optional string optional_string   = 14;
-  optional bytes  optional_bytes    = 15;
-
-  optional NestedMessage optional_nested_message = 18;
-
-  optional NestedEnum optional_nested_enum = 21;
-
-  // Repeated
-  repeated int32  repeated_int32    = 31;
-  repeated string repeated_string   = 44;
-  repeated bytes  repeated_bytes    = 45;
-
-  repeated NestedMessage repeated_nested_message  = 48;
-
-  repeated NestedEnum repeated_nested_enum  = 51;
-
-  // Singular with defaults
-  optional int32  default_int32    = 61 [default =  41    ];
-  optional string default_string   = 74 [default = "hello"];
-  optional bytes  default_bytes    = 75 [default = "world"];
-
-  optional float default_float_nan = 99  [default =  nan];
-
-  optional NestedEnum default_nested_enum = 81 [default = BAR];
-
-  required int32 id = 86;
-  required NestedEnum required_enum = 87;
-
-}
diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto
index 38275dc..8d03e38 100644
--- a/src/google/protobuf/unittest_import.proto
+++ b/src/google/protobuf/unittest_import.proto
@@ -34,6 +34,7 @@
 //
 // A proto file which is imported by unittest.proto to test importing.
 
+syntax = "proto2";
 
 // We don't put this in a package within proto2 because we need to make sure
 // that the generated code doesn't depend on being in the proto2 namespace.
@@ -42,8 +43,9 @@
 package protobuf_unittest_import;
 
 option optimize_for = SPEED;
+option cc_enable_arenas = true;
 
-// Excercise the java_package option.
+// Exercise the java_package option.
 option java_package = "com.google.protobuf.test";
 
 // Do not set a java_outer_classname here to verify that Proto2 works without
@@ -62,3 +64,10 @@
   IMPORT_BAZ = 9;
 }
 
+
+// To use an enum in a map, it must has the first value as 0.
+enum ImportEnumForMap {
+  UNKNOWN = 0;
+  FOO = 1;
+  BAR = 2;
+}
diff --git a/src/google/protobuf/unittest_import_lite.proto b/src/google/protobuf/unittest_import_lite.proto
index 7cee113..a7afa45 100644
--- a/src/google/protobuf/unittest_import_lite.proto
+++ b/src/google/protobuf/unittest_import_lite.proto
@@ -32,6 +32,7 @@
 //
 // This is like unittest_import.proto but with optimize_for = LITE_RUNTIME.
 
+syntax = "proto2";
 package protobuf_unittest_import;
 
 option optimize_for = LITE_RUNTIME;
diff --git a/src/google/protobuf/unittest_import_micro.proto b/src/google/protobuf/unittest_import_micro.proto
deleted file mode 100644
index adac807..0000000
--- a/src/google/protobuf/unittest_import_micro.proto
+++ /dev/null
@@ -1,49 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: kenton@google.com (Kenton Varda)
-//
-// This is like unittest_import.proto but with optimize_for = MICRO_RUNTIME.
-
-package protobuf_unittest_import;
-
-// java_package and java_outer_classname are specified on the command line.
-//option java_package = "com.google.protobuf.micro";
-//option java_outer_classname = "UnittestImportMicro";
-
-message ImportMessageMicro {
-  optional int32 d = 1;
-}
-
-enum ImportEnumMicro {
-  IMPORT_MICRO_FOO = 7;
-  IMPORT_MICRO_BAR = 8;
-  IMPORT_MICRO_BAZ = 9;
-}
diff --git a/src/google/protobuf/unittest_import_nano.proto b/src/google/protobuf/unittest_import_nano.proto
deleted file mode 100644
index 0a2fde7..0000000
--- a/src/google/protobuf/unittest_import_nano.proto
+++ /dev/null
@@ -1,49 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: kenton@google.com (Kenton Varda)
-//
-// This is like unittest_import.proto but with optimize_for = NANO_RUNTIME.
-
-package protobuf_unittest_import;
-
-// java_package and java_outer_classname are specified on the command line.
-//option java_package = "com.google.protobuf.nano.testimport";
-//option java_outer_classname = "UnittestImportNano";
-
-message ImportMessageNano {
-  optional int32 d = 1;
-}
-
-enum ImportEnumNano {
-  IMPORT_NANO_FOO = 7;
-  IMPORT_NANO_BAR = 8;
-  IMPORT_NANO_BAZ = 9;
-}
diff --git a/src/google/protobuf/unittest_import_proto3.proto b/src/google/protobuf/unittest_import_proto3.proto
new file mode 100644
index 0000000..59673ea
--- /dev/null
+++ b/src/google/protobuf/unittest_import_proto3.proto
@@ -0,0 +1,68 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file which is imported by unittest_proto3.proto to test importing.
+
+syntax = "proto3";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do
+// "using namespace unittest_import = protobuf_unittest_import".
+package protobuf_unittest_import;
+
+option optimize_for = SPEED;
+option cc_enable_arenas = true;
+
+// Exercise the java_package option.
+option java_package = "com.google.protobuf.test";
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+// Do not set a java_outer_classname here to verify that Proto2 works without
+// one.
+
+// Test public import
+import public "google/protobuf/unittest_import_public_proto3.proto";
+
+message ImportMessage {
+  int32 d = 1;
+}
+
+enum ImportEnum {
+  IMPORT_ENUM_UNSPECIFIED = 0;
+  IMPORT_FOO = 7;
+  IMPORT_BAR = 8;
+  IMPORT_BAZ = 9;
+}
+
diff --git a/src/google/protobuf/unittest_import_public.proto b/src/google/protobuf/unittest_import_public.proto
index e5929cb..ffaf773 100644
--- a/src/google/protobuf/unittest_import_public.proto
+++ b/src/google/protobuf/unittest_import_public.proto
@@ -30,6 +30,7 @@
 
 // Author: liujisi@google.com (Pherl Liu)
 
+syntax = "proto2";
 
 package protobuf_unittest_import;
 
diff --git a/src/google/protobuf/unittest_import_public_lite.proto b/src/google/protobuf/unittest_import_public_lite.proto
index e39bdb4..33549c2 100644
--- a/src/google/protobuf/unittest_import_public_lite.proto
+++ b/src/google/protobuf/unittest_import_public_lite.proto
@@ -30,6 +30,7 @@
 
 // Author: liujisi@google.com (Pherl Liu)
 
+syntax = "proto2";
 
 package protobuf_unittest_import;
 
diff --git a/src/google/protobuf/unittest_import_public_proto3.proto b/src/google/protobuf/unittest_import_public_proto3.proto
new file mode 100644
index 0000000..d6f11e2
--- /dev/null
+++ b/src/google/protobuf/unittest_import_public_proto3.proto
@@ -0,0 +1,42 @@
+// 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.
+
+// Author: liujisi@google.com (Pherl Liu)
+
+syntax = "proto3";
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.test";
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+message PublicImportMessage {
+ int32 e = 1;
+}
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
index 30dd67f..878ec7c 100644
--- a/src/google/protobuf/unittest_lite.proto
+++ b/src/google/protobuf/unittest_lite.proto
@@ -32,6 +32,7 @@
 //
 // This is like unittest.proto but with optimize_for = LITE_RUNTIME.
 
+syntax = "proto2";
 package protobuf_unittest;
 
 import "google/protobuf/unittest_import_lite.proto";
@@ -42,8 +43,10 @@
 
 // Same as TestAllTypes but with the lite runtime.
 message TestAllTypesLite {
+
   message NestedMessage {
     optional int32 bb = 1;
+    optional int64 cc = 2;
   }
 
   enum NestedEnum {
@@ -158,6 +161,7 @@
     NestedMessage oneof_nested_message = 112;
     string oneof_string = 113;
     bytes oneof_bytes = 114;
+    NestedMessage oneof_lazy_nested_message = 115 [lazy = true];
   }
 }
 
@@ -382,3 +386,22 @@
 message TestEmptyMessageWithExtensionsLite {
   extensions 1 to max;
 }
+
+enum V1EnumLite {
+    V1_FIRST = 1;
+}
+
+enum V2EnumLite {
+    V2_FIRST = 1;
+    V2_SECOND = 2;
+}
+
+message V1MessageLite {
+    required int32 int_field = 1;
+    optional V1EnumLite enum_field = 2 [ default = V1_FIRST ];
+}
+
+message V2MessageLite {
+    required int32 int_field = 1;
+    optional V2EnumLite enum_field = 2 [ default = V2_FIRST ];
+}
diff --git a/src/google/protobuf/unittest_lite_imports_nonlite.proto b/src/google/protobuf/unittest_lite_imports_nonlite.proto
index 5ef8a06..132d6a8 100644
--- a/src/google/protobuf/unittest_lite_imports_nonlite.proto
+++ b/src/google/protobuf/unittest_lite_imports_nonlite.proto
@@ -32,6 +32,7 @@
 //
 // Tests that a "lite" message can import a regular message.
 
+syntax = "proto2";
 package protobuf_unittest;
 
 import "google/protobuf/unittest.proto";
diff --git a/src/google/protobuf/unittest_micro.proto b/src/google/protobuf/unittest_micro.proto
deleted file mode 100644
index e6b4618..0000000
--- a/src/google/protobuf/unittest_micro.proto
+++ /dev/null
@@ -1,169 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-
-package protobuf_unittest;
-
-import "google/protobuf/unittest_import_micro.proto";
-
-option java_package = "com.google.protobuf.micro";
-option java_outer_classname = "MicroOuterClass";
-
-// Same as TestAllTypes but with the micro runtime.
-message TestAllTypesMicro {
-
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  // Singular
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
-
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
-
-  optional NestedMessage      optional_nested_message  = 18;
-  optional ForeignMessageMicro optional_foreign_message = 19;
-  optional protobuf_unittest_import.ImportMessageMicro
-    optional_import_message = 20;
-
-  optional NestedEnum      optional_nested_enum     = 21;
-  optional ForeignEnumMicro optional_foreign_enum    = 22;
-  optional protobuf_unittest_import.ImportEnumMicro optional_import_enum = 23;
-
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
-
-  // Repeated
-  repeated    int32 repeated_int32    = 31;
-  repeated    int64 repeated_int64    = 32;
-  repeated   uint32 repeated_uint32   = 33;
-  repeated   uint64 repeated_uint64   = 34;
-  repeated   sint32 repeated_sint32   = 35;
-  repeated   sint64 repeated_sint64   = 36;
-  repeated  fixed32 repeated_fixed32  = 37;
-  repeated  fixed64 repeated_fixed64  = 38;
-  repeated sfixed32 repeated_sfixed32 = 39;
-  repeated sfixed64 repeated_sfixed64 = 40;
-  repeated    float repeated_float    = 41;
-  repeated   double repeated_double   = 42;
-  repeated     bool repeated_bool     = 43;
-  repeated   string repeated_string   = 44;
-  repeated    bytes repeated_bytes    = 45;
-
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
-
-  repeated NestedMessage      repeated_nested_message  = 48;
-  repeated ForeignMessageMicro repeated_foreign_message = 49;
-  repeated protobuf_unittest_import.ImportMessageMicro
-    repeated_import_message = 50;
-
-  repeated NestedEnum      repeated_nested_enum  = 51;
-  repeated ForeignEnumMicro repeated_foreign_enum = 52;
-  repeated protobuf_unittest_import.ImportEnumMicro repeated_import_enum = 53;
-
-  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
-  repeated string repeated_cord = 55 [ctype=CORD];
-
-  // Singular with defaults
-  optional    int32 default_int32    = 61 [default =  41    ];
-  optional    int64 default_int64    = 62 [default =  42    ];
-  optional   uint32 default_uint32   = 63 [default =  43    ];
-  optional   uint64 default_uint64   = 64 [default =  44    ];
-  optional   sint32 default_sint32   = 65 [default = -45    ];
-  optional   sint64 default_sint64   = 66 [default =  46    ];
-  optional  fixed32 default_fixed32  = 67 [default =  47    ];
-  optional  fixed64 default_fixed64  = 68 [default =  48    ];
-  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
-  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
-  optional    float default_float    = 71 [default =  51.5  ];
-  optional   double default_double   = 72 [default =  52e3  ];
-  optional     bool default_bool     = 73 [default = true   ];
-  optional   string default_string   = 74 [default = "hello"];
-  optional    bytes default_bytes    = 75 [default = "world"];
-
-  optional  float default_float_inf      = 96  [default =  inf];
-  optional  float default_float_neg_inf  = 97  [default = -inf];
-  optional  float default_float_nan      = 98  [default =  nan];
-  optional double default_double_inf     = 99  [default =  inf];
-  optional double default_double_neg_inf = 100 [default = -inf];
-  optional double default_double_nan     = 101 [default =  nan];
-
-  optional NestedEnum default_nested_enum = 81 [default = BAR];
-  optional ForeignEnumMicro default_foreign_enum = 82
-      [default = FOREIGN_MICRO_BAR];
-  optional protobuf_unittest_import.ImportEnumMicro
-      default_import_enum = 83 [default = IMPORT_MICRO_BAR];
-
-  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
-  optional string default_cord = 85 [ctype=CORD,default="123"];
-
-  required int32 id = 86;
-}
-
-message ForeignMessageMicro {
-  optional int32 c = 1;
-}
-
-enum ForeignEnumMicro {
-  FOREIGN_MICRO_FOO = 4;
-  FOREIGN_MICRO_BAR = 5;
-  FOREIGN_MICRO_BAZ = 6;
-}
-
-// Test that deprecated fields work.  We only verify that they compile (at one
-// point this failed).
-message TestDeprecatedMicro {
-  optional int32 deprecated_field = 1 [deprecated = true];
-}
diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto
index 8fbe7ab..49d9ada 100644
--- a/src/google/protobuf/unittest_mset.proto
+++ b/src/google/protobuf/unittest_mset.proto
@@ -32,31 +32,31 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //
-// This file contains messages for testing message_set_wire_format.
+// This file is similar to unittest_mset_wire_format.proto, but does not
+// have a TestMessageSet, so it can be downgraded to proto1.
+
+syntax = "proto2";
+
+import "google/protobuf/unittest_mset_wire_format.proto";
 
 package protobuf_unittest;
 
+option cc_enable_arenas = true;
 option optimize_for = SPEED;
 
-// A message with message_set_wire_format.
-message TestMessageSet {
-  option message_set_wire_format = true;
-  extensions 4 to max;
-}
-
 message TestMessageSetContainer {
-  optional TestMessageSet message_set = 1;
+  optional proto2_wireformat_unittest.TestMessageSet message_set = 1;
 }
 
 message TestMessageSetExtension1 {
-  extend TestMessageSet {
+  extend proto2_wireformat_unittest.TestMessageSet {
     optional TestMessageSetExtension1 message_set_extension = 1545008;
   }
   optional int32 i = 15;
 }
 
 message TestMessageSetExtension2 {
-  extend TestMessageSet {
+  extend proto2_wireformat_unittest.TestMessageSet {
     optional TestMessageSetExtension2 message_set_extension = 1547769;
   }
   optional string str = 25;
@@ -80,4 +80,3 @@
     required bytes message = 3;
   }
 }
-
diff --git a/src/google/protobuf/unittest_mset_wire_format.proto b/src/google/protobuf/unittest_mset_wire_format.proto
new file mode 100644
index 0000000..04e4352
--- /dev/null
+++ b/src/google/protobuf/unittest_mset_wire_format.proto
@@ -0,0 +1,52 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains messages for testing message_set_wire_format.
+
+syntax = "proto2";
+package proto2_wireformat_unittest;
+
+option cc_enable_arenas = true;
+option optimize_for = SPEED;
+option csharp_namespace = "Google.ProtocolBuffers.TestProtos";
+
+// A message with message_set_wire_format.
+message TestMessageSet {
+  option message_set_wire_format = true;
+  extensions 4 to max;
+}
+
+message TestMessageSetWireFormatContainer {
+  optional TestMessageSet message_set = 1;
+}
diff --git a/src/google/protobuf/unittest_multiple_micro.proto b/src/google/protobuf/unittest_multiple_micro.proto
deleted file mode 100644
index fee8edc..0000000
--- a/src/google/protobuf/unittest_multiple_micro.proto
+++ /dev/null
@@ -1,63 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-import "google/protobuf/unittest_import_micro.proto";
-
-option java_package = "com.google.protobuf.micro";
-option java_multiple_files = true;
-
-enum FileScopeEnum {
-  ONE = 1;
-  TWO = 2;
-}
-
-message FileScopeEnumRefMicro {
-  optional FileScopeEnum enum_field = 1;
-}
-
-message MessageScopeEnumRefMicro {
-  enum MessageScopeEnum {
-    ONE = 1;
-    TWO = 2;
-  }
-  optional MessageScopeEnum enum_field = 1;
-}
-
-message MultipleImportingNonMultipleMicro1 {
-  optional ImportMessageMicro field = 1;
-}
-
-message MultipleImportingNonMultipleMicro2 {
-  optional MultipleImportingNonMultipleMicro1 micro1 = 1;
-}
diff --git a/src/google/protobuf/unittest_multiple_nameclash_micro.proto b/src/google/protobuf/unittest_multiple_nameclash_micro.proto
deleted file mode 100644
index 089fd85..0000000
--- a/src/google/protobuf/unittest_multiple_nameclash_micro.proto
+++ /dev/null
@@ -1,41 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.micro";
-option java_outer_classname = "MultipleNameClashMicro";
-option java_multiple_files = true;
-
-message MultipleNameClashMicro {
-  optional int32 field = 1;
-}
diff --git a/src/google/protobuf/unittest_multiple_nameclash_nano.proto b/src/google/protobuf/unittest_multiple_nameclash_nano.proto
deleted file mode 100644
index f2f62c4..0000000
--- a/src/google/protobuf/unittest_multiple_nameclash_nano.proto
+++ /dev/null
@@ -1,41 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "MultipleNameClashNano";
-option java_multiple_files = true;
-
-message MultipleNameClashNano {
-  optional int32 field = 1;
-}
diff --git a/src/google/protobuf/unittest_multiple_nano.proto b/src/google/protobuf/unittest_multiple_nano.proto
deleted file mode 100644
index 5ae790b..0000000
--- a/src/google/protobuf/unittest_multiple_nano.proto
+++ /dev/null
@@ -1,63 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-import "google/protobuf/unittest_import_nano.proto";
-
-option java_package = "com.google.protobuf.nano";
-option java_multiple_files = true;
-
-enum FileScopeEnum {
-  ONE = 1;
-  TWO = 2;
-}
-
-message FileScopeEnumRefNano {
-  optional FileScopeEnum enum_field = 1;
-}
-
-message MessageScopeEnumRefNano {
-  enum MessageScopeEnum {
-    ONE = 1;
-    TWO = 2;
-  }
-  optional MessageScopeEnum enum_field = 1;
-}
-
-message MultipleImportingNonMultipleNano1 {
-  optional ImportMessageNano field = 1;
-}
-
-message MultipleImportingNonMultipleNano2 {
-  optional MultipleImportingNonMultipleNano1 nano1 = 1;
-}
diff --git a/src/google/protobuf/unittest_nano.proto b/src/google/protobuf/unittest_nano.proto
deleted file mode 100644
index 1a6ba26..0000000
--- a/src/google/protobuf/unittest_nano.proto
+++ /dev/null
@@ -1,186 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-
-package protobuf_unittest;
-
-import "google/protobuf/unittest_import_nano.proto";
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "NanoOuterClass";
-
-// Same as TestAllTypes but with the nano runtime.
-message TestAllTypesNano {
-
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  // Singular
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
-
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
-
-  optional NestedMessage      optional_nested_message  = 18;
-  optional ForeignMessageNano optional_foreign_message = 19;
-  optional protobuf_unittest_import.ImportMessageNano
-    optional_import_message = 20;
-
-  optional NestedEnum      optional_nested_enum     = 21;
-  optional ForeignEnumNano optional_foreign_enum    = 22;
-  optional protobuf_unittest_import.ImportEnumNano optional_import_enum = 23;
-
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
-
-  // Repeated
-  repeated    int32 repeated_int32    = 31;
-  repeated    int64 repeated_int64    = 32;
-  repeated   uint32 repeated_uint32   = 33;
-  repeated   uint64 repeated_uint64   = 34;
-  repeated   sint32 repeated_sint32   = 35;
-  repeated   sint64 repeated_sint64   = 36;
-  repeated  fixed32 repeated_fixed32  = 37;
-  repeated  fixed64 repeated_fixed64  = 38;
-  repeated sfixed32 repeated_sfixed32 = 39;
-  repeated sfixed64 repeated_sfixed64 = 40;
-  repeated    float repeated_float    = 41;
-  repeated   double repeated_double   = 42;
-  repeated     bool repeated_bool     = 43;
-  repeated   string repeated_string   = 44;
-  repeated    bytes repeated_bytes    = 45;
-
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
-
-  repeated NestedMessage      repeated_nested_message  = 48;
-  repeated ForeignMessageNano repeated_foreign_message = 49;
-  repeated protobuf_unittest_import.ImportMessageNano
-    repeated_import_message = 50;
-
-  repeated NestedEnum      repeated_nested_enum  = 51;
-  repeated ForeignEnumNano repeated_foreign_enum = 52;
-  repeated protobuf_unittest_import.ImportEnumNano repeated_import_enum = 53;
-
-  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
-  repeated string repeated_cord = 55 [ctype=CORD];
-
-  // Repeated packed
-  repeated    int32 repeated_packed_int32    = 87 [packed=true];
-  repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
-
-  repeated NestedEnum repeated_packed_nested_enum  = 89 [packed=true];
-
-  // Singular with defaults
-  optional    int32 default_int32    = 61 [default =  41    ];
-  optional    int64 default_int64    = 62 [default =  42    ];
-  optional   uint32 default_uint32   = 63 [default =  43    ];
-  optional   uint64 default_uint64   = 64 [default =  44    ];
-  optional   sint32 default_sint32   = 65 [default = -45    ];
-  optional   sint64 default_sint64   = 66 [default =  46    ];
-  optional  fixed32 default_fixed32  = 67 [default =  47    ];
-  optional  fixed64 default_fixed64  = 68 [default =  48    ];
-  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
-  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
-  optional    float default_float    = 71 [default =  51.5  ];
-  optional   double default_double   = 72 [default =  52e3  ];
-  optional     bool default_bool     = 73 [default = true   ];
-  optional   string default_string   = 74 [default = "hello"];
-  optional    bytes default_bytes    = 75 [default = "world"];
-
-  optional string default_string_nonascii = 76 [default = "dünya"];
-  optional  bytes default_bytes_nonascii  = 77 [default = "dünyab"];
-
-  optional  float default_float_inf      = 97  [default =  inf];
-  optional  float default_float_neg_inf  = 98  [default = -inf];
-  optional  float default_float_nan      = 99  [default =  nan];
-  optional double default_double_inf     = 100 [default =  inf];
-  optional double default_double_neg_inf = 101 [default = -inf];
-  optional double default_double_nan     = 102 [default =  nan];
-
-  optional NestedEnum default_nested_enum = 81 [default = BAR];
-  optional ForeignEnumNano default_foreign_enum = 82
-      [default = FOREIGN_NANO_BAR];
-  optional protobuf_unittest_import.ImportEnumNano
-      default_import_enum = 83 [default = IMPORT_NANO_BAR];
-
-  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
-  optional string default_cord = 85 [ctype=CORD,default="123"];
-
-  required int32 id = 86;
-
-  // Try to cause conflicts.
-  optional int32 tag = 93;
-  optional int32 get_serialized_size = 94;
-  optional int32 write_to = 95;
-
-  // Try to fail with java reserved keywords
-  optional int32 synchronized = 96;
-}
-
-message ForeignMessageNano {
-  optional int32 c = 1;
-}
-
-enum ForeignEnumNano {
-  FOREIGN_NANO_FOO = 4;
-  FOREIGN_NANO_BAR = 5;
-  FOREIGN_NANO_BAZ = 6;
-}
-
-// Test that deprecated fields work.  We only verify that they compile (at one
-// point this failed).
-message TestDeprecatedNano {
-  optional int32 deprecated_field = 1 [deprecated = true];
-}
diff --git a/src/google/protobuf/unittest_no_arena.proto b/src/google/protobuf/unittest_no_arena.proto
new file mode 100644
index 0000000..41518df
--- /dev/null
+++ b/src/google/protobuf/unittest_no_arena.proto
@@ -0,0 +1,202 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This proto file contains copies of TestAllTypes and friends, but with arena
+// support disabled in code generation. It allows us to test the performance
+// impact against baseline (non-arena) google.protobuf.
+
+syntax = "proto2";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;     // auto-added
+option cc_enable_arenas = false;
+option objc_class_prefix = "NOARN";
+
+import "google/protobuf/unittest_import.proto";
+import "google/protobuf/unittest_arena.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest_no_arena;
+
+// Protos optimized for SPEED use a strict superset of the generated code
+// of equivalent ones optimized for CODE_SIZE, so we should optimize all our
+// tests for speed unless explicitly testing code size optimization.
+option optimize_for = SPEED;
+
+option java_outer_classname = "UnittestProto";
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage                        optional_nested_message  = 18;
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  optional NestedEnum                           optional_nested_enum     = 21;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnum    optional_import_enum     = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  optional protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  optional NestedMessage optional_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated protobuf_unittest_import.ImportEnum    repeated_import_enum     = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum  default_nested_enum  = 81 [default = BAR        ];
+  optional ForeignEnum default_foreign_enum = 82 [default = FOREIGN_BAR];
+  optional protobuf_unittest_import.ImportEnum
+      default_import_enum = 83 [default = IMPORT_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+
+  // For oneof test
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+    NestedMessage lazy_oneof_nested_message = 115 [lazy=true];
+  }
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  optional int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestNoArenaMessage {
+  optional proto2_arena_unittest.ArenaMessage arena_message = 1;
+};
diff --git a/src/google/protobuf/unittest_no_arena_import.proto b/src/google/protobuf/unittest_no_arena_import.proto
new file mode 100644
index 0000000..072af49
--- /dev/null
+++ b/src/google/protobuf/unittest_no_arena_import.proto
@@ -0,0 +1,37 @@
+// 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.
+
+syntax = "proto2";
+
+package proto2_arena_unittest;
+
+message ImportNoArenaNestedMessage {
+  optional int32 d = 1;
+};
diff --git a/src/google/protobuf/unittest_no_arena_lite.proto b/src/google/protobuf/unittest_no_arena_lite.proto
new file mode 100644
index 0000000..34c7b7c
--- /dev/null
+++ b/src/google/protobuf/unittest_no_arena_lite.proto
@@ -0,0 +1,42 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest_no_arena;
+
+message ForeignMessageLite {
+  optional int32 c = 1;
+}
diff --git a/src/google/protobuf/unittest_no_field_presence.proto b/src/google/protobuf/unittest_no_field_presence.proto
new file mode 100644
index 0000000..994afff
--- /dev/null
+++ b/src/google/protobuf/unittest_no_field_presence.proto
@@ -0,0 +1,138 @@
+// 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.
+
+// A proto file used to test a message type with no explicit field presence.
+
+syntax = "proto3";
+
+// We want to test embedded proto2 messages, so include some proto2 types.
+import "google/protobuf/unittest.proto";
+
+package proto2_nofieldpresence_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+
+  // Singular
+  // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make
+  // 'optional' optional.
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+  // N.B.: proto2-enum-type fields not allowed, because their default values
+  // might not be zero.
+  //optional protobuf_unittest.ForeignEnum          optional_proto2_enum     = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  NestedMessage optional_lazy_message = 30 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest.TestAllTypes         repeated_proto2_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    NestedEnum oneof_enum = 114;
+  }
+}
+
+message TestProto2Required {
+  protobuf_unittest.TestRequired proto2 = 1;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 0;
+  FOREIGN_BAR = 1;
+  FOREIGN_BAZ = 2;
+}
diff --git a/src/google/protobuf/unittest_no_generic_services.proto b/src/google/protobuf/unittest_no_generic_services.proto
index cf6d16c..8fc7713 100644
--- a/src/google/protobuf/unittest_no_generic_services.proto
+++ b/src/google/protobuf/unittest_no_generic_services.proto
@@ -30,6 +30,7 @@
 
 // Author: kenton@google.com (Kenton Varda)
 
+syntax = "proto2";
 package google.protobuf.no_generic_services_test;
 
 
diff --git a/src/google/protobuf/unittest_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto
index 9f7b4ee..ee9cc7b 100644
--- a/src/google/protobuf/unittest_optimize_for.proto
+++ b/src/google/protobuf/unittest_optimize_for.proto
@@ -34,6 +34,7 @@
 //
 // A proto file which uses optimize_for = CODE_SIZE.
 
+syntax = "proto2";
 import "google/protobuf/unittest.proto";
 
 package protobuf_unittest;
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto
new file mode 100644
index 0000000..2f91332
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto
@@ -0,0 +1,71 @@
+// 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.
+
+syntax = "proto3";
+
+package proto3_preserve_unknown_enum_unittest;
+option objc_class_prefix = "UnknownEnums";
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+enum MyEnum {
+  FOO = 0;
+  BAR = 1;
+  BAZ = 2;
+}
+
+enum MyEnumPlusExtra {
+  E_FOO = 0;
+  E_BAR = 1;
+  E_BAZ = 2;
+  E_EXTRA = 3;
+}
+
+message MyMessage {
+  MyEnum e = 1;
+  repeated MyEnum repeated_e = 2;
+  repeated MyEnum repeated_packed_e = 3 [packed=true];
+  repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4;  // not packed
+  oneof o {
+    MyEnum oneof_e_1 = 5;
+    MyEnum oneof_e_2 = 6;
+  }
+}
+
+message MyMessagePlusExtra {
+  MyEnumPlusExtra e = 1;
+  repeated MyEnumPlusExtra repeated_e = 2;
+  repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true];
+  repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4 [packed=true];
+  oneof o {
+    MyEnumPlusExtra oneof_e_1 = 5;
+    MyEnumPlusExtra oneof_e_2 = 6;
+  }
+}
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum2.proto b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
new file mode 100644
index 0000000..adf4296
--- /dev/null
+++ b/src/google/protobuf/unittest_preserve_unknown_enum2.proto
@@ -0,0 +1,50 @@
+// 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.
+
+syntax = "proto2";
+
+package proto2_preserve_unknown_enum_unittest;
+
+enum MyEnum {
+  FOO = 0;
+  BAR = 1;
+  BAZ = 2;
+}
+
+message MyMessage {
+  optional MyEnum e = 1;
+  repeated MyEnum repeated_e = 2;
+  repeated MyEnum repeated_packed_e = 3 [packed=true];
+  repeated MyEnum repeated_packed_unexpected_e = 4;  // not packed
+  oneof o {
+    MyEnum oneof_e_1 = 5;
+    MyEnum oneof_e_2 = 6;
+  }
+}
diff --git a/src/google/protobuf/unittest_proto3.proto b/src/google/protobuf/unittest_proto3.proto
new file mode 100644
index 0000000..f59d217
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3.proto
@@ -0,0 +1,388 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// A proto file we will use for unit testing.
+
+syntax = "proto3";
+
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+option java_generic_services = true;   // auto-added
+option py_generic_services = true;     // auto-added
+option cc_enable_arenas = true;
+option csharp_namespace = "Google.Protobuf.TestProtos";
+
+import "google/protobuf/unittest_import_proto3.proto";
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In test_util.h we do "using namespace unittest = protobuf_unittest".
+package protobuf_unittest;
+
+// Protos optimized for SPEED use a strict superset of the generated code
+// of equivalent ones optimized for CODE_SIZE, so we should optimize all our
+// tests for speed unless explicitly testing code size optimization.
+option optimize_for = SPEED;
+
+option java_outer_classname = "UnittestProto";
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    NESTED_ENUM_UNSPECIFIED = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+  int32 single_int32 = 1;
+  int64 single_int64 = 2;
+  uint32 single_uint32 = 3;
+  uint64 single_uint64 = 4;
+  sint32 single_sint32 = 5;
+  sint64 single_sint64 = 6;
+  fixed32 single_fixed32 = 7;
+  fixed64 single_fixed64 = 8;
+  sfixed32 single_sfixed32 = 9;
+  sfixed64 single_sfixed64 = 10;
+  float single_float = 11;
+  double single_double = 12;
+  bool single_bool = 13;
+  string single_string = 14;
+  bytes single_bytes = 15;
+
+  NestedMessage single_nested_message = 18;
+  ForeignMessage single_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage single_import_message = 20;
+
+  NestedEnum single_nested_enum = 21;
+  ForeignEnum single_foreign_enum = 22;
+  protobuf_unittest_import.ImportEnum single_import_enum = 23;
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage
+      single_public_import_message = 26;
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated protobuf_unittest_import.ImportEnum    repeated_import_enum     = 53;
+  // Defined in unittest_import_public.proto
+  repeated protobuf_unittest_import.PublicImportMessage
+      repeated_public_import_message = 54;
+
+  // For oneof test
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
+}
+
+message TestDeprecatedFields {
+  int32 deprecated_int32 = 1 [deprecated=true];
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_UNSPECIFIED = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestReservedFields {
+  reserved 2, 15, 9 to 11;
+  reserved "bar", "baz";
+}
+
+
+// Test that we can use NestedMessage from outside TestAllTypes.
+message TestForeignNested {
+  TestAllTypes.NestedMessage foreign_nested = 1;
+}
+
+// Test that really large tag numbers don't break anything.
+message TestReallyLargeTagNumber {
+  // The largest possible tag number is 2^28 - 1, since the wire format uses
+  // three bits to communicate wire type.
+  int32 a = 1;
+  int32 bb = 268435455;
+}
+
+message TestRecursiveMessage {
+  TestRecursiveMessage a = 1;
+  int32 i = 2;
+}
+
+// Test that mutual recursion works.
+message TestMutualRecursionA {
+  TestMutualRecursionB bb = 1;
+}
+
+message TestMutualRecursionB {
+  TestMutualRecursionA a = 1;
+  int32 optional_int32 = 2;
+}
+
+
+// Test an enum that has multiple values with the same number.
+enum TestEnumWithDupValue {
+  TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED = 0;
+  option allow_alias = true;
+
+  FOO1 = 1;
+  BAR1 = 2;
+  BAZ = 3;
+  FOO2 = 1;
+  BAR2 = 2;
+}
+
+// Test an enum with large, unordered values.
+enum TestSparseEnum {
+  TEST_SPARSE_ENUM_UNSPECIFIED = 0;
+  SPARSE_A = 123;
+  SPARSE_B = 62374;
+  SPARSE_C = 12589234;
+  SPARSE_D = -15;
+  SPARSE_E = -53452;
+  // In proto3, value 0 must be the first one specified
+  // SPARSE_F = 0;
+  SPARSE_G = 2;
+}
+
+// Test message with CamelCase field names.  This violates Protocol Buffer
+// standard style.
+message TestCamelCaseFieldNames {
+  int32 PrimitiveField = 1;
+  string StringField = 2;
+  ForeignEnum EnumField = 3;
+  ForeignMessage MessageField = 4;
+
+  repeated int32 RepeatedPrimitiveField = 7;
+  repeated string RepeatedStringField = 8;
+  repeated ForeignEnum RepeatedEnumField = 9;
+  repeated ForeignMessage RepeatedMessageField = 10;
+}
+
+
+// We list fields out of order, to ensure that we're using field number and not
+// field index to determine serialization order.
+message TestFieldOrderings {
+  string my_string = 11;
+  int64 my_int = 1;
+  float my_float = 101;
+  message NestedMessage {
+    int64 oo = 2;
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  NestedMessage single_nested_message  = 200;
+}
+
+message SparseEnumMessage {
+  TestSparseEnum sparse_enum = 1;
+}
+
+// Test String and Bytes: string is for valid UTF-8 strings
+message OneString {
+  string data = 1;
+}
+
+message MoreString {
+  repeated string data = 1;
+}
+
+message OneBytes {
+  bytes data = 1;
+}
+
+message MoreBytes {
+  bytes data = 1;
+}
+
+// Test int32, uint32, int64, uint64, and bool are all compatible
+message Int32Message {
+  int32 data = 1;
+}
+
+message Uint32Message {
+  uint32 data = 1;
+}
+
+message Int64Message {
+  int64 data = 1;
+}
+
+message Uint64Message {
+  uint64 data = 1;
+}
+
+message BoolMessage {
+  bool data = 1;
+}
+
+// Test oneofs.
+message TestOneof {
+  oneof foo {
+    int32 foo_int = 1;
+    string foo_string = 2;
+    TestAllTypes foo_message = 3;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// A message with the same fields as TestPackedTypes, but without packing. Used
+// to test packed <-> unpacked wire compatibility.
+message TestUnpackedTypes {
+  repeated    int32 unpacked_int32    =  90 [packed = false];
+  repeated    int64 unpacked_int64    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 =  99 [packed = false];
+  repeated    float unpacked_float    = 100 [packed = false];
+  repeated   double unpacked_double   = 101 [packed = false];
+  repeated     bool unpacked_bool     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum  = 103 [packed = false];
+}
+
+message TestRepeatedScalarDifferentTagSizes {
+  // Parsing repeated fixed size values used to fail. This message needs to be
+  // used in order to get a tag of the right size; all of the repeated fields
+  // in TestAllTypes didn't trigger the check.
+  repeated fixed32 repeated_fixed32 = 12;
+  // Check for a varint type, just for good measure.
+  repeated int32   repeated_int32   = 13;
+
+  // These have two-byte tags.
+  repeated fixed64 repeated_fixed64 = 2046;
+  repeated int64   repeated_int64   = 2047;
+
+  // Three byte tags.
+  repeated float   repeated_float   = 262142;
+  repeated uint64  repeated_uint64  = 262143;
+}
+
+message TestCommentInjectionMessage {
+  // */ <- This should not close the generated doc comment
+  string a = 1;
+}
+
+
+// Test that RPC services work.
+message FooRequest  {}
+message FooResponse {}
+
+message FooClientMessage {}
+message FooServerMessage{}
+
+service TestService {
+  rpc Foo(FooRequest) returns (FooResponse);
+  rpc Bar(BarRequest) returns (BarResponse);
+}
+
+
+message BarRequest  {}
+message BarResponse {}
+
diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto
new file mode 100644
index 0000000..b835a6b
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_arena.proto
@@ -0,0 +1,206 @@
+// 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.
+
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+
+import "google/protobuf/unittest_import.proto";
+
+package proto3_arena_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {
+}
+
diff --git a/src/google/protobuf/unittest_proto3_arena_lite.proto b/src/google/protobuf/unittest_proto3_arena_lite.proto
new file mode 100644
index 0000000..5a60b90
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_arena_lite.proto
@@ -0,0 +1,207 @@
+// 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.
+
+syntax = "proto3";
+
+option cc_enable_arenas = true;
+option optimize_for = LITE_RUNTIME;
+
+import "google/protobuf/unittest_import.proto";
+
+package proto3_arena_lite_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {
+}
+
diff --git a/src/google/protobuf/unittest_proto3_lite.proto b/src/google/protobuf/unittest_proto3_lite.proto
new file mode 100644
index 0000000..874ade6
--- /dev/null
+++ b/src/google/protobuf/unittest_proto3_lite.proto
@@ -0,0 +1,206 @@
+// 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.
+
+syntax = "proto3";
+
+option optimize_for = LITE_RUNTIME;
+
+import "google/protobuf/unittest_import.proto";
+
+package proto3_lite_unittest;
+
+// This proto includes every type of field in both singular and repeated
+// forms.
+message TestAllTypes {
+  message NestedMessage {
+    // The field name "b" fails to compile in proto1 because it conflicts with
+    // a local variable named "b" in one of the generated methods.  Doh.
+    // This file needs to compile in proto1 to test backwards-compatibility.
+    int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    ZERO = 0;
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+    NEG = -1;  // Intentionally negative.
+  }
+
+  // Singular
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
+
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
+
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
+
+  // Defined in unittest_import_public.proto
+  protobuf_unittest_import.PublicImportMessage
+      optional_public_import_message = 26;
+
+  NestedMessage optional_lazy_message = 27 [lazy=true];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
+
+  repeated NestedMessage                        repeated_nested_message  = 48;
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessage repeated_import_message  = 50;
+
+  repeated NestedEnum                           repeated_nested_enum     = 51;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Omitted (compared to unittest.proto) because proto2 enums are not allowed
+  // inside proto2 messages.
+  //
+  // repeated protobuf_unittest_import.ImportEnum    repeated_import_enum  = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  repeated NestedMessage repeated_lazy_message = 57 [lazy=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    NestedMessage oneof_nested_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+// Test messages for packed fields
+
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
+// This proto includes a recusively nested message.
+message NestedTestAllTypes {
+  NestedTestAllTypes child = 1;
+  TestAllTypes payload = 2;
+}
+
+// Define these after TestAllTypes to make sure the compiler can handle
+// that.
+message ForeignMessage {
+  int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_ZERO = 0;
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+// TestEmptyMessage is used to test behavior of unknown fields.
+message TestEmptyMessage {
+}
+
diff --git a/src/google/protobuf/unittest_recursive_micro.proto b/src/google/protobuf/unittest_recursive_micro.proto
deleted file mode 100644
index 078ca9c..0000000
--- a/src/google/protobuf/unittest_recursive_micro.proto
+++ /dev/null
@@ -1,49 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.micro";
-// Explicit outer classname to suppress legacy info.
-option java_outer_classname = "UnittestRecursiveMicro";
-
-message RecursiveMessageMicro {
-  message NestedMessage {
-    optional RecursiveMessageMicro a = 1;
-  }
-
-  required int32 id = 1;
-  optional NestedMessage nested_message = 2;
-  optional RecursiveMessageMicro optional_recursive_message_micro = 3;
-  repeated RecursiveMessageMicro repeated_recursive_message_micro = 4;
-}
diff --git a/src/google/protobuf/unittest_recursive_nano.proto b/src/google/protobuf/unittest_recursive_nano.proto
deleted file mode 100644
index 3d3a6aa..0000000
--- a/src/google/protobuf/unittest_recursive_nano.proto
+++ /dev/null
@@ -1,49 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.nano";
-// Explicit outer classname to suppress legacy info.
-option java_outer_classname = "UnittestRecursiveNano";
-
-message RecursiveMessageNano {
-  message NestedMessage {
-    optional RecursiveMessageNano a = 1;
-  }
-
-  required int32 id = 1;
-  optional NestedMessage nested_message = 2;
-  optional RecursiveMessageNano optional_recursive_message_nano = 3;
-  repeated RecursiveMessageNano repeated_recursive_message_nano = 4;
-}
diff --git a/src/google/protobuf/unittest_reference_types_nano.proto b/src/google/protobuf/unittest_reference_types_nano.proto
deleted file mode 100644
index 2b24615..0000000
--- a/src/google/protobuf/unittest_reference_types_nano.proto
+++ /dev/null
@@ -1,116 +0,0 @@
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "NanoReferenceTypes";
-
-message TestAllTypesNano {
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  message NestedMessage {
-    optional int32 foo = 1;
-  }
-
-  // Singular
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
-
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
-
-  optional NestedMessage      optional_nested_message  = 18;
-
-  optional NestedEnum      optional_nested_enum     = 21;
-
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
-
-  // Repeated
-  repeated    int32 repeated_int32    = 31;
-  repeated    int64 repeated_int64    = 32;
-  repeated   uint32 repeated_uint32   = 33;
-  repeated   uint64 repeated_uint64   = 34;
-  repeated   sint32 repeated_sint32   = 35;
-  repeated   sint64 repeated_sint64   = 36;
-  repeated  fixed32 repeated_fixed32  = 37;
-  repeated  fixed64 repeated_fixed64  = 38;
-  repeated sfixed32 repeated_sfixed32 = 39;
-  repeated sfixed64 repeated_sfixed64 = 40;
-  repeated    float repeated_float    = 41;
-  repeated   double repeated_double   = 42;
-  repeated     bool repeated_bool     = 43;
-  repeated   string repeated_string   = 44;
-  repeated    bytes repeated_bytes    = 45;
-
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
-
-  repeated NestedMessage      repeated_nested_message  = 48;
-
-  repeated NestedEnum      repeated_nested_enum  = 51;
-
-  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
-  repeated string repeated_cord = 55 [ctype=CORD];
-
-  // Repeated packed
-  repeated    int32 repeated_packed_int32    = 87 [packed=true];
-  repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true];
-
-  repeated NestedEnum repeated_packed_nested_enum  = 89 [packed=true];
-
-  // Singular with defaults
-  optional    int32 default_int32    = 61 [default =  41    ];
-  optional    int64 default_int64    = 62 [default =  42    ];
-  optional   uint32 default_uint32   = 63 [default =  43    ];
-  optional   uint64 default_uint64   = 64 [default =  44    ];
-  optional   sint32 default_sint32   = 65 [default = -45    ];
-  optional   sint64 default_sint64   = 66 [default =  46    ];
-  optional  fixed32 default_fixed32  = 67 [default =  47    ];
-  optional  fixed64 default_fixed64  = 68 [default =  48    ];
-  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
-  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
-  optional    float default_float    = 71 [default =  51.5  ];
-  optional   double default_double   = 72 [default =  52e3  ];
-  optional     bool default_bool     = 73 [default = true   ];
-  optional   string default_string   = 74 [default = "hello"];
-  optional    bytes default_bytes    = 75 [default = "world"];
-
-
-  optional  float default_float_inf      = 97  [default =  inf];
-  optional  float default_float_neg_inf  = 98  [default = -inf];
-  optional  float default_float_nan      = 99  [default =  nan];
-  optional double default_double_inf     = 100 [default =  inf];
-  optional double default_double_neg_inf = 101 [default = -inf];
-  optional double default_double_nan     = 102 [default =  nan];
-
-}
-
-message ForeignMessageNano {
-  optional int32 c = 1;
-}
-
-enum ForeignEnumNano {
-  FOREIGN_NANO_FOO = 4;
-  FOREIGN_NANO_BAR = 5;
-  FOREIGN_NANO_BAZ = 6;
-}
-
diff --git a/src/google/protobuf/unittest_repeated_merge_nano.proto b/src/google/protobuf/unittest_repeated_merge_nano.proto
deleted file mode 100644
index 4f03224..0000000
--- a/src/google/protobuf/unittest_repeated_merge_nano.proto
+++ /dev/null
@@ -1,47 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest;
-
-import "google/protobuf/unittest_nano.proto";
-
-option java_package = "com.google.protobuf.nano";
-option java_multiple_files = true;
-
-// A container message for testing the merging of repeated fields at a
-// nested level. Other tests will be done using the repeated fields in
-// TestAllTypesNano.
-message TestRepeatedMergeNano {
-
-  optional TestAllTypesNano contained = 1;
-
-}
diff --git a/src/google/protobuf/unittest_repeated_packables_nano.proto b/src/google/protobuf/unittest_repeated_packables_nano.proto
deleted file mode 100644
index 1c78918..0000000
--- a/src/google/protobuf/unittest_repeated_packables_nano.proto
+++ /dev/null
@@ -1,95 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest;
-
-option java_package = "com.google.protobuf.nano";
-option java_outer_classname = "NanoRepeatedPackables";
-
-enum Enum {
-  OPTION_ONE = 1;
-  OPTION_TWO = 2;
-}
-
-// Two almost identical messages with all packable repeated field types.
-// One with none marked as packed and the other all packed. For
-// compatibility, they should be able to parse each other's serialized
-// forms.
-
-message NonPacked {
-
-  // All packable types, none marked as packed.
-
-  repeated    int32 int32s    = 1;
-  repeated    int64 int64s    = 2;
-  repeated   uint32 uint32s   = 3;
-  repeated   uint64 uint64s   = 4;
-  repeated   sint32 sint32s   = 5;
-  repeated   sint64 sint64s   = 6;
-  repeated  fixed32 fixed32s  = 7;
-  repeated  fixed64 fixed64s  = 8;
-  repeated sfixed32 sfixed32s = 9;
-  repeated sfixed64 sfixed64s = 10;
-  repeated    float floats    = 11;
-  repeated   double doubles   = 12;
-  repeated     bool bools     = 13;
-  repeated     Enum enums     = 14;
-
-  // Noise for testing merged deserialization.
-  optional int32 noise = 15;
-
-}
-
-message Packed {
-
-  // All packable types, all matching the field numbers in NonPacked,
-  // all marked as packed.
-
-  repeated    int32 int32s    = 1  [ packed = true ];
-  repeated    int64 int64s    = 2  [ packed = true ];
-  repeated   uint32 uint32s   = 3  [ packed = true ];
-  repeated   uint64 uint64s   = 4  [ packed = true ];
-  repeated   sint32 sint32s   = 5  [ packed = true ];
-  repeated   sint64 sint64s   = 6  [ packed = true ];
-  repeated  fixed32 fixed32s  = 7  [ packed = true ];
-  repeated  fixed64 fixed64s  = 8  [ packed = true ];
-  repeated sfixed32 sfixed32s = 9  [ packed = true ];
-  repeated sfixed64 sfixed64s = 10 [ packed = true ];
-  repeated    float floats    = 11 [ packed = true ];
-  repeated   double doubles   = 12 [ packed = true ];
-  repeated     bool bools     = 13 [ packed = true ];
-  repeated     Enum enums     = 14 [ packed = true ];
-
-  // Noise for testing merged deserialization.
-  optional int32 noise = 15;
-
-}
diff --git a/src/google/protobuf/unittest_simple_micro.proto b/src/google/protobuf/unittest_simple_micro.proto
deleted file mode 100644
index 09d4aab..0000000
--- a/src/google/protobuf/unittest_simple_micro.proto
+++ /dev/null
@@ -1,54 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.micro";
-// Explicit outer classname to suppress legacy info
-option java_outer_classname = "UnittestSimpleMicro";
-
-message SimpleMessageMicro {
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  optional int32 d = 1 [default = 123];
-  optional NestedMessage nested_msg = 2;
-  optional NestedEnum default_nested_enum = 3 [default = BAZ];
-}
diff --git a/src/google/protobuf/unittest_simple_nano.proto b/src/google/protobuf/unittest_simple_nano.proto
deleted file mode 100644
index 0c780c7..0000000
--- a/src/google/protobuf/unittest_simple_nano.proto
+++ /dev/null
@@ -1,54 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.nano";
-// Explicit outer classname to suppress legacy info.
-option java_outer_classname = "UnittestSimpleNano";
-
-message SimpleMessageNano {
-  message NestedMessage {
-    optional int32 bb = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-    BAZ = 3;
-  }
-
-  optional int32 d = 1 [default = 123];
-  optional NestedMessage nested_msg = 2;
-  optional NestedEnum default_nested_enum = 3 [default = BAZ];
-}
diff --git a/src/google/protobuf/unittest_single_micro.proto b/src/google/protobuf/unittest_single_micro.proto
deleted file mode 100644
index 17e0645..0000000
--- a/src/google/protobuf/unittest_single_micro.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.micro";
-
-message SingleMessageMicro {
-}
diff --git a/src/google/protobuf/unittest_single_nano.proto b/src/google/protobuf/unittest_single_nano.proto
deleted file mode 100644
index fcb1539..0000000
--- a/src/google/protobuf/unittest_single_nano.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: maxtroy@google.com (Max Cai)
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.nano";
-
-message SingleMessageNano {
-}
diff --git a/src/google/protobuf/unittest_stringutf8_micro.proto b/src/google/protobuf/unittest_stringutf8_micro.proto
deleted file mode 100644
index 68bd5ef..0000000
--- a/src/google/protobuf/unittest_stringutf8_micro.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.micro";
-// Explicit outer classname to suppress legacy info.
-option java_outer_classname = "UnittestStringutf8Micro";
-
-message StringUtf8 {
-  optional string id = 1;
-  repeated string rs = 2;
-}
diff --git a/src/google/protobuf/unittest_stringutf8_nano.proto b/src/google/protobuf/unittest_stringutf8_nano.proto
deleted file mode 100644
index 2bbf2b7..0000000
--- a/src/google/protobuf/unittest_stringutf8_nano.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-// Author: wink@google.com (Wink Saville)
-//
-
-package protobuf_unittest_import;
-
-option java_package = "com.google.protobuf.nano";
-// Explicit outer classname to suppress legacy info.
-option java_outer_classname = "UnittestStringutf8Nano";
-
-message StringUtf8 {
-  optional string id = 1;
-  repeated string rs = 2;
-}
diff --git a/src/google/protobuf/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto
new file mode 100644
index 0000000..c907524
--- /dev/null
+++ b/src/google/protobuf/unittest_well_known_types.proto
@@ -0,0 +1,114 @@
+syntax = "proto3";
+
+package protobuf_unittest;
+
+option csharp_namespace = "Google.Protobuf.TestProtos";
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.test";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/api.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/source_context.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/type.proto";
+import "google/protobuf/wrappers.proto";
+
+// Test that we can include all well-known types.
+// Each wrapper type is included separately, as languages
+// map handle different wrappers in different ways.
+message TestWellKnownTypes {
+  google.protobuf.Any any_field = 1;
+  google.protobuf.Api api_field = 2;
+  google.protobuf.Duration duration_field = 3;
+  google.protobuf.Empty empty_field = 4;
+  google.protobuf.FieldMask field_mask_field = 5;
+  google.protobuf.SourceContext source_context_field = 6;
+  google.protobuf.Struct struct_field = 7;
+  google.protobuf.Timestamp timestamp_field = 8;
+  google.protobuf.Type type_field = 9;
+  google.protobuf.DoubleValue double_field = 10;
+  google.protobuf.FloatValue float_field = 11;
+  google.protobuf.Int64Value int64_field = 12;
+  google.protobuf.UInt64Value uint64_field = 13;
+  google.protobuf.Int32Value int32_field = 14;
+  google.protobuf.UInt32Value uint32_field = 15;
+  google.protobuf.BoolValue bool_field = 16;
+  google.protobuf.StringValue string_field = 17;
+  google.protobuf.BytesValue bytes_field = 18;
+  // Part of struct, but useful to be able to test separately
+  google.protobuf.Value value_field = 19;
+}
+
+// A repeated field for each well-known type.
+message RepeatedWellKnownTypes {
+  repeated google.protobuf.Any any_field = 1;
+  repeated google.protobuf.Api api_field = 2;
+  repeated google.protobuf.Duration duration_field = 3;
+  repeated google.protobuf.Empty empty_field = 4;
+  repeated google.protobuf.FieldMask field_mask_field = 5;
+  repeated google.protobuf.SourceContext source_context_field = 6;
+  repeated google.protobuf.Struct struct_field = 7;
+  repeated google.protobuf.Timestamp timestamp_field = 8;
+  repeated google.protobuf.Type type_field = 9;
+  // These don't actually make a lot of sense, but they're not prohibited...
+  repeated google.protobuf.DoubleValue double_field = 10;
+  repeated google.protobuf.FloatValue float_field = 11;
+  repeated google.protobuf.Int64Value int64_field = 12;
+  repeated google.protobuf.UInt64Value uint64_field = 13;
+  repeated google.protobuf.Int32Value int32_field = 14;
+  repeated google.protobuf.UInt32Value uint32_field = 15;
+  repeated google.protobuf.BoolValue bool_field = 16;
+  repeated google.protobuf.StringValue string_field = 17;
+  repeated google.protobuf.BytesValue bytes_field = 18;
+}
+
+message OneofWellKnownTypes {
+  oneof oneof_field {
+    google.protobuf.Any any_field = 1;
+    google.protobuf.Api api_field = 2;
+    google.protobuf.Duration duration_field = 3;
+    google.protobuf.Empty empty_field = 4;
+    google.protobuf.FieldMask field_mask_field = 5;
+    google.protobuf.SourceContext source_context_field = 6;
+    google.protobuf.Struct struct_field = 7;
+    google.protobuf.Timestamp timestamp_field = 8;
+    google.protobuf.Type type_field = 9;
+    google.protobuf.DoubleValue double_field = 10;
+    google.protobuf.FloatValue float_field = 11;
+    google.protobuf.Int64Value int64_field = 12;
+    google.protobuf.UInt64Value uint64_field = 13;
+    google.protobuf.Int32Value int32_field = 14;
+    google.protobuf.UInt32Value uint32_field = 15;
+    google.protobuf.BoolValue bool_field = 16;
+    google.protobuf.StringValue string_field = 17;
+    google.protobuf.BytesValue bytes_field = 18;
+  }
+}
+
+// A map field for each well-known type. We only
+// need to worry about the value part of the map being the
+// well-known types, as messages can't be map keys.
+message MapWellKnownTypes {
+  map<int32,google.protobuf.Any> any_field = 1;
+  map<int32,google.protobuf.Api> api_field = 2;
+  map<int32,google.protobuf.Duration> duration_field = 3;
+  map<int32,google.protobuf.Empty> empty_field = 4;
+  map<int32,google.protobuf.FieldMask> field_mask_field = 5;
+  map<int32,google.protobuf.SourceContext> source_context_field = 6;
+  map<int32,google.protobuf.Struct> struct_field = 7;
+  map<int32,google.protobuf.Timestamp> timestamp_field = 8;
+  map<int32,google.protobuf.Type> type_field = 9;
+  map<int32,google.protobuf.DoubleValue> double_field = 10;
+  map<int32,google.protobuf.FloatValue> float_field = 11;
+  map<int32,google.protobuf.Int64Value> int64_field = 12;
+  map<int32,google.protobuf.UInt64Value> uint64_field = 13;
+  map<int32,google.protobuf.Int32Value> int32_field = 14;
+  map<int32,google.protobuf.UInt32Value> uint32_field = 15;
+  map<int32,google.protobuf.BoolValue> bool_field = 16;
+  map<int32,google.protobuf.StringValue> string_field = 17;
+  map<int32,google.protobuf.BytesValue> bytes_field = 18;
+}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 020a323..d4e383d 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -34,6 +34,7 @@
 
 #include <google/protobuf/unknown_field_set.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -44,6 +45,30 @@
 namespace google {
 namespace protobuf {
 
+namespace {
+// This global instance is returned by unknown_fields() on any message class
+// when the object has no unknown fields. This is necessary because we now
+// instantiate the UnknownFieldSet dynamically only when required.
+UnknownFieldSet* default_unknown_field_set_instance_ = NULL;
+
+void DeleteDefaultUnknownFieldSet() {
+  delete default_unknown_field_set_instance_;
+}
+
+void InitDefaultUnknownFieldSet() {
+  default_unknown_field_set_instance_ = new UnknownFieldSet();
+  internal::OnShutdown(&DeleteDefaultUnknownFieldSet);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(default_unknown_field_set_once_init_);
+}
+
+const UnknownFieldSet* UnknownFieldSet::default_instance() {
+  ::google::protobuf::GoogleOnceInit(&default_unknown_field_set_once_init_,
+                 &InitDefaultUnknownFieldSet);
+  return default_unknown_field_set_instance_;
+}
+
 UnknownFieldSet::UnknownFieldSet()
     : fields_(NULL) {}
 
@@ -53,31 +78,63 @@
 }
 
 void UnknownFieldSet::ClearFallback() {
-  GOOGLE_DCHECK(fields_ != NULL);
-  for (int i = 0; i < fields_->size(); i++) {
-    (*fields_)[i].Delete();
-  }
-  fields_->clear();
-}
-
-void UnknownFieldSet::ClearAndFreeMemory() {
   if (fields_ != NULL) {
-    Clear();
+    for (int i = 0; i < fields_->size(); i++) {
+      (*fields_)[i].Delete();
+    }
     delete fields_;
     fields_ = NULL;
   }
 }
 
-void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
-  for (int i = 0; i < other.field_count(); i++) {
-    AddField(other.field(i));
+void UnknownFieldSet::ClearAndFreeMemory() {
+  if (fields_ != NULL) {
+    Clear();
   }
 }
 
+void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    fields_ = new vector<UnknownField>();
+    for (int i = 0; i < other_field_count; i++) {
+      fields_->push_back((*other.fields_)[i]);
+      fields_->back().DeepCopy((*other.fields_)[i]);
+    }
+  }
+}
+
+void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
+  int other_field_count = other.field_count();
+  if (other_field_count > 0) {
+    if (fields_ == NULL) fields_ = new vector<UnknownField>();
+    for (int i = 0; i < other_field_count; i++) {
+      fields_->push_back((*other.fields_)[i]);
+      fields_->back().DeepCopy((*other.fields_)[i]);
+    }
+  }
+}
+
+// A specialized MergeFrom for performance when we are merging from an UFS that
+// is temporary and can be destroyed in the process.
+void UnknownFieldSet::MergeFromAndDestroy(UnknownFieldSet* other) {
+  int other_field_count = other->field_count();
+  if (other_field_count > 0) {
+    if (fields_ == NULL) fields_ = new vector<UnknownField>();
+    for (int i = 0; i < other_field_count; i++) {
+      fields_->push_back((*other->fields_)[i]);
+      (*other->fields_)[i].Reset();
+    }
+  }
+  delete other->fields_;
+  other->fields_ = NULL;
+}
+
 int UnknownFieldSet::SpaceUsedExcludingSelf() const {
   if (fields_ == NULL) return 0;
 
   int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size();
+
   for (int i = 0; i < fields_->size(); i++) {
     const UnknownField& field = (*fields_)[i];
     switch (field.type()) {
@@ -101,61 +158,60 @@
 }
 
 void UnknownFieldSet::AddVarint(int number, uint64 value) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_VARINT);
   field.varint_ = value;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
 }
 
 void UnknownFieldSet::AddFixed32(int number, uint32 value) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_FIXED32);
   field.fixed32_ = value;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
 }
 
 void UnknownFieldSet::AddFixed64(int number, uint64 value) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_FIXED64);
   field.fixed64_ = value;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
 }
 
 string* UnknownFieldSet::AddLengthDelimited(int number) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_LENGTH_DELIMITED);
   field.length_delimited_.string_value_ = new string;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
   return field.length_delimited_.string_value_;
 }
 
 
 UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_GROUP);
   field.group_ = new UnknownFieldSet;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
   return field.group_;
 }
 
 void UnknownFieldSet::AddField(const UnknownField& field) {
-  if (fields_ == NULL) fields_ = new vector<UnknownField>;
+  if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
-  fields_->back().DeepCopy();
+  fields_->back().DeepCopy(field);
 }
 
 void UnknownFieldSet::DeleteSubrange(int start, int num) {
-  GOOGLE_DCHECK(fields_ != NULL);
   // Delete the specified fields.
   for (int i = 0; i < num; ++i) {
     (*fields_)[i + start].Delete();
@@ -168,6 +224,11 @@
   for (int i = 0; i < num; ++i) {
     fields_->pop_back();
   }
+  if (fields_ && fields_->size() == 0) {
+    // maintain invariant: never hold fields_ if empty.
+    delete fields_;
+    fields_ = NULL;
+  }
 }
 
 void UnknownFieldSet::DeleteByNumber(int number) {
@@ -185,13 +246,18 @@
     }
   }
   fields_->resize(left);
+  if (left == 0) {
+    // maintain invariant: never hold fields_ if empty.
+    delete fields_;
+    fields_ = NULL;
+  }
 }
 
 bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
   UnknownFieldSet other;
   if (internal::WireFormat::SkipMessage(input, &other) &&
       input->ConsumedEntireMessage()) {
-    MergeFrom(other);
+    MergeFromAndDestroy(&other);
     return true;
   } else {
     return false;
@@ -227,15 +293,31 @@
   }
 }
 
-void UnknownField::DeepCopy() {
+// Reset all owned ptrs, a special function for performance, to avoid double
+// owning the ptrs, when we merge from a temporary UnknownFieldSet objects.
+void UnknownField::Reset() {
+  switch (type()) {
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      length_delimited_.string_value_ = NULL;
+      break;
+    case UnknownField::TYPE_GROUP: {
+      group_ = NULL;
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+void UnknownField::DeepCopy(const UnknownField& other) {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
       length_delimited_.string_value_ = new string(
           *length_delimited_.string_value_);
       break;
     case UnknownField::TYPE_GROUP: {
-      UnknownFieldSet* group = new UnknownFieldSet;
-      group->MergeFrom(*group_);
+      UnknownFieldSet* group = new UnknownFieldSet();
+      group->InternalMergeFrom(*group_);
       group_ = group;
       break;
     }
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 31f17e2..612a942 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -42,6 +42,7 @@
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 
 namespace google {
 namespace protobuf {
@@ -88,6 +89,9 @@
   // Merge the contents of some other UnknownFieldSet with this one.
   void MergeFrom(const UnknownFieldSet& other);
 
+  // Similar to above, but this function will destroy the contents of other.
+  void MergeFromAndDestroy(UnknownFieldSet* other);
+
   // Swaps the contents of some other UnknownFieldSet with this one.
   inline void Swap(UnknownFieldSet* x);
 
@@ -141,12 +145,22 @@
     return ParseFromArray(data.data(), static_cast<int>(data.size()));
   }
 
+  static const UnknownFieldSet* default_instance();
  private:
-
+  // For InternalMergeFrom
+  friend class UnknownField;
+  // Merges from other UnknownFieldSet. This method assumes, that this object
+  // is newly created and has fields_ == NULL;
+  void InternalMergeFrom(const UnknownFieldSet& other);
   void ClearFallback();
 
+  // fields_ is either NULL, or a pointer to a vector that is *non-empty*. We
+  // never hold the empty vector because we want the 'do we have any unknown
+  // fields' check to be fast, and avoid a cache miss: the UFS instance gets
+  // embedded in the message object, so 'fields_ != NULL' tests a member
+  // variable hot in the cache, without the need to go touch a vector somewhere
+  // else in memory.
   std::vector<UnknownField>* fields_;
-
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
 };
 
@@ -198,22 +212,28 @@
   // If this UnknownField contains a pointer, delete it.
   void Delete();
 
+  // Reset all the underlying pointers to NULL. A special function to be only
+  // used while merging from a temporary UFS.
+  void Reset();
+
   // Make a deep copy of any pointers in this UnknownField.
-  void DeepCopy();
+  void DeepCopy(const UnknownField& other);
 
   // Set the wire type of this UnknownField. Should only be used when this
   // UnknownField is being created.
   inline void SetType(Type type);
 
+  union LengthDelimited {
+    string* string_value_;
+  };
+
   uint32 number_;
   uint32 type_;
   union {
     uint64 varint_;
     uint32 fixed32_;
     uint64 fixed64_;
-    mutable union {
-      string* string_value_;
-    } length_delimited_;
+    mutable union LengthDelimited length_delimited_;
     UnknownFieldSet* group_;
   };
 };
@@ -222,13 +242,14 @@
 // inline implementations
 
 inline void UnknownFieldSet::Clear() {
-  if (fields_ != NULL) {
+  if (fields_) {
     ClearFallback();
   }
 }
 
 inline bool UnknownFieldSet::empty() const {
-  return fields_ == NULL || fields_->empty();
+  // Invariant: fields_ is never empty if present.
+  return !fields_;
 }
 
 inline void UnknownFieldSet::Swap(UnknownFieldSet* x) {
@@ -236,9 +257,10 @@
 }
 
 inline int UnknownFieldSet::field_count() const {
-  return (fields_ == NULL) ? 0 : static_cast<int>(fields_->size());
+  return fields_ ? static_cast<int>(fields_->size()) : 0;
 }
 inline const UnknownField& UnknownFieldSet::field(int index) const {
+  GOOGLE_DCHECK(fields_ != NULL);
   return (*fields_)[index];
 }
 inline UnknownField* UnknownFieldSet::mutable_field(int index) {
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index aaaa2e8..5de7263 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -43,7 +43,10 @@
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/test_util.h>
 
+#include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/stl_util.h>
@@ -482,6 +485,13 @@
   }
 }
 
+TEST_F(UnknownFieldSetTest, SpaceUsedExcludingSelf) {
+  UnknownFieldSet empty;
+  empty.AddVarint(1, 0);
+  EXPECT_EQ(sizeof(vector<UnknownField>) + sizeof(UnknownField),
+            empty.SpaceUsedExcludingSelf());
+}
+
 TEST_F(UnknownFieldSetTest, SpaceUsed) {
   unittest::TestEmptyMessage empty_message;
 
diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc
new file mode 100644
index 0000000..60b8b8a
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator.cc
@@ -0,0 +1,208 @@
+// 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.
+
+// Author: ksroka@google.com (Krzysztof Sroka)
+
+#include <google/protobuf/util/field_comparator.h>
+
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+FieldComparator::FieldComparator() {}
+FieldComparator::~FieldComparator() {}
+
+DefaultFieldComparator::DefaultFieldComparator()
+    : float_comparison_(EXACT),
+      treat_nan_as_equal_(false),
+      has_default_tolerance_(false) {
+}
+
+DefaultFieldComparator::~DefaultFieldComparator() {}
+
+FieldComparator::ComparisonResult DefaultFieldComparator::Compare(
+      const google::protobuf::Message& message_1,
+      const google::protobuf::Message& message_2,
+      const google::protobuf::FieldDescriptor* field,
+      int index_1, int index_2,
+      const google::protobuf::util::FieldContext* field_context) {
+  const Reflection* reflection_1 = message_1.GetReflection();
+  const Reflection* reflection_2 = message_2.GetReflection();
+
+  switch (field->cpp_type()) {
+#define COMPARE_FIELD(METHOD)                                              \
+    if (field->is_repeated()) {                                            \
+      return ResultFromBoolean(Compare##METHOD(                            \
+          *field,                                                          \
+          reflection_1->GetRepeated##METHOD(message_1, field, index_1),    \
+          reflection_2->GetRepeated##METHOD(message_2, field, index_2)));  \
+    } else {                                                               \
+      return ResultFromBoolean(Compare##METHOD(                            \
+          *field,                                                          \
+          reflection_1->Get##METHOD(message_1, field),                     \
+          reflection_2->Get##METHOD(message_2, field)));                   \
+    }                                                                      \
+    break;  // Make sure no fall-through is introduced.
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      COMPARE_FIELD(Bool);
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      COMPARE_FIELD(Double);
+    case FieldDescriptor::CPPTYPE_ENUM:
+      COMPARE_FIELD(Enum);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      COMPARE_FIELD(Float);
+    case FieldDescriptor::CPPTYPE_INT32:
+      COMPARE_FIELD(Int32);
+    case FieldDescriptor::CPPTYPE_INT64:
+      COMPARE_FIELD(Int64);
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->is_repeated()) {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        string scratch1;
+        string scratch2;
+        return ResultFromBoolean(
+            CompareString(*field, reflection_1->GetRepeatedStringReference(
+                                      message_1, field, index_1, &scratch1),
+                          reflection_2->GetRepeatedStringReference(
+                              message_2, field, index_2, &scratch2)));
+      } else {
+        // Allocate scratch strings to store the result if a conversion is
+        // needed.
+        string scratch1;
+        string scratch2;
+        return ResultFromBoolean(CompareString(
+            *field,
+            reflection_1->GetStringReference(message_1, field, &scratch1),
+            reflection_2->GetStringReference(message_2, field, &scratch2)));
+      }
+      break;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      COMPARE_FIELD(UInt32);
+    case FieldDescriptor::CPPTYPE_UINT64:
+      COMPARE_FIELD(UInt64);
+
+#undef COMPARE_FIELD
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return RECURSE;
+
+    default:
+      GOOGLE_LOG(FATAL) << "No comparison code for field " << field->full_name()
+                 << " of CppType = " << field->cpp_type();
+      return DIFFERENT;
+  }
+}
+
+void DefaultFieldComparator::SetDefaultFractionAndMargin(double fraction,
+                                                         double margin) {
+  default_tolerance_ = Tolerance(fraction, margin);
+  has_default_tolerance_ = true;
+}
+
+void DefaultFieldComparator::SetFractionAndMargin(const FieldDescriptor* field,
+                                                  double fraction,
+                                                  double margin) {
+  GOOGLE_CHECK(FieldDescriptor::CPPTYPE_FLOAT == field->cpp_type() ||
+        FieldDescriptor::CPPTYPE_DOUBLE == field->cpp_type())
+      << "Field has to be float or double type. Field name is: "
+      << field->full_name();
+  map_tolerance_[field] = Tolerance(fraction, margin);
+}
+
+bool DefaultFieldComparator::CompareDouble(const FieldDescriptor& field,
+                                           double value_1, double value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+bool DefaultFieldComparator::CompareEnum(const FieldDescriptor& field,
+                                         const EnumValueDescriptor* value_1,
+                                         const EnumValueDescriptor* value_2) {
+  return value_1->number() == value_2->number();
+}
+
+bool DefaultFieldComparator::CompareFloat(const FieldDescriptor& field,
+                                          float value_1, float value_2) {
+  return CompareDoubleOrFloat(field, value_1, value_2);
+}
+
+template<typename T>
+bool DefaultFieldComparator::CompareDoubleOrFloat(const FieldDescriptor& field,
+                                                  T value_1, T value_2) {
+  if (value_1 == value_2) {
+    // Covers +inf and -inf (which are not within margin or fraction of
+    // themselves), and is a shortcut for finite values.
+    return true;
+  } else if (float_comparison_ == EXACT) {
+    if (treat_nan_as_equal_ &&
+        MathLimits<T>::IsNaN(value_1) && MathLimits<T>::IsNaN(value_2)) {
+      return true;
+    }
+    return false;
+  } else {
+    if (treat_nan_as_equal_ &&
+        MathLimits<T>::IsNaN(value_1) && MathLimits<T>::IsNaN(value_2)) {
+      return true;
+    }
+    // float_comparison_ == APPROXIMATE covers two use cases.
+    Tolerance* tolerance = FindOrNull(map_tolerance_, &field);
+    if (tolerance == NULL && has_default_tolerance_) {
+      tolerance = &default_tolerance_;
+    }
+    if (tolerance == NULL) {
+      return MathUtil::AlmostEquals(value_1, value_2);
+    } else {
+      // Use user-provided fraction and margin. Since they are stored as
+      // doubles, we explicitely cast them to types of values provided. This
+      // is very likely to fail if provided values are not numeric.
+      return MathUtil::WithinFractionOrMargin(
+          value_1, value_2, static_cast<T>(tolerance->fraction),
+          static_cast<T>(tolerance->margin));
+    }
+  }
+}
+
+FieldComparator::ComparisonResult DefaultFieldComparator::ResultFromBoolean(
+    bool boolean_result) const {
+  return boolean_result ? FieldComparator::SAME : FieldComparator::DIFFERENT;
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h
new file mode 100644
index 0000000..1b4d65b
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator.h
@@ -0,0 +1,259 @@
+// 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.
+
+// Author: ksroka@google.com (Krzysztof Sroka)
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+class EnumValueDescriptor;
+class FieldDescriptor;
+
+namespace util {
+
+class FieldContext;
+
+// Base class specifying the interface for comparing protocol buffer fields.
+// Regular users should consider using or subclassing DefaultFieldComparator
+// rather than this interface.
+// Currently, this does not support comparing unknown fields.
+class LIBPROTOBUF_EXPORT FieldComparator {
+ public:
+  FieldComparator();
+  virtual ~FieldComparator();
+
+  enum ComparisonResult {
+    SAME,       // Compared fields are equal. In case of comparing submessages,
+                // user should not recursively compare their contents.
+    DIFFERENT,  // Compared fields are different. In case of comparing
+                // submessages, user should not recursively compare their
+                // contents.
+    RECURSE,    // Compared submessages need to be compared recursively.
+                // FieldComparator does not specify the semantics of recursive
+                // comparison. This value should not be returned for simple
+                // values.
+  };
+
+  // Compares the values of a field in two protocol buffer messages.
+  // Returns SAME or DIFFERENT for simple values, and SAME, DIFFERENT or RECURSE
+  // for submessages. Returning RECURSE for fields not being submessages is
+  // illegal.
+  // In case the given FieldDescriptor points to a repeated field, the indices
+  // need to be valid. Otherwise they should be ignored.
+  //
+  // FieldContext contains information about the specific instances of the
+  // fields being compared, versus FieldDescriptor which only contains general
+  // type information about the fields.
+  virtual ComparisonResult Compare(
+      const google::protobuf::Message& message_1,
+      const google::protobuf::Message& message_2,
+      const google::protobuf::FieldDescriptor* field,
+      int index_1, int index_2,
+      const google::protobuf::util::FieldContext* field_context) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator);
+};
+
+// Basic implementation of FieldComparator.  Supports three modes of floating
+// point value comparison: exact, approximate using MathUtil::AlmostEqual
+// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
+class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator {
+ public:
+  enum FloatComparison {
+     EXACT,               // Floats and doubles are compared exactly.
+     APPROXIMATE,         // Floats and doubles are compared using the
+                          // MathUtil::AlmostEqual method or
+                          // MathUtil::WithinFractionOrMargin method.
+     // TODO(ksroka): Introduce third value to differenciate uses of AlmostEqual
+     //               and WithinFractionOrMargin.
+  };
+
+  // Creates new comparator with float comparison set to EXACT.
+  DefaultFieldComparator();
+
+  virtual ~DefaultFieldComparator();
+
+  virtual ComparisonResult Compare(
+      const google::protobuf::Message& message_1,
+      const google::protobuf::Message& message_2,
+      const google::protobuf::FieldDescriptor* field,
+      int index_1, int index_2,
+      const google::protobuf::util::FieldContext* field_context);
+
+  void set_float_comparison(FloatComparison float_comparison) {
+    float_comparison_ = float_comparison;
+  }
+
+  FloatComparison float_comparison() const {
+    return float_comparison_;
+  }
+
+  // Set whether the FieldComparator shall treat floats or doubles that are both
+  // NaN as equal (treat_nan_as_equal = true) or as different
+  // (treat_nan_as_equal = false). Default is treating NaNs always as different.
+  void set_treat_nan_as_equal(bool treat_nan_as_equal) {
+    treat_nan_as_equal_ = treat_nan_as_equal;
+  }
+
+  bool treat_nan_as_equal() const {
+    return treat_nan_as_equal_;
+  }
+
+  // Sets the fraction and margin for the float comparison of a given field.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  //
+  // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
+  //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
+                            double margin);
+
+  // Sets the fraction and margin for the float comparison of all float and
+  // double fields, unless a field has been given a specific setting via
+  // SetFractionAndMargin() above.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  //
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetDefaultFractionAndMargin(double fraction, double margin);
+
+ private:
+  // Defines the tolerance for floating point comparison (fraction and margin).
+  struct Tolerance {
+    double fraction;
+    double margin;
+    Tolerance()
+        : fraction(0.0),
+          margin(0.0) {}
+    Tolerance(double f, double m)
+        : fraction(f),
+          margin(m) {}
+  };
+
+  // Defines the map to store the tolerances for floating point comparison.
+  typedef map<const FieldDescriptor*, Tolerance> ToleranceMap;
+
+  // The following methods get executed when CompareFields is called for the
+  // basic types (instead of submessages). They return true on success. One
+  // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
+  // value.
+  bool CompareBool(const google::protobuf::FieldDescriptor& field,
+                   bool value_1, bool value_2) {
+    return value_1 == value_2;
+  }
+
+  // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
+  // CompareFloat.
+  bool CompareDouble(const google::protobuf::FieldDescriptor& field,
+                     double value_1, double value_2);
+
+  bool CompareEnum(const google::protobuf::FieldDescriptor& field,
+                   const EnumValueDescriptor* value_1,
+                   const EnumValueDescriptor* value_2);
+
+  // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
+  // CompareFloat.
+  bool CompareFloat(const google::protobuf::FieldDescriptor& field,
+                    float value_1, float value_2);
+
+  bool CompareInt32(const google::protobuf::FieldDescriptor& field,
+                    int32 value_1, int32 value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareInt64(const google::protobuf::FieldDescriptor& field,
+                    int64 value_1, int64 value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareString(const google::protobuf::FieldDescriptor& field,
+                     const string& value_1, const string& value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt32(const google::protobuf::FieldDescriptor& field,
+                     uint32 value_1, uint32 value_2) {
+    return value_1 == value_2;
+  }
+
+  bool CompareUInt64(const google::protobuf::FieldDescriptor& field,
+                     uint64 value_1, uint64 value_2) {
+    return value_1 == value_2;
+  }
+
+  // This function is used by CompareDouble and CompareFloat to avoid code
+  // duplication. There are no checks done against types of the values passed,
+  // but it's likely to fail if passed non-numeric arguments.
+  template<typename T>
+  bool CompareDoubleOrFloat(const google::protobuf::FieldDescriptor& field,
+                            T value_1, T value_2);
+
+  // Returns FieldComparator::SAME if boolean_result is true and
+  // FieldComparator::DIFFERENT otherwise.
+  ComparisonResult ResultFromBoolean(bool boolean_result) const;
+
+  FloatComparison float_comparison_;
+
+  // If true, floats and doubles that are both NaN are considered to be
+  // equal. Otherwise, two floats or doubles that are NaN are considered to be
+  // different.
+  bool treat_nan_as_equal_;
+
+  // True iff default_tolerance_ has been explicitly set.
+  //
+  // If false, then the default tolerance for flaots and doubles is that which
+  // is used by MathUtil::AlmostEquals().
+  bool has_default_tolerance_;
+
+  // Default float/double tolerance. Only meaningful if
+  // has_default_tolerance_ == true.
+  Tolerance default_tolerance_;
+
+  // Field-specific float/double tolerances, which override any default for
+  // those particular fields.
+  ToleranceMap map_tolerance_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultFieldComparator);
+};
+
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc
new file mode 100644
index 0000000..6fd631d
--- /dev/null
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -0,0 +1,488 @@
+// 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.
+
+// Author: ksroka@google.com (Krzysztof Sroka)
+
+#include <google/protobuf/util/field_comparator.h>
+
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/mathutil.h>
+// This gtest header is put after mathutil.h intentionally. We have to do
+// this because mathutil.h includes mathlimits.h which requires cmath not
+// being included to compile on some versions of gcc:
+//   https://github.com/google/protobuf/blob/818c5eee08840355d70d2f3bdf1a2f17986a5e70/src/google/protobuf/stubs/mathlimits.h#L48
+// and the opensource version gtest.h header includes cmath transitively
+// somehow.
+#include <gtest/gtest.h>
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+
+using protobuf_unittest::TestAllTypes;
+
+class DefaultFieldComparatorTest : public ::testing::Test {
+ protected:
+  void SetUp() {
+    descriptor_ = TestAllTypes::descriptor();
+  }
+
+  const Descriptor* descriptor_;
+  DefaultFieldComparator comparator_;
+  TestAllTypes message_1_;
+  TestAllTypes message_2_;
+};
+
+TEST_F(DefaultFieldComparatorTest, RecursesIntoGroup) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optionalgroup");
+  EXPECT_EQ(FieldComparator::RECURSE,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, RecursesIntoNestedMessage) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_nested_message");
+  EXPECT_EQ(FieldComparator::RECURSE,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, RecursesIntoForeignMessage) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_foreign_message");
+  EXPECT_EQ(FieldComparator::RECURSE,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, Int32Comparison) {
+  const FieldDescriptor* field = descriptor_->FindFieldByName("optional_int32");
+  message_1_.set_optional_int32(1);
+  message_2_.set_optional_int32(1);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_int32(-1);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, Int64Comparison) {
+  const FieldDescriptor* field = descriptor_->FindFieldByName("optional_int64");
+  message_1_.set_optional_int64(1L);
+  message_2_.set_optional_int64(1L);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_int64(-1L);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, UInt32Comparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_uint32");
+  message_1_.set_optional_uint32(1);
+  message_2_.set_optional_uint32(1);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_uint32(2);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, UInt64Comparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_uint64");
+  message_1_.set_optional_uint64(1L);
+  message_2_.set_optional_uint64(1L);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_uint64(2L);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, BooleanComparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_bool");
+  message_1_.set_optional_bool(true);
+  message_2_.set_optional_bool(true);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_bool(false);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, EnumComparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_nested_enum");
+  message_1_.set_optional_nested_enum(TestAllTypes::BAR);
+  message_2_.set_optional_nested_enum(TestAllTypes::BAR);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_nested_enum(TestAllTypes::BAZ);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, StringComparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("optional_string");
+  message_1_.set_optional_string("foo");
+  message_2_.set_optional_string("foo");
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+
+  message_2_.set_optional_string("bar");
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonExact) {
+  const FieldDescriptor* field_float =
+      descriptor_->FindFieldByName("optional_float");
+  const FieldDescriptor* field_double =
+      descriptor_->FindFieldByName("optional_double");
+
+  message_1_.set_optional_float(0.1f);
+  message_2_.set_optional_float(0.1f);
+  message_1_.set_optional_double(0.1);
+  message_2_.set_optional_double(0.1);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  message_2_.set_optional_float(0.2f);
+  message_2_.set_optional_double(0.2);
+
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonApproximate) {
+  const FieldDescriptor* field_float =
+      descriptor_->FindFieldByName("optional_float");
+  const FieldDescriptor* field_double =
+      descriptor_->FindFieldByName("optional_double");
+
+  message_1_.set_optional_float(2.300005f);
+  message_2_.set_optional_float(2.300006f);
+  message_1_.set_optional_double(2.3000000000000003);
+  message_2_.set_optional_double(2.3000000000000007);
+
+  // Approximate comparison depends on MathUtil, so we assert on MathUtil
+  // results first to check if that's where the failure was introduced.
+  ASSERT_NE(message_1_.optional_float(), message_2_.optional_float());
+  ASSERT_NE(message_1_.optional_double(), message_2_.optional_double());
+  ASSERT_TRUE(MathUtil::AlmostEquals(message_1_.optional_float(),
+                                     message_2_.optional_float()));
+  ASSERT_TRUE(MathUtil::AlmostEquals(message_1_.optional_double(),
+                                     message_2_.optional_double()));
+
+  // DefaultFieldComparator's default float comparison mode is EXACT.
+  ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonTreatNaNsAsEqual) {
+  const FieldDescriptor* field_float =
+      descriptor_->FindFieldByName("optional_float");
+  const FieldDescriptor* field_double =
+      descriptor_->FindFieldByName("optional_double");
+
+  message_1_.set_optional_float(MathLimits<float>::kNaN);
+  message_2_.set_optional_float(MathLimits<float>::kNaN);
+  message_1_.set_optional_double(MathLimits<double>::kNaN);
+  message_2_.set_optional_double(MathLimits<double>::kNaN);
+
+  // DefaultFieldComparator's default float comparison mode is EXACT with
+  // treating NaNs as different.
+  ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
+  ASSERT_EQ(false, comparator_.treat_nan_as_equal());
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  comparator_.set_treat_nan_as_equal(true);
+  ASSERT_EQ(true, comparator_.treat_nan_as_equal());
+  comparator_.set_float_comparison(DefaultFieldComparator::EXACT);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest,
+       FloatingPointComparisonWithinFractionOrMargin) {
+  const FieldDescriptor* field_float =
+      descriptor_->FindFieldByName("optional_float");
+  const FieldDescriptor* field_double =
+      descriptor_->FindFieldByName("optional_double");
+
+  message_1_.set_optional_float(100.0f);
+  message_2_.set_optional_float(109.9f);
+  message_1_.set_optional_double(100.0);
+  message_2_.set_optional_double(109.9);
+
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Should fail since the fraction is too low.
+  comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.01, 0.0);
+
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Should fail since the margin is too low.
+  comparator_.SetFractionAndMargin(field_float, 0.0, 9.0);
+  comparator_.SetFractionAndMargin(field_double, 0.0, 9.0);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Should succeed since the fraction is high enough.
+  comparator_.SetFractionAndMargin(field_float, 0.2, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.2, 0.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Should succeed since the margin is high enough.
+  comparator_.SetFractionAndMargin(field_float, 0.0, 10.0);
+  comparator_.SetFractionAndMargin(field_double, 0.0, 10.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Setting values for one of the fields should not affect the other.
+  comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // +inf should be equal even though they are not technically within margin or
+  // fraction.
+  message_1_.set_optional_float(numeric_limits<float>::infinity());
+  message_2_.set_optional_float(numeric_limits<float>::infinity());
+  message_1_.set_optional_double(numeric_limits<double>::infinity());
+  message_2_.set_optional_double(numeric_limits<double>::infinity());
+  comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // -inf should be equal even though they are not technically within margin or
+  // fraction.
+  message_1_.set_optional_float(-numeric_limits<float>::infinity());
+  message_2_.set_optional_float(-numeric_limits<float>::infinity());
+  message_1_.set_optional_double(-numeric_limits<double>::infinity());
+  message_2_.set_optional_double(-numeric_limits<double>::infinity());
+  comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+}
+
+TEST_F(DefaultFieldComparatorTest,
+       FloatingPointComparisonWithinDefaultFractionOrMargin) {
+  const FieldDescriptor* field_float =
+      descriptor_->FindFieldByName("optional_float");
+  const FieldDescriptor* field_double =
+      descriptor_->FindFieldByName("optional_double");
+
+  message_1_.set_optional_float(100.0f);
+  message_2_.set_optional_float(109.9f);
+  message_1_.set_optional_double(100.0);
+  message_2_.set_optional_double(109.9);
+
+  comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Set default fraction and margin.
+  comparator_.SetDefaultFractionAndMargin(0.01, 0.0);
+
+  // Float comparisons should fail since the fraction is too low.
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Set field-specific fraction and margin for one field (field_float) but not
+  // the other (field_double)
+  comparator_.SetFractionAndMargin(field_float, 0.2, 0.0);
+
+  // The field with the override should succeed, since its field-specific
+  // fraction is high enough.
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  // The field with no override should fail, since the default fraction is too
+  // low
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // Set the default fraction and margin high enough so that fields that use
+  // the default should succeed
+  comparator_.SetDefaultFractionAndMargin(0.2, 0.0);
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+
+  // The field with an override should still be OK
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+
+  // Set fraction and margin for the field with an override to be too low
+  comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
+
+  // Now our default is high enough but field_float's override is too low.
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_,
+                                field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_,
+                                field_double, -1, -1, NULL));
+}
+
+// Simple test checking whether we compare values at correct indices.
+TEST_F(DefaultFieldComparatorTest, RepeatedFieldComparison) {
+  const FieldDescriptor* field =
+      descriptor_->FindFieldByName("repeated_string");
+
+  message_1_.add_repeated_string("foo");
+  message_1_.add_repeated_string("bar");
+  message_2_.add_repeated_string("bar");
+  message_2_.add_repeated_string("baz");
+
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, 0, 0, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field, 1, 1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field, 1, 0, NULL));
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace
+}  // namespace google
diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc
new file mode 100644
index 0000000..547c9fb
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -0,0 +1,494 @@
+// 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.
+
+#include <google/protobuf/util/field_mask_util.h>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::FieldMask;
+
+string FieldMaskUtil::ToString(const FieldMask& mask) {
+  return Join(mask.paths(), ",");
+}
+
+void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  vector<string> paths = Split(str, ",");
+  for (int i = 0; i < paths.size(); ++i) {
+    if (paths[i].empty()) continue;
+    out->add_paths(paths[i]);
+  }
+}
+
+bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) {
+  output->clear();
+  bool after_underscore = false;
+  for (int i = 0; i < input.size(); ++i) {
+    if (input[i] >= 'A' && input[i] <= 'Z') {
+      // The field name must not contain uppercase letters.
+      return false;
+    }
+    if (after_underscore) {
+      if (input[i] >= 'a' && input[i] <= 'z') {
+        output->push_back(input[i] + 'A' - 'a');
+        after_underscore = false;
+      } else {
+        // The character after a "_" must be a lowercase letter.
+        return false;
+      }
+    } else if (input[i] == '_') {
+      after_underscore = true;
+    } else {
+      output->push_back(input[i]);
+    }
+  }
+  if (after_underscore) {
+    // Trailing "_".
+    return false;
+  }
+  return true;
+}
+
+bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) {
+  output->clear();
+  for (int i = 0; i < input.size(); ++i) {
+    if (input[i] == '_') {
+      // The field name must not contain "_"s.
+      return false;
+    }
+    if (input[i] >= 'A' && input[i] <= 'Z') {
+      output->push_back('_');
+      output->push_back(input[i] + 'a' - 'A');
+    } else {
+      output->push_back(input[i]);
+    }
+  }
+  return true;
+}
+
+bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) {
+  out->clear();
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const string& path = mask.paths(i);
+    string camelcase_path;
+    if (!SnakeCaseToCamelCase(path, &camelcase_path)) {
+      return false;
+    }
+    if (i > 0) {
+      out->push_back(',');
+    }
+    out->append(camelcase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) {
+  out->Clear();
+  vector<string> paths = Split(str, ",");
+  for (int i = 0; i < paths.size(); ++i) {
+    if (paths[i].empty()) continue;
+    string snakecase_path;
+    if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) {
+      return false;
+    }
+    out->add_paths(snakecase_path);
+  }
+  return true;
+}
+
+bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
+                                        StringPiece path) {
+  vector<string> parts = Split(path, ".");
+  for (int i = 0; i < parts.size(); ++i) {
+    const string& field_name = parts[i];
+    if (descriptor == NULL) {
+      return false;
+    }
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == NULL) {
+      return false;
+    }
+    if (!field->is_repeated() &&
+        field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      descriptor = field->message_type();
+    } else {
+      descriptor = NULL;
+    }
+  }
+  return true;
+}
+
+void FieldMaskUtil::InternalGetFieldMaskForAllFields(
+    const Descriptor* descriptor, FieldMask* out) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    out->add_paths(descriptor->field(i)->name());
+  }
+}
+
+namespace {
+// A FieldMaskTree represents a FieldMask in a tree structure. For example,
+// given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
+//
+//   [root] -+- foo -+- bar
+//           |       |
+//           |       +- baz
+//           |
+//           +- bar --- baz
+//
+// In the tree, each leaf node represents a field path.
+class FieldMaskTree {
+ public:
+  FieldMaskTree();
+  ~FieldMaskTree();
+
+  void MergeFromFieldMask(const FieldMask& mask);
+  void MergeToFieldMask(FieldMask* mask);
+
+  // Add a field path into the tree. In a FieldMask, each field path matches
+  // the specified field and also all its sub-fields. If the field path to
+  // add is a sub-path of an existing field path in the tree (i.e., a leaf
+  // node), it means the tree already matches the given path so nothing will
+  // be added to the tree. If the path matches an existing non-leaf node in the
+  // tree, that non-leaf node will be turned into a leaf node with all its
+  // children removed because the path matches all the node's children.
+  void AddPath(const string& path);
+
+  // Calculate the intersection part of a field path with this tree and add
+  // the intersection field path into out.
+  void IntersectPath(const string& path, FieldMaskTree* out);
+
+  // Merge all fields specified by this tree from one message to another.
+  void MergeMessage(const Message& source,
+                    const FieldMaskUtil::MergeOptions& options,
+                    Message* destination) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return;
+    }
+    MergeMessage(&root_, source, options, destination);
+  }
+
+ private:
+  struct Node {
+    Node() {}
+
+    ~Node() { ClearChildren(); }
+
+    void ClearChildren() {
+      for (map<string, Node*>::iterator it = children.begin();
+           it != children.end(); ++it) {
+        delete it->second;
+      }
+      children.clear();
+    }
+
+    map<string, Node*> children;
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
+  };
+
+  // Merge a sub-tree to mask. This method adds the field paths represented
+  // by all leaf nodes descended from "node" to mask.
+  void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out);
+
+  // Merge all leaf nodes of a sub-tree to another tree.
+  void MergeLeafNodesToTree(const string& prefix, const Node* node,
+                            FieldMaskTree* out);
+
+  // Merge all fields specified by a sub-tree from one message to another.
+  void MergeMessage(const Node* node, const Message& source,
+                    const FieldMaskUtil::MergeOptions& options,
+                    Message* destination);
+
+  Node root_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
+};
+
+FieldMaskTree::FieldMaskTree() {}
+
+FieldMaskTree::~FieldMaskTree() {}
+
+void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    AddPath(mask.paths(i));
+  }
+}
+
+void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
+  MergeToFieldMask("", &root_, mask);
+}
+
+void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node,
+                                     FieldMask* out) {
+  if (node->children.empty()) {
+    if (prefix.empty()) {
+      // This is the root node.
+      return;
+    }
+    out->add_paths(prefix);
+    return;
+  }
+  for (map<string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
+    MergeToFieldMask(current_path, it->second, out);
+  }
+}
+
+void FieldMaskTree::AddPath(const string& path) {
+  vector<string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  bool new_branch = false;
+  Node* node = &root_;
+  for (int i = 0; i < parts.size(); ++i) {
+    if (!new_branch && node != &root_ && node->children.empty()) {
+      // Path matches an existing leaf node. This means the path is already
+      // coverred by this tree (for example, adding "foo.bar.baz" to a tree
+      // which already contains "foo.bar").
+      return;
+    }
+    const string& node_name = parts[i];
+    Node*& child = node->children[node_name];
+    if (child == NULL) {
+      new_branch = true;
+      child = new Node();
+    }
+    node = child;
+  }
+  if (!node->children.empty()) {
+    node->ClearChildren();
+  }
+}
+
+void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) {
+  vector<string> parts = Split(path, ".");
+  if (parts.empty()) {
+    return;
+  }
+  const Node* node = &root_;
+  for (int i = 0; i < parts.size(); ++i) {
+    if (node->children.empty()) {
+      if (node != &root_) {
+        out->AddPath(path);
+      }
+      return;
+    }
+    const string& node_name = parts[i];
+    const Node* result = FindPtrOrNull(node->children, node_name);
+    if (result == NULL) {
+      // No intersection found.
+      return;
+    }
+    node = result;
+  }
+  // Now we found a matching node with the given path. Add all leaf nodes
+  // to out.
+  MergeLeafNodesToTree(path, node, out);
+}
+
+void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node,
+                                         FieldMaskTree* out) {
+  if (node->children.empty()) {
+    out->AddPath(prefix);
+  }
+  for (map<string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
+    MergeLeafNodesToTree(current_path, it->second, out);
+  }
+}
+
+void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
+                                 const FieldMaskUtil::MergeOptions& options,
+                                 Message* destination) {
+  GOOGLE_DCHECK(!node->children.empty());
+  const Reflection* source_reflection = source.GetReflection();
+  const Reflection* destination_reflection = destination->GetReflection();
+  const Descriptor* descriptor = source.GetDescriptor();
+  for (map<string, Node*>::const_iterator it = node->children.begin();
+       it != node->children.end(); ++it) {
+    const string& field_name = it->first;
+    const Node* child = it->second;
+    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
+    if (field == NULL) {
+      GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
+                 << descriptor->full_name();
+      continue;
+    }
+    if (!child->children.empty()) {
+      // Sub-paths are only allowed for singular message fields.
+      if (field->is_repeated() ||
+          field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+        GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
+                   << descriptor->full_name()
+                   << " is not a singular message field and cannot "
+                   << "have sub-fields.";
+        continue;
+      }
+      MergeMessage(child, source_reflection->GetMessage(source, field), options,
+                   destination_reflection->MutableMessage(destination, field));
+      continue;
+    }
+    if (!field->is_repeated()) {
+      switch (field->cpp_type()) {
+#define COPY_VALUE(TYPE, Name)                                            \
+  case FieldDescriptor::CPPTYPE_##TYPE: {                                 \
+    destination_reflection->Set##Name(                                    \
+        destination, field, source_reflection->Get##Name(source, field)); \
+    break;                                                                \
+  }
+        COPY_VALUE(BOOL, Bool)
+        COPY_VALUE(INT32, Int32)
+        COPY_VALUE(INT64, Int64)
+        COPY_VALUE(UINT32, UInt32)
+        COPY_VALUE(UINT64, UInt64)
+        COPY_VALUE(FLOAT, Float)
+        COPY_VALUE(DOUBLE, Double)
+        COPY_VALUE(ENUM, Enum)
+        COPY_VALUE(STRING, String)
+#undef COPY_VALUE
+        case FieldDescriptor::CPPTYPE_MESSAGE: {
+          if (options.replace_message_fields()) {
+            destination_reflection->ClearField(destination, field);
+          }
+          if (source_reflection->HasField(source, field)) {
+            destination_reflection->MutableMessage(destination, field)
+                ->MergeFrom(source_reflection->GetMessage(source, field));
+          }
+          break;
+        }
+      }
+    } else {
+      if (options.replace_repeated_fields()) {
+        destination_reflection->ClearField(destination, field);
+      }
+      switch (field->cpp_type()) {
+#define COPY_REPEATED_VALUE(TYPE, Name)                            \
+  case FieldDescriptor::CPPTYPE_##TYPE: {                          \
+    int size = source_reflection->FieldSize(source, field);        \
+    for (int i = 0; i < size; ++i) {                               \
+      destination_reflection->Add##Name(                           \
+          destination, field,                                      \
+          source_reflection->GetRepeated##Name(source, field, i)); \
+    }                                                              \
+    break;                                                         \
+  }
+        COPY_REPEATED_VALUE(BOOL, Bool)
+        COPY_REPEATED_VALUE(INT32, Int32)
+        COPY_REPEATED_VALUE(INT64, Int64)
+        COPY_REPEATED_VALUE(UINT32, UInt32)
+        COPY_REPEATED_VALUE(UINT64, UInt64)
+        COPY_REPEATED_VALUE(FLOAT, Float)
+        COPY_REPEATED_VALUE(DOUBLE, Double)
+        COPY_REPEATED_VALUE(ENUM, Enum)
+        COPY_REPEATED_VALUE(STRING, String)
+#undef COPY_REPEATED_VALUE
+        case FieldDescriptor::CPPTYPE_MESSAGE: {
+          int size = source_reflection->FieldSize(source, field);
+          for (int i = 0; i < size; ++i) {
+            destination_reflection->AddMessage(destination, field)
+                ->MergeFrom(
+                    source_reflection->GetRepeatedMessage(source, field, i));
+          }
+          break;
+        }
+      }
+    }
+  }
+}
+
+}  // namespace
+
+void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
+                          FieldMask* out) {
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask1);
+  tree.MergeFromFieldMask(mask2);
+  out->Clear();
+  tree.MergeToFieldMask(out);
+}
+
+void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
+                              FieldMask* out) {
+  FieldMaskTree tree, intersection;
+  tree.MergeFromFieldMask(mask1);
+  for (int i = 0; i < mask2.paths_size(); ++i) {
+    tree.IntersectPath(mask2.paths(i), &intersection);
+  }
+  out->Clear();
+  intersection.MergeToFieldMask(out);
+}
+
+bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
+  for (int i = 0; i < mask.paths_size(); ++i) {
+    const string& mask_path = mask.paths(i);
+    if (path == mask_path) {
+      return true;
+    } else if (mask_path.length() < path.length()) {
+      // Also check whether mask.paths(i) is a prefix of path.
+      if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
+          0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
+                                   const MergeOptions& options,
+                                   Message* destination) {
+  GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  tree.MergeMessage(source, options, destination);
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h
new file mode 100644
index 0000000..644161b
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -0,0 +1,183 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
+
+#include <string>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class LIBPROTOBUF_EXPORT FieldMaskUtil {
+  typedef google::protobuf::FieldMask FieldMask;
+
+ public:
+  // Converts FieldMask to/from string, formatted by separating each path
+  // with a comma (e.g., "foo_bar,baz.quz").
+  static string ToString(const FieldMask& mask);
+  static void FromString(StringPiece str, FieldMask* out);
+
+  // Converts FieldMask to/from string, formatted according to proto3 JSON
+  // spec for FieldMask (e.g., "fooBar,baz.quz"). If the field name is not
+  // style conforming (i.e., not snake_case when converted to string, or not
+  // camelCase when converted from string), the conversion will fail.
+  static bool ToJsonString(const FieldMask& mask, string* out);
+  static bool FromJsonString(StringPiece str, FieldMask* out);
+
+  // Checks whether the given path is valid for type T.
+  template <typename T>
+  static bool IsValidPath(StringPiece path) {
+    return InternalIsValidPath(T::descriptor(), path);
+  }
+
+  // Checks whether the given FieldMask is valid for type T.
+  template <typename T>
+  static bool IsValidFieldMask(const FieldMask& mask) {
+    for (int i = 0; i < mask.paths_size(); ++i) {
+      if (!InternalIsValidPath(T::descriptor(), mask.paths(i))) return false;
+    }
+    return true;
+  }
+
+  // Adds a path to FieldMask after checking whether the given path is valid.
+  // This method check-fails if the path is not a valid path for type T.
+  template <typename T>
+  static void AddPathToFieldMask(StringPiece path, FieldMask* mask) {
+    GOOGLE_CHECK(IsValidPath<T>(path));
+    mask->add_paths(path);
+  }
+
+  // Creates a FieldMask with all fields of type T. This FieldMask only
+  // contains fields of T but not any sub-message fields.
+  template <typename T>
+  static void GetFieldMaskForAllFields(FieldMask* out) {
+    InternalGetFieldMaskForAllFields(T::descriptor(), out);
+  }
+
+  // Converts a FieldMask to the canonical form. It will:
+  //   1. Remove paths that are covered by another path. For example,
+  //      "foo.bar" is covered by "foo" and will be removed if "foo"
+  //      is also in the FieldMask.
+  //   2. Sort all paths in alphabetical order.
+  static void ToCanonicalForm(const FieldMask& mask, FieldMask* out);
+
+  // Creates an union of two FieldMasks.
+  static void Union(const FieldMask& mask1, const FieldMask& mask2,
+                    FieldMask* out);
+
+  // Creates an intersection of two FieldMasks.
+  static void Intersect(const FieldMask& mask1, const FieldMask& mask2,
+                        FieldMask* out);
+
+  // Returns true if path is covered by the given FieldMask. Note that path
+  // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc.
+  static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
+
+  class MergeOptions;
+  // Merges fields specified in a FieldMask into another message.
+  static void MergeMessageTo(const Message& source, const FieldMask& mask,
+                             const MergeOptions& options, Message* destination);
+
+ private:
+  friend class SnakeCaseCamelCaseTest;
+  // Converts a field name from snake_case to camelCase:
+  //   1. Every character after "_" will be converted to uppercase.
+  //   2. All "_"s are removed.
+  // The conversion will fail if:
+  //   1. The field name contains uppercase letters.
+  //   2. Any character after a "_" is not a lowercase letter.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // camelCase name will yield the original snake_case name when
+  // converted using CamelCaseToSnakeCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "foo_bar,baz_quz" will be converted to "fooBar,bazQuz"
+  // successfully.
+  static bool SnakeCaseToCamelCase(StringPiece input, string* output);
+  // Converts a field name from camelCase to snake_case:
+  //   1. Every uppercase letter is converted to lowercase with a additional
+  //      preceding "-".
+  // The conversion will fail if:
+  //   1. The field name contains "_"s.
+  // If the conversion succeeds, it's guaranteed that the resulted
+  // snake_case name will yield the original camelCase name when
+  // converted using SnakeCaseToCamelCase().
+  //
+  // Note that the input can contain characters not allowed in C identifiers.
+  // For example, "fooBar,bazQuz" will be converted to "foo_bar,baz_quz"
+  // successfully.
+  static bool CamelCaseToSnakeCase(StringPiece input, string* output);
+
+  static bool InternalIsValidPath(const Descriptor* descriptor,
+                                  StringPiece path);
+
+  static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor,
+                                               FieldMask* out);
+};
+
+class LIBPROTOBUF_EXPORT FieldMaskUtil::MergeOptions {
+ public:
+  MergeOptions()
+      : replace_message_fields_(false), replace_repeated_fields_(false) {}
+  // When merging message fields, the default behavior is to merge the
+  // content of two message fields together. If you instead want to use
+  // the field from the source message to replace the corresponding field
+  // in the destination message, set this flag to true. When this flag is set,
+  // specified submessage fields that are missing in source will be cleared in
+  // destination.
+  void set_replace_message_fields(bool value) {
+    replace_message_fields_ = value;
+  }
+  bool replace_message_fields() const { return replace_message_fields_; }
+  // The default merging behavior will append entries from the source
+  // repeated field to the destination repeated field. If you only want
+  // to keep the entries from the source repeated field, set this flag
+  // to true.
+  void set_replace_repeated_fields(bool value) {
+    replace_repeated_fields_ = value;
+  }
+  bool replace_repeated_fields() const { return replace_repeated_fields_; }
+
+ private:
+  bool replace_message_fields_;
+  bool replace_repeated_fields_;
+};
+
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__
diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc
new file mode 100644
index 0000000..9b7fb62
--- /dev/null
+++ b/src/google/protobuf/util/field_mask_util_test.cc
@@ -0,0 +1,491 @@
+// 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.
+
+#include <google/protobuf/util/field_mask_util.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/test_util.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class SnakeCaseCamelCaseTest : public ::testing::Test {
+ protected:
+  string SnakeCaseToCamelCase(const string& input) {
+    string output;
+    if (FieldMaskUtil::SnakeCaseToCamelCase(input, &output)) {
+      return output;
+    } else {
+      return "#FAIL#";
+    }
+  }
+
+  string CamelCaseToSnakeCase(const string& input) {
+    string output;
+    if (FieldMaskUtil::CamelCaseToSnakeCase(input, &output)) {
+      return output;
+    } else {
+      return "#FAIL#";
+    }
+  }
+};
+
+namespace {
+
+TEST_F(SnakeCaseCamelCaseTest, SnakeToCamel) {
+  EXPECT_EQ("fooBar", SnakeCaseToCamelCase("foo_bar"));
+  EXPECT_EQ("FooBar", SnakeCaseToCamelCase("_foo_bar"));
+  EXPECT_EQ("foo3Bar", SnakeCaseToCamelCase("foo3_bar"));
+  // No uppercase letter is allowed.
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("Foo"));
+  // Any character after a "_" must be a lowercase letter.
+  //   1. "_" cannot be followed by another "_".
+  //   2. "_" cannot be followed by a digit.
+  //   3. "_" cannot appear as the last character.
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo__bar"));
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_3bar"));
+  EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_bar_"));
+}
+
+TEST_F(SnakeCaseCamelCaseTest, CamelToSnake) {
+  EXPECT_EQ("foo_bar", CamelCaseToSnakeCase("fooBar"));
+  EXPECT_EQ("_foo_bar", CamelCaseToSnakeCase("FooBar"));
+  EXPECT_EQ("foo3_bar", CamelCaseToSnakeCase("foo3Bar"));
+  // "_"s are not allowed.
+  EXPECT_EQ("#FAIL#", CamelCaseToSnakeCase("foo_bar"));
+}
+
+TEST_F(SnakeCaseCamelCaseTest, RoundTripTest) {
+  // Enumerates all possible snake_case names and test that converting it to
+  // camelCase and then to snake_case again will yield the original name.
+  string name = "___abc123";
+  std::sort(name.begin(), name.end());
+  do {
+    string camelName = SnakeCaseToCamelCase(name);
+    if (camelName != "#FAIL#") {
+      EXPECT_EQ(name, CamelCaseToSnakeCase(camelName));
+    }
+  } while (std::next_permutation(name.begin(), name.end()));
+
+  // Enumerates all possible camelCase names and test that converting it to
+  // snake_case and then to camelCase again will yield the original name.
+  name = "abcABC123";
+  std::sort(name.begin(), name.end());
+  do {
+    string camelName = CamelCaseToSnakeCase(name);
+    if (camelName != "#FAIL#") {
+      EXPECT_EQ(name, SnakeCaseToCamelCase(camelName));
+    }
+  } while (std::next_permutation(name.begin(), name.end()));
+}
+
+using protobuf_unittest::TestAllTypes;
+using protobuf_unittest::NestedTestAllTypes;
+using google::protobuf::FieldMask;
+
+TEST(FieldMaskUtilTest, StringFormat) {
+  FieldMask mask;
+  EXPECT_EQ("", FieldMaskUtil::ToString(mask));
+  mask.add_paths("foo_bar");
+  EXPECT_EQ("foo_bar", FieldMaskUtil::ToString(mask));
+  mask.add_paths("baz_quz");
+  EXPECT_EQ("foo_bar,baz_quz", FieldMaskUtil::ToString(mask));
+
+  FieldMaskUtil::FromString("", &mask);
+  EXPECT_EQ(0, mask.paths_size());
+  FieldMaskUtil::FromString("fooBar", &mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_EQ("fooBar", mask.paths(0));
+  FieldMaskUtil::FromString("fooBar,bazQuz", &mask);
+  EXPECT_EQ(2, mask.paths_size());
+  EXPECT_EQ("fooBar", mask.paths(0));
+  EXPECT_EQ("bazQuz", mask.paths(1));
+}
+
+TEST(FieldMaskUtilTest, JsonStringFormat) {
+  FieldMask mask;
+  string value;
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("", value);
+  mask.add_paths("foo_bar");
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("fooBar", value);
+  mask.add_paths("bar_quz");
+  EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value));
+  EXPECT_EQ("fooBar,barQuz", value);
+
+  FieldMaskUtil::FromJsonString("", &mask);
+  EXPECT_EQ(0, mask.paths_size());
+  FieldMaskUtil::FromJsonString("fooBar", &mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_EQ("foo_bar", mask.paths(0));
+  FieldMaskUtil::FromJsonString("fooBar,bazQuz", &mask);
+  EXPECT_EQ(2, mask.paths_size());
+  EXPECT_EQ("foo_bar", mask.paths(0));
+  EXPECT_EQ("baz_quz", mask.paths(1));
+}
+
+TEST(FieldMaskUtilTest, TestIsVaildPath) {
+  EXPECT_TRUE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_int32"));
+  EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nonexist"));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nested_message.bb"));
+  EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>(
+      "optional_nested_message.nonexist"));
+  // FieldMask cannot be used to specify sub-fields of a repeated message.
+  EXPECT_FALSE(
+      FieldMaskUtil::IsValidPath<TestAllTypes>("repeated_nested_message.bb"));
+}
+
+TEST(FieldMaskUtilTest, TestIsValidFieldMask) {
+  FieldMask mask;
+  FieldMaskUtil::FromString("optional_int32,optional_nested_message.bb", &mask);
+  EXPECT_TRUE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask));
+
+  FieldMaskUtil::FromString(
+      "optional_int32,optional_nested_message.bb,optional_nonexist", &mask);
+  EXPECT_FALSE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask));
+}
+
+TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) {
+  FieldMask mask;
+  FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>(&mask);
+  EXPECT_EQ(1, mask.paths_size());
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask));
+
+  FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(&mask);
+  EXPECT_EQ(76, mask.paths_size());
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_float", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_double", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bool", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_string", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bytes", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("optional_nested_message", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("optional_foreign_message", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("optional_import_message", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_nested_enum", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_foreign_enum", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_import_enum", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed32", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed64", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_float", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_double", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bool", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_string", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bytes", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("repeated_nested_message", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("repeated_foreign_message", mask));
+  EXPECT_TRUE(
+      FieldMaskUtil::IsPathInFieldMask("repeated_import_message", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_nested_enum", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_foreign_enum", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_import_enum", mask));
+}
+
+TEST(FieldMaskUtilTest, TestToCanonicalForm) {
+  FieldMask in, out;
+  // Paths will be sorted.
+  FieldMaskUtil::FromString("baz.quz,bar,foo", &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("bar,baz.quz,foo", FieldMaskUtil::ToString(out));
+  // Duplicated paths will be removed.
+  FieldMaskUtil::FromString("foo,bar,foo", &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("bar,foo", FieldMaskUtil::ToString(out));
+  // Sub-paths of other paths will be removed.
+  FieldMaskUtil::FromString("foo.b1,bar.b1,foo.b2,bar", &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("bar,foo.b1,foo.b2", FieldMaskUtil::ToString(out));
+
+  // Test more deeply nested cases.
+  FieldMaskUtil::FromString(
+      "foo.bar.baz1,"
+      "foo.bar.baz2.quz,"
+      "foo.bar.baz2",
+      &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out));
+  FieldMaskUtil::FromString(
+      "foo.bar.baz1,"
+      "foo.bar.baz2,"
+      "foo.bar.baz2.quz",
+      &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out));
+  FieldMaskUtil::FromString(
+      "foo.bar.baz1,"
+      "foo.bar.baz2,"
+      "foo.bar.baz2.quz,"
+      "foo.bar",
+      &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("foo.bar", FieldMaskUtil::ToString(out));
+  FieldMaskUtil::FromString(
+      "foo.bar.baz1,"
+      "foo.bar.baz2,"
+      "foo.bar.baz2.quz,"
+      "foo",
+      &in);
+  FieldMaskUtil::ToCanonicalForm(in, &out);
+  EXPECT_EQ("foo", FieldMaskUtil::ToString(out));
+}
+
+TEST(FieldMaskUtilTest, TestUnion) {
+  FieldMask mask1, mask2, out;
+  // Test cases without overlapping.
+  FieldMaskUtil::FromString("foo,baz", &mask1);
+  FieldMaskUtil::FromString("bar,quz", &mask2);
+  FieldMaskUtil::Union(mask1, mask2, &out);
+  EXPECT_EQ("bar,baz,foo,quz", FieldMaskUtil::ToString(out));
+  // Overlap with duplicated paths.
+  FieldMaskUtil::FromString("foo,baz.bb", &mask1);
+  FieldMaskUtil::FromString("baz.bb,quz", &mask2);
+  FieldMaskUtil::Union(mask1, mask2, &out);
+  EXPECT_EQ("baz.bb,foo,quz", FieldMaskUtil::ToString(out));
+  // Overlap with paths covering some other paths.
+  FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1);
+  FieldMaskUtil::FromString("foo.bar,bar", &mask2);
+  FieldMaskUtil::Union(mask1, mask2, &out);
+  EXPECT_EQ("bar,foo.bar,quz", FieldMaskUtil::ToString(out));
+}
+
+TEST(FieldMaskUtilTest, TestIntersect) {
+  FieldMask mask1, mask2, out;
+  // Test cases without overlapping.
+  FieldMaskUtil::FromString("foo,baz", &mask1);
+  FieldMaskUtil::FromString("bar,quz", &mask2);
+  FieldMaskUtil::Intersect(mask1, mask2, &out);
+  EXPECT_EQ("", FieldMaskUtil::ToString(out));
+  // Overlap with duplicated paths.
+  FieldMaskUtil::FromString("foo,baz.bb", &mask1);
+  FieldMaskUtil::FromString("baz.bb,quz", &mask2);
+  FieldMaskUtil::Intersect(mask1, mask2, &out);
+  EXPECT_EQ("baz.bb", FieldMaskUtil::ToString(out));
+  // Overlap with paths covering some other paths.
+  FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1);
+  FieldMaskUtil::FromString("foo.bar,bar", &mask2);
+  FieldMaskUtil::Intersect(mask1, mask2, &out);
+  EXPECT_EQ("foo.bar.baz", FieldMaskUtil::ToString(out));
+}
+
+TEST(FieldMaskUtilTest, TestIspathInFieldMask) {
+  FieldMask mask;
+  FieldMaskUtil::FromString("foo.bar", &mask);
+  EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("", mask));
+  EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar", mask));
+  EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar.baz", mask));
+  EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo.bar0.baz", mask));
+}
+
+TEST(FieldMaskUtilTest, MergeMessage) {
+  TestAllTypes src, dst;
+  TestUtil::SetAllFields(&src);
+  FieldMaskUtil::MergeOptions options;
+
+#define TEST_MERGE_ONE_PRIMITIVE_FIELD(field_name)           \
+  {                                                          \
+    TestAllTypes tmp;                                        \
+    tmp.set_##field_name(src.field_name());                  \
+    FieldMask mask;                                          \
+    mask.add_paths(#field_name);                             \
+    dst.Clear();                                             \
+    FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
+    EXPECT_EQ(tmp.DebugString(), dst.DebugString());         \
+  }
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int32)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int64)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint32)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint64)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint32)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint64)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed32)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed64)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed32)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed64)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_float)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_double)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bool)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_string)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bytes)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_nested_enum)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_foreign_enum)
+  TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_import_enum)
+#undef TEST_MERGE_ONE_PRIMITIVE_FIELD
+
+#define TEST_MERGE_ONE_FIELD(field_name)                     \
+  {                                                          \
+    TestAllTypes tmp;                                        \
+    *tmp.mutable_##field_name() = src.field_name();          \
+    FieldMask mask;                                          \
+    mask.add_paths(#field_name);                             \
+    dst.Clear();                                             \
+    FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
+    EXPECT_EQ(tmp.DebugString(), dst.DebugString());         \
+  }
+  TEST_MERGE_ONE_FIELD(optional_nested_message)
+  TEST_MERGE_ONE_FIELD(optional_foreign_message)
+  TEST_MERGE_ONE_FIELD(optional_import_message)
+
+  TEST_MERGE_ONE_FIELD(repeated_int32)
+  TEST_MERGE_ONE_FIELD(repeated_int64)
+  TEST_MERGE_ONE_FIELD(repeated_uint32)
+  TEST_MERGE_ONE_FIELD(repeated_uint64)
+  TEST_MERGE_ONE_FIELD(repeated_sint32)
+  TEST_MERGE_ONE_FIELD(repeated_sint64)
+  TEST_MERGE_ONE_FIELD(repeated_fixed32)
+  TEST_MERGE_ONE_FIELD(repeated_fixed64)
+  TEST_MERGE_ONE_FIELD(repeated_sfixed32)
+  TEST_MERGE_ONE_FIELD(repeated_sfixed64)
+  TEST_MERGE_ONE_FIELD(repeated_float)
+  TEST_MERGE_ONE_FIELD(repeated_double)
+  TEST_MERGE_ONE_FIELD(repeated_bool)
+  TEST_MERGE_ONE_FIELD(repeated_string)
+  TEST_MERGE_ONE_FIELD(repeated_bytes)
+  TEST_MERGE_ONE_FIELD(repeated_nested_message)
+  TEST_MERGE_ONE_FIELD(repeated_foreign_message)
+  TEST_MERGE_ONE_FIELD(repeated_import_message)
+  TEST_MERGE_ONE_FIELD(repeated_nested_enum)
+  TEST_MERGE_ONE_FIELD(repeated_foreign_enum)
+  TEST_MERGE_ONE_FIELD(repeated_import_enum)
+#undef TEST_MERGE_ONE_FIELD
+
+  // Test merge nested fields.
+  NestedTestAllTypes nested_src, nested_dst;
+  nested_src.mutable_child()->mutable_payload()->set_optional_int32(1234);
+  nested_src.mutable_child()
+      ->mutable_child()
+      ->mutable_payload()
+      ->set_optional_int32(5678);
+  FieldMask mask;
+  FieldMaskUtil::FromString("child.payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(1234, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(0, nested_dst.child().child().payload().optional_int32());
+
+  FieldMaskUtil::FromString("child.child.payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(1234, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32());
+
+  nested_dst.Clear();
+  FieldMaskUtil::FromString("child.child.payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(0, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32());
+
+  nested_dst.Clear();
+  FieldMaskUtil::FromString("child", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(1234, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32());
+
+  // Test MergeOptions.
+
+  nested_dst.Clear();
+  nested_dst.mutable_child()->mutable_payload()->set_optional_int64(4321);
+  // Message fields will be merged by default.
+  FieldMaskUtil::FromString("child.payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(1234, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(4321, nested_dst.child().payload().optional_int64());
+  // Change the behavior to replace message fields.
+  options.set_replace_message_fields(true);
+  FieldMaskUtil::FromString("child.payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_EQ(1234, nested_dst.child().payload().optional_int32());
+  EXPECT_EQ(0, nested_dst.child().payload().optional_int64());
+
+  // By default, fields missing in source are not cleared in destination.
+  options.set_replace_message_fields(false);
+  nested_dst.mutable_payload();
+  EXPECT_TRUE(nested_dst.has_payload());
+  FieldMaskUtil::FromString("payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_TRUE(nested_dst.has_payload());
+  // But they are cleared when replacing message fields.
+  options.set_replace_message_fields(true);
+  nested_dst.Clear();
+  nested_dst.mutable_payload();
+  FieldMaskUtil::FromString("payload", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  EXPECT_FALSE(nested_dst.has_payload());
+
+  nested_src.mutable_payload()->add_repeated_int32(1234);
+  nested_dst.mutable_payload()->add_repeated_int32(5678);
+  // Repeated fields will be appended by default.
+  FieldMaskUtil::FromString("payload.repeated_int32", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  ASSERT_EQ(2, nested_dst.payload().repeated_int32_size());
+  EXPECT_EQ(5678, nested_dst.payload().repeated_int32(0));
+  EXPECT_EQ(1234, nested_dst.payload().repeated_int32(1));
+  // Change the behavior to replace repeated fields.
+  options.set_replace_repeated_fields(true);
+  FieldMaskUtil::FromString("payload.repeated_int32", &mask);
+  FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst);
+  ASSERT_EQ(1, nested_dst.payload().repeated_int32_size());
+  EXPECT_EQ(1234, nested_dst.payload().repeated_int32(0));
+}
+
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/constants.h b/src/google/protobuf/util/internal/constants.h
new file mode 100644
index 0000000..e556888
--- /dev/null
+++ b/src/google/protobuf/util/internal/constants.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_CONSTANTS_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_CONSTANTS_H__
+
+#include <google/protobuf/stubs/common.h>
+
+// This file contains constants used by //net/proto2/util/converter.
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+// Prefix for type URLs.
+const char kTypeServiceBaseUrl[] = "type.googleapis.com";
+
+// Format string for RFC3339 timestamp formatting.
+const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S";
+
+// Same as above, but the year value is not zero-padded i.e. this accepts
+// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z".
+const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S";
+
+// Minimun seconds allowed in a google.protobuf.Timestamp value.
+const int64 kTimestampMinSeconds = -62135596800;
+
+// Maximum seconds allowed in a google.protobuf.Timestamp value.
+const int64 kTimestampMaxSeconds = 253402300799;
+
+// Minimum seconds allowed in a google.protobuf.Duration value.
+const int64 kDurationMinSeconds = -315576000000;
+
+// Maximum seconds allowed in a google.protobuf.Duration value.
+const int64 kDurationMaxSeconds = 315576000000;
+
+// Nano seconds in a second.
+const int32 kNanosPerSecond = 1000000000;
+
+// Type url representing NULL values in google.protobuf.Struct type.
+const char kStructNullValueTypeUrl[] =
+    "type.googleapis.com/google.protobuf.NullValue";
+
+// Type string for google.protobuf.Struct
+const char kStructType[] = "google.protobuf.Struct";
+
+// Type string for struct.proto's google.protobuf.Value value type.
+const char kStructValueType[] = "google.protobuf.Value";
+
+// Type string for struct.proto's google.protobuf.ListValue value type.
+const char kStructListValueType[] = "google.protobuf.ListValue";
+
+// Type string for google.protobuf.Timestamp
+const char kTimestampType[] = "google.protobuf.Timestamp";
+
+// Type string for google.protobuf.Duration
+const char kDurationType[] = "google.protobuf.Duration";
+
+// Type URL for struct value type google.protobuf.Value
+const char kStructValueTypeUrl[] = "type.googleapis.com/google.protobuf.Value";
+
+// Type URL for struct value type google.protobuf.Value
+const char kStructTypeUrl[] = "type.googleapis.com/google.protobuf.Struct";
+
+// Type string for google.protobuf.Any
+const char kAnyType[] = "google.protobuf.Any";
+
+// The type URL of google.protobuf.FieldMask;
+const char kFieldMaskTypeUrl[] =
+    "type.googleapis.com/google.protobuf.FieldMask";
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_CONSTANTS_H__
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
new file mode 100644
index 0000000..72c0aca
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -0,0 +1,360 @@
+// 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.
+
+#include <google/protobuf/util/internal/datapiece.h>
+
+#include <google/protobuf/struct.pb.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/mathutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::EnumDescriptor;
+using google::protobuf::EnumValueDescriptor;
+;
+;
+;
+using util::error::Code;
+using util::Status;
+using util::StatusOr;
+
+namespace {
+
+inline Status InvalidArgument(StringPiece value_str) {
+  return Status(util::error::INVALID_ARGUMENT, value_str);
+}
+
+template <typename To, typename From>
+StatusOr<To> ValidateNumberConversion(To after, From before) {
+  if (after == before &&
+      MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) {
+    return after;
+  } else {
+    return InvalidArgument(::google::protobuf::internal::is_integral<From>::value
+                               ? ValueAsString(before)
+                               : ::google::protobuf::internal::is_same<From, double>::value
+                                     ? DoubleAsString(before)
+                                     : FloatAsString(before));
+  }
+}
+
+// For general conversion between
+//     int32, int64, uint32, uint64, double and float
+// except conversion between double and float.
+template <typename To, typename From>
+StatusOr<To> NumberConvertAndCheck(From before) {
+  if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion to integer types (int32, int64, uint32, uint64) from floating
+// point types (double, float) only.
+template <typename To, typename From>
+StatusOr<To> FloatingPointToIntConvertAndCheck(From before) {
+  if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion between double and float only.
+template <typename To, typename From>
+StatusOr<To> FloatingPointConvertAndCheck(From before) {
+  if (MathLimits<From>::IsNaN(before)) {
+    return std::numeric_limits<To>::quiet_NaN();
+  }
+
+  To after = static_cast<To>(before);
+  if (MathUtil::AlmostEquals<To>(after, before)) {
+    return after;
+  } else {
+    return InvalidArgument(::google::protobuf::internal::is_same<From, double>::value
+                               ? DoubleAsString(before)
+                               : FloatAsString(before));
+  }
+}
+
+}  // namespace
+
+StatusOr<int32> DataPiece::ToInt32() const {
+  if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int32, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int32, float>(float_);
+
+  return GenericConvert<int32>();
+}
+
+StatusOr<uint32> DataPiece::ToUint32() const {
+  if (type_ == TYPE_STRING) return StringToNumber<uint32>(safe_strtou32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint32, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint32, float>(float_);
+
+  return GenericConvert<uint32>();
+}
+
+StatusOr<int64> DataPiece::ToInt64() const {
+  if (type_ == TYPE_STRING) return StringToNumber<int64>(safe_strto64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int64, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int64, float>(float_);
+
+  return GenericConvert<int64>();
+}
+
+StatusOr<uint64> DataPiece::ToUint64() const {
+  if (type_ == TYPE_STRING) return StringToNumber<uint64>(safe_strtou64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint64, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint64, float>(float_);
+
+  return GenericConvert<uint64>();
+}
+
+StatusOr<double> DataPiece::ToDouble() const {
+  if (type_ == TYPE_FLOAT) {
+    return FloatingPointConvertAndCheck<double, float>(float_);
+  }
+  if (type_ == TYPE_STRING) {
+    if (str_ == "Infinity") return std::numeric_limits<double>::infinity();
+    if (str_ == "-Infinity") return -std::numeric_limits<double>::infinity();
+    if (str_ == "NaN") return std::numeric_limits<double>::quiet_NaN();
+    return StringToNumber<double>(safe_strtod);
+  }
+  return GenericConvert<double>();
+}
+
+StatusOr<float> DataPiece::ToFloat() const {
+  if (type_ == TYPE_DOUBLE) {
+    return FloatingPointConvertAndCheck<float, double>(double_);
+  }
+  if (type_ == TYPE_STRING) {
+    if (str_ == "Infinity") return std::numeric_limits<float>::infinity();
+    if (str_ == "-Infinity") return -std::numeric_limits<float>::infinity();
+    if (str_ == "NaN") return std::numeric_limits<float>::quiet_NaN();
+    // SafeStrToFloat() is used instead of safe_strtof() because the later
+    // does not fail on inputs like SimpleDtoa(DBL_MAX).
+    return StringToNumber<float>(SafeStrToFloat);
+  }
+  return GenericConvert<float>();
+}
+
+StatusOr<bool> DataPiece::ToBool() const {
+  switch (type_) {
+    case TYPE_BOOL:
+      return bool_;
+    case TYPE_STRING:
+      return StringToNumber<bool>(safe_strtob);
+    default:
+      return InvalidArgument(
+          ValueAsStringOrDefault("Wrong type. Cannot convert to Bool."));
+  }
+}
+
+StatusOr<string> DataPiece::ToString() const {
+  switch (type_) {
+    case TYPE_STRING:
+      return str_.ToString();
+    case TYPE_BYTES: {
+      string base64;
+      Base64Escape(str_, &base64);
+      return base64;
+    }
+    default:
+      return InvalidArgument(
+          ValueAsStringOrDefault("Cannot convert to string."));
+  }
+}
+
+string DataPiece::ValueAsStringOrDefault(StringPiece default_string) const {
+  switch (type_) {
+    case TYPE_INT32:
+      return SimpleItoa(i32_);
+    case TYPE_INT64:
+      return SimpleItoa(i64_);
+    case TYPE_UINT32:
+      return SimpleItoa(u32_);
+    case TYPE_UINT64:
+      return SimpleItoa(u64_);
+    case TYPE_DOUBLE:
+      return DoubleAsString(double_);
+    case TYPE_FLOAT:
+      return FloatAsString(float_);
+    case TYPE_BOOL:
+      return SimpleBtoa(bool_);
+    case TYPE_STRING:
+      return StrCat("\"", str_.ToString(), "\"");
+    case TYPE_BYTES: {
+      string base64;
+      WebSafeBase64Escape(str_, &base64);
+      return StrCat("\"", base64, "\"");
+    }
+    case TYPE_NULL:
+      return "null";
+    default:
+      return default_string.ToString();
+  }
+}
+
+StatusOr<string> DataPiece::ToBytes() const {
+  if (type_ == TYPE_BYTES) return str_.ToString();
+  if (type_ == TYPE_STRING) {
+    string decoded;
+    if (!DecodeBase64(str_, &decoded)) {
+      return InvalidArgument(ValueAsStringOrDefault("Invalid data in input."));
+    }
+    return decoded;
+  } else {
+    return InvalidArgument(ValueAsStringOrDefault(
+        "Wrong type. Only String or Bytes can be converted to Bytes."));
+  }
+}
+
+StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type) const {
+  if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE;
+
+  if (type_ == TYPE_STRING) {
+    // First try the given value as a name.
+    string enum_name = str_.ToString();
+    const google::protobuf::EnumValue* value =
+        FindEnumValueByNameOrNull(enum_type, enum_name);
+    if (value != NULL) return value->number();
+    // Next try a normalized name.
+    for (string::iterator it = enum_name.begin(); it != enum_name.end(); ++it) {
+      *it = *it == '-' ? '_' : ascii_toupper(*it);
+    }
+    value = FindEnumValueByNameOrNull(enum_type, enum_name);
+    if (value != NULL) return value->number();
+  } else {
+    StatusOr<int32> value = ToInt32();
+    if (value.ok()) {
+      if (const google::protobuf::EnumValue* enum_value =
+              FindEnumValueByNumberOrNull(enum_type, value.ValueOrDie())) {
+        return enum_value->number();
+      }
+    }
+  }
+  return InvalidArgument(
+      ValueAsStringOrDefault("Cannot find enum with given value."));
+}
+
+template <typename To>
+StatusOr<To> DataPiece::GenericConvert() const {
+  switch (type_) {
+    case TYPE_INT32:
+      return NumberConvertAndCheck<To, int32>(i32_);
+    case TYPE_INT64:
+      return NumberConvertAndCheck<To, int64>(i64_);
+    case TYPE_UINT32:
+      return NumberConvertAndCheck<To, uint32>(u32_);
+    case TYPE_UINT64:
+      return NumberConvertAndCheck<To, uint64>(u64_);
+    case TYPE_DOUBLE:
+      return NumberConvertAndCheck<To, double>(double_);
+    case TYPE_FLOAT:
+      return NumberConvertAndCheck<To, float>(float_);
+    default:  // TYPE_ENUM, TYPE_STRING, TYPE_CORD, TYPE_BOOL
+      return InvalidArgument(ValueAsStringOrDefault(
+          "Wrong type. Bool, Enum, String and Cord not supported in "
+          "GenericConvert."));
+  }
+}
+
+template <typename To>
+StatusOr<To> DataPiece::StringToNumber(bool (*func)(StringPiece, To*)) const {
+  if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) {
+    return InvalidArgument(StrCat("\"", str_, "\""));
+  }
+  To result;
+  if (func(str_, &result)) return result;
+  return InvalidArgument(StrCat("\"", str_.ToString(), "\""));
+}
+
+bool DataPiece::DecodeBase64(StringPiece src, string* dest) const {
+  // Try web-safe decode first, if it fails, try the non-web-safe decode.
+  if (WebSafeBase64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      // In strict mode, check if the escaped version gives us the same value as
+      // unescaped.
+      string encoded;
+      // WebSafeBase64Escape does no padding by default.
+      WebSafeBase64Escape(*dest, &encoded);
+      // Remove trailing padding '=' characters before comparison.
+      StringPiece src_no_padding(src, 0, src.ends_with("=")
+                                             ? src.find_last_not_of('=') + 1
+                                             : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  if (Base64Unescape(src, dest)) {
+    if (use_strict_base64_decoding_) {
+      string encoded;
+      Base64Escape(
+          reinterpret_cast<const unsigned char*>(dest->data()), dest->length(),
+          &encoded, false);
+      StringPiece src_no_padding(src, 0, src.ends_with("=")
+                                             ? src.find_last_not_of('=') + 1
+                                             : src.length());
+      return encoded == src_no_padding;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
new file mode 100644
index 0000000..8b2e35d
--- /dev/null
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -0,0 +1,200 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_DATAPIECE_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_DATAPIECE_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+class Enum;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Container for a single piece of data together with its data type.
+//
+// For primitive types (int32, int64, uint32, uint64, double, float, bool),
+// the data is stored by value.
+//
+// For string, a StringPiece is stored. For Cord, a pointer to Cord is stored.
+// Just like StringPiece, the DataPiece class does not own the storage for
+// the actual string or Cord, so it is the user's responsiblity to guarantee
+// that the underlying storage is still valid when the DataPiece is accessed.
+class LIBPROTOBUF_EXPORT DataPiece {
+ public:
+  // Identifies data type of the value.
+  // These are the types supported by DataPiece.
+  enum Type {
+    TYPE_INT32 = 1,
+    TYPE_INT64 = 2,
+    TYPE_UINT32 = 3,
+    TYPE_UINT64 = 4,
+    TYPE_DOUBLE = 5,
+    TYPE_FLOAT = 6,
+    TYPE_BOOL = 7,
+    TYPE_ENUM = 8,
+    TYPE_STRING = 9,
+    TYPE_BYTES = 10,
+    TYPE_NULL = 11,  // explicit NULL type
+  };
+
+  // Constructors and Destructor
+  explicit DataPiece(const int32 value) : type_(TYPE_INT32), i32_(value) {}
+  explicit DataPiece(const int64 value) : type_(TYPE_INT64), i64_(value) {}
+  explicit DataPiece(const uint32 value) : type_(TYPE_UINT32), u32_(value) {}
+  explicit DataPiece(const uint64 value) : type_(TYPE_UINT64), u64_(value) {}
+  explicit DataPiece(const double value) : type_(TYPE_DOUBLE), double_(value) {}
+  explicit DataPiece(const float value) : type_(TYPE_FLOAT), float_(value) {}
+  explicit DataPiece(const bool value) : type_(TYPE_BOOL), bool_(value) {}
+  DataPiece(StringPiece value, bool use_strict_base64_decoding)
+      : type_(TYPE_STRING),
+        str_(StringPiecePod::CreateFromStringPiece(value)),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+  // Constructor for bytes. The second parameter is not used.
+  DataPiece(StringPiece value, bool dummy, bool use_strict_base64_decoding)
+      : type_(TYPE_BYTES),
+        str_(StringPiecePod::CreateFromStringPiece(value)),
+        use_strict_base64_decoding_(use_strict_base64_decoding) {}
+  DataPiece(const DataPiece& r) : type_(r.type_), str_(r.str_) {}
+  DataPiece& operator=(const DataPiece& x) {
+    type_ = x.type_;
+    str_ = x.str_;
+    return *this;
+  }
+
+  static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); }
+
+  virtual ~DataPiece() {
+  }
+
+  // Accessors
+  Type type() const { return type_; }
+
+  StringPiece str() const {
+    GOOGLE_LOG_IF(DFATAL, type_ != TYPE_STRING) << "Not a string type.";
+    return str_;
+  }
+
+
+  // Parses, casts or converts the value stored in the DataPiece into an int32.
+  util::StatusOr<int32> ToInt32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint32.
+  util::StatusOr<uint32> ToUint32() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into an int64.
+  util::StatusOr<int64> ToInt64() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a uint64.
+  util::StatusOr<uint64> ToUint64() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a double.
+  util::StatusOr<double> ToDouble() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a float.
+  util::StatusOr<float> ToFloat() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a bool.
+  util::StatusOr<bool> ToBool() const;
+
+  // Parses, casts or converts the value stored in the DataPiece into a string.
+  util::StatusOr<string> ToString() const;
+
+  // Tries to convert the value contained in this datapiece to string. If the
+  // conversion fails, it returns the default_string.
+  string ValueAsStringOrDefault(StringPiece default_string) const;
+
+  util::StatusOr<string> ToBytes() const;
+
+  // Converts a value into protocol buffer enum number. If the value is a
+  // string, first attempts conversion by name, trying names as follows:
+  //   1) the directly provided string value.
+  //   2) the value upper-cased and replacing '-' by '_'
+  // If the value is not a string, attempts to convert to a 32-bit integer.
+  // If none of these succeeds, returns a conversion error status.
+  util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type) const;
+
+ private:
+  // Disallow implicit constructor.
+  DataPiece();
+
+  // Helper to create NULL or ENUM types.
+  DataPiece(Type type, int32 val) : type_(type), i32_(val) {}
+
+  // For numeric conversion between
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> GenericConvert() const;
+
+  // For conversion from string to
+  //     int32, int64, uint32, uint64, double, float and bool
+  template <typename To>
+  util::StatusOr<To> StringToNumber(bool (*func)(StringPiece, To*)) const;
+
+  // Decodes a base64 string. Returns true on success.
+  bool DecodeBase64(StringPiece src, string* dest) const;
+
+  // Data type for this piece of data.
+  Type type_;
+
+  typedef ::google::protobuf::internal::StringPiecePod StringPiecePod;
+
+  // Stored piece of data.
+  union {
+    int32 i32_;
+    int64 i64_;
+    uint32 u32_;
+    uint64 u64_;
+    double double_;
+    float float_;
+    bool bool_;
+    StringPiecePod str_;
+  };
+
+  // Uses a stricter version of base64 decoding for byte fields.
+  bool use_strict_base64_decoding_;
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_DATAPIECE_H__
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc
new file mode 100644
index 0000000..21d7a2e
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -0,0 +1,591 @@
+// 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.
+
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/map_util.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+using util::Status;
+using util::StatusOr;
+namespace converter {
+
+namespace {
+// Helper function to convert string value to given data type by calling the
+// passed converter function on the DataPiece created from "value" argument.
+// If value is empty or if conversion fails, the default_value is returned.
+template <typename T>
+T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const,
+            T default_value) {
+  if (value.empty()) return default_value;
+  StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
+  return result.ok() ? result.ValueOrDie() : default_value;
+}
+}  // namespace
+
+DefaultValueObjectWriter::DefaultValueObjectWriter(
+    TypeResolver* type_resolver, const google::protobuf::Type& type,
+    ObjectWriter* ow)
+    : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      type_(type),
+      current_(NULL),
+      root_(NULL),
+      field_scrub_callback_(NULL),
+      ow_(ow) {}
+
+DefaultValueObjectWriter::~DefaultValueObjectWriter() {
+  for (int i = 0; i < string_values_.size(); ++i) {
+    delete string_values_[i];
+  }
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name,
+                                                               bool value) {
+  if (current_ == NULL) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
+    StringPiece name, int32 value) {
+  if (current_ == NULL) {
+    ow_->RenderInt32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
+    StringPiece name, uint32 value) {
+  if (current_ == NULL) {
+    ow_->RenderUint32(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
+    StringPiece name, int64 value) {
+  if (current_ == NULL) {
+    ow_->RenderInt64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
+    StringPiece name, uint64 value) {
+  if (current_ == NULL) {
+    ow_->RenderUint64(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
+    StringPiece name, double value) {
+  if (current_ == NULL) {
+    ow_->RenderDouble(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
+    StringPiece name, float value) {
+  if (current_ == NULL) {
+    ow_->RenderBool(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
+    StringPiece name, StringPiece value) {
+  if (current_ == NULL) {
+    ow_->RenderString(name, value);
+  } else {
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.push_back(new string(value.ToString()));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
+    StringPiece name, StringPiece value) {
+  if (current_ == NULL) {
+    ow_->RenderBytes(name, value);
+  } else {
+    RenderDataPiece(name, DataPiece(value, false, true));
+  }
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
+    StringPiece name) {
+  if (current_ == NULL) {
+    ow_->RenderNull(name);
+  } else {
+    RenderDataPiece(name, DataPiece::NullData());
+  }
+  return this;
+}
+
+void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
+    FieldScrubCallBackPtr field_scrub_callback) {
+  field_scrub_callback_.reset(field_scrub_callback.release());
+}
+
+DefaultValueObjectWriter::Node::Node(const string& name,
+                                     const google::protobuf::Type* type,
+                                     NodeKind kind, const DataPiece& data,
+                                     bool is_placeholder,
+                                     const vector<string>& path,
+                                     FieldScrubCallBack* field_scrub_callback)
+    : name_(name),
+      type_(type),
+      kind_(kind),
+      is_any_(false),
+      data_(data),
+      is_placeholder_(is_placeholder),
+      path_(path),
+      field_scrub_callback_(field_scrub_callback) {}
+
+DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
+    StringPiece name) {
+  if (name.empty() || kind_ != OBJECT) {
+    return NULL;
+  }
+  for (int i = 0; i < children_.size(); ++i) {
+    Node* child = children_[i];
+    if (child->name() == name) {
+      return child;
+    }
+  }
+  return NULL;
+}
+
+void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
+  if (kind_ == PRIMITIVE) {
+    ObjectWriter::RenderDataPieceTo(data_, name_, ow);
+    return;
+  }
+
+  // Render maps. Empty maps are rendered as "{}".
+  if (kind_ == MAP) {
+    ow->StartObject(name_);
+    WriteChildren(ow);
+    ow->EndObject();
+    return;
+  }
+
+  // Write out lists. If we didn't have any list in response, write out empty
+  // list.
+  if (kind_ == LIST) {
+    ow->StartList(name_);
+    WriteChildren(ow);
+    ow->EndList();
+    return;
+  }
+
+  // If is_placeholder_ = true, we didn't see this node in the response, so
+  // skip output.
+  if (is_placeholder_) return;
+
+  ow->StartObject(name_);
+  WriteChildren(ow);
+  ow->EndObject();
+}
+
+void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
+  for (int i = 0; i < children_.size(); ++i) {
+    Node* child = children_[i];
+    child->WriteTo(ow);
+  }
+}
+
+const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
+    const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
+  // If this field is a map, we should use the type of its "Value" as
+  // the type of the child node.
+  for (int i = 0; i < found_type.fields_size(); ++i) {
+    const google::protobuf::Field& sub_field = found_type.fields(i);
+    if (sub_field.number() != 2) {
+      continue;
+    }
+    if (sub_field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE) {
+      // This map's value type is not a message type. We don't need to
+      // get the field_type in this case.
+      break;
+    }
+    util::StatusOr<const google::protobuf::Type*> sub_type =
+        typeinfo->ResolveTypeUrl(sub_field.type_url());
+    if (!sub_type.ok()) {
+      GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
+    } else {
+      return sub_type.ValueOrDie();
+    }
+    break;
+  }
+  return NULL;
+}
+
+void DefaultValueObjectWriter::Node::PopulateChildren(
+    const TypeInfo* typeinfo) {
+  // Ignores well known types that don't require automatically populating their
+  // primitive children. For type "Any", we only populate its children when the
+  // "@type" field is set.
+  // TODO(tsun): remove "kStructValueType" from the list. It's being checked
+  //     now because of a bug in the tool-chain that causes the "oneof_index"
+  //     of kStructValueType to not be set correctly.
+  if (type_ == NULL || type_->name() == kAnyType ||
+      type_->name() == kStructType || type_->name() == kTimestampType ||
+      type_->name() == kDurationType || type_->name() == kStructValueType) {
+    return;
+  }
+  std::vector<Node*> new_children;
+  hash_map<string, int> orig_children_map;
+
+  // Creates a map of child nodes to speed up lookup.
+  for (int i = 0; i < children_.size(); ++i) {
+    InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
+  }
+
+  for (int i = 0; i < type_->fields_size(); ++i) {
+    const google::protobuf::Field& field = type_->fields(i);
+
+    // This code is checking if the field to be added to the tree should be
+    // scrubbed or not by calling the field_scrub_callback_ callback function.
+    vector<string> path;
+    if (!path_.empty()) {
+      path.insert(path.begin(), path_.begin(), path_.end());
+    }
+    path.push_back(field.name());
+    if (field_scrub_callback_ != NULL &&
+        field_scrub_callback_->Run(path, &field)) {
+      continue;
+    }
+
+    hash_map<string, int>::iterator found =
+        orig_children_map.find(field.name());
+    // If the child field has already been set, we just add it to the new list
+    // of children.
+    if (found != orig_children_map.end()) {
+      new_children.push_back(children_[found->second]);
+      children_[found->second] = NULL;
+      continue;
+    }
+
+    const google::protobuf::Type* field_type = NULL;
+    bool is_map = false;
+    NodeKind kind = PRIMITIVE;
+
+    if (field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+      kind = OBJECT;
+      util::StatusOr<const google::protobuf::Type*> found_result =
+          typeinfo->ResolveTypeUrl(field.type_url());
+      if (!found_result.ok()) {
+        // "field" is of an unknown type.
+        GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
+      } else {
+        const google::protobuf::Type* found_type = found_result.ValueOrDie();
+        is_map = IsMap(field, *found_type);
+
+        if (!is_map) {
+          field_type = found_type;
+        } else {
+          // If this field is a map, we should use the type of its "Value" as
+          // the type of the child node.
+          field_type = GetMapValueType(*found_type, typeinfo);
+          kind = MAP;
+        }
+      }
+    }
+
+    if (!is_map &&
+        field.cardinality() ==
+            google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
+      kind = LIST;
+    }
+
+    // If oneof_index() != 0, the child field is part of a "oneof", which means
+    // the child field is optional and we shouldn't populate its default value.
+    if (field.oneof_index() != 0) continue;
+
+    // If the child field is of primitive type, sets its data to the default
+    // value of its type.
+    google::protobuf::scoped_ptr<Node> child(new Node(
+        field.json_name(), field_type, kind,
+        kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo)
+                          : DataPiece::NullData(),
+        true, path, field_scrub_callback_));
+    new_children.push_back(child.release());
+  }
+  // Adds all leftover nodes in children_ to the beginning of new_child.
+  for (int i = 0; i < children_.size(); ++i) {
+    if (children_[i] == NULL) {
+      continue;
+    }
+    new_children.insert(new_children.begin(), children_[i]);
+    children_[i] = NULL;
+  }
+  children_.swap(new_children);
+}
+
+void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
+  // If this is an "Any" node with "@type" already given and no other children
+  // have been added, populates its children.
+  if (node != NULL && node->is_any() && node->type() != NULL &&
+      node->type()->name() != kAnyType && node->number_of_children() == 1) {
+    node->PopulateChildren(typeinfo_);
+  }
+}
+
+DataPiece DefaultValueObjectWriter::FindEnumDefault(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+  if (!field.default_value().empty())
+    return DataPiece(field.default_value(), true);
+
+  const google::protobuf::Enum* enum_type =
+      typeinfo->GetEnumByTypeUrl(field.type_url());
+  if (!enum_type) {
+    GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
+                 << "'";
+    return DataPiece::NullData();
+  }
+  // We treat the first value as the default if none is specified.
+  return enum_type->enumvalue_size() > 0
+             ? DataPiece(enum_type->enumvalue(0).name(), true)
+             : DataPiece::NullData();
+}
+
+DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+  switch (field.kind()) {
+    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+      return DataPiece(ConvertTo<double>(
+          field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_FLOAT: {
+      return DataPiece(ConvertTo<float>(
+          field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_INT64:
+    case google::protobuf::Field_Kind_TYPE_SINT64:
+    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+      return DataPiece(ConvertTo<int64>(
+          field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT64:
+    case google::protobuf::Field_Kind_TYPE_FIXED64: {
+      return DataPiece(ConvertTo<uint64>(
+          field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_INT32:
+    case google::protobuf::Field_Kind_TYPE_SINT32:
+    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+      return DataPiece(ConvertTo<int32>(
+          field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_BOOL: {
+      return DataPiece(
+          ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
+    }
+    case google::protobuf::Field_Kind_TYPE_STRING: {
+      return DataPiece(field.default_value(), true);
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      return DataPiece(field.default_value(), false, true);
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT32:
+    case google::protobuf::Field_Kind_TYPE_FIXED32: {
+      return DataPiece(ConvertTo<uint32>(
+          field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      return FindEnumDefault(field, typeinfo);
+    }
+    default: { return DataPiece::NullData(); }
+  }
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
+    StringPiece name) {
+  if (current_ == NULL) {
+    vector<string> path;
+    root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
+                         false, path, field_scrub_callback_.get()));
+    root_->PopulateChildren(typeinfo_);
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) {
+    // If current_ is a list or a map node, we should create a new child and use
+    // the type of current_ as the type of the new child.
+    google::protobuf::scoped_ptr<Node> node(new Node(
+        name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP)
+                              ? current_->type()
+                              : NULL),
+        OBJECT, DataPiece::NullData(), false,
+        child == NULL ? current_->path() : child->path(),
+        field_scrub_callback_.get()));
+    child = node.get();
+    current_->AddChild(node.release());
+  }
+
+  child->set_is_placeholder(false);
+  if (child->kind() == OBJECT && child->number_of_children() == 0) {
+    child->PopulateChildren(typeinfo_);
+  }
+
+  stack_.push(current_);
+  current_ = child;
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
+  if (stack_.empty()) {
+    // The root object ends here. Writes out the tree.
+    WriteRoot();
+    return this;
+  }
+  current_ = stack_.top();
+  stack_.pop();
+  return this;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
+    StringPiece name) {
+  if (current_ == NULL) {
+    vector<string> path;
+    root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(),
+                         false, path, field_scrub_callback_.get()));
+    current_ = root_.get();
+    return this;
+  }
+  MaybePopulateChildrenOfAny(current_);
+  Node* child = current_->FindChild(name);
+  if (child == NULL || child->kind() != LIST) {
+    google::protobuf::scoped_ptr<Node> node(
+        new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false,
+                 child == NULL ? current_->path() : child->path(),
+                 field_scrub_callback_.get()));
+    child = node.get();
+    current_->AddChild(node.release());
+  }
+  child->set_is_placeholder(false);
+
+  stack_.push(current_);
+  current_ = child;
+  return this;
+}
+
+void DefaultValueObjectWriter::WriteRoot() {
+  root_->WriteTo(ow_);
+  root_.reset(NULL);
+  current_ = NULL;
+}
+
+DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
+  if (stack_.empty()) {
+    WriteRoot();
+    return this;
+  }
+  current_ = stack_.top();
+  stack_.pop();
+  return this;
+}
+
+void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
+                                               const DataPiece& data) {
+  MaybePopulateChildrenOfAny(current_);
+  util::StatusOr<string> data_string = data.ToString();
+  if (current_->type() != NULL && current_->type()->name() == kAnyType &&
+      name == "@type" && data_string.ok()) {
+    const string& string_value = data_string.ValueOrDie();
+    // If the type of current_ is "Any" and its "@type" field is being set here,
+    // sets the type of current_ to be the type specified by the "@type".
+    util::StatusOr<const google::protobuf::Type*> found_type =
+        typeinfo_->ResolveTypeUrl(string_value);
+    if (!found_type.ok()) {
+      GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
+    } else {
+      current_->set_type(found_type.ValueOrDie());
+    }
+    current_->set_is_any(true);
+    // If the "@type" field is placed after other fields, we should populate
+    // other children of primitive type now. Otherwise, we should wait until the
+    // first value field is rendered before we populate the children, because
+    // the "value" field of a Any message could be omitted.
+    if (current_->number_of_children() > 1 && current_->type() != NULL) {
+      current_->PopulateChildren(typeinfo_);
+    }
+  }
+  Node* child = current_->FindChild(name);
+  if (child == NULL || child->kind() != PRIMITIVE) {
+    // No children are found, creates a new child.
+    google::protobuf::scoped_ptr<Node> node(
+        new Node(name.ToString(), NULL, PRIMITIVE, data, false,
+                 child == NULL ? current_->path() : child->path(),
+                 field_scrub_callback_.get()));
+    child = node.get();
+    current_->AddChild(node.release());
+  } else {
+    child->set_data(data);
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
new file mode 100644
index 0000000..1d85bed
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -0,0 +1,274 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <stack>
+#include <vector>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An ObjectWriter that renders non-repeated primitive fields of proto messages
+// with their default values. DefaultValueObjectWriter holds objects, lists and
+// fields it receives in a tree structure and writes them out to another
+// ObjectWriter when EndObject() is called on the root object. It also writes
+// out all non-repeated primitive fields that haven't been explicitly rendered
+// with their default values (0 for numbers, "" for strings, etc).
+class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
+ public:
+  // A Callback function to check whether a field needs to be scrubbed.
+  //
+  // Returns true if the field should not be present in the output. Returns
+  // false otherwise.
+  //
+  // The 'path' parameter is a vector of path to the field from root. For
+  // example: if a nested field "a.b.c" (b is the parent message field of c and
+  // a is the parent message field of b), then the vector should contain { "a",
+  // "b", "c" }.
+  //
+  // The Field* should point to the google::protobuf::Field of "c".
+  typedef ResultCallback2<bool /*return*/,
+                          const std::vector<string>& /*path of the field*/,
+                          const google::protobuf::Field* /*field*/>
+      FieldScrubCallBack;
+
+  // A unique pointer to a DefaultValueObjectWriter::FieldScrubCallBack.
+  typedef google::protobuf::scoped_ptr<FieldScrubCallBack> FieldScrubCallBackPtr;
+
+  DefaultValueObjectWriter(TypeResolver* type_resolver,
+                           const google::protobuf::Type& type,
+                           ObjectWriter* ow);
+
+  virtual ~DefaultValueObjectWriter();
+
+  // ObjectWriter methods.
+  virtual DefaultValueObjectWriter* StartObject(StringPiece name);
+
+  virtual DefaultValueObjectWriter* EndObject();
+
+  virtual DefaultValueObjectWriter* StartList(StringPiece name);
+
+  virtual DefaultValueObjectWriter* EndList();
+
+  virtual DefaultValueObjectWriter* RenderBool(StringPiece name, bool value);
+
+  virtual DefaultValueObjectWriter* RenderInt32(StringPiece name, int32 value);
+
+  virtual DefaultValueObjectWriter* RenderUint32(StringPiece name,
+                                                 uint32 value);
+
+  virtual DefaultValueObjectWriter* RenderInt64(StringPiece name, int64 value);
+
+  virtual DefaultValueObjectWriter* RenderUint64(StringPiece name,
+                                                 uint64 value);
+
+  virtual DefaultValueObjectWriter* RenderDouble(StringPiece name,
+                                                 double value);
+
+  virtual DefaultValueObjectWriter* RenderFloat(StringPiece name, float value);
+
+  virtual DefaultValueObjectWriter* RenderString(StringPiece name,
+                                                 StringPiece value);
+  virtual DefaultValueObjectWriter* RenderBytes(StringPiece name,
+                                                StringPiece value);
+
+  virtual DefaultValueObjectWriter* RenderNull(StringPiece name);
+
+  // Register the callback for scrubbing of fields. Owership of
+  // field_scrub_callback pointer is also transferred to this class
+  void RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback);
+
+ private:
+  enum NodeKind {
+    PRIMITIVE = 0,
+    OBJECT = 1,
+    LIST = 2,
+    MAP = 3,
+  };
+
+  // "Node" represents a node in the tree that holds the input of
+  // DefaultValueObjectWriter.
+  class LIBPROTOBUF_EXPORT Node {
+   public:
+    Node(const string& name, const google::protobuf::Type* type, NodeKind kind,
+         const DataPiece& data, bool is_placeholder, const vector<string>& path,
+         FieldScrubCallBack* field_scrub_callback);
+    virtual ~Node() {
+      for (int i = 0; i < children_.size(); ++i) {
+        delete children_[i];
+      }
+    }
+
+    // Adds a child to this node. Takes ownership of this child.
+    void AddChild(Node* child) { children_.push_back(child); }
+
+    // Finds the child given its name.
+    Node* FindChild(StringPiece name);
+
+    // Populates children of this Node based on its type. If there are already
+    // children created, they will be merged to the result. Caller should pass
+    // in TypeInfo for looking up types of the children.
+    void PopulateChildren(const TypeInfo* typeinfo);
+
+    // If this node is a leaf (has data), writes the current node to the
+    // ObjectWriter; if not, then recursively writes the children to the
+    // ObjectWriter.
+    void WriteTo(ObjectWriter* ow);
+
+    // Accessors
+    const string& name() const { return name_; }
+
+    const vector<string>& path() const { return path_; }
+
+    const google::protobuf::Type* type() const { return type_; }
+
+    void set_type(const google::protobuf::Type* type) { type_ = type; }
+
+    NodeKind kind() const { return kind_; }
+
+    int number_of_children() const { return children_.size(); }
+
+    void set_data(const DataPiece& data) { data_ = data; }
+
+    bool is_any() const { return is_any_; }
+
+    void set_is_any(bool is_any) { is_any_ = is_any; }
+
+    void set_is_placeholder(bool is_placeholder) {
+      is_placeholder_ = is_placeholder;
+    }
+
+   private:
+    // Returns the Value Type of a map given the Type of the map entry and a
+    // TypeInfo instance.
+    const google::protobuf::Type* GetMapValueType(
+        const google::protobuf::Type& entry_type, const TypeInfo* typeinfo);
+
+    // Calls WriteTo() on every child in children_.
+    void WriteChildren(ObjectWriter* ow);
+
+    // The name of this node.
+    string name_;
+    // google::protobuf::Type of this node. Owned by TypeInfo.
+    const google::protobuf::Type* type_;
+    // The kind of this node.
+    NodeKind kind_;
+    // Whether this is a node for "Any".
+    bool is_any_;
+    // The data of this node when it is a leaf node.
+    DataPiece data_;
+    // Children of this node.
+    std::vector<Node*> children_;
+    // Whether this node is a placeholder for an object or list automatically
+    // generated when creating the parent node. Should be set to false after
+    // the parent node's StartObject()/StartList() method is called with this
+    // node's name.
+    bool is_placeholder_;
+
+    // Path of the field of this node
+    std::vector<string> path_;
+
+    // Pointer to function for determining whether a field needs to be scrubbed
+    // or not. This callback is owned by the creator of this node.
+    FieldScrubCallBack* field_scrub_callback_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
+  };
+
+  // Populates children of "node" if it is an "any" Node and its real type has
+  // been given.
+  void MaybePopulateChildrenOfAny(Node* node);
+
+  // Writes the root_ node to ow_ and resets the root_ and current_ pointer to
+  // NULL.
+  void WriteRoot();
+
+  // Creates a DataPiece containing the default value of the type of the field.
+  static DataPiece CreateDefaultDataPieceForField(
+      const google::protobuf::Field& field, const TypeInfo* typeinfo);
+
+  // Adds or replaces the data_ of a primitive child node.
+  void RenderDataPiece(StringPiece name, const DataPiece& data);
+
+  // Returns the default enum value as a DataPiece, or the first enum value if
+  // there is no default. For proto3, where we cannot specify an explicit
+  // default, a zero value will always be returned.
+  static DataPiece FindEnumDefault(const google::protobuf::Field& field,
+                                   const TypeInfo* typeinfo);
+
+  // Type information for all the types used in the descriptor. Used to find
+  // google::protobuf::Type of nested messages/enums.
+  const TypeInfo* typeinfo_;
+  // Whether the TypeInfo object is owned by this class.
+  bool own_typeinfo_;
+  // google::protobuf::Type of the root message type.
+  const google::protobuf::Type& type_;
+  // Holds copies of strings passed to RenderString.
+  vector<string*> string_values_;
+
+  // The current Node. Owned by its parents.
+  Node* current_;
+  // The root Node.
+  google::protobuf::scoped_ptr<Node> root_;
+  // The stack to hold the path of Nodes from current_ to root_;
+  std::stack<Node*> stack_;
+
+  // Unique Pointer to function for determining whether a field needs to be
+  // scrubbed or not.
+  FieldScrubCallBackPtr field_scrub_callback_;
+
+  ObjectWriter* ow_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultValueObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
new file mode 100644
index 0000000..8254c0f
--- /dev/null
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -0,0 +1,156 @@
+// 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.
+
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/expecting_objectwriter.h>
+#include <google/protobuf/util/internal/testdata/default_value_test.pb.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+namespace testing {
+
+using google::protobuf::testing::DefaultValueTest;
+
+// Base class for setting up required state for running default values tests on
+// different descriptors.
+class BaseDefaultValueObjectWriterTest
+    : public ::testing::TestWithParam<testing::TypeInfoSource> {
+ protected:
+  explicit BaseDefaultValueObjectWriterTest(const Descriptor* descriptor)
+      : helper_(GetParam()), mock_(), expects_(&mock_) {
+    helper_.ResetTypeInfo(descriptor);
+    testing_.reset(helper_.NewDefaultValueWriter(
+        string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(), &mock_));
+  }
+
+  virtual ~BaseDefaultValueObjectWriterTest() {}
+
+  TypeInfoTestHelper helper_;
+  MockObjectWriter mock_;
+  ExpectingObjectWriter expects_;
+  google::protobuf::scoped_ptr<DefaultValueObjectWriter> testing_;
+};
+
+// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are
+// in the marshalling_test.cc and translator_integration_test.cc.
+class DefaultValueObjectWriterTest : public BaseDefaultValueObjectWriterTest {
+ protected:
+  DefaultValueObjectWriterTest()
+      : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {}
+  virtual ~DefaultValueObjectWriterTest() {}
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        DefaultValueObjectWriterTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(DefaultValueObjectWriterTest, Empty) {
+  // Set expectation
+  expects_.StartObject("")
+      ->RenderDouble("doubleValue", 0.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
+      ->RenderFloat("floatValue", 0.0)
+      ->RenderInt64("int64Value", 0)
+      ->RenderUint64("uint64Value", 0)
+      ->RenderInt32("int32Value", 0)
+      ->RenderUint32("uint32Value", 0)
+      ->RenderBool("boolValue", false)
+      ->RenderString("stringValue", "")
+      ->RenderBytes("bytesValue", "")
+      ->RenderString("enumValue", "ENUM_FIRST")
+      ->EndObject();
+
+  // Actual testing
+  testing_->StartObject("")->EndObject();
+}
+
+TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) {
+  // Set expectation
+  expects_.StartObject("")
+      ->RenderDouble("doubleValue", 1.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
+      ->RenderFloat("floatValue", 0.0)
+      ->RenderInt64("int64Value", 0)
+      ->RenderUint64("uint64Value", 0)
+      ->RenderInt32("int32Value", 0)
+      ->RenderUint32("uint32Value", 0)
+      ->RenderBool("boolValue", false)
+      ->RenderString("stringValue", "")
+      ->RenderString("enumValue", "ENUM_FIRST")
+      ->EndObject();
+
+  // Actual testing
+  testing_->StartObject("")->RenderDouble("doubleValue", 1.0)->EndObject();
+}
+
+TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) {
+  // Set expectation
+  expects_.StartObject("")
+      ->RenderDouble("doubleValue", 1.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
+      ->RenderFloat("floatValue", 0.0)
+      ->RenderInt64("int64Value", 0)
+      ->RenderUint64("uint64Value", 0)
+      ->RenderInt32("int32Value", 0)
+      ->RenderUint32("uint32Value", 0)
+      ->RenderBool("boolValue", false)
+      ->RenderString("stringValue", "")
+      ->RenderString("unknown", "abc")
+      ->StartObject("unknownObject")
+      ->RenderString("unknown", "def")
+      ->EndObject()
+      ->RenderString("enumValue", "ENUM_FIRST")
+      ->EndObject();
+
+  // Actual testing
+  testing_->StartObject("")
+      ->RenderDouble("doubleValue", 1.0)
+      ->RenderString("unknown", "abc")
+      ->StartObject("unknownObject")
+      ->RenderString("unknown", "def")
+      ->EndObject()
+      ->EndObject();
+}
+
+
+}  // namespace testing
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/error_listener.cc b/src/google/protobuf/util/internal/error_listener.cc
new file mode 100644
index 0000000..538307b
--- /dev/null
+++ b/src/google/protobuf/util/internal/error_listener.cc
@@ -0,0 +1,42 @@
+// 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.
+
+#include <google/protobuf/util/internal/error_listener.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h
new file mode 100644
index 0000000..3f06393
--- /dev/null
+++ b/src/google/protobuf/util/internal/error_listener.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
+
+#include <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// Interface for error listener.
+class LIBPROTOBUF_EXPORT ErrorListener {
+ public:
+  virtual ~ErrorListener() {}
+
+  // Reports an invalid name at the given location.
+  virtual void InvalidName(const LocationTrackerInterface& loc,
+                           StringPiece unknown_name, StringPiece message) = 0;
+
+  // Reports an invalid value for a field.
+  virtual void InvalidValue(const LocationTrackerInterface& loc,
+                            StringPiece type_name, StringPiece value) = 0;
+
+  // Reports a missing required field.
+  virtual void MissingField(const LocationTrackerInterface& loc,
+                            StringPiece missing_name) = 0;
+
+ protected:
+  ErrorListener() {}
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorListener);
+};
+
+// An error listener that ignores all errors.
+class LIBPROTOBUF_EXPORT NoopErrorListener : public ErrorListener {
+ public:
+  NoopErrorListener() {}
+  virtual ~NoopErrorListener() {}
+
+  virtual void InvalidName(const LocationTrackerInterface& loc,
+                           StringPiece unknown_name, StringPiece message) {}
+
+  virtual void InvalidValue(const LocationTrackerInterface& loc,
+                            StringPiece type_name, StringPiece value) {}
+
+  virtual void MissingField(const LocationTrackerInterface& loc,
+                            StringPiece missing_name) {}
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener);
+};
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
diff --git a/src/google/protobuf/util/internal/expecting_objectwriter.h b/src/google/protobuf/util/internal/expecting_objectwriter.h
new file mode 100644
index 0000000..ae98ddd
--- /dev/null
+++ b/src/google/protobuf/util/internal/expecting_objectwriter.h
@@ -0,0 +1,238 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_EXPECTING_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_EXPECTING_OBJECTWRITER_H__
+
+// An implementation of ObjectWriter that automatically sets the
+// gmock expectations for the response to a method. Every method
+// returns the object itself for chaining.
+//
+// Usage:
+//   // Setup
+//   MockObjectWriter mock;
+//   ExpectingObjectWriter ow(&mock);
+//
+//   // Set expectation
+//   ow.StartObject("")
+//       ->RenderString("key", "value")
+//     ->EndObject();
+//
+//   // Actual testing
+//   mock.StartObject(StringPiece())
+//         ->RenderString("key", "value")
+//       ->EndObject();
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <gmock/gmock.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using testing::IsEmpty;
+using testing::NanSensitiveDoubleEq;
+using testing::NanSensitiveFloatEq;
+using testing::Return;
+using testing::StrEq;
+using testing::TypedEq;
+
+class MockObjectWriter : public ObjectWriter {
+ public:
+  MockObjectWriter() {}
+
+  MOCK_METHOD1(StartObject, ObjectWriter*(StringPiece));
+  MOCK_METHOD0(EndObject, ObjectWriter*());
+  MOCK_METHOD1(StartList, ObjectWriter*(StringPiece));
+  MOCK_METHOD0(EndList, ObjectWriter*());
+  MOCK_METHOD2(RenderBool, ObjectWriter*(StringPiece, bool));
+  MOCK_METHOD2(RenderInt32, ObjectWriter*(StringPiece, int32));
+  MOCK_METHOD2(RenderUint32, ObjectWriter*(StringPiece, uint32));
+  MOCK_METHOD2(RenderInt64, ObjectWriter*(StringPiece, int64));
+  MOCK_METHOD2(RenderUint64, ObjectWriter*(StringPiece, uint64));
+  MOCK_METHOD2(RenderDouble, ObjectWriter*(StringPiece, double));
+  MOCK_METHOD2(RenderFloat, ObjectWriter*(StringPiece, float));
+  MOCK_METHOD2(RenderString, ObjectWriter*(StringPiece, StringPiece));
+  MOCK_METHOD2(RenderBytes, ObjectWriter*(StringPiece, StringPiece));
+  MOCK_METHOD1(RenderNull, ObjectWriter*(StringPiece));
+};
+
+class ExpectingObjectWriter : public ObjectWriter {
+ public:
+  explicit ExpectingObjectWriter(MockObjectWriter* mock) : mock_(mock) {}
+
+  virtual ObjectWriter* StartObject(StringPiece name) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, StartObject(IsEmpty()))
+         : EXPECT_CALL(*mock_, StartObject(StrEq(name.ToString()))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* EndObject() {
+    EXPECT_CALL(*mock_, EndObject())
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* StartList(StringPiece name) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, StartList(IsEmpty()))
+         : EXPECT_CALL(*mock_, StartList(StrEq(name.ToString()))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* EndList() {
+    EXPECT_CALL(*mock_, EndList())
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderBool(StringPiece name, bool value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderBool(IsEmpty(), TypedEq<bool>(value)))
+         : EXPECT_CALL(*mock_, RenderBool(StrEq(name.ToString()),
+                                          TypedEq<bool>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderInt32(StringPiece name, int32 value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderInt32(IsEmpty(), TypedEq<int32>(value)))
+         : EXPECT_CALL(*mock_, RenderInt32(StrEq(name.ToString()),
+                                           TypedEq<int32>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderUint32(StringPiece name, uint32 value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderUint32(IsEmpty(), TypedEq<uint32>(value)))
+         : EXPECT_CALL(*mock_, RenderUint32(StrEq(name.ToString()),
+                                            TypedEq<uint32>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderInt64(StringPiece name, int64 value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderInt64(IsEmpty(), TypedEq<int64>(value)))
+         : EXPECT_CALL(*mock_, RenderInt64(StrEq(name.ToString()),
+                                           TypedEq<int64>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderUint64(StringPiece name, uint64 value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderUint64(IsEmpty(), TypedEq<uint64>(value)))
+         : EXPECT_CALL(*mock_, RenderUint64(StrEq(name.ToString()),
+                                            TypedEq<uint64>(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderDouble(StringPiece name, double value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderDouble(IsEmpty(),
+                                            NanSensitiveDoubleEq(value)))
+         : EXPECT_CALL(*mock_, RenderDouble(StrEq(name.ToString()),
+                                            NanSensitiveDoubleEq(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderFloat(StringPiece name, float value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderFloat(IsEmpty(),
+                                           NanSensitiveFloatEq(value)))
+         : EXPECT_CALL(*mock_, RenderFloat(StrEq(name.ToString()),
+                                           NanSensitiveFloatEq(value))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderString(StringPiece name, StringPiece value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderString(IsEmpty(),
+               TypedEq<StringPiece>(value.ToString())))
+         : EXPECT_CALL(*mock_, RenderString(StrEq(name.ToString()),
+               TypedEq<StringPiece>(value.ToString()))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) {
+    (name.empty()
+         ? EXPECT_CALL(*mock_, RenderBytes(IsEmpty(), TypedEq<StringPiece>(
+                                                          value.ToString())))
+         : EXPECT_CALL(*mock_,
+                       RenderBytes(StrEq(name.ToString()),
+                                   TypedEq<StringPiece>(value.ToString()))))
+        .WillOnce(Return(mock_))
+        .RetiresOnSaturation();
+    return this;
+  }
+
+  virtual ObjectWriter* RenderNull(StringPiece name) {
+    (name.empty() ? EXPECT_CALL(*mock_, RenderNull(IsEmpty()))
+                  : EXPECT_CALL(*mock_, RenderNull(StrEq(name.ToString())))
+                        .WillOnce(Return(mock_))
+                        .RetiresOnSaturation());
+    return this;
+  }
+
+ private:
+  MockObjectWriter* mock_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ExpectingObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_EXPECTING_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc
new file mode 100644
index 0000000..f0e8fc8
--- /dev/null
+++ b/src/google/protobuf/util/internal/field_mask_utility.cc
@@ -0,0 +1,225 @@
+// 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.
+
+#include <google/protobuf/util/internal/field_mask_utility.h>
+
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+inline util::Status CallPathSink(PathSinkCallback path_sink,
+                                   StringPiece arg) {
+  return path_sink->Run(arg);
+}
+
+util::Status CreatePublicError(util::error::Code code,
+                                 const string& message) {
+  return util::Status(code, message);
+}
+
+// Appends a FieldMask path segment to a prefix.
+string AppendPathSegmentToPrefix(StringPiece prefix, StringPiece segment) {
+  if (prefix.empty()) {
+    return segment.ToString();
+  }
+  if (segment.empty()) {
+    return prefix.ToString();
+  }
+  // If the segment is a map key, appends it to the prefix without the ".".
+  if (segment.starts_with("[\"")) {
+    return StrCat(prefix, segment);
+  }
+  return StrCat(prefix, ".", segment);
+}
+
+}  // namespace
+
+string ConvertFieldMaskPath(const StringPiece path,
+                            ConverterCallback converter) {
+  string result;
+  result.reserve(path.size() << 1);
+
+  bool is_quoted = false;
+  bool is_escaping = false;
+  int current_segment_start = 0;
+
+  // Loops until 1 passed the end of the input to make handling the last
+  // segment easier.
+  for (size_t i = 0; i <= path.size(); ++i) {
+    // Outputs quoted string as-is.
+    if (is_quoted) {
+      if (i == path.size()) {
+        break;
+      }
+      result.push_back(path[i]);
+      if (is_escaping) {
+        is_escaping = false;
+      } else if (path[i] == '\\') {
+        is_escaping = true;
+      } else if (path[i] == '\"') {
+        current_segment_start = i + 1;
+        is_quoted = false;
+      }
+      continue;
+    }
+    if (i == path.size() || path[i] == '.' || path[i] == '(' ||
+        path[i] == ')' || path[i] == '\"') {
+      result += converter(
+          path.substr(current_segment_start, i - current_segment_start));
+      if (i < path.size()) {
+        result.push_back(path[i]);
+      }
+      current_segment_start = i + 1;
+    }
+    if (i < path.size() && path[i] == '\"') {
+      is_quoted = true;
+    }
+  }
+  return result;
+}
+
+util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
+                                           PathSinkCallback path_sink) {
+  stack<string> prefix;
+  int length = paths.length();
+  int previous_position = 0;
+  bool in_map_key = false;
+  bool is_escaping = false;
+  // Loops until 1 passed the end of the input to make the handle of the last
+  // segment easier.
+  for (int i = 0; i <= length; ++i) {
+    if (i != length) {
+      // Skips everything in a map key until we hit the end of it, which is
+      // marked by an un-escaped '"' immediately followed by a ']'.
+      if (in_map_key) {
+        if (is_escaping) {
+          is_escaping = false;
+          continue;
+        }
+        if (paths[i] == '\\') {
+          is_escaping = true;
+          continue;
+        }
+        if (paths[i] != '\"') {
+          continue;
+        }
+        // Un-escaped '"' must be followed with a ']'.
+        if (i >= length - 1 || paths[i + 1] != ']') {
+          return util::Status(
+              util::error::INVALID_ARGUMENT,
+              StrCat("Invalid FieldMask '", paths,
+                     "'. Map keys should be represented as [\"some_key\"]."));
+        }
+        // The end of the map key ("\"]") has been found.
+        in_map_key = false;
+        // Skips ']'.
+        i++;
+        // Checks whether the key ends at the end of a path segment.
+        if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' &&
+            paths[i + 1] != ')' && paths[i + 1] != '(') {
+          return util::Status(
+              util::error::INVALID_ARGUMENT,
+              StrCat("Invalid FieldMask '", paths,
+                     "'. Map keys should be at the end of a path segment."));
+        }
+        is_escaping = false;
+        continue;
+      }
+
+      // We are not in a map key, look for the start of one.
+      if (paths[i] == '[') {
+        if (i >= length - 1 || paths[i + 1] != '\"') {
+          return util::Status(
+              util::error::INVALID_ARGUMENT,
+              StrCat("Invalid FieldMask '", paths,
+                     "'. Map keys should be represented as [\"some_key\"]."));
+        }
+        // "[\"" starts a map key.
+        in_map_key = true;
+        i++;  // Skips the '\"'.
+        continue;
+      }
+      // If the current character is not a special character (',', '(' or ')'),
+      // continue to the next.
+      if (paths[i] != ',' && paths[i] != ')' && paths[i] != '(') {
+        continue;
+      }
+    }
+    // Gets the current segment - sub-string between previous position (after
+    // '(', ')', ',', or the beginning of the input) and the current position.
+    StringPiece segment =
+        paths.substr(previous_position, i - previous_position);
+    string current_prefix = prefix.empty() ? "" : prefix.top();
+
+    if (i < length && paths[i] == '(') {
+      // Builds a prefix and save it into the stack.
+      prefix.push(AppendPathSegmentToPrefix(current_prefix, segment));
+    } else if (!segment.empty()) {
+      // When the current charactor is ')', ',' or the current position has
+      // passed the end of the input, builds and outputs a new paths by
+      // concatenating the last prefix with the current segment.
+      RETURN_IF_ERROR(CallPathSink(
+          path_sink, AppendPathSegmentToPrefix(current_prefix, segment)));
+    }
+
+    // Removes the last prefix after seeing a ')'.
+    if (i < length && paths[i] == ')') {
+      if (prefix.empty()) {
+        return util::Status(
+            util::error::INVALID_ARGUMENT,
+            StrCat("Invalid FieldMask '", paths,
+                   "'. Cannot find matching '(' for all ')'."));
+      }
+      prefix.pop();
+    }
+    previous_position = i + 1;
+  }
+  if (in_map_key) {
+    return util::Status(util::error::INVALID_ARGUMENT,
+                          StrCat("Invalid FieldMask '", paths,
+                                 "'. Cannot find matching ']' for all '['."));
+  }
+  if (!prefix.empty()) {
+    return util::Status(util::error::INVALID_ARGUMENT,
+                          StrCat("Invalid FieldMask '", paths,
+                                 "'. Cannot find matching ')' for all '('."));
+  }
+  return util::Status::OK;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/field_mask_utility.h b/src/google/protobuf/util/internal/field_mask_utility.h
new file mode 100644
index 0000000..59f36f7
--- /dev/null
+++ b/src/google/protobuf/util/internal/field_mask_utility.h
@@ -0,0 +1,72 @@
+// 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.
+
+// FieldMask related utility methods.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+typedef string (*ConverterCallback)(StringPiece);
+typedef ResultCallback1<util::Status, StringPiece>* PathSinkCallback;
+
+// Applies a 'converter' to each segment of a FieldMask path and returns the
+// result. Quoted strings in the 'path' are copied to the output as-is without
+// converting their content. Escaping is supported within quoted strings.
+// For example, "ab\"_c" will be returned as "ab\"_c" without any changes.
+string ConvertFieldMaskPath(const StringPiece path,
+                            ConverterCallback converter);
+
+// Decodes a compact list of FieldMasks. For example, "a.b,a.c.d,a.c.e" will be
+// decoded into a list of field paths - "a.b", "a.c.d", "a.c.e". And the results
+// will be sent to 'path_sink', i.e. 'path_sink' will be called once per
+// resulting path.
+// Note that we also support Apiary style FieldMask form. The above example in
+// the Apiary style will look like "a.b,a.c(d,e)".
+util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
+                                           PathSinkCallback path_sink);
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc
new file mode 100644
index 0000000..24bd554
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -0,0 +1,404 @@
+// 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.
+
+#include <google/protobuf/util/internal/json_escaping.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+
+// Array of hex characters for conversion to hex.
+static const char kHex[] = "0123456789abcdef";
+
+// Characters 0x00 to 0x9f are very commonly used, so we provide a special
+// table lookup.
+//
+// For unicode code point ch < 0xa0:
+// kCommonEscapes[ch] is the escaped string of ch, if escaping is needed;
+//                    or an empty string, if escaping is not needed.
+static const char kCommonEscapes[160][7] = {
+  // C0 (ASCII and derivatives) control characters
+  "\\u0000", "\\u0001", "\\u0002", "\\u0003",  // 0x00
+  "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+  "\\b",     "\\t",     "\\n",     "\\u000b",
+  "\\f",     "\\r",     "\\u000e", "\\u000f",
+  "\\u0010", "\\u0011", "\\u0012", "\\u0013",  // 0x10
+  "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+  "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+  "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+  // Escaping of " and \ are required by www.json.org string definition.
+  // Escaping of < and > are required for HTML security.
+  "", "", "\\\"", "", "",        "", "",        "",  // 0x20
+  "", "", "",     "", "",        "", "",        "",
+  "", "", "",     "", "",        "", "",        "",  // 0x30
+  "", "", "",     "", "\\u003c", "", "\\u003e", "",
+  "", "", "",     "", "",        "", "",        "",  // 0x40
+  "", "", "",     "", "",        "", "",        "",
+  "", "", "",     "", "",        "", "",        "",  // 0x50
+  "", "", "",     "", "\\\\",    "", "",        "",
+  "", "", "",     "", "",        "", "",        "",  // 0x60
+  "", "", "",     "", "",        "", "",        "",
+  "", "", "",     "", "",        "", "",        "",  // 0x70
+  "", "", "",     "", "",        "", "",        "\\u007f",
+  // C1 (ISO 8859 and Unicode) extended control characters
+  "\\u0080", "\\u0081", "\\u0082", "\\u0083",  // 0x80
+  "\\u0084", "\\u0085", "\\u0086", "\\u0087",
+  "\\u0088", "\\u0089", "\\u008a", "\\u008b",
+  "\\u008c", "\\u008d", "\\u008e", "\\u008f",
+  "\\u0090", "\\u0091", "\\u0092", "\\u0093",  // 0x90
+  "\\u0094", "\\u0095", "\\u0096", "\\u0097",
+  "\\u0098", "\\u0099", "\\u009a", "\\u009b",
+  "\\u009c", "\\u009d", "\\u009e", "\\u009f"
+};
+
+// Determines if the given char value is a unicode high-surrogate code unit.
+// Such values do not represent characters by themselves, but are used in the
+// representation of supplementary characters in the utf-16 encoding.
+inline bool IsHighSurrogate(uint16 c) {
+  // Optimized form of:
+  // return c >= kMinHighSurrogate && c <= kMaxHighSurrogate;
+  // (Reduced from 3 ALU instructions to 2 ALU instructions)
+  return (c & ~(JsonEscaping::kMaxHighSurrogate -
+                JsonEscaping::kMinHighSurrogate))
+      == JsonEscaping::kMinHighSurrogate;
+}
+
+// Determines if the given char value is a unicode low-surrogate code unit.
+// Such values do not represent characters by themselves, but are used in the
+// representation of supplementary characters in the utf-16 encoding.
+inline bool IsLowSurrogate(uint16 c) {
+  // Optimized form of:
+  // return c >= kMinLowSurrogate && c <= kMaxLowSurrogate;
+  // (Reduced from 3 ALU instructions to 2 ALU instructions)
+  return (c & ~(JsonEscaping::kMaxLowSurrogate -
+                JsonEscaping::kMinLowSurrogate))
+      == JsonEscaping::kMinLowSurrogate;
+}
+
+// Determines if the given char value is a unicode surrogate code unit (either
+// high-surrogate or low-surrogate).
+inline bool IsSurrogate(uint32 c) {
+  // Optimized form of:
+  // return c >= kMinHighSurrogate && c <= kMaxLowSurrogate;
+  // (Reduced from 3 ALU instructions to 2 ALU instructions)
+  return (c & 0xfffff800) == JsonEscaping::kMinHighSurrogate;
+}
+
+// Returns true if the given unicode code point cp is
+// in the supplementary character range.
+inline bool IsSupplementalCodePoint(uint32 cp) {
+  // Optimized form of:
+  // return kMinSupplementaryCodePoint <= cp && cp <= kMaxCodePoint;
+  // (Reduced from 3 ALU instructions to 2 ALU instructions)
+  return (cp & ~(JsonEscaping::kMinSupplementaryCodePoint - 1))
+      < JsonEscaping::kMaxCodePoint;
+}
+
+// Returns true if the given unicode code point cp is a valid
+// unicode code point (i.e. in the range 0 <= cp <= kMaxCodePoint).
+inline bool IsValidCodePoint(uint32 cp) {
+  return cp <= JsonEscaping::kMaxCodePoint;
+}
+
+// Converts the specified surrogate pair to its supplementary code point value.
+// It is the callers' responsibility to validate the specified surrogate pair.
+inline uint32 ToCodePoint(uint16 high, uint16 low) {
+  // Optimized form of:
+  // return ((high - kMinHighSurrogate) << 10)
+  //     + (low - kMinLowSurrogate)
+  //     + kMinSupplementaryCodePoint;
+  // (Reduced from 5 ALU instructions to 3 ALU instructions)
+  return (high << 10) + low +
+      (JsonEscaping::kMinSupplementaryCodePoint
+       - (static_cast<unsigned>(JsonEscaping::kMinHighSurrogate) << 10)
+       - JsonEscaping::kMinLowSurrogate);
+}
+
+// Returns the low surrogate for the given unicode code point. The result is
+// meaningless if the given code point is not a supplementary character.
+inline uint16 ToLowSurrogate(uint32 cp) {
+  return (cp & (JsonEscaping::kMaxLowSurrogate
+                - JsonEscaping::kMinLowSurrogate))
+      + JsonEscaping::kMinLowSurrogate;
+}
+
+// Returns the high surrogate for the given unicode code point. The result is
+// meaningless if the given code point is not a supplementary character.
+inline uint16 ToHighSurrogate(uint32 cp) {
+  return (cp >> 10) + (JsonEscaping::kMinHighSurrogate -
+                       (JsonEscaping::kMinSupplementaryCodePoint >> 10));
+}
+
+// Input str is encoded in UTF-8. A unicode code point could be encoded in
+// UTF-8 using anywhere from 1 to 4 characters, and it could span multiple
+// reads of the ByteSource.
+//
+// This function reads the next unicode code point from the input (str) at
+// the given position (index), taking into account any left-over partial
+// code point from the previous iteration (cp), together with the number
+// of characters left to read to complete this code point (num_left).
+//
+// This function assumes that the input (str) is valid at the given position
+// (index). In order words, at least one character could be read successfully.
+//
+// The code point read (partial or complete) is stored in (cp). Upon return,
+// (num_left) stores the number of characters that has yet to be read in
+// order to complete the current unicode code point. If the read is complete,
+// then (num_left) is 0. Also, (num_read) is the number of characters read.
+//
+// Returns false if we encounter an invalid UTF-8 string. Returns true
+// otherwise, including the case when we reach the end of the input (str)
+// before a complete unicode code point is read.
+bool ReadCodePoint(StringPiece str, int index,
+                   uint32 *cp, int* num_left, int *num_read) {
+  if (*num_left == 0) {
+    // Last read was complete. Start reading a new unicode code point.
+    *cp = static_cast<uint8>(str[index++]);
+    *num_read = 1;
+    // The length of the code point is determined from reading the first byte.
+    //
+    // If the first byte is between:
+    //    0..0x7f: that's the value of the code point.
+    // 0x80..0xbf: <invalid>
+    // 0xc0..0xdf: 11-bit code point encoded in 2 bytes.
+    //                                   bit 10-6, bit 5-0
+    // 0xe0..0xef: 16-bit code point encoded in 3 bytes.
+    //                        bit 15-12, bit 11-6, bit 5-0
+    // 0xf0..0xf7: 21-bit code point encoded in 4 bytes.
+    //             bit 20-18, bit 17-12, bit 11-6, bit 5-0
+    // 0xf8..0xff: <invalid>
+    //
+    // Meaning of each bit:
+    // <msb> bit 7: 0 - single byte code point: bits 6-0 are values.
+    //              1 - multibyte code point
+    //       bit 6: 0 - subsequent bytes of multibyte code point:
+    //                  bits 5-0 are values.
+    //              1 - first byte of multibyte code point
+    //       bit 5: 0 - first byte of 2-byte code point: bits 4-0 are values.
+    //              1 - first byte of code point with >= 3 bytes.
+    //       bit 4: 0 - first byte of 3-byte code point: bits 3-0 are values.
+    //              1 - first byte of code point with >= 4 bytes.
+    //       bit 3: 0 - first byte of 4-byte code point: bits 2-0 are values.
+    //              1 - reserved for future expansion.
+    if (*cp <= 0x7f) {
+      return true;
+    } else if (*cp <= 0xbf) {
+      return false;
+    } else if (*cp <= 0xdf) {
+      *cp &= 0x1f;
+      *num_left = 1;
+    } else if (*cp <= 0xef) {
+      *cp &= 0x0f;
+      *num_left = 2;
+    } else if (*cp <= 0xf7) {
+      *cp &= 0x07;
+      *num_left = 3;
+    } else {
+      return false;
+    }
+  } else {
+    // Last read was partial. Initialize num_read to 0 and continue reading
+    // the last unicode code point.
+    *num_read = 0;
+  }
+  while (*num_left > 0 && index < str.size()) {
+    uint32 ch = static_cast<uint8>(str[index++]);
+    --(*num_left);
+    ++(*num_read);
+    *cp = (*cp << 6) | (ch & 0x3f);
+    if (ch < 0x80 || ch > 0xbf) return false;
+  }
+  return *num_left > 0 || (!IsSurrogate(*cp) && IsValidCodePoint(*cp));
+}
+
+// Stores the 16-bit unicode code point as its hexadecimal digits in buffer
+// and returns a StringPiece that points to this buffer. The input buffer needs
+// to be at least 6 bytes long.
+StringPiece ToHex(uint16 cp, char* buffer) {
+  buffer[5] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[4] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[3] = kHex[cp & 0x0f];
+  cp >>= 4;
+  buffer[2] = kHex[cp & 0x0f];
+  return StringPiece(buffer, 0, 6);
+}
+
+// Stores the 32-bit unicode code point as its hexadecimal digits in buffer
+// and returns a StringPiece that points to this buffer. The input buffer needs
+// to be at least 12 bytes long.
+StringPiece ToSurrogateHex(uint32 cp, char* buffer) {
+  uint16 low = ToLowSurrogate(cp);
+  uint16 high = ToHighSurrogate(cp);
+
+  buffer[11] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[10] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[9] = kHex[low & 0x0f];
+  low >>= 4;
+  buffer[8] = kHex[low & 0x0f];
+
+  buffer[5] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[4] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[3] = kHex[high & 0x0f];
+  high >>= 4;
+  buffer[2] = kHex[high & 0x0f];
+
+  return StringPiece(buffer, 12);
+}
+
+// If the given unicode code point needs escaping, then returns the
+// escaped form. The returned StringPiece either points to statically
+// pre-allocated char[] or to the given buffer. The input buffer needs
+// to be at least 12 bytes long.
+//
+// If the given unicode code point does not need escaping, an empty
+// StringPiece is returned.
+StringPiece EscapeCodePoint(uint32 cp, char* buffer) {
+  if (cp < 0xa0) return kCommonEscapes[cp];
+  switch (cp) {
+    // These are not required by json spec
+    // but used to prevent security bugs in javascript.
+    case 0xfeff:  // Zero width no-break space
+    case 0xfff9:  // Interlinear annotation anchor
+    case 0xfffa:  // Interlinear annotation separator
+    case 0xfffb:  // Interlinear annotation terminator
+
+    case 0x00ad:  // Soft-hyphen
+    case 0x06dd:  // Arabic end of ayah
+    case 0x070f:  // Syriac abbreviation mark
+    case 0x17b4:  // Khmer vowel inherent Aq
+    case 0x17b5:  // Khmer vowel inherent Aa
+      return ToHex(cp, buffer);
+
+    default:
+      if ((cp >= 0x0600 && cp <= 0x0603) ||  // Arabic signs
+          (cp >= 0x200b && cp <= 0x200f) ||  // Zero width etc.
+          (cp >= 0x2028 && cp <= 0x202e) ||  // Separators etc.
+          (cp >= 0x2060 && cp <= 0x2064) ||  // Invisible etc.
+          (cp >= 0x206a && cp <= 0x206f)) {  // Shaping etc.
+        return ToHex(cp, buffer);
+      }
+
+      if (cp == 0x000e0001 ||                        // Language tag
+          (cp >= 0x0001d173 && cp <= 0x0001d17a) ||  // Music formatting
+          (cp >= 0x000e0020 && cp <= 0x000e007f)) {  // TAG symbols
+        return ToSurrogateHex(cp, buffer);
+      }
+  }
+  return StringPiece();
+}
+
+// Tries to escape the given code point first. If the given code point
+// does not need to be escaped, but force_output is true, then render
+// the given multi-byte code point in UTF8 in the buffer and returns it.
+StringPiece EscapeCodePoint(uint32 cp, char* buffer, bool force_output) {
+  StringPiece sp = EscapeCodePoint(cp, buffer);
+  if (force_output && sp.empty()) {
+    buffer[5] = (cp & 0x3f) | 0x80;
+    cp >>= 6;
+    if (cp <= 0x1f) {
+      buffer[4] = cp | 0xc0;
+      sp.set(buffer + 4, 2);
+      return sp;
+    }
+    buffer[4] = (cp & 0x3f) | 0x80;
+    cp >>= 6;
+    if (cp <= 0x0f) {
+      buffer[3] = cp | 0xe0;
+      sp.set(buffer + 3, 3);
+      return sp;
+    }
+    buffer[3] = (cp & 0x3f) | 0x80;
+    buffer[2] = ((cp >> 6) & 0x07) | 0xf0;
+    sp.set(buffer + 2, 4);
+  }
+  return sp;
+}
+
+}  // namespace
+
+void JsonEscaping::Escape(strings::ByteSource* input,
+                          strings::ByteSink* output) {
+  char buffer[12] = "\\udead\\ubee";
+  uint32 cp = 0;     // Current unicode code point.
+  int num_left = 0;  // Num of chars to read to complete the code point.
+  while (input->Available() > 0) {
+    StringPiece str = input->Peek();
+    StringPiece escaped;
+    int i = 0;
+    int num_read;
+    bool ok;
+    bool cp_was_split = num_left > 0;
+    // Loop until we encounter either
+    //   i) a code point that needs to be escaped; or
+    //  ii) a split code point is completely read; or
+    // iii) a character that is not a valid utf8; or
+    //  iv) end of the StringPiece str is reached.
+    do {
+      ok = ReadCodePoint(str, i, &cp, &num_left, &num_read);
+      if (num_left > 0 || !ok) break;  // case iii or iv
+      escaped = EscapeCodePoint(cp, buffer, cp_was_split);
+      if (!escaped.empty()) break;     // case i or ii
+      i += num_read;
+      num_read = 0;
+    } while (i < str.length());        // case iv
+    // First copy the un-escaped prefix, if any, to the output ByteSink.
+    if (i > 0) input->CopyTo(output, i);
+    if (num_read > 0) input->Skip(num_read);
+    if (!ok) {
+      // Case iii: Report error.
+      // TODO(wpoon): Add error reporting.
+      num_left = 0;
+    } else if (num_left == 0 && !escaped.empty()) {
+      // Case i or ii: Append the escaped code point to the output ByteSink.
+      output->Append(escaped.data(), escaped.size());
+    }
+  }
+  if (num_left > 0) {
+    // Treat as case iii: report error.
+    // TODO(wpoon): Add error reporting.
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/json_escaping.h b/src/google/protobuf/util/internal/json_escaping.h
new file mode 100644
index 0000000..e3e329f
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_escaping.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_
+#define NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class JsonEscaping {
+ public:
+  // The minimum value of a unicode high-surrogate code unit in the utf-16
+  // encoding. A high-surrogate is also known as a leading-surrogate.
+  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
+  static const uint16 kMinHighSurrogate = 0xd800;
+
+  // The maximum value of a unicide high-surrogate code unit in the utf-16
+  // encoding. A high-surrogate is also known as a leading-surrogate.
+  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
+  static const uint16 kMaxHighSurrogate = 0xdbff;
+
+  // The minimum value of a unicode low-surrogate code unit in the utf-16
+  // encoding. A low-surrogate is also known as a trailing-surrogate.
+  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
+  static const uint16 kMinLowSurrogate = 0xdc00;
+
+  // The maximum value of a unicode low-surrogate code unit in the utf-16
+  // encoding. A low-surrogate is also known as a trailing surrogate.
+  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
+  static const uint16 kMaxLowSurrogate = 0xdfff;
+
+  // The minimum value of a unicode supplementary code point.
+  // See http://www.unicode.org/glossary/#supplementary_code_point
+  static const uint32 kMinSupplementaryCodePoint = 0x010000;
+
+  // The minimum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static const uint32 kMinCodePoint = 0x000000;
+
+  // The maximum value of a unicode code point.
+  // See http://www.unicode.org/glossary/#code_point
+  static const uint32 kMaxCodePoint = 0x10ffff;
+
+  JsonEscaping() {}
+  virtual ~JsonEscaping() {}
+
+  // Escape the given ByteSource to the given ByteSink.
+  static void Escape(strings::ByteSource* input, strings::ByteSink* output);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JsonEscaping);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+#endif  // NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc
new file mode 100644
index 0000000..b84210c
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -0,0 +1,183 @@
+// 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.
+
+#include <google/protobuf/util/internal/json_objectwriter.h>
+
+#include <math.h>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using strings::ArrayByteSource;
+;
+
+JsonObjectWriter::~JsonObjectWriter() {
+  if (!element_->is_root()) {
+    GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
+  }
+}
+
+JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('{');
+  Push();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::EndObject() {
+  Pop();
+  WriteChar('}');
+  if (element()->is_root()) NewLine();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
+  WritePrefix(name);
+  WriteChar('[');
+  Push();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::EndList() {
+  Pop();
+  WriteChar(']');
+  if (element()->is_root()) NewLine();
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, bool value) {
+  return RenderSimple(name, value ? "true" : "false");
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, int32 value) {
+  return RenderSimple(name, SimpleItoa(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
+                                                 uint32 value) {
+  return RenderSimple(name, SimpleItoa(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, int64 value) {
+  WritePrefix(name);
+  WriteChar('"');
+  stream_->WriteString(SimpleItoa(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
+                                                 uint64 value) {
+  WritePrefix(name);
+  WriteChar('"');
+  stream_->WriteString(SimpleItoa(value));
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
+                                                 double value) {
+  if (MathLimits<double>::IsFinite(value)) {
+    return RenderSimple(name, SimpleDtoa(value));
+  }
+
+  // Render quoted with NaN/Infinity-aware DoubleAsString.
+  return RenderString(name, DoubleAsString(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) {
+  if (MathLimits<float>::IsFinite(value)) {
+    return RenderSimple(name, SimpleFtoa(value));
+  }
+
+  // Render quoted with NaN/Infinity-aware FloatAsString.
+  return RenderString(name, FloatAsString(value));
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderString(StringPiece name,
+                                                 StringPiece value) {
+  WritePrefix(name);
+  WriteChar('"');
+  ArrayByteSource source(value);
+  JsonEscaping::Escape(&source, &sink_);
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
+                                                StringPiece value) {
+  WritePrefix(name);
+  string base64;
+
+  if (use_websafe_base64_for_bytes_)
+    WebSafeBase64Escape(value.ToString(), &base64);
+  else
+    Base64Escape(value, &base64);
+
+  WriteChar('"');
+  // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
+  //              directly to the stream, rather than first putting them
+  //              into a string and then writing them to the stream.
+  stream_->WriteRaw(base64.data(), base64.size());
+  WriteChar('"');
+  return this;
+}
+
+JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
+  return RenderSimple(name, "null");
+}
+
+void JsonObjectWriter::WritePrefix(StringPiece name) {
+  bool not_first = !element()->is_first();
+  if (not_first) WriteChar(',');
+  if (not_first || !element()->is_root()) NewLine();
+  if (!name.empty()) {
+    WriteChar('"');
+    ArrayByteSource source(name);
+    JsonEscaping::Escape(&source, &sink_);
+    stream_->WriteString("\":");
+    if (!indent_string_.empty()) WriteChar(' ');
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h
new file mode 100644
index 0000000..cb7e2fb
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter.h
@@ -0,0 +1,215 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An ObjectWriter implementation that outputs JSON. This ObjectWriter
+// supports writing a compact form or a pretty printed form.
+//
+// Sample usage:
+//   string output;
+//   StringOutputStream* str_stream = new StringOutputStream(&output);
+//   CodedOutputStream* out_stream = new CodedOutputStream(str_stream);
+//   JsonObjectWriter* ow = new JsonObjectWriter("  ", out_stream);
+//   ow->StartObject("")
+//       ->RenderString("name", "value")
+//       ->RenderString("emptystring", string())
+//       ->StartObject("nested")
+//         ->RenderInt64("light", 299792458);
+//         ->RenderDouble("pi", 3.141592653589793);
+//       ->EndObject()
+//       ->StartList("empty")
+//       ->EndList()
+//     ->EndObject();
+//
+// And then the output string would become:
+// {
+//   "name": "value",
+//   "emptystring": "",
+//   "nested": {
+//     "light": "299792458",
+//     "pi": 3.141592653589793
+//   },
+//   "empty": []
+// }
+//
+// JsonObjectWriter does not validate if calls actually result in valid JSON.
+// For example, passing an empty name when one would be required won't result
+// in an error, just an invalid output.
+//
+// Note that all int64 and uint64 are rendered as strings instead of numbers.
+// This is because JavaScript parses numbers as 64-bit float thus int64 and
+// uint64 would lose precision if rendered as numbers.
+//
+// JsonObjectWriter is thread-unsafe.
+class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter {
+ public:
+  JsonObjectWriter(StringPiece indent_string,
+                   google::protobuf::io::CodedOutputStream* out)
+      : element_(new Element(NULL)),
+        stream_(out),
+        sink_(out),
+        indent_string_(indent_string.ToString()),
+        use_websafe_base64_for_bytes_(false) {}
+  virtual ~JsonObjectWriter();
+
+  // ObjectWriter methods.
+  virtual JsonObjectWriter* StartObject(StringPiece name);
+  virtual JsonObjectWriter* EndObject();
+  virtual JsonObjectWriter* StartList(StringPiece name);
+  virtual JsonObjectWriter* EndList();
+  virtual JsonObjectWriter* RenderBool(StringPiece name, bool value);
+  virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value);
+  virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value);
+  virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value);
+  virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value);
+  virtual JsonObjectWriter* RenderDouble(StringPiece name, double value);
+  virtual JsonObjectWriter* RenderFloat(StringPiece name, float value);
+  virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value);
+  virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value);
+  virtual JsonObjectWriter* RenderNull(StringPiece name);
+
+  void set_use_websafe_base64_for_bytes(bool value) {
+    use_websafe_base64_for_bytes_ = value;
+  }
+
+ protected:
+  class LIBPROTOBUF_EXPORT Element : public BaseElement {
+   public:
+    explicit Element(Element* parent) : BaseElement(parent), is_first_(true) {}
+
+    // Called before each field of the Element is to be processed.
+    // Returns true if this is the first call (processing the first field).
+    bool is_first() {
+      if (is_first_) {
+        is_first_ = false;
+        return true;
+      }
+      return false;
+    }
+
+   private:
+    bool is_first_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element);
+  };
+
+  virtual Element* element() { return element_.get(); }
+
+ private:
+  class LIBPROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink {
+   public:
+    explicit ByteSinkWrapper(google::protobuf::io::CodedOutputStream* stream)
+        : stream_(stream) {}
+    virtual ~ByteSinkWrapper() {}
+
+    // ByteSink methods.
+    virtual void Append(const char* bytes, size_t n) {
+      stream_->WriteRaw(bytes, n);
+    }
+
+   private:
+    google::protobuf::io::CodedOutputStream* stream_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSinkWrapper);
+  };
+
+  // Renders a simple value as a string. By default all non-string Render
+  // methods convert their argument to a string and call this method. This
+  // method can then be used to render the simple value without escaping it.
+  JsonObjectWriter* RenderSimple(StringPiece name, const string& value) {
+    WritePrefix(name);
+    stream_->WriteString(value);
+    return this;
+  }
+
+  // Pushes a new element to the stack.
+  void Push() { element_.reset(new Element(element_.release())); }
+
+  // Pops an element off of the stack and deletes the popped element.
+  void Pop() {
+    bool needs_newline = !element_->is_first();
+    element_.reset(element_->pop<Element>());
+    if (needs_newline) NewLine();
+  }
+
+  // If pretty printing is enabled, this will write a newline to the output,
+  // followed by optional indentation. Otherwise this method is a noop.
+  void NewLine() {
+    if (!indent_string_.empty()) {
+      WriteChar('\n');
+      for (int i = 0; i < element()->level(); i++) {
+        stream_->WriteString(indent_string_);
+      }
+    }
+  }
+
+  // Writes a prefix. This will write out any pretty printing and
+  // commas that are required, followed by the name and a ':' if
+  // the name is not null.
+  void WritePrefix(StringPiece name);
+
+  // Writes an individual character to the output.
+  void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); }
+
+  google::protobuf::scoped_ptr<Element> element_;
+  google::protobuf::io::CodedOutputStream* stream_;
+  ByteSinkWrapper sink_;
+  const string indent_string_;
+
+  // Whether to use regular or websafe base64 encoding for byte fields. Defaults
+  // to regular base64 encoding.
+  bool use_websafe_base64_for_bytes_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc
new file mode 100644
index 0000000..b87b06a
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc
@@ -0,0 +1,313 @@
+// 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.
+
+#include <google/protobuf/util/internal/json_objectwriter.h>
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::io::CodedOutputStream;
+using google::protobuf::io::StringOutputStream;
+
+class JsonObjectWriterTest : public ::testing::Test {
+ protected:
+  JsonObjectWriterTest()
+      : str_stream_(new StringOutputStream(&output_)),
+        out_stream_(new CodedOutputStream(str_stream_)),
+        ow_(NULL) {}
+
+  virtual ~JsonObjectWriterTest() {
+    delete ow_;
+    delete out_stream_;
+    delete str_stream_;
+  }
+
+  string output_;
+  StringOutputStream* const str_stream_;
+  CodedOutputStream* const out_stream_;
+  JsonObjectWriter* ow_;
+};
+
+TEST_F(JsonObjectWriterTest, EmptyRootObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")->EndObject();
+  EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, EmptyObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderString("test", "value")
+      ->StartObject("empty")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, EmptyRootList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")->EndList();
+  EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, EmptyList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderString("test", "value")
+      ->StartList("empty")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, ObjectInObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->StartObject("nested")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, ListInObject) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->StartList("nested")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ("{\"nested\":[\"value\"]}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, ObjectInList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")
+      ->StartObject("")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndList();
+  EXPECT_EQ("[{\"field\":\"value\"}]",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, ListInList) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartList("")
+      ->StartList("")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndList();
+  EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, RenderPrimitives) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderBool("bool", true)
+      ->RenderDouble("double", std::numeric_limits<double>::max())
+      ->RenderFloat("float", std::numeric_limits<float>::max())
+      ->RenderInt32("int", std::numeric_limits<int32>::min())
+      ->RenderInt64("long", std::numeric_limits<int64>::min())
+      ->RenderBytes("bytes", "abracadabra")
+      ->RenderString("string", "string")
+      ->RenderBytes("emptybytes", "")
+      ->RenderString("emptystring", string())
+      ->EndObject();
+  EXPECT_EQ(
+      "{\"bool\":true,"
+      "\"double\":" +
+          ValueAsString<double>(std::numeric_limits<double>::max()) +
+          ","
+          "\"float\":" +
+          ValueAsString<float>(std::numeric_limits<float>::max()) +
+          ","
+          "\"int\":-2147483648,"
+          "\"long\":\"-9223372036854775808\","
+          "\"bytes\":\"YWJyYWNhZGFicmE=\","
+          "\"string\":\"string\","
+          "\"emptybytes\":\"\","
+          "\"emptystring\":\"\"}",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) {
+  string s;
+  s.push_back('\377');
+  s.push_back('\357');
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")->RenderBytes("bytes", s)->EndObject();
+  // Non-web-safe would encode this as "/+8="
+  EXPECT_EQ("{\"bytes\":\"/+8=\"}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, PrettyPrintList) {
+  ow_ = new JsonObjectWriter(" ", out_stream_);
+  ow_->StartObject("")
+      ->StartList("items")
+      ->RenderString("", "item1")
+      ->RenderString("", "item2")
+      ->RenderString("", "item3")
+      ->EndList()
+      ->StartList("empty")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"items\": [\n"
+      "  \"item1\",\n"
+      "  \"item2\",\n"
+      "  \"item3\"\n"
+      " ],\n"
+      " \"empty\": []\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, PrettyPrintObject) {
+  ow_ = new JsonObjectWriter(" ", out_stream_);
+  ow_->StartObject("")
+      ->StartObject("items")
+      ->RenderString("key1", "item1")
+      ->RenderString("key2", "item2")
+      ->RenderString("key3", "item3")
+      ->EndObject()
+      ->StartObject("empty")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"items\": {\n"
+      "  \"key1\": \"item1\",\n"
+      "  \"key2\": \"item2\",\n"
+      "  \"key3\": \"item3\"\n"
+      " },\n"
+      " \"empty\": {}\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) {
+  ow_ = new JsonObjectWriter(" ", out_stream_);
+  ow_->StartObject("")
+      ->StartList("list")
+      ->StartObject("")
+      ->EndObject()
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"list\": [\n"
+      "  {}\n"
+      " ]\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) {
+  ow_ = new JsonObjectWriter("  ", out_stream_);
+  ow_->StartObject("")
+      ->RenderBool("bool", true)
+      ->RenderInt32("int", 42)
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      "  \"bool\": true,\n"
+      "  \"int\": 42\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")->RenderString("string", "'<>&amp;\\\"\r\n")->EndObject();
+  EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&amp;\\\\\\\"\\r\\n\"}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, Stringification) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
+      ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
+      ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
+      ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
+      ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
+      ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
+      ->EndObject();
+  EXPECT_EQ(
+      "{\"double_nan\":\"NaN\","
+      "\"float_nan\":\"NaN\","
+      "\"double_pos\":\"Infinity\","
+      "\"float_pos\":\"Infinity\","
+      "\"double_neg\":\"-Infinity\","
+      "\"float_neg\":\"-Infinity\"}",
+      output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->StartObject("")
+      ->RenderBytes("bytes", "\x03\xef\xc0")
+      ->EndObject();
+
+  // Test that we get regular (non websafe) base64 encoding on byte fields by
+  // default.
+  EXPECT_EQ("{\"bytes\":\"A+/A\"}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) {
+  ow_ = new JsonObjectWriter("", out_stream_);
+  ow_->set_use_websafe_base64_for_bytes(true);
+  ow_->StartObject("")
+      ->RenderBytes("bytes", "\x03\xef\xc0")
+      ->EndObject();
+
+  // Test that we get websafe base64 encoding when explicitly asked.
+  EXPECT_EQ("{\"bytes\":\"A-_A\"}",
+            output_.substr(0, out_stream_->ByteCount()));
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
new file mode 100644
index 0000000..39be7b0
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -0,0 +1,820 @@
+// 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.
+
+#include <google/protobuf/util/internal/json_stream_parser.h>
+
+#include <algorithm>
+#include <cctype>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/json_escaping.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+// Allow these symbols to be referenced as util::Status, util::error::* in
+// this file.
+using util::Status;
+namespace error {
+using util::error::INTERNAL;
+using util::error::INVALID_ARGUMENT;
+}  // namespace error
+
+namespace converter {
+
+// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X)
+static const int kUnicodeEscapedLength = 6;
+
+// Length of the true, false, and null literals.
+static const int true_len = strlen("true");
+static const int false_len = strlen("false");
+static const int null_len = strlen("null");
+
+inline bool IsLetter(char c) {
+  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_') ||
+         (c == '$');
+}
+
+inline bool IsAlphanumeric(char c) {
+  return IsLetter(c) || ('0' <= c && c <= '9');
+}
+
+static bool ConsumeKey(StringPiece* input, StringPiece* key) {
+  if (input->empty() || !IsLetter((*input)[0])) return false;
+  int len = 1;
+  for (; len < input->size(); ++len) {
+    if (!IsAlphanumeric((*input)[len])) {
+      break;
+    }
+  }
+  *key = StringPiece(input->data(), len);
+  *input = StringPiece(input->data() + len, input->size() - len);
+  return true;
+}
+
+static bool MatchKey(StringPiece input) {
+  return !input.empty() && IsLetter(input[0]);
+}
+
+JsonStreamParser::JsonStreamParser(ObjectWriter* ow)
+    : ow_(ow),
+      stack_(),
+      leftover_(),
+      json_(),
+      p_(),
+      key_(),
+      key_storage_(),
+      finishing_(false),
+      parsed_(),
+      parsed_storage_(),
+      string_open_(0),
+      chunk_storage_(),
+      coerce_to_utf8_(false) {
+  // Initialize the stack with a single value to be parsed.
+  stack_.push(VALUE);
+}
+
+JsonStreamParser::~JsonStreamParser() {}
+
+
+util::Status JsonStreamParser::Parse(StringPiece json) {
+  StringPiece chunk = json;
+  // If we have leftovers from a previous chunk, append the new chunk to it
+  // and create a new StringPiece pointing at the string's data. This could
+  // be large but we rely on the chunks to be small, assuming they are
+  // fragments of a Cord.
+  if (!leftover_.empty()) {
+    // Don't point chunk to leftover_ because leftover_ will be updated in
+    // ParseChunk(chunk).
+    chunk_storage_.swap(leftover_);
+    json.AppendToString(&chunk_storage_);
+    chunk = StringPiece(chunk_storage_);
+  }
+
+  // Find the structurally valid UTF8 prefix and parse only that.
+  int n = internal::UTF8SpnStructurallyValid(chunk);
+  if (n > 0) {
+    util::Status status = ParseChunk(chunk.substr(0, n));
+
+    // Any leftover characters are stashed in leftover_ for later parsing when
+    // there is more data available.
+    chunk.substr(n).AppendToString(&leftover_);
+    return status;
+  } else {
+    chunk.CopyToString(&leftover_);
+    return util::Status::OK;
+  }
+}
+
+util::Status JsonStreamParser::FinishParse() {
+  // If we do not expect anything and there is nothing left to parse we're all
+  // done.
+  if (stack_.empty() && leftover_.empty()) {
+    return util::Status::OK;
+  }
+
+  // Storage for UTF8-coerced string.
+  google::protobuf::scoped_array<char> utf8;
+  if (coerce_to_utf8_) {
+    utf8.reset(new char[leftover_.size()]);
+    char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' ');
+    p_ = json_ = StringPiece(coerced, leftover_.size());
+  } else {
+    p_ = json_ = leftover_;
+    if (!internal::IsStructurallyValidUTF8(leftover_)) {
+      return ReportFailure("Encountered non UTF-8 code points.");
+    }
+  }
+
+  // Parse the remainder in finishing mode, which reports errors for things like
+  // unterminated strings or unknown tokens that would normally be retried.
+  finishing_ = true;
+  util::Status result = RunParser();
+  if (result.ok()) {
+    SkipWhitespace();
+    if (!p_.empty()) {
+      result = ReportFailure("Parsing terminated before end of input.");
+    }
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseChunk(StringPiece chunk) {
+  // Do not do any work if the chunk is empty.
+  if (chunk.empty()) return util::Status::OK;
+
+  p_ = json_ = chunk;
+
+  finishing_ = false;
+  util::Status result = RunParser();
+  if (!result.ok()) return result;
+
+  SkipWhitespace();
+  if (p_.empty()) {
+    // If we parsed everything we had, clear the leftover.
+    leftover_.clear();
+  } else {
+    // If we do not expect anything i.e. stack is empty, and we have non-empty
+    // string left to parse, we report an error.
+    if (stack_.empty()) {
+      return ReportFailure("Parsing terminated before end of input.");
+    }
+    // If we expect future data i.e. stack is non-empty, and we have some
+    // unparsed data left, we save it for later parse.
+    leftover_ = p_.ToString();
+  }
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::RunParser() {
+  while (!stack_.empty()) {
+    ParseType type = stack_.top();
+    TokenType t = (string_open_ == 0) ? GetNextTokenType() : BEGIN_STRING;
+    stack_.pop();
+    util::Status result;
+    switch (type) {
+      case VALUE:
+        result = ParseValue(t);
+        break;
+
+      case OBJ_MID:
+        result = ParseObjectMid(t);
+        break;
+
+      case ENTRY:
+        result = ParseEntry(t);
+        break;
+
+      case ENTRY_MID:
+        result = ParseEntryMid(t);
+        break;
+
+      case ARRAY_VALUE:
+        result = ParseArrayValue(t);
+        break;
+
+      case ARRAY_MID:
+        result = ParseArrayMid(t);
+        break;
+
+      default:
+        result = util::Status(util::error::INTERNAL,
+                              StrCat("Unknown parse type: ", type));
+        break;
+    }
+    if (!result.ok()) {
+      // If we were cancelled, save our state and try again later.
+      if (!finishing_ && result == util::Status::CANCELLED) {
+        stack_.push(type);
+        // If we have a key we still need to render, make sure to save off the
+        // contents in our own storage.
+        if (!key_.empty() && key_storage_.empty()) {
+          key_.AppendToString(&key_storage_);
+          key_ = StringPiece(key_storage_);
+        }
+        result = util::Status::OK;
+      }
+      return result;
+    }
+  }
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseValue(TokenType type) {
+  switch (type) {
+    case BEGIN_OBJECT:
+      return HandleBeginObject();
+    case BEGIN_ARRAY:
+      return HandleBeginArray();
+    case BEGIN_STRING:
+      return ParseString();
+    case BEGIN_NUMBER:
+      return ParseNumber();
+    case BEGIN_TRUE:
+      return ParseTrue();
+    case BEGIN_FALSE:
+      return ParseFalse();
+    case BEGIN_NULL:
+      return ParseNull();
+    case UNKNOWN:
+      return ReportUnknown("Expected a value.");
+    default: {
+      // Special case for having been cut off while parsing, wait for more data.
+      // This handles things like 'fals' being at the end of the string, we
+      // don't know if the next char would be e, completing it, or something
+      // else, making it invalid.
+      if (!finishing_ && p_.length() < false_len) {
+        return util::Status::CANCELLED;
+      }
+      return ReportFailure("Unexpected token.");
+    }
+  }
+}
+
+util::Status JsonStreamParser::ParseString() {
+  util::Status result = ParseStringHelper();
+  if (result.ok()) {
+    ow_->RenderString(key_, parsed_);
+    key_.clear();
+    parsed_.clear();
+    parsed_storage_.clear();
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseStringHelper() {
+  // If we haven't seen the start quote, grab it and remember it for later.
+  if (string_open_ == 0) {
+    string_open_ = *p_.data();
+    GOOGLE_DCHECK(string_open_ == '\"' || string_open_ == '\'');
+    Advance();
+  }
+  // Track where we last copied data from so we can minimize copying.
+  const char* last = p_.data();
+  while (!p_.empty()) {
+    const char* data = p_.data();
+    if (*data == '\\') {
+      // We're about to handle an escape, copy all bytes from last to data.
+      if (last < data) {
+        parsed_storage_.append(last, data - last);
+        last = data;
+      }
+      // If we ran out of string after the \, cancel or report an error
+      // depending on if we expect more data later.
+      if (p_.length() == 1) {
+        if (!finishing_) {
+          return util::Status::CANCELLED;
+        }
+        return ReportFailure("Closing quote expected in string.");
+      }
+      // Parse a unicode escape if we found \u in the string.
+      if (data[1] == 'u') {
+        util::Status result = ParseUnicodeEscape();
+        if (!result.ok()) {
+          return result;
+        }
+        // Move last pointer past the unicode escape and continue.
+        last = p_.data();
+        continue;
+      }
+      // Handle the standard set of backslash-escaped characters.
+      switch (data[1]) {
+        case 'b':
+          parsed_storage_.push_back('\b');
+          break;
+        case 'f':
+          parsed_storage_.push_back('\f');
+          break;
+        case 'n':
+          parsed_storage_.push_back('\n');
+          break;
+        case 'r':
+          parsed_storage_.push_back('\r');
+          break;
+        case 't':
+          parsed_storage_.push_back('\t');
+          break;
+        case 'v':
+          parsed_storage_.push_back('\v');
+          break;
+        default:
+          parsed_storage_.push_back(data[1]);
+      }
+      // We handled two characters, so advance past them and continue.
+      p_.remove_prefix(2);
+      last = p_.data();
+      continue;
+    }
+    // If we found the closing quote note it, advance past it, and return.
+    if (*data == string_open_) {
+      // If we didn't copy anything, reuse the input buffer.
+      if (parsed_storage_.empty()) {
+        parsed_ = StringPiece(last, data - last);
+      } else {
+        if (last < data) {
+          parsed_storage_.append(last, data - last);
+          last = data;
+        }
+        parsed_ = StringPiece(parsed_storage_);
+      }
+      // Clear the quote char so next time we try to parse a string we'll
+      // start fresh.
+      string_open_ = 0;
+      Advance();
+      return util::Status::OK;
+    }
+    // Normal character, just advance past it.
+    Advance();
+  }
+  // If we ran out of characters, copy over what we have so far.
+  if (last < p_.data()) {
+    parsed_storage_.append(last, p_.data() - last);
+  }
+  // If we didn't find the closing quote but we expect more data, cancel for now
+  if (!finishing_) {
+    return util::Status::CANCELLED;
+  }
+  // End of string reached without a closing quote, report an error.
+  string_open_ = 0;
+  return ReportFailure("Closing quote expected in string.");
+}
+
+// Converts a unicode escaped character to a decimal value stored in a char32
+// for use in UTF8 encoding utility.  We assume that str begins with \uhhhh and
+// convert that from the hex number to a decimal value.
+//
+// There are some security exploits with UTF-8 that we should be careful of:
+//   - http://www.unicode.org/reports/tr36/#UTF-8_Exploit
+//   - http://sites/intl-eng/design-guide/core-application
+util::Status JsonStreamParser::ParseUnicodeEscape() {
+  if (p_.length() < kUnicodeEscapedLength) {
+    if (!finishing_) {
+      return util::Status::CANCELLED;
+    }
+    return ReportFailure("Illegal hex string.");
+  }
+  GOOGLE_DCHECK_EQ('\\', p_.data()[0]);
+  GOOGLE_DCHECK_EQ('u', p_.data()[1]);
+  uint32 code = 0;
+  for (int i = 2; i < kUnicodeEscapedLength; ++i) {
+    if (!isxdigit(p_.data()[i])) {
+      return ReportFailure("Invalid escape sequence.");
+    }
+    code = (code << 4) + hex_digit_to_int(p_.data()[i]);
+  }
+  if (code >= JsonEscaping::kMinHighSurrogate &&
+      code <= JsonEscaping::kMaxHighSurrogate) {
+    if (p_.length() < 2 * kUnicodeEscapedLength) {
+      if (!finishing_) {
+        return util::Status::CANCELLED;
+      }
+      if (!coerce_to_utf8_) {
+        return ReportFailure("Missing low surrogate.");
+      }
+    } else if (p_.data()[kUnicodeEscapedLength] == '\\' &&
+               p_.data()[kUnicodeEscapedLength + 1] == 'u') {
+      uint32 low_code = 0;
+      for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength;
+           ++i) {
+        if (!isxdigit(p_.data()[i])) {
+          return ReportFailure("Invalid escape sequence.");
+        }
+        low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]);
+      }
+      if (low_code >= JsonEscaping::kMinLowSurrogate &&
+          low_code <= JsonEscaping::kMaxLowSurrogate) {
+        // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint.
+        code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) +
+               JsonEscaping::kMinSupplementaryCodePoint;
+        // Advance past the first code unit escape.
+        p_.remove_prefix(kUnicodeEscapedLength);
+      } else if (!coerce_to_utf8_) {
+        return ReportFailure("Invalid low surrogate.");
+      }
+    } else if (!coerce_to_utf8_) {
+      return ReportFailure("Missing low surrogate.");
+    }
+  }
+  if (!coerce_to_utf8_ && !IsValidCodePoint(code)) {
+    return ReportFailure("Invalid unicode code point.");
+  }
+  char buf[UTFmax];
+  int len = EncodeAsUTF8Char(code, buf);
+  // Advance past the [final] code unit escape.
+  p_.remove_prefix(kUnicodeEscapedLength);
+  parsed_storage_.append(buf, len);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseNumber() {
+  NumberResult number;
+  util::Status result = ParseNumberHelper(&number);
+  if (result.ok()) {
+    switch (number.type) {
+      case NumberResult::DOUBLE:
+        ow_->RenderDouble(key_, number.double_val);
+        key_.clear();
+        break;
+
+      case NumberResult::INT:
+        ow_->RenderInt64(key_, number.int_val);
+        key_.clear();
+        break;
+
+      case NumberResult::UINT:
+        ow_->RenderUint64(key_, number.uint_val);
+        key_.clear();
+        break;
+
+      default:
+        return ReportFailure("Unable to parse number.");
+    }
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) {
+  const char* data = p_.data();
+  int length = p_.length();
+
+  // Look for the first non-numeric character, or the end of the string.
+  int index = 0;
+  bool floating = false;
+  bool negative = data[index] == '-';
+  // Find the first character that cannot be part of the number. Along the way
+  // detect if the number needs to be parsed as a double.
+  // Note that this restricts numbers to the JSON specification, so for example
+  // we do not support hex or octal notations.
+  for (; index < length; ++index) {
+    char c = data[index];
+    if (isdigit(c)) continue;
+    if (c == '.' || c == 'e' || c == 'E') {
+      floating = true;
+      continue;
+    }
+    if (c == '+' || c == '-' || c == 'x') continue;
+    // Not a valid number character, break out.
+    break;
+  }
+
+  // If the entire input is a valid number, and we may have more content in the
+  // future, we abort for now and resume when we know more.
+  if (index == length && !finishing_) {
+    return util::Status::CANCELLED;
+  }
+
+  // Create a string containing just the number, so we can use safe_strtoX
+  string number = p_.substr(0, index).ToString();
+
+  // Floating point number, parse as a double.
+  if (floating) {
+    if (!safe_strtod(number, &result->double_val)) {
+      return ReportFailure("Unable to parse number.");
+    }
+    result->type = NumberResult::DOUBLE;
+    p_.remove_prefix(index);
+    return util::Status::OK;
+  }
+
+  // Positive non-floating point number, parse as a uint64.
+  if (!negative) {
+    // Octal/Hex numbers are not valid JSON values.
+    if (number.length() >= 2 && number[0] == '0') {
+      return ReportFailure("Octal/hex numbers are not valid JSON values.");
+    }
+    if (!safe_strtou64(number, &result->uint_val)) {
+      return ReportFailure("Unable to parse number.");
+    }
+    result->type = NumberResult::UINT;
+    p_.remove_prefix(index);
+    return util::Status::OK;
+  }
+
+  // Octal/Hex numbers are not valid JSON values.
+  if (number.length() >= 3 && number[1] == '0') {
+    return ReportFailure("Octal/hex numbers are not valid JSON values.");
+  }
+  // Negative non-floating point number, parse as an int64.
+  if (!safe_strto64(number, &result->int_val)) {
+    return ReportFailure("Unable to parse number.");
+  }
+  result->type = NumberResult::INT;
+  p_.remove_prefix(index);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::HandleBeginObject() {
+  GOOGLE_DCHECK_EQ('{', *p_.data());
+  Advance();
+  ow_->StartObject(key_);
+  key_.clear();
+  stack_.push(ENTRY);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseObjectMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected , or } after key:value pair.");
+  }
+
+  // Object is complete, advance past the comma and render the EndObject.
+  if (type == END_OBJECT) {
+    Advance();
+    ow_->EndObject();
+    return util::Status::OK;
+  }
+  // Found a comma, advance past it and get ready for an entry.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ENTRY);
+    return util::Status::OK;
+  }
+  // Illegal token after key:value pair.
+  return ReportFailure("Expected , or } after key:value pair.");
+}
+
+util::Status JsonStreamParser::ParseEntry(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected an object key or }.");
+  }
+
+  // Close the object and return. This allows for trailing commas.
+  if (type == END_OBJECT) {
+    ow_->EndObject();
+    Advance();
+    return util::Status::OK;
+  }
+
+  util::Status result;
+  if (type == BEGIN_STRING) {
+    // Key is a string (standard JSON), parse it and store the string.
+    result = ParseStringHelper();
+    if (result.ok()) {
+      key_storage_.clear();
+      if (!parsed_storage_.empty()) {
+        parsed_storage_.swap(key_storage_);
+        key_ = StringPiece(key_storage_);
+      } else {
+        key_ = parsed_;
+      }
+      parsed_.clear();
+    }
+  } else if (type == BEGIN_KEY) {
+    // Key is a bare key (back compat), create a StringPiece pointing to it.
+    result = ParseKey();
+  } else {
+    // Unknown key type, report an error.
+    result = ReportFailure("Expected an object key or }.");
+  }
+  // On success we next expect an entry mid ':' then an object mid ',' or '}'
+  if (result.ok()) {
+    stack_.push(OBJ_MID);
+    stack_.push(ENTRY_MID);
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseEntryMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected : between key:value pair.");
+  }
+  if (type == ENTRY_SEPARATOR) {
+    Advance();
+    stack_.push(VALUE);
+    return util::Status::OK;
+  }
+  return ReportFailure("Expected : between key:value pair.");
+}
+
+util::Status JsonStreamParser::HandleBeginArray() {
+  GOOGLE_DCHECK_EQ('[', *p_.data());
+  Advance();
+  ow_->StartList(key_);
+  key_.clear();
+  stack_.push(ARRAY_VALUE);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseArrayValue(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected a value or ] within an array.");
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status::OK;
+  }
+
+  // The ParseValue call may push something onto the stack so we need to make
+  // sure an ARRAY_MID is after it, so we push it on now.
+  stack_.push(ARRAY_MID);
+  util::Status result = ParseValue(type);
+  if (result == util::Status::CANCELLED) {
+    // If we were cancelled, pop back off the ARRAY_MID so we don't try to
+    // push it on again when we try over.
+    stack_.pop();
+  }
+  return result;
+}
+
+util::Status JsonStreamParser::ParseArrayMid(TokenType type) {
+  if (type == UNKNOWN) {
+    return ReportUnknown("Expected , or ] after array value.");
+  }
+
+  if (type == END_ARRAY) {
+    ow_->EndList();
+    Advance();
+    return util::Status::OK;
+  }
+
+  // Found a comma, advance past it and expect an array value next.
+  if (type == VALUE_SEPARATOR) {
+    Advance();
+    stack_.push(ARRAY_VALUE);
+    return util::Status::OK;
+  }
+  // Illegal token after array value.
+  return ReportFailure("Expected , or ] after array value.");
+}
+
+util::Status JsonStreamParser::ParseTrue() {
+  ow_->RenderBool(key_, true);
+  key_.clear();
+  p_.remove_prefix(true_len);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseFalse() {
+  ow_->RenderBool(key_, false);
+  key_.clear();
+  p_.remove_prefix(false_len);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ParseNull() {
+  ow_->RenderNull(key_);
+  key_.clear();
+  p_.remove_prefix(null_len);
+  return util::Status::OK;
+}
+
+util::Status JsonStreamParser::ReportFailure(StringPiece message) {
+  static const int kContextLength = 20;
+  const char* p_start = p_.data();
+  const char* json_start = json_.data();
+  const char* begin = std::max(p_start - kContextLength, json_start);
+  const char* end =
+      std::min(p_start + kContextLength, json_start + json_.size());
+  StringPiece segment(begin, end - begin);
+  string location(p_start - begin, ' ');
+  location.push_back('^');
+  return util::Status(util::error::INVALID_ARGUMENT,
+                      StrCat(message, "\n", segment, "\n", location));
+}
+
+util::Status JsonStreamParser::ReportUnknown(StringPiece message) {
+  // If we aren't finishing the parse, cancel parsing and try later.
+  if (!finishing_) {
+    return util::Status::CANCELLED;
+  }
+  if (p_.empty()) {
+    return ReportFailure(StrCat("Unexpected end of string. ", message));
+  }
+  return ReportFailure(message);
+}
+
+void JsonStreamParser::SkipWhitespace() {
+  while (!p_.empty() && ascii_isspace(*p_.data())) {
+    Advance();
+  }
+}
+
+void JsonStreamParser::Advance() {
+  // Advance by moving one UTF8 character while making sure we don't go beyond
+  // the length of StringPiece.
+  p_.remove_prefix(std::min<int>(
+      p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length())));
+}
+
+util::Status JsonStreamParser::ParseKey() {
+  StringPiece original = p_;
+  if (!ConsumeKey(&p_, &key_)) {
+    return ReportFailure("Invalid key or variable name.");
+  }
+  // If we consumed everything but expect more data, reset p_ and cancel since
+  // we can't know if the key was complete or not.
+  if (!finishing_ && p_.empty()) {
+    p_ = original;
+    return util::Status::CANCELLED;
+  }
+  // Since we aren't using the key storage, clear it out.
+  key_storage_.clear();
+  return util::Status::OK;
+}
+
+JsonStreamParser::TokenType JsonStreamParser::GetNextTokenType() {
+  SkipWhitespace();
+
+  int size = p_.size();
+  if (size == 0) {
+    // If we ran out of data, report unknown and we'll place the previous parse
+    // type onto the stack and try again when we have more data.
+    return UNKNOWN;
+  }
+  // TODO(sven): Split this method based on context since different contexts
+  // support different tokens. Would slightly speed up processing?
+  const char* data = p_.data();
+  if (*data == '\"' || *data == '\'') return BEGIN_STRING;
+  if (*data == '-' || ('0' <= *data && *data <= '9')) {
+    return BEGIN_NUMBER;
+  }
+  if (size >= true_len && !strncmp(data, "true", true_len)) {
+    return BEGIN_TRUE;
+  }
+  if (size >= false_len && !strncmp(data, "false", false_len)) {
+    return BEGIN_FALSE;
+  }
+  if (size >= null_len && !strncmp(data, "null", null_len)) {
+    return BEGIN_NULL;
+  }
+  if (*data == '{') return BEGIN_OBJECT;
+  if (*data == '}') return END_OBJECT;
+  if (*data == '[') return BEGIN_ARRAY;
+  if (*data == ']') return END_ARRAY;
+  if (*data == ':') return ENTRY_SEPARATOR;
+  if (*data == ',') return VALUE_SEPARATOR;
+  if (MatchKey(p_)) {
+    return BEGIN_KEY;
+  }
+
+  // We don't know that we necessarily have an invalid token here, just that we
+  // can't parse what we have so far. So we don't report an error and just
+  // return UNKNOWN so we can try again later when we have more data, or if we
+  // finish and we have leftovers.
+  return UNKNOWN;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/json_stream_parser.h b/src/google/protobuf/util/internal/json_stream_parser.h
new file mode 100644
index 0000000..0278c28
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser.h
@@ -0,0 +1,258 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
+
+#include <stack>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace util {
+class Status;
+}  // namespace util
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectWriter;
+
+// A JSON parser that can parse a stream of JSON chunks rather than needing the
+// entire JSON string up front. It is a modified version of the parser in
+// //net/proto/json/json-parser.h that has been changed in the following ways:
+// - Changed from recursion to an explicit stack to allow resumption
+// - Added support for int64 and uint64 numbers
+// - Removed support for octal and decimal escapes
+// - Removed support for numeric keys
+// - Removed support for functions (javascript)
+// - Removed some lax-comma support (but kept trailing comma support)
+// - Writes directly to an ObjectWriter rather than using subclassing
+//
+// Here is an example usage:
+// JsonStreamParser parser(ow_.get());
+// util::Status result = parser.Parse(chunk1);
+// result.Update(parser.Parse(chunk2));
+// result.Update(parser.FinishParse());
+// GOOGLE_DCHECK(result.ok()) << "Failed to parse JSON";
+//
+// This parser is thread-compatible as long as only one thread is calling a
+// Parse() method at a time.
+class LIBPROTOBUF_EXPORT JsonStreamParser {
+ public:
+  // Creates a JsonStreamParser that will write to the given ObjectWriter.
+  explicit JsonStreamParser(ObjectWriter* ow);
+  virtual ~JsonStreamParser();
+
+  // Parses a UTF-8 encoded JSON string from a StringPiece.
+  util::Status Parse(StringPiece json);
+
+
+  // Finish parsing the JSON string.
+  util::Status FinishParse();
+
+
+ private:
+  enum TokenType {
+    BEGIN_STRING,     // " or '
+    BEGIN_NUMBER,     // - or digit
+    BEGIN_TRUE,       // true
+    BEGIN_FALSE,      // false
+    BEGIN_NULL,       // null
+    BEGIN_OBJECT,     // {
+    END_OBJECT,       // }
+    BEGIN_ARRAY,      // [
+    END_ARRAY,        // ]
+    ENTRY_SEPARATOR,  // :
+    VALUE_SEPARATOR,  // ,
+    BEGIN_KEY,        // letter, _, $ or digit.  Must begin with non-digit
+    UNKNOWN           // Unknown token or we ran out of the stream.
+  };
+
+  enum ParseType {
+    VALUE,        // Expects a {, [, true, false, null, string or number
+    OBJ_MID,      // Expects a ',' or }
+    ENTRY,        // Expects a key or }
+    ENTRY_MID,    // Expects a :
+    ARRAY_VALUE,  // Expects a value or ]
+    ARRAY_MID     // Expects a ',' or ]
+  };
+
+  // Holds the result of parsing a number
+  struct NumberResult {
+    enum Type { DOUBLE, INT, UINT };
+    Type type;
+    union {
+      double double_val;
+      int64 int_val;
+      uint64 uint_val;
+    };
+  };
+
+  // Parses a single chunk of JSON, returning an error if the JSON was invalid.
+  util::Status ParseChunk(StringPiece json);
+
+  // Runs the parser based on stack_ and p_, until the stack is empty or p_ runs
+  // out of data. If we unexpectedly run out of p_ we push the latest back onto
+  // the stack and return.
+  util::Status RunParser();
+
+  // Parses a value from p_ and writes it to ow_.
+  // A value may be an object, array, true, false, null, string or number.
+  util::Status ParseValue(TokenType type);
+
+  // Parses a string and writes it out to the ow_.
+  util::Status ParseString();
+
+  // Parses a string, storing the result in parsed_.
+  util::Status ParseStringHelper();
+
+  // This function parses unicode escape sequences in strings. It returns an
+  // error when there's a parsing error, either the size is not the expected
+  // size or a character is not a hex digit.  When it returns str will contain
+  // what has been successfully parsed so far.
+  util::Status ParseUnicodeEscape();
+
+  // Expects p_ to point to a JSON number, writes the number to the writer using
+  // the appropriate Render method based on the type of number.
+  util::Status ParseNumber();
+
+  // Parse a number into a NumberResult, reporting an error if no number could
+  // be parsed. This method will try to parse into a uint64, int64, or double
+  // based on whether the number was positive or negative or had a decimal
+  // component.
+  util::Status ParseNumberHelper(NumberResult* result);
+
+  // Handles a { during parsing of a value.
+  util::Status HandleBeginObject();
+
+  // Parses from the ENTRY state.
+  util::Status ParseEntry(TokenType type);
+
+  // Parses from the ENTRY_MID state.
+  util::Status ParseEntryMid(TokenType type);
+
+  // Parses from the OBJ_MID state.
+  util::Status ParseObjectMid(TokenType type);
+
+  // Handles a [ during parsing of a value.
+  util::Status HandleBeginArray();
+
+  // Parses from the ARRAY_VALUE state.
+  util::Status ParseArrayValue(TokenType type);
+
+  // Parses from the ARRAY_MID state.
+  util::Status ParseArrayMid(TokenType type);
+
+  // Expects p_ to point to an unquoted literal
+  util::Status ParseTrue();
+  util::Status ParseFalse();
+  util::Status ParseNull();
+
+  // Report a failure as a util::Status.
+  util::Status ReportFailure(StringPiece message);
+
+  // Report a failure due to an UNKNOWN token type. We check if we hit the
+  // end of the stream and if we're finishing or not to detect what type of
+  // status to return in this case.
+  util::Status ReportUnknown(StringPiece message);
+
+  // Advance p_ past all whitespace or until the end of the string.
+  void SkipWhitespace();
+
+  // Advance p_ one UTF-8 character
+  void Advance();
+
+  // Expects p_ to point to the beginning of a key.
+  util::Status ParseKey();
+
+  // Return the type of the next token at p_.
+  TokenType GetNextTokenType();
+
+  // The object writer to write parse events to.
+  ObjectWriter* ow_;
+
+  // The stack of parsing we still need to do. When the stack runs empty we will
+  // have parsed a single value from the root (e.g. an object or list).
+  std::stack<ParseType> stack_;
+
+  // Contains any leftover text from a previous chunk that we weren't able to
+  // fully parse, for example the start of a key or number.
+  string leftover_;
+
+  // The current chunk of JSON being parsed. Primarily used for providing
+  // context during error reporting.
+  StringPiece json_;
+
+  // A pointer within the current JSON being parsed, used to track location.
+  StringPiece p_;
+
+  // Stores the last key read, as we separate parsing of keys and values.
+  StringPiece key_;
+
+  // Storage for key_ if we need to keep ownership, for example between chunks
+  // or if the key was unescaped from a JSON string.
+  string key_storage_;
+
+  // True during the FinishParse() call, so we know that any errors are fatal.
+  // For example an unterminated string will normally result in cancelling and
+  // trying during the next chunk, but during FinishParse() it is an error.
+  bool finishing_;
+
+  // String we parsed during a call to ParseStringHelper().
+  StringPiece parsed_;
+
+  // Storage for the string we parsed. This may be empty if the string was able
+  // to be parsed directly from the input.
+  string parsed_storage_;
+
+  // The character that opened the string, either ' or ".
+  // A value of 0 indicates that string parsing is not in process.
+  char string_open_;
+
+  // Storage for the chunk that are being parsed in ParseChunk().
+  string chunk_storage_;
+
+  // Whether to allow non UTF-8 encoded input and replace invalid code points.
+  bool coerce_to_utf8_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc
new file mode 100644
index 0000000..059ea6d
--- /dev/null
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -0,0 +1,819 @@
+// 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.
+
+#include <google/protobuf/util/internal/json_stream_parser.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/expecting_objectwriter.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/status.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+using util::Status;
+namespace error {
+using util::error::INVALID_ARGUMENT;
+}  // namespace error
+namespace converter {
+
+using util::Status;
+
+// Tests for the JSON Stream Parser. These tests are intended to be
+// comprehensive and cover the following:
+//
+// Positive tests:
+// - true, false, null
+// - empty object or array.
+// - negative and positive double and int, unsigned int
+// - single and double quoted strings
+// - string key, unquoted key, numeric key
+// - array containing array, object, value
+// - object containing array, object, value
+// - unicode handling in strings
+// - ascii escaping (\b, \f, \n, \r, \t, \v)
+// - trailing commas
+//
+// Negative tests:
+// - illegal literals
+// - mismatched quotes failure on strings
+// - unterminated string failure
+// - unexpected end of string failure
+// - mismatched object and array closing
+// - Failure to close array or object
+// - numbers too large
+// - invalid unicode escapes.
+// - invalid unicode sequences.
+// - numbers as keys
+//
+// For each test we split the input string on every possible character to ensure
+// the parser is able to handle arbitrarily split input for all cases. We also
+// do a final test of the entire test case one character at a time.
+class JsonStreamParserTest : public ::testing::Test {
+ protected:
+  JsonStreamParserTest() : mock_(), ow_(&mock_) {}
+  virtual ~JsonStreamParserTest() {}
+
+  util::Status RunTest(StringPiece json, int split, bool coerce_utf8 = false) {
+    JsonStreamParser parser(&mock_);
+
+    // Special case for split == length, test parsing one character at a time.
+    if (split == json.length()) {
+      GOOGLE_LOG(INFO) << "Testing split every char: " << json;
+      for (int i = 0; i < json.length(); ++i) {
+        StringPiece single = json.substr(i, 1);
+        util::Status result = parser.Parse(single);
+        if (!result.ok()) {
+          return result;
+        }
+      }
+      return parser.FinishParse();
+    }
+
+    // Normal case, split at the split point and parse two substrings.
+    StringPiece first = json.substr(0, split);
+    StringPiece rest = json.substr(split);
+    GOOGLE_LOG(INFO) << "Testing split: " << first << "><" << rest;
+    util::Status result = parser.Parse(first);
+    if (result.ok()) {
+      result = parser.Parse(rest);
+      if (result.ok()) {
+        result = parser.FinishParse();
+      }
+    }
+    return result;
+  }
+
+  void DoTest(StringPiece json, int split, bool coerce_utf8 = false) {
+    util::Status result = RunTest(json, split, coerce_utf8);
+    if (!result.ok()) {
+      GOOGLE_LOG(WARNING) << result;
+    }
+    EXPECT_OK(result);
+  }
+
+  void DoErrorTest(StringPiece json, int split, StringPiece error_prefix,
+                   bool coerce_utf8 = false) {
+    util::Status result = RunTest(json, split, coerce_utf8);
+    EXPECT_EQ(util::error::INVALID_ARGUMENT, result.error_code());
+    StringPiece error_message(result.error_message());
+    EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size()));
+  }
+
+
+  MockObjectWriter mock_;
+  ExpectingObjectWriter ow_;
+};
+
+
+// Positive tests
+
+// - true, false, null
+TEST_F(JsonStreamParserTest, SimpleTrue) {
+  StringPiece str = "true";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderBool("", true);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleFalse) {
+  StringPiece str = "false";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderBool("", false);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleNull) {
+  StringPiece str = "null";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderNull("");
+    DoTest(str, i);
+  }
+}
+
+// - empty object and array.
+TEST_F(JsonStreamParserTest, EmptyObject) {
+  StringPiece str = "{}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->EndObject();
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, EmptyList) {
+  StringPiece str = "[]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - negative and positive double and int, unsigned int
+TEST_F(JsonStreamParserTest, SimpleDouble) {
+  StringPiece str = "42.5";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderDouble("", 42.5);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, ScientificDouble) {
+  StringPiece str = "1.2345e-10";
+  for (int i = 0; i < str.length(); ++i) {
+    ow_.RenderDouble("", 1.2345e-10);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleNegativeDouble) {
+  StringPiece str = "-1045.235";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderDouble("", -1045.235);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleInt) {
+  StringPiece str = "123456";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderUint64("", 123456);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleNegativeInt) {
+  StringPiece str = "-79497823553162765";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderInt64("", -79497823553162765LL);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleUnsignedInt) {
+  StringPiece str = "11779497823553162765";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderUint64("", 11779497823553162765ULL);
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) {
+  StringPiece str = "01234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
+  }
+  str = "-01234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, HexNumberIsInvalid) {
+  StringPiece str = "0x1234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
+  }
+  str = "-0x1234";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values.");
+  }
+  str = "12x34";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Unable to parse number.");
+  }
+}
+
+// - single and double quoted strings
+TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) {
+  StringPiece str = "\"\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, EmptySingleQuotedString) {
+  StringPiece str = "''";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleDoubleQuotedString) {
+  StringPiece str = "\"Some String\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "Some String");
+    DoTest(str, i);
+  }
+}
+
+TEST_F(JsonStreamParserTest, SimpleSingleQuotedString) {
+  StringPiece str = "'Another String'";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "Another String");
+    DoTest(str, i);
+  }
+}
+
+// - string key, unquoted key, numeric key
+TEST_F(JsonStreamParserTest, ObjectKeyTypes) {
+  StringPiece str =
+      "{'s': true, \"d\": false, key: null, snake_key: [], camelKey: {}}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")
+        ->RenderBool("s", true)
+        ->RenderBool("d", false)
+        ->RenderNull("key")
+        ->StartList("snake_key")
+        ->EndList()
+        ->StartObject("camelKey")
+        ->EndObject()
+        ->EndObject();
+    DoTest(str, i);
+  }
+}
+
+// - array containing array, object, values (true, false, null, num, string)
+TEST_F(JsonStreamParserTest, ArrayValues) {
+  StringPiece str =
+      "[true, false, null, 'a string', \"another string\", [22, -127, 45.3, "
+      "-1056.4, 11779497823553162765], {'key': true}]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderBool("", true)
+        ->RenderBool("", false)
+        ->RenderNull("")
+        ->RenderString("", "a string")
+        ->RenderString("", "another string")
+        ->StartList("")
+        ->RenderUint64("", 22)
+        ->RenderInt64("", -127)
+        ->RenderDouble("", 45.3)
+        ->RenderDouble("", -1056.4)
+        ->RenderUint64("", 11779497823553162765ULL)
+        ->EndList()
+        ->StartObject("")
+        ->RenderBool("key", true)
+        ->EndObject()
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - object containing array, object, value (true, false, null, num, string)
+TEST_F(JsonStreamParserTest, ObjectValues) {
+  StringPiece str =
+      "{t: true, f: false, n: null, s: 'a string', d: \"another string\", pi: "
+      "22, ni: -127, pd: 45.3, nd: -1056.4, pl: 11779497823553162765, l: [[]], "
+      "o: {'key': true}}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")
+        ->RenderBool("t", true)
+        ->RenderBool("f", false)
+        ->RenderNull("n")
+        ->RenderString("s", "a string")
+        ->RenderString("d", "another string")
+        ->RenderUint64("pi", 22)
+        ->RenderInt64("ni", -127)
+        ->RenderDouble("pd", 45.3)
+        ->RenderDouble("nd", -1056.4)
+        ->RenderUint64("pl", 11779497823553162765ULL)
+        ->StartList("l")
+        ->StartList("")
+        ->EndList()
+        ->EndList()
+        ->StartObject("o")
+        ->RenderBool("key", true)
+        ->EndObject()
+        ->EndObject();
+    DoTest(str, i);
+  }
+}
+
+
+TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) {
+  StringPiece json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}";
+  for (int i = 0; i <= json.length(); ++i) {
+    DoErrorTest(json, i, "Encountered non UTF-8 code points.");
+  }
+  json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}";
+  for (int i = 0; i <= json.length(); ++i) {
+    DoErrorTest(json, i, "Encountered non UTF-8 code points.");
+  }
+  DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.");
+}
+
+// - unicode handling in strings
+TEST_F(JsonStreamParserTest, UnicodeEscaping) {
+  StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - unicode UTF-16 surrogate pair handling in strings
+TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) {
+  StringPiece str =
+      "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("",
+                       "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0"
+                       "\x9F\x90\x9D\xF0\x9F\x8D\xAF")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+
+TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) {
+  // A low surrogate alone.
+  StringPiece str = "[\"\\ude36\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid unicode code point.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) {
+  // A high surrogate alone.
+  StringPiece str = "[\"\\ud83d\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Missing low surrogate.");
+  }
+  // A high surrogate with some trailing characters.
+  str = "[\"\\ud83d|ude36\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Missing low surrogate.");
+  }
+  // A high surrogate with half a low surrogate.
+  str = "[\"\\ud83d\\ude--\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.");
+  }
+  // Two high surrogates.
+  str = "[\"\\ud83d\\ud83d\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid low surrogate.");
+  }
+}
+
+// - ascii escaping (\b, \f, \n, \r, \t, \v)
+TEST_F(JsonStreamParserTest, AsciiEscaping) {
+  StringPiece str =
+      "[\"\\b\", \"\\ning\", \"test\\f\", \"\\r\\t\", \"test\\\\\\ving\"]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->RenderString("", "\b")
+        ->RenderString("", "\ning")
+        ->RenderString("", "test\f")
+        ->RenderString("", "\r\t")
+        ->RenderString("", "test\\\ving")
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// - trailing commas, we support a single trailing comma but no internal commas.
+TEST_F(JsonStreamParserTest, TrailingCommas) {
+  StringPiece str = "[['a',true,], {b: null,},]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")
+        ->StartList("")
+        ->RenderString("", "a")
+        ->RenderBool("", true)
+        ->EndList()
+        ->StartObject("")
+        ->RenderNull("b")
+        ->EndObject()
+        ->EndList();
+    DoTest(str, i);
+  }
+}
+
+// Negative tests
+
+// illegal literals
+TEST_F(JsonStreamParserTest, ExtraTextAfterTrue) {
+  StringPiece str = "truee";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderBool("", true);
+    DoErrorTest(str, i, "Parsing terminated before end of input.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidNumberDashOnly) {
+  StringPiece str = "-";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Unable to parse number.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidNumberDashName) {
+  StringPiece str = "-foo";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Unable to parse number.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralInArray) {
+  StringPiece str = "[nule]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Unexpected token.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralInObject) {
+  StringPiece str = "{123false}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+// mismatched quotes failure on strings
+TEST_F(JsonStreamParserTest, MismatchedSingleQuotedLiteral) {
+  StringPiece str = "'Some str\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MismatchedDoubleQuotedLiteral) {
+  StringPiece str = "\"Another string that ends poorly!'";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+// unterminated strings
+TEST_F(JsonStreamParserTest, UnterminatedLiteralString) {
+  StringPiece str = "\"Forgot the rest of i";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnterminatedStringEscape) {
+  StringPiece str = "\"Forgot the rest of \\";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnterminatedStringInArray) {
+  StringPiece str = "[\"Forgot to close the string]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnterminatedStringInObject) {
+  StringPiece str = "{f: \"Forgot to close the string}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnterminatedObject) {
+  StringPiece str = "{";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected end of string.");
+  }
+}
+
+
+// mismatched object and array closing
+TEST_F(JsonStreamParserTest, MismatchedCloseObject) {
+  StringPiece str = "{'key': true]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->RenderBool("key", true);
+    DoErrorTest(str, i, "Expected , or } after key:value pair.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MismatchedCloseArray) {
+  StringPiece str = "[true, null}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")->RenderBool("", true)->RenderNull("");
+    DoErrorTest(str, i, "Expected , or ] after array value.");
+  }
+}
+
+// Invalid object keys.
+TEST_F(JsonStreamParserTest, InvalidNumericObjectKey) {
+  StringPiece str = "{42: true}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralObjectInObject) {
+  StringPiece str = "{{bob: true}}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralArrayInObject) {
+  StringPiece str = "{[null]}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralValueInObject) {
+  StringPiece str = "{false}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MissingColonAfterStringInObject) {
+  StringPiece str = "{\"key\"}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected : between key:value pair.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MissingColonAfterKeyInObject) {
+  StringPiece str = "{key}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected : between key:value pair.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, EndOfTextAfterKeyInObject) {
+  StringPiece str = "{key";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected end of string.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MissingValueAfterColonInObject) {
+  StringPiece str = "{key:}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Unexpected token.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, MissingCommaBetweenObjectEntries) {
+  StringPiece str = "{key:20 'hello': true}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->RenderUint64("key", 20);
+    DoErrorTest(str, i, "Expected , or } after key:value pair.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, InvalidLiteralAsObjectKey) {
+  StringPiece str = "{false: 20}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, ExtraCharactersAfterObject) {
+  StringPiece str = "{}}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->EndObject();
+    DoErrorTest(str, i, "Parsing terminated before end of input.");
+  }
+}
+
+// numbers too large
+TEST_F(JsonStreamParserTest, PositiveNumberTooBig) {
+  StringPiece str = "[18446744073709551616]";  // 2^64
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Unable to parse number.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, NegativeNumberTooBig) {
+  StringPiece str = "[-18446744073709551616]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Unable to parse number.");
+  }
+}
+
+/*
+TODO(sven): Fail parsing when parsing a double that is too large.
+
+TEST_F(JsonStreamParserTest, DoubleTooBig) {
+  StringPiece str = "[184464073709551232321616.45]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Unable to parse number");
+  }
+}
+*/
+
+// invalid bare backslash.
+TEST_F(JsonStreamParserTest, UnfinishedEscape) {
+  StringPiece str = "\"\\";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Closing quote expected in string.");
+  }
+}
+
+// invalid bare backslash u.
+TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) {
+  StringPiece str = "\"\\u";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Illegal hex string.");
+  }
+}
+
+// invalid unicode sequence.
+TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) {
+  StringPiece str = "\"\\u12";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Illegal hex string.");
+  }
+}
+
+// invalid unicode sequence (valid in modern EcmaScript but not in JSON).
+TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) {
+  StringPiece str = "\"\\u{1f36f}\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.");
+  }
+}
+
+
+TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) {
+  StringPiece str = "\"\\u12$4hello";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.");
+  }
+}
+
+// invalid unicode sequence in low half surrogate: g is not a hex digit.
+TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) {
+  StringPiece str = "\"\\ud800\\udcfg\"";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Invalid escape sequence.");
+  }
+}
+
+// Extra commas with an object or array.
+TEST_F(JsonStreamParserTest, ExtraCommaInObject) {
+  StringPiece str = "{'k1': true,,'k2': false}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->RenderBool("k1", true);
+    DoErrorTest(str, i, "Expected an object key or }.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, ExtraCommaInArray) {
+  StringPiece str = "[true,,false}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")->RenderBool("", true);
+    DoErrorTest(str, i, "Unexpected token.");
+  }
+}
+
+// Extra text beyond end of value.
+TEST_F(JsonStreamParserTest, ExtraTextAfterLiteral) {
+  StringPiece str = "'hello', 'world'";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.RenderString("", "hello");
+    DoErrorTest(str, i, "Parsing terminated before end of input.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, ExtraTextAfterObject) {
+  StringPiece str = "{'key': true} 'oops'";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("")->RenderBool("key", true)->EndObject();
+    DoErrorTest(str, i, "Parsing terminated before end of input.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, ExtraTextAfterArray) {
+  StringPiece str = "[null] 'oops'";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("")->RenderNull("")->EndList();
+    DoErrorTest(str, i, "Parsing terminated before end of input.");
+  }
+}
+
+// Random unknown text in the value.
+TEST_F(JsonStreamParserTest, UnknownCharactersAsValue) {
+  StringPiece str = "*&#25";
+  for (int i = 0; i <= str.length(); ++i) {
+    DoErrorTest(str, i, "Expected a value.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnknownCharactersInArray) {
+  StringPiece str = "[*&#25]";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartList("");
+    DoErrorTest(str, i, "Expected a value or ] within an array.");
+  }
+}
+
+TEST_F(JsonStreamParserTest, UnknownCharactersInObject) {
+  StringPiece str = "{'key': *&#25}";
+  for (int i = 0; i <= str.length(); ++i) {
+    ow_.StartObject("");
+    DoErrorTest(str, i, "Expected a value.");
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/location_tracker.h b/src/google/protobuf/util/internal/location_tracker.h
new file mode 100644
index 0000000..0864b05
--- /dev/null
+++ b/src/google/protobuf/util/internal/location_tracker.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// LocationTrackerInterface is an interface for classes that track
+// the location information for the purpose of error reporting.
+class LIBPROTOBUF_EXPORT LocationTrackerInterface {
+ public:
+  virtual ~LocationTrackerInterface() {}
+
+  // Returns the object location as human readable string.
+  virtual string ToString() const = 0;
+
+ protected:
+  LocationTrackerInterface() {}
+
+ private:
+  // Please do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LocationTrackerInterface);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
diff --git a/src/google/protobuf/util/internal/mock_error_listener.h b/src/google/protobuf/util/internal/mock_error_listener.h
new file mode 100644
index 0000000..591c35d
--- /dev/null
+++ b/src/google/protobuf/util/internal/mock_error_listener.h
@@ -0,0 +1,63 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__
+
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+#include <gmock/gmock.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class MockErrorListener : public ErrorListener {
+ public:
+  MockErrorListener() {}
+  virtual ~MockErrorListener() {}
+
+  MOCK_METHOD3(InvalidName, void(const LocationTrackerInterface& loc,
+                                 StringPiece unknown_name,
+                                 StringPiece message));
+  MOCK_METHOD3(InvalidValue, void(const LocationTrackerInterface& loc,
+                                  StringPiece type_name, StringPiece value));
+  MOCK_METHOD2(MissingField, void(const LocationTrackerInterface& loc,
+                                  StringPiece missing_name));
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__
diff --git a/src/google/protobuf/util/internal/object_location_tracker.h b/src/google/protobuf/util/internal/object_location_tracker.h
new file mode 100644
index 0000000..8586cec
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_location_tracker.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/location_tracker.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An empty concrete implementation of LocationTrackerInterface.
+class ObjectLocationTracker : public LocationTrackerInterface {
+ public:
+  // Creates an empty location tracker.
+  ObjectLocationTracker() {}
+
+  virtual ~ObjectLocationTracker() {}
+
+  // Returns empty because nothing is tracked.
+  virtual string ToString() const { return ""; }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectLocationTracker);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
diff --git a/src/google/protobuf/util/internal/object_source.h b/src/google/protobuf/util/internal/object_source.h
new file mode 100644
index 0000000..2c31cfb
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_source.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_SOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_SOURCE_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectWriter;
+
+// An ObjectSource is anything that can write to an ObjectWriter.
+// Implementation of this interface typically provide constructors or
+// factory methods to create an instance based on some source data, for
+// example, a character stream, or protobuf.
+//
+// Derived classes could be thread-unsafe.
+class LIBPROTOBUF_EXPORT ObjectSource {
+ public:
+  virtual ~ObjectSource() {}
+
+  // Writes to the ObjectWriter
+  virtual util::Status WriteTo(ObjectWriter* ow) const {
+    return NamedWriteTo("", ow);
+  }
+
+  // Writes to the ObjectWriter with a custom name for the message.
+  // This is useful when you chain ObjectSource together by embedding one
+  // within another.
+  virtual util::Status NamedWriteTo(StringPiece name,
+                                      ObjectWriter* ow) const = 0;
+
+ protected:
+  ObjectSource() {}
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectSource);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_SOURCE_H__
diff --git a/src/google/protobuf/util/internal/object_writer.cc b/src/google/protobuf/util/internal/object_writer.cc
new file mode 100644
index 0000000..57cc08a
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_writer.cc
@@ -0,0 +1,92 @@
+// 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.
+
+#include <google/protobuf/util/internal/object_writer.h>
+
+#include <google/protobuf/util/internal/datapiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// static
+void ObjectWriter::RenderDataPieceTo(const DataPiece& data, StringPiece name,
+                                     ObjectWriter* ow) {
+  switch (data.type()) {
+    case DataPiece::TYPE_INT32: {
+      ow->RenderInt32(name, data.ToInt32().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_INT64: {
+      ow->RenderInt64(name, data.ToInt64().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_UINT32: {
+      ow->RenderUint32(name, data.ToUint32().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      ow->RenderUint64(name, data.ToUint64().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      ow->RenderDouble(name, data.ToDouble().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_FLOAT: {
+      ow->RenderFloat(name, data.ToFloat().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_BOOL: {
+      ow->RenderBool(name, data.ToBool().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_STRING: {
+      ow->RenderString(name, data.ToString().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_BYTES: {
+      ow->RenderBytes(name, data.ToBytes().ValueOrDie());
+      break;
+    }
+    case DataPiece::TYPE_NULL: {
+      ow->RenderNull(name);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
new file mode 100644
index 0000000..9f07363
--- /dev/null
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -0,0 +1,138 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringpiece.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class DataPiece;
+
+// An ObjectWriter is an interface for writing a stream of events
+// representing objects and collections. Implementation of this
+// interface can be used to write an object stream to an in-memory
+// structure, protobufs, JSON, XML, or any other output format
+// desired. The ObjectSource interface is typically used as the
+// source of an object stream.
+//
+// See JsonObjectWriter for a sample implementation of ObjectWriter
+// and its use.
+//
+// Derived classes could be thread-unsafe.
+//
+// TODO(xinb): seems like a prime candidate to apply the RAII paradigm
+// and get rid the need to call EndXXX().
+class LIBPROTOBUF_EXPORT ObjectWriter {
+ public:
+  virtual ~ObjectWriter() {}
+
+  // Starts an object. If the name is empty, the object will not be named.
+  virtual ObjectWriter* StartObject(StringPiece name) = 0;
+
+  // Ends an object.
+  virtual ObjectWriter* EndObject() = 0;
+
+  // Starts a list. If the name is empty, the list will not be named.
+  virtual ObjectWriter* StartList(StringPiece name) = 0;
+
+  // Ends a list.
+  virtual ObjectWriter* EndList() = 0;
+
+  // Renders a boolean value.
+  virtual ObjectWriter* RenderBool(StringPiece name, bool value) = 0;
+
+  // Renders an 32-bit integer value.
+  virtual ObjectWriter* RenderInt32(StringPiece name, int32 value) = 0;
+
+  // Renders an 32-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint32(StringPiece name, uint32 value) = 0;
+
+  // Renders a 64-bit integer value.
+  virtual ObjectWriter* RenderInt64(StringPiece name, int64 value) = 0;
+
+  // Renders an 64-bit unsigned integer value.
+  virtual ObjectWriter* RenderUint64(StringPiece name, uint64 value) = 0;
+
+  // Renders a double value.
+  virtual ObjectWriter* RenderDouble(StringPiece name, double value) = 0;
+
+  // Renders a float value.
+  virtual ObjectWriter* RenderFloat(StringPiece name, float value) = 0;
+
+  // Renders a StringPiece value. This is for rendering strings.
+  virtual ObjectWriter* RenderString(StringPiece name, StringPiece value) = 0;
+
+  // Renders a bytes value.
+  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) = 0;
+
+  // Renders a Null value.
+  virtual ObjectWriter* RenderNull(StringPiece name) = 0;
+
+  // Renders a DataPiece object to a ObjectWriter.
+  static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
+                                ObjectWriter* ow);
+
+  // Indicates whether this ObjectWriter has completed writing the root message,
+  // usually this means writing of one complete object. Subclasses must override
+  // this behavior appropriately.
+  virtual bool done() { return false; }
+
+  void set_use_strict_base64_decoding(bool value) {
+    use_strict_base64_decoding_ = value;
+  }
+
+  bool use_strict_base64_decoding() const {
+    return use_strict_base64_decoding_;
+  }
+
+ protected:
+  ObjectWriter() : use_strict_base64_decoding_(true) {}
+
+ private:
+  // If set to true, we use the stricter version of base64 decoding for byte
+  // fields by making sure decoded version encodes back to the original string.
+  bool use_strict_base64_decoding_;
+
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
new file mode 100644
index 0000000..36b7941
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -0,0 +1,762 @@
+// 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.
+
+#include <google/protobuf/util/internal/proto_writer.h>
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::internal::WireFormatLite;
+using google::protobuf::io::CodedOutputStream;
+using util::error::INVALID_ARGUMENT;
+using util::Status;
+using util::StatusOr;
+
+
+ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      done_(false),
+      element_(NULL),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      done_(false),
+      element_(NULL),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::~ProtoWriter() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+  if (element_ == NULL) return;
+  // Cleanup explicitly in order to avoid destructor stack overflow when input
+  // is deeply nested.
+  // Cast to BaseElement to avoid doing additional checks (like missing fields)
+  // during pop().
+  google::protobuf::scoped_ptr<BaseElement> element(
+      static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+  while (element != NULL) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+
+// Writes an INT32 field, including tag to the stream.
+inline Status WriteInt32(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// writes an SFIXED32 field, including tag, to the stream.
+inline Status WriteSFixed32(int field_number, const DataPiece& data,
+                            CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// Writes an SINT32 field, including tag, to the stream.
+inline Status WriteSInt32(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// Writes a FIXED32 field, including tag, to the stream.
+inline Status WriteFixed32(int field_number, const DataPiece& data,
+                           CodedOutputStream* stream) {
+  StatusOr<uint32> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
+  }
+  return u32.status();
+}
+
+// Writes a UINT32 field, including tag, to the stream.
+inline Status WriteUInt32(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<uint32> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
+  }
+  return u32.status();
+}
+
+// Writes an INT64 field, including tag, to the stream.
+inline Status WriteInt64(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SFIXED64 field, including tag, to the stream.
+inline Status WriteSFixed64(int field_number, const DataPiece& data,
+                            CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SINT64 field, including tag, to the stream.
+inline Status WriteSInt64(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes a FIXED64 field, including tag, to the stream.
+inline Status WriteFixed64(int field_number, const DataPiece& data,
+                           CodedOutputStream* stream) {
+  StatusOr<uint64> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a UINT64 field, including tag, to the stream.
+inline Status WriteUInt64(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<uint64> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a DOUBLE field, including tag, to the stream.
+inline Status WriteDouble(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<double> d = data.ToDouble();
+  if (d.ok()) {
+    WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
+  }
+  return d.status();
+}
+
+// Writes a FLOAT field, including tag, to the stream.
+inline Status WriteFloat(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<float> f = data.ToFloat();
+  if (f.ok()) {
+    WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
+  }
+  return f.status();
+}
+
+// Writes a BOOL field, including tag, to the stream.
+inline Status WriteBool(int field_number, const DataPiece& data,
+                        CodedOutputStream* stream) {
+  StatusOr<bool> b = data.ToBool();
+  if (b.ok()) {
+    WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
+  }
+  return b.status();
+}
+
+// Writes a BYTES field, including tag, to the stream.
+inline Status WriteBytes(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<string> c = data.ToBytes();
+  if (c.ok()) {
+    WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
+  }
+  return c.status();
+}
+
+// Writes a STRING field, including tag, to the stream.
+inline Status WriteString(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<string> s = data.ToString();
+  if (s.ok()) {
+    WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
+  }
+  return s.status();
+}
+
+// Writes an ENUM field, including tag, to the stream.
+inline Status WriteEnum(int field_number, const DataPiece& data,
+                        const google::protobuf::Enum* enum_type,
+                        CodedOutputStream* stream) {
+  StatusOr<int> e = data.ToEnum(enum_type);
+  if (e.ok()) {
+    WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
+  }
+  return e.status();
+}
+
+// Given a google::protobuf::Type, returns the set of all required fields.
+std::set<const google::protobuf::Field*> GetRequiredFields(
+    const google::protobuf::Type& type) {
+  std::set<const google::protobuf::Field*> required;
+  for (int i = 0; i < type.fields_size(); i++) {
+    const google::protobuf::Field& field = type.fields(i);
+    if (field.cardinality() ==
+        google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+      required.insert(&field);
+    }
+  }
+  return required;
+}
+
+}  // namespace
+
+ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
+                                        const google::protobuf::Type& type,
+                                        ProtoWriter* enclosing)
+    : BaseElement(NULL),
+      ow_(enclosing),
+      parent_field_(NULL),
+      typeinfo_(typeinfo),
+      type_(type),
+      required_fields_(GetRequiredFields(type)),
+      size_index_(-1),
+      array_index_(-1) {}
+
+ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
+                                        const google::protobuf::Field* field,
+                                        const google::protobuf::Type& type,
+                                        bool is_list)
+    : BaseElement(parent),
+      ow_(this->parent()->ow_),
+      parent_field_(field),
+      typeinfo_(this->parent()->typeinfo_),
+      type_(type),
+      size_index_(
+          !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
+              ? ow_->size_insert_.size()
+              : -1),
+      array_index_(is_list ? 0 : -1) {
+  if (!is_list) {
+    if (ow_->IsRepeated(*field)) {
+      // Update array_index_ if it is an explicit list.
+      if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
+    } else {
+      this->parent()->RegisterField(field);
+    }
+
+    if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+      required_fields_ = GetRequiredFields(type_);
+      int start_pos = ow_->stream_->ByteCount();
+      // length of serialized message is the final buffer position minus
+      // starting buffer position, plus length adjustments for size fields
+      // of any nested messages. We start with -start_pos here, so we only
+      // need to add the final buffer position to it at the end.
+      SizeInfo info = {start_pos, -start_pos};
+      ow_->size_insert_.push_back(info);
+    }
+  }
+}
+
+ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
+  // Calls the registered error listener for any required field(s) not yet
+  // seen.
+  for (set<const google::protobuf::Field*>::iterator it =
+           required_fields_.begin();
+       it != required_fields_.end(); ++it) {
+    ow_->MissingField((*it)->name());
+  }
+  // Computes the total number of proto bytes used by a message, also adjusts
+  // the size of all parent messages by the length of this size field.
+  // If size_index_ < 0, this is not a message, so no size field is added.
+  if (size_index_ >= 0) {
+    // Add the final buffer position to compute the total length of this
+    // serialized message. The stored value (before this addition) already
+    // contains the total length of the size fields of all nested messages
+    // minus the initial buffer position.
+    ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
+    // Calculate the length required to serialize the size field of the
+    // message, and propagate this additional size information upward to
+    // all enclosing messages.
+    int size = ow_->size_insert_[size_index_].size;
+    int length = CodedOutputStream::VarintSize32(size);
+    for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
+      // Only nested messages have size field, lists do not have size field.
+      if (e->size_index_ >= 0) {
+        ow_->size_insert_[e->size_index_].size += length;
+      }
+    }
+  }
+  return BaseElement::pop<ProtoElement>();
+}
+
+void ProtoWriter::ProtoElement::RegisterField(
+    const google::protobuf::Field* field) {
+  if (!required_fields_.empty() &&
+      field->cardinality() ==
+          google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+    required_fields_.erase(field);
+  }
+}
+
+string ProtoWriter::ProtoElement::ToString() const {
+  if (parent() == NULL) return "";
+  string loc = parent()->ToString();
+  if (!ow_->IsRepeated(*parent_field_) ||
+      parent()->parent_field_ != parent_field_) {
+    string name = parent_field_->name();
+    int i = 0;
+    while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
+    if (i > 0 && i == name.size()) {  // safe field name
+      if (loc.empty()) {
+        loc = name;
+      } else {
+        StrAppend(&loc, ".", name);
+      }
+    } else {
+      StrAppend(&loc, "[\"", CEscape(name), "\"]");
+    }
+  }
+  if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
+    StrAppend(&loc, "[", array_index_ - 1, "]");
+  }
+  return loc.empty() ? "." : loc;
+}
+
+bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
+  return ContainsKey(oneof_indices_, index);
+}
+
+void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
+  InsertIfNotPresent(&oneof_indices_, index);
+}
+
+void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
+  listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
+}
+
+void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) {
+  listener_->InvalidValue(location(), type_name, value);
+}
+
+void ProtoWriter::MissingField(StringPiece missing_name) {
+  listener_->MissingField(location(), missing_name);
+}
+
+ProtoWriter* ProtoWriter::StartObject(StringPiece name) {
+  // Starting the root message. Create the root ProtoElement and return.
+  if (element_ == NULL) {
+    if (!name.empty()) {
+      InvalidName(name, "Root element should not be named.");
+    }
+    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+    return this;
+  }
+
+  const google::protobuf::Field* field = NULL;
+  field = BeginNamed(name, false);
+  if (field == NULL) return this;
+
+  // Check to see if this field is a oneof and that no oneof in that group has
+  // already been set.
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    ++invalid_depth_;
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+  return StartObjectField(*field, *type);
+}
+
+ProtoWriter* ProtoWriter::EndObject() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+    return this;
+  }
+
+  if (element_ != NULL) {
+    element_.reset(element_->pop());
+  }
+
+
+  // If ending the root element,
+  // then serialize the full message with calculated sizes.
+  if (element_ == NULL) {
+    WriteRootMessage();
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartList(StringPiece name) {
+  const google::protobuf::Field* field = BeginNamed(name, true);
+  if (field == NULL) return this;
+
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    ++invalid_depth_;
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+  return StartListField(*field, *type);
+}
+
+ProtoWriter* ProtoWriter::EndList() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+  } else if (element_ != NULL) {
+    element_.reset(element_->pop());
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name,
+                                          const DataPiece& data) {
+  Status status;
+  if (invalid_depth_ > 0) return this;
+
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) return this;
+
+  if (!ValidOneof(*field, name)) return this;
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+  return RenderPrimitiveField(*field, *type, data);
+}
+
+bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
+                             StringPiece unnormalized_name) {
+  if (element_ == NULL) return true;
+
+  if (field.oneof_index() > 0) {
+    if (element_->IsOneofIndexTaken(field.oneof_index())) {
+      InvalidValue(
+          "oneof",
+          StrCat("oneof field '",
+                 element_->type().oneofs(field.oneof_index() - 1),
+                 "' is already set. Cannot set '", unnormalized_name, "'"));
+      return false;
+    }
+    element_->TakeOneofIndex(field.oneof_index());
+  }
+  return true;
+}
+
+bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
+  return field.cardinality() ==
+         google::protobuf::Field_Cardinality_CARDINALITY_REPEATED;
+}
+
+ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field,
+                                           const google::protobuf::Type& type) {
+    WriteTag(field);
+  element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field,
+                                         const google::protobuf::Type& type) {
+  element_.reset(new ProtoElement(element_.release(), &field, type, true));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::RenderPrimitiveField(
+    const google::protobuf::Field& field, const google::protobuf::Type& type,
+    const DataPiece& data) {
+  Status status;
+
+  // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
+  // error location reporting and required field accounting.
+  element_.reset(new ProtoElement(element_.release(), &field, type, false));
+
+  if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
+      field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+    InvalidValue(field.type_url().empty()
+                     ? google::protobuf::Field_Kind_Name(field.kind())
+                     : field.type_url(),
+                 data.ValueAsStringOrDefault(""));
+    element_.reset(element()->pop());
+    return this;
+  }
+
+  switch (field.kind()) {
+    case google::protobuf::Field_Kind_TYPE_INT32: {
+      status = WriteInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+      status = WriteSFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT32: {
+      status = WriteSInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED32: {
+      status = WriteFixed32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT32: {
+      status = WriteUInt32(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT64: {
+      status = WriteInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+      status = WriteSFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT64: {
+      status = WriteSInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED64: {
+      status = WriteFixed64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT64: {
+      status = WriteUInt64(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+      status = WriteDouble(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FLOAT: {
+      status = WriteFloat(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BOOL: {
+      status = WriteBool(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      status = WriteBytes(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_STRING: {
+      status = WriteString(field.number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      status = WriteEnum(field.number(), data,
+                         typeinfo_->GetEnumByTypeUrl(field.type_url()),
+                         stream_.get());
+      break;
+    }
+    default:  // TYPE_GROUP or TYPE_MESSAGE
+      status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
+  }
+
+  if (!status.ok()) {
+    InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
+                 status.error_message());
+  }
+
+  element_.reset(element()->pop());
+  return this;
+}
+
+const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
+                                                       bool is_list) {
+  if (invalid_depth_ > 0) {
+    ++invalid_depth_;
+    return NULL;
+  }
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) {
+    ++invalid_depth_;
+    // InvalidName() already called in Lookup().
+    return NULL;
+  }
+  if (is_list && !IsRepeated(*field)) {
+    ++invalid_depth_;
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return NULL;
+  }
+  return field;
+}
+
+const google::protobuf::Field* ProtoWriter::Lookup(
+    StringPiece unnormalized_name) {
+  ProtoElement* e = element();
+  if (e == NULL) {
+    InvalidName(unnormalized_name, "Root element must be a message.");
+    return NULL;
+  }
+  if (unnormalized_name.empty()) {
+    // Objects in repeated field inherit the same field descriptor.
+    if (e->parent_field() == NULL) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+    } else if (!IsRepeated(*e->parent_field())) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+      return NULL;
+    }
+    return e->parent_field();
+  }
+  const google::protobuf::Field* field =
+      typeinfo_->FindField(&e->type(), unnormalized_name);
+  if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
+  return field;
+}
+
+const google::protobuf::Type* ProtoWriter::LookupType(
+    const google::protobuf::Field* field) {
+  return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE ||
+           field->kind() == google::protobuf::Field_Kind_TYPE_GROUP)
+              ? typeinfo_->GetTypeByTypeUrl(field->type_url())
+              : &element_->type());
+}
+
+void ProtoWriter::WriteRootMessage() {
+  GOOGLE_DCHECK(!done_);
+  int curr_pos = 0;
+  // Calls the destructor of CodedOutputStream to remove any uninitialized
+  // memory from the Cord before we read it.
+  stream_.reset(NULL);
+  const void* data;
+  int length;
+  google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
+  while (input_stream.Next(&data, &length)) {
+    if (length == 0) continue;
+    int num_bytes = length;
+    // Write up to where we need to insert the size field.
+    // The number of bytes we may write is the smaller of:
+    //   - the current fragment size
+    //   - the distance to the next position where a size field needs to be
+    //     inserted.
+    if (!size_insert_.empty() &&
+        size_insert_.front().pos - curr_pos < num_bytes) {
+      num_bytes = size_insert_.front().pos - curr_pos;
+    }
+    output_->Append(static_cast<const char*>(data), num_bytes);
+    if (num_bytes < length) {
+      input_stream.BackUp(length - num_bytes);
+    }
+    curr_pos += num_bytes;
+    // Insert the size field.
+    //   size_insert_.front():      the next <index, size> pair to be written.
+    //   size_insert_.front().pos:  position of the size field.
+    //   size_insert_.front().size: the size (integer) to be inserted.
+    if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
+      // Varint32 occupies at most 10 bytes.
+      uint8 insert_buffer[10];
+      uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
+          size_insert_.front().size, insert_buffer);
+      output_->Append(reinterpret_cast<const char*>(insert_buffer),
+                      insert_buffer_pos - insert_buffer);
+      size_insert_.pop_front();
+    }
+  }
+  output_->Flush();
+  stream_.reset(new CodedOutputStream(&adapter_));
+  done_ = true;
+}
+
+void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
+  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(field.kind()));
+  stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+}
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
new file mode 100644
index 0000000..957565e
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,330 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+
+#include <deque>
+#include <google/protobuf/stubs/hash.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class CodedOutputStream;
+}  // namespace io
+}  // namespace protobuf
+
+
+namespace protobuf {
+class Type;
+class Field;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class does not support special types like Struct or Map. However, since
+// this class supports raw protobuf, it can be used to provide support for
+// special types by inheriting from it or by wrapping it.
+//
+// It also supports streaming.
+class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
+ public:
+// Constructor. Does not take ownership of any parameter passed in.
+  ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+  virtual ~ProtoWriter();
+
+  // ObjectWriter methods.
+  virtual ProtoWriter* StartObject(StringPiece name);
+  virtual ProtoWriter* EndObject();
+  virtual ProtoWriter* StartList(StringPiece name);
+  virtual ProtoWriter* EndList();
+  virtual ProtoWriter* RenderBool(StringPiece name, bool value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderDouble(StringPiece name, double value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderFloat(StringPiece name, float value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) {
+    return RenderDataPiece(name,
+                           DataPiece(value, use_strict_base64_decoding()));
+  }
+  virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
+    return RenderDataPiece(
+        name, DataPiece(value, false, use_strict_base64_decoding()));
+  }
+  virtual ProtoWriter* RenderNull(StringPiece name) {
+    return RenderDataPiece(name, DataPiece::NullData());
+  }
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  virtual ProtoWriter* RenderDataPiece(StringPiece name,
+                                       const DataPiece& value);
+
+  // Returns the location tracker to use for tracking locations for errors.
+  const LocationTrackerInterface& location() {
+    return element_ != NULL ? *element_ : *tracker_;
+  }
+
+  // When true, we finished writing to output a complete message.
+  bool done() { return done_; }
+
+  // Returns the proto stream object.
+  google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); }
+
+  // Getters and mutators of invalid_depth_.
+  void IncrementInvalidDepth() { ++invalid_depth_; }
+  void DecrementInvalidDepth() { --invalid_depth_; }
+  int invalid_depth() { return invalid_depth_; }
+
+  ErrorListener* listener() { return listener_; }
+
+  const TypeInfo* typeinfo() { return typeinfo_; }
+
+ protected:
+  class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+   public:
+    // Constructor for the root element. No parent nor field.
+    ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+                 ProtoWriter* enclosing);
+
+    // Constructor for a field of an element.
+    ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
+                 const google::protobuf::Type& type, bool is_list);
+
+    virtual ~ProtoElement() {}
+
+    // Called just before the destructor for clean up:
+    //   - reports any missing required fields
+    //   - computes the space needed by the size field, and augment the
+    //     length of all parent messages by this additional space.
+    //   - releases and returns the parent pointer.
+    ProtoElement* pop();
+
+    // Accessors
+    // parent_field() may be NULL if we are at root.
+    const google::protobuf::Field* parent_field() const {
+      return parent_field_;
+    }
+    const google::protobuf::Type& type() const { return type_; }
+
+    // Registers field for accounting required fields.
+    void RegisterField(const google::protobuf::Field* field);
+
+    // To report location on error messages.
+    virtual string ToString() const;
+
+    virtual ProtoElement* parent() const {
+      return static_cast<ProtoElement*>(BaseElement::parent());
+    }
+
+    // Returns true if the index is already taken by a preceeding oneof input.
+    bool IsOneofIndexTaken(int32 index);
+
+    // Marks the oneof 'index' as taken. Future inputs to this oneof will
+    // generate an error.
+    void TakeOneofIndex(int32 index);
+
+   private:
+    // Used for access to variables of the enclosing instance of
+    // ProtoWriter.
+    ProtoWriter* ow_;
+
+    // Describes the element as a field in the parent message.
+    // parent_field_ is NULL if and only if this element is the root element.
+    const google::protobuf::Field* parent_field_;
+
+    // TypeInfo to lookup types.
+    const TypeInfo* typeinfo_;
+
+    // Additional variables if this element is a message:
+    // (Root element is always a message).
+    // type_             : the type of this element.
+    // required_fields_  : set of required fields.
+    // size_index_       : index into ProtoWriter::size_insert_
+    //                     for later insertion of serialized message length.
+    const google::protobuf::Type& type_;
+    std::set<const google::protobuf::Field*> required_fields_;
+    const int size_index_;
+
+    // Tracks position in repeated fields, needed for LocationTrackerInterface.
+    int array_index_;
+
+    // Set of oneof indices already seen for the type_. Used to validate
+    // incoming messages so no more than one oneof is set.
+    hash_set<int32> oneof_indices_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
+  };
+
+  // Container for inserting 'size' information at the 'pos' position.
+  struct SizeInfo {
+    const int pos;
+    int size;
+  };
+
+  ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+
+  virtual ProtoElement* element() { return element_.get(); }
+
+  // Helper methods for calling ErrorListener. See error_listener.h.
+  void InvalidName(StringPiece unknown_name, StringPiece message);
+  void InvalidValue(StringPiece type_name, StringPiece value);
+  void MissingField(StringPiece missing_name);
+
+  // Common code for BeginObject() and BeginList() that does invalid_depth_
+  // bookkeeping associated with name lookup.
+  const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
+
+  // Lookup the field in the current element. Looks in the base descriptor
+  // and in any extension. This will report an error if the field cannot be
+  // found or if multiple matching extensions are found.
+  const google::protobuf::Field* Lookup(StringPiece name);
+
+  // Lookup the field type in the type descriptor. Returns NULL if the type
+  // is not known.
+  const google::protobuf::Type* LookupType(
+      const google::protobuf::Field* field);
+
+  // Write serialized output to the final output ByteSink, inserting all
+  // the size information for nested messages that are missing from the
+  // intermediate Cord buffer.
+  void WriteRootMessage();
+
+  // Helper method to write proto tags based on the given field.
+  void WriteTag(const google::protobuf::Field& field);
+
+
+  // Returns true if the field for type_ can be set as a oneof. If field is not
+  // a oneof type, this function does nothing and returns true.
+  // If another field for this oneof is already set, this function returns
+  // false. It also calls the appropriate error callback.
+  // unnormalized_name is used for error string.
+  bool ValidOneof(const google::protobuf::Field& field,
+                  StringPiece unnormalized_name);
+
+  // Returns true if the field is repeated.
+  bool IsRepeated(const google::protobuf::Field& field);
+
+  // Starts an object given the field and the enclosing type.
+  ProtoWriter* StartObjectField(const google::protobuf::Field& field,
+                                const google::protobuf::Type& type);
+
+  // Starts a list given the field and the enclosing type.
+  ProtoWriter* StartListField(const google::protobuf::Field& field,
+                              const google::protobuf::Type& type);
+
+  // Renders a primitve field given the field and the enclosing type.
+  ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field,
+                                    const google::protobuf::Type& type,
+                                    const DataPiece& value);
+
+ private:
+  // Variables for describing the structure of the input tree:
+  // master_type_: descriptor for the whole protobuf message.
+  // typeinfo_ : the TypeInfo object to lookup types.
+  const google::protobuf::Type& master_type_;
+  const TypeInfo* typeinfo_;
+  // Whether we own the typeinfo_ object.
+  bool own_typeinfo_;
+
+  // Indicates whether we finished writing root message completely.
+  bool done_;
+
+  // Variable for internal state processing:
+  // element_    : the current element.
+  // size_insert_: sizes of nested messages.
+  //               pos  - position to insert the size field.
+  //               size - size value to be inserted.
+  google::protobuf::scoped_ptr<ProtoElement> element_;
+  std::deque<SizeInfo> size_insert_;
+
+  // Variables for output generation:
+  // output_  : pointer to an external ByteSink for final user-visible output.
+  // buffer_  : buffer holding partial message before being ready for output_.
+  // adapter_ : internal adapter between CodedOutputStream and buffer_.
+  // stream_  : wrapper for writing tags and other encodings in wire format.
+  strings::ByteSink* output_;
+  string buffer_;
+  google::protobuf::io::StringOutputStream adapter_;
+  google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
+
+  // Variables for error tracking and reporting:
+  // listener_     : a place to report any errors found.
+  // invalid_depth_: number of enclosing invalid nested messages.
+  // tracker_      : the root location tracker interface.
+  ErrorListener* listener_;
+  int invalid_depth_;
+  google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
new file mode 100644
index 0000000..1f3781a
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -0,0 +1,1108 @@
+// 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.
+
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+
+#include <utility>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+using util::Status;
+using util::StatusOr;
+namespace error {
+using util::error::Code;
+using util::error::INTERNAL;
+}
+namespace converter {
+
+using google::protobuf::Descriptor;
+using google::protobuf::EnumValueDescriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::internal::WireFormat;
+using google::protobuf::internal::WireFormatLite;
+using util::Status;
+using util::StatusOr;
+
+namespace {
+
+static int kDefaultMaxRecursionDepth = 64;
+
+// Finds a field with the given number. NULL if none found.
+const google::protobuf::Field* FindFieldByNumber(
+    const google::protobuf::Type& type, int number);
+
+// Returns true if the field is packable.
+bool IsPackable(const google::protobuf::Field& field);
+
+// Finds an enum value with the given number. NULL if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumber(
+    const google::protobuf::Enum& tech_enum, int number);
+
+// Utility function to format nanos.
+const string FormatNanos(uint32 nanos);
+
+StatusOr<string> MapKeyDefaultValueAsString(
+    const google::protobuf::Field& field) {
+  switch (field.kind()) {
+    case google::protobuf::Field_Kind_TYPE_BOOL:
+      return string("false");
+    case google::protobuf::Field_Kind_TYPE_INT32:
+    case google::protobuf::Field_Kind_TYPE_INT64:
+    case google::protobuf::Field_Kind_TYPE_UINT32:
+    case google::protobuf::Field_Kind_TYPE_UINT64:
+    case google::protobuf::Field_Kind_TYPE_SINT32:
+    case google::protobuf::Field_Kind_TYPE_SINT64:
+    case google::protobuf::Field_Kind_TYPE_SFIXED32:
+    case google::protobuf::Field_Kind_TYPE_SFIXED64:
+    case google::protobuf::Field_Kind_TYPE_FIXED32:
+    case google::protobuf::Field_Kind_TYPE_FIXED64:
+      return string("0");
+    case google::protobuf::Field_Kind_TYPE_STRING:
+      return string();
+    default:
+      return Status(util::error::INTERNAL, "Invalid map key type.");
+  }
+}
+}  // namespace
+
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    google::protobuf::io::CodedInputStream* stream, TypeResolver* type_resolver,
+    const google::protobuf::Type& type)
+    : stream_(stream),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      type_(type),
+      use_lower_camel_for_enums_(false),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
+}
+
+ProtoStreamObjectSource::ProtoStreamObjectSource(
+    google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo,
+    const google::protobuf::Type& type)
+    : stream_(stream),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      type_(type),
+      use_lower_camel_for_enums_(false),
+      recursion_depth_(0),
+      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+  GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
+}
+
+ProtoStreamObjectSource::~ProtoStreamObjectSource() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+}
+
+Status ProtoStreamObjectSource::NamedWriteTo(StringPiece name,
+                                             ObjectWriter* ow) const {
+  return WriteMessage(type_, name, 0, true, ow);
+}
+
+const google::protobuf::Field* ProtoStreamObjectSource::FindAndVerifyField(
+    const google::protobuf::Type& type, uint32 tag) const {
+  // Lookup the new field in the type by tag number.
+  const google::protobuf::Field* field = FindFieldByNumber(type, tag >> 3);
+  // Verify if the field corresponds to the wire type in tag.
+  // If there is any discrepancy, mark the field as not found.
+  if (field != NULL) {
+    WireFormatLite::WireType expected_type =
+        WireFormatLite::WireTypeForFieldType(
+            static_cast<WireFormatLite::FieldType>(field->kind()));
+    WireFormatLite::WireType actual_type = WireFormatLite::GetTagWireType(tag);
+    if (actual_type != expected_type &&
+        (!IsPackable(*field) ||
+         actual_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
+      field = NULL;
+    }
+  }
+  return field;
+}
+
+Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
+                                             StringPiece name,
+                                             const uint32 end_tag,
+                                             bool include_start_and_end,
+                                             ObjectWriter* ow) const {
+
+    const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
+    if (type_renderer != NULL) {
+      return (*type_renderer)(this, type, name, ow);
+    }
+
+  const google::protobuf::Field* field = NULL;
+  string field_name;
+  // last_tag set to dummy value that is different from tag.
+  uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
+
+  if (include_start_and_end) {
+    ow->StartObject(name);
+  }
+  while (tag != end_tag) {
+    if (tag != last_tag) {  // Update field only if tag is changed.
+      last_tag = tag;
+      field = FindAndVerifyField(type, tag);
+      if (field != NULL) {
+        field_name = field->json_name();
+      }
+    }
+    if (field == NULL) {
+      // If we didn't find a field, skip this unknown tag.
+      // TODO(wpoon): Check return boolean value.
+      WireFormat::SkipField(stream_, tag, NULL);
+      tag = stream_->ReadTag();
+      continue;
+    }
+
+    if (field->cardinality() ==
+        google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
+      bool check_maps = true;
+
+      if (check_maps && IsMap(*field)) {
+        ow->StartObject(field_name);
+        ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
+        ow->EndObject();
+      } else {
+        ASSIGN_OR_RETURN(tag, RenderList(field, field_name, tag, ow));
+      }
+    } else {
+      // Render the field.
+      RETURN_IF_ERROR(RenderField(field, field_name, ow));
+      tag = stream_->ReadTag();
+    }
+  }
+  if (include_start_and_end) {
+    ow->EndObject();
+  }
+  return Status::OK;
+}
+
+StatusOr<uint32> ProtoStreamObjectSource::RenderList(
+    const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
+    ObjectWriter* ow) const {
+  uint32 tag_to_return = 0;
+  ow->StartList(name);
+  if (IsPackable(*field) &&
+      list_tag ==
+          WireFormatLite::MakeTag(field->number(),
+                                  WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
+    RETURN_IF_ERROR(RenderPacked(field, ow));
+    // Since packed fields have a single tag, read another tag from stream to
+    // return.
+    tag_to_return = stream_->ReadTag();
+  } else {
+    do {
+      RETURN_IF_ERROR(RenderField(field, "", ow));
+    } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  }
+  ow->EndList();
+  return tag_to_return;
+}
+
+StatusOr<uint32> ProtoStreamObjectSource::RenderMap(
+    const google::protobuf::Field* field, StringPiece name, uint32 list_tag,
+    ObjectWriter* ow) const {
+  const google::protobuf::Type* field_type =
+      typeinfo_->GetTypeByTypeUrl(field->type_url());
+  uint32 tag_to_return = 0;
+  do {
+    // Render map entry message type.
+    uint32 buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    string map_key;
+    for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+      const google::protobuf::Field* field =
+          FindAndVerifyField(*field_type, tag);
+      if (field == NULL) {
+        WireFormat::SkipField(stream_, tag, NULL);
+        continue;
+      }
+      // Map field numbers are key = 1 and value = 2
+      if (field->number() == 1) {
+        map_key = ReadFieldValueAsString(*field);
+      } else if (field->number() == 2) {
+        if (map_key.empty()) {
+          // An absent map key is treated as the default.
+          const google::protobuf::Field* key_field =
+              FindFieldByNumber(*field_type, 1);
+          if (key_field == NULL) {
+            // The Type info for this map entry is incorrect. It should always
+            // have a field named "key" and with field number 1.
+            return Status(util::error::INTERNAL, "Invalid map entry.");
+          }
+          ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field));
+        }
+        RETURN_IF_ERROR(RenderField(field, map_key, ow));
+      } else {
+        // The Type info for this map entry is incorrect. It should contain
+        // exactly two fields with field number 1 and 2.
+        return Status(util::error::INTERNAL, "Invalid map entry.");
+      }
+    }
+    stream_->PopLimit(old_limit);
+  } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  return tag_to_return;
+}
+
+Status ProtoStreamObjectSource::RenderPacked(
+    const google::protobuf::Field* field, ObjectWriter* ow) const {
+  uint32 length;
+  stream_->ReadVarint32(&length);
+  int old_limit = stream_->PushLimit(length);
+  while (stream_->BytesUntilLimit() > 0) {
+    RETURN_IF_ERROR(RenderField(field, StringPiece(), ow));
+  }
+  stream_->PopLimit(old_limit);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderTimestamp(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  pair<int64, int32> p = os->ReadSecondsAndNanos(type);
+  int64 seconds = p.first;
+  int32 nanos = p.second;
+  if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) {
+    return Status(
+        util::error::INTERNAL,
+        StrCat("Timestamp seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos < 0 || nanos >= kNanosPerSecond) {
+    return Status(
+        util::error::INTERNAL,
+        StrCat("Timestamp nanos exceeds limit for field: ", field_name));
+  }
+
+  ow->RenderString(field_name,
+                   ::google::protobuf::internal::FormatTime(seconds, nanos));
+
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderDuration(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  pair<int64, int32> p = os->ReadSecondsAndNanos(type);
+  int64 seconds = p.first;
+  int32 nanos = p.second;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) {
+    return Status(
+        util::error::INTERNAL,
+        StrCat("Duration seconds exceeds limit for field: ", field_name));
+  }
+
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return Status(
+        util::error::INTERNAL,
+        StrCat("Duration nanos exceeds limit for field: ", field_name));
+  }
+
+  string sign = "";
+  if (seconds < 0) {
+    if (nanos > 0) {
+      return Status(util::error::INTERNAL,
+                    StrCat("Duration nanos is non-negative, but seconds is "
+                           "negative for field: ",
+                           field_name));
+    }
+    sign = "-";
+    seconds = -seconds;
+    nanos = -nanos;
+  } else if (seconds == 0 && nanos < 0) {
+    sign = "-";
+    nanos = -nanos;
+  }
+  string formatted_duration = StringPrintf("%s%lld%ss", sign.c_str(), seconds,
+                                           FormatNanos(nanos).c_str());
+  ow->RenderString(field_name, formatted_duration);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderDouble(const ProtoStreamObjectSource* os,
+                                             const google::protobuf::Type& type,
+                                             StringPiece field_name,
+                                             ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint64 buffer64 = 0;  // default value of Double wrapper value
+  if (tag != 0) {
+    os->stream_->ReadLittleEndian64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderDouble(field_name, bit_cast<double>(buffer64));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderFloat(const ProtoStreamObjectSource* os,
+                                            const google::protobuf::Type& type,
+                                            StringPiece field_name,
+                                            ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint32 buffer32 = 0;  // default value of Float wrapper value
+  if (tag != 0) {
+    os->stream_->ReadLittleEndian32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderFloat(field_name, bit_cast<float>(buffer32));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderInt64(const ProtoStreamObjectSource* os,
+                                            const google::protobuf::Type& type,
+                                            StringPiece field_name,
+                                            ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint64 buffer64 = 0;  // default value of Int64 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderUInt64(const ProtoStreamObjectSource* os,
+                                             const google::protobuf::Type& type,
+                                             StringPiece field_name,
+                                             ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint64 buffer64 = 0;  // default value of UInt64 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderInt32(const ProtoStreamObjectSource* os,
+                                            const google::protobuf::Type& type,
+                                            StringPiece field_name,
+                                            ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint32 buffer32 = 0;  // default value of Int32 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderUInt32(const ProtoStreamObjectSource* os,
+                                             const google::protobuf::Type& type,
+                                             StringPiece field_name,
+                                             ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint32 buffer32 = 0;  // default value of UInt32 wrapper value
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderBool(const ProtoStreamObjectSource* os,
+                                           const google::protobuf::Type& type,
+                                           StringPiece field_name,
+                                           ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint64 buffer64 = 0;  // results in 'false' value as default, which is the
+                        // default value of Bool wrapper
+  if (tag != 0) {
+    os->stream_->ReadVarint64(&buffer64);
+    os->stream_->ReadTag();
+  }
+  ow->RenderBool(field_name, buffer64 != 0);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderString(const ProtoStreamObjectSource* os,
+                                             const google::protobuf::Type& type,
+                                             StringPiece field_name,
+                                             ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint32 buffer32;
+  string str;  // default value of empty for String wrapper
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);  // string size.
+    os->stream_->ReadString(&str, buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderString(field_name, str);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderBytes(const ProtoStreamObjectSource* os,
+                                            const google::protobuf::Type& type,
+                                            StringPiece field_name,
+                                            ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+  uint32 buffer32;
+  string str;
+  if (tag != 0) {
+    os->stream_->ReadVarint32(&buffer32);
+    os->stream_->ReadString(&str, buffer32);
+    os->stream_->ReadTag();
+  }
+  ow->RenderBytes(field_name, str);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderStruct(const ProtoStreamObjectSource* os,
+                                             const google::protobuf::Type& type,
+                                             StringPiece field_name,
+                                             ObjectWriter* ow) {
+  const google::protobuf::Field* field = NULL;
+  uint32 tag = os->stream_->ReadTag();
+  ow->StartObject(field_name);
+  while (tag != 0) {
+    field = os->FindAndVerifyField(type, tag);
+    // google.protobuf.Struct has only one field that is a map. Hence we use
+    // RenderMap to render that field.
+    if (os->IsMap(*field)) {
+      ASSIGN_OR_RETURN(tag, os->RenderMap(field, field_name, tag, ow));
+    }
+  }
+  ow->EndObject();
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderStructValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  const google::protobuf::Field* field = NULL;
+  for (uint32 tag = os->stream_->ReadTag(); tag != 0;
+       tag = os->stream_->ReadTag()) {
+    field = os->FindAndVerifyField(type, tag);
+    if (field == NULL) {
+      WireFormat::SkipField(os->stream_, tag, NULL);
+      continue;
+    }
+    RETURN_IF_ERROR(os->RenderField(field, field_name, ow));
+  }
+  return Status::OK;
+}
+
+// TODO(skarvaje): Avoid code duplication of for loops and SkipField logic.
+Status ProtoStreamObjectSource::RenderStructListValue(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  uint32 tag = os->stream_->ReadTag();
+
+  // Render empty list when we find empty ListValue message.
+  if (tag == 0) {
+    ow->StartList(field_name);
+    ow->EndList();
+    return Status::OK;
+  }
+
+  while (tag != 0) {
+    const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+    if (field == NULL) {
+      WireFormat::SkipField(os->stream_, tag, NULL);
+      tag = os->stream_->ReadTag();
+      continue;
+    }
+    ASSIGN_OR_RETURN(tag, os->RenderList(field, field_name, tag, ow));
+  }
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderAny(const ProtoStreamObjectSource* os,
+                                          const google::protobuf::Type& type,
+                                          StringPiece field_name,
+                                          ObjectWriter* ow) {
+  // An Any is of the form { string type_url = 1; bytes value = 2; }
+  uint32 tag;
+  string type_url;
+  string value;
+
+  // First read out the type_url and value from the proto stream
+  for (tag = os->stream_->ReadTag(); tag != 0; tag = os->stream_->ReadTag()) {
+    const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+    if (field == NULL) {
+      WireFormat::SkipField(os->stream_, tag, NULL);
+      continue;
+    }
+    // 'type_url' has field number of 1 and 'value' has field number 2
+    // //google/protobuf/any.proto
+    if (field->number() == 1) {
+      // read type_url
+      uint32 type_url_size;
+      os->stream_->ReadVarint32(&type_url_size);
+      os->stream_->ReadString(&type_url, type_url_size);
+    } else if (field->number() == 2) {
+      // read value
+      uint32 value_size;
+      os->stream_->ReadVarint32(&value_size);
+      os->stream_->ReadString(&value, value_size);
+    }
+  }
+
+  // If there is no value, we don't lookup the type, we just output it (if
+  // present). If both type and value are empty we output an empty object.
+  if (value.empty()) {
+    ow->StartObject(field_name);
+    if (!type_url.empty()) {
+      ow->RenderString("@type", type_url);
+    }
+    ow->EndObject();
+    return util::Status::OK;
+  }
+
+  // If there is a value but no type, we cannot render it, so report an error.
+  if (type_url.empty()) {
+    // TODO(sven): Add an external message once those are ready.
+    return util::Status(util::error::INTERNAL,
+                        "Invalid Any, the type_url is missing.");
+  }
+
+  util::StatusOr<const google::protobuf::Type*> resolved_type =
+      os->typeinfo_->ResolveTypeUrl(type_url);
+
+  if (!resolved_type.ok()) {
+    // Convert into an internal error, since this means the backend gave us
+    // an invalid response (missing or invalid type information).
+    return util::Status(util::error::INTERNAL,
+                        resolved_type.status().error_message());
+  }
+  // nested_type cannot be null at this time.
+  const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
+
+  google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size());
+  google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream);
+  // We know the type so we can render it. Recursively parse the nested stream
+  // using a nested ProtoStreamObjectSource using our nested type information.
+  ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type);
+
+  // We manually call start and end object here so we can inject the @type.
+  ow->StartObject(field_name);
+  ow->RenderString("@type", type_url);
+  util::Status result =
+      nested_os.WriteMessage(nested_os.type_, "value", 0, false, ow);
+  ow->EndObject();
+  return result;
+}
+
+Status ProtoStreamObjectSource::RenderFieldMask(
+    const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+    StringPiece field_name, ObjectWriter* ow) {
+  string combined;
+  uint32 buffer32;
+  uint32 paths_field_tag = 0;
+  for (uint32 tag = os->stream_->ReadTag(); tag != 0;
+       tag = os->stream_->ReadTag()) {
+    if (paths_field_tag == 0) {
+      const google::protobuf::Field* field = os->FindAndVerifyField(type, tag);
+      if (field != NULL && field->number() == 1 &&
+          field->name() == "paths") {
+        paths_field_tag = tag;
+      }
+    }
+    if (paths_field_tag != tag) {
+      return util::Status(util::error::INTERNAL,
+                          "Invalid FieldMask, unexpected field.");
+    }
+    string str;
+    os->stream_->ReadVarint32(&buffer32);  // string size.
+    os->stream_->ReadString(&str, buffer32);
+    if (!combined.empty()) {
+      combined.append(",");
+    }
+    combined.append(ConvertFieldMaskPath(str, &ToCamelCase));
+  }
+  ow->RenderString(field_name, combined);
+  return Status::OK;
+}
+
+
+hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
+    ProtoStreamObjectSource::renderers_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
+
+void ProtoStreamObjectSource::InitRendererMap() {
+  renderers_ = new hash_map<string, ProtoStreamObjectSource::TypeRenderer>();
+  (*renderers_)["google.protobuf.Timestamp"] =
+      &ProtoStreamObjectSource::RenderTimestamp;
+  (*renderers_)["google.protobuf.Duration"] =
+      &ProtoStreamObjectSource::RenderDuration;
+  (*renderers_)["google.protobuf.DoubleValue"] =
+      &ProtoStreamObjectSource::RenderDouble;
+  (*renderers_)["google.protobuf.FloatValue"] =
+      &ProtoStreamObjectSource::RenderFloat;
+  (*renderers_)["google.protobuf.Int64Value"] =
+      &ProtoStreamObjectSource::RenderInt64;
+  (*renderers_)["google.protobuf.UInt64Value"] =
+      &ProtoStreamObjectSource::RenderUInt64;
+  (*renderers_)["google.protobuf.Int32Value"] =
+      &ProtoStreamObjectSource::RenderInt32;
+  (*renderers_)["google.protobuf.UInt32Value"] =
+      &ProtoStreamObjectSource::RenderUInt32;
+  (*renderers_)["google.protobuf.BoolValue"] =
+      &ProtoStreamObjectSource::RenderBool;
+  (*renderers_)["google.protobuf.StringValue"] =
+      &ProtoStreamObjectSource::RenderString;
+  (*renderers_)["google.protobuf.BytesValue"] =
+      &ProtoStreamObjectSource::RenderBytes;
+  (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
+  (*renderers_)["google.protobuf.Struct"] =
+      &ProtoStreamObjectSource::RenderStruct;
+  (*renderers_)["google.protobuf.Value"] =
+      &ProtoStreamObjectSource::RenderStructValue;
+  (*renderers_)["google.protobuf.ListValue"] =
+      &ProtoStreamObjectSource::RenderStructListValue;
+  (*renderers_)["google.protobuf.FieldMask"] =
+      &ProtoStreamObjectSource::RenderFieldMask;
+  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
+}
+
+void ProtoStreamObjectSource::DeleteRendererMap() {
+  delete ProtoStreamObjectSource::renderers_;
+  renderers_ = NULL;
+}
+
+// static
+ProtoStreamObjectSource::TypeRenderer*
+ProtoStreamObjectSource::FindTypeRenderer(const string& type_url) {
+  ::google::protobuf::GoogleOnceInit(&source_renderers_init_, &InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+Status ProtoStreamObjectSource::RenderField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Short-circuit message types as it tends to call WriteMessage recursively
+  // and ends up using a lot of stack space. Keep the stack usage of this
+  // message small in order to preserve stack space and not crash.
+  if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+    uint32 buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    // Get the nested message type for this field.
+    const google::protobuf::Type* type =
+        typeinfo_->GetTypeByTypeUrl(field->type_url());
+    if (type == NULL) {
+      return Status(util::error::INTERNAL,
+                    StrCat("Invalid configuration. Could not find the type: ",
+                           field->type_url()));
+    }
+
+    // Short-circuit any special type rendering to save call-stack space.
+    const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
+
+    bool use_type_renderer = type_renderer != NULL;
+
+    if (use_type_renderer) {
+      RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
+    } else {
+      RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name));
+      RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
+      --recursion_depth_;
+    }
+    if (!stream_->ConsumedEntireMessage()) {
+      return Status(util::error::INVALID_ARGUMENT,
+                    "Nested protocol message not parsed in its entirety.");
+    }
+    stream_->PopLimit(old_limit);
+  } else {
+    // Render all other non-message types.
+    return RenderNonMessageField(field, field_name, ow);
+  }
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderNonMessageField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Temporary buffers of different types.
+  uint32 buffer32;
+  uint64 buffer64;
+  string strbuffer;
+  switch (field->kind()) {
+    case google::protobuf::Field_Kind_TYPE_BOOL: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderBool(field_name, buffer64 != 0);
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT32: {
+      stream_->ReadVarint32(&buffer32);
+      ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT64: {
+      stream_->ReadVarint64(&buffer64);
+      ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED32: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED64: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FLOAT: {
+      stream_->ReadLittleEndian32(&buffer32);
+      ow->RenderFloat(field_name, bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+      stream_->ReadLittleEndian64(&buffer64);
+      ow->RenderDouble(field_name, bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      stream_->ReadVarint32(&buffer32);
+
+      // If the field represents an explicit NULL value, render null.
+      if (field->type_url() == kStructNullValueTypeUrl) {
+        ow->RenderNull(field_name);
+        break;
+      }
+
+      // Get the nested enum type for this field.
+      // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
+      // up.
+      const google::protobuf::Enum* en =
+          typeinfo_->GetEnumByTypeUrl(field->type_url());
+      // Lookup the name of the enum, and render that. Skips unknown enums.
+      if (en != NULL) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != NULL) {
+          if (use_lower_camel_for_enums_)
+            ow->RenderString(field_name, ToCamelCase(enum_value->name()));
+          else
+            ow->RenderString(field_name, enum_value->name());
+        }
+      } else {
+        GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url();
+      }
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_STRING: {
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderString(field_name, strbuffer);
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      stream_->ReadVarint32(&buffer32);  // bytes size.
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderBytes(field_name, strbuffer);
+      break;
+    }
+    default:
+      break;
+  }
+  return Status::OK;
+}
+
+// TODO(skarvaje): Fix this to avoid code duplication.
+const string ProtoStreamObjectSource::ReadFieldValueAsString(
+    const google::protobuf::Field& field) const {
+  string result;
+  switch (field.kind()) {
+    case google::protobuf::Field_Kind_TYPE_BOOL: {
+      uint64 buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = buffer64 != 0 ? "true" : "false";
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT32: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = SimpleItoa(bit_cast<int32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT64: {
+      uint64 buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = SimpleItoa(bit_cast<int64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT32: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = SimpleItoa(bit_cast<uint32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT64: {
+      uint64 buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = SimpleItoa(bit_cast<uint64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT32: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);
+      result = SimpleItoa(WireFormatLite::ZigZagDecode32(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT64: {
+      uint64 buffer64;
+      stream_->ReadVarint64(&buffer64);
+      result = SimpleItoa(WireFormatLite::ZigZagDecode64(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+      uint32 buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = SimpleItoa(bit_cast<int32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+      uint64 buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = SimpleItoa(bit_cast<int64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED32: {
+      uint32 buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = SimpleItoa(bit_cast<uint32>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED64: {
+      uint64 buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = SimpleItoa(bit_cast<uint64>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FLOAT: {
+      uint32 buffer32;
+      stream_->ReadLittleEndian32(&buffer32);
+      result = SimpleFtoa(bit_cast<float>(buffer32));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+      uint64 buffer64;
+      stream_->ReadLittleEndian64(&buffer64);
+      result = SimpleDtoa(bit_cast<double>(buffer64));
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);
+      // Get the nested enum type for this field.
+      // TODO(skarvaje): Avoid string manipulation. Find ways to speed this
+      // up.
+      const google::protobuf::Enum* en =
+          typeinfo_->GetEnumByTypeUrl(field.type_url());
+      // Lookup the name of the enum, and render that. Skips unknown enums.
+      if (en != NULL) {
+        const google::protobuf::EnumValue* enum_value =
+            FindEnumValueByNumber(*en, buffer32);
+        if (enum_value != NULL) {
+          result = enum_value->name();
+        }
+      }
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_STRING: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);  // string size.
+      stream_->ReadString(&result, buffer32);
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      uint32 buffer32;
+      stream_->ReadVarint32(&buffer32);  // bytes size.
+      stream_->ReadString(&result, buffer32);
+      break;
+    }
+    default:
+      break;
+  }
+  return result;
+}
+
+// Field is a map if it is a repeated message and it has an option "map_type".
+// TODO(skarvaje): Consider pre-computing the IsMap() into Field directly.
+bool ProtoStreamObjectSource::IsMap(
+    const google::protobuf::Field& field) const {
+  const google::protobuf::Type* field_type =
+      typeinfo_->GetTypeByTypeUrl(field.type_url());
+
+  // TODO(xiaofeng): Unify option names.
+  return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE &&
+         (GetBoolOptionOrDefault(field_type->options(),
+                                 "google.protobuf.MessageOptions.map_entry", false) ||
+          GetBoolOptionOrDefault(field_type->options(), "map_entry", false));
+}
+
+std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
+    const google::protobuf::Type& type) const {
+  uint64 seconds = 0;
+  uint32 nanos = 0;
+  uint32 tag = 0;
+  int64 signed_seconds = 0;
+  int32 signed_nanos = 0;
+
+  for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+    const google::protobuf::Field* field = FindAndVerifyField(type, tag);
+    if (field == NULL) {
+      WireFormat::SkipField(stream_, tag, NULL);
+      continue;
+    }
+    // 'seconds' has field number of 1 and 'nanos' has field number 2
+    // //google/protobuf/timestamp.proto & duration.proto
+    if (field->number() == 1) {
+      // read seconds
+      stream_->ReadVarint64(&seconds);
+      signed_seconds = bit_cast<int64>(seconds);
+    } else if (field->number() == 2) {
+      // read nanos
+      stream_->ReadVarint32(&nanos);
+      signed_nanos = bit_cast<int32>(nanos);
+    }
+  }
+  return std::pair<int64, int32>(signed_seconds, signed_nanos);
+}
+
+Status ProtoStreamObjectSource::IncrementRecursionDepth(
+    StringPiece type_name, StringPiece field_name) const {
+  if (++recursion_depth_ > max_recursion_depth_) {
+    return Status(
+        util::error::INVALID_ARGUMENT,
+        StrCat("Message too deep. Max recursion depth reached for type '",
+               type_name, "', field '", field_name, "'"));
+  }
+  return Status::OK;
+}
+
+namespace {
+// TODO(skarvaje): Speed this up by not doing a linear scan.
+const google::protobuf::Field* FindFieldByNumber(
+    const google::protobuf::Type& type, int number) {
+  for (int i = 0; i < type.fields_size(); ++i) {
+    if (type.fields(i).number() == number) {
+      return &type.fields(i);
+    }
+  }
+  return NULL;
+}
+
+// TODO(skarvaje): Replace FieldDescriptor by implementing IsTypePackable()
+// using tech Field.
+bool IsPackable(const google::protobuf::Field& field) {
+  return field.cardinality() ==
+             google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
+         google::protobuf::FieldDescriptor::IsTypePackable(
+             static_cast<google::protobuf::FieldDescriptor::Type>(field.kind()));
+}
+
+// TODO(skarvaje): Speed this up by not doing a linear scan.
+const google::protobuf::EnumValue* FindEnumValueByNumber(
+    const google::protobuf::Enum& tech_enum, int number) {
+  for (int i = 0; i < tech_enum.enumvalue_size(); ++i) {
+    const google::protobuf::EnumValue& ev = tech_enum.enumvalue(i);
+    if (ev.number() == number) {
+      return &ev;
+    }
+  }
+  return NULL;
+}
+
+// TODO(skarvaje): Look into optimizing this by not doing computation on
+// double.
+const string FormatNanos(uint32 nanos) {
+  const char* format =
+      (nanos % 1000 != 0) ? "%.9f" : (nanos % 1000000 != 0) ? "%.6f" : "%.3f";
+  string formatted =
+      StringPrintf(format, static_cast<double>(nanos) / kNanosPerSecond);
+  // remove the leading 0 before decimal.
+  return formatted.substr(1);
+}
+}  // namespace
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
new file mode 100644
index 0000000..d7d4347
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -0,0 +1,298 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
+
+#include <functional>
+#include <google/protobuf/stubs/hash.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/util/internal/object_source.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+class Field;
+class Type;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class TypeInfo;
+
+// An ObjectSource that can parse a stream of bytes as a protocol buffer.
+// Its WriteTo() method can be given an ObjectWriter.
+// This implementation uses a google.protobuf.Type for tag and name lookup.
+// The field names are converted into lower camel-case when writing to the
+// ObjectWriter.
+//
+// Sample usage: (suppose input is: string proto)
+//   ArrayInputStream arr_stream(proto.data(), proto.size());
+//   CodedInputStream in_stream(&arr_stream);
+//   ProtoStreamObjectSource os(&in_stream, /*ServiceTypeInfo*/ typeinfo,
+//                              <your message google::protobuf::Type>);
+//
+//   Status status = os.WriteTo(<some ObjectWriter>);
+class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
+ public:
+  ProtoStreamObjectSource(google::protobuf::io::CodedInputStream* stream,
+                          TypeResolver* type_resolver,
+                          const google::protobuf::Type& type);
+
+  virtual ~ProtoStreamObjectSource();
+
+  virtual util::Status NamedWriteTo(StringPiece name, ObjectWriter* ow) const;
+
+  // Sets whether or not to use lowerCamelCase casing for enum values. If set to
+  // false, enum values are output without any case conversions.
+  //
+  // For example, if we have an enum:
+  // enum Type {
+  //   ACTION_AND_ADVENTURE = 1;
+  // }
+  // Type type = 20;
+  //
+  // And this option is set to true. Then the rendered "type" field will have
+  // the string "actionAndAdventure".
+  // {
+  //   ...
+  //   "type": "actionAndAdventure",
+  //   ...
+  // }
+  //
+  // If set to false, the rendered "type" field will have the string
+  // "ACTION_AND_ADVENTURE".
+  // {
+  //   ...
+  //   "type": "ACTION_AND_ADVENTURE",
+  //   ...
+  // }
+  void set_use_lower_camel_for_enums(bool value) {
+    use_lower_camel_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.
+  void set_max_recursion_depth(int max_depth) {
+    max_recursion_depth_ = max_depth;
+  }
+
+ protected:
+  // Writes a proto2 Message to the ObjectWriter. When the given end_tag is
+  // found this method will complete, allowing it to be used for parsing both
+  // nested messages (end with 0) and nested groups (end with group end tag).
+  // The include_start_and_end parameter allows this method to be called when
+  // already inside of an object, and skip calling StartObject and EndObject.
+  virtual util::Status WriteMessage(const google::protobuf::Type& descriptor,
+                                      StringPiece name, const uint32 end_tag,
+                                      bool include_start_and_end,
+                                      ObjectWriter* ow) const;
+
+ private:
+  ProtoStreamObjectSource(google::protobuf::io::CodedInputStream* stream,
+                          const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type);
+  // Function that renders a well known type with a modified behavior.
+  typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*,
+                                         const google::protobuf::Type&,
+                                         StringPiece, ObjectWriter*);
+
+  // Looks up a field and verify its consistency with wire type in tag.
+  const google::protobuf::Field* FindAndVerifyField(
+      const google::protobuf::Type& type, uint32 tag) const;
+
+  // TODO(skarvaje): Mark these methods as non-const as they modify internal
+  // state (stream_).
+  //
+  // Renders a repeating field (packed or unpacked).
+  // Returns the next tag after reading all sequential repeating elements. The
+  // caller should use this tag before reading more tags from the stream.
+  util::StatusOr<uint32> RenderList(const google::protobuf::Field* field,
+                                      StringPiece name, uint32 list_tag,
+                                      ObjectWriter* ow) const;
+  // Renders a NWP map.
+  // Returns the next tag after reading all map entries. The caller should use
+  // this tag before reading more tags from the stream.
+  util::StatusOr<uint32> RenderMap(const google::protobuf::Field* field,
+                                     StringPiece name, uint32 list_tag,
+                                     ObjectWriter* ow) const;
+
+  // Renders a packed repeating field. A packed field is stored as:
+  // {tag length item1 item2 item3} instead of the less efficient
+  // {tag item1 tag item2 tag item3}.
+  util::Status RenderPacked(const google::protobuf::Field* field,
+                              ObjectWriter* ow) const;
+
+  // Renders a google.protobuf.Timestamp value to ObjectWriter
+  static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
+                                        const google::protobuf::Type& type,
+                                        StringPiece name, ObjectWriter* ow);
+
+  // Renders a google.protobuf.Duration value to ObjectWriter
+  static util::Status RenderDuration(const ProtoStreamObjectSource* os,
+                                       const google::protobuf::Type& type,
+                                       StringPiece name, ObjectWriter* ow);
+
+  // Following RenderTYPE functions render well known types in
+  // google/protobuf/wrappers.proto corresponding to TYPE.
+  static util::Status RenderDouble(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+  static util::Status RenderFloat(const ProtoStreamObjectSource* os,
+                                    const google::protobuf::Type& type,
+                                    StringPiece name, ObjectWriter* ow);
+  static util::Status RenderInt64(const ProtoStreamObjectSource* os,
+                                    const google::protobuf::Type& type,
+                                    StringPiece name, ObjectWriter* ow);
+  static util::Status RenderUInt64(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+  static util::Status RenderInt32(const ProtoStreamObjectSource* os,
+                                    const google::protobuf::Type& type,
+                                    StringPiece name, ObjectWriter* ow);
+  static util::Status RenderUInt32(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+  static util::Status RenderBool(const ProtoStreamObjectSource* os,
+                                   const google::protobuf::Type& type,
+                                   StringPiece name, ObjectWriter* ow);
+  static util::Status RenderString(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+  static util::Status RenderBytes(const ProtoStreamObjectSource* os,
+                                    const google::protobuf::Type& type,
+                                    StringPiece name, ObjectWriter* ow);
+
+  // Renders a google.protobuf.Struct to ObjectWriter.
+  static util::Status RenderStruct(const ProtoStreamObjectSource* os,
+                                     const google::protobuf::Type& type,
+                                     StringPiece name, ObjectWriter* ow);
+
+  // Helper to render google.protobuf.Struct's Value fields to ObjectWriter.
+  static util::Status RenderStructValue(const ProtoStreamObjectSource* os,
+                                          const google::protobuf::Type& type,
+                                          StringPiece name, ObjectWriter* ow);
+
+  // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
+  static util::Status RenderStructListValue(
+      const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
+      StringPiece name, ObjectWriter* ow);
+
+  // Render the "Any" type.
+  static util::Status RenderAny(const ProtoStreamObjectSource* os,
+                                  const google::protobuf::Type& type,
+                                  StringPiece name, ObjectWriter* ow);
+
+  // Render the "FieldMask" type.
+  static util::Status RenderFieldMask(const ProtoStreamObjectSource* os,
+                                        const google::protobuf::Type& type,
+                                        StringPiece name, ObjectWriter* ow);
+
+  static hash_map<string, TypeRenderer>* renderers_;
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const string& type_url);
+
+  // Renders a field value to the ObjectWriter.
+  util::Status RenderField(const google::protobuf::Field* field,
+                             StringPiece field_name, ObjectWriter* ow) const;
+
+  // Same as above but renders all non-message field types. Callers don't call
+  // this function directly. They just use RenderField.
+  util::Status RenderNonMessageField(const google::protobuf::Field* field,
+                                       StringPiece field_name,
+                                       ObjectWriter* ow) const;
+
+
+  // Reads field value according to Field spec in 'field' and returns the read
+  // value as string. This only works for primitive datatypes (no message
+  // types).
+  const string ReadFieldValueAsString(
+      const google::protobuf::Field& field) const;
+
+  // Utility function to detect proto maps. The 'field' MUST be repeated.
+  bool IsMap(const google::protobuf::Field& field) const;
+
+  // Utility to read int64 and int32 values from a message type in stream_.
+  // Used for reading google.protobuf.Timestamp and Duration messages.
+  std::pair<int64, int32> ReadSecondsAndNanos(
+      const google::protobuf::Type& type) const;
+
+  // Helper function to check recursion depth and increment it. It will return
+  // Status::OK if the current depth is allowed. Otherwise an error is returned.
+  // type_name and field_name are used for error reporting.
+  util::Status IncrementRecursionDepth(StringPiece type_name,
+                                         StringPiece field_name) const;
+
+  // Input stream to read from. Ownership rests with the caller.
+  google::protobuf::io::CodedInputStream* stream_;
+
+  // Type information for all the types used in the descriptor. Used to find
+  // google::protobuf::Type of nested messages/enums.
+  const TypeInfo* typeinfo_;
+  // Whether this class owns the typeinfo_ object. If true the typeinfo_ object
+  // should be deleted in the destructor.
+  bool own_typeinfo_;
+
+  // google::protobuf::Type of the message source.
+  const google::protobuf::Type& type_;
+
+
+  // Whether to render enums using lowerCamelCase. Defaults to false.
+  bool use_lower_camel_for_enums_;
+
+  // Tracks current recursion depth.
+  mutable int recursion_depth_;
+
+  // Maximum allowed recursion depth.
+  int max_recursion_depth_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
new file mode 100644
index 0000000..3f6fdf9
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -0,0 +1,1007 @@
+// 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.
+
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <sstream>
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/expecting_objectwriter.h>
+#include <google/protobuf/util/internal/testdata/books.pb.h>
+#include <google/protobuf/util/internal/testdata/field_mask.pb.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/testdata/anys.pb.h>
+#include <google/protobuf/util/internal/testdata/maps.pb.h>
+#include <google/protobuf/util/internal/testdata/struct.pb.h>
+#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h>
+#include <gtest/gtest.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::Descriptor;
+using google::protobuf::DescriptorPool;
+using google::protobuf::FileDescriptorProto;
+using google::protobuf::Message;
+using google::protobuf::io::ArrayInputStream;
+using google::protobuf::io::CodedInputStream;
+using util::Status;
+using google::protobuf::testing::Author;
+using google::protobuf::testing::BadAuthor;
+using google::protobuf::testing::BadNestedBook;
+using google::protobuf::testing::Book;
+using google::protobuf::testing::Cyclic;
+using google::protobuf::testing::Book_Label;
+using google::protobuf::testing::NestedBook;
+using google::protobuf::testing::PackedPrimitive;
+using google::protobuf::testing::Primitive;
+using google::protobuf::testing::more_author;
+using google::protobuf::testing::maps::MapOut;
+using google::protobuf::testing::maps::MapOutWireFormat;
+using google::protobuf::testing::timestampduration::TimestampDuration;
+using google::protobuf::testing::anys::AnyOut;
+using google::protobuf::testing::anys::AnyM;
+using google::protobuf::testing::FieldMaskTest;
+using google::protobuf::testing::NestedFieldMask;
+using google::protobuf::testing::structs::StructType;
+using ::testing::_;
+
+
+namespace {
+string GetTypeUrl(const Descriptor* descriptor) {
+  return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
+}
+}  // namespace
+
+class ProtostreamObjectSourceTest
+    : public ::testing::TestWithParam<testing::TypeInfoSource> {
+ protected:
+  ProtostreamObjectSourceTest()
+      : helper_(GetParam()),
+        mock_(),
+        ow_(&mock_),
+        use_lower_camel_for_enums_(false) {
+    helper_.ResetTypeInfo(Book::descriptor());
+  }
+
+  virtual ~ProtostreamObjectSourceTest() {}
+
+  void DoTest(const Message& msg, const Descriptor* descriptor) {
+    Status status = ExecuteTest(msg, descriptor);
+    EXPECT_EQ(Status::OK, status);
+  }
+
+  Status ExecuteTest(const Message& msg, const Descriptor* descriptor) {
+    ostringstream oss;
+    msg.SerializePartialToOstream(&oss);
+    string proto = oss.str();
+    ArrayInputStream arr_stream(proto.data(), proto.size());
+    CodedInputStream in_stream(&arr_stream);
+
+    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);
+    os->set_max_recursion_depth(64);
+    return os->WriteTo(&mock_);
+  }
+
+  void PrepareExpectingObjectWriterForRepeatedPrimitive() {
+    ow_.StartObject("")
+        ->StartList("repFix32")
+        ->RenderUint32("", bit_cast<uint32>(3201))
+        ->RenderUint32("", bit_cast<uint32>(0))
+        ->RenderUint32("", bit_cast<uint32>(3202))
+        ->EndList()
+        ->StartList("repU32")
+        ->RenderUint32("", bit_cast<uint32>(3203))
+        ->RenderUint32("", bit_cast<uint32>(0))
+        ->EndList()
+        ->StartList("repI32")
+        ->RenderInt32("", 0)
+        ->RenderInt32("", 3204)
+        ->RenderInt32("", 3205)
+        ->EndList()
+        ->StartList("repSf32")
+        ->RenderInt32("", 3206)
+        ->RenderInt32("", 0)
+        ->EndList()
+        ->StartList("repS32")
+        ->RenderInt32("", 0)
+        ->RenderInt32("", 3207)
+        ->RenderInt32("", 3208)
+        ->EndList()
+        ->StartList("repFix64")
+        ->RenderUint64("", bit_cast<uint64>(6401LL))
+        ->RenderUint64("", bit_cast<uint64>(0LL))
+        ->EndList()
+        ->StartList("repU64")
+        ->RenderUint64("", bit_cast<uint64>(0LL))
+        ->RenderUint64("", bit_cast<uint64>(6402LL))
+        ->RenderUint64("", bit_cast<uint64>(6403LL))
+        ->EndList()
+        ->StartList("repI64")
+        ->RenderInt64("", 6404L)
+        ->RenderInt64("", 0L)
+        ->EndList()
+        ->StartList("repSf64")
+        ->RenderInt64("", 0L)
+        ->RenderInt64("", 6405L)
+        ->RenderInt64("", 6406L)
+        ->EndList()
+        ->StartList("repS64")
+        ->RenderInt64("", 6407L)
+        ->RenderInt64("", 0L)
+        ->EndList()
+        ->StartList("repFloat")
+        ->RenderFloat("", 0.0f)
+        ->RenderFloat("", 32.1f)
+        ->RenderFloat("", 32.2f)
+        ->EndList()
+        ->StartList("repDouble")
+        ->RenderDouble("", 64.1L)
+        ->RenderDouble("", 0.0L)
+        ->EndList()
+        ->StartList("repBool")
+        ->RenderBool("", true)
+        ->RenderBool("", false)
+        ->EndList()
+        ->EndObject();
+  }
+
+  Primitive PrepareRepeatedPrimitive() {
+    Primitive primitive;
+    primitive.add_rep_fix32(3201);
+    primitive.add_rep_fix32(0);
+    primitive.add_rep_fix32(3202);
+    primitive.add_rep_u32(3203);
+    primitive.add_rep_u32(0);
+    primitive.add_rep_i32(0);
+    primitive.add_rep_i32(3204);
+    primitive.add_rep_i32(3205);
+    primitive.add_rep_sf32(3206);
+    primitive.add_rep_sf32(0);
+    primitive.add_rep_s32(0);
+    primitive.add_rep_s32(3207);
+    primitive.add_rep_s32(3208);
+    primitive.add_rep_fix64(6401L);
+    primitive.add_rep_fix64(0L);
+    primitive.add_rep_u64(0L);
+    primitive.add_rep_u64(6402L);
+    primitive.add_rep_u64(6403L);
+    primitive.add_rep_i64(6404L);
+    primitive.add_rep_i64(0L);
+    primitive.add_rep_sf64(0L);
+    primitive.add_rep_sf64(6405L);
+    primitive.add_rep_sf64(6406L);
+    primitive.add_rep_s64(6407L);
+    primitive.add_rep_s64(0L);
+    primitive.add_rep_float(0.0f);
+    primitive.add_rep_float(32.1f);
+    primitive.add_rep_float(32.2f);
+    primitive.add_rep_double(64.1L);
+    primitive.add_rep_double(0.0);
+    primitive.add_rep_bool(true);
+    primitive.add_rep_bool(false);
+
+    PrepareExpectingObjectWriterForRepeatedPrimitive();
+    return primitive;
+  }
+
+  PackedPrimitive PreparePackedPrimitive() {
+    PackedPrimitive primitive;
+    primitive.add_rep_fix32(3201);
+    primitive.add_rep_fix32(0);
+    primitive.add_rep_fix32(3202);
+    primitive.add_rep_u32(3203);
+    primitive.add_rep_u32(0);
+    primitive.add_rep_i32(0);
+    primitive.add_rep_i32(3204);
+    primitive.add_rep_i32(3205);
+    primitive.add_rep_sf32(3206);
+    primitive.add_rep_sf32(0);
+    primitive.add_rep_s32(0);
+    primitive.add_rep_s32(3207);
+    primitive.add_rep_s32(3208);
+    primitive.add_rep_fix64(6401L);
+    primitive.add_rep_fix64(0L);
+    primitive.add_rep_u64(0L);
+    primitive.add_rep_u64(6402L);
+    primitive.add_rep_u64(6403L);
+    primitive.add_rep_i64(6404L);
+    primitive.add_rep_i64(0L);
+    primitive.add_rep_sf64(0L);
+    primitive.add_rep_sf64(6405L);
+    primitive.add_rep_sf64(6406L);
+    primitive.add_rep_s64(6407L);
+    primitive.add_rep_s64(0L);
+    primitive.add_rep_float(0.0f);
+    primitive.add_rep_float(32.1f);
+    primitive.add_rep_float(32.2f);
+    primitive.add_rep_double(64.1L);
+    primitive.add_rep_double(0.0);
+    primitive.add_rep_bool(true);
+    primitive.add_rep_bool(false);
+
+    PrepareExpectingObjectWriterForRepeatedPrimitive();
+    return primitive;
+  }
+
+  void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }
+
+  testing::TypeInfoTestHelper helper_;
+
+  ::testing::NiceMock<MockObjectWriter> mock_;
+  ExpectingObjectWriter ow_;
+  bool use_lower_camel_for_enums_;
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtostreamObjectSourceTest, EmptyMessage) {
+  Book empty;
+  ow_.StartObject("")->EndObject();
+  DoTest(empty, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, Primitives) {
+  Primitive primitive;
+  primitive.set_fix32(3201);
+  primitive.set_u32(3202);
+  primitive.set_i32(3203);
+  primitive.set_sf32(3204);
+  primitive.set_s32(3205);
+  primitive.set_fix64(6401L);
+  primitive.set_u64(6402L);
+  primitive.set_i64(6403L);
+  primitive.set_sf64(6404L);
+  primitive.set_s64(6405L);
+  primitive.set_str("String Value");
+  primitive.set_bytes("Some Bytes");
+  primitive.set_float_(32.1f);
+  primitive.set_double_(64.1L);
+  primitive.set_bool_(true);
+
+  ow_.StartObject("")
+      ->RenderUint32("fix32", bit_cast<uint32>(3201))
+      ->RenderUint32("u32", bit_cast<uint32>(3202))
+      ->RenderInt32("i32", 3203)
+      ->RenderInt32("sf32", 3204)
+      ->RenderInt32("s32", 3205)
+      ->RenderUint64("fix64", bit_cast<uint64>(6401LL))
+      ->RenderUint64("u64", bit_cast<uint64>(6402LL))
+      ->RenderInt64("i64", 6403L)
+      ->RenderInt64("sf64", 6404L)
+      ->RenderInt64("s64", 6405L)
+      ->RenderString("str", "String Value")
+      ->RenderBytes("bytes", "Some Bytes")
+      ->RenderFloat("float", 32.1f)
+      ->RenderDouble("double", 64.1L)
+      ->RenderBool("bool", true)
+      ->EndObject();
+  DoTest(primitive, Primitive::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) {
+  Primitive primitive = PrepareRepeatedPrimitive();
+  primitive.add_rep_str("String One");
+  primitive.add_rep_str("String Two");
+  primitive.add_rep_bytes("Some Bytes");
+
+  ow_.StartList("repStr")
+      ->RenderString("", "String One")
+      ->RenderString("", "String Two")
+      ->EndList()
+      ->StartList("repBytes")
+      ->RenderBytes("", "Some Bytes")
+      ->EndList();
+  DoTest(primitive, Primitive::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
+  Author author;
+  author.set_id(12345);
+
+  ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
+  DoTest(author, Author::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
+  Author* author = new Author();
+  author->set_name("Tolstoy");
+  Book book;
+  book.set_title("My Book");
+  book.set_allocated_author(author);
+
+  ow_.StartObject("")
+      ->RenderString("title", "My Book")
+      ->StartObject("author")
+      ->RenderString("name", "Tolstoy")
+      ->EndObject()
+      ->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, RepeatingField) {
+  Author author;
+  author.set_alive(false);
+  author.set_name("john");
+  author.add_pseudonym("phil");
+  author.add_pseudonym("bob");
+
+  ow_.StartObject("")
+      ->RenderBool("alive", false)
+      ->RenderString("name", "john")
+      ->StartList("pseudonym")
+      ->RenderString("", "phil")
+      ->RenderString("", "bob")
+      ->EndList()
+      ->EndObject();
+  DoTest(author, Author::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) {
+  DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) {
+  // Protostream is packed, but parse with non-packed Primitive.
+  DoTest(PreparePackedPrimitive(), Primitive::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) {
+  // Protostream is not packed, but parse with PackedPrimitive.
+  DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, BadAuthor) {
+  Author author;
+  author.set_alive(false);
+  author.set_name("john");
+  author.set_id(1234L);
+  author.add_pseudonym("phil");
+  author.add_pseudonym("bob");
+
+  ow_.StartObject("")
+      ->StartList("alive")
+      ->RenderBool("", false)
+      ->EndList()
+      ->StartList("name")
+      ->RenderUint64("", static_cast<uint64>('j'))
+      ->RenderUint64("", static_cast<uint64>('o'))
+      ->RenderUint64("", static_cast<uint64>('h'))
+      ->RenderUint64("", static_cast<uint64>('n'))
+      ->EndList()
+      ->RenderString("pseudonym", "phil")
+      ->RenderString("pseudonym", "bob")
+      ->EndObject();
+  // Protostream created with Author, but parsed with BadAuthor.
+  DoTest(author, BadAuthor::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) {
+  Book* book = new Book();
+  book->set_length(250);
+  book->set_published(2014L);
+  NestedBook nested;
+  nested.set_allocated_book(book);
+
+  ow_.StartObject("")
+      ->StartList("book")
+      ->RenderUint32("", 24)  // tag for field length (3 << 3)
+      ->RenderUint32("", 250)
+      ->RenderUint32("", 32)  // tag for field published (4 << 3)
+      ->RenderUint32("", 2014)
+      ->EndList()
+      ->EndObject();
+  // Protostream created with NestedBook, but parsed with BadNestedBook.
+  DoTest(nested, BadNestedBook::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) {
+  BadNestedBook nested;
+  nested.add_book(1);
+  nested.add_book(2);
+  nested.add_book(3);
+  nested.add_book(4);
+  nested.add_book(5);
+  nested.add_book(6);
+  nested.add_book(7);
+
+  ow_.StartObject("")->StartObject("book")->EndObject()->EndObject();
+  // Protostream created with BadNestedBook, but parsed with NestedBook.
+  DoTest(nested, NestedBook::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest,
+       LongRepeatedListDoesNotBreakIntoMultipleJsonLists) {
+  Book book;
+
+  int repeat = 10000;
+  for (int i = 0; i < repeat; ++i) {
+    Book_Label* label = book.add_labels();
+    label->set_key(StrCat("i", i));
+    label->set_value(StrCat("v", i));
+  }
+
+  // Make sure StartList and EndList are called exactly once (see b/18227499 for
+  // problems when this doesn't happen)
+  EXPECT_CALL(mock_, StartList(_)).Times(1);
+  EXPECT_CALL(mock_, EndList()).Times(1);
+
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) {
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+
+  UseLowerCamelForEnums();
+
+  ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
+  Book book;
+  book.set_type(Book::ACTION_AND_ADVENTURE);
+  ow_.StartObject("")
+      ->RenderString("type", "ACTION_AND_ADVENTURE")
+      ->EndObject();
+  DoTest(book, Book::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) {
+  Cyclic cyclic;
+  cyclic.set_m_int(123);
+
+  Book* book = cyclic.mutable_m_book();
+  book->set_title("book title");
+  Cyclic* current = cyclic.mutable_m_cyclic();
+  Author* current_author = cyclic.add_m_author();
+  for (int i = 0; i < 63; ++i) {
+    Author* next = current_author->add_friend_();
+    next->set_id(i);
+    next->set_name(StrCat("author_name_", i));
+    next->set_alive(true);
+    current_author = next;
+  }
+
+  // Recursive message with depth (65) > max (max is 64).
+  for (int i = 0; i < 64; ++i) {
+    Cyclic* next = current->mutable_m_cyclic();
+    next->set_m_str(StrCat("count_", i));
+    current = next;
+  }
+
+  Status status = ExecuteTest(cyclic, Cyclic::descriptor());
+  EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
+}
+
+class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceMapsTest() {
+    helper_.ResetTypeInfo(MapOut::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceMapsTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+// Tests JSON map.
+//
+// This is the example expected output.
+// {
+//   "map1": {
+//     "key1": {
+//       "foo": "foovalue"
+//     },
+//     "key2": {
+//       "foo": "barvalue"
+//     }
+//   },
+//   "map2": {
+//     "nestedself": {
+//       "map1": {
+//         "nested_key1": {
+//           "foo": "nested_foo"
+//         }
+//       },
+//       "bar": "nested_bar_string"
+//     }
+//   },
+//   "map3": {
+//     "111": "one one one"
+//   },
+//   "bar": "top bar"
+// }
+TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) {
+  MapOut out;
+  (*out.mutable_map1())["key1"].set_foo("foovalue");
+  (*out.mutable_map1())["key2"].set_foo("barvalue");
+
+  MapOut* nested_value = &(*out.mutable_map2())["nestedself"];
+  (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo");
+  nested_value->set_bar("nested_bar_string");
+
+  (*out.mutable_map3())[111] = "one one one";
+
+  out.set_bar("top bar");
+
+  ow_.StartObject("")
+      ->StartObject("map1")
+      ->StartObject("key1")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->StartObject("key2")
+      ->RenderString("foo", "barvalue")
+      ->EndObject()
+      ->StartObject("map2")
+      ->StartObject("nestedself")
+      ->StartObject("map1")
+      ->StartObject("nested_key1")
+      ->RenderString("foo", "nested_foo")
+      ->EndObject()
+      ->EndObject()
+      ->RenderString("bar", "nested_bar_string")
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map3")
+      ->RenderString("111", "one one one")
+      ->EndObject()
+      ->EndObject()
+      ->RenderString("bar", "top bar")
+      ->EndObject();
+
+  DoTest(out, MapOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) {
+  // MapOutWireFormat has the same wire representation with MapOut but uses
+  // repeated message fields to represent map fields so we can intentionally
+  // leave out the key field or the value field of a map entry.
+  MapOutWireFormat out;
+  // Create some map entries without keys. They will be rendered with the
+  // default values ("" for strings, "0" for integers, etc.).
+  // {
+  //   "map1": {
+  //     "": {
+  //       "foo": "foovalue"
+  //     }
+  //   },
+  //   "map2": {
+  //     "": {
+  //       "map1": {
+  //         "nested_key1": {
+  //           "foo": "nested_foo"
+  //         }
+  //       }
+  //     }
+  //   },
+  //   "map3": {
+  //     "0": "one one one"
+  //   },
+  //   "map4": {
+  //     "false": "bool"
+  //   }
+  // }
+  out.add_map1()->mutable_value()->set_foo("foovalue");
+  MapOut* nested = out.add_map2()->mutable_value();
+  (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo");
+  out.add_map3()->set_value("one one one");
+  out.add_map4()->set_value("bool");
+
+  ow_.StartObject("")
+      ->StartObject("map1")
+      ->StartObject("")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map2")
+      ->StartObject("")
+      ->StartObject("map1")
+      ->StartObject("nested_key1")
+      ->RenderString("foo", "nested_foo")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->StartObject("map3")
+      ->RenderString("0", "one one one")
+      ->EndObject()
+      ->StartObject("map4")
+      ->RenderString("false", "bool")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, MapOut::descriptor());
+}
+
+class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceAnysTest() {
+    helper_.ResetTypeInfo(AnyOut::descriptor(),
+                          google::protobuf::Any::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceAnysTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+// Tests JSON any support.
+//
+// This is the example expected output.
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.testing.anys.AnyM"
+//     "foo": "foovalue"
+//   }
+// }
+TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  AnyM m;
+  m.set_foo("foovalue");
+  any->PackFrom(m);
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type",
+                     "type.googleapis.com/google.protobuf.testing.anys.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any nested_any;
+  nested_any.set_type_url(
+      "type.googleapis.com/google.protobuf.testing.anys.AnyM");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  nested_any.set_value(m.SerializeAsString());
+
+  any->set_value(nested_any.SerializeAsString());
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type",
+                     "type.googleapis.com/google.protobuf.testing.anys.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any nested_any;
+  nested_any.set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any second_nested_any;
+  second_nested_any.set_type_url(
+      "type.googleapis.com/google.protobuf.testing.anys.AnyM");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  second_nested_any.set_value(m.SerializeAsString());
+  nested_any.set_value(second_nested_any.SerializeAsString());
+  any->set_value(nested_any.SerializeAsString());
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type",
+                     "type.googleapis.com/google.protobuf.testing.anys.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) {
+  AnyOut out;
+  out.mutable_any();
+
+  ow_.StartObject("")->StartObject("any")->EndObject()->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) {
+  AnyOut out;
+  out.mutable_any()->set_type_url("foo.googleapis.com/my.Type");
+
+  ow_.StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "foo.googleapis.com/my.Type")
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, AnyOut::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  AnyM m;
+  m.set_foo("foovalue");
+  any->set_value(m.SerializeAsString());
+
+  // We start the "AnyOut" part and then fail when we hit the Any object.
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("foo.googleapis.com/my.own.Type");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  any->set_value(m.SerializeAsString());
+
+  // We start the "AnyOut" part and then fail when we hit the Any object.
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("type.googleapis.com/unknown.Type");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  any->set_value(m.SerializeAsString());
+
+  // We start the "AnyOut" part and then fail when we hit the Any object.
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, AnyOut::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceStructTest() {
+    helper_.ResetTypeInfo(StructType::descriptor(),
+                          google::protobuf::Struct::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceStructTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+// Tests struct
+//
+//  "object": {
+//    "k1": 123,
+//    "k2": true
+//  }
+TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) {
+  StructType out;
+  google::protobuf::Struct* s = out.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_number_value(123);
+  s->mutable_fields()->operator[]("k2").set_bool_value(true);
+
+  ow_.StartObject("")
+      ->StartObject("object")
+      ->RenderDouble("k1", 123)
+      ->RenderBool("k2", true)
+      ->EndObject()
+      ->EndObject();
+
+  DoTest(out, StructType::descriptor());
+}
+
+TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) {
+  StructType out;
+  google::protobuf::Struct* s = out.mutable_object();
+  s->mutable_fields()->operator[]("k1");
+
+  ow_.StartObject("")->StartObject("object")->EndObject()->EndObject();
+
+  DoTest(out, StructType::descriptor());
+}
+
+class ProtostreamObjectSourceFieldMaskTest
+    : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceFieldMaskTest() {
+    helper_.ResetTypeInfo(FieldMaskTest::descriptor(),
+                          google::protobuf::FieldMask::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceFieldMaskTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
+  FieldMaskTest out;
+  out.set_id("1");
+  out.mutable_single_mask()->add_paths("path1");
+  out.mutable_single_mask()->add_paths("snake_case_path2");
+  ::google::protobuf::FieldMask* mask = out.add_repeated_mask();
+  mask->add_paths("path3");
+  mask = out.add_repeated_mask();
+  mask->add_paths("snake_case_path4");
+  mask->add_paths("path5");
+  NestedFieldMask* nested = out.add_nested_mask();
+  nested->set_data("data");
+  nested->mutable_single_mask()->add_paths("nested.path1");
+  nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2");
+  mask = nested->add_repeated_mask();
+  mask->add_paths("nested_field.path3");
+  mask->add_paths("nested.snake_case_path4");
+  mask = nested->add_repeated_mask();
+  mask->add_paths("nested.path5");
+  mask = nested->add_repeated_mask();
+  mask->add_paths(
+      "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case."
+      "map_field[\"map_key_sho\\\"uld_be_ignored\"]");
+
+  ow_.StartObject("")
+      ->RenderString("id", "1")
+      ->RenderString("singleMask", "path1,snakeCasePath2")
+      ->StartList("repeatedMask")
+      ->RenderString("", "path3")
+      ->RenderString("", "snakeCasePath4,path5")
+      ->EndList()
+      ->StartList("nestedMask")
+      ->StartObject("")
+      ->RenderString("data", "data")
+      ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2")
+      ->StartList("repeatedMask")
+      ->RenderString("", "nestedField.path3,nested.snakeCasePath4")
+      ->RenderString("", "nested.path5")
+      ->RenderString("",
+                     "snakeCase.mapField[\"map_key_should_be_ignored\"]."
+                     "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_"
+                     "ignored\"]")
+      ->EndList()
+      ->EndObject()
+      ->EndList()
+      ->EndObject();
+
+  DoTest(out, FieldMaskTest::descriptor());
+}
+
+class ProtostreamObjectSourceTimestampTest
+    : public ProtostreamObjectSourceTest {
+ protected:
+  ProtostreamObjectSourceTimestampTest() {
+    helper_.ResetTypeInfo(TimestampDuration::descriptor());
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtostreamObjectSourceTimestampTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
+  TimestampDuration out;
+  google::protobuf::Timestamp* ts = out.mutable_ts();
+  // Min allowed seconds - 1
+  ts->set_seconds(kTimestampMinSeconds - 1);
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) {
+  TimestampDuration out;
+  google::protobuf::Timestamp* ts = out.mutable_ts();
+  // Max allowed seconds + 1
+  ts->set_seconds(kTimestampMaxSeconds + 1);
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) {
+  TimestampDuration out;
+  google::protobuf::Duration* dur = out.mutable_dur();
+  // Min allowed seconds - 1
+  dur->set_seconds(kDurationMinSeconds - 1);
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) {
+  TimestampDuration out;
+  google::protobuf::Duration* dur = out.mutable_dur();
+  // Min allowed seconds + 1
+  dur->set_seconds(kDurationMaxSeconds + 1);
+  ow_.StartObject("");
+
+  Status status = ExecuteTest(out, TimestampDuration::descriptor());
+  EXPECT_EQ(util::error::INTERNAL, status.error_code());
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
new file mode 100644
index 0000000..97a7909
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -0,0 +1,1206 @@
+// 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.
+
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::internal::WireFormatLite;
+using util::error::INVALID_ARGUMENT;
+using util::Status;
+using util::StatusOr;
+
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    TypeResolver* type_resolver, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options)
+    : ProtoWriter(type_resolver, type, output, listener),
+      master_type_(type),
+      current_(NULL),
+      options_(options) {}
+
+ProtoStreamObjectWriter::ProtoStreamObjectWriter(
+    const TypeInfo* typeinfo, const google::protobuf::Type& type,
+    strings::ByteSink* output, ErrorListener* listener)
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(NULL),
+      options_(ProtoStreamObjectWriter::Options::Defaults()) {}
+
+ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
+  if (current_ == NULL) return;
+  // Cleanup explicitly in order to avoid destructor stack overflow when input
+  // is deeply nested.
+  // Cast to BaseElement to avoid doing additional checks (like missing fields)
+  // during pop().
+  google::protobuf::scoped_ptr<BaseElement> element(
+      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
+  while (element != NULL) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+// Utility method to split a string representation of Timestamp or Duration and
+// return the parts.
+void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
+                          StringPiece* nanos) {
+  size_t idx = input.rfind('.');
+  if (idx != string::npos) {
+    *seconds = input.substr(0, idx);
+    *nanos = input.substr(idx + 1);
+  } else {
+    *seconds = input;
+    *nanos = StringPiece();
+  }
+}
+
+Status GetNanosFromStringPiece(StringPiece s_nanos,
+                               const char* parse_failure_message,
+                               const char* exceeded_limit_message,
+                               int32* nanos) {
+  *nanos = 0;
+
+  // Count the number of leading 0s and consume them.
+  int num_leading_zeros = 0;
+  while (s_nanos.Consume("0")) {
+    num_leading_zeros++;
+  }
+  int32 i_nanos = 0;
+  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
+  // "0." + s_nanos.ToString() seconds. An int32 is used for the
+  // conversion to 'nanos', rather than a double, so that there is no
+  // loss of precision.
+  if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
+    return Status(INVALID_ARGUMENT, parse_failure_message);
+  }
+  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
+    return Status(INVALID_ARGUMENT, exceeded_limit_message);
+  }
+  // s_nanos should only have digits. No whitespace.
+  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
+    return Status(INVALID_ARGUMENT, parse_failure_message);
+  }
+
+  if (i_nanos > 0) {
+    // 'scale' is the number of digits to the right of the decimal
+    // point in "0." + s_nanos.ToString()
+    int32 scale = num_leading_zeros + s_nanos.size();
+    // 'conversion' converts i_nanos into nanoseconds.
+    // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
+    // For efficiency, we precompute the conversion factor.
+    int32 conversion = 0;
+    switch (scale) {
+      case 1:
+        conversion = 100000000;
+        break;
+      case 2:
+        conversion = 10000000;
+        break;
+      case 3:
+        conversion = 1000000;
+        break;
+      case 4:
+        conversion = 100000;
+        break;
+      case 5:
+        conversion = 10000;
+        break;
+      case 6:
+        conversion = 1000;
+        break;
+      case 7:
+        conversion = 100;
+        break;
+      case 8:
+        conversion = 10;
+        break;
+      case 9:
+        conversion = 1;
+        break;
+      default:
+        return Status(INVALID_ARGUMENT, exceeded_limit_message);
+    }
+    *nanos = i_nanos * conversion;
+  }
+
+  return Status::OK;
+}
+
+}  // namespace
+
+ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
+    : parent_(parent),
+      ow_(),
+      invalid_(false),
+      data_(),
+      output_(&data_),
+      depth_(0),
+      is_well_known_type_(false),
+      well_known_type_render_(NULL) {}
+
+ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
+
+void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
+  ++depth_;
+  // If an object writer is absent, that means we have not called StartAny()
+  // before reaching here. This is an invalid state. StartAny() gets called
+  // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece).
+  if (ow_ == NULL) {
+    // Make sure we are not already in an invalid state. This avoids making
+    // multiple unnecessary InvalidValue calls.
+    if (!invalid_) {
+      parent_->InvalidValue("Any",
+                            StrCat("Missing or invalid @type for any field in ",
+                                   parent_->master_type_.name()));
+      invalid_ = true;
+    }
+  } else if (is_well_known_type_ && depth_ == 1) {
+    // For well-known types, the only other field besides "@type" should be a
+    // "value" field.
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartObject("");
+  } else {
+    // Forward the call to the child writer if:
+    //   1. the type is not a well-known type.
+    //   2. or, we are in a nested Any, Struct, or Value object.
+    ow_->StartObject(name);
+  }
+}
+
+bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
+  --depth_;
+  // As long as depth_ >= 0, we know we haven't reached the end of Any.
+  // Propagate these EndObject() calls to the contained ow_. For regular
+  // message types, we propagate the end of Any as well.
+  if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) {
+    ow_->EndObject();
+  }
+  // A negative depth_ implies that we have reached the end of Any
+  // object. Now we write out its contents.
+  if (depth_ < 0) {
+    WriteAny();
+    return false;
+  }
+  return true;
+}
+
+void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
+  ++depth_;
+  // We expect ow_ to be present as this call only makes sense inside an Any.
+  if (ow_ == NULL) {
+    if (!invalid_) {
+      parent_->InvalidValue("Any",
+                            StrCat("Missing or invalid @type for any field in ",
+                                   parent_->master_type_.name()));
+      invalid_ = true;
+    }
+  } else if (is_well_known_type_ && depth_ == 1) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    ow_->StartList("");
+  } else {
+    ow_->StartList(name);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::EndList() {
+  --depth_;
+  if (depth_ < 0) {
+    GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
+    depth_ = 0;
+  }
+  // We don't write an error on the close, only on the open
+  if (ow_ != NULL) {
+    ow_->EndList();
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& value) {
+  // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
+  // should go to the contained ow_ as they indicate nested Anys.
+  if (depth_ == 0 && ow_ == NULL && name == "@type") {
+    StartAny(value);
+  } else if (ow_ == NULL) {
+    if (!invalid_) {
+      parent_->InvalidValue("Any",
+                            StrCat("Missing or invalid @type for any field in ",
+                                   parent_->master_type_.name()));
+      invalid_ = true;
+    }
+  } else if (depth_ == 0 && is_well_known_type_) {
+    if (name != "value" && !invalid_) {
+      parent_->InvalidValue("Any",
+                            "Expect a \"value\" field for well-known types.");
+      invalid_ = true;
+    }
+    if (well_known_type_render_ == NULL) {
+      // Only Any and Struct don't have a special type render but both of
+      // them expect a JSON object (i.e., a StartObject() call).
+      if (!invalid_) {
+        parent_->InvalidValue("Any", "Expect a JSON object.");
+        invalid_ = true;
+      }
+    } else {
+      ow_->ProtoWriter::StartObject("");
+      Status status = (*well_known_type_render_)(ow_.get(), value);
+      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
+      ow_->ProtoWriter::EndObject();
+    }
+  } else {
+    ow_->RenderDataPiece(name, value);
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
+  // Figure out the type url. This is a copy-paste from WriteString but we also
+  // need the value, so we can't just call through to that.
+  if (value.type() == DataPiece::TYPE_STRING) {
+    type_url_ = value.str().ToString();
+  } else {
+    StatusOr<string> s = value.ToString();
+    if (!s.ok()) {
+      parent_->InvalidValue("String", s.status().error_message());
+      invalid_ = true;
+      return;
+    }
+    type_url_ = s.ValueOrDie();
+  }
+  // Resolve the type url, and report an error if we failed to resolve it.
+  StatusOr<const google::protobuf::Type*> resolved_type =
+      parent_->typeinfo()->ResolveTypeUrl(type_url_);
+  if (!resolved_type.ok()) {
+    parent_->InvalidValue("Any", resolved_type.status().error_message());
+    invalid_ = true;
+    return;
+  }
+  // At this point, type is never null.
+  const google::protobuf::Type* type = resolved_type.ValueOrDie();
+
+  well_known_type_render_ = FindTypeRenderer(type_url_);
+  if (well_known_type_render_ != NULL ||
+      // Explicitly list Any and Struct here because they don't have a
+      // custom renderer.
+      type->name() == kAnyType || type->name() == kStructType) {
+    is_well_known_type_ = true;
+  }
+
+  // Create our object writer and initialize it with the first StartObject
+  // call.
+  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+                                        parent_->listener()));
+
+  // Don't call StartObject() for well-known types yet. Depending on the
+  // type of actual data, we may not need to call StartObject(). For
+  // example:
+  // {
+  //   "@type": "type.googleapis.com/google.protobuf.Value",
+  //   "value": [1, 2, 3],
+  // }
+  // With the above JSON representation, we will only call StartList() on the
+  // contained ow_.
+  if (!is_well_known_type_) {
+    ow_->StartObject("");
+  }
+}
+
+void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
+  if (ow_ == NULL) {
+    // If we had no object writer, we never got any content, so just return
+    // immediately, which is equivalent to writing an empty Any.
+    return;
+  }
+  // Render the type_url and value fields directly to the stream.
+  // type_url has tag 1 and value has tag 2.
+  WireFormatLite::WriteString(1, type_url_, parent_->stream());
+  if (!data_.empty()) {
+    WireFormatLite::WriteBytes(2, data_, parent_->stream());
+  }
+}
+
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
+    : BaseElement(NULL),
+      ow_(enclosing),
+      any_(),
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type_ == ANY) {
+    any_.reset(new AnyWriter(ow_));
+  }
+}
+
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
+    : BaseElement(parent),
+      ow_(this->parent()->ow_),
+      any_(),
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type == ANY) {
+    any_.reset(new AnyWriter(ow_));
+  }
+}
+
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
+    StringPiece map_key) {
+  return InsertIfNotPresent(&map_keys_, map_key.ToString());
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
+    StringPiece name) {
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Starting the root message. Create the root Item and return.
+  // ANY message type does not need special handling, just set the ItemType
+  // to ANY.
+  if (current_ == NULL) {
+    ProtoWriter::StartObject(name);
+    current_.reset(new Item(
+        this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
+        false, false));
+
+    // If master type is a special type that needs extra values to be written to
+    // stream, we write those values.
+    if (master_type_.name() == kStructType) {
+      // Struct has a map<string, Value> field called "fields".
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      // "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructValueType) {
+      // We got a StartObject call with google.protobuf.Value field. The only
+      // object within that type is a struct type. So start a struct.
+      //
+      // The struct field in Value type is named "struct_value"
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      // Also start the map field "fields" within the struct.
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      InvalidValue(kStructListValueType,
+                   "Cannot start root message with ListValue.");
+    }
+
+    return this;
+  }
+
+  // Send all ANY events to AnyWriter.
+  if (current_->IsAny()) {
+    current_->any()->StartObject(name);
+    return this;
+  }
+
+  // If we are within a map, we render name as keys and send StartObject to the
+  // value field.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Map is a repeated field of message type with a "key" and a "value" field.
+    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
+    // message MapFieldEntry {
+    //   key_type key = 1;
+    //   value_type value = 2;
+    // }
+    //
+    // repeated MapFieldEntry map_field = N;
+    //
+    // That means, we render the following element within a list (hence no
+    // name):
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid so far after starting map fields.
+    if (invalid_depth() > 0) return this;
+
+    // If top of stack is g.p.Struct type, start the struct the map field within
+    // it.
+    if (element() != NULL && IsStruct(*element()->parent_field())) {
+      // Render "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    // If top of stack is g.p.Value type, start the Struct within it.
+    if (element() != NULL && IsStructValue(*element()->parent_field())) {
+      // Render
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+    }
+    return this;
+  }
+
+  const google::protobuf::Field* field = BeginNamed(name, false);
+  if (field == NULL) return this;
+
+  if (IsStruct(*field)) {
+    // Start a struct object.
+    // Render
+    // "<name>": {
+    //   "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
+  }
+
+  if (IsStructValue(*field)) {
+    // We got a StartObject call with google.protobuf.Value field.  The only
+    // object within that type is a struct type. So start a struct.
+    // Render
+    // "<name>": {
+    //   "struct_value": {
+    //     "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("struct_value", Item::MESSAGE, true, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    // Begin a map. A map is triggered by a StartObject() call if the current
+    // field has a map type.
+    // A map type is always repeated, hence set is_list to true.
+    // Render
+    // "<name>": [
+    Push(name, Item::MAP, false, true);
+    return this;
+  }
+
+  // A regular message type. Pass it directly to ProtoWriter.
+  // Render
+  // "<name>": {
+  Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
+  return this;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
+    return this;
+  }
+
+  if (current_ == NULL) return this;
+
+  if (current_->IsAny()) {
+    if (current_->any()->EndObject()) return this;
+  }
+
+  Pop();
+
+  return this;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Since we cannot have a top-level repeated item in protobuf, the only way
+  // this is valid is if we start a special type google.protobuf.ListValue or
+  // google.protobuf.Value.
+  if (current_ == NULL) {
+    if (!name.empty()) {
+      InvalidName(name, "Root element should not be named.");
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // If master type is a special type that needs extra values to be written to
+    // stream, we write those values.
+    if (master_type_.name() == kStructValueType) {
+      // We got a StartList with google.protobuf.Value master type. This means
+      // we have to start the "list_value" within google.protobuf.Value.
+      //
+      // See
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      //
+      // Render
+      // "<name>": {
+      //   "list_value": {
+      //     "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("list_value", Item::MESSAGE, true, false);
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      // We got a StartList with google.protobuf.ListValue master type. This
+      // means we have to start the "values" within google.protobuf.ListValue.
+      //
+      // Render
+      // "<name>": {
+      //   "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    // Send the event to ProtoWriter so proper errors can be reported.
+    //
+    // Render a regular list:
+    // "<name>": [
+    ProtoWriter::StartList(name);
+    current_.reset(new Item(this, Item::MESSAGE, false, true));
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->StartList(name);
+    return this;
+  }
+
+  // If the top of stack is a map, we are starting a list value within a map.
+  // Since map does not allow repeated values, this can only happen when the map
+  // value is of a special type that renders a list in JSON.  These can be one
+  // of 3 cases:
+  // i. We are rendering a list value within google.protobuf.Struct
+  // ii. We are rendering a list value within google.protobuf.Value
+  // iii. We are rendering a list value with type google.protobuf.ListValue.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Start the repeated map entry object.
+    // Render
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid after pushing all above items.
+    if (invalid_depth() > 0) return this;
+
+    // case i and ii above. Start "list_value" field within g.p.Value
+    if (element() != NULL && element()->parent_field() != NULL) {
+      // Render
+      // "list_value": {
+      //   "values": [  // Start this list
+      if (IsStructValue(*element()->parent_field())) {
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+
+      // Render
+      // "values": [
+      if (IsStructListValue(*element()->parent_field())) {
+        // case iii above. Bind directly to g.p.ListValue
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Report an error.
+    InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
+                               "') within a map."));
+    return this;
+  }
+
+  // When name is empty and stack is not empty, we are rendering an item within
+  // a list.
+  if (name.empty()) {
+    if (element() != NULL && element()->parent_field() != NULL) {
+      if (IsStructValue(*element()->parent_field())) {
+        // Since it is g.p.Value, we bind directly to the list_value.
+        // Render
+        // {  // g.p.Value item within the list
+        //   "list_value": {
+        //     "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+
+      if (IsStructListValue(*element()->parent_field())) {
+        // Since it is g.p.ListValue, we bind to it directly.
+        // Render
+        // {  // g.p.ListValue item within the list
+        //   "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Pass the event to underlying ProtoWriter.
+    Push(name, Item::MESSAGE, false, true);
+    return this;
+  }
+
+  // name is not empty
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  if (IsStructValue(*field)) {
+    // If g.p.Value is repeated, start that list. Otherwise, start the
+    // "list_value" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "list_value" field.
+    // Render
+    // "<name>": {
+    //   "list_value": {
+    //     "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("list_value", Item::MESSAGE, true, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  if (IsStructListValue(*field)) {
+    // If g.p.ListValue is repeated, start that list. Otherwise, start the
+    // "values" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "values" field within g.p.ListValue.
+    // Render
+    // "<name>": {
+    //   "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  // If we are here, the field should be repeated. Report an error otherwise.
+  if (!IsRepeated(*field)) {
+    IncrementInvalidDepth();
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    InvalidValue("Map",
+                 StrCat("Cannot bind a list to map for field '", name, "'."));
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Pass the event to ProtoWriter.
+  // Render
+  // "<name>": [
+  Push(name, Item::MESSAGE, false, true);
+  return this;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
+    return this;
+  }
+
+  if (current_ == NULL) return this;
+
+  if (current_->IsAny()) {
+    current_->any()->EndList();
+    return this;
+  }
+
+  Pop();
+  return this;
+}
+
+Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  string struct_field_name;
+  switch (data.type()) {
+    // Our JSON parser parses numbers as either int64, uint64, or double.
+    case DataPiece::TYPE_INT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        StatusOr<int64> int_value = data.ToInt64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
+          return Status::OK;
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_UINT64: {
+      // If the option to treat integers as strings is set, then render them as
+      // strings. Otherwise, fallback to rendering them as double.
+      if (ow->options_.struct_integers_as_strings) {
+        StatusOr<uint64> int_value = data.ToUint64();
+        if (int_value.ok()) {
+          ow->ProtoWriter::RenderDataPiece(
+              "string_value",
+              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
+          return Status::OK;
+        }
+      }
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_DOUBLE: {
+      struct_field_name = "number_value";
+      break;
+    }
+    case DataPiece::TYPE_STRING: {
+      struct_field_name = "string_value";
+      break;
+    }
+    case DataPiece::TYPE_BOOL: {
+      struct_field_name = "bool_value";
+      break;
+    }
+    case DataPiece::TYPE_NULL: {
+      struct_field_name = "null_value";
+      break;
+    }
+    default: {
+      return Status(INVALID_ARGUMENT,
+                    "Invalid struct data type. Only number, string, boolean or "
+                    "null values are supported.");
+    }
+  }
+  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
+  return Status::OK;
+}
+
+Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return Status(INVALID_ARGUMENT,
+                  StrCat("Invalid data type for timestamp, value is ",
+                         data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  int64 seconds;
+  int32 nanos;
+  if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
+                                               &nanos)) {
+    return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value));
+  }
+
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status::OK;
+}
+
+static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
+                                                StringPiece path) {
+  ow->ProtoWriter::RenderDataPiece(
+      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                                const DataPiece& data) {
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return Status(INVALID_ARGUMENT,
+                  StrCat("Invalid data type for field mask, value is ",
+                         data.ValueAsStringOrDefault("")));
+  }
+
+// TODO(tsun): figure out how to do proto descriptor based snake case
+// conversions as much as possible. Because ToSnakeCase sometimes returns the
+// wrong value.
+  google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
+      ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
+  return DecodeCompactFieldMaskPaths(data.str(), callback.get());
+}
+
+Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
+                                               const DataPiece& data) {
+  if (data.type() != DataPiece::TYPE_STRING) {
+    return Status(INVALID_ARGUMENT,
+                  StrCat("Invalid data type for duration, value is ",
+                         data.ValueAsStringOrDefault("")));
+  }
+
+  StringPiece value(data.str());
+
+  if (!value.ends_with("s")) {
+    return Status(INVALID_ARGUMENT,
+                  "Illegal duration format; duration must end with 's'");
+  }
+  value = value.substr(0, value.size() - 1);
+  int sign = 1;
+  if (value.starts_with("-")) {
+    sign = -1;
+    value = value.substr(1);
+  }
+
+  StringPiece s_secs, s_nanos;
+  SplitSecondsAndNanos(value, &s_secs, &s_nanos);
+  uint64 unsigned_seconds;
+  if (!safe_strtou64(s_secs, &unsigned_seconds)) {
+    return Status(INVALID_ARGUMENT,
+                  "Invalid duration format, failed to parse seconds");
+  }
+
+  int32 nanos = 0;
+  Status nanos_status = GetNanosFromStringPiece(
+      s_nanos, "Invalid duration format, failed to parse nano seconds",
+      "Duration value exceeds limits", &nanos);
+  if (!nanos_status.ok()) {
+    return nanos_status;
+  }
+  nanos = sign * nanos;
+
+  int64 seconds = sign * unsigned_seconds;
+  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
+      nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
+  }
+
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
+  return Status::OK;
+}
+
+Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                                  const DataPiece& data) {
+  ow->ProtoWriter::RenderDataPiece("value", data);
+  return Status::OK;
+}
+
+ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
+    StringPiece name, const DataPiece& data) {
+  Status status;
+  if (invalid_depth() > 0) return this;
+
+  if (current_ == NULL) {
+    const TypeRenderer* type_renderer =
+        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
+    if (type_renderer == NULL) {
+      InvalidName(name, "Root element must be a message.");
+      return this;
+    }
+    // Render the special type.
+    // "<name>": {
+    //   ... Render special type ...
+    // }
+    ProtoWriter::StartObject(name);
+    status = (*type_renderer)(this, data);
+    if (!status.ok()) {
+      InvalidValue(master_type_.name(),
+                   StrCat("Field '", name, "', ", status.error_message()));
+    }
+    ProtoWriter::EndObject();
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->RenderDataPiece(name, data);
+    return this;
+  }
+
+  const google::protobuf::Field* field = NULL;
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) return this;
+
+    // Render an item in repeated map list.
+    // { "key": "<name>", "value":
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key",
+                                 DataPiece(name, use_strict_base64_decoding()));
+    field = Lookup("value");
+    if (field == NULL) {
+      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
+      return this;
+    }
+
+    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+    if (type_renderer != NULL) {
+      // Map's value type is a special type. Render it like a message:
+      // "value": {
+      //   ... Render special type ...
+      // }
+      Push("value", Item::MESSAGE, true, false);
+      status = (*type_renderer)(this, data);
+      if (!status.ok()) {
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.error_message()));
+      }
+      Pop();
+      return this;
+    }
+
+    // If we are rendering explicit null values and the backend proto field is
+    // not of the google.protobuf.NullType type, we do nothing.
+    if (data.type() == DataPiece::TYPE_NULL &&
+        field->type_url() != kStructNullValueTypeUrl) {
+      Pop();
+      return this;
+    }
+
+    // Render the map value as a primitive type.
+    ProtoWriter::RenderDataPiece("value", data);
+    Pop();
+    return this;
+  }
+
+  field = Lookup(name);
+  if (field == NULL) return this;
+
+  // Check if the field is of special type. Render it accordingly if so.
+  const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+  if (type_renderer != NULL) {
+    Push(name, Item::MESSAGE, false, false);
+    status = (*type_renderer)(this, data);
+    if (!status.ok()) {
+      InvalidValue(field->type_url(),
+                   StrCat("Field '", name, "', ", status.error_message()));
+    }
+    Pop();
+    return this;
+  }
+
+  // If we are rendering explicit null values and the backend proto field is
+  // not of the google.protobuf.NullType type, we do nothing.
+  if (data.type() == DataPiece::TYPE_NULL &&
+      field->type_url() != kStructNullValueTypeUrl) {
+    return this;
+  }
+
+  ProtoWriter::RenderDataPiece(name, data);
+  return this;
+}
+
+// Map of functions that are responsible for rendering well known type
+// represented by the key.
+hash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
+    ProtoStreamObjectWriter::renderers_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_);
+
+void ProtoStreamObjectWriter::InitRendererMap() {
+  renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>();
+  (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
+      &ProtoStreamObjectWriter::RenderTimestamp;
+  (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
+      &ProtoStreamObjectWriter::RenderDuration;
+  (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
+      &ProtoStreamObjectWriter::RenderFieldMask;
+  (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.String"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
+      &ProtoStreamObjectWriter::RenderWrapperType;
+  (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
+      &ProtoStreamObjectWriter::RenderStructValue;
+  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
+}
+
+void ProtoStreamObjectWriter::DeleteRendererMap() {
+  delete ProtoStreamObjectWriter::renderers_;
+  renderers_ = NULL;
+}
+
+ProtoStreamObjectWriter::TypeRenderer*
+ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
+  ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap);
+  return FindOrNull(*renderers_, type_url);
+}
+
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+  if (current_ == NULL) return true;
+
+  if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+    listener()->InvalidName(
+        location(), unnormalized_name,
+        StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
+    return false;
+  }
+
+  return true;
+}
+
+void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
+                                   bool is_placeholder, bool is_list) {
+  is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
+
+  // invalid_depth == 0 means it is a successful StartObject or StartList.
+  if (invalid_depth() == 0)
+    current_.reset(
+        new Item(current_.release(), item_type, is_placeholder, is_list));
+}
+
+void ProtoStreamObjectWriter::Pop() {
+  // Pop all placeholder items sending StartObject or StartList events to
+  // ProtoWriter according to is_list value.
+  while (current_ != NULL && current_->is_placeholder()) {
+    PopOneElement();
+  }
+  if (current_ != NULL) {
+    PopOneElement();
+  }
+}
+
+void ProtoStreamObjectWriter::PopOneElement() {
+  current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
+  current_.reset(current_->pop<Item>());
+}
+
+bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
+  if (field.type_url().empty() ||
+      field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE ||
+      field.cardinality() !=
+          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
+    return false;
+  }
+  const google::protobuf::Type* field_type =
+      typeinfo()->GetTypeByTypeUrl(field.type_url());
+
+  // TODO(xiaofeng): Unify option names.
+  return GetBoolOptionOrDefault(field_type->options(),
+                                "google.protobuf.MessageOptions.map_entry", false) ||
+         GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
+}
+
+bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kAnyType;
+}
+
+bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructType;
+}
+
+bool ProtoStreamObjectWriter::IsStructValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
+}
+
+bool ProtoStreamObjectWriter::IsStructListValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
new file mode 100644
index 0000000..e1162d4
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -0,0 +1,340 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
+
+#include <deque>
+#include <google/protobuf/stubs/hash.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/proto_writer.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class CodedOutputStream;
+}  // namespace io
+}  // namespace protobuf
+
+
+namespace protobuf {
+class Type;
+class Field;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class supports all special types like Struct and Map. It uses
+// the ProtoWriter class to write raw proto bytes.
+//
+// It also supports streaming.
+class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
+ public:
+  // Options that control ProtoStreamObjectWriter class's behavior.
+  struct Options {
+    // Treats integer inputs in google.protobuf.Struct as strings. Normally,
+    // integer values are returned in double field "number_value" of
+    // google.protobuf.Struct. However, this can cause precision loss for
+    // int64/uint64 inputs. This option is provided for cases that want to
+    // preserve integer precision.
+    bool struct_integers_as_strings;
+
+    Options() : struct_integers_as_strings(false) {}
+
+    // Default instance of Options with all options set to defaults.
+    static const Options& Defaults() {
+      static Options defaults;
+      return defaults;
+    }
+  };
+
+// Constructor. Does not take ownership of any parameter passed in.
+  ProtoStreamObjectWriter(TypeResolver* type_resolver,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener,
+                          const ProtoStreamObjectWriter::Options& options =
+                              ProtoStreamObjectWriter::Options::Defaults());
+  virtual ~ProtoStreamObjectWriter();
+
+  // ObjectWriter methods.
+  virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
+  virtual ProtoStreamObjectWriter* EndObject();
+  virtual ProtoStreamObjectWriter* StartList(StringPiece name);
+  virtual ProtoStreamObjectWriter* EndList();
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+                                                   const DataPiece& value);
+
+ protected:
+  // Function that renders a well known type with modified behavior.
+  typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
+                                         const DataPiece&);
+
+  // Handles writing Anys out using nested object writers and the like.
+  class LIBPROTOBUF_EXPORT AnyWriter {
+   public:
+    explicit AnyWriter(ProtoStreamObjectWriter* parent);
+    ~AnyWriter();
+
+    // Passes a StartObject call through to the Any writer.
+    void StartObject(StringPiece name);
+
+    // Passes an EndObject call through to the Any. Returns true if the any
+    // handled the EndObject call, false if the Any is now all done and is no
+    // longer needed.
+    bool EndObject();
+
+    // Passes a StartList call through to the Any writer.
+    void StartList(StringPiece name);
+
+    // Passes an EndList call through to the Any writer.
+    void EndList();
+
+    // Renders a data piece on the any.
+    void RenderDataPiece(StringPiece name, const DataPiece& value);
+
+   private:
+    // Handles starting up the any once we have a type.
+    void StartAny(const DataPiece& value);
+
+    // Writes the Any out to the parent writer in its serialized form.
+    void WriteAny();
+
+    // The parent of this writer, needed for various bits such as type info and
+    // the listeners.
+    ProtoStreamObjectWriter* parent_;
+
+    // The nested object writer, used to write events.
+    google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_;
+
+    // The type_url_ that this Any represents.
+    string type_url_;
+
+    // Whether this any is invalid. This allows us to only report an invalid
+    // Any message a single time rather than every time we get a nested field.
+    bool invalid_;
+
+    // The output data and wrapping ByteSink.
+    string data_;
+    strings::StringByteSink output_;
+
+    // The depth within the Any, so we can track when we're done.
+    int depth_;
+
+    // True if the type is a well-known type. Well-known types in Any
+    // has a special formating:
+    // {
+    //   "@type": "type.googleapis.com/google.protobuf.XXX",
+    //   "value": <JSON representation of the type>,
+    // }
+    bool is_well_known_type_;
+    TypeRenderer* well_known_type_render_;
+  };
+
+  // Represents an item in a stack of items used to keep state between
+  // ObjectWrier events.
+  class LIBPROTOBUF_EXPORT Item : public BaseElement {
+   public:
+    // Indicates the type of item.
+    enum ItemType {
+      MESSAGE,  // Simple message
+      MAP,      // Proto3 map type
+      ANY,      // Proto3 Any type
+    };
+
+    // Constructor for the root item.
+    Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
+         bool is_placeholder, bool is_list);
+
+    // Constructor for a field of a message.
+    Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
+
+    virtual ~Item() {}
+
+    // These functions return true if the element type is corresponding to the
+    // type in function name.
+    bool IsMap() { return item_type_ == MAP; }
+    bool IsAny() { return item_type_ == ANY; }
+
+    AnyWriter* any() const { return any_.get(); }
+
+    virtual Item* parent() const {
+      return static_cast<Item*>(BaseElement::parent());
+    }
+
+    // Inserts map key into hash set if and only if the key did NOT already
+    // exist in hash set.
+    // The hash set (map_keys_) is ONLY used to keep track of map keys.
+    // Return true if insert successfully; returns false if the map key was
+    // already present.
+    bool InsertMapKeyIfNotPresent(StringPiece map_key);
+
+    bool is_placeholder() const { return is_placeholder_; }
+    bool is_list() const { return is_list_; }
+
+   private:
+    // Used for access to variables of the enclosing instance of
+    // ProtoStreamObjectWriter.
+    ProtoStreamObjectWriter* ow_;
+
+    // A writer for Any objects, handles all Any-related nonsense.
+    google::protobuf::scoped_ptr<AnyWriter> any_;
+
+    // The type of this element, see enum for permissible types.
+    ItemType item_type_;
+
+    // Set of map keys already seen for the type_. Used to validate incoming
+    // messages so no map key appears more than once.
+    hash_set<string> map_keys_;
+
+    // Conveys whether this Item is a placeholder or not. Placeholder items are
+    // pushed to stack to account for special types.
+    bool is_placeholder_;
+
+    // Conveys whether this Item is a list or not. This is used to send
+    // StartList or EndList calls to underlying ObjectWriter.
+    bool is_list_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
+  };
+
+  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+                          const google::protobuf::Type& type,
+                          strings::ByteSink* output, ErrorListener* listener);
+
+  // Returns true if the field is a map.
+  bool IsMap(const google::protobuf::Field& field);
+
+  // Returns true if the field is an any.
+  bool IsAny(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Struct.
+  bool IsStruct(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.Value.
+  bool IsStructValue(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.ListValue.
+  bool IsStructListValue(const google::protobuf::Field& field);
+
+  // Renders google.protobuf.Value in struct.proto. It picks the right oneof
+  // type based on value's type.
+  static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
+                                          const DataPiece& value);
+
+  // Renders google.protobuf.Timestamp value.
+  static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
+                                        const DataPiece& value);
+
+  // Renders google.protobuf.FieldMask value.
+  static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
+                                        const DataPiece& value);
+
+  // Renders google.protobuf.Duration value.
+  static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
+                                       const DataPiece& value);
+
+  // Renders wrapper message types for primitive types in
+  // google/protobuf/wrappers.proto.
+  static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
+                                          const DataPiece& value);
+
+  static void InitRendererMap();
+  static void DeleteRendererMap();
+  static TypeRenderer* FindTypeRenderer(const string& type_url);
+
+  // Returns true if the map key for type_ is not duplicated key.
+  // If map key is duplicated key, this function returns false.
+  // Note that caller should make sure that the current proto element (current_)
+  // is of element type MAP or STRUCT_MAP.
+  // It also calls the appropriate error callback and unnormalzied_name is used
+  // for error string.
+  bool ValidMapKey(StringPiece unnormalized_name);
+
+  // Pushes an item on to the stack. Also calls either StartObject or StartList
+  // on the underlying ObjectWriter depending on whether is_list is false or
+  // not.
+  // is_placeholder conveys whether the item is a placeholder item or not.
+  // Placeholder items are pushed when adding auxillary types' StartObject or
+  // StartList calls.
+  void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
+            bool is_list);
+
+  // Pops items from the stack. All placeholder items are popped until a
+  // non-placeholder item is found.
+  void Pop();
+
+  // Pops one element from the stack. Calls EndObject() or EndList() on the
+  // underlying ObjectWriter depending on the value of is_list_.
+  void PopOneElement();
+
+ private:
+  // Helper functions to create the map and find functions responsible for
+  // rendering well known types, keyed by type URL.
+  static hash_map<string, TypeRenderer>* renderers_;
+
+  // Variables for describing the structure of the input tree:
+  // master_type_: descriptor for the whole protobuf message.
+  const google::protobuf::Type& master_type_;
+
+  // The current element, variable for internal state processing.
+  google::protobuf::scoped_ptr<Item> current_;
+
+  // Reference to the options that control this class's behavior.
+  const ProtoStreamObjectWriter::Options options_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
new file mode 100644
index 0000000..9a0dcde
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -0,0 +1,2277 @@
+// 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.
+
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+
+#include <stddef.h>  // For size_t
+
+#include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/util/internal/mock_error_listener.h>
+#include <google/protobuf/util/internal/testdata/books.pb.h>
+#include <google/protobuf/util/internal/testdata/field_mask.pb.h>
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/testdata/anys.pb.h>
+#include <google/protobuf/util/internal/testdata/maps.pb.h>
+#include <google/protobuf/util/internal/testdata/oneofs.pb.h>
+#include <google/protobuf/util/internal/testdata/struct.pb.h>
+#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h>
+#include <gtest/gtest.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::testing::Author;
+using google::protobuf::testing::Book;
+using google::protobuf::testing::Book_Data;
+using google::protobuf::testing::Primitive;
+using google::protobuf::testing::Publisher;
+using google::protobuf::Descriptor;
+using google::protobuf::DescriptorPool;
+using google::protobuf::DynamicMessageFactory;
+using google::protobuf::FileDescriptorProto;
+using google::protobuf::Message;
+using google::protobuf::io::ArrayInputStream;
+using strings::GrowingArrayByteSink;
+using ::testing::_;
+using ::testing::Args;
+using google::protobuf::testing::anys::AnyM;
+using google::protobuf::testing::anys::AnyOut;
+using google::protobuf::testing::oneofs::OneOfsRequest;
+using google::protobuf::testing::FieldMaskTest;
+using google::protobuf::testing::maps::MapIn;
+using google::protobuf::testing::structs::StructType;
+using google::protobuf::testing::timestampduration::TimestampDuration;
+
+
+namespace {
+string GetTypeUrl(const Descriptor* descriptor) {
+  return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
+}
+}  // namespace
+
+#if __cplusplus >= 201103L
+  using std::get;
+#else
+  using std::tr1::get;
+#endif
+
+class BaseProtoStreamObjectWriterTest
+    : public ::testing::TestWithParam<testing::TypeInfoSource> {
+ protected:
+  BaseProtoStreamObjectWriterTest()
+      : helper_(GetParam()),
+        listener_(),
+        output_(new GrowingArrayByteSink(1000)),
+        ow_() {}
+
+  explicit BaseProtoStreamObjectWriterTest(const Descriptor* descriptor)
+      : helper_(GetParam()),
+        listener_(),
+        output_(new GrowingArrayByteSink(1000)),
+        ow_() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(descriptor);
+    ResetTypeInfo(descriptors);
+  }
+
+  explicit BaseProtoStreamObjectWriterTest(
+      vector<const Descriptor*> descriptors)
+      : helper_(GetParam()),
+        listener_(),
+        output_(new GrowingArrayByteSink(1000)),
+        ow_() {
+    ResetTypeInfo(descriptors);
+  }
+
+  void ResetTypeInfo(vector<const Descriptor*> descriptors) {
+    GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!";
+    helper_.ResetTypeInfo(descriptors);
+    ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(),
+                                     &listener_, options_));
+  }
+
+  void ResetTypeInfo(const Descriptor* descriptor) {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(descriptor);
+    ResetTypeInfo(descriptors);
+  }
+
+  virtual ~BaseProtoStreamObjectWriterTest() {}
+
+  void CheckOutput(const Message& expected, int expected_length) {
+    size_t nbytes;
+    google::protobuf::scoped_array<char> buffer(output_->GetBuffer(&nbytes));
+    if (expected_length >= 0) {
+      EXPECT_EQ(expected_length, nbytes);
+    }
+    string str(buffer.get(), nbytes);
+
+    std::stringbuf str_buf(str, std::ios_base::in);
+    std::istream istream(&str_buf);
+    google::protobuf::scoped_ptr<Message> message(expected.New());
+    message->ParsePartialFromIstream(&istream);
+
+    if (!MessageDifferencer::Equivalent(expected, *message)) {
+      EXPECT_EQ(expected.DebugString(), message->DebugString());
+    }
+  }
+
+  void CheckOutput(const Message& expected) { CheckOutput(expected, -1); }
+
+  const google::protobuf::Type* GetType(const Descriptor* descriptor) {
+    return helper_.GetTypeInfo()->GetTypeByTypeUrl(GetTypeUrl(descriptor));
+  }
+
+  testing::TypeInfoTestHelper helper_;
+  MockErrorListener listener_;
+  google::protobuf::scoped_ptr<GrowingArrayByteSink> output_;
+  google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_;
+  ProtoStreamObjectWriter::Options options_;
+};
+
+MATCHER_P(HasObjectLocation, expected,
+          "Verifies the expected object location") {
+  string actual = get<0>(arg).ToString();
+  if (actual.compare(expected) == 0) return true;
+  *result_listener << "actual location is: " << actual;
+  return false;
+}
+
+class ProtoStreamObjectWriterTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterTest()
+      : BaseProtoStreamObjectWriterTest(Book::descriptor()) {}
+
+  virtual ~ProtoStreamObjectWriterTest() {}
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterTest, EmptyObject) {
+  Book empty;
+  ow_->StartObject("")->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, SimpleObject) {
+  string content("My content");
+
+  Book book;
+  book.set_title("My Title");
+  book.set_length(222);
+  book.set_content(content);
+
+  ow_->StartObject("")
+      ->RenderString("title", "My Title")
+      ->RenderInt32("length", 222)
+      ->RenderBytes("content", content)
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, SimpleMessage) {
+  Book book;
+  book.set_title("Some Book");
+  book.set_length(102);
+  Publisher* publisher = book.mutable_publisher();
+  publisher->set_name("My Publisher");
+  Author* robert = book.mutable_author();
+  robert->set_alive(true);
+  robert->set_name("robert");
+  robert->add_pseudonym("bob");
+  robert->add_pseudonym("bobby");
+  robert->add_friend_()->set_name("john");
+
+  ow_->StartObject("")
+      ->RenderString("title", "Some Book")
+      ->RenderInt32("length", 102)
+      ->StartObject("publisher")
+      ->RenderString("name", "My Publisher")
+      ->EndObject()
+      ->StartObject("author")
+      ->RenderBool("alive", true)
+      ->RenderString("name", "robert")
+      ->StartList("pseudonym")
+      ->RenderString("", "bob")
+      ->RenderString("", "bobby")
+      ->EndList()
+      ->StartList("friend")
+      ->StartObject("")
+      ->RenderString("name", "john")
+      ->EndObject()
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) {
+  Book book;
+  Author* robert = book.mutable_author();
+  robert->set_id(12345);
+  robert->set_name("robert");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderUint64("@id", 12345)
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) {
+  Primitive full;
+  full.set_fix32(101);
+  full.set_u32(102);
+  full.set_i32(-103);
+  full.set_sf32(-104);
+  full.set_s32(-105);
+  full.set_fix64(40000000001L);
+  full.set_u64(40000000002L);
+  full.set_i64(-40000000003L);
+  full.set_sf64(-40000000004L);
+  full.set_s64(-40000000005L);
+  full.set_str("string1");
+  full.set_bytes("Some Bytes");
+  full.set_float_(3.14f);
+  full.set_double_(-4.05L);
+  full.set_bool_(true);
+  full.add_rep_fix32(201);
+  full.add_rep_u32(202);
+  full.add_rep_i32(-203);
+  full.add_rep_sf32(-204);
+  full.add_rep_s32(-205);
+  full.add_rep_fix64(80000000001L);
+  full.add_rep_u64(80000000002L);
+  full.add_rep_i64(-80000000003L);
+  full.add_rep_sf64(-80000000004L);
+  full.add_rep_s64(-80000000005L);
+  full.add_rep_str("string2");
+  full.add_rep_bytes("More Bytes");
+  full.add_rep_float(6.14f);
+  full.add_rep_double(-8.05L);
+  full.add_rep_bool(false);
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  ow_->StartObject("")
+      ->RenderString("fix32", "101")
+      ->RenderString("u32", "102")
+      ->RenderString("i32", "-103")
+      ->RenderString("sf32", "-104")
+      ->RenderString("s32", "-105")
+      ->RenderString("fix64", "40000000001")
+      ->RenderString("u64", "40000000002")
+      ->RenderString("i64", "-40000000003")
+      ->RenderString("sf64", "-40000000004")
+      ->RenderString("s64", "-40000000005")
+      ->RenderString("str", "string1")
+      ->RenderString("bytes", "U29tZSBCeXRlcw==")  // "Some Bytes"
+      ->RenderString("float", "3.14")
+      ->RenderString("double", "-4.05")
+      ->RenderString("bool", "true")
+      ->StartList("rep_fix32")
+      ->RenderString("", "201")
+      ->EndList()
+      ->StartList("rep_u32")
+      ->RenderString("", "202")
+      ->EndList()
+      ->StartList("rep_i32")
+      ->RenderString("", "-203")
+      ->EndList()
+      ->StartList("rep_sf32")
+      ->RenderString("", "-204")
+      ->EndList()
+      ->StartList("rep_s32")
+      ->RenderString("", "-205")
+      ->EndList()
+      ->StartList("rep_fix64")
+      ->RenderString("", "80000000001")
+      ->EndList()
+      ->StartList("rep_u64")
+      ->RenderString("", "80000000002")
+      ->EndList()
+      ->StartList("rep_i64")
+      ->RenderString("", "-80000000003")
+      ->EndList()
+      ->StartList("rep_sf64")
+      ->RenderString("", "-80000000004")
+      ->EndList()
+      ->StartList("rep_s64")
+      ->RenderString("", "-80000000005")
+      ->EndList()
+      ->StartList("rep_str")
+      ->RenderString("", "string2")
+      ->EndList()
+      ->StartList("rep_bytes")
+      ->RenderString("", "TW9yZSBCeXRlcw==")  // "More Bytes"
+      ->EndList()
+      ->StartList("rep_float")
+      ->RenderString("", "6.14")
+      ->EndList()
+      ->StartList("rep_double")
+      ->RenderString("", "-8.05")
+      ->EndList()
+      ->StartList("rep_bool")
+      ->RenderString("", "false")
+      ->EndList()
+      ->EndObject();
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) {
+  Primitive full;
+  full.set_double_(std::numeric_limits<double>::infinity());
+  full.set_float_(std::numeric_limits<float>::infinity());
+  full.set_str("-Infinity");
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("i32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("u32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"),
+                                      StringPiece("\"-Infinity\"")))
+      .With(Args<0>(HasObjectLocation("sf64")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_BOOL"),
+                                      StringPiece("\"Infinity\"")))
+      .With(Args<0>(HasObjectLocation("bool")));
+
+  ow_->StartObject("")
+      ->RenderString("double", "Infinity")
+      ->RenderString("float", "Infinity")
+      ->RenderString("i32", "Infinity")
+      ->RenderString("u32", "Infinity")
+      ->RenderString("sf64", "-Infinity")
+      ->RenderString("str", "-Infinity")
+      ->RenderString("bool", "Infinity")
+      ->EndObject();
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) {
+  Primitive full;
+  full.set_double_(std::numeric_limits<double>::quiet_NaN());
+  full.set_float_(std::numeric_limits<float>::quiet_NaN());
+  full.set_str("NaN");
+
+  ResetTypeInfo(Primitive::descriptor());
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("i32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("u32")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"),
+                                      StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("sf64")));
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("TYPE_BOOL"), StringPiece("\"NaN\"")))
+      .With(Args<0>(HasObjectLocation("bool")));
+
+  ow_->StartObject("")
+      ->RenderString("double", "NaN")
+      ->RenderString("float", "NaN")
+      ->RenderString("i32", "NaN")
+      ->RenderString("u32", "NaN")
+      ->RenderString("sf64", "NaN")
+      ->RenderString("str", "NaN")
+      ->RenderString("bool", "NaN")
+      ->EndObject();
+
+  CheckOutput(full);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ImplicitPrimitiveList) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+  author->add_pseudonym("first");
+  author->add_pseudonym("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->RenderString("pseudonym", "first")
+      ->RenderString("pseudonym", "second")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       LastWriteWinsOnNonRepeatedPrimitiveFieldWithDuplicates) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "first")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ExplicitPrimitiveList) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+  author->add_pseudonym("first");
+  author->add_pseudonym("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->StartList("pseudonym")
+      ->RenderString("", "first")
+      ->RenderString("", "second")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitPrimitiveList) {
+  Book expected;
+  expected.set_allocated_author(new Author());
+
+  EXPECT_CALL(
+      listener_,
+      InvalidName(
+          _, StringPiece("name"),
+          StringPiece("Proto field is not repeating, cannot start list.")))
+      .With(Args<0>(HasObjectLocation("author")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->StartList("name")
+      ->RenderString("", "first")
+      ->RenderString("", "second")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ImplicitMessageList) {
+  Book expected;
+  Author* outer = expected.mutable_author();
+  outer->set_name("outer");
+  outer->set_alive(true);
+  Author* first = outer->add_friend_();
+  first->set_name("first");
+  Author* second = outer->add_friend_();
+  second->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "outer")
+      ->RenderBool("alive", true)
+      ->StartObject("friend")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("friend")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest,
+       LastWriteWinsOnNonRepeatedMessageFieldWithDuplicates) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+  Publisher* publisher = expected.mutable_publisher();
+  publisher->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->EndObject()
+      ->StartObject("publisher")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("publisher")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, ExplicitMessageList) {
+  Book expected;
+  Author* outer = expected.mutable_author();
+  outer->set_name("outer");
+  outer->set_alive(true);
+  Author* first = outer->add_friend_();
+  first->set_name("first");
+  Author* second = outer->add_friend_();
+  second->set_name("second");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "outer")
+      ->RenderBool("alive", true)
+      ->StartList("friend")
+      ->StartObject("")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitMessageList) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("The Author");
+
+  EXPECT_CALL(
+      listener_,
+      InvalidName(
+          _, StringPiece("publisher"),
+          StringPiece("Proto field is not repeating, cannot start list.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "The Author")
+      ->EndObject()
+      ->StartList("publisher")
+      ->StartObject("")
+      ->RenderString("name", "first")
+      ->EndObject()
+      ->StartObject("")
+      ->RenderString("name", "second")
+      ->EndObject()
+      ->EndList()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtRoot) {
+  Book empty;
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")->RenderString("unknown", "Nope!")->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtAuthorFriend) {
+  Book expected;
+  Author* paul = expected.mutable_author();
+  paul->set_name("Paul");
+  Author* mark = paul->add_friend_();
+  mark->set_name("Mark");
+  Author* john = paul->add_friend_();
+  john->set_name("John");
+  Author* luke = paul->add_friend_();
+  luke->set_name("Luke");
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("address"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("author.friend[1]")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "Paul")
+      ->StartList("friend")
+      ->StartObject("")
+      ->RenderString("name", "Mark")
+      ->EndObject()
+      ->StartObject("")
+      ->RenderString("name", "John")
+      ->RenderString("address", "Patmos")
+      ->EndObject()
+      ->StartObject("")
+      ->RenderString("name", "Luke")
+      ->EndObject()
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtRoot) {
+  Book empty;
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")->StartObject("unknown")->EndObject()->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtAuthor) {
+  Book expected;
+  Author* author = expected.mutable_author();
+  author->set_name("William");
+  author->add_pseudonym("Bill");
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("wife"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("author")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderString("name", "William")
+      ->StartObject("wife")
+      ->RenderString("name", "Hilary")
+      ->EndObject()
+      ->RenderString("pseudonym", "Bill")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownListAtRoot) {
+  Book empty;
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")->StartList("unknown")->EndList()->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnknownListAtPublisher) {
+  Book expected;
+  expected.set_title("Brainwashing");
+  Publisher* publisher = expected.mutable_publisher();
+  publisher->set_name("propaganda");
+
+  EXPECT_CALL(listener_, InvalidName(_, StringPiece("alliance"),
+                                     StringPiece("Cannot find field.")))
+      .With(Args<0>(HasObjectLocation("publisher")));
+  ow_->StartObject("")
+      ->StartObject("publisher")
+      ->RenderString("name", "propaganda")
+      ->StartList("alliance")
+      ->EndList()
+      ->EndObject()
+      ->RenderString("title", "Brainwashing")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, MissingRequiredField) {
+  Book expected;
+  expected.set_title("My Title");
+  expected.set_allocated_publisher(new Publisher());
+
+  EXPECT_CALL(listener_, MissingField(_, StringPiece("name")))
+      .With(Args<0>(HasObjectLocation("publisher")));
+  ow_->StartObject("")
+      ->StartObject("publisher")
+      ->EndObject()
+      ->RenderString("title", "My Title")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, InvalidFieldValueAtRoot) {
+  Book empty;
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"garbage\"")))
+      .With(Args<0>(HasObjectLocation("length")));
+  ow_->StartObject("")->RenderString("length", "garbage")->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, MultipleInvalidFieldValues) {
+  Book expected;
+  expected.set_title("My Title");
+
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"),
+                                      StringPiece("\"-400\"")))
+      .With(Args<0>(HasObjectLocation("length")));
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT64"),
+                                      StringPiece("\"3.14\"")))
+      .With(Args<0>(HasObjectLocation("published")));
+  ow_->StartObject("")
+      ->RenderString("length", "-400")
+      ->RenderString("published", "3.14")
+      ->RenderString("title", "My Title")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtRoot) {
+  Book empty;
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece(""),
+                          StringPiece("Proto fields must have a name.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")->RenderFloat("", 3.14)->EndObject();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtAuthor) {
+  Book expected;
+  expected.set_title("noname");
+  expected.set_allocated_author(new Author());
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece(""),
+                          StringPiece("Proto fields must have a name.")))
+      .With(Args<0>(HasObjectLocation("author")));
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderInt32("", 123)
+      ->EndObject()
+      ->RenderString("title", "noname")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, UnnamedListAtRoot) {
+  Book expected;
+  expected.set_title("noname");
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece(""),
+                          StringPiece("Proto fields must have a name.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")
+      ->StartList("")
+      ->EndList()
+      ->RenderString("title", "noname")
+      ->EndObject();
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, RootNamedObject) {
+  Book expected;
+  expected.set_title("Annie");
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece("oops"),
+                          StringPiece("Root element should not be named.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("oops")->RenderString("title", "Annie")->EndObject();
+  CheckOutput(expected, 7);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, RootNamedList) {
+  Book empty;
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece("oops"),
+                          StringPiece("Root element should not be named.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartList("oops")->RenderString("", "item")->EndList();
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, RootUnnamedField) {
+  Book empty;
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece(""),
+                          StringPiece("Root element must be a message.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->RenderBool("", true);
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, RootNamedField) {
+  Book empty;
+
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece("oops"),
+                          StringPiece("Root element must be a message.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->RenderBool("oops", true);
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NullValue) {
+  Book empty;
+
+  ow_->RenderNull("");
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NullValueForMessageField) {
+  Book empty;
+
+  ow_->RenderNull("author");
+  CheckOutput(empty, 0);
+}
+
+TEST_P(ProtoStreamObjectWriterTest, NullValueForPrimitiveField) {
+  Book empty;
+
+  ow_->RenderNull("length");
+  CheckOutput(empty, 0);
+}
+
+class ProtoStreamObjectWriterTimestampDurationTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterTimestampDurationTest() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(TimestampDuration::descriptor());
+    descriptors.push_back(google::protobuf::Timestamp::descriptor());
+    descriptors.push_back(google::protobuf::Duration::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterTimestampDurationTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampYearNotZeroPadded) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(-61665654145);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "15-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampYearZeroPadded) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(-61665654145);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "0015-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampWithPositiveOffset) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       ParseTimestampWithNegativeOffset) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset1) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2016-03-07T15:14:23+")));
+
+  ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset2) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2016-03-07T15:14:23+08-10")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+08-10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset3) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2016-03-07T15:14:23+24:10")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+24:10")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       TimestampWithInvalidOffset4) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2016-03-07T15:14:23+04:60")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2016-03-07T15:14:23+04:60")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: ")));
+
+  ow_->StartObject("")->RenderString("ts", "")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: Z")));
+
+  ow_->StartObject("")->RenderString("ts", "Z")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "1970-01-01T00:00:00.ABZ")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "1970-01-01T00:00:00.ABZ")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "-8031-10-18T00:00:00.000Z")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "-8031-10-18T00:00:00.000Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033155   Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155   Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033155 1234Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033abc155Z")));
+
+  ow_->StartObject("")
+      // Non-numeric characters in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "0-12-31T23:59:59.000Z")));
+
+  ow_->StartObject("")
+      ->RenderString("ts", "0-12-31T23:59:59.000Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) {
+  TimestampDuration duration;
+  google::protobuf::Duration* dur = duration.mutable_dur();
+  dur->set_seconds(1448216930);
+  dur->set_nanos(132262000);
+
+  ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Illegal duration format; duration must "
+                      "end with 's'")));
+
+  ow_->StartObject("")->RenderString("dur", "")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Invalid duration format, failed to parse "
+                      "seconds")));
+
+  ow_->StartObject("")->RenderString("dur", "s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece("Field 'dur', Invalid duration format, failed to "
+                      "parse nano seconds")));
+
+  ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Duration"),
+                   StringPiece("Field 'dur', Duration value exceeds limits")));
+
+  ow_->StartObject("")->RenderString("dur", "315576000002s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Duration"),
+                   StringPiece("Field 'dur', Duration value exceeds limits")));
+
+  ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject();
+  CheckOutput(duration);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       MismatchedTimestampTypeInput) {
+  TimestampDuration timestamp;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+          StringPiece(
+              "Field 'ts', Invalid data type for timestamp, value is null")))
+      .With(Args<0>(HasObjectLocation("ts")));
+  ow_->StartObject("")->RenderNull("ts")->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
+       MismatchedDurationTypeInput) {
+  TimestampDuration duration;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
+          StringPiece(
+              "Field 'dur', Invalid data type for duration, value is null")))
+      .With(Args<0>(HasObjectLocation("dur")));
+  ow_->StartObject("")->RenderNull("dur")->EndObject();
+  CheckOutput(duration);
+}
+
+class ProtoStreamObjectWriterStructTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); }
+
+  // Resets ProtoWriter with current set of options and other state.
+  void ResetProtoWriter() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(StructType::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterStructTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+// TODO(skarvaje): Write tests for failure cases.
+TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) {
+  StructType struct_type;
+  google::protobuf::Struct* s = struct_type.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_number_value(123);
+  s->mutable_fields()->operator[]("k2").set_bool_value(true);
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderDouble("k1", 123)
+      ->RenderBool("k2", true)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, StructNullInputSuccess) {
+  StructType struct_type;
+  EXPECT_CALL(listener_,
+              InvalidName(_, StringPiece(""),
+                          StringPiece("Proto fields must have a name.")))
+      .With(Args<0>(HasObjectLocation("")));
+  ow_->StartObject("")->RenderNull("")->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) {
+  StructType struct_type;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Struct"),
+                   StringPiece("true")))
+      .With(Args<0>(HasObjectLocation("object")));
+
+  ow_->StartObject("")->RenderBool("object", true)->EndObject();
+  CheckOutput(struct_type);
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("gBike"),
+                  StringPiece("Repeated map key: 'gBike' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("gBike", "v1")
+      ->RenderString("gBike", "v2")
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("k1", "v1")
+      ->StartList("k1")
+      ->RenderString("", "v2")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->StartObject("k1")
+      ->RenderString("sub_k1", "v1")
+      ->EndObject()
+      ->StartObject("k1")
+      ->RenderString("sub_k2", "v2")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) {
+  StructType struct_type;
+  google::protobuf::Struct* s = struct_type.mutable_object();
+  s->mutable_fields()->operator[]("k1").set_number_value(123);
+  s->mutable_fields()->operator[]("k2").set_bool_value(true);
+  s->mutable_fields()->operator[]("k3").set_string_value("-222222222");
+  s->mutable_fields()->operator[]("k4").set_string_value("33333333");
+
+  options_.struct_integers_as_strings = true;
+  ResetProtoWriter();
+
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderDouble("k1", 123)
+      ->RenderBool("k2", true)
+      ->RenderInt64("k3", -222222222)
+      ->RenderUint64("k4", 33333333)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(struct_type);
+}
+
+class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterMapTest()
+      : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {}
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterMapTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
+  MapIn mm;
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Map"),
+          StringPiece("Cannot bind a list to map for field 'map_input'.")));
+  ow_->StartObject("")
+      ->StartList("map_input")
+      ->RenderString("a", "b")
+      ->EndList()
+      ->EndObject();
+  CheckOutput(mm);
+}
+
+TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->RenderString("other", "test")
+      ->StartObject("map_input")
+      ->RenderString("k1", "v1")
+      ->RenderString("k1", "v2")
+      ->EndObject()
+      ->EndObject();
+}
+
+class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterAnyTest() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(AnyOut::descriptor());
+    descriptors.push_back(google::protobuf::DoubleValue::descriptor());
+    descriptors.push_back(google::protobuf::Timestamp::descriptor());
+    descriptors.push_back(google::protobuf::Any::descriptor());
+    descriptors.push_back(google::protobuf::Value::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterAnyTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) {
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.DoubleValue");
+  google::protobuf::DoubleValue d;
+  d.set_value(40.2);
+  any_type->set_value(d.SerializeAsString());
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue")
+      ->RenderDouble("value", 40.2)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any nested_any;
+  nested_any.set_type_url(
+      "type.googleapis.com/google.protobuf.testing.anys.AnyM");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  nested_any.set_value(m.SerializeAsString());
+
+  any->set_value(nested_any.SerializeAsString());
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type",
+                     "type.googleapis.com/google.protobuf.testing.anys.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+  any->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any nested_any;
+  nested_any.set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ::google::protobuf::Any second_nested_any;
+  second_nested_any.set_type_url(
+      "type.googleapis.com/google.protobuf.testing.anys.AnyM");
+
+  AnyM m;
+  m.set_foo("foovalue");
+  second_nested_any.set_value(m.SerializeAsString());
+
+  nested_any.set_value(second_nested_any.SerializeAsString());
+  any->set_value(nested_any.SerializeAsString());
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->StartObject("value")
+      ->RenderString("@type",
+                     "type.googleapis.com/google.protobuf.testing.anys.AnyM")
+      ->RenderString("foo", "foovalue")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
+  AnyOut out;
+  out.mutable_any();
+
+  ow_->StartObject("")->StartObject("any")->EndObject()->EndObject();
+
+  CheckOutput(out, 2);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("Any"),
+                   StringPiece("Missing or invalid @type for any field in "
+                               "google.protobuf.testing.anys.AnyOut")));
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->StartObject("another")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("Any"),
+                   StringPiece("Missing or invalid @type for any field in "
+                               "google.protobuf.testing.anys.AnyOut")));
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->StartList("another")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("Any"),
+                   StringPiece("Missing or invalid @type for any field in "
+                               "google.protobuf.testing.anys.AnyOut")));
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("value", "somevalue")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithInvalidTypeUrlFails) {
+  AnyOut any;
+
+  EXPECT_CALL(listener_,
+              InvalidValue(
+                  _, StringPiece("Any"),
+                  StringPiece("Invalid type URL, type URLs must be of the form "
+                              "'type.googleapis.com/<typename>', got: "
+                              "type.other.com/some.Type")));
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.other.com/some.Type")
+      ->RenderDouble("value", 40.2)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithUnknownTypeFails) {
+  AnyOut any;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_, StringPiece("Any"),
+                   StringPiece("Invalid type URL, unknown type: some.Type")));
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/some.Type")
+      ->RenderDouble("value", 40.2)
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) {
+  AnyOut any;
+
+  ow_->StartObject("")->RenderNull("any")->EndObject();
+  CheckOutput(any);
+}
+
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) {
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+                                      StringPiece("Invalid time format: ")));
+
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": "abc"
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  value.set_string_value("abc");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->RenderString("value", "abc")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": {
+//       "foo": "abc"
+//     }
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value(
+      "abc");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartObject("value")
+      ->RenderString("foo", "abc")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "value": ["hello"],
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) {
+  AnyOut out;
+  ::google::protobuf::Any* any = out.mutable_any();
+
+  ::google::protobuf::Value value;
+  value.mutable_list_value()->add_values()->set_string_value("hello");
+  any->PackFrom(value);
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartList("value")
+      ->RenderString("", "hello")
+      ->EndList()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(out);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": ""
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest,
+       AnyWellKnownTypesNoValueFieldForPrimitive) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->RenderString("not_value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": {}
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartObject("not_value")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Value",
+//     "not_value": [],
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Any"),
+          StringPiece("Expect a \"value\" field for well-known types.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Value");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Value")
+      ->StartList("not_value")
+      ->EndList()
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Struct",
+//     "value": "",
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) {
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+                                      StringPiece("Expect a JSON object.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Struct");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+// Test the following case:
+//
+// {
+//   "any": {
+//     "@type": "type.googleapis.com/google.protobuf.Any",
+//     "value": "",
+//   }
+// }
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) {
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+                                      StringPiece("Expect a JSON object.")));
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Any");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
+class ProtoStreamObjectWriterFieldMaskTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterFieldMaskTest() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(FieldMaskTest::descriptor());
+    descriptors.push_back(google::protobuf::FieldMask::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterFieldMaskTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) {
+  FieldMaskTest expected;
+  expected.set_id("1");
+  expected.mutable_single_mask()->add_paths("path1");
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->RenderString("single_mask", "path1");
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MutipleMasksInCompactForm) {
+  FieldMaskTest expected;
+  expected.set_id("1");
+  expected.mutable_single_mask()->add_paths("camel_case1");
+  expected.mutable_single_mask()->add_paths("camel_case2");
+  expected.mutable_single_mask()->add_paths("camel_case3");
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->RenderString("single_mask", "camelCase1,camelCase2,camelCase3");
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, RepeatedFieldMaskTest) {
+  FieldMaskTest expected;
+  expected.set_id("1");
+  google::protobuf::FieldMask* mask = expected.add_repeated_mask();
+  mask->add_paths("field1");
+  mask->add_paths("field2");
+  expected.add_repeated_mask()->add_paths("field3");
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->StartList("repeated_mask");
+  ow_->RenderString("", "field1,field2");
+  ow_->RenderString("", "field3");
+  ow_->EndList();
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, EmptyFieldMaskTest) {
+  FieldMaskTest expected;
+  expected.set_id("1");
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->RenderString("single_mask", "");
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MaskUsingApiaryStyleShouldWork) {
+  FieldMaskTest expected;
+  expected.set_id("1");
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  // Case1
+  ow_->RenderString("single_mask",
+                    "outerField(camelCase1,camelCase2,camelCase3)");
+  expected.mutable_single_mask()->add_paths("outer_field.camel_case1");
+  expected.mutable_single_mask()->add_paths("outer_field.camel_case2");
+  expected.mutable_single_mask()->add_paths("outer_field.camel_case3");
+
+  ow_->StartList("repeated_mask");
+
+  ow_->RenderString("", "a(field1,field2)");
+  google::protobuf::FieldMask* mask = expected.add_repeated_mask();
+  mask->add_paths("a.field1");
+  mask->add_paths("a.field2");
+
+  ow_->RenderString("", "a(field3)");
+  mask = expected.add_repeated_mask();
+  mask->add_paths("a.field3");
+
+  ow_->RenderString("", "a()");
+  expected.add_repeated_mask();
+
+  ow_->RenderString("", "a(,)");
+  expected.add_repeated_mask();
+
+  ow_->RenderString("", "a(field1(field2(field3)))");
+  mask = expected.add_repeated_mask();
+  mask->add_paths("a.field1.field2.field3");
+
+  ow_->RenderString("", "a(field1(field2(field3,field4),field5),field6)");
+  mask = expected.add_repeated_mask();
+  mask->add_paths("a.field1.field2.field3");
+  mask->add_paths("a.field1.field2.field4");
+  mask->add_paths("a.field1.field5");
+  mask->add_paths("a.field6");
+
+  ow_->RenderString("", "a(id,field1(id,field2(field3,field4),field5),field6)");
+  mask = expected.add_repeated_mask();
+  mask->add_paths("a.id");
+  mask->add_paths("a.field1.id");
+  mask->add_paths("a.field1.field2.field3");
+  mask->add_paths("a.field1.field2.field4");
+  mask->add_paths("a.field1.field5");
+  mask->add_paths("a.field6");
+
+  ow_->RenderString("", "a(((field3,field4)))");
+  mask = expected.add_repeated_mask();
+  mask->add_paths("a.field3");
+  mask->add_paths("a.field4");
+
+  ow_->EndList();
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreCloseThanOpenParentheses) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"),
+          StringPiece("Field 'single_mask', Invalid FieldMask 'a(b,c))'. "
+                      "Cannot find matching '(' for all ')'.")));
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->RenderString("single_mask", "a(b,c))");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreOpenThanCloseParentheses) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"),
+          StringPiece(
+              "Field 'single_mask', Invalid FieldMask 'a(((b,c)'. Cannot "
+              "find matching ')' for all '('.")));
+
+  ow_->StartObject("");
+  ow_->RenderString("id", "1");
+  ow_->RenderString("single_mask", "a(((b,c)");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, PathWithMapKeyShouldWork) {
+  FieldMaskTest expected;
+  expected.mutable_single_mask()->add_paths("path.to.map[\"key1\"]");
+  expected.mutable_single_mask()->add_paths(
+      "path.to.map[\"e\\\"[]][scape\\\"\"]");
+  expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]");
+
+  ow_->StartObject("");
+  ow_->RenderString("single_mask",
+                    "path.to.map[\"key1\"],path.to.map[\"e\\\"[]][scape\\\"\"],"
+                    "path.to.map[\"key2\"]");
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest,
+       MapKeyMustBeAtTheEndOfAPathSegment) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"),
+          StringPiece("Field 'single_mask', Invalid FieldMask "
+                      "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. "
+                      "Map keys should be at the end of a path segment.")));
+
+  ow_->StartObject("");
+  ow_->RenderString("single_mask",
+                    "path.to.map[\"key1\"]a,path.to.map[\"key2\"]");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustEnd) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.FieldMask"),
+                   StringPiece("Field 'single_mask', Invalid FieldMask "
+                               "'path.to.map[\"key1\"'. Map keys should be "
+                               "represented as [\"some_key\"].")));
+
+  ow_->StartObject("");
+  ow_->RenderString("single_mask", "path.to.map[\"key1\"");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.FieldMask"),
+                   StringPiece("Field 'single_mask', Invalid FieldMask "
+                               "'path.to.map[\"ke\"y1\"]'. Map keys should be "
+                               "represented as [\"some_key\"].")));
+
+  ow_->StartObject("");
+  ow_->RenderString("single_mask", "path.to.map[\"ke\"y1\"]");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) {
+  FieldMaskTest expected;
+  expected.mutable_single_mask()->add_paths(
+      // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character 孙.
+      // We cannot embed non-ASCII characters in the code directly because
+      // some windows compilers will try to interpret them using the system's
+      // current encoding and end up with invalid UTF-8 byte sequence.
+      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]");
+  expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]");
+
+  ow_->StartObject("");
+  ow_->RenderString(
+      "single_mask",
+      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"],"
+      "path.to.map[\"key2\"]");
+  ow_->EndObject();
+
+  CheckOutput(expected);
+}
+
+class ProtoStreamObjectWriterOneOfsTest
+    : public BaseProtoStreamObjectWriterTest {
+ protected:
+  ProtoStreamObjectWriterOneOfsTest() {
+    vector<const Descriptor*> descriptors;
+    descriptors.push_back(OneOfsRequest::descriptor());
+    descriptors.push_back(google::protobuf::Struct::descriptor());
+    ResetTypeInfo(descriptors);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterOneOfsTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForPrimitiveTypesTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("oneof"),
+          StringPiece(
+              "oneof field 'data' is already set. Cannot set 'intData'")));
+
+  ow_->StartObject("");
+  ow_->RenderString("strData", "blah");
+  ow_->RenderString("intData", "123");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForMessageTypesPrimitiveFirstTest) {
+  // Test for setting primitive oneof field first and then message field.
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'messageData'")));
+
+  // JSON: { "strData": "blah", "messageData": { "dataValue": 123 } }
+  ow_->StartObject("");
+  ow_->RenderString("strData", "blah");
+  ow_->StartObject("messageData");
+  ow_->RenderInt32("dataValue", 123);
+  ow_->EndObject();
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForMessageTypesMessageFirstTest) {
+  // Test for setting message oneof field first and then primitive field.
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'strData'")));
+
+  // JSON: { "messageData": { "dataValue": 123 }, "strData": "blah" }
+  ow_->StartObject("");
+  ow_->StartObject("messageData");
+  ow_->RenderInt32("dataValue", 123);
+  ow_->EndObject();
+  ow_->RenderString("strData", "blah");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForStructTypesPrimitiveFirstTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'structData'")));
+
+  // JSON: { "strData": "blah", "structData": { "a": "b" } }
+  ow_->StartObject("");
+  ow_->RenderString("strData", "blah");
+  ow_->StartObject("structData");
+  ow_->RenderString("a", "b");
+  ow_->EndObject();
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForStructTypesStructFirstTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'strData'")));
+
+  // JSON: { "structData": { "a": "b" }, "strData": "blah" }
+  ow_->StartObject("");
+  ow_->StartObject("structData");
+  ow_->RenderString("a", "b");
+  ow_->EndObject();
+  ow_->RenderString("strData", "blah");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForStructValueTypesTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'valueData'")));
+
+  // JSON: { "messageData": { "dataValue": 123 }, "valueData": { "a": "b" } }
+  ow_->StartObject("");
+  ow_->StartObject("messageData");
+  ow_->RenderInt32("dataValue", 123);
+  ow_->EndObject();
+  ow_->StartObject("valueData");
+  ow_->RenderString("a", "b");
+  ow_->EndObject();
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForWellKnownTypesPrimitiveFirstTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'tsData'")));
+
+  // JSON: { "intData": 123, "tsData": "1970-01-02T01:00:00.000Z" }
+  ow_->StartObject("");
+  ow_->RenderInt32("intData", 123);
+  ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z");
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForWellKnownTypesWktFirstTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'intData'")));
+
+  // JSON: { "tsData": "1970-01-02T01:00:00.000Z", "intData": 123 }
+  ow_->StartObject("");
+  ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z");
+  ow_->RenderInt32("intData", 123);
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForWellKnownTypesAndMessageTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'messageData'")));
+
+  // JSON: { "tsData": "1970-01-02T01:00:00.000Z",
+  //         "messageData": { "dataValue": 123 } }
+  ow_->StartObject("");
+  ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z");
+  ow_->StartObject("messageData");
+  ow_->RenderInt32("dataValue", 123);
+  ow_->EndObject();
+  ow_->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterOneOfsTest,
+       MultipleOneofsFailForOneofWithinAnyTest) {
+  EXPECT_CALL(listener_,
+              InvalidValue(_, StringPiece("oneof"),
+                           StringPiece("oneof field 'data' is already set. "
+                                       "Cannot set 'intData'")));
+
+  using google::protobuf::testing::oneofs::OneOfsRequest;
+  // JSON:
+  // { "anyData":
+  //    { "@type":
+  //       "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest",
+  //     "strData": "blah",
+  //     "intData": 123
+  //    }
+  // }
+  ow_->StartObject("");
+  ow_->StartObject("anyData");
+  ow_->RenderString(
+      "@type",
+      "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest");
+  ow_->RenderString("strData", "blah");
+  ow_->RenderInt32("intData", 123);
+  ow_->EndObject();
+  ow_->EndObject();
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/structured_objectwriter.h b/src/google/protobuf/util/internal/structured_objectwriter.h
new file mode 100644
index 0000000..3f065d6
--- /dev/null
+++ b/src/google/protobuf/util/internal/structured_objectwriter.h
@@ -0,0 +1,118 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/util/internal/object_writer.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+// An StructuredObjectWriter is an ObjectWriter for writing
+// tree-structured data in a stream of events representing objects
+// and collections. Implementation of this interface can be used to
+// write an object stream to an in-memory structure, protobufs,
+// JSON, XML, or any other output format desired. The ObjectSource
+// interface is typically used as the source of an object stream.
+//
+// See JsonObjectWriter for a sample implementation of
+// StructuredObjectWriter and its use.
+//
+// Derived classes could be thread-unsafe.
+class LIBPROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter {
+ public:
+  virtual ~StructuredObjectWriter() {}
+
+ protected:
+  // A base element class for subclasses to extend, makes tracking state easier.
+  //
+  // StructuredObjectWriter behaves as a visitor. BaseElement represents a node
+  // in the input tree. Implementation of StructuredObjectWriter should also
+  // extend BaseElement to keep track of the location in the input tree.
+  class LIBPROTOBUF_EXPORT BaseElement {
+   public:
+    // Takes ownership of the parent Element.
+    explicit BaseElement(BaseElement* parent)
+        : parent_(parent), level_(parent == NULL ? 0 : parent->level() + 1) {}
+    virtual ~BaseElement() {}
+
+    // Releases ownership of the parent and returns a pointer to it.
+    template <typename ElementType>
+    ElementType* pop() {
+      return down_cast<ElementType*>(parent_.release());
+    }
+
+    // Returns true if this element is the root.
+    bool is_root() const { return parent_ == NULL; }
+
+    // Returns the number of hops from this element to the root element.
+    int level() const { return level_; }
+
+   protected:
+    // Returns pointer to parent element without releasing ownership.
+    virtual BaseElement* parent() const { return parent_.get(); }
+
+   private:
+    // Pointer to the parent Element.
+    google::protobuf::scoped_ptr<BaseElement> parent_;
+
+    // Number of hops to the root Element.
+    // The root Element has NULL parent_ and a level_ of 0.
+    const int level_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(BaseElement);
+  };
+
+  StructuredObjectWriter() {}
+
+  // Returns the current element. Used for indentation and name overrides.
+  virtual BaseElement* element() = 0;
+
+ private:
+  // Do not add any data members to this class.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StructuredObjectWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/testdata/anys.proto b/src/google/protobuf/util/internal/testdata/anys.proto
new file mode 100644
index 0000000..18c59cb
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/anys.proto
@@ -0,0 +1,53 @@
+// 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.
+
+// Proto to test Proto3 Any serialization.
+syntax = "proto3";
+
+package google.protobuf.testing.anys;
+option java_package = "com.google.protobuf.testing.anys";
+
+import "google/protobuf/any.proto";
+
+message AnyIn {
+  string something = 1;
+}
+
+message AnyOut {
+  google.protobuf.Any any = 1;
+}
+
+message AnyM {
+  string foo = 1;
+}
+
+service TestService {
+  rpc Call(AnyIn) returns (AnyOut);
+}
diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto
new file mode 100644
index 0000000..1cbbba4
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -0,0 +1,187 @@
+// 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.
+
+// Author: sven@google.com (Sven Mawson)
+//
+// Sample protos for testing.
+syntax = "proto2";
+
+package google.protobuf.testing;
+
+// A book
+message Book {
+  optional string title = 1;
+  optional Author author = 2;
+  optional uint32 length = 3;
+  optional int64 published = 4;
+  optional bytes content = 5;
+
+  optional group Data = 6 {
+    optional uint32 year = 7;
+    optional string copyright = 8;
+  }
+
+  message Label {
+    optional string key = 1;
+    optional string value = 2;
+  }
+
+  optional Publisher publisher = 9;
+  repeated Label labels = 10;
+
+  enum Type {
+    FICTION = 1;
+    KIDS = 2;
+    ACTION_AND_ADVENTURE = 3;
+  }
+  optional Type type = 11;
+
+  extensions 200 to 499;
+}
+
+// A publisher of a book, tests required fields.
+message Publisher {
+  required string name = 1;
+}
+
+// An author of a book
+message Author {
+  optional uint64 id = 1 [json_name = "@id"];
+  optional string name = 2;
+  repeated string pseudonym = 3;
+  optional bool alive = 4;
+  repeated Author friend = 5;
+}
+
+// For testing resiliency of our protostream parser.
+// Field numbers of Author are reused for something else.
+message BadAuthor {
+  optional string id = 1;  // non-length-delimited to length-delimited.
+  repeated uint64 name = 2;  // string to repeated (both length-delimited).
+  optional string pseudonym = 3;  // Repeated to optional.
+  repeated bool alive = 4 [packed=true];  // Optional to repeated.
+}
+
+// All primitive types
+message Primitive {
+  // 32 bit numbers:
+  optional fixed32 fix32 = 1;
+  optional uint32 u32 = 2;
+  optional int32 i32 = 3;
+  optional sfixed32 sf32 = 4;
+  optional sint32 s32 = 5;
+
+  // 64 bit numbers:
+  optional fixed64 fix64 = 6;
+  optional uint64 u64 = 7;
+  optional int64 i64 = 8;
+  optional sfixed64 sf64 = 9;
+  optional sint64 s64 = 10;
+
+  // The other stuff.
+  optional string str = 11;
+  optional bytes bytes = 12;
+  optional float float = 13;
+  optional double double = 14;
+  optional bool bool = 15;
+
+  // repeated 32 bit numbers:
+  repeated fixed32 rep_fix32 = 16;
+  repeated uint32 rep_u32 = 17;
+  repeated int32 rep_i32 = 18;
+  repeated sfixed32 rep_sf32 = 19;
+  repeated sint32 rep_s32 = 20;
+
+  // repeated 64 bit numbers:
+  repeated fixed64 rep_fix64 = 21;
+  repeated uint64 rep_u64 = 22;
+  repeated int64 rep_i64 = 23;
+  repeated sfixed64 rep_sf64 = 24;
+  repeated sint64 rep_s64 = 25;
+
+  // repeated other stuff:
+  repeated string rep_str = 26;
+  repeated bytes rep_bytes = 27;
+  repeated float rep_float = 28;
+  repeated double rep_double = 29;
+  repeated bool rep_bool = 30;
+}
+
+// Test packed versions of all repeated primitives.
+// The field numbers should match their non-packed version in Primitive message.
+message PackedPrimitive {
+  // repeated 32 bit numbers:
+  repeated fixed32 rep_fix32 = 16 [packed=true];
+  repeated uint32 rep_u32 = 17 [packed=true];
+  repeated int32 rep_i32 = 18 [packed=true];
+  repeated sfixed32 rep_sf32 = 19 [packed=true];
+  repeated sint32 rep_s32 = 20 [packed=true];
+
+  // repeated 64 bit numbers:
+  repeated fixed64 rep_fix64 = 21 [packed=true];
+  repeated uint64 rep_u64 = 22 [packed=true];
+  repeated int64 rep_i64 = 23 [packed=true];
+  repeated sfixed64 rep_sf64 = 24 [packed=true];
+  repeated sint64 rep_s64 = 25 [packed=true];
+
+  // repeated other stuff:
+  repeated float rep_float = 28 [packed=true];
+  repeated double rep_double = 29 [packed=true];
+  repeated bool rep_bool = 30 [packed=true];
+}
+
+// Test extensions.
+extend Book {
+  repeated Author more_author = 201;
+}
+
+// Test nested extensions.
+message NestedBook {
+  extend Book {
+    optional NestedBook another_book = 301;
+  }
+  // Recurse
+  optional Book book = 1;
+}
+
+// For testing resiliency of our protostream parser.
+// Field number of NestedBook is reused for something else.
+message BadNestedBook {
+  repeated uint32 book = 1 [packed=true];  // Packed to optional message.
+}
+
+// A recursively defined message.
+message Cyclic {
+  optional int32 m_int = 1;
+  optional string m_str = 2;
+  optional Book m_book = 3;
+  repeated Author m_author = 5;
+  optional Cyclic m_cyclic = 4;
+}
diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto
new file mode 100644
index 0000000..cccc741
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/default_value.proto
@@ -0,0 +1,170 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf.testing;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/wrappers.proto";
+
+message DefaultValueTestCases {
+  DoubleMessage empty_double = 1;
+  DoubleMessage double_with_default_value = 2;
+  DoubleMessage double_with_nondefault_value = 3;
+  DoubleMessage repeated_double = 4;
+  DoubleMessage nested_message = 5;
+  DoubleMessage repeated_nested_message = 6;
+  DoubleMessage double_message_with_oneof = 7;
+  StructMessage empty_struct = 201;
+  StructMessage empty_struct2 = 202;
+  StructMessage struct_with_null_value = 203;
+  StructMessage struct_with_values = 204;
+  StructMessage struct_with_nested_struct = 205;
+  StructMessage struct_with_nested_list = 206;
+  StructMessage struct_with_list_of_nulls = 207;
+  StructMessage struct_with_list_of_lists = 208;
+  StructMessage struct_with_list_of_structs = 209;
+  google.protobuf.Struct top_level_struct = 210;
+  ValueMessage value_wrapper_simple = 212;
+  ValueMessage value_wrapper_with_struct = 213;
+  ValueMessage value_wrapper_with_list = 214;
+  ListValueMessage list_value_wrapper = 215;
+  google.protobuf.Value top_level_value_simple = 216;
+  google.protobuf.Value top_level_value_with_struct = 217;
+  google.protobuf.Value top_level_value_with_list = 218;
+  google.protobuf.ListValue top_level_listvalue = 219;
+  AnyMessage empty_any = 301;
+  AnyMessage type_only_any = 302;
+  AnyMessage recursive_any = 303;
+  AnyMessage any_with_message_value = 304;
+  AnyMessage any_with_nested_message = 305;
+  AnyMessage any_with_message_containing_map = 306;
+  AnyMessage any_with_message_containing_struct = 307;
+  google.protobuf.Any top_level_any = 308;
+  StringtoIntMap empty_map = 401;
+  StringtoIntMap string_to_int = 402;
+  IntToStringMap int_to_string = 403;
+  MixedMap mixed1 = 404;
+  MixedMap2 mixed2 = 405;
+  MixedMap2 empty_mixed2 = 406;
+  MessageMap map_of_objects = 407;
+  MixedMap mixed_empty = 408;
+  MessageMap message_map_empty = 409;
+  DoubleValueMessage double_value = 501;
+  DoubleValueMessage double_value_default = 502;
+}
+
+message DoubleMessage {
+  double double_value = 1;
+  repeated double repeated_double = 2;
+  DoubleMessage nested_message = 3;
+  repeated DoubleMessage repeated_nested_message = 4;
+  google.protobuf.DoubleValue double_wrapper = 100;
+  oneof value {
+    string str_value = 112;
+    int64 num_value = 113;
+  }
+}
+
+message StructMessage {
+  google.protobuf.Struct struct = 1;
+}
+
+message ValueMessage {
+  google.protobuf.Value value = 1;
+}
+
+message ListValueMessage {
+  google.protobuf.ListValue shopping_list = 1;
+}
+message RequestMessage {
+  string content = 1;
+}
+
+// A test service.
+service DefaultValueTestService {
+  // A test method.
+  rpc Call(RequestMessage) returns (DefaultValueTestCases);
+}
+
+message AnyMessage {
+  google.protobuf.Any any = 1;
+  AnyData data = 2;
+}
+
+message AnyData {
+  int32 attr = 1;
+  string str = 2;
+  repeated string msgs = 3;
+  AnyData nested_data = 4;
+  map<string, string> map_data = 7;
+  google.protobuf.Struct struct_data = 8;
+  repeated AnyData repeated_data = 9;
+}
+
+message StringtoIntMap {
+  map<string, int32> map = 1;
+}
+
+message IntToStringMap {
+  map<int32, string> map = 1;
+}
+
+message MixedMap {
+  string msg = 1;
+  map<string, float> map = 2;
+  int32 int_value = 3;
+}
+
+message MixedMap2 {
+  enum E {
+    E0 = 0;
+    E1 = 1;
+    E2 = 2;
+    E3 = 3;
+  }
+  map<int32, bool> map = 1;
+  E ee = 2;
+  string msg = 4;
+}
+
+message MessageMap {
+  message M {
+    int32 inner_int = 1;
+    string inner_text = 2;
+  }
+  map<string, M> map = 1;
+}
+
+message DoubleValueMessage {
+  google.protobuf.DoubleValue double = 1;
+}
diff --git a/src/google/protobuf/util/internal/testdata/default_value_test.proto b/src/google/protobuf/util/internal/testdata/default_value_test.proto
new file mode 100644
index 0000000..9328834
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/default_value_test.proto
@@ -0,0 +1,53 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf.testing;
+
+message DefaultValueTest {
+  double double_value = 1;
+  repeated double repeated_double = 2;
+  float float_value = 3;
+  int64 int64_value = 5;
+  uint64 uint64_value = 7;
+  int32 int32_value = 9;
+  uint32 uint32_value = 11;
+  bool bool_value = 13;
+  string string_value = 15;
+  bytes bytes_value = 17 [ctype = CORD];
+
+  enum EnumDefault {
+    ENUM_FIRST = 0;
+    ENUM_SECOND = 1;
+    ENUM_THIRD = 2;
+  }
+  EnumDefault enum_value = 18;
+}
diff --git a/src/google/protobuf/util/internal/testdata/field_mask.proto b/src/google/protobuf/util/internal/testdata/field_mask.proto
new file mode 100644
index 0000000..e8b2bc5
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/field_mask.proto
@@ -0,0 +1,71 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf.testing;
+
+import "google/protobuf/field_mask.proto";
+
+message NestedFieldMask {
+  string data = 1;
+  google.protobuf.FieldMask single_mask = 2;
+  repeated google.protobuf.FieldMask repeated_mask = 3;
+}
+
+message FieldMaskTest {
+  string id = 1;
+  google.protobuf.FieldMask single_mask = 2;
+  repeated google.protobuf.FieldMask repeated_mask = 3;
+  repeated NestedFieldMask nested_mask = 4;
+}
+
+message FieldMaskTestCases {
+  FieldMaskWrapper single_mask = 1;
+  FieldMaskWrapper multiple_mask = 2;
+  FieldMaskWrapper snake_camel = 3;
+  FieldMaskWrapper empty_field = 4;
+  FieldMaskWrapper apiary_format1 = 5;
+  FieldMaskWrapper apiary_format2 = 6;
+  FieldMaskWrapper apiary_format3 = 7;
+  FieldMaskWrapper map_key1 = 8;
+  FieldMaskWrapper map_key2 = 9;
+  FieldMaskWrapper map_key3 = 10;
+  FieldMaskWrapper map_key4 = 11;
+  FieldMaskWrapper map_key5 = 12;
+}
+
+message FieldMaskWrapper {
+  google.protobuf.FieldMask mask = 1;
+}
+
+service FieldMaskTestService {
+  rpc Call(FieldMaskTestCases) returns (FieldMaskTestCases);
+}
diff --git a/src/google/protobuf/util/internal/testdata/maps.proto b/src/google/protobuf/util/internal/testdata/maps.proto
new file mode 100644
index 0000000..6475ecd
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/maps.proto
@@ -0,0 +1,86 @@
+// 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.
+
+// Proto to test proto3 maps.
+syntax = "proto3";
+
+package google.protobuf.testing.maps;
+option java_package = "com.google.protobuf.testing.maps";
+
+message MapIn {
+  string other = 1;
+  repeated string things = 2;
+  map<string, string> map_input = 3;
+}
+
+message MapOut {
+  map<string, MapM> map1 = 1;
+  map<string, MapOut> map2 = 2;
+  map<int32, string> map3 = 3;
+  map<bool, string> map4 = 5;
+  string bar = 4;
+}
+
+// A message with exactly the same wire representation as MapOut, but using
+// repeated message fields instead of map fields. We use this message to test
+// the wire-format compatibility of the JSON transcoder (e.g., whether it
+// handles missing keys correctly).
+message MapOutWireFormat {
+  message Map1Entry {
+    string key = 1;
+    MapM value = 2;
+  }
+  repeated Map1Entry map1 = 1;
+  message Map2Entry {
+    string key = 1;
+    MapOut value = 2;
+  }
+  repeated Map2Entry map2 = 2;
+  message Map3Entry {
+    int32 key = 1;
+    string value = 2;
+  }
+  repeated Map3Entry map3 = 3;
+  message Map4Entry {
+    bool key = 1;
+    string value = 2;
+  }
+  repeated Map4Entry map4 = 5;
+  string bar = 4;
+}
+
+message MapM {
+  string foo = 1;
+}
+
+service TestService {
+  rpc Call1(MapIn) returns (MapOut);
+  rpc Call2(MapIn) returns (MapOut);
+}
diff --git a/src/google/protobuf/util/internal/testdata/oneofs.proto b/src/google/protobuf/util/internal/testdata/oneofs.proto
new file mode 100644
index 0000000..5bc9fa0
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/oneofs.proto
@@ -0,0 +1,68 @@
+// 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.
+
+// Proto to test oneofs.
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+
+package google.protobuf.testing.oneofs;
+option java_package = "com.google.protobuf.testing.oneofs";
+
+message OneOfsRequest {
+  string value = 1;
+  oneof data {
+    string str_data = 2;
+    int32 int_data = 3;
+    // Simple message
+    Data message_data = 4;
+    // Well known types
+    google.protobuf.Struct struct_data = 5;
+    google.protobuf.Value value_data = 6;
+    google.protobuf.ListValue list_value_data = 7;
+    google.protobuf.Timestamp ts_data = 8;
+  }
+  google.protobuf.Any any_data = 19;
+}
+
+message Data {
+  int32 data_value = 1;
+}
+
+message Response {
+  string value = 1;
+}
+
+service TestService {
+  // Test call.
+  rpc Call(OneOfsRequest) returns (Response);
+}
diff --git a/src/google/protobuf/util/internal/testdata/struct.proto b/src/google/protobuf/util/internal/testdata/struct.proto
new file mode 100644
index 0000000..c15aba0
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/struct.proto
@@ -0,0 +1,45 @@
+// 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.
+
+// Proto to test proto3 struct.
+syntax = "proto3";
+
+package google.protobuf.testing.structs;
+option java_package = "com.google.protobuf.testing.structs";
+
+import "google/protobuf/struct.proto";
+
+message StructType {
+  google.protobuf.Struct object = 1;
+}
+
+service TestService {
+  rpc Call(StructType) returns (StructType);
+}
diff --git a/src/google/protobuf/util/internal/testdata/timestamp_duration.proto b/src/google/protobuf/util/internal/testdata/timestamp_duration.proto
new file mode 100644
index 0000000..56351f1
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/timestamp_duration.proto
@@ -0,0 +1,47 @@
+// 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.
+
+// Proto to test proto3 Timestamp and Duration.
+syntax = "proto3";
+
+package google.protobuf.testing.timestampduration;
+option java_package = "com.google.protobuf.testing.timestampduration";
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+
+message TimestampDuration {
+  google.protobuf.Timestamp ts = 1;
+  google.protobuf.Duration dur = 2;
+}
+
+service TestService {
+  rpc Call(TimestampDuration) returns (TimestampDuration);
+}
diff --git a/src/google/protobuf/util/internal/testdata/wrappers.proto b/src/google/protobuf/util/internal/testdata/wrappers.proto
new file mode 100644
index 0000000..eabc99f
--- /dev/null
+++ b/src/google/protobuf/util/internal/testdata/wrappers.proto
@@ -0,0 +1,100 @@
+// 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.
+
+syntax = "proto3";
+
+package google.protobuf.testing;
+
+import "google/protobuf/wrappers.proto";
+
+// Top-level test cases proto used by MarshallingTest. See description
+// at the top of the class MarshallingTest for details on how to write
+// test cases.
+message WrappersTestCases {
+  DoubleWrapper double_wrapper = 1;
+  FloatWrapper float_wrapper = 2;
+  Int64Wrapper int64_wrapper = 3;
+  UInt64Wrapper uint64_wrapper = 4;
+  Int32Wrapper int32_wrapper = 5;
+  UInt32Wrapper uint32_wrapper = 6;
+  BoolWrapper bool_wrapper = 7;
+  StringWrapper string_wrapper = 8;
+  BytesWrapper bytes_wrapper = 9;
+
+  DoubleWrapper double_wrapper_default = 10;
+  FloatWrapper float_wrapper_default = 11;
+  Int64Wrapper int64_wrapper_default = 12;
+  UInt64Wrapper uint64_wrapper_default = 13;
+  Int32Wrapper int32_wrapper_default = 14;
+  UInt32Wrapper uint32_wrapper_default = 15;
+  BoolWrapper bool_wrapper_default = 16;
+  StringWrapper string_wrapper_default = 17;
+  BytesWrapper bytes_wrapper_default = 18;
+}
+
+message DoubleWrapper {
+  google.protobuf.DoubleValue double = 1;
+}
+
+message FloatWrapper {
+  google.protobuf.FloatValue float = 1;
+}
+
+message Int64Wrapper {
+  google.protobuf.Int64Value int64 = 1;
+}
+
+message UInt64Wrapper {
+  google.protobuf.UInt64Value uint64 = 1;
+}
+
+message Int32Wrapper {
+  google.protobuf.Int32Value int32 = 1;
+}
+
+message UInt32Wrapper {
+  google.protobuf.UInt32Value uint32 = 1;
+}
+
+message BoolWrapper {
+  google.protobuf.BoolValue bool = 1;
+}
+
+message StringWrapper {
+  google.protobuf.StringValue string = 1;
+}
+
+message BytesWrapper {
+  google.protobuf.BytesValue bytes = 1;
+}
+
+service WrappersTestService {
+  rpc Call(WrappersTestCases) returns (WrappersTestCases);
+}
diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc
new file mode 100644
index 0000000..00a8ee7
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info.cc
@@ -0,0 +1,171 @@
+// 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.
+
+#include <google/protobuf/util/internal/type_info.h>
+
+#include <map>
+#include <set>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+// A TypeInfo that looks up information provided by a TypeResolver.
+class TypeInfoForTypeResolver : public TypeInfo {
+ public:
+  explicit TypeInfoForTypeResolver(TypeResolver* type_resolver)
+      : type_resolver_(type_resolver) {}
+
+  virtual ~TypeInfoForTypeResolver() {
+    DeleteCachedTypes(&cached_types_);
+    DeleteCachedTypes(&cached_enums_);
+  }
+
+  virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
+      StringPiece type_url) const {
+    map<StringPiece, StatusOrType>::iterator it = cached_types_.find(type_url);
+    if (it != cached_types_.end()) {
+      return it->second;
+    }
+    // Stores the string value so it can be referenced using StringPiece in the
+    // cached_types_ map.
+    const string& string_type_url =
+        *string_storage_.insert(type_url.ToString()).first;
+    google::protobuf::scoped_ptr<google::protobuf::Type> type(new google::protobuf::Type());
+    util::Status status =
+        type_resolver_->ResolveMessageType(string_type_url, type.get());
+    StatusOrType result =
+        status.ok() ? StatusOrType(type.release()) : StatusOrType(status);
+    cached_types_[string_type_url] = result;
+    return result;
+  }
+
+  virtual const google::protobuf::Type* GetTypeByTypeUrl(
+      StringPiece type_url) const {
+    StatusOrType result = ResolveTypeUrl(type_url);
+    return result.ok() ? result.ValueOrDie() : NULL;
+  }
+
+  virtual const google::protobuf::Enum* GetEnumByTypeUrl(
+      StringPiece type_url) const {
+    map<StringPiece, StatusOrEnum>::iterator it = cached_enums_.find(type_url);
+    if (it != cached_enums_.end()) {
+      return it->second.ok() ? it->second.ValueOrDie() : NULL;
+    }
+    // Stores the string value so it can be referenced using StringPiece in the
+    // cached_enums_ map.
+    const string& string_type_url =
+        *string_storage_.insert(type_url.ToString()).first;
+    google::protobuf::scoped_ptr<google::protobuf::Enum> enum_type(
+        new google::protobuf::Enum());
+    util::Status status =
+        type_resolver_->ResolveEnumType(string_type_url, enum_type.get());
+    StatusOrEnum result =
+        status.ok() ? StatusOrEnum(enum_type.release()) : StatusOrEnum(status);
+    cached_enums_[string_type_url] = result;
+    return result.ok() ? result.ValueOrDie() : NULL;
+  }
+
+  virtual const google::protobuf::Field* FindField(
+      const google::protobuf::Type* type, StringPiece camel_case_name) const {
+    if (indexed_types_.find(type) == indexed_types_.end()) {
+      PopulateNameLookupTable(type);
+      indexed_types_.insert(type);
+    }
+    StringPiece name =
+        FindWithDefault(camel_case_name_table_, camel_case_name, StringPiece());
+    if (name.empty()) {
+      // Didn't find a mapping. Use whatever provided.
+      name = camel_case_name;
+    }
+    return FindFieldInTypeOrNull(type, name);
+  }
+
+ private:
+  typedef util::StatusOr<const google::protobuf::Type*> StatusOrType;
+  typedef util::StatusOr<const google::protobuf::Enum*> StatusOrEnum;
+
+  template <typename T>
+  static void DeleteCachedTypes(map<StringPiece, T>* cached_types) {
+    for (typename map<StringPiece, T>::iterator it = cached_types->begin();
+         it != cached_types->end(); ++it) {
+      if (it->second.ok()) {
+        delete it->second.ValueOrDie();
+      }
+    }
+  }
+
+  void PopulateNameLookupTable(const google::protobuf::Type* type) const {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      StringPiece name = field.name();
+      StringPiece camel_case_name = field.json_name();
+      const StringPiece* existing = InsertOrReturnExisting(
+          &camel_case_name_table_, camel_case_name, name);
+      if (existing && *existing != name) {
+        GOOGLE_LOG(WARNING) << "Field '" << name << "' and '" << *existing
+                     << "' map to the same camel case name '" << camel_case_name
+                     << "'.";
+      }
+    }
+  }
+
+  TypeResolver* type_resolver_;
+
+  // Stores string values that will be referenced by StringPieces in
+  // cached_types_, cached_enums_ and camel_case_name_table_.
+  mutable set<string> string_storage_;
+
+  mutable map<StringPiece, StatusOrType> cached_types_;
+  mutable map<StringPiece, StatusOrEnum> cached_enums_;
+
+  mutable set<const google::protobuf::Type*> indexed_types_;
+  mutable map<StringPiece, StringPiece> camel_case_name_table_;
+};
+}  // namespace
+
+TypeInfo* TypeInfo::NewTypeInfo(TypeResolver* type_resolver) {
+  return new TypeInfoForTypeResolver(type_resolver);
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/type_info.h b/src/google/protobuf/util/internal/type_info.h
new file mode 100644
index 0000000..d813317
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+// Internal helper class for type resolving. Note that this class is not
+// thread-safe and should only be accessed in one thread.
+class LIBPROTOBUF_EXPORT TypeInfo {
+ public:
+  TypeInfo() {}
+  virtual ~TypeInfo() {}
+
+  // Resolves a type url into a Type. If the type url is invalid, returns
+  // INVALID_ARGUMENT error status. If the type url is valid but the
+  // corresponding type cannot be found, returns a NOT_FOUND error status.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Resolves a type url into a Type. Like ResolveTypeUrl() but returns
+  // NULL if the type url is invalid or the type cannot be found.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual const google::protobuf::Type* GetTypeByTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Resolves a type url for an enum. Returns NULL if the type url is
+  // invalid or the type cannot be found.
+  //
+  // This TypeInfo class retains the ownership of the returned pointer.
+  virtual const google::protobuf::Enum* GetEnumByTypeUrl(
+      StringPiece type_url) const = 0;
+
+  // Looks up a field in the specified type given a CamelCase name.
+  virtual const google::protobuf::Field* FindField(
+      const google::protobuf::Type* type,
+      StringPiece camel_case_name) const = 0;
+
+  // Creates a TypeInfo object that looks up type information from a
+  // TypeResolver. Caller takes ownership of the returned pointer.
+  static TypeInfo* NewTypeInfo(TypeResolver* type_resolver);
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeInfo);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc
new file mode 100644
index 0000000..49e18ed
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info_test_helper.cc
@@ -0,0 +1,134 @@
+// 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.
+
+#include <google/protobuf/util/internal/type_info_test_helper.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/util/type_resolver_util.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+namespace testing {
+
+
+void TypeInfoTestHelper::ResetTypeInfo(
+    const vector<const Descriptor*>& descriptors) {
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      const DescriptorPool* pool = descriptors[0]->file()->pool();
+      for (int i = 1; i < descriptors.size(); ++i) {
+        GOOGLE_CHECK(pool == descriptors[i]->file()->pool())
+            << "Descriptors from different pools are not supported.";
+      }
+      type_resolver_.reset(
+          NewTypeResolverForDescriptorPool(kTypeServiceBaseUrl, pool));
+      typeinfo_.reset(TypeInfo::NewTypeInfo(type_resolver_.get()));
+      return;
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+}
+
+void TypeInfoTestHelper::ResetTypeInfo(const Descriptor* descriptor) {
+  vector<const Descriptor*> descriptors;
+  descriptors.push_back(descriptor);
+  ResetTypeInfo(descriptors);
+}
+
+void TypeInfoTestHelper::ResetTypeInfo(const Descriptor* descriptor1,
+                                       const Descriptor* descriptor2) {
+  vector<const Descriptor*> descriptors;
+  descriptors.push_back(descriptor1);
+  descriptors.push_back(descriptor2);
+  ResetTypeInfo(descriptors);
+}
+
+TypeInfo* TypeInfoTestHelper::GetTypeInfo() { return typeinfo_.get(); }
+
+ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource(
+    io::CodedInputStream* coded_input, const string& type_url) {
+  const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new ProtoStreamObjectSource(coded_input, type_resolver_.get(),
+                                         *type);
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+  return NULL;
+}
+
+ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter(
+    const string& type_url, strings::ByteSink* output, ErrorListener* listener,
+    const ProtoStreamObjectWriter::Options& options) {
+  const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output,
+                                         listener, options);
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+  return NULL;
+}
+
+DefaultValueObjectWriter* TypeInfoTestHelper::NewDefaultValueWriter(
+    const string& type_url, ObjectWriter* writer) {
+  const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url);
+  switch (type_) {
+    case USE_TYPE_RESOLVER: {
+      return new DefaultValueObjectWriter(type_resolver_.get(), *type, writer);
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Can not reach here.";
+  return NULL;
+}
+
+}  // namespace testing
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/type_info_test_helper.h b/src/google/protobuf/util/internal/type_info_test_helper.h
new file mode 100644
index 0000000..1a27984
--- /dev/null
+++ b/src/google/protobuf/util/internal/type_info_test_helper.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_TEST_HELPER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_TEST_HELPER_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+namespace testing {
+
+enum TypeInfoSource {
+  USE_TYPE_RESOLVER,
+};
+
+// In the unit-tests we want to test two scenarios: one with type info from
+// ServiceTypeInfo, the other with type info from TypeResolver. This class
+// wraps the detail of where the type info is from and provides the same
+// interface so the same unit-test code can test both scenarios.
+class TypeInfoTestHelper {
+ public:
+  explicit TypeInfoTestHelper(TypeInfoSource type) : type_(type) {}
+
+  // Creates a TypeInfo object for the given set of descriptors.
+  void ResetTypeInfo(const vector<const Descriptor*>& descriptors);
+
+  // Convinent overloads.
+  void ResetTypeInfo(const Descriptor* descriptor);
+  void ResetTypeInfo(const Descriptor* descriptor1,
+                     const Descriptor* descriptor2);
+
+  // Returns the TypeInfo created after ResetTypeInfo.
+  TypeInfo* GetTypeInfo();
+
+  ProtoStreamObjectSource* NewProtoSource(io::CodedInputStream* coded_input,
+                                          const string& type_url);
+
+  ProtoStreamObjectWriter* NewProtoWriter(
+      const string& type_url, strings::ByteSink* output,
+      ErrorListener* listener, const ProtoStreamObjectWriter::Options& options);
+
+  DefaultValueObjectWriter* NewDefaultValueWriter(const string& type_url,
+                                                  ObjectWriter* writer);
+
+ private:
+  TypeInfoSource type_;
+  google::protobuf::scoped_ptr<TypeInfo> typeinfo_;
+  google::protobuf::scoped_ptr<TypeResolver> type_resolver_;
+};
+}  // namespace testing
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_TEST_HELPER_H__
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
new file mode 100644
index 0000000..d58de0d
--- /dev/null
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -0,0 +1,361 @@
+// 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.
+
+#include <google/protobuf/util/internal/utility.h>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/mathlimits.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+namespace {
+const StringPiece SkipWhiteSpace(StringPiece str) {
+  StringPiece::size_type i;
+  for (i = 0; i < str.size() && ascii_isspace(str[i]); ++i) {
+  }
+  GOOGLE_DCHECK(i == str.size() || !ascii_isspace(str[i]));
+  return StringPiece(str, i);
+}
+}  // namespace
+
+bool GetBoolOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, bool default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == NULL) {
+    return default_value;
+  }
+  return GetBoolFromAny(opt->value());
+}
+
+int64 GetInt64OptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, int64 default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == NULL) {
+    return default_value;
+  }
+  return GetInt64FromAny(opt->value());
+}
+
+double GetDoubleOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, double default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == NULL) {
+    return default_value;
+  }
+  return GetDoubleFromAny(opt->value());
+}
+
+string GetStringOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, const string& default_value) {
+  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
+  if (opt == NULL) {
+    return default_value;
+  }
+  return GetStringFromAny(opt->value());
+}
+
+template <typename T>
+void ParseFromAny(const string& data, T* result) {
+  result->ParseFromString(data);
+}
+
+// Returns a boolean value contained in Any type.
+// TODO(skarvaje): Add type checking & error messages here.
+bool GetBoolFromAny(const google::protobuf::Any& any) {
+  google::protobuf::BoolValue b;
+  ParseFromAny(any.value(), &b);
+  return b.value();
+}
+
+int64 GetInt64FromAny(const google::protobuf::Any& any) {
+  google::protobuf::Int64Value i;
+  ParseFromAny(any.value(), &i);
+  return i.value();
+}
+
+double GetDoubleFromAny(const google::protobuf::Any& any) {
+  google::protobuf::DoubleValue i;
+  ParseFromAny(any.value(), &i);
+  return i.value();
+}
+
+string GetStringFromAny(const google::protobuf::Any& any) {
+  google::protobuf::StringValue s;
+  ParseFromAny(any.value(), &s);
+  return s.value();
+}
+
+const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
+  size_t idx = type_url.rfind('/');
+  return type_url.substr(idx + 1);
+}
+
+const string GetFullTypeWithUrl(StringPiece simple_type) {
+  return StrCat(kTypeServiceBaseUrl, "/", simple_type);
+}
+
+const google::protobuf::Option* FindOptionOrNull(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name) {
+  for (int i = 0; i < options.size(); ++i) {
+    const google::protobuf::Option& opt = options.Get(i);
+    if (opt.name() == option_name) {
+      return &opt;
+    }
+  }
+  return NULL;
+}
+
+const google::protobuf::Field* FindFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece field_name) {
+  if (type != NULL) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.name() == field_name) {
+        return &field;
+      }
+    }
+  }
+  return NULL;
+}
+
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name) {
+  if (type != NULL) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.json_name() == json_name) {
+        return &field;
+      }
+    }
+  }
+  return NULL;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
+  if (enum_type != NULL) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      if (enum_value.name() == enum_name) {
+        return &enum_value;
+      }
+    }
+  }
+  return NULL;
+}
+
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32 value) {
+  if (enum_type != NULL) {
+    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
+      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
+      if (enum_value.number() == value) {
+        return &enum_value;
+      }
+    }
+  }
+  return NULL;
+}
+
+string ToCamelCase(const StringPiece input) {
+  bool capitalize_next = false;
+  bool was_cap = true;
+  bool is_cap = false;
+  bool first_word = true;
+  string result;
+  result.reserve(input.size());
+
+  for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
+    is_cap = ascii_isupper(input[i]);
+    if (input[i] == '_') {
+      capitalize_next = true;
+      if (!result.empty()) first_word = false;
+      continue;
+    } else if (first_word) {
+      // Consider when the current character B is capitalized,
+      // first word ends when:
+      // 1) following a lowercase:   "...aB..."
+      // 2) followed by a lowercase: "...ABc..."
+      if (!result.empty() && is_cap &&
+          (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
+        first_word = false;
+        result.push_back(input[i]);
+      } else {
+        result.push_back(ascii_tolower(input[i]));
+        continue;
+      }
+    } else if (capitalize_next) {
+      capitalize_next = false;
+      if (ascii_islower(input[i])) {
+        result.push_back(ascii_toupper(input[i]));
+        continue;
+      } else {
+        result.push_back(input[i]);
+        continue;
+      }
+    } else {
+      result.push_back(ascii_tolower(input[i]));
+    }
+  }
+  return result;
+}
+
+string ToSnakeCase(StringPiece input) {
+  bool was_not_underscore = false;  // Initialize to false for case 1 (below)
+  bool was_not_cap = false;
+  string result;
+  result.reserve(input.size() << 1);
+
+  for (size_t i = 0; i < input.size(); ++i) {
+    if (ascii_isupper(input[i])) {
+      // Consider when the current character B is capitalized:
+      // 1) At beginning of input:   "B..." => "b..."
+      //    (e.g. "Biscuit" => "biscuit")
+      // 2) Following a lowercase:   "...aB..." => "...a_b..."
+      //    (e.g. "gBike" => "g_bike")
+      // 3) At the end of input:     "...AB" => "...ab"
+      //    (e.g. "GoogleLAB" => "google_lab")
+      // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
+      //    (e.g. "GBike" => "g_bike")
+      if (was_not_underscore &&               //            case 1 out
+          (was_not_cap ||                     // case 2 in, case 3 out
+           (i + 1 < input.size() &&           //            case 3 out
+            ascii_islower(input[i + 1])))) {  // case 4 in
+        // We add an underscore for case 2 and case 4.
+        result.push_back('_');
+      }
+      result.push_back(ascii_tolower(input[i]));
+      was_not_underscore = true;
+      was_not_cap = false;
+    } else {
+      result.push_back(input[i]);
+      was_not_underscore = input[i] != '_';
+      was_not_cap = true;
+    }
+  }
+  return result;
+}
+
+set<string>* well_known_types_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(well_known_types_init_);
+const char* well_known_types_name_array_[] = {
+    "google.protobuf.Timestamp",   "google.protobuf.Duration",
+    "google.protobuf.DoubleValue", "google.protobuf.FloatValue",
+    "google.protobuf.Int64Value",  "google.protobuf.UInt64Value",
+    "google.protobuf.Int32Value",  "google.protobuf.UInt32Value",
+    "google.protobuf.BoolValue",   "google.protobuf.StringValue",
+    "google.protobuf.BytesValue",  "google.protobuf.FieldMask"};
+
+void DeleteWellKnownTypes() { delete well_known_types_; }
+
+void InitWellKnownTypes() {
+  well_known_types_ = new set<string>;
+  for (int i = 0; i < GOOGLE_ARRAYSIZE(well_known_types_name_array_); ++i) {
+    well_known_types_->insert(well_known_types_name_array_[i]);
+  }
+  google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes);
+}
+
+bool IsWellKnownType(const string& type_name) {
+  InitWellKnownTypes();
+  return ContainsKey(*well_known_types_, type_name);
+}
+
+bool IsValidBoolString(const string& bool_string) {
+  return bool_string == "true" || bool_string == "false" ||
+         bool_string == "1" || bool_string == "0";
+}
+
+bool IsMap(const google::protobuf::Field& field,
+           const google::protobuf::Type& type) {
+  return (field.cardinality() ==
+              google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
+          GetBoolOptionOrDefault(type.options(),
+                                 "google.protobuf.MessageOptions.map_entry", false));
+}
+
+bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
+  return GetBoolOptionOrDefault(
+      type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false);
+}
+
+string DoubleAsString(double value) {
+  if (MathLimits<double>::IsPosInf(value)) return "Infinity";
+  if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
+  if (MathLimits<double>::IsNaN(value)) return "NaN";
+
+  return SimpleDtoa(value);
+}
+
+string FloatAsString(float value) {
+  if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
+  return DoubleAsString(value);
+}
+
+bool SafeStrToFloat(StringPiece str, float* value) {
+  double double_value;
+  if (!safe_strtod(str, &double_value)) {
+    return false;
+  }
+
+  if (MathLimits<double>::IsInf(double_value) ||
+      MathLimits<double>::IsNaN(double_value))
+    return false;
+
+  // Fail if the value is not representable in float.
+  if (double_value > std::numeric_limits<float>::max() ||
+      double_value < -std::numeric_limits<float>::max()) {
+    return false;
+  }
+
+  *value = static_cast<float>(double_value);
+  return true;
+}
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
new file mode 100644
index 0000000..33df8ed
--- /dev/null
+++ b/src/google/protobuf/util/internal/utility.h
@@ -0,0 +1,193 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <utility>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/stringpiece.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+class Method;
+class Any;
+class Bool;
+class Option;
+class Field;
+class Type;
+class Enum;
+class EnumValue;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+// Finds the tech option identified by option_name. Parses the boolean value and
+// returns it.
+// When the option with the given name is not found, default_value is returned.
+LIBPROTOBUF_EXPORT bool GetBoolOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, bool default_value);
+
+// Returns int64 option value. If the option isn't found, returns the
+// default_value.
+LIBPROTOBUF_EXPORT int64 GetInt64OptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, int64 default_value);
+
+// Returns double option value. If the option isn't found, returns the
+// default_value.
+LIBPROTOBUF_EXPORT double GetDoubleOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, double default_value);
+
+// Returns string option value. If the option isn't found, returns the
+// default_value.
+LIBPROTOBUF_EXPORT string GetStringOptionOrDefault(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name, const string& default_value);
+
+// Returns a boolean value contained in Any type.
+// TODO(skarvaje): Make these utilities dealing with Any types more generic,
+// add more error checking and move to a more public/sharable location so others
+// can use.
+LIBPROTOBUF_EXPORT bool GetBoolFromAny(const google::protobuf::Any& any);
+
+// Returns int64 value contained in Any type.
+LIBPROTOBUF_EXPORT int64 GetInt64FromAny(const google::protobuf::Any& any);
+
+// Returns double value contained in Any type.
+LIBPROTOBUF_EXPORT double GetDoubleFromAny(const google::protobuf::Any& any);
+
+// Returns string value contained in Any type.
+LIBPROTOBUF_EXPORT string GetStringFromAny(const google::protobuf::Any& any);
+
+// Returns the type string without the url prefix. e.g.: If the passed type is
+// 'type.googleapis.com/tech.type.Bool', the returned value is 'tech.type.Bool'.
+LIBPROTOBUF_EXPORT const StringPiece GetTypeWithoutUrl(StringPiece type_url);
+
+// Returns the simple_type with the base type url (kTypeServiceBaseUrl)
+// prefixed.
+//
+// E.g:
+// GetFullTypeWithUrl("google.protobuf.Timestamp") returns the string
+// "type.googleapis.com/google.protobuf.Timestamp".
+LIBPROTOBUF_EXPORT const string GetFullTypeWithUrl(StringPiece simple_type);
+
+// Finds and returns option identified by name and option_name within the
+// provided map. Returns NULL if none found.
+const google::protobuf::Option* FindOptionOrNull(
+    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
+    const string& option_name);
+
+// Finds and returns the field identified by field_name in the passed tech Type
+// object. Returns NULL if none found.
+const google::protobuf::Field* FindFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece field_name);
+
+// Similar to FindFieldInTypeOrNull, but this looks up fields with given
+// json_name.
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name);
+
+// Finds and returns the EnumValue identified by enum_name in the passed tech
+// Enum object. Returns NULL if none found.
+const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
+    const google::protobuf::Enum* enum_type, StringPiece enum_name);
+
+// Finds and returns the EnumValue identified by value in the passed tech
+// Enum object. Returns NULL if none found.
+const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
+    const google::protobuf::Enum* enum_type, int32 value);
+
+// Converts input to camel-case and returns it.
+LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input);
+
+// Converts input to snake_case and returns it.
+LIBPROTOBUF_EXPORT string ToSnakeCase(StringPiece input);
+
+// Returns true if type_name represents a well-known type.
+LIBPROTOBUF_EXPORT bool IsWellKnownType(const string& type_name);
+
+// Returns true if 'bool_string' represents a valid boolean value. Only "true",
+// "false", "0" and "1" are allowed.
+LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string);
+
+// Returns true if "field" is a protobuf map field based on its type.
+LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field,
+           const google::protobuf::Type& type);
+
+// Returns true if the given type has special MessageSet wire format.
+bool IsMessageSetWireFormat(const google::protobuf::Type& type);
+
+// Infinity/NaN-aware conversion to string.
+LIBPROTOBUF_EXPORT string DoubleAsString(double value);
+LIBPROTOBUF_EXPORT string FloatAsString(float value);
+
+// Convert from int32, int64, uint32, uint64, double or float to string.
+template <typename T>
+string ValueAsString(T value) {
+  return SimpleItoa(value);
+}
+
+template <>
+inline string ValueAsString(float value) {
+  return FloatAsString(value);
+}
+
+template <>
+inline string ValueAsString(double value) {
+  return DoubleAsString(value);
+}
+
+// Converts a string to float. Unlike safe_strtof, conversion will fail if the
+// value fits into double but not float (e.g., DBL_MAX).
+LIBPROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value);
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
new file mode 100644
index 0000000..a1e24c1
--- /dev/null
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -0,0 +1,176 @@
+// 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.
+
+syntax = "proto3";
+
+package proto3;
+
+
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/any.proto";
+import "google/protobuf/field_mask.proto";
+
+enum EnumType {
+  FOO = 0;
+  BAR = 1;
+}
+
+message MessageType {
+  int32 value = 1;
+}
+
+message TestMessage {
+  bool bool_value = 1;
+  int32 int32_value = 2;
+  int64 int64_value = 3;
+  uint32 uint32_value = 4;
+  uint64 uint64_value = 5;
+  float float_value = 6;
+  double double_value = 7;
+  string string_value = 8;
+  bytes bytes_value = 9;
+  EnumType enum_value = 10;
+  MessageType message_value = 11;
+
+  repeated bool repeated_bool_value = 21;
+  repeated int32 repeated_int32_value = 22;
+  repeated int64 repeated_int64_value = 23;
+  repeated uint32 repeated_uint32_value = 24;
+  repeated uint64 repeated_uint64_value = 25;
+  repeated float repeated_float_value = 26;
+  repeated double repeated_double_value = 27;
+  repeated string repeated_string_value = 28;
+  repeated bytes repeated_bytes_value = 29;
+  repeated EnumType repeated_enum_value = 30;
+  repeated MessageType repeated_message_value = 31;
+}
+
+message TestOneof {
+  // In JSON format oneof fields behave mostly the same as optional
+  // fields except that:
+  //   1. Oneof fields have field presence information and will be
+  //      printed if it's set no matter whether it's the default value.
+  //   2. Multiple oneof fields in the same oneof cannot appear at the
+  //      same time in the input.
+  oneof oneof_value {
+    int32 oneof_int32_value = 1;
+    string oneof_string_value = 2;
+    bytes oneof_bytes_value = 3;
+    EnumType oneof_enum_value = 4;
+    MessageType oneof_message_value = 5;
+  }
+}
+
+message TestMap {
+  map<bool, int32> bool_map = 1;
+  map<int32, int32> int32_map = 2;
+  map<int64, int32> int64_map = 3;
+  map<uint32, int32> uint32_map = 4;
+  map<uint64, int32> uint64_map = 5;
+  map<string, int32> string_map = 6;
+}
+
+message TestNestedMap {
+  map<bool, int32> bool_map = 1;
+  map<int32, int32> int32_map = 2;
+  map<int64, int32> int64_map = 3;
+  map<uint32, int32> uint32_map = 4;
+  map<uint64, int32> uint64_map = 5;
+  map<string, int32> string_map = 6;
+  map<string, TestNestedMap> map_map = 7;
+}
+
+message TestWrapper {
+  google.protobuf.BoolValue bool_value = 1;
+  google.protobuf.Int32Value int32_value = 2;
+  google.protobuf.Int64Value int64_value = 3;
+  google.protobuf.UInt32Value uint32_value = 4;
+  google.protobuf.UInt64Value uint64_value = 5;
+  google.protobuf.FloatValue float_value = 6;
+  google.protobuf.DoubleValue double_value = 7;
+  google.protobuf.StringValue string_value = 8;
+  google.protobuf.BytesValue bytes_value = 9;
+
+  repeated google.protobuf.BoolValue repeated_bool_value = 11;
+  repeated google.protobuf.Int32Value repeated_int32_value = 12;
+  repeated google.protobuf.Int64Value repeated_int64_value = 13;
+  repeated google.protobuf.UInt32Value repeated_uint32_value = 14;
+  repeated google.protobuf.UInt64Value repeated_uint64_value = 15;
+  repeated google.protobuf.FloatValue repeated_float_value = 16;
+  repeated google.protobuf.DoubleValue repeated_double_value = 17;
+  repeated google.protobuf.StringValue repeated_string_value = 18;
+  repeated google.protobuf.BytesValue repeated_bytes_value = 19;
+}
+
+message TestTimestamp {
+  google.protobuf.Timestamp value = 1;
+  repeated google.protobuf.Timestamp repeated_value = 2;
+}
+
+message TestDuration {
+  google.protobuf.Duration value = 1;
+  repeated google.protobuf.Duration repeated_value = 2;
+}
+
+message TestFieldMask {
+  google.protobuf.FieldMask value = 1;
+}
+
+message TestStruct {
+  google.protobuf.Struct value = 1;
+  repeated google.protobuf.Struct repeated_value = 2;
+}
+
+message TestAny {
+  google.protobuf.Any value = 1;
+  repeated google.protobuf.Any repeated_value = 2;
+}
+
+message TestValue {
+  google.protobuf.Value value = 1;
+  repeated google.protobuf.Value repeated_value = 2;
+}
+
+message TestListValue {
+  google.protobuf.ListValue value = 1;
+  repeated google.protobuf.ListValue repeated_value = 2;
+}
+
+message TestBoolValue {
+  bool bool_value = 1;
+  map<bool, int32> bool_map = 2;
+}
+
+message TestCustomJsonName {
+  int32 value = 1 [json_name = "@value"];
+}
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
new file mode 100644
index 0000000..2659320
--- /dev/null
+++ b/src/google/protobuf/util/json_util.cc
@@ -0,0 +1,176 @@
+// 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.
+
+#include <google/protobuf/util/json_util.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/util/internal/default_value_objectwriter.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/json_objectwriter.h>
+#include <google/protobuf/util/internal/json_stream_parser.h>
+#include <google/protobuf/util/internal/protostream_objectsource.h>
+#include <google/protobuf/util/internal/protostream_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/util/type_resolver_util.h>
+#include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/status_macros.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+namespace internal {
+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.
+      return;
+    }
+    if (len < length) {
+      memcpy(buffer, bytes, len);
+      stream_->BackUp(length - len);
+      break;
+    } else {
+      memcpy(buffer, bytes, length);
+      bytes += length;
+      len -= length;
+    }
+  }
+}
+}  // namespace internal
+
+util::Status BinaryToJsonStream(TypeResolver* resolver,
+                                  const string& type_url,
+                                  io::ZeroCopyInputStream* binary_input,
+                                  io::ZeroCopyOutputStream* json_output,
+                                  const JsonOptions& options) {
+  io::CodedInputStream in_stream(binary_input);
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  converter::ProtoStreamObjectSource proto_source(&in_stream, resolver, type);
+  io::CodedOutputStream out_stream(json_output);
+  converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "",
+                                          &out_stream);
+  if (options.always_print_primitive_fields) {
+    converter::DefaultValueObjectWriter default_value_writer(
+        resolver, type, &json_writer);
+    return proto_source.WriteTo(&default_value_writer);
+  } else {
+    return proto_source.WriteTo(&json_writer);
+  }
+}
+
+util::Status BinaryToJsonString(TypeResolver* resolver,
+                                  const string& type_url,
+                                  const string& binary_input,
+                                  string* json_output,
+                                  const JsonOptions& options) {
+  io::ArrayInputStream input_stream(binary_input.data(), binary_input.size());
+  io::StringOutputStream output_stream(json_output);
+  return BinaryToJsonStream(resolver, type_url, &input_stream, &output_stream,
+                            options);
+}
+
+namespace {
+class StatusErrorListener : public converter::ErrorListener {
+ public:
+  StatusErrorListener() : status_(util::Status::OK) {}
+  virtual ~StatusErrorListener() {}
+
+  util::Status GetStatus() { return status_; }
+
+  virtual void InvalidName(const converter::LocationTrackerInterface& loc,
+                           StringPiece unknown_name, StringPiece message) {
+    status_ = util::Status(util::error::INVALID_ARGUMENT,
+                             loc.ToString() + ": " + message.ToString());
+  }
+
+  virtual void InvalidValue(const converter::LocationTrackerInterface& loc,
+                            StringPiece type_name, StringPiece value) {
+    status_ =
+        util::Status(util::error::INVALID_ARGUMENT,
+                       loc.ToString() + ": invalid value " + value.ToString() +
+                           " for type " + type_name.ToString());
+  }
+
+  virtual void MissingField(const converter::LocationTrackerInterface& loc,
+                            StringPiece missing_name) {
+    status_ = util::Status(
+        util::error::INVALID_ARGUMENT,
+        loc.ToString() + ": missing field " + missing_name.ToString());
+  }
+
+ private:
+  util::Status status_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StatusErrorListener);
+};
+}  // namespace
+
+util::Status JsonToBinaryStream(TypeResolver* resolver,
+                                  const string& type_url,
+                                  io::ZeroCopyInputStream* json_input,
+                                  io::ZeroCopyOutputStream* binary_output) {
+  google::protobuf::Type type;
+  RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
+  internal::ZeroCopyStreamByteSink sink(binary_output);
+  StatusErrorListener listener;
+  converter::ProtoStreamObjectWriter proto_writer(resolver, type, &sink,
+                                                  &listener);
+
+  converter::JsonStreamParser parser(&proto_writer);
+  const void* buffer;
+  int length;
+  while (json_input->Next(&buffer, &length)) {
+    if (length == 0) continue;
+    RETURN_IF_ERROR(
+        parser.Parse(StringPiece(static_cast<const char*>(buffer), length)));
+  }
+  RETURN_IF_ERROR(parser.FinishParse());
+
+  return listener.GetStatus();
+}
+
+util::Status JsonToBinaryString(TypeResolver* resolver,
+                                  const string& type_url,
+                                  const string& json_input,
+                                  string* binary_output) {
+  io::ArrayInputStream input_stream(json_input.data(), json_input.size());
+  io::StringOutputStream output_stream(binary_output);
+  return JsonToBinaryStream(resolver, type_url, &input_stream, &output_stream);
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
new file mode 100644
index 0000000..1718bfb
--- /dev/null
+++ b/src/google/protobuf/util/json_util.h
@@ -0,0 +1,136 @@
+// 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.
+
+// Utility functions to convert between protobuf binary format and proto3 JSON
+// format.
+#ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
+
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyInputStream;
+class ZeroCopyOutputStream;
+}  // namespace io
+namespace util {
+
+struct JsonOptions {
+  // Whether to add spaces, line breaks and indentation to make the JSON output
+  // easy to read.
+  bool add_whitespace;
+  // Whether to always print primitive fields. By default primitive fields with
+  // default values will be omitted in JSON joutput. For example, an int32 field
+  // 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;
+
+  JsonOptions() : add_whitespace(false),
+                  always_print_primitive_fields(false) {
+  }
+};
+
+// Converts protobuf binary data to JSON.
+// The conversion will fail if:
+//   1. TypeResolver fails to resolve a type.
+//   2. input is not valid protobuf wire format, or conflicts with the type
+//      information returned by TypeResolver.
+// Note that unknown fields will be discarded silently.
+util::Status BinaryToJsonStream(
+    TypeResolver* resolver,
+    const string& type_url,
+    io::ZeroCopyInputStream* binary_input,
+    io::ZeroCopyOutputStream* json_output,
+    const JsonOptions& options);
+
+inline util::Status BinaryToJsonStream(
+    TypeResolver* resolver, const string& type_url,
+    io::ZeroCopyInputStream* binary_input,
+    io::ZeroCopyOutputStream* json_output) {
+  return BinaryToJsonStream(resolver, type_url, binary_input, json_output,
+                            JsonOptions());
+}
+
+LIBPROTOBUF_EXPORT util::Status BinaryToJsonString(
+    TypeResolver* resolver,
+    const string& type_url,
+    const string& binary_input,
+    string* json_output,
+    const JsonOptions& options);
+
+inline util::Status BinaryToJsonString(TypeResolver* resolver,
+                                         const string& type_url,
+                                         const string& binary_input,
+                                         string* json_output) {
+  return BinaryToJsonString(resolver, type_url, binary_input, json_output,
+                            JsonOptions());
+}
+
+// Converts JSON data to protobuf binary format.
+// The conversion will fail if:
+//   1. TypeResolver fails to resolve a type.
+//   2. input is not valid JSON format, or conflicts with the type
+//      information returned by TypeResolver.
+//   3. input has unknown fields.
+util::Status JsonToBinaryStream(
+    TypeResolver* resolver,
+    const string& type_url,
+    io::ZeroCopyInputStream* json_input,
+    io::ZeroCopyOutputStream* binary_output);
+
+LIBPROTOBUF_EXPORT util::Status JsonToBinaryString(
+    TypeResolver* resolver,
+    const string& type_url,
+    const string& json_input,
+    string* binary_output);
+
+namespace internal {
+// Internal helper class. Put in the header so we can write unit-tests for it.
+class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
+ public:
+  explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
+      : stream_(stream) {}
+
+  virtual void Append(const char* bytes, size_t len);
+
+ private:
+  io::ZeroCopyOutputStream* stream_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
+};
+}  // namespace internal
+
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
new file mode 100644
index 0000000..a4d3cc9
--- /dev/null
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -0,0 +1,309 @@
+// 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.
+
+#include <google/protobuf/util/json_util.h>
+
+#include <list>
+#include <string>
+
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/util/json_format_proto3.pb.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/util/type_resolver_util.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+
+using proto3::FOO;
+using proto3::BAR;
+using proto3::TestMessage;
+using proto3::TestMap;
+
+static const char kTypeUrlPrefix[] = "type.googleapis.com";
+
+static string GetTypeUrl(const Descriptor* message) {
+  return string(kTypeUrlPrefix) + "/" + message->full_name();
+}
+
+// As functions defined in json_util.h are just thin wrappers around the
+// JSON conversion code in //net/proto2/util/converter, in this test we
+// only cover some very basic cases to make sure the wrappers have forwarded
+// parameters to the underlying implementation correctly. More detailed
+// tests are contained in the //net/proto2/util/converter directory.
+class JsonUtilTest : public testing::Test {
+ protected:
+  JsonUtilTest() {
+    resolver_.reset(NewTypeResolverForDescriptorPool(
+        kTypeUrlPrefix, DescriptorPool::generated_pool()));
+  }
+
+  string ToJson(const Message& message, const JsonOptions& options) {
+    string result;
+    GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(),
+                                GetTypeUrl(message.GetDescriptor()),
+                                message.SerializeAsString(), &result, options));
+    return result;
+  }
+
+  bool FromJson(const string& json, Message* message) {
+    string binary;
+    if (!JsonToBinaryString(resolver_.get(),
+                            GetTypeUrl(message->GetDescriptor()), json, &binary)
+             .ok()) {
+      return false;
+    }
+    return message->ParseFromString(binary);
+  }
+
+  google::protobuf::scoped_ptr<TypeResolver> resolver_;
+};
+
+TEST_F(JsonUtilTest, TestWhitespaces) {
+  TestMessage m;
+  m.mutable_message_value();
+
+  JsonOptions options;
+  EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options));
+  options.add_whitespace = true;
+  EXPECT_EQ(
+      "{\n"
+      " \"messageValue\": {}\n"
+      "}\n",
+      ToJson(m, options));
+}
+
+TEST_F(JsonUtilTest, TestDefaultValues) {
+  TestMessage m;
+  JsonOptions options;
+  EXPECT_EQ("{}", ToJson(m, options));
+  options.always_print_primitive_fields = true;
+  EXPECT_EQ(
+      "{\"boolValue\":false,"
+      "\"int32Value\":0,"
+      "\"int64Value\":\"0\","
+      "\"uint32Value\":0,"
+      "\"uint64Value\":\"0\","
+      "\"floatValue\":0,"
+      "\"doubleValue\":0,"
+      "\"stringValue\":\"\","
+      "\"bytesValue\":\"\","
+      "\"enumValue\":\"FOO\","
+      "\"repeatedBoolValue\":[],"
+      "\"repeatedInt32Value\":[],"
+      "\"repeatedInt64Value\":[],"
+      "\"repeatedUint32Value\":[],"
+      "\"repeatedUint64Value\":[],"
+      "\"repeatedFloatValue\":[],"
+      "\"repeatedDoubleValue\":[],"
+      "\"repeatedStringValue\":[],"
+      "\"repeatedBytesValue\":[],"
+      "\"repeatedEnumValue\":[],"
+      "\"repeatedMessageValue\":[]"
+      "}",
+      ToJson(m, options));
+}
+
+TEST_F(JsonUtilTest, ParseMessage) {
+  // Some random message but good enough to verify that the parsing warpper
+  // functions are working properly.
+  string input =
+      "{\n"
+      "  \"int32Value\": 1024,\n"
+      "  \"repeatedInt32Value\": [1, 2],\n"
+      "  \"messageValue\": {\n"
+      "    \"value\": 2048\n"
+      "  },\n"
+      "  \"repeatedMessageValue\": [\n"
+      "    {\"value\": 40}, {\"value\": 96}\n"
+      "  ]\n"
+      "}\n";
+  TestMessage m;
+  ASSERT_TRUE(FromJson(input, &m));
+  EXPECT_EQ(1024, m.int32_value());
+  ASSERT_EQ(2, m.repeated_int32_value_size());
+  EXPECT_EQ(1, m.repeated_int32_value(0));
+  EXPECT_EQ(2, m.repeated_int32_value(1));
+  EXPECT_EQ(2048, m.message_value().value());
+  ASSERT_EQ(2, m.repeated_message_value_size());
+  EXPECT_EQ(40, m.repeated_message_value(0).value());
+  EXPECT_EQ(96, m.repeated_message_value(1).value());
+}
+
+TEST_F(JsonUtilTest, ParseMap) {
+  TestMap message;
+  (*message.mutable_string_map())["hello"] = 1234;
+  JsonOptions options;
+  EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, options));
+  TestMap other;
+  ASSERT_TRUE(FromJson(ToJson(message, options), &other));
+  EXPECT_EQ(message.DebugString(), other.DebugString());
+}
+
+TEST_F(JsonUtilTest, TestParseErrors) {
+  TestMessage m;
+  JsonOptions options;
+  // Parsing should fail if the field name can not be recognized.
+  EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m));
+  // Parsing should fail if the value is invalid.
+  EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m));
+}
+
+typedef pair<char*, int> Segment;
+// A ZeroCopyOutputStream that writes to multiple buffers.
+class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
+ public:
+  explicit SegmentedZeroCopyOutputStream(list<Segment> segments)
+      : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_count_(0) {}
+
+  virtual bool Next(void** buffer, int* length) {
+    if (segments_.empty()) {
+      return false;
+    }
+    last_segment_ = segments_.front();
+    segments_.pop_front();
+    *buffer = last_segment_.first;
+    *length = last_segment_.second;
+    byte_count_ += *length;
+    return true;
+  }
+
+  virtual void BackUp(int length) {
+    GOOGLE_CHECK(length <= last_segment_.second);
+    segments_.push_front(
+        Segment(last_segment_.first + last_segment_.second - length, length));
+    last_segment_ = Segment(last_segment_.first, last_segment_.second - length);
+    byte_count_ -= length;
+  }
+
+  virtual int64 ByteCount() const { return byte_count_; }
+
+ private:
+  list<Segment> segments_;
+  Segment last_segment_;
+  int64 byte_count_;
+};
+
+// This test splits the output buffer and also the input data into multiple
+// segments and checks that the implementation of ZeroCopyStreamByteSink
+// handles all possible cases correctly.
+TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
+  static const int kOutputBufferLength = 10;
+  // An exhaustive test takes too long, skip some combinations to make the test
+  // run faster.
+  static const int kSkippedPatternCount = 7;
+
+  char buffer[kOutputBufferLength];
+  for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1));
+       split_pattern += kSkippedPatternCount) {
+    // Split the buffer into small segments according to the split_pattern.
+    list<Segment> segments;
+    int segment_start = 0;
+    for (int i = 0; i < kOutputBufferLength - 1; ++i) {
+      if (split_pattern & (1 << i)) {
+        segments.push_back(
+            Segment(buffer + segment_start, i - segment_start + 1));
+        segment_start = i + 1;
+      }
+    }
+    segments.push_back(
+        Segment(buffer + segment_start, kOutputBufferLength - segment_start));
+
+    // Write exactly 10 bytes through the ByteSink.
+    string input_data = "0123456789";
+    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
+         input_pattern += kSkippedPatternCount) {
+      memset(buffer, 0, sizeof(buffer));
+      {
+        SegmentedZeroCopyOutputStream output_stream(segments);
+        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
+        int start = 0;
+        for (int j = 0; j < input_data.length() - 1; ++j) {
+          if (input_pattern & (1 << j)) {
+            byte_sink.Append(&input_data[start], j - start + 1);
+            start = j + 1;
+          }
+        }
+        byte_sink.Append(&input_data[start], input_data.length() - start);
+      }
+      EXPECT_EQ(input_data, string(buffer, input_data.length()));
+    }
+
+    // Write only 9 bytes through the ByteSink.
+    input_data = "012345678";
+    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
+         input_pattern += kSkippedPatternCount) {
+      memset(buffer, 0, sizeof(buffer));
+      {
+        SegmentedZeroCopyOutputStream output_stream(segments);
+        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
+        int start = 0;
+        for (int j = 0; j < input_data.length() - 1; ++j) {
+          if (input_pattern & (1 << j)) {
+            byte_sink.Append(&input_data[start], j - start + 1);
+            start = j + 1;
+          }
+        }
+        byte_sink.Append(&input_data[start], input_data.length() - start);
+      }
+      EXPECT_EQ(input_data, string(buffer, input_data.length()));
+      EXPECT_EQ(0, buffer[input_data.length()]);
+    }
+
+    // Write 11 bytes through the ByteSink. The extra byte will just
+    // be ignored.
+    input_data = "0123456789A";
+    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
+         input_pattern += kSkippedPatternCount) {
+      memset(buffer, 0, sizeof(buffer));
+      {
+        SegmentedZeroCopyOutputStream output_stream(segments);
+        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
+        int start = 0;
+        for (int j = 0; j < input_data.length() - 1; ++j) {
+          if (input_pattern & (1 << j)) {
+            byte_sink.Append(&input_data[start], j - start + 1);
+            start = j + 1;
+          }
+        }
+        byte_sink.Append(&input_data[start], input_data.length() - start);
+      }
+      EXPECT_EQ(input_data.substr(0, kOutputBufferLength),
+                string(buffer, kOutputBufferLength));
+    }
+  }
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
new file mode 100644
index 0000000..fe8119b
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -0,0 +1,1689 @@
+// 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.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file defines static methods and classes for comparing Protocol
+// Messages (see //google/protobuf/util/message_differencer.h for more
+// information).
+
+#include <google/protobuf/util/message_differencer.h>
+
+#include <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <utility>
+
+#include <google/protobuf/stubs/callback.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/any.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/field_comparator.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+
+namespace util {
+
+// When comparing a repeated field as map, MultipleFieldMapKeyComparator can
+// be used to specify multiple fields as key for key comparison.
+// Two elements of a repeated field will be regarded as having the same key
+// iff they have the same value for every specified key field.
+// Note that you can also specify only one field as key.
+class MessageDifferencer::MultipleFieldsMapKeyComparator
+    : public MessageDifferencer::MapKeyComparator {
+ public:
+  MultipleFieldsMapKeyComparator(
+      MessageDifferencer* message_differencer,
+      const vector<vector<const FieldDescriptor*> >& key_field_paths)
+        : message_differencer_(message_differencer),
+          key_field_paths_(key_field_paths) {
+    GOOGLE_CHECK(!key_field_paths_.empty());
+    for (int i = 0; i < key_field_paths_.size(); ++i) {
+      GOOGLE_CHECK(!key_field_paths_[i].empty());
+    }
+  }
+  MultipleFieldsMapKeyComparator(
+      MessageDifferencer* message_differencer,
+      const FieldDescriptor* key)
+        : message_differencer_(message_differencer) {
+    vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key);
+    key_field_paths_.push_back(key_field_path);
+  }
+  virtual bool IsMatch(
+      const Message& message1,
+      const Message& message2,
+      const vector<SpecificField>& parent_fields) const {
+    for (int i = 0; i < key_field_paths_.size(); ++i) {
+      if (!IsMatchInternal(message1, message2, parent_fields,
+                           key_field_paths_[i], 0)) {
+        return false;
+      }
+    }
+    return true;
+  }
+ private:
+  bool IsMatchInternal(
+      const Message& message1,
+      const Message& message2,
+      const vector<SpecificField>& parent_fields,
+      const vector<const FieldDescriptor*>& key_field_path,
+      int path_index) const {
+    const FieldDescriptor* field = key_field_path[path_index];
+    vector<SpecificField> current_parent_fields(parent_fields);
+    if (path_index == key_field_path.size() - 1) {
+      if (field->is_repeated()) {
+        if (!message_differencer_->CompareRepeatedField(
+            message1, message2, field, &current_parent_fields)) {
+          return false;
+        }
+      } else {
+        if (!message_differencer_->CompareFieldValueUsingParentFields(
+            message1, message2, field, -1, -1, &current_parent_fields)) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      const Reflection* reflection1 = message1.GetReflection();
+      const Reflection* reflection2 = message2.GetReflection();
+      bool has_field1 = reflection1->HasField(message1, field);
+      bool has_field2 = reflection2->HasField(message2, field);
+      if (!has_field1 && !has_field2) {
+        return true;
+      }
+      if (has_field1 != has_field2) {
+        return false;
+      }
+      SpecificField specific_field;
+      specific_field.field = field;
+      current_parent_fields.push_back(specific_field);
+      return IsMatchInternal(
+          reflection1->GetMessage(message1, field),
+          reflection2->GetMessage(message2, field),
+          current_parent_fields,
+          key_field_path,
+          path_index + 1);
+    }
+  }
+  MessageDifferencer* message_differencer_;
+  vector<vector<const FieldDescriptor*> > key_field_paths_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
+};
+
+bool MessageDifferencer::Equals(const Message& message1,
+                                const Message& message2) {
+  MessageDifferencer differencer;
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::Equivalent(const Message& message1,
+                                    const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::ApproximatelyEquals(const Message& message1,
+                                             const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_float_comparison(
+      MessageDifferencer::APPROXIMATE);
+
+  return differencer.Compare(message1, message2);
+}
+
+bool MessageDifferencer::ApproximatelyEquivalent(const Message& message1,
+                                                 const Message& message2) {
+  MessageDifferencer differencer;
+  differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
+  differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
+
+  return differencer.Compare(message1, message2);
+}
+
+// ===========================================================================
+
+MessageDifferencer::MessageDifferencer()
+    : reporter_(NULL),
+      field_comparator_(NULL),
+      message_field_comparison_(EQUAL),
+      scope_(FULL),
+      repeated_field_comparison_(AS_LIST),
+      report_matches_(false),
+      output_string_(NULL) { }
+
+MessageDifferencer::~MessageDifferencer() {
+  for (int i = 0; i < owned_key_comparators_.size(); ++i) {
+    delete owned_key_comparators_[i];
+  }
+  for (int i = 0; i < ignore_criteria_.size(); ++i) {
+    delete ignore_criteria_[i];
+  }
+}
+
+void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
+  GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
+  field_comparator_ = comparator;
+}
+
+void MessageDifferencer::set_message_field_comparison(
+    MessageFieldComparison comparison) {
+  message_field_comparison_ = comparison;
+}
+
+void MessageDifferencer::set_scope(Scope scope) {
+  scope_ = scope;
+}
+
+MessageDifferencer::Scope MessageDifferencer::scope() {
+  return scope_;
+}
+
+void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
+  default_field_comparator_.set_float_comparison(
+      comparison == EXACT ?
+      DefaultFieldComparator::EXACT : DefaultFieldComparator::APPROXIMATE);
+}
+
+void MessageDifferencer::set_repeated_field_comparison(
+    RepeatedFieldComparison comparison) {
+  repeated_field_comparison_ = comparison;
+}
+
+void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                               << field->full_name();
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
+  GOOGLE_CHECK(key_comparator == NULL)
+      << "Cannot treat this repeated field as both Map and Set for"
+      << " comparison.  Field name is: " << field->full_name();
+  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+      << "Cannot treat the same field as both SET and LIST. Field name is: "
+      << field->full_name();
+  set_fields_.insert(field);
+}
+
+void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                              << field->full_name();
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
+  GOOGLE_CHECK(key_comparator == NULL)
+      << "Cannot treat this repeated field as both Map and Set for"
+      << " comparison.  Field name is: " << field->full_name();
+  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+      << "Cannot treat the same field as both SET and LIST. Field name is: "
+      << field->full_name();
+  list_fields_.insert(field);
+}
+
+void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
+                                    const FieldDescriptor* key) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                               << field->full_name();
+  GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
+      << "Field has to be message type.  Field name is: "
+      << field->full_name();
+  GOOGLE_CHECK(key->containing_type() == field->message_type())
+      << key->full_name()
+      << " must be a direct subfield within the repeated field "
+      << field->full_name() << ", not " << key->containing_type()->full_name();
+  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+      << "Cannot treat this repeated field as both Map and Set for "
+      << "comparison.";
+  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+      << "Cannot treat this repeated field as both Map and List for "
+      << "comparison.";
+  MapKeyComparator* key_comparator =
+      new MultipleFieldsMapKeyComparator(this, key);
+  owned_key_comparators_.push_back(key_comparator);
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::TreatAsMapWithMultipleFieldsAsKey(
+    const FieldDescriptor* field,
+    const vector<const FieldDescriptor*>& key_fields) {
+  vector<vector<const FieldDescriptor*> > key_field_paths;
+  for (int i = 0; i < key_fields.size(); ++i) {
+    vector<const FieldDescriptor*> key_field_path;
+    key_field_path.push_back(key_fields[i]);
+    key_field_paths.push_back(key_field_path);
+  }
+  TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
+}
+
+void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
+    const FieldDescriptor* field,
+    const vector<vector<const FieldDescriptor*> >& key_field_paths) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                              << field->full_name();
+  GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
+      << "Field has to be message type.  Field name is: "
+      << field->full_name();
+  for (int i = 0; i < key_field_paths.size(); ++i) {
+    const vector<const FieldDescriptor*>& key_field_path = key_field_paths[i];
+    for (int j = 0; j < key_field_path.size(); ++j) {
+      const FieldDescriptor* parent_field =
+          j == 0 ? field : key_field_path[j - 1];
+      const FieldDescriptor* child_field = key_field_path[j];
+      GOOGLE_CHECK(child_field->containing_type() == parent_field->message_type())
+          << child_field->full_name()
+          << " must be a direct subfield within the field: "
+          << parent_field->full_name();
+      if (j != 0) {
+        GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, parent_field->cpp_type())
+            << parent_field->full_name() << " has to be of type message.";
+        GOOGLE_CHECK(!parent_field->is_repeated())
+            << parent_field->full_name() << " cannot be a repeated field.";
+      }
+    }
+  }
+  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+      << "Cannot treat this repeated field as both Map and Set for "
+      << "comparison.";
+  MapKeyComparator* key_comparator =
+      new MultipleFieldsMapKeyComparator(this, key_field_paths);
+  owned_key_comparators_.push_back(key_comparator);
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::TreatAsMapUsingKeyComparator(
+    const FieldDescriptor* field,
+    const MapKeyComparator* key_comparator) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                               << field->full_name();
+  GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
+      << "Field has to be message type.  Field name is: "
+      << field->full_name();
+  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+      << "Cannot treat this repeated field as both Map and Set for "
+      << "comparison.";
+  map_field_key_comparator_[field] = key_comparator;
+}
+
+void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) {
+  ignore_criteria_.push_back(ignore_criteria);
+}
+
+void MessageDifferencer::IgnoreField(const FieldDescriptor* field) {
+  ignored_fields_.insert(field);
+}
+
+void MessageDifferencer::SetFractionAndMargin(const FieldDescriptor* field,
+                                              double fraction, double margin) {
+  default_field_comparator_.SetFractionAndMargin(field, fraction, margin);
+}
+
+void MessageDifferencer::ReportDifferencesToString(string* output) {
+  GOOGLE_DCHECK(output) << "Specified output string was NULL";
+
+  output_string_ = output;
+  output_string_->clear();
+}
+
+void MessageDifferencer::ReportDifferencesTo(Reporter* reporter) {
+  // If an output string is set, clear it to prevent
+  // it superceding the specified reporter.
+  if (output_string_) {
+    output_string_ = NULL;
+  }
+
+  reporter_ = reporter;
+}
+
+bool MessageDifferencer::FieldBefore(const FieldDescriptor* field1,
+                                     const FieldDescriptor* field2) {
+  // Handle sentinel values (i.e. make sure NULLs are always ordered
+  // at the end of the list).
+  if (field1 == NULL) {
+    return false;
+  }
+
+  if (field2 == NULL) {
+    return true;
+  }
+
+  // Always order fields by their tag number
+  return (field1->number() < field2->number());
+}
+
+bool MessageDifferencer::Compare(const Message& message1,
+                                 const Message& message2) {
+  vector<SpecificField> parent_fields;
+
+  bool result = false;
+
+  // Setup the internal reporter if need be.
+  if (output_string_) {
+    io::StringOutputStream output_stream(output_string_);
+    StreamReporter reporter(&output_stream);
+    reporter_ = &reporter;
+    result = Compare(message1, message2, &parent_fields);
+    reporter_ = NULL;
+  } else {
+    result = Compare(message1, message2, &parent_fields);
+  }
+
+  return result;
+}
+
+bool MessageDifferencer::CompareWithFields(
+    const Message& message1,
+    const Message& message2,
+    const vector<const FieldDescriptor*>& message1_fields_arg,
+    const vector<const FieldDescriptor*>& message2_fields_arg) {
+  if (message1.GetDescriptor() != message2.GetDescriptor()) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors.";
+    return false;
+  }
+
+  vector<SpecificField> parent_fields;
+
+  bool result = false;
+
+  vector<const FieldDescriptor*> message1_fields(message1_fields_arg);
+  vector<const FieldDescriptor*> message2_fields(message2_fields_arg);
+
+  std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
+  std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
+  // Append NULL sentinel values.
+  message1_fields.push_back(NULL);
+  message2_fields.push_back(NULL);
+
+  // Setup the internal reporter if need be.
+  if (output_string_) {
+    io::StringOutputStream output_stream(output_string_);
+    StreamReporter reporter(&output_stream);
+    reporter_ = &reporter;
+    result = CompareRequestedFieldsUsingSettings(
+        message1, message2, message1_fields, message2_fields, &parent_fields);
+    reporter_ = NULL;
+  } else {
+    result = CompareRequestedFieldsUsingSettings(
+        message1, message2, message1_fields, message2_fields, &parent_fields);
+  }
+
+  return result;
+}
+
+bool MessageDifferencer::Compare(
+    const Message& message1,
+    const Message& message2,
+    vector<SpecificField>* parent_fields) {
+  const Descriptor* descriptor1 = message1.GetDescriptor();
+  const Descriptor* descriptor2 = message2.GetDescriptor();
+  if (descriptor1 != descriptor2) {
+    GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
+                << "descriptors. "
+                << descriptor1->full_name() << " vs "
+                << descriptor2->full_name();
+    return false;
+  }
+  // Expand google.protobuf.Any payload if possible.
+  if (descriptor1->full_name() == internal::kAnyFullTypeName) {
+    google::protobuf::scoped_ptr<Message> data1;
+    google::protobuf::scoped_ptr<Message> data2;
+    if (UnpackAny(message1, &data1) && UnpackAny(message2, &data2)) {
+      return Compare(*data1, *data2, parent_fields);
+    }
+  }
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  // Retrieve all the set fields, including extensions.
+  vector<const FieldDescriptor*> message1_fields;
+  vector<const FieldDescriptor*> message2_fields;
+
+  reflection1->ListFields(message1, &message1_fields);
+  reflection2->ListFields(message2, &message2_fields);
+
+  // Add sentinel values to deal with the
+  // case where the number of the fields in
+  // each list are different.
+  message1_fields.push_back(NULL);
+  message2_fields.push_back(NULL);
+
+  bool unknown_compare_result = true;
+  // Ignore unknown fields in EQUIVALENT mode
+  if (message_field_comparison_ != EQUIVALENT) {
+    const google::protobuf::UnknownFieldSet* unknown_field_set1 =
+        &reflection1->GetUnknownFields(message1);
+    const google::protobuf::UnknownFieldSet* unknown_field_set2 =
+        &reflection2->GetUnknownFields(message2);
+    if (!CompareUnknownFields(message1, message2,
+                              *unknown_field_set1, *unknown_field_set2,
+                              parent_fields)) {
+      if (reporter_ == NULL) {
+        return false;
+      };
+      unknown_compare_result = false;
+    }
+  }
+
+  return CompareRequestedFieldsUsingSettings(
+      message1, message2,
+      message1_fields, message2_fields,
+      parent_fields) && unknown_compare_result;
+}
+
+bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
+    const Message& message1,
+    const Message& message2,
+    const vector<const FieldDescriptor*>& message1_fields,
+    const vector<const FieldDescriptor*>& message2_fields,
+    vector<SpecificField>* parent_fields) {
+  if (scope_ == FULL) {
+    if (message_field_comparison_ == EQUIVALENT) {
+      // We need to merge the field lists of both messages (i.e.
+      // we are merely checking for a difference in field values,
+      // rather than the addition or deletion of fields).
+      vector<const FieldDescriptor*> fields_union;
+      CombineFields(message1_fields, FULL, message2_fields, FULL,
+                    &fields_union);
+      return CompareWithFieldsInternal(message1, message2, fields_union,
+                                       fields_union, parent_fields);
+    } else {
+      // Simple equality comparison, use the unaltered field lists.
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       message2_fields, parent_fields);
+    }
+  } else {
+    if (message_field_comparison_ == EQUIVALENT) {
+      // We use the list of fields for message1 for both messages when
+      // comparing.  This way, extra fields in message2 are ignored,
+      // and missing fields in message2 use their default value.
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       message1_fields, parent_fields);
+    } else {
+      // We need to consider the full list of fields for message1
+      // but only the intersection for message2.  This way, any fields
+      // only present in message2 will be ignored, but any fields only
+      // present in message1 will be marked as a difference.
+      vector<const FieldDescriptor*> fields_intersection;
+      CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL,
+                    &fields_intersection);
+      return CompareWithFieldsInternal(message1, message2, message1_fields,
+                                       fields_intersection, parent_fields);
+    }
+  }
+}
+
+void MessageDifferencer::CombineFields(
+    const vector<const FieldDescriptor*>& fields1,
+    Scope fields1_scope,
+    const vector<const FieldDescriptor*>& fields2,
+    Scope fields2_scope,
+    vector<const FieldDescriptor*>* combined_fields) {
+
+  int index1 = 0;
+  int index2 = 0;
+
+  while (index1 < fields1.size() && index2 < fields2.size()) {
+    const FieldDescriptor* field1 = fields1[index1];
+    const FieldDescriptor* field2 = fields2[index2];
+
+    if (FieldBefore(field1, field2)) {
+      if (fields1_scope == FULL) {
+        combined_fields->push_back(fields1[index1]);
+      }
+      ++index1;
+    } else if (FieldBefore(field2, field1)) {
+      if (fields2_scope == FULL) {
+        combined_fields->push_back(fields2[index2]);
+      }
+      ++index2;
+    } else {
+      combined_fields->push_back(fields1[index1]);
+      ++index1;
+      ++index2;
+    }
+  }
+}
+
+bool MessageDifferencer::CompareWithFieldsInternal(
+    const Message& message1,
+    const Message& message2,
+    const vector<const FieldDescriptor*>& message1_fields,
+    const vector<const FieldDescriptor*>& message2_fields,
+    vector<SpecificField>* parent_fields) {
+  bool isDifferent = false;
+  int field_index1 = 0;
+  int field_index2 = 0;
+
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+
+  while (true) {
+    const FieldDescriptor* field1 = message1_fields[field_index1];
+    const FieldDescriptor* field2 = message2_fields[field_index2];
+
+    // Once we have reached sentinel values, we are done the comparison.
+    if (field1 == NULL && field2 == NULL) {
+      break;
+    }
+
+    // Check for differences in the field itself.
+    if (FieldBefore(field1, field2)) {
+      // Field 1 is not in the field list for message 2.
+      if (IsIgnored(message1, message2, field1, *parent_fields)) {
+        // We are ignoring field1. Report the ignore and move on to
+        // the next field in message1_fields.
+        if (reporter_ != NULL) {
+          SpecificField specific_field;
+          specific_field.field = field1;
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportIgnored(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+        ++field_index1;
+        continue;
+      }
+
+      if (reporter_ != NULL) {
+        int count = field1->is_repeated() ?
+            reflection1->FieldSize(message1, field1) : 1;
+
+        for (int i = 0; i < count; ++i) {
+          SpecificField specific_field;
+          specific_field.field = field1;
+          specific_field.index = field1->is_repeated() ? i : -1;
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportDeleted(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+
+        isDifferent = true;
+      } else {
+        return false;
+      }
+
+      ++field_index1;
+      continue;
+    } else if (FieldBefore(field2, field1)) {
+      // Field 2 is not in the field list for message 1.
+      if (IsIgnored(message1, message2, field2, *parent_fields)) {
+        // We are ignoring field2. Report the ignore and move on to
+        // the next field in message2_fields.
+        if (reporter_ != NULL) {
+          SpecificField specific_field;
+          specific_field.field = field2;
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportIgnored(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+        ++field_index2;
+        continue;
+      }
+
+      if (reporter_ != NULL) {
+        int count = field2->is_repeated() ?
+            reflection2->FieldSize(message2, field2) : 1;
+
+        for (int i = 0; i < count; ++i) {
+          SpecificField specific_field;
+          specific_field.field = field2;
+          specific_field.index = field2->is_repeated() ? i : -1;
+          specific_field.new_index = specific_field.index;
+
+          parent_fields->push_back(specific_field);
+          reporter_->ReportAdded(message1, message2, *parent_fields);
+          parent_fields->pop_back();
+        }
+
+        isDifferent = true;
+      } else {
+        return false;
+      }
+
+      ++field_index2;
+      continue;
+    }
+
+    // By this point, field1 and field2 are guarenteed to point to the same
+    // field, so we can now compare the values.
+    if (IsIgnored(message1, message2, field1, *parent_fields)) {
+      // Ignore this field. Report and move on.
+      if (reporter_ != NULL) {
+        SpecificField specific_field;
+        specific_field.field = field1;
+
+        parent_fields->push_back(specific_field);
+        reporter_->ReportIgnored(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+      }
+
+      ++field_index1;
+      ++field_index2;
+      continue;
+    }
+
+    bool fieldDifferent = false;
+    if (field1->is_repeated()) {
+      fieldDifferent = !CompareRepeatedField(message1, message2, field1,
+                                             parent_fields);
+      if (fieldDifferent) {
+        if (reporter_ == NULL) return false;
+        isDifferent = true;
+      }
+    } else {
+      fieldDifferent = !CompareFieldValueUsingParentFields(
+          message1, message2, field1, -1, -1, parent_fields);
+
+      // If we have found differences, either report them or terminate if
+      // no reporter is present.
+      if (fieldDifferent && reporter_ == NULL) {
+        return false;
+      }
+
+      if (reporter_ != NULL) {
+        SpecificField specific_field;
+        specific_field.field = field1;
+        parent_fields->push_back(specific_field);
+        if (fieldDifferent) {
+          reporter_->ReportModified(message1, message2, *parent_fields);
+          isDifferent = true;
+        } else if (report_matches_) {
+          reporter_->ReportMatched(message1, message2, *parent_fields);
+        }
+        parent_fields->pop_back();
+      }
+    }
+    // Increment the field indicies.
+    ++field_index1;
+    ++field_index2;
+  }
+
+  return !isDifferent;
+}
+
+bool MessageDifferencer::IsMatch(const FieldDescriptor* repeated_field,
+                                 const MapKeyComparator* key_comparator,
+                                 const Message* message1,
+                                 const Message* message2,
+                                 const vector<SpecificField>& parent_fields,
+                                 int index1, int index2) {
+  vector<SpecificField> current_parent_fields(parent_fields);
+  if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return CompareFieldValueUsingParentFields(
+        *message1, *message2, repeated_field, index1, index2,
+        &current_parent_fields);
+  }
+  // Back up the Reporter and output_string_.  They will be reset in the
+  // following code.
+  Reporter* backup_reporter = reporter_;
+  string* output_string = output_string_;
+  reporter_ = NULL;
+  output_string_ = NULL;
+  bool match;
+
+  if (key_comparator == NULL) {
+    match = CompareFieldValueUsingParentFields(
+        *message1, *message2, repeated_field, index1, index2,
+        &current_parent_fields);
+  } else {
+    const Reflection* reflection1 = message1->GetReflection();
+    const Reflection* reflection2 = message2->GetReflection();
+    const Message& m1 =
+        reflection1->GetRepeatedMessage(*message1, repeated_field, index1);
+    const Message& m2 =
+        reflection2->GetRepeatedMessage(*message2, repeated_field, index2);
+    SpecificField specific_field;
+    specific_field.field = repeated_field;
+    current_parent_fields.push_back(specific_field);
+    match = key_comparator->IsMatch(m1, m2, current_parent_fields);
+  }
+
+  reporter_ = backup_reporter;
+  output_string_ = output_string;
+  return match;
+}
+
+bool MessageDifferencer::CompareRepeatedField(
+    const Message& message1,
+    const Message& message2,
+    const FieldDescriptor* repeated_field,
+    vector<SpecificField>* parent_fields) {
+  // the input FieldDescriptor is guaranteed to be repeated field.
+  const Reflection* reflection1 = message1.GetReflection();
+  const Reflection* reflection2 = message2.GetReflection();
+  const int count1 = reflection1->FieldSize(message1, repeated_field);
+  const int count2 = reflection2->FieldSize(message2, repeated_field);
+  const bool treated_as_subset = IsTreatedAsSubset(repeated_field);
+
+  // If the field is not treated as subset and no detailed reports is needed,
+  // we do a quick check on the number of the elements to avoid unnecessary
+  // comparison.
+  if (count1 != count2 && reporter_ == NULL && !treated_as_subset) {
+    return false;
+  }
+  // A match can never be found if message1 has more items than message2.
+  if (count1 > count2 && reporter_ == NULL) {
+    return false;
+  }
+
+  // These two list are used for store the index of the correspondent
+  // element in peer repeated field.
+  vector<int> match_list1;
+  vector<int> match_list2;
+
+  // Try to match indices of the repeated fields. Return false if match fails
+  // and there's no detailed report needed.
+  if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
+                                 *parent_fields, &match_list1, &match_list2) &&
+      reporter_ == NULL) {
+    return false;
+  }
+
+  bool fieldDifferent = false;
+  SpecificField specific_field;
+  specific_field.field = repeated_field;
+
+  // At this point, we have already matched pairs of fields (with the reporting
+  // to be done later). Now to check if the paired elements are different.
+  for (int i = 0; i < count1; i++) {
+    if (match_list1[i] == -1) continue;
+    specific_field.index = i;
+    specific_field.new_index = match_list1[i];
+
+    const bool result = CompareFieldValueUsingParentFields(
+        message1, message2, repeated_field, i, specific_field.new_index,
+        parent_fields);
+
+    // If we have found differences, either report them or terminate if
+    // no reporter is present. Note that ReportModified, ReportMoved, and
+    // ReportMatched are all mutually exclusive.
+    if (!result) {
+      if (reporter_ == NULL) return false;
+      parent_fields->push_back(specific_field);
+      reporter_->ReportModified(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+      fieldDifferent = true;
+    } else if (reporter_ != NULL &&
+               specific_field.index != specific_field.new_index) {
+      parent_fields->push_back(specific_field);
+      reporter_->ReportMoved(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+    } else if (report_matches_ && reporter_ != NULL) {
+      parent_fields->push_back(specific_field);
+      reporter_->ReportMatched(message1, message2, *parent_fields);
+      parent_fields->pop_back();
+    }
+  }
+
+  // Report any remaining additions or deletions.
+  for (int i = 0; i < count2; ++i) {
+    if (match_list2[i] != -1) continue;
+    if (!treated_as_subset) {
+      fieldDifferent = true;
+    }
+
+    if (reporter_ == NULL) continue;
+    specific_field.index = i;
+    specific_field.new_index = i;
+    parent_fields->push_back(specific_field);
+    reporter_->ReportAdded(message1, message2, *parent_fields);
+    parent_fields->pop_back();
+  }
+
+  for (int i = 0; i < count1; ++i) {
+    if (match_list1[i] != -1) continue;
+    specific_field.index = i;
+    parent_fields->push_back(specific_field);
+    reporter_->ReportDeleted(message1, message2, *parent_fields);
+    parent_fields->pop_back();
+    fieldDifferent = true;
+  }
+  return !fieldDifferent;
+}
+
+bool MessageDifferencer::CompareFieldValue(const Message& message1,
+                                           const Message& message2,
+                                           const FieldDescriptor* field,
+                                           int index1,
+                                           int index2) {
+  return CompareFieldValueUsingParentFields(message1, message2, field, index1,
+                                            index2, NULL);
+}
+
+bool MessageDifferencer::CompareFieldValueUsingParentFields(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* field, int index1, int index2,
+    vector<SpecificField>* parent_fields) {
+  FieldContext field_context(parent_fields);
+  FieldComparator::ComparisonResult result = GetFieldComparisonResult(
+      message1, message2, field, index1, index2, &field_context);
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      result == FieldComparator::RECURSE) {
+    // Get the nested messages and compare them using one of the Compare
+    // methods.
+    const Reflection* reflection1 = message1.GetReflection();
+    const Reflection* reflection2 = message2.GetReflection();
+    const Message& m1 = field->is_repeated() ?
+        reflection1->GetRepeatedMessage(message1, field, index1) :
+        reflection1->GetMessage(message1, field);
+    const Message& m2 = field->is_repeated() ?
+        reflection2->GetRepeatedMessage(message2, field, index2) :
+        reflection2->GetMessage(message2, field);
+
+    // parent_fields is used in calls to Reporter methods.
+    if (parent_fields != NULL) {
+      // Append currently compared field to the end of parent_fields.
+      SpecificField specific_field;
+      specific_field.field = field;
+      specific_field.index = index1;
+      specific_field.new_index = index2;
+      parent_fields->push_back(specific_field);
+      const bool compare_result = Compare(m1, m2, parent_fields);
+      parent_fields->pop_back();
+      return compare_result;
+    } else {
+      // Recreates parent_fields as if m1 and m2 had no parents.
+      return Compare(m1, m2);
+    }
+  } else {
+    return (result == FieldComparator::SAME);
+  }
+}
+
+bool MessageDifferencer::CheckPathChanged(
+    const vector<SpecificField>& field_path) {
+  for (int i = 0; i < field_path.size(); ++i) {
+    if (field_path[i].index != field_path[i].new_index) return true;
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (field->is_map()) return true;
+  if (repeated_field_comparison_ == AS_SET)
+    return list_fields_.find(field) == list_fields_.end();
+  return (set_fields_.find(field) != set_fields_.end());
+}
+
+bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
+  return scope_ == PARTIAL &&
+      (IsTreatedAsSet(field) || GetMapKeyComparator(field) != NULL);
+}
+
+bool MessageDifferencer::IsIgnored(
+    const Message& message1,
+    const Message& message2,
+    const FieldDescriptor* field,
+    const vector<SpecificField>& parent_fields) {
+  if (ignored_fields_.find(field) != ignored_fields_.end()) {
+    return true;
+  }
+  for (int i = 0; i < ignore_criteria_.size(); ++i) {
+    if (ignore_criteria_[i]->IsIgnored(message1, message2, field,
+                                       parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MessageDifferencer::IsUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const SpecificField& field, const vector<SpecificField>& parent_fields) {
+  for (int i = 0; i < ignore_criteria_.size(); ++i) {
+    if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field,
+                                                   parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const MessageDifferencer::MapKeyComparator* MessageDifferencer
+    ::GetMapKeyComparator(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return NULL;
+  if (map_field_key_comparator_.find(field) !=
+      map_field_key_comparator_.end()) {
+    return map_field_key_comparator_[field];
+  }
+  return NULL;
+}
+
+namespace {
+
+typedef pair<int, const UnknownField*> IndexUnknownFieldPair;
+
+struct UnknownFieldOrdering {
+  inline bool operator()(const IndexUnknownFieldPair& a,
+                         const IndexUnknownFieldPair& b) const {
+    if (a.second->number() < b.second->number()) return true;
+    if (a.second->number() > b.second->number()) return false;
+    return a.second->type() < b.second->type();
+  }
+};
+
+}  // namespace
+
+bool MessageDifferencer::UnpackAny(const Message& any,
+                                   google::protobuf::scoped_ptr<Message>* data) {
+  const Reflection* reflection = any.GetReflection();
+  const FieldDescriptor* type_url_field;
+  const FieldDescriptor* value_field;
+  if (!internal::GetAnyFieldDescriptors(any, &type_url_field, &value_field)) {
+    return false;
+  }
+  const string& type_url = reflection->GetString(any, type_url_field);
+  string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+    return false;
+  }
+
+  const google::protobuf::Descriptor* desc =
+      any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
+          full_type_name);
+  if (desc == NULL) {
+    GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found";
+    return false;
+  }
+
+  if (dynamic_message_factory_ == NULL) {
+    dynamic_message_factory_.reset(new DynamicMessageFactory());
+  }
+  data->reset(dynamic_message_factory_->GetPrototype(desc)->New());
+  string serialized_value = reflection->GetString(any, value_field);
+  if (!(*data)->ParseFromString(serialized_value)) {
+    GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
+    return false;
+  }
+  return true;
+}
+
+bool MessageDifferencer::CompareUnknownFields(
+    const Message& message1, const Message& message2,
+    const google::protobuf::UnknownFieldSet& unknown_field_set1,
+    const google::protobuf::UnknownFieldSet& unknown_field_set2,
+    vector<SpecificField>* parent_field) {
+  // Ignore unknown fields in EQUIVALENT mode.
+  if (message_field_comparison_ == EQUIVALENT) return true;
+
+  if (unknown_field_set1.empty() && unknown_field_set2.empty()) {
+    return true;
+  }
+
+  bool is_different = false;
+
+  // We first sort the unknown fields by field number and type (in other words,
+  // in tag order), making sure to preserve ordering of values with the same
+  // tag.  This allows us to report only meaningful differences between the
+  // two sets -- that is, differing values for the same tag.  We use
+  // IndexUnknownFieldPairs to keep track of the field's original index for
+  // reporting purposes.
+  vector<IndexUnknownFieldPair> fields1;  // unknown_field_set1, sorted
+  vector<IndexUnknownFieldPair> fields2;  // unknown_field_set2, sorted
+  fields1.reserve(unknown_field_set1.field_count());
+  fields2.reserve(unknown_field_set2.field_count());
+
+  for (int i = 0; i < unknown_field_set1.field_count(); i++) {
+    fields1.push_back(std::make_pair(i, &unknown_field_set1.field(i)));
+  }
+  for (int i = 0; i < unknown_field_set2.field_count(); i++) {
+    fields2.push_back(std::make_pair(i, &unknown_field_set2.field(i)));
+  }
+
+  UnknownFieldOrdering is_before;
+  std::stable_sort(fields1.begin(), fields1.end(), is_before);
+  std::stable_sort(fields2.begin(), fields2.end(), is_before);
+
+  // In order to fill in SpecificField::index, we have to keep track of how
+  // many values we've seen with the same field number and type.
+  // current_repeated points at the first field in this range, and
+  // current_repeated_start{1,2} are the indexes of the first field in the
+  // range within fields1 and fields2.
+  const UnknownField* current_repeated = NULL;
+  int current_repeated_start1 = 0;
+  int current_repeated_start2 = 0;
+
+  // Now that we have two sorted lists, we can detect fields which appear only
+  // in one list or the other by traversing them simultaneously.
+  int index1 = 0;
+  int index2 = 0;
+  while (index1 < fields1.size() || index2 < fields2.size()) {
+    enum { ADDITION, DELETION, MODIFICATION, COMPARE_GROUPS,
+      NO_CHANGE } change_type;
+
+    // focus_field is the field we're currently reporting on.  (In the case
+    // of a modification, it's the field on the left side.)
+    const UnknownField* focus_field;
+    bool match = false;
+
+    if (index2 == fields2.size() ||
+        (index1 < fields1.size() &&
+          is_before(fields1[index1], fields2[index2]))) {
+      // fields1[index1] is not present in fields2.
+      change_type = DELETION;
+      focus_field = fields1[index1].second;
+    } else if (index1 == fields1.size() ||
+               is_before(fields2[index2], fields1[index1])) {
+      // fields2[index2] is not present in fields1.
+      if (scope_ == PARTIAL) {
+        // Ignore.
+        ++index2;
+        continue;
+      }
+      change_type = ADDITION;
+      focus_field = fields2[index2].second;
+    } else {
+      // Field type and number are the same.  See if the values differ.
+      change_type = MODIFICATION;
+      focus_field = fields1[index1].second;
+
+      switch (focus_field->type()) {
+        case UnknownField::TYPE_VARINT:
+          match = fields1[index1].second->varint() ==
+                  fields2[index2].second->varint();
+          break;
+        case UnknownField::TYPE_FIXED32:
+          match = fields1[index1].second->fixed32() ==
+                  fields2[index2].second->fixed32();
+          break;
+        case UnknownField::TYPE_FIXED64:
+          match = fields1[index1].second->fixed64() ==
+                  fields2[index2].second->fixed64();
+          break;
+        case UnknownField::TYPE_LENGTH_DELIMITED:
+          match = fields1[index1].second->length_delimited() ==
+                  fields2[index2].second->length_delimited();
+          break;
+        case UnknownField::TYPE_GROUP:
+          // We must deal with this later, after building the SpecificField.
+          change_type = COMPARE_GROUPS;
+          break;
+      }
+      if (match && change_type != COMPARE_GROUPS) {
+        change_type = NO_CHANGE;
+      }
+    }
+
+    if (current_repeated == NULL ||
+        focus_field->number() != current_repeated->number() ||
+        focus_field->type() != current_repeated->type()) {
+      // We've started a new repeated field.
+      current_repeated = focus_field;
+      current_repeated_start1 = index1;
+      current_repeated_start2 = index2;
+    }
+
+    if (change_type == NO_CHANGE && reporter_ == NULL) {
+      // Fields were already compared and matched and we have no reporter.
+      ++index1;
+      ++index2;
+      continue;
+    }
+
+    // Build the SpecificField.  This is slightly complicated.
+    SpecificField specific_field;
+    specific_field.unknown_field_number = focus_field->number();
+    specific_field.unknown_field_type = focus_field->type();
+
+    specific_field.unknown_field_set1 = &unknown_field_set1;
+    specific_field.unknown_field_set2 = &unknown_field_set2;
+
+    if (change_type != ADDITION) {
+      specific_field.unknown_field_index1 = fields1[index1].first;
+    }
+    if (change_type != DELETION) {
+      specific_field.unknown_field_index2 = fields2[index2].first;
+    }
+
+    // Calculate the field index.
+    if (change_type == ADDITION) {
+      specific_field.index = index2 - current_repeated_start2;
+      specific_field.new_index = index2 - current_repeated_start2;
+    } else {
+      specific_field.index = index1 - current_repeated_start1;
+      specific_field.new_index = index2 - current_repeated_start2;
+    }
+
+    if (IsUnknownFieldIgnored(message1, message2, specific_field,
+                              *parent_field)) {
+      if (reporter_ != NULL) {
+        parent_field->push_back(specific_field);
+        reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
+        parent_field->pop_back();
+      }
+      return true;
+    }
+
+    if (change_type == ADDITION || change_type == DELETION ||
+        change_type == MODIFICATION) {
+      if (reporter_ == NULL) {
+        // We found a difference and we have no reproter.
+        return false;
+      }
+      is_different = true;
+    }
+
+    parent_field->push_back(specific_field);
+
+    switch (change_type) {
+      case ADDITION:
+        reporter_->ReportAdded(message1, message2, *parent_field);
+        ++index2;
+        break;
+      case DELETION:
+        reporter_->ReportDeleted(message1, message2, *parent_field);
+        ++index1;
+        break;
+      case MODIFICATION:
+        reporter_->ReportModified(message1, message2, *parent_field);
+        ++index1;
+        ++index2;
+        break;
+      case COMPARE_GROUPS:
+        if (!CompareUnknownFields(message1, message2,
+                                  fields1[index1].second->group(),
+                                  fields2[index2].second->group(),
+                                  parent_field)) {
+          if (reporter_ == NULL) return false;
+          is_different = true;
+          reporter_->ReportModified(message1, message2, *parent_field);
+        }
+        ++index1;
+        ++index2;
+        break;
+      case NO_CHANGE:
+        ++index1;
+        ++index2;
+        if (report_matches_) {
+          reporter_->ReportMatched(message1, message2, *parent_field);
+        }
+    }
+
+    parent_field->pop_back();
+  }
+
+  return !is_different;
+}
+
+namespace {
+
+// Find maximum bipartite matching using the argumenting path algorithm.
+class MaximumMatcher {
+ public:
+  typedef ResultCallback2<bool, int, int> NodeMatchCallback;
+  // MaximumMatcher takes ownership of the passed in callback and uses it to
+  // determine whether a node on the left side of the bipartial graph matches
+  // a node on the right side. count1 is the number of nodes on the left side
+  // of the graph and count2 to is the number of nodes on the right side.
+  // Every node is referred to using 0-based indices.
+  // If a maximum match is found, the result will be stored in match_list1 and
+  // match_list2. match_list1[i] == j means the i-th node on the left side is
+  // matched to the j-th node on the right side and match_list2[x] == y means
+  // the x-th node on the right side is matched to y-th node on the left side.
+  // match_list1[i] == -1 means the node is not matched. Same with match_list2.
+  MaximumMatcher(int count1, int count2, NodeMatchCallback* callback,
+                 vector<int>* match_list1, vector<int>* match_list2);
+  // Find a maximum match and return the number of matched node pairs.
+  // If early_return is true, this method will return 0 immediately when it
+  // finds that not all nodes on the left side can be matched.
+  int FindMaximumMatch(bool early_return);
+ private:
+  // Determines whether the node on the left side of the bipartial graph
+  // matches the one on the right side.
+  bool Match(int left, int right);
+  // Find an argumenting path starting from the node v on the left side. If a
+  // path can be found, update match_list2_ to reflect the path and return
+  // true.
+  bool FindArgumentPathDFS(int v, vector<bool>* visited);
+
+  int count1_;
+  int count2_;
+  google::protobuf::scoped_ptr<NodeMatchCallback> match_callback_;
+  map<pair<int, int>, bool> cached_match_results_;
+  vector<int>* match_list1_;
+  vector<int>* match_list2_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
+};
+
+MaximumMatcher::MaximumMatcher(int count1, int count2,
+                               NodeMatchCallback* callback,
+                               vector<int>* match_list1,
+                               vector<int>* match_list2)
+    : count1_(count1), count2_(count2), match_callback_(callback),
+      match_list1_(match_list1), match_list2_(match_list2) {
+  match_list1_->assign(count1, -1);
+  match_list2_->assign(count2, -1);
+}
+
+int MaximumMatcher::FindMaximumMatch(bool early_return) {
+  int result = 0;
+  for (int i = 0; i < count1_; ++i) {
+    vector<bool> visited(count1_);
+    if (FindArgumentPathDFS(i, &visited)) {
+      ++result;
+    } else if (early_return) {
+      return 0;
+    }
+  }
+  // Backfill match_list1_ as we only filled match_list2_ when finding
+  // argumenting pathes.
+  for (int i = 0; i < count2_; ++i) {
+    if ((*match_list2_)[i] != -1) {
+      (*match_list1_)[(*match_list2_)[i]] = i;
+    }
+  }
+  return result;
+}
+
+bool MaximumMatcher::Match(int left, int right) {
+  pair<int, int> p(left, right);
+  map<pair<int, int>, bool>::iterator it = cached_match_results_.find(p);
+  if (it != cached_match_results_.end()) {
+    return it->second;
+  }
+  cached_match_results_[p] = match_callback_->Run(left, right);
+  return cached_match_results_[p];
+}
+
+bool MaximumMatcher::FindArgumentPathDFS(int v, vector<bool>* visited) {
+  (*visited)[v] = true;
+  // We try to match those un-matched nodes on the right side first. This is
+  // the step that the navie greedy matching algorithm uses. In the best cases
+  // where the greedy algorithm can find a maximum matching, we will always
+  // find a match in this step and the performance will be identical to the
+  // greedy algorithm.
+  for (int i = 0; i < count2_; ++i) {
+    int matched = (*match_list2_)[i];
+    if (matched == -1 && Match(v, i)) {
+      (*match_list2_)[i] = v;
+      return true;
+    }
+  }
+  // Then we try those already matched nodes and see if we can find an
+  // alternaive match for the node matched to them.
+  // The greedy algorithm will stop before this and fail to produce the
+  // correct result.
+  for (int i = 0; i < count2_; ++i) {
+    int matched = (*match_list2_)[i];
+    if (matched != -1 && Match(v, i)) {
+      if (!(*visited)[matched] && FindArgumentPathDFS(matched, visited)) {
+        (*match_list2_)[i] = v;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+bool MessageDifferencer::MatchRepeatedFieldIndices(
+    const Message& message1,
+    const Message& message2,
+    const FieldDescriptor* repeated_field,
+    const vector<SpecificField>& parent_fields,
+    vector<int>* match_list1,
+    vector<int>* match_list2) {
+  const int count1 =
+      message1.GetReflection()->FieldSize(message1, repeated_field);
+  const int count2 =
+      message2.GetReflection()->FieldSize(message2, repeated_field);
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
+
+  match_list1->assign(count1, -1);
+  match_list2->assign(count2, -1);
+
+  SpecificField specific_field;
+  specific_field.field = repeated_field;
+
+  bool success = true;
+  // Find potential match if this is a special repeated field.
+  if (key_comparator != NULL || IsTreatedAsSet(repeated_field)) {
+    if (scope_ == PARTIAL) {
+      // When partial matching is enabled, Compare(a, b) && Compare(a, c)
+      // doesn't neccessarily imply Compare(b, c). Therefore a naive greedy
+      // algorithm will fail to find a maximum matching.
+      // Here we use the argumenting path algorithm.
+      MaximumMatcher::NodeMatchCallback* callback =
+          ::google::protobuf::internal::NewPermanentCallback(
+              this, &MessageDifferencer::IsMatch,
+              repeated_field, key_comparator,
+              &message1, &message2, parent_fields);
+      MaximumMatcher matcher(count1, count2, callback, match_list1,
+                             match_list2);
+      // If diff info is not needed, we should end the matching process as
+      // soon as possible if not all items can be matched.
+      bool early_return = (reporter_ == NULL);
+      int match_count = matcher.FindMaximumMatch(early_return);
+      if (match_count != count1 && reporter_ == NULL) return false;
+      success = success && (match_count == count1);
+    } else {
+      for (int i = 0; i < count1; ++i) {
+        // Indicates any matched elements for this repeated field.
+        bool match = false;
+
+        specific_field.index = i;
+        specific_field.new_index = i;
+
+        for (int j = 0; j < count2; j++) {
+          if (match_list2->at(j) != -1) continue;
+          specific_field.index = i;
+          specific_field.new_index = j;
+
+          match = IsMatch(repeated_field, key_comparator,
+                          &message1, &message2, parent_fields, i, j);
+
+          if (match) {
+            match_list1->at(specific_field.index) = specific_field.new_index;
+            match_list2->at(specific_field.new_index) = specific_field.index;
+            break;
+          }
+        }
+        if (!match && reporter_ == NULL) return false;
+        success = success && match;
+      }
+    }
+  } else {
+    // If this field should be treated as list, just label the match_list.
+    for (int i = 0; i < count1 && i < count2; i++) {
+      match_list1->at(i) = i;
+      match_list2->at(i) = i;
+    }
+  }
+
+  return success;
+}
+
+FieldComparator::ComparisonResult MessageDifferencer::GetFieldComparisonResult(
+    const Message& message1, const Message& message2,
+    const FieldDescriptor* field, int index1, int index2,
+    const FieldContext* field_context) {
+  FieldComparator* comparator = field_comparator_ != NULL ?
+      field_comparator_ : &default_field_comparator_;
+  return comparator->Compare(message1, message2, field,
+                             index1, index2, field_context);
+}
+
+// ===========================================================================
+
+MessageDifferencer::Reporter::Reporter() { }
+MessageDifferencer::Reporter::~Reporter() {}
+
+// ===========================================================================
+
+MessageDifferencer::MapKeyComparator::MapKeyComparator() {}
+MessageDifferencer::MapKeyComparator::~MapKeyComparator() {}
+
+// ===========================================================================
+
+MessageDifferencer::IgnoreCriteria::IgnoreCriteria() {}
+MessageDifferencer::IgnoreCriteria::~IgnoreCriteria() {}
+
+// ===========================================================================
+
+// Note that the printer's delimiter is not used, because if we are given a
+// printer, we don't know its delimiter.
+MessageDifferencer::StreamReporter::StreamReporter(
+    io::ZeroCopyOutputStream* output) : printer_(new io::Printer(output, '$')),
+                                        delete_printer_(true),
+                                        report_modified_aggregates_(false) { }
+
+MessageDifferencer::StreamReporter::StreamReporter(
+    io::Printer* printer) : printer_(printer),
+                            delete_printer_(false),
+                            report_modified_aggregates_(false) { }
+
+MessageDifferencer::StreamReporter::~StreamReporter() {
+  if (delete_printer_) delete printer_;
+}
+
+void MessageDifferencer::StreamReporter::PrintPath(
+    const vector<SpecificField>& field_path, bool left_side) {
+  for (int i = 0; i < field_path.size(); ++i) {
+    if (i > 0) {
+      printer_->Print(".");
+    }
+
+    SpecificField specific_field = field_path[i];
+
+    if (specific_field.field != NULL) {
+      if (specific_field.field->is_extension()) {
+        printer_->Print("($name$)", "name",
+                        specific_field.field->full_name());
+      } else {
+        printer_->PrintRaw(specific_field.field->name());
+      }
+    } else {
+      printer_->PrintRaw(SimpleItoa(specific_field.unknown_field_number));
+    }
+    if (left_side && specific_field.index >= 0) {
+      printer_->Print("[$name$]", "name", SimpleItoa(specific_field.index));
+    }
+    if (!left_side && specific_field.new_index >= 0) {
+      printer_->Print("[$name$]", "name", SimpleItoa(specific_field.new_index));
+    }
+  }
+}
+
+void MessageDifferencer::
+StreamReporter::PrintValue(const Message& message,
+                           const vector<SpecificField>& field_path,
+                           bool left_side) {
+  const SpecificField& specific_field = field_path.back();
+  const FieldDescriptor* field = specific_field.field;
+  if (field != NULL) {
+    string output;
+    int index = left_side ? specific_field.index : specific_field.new_index;
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const Reflection* reflection = message.GetReflection();
+      const Message& field_message = field->is_repeated() ?
+          reflection->GetRepeatedMessage(message, field, index) :
+          reflection->GetMessage(message, field);
+      output = field_message.ShortDebugString();
+      if (output.empty()) {
+        printer_->Print("{ }");
+      } else {
+        printer_->Print("{ $name$ }", "name", output);
+      }
+    } else {
+      TextFormat::PrintFieldValueToString(message, field, index, &output);
+      printer_->PrintRaw(output);
+    }
+  } else {
+    const UnknownFieldSet* unknown_fields =
+        (left_side ?
+         specific_field.unknown_field_set1 :
+         specific_field.unknown_field_set2);
+    const UnknownField* unknown_field = &unknown_fields->field(
+        left_side ?
+        specific_field.unknown_field_index1 :
+        specific_field.unknown_field_index2);
+    PrintUnknownFieldValue(unknown_field);
+  }
+}
+
+void MessageDifferencer::
+StreamReporter::PrintUnknownFieldValue(const UnknownField* unknown_field) {
+  GOOGLE_CHECK(unknown_field != NULL) << " Cannot print NULL unknown_field.";
+
+  string output;
+  switch (unknown_field->type()) {
+    case UnknownField::TYPE_VARINT:
+      output = SimpleItoa(unknown_field->varint());
+      break;
+    case UnknownField::TYPE_FIXED32:
+      output = StrCat("0x", strings::Hex(unknown_field->fixed32(),
+                                         strings::ZERO_PAD_8));
+      break;
+    case UnknownField::TYPE_FIXED64:
+      output = StrCat("0x", strings::Hex(unknown_field->fixed64(),
+                                         strings::ZERO_PAD_16));
+      break;
+    case UnknownField::TYPE_LENGTH_DELIMITED:
+      output = StringPrintf("\"%s\"",
+          CEscape(unknown_field->length_delimited()).c_str());
+      break;
+    case UnknownField::TYPE_GROUP:
+      // TODO(kenton):  Print the contents of the group like we do for
+      //   messages.  Requires an equivalent of ShortDebugString() for
+      //   UnknownFieldSet.
+      output = "{ ... }";
+      break;
+  }
+  printer_->PrintRaw(output);
+}
+
+void MessageDifferencer::StreamReporter::Print(const string& str) {
+  printer_->Print(str.c_str());
+}
+
+void MessageDifferencer::StreamReporter::ReportAdded(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("added: ");
+  PrintPath(field_path, false);
+  printer_->Print(": ");
+  PrintValue(message2, field_path, false);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportDeleted(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("deleted: ");
+  PrintPath(field_path, true);
+  printer_->Print(": ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines
+}
+
+void MessageDifferencer::StreamReporter::ReportModified(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  if (!report_modified_aggregates_ && field_path.back().field == NULL) {
+    if (field_path.back().unknown_field_type == UnknownField::TYPE_GROUP) {
+      // Any changes to the subfields have already been printed.
+      return;
+    }
+  } else if (!report_modified_aggregates_) {
+    if (field_path.back().field->cpp_type() ==
+        FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Any changes to the subfields have already been printed.
+      return;
+    }
+  }
+
+  printer_->Print("modified: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print(": ");
+  PrintValue(message1, field_path, true);
+  printer_->Print(" -> ");
+  PrintValue(message2, field_path, false);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportMoved(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("moved: ");
+  PrintPath(field_path, true);
+  printer_->Print(" -> ");
+  PrintPath(field_path, false);
+  printer_->Print(" : ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportMatched(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("matched: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print(" : ");
+  PrintValue(message1, field_path, true);
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportIgnored(
+    const Message& message1,
+    const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("ignored: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print("\n");  // Print for newlines.
+}
+
+void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("ignored: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print("\n");  // Print for newlines.
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
new file mode 100644
index 0000000..3ea74e6
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer.h
@@ -0,0 +1,843 @@
+// 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.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file defines static methods and classes for comparing Protocol
+// Messages.
+//
+// Aug. 2008: Added Unknown Fields Comparison for messages.
+// Aug. 2009: Added different options to compare repeated fields.
+// Apr. 2010: Moved field comparison to FieldComparator.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+#define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <google/protobuf/descriptor.h>  // FieldDescriptor
+#include <google/protobuf/message.h>  // Message
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/util/field_comparator.h>
+
+namespace google {
+namespace protobuf {
+
+class DynamicMessageFactory;
+class FieldDescriptor;
+
+namespace io {
+class ZeroCopyOutputStream;
+class Printer;
+}
+
+namespace util {
+
+class FieldContext;  // declared below MessageDifferencer
+
+// A basic differencer that can be used to determine
+// the differences between two specified Protocol Messages. If any differences
+// are found, the Compare method will return false, and any differencer reporter
+// specified via ReportDifferencesTo will have its reporting methods called (see
+// below for implementation of the report). Based off of the original
+// ProtocolDifferencer implementation in //net/proto/protocol-differencer.h
+// (Thanks Todd!).
+//
+// MessageDifferencer REQUIRES that compared messages be the same type, defined
+// as messages that share the same descriptor.  If not, the behavior of this
+// class is undefined.
+//
+// People disagree on what MessageDifferencer should do when asked to compare
+// messages with different descriptors.  Some people think it should always
+// return false.  Others expect it to try to look for similar fields and
+// compare them anyway -- especially if the descriptors happen to be identical.
+// If we chose either of these behaviors, some set of people would find it
+// surprising, and could end up writing code expecting the other behavior
+// without realizing their error.  Therefore, we forbid that usage.
+//
+// This class is implemented based on the proto2 reflection. The performance
+// should be good enough for normal usages. However, for places where the
+// performance is extremely sensitive, there are several alternatives:
+// - Comparing serialized string
+// Downside: false negatives (there are messages that are the same but their
+// serialized strings are different).
+// - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin)
+// Downside: more generated code; maintenance overhead for the additional rule
+// (must be in sync with the original proto_library).
+//
+// Note on handling of google.protobuf.Any: MessageDifferencer automatically
+// unpacks Any::value into a Message and compares its individual fields.
+// Messages encoded in a repeated Any cannot be compared using TreatAsMap.
+//
+//
+// Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to
+// guard it with a lock to use the same MessageDifferencer instance from
+// multiple threads. Note that it's fine to call static comparison methods
+// (like MessageDifferencer::Equals) concurrently.
+class LIBPROTOBUF_EXPORT MessageDifferencer {
+ public:
+  // Determines whether the supplied messages are equal. Equality is defined as
+  // all fields within the two messages being set to the same value. Primitive
+  // fields and strings are compared by value while embedded messages/groups
+  // are compared as if via a recursive call. Use IgnoreField() and Compare()
+  // if some fields should be ignored in the comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool Equals(const Message& message1, const Message& message2);
+
+  // Determines whether the supplied messages are equivalent. Equivalency is
+  // defined as all fields within the two messages having the same value. This
+  // differs from the Equals method above in that fields with default values
+  // are considered set to said value automatically. For details on how default
+  // values are defined for each field type, see http://shortn/_x2Gv6XFrWt.
+  // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare()
+  // if some fields should be ignored in the comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool Equivalent(const Message& message1, const Message& message2);
+
+  // Determines whether the supplied messages are approximately equal.
+  // Approximate equality is defined as all fields within the two messages
+  // being approximately equal.  Primitive (non-float) fields and strings are
+  // compared by value, floats are compared using MathUtil::AlmostEquals() and
+  // embedded messages/groups are compared as if via a recursive call. Use
+  // IgnoreField() and Compare() if some fields should be ignored in the
+  // comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool ApproximatelyEquals(const Message& message1,
+                                  const Message& message2);
+
+  // Determines whether the supplied messages are approximately equivalent.
+  // Approximate equivalency is defined as all fields within the two messages
+  // being approximately equivalent. As in
+  // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and
+  // strings are compared by value, floats are compared using
+  // MathUtil::AlmostEquals() and embedded messages/groups are compared as if
+  // via a recursive call. However, fields with default values are considered
+  // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField()
+  // and Compare() if some fields should be ignored in the comparison.
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  static bool ApproximatelyEquivalent(const Message& message1,
+                                      const Message& message2);
+
+  // Identifies an individual field in a message instance.  Used for field_path,
+  // below.
+  struct SpecificField {
+    // For known fields, "field" is filled in and "unknown_field_number" is -1.
+    // For unknown fields, "field" is NULL, "unknown_field_number" is the field
+    // number, and "unknown_field_type" is its type.
+    const FieldDescriptor* field;
+    int unknown_field_number;
+    UnknownField::Type unknown_field_type;
+
+    // If this a repeated field, "index" is the index within it.  For unknown
+    // fields, this is the index of the field among all unknown fields of the
+    // same field number and type.
+    int index;
+
+    // If "field" is a repeated field which is being treated as a map or
+    // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates
+    // the index the position to which the element has moved.  This only
+    // applies to ReportMoved() and (in the case of TreatAsMap())
+    // ReportModified().  In all other cases, "new_index" will have the same
+    // value as "index".
+    int new_index;
+
+    // For unknown fields, these are the pointers to the UnknownFieldSet
+    // containing the unknown fields. In certain cases (e.g. proto1's
+    // MessageSet, or nested groups of unknown fields), these may differ from
+    // the messages' internal UnknownFieldSets.
+    const UnknownFieldSet* unknown_field_set1;
+    const UnknownFieldSet* unknown_field_set2;
+
+    // For unknown fields, these are the index of the field within the
+    // UnknownFieldSets. One or the other will be -1 when
+    // reporting an addition or deletion.
+    int unknown_field_index1;
+    int unknown_field_index2;
+
+    SpecificField()
+        : field(NULL),
+          unknown_field_number(-1),
+          index(-1),
+          new_index(-1),
+          unknown_field_set1(NULL),
+          unknown_field_set2(NULL),
+          unknown_field_index1(-1),
+          unknown_field_index2(-1) {}
+  };
+
+  // Abstract base class from which all MessageDifferencer
+  // reporters derive. The five Report* methods below will be called when
+  // a field has been added, deleted, modified, moved, or matched. The third
+  // argument is a vector of FieldDescriptor pointers which describes the chain
+  // of fields that was taken to find the current field. For example, for a
+  // field found in an embedded message, the vector will contain two
+  // FieldDescriptors. The first will be the field of the embedded message
+  // itself and the second will be the actual field in the embedded message
+  // that was added/deleted/modified.
+  class LIBPROTOBUF_EXPORT Reporter {
+   public:
+    Reporter();
+    virtual ~Reporter();
+
+    // Reports that a field has been added into Message2.
+    virtual void ReportAdded(
+        const Message& message1, const Message& message2,
+        const vector<SpecificField>& field_path) = 0;
+
+    // Reports that a field has been deleted from Message1.
+    virtual void ReportDeleted(
+        const Message& message1,
+        const Message& message2,
+        const vector<SpecificField>& field_path) = 0;
+
+    // Reports that the value of a field has been modified.
+    virtual void ReportModified(
+        const Message& message1,
+        const Message& message2,
+        const vector<SpecificField>& field_path) = 0;
+
+    // Reports that a repeated field has been moved to another location.  This
+    // only applies when using TreatAsSet or TreatAsMap()  -- see below. Also
+    // note that for any given field, ReportModified and ReportMoved are
+    // mutually exclusive. If a field has been both moved and modified, then
+    // only ReportModified will be called.
+    virtual void ReportMoved(
+        const Message& message1,
+        const Message& message2,
+        const vector<SpecificField>& field_path) { }
+
+    // Reports that two fields match. Useful for doing side-by-side diffs.
+    // This function is mutually exclusive with ReportModified and ReportMoved.
+    // Note that you must call set_report_matches(true) before calling Compare
+    // to make use of this function.
+    virtual void ReportMatched(
+        const Message& message1,
+        const Message& message2,
+        const vector<SpecificField>& field_path) { }
+
+    // Reports that two fields would have been compared, but the
+    // comparison has been skipped because the field was marked as
+    // 'ignored' using IgnoreField().  This function is mutually
+    // exclusive with all the other Report() functions.
+    //
+    // The contract of ReportIgnored is slightly different than the
+    // other Report() functions, in that |field_path.back().index| is
+    // always equal to -1, even if the last field is repeated. This is
+    // because while the other Report() functions indicate where in a
+    // repeated field the action (Addition, Deletion, etc...)
+    // happened, when a repeated field is 'ignored', the differencer
+    // simply calls ReportIgnored on the repeated field as a whole and
+    // moves on without looking at its individual elements.
+    //
+    // Furthermore, ReportIgnored() does not indicate whether the
+    // fields were in fact equal or not, as Compare() does not inspect
+    // these fields at all. It is up to the Reporter to decide whether
+    // the fields are equal or not (perhaps with a second call to
+    // Compare()), if it cares.
+    virtual void ReportIgnored(
+        const Message& message1,
+        const Message& message2,
+        const vector<SpecificField>& field_path) { }
+
+    // Report that an unkown field is ignored. (see comment above).
+    // Note this is a different function since the last SpecificField in field
+    // path has a null field.  This could break existing Reporter.
+    virtual void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const vector<SpecificField>& field_path) {}
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter);
+  };
+
+  // MapKeyComparator is used to determine if two elements have the same key
+  // when comparing elements of a repeated field as a map.
+  class LIBPROTOBUF_EXPORT MapKeyComparator {
+   public:
+    MapKeyComparator();
+    virtual ~MapKeyComparator();
+
+    virtual bool IsMatch(const Message& message1,
+                         const Message& message2,
+                         const vector<SpecificField>& parent_fields) const {
+      GOOGLE_CHECK(false) << "IsMatch() is not implemented.";
+      return false;
+    }
+
+   private:
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapKeyComparator);
+  };
+
+  // Abstract base class from which all IgnoreCriteria derive.
+  // By adding IgnoreCriteria more complex ignore logic can be implemented.
+  // IgnoreCriteria are registed with AddIgnoreCriteria. For each compared
+  // field IsIgnored is called on each added IgnoreCriteria until one returns
+  // true or all return false.
+  // IsIgnored is called for fields where at least one side has a value.
+  class LIBPROTOBUF_EXPORT IgnoreCriteria {
+   public:
+    IgnoreCriteria();
+    virtual ~IgnoreCriteria();
+
+    // Returns true if the field should be ignored.
+    virtual bool IsIgnored(
+        const Message& message1,
+        const Message& message2,
+        const FieldDescriptor* field,
+        const vector<SpecificField>& parent_fields) = 0;
+
+    // Returns true if the unknown field should be ignored.
+    // Note: This will be called for unknown fields as well in which case
+    //       field.field will be null.
+    virtual bool IsUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const SpecificField& field,
+        const vector<SpecificField>& parent_fields) {
+      return false;
+    }
+  };
+
+  // To add a Reporter, construct default here, then use ReportDifferencesTo or
+  // ReportDifferencesToString.
+  explicit MessageDifferencer();
+
+  ~MessageDifferencer();
+
+  enum MessageFieldComparison {
+    EQUAL,       // Fields must be present in both messages
+                 // for the messages to be considered the same.
+    EQUIVALENT,  // Fields with default values are considered set
+                 // for comparison purposes even if not explicitly
+                 // set in the messages themselves.  Unknown fields
+                 // are ignored.
+  };
+
+  enum Scope {
+    FULL,    // All fields of both messages are considered in the comparison.
+    PARTIAL  // Only fields present in the first message are considered; fields
+             // set only in the second message will be skipped during
+             // comparison.
+  };
+
+  // DEPRECATED. Use FieldComparator::FloatComparison instead.
+  enum FloatComparison {
+    EXACT,       // Floats and doubles are compared exactly.
+    APPROXIMATE  // Floats and doubles are compared using the
+                 // MathUtil::AlmostEquals method.
+  };
+
+  enum RepeatedFieldComparison {
+    AS_LIST,     // Repeated fields are compared in order.  Differing values at
+                 // the same index are reported using ReportModified().  If the
+                 // repeated fields have different numbers of elements, the
+                 // unpaired elements are reported using ReportAdded() or
+                 // ReportDeleted().
+    AS_SET,      // Treat all the repeated fields as sets by default.
+                 // See TreatAsSet(), as below.
+  };
+
+  // The elements of the given repeated field will be treated as a set for
+  // diffing purposes, so different orderings of the same elements will be
+  // considered equal.  Elements which are present on both sides of the
+  // comparison but which have changed position will be reported with
+  // ReportMoved().  Elements which only exist on one side or the other are
+  // reported with ReportAdded() and ReportDeleted() regardless of their
+  // positions.  ReportModified() is never used for this repeated field.  If
+  // the only differences between the compared messages is that some fields
+  // have been moved, then the comparison returns true.
+  //
+  // If the scope of comparison is set to PARTIAL, then in addition to what's
+  // above, extra values added to repeated fields of the second message will
+  // not cause the comparison to fail.
+  //
+  // Note that set comparison is currently O(k * n^2) (where n is the total
+  // number of elements, and k is the average size of each element). In theory
+  // it could be made O(n * k) with a more complex hashing implementation. Feel
+  // free to contribute one if the current implementation is too slow for you.
+  // If partial matching is also enabled, the time complexity will be O(k * n^2
+  // + n^3) in which n^3 is the time complexity of the maximum matching
+  // algorithm.
+  //
+  // REQUIRES:  field->is_repeated() and field not registered with TreatAsList
+  void TreatAsSet(const FieldDescriptor* field);
+
+  // The elements of the given repeated field will be treated as a list for
+  // diffing purposes, so different orderings of the same elements will NOT be
+  // considered equal.
+  //
+  // REQUIRED: field->is_repeated() and field not registered with TreatAsSet
+  void TreatAsList(const FieldDescriptor* field);
+
+  // The elements of the given repeated field will be treated as a map for
+  // diffing purposes, with |key| being the map key.  Thus, elements with the
+  // same key will be compared even if they do not appear at the same index.
+  // Differences are reported similarly to TreatAsSet(), except that
+  // ReportModified() is used to report elements with the same key but
+  // different values.  Note that if an element is both moved and modified,
+  // only ReportModified() will be called.  As with TreatAsSet, if the only
+  // differences between the compared messages is that some fields have been
+  // moved, then the comparison returns true. See TreatAsSet for notes on
+  // performance.
+  //
+  // REQUIRES:  field->is_repeated()
+  // REQUIRES:  field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+  // REQUIRES:  key->containing_type() == field->message_type()
+  void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key);
+  // Same as TreatAsMap except that this method will use multiple fields as
+  // the key in comparison. All specified fields in 'key_fields' should be
+  // present in the compared elements. Two elements will be treated as having
+  // the same key iff they have the same value for every specified field. There
+  // are two steps in the comparison process. The first one is key matching.
+  // Every element from one message will be compared to every element from
+  // the other message. Only fields in 'key_fields' are compared in this step
+  // to decide if two elements have the same key. The second step is value
+  // comparison. Those pairs of elements with the same key (with equal value
+  // for every field in 'key_fields') will be compared in this step.
+  // Time complexity of the first step is O(s * m * n ^ 2) where s is the
+  // average size of the fields specified in 'key_fields', m is the number of
+  // fields in 'key_fields' and n is the number of elements. If partial
+  // matching is enabled, an extra O(n^3) will be incured by the maximum
+  // matching algorithm. The second step is O(k * n) where k is the average
+  // size of each element.
+  void TreatAsMapWithMultipleFieldsAsKey(
+      const FieldDescriptor* field,
+      const vector<const FieldDescriptor*>& key_fields);
+  // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field
+  // do not necessarily need to be a direct subfield. Each element in
+  // key_field_paths indicate a path from the message being compared, listing
+  // successive subfield to reach the key field.
+  //
+  // REQUIRES:
+  //   for key_field_path in key_field_paths:
+  //     key_field_path[0]->containing_type() == field->message_type()
+  //     for i in [0, key_field_path.size() - 1):
+  //       key_field_path[i+1]->containing_type() ==
+  //           key_field_path[i]->message_type()
+  //       key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+  //       !key_field_path[i]->is_repeated()
+  void TreatAsMapWithMultipleFieldPathsAsKey(
+      const FieldDescriptor* field,
+      const vector<vector<const FieldDescriptor*> >& key_field_paths);
+
+  // Uses a custom MapKeyComparator to determine if two elements have the same
+  // key when comparing a repeated field as a map.
+  // The caller is responsible to delete the key_comparator.
+  // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the
+  // first key matching step. Rather than comparing some specified fields, it
+  // will invoke the IsMatch method of the given 'key_comparator' to decide if
+  // two elements have the same key.
+  void TreatAsMapUsingKeyComparator(
+      const FieldDescriptor* field,
+      const MapKeyComparator* key_comparator);
+
+  // Add a custom ignore criteria that is evaluated in addition to the
+  // ignored fields added with IgnoreField.
+  // Takes ownership of ignore_criteria.
+  void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria);
+
+  // Indicates that any field with the given descriptor should be
+  // ignored for the purposes of comparing two messages. This applies
+  // to fields nested in the message structure as well as top level
+  // ones. When the MessageDifferencer encounters an ignored field,
+  // ReportIgnored is called on the reporter, if one is specified.
+  //
+  // The only place where the field's 'ignored' status is not applied is when
+  // it is being used as a key in a field passed to TreatAsMap or is one of
+  // the fields passed to TreatAsMapWithMultipleFieldsAsKey.
+  // In this case it is compared in key matching but after that it's ignored
+  // in value comparison.
+  void IgnoreField(const FieldDescriptor* field);
+
+  // Sets the field comparator used to determine differences between protocol
+  // buffer fields. By default it's set to a DefaultFieldComparator instance.
+  // MessageDifferencer doesn't take ownership over the passed object.
+  // Note that this method must be called before Compare for the comparator to
+  // be used.
+  void set_field_comparator(FieldComparator* comparator);
+
+  // DEPRECATED. Pass a DefaultFieldComparator instance instead.
+  // Sets the fraction and margin for the float comparison of a given field.
+  // Uses MathUtil::WithinFractionOrMargin to compare the values.
+  // NOTE: this method does nothing if differencer's field comparator has been
+  //       set to a custom object.
+  //
+  // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
+  //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
+  // REQUIRES: float_comparison_ == APPROXIMATE
+  void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
+                            double margin);
+
+  // Sets the type of comparison (as defined in the MessageFieldComparison
+  // enumeration above) that is used by this differencer when determining how
+  // to compare fields in messages.
+  void set_message_field_comparison(MessageFieldComparison comparison);
+
+  // Tells the differencer whether or not to report matches. This method must
+  // be called before Compare. The default for a new differencer is false.
+  void set_report_matches(bool report_matches) {
+    report_matches_ = report_matches;
+  }
+
+  // Sets the scope of the comparison (as defined in the Scope enumeration
+  // above) that is used by this differencer when determining which fields to
+  // compare between the messages.
+  void set_scope(Scope scope);
+
+  // Returns the current scope used by this differencer.
+  Scope scope();
+
+  // DEPRECATED. Pass a DefaultFieldComparator instance instead.
+  // Sets the type of comparison (as defined in the FloatComparison enumeration
+  // above) that is used by this differencer when comparing float (and double)
+  // fields in messages.
+  // NOTE: this method does nothing if differencer's field comparator has been
+  //       set to a custom object.
+  void set_float_comparison(FloatComparison comparison);
+
+  // Sets the type of comparison for repeated field (as defined in the
+  // RepeatedFieldComparison enumeration above) that is used by this
+  // differencer when compare repeated fields in messages.
+  void set_repeated_field_comparison(RepeatedFieldComparison comparison);
+
+  // Compares the two specified messages, returning true if they are the same,
+  // false otherwise. If this method returns false, any changes between the
+  // two messages will be reported if a Reporter was specified via
+  // ReportDifferencesTo (see also ReportDifferencesToString).
+  //
+  // This method REQUIRES that the two messages have the same
+  // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()).
+  bool Compare(const Message& message1, const Message& message2);
+
+  // Same as above, except comparing only the list of fields specified by the
+  // two vectors of FieldDescriptors.
+  bool CompareWithFields(const Message& message1, const Message& message2,
+                         const vector<const FieldDescriptor*>& message1_fields,
+                         const vector<const FieldDescriptor*>& message2_fields);
+
+  // Automatically creates a reporter that will output the differences
+  // found (if any) to the specified output string pointer. Note that this
+  // method must be called before Compare.
+  void ReportDifferencesToString(string* output);
+
+  // Tells the MessageDifferencer to report differences via the specified
+  // reporter. Note that this method must be called before Compare for
+  // the reporter to be used. It is the responsibility of the caller to delete
+  // this object.
+  // If the provided pointer equals NULL, the MessageDifferencer stops reporting
+  // differences to any previously set reporters or output strings.
+  void ReportDifferencesTo(Reporter* reporter);
+
+  // An implementation of the MessageDifferencer Reporter that outputs
+  // any differences found in human-readable form to the supplied
+  // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter
+  // *must* be '$'.
+  class LIBPROTOBUF_EXPORT StreamReporter : public Reporter {
+   public:
+    explicit StreamReporter(io::ZeroCopyOutputStream* output);
+    explicit StreamReporter(io::Printer* printer);  // delimiter '$'
+    virtual ~StreamReporter();
+
+    // When set to true, the stream reporter will also output aggregates nodes
+    // (i.e. messages and groups) whose subfields have been modified. When
+    // false, will only report the individual subfields. Defaults to false.
+    void set_report_modified_aggregates(bool report) {
+      report_modified_aggregates_ = report;
+    }
+
+    // The following are implementations of the methods described above.
+    virtual void ReportAdded(const Message& message1, const Message& message2,
+                             const vector<SpecificField>& field_path);
+
+    virtual void ReportDeleted(const Message& message1,
+                               const Message& message2,
+                               const vector<SpecificField>& field_path);
+
+    virtual void ReportModified(const Message& message1,
+                                const Message& message2,
+                                const vector<SpecificField>& field_path);
+
+    virtual void ReportMoved(const Message& message1,
+                             const Message& message2,
+                             const vector<SpecificField>& field_path);
+
+    virtual void ReportMatched(const Message& message1,
+                               const Message& message2,
+                               const vector<SpecificField>& field_path);
+
+    virtual void ReportIgnored(const Message& message1,
+                               const Message& message2,
+                               const vector<SpecificField>& field_path);
+
+    virtual void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const vector<SpecificField>& field_path);
+
+   protected:
+    // Prints the specified path of fields to the buffer.
+    virtual void PrintPath(const vector<SpecificField>& field_path,
+                           bool left_side);
+
+    // Prints the value of fields to the buffer.  left_side is true if the
+    // given message is from the left side of the comparison, false if it
+    // was the right.  This is relevant only to decide whether to follow
+    // unknown_field_index1 or unknown_field_index2 when an unknown field
+    // is encountered in field_path.
+    virtual void PrintValue(const Message& message,
+                            const vector<SpecificField>& field_path,
+                            bool left_side);
+
+    // Prints the specified path of unknown fields to the buffer.
+    virtual void PrintUnknownFieldValue(const UnknownField* unknown_field);
+
+    // Just print a string
+    void Print(const string& str);
+
+   private:
+    io::Printer* printer_;
+    bool delete_printer_;
+    bool report_modified_aggregates_;
+
+    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter);
+  };
+
+ private:
+  // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator.
+  // Implementation of this class needs to do field value comparison which
+  // relies on some private methods of MessageDifferencer. That's why this
+  // class is declared as a nested class of MessageDifferencer.
+  class MultipleFieldsMapKeyComparator;
+  // Returns true if field1's number() is less than field2's.
+  static bool FieldBefore(const FieldDescriptor* field1,
+                          const FieldDescriptor* field2);
+
+  // Combine the two lists of fields into the combined_fields output vector.
+  // All fields present in both lists will always be included in the combined
+  // list.  Fields only present in one of the lists will only appear in the
+  // combined list if the corresponding fields_scope option is set to FULL.
+  void CombineFields(const vector<const FieldDescriptor*>& fields1,
+                     Scope fields1_scope,
+                     const vector<const FieldDescriptor*>& fields2,
+                     Scope fields2_scope,
+                     vector<const FieldDescriptor*>* combined_fields);
+
+  // Internal version of the Compare method which performs the actual
+  // comparison. The parent_fields vector is a vector containing field
+  // descriptors of all fields accessed to get to this comparison operation
+  // (i.e. if the current message is an embedded message, the parent_fields
+  // vector will contain the field that has this embedded message).
+  bool Compare(const Message& message1, const Message& message2,
+               vector<SpecificField>* parent_fields);
+
+  // Compares all the unknown fields in two messages.
+  bool CompareUnknownFields(const Message& message1, const Message& message2,
+                            const google::protobuf::UnknownFieldSet&,
+                            const google::protobuf::UnknownFieldSet&,
+                            vector<SpecificField>* parent_fields);
+
+  // Compares the specified messages for the requested field lists. The field
+  // lists are modified depending on comparison settings, and then passed to
+  // CompareWithFieldsInternal.
+  bool CompareRequestedFieldsUsingSettings(
+      const Message& message1, const Message& message2,
+      const vector<const FieldDescriptor*>& message1_fields,
+      const vector<const FieldDescriptor*>& message2_fields,
+      vector<SpecificField>* parent_fields);
+
+  // Compares the specified messages with the specified field lists.
+  bool CompareWithFieldsInternal(
+      const Message& message1, const Message& message2,
+      const vector<const FieldDescriptor*>& message1_fields,
+      const vector<const FieldDescriptor*>& message2_fields,
+      vector<SpecificField>* parent_fields);
+
+  // Compares the repeated fields, and report the error.
+  bool CompareRepeatedField(const Message& message1, const Message& message2,
+                            const FieldDescriptor* field,
+                            vector<SpecificField>* parent_fields);
+
+  // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields.
+  bool CompareFieldValue(const Message& message1,
+                         const Message& message2,
+                         const FieldDescriptor* field,
+                         int index1,
+                         int index2);
+
+  // Compares the specified field on the two messages, returning
+  // true if they are the same, false otherwise. For repeated fields,
+  // this method only compares the value in the specified index. This method
+  // uses Compare functions to recurse into submessages.
+  // The parent_fields vector is used in calls to a Reporter instance calls.
+  // It can be NULL, in which case the MessageDifferencer will create new
+  // list of parent messages if it needs to recursively compare the given field.
+  // To avoid confusing users you should not set it to NULL unless you modified
+  // Reporter to handle the change of parent_fields correctly.
+  bool CompareFieldValueUsingParentFields(const Message& message1,
+                                          const Message& message2,
+                                          const FieldDescriptor* field,
+                                          int index1,
+                                          int index2,
+                                          vector<SpecificField>* parent_fields);
+
+  // Compares the specified field on the two messages, returning comparison
+  // result, as returned by appropriate FieldComparator.
+  FieldComparator::ComparisonResult GetFieldComparisonResult(
+      const Message& message1, const Message& message2,
+      const FieldDescriptor* field, int index1, int index2,
+      const FieldContext* field_context);
+
+  // Check if the two elements in the repeated field are match to each other.
+  // if the key_comprator is NULL, this function returns true when the two
+  // elements are equal.
+  bool IsMatch(const FieldDescriptor* repeated_field,
+               const MapKeyComparator* key_comparator,
+               const Message* message1, const Message* message2,
+               const vector<SpecificField>& parent_fields,
+               int index1, int index2);
+
+  // Returns true when this repeated field has been configured to be treated
+  // as a set.
+  bool IsTreatedAsSet(const FieldDescriptor* field);
+
+  // Returns true when this repeated field is to be compared as a subset, ie.
+  // has been configured to be treated as a set or map and scope is set to
+  // PARTIAL.
+  bool IsTreatedAsSubset(const FieldDescriptor* field);
+
+  // Returns true if this field is to be ignored when this
+  // MessageDifferencer compares messages.
+  bool IsIgnored(
+      const Message& message1,
+      const Message& message2,
+      const FieldDescriptor* field,
+      const vector<SpecificField>& parent_fields);
+
+  // Returns true if this unknown field is to be ignored when this
+  // MessageDifferencer compares messages.
+  bool IsUnknownFieldIgnored(const Message& message1, const Message& message2,
+                             const SpecificField& field,
+                             const vector<SpecificField>& parent_fields);
+
+  // Returns MapKeyComparator* when this field has been configured to
+  // be treated as a map.  If not, returns NULL.
+  const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field);
+
+  // Attempts to match indices of a repeated field, so that the contained values
+  // match. Clears output vectors and sets their values to indices of paired
+  // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1
+  // and match_list2[1] == 0. The unmatched indices are indicated by -1.
+  // This method returns false if the match failed. However, it doesn't mean
+  // that the comparison succeeds when this method returns true (you need to
+  // double-check in this case).
+  bool MatchRepeatedFieldIndices(const Message& message1,
+                                 const Message& message2,
+                                 const FieldDescriptor* repeated_field,
+                                 const vector<SpecificField>& parent_fields,
+                                 vector<int>* match_list1,
+                                 vector<int>* match_list2);
+
+  // If "any" is of type google.protobuf.Any, extract its payload using
+  // DynamicMessageFactory and store in "data".
+  bool UnpackAny(const Message& any, google::protobuf::scoped_ptr<Message>* data);
+
+  // Checks if index is equal to new_index in all the specific fields.
+  static bool CheckPathChanged(const vector<SpecificField>& parent_fields);
+
+  // Defines a map between field descriptors and their MapKeyComparators.
+  // Used for repeated fields when they are configured as TreatAsMap.
+  typedef map<const FieldDescriptor*,
+              const MapKeyComparator*> FieldKeyComparatorMap;
+
+  // Defines a set to store field descriptors.  Used for repeated fields when
+  // they are configured as TreatAsSet.
+  typedef set<const FieldDescriptor*> FieldSet;
+
+  Reporter* reporter_;
+  DefaultFieldComparator default_field_comparator_;
+  FieldComparator* field_comparator_;
+  MessageFieldComparison message_field_comparison_;
+  Scope scope_;
+  RepeatedFieldComparison repeated_field_comparison_;
+
+  FieldSet set_fields_;
+  FieldSet list_fields_;
+  // Keeps track of MapKeyComparators that are created within
+  // MessageDifferencer. These MapKeyComparators should be deleted
+  // before MessageDifferencer is destroyed.
+  // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't
+  // store the supplied FieldDescriptors directly. Instead, a new
+  // MapKeyComparator is created for comparison purpose.
+  vector<MapKeyComparator*> owned_key_comparators_;
+  FieldKeyComparatorMap map_field_key_comparator_;
+  vector<IgnoreCriteria*> ignore_criteria_;
+
+  FieldSet ignored_fields_;
+
+  bool compare_unknown_fields_;
+  bool report_matches_;
+
+  string* output_string_;
+
+  google::protobuf::scoped_ptr<DynamicMessageFactory> dynamic_message_factory_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer);
+};
+
+// This class provides extra information to the FieldComparator::Compare
+// function.
+class LIBPROTOBUF_EXPORT FieldContext {
+ public:
+  explicit FieldContext(
+      vector<MessageDifferencer::SpecificField>* parent_fields)
+      : parent_fields_(parent_fields) {}
+
+  vector<MessageDifferencer::SpecificField>* parent_fields() const {
+    return parent_fields_;
+  }
+
+ private:
+  vector<MessageDifferencer::SpecificField>* parent_fields_;
+};
+
+}
+}
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
new file mode 100755
index 0000000..a867c88
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -0,0 +1,3151 @@
+// 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.
+
+// Author: jschorr@google.com (Joseph Schorr)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// TODO(ksroka): Move some of these tests to field_comparator_test.cc.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+
+#include <google/protobuf/util/field_comparator.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <google/protobuf/util/message_differencer_unittest.pb.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/any_test.pb.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/map_test_util.h>
+#include <google/protobuf/test_util.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+
+const FieldDescriptor* GetFieldDescriptor(
+    const Message& message, const string& field_name) {
+  vector<string> field_path =
+      Split(field_name, ".", true);
+  const Descriptor* descriptor = message.GetDescriptor();
+  const FieldDescriptor* field = NULL;
+  for (int i = 0; i < field_path.size(); i++) {
+    field = descriptor->FindFieldByName(field_path[i]);
+    descriptor = field->message_type();
+  }
+  return field;
+}
+
+void ExpectEqualsWithDifferencer(util::MessageDifferencer* differencer,
+                                 const Message& msg1,
+                                 const Message& msg2) {
+  differencer->set_scope(util::MessageDifferencer::FULL);
+  EXPECT_TRUE(differencer->Compare(msg1, msg2));
+
+  differencer->set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer->Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicEqualityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicInequalityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldInequalityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.add_repeated_int32(-1);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, MapFieldEqualityTest) {
+  // Create the testing protos
+  unittest::TestMap msg1;
+  unittest::TestMap msg2;
+
+  MapReflectionTester tester(unittest::TestMap::descriptor());
+  tester.SetMapFieldsViaReflection(&msg1);
+  tester.SetMapFieldsViaReflection(&msg2);
+  tester.SwapMapsViaReflection(&msg1);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicPartialEqualityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialEqualityTestExtraField) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.clear_optional_int32();
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialEqualityTestSkipRequiredField) {
+  // Create the testing protos
+  unittest::TestRequired msg1;
+  unittest::TestRequired msg2;
+
+  msg1.set_a(401);
+  msg2.set_a(401);
+  msg2.set_b(402);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicPartialInequalityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialInequalityMissingFieldTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg2.clear_optional_int32();
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldPartialInequalityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.add_repeated_int32(-1);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicEquivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, EquivalencyNotEqualTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.clear_optional_int32();
+  msg2.set_optional_int32(0);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+  EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicInequivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2));
+}
+
+
+TEST(MessageDifferencerTest, BasicEquivalencyNonSetTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2));
+}
+
+
+TEST(MessageDifferencerTest, BasicInequivalencyNonSetTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2));
+}
+
+
+TEST(MessageDifferencerTest, BasicPartialEquivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialEquivalencyNotEqualTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.set_optional_int32(0);
+  msg2.clear_optional_int32();
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialEquivalencyTestExtraField) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.clear_optional_int32();
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, PartialEquivalencyTestSkipRequiredField) {
+  // Create the testing protos
+  unittest::TestRequired msg1;
+  unittest::TestRequired msg2;
+
+  msg1.set_a(401);
+  msg2.set_a(401);
+  msg2.set_b(402);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicPartialInequivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicPartialEquivalencyNonSetTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicPartialInequivalencyNonSetTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  msg1.set_optional_int32(-1);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, ApproximateEqualityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, ApproximateModifiedEqualityTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  const float v1 = 2.300005f;
+  const float v2 = 2.300006f;
+  msg1.set_optional_float(v1);
+  msg2.set_optional_float(v2);
+
+  // Compare
+  ASSERT_NE(v1, v2) << "Should not be the same: " << v1 << ", " << v2;
+  ASSERT_FLOAT_EQ(v1, v2) << "Should be approx. equal: " << v1 << ", " << v2;
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, ApproximateEquivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                msg2));
+}
+
+TEST(MessageDifferencerTest, ApproximateModifiedEquivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Modify the approximateness requirement
+  const float v1 = 2.300005f;
+  const float v2 = 2.300006f;
+  msg1.set_optional_float(v1);
+  msg2.set_optional_float(v2);
+
+  // Compare
+  ASSERT_NE(v1, v2) << "Should not be the same: " << v1 << ", " << v2;
+  ASSERT_FLOAT_EQ(v1, v2) << "Should be approx. equal: " << v1 << ", " << v2;
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                msg2));
+
+  // Modify the equivalency requirement too
+  msg1.clear_optional_int32();
+  msg2.set_optional_int32(0);
+
+  // Compare. Now should only pass on ApproximatelyEquivalent
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+  EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2));
+  EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2));
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                msg2));
+}
+
+TEST(MessageDifferencerTest, ApproximateInequivalencyTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Should fail on equivalency
+  msg1.set_optional_int32(-1);
+  EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                 msg2));
+
+  // Make these fields the same again.
+  msg1.set_optional_int32(0);
+  msg2.set_optional_int32(0);
+  EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                msg2));
+
+  // Should fail on approximate equality check
+  const float v1 = 2.3f;
+  const float v2 = 9.3f;
+  msg1.set_optional_float(v1);
+  msg2.set_optional_float(v2);
+  EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquivalent(msg1,
+                                                                 msg2));
+}
+
+TEST(MessageDifferencerTest, WithinFractionOrMarginFloatTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Should fail on approximate equality check
+  const float v1 = 100.0f;
+  const float v2 = 109.9f;
+  msg1.set_optional_float(v1);
+  msg2.set_optional_float(v2);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  const FieldDescriptor* fd =
+      msg1.GetDescriptor()->FindFieldByName("optional_float");
+
+  // Set float comparison to exact, margin and fraction value should not matter.
+  differencer.set_float_comparison(util::MessageDifferencer::EXACT);
+  // Set margin for float comparison.
+  differencer.SetFractionAndMargin(fd, 0.0, 10.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Margin and fraction float comparison is activated when float comparison is
+  // set to approximate.
+  differencer.set_float_comparison(util::MessageDifferencer::APPROXIMATE);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Test out float comparison with fraction.
+  differencer.SetFractionAndMargin(fd, 0.2, 0.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Should fail since the fraction is smaller than error.
+  differencer.SetFractionAndMargin(fd, 0.01, 0.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Should pass if either fraction or margin are satisfied.
+  differencer.SetFractionAndMargin(fd, 0.01, 10.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Make sure that the margin and fraction only affects the field that it was
+  // set for.
+  msg1.set_default_float(v1);
+  msg2.set_default_float(v2);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  msg1.set_default_float(v1);
+  msg2.set_default_float(v1);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, WithinFractionOrMarginDoubleTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Should fail on approximate equality check
+  const double v1 = 100.0;
+  const double v2 = 109.9;
+  msg1.set_optional_double(v1);
+  msg2.set_optional_double(v2);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Set comparison to exact, margin and fraction value should not matter.
+  differencer.set_float_comparison(util::MessageDifferencer::EXACT);
+  // Set margin for float comparison.
+  const FieldDescriptor* fd =
+      msg1.GetDescriptor()->FindFieldByName("optional_double");
+  differencer.SetFractionAndMargin(fd, 0.0, 10.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Margin and fraction comparison is activated when float comparison is
+  // set to approximate.
+  differencer.set_float_comparison(util::MessageDifferencer::APPROXIMATE);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Test out comparison with fraction.
+  differencer.SetFractionAndMargin(fd, 0.2, 0.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Should fail since the fraction is smaller than error.
+  differencer.SetFractionAndMargin(fd, 0.01, 0.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Should pass if either fraction or margin are satisfied.
+  differencer.SetFractionAndMargin(fd, 0.01, 10.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Make sure that the margin and fraction only affects the field that it was
+  // set for.
+  msg1.set_default_double(v1);
+  msg2.set_default_double(v2);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  msg1.set_default_double(v1);
+  msg2.set_default_double(v1);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, WithinDefaultFractionOrMarginDoubleTest) {
+  // Create the testing protos
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  // Should fail on approximate equality check
+  const double v1 = 100.0;
+  const double v2 = 109.9;
+  msg1.set_optional_double(v1);
+  msg2.set_optional_double(v2);
+
+  util::MessageDifferencer differencer;
+
+  // Compare
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Set up a custom field comparitor, with a default fraction and margin for
+  // float and double comparison.
+  util::DefaultFieldComparator field_comparitor;
+  field_comparitor.SetDefaultFractionAndMargin(0.0, 10.0);
+  differencer.set_field_comparator(&field_comparitor);
+
+  // Set comparison to exact, margin and fraction value should not matter.
+  field_comparitor.set_float_comparison(util::DefaultFieldComparator::EXACT);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Margin and fraction comparison is activated when float comparison is
+  // set to approximate.
+  field_comparitor.set_float_comparison(
+      util::DefaultFieldComparator::APPROXIMATE);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Test out comparison with fraction.
+  field_comparitor.SetDefaultFractionAndMargin(0.2, 0.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Should fail since the fraction is smaller than error.
+  field_comparitor.SetDefaultFractionAndMargin(0.01, 0.0);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Should pass if either fraction or margin are satisfied.
+  field_comparitor.SetDefaultFractionAndMargin(0.01, 10.0);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Make sure that the default margin and fraction affects all fields
+  msg1.set_default_double(v1);
+  msg2.set_default_double(v2);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicFieldOrderingsTest) {
+  // Create the testing protos
+  unittest::TestFieldOrderings msg1;
+  unittest::TestFieldOrderings msg2;
+
+  TestUtil::SetAllFieldsAndExtensions(&msg1);
+  TestUtil::SetAllFieldsAndExtensions(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+
+TEST(MessageDifferencerTest, BasicFieldOrderingInequalityTest) {
+  // Create the testing protos
+  unittest::TestFieldOrderings msg1;
+  unittest::TestFieldOrderings msg2;
+
+  TestUtil::SetAllFieldsAndExtensions(&msg1);
+  TestUtil::SetAllFieldsAndExtensions(&msg2);
+
+  msg1.set_my_float(15.00);
+  msg2.set_my_float(16.00);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, BasicExtensionTest) {
+  // Create the testing protos
+  unittest::TestAllExtensions msg1;
+  unittest::TestAllExtensions msg2;
+
+  TestUtil::SetAllExtensions(&msg1);
+  TestUtil::SetAllExtensions(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+
+TEST(MessageDifferencerTest, BasicExtensionInequalityTest) {
+  // Create the testing protos
+  unittest::TestAllExtensions msg1;
+  unittest::TestAllExtensions msg2;
+
+  TestUtil::SetAllExtensions(&msg1);
+  TestUtil::SetAllExtensions(&msg2);
+
+  msg1.SetExtension(unittest::optional_int32_extension, 101);
+  msg2.SetExtension(unittest::optional_int32_extension, 102);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, OneofTest) {
+  // Create the testing protos
+  unittest::TestOneof2 msg1;
+  unittest::TestOneof2 msg2;
+
+  TestUtil::SetOneof1(&msg1);
+  TestUtil::SetOneof1(&msg2);
+
+  // Compare
+  EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, OneofInequalityTest) {
+  // Create the testing protos
+  unittest::TestOneof2 msg1;
+  unittest::TestOneof2 msg2;
+
+  TestUtil::SetOneof1(&msg1);
+  TestUtil::SetOneof2(&msg2);
+
+  // Compare
+  EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, UnknownFieldPartialEqualTest) {
+  unittest::TestEmptyMessage empty1;
+  unittest::TestEmptyMessage empty2;
+
+  UnknownFieldSet* unknown1 = empty1.mutable_unknown_fields();
+  UnknownFieldSet* unknown2 = empty2.mutable_unknown_fields();
+
+  unknown1->AddVarint(243, 122);
+  unknown1->AddLengthDelimited(245, "abc");
+  unknown1->AddGroup(246)->AddFixed32(248, 1);
+  unknown1->mutable_field(2)->mutable_group()->AddFixed32(248, 2);
+
+  unknown2->AddVarint(243, 122);
+  unknown2->AddLengthDelimited(245, "abc");
+  unknown2->AddGroup(246)->AddFixed32(248, 1);
+  unknown2->mutable_field(2)->mutable_group()->AddFixed32(248, 2);
+
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(empty1, empty2));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsEqualityAllTest) {
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  vector<const FieldDescriptor*> fields2;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+  msg2.GetReflection()->ListFields(msg2, &fields2);
+
+  util::MessageDifferencer differencer;
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsInequalityAllTest) {
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+
+  vector<const FieldDescriptor*> fields1;
+  vector<const FieldDescriptor*> fields2;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+  msg2.GetReflection()->ListFields(msg2, &fields2);
+
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsEmptyListAlwaysSucceeds) {
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+
+  vector<const FieldDescriptor*> empty_fields;
+
+  util::MessageDifferencer differencer;
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2,
+                                            empty_fields, empty_fields));
+
+  TestUtil::SetAllFields(&msg2);
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2,
+                                            empty_fields, empty_fields));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsCompareWithSelf) {
+  unittest::TestAllTypes msg1;
+  TestUtil::SetAllFields(&msg1);
+
+  vector<const FieldDescriptor*> fields;
+  msg1.GetReflection()->ListFields(msg1, &fields);
+
+  util::MessageDifferencer differencer;
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg1, fields, fields));
+
+  {
+    // Compare with a subset of fields.
+    vector<const FieldDescriptor*> compare_fields;
+    for (int i = 0; i < fields.size(); ++i) {
+      if (i % 2 == 0) {
+        compare_fields.push_back(fields[i]);
+      }
+    }
+    EXPECT_TRUE(differencer.CompareWithFields(msg1, msg1,
+                                              compare_fields, compare_fields));
+  }
+  {
+    // Specify a different set of fields to compare, even though we're using the
+    // same message. This should fail, since we are explicitly saying that the
+    // set of fields are different.
+    vector<const FieldDescriptor*> compare_fields1;
+    vector<const FieldDescriptor*> compare_fields2;
+    for (int i = 0; i < fields.size(); ++i) {
+      if (i % 2 == 0) {
+        compare_fields1.push_back(fields[i]);
+      } else {
+        compare_fields2.push_back(fields[i]);
+      }
+    }
+    EXPECT_FALSE(differencer.CompareWithFields(
+        msg1, msg1, compare_fields1, compare_fields2));
+  }
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsEqualityAllShuffledTest) {
+  // This is a public function, so make sure there are no assumptions about the
+  // list of fields. Randomly shuffle them to make sure that they are properly
+  // ordered for comparison.
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  vector<const FieldDescriptor*> fields2;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+  msg2.GetReflection()->ListFields(msg2, &fields2);
+
+  std::random_shuffle(fields1.begin(), fields1.end());
+  std::random_shuffle(fields2.begin(), fields2.end());
+
+  util::MessageDifferencer differencer;
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsSubsetEqualityTest) {
+  // Specify a set of fields to compare. All the fields are equal.
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+
+  vector<const FieldDescriptor*> compare_fields;
+  // Only compare the field descriptors with even indices.
+  for (int i = 0; i < fields1.size(); ++i) {
+    if (i % 2 == 0) {
+      compare_fields.push_back(fields1[i]);
+    }
+  }
+
+  util::MessageDifferencer differencer;
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2,
+                                            compare_fields, compare_fields));
+}
+
+TEST(MessageDifferencerTest,
+     SpecifiedFieldsSubsetIgnoresOtherFieldDifferencesTest) {
+  // Specify a set of fields to compare, but clear all the other fields in one
+  // of the messages. This should fail a regular compare, but CompareWithFields
+  // should succeed.
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  const Reflection* reflection = msg1.GetReflection();
+  reflection->ListFields(msg1, &fields1);
+
+  vector<const FieldDescriptor*> compare_fields;
+  // Only compare the field descriptors with even indices.
+  for (int i = 0; i < fields1.size(); ++i) {
+    if (i % 2 == 0) {
+      compare_fields.push_back(fields1[i]);
+    } else {
+      reflection->ClearField(&msg2, fields1[i]);
+    }
+  }
+
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2,
+                                            compare_fields, compare_fields));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsDetectsDifferencesTest) {
+  // Change all of the repeated fields in one of the messages, and use only
+  // those fields for comparison.
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+  TestUtil::ModifyRepeatedFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+
+  vector<const FieldDescriptor*> compare_fields;
+  // Only compare the repeated field descriptors.
+  for (int i = 0; i < fields1.size(); ++i) {
+    if (fields1[i]->is_repeated()) {
+      compare_fields.push_back(fields1[i]);
+    }
+  }
+
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2,
+                                             compare_fields, compare_fields));
+}
+
+TEST(MessageDifferencerTest, SpecifiedFieldsEquivalenceAllTest) {
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+
+  TestUtil::SetAllFields(&msg1);
+  TestUtil::SetAllFields(&msg2);
+
+  vector<const FieldDescriptor*> fields1;
+  vector<const FieldDescriptor*> fields2;
+  msg1.GetReflection()->ListFields(msg1, &fields1);
+  msg2.GetReflection()->ListFields(msg2, &fields2);
+
+  util::MessageDifferencer differencer;
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+}
+
+TEST(MessageDifferencerTest,
+     SpecifiedFieldsEquivalenceIgnoresOtherFieldDifferencesTest) {
+  unittest::TestAllTypes msg1;
+  unittest::TestAllTypes msg2;
+  const Descriptor* desc = msg1.GetDescriptor();
+
+  const FieldDescriptor* optional_int32_desc =
+      desc->FindFieldByName("optional_int32");
+  const FieldDescriptor* optional_int64_desc =
+      desc->FindFieldByName("optional_int64");
+  const FieldDescriptor* default_int64_desc =
+      desc->FindFieldByName("default_int64");
+  ASSERT_TRUE(optional_int32_desc != NULL);
+  ASSERT_TRUE(optional_int64_desc != NULL);
+  ASSERT_TRUE(default_int64_desc != NULL);
+  msg1.set_optional_int32(0);
+  msg2.set_optional_int64(0);
+  msg1.set_default_int64(default_int64_desc->default_value_int64());
+
+  // Set a field to a non-default value so we know that field selection is
+  // actually doing something.
+  msg2.set_optional_uint64(23);
+
+  vector<const FieldDescriptor*> fields1;
+  vector<const FieldDescriptor*> fields2;
+  fields1.push_back(optional_int32_desc);
+  fields1.push_back(default_int64_desc);
+
+  fields2.push_back(optional_int64_desc);
+
+  util::MessageDifferencer differencer;
+  EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+  differencer.set_message_field_comparison(
+      util::MessageDifferencer::EQUIVALENT);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_SetOfSet) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->add_ra(1); item->add_ra(2); item->add_ra(3);
+  item = msg1.add_item();
+  item->add_ra(5); item->add_ra(6);
+  item = msg1.add_item();
+  item->add_ra(1); item->add_ra(3);
+  item = msg1.add_item();
+  item->add_ra(6); item->add_ra(7); item->add_ra(8);
+
+  item = msg2.add_item();
+  item->add_ra(6); item->add_ra(5);
+  item = msg2.add_item();
+  item->add_ra(6); item->add_ra(8); item->add_ra(7);
+  item = msg2.add_item();
+  item->add_ra(1); item->add_ra(3);
+  item = msg2.add_item();
+  item->add_ra(3); item->add_ra(2); item->add_ra(1);
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_Combination) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  // Treat "item" as Map, with key = "a"
+  // Treat "item.ra" also as Set
+  // Treat "rv" as Set
+  // Treat "rw" as List
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->set_a(3);
+  item->add_ra(1); item->add_ra(2); item->add_ra(3);
+  item = msg1.add_item();
+  item->set_a(4);
+  item->add_ra(5); item->add_ra(6);
+  item = msg1.add_item();
+  item->set_a(1);
+  item->add_ra(1); item->add_ra(3);
+  item = msg1.add_item();
+  item->set_a(2);
+  item->add_ra(6); item->add_ra(7); item->add_ra(8);
+
+  item = msg2.add_item();
+  item->set_a(4);
+  item->add_ra(6); item->add_ra(5);
+  item = msg2.add_item();
+  item->set_a(2);
+  item->add_ra(6); item->add_ra(8); item->add_ra(7);
+  item = msg2.add_item();
+  item->set_a(1);
+  item->add_ra(1); item->add_ra(3);
+  item = msg2.add_item();
+  item->set_a(3);
+  item->add_ra(3); item->add_ra(2); item->add_ra(1);
+
+  msg1.add_rv(3);
+  msg1.add_rv(4);
+  msg1.add_rv(7);
+  msg1.add_rv(0);
+  msg2.add_rv(4);
+  msg2.add_rv(3);
+  msg2.add_rv(0);
+  msg2.add_rv(7);
+
+  msg1.add_rw("nothing"); msg2.add_rw("nothing");
+  msg1.add_rw("should"); msg2.add_rw("should");
+  msg1.add_rw("change"); msg2.add_rw("change");
+
+  // Compare
+  util::MessageDifferencer differencer1;
+  differencer1.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+                          item->GetDescriptor()->FindFieldByName("a"));
+  differencer1.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv"));
+  differencer1.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra"));
+  EXPECT_TRUE(differencer1.Compare(msg1, msg2));
+
+  util::MessageDifferencer differencer2;
+  differencer2.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+                          item->GetDescriptor()->FindFieldByName("a"));
+  differencer2.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  differencer2.TreatAsList(msg1.GetDescriptor()->FindFieldByName("rw"));
+  EXPECT_TRUE(differencer2.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_Partial) {
+  protobuf_unittest::TestDiffMessage msg1;
+  // message msg1 {
+  //   item { a: 1; b: "11" }
+  // }
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->set_a(1);
+  item->set_b("11");
+
+  protobuf_unittest::TestDiffMessage msg2;
+  // message msg2 {
+  //   item { a: 2; b: "22" }
+  //   item { a: 1; b: "11" }
+  // }
+  item = msg2.add_item();
+  item->set_a(2);
+  item->set_b("22");
+  item = msg2.add_item();
+  item->set_a(1);
+  item->set_b("11");
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.TreatAsMap(GetFieldDescriptor(msg1, "item"),
+                         GetFieldDescriptor(msg1, "item.a"));
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_Duplicates) {
+  protobuf_unittest::TestDiffMessage a, b, c;
+  // message a: {
+  //   rv: 0
+  //   rv: 1
+  //   rv: 0
+  // }
+  a.add_rv(0);
+  a.add_rv(1);
+  a.add_rv(0);
+  // message b: {
+  //   rv: 0
+  //   rv: 0
+  //   rv: 1
+  // }
+  b.add_rv(0);
+  b.add_rv(0);
+  b.add_rv(1);
+  // message c: {
+  //   rv: 0
+  //   rv: 1
+  // }
+  c.add_rv(0);
+  c.add_rv(1);
+  util::MessageDifferencer differencer;
+  differencer.TreatAsSet(GetFieldDescriptor(a, "rv"));
+  EXPECT_TRUE(differencer.Compare(b, a));
+  EXPECT_FALSE(differencer.Compare(c, a));
+
+  util::MessageDifferencer differencer1;
+  differencer1.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  EXPECT_TRUE(differencer1.Compare(b, a));
+  EXPECT_FALSE(differencer1.Compare(c, a));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_PartialSimple) {
+  protobuf_unittest::TestDiffMessage a, b, c;
+  // message a: {
+  //   rm { c: 1 }
+  //   rm { c: 0 }
+  // }
+  a.add_rm()->set_c(1);
+  a.add_rm()->set_c(0);
+  // message b: {
+  //   rm { c: 1 }
+  //   rm {}
+  // }
+  b.add_rm()->set_c(1);
+  b.add_rm();
+  // message c: {
+  //   rm {}
+  //   rm { c: 1 }
+  // }
+  c.add_rm();
+  c.add_rm()->set_c(1);
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  differencer.TreatAsSet(GetFieldDescriptor(a, "rm"));
+  EXPECT_TRUE(differencer.Compare(b, a));
+  EXPECT_TRUE(differencer.Compare(c, a));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_Partial) {
+  protobuf_unittest::TestDiffMessage msg1, msg2;
+  // message msg1: {
+  //   rm { a: 1 }
+  //   rm { b: 2 }
+  //   rm { c: 3 }
+  // }
+  msg1.add_rm()->set_a(1);
+  msg1.add_rm()->set_b(2);
+  msg1.add_rm()->set_c(3);
+  // message msg2: {
+  //   rm { a: 1; c: 3 }
+  //   rm { b: 2; c: 3 }
+  //   rm { b: 2 }
+  // }
+  protobuf_unittest::TestField* field = msg2.add_rm();
+  field->set_a(1);
+  field->set_c(3);
+  field = msg2.add_rm();
+  field->set_b(2);
+  field->set_c(3);
+  field = msg2.add_rm();
+  field->set_b(2);
+
+  util::MessageDifferencer differencer;
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  differencer.TreatAsSet(GetFieldDescriptor(msg1, "rm"));
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_MultipleFieldsAsKey) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  // Treat "item" as Map, with key = ("a", "ra")
+  // Treat "item.ra" as Set
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  // key => value: (1, {2, 3}) => "a"
+  item->set_a(1);
+  item->add_ra(2);
+  item->add_ra(3);
+  item->set_b("a");
+  item = msg1.add_item();
+  // key => value: (2, {1, 3}) => "b"
+  item->set_a(2);
+  item->add_ra(1);
+  item->add_ra(3);
+  item->set_b("b");
+  item = msg1.add_item();
+  // key => value: (1, {1, 3}) => "c"
+  item->set_a(1);
+  item->add_ra(1);
+  item->add_ra(3);
+  item->set_b("c");
+
+  item = msg2.add_item();
+  // key => value: (1, {1, 3}) => "c"
+  item->set_a(1);
+  item->add_ra(3);
+  item->add_ra(1);
+  item->set_b("c");
+  item = msg2.add_item();
+  // key => value: (1, {2, 3}) => "a"
+  item->set_a(1);
+  item->add_ra(3);
+  item->add_ra(2);
+  item->set_b("a");
+  item = msg2.add_item();
+  // key => value: (2, {1, 3}) => "b"
+  item->set_a(2);
+  item->add_ra(3);
+  item->add_ra(1);
+  item->set_b("b");
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.TreatAsSet(GetFieldDescriptor(msg1, "item.ra"));
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  vector<const FieldDescriptor*> key_fields;
+  key_fields.push_back(GetFieldDescriptor(msg1, "item.a"));
+  key_fields.push_back(GetFieldDescriptor(msg1, "item.ra"));
+  differencer.TreatAsMapWithMultipleFieldsAsKey(
+      GetFieldDescriptor(msg1, "item"), key_fields);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Introduce some differences.
+  msg1.clear_item();
+  msg2.clear_item();
+  item = msg1.add_item();
+  item->set_a(4);
+  item->add_ra(5);
+  item->add_ra(6);
+  item->set_b("hello");
+  item = msg2.add_item();
+  item->set_a(4);
+  item->add_ra(6);
+  item->add_ra(5);
+  item->set_b("world");
+  string output;
+  differencer.ReportDifferencesToString(&output);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "moved: item[0].ra[0] -> item[0].ra[1] : 5\n"
+      "moved: item[0].ra[1] -> item[0].ra[0] : 6\n"
+      "modified: item[0].b: \"hello\" -> \"world\"\n",
+      output);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_MultipleFieldPathsAsKey) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  // Treat "item" as Map, with key = ("m.a", "m.rc")
+  // Treat "item.m.rc" as Set
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  // key => value: (1, {2, 3}) => "a"
+  item->mutable_m()->set_a(1);
+  item->mutable_m()->add_rc(2);
+  item->mutable_m()->add_rc(3);
+  item->set_b("a");
+  item = msg1.add_item();
+  // key => value: (2, {1, 3}) => "b"
+  item->mutable_m()->set_a(2);
+  item->mutable_m()->add_rc(1);
+  item->mutable_m()->add_rc(3);
+  item->set_b("b");
+  item = msg1.add_item();
+  // key => value: (1, {1, 3}) => "c"
+  item->mutable_m()->set_a(1);
+  item->mutable_m()->add_rc(1);
+  item->mutable_m()->add_rc(3);
+  item->set_b("c");
+
+  item = msg2.add_item();
+  // key => value: (1, {1, 3}) => "c"
+  item->mutable_m()->set_a(1);
+  item->mutable_m()->add_rc(3);
+  item->mutable_m()->add_rc(1);
+  item->set_b("c");
+  item = msg2.add_item();
+  // key => value: (1, {2, 3}) => "a"
+  item->mutable_m()->set_a(1);
+  item->mutable_m()->add_rc(3);
+  item->mutable_m()->add_rc(2);
+  item->set_b("a");
+  item = msg2.add_item();
+  // key => value: (2, {1, 3}) => "b"
+  item->mutable_m()->set_a(2);
+  item->mutable_m()->add_rc(3);
+  item->mutable_m()->add_rc(1);
+  item->set_b("b");
+
+  // Compare
+  util::MessageDifferencer differencer;
+  differencer.TreatAsSet(GetFieldDescriptor(msg1, "item.m.rc"));
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  vector<vector<const FieldDescriptor*> > key_field_paths;
+  vector<const FieldDescriptor*> key_field_path1;
+  key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m"));
+  key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m.a"));
+  vector<const FieldDescriptor*> key_field_path2;
+  key_field_path2.push_back(GetFieldDescriptor(msg1, "item.m"));
+  key_field_path2.push_back(GetFieldDescriptor(msg1, "item.m.rc"));
+  key_field_paths.push_back(key_field_path1);
+  key_field_paths.push_back(key_field_path2);
+  differencer.TreatAsMapWithMultipleFieldPathsAsKey(
+      GetFieldDescriptor(msg1, "item"), key_field_paths);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+
+  // Introduce some differences.
+  msg1.clear_item();
+  msg2.clear_item();
+  item = msg1.add_item();
+  item->mutable_m()->set_a(4);
+  item->mutable_m()->add_rc(5);
+  item->mutable_m()->add_rc(6);
+  item->set_b("hello");
+  item = msg2.add_item();
+  item->mutable_m()->set_a(4);
+  item->mutable_m()->add_rc(6);
+  item->mutable_m()->add_rc(5);
+  item->set_b("world");
+  string output;
+  differencer.ReportDifferencesToString(&output);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: item[0].b: \"hello\" -> \"world\"\n"
+      "moved: item[0].m.rc[0] -> item[0].m.rc[1] : 5\n"
+      "moved: item[0].m.rc[1] -> item[0].m.rc[0] : 6\n",
+      output);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_IgnoredKeyFields) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  // Treat "item" as Map, with key = ("a", "ra")
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->set_a(1);
+  item->add_ra(2);
+  item->set_b("hello");
+  item = msg2.add_item();
+  item->set_a(1);
+  item->add_ra(3);
+  item->set_b("world");
+  // Compare
+  util::MessageDifferencer differencer;
+  vector<const FieldDescriptor*> key_fields;
+  key_fields.push_back(GetFieldDescriptor(msg1, "item.a"));
+  key_fields.push_back(GetFieldDescriptor(msg1, "item.ra"));
+  differencer.TreatAsMapWithMultipleFieldsAsKey(
+      GetFieldDescriptor(msg1, "item"), key_fields);
+  string output;
+  differencer.ReportDifferencesToString(&output);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "added: item[0]: { a: 1 ra: 3 b: \"world\" }\n"
+      "deleted: item[0]: { a: 1 ra: 2 b: \"hello\" }\n",
+      output);
+  // Ignored fields that are listed as parts of the key are still used
+  // in key comparison, but they're not used in value comparison.
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "item.ra"));
+  output.clear();
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "added: item[0]: { a: 1 ra: 3 b: \"world\" }\n"
+      "deleted: item[0]: { a: 1 ra: 2 b: \"hello\" }\n",
+      output);
+  // Ignoring a field in the key is different from treating the left fields
+  // as key. That is:
+  //   (key = ("a", "ra") && ignore "ra") != (key = ("a") && ignore "ra")
+  util::MessageDifferencer differencer2;
+  differencer2.TreatAsMap(GetFieldDescriptor(msg1, "item"),
+                          GetFieldDescriptor(msg1, "item.a"));
+  differencer2.IgnoreField(GetFieldDescriptor(msg1, "item.ra"));
+  output.clear();
+  differencer2.ReportDifferencesToString(&output);
+  EXPECT_FALSE(differencer2.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "ignored: item[0].ra\n"
+      "modified: item[0].b: \"hello\" -> \"world\"\n",
+      output);
+}
+
+static const char* const kIgnoredFields[] = {"rm.b", "rm.m.b"};
+
+class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria {
+ public:
+  virtual bool IsIgnored(
+      const Message& message1, const Message& message2,
+      const FieldDescriptor* field,
+      const vector<util::MessageDifferencer::SpecificField>& parent_fields) {
+    string name = "";
+    for (int i = 0; i < parent_fields.size(); ++i) {
+      name += parent_fields[i].field->name() + ".";
+    }
+    name += field->name();
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(kIgnoredFields); ++i) {
+      if (name.compare(kIgnoredFields[i]) == 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+TEST(MessageDifferencerTest, TreatRepeatedFieldAsSetWithIgnoredFields) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  TextFormat::MergeFromString("rm { a: 11\n b: 12 }", &msg1);
+  TextFormat::MergeFromString("rm { a: 11\n b: 13 }", &msg2);
+  util::MessageDifferencer differ;
+  differ.TreatAsSet(GetFieldDescriptor(msg1, "rm"));
+  differ.AddIgnoreCriteria(new TestIgnorer);
+  EXPECT_TRUE(differ.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, TreatRepeatedFieldAsMapWithIgnoredKeyFields) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  TextFormat::MergeFromString("rm { a: 11\n m { a: 12\n b: 13\n } }", &msg1);
+  TextFormat::MergeFromString("rm { a: 11\n m { a: 12\n b: 14\n } }", &msg2);
+  util::MessageDifferencer differ;
+  differ.TreatAsMap(GetFieldDescriptor(msg1, "rm"),
+                    GetFieldDescriptor(msg1, "rm.m"));
+  differ.AddIgnoreCriteria(new TestIgnorer);
+  EXPECT_TRUE(differ.Compare(msg1, msg2));
+}
+
+// Takes the product of all elements of item.ra as the key for key comparison.
+class ValueProductMapKeyComparator
+    : public util::MessageDifferencer::MapKeyComparator {
+ public:
+  typedef util::MessageDifferencer::SpecificField SpecificField;
+  virtual bool IsMatch(
+      const Message &message1, const Message &message2,
+      const vector<SpecificField>& parent_fields) const {
+    const Reflection* reflection1 = message1.GetReflection();
+    const Reflection* reflection2 = message2.GetReflection();
+    // FieldDescriptor for item.ra
+    const FieldDescriptor* ra_field =
+        message1.GetDescriptor()->FindFieldByName("ra");
+    // Get the product of all elements in item.ra
+    int result1 = 1, result2 = 1;
+    for (int i = 0; i < reflection1->FieldSize(message1, ra_field); ++i) {
+      result1 *= reflection1->GetRepeatedInt32(message1, ra_field, i);
+    }
+    for (int i = 0; i < reflection2->FieldSize(message2, ra_field); ++i) {
+      result2 *= reflection2->GetRepeatedInt32(message2, ra_field, i);
+    }
+    return result1 == result2;
+  }
+};
+
+TEST(MessageDifferencerTest, RepeatedFieldMapTest_CustomMapKeyComparator) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  // Treat "item" as Map, using custom key comparator to determine if two
+  // elements have the same key.
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->add_ra(6);
+  item->add_ra(35);
+  item->set_b("hello");
+  item = msg2.add_item();
+  item->add_ra(10);
+  item->add_ra(21);
+  item->set_b("hello");
+  util::MessageDifferencer differencer;
+  ValueProductMapKeyComparator key_comparator;
+  differencer.TreatAsMapUsingKeyComparator(
+      GetFieldDescriptor(msg1, "item"), &key_comparator);
+  string output;
+  differencer.ReportDifferencesToString(&output);
+  // Though the above two messages have different values for item.ra, they
+  // are regarded as having the same key because 6 * 35 == 10 * 21. That's
+  // how the key comparator determines if the two have the same key.
+  // However, in value comparison, all fields of the message are taken into
+  // consideration, so they are different because their item.ra fields have
+  // different values using normal value comparison.
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: item[0].ra[0]: 6 -> 10\n"
+      "modified: item[0].ra[1]: 35 -> 21\n",
+      output);
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "item.ra"));
+  output.clear();
+  // item.ra is ignored in value comparison, so the two messages equal.
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("ignored: item[0].ra\n", output);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSetTest_Subset) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  msg1.add_rv(3);
+  msg1.add_rv(8);
+  msg1.add_rv(2);
+  msg2.add_rv(2);
+  msg2.add_rv(3);
+  msg2.add_rv(5);
+  msg2.add_rv(8);
+
+  util::MessageDifferencer differencer;
+
+  // Fail with only partial scope set.
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_LIST);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Fail with only set-like comparison set.
+  differencer.set_scope(util::MessageDifferencer::FULL);
+  differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+  // Succeed with scope and repeated field comparison set properly.
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Single) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_c(3);
+  msg1.add_rc(1);
+
+  msg2.set_c(5);
+  msg2.add_rc(1);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "c"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Repeated) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_c(3);
+  msg1.add_rc(1);
+  msg1.add_rc(2);
+
+  msg2.set_c(3);
+  msg2.add_rc(1);
+  msg2.add_rc(3);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "rc"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Message) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestField* field;
+
+  field = msg1.add_rm();
+  field->set_c(3);
+
+  field = msg2.add_rm();
+  field->set_c(4);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "rm"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Group) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item;
+
+  item = msg1.add_item();
+  item->set_a(3);
+
+  item = msg2.add_item();
+  item->set_a(4);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "item"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Missing) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_c(3);
+  msg1.add_rc(1);
+
+  msg2.add_rc(1);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "c"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+  ExpectEqualsWithDifferencer(&differencer, msg2, msg1);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_Multiple) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_c(3);
+  msg1.add_rc(1);
+  msg1.add_rc(2);
+
+  msg2.set_c(5);
+  msg2.add_rc(1);
+  msg2.add_rc(3);
+
+  const FieldDescriptor* c = GetFieldDescriptor(msg1, "c");
+  const FieldDescriptor* rc = GetFieldDescriptor(msg1, "rc");
+
+  { // Ignore c
+    util::MessageDifferencer differencer;
+    differencer.IgnoreField(c);
+
+    EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  }
+  { // Ignore rc
+    util::MessageDifferencer differencer;
+    differencer.IgnoreField(rc);
+
+    EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  }
+  { // Ignore both
+    util::MessageDifferencer differencer;
+    differencer.IgnoreField(c);
+    differencer.IgnoreField(rc);
+
+    ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+  }
+}
+
+TEST(MessageDifferencerTest, IgnoreField_NestedMessage) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestField* field;
+
+  field = msg1.add_rm();
+  field->set_c(3);
+  field->add_rc(1);
+
+  field = msg2.add_rm();
+  field->set_c(4);
+  field->add_rc(1);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "rm.c"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_NestedGroup) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item;
+
+  item = msg1.add_item();
+  item->set_a(3);
+  item->set_b("foo");
+
+  item = msg2.add_item();
+  item->set_a(4);
+  item->set_b("foo");
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(GetFieldDescriptor(msg1, "item.a"));
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_InsideSet) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item;
+
+  item = msg1.add_item();
+  item->set_a(1);
+  item->set_b("foo");
+  item->add_ra(1);
+
+  item = msg1.add_item();
+  item->set_a(2);
+  item->set_b("bar");
+  item->add_ra(2);
+
+  item = msg2.add_item();
+  item->set_a(2);
+  item->set_b("bar");
+  item->add_ra(2);
+
+  item = msg2.add_item();
+  item->set_a(1);
+  item->set_b("baz");
+  item->add_ra(1);
+
+  const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item");
+  const FieldDescriptor* b = GetFieldDescriptor(msg1, "item.b");
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(b);
+  differencer.TreatAsSet(item_desc);
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_InsideMap) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item;
+
+  item = msg1.add_item();
+  item->set_a(1);
+  item->set_b("foo");
+  item->add_ra(1);
+
+  item = msg1.add_item();
+  item->set_a(2);
+  item->set_b("bar");
+  item->add_ra(2);
+
+  item = msg2.add_item();
+  item->set_a(2);
+  item->set_b("bar");
+  item->add_ra(2);
+
+  item = msg2.add_item();
+  item->set_a(1);
+  item->set_b("baz");
+  item->add_ra(1);
+
+  const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item");
+  const FieldDescriptor* a = GetFieldDescriptor(msg1, "item.a");
+  const FieldDescriptor* b = GetFieldDescriptor(msg1, "item.b");
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(b);
+  differencer.TreatAsMap(item_desc, a);
+
+  ExpectEqualsWithDifferencer(&differencer, msg1, msg2);
+}
+
+TEST(MessageDifferencerTest, IgnoreField_DoesNotIgnoreKey) {
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item;
+
+  item = msg1.add_item();
+  item->set_a(1);
+  item->set_b("foo");
+  item->add_ra(1);
+
+  item = msg2.add_item();
+  item->set_a(2);
+  item->set_b("foo");
+  item->add_ra(1);
+
+  const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item");
+  const FieldDescriptor* a = GetFieldDescriptor(msg1, "item.a");
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(a);
+  differencer.TreatAsMap(item_desc, a);
+
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, IgnoreField_TrumpsCompareWithFields) {
+  protobuf_unittest::TestField msg1;
+  protobuf_unittest::TestField msg2;
+
+  msg1.set_c(3);
+  msg1.add_rc(1);
+  msg1.add_rc(2);
+
+  msg2.set_c(3);
+  msg2.add_rc(1);
+  msg2.add_rc(3);
+
+  const FieldDescriptor* c = GetFieldDescriptor(msg1, "c");
+  const FieldDescriptor* rc = GetFieldDescriptor(msg1, "rc");
+
+  vector<const FieldDescriptor*> fields;
+  fields.push_back(c);
+  fields.push_back(rc);
+
+  util::MessageDifferencer differencer;
+  differencer.IgnoreField(rc);
+
+  differencer.set_scope(util::MessageDifferencer::FULL);
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields, fields));
+
+  differencer.set_scope(util::MessageDifferencer::PARTIAL);
+  EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields, fields));
+}
+
+
+// Test class to save a copy of the last field_context.parent_fields() vector
+// passed to the comparison function.
+class ParentSavingFieldComparator : public util::FieldComparator {
+ public:
+  ParentSavingFieldComparator() {}
+
+  virtual ComparisonResult Compare(
+      const google::protobuf::Message& message_1,
+      const google::protobuf::Message& message_2,
+      const google::protobuf::FieldDescriptor* field,
+      int index_1, int index_2,
+      const google::protobuf::util::FieldContext* field_context) {
+    if (field_context)
+      parent_fields_ = *(field_context->parent_fields());
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      return RECURSE;
+    } else {
+      return SAME;
+    }
+  }
+
+  vector<google::protobuf::util::MessageDifferencer::SpecificField> parent_fields() {
+    return parent_fields_;
+  }
+
+ private:
+  vector<google::protobuf::util::MessageDifferencer::SpecificField> parent_fields_;
+};
+
+// Tests if MessageDifferencer sends the parent fields in the FieldContext
+// parameter.
+TEST(MessageDifferencerTest, FieldContextParentFieldsTest) {
+  protobuf_unittest::TestDiffMessage msg1;
+  msg1.add_rm()->set_c(1);
+  protobuf_unittest::TestDiffMessage msg2;
+  msg2.add_rm()->set_c(1);
+
+  ParentSavingFieldComparator field_comparator;
+  util::MessageDifferencer differencer;
+  differencer.set_field_comparator(&field_comparator);
+  differencer.Compare(msg1, msg2);
+
+  // We want only one parent with the name "rm"
+  ASSERT_EQ(1, field_comparator.parent_fields().size());
+  EXPECT_EQ("rm", field_comparator.parent_fields()[0].field->name());
+}
+
+
+class ComparisonTest : public testing::Test {
+ protected:
+  ComparisonTest() : use_equivalency_(false), repeated_field_as_set_(false) {
+    // Setup the test.
+    TestUtil::SetAllFields(&proto1_);
+    TestUtil::SetAllFields(&proto2_);
+
+    TestUtil::SetAllExtensions(&proto1ex_);
+    TestUtil::SetAllExtensions(&proto2ex_);
+
+    TestUtil::SetAllFieldsAndExtensions(&orderings_proto1_);
+    TestUtil::SetAllFieldsAndExtensions(&orderings_proto2_);
+
+    unknown1_ = empty1_.mutable_unknown_fields();
+    unknown2_ = empty2_.mutable_unknown_fields();
+  }
+
+  ~ComparisonTest() { }
+
+  void SetSpecialFieldOption(const Message& message,
+                              util::MessageDifferencer* d) {
+    if (!ignored_field_.empty()) {
+      d->IgnoreField(GetFieldDescriptor(message, ignored_field_));
+    }
+
+    if (repeated_field_as_set_) {
+      d->set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+    }
+
+    if (!set_field_.empty()) {
+      d->TreatAsSet(GetFieldDescriptor(message, set_field_));
+    }
+
+    if (!map_field_.empty() && !map_key_.empty()) {
+      d->TreatAsMap(GetFieldDescriptor(message, map_field_),
+                    GetFieldDescriptor(message, map_field_ + "." + map_key_));
+    }
+  }
+
+  string Run(const Message& msg1, const Message& msg2) {
+    string output;
+
+    // Setup the comparison.
+    util::MessageDifferencer differencer;
+    differencer.ReportDifferencesToString(&output);
+
+    if (use_equivalency_) {
+      differencer.set_message_field_comparison(
+          util::MessageDifferencer::EQUIVALENT);
+    }
+
+    SetSpecialFieldOption(msg1, &differencer);
+
+    // Conduct the comparison.
+    EXPECT_FALSE(differencer.Compare(msg1, msg2));
+
+    return output;
+  }
+
+  string Run() {
+    return Run(proto1_, proto2_);
+  }
+
+  string RunOrder() {
+    return Run(orderings_proto1_, orderings_proto2_);
+  }
+
+  string RunEx() {
+    return Run(proto1ex_, proto2ex_);
+  }
+
+  string RunDiff() {
+    return Run(proto1diff_, proto2diff_);
+  }
+
+  string RunUn() {
+    return Run(empty1_, empty2_);
+  }
+
+  void use_equivalency() {
+    use_equivalency_ = true;
+  }
+
+  void repeated_field_as_set() {
+    repeated_field_as_set_ = true;
+  }
+
+  void field_as_set(const string& field) {
+    set_field_ = field;
+  }
+
+  void field_as_map(const string& field, const string& key) {
+    map_field_ = field;
+    map_key_   = key;
+  }
+
+  void ignore_field(const string& field) {
+    ignored_field_ = field;
+  }
+
+  unittest::TestAllTypes proto1_;
+  unittest::TestAllTypes proto2_;
+
+  unittest::TestFieldOrderings orderings_proto1_;
+  unittest::TestFieldOrderings orderings_proto2_;
+
+  unittest::TestAllExtensions proto1ex_;
+  unittest::TestAllExtensions proto2ex_;
+
+  unittest::TestDiffMessage proto1diff_;
+  unittest::TestDiffMessage proto2diff_;
+
+  unittest::TestEmptyMessage empty1_;
+  unittest::TestEmptyMessage empty2_;
+
+  UnknownFieldSet* unknown1_;
+  UnknownFieldSet* unknown2_;
+
+  bool use_equivalency_;
+  bool repeated_field_as_set_;
+
+  string set_field_;
+  string map_field_;
+  string map_key_;
+  string ignored_field_;
+};
+
+// Basic tests.
+TEST_F(ComparisonTest, AdditionTest) {
+  proto1_.clear_optional_int32();
+
+  EXPECT_EQ("added: optional_int32: 101\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, Addition_OrderTest) {
+  orderings_proto1_.clear_my_int();
+
+  EXPECT_EQ("added: my_int: 1\n",
+            RunOrder());
+}
+
+TEST_F(ComparisonTest, DeletionTest) {
+  proto2_.clear_optional_int32();
+
+  EXPECT_EQ("deleted: optional_int32: 101\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, Deletion_OrderTest) {
+  orderings_proto2_.clear_my_string();
+
+  EXPECT_EQ("deleted: my_string: \"foo\"\n",
+            RunOrder());
+}
+
+TEST_F(ComparisonTest, RepeatedDeletionTest) {
+  proto2_.clear_repeated_int32();
+
+  EXPECT_EQ("deleted: repeated_int32[0]: 201\n"
+            "deleted: repeated_int32[1]: 301\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, ModificationTest) {
+  proto1_.set_optional_int32(-1);
+
+  EXPECT_EQ("modified: optional_int32: -1 -> 101\n",
+            Run());
+}
+
+// Basic equivalency tests.
+TEST_F(ComparisonTest, EquivalencyAdditionTest) {
+  use_equivalency();
+
+  proto1_.clear_optional_int32();
+
+  EXPECT_EQ("modified: optional_int32: 0 -> 101\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EquivalencyDeletionTest) {
+  use_equivalency();
+
+  proto2_.clear_optional_int32();
+
+  EXPECT_EQ("modified: optional_int32: 101 -> 0\n",
+            Run());
+}
+
+// Group tests.
+TEST_F(ComparisonTest, GroupAdditionTest) {
+  proto1_.mutable_optionalgroup()->clear_a();
+
+  EXPECT_EQ("added: optionalgroup.a: 117\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, GroupDeletionTest) {
+  proto2_.mutable_optionalgroup()->clear_a();
+
+  EXPECT_EQ("deleted: optionalgroup.a: 117\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, GroupModificationTest) {
+  proto1_.mutable_optionalgroup()->set_a(2);
+
+  EXPECT_EQ("modified: optionalgroup.a: 2 -> 117\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, GroupFullAdditionTest) {
+  proto1_.clear_optionalgroup();
+
+  // Note the difference in the output between this and GroupAdditionTest.
+  EXPECT_EQ("added: optionalgroup: { a: 117 }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, GroupFullDeletionTest) {
+  proto2_.clear_optionalgroup();
+
+  EXPECT_EQ("deleted: optionalgroup: { a: 117 }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, RepeatedSetOptionTest) {
+  repeated_field_as_set();
+
+  proto2_.clear_repeatedgroup();
+  proto1_.clear_repeatedgroup();
+  proto1_.add_repeatedgroup()->set_a(317);
+  proto2_.add_repeatedgroup()->set_a(909);
+  proto2_.add_repeatedgroup()->set_a(907);
+  proto1_.add_repeatedgroup()->set_a(904);
+  proto1_.add_repeatedgroup()->set_a(907);
+  proto1_.add_repeatedgroup()->set_a(909);
+
+  EXPECT_EQ("moved: repeatedgroup[2] -> repeatedgroup[1] : { a: 907 }\n"
+            "moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n"
+            "deleted: repeatedgroup[0]: { a: 317 }\n"
+            "deleted: repeatedgroup[1]: { a: 904 }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, RepeatedSetOptionTest_Ex) {
+  repeated_field_as_set();
+
+  proto1ex_.ClearExtension(protobuf_unittest::repeated_nested_message_extension);
+  proto2ex_.ClearExtension(protobuf_unittest::repeated_nested_message_extension);
+  proto2ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension)
+      ->set_bb(909);
+  proto2ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension)
+      ->set_bb(907);
+  proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension)
+      ->set_bb(904);
+  proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension)
+      ->set_bb(907);
+  proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension)
+      ->set_bb(909);
+
+  EXPECT_EQ("moved: (protobuf_unittest.repeated_nested_message_extension)[2] ->"
+            " (protobuf_unittest.repeated_nested_message_extension)[0] :"
+            " { bb: 909 }\n"
+            "deleted: (protobuf_unittest.repeated_nested_message_extension)[0]:"
+            " { bb: 904 }\n",
+            RunEx());
+}
+
+TEST_F(ComparisonTest, RepeatedMapFieldTest_Group) {
+  field_as_map("repeatedgroup", "a");
+  proto1_.clear_repeatedgroup();
+  proto2_.clear_repeatedgroup();
+
+  proto1_.add_repeatedgroup()->set_a(317);  // deleted
+  proto1_.add_repeatedgroup()->set_a(904);  // deleted
+  proto1_.add_repeatedgroup()->set_a(907);  // moved from
+  proto1_.add_repeatedgroup()->set_a(909);  // moved from
+
+  proto2_.add_repeatedgroup()->set_a(909);  // moved to
+  proto2_.add_repeatedgroup()->set_a(318);  // added
+  proto2_.add_repeatedgroup()->set_a(907);  // moved to
+
+  EXPECT_EQ("moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n"
+            "added: repeatedgroup[1]: { a: 318 }\n"
+            "deleted: repeatedgroup[0]: { a: 317 }\n"
+            "deleted: repeatedgroup[1]: { a: 904 }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, RepeatedMapFieldTest_MessageKey) {
+  // Use m as key, but use b as value.
+  field_as_map("item", "m");
+
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+
+  // The following code creates one deletion, one addition and two moved fields
+  // on the messages.
+  item->mutable_m()->set_c(0);
+  item->set_b("first");
+  item = msg1.add_item();
+  item->mutable_m()->set_c(2);
+  item->set_b("second");
+  item = msg1.add_item(); item->set_b("null");  // empty key moved
+  item = msg1.add_item();
+  item->mutable_m()->set_c(3);
+  item->set_b("third");   // deletion
+  item = msg1.add_item();
+  item->mutable_m()->set_c(2);
+  item->set_b("second");  // duplicated key ( deletion )
+  item = msg2.add_item();
+  item->mutable_m()->set_c(2);
+  item->set_b("second");  // modification
+  item = msg2.add_item();
+  item->mutable_m()->set_c(4);
+  item->set_b("fourth");  // addition
+  item = msg2.add_item();
+  item->mutable_m()->set_c(0);
+  item->set_b("fist");    // move with change
+  item = msg2.add_item(); item->set_b("null");
+
+  EXPECT_EQ(
+      "modified: item[0].b -> item[2].b: \"first\" -> \"fist\"\n"
+      "moved: item[1] -> item[0] : { b: \"second\" m { c: 2 } }\n"
+      "moved: item[2] -> item[3] : { b: \"null\" }\n"
+      "added: item[1]: { b: \"fourth\" m { c: 4 } }\n"
+      "deleted: item[3]: { b: \"third\" m { c: 3 } }\n"
+      "deleted: item[4]: { b: \"second\" m { c: 2 } }\n",
+      Run(msg1, msg2));
+}
+
+TEST_F(ComparisonTest, RepeatedFieldSetTest_SetOfSet) {
+  repeated_field_as_set();
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->add_ra(1); item->add_ra(2); item->add_ra(3);
+  item = msg1.add_item();
+  item->add_ra(5); item->add_ra(6);
+  item = msg1.add_item();
+  item->add_ra(1); item->add_ra(3);
+  item = msg1.add_item();
+  item->add_ra(6); item->add_ra(7); item->add_ra(8);
+
+  item = msg2.add_item();
+  item->add_ra(6); item->add_ra(5);
+  item = msg2.add_item();
+  item->add_ra(6); item->add_ra(8);
+  item = msg2.add_item();
+  item->add_ra(1); item->add_ra(3);
+  item = msg2.add_item();
+  item->add_ra(3); item->add_ra(2); item->add_ra(1);
+
+  // Compare
+  EXPECT_EQ("moved: item[0].ra[0] -> item[3].ra[2] : 1\n"
+            "moved: item[0].ra[2] -> item[3].ra[0] : 3\n"
+            "moved: item[0] -> item[3] : { ra: 1 ra: 2 ra: 3 }\n"
+            "moved: item[1].ra[0] -> item[0].ra[1] : 5\n"
+            "moved: item[1].ra[1] -> item[0].ra[0] : 6\n"
+            "moved: item[1] -> item[0] : { ra: 5 ra: 6 }\n"
+            "added: item[1]: { ra: 6 ra: 8 }\n"
+            "deleted: item[3]: { ra: 6 ra: 7 ra: 8 }\n",
+            Run(msg1, msg2));
+}
+
+TEST_F(ComparisonTest, RepeatedMapFieldTest_RepeatedKey) {
+  // used rb as a key, but b is the value.
+  repeated_field_as_set();
+  field_as_map("item", "rb");
+
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->add_rb("a");
+  item->add_rb("b");
+  item->set_b("first");
+
+  item = msg2.add_item();
+  item->add_rb("c");
+  item->set_b("second");
+
+  item = msg2.add_item();
+  item->add_rb("b");
+  item->add_rb("a");
+  item->set_b("fist");
+
+
+  EXPECT_EQ("modified: item[0].b -> item[1].b: \"first\" -> \"fist\"\n"
+            "moved: item[0].rb[0] -> item[1].rb[1] : \"a\"\n"
+            "moved: item[0].rb[1] -> item[1].rb[0] : \"b\"\n"
+            "added: item[0]: { b: \"second\" rb: \"c\" }\n",
+            Run(msg1, msg2));
+}
+
+TEST_F(ComparisonTest, RepeatedMapFieldTest_RepeatedMessageKey) {
+  field_as_map("item", "rm");
+
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  protobuf_unittest::TestField* key = item->add_rm();
+  key->set_c(2); key->add_rc(10); key->add_rc(10);
+  item = msg1.add_item(); key = item->add_rm();
+  key->set_c(0); key->add_rc(1); key->add_rc(2);
+  key = item->add_rm();
+  key->set_c(0);
+  item->add_rb("first");
+
+  item = msg2.add_item();
+  item->CopyFrom(msg1.item(1));
+  item->add_rb("second");
+
+  EXPECT_EQ("added: item[0].rb[1]: \"second\"\n"
+            "deleted: item[0]: { rm { c: 2 rc: 10 rc: 10 } }\n",
+            Run(msg1, msg2));
+}
+
+TEST_F(ComparisonTest, RepeatedSetOptionTest_Unknown) {
+  // Currently, as_set option doens't have affects on unknown field.
+  // If needed, this feature will be added by request.
+  repeated_field_as_set();
+  unknown1_->AddGroup(245)->AddFixed32(248, 1);
+  unknown2_->AddGroup(245)->AddFixed32(248, 3);
+  unknown2_->AddGroup(245)->AddFixed32(248, 1);
+
+  // We expect it behaves the same as normal comparison.
+  EXPECT_EQ("modified: 245[0].248[0]: 0x00000001 -> 0x00000003\n"
+            "added: 245[1]: { ... }\n",
+            RunUn());
+}
+
+TEST_F(ComparisonTest, Matching_Unknown) {
+  unknown1_->AddGroup(245)->AddFixed32(248, 1);
+  unknown2_->AddGroup(245)->AddFixed32(248, 1);
+  unknown1_->AddGroup(245)->AddFixed32(248, 3);
+  unknown2_->AddGroup(245)->AddFixed32(248, 3);
+  unknown2_->AddLengthDelimited(242, "cat");
+  unknown2_->AddGroup(246)->AddFixed32(248, 4);
+
+  // report_match is false so only added/modified fields are expected.
+  EXPECT_EQ("added: 242[0]: \"cat\"\n"
+            "added: 246[0]: { ... }\n",
+            RunUn());
+}
+
+TEST_F(ComparisonTest, RepeatedSetFieldTest) {
+  field_as_set("repeatedgroup");
+
+  proto1_.clear_repeatedgroup();
+  proto2_.clear_repeatedgroup();
+  proto2_.add_repeatedgroup()->set_a(909);
+  proto2_.add_repeatedgroup()->set_a(907);
+  proto1_.add_repeatedgroup()->set_a(317);
+  proto1_.add_repeatedgroup()->set_a(904);
+  proto1_.add_repeatedgroup()->set_a(907);
+  proto1_.add_repeatedgroup()->set_a(909);
+
+  EXPECT_EQ("moved: repeatedgroup[2] -> repeatedgroup[1] : { a: 907 }\n"
+            "moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n"
+            "deleted: repeatedgroup[0]: { a: 317 }\n"
+            "deleted: repeatedgroup[1]: { a: 904 }\n",
+            Run());
+}
+
+// Embedded message tests.
+TEST_F(ComparisonTest, EmbeddedAdditionTest) {
+  proto1_.mutable_optional_nested_message()->clear_bb();
+
+  EXPECT_EQ("added: optional_nested_message.bb: 118\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EmbeddedDeletionTest) {
+  proto2_.mutable_optional_nested_message()->clear_bb();
+
+  EXPECT_EQ("deleted: optional_nested_message.bb: 118\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EmbeddedModificationTest) {
+  proto1_.mutable_optional_nested_message()->set_bb(2);
+
+  EXPECT_EQ("modified: optional_nested_message.bb: 2 -> 118\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EmbeddedFullAdditionTest) {
+  proto1_.clear_optional_nested_message();
+
+  EXPECT_EQ("added: optional_nested_message: { bb: 118 }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EmbeddedPartialAdditionTest) {
+  proto1_.clear_optional_nested_message();
+  proto2_.mutable_optional_nested_message()->clear_bb();
+
+  EXPECT_EQ("added: optional_nested_message: { }\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, EmbeddedFullDeletionTest) {
+  proto2_.clear_optional_nested_message();
+
+  EXPECT_EQ("deleted: optional_nested_message: { bb: 118 }\n",
+            Run());
+}
+
+// Repeated element tests.
+TEST_F(ComparisonTest, BasicRepeatedTest) {
+  proto1_.clear_repeated_int32();
+  proto2_.clear_repeated_int32();
+
+  proto1_.add_repeated_int32(500);
+  proto1_.add_repeated_int32(501);
+  proto1_.add_repeated_int32(502);
+  proto1_.add_repeated_int32(503);
+  proto1_.add_repeated_int32(500);
+
+  proto2_.add_repeated_int32(500);
+  proto2_.add_repeated_int32(509);
+  proto2_.add_repeated_int32(502);
+  proto2_.add_repeated_int32(504);
+
+  EXPECT_EQ("modified: repeated_int32[1]: 501 -> 509\n"
+            "modified: repeated_int32[3]: 503 -> 504\n"
+            "deleted: repeated_int32[4]: 500\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, BasicRepeatedTest_SetOption) {
+  repeated_field_as_set();
+  proto1_.clear_repeated_int32();
+  proto2_.clear_repeated_int32();
+
+  proto1_.add_repeated_int32(501);
+  proto1_.add_repeated_int32(502);
+  proto1_.add_repeated_int32(503);
+  proto1_.add_repeated_int32(500);
+  proto1_.add_repeated_int32(500);
+
+  proto2_.add_repeated_int32(500);
+  proto2_.add_repeated_int32(509);
+  proto2_.add_repeated_int32(503);
+  proto2_.add_repeated_int32(502);
+  proto2_.add_repeated_int32(504);
+
+  EXPECT_EQ("moved: repeated_int32[1] -> repeated_int32[3] : 502\n"
+            "moved: repeated_int32[3] -> repeated_int32[0] : 500\n"
+            "added: repeated_int32[1]: 509\n"
+            "added: repeated_int32[4]: 504\n"
+            "deleted: repeated_int32[0]: 501\n"
+            "deleted: repeated_int32[4]: 500\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, BasicRepeatedTest_SetField) {
+  field_as_set("repeated_int32");
+  proto1_.clear_repeated_int32();
+  proto2_.clear_repeated_int32();
+
+  proto1_.add_repeated_int32(501);
+  proto1_.add_repeated_int32(502);
+  proto1_.add_repeated_int32(503);
+  proto1_.add_repeated_int32(500);
+  proto1_.add_repeated_int32(500);
+
+  proto2_.add_repeated_int32(500);
+  proto2_.add_repeated_int32(509);
+  proto2_.add_repeated_int32(503);
+  proto2_.add_repeated_int32(502);
+  proto2_.add_repeated_int32(504);
+
+  EXPECT_EQ("moved: repeated_int32[1] -> repeated_int32[3] : 502\n"
+            "moved: repeated_int32[3] -> repeated_int32[0] : 500\n"
+            "added: repeated_int32[1]: 509\n"
+            "added: repeated_int32[4]: 504\n"
+            "deleted: repeated_int32[0]: 501\n"
+            "deleted: repeated_int32[4]: 500\n",
+            Run());
+}
+
+// Multiple action tests.
+TEST_F(ComparisonTest, AddDeleteTest) {
+  proto1_.clear_optional_int32();
+  proto2_.clear_optional_int64();
+
+  EXPECT_EQ("added: optional_int32: 101\n"
+            "deleted: optional_int64: 102\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, AddDelete_FieldOrderingTest) {
+  orderings_proto1_.ClearExtension(unittest::my_extension_string);
+  orderings_proto2_.clear_my_int();
+
+  EXPECT_EQ("deleted: my_int: 1\n"
+            "added: (protobuf_unittest.my_extension_string): \"bar\"\n",
+            RunOrder());
+}
+
+TEST_F(ComparisonTest, AllThreeTest) {
+  proto1_.clear_optional_int32();
+  proto2_.clear_optional_float();
+  proto2_.set_optional_string("hello world!");
+
+  EXPECT_EQ("added: optional_int32: 101\n"
+            "deleted: optional_float: 111\n"
+            "modified: optional_string: \"115\" -> \"hello world!\"\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, SandwhichTest) {
+  proto1_.clear_optional_int64();
+  proto1_.clear_optional_uint32();
+
+  proto2_.clear_optional_uint64();
+
+  EXPECT_EQ("added: optional_int64: 102\n"
+            "added: optional_uint32: 103\n"
+            "deleted: optional_uint64: 104\n",
+            Run());
+}
+
+TEST_F(ComparisonTest, IgnoredNoChangeTest) {
+  proto1diff_.set_v(3);
+  proto2diff_.set_v(3);
+  proto2diff_.set_w("foo");
+
+  ignore_field("v");
+
+  EXPECT_EQ("ignored: v\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredAddTest) {
+  proto2diff_.set_v(3);
+  proto2diff_.set_w("foo");
+
+  ignore_field("v");
+
+  EXPECT_EQ("ignored: v\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredDeleteTest) {
+  proto1diff_.set_v(3);
+  proto2diff_.set_w("foo");
+
+  ignore_field("v");
+
+  EXPECT_EQ("ignored: v\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredModifyTest) {
+  proto1diff_.set_v(3);
+  proto2diff_.set_v(4);
+  proto2diff_.set_w("foo");
+
+  ignore_field("v");
+
+  EXPECT_EQ("ignored: v\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredRepeatedAddTest) {
+  proto1diff_.add_rv(3);
+  proto1diff_.add_rv(4);
+
+  proto2diff_.add_rv(3);
+  proto2diff_.add_rv(4);
+  proto2diff_.add_rv(5);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("rv");
+
+  EXPECT_EQ("ignored: rv\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredRepeatedDeleteTest) {
+  proto1diff_.add_rv(3);
+  proto1diff_.add_rv(4);
+  proto1diff_.add_rv(5);
+
+  proto2diff_.add_rv(3);
+  proto2diff_.add_rv(4);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("rv");
+
+  EXPECT_EQ("ignored: rv\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredRepeatedModifyTest) {
+  proto1diff_.add_rv(3);
+  proto1diff_.add_rv(4);
+
+  proto2diff_.add_rv(3);
+  proto2diff_.add_rv(5);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("rv");
+
+  EXPECT_EQ("ignored: rv\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredWholeNestedMessage) {
+  proto1diff_.mutable_m()->set_c(3);
+  proto2diff_.mutable_m()->set_c(4);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("m");
+
+  EXPECT_EQ("added: w: \"foo\"\n"
+            "ignored: m\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredNestedField) {
+  proto1diff_.mutable_m()->set_c(3);
+  proto2diff_.mutable_m()->set_c(4);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("m.c");
+
+  EXPECT_EQ("added: w: \"foo\"\n"
+            "ignored: m.c\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredRepeatedNested) {
+  proto1diff_.add_rm()->set_c(0);
+  proto1diff_.add_rm()->set_c(1);
+  proto2diff_.add_rm()->set_c(2);
+  proto2diff_.add_rm()->set_c(3);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("rm.c");
+
+  EXPECT_EQ("ignored: rm[0].c\n"
+            "ignored: rm[1].c\n"
+            "added: w: \"foo\"\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, IgnoredNestedRepeated) {
+  proto1diff_.mutable_m()->add_rc(23);
+  proto1diff_.mutable_m()->add_rc(24);
+  proto2diff_.mutable_m()->add_rc(25);
+
+  proto2diff_.set_w("foo");
+
+  ignore_field("m.rc");
+
+  EXPECT_EQ("added: w: \"foo\"\n"
+            "ignored: m.rc\n",
+            RunDiff());
+}
+
+TEST_F(ComparisonTest, ExtensionTest) {
+  proto1ex_.SetExtension(unittest::optional_int32_extension, 401);
+  proto2ex_.SetExtension(unittest::optional_int32_extension, 402);
+
+  proto1ex_.ClearExtension(unittest::optional_int64_extension);
+  proto2ex_.SetExtension(unittest::optional_int64_extension, 403);
+
+  EXPECT_EQ(
+      "modified: (protobuf_unittest.optional_int32_extension): 401 -> 402\n"
+      "added: (protobuf_unittest.optional_int64_extension): 403\n",
+      RunEx());
+}
+
+TEST_F(ComparisonTest, MatchedUnknownFieldTagTest) {
+  unknown1_->AddVarint(240, 122);
+  unknown2_->AddVarint(240, 121);
+  unknown1_->AddFixed32(241, 1);
+  unknown2_->AddFixed64(241, 2);
+  unknown1_->AddLengthDelimited(242, "cat");
+  unknown2_->AddLengthDelimited(242, "dog");
+
+  EXPECT_EQ(
+      "modified: 240[0]: 122 -> 121\n"
+      "deleted: 241[0]: 0x00000001\n"
+      "added: 241[0]: 0x0000000000000002\n"
+      "modified: 242[0]: \"cat\" -> \"dog\"\n",
+      RunUn());
+}
+
+TEST_F(ComparisonTest, UnmatchedUnknownFieldTagTest) {
+  unknown1_->AddFixed32(243, 1);
+  unknown2_->AddVarint(244, 2);
+  unknown2_->AddVarint(244, 4);
+
+  EXPECT_EQ(
+      "deleted: 243[0]: 0x00000001\n"
+      "added: 244[0]: 2\n"
+      "added: 244[1]: 4\n",
+      RunUn());
+}
+
+TEST_F(ComparisonTest, DifferentSizedUnknownFieldTest) {
+  unknown1_->AddVarint(240, 1);
+  unknown1_->AddVarint(240, 3);
+  unknown1_->AddVarint(240, 4);
+  unknown2_->AddVarint(240, 2);
+  unknown2_->AddVarint(240, 3);
+  unknown2_->AddVarint(240, 2);
+  unknown2_->AddVarint(240, 5);
+
+  EXPECT_EQ(
+      "modified: 240[0]: 1 -> 2\n"
+      "modified: 240[2]: 4 -> 2\n"
+      "added: 240[3]: 5\n",
+      RunUn());
+}
+
+TEST_F(ComparisonTest, UnknownFieldsAll) {
+  unknown1_->AddVarint(243, 122);
+  unknown1_->AddFixed64(244, 0x0172356);
+  unknown1_->AddFixed64(244, 0x098);
+  unknown1_->AddGroup(245)->AddFixed32(248, 1);
+  unknown1_->mutable_field(3)->mutable_group()->AddFixed32(248, 2);
+  unknown1_->AddGroup(249)->AddFixed64(250, 1);
+
+  unknown2_->AddVarint(243, 121);
+  unknown2_->AddLengthDelimited(73882, "test 123");
+  unknown2_->AddGroup(245)->AddFixed32(248, 3);
+  unknown2_->AddGroup(247);
+
+  EXPECT_EQ(
+      "modified: 243[0]: 122 -> 121\n"
+      "deleted: 244[0]: 0x0000000000172356\n"
+      "deleted: 244[1]: 0x0000000000000098\n"
+      "modified: 245[0].248[0]: 0x00000001 -> 0x00000003\n"
+      "deleted: 245[0].248[1]: 0x00000002\n"
+      "added: 247[0]: { ... }\n"
+      "deleted: 249[0]: { ... }\n"
+      "added: 73882[0]: \"test 123\"\n",
+      RunUn());
+}
+
+TEST_F(ComparisonTest, EquivalentIgnoresUnknown) {
+  unittest::ForeignMessage message1, message2;
+
+  message1.set_c(5);
+  message1.mutable_unknown_fields()->AddVarint(123, 456);
+  message2.set_c(5);
+  message2.mutable_unknown_fields()->AddVarint(321, 654);
+
+  EXPECT_FALSE(util::MessageDifferencer::Equals(message1, message2));
+  EXPECT_TRUE(util::MessageDifferencer::Equivalent(message1, message2));
+}
+
+class MatchingTest : public testing::Test {
+ public:
+  typedef util::MessageDifferencer MessageDifferencer;
+
+ protected:
+  MatchingTest() {
+  }
+
+  ~MatchingTest() {
+  }
+
+  string RunWithResult(MessageDifferencer* differencer,
+                              const Message& msg1, const Message& msg2,
+                              bool result) {
+    string output;
+    {
+      // Before we return the "output" string, we must make sure the
+      // StreamReporter is destructored because its destructor will
+      // flush the stream.
+      io::StringOutputStream output_stream(&output);
+      MessageDifferencer::StreamReporter reporter(&output_stream);
+      reporter.set_report_modified_aggregates(true);
+      differencer->set_report_matches(true);
+      differencer->ReportDifferencesTo(&reporter);
+      if (result) {
+        EXPECT_TRUE(differencer->Compare(msg1, msg2));
+      } else {
+        EXPECT_FALSE(differencer->Compare(msg1, msg2));
+      }
+    }
+    return output;
+  }
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MatchingTest);
+};
+
+TEST_F(MatchingTest, StreamReporterMatching) {
+  protobuf_unittest::TestField msg1, msg2;
+  msg1.set_c(72);
+  msg2.set_c(72);
+  msg1.add_rc(13);
+  msg2.add_rc(13);
+  msg1.add_rc(17);
+  msg2.add_rc(17);
+  string output;
+  MessageDifferencer differencer;
+  differencer.set_report_matches(true);
+  differencer.ReportDifferencesToString(&output);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "matched: c : 72\n"
+      "matched: rc[0] : 13\n"
+      "matched: rc[1] : 17\n",
+      output);
+}
+
+TEST_F(MatchingTest, DontReportMatchedWhenIgnoring) {
+  protobuf_unittest::TestField msg1, msg2;
+  msg1.set_c(72);
+  msg2.set_c(72);
+  msg1.add_rc(13);
+  msg2.add_rc(13);
+  msg1.add_rc(17);
+  msg2.add_rc(17);
+  string output;
+  MessageDifferencer differencer;
+  differencer.set_report_matches(true);
+  differencer.ReportDifferencesToString(&output);
+
+  differencer.IgnoreField(msg1.GetDescriptor()->FindFieldByName("c"));
+
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "ignored: c\n"
+      "matched: rc[0] : 13\n"
+      "matched: rc[1] : 17\n",
+      output);
+}
+
+TEST_F(MatchingTest, ReportMatchedForMovedFields) {
+  protobuf_unittest::TestDiffMessage msg1, msg2;
+  protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item();
+  item->set_a(53);
+  item->set_b("hello");
+  item = msg2.add_item();
+  item->set_a(27);
+  item = msg2.add_item();
+  item->set_a(53);
+  item->set_b("hello");
+  item = msg1.add_item();
+  item->set_a(27);
+  MessageDifferencer differencer;
+  const FieldDescriptor* desc;
+  desc = msg1.GetDescriptor()->FindFieldByName("item");
+  differencer.TreatAsSet(desc);
+
+  EXPECT_EQ(
+      "matched: item[0].a -> item[1].a : 53\n"
+      "matched: item[0].b -> item[1].b : \"hello\"\n"
+      "moved: item[0] -> item[1] : { a: 53 b: \"hello\" }\n"
+      "matched: item[1].a -> item[0].a : 27\n"
+      "moved: item[1] -> item[0] : { a: 27 }\n",
+      RunWithResult(&differencer, msg1, msg2, true));
+}
+
+TEST_F(MatchingTest, MatchesAppearInPostTraversalOrderForMovedFields) {
+  protobuf_unittest::TestDiffMessage msg1, msg2;
+  protobuf_unittest::TestDiffMessage::Item* item;
+  protobuf_unittest::TestField* field;
+
+  const FieldDescriptor* desc;
+  const FieldDescriptor* nested_desc;
+  const FieldDescriptor* double_nested_desc;
+  desc = msg1.GetDescriptor()->FindFieldByName("item");
+  nested_desc = desc->message_type()->FindFieldByName("rm");
+  double_nested_desc = nested_desc->message_type()->FindFieldByName("rc");
+  MessageDifferencer differencer;
+  differencer.TreatAsSet(desc);
+  differencer.TreatAsSet(nested_desc);
+  differencer.TreatAsSet(double_nested_desc);
+
+  item = msg1.add_item();
+  field = item->add_rm();
+  field->set_c(1);
+  field->add_rc(2);
+  field->add_rc(3);
+  field = item->add_rm();
+  field->set_c(4);
+  field->add_rc(5);
+  field->add_rc(6);
+  field->add_rc(7);
+  item = msg2.add_item();
+  field = item->add_rm();
+  field->set_c(4);
+  field->add_rc(7);
+  field->add_rc(6);
+  field->add_rc(5);
+  field = item->add_rm();
+  field->set_c(1);
+  field->add_rc(3);
+  field->add_rc(2);
+  item = msg1.add_item();
+  field = item->add_rm();
+  field->set_c(8);
+  field->add_rc(10);
+  field->add_rc(11);
+  field->add_rc(9);
+  item = msg2.add_item();
+  field = item->add_rm();
+  field->set_c(8);
+  field->add_rc(9);
+  field->add_rc(10);
+  field->add_rc(11);
+
+  EXPECT_EQ(
+      "matched: item[0].rm[0].c -> item[0].rm[1].c : 1\n"
+      "moved: item[0].rm[0].rc[0] -> item[0].rm[1].rc[1] : 2\n"
+      "moved: item[0].rm[0].rc[1] -> item[0].rm[1].rc[0] : 3\n"
+      "moved: item[0].rm[0] -> item[0].rm[1] : { c: 1 rc: 2 rc: 3 }\n"
+      "matched: item[0].rm[1].c -> item[0].rm[0].c : 4\n"
+      "moved: item[0].rm[1].rc[0] -> item[0].rm[0].rc[2] : 5\n"
+      "matched: item[0].rm[1].rc[1] -> item[0].rm[0].rc[1] : 6\n"
+      "moved: item[0].rm[1].rc[2] -> item[0].rm[0].rc[0] : 7\n"
+      "moved: item[0].rm[1] -> item[0].rm[0] : { c: 4 rc: 5 rc: 6 rc: 7 }\n"
+      "matched: item[0] : { rm { c: 1 rc: 2 rc: 3 }"
+                          " rm { c: 4 rc: 5 rc: 6 rc: 7 } }\n"
+      "matched: item[1].rm[0].c : 8\n"
+      "moved: item[1].rm[0].rc[0] -> item[1].rm[0].rc[1] : 10\n"
+      "moved: item[1].rm[0].rc[1] -> item[1].rm[0].rc[2] : 11\n"
+      "moved: item[1].rm[0].rc[2] -> item[1].rm[0].rc[0] : 9\n"
+      "matched: item[1].rm[0] : { c: 8 rc: 10 rc: 11 rc: 9 }\n"
+      "matched: item[1] : { rm { c: 8 rc: 10 rc: 11 rc: 9 } }\n",
+      RunWithResult(&differencer, msg1, msg2, true));
+}
+
+TEST_F(MatchingTest, MatchAndModifiedInterleaveProperly) {
+  protobuf_unittest::TestDiffMessage msg1, msg2;
+  protobuf_unittest::TestDiffMessage::Item* item;
+  protobuf_unittest::TestField* field;
+
+  const FieldDescriptor* desc;
+  const FieldDescriptor* nested_key;
+  const FieldDescriptor* nested_desc;
+  const FieldDescriptor* double_nested_key;
+  const FieldDescriptor* double_nested_desc;
+  desc = msg1.GetDescriptor()->FindFieldByName("item");
+  nested_key = desc->message_type()->FindFieldByName("a");
+  nested_desc = desc->message_type()->FindFieldByName("rm");
+  double_nested_key = nested_desc->message_type()->FindFieldByName("c");
+  double_nested_desc = nested_desc->message_type()->FindFieldByName("rc");
+
+  MessageDifferencer differencer;
+  differencer.TreatAsMap(desc, nested_key);
+  differencer.TreatAsMap(nested_desc, double_nested_key);
+  differencer.TreatAsSet(double_nested_desc);
+
+  item = msg1.add_item();
+  item->set_a(1);
+  field = item->add_rm();
+  field->set_c(2);
+  field->add_rc(3);
+  field->add_rc(4);
+  field = item->add_rm();
+  field->set_c(5);
+  field->add_rc(6);
+  field->add_rc(7);
+  field->add_rc(8);
+  item = msg1.add_item();
+  item->set_a(9);
+  field = item->add_rm();
+  field->set_c(10);
+  field->add_rc(11);
+  field->add_rc(12);
+  field = item->add_rm();
+  field->set_c(13);
+
+  item = msg2.add_item();
+  item->set_a(1);
+  field = item->add_rm();
+  field->set_c(5);
+  field->add_rc(8);
+  field->add_rc(8);
+  field->add_rc(6);
+  field = item->add_rm();
+  field->set_c(3);
+  field->add_rc(2);
+  field->add_rc(4);
+  item = msg2.add_item();
+  item->set_a(9);
+  field = item->add_rm();
+  field->set_c(10);
+  field->add_rc(12);
+  field->add_rc(11);
+  field = item->add_rm();
+  field->set_c(13);
+
+  EXPECT_EQ(
+      "matched: item[0].a : 1\n"
+      "matched: item[0].rm[1].c -> item[0].rm[0].c : 5\n"
+      "moved: item[0].rm[1].rc[0] -> item[0].rm[0].rc[2] : 6\n"
+      "moved: item[0].rm[1].rc[2] -> item[0].rm[0].rc[0] : 8\n"
+      "added: item[0].rm[0].rc[1]: 8\n"
+      "deleted: item[0].rm[1].rc[1]: 7\n"
+      "modified: item[0].rm[1] -> item[0].rm[0]: { c: 5 rc: 6 rc: 7 rc: 8 } ->"
+                                               " { c: 5 rc: 8 rc: 8 rc: 6 }\n"
+      "added: item[0].rm[1]: { c: 3 rc: 2 rc: 4 }\n"
+      "deleted: item[0].rm[0]: { c: 2 rc: 3 rc: 4 }\n"
+      "modified: item[0]: { a: 1 rm { c: 2 rc: 3 rc: 4 }"
+                               " rm { c: 5 rc: 6 rc: 7 rc: 8 } } ->"
+                        " { a: 1 rm { c: 5 rc: 8 rc: 8 rc: 6 }"
+                               " rm { c: 3 rc: 2 rc: 4 } }\n"
+      "matched: item[1].a : 9\n"
+      "matched: item[1].rm[0].c : 10\n"
+      "moved: item[1].rm[0].rc[0] -> item[1].rm[0].rc[1] : 11\n"
+      "moved: item[1].rm[0].rc[1] -> item[1].rm[0].rc[0] : 12\n"
+      "matched: item[1].rm[0] : { c: 10 rc: 11 rc: 12 }\n"
+      "matched: item[1].rm[1].c : 13\n"
+      "matched: item[1].rm[1] : { c: 13 }\n"
+      "matched: item[1] : { a: 9 rm { c: 10 rc: 11 rc: 12 } rm { c: 13 } }\n",
+      RunWithResult(&differencer, msg1, msg2, false));
+}
+
+TEST_F(MatchingTest, MatchingWorksWithExtensions) {
+  protobuf_unittest::TestAllExtensions msg1, msg2;
+  protobuf_unittest::TestAllTypes::NestedMessage* nested;
+  using protobuf_unittest::repeated_nested_message_extension;
+
+  const FileDescriptor* descriptor;
+  const FieldDescriptor* desc;
+  const FieldDescriptor* nested_key;
+  descriptor = msg1.GetDescriptor()->file();
+  desc = descriptor->FindExtensionByName("repeated_nested_message_extension");
+  ASSERT_FALSE(desc == NULL);
+  nested_key = desc->message_type()->FindFieldByName("bb");
+
+  MessageDifferencer differencer;
+  differencer.TreatAsMap(desc, nested_key);
+
+  nested = msg1.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(7);
+  nested = msg1.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(13);
+  nested = msg1.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(11);
+  nested = msg2.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(11);
+  nested = msg2.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(13);
+  nested = msg2.AddExtension(repeated_nested_message_extension);
+  nested->set_bb(7);
+
+  EXPECT_EQ(
+      "matched: (protobuf_unittest.repeated_nested_message_extension)[0].bb ->"
+              " (protobuf_unittest.repeated_nested_message_extension)[2].bb : 7\n"
+      "moved: (protobuf_unittest.repeated_nested_message_extension)[0] ->"
+            " (protobuf_unittest.repeated_nested_message_extension)[2] :"
+                " { bb: 7 }\n"
+      "matched: (protobuf_unittest.repeated_nested_message_extension)[1].bb :"
+                  " 13\n"
+      "matched: (protobuf_unittest.repeated_nested_message_extension)[1] :"
+                  " { bb: 13 }\n"
+      "matched: (protobuf_unittest.repeated_nested_message_extension)[2].bb ->"
+              " (protobuf_unittest.repeated_nested_message_extension)[0].bb :"
+                  " 11\n"
+      "moved: (protobuf_unittest.repeated_nested_message_extension)[2] ->"
+            " (protobuf_unittest.repeated_nested_message_extension)[0] :"
+                " { bb: 11 }\n",
+      RunWithResult(&differencer, msg1, msg2, true));
+}
+
+TEST(AnyTest, Simple) {
+  protobuf_unittest::TestField value1, value2;
+  value1.set_a(20);
+  value2.set_a(21);
+
+  protobuf_unittest::TestAny m1, m2;
+  m1.mutable_any_value()->PackFrom(value1);
+  m2.mutable_any_value()->PackFrom(value2);
+  util::MessageDifferencer message_differencer;
+  string difference_string;
+  message_differencer.ReportDifferencesToString(&difference_string);
+  EXPECT_FALSE(message_differencer.Compare(m1, m2));
+  EXPECT_EQ("modified: any_value.a: 20 -> 21\n", difference_string);
+}
+
+TEST(Anytest, TreatAsSet) {
+  protobuf_unittest::TestField value1, value2;
+  value1.set_a(20);
+  value1.set_b(30);
+  value2.set_a(20);
+  value2.set_b(31);
+
+  protobuf_unittest::TestAny m1, m2;
+  m1.add_repeated_any_value()->PackFrom(value1);
+  m1.add_repeated_any_value()->PackFrom(value2);
+  m2.add_repeated_any_value()->PackFrom(value2);
+  m2.add_repeated_any_value()->PackFrom(value1);
+
+  util::MessageDifferencer message_differencer;
+  message_differencer.TreatAsSet(GetFieldDescriptor(m1, "repeated_any_value"));
+  EXPECT_TRUE(message_differencer.Compare(m1, m2));
+}
+
+
+}  // namespace
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/message_differencer_unittest.proto b/src/google/protobuf/util/message_differencer_unittest.proto
new file mode 100644
index 0000000..698775f
--- /dev/null
+++ b/src/google/protobuf/util/message_differencer_unittest.proto
@@ -0,0 +1,74 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// This file contains messages for testing repeated field comparison
+
+syntax = "proto2";
+package protobuf_unittest;
+
+option optimize_for = SPEED;
+
+message TestField {
+  optional int32 a = 3;
+  optional int32 b = 4;
+  optional int32 c = 1;
+  repeated int32 rc = 2;
+  optional TestField m = 5;
+
+  extend TestDiffMessage {
+    optional TestField tf = 100;
+  }
+}
+
+message TestDiffMessage {
+  repeated group Item = 1 {
+    optional int32  a  =  2;     // Test basic repeated field comparison.
+    optional string b  =  4;     // Test basic repeated field comparison.
+    repeated int32  ra =  3;     // Test SetOfSet Comparison.
+    repeated string rb =  5;     // Test TreatAsMap when key is repeated
+    optional TestField m  = 6;   // Test TreatAsMap when key is a message
+    repeated TestField rm = 7;   // Test TreatAsMap when key is a repeated
+                                 // message
+  }
+
+  optional int32  v  = 13 [deprecated = true];
+  optional string w  = 14;
+  optional TestField m  = 15;
+  repeated int32  rv = 11;       // Test for combinations
+  repeated string rw = 10;       // Test for combinations
+  repeated TestField rm = 12 [deprecated = true];    // Test for combinations
+
+  extensions 100 to 199;
+}
+
diff --git a/src/google/protobuf/util/time_util.cc b/src/google/protobuf/util/time_util.cc
new file mode 100644
index 0000000..c782d69
--- /dev/null
+++ b/src/google/protobuf/util/time_util.cc
@@ -0,0 +1,525 @@
+// 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.
+
+#include <google/protobuf/util/time_util.h>
+
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/stubs/int128.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::Timestamp;
+using google::protobuf::Duration;
+
+namespace {
+static const int kNanosPerSecond = 1000000000;
+static const int kMicrosPerSecond = 1000000;
+static const int kMillisPerSecond = 1000;
+static const int kNanosPerMillisecond = 1000000;
+static const int kMicrosPerMillisecond = 1000;
+static const int kNanosPerMicrosecond = 1000;
+static const int kSecondsPerMinute = 60;  // Note that we ignore leap seconds.
+static const int kSecondsPerHour = 3600;
+static const char kTimestampFormat[] = "%E4Y-%m-%dT%H:%M:%S";
+
+template <typename T>
+T CreateNormalized(int64 seconds, int64 nanos);
+
+template <>
+Timestamp CreateNormalized(int64 seconds, int64 nanos) {
+  // Make sure nanos is in the range.
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    seconds += nanos / kNanosPerSecond;
+    nanos = nanos % kNanosPerSecond;
+  }
+  // For Timestamp nanos should be in the range [0, 999999999]
+  if (nanos < 0) {
+    seconds -= 1;
+    nanos += kNanosPerSecond;
+  }
+  GOOGLE_DCHECK(seconds >= TimeUtil::kTimestampMinSeconds &&
+         seconds <= TimeUtil::kTimestampMaxSeconds);
+  Timestamp result;
+  result.set_seconds(seconds);
+  result.set_nanos(static_cast<int32>(nanos));
+  return result;
+}
+
+template <>
+Duration CreateNormalized(int64 seconds, int64 nanos) {
+  // Make sure nanos is in the range.
+  if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
+    seconds += nanos / kNanosPerSecond;
+    nanos = nanos % kNanosPerSecond;
+  }
+  // nanos should have the same sign as seconds.
+  if (seconds < 0 && nanos > 0) {
+    seconds += 1;
+    nanos -= kNanosPerSecond;
+  } else if (seconds > 0 && nanos < 0) {
+    seconds -= 1;
+    nanos += kNanosPerSecond;
+  }
+  GOOGLE_DCHECK(seconds >= TimeUtil::kDurationMinSeconds &&
+         seconds <= TimeUtil::kDurationMaxSeconds);
+  Duration result;
+  result.set_seconds(seconds);
+  result.set_nanos(static_cast<int32>(nanos));
+  return result;
+}
+
+// Format nanoseconds with either 3, 6, or 9 digits depending on the required
+// precision to represent the exact value.
+string FormatNanos(int32 nanos) {
+  if (nanos % kNanosPerMillisecond == 0) {
+    return StringPrintf("%03d", nanos / kNanosPerMillisecond);
+  } else if (nanos % kNanosPerMicrosecond == 0) {
+    return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
+  } else {
+    return StringPrintf("%09d", nanos);
+  }
+}
+
+string FormatTime(int64 seconds, int32 nanos) {
+  return ::google::protobuf::internal::FormatTime(seconds, nanos);
+}
+
+bool ParseTime(const string& value, int64* seconds, int32* nanos) {
+  return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
+}
+
+void CurrentTime(int64* seconds, int32* nanos) {
+  return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
+}
+
+// Truncates the remainder part after division.
+int64 RoundTowardZero(int64 value, int64 divider) {
+  int64 result = value / divider;
+  int64 remainder = value % divider;
+  // Before C++11, the sign of the remainder is implementation dependent if
+  // any of the operands is negative. Here we try to enforce C++11's "rounded
+  // toward zero" semantics. For example, for (-5) / 2 an implementation may
+  // give -3 as the result with the remainder being 1. This function ensures
+  // we always return -2 (closer to zero) regardless of the implementation.
+  if (result < 0 && remainder > 0) {
+    return result + 1;
+  } else {
+    return result;
+  }
+}
+}  // namespace
+
+string TimeUtil::ToString(const Timestamp& timestamp) {
+  return FormatTime(timestamp.seconds(), timestamp.nanos());
+}
+
+bool TimeUtil::FromString(const string& value, Timestamp* timestamp) {
+  int64 seconds;
+  int32 nanos;
+  if (!ParseTime(value, &seconds, &nanos)) {
+    return false;
+  }
+  *timestamp = CreateNormalized<Timestamp>(seconds, nanos);
+  return true;
+}
+
+Timestamp TimeUtil::GetCurrentTime() {
+  int64 seconds;
+  int32 nanos;
+  CurrentTime(&seconds, &nanos);
+  return CreateNormalized<Timestamp>(seconds, nanos);
+}
+
+Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
+
+string TimeUtil::ToString(const Duration& duration) {
+  string result;
+  int64 seconds = duration.seconds();
+  int32 nanos = duration.nanos();
+  if (seconds < 0 || nanos < 0) {
+    result += "-";
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  result += StringPrintf("%" GOOGLE_LL_FORMAT "d", seconds);
+  if (nanos != 0) {
+    result += "." + FormatNanos(nanos);
+  }
+  result += "s";
+  return result;
+}
+
+static int64 Pow(int64 x, int y) {
+  int64 result = 1;
+  for (int i = 0; i < y; ++i) {
+    result *= x;
+  }
+  return result;
+}
+
+bool TimeUtil::FromString(const string& value, Duration* duration) {
+  if (value.length() <= 1 || value[value.length() - 1] != 's') {
+    return false;
+  }
+  bool negative = (value[0] == '-');
+  int sign_length = (negative ? 1 : 0);
+  // Parse the duration value as two integers rather than a float value
+  // to avoid precision loss.
+  string seconds_part, nanos_part;
+  size_t pos = value.find_last_of(".");
+  if (pos == string::npos) {
+    seconds_part = value.substr(sign_length, value.length() - 1 - sign_length);
+    nanos_part = "0";
+  } else {
+    seconds_part = value.substr(sign_length, pos - sign_length);
+    nanos_part = value.substr(pos + 1, value.length() - pos - 2);
+  }
+  char* end;
+  int64 seconds = strto64(seconds_part.c_str(), &end, 10);
+  if (end != seconds_part.c_str() + seconds_part.length()) {
+    return false;
+  }
+  int64 nanos = strto64(nanos_part.c_str(), &end, 10);
+  if (end != nanos_part.c_str() + nanos_part.length()) {
+    return false;
+  }
+  nanos = nanos * Pow(10, 9 - nanos_part.length());
+  if (negative) {
+    // If a Duration is negative, both seconds and nanos should be negative.
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  duration->set_seconds(seconds);
+  duration->set_nanos(static_cast<int32>(nanos));
+  return true;
+}
+
+Duration TimeUtil::NanosecondsToDuration(int64 nanos) {
+  return CreateNormalized<Duration>(nanos / kNanosPerSecond,
+                                    nanos % kNanosPerSecond);
+}
+
+Duration TimeUtil::MicrosecondsToDuration(int64 micros) {
+  return CreateNormalized<Duration>(
+      micros / kMicrosPerSecond,
+      (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
+}
+
+Duration TimeUtil::MillisecondsToDuration(int64 millis) {
+  return CreateNormalized<Duration>(
+      millis / kMillisPerSecond,
+      (millis % kMillisPerSecond) * kNanosPerMillisecond);
+}
+
+Duration TimeUtil::SecondsToDuration(int64 seconds) {
+  return CreateNormalized<Duration>(seconds, 0);
+}
+
+Duration TimeUtil::MinutesToDuration(int64 minutes) {
+  return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0);
+}
+
+Duration TimeUtil::HoursToDuration(int64 hours) {
+  return CreateNormalized<Duration>(hours * kSecondsPerHour, 0);
+}
+
+int64 TimeUtil::DurationToNanoseconds(const Duration& duration) {
+  return duration.seconds() * kNanosPerSecond + duration.nanos();
+}
+
+int64 TimeUtil::DurationToMicroseconds(const Duration& duration) {
+  return duration.seconds() * kMicrosPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMicrosecond);
+}
+
+int64 TimeUtil::DurationToMilliseconds(const Duration& duration) {
+  return duration.seconds() * kMillisPerSecond +
+         RoundTowardZero(duration.nanos(), kNanosPerMillisecond);
+}
+
+int64 TimeUtil::DurationToSeconds(const Duration& duration) {
+  return duration.seconds();
+}
+
+int64 TimeUtil::DurationToMinutes(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerMinute);
+}
+
+int64 TimeUtil::DurationToHours(const Duration& duration) {
+  return RoundTowardZero(duration.seconds(), kSecondsPerHour);
+}
+
+Timestamp TimeUtil::NanosecondsToTimestamp(int64 nanos) {
+  return CreateNormalized<Timestamp>(nanos / kNanosPerSecond,
+                                     nanos % kNanosPerSecond);
+}
+
+Timestamp TimeUtil::MicrosecondsToTimestamp(int64 micros) {
+  return CreateNormalized<Timestamp>(
+      micros / kMicrosPerSecond,
+      micros % kMicrosPerSecond * kNanosPerMicrosecond);
+}
+
+Timestamp TimeUtil::MillisecondsToTimestamp(int64 millis) {
+  return CreateNormalized<Timestamp>(
+      millis / kMillisPerSecond,
+      millis % kMillisPerSecond * kNanosPerMillisecond);
+}
+
+Timestamp TimeUtil::SecondsToTimestamp(int64 seconds) {
+  return CreateNormalized<Timestamp>(seconds, 0);
+}
+
+int64 TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
+}
+
+int64 TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMicrosPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond);
+}
+
+int64 TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
+  return timestamp.seconds() * kMillisPerSecond +
+         RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond);
+}
+
+int64 TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
+  return timestamp.seconds();
+}
+
+Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
+  return CreateNormalized<Timestamp>(static_cast<int64>(value), 0);
+}
+
+time_t TimeUtil::TimestampToTimeT(const Timestamp& value) {
+  return static_cast<time_t>(value.seconds());
+}
+
+Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) {
+  return CreateNormalized<Timestamp>(value.tv_sec,
+                                     value.tv_usec * kNanosPerMicrosecond);
+}
+
+timeval TimeUtil::TimestampToTimeval(const Timestamp& value) {
+  timeval result;
+  result.tv_sec = value.seconds();
+  result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
+  return result;
+}
+
+Duration TimeUtil::TimevalToDuration(const timeval& value) {
+  return CreateNormalized<Duration>(value.tv_sec,
+                                    value.tv_usec * kNanosPerMicrosecond);
+}
+
+timeval TimeUtil::DurationToTimeval(const Duration& value) {
+  timeval result;
+  result.tv_sec = value.seconds();
+  result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
+  // timeval.tv_usec's range is [0, 1000000)
+  if (result.tv_usec < 0) {
+    result.tv_sec -= 1;
+    result.tv_usec += kMicrosPerSecond;
+  }
+  return result;
+}
+
+}  // namespace util
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace {
+using google::protobuf::util::kNanosPerSecond;
+using google::protobuf::util::CreateNormalized;
+
+// Convert a Timestamp to uint128.
+void ToUint128(const Timestamp& value, uint128* result, bool* negative) {
+  if (value.seconds() < 0) {
+    *negative = true;
+    *result = static_cast<uint64>(-value.seconds());
+    *result = *result * kNanosPerSecond - static_cast<uint32>(value.nanos());
+  } else {
+    *negative = false;
+    *result = static_cast<uint64>(value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos());
+  }
+}
+
+// Convert a Duration to uint128.
+void ToUint128(const Duration& value, uint128* result, bool* negative) {
+  if (value.seconds() < 0 || value.nanos() < 0) {
+    *negative = true;
+    *result = static_cast<uint64>(-value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32>(-value.nanos());
+  } else {
+    *negative = false;
+    *result = static_cast<uint64>(value.seconds());
+    *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos());
+  }
+}
+
+void ToTimestamp(const uint128& value, bool negative, Timestamp* timestamp) {
+  int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond));
+  int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond));
+  if (negative) {
+    seconds = -seconds;
+    nanos = -nanos;
+    if (nanos < 0) {
+      nanos += kNanosPerSecond;
+      seconds -= 1;
+    }
+  }
+  timestamp->set_seconds(seconds);
+  timestamp->set_nanos(nanos);
+}
+
+void ToDuration(const uint128& value, bool negative, Duration* duration) {
+  int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond));
+  int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond));
+  if (negative) {
+    seconds = -seconds;
+    nanos = -nanos;
+  }
+  duration->set_seconds(seconds);
+  duration->set_nanos(nanos);
+}
+}  // namespace
+
+Duration& operator+=(Duration& d1, const Duration& d2) {
+  d1 = CreateNormalized<Duration>(d1.seconds() + d2.seconds(),
+                                  d1.nanos() + d2.nanos());
+  return d1;
+}
+
+Duration& operator-=(Duration& d1, const Duration& d2) {  // NOLINT
+  d1 = CreateNormalized<Duration>(d1.seconds() - d2.seconds(),
+                                  d1.nanos() - d2.nanos());
+  return d1;
+}
+
+Duration& operator*=(Duration& d, int64 r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value *= static_cast<uint64>(r);
+  } else {
+    negative = !negative;
+    value *= static_cast<uint64>(-r);
+  }
+  ToDuration(value, negative, &d);
+  return d;
+}
+
+Duration& operator*=(Duration& d, double r) {  // NOLINT
+  double result = (d.seconds() * 1.0 + 1.0 * d.nanos() / kNanosPerSecond) * r;
+  int64 seconds = static_cast<int64>(result);
+  int32 nanos = static_cast<int32>((result - seconds) * kNanosPerSecond);
+  // Note that we normalize here not just because nanos can have a different
+  // sign from seconds but also that nanos can be any arbitrary value when
+  // overflow happens (i.e., the result is a much larger value than what
+  // int64 can represent).
+  d = CreateNormalized<Duration>(seconds, nanos);
+  return d;
+}
+
+Duration& operator/=(Duration& d, int64 r) {  // NOLINT
+  bool negative;
+  uint128 value;
+  ToUint128(d, &value, &negative);
+  if (r > 0) {
+    value /= static_cast<uint64>(r);
+  } else {
+    negative = !negative;
+    value /= static_cast<uint64>(-r);
+  }
+  ToDuration(value, negative, &d);
+  return d;
+}
+
+Duration& operator/=(Duration& d, double r) {  // NOLINT
+  return d *= 1.0 / r;
+}
+
+Duration& operator%=(Duration& d1, const Duration& d2) {  // NOLINT
+  bool negative1, negative2;
+  uint128 value1, value2;
+  ToUint128(d1, &value1, &negative1);
+  ToUint128(d2, &value2, &negative2);
+  uint128 result = value1 % value2;
+  // When negative values are involved in division, we round the division
+  // result towards zero. With this semantics, sign of the remainder is the
+  // same as the dividend. For example:
+  //     -5 / 10    = 0, -5 % 10    = -5
+  //     -5 / (-10) = 0, -5 % (-10) = -5
+  //      5 / (-10) = 0,  5 % (-10) = 5
+  ToDuration(result, negative1, &d1);
+  return d1;
+}
+
+int64 operator/(const Duration& d1, const Duration& d2) {
+  bool negative1, negative2;
+  uint128 value1, value2;
+  ToUint128(d1, &value1, &negative1);
+  ToUint128(d2, &value2, &negative2);
+  int64 result = Uint128Low64(value1 / value2);
+  if (negative1 != negative2) {
+    result = -result;
+  }
+  return result;
+}
+
+Timestamp& operator+=(Timestamp& t, const Duration& d) {  // NOLINT
+  t = CreateNormalized<Timestamp>(t.seconds() + d.seconds(),
+                                  t.nanos() + d.nanos());
+  return t;
+}
+
+Timestamp& operator-=(Timestamp& t, const Duration& d) {  // NOLINT
+  t = CreateNormalized<Timestamp>(t.seconds() - d.seconds(),
+                                  t.nanos() - d.nanos());
+  return t;
+}
+
+Duration operator-(const Timestamp& t1, const Timestamp& t2) {
+  return CreateNormalized<Duration>(t1.seconds() - t2.seconds(),
+                                    t1.nanos() - t2.nanos());
+}
+}  // namespace protobuf
+
+}  // namespace google
diff --git a/src/google/protobuf/util/time_util.h b/src/google/protobuf/util/time_util.h
new file mode 100644
index 0000000..1bac089
--- /dev/null
+++ b/src/google/protobuf/util/time_util.h
@@ -0,0 +1,293 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
+
+#include <ctime>
+#include <ostream>
+#include <string>
+#ifdef _MSC_VER
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+class LIBPROTOBUF_EXPORT TimeUtil {
+  typedef google::protobuf::Timestamp Timestamp;
+  typedef google::protobuf::Duration Duration;
+
+ public:
+  // The min/max Timestamp/Duration values we support.
+  //
+  // For "0001-01-01T00:00:00Z".
+  static const int64 kTimestampMinSeconds = -62135596800LL;
+  // For "9999-12-31T23:59:59.999999999Z".
+  static const int64 kTimestampMaxSeconds = 253402300799LL;
+  static const int64 kDurationMinSeconds = -315576000000LL;
+  static const int64 kDurationMaxSeconds = 315576000000LL;
+
+  // Converts Timestamp to/from RFC 3339 date string format.
+  // Generated output will always be Z-normalized and uses 3, 6 or 9
+  // fractional digits as required to represent the exact time. When
+  // parsing, any fractional digits (or none) and any offset are
+  // accepted as long as they fit into nano-seconds precision.
+  // Note that Timestamp can only represent time from
+  // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. Converting
+  // a Timestamp outside of this range is undefined behavior.
+  // See https://www.ietf.org/rfc/rfc3339.txt
+  //
+  // Example of generated format:
+  //   "1972-01-01T10:00:20.021Z"
+  //
+  // Example of accepted format:
+  //   "1972-01-01T10:00:20.021-05:00"
+  static string ToString(const Timestamp& timestamp);
+  static bool FromString(const string& value, Timestamp* timestamp);
+
+  // Converts Duration to/from string format. The string format will contains
+  // 3, 6, or 9 fractional digits depending on the precision required to
+  // represent the exact Duration value. For example:
+  //   "1s", "1.010s", "1.000000100s", "-3.100s"
+  // The range that can be represented by Duration is from -315,576,000,000
+  // to +315,576,000,000 inclusive (in seconds).
+  static string ToString(const Duration& duration);
+  static bool FromString(const string& value, Duration* timestamp);
+
+#ifdef GetCurrentTime
+#undef GetCurrentTime  // Visual Studio has macro GetCurrentTime
+#endif
+  // Gets the current UTC time.
+  static Timestamp GetCurrentTime();
+  // Returns the Time representing "1970-01-01 00:00:00".
+  static Timestamp GetEpoch();
+
+  // Converts between Duration and integer types. The behavior is undefined if
+  // the input value is not in the valid range of Duration.
+  static Duration NanosecondsToDuration(int64 nanos);
+  static Duration MicrosecondsToDuration(int64 micros);
+  static Duration MillisecondsToDuration(int64 millis);
+  static Duration SecondsToDuration(int64 seconds);
+  static Duration MinutesToDuration(int64 minutes);
+  static Duration HoursToDuration(int64 hours);
+  // Result will be truncated towards zero. For example, "-1.5s" will be
+  // truncated to "-1s", and "1.5s" to "1s" when converting to seconds.
+  // It's undefined behavior if the input duration is not valid or the result
+  // exceeds the range of int64. A duration is not valid if it's not in the
+  // valid range of Duration, or have an invalid nanos value (i.e., larger
+  // than 999999999, less than -999999999, or have a different sign from the
+  // seconds part).
+  static int64 DurationToNanoseconds(const Duration& duration);
+  static int64 DurationToMicroseconds(const Duration& duration);
+  static int64 DurationToMilliseconds(const Duration& duration);
+  static int64 DurationToSeconds(const Duration& duration);
+  static int64 DurationToMinutes(const Duration& duration);
+  static int64 DurationToHours(const Duration& duration);
+  // Creates Timestamp from integer types. The integer value indicates the
+  // time elapsed from Epoch time. The behavior is undefined if the input
+  // value is not in the valid range of Timestamp.
+  static Timestamp NanosecondsToTimestamp(int64 nanos);
+  static Timestamp MicrosecondsToTimestamp(int64 micros);
+  static Timestamp MillisecondsToTimestamp(int64 millis);
+  static Timestamp SecondsToTimestamp(int64 seconds);
+  // Result will be truncated down to the nearest integer value. For example,
+  // with "1969-12-31T23:59:59.9Z", TimestampToMilliseconds() returns -100
+  // and TimestampToSeconds() returns -1. It's undefined behavior if the input
+  // Timestamp is not valid (i.e., its seconds part or nanos part does not fall
+  // in the valid range) or the return value doesn't fit into int64.
+  static int64 TimestampToNanoseconds(const Timestamp& timestamp);
+  static int64 TimestampToMicroseconds(const Timestamp& timestamp);
+  static int64 TimestampToMilliseconds(const Timestamp& timestamp);
+  static int64 TimestampToSeconds(const Timestamp& timestamp);
+
+  // Conversion to/from other time/date types. Note that these types may
+  // have a different precision and time range from Timestamp/Duration.
+  // When converting to a lower precision type, the value will be truncated
+  // to the nearest value that can be represented. If the value is
+  // out of the range of the result type, the return value is undefined.
+  //
+  // Conversion to/from time_t
+  static Timestamp TimeTToTimestamp(time_t value);
+  static time_t TimestampToTimeT(const Timestamp& value);
+
+  // Conversion to/from timeval
+  static Timestamp TimevalToTimestamp(const timeval& value);
+  static timeval TimestampToTimeval(const Timestamp& value);
+  static Duration TimevalToDuration(const timeval& value);
+  static timeval DurationToTimeval(const Duration& value);
+};
+
+}  // namespace util
+}  // namespace protobuf
+
+
+namespace protobuf {
+// Overloaded operators for Duration.
+//
+// Assignment operators.
+LIBPROTOBUF_EXPORT Duration& operator+=(Duration& d1, const Duration& d2);  // NOLINT
+LIBPROTOBUF_EXPORT Duration& operator-=(Duration& d1, const Duration& d2);  // NOLINT
+LIBPROTOBUF_EXPORT Duration& operator*=(Duration& d, int64 r);  // NOLINT
+LIBPROTOBUF_EXPORT Duration& operator*=(Duration& d, double r);  // NOLINT
+LIBPROTOBUF_EXPORT Duration& operator/=(Duration& d, int64 r);  // NOLINT
+LIBPROTOBUF_EXPORT Duration& operator/=(Duration& d, double r);  // NOLINT
+// Overload for other integer types.
+template <typename T>
+Duration& operator*=(Duration& d, T r) {  // NOLINT
+  int64 x = r;
+  return d *= x;
+}
+template <typename T>
+Duration& operator/=(Duration& d, T r) {  // NOLINT
+  int64 x = r;
+  return d /= x;
+}
+LIBPROTOBUF_EXPORT Duration& operator%=(Duration& d1, const Duration& d2);  // NOLINT
+// Relational operators.
+inline bool operator<(const Duration& d1, const Duration& d2) {
+  if (d1.seconds() == d2.seconds()) {
+    return d1.nanos() < d2.nanos();
+  }
+  return d1.seconds() < d2.seconds();
+}
+inline bool operator>(const Duration& d1, const Duration& d2) {
+  return d2 < d1;
+}
+inline bool operator>=(const Duration& d1, const Duration& d2) {
+  return !(d1 < d2);
+}
+inline bool operator<=(const Duration& d1, const Duration& d2) {
+  return !(d2 < d1);
+}
+inline bool operator==(const Duration& d1, const Duration& d2) {
+  return d1.seconds() == d2.seconds() && d1.nanos() == d2.nanos();
+}
+inline bool operator!=(const Duration& d1, const Duration& d2) {
+  return !(d1 == d2);
+}
+// Additive operators
+inline Duration operator-(const Duration& d) {
+  Duration result;
+  result.set_seconds(-d.seconds());
+  result.set_nanos(-d.nanos());
+  return result;
+}
+inline Duration operator+(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result += d2;
+}
+inline Duration operator-(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result -= d2;
+}
+// Multiplicative operators
+template<typename T>
+inline Duration operator*(Duration d, T r) {
+  return d *= r;
+}
+template<typename T>
+inline Duration operator*(T r, Duration d) {
+  return d *= r;
+}
+template<typename T>
+inline Duration operator/(Duration d, T r) {
+  return d /= r;
+}
+LIBPROTOBUF_EXPORT int64 operator/(const Duration& d1, const Duration& d2);
+
+inline Duration operator%(const Duration& d1, const Duration& d2) {
+  Duration result = d1;
+  return result %= d2;
+}
+
+inline ostream& operator<<(ostream& out, const Duration& d) {
+  out << google::protobuf::util::TimeUtil::ToString(d);
+  return out;
+}
+
+// Overloaded operators for Timestamp
+//
+// Assignement operators.
+LIBPROTOBUF_EXPORT Timestamp& operator+=(Timestamp& t, const Duration& d);  // NOLINT
+LIBPROTOBUF_EXPORT Timestamp& operator-=(Timestamp& t, const Duration& d);  // NOLINT
+// Relational operators.
+inline bool operator<(const Timestamp& t1, const Timestamp& t2) {
+  if (t1.seconds() == t2.seconds()) {
+    return t1.nanos() < t2.nanos();
+  }
+  return t1.seconds() < t2.seconds();
+}
+inline bool operator>(const Timestamp& t1, const Timestamp& t2) {
+  return t2 < t1;
+}
+inline bool operator>=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t1 < t2);
+}
+inline bool operator<=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t2 < t1);
+}
+inline bool operator==(const Timestamp& t1, const Timestamp& t2) {
+  return t1.seconds() == t2.seconds() && t1.nanos() == t2.nanos();
+}
+inline bool operator!=(const Timestamp& t1, const Timestamp& t2) {
+  return !(t1 == t2);
+}
+// Additive operators.
+inline Timestamp operator+(const Timestamp& t, const Duration& d) {
+  Timestamp result = t;
+  return result += d;
+}
+inline Timestamp operator+(const Duration& d, const Timestamp& t) {
+  Timestamp result = t;
+  return result += d;
+}
+inline Timestamp operator-(const Timestamp& t, const Duration& d) {
+  Timestamp result = t;
+  return result -= d;
+}
+LIBPROTOBUF_EXPORT Duration operator-(const Timestamp& t1, const Timestamp& t2);
+
+inline ostream& operator<<(ostream& out, const Timestamp& t) {
+  out << google::protobuf::util::TimeUtil::ToString(t);
+  return out;
+}
+
+}  // namespace protobuf
+
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__
diff --git a/src/google/protobuf/util/time_util_test.cc b/src/google/protobuf/util/time_util_test.cc
new file mode 100644
index 0000000..285740a
--- /dev/null
+++ b/src/google/protobuf/util/time_util_test.cc
@@ -0,0 +1,380 @@
+// 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.
+
+#include <google/protobuf/util/time_util.h>
+
+#include <ctime>
+
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+
+using google::protobuf::Timestamp;
+using google::protobuf::Duration;
+
+namespace {
+
+TEST(TimeUtilTest, TimestampStringFormat) {
+  Timestamp begin, end;
+  EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin));
+  EXPECT_EQ(TimeUtil::kTimestampMinSeconds, begin.seconds());
+  EXPECT_EQ(0, begin.nanos());
+  EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end));
+  EXPECT_EQ(TimeUtil::kTimestampMaxSeconds, end.seconds());
+  EXPECT_EQ(999999999, end.nanos());
+  EXPECT_EQ("0001-01-01T00:00:00Z", TimeUtil::ToString(begin));
+  EXPECT_EQ("9999-12-31T23:59:59.999999999Z", TimeUtil::ToString(end));
+
+  // Test negative timestamps.
+  Timestamp time = TimeUtil::NanosecondsToTimestamp(-1);
+  EXPECT_EQ(-1, time.seconds());
+  // Timestamp's nano part is always non-negative.
+  EXPECT_EQ(999999999, time.nanos());
+  EXPECT_EQ("1969-12-31T23:59:59.999999999Z", TimeUtil::ToString(time));
+
+  // Generated output should contain 3, 6, or 9 fractional digits.
+  EXPECT_EQ("1970-01-01T00:00:00Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(0)));
+  EXPECT_EQ("1970-01-01T00:00:00.010Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10000000)));
+  EXPECT_EQ("1970-01-01T00:00:00.000010Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10000)));
+  EXPECT_EQ("1970-01-01T00:00:00.000000010Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10)));
+
+  // Parsing accepts an fractional digits as long as they fit into nano
+  // precision.
+  EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.1Z", &time));
+  EXPECT_EQ(100000000, TimeUtil::TimestampToNanoseconds(time));
+  EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.0001Z", &time));
+  EXPECT_EQ(100000, TimeUtil::TimestampToNanoseconds(time));
+  EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.0000001Z", &time));
+  EXPECT_EQ(100, TimeUtil::TimestampToNanoseconds(time));
+
+  // Also accpets offsets.
+  EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00-08:00", &time));
+  EXPECT_EQ(8 * 3600, TimeUtil::TimestampToSeconds(time));
+}
+
+TEST(TimeUtilTest, DurationStringFormat) {
+  Timestamp begin, end;
+  EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin));
+  EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end));
+
+  EXPECT_EQ("315537897599.999999999s", TimeUtil::ToString(end - begin));
+  EXPECT_EQ(999999999, (end - begin).nanos());
+  EXPECT_EQ("-315537897599.999999999s", TimeUtil::ToString(begin - end));
+  EXPECT_EQ(-999999999, (begin - end).nanos());
+
+  // Generated output should contain 3, 6, or 9 fractional digits.
+  EXPECT_EQ("1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(1)));
+  EXPECT_EQ("0.010s", TimeUtil::ToString(TimeUtil::MillisecondsToDuration(10)));
+  EXPECT_EQ("0.000010s",
+            TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(10)));
+  EXPECT_EQ("0.000000010s",
+            TimeUtil::ToString(TimeUtil::NanosecondsToDuration(10)));
+
+  // Parsing accepts an fractional digits as long as they fit into nano
+  // precision.
+  Duration d;
+  EXPECT_TRUE(TimeUtil::FromString("0.1s", &d));
+  EXPECT_EQ(100, TimeUtil::DurationToMilliseconds(d));
+  EXPECT_TRUE(TimeUtil::FromString("0.0001s", &d));
+  EXPECT_EQ(100, TimeUtil::DurationToMicroseconds(d));
+  EXPECT_TRUE(TimeUtil::FromString("0.0000001s", &d));
+  EXPECT_EQ(100, TimeUtil::DurationToNanoseconds(d));
+
+  // Duration must support range from -315,576,000,000s to +315576000000s
+  // which includes negative values.
+  EXPECT_TRUE(TimeUtil::FromString("315576000000.999999999s", &d));
+  EXPECT_EQ(315576000000LL, d.seconds());
+  EXPECT_EQ(999999999, d.nanos());
+  EXPECT_TRUE(TimeUtil::FromString("-315576000000.999999999s", &d));
+  EXPECT_EQ(-315576000000LL, d.seconds());
+  EXPECT_EQ(-999999999, d.nanos());
+}
+
+TEST(TimeUtilTest, GetEpoch) {
+  EXPECT_EQ(0, TimeUtil::TimestampToNanoseconds(TimeUtil::GetEpoch()));
+}
+
+TEST(TimeUtilTest, DurationIntegerConversion) {
+  EXPECT_EQ("0.000000001s",
+            TimeUtil::ToString(TimeUtil::NanosecondsToDuration(1)));
+  EXPECT_EQ("-0.000000001s",
+            TimeUtil::ToString(TimeUtil::NanosecondsToDuration(-1)));
+  EXPECT_EQ("0.000001s",
+            TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(1)));
+  EXPECT_EQ("-0.000001s",
+            TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(-1)));
+  EXPECT_EQ("0.001s", TimeUtil::ToString(TimeUtil::MillisecondsToDuration(1)));
+  EXPECT_EQ("-0.001s",
+            TimeUtil::ToString(TimeUtil::MillisecondsToDuration(-1)));
+  EXPECT_EQ("1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(1)));
+  EXPECT_EQ("-1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(-1)));
+  EXPECT_EQ("60s", TimeUtil::ToString(TimeUtil::MinutesToDuration(1)));
+  EXPECT_EQ("-60s", TimeUtil::ToString(TimeUtil::MinutesToDuration(-1)));
+  EXPECT_EQ("3600s", TimeUtil::ToString(TimeUtil::HoursToDuration(1)));
+  EXPECT_EQ("-3600s", TimeUtil::ToString(TimeUtil::HoursToDuration(-1)));
+
+  EXPECT_EQ(
+      1, TimeUtil::DurationToNanoseconds(TimeUtil::NanosecondsToDuration(1)));
+  EXPECT_EQ(
+      -1, TimeUtil::DurationToNanoseconds(TimeUtil::NanosecondsToDuration(-1)));
+  EXPECT_EQ(
+      1, TimeUtil::DurationToMicroseconds(TimeUtil::MicrosecondsToDuration(1)));
+  EXPECT_EQ(-1, TimeUtil::DurationToMicroseconds(
+                    TimeUtil::MicrosecondsToDuration(-1)));
+  EXPECT_EQ(
+      1, TimeUtil::DurationToMilliseconds(TimeUtil::MillisecondsToDuration(1)));
+  EXPECT_EQ(-1, TimeUtil::DurationToMilliseconds(
+                    TimeUtil::MillisecondsToDuration(-1)));
+  EXPECT_EQ(1, TimeUtil::DurationToSeconds(TimeUtil::SecondsToDuration(1)));
+  EXPECT_EQ(-1, TimeUtil::DurationToSeconds(TimeUtil::SecondsToDuration(-1)));
+  EXPECT_EQ(1, TimeUtil::DurationToMinutes(TimeUtil::MinutesToDuration(1)));
+  EXPECT_EQ(-1, TimeUtil::DurationToMinutes(TimeUtil::MinutesToDuration(-1)));
+  EXPECT_EQ(1, TimeUtil::DurationToHours(TimeUtil::HoursToDuration(1)));
+  EXPECT_EQ(-1, TimeUtil::DurationToHours(TimeUtil::HoursToDuration(-1)));
+
+  // Test truncation behavior.
+  EXPECT_EQ(1, TimeUtil::DurationToMicroseconds(
+                   TimeUtil::NanosecondsToDuration(1999)));
+  // For negative values, Duration will be rounded towards 0.
+  EXPECT_EQ(-1, TimeUtil::DurationToMicroseconds(
+                    TimeUtil::NanosecondsToDuration(-1999)));
+}
+
+TEST(TestUtilTest, TimestampIntegerConversion) {
+  EXPECT_EQ("1970-01-01T00:00:00.000000001Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(1)));
+  EXPECT_EQ("1969-12-31T23:59:59.999999999Z",
+            TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(-1)));
+  EXPECT_EQ("1970-01-01T00:00:00.000001Z",
+            TimeUtil::ToString(TimeUtil::MicrosecondsToTimestamp(1)));
+  EXPECT_EQ("1969-12-31T23:59:59.999999Z",
+            TimeUtil::ToString(TimeUtil::MicrosecondsToTimestamp(-1)));
+  EXPECT_EQ("1970-01-01T00:00:00.001Z",
+            TimeUtil::ToString(TimeUtil::MillisecondsToTimestamp(1)));
+  EXPECT_EQ("1969-12-31T23:59:59.999Z",
+            TimeUtil::ToString(TimeUtil::MillisecondsToTimestamp(-1)));
+  EXPECT_EQ("1970-01-01T00:00:01Z",
+            TimeUtil::ToString(TimeUtil::SecondsToTimestamp(1)));
+  EXPECT_EQ("1969-12-31T23:59:59Z",
+            TimeUtil::ToString(TimeUtil::SecondsToTimestamp(-1)));
+
+  EXPECT_EQ(
+      1, TimeUtil::TimestampToNanoseconds(TimeUtil::NanosecondsToTimestamp(1)));
+  EXPECT_EQ(-1, TimeUtil::TimestampToNanoseconds(
+                    TimeUtil::NanosecondsToTimestamp(-1)));
+  EXPECT_EQ(1, TimeUtil::TimestampToMicroseconds(
+                   TimeUtil::MicrosecondsToTimestamp(1)));
+  EXPECT_EQ(-1, TimeUtil::TimestampToMicroseconds(
+                    TimeUtil::MicrosecondsToTimestamp(-1)));
+  EXPECT_EQ(1, TimeUtil::TimestampToMilliseconds(
+                   TimeUtil::MillisecondsToTimestamp(1)));
+  EXPECT_EQ(-1, TimeUtil::TimestampToMilliseconds(
+                    TimeUtil::MillisecondsToTimestamp(-1)));
+  EXPECT_EQ(1, TimeUtil::TimestampToSeconds(TimeUtil::SecondsToTimestamp(1)));
+  EXPECT_EQ(-1, TimeUtil::TimestampToSeconds(TimeUtil::SecondsToTimestamp(-1)));
+
+  // Test truncation behavior.
+  EXPECT_EQ(1, TimeUtil::TimestampToMicroseconds(
+                   TimeUtil::NanosecondsToTimestamp(1999)));
+  // For negative values, Timestamp will be rounded down.
+  // For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds
+  // will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than
+  // "1970-01-01T00:00:00Z" (i.e., 0s).
+  EXPECT_EQ(-2, TimeUtil::TimestampToMicroseconds(
+                    TimeUtil::NanosecondsToTimestamp(-1999)));
+}
+
+TEST(TimeUtilTest, TimeTConversion) {
+  time_t value = time(NULL);
+  EXPECT_EQ(value,
+            TimeUtil::TimestampToTimeT(TimeUtil::TimeTToTimestamp(value)));
+  EXPECT_EQ(
+      1, TimeUtil::TimestampToTimeT(TimeUtil::MillisecondsToTimestamp(1999)));
+}
+
+TEST(TimeUtilTest, TimevalConversion) {
+  timeval value = TimeUtil::TimestampToTimeval(
+      TimeUtil::NanosecondsToTimestamp(1999999999));
+  EXPECT_EQ(1, value.tv_sec);
+  EXPECT_EQ(999999, value.tv_usec);
+  value = TimeUtil::TimestampToTimeval(
+      TimeUtil::NanosecondsToTimestamp(-1999999999));
+  EXPECT_EQ(-2, value.tv_sec);
+  EXPECT_EQ(0, value.tv_usec);
+
+  value =
+      TimeUtil::DurationToTimeval(TimeUtil::NanosecondsToDuration(1999999999));
+  EXPECT_EQ(1, value.tv_sec);
+  EXPECT_EQ(999999, value.tv_usec);
+  value =
+      TimeUtil::DurationToTimeval(TimeUtil::NanosecondsToDuration(-1999999999));
+  EXPECT_EQ(-2, value.tv_sec);
+  EXPECT_EQ(1, value.tv_usec);
+}
+
+TEST(TimeUtilTest, DurationOperators) {
+  Duration one_second = TimeUtil::SecondsToDuration(1);
+  Duration one_nano = TimeUtil::NanosecondsToDuration(1);
+
+  // Test +/-
+  Duration a = one_second;
+  a += one_second;
+  a -= one_nano;
+  EXPECT_EQ("1.999999999s", TimeUtil::ToString(a));
+  Duration b = -a;
+  EXPECT_EQ("-1.999999999s", TimeUtil::ToString(b));
+  EXPECT_EQ("3.999999998s", TimeUtil::ToString(a + a));
+  EXPECT_EQ("0s", TimeUtil::ToString(a + b));
+  EXPECT_EQ("0s", TimeUtil::ToString(b + a));
+  EXPECT_EQ("-3.999999998s", TimeUtil::ToString(b + b));
+  EXPECT_EQ("3.999999998s", TimeUtil::ToString(a - b));
+  EXPECT_EQ("0s", TimeUtil::ToString(a - a));
+  EXPECT_EQ("0s", TimeUtil::ToString(b - b));
+  EXPECT_EQ("-3.999999998s", TimeUtil::ToString(b - a));
+
+  // Test *
+  EXPECT_EQ(a + a, a * 2);
+  EXPECT_EQ(b + b, a * (-2));
+  EXPECT_EQ(b + b, b * 2);
+  EXPECT_EQ(a + a, b * (-2));
+  EXPECT_EQ("0.999999999s", TimeUtil::ToString(a * 0.5));
+  EXPECT_EQ("-0.999999999s", TimeUtil::ToString(b * 0.5));
+  // Multiplication should not overflow if the result fits into the supported
+  // range of Duration (intermediate result may be larger than int64).
+  EXPECT_EQ("315575999684.424s",
+            TimeUtil::ToString((one_second - one_nano) * 315576000000LL));
+  EXPECT_EQ("-315575999684.424s",
+            TimeUtil::ToString((one_nano - one_second) * 315576000000LL));
+  EXPECT_EQ("-315575999684.424s",
+            TimeUtil::ToString((one_second - one_nano) * (-315576000000LL)));
+
+  // Test / and %
+  EXPECT_EQ("0.999999999s", TimeUtil::ToString(a / 2));
+  EXPECT_EQ("-0.999999999s", TimeUtil::ToString(b / 2));
+  Duration large = TimeUtil::SecondsToDuration(315576000000LL) - one_nano;
+  // We have to handle division with values beyond 64 bits.
+  EXPECT_EQ("0.999999999s", TimeUtil::ToString(large / 315576000000LL));
+  EXPECT_EQ("-0.999999999s", TimeUtil::ToString((-large) / 315576000000LL));
+  EXPECT_EQ("-0.999999999s", TimeUtil::ToString(large / (-315576000000LL)));
+  Duration large2 = large + one_nano;
+  EXPECT_EQ(large, large % large2);
+  EXPECT_EQ(-large, (-large) % large2);
+  EXPECT_EQ(large, large % (-large2));
+  EXPECT_EQ(one_nano, large2 % large);
+  EXPECT_EQ(-one_nano, (-large2) % large);
+  EXPECT_EQ(one_nano, large2 % (-large));
+  // Some corner cases about negative values.
+  //
+  // (-5) / 2 = -2, remainder = -1
+  // (-5) / (-2) = 2, remainder = -1
+  a = TimeUtil::NanosecondsToDuration(-5);
+  EXPECT_EQ(TimeUtil::NanosecondsToDuration(-2), a / 2);
+  EXPECT_EQ(TimeUtil::NanosecondsToDuration(2), a / (-2));
+  b = TimeUtil::NanosecondsToDuration(2);
+  EXPECT_EQ(-2, a / b);
+  EXPECT_EQ(TimeUtil::NanosecondsToDuration(-1), a % b);
+  EXPECT_EQ(2, a / (-b));
+  EXPECT_EQ(TimeUtil::NanosecondsToDuration(-1), a % (-b));
+
+  // Test relational operators.
+  EXPECT_TRUE(one_nano < one_second);
+  EXPECT_FALSE(one_second < one_second);
+  EXPECT_FALSE(one_second < one_nano);
+  EXPECT_FALSE(-one_nano < -one_second);
+  EXPECT_FALSE(-one_second < -one_second);
+  EXPECT_TRUE(-one_second < -one_nano);
+  EXPECT_TRUE(-one_nano < one_nano);
+  EXPECT_FALSE(one_nano < -one_nano);
+
+  EXPECT_FALSE(one_nano > one_second);
+  EXPECT_FALSE(one_nano > one_nano);
+  EXPECT_TRUE(one_second > one_nano);
+
+  EXPECT_FALSE(one_nano >= one_second);
+  EXPECT_TRUE(one_nano >= one_nano);
+  EXPECT_TRUE(one_second >= one_nano);
+
+  EXPECT_TRUE(one_nano <= one_second);
+  EXPECT_TRUE(one_nano <= one_nano);
+  EXPECT_FALSE(one_second <= one_nano);
+
+  EXPECT_TRUE(one_nano == one_nano);
+  EXPECT_FALSE(one_nano == one_second);
+
+  EXPECT_FALSE(one_nano != one_nano);
+  EXPECT_TRUE(one_nano != one_second);
+}
+
+TEST(TimeUtilTest, TimestampOperators) {
+  Timestamp begin, end;
+  EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin));
+  EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end));
+  Duration d = end - begin;
+  EXPECT_TRUE(end == begin + d);
+  EXPECT_TRUE(end == d + begin);
+  EXPECT_TRUE(begin == end - d);
+
+  // Test relational operators
+  Timestamp t1 = begin + d / 4;
+  Timestamp t2 = end - d / 4;
+  EXPECT_TRUE(t1 < t2);
+  EXPECT_FALSE(t1 < t1);
+  EXPECT_FALSE(t2 < t1);
+  EXPECT_FALSE(t1 > t2);
+  EXPECT_FALSE(t1 > t1);
+  EXPECT_TRUE(t2 > t1);
+  EXPECT_FALSE(t1 >= t2);
+  EXPECT_TRUE(t1 >= t1);
+  EXPECT_TRUE(t2 >= t1);
+  EXPECT_TRUE(t1 <= t2);
+  EXPECT_TRUE(t1 <= t1);
+  EXPECT_FALSE(t2 <= t1);
+
+  EXPECT_FALSE(t1 == t2);
+  EXPECT_TRUE(t1 == t1);
+  EXPECT_FALSE(t2 == t1);
+  EXPECT_TRUE(t1 != t2);
+  EXPECT_FALSE(t1 != t1);
+  EXPECT_TRUE(t2 != t1);
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/type_resolver.h b/src/google/protobuf/util/type_resolver.h
new file mode 100644
index 0000000..77d4416
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
+#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/status.h>
+
+
+namespace google {
+namespace protobuf {
+class Type;
+class Enum;
+}  // namespace protobuf
+
+
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+
+// Abstract interface for a type resovler.
+//
+// Implementations of this interface must be thread-safe.
+class LIBPROTOBUF_EXPORT TypeResolver {
+ public:
+  TypeResolver() {}
+  virtual ~TypeResolver() {}
+
+  // Resolves a type url for a message type.
+  virtual util::Status ResolveMessageType(
+      const string& type_url, google::protobuf::Type* message_type) = 0;
+
+  // Resolves a type url for an enum type.
+  virtual util::Status ResolveEnumType(const string& type_url,
+                                         google::protobuf::Enum* enum_type) = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeResolver);
+};
+
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_H__
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
new file mode 100644
index 0000000..9639390
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -0,0 +1,259 @@
+// 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.
+
+#include <google/protobuf/util/type_resolver_util.h>
+
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/status.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+using google::protobuf::BoolValue;
+using google::protobuf::Enum;
+using google::protobuf::EnumValue;
+using google::protobuf::Field;
+using google::protobuf::Option;
+using google::protobuf::Type;
+
+using util::Status;
+using util::error::INVALID_ARGUMENT;
+using util::error::NOT_FOUND;
+
+bool SplitTypeUrl(const string& type_url, string* url_prefix,
+                  string* message_name) {
+  size_t pos = type_url.find_last_of("/");
+  if (pos == string::npos) {
+    return false;
+  }
+  *url_prefix = type_url.substr(0, pos);
+  *message_name = type_url.substr(pos + 1);
+  return true;
+}
+
+class DescriptorPoolTypeResolver : public TypeResolver {
+ public:
+  DescriptorPoolTypeResolver(const string& url_prefix,
+                             const DescriptorPool* pool)
+      : url_prefix_(url_prefix), pool_(pool) {}
+
+  Status ResolveMessageType(const string& type_url, Type* type) {
+    string url_prefix, message_name;
+    if (!SplitTypeUrl(type_url, &url_prefix, &message_name) ||
+        url_prefix != url_prefix_) {
+      return Status(INVALID_ARGUMENT,
+                    StrCat("Invalid type URL, type URLs must be of the form '",
+                           url_prefix_, "/<typename>', got: ", type_url));
+    }
+    if (url_prefix != url_prefix_) {
+      return Status(INVALID_ARGUMENT,
+                    "Cannot resolve types from URL: " + url_prefix);
+    }
+    const Descriptor* descriptor = pool_->FindMessageTypeByName(message_name);
+    if (descriptor == NULL) {
+      return Status(NOT_FOUND,
+                    "Invalid type URL, unknown type: " + message_name);
+    }
+    ConvertDescriptor(descriptor, type);
+    return Status();
+  }
+
+  Status ResolveEnumType(const string& type_url, Enum* enum_type) {
+    string url_prefix, type_name;
+    if (!SplitTypeUrl(type_url, &url_prefix, &type_name) ||
+        url_prefix != url_prefix_) {
+      return Status(INVALID_ARGUMENT,
+                    StrCat("Invalid type URL, type URLs must be of the form '",
+                           url_prefix_, "/<typename>', got: ", type_url));
+    }
+    if (url_prefix != url_prefix_) {
+      return Status(INVALID_ARGUMENT,
+                    "Cannot resolve types from URL: " + url_prefix);
+    }
+    const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
+    if (descriptor == NULL) {
+      return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
+    }
+    ConvertEnumDescriptor(descriptor, enum_type);
+    return Status();
+  }
+
+ private:
+  void ConvertDescriptor(const Descriptor* descriptor, Type* type) {
+    type->Clear();
+    type->set_name(descriptor->full_name());
+    for (int i = 0; i < descriptor->field_count(); ++i) {
+      const FieldDescriptor* field = descriptor->field(i);
+      if (field->type() == FieldDescriptor::TYPE_GROUP) {
+        // Group fields cannot be represented with Type. We discard them.
+        continue;
+      }
+      ConvertFieldDescriptor(descriptor->field(i), type->add_fields());
+    }
+    for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
+      type->add_oneofs(descriptor->oneof_decl(i)->name());
+    }
+    type->mutable_source_context()->set_file_name(descriptor->file()->name());
+    ConvertMessageOptions(descriptor->options(), type->mutable_options());
+  }
+
+  void ConvertMessageOptions(const MessageOptions& options,
+                             RepeatedPtrField<Option>* output) {
+    if (options.map_entry()) {
+      Option* option = output->Add();
+      option->set_name("map_entry");
+      BoolValue value;
+      value.set_value(true);
+      option->mutable_value()->PackFrom(value);
+    }
+
+    // TODO(xiaofeng): Set other "options"?
+  }
+
+  void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
+    field->set_kind(static_cast<Field::Kind>(descriptor->type()));
+    switch (descriptor->label()) {
+      case FieldDescriptor::LABEL_OPTIONAL:
+        field->set_cardinality(Field::CARDINALITY_OPTIONAL);
+        break;
+      case FieldDescriptor::LABEL_REPEATED:
+        field->set_cardinality(Field::CARDINALITY_REPEATED);
+        break;
+      case FieldDescriptor::LABEL_REQUIRED:
+        field->set_cardinality(Field::CARDINALITY_REQUIRED);
+        break;
+    }
+    field->set_number(descriptor->number());
+    field->set_name(descriptor->name());
+    field->set_json_name(descriptor->json_name());
+    if (descriptor->has_default_value()) {
+      field->set_default_value(DefaultValueAsString(descriptor));
+    }
+    if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
+      field->set_type_url(GetTypeUrl(descriptor->message_type()));
+    } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
+      field->set_type_url(GetTypeUrl(descriptor->enum_type()));
+    }
+    if (descriptor->containing_oneof() != NULL) {
+      field->set_oneof_index(descriptor->containing_oneof()->index() + 1);
+    }
+    if (descriptor->is_packed()) {
+      field->set_packed(true);
+    }
+
+    // TODO(xiaofeng): Set other field "options"?
+  }
+
+  void ConvertEnumDescriptor(const EnumDescriptor* descriptor,
+                             Enum* enum_type) {
+    enum_type->Clear();
+    enum_type->set_name(descriptor->full_name());
+    enum_type->mutable_source_context()->set_file_name(
+        descriptor->file()->name());
+    for (int i = 0; i < descriptor->value_count(); ++i) {
+      const EnumValueDescriptor* value_descriptor = descriptor->value(i);
+      EnumValue* value = enum_type->mutable_enumvalue()->Add();
+      value->set_name(value_descriptor->name());
+      value->set_number(value_descriptor->number());
+
+      // TODO(xiaofeng): Set EnumValue options.
+    }
+    // TODO(xiaofeng): Set Enum "options".
+  }
+
+  string GetTypeUrl(const Descriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  string GetTypeUrl(const EnumDescriptor* descriptor) {
+    return url_prefix_ + "/" + descriptor->full_name();
+  }
+
+  string DefaultValueAsString(const FieldDescriptor* descriptor) {
+    switch (descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        return SimpleItoa(descriptor->default_value_int32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return SimpleItoa(descriptor->default_value_int64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return SimpleItoa(descriptor->default_value_uint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return SimpleItoa(descriptor->default_value_uint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        return SimpleFtoa(descriptor->default_value_float());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        return SimpleDtoa(descriptor->default_value_double());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return descriptor->default_value_bool() ? "true" : "false";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+          return CEscape(descriptor->default_value_string());
+        } else {
+          return descriptor->default_value_string();
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return descriptor->default_value_enum()->name();
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+        break;
+    }
+    return "";
+  }
+
+  string url_prefix_;
+  const DescriptorPool* pool_;
+};
+
+}  // namespace
+
+TypeResolver* NewTypeResolverForDescriptorPool(const string& url_prefix,
+                                               const DescriptorPool* pool) {
+  return new DescriptorPoolTypeResolver(url_prefix, pool);
+}
+
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/type_resolver_util.h b/src/google/protobuf/util/type_resolver_util.h
new file mode 100644
index 0000000..c0ef3c1
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util.h
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+namespace google {
+namespace protobuf {
+class DescriptorPool;
+namespace util {
+class TypeResolver;
+
+// Creates a TypeResolver that serves type information in the given descriptor
+// pool. Caller takes ownership of the returned TypeResolver.
+LIBPROTOBUF_EXPORT TypeResolver* NewTypeResolverForDescriptorPool(
+    const string& url_prefix, const DescriptorPool* pool);
+
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
new file mode 100644
index 0000000..8a0bf65
--- /dev/null
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -0,0 +1,352 @@
+// 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.
+
+#include <google/protobuf/util/type_resolver_util.h>
+
+#include <limits>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <vector>
+
+#include <google/protobuf/type.pb.h>
+#include <google/protobuf/wrappers.pb.h>
+#include <google/protobuf/map_unittest.pb.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/util/json_format_proto3.pb.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace {
+using google::protobuf::Type;
+using google::protobuf::Enum;
+using google::protobuf::Field;
+using google::protobuf::Option;
+using google::protobuf::BoolValue;
+
+static const char kUrlPrefix[] = "type.googleapis.com";
+
+class DescriptorPoolTypeResolverTest : public testing::Test {
+ public:
+  DescriptorPoolTypeResolverTest() {
+    resolver_.reset(NewTypeResolverForDescriptorPool(
+        kUrlPrefix, DescriptorPool::generated_pool()));
+  }
+
+  const Field* FindField(const Type& type, const string& name) {
+    for (int i = 0; i < type.fields_size(); ++i) {
+      const Field& field = type.fields(i);
+      if (field.name() == name) {
+        return &field;
+      }
+    }
+    return NULL;
+  }
+
+  bool HasField(const Type& type, const string& name) {
+    return FindField(type, name) != NULL;
+  }
+
+  bool HasField(const Type& type, Field::Cardinality cardinality,
+                Field::Kind kind, const string& name, int number) {
+    const Field* field = FindField(type, name);
+    if (field == NULL) {
+      return false;
+    }
+    return field->cardinality() == cardinality &&
+        field->kind() == kind && field->number() == number;
+  }
+
+  bool CheckFieldTypeUrl(const Type& type, const string& name,
+                         const string& type_url) {
+    const Field* field = FindField(type, name);
+    if (field == NULL) {
+      return false;
+    }
+    return field->type_url() == type_url;
+  }
+
+  bool FieldInOneof(const Type& type, const string& name,
+                    const string& oneof_name) {
+    const Field* field = FindField(type, name);
+    if (field == NULL || field->oneof_index() <= 0 ||
+        field->oneof_index() > type.oneofs_size()) {
+      return false;
+    }
+    return type.oneofs(field->oneof_index() - 1) == oneof_name;
+  }
+
+  bool IsPacked(const Type& type, const string& name) {
+    const Field* field = FindField(type, name);
+    if (field == NULL) {
+      return false;
+    }
+    return field->packed();
+  }
+
+  bool EnumHasValue(const Enum& type, const string& name, int number) {
+    for (int i = 0; i < type.enumvalue_size(); ++i) {
+      if (type.enumvalue(i).name() == name &&
+          type.enumvalue(i).number() == number) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool HasBoolOption(const RepeatedPtrField<Option>& options,
+                     const string& name, bool value) {
+    for (int i = 0; i < options.size(); ++i) {
+      const Option& option = options.Get(i);
+      if (option.name() == name) {
+        BoolValue bool_value;
+        if (option.value().UnpackTo(&bool_value) &&
+            bool_value.value() == value) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  string GetTypeUrl(string full_name) {
+    return kUrlPrefix + string("/") + full_name;
+  }
+
+  template<typename T>
+  string GetTypeUrl() {
+    return GetTypeUrl(T::descriptor()->full_name());
+  }
+
+ protected:
+  google::protobuf::scoped_ptr<TypeResolver> resolver_;
+};
+
+TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+      GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type).ok());
+  // Check all optional fields.
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_INT32, "optional_int32", 1));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_INT64, "optional_int64", 2));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_UINT32, "optional_uint32", 3));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_UINT64, "optional_uint64", 4));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_SINT32, "optional_sint32", 5));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_SINT64, "optional_sint64", 6));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_FIXED32, "optional_fixed32", 7));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_FIXED64, "optional_fixed64", 8));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_SFIXED32, "optional_sfixed32", 9));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_SFIXED64, "optional_sfixed64", 10));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_FLOAT, "optional_float", 11));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_DOUBLE, "optional_double", 12));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_BOOL, "optional_bool", 13));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_STRING, "optional_string", 14));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_BYTES, "optional_bytes", 15));
+
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_MESSAGE, "optional_nested_message", 18));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_MESSAGE, "optional_foreign_message", 19));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "optional_nested_message",
+      GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>()));
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "optional_foreign_message",
+      GetTypeUrl<protobuf_unittest::ForeignMessage>()));
+
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_ENUM, "optional_nested_enum", 21));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_ENUM, "optional_foreign_enum", 22));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "optional_nested_enum",
+      GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum")));
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "optional_foreign_enum",
+      GetTypeUrl("protobuf_unittest.ForeignEnum")));
+
+  // Check all repeated fields.
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_INT32, "repeated_int32", 31));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_INT64, "repeated_int64", 32));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_UINT32, "repeated_uint32", 33));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_UINT64, "repeated_uint64", 34));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_SINT32, "repeated_sint32", 35));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_SINT64, "repeated_sint64", 36));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_FIXED32, "repeated_fixed32", 37));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_FIXED64, "repeated_fixed64", 38));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_SFIXED32, "repeated_sfixed32", 39));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_SFIXED64, "repeated_sfixed64", 40));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_FLOAT, "repeated_float", 41));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_DOUBLE, "repeated_double", 42));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_BOOL, "repeated_bool", 43));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_STRING, "repeated_string", 44));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_BYTES, "repeated_bytes", 45));
+
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_MESSAGE, "repeated_nested_message", 48));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_MESSAGE, "repeated_foreign_message", 49));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "repeated_nested_message",
+      GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>()));
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "repeated_foreign_message",
+      GetTypeUrl<protobuf_unittest::ForeignMessage>()));
+
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_ENUM, "repeated_nested_enum", 51));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_ENUM, "repeated_foreign_enum", 52));
+
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "repeated_nested_enum",
+      GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum")));
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "repeated_foreign_enum",
+      GetTypeUrl("protobuf_unittest.ForeignEnum")));
+
+  // Groups are discarded when converting to Type.
+  const Descriptor* descriptor = protobuf_unittest::TestAllTypes::descriptor();
+  EXPECT_TRUE(descriptor->FindFieldByName("optionalgroup") != NULL);
+  EXPECT_TRUE(descriptor->FindFieldByName("repeatedgroup") != NULL);
+  ASSERT_FALSE(HasField(type, "optionalgroup"));
+  ASSERT_FALSE(HasField(type, "repeatedgroup"));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestPackedField) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+      GetTypeUrl<protobuf_unittest::TestPackedTypes>(), &type).ok());
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_INT32, "packed_int32", 90));
+  EXPECT_TRUE(IsPacked(type, "packed_int32"));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestOneof) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+      GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type).ok());
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_UINT32, "oneof_uint32", 111));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_MESSAGE, "oneof_nested_message", 112));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_STRING, "oneof_string", 113));
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL,
+                       Field::TYPE_BYTES, "oneof_bytes", 114));
+  EXPECT_TRUE(FieldInOneof(type, "oneof_uint32", "oneof_field"));
+  EXPECT_TRUE(FieldInOneof(type, "oneof_nested_message", "oneof_field"));
+  EXPECT_TRUE(FieldInOneof(type, "oneof_string", "oneof_field"));
+  EXPECT_TRUE(FieldInOneof(type, "oneof_bytes", "oneof_field"));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestMap) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+      GetTypeUrl<protobuf_unittest::TestMap>(), &type).ok());
+  EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED,
+                       Field::TYPE_MESSAGE, "map_int32_int32", 1));
+  EXPECT_TRUE(CheckFieldTypeUrl(
+      type, "map_int32_int32",
+      GetTypeUrl("protobuf_unittest.TestMap.MapInt32Int32Entry")));
+
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+      GetTypeUrl("protobuf_unittest.TestMap.MapInt32Int32Entry"),
+      &type).ok());
+  EXPECT_TRUE(HasBoolOption(type.options(), "map_entry", true));
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestEnum) {
+  Enum type;
+  ASSERT_TRUE(resolver_->ResolveEnumType(
+      GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum"), &type).ok());
+  EnumHasValue(type, "FOO", 1);
+  EnumHasValue(type, "BAR", 2);
+  EnumHasValue(type, "BAZ", 3);
+  EnumHasValue(type, "NEG", -1);
+}
+
+TEST_F(DescriptorPoolTypeResolverTest, TestJsonName) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+                           GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type)
+                  .ok());
+  EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name());
+
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+                           GetTypeUrl<proto3::TestCustomJsonName>(), &type)
+                  .ok());
+  EXPECT_EQ("@value", FindField(type, "value")->json_name());
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/well_known_types_unittest.cc b/src/google/protobuf/well_known_types_unittest.cc
new file mode 100644
index 0000000..c9a9aa1
--- /dev/null
+++ b/src/google/protobuf/well_known_types_unittest.cc
@@ -0,0 +1,60 @@
+// 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.
+#include <google/protobuf/unittest_well_known_types.pb.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/stl_util.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+// This test only checks whether well-known types are included in protobuf
+// runtime library. The test passes if it compiles.
+TEST(WellKnownTypesTest, AllKnownTypesAreIncluded) {
+  protobuf_unittest::TestWellKnownTypes message;
+  EXPECT_EQ(0, message.any_field().ByteSize());
+  EXPECT_EQ(0, message.api_field().ByteSize());
+  EXPECT_EQ(0, message.duration_field().ByteSize());
+  EXPECT_EQ(0, message.empty_field().ByteSize());
+  EXPECT_EQ(0, message.field_mask_field().ByteSize());
+  EXPECT_EQ(0, message.source_context_field().ByteSize());
+  EXPECT_EQ(0, message.struct_field().ByteSize());
+  EXPECT_EQ(0, message.timestamp_field().ByteSize());
+  EXPECT_EQ(0, message.type_field().ByteSize());
+  EXPECT_EQ(0, message.int32_field().ByteSize());
+}
+
+}  // namespace
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 6bdfcd6..5ee4e25 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -38,6 +38,7 @@
 
 #include <google/protobuf/wire_format.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/descriptor.h>
@@ -54,15 +55,6 @@
 namespace protobuf {
 namespace internal {
 
-namespace {
-
-// This function turns out to be convenient when using some macros later.
-inline int GetEnumNumber(const EnumValueDescriptor* descriptor) {
-  return descriptor->number();
-}
-
-}  // anonymous namespace
-
 // ===================================================================
 
 bool UnknownFieldSetFieldSkipper::SkipField(
@@ -141,7 +133,7 @@
 
 bool WireFormat::SkipMessage(io::CodedInputStream* input,
                              UnknownFieldSet* unknown_fields) {
-  while(true) {
+  while (true) {
     uint32 tag = input->ReadTag();
     if (tag == 0) {
       // End of input.  This is a valid place to end, so return true.
@@ -159,6 +151,31 @@
   }
 }
 
+bool WireFormat::ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                                uint32 field_number,
+                                                bool (*is_valid)(int),
+                                                UnknownFieldSet* unknown_fields,
+                                                RepeatedField<int>* values) {
+  uint32 length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
+        int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+      return false;
+    }
+    if (is_valid == NULL || is_valid(value)) {
+      values->Add(value);
+    } else {
+      unknown_fields->AddVarint(field_number, value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
+
 void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
                                         io::CodedOutputStream* output) {
   for (int i = 0; i < unknown_fields.field_count(); i++) {
@@ -444,6 +461,10 @@
   }
 }
 
+static bool StrictUtf8Check(const FieldDescriptor* field) {
+  return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
 bool WireFormat::ParseAndMergeField(
     uint32 tag,
     const FieldDescriptor* field,        // May be NULL for unknown
@@ -512,10 +533,23 @@
           int value;
           if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
                   input, &value)) return false;
-          const EnumValueDescriptor* enum_value =
-              field->enum_type()->FindValueByNumber(value);
-          if (enum_value != NULL) {
-            message_reflection->AddEnum(message, field, enum_value);
+          if (message->GetDescriptor()->file()->syntax() ==
+              FileDescriptor::SYNTAX_PROTO3) {
+            message_reflection->AddEnumValue(message, field, value);
+          } else {
+            const EnumValueDescriptor* enum_value =
+                field->enum_type()->FindValueByNumber(value);
+            if (enum_value != NULL) {
+              message_reflection->AddEnum(message, field, enum_value);
+            } else {
+              // The enum value is not one of the known values.  Add it to the
+              // UnknownFieldSet.
+              int64 sign_extended_value = static_cast<int64>(value);
+              message_reflection->MutableUnknownFields(message)
+                  ->AddVarint(
+                      WireFormatLite::GetTagFieldNumber(tag),
+                      sign_extended_value);
+            }
           }
         }
 
@@ -572,31 +606,50 @@
         int value;
         if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
                 input, &value)) return false;
-        const EnumValueDescriptor* enum_value =
-          field->enum_type()->FindValueByNumber(value);
-        if (enum_value != NULL) {
+        if (message->GetDescriptor()->file()->syntax() ==
+            FileDescriptor::SYNTAX_PROTO3) {
           if (field->is_repeated()) {
-            message_reflection->AddEnum(message, field, enum_value);
+            message_reflection->AddEnumValue(message, field, value);
           } else {
-            message_reflection->SetEnum(message, field, enum_value);
+            message_reflection->SetEnumValue(message, field, value);
           }
         } else {
-          // The enum value is not one of the known values.  Add it to the
-          // UnknownFieldSet.
-          int64 sign_extended_value = static_cast<int64>(value);
-          message_reflection->MutableUnknownFields(message)
-                            ->AddVarint(WireFormatLite::GetTagFieldNumber(tag),
-                                        sign_extended_value);
+          const EnumValueDescriptor* enum_value =
+              field->enum_type()->FindValueByNumber(value);
+          if (enum_value != NULL) {
+            if (field->is_repeated()) {
+              message_reflection->AddEnum(message, field, enum_value);
+            } else {
+              message_reflection->SetEnum(message, field, enum_value);
+            }
+          } else {
+            // The enum value is not one of the known values.  Add it to the
+            // UnknownFieldSet.
+            int64 sign_extended_value = static_cast<int64>(value);
+            message_reflection->MutableUnknownFields(message)
+                              ->AddVarint(
+                                  WireFormatLite::GetTagFieldNumber(tag),
+                                  sign_extended_value);
+          }
         }
         break;
       }
 
       // Handle strings separately so that we can optimize the ctype=CORD case.
       case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
         string value;
         if (!WireFormatLite::ReadString(input, &value)) return false;
-        VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
-                                   field->name().c_str());
+        if (strict_utf8_check) {
+          if (!WireFormatLite::VerifyUtf8String(
+                  value.data(), value.length(), WireFormatLite::PARSE,
+                  field->full_name().c_str())) {
+            return false;
+          }
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), PARSE,
+                                     field->full_name().c_str());
+        }
         if (field->is_repeated()) {
           message_reflection->AddString(message, field, value);
         } else {
@@ -781,7 +834,7 @@
     count = 1;
   }
 
-  const bool is_packed = field->options().packed();
+  const bool is_packed = field->is_packed();
   if (is_packed && count > 0) {
     WireFormatLite::WriteTag(field->number(),
         WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
@@ -854,13 +907,20 @@
       // Handle strings separately so that we can get string references
       // instead of copying.
       case FieldDescriptor::TYPE_STRING: {
+        bool strict_utf8_check = StrictUtf8Check(field);
         string scratch;
         const string& value = field->is_repeated() ?
           message_reflection->GetRepeatedStringReference(
             message, field, j, &scratch) :
           message_reflection->GetStringReference(message, field, &scratch);
-        VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
-                                   field->name().c_str());
+        if (strict_utf8_check) {
+          WireFormatLite::VerifyUtf8String(value.data(), value.length(),
+                                           WireFormatLite::SERIALIZE,
+                                           field->full_name().c_str());
+        } else {
+          VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
+                                     field->full_name().c_str());
+        }
         WireFormatLite::WriteString(field->number(), value, output);
         break;
       }
@@ -948,7 +1008,7 @@
 
   const int data_size = FieldDataOnlyByteSize(field, message);
   int our_size = data_size;
-  if (field->options().packed()) {
+  if (field->is_packed()) {
     if (data_size > 0) {
       // Packed fields get serialized like a string, not their native type.
       // Technically this doesn't really matter; the size only changes if it's
@@ -1068,34 +1128,6 @@
   return our_size;
 }
 
-void WireFormat::VerifyUTF8StringFallback(const char* data,
-                                          int size,
-                                          Operation op,
-                                          const char* field_name) {
-  if (!IsStructurallyValidUTF8(data, size)) {
-    const char* operation_str = NULL;
-    switch (op) {
-      case PARSE:
-        operation_str = "parsing";
-        break;
-      case SERIALIZE:
-        operation_str = "serializing";
-        break;
-      // no default case: have the compiler warn if a case is not covered.
-    }
-    string quoted_field_name = "";
-    if (field_name != NULL) {
-      quoted_field_name = StringPrintf(" '%s'", field_name);
-    }
-    // no space below to avoid double space when the field name is missing.
-    GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "
-               << "UTF-8 data when " << operation_str << " a protocol "
-               << "buffer. Use the 'bytes' type if you intend to send raw "
-               << "bytes. ";
-  }
-}
-
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index c13ff5e..5b41aad 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -138,6 +138,14 @@
   static bool SkipMessage(io::CodedInputStream* input,
                           UnknownFieldSet* unknown_fields);
 
+  // Read a packed enum field. If the is_valid function is not NULL, values for
+  // which is_valid(value) returns false are appended to unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(io::CodedInputStream* input,
+                                             uint32 field_number,
+                                             bool (*is_valid)(int),
+                                             UnknownFieldSet* unknown_fields,
+                                             RepeatedField<int>* values);
+
   // Write the contents of an UnknownFieldSet to the output.
   static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
                                      io::CodedOutputStream* output);
@@ -223,8 +231,8 @@
       const Message& message);
 
   enum Operation {
-    PARSE,
-    SERIALIZE,
+    PARSE = 0,
+    SERIALIZE = 1,
   };
 
   // Verifies that a string field is valid UTF8, logging an error if not.
@@ -239,13 +247,6 @@
                                          const char* field_name);
 
  private:
-  // Verifies that a string field is valid UTF8, logging an error if not.
-  static void VerifyUTF8StringFallback(
-      const char* data,
-      int size,
-      Operation op,
-      const char* field_name);
-
   // Skip a MessageSet field.
   static bool SkipMessageSetField(io::CodedInputStream* input,
                                   uint32 field_number,
@@ -257,8 +258,6 @@
                                            Message* message,
                                            io::CodedInputStream* input);
 
-
-
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
 };
 
@@ -282,7 +281,7 @@
 
 inline WireFormatLite::WireType WireFormat::WireTypeForField(
     const FieldDescriptor* field) {
-  if (field->options().packed()) {
+  if (field->is_packed()) {
     return WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
   } else {
     return WireTypeForFieldType(field->type());
@@ -313,7 +312,8 @@
 inline void WireFormat::VerifyUTF8String(const char* data, int size,
     WireFormat::Operation op) {
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  WireFormat::VerifyUTF8StringFallback(data, size, op, NULL);
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), NULL);
 #else
   // Avoid the compiler warning about unsued variables.
   (void)data; (void)size; (void)op;
@@ -324,7 +324,8 @@
     const char* data, int size, WireFormat::Operation op,
     const char* field_name) {
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  WireFormat::VerifyUTF8StringFallback(data, size, op, field_name);
+  WireFormatLite::VerifyUtf8String(
+      data, size, static_cast<WireFormatLite::Operation>(op), field_name);
 #else
   // Avoid the compiler warning about unused variables.
   (void)data; (void)size; (void)op; (void)field_name;
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 8de8278..f251707 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -37,17 +37,22 @@
 #include <stack>
 #include <string>
 #include <vector>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/io/coded_stream_inl.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 
+
 namespace google {
 namespace protobuf {
 namespace internal {
 
-#ifndef _MSC_VER    // MSVC doesn't like definitions of inline constants, GCC
-                    // requires them.
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+// Old version of MSVC doesn't like definitions of inline constants, GCC
+// requires them.
 const int WireFormatLite::kMessageSetItemStartTag;
 const int WireFormatLite::kMessageSetItemEndTag;
 const int WireFormatLite::kMessageSetTypeIdTag;
@@ -55,11 +60,16 @@
 
 #endif
 
+// IBM xlC requires prefixing constants with WireFormatLite::
 const int WireFormatLite::kMessageSetItemTagsSize =
-  io::CodedOutputStream::StaticVarintSize32<kMessageSetItemStartTag>::value +
-  io::CodedOutputStream::StaticVarintSize32<kMessageSetItemEndTag>::value +
-  io::CodedOutputStream::StaticVarintSize32<kMessageSetTypeIdTag>::value +
-  io::CodedOutputStream::StaticVarintSize32<kMessageSetMessageTag>::value;
+  io::CodedOutputStream::StaticVarintSize32<
+      WireFormatLite::kMessageSetItemStartTag>::value +
+  io::CodedOutputStream::StaticVarintSize32<
+      WireFormatLite::kMessageSetItemEndTag>::value +
+  io::CodedOutputStream::StaticVarintSize32<
+      WireFormatLite::kMessageSetTypeIdTag>::value +
+  io::CodedOutputStream::StaticVarintSize32<
+      WireFormatLite::kMessageSetMessageTag>::value;
 
 const WireFormatLite::CppType
 WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
@@ -291,7 +301,7 @@
         int, WireFormatLite::TYPE_ENUM>(input, &value)) {
       return false;
     }
-    if (is_valid(value)) {
+    if (is_valid == NULL || is_valid(value)) {
       values->Add(value);
     }
   }
@@ -299,6 +309,34 @@
   return true;
 }
 
+bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
+    io::CodedInputStream* input,
+    int field_number,
+    bool (*is_valid)(int),
+    io::CodedOutputStream* unknown_fields_stream,
+    RepeatedField<int>* values) {
+  uint32 length;
+  if (!input->ReadVarint32(&length)) return false;
+  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  while (input->BytesUntilLimit() > 0) {
+    int value;
+    if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
+        int, WireFormatLite::TYPE_ENUM>(input, &value)) {
+      return false;
+    }
+    if (is_valid == NULL || is_valid(value)) {
+      values->Add(value);
+    } else {
+      uint32 tag = WireFormatLite::MakeTag(field_number,
+                                           WireFormatLite::WIRETYPE_VARINT);
+      unknown_fields_stream->WriteVarint32(tag);
+      unknown_fields_stream->WriteVarint32(value);
+    }
+  }
+  input->PopLimit(limit);
+  return true;
+}
+
 void WireFormatLite::WriteInt32(int field_number, int32 value,
                                 io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_VARINT, output);
@@ -374,7 +412,7 @@
                                  io::CodedOutputStream* output) {
   // String is for UTF-8 text only
   WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
-  GOOGLE_CHECK(value.size() <= kint32max);
+  GOOGLE_CHECK_LE(value.size(), kint32max);
   output->WriteVarint32(value.size());
   output->WriteString(value);
 }
@@ -383,14 +421,14 @@
     io::CodedOutputStream* output) {
   // String is for UTF-8 text only
   WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
-  GOOGLE_CHECK(value.size() <= kint32max);
+  GOOGLE_CHECK_LE(value.size(), kint32max);
   output->WriteVarint32(value.size());
   output->WriteRawMaybeAliased(value.data(), value.size());
 }
 void WireFormatLite::WriteBytes(int field_number, const string& value,
                                 io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
-  GOOGLE_CHECK(value.size() <= kint32max);
+  GOOGLE_CHECK_LE(value.size(), kint32max);
   output->WriteVarint32(value.size());
   output->WriteString(value);
 }
@@ -398,7 +436,7 @@
     int field_number, const string& value,
     io::CodedOutputStream* output) {
   WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
-  GOOGLE_CHECK(value.size() <= kint32max);
+  GOOGLE_CHECK_LE(value.size(), kint32max);
   output->WriteVarint32(value.size());
   output->WriteRawMaybeAliased(value.data(), value.size());
 }
@@ -451,19 +489,53 @@
   }
 }
 
-bool WireFormatLite::ReadString(io::CodedInputStream* input,
-                                string* value) {
-  // String is for UTF-8 text only
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE static bool ReadBytesToString(
+    io::CodedInputStream* input, string* value);
+inline static bool ReadBytesToString(io::CodedInputStream* input,
+                                     string* value) {
   uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
-  if (!input->InternalReadStringInline(value, length)) return false;
-  return true;
+  return input->ReadVarint32(&length) &&
+      input->InternalReadStringInline(value, length);
 }
-bool WireFormatLite::ReadBytes(io::CodedInputStream* input,
-                               string* value) {
-  uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
-  return input->InternalReadStringInline(value, length);
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string* value) {
+  return ReadBytesToString(input, value);
+}
+
+bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string** p) {
+  if (*p == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    *p = new ::std::string();
+  }
+  return ReadBytesToString(input, *p);
+}
+
+bool WireFormatLite::VerifyUtf8String(const char* data,
+                                      int size,
+                                      Operation op,
+                                      const char* field_name) {
+  if (!IsStructurallyValidUTF8(data, size)) {
+    const char* operation_str = NULL;
+    switch (op) {
+      case PARSE:
+        operation_str = "parsing";
+        break;
+      case SERIALIZE:
+        operation_str = "serializing";
+        break;
+      // no default case: have the compiler warn if a case is not covered.
+    }
+    string quoted_field_name = "";
+    if (field_name != NULL) {
+      quoted_field_name = StringPrintf(" '%s'", field_name);
+    }
+    // no space below to avoid double space when the field name is missing.
+    GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "
+               << "UTF-8 data when " << operation_str << " a protocol "
+               << "buffer. Use the 'bytes' type if you intend to send raw "
+               << "bytes. ";
+    return false;
+  }
+  return true;
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 21aa488..55fc7ec 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -250,17 +250,17 @@
   // For primitive fields, we just use a templatized routine parameterized by
   // the represented type and the FieldType. These are specialized with the
   // appropriate definition for each declared type.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline bool ReadPrimitive(input, CType* value) INL;
+  template <typename CType, enum FieldType DeclaredType> INL
+  static bool ReadPrimitive(input, CType* value);
 
   // Reads repeated primitive values, with optimizations for repeats.
   // tag_size and tag should both be compile-time constants provided by the
   // protocol compiler.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline bool ReadRepeatedPrimitive(int tag_size,
-                                           uint32 tag,
-                                           input,
-                                           RepeatedField<CType>* value) INL;
+  template <typename CType, enum FieldType DeclaredType> INL
+  static bool ReadRepeatedPrimitive(int tag_size,
+                                    uint32 tag,
+                                    input,
+                                    RepeatedField<CType>* value);
 
   // Identical to ReadRepeatedPrimitive, except will not inline the
   // implementation.
@@ -275,30 +275,56 @@
   //
   // This is only implemented for the types with fixed wire size, e.g.
   // float, double, and the (s)fixed* types.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer,
-                                                    CType* value) INL;
+  template <typename CType, enum FieldType DeclaredType> INL
+  static const uint8* ReadPrimitiveFromArray(const uint8* buffer, CType* value);
 
   // Reads a primitive packed field.
   //
   // This is only implemented for packable types.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline bool ReadPackedPrimitive(input,
-                                         RepeatedField<CType>* value) INL;
+  template <typename CType, enum FieldType DeclaredType> INL
+  static bool ReadPackedPrimitive(input, RepeatedField<CType>* value);
 
   // Identical to ReadPackedPrimitive, except will not inline the
   // implementation.
   template <typename CType, enum FieldType DeclaredType>
   static bool ReadPackedPrimitiveNoInline(input, RepeatedField<CType>* value);
 
-  // Read a packed enum field. Values for which is_valid() returns false are
-  // dropped.
+  // Read a packed enum field. If the is_valid function is not NULL, values for
+  // which is_valid(value) returns false are silently dropped.
   static bool ReadPackedEnumNoInline(input,
                                      bool (*is_valid)(int),
-                                     RepeatedField<int>* value);
+                                     RepeatedField<int>* values);
 
-  static bool ReadString(input, string* value);
-  static bool ReadBytes (input, string* value);
+  // Read a packed enum field. If the is_valid function is not NULL, values for
+  // which is_valid(value) returns false are appended to unknown_fields_stream.
+  static bool ReadPackedEnumPreserveUnknowns(
+      input,
+      field_number,
+      bool (*is_valid)(int),
+      io::CodedOutputStream* unknown_fields_stream,
+      RepeatedField<int>* values);
+
+  // Read a string.  ReadString(..., string* value) requires an existing string.
+  static inline bool ReadString(input, string* value);
+  // ReadString(..., string** p) is internal-only, and should only be called
+  // from generated code. It starts by setting *p to "new string"
+  // if *p == &GetEmptyStringAlreadyInited().  It then invokes
+  // ReadString(input, *p).  This is useful for reducing code size.
+  static inline bool ReadString(input, string** p);
+  // Analogous to ReadString().
+  static bool ReadBytes(input, string* value);
+  static bool ReadBytes(input, string** p);
+
+
+  enum Operation {
+    PARSE = 0,
+    SERIALIZE = 1,
+  };
+
+  // Returns true if the data is valid UTF-8.
+  static bool VerifyUtf8String(const char* data, int size,
+                               Operation op,
+                               const char* field_name);
 
   static inline bool ReadGroup  (field_number, input, MessageLite* value);
   static inline bool ReadMessage(input, MessageLite* value);
@@ -312,26 +338,37 @@
   template<typename MessageType>
   static inline bool ReadMessageNoVirtual(input, MessageType* value);
 
+  // The same, but do not modify input's recursion depth.  This is useful
+  // when reading a bunch of groups or messages in a loop, because then the
+  // recursion depth can be incremented before the loop and decremented after.
+  template<typename MessageType>
+  static inline bool ReadGroupNoVirtualNoRecursionDepth(field_number, input,
+                                                        MessageType* value);
+
+  template<typename MessageType>
+  static inline bool ReadMessageNoVirtualNoRecursionDepth(input,
+                                                          MessageType* value);
+
   // Write a tag.  The Write*() functions typically include the tag, so
   // normally there's no need to call this unless using the Write*NoTag()
   // variants.
-  static inline void WriteTag(field_number, WireType type, output) INL;
+  INL static void WriteTag(field_number, WireType type, output);
 
   // Write fields, without tags.
-  static inline void WriteInt32NoTag   (int32 value, output) INL;
-  static inline void WriteInt64NoTag   (int64 value, output) INL;
-  static inline void WriteUInt32NoTag  (uint32 value, output) INL;
-  static inline void WriteUInt64NoTag  (uint64 value, output) INL;
-  static inline void WriteSInt32NoTag  (int32 value, output) INL;
-  static inline void WriteSInt64NoTag  (int64 value, output) INL;
-  static inline void WriteFixed32NoTag (uint32 value, output) INL;
-  static inline void WriteFixed64NoTag (uint64 value, output) INL;
-  static inline void WriteSFixed32NoTag(int32 value, output) INL;
-  static inline void WriteSFixed64NoTag(int64 value, output) INL;
-  static inline void WriteFloatNoTag   (float value, output) INL;
-  static inline void WriteDoubleNoTag  (double value, output) INL;
-  static inline void WriteBoolNoTag    (bool value, output) INL;
-  static inline void WriteEnumNoTag    (int value, output) INL;
+  INL static void WriteInt32NoTag   (int32 value, output);
+  INL static void WriteInt64NoTag   (int64 value, output);
+  INL static void WriteUInt32NoTag  (uint32 value, output);
+  INL static void WriteUInt64NoTag  (uint64 value, output);
+  INL static void WriteSInt32NoTag  (int32 value, output);
+  INL static void WriteSInt64NoTag  (int64 value, output);
+  INL static void WriteFixed32NoTag (uint32 value, output);
+  INL static void WriteFixed64NoTag (uint64 value, output);
+  INL static void WriteSFixed32NoTag(int32 value, output);
+  INL static void WriteSFixed64NoTag(int64 value, output);
+  INL static void WriteFloatNoTag   (float value, output);
+  INL static void WriteDoubleNoTag  (double value, output);
+  INL static void WriteBoolNoTag    (bool value, output);
+  INL static void WriteEnumNoTag    (int value, output);
 
   // Write fields, including tags.
   static void WriteInt32   (field_number,  int32 value, output);
@@ -381,73 +418,59 @@
 #define output uint8* target
 
   // Like above, but use only *ToArray methods of CodedOutputStream.
-  static inline uint8* WriteTagToArray(field_number, WireType type, output) INL;
+  INL static uint8* WriteTagToArray(field_number, WireType type, output);
 
   // Write fields, without tags.
-  static inline uint8* WriteInt32NoTagToArray   (int32 value, output) INL;
-  static inline uint8* WriteInt64NoTagToArray   (int64 value, output) INL;
-  static inline uint8* WriteUInt32NoTagToArray  (uint32 value, output) INL;
-  static inline uint8* WriteUInt64NoTagToArray  (uint64 value, output) INL;
-  static inline uint8* WriteSInt32NoTagToArray  (int32 value, output) INL;
-  static inline uint8* WriteSInt64NoTagToArray  (int64 value, output) INL;
-  static inline uint8* WriteFixed32NoTagToArray (uint32 value, output) INL;
-  static inline uint8* WriteFixed64NoTagToArray (uint64 value, output) INL;
-  static inline uint8* WriteSFixed32NoTagToArray(int32 value, output) INL;
-  static inline uint8* WriteSFixed64NoTagToArray(int64 value, output) INL;
-  static inline uint8* WriteFloatNoTagToArray   (float value, output) INL;
-  static inline uint8* WriteDoubleNoTagToArray  (double value, output) INL;
-  static inline uint8* WriteBoolNoTagToArray    (bool value, output) INL;
-  static inline uint8* WriteEnumNoTagToArray    (int value, output) INL;
+  INL static uint8* WriteInt32NoTagToArray   (int32 value, output);
+  INL static uint8* WriteInt64NoTagToArray   (int64 value, output);
+  INL static uint8* WriteUInt32NoTagToArray  (uint32 value, output);
+  INL static uint8* WriteUInt64NoTagToArray  (uint64 value, output);
+  INL static uint8* WriteSInt32NoTagToArray  (int32 value, output);
+  INL static uint8* WriteSInt64NoTagToArray  (int64 value, output);
+  INL static uint8* WriteFixed32NoTagToArray (uint32 value, output);
+  INL static uint8* WriteFixed64NoTagToArray (uint64 value, output);
+  INL static uint8* WriteSFixed32NoTagToArray(int32 value, output);
+  INL static uint8* WriteSFixed64NoTagToArray(int64 value, output);
+  INL static uint8* WriteFloatNoTagToArray   (float value, output);
+  INL static uint8* WriteDoubleNoTagToArray  (double value, output);
+  INL static uint8* WriteBoolNoTagToArray    (bool value, output);
+  INL static uint8* WriteEnumNoTagToArray    (int value, output);
 
   // Write fields, including tags.
-  static inline uint8* WriteInt32ToArray(
-    field_number, int32 value, output) INL;
-  static inline uint8* WriteInt64ToArray(
-    field_number, int64 value, output) INL;
-  static inline uint8* WriteUInt32ToArray(
-    field_number, uint32 value, output) INL;
-  static inline uint8* WriteUInt64ToArray(
-    field_number, uint64 value, output) INL;
-  static inline uint8* WriteSInt32ToArray(
-    field_number, int32 value, output) INL;
-  static inline uint8* WriteSInt64ToArray(
-    field_number, int64 value, output) INL;
-  static inline uint8* WriteFixed32ToArray(
-    field_number, uint32 value, output) INL;
-  static inline uint8* WriteFixed64ToArray(
-    field_number, uint64 value, output) INL;
-  static inline uint8* WriteSFixed32ToArray(
-    field_number, int32 value, output) INL;
-  static inline uint8* WriteSFixed64ToArray(
-    field_number, int64 value, output) INL;
-  static inline uint8* WriteFloatToArray(
-    field_number, float value, output) INL;
-  static inline uint8* WriteDoubleToArray(
-    field_number, double value, output) INL;
-  static inline uint8* WriteBoolToArray(
-    field_number, bool value, output) INL;
-  static inline uint8* WriteEnumToArray(
-    field_number, int value, output) INL;
+  INL static uint8* WriteInt32ToArray(field_number, int32 value, output);
+  INL static uint8* WriteInt64ToArray(field_number, int64 value, output);
+  INL static uint8* WriteUInt32ToArray(field_number, uint32 value, output);
+  INL static uint8* WriteUInt64ToArray(field_number, uint64 value, output);
+  INL static uint8* WriteSInt32ToArray(field_number, int32 value, output);
+  INL static uint8* WriteSInt64ToArray(field_number, int64 value, output);
+  INL static uint8* WriteFixed32ToArray(field_number, uint32 value, output);
+  INL static uint8* WriteFixed64ToArray(field_number, uint64 value, output);
+  INL static uint8* WriteSFixed32ToArray(field_number, int32 value, output);
+  INL static uint8* WriteSFixed64ToArray(field_number, int64 value, output);
+  INL static uint8* WriteFloatToArray(field_number, float value, output);
+  INL static uint8* WriteDoubleToArray(field_number, double value, output);
+  INL static uint8* WriteBoolToArray(field_number, bool value, output);
+  INL static uint8* WriteEnumToArray(field_number, int value, output);
 
-  static inline uint8* WriteStringToArray(
-    field_number, const string& value, output) INL;
-  static inline uint8* WriteBytesToArray(
-    field_number, const string& value, output) INL;
+  INL static uint8* WriteStringToArray(
+    field_number, const string& value, output);
+  INL static uint8* WriteBytesToArray(
+    field_number, const string& value, output);
 
-  static inline uint8* WriteGroupToArray(
-      field_number, const MessageLite& value, output) INL;
-  static inline uint8* WriteMessageToArray(
-      field_number, const MessageLite& value, output) INL;
+  INL static uint8* WriteGroupToArray(
+      field_number, const MessageLite& value, output);
+  INL static uint8* WriteMessageToArray(
+      field_number, const MessageLite& value, output);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
   // the subclass must not override SerializeWithCachedSizes()).
   template<typename MessageType>
-  static inline uint8* WriteGroupNoVirtualToArray(
-    field_number, const MessageType& value, output) INL;
+  INL static uint8* WriteGroupNoVirtualToArray(
+    field_number, const MessageType& value, output);
   template<typename MessageType>
-  static inline uint8* WriteMessageNoVirtualToArray(
-    field_number, const MessageType& value, output) INL;
+  INL static uint8* WriteMessageNoVirtualToArray(
+    field_number, const MessageType& value, output);
 
 #undef output
 #undef input
@@ -498,18 +521,17 @@
   // A helper method for the repeated primitive reader. This method has
   // optimizations for primitive types that have fixed size on the wire, and
   // can be read using potentially faster paths.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline bool ReadRepeatedFixedSizePrimitive(
+  template <typename CType, enum FieldType DeclaredType> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static bool ReadRepeatedFixedSizePrimitive(
       int tag_size,
       uint32 tag,
       google::protobuf::io::CodedInputStream* input,
-      RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+      RepeatedField<CType>* value);
 
   // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
-  template <typename CType, enum FieldType DeclaredType>
-  static inline bool ReadPackedFixedSizePrimitive(
-      google::protobuf::io::CodedInputStream* input,
-      RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+  template <typename CType, enum FieldType DeclaredType> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static bool ReadPackedFixedSizePrimitive(google::protobuf::io::CodedInputStream* input,
+                                           RepeatedField<CType>* value);
 
   static const CppType kFieldTypeToCppTypeMap[];
   static const WireFormatLite::WireType kWireTypeForFieldType[];
@@ -638,7 +660,7 @@
 
 inline uint32 WireFormatLite::ZigZagEncode32(int32 n) {
   // Note:  the right-shift must be arithmetic
-  return (n << 1) ^ (n >> 31);
+  return (static_cast<uint32>(n) << 1) ^ (n >> 31);
 }
 
 inline int32 WireFormatLite::ZigZagDecode32(uint32 n) {
@@ -647,13 +669,26 @@
 
 inline uint64 WireFormatLite::ZigZagEncode64(int64 n) {
   // Note:  the right-shift must be arithmetic
-  return (n << 1) ^ (n >> 63);
+  return (static_cast<uint64>(n) << 1) ^ (n >> 63);
 }
 
 inline int64 WireFormatLite::ZigZagDecode64(uint64 n) {
   return (n >> 1) ^ -static_cast<int64>(n & 1);
 }
 
+// String is for UTF-8 text only, but, even so, ReadString() can simply
+// call ReadBytes().
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       string* value) {
+  return ReadBytes(input, value);
+}
+
+inline bool WireFormatLite::ReadString(io::CodedInputStream* input,
+                                       string** p) {
+  return ReadBytes(input, p);
+}
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index feb2254..7bce21c 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -43,10 +43,12 @@
 
 #include <string>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arenastring.h>
 
 
 namespace google {
@@ -272,8 +274,8 @@
     // The number of bytes each type occupies on the wire.
     const int per_value_size = tag_size + sizeof(value);
 
-    int elements_available = min(values->Capacity() - values->size(),
-                                 size / per_value_size);
+    int elements_available =
+        std::min(values->Capacity() - values->size(), size / per_value_size);
     int num_read = 0;
     while (num_read < elements_available &&
            (buffer = io::CodedInputStream::ExpectTagFromArray(
@@ -365,7 +367,7 @@
     bytes_limit = input->BytesUntilLimit();
   } else {
     bytes_limit =
-        min(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
+        std::min(bytes_limit, static_cast<int64>(input->BytesUntilLimit()));
   }
   if (bytes_limit >= new_bytes) {
     // Fast-path that pre-allocates *values to the final size.
@@ -410,12 +412,12 @@
       CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values);                  \
 }
 
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
 
 #undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
 
@@ -426,6 +428,7 @@
 }
 
 
+
 inline bool WireFormatLite::ReadGroup(int field_number,
                                       io::CodedInputStream* input,
                                       MessageLite* value) {
@@ -442,15 +445,12 @@
                                         MessageLite* value) {
   uint32 length;
   if (!input->ReadVarint32(&length)) return false;
-  if (!input->IncrementRecursionDepth()) return false;
-  io::CodedInputStream::Limit limit = input->PushLimit(length);
-  if (!value->MergePartialFromCodedStream(input)) return false;
+  std::pair<io::CodedInputStream::Limit, int> p =
+      input->IncrementRecursionDepthAndPushLimit(length);
+  if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
   // Make sure that parsing stopped when the limit was hit, not at an endgroup
   // tag.
-  if (!input->ConsumedEntireMessage()) return false;
-  input->PopLimit(limit);
-  input->DecrementRecursionDepth();
-  return true;
+  return input->DecrementRecursionDepthAndPopLimit(p.first);
 }
 
 // We name the template parameter something long and extremely unlikely to occur
@@ -471,7 +471,7 @@
   if (!value->
       MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
     return false;
-  input->DecrementRecursionDepth();
+  input->UnsafeDecrementRecursionDepth();
   // Make sure the last thing read was an end tag for this group.
   if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) {
     return false;
@@ -479,21 +479,37 @@
   return true;
 }
 template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadGroupNoVirtualNoRecursionDepth(
+    int field_number, io::CodedInputStream* input,
+    MessageType_WorkAroundCppLookupDefect* value) {
+  return value->MessageType_WorkAroundCppLookupDefect::
+             MergePartialFromCodedStream(input) &&
+         input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP));
+}
+template<typename MessageType_WorkAroundCppLookupDefect>
 inline bool WireFormatLite::ReadMessageNoVirtual(
     io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
   uint32 length;
   if (!input->ReadVarint32(&length)) return false;
-  if (!input->IncrementRecursionDepth()) return false;
-  io::CodedInputStream::Limit limit = input->PushLimit(length);
+  std::pair<io::CodedInputStream::Limit, int> p =
+      input->IncrementRecursionDepthAndPushLimit(length);
+  if (p.second < 0 || !value->
+      MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
+    return false;
+  // Make sure that parsing stopped when the limit was hit, not at an endgroup
+  // tag.
+  return input->DecrementRecursionDepthAndPopLimit(p.first);
+}
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+    io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
+  io::CodedInputStream::Limit old_limit = input->ReadLengthAndPushLimit();
   if (!value->
       MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
     return false;
   // Make sure that parsing stopped when the limit was hit, not at an endgroup
   // tag.
-  if (!input->ConsumedEntireMessage()) return false;
-  input->PopLimit(limit);
-  input->DecrementRecursionDepth();
-  return true;
+  return input->CheckEntireMessageConsumedAndPopLimit(old_limit);
 }
 
 // ===================================================================
@@ -819,12 +835,14 @@
 }
 
 inline int WireFormatLite::StringSize(const string& value) {
-  return io::CodedOutputStream::VarintSize32(value.size()) +
-         value.size();
+  return static_cast<int>(
+      io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+      value.size());
 }
 inline int WireFormatLite::BytesSize(const string& value) {
-  return io::CodedOutputStream::VarintSize32(value.size()) +
-         value.size();
+  return static_cast<int>(
+      io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+      value.size());
 }
 
 
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 81a024b..4e4add6 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -38,10 +38,14 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
 #include <google/protobuf/unittest_mset.pb.h>
+#include <google/protobuf/unittest_mset_wire_format.pb.h>
 #include <google/protobuf/test_util.h>
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/stl_util.h>
@@ -418,7 +422,7 @@
 
 TEST(WireFormatTest, SerializeMessageSet) {
   // Set up a TestMessageSet with two known messages and an unknown one.
-  unittest::TestMessageSet message_set;
+  proto2_wireformat_unittest::TestMessageSet message_set;
   message_set.MutableExtension(
     unittest::TestMessageSetExtension1::message_set_extension)->set_i(123);
   message_set.MutableExtension(
@@ -461,7 +465,7 @@
   // Set up a TestMessageSet with two known messages and an unknown one, as
   // above.
 
-  unittest::TestMessageSet message_set;
+  proto2_wireformat_unittest::TestMessageSet message_set;
   message_set.MutableExtension(
     unittest::TestMessageSetExtension1::message_set_extension)->set_i(123);
   message_set.MutableExtension(
@@ -538,7 +542,7 @@
   ASSERT_TRUE(raw.SerializeToString(&data));
 
   // Parse as a TestMessageSet and check the contents.
-  unittest::TestMessageSet message_set;
+  proto2_wireformat_unittest::TestMessageSet message_set;
   ASSERT_TRUE(message_set.ParseFromString(data));
 
   EXPECT_EQ(123, message_set.GetExtension(
@@ -552,7 +556,7 @@
   EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited());
 
   // Also parse using WireFormat.
-  unittest::TestMessageSet dynamic_message_set;
+  proto2_wireformat_unittest::TestMessageSet dynamic_message_set;
   io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
                              data.size());
   ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set));
@@ -582,7 +586,7 @@
     coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
   }
   {
-    unittest::TestMessageSet message_set;
+    proto2_wireformat_unittest::TestMessageSet message_set;
     ASSERT_TRUE(message_set.ParseFromString(data));
 
     EXPECT_EQ(123, message_set.GetExtension(
@@ -590,7 +594,7 @@
   }
   {
     // Test parse the message via Reflection.
-    unittest::TestMessageSet message_set;
+    proto2_wireformat_unittest::TestMessageSet message_set;
     io::CodedInputStream input(
         reinterpret_cast<const uint8*>(data.data()), data.size());
     EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
@@ -602,7 +606,7 @@
 }
 
 TEST(WireFormatTest, ParseBrokenMessageSet) {
-  unittest::TestMessageSet message_set;
+  proto2_wireformat_unittest::TestMessageSet message_set;
   string input("goodbye");  // Invalid wire format data.
   EXPECT_FALSE(message_set.ParseFromString(input));
 }
@@ -767,7 +771,7 @@
 }
 
 TEST(WireFormatTest, CompatibleTypes) {
-  const int64 data = 0x100000000;
+  const int64 data = 0x100000000LL;
   unittest::Int64Message msg1;
   msg1.set_data(data);
   string serialized;
@@ -794,6 +798,169 @@
   ASSERT_EQ(static_cast<uint32>(data), msg5.data());
 }
 
+class Proto3PrimitiveRepeatedWireFormatTest : public ::testing::Test {
+ protected:
+  Proto3PrimitiveRepeatedWireFormatTest()
+      : packedTestAllTypes_(
+            "\xFA\x01\x01\x01"
+            "\x82\x02\x01\x01"
+            "\x8A\x02\x01\x01"
+            "\x92\x02\x01\x01"
+            "\x9A\x02\x01\x02"
+            "\xA2\x02\x01\x02"
+            "\xAA\x02\x04\x01\x00\x00\x00"
+            "\xB2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xBA\x02\x04\x01\x00\x00\x00"
+            "\xC2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xCA\x02\x04\x00\x00\x80\x3f"
+            "\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\xDA\x02\x01\x01"
+            "\x9A\x03\x01\x01",
+            86),
+        packedTestUnpackedTypes_(
+            "\x0A\x01\x01"
+            "\x12\x01\x01"
+            "\x1A\x01\x01"
+            "\x22\x01\x01"
+            "\x2A\x01\x02"
+            "\x32\x01\x02"
+            "\x3A\x04\x01\x00\x00\x00"
+            "\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x4A\x04\x01\x00\x00\x00"
+            "\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x5A\x04\x00\x00\x80\x3f"
+            "\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\x6A\x01\x01"
+            "\x72\x01\x01",
+            72),
+        unpackedTestAllTypes_(
+            "\xF8\x01\x01"
+            "\x80\x02\x01"
+            "\x88\x02\x01"
+            "\x90\x02\x01"
+            "\x98\x02\x02"
+            "\xA0\x02\x02"
+            "\xAD\x02\x01\x00\x00\x00"
+            "\xB1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xBD\x02\x01\x00\x00\x00"
+            "\xC1\x02\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\xCD\x02\x00\x00\x80\x3f"
+            "\xD1\x02\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\xD8\x02\x01"
+            "\x98\x03\x01",
+            72),
+        unpackedTestUnpackedTypes_(
+            "\x08\x01"
+            "\x10\x01"
+            "\x18\x01"
+            "\x20\x01"
+            "\x28\x02"
+            "\x30\x02"
+            "\x3D\x01\x00\x00\x00"
+            "\x41\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x4D\x01\x00\x00\x00"
+            "\x51\x01\x00\x00\x00\x00\x00\x00\x00"
+            "\x5D\x00\x00\x80\x3f"
+            "\x61\x00\x00\x00\x00\x00\x00\xf0\x3f"
+            "\x68\x01"
+            "\x70\x01",
+            58) {}
+  template <class Proto>
+  void SetProto3PrimitiveRepeatedFields(Proto* message) {
+    message->add_repeated_int32(1);
+    message->add_repeated_int64(1);
+    message->add_repeated_uint32(1);
+    message->add_repeated_uint64(1);
+    message->add_repeated_sint32(1);
+    message->add_repeated_sint64(1);
+    message->add_repeated_fixed32(1);
+    message->add_repeated_fixed64(1);
+    message->add_repeated_sfixed32(1);
+    message->add_repeated_sfixed64(1);
+    message->add_repeated_float(1.0);
+    message->add_repeated_double(1.0);
+    message->add_repeated_bool(true);
+    message->add_repeated_nested_enum(
+        proto3_arena_unittest::TestAllTypes_NestedEnum_FOO);
+  }
+
+  template <class Proto>
+  void ExpectProto3PrimitiveRepeatedFieldsSet(const Proto& message) {
+    EXPECT_EQ(1, message.repeated_int32(0));
+    EXPECT_EQ(1, message.repeated_int64(0));
+    EXPECT_EQ(1, message.repeated_uint32(0));
+    EXPECT_EQ(1, message.repeated_uint64(0));
+    EXPECT_EQ(1, message.repeated_sint32(0));
+    EXPECT_EQ(1, message.repeated_sint64(0));
+    EXPECT_EQ(1, message.repeated_fixed32(0));
+    EXPECT_EQ(1, message.repeated_fixed64(0));
+    EXPECT_EQ(1, message.repeated_sfixed32(0));
+    EXPECT_EQ(1, message.repeated_sfixed64(0));
+    EXPECT_EQ(1.0, message.repeated_float(0));
+    EXPECT_EQ(1.0, message.repeated_double(0));
+    EXPECT_EQ(true, message.repeated_bool(0));
+    EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_FOO,
+              message.repeated_nested_enum(0));
+  }
+
+  template <class Proto>
+  void TestSerialization(Proto* message, const string& expected) {
+    SetProto3PrimitiveRepeatedFields(message);
+
+    int size = message->ByteSize();
+
+    // Serialize using the generated code.
+    string generated_data;
+    {
+      io::StringOutputStream raw_output(&generated_data);
+      io::CodedOutputStream output(&raw_output);
+      message->SerializeWithCachedSizes(&output);
+      ASSERT_FALSE(output.HadError());
+    }
+    EXPECT_TRUE(expected == generated_data);
+
+    // Serialize using the dynamic code.
+    string dynamic_data;
+    {
+      io::StringOutputStream raw_output(&dynamic_data);
+      io::CodedOutputStream output(&raw_output);
+      WireFormat::SerializeWithCachedSizes(*message, size, &output);
+      ASSERT_FALSE(output.HadError());
+    }
+    EXPECT_TRUE(expected == dynamic_data);
+  }
+
+  template <class Proto>
+  void TestParsing(Proto* message, const string& compatible_data) {
+    message->Clear();
+    message->ParseFromString(compatible_data);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+
+    message->Clear();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8*>(compatible_data.data()),
+        compatible_data.size());
+    WireFormat::ParseAndMergePartial(&input, message);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+  }
+
+  const string packedTestAllTypes_;
+  const string packedTestUnpackedTypes_;
+  const string unpackedTestAllTypes_;
+  const string unpackedTestUnpackedTypes_;
+};
+
+TEST_F(Proto3PrimitiveRepeatedWireFormatTest, Proto3PrimitiveRepeated) {
+  proto3_arena_unittest::TestAllTypes packed_message;
+  proto3_arena_unittest::TestUnpackedTypes unpacked_message;
+  TestSerialization(&packed_message, packedTestAllTypes_);
+  TestParsing(&packed_message, packedTestAllTypes_);
+  TestParsing(&packed_message, unpackedTestAllTypes_);
+  TestSerialization(&unpacked_message, unpackedTestUnpackedTypes_);
+  TestParsing(&unpacked_message, packedTestUnpackedTypes_);
+  TestParsing(&unpacked_message, unpackedTestUnpackedTypes_);
+}
+
 class WireFormatInvalidInputTest : public testing::Test {
  protected:
   // Make a serialized TestAllTypes in which the field optional_nested_message
@@ -980,7 +1147,8 @@
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
   EXPECT_TRUE(StartsWith(errors[0],
-                         "String field 'data' contains invalid UTF-8 data when "
+                         "String field 'protobuf_unittest.OneString.data' "
+                         "contains invalid UTF-8 data when "
                          "serializing a protocol buffer. Use the "
                          "'bytes' type if you intend to send raw bytes."));
 #else
@@ -1003,7 +1171,8 @@
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
   EXPECT_TRUE(StartsWith(errors[0],
-                         "String field 'data' contains invalid UTF-8 data when "
+                         "String field 'protobuf_unittest.OneString.data' "
+                         "contains invalid UTF-8 data when "
                          "parsing a protocol buffer. Use the "
                          "'bytes' type if you intend to send raw bytes."));
 
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
new file mode 100644
index 0000000..6080142
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -0,0 +1,2772 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <google/protobuf/wrappers.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* DoubleValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DoubleValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FloatValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FloatValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Int64Value_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Int64Value_reflection_ = NULL;
+const ::google::protobuf::Descriptor* UInt64Value_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  UInt64Value_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Int32Value_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Int32Value_reflection_ = NULL;
+const ::google::protobuf::Descriptor* UInt32Value_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  UInt32Value_reflection_ = NULL;
+const ::google::protobuf::Descriptor* BoolValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  BoolValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* StringValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  StringValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* BytesValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  BytesValue_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto() {
+  protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "google/protobuf/wrappers.proto");
+  GOOGLE_CHECK(file != NULL);
+  DoubleValue_descriptor_ = file->message_type(0);
+  static const int DoubleValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DoubleValue, value_),
+  };
+  DoubleValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DoubleValue_descriptor_,
+      DoubleValue::default_instance_,
+      DoubleValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(DoubleValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DoubleValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DoubleValue, _is_default_instance_));
+  FloatValue_descriptor_ = file->message_type(1);
+  static const int FloatValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FloatValue, value_),
+  };
+  FloatValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FloatValue_descriptor_,
+      FloatValue::default_instance_,
+      FloatValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(FloatValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FloatValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FloatValue, _is_default_instance_));
+  Int64Value_descriptor_ = file->message_type(2);
+  static const int Int64Value_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int64Value, value_),
+  };
+  Int64Value_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Int64Value_descriptor_,
+      Int64Value::default_instance_,
+      Int64Value_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Int64Value),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int64Value, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int64Value, _is_default_instance_));
+  UInt64Value_descriptor_ = file->message_type(3);
+  static const int UInt64Value_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt64Value, value_),
+  };
+  UInt64Value_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      UInt64Value_descriptor_,
+      UInt64Value::default_instance_,
+      UInt64Value_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(UInt64Value),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt64Value, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt64Value, _is_default_instance_));
+  Int32Value_descriptor_ = file->message_type(4);
+  static const int Int32Value_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int32Value, value_),
+  };
+  Int32Value_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Int32Value_descriptor_,
+      Int32Value::default_instance_,
+      Int32Value_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(Int32Value),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int32Value, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Int32Value, _is_default_instance_));
+  UInt32Value_descriptor_ = file->message_type(5);
+  static const int UInt32Value_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt32Value, value_),
+  };
+  UInt32Value_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      UInt32Value_descriptor_,
+      UInt32Value::default_instance_,
+      UInt32Value_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(UInt32Value),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt32Value, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UInt32Value, _is_default_instance_));
+  BoolValue_descriptor_ = file->message_type(6);
+  static const int BoolValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BoolValue, value_),
+  };
+  BoolValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      BoolValue_descriptor_,
+      BoolValue::default_instance_,
+      BoolValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(BoolValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BoolValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BoolValue, _is_default_instance_));
+  StringValue_descriptor_ = file->message_type(7);
+  static const int StringValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StringValue, value_),
+  };
+  StringValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      StringValue_descriptor_,
+      StringValue::default_instance_,
+      StringValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(StringValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StringValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StringValue, _is_default_instance_));
+  BytesValue_descriptor_ = file->message_type(8);
+  static const int BytesValue_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BytesValue, value_),
+  };
+  BytesValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      BytesValue_descriptor_,
+      BytesValue::default_instance_,
+      BytesValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(BytesValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BytesValue, _internal_metadata_),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BytesValue, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DoubleValue_descriptor_, &DoubleValue::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FloatValue_descriptor_, &FloatValue::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Int64Value_descriptor_, &Int64Value::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      UInt64Value_descriptor_, &UInt64Value::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Int32Value_descriptor_, &Int32Value::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      UInt32Value_descriptor_, &UInt32Value::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      BoolValue_descriptor_, &BoolValue::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      StringValue_descriptor_, &StringValue::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      BytesValue_descriptor_, &BytesValue::default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto() {
+  delete DoubleValue::default_instance_;
+  delete DoubleValue_reflection_;
+  delete FloatValue::default_instance_;
+  delete FloatValue_reflection_;
+  delete Int64Value::default_instance_;
+  delete Int64Value_reflection_;
+  delete UInt64Value::default_instance_;
+  delete UInt64Value_reflection_;
+  delete Int32Value::default_instance_;
+  delete Int32Value_reflection_;
+  delete UInt32Value::default_instance_;
+  delete UInt32Value_reflection_;
+  delete BoolValue::default_instance_;
+  delete BoolValue_reflection_;
+  delete StringValue::default_instance_;
+  delete StringValue_reflection_;
+  delete BytesValue::default_instance_;
+  delete BytesValue_reflection_;
+}
+
+void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() {
+  static bool already_here = false;
+  if (already_here) return;
+  already_here = true;
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\036google/protobuf/wrappers.proto\022\017google"
+    ".protobuf\"\034\n\013DoubleValue\022\r\n\005value\030\001 \001(\001\""
+    "\033\n\nFloatValue\022\r\n\005value\030\001 \001(\002\"\033\n\nInt64Val"
+    "ue\022\r\n\005value\030\001 \001(\003\"\034\n\013UInt64Value\022\r\n\005valu"
+    "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013"
+    "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022"
+    "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001"
+    " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014B\177\n\023com"
+    ".google.protobufB\rWrappersProtoP\001Z*githu"
+    "b.com/golang/protobuf/ptypes/wrappers\240\001\001"
+    "\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTyp"
+    "esb\006proto3", 450);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "google/protobuf/wrappers.proto", &protobuf_RegisterTypes);
+  DoubleValue::default_instance_ = new DoubleValue();
+  FloatValue::default_instance_ = new FloatValue();
+  Int64Value::default_instance_ = new Int64Value();
+  UInt64Value::default_instance_ = new UInt64Value();
+  Int32Value::default_instance_ = new Int32Value();
+  UInt32Value::default_instance_ = new UInt32Value();
+  BoolValue::default_instance_ = new BoolValue();
+  StringValue::default_instance_ = new StringValue();
+  BytesValue::default_instance_ = new BytesValue();
+  DoubleValue::default_instance_->InitAsDefaultInstance();
+  FloatValue::default_instance_->InitAsDefaultInstance();
+  Int64Value::default_instance_->InitAsDefaultInstance();
+  UInt64Value::default_instance_->InitAsDefaultInstance();
+  Int32Value::default_instance_->InitAsDefaultInstance();
+  UInt32Value::default_instance_->InitAsDefaultInstance();
+  BoolValue::default_instance_->InitAsDefaultInstance();
+  StringValue::default_instance_->InitAsDefaultInstance();
+  BytesValue::default_instance_->InitAsDefaultInstance();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_google_2fprotobuf_2fwrappers_2eproto {
+  StaticDescriptorInitializer_google_2fprotobuf_2fwrappers_2eproto() {
+    protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  }
+} static_descriptor_initializer_google_2fprotobuf_2fwrappers_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DoubleValue::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DoubleValue::DoubleValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.DoubleValue)
+}
+
+DoubleValue::DoubleValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
+}
+
+void DoubleValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+DoubleValue::DoubleValue(const DoubleValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DoubleValue)
+}
+
+void DoubleValue::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = 0;
+}
+
+DoubleValue::~DoubleValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DoubleValue)
+  SharedDtor();
+}
+
+void DoubleValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void DoubleValue::ArenaDtor(void* object) {
+  DoubleValue* _this = reinterpret_cast< DoubleValue* >(object);
+  (void)_this;
+}
+void DoubleValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void DoubleValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DoubleValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DoubleValue_descriptor_;
+}
+
+const DoubleValue& DoubleValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+DoubleValue* DoubleValue::default_instance_ = NULL;
+
+DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<DoubleValue>(arena);
+}
+
+void DoubleValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.DoubleValue)
+  value_ = 0;
+}
+
+bool DoubleValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.DoubleValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional double value = 1;
+      case 1: {
+        if (tag == 9) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.DoubleValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.DoubleValue)
+  return false;
+#undef DO_
+}
+
+void DoubleValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.DoubleValue)
+  // optional double value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteDouble(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.DoubleValue)
+}
+
+::google::protobuf::uint8* DoubleValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
+  // optional double value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DoubleValue)
+  return target;
+}
+
+int DoubleValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue)
+  int total_size = 0;
+
+  // optional double value = 1;
+  if (this->value() != 0) {
+    total_size += 1 + 8;
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DoubleValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DoubleValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DoubleValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DoubleValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DoubleValue)
+    MergeFrom(*source);
+  }
+}
+
+void DoubleValue::MergeFrom(const DoubleValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void DoubleValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DoubleValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DoubleValue::CopyFrom(const DoubleValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DoubleValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DoubleValue::IsInitialized() const {
+
+  return true;
+}
+
+void DoubleValue::Swap(DoubleValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    DoubleValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void DoubleValue::UnsafeArenaSwap(DoubleValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void DoubleValue::InternalSwap(DoubleValue* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DoubleValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DoubleValue_descriptor_;
+  metadata.reflection = DoubleValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DoubleValue
+
+// optional double value = 1;
+void DoubleValue::clear_value() {
+  value_ = 0;
+}
+ double DoubleValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DoubleValue.value)
+  return value_;
+}
+ void DoubleValue::set_value(double value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DoubleValue.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FloatValue::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FloatValue::FloatValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.FloatValue)
+}
+
+FloatValue::FloatValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
+}
+
+void FloatValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+FloatValue::FloatValue(const FloatValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.FloatValue)
+}
+
+void FloatValue::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = 0;
+}
+
+FloatValue::~FloatValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.FloatValue)
+  SharedDtor();
+}
+
+void FloatValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void FloatValue::ArenaDtor(void* object) {
+  FloatValue* _this = reinterpret_cast< FloatValue* >(object);
+  (void)_this;
+}
+void FloatValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void FloatValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FloatValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FloatValue_descriptor_;
+}
+
+const FloatValue& FloatValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+FloatValue* FloatValue::default_instance_ = NULL;
+
+FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<FloatValue>(arena);
+}
+
+void FloatValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.FloatValue)
+  value_ = 0;
+}
+
+bool FloatValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.FloatValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float value = 1;
+      case 1: {
+        if (tag == 13) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.FloatValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.FloatValue)
+  return false;
+#undef DO_
+}
+
+void FloatValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.FloatValue)
+  // optional float value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.FloatValue)
+}
+
+::google::protobuf::uint8* FloatValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
+  // optional float value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FloatValue)
+  return target;
+}
+
+int FloatValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue)
+  int total_size = 0;
+
+  // optional float value = 1;
+  if (this->value() != 0) {
+    total_size += 1 + 4;
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FloatValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FloatValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FloatValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FloatValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FloatValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FloatValue)
+    MergeFrom(*source);
+  }
+}
+
+void FloatValue::MergeFrom(const FloatValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void FloatValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FloatValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FloatValue::CopyFrom(const FloatValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FloatValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool FloatValue::IsInitialized() const {
+
+  return true;
+}
+
+void FloatValue::Swap(FloatValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    FloatValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void FloatValue::UnsafeArenaSwap(FloatValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void FloatValue::InternalSwap(FloatValue* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FloatValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FloatValue_descriptor_;
+  metadata.reflection = FloatValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FloatValue
+
+// optional float value = 1;
+void FloatValue::clear_value() {
+  value_ = 0;
+}
+ float FloatValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FloatValue.value)
+  return value_;
+}
+ void FloatValue::set_value(float value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FloatValue.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Int64Value::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Int64Value::Int64Value()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Int64Value)
+}
+
+Int64Value::Int64Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
+}
+
+void Int64Value::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Int64Value::Int64Value(const Int64Value& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int64Value)
+}
+
+void Int64Value::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = GOOGLE_LONGLONG(0);
+}
+
+Int64Value::~Int64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int64Value)
+  SharedDtor();
+}
+
+void Int64Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void Int64Value::ArenaDtor(void* object) {
+  Int64Value* _this = reinterpret_cast< Int64Value* >(object);
+  (void)_this;
+}
+void Int64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void Int64Value::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Int64Value::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Int64Value_descriptor_;
+}
+
+const Int64Value& Int64Value::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+Int64Value* Int64Value::default_instance_ = NULL;
+
+Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<Int64Value>(arena);
+}
+
+void Int64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int64Value)
+  value_ = GOOGLE_LONGLONG(0);
+}
+
+bool Int64Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Int64Value)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int64 value = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Int64Value)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Int64Value)
+  return false;
+#undef DO_
+}
+
+void Int64Value::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Int64Value)
+  // optional int64 value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Int64Value)
+}
+
+::google::protobuf::uint8* Int64Value::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
+  // optional int64 value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int64Value)
+  return target;
+}
+
+int Int64Value::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value)
+  int total_size = 0;
+
+  // optional int64 value = 1;
+  if (this->value() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int64Size(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Int64Value::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int64Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Int64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int64Value>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int64Value)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int64Value)
+    MergeFrom(*source);
+  }
+}
+
+void Int64Value::MergeFrom(const Int64Value& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void Int64Value::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Int64Value::CopyFrom(const Int64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int64Value::IsInitialized() const {
+
+  return true;
+}
+
+void Int64Value::Swap(Int64Value* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Int64Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Int64Value::UnsafeArenaSwap(Int64Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void Int64Value::InternalSwap(Int64Value* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Int64Value::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Int64Value_descriptor_;
+  metadata.reflection = Int64Value_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Int64Value
+
+// optional int64 value = 1;
+void Int64Value::clear_value() {
+  value_ = GOOGLE_LONGLONG(0);
+}
+ ::google::protobuf::int64 Int64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int64Value.value)
+  return value_;
+}
+ void Int64Value::set_value(::google::protobuf::int64 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Int64Value.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int UInt64Value::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+UInt64Value::UInt64Value()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.UInt64Value)
+}
+
+UInt64Value::UInt64Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
+}
+
+void UInt64Value::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+UInt64Value::UInt64Value(const UInt64Value& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt64Value)
+}
+
+void UInt64Value::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = GOOGLE_ULONGLONG(0);
+}
+
+UInt64Value::~UInt64Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt64Value)
+  SharedDtor();
+}
+
+void UInt64Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void UInt64Value::ArenaDtor(void* object) {
+  UInt64Value* _this = reinterpret_cast< UInt64Value* >(object);
+  (void)_this;
+}
+void UInt64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void UInt64Value::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* UInt64Value::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return UInt64Value_descriptor_;
+}
+
+const UInt64Value& UInt64Value::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+UInt64Value* UInt64Value::default_instance_ = NULL;
+
+UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<UInt64Value>(arena);
+}
+
+void UInt64Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt64Value)
+  value_ = GOOGLE_ULONGLONG(0);
+}
+
+bool UInt64Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.UInt64Value)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint64 value = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.UInt64Value)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.UInt64Value)
+  return false;
+#undef DO_
+}
+
+void UInt64Value::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.UInt64Value)
+  // optional uint64 value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.UInt64Value)
+}
+
+::google::protobuf::uint8* UInt64Value::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
+  // optional uint64 value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt64Value)
+  return target;
+}
+
+int UInt64Value::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value)
+  int total_size = 0;
+
+  // optional uint64 value = 1;
+  if (this->value() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt64Size(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt64Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UInt64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt64Value>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt64Value)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt64Value)
+    MergeFrom(*source);
+  }
+}
+
+void UInt64Value::MergeFrom(const UInt64Value& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void UInt64Value::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void UInt64Value::CopyFrom(const UInt64Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt64Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt64Value::IsInitialized() const {
+
+  return true;
+}
+
+void UInt64Value::Swap(UInt64Value* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    UInt64Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void UInt64Value::UnsafeArenaSwap(UInt64Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void UInt64Value::InternalSwap(UInt64Value* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata UInt64Value::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = UInt64Value_descriptor_;
+  metadata.reflection = UInt64Value_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// UInt64Value
+
+// optional uint64 value = 1;
+void UInt64Value::clear_value() {
+  value_ = GOOGLE_ULONGLONG(0);
+}
+ ::google::protobuf::uint64 UInt64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt64Value.value)
+  return value_;
+}
+ void UInt64Value::set_value(::google::protobuf::uint64 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt64Value.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Int32Value::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Int32Value::Int32Value()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.Int32Value)
+}
+
+Int32Value::Int32Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
+}
+
+void Int32Value::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+Int32Value::Int32Value(const Int32Value& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.Int32Value)
+}
+
+void Int32Value::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = 0;
+}
+
+Int32Value::~Int32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.Int32Value)
+  SharedDtor();
+}
+
+void Int32Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void Int32Value::ArenaDtor(void* object) {
+  Int32Value* _this = reinterpret_cast< Int32Value* >(object);
+  (void)_this;
+}
+void Int32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void Int32Value::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Int32Value::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Int32Value_descriptor_;
+}
+
+const Int32Value& Int32Value::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+Int32Value* Int32Value::default_instance_ = NULL;
+
+Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<Int32Value>(arena);
+}
+
+void Int32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.Int32Value)
+  value_ = 0;
+}
+
+bool Int32Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.Int32Value)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 value = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.Int32Value)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.Int32Value)
+  return false;
+#undef DO_
+}
+
+void Int32Value::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.Int32Value)
+  // optional int32 value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.Int32Value)
+}
+
+::google::protobuf::uint8* Int32Value::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
+  // optional int32 value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int32Value)
+  return target;
+}
+
+int Int32Value::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value)
+  int total_size = 0;
+
+  // optional int32 value = 1;
+  if (this->value() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Int32Value::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int32Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Int32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int32Value>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int32Value)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int32Value)
+    MergeFrom(*source);
+  }
+}
+
+void Int32Value::MergeFrom(const Int32Value& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void Int32Value::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Int32Value::CopyFrom(const Int32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Int32Value::IsInitialized() const {
+
+  return true;
+}
+
+void Int32Value::Swap(Int32Value* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Int32Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Int32Value::UnsafeArenaSwap(Int32Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void Int32Value::InternalSwap(Int32Value* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Int32Value::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Int32Value_descriptor_;
+  metadata.reflection = Int32Value_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Int32Value
+
+// optional int32 value = 1;
+void Int32Value::clear_value() {
+  value_ = 0;
+}
+ ::google::protobuf::int32 Int32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int32Value.value)
+  return value_;
+}
+ void Int32Value::set_value(::google::protobuf::int32 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Int32Value.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int UInt32Value::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+UInt32Value::UInt32Value()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.UInt32Value)
+}
+
+UInt32Value::UInt32Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
+}
+
+void UInt32Value::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+UInt32Value::UInt32Value(const UInt32Value& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.UInt32Value)
+}
+
+void UInt32Value::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = 0u;
+}
+
+UInt32Value::~UInt32Value() {
+  // @@protoc_insertion_point(destructor:google.protobuf.UInt32Value)
+  SharedDtor();
+}
+
+void UInt32Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void UInt32Value::ArenaDtor(void* object) {
+  UInt32Value* _this = reinterpret_cast< UInt32Value* >(object);
+  (void)_this;
+}
+void UInt32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void UInt32Value::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* UInt32Value::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return UInt32Value_descriptor_;
+}
+
+const UInt32Value& UInt32Value::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+UInt32Value* UInt32Value::default_instance_ = NULL;
+
+UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<UInt32Value>(arena);
+}
+
+void UInt32Value::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt32Value)
+  value_ = 0u;
+}
+
+bool UInt32Value::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.UInt32Value)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 value = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.UInt32Value)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.UInt32Value)
+  return false;
+#undef DO_
+}
+
+void UInt32Value::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.UInt32Value)
+  // optional uint32 value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.UInt32Value)
+}
+
+::google::protobuf::uint8* UInt32Value::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
+  // optional uint32 value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt32Value)
+  return target;
+}
+
+int UInt32Value::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value)
+  int total_size = 0;
+
+  // optional uint32 value = 1;
+  if (this->value() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt32Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const UInt32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt32Value>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt32Value)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt32Value)
+    MergeFrom(*source);
+  }
+}
+
+void UInt32Value::MergeFrom(const UInt32Value& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void UInt32Value::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void UInt32Value::CopyFrom(const UInt32Value& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt32Value)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool UInt32Value::IsInitialized() const {
+
+  return true;
+}
+
+void UInt32Value::Swap(UInt32Value* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    UInt32Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void UInt32Value::UnsafeArenaSwap(UInt32Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void UInt32Value::InternalSwap(UInt32Value* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata UInt32Value::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = UInt32Value_descriptor_;
+  metadata.reflection = UInt32Value_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// UInt32Value
+
+// optional uint32 value = 1;
+void UInt32Value::clear_value() {
+  value_ = 0u;
+}
+ ::google::protobuf::uint32 UInt32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt32Value.value)
+  return value_;
+}
+ void UInt32Value::set_value(::google::protobuf::uint32 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt32Value.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int BoolValue::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+BoolValue::BoolValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.BoolValue)
+}
+
+BoolValue::BoolValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
+}
+
+void BoolValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+BoolValue::BoolValue(const BoolValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BoolValue)
+}
+
+void BoolValue::SharedCtor() {
+    _is_default_instance_ = false;
+  _cached_size_ = 0;
+  value_ = false;
+}
+
+BoolValue::~BoolValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BoolValue)
+  SharedDtor();
+}
+
+void BoolValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  if (this != default_instance_) {
+  }
+}
+
+void BoolValue::ArenaDtor(void* object) {
+  BoolValue* _this = reinterpret_cast< BoolValue* >(object);
+  (void)_this;
+}
+void BoolValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void BoolValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* BoolValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return BoolValue_descriptor_;
+}
+
+const BoolValue& BoolValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+BoolValue* BoolValue::default_instance_ = NULL;
+
+BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<BoolValue>(arena);
+}
+
+void BoolValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BoolValue)
+  value_ = false;
+}
+
+bool BoolValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.BoolValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool value = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &value_)));
+
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.BoolValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.BoolValue)
+  return false;
+#undef DO_
+}
+
+void BoolValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.BoolValue)
+  // optional bool value = 1;
+  if (this->value() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.BoolValue)
+}
+
+::google::protobuf::uint8* BoolValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
+  // optional bool value = 1;
+  if (this->value() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BoolValue)
+  return target;
+}
+
+int BoolValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue)
+  int total_size = 0;
+
+  // optional bool value = 1;
+  if (this->value() != 0) {
+    total_size += 1 + 1;
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void BoolValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BoolValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BoolValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BoolValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BoolValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BoolValue)
+    MergeFrom(*source);
+  }
+}
+
+void BoolValue::MergeFrom(const BoolValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value() != 0) {
+    set_value(from.value());
+  }
+}
+
+void BoolValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BoolValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BoolValue::CopyFrom(const BoolValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BoolValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BoolValue::IsInitialized() const {
+
+  return true;
+}
+
+void BoolValue::Swap(BoolValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    BoolValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void BoolValue::UnsafeArenaSwap(BoolValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void BoolValue::InternalSwap(BoolValue* other) {
+  std::swap(value_, other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata BoolValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = BoolValue_descriptor_;
+  metadata.reflection = BoolValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// BoolValue
+
+// optional bool value = 1;
+void BoolValue::clear_value() {
+  value_ = false;
+}
+ bool BoolValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BoolValue.value)
+  return value_;
+}
+ void BoolValue::set_value(bool value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.BoolValue.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int StringValue::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+StringValue::StringValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.StringValue)
+}
+
+StringValue::StringValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
+}
+
+void StringValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+StringValue::StringValue(const StringValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.StringValue)
+}
+
+void StringValue::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+StringValue::~StringValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.StringValue)
+  SharedDtor();
+}
+
+void StringValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  if (this != default_instance_) {
+  }
+}
+
+void StringValue::ArenaDtor(void* object) {
+  StringValue* _this = reinterpret_cast< StringValue* >(object);
+  (void)_this;
+}
+void StringValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void StringValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* StringValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return StringValue_descriptor_;
+}
+
+const StringValue& StringValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+StringValue* StringValue::default_instance_ = NULL;
+
+StringValue* StringValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<StringValue>(arena);
+}
+
+void StringValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.StringValue)
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool StringValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.StringValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string value = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_value()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->value().data(), this->value().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.StringValue.value"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.StringValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.StringValue)
+  return false;
+#undef DO_
+}
+
+void StringValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.StringValue)
+  // optional string value = 1;
+  if (this->value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->value().data(), this->value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.StringValue.value");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.StringValue)
+}
+
+::google::protobuf::uint8* StringValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
+  // optional string value = 1;
+  if (this->value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->value().data(), this->value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.StringValue.value");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.StringValue)
+  return target;
+}
+
+int StringValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue)
+  int total_size = 0;
+
+  // optional string value = 1;
+  if (this->value().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void StringValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.StringValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const StringValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const StringValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.StringValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.StringValue)
+    MergeFrom(*source);
+  }
+}
+
+void StringValue::MergeFrom(const StringValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value().size() > 0) {
+    set_value(from.value());
+  }
+}
+
+void StringValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.StringValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void StringValue::CopyFrom(const StringValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.StringValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool StringValue::IsInitialized() const {
+
+  return true;
+}
+
+void StringValue::Swap(StringValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    StringValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void StringValue::UnsafeArenaSwap(StringValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void StringValue::InternalSwap(StringValue* other) {
+  value_.Swap(&other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata StringValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = StringValue_descriptor_;
+  metadata.reflection = StringValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// StringValue
+
+// optional string value = 1;
+void StringValue::clear_value() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ const ::std::string& StringValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void StringValue::set_value(const ::std::string& value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
+}
+ void StringValue::set_value(const char* value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
+}
+ void StringValue::set_value(const char* value,
+    size_t size) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
+}
+ ::std::string* StringValue::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* StringValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value)
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* StringValue::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+ void StringValue::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+ void StringValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int BytesValue::kValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+BytesValue::BytesValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.BytesValue)
+}
+
+BytesValue::BytesValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
+}
+
+void BytesValue::InitAsDefaultInstance() {
+  _is_default_instance_ = true;
+}
+
+BytesValue::BytesValue(const BytesValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.BytesValue)
+}
+
+void BytesValue::SharedCtor() {
+    _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+BytesValue::~BytesValue() {
+  // @@protoc_insertion_point(destructor:google.protobuf.BytesValue)
+  SharedDtor();
+}
+
+void BytesValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  if (this != default_instance_) {
+  }
+}
+
+void BytesValue::ArenaDtor(void* object) {
+  BytesValue* _this = reinterpret_cast< BytesValue* >(object);
+  (void)_this;
+}
+void BytesValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void BytesValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* BytesValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return BytesValue_descriptor_;
+}
+
+const BytesValue& BytesValue::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  return *default_instance_;
+}
+
+BytesValue* BytesValue::default_instance_ = NULL;
+
+BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<BytesValue>(arena);
+}
+
+void BytesValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.BytesValue)
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool BytesValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.BytesValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bytes value = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.BytesValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.BytesValue)
+  return false;
+#undef DO_
+}
+
+void BytesValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.BytesValue)
+  // optional bytes value = 1;
+  if (this->value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      1, this->value(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:google.protobuf.BytesValue)
+}
+
+::google::protobuf::uint8* BytesValue::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
+  // optional bytes value = 1;
+  if (this->value().size() > 0) {
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+        1, this->value(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BytesValue)
+  return target;
+}
+
+int BytesValue::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue)
+  int total_size = 0;
+
+  // optional bytes value = 1;
+  if (this->value().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::BytesSize(
+        this->value());
+  }
+
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void BytesValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BytesValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BytesValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BytesValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BytesValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BytesValue)
+    MergeFrom(*source);
+  }
+}
+
+void BytesValue::MergeFrom(const BytesValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from.value().size() > 0) {
+    set_value(from.value());
+  }
+}
+
+void BytesValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BytesValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BytesValue::CopyFrom(const BytesValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BytesValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool BytesValue::IsInitialized() const {
+
+  return true;
+}
+
+void BytesValue::Swap(BytesValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    BytesValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void BytesValue::UnsafeArenaSwap(BytesValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void BytesValue::InternalSwap(BytesValue* other) {
+  value_.Swap(&other->value_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata BytesValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = BytesValue_descriptor_;
+  metadata.reflection = BytesValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// BytesValue
+
+// optional bytes value = 1;
+void BytesValue::clear_value() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ const ::std::string& BytesValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void BytesValue::set_value(const ::std::string& value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
+}
+ void BytesValue::set_value(const char* value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
+}
+ void BytesValue::set_value(const void* value,
+    size_t size) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
+}
+ ::std::string* BytesValue::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* BytesValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value)
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* BytesValue::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+ void BytesValue::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+ void BytesValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value)
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
new file mode 100644
index 0000000..1078477
--- /dev/null
+++ b/src/google/protobuf/wrappers.pb.h
@@ -0,0 +1,1180 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#ifndef PROTOBUF_google_2fprotobuf_2fwrappers_2eproto__INCLUDED
+#define PROTOBUF_google_2fprotobuf_2fwrappers_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3000000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace google {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+class BoolValue;
+class BytesValue;
+class DoubleValue;
+class FloatValue;
+class Int32Value;
+class Int64Value;
+class StringValue;
+class UInt32Value;
+class UInt64Value;
+
+// ===================================================================
+
+class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
+ public:
+  DoubleValue();
+  virtual ~DoubleValue();
+
+  DoubleValue(const DoubleValue& from);
+
+  inline DoubleValue& operator=(const DoubleValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DoubleValue& default_instance();
+
+  void UnsafeArenaSwap(DoubleValue* other);
+  void Swap(DoubleValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DoubleValue* New() const { return New(NULL); }
+
+  DoubleValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DoubleValue& from);
+  void MergeFrom(const DoubleValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DoubleValue* other);
+  protected:
+  explicit DoubleValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional double value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  double value() const;
+  void set_value(double value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DoubleValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  double value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static DoubleValue* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
+ public:
+  FloatValue();
+  virtual ~FloatValue();
+
+  FloatValue(const FloatValue& from);
+
+  inline FloatValue& operator=(const FloatValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FloatValue& default_instance();
+
+  void UnsafeArenaSwap(FloatValue* other);
+  void Swap(FloatValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FloatValue* New() const { return New(NULL); }
+
+  FloatValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FloatValue& from);
+  void MergeFrom(const FloatValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FloatValue* other);
+  protected:
+  explicit FloatValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  float value() const;
+  void set_value(float value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.FloatValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  float value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static FloatValue* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
+ public:
+  Int64Value();
+  virtual ~Int64Value();
+
+  Int64Value(const Int64Value& from);
+
+  inline Int64Value& operator=(const Int64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Int64Value& default_instance();
+
+  void UnsafeArenaSwap(Int64Value* other);
+  void Swap(Int64Value* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Int64Value* New() const { return New(NULL); }
+
+  Int64Value* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Int64Value& from);
+  void MergeFrom(const Int64Value& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Int64Value* other);
+  protected:
+  explicit Int64Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int64 value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  ::google::protobuf::int64 value() const;
+  void set_value(::google::protobuf::int64 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int64Value)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::int64 value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static Int64Value* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
+ public:
+  UInt64Value();
+  virtual ~UInt64Value();
+
+  UInt64Value(const UInt64Value& from);
+
+  inline UInt64Value& operator=(const UInt64Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const UInt64Value& default_instance();
+
+  void UnsafeArenaSwap(UInt64Value* other);
+  void Swap(UInt64Value* other);
+
+  // implements Message ----------------------------------------------
+
+  inline UInt64Value* New() const { return New(NULL); }
+
+  UInt64Value* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const UInt64Value& from);
+  void MergeFrom(const UInt64Value& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(UInt64Value* other);
+  protected:
+  explicit UInt64Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint64 value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  ::google::protobuf::uint64 value() const;
+  void set_value(::google::protobuf::uint64 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt64Value)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::uint64 value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static UInt64Value* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
+ public:
+  Int32Value();
+  virtual ~Int32Value();
+
+  Int32Value(const Int32Value& from);
+
+  inline Int32Value& operator=(const Int32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Int32Value& default_instance();
+
+  void UnsafeArenaSwap(Int32Value* other);
+  void Swap(Int32Value* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Int32Value* New() const { return New(NULL); }
+
+  Int32Value* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Int32Value& from);
+  void MergeFrom(const Int32Value& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Int32Value* other);
+  protected:
+  explicit Int32Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  ::google::protobuf::int32 value() const;
+  void set_value(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.Int32Value)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::int32 value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static Int32Value* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
+ public:
+  UInt32Value();
+  virtual ~UInt32Value();
+
+  UInt32Value(const UInt32Value& from);
+
+  inline UInt32Value& operator=(const UInt32Value& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const UInt32Value& default_instance();
+
+  void UnsafeArenaSwap(UInt32Value* other);
+  void Swap(UInt32Value* other);
+
+  // implements Message ----------------------------------------------
+
+  inline UInt32Value* New() const { return New(NULL); }
+
+  UInt32Value* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const UInt32Value& from);
+  void MergeFrom(const UInt32Value& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(UInt32Value* other);
+  protected:
+  explicit UInt32Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  ::google::protobuf::uint32 value() const;
+  void set_value(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.UInt32Value)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::uint32 value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static UInt32Value* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
+ public:
+  BoolValue();
+  virtual ~BoolValue();
+
+  BoolValue(const BoolValue& from);
+
+  inline BoolValue& operator=(const BoolValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const BoolValue& default_instance();
+
+  void UnsafeArenaSwap(BoolValue* other);
+  void Swap(BoolValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline BoolValue* New() const { return New(NULL); }
+
+  BoolValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const BoolValue& from);
+  void MergeFrom(const BoolValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(BoolValue* other);
+  protected:
+  explicit BoolValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  bool value() const;
+  void set_value(bool value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BoolValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  bool value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static BoolValue* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
+ public:
+  StringValue();
+  virtual ~StringValue();
+
+  StringValue(const StringValue& from);
+
+  inline StringValue& operator=(const StringValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const StringValue& default_instance();
+
+  void UnsafeArenaSwap(StringValue* other);
+  void Swap(StringValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline StringValue* New() const { return New(NULL); }
+
+  StringValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const StringValue& from);
+  void MergeFrom(const StringValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(StringValue* other);
+  protected:
+  explicit StringValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  const ::std::string& value() const;
+  void set_value(const ::std::string& value);
+  void set_value(const char* value);
+  void set_value(const char* value, size_t size);
+  ::std::string* mutable_value();
+  ::std::string* release_value();
+  void set_allocated_value(::std::string* value);
+  ::std::string* unsafe_arena_release_value();
+  void unsafe_arena_set_allocated_value(
+      ::std::string* value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static StringValue* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
+ public:
+  BytesValue();
+  virtual ~BytesValue();
+
+  BytesValue(const BytesValue& from);
+
+  inline BytesValue& operator=(const BytesValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const BytesValue& default_instance();
+
+  void UnsafeArenaSwap(BytesValue* other);
+  void Swap(BytesValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline BytesValue* New() const { return New(NULL); }
+
+  BytesValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const BytesValue& from);
+  void MergeFrom(const BytesValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(BytesValue* other);
+  protected:
+  explicit BytesValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bytes value = 1;
+  void clear_value();
+  static const int kValueFieldNumber = 1;
+  const ::std::string& value() const;
+  void set_value(const ::std::string& value);
+  void set_value(const char* value);
+  void set_value(const void* value, size_t size);
+  ::std::string* mutable_value();
+  ::std::string* release_value();
+  void set_allocated_value(::std::string* value);
+  ::std::string* unsafe_arena_release_value();
+  void unsafe_arena_set_allocated_value(
+      ::std::string* value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  bool _is_default_instance_;
+  ::google::protobuf::internal::ArenaStringPtr value_;
+  mutable int _cached_size_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto();
+
+  void InitAsDefaultInstance();
+  static BytesValue* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// DoubleValue
+
+// optional double value = 1;
+inline void DoubleValue::clear_value() {
+  value_ = 0;
+}
+inline double DoubleValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DoubleValue.value)
+  return value_;
+}
+inline void DoubleValue::set_value(double value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DoubleValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// FloatValue
+
+// optional float value = 1;
+inline void FloatValue::clear_value() {
+  value_ = 0;
+}
+inline float FloatValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FloatValue.value)
+  return value_;
+}
+inline void FloatValue::set_value(float value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FloatValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int64Value
+
+// optional int64 value = 1;
+inline void Int64Value::clear_value() {
+  value_ = GOOGLE_LONGLONG(0);
+}
+inline ::google::protobuf::int64 Int64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int64Value.value)
+  return value_;
+}
+inline void Int64Value::set_value(::google::protobuf::int64 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Int64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt64Value
+
+// optional uint64 value = 1;
+inline void UInt64Value::clear_value() {
+  value_ = GOOGLE_ULONGLONG(0);
+}
+inline ::google::protobuf::uint64 UInt64Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt64Value.value)
+  return value_;
+}
+inline void UInt64Value::set_value(::google::protobuf::uint64 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt64Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// Int32Value
+
+// optional int32 value = 1;
+inline void Int32Value::clear_value() {
+  value_ = 0;
+}
+inline ::google::protobuf::int32 Int32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Int32Value.value)
+  return value_;
+}
+inline void Int32Value::set_value(::google::protobuf::int32 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.Int32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// UInt32Value
+
+// optional uint32 value = 1;
+inline void UInt32Value::clear_value() {
+  value_ = 0u;
+}
+inline ::google::protobuf::uint32 UInt32Value::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.UInt32Value.value)
+  return value_;
+}
+inline void UInt32Value::set_value(::google::protobuf::uint32 value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.UInt32Value.value)
+}
+
+// -------------------------------------------------------------------
+
+// BoolValue
+
+// optional bool value = 1;
+inline void BoolValue::clear_value() {
+  value_ = false;
+}
+inline bool BoolValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BoolValue.value)
+  return value_;
+}
+inline void BoolValue::set_value(bool value) {
+  
+  value_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.BoolValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// StringValue
+
+// optional string value = 1;
+inline void StringValue::clear_value() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& StringValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void StringValue::set_value(const ::std::string& value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
+}
+inline void StringValue::set_value(const char* value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
+}
+inline void StringValue::set_value(const char* value,
+    size_t size) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
+}
+inline ::std::string* StringValue::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* StringValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value)
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* StringValue::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void StringValue::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+inline void StringValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value)
+}
+
+// -------------------------------------------------------------------
+
+// BytesValue
+
+// optional bytes value = 1;
+inline void BytesValue::clear_value() {
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& BytesValue::value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void BytesValue::set_value(const ::std::string& value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
+}
+inline void BytesValue::set_value(const char* value) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
+}
+inline void BytesValue::set_value(const void* value,
+    size_t size) {
+  
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
+}
+inline ::std::string* BytesValue::mutable_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* BytesValue::release_value() {
+  // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value)
+  
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* BytesValue::unsafe_arena_release_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void BytesValue::set_allocated_value(::std::string* value) {
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+inline void BytesValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value)
+}
+
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace protobuf
+}  // namespace google
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_google_2fprotobuf_2fwrappers_2eproto__INCLUDED
diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto
new file mode 100644
index 0000000..4828ad9
--- /dev/null
+++ b/src/google/protobuf/wrappers.proto
@@ -0,0 +1,119 @@
+// 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.
+
+// Wrappers for primitive (non-message) types. These types are useful
+// for embedding primitives in the `google.protobuf.Any` type and for places
+// where we need to distinguish between the absence of a primitive
+// typed field and its default value.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "github.com/golang/protobuf/ptypes/wrappers";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
+option objc_class_prefix = "GPB";
+
+// Wrapper message for `double`.
+//
+// The JSON representation for `DoubleValue` is JSON number.
+message DoubleValue {
+  // The double value.
+  double value = 1;
+}
+
+// Wrapper message for `float`.
+//
+// The JSON representation for `FloatValue` is JSON number.
+message FloatValue {
+  // The float value.
+  float value = 1;
+}
+
+// Wrapper message for `int64`.
+//
+// The JSON representation for `Int64Value` is JSON string.
+message Int64Value {
+  // The int64 value.
+  int64 value = 1;
+}
+
+// Wrapper message for `uint64`.
+//
+// The JSON representation for `UInt64Value` is JSON string.
+message UInt64Value {
+  // The uint64 value.
+  uint64 value = 1;
+}
+
+// Wrapper message for `int32`.
+//
+// The JSON representation for `Int32Value` is JSON number.
+message Int32Value {
+  // The int32 value.
+  int32 value = 1;
+}
+
+// Wrapper message for `uint32`.
+//
+// The JSON representation for `UInt32Value` is JSON number.
+message UInt32Value {
+  // The uint32 value.
+  uint32 value = 1;
+}
+
+// Wrapper message for `bool`.
+//
+// The JSON representation for `BoolValue` is JSON `true` and `false`.
+message BoolValue {
+  // The bool value.
+  bool value = 1;
+}
+
+// Wrapper message for `string`.
+//
+// The JSON representation for `StringValue` is JSON string.
+message StringValue {
+  // The string value.
+  string value = 1;
+}
+
+// Wrapper message for `bytes`.
+//
+// The JSON representation for `BytesValue` is JSON string.
+message BytesValue {
+  // The bytes value.
+  bytes value = 1;
+}
diff --git a/tests.sh b/tests.sh
new file mode 100755
index 0000000..6a9439a
--- /dev/null
+++ b/tests.sh
@@ -0,0 +1,347 @@
+#!/bin/bash
+#
+# Build and runs tests for the protobuf project.  The tests as written here are
+# used by both Jenkins and Travis, though some specialized logic is required to
+# handle the differences between them.
+
+on_travis() {
+  if [ "$TRAVIS" == "true" ]; then
+    "$@"
+  fi
+}
+
+# For when some other test needs the C++ main build, including protoc and
+# libprotobuf.
+internal_build_cpp() {
+  if [ -f src/protoc ]; then
+    # Already built.
+    return
+  fi
+
+  if [[ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]]; then
+    # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more
+    # decent C++ 11 support in order to compile conformance tests.
+    sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+    sudo apt-get update -qq
+    sudo apt-get install -qq g++-4.8
+    export CXX="g++-4.8" CC="gcc-4.8"
+  fi
+
+  ./autogen.sh
+  ./configure
+  make -j2
+}
+
+build_cpp() {
+  internal_build_cpp
+  make check -j2
+  cd conformance && make test_cpp && cd ..
+
+  # Verify benchmarking code can build successfully.
+  cd benchmarks && make && ./generate-datasets && cd ..
+}
+
+build_cpp_distcheck() {
+  ./autogen.sh
+  ./configure
+  make distcheck -j2
+}
+
+build_csharp() {
+  # Just for the conformance tests. We don't currently
+  # need to really build protoc, but it's simplest to keep with the
+  # conventions of the other builds.
+  internal_build_cpp
+  NUGET=/usr/local/bin/nuget.exe
+
+  if [ "$TRAVIS" == "true" ]; then
+    # Install latest version of Mono
+    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+    echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
+    echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
+    sudo apt-get update -qq
+    sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit
+    wget www.nuget.org/NuGet.exe -O nuget.exe
+    NUGET=../../nuget.exe
+  fi
+
+  (cd csharp/src; mono $NUGET restore)
+  csharp/buildall.sh
+  cd conformance && make test_csharp && cd ..
+}
+
+build_golang() {
+  # Go build needs `protoc`.
+  internal_build_cpp
+  # Add protoc to the path so that the examples build finds it.
+  export PATH="`pwd`/src:$PATH"
+
+  # Install Go and the Go protobuf compiler plugin.
+  sudo apt-get update -qq
+  sudo apt-get install -qq golang
+  export GOPATH="$HOME/gocode"
+  mkdir -p "$GOPATH/src/github.com/google"
+  ln -s "`pwd`" "$GOPATH/src/github.com/google/protobuf"
+  export PATH="$GOPATH/bin:$PATH"
+  go get github.com/golang/protobuf/protoc-gen-go
+
+  cd examples && make gotest && cd ..
+}
+
+use_java() {
+  version=$1
+  case "$version" in
+    jdk6)
+      on_travis sudo apt-get install openjdk-6-jdk
+      export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH
+      ;;
+    jdk7)
+      on_travis sudo apt-get install openjdk-7-jdk
+      export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
+      ;;
+    oracle7)
+      if [ "$TRAVIS" == "true" ]; then
+        sudo apt-get install python-software-properties # for apt-add-repository
+        echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | \
+          sudo debconf-set-selections
+        yes | sudo apt-add-repository ppa:webupd8team/java
+        yes | sudo apt-get install oracle-java7-installer
+      fi;
+      export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH
+      ;;
+  esac
+
+  if [ "$TRAVIS" != "true" ]; then
+    MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository
+    MVN="$MVN -e -X --offline -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
+  fi;
+
+  which java
+  java -version
+}
+
+# --batch-mode supresses download progress output that spams the logs.
+MVN="mvn --batch-mode"
+
+build_java() {
+  version=$1
+  dir=java_$version
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cp -r java $dir
+  cd $dir && $MVN clean && $MVN test
+  cd ../..
+}
+
+# The conformance tests are hard-coded to work with the $ROOT/java directory.
+# So this can't run in parallel with two different sets of tests.
+build_java_with_conformance_tests() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd java && $MVN test && $MVN install
+  cd util && $MVN package assembly:single
+  cd ../..
+  cd conformance && make test_java && cd ..
+}
+
+build_javanano() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd javanano && $MVN test && cd ..
+}
+
+build_java_jdk6() {
+  use_java jdk6
+  build_java jdk6
+}
+build_java_jdk7() {
+  use_java jdk7
+  build_java_with_conformance_tests
+}
+build_java_oracle7() {
+  use_java oracle7
+  build_java oracle7
+}
+
+build_javanano_jdk6() {
+  use_java jdk6
+  build_javanano
+}
+build_javanano_jdk7() {
+  use_java jdk7
+  build_javanano
+}
+build_javanano_oracle7() {
+  use_java oracle7
+  build_javanano
+}
+
+internal_install_python_deps() {
+  if [ "$TRAVIS" != "true" ]; then
+    return;
+  fi
+  # Install tox (OS X doesn't have pip).
+  if [ $(uname -s) == "Darwin" ]; then
+    sudo easy_install tox
+  else
+    sudo pip install tox
+  fi
+  # Only install Python2.6/3.x on Linux.
+  if [ $(uname -s) == "Linux" ]; then
+    sudo apt-get install -y python-software-properties # for apt-add-repository
+    sudo apt-add-repository -y ppa:fkrull/deadsnakes
+    sudo apt-get update -qq
+    sudo apt-get install -y python2.6 python2.6-dev
+    sudo apt-get install -y python3.3 python3.3-dev
+    sudo apt-get install -y python3.4 python3.4-dev
+  fi
+}
+
+internal_objectivec_common () {
+  # Make sure xctool is up to date. Adapted from
+  #  http://docs.travis-ci.com/user/osx-ci-environment/
+  # We don't use a before_install because we test multiple OSes.
+  brew update
+  brew outdated xctool || brew upgrade xctool
+  # Reused the build script that takes care of configuring and ensuring things
+  # are up to date. Xcode and conformance tests will be directly invoked.
+  objectivec/DevTools/full_mac_build.sh \
+      --core-only --skip-xcode --skip-objc-conformance
+}
+
+internal_xctool_debug_and_release() {
+  # Always use -reporter plain to avoid escape codes in output (makes travis
+  # logs easier to read).
+  xctool -reporter plain -configuration Debug "$@"
+  xctool -reporter plain -configuration Release "$@"
+}
+
+build_objectivec_ios() {
+  internal_objectivec_common
+  # https://github.com/facebook/xctool/issues/509 - unlike xcodebuild, xctool
+  # doesn't support >1 destination, so we have to build first and then run the
+  # tests one destination at a time.
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+    -scheme ProtocolBuffers \
+    -sdk iphonesimulator \
+    build-tests
+  IOS_DESTINATIONS=(
+    "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
+    "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
+  )
+  for i in "${IOS_DESTINATIONS[@]}" ; do
+    internal_xctool_debug_and_release \
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+      -scheme ProtocolBuffers \
+      -sdk iphonesimulator \
+      -destination "${i}" \
+      run-tests
+  done
+}
+
+build_objectivec_osx() {
+  internal_objectivec_common
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_OSX.xcodeproj \
+    -scheme ProtocolBuffers \
+    -destination "platform=OS X,arch=x86_64" \
+    test
+  cd conformance && make test_objc && cd ..
+}
+
+build_python() {
+  internal_build_cpp
+  internal_install_python_deps
+  cd python
+  # Only test Python 2.6/3.x on Linux
+  if [ $(uname -s) == "Linux" ]; then
+    envlist=py\{26,27,33,34\}-python
+  else
+    envlist=py27-python
+  fi
+  tox -e $envlist
+  cd ..
+}
+
+build_python_cpp() {
+  internal_build_cpp
+  internal_install_python_deps
+  export LD_LIBRARY_PATH=../src/.libs # for Linux
+  export DYLD_LIBRARY_PATH=../src/.libs # for OS X
+  cd python
+  # Only test Python 2.6/3.x on Linux
+  if [ $(uname -s) == "Linux" ]; then
+    # py26 is currently disabled due to json_format
+    envlist=py\{27,33,34\}-cpp
+  else
+    envlist=py27-cpp
+  fi
+  tox -e $envlist
+  cd ..
+}
+
+build_ruby19() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-1.9 && cd ..
+}
+build_ruby20() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.0 && cd ..
+}
+build_ruby21() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.1 && cd ..
+}
+build_ruby22() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.2 && cd ..
+}
+build_jruby() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh jruby && cd ..
+}
+
+build_javascript() {
+  internal_build_cpp
+  cd js && npm install && npm test && cd ..
+}
+
+# Note: travis currently does not support testing more than one language so the
+# .travis.yml cheats and claims to only be cpp.  If they add multiple language
+# support, this should probably get updated to install steps and/or
+# rvm/gemfile/jdk/etc. entries rather than manually doing the work.
+
+# .travis.yml uses matrix.exclude to block the cases where app-get can't be
+# use to install things.
+
+# -------- main --------
+
+if [ "$#" -ne 1 ]; then
+  echo "
+Usage: $0 { cpp |
+            csharp |
+            java_jdk6 |
+            java_jdk7 |
+            java_oracle7 |
+            javanano_jdk6 |
+            javanano_jdk7 |
+            javanano_oracle7 |
+            objectivec_ios |
+            objectivec_osx |
+            python |
+            python_cpp |
+            ruby19 |
+            ruby20 |
+            ruby21 |
+            ruby22 |
+            jruby }
+"
+  exit 1
+fi
+
+set -e  # exit immediately on error
+set -x  # display all commands
+eval "build_$1"
diff --git a/update_file_lists.sh b/update_file_lists.sh
new file mode 100755
index 0000000..d76a161
--- /dev/null
+++ b/update_file_lists.sh
@@ -0,0 +1,191 @@
+#!/bin/sh
+
+# This script copies source file lists from src/Makefile.am to cmake files.
+
+get_variable_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  awk "
+    BEGIN { start = 0; }
+    /^$VARNAME =/ { start = 1; }
+    { if (start) { print \$0; } }
+    /\\\\\$/ { next; }
+    { start = 0; }
+  " $FILENAME \
+    | sed "s/^$VARNAME =//" \
+    | sed "s/[ \\]//g" \
+    | grep -v "^\\$" \
+    | grep -v "^$" \
+    | LC_ALL=C sort | uniq
+}
+
+get_header_files() {
+  get_variable_value $@ | grep '\.h$'
+}
+
+get_source_files() {
+  get_variable_value $@ | grep "cc$"
+}
+
+get_proto_files_blacklisted() {
+  get_proto_files $@ | sed '/^google\/protobuf\/unittest_enormous_descriptor.proto$/d'
+}
+
+get_proto_files() {
+  get_variable_value $@ | grep "pb.cc$" | sed "s/pb.cc/proto/"
+}
+
+sort_files() {
+  for FILE in $@; do
+    echo $FILE
+  done | LC_ALL=C sort | uniq
+}
+
+MAKEFILE=src/Makefile.am
+
+[ -f "$MAKEFILE" ] || {
+  echo "Cannot find: $MAKEFILE"
+  exit 1
+}
+
+# Extract file lists from src/Makefile.am
+GZHEADERS=$(get_variable_value $MAKEFILE GZHEADERS)
+HEADERS=$(get_variable_value $MAKEFILE nobase_include_HEADERS)
+PUBLIC_HEADERS=$(sort_files $GZHEADERS $HEADERS)
+LIBPROTOBUF_LITE_SOURCES=$(get_source_files $MAKEFILE libprotobuf_lite_la_SOURCES)
+LIBPROTOBUF_SOURCES=$(get_source_files $MAKEFILE libprotobuf_la_SOURCES)
+LIBPROTOC_SOURCES=$(get_source_files $MAKEFILE libprotoc_la_SOURCES)
+LITE_PROTOS=$(get_proto_files $MAKEFILE protoc_lite_outputs)
+PROTOS=$(get_proto_files $MAKEFILE protoc_outputs)
+PROTOS_BLACKLISTED=$(get_proto_files_blacklisted $MAKEFILE protoc_outputs)
+WKT_PROTOS=$(get_variable_value $MAKEFILE nobase_dist_proto_DATA)
+COMMON_TEST_SOURCES=$(get_source_files $MAKEFILE COMMON_TEST_SOURCES)
+COMMON_LITE_TEST_SOURCES=$(get_source_files $MAKEFILE COMMON_LITE_TEST_SOURCES)
+TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_test_SOURCES)
+LITE_TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_lite_test_SOURCES)
+LITE_ARENA_TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_lite_arena_test_SOURCES)
+TEST_PLUGIN_SOURCES=$(get_source_files $MAKEFILE test_plugin_SOURCES)
+
+################################################################################
+# Update cmake files.
+################################################################################
+
+CMAKE_DIR=cmake
+EXTRACT_INCLUDES_BAT=cmake/extract_includes.bat.in
+[ -d "$CMAKE_DIR" ] || {
+  echo "Cannot find: $CMAKE_DIR"
+  exit 1
+}
+
+[ -f "$EXTRACT_INCLUDES_BAT" ] || {
+  echo "Cannot find: $EXTRACT_INCLUDES_BAT"
+  exit 1
+}
+
+set_cmake_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  local PREFIX=$3
+  shift
+  shift
+  shift
+  awk -v values="$*" -v prefix="$PREFIX" "
+    BEGIN { start = 0; }
+    /^set\\($VARNAME/ {
+      start = 1;
+      print \$0;
+      len = split(values, vlist, \" \");
+      for (i = 1; i <= len; ++i) {
+        printf(\"  %s%s\\n\", prefix, vlist[i]);
+      }
+      next;
+    }
+    start && /^\\)/ {
+      start = 0;
+    }
+    !start {
+      print \$0;
+    }
+  " $FILENAME > /tmp/$$
+  cp /tmp/$$ $FILENAME
+}
+
+
+# Replace file lists in cmake files.
+CMAKE_PREFIX="\${protobuf_source_dir}/src/"
+set_cmake_value $CMAKE_DIR/libprotobuf-lite.cmake libprotobuf_lite_files $CMAKE_PREFIX $LIBPROTOBUF_LITE_SOURCES
+set_cmake_value $CMAKE_DIR/libprotobuf.cmake libprotobuf_files $CMAKE_PREFIX $LIBPROTOBUF_SOURCES
+set_cmake_value $CMAKE_DIR/libprotoc.cmake libprotoc_files $CMAKE_PREFIX $LIBPROTOC_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_test_protos "" $LITE_PROTOS
+set_cmake_value $CMAKE_DIR/tests.cmake tests_protos "" $PROTOS_BLACKLISTED
+set_cmake_value $CMAKE_DIR/tests.cmake common_test_files $CMAKE_PREFIX $COMMON_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake common_lite_test_files $CMAKE_PREFIX $COMMON_LITE_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake tests_files $CMAKE_PREFIX $TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_test_files $CMAKE_PREFIX $LITE_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_arena_test_files $CMAKE_PREFIX $LITE_ARENA_TEST_SOURCES
+
+# Generate extract_includes.bat
+echo "mkdir include" > $EXTRACT_INCLUDES_BAT
+for HEADER in $PUBLIC_HEADERS; do
+  HEADER_DIR=$(dirname $HEADER)
+  while [ ! "$HEADER_DIR" = "." ]; do
+    echo $HEADER_DIR | sed "s/\\//\\\\/g"
+    HEADER_DIR=$(dirname $HEADER_DIR)
+  done
+done | sort | uniq | sed "s/^/mkdir include\\\\/" >> $EXTRACT_INCLUDES_BAT
+for HEADER in $PUBLIC_HEADERS; do
+  WINPATH=$(echo $HEADER | sed 's;/;\\;g')
+  echo "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\..\\src\\$WINPATH include\\$WINPATH" >> $EXTRACT_INCLUDES_BAT
+done
+
+################################################################################
+# Update bazel BUILD files.
+################################################################################
+
+set_bazel_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  local PREFIX=$3
+  shift
+  shift
+  shift
+  awk -v values="$*" -v prefix="$PREFIX" "
+    BEGIN { start = 0; }
+    /# AUTOGEN\\($VARNAME\\)/ {
+      start = 1;
+      print \$0;
+      # replace \$0 with indent.
+      sub(/#.*/, \"\", \$0)
+      len = split(values, vlist, \" \");
+      for (i = 1; i <= len; ++i) {
+        printf(\"%s\\\"%s%s\\\",\n\", \$0, prefix, vlist[i]);
+      }
+      next;
+    }
+    start && /\]/ {
+      start = 0
+    }
+    !start {
+      print \$0;
+    }
+  " $FILENAME > /tmp/$$
+  cp /tmp/$$ $FILENAME
+}
+
+
+BAZEL_BUILD=./BUILD
+BAZEL_PREFIX="src/"
+if [ -f "$BAZEL_BUILD" ]; then
+  set_bazel_value $BAZEL_BUILD protobuf_lite_srcs $BAZEL_PREFIX $LIBPROTOBUF_LITE_SOURCES
+  set_bazel_value $BAZEL_BUILD protobuf_srcs $BAZEL_PREFIX $LIBPROTOBUF_SOURCES
+  set_bazel_value $BAZEL_BUILD protoc_lib_srcs $BAZEL_PREFIX $LIBPROTOC_SOURCES
+  set_bazel_value $BAZEL_BUILD lite_test_protos "" $LITE_PROTOS
+  set_bazel_value $BAZEL_BUILD well_known_protos "" $WKT_PROTOS
+  set_bazel_value $BAZEL_BUILD test_protos "" $PROTOS
+  set_bazel_value $BAZEL_BUILD common_test_srcs $BAZEL_PREFIX $COMMON_TEST_SOURCES
+  set_bazel_value $BAZEL_BUILD test_srcs $BAZEL_PREFIX $TEST_SOURCES
+  set_bazel_value $BAZEL_BUILD test_plugin_srcs $BAZEL_PREFIX $TEST_PLUGIN_SOURCES
+else
+  echo "Skipped BUILD file update."
+fi
+
diff --git a/util/BUILD b/util/BUILD
new file mode 100644
index 0000000..8b1046b
--- /dev/null
+++ b/util/BUILD
@@ -0,0 +1,709 @@
+# Bazel (http://bazel.io/) BUILD file for Protobuf.
+
+licenses(["notice"])
+
+################################################################################
+# Protobuf Runtime Library
+################################################################################
+
+COPTS = [
+    "-DHAVE_PTHREAD",
+    "-Wall",
+    "-Wwrite-strings",
+    "-Woverloaded-virtual",
+    "-Wno-sign-compare",
+    "-Wno-error=unused-function",
+]
+
+config_setting(
+    name = "android",
+    values = {
+        "crosstool_top": "//external:android/crosstool",
+    },
+)
+
+# Android builds do not need to link in a separate pthread library.
+LINK_OPTS = select({
+    ":android": [],
+    "//conditions:default": ["-lpthread"],
+})
+
+load(
+    "protobuf",
+    "cc_proto_library",
+    "py_proto_library",
+    "internal_gen_well_known_protos_java",
+    "internal_protobuf_py_tests",
+)
+
+config_setting(
+    name = "ios_armv7",
+    values = {
+        "ios_cpu": "armv7",
+    },
+)
+
+config_setting(
+    name = "ios_armv7s",
+    values = {
+        "ios_cpu": "armv7s",
+    },
+)
+
+config_setting(
+    name = "ios_arm64",
+    values = {
+        "ios_cpu": "arm64",
+    },
+)
+
+IOS_ARM_COPTS = COPTS + [
+    "-DOS_IOS",
+    "-miphoneos-version-min=7.0",
+    "-arch armv7",
+    "-arch armv7s",
+    "-arch arm64",
+    "-D__thread=",
+    "-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.2.sdk/",
+]
+
+cc_library(
+    name = "protobuf_lite",
+    srcs = [
+        # AUTOGEN(protobuf_lite_srcs)
+        "src/google/protobuf/arena.cc",
+        "src/google/protobuf/arenastring.cc",
+        "src/google/protobuf/extension_set.cc",
+        "src/google/protobuf/generated_message_util.cc",
+        "src/google/protobuf/io/coded_stream.cc",
+        "src/google/protobuf/io/zero_copy_stream.cc",
+        "src/google/protobuf/io/zero_copy_stream_impl_lite.cc",
+        "src/google/protobuf/message_lite.cc",
+        "src/google/protobuf/repeated_field.cc",
+        "src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
+        "src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc",
+        "src/google/protobuf/stubs/bytestream.cc",
+        "src/google/protobuf/stubs/common.cc",
+        "src/google/protobuf/stubs/int128.cc",
+        "src/google/protobuf/stubs/once.cc",
+        "src/google/protobuf/stubs/status.cc",
+        "src/google/protobuf/stubs/statusor.cc",
+        "src/google/protobuf/stubs/stringpiece.cc",
+        "src/google/protobuf/stubs/stringprintf.cc",
+        "src/google/protobuf/stubs/structurally_valid.cc",
+        "src/google/protobuf/stubs/strutil.cc",
+        "src/google/protobuf/stubs/time.cc",
+        "src/google/protobuf/wire_format_lite.cc",
+    ],
+    hdrs = glob(["src/google/protobuf/**/*.h"]),
+    copts = select({
+        ":ios_armv7": IOS_ARM_COPTS,
+        ":ios_armv7s": IOS_ARM_COPTS,
+        ":ios_arm64": IOS_ARM_COPTS,
+        "//conditions:default": COPTS,
+    }),
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+)
+
+cc_library(
+    name = "protobuf",
+    srcs = [
+        # AUTOGEN(protobuf_srcs)
+        "src/google/protobuf/any.cc",
+        "src/google/protobuf/any.pb.cc",
+        "src/google/protobuf/api.pb.cc",
+        "src/google/protobuf/compiler/importer.cc",
+        "src/google/protobuf/compiler/parser.cc",
+        "src/google/protobuf/descriptor.cc",
+        "src/google/protobuf/descriptor.pb.cc",
+        "src/google/protobuf/descriptor_database.cc",
+        "src/google/protobuf/duration.pb.cc",
+        "src/google/protobuf/dynamic_message.cc",
+        "src/google/protobuf/empty.pb.cc",
+        "src/google/protobuf/extension_set_heavy.cc",
+        "src/google/protobuf/field_mask.pb.cc",
+        "src/google/protobuf/generated_message_reflection.cc",
+        "src/google/protobuf/io/gzip_stream.cc",
+        "src/google/protobuf/io/printer.cc",
+        "src/google/protobuf/io/strtod.cc",
+        "src/google/protobuf/io/tokenizer.cc",
+        "src/google/protobuf/io/zero_copy_stream_impl.cc",
+        "src/google/protobuf/map_field.cc",
+        "src/google/protobuf/message.cc",
+        "src/google/protobuf/reflection_ops.cc",
+        "src/google/protobuf/service.cc",
+        "src/google/protobuf/source_context.pb.cc",
+        "src/google/protobuf/struct.pb.cc",
+        "src/google/protobuf/stubs/mathlimits.cc",
+        "src/google/protobuf/stubs/substitute.cc",
+        "src/google/protobuf/text_format.cc",
+        "src/google/protobuf/timestamp.pb.cc",
+        "src/google/protobuf/type.pb.cc",
+        "src/google/protobuf/unknown_field_set.cc",
+        "src/google/protobuf/util/field_comparator.cc",
+        "src/google/protobuf/util/field_mask_util.cc",
+        "src/google/protobuf/util/internal/datapiece.cc",
+        "src/google/protobuf/util/internal/default_value_objectwriter.cc",
+        "src/google/protobuf/util/internal/error_listener.cc",
+        "src/google/protobuf/util/internal/field_mask_utility.cc",
+        "src/google/protobuf/util/internal/json_escaping.cc",
+        "src/google/protobuf/util/internal/json_objectwriter.cc",
+        "src/google/protobuf/util/internal/json_stream_parser.cc",
+        "src/google/protobuf/util/internal/object_writer.cc",
+        "src/google/protobuf/util/internal/proto_writer.cc",
+        "src/google/protobuf/util/internal/protostream_objectsource.cc",
+        "src/google/protobuf/util/internal/protostream_objectwriter.cc",
+        "src/google/protobuf/util/internal/type_info.cc",
+        "src/google/protobuf/util/internal/type_info_test_helper.cc",
+        "src/google/protobuf/util/internal/utility.cc",
+        "src/google/protobuf/util/json_util.cc",
+        "src/google/protobuf/util/message_differencer.cc",
+        "src/google/protobuf/util/time_util.cc",
+        "src/google/protobuf/util/type_resolver_util.cc",
+        "src/google/protobuf/wire_format.cc",
+        "src/google/protobuf/wrappers.pb.cc",
+    ],
+    hdrs = glob(["src/**/*.h"]),
+    copts = select({
+        ":ios_armv7": IOS_ARM_COPTS,
+        ":ios_armv7s": IOS_ARM_COPTS,
+        ":ios_arm64": IOS_ARM_COPTS,
+        "//conditions:default": COPTS,
+    }),
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protobuf_lite"],
+)
+
+objc_library(
+    name = "protobuf_objc",
+    hdrs = ["objectivec/GPBProtocolBuffers.h"],
+    includes = ["objectivec"],
+    non_arc_srcs = ["objectivec/GPBProtocolBuffers.m"],
+    visibility = ["//visibility:public"],
+)
+
+RELATIVE_WELL_KNOWN_PROTOS = [
+    # AUTOGEN(well_known_protos)
+    "google/protobuf/any.proto",
+    "google/protobuf/api.proto",
+    "google/protobuf/compiler/plugin.proto",
+    "google/protobuf/descriptor.proto",
+    "google/protobuf/duration.proto",
+    "google/protobuf/empty.proto",
+    "google/protobuf/field_mask.proto",
+    "google/protobuf/source_context.proto",
+    "google/protobuf/struct.proto",
+    "google/protobuf/timestamp.proto",
+    "google/protobuf/type.proto",
+    "google/protobuf/wrappers.proto",
+]
+
+WELL_KNOWN_PROTOS = ["src/" + s for s in RELATIVE_WELL_KNOWN_PROTOS]
+
+filegroup(
+    name = "well_known_protos",
+    srcs = WELL_KNOWN_PROTOS,
+    visibility = ["//visibility:public"],
+)
+
+cc_proto_library(
+    name = "cc_wkt_protos",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    internal_bootstrap_hack = 1,
+    protoc = ":protoc",
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Protocol Buffers Compiler
+################################################################################
+
+cc_library(
+    name = "protoc_lib",
+    srcs = [
+        # AUTOGEN(protoc_lib_srcs)
+        "src/google/protobuf/compiler/code_generator.cc",
+        "src/google/protobuf/compiler/command_line_interface.cc",
+        "src/google/protobuf/compiler/cpp/cpp_enum.cc",
+        "src/google/protobuf/compiler/cpp/cpp_enum_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_extension.cc",
+        "src/google/protobuf/compiler/cpp/cpp_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_file.cc",
+        "src/google/protobuf/compiler/cpp/cpp_generator.cc",
+        "src/google/protobuf/compiler/cpp/cpp_helpers.cc",
+        "src/google/protobuf/compiler/cpp/cpp_map_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_message.cc",
+        "src/google/protobuf/compiler/cpp/cpp_message_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc",
+        "src/google/protobuf/compiler/cpp/cpp_service.cc",
+        "src/google/protobuf/compiler/cpp/cpp_string_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum.cc",
+        "src/google/protobuf/compiler/csharp/csharp_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_field_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_generator.cc",
+        "src/google/protobuf/compiler/csharp/csharp_helpers.cc",
+        "src/google/protobuf/compiler/csharp/csharp_map_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message.cc",
+        "src/google/protobuf/compiler/csharp/csharp_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc",
+        "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc",
+        "src/google/protobuf/compiler/java/java_context.cc",
+        "src/google/protobuf/compiler/java/java_doc_comment.cc",
+        "src/google/protobuf/compiler/java/java_enum.cc",
+        "src/google/protobuf/compiler/java/java_enum_field.cc",
+        "src/google/protobuf/compiler/java/java_enum_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_enum_lite.cc",
+        "src/google/protobuf/compiler/java/java_extension.cc",
+        "src/google/protobuf/compiler/java/java_extension_lite.cc",
+        "src/google/protobuf/compiler/java/java_field.cc",
+        "src/google/protobuf/compiler/java/java_file.cc",
+        "src/google/protobuf/compiler/java/java_generator.cc",
+        "src/google/protobuf/compiler/java/java_generator_factory.cc",
+        "src/google/protobuf/compiler/java/java_helpers.cc",
+        "src/google/protobuf/compiler/java/java_lazy_message_field.cc",
+        "src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_map_field.cc",
+        "src/google/protobuf/compiler/java/java_map_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message.cc",
+        "src/google/protobuf/compiler/java/java_message_builder.cc",
+        "src/google/protobuf/compiler/java/java_message_builder_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_field.cc",
+        "src/google/protobuf/compiler/java/java_message_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_message_lite.cc",
+        "src/google/protobuf/compiler/java/java_name_resolver.cc",
+        "src/google/protobuf/compiler/java/java_primitive_field.cc",
+        "src/google/protobuf/compiler/java/java_primitive_field_lite.cc",
+        "src/google/protobuf/compiler/java/java_service.cc",
+        "src/google/protobuf/compiler/java/java_shared_code_generator.cc",
+        "src/google/protobuf/compiler/java/java_string_field.cc",
+        "src/google/protobuf/compiler/java/java_string_field_lite.cc",
+        "src/google/protobuf/compiler/javanano/javanano_enum.cc",
+        "src/google/protobuf/compiler/javanano/javanano_enum_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_extension.cc",
+        "src/google/protobuf/compiler/javanano/javanano_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_file.cc",
+        "src/google/protobuf/compiler/javanano/javanano_generator.cc",
+        "src/google/protobuf/compiler/javanano/javanano_helpers.cc",
+        "src/google/protobuf/compiler/javanano/javanano_map_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_message.cc",
+        "src/google/protobuf/compiler/javanano/javanano_message_field.cc",
+        "src/google/protobuf/compiler/javanano/javanano_primitive_field.cc",
+        "src/google/protobuf/compiler/js/js_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_extension.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_file.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_helpers.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_map_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_message_field.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_oneof.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc",
+        "src/google/protobuf/compiler/plugin.cc",
+        "src/google/protobuf/compiler/plugin.pb.cc",
+        "src/google/protobuf/compiler/python/python_generator.cc",
+        "src/google/protobuf/compiler/ruby/ruby_generator.cc",
+        "src/google/protobuf/compiler/subprocess.cc",
+        "src/google/protobuf/compiler/zip_writer.cc",
+    ],
+    copts = COPTS,
+    includes = ["src/"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protobuf"],
+)
+
+cc_binary(
+    name = "protoc",
+    srcs = ["src/google/protobuf/compiler/main.cc"],
+    linkopts = LINK_OPTS,
+    visibility = ["//visibility:public"],
+    deps = [":protoc_lib"],
+)
+
+################################################################################
+# Tests
+################################################################################
+
+RELATIVE_LITE_TEST_PROTOS = [
+    # AUTOGEN(lite_test_protos)
+    "google/protobuf/map_lite_unittest.proto",
+    "google/protobuf/unittest_import_lite.proto",
+    "google/protobuf/unittest_import_public_lite.proto",
+    "google/protobuf/unittest_lite.proto",
+    "google/protobuf/unittest_no_arena_lite.proto",
+]
+
+LITE_TEST_PROTOS = ["src/" + s for s in RELATIVE_LITE_TEST_PROTOS]
+
+RELATIVE_TEST_PROTOS = [
+    # AUTOGEN(test_protos)
+    "google/protobuf/any_test.proto",
+    "google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto",
+    "google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto",
+    "google/protobuf/map_proto2_unittest.proto",
+    "google/protobuf/map_unittest.proto",
+    "google/protobuf/unittest.proto",
+    "google/protobuf/unittest_arena.proto",
+    "google/protobuf/unittest_custom_options.proto",
+    "google/protobuf/unittest_drop_unknown_fields.proto",
+    "google/protobuf/unittest_embed_optimize_for.proto",
+    "google/protobuf/unittest_empty.proto",
+    "google/protobuf/unittest_enormous_descriptor.proto",
+    "google/protobuf/unittest_import.proto",
+    "google/protobuf/unittest_import_public.proto",
+    "google/protobuf/unittest_lite_imports_nonlite.proto",
+    "google/protobuf/unittest_mset.proto",
+    "google/protobuf/unittest_mset_wire_format.proto",
+    "google/protobuf/unittest_no_arena.proto",
+    "google/protobuf/unittest_no_arena_import.proto",
+    "google/protobuf/unittest_no_field_presence.proto",
+    "google/protobuf/unittest_no_generic_services.proto",
+    "google/protobuf/unittest_optimize_for.proto",
+    "google/protobuf/unittest_preserve_unknown_enum.proto",
+    "google/protobuf/unittest_preserve_unknown_enum2.proto",
+    "google/protobuf/unittest_proto3_arena.proto",
+    "google/protobuf/unittest_proto3_arena_lite.proto",
+    "google/protobuf/unittest_proto3_lite.proto",
+    "google/protobuf/unittest_well_known_types.proto",
+    "google/protobuf/util/internal/testdata/anys.proto",
+    "google/protobuf/util/internal/testdata/books.proto",
+    "google/protobuf/util/internal/testdata/default_value.proto",
+    "google/protobuf/util/internal/testdata/default_value_test.proto",
+    "google/protobuf/util/internal/testdata/field_mask.proto",
+    "google/protobuf/util/internal/testdata/maps.proto",
+    "google/protobuf/util/internal/testdata/oneofs.proto",
+    "google/protobuf/util/internal/testdata/struct.proto",
+    "google/protobuf/util/internal/testdata/timestamp_duration.proto",
+    "google/protobuf/util/json_format_proto3.proto",
+    "google/protobuf/util/message_differencer_unittest.proto",
+]
+
+TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
+
+cc_proto_library(
+    name = "cc_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    protoc = ":protoc",
+    deps = [":cc_wkt_protos"],
+)
+
+COMMON_TEST_SRCS = [
+    # AUTOGEN(common_test_srcs)
+    "src/google/protobuf/arena_test_util.cc",
+    "src/google/protobuf/map_test_util.cc",
+    "src/google/protobuf/test_util.cc",
+    "src/google/protobuf/testing/file.cc",
+    "src/google/protobuf/testing/googletest.cc",
+]
+
+cc_binary(
+    name = "test_plugin",
+    srcs = [
+        # AUTOGEN(test_plugin_srcs)
+        "src/google/protobuf/compiler/mock_code_generator.cc",
+        "src/google/protobuf/compiler/test_plugin.cc",
+        "src/google/protobuf/testing/file.cc",
+    ],
+    deps = [
+        ":protobuf",
+        ":protoc_lib",
+        "//external:gtest",
+    ],
+)
+
+cc_test(
+    name = "protobuf_test",
+    srcs = COMMON_TEST_SRCS + [
+        # AUTOGEN(test_srcs)
+        "src/google/protobuf/any_test.cc",
+        "src/google/protobuf/arena_unittest.cc",
+        "src/google/protobuf/arenastring_unittest.cc",
+        "src/google/protobuf/compiler/command_line_interface_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc",
+        "src/google/protobuf/compiler/cpp/cpp_unittest.cc",
+        "src/google/protobuf/compiler/cpp/metadata_test.cc",
+        "src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc",
+        "src/google/protobuf/compiler/importer_unittest.cc",
+        "src/google/protobuf/compiler/java/java_doc_comment_unittest.cc",
+        "src/google/protobuf/compiler/java/java_plugin_unittest.cc",
+        "src/google/protobuf/compiler/mock_code_generator.cc",
+        "src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc",
+        "src/google/protobuf/compiler/parser_unittest.cc",
+        "src/google/protobuf/compiler/python/python_plugin_unittest.cc",
+        "src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc",
+        "src/google/protobuf/descriptor_database_unittest.cc",
+        "src/google/protobuf/descriptor_unittest.cc",
+        "src/google/protobuf/drop_unknown_fields_test.cc",
+        "src/google/protobuf/dynamic_message_unittest.cc",
+        "src/google/protobuf/extension_set_unittest.cc",
+        "src/google/protobuf/generated_message_reflection_unittest.cc",
+        "src/google/protobuf/io/coded_stream_unittest.cc",
+        "src/google/protobuf/io/printer_unittest.cc",
+        "src/google/protobuf/io/tokenizer_unittest.cc",
+        "src/google/protobuf/io/zero_copy_stream_unittest.cc",
+        "src/google/protobuf/map_field_test.cc",
+        "src/google/protobuf/map_test.cc",
+        "src/google/protobuf/message_unittest.cc",
+        "src/google/protobuf/no_field_presence_test.cc",
+        "src/google/protobuf/preserve_unknown_enum_test.cc",
+        "src/google/protobuf/proto3_arena_lite_unittest.cc",
+        "src/google/protobuf/proto3_arena_unittest.cc",
+        "src/google/protobuf/proto3_lite_unittest.cc",
+        "src/google/protobuf/reflection_ops_unittest.cc",
+        "src/google/protobuf/repeated_field_reflection_unittest.cc",
+        "src/google/protobuf/repeated_field_unittest.cc",
+        "src/google/protobuf/stubs/bytestream_unittest.cc",
+        "src/google/protobuf/stubs/common_unittest.cc",
+        "src/google/protobuf/stubs/int128_unittest.cc",
+        "src/google/protobuf/stubs/once_unittest.cc",
+        "src/google/protobuf/stubs/status_test.cc",
+        "src/google/protobuf/stubs/statusor_test.cc",
+        "src/google/protobuf/stubs/stringpiece_unittest.cc",
+        "src/google/protobuf/stubs/stringprintf_unittest.cc",
+        "src/google/protobuf/stubs/structurally_valid_unittest.cc",
+        "src/google/protobuf/stubs/strutil_unittest.cc",
+        "src/google/protobuf/stubs/template_util_unittest.cc",
+        "src/google/protobuf/stubs/time_test.cc",
+        "src/google/protobuf/stubs/type_traits_unittest.cc",
+        "src/google/protobuf/text_format_unittest.cc",
+        "src/google/protobuf/unknown_field_set_unittest.cc",
+        "src/google/protobuf/util/field_comparator_test.cc",
+        "src/google/protobuf/util/field_mask_util_test.cc",
+        "src/google/protobuf/util/internal/default_value_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/json_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/json_stream_parser_test.cc",
+        "src/google/protobuf/util/internal/protostream_objectsource_test.cc",
+        "src/google/protobuf/util/internal/protostream_objectwriter_test.cc",
+        "src/google/protobuf/util/internal/type_info_test_helper.cc",
+        "src/google/protobuf/util/json_util_test.cc",
+        "src/google/protobuf/util/message_differencer_unittest.cc",
+        "src/google/protobuf/util/time_util_test.cc",
+        "src/google/protobuf/util/type_resolver_util_test.cc",
+        "src/google/protobuf/well_known_types_unittest.cc",
+        "src/google/protobuf/wire_format_unittest.cc",
+    ],
+    copts = COPTS,
+    data = [
+        ":test_plugin",
+    ] + glob([
+        "src/google/protobuf/**/*",
+    ]),
+    includes = [
+        "src/",
+    ],
+    linkopts = LINK_OPTS,
+    deps = [
+        ":cc_test_protos",
+        ":protobuf",
+        ":protoc_lib",
+        "//external:gtest_main",
+    ],
+)
+
+################################################################################
+# Java support
+################################################################################
+internal_gen_well_known_protos_java(
+    srcs = WELL_KNOWN_PROTOS,
+)
+
+java_library(
+    name = "protobuf_java",
+    srcs = glob([
+        "java/core/src/main/java/com/google/protobuf/*.java",
+    ]) + [
+        ":gen_well_known_protos_java",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "protobuf_java_util",
+    srcs = glob([
+        "java/util/src/main/java/com/google/protobuf/util/*.java",
+    ]),
+    deps = [
+        "protobuf_java",
+        "//external:gson",
+        "//external:guava",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Python support
+################################################################################
+
+py_library(
+    name = "python_srcs",
+    srcs = glob(
+        [
+            "python/google/protobuf/*.py",
+            "python/google/protobuf/**/*.py",
+        ],
+        exclude = [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    srcs_version = "PY2AND3",
+    imports = ["python"],
+)
+
+cc_binary(
+    name = "internal/_api_implementation.so",
+    srcs = ["python/google/protobuf/internal/api_implementation.cc"],
+    copts = COPTS + [
+        "-DPYTHON_PROTO2_CPP_IMPL_V2",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//external:python_headers"],
+    }),
+)
+
+cc_binary(
+    name = "pyext/_message.so",
+    srcs = glob([
+        "python/google/protobuf/pyext/*.cc",
+        "python/google/protobuf/pyext/*.h",
+    ]),
+    copts = COPTS + [
+        "-DGOOGLE_PROTOBUF_HAS_ONEOF=1",
+    ] + select({
+        "//conditions:default": [],
+        ":allow_oversize_protos": ["-DPROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS=1"],
+    }),
+    includes = [
+        "python/",
+        "src/",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = [
+        ":protobuf",
+    ] + select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//external:python_headers"],
+    }),
+)
+
+config_setting(
+    name = "use_fast_cpp_protos",
+    values = {
+        "define": "use_fast_cpp_protos=true",
+    },
+)
+
+config_setting(
+    name = "allow_oversize_protos",
+    values = {
+        "define": "allow_oversize_protos=true",
+    },
+)
+
+py_proto_library(
+    name = "protobuf_python",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    data = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": [
+            ":internal/_api_implementation.so",
+            ":pyext/_message.so",
+        ],
+    }),
+    default_runtime = "",
+    protoc = ":protoc",
+    py_libs = [
+        ":python_srcs",
+        "//external:six"
+    ],
+    srcs_version = "PY2AND3",
+    visibility = ["//visibility:public"],
+)
+
+py_proto_library(
+    name = "python_common_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = "",
+    protoc = ":protoc",
+    srcs_version = "PY2AND3",
+    deps = [":protobuf_python"],
+)
+
+py_proto_library(
+    name = "python_specific_test_protos",
+    srcs = glob([
+        "python/google/protobuf/internal/*.proto",
+        "python/google/protobuf/internal/import_test_package/*.proto",
+    ]),
+    include = "python",
+    default_runtime = ":protobuf_python",
+    protoc = ":protoc",
+    srcs_version = "PY2AND3",
+    deps = [":python_common_test_protos"],
+)
+
+py_library(
+    name = "python_tests",
+    srcs = glob(
+        [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    imports = ["python"],
+    srcs_version = "PY2AND3",
+    deps = [
+        ":protobuf_python",
+        ":python_common_test_protos",
+        ":python_specific_test_protos",
+    ],
+)
+
+internal_protobuf_py_tests(
+    name = "python_tests_batch",
+    data = glob([
+        "src/google/protobuf/**/*",
+    ]),
+    modules = [
+        "descriptor_database_test",
+        "descriptor_pool_test",
+        "descriptor_test",
+        "generator_test",
+        "json_format_test",
+        "message_factory_test",
+        "message_test",
+        "proto_builder_test",
+        "reflection_test",
+        "service_reflection_test",
+        "symbol_database_test",
+        "text_encoding_test",
+        "text_format_test",
+        "unknown_fields_test",
+        "wire_format_test",
+    ],
+    deps = [":python_tests"],
+)
diff --git a/util/CHANGES.txt b/util/CHANGES.txt
new file mode 100644
index 0000000..3459ccc
--- /dev/null
+++ b/util/CHANGES.txt
@@ -0,0 +1,1182 @@
+2016-05-16 version 3.0.0-beta-3 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
+  General
+  * Supported Proto3 lite-runtime in C++/Java for mobile platforms.
+  * Any type now supports APIs to specify prefixes other than
+    type.googleapis.com
+  * Removed javanano_use_deprecated_package option; Nano will always has its own
+    ".nano" package.
+
+  C++ (Beta)
+  * Improved hash maps.
+      - Improved hash maps comments. In particular, please note that equal hash
+        maps will not necessarily have the same iteration order and
+        serialization.
+      - Added a new hash maps implementation that will become the default in a
+        later release.
+  * Arenas
+      - Several inlined methods in Arena were moved to out-of-line to improve
+        build performance and code size.
+      - Added SpaceAllocatedAndUsed() to report both space used and allocated
+      - Added convenient class UnsafeArenaAllocatedRepeatedPtrFieldBackInserter
+  * Any
+      - Allow custom type URL prefixes in Any packing.
+      - TextFormat now expand the Any type rather than printing bytes.
+  * Performance optimizations and various bug fixes.
+
+  Java (Beta)
+  * Introduced an ExperimentalApi annotation. Annotated APIs are experimental
+    and are subject to change in a backward incompatible way in future releases.
+  * Introduced zero-copy serialization as an ExperimentalApi
+      - Introduction of the `ByteOutput` interface. This is similar to
+        `OutputStream` but provides semantics for lazy writing (i.e. no
+        immediate copy required) of fields that are considered to be immutable.
+      - `ByteString` now supports writing to a `ByteOutput`, which will directly
+        expose the internals of the `ByteString` (i.e. `byte[]` or `ByteBuffer`)
+        to the `ByteOutput` without copying.
+      - `CodedOutputStream` now supports writing to a `ByteOutput`. `ByteString`
+        instances that are too large to fit in the internal buffer will be
+        (lazily) written to the `ByteOutput` directly.
+      - This allows applications using large `ByteString` fields to avoid
+        duplication of these fields entirely. Such an application can supply a
+        `ByteOutput` that chains together the chunks received from
+        `CodedOutputStream` before forwarding them onto the IO system.
+  * Other related changes to `CodedOutputStream`
+      - Additional use of `sun.misc.Unsafe` where possible to perform fast
+        access to `byte[]` and `ByteBuffer` values and avoiding unnecessary
+        range checking.
+      - `ByteBuffer`-backed `CodedOutputStream` now writes directly to the
+        `ByteBuffer` rather than to an intermediate array.
+  * Improved lite-runtime.
+      - Lite protos now implement deep equals/hashCode/toString
+      - Significantly improved the performance of Builder#mergeFrom() and
+        Builder#mergeDelimitedFrom()
+  * Various bug fixes and small feature enhancement.
+      - Fixed stack overflow when in hashCode() for infinite recursive oneofs.
+      - Fixed the lazy field parsing in lite to merge rather than overwrite.
+      - TextFormat now supports reporting line/column numbers on errors.
+      - Updated to add appropriate @Override for better compiler errors.
+
+  Python (Beta)
+  * Added JSON format for Any, Struct, Value and ListValue
+  * [ ] is now accepted for both repeated scalar fields and repeated message
+    fields in text format parser.
+  * Numerical field name is now supported in text format.
+  * Added DiscardUnknownFields API for python protobuf message.
+
+  Objective-C (Beta)
+  * Proto comments now come over as HeaderDoc comments in the generated sources
+    so Xcode can pick them up and display them.
+  * The library headers have been updated to use HeaderDoc comments so Xcode can
+    pick them up and display them.
+  * The per message and per field overhead in both generated code and runtime
+    object sizes was reduced.
+  * Generated code now include deprecated annotations when the proto file
+    included them.
+
+  C# (Beta)
+  In general: some changes are breaking, which require regenerating messages.
+  Most user-written code will not be impacted *except* for the renaming of enum
+  values.
+
+  * Allow custom type URL prefixes in `Any` packing, and ignore them when
+    unpacking
+  * `protoc` is now in a separate NuGet package (Google.Protobuf.Tools)
+  * New option: `internal_access` to generate internal classes
+  * Enum values are now PascalCased, and if there's a prefix which matches the
+    name of the enum, that is removed (so an enum `COLOR` with a value
+    `COLOR_BLUE` would generate a value of just `Blue`). An option
+    (`legacy_enum_values`) is temporarily available to disable this, but the
+    option will be removed for GA.
+  * `json_name` option is now honored
+  * If group tags are encountered when parsing, they are validated more
+    thoroughly (although we don't support actual groups)
+  * NuGet dependencies are better specified
+  * Breaking: `Preconditions` is renamed to `ProtoPreconditions`
+  * Breaking: `GeneratedCodeInfo` is renamed to `GeneratedClrTypeInfo`
+  * `JsonFormatter` now allows writing to a `TextWriter`
+  * New interface, `ICustomDiagnosticMessage` to allow more compact
+    representations from `ToString`
+  * `CodedInputStream` and `CodedOutputStream` now implement `IDisposable`,
+    which simply disposes of the streams they were constructed with
+  * Map fields no longer support null values (in line with other languages)
+  * Improvements in JSON formatting and parsing
+
+  Javascript (Alpha)
+  * Better support for "bytes" fields: bytes fields can be read as either a
+    base64 string or UInt8Array (in environments where TypedArray is supported).
+  * New support for CommonJS imports.  This should make it easier to use the
+    JavaScript support in Node.js and tools like WebPack.  See js/README.md for
+    more information.
+  * Some significant internal refactoring to simplify and modularize the code.
+
+  Ruby (Alpha)
+  * JSON serialization now properly uses camelCased names, with a runtime option
+    that will preserve original names from .proto files instead.
+  * Well-known types are now included in the distribution.
+  * Release now includes binary gems for Windows, Mac, and Linux instead of just
+    source gems.
+  * Bugfix for serializing oneofs.
+
+  C++/Java Lite (Alpha)
+    A new "lite" generator parameter was introduced in the protoc for C++ and
+    Java for Proto3 syntax messages. Example usage:
+
+     ./protoc --cpp_out=lite:$OUTPUT_PATH foo.proto
+
+    The protoc will treat the current input and all the transitive dependencies
+    as LITE. The same generator parameter must be used to generate the
+    dependencies.
+
+    In Proto3 syntax files, "optimized_for=LITE_RUNTIME" is no longer supported.
+
+
+2015-12-30 version 3.0.0-beta-2 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
+  General
+  * Introduced a new language implementation: JavaScript.
+  * Added a new field option "json_name". By default proto field names are
+    converted to "lowerCamelCase" in proto3 JSON format. This option can be
+    used to override this behavior and specify a different JSON name for the
+    field.
+  * Added conformance tests to ensure implementations are following proto3 JSON
+    specification.
+
+  C++ (Beta)
+  * Various bug fixes and improvements to the JSON support utility:
+      - Duplicate map keys in JSON are now rejected (i.e., translation will
+        fail).
+      - Fixed wire-format for google.protobuf.Value/ListValue.
+      - Fixed precision loss when converting google.protobuf.Timestamp.
+      - Fixed a bug when parsing invalid UTF-8 code points.
+      - Fixed a memory leak.
+      - Reduced call stack usage.
+
+  Java (Beta)
+  * Cleaned up some unused methods on CodedOutputStream.
+  * Presized lists for packed fields during parsing in the lite runtime to
+    reduce allocations and improve performance.
+  * Improved the performance of unknown fields in the lite runtime.
+  * Introduced UnsafeByteStrings to support zero-copy ByteString creation.
+  * Various bug fixes and improvements to the JSON support utility:
+      - Fixed a thread-safety bug.
+      - Added a new option “preservingProtoFieldNames” to JsonFormat.
+      - Added a new option “includingDefaultValueFields” to JsonFormat.
+      - Updated the JSON utility to comply with proto3 JSON specification.
+
+  Python (Beta)
+  * Added proto3 JSON format utility. It includes support for all field types
+    and a few well-known types except for Any and Struct.
+  * Added runtime support for Any, Timestamp, Duration and FieldMask.
+  * [ ] is now accepted for repeated scalar fields in text format parser.
+  * Map fields now have proper O(1) performance for lookup/insert/delete
+    when using the Python/C++ implementation. They were previously using O(n)
+    search-based algorithms because the C++ reflection interface didn't
+    support true map operations.
+
+  Objective-C (Beta)
+  * Various bug-fixes and code tweaks to pass more strict compiler warnings.
+  * Now has conformance test coverage and is passing all tests.
+
+  C# (Beta)
+  * Various bug-fixes.
+  * Code generation: Files generated in directories based on namespace.
+  * Code generation: Include comments from .proto files in XML doc
+    comments (naively)
+  * Code generation: Change organization/naming of "reflection class" (access
+    to file descriptor)
+  * Code generation and library: Add Parser property to MessageDescriptor,
+    and introduce a non-generic parser type.
+  * Library: Added TypeRegistry to support JSON parsing/formatting of Any.
+  * Library: Added Any.Pack/Unpack support.
+  * Library: Implemented JSON parsing.
+
+  Javascript (Alpha)
+  * Added proto3 support for JavaScript. The runtime is written in pure
+    JavaScript and works in browsers and in Node.js. To generate JavaScript
+    code for your proto, invoke protoc with "--js_out". See js/README.md
+    for more build instructions.
+
+2015-08-26 version 3.0.0-beta-1 (C++/Java/Python/Ruby/Nano/Objective-C/C#)
+  About Beta
+  * This is the first beta release of protobuf v3.0.0. Not all languages
+    have reached beta stage. Languages not marked as beta are still in
+    alpha (i.e., be prepared for API breaking changes).
+
+  General
+  * Proto3 JSON is supported in several languages (fully supported in C++
+    and Java, partially supported in Ruby/C#). The JSON spec is defined in
+    the proto3 language guide:
+
+      https://developers.google.com/protocol-buffers/docs/proto3#json
+
+    We will publish a more detailed spec to define the exact behavior of
+    proto3-conformant JSON serializers and parsers. Until then, do not rely
+    on specific behaviors of the implementation if it’s not documented in
+    the above spec. More specifically, the behavior is not yet finalized for
+    the following:
+      - Parsing invalid JSON input (e.g., input with trailing commas).
+      - Non-camelCase names in JSON input.
+      - The same field appears multiple times in JSON input.
+      - JSON arrays contain “null” values.
+      - The message has unknown fields.
+
+  * Proto3 now enforces strict UTF-8 checking. Parsing will fail if a string
+    field contains non UTF-8 data.
+
+  C++ (Beta)
+  * Introduced new utility functions/classes in the google/protobuf/util
+    directory:
+      - MessageDifferencer: compare two proto messages and report their
+                            differences.
+      - JsonUtil: support converting protobuf binary format to/from JSON.
+      - TimeUtil: utility functions to work with well-known types Timestamp
+                  and Duration.
+      - FieldMaskUtil: utility functions to work with FieldMask.
+
+  * Performance optimization of arena construction and destruction.
+  * Bug fixes for arena and maps support.
+  * Changed to use cmake for Windows Visual Studio builds.
+  * Added Bazel support.
+
+  Java (Beta)
+  * Introduced a new util package that will be distributed as a separate
+    artifact in maven. It contains:
+      - JsonFormat: convert proto messages to/from JSON.
+      - TimeUtil: utility functions to work with Timestamp and Duration.
+      - FieldMaskUtil: utility functions to work with FieldMask.
+
+  * The static PARSER in each generated message is deprecated, and it will
+    be removed in a future release. A static parser() getter is generated
+    for each message type instead.
+  * Performance optimizations for String fields serialization.
+  * Performance optimizations for Lite runtime on Android:
+      - Reduced allocations
+      - Reduced method overhead after ProGuarding
+      - Reduced code size after ProGuarding
+
+  Python (Alpha)
+  * Removed legacy Python 2.5 support.
+  * Moved to a single Python 2.x/3.x-compatible codebase, instead of using 2to3.
+  * Fixed build/tests on Python 2.6, 2.7, 3.3, and 3.4.
+      - Pure-Python works on all four.
+      - Python/C++ implementation works on all but 3.4, due to changes in the
+        Python/C++ API in 3.4.
+  * Some preliminary work has been done to allow for multiple DescriptorPools
+    with Python/C++.
+
+  Ruby (Alpha)
+  * Many bugfixes:
+      - fixed parsing/serialization of bytes, sint, sfixed types
+      - other parser bugfixes
+      - fixed memory leak affecting Ruby 2.2
+
+  JavaNano (Alpha)
+  * JavaNano generated code now will be put in a nano package by default to
+    avoid conflicts with Java generated code.
+
+  Objective-C (Alpha)
+  * Added non-null markup to ObjC library. Requires SDK 8.4+ to build.
+  * Many bugfixes:
+      - Removed the class/enum filter.
+      - Renamed some internal types to avoid conflicts with the well-known types
+        protos.
+      - Added missing support for parsing repeated primitive fields in packed or
+        unpacked forms.
+      - Added *Count for repeated and map<> fields to avoid auto-create when
+        checking for them being set.
+
+  C# (Alpha)
+  * Namespace changed to Google.Protobuf (and NuGet package will be named
+    correspondingly).
+  * Target platforms now .NET 4.5 and selected portable subsets only.
+  * Removed lite runtime.
+  * Reimplementation to use mutable message types.
+  * Null references used to represent "no value" for message type fields.
+  * Proto3 semantics supported; proto2 files are prohibited for C# codegen.
+    Most proto3 features supported:
+      - JSON formatting (a.k.a. serialization to JSON), including well-known
+        types (except for Any).
+      - Wrapper types mapped to nullable value types (or string/ByteString
+        allowing nullability). JSON parsing is not supported yet.
+      - maps
+      - oneof
+      - enum unknown value preservation
+
+2015-05-25 version 3.0.0-alpha-3 (Objective-C/C#):
+  General
+  * Introduced two new language implementations (Objective-C, C#) to proto3.
+  * Explicit "optional" keyword are disallowed in proto3 syntax, as fields are
+    optional by default.
+  * Group fields are no longer supported in proto3 syntax.
+  * Changed repeated primitive fields to use packed serialization by default in
+    proto3 (implemented for C++, Java, Python in this release).  The user can
+    still disable packed serialization by setting packed to false for now.
+  * Added well-known type protos (any.proto, empty.proto, timestamp.proto,
+    duration.proto, etc.). Users can import and use these protos just like
+    regular proto files. Additional runtime support will be added for them in
+    future releases (in the form of utility helper functions, or having them
+    replaced by language specific types in generated code).
+  * Added a "reserved" keyword in both proto2 and proto3 syntax. User can use
+    this keyword to declare reserved field numbers and names to prevent them
+    from being reused by other fields in the same message.
+
+    To reserve field numbers, add a reserved declaration in your message:
+
+      message TestMessage {
+        reserved 2, 15, 9 to 11, 3;
+      }
+
+    This reserves field numbers 2, 3, 9, 10, 11 and 15. If a user uses any of
+    these as field numbers, the protocol buffer compiler will report an error.
+
+    Field names can also be reserved:
+
+      message TestMessage {
+        reserved "foo", "bar";
+      }
+
+  * Various bug fixes since 3.0.0-alpha-2
+
+  Objective-C
+    Objective-C includes a code generator and a native objective-c runtime
+    library.  By adding “--objc_out” to protoc, the code generator will generate
+    a header(*.pbobjc.h) and an implementation file(*.pbobjc.m) for each proto
+    file.
+
+    In this first release, the generated interface provides: enums, messages,
+    field support(single, repeated, map, oneof), proto2 and proto3 syntax
+    support, parsing and serialization. It’s  compatible with ARC and non-ARC
+    usage. Besides, user can also access it via the swift bridging header.
+
+    See objectivec/README.md for details.
+
+  C#
+    * C# protobufs are based on project
+      https://github.com/jskeet/protobuf-csharp-port. The original project was
+      frozen and all the new development will happen here.
+    * Codegen plugin for C# was completely rewritten to C++ and is now an
+      integral part of protoc.
+    * Some refactorings and cleanup has been applied to the C# runtime library.
+    * Only proto2 is supported in C# at the moment, proto3 support is in
+      progress and will likely bring significant breaking changes to the API.
+
+    See csharp/README.md for details.
+
+  C++
+    * Added runtime support for Any type. To use Any in your proto file, first
+      import the definition of Any:
+
+        // foo.proto
+        import "google/protobuf/any.proto";
+        message Foo {
+          google.protobuf.Any any_field = 1;
+        }
+        message Bar {
+          int32 value = 1;
+        }
+
+      Then in C++ you can access the Any field using PackFrom()/UnpackTo()
+      methods:
+
+        Foo foo;
+        Bar bar = ...;
+        foo.mutable_any_field()->PackFrom(bar);
+        ...
+        if (foo.any_field().IsType<Bar>()) {
+          foo.any_field().UnpackTo(&bar);
+          ...
+        }
+    * In text format, entries of a map field will be sorted by key.
+
+  Java
+    * Continued optimizations on the lite runtime to improve performance for
+      Android.
+
+  Python
+    * Added map support.
+      - maps now have a dict-like interface (msg.map_field[key] = value)
+      - existing code that modifies maps via the repeated field interface
+        will need to be updated.
+
+  Ruby
+    * Improvements to RepeatedField's emulation of the Ruby Array API.
+    * Various speedups and internal cleanups.
+
+2015-02-26 version 3.0.0-alpha-2 (Python/Ruby/JavaNano):
+  General
+  * Introduced three new language implementations (Ruby, JavaNano, and
+    Python) to proto3.
+  * Various bug fixes since 3.0.0-alpha-1
+
+  Python:
+    Python has received several updates, most notably support for proto3
+    semantics in any .proto file that declares syntax="proto3".
+    Messages declared in proto3 files no longer represent field presence
+    for scalar fields (number, enums, booleans, or strings).  You can
+    no longer call HasField() for such fields, and they are serialized
+    based on whether they have a non-zero/empty/false value.
+
+    One other notable change is in the C++-accelerated implementation.
+    Descriptor objects (which describe the protobuf schema and allow
+    reflection over it) are no longer duplicated between the Python
+    and C++ layers.  The Python descriptors are now simple wrappers
+    around the C++ descriptors.  This change should significantly
+    reduce the memory usage of programs that use a lot of message
+    types.
+
+  Ruby:
+    We have added proto3 support for Ruby via a native C extension.
+
+    The Ruby extension itself is included in the ruby/ directory, and details on
+    building and installing the extension are in ruby/README.md. The extension
+    will also be published as a Ruby gem. Code generator support is included as
+    part of `protoc` with the `--ruby_out` flag.
+
+    The Ruby extension implements a user-friendly DSL to define message types
+    (also generated by the code generator from `.proto` files).  Once a message
+    type is defined, the user may create instances of the message that behave in
+    ways idiomatic to Ruby. For example:
+
+    - Message fields are present as ordinary Ruby properties (getter method
+      `foo` and setter method `foo=`).
+    - Repeated field elements are stored in a container that acts like a native
+      Ruby array, and map elements are stored in a container that acts like a
+      native Ruby hashmap.
+    - The usual well-known methods, such as `#to_s`, `#dup`, and the like, are
+      present.
+
+    Unlike several existing third-party Ruby extensions for protobuf, this
+    extension is built on a "strongly-typed" philosophy: message fields and
+    array/map containers will throw exceptions eagerly when values of the
+    incorrect type are inserted.
+
+    See ruby/README.md for details.
+
+  JavaNano:
+    JavaNano is a special code generator and runtime library designed especially
+    for resource-restricted systems, like Android. It is very resource-friendly
+    in both the amount of code and the runtime overhead. Here is an an overview
+    of JavaNano features compared with the official Java protobuf:
+
+    - No descriptors or message builders.
+    - All messages are mutable; fields are public Java fields.
+    - For optional fields only, encapsulation behind setter/getter/hazzer/
+      clearer functions is opt-in, which provide proper 'has' state support.
+    - For proto2, if not opted in, has state (field presence) is not available.
+      Serialization outputs all fields not equal to their defaults.
+      The behavior is consistent with proto3 semantics.
+    - Required fields (proto2 only) are always serialized.
+    - Enum constants are integers; protection against invalid values only
+      when parsing from the wire.
+    - Enum constants can be generated into container interfaces bearing
+      the enum's name (so the referencing code is in Java style).
+    - CodedInputByteBufferNano can only take byte[] (not InputStream).
+    - Similarly CodedOutputByteBufferNano can only write to byte[].
+    - Repeated fields are in arrays, not ArrayList or Vector. Null array
+      elements are allowed and silently ignored.
+    - Full support for serializing/deserializing repeated packed fields.
+    - Support  extensions (in proto2).
+    - Unset messages/groups are null, not an immutable empty default
+      instance.
+    - toByteArray(...) and mergeFrom(...) are now static functions of
+      MessageNano.
+    - The 'bytes' type translates to the Java type byte[].
+
+    See javanano/README.txt for details.
+
+2014-12-01 version 3.0.0-alpha-1 (C++/Java):
+
+  General
+  * Introduced Protocol Buffers language version 3 (aka proto3).
+
+    When protobuf was initially opensourced it implemented Protocol Buffers
+    language version 2 (aka proto2), which is why the version number
+    started from v2.0.0. From v3.0.0, a new language version (proto3) is
+    introduced while the old version (proto2) will continue to be supported.
+
+    The main intent of introducing proto3 is to clean up protobuf before
+    pushing the language as the foundation of Google's new API platform.
+    In proto3, the language is simplified, both for ease of use and  to
+    make it available in a wider range of programming languages. At the
+    same time a few features are added to better support common idioms
+    found in APIs.
+
+    The following are the main new features in language version 3:
+
+      1. Removal of field presence logic for primitive value fields, removal
+         of required fields, and removal of default values. This makes proto3
+         significantly easier to implement with open struct representations,
+         as in languages like Android Java, Objective C, or Go.
+      2. Removal of unknown fields.
+      3. Removal of extensions, which are instead replaced by a new standard
+         type called Any.
+      4. Fix semantics for unknown enum values.
+      5. Addition of maps.
+      6. Addition of a small set of standard types for representation of time,
+         dynamic data, etc.
+      7. A well-defined encoding in JSON as an alternative to binary proto
+         encoding.
+
+    This release (v3.0.0-alpha-1) includes partial proto3 support for C++ and
+    Java. Items 6 (well-known types) and 7 (JSON format) in the above feature
+    list are not implemented.
+
+    A new notion "syntax" is introduced to specify whether a .proto file
+    uses proto2 or proto3:
+
+      // foo.proto
+      syntax = "proto3";
+      message Bar {...}
+
+    If omitted, the protocol compiler will generate a warning and "proto2" will
+    be used as the default. This warning will be turned into an error in a
+    future release.
+
+    We recommend that new Protocol Buffers users use proto3. However, we do not
+    generally recommend that existing users migrate from proto2 from proto3 due
+    to API incompatibility, and we will continue to support proto2 for a long
+    time.
+
+  * Added support for map fields (implemented in C++/Java for both proto2 and
+    proto3).
+
+    Map fields can be declared using the following syntax:
+
+      message Foo {
+        map<string, string> values = 1;
+      }
+
+    Data of a map field will be stored in memory as an unordered map and it
+    can be accessed through generated accessors.
+
+  C++
+  * Added arena allocation support (for both proto2 and proto3).
+
+    Profiling shows memory allocation and deallocation constitutes a significant
+    fraction of CPU-time spent in protobuf code and arena allocation is a
+    technique introduced to reduce this cost. With arena allocation, new
+    objects will be allocated from a large piece of preallocated memory and
+    deallocation of these objects is almost free. Early adoption shows 20% to
+    50% improvement in some Google binaries.
+
+    To enable arena support, add the following option to your .proto file:
+
+      option cc_enable_arenas = true;
+
+    Protocol compiler will generate additional code to make the generated
+    message classes work with arenas. This does not change the existing API
+    of protobuf messages and does not affect wire format. Your existing code
+    should continue to work after adding this option. In the future we will
+    make this option enabled by default.
+
+    To actually take advantage of arena allocation, you need to use the arena
+    APIs when creating messages. A quick example of using the arena API:
+
+      {
+        google::protobuf::Arena arena;
+        // Allocate a protobuf message in the arena.
+        MyMessage* message = Arena::CreateMessage<MyMessage>(&arena);
+        // All submessages will be allocated in the same arena.
+        if (!message->ParseFromString(data)) {
+          // Deal with malformed input data.
+        }
+        // Must not delete the message here. It will be deleted automatically
+        // when the arena is destroyed.
+      }
+
+    Currently arena does not work with map fields. Enabling arena in a .proto
+    file containing map fields will result in compile errors in the generated
+    code. This will be addressed in a future release.
+
+2014-10-20 version 2.6.1:
+
+  C++
+  * Added atomicops support for Solaris.
+  * Released memory allocated by InitializeDefaultRepeatedFields() and
+    GetEmptyString(). Some memory sanitizers reported them as memory leaks.
+
+  Java
+  * Updated DynamicMessage.setField() to handle repeated enum values
+    correctly.
+  * Fixed a bug that caused NullPointerException to be thrown when
+    converting manually constructed FileDescriptorProto to
+    FileDescriptor.
+
+  Python
+  * Fixed WhichOneof() to work with de-serialized protobuf messages.
+  * Fixed a missing file problem of Python C++ implementation.
+
+2014-08-15 version 2.6.0:
+
+  General
+  * Added oneofs(unions) feature. Fields in the same oneof will share
+    memory and at most one field can be set at the same time. Use the
+    oneof keyword to define a oneof like:
+      message SampleMessage {
+        oneof test_oneof {
+          string name = 4;
+          YourMessage sub_message = 9;
+        }
+      }
+  * Files, services, enums, messages, methods and enum values can be marked
+    as deprecated now.
+  * Added Support for list values, including lists of messages, when
+    parsing text-formatted protos in C++ and Java.
+      For example:  foo: [1, 2, 3]
+
+  C++
+  * Enhanced customization on TestFormat printing.
+  * Added SwapFields() in reflection API to swap a subset of fields.
+    Added SetAllocatedMessage() in reflection API.
+  * Repeated primitive extensions are now packable. The
+    [packed=true] option only affects serializers. Therefore, it is
+    possible to switch a repeated extension field to packed format
+    without breaking backwards-compatibility.
+  * Various speed optimizations.
+
+  Java
+  * writeTo() method in ByteString can now write a substring to an
+    output stream. Added endWith() method for ByteString.
+  * ByteString and ByteBuffer are now supported in CodedInputStream
+    and CodedOutputStream.
+  * java_generate_equals_and_hash can now be used with the LITE_RUNTIME.
+
+  Python
+  * A new C++-backed extension module (aka "cpp api v2") that replaces the
+    old ("cpp api v1") one.  Much faster than the pure Python code.  This one
+    resolves many bugs and is recommended for general use over the
+    pure Python when possible.
+  * Descriptors now have enum_types_by_name and extension_types_by_name dict
+    attributes.
+  * Support for Python 3.
+
+2013-02-27 version 2.5.0:
+
+  General
+  * New notion "import public" that allows a proto file to forward the content
+    it imports to its importers. For example,
+      // foo.proto
+      import public "bar.proto";
+      import "baz.proto";
+
+      // qux.proto
+      import "foo.proto";
+      // Stuff defined in bar.proto may be used in this file, but stuff from
+      // baz.proto may NOT be used without importing it explicitly.
+    This is useful for moving proto files. To move a proto file, just leave
+    a single "import public" in the old proto file.
+  * New enum option "allow_alias" that specifies whether different symbols can
+    be assigned the same numeric value. Default value is "true". Setting it to
+    false causes the compiler to reject enum definitions where multiple symbols
+    have the same numeric value.
+    Note: We plan to flip the default value to "false" in a future release.
+    Projects using enum aliases should set the option to "true" in their .proto
+    files.
+
+  C++
+  * New generated method set_allocated_foo(Type* foo) for message and string
+    fields. This method allows you to set the field to a pre-allocated object
+    and the containing message takes the ownership of that object.
+  * Added SetAllocatedExtension() and ReleaseExtension() to extensions API.
+  * Custom options are now formatted correctly when descriptors are printed in
+    text format.
+  * Various speed optimizations.
+
+  Java
+  * Comments in proto files are now collected and put into generated code as
+    comments for corresponding classes and data members.
+  * Added Parser to parse directly into messages without a Builder. For
+    example,
+      Foo foo = Foo.PARSER.ParseFrom(input);
+    Using Parser is ~25% faster than using Builder to parse messages.
+  * Added getters/setters to access the underlying ByteString of a string field
+    directly.
+  * ByteString now supports more operations: substring(), prepend(), and
+    append(). The implementation of ByteString uses a binary tree structure
+    to support these operations efficiently.
+  * New method findInitializationErrors() that lists all missing required
+    fields.
+  * Various code size and speed optimizations.
+
+  Python
+  * Added support for dynamic message creation. DescriptorDatabase,
+    DescriptorPool, and MessageFactory work like their C++ counterparts to
+    simplify Descriptor construction from *DescriptorProtos, and MessageFactory
+    provides a message instance from a Descriptor.
+  * Added pickle support for protobuf messages.
+  * Unknown fields are now preserved after parsing.
+  * Fixed bug where custom options were not correctly populated. Custom
+    options can be accessed now.
+  * Added EnumTypeWrapper that provides better accessibility to enum types.
+  * Added ParseMessage(descriptor, bytes) to generate a new Message instance
+    from a descriptor and a byte string.
+
+2011-05-01 version 2.4.1:
+
+  C++
+  * Fixed the friendship problem for old compilers to make the library now gcc 3
+    compatible again.
+  * Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.
+
+  Java
+  * Removed usages of JDK 1.6 only features to make the library now JDK 1.5
+    compatible again.
+  * Fixed a bug about negative enum values.
+  * serialVersionUID is now defined in generated messages for java serializing.
+  * Fixed protoc to use java.lang.Object, which makes "Object" now a valid
+    message name again.
+
+  Python
+  * Experimental C++ implementation now requires C++ protobuf library installed.
+    See the README.txt in the python directory for details.
+
+2011-02-02 version 2.4.0:
+
+  General
+  * The RPC (cc|java|py)_generic_services default value is now false instead of
+    true.
+  * Custom options can have aggregate types. For example,
+      message MyOption {
+        optional string comment = 1;
+        optional string author = 2;
+      }
+      extend google.protobuf.FieldOptions {
+        optional MyOption myoption = 12345;
+      }
+    This option can now be set as follows:
+      message SomeType {
+        optional int32 field = 1 [(myoption) = { comment:'x' author:'y' }];
+      }
+
+  C++
+  * Various speed and code size optimizations.
+  * Added a release_foo() method on string and message fields.
+  * Fixed gzip_output_stream sub-stream handling.
+
+  Java
+  * Builders now maintain sub-builders for sub-messages. Use getFooBuilder() to
+    get the builder for the sub-message "foo". This allows you to repeatedly
+    modify deeply-nested sub-messages without rebuilding them.
+  * Builder.build() no longer invalidates the Builder for generated messages
+    (You may continue to modify it and then build another message).
+  * Code generator will generate efficient equals() and hashCode()
+    implementations if new option java_generate_equals_and_hash is enabled.
+    (Otherwise, reflection-based implementations are used.)
+  * Generated messages now implement Serializable.
+  * Fields with [deprecated=true] will be marked with @Deprecated in Java.
+  * Added lazy conversion of UTF-8 encoded strings to String objects to improve
+    performance.
+  * Various optimizations.
+  * Enum value can be accessed directly, instead of calling getNumber() on the
+    enum member.
+  * For each enum value, an integer constant is also generated with the suffix
+    _VALUE.
+
+  Python
+  * Added an experimental  C++ implementation for Python messages via a Python
+    extension. Implementation type is controlled by an environment variable
+    PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION (valid values: "cpp" and "python")
+    The default value is currently "python" but will be changed to "cpp" in
+    future release.
+  * Improved performance on message instantiation significantly.
+    Most of the work on message instantiation is done just once per message
+    class, instead of once per message instance.
+  * Improved performance on text message parsing.
+  * Allow add() to forward keyword arguments to the concrete class.
+      E.g. instead of
+        item = repeated_field.add()
+        item.foo = bar
+        item.baz = quux
+      You can do:
+        repeated_field.add(foo=bar, baz=quux)
+  * Added a sort() interface to the BaseContainer.
+  * Added an extend() method to repeated composite fields.
+  * Added UTF8 debug string support.
+
+2010-01-08 version 2.3.0:
+
+  General
+  * Parsers for repeated numeric fields now always accept both packed and
+    unpacked input.  The [packed=true] option only affects serializers.
+    Therefore, it is possible to switch a field to packed format without
+    breaking backwards-compatibility -- as long as all parties are using
+    protobuf 2.3.0 or above, at least.
+  * The generic RPC service code generated by the C++, Java, and Python
+    generators can be disabled via file options:
+      option cc_generic_services = false;
+      option java_generic_services = false;
+      option py_generic_services = false;
+    This allows plugins to generate alternative code, possibly specific to some
+    particular RPC implementation.
+
+  protoc
+  * Now supports a plugin system for code generators.  Plugins can generate
+    code for new languages or inject additional code into the output of other
+    code generators.  Plugins are just binaries which accept a protocol buffer
+    on stdin and write a protocol buffer to stdout, so they may be written in
+    any language.  See src/google/protobuf/compiler/plugin.proto.
+    **WARNING**:  Plugins are experimental.  The interface may change in a
+    future version.
+  * If the output location ends in .zip or .jar, protoc will write its output
+    to a zip/jar archive instead of a directory.  For example:
+      protoc --java_out=myproto_srcs.jar --python_out=myproto.zip myproto.proto
+    Currently the archive contents are not compressed, though this could change
+    in the future.
+  * inf, -inf, and nan can now be used as default values for float and double
+    fields.
+
+  C++
+  * Various speed and code size optimizations.
+  * DynamicMessageFactory is now fully thread-safe.
+  * Message::Utf8DebugString() method is like DebugString() but avoids escaping
+    UTF-8 bytes.
+  * Compiled-in message types can now contain dynamic extensions, through use
+    of CodedInputStream::SetExtensionRegistry().
+  * Now compiles shared libraries (DLLs) by default on Cygwin and MinGW, to
+    match other platforms.  Use --disable-shared to avoid this.
+
+  Java
+  * parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return
+    false/null instead of throwing an exception.
+  * Fixed some initialization ordering bugs.
+  * Fixes for OpenJDK 7.
+
+  Python
+  * 10-25 times faster than 2.2.0, still pure-Python.
+  * Calling a mutating method on a sub-message always instantiates the message
+    in its parent even if the mutating method doesn't actually mutate anything
+    (e.g. parsing from an empty string).
+  * Expanded descriptors a bit.
+
+2009-08-11 version 2.2.0:
+
+  C++
+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler
+    to generate code which only depends libprotobuf-lite, which is much smaller
+    than libprotobuf but lacks descriptors, reflection, and some other features.
+  * Fixed bug where Message.Swap(Message) was only implemented for
+    optimize_for_speed.  Swap now properly implemented in both modes
+    (Issue 91).
+  * Added RemoveLast and SwapElements(index1, index2) to Reflection
+    interface for repeated elements.
+  * Added Swap(Message) to Reflection interface.
+  * Floating-point literals in generated code that are intended to be
+    single-precision now explicitly have 'f' suffix to avoid pedantic warnings
+    produced by some compilers.
+  * The [deprecated=true] option now causes the C++ code generator to generate
+    a GCC-style deprecation annotation (no-op on other compilers).
+  * google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the
+    EnumDescriptor for that type -- useful for templates which cannot call
+    SomeGeneratedEnumType_descriptor().
+  * Various optimizations and obscure bug fixes.
+
+  Java
+  * Lite mode:  The "optimize_for = LITE_RUNTIME" option causes the compiler
+    to generate code which only depends libprotobuf-lite, which is much smaller
+    than libprotobuf but lacks descriptors, reflection, and some other features.
+  * Lots of style cleanups.
+
+  Python
+  * Fixed endianness bug with floats and doubles.
+  * Text format parsing support.
+  * Fix bug with parsing packed repeated fields in embedded messages.
+  * Ability to initialize fields by passing keyword args to constructor.
+  * Support iterators in extend and __setslice__ for containers.
+
+2009-05-13 version 2.1.0:
+
+  General
+  * Repeated fields of primitive types (types other that string, group, and
+    nested messages) may now use the option [packed = true] to get a more
+    efficient encoding.  In the new encoding, the entire list is written
+    as a single byte blob using the "length-delimited" wire type.  Within
+    this blob, the individual values are encoded the same way they would
+    be normally except without a tag before each value (thus, they are
+    tightly "packed").
+  * For each field, the generated code contains an integer constant assigned
+    to the field number.  For example, the .proto file:
+      message Foo { optional int bar_baz = 123; }
+    would generate the following constants, all with the integer value 123:
+      C++:     Foo::kBarBazFieldNumber
+      Java:    Foo.BAR_BAZ_FIELD_NUMBER
+      Python:  Foo.BAR_BAZ_FIELD_NUMBER
+    Constants are also generated for extensions, with the same naming scheme.
+    These constants may be used as switch cases.
+  * Updated bundled Google Test to version 1.3.0.  Google Test is now bundled
+    in its verbatim form as a nested autoconf package, so you can drop in any
+    other version of Google Test if needed.
+  * optimize_for = SPEED is now the default, by popular demand.  Use
+    optimize_for = CODE_SIZE if code size is more important in your app.
+  * It is now an error to define a default value for a repeated field.
+    Previously, this was silently ignored (it had no effect on the generated
+    code).
+  * Fields can now be marked deprecated like:
+      optional int32 foo = 1 [deprecated = true];
+    Currently this does not have any actual effect, but in the future the code
+    generators may generate deprecation annotations in each language.
+  * Cross-compiling should now be possible using the --with-protoc option to
+    configure.  See README.txt for more info.
+
+  protoc
+  * --error_format=msvs option causes errors to be printed in Visual Studio
+    format, which should allow them to be clicked on in the build log to go
+    directly to the error location.
+  * The type name resolver will no longer resolve type names to fields.  For
+    example, this now works:
+      message Foo {}
+      message Bar {
+        optional int32 Foo = 1;
+        optional Foo baz = 2;
+      }
+    Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get
+    an error because Bar.Foo is a field, not a type.  Now the type of "baz"
+    resolves to the message type Foo.  This change is unlikely to make a
+    difference to anyone who follows the Protocol Buffers style guide.
+
+  C++
+  * Several optimizations, including but not limited to:
+    - Serialization, especially to flat arrays, is 10%-50% faster, possibly
+      more for small objects.
+    - Several descriptor operations which previously required locking no longer
+      do.
+    - Descriptors are now constructed lazily on first use, rather than at
+      process startup time.  This should save memory in programs which do not
+      use descriptors or reflection.
+    - UnknownFieldSet completely redesigned to be more efficient (especially in
+      terms of memory usage).
+    - Various optimizations to reduce code size (though the serialization speed
+      optimizations increased code size).
+  * Message interface has method ParseFromBoundedZeroCopyStream() which parses
+    a limited number of bytes from an input stream rather than parsing until
+    EOF.
+  * GzipInputStream and GzipOutputStream support reading/writing gzip- or
+    zlib-compressed streams if zlib is available.
+    (google/protobuf/io/gzip_stream.h)
+  * DescriptorPool::FindAllExtensions() and corresponding
+    DescriptorDatabase::FindAllExtensions() can be used to enumerate all
+    extensions of a given type.
+  * For each enum type Foo, protoc will generate functions:
+      const string& Foo_Name(Foo value);
+      bool Foo_Parse(const string& name, Foo* result);
+    The former returns the name of the enum constant corresponding to the given
+    value while the latter finds the value corresponding to a name.
+  * RepeatedField and RepeatedPtrField now have back-insertion iterators.
+  * String fields now have setters that take a char* and a size, in addition
+    to the existing ones that took char* or const string&.
+  * DescriptorPool::AllowUnknownDependencies() may be used to tell
+    DescriptorPool to create placeholder descriptors for unknown entities
+    referenced in a FileDescriptorProto.  This can allow you to parse a .proto
+    file without having access to other .proto files that it imports, for
+    example.
+  * Updated gtest to latest version.  The gtest package is now included as a
+    nested autoconf package, so it should be able to drop new versions into the
+    "gtest" subdirectory without modification.
+
+  Java
+  * Fixed bug where Message.mergeFrom(Message) failed to merge extensions.
+  * Message interface has new method toBuilder() which is equivalent to
+    newBuilderForType().mergeFrom(this).
+  * All enums now implement the ProtocolMessageEnum interface.
+  * Setting a field to null now throws NullPointerException.
+  * Fixed tendency for TextFormat's parsing to overflow the stack when
+    parsing large string values.  The underlying problem is with Java's
+    regex implementation (which unfortunately uses recursive backtracking
+    rather than building an NFA).  Worked around by making use of possessive
+    quantifiers.
+  * Generated service classes now also generate pure interfaces.  For a service
+    Foo, Foo.Interface is a pure interface containing all of the service's
+    defined methods.  Foo.newReflectiveService() can be called to wrap an
+    instance of this interface in a class that implements the generic
+    RpcService interface, which provides reflection support that is usually
+    needed by RPC server implementations.
+  * RPC interfaces now support blocking operation in addition to non-blocking.
+    The protocol compiler generates separate blocking and non-blocking stubs
+    which operate against separate blocking and non-blocking RPC interfaces.
+    RPC implementations will have to implement the new interfaces in order to
+    support blocking mode.
+  * New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and
+    writeDelimitedTo() read and write "delimited" messages from/to a stream,
+    meaning that the message size precedes the data.  This way, you can write
+    multiple messages to a stream without having to worry about delimiting
+    them yourself.
+  * Throw a more descriptive exception when build() is double-called.
+  * Add a method to query whether CodedInputStream is at the end of the input
+    stream.
+  * Add a method to reset a CodedInputStream's size counter; useful when
+    reading many messages with the same stream.
+  * equals() and hashCode() now account for unknown fields.
+
+  Python
+  * Added slicing support for repeated scalar fields. Added slice retrieval and
+    removal of repeated composite fields.
+  * Updated RPC interfaces to allow for blocking operation.  A client may
+    now pass None for a callback when making an RPC, in which case the
+    call will block until the response is received, and the response
+    object will be returned directly to the caller.  This interface change
+    cannot be used in practice until RPC implementations are updated to
+    implement it.
+  * Changes to input_stream.py should make protobuf compatible with appengine.
+
+2008-11-25 version 2.0.3:
+
+  protoc
+  * Enum values may now have custom options, using syntax similar to field
+    options.
+  * Fixed bug where .proto files which use custom options but don't actually
+    define them (i.e. they import another .proto file defining the options)
+    had to explicitly import descriptor.proto.
+  * Adjacent string literals in .proto files will now be concatenated, like in
+    C.
+  * If an input file is a Windows absolute path (e.g. "C:\foo\bar.proto") and
+    the import path only contains "." (or contains "." but does not contain
+    the file), protoc incorrectly thought that the file was under ".", because
+    it thought that the path was relative (since it didn't start with a slash).
+    This has been fixed.
+
+  C++
+  * Generated message classes now have a Swap() method which efficiently swaps
+    the contents of two objects.
+  * All message classes now have a SpaceUsed() method which returns an estimate
+    of the number of bytes of allocated memory currently owned by the object.
+    This is particularly useful when you are reusing a single message object
+    to improve performance but want to make sure it doesn't bloat up too large.
+  * New method Message::SerializeAsString() returns a string containing the
+    serialized data.  May be more convenient than calling
+    SerializeToString(string*).
+  * In debug mode, log error messages when string-type fields are found to
+    contain bytes that are not valid UTF-8.
+  * Fixed bug where a message with multiple extension ranges couldn't parse
+    extensions.
+  * Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on
+    a message that contained no fields (but possibly contained extensions).
+  * Fixed ShortDebugString() to not be O(n^2).  Durr.
+  * Fixed crash in TextFormat parsing if the first token in the input caused a
+    tokenization error.
+  * Fixed obscure bugs in zero_copy_stream_impl.cc.
+  * Added support for HP C++ on Tru64.
+  * Only build tests on "make check", not "make".
+  * Fixed alignment issue that caused crashes when using DynamicMessage on
+    64-bit Sparc machines.
+  * Simplify template usage to work with MSVC 2003.
+  * Work around GCC 4.3.x x86_64 compiler bug that caused crashes on startup.
+    (This affected Fedora 9 in particular.)
+  * Now works on "Solaris 10 using recent Sun Studio".
+
+  Java
+  * New overload of mergeFrom() which parses a slice of a byte array instead
+    of the whole thing.
+  * New method ByteString.asReadOnlyByteBuffer() does what it sounds like.
+  * Improved performance of isInitialized() when optimizing for code size.
+
+  Python
+  * Corrected ListFields() signature in Message base class to match what
+    subclasses actually implement.
+  * Some minor refactoring.
+  * Don't pass self as first argument to superclass constructor (no longer
+    allowed in Python 2.6).
+
+2008-09-29 version 2.0.2:
+
+  General
+  * License changed from Apache 2.0 to New BSD.
+  * It is now possible to define custom "options", which are basically
+    annotations which may be placed on definitions in a .proto file.
+    For example, you might define a field option called "foo" like so:
+      import "google/protobuf/descriptor.proto"
+      extend google.protobuf.FieldOptions {
+        optional string foo = 12345;
+      }
+    Then you annotate a field using the "foo" option:
+      message MyMessage {
+        optional int32 some_field = 1 [(foo) = "bar"]
+      }
+    The value of this option is then visible via the message's
+    Descriptor:
+      const FieldDescriptor* field =
+        MyMessage::descriptor()->FindFieldByName("some_field");
+      assert(field->options().GetExtension(foo) == "bar");
+    This feature has been implemented and tested in C++ and Java.
+    Other languages may or may not need to do extra work to support
+    custom options, depending on how they construct descriptors.
+
+  C++
+  * Fixed some GCC warnings that only occur when using -pedantic.
+  * Improved static initialization code, making ordering more
+    predictable among other things.
+  * TextFormat will no longer accept messages which contain multiple
+    instances of a singular field.  Previously, the latter instance
+    would overwrite the former.
+  * Now works on systems that don't have hash_map.
+
+  Java
+  * Print @Override annotation in generated code where appropriate.
+
+  Python
+  * Strings now use the "unicode" type rather than the "str" type.
+    String fields may still be assigned ASCII "str" values; they will
+    automatically be converted.
+  * Adding a property to an object representing a repeated field now
+    raises an exception.  For example:
+      # No longer works (and never should have).
+      message.some_repeated_field.foo = 1
+
+  Windows
+  * We now build static libraries rather than DLLs by default on MSVC.
+    See vsprojects/readme.txt for more information.
+
+2008-08-15 version 2.0.1:
+
+  protoc
+  * New flags --encode and --decode can be used to convert between protobuf text
+    format and binary format from the command-line.
+  * New flag --descriptor_set_out can be used to write FileDescriptorProtos for
+    all parsed files directly into a single output file.  This is particularly
+    useful if you wish to parse .proto files from programs written in languages
+    other than C++: just run protoc as a background process and have it output
+    a FileDescriptorList, then parse that natively.
+  * Improved error message when an enum value's name conflicts with another
+    symbol defined in the enum type's scope, e.g. if two enum types declared
+    in the same scope have values with the same name.  This is disallowed for
+    compatibility with C++, but this wasn't clear from the error.
+  * Fixed absolute output paths on Windows.
+  * Allow trailing slashes in --proto_path mappings.
+
+  C++
+  * Reflection objects are now per-class rather than per-instance.  To make this
+    possible, the Reflection interface had to be changed such that all methods
+    take the Message instance as a parameter.  This change improves performance
+    significantly in memory-bandwidth-limited use cases, since it makes the
+    message objects smaller.  Note that source-incompatible interface changes
+    like this will not be made again after the library leaves beta.
+  * Heuristically detect sub-messages when printing unknown fields.
+  * Fix static initialization ordering bug that caused crashes at startup when
+    compiling on Mac with static linking.
+  * Fixed TokenizerTest when compiling with -DNDEBUG on Linux.
+  * Fixed incorrect definition of kint32min.
+  * Fix bytes type setter to work with byte sequences with embedded NULLs.
+  * Other irrelevant tweaks.
+
+  Java
+  * Fixed UnknownFieldSet's parsing of varints larger than 32 bits.
+  * Fixed TextFormat's parsing of "inf" and "nan".
+  * Fixed TextFormat's parsing of comments.
+  * Added info to Java POM that will be required when we upload the
+    package to a Maven repo.
+
+  Python
+  * MergeFrom(message) and CopyFrom(message) are now implemented.
+  * SerializeToString() raises an exception if the message is missing required
+    fields.
+  * Code organization improvements.
+  * Fixed doc comments for RpcController and RpcChannel, which had somehow been
+    swapped.
+  * Fixed text_format_test on Windows where floating-point exponents sometimes
+    contain extra zeros.
+  * Fix Python service CallMethod() implementation.
+
+  Other
+  * Improved readmes.
+  * VIM syntax highlighting improvements.
+
+2008-07-07 version 2.0.0:
+
+  * First public release.
diff --git a/util/CONTRIBUTORS.txt b/util/CONTRIBUTORS.txt
new file mode 100644
index 0000000..b8d97fc
--- /dev/null
+++ b/util/CONTRIBUTORS.txt
@@ -0,0 +1,102 @@
+This file contains a list of people who have made large contributions
+to the public version of Protocol Buffers.
+
+Original Protocol Buffers design and implementation:
+  Sanjay Ghemawat <sanjay@google.com>
+  Jeff Dean <jeff@google.com>
+  Daniel Dulitz <daniel@google.com>
+  Craig Silverstein
+  Paul Haahr <haahr@google.com>
+  Corey Anderson <corin@google.com>
+  (and many others)
+
+Proto2 C++ and Java primary author:
+  Kenton Varda <kenton@google.com>
+
+Proto2 Python primary authors:
+  Will Robinson <robinson@google.com>
+  Petar Petrov <petar@google.com>
+
+Java Nano primary authors:
+  Brian Duff <bduff@google.com>
+  Tom Chao <chaot@google.com>
+  Max Cai <maxtroy@google.com>
+  Ulas Kirazci <ulas@google.com>
+
+Large code contributions:
+  Jason Hsueh <jasonh@google.com>
+  Joseph Schorr <jschorr@google.com>
+  Wenbo Zhu <wenboz@google.com>
+
+Large quantity of code reviews:
+  Scott Bruce <sbruce@google.com>
+  Frank Yellin
+  Neal Norwitz <nnorwitz@google.com>
+  Jeffrey Yasskin <jyasskin@google.com>
+  Ambrose Feinstein <ambrose@google.com>
+
+Documentation:
+  Lisa Carey <lcarey@google.com>
+
+Maven packaging:
+  Gregory Kick <gak@google.com>
+
+Patch contributors:
+  Kevin Ko <kevin.s.ko@gmail.com>
+    * Small patch to handle trailing slashes in --proto_path flag.
+  Johan Euphrosine <proppy@aminche.com>
+    * Small patch to fix Python CallMethod().
+  Ulrich Kunitz <kune@deine-taler.de>
+    * Small optimizations to Python serialization.
+  Leandro Lucarella <llucax@gmail.com>
+    * VI syntax highlighting tweaks.
+    * Fix compiler to not make output executable.
+  Dilip Joseph <dilip.antony.joseph@gmail.com>
+    * Heuristic detection of sub-messages when printing unknown fields in
+      text format.
+  Brian Atkinson <nairb774@gmail.com>
+    * Added @Override annotation to generated Java code where appropriate.
+  Vincent Choinière <Choiniere.Vincent@hydro.qc.ca>
+    * Tru64 support.
+  Monty Taylor <monty.taylor@gmail.com>
+    * Solaris 10 + Sun Studio fixes.
+  Alek Storm <alek.storm@gmail.com>
+    * Slicing support for repeated scalar fields for the Python API.
+  Oleg Smolsky <oleg.smolsky@gmail.com>
+    * MS Visual Studio error format option.
+    * Detect unordered_map in stl_hash.m4.
+  Brian Olson <brianolson@google.com>
+    * gzip/zlib I/O support.
+  Michael Poole <mdpoole@troilus.org>
+    * Fixed warnings about generated constructors not explicitly initializing
+      all fields (only present with certain compiler settings).
+    * Added generation of field number constants.
+  Wink Saville <wink@google.com>
+    * Fixed initialization ordering problem in logging code.
+  Will Pierce <willp@nuclei.com>
+    * Small patch improving performance of in Python serialization.
+  Alexandre Vassalotti <alexandre@peadrop.com>
+    * Emacs mode for Protocol Buffers (editors/protobuf-mode.el).
+  Scott Stafford <scott.stafford@gmail.com>
+    * Added Swap(), SwapElements(), and RemoveLast() to Reflection interface.
+  Alexander Melnikov <alm@sibmail.ru>
+    * HPUX support.
+  Oliver Jowett <oliver.jowett@gmail.com>
+    * Detect whether zlib is new enough in configure script.
+    * Fixes for Solaris 10 32/64-bit confusion.
+  Evan Jones <evanj@mit.edu>
+    * Optimize Java serialization code when writing a small message to a stream.
+    * Optimize Java serialization of strings so that UTF-8 encoding happens only
+      once per string per serialization call.
+    * Clean up some Java warnings.
+    * Fix bug with permanent callbacks that delete themselves when run.
+  Michael Kucharski <m.kucharski@gmail.com>
+    * Added CodedInputStream.getTotalBytesRead().
+  Kacper Kowalik <xarthisius.kk@gmail.com>
+    * Fixed m4/acx_pthread.m4 problem for some Linux distributions.
+  William Orr <will@worrbase.com>
+    * Fixed detection of sched_yield on Solaris.
+    * Added atomicops for Solaris
+  Andrew Paprocki <andrew@ishiboo.com>
+    * Fixed minor IBM xlC compiler build issues
+    * Added atomicops for AIX (POWER)
diff --git a/util/LICENSE b/util/LICENSE
new file mode 100644
index 0000000..f028c82
--- /dev/null
+++ b/util/LICENSE
@@ -0,0 +1,42 @@
+This license applies to all parts of Protocol Buffers except the following:
+
+  - Atomicops support for generic gcc, located in
+    src/google/protobuf/stubs/atomicops_internals_generic_gcc.h.
+    This file is copyrighted by Red Hat Inc.
+
+  - Atomicops support for AIX/POWER, located in
+    src/google/protobuf/stubs/atomicops_internals_power.h.
+    This file is copyrighted by Bloomberg Finance LP.
+
+Copyright 2014, Google Inc.  All rights reserved.
+
+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.
+
+Code generated by the Protocol Buffer compiler is owned by the owner
+of the input file used when generating it.  This code is not
+standalone and requires a support library to be linked with it.  This
+support library is itself covered by the above license.
diff --git a/util/Makefile.am b/util/Makefile.am
new file mode 100644
index 0000000..3e98881
--- /dev/null
+++ b/util/Makefile.am
@@ -0,0 +1,769 @@
+## Process this file with automake to produce Makefile.in
+
+ACLOCAL_AMFLAGS = -I m4
+
+AUTOMAKE_OPTIONS = foreign
+
+# Build . before src so that our all-local and clean-local hooks kicks in at
+# the right time.
+SUBDIRS = . src
+
+# Always include gmock in distributions.
+DIST_SUBDIRS = $(subdirs) src conformance benchmarks
+
+# Build gmock before we build protobuf tests.  We don't add gmock to SUBDIRS
+# because then "make check" would also build and run all of gmock's own tests,
+# which takes a lot of time and is generally not useful to us.  Also, we don't
+# want "make install" to recurse into gmock since we don't want to overwrite
+# the installed version of gmock if there is one.
+check-local:
+	@echo "Making lib/libgmock.a lib/libgmock_main.a in gmock"
+	@cd gmock && $(MAKE) $(AM_MAKEFLAGS) lib/libgmock.la lib/libgmock_main.la
+	@cd gmock/gtest && $(MAKE) $(AM_MAKEFLAGS) lib/libgtest.la lib/libgtest_main.la
+
+# We would like to clean gmock when "make clean" is invoked.  But we have to
+# be careful because clean-local is also invoked during "make distclean", but
+# "make distclean" already recurses into gmock because it's listed among the
+# DIST_SUBDIRS.  distclean will delete gmock/Makefile, so if we then try to
+# cd to the directory again and "make clean" it will fail.  So, check that the
+# Makefile exists before recursing.
+clean-local:
+	@if test -e gmock/Makefile; then \
+	  echo "Making clean in gmock"; \
+	  cd gmock && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e conformance/Makefile; then \
+	  echo "Making clean in conformance"; \
+	  cd conformance && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e benchmarks/Makefile; then \
+	  echo "Making clean in benchmarks"; \
+	  cd benchmarks && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e objectivec/DevTools; then \
+	  echo "Cleaning any ObjC pyc files"; \
+	  rm -f objectivec/DevTools/*.pyc; \
+	fi
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = protobuf.pc protobuf-lite.pc
+
+csharp_EXTRA_DIST=                                                           \
+  csharp/.gitignore                                                          \
+  csharp/CHANGES.txt                                                         \
+  csharp/README.md                                                           \
+  csharp/build_packages.bat                                                  \
+  csharp/buildall.sh                                                         \
+  csharp/generate_protos.sh                                                  \
+  csharp/keys/Google.Protobuf.public.snk                                     \
+  csharp/keys/README.md                                                      \
+  csharp/protos/unittest_issues.proto                                        \
+  csharp/src/AddressBook/AddPerson.cs                                        \
+  csharp/src/AddressBook/AddressBook.csproj                                  \
+  csharp/src/AddressBook/Addressbook.cs                                      \
+  csharp/src/AddressBook/ListPeople.cs                                       \
+  csharp/src/AddressBook/Program.cs                                          \
+  csharp/src/AddressBook/Properties/AssemblyInfo.cs                          \
+  csharp/src/AddressBook/SampleUsage.cs                                      \
+  csharp/src/AddressBook/app.config                                          \
+  csharp/src/Google.Protobuf.Conformance/App.config                          \
+  csharp/src/Google.Protobuf.Conformance/Conformance.cs                      \
+  csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj  \
+  csharp/src/Google.Protobuf.Conformance/Program.cs                          \
+  csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs          \
+  csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj        \
+  csharp/src/Google.Protobuf.JsonDump/Program.cs                             \
+  csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs             \
+  csharp/src/Google.Protobuf.JsonDump/app.config                             \
+  csharp/src/Google.Protobuf.Test/ByteStringTest.cs                          \
+  csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs              \
+  csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs                    \
+  csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs                   \
+  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/TypeExtensionsTest.cs        \
+  csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs                    \
+  csharp/src/Google.Protobuf.Test/EqualityTester.cs                          \
+  csharp/src/Google.Protobuf.Test/FieldCodecTest.cs                          \
+  csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs                    \
+  csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj                \
+  csharp/src/Google.Protobuf.Test/IssuesTest.cs                              \
+  csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs                       \
+  csharp/src/Google.Protobuf.Test/JsonParserTest.cs                          \
+  csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs                       \
+  csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml                 \
+  csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs                 \
+  csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs              \
+  csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs              \
+  csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs             \
+  csharp/src/Google.Protobuf.Test/SampleEnum.cs                              \
+  csharp/src/Google.Protobuf.Test/SampleMessages.cs                          \
+  csharp/src/Google.Protobuf.Test/TestCornerCases.cs                         \
+  csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs            \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs         \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs   \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs               \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs               \
+  csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs       \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs                  \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs             \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs            \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs             \
+  csharp/src/Google.Protobuf.Test/packages.config                            \
+  csharp/src/Google.Protobuf.sln                                             \
+  csharp/src/Google.Protobuf/ByteArray.cs                                    \
+  csharp/src/Google.Protobuf/ByteString.cs                                   \
+  csharp/src/Google.Protobuf/CodedInputStream.cs                             \
+  csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs                \
+  csharp/src/Google.Protobuf/CodedOutputStream.cs                            \
+  csharp/src/Google.Protobuf/Collections/MapField.cs                         \
+  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/TypeExtensions.cs                 \
+  csharp/src/Google.Protobuf/FieldCodec.cs                                   \
+  csharp/src/Google.Protobuf/FrameworkPortability.cs                         \
+  csharp/src/Google.Protobuf/Google.Protobuf.csproj                          \
+  csharp/src/Google.Protobuf/Google.Protobuf.nuspec                          \
+  csharp/src/Google.Protobuf/IDeepCloneable.cs                               \
+  csharp/src/Google.Protobuf/IMessage.cs                                     \
+  csharp/src/Google.Protobuf/InvalidJsonException.cs                         \
+  csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs               \
+  csharp/src/Google.Protobuf/JsonFormatter.cs                                \
+  csharp/src/Google.Protobuf/JsonParser.cs                                   \
+  csharp/src/Google.Protobuf/JsonToken.cs                                    \
+  csharp/src/Google.Protobuf/JsonTokenizer.cs                                \
+  csharp/src/Google.Protobuf/LimitedInputStream.cs                           \
+  csharp/src/Google.Protobuf/MessageExtensions.cs                            \
+  csharp/src/Google.Protobuf/MessageParser.cs                                \
+  csharp/src/Google.Protobuf/ProtoPreconditions.cs                           \
+  csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs                      \
+  csharp/src/Google.Protobuf/Reflection/Descriptor.cs                        \
+  csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs                    \
+  csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs     \
+  csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs               \
+  csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs                 \
+  csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs                   \
+  csharp/src/Google.Protobuf/Reflection/FieldType.cs                         \
+  csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs              \
+  csharp/src/Google.Protobuf/Reflection/IDescriptor.cs                       \
+  csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs                    \
+  csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs                  \
+  csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs                  \
+  csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs                     \
+  csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs                   \
+  csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs             \
+  csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/PartialClasses.cs                    \
+  csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs                    \
+  csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs             \
+  csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs                 \
+  csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs               \
+  csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/Any.cs                           \
+  csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs                    \
+  csharp/src/Google.Protobuf/WellKnownTypes/Api.cs                           \
+  csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs               \
+  csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs                         \
+  csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs                     \
+  csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs                 \
+  csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs                        \
+  csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs                \
+  csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs                     \
+  csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs              \
+  csharp/src/Google.Protobuf/WellKnownTypes/Type.cs                          \
+  csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs                  \
+  csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs                      \
+  csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs               \
+  csharp/src/Google.Protobuf/WireFormat.cs                                   \
+  csharp/src/Google.Protobuf/packages.config                                 \
+  csharp/src/packages/repositories.config
+
+java_EXTRA_DIST=                                                                   \
+  java/README.md                                                                   \
+  java/core/generate-sources-build.xml                                             \
+  java/core/generate-test-sources-build.xml                                        \
+  java/core/pom.xml                                                                \
+  java/core/src/main/java/com/google/protobuf/AbstractMessage.java                 \
+  java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java             \
+  java/core/src/main/java/com/google/protobuf/AbstractParser.java                  \
+  java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java            \
+  java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java              \
+  java/core/src/main/java/com/google/protobuf/BlockingService.java                 \
+  java/core/src/main/java/com/google/protobuf/BooleanArrayList.java                \
+  java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java                \
+  java/core/src/main/java/com/google/protobuf/ByteOutput.java                      \
+  java/core/src/main/java/com/google/protobuf/ByteString.java                      \
+  java/core/src/main/java/com/google/protobuf/CodedInputStream.java                \
+  java/core/src/main/java/com/google/protobuf/CodedOutputStream.java               \
+  java/core/src/main/java/com/google/protobuf/Descriptors.java                     \
+  java/core/src/main/java/com/google/protobuf/DoubleArrayList.java                 \
+  java/core/src/main/java/com/google/protobuf/DynamicMessage.java                  \
+  java/core/src/main/java/com/google/protobuf/Extension.java                       \
+  java/core/src/main/java/com/google/protobuf/ExtensionLite.java                   \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java               \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java           \
+  java/core/src/main/java/com/google/protobuf/FieldSet.java                        \
+  java/core/src/main/java/com/google/protobuf/FloatArrayList.java                  \
+  java/core/src/main/java/com/google/protobuf/GeneratedMessage.java                \
+  java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java            \
+  java/core/src/main/java/com/google/protobuf/IntArrayList.java                    \
+  java/core/src/main/java/com/google/protobuf/Internal.java                        \
+  java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java  \
+  java/core/src/main/java/com/google/protobuf/LazyField.java                       \
+  java/core/src/main/java/com/google/protobuf/LazyFieldLite.java                   \
+  java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java             \
+  java/core/src/main/java/com/google/protobuf/LazyStringList.java                  \
+  java/core/src/main/java/com/google/protobuf/LongArrayList.java                   \
+  java/core/src/main/java/com/google/protobuf/MapEntry.java                        \
+  java/core/src/main/java/com/google/protobuf/MapEntryLite.java                    \
+  java/core/src/main/java/com/google/protobuf/MapField.java                        \
+  java/core/src/main/java/com/google/protobuf/MapFieldLite.java                    \
+  java/core/src/main/java/com/google/protobuf/Message.java                         \
+  java/core/src/main/java/com/google/protobuf/MessageLite.java                     \
+  java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/MessageLiteToString.java             \
+  java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java                \
+  java/core/src/main/java/com/google/protobuf/MessageReflection.java               \
+  java/core/src/main/java/com/google/protobuf/MutabilityOracle.java                \
+  java/core/src/main/java/com/google/protobuf/NioByteString.java                   \
+  java/core/src/main/java/com/google/protobuf/Parser.java                          \
+  java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java               \
+  java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java             \
+  java/core/src/main/java/com/google/protobuf/ProtocolStringList.java              \
+  java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/RopeByteString.java                  \
+  java/core/src/main/java/com/google/protobuf/RpcCallback.java                     \
+  java/core/src/main/java/com/google/protobuf/RpcChannel.java                      \
+  java/core/src/main/java/com/google/protobuf/RpcController.java                   \
+  java/core/src/main/java/com/google/protobuf/RpcUtil.java                         \
+  java/core/src/main/java/com/google/protobuf/Service.java                         \
+  java/core/src/main/java/com/google/protobuf/ServiceException.java                \
+  java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java              \
+  java/core/src/main/java/com/google/protobuf/SmallSortedMap.java                  \
+  java/core/src/main/java/com/google/protobuf/TextFormat.java                      \
+  java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java               \
+  java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java         \
+  java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java         \
+  java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java   \
+  java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java                 \
+  java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java             \
+  java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java      \
+  java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java            \
+  java/core/src/main/java/com/google/protobuf/Utf8.java                            \
+  java/core/src/main/java/com/google/protobuf/WireFormat.java                      \
+  java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java             \
+  java/core/src/test/java/com/google/protobuf/AnyTest.java                         \
+  java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java            \
+  java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java            \
+  java/core/src/test/java/com/google/protobuf/ByteStringTest.java                  \
+  java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java                   \
+  java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java            \
+  java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java           \
+  java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java             \
+  java/core/src/test/java/com/google/protobuf/DescriptorsTest.java                 \
+  java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java             \
+  java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java              \
+  java/core/src/test/java/com/google/protobuf/EnumTest.java                        \
+  java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java               \
+  java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java              \
+  java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java        \
+  java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java            \
+  java/core/src/test/java/com/google/protobuf/IntArrayListTest.java                \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java                 \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java             \
+  java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java               \
+  java/core/src/test/java/com/google/protobuf/LazyFieldTest.java                   \
+  java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java             \
+  java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java         \
+  java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java          \
+  java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java           \
+  java/core/src/test/java/com/google/protobuf/LiteTest.java                        \
+  java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/LongArrayListTest.java               \
+  java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java            \
+  java/core/src/test/java/com/google/protobuf/MapForProto2Test.java                \
+  java/core/src/test/java/com/google/protobuf/MapTest.java                         \
+  java/core/src/test/java/com/google/protobuf/MessageTest.java                     \
+  java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java              \
+  java/core/src/test/java/com/google/protobuf/NioByteStringTest.java               \
+  java/core/src/test/java/com/google/protobuf/ParserTest.java                      \
+  java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java           \
+  java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java        \
+  java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java     \
+  java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java              \
+  java/core/src/test/java/com/google/protobuf/ServiceTest.java                     \
+  java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java          \
+  java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java              \
+  java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java              \
+  java/core/src/test/java/com/google/protobuf/TestUtil.java                        \
+  java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java     \
+  java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java     \
+  java/core/src/test/java/com/google/protobuf/TextFormatTest.java                  \
+  java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java            \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java         \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java             \
+  java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java  \
+  java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java              \
+  java/core/src/test/java/com/google/protobuf/WireFormatTest.java                  \
+  java/core/src/test/proto/com/google/protobuf/any_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/field_presence_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto              \
+  java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto          \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto      \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto \
+  java/core/src/test/proto/com/google/protobuf/map_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto          \
+  java/core/src/test/proto/com/google/protobuf/nested_extension.proto              \
+  java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto         \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto          \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto     \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto         \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto        \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto        \
+  java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto          \
+  java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto               \
+  java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto          \
+  java/core/src/test/proto/com/google/protobuf/test_custom_options.proto           \
+  java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto         \
+  java/lite/pom.xml                                                                \
+  java/pom.xml                                                                     \
+  java/util/pom.xml                                                                \
+  java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java              \
+  java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java              \
+  java/util/src/main/java/com/google/protobuf/util/JsonFormat.java                 \
+  java/util/src/main/java/com/google/protobuf/util/TimeUtil.java                   \
+  java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java          \
+  java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java          \
+  java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java             \
+  java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java               \
+  java/util/src/test/proto/com/google/protobuf/util/json_test.proto
+
+javanano_EXTRA_DIST=                                                                      \
+  javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java          \
+  javanano/src/main/java/com/google/protobuf/nano/FieldData.java                          \
+  javanano/src/main/java/com/google/protobuf/nano/FieldArray.java                         \
+  javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java                     \
+  javanano/src/main/java/com/google/protobuf/nano/Extension.java                          \
+  javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java           \
+  javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java                   \
+  javanano/src/main/java/com/google/protobuf/nano/MessageNano.java                        \
+  javanano/src/main/java/com/google/protobuf/nano/InternalNano.java                       \
+  javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java \
+  javanano/src/main/java/com/google/protobuf/nano/MapFactories.java                       \
+  javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java              \
+  javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java                 \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto          \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto     \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto                 \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto                     \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/NanoTest.java                           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto              \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto      \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto  \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto           \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto    \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto       \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto          \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto            \
+  javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto \
+  javanano/src/test/java/com/google/protobuf/nano/map_test.proto                          \
+  javanano/README.md                                                                      \
+  javanano/pom.xml
+
+objectivec_EXTRA_DIST=                                                       \
+  objectivec/DevTools/check_version_stamps.sh                                \
+  objectivec/DevTools/compile_testing_protos.sh                              \
+  objectivec/DevTools/full_mac_build.sh                                      \
+  objectivec/DevTools/pddm.py                                                \
+  objectivec/DevTools/pddm_tests.py                                          \
+  objectivec/generate_well_known_types.sh                                    \
+  objectivec/google/protobuf/Any.pbobjc.h                                    \
+  objectivec/google/protobuf/Any.pbobjc.m                                    \
+  objectivec/google/protobuf/Api.pbobjc.h                                    \
+  objectivec/google/protobuf/Api.pbobjc.m                                    \
+  objectivec/google/protobuf/Duration.pbobjc.h                               \
+  objectivec/google/protobuf/Duration.pbobjc.m                               \
+  objectivec/google/protobuf/Empty.pbobjc.h                                  \
+  objectivec/google/protobuf/Empty.pbobjc.m                                  \
+  objectivec/google/protobuf/FieldMask.pbobjc.h                              \
+  objectivec/google/protobuf/FieldMask.pbobjc.m                              \
+  objectivec/google/protobuf/SourceContext.pbobjc.h                          \
+  objectivec/google/protobuf/SourceContext.pbobjc.m                          \
+  objectivec/google/protobuf/Struct.pbobjc.h                                 \
+  objectivec/google/protobuf/Struct.pbobjc.m                                 \
+  objectivec/google/protobuf/Timestamp.pbobjc.h                              \
+  objectivec/google/protobuf/Timestamp.pbobjc.m                              \
+  objectivec/google/protobuf/Type.pbobjc.h                                   \
+  objectivec/google/protobuf/Type.pbobjc.m                                   \
+  objectivec/google/protobuf/Wrappers.pbobjc.h                               \
+  objectivec/google/protobuf/Wrappers.pbobjc.m                               \
+  objectivec/GPBArray.h                                                      \
+  objectivec/GPBArray.m                                                      \
+  objectivec/GPBArray_PackagePrivate.h                                       \
+  objectivec/GPBBootstrap.h                                                  \
+  objectivec/GPBCodedInputStream.h                                           \
+  objectivec/GPBCodedInputStream.m                                           \
+  objectivec/GPBCodedInputStream_PackagePrivate.h                            \
+  objectivec/GPBCodedOutputStream.h                                          \
+  objectivec/GPBCodedOutputStream.m                                          \
+  objectivec/GPBCodedOutputStream_PackagePrivate.h                           \
+  objectivec/GPBDescriptor.h                                                 \
+  objectivec/GPBDescriptor.m                                                 \
+  objectivec/GPBDescriptor_PackagePrivate.h                                  \
+  objectivec/GPBDictionary.h                                                 \
+  objectivec/GPBDictionary.m                                                 \
+  objectivec/GPBDictionary_PackagePrivate.h                                  \
+  objectivec/GPBExtensionInternals.h                                         \
+  objectivec/GPBExtensionInternals.m                                         \
+  objectivec/GPBExtensionRegistry.h                                          \
+  objectivec/GPBExtensionRegistry.m                                          \
+  objectivec/GPBMessage.h                                                    \
+  objectivec/GPBMessage.m                                                    \
+  objectivec/GPBMessage_PackagePrivate.h                                     \
+  objectivec/GPBProtocolBuffers.h                                            \
+  objectivec/GPBProtocolBuffers.m                                            \
+  objectivec/GPBProtocolBuffers_RuntimeSupport.h                             \
+  objectivec/GPBRootObject.h                                                 \
+  objectivec/GPBRootObject.m                                                 \
+  objectivec/GPBRootObject_PackagePrivate.h                                  \
+  objectivec/GPBRuntimeTypes.h                                               \
+  objectivec/GPBUnknownField.h                                               \
+  objectivec/GPBUnknownField.m                                               \
+  objectivec/GPBUnknownField_PackagePrivate.h                                \
+  objectivec/GPBUnknownFieldSet.h                                            \
+  objectivec/GPBUnknownFieldSet.m                                            \
+  objectivec/GPBUnknownFieldSet_PackagePrivate.h                             \
+  objectivec/GPBUtilities.h                                                  \
+  objectivec/GPBUtilities.m                                                  \
+  objectivec/GPBUtilities_PackagePrivate.h                                   \
+  objectivec/GPBWellKnownTypes.h                                             \
+  objectivec/GPBWellKnownTypes.m                                             \
+  objectivec/GPBWireFormat.h                                                 \
+  objectivec/GPBWireFormat.m                                                 \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj                   \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
+  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj                   \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
+  objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
+  objectivec/README.md                                                       \
+  objectivec/Tests/golden_message                                            \
+  objectivec/Tests/golden_packed_fields_message                              \
+  objectivec/Tests/GPBARCUnittestProtos.m                                    \
+  objectivec/Tests/GPBArrayTests.m                                           \
+  objectivec/Tests/GPBCodedInputStreamTests.m                                \
+  objectivec/Tests/GPBCodedOuputStreamTests.m                                \
+  objectivec/Tests/GPBConcurrencyTests.m                                     \
+  objectivec/Tests/GPBDescriptorTests.m                                      \
+  objectivec/Tests/GPBDictionaryTests+Bool.m                                 \
+  objectivec/Tests/GPBDictionaryTests+Int32.m                                \
+  objectivec/Tests/GPBDictionaryTests+Int64.m                                \
+  objectivec/Tests/GPBDictionaryTests+String.m                               \
+  objectivec/Tests/GPBDictionaryTests+UInt32.m                               \
+  objectivec/Tests/GPBDictionaryTests+UInt64.m                               \
+  objectivec/Tests/GPBDictionaryTests.pddm                                   \
+  objectivec/Tests/GPBMessageTests+Merge.m                                   \
+  objectivec/Tests/GPBMessageTests+Runtime.m                                 \
+  objectivec/Tests/GPBMessageTests+Serialization.m                           \
+  objectivec/Tests/GPBMessageTests.m                                         \
+  objectivec/Tests/GPBObjectiveCPlusPlusTest.mm                              \
+  objectivec/Tests/GPBPerfTests.m                                            \
+  objectivec/Tests/GPBSwiftTests.swift                                       \
+  objectivec/Tests/GPBTestUtilities.h                                        \
+  objectivec/Tests/GPBTestUtilities.m                                        \
+  objectivec/Tests/GPBUnittestProtos.m                                       \
+  objectivec/Tests/GPBUnknownFieldSetTest.m                                  \
+  objectivec/Tests/GPBUtilitiesTests.m                                       \
+  objectivec/Tests/GPBWellKnownTypesTest.m                                   \
+  objectivec/Tests/GPBWireFormatTests.m                                      \
+  objectivec/Tests/iOSTestHarness/AppDelegate.m                              \
+  objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings                 \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json      \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png          \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6_2x.png       \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png          \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7_2x.png       \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png        \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6_2x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_2x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7_3x.png     \
+  objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json \
+  objectivec/Tests/iOSTestHarness/Info.plist                                  \
+  objectivec/Tests/iOSTestHarness/LaunchScreen.xib                            \
+  objectivec/Tests/text_format_map_unittest_data.txt                          \
+  objectivec/Tests/text_format_unittest_data.txt                              \
+  objectivec/Tests/unittest_cycle.proto                                       \
+  objectivec/Tests/unittest_objc.proto                                        \
+  objectivec/Tests/unittest_objc_startup.proto                                \
+  objectivec/Tests/unittest_runtime_proto2.proto                              \
+  objectivec/Tests/unittest_runtime_proto3.proto                              \
+  objectivec/Tests/UnitTests-Bridging-Header.h                                \
+  objectivec/Tests/UnitTests-Info.plist                                       \
+  Protobuf.podspec
+
+python_EXTRA_DIST=                                                           \
+  python/MANIFEST.in                                                         \
+  python/google/__init__.py                                                  \
+  python/google/protobuf/__init__.py                                         \
+  python/google/protobuf/descriptor.py                                       \
+  python/google/protobuf/descriptor_database.py                              \
+  python/google/protobuf/descriptor_pool.py                                  \
+  python/google/protobuf/internal/__init__.py                                \
+  python/google/protobuf/internal/_parameterized.py                          \
+  python/google/protobuf/internal/any_test.proto                             \
+  python/google/protobuf/internal/any_test.proto                             \
+  python/google/protobuf/internal/api_implementation.cc                      \
+  python/google/protobuf/internal/api_implementation.py                      \
+  python/google/protobuf/internal/containers.py                              \
+  python/google/protobuf/internal/decoder.py                                 \
+  python/google/protobuf/internal/descriptor_database_test.py                \
+  python/google/protobuf/internal/descriptor_pool_test.py                    \
+  python/google/protobuf/internal/descriptor_pool_test1.proto                \
+  python/google/protobuf/internal/descriptor_pool_test2.proto                \
+  python/google/protobuf/internal/descriptor_test.py                         \
+  python/google/protobuf/internal/encoder.py                                 \
+  python/google/protobuf/internal/enum_type_wrapper.py                       \
+  python/google/protobuf/internal/factory_test1.proto                        \
+  python/google/protobuf/internal/factory_test2.proto                        \
+  python/google/protobuf/internal/generator_test.py                          \
+  python/google/protobuf/internal/import_test_package/__init__.py            \
+  python/google/protobuf/internal/import_test_package/inner.proto            \
+  python/google/protobuf/internal/import_test_package/outer.proto            \
+  python/google/protobuf/internal/json_format_test.py                        \
+  python/google/protobuf/internal/message_factory_test.py                    \
+  python/google/protobuf/internal/message_listener.py                        \
+  python/google/protobuf/internal/message_set_extensions.proto               \
+  python/google/protobuf/internal/message_test.py                            \
+  python/google/protobuf/internal/missing_enum_values.proto                  \
+  python/google/protobuf/internal/more_extensions.proto                      \
+  python/google/protobuf/internal/more_extensions_dynamic.proto              \
+  python/google/protobuf/internal/more_messages.proto                        \
+  python/google/protobuf/internal/packed_field_test.proto                    \
+  python/google/protobuf/internal/proto_builder_test.py                      \
+  python/google/protobuf/internal/python_message.py                          \
+  python/google/protobuf/internal/reflection_test.py                         \
+  python/google/protobuf/internal/service_reflection_test.py                 \
+  python/google/protobuf/internal/symbol_database_test.py                    \
+  python/google/protobuf/internal/test_bad_identifiers.proto                 \
+  python/google/protobuf/internal/test_util.py                               \
+  python/google/protobuf/internal/text_encoding_test.py                      \
+  python/google/protobuf/internal/text_format_test.py                        \
+  python/google/protobuf/internal/type_checkers.py                           \
+  python/google/protobuf/internal/unknown_fields_test.py                     \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types_test.py                   \
+  python/google/protobuf/internal/well_known_types_test.py                   \
+  python/google/protobuf/internal/wire_format.py                             \
+  python/google/protobuf/internal/wire_format_test.py                        \
+  python/google/protobuf/json_format.py                                      \
+  python/google/protobuf/message.py                                          \
+  python/google/protobuf/message_factory.py                                  \
+  python/google/protobuf/proto_builder.py                                    \
+  python/google/protobuf/pyext/README                                        \
+  python/google/protobuf/pyext/__init__.py                                   \
+  python/google/protobuf/pyext/cpp_message.py                                \
+  python/google/protobuf/pyext/descriptor.cc                                 \
+  python/google/protobuf/pyext/descriptor.h                                  \
+  python/google/protobuf/pyext/descriptor_containers.cc                      \
+  python/google/protobuf/pyext/descriptor_containers.h                       \
+  python/google/protobuf/pyext/descriptor_database.cc                        \
+  python/google/protobuf/pyext/descriptor_database.h                         \
+  python/google/protobuf/pyext/descriptor_pool.cc                            \
+  python/google/protobuf/pyext/descriptor_pool.h                             \
+  python/google/protobuf/pyext/extension_dict.cc                             \
+  python/google/protobuf/pyext/extension_dict.h                              \
+  python/google/protobuf/pyext/map_container.cc                              \
+  python/google/protobuf/pyext/map_container.h                               \
+  python/google/protobuf/pyext/message.cc                                    \
+  python/google/protobuf/pyext/message.h                                     \
+  python/google/protobuf/pyext/proto2_api_test.proto                         \
+  python/google/protobuf/pyext/python.proto                                  \
+  python/google/protobuf/pyext/python_protobuf.h                             \
+  python/google/protobuf/pyext/repeated_composite_container.cc               \
+  python/google/protobuf/pyext/repeated_composite_container.h                \
+  python/google/protobuf/pyext/repeated_scalar_container.cc                  \
+  python/google/protobuf/pyext/repeated_scalar_container.h                   \
+  python/google/protobuf/pyext/scoped_pyobject_ptr.h                         \
+  python/google/protobuf/reflection.py                                       \
+  python/google/protobuf/service.py                                          \
+  python/google/protobuf/service_reflection.py                               \
+  python/google/protobuf/symbol_database.py                                  \
+  python/google/protobuf/text_encoding.py                                    \
+  python/google/protobuf/text_format.py                                      \
+  python/mox.py                                                              \
+  python/setup.py                                                            \
+  python/stubout.py                                                          \
+  python/tox.ini                                                             \
+  python/README.md
+
+ruby_EXTRA_DIST=                                                             \
+  ruby/Gemfile                                                               \
+  ruby/Gemfile.lock                                                          \
+  ruby/.gitignore                                                            \
+  ruby/README.md                                                             \
+  ruby/Rakefile                                                              \
+  ruby/ext/google/protobuf_c/defs.c                                          \
+  ruby/ext/google/protobuf_c/encode_decode.c                                 \
+  ruby/ext/google/protobuf_c/extconf.rb                                      \
+  ruby/ext/google/protobuf_c/map.c                                           \
+  ruby/ext/google/protobuf_c/message.c                                       \
+  ruby/ext/google/protobuf_c/protobuf.c                                      \
+  ruby/ext/google/protobuf_c/protobuf.h                                      \
+  ruby/ext/google/protobuf_c/repeated_field.c                                \
+  ruby/ext/google/protobuf_c/storage.c                                       \
+  ruby/ext/google/protobuf_c/upb.c                                           \
+  ruby/ext/google/protobuf_c/upb.h                                           \
+  ruby/google-protobuf.gemspec                                               \
+  ruby/lib/google/protobuf/message_exts.rb                                   \
+  ruby/lib/google/protobuf/repeated_field.rb                                 \
+  ruby/lib/google/protobuf.rb                                                \
+  ruby/pom.xml                                                               \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java              \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java           \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnumBuilderContext.java   \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java                 \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java      \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java                  \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMessageBuilderContext.java \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java              \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyOneofBuilderContext.java  \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java      \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java             \
+  ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java        \
+  ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java       \
+  ruby/src/main/java/com/google/protobuf/jruby/Utils.java                    \
+  ruby/src/main/java/google/ProtobufJavaService.java                         \
+  ruby/src/main/sentinel.proto                                               \
+  ruby/tests/basic.rb                                                        \
+  ruby/tests/repeated_field_test.rb                                          \
+  ruby/tests/stress.rb                                                       \
+  ruby/tests/generated_code.proto                                            \
+  ruby/tests/generated_code_test.rb                                          \
+  ruby/travis-test.sh
+
+js_EXTRA_DIST=              \
+  js/README.md              \
+  js/binary/arith.js        \
+  js/binary/arith_test.js   \
+  js/binary/constants.js    \
+  js/binary/decoder.js      \
+  js/binary/decoder_test.js \
+  js/binary/proto_test.js   \
+  js/binary/reader.js       \
+  js/binary/reader_test.js  \
+  js/binary/utils.js        \
+  js/binary/utils_test.js   \
+  js/binary/writer.js       \
+  js/binary/writer_test.js  \
+  js/data.proto             \
+  js/debug.js               \
+  js/debug_test.js          \
+  js/gulpfile.js            \
+  js/jasmine.json           \
+  js/message.js             \
+  js/message_test.js        \
+  js/node_loader.js         \
+  js/package.json           \
+  js/proto3_test.js         \
+  js/proto3_test.proto      \
+  js/test.proto             \
+  js/test2.proto            \
+  js/test3.proto            \
+  js/test4.proto            \
+  js/test5.proto            \
+  js/test_bootstrap.js      \
+  js/testbinary.proto       \
+  js/testempty.proto
+
+all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) $(js_EXTRA_DIST)
+
+EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)   \
+  autogen.sh                             \
+  generate_descriptor_proto.sh           \
+  README.md                              \
+  LICENSE                                \
+  CONTRIBUTORS.txt                       \
+  CHANGES.txt                            \
+  update_file_lists.sh                   \
+  BUILD                                  \
+  gmock.BUILD                            \
+  WORKSPACE                              \
+  cmake/CMakeLists.txt                   \
+  cmake/README.md                        \
+  cmake/extract_includes.bat.in          \
+  cmake/install.cmake                    \
+  cmake/libprotobuf.cmake                \
+  cmake/libprotobuf-lite.cmake           \
+  cmake/libprotoc.cmake                  \
+  cmake/protobuf-config-version.cmake.in \
+  cmake/protobuf-config.cmake.in         \
+  cmake/protobuf-module.cmake.in         \
+  cmake/protoc.cmake                     \
+  cmake/tests.cmake                      \
+  editors/README.txt                     \
+  editors/proto.vim                      \
+  editors/protobuf-mode.el               \
+  examples/README.txt                    \
+  examples/Makefile                      \
+  examples/addressbook.proto             \
+  examples/add_person.cc                 \
+  examples/add_person.go                 \
+  examples/add_person_test.go            \
+  examples/list_people.cc                \
+  examples/list_people.go                \
+  examples/AddPerson.java                \
+  examples/ListPeople.java               \
+  examples/add_person.py                 \
+  examples/list_people.py                \
+  examples/list_people_test.go           \
+  protobuf.bzl                           \
+  six.BUILD                              \
+  util/python/BUILD
+
+# Deletes all the files generated by autogen.sh.
+MAINTAINERCLEANFILES =   \
+  aclocal.m4             \
+  ar-lib                 \
+  config.guess           \
+  config.sub             \
+  configure              \
+  depcomp                \
+  install-sh             \
+  ltmain.sh              \
+  Makefile.in            \
+  missing                \
+  mkinstalldirs          \
+  config.h.in            \
+  stamp.h.in             \
+  m4/ltsugar.m4          \
+  m4/libtool.m4          \
+  m4/ltversion.m4        \
+  m4/lt~obsolete.m4      \
+  m4/ltoptions.m4
diff --git a/util/Protobuf.podspec b/util/Protobuf.podspec
new file mode 100644
index 0000000..0bbd06d
--- /dev/null
+++ b/util/Protobuf.podspec
@@ -0,0 +1,40 @@
+# This file describes to Cocoapods how to integrate the Objective-C runtime into a dependent
+# project.
+# Despite this file being specific to Objective-C, it needs to be on the root of the repository.
+# Otherwise, Cocoapods gives trouble like not picking up the license file correctly, or not letting
+# dependent projects use the :git notation to refer to the library.
+Pod::Spec.new do |s|
+  s.name     = 'Protobuf'
+  s.version  = '3.0.0-beta-2'
+  s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
+  s.homepage = 'https://github.com/google/protobuf'
+  s.license  = 'New BSD'
+  s.authors  = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
+
+  s.source = { :git => 'https://github.com/google/protobuf.git',
+               :tag => "v#{s.version}" }
+
+  s.source_files = 'objectivec/*.{h,m}',
+                   'objectivec/google/protobuf/Any.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Api.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Duration.pbobjc.h',
+                   'objectivec/google/protobuf/Empty.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/FieldMask.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/SourceContext.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Struct.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Timestamp.pbobjc.h',
+                   'objectivec/google/protobuf/Type.pbobjc.{h,m}',
+                   'objectivec/google/protobuf/Wrappers.pbobjc.{h,m}'
+  # Timestamp.pbobjc.m and Duration.pbobjc.m are #imported by GPBWellKnownTypes.m. So we can't
+  # compile them (duplicate symbols), but we need them available for the importing:
+  s.preserve_paths = 'objectivec/google/protobuf/Duration.pbobjc.m',
+                     'objectivec/google/protobuf/Timestamp.pbobjc.m'
+  # The following would cause duplicate symbol definitions. GPBProtocolBuffers is expected to be
+  # left out, as it's an umbrella implementation file.
+  s.exclude_files = 'objectivec/GPBProtocolBuffers.m'
+  s.header_mappings_dir = 'objectivec'
+
+  s.ios.deployment_target = '7.1'
+  s.osx.deployment_target = '10.9'
+  s.requires_arc = false
+end
diff --git a/util/README.md b/util/README.md
new file mode 100644
index 0000000..ba9c589
--- /dev/null
+++ b/util/README.md
@@ -0,0 +1,77 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
+
+Copyright 2008 Google Inc.
+
+https://developers.google.com/protocol-buffers/
+
+Overview
+--------
+
+Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
+platform-neutral, extensible mechanism for serializing structured data. You
+can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
+
+This README file contains protobuf installation instructions. To install
+protobuf, you need to install the protocol compiler (used to compile .proto
+files) and the protobuf runtime for your chosen programming language.
+
+Protocol Compiler Installation
+------------------------------
+
+The protocol compiler is written in C++. If you are using C++, please follow
+the [C++ Installation Instructions](src/README.md) to install protoc along
+with the C++ runtime.
+
+For non-C++ users, the simplest way to install the protocol compiler is to
+download a pre-built binary from our release page:
+
+  [https://github.com/google/protobuf/releases](https://github.com/google/protobuf/releases)
+
+In the downloads section of each release, you can find pre-built binaries in
+zip packages: protoc-$VERSION-$PLATFORM.zip. It contains the protoc binary
+as well as a set of standard .proto files distributed along with protobuf.
+
+If you are looking for an old version that is not available in the release
+page, check out the maven repo here:
+
+  [http://repo1.maven.org/maven2/com/google/protobuf/protoc/](http://repo1.maven.org/maven2/com/google/protobuf/protoc/)
+
+These pre-built binaries are only provided for released versions. If you want
+to use the github master version at HEAD, or you need to modify protobuf code,
+or you are using C++, it's recommended to build your own protoc binary from
+source.
+
+If you would like to build protoc binary from source, see the [C++ Installation
+Instructions](src/README.md).
+
+Protobuf Runtime Installation
+-----------------------------
+
+Protobuf supports several different programming languages. For each programming
+language, you can find instructions in the corresponding source directory about
+how to install protobuf runtime for that specific language:
+
+| Language                             | Source                                                |
+|--------------------------------------|-------------------------------------------------------|
+| C++ (include C++ runtime and protoc) | [src](src)                                            |
+| Java                                 | [java](java)                                          |
+| Python                               | [python](python)                                      |
+| Objective-C                          | [objectivec](objectivec)                              |
+| C#                                   | [csharp](csharp)                                      |
+| JavaNano                             | [javanano](javanano)                                  |
+| JavaScript                           | [js](js)                                              |
+| Ruby                                 | [ruby](ruby)                                          |
+| Go                                   | [golang/protobuf](https://github.com/golang/protobuf) |
+| PHP                                  | TBD                                                   |
+
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/util/WORKSPACE b/util/WORKSPACE
new file mode 100644
index 0000000..065dc81
--- /dev/null
+++ b/util/WORKSPACE
@@ -0,0 +1,53 @@
+new_http_archive(
+    name = "gmock_archive",
+    url = "https://googlemock.googlecode.com/files/gmock-1.7.0.zip",
+    sha256 = "26fcbb5925b74ad5fc8c26b0495dfc96353f4d553492eb97e85a8a6d2f43095b",
+    build_file = "gmock.BUILD",
+)
+
+new_http_archive(
+    name = "six_archive",
+    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
+    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
+    build_file = "six.BUILD",
+)
+
+bind(
+    name = "python_headers",
+    actual = "//util/python:python_headers",
+)
+
+bind(
+    name = "gtest",
+    actual = "@gmock_archive//:gtest",
+)
+
+bind(
+    name = "gtest_main",
+    actual = "@gmock_archive//:gtest_main",
+)
+
+bind(
+    name = "six",
+    actual = "@six_archive//:six",
+)
+
+maven_jar(
+  name = "guava_maven",
+  artifact = "com.google.guava:guava:18.0",
+)
+
+bind(
+    name = "guava",
+    actual = "@guava_maven//jar",
+)
+
+maven_jar(
+  name = "gson_maven",
+  artifact = "com.google.code.gson:gson:2.3",
+)
+
+bind(
+    name = "gson",
+    actual = "@gson_maven//jar",
+)
diff --git a/util/appveyor.bat b/util/appveyor.bat
new file mode 100644
index 0000000..9a46b92
--- /dev/null
+++ b/util/appveyor.bat
@@ -0,0 +1,29 @@
+setlocal
+
+IF %language%==cpp GOTO build_cpp
+IF %language%==csharp GOTO build_csharp
+
+echo Unsupported language %language%. Exiting.
+goto :error
+
+:build_cpp
+echo Building C++
+mkdir build_msvc
+cd build_msvc
+cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
+msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
+cd %configuration%
+tests.exe || goto error
+goto :EOF
+
+:build_csharp
+echo Building C#
+cd csharp\src
+nuget restore
+msbuild Google.Protobuf.sln /p:Platform="Any CPU" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
+nunit-console Google.Protobuf.Test\bin\%configuration%\Google.Protobuf.Test.dll || goto error
+goto :EOF
+
+:error
+echo Failed!
+EXIT /b %ERRORLEVEL%
diff --git a/util/appveyor.yml b/util/appveyor.yml
new file mode 100644
index 0000000..c84ecae
--- /dev/null
+++ b/util/appveyor.yml
@@ -0,0 +1,32 @@
+# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can
+# test more combinations but AppVeyor just takes too long to finish (each
+# combination takes ~15mins).
+platform:
+  - Win64
+
+configuration:
+  - Debug
+
+environment:
+  matrix:
+    - language: cpp
+      BUILD_DLL: ON
+
+    - language: csharp
+
+install:
+  - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+  - 7z x gmock-1.7.0.zip
+  - rename gmock-1.7.0 gmock
+
+before_build:
+  - if %platform%==Win32 set generator=Visual Studio 12
+  - if %platform%==Win64 set generator=Visual Studio 12 Win64
+  - if %platform%==Win32 set vcplatform=Win32
+  - if %platform%==Win64 set vcplatform=x64
+
+build_script:
+  - CALL appveyor.bat
+
+skip_commits:
+  message: /.*\[skip appveyor\].*/
diff --git a/util/autogen.sh b/util/autogen.sh
new file mode 100755
index 0000000..5b4c29f
--- /dev/null
+++ b/util/autogen.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Run this script to generate the configure script and other files that will
+# be included in the distribution.  These files are not checked in because they
+# are automatically generated.
+
+set -e
+
+if [ ! -z "$@" ]; then
+  for argument in "$@"; do
+    case $argument in
+	  # make curl silent
+      "-s")
+        curlopts="-s"
+        ;;
+    esac
+  done
+fi
+
+
+# Check that we're being run from the right directory.
+if test ! -f src/google/protobuf/stubs/common.h; then
+  cat >&2 << __EOF__
+Could not find source code.  Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+  exit 1
+fi
+
+# Check that gmock is present.  Usually it is already there since the
+# directory is set up as an SVN external.
+if test ! -e gmock; then
+  echo "Google Mock not present.  Fetching gmock-1.7.0 from the web..."
+  curl $curlopts -O https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+  unzip -q gmock-1.7.0.zip
+  rm gmock-1.7.0.zip
+  mv gmock-1.7.0 gmock
+fi
+
+set -ex
+
+# TODO(kenton):  Remove the ",no-obsolete" part and fix the resulting warnings.
+autoreconf -f -i -Wall,no-obsolete
+
+rm -rf autom4te.cache config.h.in~
+exit 0
diff --git a/util/configure.ac b/util/configure.ac
new file mode 100644
index 0000000..bdc72ee
--- /dev/null
+++ b/util/configure.ac
@@ -0,0 +1,184 @@
+## Process this file with autoconf to produce configure.
+## In general, the safest way to proceed is to run ./autogen.sh
+
+AC_PREREQ(2.59)
+
+# Note:  If you change the version, you must also update it in:
+# * java/pom.xml
+# * python/setup.py
+# * src/google/protobuf/stubs/common.h
+# * src/Makefile.am (Update -version-info for LDFLAGS if needed)
+#
+# In the SVN trunk, the version should always be the next anticipated release
+# version with the "-pre" suffix.  (We used to use "-SNAPSHOT" but this pushed
+# the size of one file name in the dist tarfile over the 99-char limit.)
+AC_INIT([Protocol Buffers],[3.0.0-beta-3],[protobuf@googlegroups.com],[protobuf])
+
+AM_MAINTAINER_MODE([enable])
+
+AC_CONFIG_SRCDIR(src/google/protobuf/message.cc)
+# The config file is generated but not used by the source code, since we only
+# need very few of them, e.g. HAVE_PTHREAD and HAVE_ZLIB. Those macros are
+# passed down in CXXFLAGS manually in src/Makefile.am
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
+case "$DIST_LANG" in
+  "") DIST_LANG=all ;;
+  all | cpp | csharp | java | python | javanano | objectivec | ruby | js) ;;
+  *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
+esac
+AC_SUBST(DIST_LANG)
+
+# autoconf's default CXXFLAGS are usually "-g -O2".  These aren't necessarily
+# the best choice for libprotobuf.
+AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"],
+      [CFLAGS=""])
+AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"],
+      [CXXFLAGS=""])
+
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE([1.9 tar-ustar subdir-objects])
+
+AC_ARG_WITH([zlib],
+  [AS_HELP_STRING([--with-zlib],
+    [include classes for streaming compressed data in and out @<:@default=check@:>@])],
+  [],[with_zlib=check])
+
+AC_ARG_WITH([protoc],
+  [AS_HELP_STRING([--with-protoc=COMMAND],
+    [use the given protoc command instead of building a new one when building tests (useful for cross-compiling)])],
+  [],[with_protoc=no])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CXX
+AC_LANG([C++])
+ACX_USE_SYSTEM_EXTENSIONS
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc
+AC_PROG_OBJC
+
+# test_util.cc takes forever to compile with GCC and optimization turned on.
+AC_MSG_CHECKING([C++ compiler flags...])
+AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"],[
+  AS_IF([test "$GCC" = "yes"],[
+    PROTOBUF_OPT_FLAG="-O2"
+    CXXFLAGS="${CXXFLAGS} -g"
+  ])
+
+  # Protocol Buffers contains several checks that are intended to be used only
+  # for debugging and which might hurt performance.  Most users are probably
+  # end users who don't want these checks, so add -DNDEBUG by default.
+  CXXFLAGS="$CXXFLAGS -DNDEBUG"
+
+  AC_MSG_RESULT([use default: $PROTOBUF_OPT_FLAG $CXXFLAGS])
+],[
+  AC_MSG_RESULT([use user-supplied: $CXXFLAGS])
+])
+
+AC_SUBST(PROTOBUF_OPT_FLAG)
+
+ACX_CHECK_SUNCC
+
+# Have to do libtool after SUNCC, other wise it "helpfully" adds Crun Cstd
+# to the link
+AC_PROG_LIBTOOL
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h stdlib.h unistd.h])
+
+# Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_STRTOD
+AC_CHECK_FUNCS([ftruncate memset mkdir strchr strerror strtol])
+
+# Check for zlib.
+HAVE_ZLIB=0
+AS_IF([test "$with_zlib" != no], [
+  AC_MSG_CHECKING([zlib version])
+
+  # First check the zlib header version.
+  AC_COMPILE_IFELSE(
+    [AC_LANG_PROGRAM([[
+        #include <zlib.h>
+        #if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
+        # error zlib version too old
+        #endif
+        ]], [])], [
+    AC_MSG_RESULT([ok (1.2.0.4 or later)])
+
+    # Also need to add -lz to the linker flags and make sure this succeeds.
+    AC_SEARCH_LIBS([zlibVersion], [z], [
+      AC_DEFINE([HAVE_ZLIB], [1], [Enable classes using zlib compression.])
+      HAVE_ZLIB=1
+    ], [
+      AS_IF([test "$with_zlib" != check], [
+        AC_MSG_FAILURE([--with-zlib was given, but no working zlib library was found])
+      ])
+    ])
+  ], [
+    AS_IF([test "$with_zlib" = check], [
+      AC_MSG_RESULT([headers missing or too old (requires 1.2.0.4)])
+    ], [
+      AC_MSG_FAILURE([--with-zlib was given, but zlib headers were not present or were too old (requires 1.2.0.4)])
+    ])
+  ])
+])
+AM_CONDITIONAL([HAVE_ZLIB], [test $HAVE_ZLIB = 1])
+
+AS_IF([test "$with_protoc" != "no"], [
+  PROTOC=$with_protoc
+  AS_IF([test "$with_protoc" = "yes"], [
+    # No argument given.  Use system protoc.
+    PROTOC=protoc
+  ])
+  AS_IF([echo "$PROTOC" | grep -q '^@<:@^/@:>@.*/'], [
+    # Does not start with a slash, but contains a slash.  So, it's a relative
+    # path (as opposed to an absolute path or an executable in $PATH).
+    # Since it will actually be executed from the src directory, prefix with
+    # the current directory.  We also insert $ac_top_build_prefix in case this
+    # is a nested package and --with-protoc was actually given on the outer
+    # package's configure script.
+    PROTOC=`pwd`/${ac_top_build_prefix}$PROTOC
+  ])
+  AC_SUBST([PROTOC])
+])
+AM_CONDITIONAL([USE_EXTERNAL_PROTOC], [test "$with_protoc" != "no"])
+
+ACX_PTHREAD
+AM_CONDITIONAL([HAVE_PTHREAD], [test "x$acx_pthread_ok" = "xyes"])
+
+# We still keep this for improving pbconfig.h for unsupported platforms.
+AC_CXX_STL_HASH
+
+case "$target_os" in
+  mingw* | cygwin* | win*)
+    ;;
+  *)
+    # Need to link against rt on Solaris
+    AC_SEARCH_LIBS([sched_yield], [rt], [], [AC_MSG_FAILURE([sched_yield was not found on your system])])
+    ;;
+esac
+
+# Enable ObjC support for conformance directory on OS X.
+OBJC_CONFORMANCE_TEST=0
+case "$target_os" in
+  darwin*)
+    OBJC_CONFORMANCE_TEST=1
+    ;;
+esac
+AM_CONDITIONAL([OBJC_CONFORMANCE_TEST], [test $OBJC_CONFORMANCE_TEST = 1])
+
+# HACK:  Make gmock's configure script pick up our copy of CFLAGS and CXXFLAGS,
+#   since the flags added by ACX_CHECK_SUNCC must be used when compiling gmock
+#   too.
+export CFLAGS
+export CXXFLAGS
+AC_CONFIG_SUBDIRS([gmock])
+
+AC_CONFIG_FILES([Makefile src/Makefile benchmarks/Makefile conformance/Makefile protobuf.pc protobuf-lite.pc])
+AC_OUTPUT
diff --git a/util/generate_descriptor_proto.sh b/util/generate_descriptor_proto.sh
new file mode 100755
index 0000000..c170c83
--- /dev/null
+++ b/util/generate_descriptor_proto.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+# Run this script to regenerate descriptor.pb.{h,cc} after the protocol
+# compiler changes.  Since these files are compiled into the protocol compiler
+# itself, they cannot be generated automatically by a make rule.  "make check"
+# will fail if these files do not match what the protocol compiler would
+# generate.
+#
+# HINT:  Flags passed to generate_descriptor_proto.sh will be passed directly
+#   to make when building protoc.  This is particularly useful for passing
+#   -j4 to run 4 jobs simultaneously.
+
+if test ! -e src/google/protobuf/stubs/common.h; then
+  cat >&2 << __EOF__
+Could not find source code.  Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+  exit 1
+fi
+
+if test ! -e src/Makefile; then
+  cat >&2 << __EOF__
+Could not find src/Makefile.  You must run ./configure (and perhaps
+./autogen.sh) first.
+__EOF__
+  exit 1
+fi
+
+cd src
+
+declare -a RUNTIME_PROTO_FILES=(\
+  google/protobuf/any.proto \
+  google/protobuf/api.proto \
+  google/protobuf/descriptor.proto \
+  google/protobuf/duration.proto \
+  google/protobuf/empty.proto \
+  google/protobuf/field_mask.proto \
+  google/protobuf/source_context.proto \
+  google/protobuf/struct.proto \
+  google/protobuf/timestamp.proto \
+  google/protobuf/type.proto \
+  google/protobuf/wrappers.proto)
+
+CORE_PROTO_IS_CORRECT=0
+PROCESS_ROUND=1
+TMP=$(mktemp -d)
+echo "Updating descriptor protos..."
+while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
+do
+  echo "Round $PROCESS_ROUND"
+  CORE_PROTO_IS_CORRECT=1
+
+  make $@ protoc
+  if test $? -ne 0; then
+    echo "Failed to build protoc."
+    exit 1
+  fi
+
+  ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
+  ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto
+
+  for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
+    BASE_NAME=${PROTO_FILE%.*}
+    diff ${BASE_NAME}.pb.h $TMP/${BASE_NAME}.pb.h > /dev/null
+    if test $? -ne 0; then
+      CORE_PROTO_IS_CORRECT=0
+    fi
+    diff ${BASE_NAME}.pb.cc $TMP/${BASE_NAME}.pb.cc > /dev/null
+    if test $? -ne 0; then
+      CORE_PROTO_IS_CORRECT=0
+    fi
+  done
+
+  diff google/protobuf/compiler/plugin.pb.h $TMP/google/protobuf/compiler/plugin.pb.h > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+  diff google/protobuf/compiler/plugin.pb.cc $TMP/google/protobuf/compiler/plugin.pb.cc > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+
+  # Only override the output if the files are different to avoid re-compilation
+  # of the protoc.
+  if [ $CORE_PROTO_IS_CORRECT -ne 1 ]; then
+    for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
+      BASE_NAME=${PROTO_FILE%.*}
+      mv $TMP/${BASE_NAME}.pb.h ${BASE_NAME}.pb.h
+      mv $TMP/${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc
+    done
+    mv $TMP/google/protobuf/compiler/plugin.pb.* google/protobuf/compiler/
+  fi
+
+  PROCESS_ROUND=$((PROCESS_ROUND + 1))
+done
+cd ..
+
+if test -x objectivec/generate_well_known_types.sh; then
+  echo "Generating messages for objc."
+  objectivec/generate_well_known_types.sh $@
+fi
+
+if test -x csharp/generate_protos.sh; then
+  echo "Generating messages for C#."
+  csharp/generate_protos.sh $@
+fi
diff --git a/util/gmock.BUILD b/util/gmock.BUILD
new file mode 100644
index 0000000..82abf27
--- /dev/null
+++ b/util/gmock.BUILD
@@ -0,0 +1,28 @@
+cc_library(
+    name = "gtest",
+    srcs = [
+        "gmock-1.7.0/gtest/src/gtest-all.cc",
+        "gmock-1.7.0/src/gmock-all.cc",
+    ],
+    hdrs = glob([
+        "gmock-1.7.0/**/*.h",
+        "gmock-1.7.0/gtest/src/*.cc",
+        "gmock-1.7.0/src/*.cc",
+    ]),
+    includes = [
+        "gmock-1.7.0",
+        "gmock-1.7.0/gtest",
+        "gmock-1.7.0/gtest/include",
+        "gmock-1.7.0/include",
+    ],
+    linkopts = ["-pthread"],
+    visibility = ["//visibility:public"],
+)
+
+cc_library(
+    name = "gtest_main",
+    srcs = ["gmock-1.7.0/src/gmock_main.cc"],
+    linkopts = ["-pthread"],
+    visibility = ["//visibility:public"],
+    deps = [":gtest"],
+)
diff --git a/util/post_process_dist.sh b/util/post_process_dist.sh
new file mode 100755
index 0000000..82736bd
--- /dev/null
+++ b/util/post_process_dist.sh
@@ -0,0 +1,64 @@
+#! /bin/sh
+
+# This script takes the result of "make dist" and:
+# 1) Unpacks it.
+# 2) Ensures all contents are user-writable.  Some version control systems
+#    keep code read-only until you explicitly ask to edit it, and the normal
+#    "make dist" process does not correct for this, so the result is that
+#    the entire dist is still marked read-only when unpacked, which is
+#    annoying.  So, we fix it.
+# 3) Convert MSVC project files to MSVC 2005, so that anyone who has version
+#    2005 *or* 2008 can open them.  (In version control, we keep things in
+#    MSVC 2008 format since that's what we use in development.)
+# 4) Uses the result to create .tar.gz, .tar.bz2, and .zip versions and
+#    deposites them in the "dist" directory.  In the .zip version, all
+#    non-testdata .txt files are converted to Windows-style line endings.
+# 5) Cleans up after itself.
+
+if [ "$1" == "" ]; then
+  echo "USAGE:  $0 DISTFILE" >&2
+  exit 1
+fi
+
+if [ ! -e $1 ]; then
+  echo $1": File not found." >&2
+  exit 1
+fi
+
+set -ex
+
+LANGUAGES="cpp csharp java javanano js objectivec python ruby"
+BASENAME=`basename $1 .tar.gz`
+VERSION=${BASENAME:9}
+
+# Create a directory called "dist", copy the tarball there and unpack it.
+mkdir dist
+cp $1 dist
+cd dist
+tar zxvf $BASENAME.tar.gz
+rm $BASENAME.tar.gz
+
+# Set the entire contents to be user-writable.
+chmod -R u+w $BASENAME
+cd $BASENAME
+
+for LANG in $LANGUAGES; do
+  # Build the dist again in .tar.gz
+  ./configure DIST_LANG=$LANG
+  make dist-gzip
+  mv $BASENAME.tar.gz ../protobuf-$LANG-$VERSION.tar.gz
+done
+
+# Convert all text files to use DOS-style line endings, then build a .zip
+# distribution.
+todos *.txt */*.txt
+
+for LANG in $LANGUAGES; do
+  # Build the dist again in .zip
+  ./configure DIST_LANG=$LANG
+  make dist-zip
+  mv $BASENAME.zip ../protobuf-$LANG-$VERSION.zip
+done
+
+cd ..
+rm -rf $BASENAME
diff --git a/util/protobuf-lite.pc.in b/util/protobuf-lite.pc.in
new file mode 100644
index 0000000..80f1f46
--- /dev/null
+++ b/util/protobuf-lite.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Protocol Buffers
+Description: Google's Data Interchange Format
+Version: @VERSION@
+Libs: -L${libdir} -lprotobuf-lite @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
+Cflags: -I${includedir} @PTHREAD_CFLAGS@
+Conflicts: protobuf
diff --git a/util/protobuf.bzl b/util/protobuf.bzl
new file mode 100644
index 0000000..fbcae0b
--- /dev/null
+++ b/util/protobuf.bzl
@@ -0,0 +1,304 @@
+# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
+
+def _GetPath(ctx, path):
+  if ctx.label.workspace_root:
+    return ctx.label.workspace_root + '/' + path
+  else:
+    return path
+
+def _GenDir(ctx):
+  if not ctx.attr.includes:
+    return ctx.label.workspace_root
+  if not ctx.attr.includes[0]:
+    return _GetPath(ctx, ctx.label.package)
+  if not ctx.label.package:
+    return _GetPath(ctx, ctx.attr.includes[0])
+  return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
+
+def _CcOuts(srcs, use_grpc_plugin=False):
+  ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
+        [s[:-len(".proto")] + ".pb.cc" for s in srcs]
+  if use_grpc_plugin:
+    ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] + \
+           [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
+  return ret
+
+def _PyOuts(srcs):
+  return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
+
+def _RelativeOutputPath(path, include):
+  if include == None:
+    return path
+
+  if not path.startswith(include):
+    fail("Include path %s isn't part of the path %s." % (include, path))
+
+  if include and include[-1] != '/':
+    include = include + '/'
+
+  path = path[len(include):]
+
+  if not path.startswith(PACKAGE_NAME):
+    fail("The package %s is not within the path %s" % (PACKAGE_NAME, path))
+
+  if not PACKAGE_NAME:
+    return path
+
+  return path[len(PACKAGE_NAME)+1:]
+
+def _proto_gen_impl(ctx):
+  """General implementation for generating protos"""
+  srcs = ctx.files.srcs
+  deps = []
+  deps += ctx.files.srcs
+  gen_dir = _GenDir(ctx)
+  if gen_dir:
+    import_flags = ["-I" + gen_dir]
+  else:
+    import_flags = ["-I."]
+
+  for dep in ctx.attr.deps:
+    import_flags += dep.proto.import_flags
+    deps += dep.proto.deps
+
+  args = []
+  if ctx.attr.gen_cc:
+    args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+  if ctx.attr.gen_py:
+    args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+
+  if ctx.executable.grpc_cpp_plugin:
+    args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path]
+    args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+
+  if args:
+    ctx.action(
+        inputs=srcs + deps,
+        outputs=ctx.outputs.outs,
+        arguments=args + import_flags + [s.path for s in srcs],
+        executable=ctx.executable.protoc,
+    )
+
+  return struct(
+      proto=struct(
+          srcs=srcs,
+          import_flags=import_flags,
+          deps=deps,
+      ),
+  )
+
+_proto_gen = rule(
+    attrs = {
+        "srcs": attr.label_list(allow_files = True),
+        "deps": attr.label_list(providers = ["proto"]),
+        "includes": attr.string_list(),
+        "protoc": attr.label(
+            cfg = HOST_CFG,
+            executable = True,
+            single_file = True,
+            mandatory = True,
+        ),
+        "grpc_cpp_plugin": attr.label(
+            cfg = HOST_CFG,
+            executable = True,
+            single_file = True,
+        ),
+        "gen_cc": attr.bool(),
+        "gen_py": attr.bool(),
+        "outs": attr.output_list(),
+    },
+    output_to_genfiles = True,
+    implementation = _proto_gen_impl,
+)
+
+def cc_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        cc_libs=[],
+        include=None,
+        protoc="//:protoc",
+        internal_bootstrap_hack=False,
+        use_grpc_plugin=False,
+        default_runtime="//:protobuf",
+        **kargs):
+  """Bazel rule to create a C++ protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the cc_proto_library.
+    srcs: the .proto files of the cc_proto_library.
+    deps: a list of dependency labels; must be cc_proto_library.
+    cc_libs: a list of other cc_library targets depended by the generated
+        cc_library.
+    include: a string indicating the include path of the .proto files.
+    protoc: the label of the protocol compiler to generate the sources.
+    internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
+        for bootstraping. When it is set to True, no files will be generated.
+        The rule will simply be a provider for .proto files, so that other
+        cc_proto_library can depend on it.
+    use_grpc_plugin: a flag to indicate whether to call the grpc C++ plugin
+        when processing the proto files.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated cc_library target.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  if internal_bootstrap_hack:
+    # For pre-checked-in generated files, we add the internal_bootstrap_hack
+    # which will skip the codegen action.
+    _proto_gen(
+        name=name + "_genproto",
+        srcs=srcs,
+        deps=[s + "_genproto" for s in deps],
+        includes=includes,
+        protoc=protoc,
+        visibility=["//visibility:public"],
+    )
+    # An empty cc_library to make rule dependency consistent.
+    native.cc_library(
+        name=name,
+        **kargs)
+    return
+
+  grpc_cpp_plugin = None
+  if use_grpc_plugin:
+    grpc_cpp_plugin = "//external:grpc_cpp_plugin"
+
+  outs = _CcOuts(srcs, use_grpc_plugin)
+
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      grpc_cpp_plugin=grpc_cpp_plugin,
+      gen_cc=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in cc_libs:
+    cc_libs += [default_runtime]
+  if use_grpc_plugin:
+    cc_libs += ["//external:grpc_lib"]
+
+  native.cc_library(
+      name=name,
+      srcs=outs,
+      deps=cc_libs + deps,
+      includes=includes,
+      **kargs)
+
+
+def internal_gen_well_known_protos_java(srcs):
+  """Bazel rule to generate the gen_well_known_protos_java genrule
+
+  Args:
+    srcs: the well known protos
+  """
+  root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root
+  if root == "":
+    include = " -Isrc "
+  else:
+    include = " -I%s/src " % root
+  native.genrule(
+    name = "gen_well_known_protos_java",
+    srcs = srcs,
+    outs = [
+        "wellknown.srcjar",
+    ],
+    cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
+          " %s $(SRCS) " % include +
+          " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
+    tools = [":protoc"],
+  )
+
+
+def py_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        py_libs=[],
+        py_extra_srcs=[],
+        include=None,
+        default_runtime="//:protobuf_python",
+        protoc="//:protoc",
+        **kargs):
+  """Bazel rule to create a Python protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the py_proto_library.
+    srcs: the .proto files of the py_proto_library.
+    deps: a list of dependency labels; must be py_proto_library.
+    py_libs: a list of other py_library targets depended by the generated
+        py_library.
+    py_extra_srcs: extra source files that will be added to the output
+        py_library. This attribute is used for internal bootstrapping.
+    include: a string indicating the include path of the .proto files.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated py_library target.
+    protoc: the label of the protocol compiler to generate the sources.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+  outs = _PyOuts(srcs)
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      gen_py=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in py_libs + deps:
+    py_libs += [default_runtime]
+
+  native.py_library(
+      name=name,
+      srcs=outs+py_extra_srcs,
+      deps=py_libs+deps,
+      imports=includes,
+      **kargs)
+
+def internal_protobuf_py_tests(
+    name,
+    modules=[],
+    **kargs):
+  """Bazel rules to create batch tests for protobuf internal.
+
+  Args:
+    name: the name of the rule.
+    modules: a list of modules for tests. The macro will create a py_test for
+        each of the parameter with the source "google/protobuf/%s.py"
+    kargs: extra parameters that will be passed into the py_test.
+
+  """
+  for m in modules:
+    s = "python/google/protobuf/internal/%s.py" % m
+    native.py_test(
+        name="py_%s" % m,
+        srcs=[s],
+        main=s,
+        **kargs)
diff --git a/util/protobuf.pc.in b/util/protobuf.pc.in
new file mode 100644
index 0000000..4901490
--- /dev/null
+++ b/util/protobuf.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Protocol Buffers
+Description: Google's Data Interchange Format
+Version: @VERSION@
+Libs: -L${libdir} -lprotobuf @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
+Libs.private: @LIBS@
+Cflags: -I${includedir} @PTHREAD_CFLAGS@
+Conflicts: protobuf-lite
diff --git a/util/python/BUILD b/util/python/BUILD
new file mode 100644
index 0000000..3ac0385
--- /dev/null
+++ b/util/python/BUILD
@@ -0,0 +1,18 @@
+# This is a placeholder for python headers. Projects needing to use
+# fast cpp protos in protobuf's python interface should build with
+# --define=use_fast_cpp_protos=true, and in addition, provide
+# //external:python_headers dependency that in turn provides Python.h.
+#
+# Projects that include protobuf using a Bazel external repository will need to
+# add a workspace rule to their WORKSPACE files to add an external workspace
+# that includes the Python headers. For example, the protobuf WORKSPACE file
+# includes the following local_repository rule that points to this directory:
+#
+# new_local_repository(
+#   name = "python",
+#   path = __workspace_dir__ + "/util/python",
+# )
+cc_library(
+    name = "python_headers",
+    visibility = ["//visibility:public"],
+)
diff --git a/util/six.BUILD b/util/six.BUILD
new file mode 100644
index 0000000..fb0b360
--- /dev/null
+++ b/util/six.BUILD
@@ -0,0 +1,13 @@
+genrule(
+  name = "copy_six",
+  srcs = ["six-1.10.0/six.py"],
+  outs = ["six.py"],
+  cmd = "cp $< $(@)",
+)
+
+py_library(
+  name = "six",
+  srcs = ["six.py"],
+  srcs_version = "PY2AND3",
+  visibility = ["//visibility:public"],
+)
diff --git a/util/tests.sh b/util/tests.sh
new file mode 100755
index 0000000..6a9439a
--- /dev/null
+++ b/util/tests.sh
@@ -0,0 +1,347 @@
+#!/bin/bash
+#
+# Build and runs tests for the protobuf project.  The tests as written here are
+# used by both Jenkins and Travis, though some specialized logic is required to
+# handle the differences between them.
+
+on_travis() {
+  if [ "$TRAVIS" == "true" ]; then
+    "$@"
+  fi
+}
+
+# For when some other test needs the C++ main build, including protoc and
+# libprotobuf.
+internal_build_cpp() {
+  if [ -f src/protoc ]; then
+    # Already built.
+    return
+  fi
+
+  if [[ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]]; then
+    # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more
+    # decent C++ 11 support in order to compile conformance tests.
+    sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+    sudo apt-get update -qq
+    sudo apt-get install -qq g++-4.8
+    export CXX="g++-4.8" CC="gcc-4.8"
+  fi
+
+  ./autogen.sh
+  ./configure
+  make -j2
+}
+
+build_cpp() {
+  internal_build_cpp
+  make check -j2
+  cd conformance && make test_cpp && cd ..
+
+  # Verify benchmarking code can build successfully.
+  cd benchmarks && make && ./generate-datasets && cd ..
+}
+
+build_cpp_distcheck() {
+  ./autogen.sh
+  ./configure
+  make distcheck -j2
+}
+
+build_csharp() {
+  # Just for the conformance tests. We don't currently
+  # need to really build protoc, but it's simplest to keep with the
+  # conventions of the other builds.
+  internal_build_cpp
+  NUGET=/usr/local/bin/nuget.exe
+
+  if [ "$TRAVIS" == "true" ]; then
+    # Install latest version of Mono
+    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+    echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
+    echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
+    sudo apt-get update -qq
+    sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit
+    wget www.nuget.org/NuGet.exe -O nuget.exe
+    NUGET=../../nuget.exe
+  fi
+
+  (cd csharp/src; mono $NUGET restore)
+  csharp/buildall.sh
+  cd conformance && make test_csharp && cd ..
+}
+
+build_golang() {
+  # Go build needs `protoc`.
+  internal_build_cpp
+  # Add protoc to the path so that the examples build finds it.
+  export PATH="`pwd`/src:$PATH"
+
+  # Install Go and the Go protobuf compiler plugin.
+  sudo apt-get update -qq
+  sudo apt-get install -qq golang
+  export GOPATH="$HOME/gocode"
+  mkdir -p "$GOPATH/src/github.com/google"
+  ln -s "`pwd`" "$GOPATH/src/github.com/google/protobuf"
+  export PATH="$GOPATH/bin:$PATH"
+  go get github.com/golang/protobuf/protoc-gen-go
+
+  cd examples && make gotest && cd ..
+}
+
+use_java() {
+  version=$1
+  case "$version" in
+    jdk6)
+      on_travis sudo apt-get install openjdk-6-jdk
+      export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH
+      ;;
+    jdk7)
+      on_travis sudo apt-get install openjdk-7-jdk
+      export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
+      ;;
+    oracle7)
+      if [ "$TRAVIS" == "true" ]; then
+        sudo apt-get install python-software-properties # for apt-add-repository
+        echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | \
+          sudo debconf-set-selections
+        yes | sudo apt-add-repository ppa:webupd8team/java
+        yes | sudo apt-get install oracle-java7-installer
+      fi;
+      export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH
+      ;;
+  esac
+
+  if [ "$TRAVIS" != "true" ]; then
+    MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository
+    MVN="$MVN -e -X --offline -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
+  fi;
+
+  which java
+  java -version
+}
+
+# --batch-mode supresses download progress output that spams the logs.
+MVN="mvn --batch-mode"
+
+build_java() {
+  version=$1
+  dir=java_$version
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cp -r java $dir
+  cd $dir && $MVN clean && $MVN test
+  cd ../..
+}
+
+# The conformance tests are hard-coded to work with the $ROOT/java directory.
+# So this can't run in parallel with two different sets of tests.
+build_java_with_conformance_tests() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd java && $MVN test && $MVN install
+  cd util && $MVN package assembly:single
+  cd ../..
+  cd conformance && make test_java && cd ..
+}
+
+build_javanano() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd javanano && $MVN test && cd ..
+}
+
+build_java_jdk6() {
+  use_java jdk6
+  build_java jdk6
+}
+build_java_jdk7() {
+  use_java jdk7
+  build_java_with_conformance_tests
+}
+build_java_oracle7() {
+  use_java oracle7
+  build_java oracle7
+}
+
+build_javanano_jdk6() {
+  use_java jdk6
+  build_javanano
+}
+build_javanano_jdk7() {
+  use_java jdk7
+  build_javanano
+}
+build_javanano_oracle7() {
+  use_java oracle7
+  build_javanano
+}
+
+internal_install_python_deps() {
+  if [ "$TRAVIS" != "true" ]; then
+    return;
+  fi
+  # Install tox (OS X doesn't have pip).
+  if [ $(uname -s) == "Darwin" ]; then
+    sudo easy_install tox
+  else
+    sudo pip install tox
+  fi
+  # Only install Python2.6/3.x on Linux.
+  if [ $(uname -s) == "Linux" ]; then
+    sudo apt-get install -y python-software-properties # for apt-add-repository
+    sudo apt-add-repository -y ppa:fkrull/deadsnakes
+    sudo apt-get update -qq
+    sudo apt-get install -y python2.6 python2.6-dev
+    sudo apt-get install -y python3.3 python3.3-dev
+    sudo apt-get install -y python3.4 python3.4-dev
+  fi
+}
+
+internal_objectivec_common () {
+  # Make sure xctool is up to date. Adapted from
+  #  http://docs.travis-ci.com/user/osx-ci-environment/
+  # We don't use a before_install because we test multiple OSes.
+  brew update
+  brew outdated xctool || brew upgrade xctool
+  # Reused the build script that takes care of configuring and ensuring things
+  # are up to date. Xcode and conformance tests will be directly invoked.
+  objectivec/DevTools/full_mac_build.sh \
+      --core-only --skip-xcode --skip-objc-conformance
+}
+
+internal_xctool_debug_and_release() {
+  # Always use -reporter plain to avoid escape codes in output (makes travis
+  # logs easier to read).
+  xctool -reporter plain -configuration Debug "$@"
+  xctool -reporter plain -configuration Release "$@"
+}
+
+build_objectivec_ios() {
+  internal_objectivec_common
+  # https://github.com/facebook/xctool/issues/509 - unlike xcodebuild, xctool
+  # doesn't support >1 destination, so we have to build first and then run the
+  # tests one destination at a time.
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+    -scheme ProtocolBuffers \
+    -sdk iphonesimulator \
+    build-tests
+  IOS_DESTINATIONS=(
+    "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
+    "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
+  )
+  for i in "${IOS_DESTINATIONS[@]}" ; do
+    internal_xctool_debug_and_release \
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+      -scheme ProtocolBuffers \
+      -sdk iphonesimulator \
+      -destination "${i}" \
+      run-tests
+  done
+}
+
+build_objectivec_osx() {
+  internal_objectivec_common
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_OSX.xcodeproj \
+    -scheme ProtocolBuffers \
+    -destination "platform=OS X,arch=x86_64" \
+    test
+  cd conformance && make test_objc && cd ..
+}
+
+build_python() {
+  internal_build_cpp
+  internal_install_python_deps
+  cd python
+  # Only test Python 2.6/3.x on Linux
+  if [ $(uname -s) == "Linux" ]; then
+    envlist=py\{26,27,33,34\}-python
+  else
+    envlist=py27-python
+  fi
+  tox -e $envlist
+  cd ..
+}
+
+build_python_cpp() {
+  internal_build_cpp
+  internal_install_python_deps
+  export LD_LIBRARY_PATH=../src/.libs # for Linux
+  export DYLD_LIBRARY_PATH=../src/.libs # for OS X
+  cd python
+  # Only test Python 2.6/3.x on Linux
+  if [ $(uname -s) == "Linux" ]; then
+    # py26 is currently disabled due to json_format
+    envlist=py\{27,33,34\}-cpp
+  else
+    envlist=py27-cpp
+  fi
+  tox -e $envlist
+  cd ..
+}
+
+build_ruby19() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-1.9 && cd ..
+}
+build_ruby20() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.0 && cd ..
+}
+build_ruby21() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.1 && cd ..
+}
+build_ruby22() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh ruby-2.2 && cd ..
+}
+build_jruby() {
+  internal_build_cpp  # For conformance tests.
+  cd ruby && bash travis-test.sh jruby && cd ..
+}
+
+build_javascript() {
+  internal_build_cpp
+  cd js && npm install && npm test && cd ..
+}
+
+# Note: travis currently does not support testing more than one language so the
+# .travis.yml cheats and claims to only be cpp.  If they add multiple language
+# support, this should probably get updated to install steps and/or
+# rvm/gemfile/jdk/etc. entries rather than manually doing the work.
+
+# .travis.yml uses matrix.exclude to block the cases where app-get can't be
+# use to install things.
+
+# -------- main --------
+
+if [ "$#" -ne 1 ]; then
+  echo "
+Usage: $0 { cpp |
+            csharp |
+            java_jdk6 |
+            java_jdk7 |
+            java_oracle7 |
+            javanano_jdk6 |
+            javanano_jdk7 |
+            javanano_oracle7 |
+            objectivec_ios |
+            objectivec_osx |
+            python |
+            python_cpp |
+            ruby19 |
+            ruby20 |
+            ruby21 |
+            ruby22 |
+            jruby }
+"
+  exit 1
+fi
+
+set -e  # exit immediately on error
+set -x  # display all commands
+eval "build_$1"
diff --git a/util/update_file_lists.sh b/util/update_file_lists.sh
new file mode 100755
index 0000000..d76a161
--- /dev/null
+++ b/util/update_file_lists.sh
@@ -0,0 +1,191 @@
+#!/bin/sh
+
+# This script copies source file lists from src/Makefile.am to cmake files.
+
+get_variable_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  awk "
+    BEGIN { start = 0; }
+    /^$VARNAME =/ { start = 1; }
+    { if (start) { print \$0; } }
+    /\\\\\$/ { next; }
+    { start = 0; }
+  " $FILENAME \
+    | sed "s/^$VARNAME =//" \
+    | sed "s/[ \\]//g" \
+    | grep -v "^\\$" \
+    | grep -v "^$" \
+    | LC_ALL=C sort | uniq
+}
+
+get_header_files() {
+  get_variable_value $@ | grep '\.h$'
+}
+
+get_source_files() {
+  get_variable_value $@ | grep "cc$"
+}
+
+get_proto_files_blacklisted() {
+  get_proto_files $@ | sed '/^google\/protobuf\/unittest_enormous_descriptor.proto$/d'
+}
+
+get_proto_files() {
+  get_variable_value $@ | grep "pb.cc$" | sed "s/pb.cc/proto/"
+}
+
+sort_files() {
+  for FILE in $@; do
+    echo $FILE
+  done | LC_ALL=C sort | uniq
+}
+
+MAKEFILE=src/Makefile.am
+
+[ -f "$MAKEFILE" ] || {
+  echo "Cannot find: $MAKEFILE"
+  exit 1
+}
+
+# Extract file lists from src/Makefile.am
+GZHEADERS=$(get_variable_value $MAKEFILE GZHEADERS)
+HEADERS=$(get_variable_value $MAKEFILE nobase_include_HEADERS)
+PUBLIC_HEADERS=$(sort_files $GZHEADERS $HEADERS)
+LIBPROTOBUF_LITE_SOURCES=$(get_source_files $MAKEFILE libprotobuf_lite_la_SOURCES)
+LIBPROTOBUF_SOURCES=$(get_source_files $MAKEFILE libprotobuf_la_SOURCES)
+LIBPROTOC_SOURCES=$(get_source_files $MAKEFILE libprotoc_la_SOURCES)
+LITE_PROTOS=$(get_proto_files $MAKEFILE protoc_lite_outputs)
+PROTOS=$(get_proto_files $MAKEFILE protoc_outputs)
+PROTOS_BLACKLISTED=$(get_proto_files_blacklisted $MAKEFILE protoc_outputs)
+WKT_PROTOS=$(get_variable_value $MAKEFILE nobase_dist_proto_DATA)
+COMMON_TEST_SOURCES=$(get_source_files $MAKEFILE COMMON_TEST_SOURCES)
+COMMON_LITE_TEST_SOURCES=$(get_source_files $MAKEFILE COMMON_LITE_TEST_SOURCES)
+TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_test_SOURCES)
+LITE_TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_lite_test_SOURCES)
+LITE_ARENA_TEST_SOURCES=$(get_source_files $MAKEFILE protobuf_lite_arena_test_SOURCES)
+TEST_PLUGIN_SOURCES=$(get_source_files $MAKEFILE test_plugin_SOURCES)
+
+################################################################################
+# Update cmake files.
+################################################################################
+
+CMAKE_DIR=cmake
+EXTRACT_INCLUDES_BAT=cmake/extract_includes.bat.in
+[ -d "$CMAKE_DIR" ] || {
+  echo "Cannot find: $CMAKE_DIR"
+  exit 1
+}
+
+[ -f "$EXTRACT_INCLUDES_BAT" ] || {
+  echo "Cannot find: $EXTRACT_INCLUDES_BAT"
+  exit 1
+}
+
+set_cmake_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  local PREFIX=$3
+  shift
+  shift
+  shift
+  awk -v values="$*" -v prefix="$PREFIX" "
+    BEGIN { start = 0; }
+    /^set\\($VARNAME/ {
+      start = 1;
+      print \$0;
+      len = split(values, vlist, \" \");
+      for (i = 1; i <= len; ++i) {
+        printf(\"  %s%s\\n\", prefix, vlist[i]);
+      }
+      next;
+    }
+    start && /^\\)/ {
+      start = 0;
+    }
+    !start {
+      print \$0;
+    }
+  " $FILENAME > /tmp/$$
+  cp /tmp/$$ $FILENAME
+}
+
+
+# Replace file lists in cmake files.
+CMAKE_PREFIX="\${protobuf_source_dir}/src/"
+set_cmake_value $CMAKE_DIR/libprotobuf-lite.cmake libprotobuf_lite_files $CMAKE_PREFIX $LIBPROTOBUF_LITE_SOURCES
+set_cmake_value $CMAKE_DIR/libprotobuf.cmake libprotobuf_files $CMAKE_PREFIX $LIBPROTOBUF_SOURCES
+set_cmake_value $CMAKE_DIR/libprotoc.cmake libprotoc_files $CMAKE_PREFIX $LIBPROTOC_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_test_protos "" $LITE_PROTOS
+set_cmake_value $CMAKE_DIR/tests.cmake tests_protos "" $PROTOS_BLACKLISTED
+set_cmake_value $CMAKE_DIR/tests.cmake common_test_files $CMAKE_PREFIX $COMMON_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake common_lite_test_files $CMAKE_PREFIX $COMMON_LITE_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake tests_files $CMAKE_PREFIX $TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_test_files $CMAKE_PREFIX $LITE_TEST_SOURCES
+set_cmake_value $CMAKE_DIR/tests.cmake lite_arena_test_files $CMAKE_PREFIX $LITE_ARENA_TEST_SOURCES
+
+# Generate extract_includes.bat
+echo "mkdir include" > $EXTRACT_INCLUDES_BAT
+for HEADER in $PUBLIC_HEADERS; do
+  HEADER_DIR=$(dirname $HEADER)
+  while [ ! "$HEADER_DIR" = "." ]; do
+    echo $HEADER_DIR | sed "s/\\//\\\\/g"
+    HEADER_DIR=$(dirname $HEADER_DIR)
+  done
+done | sort | uniq | sed "s/^/mkdir include\\\\/" >> $EXTRACT_INCLUDES_BAT
+for HEADER in $PUBLIC_HEADERS; do
+  WINPATH=$(echo $HEADER | sed 's;/;\\;g')
+  echo "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\..\\src\\$WINPATH include\\$WINPATH" >> $EXTRACT_INCLUDES_BAT
+done
+
+################################################################################
+# Update bazel BUILD files.
+################################################################################
+
+set_bazel_value() {
+  local FILENAME=$1
+  local VARNAME=$2
+  local PREFIX=$3
+  shift
+  shift
+  shift
+  awk -v values="$*" -v prefix="$PREFIX" "
+    BEGIN { start = 0; }
+    /# AUTOGEN\\($VARNAME\\)/ {
+      start = 1;
+      print \$0;
+      # replace \$0 with indent.
+      sub(/#.*/, \"\", \$0)
+      len = split(values, vlist, \" \");
+      for (i = 1; i <= len; ++i) {
+        printf(\"%s\\\"%s%s\\\",\n\", \$0, prefix, vlist[i]);
+      }
+      next;
+    }
+    start && /\]/ {
+      start = 0
+    }
+    !start {
+      print \$0;
+    }
+  " $FILENAME > /tmp/$$
+  cp /tmp/$$ $FILENAME
+}
+
+
+BAZEL_BUILD=./BUILD
+BAZEL_PREFIX="src/"
+if [ -f "$BAZEL_BUILD" ]; then
+  set_bazel_value $BAZEL_BUILD protobuf_lite_srcs $BAZEL_PREFIX $LIBPROTOBUF_LITE_SOURCES
+  set_bazel_value $BAZEL_BUILD protobuf_srcs $BAZEL_PREFIX $LIBPROTOBUF_SOURCES
+  set_bazel_value $BAZEL_BUILD protoc_lib_srcs $BAZEL_PREFIX $LIBPROTOC_SOURCES
+  set_bazel_value $BAZEL_BUILD lite_test_protos "" $LITE_PROTOS
+  set_bazel_value $BAZEL_BUILD well_known_protos "" $WKT_PROTOS
+  set_bazel_value $BAZEL_BUILD test_protos "" $PROTOS
+  set_bazel_value $BAZEL_BUILD common_test_srcs $BAZEL_PREFIX $COMMON_TEST_SOURCES
+  set_bazel_value $BAZEL_BUILD test_srcs $BAZEL_PREFIX $TEST_SOURCES
+  set_bazel_value $BAZEL_BUILD test_plugin_srcs $BAZEL_PREFIX $TEST_PLUGIN_SOURCES
+else
+  echo "Skipped BUILD file update."
+fi
+
diff --git a/vsprojects/config.h b/vsprojects/config.h
deleted file mode 100644
index 2c64450..0000000
--- a/vsprojects/config.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* protobuf config.h for MSVC.  On other platforms, this is generated
- * automatically by autoheader / autoconf / configure. */
-
-/* the location of <hash_map> */
-#define HASH_MAP_H <hash_map>
-
-/* the namespace of hash_map/hash_set */
-// Apparently Microsoft decided to move hash_map *back* to the std namespace
-// in MSVC 2010:
-//   http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
-// TODO(kenton):  Use unordered_map instead, which is available in MSVC 2010.
-#if _MSC_VER < 1310 || _MSC_VER >= 1600
-#define HASH_NAMESPACE std
-#else
-#define HASH_NAMESPACE stdext
-#endif
-
-/* the location of <hash_set> */
-#define HASH_SET_H <hash_set>
-
-/* define if the compiler has hash_map */
-#define HAVE_HASH_MAP 1
-
-/* define if the compiler has hash_set */
-#define HAVE_HASH_SET 1
-
-/* define if you want to use zlib.  See readme.txt for additional
- * requirements. */
-// #define HAVE_ZLIB 1
diff --git a/vsprojects/convert2008to2005.sh b/vsprojects/convert2008to2005.sh
deleted file mode 100755
index 60eccaf..0000000
--- a/vsprojects/convert2008to2005.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#! /bin/sh -e
-
-# This script downgrades MSVC 2008 projects to MSVC 2005 projects, allowing
-# people with MSVC 2005 to open them.  Otherwise, MSVC 2005 simply refuses to
-# open projects created with 2008.  We run this as part of our release process.
-# If you obtained the code direct from version control and you want to use
-# MSVC 2005, you may have to run this manually.  (Hint:  Use Cygwin or MSYS.)
-
-for file in *.sln; do
-  echo "downgrading $file..."
-  sed -i -re 's/Format Version 10.00/Format Version 9.00/g;
-              s/Visual Studio 2008/Visual Studio 2005/g;' $file
-done
-
-for file in *.vcproj; do
-  echo "downgrading $file..."
-  sed -i -re 's/Version="9.00"/Version="8.00"/g;' $file
-done
-
-# Yes, really, that's it.
diff --git a/vsprojects/extract_includes.bat b/vsprojects/extract_includes.bat
deleted file mode 100755
index beab8c4..0000000
--- a/vsprojects/extract_includes.bat
+++ /dev/null
@@ -1,50 +0,0 @@
-md include
-md include\google
-md include\google\protobuf
-md include\google\protobuf\stubs
-md include\google\protobuf\io
-md include\google\protobuf\compiler
-md include\google\protobuf\compiler\cpp
-md include\google\protobuf\compiler\java
-md include\google\protobuf\compiler\python
-copy ..\src\google\protobuf\stubs\atomicops.h include\google\protobuf\stubs\atomicops.h
-copy ..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h include\google\protobuf\stubs\atomicops_internals_x86_msvc.h
-copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h
-copy ..\src\google\protobuf\stubs\once.h include\google\protobuf\stubs\once.h
-copy ..\src\google\protobuf\stubs\platform_macros.h include\google\protobuf\stubs\platform_macros.h
-copy ..\src\google\protobuf\stubs\template_util.h include\google\protobuf\stubs\template_util.h
-copy ..\src\google\protobuf\stubs\type_traits.h include\google\protobuf\stubs\type_traits.h
-copy ..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h
-copy ..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h
-copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h
-copy ..\src\google\protobuf\dynamic_message.h include\google\protobuf\dynamic_message.h
-copy ..\src\google\protobuf\extension_set.h include\google\protobuf\extension_set.h
-copy ..\src\google\protobuf\generated_enum_reflection.h include\google\protobuf\generated_enum_reflection.h
-copy ..\src\google\protobuf\generated_message_util.h include\google\protobuf\generated_message_util.h
-copy ..\src\google\protobuf\generated_message_reflection.h include\google\protobuf\generated_message_reflection.h
-copy ..\src\google\protobuf\message.h include\google\protobuf\message.h
-copy ..\src\google\protobuf\message_lite.h include\google\protobuf\message_lite.h
-copy ..\src\google\protobuf\reflection_ops.h include\google\protobuf\reflection_ops.h
-copy ..\src\google\protobuf\repeated_field.h include\google\protobuf\repeated_field.h
-copy ..\src\google\protobuf\service.h include\google\protobuf\service.h
-copy ..\src\google\protobuf\text_format.h include\google\protobuf\text_format.h
-copy ..\src\google\protobuf\unknown_field_set.h include\google\protobuf\unknown_field_set.h
-copy ..\src\google\protobuf\wire_format.h include\google\protobuf\wire_format.h
-copy ..\src\google\protobuf\wire_format_lite.h include\google\protobuf\wire_format_lite.h
-copy ..\src\google\protobuf\wire_format_lite_inl.h include\google\protobuf\wire_format_lite_inl.h
-copy ..\src\google\protobuf\io\coded_stream.h include\google\protobuf\io\coded_stream.h
-copy ..\src\google\protobuf\io\gzip_stream.h include\google\protobuf\io\gzip_stream.h
-copy ..\src\google\protobuf\io\printer.h include\google\protobuf\io\printer.h
-copy ..\src\google\protobuf\io\strtod.h include\google\protobuf\io\strtod.h
-copy ..\src\google\protobuf\io\tokenizer.h include\google\protobuf\io\tokenizer.h
-copy ..\src\google\protobuf\io\zero_copy_stream.h include\google\protobuf\io\zero_copy_stream.h
-copy ..\src\google\protobuf\io\zero_copy_stream_impl.h include\google\protobuf\io\zero_copy_stream_impl.h
-copy ..\src\google\protobuf\io\zero_copy_stream_impl_lite.h include\google\protobuf\io\zero_copy_stream_impl_lite.h
-copy ..\src\google\protobuf\compiler\code_generator.h include\google\protobuf\compiler\code_generator.h
-copy ..\src\google\protobuf\compiler\command_line_interface.h include\google\protobuf\compiler\command_line_interface.h
-copy ..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h
-copy ..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
-copy ..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h
-copy ..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
-copy ..\src\google\protobuf\compiler\python\python_generator.h include\google\protobuf\compiler\python\python_generator.h
-copy ..\src\google\protobuf\compiler\plugin.h include\google\protobuf\compiler\plugin.h
diff --git a/vsprojects/libprotobuf-lite.vcproj b/vsprojects/libprotobuf-lite.vcproj
deleted file mode 100644
index 06b1598..0000000
--- a/vsprojects/libprotobuf-lite.vcproj
+++ /dev/null
@@ -1,302 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="libprotobuf-lite"
-	ProjectGUID="{49EA010D-706F-4BE2-A397-77854B72A040}"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream_inl.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.h"
-				>
-			</File>
-			<File
-				RelativePath=".\config.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\hash.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\map-util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_lite.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\platform_macros.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stl_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite_inl.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\template_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\type_traits.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_util.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/libprotobuf.vcproj b/vsprojects/libprotobuf.vcproj
deleted file mode 100644
index 1a488f7..0000000
--- a/vsprojects/libprotobuf.vcproj
+++ /dev/null
@@ -1,470 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="libprotobuf"
-	ProjectGUID="{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOBUF_EXPORTS;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream_inl.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.h"
-				>
-			</File>
-			<File
-				RelativePath=".\config.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.pb.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor_database.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\dynamic_message.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_reflection.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\gzip_stream.h"
-				>
-			</File>
-			<File
-			        RelativePath="..\src\google\protobuf\io\strtod.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\hash.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\importer.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\map_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_lite.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\platform_macros.h"
-			>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\parser.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\printer.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_ops.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\service.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stl_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\template_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\type_traits.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\strutil.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\substitute.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\text_format.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\tokenizer.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\unknown_field_set.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite_inl.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor_database.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\dynamic_message.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set_heavy.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_reflection.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_util.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\gzip_stream.cc"
-				>
-			</File>
-			<File
-			        RelativePath="..\src\google\protobuf\io\strtod.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\importer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\parser.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\printer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_ops.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\service.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\structurally_valid.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\strutil.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\substitute.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\text_format.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\tokenizer.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\unknown_field_set.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_impl_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj
deleted file mode 100644
index ccbc0b3..0000000
--- a/vsprojects/libprotoc.vcproj
+++ /dev/null
@@ -1,466 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="libprotoc"
-	ProjectGUID="{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="4"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBPROTOC_EXPORTS;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLibrarianTool"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\code_generator.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\command_line_interface.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\subprocess.h"
-				>
-			</File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\zip_writer.h"
-        >
-      </File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\plugin.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\plugin.pb.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_options.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_context.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_enum.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_extension.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_file.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_generator.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_generator_factory.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_helpers.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_message.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_message_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_service.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_shared_code_generator.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_string_field.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\python\python_generator.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\code_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\command_line_interface.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\subprocess.cc"
-				>
-			</File>
-      <File
-        RelativePath="..\src\google\protobuf\compiler\zip_writer.cc"
-        >
-      </File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\plugin.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\plugin.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_enum_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_extension.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_file.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_helpers.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_message_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_primitive_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_service.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_string_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_context.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_enum.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_extension.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_file.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_generator_factory.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_helpers.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_message.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_message_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_service.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_shared_code_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_string_field.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\python\python_generator.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/lite-test.vcproj b/vsprojects/lite-test.vcproj
deleted file mode 100644
index 0314b36..0000000
--- a/vsprojects/lite-test.vcproj
+++ /dev/null
@@ -1,305 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="lite-test"
-	ProjectGUID="{12015ACE-42BE-4952-A5A0-44A9A46908E2}"
-	RootNamespace="tests"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\test_util_lite.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_lite.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_lite.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_public_lite.pb.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\lite_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\test_util_lite.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_lite.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_lite.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_public_lite.pb.cc"
-				>
-			</File>
-		</Filter>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_lite.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_lite.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_lite.pb.h;google\protobuf\unittest_lite.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_lite.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_lite.pb.h;google\protobuf\unittest_lite.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_import_lite.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_lite.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_lite.pb.h;google\protobuf\unittest_import_lite.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_lite.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_lite.pb.h;google\protobuf\unittest_import_lite.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_import_public_lite.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_public_lite.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_public_lite.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public_lite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_public_lite.pb.h;google\protobuf\unittest_import_public_lite.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/protobuf.sln b/vsprojects/protobuf.sln
deleted file mode 100644
index 567dee6..0000000
--- a/vsprojects/protobuf.sln
+++ /dev/null
@@ -1,92 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf", "libprotobuf.vcproj", "{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotoc", "libprotoc.vcproj", "{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}"
-	ProjectSection(ProjectDependencies) = postProject
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "protoc.vcproj", "{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}"
-	ProjectSection(ProjectDependencies) = postProject
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests.vcproj", "{4DF72760-C055-40A5-A77E-30A17E2AC2DB}"
-	ProjectSection(ProjectDependencies) = postProject
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} = {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}
-		{3AF54C8A-10BF-4332-9147-F68ED9862032} = {3AF54C8A-10BF-4332-9147-F68ED9862032}
-		{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32} = {CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\gtest\msvc\gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "..\gtest\msvc\gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libprotobuf-lite", "libprotobuf-lite.vcproj", "{49EA010D-706F-4BE2-A397-77854B72A040}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lite-test", "lite-test.vcproj", "{12015ACE-42BE-4952-A5A0-44A9A46908E2}"
-	ProjectSection(ProjectDependencies) = postProject
-		{49EA010D-706F-4BE2-A397-77854B72A040} = {49EA010D-706F-4BE2-A397-77854B72A040}
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E} = {1738D5F6-ED1E-47E0-B2F0-456864B93C1E}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_plugin", "test_plugin.vcproj", "{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}"
-	ProjectSection(ProjectDependencies) = postProject
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE} = {B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30} = {3E283F37-A4ED-41B7-A3E6-A2D89D131A30}
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7} = {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Win32 = Debug|Win32
-		Release|Win32 = Release|Win32
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.ActiveCfg = Debug|Win32
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Debug|Win32.Build.0 = Debug|Win32
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.ActiveCfg = Release|Win32
-		{3E283F37-A4ED-41B7-A3E6-A2D89D131A30}.Release|Win32.Build.0 = Release|Win32
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.ActiveCfg = Debug|Win32
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Debug|Win32.Build.0 = Debug|Win32
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.ActiveCfg = Release|Win32
-		{B84FF31A-5F9A-46F8-AB22-DBFC9BECE3BE}.Release|Win32.Build.0 = Release|Win32
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.ActiveCfg = Debug|Win32
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Debug|Win32.Build.0 = Debug|Win32
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.ActiveCfg = Release|Win32
-		{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}.Release|Win32.Build.0 = Release|Win32
-		{4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.ActiveCfg = Debug|Win32
-		{4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Debug|Win32.Build.0 = Debug|Win32
-		{4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.ActiveCfg = Release|Win32
-		{4DF72760-C055-40A5-A77E-30A17E2AC2DB}.Release|Win32.Build.0 = Release|Win32
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.ActiveCfg = Debug|Win32
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.Build.0 = Debug|Win32
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.ActiveCfg = Release|Win32
-		{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.Build.0 = Release|Win32
-		{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.ActiveCfg = Debug|Win32
-		{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.Build.0 = Debug|Win32
-		{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.ActiveCfg = Release|Win32
-		{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.Build.0 = Release|Win32
-		{49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.ActiveCfg = Debug|Win32
-		{49EA010D-706F-4BE2-A397-77854B72A040}.Debug|Win32.Build.0 = Debug|Win32
-		{49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.ActiveCfg = Release|Win32
-		{49EA010D-706F-4BE2-A397-77854B72A040}.Release|Win32.Build.0 = Release|Win32
-		{12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.ActiveCfg = Debug|Win32
-		{12015ACE-42BE-4952-A5A0-44A9A46908E2}.Debug|Win32.Build.0 = Debug|Win32
-		{12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.ActiveCfg = Release|Win32
-		{12015ACE-42BE-4952-A5A0-44A9A46908E2}.Release|Win32.Build.0 = Release|Win32
-		{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}.Debug|Win32.ActiveCfg = Debug|Win32
-		{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}.Debug|Win32.Build.0 = Debug|Win32
-		{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}.Release|Win32.ActiveCfg = Release|Win32
-		{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}.Release|Win32.Build.0 = Release|Win32
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal
diff --git a/vsprojects/protoc.vcproj b/vsprojects/protoc.vcproj
deleted file mode 100644
index 17e8474..0000000
--- a/vsprojects/protoc.vcproj
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="protoc"
-	ProjectGUID="{1738D5F6-ED1E-47E0-B2F0-456864B93C1E}"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;."
-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\main.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/readme.txt b/vsprojects/readme.txt
deleted file mode 100644
index 288345a..0000000
--- a/vsprojects/readme.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-This directory contains project files for compiling Protocol Buffers using
-MSVC.  This is not the recommended way to do Protocol Buffer development --
-we prefer to develop under a Unix-like environment -- but it may be more
-accessible to those who primarily work with MSVC.
-
-Compiling and Installing
-========================
-
-1) Open protobuf.sln in Microsoft Visual Studio.
-2) Choose "Debug" or "Release" configuration as desired.*
-3) From the Build menu, choose "Build Solution".  Wait for compiling to finish.
-4) From a command shell, run tests.exe and lite-test.exe and check that all
-   tests pass.
-5) Run extract_includes.bat to copy all the public headers into a separate
-   "include" directory (under the top-level package directory).
-6) Copy the contents of the include directory to wherever you want to put
-   headers.
-7) Copy protoc.exe wherever you put build tools (probably somewhere in your
-   PATH).
-8) Copy libprotobuf.lib, libprotobuf-lite.lib, and libprotoc.lib wherever you
-   put libraries.
-
-* To avoid conflicts between the MSVC debug and release runtime libraries, when
-  compiling a debug build of your application, you may need to link against a
-  debug build of libprotobuf.lib.  Similarly, release builds should link against
-  release libs.
-
-DLLs vs. static linking
-=======================
-
-Static linking is now the default for the Protocol Buffer libraries.  Due to
-issues with Win32's use of a separate heap for each DLL, as well as binary
-compatibility issues between different versions of MSVC's STL library, it is
-recommended that you use static linkage only.  However, it is possible to
-build libprotobuf and libprotoc as DLLs if you really want.  To do this,
-do the following:
-
-  1) Open protobuf.sln in MSVC.
-  2) For each of the projects libprotobuf, libprotobuf-lite, and libprotoc, do
-     the following:
-    2a) Right-click the project and choose "properties".
-    2b) From the side bar, choose "General", under "Configuration Properties".
-    2c) Change the "Configuration Type" to "Dynamic Library (.dll)".
-    2d) From the side bar, choose "Preprocessor", under "C/C++".
-    2e) Add PROTOBUF_USE_DLLS to the list of preprocessor defines.
-  3) When compiling your project, make sure to #define PROTOBUF_USE_DLLS.
-
-When distributing your software to end users, we strongly recommend that you
-do NOT install libprotobuf.dll or libprotoc.dll to any shared location.
-Instead, keep these libraries next to your binaries, in your application's
-own install directory.  C++ makes it very difficult to maintain binary
-compatibility between releases, so it is likely that future versions of these
-libraries will *not* be usable as drop-in replacements.
-
-If your project is itself a DLL intended for use by third-party software, we
-recommend that you do NOT expose protocol buffer objects in your library's
-public interface, and that you statically link protocol buffers into your
-library.
-
-ZLib support
-============
-
-If you want to include GzipInputStream and GzipOutputStream
-(google/protobuf/io/gzip_stream.h) in libprotoc, you will need to do a few
-additional steps:
-
-1) Obtain a copy of the zlib library.  The pre-compiled DLL at zlib.net works.
-2) Make sure zlib's two headers are in your include path and that the .lib file
-   is in your library path.  You could place all three files directly into the
-   vsproject directory to compile libprotobuf, but they need to be visible to
-   your own project as well, so you should probably just put them into the
-   VC shared icnlude and library directories.
-3) Right-click on the "tests" project and choose "properties".  Navigate the
-   sidebar to "Configuration Properties" -> "Linker" -> "Input".
-4) Under "Additional Dependencies", add the name of the zlib .lib file (e.g.
-   zdll.lib).  Make sure to update both the Debug and Release configurations.
-5) If you are compiling libprotobuf and libprotoc as DLLs (see previous
-   section), repeat steps 2 and 3 for the libprotobuf and libprotoc projects.
-   If you are compiling them as static libraries, then you will need to link
-   against the zlib library directly from your own app.
-6) Edit config.h (in the vsprojects directory) and un-comment the line that
-   #defines HAVE_ZLIB.  (Or, alternatively, define this macro via the project
-   settings.)
-
-Notes on Compiler Warnings
-==========================
-
-The following warnings have been disabled while building the protobuf libraries
-and compiler.  You may have to disable some of them in your own project as
-well, or live with them.
-
-C4018 - 'expression' : signed/unsigned mismatch
-C4146 - unary minus operator applied to unsigned type, result still unsigned
-C4244 - Conversion from 'type1' to 'type2', possible loss of data.
-C4251 - 'identifier' : class 'type' needs to have dll-interface to be used by
-        clients of class 'type2'
-C4267 - Conversion from 'size_t' to 'type', possible loss of data.
-C4305 - 'identifier' : truncation from 'type1' to 'type2'
-C4355 - 'this' : used in base member initializer list
-C4800 - 'type' : forcing value to bool 'true' or 'false' (performance warning)
-C4996 - 'function': was declared deprecated
-
-C4251 is of particular note, if you are compiling the Protocol Buffer library
-as a DLL (see previous section).  The protocol buffer library uses templates in
-its public interfaces.  MSVC does not provide any reasonable way to export
-template classes from a DLL.  However, in practice, it appears that exporting
-templates is not necessary anyway.  Since the complete definition of any
-template is available in the header files, anyone importing the DLL will just
-end up compiling instances of the templates into their own binary.  The
-Protocol Buffer implementation does not rely on static template members being
-unique, so there should be no problem with this, but MSVC prints warning
-nevertheless.  So, we disable it.  Unfortunately, this warning will also be
-produced when compiling code which merely uses protocol buffers, meaning you
-may have to disable it in your code too.
diff --git a/vsprojects/test_plugin.vcproj b/vsprojects/test_plugin.vcproj
deleted file mode 100755
index 2dcf2ad..0000000
--- a/vsprojects/test_plugin.vcproj
+++ /dev/null
@@ -1,209 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="test_plugin"
-	ProjectGUID="{CBBD34E5-02B0-40D5-B6D8-BFEA83E18B32}"
-	RootNamespace="test_plugin"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="196613"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\mock_code_generator.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\file.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\test_plugin.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\mock_code_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\file.cc"
-				>
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/vsprojects/tests.vcproj b/vsprojects/tests.vcproj
deleted file mode 100644
index fb815b5..0000000
--- a/vsprojects/tests.vcproj
+++ /dev/null
@@ -1,681 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="tests"
-	ProjectGUID="{4DF72760-C055-40A5-A77E-30A17E2AC2DB}"
-	RootNamespace="tests"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="0"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				Optimization="0"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-				Description=""
-				CommandLine=""
-				AdditionalDependencies=""
-				Outputs=""
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				AdditionalOptions="/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305"
-				AdditionalIncludeDirectories="../src;.;../gtest/include"
-				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_VARIADIC_MAX=10;"
-				RuntimeLibrary="2"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="true"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				GenerateDebugInformation="true"
-				SubSystem="1"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\file.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\googletest.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\test_util.h"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\mock_code_generator.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_custom_options.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_public.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_lite_imports_nonline.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_mset.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_optimize_for.pb.h"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_generic_services.pb.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath="..\src\google\protobuf\io\coded_stream_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\command_line_interface_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\mock_code_generator.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\common_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_bootstrap_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\cpp\cpp_plugin_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_plugin_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\python\python_plugin_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor_database_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\descriptor_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\dynamic_message_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\extension_set_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\file.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\generated_message_reflection_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\testing\googletest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\importer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\message_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\once_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\compiler\parser_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\printer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\reflection_ops_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\repeated_field_reflection_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\structurally_valid_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\stringprintf_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\template_util_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\type_traits_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\stubs\strutil_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\test_util.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\text_format_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\tokenizer_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_custom_options.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_embed_optimize_for.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_import_public.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_lite_imports_nonlite.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_mset.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_optimize_for.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\google\protobuf\unittest_no_generic_services.pb.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\unknown_field_set_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\wire_format_unittest.cc"
-				>
-			</File>
-			<File
-				RelativePath="..\src\google\protobuf\io\zero_copy_stream_unittest.cc"
-				>
-			</File>
-		</Filter>
-		<File
-			RelativePath="..\src\google\protobuf\compiler\cpp\cpp_test_bad_identifiers.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating cpp_test_bad_identifiers.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.h;google\protobuf\compiler\cpp\cpp_test_bad_identifiers.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest.pb.h;google\protobuf\unittest.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_custom_options.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_custom_options.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_custom_options.pb.h;google\protobuf\unittest_custom_options.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_custom_options.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_custom_options.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_custom_options.pb.h;google\protobuf\unittest_custom_options.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_embed_optimize_for.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_embed_optimize_for.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_embed_optimize_for.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_embed_optimize_for.pb.h;google\protobuf\unittest_embed_optimize_for.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_import.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import.pb.h;google\protobuf\unittest_import.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_import_public.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_public.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_public.pb.h;google\protobuf\unittest_import_public.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_import_public.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_import_public.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_import_public.pb.h;google\protobuf\unittest_import_public.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_lite_imports_nonlite.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_lite_imports_nonlite.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_lite_imports_nonlite.pb.h;google\protobuf\unittest_lite_imports_nonlite.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_lite_imports_nonlite.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_lite_imports_nonlite.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_lite_imports_nonlite.pb.h;google\protobuf\unittest_lite_imports_nonlite.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_mset.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_mset.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_mset.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_mset.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_mset.pb.h;google\protobuf\unittest_mset.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_optimize_for.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_optimize_for.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_optimize_for.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_optimize_for.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_optimize_for.pb.h;google\protobuf\unittest_optimize_for.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-		<File
-			RelativePath="..\src\google\protobuf\unittest_no_generic_services.proto"
-			>
-			<FileConfiguration
-				Name="Debug|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_generic_services.pb.{h,cc}..."
-					CommandLine="Debug\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_no_generic_services.pb.h;google\protobuf\unittest_no_generic_services.pb.cc"
-				/>
-			</FileConfiguration>
-			<FileConfiguration
-				Name="Release|Win32"
-				>
-				<Tool
-					Name="VCCustomBuildTool"
-					Description="Generating unittest_no_generic_services.pb.{h,cc}..."
-					CommandLine="Release\protoc -I../src --cpp_out=. ../src/google/protobuf/unittest_no_generic_services.proto&#x0D;&#x0A;"
-					Outputs="google\protobuf\unittest_no_generic_services.pb.h;google\protobuf\unittest_no_generic_services.pb.cc"
-				/>
-			</FileConfiguration>
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>